Merge
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index cb9368a..5f49404 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -391,3 +391,4 @@
 a22e2671d88f6b22a4aa82e3966986542ed2a381 jdk-9+146
 5f6920274c48eb00d31afee6c034826a754c13d9 jdk-9+147
 3ffc3e886c74736e387f3685e86b557cdea706c8 jdk-9+148
+b119012d1c2ab2570fe8718633840d0c1f1f441d jdk-9+149
diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README
deleted file mode 100644
index a93b35b..0000000
--- a/THIRD_PARTY_README
+++ /dev/null
@@ -1,3605 +0,0 @@
-DO NOT TRANSLATE OR LOCALIZE.
------------------------------
-
-%% This notice is provided with respect to ASM Bytecode Manipulation 
-Framework v5.0, which may be included with JRE 8, and JDK 8, and 
-OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2011 France Télécom
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holders nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to BSDiff v4.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 2003-2005 Colin Percival
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CodeViewer 1.0, which may be
-included with JDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1999 by CoolServlets.com.
-
-Any errors or suggested improvements to this class can be reported as
-instructed on CoolServlets.com. We hope you enjoy this program... your
-comments will encourage further development!  This software is distributed
-under the terms of the BSD License.  Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-Neither name of CoolServlets.com nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Cryptix AES 3.2.0, which may be
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Cryptix General License
-
-Copyright (c) 1995-2005 The Cryptix Foundation Limited.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  1. Redistributions of source code must retain the copyright notice,
-     this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CUP Parser Generator for 
-Java 0.10k, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted, provided
-that the above copyright notice appear in all copies and that both the
-copyright notice and this permission notice and warranty disclaimer appear in
-supporting documentation, and that the names of the authors or their
-employers not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission.
-
-The authors and their employers disclaim all warranties with regard to
-this software, including all implied warranties of merchantability and fitness.
-In no event shall the authors or their employers be liable for any special,
-indirect or consequential damages or any damages whatsoever resulting from
-loss of use, data or profits, whether in an action of contract, negligence or
-other tortious action, arising out of or in connection with the use or
-performance of this software.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Document Object Model (DOM) Level 2
-& 3, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-W3C SOFTWARE NOTICE AND LICENSE
-
-http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
-
-This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license. By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following terms
-and conditions.
-
-Permission to copy, modify, and distribute this software and its
-documentation, with or without modification, for any purpose and without fee
-or royalty is hereby granted, provided that you include the following on ALL
-copies of the software and documentation or portions thereof, including
-modifications:
-
-   1.The full text of this NOTICE in a location viewable to users of the
-   redistributed or derivative work.
-
-   2.Any pre-existing intellectual property disclaimers, notices, or terms and
-   conditions. If none exist, the W3C Software Short Notice should be included
-   (hypertext is preferred, text is permitted) within the body of any
-   redistributed or derivative code.
-
-   3.Notice of any changes or modifications to the files, including the date
-   changes were made. (We recommend you provide URIs to the location from
-   which the code is derived.)
-
-THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
-THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
-COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
-in advertising or publicity pertaining to the software without specific,
-written prior permission. Title to copyright in this software and any
-associated documentation will at all times remain with copyright holders.
-
-____________________________________
-
-This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C, reflects
-that ERCIM is now a host of the W3C, includes references to this specific
-dated version of the license, and removes the ambiguous grant of "use".
-Otherwise, this version is the same as the previous version and is written so
-as to preserve the Free Software Foundation's assessment of GPL compatibility
-and OSI's certification under the Open Source Definition. Please see our
-Copyright FAQ for common questions about using materials from our site,
-including specific terms and conditions for packages like libwww, Amaya, and
-Jigsaw. Other questions about this notice can be directed to
-site-policy@w3.org.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Dynalink v0.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2009-2013, Attila Szegedi
-
-All rights reserved.Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following conditions are
-met:* Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.  * Redistributions in
-binary form must reproduce the above copyright notice,   this list of
-conditions and the following disclaimer in the documentation  and/or other
-materials provided with the distribution.  * Neither the name of Attila
-Szegedi nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Elliptic Curve Cryptography, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
-You are receiving a copy of the Elliptic Curve Cryptography library in source
-form with the JDK 8 and OpenJDK 8 source distributions, and as object code in
-the JRE 8 & JDK 8 runtimes.
-
-In the case of the JRE 8 & JDK 8 runtimes, the terms of the Oracle license do
-NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
-following license, separately from Oracle's JDK & JRE.  If you do not wish to
-install the Elliptic Curve Cryptography library, you may delete the library
-named libsunec.so (on Solaris and Linux systems) or sunec.dll (on Windows
-systems) from the JRE bin directory reserved for native libraries.
-
-
---- begin of LICENSE ---
-
-                  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!
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to  ECMAScript Language
-Specification ECMA-262 Edition 5.1 which may be included with 
-JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright notice
-Copyright © 2011 Ecma International
-Ecma International
-Rue du Rhone 114
-CH-1204 Geneva
-Tel: +41 22 849 6000
-Fax: +41 22 849 6001
-Web: http://www.ecma-international.org
-
-This document and possible translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it or assist
-in its implementation may be prepared, copied, published, and distributed, in
-whole or in part, without restriction of any kind, provided that the above
-copyright notice and this section are included on all such copies and derivative
-works. However, this document itself may not be modified in any way, including
-by removing the copyright notice or references to Ecma International, except as
-needed for the purpose of developing any document or deliverable produced by
-Ecma International (in which case the rules applied to copyrights must be
-followed) or as required to translate it into languages other than English. The
-limited permissions granted above are perpetual and will not be revoked by Ecma
-International or its successors or assigns. This document and the information
-contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL
-DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
-WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
-RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
-PURPOSE." Software License
-
-All Software contained in this document ("Software)" is protected by copyright
-and is being made available under the "BSD License", included below. This
-Software may be subject to third party rights (rights from parties other than
-Ecma International), including patent rights, and no licenses under such third
-party rights are granted under this license even if the third party concerned is
-a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS
-AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
-INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO
-IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the authors nor Ecma International may be used to endorse
-or promote products derived from this software without specific prior written
-permission.
-
-THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Dynalink library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Copyright (c) 2009-2013, Attila Szegedi
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the copyright holder nor the names of
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Joni library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to FontConfig 2.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 source distributions on
-Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright © 2001,2003 Keith Packard
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation, and that
-the name of Keith Packard not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior permission.
-Keith Packard makes no representations about the suitability of this software
-for any purpose.  It is provided "as is" without express or implied warranty.
-
-KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IAIK PKCS#11 Wrapper, 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-IAIK PKCS#11 Wrapper License
-
-Copyright (c) 2002 Graz University of Technology. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-   "This product includes software developed by IAIK of Graz University of
-    Technology."
-
-   Alternately, this acknowledgment may appear in the software itself, if and
-   wherever such third-party acknowledgments normally appear.
-
-4. The names "Graz University of Technology" and "IAIK of Graz University of
-   Technology" must not be used to endorse or promote products derived from this
-   software without prior written permission.
-
-5. Products derived from this software may not be called "IAIK PKCS Wrapper",
-   nor may "IAIK" appear in their name, without prior written permission of
-   Graz University of Technology.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to ICU4C 4.0.1 and ICU4J 4.4, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 1995-2010 International Business Machines Corporation and others 
-
-All rights reserved. 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice appear
-in all copies of the Software and that both the above copyright notice(s) and
-this permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
-All trademarks and registered trademarks mentioned herein are the property of
-their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IJG JPEG 6b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library.  If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it.  This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Joni v1.1.9, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JOpt-Simple v3.0,  which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (c) 2004-2009 Paul R. Holser, Jr.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JSON, which may be included 
-with JRE 8 & JDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality, which 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- (C) Copyright IBM Corp. 1999 All Rights Reserved.
- Copyright 1997 The Open Group Research Institute. All rights reserved.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality from 
-FundsXpress, INC., which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (C) 1998 by the FundsXpress, INC.
-
- All rights reserved.
-
- Export of this software from the United States of America may require
- a specific license from the United States Government.  It is the
- responsibility of any person or organization contemplating export to
- obtain such a license before exporting.
-
- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- distribute this software and its documentation for any purpose and
- without fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation, and that
- the name of FundsXpress. not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.  FundsXpress makes no representations about the suitability of
- this software for any purpose.  It is provided "as is" without express
- or implied warranty.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kronos OpenGL headers, which may be 
-included with JDK 8 and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Copyright (c) 2007 The Khronos Group Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and/or associated documentation files (the "Materials"), to
- deal in the Materials without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Materials, and to permit persons to whom the Materials are
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Materials.
-
- THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- MATERIALS.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions Copyright Eastman Kodak Company 1992
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libpng 1.5.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This copy of the libpng notices is provided for your convenience.  In case of
-any discrepancy between this copy and the notices in the file png.h that is
-included in the libpng distribution, the latter shall prevail.
-
-COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
-
-If you modify libpng you may insert additional notices immediately following
-this sentence.
-
-This code is released under the libpng license.
-
-libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
-Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.2.5
-with the following individual added to the list of Contributing Authors
-
-   Cosmin Truta
-
-libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
-Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.0.6
-with the following individuals added to the list of Contributing Authors
-
-   Simon-Pierre Cadieux
-   Eric S. Raymond
-   Gilles Vollant
-
-and with the following additions to the disclaimer:
-
-   There is no warranty against interference with your enjoyment of the
-   library or against infringement.  There is no warranty that our
-   efforts or the library will fulfill any of your particular purposes
-   or needs.  This library is provided with all faults, and the entire
-   risk of satisfactory quality, performance, accuracy, and effort is with
-   the user.
-
-libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
-Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-0.96,
-with the following individuals added to the list of Contributing Authors:
-
-   Tom Lane
-   Glenn Randers-Pehrson
-   Willem van Schaik
-
-libpng versions 0.89, June 1996, through 0.96, May 1997, are
-Copyright (c) 1996, 1997 Andreas Dilger
-Distributed according to the same disclaimer and license as libpng-0.88,
-with the following individuals added to the list of Contributing Authors:
-
-   John Bowler
-   Kevin Bracey
-   Sam Bushell
-   Magnus Holmgren
-   Greg Roelofs
-   Tom Tanner
-
-libpng versions 0.5, May 1995, through 0.88, January 1996, are
-Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-
-For the purposes of this copyright and license, "Contributing Authors"
-is defined as the following set of individuals:
-
-   Andreas Dilger
-   Dave Martindale
-   Guy Eric Schalnat
-   Paul Schmidt
-   Tim Wegner
-
-The PNG Reference Library is supplied "AS IS".  The Contributing Authors
-and Group 42, Inc. disclaim all warranties, expressed or implied,
-including, without limitation, the warranties of merchantability and of
-fitness for any purpose.  The Contributing Authors and Group 42, Inc.
-assume no liability for direct, indirect, incidental, special, exemplary,
-or consequential damages, which may result from the use of the PNG
-Reference Library, even if advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-source code, or portions hereof, for any purpose, without fee, subject
-to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-
-2. Altered versions must be plainly marked as such and must not
-   be misrepresented as being the original source.
-
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The Contributing Authors and Group 42, Inc. specifically permit, without
-fee, and encourage the use of this source code as a component to
-supporting the PNG file format in commercial products.  If you use this
-source code in a product, acknowledgment is not required but would be
-appreciated.
-
-
-A "png_get_copyright" function is available, for convenient use in "about"
-boxes and the like:
-
-   printf("%s",png_get_copyright(NULL));
-
-Also, the PNG logo (in PNG format, of course) is supplied in the
-files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
-
-Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
-certification mark of the Open Source Initiative.
-
-Glenn Randers-Pehrson
-glennrp at users.sourceforge.net
-July 7, 2011
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libungif 4.1.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Little CMS 2.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Little CMS
-Copyright (c) 1998-2010 Marti Maria Saguer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Lucida is a registered trademark or trademark of Bigelow & Holmes in the
-U.S. and other countries.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mesa 3D Graphics Library v4.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Mesa 3-D graphics library
- Version:  4.1
-
- Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mozilla Network Security
-Services (NSS), which is supplied with the JDK test suite in the OpenJDK
-source code repository. It is licensed under Mozilla Public License (MPL),
-version 2.0.
-
-The NSS libraries are supplied in executable form, built from unmodified
-NSS source code labeled with the "NSS_3.13.1_RTM" release tag.
-
-The NSS source code is available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/src
-
-The NSS libraries are available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/lib
-
---- begin of LICENSE ---
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PC/SC Lite for Suse Linux v.1.1.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
-Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by: 
-      David Corcoran <corcoran@linuxnet.com>
-      http://www.linuxnet.com (MUSCLE)
-4. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-Changes to this license can be made only by the copyright author with 
-explicit written consent.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PorterStemmer v4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-See: http://tartarus.org/~martin/PorterStemmer
-
-The software is completely free for any purpose, unless notes at the head of
-the program text indicates otherwise (which is rare). In any case, the notes
-about licensing are never more restrictive than the BSD License.
-
-In every case where the software is not written by me (Martin Porter), this
-licensing arrangement has been endorsed by the contributor, and it is
-therefore unnecessary to ask the contributor again to confirm it.
-
-I have not asked any contributors (or their employers, if they have them) for
-proofs that they have the right to distribute their software in this way.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Relax NG Object/Parser v.20050510,
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions: The above copyright
-notice and this permission notice shall be included in all copies or
-substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to RelaxNGCC v1.12, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2003 Daisuke Okajima and Kohsuke Kawaguchi.  
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-    "This product includes software developed by Daisuke Okajima
-    and Kohsuke Kawaguchi (http://relaxngcc.sf.net/)."
-
-Alternately, this acknowledgment may appear in the software itself, if and
-wherever such third-party acknowledgments normally appear.
-
-4. The names of the copyright holders must not be used to endorse or promote
-   products derived from this software without prior written permission. For
-   written permission, please contact the copyright holders.
-
-5. Products derived from this software may not be called "RELAXNGCC", nor may
-  "RELAXNGCC" appear in their name, without prior written permission of the
-  copyright holders.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE APACHE
-SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SAX 2.0.1, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- SAX is free!
-
- In fact, it's not possible to own a license to SAX, since it's been placed in
- the public domain.
-
- No Warranty
-
- Because SAX is released to the public domain, there is no warranty for the
- design or for the software implementation, to the extent permitted by
- applicable law. Except when otherwise stated in writing the copyright holders
- and/or other parties provide SAX "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 SAX is with you. Should SAX prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- 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
- SAX, be liable to you for damages, including any general, special, incidental
- or consequential damages arising out of the use or inability to use SAX
- (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 SAX to
- operate with any other programs), even if such holder or other party has been
- advised of the possibility of such damages.
-
- Copyright Disclaimers 
-
- This page includes statements to that effect by David Megginson, who would
- have been able to claim copyright for the original work.  SAX 1.0
-
- Version 1.0 of the Simple API for XML (SAX), created collectively by the
- membership of the XML-DEV mailing list, is hereby released into the public
- domain.
-
- No one owns SAX: you may use it freely in both commercial and non-commercial
- applications, bundle it with your software distribution, include it on a
- CD-ROM, list the source code in a book, mirror the documentation at your own
- web site, or use it in any other way you see fit.
-
- David Megginson, sax@megginson.com
- 1998-05-11
-
- SAX 2.0 
-
- I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and
- release all of the SAX 2.0 source code, compiled code, and documentation
- contained in this distribution into the Public Domain. SAX comes with NO
- WARRANTY or guarantee of fitness for any purpose.
-
- David Megginson, david@megginson.com
- 2000-05-05
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SoftFloat version 2b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux/ARM.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-SoftFloat was written by me, John R. Hauser. This work was made possible in 
-part by the International Computer Science Institute, located at Suite 600, 
-1947 Center Street, Berkeley, California 94704. Funding was partially 
-provided by the National Science Foundation under grant MIP-9311980. The 
-original version of this code was written as part of a project to build 
-a fixed-point vector processor in collaboration with the University of 
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. 
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort 
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT 
-TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO 
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL 
-LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO 
-FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER 
-SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, 
-COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE 
-SOFTWARE. 
-
-Derivative works are acceptable, even for commercial purposes, provided 
-that the minimal documentation requirements stated in the source code are 
-satisfied. 
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Sparkle 1.5,
-which may be included with JRE 8 on Mac OS X.
-
---- begin of LICENSE ---
-
-Copyright (c) 2012 Sparkle.org and Andy Matuschak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions licensed from Taligent, Inc.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Thai Dictionary, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (C) 1982 The Royal Institute, Thai Royal Government.
-
-Copyright (C) 1998 National Electronics and Computer Technology Center,
-National Science and Technology Development Agency,
-Ministry of Science Technology and Environment,
-Thai Royal Government.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Unicode 6.2.0 & CLDR 21.0.1
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Unicode Terms of Use
-
-For the general privacy policy governing access to this site, see the Unicode
-Privacy Policy. For trademark usage, see the Unicode® Consortium Name and
-Trademark Usage Policy.
-
-A. Unicode Copyright.
-   1. Copyright © 1991-2013 Unicode, Inc. All rights reserved.
-
-   2. Certain documents and files on this website contain a legend indicating
-      that "Modification is permitted." Any person is hereby authorized,
-      without fee, to modify such documents and files to create derivative
-      works conforming to the Unicode® Standard, subject to Terms and
-      Conditions herein.
-
-    3. Any person is hereby authorized, without fee, to view, use, reproduce,
-       and distribute all documents and files solely for informational
-       purposes in the creation of products supporting the Unicode Standard,
-       subject to the Terms and Conditions herein.
-
-    4. Further specifications of rights and restrictions pertaining to the use
-       of the particular set of data files known as the "Unicode Character
-       Database" can be found in Exhibit 1.
-
-    5. Each version of the Unicode Standard has further specifications of
-       rights and restrictions of use. For the book editions (Unicode 5.0 and
-       earlier), these are found on the back of the title page. The online
-       code charts carry specific restrictions. All other files, including
-       online documentation of the core specification for Unicode 6.0 and
-       later, are covered under these general Terms of Use.
-
-    6. No license is granted to "mirror" the Unicode website where a fee is
-       charged for access to the "mirror" site.
-
-    7. Modification is not permitted with respect to this document. All copies
-       of this document must be verbatim.
-
-B. Restricted Rights Legend. Any technical data or software which is licensed
-   to the United States of America, its agencies and/or instrumentalities
-   under this Agreement is commercial technical data or commercial computer
-   software developed exclusively at private expense as defined in FAR 2.101,
-   or DFARS 252.227-7014 (June 1995), as applicable. For technical data, use,
-   duplication, or disclosure by the Government is subject to restrictions as
-   set forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov
-   1995) and this Agreement. For Software, in accordance with FAR 12-212 or
-   DFARS 227-7202, as applicable, use, duplication or disclosure by the
-   Government is subject to the restrictions set forth in this Agreement.
-
-C. Warranties and Disclaimers.
-   1. This publication and/or website may include technical or typographical
-      errors or other inaccuracies . Changes are periodically added to the
-      information herein; these changes will be incorporated in new editions
-      of the publication and/or website. Unicode may make improvements and/or
-      changes in the product(s) and/or program(s) described in this
-      publication and/or website at any time.
-
-    2. If this file has been purchased on magnetic or optical media from
-       Unicode, Inc. the sole and exclusive remedy for any claim will be
-       exchange of the defective media within ninety (90) days of original
-       purchase.
-
-    3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR SOFTWARE IS
-       PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, IMPLIED,
-       OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
-       UNICODE AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR
-       OMISSIONS IN THIS PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH
-       ARE REFERENCED BY OR LINKED TO THIS PUBLICATION OR THE UNICODE WEBSITE.
-
-D. Waiver of Damages. In no event shall Unicode or its licensors be liable for
-   any special, incidental, indirect or consequential damages of any kind, or
-   any damages whatsoever, whether or not Unicode was advised of the
-   possibility of the damage, including, without limitation, those resulting
-   from the following: loss of use, data or profits, in connection with the
-   use, modification or distribution of this information or its derivatives.
-
-E.Trademarks & Logos.
-   1. The Unicode Word Mark and the Unicode Logo are trademarks of Unicode,
-      Inc.  “The Unicode Consortium” and “Unicode, Inc.” are trade names of
-      Unicode, Inc.  Use of the information and materials found on this
-      website indicates your acknowledgement of Unicode, Inc.’s exclusive
-      worldwide rights in the Unicode Word Mark, the Unicode Logo, and the
-      Unicode trade names.
-
-   2. The Unicode Consortium Name and Trademark Usage Policy (“Trademark
-      Policy”) are incorporated herein by reference and you agree to abide by
-      the provisions of the Trademark Policy, which may be changed from time
-      to time in the sole discretion of Unicode, Inc.
-
-   3. All third party trademarks referenced herein are the property of their
-      respective owners.
-
-Miscellaneous.
-   1. Jurisdiction and Venue. This server is operated from a location in the
-      State of California, United States of America. Unicode makes no
-      representation that the materials are appropriate for use in other
-      locations. If you access this server from other locations, you are
-      responsible for compliance with local laws. This Agreement, all use of
-      this site and any claims and damages resulting from use of this site are
-      governed solely by the laws of the State of California without regard to
-      any principles which would apply the laws of a different jurisdiction.
-      The user agrees that any disputes regarding this site shall be resolved
-      solely in the courts located in Santa Clara County, California. The user
-      agrees said courts have personal jurisdiction and agree to waive any
-      right to transfer the dispute to any other forum.
-
-   2. Modification by Unicode.  Unicode shall have the right to modify this
-      Agreement at any time by posting it to this site. The user may not
-      assign any part of this Agreement without Unicode’s prior written
-      consent.
-
-   3. Taxes. The user agrees to pay any taxes arising from access to this
-      website or use of the information herein, except for those based on
-      Unicode’s net income.
-
-   4. Severability.  If any provision of this Agreement is declared invalid or
-      unenforceable, the remaining provisions of this Agreement shall remain
-      in effect.
-
-   5. Entire Agreement. This Agreement constitutes the entire agreement
-      between the parties.
-
-EXHIBIT 1
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-Unicode Data Files include all data files under the directories
-http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
-http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
-online code charts under the directory http://www.unicode.org/Public/.
-Software includes any source code published in the Unicode Standard or under
-the directories http://www.unicode.org/Public/,
-http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
-
-NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
-INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
-FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
-BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
-AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
-SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under the
-Terms of Use in http://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the Unicode data files and any associated documentation (the "Data Files")
-or Unicode software and any associated documentation (the "Software") to deal
-in the Data Files or Software without restriction, including without
-limitation the rights to use, copy, modify, merge, publish, distribute, and/or
-sell copies of the Data Files or Software, and to permit persons to whom the
-Data Files or Software are furnished to do so, provided that (a) the above
-copyright notice(s) and this permission notice appear with all copies of the
-Data Files or Software, (b) both the above copyright notice(s) and this
-permission notice appear in associated documentation, and (c) there is clear
-notice in each modified Data File or in the Software as well as in the
-documentation associated with the Data File(s) or Software that the data or
-software has been modified.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
-THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
-DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in these Data Files or Software without prior written authorization of the
-copyright holder.
-
-Unicode and the Unicode logo are trademarks of Unicode, Inc. in the United
-States and other countries. All third party trademarks referenced herein are
-the property of their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to UPX v3.01, which may be included 
-with JRE 8 on Windows.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-
-                 ooooo     ooo ooooooooo.   ooooooo  ooooo
-                 `888'     `8' `888   `Y88.  `8888    d8'
-                  888       8   888   .d88'    Y888..8P
-                  888       8   888ooo88P'      `8888'
-                  888       8   888            .8PY888.
-                  `88.    .8'   888           d8'  `888b
-                    `YbodP'    o888o        o888o  o88888o
-
-
-                    The Ultimate Packer for eXecutables
-          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
-               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
-                          http://www.nexus.hu/upx
-                            http://upx.tsx.org
-
-
-PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
-TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
-
-
-ABSTRACT
-========
-
-   UPX and UCL are copyrighted software distributed under the terms
-   of the GNU General Public License (hereinafter the "GPL").
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   As a special exception we grant the free usage of UPX for all
-   executables, including commercial programs.
-   See below for details and restrictions.
-
-
-COPYRIGHT
-=========
-
-   UPX and UCL are copyrighted software. All rights remain with the authors.
-
-   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-   UPX is Copyright (C) 1996-2000 Laszlo Molnar
-
-   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-
-
-GNU GENERAL PUBLIC LICENSE
-==========================
-
-   UPX and the UCL library are free software; you can redistribute them
-   and/or modify them under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   UPX and UCL are distributed in the hope that they will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; see the file COPYING.
-
-
-SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
-============================================
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
-   permission to freely use and distribute all UPX compressed programs
-   (including commercial ones), subject to the following restrictions:
-
-   1. You must compress your program with a completely unmodified UPX
-      version; either with our precompiled version, or (at your option)
-      with a self compiled version of the unmodified UPX sources as
-      distributed by us.
-   2. This also implies that the UPX stub must be completely unmodfied, i.e.
-      the stub imbedded in your compressed program must be byte-identical
-      to the stub that is produced by the official unmodified UPX version.
-   3. The decompressor and any other code from the stub must exclusively get
-      used by the unmodified UPX stub for decompressing your program at
-      program startup. No portion of the stub may get read, copied,
-      called or otherwise get used or accessed by your program.
-
-
-ANNOTATIONS
-===========
-
-  - You can use a modified UPX version or modified UPX stub only for
-    programs that are compatible with the GNU General Public License.
-
-  - We grant you special permission to freely use and distribute all UPX
-    compressed programs. But any modification of the UPX stub (such as,
-    but not limited to, removing our copyright string or making your
-    program non-decompressible) will immediately revoke your right to
-    use and distribute a UPX compressed program.
-
-  - UPX is not a software protection tool; by requiring that you use
-    the unmodified UPX version for your proprietary programs we
-    make sure that any user can decompress your program. This protects
-    both you and your users as nobody can hide malicious code -
-    any program that cannot be decompressed is highly suspicious
-    by definition.
-
-  - You can integrate all or part of UPX and UCL into projects that
-    are compatible with the GNU GPL, but obviously you cannot grant
-    any special exceptions beyond the GPL for our code in your project.
-
-  - We want to actively support manufacturers of virus scanners and
-    similar security software. Please contact us if you would like to
-    incorporate parts of UPX or UCL into such a product.
-
-
-
-Markus F.X.J. Oberhumer                   Laszlo Molnar
-markus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu
-
-Linz, Austria, 25 Feb 2000
-
-Additional License(s)
-
-The UPX license file is at http://upx.sourceforge.net/upx-license.html.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Xfree86-VidMode Extension 1.0,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Version 1.1 of XFree86 ProjectLicence.
-
-Copyright (C) 1994-2004 The XFree86 Project, Inc.    All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicence, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so,subject to the following conditions:
-
-   1. Redistributions of source code must retain the above copyright
-   notice,this list of conditions, and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution, and in the same place
-   and form as other copyright, license and disclaimer information.
-
-   3. The end-user documentation included with the redistribution, if any,must
-   include the following acknowledgment: "This product includes
-   software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and
-   its contributors", in the same place and form as other third-party
-   acknowledgments. Alternately, this acknowledgment may appear in the software
-   itself, in the same form and location as other such third-party
-   acknowledgments.
-
-    4. Except as contained in this notice, the name of The XFree86 Project,Inc
-    shall not be used in advertising or otherwise to promote the sale, use
-    or other dealings in this Software without prior written authorization from
-    The XFree86 Project, Inc.
-
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-    WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-    EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-    DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-    DAMAGE.  
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to X Window System 6.8.2, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-          Licenses
-The X.Org Foundation March 2004
-
-1. Introduction
-
-The X.org Foundation X Window System distribution is a compilation of code and
-documentation from many sources. This document is intended primarily as a
-guide to the licenses used in the distribution: you must check each file
-and/or package for precise redistribution terms. None-the-less, this summary
-may be useful to many users. No software incorporating the XFree86 1.1 license
-has been incorporated.
-
-This document is based on the compilation from XFree86.
-
-2. XFree86 License
-
-XFree86 code without an explicit copyright is covered by the following
-copyright/license:
-
-Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the XFree86 Project shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from the XFree86 Project.
-
-3. Other Licenses
-
-Portions of code are covered by the following licenses/copyrights. See
-individual files for the copyright dates.
-
-3.1. X/MIT Copyrights
-
-3.1.1. X Consortium
-
-Copyright (C) <date> X Consortium
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
-CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from the X Consortium.
-
-X Window System is a trademark of X Consortium, Inc.
-
-3.1.2. The Open Group
-
-Copyright <date> The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation.
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from The Open Group.  3.2.
-Berkeley-based copyrights:
-
-o
-3.2.1. General
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.2. UCB/LBL
-
-Copyright (c) 1993 The Regents of the University of California. All rights
-reserved.
-
-This software was developed by the Computer Systems Engineering group at
-Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to
-Berkeley.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement: This product includes software
-developed by the University of California, Lawrence Berkeley Laboratory.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the University of California, Berkeley and its contributors.
-
-   4. Neither the name of the University nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.3. The
-NetBSD Foundation, Inc.
-
-Copyright (c) 2003 The NetBSD Foundation, Inc. All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation by Ben
-Collver <collver1@attbi.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the NetBSD Foundation, Inc. and its contributors.
-
-   4. Neither the name of The NetBSD Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS
-IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.4. Theodore
-Ts'o.
-
-Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   and the entire permission notice in its entirety, including the disclaimer
-   of warranties.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. he name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.5. Theo de Raadt and Damien Miller
-
-Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. Copyright (c)
-2001-2002 Damien Miller. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.6. Todd C. Miller
-
-Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  3.2.7. Thomas
-Winischhofer
-
-Copyright (C) 2001-2004 Thomas Winischhofer
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.3. NVIDIA Corp
-
-Copyright (c) 1996 NVIDIA, Corp. All rights reserved.
-
-NOTICE TO USER: The source code is copyrighted under U.S. and international
-laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design
-patents pending on the design and interface of the NV chips. Users and
-possessors of this source code are hereby granted a nonexclusive, royalty-free
-copyright and design patent license to use this code in individual and
-commercial software.
-
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
-
-Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and
-foreign countries.
-
-NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
-CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
-WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE
-FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.  3.4. GLX Public
-License
-
-GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License")
-
-Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby
-grants permission to Recipient (defined below), under Recipient's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below), and to permit persons to whom the Subject Software is
-furnished in accordance with this License to do the same, subject to all of
-the following terms and conditions, which Recipient accepts by engaging in any
-such use, copying, modifying, merging, publishing, distributing, sublicensing
-or selling:
-
-1. Definitions.
-
-    (a) "Original Software" means source code of computer software code which
-    is described in Exhibit A as Original Software.
-
-    (b) "Modifications" means any addition to or deletion from the substance
-    or structure of either the Original Software or any previous
-    Modifications. When Subject Software is released as a series of files, a
-    Modification means (i) any addition to or deletion from the contents of a
-    file containing Original Software or previous Modifications and (ii) any
-    new file that contains any part of the Original Code or previous
-    Modifications.
-
-    (c) "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    (d) "Recipient" means an individual or a legal entity exercising rights
-    under, and complying with all of the terms of, this License. For legal
-    entities, "Recipient" includes any entity which controls, is controlled
-    by, or is under common control with Recipient. For purposes of this
-    definition, "control" of an entity means (a) the power, direct or
-    indirect, to direct or manage such entity, or (b) ownership of fifty
-    percent (50%) or more of the outstanding shares or beneficial ownership of
-    such entity.
-
-2. Redistribution of Source Code Subject to These Terms. Redistributions of
-Subject Software in source code form must retain the notice set forth in
-Exhibit A, below, in every file. A copy of this License must be included in
-any documentation for such Subject Software where the recipients' rights
-relating to Subject Software are described. Recipient may distribute the
-source code version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the source code version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-3. Redistribution in Executable Form. The notice set forth in Exhibit A must
-be conspicuously included in any notice in an executable version of Subject
-Software, related documentation or collateral in which Recipient describes the
-user's rights relating to the Subject Software. Recipient may distribute the
-executable version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the executable version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-4. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software which is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-5. No Trademark Rights. This License does not grant any rights to use any
-trade name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from
-the Subject Software without prior written permission of SGI.
-
-6. No Other Rights. This License does not grant any rights with respect to the
-OpenGL API or to any software or hardware implementation thereof or to any
-other software whatsoever, nor shall any other rights or licenses not
-expressly granted hereunder arise by implication, estoppel or otherwise with
-respect to the Subject Software. Title to and ownership of the Original
-Software at all times remains with SGI. All rights in the Original Software
-not expressly granted under this License are reserved.
-
-7. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-8. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Exhibit A notice required under Sections 2 and 3,
-above, and in the text of any related documentation, license agreement or
-collateral in which Recipient describes end user's rights relating to the
-Subject Software. If Recipient obtains such knowledge after it makes Subject
-Software available to any other person or entity, Recipient shall take other
-steps (such as notifying appropriate mailing lists or newsgroups) reasonably
-calculated to inform those who received the Subject Software that new
-knowledge has been obtained.
-
-9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
-STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF
-THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY
-TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO
-THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT.
-
-11. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from
-and against any loss, liability, damages, costs or expenses (including the
-payment of reasonable attorneys fees) arising out of Recipient's use,
-modification, reproduction and distribution of the Subject Software or out of
-any representation or warranty made by Recipient.
-
-12. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-13. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed so as to achieve as nearly as
-possible the same economic effect as the original provision and the remainder
-of this License will remain in effect. This License shall be governed by and
-construed in accordance with the laws of the United States and the State of
-California as applied to agreements entered into and to be performed entirely
-within California between California residents. Any litigation relating to
-this License shall be subject to the exclusive jurisdiction of the Federal
-Courts of the Northern District of California (or, absent subject matter
-jurisdiction in such courts, the courts of the State of California), with
-venue lying exclusively in Santa Clara County, California, with the losing
-party responsible for costs, including without limitation, court costs and
-reasonable attorneys fees and expenses. The application of the United Nations
-Convention on Contracts for the International Sale of Goods is expressly
-excluded. Any law or regulation which provides that the language of a contract
-shall be construed against the drafter shall not apply to this License.
-
-Exhibit A
-
-The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13
-of the GLX Public License Version 1.0 (the "License"). You may not use this
-file except in compliance with those sections of the License. You may obtain a
-copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N.
-Shoreline Blvd., Mountain View, CA 94043 or at
-http://www.sgi.com/software/opensource/glx/license.html.
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON-
-INFRINGEMENT. See the License for the specific language governing rights and
-limitations under the License.
-
-The Original Software is GLX version 1.2 source code, released February, 1999.
-The developer of the Original Software is Silicon Graphics, Inc. Those
-portions of the Subject Software created by Silicon Graphics, Inc. are
-Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.  3.5. CID
-Font Code Public License
-
-CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License")
-
-Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI")
-hereby grants permission to Recipient (defined below), under SGI's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below) in both source code and executable form, and to permit persons
-to whom the Subject Software is furnished in accordance with this License to
-do the same, subject to all of the following terms and conditions, which
-Recipient accepts by engaging in any such use, copying, modifying, merging,
-publication, distributing, sublicensing or selling:
-
-1. Definitions.
-
-    a. "Original Software" means source code of computer software code that is
-    described in Exhibit A as Original Software.
-
-    b. "Modifications" means any addition to or deletion from the substance or
-    structure of either the Original Software or any previous Modifications.
-    When Subject Software is released as a series of files, a Modification
-    means (i) any addition to or deletion from the contents of a file
-    containing Original Software or previous Modifications and (ii) any new
-    file that contains any part of the Original Code or previous
-    Modifications.
-
-    c. "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    d. "Recipient" means an individual or a legal entity exercising rights
-    under the terms of this License. For legal entities, "Recipient" includes
-    any entity that controls, is controlled by, or is under common control
-    with Recipient. For purposes of this definition, "control" of an entity
-    means (i) the power, direct or indirect, to direct or manage such entity,
-    or (ii) ownership of fifty percent (50%) or more of the outstanding shares
-    or beneficial ownership of such entity.
-
-    e. "Required Notice" means the notice set forth in Exhibit A to this
-    License.
-
-    f. "Accompanying Technology" means any software or other technology that
-    is not a Modification and that is distributed or made publicly available
-    by Recipient with the Subject Software. Separate software files that do
-    not contain any Original Software or any previous Modification shall not
-    be deemed a Modification, even if such software files are aggregated as
-    part of a product, or in any medium of storage, with any file that does
-    contain Original Software or any previous Modification.
-
-2. License Terms. All distribution of the Subject Software must be made
-subject to the terms of this License. A copy of this License and the Required
-Notice must be included in any documentation for Subject Software where
-Recipient's rights relating to Subject Software and/or any Accompanying
-Technology are described. Distributions of Subject Software in source code
-form must also include the Required Notice in every file distributed. In
-addition, a ReadMe file entitled "Important Legal Notice" must be distributed
-with each distribution of one or more files that incorporate Subject Software.
-That file must be included with distributions made in both source code and
-executable form. A copy of the License and the Required Notice must be
-included in that file. Recipient may distribute Accompanying Technology under
-a license of Recipient's choice, which may contain terms different from this
-License, provided that (i) Recipient is in compliance with the terms of this
-License, (ii) such other license terms do not modify or supersede the terms of
-this License as applicable to the Subject Software, (iii) Recipient hereby
-indemnifies SGI for any liability incurred by SGI as a result of the
-distribution of Accompanying Technology or the use of other license terms.
-
-3. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software that is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-4. Trademark Rights. This License does not grant any rights to use any trade
-name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from or
-incorporating any Subject Software without prior written permission of SGI.
-
-5. No Other Rights. No rights or licenses not expressly granted hereunder
-shall arise by implication, estoppel or otherwise. Title to and ownership of
-the Original Software at all times remains with SGI. All rights in the
-Original Software not expressly granted under this License are reserved.
-
-6. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity, or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-7. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Required Notice, and in the text of any related
-documentation, license agreement or collateral in which Recipient describes
-end user's rights relating to the Subject Software. If Recipient obtains such
-knowledge after it makes Subject Software available to any other person or
-entity, Recipient shall take other steps (such as notifying appropriate
-mailing lists or newsgroups) reasonably calculated to provide such knowledge
-to those who received the Subject Software.
-
-8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND
-LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED.
-
-10. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold SGI and its successors and assigns
-harmless from and against any loss, liability, damages, costs or expenses
-(including the payment of reasonable attorneys fees) arising out of
-(Recipient's use, modification, reproduction and distribution of the Subject
-Software or out of any representation or warranty made by Recipient.
-
-11. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-12. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable by any judicial or administrative authority having proper
-jurisdiction with respect thereto, such provision shall be reformed so as to
-achieve as nearly as possible the same economic effect as the original
-provision and the remainder of this License will remain in effect. This
-License shall be governed by and construed in accordance with the laws of the
-United States and the State of California as applied to agreements entered
-into and to be performed entirely within California between California
-residents. Any litigation relating to this License shall be subject to the
-exclusive jurisdiction of the Federal Courts of the Northern District of
-California (or, absent subject matter jurisdiction in such courts, the courts
-of the State of California), with venue lying exclusively in Santa Clara
-County, California, with the losing party responsible for costs, including
-without limitation, court costs and reasonable attorneys fees and expenses.
-The application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded. Any law or regulation that
-provides that the language of a contract shall be construed against the
-drafter shall not apply to this License.
-
-Exhibit A
-
-Copyright (c) 1994-1999 Silicon Graphics, Inc.
-
-The contents of this file are subject to the CID Font Code Public License
-Version 1.0 (the "License"). You may not use this file except in compliance
-with the License. You may obtain a copy of the License at Silicon Graphics,
-Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
-or at http://www.sgi.com/software/opensource/cid/license.html
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF
-NON-INFRINGEMENT. See the License for the specific language governing rights
-and limitations under the License.
-
-The Original Software (as defined in the License) is CID font code that was
-developed by Silicon Graphics, Inc. Those portions of the Subject Software (as
-defined in the License) that were created by Silicon Graphics, Inc. are
-Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved.
-
-[NOTE: When using this text in connection with Subject Software delivered
-solely in object code form, Recipient may replace the words "this file" with
-"this software" in both the first and second sentences.] 3.6. Bitstream Vera
-Fonts Copyright
-
-The fonts have a generous copyright, allowing derivative works (as long as
-"Bitstream" or "Vera" are not in the names), and full redistribution (so long
-as they are not *sold* by themselves). They can be be bundled, redistributed
-and sold with any software.
-
-The fonts are distributed under the following copyright:
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.  3.7. Bigelow & Holmes
-Inc and URW++ GmbH Luxi font license
-
-Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font instruction
-code copyright (c) 2001 by URW++ GmbH. All Rights Reserved. Luxi is a
-registered trademark of Bigelow & Holmes Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of these Fonts and associated documentation files (the "Font Software"), to
-deal in the Font Software, including without limitation the rights to use,
-copy, merge, publish, distribute, sublicense, and/or sell copies of the Font
-Software, and to permit persons to whom the Font Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software.
-
-The Font Software may not be modified, altered, or added to, and in particular
-the designs of glyphs or characters in the Fonts may not be modified nor may
-additional glyphs or characters be added to the Fonts. This License becomes
-null and void when the Fonts or Font Software have been modified.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BIGELOW & HOLMES INC. OR URW++
-GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
-GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
-Except as contained in this notice, the names of Bigelow & Holmes Inc. and
-URW++ GmbH. shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Font Software without prior written
-authorization from Bigelow & Holmes Inc. and URW++ GmbH.
-
-For further information, contact:
-
-info@urwpp.de or design@bigelowandholmes.com
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to zlib v1.2.5, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-  version 1.2.5, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to the following which may be 
-included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
-
-  Apache Commons Math 2.2
-  Apache Derby 10.10.1.2        [included with JDK 8]
-  Apache Jakarta BCEL 5.2 
-  Apache Jakarta Regexp 1.4 
-  Apache Santuario XML Security for Java 1.5.4
-  Apache Xalan-Java 2.7.1 
-  Apache Xerces Java 2.10.0 
-  Apache XML Resolver 1.1 
-  Dynalink 0.5
-
-
---- begin of LICENSE ---
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in
index e26450a..adde830 100644
--- a/common/autoconf/bootcycle-spec.gmk.in
+++ b/common/autoconf/bootcycle-spec.gmk.in
@@ -50,9 +50,6 @@
 # The bootcycle build has a different output directory
 OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@
 BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build
-# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk. Must not
-# use space in this patsubst to avoid leading space in HOTSPOT_DIST.
-HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%,$(BUILD_OUTPUT)%,$(HOTSPOT_DIST))
 SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR))
 
 JAVA_CMD:=$(BOOT_JDK)/bin/java
diff --git a/common/autoconf/buildjdk-spec.gmk.in b/common/autoconf/buildjdk-spec.gmk.in
index ddd388c..d6abc42 100644
--- a/common/autoconf/buildjdk-spec.gmk.in
+++ b/common/autoconf/buildjdk-spec.gmk.in
@@ -44,15 +44,12 @@
 
 # These directories should not be moved to BUILDJDK_OUTPUTDIR
 HOTSPOT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_OUTPUTDIR))
-HOTSPOT_DIST := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_DIST))
 SUPPORT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(SUPPORT_OUTPUTDIR))
 JDK_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(JDK_OUTPUTDIR))
 IMAGES_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(IMAGES_OUTPUTDIR))
 
 OPENJDK_BUILD_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@
 OPENJDK_BUILD_CPU_LEGACY_LIB := @OPENJDK_BUILD_CPU_LEGACY_LIB@
-OPENJDK_BUILD_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@
-OPENJDK_TARGET_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@
 OPENJDK_TARGET_CPU := @OPENJDK_BUILD_CPU@
 OPENJDK_TARGET_CPU_ARCH := @OPENJDK_BUILD_CPU_ARCH@
 OPENJDK_TARGET_CPU_BITS := @OPENJDK_BUILD_CPU_BITS@
@@ -90,6 +87,7 @@
 BUILD_GTEST := false
 
 JVM_VARIANTS := server
+JVM_VARIANT_MAIN := server
 
 # Some users still set EXTRA_*FLAGS on the make command line. Must
 # make sure to override that when building buildjdk.
diff --git a/common/autoconf/compare.sh.in b/common/autoconf/compare.sh.in
index 4493380..76d921f 100644
--- a/common/autoconf/compare.sh.in
+++ b/common/autoconf/compare.sh.in
@@ -33,7 +33,6 @@
 
 export OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@"
 export OPENJDK_TARGET_CPU="@OPENJDK_TARGET_CPU@"
-export OPENJDK_TARGET_CPU_LIBDIR="@OPENJDK_TARGET_CPU_LIBDIR@"
 export DEBUG_LEVEL="@DEBUG_LEVEL@"
 
 export AWK="@AWK@"
diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac
index 4879d05..e9aff62 100644
--- a/common/autoconf/configure.ac
+++ b/common/autoconf/configure.ac
@@ -205,7 +205,7 @@
 
 # Need toolchain to setup dtrace
 HOTSPOT_SETUP_DTRACE
-HOTSPOT_SETUP_JVM_FEATURES
+HOTSPOT_ENABLE_DISABLE_AOT
 HOTSPOT_ENABLE_DISABLE_GTEST
 
 ###############################################################################
@@ -220,6 +220,10 @@
 LIB_DETERMINE_DEPENDENCIES
 LIB_SETUP_LIBRARIES
 
+# Hotspot setup depends on lib checks (AOT needs libelf).
+
+HOTSPOT_SETUP_JVM_FEATURES
+
 ###############################################################################
 #
 # We need to do some final tweaking, when everything else is done.
diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4
index 767f6be..0621463 100644
--- a/common/autoconf/flags.m4
+++ b/common/autoconf/flags.m4
@@ -23,6 +23,101 @@
 # questions.
 #
 
+################################################################################
+#
+# Setup ABI profile (for arm)
+#
+AC_DEFUN([FLAGS_SETUP_ABI_PROFILE],
+[
+  AC_ARG_WITH(abi-profile, [AS_HELP_STRING([--with-abi-profile],
+      [specify ABI profile for ARM builds (arm-vfp-sflt,arm-vfp-hflt,arm-sflt, armv5-vfp-sflt,armv6-vfp-hflt,arm64,aarch64) @<:@toolchain dependent@:>@ ])])
+
+  if test "x$with_abi_profile" != x; then
+    if test "x$OPENJDK_TARGET_CPU" != xarm && \
+        test "x$OPENJDK_TARGET_CPU" != xaarch64; then
+      AC_MSG_ERROR([--with-abi-profile only available on arm/aarch64])
+    fi
+
+    OPENJDK_TARGET_ABI_PROFILE=$with_abi_profile
+    AC_MSG_CHECKING([for ABI profle])
+    AC_MSG_RESULT([$OPENJDK_TARGET_ABI_PROFILE])
+
+    if test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-vfp-sflt; then
+      ARM_FLOAT_TYPE=vfp-sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv7-a -mthumb'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-vfp-hflt; then
+      ARM_FLOAT_TYPE=vfp-hflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv7-a -mthumb'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-sflt; then
+      ARM_FLOAT_TYPE=sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv5t -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarmv5-vfp-sflt; then
+      ARM_FLOAT_TYPE=vfp-sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv5t -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarmv6-vfp-hflt; then
+      ARM_FLOAT_TYPE=vfp-hflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv6 -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm64; then
+      # No special flags, just need to trigger setting JDK_ARCH_ABI_PROP_NAME
+      ARM_FLOAT_TYPE=
+      ARM_ARCH_TYPE_FLAGS=
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xaarch64; then
+      # No special flags, just need to trigger setting JDK_ARCH_ABI_PROP_NAME
+      ARM_FLOAT_TYPE=
+      ARM_ARCH_TYPE_FLAGS=
+    else
+      AC_MSG_ERROR([Invalid ABI profile: "$OPENJDK_TARGET_ABI_PROFILE"])
+    fi
+
+    if test "x$ARM_FLOAT_TYPE" = xvfp-sflt; then
+      ARM_FLOAT_TYPE_FLAGS='-mfloat-abi=softfp -mfpu=vfp -DFLOAT_ARCH=-vfp-sflt'
+    elif test "x$ARM_FLOAT_TYPE" = xvfp-hflt; then
+      ARM_FLOAT_TYPE_FLAGS='-mfloat-abi=hard -mfpu=vfp -DFLOAT_ARCH=-vfp-hflt'
+    elif test "x$ARM_FLOAT_TYPE" = xsflt; then
+      ARM_FLOAT_TYPE_FLAGS='-msoft-float -mfpu=vfp'
+    fi
+    AC_MSG_CHECKING([for $ARM_FLOAT_TYPE floating point flags])
+    AC_MSG_RESULT([$ARM_FLOAT_TYPE_FLAGS])
+
+    AC_MSG_CHECKING([for arch type flags])
+    AC_MSG_RESULT([$ARM_ARCH_TYPE_FLAGS])
+
+    # Now set JDK_ARCH_ABI_PROP_NAME. This is equivalent to the last part of the
+    # autoconf target triplet.
+    [ JDK_ARCH_ABI_PROP_NAME=`$ECHO $OPENJDK_TARGET_AUTOCONF_NAME | $SED -e 's/.*-\([^-]*\)$/\1/'` ]
+    # Sanity check that it is a known ABI.
+    if test "x$JDK_ARCH_ABI_PROP_NAME" != xgnu && \
+        test "x$JDK_ARCH_ABI_PROP_NAME" != xgnueabi  && \
+        test "x$JDK_ARCH_ABI_PROP_NAME" != xgnueabihf; then
+          AC_MSG_WARN([Unknown autoconf target triplet ABI: "$JDK_ARCH_ABI_PROP_NAME"])
+    fi
+    AC_MSG_CHECKING([for ABI property name])
+    AC_MSG_RESULT([$JDK_ARCH_ABI_PROP_NAME])
+    AC_SUBST(JDK_ARCH_ABI_PROP_NAME)
+
+    # Pass these on to the open part of configure as if they were set using
+    # --with-extra-c[xx]flags.
+    EXTRA_CFLAGS="$EXTRA_CFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+    EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+    # Get rid of annoying "note: the mangling of 'va_list' has changed in GCC 4.4"
+    # FIXME: This should not really be set using extra_cflags.
+    if test "x$OPENJDK_TARGET_CPU" = xarm; then
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -Wno-psabi"
+        EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS -Wno-psabi"
+    fi
+    # Also add JDK_ARCH_ABI_PROP_NAME define, but only to CFLAGS.
+    EXTRA_CFLAGS="$EXTRA_CFLAGS -DJDK_ARCH_ABI_PROP_NAME='\"\$(JDK_ARCH_ABI_PROP_NAME)\"'"
+    # And pass the architecture flags to the linker as well
+    EXTRA_LDFLAGS="$EXTRA_LDFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+  fi
+
+  # When building with an abi profile, the name of that profile is appended on the
+  # bundle platform, which is used in bundle names.
+  if test "x$OPENJDK_TARGET_ABI_PROFILE" != x; then
+    OPENJDK_TARGET_BUNDLE_PLATFORM="$OPENJDK_TARGET_OS_BUNDLE-$OPENJDK_TARGET_ABI_PROFILE"
+  fi
+])
+
 # Reset the global CFLAGS/LDFLAGS variables and initialize them with the
 # corresponding configure arguments instead
 AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS],
@@ -306,9 +401,17 @@
       PICFLAG='-fPIC'
       SHARED_LIBRARY_FLAGS='-shared'
       SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1'
-      SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
       SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1'
       SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1'
+
+      # arm specific settings
+      if test "x$OPENJDK_TARGET_CPU" = "xarm"; then
+        # '-Wl,-z,origin' isn't used on arm.
+        SET_SHARED_LIBRARY_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1'
+      else
+        SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+      fi
+
     fi
   elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     if test "x$OPENJDK_TARGET_CPU" = xsparcv9; then
@@ -669,6 +772,7 @@
 AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK],
 [
 
+  FLAGS_SETUP_ABI_PROFILE
   FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER([TARGET])
   FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER([BUILD], [OPENJDK_BUILD_])
 
@@ -758,6 +862,7 @@
       arm )
         # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing
         $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing"
+        $2COMMON_CCXXFLAGS_JDK="${$2COMMON_CCXXFLAGS_JDK} -fsigned-char"
         ;;
       ppc )
         # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing
@@ -1160,26 +1265,25 @@
     $2JDKLIB_LIBS=""
   else
     $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
-        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)"
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base"
 
     if test "x$1" = "xTARGET"; then
-    # On some platforms (mac) the linker warns about non existing -L dirs.
-    # Add server first if available. Linking aginst client does not always produce the same results.
-      # Only add client/minimal dir if client/minimal is being built.
-    # Default to server for other variants.
-      if HOTSPOT_CHECK_JVM_VARIANT(server); then
-        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server"
-      elif HOTSPOT_CHECK_JVM_VARIANT(client); then
-        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/client"
-      elif HOTSPOT_CHECK_JVM_VARIANT(minimal); then
-        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/minimal"
-    else
-        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server"
-    fi
+      # On some platforms (mac) the linker warns about non existing -L dirs.
+      # For any of the variants server, client or minimal, the dir matches the
+      # variant name. The "main" variant should be used for linking. For the
+      # rest, the dir is just server.
+      if HOTSPOT_CHECK_JVM_VARIANT(server) || HOTSPOT_CHECK_JVM_VARIANT(client) \
+          || HOTSPOT_CHECK_JVM_VARIANT(minimal); then
+        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$JVM_VARIANT_MAIN"
+      else
+        $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
+      fi
     elif test "x$1" = "xBUILD"; then
       # When building a buildjdk, it's always only the server variant
       $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
-          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_$1_CPU_LIBDIR)/server"
+          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
     fi
 
     $2JDKLIB_LIBS="-ljava -ljvm"
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 79ef6b5..5cad333 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -654,6 +654,17 @@
 ENABLE_GENERATE_CLASSLIST
 BUILD_FAILURE_HANDLER
 ENABLE_INTREE_EC
+VALID_JVM_FEATURES
+JVM_FEATURES_custom
+JVM_FEATURES_zeroshark
+JVM_FEATURES_zero
+JVM_FEATURES_minimal
+JVM_FEATURES_core
+JVM_FEATURES_client
+JVM_FEATURES_server
+INCLUDE_GRAAL
+ELF_LIBS
+ELF_CFLAGS
 STLPORT_LIB
 LIBZIP_CAN_USE_MMAP
 LIBDL
@@ -692,14 +703,7 @@
 FIXPATH_DETACH_FLAG
 FIXPATH
 BUILD_GTEST
-VALID_JVM_FEATURES
-JVM_FEATURES_custom
-JVM_FEATURES_zeroshark
-JVM_FEATURES_zero
-JVM_FEATURES_minimal
-JVM_FEATURES_core
-JVM_FEATURES_client
-JVM_FEATURES_server
+ENABLE_AOT
 INCLUDE_DTRACE
 GCOV_ENABLED
 ZIP_EXTERNAL_DEBUG_SYMBOLS
@@ -749,6 +753,7 @@
 CFLAGS_JDKLIB
 MACOSX_VERSION_MIN
 CXXSTD_CXXFLAG
+JDK_ARCH_ABI_PROP_NAME
 CXX_O_FLAG_SIZE
 CXX_O_FLAG_NONE
 CXX_O_FLAG_DEBUG
@@ -863,12 +868,12 @@
 STATIC_BUILD
 IMPORT_MODULES_MAKE
 IMPORT_MODULES_SRC
+IMPORT_MODULES_MAN
+IMPORT_MODULES_LEGAL
 IMPORT_MODULES_CONF
 IMPORT_MODULES_LIBS
 IMPORT_MODULES_CMDS
 IMPORT_MODULES_CLASSES
-BUILD_HOTSPOT
-HOTSPOT_DIST
 BUILD_OUTPUT
 JDK_TOPDIR
 NASHORN_TOPDIR
@@ -961,6 +966,7 @@
 SPEC
 SDKROOT
 XCODEBUILD
+JVM_VARIANT_MAIN
 VALID_JVM_VARIANTS
 JVM_VARIANTS
 DEBUG_LEVEL
@@ -981,10 +987,8 @@
 OPENJDK_BUILD_CPU_BUNDLE
 OPENJDK_BUILD_OS_BUNDLE
 OPENJDK_BUILD_OS_EXPORT_DIR
-OPENJDK_BUILD_CPU_JLI_CFLAGS
 OPENJDK_BUILD_CPU_OSARCH
 OPENJDK_BUILD_CPU_ISADIR
-OPENJDK_BUILD_CPU_LIBDIR
 OPENJDK_BUILD_CPU_LEGACY_LIB
 OPENJDK_BUILD_CPU_LEGACY
 HOTSPOT_TARGET_CPU_DEFINE
@@ -998,10 +1002,8 @@
 OPENJDK_TARGET_CPU_BUNDLE
 OPENJDK_TARGET_OS_BUNDLE
 OPENJDK_TARGET_OS_EXPORT_DIR
-OPENJDK_TARGET_CPU_JLI_CFLAGS
 OPENJDK_TARGET_CPU_OSARCH
 OPENJDK_TARGET_CPU_ISADIR
-OPENJDK_TARGET_CPU_LIBDIR
 OPENJDK_TARGET_CPU_LEGACY_LIB
 OPENJDK_TARGET_CPU_LEGACY
 REQUIRED_OS_VERSION
@@ -1135,6 +1137,7 @@
 enable_debug
 with_debug_level
 with_jvm_variants
+with_cpu_port
 with_devkit
 with_sys_root
 with_sysroot
@@ -1184,14 +1187,14 @@
 with_toolchain_version
 with_build_devkit
 with_jtreg
+with_abi_profile
 enable_warnings_as_errors
 with_native_debug_symbols
 enable_debug_symbols
 enable_zip_debug_info
 enable_native_coverage
 enable_dtrace
-with_jvm_features
-with_jvm_interpreter
+enable_aot
 enable_hotspot_gtest
 with_stdc__lib
 with_msvcr_dll
@@ -1219,6 +1222,11 @@
 with_dxsdk
 with_dxsdk_lib
 with_dxsdk_include
+with_libelf
+with_libelf_include
+with_libelf_lib
+with_jvm_features
+with_jvm_interpreter
 enable_jtreg_failure_handler
 enable_generate_classlist
 with_num_cores
@@ -1343,6 +1351,8 @@
 PNG_LIBS
 LCMS_CFLAGS
 LCMS_LIBS
+ELF_CFLAGS
+ELF_LIBS
 ICECC_CMD
 ICECC_CREATE_ENV
 ICECC_WRAPPER
@@ -1988,6 +1998,10 @@
   --enable-dtrace[=yes/no/auto]
                           enable dtrace. Default is auto, where dtrace is
                           enabled if all dependencies are present.
+  --enable-aot[=yes/no/auto]
+                          enable ahead of time compilation feature. Default is
+                          auto, where aot is enabled if all dependencies are
+                          present.
   --disable-hotspot-gtest Disables building of the Hotspot unit tests
   --disable-freetype-bundling
                           disable bundling of the freetype library with the
@@ -2030,6 +2044,8 @@
   --with-jvm-variants     JVM variants (separated by commas) to build
                           (server,client,minimal,core,zero,zeroshark,custom)
                           [server]
+  --with-cpu-port         specify sources to use for Hotspot 64-bit ARM port
+                          (arm64,aarch64) [aarch64]
   --with-devkit           use this devkit for compilers, tools and resources
   --with-sys-root         alias for --with-sysroot for backwards compatability
   --with-sysroot          use this directory as sysroot
@@ -2097,9 +2113,8 @@
                           compatibility and is ignored
   --with-override-jdk     Deprecated. Option is kept for backwards
                           compatibility and is ignored
-  --with-import-hotspot   import hotspot binaries from this jdk image or
-                          hotspot build dist dir instead of building from
-                          source
+  --with-import_hotspot   Deprecated. Option is kept for backwards
+                          compatibility and is ignored
   --with-import-modules   import a set of prebuilt modules either as a zip
                           file or an exploded directory
   --with-toolchain-type   the toolchain type (or family) to use, use '--help'
@@ -2113,13 +2128,13 @@
                           dependent]
   --with-build-devkit     Devkit to use for the build platform toolchain
   --with-jtreg            Regression Test Harness [probed]
+  --with-abi-profile      specify ABI profile for ARM builds
+                          (arm-vfp-sflt,arm-vfp-hflt,arm-sflt,
+                          armv5-vfp-sflt,armv6-vfp-hflt,arm64,aarch64)
+                          [toolchain dependent]
   --with-native-debug-symbols
                           set the native debug symbol configuration (none,
                           internal, external, zipped) [varying]
-  --with-jvm-features     additional JVM features to enable (separated by
-                          comma), use '--help' to show possible values [none]
-  --with-jvm-interpreter  Deprecated. Option is kept for backwards
-                          compatibility and is ignored
   --with-stdc++lib=<static>,<dynamic>,<default>
                           force linking of the C++ runtime on Linux to either
                           static or dynamic, default is static with dynamic as
@@ -2166,6 +2181,15 @@
                           compatibility and is ignored
   --with-dxsdk-include    Deprecated. Option is kept for backwards
                           compatibility and is ignored
+  --with-libelf           specify prefix directory for the libelf package
+                          (expecting the libraries under PATH/lib and the
+                          headers under PATH/include)
+  --with-libelf-include   specify directory for the libelf include files
+  --with-libelf-lib       specify directory for the libelf library
+  --with-jvm-features     additional JVM features to enable (separated by
+                          comma), use '--help' to show possible values [none]
+  --with-jvm-interpreter  Deprecated. Option is kept for backwards
+                          compatibility and is ignored
   --with-num-cores        number of cores in the build system, e.g.
                           --with-num-cores=8 [probed]
   --with-memory-size      memory (in MB) available in the build system, e.g.
@@ -2295,6 +2319,8 @@
   PNG_LIBS    linker flags for PNG, overriding pkg-config
   LCMS_CFLAGS C compiler flags for LCMS, overriding pkg-config
   LCMS_LIBS   linker flags for LCMS, overriding pkg-config
+  ELF_CFLAGS  C compiler flags for ELF, overriding pkg-config
+  ELF_LIBS    linker flags for ELF, overriding pkg-config
   ICECC_CMD   Override default value for ICECC_CMD
   ICECC_CREATE_ENV
               Override default value for ICECC_CREATE_ENV
@@ -3997,6 +4023,12 @@
 # questions.
 #
 
+################################################################################
+#
+# Setup ABI profile (for arm)
+#
+
+
 # Reset the global CFLAGS/LDFLAGS variables and initialize them with the
 # corresponding configure arguments instead
 
@@ -4182,6 +4214,8 @@
       PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
     dtrace)
       PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;;
+    elf)
+      PKGHANDLER_COMMAND="sudo apt-get install libelf-dev" ;;
   esac
 }
 
@@ -4201,6 +4235,8 @@
       PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel libXi-devel" ;;
     ccache)
       PKGHANDLER_COMMAND="sudo yum install ccache" ;;
+    elf)
+      PKGHANDLER_COMMAND="sudo yum install elfutils-libelf-devel" ;;
   esac
 }
 
@@ -4253,7 +4289,8 @@
 
 # All valid JVM features, regardless of platform
 VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \
-    fprof vm-structs jni-check services management all-gcs nmt cds static-build"
+    graal fprof vm-structs jni-check services management all-gcs nmt cds \
+    static-build link-time-opt aot"
 
 # All valid JVM variants
 VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
@@ -4297,6 +4334,11 @@
 #
 
 
+################################################################################
+# Check if AOT should be enabled
+#
+
+
 ###############################################################################
 # Set up all JVM features for each JVM variant.
 #
@@ -4308,6 +4350,16 @@
 
 
 ################################################################################
+#
+# Specify which sources will be used to build the 64-bit ARM port
+#
+# --with-cpu-port=arm64   will use hotspot/src/cpu/arm
+# --with-cpu-port=aarch64 will use hotspot/src/cpu/aarch64
+#
+
+
+
+################################################################################
 # Check if gtest should be built
 #
 
@@ -4720,6 +4772,36 @@
 ################################################################################
 
 
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Setup libelf (ELF library)
+################################################################################
+
+
 
 ################################################################################
 # Determine which libraries are needed for this configuration
@@ -5088,7 +5170,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1481104795
+DATE_WHEN_GENERATED=1482168759
 
 ###############################################################################
 #
@@ -15790,15 +15872,6 @@
   fi
 
 
-  # This is the name of the cpu (but using i386 and amd64 instead of
-  # x86 and x86_64, respectively), preceeded by a /, to be used when
-  # locating libraries. On macosx, it's empty, though.
-  OPENJDK_TARGET_CPU_LIBDIR="/$OPENJDK_TARGET_CPU_LEGACY_LIB"
-  if test "x$OPENJDK_TARGET_OS" = xmacosx; then
-    OPENJDK_TARGET_CPU_LIBDIR=""
-  fi
-
-
   # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
   # /amd64 or /sparcv9. This string is appended to some library paths, like this:
   # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so
@@ -15830,16 +15903,6 @@
     # On all platforms except macosx, we replace x86_64 with amd64.
     OPENJDK_TARGET_CPU_JLI="amd64"
   fi
-  # Now setup the -D flags for building libjli.
-  OPENJDK_TARGET_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_TARGET_CPU_JLI\"'"
-  if test "x$OPENJDK_TARGET_OS" = xsolaris; then
-    if test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc; then
-      OPENJDK_TARGET_CPU_JLI_CFLAGS="$OPENJDK_TARGET_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'"
-    elif test "x$OPENJDK_TARGET_CPU_ARCH" = xx86; then
-      OPENJDK_TARGET_CPU_JLI_CFLAGS="$OPENJDK_TARGET_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'"
-    fi
-  fi
-
 
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
       OPENJDK_TARGET_OS_EXPORT_DIR=macosx
@@ -15965,15 +16028,6 @@
   fi
 
 
-  # This is the name of the cpu (but using i386 and amd64 instead of
-  # x86 and x86_64, respectively), preceeded by a /, to be used when
-  # locating libraries. On macosx, it's empty, though.
-  OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB"
-  if test "x$OPENJDK_BUILD_OS" = xmacosx; then
-    OPENJDK_BUILD_CPU_LIBDIR=""
-  fi
-
-
   # OPENJDK_BUILD_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
   # /amd64 or /sparcv9. This string is appended to some library paths, like this:
   # /usr/lib${OPENJDK_BUILD_CPU_ISADIR}/libexample.so
@@ -16005,16 +16059,6 @@
     # On all platforms except macosx, we replace x86_64 with amd64.
     OPENJDK_BUILD_CPU_JLI="amd64"
   fi
-  # Now setup the -D flags for building libjli.
-  OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'"
-  if test "x$OPENJDK_BUILD_OS" = xsolaris; then
-    if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then
-      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'"
-    elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then
-      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'"
-    fi
-  fi
-
 
   if test "x$OPENJDK_BUILD_OS" = xmacosx; then
       OPENJDK_BUILD_OS_EXPORT_DIR=macosx
@@ -16705,6 +16749,26 @@
 fi
 
 
+
+
+# Check whether --with-cpu-port was given.
+if test "${with_cpu_port+set}" = set; then :
+  withval=$with_cpu_port;
+fi
+
+
+  if test "x$with_cpu_port" != x; then
+    if test "x$OPENJDK_TARGET_CPU" != xaarch64; then
+      as_fn_error $? "--with-cpu-port only available on aarch64" "$LINENO" 5
+    fi
+    if test "x$with_cpu_port" != xarm64 && \
+        test "x$with_cpu_port" != xaarch64; then
+      as_fn_error $? "--with-cpu-port must specify arm64 or aarch64" "$LINENO" 5
+    fi
+    HOTSPOT_TARGET_CPU_PORT="$with_cpu_port"
+  fi
+
+
   if test "x$with_jvm_variants" = x; then
     with_jvm_variants="server"
   fi
@@ -16750,6 +16814,21 @@
     as_fn_error $? "You cannot build multiple variants with anything else than $VALID_MULTIPLE_JVM_VARIANTS." "$LINENO" 5
   fi
 
+  # The "main" variant is the one used by other libs to link against during the
+  # build.
+  if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then
+    MAIN_VARIANT_PRIO_ORDER="server client minimal"
+    for variant in $MAIN_VARIANT_PRIO_ORDER; do
+      if   [[ " $JVM_VARIANTS " =~ " $variant " ]]  ; then
+        JVM_VARIANT_MAIN="$variant"
+        break
+      fi
+    done
+  else
+    JVM_VARIANT_MAIN="$JVM_VARIANTS"
+  fi
+
+
 
 
 
@@ -30992,33 +31071,17 @@
 
   BUILD_OUTPUT="$OUTPUT_ROOT"
 
-
-  HOTSPOT_DIST="$OUTPUT_ROOT/hotspot/dist"
-  BUILD_HOTSPOT=true
+  JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk"
 
 
 
-# Check whether --with-import-hotspot was given.
+# Check whether --with-import_hotspot was given.
 if test "${with_import_hotspot+set}" = set; then :
-  withval=$with_import_hotspot;
+  withval=$with_import_hotspot; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-import_hotspot is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-import_hotspot is deprecated and will be ignored." >&2;}
 fi
 
-  if test "x$with_import_hotspot" != x; then
-    CURDIR="$PWD"
-    cd "$with_import_hotspot"
-    HOTSPOT_DIST="`pwd`"
-    cd "$CURDIR"
-    if ! (test -d $HOTSPOT_DIST/lib && test -d $HOTSPOT_DIST/jre/lib); then
-      as_fn_error $? "You have to import hotspot from a full jdk image or hotspot build dist dir!" "$LINENO" 5
-    fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if hotspot should be imported" >&5
-$as_echo_n "checking if hotspot should be imported... " >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes from $HOTSPOT_DIST" >&5
-$as_echo "yes from $HOTSPOT_DIST" >&6; }
-    BUILD_HOTSPOT=false
-  fi
 
-  JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk"
 
 
 
@@ -31189,6 +31252,12 @@
   if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then
     IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf"
   fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_legal"; then
+    IMPORT_MODULES_LEGAL="$IMPORT_MODULES_TOPDIR/modules_legal"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_man"; then
+    IMPORT_MODULES_MAN="$IMPORT_MODULES_TOPDIR/modules_man"
+  fi
   if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
     IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
   fi
@@ -31210,6 +31279,8 @@
 
 
 
+
+
 ###############################################################################
 #
 # Setup the toolchain (compilers etc), i.e. tools used to compile and process
@@ -49044,9 +49115,17 @@
       PICFLAG='-fPIC'
       SHARED_LIBRARY_FLAGS='-shared'
       SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN$1'
-      SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
       SET_SHARED_LIBRARY_NAME='-Wl,-soname=$1'
       SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=$1'
+
+      # arm specific settings
+      if test "x$OPENJDK_TARGET_CPU" = "xarm"; then
+        # '-Wl,-z,origin' isn't used on arm.
+        SET_SHARED_LIBRARY_ORIGIN='-Wl,-rpath,\$$$$ORIGIN$1'
+      else
+        SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN"
+      fi
+
     fi
   elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     if test "x$OPENJDK_TARGET_CPU" = xsparcv9; then
@@ -49636,6 +49715,108 @@
 
 
 
+
+# Check whether --with-abi-profile was given.
+if test "${with_abi_profile+set}" = set; then :
+  withval=$with_abi_profile;
+fi
+
+
+  if test "x$with_abi_profile" != x; then
+    if test "x$OPENJDK_TARGET_CPU" != xarm && \
+        test "x$OPENJDK_TARGET_CPU" != xaarch64; then
+      as_fn_error $? "--with-abi-profile only available on arm/aarch64" "$LINENO" 5
+    fi
+
+    OPENJDK_TARGET_ABI_PROFILE=$with_abi_profile
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ABI profle" >&5
+$as_echo_n "checking for ABI profle... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENJDK_TARGET_ABI_PROFILE" >&5
+$as_echo "$OPENJDK_TARGET_ABI_PROFILE" >&6; }
+
+    if test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-vfp-sflt; then
+      ARM_FLOAT_TYPE=vfp-sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv7-a -mthumb'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-vfp-hflt; then
+      ARM_FLOAT_TYPE=vfp-hflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv7-a -mthumb'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm-sflt; then
+      ARM_FLOAT_TYPE=sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv5t -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarmv5-vfp-sflt; then
+      ARM_FLOAT_TYPE=vfp-sflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv5t -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarmv6-vfp-hflt; then
+      ARM_FLOAT_TYPE=vfp-hflt
+      ARM_ARCH_TYPE_FLAGS='-march=armv6 -marm'
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xarm64; then
+      # No special flags, just need to trigger setting JDK_ARCH_ABI_PROP_NAME
+      ARM_FLOAT_TYPE=
+      ARM_ARCH_TYPE_FLAGS=
+    elif test "x$OPENJDK_TARGET_ABI_PROFILE" = xaarch64; then
+      # No special flags, just need to trigger setting JDK_ARCH_ABI_PROP_NAME
+      ARM_FLOAT_TYPE=
+      ARM_ARCH_TYPE_FLAGS=
+    else
+      as_fn_error $? "Invalid ABI profile: \"$OPENJDK_TARGET_ABI_PROFILE\"" "$LINENO" 5
+    fi
+
+    if test "x$ARM_FLOAT_TYPE" = xvfp-sflt; then
+      ARM_FLOAT_TYPE_FLAGS='-mfloat-abi=softfp -mfpu=vfp -DFLOAT_ARCH=-vfp-sflt'
+    elif test "x$ARM_FLOAT_TYPE" = xvfp-hflt; then
+      ARM_FLOAT_TYPE_FLAGS='-mfloat-abi=hard -mfpu=vfp -DFLOAT_ARCH=-vfp-hflt'
+    elif test "x$ARM_FLOAT_TYPE" = xsflt; then
+      ARM_FLOAT_TYPE_FLAGS='-msoft-float -mfpu=vfp'
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ARM_FLOAT_TYPE floating point flags" >&5
+$as_echo_n "checking for $ARM_FLOAT_TYPE floating point flags... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ARM_FLOAT_TYPE_FLAGS" >&5
+$as_echo "$ARM_FLOAT_TYPE_FLAGS" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arch type flags" >&5
+$as_echo_n "checking for arch type flags... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ARM_ARCH_TYPE_FLAGS" >&5
+$as_echo "$ARM_ARCH_TYPE_FLAGS" >&6; }
+
+    # Now set JDK_ARCH_ABI_PROP_NAME. This is equivalent to the last part of the
+    # autoconf target triplet.
+     JDK_ARCH_ABI_PROP_NAME=`$ECHO $OPENJDK_TARGET_AUTOCONF_NAME | $SED -e 's/.*-\([^-]*\)$/\1/'`
+    # Sanity check that it is a known ABI.
+    if test "x$JDK_ARCH_ABI_PROP_NAME" != xgnu && \
+        test "x$JDK_ARCH_ABI_PROP_NAME" != xgnueabi  && \
+        test "x$JDK_ARCH_ABI_PROP_NAME" != xgnueabihf; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unknown autoconf target triplet ABI: \"$JDK_ARCH_ABI_PROP_NAME\"" >&5
+$as_echo "$as_me: WARNING: Unknown autoconf target triplet ABI: \"$JDK_ARCH_ABI_PROP_NAME\"" >&2;}
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ABI property name" >&5
+$as_echo_n "checking for ABI property name... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JDK_ARCH_ABI_PROP_NAME" >&5
+$as_echo "$JDK_ARCH_ABI_PROP_NAME" >&6; }
+
+
+    # Pass these on to the open part of configure as if they were set using
+    # --with-extra-c[xx]flags.
+    EXTRA_CFLAGS="$EXTRA_CFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+    EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+    # Get rid of annoying "note: the mangling of 'va_list' has changed in GCC 4.4"
+    # FIXME: This should not really be set using extra_cflags.
+    if test "x$OPENJDK_TARGET_CPU" = xarm; then
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -Wno-psabi"
+        EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS -Wno-psabi"
+    fi
+    # Also add JDK_ARCH_ABI_PROP_NAME define, but only to CFLAGS.
+    EXTRA_CFLAGS="$EXTRA_CFLAGS -DJDK_ARCH_ABI_PROP_NAME='\"\$(JDK_ARCH_ABI_PROP_NAME)\"'"
+    # And pass the architecture flags to the linker as well
+    EXTRA_LDFLAGS="$EXTRA_LDFLAGS $ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
+  fi
+
+  # When building with an abi profile, the name of that profile is appended on the
+  # bundle platform, which is used in bundle names.
+  if test "x$OPENJDK_TARGET_ABI_PROFILE" != x; then
+    OPENJDK_TARGET_BUNDLE_PLATFORM="$OPENJDK_TARGET_OS_BUNDLE-$OPENJDK_TARGET_ABI_PROFILE"
+  fi
+
+
   # Special extras...
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     if test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then
@@ -49787,6 +49968,7 @@
       arm )
         # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing
         CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing"
+        COMMON_CCXXFLAGS_JDK="${COMMON_CCXXFLAGS_JDK} -fsigned-char"
         ;;
       ppc )
         # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing
@@ -50379,26 +50561,25 @@
     JDKLIB_LIBS=""
   else
     JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
-        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)"
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base"
 
     if test "xTARGET" = "xTARGET"; then
-    # On some platforms (mac) the linker warns about non existing -L dirs.
-    # Add server first if available. Linking aginst client does not always produce the same results.
-      # Only add client/minimal dir if client/minimal is being built.
-    # Default to server for other variants.
-      if   [[ " $JVM_VARIANTS " =~ " server " ]]  ; then
-        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
-      elif   [[ " $JVM_VARIANTS " =~ " client " ]]  ; then
-        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client"
-      elif   [[ " $JVM_VARIANTS " =~ " minimal " ]]  ; then
-        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal"
-    else
-        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
-    fi
+      # On some platforms (mac) the linker warns about non existing -L dirs.
+      # For any of the variants server, client or minimal, the dir matches the
+      # variant name. The "main" variant should be used for linking. For the
+      # rest, the dir is just server.
+      if   [[ " $JVM_VARIANTS " =~ " server " ]]   ||   [[ " $JVM_VARIANTS " =~ " client " ]]   \
+          ||   [[ " $JVM_VARIANTS " =~ " minimal " ]]  ; then
+        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$JVM_VARIANT_MAIN"
+      else
+        JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
+      fi
     elif test "xTARGET" = "xBUILD"; then
       # When building a buildjdk, it's always only the server variant
       JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
-          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
+          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
     fi
 
     JDKLIB_LIBS="-ljava -ljvm"
@@ -50610,6 +50791,7 @@
       arm )
         # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing
         OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing"
+        OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="${OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK} -fsigned-char"
         ;;
       ppc )
         # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing
@@ -51202,26 +51384,25 @@
     OPENJDK_BUILD_JDKLIB_LIBS=""
   else
     OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
-        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)"
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base"
 
     if test "xBUILD" = "xTARGET"; then
-    # On some platforms (mac) the linker warns about non existing -L dirs.
-    # Add server first if available. Linking aginst client does not always produce the same results.
-      # Only add client/minimal dir if client/minimal is being built.
-    # Default to server for other variants.
-      if   [[ " $JVM_VARIANTS " =~ " server " ]]  ; then
-        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server"
-      elif   [[ " $JVM_VARIANTS " =~ " client " ]]  ; then
-        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/client"
-      elif   [[ " $JVM_VARIANTS " =~ " minimal " ]]  ; then
-        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/minimal"
-    else
-        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server"
-    fi
+      # On some platforms (mac) the linker warns about non existing -L dirs.
+      # For any of the variants server, client or minimal, the dir matches the
+      # variant name. The "main" variant should be used for linking. For the
+      # rest, the dir is just server.
+      if   [[ " $JVM_VARIANTS " =~ " server " ]]   ||   [[ " $JVM_VARIANTS " =~ " client " ]]   \
+          ||   [[ " $JVM_VARIANTS " =~ " minimal " ]]  ; then
+        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$JVM_VARIANT_MAIN"
+      else
+        OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
+            -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
+      fi
     elif test "xBUILD" = "xBUILD"; then
       # When building a buildjdk, it's always only the server variant
       OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
-          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_BUILD_CPU_LIBDIR)/server"
+          -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server"
     fi
 
     OPENJDK_BUILD_JDKLIB_LIBS="-ljava -ljvm"
@@ -52740,113 +52921,52 @@
 
 
 
-  # The user can in some cases supply additional jvm features. For the custom
-  # variant, this defines the entire variant.
-
-# Check whether --with-jvm-features was given.
-if test "${with_jvm_features+set}" = set; then :
-  withval=$with_jvm_features;
+  # Check whether --enable-aot was given.
+if test "${enable_aot+set}" = set; then :
+  enableval=$enable_aot;
 fi
 
-  if test "x$with_jvm_features" != x; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking additional JVM features" >&5
-$as_echo_n "checking additional JVM features... " >&6; }
-    JVM_FEATURES=`$ECHO $with_jvm_features | $SED -e 's/,/ /g'`
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_FEATURES" >&5
-$as_echo "$JVM_FEATURES" >&6; }
-  fi
 
-  # Verify that dependencies are met for explicitly set features.
-  if   [[ " $JVM_FEATURES " =~ " jvmti " ]]   && !   [[ " $JVM_FEATURES " =~ " services " ]]  ; then
-    as_fn_error $? "Specified JVM feature 'jvmti' requires feature 'services'" "$LINENO" 5
-  fi
-
-  if   [[ " $JVM_FEATURES " =~ " management " ]]   && !   [[ " $JVM_FEATURES " =~ " nmt " ]]  ; then
-    as_fn_error $? "Specified JVM feature 'management' requires feature 'nmt'" "$LINENO" 5
-  fi
-
-  if   [[ " $JVM_FEATURES " =~ " jvmci " ]]   && ! (  [[ " $JVM_FEATURES " =~ " compiler1 " ]]   ||   [[ " $JVM_FEATURES " =~ " compiler2 " ]]  ); then
-    as_fn_error $? "Specified JVM feature 'jvmci' requires feature 'compiler2' or 'compiler1'" "$LINENO" 5
-  fi
-
-  if   [[ " $JVM_FEATURES " =~ " compiler2 " ]]   && !   [[ " $JVM_FEATURES " =~ " all-gcs " ]]  ; then
-    as_fn_error $? "Specified JVM feature 'compiler2' requires feature 'all-gcs'" "$LINENO" 5
-  fi
-
-  if   [[ " $JVM_FEATURES " =~ " vm-structs " ]]   && !   [[ " $JVM_FEATURES " =~ " all-gcs " ]]  ; then
-    as_fn_error $? "Specified JVM feature 'vm-structs' requires feature 'all-gcs'" "$LINENO" 5
-  fi
-
-  # Turn on additional features based on other parts of configure
-  if test "x$INCLUDE_DTRACE" = "xtrue"; then
-    JVM_FEATURES="$JVM_FEATURES dtrace"
+  if test "x$enable_aot" = "x" || test "x$enable_aot" = "xauto"; then
+    ENABLE_AOT="true"
+  elif test "x$enable_aot" = "xyes"; then
+    ENABLE_AOT="true"
+  elif test "x$enable_aot" = "xno"; then
+    ENABLE_AOT="false"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if aot should be enabled" >&5
+$as_echo_n "checking if aot should be enabled... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5
+$as_echo "no, forced" >&6; }
   else
-    if   [[ " $JVM_FEATURES " =~ " dtrace " ]]  ; then
-      as_fn_error $? "To enable dtrace, you must use --enable-dtrace" "$LINENO" 5
+    as_fn_error $? "Invalid value for --enable-aot: $enable_aot" "$LINENO" 5
+  fi
+
+  if test "x$ENABLE_AOT" = "xtrue"; then
+    # Only enable AOT on linux-X64.
+    if test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = "xlinux-x86_64"; then
+      if test -e "$HOTSPOT_TOPDIR/src/jdk.aot"; then
+        if test -e "$HOTSPOT_TOPDIR/src/jdk.vm.compiler"; then
+          ENABLE_AOT="true"
+        else
+          ENABLE_AOT="false"
+          if test "x$enable_aot" = "xyes"; then
+            as_fn_error $? "Cannot build AOT without hotspot/src/jdk.vm.compiler sources. Remove --enable-aot." "$LINENO" 5
+          fi
+        fi
+      else
+        ENABLE_AOT="false"
+        if test "x$enable_aot" = "xyes"; then
+          as_fn_error $? "Cannot build AOT without hotspot/src/jdk.aot sources. Remove --enable-aot." "$LINENO" 5
+        fi
+      fi
+    else
+      ENABLE_AOT="false"
+      if test "x$enable_aot" = "xyes"; then
+        as_fn_error $? "AOT is currently only supported on Linux-x86_64. Remove --enable-aot." "$LINENO" 5
+      fi
     fi
   fi
 
-  if test "x$STATIC_BUILD" = "xtrue"; then
-    JVM_FEATURES="$JVM_FEATURES static-build"
-  else
-    if   [[ " $JVM_FEATURES " =~ " static-build " ]]  ; then
-      as_fn_error $? "To enable static-build, you must use --enable-static-build" "$LINENO" 5
-    fi
-  fi
-
-  if !   [[ " $JVM_VARIANTS " =~ " zero " ]]   && !   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
-    if   [[ " $JVM_FEATURES " =~ " zero " ]]  ; then
-      as_fn_error $? "To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark" "$LINENO" 5
-    fi
-  fi
-
-  if !   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
-    if   [[ " $JVM_FEATURES " =~ " shark " ]]  ; then
-      as_fn_error $? "To enable shark, you must use --with-jvm-variants=zeroshark" "$LINENO" 5
-    fi
-  fi
-
-  # Only enable jvmci on x86_64, sparcv9 and aarch64.
-  if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \
-      test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \
-      test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then
-    JVM_FEATURES_jvmci="jvmci"
-  else
-    JVM_FEATURES_jvmci=""
-  fi
-
-  # All variants but minimal (and custom) get these features
-  NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds"
-
-  # Enable features depending on variant.
-  JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
-  JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
-  JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
-  JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES"
-  JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES"
-  JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES"
-  JVM_FEATURES_custom="$JVM_FEATURES"
-
-
-
-
-
-
-
-
-
-  # Used for verification of Makefiles by check-jvm-feature
-
-
-  # We don't support --with-jvm-interpreter anymore, use zero instead.
-
-
-# Check whether --with-jvm-interpreter was given.
-if test "${with_jvm_interpreter+set}" = set; then :
-  withval=$with_jvm_interpreter; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&5
-$as_echo "$as_me: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&2;}
-fi
-
 
 
 
@@ -63814,6 +63934,275 @@
 
 
 
+# Check whether --with-libelf was given.
+if test "${with_libelf+set}" = set; then :
+  withval=$with_libelf;
+fi
+
+
+# Check whether --with-libelf-include was given.
+if test "${with_libelf_include+set}" = set; then :
+  withval=$with_libelf_include;
+fi
+
+
+# Check whether --with-libelf-lib was given.
+if test "${with_libelf_lib+set}" = set; then :
+  withval=$with_libelf_lib;
+fi
+
+
+  if test "x$ENABLE_AOT" = xfalse; then
+    if (test "x${with_libelf}" != x && test "x${with_libelf}" != xno) || \
+        (test "x${with_libelf_include}" != x && test "x${with_libelf_include}" != xno) || \
+        (test "x${with_libelf_lib}" != x && test "x${with_libelf_lib}" != xno); then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libelf is not used, so --with-libelf[-*] is ignored" >&5
+$as_echo "$as_me: WARNING: libelf is not used, so --with-libelf[-*] is ignored" >&2;}
+    fi
+    LIBELF_CFLAGS=
+    LIBELF_LIBS=
+  else
+    LIBELF_FOUND=no
+
+    if test "x${with_libelf}" = xno || test "x${with_libelf_include}" = xno || test "x${with_libelf_lib}" = xno; then
+      ENABLE_AOT="false"
+      if test "x${enable_aot}" = xyes; then
+        as_fn_error $? "libelf is explicitly disabled, cannot build AOT. Enable libelf or remove --enable-aot to disable AOT." "$LINENO" 5
+      fi
+    else
+      if test "x${with_libelf}" != x; then
+        ELF_LIBS="-L${with_libelf}/lib -lelf"
+        ELF_CFLAGS="-I${with_libelf}/include"
+        LIBELF_FOUND=yes
+      fi
+      if test "x${with_libelf_include}" != x; then
+        ELF_CFLAGS="-I${with_libelf_include}"
+        LIBELF_FOUND=yes
+      fi
+      if test "x${with_libelf_lib}" != x; then
+        ELF_LIBS="-L${with_libelf_lib} -lelf"
+        LIBELF_FOUND=yes
+      fi
+      # Do not try pkg-config if we have a sysroot set.
+      if test "x$SYSROOT" = x; then
+        if test "x$LIBELF_FOUND" = xno; then
+          # Figure out ELF_CFLAGS and ELF_LIBS
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5
+$as_echo_n "checking for ELF... " >&6; }
+
+if test -n "$ELF_CFLAGS"; then
+    pkg_cv_ELF_CFLAGS="$ELF_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libelf\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libelf") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ELF_CFLAGS=`$PKG_CONFIG --cflags "libelf" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ELF_LIBS"; then
+    pkg_cv_ELF_LIBS="$ELF_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libelf\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libelf") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ELF_LIBS=`$PKG_CONFIG --libs "libelf" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ELF_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libelf" 2>&1`
+        else
+	        ELF_PKG_ERRORS=`$PKG_CONFIG --print-errors "libelf" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ELF_PKG_ERRORS" >&5
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+                LIBELF_FOUND=no
+elif test $pkg_failed = untried; then
+	LIBELF_FOUND=no
+else
+	ELF_CFLAGS=$pkg_cv_ELF_CFLAGS
+	ELF_LIBS=$pkg_cv_ELF_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	LIBELF_FOUND=yes
+fi
+        fi
+      fi
+      if test "x$LIBELF_FOUND" = xno; then
+        for ac_header in libelf.h
+do :
+  ac_fn_cxx_check_header_mongrel "$LINENO" "libelf.h" "ac_cv_header_libelf_h" "$ac_includes_default"
+if test "x$ac_cv_header_libelf_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBELF_H 1
+_ACEOF
+
+              LIBELF_FOUND=yes
+              ELF_CFLAGS=
+              ELF_LIBS=-lelf
+
+else
+  LIBELF_FOUND=no
+
+fi
+
+done
+
+      fi
+      if test "x$LIBELF_FOUND" = xno; then
+        ENABLE_AOT="false"
+
+  # Print a helpful message on how to acquire the necessary build dependency.
+  # elf is the help tag: freetype, cups, alsa etc
+  MISSING_DEPENDENCY=elf
+
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    cygwin_help $MISSING_DEPENDENCY
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    msys_help $MISSING_DEPENDENCY
+  else
+    PKGHANDLER_COMMAND=
+
+    case $PKGHANDLER in
+      apt-get)
+        apt_help     $MISSING_DEPENDENCY ;;
+      yum)
+        yum_help     $MISSING_DEPENDENCY ;;
+      port)
+        port_help    $MISSING_DEPENDENCY ;;
+      pkgutil)
+        pkgutil_help $MISSING_DEPENDENCY ;;
+      pkgadd)
+        pkgadd_help  $MISSING_DEPENDENCY ;;
+    esac
+
+    if test "x$PKGHANDLER_COMMAND" != x; then
+      HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'."
+    fi
+  fi
+
+        if test "x${enable_aot}" = xyes; then
+          as_fn_error $? "libelf not found, cannot build AOT. Remove --enable-aot to disable AOT or: $HELP_MSG" "$LINENO" 5
+        else
+          { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libelf not found, cannot build AOT. $HELP_MSG" >&5
+$as_echo "$as_me: WARNING: libelf not found, cannot build AOT. $HELP_MSG" >&2;}
+        fi
+      else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libelf works" >&5
+$as_echo_n "checking if libelf works... " >&6; }
+        ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+        OLD_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $ELF_CFLAGS"
+        OLD_LIBS="$LIBS"
+        LIBS="$LIBS $ELF_LIBS"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <libelf.h>
+int
+main ()
+{
+
+              elf_version(0);
+              return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  LIBELF_WORKS=yes
+else
+  LIBELF_WORKS=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        CFLAGS="$OLD_CFLAGS"
+        LIBS="$OLD_LIBS"
+        ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBELF_WORKS" >&5
+$as_echo "$LIBELF_WORKS" >&6; }
+
+        if test "x$LIBELF_WORKS" = xno; then
+          ENABLE_AOT="false"
+
+  # Print a helpful message on how to acquire the necessary build dependency.
+  # elf is the help tag: freetype, cups, alsa etc
+  MISSING_DEPENDENCY=elf
+
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    cygwin_help $MISSING_DEPENDENCY
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    msys_help $MISSING_DEPENDENCY
+  else
+    PKGHANDLER_COMMAND=
+
+    case $PKGHANDLER in
+      apt-get)
+        apt_help     $MISSING_DEPENDENCY ;;
+      yum)
+        yum_help     $MISSING_DEPENDENCY ;;
+      port)
+        port_help    $MISSING_DEPENDENCY ;;
+      pkgutil)
+        pkgutil_help $MISSING_DEPENDENCY ;;
+      pkgadd)
+        pkgadd_help  $MISSING_DEPENDENCY ;;
+    esac
+
+    if test "x$PKGHANDLER_COMMAND" != x; then
+      HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'."
+    fi
+  fi
+
+          if test "x$enable_aot" = "xyes"; then
+            as_fn_error $? "Found libelf but could not link and compile with it. Remove --enable-aot to disable AOT or: $HELP_MSG" "$LINENO" 5
+          else
+            { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Found libelf but could not link and compile with it. $HELP_MSG" >&5
+$as_echo "$as_me: WARNING: Found libelf but could not link and compile with it. $HELP_MSG" >&2;}
+          fi
+        fi
+      fi
+    fi
+  fi
 
 
 
@@ -63825,6 +64214,194 @@
 
 
 
+
+
+
+
+
+
+
+# Hotspot setup depends on lib checks (AOT needs libelf).
+
+
+  # The user can in some cases supply additional jvm features. For the custom
+  # variant, this defines the entire variant.
+
+# Check whether --with-jvm-features was given.
+if test "${with_jvm_features+set}" = set; then :
+  withval=$with_jvm_features;
+fi
+
+  if test "x$with_jvm_features" != x; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking additional JVM features" >&5
+$as_echo_n "checking additional JVM features... " >&6; }
+    JVM_FEATURES=`$ECHO $with_jvm_features | $SED -e 's/,/ /g'`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JVM_FEATURES" >&5
+$as_echo "$JVM_FEATURES" >&6; }
+  fi
+
+  # Override hotspot cpu definitions for ARM platforms
+  if test "x$OPENJDK_TARGET_CPU" = xarm; then
+    HOTSPOT_TARGET_CPU=arm_32
+    HOTSPOT_TARGET_CPU_DEFINE="ARM32"
+    JVM_LDFLAGS="$JVM_LDFLAGS -fsigned-char"
+    JVM_CFLAGS="$JVM_CFLAGS -DARM -fsigned-char"
+  elif test "x$OPENJDK_TARGET_CPU" = xaarch64 && test "x$HOTSPOT_TARGET_CPU_PORT" = xarm64; then
+    HOTSPOT_TARGET_CPU=arm_64
+    HOTSPOT_TARGET_CPU_ARCH=arm
+    JVM_LDFLAGS="$JVM_LDFLAGS -fsigned-char"
+    JVM_CFLAGS="$JVM_CFLAGS -DARM -fsigned-char"
+  fi
+
+  # Verify that dependencies are met for explicitly set features.
+  if   [[ " $JVM_FEATURES " =~ " jvmti " ]]   && !   [[ " $JVM_FEATURES " =~ " services " ]]  ; then
+    as_fn_error $? "Specified JVM feature 'jvmti' requires feature 'services'" "$LINENO" 5
+  fi
+
+  if   [[ " $JVM_FEATURES " =~ " management " ]]   && !   [[ " $JVM_FEATURES " =~ " nmt " ]]  ; then
+    as_fn_error $? "Specified JVM feature 'management' requires feature 'nmt'" "$LINENO" 5
+  fi
+
+  if   [[ " $JVM_FEATURES " =~ " jvmci " ]]   && ! (  [[ " $JVM_FEATURES " =~ " compiler1 " ]]   ||   [[ " $JVM_FEATURES " =~ " compiler2 " ]]  ); then
+    as_fn_error $? "Specified JVM feature 'jvmci' requires feature 'compiler2' or 'compiler1'" "$LINENO" 5
+  fi
+
+  if   [[ " $JVM_FEATURES " =~ " compiler2 " ]]   && !   [[ " $JVM_FEATURES " =~ " all-gcs " ]]  ; then
+    as_fn_error $? "Specified JVM feature 'compiler2' requires feature 'all-gcs'" "$LINENO" 5
+  fi
+
+  if   [[ " $JVM_FEATURES " =~ " vm-structs " ]]   && !   [[ " $JVM_FEATURES " =~ " all-gcs " ]]  ; then
+    as_fn_error $? "Specified JVM feature 'vm-structs' requires feature 'all-gcs'" "$LINENO" 5
+  fi
+
+  # Turn on additional features based on other parts of configure
+  if test "x$INCLUDE_DTRACE" = "xtrue"; then
+    JVM_FEATURES="$JVM_FEATURES dtrace"
+  else
+    if   [[ " $JVM_FEATURES " =~ " dtrace " ]]  ; then
+      as_fn_error $? "To enable dtrace, you must use --enable-dtrace" "$LINENO" 5
+    fi
+  fi
+
+  if test "x$STATIC_BUILD" = "xtrue"; then
+    JVM_FEATURES="$JVM_FEATURES static-build"
+  else
+    if   [[ " $JVM_FEATURES " =~ " static-build " ]]  ; then
+      as_fn_error $? "To enable static-build, you must use --enable-static-build" "$LINENO" 5
+    fi
+  fi
+
+  if !   [[ " $JVM_VARIANTS " =~ " zero " ]]   && !   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
+    if   [[ " $JVM_FEATURES " =~ " zero " ]]  ; then
+      as_fn_error $? "To enable zero/zeroshark, you must use --with-jvm-variants=zero/zeroshark" "$LINENO" 5
+    fi
+  fi
+
+  if !   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
+    if   [[ " $JVM_FEATURES " =~ " shark " ]]  ; then
+      as_fn_error $? "To enable shark, you must use --with-jvm-variants=zeroshark" "$LINENO" 5
+    fi
+  fi
+
+  # Only enable jvmci on x86_64, sparcv9 and aarch64.
+  if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \
+     test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \
+     test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then
+    JVM_FEATURES_jvmci="jvmci"
+  else
+    JVM_FEATURES_jvmci=""
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if jdk.vm.compiler should be built" >&5
+$as_echo_n "checking if jdk.vm.compiler should be built... " >&6; }
+  if   [[ " $JVM_FEATURES " =~ " graal " ]]  ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5
+$as_echo "yes, forced" >&6; }
+    if test "x$JVM_FEATURES_jvmci" != "xjvmci" ; then
+      as_fn_error $? "Specified JVM feature 'graal' requires feature 'jvmci'" "$LINENO" 5
+    fi
+    INCLUDE_GRAAL="true"
+  else
+    # By default enable graal build where AOT is available
+    if test "x$ENABLE_AOT" = "xtrue"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+      JVM_FEATURES_graal="graal"
+      INCLUDE_GRAAL="true"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+      JVM_FEATURES_graal=""
+      INCLUDE_GRAAL="false"
+    fi
+  fi
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if aot should be enabled" >&5
+$as_echo_n "checking if aot should be enabled... " >&6; }
+  if test "x$ENABLE_AOT" = "xtrue"; then
+    if test "x$enable_aot" = "xyes"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5
+$as_echo "yes, forced" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    fi
+    JVM_FEATURES_aot="aot"
+  else
+    if test "x$enable_aot" = "xno"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5
+$as_echo "no, forced" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    JVM_FEATURES_aot=""
+  fi
+
+  if test "x$OPENJDK_TARGET_CPU" = xarm ; then
+    # Default to use link time optimizations on minimal on arm
+    JVM_FEATURES_link_time_opt="link-time-opt"
+  else
+    JVM_FEATURES_link_time_opt=""
+  fi
+
+  # All variants but minimal (and custom) get these features
+  NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds"
+
+  # Enable features depending on variant.
+  JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
+  JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
+  JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
+  JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES $JVM_FEATURES_link_time_opt"
+  JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES"
+  JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES"
+  JVM_FEATURES_custom="$JVM_FEATURES"
+
+
+
+
+
+
+
+
+
+  # Used for verification of Makefiles by check-jvm-feature
+
+
+  # We don't support --with-jvm-interpreter anymore, use zero instead.
+
+
+# Check whether --with-jvm-interpreter was given.
+if test "${with_jvm_interpreter+set}" = set; then :
+  withval=$with_jvm_interpreter; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-jvm-interpreter is deprecated and will be ignored." >&2;}
+fi
+
+
+
+
 ###############################################################################
 #
 # We need to do some final tweaking, when everything else is done.
diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4
index 98e2a92..76824e5 100644
--- a/common/autoconf/help.m4
+++ b/common/autoconf/help.m4
@@ -121,6 +121,8 @@
       PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
     dtrace)
       PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;;
+    elf)
+      PKGHANDLER_COMMAND="sudo apt-get install libelf-dev" ;;
   esac
 }
 
@@ -140,6 +142,8 @@
       PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel libXi-devel" ;;
     ccache)
       PKGHANDLER_COMMAND="sudo yum install ccache" ;;
+    elf)
+      PKGHANDLER_COMMAND="sudo yum install elfutils-libelf-devel" ;;
   esac
 }
 
diff --git a/common/autoconf/hotspot.m4 b/common/autoconf/hotspot.m4
index cda292e..b12914b 100644
--- a/common/autoconf/hotspot.m4
+++ b/common/autoconf/hotspot.m4
@@ -25,7 +25,8 @@
 
 # All valid JVM features, regardless of platform
 VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \
-    fprof vm-structs jni-check services management all-gcs nmt cds static-build"
+    graal fprof vm-structs jni-check services management all-gcs nmt cds \
+    static-build link-time-opt aot"
 
 # All valid JVM variants
 VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
@@ -69,6 +70,8 @@
   AC_ARG_WITH([jvm-variants], [AS_HELP_STRING([--with-jvm-variants],
       [JVM variants (separated by commas) to build (server,client,minimal,core,zero,zeroshark,custom) @<:@server@:>@])])
 
+  SETUP_HOTSPOT_TARGET_CPU_PORT
+
   if test "x$with_jvm_variants" = x; then
     with_jvm_variants="server"
   fi
@@ -111,8 +114,23 @@
     AC_MSG_ERROR([You cannot build multiple variants with anything else than $VALID_MULTIPLE_JVM_VARIANTS.])
   fi
 
+  # The "main" variant is the one used by other libs to link against during the
+  # build.
+  if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then
+    MAIN_VARIANT_PRIO_ORDER="server client minimal"
+    for variant in $MAIN_VARIANT_PRIO_ORDER; do
+      if HOTSPOT_CHECK_JVM_VARIANT($variant); then
+        JVM_VARIANT_MAIN="$variant"
+        break
+      fi
+    done
+  else
+    JVM_VARIANT_MAIN="$JVM_VARIANTS"
+  fi
+
   AC_SUBST(JVM_VARIANTS)
   AC_SUBST(VALID_JVM_VARIANTS)
+  AC_SUBST(JVM_VARIANT_MAIN)
 
   if HOTSPOT_CHECK_JVM_VARIANT(zero) || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then
     # zero behaves as a platform and rewrites these values. This is really weird. :(
@@ -174,6 +192,55 @@
   AC_SUBST(INCLUDE_DTRACE)
 ])
 
+################################################################################
+# Check if AOT should be enabled
+#
+AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_AOT],
+[
+  AC_ARG_ENABLE([aot], [AS_HELP_STRING([--enable-aot@<:@=yes/no/auto@:>@],
+      [enable ahead of time compilation feature. Default is auto, where aot is enabled if all dependencies are present.])])
+
+  if test "x$enable_aot" = "x" || test "x$enable_aot" = "xauto"; then
+    ENABLE_AOT="true"
+  elif test "x$enable_aot" = "xyes"; then
+    ENABLE_AOT="true"
+  elif test "x$enable_aot" = "xno"; then
+    ENABLE_AOT="false"
+    AC_MSG_CHECKING([if aot should be enabled])
+    AC_MSG_RESULT([no, forced])
+  else
+    AC_MSG_ERROR([Invalid value for --enable-aot: $enable_aot])
+  fi
+
+  if test "x$ENABLE_AOT" = "xtrue"; then
+    # Only enable AOT on linux-X64.
+    if test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = "xlinux-x86_64"; then
+      if test -e "$HOTSPOT_TOPDIR/src/jdk.aot"; then
+        if test -e "$HOTSPOT_TOPDIR/src/jdk.vm.compiler"; then
+          ENABLE_AOT="true"
+        else
+          ENABLE_AOT="false"
+          if test "x$enable_aot" = "xyes"; then
+            AC_MSG_ERROR([Cannot build AOT without hotspot/src/jdk.vm.compiler sources. Remove --enable-aot.])
+          fi
+        fi
+      else
+        ENABLE_AOT="false"
+        if test "x$enable_aot" = "xyes"; then
+          AC_MSG_ERROR([Cannot build AOT without hotspot/src/jdk.aot sources. Remove --enable-aot.])
+        fi
+      fi
+    else
+      ENABLE_AOT="false"
+      if test "x$enable_aot" = "xyes"; then
+        AC_MSG_ERROR([AOT is currently only supported on Linux-x86_64. Remove --enable-aot.])
+      fi
+    fi
+  fi
+
+  AC_SUBST(ENABLE_AOT)
+])
+
 ###############################################################################
 # Set up all JVM features for each JVM variant.
 #
@@ -189,6 +256,19 @@
     AC_MSG_RESULT([$JVM_FEATURES])
   fi
 
+  # Override hotspot cpu definitions for ARM platforms
+  if test "x$OPENJDK_TARGET_CPU" = xarm; then
+    HOTSPOT_TARGET_CPU=arm_32
+    HOTSPOT_TARGET_CPU_DEFINE="ARM32"
+    JVM_LDFLAGS="$JVM_LDFLAGS -fsigned-char"
+    JVM_CFLAGS="$JVM_CFLAGS -DARM -fsigned-char"
+  elif test "x$OPENJDK_TARGET_CPU" = xaarch64 && test "x$HOTSPOT_TARGET_CPU_PORT" = xarm64; then
+    HOTSPOT_TARGET_CPU=arm_64
+    HOTSPOT_TARGET_CPU_ARCH=arm
+    JVM_LDFLAGS="$JVM_LDFLAGS -fsigned-char"
+    JVM_CFLAGS="$JVM_CFLAGS -DARM -fsigned-char"
+  fi
+
   # Verify that dependencies are met for explicitly set features.
   if HOTSPOT_CHECK_JVM_FEATURE(jvmti) && ! HOTSPOT_CHECK_JVM_FEATURE(services); then
     AC_MSG_ERROR([Specified JVM feature 'jvmti' requires feature 'services'])
@@ -241,21 +321,67 @@
 
   # Only enable jvmci on x86_64, sparcv9 and aarch64.
   if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \
-      test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \
-      test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then
+     test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \
+     test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then
     JVM_FEATURES_jvmci="jvmci"
   else
     JVM_FEATURES_jvmci=""
   fi
 
+  AC_MSG_CHECKING([if jdk.vm.compiler should be built])
+  if HOTSPOT_CHECK_JVM_FEATURE(graal); then
+    AC_MSG_RESULT([yes, forced])
+    if test "x$JVM_FEATURES_jvmci" != "xjvmci" ; then
+      AC_MSG_ERROR([Specified JVM feature 'graal' requires feature 'jvmci'])
+    fi
+    INCLUDE_GRAAL="true"
+  else
+    # By default enable graal build where AOT is available
+    if test "x$ENABLE_AOT" = "xtrue"; then
+      AC_MSG_RESULT([yes])
+      JVM_FEATURES_graal="graal"
+      INCLUDE_GRAAL="true"
+    else
+      AC_MSG_RESULT([no])
+      JVM_FEATURES_graal=""
+      INCLUDE_GRAAL="false"
+    fi
+  fi
+
+  AC_SUBST(INCLUDE_GRAAL)
+
+  AC_MSG_CHECKING([if aot should be enabled])
+  if test "x$ENABLE_AOT" = "xtrue"; then
+    if test "x$enable_aot" = "xyes"; then
+      AC_MSG_RESULT([yes, forced])
+    else
+      AC_MSG_RESULT([yes])
+    fi
+    JVM_FEATURES_aot="aot"
+  else
+    if test "x$enable_aot" = "xno"; then
+      AC_MSG_RESULT([no, forced])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    JVM_FEATURES_aot=""
+  fi
+
+  if test "x$OPENJDK_TARGET_CPU" = xarm ; then
+    # Default to use link time optimizations on minimal on arm
+    JVM_FEATURES_link_time_opt="link-time-opt"
+  else
+    JVM_FEATURES_link_time_opt=""
+  fi
+
   # All variants but minimal (and custom) get these features
   NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds"
 
   # Enable features depending on variant.
-  JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
+  JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
   JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
   JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
-  JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES"
+  JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES $JVM_FEATURES_link_time_opt"
   JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES"
   JVM_FEATURES_zeroshark="zero shark $NON_MINIMAL_FEATURES $JVM_FEATURES"
   JVM_FEATURES_custom="$JVM_FEATURES"
@@ -305,6 +431,31 @@
 ])
 
 ################################################################################
+#
+# Specify which sources will be used to build the 64-bit ARM port
+#
+# --with-cpu-port=arm64   will use hotspot/src/cpu/arm
+# --with-cpu-port=aarch64 will use hotspot/src/cpu/aarch64
+#
+AC_DEFUN([SETUP_HOTSPOT_TARGET_CPU_PORT],
+[
+  AC_ARG_WITH(cpu-port, [AS_HELP_STRING([--with-cpu-port],
+      [specify sources to use for Hotspot 64-bit ARM port (arm64,aarch64) @<:@aarch64@:>@ ])])
+
+  if test "x$with_cpu_port" != x; then
+    if test "x$OPENJDK_TARGET_CPU" != xaarch64; then
+      AC_MSG_ERROR([--with-cpu-port only available on aarch64])
+    fi
+    if test "x$with_cpu_port" != xarm64 && \
+        test "x$with_cpu_port" != xaarch64; then
+      AC_MSG_ERROR([--with-cpu-port must specify arm64 or aarch64])
+    fi
+    HOTSPOT_TARGET_CPU_PORT="$with_cpu_port"
+  fi
+])
+
+
+################################################################################
 # Check if gtest should be built
 #
 AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_GTEST],
diff --git a/common/autoconf/lib-elf.m4 b/common/autoconf/lib-elf.m4
new file mode 100644
index 0000000..9d5230b
--- /dev/null
+++ b/common/autoconf/lib-elf.m4
@@ -0,0 +1,129 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Setup libelf (ELF library)
+################################################################################
+AC_DEFUN_ONCE([LIB_SETUP_LIBELF],
+[
+  AC_ARG_WITH(libelf, [AS_HELP_STRING([--with-libelf],
+      [specify prefix directory for the libelf package
+      (expecting the libraries under PATH/lib and the headers under PATH/include)])])
+  AC_ARG_WITH(libelf-include, [AS_HELP_STRING([--with-libelf-include],
+      [specify directory for the libelf include files])])
+  AC_ARG_WITH(libelf-lib, [AS_HELP_STRING([--with-libelf-lib],
+      [specify directory for the libelf library])])
+
+  if test "x$ENABLE_AOT" = xfalse; then
+    if (test "x${with_libelf}" != x && test "x${with_libelf}" != xno) || \
+        (test "x${with_libelf_include}" != x && test "x${with_libelf_include}" != xno) || \
+        (test "x${with_libelf_lib}" != x && test "x${with_libelf_lib}" != xno); then
+      AC_MSG_WARN([[libelf is not used, so --with-libelf[-*] is ignored]])
+    fi
+    LIBELF_CFLAGS=
+    LIBELF_LIBS=
+  else
+    LIBELF_FOUND=no
+
+    if test "x${with_libelf}" = xno || test "x${with_libelf_include}" = xno || test "x${with_libelf_lib}" = xno; then
+      ENABLE_AOT="false"
+      if test "x${enable_aot}" = xyes; then
+        AC_MSG_ERROR([libelf is explicitly disabled, cannot build AOT. Enable libelf or remove --enable-aot to disable AOT.])
+      fi
+    else
+      if test "x${with_libelf}" != x; then
+        ELF_LIBS="-L${with_libelf}/lib -lelf"
+        ELF_CFLAGS="-I${with_libelf}/include"
+        LIBELF_FOUND=yes
+      fi
+      if test "x${with_libelf_include}" != x; then
+        ELF_CFLAGS="-I${with_libelf_include}"
+        LIBELF_FOUND=yes
+      fi
+      if test "x${with_libelf_lib}" != x; then
+        ELF_LIBS="-L${with_libelf_lib} -lelf"
+        LIBELF_FOUND=yes
+      fi
+      # Do not try pkg-config if we have a sysroot set.
+      if test "x$SYSROOT" = x; then
+        if test "x$LIBELF_FOUND" = xno; then
+          # Figure out ELF_CFLAGS and ELF_LIBS
+          PKG_CHECK_MODULES([ELF], [libelf], [LIBELF_FOUND=yes], [LIBELF_FOUND=no])
+        fi
+      fi
+      if test "x$LIBELF_FOUND" = xno; then
+        AC_CHECK_HEADERS([libelf.h],
+            [
+              LIBELF_FOUND=yes
+              ELF_CFLAGS=
+              ELF_LIBS=-lelf
+            ],
+            [LIBELF_FOUND=no]
+        )
+      fi
+      if test "x$LIBELF_FOUND" = xno; then
+        ENABLE_AOT="false"
+        HELP_MSG_MISSING_DEPENDENCY([elf])
+        if test "x${enable_aot}" = xyes; then
+          AC_MSG_ERROR([libelf not found, cannot build AOT. Remove --enable-aot to disable AOT or: $HELP_MSG])
+        else
+          AC_MSG_WARN([libelf not found, cannot build AOT. $HELP_MSG])
+        fi
+      else
+        AC_MSG_CHECKING([if libelf works])
+        AC_LANG_PUSH(C)
+        OLD_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $ELF_CFLAGS"
+        OLD_LIBS="$LIBS"
+        LIBS="$LIBS $ELF_LIBS"
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <libelf.h>],
+            [
+              elf_version(0);
+              return 0;
+            ])],
+            [LIBELF_WORKS=yes],
+            [LIBELF_WORKS=no]
+        )
+        CFLAGS="$OLD_CFLAGS"
+        LIBS="$OLD_LIBS"
+        AC_LANG_POP(C)
+        AC_MSG_RESULT([$LIBELF_WORKS])
+
+        if test "x$LIBELF_WORKS" = xno; then
+          ENABLE_AOT="false"
+          HELP_MSG_MISSING_DEPENDENCY([elf])
+          if test "x$enable_aot" = "xyes"; then
+            AC_MSG_ERROR([Found libelf but could not link and compile with it. Remove --enable-aot to disable AOT or: $HELP_MSG])
+          else
+            AC_MSG_WARN([Found libelf but could not link and compile with it. $HELP_MSG])
+          fi
+        fi
+      fi
+    fi
+  fi
+
+  AC_SUBST(ELF_CFLAGS)
+  AC_SUBST(ELF_LIBS)
+])
diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4
index 3ca12d4..bd5a40a 100644
--- a/common/autoconf/libraries.m4
+++ b/common/autoconf/libraries.m4
@@ -31,6 +31,7 @@
 m4_include([lib-freetype.m4])
 m4_include([lib-std.m4])
 m4_include([lib-x11.m4])
+m4_include([lib-elf.m4])
 
 ################################################################################
 # Determine which libraries are needed for this configuration
@@ -90,6 +91,7 @@
   LIB_SETUP_BUNDLED_LIBS
   LIB_SETUP_MISC_LIBS
   LIB_SETUP_SOLARIS_STLPORT
+  LIB_SETUP_LIBELF
 ])
 
 ################################################################################
diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4
index 392a23a..5217ca3 100644
--- a/common/autoconf/platform.m4
+++ b/common/autoconf/platform.m4
@@ -308,15 +308,6 @@
   fi
   AC_SUBST(OPENJDK_$1_CPU_LEGACY_LIB)
 
-  # This is the name of the cpu (but using i386 and amd64 instead of
-  # x86 and x86_64, respectively), preceeded by a /, to be used when
-  # locating libraries. On macosx, it's empty, though.
-  OPENJDK_$1_CPU_LIBDIR="/$OPENJDK_$1_CPU_LEGACY_LIB"
-  if test "x$OPENJDK_$1_OS" = xmacosx; then
-    OPENJDK_$1_CPU_LIBDIR=""
-  fi
-  AC_SUBST(OPENJDK_$1_CPU_LIBDIR)
-
   # OPENJDK_$1_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
   # /amd64 or /sparcv9. This string is appended to some library paths, like this:
   # /usr/lib${OPENJDK_$1_CPU_ISADIR}/libexample.so
@@ -348,16 +339,6 @@
     # On all platforms except macosx, we replace x86_64 with amd64.
     OPENJDK_$1_CPU_JLI="amd64"
   fi
-  # Now setup the -D flags for building libjli.
-  OPENJDK_$1_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_$1_CPU_JLI\"'"
-  if test "x$OPENJDK_$1_OS" = xsolaris; then
-    if test "x$OPENJDK_$1_CPU_ARCH" = xsparc; then
-      OPENJDK_$1_CPU_JLI_CFLAGS="$OPENJDK_$1_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'"
-    elif test "x$OPENJDK_$1_CPU_ARCH" = xx86; then
-      OPENJDK_$1_CPU_JLI_CFLAGS="$OPENJDK_$1_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'"
-    fi
-  fi
-  AC_SUBST(OPENJDK_$1_CPU_JLI_CFLAGS)
 
   if test "x$OPENJDK_$1_OS" = xmacosx; then
       OPENJDK_$1_OS_EXPORT_DIR=macosx
diff --git a/common/autoconf/source-dirs.m4 b/common/autoconf/source-dirs.m4
index 81137cf..49db473 100644
--- a/common/autoconf/source-dirs.m4
+++ b/common/autoconf/source-dirs.m4
@@ -62,27 +62,9 @@
 [
   BUILD_OUTPUT="$OUTPUT_ROOT"
   AC_SUBST(BUILD_OUTPUT)
-
-  HOTSPOT_DIST="$OUTPUT_ROOT/hotspot/dist"
-  BUILD_HOTSPOT=true
-  AC_SUBST(HOTSPOT_DIST)
-  AC_SUBST(BUILD_HOTSPOT)
-  AC_ARG_WITH(import-hotspot, [AS_HELP_STRING([--with-import-hotspot],
-  [import hotspot binaries from this jdk image or hotspot build dist dir instead of building from source])])
-  if test "x$with_import_hotspot" != x; then
-    CURDIR="$PWD"
-    cd "$with_import_hotspot"
-    HOTSPOT_DIST="`pwd`"
-    cd "$CURDIR"
-    if ! (test -d $HOTSPOT_DIST/lib && test -d $HOTSPOT_DIST/jre/lib); then
-      AC_MSG_ERROR([You have to import hotspot from a full jdk image or hotspot build dist dir!])
-    fi
-    AC_MSG_CHECKING([if hotspot should be imported])
-    AC_MSG_RESULT([yes from $HOTSPOT_DIST])
-    BUILD_HOTSPOT=false
-  fi
-
   JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk"
+
+  BASIC_DEPRECATED_ARG_WITH(import_hotspot)
 ])
 
 ################################################################################
@@ -123,6 +105,12 @@
   if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then
     IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf"
   fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_legal"; then
+    IMPORT_MODULES_LEGAL="$IMPORT_MODULES_TOPDIR/modules_legal"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_man"; then
+    IMPORT_MODULES_MAN="$IMPORT_MODULES_TOPDIR/modules_man"
+  fi
   if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
     IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
   fi
@@ -140,6 +128,8 @@
   AC_SUBST(IMPORT_MODULES_CMDS)
   AC_SUBST(IMPORT_MODULES_LIBS)
   AC_SUBST(IMPORT_MODULES_CONF)
+  AC_SUBST(IMPORT_MODULES_LEGAL)
+  AC_SUBST(IMPORT_MODULES_MAN)
   AC_SUBST(IMPORT_MODULES_SRC)
   AC_SUBST(IMPORT_MODULES_MAKE)
 ])
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index fa16d6b..a15b9f4 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -75,11 +75,9 @@
 
 # Legacy support
 OPENJDK_TARGET_CPU_ISADIR:=@OPENJDK_TARGET_CPU_ISADIR@
-OPENJDK_TARGET_CPU_LIBDIR:=@OPENJDK_TARGET_CPU_LIBDIR@
 OPENJDK_TARGET_CPU_LEGACY:=@OPENJDK_TARGET_CPU_LEGACY@
 OPENJDK_TARGET_CPU_LEGACY_LIB:=@OPENJDK_TARGET_CPU_LEGACY_LIB@
 OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@
-OPENJDK_TARGET_CPU_JLI_CFLAGS:=@OPENJDK_TARGET_CPU_JLI_CFLAGS@
 OPENJDK_TARGET_OS_EXPORT_DIR:=@OPENJDK_TARGET_OS_EXPORT_DIR@
 
 HOTSPOT_TARGET_OS := @HOTSPOT_TARGET_OS@
@@ -145,6 +143,8 @@
 IMPORT_MODULES_CMDS:=@IMPORT_MODULES_CMDS@
 IMPORT_MODULES_LIBS:=@IMPORT_MODULES_LIBS@
 IMPORT_MODULES_CONF:=@IMPORT_MODULES_CONF@
+IMPORT_MODULES_LEGAL:=@IMPORT_MODULES_LEGAL@
+IMPORT_MODULES_MAN:=@IMPORT_MODULES_MAN@
 IMPORT_MODULES_SRC:=@IMPORT_MODULES_SRC@
 IMPORT_MODULES_MAKE:=@IMPORT_MODULES_MAKE@
 
@@ -220,6 +220,7 @@
 
 # Which JVM variants to build (space-separated list)
 JVM_VARIANTS := @JVM_VARIANTS@
+JVM_VARIANT_MAIN := @JVM_VARIANT_MAIN@
 
 # Lists of features per variant. Only relevant for the variants listed in
 # JVM_VARIANTS.
@@ -273,8 +274,6 @@
 CONFIGURESUPPORT_OUTPUTDIR:=@CONFIGURESUPPORT_OUTPUTDIR@
 BUILDJDK_OUTPUTDIR=$(BUILD_OUTPUT)/buildjdk
 
-HOTSPOT_DIST=@HOTSPOT_DIST@
-
 BUILD_HOTSPOT=@BUILD_HOTSPOT@
 
 BUILD_FAILURE_HANDLER := @BUILD_FAILURE_HANDLER@
@@ -686,6 +685,7 @@
 TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@
 
 # Build setup
+ENABLE_AOT:=@ENABLE_AOT@
 ENABLE_JFR=@ENABLE_JFR@
 ENABLE_INTREE_EC=@ENABLE_INTREE_EC@
 USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@
@@ -760,6 +760,8 @@
 PNG_LIBS:=@PNG_LIBS@
 PNG_CFLAGS:=@PNG_CFLAGS@
 
+ELF_CFLAGS:=@ELF_CFLAGS@
+ELF_LIBS:=@ELF_LIBS@
 
 ####################################################
 #
@@ -767,6 +769,7 @@
 #
 
 INCLUDE_SA=@INCLUDE_SA@
+INCLUDE_GRAAL=@INCLUDE_GRAAL@
 
 OS_VERSION_MAJOR:=@OS_VERSION_MAJOR@
 OS_VERSION_MINOR:=@OS_VERSION_MINOR@
diff --git a/common/bin/compare.sh b/common/bin/compare.sh
index de909e0..3385423 100644
--- a/common/bin/compare.sh
+++ b/common/bin/compare.sh
@@ -509,30 +509,32 @@
             | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g")
     fi
 
-    $RM -f $WORK_DIR/$ZIP_FILE.diffs
-    for file in $DIFFING_FILES; do
-        if [[ "$ACCEPTED_JARZIP_CONTENTS $EXCEPTIONS" != *"$file"* ]]; then
-            diff_text $OTHER_UNZIPDIR/$file $THIS_UNZIPDIR/$file >> $WORK_DIR/$ZIP_FILE.diffs
-        fi
-    done
+    if [ "$CMP_ZIPS_CONTENTS" = "true" ]; then
+        $RM -f $WORK_DIR/$ZIP_FILE.diffs
+        for file in $DIFFING_FILES; do
+            if [[ "$ACCEPTED_JARZIP_CONTENTS $EXCEPTIONS" != *"$file"* ]]; then
+                diff_text $OTHER_UNZIPDIR/$file $THIS_UNZIPDIR/$file >> $WORK_DIR/$ZIP_FILE.diffs
+            fi
+        done
 
-    if [ -s "$WORK_DIR/$ZIP_FILE.diffs" ]; then
-        return_value=1
-        echo "        Differing files in $ZIP_FILE"
-        $CAT $WORK_DIR/$ZIP_FILE.diffs | $GREP 'differ$' | cut -f 2 -d ' ' | \
-            $SED "s|$OTHER_UNZIPDIR|            |g" > $WORK_DIR/$ZIP_FILE.difflist
-        $CAT $WORK_DIR/$ZIP_FILE.difflist
+        if [ -s "$WORK_DIR/$ZIP_FILE.diffs" ]; then
+            return_value=1
+            echo "        Differing files in $ZIP_FILE"
+            $CAT $WORK_DIR/$ZIP_FILE.diffs | $GREP 'differ$' | cut -f 2 -d ' ' | \
+                $SED "s|$OTHER_UNZIPDIR|            |g" > $WORK_DIR/$ZIP_FILE.difflist
+            $CAT $WORK_DIR/$ZIP_FILE.difflist
 
-        if [ -n "$SHOW_DIFFS" ]; then
-            for i in $(cat $WORK_DIR/$ZIP_FILE.difflist) ; do
-                if [ -f "${OTHER_UNZIPDIR}/$i.javap" ]; then
-                    LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.javap ${THIS_UNZIPDIR}/$i.javap
-                elif [ -f "${OTHER_UNZIPDIR}/$i.cleaned" ]; then
-                    LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.cleaned ${THIS_UNZIPDIR}/$i
-                else
-                    LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i ${THIS_UNZIPDIR}/$i
-                fi
-            done
+            if [ -n "$SHOW_DIFFS" ]; then
+                for i in $(cat $WORK_DIR/$ZIP_FILE.difflist) ; do
+                    if [ -f "${OTHER_UNZIPDIR}/$i.javap" ]; then
+                        LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.javap ${THIS_UNZIPDIR}/$i.javap
+                    elif [ -f "${OTHER_UNZIPDIR}/$i.cleaned" ]; then
+                        LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i.cleaned ${THIS_UNZIPDIR}/$i
+                    else
+                        LC_ALL=C $DIFF ${OTHER_UNZIPDIR}/$i ${THIS_UNZIPDIR}/$i
+                    fi
+                done
+            fi
         fi
     fi
 
@@ -1072,7 +1074,8 @@
     echo "-perms              Compare the permission bits on all files and directories"
     echo "-types              Compare the output of the file command on all files"
     echo "-general            Compare the files not convered by the specialized comparisons"
-    echo "-zips               Compare the contents of all zip files"
+    echo "-zips               Compare the contents of all zip files and files in them"
+    echo "-zips-names         Compare the file names inside all zip files"
     echo "-jars               Compare the contents of all jar files"
     echo "-libs               Compare all native libraries"
     echo "-execs              Compare all executables"
@@ -1100,6 +1103,7 @@
 CMP_TYPES=false
 CMP_GENERAL=false
 CMP_ZIPS=false
+CMP_ZIPS_CONTENTS=true
 CMP_JARS=false
 CMP_LIBS=false
 CMP_EXECS=false
@@ -1143,6 +1147,11 @@
             ;;
         -zips)
             CMP_ZIPS=true
+            CMP_ZIPS_CONTENTS=true
+            ;;
+        -zips-names)
+            CMP_ZIPS=true
+            CMP_ZIPS_CONTENTS=false
             ;;
         -jars)
             CMP_JARS=true
diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl
index 5042cdc..8aa1df1 100644
--- a/common/bin/compare_exceptions.sh.incl
+++ b/common/bin/compare_exceptions.sh.incl
@@ -57,21 +57,21 @@
       ./demo/jvmti/mtrace/lib/libmtrace.so
       ./demo/jvmti/versionCheck/lib/libversionCheck.so
       ./demo/jvmti/waiters/lib/libwaiters.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/client/libjsig.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/client/libjvm.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libattach.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libdt_socket.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libinstrument.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libjsdt.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libjsig.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libmanagement.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libnet.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libnpt.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/libverify.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjsig.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/server/libjsig.so
-      ./lib$OPENJDK_TARGET_CPU_LIBDIR/server/libjvm.so
+      ./lib/client/libjsig.so
+      ./lib/client/libjvm.so
+      ./lib/libattach.so
+      ./lib/libdt_socket.so
+      ./lib/libinstrument.so
+      ./lib/libjsdt.so
+      ./lib/libjsig.so
+      ./lib/libmanagement.so
+      ./lib/libnet.so
+      ./lib/libnpt.so
+      ./lib/libverify.so
+      ./lib/minimal/libjsig.so
+      ./lib/minimal/libjvm.so
+      ./lib/server/libjsig.so
+      ./lib/server/libjvm.so
       ./bin/appletviewer
       ./bin/idlj
       ./bin/jar
@@ -122,12 +122,12 @@
     # So for now, accept the difference but put a limit on the size. The
     # different order of functions shouldn't result in a very big diff.
     KNOWN_FULLDUMP_DIFF="
-        ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so
+        ./lib/minimal/libjvm.so
         "
 
     # Link time optimization adds random numbers to symbol names
     NEED_DIS_DIFF_FILTER="
-        ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so
+        ./lib/minimal/libjvm.so
         "
     DIS_DIFF_FILTER="$SED -r \
         -e 's/\.[0-9]+/.X/g' \
@@ -135,12 +135,12 @@
         -e 's/\t[0-9a-f]{5,} /\t<HEX> /' \
         "
     KNOWN_DIS_DIFF="
-        ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so
+        ./lib/minimal/libjvm.so
         "
     MAX_KNOWN_DIS_DIFF_SIZE="3000"
 
     NEED_SYMBOLS_DIFF_FILTER="
-        ./lib$OPENJDK_TARGET_CPU_LIBDIR/minimal/libjvm.so
+        ./lib/minimal/libjvm.so
         "
     SYMBOLS_DIFF_FILTER="$SED -r \
         -e 's/\.[0-9]+/.X/g'
@@ -163,11 +163,11 @@
       "
 
   SORT_SYMBOLS="
-      ./lib/amd64/server/libjvm.so
-      ./lib/amd64/libfontmanager.so
-      ./lib/amd64/libjimage.so
-      ./lib/amd64/libsaproc.so
-      ./lib/amd64/libunpack.so
+      ./lib/server/libjvm.so
+      ./lib/libfontmanager.so
+      ./lib/libjimage.so
+      ./lib/libsaproc.so
+      ./lib/libunpack.so
       ./bin/unpack200
       "
 
@@ -183,48 +183,48 @@
       ./demo/jvmti/mtrace/lib/libmtrace.so
       ./demo/jvmti/versionCheck/lib/libversionCheck.so
       ./demo/jvmti/waiters/lib/libwaiters.so
-      ./lib/amd64/jli/libjli.so
-      ./lib/amd64/jspawnhelper
-      ./lib/amd64/libJdbcOdbc.so
-      ./lib/amd64/libattach.so
-      ./lib/amd64/libawt.so
-      ./lib/amd64/libawt_headless.so
-      ./lib/amd64/libawt_xawt.so
-      ./lib/amd64/libdcpr.so
-      ./lib/amd64/libdt_socket.so
-      ./lib/amd64/libfontmanager.so
-      ./lib/amd64/libinstrument.so
-      ./lib/amd64/libj2gss.so
-      ./lib/amd64/libj2pcsc.so
-      ./lib/amd64/libj2pkcs11.so
-      ./lib/amd64/libj2ucrypto.so
-      ./lib/amd64/libjaas_unix.so
-      ./lib/amd64/libjava.so
-      ./lib/amd64/libjawt.so
-      ./lib/amd64/libjdwp.so
-      ./lib/amd64/libjpeg.so
-      ./lib/amd64/libjsdt.so
-      ./lib/amd64/libjsound.so
-      ./lib/amd64/libkcms.so
-      ./lib/amd64/liblcms.so
-      ./lib/amd64/libmanagement.so
-      ./lib/amd64/libmlib_image.so
-      ./lib/amd64/libnet.so
-      ./lib/amd64/libnio.so
-      ./lib/amd64/libnpt.so
-      ./lib/amd64/libsctp.so
-      ./lib/amd64/libsplashscreen.so
-      ./lib/amd64/libsunec.so
-      ./lib/amd64/libsunwjdga.so
-      ./lib/amd64/libt2k.so
-      ./lib/amd64/libunpack.so
-      ./lib/amd64/libverify.so
-      ./lib/amd64/libzip.so
-      ./lib/amd64/server/64/libjvm_db.so
-      ./lib/amd64/server/64/libjvm_dtrace.so
-      ./lib/amd64/server/libjvm.so
-      ./lib/amd64/server/libjvm_db.so
-      ./lib/amd64/server/libjvm_dtrace.so
+      ./lib/jli/libjli.so
+      ./lib/jspawnhelper
+      ./lib/libJdbcOdbc.so
+      ./lib/libattach.so
+      ./lib/libawt.so
+      ./lib/libawt_headless.so
+      ./lib/libawt_xawt.so
+      ./lib/libdcpr.so
+      ./lib/libdt_socket.so
+      ./lib/libfontmanager.so
+      ./lib/libinstrument.so
+      ./lib/libj2gss.so
+      ./lib/libj2pcsc.so
+      ./lib/libj2pkcs11.so
+      ./lib/libj2ucrypto.so
+      ./lib/libjaas_unix.so
+      ./lib/libjava.so
+      ./lib/libjawt.so
+      ./lib/libjdwp.so
+      ./lib/libjpeg.so
+      ./lib/libjsdt.so
+      ./lib/libjsound.so
+      ./lib/libkcms.so
+      ./lib/liblcms.so
+      ./lib/libmanagement.so
+      ./lib/libmlib_image.so
+      ./lib/libnet.so
+      ./lib/libnio.so
+      ./lib/libnpt.so
+      ./lib/libsctp.so
+      ./lib/libsplashscreen.so
+      ./lib/libsunec.so
+      ./lib/libsunwjdga.so
+      ./lib/libt2k.so
+      ./lib/libunpack.so
+      ./lib/libverify.so
+      ./lib/libzip.so
+      ./lib/server/64/libjvm_db.so
+      ./lib/server/64/libjvm_dtrace.so
+      ./lib/server/libjvm.so
+      ./lib/server/libjvm_db.so
+      ./lib/server/libjvm_dtrace.so
       ./bin/appletviewer
       ./bin/idlj
       ./bin/jar
@@ -292,13 +292,13 @@
 
   SORT_SYMBOLS="
       ./demo/jvmti/waiters/lib/libwaiters.so
-      ./lib/sparcv9/libjsig.so
-      ./lib/sparcv9/libfontmanager.so
-      ./lib/sparcv9/libjimage.so
-      ./lib/sparcv9/libsaproc.so
-      ./lib/sparcv9/libunpack.so
-      ./lib/sparcv9/server/libjvm.so
-      ./lib/sparcv9/server/libjvm_dtrace.so
+      ./lib/libjsig.so
+      ./lib/libfontmanager.so
+      ./lib/libjimage.so
+      ./lib/libsaproc.so
+      ./lib/libunpack.so
+      ./lib/server/libjvm.so
+      ./lib/server/libjvm_dtrace.so
       ./bin/unpack200
       "
 
@@ -314,46 +314,46 @@
       ./demo/jvmti/mtrace/lib/libmtrace.so
       ./demo/jvmti/versionCheck/lib/libversionCheck.so
       ./demo/jvmti/waiters/lib/libwaiters.so
-      ./lib/sparcv9/client/libjvm.so
-      ./lib/sparcv9/jli/libjli.so
-      ./lib/sparcv9/jspawnhelper
-      ./lib/sparcv9/libJdbcOdbc.so
-      ./lib/sparcv9/libattach.so
-      ./lib/sparcv9/libawt.so
-      ./lib/sparcv9/libawt_headless.so
-      ./lib/sparcv9/libawt_xawt.so
-      ./lib/sparcv9/libdcpr.so
-      ./lib/sparcv9/libdt_socket.so
-      ./lib/sparcv9/libfontmanager.so
-      ./lib/sparcv9/libinstrument.so
-      ./lib/sparcv9/libj2gss.so
-      ./lib/sparcv9/libj2pcsc.so
-      ./lib/sparcv9/libj2pkcs11.so
-      ./lib/sparcv9/libj2ucrypto.so
-      ./lib/sparcv9/libjaas_unix.so
-      ./lib/sparcv9/libjava.so
-      ./lib/sparcv9/libjawt.so
-      ./lib/sparcv9/libjdwp.so
-      ./lib/sparcv9/libjpeg.so
-      ./lib/sparcv9/libjsdt.so
-      ./lib/sparcv9/libjsound.so
-      ./lib/sparcv9/libkcms.so
-      ./lib/sparcv9/liblcms.so
-      ./lib/sparcv9/libmanagement.so
-      ./lib/sparcv9/libmlib_image.so
-      ./lib/sparcv9/libmlib_image_v.so
-      ./lib/sparcv9/libnet.so
-      ./lib/sparcv9/libnio.so
-      ./lib/sparcv9/libnpt.so
-      ./lib/sparcv9/libsctp.so
-      ./lib/sparcv9/libsplashscreen.so
-      ./lib/sparcv9/libsunec.so
-      ./lib/sparcv9/libsunwjdga.so
-      ./lib/sparcv9/libt2k.so
-      ./lib/sparcv9/libunpack.so
-      ./lib/sparcv9/libverify.so
-      ./lib/sparcv9/libzip.so
-      ./lib/sparcv9/server/libjvm.so
+      ./lib/client/libjvm.so
+      ./lib/jli/libjli.so
+      ./lib/jspawnhelper
+      ./lib/libJdbcOdbc.so
+      ./lib/libattach.so
+      ./lib/libawt.so
+      ./lib/libawt_headless.so
+      ./lib/libawt_xawt.so
+      ./lib/libdcpr.so
+      ./lib/libdt_socket.so
+      ./lib/libfontmanager.so
+      ./lib/libinstrument.so
+      ./lib/libj2gss.so
+      ./lib/libj2pcsc.so
+      ./lib/libj2pkcs11.so
+      ./lib/libj2ucrypto.so
+      ./lib/libjaas_unix.so
+      ./lib/libjava.so
+      ./lib/libjawt.so
+      ./lib/libjdwp.so
+      ./lib/libjpeg.so
+      ./lib/libjsdt.so
+      ./lib/libjsound.so
+      ./lib/libkcms.so
+      ./lib/liblcms.so
+      ./lib/libmanagement.so
+      ./lib/libmlib_image.so
+      ./lib/libmlib_image_v.so
+      ./lib/libnet.so
+      ./lib/libnio.so
+      ./lib/libnpt.so
+      ./lib/libsctp.so
+      ./lib/libsplashscreen.so
+      ./lib/libsunec.so
+      ./lib/libsunwjdga.so
+      ./lib/libt2k.so
+      ./lib/libunpack.so
+      ./lib/libverify.so
+      ./lib/libzip.so
+      ./lib/server/libjvm.so
       ./bin/appletviewer
       ./bin/idlj
       ./bin/jar
@@ -409,7 +409,7 @@
       "
 
   KNOWN_DIS_DIFF="
-      ./lib/sparcv9/libsaproc.so
+      ./lib/libsaproc.so
   "
 
   MAX_KNOWN_DIS_DIFF_SIZE="3000"
@@ -417,8 +417,8 @@
   # On slowdebug the disassembly can differ randomly.
   if [ "$DEBUG_LEVEL" = "slowdebug" ]; then
     ACCEPTED_DIS_DIFF="
-        ./lib/sparcv9/libfontmanager.so
-        ./lib/sparcv9/server/libjvm.so
+        ./lib/libfontmanager.so
+        ./lib/server/libjvm.so
     "
   fi
 
diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt
index daa919b..a43b049 100644
--- a/common/bin/unshuffle_list.txt
+++ b/common/bin/unshuffle_list.txt
@@ -28,6 +28,11 @@
 corba/src/java.corba/share/classes/javax/rmi : corba/src/share/classes/javax/rmi
 corba/src/java.corba/share/classes/org/omg : corba/src/share/classes/org/omg
 corba/src/java.corba/share/classes/sun/corba : corba/src/share/classes/sun/corba
+corba/src/java.corba/share/classes/com/sun/jndi/cosnaming : jdk/src/share/classes/com/sun/jndi/cosnaming
+corba/src/java.corba/share/classes/com/sun/jndi/toolkit/corba : jdk/src/share/classes/com/sun/jndi/toolkit/corba
+corba/src/java.corba/share/classes/com/sun/jndi/url/corbaname : jdk/src/share/classes/com/sun/jndi/url/corbaname
+corba/src/java.corba/share/classes/com/sun/jndi/url/iiop : jdk/src/share/classes/com/sun/jndi/url/iiop
+corba/src/java.corba/share/classes/com/sun/jndi/url/iiopname : jdk/src/share/classes/com/sun/jndi/url/iiopname
 corba/src/jdk.rmic/share/classes/sun/rmi/rmic/iiop : corba/src/share/classes/sun/rmi/rmic/iiop
 jaxp/src/java.xml/share/classes/com/sun/java_cup/internal/runtime : jaxp/src/com/sun/java_cup/internal/runtime
 jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal : jaxp/src/com/sun/org/apache/bcel/internal
@@ -516,11 +521,6 @@
 jdk/src/java.base/windows/native/libnio/ch : jdk/src/windows/native/sun/nio/ch
 jdk/src/java.base/windows/native/libnio/fs : jdk/src/windows/native/sun/nio/fs
 jdk/src/java.base/windows/native/libnio/MappedByteBuffer.c : jdk/src/windows/native/java/nio/MappedByteBuffer.c
-jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming : jdk/src/share/classes/com/sun/jndi/cosnaming
-jdk/src/java.corba/share/classes/com/sun/jndi/toolkit/corba : jdk/src/share/classes/com/sun/jndi/toolkit/corba
-jdk/src/java.corba/share/classes/com/sun/jndi/url/corbaname : jdk/src/share/classes/com/sun/jndi/url/corbaname
-jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop : jdk/src/share/classes/com/sun/jndi/url/iiop
-jdk/src/java.corba/share/classes/com/sun/jndi/url/iiopname : jdk/src/share/classes/com/sun/jndi/url/iiopname
 jdk/src/java.desktop/aix/native/libawt : jdk/src/aix/porting
 jdk/src/java.desktop/linux/conf/oblique-fonts/fonts.dir : jdk/src/solaris/classes/sun/awt/motif/java.oblique-fonts.dir
 jdk/src/java.desktop/macosx/classes/com/apple/eawt/event/package.html : jdk/src/macosx/classes/com/apple/eawt/event/package.html
@@ -1266,33 +1266,33 @@
 jdk/src/jdk.crypto.ec/share/native/libsunec/impl : jdk/src/share/native/sun/security/ec/impl
 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi : jdk/src/windows/classes/sun/security/mscapi
 jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi : jdk/src/windows/native/sun/security/mscapi
-jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11 : jdk/src/share/classes/sun/security/pkcs11
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c : jdk/src/share/native/sun/security/pkcs11/j2secmod.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.h : jdk/src/share/native/sun/security/pkcs11/j2secmod.h
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11f.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11f.h
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11.h
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11t.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11t.h
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs-11v2-20a3.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs-11v2-20a3.h
-jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11wrapper.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h
-jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c : jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c
-jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.h : jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.h
-jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c : jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.c
-jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.h : jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h
-jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c
-jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.h
-jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.c
-jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h
+jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11 : jdk/src/share/classes/sun/security/pkcs11
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c : jdk/src/share/native/sun/security/pkcs11/j2secmod.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.h : jdk/src/share/native/sun/security/pkcs11/j2secmod.h
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_digest.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_dual.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_general.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_sign.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c : jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11f.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11f.h
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11.h
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11t.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11t.h
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs-11v2-20a3.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs-11v2-20a3.h
+jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11wrapper.h : jdk/src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h
+jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c : jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c
+jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.h : jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.h
+jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c : jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.c
+jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.h : jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h
+jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.c : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c
+jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.h : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.h
+jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.c : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.c
+jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.h : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h
 jdk/src/java.desktop/macosx/native/libosx/CFileManager.m : jdk/src/macosx/native/com/apple/eio/CFileManager.m
 jdk/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m : jdk/src/macosx/native/apple/security/KeystoreImpl.m
 jdk/src/jdk.hprof.agent/share/classes/com/sun/demo/jvmti/hprof : jdk/src/share/classes/com/sun/demo/jvmti/hprof
@@ -1427,26 +1427,26 @@
 jdk/src/jdk.naming.dns/share/classes/sun/net/spi/nameservice/dns : jdk/src/share/classes/sun/net/spi/nameservice/dns
 jdk/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry : jdk/src/share/classes/com/sun/jndi/rmi/registry
 jdk/src/jdk.naming.rmi/share/classes/com/sun/jndi/url/rmi : jdk/src/share/classes/com/sun/jndi/url/rmi
-jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/bands.h : jdk/src/share/native/com/sun/java/util/jar/pack/bands.h
-jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/bytes.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/bytes.h : jdk/src/share/native/com/sun/java/util/jar/pack/bytes.h
-jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/coding.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/coding.h : jdk/src/share/native/com/sun/java/util/jar/pack/coding.h
-jdk/src/jdk.pack200/share/native/common-unpack/constants.h : jdk/src/share/native/com/sun/java/util/jar/pack/constants.h
-jdk/src/jdk.pack200/share/native/common-unpack/defines.h : jdk/src/share/native/com/sun/java/util/jar/pack/defines.h
-jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/unpack.h : jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h
-jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/utils.h : jdk/src/share/native/com/sun/java/util/jar/pack/utils.h
-jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/zip.cpp
-jdk/src/jdk.pack200/share/native/common-unpack/zip.h : jdk/src/share/native/com/sun/java/util/jar/pack/zip.h
-jdk/src/jdk.pack200/share/native/libjsdt : jdk/src/share/native/sun/tracing/dtrace
-jdk/src/jdk.pack200/share/native/libunpack/jni.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp
-jdk/src/jdk.pack200/share/native/unpack200/main.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp
-jdk/src/jdk.pack200/unix/native/libjsdt/jvm_symbols_md.c : jdk/src/solaris/native/sun/tracing/dtrace/jvm_symbols_md.c
-jdk/src/jdk.pack200/windows/native/libjsdt/jvm_symbols_md.c : jdk/src/windows/native/sun/tracing/dtrace/jvm_symbols_md.c
-jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest : jdk/src/windows/resource/unpack200_proto.exe.manifest
+jdk/src/jdk.pack/share/native/common-unpack/bands.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp
+jdk/src/jdk.pack/share/native/common-unpack/bands.h : jdk/src/share/native/com/sun/java/util/jar/pack/bands.h
+jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/bytes.cpp
+jdk/src/jdk.pack/share/native/common-unpack/bytes.h : jdk/src/share/native/com/sun/java/util/jar/pack/bytes.h
+jdk/src/jdk.pack/share/native/common-unpack/coding.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/coding.cpp
+jdk/src/jdk.pack/share/native/common-unpack/coding.h : jdk/src/share/native/com/sun/java/util/jar/pack/coding.h
+jdk/src/jdk.pack/share/native/common-unpack/constants.h : jdk/src/share/native/com/sun/java/util/jar/pack/constants.h
+jdk/src/jdk.pack/share/native/common-unpack/defines.h : jdk/src/share/native/com/sun/java/util/jar/pack/defines.h
+jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
+jdk/src/jdk.pack/share/native/common-unpack/unpack.h : jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h
+jdk/src/jdk.pack/share/native/common-unpack/utils.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp
+jdk/src/jdk.pack/share/native/common-unpack/utils.h : jdk/src/share/native/com/sun/java/util/jar/pack/utils.h
+jdk/src/jdk.pack/share/native/common-unpack/zip.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/zip.cpp
+jdk/src/jdk.pack/share/native/common-unpack/zip.h : jdk/src/share/native/com/sun/java/util/jar/pack/zip.h
+jdk/src/jdk.pack/share/native/libjsdt : jdk/src/share/native/sun/tracing/dtrace
+jdk/src/jdk.pack/share/native/libunpack/jni.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp
+jdk/src/jdk.pack/share/native/unpack200/main.cpp : jdk/src/share/native/com/sun/java/util/jar/pack/main.cpp
+jdk/src/jdk.pack/unix/native/libjsdt/jvm_symbols_md.c : jdk/src/solaris/native/sun/tracing/dtrace/jvm_symbols_md.c
+jdk/src/jdk.pack/windows/native/libjsdt/jvm_symbols_md.c : jdk/src/windows/native/sun/tracing/dtrace/jvm_symbols_md.c
+jdk/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest : jdk/src/windows/resource/unpack200_proto.exe.manifest
 jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool : jdk/src/share/classes/sun/security/tools/policytool
 jdk/src/jdk.rmic/share/classes/sun/rmi/rmic : jdk/src/share/classes/sun/rmi/rmic
 jdk/src/jdk.rmic/share/classes/sun/rmi/rmic/newrmic : jdk/src/share/classes/sun/rmi/rmic/newrmic
diff --git a/common/nb_native/nbproject/configurations.xml b/common/nb_native/nbproject/configurations.xml
index 8b23549..026734b 100644
--- a/common/nb_native/nbproject/configurations.xml
+++ b/common/nb_native/nbproject/configurations.xml
@@ -2166,7 +2166,7 @@
               </df>
             </df>
           </df>
-          <df name="jdk.crypto.pkcs11">
+          <df name="jdk.crypto.token">
             <df name="share">
               <df name="native">
                 <df name="libj2pkcs11">
@@ -2318,7 +2318,7 @@
               </df>
             </df>
           </df>
-          <df name="jdk.pack200">
+          <df name="jdk.pack">
             <df name="share">
               <df name="native">
                 <df name="common-unpack">
@@ -29422,35 +29422,35 @@
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c"
             ex="false"
             tool="0"
             flavor2="2">
@@ -29460,63 +29460,63 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c"
             ex="false"
             tool="0"
             flavor2="3">
         <cTool flags="5">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c"
             ex="false"
             tool="0"
             flavor2="3">
@@ -30022,12 +30022,12 @@
         <cTool flags="2">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bands.cpp"
             ex="false"
             tool="1"
             flavor2="4">
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -30037,7 +30037,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/coding.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -30047,7 +30047,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -30057,7 +30057,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/utils.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -30067,7 +30067,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/zip.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -30077,12 +30077,12 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/libunpack/jni.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/libunpack/jni.cpp"
             ex="false"
             tool="1"
             flavor2="4">
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/unpack200/main.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/unpack200/main.cpp"
             ex="false"
             tool="1"
             flavor2="4">
@@ -31752,7 +31752,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11">
+      <folder path="0/jdk/src/jdk.crypto.token">
         <cTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -31760,10 +31760,10 @@
             <pElem>../../jdk/src/java.base/unix/native/include</pElem>
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11</pElem>
             <pElem>../../jdk/src/java.base/macosx/native/libjava</pElem>
-            <pElem>../../build/support/headers/jdk.crypto.pkcs11</pElem>
+            <pElem>../../build/support/headers/jdk.crypto.token</pElem>
             <pElem>../../make</pElem>
           </incDir>
           <preprocessorList>
@@ -31772,7 +31772,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11/unix">
+      <folder path="0/jdk/src/jdk.crypto.token/unix">
         <cTool>
           <preprocessorList>
             <Elem>THIS_FILE="j2secmod_md.c"</Elem>
@@ -31899,7 +31899,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200">
+      <folder path="0/jdk/src/jdk.pack">
         <ccTool>
           <preprocessorList>
             <Elem>DEBUG</Elem>
@@ -31908,7 +31908,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/common-unpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/common-unpack">
         <ccTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -31917,7 +31917,7 @@
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/macosx/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -31927,7 +31927,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/libunpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/libunpack">
         <ccTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -31936,7 +31936,7 @@
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/macosx/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -31947,10 +31947,10 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/unpack200">
+      <folder path="0/jdk/src/jdk.pack/share/native/unpack200">
         <ccTool>
           <incDir>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -44741,14 +44741,14 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c"
             ex="false"
             tool="0"
             flavor2="0">
         <cTool flags="4">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44758,7 +44758,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44768,7 +44768,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44778,7 +44778,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44788,7 +44788,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44798,7 +44798,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44808,7 +44808,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44818,7 +44818,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44828,7 +44828,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44838,7 +44838,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44848,7 +44848,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -44858,14 +44858,14 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c"
             ex="false"
             tool="0"
             flavor2="0">
         <cTool flags="4">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -45364,14 +45364,14 @@
         <cTool flags="4">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bands.cpp"
             ex="false"
             tool="1"
             flavor2="0">
         <ccTool flags="2">
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -45381,7 +45381,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/coding.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -45391,7 +45391,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -45401,7 +45401,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/utils.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -45411,7 +45411,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/zip.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -45421,14 +45421,14 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/libunpack/jni.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/libunpack/jni.cpp"
             ex="false"
             tool="1"
             flavor2="0">
         <ccTool flags="2">
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/unpack200/main.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/unpack200/main.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -47795,7 +47795,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11">
+      <folder path="0/jdk/src/jdk.crypto.token">
         <cTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -47803,10 +47803,10 @@
             <pElem>../../jdk/src/java.base/unix/native/include</pElem>
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11</pElem>
             <pElem>../../jdk/src/java.base/linux/native/libjava</pElem>
-            <pElem>../../build/support/headers/jdk.crypto.pkcs11</pElem>
+            <pElem>../../build/support/headers/jdk.crypto.token</pElem>
             <pElem>../../make</pElem>
           </incDir>
           <preprocessorList>
@@ -47815,7 +47815,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11/unix">
+      <folder path="0/jdk/src/jdk.crypto.token/unix">
         <cTool>
           <preprocessorList>
             <Elem>THIS_FILE="j2secmod_md.c"</Elem>
@@ -47942,7 +47942,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200">
+      <folder path="0/jdk/src/jdk.pack">
         <ccTool>
           <preprocessorList>
             <Elem>DEBUG</Elem>
@@ -47951,7 +47951,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/common-unpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/common-unpack">
         <ccTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -47960,7 +47960,7 @@
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/linux/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -47970,7 +47970,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/libunpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/libunpack">
         <ccTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -47979,7 +47979,7 @@
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/linux/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -47990,10 +47990,10 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/unpack200">
+      <folder path="0/jdk/src/jdk.pack/share/native/unpack200">
         <ccTool>
           <incDir>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/share/native/libzip/zlib-1.2.8</pElem>
@@ -62728,14 +62728,14 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c"
             ex="false"
             tool="0"
             flavor2="0">
         <cTool flags="2">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62745,7 +62745,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62755,7 +62755,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62765,7 +62765,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62775,7 +62775,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62785,7 +62785,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62795,7 +62795,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62805,7 +62805,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62815,7 +62815,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62825,7 +62825,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62835,7 +62835,7 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c"
+      <item path="../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -62845,14 +62845,14 @@
           </preprocessorList>
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c"
             ex="false"
             tool="0"
             flavor2="0">
         <cTool flags="2">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c"
+      <item path="../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c"
             ex="false"
             tool="0"
             flavor2="0">
@@ -63395,14 +63395,14 @@
         <cTool flags="2">
         </cTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bands.cpp"
             ex="false"
             tool="1"
             flavor2="0">
         <ccTool flags="0">
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -63412,7 +63412,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/coding.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -63422,7 +63422,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -63432,7 +63432,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/utils.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -63442,7 +63442,7 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/common-unpack/zip.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -63452,14 +63452,14 @@
           </preprocessorList>
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/libunpack/jni.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/libunpack/jni.cpp"
             ex="false"
             tool="1"
             flavor2="0">
         <ccTool flags="0">
         </ccTool>
       </item>
-      <item path="../../jdk/src/jdk.pack200/share/native/unpack200/main.cpp"
+      <item path="../../jdk/src/jdk.pack/share/native/unpack200/main.cpp"
             ex="false"
             tool="1"
             flavor2="0">
@@ -66281,7 +66281,7 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11">
+      <folder path="0/jdk/src/jdk.crypto.token">
         <cTool>
           <incDir>
             <pElem>../../jdk/src/java.base/share/native/include</pElem>
@@ -66289,10 +66289,10 @@
             <pElem>../../jdk/src/java.base/unix/native/include</pElem>
             <pElem>../../jdk/src/java.base/share/native/libjava</pElem>
             <pElem>../../jdk/src/java.base/unix/native/libjava</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11</pElem>
-            <pElem>../../jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/share/native/libj2pkcs11</pElem>
+            <pElem>../../jdk/src/jdk.crypto.token/unix/native/libj2pkcs11</pElem>
             <pElem>../../jdk/src/java.base/solaris/native/libjava</pElem>
-            <pElem>../../build/support/headers/jdk.crypto.pkcs11</pElem>
+            <pElem>../../build/support/headers/jdk.crypto.token</pElem>
             <pElem>../../make</pElem>
           </incDir>
           <preprocessorList>
@@ -66301,7 +66301,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.crypto.pkcs11/unix">
+      <folder path="0/jdk/src/jdk.crypto.token/unix">
         <cTool>
           <preprocessorList>
             <Elem>THIS_FILE="j2secmod_md.c"</Elem>
@@ -66462,7 +66462,7 @@
           </preprocessorList>
         </cTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200">
+      <folder path="0/jdk/src/jdk.pack">
         <ccTool>
           <preprocessorList>
             <Elem>DEBUG</Elem>
@@ -66471,11 +66471,11 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/common-unpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/common-unpack">
         <ccTool>
           <incDir>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/solaris/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -66485,11 +66485,11 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/libunpack">
+      <folder path="0/jdk/src/jdk.pack/share/native/libunpack">
         <ccTool>
           <incDir>
             <pElem>../../build/support/headers/java.base</pElem>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../jdk/src/java.base/solaris/native/libjava</pElem>
             <pElem>../../make</pElem>
           </incDir>
@@ -66500,10 +66500,10 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/jdk/src/jdk.pack200/share/native/unpack200">
+      <folder path="0/jdk/src/jdk.pack/share/native/unpack200">
         <ccTool>
           <incDir>
-            <pElem>../../jdk/src/jdk.pack200/share/native/common-unpack</pElem>
+            <pElem>../../jdk/src/jdk.pack/share/native/common-unpack</pElem>
             <pElem>../../make</pElem>
           </incDir>
           <preprocessorList>
diff --git a/corba/.hgtags b/corba/.hgtags
index 02f91e9..a1d96e4 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -391,3 +391,4 @@
 ecd74b41ab65bf228837b5bdf99690638d55425c jdk-9+146
 dc49e0922a8e4387cbf8670bbe1dc51c9874b74b jdk-9+147
 f95cc86b6ac22ec1ade5d4f825dc7782adeea228 jdk-9+148
+00b19338e505690abe93d5995ed74a473d969c2c jdk-9+149
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNBindingEnumeration.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNBindingEnumeration.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNBindingEnumeration.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNBindingEnumeration.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtx.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtx.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtx.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtx.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtxFactory.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtxFactory.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtxFactory.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtxFactory.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNNameParser.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNNameParser.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNNameParser.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNNameParser.java
diff --git a/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java
new file mode 100644
index 0000000..a24044a
--- /dev/null
+++ b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.cosnaming;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+
+import java.net.MalformedURLException;
+import com.sun.jndi.toolkit.corba.CorbaUtils;
+
+/**
+ * Extract components of a "corbaname" URL.
+ *
+ * The format of an corbaname URL is defined in INS 99-12-03 as follows.
+ * <pre>{@code
+ * corbaname url = "corbaname:" <corbaloc_obj> ["#" <string_name>]
+ * corbaloc_obj  = <obj_addr_list> ["/" <key_string>]
+ * obj_addr_list = as defined in a corbaloc URL
+ * key_string    = as defined in a corbaloc URL
+ * string_name   = stringified COS name | empty_string
+ * }</pre>
+ * Characters in {@code <string_name>} are escaped as follows.
+ * US-ASCII alphanumeric characters are not escaped. Any characters outside
+ * of this range are escaped except for the following:
+ * <pre>{@code
+ *        ; / : ? @ & = + $ , - _ . ! ~ * ; ( )
+ * }</pre>
+ * Escaped characters is escaped by using a % followed by its 2 hexadecimal
+ * numbers representing the octet.
+ * <p>
+ * The corbaname URL is parsed into two parts: a corbaloc URL and a COS name.
+ * The corbaloc URL is constructed by concatenation {@code "corbaloc:"} with
+ * {@code <corbaloc_obj>}.
+ * The COS name is {@code <string_name>} with the escaped characters resolved.
+ * <p>
+ * A corbaname URL is resolved by:
+ * <ol>
+ * <li>Construct a corbaloc URL by concatenating {@code "corbaloc:"} and {@code <corbaloc_obj>}.
+ * <li>Resolve the corbaloc URL to a NamingContext by using
+ * <pre>{@code
+ *     nctx = ORB.string_to_object(corbalocUrl);
+ * }</pre>
+ * <li>Resolve {@code <string_name>} in the NamingContext.
+ * </ol>
+ *
+ * @author Rosanna Lee
+ */
+
+public final class CorbanameUrl {
+    private String stringName;
+    private String location;
+
+    /**
+     * Returns a possibly empty but non-null string that is the "string_name"
+     * portion of the URL.
+     */
+    public String getStringName() {
+        return stringName;
+    }
+
+    public Name getCosName() throws NamingException {
+        return CNCtx.parser.parse(stringName);
+    }
+
+    public String getLocation() {
+        return "corbaloc:" + location;
+    }
+
+    public CorbanameUrl(String url) throws MalformedURLException {
+
+        if (!url.startsWith("corbaname:")) {
+            throw new MalformedURLException("Invalid corbaname URL: " + url);
+        }
+
+        int addrStart = 10;  // "corbaname:"
+
+        int addrEnd = url.indexOf('#', addrStart);
+        if (addrEnd < 0) {
+            addrEnd = url.length();
+            stringName = "";
+        } else {
+            stringName = CorbaUtils.decode(url.substring(addrEnd+1));
+        }
+        location = url.substring(addrStart, addrEnd);
+
+        int keyStart = location.indexOf('/');
+        if (keyStart >= 0) {
+            // Has key string
+            if (keyStart == (location.length() -1)) {
+                location += "NameService";
+            }
+        } else {
+            location += "/NameService";
+        }
+    }
+/*
+    // for testing only
+    public static void main(String[] args) {
+        try {
+            CorbanameUrl url = new CorbanameUrl(args[0]);
+
+            System.out.println("location: " + url.getLocation());
+            System.out.println("string name: " + url.getStringName());
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+*/
+}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/ExceptionMapper.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/ExceptionMapper.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/ExceptionMapper.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/ExceptionMapper.java
diff --git a/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java
new file mode 100644
index 0000000..d328f52
--- /dev/null
+++ b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.cosnaming;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+
+import java.net.MalformedURLException;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import com.sun.jndi.toolkit.corba.CorbaUtils;
+
+/**
+ * Extract components of an "iiop" or "iiopname" URL.
+ *
+ * The format of an iiopname URL is defined in INS 98-10-11 as follows:
+ *
+ * <pre>
+ * iiopname url = "iiopname://" [addr_list]["/" string_name]
+ * addr_list    = [address ","]* address
+ * address      = [version host [":" port]]
+ * host         = DNS style host name | IP address
+ * version      = major "." minor "@" | empty_string
+ * port         = number
+ * major        = number
+ * minor        = number
+ * string_name  = stringified name | empty_string
+ * </pre>
+ *
+ * The default port is 9999. The default version is "1.0"
+ * US-ASCII alphanumeric characters are not escaped. Any characters outside
+ * of this range are escaped except for the following:
+ * <pre>{@code
+ * ; / : ? : @ & = + $ , - _ . ! ~ *  ' ( )
+ * }</pre>
+ * Escaped characters is escaped by using a % followed by its 2 hexadecimal
+ * numbers representing the octet.
+ *
+ * For backward compatibility,  the "iiop" URL as defined in INS 97-6-6
+ * is also supported:
+ * <pre>{@code
+ * iiop url     = "iiop://" [host [":" port]] ["/" string_name]
+ * }</pre>
+ * The default port is 900.
+ *
+ * @author Rosanna Lee
+ */
+
+public final class IiopUrl {
+    static final private int DEFAULT_IIOPNAME_PORT = 9999;
+    static final private int DEFAULT_IIOP_PORT = 900;
+    static final private String DEFAULT_HOST = "localhost";
+    private Vector<Address> addresses;
+    private String stringName;
+
+    public static class Address {
+        public int port = -1;
+        public int major, minor;
+        public String host;
+
+        public Address(String hostPortVers, boolean oldFormat)
+            throws MalformedURLException {
+            // [version host [":" port]]
+            int start;
+
+            // Parse version
+            int at;
+            if (oldFormat || (at = hostPortVers.indexOf('@')) < 0) {
+                major = 1;
+                minor = 0;
+                start = 0;     // start at the beginning
+            } else {
+                int dot = hostPortVers.indexOf('.');
+                if (dot < 0) {
+                    throw new MalformedURLException(
+                        "invalid version: " + hostPortVers);
+                }
+                try {
+                    major = Integer.parseInt(hostPortVers.substring(0, dot));
+                    minor = Integer.parseInt(hostPortVers.substring(dot+1, at));
+                } catch (NumberFormatException e) {
+                    throw new MalformedURLException(
+                        "Nonnumeric version: " + hostPortVers);
+                }
+                start = at + 1;  // skip '@' sign
+            }
+
+            // Parse host and port
+            int slash = hostPortVers.indexOf('/', start);
+            if (slash < 0) {
+                slash = hostPortVers.length();
+            }
+            if (hostPortVers.startsWith("[", start)) {  // at IPv6 literal
+                int brac = hostPortVers.indexOf(']', start + 1);
+                if (brac < 0 || brac > slash) {
+                    throw new IllegalArgumentException(
+                        "IiopURL: name is an Invalid URL: " + hostPortVers);
+                }
+
+                // include brackets
+                host = hostPortVers.substring(start, brac + 1);
+                start = brac + 1;
+            } else {      // at hostname or IPv4
+                int colon = hostPortVers.indexOf(':', start);
+                int hostEnd = (colon < 0 || colon > slash)
+                    ? slash
+                    : colon;
+                if (start < hostEnd) {
+                    host = hostPortVers.substring(start, hostEnd);
+                }
+                start = hostEnd;   // skip past host
+            }
+            if ((start + 1 < slash)) {
+                if ( hostPortVers.startsWith(":", start)) { // parse port
+                    start++;    // skip past ":"
+                    port = Integer.parseInt(hostPortVers.
+                                            substring(start, slash));
+                } else {
+                    throw new IllegalArgumentException(
+                        "IiopURL: name is an Invalid URL: " + hostPortVers);
+                }
+            }
+            start = slash;
+            if ("".equals(host) || host == null) {
+                host = DEFAULT_HOST ;
+            }
+            if (port == -1) {
+                port = (oldFormat ? DEFAULT_IIOP_PORT :
+                                DEFAULT_IIOPNAME_PORT);
+            }
+        }
+    }
+
+    public Vector<Address> getAddresses() {
+        return addresses;
+    }
+
+    /**
+     * Returns a possibly empty but non-null string that is the "string_name"
+     * portion of the URL.
+     */
+    public String getStringName() {
+        return stringName;
+    }
+
+    public Name getCosName() throws NamingException {
+        return CNCtx.parser.parse(stringName);
+    }
+
+    public IiopUrl(String url) throws MalformedURLException {
+        int addrStart;
+        boolean oldFormat;
+
+        if (url.startsWith("iiopname://")) {
+            oldFormat = false;
+            addrStart = 11;
+        } else if (url.startsWith("iiop://")) {
+            oldFormat = true;
+            addrStart = 7;
+        } else {
+            throw new MalformedURLException("Invalid iiop/iiopname URL: " + url);
+        }
+        int addrEnd = url.indexOf('/', addrStart);
+        if (addrEnd < 0) {
+            addrEnd = url.length();
+            stringName = "";
+        } else {
+            stringName = CorbaUtils.decode(url.substring(addrEnd+1));
+        }
+        addresses = new Vector<>(3);
+        if (oldFormat) {
+            // Only one host:port part, not multiple
+            addresses.addElement(
+                new Address(url.substring(addrStart, addrEnd), oldFormat));
+        } else {
+            StringTokenizer tokens =
+                new StringTokenizer(url.substring(addrStart, addrEnd), ",");
+            while (tokens.hasMoreTokens()) {
+                addresses.addElement(new Address(tokens.nextToken(), oldFormat));
+            }
+            if (addresses.size() == 0) {
+                addresses.addElement(new Address("", oldFormat));
+            }
+        }
+    }
+
+    // for testing only
+    /*public static void main(String[] args) {
+        try {
+            IiopUrl url = new IiopUrl(args[0]);
+            Vector addrs = url.getAddresses();
+            String name = url.getStringName();
+
+            for (int i = 0; i < addrs.size(); i++) {
+                Address addr = (Address)addrs.elementAt(i);
+                System.out.println("host: " + addr.host);
+                System.out.println("port: " + addr.port);
+                System.out.println("version: " + addr.major + " " + addr.minor);
+            }
+            System.out.println("name: " + name);
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    } */
+}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/OrbReuseTracker.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/OrbReuseTracker.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/OrbReuseTracker.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/OrbReuseTracker.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/RemoteToCorba.java b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/RemoteToCorba.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/RemoteToCorba.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/RemoteToCorba.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties b/corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties
rename to corba/src/java.corba/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties
diff --git a/corba/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java b/corba/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java
new file mode 100644
index 0000000..422857b
--- /dev/null
+++ b/corba/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.toolkit.corba;
+
+// Needed for RMI/IIOP
+import java.rmi.Remote;
+
+import java.rmi.RemoteException;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.applet.Applet;
+
+import org.omg.CORBA.ORB;
+
+import javax.naming.Context;
+import javax.naming.ConfigurationException;
+import javax.rmi.CORBA.Stub;
+import javax.rmi.PortableRemoteObject;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URLDecoder;
+
+/**
+  * Contains utilities for performing CORBA-related tasks:
+  * 1. Get the org.omg.CORBA.Object for a java.rmi.Remote object.
+  * 2. Create an ORB to use for a given host/port, and environment properties.
+  *    ...
+  *
+  * @author Simon Nash
+  * @author Bryan Atsatt
+  */
+
+public class CorbaUtils {
+    /**
+      * Returns the CORBA object reference associated with a Remote
+      * object by using the javax.rmi.CORBA package.
+      *<p>
+      * This method effective does the following:
+      * <blockquote><pre>
+      * java.lang.Object stub;
+      * try {
+      *     stub = PortableRemoteObject.toStub(remoteObj);
+      * } catch (Exception e) {
+      *     throw new ConfigurationException("Object not exported or not found");
+      * }
+      * if (!(stub instanceof javax.rmi.CORBA.Stub)) {
+      *     return null; // JRMP impl or JRMP stub
+      * }
+      * try {
+      *     ((javax.rmi.CORBA.Stub)stub).connect(orb);  // try to connect IIOP stub
+      * } catch (RemoteException e) {
+      *     // ignore 'already connected' error
+      * }
+      * return (javax.rmi.CORBA.Stub)stub;
+      * </pre></blockquote>
+      *
+      * @param remoteObj The non-null remote object for
+      * @param orb       The non-null ORB to connect the remote object to
+      * @return The CORBA Object for remoteObj; null if {@code remoteObj}
+      *                 is a JRMP implementation or JRMP stub.
+      * @exception ConfigurationException The CORBA Object cannot be obtained
+      *         because of configuration problems.
+      */
+    public static org.omg.CORBA.Object remoteToCorba(Remote remoteObj, ORB orb)
+        throws ConfigurationException {
+
+// First, get remoteObj's stub
+
+            // javax.rmi.CORBA.Stub stub = PortableRemoteObject.toStub(remoteObj);
+
+            Remote stub;
+
+            try {
+                stub = PortableRemoteObject.toStub(remoteObj);
+            } catch (Throwable t) {
+                ConfigurationException ce = new ConfigurationException(
+    "Problem with PortableRemoteObject.toStub(); object not exported or stub not found");
+                ce.setRootCause(t);
+                throw ce;
+            }
+
+// Next, make sure that the stub is javax.rmi.CORBA.Stub
+
+            if (!(stub instanceof Stub)) {
+                return null;  // JRMP implementation or JRMP stub
+            }
+
+// Next, make sure that the stub is connected
+            try {
+                ((Stub) stub).connect(orb);
+            } catch (RemoteException e) {
+                // ignore RemoteException because stub might have already
+                // been connected
+            } catch (Throwable t) {
+                ConfigurationException ce = new ConfigurationException(
+                        "Problem invoking javax.rmi.CORBA.Stub.connect()");
+                ce.setRootCause(t);
+                throw ce;
+            }
+// Finally, return stub
+            return (org.omg.CORBA.Object)stub;
+    }
+
+    /**
+     * Get ORB using given server and port number, and properties from environment.
+     *
+     * @param server Possibly null server; if null means use default;
+     *               For applet, it is the applet host; for app, it is localhost.
+     * @param port   Port number, -1 means default port
+     * @param env    Possibly null environment. Contains environment properties.
+     *               Could contain ORB itself; or applet used for initializing ORB.
+     *               Use all String properties from env for initializing ORB
+     * @return A non-null ORB.
+     */
+    public static ORB getOrb(String server, int port, Hashtable<?,?> env) {
+        // See if we can get info from environment
+        Properties orbProp;
+
+        // Extract any org.omg.CORBA properties from environment
+        if (env != null) {
+            if (env instanceof Properties) {
+                // Already a Properties, just clone
+                orbProp = (Properties) env.clone();
+            } else {
+                // Get all String properties
+                Enumeration<?> envProp;
+                orbProp = new Properties();
+                for (envProp = env.keys(); envProp.hasMoreElements();) {
+                    String key = (String)envProp.nextElement();
+                    Object val = env.get(key);
+                    if (val instanceof String) {
+                        orbProp.put(key, val);
+                    }
+                }
+            }
+        } else {
+            orbProp = new Properties();
+        }
+
+        if (server != null) {
+            orbProp.put("org.omg.CORBA.ORBInitialHost", server);
+        }
+        if (port >= 0) {
+            orbProp.put("org.omg.CORBA.ORBInitialPort", ""+port);
+        }
+
+        // Get Applet from environment
+        if (env != null) {
+            @SuppressWarnings("deprecation")
+            Applet applet = (Applet) env.get(Context.APPLET);
+            if (applet != null) {
+            // Create ORBs using applet and orbProp
+                return ORB.init(applet, orbProp);
+            }
+        }
+
+        return ORB.init(new String[0], orbProp);
+    }
+
+    /**
+     * Decode a URI string (according to RFC 2396).
+     */
+    public static final String decode(String s) throws MalformedURLException {
+        try {
+            return decode(s, "8859_1");
+        } catch (UnsupportedEncodingException e) {
+            // ISO-Latin-1 should always be available?
+            throw new MalformedURLException("ISO-Latin-1 decoder unavailable");
+        }
+    }
+
+    /**
+     * Decode a URI string (according to RFC 2396).
+     *
+     * Three-character sequences '%xy', where 'xy' is the two-digit
+     * hexadecimal representation of the lower 8-bits of a character,
+     * are decoded into the character itself.
+     *
+     * The string is subsequently converted using the specified encoding
+     */
+    public static final String decode(String s, String enc)
+            throws MalformedURLException, UnsupportedEncodingException {
+        try {
+            return URLDecoder.decode(s, enc);
+        } catch (IllegalArgumentException iae) {
+            MalformedURLException mue = new MalformedURLException("Invalid URI encoding: " + s);
+            mue.initCause(iae);
+            throw mue;
+        }
+    }
+
+}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/url/corbaname/corbanameURLContextFactory.java b/corba/src/java.corba/share/classes/com/sun/jndi/url/corbaname/corbanameURLContextFactory.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/url/corbaname/corbanameURLContextFactory.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/url/corbaname/corbanameURLContextFactory.java
diff --git a/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/GenericURLContext.java b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/GenericURLContext.java
new file mode 100644
index 0000000..1c78b92
--- /dev/null
+++ b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/GenericURLContext.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.url.iiop;
+
+import com.sun.jndi.toolkit.corba.CorbaUtils;
+
+import javax.naming.*;
+import javax.naming.spi.ResolveResult;
+import javax.naming.spi.NamingManager;
+
+import java.util.Hashtable;
+import java.net.MalformedURLException;
+
+/**
+ * This abstract class is a generic URL context that accepts as the
+ * name argument either a string URL or a Name whose first component
+ * is a URL. It resolves the URL to a target context and then continues
+ * the operation using the remaining name in the target context as if
+ * the first component names a junction.
+ *
+ * A subclass must define getRootURLContext()
+ * to process the URL into head/tail pieces. If it wants to control how
+ * URL strings are parsed and compared for the rename() operation, then
+ * it should override getNonRootURLSuffixes() and urlEquals().
+ *
+ * @author Scott Seligman
+ * @author Rosanna Lee
+ */
+abstract public class GenericURLContext implements Context {
+    protected Hashtable<String, Object> myEnv = null;
+
+    @SuppressWarnings("unchecked") // Expect Hashtable<String, Object>
+    public GenericURLContext(Hashtable<?,?> env) {
+        // context that is not tied to any specific URL
+        myEnv =
+                (Hashtable<String, Object>)(env == null ? null : env.clone());
+    }
+
+    public void close() throws NamingException {
+        myEnv = null;
+    }
+
+    public String getNameInNamespace() throws NamingException {
+        return ""; // %%% check this out: A URL context's name is ""
+    }
+
+    /**
+     * Resolves 'name' into a target context with remaining name.
+     * For example, with a JNDI URL "jndi://dnsname/rest_name",
+     * this method resolves "jndi://dnsname/" to a target context,
+     * and returns the target context with "rest_name".
+     * The definition of "root URL" and how much of the URL to
+     * consume is implementation specific.
+     * If rename() is supported for a particular URL scheme,
+     * getRootURLContext(), getURLPrefix(), and getURLSuffix()
+     * must be in sync wrt how URLs are parsed and returned.
+     */
+    abstract protected ResolveResult getRootURLContext(String url,
+                                                       Hashtable<?,?> env) throws NamingException;
+
+    /**
+     * Returns the suffix of the url. The result should be identical to
+     * that of calling getRootURLContext().getRemainingName(), but
+     * without the overhead of doing anything with the prefix like
+     * creating a context.
+     *<p>
+     * This method returns a Name instead of a String because to give
+     * the provider an opportunity to return a Name (for example,
+     * for weakly separated naming systems like COS naming).
+     *<p>
+     * The default implementation uses skips 'prefix', calls
+     * CorbaUtils.decode() on it, and returns the result as a single component
+     * CompositeName.
+     * Subclass should override if this is not appropriate.
+     * This method is used only by rename().
+     * If rename() is supported for a particular URL scheme,
+     * getRootURLContext(), getURLPrefix(), and getURLSuffix()
+     * must be in sync wrt how URLs are parsed and returned.
+     *<p>
+     * For many URL schemes, this method is very similar to URL.getFile(),
+     * except getFile() will return a leading slash in the
+     * 2nd, 3rd, and 4th cases. For schemes like "ldap" and "iiop",
+     * the leading slash must be skipped before the name is an acceptable
+     * format for operation by the Context methods. For schemes that treat the
+     * leading slash as significant (such as "file"),
+     * the subclass must override getURLSuffix() to get the correct behavior.
+     * Remember, the behavior must match getRootURLContext().
+     *
+     * <pre>{@code
+     * URL                                     Suffix
+     * foo://host:port                         <empty string>
+     * foo://host:port/rest/of/name            rest/of/name
+     * foo:///rest/of/name                     rest/of/name
+     * foo:/rest/of/name                       rest/of/name
+     * foo:rest/of/name                        rest/of/name
+     * }</pre>
+     */
+    protected Name getURLSuffix(String prefix, String url) throws NamingException {
+        String suffix = url.substring(prefix.length());
+        if (suffix.length() == 0) {
+            return new CompositeName();
+        }
+
+        if (suffix.charAt(0) == '/') {
+            suffix = suffix.substring(1); // skip leading slash
+        }
+
+        try {
+            return new CompositeName().add(CorbaUtils.decode(suffix));
+        } catch (MalformedURLException e) {
+            throw new InvalidNameException(e.getMessage());
+        }
+    }
+
+    /**
+     * Finds the prefix of a URL.
+     * Default implementation looks for slashes and then extracts
+     * prefixes using String.substring().
+     * Subclass should override if this is not appropriate.
+     * This method is used only by rename().
+     * If rename() is supported for a particular URL scheme,
+     * getRootURLContext(), getURLPrefix(), and getURLSuffix()
+     * must be in sync wrt how URLs are parsed and returned.
+     *<p>
+     * URL                                     Prefix
+     * foo://host:port                         foo://host:port
+     * foo://host:port/rest/of/name            foo://host:port
+     * foo:///rest/of/name                     foo://
+     * foo:/rest/of/name                       foo:
+     * foo:rest/of/name                        foo:
+     */
+    protected String getURLPrefix(String url) throws NamingException {
+        int start = url.indexOf(':');
+
+        if (start < 0) {
+            throw new OperationNotSupportedException("Invalid URL: " + url);
+        }
+        ++start; // skip ':'
+
+        if (url.startsWith("//", start)) {
+            start += 2;  // skip double slash
+
+            // find last slash
+            int posn = url.indexOf('/', start);
+            if (posn >= 0) {
+                start = posn;
+            } else {
+                start = url.length();  // rest of URL
+            }
+        }
+
+        // else 0 or 1 initial slashes; start is unchanged
+        return url.substring(0, start);
+    }
+
+    /**
+     * Determines whether two URLs are the same.
+     * Default implementation uses String.equals().
+     * Subclass should override if this is not appropriate.
+     * This method is used by rename().
+     */
+    protected boolean urlEquals(String url1, String url2) {
+        return url1.equals(url2);
+    }
+
+    /**
+     * Gets the context in which to continue the operation. This method
+     * is called when this context is asked to process a multicomponent
+     * Name in which the first component is a URL.
+     * Treat the first component like a junction: resolve it and then use
+     * NamingManager.getContinuationContext() to get the target context in
+     * which to operate on the remainder of the name (n.getSuffix(1)).
+     */
+    protected Context getContinuationContext(Name n) throws NamingException {
+        Object obj = lookup(n.get(0));
+        CannotProceedException cpe = new CannotProceedException();
+        cpe.setResolvedObj(obj);
+        cpe.setEnvironment(myEnv);
+        return NamingManager.getContinuationContext(cpe);
+    }
+
+    public Object lookup(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.lookup(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public Object lookup(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return lookup(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.lookup(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public void bind(String name, Object obj) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            ctx.bind(res.getRemainingName(), obj);
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public void bind(Name name, Object obj) throws NamingException {
+        if (name.size() == 1) {
+            bind(name.get(0), obj);
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                ctx.bind(name.getSuffix(1), obj);
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public void rebind(String name, Object obj) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            ctx.rebind(res.getRemainingName(), obj);
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public void rebind(Name name, Object obj) throws NamingException {
+        if (name.size() == 1) {
+            rebind(name.get(0), obj);
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                ctx.rebind(name.getSuffix(1), obj);
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public void unbind(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            ctx.unbind(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public void unbind(Name name) throws NamingException {
+        if (name.size() == 1) {
+            unbind(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                ctx.unbind(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public void rename(String oldName, String newName) throws NamingException {
+        String oldPrefix = getURLPrefix(oldName);
+        String newPrefix = getURLPrefix(newName);
+        if (!urlEquals(oldPrefix, newPrefix)) {
+            throw new OperationNotSupportedException(
+                    "Renaming using different URL prefixes not supported : " +
+                            oldName + " " + newName);
+        }
+
+        ResolveResult res = getRootURLContext(oldName, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            ctx.rename(res.getRemainingName(), getURLSuffix(newPrefix, newName));
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public void rename(Name name, Name newName) throws NamingException {
+        if (name.size() == 1) {
+            if (newName.size() != 1) {
+                throw new OperationNotSupportedException(
+                        "Renaming to a Name with more components not supported: " + newName);
+            }
+            rename(name.get(0), newName.get(0));
+        } else {
+            // > 1 component with 1st one being URL
+            // URLs must be identical; cannot deal with diff URLs
+            if (!urlEquals(name.get(0), newName.get(0))) {
+                throw new OperationNotSupportedException(
+                        "Renaming using different URLs as first components not supported: " +
+                                name + " " + newName);
+            }
+
+            Context ctx = getContinuationContext(name);
+            try {
+                ctx.rename(name.getSuffix(1), newName.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public NamingEnumeration<NameClassPair> list(String name)   throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.list(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return list(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.list(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public NamingEnumeration<Binding> listBindings(String name)
+            throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.listBindings(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return listBindings(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.listBindings(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public void destroySubcontext(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            ctx.destroySubcontext(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public void destroySubcontext(Name name) throws NamingException {
+        if (name.size() == 1) {
+            destroySubcontext(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                ctx.destroySubcontext(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public Context createSubcontext(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.createSubcontext(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public Context createSubcontext(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return createSubcontext(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.createSubcontext(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public Object lookupLink(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.lookupLink(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public Object lookupLink(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return lookupLink(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.lookupLink(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public NameParser getNameParser(String name) throws NamingException {
+        ResolveResult res = getRootURLContext(name, myEnv);
+        Context ctx = (Context)res.getResolvedObj();
+        try {
+            return ctx.getNameParser(res.getRemainingName());
+        } finally {
+            ctx.close();
+        }
+    }
+
+    public NameParser getNameParser(Name name) throws NamingException {
+        if (name.size() == 1) {
+            return getNameParser(name.get(0));
+        } else {
+            Context ctx = getContinuationContext(name);
+            try {
+                return ctx.getNameParser(name.getSuffix(1));
+            } finally {
+                ctx.close();
+            }
+        }
+    }
+
+    public String composeName(String name, String prefix)
+            throws NamingException {
+        if (prefix.equals("")) {
+            return name;
+        } else if (name.equals("")) {
+            return prefix;
+        } else {
+            return (prefix + "/" + name);
+        }
+    }
+
+    public Name composeName(Name name, Name prefix) throws NamingException {
+        Name result = (Name)prefix.clone();
+        result.addAll(name);
+        return result;
+    }
+
+    public Object removeFromEnvironment(String propName)
+            throws NamingException {
+        if (myEnv == null) {
+            return null;
+        }
+        return myEnv.remove(propName);
+    }
+
+    public Object addToEnvironment(String propName, Object propVal)
+            throws NamingException {
+        if (myEnv == null) {
+            myEnv = new Hashtable<String, Object>(11, 0.75f);
+        }
+        return myEnv.put(propName, propVal);
+    }
+
+    @SuppressWarnings("unchecked") // clone()
+    public Hashtable<String, Object> getEnvironment() throws NamingException {
+        if (myEnv == null) {
+            return new Hashtable<>(5, 0.75f);
+        } else {
+            return (Hashtable<String, Object>)myEnv.clone();
+        }
+    }
+
+/*
+// To test, declare getURLPrefix and getURLSuffix static.
+
+    public static void main(String[] args) throws Exception {
+        String[] tests = {"file://host:port",
+                          "file:///rest/of/name",
+                          "file://host:port/rest/of/name",
+                          "file:/rest/of/name",
+                          "file:rest/of/name"};
+        for (int i = 0; i < tests.length; i++) {
+            String pre = getURLPrefix(tests[i]);
+            System.out.println(pre);
+            System.out.println(getURLSuffix(pre, tests[i]));
+        }
+    }
+*/
+}
diff --git a/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java
new file mode 100644
index 0000000..2f83f4a
--- /dev/null
+++ b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jndi.url.iiop;
+
+import javax.naming.spi.ResolveResult;
+import javax.naming.*;
+import java.util.Hashtable;
+import java.net.MalformedURLException;
+
+import com.sun.jndi.cosnaming.IiopUrl;
+import com.sun.jndi.cosnaming.CorbanameUrl;
+
+/**
+ * An IIOP URL context.
+ *
+ * @author Rosanna Lee
+ */
+
+public class iiopURLContext
+        extends GenericURLContext {
+
+    iiopURLContext(Hashtable<?,?> env) {
+        super(env);
+    }
+
+    /**
+      * Resolves 'name' into a target context with remaining name.
+      * It only resolves the hostname/port number. The remaining name
+      * contains the rest of the name found in the URL.
+      *
+      * For example, with a iiop URL "iiop://localhost:900/rest/of/name",
+      * this method resolves "iiop://localhost:900/" to the "NameService"
+      * context on for the ORB at 'localhost' on port 900,
+      * and returns as the remaining name "rest/of/name".
+      */
+    protected ResolveResult getRootURLContext(String name, Hashtable<?,?> env)
+    throws NamingException {
+        return iiopURLContextFactory.getUsingURLIgnoreRest(name, env);
+    }
+
+    /**
+     * Return the suffix of an "iiop", "iiopname", or "corbaname" url.
+     * prefix parameter is ignored.
+     */
+    protected Name getURLSuffix(String prefix, String url)
+        throws NamingException {
+        try {
+            if (url.startsWith("iiop://") || url.startsWith("iiopname://")) {
+                IiopUrl parsedUrl = new IiopUrl(url);
+                return parsedUrl.getCosName();
+            } else if (url.startsWith("corbaname:")) {
+                CorbanameUrl parsedUrl = new CorbanameUrl(url);
+                return parsedUrl.getCosName();
+            } else {
+                throw new MalformedURLException("Not a valid URL: " + url);
+            }
+        } catch (MalformedURLException e) {
+            throw new InvalidNameException(e.getMessage());
+        }
+    }
+}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContextFactory.java b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContextFactory.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContextFactory.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContextFactory.java
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/url/iiopname/iiopnameURLContextFactory.java b/corba/src/java.corba/share/classes/com/sun/jndi/url/iiopname/iiopnameURLContextFactory.java
similarity index 100%
rename from jdk/src/java.corba/share/classes/com/sun/jndi/url/iiopname/iiopnameURLContextFactory.java
rename to corba/src/java.corba/share/classes/com/sun/jndi/url/iiopname/iiopnameURLContextFactory.java
diff --git a/hotspot/.hgignore b/hotspot/.hgignore
index d3a43d0..0c053ad 100644
--- a/hotspot/.hgignore
+++ b/hotspot/.hgignore
@@ -23,3 +23,19 @@
 ^test/compiler/jvmci/\w[\w\.]*/.*\.iml
 ^test/compiler/jvmci/\w[\w\.]*/nbproject
 ^test/compiler/jvmci/\w[\w\.]*/\..*
+^test/compiler/aot/\w[\w\.]*/.*\.xml
+^test/compiler/aot/\w[\w\.]*/.*\.iml
+^test/compiler/aot/\w[\w\.]*/nbproject
+^test/compiler/aot/\w[\w\.]*/\..*
+^src/jdk.vm.compiler/\.mx.graal/env
+^src/jdk.vm.compiler/\.mx.graal/.*\.pyc
+^src/jdk.vm.compiler/\.mx.graal/eclipse-launches/.*
+^src/jdk.aot/share/classes/\w[\w\.]*/.*\.xml
+^src/jdk.aot/share/classes/\w[\w\.]*/.*\.iml
+^src/jdk.aot/share/classes/\w[\w\.]*/nbproject
+^src/jdk.aot/share/classes/\w[\w\.]*/\..*
+^src/jdk.vm.compiler/share/classes/\w[\w\.]*/.*\.xml
+^src/jdk.vm.compiler/share/classes/\w[\w\.]*/.*\.iml
+^src/jdk.vm.compiler/share/classes/\w[\w\.]*/nbproject
+^src/jdk.vm.compiler/share/classes/\w[\w\.]*/\..*
+
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 3a53193..7b65fd3 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -551,3 +551,4 @@
 a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146
 132a72c782071cc11ab25cc7c9ee167c3632fea4 jdk-9+147
 5e4e893520ecdbd517c6ed6375f0885664fe62c4 jdk-9+148
+30e1996bd55da36183434f24ed964adebf9ca71e jdk-9+149
diff --git a/hotspot/make/BuildHotspot.gmk b/hotspot/make/BuildHotspot.gmk
deleted file mode 100644
index 0ac43f6..0000000
--- a/hotspot/make/BuildHotspot.gmk
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# This must be the first rule
-default: all
-
-include $(SPEC)
-include MakeBase.gmk
-
-VARIANT_TARGETS := $(foreach v, $(JVM_VARIANTS), variant-$v)
-VARIANT_GENSRC_TARGETS := $(addsuffix -gensrc, $(VARIANT_TARGETS))
-VARIANT_LIBS_TARGETS := $(addsuffix -libs, $(VARIANT_TARGETS))
-
-$(VARIANT_GENSRC_TARGETS): variant-%-gensrc:
-	$(call LogWarn, Building JVM variant '$*' with features '$(JVM_FEATURES_$*)')
-	+$(MAKE) -f gensrc/GenerateSources.gmk JVM_VARIANT=$*
-
-$(VARIANT_LIBS_TARGETS): variant-%-libs: variant-%-gensrc
-	+$(MAKE) -f lib/CompileLibraries.gmk JVM_VARIANT=$*
-
-$(VARIANT_TARGETS): variant-%: variant-%-gensrc variant-%-libs
-
-jsig:
-	+$(MAKE) -f lib/CompileLibjsig.gmk
-
-all: $(VARIANT_TARGETS) jsig
-
-.PHONY: $(VARIANT_TARGETS) $(VARIANT_GENSRC_TARGETS) $(VARIANT_LIBS_TARGETS) \
-    jsig all
diff --git a/hotspot/make/CompileTools.gmk b/hotspot/make/CompileTools.gmk
new file mode 100644
index 0000000..ea6c504
--- /dev/null
+++ b/hotspot/make/CompileTools.gmk
@@ -0,0 +1,162 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# This must be the first rule
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+
+include JavaCompilation.gmk
+include SetupJavaCompilers.gmk
+
+TARGETS :=
+
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, hotspot, CompileTools.gmk))
+
+ifeq ($(INCLUDE_GRAAL), true)
+  VM_CI_SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes
+
+  SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.compiler/share/classes
+
+  ##############################################################################
+  # Compile the annotation processors
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
+      SETUP := GENERATE_OLDBYTECODE, \
+      SRC := \
+          $(SRC_DIR)/org.graalvm.compiler.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.core/src \
+          $(SRC_DIR)/org.graalvm.compiler.core.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
+          $(SRC_DIR)/org.graalvm.compiler.api.collections/src \
+          $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
+          $(SRC_DIR)/org.graalvm.compiler.asm/src \
+          $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
+          $(SRC_DIR)/org.graalvm.compiler.code/src \
+          $(SRC_DIR)/org.graalvm.compiler.debug/src \
+          $(SRC_DIR)/org.graalvm.compiler.graph/src \
+          $(SRC_DIR)/org.graalvm.compiler.lir/src \
+          $(SRC_DIR)/org.graalvm.compiler.loop/src \
+          $(SRC_DIR)/org.graalvm.compiler.loop.phases/src \
+          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
+          $(SRC_DIR)/org.graalvm.compiler.nodes/src \
+          $(SRC_DIR)/org.graalvm.compiler.options/src \
+          $(SRC_DIR)/org.graalvm.compiler.phases/src \
+          $(SRC_DIR)/org.graalvm.compiler.phases.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+          $(SRC_DIR)/org.graalvm.compiler.virtual/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
+          , \
+      EXCLUDE_FILES := $(EXCLUDE_FILES), \
+      BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \
+      JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar, \
+  ))
+
+  TARGETS += $(BUILD_VM_COMPILER_MATCH_PROCESSOR)
+
+  ##############################################################################
+
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \
+      SETUP := GENERATE_OLDBYTECODE, \
+      SRC := \
+          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
+          $(SRC_DIR)/org.graalvm.compiler.nodeinfo.processor/src \
+          , \
+      BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \
+      JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar, \
+  ))
+
+  TARGETS += $(BUILD_VM_COMPILER_NODEINFO_PROCESSOR)
+
+  ##############################################################################
+
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
+      SETUP := GENERATE_OLDBYTECODE, \
+      SRC := \
+          $(SRC_DIR)/org.graalvm.compiler.options/src \
+          $(SRC_DIR)/org.graalvm.compiler.options.processor/src \
+          , \
+      BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
+      JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
+  ))
+
+  TARGETS += $(BUILD_VM_COMPILER_OPTIONS_PROCESSOR)
+
+  ##############################################################################
+
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
+      SETUP := GENERATE_OLDBYTECODE, \
+      SRC := \
+          $(SRC_DIR)/org.graalvm.compiler.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
+          $(SRC_DIR)/org.graalvm.compiler.api.collections/src \
+          $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
+          $(SRC_DIR)/org.graalvm.compiler.code/src \
+          $(SRC_DIR)/org.graalvm.compiler.core.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.debug/src \
+          $(SRC_DIR)/org.graalvm.compiler.graph/src \
+          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
+          $(SRC_DIR)/org.graalvm.compiler.options/src \
+          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
+          , \
+      EXCLUDE_FILES := $(EXCLUDE_FILES), \
+      BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \
+      JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \
+  ))
+
+  TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER)
+
+  ##############################################################################
+
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \
+      SETUP := GENERATE_OLDBYTECODE, \
+      SRC := \
+          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+          $(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \
+          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
+          , \
+      EXCLUDE_FILES := $(EXCLUDE_FILES), \
+      BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \
+      JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar, \
+  ))
+
+  TARGETS += $(BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR)
+
+  ##############################################################################
+endif
+
+all: $(TARGETS)
+
+.PHONY: all
diff --git a/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk b/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk
new file mode 100644
index 0000000..f12a2e9
--- /dev/null
+++ b/hotspot/make/gensrc/Gensrc-jdk.vm.compiler.gmk
@@ -0,0 +1,152 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+
+$(eval $(call IncludeCustomExtension, hotspot, gensrc/Gensrc-jdk.vm.compiler.gmk))
+
+GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)
+SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
+
+################################################################################
+
+PROC_SRC_SUBDIRS := \
+    org.graalvm.compiler.code \
+    org.graalvm.compiler.common \
+    org.graalvm.compiler.core \
+    org.graalvm.compiler.core.aarch64 \
+    org.graalvm.compiler.core.amd64 \
+    org.graalvm.compiler.core.common \
+    org.graalvm.compiler.core.sparc \
+    org.graalvm.compiler.debug \
+    org.graalvm.compiler.hotspot \
+    org.graalvm.compiler.hotspot.aarch64 \
+    org.graalvm.compiler.hotspot.amd64 \
+    org.graalvm.compiler.hotspot.sparc \
+    org.graalvm.compiler.graph \
+    org.graalvm.compiler.java \
+    org.graalvm.compiler.lir \
+    org.graalvm.compiler.lir.amd64 \
+    org.graalvm.compiler.loop \
+    org.graalvm.compiler.loop.phases \
+    org.graalvm.compiler.nodes \
+    org.graalvm.compiler.replacements \
+    org.graalvm.compiler.replacements.aarch64 \
+    org.graalvm.compiler.replacements.amd64 \
+    org.graalvm.compiler.phases \
+    org.graalvm.compiler.phases.common \
+    org.graalvm.compiler.printer \
+    org.graalvm.compiler.virtual \
+    #
+
+PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS))
+
+PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS)))
+
+ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src)
+SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS))
+
+PROCESSOR_JARS := \
+    $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar \
+    $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar \
+    $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar \
+    $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar \
+    $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar \
+    #
+PROCESSOR_PATH := $(call PathList, $(PROCESSOR_JARS))
+
+ADD_EXPORTS := \
+    --add-exports jdk.vm.ci/jdk.vm.ci.aarch64=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.amd64=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.code=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.code.site=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.code.stack=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.common=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.aarch64=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.amd64=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.events=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspot.sparc=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.hotspotvmconfig=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.inittimer=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.services=ALL-UNNAMED \
+    --add-exports jdk.vm.ci/jdk.vm.ci.sparc=ALL-UNNAMED \
+    #
+
+$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS)
+	$(call MakeDir, $(@D))
+	$(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files))
+	$(JAVA_SMALL) $(NEW_JAVAC) \
+	    -XDignore.symbol.file \
+	    --upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none \
+	    $(ADD_EXPORTS) \
+	    -sourcepath $(SOURCEPATH) \
+	    -implicit:none \
+	    -proc:only \
+	    -processorpath $(PROCESSOR_PATH) \
+	    -d $(GENSRC_DIR) \
+	    -s $(GENSRC_DIR) \
+	    @$(@D)/_gensrc_proc_files
+	$(TOUCH) $@
+
+TARGETS += $(GENSRC_DIR)/_gensrc_proc_done
+
+################################################################################
+
+$(GENSRC_DIR)/module-info.java.extra: $(GENSRC_DIR)/_gensrc_proc_done
+	($(CD) $(GENSRC_DIR)/META-INF/providers && \
+	    p=""; \
+	    for i in $$($(LS)); do \
+	      c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
+	      if test x$$p != x$$c; then \
+                if test x$$p != x; then \
+	          $(ECHO) "    ;" >> $@; \
+	        fi; \
+	        $(ECHO) "provides $$c with" >> $@; \
+                p=$$c; \
+	      fi; \
+	      $(ECHO) "    $$i," >> $@; \
+	    done); \
+            $(ECHO) "    ;" >> $@; \
+	$(ECHO) "uses org.graalvm.compiler.options.OptionDescriptors;" >> $@; \
+	$(ECHO) "provides org.graalvm.compiler.options.OptionDescriptors with" >> $@; \
+	for i in $$($(FIND) $(GENSRC_DIR) -name '*_OptionDescriptors.java'); do \
+	    c=$$($(ECHO) $$i | $(SED) 's:.*/jdk\.vm\.compiler/\(.*\)\.java:\1:' | $(TR) '/' '.'); \
+	    $(ECHO) "    $$c," >> $@; \
+	done; \
+	$(ECHO) "    ;" >> $@;
+
+TARGETS += $(GENSRC_DIR)/module-info.java.extra
+
+################################################################################
+
+all: $(TARGETS)
+
+.PHONY: default all
diff --git a/hotspot/make/gensrc/GensrcAdlc.gmk b/hotspot/make/gensrc/GensrcAdlc.gmk
index abe6fd4..3153476 100644
--- a/hotspot/make/gensrc/GensrcAdlc.gmk
+++ b/hotspot/make/gensrc/GensrcAdlc.gmk
@@ -114,6 +114,10 @@
     ADLCFLAGS += -U_LP64
   endif
 
+  ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm)
+    ADLCFLAGS += -DARM=1
+  endif
+
   ##############################################################################
   # Concatenate all ad source files into a single file, which will be fed to
   # adlc. Also include a #line directive at the start of every included file
diff --git a/hotspot/make/hotspot.script b/hotspot/make/hotspot.script
index 942eafa..13fc625 100644
--- a/hotspot/make/hotspot.script
+++ b/hotspot/make/hotspot.script
@@ -124,15 +124,14 @@
 
 # We will set the LD_LIBRARY_PATH as follows:
 #     o		$JVMPATH (directory portion only)
-#     o		$JRE/lib/$ARCH
+#     o		$JRE/lib
 # followed by the user's previous effective LD_LIBRARY_PATH, if
 # any.
 JRE=$JDK
 JAVA_HOME=$JDK
 export JAVA_HOME
 
-ARCH=@@LIBARCH@@
-SBP=${MYDIR}:${JRE}/lib/${ARCH}
+SBP=${MYDIR}:${JRE}/lib
 
 
 # Set up a suitable LD_LIBRARY_PATH or DYLD_LIBRARY_PATH
diff --git a/hotspot/make/lib/CompileGtest.gmk b/hotspot/make/lib/CompileGtest.gmk
index 9c69a2f..a4c2c0c 100644
--- a/hotspot/make/lib/CompileGtest.gmk
+++ b/hotspot/make/lib/CompileGtest.gmk
@@ -107,6 +107,7 @@
     LDFLAGS := $(LDFLAGS_JDKEXE), \
     LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \
     LDFLAGS_solaris := -library=stlport4, \
+    LIBS_linux := $(LIBCXX), \
     LIBS_unix := -ljvm, \
     LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \
     COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
diff --git a/hotspot/make/lib/CompileJvm.gmk b/hotspot/make/lib/CompileJvm.gmk
index 5a6ec7c..870dde1 100644
--- a/hotspot/make/lib/CompileJvm.gmk
+++ b/hotspot/make/lib/CompileJvm.gmk
@@ -63,8 +63,8 @@
 # INCLUDE_SUFFIX_* is only meant for including the proper
 # platform files. Don't use it to guard code. Use the value of
 # HOTSPOT_TARGET_CPU_DEFINE etc. instead.
-# Remaining TARGET_ARCH_* is needed to distinguish closed and open
-# 64-bit ARM ports (also called AARCH64).
+# Remaining TARGET_ARCH_* is needed to select the cpu specific 
+# sources for 64-bit ARM ports (arm versus aarch64).
 JVM_CFLAGS_TARGET_DEFINES += \
     -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
     -DINCLUDE_SUFFIX_OS=_$(HOTSPOT_TARGET_OS) \
@@ -139,6 +139,20 @@
 ################################################################################
 # Platform specific setup
 
+# ARM source selection
+
+ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-arm)
+  JVM_EXCLUDE_PATTERNS += arm_64
+
+else ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-aarch64)
+  # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm 
+  # hotspot sources if HOTSPOT_TARGET_CPU_ARCH is set to arm.
+  # Exclude the aarch64 and 32 bit arm files for this build.
+  ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm)
+    JVM_EXCLUDE_PATTERNS += arm_32 aarch64
+  endif
+endif
+
 ifneq ($(filter $(OPENJDK_TARGET_OS), linux macosx windows), )
   JVM_PRECOMPILED_HEADER := $(HOTSPOT_TOPDIR)/src/share/vm/precompiled/precompiled.hpp
 endif
diff --git a/hotspot/make/lib/CompileLibjsig.gmk b/hotspot/make/lib/CompileLibjsig.gmk
index bc26ae4..fbc8abb 100644
--- a/hotspot/make/lib/CompileLibjsig.gmk
+++ b/hotspot/make/lib/CompileLibjsig.gmk
@@ -48,6 +48,12 @@
         LIBJSIG_CPU_FLAGS := -m64
       else ifeq ($(OPENJDK_TARGET_CPU), x86)
         LIBJSIG_CPU_FLAGS := -m32 -march=i586
+      else ifeq ($(OPENJDK_TARGET_CPU), ppc64)
+        LIBJSIG_CPU_FLAGS := -mcpu=powerpc64 -mtune=power5
+      else ifeq ($(OPENJDK_TARGET_CPU), ppc64le)
+        LIBJSIG_CPU_FLAGS := -DABI_ELFv2 -mcpu=power8 -mtune=power8
+      else ifeq ($(OPENJDK_TARGET_CPU), s390x)
+        LIBJSIG_CPU_FLAGS := -mbackchain -march=z10
       endif
 
     else ifeq ($(OPENJDK_TARGET_OS), solaris)
diff --git a/hotspot/make/lib/JvmFeatures.gmk b/hotspot/make/lib/JvmFeatures.gmk
index 0cb2e3c..c5e06af 100644
--- a/hotspot/make/lib/JvmFeatures.gmk
+++ b/hotspot/make/lib/JvmFeatures.gmk
@@ -146,3 +146,116 @@
       memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \
       memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
 endif
+
+ifeq ($(call check-jvm-feature, aot), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_AOT
+else
+  JVM_EXCLUDE_FILES += \
+      compiledIC_aot_x86_64.cpp compilerRuntime.cpp \
+      aotCodeHeap.cpp aotCompiledMethod.cpp aotLoader.cpp compiledIC_aot.cpp
+endif
+################################################################################
+
+ifeq ($(call check-jvm-feature, link-time-opt), true)
+  # NOTE: Disable automatic opimization level and let the explicit cflag control
+  # optimization level instead. This activates O3 on slowdebug builds, just
+  # like the old build, but it's probably not right.
+  JVM_OPTIMIZATION :=
+  JVM_CFLAGS_FEATURES += -O3 -flto
+  JVM_LDFLAGS_FEATURES += -O3 -flto -fwhole-program -fno-strict-aliasing
+endif
+
+ifeq ($(call check-jvm-feature, minimal), true)
+  ifeq ($(call check-jvm-feature, link-time-opt), false)
+    JVM_OPTIMIZATION := SIZE
+    OPT_SPEED_SRC := \
+        allocation.cpp \
+        assembler.cpp \
+        assembler_linux_arm.cpp \
+        barrierSet.cpp \
+        basicLock.cpp \
+        biasedLocking.cpp \
+        bytecode.cpp \
+        bytecodeInterpreter.cpp \
+        bytecodeInterpreter_x86.cpp \
+        c1_Compilation.cpp \
+        c1_Compiler.cpp \
+        c1_GraphBuilder.cpp \
+        c1_LinearScan.cpp \
+        c1_LIR.cpp \
+        ciEnv.cpp \
+        ciObjectFactory.cpp \
+        codeBlob.cpp \
+        constantPool.cpp \
+        constMethod.cpp \
+        classLoader.cpp \
+        classLoaderData.cpp \
+        classFileParser.cpp \
+        classFileStream.cpp \
+        cpCache.cpp \
+        defNewGeneration.cpp \
+        frame_arm.cpp \
+        genCollectedHeap.cpp \
+        generation.cpp \
+        genMarkSweep.cpp \
+        growableArray.cpp \
+        handles.cpp \
+        hashtable.cpp \
+        heap.cpp \
+        icache.cpp \
+        icache_arm.cpp \
+        instanceKlass.cpp \
+        invocationCounter.cpp \
+        iterator.cpp \
+        javaCalls.cpp \
+        javaClasses.cpp \
+        jniFastGetField_arm.cpp \
+        jvm.cpp \
+        jvm_linux.cpp \
+        linkResolver.cpp \
+        klass.cpp \
+        klassVtable.cpp \
+        markSweep.cpp \
+        memRegion.cpp \
+        memoryPool.cpp \
+        method.cpp \
+        methodHandles.cpp \
+        methodHandles_arm.cpp \
+        methodLiveness.cpp \
+        metablock.cpp \
+        metaspace.cpp \
+        mutex.cpp \
+        mutex_linux.cpp \
+        mutexLocker.cpp \
+        nativeLookup.cpp \
+        objArrayKlass.cpp \
+        os_linux.cpp \
+        os_linux_arm.cpp \
+        placeHolders.cpp \
+        quickSort.cpp \
+        resourceArea.cpp \
+        rewriter.cpp \
+        sharedRuntime.cpp \
+        signature.cpp \
+        space.cpp \
+        stackMapTable.cpp \
+        symbolTable.cpp \
+        systemDictionary.cpp \
+        symbol.cpp \
+        synchronizer.cpp \
+        threadLS_bsd_x86.cpp \
+        threadLS_linux_arm.cpp \
+        threadLS_linux_x86.cpp \
+        timer.cpp \
+        typeArrayKlass.cpp \
+        unsafe.cpp \
+        utf8.cpp \
+        vmSymbols.cpp \
+        #
+
+    $(foreach s, $(OPT_SPEED_SRC), \
+        $(eval BUILD_LIBJVM_$s_OPTIMIZATION := HIGHEST_JVM))
+
+    BUILD_LIBJVM_systemDictionary.cpp_CXXFLAGS := -fno-optimize-sibling-calls
+  endif
+endif
diff --git a/hotspot/make/lib/Lib-jdk.aot.gmk b/hotspot/make/lib/Lib-jdk.aot.gmk
new file mode 100644
index 0000000..d799fa4
--- /dev/null
+++ b/hotspot/make/lib/Lib-jdk.aot.gmk
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include $(SPEC)
+include NativeCompilation.gmk
+
+$(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.aot.gmk))
+
+##############################################################################
+# Build libjelfshim only when AOT is enabled.
+ifeq ($(ENABLE_AOT), true)
+  JELFSHIM_NAME := jelfshim
+
+  $(eval $(call SetupNativeCompilation, BUILD_LIBJELFSHIM, \
+      TOOLCHAIN := TOOLCHAIN_DEFAULT, \
+      OPTIMIZATION := LOW, \
+      LIBRARY := $(JELFSHIM_NAME), \
+      OUTPUT_DIR := $(call FindLibDirForModule, $(MODULE)), \
+      SRC := $(HOTSPOT_TOPDIR)/src/jdk.aot/unix/native/libjelfshim, \
+      CFLAGS := $(CFLAGS_JDKLIB) $(ELF_CFLAGS) \
+          -DAOT_VERSION_STRING='"$(VERSION_STRING)"' \
+          -I$(SUPPORT_OUTPUTDIR)/headers/$(MODULE), \
+      LDFLAGS := $(LDFLAGS_JDKLIB), \
+      OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lib$(JELFSHIM_NAME), \
+      LIBS := $(ELF_LIBS) $(LIBS_JDKLIB), \
+  ))
+
+  TARGETS += $(BUILD_LIBJELFSHIM)
+endif
+
+##############################################################################
diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk
index cdead40..7223733 100644
--- a/hotspot/make/test/JtregNative.gmk
+++ b/hotspot/make/test/JtregNative.gmk
@@ -53,7 +53,6 @@
     $(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \
     $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
     $(HOTSPOT_TOPDIR)/test/compiler/calls \
-    $(HOTSPOT_TOPDIR)/test/compiler/native \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleReads \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleExportsAndOpens \
@@ -97,7 +96,7 @@
     BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rwx := -z execstack
     BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeinvoke := -ljvm -lpthread
     BUILD_TEST_invoke_exeinvoke.c_OPTIMIZATION := NONE
-    BUILD_HOTSPOT_JTREG_EXECUTABLES_LDFLAGS_exeFPRegs := -ldl
+    BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeFPRegs := -ldl
 endif
 
 ifeq ($(OPENJDK_TARGET_OS), windows)
diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad
index 3708908..24bce03 100644
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad
@@ -9646,6 +9646,10 @@
 
 
 // ---------------------------------------------------------------------
+
+
+// BEGIN This section of the file is automatically generated. Do not edit --------------
+
 // Sundry CAS operations.  Note that release is always true,
 // regardless of the memory ordering of the CAS.  This is because we
 // need the volatile case to be sequentially consistent but there is
@@ -9656,10 +9660,11 @@
 // This section is generated from aarch64_ad_cas.m4
 
 
-instruct compareAndExchangeB(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{
+
+instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9673,10 +9678,10 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct compareAndExchangeS(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9690,10 +9695,10 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct compareAndExchangeI(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9705,10 +9710,10 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct compareAndExchangeL(iRegL_R0 res, indirect mem, iRegL_R2 oldval, iRegL_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9720,10 +9725,10 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct compareAndExchangeN(iRegN_R0 res, indirect mem, iRegN_R2 oldval, iRegN_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9735,10 +9740,10 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct compareAndExchangeP(iRegP_R0 res, indirect mem, iRegP_R2 oldval, iRegP_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
   ins_cost(2 * VOLATILE_REF_COST);
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -9853,6 +9858,8 @@
   %}
   ins_pipe(pipe_slow);
 %}
+
+// END This section of the file is automatically generated. Do not edit --------------
 // ---------------------------------------------------------------------
 
 instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{
@@ -12990,137 +12997,146 @@
   ins_pipe(fp_dop_reg_reg_d);
 %}
 
-// We cannot use these fused mul w add/sub ops because they don't
-// produce the same result as the equivalent separated ops
-// (essentially they don't round the intermediate result). that's a
-// shame. leaving them here in case we can idenitfy cases where it is
-// legitimate to use them
+// src1 * src2 + src3
+instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaF src3 (Binary src1 src2)));
 
+  format %{ "fmadds   $dst, $src1, $src2, $src3" %}
 
-// instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
-//   match(Set dst (AddF (MulF src1 src2) src3));
+  ins_encode %{
+    __ fmadds(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg),
+             as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fmadds   $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fmadds(as_FloatRegister($dst$$reg),
-//              as_FloatRegister($src1$$reg),
-//              as_FloatRegister($src2$$reg),
-//              as_FloatRegister($src3$$reg));
-//   %}
+// src1 * src2 + src3
+instruct maddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaD src3 (Binary src1 src2)));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fmaddd   $dst, $src1, $src2, $src3" %}
 
-// instruct maddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
-//   match(Set dst (AddD (MulD src1 src2) src3));
+  ins_encode %{
+    __ fmaddd(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg),
+             as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fmaddd   $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fmaddd(as_FloatRegister($dst$$reg),
-//              as_FloatRegister($src1$$reg),
-//              as_FloatRegister($src2$$reg),
-//              as_FloatRegister($src3$$reg));
-//   %}
+// -src1 * src2 + src3
+instruct msubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaF src3 (Binary (NegF src1) src2)));
+  match(Set dst (FmaF src3 (Binary src1 (NegF src2))));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fmsubs   $dst, $src1, $src2, $src3" %}
 
-// instruct msubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
-//   match(Set dst (AddF (MulF (NegF src1) src2) src3));
-//   match(Set dst (AddF (NegF (MulF src1 src2)) src3));
+  ins_encode %{
+    __ fmsubs(as_FloatRegister($dst$$reg),
+              as_FloatRegister($src1$$reg),
+              as_FloatRegister($src2$$reg),
+              as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fmsubs   $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fmsubs(as_FloatRegister($dst$$reg),
-//               as_FloatRegister($src1$$reg),
-//               as_FloatRegister($src2$$reg),
-//              as_FloatRegister($src3$$reg));
-//   %}
+// -src1 * src2 + src3
+instruct msubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaD src3 (Binary (NegD src1) src2)));
+  match(Set dst (FmaD src3 (Binary src1 (NegD src2))));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fmsubd   $dst, $src1, $src2, $src3" %}
 
-// instruct msubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
-//   match(Set dst (AddD (MulD (NegD src1) src2) src3));
-//   match(Set dst (AddD (NegD (MulD src1 src2)) src3));
+  ins_encode %{
+    __ fmsubd(as_FloatRegister($dst$$reg),
+              as_FloatRegister($src1$$reg),
+              as_FloatRegister($src2$$reg),
+              as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fmsubd   $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fmsubd(as_FloatRegister($dst$$reg),
-//               as_FloatRegister($src1$$reg),
-//               as_FloatRegister($src2$$reg),
-//               as_FloatRegister($src3$$reg));
-//   %}
+// -src1 * src2 - src3
+instruct mnaddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaF (NegF src3) (Binary (NegF src1) src2)));
+  match(Set dst (FmaF (NegF src3) (Binary src1 (NegF src2))));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fnmadds  $dst, $src1, $src2, $src3" %}
 
-// instruct mnaddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{
-//   match(Set dst (SubF (MulF (NegF src1) src2) src3));
-//   match(Set dst (SubF (NegF (MulF src1 src2)) src3));
+  ins_encode %{
+    __ fnmadds(as_FloatRegister($dst$$reg),
+               as_FloatRegister($src1$$reg),
+               as_FloatRegister($src2$$reg),
+               as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fnmadds  $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fnmadds(as_FloatRegister($dst$$reg),
-//                as_FloatRegister($src1$$reg),
-//                as_FloatRegister($src2$$reg),
-//                as_FloatRegister($src3$$reg));
-//   %}
+// -src1 * src2 - src3
+instruct mnaddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
+  predicate(UseFMA);
+  match(Set dst (FmaD (NegD src3) (Binary (NegD src1) src2)));
+  match(Set dst (FmaD (NegD src3) (Binary src1 (NegD src2))));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fnmaddd   $dst, $src1, $src2, $src3" %}
 
-// instruct mnaddD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3) %{
-//   match(Set dst (SubD (MulD (NegD src1) src2) src3));
-//   match(Set dst (SubD (NegD (MulD src1 src2)) src3));
+  ins_encode %{
+    __ fnmaddd(as_FloatRegister($dst$$reg),
+               as_FloatRegister($src1$$reg),
+               as_FloatRegister($src2$$reg),
+               as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fnmaddd   $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fnmaddd(as_FloatRegister($dst$$reg),
-//                as_FloatRegister($src1$$reg),
-//                as_FloatRegister($src2$$reg),
-//                as_FloatRegister($src3$$reg));
-//   %}
+// src1 * src2 - src3
+instruct mnsubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3, immF0 zero) %{
+  predicate(UseFMA);
+  match(Set dst (FmaF (NegF src3) (Binary src1 src2)));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fnmsubs  $dst, $src1, $src2, $src3" %}
 
-// instruct mnsubF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3, immF0 zero) %{
-//   match(Set dst (SubF (MulF src1 src2) src3));
+  ins_encode %{
+    __ fnmsubs(as_FloatRegister($dst$$reg),
+               as_FloatRegister($src1$$reg),
+               as_FloatRegister($src2$$reg),
+               as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fnmsubs  $dst, $src1, $src2, $src3" %}
+  ins_pipe(pipe_class_default);
+%}
 
-//   ins_encode %{
-//     __ fnmsubs(as_FloatRegister($dst$$reg),
-//                as_FloatRegister($src1$$reg),
-//                as_FloatRegister($src2$$reg),
-//                as_FloatRegister($src3$$reg));
-//   %}
+// src1 * src2 - src3
+instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zero) %{
+  predicate(UseFMA);
+  match(Set dst (FmaD (NegD src3) (Binary src1 src2)));
 
-//   ins_pipe(pipe_class_default);
-// %}
+  format %{ "fnmsubd   $dst, $src1, $src2, $src3" %}
 
-// instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zero) %{
-//   match(Set dst (SubD (MulD src1 src2) src3));
+  ins_encode %{
+  // n.b. insn name should be fnmsubd
+    __ fnmsub(as_FloatRegister($dst$$reg),
+              as_FloatRegister($src1$$reg),
+              as_FloatRegister($src2$$reg),
+              as_FloatRegister($src3$$reg));
+  %}
 
-//   format %{ "fnmsubd   $dst, $src1, $src2, $src3" %}
-
-//   ins_encode %{
-//   // n.b. insn name should be fnmsubd
-//     __ fnmsub(as_FloatRegister($dst$$reg),
-//                as_FloatRegister($src1$$reg),
-//                as_FloatRegister($src2$$reg),
-//                as_FloatRegister($src3$$reg));
-//   %}
-
-//   ins_pipe(pipe_class_default);
-// %}
+  ins_pipe(pipe_class_default);
+%}
 
 
 instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
diff --git a/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp
index a09f268..adb30aa 100644
--- a/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/abstractInterpreter_aarch64.cpp
@@ -65,7 +65,9 @@
     case Interpreter::java_lang_math_log10   : // fall thru
     case Interpreter::java_lang_math_sqrt    : // fall thru
     case Interpreter::java_lang_math_pow     : // fall thru
-    case Interpreter::java_lang_math_exp     :
+    case Interpreter::java_lang_math_exp     : // fall thru
+    case Interpreter::java_lang_math_fmaD    : // fall thru
+    case Interpreter::java_lang_math_fmaF    :
       return false;
     default:
       return true;
diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
index 8c7901e..2f97a3e 100644
--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
@@ -848,7 +848,7 @@
   // architecture.  In debug mode we shrink it in order to test
   // trampolines, but not so small that branches in the interpreter
   // are out of range.
-  static const unsigned long branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);
+  static const unsigned long branch_range = INCLUDE_JVMCI ? 128 * M : NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);
 
   static bool reachable_from_branch_at(address branch, address target) {
     return uabs(target - branch) < branch_range;
diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
index f4131ab..66686fd 100644
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
@@ -375,7 +375,7 @@
   __ nop();
 
   // generate code for exception handler
-  address handler_base = __ start_a_stub(exception_handler_size);
+  address handler_base = __ start_a_stub(exception_handler_size());
   if (handler_base == NULL) {
     // not enough space left for the handler
     bailout("exception handler overflow");
@@ -393,7 +393,7 @@
 
   // search an exception handler (r0: exception oop, r3: throwing pc)
   __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));  __ should_not_reach_here();
-  guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -467,7 +467,7 @@
   __ nop();
 
   // generate code for exception handler
-  address handler_base = __ start_a_stub(deopt_handler_size);
+  address handler_base = __ start_a_stub(deopt_handler_size());
   if (handler_base == NULL) {
     // not enough space left for the handler
     bailout("deopt handler overflow");
@@ -478,7 +478,7 @@
 
   __ adr(lr, pc());
   __ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
-  guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -1055,7 +1055,7 @@
   return exact_log2(elem_size);
 }
 
-void LIR_Assembler::emit_op3(LIR_Op3* op) {
+void LIR_Assembler::arithmetic_idiv(LIR_Op3* op, bool is_irem) {
   Register Rdividend = op->in_opr1()->as_register();
   Register Rdivisor  = op->in_opr2()->as_register();
   Register Rscratch  = op->in_opr3()->as_register();
@@ -1076,12 +1076,31 @@
     // convert division by a power of two into some shifts and logical operations
   }
 
-  if (op->code() == lir_irem) {
-    __ corrected_idivl(Rresult, Rdividend, Rdivisor, true, rscratch1);
-   } else if (op->code() == lir_idiv) {
-    __ corrected_idivl(Rresult, Rdividend, Rdivisor, false, rscratch1);
-  } else
-    ShouldNotReachHere();
+  __ corrected_idivl(Rresult, Rdividend, Rdivisor, is_irem, rscratch1);
+}
+
+void LIR_Assembler::emit_op3(LIR_Op3* op) {
+  switch (op->code()) {
+  case lir_idiv:
+    arithmetic_idiv(op, false);
+    break;
+  case lir_irem:
+    arithmetic_idiv(op, true);
+    break;
+  case lir_fmad:
+    __ fmaddd(op->result_opr()->as_double_reg(),
+              op->in_opr1()->as_double_reg(),
+              op->in_opr2()->as_double_reg(),
+              op->in_opr3()->as_double_reg());
+    break;
+  case lir_fmaf:
+    __ fmadds(op->result_opr()->as_float_reg(),
+              op->in_opr1()->as_float_reg(),
+              op->in_opr2()->as_float_reg(),
+              op->in_opr3()->as_float_reg());
+    break;
+  default:      ShouldNotReachHere(); break;
+  }
 }
 
 void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
@@ -2001,7 +2020,7 @@
 
 void LIR_Assembler::emit_static_call_stub() {
   address call_pc = __ pc();
-  address stub = __ start_a_stub(call_stub_size);
+  address stub = __ start_a_stub(call_stub_size());
   if (stub == NULL) {
     bailout("static call stub overflow");
     return;
@@ -2014,7 +2033,7 @@
   __ movptr(rscratch1, 0);
   __ br(rscratch1);
 
-  assert(__ offset() - start <= call_stub_size, "stub too big");
+  assert(__ offset() - start <= call_stub_size(), "stub too big");
   __ end_a_stub();
 }
 
@@ -2249,6 +2268,25 @@
     __ cbz(dst, *stub->entry());
   }
 
+  // If the compiler was not able to prove that exact type of the source or the destination
+  // of the arraycopy is an array type, check at runtime if the source or the destination is
+  // an instance type.
+  if (flags & LIR_OpArrayCopy::type_check) {
+    if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) {
+      __ load_klass(tmp, dst);
+      __ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset())));
+      __ cmpw(rscratch1, Klass::_lh_neutral_value);
+      __ br(Assembler::GE, *stub->entry());
+    }
+
+    if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) {
+      __ load_klass(tmp, src);
+      __ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset())));
+      __ cmpw(rscratch1, Klass::_lh_neutral_value);
+      __ br(Assembler::GE, *stub->entry());
+    }
+  }
+
   // check if negative
   if (flags & LIR_OpArrayCopy::src_pos_positive_check) {
     __ cmpw(src_pos, 0);
diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp
index f12fa86..95b89dd 100644
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp
@@ -68,14 +68,19 @@
 
   void deoptimize_trap(CodeEmitInfo *info);
 
+  enum {
+    _call_stub_size = 12 * NativeInstruction::instruction_size,
+    _call_aot_stub_size = 0,
+    _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
+    _deopt_handler_size = 7 * NativeInstruction::instruction_size
+  };
+
+  void arithmetic_idiv(LIR_Op3* op, bool is_irem);
+
 public:
 
   void store_parameter(Register r, int offset_from_esp_in_words);
   void store_parameter(jint c,     int offset_from_esp_in_words);
   void store_parameter(jobject c,  int offset_from_esp_in_words);
 
-enum { call_stub_size = 12 * NativeInstruction::instruction_size,
-       exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
-       deopt_handler_size = 7 * NativeInstruction::instruction_size };
-
 #endif // CPU_AARCH64_VM_C1_LIRASSEMBLER_AARCH64_HPP
diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp
index 0337417..96793e6 100644
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp
@@ -1034,7 +1034,26 @@
 }
 
 void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
-  fatal("FMA intrinsic is not implemented on this platform");
+  assert(x->number_of_arguments() == 3, "wrong type");
+  assert(UseFMA, "Needs FMA instructions support.");
+  LIRItem value(x->argument_at(0), this);
+  LIRItem value1(x->argument_at(1), this);
+  LIRItem value2(x->argument_at(2), this);
+
+  value.load_item();
+  value1.load_item();
+  value2.load_item();
+
+  LIR_Opr calc_input = value.result();
+  LIR_Opr calc_input1 = value1.result();
+  LIR_Opr calc_input2 = value2.result();
+  LIR_Opr calc_result = rlock_result(x);
+
+  switch (x->id()) {
+  case vmIntrinsics::_fmaD:   __ fmad(calc_input, calc_input1, calc_input2, calc_result); break;
+  case vmIntrinsics::_fmaF:   __ fmaf(calc_input, calc_input1, calc_input2, calc_result); break;
+  default:                    ShouldNotReachHere();
+  }
 }
 
 void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
diff --git a/hotspot/src/cpu/aarch64/vm/cas.m4 b/hotspot/src/cpu/aarch64/vm/cas.m4
index eb276df..b56112b 100644
--- a/hotspot/src/cpu/aarch64/vm/cas.m4
+++ b/hotspot/src/cpu/aarch64/vm/cas.m4
@@ -1,3 +1,31 @@
+dnl Copyright (c) 2016, Red Hat Inc. All rights reserved.
+dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+dnl
+dnl This code is free software; you can redistribute it and/or modify it
+dnl under the terms of the GNU General Public License version 2 only, as
+dnl published by the Free Software Foundation.
+dnl
+dnl This code is distributed in the hope that it will be useful, but WITHOUT
+dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl version 2 for more details (a copy is included in the LICENSE file that
+dnl accompanied this code).
+dnl
+dnl You should have received a copy of the GNU General Public License version
+dnl 2 along with this work; if not, write to the Free Software Foundation,
+dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+dnl
+dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+dnl or visit www.oracle.com if you need additional information or have any
+dnl questions.
+dnl
+dnl 
+dnl Process this file with m4 cas.m4 to generate the CAE and wCAS
+dnl instructions used in aarch64.ad.
+dnl
+
+// BEGIN This section of the file is automatically generated. Do not edit --------------
+
 // Sundry CAS operations.  Note that release is always true,
 // regardless of the memory ordering of the CAS.  This is because we
 // need the volatile case to be sequentially consistent but there is
@@ -5,13 +33,16 @@
 // can't check the type of memory ordering here, so we always emit a
 // STLXR.
 
+// This section is generated from aarch64_ad_cas.m4
+
+
 define(`CAS_INSN',
 `
-instruct compareAndExchange$1$5(iReg$2_R0 res, indirect mem, iReg$2_R2 oldval, iReg$2_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchange$1$5(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
   ifelse($5,Acq,'  predicate(needs_acquiring_load_exclusive(n));
   ins_cost(VOLATILE_REF_COST);`,'  ins_cost(2 * VOLATILE_REF_COST);`)
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -24,11 +55,11 @@
 %}')dnl
 define(`CAS_INSN4',
 `
-instruct compareAndExchange$1$7(iReg$2_R0 res, indirect mem, iReg$2_R2 oldval, iReg$2_R3 newval, rFlagsReg cr) %{
+instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
   match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
   ifelse($7,Acq,'  predicate(needs_acquiring_load_exclusive(n));
   ins_cost(VOLATILE_REF_COST);`,'  ins_cost(2 * VOLATILE_REF_COST);`)
-  effect(KILL cr);
+  effect(TEMP_DEF res, KILL cr);
   format %{
     "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
   %}
@@ -107,3 +138,5 @@
 dnl CAS_INSN3(N,N,narrow oop,word,Acq)
 dnl CAS_INSN3(P,P,ptr,xword,Acq)
 dnl
+
+// END This section of the file is automatically generated. Do not edit --------------
diff --git a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp
index 1999b0f..3059ad3 100644
--- a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp
@@ -76,13 +76,13 @@
   return 4; // 3 in emit_to_interp_stub + 1 in emit_call
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub = find_stub();
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(false /* is_aot */);
   guarantee(stub != NULL, "stub not found");
 
   if (TraceICs) {
     ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                   p2i(instruction_address()),
                   callee->name_and_sig_as_C_string());
   }
@@ -107,7 +107,7 @@
   set_destination_mt_safe(stub);
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   // Reset stub.
   address stub = static_stub->addr();
@@ -121,15 +121,15 @@
 // Non-product mode code
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   // Verify call.
-  NativeCall::verify();
+  _call->verify();
   if (os::is_MP()) {
-    verify_alignment();
+    _call->verify_alignment();
   }
 
   // Verify stub.
-  address stub = find_stub();
+  address stub = find_stub(false /* is_aot */);
   assert(stub != NULL, "no stub found for static call");
   // Creation also verifies the object.
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
index 76e0cbe..ed95d41 100644
--- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
@@ -407,10 +407,8 @@
     // JVMTI events, such as single-stepping, are implemented partly by avoiding running
     // compiled code in threads for which the event is enabled.  Check here for
     // interp_only_mode if these events CAN be enabled.
-    // interp_only is an int, on little endian it is sufficient to test the byte only
-    // Is a cmpl faster?
-    ldr(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
-    cbz(rscratch1, run_compiled_code);
+    ldrw(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
+    cbzw(rscratch1, run_compiled_code);
     ldr(rscratch1, Address(method, Method::interpreter_entry_offset()));
     br(rscratch1);
     bind(run_compiled_code);
diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
index eb3cc44..f9cc50f 100644
--- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
@@ -41,28 +41,34 @@
 
 void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
   address pc = _instructions->start() + pc_offset;
+#ifdef ASSERT
+  {
+    NativeInstruction *insn = nativeInstruction_at(pc);
+    if (HotSpotObjectConstantImpl::compressed(constant)) {
+      // Mov narrow constant: movz n << 16, movk
+      assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
+             nativeInstruction_at(pc+4)->is_movk(), "wrong insn in patch");
+    } else {
+      // Move wide constant: movz n, movk, movk.
+      assert(nativeInstruction_at(pc+4)->is_movk()
+             && nativeInstruction_at(pc+8)->is_movk(), "wrong insn in patch");
+    }
+  }
+#endif // ASSERT
   Handle obj = HotSpotObjectConstantImpl::object(constant);
   jobject value = JNIHandles::make_local(obj());
-  if (HotSpotObjectConstantImpl::compressed(constant)) {
-    int oop_index = _oop_recorder->find_index(value);
-    RelocationHolder rspec = oop_Relocation::spec(oop_index);
-    _instructions->relocate(pc, rspec, 1);
-    Unimplemented();
-  } else {
-    NativeMovConstReg* move = nativeMovConstReg_at(pc);
-    move->set_data((intptr_t) value);
-    int oop_index = _oop_recorder->find_index(value);
-    RelocationHolder rspec = oop_Relocation::spec(oop_index);
-    _instructions->relocate(pc, rspec);
-  }
+  MacroAssembler::patch_oop(pc, (address)obj());
+  int oop_index = _oop_recorder->find_index(value);
+  RelocationHolder rspec = oop_Relocation::spec(oop_index);
+  _instructions->relocate(pc, rspec);
 }
 
 void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
   address pc = _instructions->start() + pc_offset;
   if (HotSpotMetaspaceConstantImpl::compressed(constant)) {
     narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, CHECK);
+    MacroAssembler::patch_narrow_klass(pc, narrowOop);
     TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
-    Unimplemented();
   } else {
     NativeMovConstReg* move = nativeMovConstReg_at(pc);
     void* reference = record_metadata_reference(_instructions, pc, constant, CHECK);
@@ -167,8 +173,8 @@
   if (jvmci_reg < RegisterImpl::number_of_registers) {
     return as_Register(jvmci_reg)->as_VMReg();
   } else {
-    jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
-    if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
+    jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers_for_jvmci;
+    if (floatRegisterNumber >= 0 && floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
       return as_FloatRegister(floatRegisterNumber)->as_VMReg();
     }
     JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);
diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
index 2a2034c..76ffc9d 100644
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
@@ -185,6 +185,19 @@
   return instructions * NativeInstruction::instruction_size;
 }
 
+int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
+  // Metatdata pointers are either narrow (32 bits) or wide (48 bits).
+  // We encode narrow ones by setting the upper 16 bits in the first
+  // instruction.
+  NativeInstruction *insn = nativeInstruction_at(insn_addr);
+  assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
+         nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
+
+  Instruction_aarch64::patch(insn_addr, 20, 5, n >> 16);
+  Instruction_aarch64::patch(insn_addr+4, 20, 5, n & 0xffff);
+  return 2 * NativeInstruction::instruction_size;
+}
+
 address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) {
   long offset = 0;
   if ((Instruction_aarch64::extract(insn, 29, 24) & 0b011011) == 0b00011000) {
diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
index 6c84aa6..207292a 100644
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
@@ -590,6 +590,7 @@
 #endif
 
   static int patch_oop(address insn_addr, address o);
+  static int patch_narrow_klass(address insn_addr, narrowKlass n);
 
   address emit_trampoline_stub(int insts_call_instruction_offset, address target);
 
diff --git a/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp
index 6e935f6..8cda52a 100644
--- a/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp
@@ -42,8 +42,9 @@
 class RegisterImpl: public AbstractRegisterImpl {
  public:
   enum {
-    number_of_registers      = 32,
-    number_of_byte_registers = 32
+    number_of_registers         =   32,
+    number_of_byte_registers      = 32,
+    number_of_registers_for_jvmci = 34   // Including SP and ZR.
   };
 
   // derived registers, offsets, and addresses
@@ -103,6 +104,10 @@
 CONSTANT_REGISTER_DECLARATION(Register, r29,  (29));
 CONSTANT_REGISTER_DECLARATION(Register, r30,  (30));
 
+
+// r31 is not a general purpose register, but represents either the
+// stack pointer or the zero/discard register depending on the
+// instruction.
 CONSTANT_REGISTER_DECLARATION(Register, r31_sp, (31));
 CONSTANT_REGISTER_DECLARATION(Register, zr,  (32));
 CONSTANT_REGISTER_DECLARATION(Register, sp,  (33));
diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
index 8f17364..c8bb354 100644
--- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
@@ -2388,6 +2388,7 @@
 
     __ movw(rcpool, (int32_t)Deoptimization::Unpack_reexecute);
     __ mov(c_rarg0, rthread);
+    __ movw(c_rarg2, rcpool); // exec mode
     __ lea(rscratch1,
            RuntimeAddress(CAST_FROM_FN_PTR(address,
                                            Deoptimization::uncommon_trap)));
diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
index 41a7956..681ecf3 100644
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
@@ -2743,7 +2743,7 @@
     __ align(CodeEntryAlignment);
     StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
 
-    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52, _L_finish;
+    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
 
     const Register from        = c_rarg0;  // source array address
     const Register to          = c_rarg1;  // destination array address
@@ -2757,8 +2757,7 @@
 
       __ enter();
 
-      __ subsw(rscratch2, len_reg, zr);
-      __ br(Assembler::LE, _L_finish);
+      __ movw(rscratch2, len_reg);
 
       __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
 
@@ -2823,7 +2822,6 @@
 
       __ st1(v0, __ T16B, rvec);
 
-    __ BIND(_L_finish);
       __ mov(r0, rscratch2);
 
       __ leave();
@@ -2849,7 +2847,7 @@
     __ align(CodeEntryAlignment);
     StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
 
-    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52, _L_finish;
+    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
 
     const Register from        = c_rarg0;  // source array address
     const Register to          = c_rarg1;  // destination array address
@@ -2863,8 +2861,7 @@
 
       __ enter();
 
-      __ subsw(rscratch2, len_reg, zr);
-      __ br(Assembler::LE, _L_finish);
+      __ movw(rscratch2, len_reg);
 
       __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
 
@@ -2933,7 +2930,6 @@
 
       __ st1(v2, __ T16B, rvec);
 
-    __ BIND(_L_finish);
       __ mov(r0, rscratch2);
 
       __ leave();
diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp
index 8ff0bc6..90dcd6c 100644
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp
@@ -203,6 +203,26 @@
     __ mov(sp, r13);
     generate_transcendental_entry(kind, 2);
     break;
+  case Interpreter::java_lang_math_fmaD :
+    if (UseFMA) {
+      entry_point = __ pc();
+      __ ldrd(v0, Address(esp, 4 * Interpreter::stackElementSize));
+      __ ldrd(v1, Address(esp, 2 * Interpreter::stackElementSize));
+      __ ldrd(v2, Address(esp));
+      __ fmaddd(v0, v0, v1, v2);
+      __ mov(sp, r13); // Restore caller's SP
+    }
+    break;
+  case Interpreter::java_lang_math_fmaF :
+    if (UseFMA) {
+      entry_point = __ pc();
+      __ ldrs(v0, Address(esp, 2 * Interpreter::stackElementSize));
+      __ ldrs(v1, Address(esp, Interpreter::stackElementSize));
+      __ ldrs(v2, Address(esp));
+      __ fmadds(v0, v0, v1, v2);
+      __ mov(sp, r13); // Restore caller's SP
+    }
+    break;
   default:
     ;
   }
@@ -883,7 +903,7 @@
   //   and so we don't need to call the G1 pre-barrier. Thus we can use the
   //   regular method entry code to generate the NPE.
   //
-  // This code is based on generate_accessor_enty.
+  // This code is based on generate_accessor_entry.
   //
   // rmethod: Method*
   // r13: senderSP must preserve for slow path, set SP to it on fast path
@@ -901,11 +921,11 @@
     __ ldr(local_0, Address(esp, 0));
     __ cbz(local_0, slow_path);
 
-
     // Load the value of the referent field.
     const Address field_address(local_0, referent_offset);
     __ load_heap_oop(local_0, field_address);
 
+    __ mov(r19, r13);   // Move senderSP to a callee-saved register
     // Generate the G1 pre-barrier code to log the value of
     // the referent field in an SATB buffer.
     __ enter(); // g1_write may call runtime
@@ -917,7 +937,7 @@
                             true /* expand_call */);
     __ leave();
     // areturn
-    __ andr(sp, r13, -16);  // done with stack
+    __ andr(sp, r19, -16);  // done with stack
     __ ret(lr);
 
     // generate a vanilla interpreter entry as the slow path
diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp
index 53a294b..33cb949 100644
--- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp
@@ -262,9 +262,8 @@
     FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
   }
 
-  if (UseFMA) {
-    warning("FMA instructions are not available on this CPU");
-    FLAG_SET_DEFAULT(UseFMA, false);
+  if (FLAG_IS_DEFAULT(UseFMA)) {
+    FLAG_SET_DEFAULT(UseFMA, true);
   }
 
   if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) {
diff --git a/hotspot/src/cpu/arm/vm/abstractInterpreter_arm.cpp b/hotspot/src/cpu/arm/vm/abstractInterpreter_arm.cpp
new file mode 100644
index 0000000..7899c10
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/abstractInterpreter_arm.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "interpreter/bytecode.hpp"
+#include "interpreter/interpreter.hpp"
+#include "oops/constMethod.hpp"
+#include "oops/method.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/synchronizer.hpp"
+#include "utilities/macros.hpp"
+
+int AbstractInterpreter::BasicType_as_index(BasicType type) {
+  int i = 0;
+  switch (type) {
+#ifdef AARCH64
+    case T_BOOLEAN: i = 0; break;
+    case T_CHAR   : i = 1; break;
+    case T_BYTE   : i = 2; break;
+    case T_SHORT  : i = 3; break;
+    case T_INT    : // fall through
+    case T_LONG   : // fall through
+    case T_VOID   : // fall through
+    case T_FLOAT  : // fall through
+    case T_DOUBLE : i = 4; break;
+    case T_OBJECT : // fall through
+    case T_ARRAY  : i = 5; break;
+#else
+    case T_VOID   : i = 0; break;
+    case T_BOOLEAN: i = 1; break;
+    case T_CHAR   : i = 2; break;
+    case T_BYTE   : i = 3; break;
+    case T_SHORT  : i = 4; break;
+    case T_INT    : i = 5; break;
+    case T_OBJECT : // fall through
+    case T_ARRAY  : i = 6; break;
+    case T_LONG   : i = 7; break;
+    case T_FLOAT  : i = 8; break;
+    case T_DOUBLE : i = 9; break;
+#endif // AARCH64
+    default       : ShouldNotReachHere();
+  }
+  assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
+  return i;
+}
+
+// These should never be compiled since the interpreter will prefer
+// the compiled version to the intrinsic version.
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+  switch (method_kind(m)) {
+    case Interpreter::java_lang_math_sin     : // fall thru
+    case Interpreter::java_lang_math_cos     : // fall thru
+    case Interpreter::java_lang_math_tan     : // fall thru
+    case Interpreter::java_lang_math_abs     : // fall thru
+    case Interpreter::java_lang_math_log     : // fall thru
+    case Interpreter::java_lang_math_log10   : // fall thru
+    case Interpreter::java_lang_math_sqrt    :
+      return false;
+    default:
+      return true;
+  }
+}
+
+// How much stack a method activation needs in words.
+int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
+  const int stub_code = AARCH64_ONLY(24) NOT_AARCH64(12);  // see generate_call_stub
+  // Save space for one monitor to get into the interpreted method in case
+  // the method is synchronized
+  int monitor_size    = method->is_synchronized() ?
+                                1*frame::interpreter_frame_monitor_size() : 0;
+
+  // total overhead size: monitor_size + (sender SP, thru expr stack bottom).
+  // be sure to change this if you add/subtract anything to/from the overhead area
+  const int overhead_size = monitor_size +
+                            (frame::sender_sp_offset - frame::interpreter_frame_initial_sp_offset);
+  const int method_stack = (method->max_locals() + method->max_stack()) *
+                           Interpreter::stackElementWords;
+  return overhead_size + method_stack + stub_code;
+}
+
+// asm based interpreter deoptimization helpers
+int AbstractInterpreter::size_activation(int max_stack,
+                                         int tempcount,
+                                         int extra_args,
+                                         int moncount,
+                                         int callee_param_count,
+                                         int callee_locals,
+                                         bool is_top_frame) {
+  // Note: This calculation must exactly parallel the frame setup
+  // in TemplateInterpreterGenerator::generate_fixed_frame.
+  // fixed size of an interpreter frame:
+  int overhead = frame::sender_sp_offset - frame::interpreter_frame_initial_sp_offset;
+
+  // Our locals were accounted for by the caller (or last_frame_adjust on the transistion)
+  // Since the callee parameters already account for the callee's params we only need to account for
+  // the extra locals.
+
+  int size = overhead +
+         ((callee_locals - callee_param_count)*Interpreter::stackElementWords) +
+         (moncount*frame::interpreter_frame_monitor_size()) +
+         tempcount*Interpreter::stackElementWords + extra_args;
+
+#ifdef AARCH64
+  size = round_to(size, StackAlignmentInBytes/BytesPerWord);
+#endif // AARCH64
+
+  return size;
+}
+
+void AbstractInterpreter::layout_activation(Method* method,
+                                            int tempcount,
+                                            int popframe_extra_args,
+                                            int moncount,
+                                            int caller_actual_parameters,
+                                            int callee_param_count,
+                                            int callee_locals,
+                                            frame* caller,
+                                            frame* interpreter_frame,
+                                            bool is_top_frame,
+                                            bool is_bottom_frame) {
+
+  // Set up the method, locals, and monitors.
+  // The frame interpreter_frame is guaranteed to be the right size,
+  // as determined by a previous call to the size_activation() method.
+  // It is also guaranteed to be walkable even though it is in a skeletal state
+  // NOTE: return size is in words not bytes
+
+  // fixed size of an interpreter frame:
+  int max_locals = method->max_locals() * Interpreter::stackElementWords;
+  int extra_locals = (method->max_locals() - method->size_of_parameters()) * Interpreter::stackElementWords;
+
+#ifdef ASSERT
+  assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable");
+#endif
+
+  interpreter_frame->interpreter_frame_set_method(method);
+  // NOTE the difference in using sender_sp and interpreter_frame_sender_sp
+  // interpreter_frame_sender_sp is the original sp of the caller (the unextended_sp)
+  // and sender_sp is (fp + sender_sp_offset*wordSize)
+
+#ifdef AARCH64
+  intptr_t* locals;
+  if (caller->is_interpreted_frame()) {
+    // attach locals to the expression stack of caller interpreter frame
+    locals = caller->interpreter_frame_tos_address() + caller_actual_parameters*Interpreter::stackElementWords - 1;
+  } else {
+    assert (is_bottom_frame, "should be");
+    locals = interpreter_frame->fp() + frame::sender_sp_offset + method->max_locals() - 1;
+  }
+
+  if (TraceDeoptimization) {
+    tty->print_cr("layout_activation:");
+
+    if (caller->is_entry_frame()) {
+      tty->print("entry ");
+    }
+    if (caller->is_compiled_frame()) {
+      tty->print("compiled ");
+    }
+    if (caller->is_interpreted_frame()) {
+      tty->print("interpreted ");
+    }
+    tty->print_cr("caller: sp=%p, unextended_sp=%p, fp=%p, pc=%p", caller->sp(), caller->unextended_sp(), caller->fp(), caller->pc());
+    tty->print_cr("interpreter_frame: sp=%p, unextended_sp=%p, fp=%p, pc=%p", interpreter_frame->sp(), interpreter_frame->unextended_sp(), interpreter_frame->fp(), interpreter_frame->pc());
+    tty->print_cr("method: max_locals = %d, size_of_parameters = %d", method->max_locals(), method->size_of_parameters());
+    tty->print_cr("caller_actual_parameters = %d", caller_actual_parameters);
+    tty->print_cr("locals = %p", locals);
+  }
+
+#ifdef ASSERT
+  if (caller_actual_parameters != method->size_of_parameters()) {
+    assert(caller->is_interpreted_frame(), "adjusted caller_actual_parameters, but caller is not interpreter frame");
+    Bytecode_invoke inv(caller->interpreter_frame_method(), caller->interpreter_frame_bci());
+
+    if (is_bottom_frame) {
+      assert(caller_actual_parameters == 0, "invalid adjusted caller_actual_parameters value for bottom frame");
+      assert(inv.is_invokedynamic() || inv.is_invokehandle(), "adjusted caller_actual_parameters for bottom frame, but not invokedynamic/invokehandle");
+    } else {
+      assert(caller_actual_parameters == method->size_of_parameters()+1, "invalid adjusted caller_actual_parameters value");
+      assert(!inv.is_invokedynamic() && MethodHandles::has_member_arg(inv.klass(), inv.name()), "adjusted caller_actual_parameters, but no member arg");
+    }
+  }
+  if (caller->is_interpreted_frame()) {
+    intptr_t* locals_base = (locals - method->max_locals()*Interpreter::stackElementWords + 1);
+    locals_base = (intptr_t*)round_down((intptr_t)locals_base, StackAlignmentInBytes);
+    assert(interpreter_frame->sender_sp() <= locals_base, "interpreter-to-interpreter frame chaining");
+
+  } else if (caller->is_compiled_frame()) {
+    assert(locals + 1 <= caller->unextended_sp(), "compiled-to-interpreter frame chaining");
+
+  } else {
+    assert(caller->is_entry_frame(), "should be");
+    assert(locals + 1 <= caller->fp(), "entry-to-interpreter frame chaining");
+  }
+#endif // ASSERT
+
+#else
+  intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1;
+#endif // AARCH64
+
+  interpreter_frame->interpreter_frame_set_locals(locals);
+  BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin();
+  BasicObjectLock* monbot = montop - moncount;
+  interpreter_frame->interpreter_frame_set_monitor_end(monbot);
+
+  // Set last_sp
+  intptr_t* stack_top = (intptr_t*) monbot  -
+    tempcount*Interpreter::stackElementWords -
+    popframe_extra_args;
+#ifdef AARCH64
+  interpreter_frame->interpreter_frame_set_stack_top(stack_top);
+
+  intptr_t* extended_sp = (intptr_t*) monbot  -
+    (method->max_stack() + 1) * Interpreter::stackElementWords - // +1 is reserved slot for exception handler
+    popframe_extra_args;
+  extended_sp = (intptr_t*)round_down((intptr_t)extended_sp, StackAlignmentInBytes);
+  interpreter_frame->interpreter_frame_set_extended_sp(extended_sp);
+#else
+  interpreter_frame->interpreter_frame_set_last_sp(stack_top);
+#endif // AARCH64
+
+  // All frames but the initial (oldest) interpreter frame we fill in have a
+  // value for sender_sp that allows walking the stack but isn't
+  // truly correct. Correct the value here.
+
+#ifdef AARCH64
+  if (caller->is_interpreted_frame()) {
+    intptr_t* sender_sp = (intptr_t*)round_down((intptr_t)caller->interpreter_frame_tos_address(), StackAlignmentInBytes);
+    interpreter_frame->set_interpreter_frame_sender_sp(sender_sp);
+
+  } else {
+    // in case of non-interpreter caller sender_sp of the oldest frame is already
+    // set to valid value
+  }
+#else
+  if (extra_locals != 0 &&
+      interpreter_frame->sender_sp() == interpreter_frame->interpreter_frame_sender_sp() ) {
+    interpreter_frame->set_interpreter_frame_sender_sp(caller->sp() + extra_locals);
+  }
+#endif // AARCH64
+
+  *interpreter_frame->interpreter_frame_cache_addr() =
+    method->constants()->cache();
+  *interpreter_frame->interpreter_frame_mirror_addr() =
+    method->method_holder()->java_mirror();
+}
diff --git a/hotspot/src/cpu/arm/vm/arm.ad b/hotspot/src/cpu/arm/vm/arm.ad
new file mode 100644
index 0000000..ef84124
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/arm.ad
@@ -0,0 +1,14428 @@
+//
+// Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code 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 General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+// ARM Architecture Description File
+
+//----------DEFINITION BLOCK---------------------------------------------------
+// Define name --> value mappings to inform the ADLC of an integer valued name
+// Current support includes integer values in the range [0, 0x7FFFFFFF]
+// Format:
+//        int_def  <name>         ( <int_value>, <expression>);
+// Generated Code in ad_<arch>.hpp
+//        #define  <name>   (<expression>)
+//        // value == <int_value>
+// Generated code in ad_<arch>.cpp adlc_verification()
+//        assert( <name> == <int_value>, "Expect (<expression>) to equal <int_value>");
+//
+definitions %{
+// The default cost (of an ALU instruction).
+  int_def DEFAULT_COST      (    100,     100);
+  int_def HUGE_COST         (1000000, 1000000);
+
+// Memory refs are twice as expensive as run-of-the-mill.
+  int_def MEMORY_REF_COST   (    200, DEFAULT_COST * 2);
+
+// Branches are even more expensive.
+  int_def BRANCH_COST       (    300, DEFAULT_COST * 3);
+  int_def CALL_COST         (    300, DEFAULT_COST * 3);
+%}
+
+
+//----------SOURCE BLOCK-------------------------------------------------------
+// This is a block of C++ code which provides values, functions, and
+// definitions necessary in the rest of the architecture description
+source_hpp %{
+// Header information of the source block.
+// Method declarations/definitions which are used outside
+// the ad-scope can conveniently be defined here.
+//
+// To keep related declarations/definitions/uses close together,
+// we switch between source %{ }% and source_hpp %{ }% freely as needed.
+
+// Does destination need to be loaded in a register then passed to a
+// branch instruction?
+extern bool maybe_far_call(const CallNode *n);
+extern bool maybe_far_call(const MachCallNode *n);
+static inline bool cache_reachable() {
+  return MacroAssembler::_cache_fully_reachable();
+}
+
+#ifdef AARCH64
+#define ldr_32 ldr_w
+#define str_32 str_w
+#else
+#define ldr_32 ldr
+#define str_32 str
+#define tst_32 tst
+#define teq_32 teq
+#endif
+#if 1
+extern bool PrintOptoAssembly;
+#endif
+
+class c2 {
+public:
+  static OptoRegPair return_value(int ideal_reg);
+};
+
+class CallStubImpl {
+
+  //--------------------------------------------------------------
+  //---<  Used for optimization in Compile::Shorten_branches  >---
+  //--------------------------------------------------------------
+
+ public:
+  // Size of call trampoline stub.
+  static uint size_call_trampoline() {
+    return 0; // no call trampolines on this platform
+  }
+
+  // number of relocations needed by a call trampoline stub
+  static uint reloc_call_trampoline() {
+    return 0; // no call trampolines on this platform
+  }
+};
+
+class HandlerImpl {
+
+ public:
+
+  static int emit_exception_handler(CodeBuffer &cbuf);
+  static int emit_deopt_handler(CodeBuffer& cbuf);
+
+  static uint size_exception_handler() {
+#ifdef AARCH64
+    // ldr_literal; br; (pad); <literal>
+    return 3 * Assembler::InstructionSize + wordSize;
+#else
+    return ( 3 * 4 );
+#endif
+  }
+
+
+  static uint size_deopt_handler() {
+    return ( 9 * 4 );
+  }
+
+};
+
+%}
+
+source %{
+#define __ _masm.
+
+static FloatRegister reg_to_FloatRegister_object(int register_encoding);
+static Register reg_to_register_object(int register_encoding);
+
+
+// ****************************************************************************
+
+// REQUIRED FUNCTIONALITY
+
+// Indicate if the safepoint node needs the polling page as an input.
+// Since ARM does not have absolute addressing, it does.
+bool SafePointNode::needs_polling_address_input() {
+  return true;
+}
+
+// emit an interrupt that is caught by the debugger (for debugging compiler)
+void emit_break(CodeBuffer &cbuf) {
+  MacroAssembler _masm(&cbuf);
+  __ breakpoint();
+}
+
+#ifndef PRODUCT
+void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const {
+  st->print("TA");
+}
+#endif
+
+void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  emit_break(cbuf);
+}
+
+uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
+  return MachNode::size(ra_);
+}
+
+
+void emit_nop(CodeBuffer &cbuf) {
+  MacroAssembler _masm(&cbuf);
+  __ nop();
+}
+
+
+void emit_call_reloc(CodeBuffer &cbuf, const MachCallNode *n, MachOper *m, RelocationHolder const& rspec) {
+  int ret_addr_offset0 = n->as_MachCall()->ret_addr_offset();
+  int call_site_offset = cbuf.insts()->mark_off();
+  MacroAssembler _masm(&cbuf);
+  __ set_inst_mark(); // needed in emit_to_interp_stub() to locate the call
+  address target = (address)m->method();
+  assert(n->as_MachCall()->entry_point() == target, "sanity");
+  assert(maybe_far_call(n) == !__ reachable_from_cache(target), "sanity");
+  assert(cache_reachable() == __ cache_fully_reachable(), "sanity");
+
+  assert(target != NULL, "need real address");
+
+  int ret_addr_offset = -1;
+  if (rspec.type() == relocInfo::runtime_call_type) {
+    __ call(target, rspec);
+    ret_addr_offset = __ offset();
+  } else {
+    // scratches Rtemp
+    ret_addr_offset = __ patchable_call(target, rspec, true);
+  }
+  assert(ret_addr_offset - call_site_offset == ret_addr_offset0, "fix ret_addr_offset()");
+}
+
+//=============================================================================
+// REQUIRED FUNCTIONALITY for encoding
+void emit_lo(CodeBuffer &cbuf, int val) {  }
+void emit_hi(CodeBuffer &cbuf, int val) {  }
+
+
+//=============================================================================
+const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
+
+int Compile::ConstantTable::calculate_table_base_offset() const {
+#ifdef AARCH64
+  return 0;
+#else
+  int offset = -(size() / 2);
+  // flds, fldd: 8-bit  offset multiplied by 4: +/- 1024
+  // ldr, ldrb : 12-bit offset:                 +/- 4096
+  if (!Assembler::is_simm10(offset)) {
+    offset = Assembler::min_simm10();
+  }
+  return offset;
+#endif
+}
+
+bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
+void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
+  ShouldNotReachHere();
+}
+
+void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
+  Compile* C = ra_->C;
+  Compile::ConstantTable& constant_table = C->constant_table();
+  MacroAssembler _masm(&cbuf);
+
+  Register r = as_Register(ra_->get_encode(this));
+  CodeSection* consts_section = __ code()->consts();
+  int consts_size = consts_section->align_at_start(consts_section->size());
+  assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size);
+
+  // Materialize the constant table base.
+  address baseaddr = consts_section->start() + -(constant_table.table_base_offset());
+  RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
+  __ mov_address(r, baseaddr, rspec);
+}
+
+uint MachConstantBaseNode::size(PhaseRegAlloc*) const {
+#ifdef AARCH64
+  return 5 * Assembler::InstructionSize;
+#else
+  return 8;
+#endif
+}
+
+#ifndef PRODUCT
+void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
+  char reg[128];
+  ra_->dump_register(this, reg);
+  st->print("MOV_SLOW    &constanttable,%s\t! constant table base", reg);
+}
+#endif
+
+#ifndef PRODUCT
+void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
+  Compile* C = ra_->C;
+
+  for (int i = 0; i < OptoPrologueNops; i++) {
+    st->print_cr("NOP"); st->print("\t");
+  }
+#ifdef AARCH64
+  if (OptoPrologueNops <= 0) {
+    st->print_cr("NOP\t! required for safe patching");
+    st->print("\t");
+  }
+#endif
+
+  size_t framesize = C->frame_size_in_bytes();
+  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
+  int bangsize = C->bang_size_in_bytes();
+  // Remove two words for return addr and rbp,
+  framesize -= 2*wordSize;
+  bangsize -= 2*wordSize;
+
+  // Calls to C2R adapters often do not accept exceptional returns.
+  // We require that their callers must bang for them.  But be careful, because
+  // some VM calls (such as call site linkage) can use several kilobytes of
+  // stack.  But the stack safety zone should account for that.
+  // See bugs 4446381, 4468289, 4497237.
+  if (C->need_stack_bang(bangsize)) {
+    st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
+  }
+  st->print_cr("PUSH   R_FP|R_LR_LR"); st->print("\t");
+  if (framesize != 0) {
+    st->print   ("SUB    R_SP, R_SP, " SIZE_FORMAT,framesize);
+  }
+}
+#endif
+
+void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  Compile* C = ra_->C;
+  MacroAssembler _masm(&cbuf);
+
+  for (int i = 0; i < OptoPrologueNops; i++) {
+    __ nop();
+  }
+#ifdef AARCH64
+  if (OptoPrologueNops <= 0) {
+    __ nop(); // required for safe patching by patch_verified_entry()
+  }
+#endif
+
+  size_t framesize = C->frame_size_in_bytes();
+  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
+  int bangsize = C->bang_size_in_bytes();
+  // Remove two words for return addr and fp,
+  framesize -= 2*wordSize;
+  bangsize -= 2*wordSize;
+
+  // Calls to C2R adapters often do not accept exceptional returns.
+  // We require that their callers must bang for them.  But be careful, because
+  // some VM calls (such as call site linkage) can use several kilobytes of
+  // stack.  But the stack safety zone should account for that.
+  // See bugs 4446381, 4468289, 4497237.
+  if (C->need_stack_bang(bangsize)) {
+    __ arm_stack_overflow_check(bangsize, Rtemp);
+  }
+
+  __ raw_push(FP, LR);
+  if (framesize != 0) {
+    __ sub_slow(SP, SP, framesize);
+  }
+
+  // offset from scratch buffer is not valid
+  if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
+    C->set_frame_complete( __ offset() );
+  }
+
+  if (C->has_mach_constant_base_node()) {
+    // NOTE: We set the table base offset here because users might be
+    // emitted before MachConstantBaseNode.
+    Compile::ConstantTable& constant_table = C->constant_table();
+    constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
+  }
+}
+
+uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
+  return MachNode::size(ra_);
+}
+
+int MachPrologNode::reloc() const {
+  return 10; // a large enough number
+}
+
+//=============================================================================
+#ifndef PRODUCT
+void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
+  Compile* C = ra_->C;
+
+  size_t framesize = C->frame_size_in_bytes();
+  framesize -= 2*wordSize;
+
+  if (framesize != 0) {
+    st->print("ADD    R_SP, R_SP, " SIZE_FORMAT "\n\t",framesize);
+  }
+  st->print("POP    R_FP|R_LR_LR");
+
+  if (do_polling() && ra_->C->is_method_compilation()) {
+    st->print("\n\t");
+#ifdef AARCH64
+    if (MacroAssembler::page_reachable_from_cache(os::get_polling_page())) {
+      st->print("ADRP     Rtemp, #PollAddr\t! Load Polling address\n\t");
+      st->print("LDR      ZR,[Rtemp + #PollAddr & 0xfff]\t!Poll for Safepointing");
+    } else {
+      st->print("mov_slow Rtemp, #PollAddr\t! Load Polling address\n\t");
+      st->print("LDR      ZR,[Rtemp]\t!Poll for Safepointing");
+    }
+#else
+    st->print("MOV    Rtemp, #PollAddr\t! Load Polling address\n\t");
+    st->print("LDR    Rtemp,[Rtemp]\t!Poll for Safepointing");
+#endif
+  }
+}
+#endif
+
+void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  MacroAssembler _masm(&cbuf);
+  Compile* C = ra_->C;
+
+  size_t framesize = C->frame_size_in_bytes();
+  framesize -= 2*wordSize;
+  if (framesize != 0) {
+    __ add_slow(SP, SP, framesize);
+  }
+  __ raw_pop(FP, LR);
+
+  // If this does safepoint polling, then do it here
+  if (do_polling() && ra_->C->is_method_compilation()) {
+#ifdef AARCH64
+    if (false && MacroAssembler::page_reachable_from_cache(os::get_polling_page())) {
+/* FIXME: TODO
+      __ relocate(relocInfo::xxx);
+      __ adrp(Rtemp, (intptr_t)os::get_polling_page());
+      __ relocate(relocInfo::poll_return_type);
+      int offset = os::get_polling_page() & 0xfff;
+      __ ldr(ZR, Address(Rtemp + offset));
+*/
+    } else {
+      __ mov_address(Rtemp, (address)os::get_polling_page(), symbolic_Relocation::polling_page_reference);
+      __ relocate(relocInfo::poll_return_type);
+      __ ldr(ZR, Address(Rtemp));
+    }
+#else
+    // mov_slow here is usually one or two instruction
+    __ mov_address(Rtemp, (address)os::get_polling_page(), symbolic_Relocation::polling_page_reference);
+    __ relocate(relocInfo::poll_return_type);
+    __ ldr(Rtemp, Address(Rtemp));
+#endif
+  }
+}
+
+uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
+#ifdef AARCH64
+  // allow for added alignment nop from mov_address bind_literal
+  return MachNode::size(ra_) + 1 * Assembler::InstructionSize;
+#else
+  return MachNode::size(ra_);
+#endif
+}
+
+int MachEpilogNode::reloc() const {
+  return 16; // a large enough number
+}
+
+const Pipeline * MachEpilogNode::pipeline() const {
+  return MachNode::pipeline_class();
+}
+
+int MachEpilogNode::safepoint_offset() const {
+  assert( do_polling(), "no return for this epilog node");
+  //  return MacroAssembler::size_of_sethi(os::get_polling_page());
+  Unimplemented();
+  return 0;
+}
+
+//=============================================================================
+
+// Figure out which register class each belongs in: rc_int, rc_float, rc_stack
+enum RC { rc_bad, rc_int, rc_float, rc_stack };
+static enum RC rc_class( OptoReg::Name reg ) {
+  if (!OptoReg::is_valid(reg)) return rc_bad;
+  if (OptoReg::is_stack(reg)) return rc_stack;
+  VMReg r = OptoReg::as_VMReg(reg);
+  if (r->is_Register()) return rc_int;
+  assert(r->is_FloatRegister(), "must be");
+  return rc_float;
+}
+
+static inline bool is_iRegLd_memhd(OptoReg::Name src_first, OptoReg::Name src_second, int offset) {
+#ifdef AARCH64
+  return is_memoryHD(offset);
+#else
+  int rlo = Matcher::_regEncode[src_first];
+  int rhi = Matcher::_regEncode[src_second];
+  if (!((rlo&1)==0 && (rlo+1 == rhi))) {
+    tty->print_cr("CAUGHT BAD LDRD/STRD");
+  }
+  return (rlo&1)==0 && (rlo+1 == rhi) && is_memoryHD(offset);
+#endif
+}
+
+uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
+                                        PhaseRegAlloc *ra_,
+                                        bool do_size,
+                                        outputStream* st ) const {
+  // Get registers to move
+  OptoReg::Name src_second = ra_->get_reg_second(in(1));
+  OptoReg::Name src_first = ra_->get_reg_first(in(1));
+  OptoReg::Name dst_second = ra_->get_reg_second(this );
+  OptoReg::Name dst_first = ra_->get_reg_first(this );
+
+  enum RC src_second_rc = rc_class(src_second);
+  enum RC src_first_rc = rc_class(src_first);
+  enum RC dst_second_rc = rc_class(dst_second);
+  enum RC dst_first_rc = rc_class(dst_first);
+
+  assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" );
+
+  // Generate spill code!
+  int size = 0;
+
+  if (src_first == dst_first && src_second == dst_second)
+    return size;            // Self copy, no move
+
+#ifdef TODO
+  if (bottom_type()->isa_vect() != NULL) {
+  }
+#endif
+
+  // Shared code does not expect instruction set capability based bailouts here.
+  // Handle offset unreachable bailout with minimal change in shared code.
+  // Bailout only for real instruction emit.
+  // This requires a single comment change in shared code. ( see output.cpp "Normal" instruction case )
+
+  MacroAssembler _masm(cbuf);
+
+  // --------------------------------------
+  // Check for mem-mem move.  Load into unused float registers and fall into
+  // the float-store case.
+  if (src_first_rc == rc_stack && dst_first_rc == rc_stack) {
+    int offset = ra_->reg2offset(src_first);
+    if (cbuf && !is_memoryfp(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      if (src_second_rc != rc_bad) {
+        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
+        src_first     = OptoReg::Name(R_mem_copy_lo_num);
+        src_second    = OptoReg::Name(R_mem_copy_hi_num);
+        src_first_rc  = rc_float;
+        src_second_rc = rc_float;
+        if (cbuf) {
+          __ ldr_double(Rmemcopy, Address(SP, offset));
+        } else if (!do_size) {
+          st->print(LDR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
+        }
+      } else {
+        src_first     = OptoReg::Name(R_mem_copy_lo_num);
+        src_first_rc  = rc_float;
+        if (cbuf) {
+          __ ldr_float(Rmemcopy, Address(SP, offset));
+        } else if (!do_size) {
+          st->print(LDR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
+        }
+      }
+      size += 4;
+    }
+  }
+
+  if (src_second_rc == rc_stack && dst_second_rc == rc_stack) {
+    Unimplemented();
+  }
+
+  // --------------------------------------
+  // Check for integer reg-reg copy
+  if (src_first_rc == rc_int && dst_first_rc == rc_int) {
+    // Else normal reg-reg copy
+    assert( src_second != dst_first, "smashed second before evacuating it" );
+    if (cbuf) {
+      __ mov(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
+#ifndef PRODUCT
+    } else if (!do_size) {
+      st->print("MOV    R_%s, R_%s\t# spill",
+                Matcher::regName[dst_first],
+                Matcher::regName[src_first]);
+#endif
+    }
+#ifdef AARCH64
+    if (src_first+1 == src_second && dst_first+1 == dst_second) {
+      return size + 4;
+    }
+#endif
+    size += 4;
+  }
+
+  // Check for integer store
+  if (src_first_rc == rc_int && dst_first_rc == rc_stack) {
+    int offset = ra_->reg2offset(dst_first);
+    if (cbuf && !is_memoryI(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      if (src_second_rc != rc_bad && is_iRegLd_memhd(src_first, src_second, offset)) {
+        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
+        if (cbuf) {
+          __ str_64(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(STR_64 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
+#endif
+        }
+        return size + 4;
+      } else {
+        if (cbuf) {
+          __ str_32(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(STR_32 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
+#endif
+        }
+      }
+    }
+    size += 4;
+  }
+
+  // Check for integer load
+  if (dst_first_rc == rc_int && src_first_rc == rc_stack) {
+    int offset = ra_->reg2offset(src_first);
+    if (cbuf && !is_memoryI(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      if (src_second_rc != rc_bad && is_iRegLd_memhd(dst_first, dst_second, offset)) {
+        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
+        if (cbuf) {
+          __ ldr_64(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(LDR_64 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
+#endif
+        }
+        return size + 4;
+      } else {
+        if (cbuf) {
+          __ ldr_32(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(LDR_32 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
+#endif
+        }
+      }
+    }
+    size += 4;
+  }
+
+  // Check for float reg-reg copy
+  if (src_first_rc == rc_float && dst_first_rc == rc_float) {
+    if (src_second_rc != rc_bad) {
+      assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
+      if (cbuf) {
+      __ mov_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
+#ifndef PRODUCT
+      } else if (!do_size) {
+        st->print(MOV_DOUBLE "    R_%s, R_%s\t# spill",
+                  Matcher::regName[dst_first],
+                  Matcher::regName[src_first]);
+#endif
+      }
+      return 4;
+    }
+    if (cbuf) {
+      __ mov_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
+#ifndef PRODUCT
+    } else if (!do_size) {
+      st->print(MOV_FLOAT "    R_%s, R_%s\t# spill",
+                Matcher::regName[dst_first],
+                Matcher::regName[src_first]);
+#endif
+    }
+    size = 4;
+  }
+
+  // Check for float store
+  if (src_first_rc == rc_float && dst_first_rc == rc_stack) {
+    int offset = ra_->reg2offset(dst_first);
+    if (cbuf && !is_memoryfp(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      // Further check for aligned-adjacent pair, so we can use a double store
+      if (src_second_rc != rc_bad) {
+        assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
+        if (cbuf) {
+          __ str_double(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(STR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
+#endif
+        }
+        return size + 4;
+      } else {
+        if (cbuf) {
+          __ str_float(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(STR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
+#endif
+        }
+      }
+    }
+    size += 4;
+  }
+
+  // Check for float load
+  if (dst_first_rc == rc_float && src_first_rc == rc_stack) {
+    int offset = ra_->reg2offset(src_first);
+    if (cbuf && !is_memoryfp(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      // Further check for aligned-adjacent pair, so we can use a double store
+      if (src_second_rc != rc_bad) {
+        assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
+        if (cbuf) {
+          __ ldr_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(LDR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
+#endif
+        }
+        return size + 4;
+      } else {
+        if (cbuf) {
+          __ ldr_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
+#ifndef PRODUCT
+        } else if (!do_size) {
+          if (size != 0) st->print("\n\t");
+          st->print(LDR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
+#endif
+        }
+      }
+    }
+    size += 4;
+  }
+
+  // check for int reg -> float reg move
+  if (src_first_rc == rc_int && dst_first_rc == rc_float) {
+    // Further check for aligned-adjacent pair, so we can use a single instruction
+    if (src_second_rc != rc_bad) {
+      assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
+      assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
+      assert(src_second_rc == rc_int && dst_second_rc == rc_float, "unsupported");
+      if (cbuf) {
+#ifdef AARCH64
+        __ fmov_dx(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
+#else
+        __ fmdrr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]), reg_to_register_object(Matcher::_regEncode[src_second]));
+#endif
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+#ifdef AARCH64
+        st->print("FMOV_DX   R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
+#else
+        st->print("FMDRR   R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first), OptoReg::regname(src_second));
+#endif
+#endif
+      }
+      return size + 4;
+    } else {
+      if (cbuf) {
+        __ fmsr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+        st->print(FMSR "   R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
+#endif
+      }
+      size += 4;
+    }
+  }
+
+  // check for float reg -> int reg move
+  if (src_first_rc == rc_float && dst_first_rc == rc_int) {
+    // Further check for aligned-adjacent pair, so we can use a single instruction
+    if (src_second_rc != rc_bad) {
+      assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
+      assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
+      assert(src_second_rc == rc_float && dst_second_rc == rc_int, "unsupported");
+      if (cbuf) {
+#ifdef AARCH64
+        __ fmov_xd(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
+#else
+        __ fmrrd(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
+#endif
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+#ifdef AARCH64
+        st->print("FMOV_XD R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
+#else
+        st->print("FMRRD   R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(dst_second), OptoReg::regname(src_first));
+#endif
+#endif
+      }
+      return size + 4;
+    } else {
+      if (cbuf) {
+        __ fmrs(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+        st->print(FMRS "   R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
+#endif
+      }
+      size += 4;
+    }
+  }
+
+  // --------------------------------------------------------------------
+  // Check for hi bits still needing moving.  Only happens for misaligned
+  // arguments to native calls.
+  if (src_second == dst_second)
+    return size;               // Self copy; no move
+  assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" );
+
+#ifndef AARCH64
+  // Check for integer reg-reg copy.  Hi bits are stuck up in the top
+  // 32-bits of a 64-bit register, but are needed in low bits of another
+  // register (else it's a hi-bits-to-hi-bits copy which should have
+  // happened already as part of a 64-bit move)
+  if (src_second_rc == rc_int && dst_second_rc == rc_int) {
+    if (cbuf) {
+      __ mov(reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_register_object(Matcher::_regEncode[src_second]));
+#ifndef PRODUCT
+    } else if (!do_size) {
+      if (size != 0) st->print("\n\t");
+      st->print("MOV    R_%s, R_%s\t# spill high",
+                Matcher::regName[dst_second],
+                Matcher::regName[src_second]);
+#endif
+    }
+    return size+4;
+  }
+
+  // Check for high word integer store
+  if (src_second_rc == rc_int && dst_second_rc == rc_stack) {
+    int offset = ra_->reg2offset(dst_second);
+
+    if (cbuf && !is_memoryP(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      if (cbuf) {
+        __ str(reg_to_register_object(Matcher::_regEncode[src_second]), Address(SP, offset));
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+        st->print("STR   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_second), offset);
+#endif
+      }
+    }
+    return size + 4;
+  }
+
+  // Check for high word integer load
+  if (dst_second_rc == rc_int && src_second_rc == rc_stack) {
+    int offset = ra_->reg2offset(src_second);
+    if (cbuf && !is_memoryP(offset)) {
+      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
+      return 0;
+    } else {
+      if (cbuf) {
+        __ ldr(reg_to_register_object(Matcher::_regEncode[dst_second]), Address(SP, offset));
+#ifndef PRODUCT
+      } else if (!do_size) {
+        if (size != 0) st->print("\n\t");
+        st->print("LDR   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_second), offset);
+#endif
+      }
+    }
+    return size + 4;
+  }
+#endif
+
+  Unimplemented();
+  return 0; // Mute compiler
+}
+
+#ifndef PRODUCT
+void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
+  implementation( NULL, ra_, false, st );
+}
+#endif
+
+void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  implementation( &cbuf, ra_, false, NULL );
+}
+
+uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const {
+  return implementation( NULL, ra_, true, NULL );
+}
+
+//=============================================================================
+#ifndef PRODUCT
+void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const {
+  st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count);
+}
+#endif
+
+void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const {
+  MacroAssembler _masm(&cbuf);
+  for(int i = 0; i < _count; i += 1) {
+    __ nop();
+  }
+}
+
+uint MachNopNode::size(PhaseRegAlloc *ra_) const {
+  return 4 * _count;
+}
+
+
+//=============================================================================
+#ifndef PRODUCT
+void BoxLockNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
+  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
+  int reg = ra_->get_reg_first(this);
+  st->print("ADD    %s,R_SP+#%d",Matcher::regName[reg], offset);
+}
+#endif
+
+void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  MacroAssembler _masm(&cbuf);
+  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
+  int reg = ra_->get_encode(this);
+  Register dst = reg_to_register_object(reg);
+
+  if (is_aimm(offset)) {
+    __ add(dst, SP, offset);
+  } else {
+    __ mov_slow(dst, offset);
+#ifdef AARCH64
+    __ add(dst, SP, dst, ex_lsl);
+#else
+    __ add(dst, SP, dst);
+#endif
+  }
+}
+
+uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
+  // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
+  assert(ra_ == ra_->C->regalloc(), "sanity");
+  return ra_->C->scratch_emit_size(this);
+}
+
+//=============================================================================
+#ifndef PRODUCT
+#ifdef AARCH64
+#define R_RTEMP "R_R16"
+#else
+#define R_RTEMP "R_R12"
+#endif
+void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
+  st->print_cr("\nUEP:");
+  if (UseCompressedClassPointers) {
+    st->print_cr("\tLDR_w " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
+    st->print_cr("\tdecode_klass " R_RTEMP);
+  } else {
+    st->print_cr("\tLDR   " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
+  }
+  st->print_cr("\tCMP   " R_RTEMP ",R_R8" );
+  st->print   ("\tB.NE  SharedRuntime::handle_ic_miss_stub");
+}
+#endif
+
+void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
+  MacroAssembler _masm(&cbuf);
+  Register iCache  = reg_to_register_object(Matcher::inline_cache_reg_encode());
+  assert(iCache == Ricklass, "should be");
+  Register receiver = R0;
+
+  __ load_klass(Rtemp, receiver);
+  __ cmp(Rtemp, iCache);
+#ifdef AARCH64
+  Label match;
+  __ b(match, eq);
+  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp);
+  __ bind(match);
+#else
+  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
+#endif
+}
+
+uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
+  return MachNode::size(ra_);
+}
+
+
+//=============================================================================
+
+// Emit exception handler code.
+int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
+  MacroAssembler _masm(&cbuf);
+
+  address base = __ start_a_stub(size_exception_handler());
+  if (base == NULL) {
+    ciEnv::current()->record_failure("CodeCache is full");
+    return 0;  // CodeBuffer::expand failed
+  }
+
+  int offset = __ offset();
+
+  // OK to trash LR, because exception blob will kill it
+  __ jump(OptoRuntime::exception_blob()->entry_point(), relocInfo::runtime_call_type, LR_tmp);
+
+  assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
+
+  __ end_a_stub();
+
+  return offset;
+}
+
+int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
+  // Can't use any of the current frame's registers as we may have deopted
+  // at a poll and everything can be live.
+  MacroAssembler _masm(&cbuf);
+
+  address base = __ start_a_stub(size_deopt_handler());
+  if (base == NULL) {
+    ciEnv::current()->record_failure("CodeCache is full");
+    return 0;  // CodeBuffer::expand failed
+  }
+
+  int offset = __ offset();
+  address deopt_pc = __ pc();
+
+#ifdef AARCH64
+  // See LR saved by caller in sharedRuntime_arm.cpp
+  // see also hse1 ws
+  // see also LIR_Assembler::emit_deopt_handler
+
+  __ raw_push(LR, LR); // preserve LR in both slots
+  __ mov_relative_address(LR, deopt_pc);
+  __ str(LR, Address(SP, 1 * wordSize)); // save deopt PC
+  // OK to kill LR, because deopt blob will restore it from SP[0]
+  __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, LR_tmp);
+#else
+  __ sub(SP, SP, wordSize); // make room for saved PC
+  __ push(LR); // save LR that may be live when we get here
+  __ mov_relative_address(LR, deopt_pc);
+  __ str(LR, Address(SP, wordSize)); // save deopt PC
+  __ pop(LR); // restore LR
+  __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);
+#endif
+
+  assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");
+
+  __ end_a_stub();
+  return offset;
+}
+
+const bool Matcher::match_rule_supported(int opcode) {
+  if (!has_match_rule(opcode))
+    return false;
+
+  switch (opcode) {
+  case Op_PopCountI:
+  case Op_PopCountL:
+    if (!UsePopCountInstruction)
+      return false;
+    break;
+  case Op_LShiftCntV:
+  case Op_RShiftCntV:
+  case Op_AddVB:
+  case Op_AddVS:
+  case Op_AddVI:
+  case Op_AddVL:
+  case Op_SubVB:
+  case Op_SubVS:
+  case Op_SubVI:
+  case Op_SubVL:
+  case Op_MulVS:
+  case Op_MulVI:
+  case Op_LShiftVB:
+  case Op_LShiftVS:
+  case Op_LShiftVI:
+  case Op_LShiftVL:
+  case Op_RShiftVB:
+  case Op_RShiftVS:
+  case Op_RShiftVI:
+  case Op_RShiftVL:
+  case Op_URShiftVB:
+  case Op_URShiftVS:
+  case Op_URShiftVI:
+  case Op_URShiftVL:
+  case Op_AndV:
+  case Op_OrV:
+  case Op_XorV:
+    return VM_Version::has_simd();
+  case Op_LoadVector:
+  case Op_StoreVector:
+  case Op_AddVF:
+  case Op_SubVF:
+  case Op_MulVF:
+#ifdef AARCH64
+    return VM_Version::has_simd();
+#else
+    return VM_Version::has_vfp() || VM_Version::has_simd();
+#endif
+  case Op_AddVD:
+  case Op_SubVD:
+  case Op_MulVD:
+  case Op_DivVF:
+  case Op_DivVD:
+#ifdef AARCH64
+    return VM_Version::has_simd();
+#else
+    return VM_Version::has_vfp();
+#endif
+  }
+
+  return true;  // Per default match rules are supported.
+}
+
+const bool Matcher::match_rule_supported_vector(int opcode, int vlen) {
+
+  // TODO
+  // identify extra cases that we might want to provide match rules for
+  // e.g. Op_ vector nodes and other intrinsics while guarding with vlen
+  bool ret_value = match_rule_supported(opcode);
+  // Add rules here.
+
+  return ret_value;  // Per default match rules are supported.
+}
+
+const bool Matcher::has_predicated_vectors(void) {
+  return false;
+}
+
+const int Matcher::float_pressure(int default_pressure_threshold) {
+  return default_pressure_threshold;
+}
+
+int Matcher::regnum_to_fpu_offset(int regnum) {
+  return regnum - 32; // The FP registers are in the second chunk
+}
+
+// Vector width in bytes
+const int Matcher::vector_width_in_bytes(BasicType bt) {
+  return MaxVectorSize;
+}
+
+// Vector ideal reg corresponding to specified size in bytes
+const int Matcher::vector_ideal_reg(int size) {
+  assert(MaxVectorSize >= size, "");
+  switch(size) {
+    case  8: return Op_VecD;
+    case 16: return Op_VecX;
+  }
+  ShouldNotReachHere();
+  return 0;
+}
+
+const int Matcher::vector_shift_count_ideal_reg(int size) {
+  return vector_ideal_reg(size);
+}
+
+// Limits on vector size (number of elements) loaded into vector.
+const int Matcher::max_vector_size(const BasicType bt) {
+  assert(is_java_primitive(bt), "only primitive type vectors");
+  return vector_width_in_bytes(bt)/type2aelembytes(bt);
+}
+
+const int Matcher::min_vector_size(const BasicType bt) {
+  assert(is_java_primitive(bt), "only primitive type vectors");
+  return 8/type2aelembytes(bt);
+}
+
+// ARM doesn't support misaligned vectors store/load.
+const bool Matcher::misaligned_vectors_ok() {
+  return false;
+}
+
+// ARM doesn't support AES intrinsics
+const bool Matcher::pass_original_key_for_aes() {
+  return false;
+}
+
+const bool Matcher::convL2FSupported(void) {
+#ifdef AARCH64
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Is this branch offset short enough that a short branch can be used?
+//
+// NOTE: If the platform does not provide any short branch variants, then
+//       this method should return false for offset 0.
+bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
+  // The passed offset is relative to address of the branch.
+  // On ARM a branch displacement is calculated relative to address
+  // of the branch + 8.
+  //
+  // offset -= 8;
+  // return (Assembler::is_simm24(offset));
+  return false;
+}
+
+const bool Matcher::isSimpleConstant64(jlong value) {
+  // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?.
+#ifdef AARCH64
+  return (value == 0);
+#else
+  return false;
+#endif
+}
+
+// No scaling for the parameter the ClearArray node.
+const bool Matcher::init_array_count_is_in_bytes = true;
+
+#ifdef AARCH64
+const int Matcher::long_cmove_cost() { return 1; }
+#else
+// Needs 2 CMOV's for longs.
+const int Matcher::long_cmove_cost() { return 2; }
+#endif
+
+#ifdef AARCH64
+const int Matcher::float_cmove_cost() { return 1; }
+#else
+// CMOVF/CMOVD are expensive on ARM.
+const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; }
+#endif
+
+// Does the CPU require late expand (see block.cpp for description of late expand)?
+const bool Matcher::require_postalloc_expand = false;
+
+// Do we need to mask the count passed to shift instructions or does
+// the cpu only look at the lower 5/6 bits anyway?
+// FIXME: does this handle vector shifts as well?
+#ifdef AARCH64
+const bool Matcher::need_masked_shift_count = false;
+#else
+const bool Matcher::need_masked_shift_count = true;
+#endif
+
+const bool Matcher::convi2l_type_required = true;
+
+// Should the Matcher clone shifts on addressing modes, expecting them
+// to be subsumed into complex addressing expressions or compute them
+// into registers?
+bool Matcher::clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
+  return clone_base_plus_offset_address(m, mstack, address_visited);
+}
+
+void Compile::reshape_address(AddPNode* addp) {
+}
+
+bool Matcher::narrow_oop_use_complex_address() {
+  NOT_LP64(ShouldNotCallThis());
+  assert(UseCompressedOops, "only for compressed oops code");
+  return false;
+}
+
+bool Matcher::narrow_klass_use_complex_address() {
+  NOT_LP64(ShouldNotCallThis());
+  assert(UseCompressedClassPointers, "only for compressed klass code");
+  return false;
+}
+
+bool Matcher::const_oop_prefer_decode() {
+  NOT_LP64(ShouldNotCallThis());
+  return true;
+}
+
+bool Matcher::const_klass_prefer_decode() {
+  NOT_LP64(ShouldNotCallThis());
+  return true;
+}
+
+// Is it better to copy float constants, or load them directly from memory?
+// Intel can load a float constant from a direct address, requiring no
+// extra registers.  Most RISCs will have to materialize an address into a
+// register first, so they would do better to copy the constant from stack.
+const bool Matcher::rematerialize_float_constants = false;
+
+// If CPU can load and store mis-aligned doubles directly then no fixup is
+// needed.  Else we split the double into 2 integer pieces and move it
+// piece-by-piece.  Only happens when passing doubles into C code as the
+// Java calling convention forces doubles to be aligned.
+#ifdef AARCH64
+// On stack replacement support:
+// We don't need Load[DL]_unaligned support, because interpreter stack
+// has correct alignment
+const bool Matcher::misaligned_doubles_ok = true;
+#else
+const bool Matcher::misaligned_doubles_ok = false;
+#endif
+
+// No-op on ARM.
+void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
+}
+
+// Advertise here if the CPU requires explicit rounding operations
+// to implement the UseStrictFP mode.
+const bool Matcher::strict_fp_requires_explicit_rounding = false;
+
+// Are floats converted to double when stored to stack during deoptimization?
+// ARM does not handle callee-save floats.
+bool Matcher::float_in_double() {
+  return false;
+}
+
+// Do ints take an entire long register or just half?
+// Note that we if-def off of _LP64.
+// The relevant question is how the int is callee-saved.  In _LP64
+// the whole long is written but de-opt'ing will have to extract
+// the relevant 32 bits, in not-_LP64 only the low 32 bits is written.
+#ifdef _LP64
+const bool Matcher::int_in_long = true;
+#else
+const bool Matcher::int_in_long = false;
+#endif
+
+// Return whether or not this register is ever used as an argument.  This
+// function is used on startup to build the trampoline stubs in generateOptoStub.
+// Registers not mentioned will be killed by the VM call in the trampoline, and
+// arguments in those registers not be available to the callee.
+bool Matcher::can_be_java_arg( int reg ) {
+#ifdef AARCH64
+  if (reg >= R_R0_num && reg < R_R8_num) return true;
+  if (reg >= R_V0_num && reg <= R_V7b_num && ((reg & 3) < 2)) return true;
+#else
+  if (reg == R_R0_num ||
+      reg == R_R1_num ||
+      reg == R_R2_num ||
+      reg == R_R3_num) return true;
+
+  if (reg >= R_S0_num &&
+      reg <= R_S13_num) return true;
+#endif
+  return false;
+}
+
+bool Matcher::is_spillable_arg( int reg ) {
+  return can_be_java_arg(reg);
+}
+
+bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
+  return false;
+}
+
+// Register for DIVI projection of divmodI
+RegMask Matcher::divI_proj_mask() {
+  ShouldNotReachHere();
+  return RegMask();
+}
+
+// Register for MODI projection of divmodI
+RegMask Matcher::modI_proj_mask() {
+  ShouldNotReachHere();
+  return RegMask();
+}
+
+// Register for DIVL projection of divmodL
+RegMask Matcher::divL_proj_mask() {
+  ShouldNotReachHere();
+  return RegMask();
+}
+
+// Register for MODL projection of divmodL
+RegMask Matcher::modL_proj_mask() {
+  ShouldNotReachHere();
+  return RegMask();
+}
+
+const RegMask Matcher::method_handle_invoke_SP_save_mask() {
+  return FP_REGP_mask();
+}
+
+bool maybe_far_call(const CallNode *n) {
+  return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point());
+}
+
+bool maybe_far_call(const MachCallNode *n) {
+  return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point());
+}
+
+%}
+
+//----------ENCODING BLOCK-----------------------------------------------------
+// This block specifies the encoding classes used by the compiler to output
+// byte streams.  Encoding classes are parameterized macros used by
+// Machine Instruction Nodes in order to generate the bit encoding of the
+// instruction.  Operands specify their base encoding interface with the
+// interface keyword.  There are currently supported four interfaces,
+// REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER.  REG_INTER causes an
+// operand to generate a function which returns its register number when
+// queried.   CONST_INTER causes an operand to generate a function which
+// returns the value of the constant when queried.  MEMORY_INTER causes an
+// operand to generate four functions which return the Base Register, the
+// Index Register, the Scale Value, and the Offset Value of the operand when
+// queried.  COND_INTER causes an operand to generate six functions which
+// return the encoding code (ie - encoding bits for the instruction)
+// associated with each basic boolean condition for a conditional instruction.
+//
+// Instructions specify two basic values for encoding.  Again, a function
+// is available to check if the constant displacement is an oop. They use the
+// ins_encode keyword to specify their encoding classes (which must be
+// a sequence of enc_class names, and their parameters, specified in
+// the encoding block), and they use the
+// opcode keyword to specify, in order, their primary, secondary, and
+// tertiary opcode.  Only the opcode sections which a particular instruction
+// needs for encoding need to be specified.
+encode %{
+  enc_class call_epilog %{
+    // nothing
+  %}
+
+  enc_class Java_To_Runtime (method meth) %{
+    // CALL directly to the runtime
+    emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
+  %}
+
+  enc_class Java_Static_Call (method meth) %{
+    // CALL to fixup routine.  Fixup routine uses ScopeDesc info to determine
+    // who we intended to call.
+
+    if ( !_method) {
+      emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
+    } else {
+      int method_index = resolved_method_index(cbuf);
+      RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
+                                                  : static_call_Relocation::spec(method_index);
+      emit_call_reloc(cbuf, as_MachCall(), $meth, rspec);
+
+      // Emit stubs for static call.
+      address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
+      if (stub == NULL) {
+        ciEnv::current()->record_failure("CodeCache is full");
+        return;
+      }
+    }
+  %}
+
+  enc_class save_last_PC %{
+    // preserve mark
+    address mark = cbuf.insts()->mark();
+    debug_only(int off0 = cbuf.insts_size());
+    MacroAssembler _masm(&cbuf);
+    int ret_addr_offset = as_MachCall()->ret_addr_offset();
+    __ adr(LR, mark + ret_addr_offset);
+    __ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset()));
+    debug_only(int off1 = cbuf.insts_size());
+    assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction");
+    // restore mark
+    cbuf.insts()->set_mark(mark);
+  %}
+
+  enc_class preserve_SP %{
+    // preserve mark
+    address mark = cbuf.insts()->mark();
+    debug_only(int off0 = cbuf.insts_size());
+    MacroAssembler _masm(&cbuf);
+    // FP is preserved across all calls, even compiled calls.
+    // Use it to preserve SP in places where the callee might change the SP.
+    __ mov(Rmh_SP_save, SP);
+    debug_only(int off1 = cbuf.insts_size());
+    assert(off1 - off0 == 4, "correct size prediction");
+    // restore mark
+    cbuf.insts()->set_mark(mark);
+  %}
+
+  enc_class restore_SP %{
+    MacroAssembler _masm(&cbuf);
+    __ mov(SP, Rmh_SP_save);
+  %}
+
+  enc_class Java_Dynamic_Call (method meth) %{
+    MacroAssembler _masm(&cbuf);
+    Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
+    assert(R8_ic_reg == Ricklass, "should be");
+    __ set_inst_mark();
+#ifdef AARCH64
+// TODO: see C1 LIR_Assembler::ic_call()
+    InlinedAddress oop_literal((address)Universe::non_oop_word());
+    int offset = __ offset();
+    int fixed_size = mov_oop_size * 4;
+    if (VM_Version::prefer_moves_over_load_literal()) {
+      uintptr_t val = (uintptr_t)Universe::non_oop_word();
+      __ movz(R8_ic_reg, (val >>  0) & 0xffff,  0);
+      __ movk(R8_ic_reg, (val >> 16) & 0xffff, 16);
+      __ movk(R8_ic_reg, (val >> 32) & 0xffff, 32);
+      __ movk(R8_ic_reg, (val >> 48) & 0xffff, 48);
+    } else {
+      __ ldr_literal(R8_ic_reg, oop_literal);
+    }
+    assert(__ offset() - offset == fixed_size, "bad mov_oop size");
+#else
+    __ movw(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) & 0xffff);
+    __ movt(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) >> 16);
+#endif
+    address  virtual_call_oop_addr = __ inst_mark();
+    // CALL to fixup routine.  Fixup routine uses ScopeDesc info to determine
+    // who we intended to call.
+    int method_index = resolved_method_index(cbuf);
+    __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index));
+    emit_call_reloc(cbuf, as_MachCall(), $meth, RelocationHolder::none);
+#ifdef AARCH64
+    if (!VM_Version::prefer_moves_over_load_literal()) {
+      Label skip_literal;
+      __ b(skip_literal);
+      int off2 = __ offset();
+      __ bind_literal(oop_literal);
+      if (__ offset() - off2 == wordSize) {
+        // no padding, so insert nop for worst-case sizing
+        __ nop();
+      }
+      __ bind(skip_literal);
+    }
+#endif
+  %}
+
+  enc_class LdReplImmI(immI src, regD dst, iRegI tmp, int cnt, int wth) %{
+    // FIXME: load from constant table?
+    // Load a constant replicated "count" times with width "width"
+    int count = $cnt$$constant;
+    int width = $wth$$constant;
+    assert(count*width == 4, "sanity");
+    int val = $src$$constant;
+    if (width < 4) {
+      int bit_width = width * 8;
+      val &= (((int)1) << bit_width) - 1; // mask off sign bits
+      for (int i = 0; i < count - 1; i++) {
+        val |= (val << bit_width);
+      }
+    }
+    MacroAssembler _masm(&cbuf);
+
+    if (val == -1) {
+      __ mvn($tmp$$Register, 0);
+    } else if (val == 0) {
+      __ mov($tmp$$Register, 0);
+    } else {
+      __ movw($tmp$$Register, val & 0xffff);
+      __ movt($tmp$$Register, (unsigned int)val >> 16);
+    }
+    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
+  %}
+
+  enc_class LdReplImmF(immF src, regD dst, iRegI tmp) %{
+    // Replicate float con 2 times and pack into vector (8 bytes) in regD.
+    float fval = $src$$constant;
+    int val = *((int*)&fval);
+    MacroAssembler _masm(&cbuf);
+
+    if (val == -1) {
+      __ mvn($tmp$$Register, 0);
+    } else if (val == 0) {
+      __ mov($tmp$$Register, 0);
+    } else {
+      __ movw($tmp$$Register, val & 0xffff);
+      __ movt($tmp$$Register, (unsigned int)val >> 16);
+    }
+    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
+  %}
+
+  enc_class enc_String_Compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2) %{
+    Label Ldone, Lloop;
+    MacroAssembler _masm(&cbuf);
+
+    Register   str1_reg = $str1$$Register;
+    Register   str2_reg = $str2$$Register;
+    Register   cnt1_reg = $cnt1$$Register; // int
+    Register   cnt2_reg = $cnt2$$Register; // int
+    Register   tmp1_reg = $tmp1$$Register;
+    Register   tmp2_reg = $tmp2$$Register;
+    Register result_reg = $result$$Register;
+
+    assert_different_registers(str1_reg, str2_reg, cnt1_reg, cnt2_reg, tmp1_reg, tmp2_reg);
+
+    // Compute the minimum of the string lengths(str1_reg) and the
+    // difference of the string lengths (stack)
+
+    // See if the lengths are different, and calculate min in str1_reg.
+    // Stash diff in tmp2 in case we need it for a tie-breaker.
+    __ subs_32(tmp2_reg, cnt1_reg, cnt2_reg);
+#ifdef AARCH64
+    Label Lskip;
+    __ _lsl_w(cnt1_reg, cnt1_reg, exact_log2(sizeof(jchar))); // scale the limit
+    __ b(Lskip, mi);
+    __ _lsl_w(cnt1_reg, cnt2_reg, exact_log2(sizeof(jchar))); // scale the limit
+    __ bind(Lskip);
+#else
+    __ mov(cnt1_reg, AsmOperand(cnt1_reg, lsl, exact_log2(sizeof(jchar)))); // scale the limit
+    __ mov(cnt1_reg, AsmOperand(cnt2_reg, lsl, exact_log2(sizeof(jchar))), pl); // scale the limit
+#endif
+
+    // reallocate cnt1_reg, cnt2_reg, result_reg
+    // Note:  limit_reg holds the string length pre-scaled by 2
+    Register limit_reg = cnt1_reg;
+    Register  chr2_reg = cnt2_reg;
+    Register  chr1_reg = tmp1_reg;
+    // str{12} are the base pointers
+
+    // Is the minimum length zero?
+    __ cmp_32(limit_reg, 0);
+    if (result_reg != tmp2_reg) {
+      __ mov(result_reg, tmp2_reg, eq);
+    }
+    __ b(Ldone, eq);
+
+    // Load first characters
+    __ ldrh(chr1_reg, Address(str1_reg, 0));
+    __ ldrh(chr2_reg, Address(str2_reg, 0));
+
+    // Compare first characters
+    __ subs(chr1_reg, chr1_reg, chr2_reg);
+    if (result_reg != chr1_reg) {
+      __ mov(result_reg, chr1_reg, ne);
+    }
+    __ b(Ldone, ne);
+
+    {
+      // Check after comparing first character to see if strings are equivalent
+      // Check if the strings start at same location
+      __ cmp(str1_reg, str2_reg);
+      // Check if the length difference is zero
+      __ cond_cmp(tmp2_reg, 0, eq);
+      __ mov(result_reg, 0, eq); // result is zero
+      __ b(Ldone, eq);
+      // Strings might not be equal
+    }
+
+    __ subs(chr1_reg, limit_reg, 1 * sizeof(jchar));
+    if (result_reg != tmp2_reg) {
+      __ mov(result_reg, tmp2_reg, eq);
+    }
+    __ b(Ldone, eq);
+
+    // Shift str1_reg and str2_reg to the end of the arrays, negate limit
+    __ add(str1_reg, str1_reg, limit_reg);
+    __ add(str2_reg, str2_reg, limit_reg);
+    __ neg(limit_reg, chr1_reg);  // limit = -(limit-2)
+
+    // Compare the rest of the characters
+    __ bind(Lloop);
+    __ ldrh(chr1_reg, Address(str1_reg, limit_reg));
+    __ ldrh(chr2_reg, Address(str2_reg, limit_reg));
+    __ subs(chr1_reg, chr1_reg, chr2_reg);
+    if (result_reg != chr1_reg) {
+      __ mov(result_reg, chr1_reg, ne);
+    }
+    __ b(Ldone, ne);
+
+    __ adds(limit_reg, limit_reg, sizeof(jchar));
+    __ b(Lloop, ne);
+
+    // If strings are equal up to min length, return the length difference.
+    if (result_reg != tmp2_reg) {
+      __ mov(result_reg, tmp2_reg);
+    }
+
+    // Otherwise, return the difference between the first mismatched chars.
+    __ bind(Ldone);
+  %}
+
+  enc_class enc_String_Equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2) %{
+    Label Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone, Lequal;
+    MacroAssembler _masm(&cbuf);
+
+    Register   str1_reg = $str1$$Register;
+    Register   str2_reg = $str2$$Register;
+    Register    cnt_reg = $cnt$$Register; // int
+    Register   tmp1_reg = $tmp1$$Register;
+    Register   tmp2_reg = $tmp2$$Register;
+    Register result_reg = $result$$Register;
+
+    assert_different_registers(str1_reg, str2_reg, cnt_reg, tmp1_reg, tmp2_reg, result_reg);
+
+    __ cmp(str1_reg, str2_reg); //same char[] ?
+    __ b(Lequal, eq);
+
+    __ cbz_32(cnt_reg, Lequal); // count == 0
+
+    //rename registers
+    Register limit_reg = cnt_reg;
+    Register  chr1_reg = tmp1_reg;
+    Register  chr2_reg = tmp2_reg;
+
+    __ logical_shift_left(limit_reg, limit_reg, exact_log2(sizeof(jchar)));
+
+    //check for alignment and position the pointers to the ends
+    __ orr(chr1_reg, str1_reg, str2_reg);
+    __ tst(chr1_reg, 0x3);
+
+    // notZero means at least one not 4-byte aligned.
+    // We could optimize the case when both arrays are not aligned
+    // but it is not frequent case and it requires additional checks.
+    __ b(Lchar, ne);
+
+    // Compare char[] arrays aligned to 4 bytes.
+    __ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg,
+                          chr1_reg, chr2_reg, Ldone);
+
+    __ b(Lequal); // equal
+
+    // char by char compare
+    __ bind(Lchar);
+    __ mov(result_reg, 0);
+    __ add(str1_reg, limit_reg, str1_reg);
+    __ add(str2_reg, limit_reg, str2_reg);
+    __ neg(limit_reg, limit_reg); //negate count
+
+    // Lchar_loop
+    __ bind(Lchar_loop);
+    __ ldrh(chr1_reg, Address(str1_reg, limit_reg));
+    __ ldrh(chr2_reg, Address(str2_reg, limit_reg));
+    __ cmp(chr1_reg, chr2_reg);
+    __ b(Ldone, ne);
+    __ adds(limit_reg, limit_reg, sizeof(jchar));
+    __ b(Lchar_loop, ne);
+
+    __ bind(Lequal);
+    __ mov(result_reg, 1);  //equal
+
+    __ bind(Ldone);
+  %}
+
+  enc_class enc_Array_Equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result) %{
+    Label Lvector, Ldone, Lloop, Lequal;
+    MacroAssembler _masm(&cbuf);
+
+    Register   ary1_reg = $ary1$$Register;
+    Register   ary2_reg = $ary2$$Register;
+    Register   tmp1_reg = $tmp1$$Register;
+    Register   tmp2_reg = $tmp2$$Register;
+    Register   tmp3_reg = $tmp3$$Register;
+    Register result_reg = $result$$Register;
+
+    assert_different_registers(ary1_reg, ary2_reg, tmp1_reg, tmp2_reg, tmp3_reg, result_reg);
+
+    int length_offset  = arrayOopDesc::length_offset_in_bytes();
+    int base_offset    = arrayOopDesc::base_offset_in_bytes(T_CHAR);
+
+    // return true if the same array
+#ifdef AARCH64
+    __ cmp(ary1_reg, ary2_reg);
+    __ b(Lequal, eq);
+
+    __ mov(result_reg, 0);
+
+    __ cbz(ary1_reg, Ldone); // not equal
+
+    __ cbz(ary2_reg, Ldone); // not equal
+#else
+    __ teq(ary1_reg, ary2_reg);
+    __ mov(result_reg, 1, eq);
+    __ b(Ldone, eq); // equal
+
+    __ tst(ary1_reg, ary1_reg);
+    __ mov(result_reg, 0, eq);
+    __ b(Ldone, eq);    // not equal
+
+    __ tst(ary2_reg, ary2_reg);
+    __ mov(result_reg, 0, eq);
+    __ b(Ldone, eq);    // not equal
+#endif
+
+    //load the lengths of arrays
+    __ ldr_s32(tmp1_reg, Address(ary1_reg, length_offset)); // int
+    __ ldr_s32(tmp2_reg, Address(ary2_reg, length_offset)); // int
+
+    // return false if the two arrays are not equal length
+#ifdef AARCH64
+    __ cmp_w(tmp1_reg, tmp2_reg);
+    __ b(Ldone, ne);    // not equal
+
+    __ cbz_w(tmp1_reg, Lequal); // zero-length arrays are equal
+#else
+    __ teq_32(tmp1_reg, tmp2_reg);
+    __ mov(result_reg, 0, ne);
+    __ b(Ldone, ne);    // not equal
+
+    __ tst(tmp1_reg, tmp1_reg);
+    __ mov(result_reg, 1, eq);
+    __ b(Ldone, eq);    // zero-length arrays are equal
+#endif
+
+    // load array addresses
+    __ add(ary1_reg, ary1_reg, base_offset);
+    __ add(ary2_reg, ary2_reg, base_offset);
+
+    // renaming registers
+    Register chr1_reg  =  tmp3_reg;   // for characters in ary1
+    Register chr2_reg  =  tmp2_reg;   // for characters in ary2
+    Register limit_reg =  tmp1_reg;   // length
+
+    // set byte count
+    __ logical_shift_left_32(limit_reg, limit_reg, exact_log2(sizeof(jchar)));
+
+    // Compare char[] arrays aligned to 4 bytes.
+    __ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg,
+                          chr1_reg, chr2_reg, Ldone);
+    __ bind(Lequal);
+    __ mov(result_reg, 1);  //equal
+
+    __ bind(Ldone);
+    %}
+%}
+
+//----------FRAME--------------------------------------------------------------
+// Definition of frame structure and management information.
+//
+//  S T A C K   L A Y O U T    Allocators stack-slot number
+//                             |   (to get allocators register number
+//  G  Owned by    |        |  v    add VMRegImpl::stack0)
+//  r   CALLER     |        |
+//  o     |        +--------+      pad to even-align allocators stack-slot
+//  w     V        |  pad0  |        numbers; owned by CALLER
+//  t   -----------+--------+----> Matcher::_in_arg_limit, unaligned
+//  h     ^        |   in   |  5
+//        |        |  args  |  4   Holes in incoming args owned by SELF
+//  |     |        |        |  3
+//  |     |        +--------+
+//  V     |        | old out|      Empty on Intel, window on Sparc
+//        |    old |preserve|      Must be even aligned.
+//        |     SP-+--------+----> Matcher::_old_SP, 8 (or 16 in LP64)-byte aligned
+//        |        |   in   |  3   area for Intel ret address
+//     Owned by    |preserve|      Empty on Sparc.
+//       SELF      +--------+
+//        |        |  pad2  |  2   pad to align old SP
+//        |        +--------+  1
+//        |        | locks  |  0
+//        |        +--------+----> VMRegImpl::stack0, 8 (or 16 in LP64)-byte aligned
+//        |        |  pad1  | 11   pad to align new SP
+//        |        +--------+
+//        |        |        | 10
+//        |        | spills |  9   spills
+//        V        |        |  8   (pad0 slot for callee)
+//      -----------+--------+----> Matcher::_out_arg_limit, unaligned
+//        ^        |  out   |  7
+//        |        |  args  |  6   Holes in outgoing args owned by CALLEE
+//     Owned by    +--------+
+//      CALLEE     | new out|  6   Empty on Intel, window on Sparc
+//        |    new |preserve|      Must be even-aligned.
+//        |     SP-+--------+----> Matcher::_new_SP, even aligned
+//        |        |        |
+//
+// Note 1: Only region 8-11 is determined by the allocator.  Region 0-5 is
+//         known from SELF's arguments and the Java calling convention.
+//         Region 6-7 is determined per call site.
+// Note 2: If the calling convention leaves holes in the incoming argument
+//         area, those holes are owned by SELF.  Holes in the outgoing area
+//         are owned by the CALLEE.  Holes should not be nessecary in the
+//         incoming area, as the Java calling convention is completely under
+//         the control of the AD file.  Doubles can be sorted and packed to
+//         avoid holes.  Holes in the outgoing arguments may be nessecary for
+//         varargs C calling conventions.
+// Note 3: Region 0-3 is even aligned, with pad2 as needed.  Region 3-5 is
+//         even aligned with pad0 as needed.
+//         Region 6 is even aligned.  Region 6-7 is NOT even aligned;
+//         region 6-11 is even aligned; it may be padded out more so that
+//         the region from SP to FP meets the minimum stack alignment.
+
+frame %{
+  // What direction does stack grow in (assumed to be same for native & Java)
+  stack_direction(TOWARDS_LOW);
+
+  // These two registers define part of the calling convention
+  // between compiled code and the interpreter.
+  inline_cache_reg(R_Ricklass);          // Inline Cache Register or Method* for I2C
+  interpreter_method_oop_reg(R_Rmethod); // Method Oop Register when calling interpreter
+
+  // Optional: name the operand used by cisc-spilling to access [stack_pointer + offset]
+  cisc_spilling_operand_name(indOffset);
+
+  // Number of stack slots consumed by a Monitor enter
+  sync_stack_slots(1 * VMRegImpl::slots_per_word);
+
+  // Compiled code's Frame Pointer
+#ifdef AARCH64
+  frame_pointer(R_SP);
+#else
+  frame_pointer(R_R13);
+#endif
+
+  // Stack alignment requirement
+  stack_alignment(StackAlignmentInBytes);
+  //  LP64: Alignment size in bytes (128-bit -> 16 bytes)
+  // !LP64: Alignment size in bytes (64-bit  ->  8 bytes)
+
+  // Number of stack slots between incoming argument block and the start of
+  // a new frame.  The PROLOG must add this many slots to the stack.  The
+  // EPILOG must remove this many slots.
+  // FP + LR
+  in_preserve_stack_slots(2 * VMRegImpl::slots_per_word);
+
+  // Number of outgoing stack slots killed above the out_preserve_stack_slots
+  // for calls to C.  Supports the var-args backing area for register parms.
+  // ADLC doesn't support parsing expressions, so I folded the math by hand.
+  varargs_C_out_slots_killed( 0);
+
+  // The after-PROLOG location of the return address.  Location of
+  // return address specifies a type (REG or STACK) and a number
+  // representing the register number (i.e. - use a register name) or
+  // stack slot.
+  // Ret Addr is on stack in slot 0 if no locks or verification or alignment.
+  // Otherwise, it is above the locks and verification slot and alignment word
+  return_addr(STACK - 1*VMRegImpl::slots_per_word +
+              round_to((Compile::current()->in_preserve_stack_slots() +
+                        Compile::current()->fixed_slots()),
+                       stack_alignment_in_slots()));
+
+  // Body of function which returns an OptoRegs array locating
+  // arguments either in registers or in stack slots for calling
+  // java
+  calling_convention %{
+    (void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing);
+
+  %}
+
+  // Body of function which returns an OptoRegs array locating
+  // arguments either in registers or in stack slots for callin
+  // C.
+  c_calling_convention %{
+    // This is obviously always outgoing
+    (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length);
+  %}
+
+  // Location of compiled Java return values.  Same as C
+  return_value %{
+    return c2::return_value(ideal_reg);
+  %}
+
+%}
+
+//----------ATTRIBUTES---------------------------------------------------------
+//----------Instruction Attributes---------------------------------------------
+ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute
+ins_attrib ins_size(32);           // Required size attribute (in bits)
+ins_attrib ins_short_branch(0);    // Required flag: is this instruction a
+                                   // non-matching short branch variant of some
+                                                            // long branch?
+
+//----------OPERANDS-----------------------------------------------------------
+// Operand definitions must precede instruction definitions for correct parsing
+// in the ADLC because operands constitute user defined types which are used in
+// instruction definitions.
+
+//----------Simple Operands----------------------------------------------------
+// Immediate Operands
+// Integer Immediate: 32-bit
+operand immI() %{
+  match(ConI);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 8-bit unsigned - for VMOV
+operand immU8() %{
+  predicate(0 <= n->get_int() && (n->get_int() <= 255));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 16-bit
+operand immI16() %{
+  predicate((n->get_int() >> 16) == 0 && VM_Version::supports_movw());
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+#ifndef AARCH64
+// Integer Immediate: offset for half and double word loads and stores
+operand immIHD() %{
+  predicate(is_memoryHD(n->get_int()));
+  match(ConI);
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: offset for fp loads and stores
+operand immIFP() %{
+  predicate(is_memoryfp(n->get_int()) && ((n->get_int() & 3) == 0));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+#endif
+
+// Valid scale values for addressing modes and shifts
+operand immU5() %{
+  predicate(0 <= n->get_int() && (n->get_int() <= 31));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 6-bit
+operand immU6Big() %{
+  predicate(n->get_int() >= 32 && n->get_int() <= 63);
+  match(ConI);
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 0-bit
+operand immI0() %{
+  predicate(n->get_int() == 0);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 1
+operand immI_1() %{
+  predicate(n->get_int() == 1);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 2
+operand immI_2() %{
+  predicate(n->get_int() == 2);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 3
+operand immI_3() %{
+  predicate(n->get_int() == 3);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 4
+operand immI_4() %{
+  predicate(n->get_int() == 4);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 8
+operand immI_8() %{
+  predicate(n->get_int() == 8);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Int Immediate non-negative
+operand immU31()
+%{
+  predicate(n->get_int() >= 0);
+  match(ConI);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the values 32-63
+operand immI_32_63() %{
+  predicate(n->get_int() >= 32 && n->get_int() <= 63);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Immediates for special shifts (sign extend)
+
+// Integer Immediate: the value 16
+operand immI_16() %{
+  predicate(n->get_int() == 16);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 24
+operand immI_24() %{
+  predicate(n->get_int() == 24);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 255
+operand immI_255() %{
+  predicate( n->get_int() == 255 );
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 65535
+operand immI_65535() %{
+  predicate(n->get_int() == 65535);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediates for arithmetic instructions
+
+operand aimmI() %{
+  predicate(is_aimm(n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand aimmIneg() %{
+  predicate(is_aimm(-n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand aimmU31() %{
+  predicate((0 <= n->get_int()) && is_aimm(n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediates for logical instructions
+
+operand limmI() %{
+  predicate(is_limmI(n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand limmIlow8() %{
+  predicate(is_limmI_low(n->get_int(), 8));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand limmU31() %{
+  predicate(0 <= n->get_int() && is_limmI(n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand limmIn() %{
+  predicate(is_limmI(~n->get_int()));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+#ifdef AARCH64
+// Long Immediate: for logical instruction
+operand limmL() %{
+  predicate(is_limmL(n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand limmLn() %{
+  predicate(is_limmL(~n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: for arithmetic instruction
+operand aimmL() %{
+  predicate(is_aimm(n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand aimmLneg() %{
+  predicate(is_aimm(-n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+#endif // AARCH64
+
+// Long Immediate: the value FF
+operand immL_FF() %{
+  predicate( n->get_long() == 0xFFL );
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: the value FFFF
+operand immL_FFFF() %{
+  predicate( n->get_long() == 0xFFFFL );
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Pointer Immediate: 32 or 64-bit
+operand immP() %{
+  match(ConP);
+
+  op_cost(5);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immP0() %{
+  predicate(n->get_ptr() == 0);
+  match(ConP);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immP_poll() %{
+  predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page());
+  match(ConP);
+
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Pointer Immediate
+operand immN()
+%{
+  match(ConN);
+
+  op_cost(10);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immNKlass()
+%{
+  match(ConNKlass);
+
+  op_cost(10);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// NULL Pointer Immediate
+operand immN0()
+%{
+  predicate(n->get_narrowcon() == 0);
+  match(ConN);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immL() %{
+  match(ConL);
+  op_cost(40);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immL0() %{
+  predicate(n->get_long() == 0L);
+  match(ConL);
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: 16-bit
+operand immL16() %{
+  predicate(n->get_long() >= 0 && n->get_long() < (1<<16)  && VM_Version::supports_movw());
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: low 32-bit mask
+operand immL_32bits() %{
+  predicate(n->get_long() == 0xFFFFFFFFL);
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Double Immediate
+operand immD() %{
+  match(ConD);
+
+  op_cost(40);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Double Immediate: +0.0d.
+operand immD0() %{
+  predicate(jlong_cast(n->getd()) == 0);
+
+  match(ConD);
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand imm8D() %{
+  predicate(Assembler::double_num(n->getd()).can_be_imm8());
+  match(ConD);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Float Immediate
+operand immF() %{
+  match(ConF);
+
+  op_cost(20);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Float Immediate: +0.0f
+operand immF0() %{
+  predicate(jint_cast(n->getf()) == 0);
+  match(ConF);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Float Immediate: encoded as 8 bits
+operand imm8F() %{
+  predicate(Assembler::float_num(n->getf()).can_be_imm8());
+  match(ConF);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Register Operands
+// Integer Register
+operand iRegI() %{
+  constraint(ALLOC_IN_RC(int_reg));
+  match(RegI);
+  match(R0RegI);
+  match(R1RegI);
+  match(R2RegI);
+  match(R3RegI);
+#ifdef AARCH64
+  match(ZRRegI);
+#else
+  match(R12RegI);
+#endif
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+// Pointer Register
+operand iRegP() %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(RegP);
+  match(R0RegP);
+  match(R1RegP);
+  match(R2RegP);
+  match(RExceptionRegP);
+  match(R8RegP);
+  match(R9RegP);
+  match(RthreadRegP); // FIXME: move to sp_ptr_RegP?
+  match(R12RegP);
+  match(LRRegP);
+
+  match(sp_ptr_RegP);
+  match(store_ptr_RegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+// GPRs + Rthread + SP
+operand sp_ptr_RegP() %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(RegP);
+  match(iRegP);
+  match(SPRegP); // FIXME: check cost
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+#ifdef AARCH64
+// Like sp_ptr_reg, but exclude regs (Aarch64 SP) that can't be
+// stored directly.  Includes ZR, so can't be used as a destination.
+operand store_ptr_RegP() %{
+  constraint(ALLOC_IN_RC(store_ptr_reg));
+  match(RegP);
+  match(iRegP);
+  match(ZRRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand store_RegI() %{
+  constraint(ALLOC_IN_RC(store_reg));
+  match(RegI);
+  match(iRegI);
+  match(ZRRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand store_RegL() %{
+  constraint(ALLOC_IN_RC(store_ptr_reg));
+  match(RegL);
+  match(iRegL);
+  match(ZRRegL);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand store_RegN() %{
+  constraint(ALLOC_IN_RC(store_reg));
+  match(RegN);
+  match(iRegN);
+  match(ZRRegN);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+#endif
+
+operand R0RegP() %{
+  constraint(ALLOC_IN_RC(R0_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R1RegP() %{
+  constraint(ALLOC_IN_RC(R1_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R2RegP() %{
+  constraint(ALLOC_IN_RC(R2_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand RExceptionRegP() %{
+  constraint(ALLOC_IN_RC(Rexception_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand RthreadRegP() %{
+  constraint(ALLOC_IN_RC(Rthread_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand IPRegP() %{
+  constraint(ALLOC_IN_RC(IP_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand LRRegP() %{
+  constraint(ALLOC_IN_RC(LR_regP));
+  match(iRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R0RegI() %{
+  constraint(ALLOC_IN_RC(R0_regI));
+  match(iRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R1RegI() %{
+  constraint(ALLOC_IN_RC(R1_regI));
+  match(iRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R2RegI() %{
+  constraint(ALLOC_IN_RC(R2_regI));
+  match(iRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R3RegI() %{
+  constraint(ALLOC_IN_RC(R3_regI));
+  match(iRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+#ifndef AARCH64
+operand R12RegI() %{
+  constraint(ALLOC_IN_RC(R12_regI));
+  match(iRegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+#endif
+
+// Long Register
+operand iRegL() %{
+  constraint(ALLOC_IN_RC(long_reg));
+  match(RegL);
+#ifdef AARCH64
+  match(iRegLd);
+#else
+  match(R0R1RegL);
+  match(R2R3RegL);
+#endif
+//match(iRegLex);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand iRegLd() %{
+  constraint(ALLOC_IN_RC(long_reg_align));
+  match(iRegL); // FIXME: allows unaligned R11/R12?
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+#ifndef AARCH64
+// first long arg, or return value
+operand R0R1RegL() %{
+  constraint(ALLOC_IN_RC(R0R1_regL));
+  match(iRegL);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand R2R3RegL() %{
+  constraint(ALLOC_IN_RC(R2R3_regL));
+  match(iRegL);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+#endif
+
+// Condition Code Flag Register
+operand flagsReg() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr" %}
+  interface(REG_INTER);
+%}
+
+// Result of compare to 0 (TST)
+operand flagsReg_EQNELTGE() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr_EQNELTGE" %}
+  interface(REG_INTER);
+%}
+
+// Condition Code Register, unsigned comparisons.
+operand flagsRegU() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+#ifdef TODO
+  match(RegFlagsP);
+#endif
+
+  format %{ "apsr_U" %}
+  interface(REG_INTER);
+%}
+
+// Condition Code Register, pointer comparisons.
+operand flagsRegP() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr_P" %}
+  interface(REG_INTER);
+%}
+
+// Condition Code Register, long comparisons.
+#ifndef AARCH64
+operand flagsRegL_LTGE() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr_L_LTGE" %}
+  interface(REG_INTER);
+%}
+
+operand flagsRegL_EQNE() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr_L_EQNE" %}
+  interface(REG_INTER);
+%}
+
+operand flagsRegL_LEGT() %{
+  constraint(ALLOC_IN_RC(int_flags));
+  match(RegFlags);
+
+  format %{ "apsr_L_LEGT" %}
+  interface(REG_INTER);
+%}
+#endif
+
+// Condition Code Register, floating comparisons, unordered same as "less".
+operand flagsRegF() %{
+  constraint(ALLOC_IN_RC(float_flags));
+  match(RegFlags);
+
+  format %{ "fpscr_F" %}
+  interface(REG_INTER);
+%}
+
+// Vectors
+operand vecD() %{
+  constraint(ALLOC_IN_RC(actual_dflt_reg));
+  match(VecD);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand vecX() %{
+  constraint(ALLOC_IN_RC(vectorx_reg));
+  match(VecX);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand regD() %{
+  constraint(ALLOC_IN_RC(actual_dflt_reg));
+  match(RegD);
+  match(regD_low);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand regF() %{
+  constraint(ALLOC_IN_RC(sflt_reg));
+  match(RegF);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand regD_low() %{
+  constraint(ALLOC_IN_RC(dflt_low_reg));
+  match(RegD);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+// Special Registers
+
+// Method Register
+operand inline_cache_regP(iRegP reg) %{
+  constraint(ALLOC_IN_RC(Ricklass_regP));
+  match(reg);
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand interpreter_method_oop_regP(iRegP reg) %{
+  constraint(ALLOC_IN_RC(Rmethod_regP));
+  match(reg);
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+
+//----------Complex Operands---------------------------------------------------
+// Indirect Memory Reference
+operand indirect(sp_ptr_RegP reg) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(reg);
+
+  op_cost(100);
+  format %{ "[$reg]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp(0x0);
+  %}
+%}
+
+#ifdef AARCH64
+// Indirect with scaled*1 uimm12 offset
+operand indOffsetU12ScaleB(sp_ptr_RegP reg, immUL12 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with scaled*2 uimm12 offset
+operand indOffsetU12ScaleS(sp_ptr_RegP reg, immUL12x2 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with scaled*4 uimm12 offset
+operand indOffsetU12ScaleI(sp_ptr_RegP reg, immUL12x4 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with scaled*8 uimm12 offset
+operand indOffsetU12ScaleL(sp_ptr_RegP reg, immUL12x8 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with scaled*16 uimm12 offset
+operand indOffsetU12ScaleQ(sp_ptr_RegP reg, immUL12x16 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+#else // ! AARCH64
+
+// Indirect with Offset in ]-4096, 4096[
+operand indOffset12(sp_ptr_RegP reg, immI12 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with offset for float load/store
+operand indOffsetFP(sp_ptr_RegP reg, immIFP offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with Offset for half and double words
+operand indOffsetHD(sp_ptr_RegP reg, immIHD offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with Offset and Offset+4 in ]-1024, 1024[
+operand indOffsetFPx2(sp_ptr_RegP reg, immX10x2 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
+// Indirect with Offset and Offset+4 in ]-4096, 4096[
+operand indOffset12x2(sp_ptr_RegP reg, immI12x2 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+#ifdef AARCH64
+    index(0xff); // 0xff => no index
+#else
+    index(0xf); // PC => no index
+#endif
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+#endif // !AARCH64
+
+// Indirect with Register Index
+operand indIndex(iRegP addr, iRegX index) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr index);
+
+  op_cost(100);
+  format %{ "[$addr + $index]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale(0x0);
+    disp(0x0);
+  %}
+%}
+
+#ifdef AARCH64
+// Indirect Memory Times Scale Plus Index Register
+operand indIndexScaleS(iRegP addr, iRegX index, immI_1 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX index scale));
+
+  op_cost(100);
+  format %{"[$addr + $index << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x0);
+  %}
+%}
+
+// Indirect Memory Times Scale Plus 32-bit Index Register
+operand indIndexIScaleS(iRegP addr, iRegI index, immI_1 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX (ConvI2L index) scale));
+
+  op_cost(100);
+  format %{"[$addr + $index.w << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x7fffffff); // sxtw
+  %}
+%}
+
+// Indirect Memory Times Scale Plus Index Register
+operand indIndexScaleI(iRegP addr, iRegX index, immI_2 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX index scale));
+
+  op_cost(100);
+  format %{"[$addr + $index << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x0);
+  %}
+%}
+
+// Indirect Memory Times Scale Plus 32-bit Index Register
+operand indIndexIScaleI(iRegP addr, iRegI index, immI_2 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX (ConvI2L index) scale));
+
+  op_cost(100);
+  format %{"[$addr + $index.w << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x7fffffff); // sxtw
+  %}
+%}
+
+// Indirect Memory Times Scale Plus Index Register
+operand indIndexScaleL(iRegP addr, iRegX index, immI_3 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX index scale));
+
+  op_cost(100);
+  format %{"[$addr + $index << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x0);
+  %}
+%}
+
+// Indirect Memory Times Scale Plus 32-bit Index Register
+operand indIndexIScaleL(iRegP addr, iRegI index, immI_3 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX (ConvI2L index) scale));
+
+  op_cost(100);
+  format %{"[$addr + $index.w << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x7fffffff); // sxtw
+  %}
+%}
+
+// Indirect Memory Times Scale Plus Index Register
+operand indIndexScaleQ(iRegP addr, iRegX index, immI_4 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX index scale));
+
+  op_cost(100);
+  format %{"[$addr + $index << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x0);
+  %}
+%}
+
+// Indirect Memory Times Scale Plus 32-bit Index Register
+operand indIndexIScaleQ(iRegP addr, iRegI index, immI_4 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX (ConvI2L index) scale));
+
+  op_cost(100);
+  format %{"[$addr + $index.w << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x7fffffff); // sxtw
+  %}
+%}
+#else
+// Indirect Memory Times Scale Plus Index Register
+operand indIndexScale(iRegP addr, iRegX index, immU5 scale) %{
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(AddP addr (LShiftX index scale));
+
+  op_cost(100);
+  format %{"[$addr + $index << $scale]" %}
+  interface(MEMORY_INTER) %{
+    base($addr);
+    index($index);
+    scale($scale);
+    disp(0x0);
+  %}
+%}
+#endif
+
+// Operands for expressing Control Flow
+// NOTE:  Label is a predefined operand which should not be redefined in
+//        the AD file.  It is generically handled within the ADLC.
+
+//----------Conditional Branch Operands----------------------------------------
+// Comparison Op  - This is the operation of the comparison, and is limited to
+//                  the following set of codes:
+//                  L (<), LE (<=), G (>), GE (>=), E (==), NE (!=)
+//
+// Other attributes of the comparison, such as unsignedness, are specified
+// by the comparison instruction that sets a condition code flags register.
+// That result is represented by a flags operand whose subtype is appropriate
+// to the unsignedness (etc.) of the comparison.
+//
+// Later, the instruction which matches both the Comparison Op (a Bool) and
+// the flags (produced by the Cmp) specifies the coding of the comparison op
+// by matching a specific subtype of Bool operand below, such as cmpOpU.
+
+operand cmpOp() %{
+  match(Bool);
+
+  format %{ "" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0xb);
+    greater_equal(0xa);
+    less_equal(0xd);
+    greater(0xc);
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+// integer comparison with 0, signed
+operand cmpOp0() %{
+  match(Bool);
+
+  format %{ "" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0x4);
+    greater_equal(0x5);
+    less_equal(0xd); // unsupported
+    greater(0xc); // unsupported
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+// Comparison Op, unsigned
+operand cmpOpU() %{
+  match(Bool);
+
+  format %{ "u" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0x3);
+    greater_equal(0x2);
+    less_equal(0x9);
+    greater(0x8);
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+// Comparison Op, pointer (same as unsigned)
+operand cmpOpP() %{
+  match(Bool);
+
+  format %{ "p" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0x3);
+    greater_equal(0x2);
+    less_equal(0x9);
+    greater(0x8);
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+operand cmpOpL() %{
+  match(Bool);
+
+  format %{ "L" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0xb);
+    greater_equal(0xa);
+    less_equal(0xd);
+    greater(0xc);
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+operand cmpOpL_commute() %{
+  match(Bool);
+
+  format %{ "L" %}
+  interface(COND_INTER) %{
+    equal(0x0);
+    not_equal(0x1);
+    less(0xc);
+    greater_equal(0xd);
+    less_equal(0xa);
+    greater(0xb);
+    overflow(0x0); // unsupported/unimplemented
+    no_overflow(0x0); // unsupported/unimplemented
+  %}
+%}
+
+//----------OPERAND CLASSES----------------------------------------------------
+// Operand Classes are groups of operands that are used to simplify
+// instruction definitions by not requiring the AD writer to specify separate
+// instructions for every form of operand when the instruction accepts
+// multiple operand types with the same basic encoding and format.  The classic
+// case of this is memory operands.
+#ifdef AARCH64
+opclass memoryB(indirect, indIndex, indOffsetU12ScaleB);
+opclass memoryS(indirect, indIndex, indIndexScaleS, indIndexIScaleS, indOffsetU12ScaleS);
+opclass memoryI(indirect, indIndex, indIndexScaleI, indIndexIScaleI, indOffsetU12ScaleI);
+opclass memoryL(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL);
+opclass memoryP(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL);
+opclass memoryQ(indirect, indIndex, indIndexScaleQ, indIndexIScaleQ, indOffsetU12ScaleQ);
+opclass memoryF(indirect, indIndex, indIndexScaleI, indIndexIScaleI, indOffsetU12ScaleI);
+opclass memoryD(indirect, indIndex, indIndexScaleL, indIndexIScaleL, indOffsetU12ScaleL);
+
+opclass memoryScaledS(indIndexScaleS, indIndexIScaleS);
+opclass memoryScaledI(indIndexScaleI, indIndexIScaleI);
+opclass memoryScaledL(indIndexScaleL, indIndexIScaleL);
+opclass memoryScaledP(indIndexScaleL, indIndexIScaleL);
+opclass memoryScaledQ(indIndexScaleQ, indIndexIScaleQ);
+opclass memoryScaledF(indIndexScaleI, indIndexIScaleI);
+opclass memoryScaledD(indIndexScaleL, indIndexIScaleL);
+// when ldrex/strex is used:
+opclass memoryex ( indirect );
+opclass indIndexMemory( indIndex );
+opclass memoryvld ( indirect /* , write back mode not implemented */ );
+
+#else
+
+opclass memoryI ( indirect, indOffset12, indIndex, indIndexScale );
+opclass memoryP ( indirect, indOffset12, indIndex, indIndexScale );
+opclass memoryF ( indirect, indOffsetFP );
+opclass memoryF2 ( indirect, indOffsetFPx2 );
+opclass memoryD ( indirect, indOffsetFP );
+opclass memoryfp( indirect, indOffsetFP );
+opclass memoryB ( indirect, indIndex, indOffsetHD );
+opclass memoryS ( indirect, indIndex, indOffsetHD );
+opclass memoryL ( indirect, indIndex, indOffsetHD );
+
+opclass memoryScaledI(indIndexScale);
+opclass memoryScaledP(indIndexScale);
+
+// when ldrex/strex is used:
+opclass memoryex ( indirect );
+opclass indIndexMemory( indIndex );
+opclass memorylong ( indirect, indOffset12x2 );
+opclass memoryvld ( indirect /* , write back mode not implemented */ );
+#endif
+
+//----------PIPELINE-----------------------------------------------------------
+pipeline %{
+
+//----------ATTRIBUTES---------------------------------------------------------
+attributes %{
+  fixed_size_instructions;           // Fixed size instructions
+  max_instructions_per_bundle = 4;   // Up to 4 instructions per bundle
+  instruction_unit_size = 4;         // An instruction is 4 bytes long
+  instruction_fetch_unit_size = 16;  // The processor fetches one line
+  instruction_fetch_units = 1;       // of 16 bytes
+
+  // List of nop instructions
+  nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR );
+%}
+
+//----------RESOURCES----------------------------------------------------------
+// Resources are the functional units available to the machine
+resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1);
+
+//----------PIPELINE DESCRIPTION-----------------------------------------------
+// Pipeline Description specifies the stages in the machine's pipeline
+
+pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D);
+
+//----------PIPELINE CLASSES---------------------------------------------------
+// Pipeline Classes describe the stages in which input and output are
+// referenced by the hardware pipeline.
+
+// Integer ALU reg-reg operation
+pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+    single_instruction;
+    dst   : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg long operation
+pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{
+    instruction_count(2);
+    dst   : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg long dependent operation
+pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    cr    : E(write);
+    IALU  : R(2);
+%}
+
+// Integer ALU reg-imm operaion
+pipe_class ialu_reg_imm(iRegI dst, iRegI src1) %{
+    single_instruction;
+    dst   : E(write);
+    src1  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg operation with condition code
+pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
+    single_instruction;
+    dst   : E(write);
+    cr    : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU zero-reg operation
+pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{
+    single_instruction;
+    dst   : E(write);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU zero-reg operation with condition code only
+pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{
+    single_instruction;
+    cr    : E(write);
+    src   : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg operation with condition code only
+pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
+    single_instruction;
+    cr    : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-imm operation with condition code only
+pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1) %{
+    single_instruction;
+    cr    : E(write);
+    src1  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg-zero operation with condition code only
+pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{
+    single_instruction;
+    cr    : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-imm-zero operation with condition code only
+pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI0 zero) %{
+    single_instruction;
+    cr    : E(write);
+    src1  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg operation with condition code, src1 modified
+pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
+    single_instruction;
+    cr    : E(write);
+    src1  : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{
+    multiple_bundles;
+    dst   : E(write)+4;
+    cr    : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R(3);
+    BR    : R(2);
+%}
+
+// Integer ALU operation
+pipe_class ialu_none(iRegI dst) %{
+    single_instruction;
+    dst   : E(write);
+    IALU  : R;
+%}
+
+// Integer ALU reg operation
+pipe_class ialu_reg(iRegI dst, iRegI src) %{
+    single_instruction; may_have_no_code;
+    dst   : E(write);
+    src   : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU reg conditional operation
+// This instruction has a 1 cycle stall, and cannot execute
+// in the same cycle as the instruction setting the condition
+// code. We kludge this by pretending to read the condition code
+// 1 cycle earlier, and by marking the functional units as busy
+// for 2 cycles with the result available 1 cycle later than
+// is really the case.
+pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{
+    single_instruction;
+    op2_out : C(write);
+    op1     : R(read);
+    cr      : R(read);       // This is really E, with a 1 cycle stall
+    BR      : R(2);
+    MS      : R(2);
+%}
+
+// Integer ALU reg operation
+pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{
+    single_instruction; may_have_no_code;
+    dst   : E(write);
+    src   : R(read);
+    IALU  : R;
+%}
+pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{
+    single_instruction; may_have_no_code;
+    dst   : E(write);
+    src   : R(read);
+    IALU  : R;
+%}
+
+// Two integer ALU reg operations
+pipe_class ialu_reg_2(iRegL dst, iRegL src) %{
+    instruction_count(2);
+    dst   : E(write);
+    src   : R(read);
+    A0    : R;
+    A1    : R;
+%}
+
+// Two integer ALU reg operations
+pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{
+    instruction_count(2); may_have_no_code;
+    dst   : E(write);
+    src   : R(read);
+    A0    : R;
+    A1    : R;
+%}
+
+// Integer ALU imm operation
+pipe_class ialu_imm(iRegI dst) %{
+    single_instruction;
+    dst   : E(write);
+    IALU  : R;
+%}
+
+pipe_class ialu_imm_n(iRegI dst) %{
+    single_instruction;
+    dst   : E(write);
+    IALU  : R;
+%}
+
+// Integer ALU reg-reg with carry operation
+pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{
+    single_instruction;
+    dst   : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU cc operation
+pipe_class ialu_cc(iRegI dst, flagsReg cc) %{
+    single_instruction;
+    dst   : E(write);
+    cc    : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU cc / second IALU operation
+pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{
+    instruction_count(1); multiple_bundles;
+    dst   : E(write)+1;
+    src   : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU cc / second IALU operation
+pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{
+    instruction_count(1); multiple_bundles;
+    dst   : E(write)+1;
+    p     : R(read);
+    q     : R(read);
+    IALU  : R;
+%}
+
+// Integer ALU hi-lo-reg operation
+pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{
+    instruction_count(1); multiple_bundles;
+    dst   : E(write)+1;
+    IALU  : R(2);
+%}
+
+// Long Constant
+pipe_class loadConL( iRegL dst, immL src ) %{
+    instruction_count(2); multiple_bundles;
+    dst   : E(write)+1;
+    IALU  : R(2);
+    IALU  : R(2);
+%}
+
+// Pointer Constant
+pipe_class loadConP( iRegP dst, immP src ) %{
+    instruction_count(0); multiple_bundles;
+    fixed_latency(6);
+%}
+
+// Polling Address
+pipe_class loadConP_poll( iRegP dst, immP_poll src ) %{
+    dst   : E(write);
+    IALU  : R;
+%}
+
+// Long Constant small
+pipe_class loadConLlo( iRegL dst, immL src ) %{
+    instruction_count(2);
+    dst   : E(write);
+    IALU  : R;
+    IALU  : R;
+%}
+
+// [PHH] This is wrong for 64-bit.  See LdImmF/D.
+pipe_class loadConFD(regF dst, immF src, iRegP tmp) %{
+    instruction_count(1); multiple_bundles;
+    src   : R(read);
+    dst   : M(write)+1;
+    IALU  : R;
+    MS    : E;
+%}
+
+// Integer ALU nop operation
+pipe_class ialu_nop() %{
+    single_instruction;
+    IALU  : R;
+%}
+
+// Integer ALU nop operation
+pipe_class ialu_nop_A0() %{
+    single_instruction;
+    A0    : R;
+%}
+
+// Integer ALU nop operation
+pipe_class ialu_nop_A1() %{
+    single_instruction;
+    A1    : R;
+%}
+
+// Integer Multiply reg-reg operation
+pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+    single_instruction;
+    dst   : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    MS    : R(5);
+%}
+
+pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+    single_instruction;
+    dst   : E(write)+4;
+    src1  : R(read);
+    src2  : R(read);
+    MS    : R(6);
+%}
+
+// Integer Divide reg-reg
+pipe_class sdiv_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : E(write);
+    temp  : E(write);
+    src1  : R(read);
+    src2  : R(read);
+    temp  : R(read);
+    MS    : R(38);
+%}
+
+// Long Divide
+pipe_class divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+    dst  : E(write)+71;
+    src1 : R(read);
+    src2 : R(read)+1;
+    MS   : R(70);
+%}
+
+// Floating Point Add Float
+pipe_class faddF_reg_reg(regF dst, regF src1, regF src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FA    : R;
+%}
+
+// Floating Point Add Double
+pipe_class faddD_reg_reg(regD dst, regD src1, regD src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FA    : R;
+%}
+
+// Floating Point Conditional Move based on integer flags
+pipe_class int_conditional_float_move (cmpOp cmp, flagsReg cr, regF dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    cr    : R(read);
+    FA    : R(2);
+    BR    : R(2);
+%}
+
+// Floating Point Conditional Move based on integer flags
+pipe_class int_conditional_double_move (cmpOp cmp, flagsReg cr, regD dst, regD src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    cr    : R(read);
+    FA    : R(2);
+    BR    : R(2);
+%}
+
+// Floating Point Multiply Float
+pipe_class fmulF_reg_reg(regF dst, regF src1, regF src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FM    : R;
+%}
+
+// Floating Point Multiply Double
+pipe_class fmulD_reg_reg(regD dst, regD src1, regD src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FM    : R;
+%}
+
+// Floating Point Divide Float
+pipe_class fdivF_reg_reg(regF dst, regF src1, regF src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FM    : R;
+    FDIV  : C(14);
+%}
+
+// Floating Point Divide Double
+pipe_class fdivD_reg_reg(regD dst, regD src1, regD src2) %{
+    single_instruction;
+    dst   : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FM    : R;
+    FDIV  : C(17);
+%}
+
+// Floating Point Move/Negate/Abs Float
+pipe_class faddF_reg(regF dst, regF src) %{
+    single_instruction;
+    dst   : W(write);
+    src   : E(read);
+    FA    : R(1);
+%}
+
+// Floating Point Move/Negate/Abs Double
+pipe_class faddD_reg(regD dst, regD src) %{
+    single_instruction;
+    dst   : W(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert F->D
+pipe_class fcvtF2D(regD dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert I->D
+pipe_class fcvtI2D(regD dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert LHi->D
+pipe_class fcvtLHi2D(regD dst, regD src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert L->D
+pipe_class fcvtL2D(regD dst, iRegL src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert L->F
+pipe_class fcvtL2F(regF dst, iRegL src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert D->F
+pipe_class fcvtD2F(regD dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert I->L
+pipe_class fcvtI2L(regD dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert D->F
+pipe_class fcvtD2I(iRegI dst, regD src, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : X(write)+6;
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert D->L
+pipe_class fcvtD2L(regD dst, regD src, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : X(write)+6;
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert F->I
+pipe_class fcvtF2I(regF dst, regF src, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : X(write)+6;
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert F->L
+pipe_class fcvtF2L(regD dst, regF src, flagsReg cr) %{
+    instruction_count(1); multiple_bundles;
+    dst   : X(write)+6;
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Convert I->F
+pipe_class fcvtI2F(regF dst, regF src) %{
+    single_instruction;
+    dst   : X(write);
+    src   : E(read);
+    FA    : R;
+%}
+
+// Floating Point Compare
+pipe_class faddF_fcc_reg_reg_zero(flagsRegF cr, regF src1, regF src2, immI0 zero) %{
+    single_instruction;
+    cr    : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FA    : R;
+%}
+
+// Floating Point Compare
+pipe_class faddD_fcc_reg_reg_zero(flagsRegF cr, regD src1, regD src2, immI0 zero) %{
+    single_instruction;
+    cr    : X(write);
+    src1  : E(read);
+    src2  : E(read);
+    FA    : R;
+%}
+
+// Floating Add Nop
+pipe_class fadd_nop() %{
+    single_instruction;
+    FA  : R;
+%}
+
+// Integer Store to Memory
+pipe_class istore_mem_reg(memoryI mem, iRegI src) %{
+    single_instruction;
+    mem   : R(read);
+    src   : C(read);
+    MS    : R;
+%}
+
+// Integer Store to Memory
+pipe_class istore_mem_spORreg(memoryI mem, sp_ptr_RegP src) %{
+    single_instruction;
+    mem   : R(read);
+    src   : C(read);
+    MS    : R;
+%}
+
+// Float Store
+pipe_class fstoreF_mem_reg(memoryF mem, RegF src) %{
+    single_instruction;
+    mem : R(read);
+    src : C(read);
+    MS  : R;
+%}
+
+// Float Store
+pipe_class fstoreF_mem_zero(memoryF mem, immF0 src) %{
+    single_instruction;
+    mem : R(read);
+    MS  : R;
+%}
+
+// Double Store
+pipe_class fstoreD_mem_reg(memoryD mem, RegD src) %{
+    instruction_count(1);
+    mem : R(read);
+    src : C(read);
+    MS  : R;
+%}
+
+// Double Store
+pipe_class fstoreD_mem_zero(memoryD mem, immD0 src) %{
+    single_instruction;
+    mem : R(read);
+    MS  : R;
+%}
+
+// Integer Load (when sign bit propagation not needed)
+pipe_class iload_mem(iRegI dst, memoryI mem) %{
+    single_instruction;
+    mem : R(read);
+    dst : C(write);
+    MS  : R;
+%}
+
+// Integer Load (when sign bit propagation or masking is needed)
+pipe_class iload_mask_mem(iRegI dst, memoryI mem) %{
+    single_instruction;
+    mem : R(read);
+    dst : M(write);
+    MS  : R;
+%}
+
+// Float Load
+pipe_class floadF_mem(regF dst, memoryF mem) %{
+    single_instruction;
+    mem : R(read);
+    dst : M(write);
+    MS  : R;
+%}
+
+// Float Load
+pipe_class floadD_mem(regD dst, memoryD mem) %{
+    instruction_count(1); multiple_bundles; // Again, unaligned argument is only multiple case
+    mem : R(read);
+    dst : M(write);
+    MS  : R;
+%}
+
+// Memory Nop
+pipe_class mem_nop() %{
+    single_instruction;
+    MS  : R;
+%}
+
+pipe_class sethi(iRegP dst, immI src) %{
+    single_instruction;
+    dst  : E(write);
+    IALU : R;
+%}
+
+pipe_class loadPollP(iRegP poll) %{
+    single_instruction;
+    poll : R(read);
+    MS   : R;
+%}
+
+pipe_class br(Universe br, label labl) %{
+    single_instruction_with_delay_slot;
+    BR  : R;
+%}
+
+pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{
+    single_instruction_with_delay_slot;
+    cr    : E(read);
+    BR    : R;
+%}
+
+pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
+    single_instruction_with_delay_slot;
+    op1 : E(read);
+    BR  : R;
+    MS  : R;
+%}
+
+pipe_class br_nop() %{
+    single_instruction;
+    BR  : R;
+%}
+
+pipe_class simple_call(method meth) %{
+    instruction_count(2); multiple_bundles; force_serialization;
+    fixed_latency(100);
+    BR  : R(1);
+    MS  : R(1);
+    A0  : R(1);
+%}
+
+pipe_class compiled_call(method meth) %{
+    instruction_count(1); multiple_bundles; force_serialization;
+    fixed_latency(100);
+    MS  : R(1);
+%}
+
+pipe_class call(method meth) %{
+    instruction_count(0); multiple_bundles; force_serialization;
+    fixed_latency(100);
+%}
+
+pipe_class tail_call(Universe ignore, label labl) %{
+    single_instruction; has_delay_slot;
+    fixed_latency(100);
+    BR  : R(1);
+    MS  : R(1);
+%}
+
+pipe_class ret(Universe ignore) %{
+    single_instruction; has_delay_slot;
+    BR  : R(1);
+    MS  : R(1);
+%}
+
+// The real do-nothing guy
+pipe_class empty( ) %{
+    instruction_count(0);
+%}
+
+pipe_class long_memory_op() %{
+    instruction_count(0); multiple_bundles; force_serialization;
+    fixed_latency(25);
+    MS  : R(1);
+%}
+
+// Check-cast
+pipe_class partial_subtype_check_pipe(Universe ignore, iRegP array, iRegP match ) %{
+    array : R(read);
+    match  : R(read);
+    IALU   : R(2);
+    BR     : R(2);
+    MS     : R;
+%}
+
+// Convert FPU flags into +1,0,-1
+pipe_class floating_cmp( iRegI dst, regF src1, regF src2 ) %{
+    src1  : E(read);
+    src2  : E(read);
+    dst   : E(write);
+    FA    : R;
+    MS    : R(2);
+    BR    : R(2);
+%}
+
+// Compare for p < q, and conditionally add y
+pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{
+    p     : E(read);
+    q     : E(read);
+    y     : E(read);
+    IALU  : R(3)
+%}
+
+// Perform a compare, then move conditionally in a branch delay slot.
+pipe_class min_max( iRegI src2, iRegI srcdst ) %{
+    src2   : E(read);
+    srcdst : E(read);
+    IALU   : R;
+    BR     : R;
+%}
+
+// Define the class for the Nop node
+define %{
+   MachNop = ialu_nop;
+%}
+
+%}
+
+//----------INSTRUCTIONS-------------------------------------------------------
+
+//------------Special Nop instructions for bundling - no match rules-----------
+// Nop using the A0 functional unit
+instruct Nop_A0() %{
+  ins_pipe(ialu_nop_A0);
+%}
+
+// Nop using the A1 functional unit
+instruct Nop_A1( ) %{
+  ins_pipe(ialu_nop_A1);
+%}
+
+// Nop using the memory functional unit
+instruct Nop_MS( ) %{
+  ins_pipe(mem_nop);
+%}
+
+// Nop using the floating add functional unit
+instruct Nop_FA( ) %{
+  ins_pipe(fadd_nop);
+%}
+
+// Nop using the branch functional unit
+instruct Nop_BR( ) %{
+  ins_pipe(br_nop);
+%}
+
+//----------Load/Store/Move Instructions---------------------------------------
+//----------Load Instructions--------------------------------------------------
+// Load Byte (8bit signed)
+instruct loadB(iRegI dst, memoryB mem) %{
+  match(Set dst (LoadB mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRSB   $dst,$mem\t! byte -> int" %}
+  ins_encode %{
+    // High 32 bits are harmlessly set on Aarch64
+    __ ldrsb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Byte (8bit signed) into a Long Register
+instruct loadB2L(iRegL dst, memoryB mem) %{
+  match(Set dst (ConvI2L (LoadB mem)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRSB $dst,$mem\t! byte -> long"  %}
+  ins_encode %{
+    __ ldrsb($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRSB $dst.lo,$mem\t! byte -> long\n\t"
+            "ASR   $dst.hi,$dst.lo,31" %}
+  ins_encode %{
+    __ ldrsb($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
+  %}
+#endif
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Unsigned Byte (8bit UNsigned) into an int reg
+instruct loadUB(iRegI dst, memoryB mem) %{
+  match(Set dst (LoadUB mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRB   $dst,$mem\t! ubyte -> int" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+// Load Unsigned Byte (8bit UNsigned) into a Long Register
+instruct loadUB2L(iRegL dst, memoryB mem) %{
+  match(Set dst (ConvI2L (LoadUB mem)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRB  $dst,$mem\t! ubyte -> long"  %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRB  $dst.lo,$mem\t! ubyte -> long\n\t"
+            "MOV   $dst.hi,0" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Unsigned Byte (8 bit UNsigned) with immediate mask into Long Register
+instruct loadUB2L_limmI(iRegL dst, memoryB mem, limmIlow8 mask) %{
+  match(Set dst (ConvI2L (AndI (LoadUB mem) mask)));
+
+#ifdef AARCH64
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST);
+  size(8);
+  format %{ "LDRB  $dst,$mem\t! ubyte -> long\n\t"
+            "AND  $dst,$dst,$mask" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+    __ andr($dst$$Register, $dst$$Register, limmI_low($mask$$constant, 8));
+  %}
+#else
+  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
+  size(12);
+  format %{ "LDRB  $dst.lo,$mem\t! ubyte -> long\n\t"
+            "MOV   $dst.hi,0\n\t"
+            "AND  $dst.lo,$dst.lo,$mask" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+    __ andr($dst$$Register, $dst$$Register, limmI_low($mask$$constant, 8));
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Short (16bit signed)
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadSoff(iRegI dst, memoryScaledS mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadS (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "LDRSH   $dst,$mem+$off\t! short temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldrsh($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+#endif
+
+instruct loadS(iRegI dst, memoryS mem) %{
+  match(Set dst (LoadS mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRSH   $dst,$mem\t! short" %}
+  ins_encode %{
+    __ ldrsh($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Short (16 bit signed) to Byte (8 bit signed)
+instruct loadS2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDRSB   $dst,$mem\t! short -> byte" %}
+  ins_encode %{
+    // High 32 bits are harmlessly set on Aarch64
+    __ ldrsb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Short (16bit signed) into a Long Register
+instruct loadS2L(iRegL dst, memoryS mem) %{
+  match(Set dst (ConvI2L (LoadS mem)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRSH $dst,$mem\t! short -> long"  %}
+  ins_encode %{
+    __ ldrsh($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRSH $dst.lo,$mem\t! short -> long\n\t"
+            "ASR   $dst.hi,$dst.lo,31" %}
+  ins_encode %{
+    __ ldrsh($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
+  %}
+#endif
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Unsigned Short/Char (16bit UNsigned)
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadUSoff(iRegI dst, memoryScaledS mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadUS (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "LDRH   $dst,$mem+$off\t! ushort/char temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldrh($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+instruct loadUS(iRegI dst, memoryS mem) %{
+  match(Set dst (LoadUS mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRH   $dst,$mem\t! ushort/char" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
+instruct loadUS2B(iRegI dst, memoryB mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRSB   $dst,$mem\t! ushort -> byte" %}
+  ins_encode %{
+    __ ldrsb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
+instruct loadUS2L(iRegL dst, memoryS mem) %{
+  match(Set dst (ConvI2L (LoadUS mem)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRH  $dst,$mem\t! short -> long"  %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRH  $dst.lo,$mem\t! short -> long\n\t"
+            "MOV   $dst.hi, 0" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Unsigned Short/Char (16bit UNsigned) with mask 0xFF into a Long Register
+instruct loadUS2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
+  match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRB  $dst,$mem"  %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRB  $dst.lo,$mem\t! \n\t"
+            "MOV   $dst.hi, 0" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Unsigned Short/Char (16bit UNsigned) with a immediate mask into a Long Register
+instruct loadUS2L_limmI(iRegL dst, memoryS mem, limmI mask) %{
+  match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
+#ifdef AARCH64
+  ins_cost(MEMORY_REF_COST + 1*DEFAULT_COST);
+
+  size(8);
+  format %{ "LDRH   $dst,$mem\t! ushort/char & mask -> long\n\t"
+            "AND    $dst,$dst,$mask" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+    __ andr($dst$$Register, $dst$$Register, (uintx)$mask$$constant);
+  %}
+#else
+  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
+
+  size(12);
+  format %{ "LDRH   $dst,$mem\t! ushort/char & mask -> long\n\t"
+            "MOV    $dst.hi, 0\n\t"
+            "AND    $dst,$dst,$mask" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+    __ andr($dst$$Register, $dst$$Register, $mask$$constant);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Integer
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadIoff(iRegI dst, memoryScaledI mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadI (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "ldr_s32 $dst,$mem+$off\t! int temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr_s32($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+instruct loadI(iRegI dst, memoryI mem) %{
+  match(Set dst (LoadI mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "ldr_s32 $dst,$mem\t! int" %}
+  ins_encode %{
+    __ ldr_s32($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+// Load Integer to Byte (8 bit signed)
+instruct loadI2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDRSB   $dst,$mem\t! int -> byte" %}
+  ins_encode %{
+    __ ldrsb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Unsigned Byte (8 bit UNsigned)
+instruct loadI2UB(iRegI dst, memoryB mem, immI_255 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDRB   $dst,$mem\t! int -> ubyte" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Short (16 bit signed)
+instruct loadI2S(iRegI dst, memoryS mem, immI_16 sixteen) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRSH   $dst,$mem\t! int -> short" %}
+  ins_encode %{
+    __ ldrsh($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Unsigned Short (16 bit UNsigned)
+instruct loadI2US(iRegI dst, memoryS mem, immI_65535 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRH   $dst,$mem\t! int -> ushort/char" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer into a Long Register
+instruct loadI2L(iRegL dst, memoryI mem) %{
+  match(Set dst (ConvI2L (LoadI mem)));
+#ifdef AARCH64
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRSW $dst.lo,$mem\t! int -> long"  %}
+  ins_encode %{
+    __ ldr_s32($dst$$Register, $mem$$Address);
+  %}
+#else
+  ins_cost(MEMORY_REF_COST);
+
+  size(8);
+  format %{ "LDR   $dst.lo,$mem\t! int -> long\n\t"
+            "ASR   $dst.hi,$dst.lo,31\t! int->long" %}
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
+  %}
+#endif
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer with mask 0xFF into a Long Register
+instruct loadI2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+#ifdef AARCH64
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDRB   $dst.lo,$mem\t! int & 0xFF -> long"  %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+  %}
+#else
+  ins_cost(MEMORY_REF_COST);
+
+  size(8);
+  format %{ "LDRB   $dst.lo,$mem\t! int & 0xFF -> long\n\t"
+            "MOV    $dst.hi, 0" %}
+  ins_encode %{
+    __ ldrb($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Integer with mask 0xFFFF into a Long Register
+instruct loadI2L_immI_65535(iRegL dst, memoryS mem, immI_65535 mask) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LDRH   $dst,$mem\t! int & 0xFFFF -> long" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDRH   $dst,$mem\t! int & 0xFFFF -> long\n\t"
+            "MOV    $dst.hi, 0" %}
+  ins_encode %{
+    __ ldrh($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mask_mem);
+%}
+
+#ifdef AARCH64
+// Load Integer with an immediate mask into a Long Register
+instruct loadI2L_limmI(iRegL dst, memoryI mem, limmI mask) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+  ins_cost(MEMORY_REF_COST + 1*DEFAULT_COST);
+
+  size(8);
+  format %{ "LDRSW $dst,$mem\t! int -> long\n\t"
+            "AND   $dst,$dst,$mask" %}
+
+  ins_encode %{
+    __ ldr_s32($dst$$Register, $mem$$Address);
+    __ andr($dst$$Register, $dst$$Register, (uintx)$mask$$constant);
+  %}
+  ins_pipe(iload_mem);
+%}
+#else
+// Load Integer with a 31-bit immediate mask into a Long Register
+instruct loadI2L_limmU31(iRegL dst, memoryI mem, limmU31 mask) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
+
+  size(12);
+  format %{ "LDR   $dst.lo,$mem\t! int -> long\n\t"
+            "MOV    $dst.hi, 0\n\t"
+            "AND   $dst,$dst,$mask" %}
+
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+    __ andr($dst$$Register, $dst$$Register, $mask$$constant);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+#ifdef AARCH64
+// Load Integer with mask into a Long Register
+// FIXME: use signedRegI mask, remove tmp?
+instruct loadI2L_immI(iRegL dst, memoryI mem, immI mask, iRegI tmp) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+  effect(TEMP dst, TEMP tmp);
+
+  ins_cost(MEMORY_REF_COST + 3*DEFAULT_COST);
+  format %{ "LDRSW    $mem,$dst\t! int & 31-bit mask -> long\n\t"
+            "MOV_SLOW $tmp,$mask\n\t"
+            "AND      $dst,$tmp,$dst" %}
+  ins_encode %{
+    __ ldrsw($dst$$Register, $mem$$Address);
+    __ mov_slow($tmp$$Register, $mask$$constant);
+    __ andr($dst$$Register, $dst$$Register, $tmp$$Register);
+  %}
+  ins_pipe(iload_mem);
+%}
+#else
+// Load Integer with a 31-bit mask into a Long Register
+// FIXME: use iRegI mask, remove tmp?
+instruct loadI2L_immU31(iRegL dst, memoryI mem, immU31 mask, iRegI tmp) %{
+  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
+  effect(TEMP dst, TEMP tmp);
+
+  ins_cost(MEMORY_REF_COST + 4*DEFAULT_COST);
+  size(20);
+  format %{ "LDR      $mem,$dst\t! int & 31-bit mask -> long\n\t"
+            "MOV      $dst.hi, 0\n\t"
+            "MOV_SLOW $tmp,$mask\n\t"
+            "AND      $dst,$tmp,$dst" %}
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+    __ mov_slow($tmp$$Register, $mask$$constant);
+    __ andr($dst$$Register, $dst$$Register, $tmp$$Register);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+// Load Unsigned Integer into a Long Register
+instruct loadUI2L(iRegL dst, memoryI mem, immL_32bits mask) %{
+  match(Set dst (AndL (ConvI2L (LoadI mem)) mask));
+  ins_cost(MEMORY_REF_COST);
+
+#ifdef AARCH64
+//size(4);
+  format %{ "LDR_w $dst,$mem\t! uint -> long" %}
+  ins_encode %{
+    __ ldr_w($dst$$Register, $mem$$Address);
+  %}
+#else
+  size(8);
+  format %{ "LDR   $dst.lo,$mem\t! uint -> long\n\t"
+            "MOV   $dst.hi,0" %}
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(iload_mem);
+%}
+
+// Load Long
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadLoff(iRegLd dst, memoryScaledL mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadL (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "LDR    $dst,$mem+$off\t! long temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+instruct loadL(iRegLd dst, memoryL mem ) %{
+#ifdef AARCH64
+  // already atomic for Aarch64
+#else
+  predicate(!((LoadLNode*)n)->require_atomic_access());
+#endif
+  match(Set dst (LoadL mem));
+  effect(TEMP dst);
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "ldr_64  $dst,$mem\t! long" %}
+  ins_encode %{
+    __ ldr_64($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+#ifndef AARCH64
+instruct loadL_2instr(iRegL dst, memorylong mem ) %{
+  predicate(!((LoadLNode*)n)->require_atomic_access());
+  match(Set dst (LoadL mem));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST);
+
+  size(8);
+  format %{ "LDR    $dst.lo,$mem \t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
+            "LDR    $dst.hi,$mem+4 or $mem" %}
+  ins_encode %{
+    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
+
+    if ($dst$$Register == reg_to_register_object($mem$$base)) {
+      __ ldr($dst$$Register->successor(), Amemhi);
+      __ ldr($dst$$Register, Amemlo);
+    } else {
+      __ ldr($dst$$Register, Amemlo);
+      __ ldr($dst$$Register->successor(), Amemhi);
+    }
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct loadL_volatile(iRegL dst, indirect mem ) %{
+  predicate(((LoadLNode*)n)->require_atomic_access());
+  match(Set dst (LoadL mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDMIA    $dst,$mem\t! long" %}
+  ins_encode %{
+    // FIXME: why is ldmia considered atomic?  Should be ldrexd
+    RegisterSet set($dst$$Register);
+    set = set | reg_to_register_object($dst$$reg + 1);
+    __ ldmia(reg_to_register_object($mem$$base), set);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct loadL_volatile_fp(iRegL dst, memoryD mem ) %{
+  predicate(((LoadLNode*)n)->require_atomic_access());
+  match(Set dst (LoadL mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(8);
+  format %{ "FLDD      S14, $mem"
+            "FMRRD    $dst, S14\t! long \n't" %}
+  ins_encode %{
+    __ fldd(S14, $mem$$Address);
+    __ fmrrd($dst$$Register, $dst$$Register->successor(), S14);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct loadL_unaligned(iRegL dst, memorylong mem ) %{
+  match(Set dst (LoadL_unaligned mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(8);
+  format %{ "LDR    $dst.lo,$mem\t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
+            "LDR    $dst.hi,$mem+4" %}
+  ins_encode %{
+    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
+
+    if ($dst$$Register == reg_to_register_object($mem$$base)) {
+      __ ldr($dst$$Register->successor(), Amemhi);
+      __ ldr($dst$$Register, Amemlo);
+    } else {
+      __ ldr($dst$$Register, Amemlo);
+      __ ldr($dst$$Register->successor(), Amemhi);
+    }
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif // !AARCH64
+
+// Load Range
+instruct loadRange(iRegI dst, memoryI mem) %{
+  match(Set dst (LoadRange mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDR_u32 $dst,$mem\t! range" %}
+  ins_encode %{
+    __ ldr_u32($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+// Load Pointer
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadPoff(iRegP dst, memoryScaledP mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadP (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "LDR    $dst,$mem+$off\t! ptr temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+instruct loadP(iRegP dst, memoryP mem) %{
+  match(Set dst (LoadP mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "LDR   $dst,$mem\t! ptr" %}
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+#ifdef XXX
+// FIXME XXXX
+//instruct loadSP(iRegP dst, memoryP mem) %{
+instruct loadSP(SPRegP dst, memoryP mem, iRegP tmp) %{
+  match(Set dst (LoadP mem));
+  effect(TEMP tmp);
+  ins_cost(MEMORY_REF_COST+1);
+  size(8);
+
+  format %{ "LDR   $tmp,$mem\t! ptr\n\t"
+            "MOV   $dst,$tmp\t! ptr" %}
+  ins_encode %{
+    __ ldr($tmp$$Register, $mem$$Address);
+    __ mov($dst$$Register, $tmp$$Register);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+#ifdef _LP64
+// Load Compressed Pointer
+
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadNoff(iRegN dst, memoryScaledI mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadN (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "ldr_u32 $dst,$mem+$off\t! compressed ptr temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr_u32($dst$$Register, nmem);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct loadN(iRegN dst, memoryI mem) %{
+  match(Set dst (LoadN mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "ldr_u32 $dst,$mem\t! compressed ptr" %}
+  ins_encode %{
+    __ ldr_u32($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+// Load Klass Pointer
+instruct loadKlass(iRegP dst, memoryI mem) %{
+  match(Set dst (LoadKlass mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "LDR   $dst,$mem\t! klass ptr" %}
+  ins_encode %{
+    __ ldr($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+#ifdef _LP64
+// Load narrow Klass Pointer
+instruct loadNKlass(iRegN dst, memoryI mem) %{
+  match(Set dst (LoadNKlass mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "ldr_u32 $dst,$mem\t! compressed klass ptr" %}
+  ins_encode %{
+    __ ldr_u32($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadDoff(regD dst, memoryScaledD mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadD (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "ldr    $dst,$mem+$off\t! double temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr_d($dst$$FloatRegister, nmem);
+  %}
+  ins_pipe(floadD_mem);
+%}
+#endif
+
+instruct loadD(regD dst, memoryD mem) %{
+  match(Set dst (LoadD mem));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  // FIXME: needs to be atomic, but  ARMv7 A.R.M. guarantees
+  // only LDREXD and STREXD are 64-bit single-copy atomic
+  format %{ "FLDD   $dst,$mem" %}
+  ins_encode %{
+    __ ldr_double($dst$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(floadD_mem);
+%}
+
+#ifndef AARCH64
+// Load Double - UNaligned
+instruct loadD_unaligned(regD_low dst, memoryF2 mem ) %{
+  match(Set dst (LoadD_unaligned mem));
+  ins_cost(MEMORY_REF_COST*2+DEFAULT_COST);
+  size(8);
+  format %{ "FLDS    $dst.lo,$mem\t! misaligned double\n"
+          "\tFLDS    $dst.hi,$mem+4\t!" %}
+  ins_encode %{
+    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
+      __ flds($dst$$FloatRegister, Amemlo);
+      __ flds($dst$$FloatRegister->successor(), Amemhi);
+  %}
+  ins_pipe(iload_mem);
+%}
+#endif
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct loadFoff(regF dst, memoryScaledF mem, aimmX off, iRegP tmp) %{
+  match(Set dst (LoadF (AddP mem off)));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "ldr    $dst,$mem+$off\t! float temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ ldr_s($dst$$FloatRegister, nmem);
+  %}
+  ins_pipe(floadF_mem);
+%}
+#endif
+
+instruct loadF(regF dst, memoryF mem) %{
+  match(Set dst (LoadF mem));
+
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "FLDS    $dst,$mem" %}
+  ins_encode %{
+    __ ldr_float($dst$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(floadF_mem);
+%}
+
+#ifdef AARCH64
+instruct load_limmI(iRegI dst, limmI src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST + 1); // + 1 because MOV is preferred
+  format %{ "ORR_w  $dst, ZR, $src\t! int"  %}
+  ins_encode %{
+    __ orr_w($dst$$Register, ZR, (uintx)$src$$constant);
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+// // Load Constant
+instruct loadConI( iRegI dst, immI src ) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 3/2);
+  format %{ "MOV_SLOW    $dst, $src" %}
+  ins_encode %{
+    __ mov_slow($dst$$Register, $src$$constant);
+  %}
+  ins_pipe(ialu_hi_lo_reg);
+%}
+
+instruct loadConIMov( iRegI dst, immIMov src ) %{
+  match(Set dst src);
+  size(4);
+  format %{ "MOV    $dst, $src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant);
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+#ifndef AARCH64
+instruct loadConIMovn( iRegI dst, immIRotn src ) %{
+  match(Set dst src);
+  size(4);
+  format %{ "MVN    $dst, ~$src" %}
+  ins_encode %{
+    __ mvn($dst$$Register, ~$src$$constant);
+  %}
+  ins_pipe(ialu_imm_n);
+%}
+#endif
+
+instruct loadConI16( iRegI dst, immI16 src ) %{
+  match(Set dst src);
+  size(4);
+#ifdef AARCH64
+  format %{ "MOVZ_w  $dst, $src" %}
+#else
+  format %{ "MOVW    $dst, $src" %}
+#endif
+  ins_encode %{
+#ifdef AARCH64
+    __ mov_w($dst$$Register, $src$$constant);
+#else
+    __ movw($dst$$Register, $src$$constant);
+#endif
+  %}
+  ins_pipe(ialu_imm_n);
+%}
+
+instruct loadConP(iRegP dst, immP src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 3/2);
+  format %{ "MOV_SLOW    $dst,$src\t!ptr" %}
+  ins_encode %{
+    relocInfo::relocType constant_reloc = _opnds[1]->constant_reloc();
+    intptr_t val = $src$$constant;
+    if (constant_reloc == relocInfo::oop_type) {
+      __ mov_oop($dst$$Register, (jobject)val);
+    } else if (constant_reloc == relocInfo::metadata_type) {
+      __ mov_metadata($dst$$Register, (Metadata*)val);
+    } else {
+      __ mov_slow($dst$$Register, val);
+    }
+  %}
+  ins_pipe(loadConP);
+%}
+
+
+instruct loadConP_poll(iRegP dst, immP_poll src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  format %{ "MOV_SLOW    $dst,$src\t!ptr" %}
+  ins_encode %{
+      __ mov_slow($dst$$Register, $src$$constant);
+  %}
+  ins_pipe(loadConP_poll);
+%}
+
+#ifdef AARCH64
+instruct loadConP0(iRegP dst, immP0 src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  format %{ "MOV    $dst,ZR\t!ptr" %}
+  ins_encode %{
+    __ mov($dst$$Register, ZR);
+  %}
+  ins_pipe(ialu_none);
+%}
+
+instruct loadConN(iRegN dst, immN src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 3/2);
+  format %{ "SET    $dst,$src\t! compressed ptr" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    // FIXME: use $constanttablebase?
+    __ set_narrow_oop(dst, (jobject)$src$$constant);
+  %}
+  ins_pipe(ialu_hi_lo_reg);
+%}
+
+instruct loadConN0(iRegN dst, immN0 src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  format %{ "MOV    $dst,ZR\t! compressed ptr" %}
+  ins_encode %{
+    __ mov($dst$$Register, ZR);
+  %}
+  ins_pipe(ialu_none);
+%}
+
+instruct loadConNKlass(iRegN dst, immNKlass src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 3/2);
+  format %{ "SET    $dst,$src\t! compressed klass ptr" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    // FIXME: use $constanttablebase?
+    __ set_narrow_klass(dst, (Klass*)$src$$constant);
+  %}
+  ins_pipe(ialu_hi_lo_reg);
+%}
+
+instruct load_limmL(iRegL dst, limmL src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  format %{ "ORR    $dst, ZR, $src\t! long"  %}
+  ins_encode %{
+    __ orr($dst$$Register, ZR, (uintx)$src$$constant);
+  %}
+  ins_pipe(loadConL);
+%}
+instruct load_immLMov(iRegL dst, immLMov src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  format %{ "MOV    $dst, $src\t! long"  %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant);
+  %}
+  ins_pipe(loadConL);
+%}
+instruct loadConL(iRegL dst, immL src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 4); // worst case
+  format %{ "mov_slow   $dst, $src\t! long"  %}
+  ins_encode %{
+    // FIXME: use $constanttablebase?
+    __ mov_slow($dst$$Register, $src$$constant);
+  %}
+  ins_pipe(loadConL);
+%}
+#else
+instruct loadConL(iRegL dst, immL src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 4);
+  format %{ "MOV_SLOW   $dst.lo, $src & 0x0FFFFFFFFL \t! long\n\t"
+            "MOV_SLOW   $dst.hi, $src >> 32" %}
+  ins_encode %{
+    __ mov_slow(reg_to_register_object($dst$$reg), $src$$constant & 0x0FFFFFFFFL);
+    __ mov_slow(reg_to_register_object($dst$$reg + 1), ((julong)($src$$constant)) >> 32);
+  %}
+  ins_pipe(loadConL);
+%}
+
+instruct loadConL16( iRegL dst, immL16 src ) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 2);
+
+  size(8);
+  format %{ "MOVW    $dst.lo, $src \n\t"
+            "MOVW    $dst.hi, 0 \n\t" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant);
+    __ movw($dst$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+instruct loadConF_imm8(regF dst, imm8F src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  size(4);
+
+  format %{ "FCONSTS      $dst, $src"%}
+
+  ins_encode %{
+    __ fconsts($dst$$FloatRegister, Assembler::float_num($src$$constant).imm8());
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+#ifdef AARCH64
+instruct loadIConF(iRegI dst, immF src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 2);
+
+  format %{ "MOV_SLOW  $dst, $src\t! loadIConF"  %}
+
+  ins_encode %{
+    // FIXME revisit once 6961697 is in
+    union {
+      jfloat f;
+      int i;
+    } v;
+    v.f = $src$$constant;
+    __ mov_slow($dst$$Register, v.i);
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+instruct loadConF(regF dst, immF src, iRegI tmp) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST * 2);
+  effect(TEMP tmp);
+  size(3*4);
+
+  format %{ "MOV_SLOW  $tmp, $src\n\t"
+            "FMSR      $dst, $tmp"%}
+
+  ins_encode %{
+    // FIXME revisit once 6961697 is in
+    union {
+      jfloat f;
+      int i;
+    } v;
+    v.f = $src$$constant;
+    __ mov_slow($tmp$$Register, v.i);
+    __ fmsr($dst$$FloatRegister, $tmp$$Register);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+instruct loadConD_imm8(regD dst, imm8D src) %{
+  match(Set dst src);
+  ins_cost(DEFAULT_COST);
+  size(4);
+
+  format %{ "FCONSTD      $dst, $src"%}
+
+  ins_encode %{
+    __ fconstd($dst$$FloatRegister, Assembler::double_num($src$$constant).imm8());
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+instruct loadConD(regD dst, immD src, iRegP tmp) %{
+  match(Set dst src);
+  effect(TEMP tmp);
+  ins_cost(MEMORY_REF_COST);
+  format %{ "FLDD  $dst, [$constanttablebase + $constantoffset]\t! load from constant table: double=$src" %}
+
+  ins_encode %{
+    Register r = $constanttablebase;
+    int offset  = $constantoffset($src);
+    if (!is_memoryD(offset)) {                // can't use a predicate
+                                              // in load constant instructs
+      __ add_slow($tmp$$Register, r, offset);
+      r = $tmp$$Register;
+      offset = 0;
+    }
+    __ ldr_double($dst$$FloatRegister, Address(r, offset));
+  %}
+  ins_pipe(loadConFD);
+%}
+
+// Prefetch instructions.
+// Must be safe to execute with invalid address (cannot fault).
+
+instruct prefetchAlloc_mp( memoryP mem ) %{
+  predicate(os::is_MP());
+  match( PrefetchAllocation mem );
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "PLDW $mem\t! Prefetch allocation" %}
+  ins_encode %{
+#ifdef AARCH64
+    __ prfm(pstl1keep, $mem$$Address);
+#else
+    __ pldw($mem$$Address);
+#endif
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct prefetchAlloc_sp( memoryP mem ) %{
+  predicate(!os::is_MP());
+  match( PrefetchAllocation mem );
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "PLD $mem\t! Prefetch allocation" %}
+  ins_encode %{
+#ifdef AARCH64
+    __ prfm(pstl1keep, $mem$$Address);
+#else
+    __ pld($mem$$Address);
+#endif
+  %}
+  ins_pipe(iload_mem);
+%}
+
+//----------Store Instructions-------------------------------------------------
+// Store Byte
+instruct storeB(memoryB mem, store_RegI src) %{
+  match(Set mem (StoreB mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "STRB    $src,$mem\t! byte" %}
+  ins_encode %{
+    __ strb($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+instruct storeCM(memoryB mem, store_RegI src) %{
+  match(Set mem (StoreCM mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "STRB    $src,$mem\t! CMS card-mark byte" %}
+  ins_encode %{
+    __ strb($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+// Store Char/Short
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeCoff(store_RegI src, memoryScaledS mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreC (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "STRH    $src,$mem+$off\t! short temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ strh($src$$Register, nmem);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+instruct storeC(memoryS mem, store_RegI src) %{
+  match(Set mem (StoreC mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "STRH    $src,$mem\t! short" %}
+  ins_encode %{
+    __ strh($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+// Store Integer
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeIoff(store_RegI src, memoryScaledI mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreI (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "str_32 $src,$mem+$off\t! int temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str_32($src$$Register, nmem);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+instruct storeI(memoryI mem, store_RegI src) %{
+  match(Set mem (StoreI mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "str_32 $src,$mem" %}
+  ins_encode %{
+    __ str_32($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+// Store Long
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeLoff(store_RegLd src, memoryScaledL mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreL (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "str_64 $src,$mem+$off\t! long temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str_64($src$$Register, nmem);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+instruct storeL(memoryL mem, store_RegLd src) %{
+#ifdef AARCH64
+  // already atomic for Aarch64
+#else
+  predicate(!((StoreLNode*)n)->require_atomic_access());
+#endif
+  match(Set mem (StoreL mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "str_64  $src,$mem\t! long\n\t" %}
+
+  ins_encode %{
+    __ str_64($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+#ifndef AARCH64
+instruct storeL_2instr(memorylong mem, iRegL src) %{
+  predicate(!((StoreLNode*)n)->require_atomic_access());
+  match(Set mem (StoreL mem src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST);
+
+  size(8);
+  format %{ "STR    $src.lo,$mem\t! long\n\t"
+            "STR    $src.hi,$mem+4" %}
+
+  ins_encode %{
+    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
+    __ str($src$$Register, Amemlo);
+    __ str($src$$Register->successor(), Amemhi);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+instruct storeL_volatile(indirect mem, iRegL src) %{
+  predicate(((StoreLNode*)n)->require_atomic_access());
+  match(Set mem (StoreL mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "STMIA    $src,$mem\t! long" %}
+  ins_encode %{
+    // FIXME: why is stmia considered atomic?  Should be strexd
+    RegisterSet set($src$$Register);
+    set = set | reg_to_register_object($src$$reg + 1);
+    __ stmia(reg_to_register_object($mem$$base), set);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif // !AARCH64
+
+#ifndef AARCH64
+instruct storeL_volatile_fp(memoryD mem, iRegL src) %{
+  predicate(((StoreLNode*)n)->require_atomic_access());
+  match(Set mem (StoreL mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(8);
+  format %{ "FMDRR    S14, $src\t! long \n\t"
+            "FSTD     S14, $mem" %}
+  ins_encode %{
+    __ fmdrr(S14, $src$$Register, $src$$Register->successor());
+    __ fstd(S14, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+#ifdef XXX
+// Move SP Pointer
+//instruct movSP(sp_ptr_RegP dst, SPRegP src) %{
+//instruct movSP(iRegP dst, SPRegP src) %{
+instruct movSP(store_ptr_RegP dst, SPRegP src) %{
+  match(Set dst src);
+//predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con == TypeFunc::FramePtr);
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "MOV    $dst,$src\t! SP ptr\n\t" %}
+  ins_encode %{
+    assert(false, "XXX1 got here");
+    __ mov($dst$$Register, SP);
+    __ mov($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+#ifdef AARCH64
+// FIXME
+// Store SP Pointer
+instruct storeSP(memoryP mem, SPRegP src, iRegP tmp) %{
+  match(Set mem (StoreP mem src));
+  predicate(_kids[1]->_leaf->is_Proj() && _kids[1]->_leaf->as_Proj()->_con == TypeFunc::FramePtr);
+  // Multiple StoreP rules, different only in register mask.
+  // Matcher makes the last always valid.  The others will
+  // only be valid if they cost less than the last valid
+  // rule.  So cost(rule1) < cost(rule2) < cost(last)
+  // Unlike immediates, register constraints are not checked
+  // at match time.
+  ins_cost(MEMORY_REF_COST+DEFAULT_COST+4);
+  effect(TEMP tmp);
+  size(8);
+
+  format %{ "MOV    $tmp,$src\t! SP ptr\n\t"
+            "STR    $tmp,$mem\t! SP ptr" %}
+  ins_encode %{
+    assert($src$$Register == SP, "SP expected");
+    __ mov($tmp$$Register, $src$$Register);
+    __ str($tmp$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_spORreg); // FIXME
+%}
+#endif // AARCH64
+
+// Store Pointer
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storePoff(store_ptr_RegP src, memoryScaledP mem, aimmX off, iRegP tmp) %{
+  predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con != TypeFunc::FramePtr);
+  match(Set mem (StoreP (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "STR    $src,$mem+$off\t! ptr temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str($src$$Register, nmem);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+instruct storeP(memoryP mem, store_ptr_RegP src) %{
+  match(Set mem (StoreP mem src));
+#ifdef AARCH64
+  predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con != TypeFunc::FramePtr);
+#endif
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "STR    $src,$mem\t! ptr" %}
+  ins_encode %{
+    __ str($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_spORreg);
+%}
+
+#ifdef AARCH64
+// Store NULL Pointer
+instruct storeP0(memoryP mem, immP0 src) %{
+  match(Set mem (StoreP mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "STR    ZR,$mem\t! ptr" %}
+  ins_encode %{
+    __ str(ZR, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_spORreg);
+%}
+#endif // AARCH64
+
+#ifdef _LP64
+// Store Compressed Pointer
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeNoff(store_RegN src, memoryScaledI mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreN (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "str_32 $src,$mem+$off\t! compressed ptr temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str_32($src$$Register, nmem);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+instruct storeN(memoryI mem, store_RegN src) %{
+  match(Set mem (StoreN mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "str_32 $src,$mem\t! compressed ptr" %}
+  ins_encode %{
+    __ str_32($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+
+#ifdef AARCH64
+// Store NULL Pointer
+instruct storeN0(memoryI mem, immN0 src) %{
+  match(Set mem (StoreN mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "str_32 ZR,$mem\t! compressed ptr" %}
+  ins_encode %{
+    __ str_32(ZR, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+// Store Compressed Klass Pointer
+instruct storeNKlass(memoryI mem, store_RegN src) %{
+  match(Set mem (StoreNKlass mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "str_32 $src,$mem\t! compressed klass ptr" %}
+  ins_encode %{
+    __ str_32($src$$Register, $mem$$Address);
+  %}
+  ins_pipe(istore_mem_reg);
+%}
+#endif
+
+// Store Double
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeDoff(regD src, memoryScaledD mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreD (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "STR    $src,$mem+$off\t! double temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str_d($src$$FloatRegister, nmem);
+  %}
+  ins_pipe(fstoreD_mem_reg);
+%}
+#endif
+
+instruct storeD(memoryD mem, regD src) %{
+  match(Set mem (StoreD mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  // FIXME: needs to be atomic, but  ARMv7 A.R.M. guarantees
+  // only LDREXD and STREXD are 64-bit single-copy atomic
+  format %{ "FSTD   $src,$mem" %}
+  ins_encode %{
+    __ str_double($src$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(fstoreD_mem_reg);
+%}
+
+#ifdef AARCH64
+instruct movI2F(regF dst, iRegI src) %{
+  match(Set dst src);
+  size(4);
+
+  format %{ "FMOV_sw $dst,$src\t! movI2F" %}
+  ins_encode %{
+    __ fmov_sw($dst$$FloatRegister, $src$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+instruct movF2I(iRegI dst, regF src) %{
+  match(Set dst src);
+  size(4);
+
+  format %{ "FMOV_ws $dst,$src\t! movF2I" %}
+  ins_encode %{
+    __ fmov_ws($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif
+
+// Store Float
+
+#ifdef AARCH64
+// XXX This variant shouldn't be necessary if 6217251 is implemented
+instruct storeFoff(regF src, memoryScaledF mem, aimmX off, iRegP tmp) %{
+  match(Set mem (StoreF (AddP mem off) src));
+  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
+  effect(TEMP tmp);
+  size(4 * 2);
+
+  format %{ "str_s  $src,$mem+$off\t! float temp=$tmp" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    __ add($tmp$$Register, base, $off$$constant);
+    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
+    __ str_s($src$$FloatRegister, nmem);
+  %}
+  ins_pipe(fstoreF_mem_reg);
+%}
+#endif
+
+instruct storeF( memoryF mem, regF src) %{
+  match(Set mem (StoreF mem src));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "FSTS    $src,$mem" %}
+  ins_encode %{
+    __ str_float($src$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(fstoreF_mem_reg);
+%}
+
+#ifdef AARCH64
+// Convert oop pointer into compressed form
+instruct encodeHeapOop(iRegN dst, iRegP src, flagsReg ccr) %{
+  predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull);
+  match(Set dst (EncodeP src));
+  effect(KILL ccr);
+  format %{ "encode_heap_oop $dst, $src" %}
+  ins_encode %{
+    __ encode_heap_oop($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct encodeHeapOop_not_null(iRegN dst, iRegP src) %{
+  predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull);
+  match(Set dst (EncodeP src));
+  format %{ "encode_heap_oop_not_null $dst, $src" %}
+  ins_encode %{
+    __ encode_heap_oop_not_null($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct decodeHeapOop(iRegP dst, iRegN src, flagsReg ccr) %{
+  predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull &&
+            n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant);
+  match(Set dst (DecodeN src));
+  effect(KILL ccr);
+  format %{ "decode_heap_oop $dst, $src" %}
+  ins_encode %{
+    __ decode_heap_oop($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{
+  predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull ||
+            n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant);
+  match(Set dst (DecodeN src));
+  format %{ "decode_heap_oop_not_null $dst, $src" %}
+  ins_encode %{
+    __ decode_heap_oop_not_null($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct encodeKlass_not_null(iRegN dst, iRegP src) %{
+  match(Set dst (EncodePKlass src));
+  format %{ "encode_klass_not_null $dst, $src" %}
+  ins_encode %{
+    __ encode_klass_not_null($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct decodeKlass_not_null(iRegP dst, iRegN src) %{
+  match(Set dst (DecodeNKlass src));
+  format %{ "decode_klass_not_null $dst, $src" %}
+  ins_encode %{
+    __ decode_klass_not_null($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif // AARCH64
+
+//----------MemBar Instructions-----------------------------------------------
+// Memory barrier flavors
+
+// TODO: take advantage of Aarch64 load-acquire, store-release, etc
+// pattern-match out unnecessary membars
+instruct membar_storestore() %{
+  match(MemBarStoreStore);
+  ins_cost(4*MEMORY_REF_COST);
+
+  size(4);
+  format %{ "MEMBAR-storestore" %}
+  ins_encode %{
+    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
+  %}
+  ins_pipe(long_memory_op);
+%}
+
+instruct membar_acquire() %{
+  match(MemBarAcquire);
+  match(LoadFence);
+  ins_cost(4*MEMORY_REF_COST);
+
+  size(4);
+  format %{ "MEMBAR-acquire" %}
+  ins_encode %{
+    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), noreg);
+  %}
+  ins_pipe(long_memory_op);
+%}
+
+instruct membar_acquire_lock() %{
+  match(MemBarAcquireLock);
+  ins_cost(0);
+
+  size(0);
+  format %{ "!MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %}
+  ins_encode( );
+  ins_pipe(empty);
+%}
+
+instruct membar_release() %{
+  match(MemBarRelease);
+  match(StoreFence);
+  ins_cost(4*MEMORY_REF_COST);
+
+  size(4);
+  format %{ "MEMBAR-release" %}
+  ins_encode %{
+    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), noreg);
+  %}
+  ins_pipe(long_memory_op);
+%}
+
+instruct membar_release_lock() %{
+  match(MemBarReleaseLock);
+  ins_cost(0);
+
+  size(0);
+  format %{ "!MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %}
+  ins_encode( );
+  ins_pipe(empty);
+%}
+
+instruct membar_volatile() %{
+  match(MemBarVolatile);
+  ins_cost(4*MEMORY_REF_COST);
+
+  size(4);
+  format %{ "MEMBAR-volatile" %}
+  ins_encode %{
+    __ membar(MacroAssembler::StoreLoad, noreg);
+  %}
+  ins_pipe(long_memory_op);
+%}
+
+instruct unnecessary_membar_volatile() %{
+  match(MemBarVolatile);
+  predicate(Matcher::post_store_load_barrier(n));
+  ins_cost(0);
+
+  size(0);
+  format %{ "!MEMBAR-volatile (unnecessary so empty encoding)" %}
+  ins_encode( );
+  ins_pipe(empty);
+%}
+
+//----------Register Move Instructions-----------------------------------------
+// instruct roundDouble_nop(regD dst) %{
+//   match(Set dst (RoundDouble dst));
+//   ins_pipe(empty);
+// %}
+
+
+// instruct roundFloat_nop(regF dst) %{
+//   match(Set dst (RoundFloat dst));
+//   ins_pipe(empty);
+// %}
+
+
+#ifdef AARCH64
+// 0 constant in register
+instruct zrImmI0(ZRRegI dst, immI0 imm) %{
+  match(Set dst imm);
+  size(0);
+  ins_cost(0);
+
+  format %{ "! ZR (int 0)" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(ialu_none);
+%}
+
+// 0 constant in register
+instruct zrImmL0(ZRRegL dst, immL0 imm) %{
+  match(Set dst imm);
+  size(0);
+  ins_cost(0);
+
+  format %{ "! ZR (long 0)" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(ialu_none);
+%}
+
+#ifdef XXX
+// 0 constant in register
+instruct zrImmN0(ZRRegN dst, immN0 imm) %{
+  match(Set dst imm);
+  size(0);
+  ins_cost(0);
+
+  format %{ "! ZR (compressed pointer NULL)" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(ialu_none);
+%}
+
+// 0 constant in register
+instruct zrImmP0(ZRRegP dst, immP0 imm) %{
+  match(Set dst imm);
+  size(0);
+  ins_cost(0);
+
+  format %{ "! ZR (NULL)" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(ialu_none);
+%}
+#endif
+#endif // AARCH64
+
+// Cast Index to Pointer for unsafe natives
+instruct castX2P(iRegX src, iRegP dst) %{
+  match(Set dst (CastX2P src));
+
+  format %{ "MOV    $dst,$src\t! IntX->Ptr if $dst != $src" %}
+  ins_encode %{
+    if ($dst$$Register !=  $src$$Register) {
+      __ mov($dst$$Register, $src$$Register);
+    }
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+// Cast Pointer to Index for unsafe natives
+instruct castP2X(iRegP src, iRegX dst) %{
+  match(Set dst (CastP2X src));
+
+  format %{ "MOV    $dst,$src\t! Ptr->IntX if $dst != $src" %}
+  ins_encode %{
+    if ($dst$$Register !=  $src$$Register) {
+      __ mov($dst$$Register, $src$$Register);
+    }
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifndef AARCH64
+//----------Conditional Move---------------------------------------------------
+// Conditional move
+instruct cmovIP_reg(cmpOpP cmp, flagsRegP pcc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src\t! int" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+#ifdef AARCH64
+instruct cmovI_reg3(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovL_reg3(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovP_reg3(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src1, iRegP src2) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovN_reg3(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src1, iRegN src2) %{
+  match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovIP_reg3(cmpOpP cmp, flagsRegP icc, iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLP_reg3(cmpOpP cmp, flagsRegP icc, iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPP_reg3(cmpOpP cmp, flagsRegP icc, iRegP dst, iRegP src1, iRegP src2) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovNP_reg3(cmpOpP cmp, flagsRegP icc, iRegN dst, iRegN src1, iRegN src2) %{
+  match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovIU_reg3(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLU_reg3(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPU_reg3(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src1, iRegP src2) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovNU_reg3(cmpOpU cmp, flagsRegU icc, iRegN dst, iRegN src1, iRegN src2) %{
+  match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovIZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! int" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! long" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, iRegP src1, iRegP src2) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovNZ_reg3(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegN dst, iRegN src1, iRegN src2) %{
+  match(Set dst (CMoveN (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "CSEL $dst,$src1,$src2,$cmp\t! compressed ptr" %}
+  ins_encode %{
+    __ csel($dst$$Register, $src1$$Register, $src2$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif // AARCH64
+
+#ifndef AARCH64
+instruct cmovIP_immMov(cmpOpP cmp, flagsRegP pcc, iRegI dst, immIMov src) %{
+  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovIP_imm16(cmpOpP cmp, flagsRegP pcc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOVw$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+instruct cmovI_reg(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifdef AARCH64
+instruct cmovL_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src\t! long" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+#ifndef AARCH64
+instruct cmovI_immMov(cmpOp cmp, flagsReg icc, iRegI dst, immIMov src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovII_imm16(cmpOp cmp, flagsReg icc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOVw$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+instruct cmovII_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifndef AARCH64
+instruct cmovII_immMov_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immIMov src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(140);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovII_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(140);
+  size(4);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifndef AARCH64
+instruct cmovIIu_immMov(cmpOpU cmp, flagsRegU icc, iRegI dst, immIMov src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovIIu_imm16(cmpOpU cmp, flagsRegU icc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif
+
+// Conditional move
+instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPP_imm(cmpOpP cmp, flagsRegP pcc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
+  ins_cost(140);
+  size(4);
+#ifdef AARCH64
+  format %{ "MOV$cmp  $dst,ZR" %}
+#else
+  format %{ "MOV$cmp  $dst,$src" %}
+#endif
+  ins_encode %{
+#ifdef AARCH64
+    __ mov($dst$$Register,             ZR, (AsmCondition)($cmp$$cmpcode));
+#else
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+#endif
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+// This instruction also works with CmpN so we don't need cmovPN_reg.
+instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(150);
+
+  size(4);
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+
+  size(4);
+#ifdef AARCH64
+  format %{ "MOV$cmp  $dst,ZR\t! ptr" %}
+#else
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+#endif
+  ins_encode %{
+#ifdef AARCH64
+    __ mov($dst$$Register,             ZR, (AsmCondition)($cmp$$cmpcode));
+#else
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+#endif
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovPI_imm_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(140);
+
+  size(4);
+#ifdef AARCH64
+  format %{ "MOV$cmp  $dst,ZR\t! ptr" %}
+#else
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+#endif
+  ins_encode %{
+#ifdef AARCH64
+    __ mov($dst$$Register,             ZR, (AsmCondition)($cmp$$cmpcode));
+#else
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+#endif
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+
+  size(4);
+#ifdef AARCH64
+  format %{ "MOV$cmp  $dst,ZR\t! ptr" %}
+#else
+  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
+#endif
+  ins_encode %{
+#ifdef AARCH64
+    __ mov($dst$$Register,             ZR, (AsmCondition)($cmp$$cmpcode));
+#else
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+#endif
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+#ifdef AARCH64
+// Conditional move
+instruct cmovF_reg(cmpOp cmp, flagsReg icc, regF dst, regF src1, regF src2) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovD_reg(cmpOp cmp, flagsReg icc, regD dst, regD src1, regD src2) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFP_reg(cmpOpP cmp, flagsRegP icc, regF dst, regF src1, regF src2) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDP_reg(cmpOpP cmp, flagsRegP icc, regD dst, regD src1, regD src2) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFU_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src1, regF src2) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDU_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src1, regD src2) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFZ_reg(cmpOp0 cmp, flagsReg_EQNELTGE icc, regF dst, regF src1, regF src2) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_s $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_s($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDZ_reg(cmpOp0 cmp, flagsReg_EQNELTGE icc, regD dst, regD src1, regD src2) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary src2 src1)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCSEL_d $dst,$src1,$src2,$cmp" %}
+  ins_encode %{
+    __ fcsel_d($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+#else // !AARCH64
+
+// Conditional move
+instruct cmovFP_reg(cmpOpP cmp, flagsRegP pcc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp pcc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+// Conditional move
+instruct cmovDP_reg(cmpOpP cmp, flagsRegP pcc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp pcc) (Binary dst src)));
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_double_move);
+%}
+
+instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_double_move);
+%}
+
+instruct cmovDI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_double_move);
+%}
+
+instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_double_move);
+%}
+
+// Conditional move
+instruct cmovLP_reg(cmpOpP cmp, flagsRegP pcc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
+  ins_cost(150);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst.hi,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct cmovLP_immRot(cmpOpP cmp, flagsRegP pcc, iRegL dst, immLlowRot src) %{
+  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLP_imm16(cmpOpP cmp, flagsRegP pcc, iRegL dst, immL16 src) %{
+  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst.hi,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(150);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst.hi,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct cmovLI_immRot(cmpOp cmp, flagsReg icc, iRegL dst, immLlowRot src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct cmovLI_immRot_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immLlowRot src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLI_imm16(cmpOp cmp, flagsReg icc, iRegL dst, immL16 src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLI_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immL16 src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
+            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+  ins_cost(140);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
+            "MOV$cmp  $dst.hi,0" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+    __ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
+  ins_cost(150);
+
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst.hi,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif // !AARCH64
+
+
+//----------OS and Locking Instructions----------------------------------------
+
+// This name is KNOWN by the ADLC and cannot be changed.
+// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
+// for this guy.
+instruct tlsLoadP(RthreadRegP dst) %{
+  match(Set dst (ThreadLocal));
+
+  size(0);
+  ins_cost(0);
+  format %{ "! TLS is in $dst" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(ialu_none);
+%}
+
+instruct checkCastPP( iRegP dst ) %{
+  match(Set dst (CheckCastPP dst));
+
+  size(0);
+  format %{ "! checkcastPP of $dst" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(empty);
+%}
+
+
+instruct castPP( iRegP dst ) %{
+  match(Set dst (CastPP dst));
+  format %{ "! castPP of $dst" %}
+  ins_encode( /*empty encoding*/ );
+  ins_pipe(empty);
+%}
+
+instruct castII( iRegI dst ) %{
+  match(Set dst (CastII dst));
+  format %{ "! castII of $dst" %}
+  ins_encode( /*empty encoding*/ );
+  ins_cost(0);
+  ins_pipe(empty);
+%}
+
+//----------Arithmetic Instructions--------------------------------------------
+// Addition Instructions
+// Register Addition
+instruct addI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (AddI src1 src2));
+
+  size(4);
+  format %{ "add_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct addshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AddI (LShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+#ifdef AARCH64
+#ifdef TODO
+instruct addshlL_reg_imm_reg(iRegL dst, iRegL src1, immU6 src2, iRegL src3) %{
+  match(Set dst (AddL (LShiftL src1 src2) src3));
+
+  size(4);
+  format %{ "ADD    $dst,$src3,$src1<<$src2\t! long" %}
+  ins_encode %{
+    __ add($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+#endif
+
+instruct addshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (AddI (LShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct addsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AddI (RShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct addsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (AddI (RShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct addshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AddI (URShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct addshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (AddI (URShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Immediate Addition
+instruct addI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
+  match(Set dst (AddI src1 src2));
+
+  size(4);
+  format %{ "add_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ add_32($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+// Pointer Register Addition
+instruct addP_reg_reg(iRegP dst, iRegP src1, iRegX src2) %{
+  match(Set dst (AddP src1 src2));
+
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
+  ins_encode %{
+    __ add($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifdef AARCH64
+// unshifted I2L operand
+operand unshiftedI2L(iRegI src2) %{
+//constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(ConvI2L src2);
+
+  op_cost(1);
+  format %{ "$src2.w" %}
+  interface(MEMORY_INTER) %{
+    base($src2);
+    index(0xff);
+    scale(0x0);
+    disp(0x0);
+  %}
+%}
+
+// shifted I2L operand
+operand shiftedI2L(iRegI src2, immI_0_4 src3) %{
+//constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(LShiftX (ConvI2L src2) src3);
+
+  op_cost(1);
+  format %{ "$src2.w << $src3" %}
+  interface(MEMORY_INTER) %{
+    base($src2);
+    index(0xff);
+    scale($src3);
+    disp(0x0);
+  %}
+%}
+
+opclass shiftedRegI(shiftedI2L, unshiftedI2L);
+
+instruct shlL_reg_regI(iRegL dst, iRegI src1, immU6 src2) %{
+  match(Set dst (LShiftL (ConvI2L src1) src2));
+
+  size(4);
+  format %{ "LSL    $dst,$src1.w,$src2\t! ptr" %}
+  ins_encode %{
+    int c = $src2$$constant;
+    int r = 64 - c;
+    int s = 31;
+    if (s >= r) {
+      s = r - 1;
+    }
+    __ sbfm($dst$$Register, $src1$$Register, r, s);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct addP_reg_regI(iRegP dst, iRegP src1, shiftedRegI src2) %{
+  match(Set dst (AddP src1 src2));
+
+  ins_cost(DEFAULT_COST * 3/2);
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2, sxtw\t! ptr" %}
+  ins_encode %{
+    Register base = reg_to_register_object($src2$$base);
+    __ add($dst$$Register, $src1$$Register, base, ex_sxtw, $src2$$scale);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+// shifted iRegX operand
+operand shiftedX(iRegX src2, shimmX src3) %{
+//constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(LShiftX src2 src3);
+
+  op_cost(1);
+  format %{ "$src2 << $src3" %}
+  interface(MEMORY_INTER) %{
+    base($src2);
+    index(0xff);
+    scale($src3);
+    disp(0x0);
+  %}
+%}
+
+instruct addshlP_reg_reg_imm(iRegP dst, iRegP src1, shiftedX src2) %{
+  match(Set dst (AddP src1 src2));
+
+  ins_cost(DEFAULT_COST * 3/2);
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
+  ins_encode %{
+    Register base = reg_to_register_object($src2$$base);
+    __ add($dst$$Register, $src1$$Register, AsmOperand(base, lsl, $src2$$scale));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Pointer Immediate Addition
+instruct addP_reg_aimmX(iRegP dst, iRegP src1, aimmX src2) %{
+  match(Set dst (AddP src1 src2));
+
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
+  ins_encode %{
+    __ add($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+// Long Addition
+#ifdef AARCH64
+instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (AddL src1 src2));
+  size(4);
+  format %{ "ADD     $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ add($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct addL_reg_regI(iRegL dst, iRegL src1, shiftedRegI src2) %{
+  match(Set dst (AddL src1 src2));
+
+  ins_cost(DEFAULT_COST * 3/2);
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2, sxtw\t! long" %}
+  ins_encode %{
+    Register base = reg_to_register_object($src2$$base);
+    __ add($dst$$Register, $src1$$Register, base, ex_sxtw, $src2$$scale);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#else
+instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg ccr) %{
+  match(Set dst (AddL src1 src2));
+  effect(KILL ccr);
+  size(8);
+  format %{ "ADDS    $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
+            "ADC     $dst.hi,$src1.hi,$src2.hi" %}
+  ins_encode %{
+    __ adds($dst$$Register, $src1$$Register, $src2$$Register);
+    __ adc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+#ifdef AARCH64
+// Immediate Addition
+instruct addL_reg_aimm(iRegL dst, iRegL src1, aimmL src2) %{
+  match(Set dst (AddL src1 src2));
+
+  size(4);
+  format %{ "ADD    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ add($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct addL_reg_immLneg(iRegL dst, iRegL src1, aimmLneg src2) %{
+  match(Set dst (SubL src1 src2));
+
+  size(4);
+  format %{ "ADD    $dst,$src1,-($src2)\t! long" %}
+  ins_encode %{
+    __ add($dst$$Register, $src1$$Register, -$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// TODO
+#endif
+
+#ifndef AARCH64
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct addL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg ccr) %{
+  match(Set dst (AddL src1 con));
+  effect(KILL ccr);
+  size(8);
+  format %{ "ADDS    $dst.lo,$src1.lo,$con\t! long\n\t"
+            "ADC     $dst.hi,$src1.hi,0" %}
+  ins_encode %{
+    __ adds($dst$$Register, $src1$$Register, $con$$constant);
+    __ adc($dst$$Register->successor(), $src1$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+//----------Conditional_store--------------------------------------------------
+// Conditional-store of the updated heap-top.
+// Used during allocation of the shared heap.
+// Sets flags (EQ) on success.
+
+// TODO: optimize out barriers with AArch64 load-acquire/store-release
+// LoadP-locked.
+instruct loadPLocked(iRegP dst, memoryex mem) %{
+  match(Set dst (LoadPLocked mem));
+  size(4);
+  format %{ "LDREX  $dst,$mem" %}
+  ins_encode %{
+#ifdef AARCH64
+    Register base = reg_to_register_object($mem$$base);
+    __ ldxr($dst$$Register, base);
+#else
+    __ ldrex($dst$$Register,$mem$$Address);
+#endif
+  %}
+  ins_pipe(iload_mem);
+%}
+
+instruct storePConditional( memoryex heap_top_ptr, iRegP oldval, iRegP newval, iRegI tmp, flagsRegP pcc ) %{
+  predicate(_kids[1]->_kids[0]->_leaf->Opcode() == Op_LoadPLocked); // only works in conjunction with a LoadPLocked node
+  match(Set pcc (StorePConditional heap_top_ptr (Binary oldval newval)));
+  effect( TEMP tmp );
+  size(8);
+  format %{ "STREX  $tmp,$newval,$heap_top_ptr\n\t"
+            "CMP    $tmp, 0" %}
+  ins_encode %{
+#ifdef AARCH64
+    Register base = reg_to_register_object($heap_top_ptr$$base);
+    __ stxr($tmp$$Register, $newval$$Register, base);
+#else
+    __ strex($tmp$$Register, $newval$$Register, $heap_top_ptr$$Address);
+#endif
+    __ cmp($tmp$$Register, 0);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+// Conditional-store of an intx value.
+instruct storeXConditional( memoryex mem, iRegX oldval, iRegX newval, iRegX tmp, flagsReg icc ) %{
+#ifdef AARCH64
+  match(Set icc (StoreLConditional mem (Binary oldval newval)));
+  effect( TEMP tmp );
+  size(28);
+  format %{ "loop:\n\t"
+            "LDXR     $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem], DOESN'T set $newval=[$mem] in any case\n\t"
+            "SUBS     $tmp, $tmp, $oldval\n\t"
+            "B.ne     done\n\t"
+            "STXR     $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop\n\t"
+            "CMP      $tmp, 0\n\t"
+            "done:\n\t"
+            "membar   LoadStore|LoadLoad" %}
+#else
+  match(Set icc (StoreIConditional mem (Binary oldval newval)));
+  effect( TEMP tmp );
+  size(28);
+  format %{ "loop: \n\t"
+            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem], DOESN'T set $newval=[$mem] in any case\n\t"
+            "XORS     $tmp,$tmp, $oldval\n\t"
+            "STREX.eq $tmp, $newval, $mem\n\t"
+            "CMP.eq   $tmp, 1 \n\t"
+            "B.eq     loop \n\t"
+            "TEQ      $tmp, 0\n\t"
+            "membar   LoadStore|LoadLoad" %}
+#endif
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+#ifdef AARCH64
+// FIXME: use load-acquire/store-release, remove membar?
+    Label done;
+    Register base = reg_to_register_object($mem$$base);
+    __ ldxr($tmp$$Register, base);
+    __ subs($tmp$$Register, $tmp$$Register, $oldval$$Register);
+    __ b(done, ne);
+    __ stxr($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+    __ cmp($tmp$$Register, 0);
+    __ bind(done);
+#else
+    __ ldrex($tmp$$Register, $mem$$Address);
+    __ eors($tmp$$Register, $tmp$$Register, $oldval$$Register);
+    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
+    __ cmp($tmp$$Register, 1, eq);
+    __ b(loop, eq);
+    __ teq($tmp$$Register, 0);
+#endif
+    // used by biased locking only. Requires a membar.
+    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadStore | MacroAssembler::LoadLoad), noreg);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+// No flag versions for CompareAndSwap{P,I,L} because matcher can't match them
+
+#ifdef AARCH64
+// TODO: if combined with membar, elide membar and use
+// load-acquire/store-release if appropriate
+instruct compareAndSwapL_bool(memoryex mem, iRegL oldval, iRegL newval, iRegI res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(24);
+  format %{ "loop:\n\t"
+            "LDXR     $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP      $tmp, $oldval\n\t"
+            "B.ne     done\n\t"
+            "STXR     $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop\n\t"
+            "done:\n\t"
+            "CSET_w   $res, eq" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    Label loop, done;
+    __ bind(loop);
+    __ ldxr($tmp$$Register, base);
+    __ cmp($tmp$$Register, $oldval$$Register);
+    __ b(done, ne);
+    __ stxr($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+    __ bind(done);
+    __ cset_w($res$$Register, eq);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(24);
+  format %{ "loop:\n\t"
+            "LDXR_w   $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP_w    $tmp, $oldval\n\t"
+            "B.ne     done\n\t"
+            "STXR_w   $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop\n\t"
+            "done:\n\t"
+            "CSET_w   $res, eq" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    Label loop, done;
+    __ bind(loop);
+    __ ldxr_w($tmp$$Register, base);
+    __ cmp_w($tmp$$Register, $oldval$$Register);
+    __ b(done, ne);
+    __ stxr_w($tmp$$Register, $newval$$Register,  base);
+    __ cbnz_w($tmp$$Register, loop);
+    __ bind(done);
+    __ cset_w($res$$Register, eq);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+// tmp must use iRegI instead of iRegN until 8051805 is fixed.
+instruct compareAndSwapN_bool(memoryex mem, iRegN oldval, iRegN newval, iRegI res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(24);
+  format %{ "loop:\n\t"
+            "LDXR_w   $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP_w    $tmp, $oldval\n\t"
+            "B.ne     done\n\t"
+            "STXR_w   $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop\n\t"
+            "done:\n\t"
+            "CSET_w   $res, eq" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    Label loop, done;
+    __ bind(loop);
+    __ ldxr_w($tmp$$Register, base);
+    __ cmp_w($tmp$$Register, $oldval$$Register);
+    __ b(done, ne);
+    __ stxr_w($tmp$$Register, $newval$$Register,  base);
+    __ cbnz_w($tmp$$Register, loop);
+    __ bind(done);
+    __ cset_w($res$$Register, eq);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(24);
+  format %{ "loop:\n\t"
+            "LDXR     $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP      $tmp, $oldval\n\t"
+            "B.ne     done\n\t"
+            "STXR     $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop\n\t"
+            "done:\n\t"
+            "CSET_w   $res, eq" %}
+  ins_encode %{
+    Register base = reg_to_register_object($mem$$base);
+    Label loop, done;
+    __ bind(loop);
+    __ ldxr($tmp$$Register, base);
+    __ cmp($tmp$$Register, $oldval$$Register);
+    __ b(done, ne);
+    __ stxr($tmp$$Register, $newval$$Register,  base);
+    __ cbnz_w($tmp$$Register, loop);
+    __ bind(done);
+    __ cset_w($res$$Register, eq);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else // !AARCH64
+instruct compareAndSwapL_bool(memoryex mem, iRegL oldval, iRegLd newval, iRegI res, iRegLd tmp, flagsReg ccr ) %{
+  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(32);
+  format %{ "loop: \n\t"
+            "LDREXD   $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP      $tmp.lo, $oldval.lo\n\t"
+            "CMP.eq   $tmp.hi, $oldval.hi\n\t"
+            "STREXD.eq $tmp, $newval, $mem\n\t"
+            "MOV.ne   $tmp, 0 \n\t"
+            "XORS.eq  $tmp,$tmp, 1 \n\t"
+            "B.eq     loop \n\t"
+            "MOV      $res, $tmp" %}
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($tmp$$Register, $mem$$Address);
+    __ cmp($tmp$$Register, $oldval$$Register);
+    __ cmp($tmp$$Register->successor(), $oldval$$Register->successor(), eq);
+    __ strexd($tmp$$Register, $newval$$Register, $mem$$Address, eq);
+    __ mov($tmp$$Register, 0, ne);
+    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
+    __ b(loop, eq);
+    __ mov($res$$Register, $tmp$$Register);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+
+instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
+  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(28);
+  format %{ "loop: \n\t"
+            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP      $tmp, $oldval\n\t"
+            "STREX.eq $tmp, $newval, $mem\n\t"
+            "MOV.ne   $tmp, 0 \n\t"
+            "XORS.eq  $tmp,$tmp, 1 \n\t"
+            "B.eq     loop \n\t"
+            "MOV      $res, $tmp" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($tmp$$Register,$mem$$Address);
+    __ cmp($tmp$$Register, $oldval$$Register);
+    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
+    __ mov($tmp$$Register, 0, ne);
+    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
+    __ b(loop, eq);
+    __ mov($res$$Register, $tmp$$Register);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
+  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+  effect( KILL ccr, TEMP tmp);
+  size(28);
+  format %{ "loop: \n\t"
+            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+            "CMP      $tmp, $oldval\n\t"
+            "STREX.eq $tmp, $newval, $mem\n\t"
+            "MOV.ne   $tmp, 0 \n\t"
+            "EORS.eq  $tmp,$tmp, 1 \n\t"
+            "B.eq     loop \n\t"
+            "MOV      $res, $tmp" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($tmp$$Register,$mem$$Address);
+    __ cmp($tmp$$Register, $oldval$$Register);
+    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
+    __ mov($tmp$$Register, 0, ne);
+    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
+    __ b(loop, eq);
+    __ mov($res$$Register, $tmp$$Register);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif // !AARCH64
+
+#ifdef AARCH64
+instruct xaddI_aimmI_no_res(memoryex mem, aimmI add, Universe dummy, iRegI tmp1, iRegI tmp2) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddI mem add));
+  effect(TEMP tmp1, TEMP tmp2);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR_w   $tmp1, $mem\n\t"
+            "ADD_w    $tmp1, $tmp1, $add\n\t"
+            "STXR_w   $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($tmp1$$Register, base);
+    __ add_w($tmp1$$Register, $tmp1$$Register, $add$$constant);
+    __ stxr_w($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddI_aimmI_no_res(memoryex mem, aimmI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddI mem add));
+  effect(KILL ccr, TEMP tmp1, TEMP tmp2);
+  size(20);
+  format %{ "loop: \n\t"
+            "LDREX    $tmp1, $mem\n\t"
+            "ADD      $tmp1, $tmp1, $add\n\t"
+            "STREX    $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($tmp1$$Register,$mem$$Address);
+    __ add($tmp1$$Register, $tmp1$$Register, $add$$constant);
+    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddI_reg_no_res(memoryex mem, iRegI add, Universe dummy, iRegI tmp1, iRegI tmp2) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddI mem add));
+  effect(TEMP tmp1, TEMP tmp2);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR_w   $tmp1, $mem\n\t"
+            "ADD_w    $tmp1, $tmp1, $add\n\t"
+            "STXR_w   $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($tmp1$$Register, base);
+    __ add_w($tmp1$$Register, $tmp1$$Register, $add$$Register);
+    __ stxr_w($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddI_reg_no_res(memoryex mem, iRegI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddI mem add));
+  effect(KILL ccr, TEMP tmp1, TEMP tmp2);
+  size(20);
+  format %{ "loop: \n\t"
+            "LDREX    $tmp1, $mem\n\t"
+            "ADD      $tmp1, $tmp1, $add\n\t"
+            "STREX    $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($tmp1$$Register,$mem$$Address);
+    __ add($tmp1$$Register, $tmp1$$Register, $add$$Register);
+    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddI_aimmI(memoryex mem, aimmI add, iRegI res, iRegI tmp1, iRegI tmp2) %{
+  match(Set res (GetAndAddI mem add));
+  effect(TEMP tmp1, TEMP tmp2, TEMP res);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR_w   $res, $mem\n\t"
+            "ADD_w    $tmp1, $res, $add\n\t"
+            "STXR_w   $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($res$$Register, base);
+    __ add_w($tmp1$$Register, $res$$Register, $add$$constant);
+    __ stxr_w($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddI_aimmI(memoryex mem, aimmI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
+  match(Set res (GetAndAddI mem add));
+  effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
+  size(20);
+  format %{ "loop: \n\t"
+            "LDREX    $res, $mem\n\t"
+            "ADD      $tmp1, $res, $add\n\t"
+            "STREX    $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($res$$Register,$mem$$Address);
+    __ add($tmp1$$Register, $res$$Register, $add$$constant);
+    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddI_reg(memoryex mem, iRegI add, iRegI res, iRegI tmp1, iRegI tmp2) %{
+  match(Set res (GetAndAddI mem add));
+  effect(TEMP tmp1, TEMP tmp2, TEMP res);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR_w   $res, $mem\n\t"
+            "ADD_w    $tmp1, $res, $add\n\t"
+            "STXR_w   $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($res$$Register, base);
+    __ add_w($tmp1$$Register, $res$$Register, $add$$Register);
+    __ stxr_w($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddI_reg(memoryex mem, iRegI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
+  match(Set res (GetAndAddI mem add));
+  effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
+  size(20);
+  format %{ "loop: \n\t"
+            "LDREX    $res, $mem\n\t"
+            "ADD      $tmp1, $res, $add\n\t"
+            "STREX    $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($res$$Register,$mem$$Address);
+    __ add($tmp1$$Register, $res$$Register, $add$$Register);
+    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddL_reg_no_res(memoryex mem, iRegL add, Universe dummy, iRegL tmp1, iRegI tmp2) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddL mem add));
+  effect(TEMP tmp1, TEMP tmp2);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR     $tmp1, $mem\n\t"
+            "ADD      $tmp1, $tmp1, $add\n\t"
+            "STXR     $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr($tmp1$$Register, base);
+    __ add($tmp1$$Register, $tmp1$$Register, $add$$Register);
+    __ stxr($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddL_reg_no_res(memoryex mem, iRegL add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddL mem add));
+  effect( KILL ccr, TEMP tmp1, TEMP tmp2);
+  size(24);
+  format %{ "loop: \n\t"
+            "LDREXD   $tmp1, $mem\n\t"
+            "ADDS     $tmp1.lo, $tmp1.lo, $add.lo\n\t"
+            "ADC      $tmp1.hi, $tmp1.hi, $add.hi\n\t"
+            "STREXD   $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($tmp1$$Register, $mem$$Address);
+    __ adds($tmp1$$Register, $tmp1$$Register, $add$$Register);
+    __ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), $add$$Register->successor());
+    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddL_imm_no_res(memoryex mem, aimmL add, Universe dummy, iRegL tmp1, iRegI tmp2) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddL mem add));
+  effect(TEMP tmp1, TEMP tmp2);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR     $tmp1, $mem\n\t"
+            "ADD      $tmp1, $tmp1, $add\n\t"
+            "STXR     $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr($tmp1$$Register, base);
+    __ add($tmp1$$Register, $tmp1$$Register, $add$$constant);
+    __ stxr($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct xaddL_immRot_no_res(memoryex mem, immLlowRot add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
+  predicate(n->as_LoadStore()->result_not_used());
+  match(Set dummy (GetAndAddL mem add));
+  effect( KILL ccr, TEMP tmp1, TEMP tmp2);
+  size(24);
+  format %{ "loop: \n\t"
+            "LDREXD   $tmp1, $mem\n\t"
+            "ADDS     $tmp1.lo, $tmp1.lo, $add\n\t"
+            "ADC      $tmp1.hi, $tmp1.hi, 0\n\t"
+            "STREXD   $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($tmp1$$Register, $mem$$Address);
+    __ adds($tmp1$$Register, $tmp1$$Register, $add$$constant);
+    __ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), 0);
+    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddL_reg(memoryex mem, iRegL add, iRegL res, iRegL tmp1, iRegI tmp2) %{
+  match(Set res (GetAndAddL mem add));
+  effect(TEMP tmp1, TEMP tmp2, TEMP res);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR     $res, $mem\n\t"
+            "ADD      $tmp1, $res, $add\n\t"
+            "STXR     $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr($res$$Register, base);
+    __ add($tmp1$$Register, $res$$Register, $add$$Register);
+    __ stxr($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xaddL_reg(memoryex mem, iRegL add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
+  match(Set res (GetAndAddL mem add));
+  effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
+  size(24);
+  format %{ "loop: \n\t"
+            "LDREXD   $res, $mem\n\t"
+            "ADDS     $tmp1.lo, $res.lo, $add.lo\n\t"
+            "ADC      $tmp1.hi, $res.hi, $add.hi\n\t"
+            "STREXD   $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($res$$Register, $mem$$Address);
+    __ adds($tmp1$$Register, $res$$Register, $add$$Register);
+    __ adc($tmp1$$Register->successor(), $res$$Register->successor(), $add$$Register->successor());
+    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xaddL_imm(memoryex mem, aimmL add, iRegL res, iRegL tmp1, iRegI tmp2) %{
+  match(Set res (GetAndAddL mem add));
+  effect(TEMP tmp1, TEMP tmp2, TEMP res);
+  size(16);
+  format %{ "loop:\n\t"
+            "LDXR     $res, $mem\n\t"
+            "ADD      $tmp1, $res, $add\n\t"
+            "STXR     $tmp2, $tmp1, $mem\n\t"
+            "CBNZ_w   $tmp2, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr($res$$Register, base);
+    __ add($tmp1$$Register, $res$$Register, $add$$constant);
+    __ stxr($tmp2$$Register, $tmp1$$Register, base);
+    __ cbnz_w($tmp2$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct xaddL_immRot(memoryex mem, immLlowRot add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
+  match(Set res (GetAndAddL mem add));
+  effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
+  size(24);
+  format %{ "loop: \n\t"
+            "LDREXD   $res, $mem\n\t"
+            "ADDS     $tmp1.lo, $res.lo, $add\n\t"
+            "ADC      $tmp1.hi, $res.hi, 0\n\t"
+            "STREXD   $tmp2, $tmp1, $mem\n\t"
+            "CMP      $tmp2, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($res$$Register, $mem$$Address);
+    __ adds($tmp1$$Register, $res$$Register, $add$$constant);
+    __ adc($tmp1$$Register->successor(), $res$$Register->successor(), 0);
+    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
+    __ cmp($tmp2$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xchgI(memoryex mem, iRegI newval, iRegI res, iRegI tmp) %{
+  match(Set res (GetAndSetI mem newval));
+  effect(TEMP tmp, TEMP res);
+  size(12);
+  format %{ "loop:\n\t"
+            "LDXR_w   $res, $mem\n\t"
+            "STXR_w   $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($res$$Register, base);
+    __ stxr_w($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+
+#ifdef XXX
+// Disabled until 8051805 is fixed.
+instruct xchgN(memoryex mem, iRegN newval, iRegN res, iRegN tmp) %{
+  match(Set res (GetAndSetN mem newval));
+  effect(TEMP tmp, TEMP res);
+  size(12);
+  format %{ "loop:\n\t"
+            "LDXR_w   $res, $mem\n\t"
+            "STXR_w   $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr_w($res$$Register, base);
+    __ stxr_w($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+#else
+instruct xchgI(memoryex mem, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (GetAndSetI mem newval));
+  effect(KILL ccr, TEMP tmp, TEMP res);
+  size(16);
+  format %{ "loop: \n\t"
+            "LDREX    $res, $mem\n\t"
+            "STREX    $tmp, $newval, $mem\n\t"
+            "CMP      $tmp, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($res$$Register,$mem$$Address);
+    __ strex($tmp$$Register, $newval$$Register, $mem$$Address);
+    __ cmp($tmp$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif
+
+#ifdef AARCH64
+instruct xchgL(memoryex mem, iRegL newval, iRegL res, iRegI tmp) %{
+  match(Set res (GetAndSetL mem newval));
+  effect(TEMP tmp, TEMP res);
+  size(12);
+  format %{ "loop:\n\t"
+            "LDXR     $res, $mem\n\t"
+            "STXR     $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldxr($res$$Register, base);
+    __ stxr($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (GetAndSetL mem newval));
+  effect( KILL ccr, TEMP tmp, TEMP res);
+  size(16);
+  format %{ "loop: \n\t"
+            "LDREXD   $res, $mem\n\t"
+            "STREXD   $tmp, $newval, $mem\n\t"
+            "CMP      $tmp, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrexd($res$$Register, $mem$$Address);
+    __ strexd($tmp$$Register, $newval$$Register, $mem$$Address);
+    __ cmp($tmp$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif // !AARCH64
+
+#ifdef AARCH64
+instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp) %{
+  match(Set res (GetAndSetP mem newval));
+  effect(TEMP tmp, TEMP res);
+  size(12);
+  format %{ "loop:\n\t"
+            "LDREX    $res, $mem\n\t"
+            "STREX    $tmp, $newval, $mem\n\t"
+            "CBNZ_w   $tmp, loop" %}
+
+  ins_encode %{
+    Label loop;
+    Register base = reg_to_register_object($mem$$base);
+    __ bind(loop);
+    __ ldrex($res$$Register, base);
+    __ strex($tmp$$Register, $newval$$Register, base);
+    __ cbnz_w($tmp$$Register, loop);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#else
+instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{
+  match(Set res (GetAndSetP mem newval));
+  effect(KILL ccr, TEMP tmp, TEMP res);
+  size(16);
+  format %{ "loop: \n\t"
+            "LDREX    $res, $mem\n\t"
+            "STREX    $tmp, $newval, $mem\n\t"
+            "CMP      $tmp, 0 \n\t"
+            "B.ne     loop \n\t" %}
+
+  ins_encode %{
+    Label loop;
+    __ bind(loop);
+    __ ldrex($res$$Register,$mem$$Address);
+    __ strex($tmp$$Register, $newval$$Register, $mem$$Address);
+    __ cmp($tmp$$Register, 0);
+    __ b(loop, ne);
+  %}
+  ins_pipe( long_memory_op );
+%}
+#endif // !AARCH64
+
+//---------------------
+// Subtraction Instructions
+// Register Subtraction
+instruct subI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (SubI src1 src2));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct subshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct subshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (SubI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,$src2<<$src3\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct subsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct subsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (SubI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,$src2>>$src3\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct subshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct subshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (SubI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,$src2>>>$src3\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct rsbshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI (LShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1<<$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rsbshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (SubI (LShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1<<$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rsbsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI (RShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1>>$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rsbsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (SubI (RShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1>>$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rsbshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI (URShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1>>>$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rsbshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
+  match(Set dst (SubI (URShiftI src1 src2) src3));
+
+  size(4);
+  format %{ "RSB    $dst,$src3,$src1>>>$src2" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+// Immediate Subtraction
+instruct subI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
+  match(Set dst (SubI src1 src2));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct subI_reg_immRotneg(iRegI dst, iRegI src1, aimmIneg src2) %{
+  match(Set dst (AddI src1 src2));
+
+  size(4);
+  format %{ "sub_32 $dst,$src1,-($src2)\t! int" %}
+  ins_encode %{
+    __ sub_32($dst$$Register, $src1$$Register, -$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+#ifndef AARCH64
+instruct subI_immRot_reg(iRegI dst, immIRot src1, iRegI src2) %{
+  match(Set dst (SubI src1 src2));
+
+  size(4);
+  format %{ "RSB    $dst,$src2,src1" %}
+  ins_encode %{
+    __ rsb($dst$$Register, $src2$$Register, $src1$$constant);
+  %}
+  ins_pipe(ialu_zero_reg);
+%}
+#endif
+
+// Register Subtraction
+#ifdef AARCH64
+instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (SubL src1 src2));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#else
+instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg icc ) %{
+  match(Set dst (SubL src1 src2));
+  effect (KILL icc);
+
+  size(8);
+  format %{ "SUBS   $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
+            "SBC    $dst.hi,$src1.hi,$src2.hi" %}
+  ins_encode %{
+    __ subs($dst$$Register, $src1$$Register, $src2$$Register);
+    __ sbc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+#ifdef AARCH64
+// Immediate Subtraction
+instruct subL_reg_aimm(iRegL dst, iRegL src1, aimmL src2) %{
+  match(Set dst (SubL src1 src2));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct subL_reg_immLneg(iRegL dst, iRegL src1, aimmLneg src2) %{
+  match(Set dst (AddL src1 src2));
+
+  size(4);
+  format %{ "SUB    $dst,$src1,-($src2)\t! long" %}
+  ins_encode %{
+    __ sub($dst$$Register, $src1$$Register, -$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// TODO
+#endif
+
+#ifndef AARCH64
+// Immediate Subtraction
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct subL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg icc) %{
+  match(Set dst (SubL src1 con));
+  effect (KILL icc);
+
+  size(8);
+  format %{ "SUB    $dst.lo,$src1.lo,$con\t! long\n\t"
+            "SBC    $dst.hi,$src1.hi,0" %}
+  ins_encode %{
+    __ subs($dst$$Register, $src1$$Register, $con$$constant);
+    __ sbc($dst$$Register->successor(), $src1$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+// Long negation
+instruct negL_reg_reg(iRegL dst, immL0 zero, iRegL src2, flagsReg icc) %{
+  match(Set dst (SubL zero src2));
+  effect (KILL icc);
+
+  size(8);
+  format %{ "RSBS   $dst.lo,$src2.lo,0\t! long\n\t"
+            "RSC    $dst.hi,$src2.hi,0" %}
+  ins_encode %{
+    __ rsbs($dst$$Register, $src2$$Register, 0);
+    __ rsc($dst$$Register->successor(), $src2$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_zero_reg);
+%}
+#endif // !AARCH64
+
+// Multiplication Instructions
+// Integer Multiplication
+// Register Multiplication
+instruct mulI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (MulI src1 src2));
+
+  size(4);
+  format %{ "mul_32 $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mul_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(imul_reg_reg);
+%}
+
+#ifdef AARCH64
+instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (MulL src1 src2));
+  size(4);
+  format %{ "MUL  $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ mul($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(imul_reg_reg);
+%}
+#else
+instruct mulL_lo1_hi2(iRegL dst, iRegL src1, iRegL src2) %{
+  effect(DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "MUL  $dst.hi,$src1.lo,$src2.hi\t! long" %}
+  ins_encode %{
+    __ mul($dst$$Register->successor(), $src1$$Register, $src2$$Register->successor());
+  %}
+  ins_pipe(imul_reg_reg);
+%}
+
+instruct mulL_hi1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(8);
+  format %{ "MLA  $dst.hi,$src1.hi,$src2.lo,$dst.hi\t! long\n\t"
+            "MOV  $dst.lo, 0"%}
+  ins_encode %{
+    __ mla($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register, $dst$$Register->successor());
+    __ mov($dst$$Register, 0);
+  %}
+  ins_pipe(imul_reg_reg);
+%}
+
+instruct mulL_lo1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "UMLAL  $dst.lo,$dst.hi,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ umlal($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(imul_reg_reg);
+%}
+
+instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (MulL src1 src2));
+
+  expand %{
+    mulL_lo1_hi2(dst, src1, src2);
+    mulL_hi1_lo2(dst, src1, src2);
+    mulL_lo1_lo2(dst, src1, src2);
+  %}
+%}
+#endif // !AARCH64
+
+// Integer Division
+// Register Division
+#ifdef AARCH64
+instruct divI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (DivI src1 src2));
+
+  size(4);
+  format %{ "SDIV    $dst,$src1,$src2\t! 32-bit" %}
+  ins_encode %{
+    __ sdiv_w($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+#else
+instruct divI_reg_reg(R1RegI dst, R0RegI src1, R2RegI src2, LRRegP lr, flagsReg ccr) %{
+  match(Set dst (DivI src1 src2));
+  effect( KILL ccr, KILL src1, KILL src2, KILL lr);
+  ins_cost((2+71)*DEFAULT_COST);
+
+  format %{ "DIV   $dst,$src1,$src2 ! call to StubRoutines::Arm::idiv_irem_entry()" %}
+  ins_encode %{
+    __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
+  %}
+  ins_pipe(sdiv_reg_reg);
+%}
+#endif
+
+// Register Long Division
+#ifdef AARCH64
+instruct divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (DivL src1 src2));
+
+  size(4);
+  format %{ "SDIV    $dst,$src1,$src2" %}
+  ins_encode %{
+    __ sdiv($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+#else
+instruct divL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
+  match(Set dst (DivL src1 src2));
+  effect(CALL);
+  ins_cost(DEFAULT_COST*71);
+  format %{ "DIVL  $src1,$src2,$dst\t! long ! call to SharedRuntime::ldiv" %}
+  ins_encode %{
+    address target = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv);
+    __ call(target, relocInfo::runtime_call_type);
+  %}
+  ins_pipe(divL_reg_reg);
+%}
+#endif
+
+// Integer Remainder
+// Register Remainder
+#ifdef AARCH64
+#ifdef TODO
+instruct msubI_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (SubI src1 (MulI src2 src3)));
+
+  size(4);
+  format %{ "MSUB    $dst,$src2,$src3,$src1\t! 32-bit\n\t" %}
+  ins_encode %{
+    __ msub_w($dst$$Register, $src2$$Register, $src3$$Register, $src1$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+#endif
+
+instruct modI_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp) %{
+  match(Set dst (ModI src1 src2));
+  effect(TEMP temp);
+
+  size(8);
+  format %{ "SDIV    $temp,$src1,$src2\t! 32-bit\n\t"
+            "MSUB    $dst,$src2,$temp,$src1\t! 32-bit\n\t" %}
+  ins_encode %{
+    __ sdiv_w($temp$$Register, $src1$$Register, $src2$$Register);
+    __ msub_w($dst$$Register, $src2$$Register, $temp$$Register, $src1$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+#else
+instruct modI_reg_reg(R0RegI dst, R0RegI src1, R2RegI src2, R1RegI temp, LRRegP lr, flagsReg ccr ) %{
+  match(Set dst (ModI src1 src2));
+  effect( KILL ccr, KILL temp, KILL src2, KILL lr);
+
+  format %{ "MODI   $dst,$src1,$src2\t ! call to StubRoutines::Arm::idiv_irem_entry" %}
+  ins_encode %{
+    __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
+  %}
+  ins_pipe(sdiv_reg_reg);
+%}
+#endif
+
+// Register Long Remainder
+#ifdef AARCH64
+instruct modL_reg_reg(iRegL dst, iRegL src1, iRegL src2, iRegL temp) %{
+  match(Set dst (ModL src1 src2));
+  effect(TEMP temp);
+
+  size(8);
+  format %{ "SDIV    $temp,$src1,$src2\n\t"
+            "MSUB    $dst,$src2,$temp,$src1" %}
+  ins_encode %{
+    __ sdiv($temp$$Register, $src1$$Register, $src2$$Register);
+    __ msub($dst$$Register, $src2$$Register, $temp$$Register, $src1$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+#else
+instruct modL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
+  match(Set dst (ModL src1 src2));
+  effect(CALL);
+  ins_cost(MEMORY_REF_COST); // FIXME
+  format %{ "modL    $dst,$src1,$src2\t ! call to SharedRuntime::lrem" %}
+  ins_encode %{
+    address target = CAST_FROM_FN_PTR(address, SharedRuntime::lrem);
+    __ call(target, relocInfo::runtime_call_type);
+  %}
+  ins_pipe(divL_reg_reg);
+%}
+#endif
+
+// Integer Shift Instructions
+
+// Register Shift Left
+instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (LShiftI src1 src2));
+
+  size(4);
+#ifdef AARCH64
+  format %{ "LSLV   $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ lslv_w($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  format %{ "LSL  $dst,$src1,$src2 \n\t" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Register Shift Left Immediate
+instruct shlI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
+  match(Set dst (LShiftI src1 src2));
+
+  size(4);
+#ifdef AARCH64
+  format %{ "LSL_w  $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ _lsl($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+#else
+  format %{ "LSL    $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+#endif
+  ins_pipe(ialu_reg_imm);
+%}
+
+#ifndef AARCH64
+instruct shlL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{"OR  $dst.hi,$dst.hi,($src1.hi << $src2)"  %}
+  ins_encode %{
+    __ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct shlL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "LSL  $dst.lo,$src1.lo,$src2 \n\t" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct shlL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
+  effect(DEF dst, USE src1, USE src2, KILL ccr);
+  size(16);
+  format %{ "SUBS  $dst.hi,$src2,32 \n\t"
+            "LSLpl $dst.hi,$src1.lo,$dst.hi \n\t"
+            "RSBmi $dst.hi,$dst.hi,0 \n\t"
+            "LSRmi $dst.hi,$src1.lo,$dst.hi" %}
+
+  ins_encode %{
+    // $src1$$Register and $dst$$Register->successor() can't be the same
+    __ subs($dst$$Register->successor(), $src2$$Register, 32);
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $dst$$Register->successor()), pl);
+    __ rsb($dst$$Register->successor(), $dst$$Register->successor(), 0, mi);
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsr, $dst$$Register->successor()), mi);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif // !AARCH64
+
+instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
+  match(Set dst (LShiftL src1 src2));
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LSLV  $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ lslv($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+#else
+  expand %{
+    flagsReg ccr;
+    shlL_reg_reg_overlap(dst, src1, src2, ccr);
+    shlL_reg_reg_merge_hi(dst, src1, src2);
+    shlL_reg_reg_merge_lo(dst, src1, src2);
+  %}
+#endif
+%}
+
+#ifdef AARCH64
+instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
+  match(Set dst (LShiftL src1 src2));
+
+  size(4);
+  format %{ "LSL    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// Register Shift Left Immediate
+instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
+  match(Set dst (LShiftL src1 src2));
+
+  size(8);
+  format %{ "LSL   $dst.hi,$src1.lo,$src2-32\t! or mov if $src2==32\n\t"
+            "MOV   $dst.lo, 0" %}
+  ins_encode %{
+    if ($src2$$constant == 32) {
+      __ mov($dst$$Register->successor(), $src1$$Register);
+    } else {
+      __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $src2$$constant-32));
+    }
+    __ mov($dst$$Register, 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct shlL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
+  match(Set dst (LShiftL src1 src2));
+
+  size(12);
+  format %{ "LSL   $dst.hi,$src1.lo,$src2\n\t"
+            "OR    $dst.hi, $dst.hi, $src1.lo >> 32-$src2\n\t"
+            "LSL   $dst.lo,$src1.lo,$src2" %}
+  ins_encode %{
+    // The order of the following 3 instructions matters: src1.lo and
+    // dst.hi can't overlap but src.hi and dst.hi can.
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$constant));
+    __ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register, lsr, 32-$src2$$constant));
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif // !AARCH64
+
+// Register Arithmetic Shift Right
+instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (RShiftI src1 src2));
+  size(4);
+#ifdef AARCH64
+  format %{ "ASRV   $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ asrv_w($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  format %{ "ASR    $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Register Arithmetic Shift Right Immediate
+instruct sarI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
+  match(Set dst (RShiftI src1 src2));
+
+  size(4);
+#ifdef AARCH64
+  format %{ "ASR_w  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ _asr_w($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+#else
+  format %{ "ASR    $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
+  %}
+#endif
+  ins_pipe(ialu_reg_imm);
+%}
+
+#ifndef AARCH64
+// Register Shift Right Arithmetic Long
+instruct sarL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "OR  $dst.lo,$dst.lo,($src1.lo >> $src2)"  %}
+  ins_encode %{
+    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct sarL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "ASR  $dst.hi,$src1.hi,$src2 \n\t" %}
+  ins_encode %{
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct sarL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
+  effect(DEF dst, USE src1, USE src2, KILL ccr);
+  size(16);
+  format %{ "SUBS  $dst.lo,$src2,32 \n\t"
+            "ASRpl $dst.lo,$src1.hi,$dst.lo \n\t"
+            "RSBmi $dst.lo,$dst.lo,0 \n\t"
+            "LSLmi $dst.lo,$src1.hi,$dst.lo" %}
+
+  ins_encode %{
+    // $src1$$Register->successor() and $dst$$Register can't be the same
+    __ subs($dst$$Register, $src2$$Register, 32);
+    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $dst$$Register), pl);
+    __ rsb($dst$$Register, $dst$$Register, 0, mi);
+    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif // !AARCH64
+
+instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
+  match(Set dst (RShiftL src1 src2));
+
+#ifdef AARCH64
+  size(4);
+  format %{ "ASRV  $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ asrv($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+#else
+  expand %{
+    flagsReg ccr;
+    sarL_reg_reg_overlap(dst, src1, src2, ccr);
+    sarL_reg_reg_merge_lo(dst, src1, src2);
+    sarL_reg_reg_merge_hi(dst, src1, src2);
+  %}
+#endif
+%}
+
+// Register Shift Left Immediate
+#ifdef AARCH64
+instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
+  match(Set dst (RShiftL src1 src2));
+
+  size(4);
+  format %{ "ASR    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ _asr($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
+  match(Set dst (RShiftL src1 src2));
+
+  size(8);
+  format %{ "ASR   $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
+            "ASR   $dst.hi,$src1.hi, $src2" %}
+  ins_encode %{
+    if ($src2$$constant == 32) {
+      __ mov($dst$$Register, $src1$$Register->successor());
+    } else{
+      __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $src2$$constant-32));
+    }
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, 0));
+  %}
+
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct sarL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
+  match(Set dst (RShiftL src1 src2));
+  size(12);
+  format %{ "LSR   $dst.lo,$src1.lo,$src2\n\t"
+            "OR    $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
+            "ASR   $dst.hi,$src1.hi,$src2" %}
+  ins_encode %{
+    // The order of the following 3 instructions matters: src1.lo and
+    // dst.hi can't overlap but src.hi and dst.hi can.
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
+    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+// Register Shift Right
+instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (URShiftI src1 src2));
+  size(4);
+#ifdef AARCH64
+  format %{ "LSRV   $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ lsrv_w($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  format %{ "LSR    $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Register Shift Right Immediate
+instruct shrI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
+  match(Set dst (URShiftI src1 src2));
+
+  size(4);
+#ifdef AARCH64
+  format %{ "LSR_w  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ _lsr_w($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+#else
+  format %{ "LSR    $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
+  %}
+#endif
+  ins_pipe(ialu_reg_imm);
+%}
+
+#ifndef AARCH64
+// Register Shift Right
+instruct shrL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "OR   $dst.lo,$dst,($src1.lo >>> $src2)"  %}
+  ins_encode %{
+    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct shrL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
+  effect(USE_DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "LSR  $dst.hi,$src1.hi,$src2 \n\t" %}
+  ins_encode %{
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct shrL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
+  effect(DEF dst, USE src1, USE src2, KILL ccr);
+  size(16);
+  format %{ "SUBS  $dst,$src2,32 \n\t"
+            "LSRpl $dst,$src1.hi,$dst \n\t"
+            "RSBmi $dst,$dst,0 \n\t"
+            "LSLmi $dst,$src1.hi,$dst" %}
+
+  ins_encode %{
+    // $src1$$Register->successor() and $dst$$Register can't be the same
+    __ subs($dst$$Register, $src2$$Register, 32);
+    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $dst$$Register), pl);
+    __ rsb($dst$$Register, $dst$$Register, 0, mi);
+    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif // !AARCH64
+
+instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
+  match(Set dst (URShiftL src1 src2));
+
+#ifdef AARCH64
+  size(4);
+  format %{ "LSRV  $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ lsrv($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+#else
+  expand %{
+    flagsReg ccr;
+    shrL_reg_reg_overlap(dst, src1, src2, ccr);
+    shrL_reg_reg_merge_lo(dst, src1, src2);
+    shrL_reg_reg_merge_hi(dst, src1, src2);
+  %}
+#endif
+%}
+
+// Register Shift Right Immediate
+#ifdef AARCH64
+instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
+  match(Set dst (URShiftL src1 src2));
+
+  size(4);
+  format %{ "LSR    $dst,$src1,$src2" %}
+  ins_encode %{
+    __ _lsr($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
+  match(Set dst (URShiftL src1 src2));
+
+  size(8);
+  format %{ "LSR   $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
+            "MOV   $dst.hi, 0" %}
+  ins_encode %{
+    if ($src2$$constant == 32) {
+      __ mov($dst$$Register, $src1$$Register->successor());
+    } else {
+      __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $src2$$constant-32));
+    }
+    __ mov($dst$$Register->successor(), 0);
+  %}
+
+  ins_pipe(ialu_reg_imm);
+%}
+
+instruct shrL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
+  match(Set dst (URShiftL src1 src2));
+
+  size(12);
+  format %{ "LSR   $dst.lo,$src1.lo,$src2\n\t"
+            "OR    $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
+            "LSR   $dst.hi,$src1.hi,$src2" %}
+  ins_encode %{
+    // The order of the following 3 instructions matters: src1.lo and
+    // dst.hi can't overlap but src.hi and dst.hi can.
+    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
+    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
+    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$constant));
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif // !AARCH64
+
+
+instruct shrP_reg_imm5(iRegX dst, iRegP src1, immU5 src2) %{
+  match(Set dst (URShiftI (CastP2X src1) src2));
+  size(4);
+  format %{ "LSR    $dst,$src1,$src2\t! Cast ptr $src1 to int and shift" %}
+  ins_encode %{
+    __ logical_shift_right($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+//----------Floating Point Arithmetic Instructions-----------------------------
+
+//  Add float single precision
+instruct addF_reg_reg(regF dst, regF src1, regF src2) %{
+  match(Set dst (AddF src1 src2));
+
+  size(4);
+  format %{ "FADDS  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(faddF_reg_reg);
+%}
+
+//  Add float double precision
+instruct addD_reg_reg(regD dst, regD src1, regD src2) %{
+  match(Set dst (AddD src1 src2));
+
+  size(4);
+  format %{ "FADDD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(faddD_reg_reg);
+%}
+
+//  Sub float single precision
+instruct subF_reg_reg(regF dst, regF src1, regF src2) %{
+  match(Set dst (SubF src1 src2));
+
+  size(4);
+  format %{ "FSUBS  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ sub_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(faddF_reg_reg);
+%}
+
+//  Sub float double precision
+instruct subD_reg_reg(regD dst, regD src1, regD src2) %{
+  match(Set dst (SubD src1 src2));
+
+  size(4);
+  format %{ "FSUBD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg_reg);
+%}
+
+//  Mul float single precision
+instruct mulF_reg_reg(regF dst, regF src1, regF src2) %{
+  match(Set dst (MulF src1 src2));
+
+  size(4);
+  format %{ "FMULS  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(fmulF_reg_reg);
+%}
+
+//  Mul float double precision
+instruct mulD_reg_reg(regD dst, regD src1, regD src2) %{
+  match(Set dst (MulD src1 src2));
+
+  size(4);
+  format %{ "FMULD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(fmulD_reg_reg);
+%}
+
+//  Div float single precision
+instruct divF_reg_reg(regF dst, regF src1, regF src2) %{
+  match(Set dst (DivF src1 src2));
+
+  size(4);
+  format %{ "FDIVS  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(fdivF_reg_reg);
+%}
+
+//  Div float double precision
+instruct divD_reg_reg(regD dst, regD src1, regD src2) %{
+  match(Set dst (DivD src1 src2));
+
+  size(4);
+  format %{ "FDIVD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ div_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+
+  ins_pipe(fdivD_reg_reg);
+%}
+
+//  Absolute float double precision
+instruct absD_reg(regD dst, regD src) %{
+  match(Set dst (AbsD src));
+
+  size(4);
+  format %{ "FABSd  $dst,$src" %}
+  ins_encode %{
+    __ abs_double($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg);
+%}
+
+//  Absolute float single precision
+instruct absF_reg(regF dst, regF src) %{
+  match(Set dst (AbsF src));
+  format %{ "FABSs  $dst,$src" %}
+  ins_encode %{
+    __ abs_float($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(faddF_reg);
+%}
+
+instruct negF_reg(regF dst, regF src) %{
+  match(Set dst (NegF src));
+
+  size(4);
+  format %{ "FNEGs  $dst,$src" %}
+  ins_encode %{
+    __ neg_float($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(faddF_reg);
+%}
+
+instruct negD_reg(regD dst, regD src) %{
+  match(Set dst (NegD src));
+
+  format %{ "FNEGd  $dst,$src" %}
+  ins_encode %{
+    __ neg_double($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg);
+%}
+
+//  Sqrt float double precision
+instruct sqrtF_reg_reg(regF dst, regF src) %{
+  match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
+
+  size(4);
+  format %{ "FSQRTS $dst,$src" %}
+  ins_encode %{
+    __ sqrt_float($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(fdivF_reg_reg);
+%}
+
+//  Sqrt float double precision
+instruct sqrtD_reg_reg(regD dst, regD src) %{
+  match(Set dst (SqrtD src));
+
+  size(4);
+  format %{ "FSQRTD $dst,$src" %}
+  ins_encode %{
+    __ sqrt_double($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(fdivD_reg_reg);
+%}
+
+//----------Logical Instructions-----------------------------------------------
+// And Instructions
+// Register And
+instruct andI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (AndI src1 src2));
+
+  size(4);
+  format %{ "and_32 $dst,$src1,$src2" %}
+  ins_encode %{
+    __ and_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct andshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AndI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "AND    $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct andshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (AndI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "and_32 $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct andsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AndI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "AND    $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct andsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (AndI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "and_32 $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct andshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (AndI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "AND    $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct andshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (AndI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "and_32 $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Immediate And
+instruct andI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
+  match(Set dst (AndI src1 src2));
+
+  size(4);
+  format %{ "and_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ and_32($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+#ifndef AARCH64
+instruct andI_reg_limmn(iRegI dst, iRegI src1, limmIn src2) %{
+  match(Set dst (AndI src1 src2));
+
+  size(4);
+  format %{ "bic    $dst,$src1,~$src2\t! int" %}
+  ins_encode %{
+    __ bic($dst$$Register, $src1$$Register, ~$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+// Register And Long
+instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (AndL src1 src2));
+
+  ins_cost(DEFAULT_COST);
+#ifdef AARCH64
+  size(4);
+  format %{ "AND    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  size(8);
+  format %{ "AND    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, $src2$$Register);
+    __ andr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifdef AARCH64
+// Immediate And
+instruct andL_reg_limm(iRegL dst, iRegL src1, limmL src2) %{
+  match(Set dst (AndL src1 src2));
+
+  size(4);
+  format %{ "AND    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, (uintx)$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct andL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
+  match(Set dst (AndL src1 con));
+  ins_cost(DEFAULT_COST);
+  size(8);
+  format %{ "AND    $dst,$src1,$con\t! long" %}
+  ins_encode %{
+    __ andr($dst$$Register, $src1$$Register, $con$$constant);
+    __ andr($dst$$Register->successor(), $src1$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+// Or Instructions
+// Register Or
+instruct orI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (OrI src1 src2));
+
+  size(4);
+  format %{ "orr_32 $dst,$src1,$src2\t! int" %}
+  ins_encode %{
+    __ orr_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct orshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (OrI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "OR    $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct orshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (OrI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "orr_32 $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct orsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (OrI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "OR    $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct orsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (OrI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "orr_32 $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct orshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (OrI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "OR    $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct orshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (OrI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "orr_32 $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Immediate Or
+instruct orI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
+  match(Set dst (OrI src1 src2));
+
+  size(4);
+  format %{ "orr_32  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ orr_32($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+// TODO: orn_32 with limmIn
+
+// Register Or Long
+instruct orL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (OrL src1 src2));
+
+  ins_cost(DEFAULT_COST);
+#ifdef AARCH64
+  size(4);
+  format %{ "OR     $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  size(8);
+  format %{ "OR     $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
+            "OR     $dst.hi,$src1.hi,$src2.hi" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, $src2$$Register);
+    __ orr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifdef AARCH64
+instruct orL_reg_limm(iRegL dst, iRegL src1, limmL src2) %{
+  match(Set dst (OrL src1 src2));
+
+  size(4);
+  format %{ "ORR    $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, (uintx)$src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct orL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
+  match(Set dst (OrL src1 con));
+  ins_cost(DEFAULT_COST);
+  size(8);
+  format %{ "OR     $dst.lo,$src1.lo,$con\t! long\n\t"
+            "OR     $dst.hi,$src1.hi,$con" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, $con$$constant);
+    __ orr($dst$$Register->successor(), $src1$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+#ifdef TODO
+// Use SPRegP to match Rthread (TLS register) without spilling.
+// Use store_ptr_RegP to match Rthread (TLS register) without spilling.
+// Use sp_ptr_RegP to match Rthread (TLS register) without spilling.
+instruct orI_reg_castP2X(iRegI dst, iRegI src1, sp_ptr_RegP src2) %{
+  match(Set dst (OrI src1 (CastP2X src2)));
+  size(4);
+  format %{ "OR     $dst,$src1,$src2" %}
+  ins_encode %{
+    __ orr($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+// Xor Instructions
+// Register Xor
+instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
+  match(Set dst (XorI src1 src2));
+
+  size(4);
+  format %{ "eor_32 $dst,$src1,$src2" %}
+  ins_encode %{
+    __ eor_32($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct xorshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (XorI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "XOR    $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct xorshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (XorI src1 (LShiftI src2 src3)));
+
+  size(4);
+  format %{ "eor_32 $dst,$src1,$src2<<$src3" %}
+  ins_encode %{
+    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct xorsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (XorI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "XOR    $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct xorsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (XorI src1 (RShiftI src2 src3)));
+
+  size(4);
+  format %{ "eor_32 $dst,$src1,$src2>>$src3" %}
+  ins_encode %{
+    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifndef AARCH64
+instruct xorshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
+  match(Set dst (XorI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "XOR    $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+#endif
+
+instruct xorshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
+  match(Set dst (XorI src1 (URShiftI src2 src3)));
+
+  size(4);
+  format %{ "eor_32 $dst,$src1,$src2>>>$src3" %}
+  ins_encode %{
+    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Immediate Xor
+instruct xorI_reg_imm(iRegI dst, iRegI src1, limmI src2) %{
+  match(Set dst (XorI src1 src2));
+
+  size(4);
+  format %{ "eor_32 $dst,$src1,$src2" %}
+  ins_encode %{
+    __ eor_32($dst$$Register, $src1$$Register, $src2$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+
+// Register Xor Long
+instruct xorL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
+  match(Set dst (XorL src1 src2));
+  ins_cost(DEFAULT_COST);
+#ifdef AARCH64
+  size(4);
+  format %{ "XOR     $dst,$src1,$src2\t! long" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, $src2$$Register);
+  %}
+#else
+  size(8);
+  format %{ "XOR     $dst.hi,$src1.hi,$src2.hi\t! long\n\t"
+            "XOR     $dst.lo,$src1.lo,$src2.lo\t! long" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, $src2$$Register);
+    __ eor($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+#ifdef AARCH64
+instruct xorL_reg_limmL(iRegL dst, iRegL src1, limmL con) %{
+  match(Set dst (XorL src1 con));
+  ins_cost(DEFAULT_COST);
+  size(4);
+  format %{ "EOR     $dst,$src1,$con\t! long" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, (uintx)$con$$constant);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#else
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct xorL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
+  match(Set dst (XorL src1 con));
+  ins_cost(DEFAULT_COST);
+  size(8);
+  format %{ "XOR     $dst.hi,$src1.hi,$con\t! long\n\t"
+            "XOR     $dst.lo,$src1.lo,0\t! long" %}
+  ins_encode %{
+    __ eor($dst$$Register, $src1$$Register, $con$$constant);
+    __ eor($dst$$Register->successor(), $src1$$Register->successor(), 0);
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif // AARCH64
+
+//----------Convert to Boolean-------------------------------------------------
+instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{
+  match(Set dst (Conv2B src));
+  effect(KILL ccr);
+#ifdef AARCH64
+  size(8);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "cmp_32 $src,ZR\n\t"
+            "cset_w $dst, ne" %}
+  ins_encode %{
+    __ cmp_32($src$$Register, ZR);
+    __ cset_w($dst$$Register, ne);
+  %}
+#else
+  size(12);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "TST    $src,$src \n\t"
+            "MOV    $dst, 0   \n\t"
+            "MOV.ne $dst, 1" %}
+  ins_encode %{ // FIXME: can do better?
+    __ tst($src$$Register, $src$$Register);
+    __ mov($dst$$Register, 0);
+    __ mov($dst$$Register, 1, ne);
+  %}
+#endif
+  ins_pipe(ialu_reg_ialu);
+%}
+
+instruct convP2B( iRegI dst, iRegP src, flagsReg ccr ) %{
+  match(Set dst (Conv2B src));
+  effect(KILL ccr);
+#ifdef AARCH64
+  size(8);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "CMP    $src,ZR\n\t"
+            "cset   $dst, ne" %}
+  ins_encode %{
+    __ cmp($src$$Register, ZR);
+    __ cset($dst$$Register, ne);
+  %}
+#else
+  size(12);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "TST    $src,$src \n\t"
+            "MOV    $dst, 0   \n\t"
+            "MOV.ne $dst, 1" %}
+  ins_encode %{
+    __ tst($src$$Register, $src$$Register);
+    __ mov($dst$$Register, 0);
+    __ mov($dst$$Register, 1, ne);
+  %}
+#endif
+  ins_pipe(ialu_reg_ialu);
+%}
+
+instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{
+  match(Set dst (CmpLTMask p q));
+  effect( KILL ccr );
+#ifdef AARCH64
+  size(8);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "CMP_w   $p,$q\n\t"
+            "CSETM_w $dst, lt" %}
+  ins_encode %{
+    __ cmp_w($p$$Register, $q$$Register);
+    __ csetm_w($dst$$Register, lt);
+  %}
+#else
+  ins_cost(DEFAULT_COST*3);
+  format %{ "CMP    $p,$q\n\t"
+            "MOV    $dst, #0\n\t"
+            "MOV.lt $dst, #-1" %}
+  ins_encode %{
+    __ cmp($p$$Register, $q$$Register);
+    __ mov($dst$$Register, 0);
+    __ mvn($dst$$Register, 0, lt);
+  %}
+#endif
+  ins_pipe(ialu_reg_reg_ialu);
+%}
+
+instruct cmpLTMask_reg_imm( iRegI dst, iRegI p, aimmI q, flagsReg ccr ) %{
+  match(Set dst (CmpLTMask p q));
+  effect( KILL ccr );
+#ifdef AARCH64
+  size(8);
+  ins_cost(DEFAULT_COST*2);
+  format %{ "CMP_w   $p,$q\n\t"
+            "CSETM_w $dst, lt" %}
+  ins_encode %{
+    __ cmp_w($p$$Register, $q$$constant);
+    __ csetm_w($dst$$Register, lt);
+  %}
+#else
+  ins_cost(DEFAULT_COST*3);
+  format %{ "CMP    $p,$q\n\t"
+            "MOV    $dst, #0\n\t"
+            "MOV.lt $dst, #-1" %}
+  ins_encode %{
+    __ cmp($p$$Register, $q$$constant);
+    __ mov($dst$$Register, 0);
+    __ mvn($dst$$Register, 0, lt);
+  %}
+#endif
+  ins_pipe(ialu_reg_reg_ialu);
+%}
+
+#ifdef AARCH64
+instruct cadd_cmpLTMask3( iRegI dst, iRegI p, iRegI q, iRegI y, iRegI x, flagsReg ccr ) %{
+  match(Set dst (AddI (AndI (CmpLTMask p q) y) x));
+  effect( TEMP dst, KILL ccr );
+  size(12);
+  ins_cost(DEFAULT_COST*3);
+  format %{ "CMP_w  $p,$q\n\t"
+            "ADD_w  $dst,$y,$x\n\t"
+            "CSEL_w $dst,$dst,$x,lt" %}
+  ins_encode %{
+    __ cmp_w($p$$Register, $q$$Register);
+    __ add_w($dst$$Register, $y$$Register, $x$$Register);
+    __ csel_w($dst$$Register, $dst$$Register, $x$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask );
+%}
+#else
+instruct cadd_cmpLTMask3( iRegI p, iRegI q, iRegI y, iRegI z, flagsReg ccr ) %{
+  match(Set z (AddI (AndI (CmpLTMask p q) y) z));
+  effect( KILL ccr );
+  ins_cost(DEFAULT_COST*2);
+  format %{ "CMP    $p,$q\n\t"
+            "ADD.lt $z,$y,$z" %}
+  ins_encode %{
+    __ cmp($p$$Register, $q$$Register);
+    __ add($z$$Register, $y$$Register, $z$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask );
+%}
+#endif
+
+#ifdef AARCH64
+instruct cadd_cmpLTMask4( iRegI dst, iRegI p, aimmI q, iRegI y, iRegI x, flagsReg ccr ) %{
+  match(Set dst (AddI (AndI (CmpLTMask p q) y) x));
+  effect( TEMP dst, KILL ccr );
+  size(12);
+  ins_cost(DEFAULT_COST*3);
+  format %{ "CMP_w  $p,$q\n\t"
+            "ADD_w  $dst,$y,$x\n\t"
+            "CSEL_w $dst,$dst,$x,lt" %}
+  ins_encode %{
+    __ cmp_w($p$$Register, $q$$constant);
+    __ add_w($dst$$Register, $y$$Register, $x$$Register);
+    __ csel_w($dst$$Register, $dst$$Register, $x$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask );
+%}
+#else
+// FIXME: remove unused "dst"
+instruct cadd_cmpLTMask4( iRegI dst, iRegI p, aimmI q, iRegI y, iRegI z, flagsReg ccr ) %{
+  match(Set z (AddI (AndI (CmpLTMask p q) y) z));
+  effect( KILL ccr );
+  ins_cost(DEFAULT_COST*2);
+  format %{ "CMP    $p,$q\n\t"
+            "ADD.lt $z,$y,$z" %}
+  ins_encode %{
+    __ cmp($p$$Register, $q$$constant);
+    __ add($z$$Register, $y$$Register, $z$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask );
+%}
+#endif // !AARCH64
+
+#ifdef AARCH64
+instruct cadd_cmpLTMask( iRegI dst, iRegI p, iRegI q, iRegI y, flagsReg ccr ) %{
+  match(Set dst (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
+  effect( TEMP dst, KILL ccr );
+  size(12);
+  ins_cost(DEFAULT_COST*3);
+  format %{ "SUBS_w $p,$p,$q\n\t"
+            "ADD_w  $dst,$y,$p\n\t"
+            "CSEL_w $dst,$dst,$p,lt" %}
+  ins_encode %{
+    __ subs_w($p$$Register, $p$$Register, $q$$Register);
+    __ add_w($dst$$Register, $y$$Register, $p$$Register);
+    __ csel_w($dst$$Register, $dst$$Register, $p$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask ); // FIXME
+%}
+#else
+instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, flagsReg ccr ) %{
+  match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
+  effect( KILL ccr );
+  ins_cost(DEFAULT_COST*2);
+  format %{ "SUBS   $p,$p,$q\n\t"
+            "ADD.lt $p,$y,$p" %}
+  ins_encode %{
+    __ subs($p$$Register, $p$$Register, $q$$Register);
+    __ add($p$$Register, $y$$Register, $p$$Register, lt);
+  %}
+  ins_pipe( cadd_cmpltmask );
+%}
+#endif
+
+//----------Arithmetic Conversion Instructions---------------------------------
+// The conversions operations are all Alpha sorted.  Please keep it that way!
+
+instruct convD2F_reg(regF dst, regD src) %{
+  match(Set dst (ConvD2F src));
+  size(4);
+  format %{ "FCVTSD  $dst,$src" %}
+  ins_encode %{
+    __ convert_d2f($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtD2F);
+%}
+
+// Convert a double to an int in a float register.
+// If the double is a NAN, stuff a zero in instead.
+
+#ifdef AARCH64
+instruct convD2I_reg_reg(iRegI dst, regD src) %{
+  match(Set dst (ConvD2I src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  format %{ "FCVTZS_wd $dst, $src" %}
+  ins_encode %{
+    __ fcvtzs_wd($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtD2I);
+%}
+
+instruct convD2L_reg_reg(iRegL dst, regD src) %{
+  match(Set dst (ConvD2L src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  format %{ "FCVTZS_xd $dst, $src" %}
+  ins_encode %{
+    __ fcvtzs_xd($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtD2L);
+%}
+#else
+instruct convD2I_reg_reg(iRegI dst, regD src, regF tmp) %{
+  match(Set dst (ConvD2I src));
+  effect( TEMP tmp );
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  format %{ "FTOSIZD  $tmp,$src\n\t"
+            "FMRS     $dst, $tmp" %}
+  ins_encode %{
+    __ ftosizd($tmp$$FloatRegister, $src$$FloatRegister);
+    __ fmrs($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(fcvtD2I);
+%}
+#endif
+
+// Convert a double to a long in a double register.
+// If the double is a NAN, stuff a zero in instead.
+
+#ifndef AARCH64
+// Double to Long conversion
+instruct convD2L_reg(R0R1RegL dst, regD src) %{
+  match(Set dst (ConvD2L src));
+  effect(CALL);
+  ins_cost(MEMORY_REF_COST); // FIXME
+  format %{ "convD2L    $dst,$src\t ! call to SharedRuntime::d2l" %}
+  ins_encode %{
+#ifndef __ABI_HARD__
+    __ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
+#else
+    if ($src$$FloatRegister != D0) {
+      __ mov_double(D0, $src$$FloatRegister);
+    }
+#endif
+    address target = CAST_FROM_FN_PTR(address, SharedRuntime::d2l);
+    __ call(target, relocInfo::runtime_call_type);
+  %}
+  ins_pipe(fcvtD2L);
+%}
+#endif
+
+instruct convF2D_reg(regD dst, regF src) %{
+  match(Set dst (ConvF2D src));
+  size(4);
+  format %{ "FCVTDS  $dst,$src" %}
+  ins_encode %{
+    __ convert_f2d($dst$$FloatRegister, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtF2D);
+%}
+
+#ifdef AARCH64
+instruct convF2I_reg_reg(iRegI dst, regF src) %{
+  match(Set dst (ConvF2I src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  size(4);
+  format %{ "FCVTZS_ws $dst, $src" %}
+  ins_encode %{
+    __ fcvtzs_ws($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtF2I);
+%}
+
+instruct convF2L_reg_reg(iRegL dst, regF src) %{
+  match(Set dst (ConvF2L src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  size(4);
+  format %{ "FCVTZS_xs $dst, $src" %}
+  ins_encode %{
+    __ fcvtzs_xs($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(fcvtF2L);
+%}
+#else
+instruct convF2I_reg_reg(iRegI dst, regF src, regF tmp) %{
+  match(Set dst (ConvF2I src));
+  effect( TEMP tmp );
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  size(8);
+  format %{ "FTOSIZS  $tmp,$src\n\t"
+            "FMRS     $dst, $tmp" %}
+  ins_encode %{
+    __ ftosizs($tmp$$FloatRegister, $src$$FloatRegister);
+    __ fmrs($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(fcvtF2I);
+%}
+
+// Float to Long conversion
+instruct convF2L_reg(R0R1RegL dst, regF src, R0RegI arg1) %{
+  match(Set dst (ConvF2L src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  effect(CALL);
+  format %{ "convF2L  $dst,$src\t! call to SharedRuntime::f2l" %}
+  ins_encode %{
+#ifndef __ABI_HARD__
+    __ fmrs($arg1$$Register, $src$$FloatRegister);
+#else
+    if($src$$FloatRegister != S0) {
+      __ mov_float(S0, $src$$FloatRegister);
+    }
+#endif
+    address target = CAST_FROM_FN_PTR(address, SharedRuntime::f2l);
+    __ call(target, relocInfo::runtime_call_type);
+  %}
+  ins_pipe(fcvtF2L);
+%}
+#endif
+
+#ifdef AARCH64
+instruct convI2D_reg_reg(iRegI src, regD dst) %{
+  match(Set dst (ConvI2D src));
+  ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
+  size(4);
+  format %{ "SCVTF_dw $dst,$src" %}
+  ins_encode %{
+      __ scvtf_dw($dst$$FloatRegister, $src$$Register);
+  %}
+  ins_pipe(fcvtI2D);
+%}
+#else
+instruct convI2D_reg_reg(iRegI src, regD_low dst) %{
+  match(Set dst (ConvI2D src));
+  ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
+  size(8);
+  format %{ "FMSR     $dst,$src \n\t"
+            "FSITOD   $dst $dst"%}
+  ins_encode %{
+      __ fmsr($dst$$FloatRegister, $src$$Register);
+      __ fsitod($dst$$FloatRegister, $dst$$FloatRegister);
+  %}
+  ins_pipe(fcvtI2D);
+%}
+#endif
+
+instruct convI2F_reg_reg( regF dst, iRegI src ) %{
+  match(Set dst (ConvI2F src));
+  ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
+#ifdef AARCH64
+  size(4);
+  format %{ "SCVTF_sw $dst,$src" %}
+  ins_encode %{
+      __ scvtf_sw($dst$$FloatRegister, $src$$Register);
+  %}
+#else
+  size(8);
+  format %{ "FMSR     $dst,$src \n\t"
+            "FSITOS   $dst, $dst"%}
+  ins_encode %{
+      __ fmsr($dst$$FloatRegister, $src$$Register);
+      __ fsitos($dst$$FloatRegister, $dst$$FloatRegister);
+  %}
+#endif
+  ins_pipe(fcvtI2F);
+%}
+
+instruct convI2L_reg(iRegL dst, iRegI src) %{
+  match(Set dst (ConvI2L src));
+#ifdef AARCH64
+  size(4);
+  format %{ "SXTW   $dst,$src\t! int->long" %}
+  ins_encode %{
+    __ sxtw($dst$$Register, $src$$Register);
+  %}
+#else
+  size(8);
+  format %{ "MOV    $dst.lo, $src \n\t"
+            "ASR    $dst.hi,$src,31\t! int->long" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register);
+    __ mov($dst$$Register->successor(), AsmOperand($src$$Register, asr, 31));
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Zero-extend convert int to long
+instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
+  match(Set dst (AndL (ConvI2L src) mask) );
+#ifdef AARCH64
+  size(4);
+  format %{ "mov_w  $dst,$src\t! zero-extend int to long"  %}
+  ins_encode %{
+    __ mov_w($dst$$Register, $src$$Register);
+  %}
+#else
+  size(8);
+  format %{ "MOV    $dst.lo,$src.lo\t! zero-extend int to long\n\t"
+            "MOV    $dst.hi, 0"%}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+// Zero-extend long
+instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
+  match(Set dst (AndL src mask) );
+#ifdef AARCH64
+  size(4);
+  format %{ "mov_w  $dst,$src\t! zero-extend long"  %}
+  ins_encode %{
+    __ mov_w($dst$$Register, $src$$Register);
+  %}
+#else
+  size(8);
+  format %{ "MOV    $dst.lo,$src.lo\t! zero-extend long\n\t"
+            "MOV    $dst.hi, 0"%}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register);
+    __ mov($dst$$Register->successor(), 0);
+  %}
+#endif
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct MoveF2I_reg_reg(iRegI dst, regF src) %{
+  match(Set dst (MoveF2I src));
+  effect(DEF dst, USE src);
+  ins_cost(MEMORY_REF_COST); // FIXME
+
+  size(4);
+  format %{ "FMRS   $dst,$src\t! MoveF2I" %}
+  ins_encode %{
+    __ fmrs($dst$$Register, $src$$FloatRegister);
+  %}
+  ins_pipe(iload_mem); // FIXME
+%}
+
+instruct MoveI2F_reg_reg(regF dst, iRegI src) %{
+  match(Set dst (MoveI2F src));
+  ins_cost(MEMORY_REF_COST); // FIXME
+
+  size(4);
+  format %{ "FMSR   $dst,$src\t! MoveI2F" %}
+  ins_encode %{
+    __ fmsr($dst$$FloatRegister, $src$$Register);
+  %}
+  ins_pipe(iload_mem); // FIXME
+%}
+
+instruct MoveD2L_reg_reg(iRegL dst, regD src) %{
+  match(Set dst (MoveD2L src));
+  effect(DEF dst, USE src);
+  ins_cost(MEMORY_REF_COST); // FIXME
+
+  size(4);
+#ifdef AARCH64
+  format %{ "FMOV_xd  $dst,$src\t! MoveD2L" %}
+  ins_encode %{
+    __ fmov_xd($dst$$Register, $src$$FloatRegister);
+  %}
+#else
+  format %{ "FMRRD    $dst,$src\t! MoveD2L" %}
+  ins_encode %{
+    __ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
+  %}
+#endif
+  ins_pipe(iload_mem); // FIXME
+%}
+
+instruct MoveL2D_reg_reg(regD dst, iRegL src) %{
+  match(Set dst (MoveL2D src));
+  effect(DEF dst, USE src);
+  ins_cost(MEMORY_REF_COST); // FIXME
+
+  size(4);
+#ifdef AARCH64
+  format %{ "FMOV_dx $dst,$src\t! MoveL2D" %}
+  ins_encode %{
+    __ fmov_dx($dst$$FloatRegister, $src$$Register);
+  %}
+#else
+  format %{ "FMDRR   $dst,$src\t! MoveL2D" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
+  %}
+#endif
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+
+//-----------
+// Long to Double conversion
+
+#ifdef AARCH64
+instruct convL2D(regD dst, iRegL src) %{
+  match(Set dst (ConvL2D src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  size(4);
+  format %{ "SCVTF_dx $dst, $src" %}
+  ins_encode %{
+    __ scvtf_dx($dst$$FloatRegister, $src$$Register);
+  %}
+  ins_pipe(fcvtL2D);
+%}
+
+instruct convL2F(regF dst, iRegL src) %{
+  match(Set dst (ConvL2F src));
+  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
+  size(4);
+  format %{ "SCVTF_sx $dst, $src" %}
+  ins_encode %{
+    __ scvtf_sx($dst$$FloatRegister, $src$$Register);
+  %}
+  ins_pipe(fcvtL2F);
+%}
+#else
+// Magic constant, 0x43300000
+instruct loadConI_x43300000(iRegI dst) %{
+  effect(DEF dst);
+  size(8);
+  format %{ "MOV_SLOW  $dst,0x43300000\t! 2^52" %}
+  ins_encode %{
+    __ mov_slow($dst$$Register, 0x43300000);
+  %}
+  ins_pipe(ialu_none);
+%}
+
+// Magic constant, 0x41f00000
+instruct loadConI_x41f00000(iRegI dst) %{
+  effect(DEF dst);
+  size(8);
+  format %{ "MOV_SLOW  $dst, 0x41f00000\t! 2^32" %}
+  ins_encode %{
+    __ mov_slow($dst$$Register, 0x41f00000);
+  %}
+  ins_pipe(ialu_none);
+%}
+
+instruct loadConI_x0(iRegI dst) %{
+  effect(DEF dst);
+  size(4);
+  format %{ "MOV  $dst, 0x0\t! 0" %}
+  ins_encode %{
+    __ mov($dst$$Register, 0);
+  %}
+  ins_pipe(ialu_none);
+%}
+
+// Construct a double from two float halves
+instruct regDHi_regDLo_to_regD(regD_low dst, regD_low src1, regD_low src2) %{
+  effect(DEF dst, USE src1, USE src2);
+  size(8);
+  format %{ "FCPYS  $dst.hi,$src1.hi\n\t"
+            "FCPYS  $dst.lo,$src2.lo" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister->successor(), $src1$$FloatRegister->successor());
+    __ fcpys($dst$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg_reg);
+%}
+
+#ifndef AARCH64
+// Convert integer in high half of a double register (in the lower half of
+// the double register file) to double
+instruct convI2D_regDHi_regD(regD dst, regD_low src) %{
+  effect(DEF dst, USE src);
+  size(4);
+  format %{ "FSITOD  $dst,$src" %}
+  ins_encode %{
+    __ fsitod($dst$$FloatRegister, $src$$FloatRegister->successor());
+  %}
+  ins_pipe(fcvtLHi2D);
+%}
+#endif
+
+// Add float double precision
+instruct addD_regD_regD(regD dst, regD src1, regD src2) %{
+  effect(DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "FADDD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg_reg);
+%}
+
+// Sub float double precision
+instruct subD_regD_regD(regD dst, regD src1, regD src2) %{
+  effect(DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "FSUBD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(faddD_reg_reg);
+%}
+
+// Mul float double precision
+instruct mulD_regD_regD(regD dst, regD src1, regD src2) %{
+  effect(DEF dst, USE src1, USE src2);
+  size(4);
+  format %{ "FMULD  $dst,$src1,$src2" %}
+  ins_encode %{
+    __ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+  ins_pipe(fmulD_reg_reg);
+%}
+
+instruct regL_to_regD(regD dst, iRegL src) %{
+  // No match rule to avoid chain rule match.
+  effect(DEF dst, USE src);
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "FMDRR   $dst,$src\t! regL to regD" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+
+instruct regI_regI_to_regD(regD dst, iRegI src1, iRegI src2) %{
+  // No match rule to avoid chain rule match.
+  effect(DEF dst, USE src1, USE src2);
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "FMDRR   $dst,$src1,$src2\t! regI,regI to regD" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src1$$Register, $src2$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+%}
+
+instruct convL2D_reg_slow_fxtof(regD dst, iRegL src) %{
+  match(Set dst (ConvL2D src));
+  ins_cost(DEFAULT_COST*8 + MEMORY_REF_COST*6); // FIXME
+
+  expand %{
+    regD_low   tmpsrc;
+    iRegI      ix43300000;
+    iRegI      ix41f00000;
+    iRegI      ix0;
+    regD_low   dx43300000;
+    regD       dx41f00000;
+    regD       tmp1;
+    regD_low   tmp2;
+    regD       tmp3;
+    regD       tmp4;
+
+    regL_to_regD(tmpsrc, src);
+
+    loadConI_x43300000(ix43300000);
+    loadConI_x41f00000(ix41f00000);
+    loadConI_x0(ix0);
+
+    regI_regI_to_regD(dx43300000, ix0, ix43300000);
+    regI_regI_to_regD(dx41f00000, ix0, ix41f00000);
+
+    convI2D_regDHi_regD(tmp1, tmpsrc);
+    regDHi_regDLo_to_regD(tmp2, dx43300000, tmpsrc);
+    subD_regD_regD(tmp3, tmp2, dx43300000);
+    mulD_regD_regD(tmp4, tmp1, dx41f00000);
+    addD_regD_regD(dst, tmp3, tmp4);
+  %}
+%}
+#endif // !AARCH64
+
+instruct convL2I_reg(iRegI dst, iRegL src) %{
+  match(Set dst (ConvL2I src));
+  size(4);
+#ifdef AARCH64
+  format %{ "MOV_w  $dst,$src\t! long->int" %}
+  ins_encode %{
+    __ mov_w($dst$$Register, $src$$Register);
+  %}
+#else
+  format %{ "MOV    $dst,$src.lo\t! long->int" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register);
+  %}
+#endif
+  ins_pipe(ialu_move_reg_I_to_L);
+%}
+
+#ifndef AARCH64
+// Register Shift Right Immediate
+instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
+  match(Set dst (ConvL2I (RShiftL src cnt)));
+  size(4);
+  format %{ "ASR    $dst,$src.hi,($cnt - 32)\t! long->int or mov if $cnt==32" %}
+  ins_encode %{
+    if ($cnt$$constant == 32) {
+      __ mov($dst$$Register, $src$$Register->successor());
+    } else {
+      __ mov($dst$$Register, AsmOperand($src$$Register->successor(), asr, $cnt$$constant - 32));
+    }
+  %}
+  ins_pipe(ialu_reg_imm);
+%}
+#endif
+
+
+//----------Control Flow Instructions------------------------------------------
+// Compare Instructions
+// Compare Integers
+instruct compI_iReg(flagsReg icc, iRegI op1, iRegI op2) %{
+  match(Set icc (CmpI op1 op2));
+  effect( DEF icc, USE op1, USE op2 );
+
+  size(4);
+  format %{ "cmp_32 $op1,$op2\t! int" %}
+  ins_encode %{
+    __ cmp_32($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+#ifdef _LP64
+// Compare compressed pointers
+instruct compN_reg2(flagsRegU icc, iRegN op1, iRegN op2) %{
+  match(Set icc (CmpN op1 op2));
+  effect( DEF icc, USE op1, USE op2 );
+
+  size(4);
+  format %{ "cmp_32 $op1,$op2\t! int" %}
+  ins_encode %{
+    __ cmp_32($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+#endif
+
+instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
+  match(Set icc (CmpU op1 op2));
+
+  size(4);
+  format %{ "cmp_32 $op1,$op2\t! unsigned int" %}
+  ins_encode %{
+    __ cmp_32($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+instruct compI_iReg_immneg(flagsReg icc, iRegI op1, aimmIneg op2) %{
+  match(Set icc (CmpI op1 op2));
+  effect( DEF icc, USE op1 );
+
+  size(4);
+  format %{ "cmn_32 $op1,-$op2\t! int" %}
+  ins_encode %{
+    __ cmn_32($op1$$Register, -$op2$$constant);
+  %}
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+
+instruct compI_iReg_imm(flagsReg icc, iRegI op1, aimmI op2) %{
+  match(Set icc (CmpI op1 op2));
+  effect( DEF icc, USE op1 );
+
+  size(4);
+  format %{ "cmp_32 $op1,$op2\t! int" %}
+  ins_encode %{
+    __ cmp_32($op1$$Register, $op2$$constant);
+  %}
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+
+instruct testI_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 op2) zero));
+  size(4);
+  format %{ "tst_32 $op2,$op1" %}
+
+  ins_encode %{
+    __ tst_32($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+
+#ifndef AARCH64
+instruct testshlI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
+  size(4);
+  format %{ "TST   $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$Register));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+#endif
+
+instruct testshlI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
+  size(4);
+  format %{ "tst_32 $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst_32($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$constant));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+
+#ifndef AARCH64
+instruct testsarI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
+  size(4);
+  format %{ "TST   $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$Register));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+#endif
+
+instruct testsarI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
+  size(4);
+  format %{ "tst_32 $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst_32($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$constant));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+
+#ifndef AARCH64
+instruct testshrI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
+  size(4);
+  format %{ "TST   $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$Register));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+#endif
+
+instruct testshrI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
+  size(4);
+  format %{ "tst_32 $op2,$op1<<$op3" %}
+
+  ins_encode %{
+    __ tst_32($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$constant));
+  %}
+  ins_pipe(ialu_cconly_reg_reg_zero);
+%}
+
+instruct testI_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, limmI op2, immI0 zero ) %{
+  match(Set icc (CmpI (AndI op1 op2) zero));
+  size(4);
+  format %{ "tst_32 $op2,$op1" %}
+
+  ins_encode %{
+    __ tst_32($op1$$Register, $op2$$constant);
+  %}
+  ins_pipe(ialu_cconly_reg_imm_zero);
+%}
+
+#ifdef AARCH64
+instruct compL_reg_reg(flagsReg xcc, iRegL op1, iRegL op2)
+%{
+  match(Set xcc (CmpL op1 op2));
+  effect( DEF xcc, USE op1, USE op2 );
+
+  size(4);
+  format %{ "CMP     $op1,$op2\t! long" %}
+  ins_encode %{
+    __ cmp($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+#else
+instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
+  match(Set xcc (CmpL op1 op2));
+  effect( DEF xcc, USE op1, USE op2, TEMP tmp );
+
+  size(8);
+  format %{ "SUBS    $tmp,$op1.low,$op2.low\t\t! long\n\t"
+            "SBCS    $tmp,$op1.hi,$op2.hi" %}
+  ins_encode %{
+    __ subs($tmp$$Register, $op1$$Register, $op2$$Register);
+    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+#endif
+
+#ifdef AARCH64
+instruct compL_reg_con(flagsReg xcc, iRegL op1, aimmL con) %{
+  match(Set xcc (CmpL op1 con));
+  effect( DEF xcc, USE op1, USE con );
+
+  size(8);
+  format %{ "CMP     $op1,$con\t\t! long"  %}
+  ins_encode %{
+    __ cmp($op1$$Register, $con$$constant);
+  %}
+
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+#else
+instruct compL_reg_reg_EQNE(flagsRegL_EQNE xcc, iRegL op1, iRegL op2) %{
+  match(Set xcc (CmpL op1 op2));
+  effect( DEF xcc, USE op1, USE op2 );
+
+  size(8);
+  format %{ "TEQ    $op1.hi,$op2.hi\t\t! long\n\t"
+            "TEQ.eq $op1.lo,$op2.lo" %}
+  ins_encode %{
+    __ teq($op1$$Register->successor(), $op2$$Register->successor());
+    __ teq($op1$$Register, $op2$$Register, eq);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+instruct compL_reg_reg_LEGT(flagsRegL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
+  match(Set xcc (CmpL op1 op2));
+  effect( DEF xcc, USE op1, USE op2, TEMP tmp );
+
+  size(8);
+  format %{ "SUBS    $tmp,$op2.low,$op1.low\t\t! long\n\t"
+            "SBCS    $tmp,$op2.hi,$op1.hi" %}
+  ins_encode %{
+    __ subs($tmp$$Register, $op2$$Register, $op1$$Register);
+    __ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compL_reg_con_LTGE(flagsRegL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
+  match(Set xcc (CmpL op1 con));
+  effect( DEF xcc, USE op1, USE con, TEMP tmp );
+
+  size(8);
+  format %{ "SUBS    $tmp,$op1.low,$con\t\t! long\n\t"
+            "SBCS    $tmp,$op1.hi,0" %}
+  ins_encode %{
+    __ subs($tmp$$Register, $op1$$Register, $con$$constant);
+    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
+  %}
+
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compL_reg_con_EQNE(flagsRegL_EQNE xcc, iRegL op1, immLlowRot con) %{
+  match(Set xcc (CmpL op1 con));
+  effect( DEF xcc, USE op1, USE con );
+
+  size(8);
+  format %{ "TEQ    $op1.hi,0\t\t! long\n\t"
+            "TEQ.eq $op1.lo,$con" %}
+  ins_encode %{
+    __ teq($op1$$Register->successor(), 0);
+    __ teq($op1$$Register, $con$$constant, eq);
+  %}
+
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+// TODO: try immLRot2 instead, (0, $con$$constant) becomes
+// (hi($con$$constant), lo($con$$constant)) becomes
+instruct compL_reg_con_LEGT(flagsRegL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
+  match(Set xcc (CmpL op1 con));
+  effect( DEF xcc, USE op1, USE con, TEMP tmp );
+
+  size(8);
+  format %{ "RSBS    $tmp,$op1.low,$con\t\t! long\n\t"
+            "RSCS    $tmp,$op1.hi,0" %}
+  ins_encode %{
+    __ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
+    __ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
+  %}
+
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+#endif
+
+/* instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{ */
+/*   match(Set xcc (CmpL (AndL op1 op2) zero)); */
+/*   ins_encode %{ */
+/*     __ stop("testL_reg_reg unimplemented"); */
+/*   %} */
+/*   ins_pipe(ialu_cconly_reg_reg); */
+/* %} */
+
+/* // useful for checking the alignment of a pointer: */
+/* instruct testL_reg_con(flagsRegL xcc, iRegL op1, immLlowRot con, immL0 zero) %{ */
+/*   match(Set xcc (CmpL (AndL op1 con) zero)); */
+/*   ins_encode %{ */
+/*     __ stop("testL_reg_con unimplemented"); */
+/*   %} */
+/*   ins_pipe(ialu_cconly_reg_reg); */
+/* %} */
+
+instruct compU_iReg_imm(flagsRegU icc, iRegI op1, aimmU31 op2 ) %{
+  match(Set icc (CmpU op1 op2));
+
+  size(4);
+  format %{ "cmp_32 $op1,$op2\t! unsigned" %}
+  ins_encode %{
+    __ cmp_32($op1$$Register, $op2$$constant);
+  %}
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+
+// Compare Pointers
+instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
+  match(Set pcc (CmpP op1 op2));
+
+  size(4);
+  format %{ "CMP    $op1,$op2\t! ptr" %}
+  ins_encode %{
+    __ cmp($op1$$Register, $op2$$Register);
+  %}
+  ins_pipe(ialu_cconly_reg_reg);
+%}
+
+instruct compP_iRegP_imm(flagsRegP pcc, iRegP op1, aimmP op2 ) %{
+  match(Set pcc (CmpP op1 op2));
+
+  size(4);
+  format %{ "CMP    $op1,$op2\t! ptr" %}
+  ins_encode %{
+    assert($op2$$constant == 0 || _opnds[2]->constant_reloc() == relocInfo::none, "reloc in cmp?");
+    __ cmp($op1$$Register, $op2$$constant);
+  %}
+  ins_pipe(ialu_cconly_reg_imm);
+%}
+
+//----------Max and Min--------------------------------------------------------
+// Min Instructions
+// Conditional move for min
+instruct cmovI_reg_lt( iRegI op2, iRegI op1, flagsReg icc ) %{
+  effect( USE_DEF op2, USE op1, USE icc );
+
+  size(4);
+  format %{ "MOV.lt  $op2,$op1\t! min" %}
+  ins_encode %{
+    __ mov($op2$$Register, $op1$$Register, lt);
+  %}
+  ins_pipe(ialu_reg_flags);
+%}
+
+// Min Register with Register.
+instruct minI_eReg(iRegI op1, iRegI op2) %{
+  match(Set op2 (MinI op1 op2));
+  ins_cost(DEFAULT_COST*2);
+  expand %{
+    flagsReg icc;
+    compI_iReg(icc,op1,op2);
+    cmovI_reg_lt(op2,op1,icc);
+  %}
+%}
+
+// Max Instructions
+// Conditional move for max
+instruct cmovI_reg_gt( iRegI op2, iRegI op1, flagsReg icc ) %{
+  effect( USE_DEF op2, USE op1, USE icc );
+  format %{ "MOV.gt  $op2,$op1\t! max" %}
+  ins_encode %{
+    __ mov($op2$$Register, $op1$$Register, gt);
+  %}
+  ins_pipe(ialu_reg_flags);
+%}
+
+// Max Register with Register
+instruct maxI_eReg(iRegI op1, iRegI op2) %{
+  match(Set op2 (MaxI op1 op2));
+  ins_cost(DEFAULT_COST*2);
+  expand %{
+    flagsReg icc;
+    compI_iReg(icc,op1,op2);
+    cmovI_reg_gt(op2,op1,icc);
+  %}
+%}
+
+
+//----------Float Compares----------------------------------------------------
+// Compare floating, generate condition code
+instruct cmpF_cc(flagsRegF fcc, flagsReg icc, regF src1, regF src2) %{
+  match(Set icc (CmpF src1 src2));
+  effect(KILL fcc);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "FCMP_s  $src1,$src2" %}
+  ins_encode %{
+    __ fcmp_s($src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+#else
+  size(8);
+  format %{ "FCMPs  $src1,$src2\n\t"
+            "FMSTAT" %}
+  ins_encode %{
+    __ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
+    __ fmstat();
+  %}
+#endif
+  ins_pipe(faddF_fcc_reg_reg_zero);
+%}
+
+instruct cmpF0_cc(flagsRegF fcc, flagsReg icc, regF src1, immF0 src2) %{
+  match(Set icc (CmpF src1 src2));
+  effect(KILL fcc);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "FCMP0_s $src1" %}
+  ins_encode %{
+    __ fcmp0_s($src1$$FloatRegister);
+  %}
+#else
+  size(8);
+  format %{ "FCMPs  $src1,$src2\n\t"
+            "FMSTAT" %}
+  ins_encode %{
+    __ fcmpzs($src1$$FloatRegister);
+    __ fmstat();
+  %}
+#endif
+  ins_pipe(faddF_fcc_reg_reg_zero);
+%}
+
+instruct cmpD_cc(flagsRegF fcc, flagsReg icc, regD src1, regD src2) %{
+  match(Set icc (CmpD src1 src2));
+  effect(KILL fcc);
+
+#ifdef AARCH64
+  size(4);
+  format %{ "FCMP_d $src1,$src2" %}
+  ins_encode %{
+    __ fcmp_d($src1$$FloatRegister, $src2$$FloatRegister);
+  %}
+#else
+  size(8);
+  format %{ "FCMPd  $src1,$src2 \n\t"
+            "FMSTAT" %}
+  ins_encode %{
+    __ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
+    __ fmstat();
+  %}
+#endif
+  ins_pipe(faddD_fcc_reg_reg_zero);
+%}
+
+instruct cmpD0_cc(flagsRegF fcc, flagsReg icc, regD src1, immD0 src2) %{
+  match(Set icc (CmpD src1 src2));
+  effect(KILL fcc);
+
+#ifdef AARCH64
+  size(8);
+  format %{ "FCMP0_d $src1" %}
+  ins_encode %{
+    __ fcmp0_d($src1$$FloatRegister);
+  %}
+#else
+  size(8);
+  format %{ "FCMPZd  $src1,$src2 \n\t"
+            "FMSTAT" %}
+  ins_encode %{
+    __ fcmpzd($src1$$FloatRegister);
+    __ fmstat();
+  %}
+#endif
+  ins_pipe(faddD_fcc_reg_reg_zero);
+%}
+
+#ifdef AARCH64
+// Compare floating, generate -1,0,1
+instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsReg icc) %{
+  match(Set dst (CmpF3 src1 src2));
+  // effect(KILL fcc); // nobody cares if flagsRegF is killed
+  effect(KILL icc);
+  ins_cost(DEFAULT_COST*3); // FIXME
+  size(12);
+  format %{ "FCMP_s $src1,$src2\n\t"
+            "CSET   $dst, gt\n\t"
+            "CSINV  $dst, $dst, ZR, ge" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    __ fcmp_s($src1$$FloatRegister, $src2$$FloatRegister);
+    __ cset(dst, gt);            // 1 if '>', else 0
+    __ csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+  %}
+  ins_pipe( floating_cmp ); // FIXME
+%}
+
+// Compare floating, generate -1,0,1
+instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsReg icc) %{
+  match(Set dst (CmpD3 src1 src2));
+  // effect(KILL fcc); // nobody cares if flagsRegF is killed
+  effect(KILL icc);
+  ins_cost(DEFAULT_COST*3); // FIXME
+  size(12);
+  format %{ "FCMP_d $src1,$src2\n\t"
+            "CSET   $dst, gt\n\t"
+            "CSINV  $dst, $dst, ZR, ge" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    __ fcmp_d($src1$$FloatRegister, $src2$$FloatRegister);
+    __ cset(dst, gt);            // 1 if '>', else 0
+    __ csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+  %}
+  ins_pipe( floating_cmp ); // FIXME
+%}
+
+// Compare floating, generate -1,0,1
+instruct cmpF0_reg(iRegI dst, regF src1, immF0 src2, flagsReg icc) %{
+  match(Set dst (CmpF3 src1 src2));
+  // effect(KILL fcc); // nobody cares if flagsRegF is killed
+  effect(KILL icc);
+  ins_cost(DEFAULT_COST*3); // FIXME
+  size(12);
+  format %{ "FCMP0_s $src1\n\t"
+            "CSET   $dst, gt\n\t"
+            "CSINV  $dst, $dst, ZR, ge" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    __ fcmp0_s($src1$$FloatRegister);
+    __ cset(dst, gt);            // 1 if '>', else 0
+    __ csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+  %}
+  ins_pipe( floating_cmp ); // FIXME
+%}
+
+// Compare floating, generate -1,0,1
+instruct cmpD0_reg(iRegI dst, regD src1, immD0 src2, flagsReg icc) %{
+  match(Set dst (CmpD3 src1 src2));
+  // effect(KILL fcc); // nobody cares if flagsRegF is killed
+  effect(KILL icc);
+  ins_cost(DEFAULT_COST*3); // FIXME
+  size(12);
+  format %{ "FCMP0_d $src1\n\t"
+            "CSET   $dst, gt\n\t"
+            "CSINV  $dst, $dst, ZR, ge" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    __ fcmp0_d($src1$$FloatRegister);
+    __ cset(dst, gt);            // 1 if '>', else 0
+    __ csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+  %}
+  ins_pipe( floating_cmp ); // FIXME
+%}
+#else
+// Compare floating, generate -1,0,1
+instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsRegF fcc) %{
+  match(Set dst (CmpF3 src1 src2));
+  effect(KILL fcc);
+  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
+  size(20);
+  // same number of instructions as code using conditional moves but
+  // doesn't kill integer condition register
+  format %{ "FCMPs  $dst,$src1,$src2 \n\t"
+            "VMRS   $dst, FPSCR \n\t"
+            "OR     $dst, $dst, 0x08000000 \n\t"
+            "EOR    $dst, $dst, $dst << 3 \n\t"
+            "MOV    $dst, $dst >> 30" %}
+  ins_encode %{
+    __ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
+    __ floating_cmp($dst$$Register);
+  %}
+  ins_pipe( floating_cmp );
+%}
+
+instruct cmpF0_reg(iRegI dst, regF src1, immF0 src2, flagsRegF fcc) %{
+  match(Set dst (CmpF3 src1 src2));
+  effect(KILL fcc);
+  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
+  size(20);
+  // same number of instructions as code using conditional moves but
+  // doesn't kill integer condition register
+  format %{ "FCMPZs $dst,$src1,$src2 \n\t"
+            "VMRS   $dst, FPSCR \n\t"
+            "OR     $dst, $dst, 0x08000000 \n\t"
+            "EOR    $dst, $dst, $dst << 3 \n\t"
+            "MOV    $dst, $dst >> 30" %}
+  ins_encode %{
+    __ fcmpzs($src1$$FloatRegister);
+    __ floating_cmp($dst$$Register);
+  %}
+  ins_pipe( floating_cmp );
+%}
+
+instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsRegF fcc) %{
+  match(Set dst (CmpD3 src1 src2));
+  effect(KILL fcc);
+  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
+  size(20);
+  // same number of instructions as code using conditional moves but
+  // doesn't kill integer condition register
+  format %{ "FCMPd  $dst,$src1,$src2 \n\t"
+            "VMRS   $dst, FPSCR \n\t"
+            "OR     $dst, $dst, 0x08000000 \n\t"
+            "EOR    $dst, $dst, $dst << 3 \n\t"
+            "MOV    $dst, $dst >> 30" %}
+  ins_encode %{
+    __ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
+    __ floating_cmp($dst$$Register);
+  %}
+  ins_pipe( floating_cmp );
+%}
+
+instruct cmpD0_reg(iRegI dst, regD src1, immD0 src2, flagsRegF fcc) %{
+  match(Set dst (CmpD3 src1 src2));
+  effect(KILL fcc);
+  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
+  size(20);
+  // same number of instructions as code using conditional moves but
+  // doesn't kill integer condition register
+  format %{ "FCMPZd $dst,$src1,$src2 \n\t"
+            "VMRS   $dst, FPSCR \n\t"
+            "OR     $dst, $dst, 0x08000000 \n\t"
+            "EOR    $dst, $dst, $dst << 3 \n\t"
+            "MOV    $dst, $dst >> 30" %}
+  ins_encode %{
+    __ fcmpzd($src1$$FloatRegister);
+    __ floating_cmp($dst$$Register);
+  %}
+  ins_pipe( floating_cmp );
+%}
+#endif // !AARCH64
+
+//----------Branches---------------------------------------------------------
+// Jump
+// (compare 'operand indIndex' and 'instruct addP_reg_reg' above)
+// FIXME
+instruct jumpXtnd(iRegX switch_val, iRegP tmp) %{
+  match(Jump switch_val);
+  effect(TEMP tmp);
+  ins_cost(350);
+  format %{  "ADD    $tmp, $constanttablebase, $switch_val\n\t"
+             "LDR    $tmp,[$tmp + $constantoffset]\n\t"
+             "BX     $tmp" %}
+  size(20);
+  ins_encode %{
+    Register table_reg;
+    Register label_reg = $tmp$$Register;
+    if (constant_offset() == 0) {
+      table_reg = $constanttablebase;
+      __ ldr(label_reg, Address(table_reg, $switch_val$$Register));
+    } else {
+      table_reg = $tmp$$Register;
+      int offset = $constantoffset;
+      if (is_memoryP(offset)) {
+        __ add(table_reg, $constanttablebase, $switch_val$$Register);
+        __ ldr(label_reg, Address(table_reg, offset));
+      } else {
+        __ mov_slow(table_reg, $constantoffset);
+        __ add(table_reg, $constanttablebase, table_reg);
+        __ ldr(label_reg, Address(table_reg, $switch_val$$Register));
+      }
+    }
+    __ jump(label_reg); // ldr + b better than ldr to PC for branch predictor?
+    //    __ ldr(PC, Address($table$$Register, $switch_val$$Register));
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+// // Direct Branch.
+instruct branch(label labl) %{
+  match(Goto);
+  effect(USE labl);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B     $labl" %}
+  ins_encode %{
+    __ b(*($labl$$label));
+  %}
+  ins_pipe(br);
+%}
+
+// Conditional Direct Branch
+instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
+  match(If cmp icc);
+  effect(USE labl);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp   $icc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+#ifdef ARM
+instruct branchCon_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, label labl) %{
+  match(If cmp icc);
+  effect(USE labl);
+  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp   $icc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+#endif
+
+#ifdef AARCH64
+instruct cbzI(cmpOp cmp, iRegI op1, immI0 op2, label labl) %{
+  match(If cmp (CmpI op1 op2));
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "CB{N}Z $op1, $labl\t! int $cmp" %}
+  ins_encode %{
+    if ($cmp$$cmpcode == eq) {
+      __ cbz_w($op1$$Register, *($labl$$label));
+    } else {
+      __ cbnz_w($op1$$Register, *($labl$$label));
+    }
+  %}
+  ins_pipe(br_cc); // FIXME
+%}
+
+instruct cbzP(cmpOpP cmp, iRegP op1, immP0 op2, label labl) %{
+  match(If cmp (CmpP op1 op2));
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "CB{N}Z $op1, $labl\t! ptr $cmp" %}
+  ins_encode %{
+    if ($cmp$$cmpcode == eq) {
+      __ cbz($op1$$Register, *($labl$$label));
+    } else {
+      __ cbnz($op1$$Register, *($labl$$label));
+    }
+  %}
+  ins_pipe(br_cc); // FIXME
+%}
+
+instruct cbzL(cmpOpL cmp, iRegL op1, immL0 op2, label labl) %{
+  match(If cmp (CmpL op1 op2));
+  effect(USE labl);
+  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
+            _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "CB{N}Z $op1, $labl\t! long $cmp" %}
+  ins_encode %{
+    if ($cmp$$cmpcode == eq) {
+      __ cbz($op1$$Register, *($labl$$label));
+    } else {
+      __ cbnz($op1$$Register, *($labl$$label));
+    }
+  %}
+  ins_pipe(br_cc); // FIXME
+%}
+#endif
+
+instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{
+  match(If cmp icc);
+  effect(USE labl);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp  $icc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+instruct branchConP(cmpOpP cmp, flagsRegP pcc, label labl) %{
+  match(If cmp pcc);
+  effect(USE labl);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp  $pcc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+#ifndef AARCH64
+instruct branchConL_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, label labl) %{
+  match(If cmp xcc);
+  effect(USE labl);
+  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp  $xcc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+instruct branchConL_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, label labl) %{
+  match(If cmp xcc);
+  effect(USE labl);
+  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp  $xcc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+instruct branchConL_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, label labl) %{
+  match(If cmp xcc);
+  effect(USE labl);
+  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le );
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp  $xcc,$labl" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+#endif
+
+instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{
+  match(CountedLoopEnd cmp icc);
+  effect(USE labl);
+
+  size(4);
+  ins_cost(BRANCH_COST);
+  format %{ "B$cmp   $icc,$labl\t! Loop end" %}
+  ins_encode %{
+    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(br_cc);
+%}
+
+// instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{
+//   match(CountedLoopEnd cmp icc);
+//   ins_pipe(br_cc);
+// %}
+
+// ============================================================================
+// Long Compare
+//
+// Currently we hold longs in 2 registers.  Comparing such values efficiently
+// is tricky.  The flavor of compare used depends on whether we are testing
+// for LT, LE, or EQ.  For a simple LT test we can check just the sign bit.
+// The GE test is the negated LT test.  The LE test can be had by commuting
+// the operands (yielding a GE test) and then negating; negate again for the
+// GT test.  The EQ test is done by ORcc'ing the high and low halves, and the
+// NE test is negated from that.
+
+// Due to a shortcoming in the ADLC, it mixes up expressions like:
+// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)).  Note the
+// difference between 'Y' and '0L'.  The tree-matches for the CmpI sections
+// are collapsed internally in the ADLC's dfa-gen code.  The match for
+// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the
+// foo match ends up with the wrong leaf.  One fix is to not match both
+// reg-reg and reg-zero forms of long-compare.  This is unfortunate because
+// both forms beat the trinary form of long-compare and both are very useful
+// on Intel which has so few registers.
+
+// instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
+//   match(If cmp xcc);
+//   ins_pipe(br_cc);
+// %}
+
+// Manifest a CmpL3 result in an integer register.  Very painful.
+// This is the test to avoid.
+#ifdef AARCH64
+instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr) %{
+  match(Set dst (CmpL3 src1 src2));
+  // effect(KILL fcc); // nobody cares if flagsRegF is killed
+  effect(KILL ccr);
+  ins_cost(DEFAULT_COST*3); // FIXME
+  size(12);
+  format %{ "CMP    $src1,$src2\n\t"
+            "CSET   $dst, gt\n\t"
+            "CSINV  $dst, $dst, ZR, ge" %}
+  ins_encode %{
+    Register dst = $dst$$Register;
+    __ cmp($src1$$Register, $src2$$Register);
+    __ cset(dst, gt);            // 1 if '>', else 0
+    __ csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+  %}
+  ins_pipe( ialu_cconly_reg_reg ); // FIXME
+%}
+// TODO cmpL3_reg_imm
+#else
+instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
+  match(Set dst (CmpL3 src1 src2) );
+  effect( KILL ccr );
+  ins_cost(6*DEFAULT_COST); // FIXME
+  size(32);
+  format %{
+      "CMP    $src1.hi, $src2.hi\t\t! long\n"
+    "\tMOV.gt $dst, 1\n"
+    "\tmvn.lt $dst, 0\n"
+    "\tB.ne   done\n"
+    "\tSUBS   $dst, $src1.lo, $src2.lo\n"
+    "\tMOV.hi $dst, 1\n"
+    "\tmvn.lo $dst, 0\n"
+    "done:"     %}
+  ins_encode %{
+    Label done;
+    __ cmp($src1$$Register->successor(), $src2$$Register->successor());
+    __ mov($dst$$Register, 1, gt);
+    __ mvn($dst$$Register, 0, lt);
+    __ b(done, ne);
+    __ subs($dst$$Register, $src1$$Register, $src2$$Register);
+    __ mov($dst$$Register, 1, hi);
+    __ mvn($dst$$Register, 0, lo);
+    __ bind(done);
+  %}
+  ins_pipe(cmpL_reg);
+%}
+#endif
+
+#ifndef AARCH64
+// Conditional move
+instruct cmovLL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(150);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(150);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, iRegL src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(150);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
+            "MOV$cmp  $dst,$src.hi" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovLL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, immL0 src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+  ins_cost(140);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
+            "MOV$cmp  $dst,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, immL0 src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+  ins_cost(140);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
+            "MOV$cmp  $dst,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovLL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, immL0 src) %{
+  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+  ins_cost(140);
+  size(8);
+  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
+            "MOV$cmp  $dst,0" %}
+  ins_encode %{
+    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
+    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+#endif // !AARCH64
+
+#ifndef AARCH64
+instruct cmovIL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovIL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovIL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, iRegI src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif // !AARCH64
+
+#ifndef AARCH64
+instruct cmovIL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovIL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovIL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI16 src) %{
+  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovPL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, iRegP src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(150);
+  size(4);
+  format %{ "MOV$cmp  $dst,$src" %}
+  ins_encode %{
+    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+instruct cmovPL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovPL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovPL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, immP0 src) %{
+  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(140);
+  format %{ "MOVW$cmp  $dst,$src" %}
+  ins_encode %{
+    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(ialu_imm);
+%}
+
+instruct cmovFL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovFL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regF dst, regF src) %{
+  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYS$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );
+
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );
+
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+
+instruct cmovDL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regD dst, regD src) %{
+  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
+  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt );
+
+  ins_cost(150);
+  size(4);
+  format %{ "FCPYD$cmp $dst,$src" %}
+  ins_encode %{
+    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
+  %}
+  ins_pipe(int_conditional_float_move);
+%}
+#endif // !AARCH64
+
+// ============================================================================
+// Safepoint Instruction
+#ifdef AARCH64
+instruct safePoint_poll(iRegP poll, flagsReg icc, RtempRegP tmp) %{
+  match(SafePoint poll);
+  // The handler stub kills Rtemp
+  effect(USE poll, KILL tmp, KILL icc);
+
+  size(4);
+  format %{ "LDR   ZR,[$poll]\t! Safepoint: poll for GC" %}
+  ins_encode %{
+    __ relocate(relocInfo::poll_type);
+    __ ldr(ZR, Address($poll$$Register));
+  %}
+  ins_pipe(loadPollP);
+%}
+#else
+// rather than KILL R12, it would be better to use any reg as
+// TEMP. Can't do that at this point because it crashes the compiler
+instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{
+  match(SafePoint poll);
+  effect(USE poll, KILL tmp, KILL icc);
+
+  size(4);
+  format %{ "LDR   $tmp,[$poll]\t! Safepoint: poll for GC" %}
+  ins_encode %{
+    __ relocate(relocInfo::poll_type);
+    __ ldr($tmp$$Register, Address($poll$$Register));
+  %}
+  ins_pipe(loadPollP);
+%}
+#endif
+
+
+// ============================================================================
+// Call Instructions
+// Call Java Static Instruction
+instruct CallStaticJavaDirect( method meth ) %{
+  match(CallStaticJava);
+  predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
+  effect(USE meth);
+
+  ins_cost(CALL_COST);
+  format %{ "CALL,static ==> " %}
+  ins_encode( Java_Static_Call( meth ), call_epilog );
+  ins_pipe(simple_call);
+%}
+
+// Call Java Static Instruction (method handle version)
+instruct CallStaticJavaHandle( method meth ) %{
+  match(CallStaticJava);
+  predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
+  effect(USE meth);
+  // FP is saved by all callees (for interpreter stack correction).
+  // We use it here for a similar purpose, in {preserve,restore}_FP.
+
+  ins_cost(CALL_COST);
+  format %{ "CALL,static/MethodHandle ==> " %}
+  ins_encode( preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog );
+  ins_pipe(simple_call);
+%}
+
+// Call Java Dynamic Instruction
+instruct CallDynamicJavaDirect( method meth ) %{
+  match(CallDynamicJava);
+  effect(USE meth);
+
+  ins_cost(CALL_COST);
+  format %{ "MOV_OOP    (empty),R_R8\n\t"
+            "CALL,dynamic  ; NOP ==> " %}
+  ins_encode( Java_Dynamic_Call( meth ), call_epilog );
+  ins_pipe(call);
+%}
+
+// Call Runtime Instruction
+instruct CallRuntimeDirect(method meth) %{
+  match(CallRuntime);
+  effect(USE meth);
+  ins_cost(CALL_COST);
+  format %{ "CALL,runtime" %}
+#ifdef AARCH64
+  ins_encode( save_last_PC, Java_To_Runtime( meth ),
+              call_epilog );
+#else
+  ins_encode( Java_To_Runtime( meth ),
+              call_epilog );
+#endif
+  ins_pipe(simple_call);
+%}
+
+// Call runtime without safepoint - same as CallRuntime
+instruct CallLeafDirect(method meth) %{
+  match(CallLeaf);
+  effect(USE meth);
+  ins_cost(CALL_COST);
+  format %{ "CALL,runtime leaf" %}
+  // TODO: ned save_last_PC here?
+  ins_encode( Java_To_Runtime( meth ),
+              call_epilog );
+  ins_pipe(simple_call);
+%}
+
+// Call runtime without safepoint - same as CallLeaf
+instruct CallLeafNoFPDirect(method meth) %{
+  match(CallLeafNoFP);
+  effect(USE meth);
+  ins_cost(CALL_COST);
+  format %{ "CALL,runtime leaf nofp" %}
+  // TODO: ned save_last_PC here?
+  ins_encode( Java_To_Runtime( meth ),
+              call_epilog );
+  ins_pipe(simple_call);
+%}
+
+// Tail Call; Jump from runtime stub to Java code.
+// Also known as an 'interprocedural jump'.
+// Target of jump will eventually return to caller.
+// TailJump below removes the return address.
+instruct TailCalljmpInd(IPRegP jump_target, inline_cache_regP method_oop) %{
+  match(TailCall jump_target method_oop );
+
+  ins_cost(CALL_COST);
+  format %{ "MOV    Rexception_pc, LR\n\t"
+            "jump   $jump_target  \t! $method_oop holds method oop" %}
+  ins_encode %{
+    __ mov(Rexception_pc, LR);   // this is used only to call
+                                 // StubRoutines::forward_exception_entry()
+                                 // which expects PC of exception in
+                                 // R5. FIXME?
+    __ jump($jump_target$$Register);
+  %}
+  ins_pipe(tail_call);
+%}
+
+
+// Return Instruction
+instruct Ret() %{
+  match(Return);
+
+  format %{ "ret LR" %}
+
+  ins_encode %{
+    __ ret(LR);
+  %}
+
+  ins_pipe(br);
+%}
+
+
+// Tail Jump; remove the return address; jump to target.
+// TailCall above leaves the return address around.
+// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2).
+// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a
+// "restore" before this instruction (in Epilogue), we need to materialize it
+// in %i0.
+instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{
+  match( TailJump jump_target ex_oop );
+  ins_cost(CALL_COST);
+  format %{ "MOV    Rexception_pc, LR\n\t"
+            "jump   $jump_target \t! $ex_oop holds exc. oop" %}
+  ins_encode %{
+    __ mov(Rexception_pc, LR);
+    __ jump($jump_target$$Register);
+  %}
+  ins_pipe(tail_call);
+%}
+
+// Create exception oop: created by stack-crawling runtime code.
+// Created exception is now available to this handler, and is setup
+// just prior to jumping to this handler.  No code emitted.
+instruct CreateException( RExceptionRegP ex_oop )
+%{
+  match(Set ex_oop (CreateEx));
+  ins_cost(0);
+
+  size(0);
+  // use the following format syntax
+  format %{ "! exception oop is in Rexception_obj; no code emitted" %}
+  ins_encode();
+  ins_pipe(empty);
+%}
+
+
+// Rethrow exception:
+// The exception oop will come in the first argument position.
+// Then JUMP (not call) to the rethrow stub code.
+instruct RethrowException()
+%{
+  match(Rethrow);
+  ins_cost(CALL_COST);
+
+  // use the following format syntax
+  format %{ "b    rethrow_stub" %}
+  ins_encode %{
+    Register scratch = R1_tmp;
+    assert_different_registers(scratch, c_rarg0, LR);
+    __ jump(OptoRuntime::rethrow_stub(), relocInfo::runtime_call_type, scratch);
+  %}
+  ins_pipe(tail_call);
+%}
+
+
+// Die now
+instruct ShouldNotReachHere( )
+%{
+  match(Halt);
+  ins_cost(CALL_COST);
+
+  size(4);
+  // Use the following format syntax
+  format %{ "breakpoint   ; ShouldNotReachHere" %}
+  ins_encode %{
+    __ breakpoint();
+  %}
+  ins_pipe(tail_call);
+%}
+
+// ============================================================================
+// The 2nd slow-half of a subtype check.  Scan the subklass's 2ndary superklass
+// array for an instance of the superklass.  Set a hidden internal cache on a
+// hit (cache is checked with exposed code in gen_subtype_check()).  Return
+// not zero for a miss or zero for a hit.  The encoding ALSO sets flags.
+instruct partialSubtypeCheck( R0RegP index, R1RegP sub, R2RegP super, flagsRegP pcc, LRRegP lr ) %{
+  match(Set index (PartialSubtypeCheck sub super));
+  effect( KILL pcc, KILL lr );
+  ins_cost(DEFAULT_COST*10);
+  format %{ "CALL   PartialSubtypeCheck" %}
+  ins_encode %{
+    __ call(StubRoutines::Arm::partial_subtype_check(), relocInfo::runtime_call_type);
+  %}
+  ins_pipe(partial_subtype_check_pipe);
+%}
+
+/* instruct partialSubtypeCheck_vs_zero( flagsRegP pcc, o1RegP sub, o2RegP super, immP0 zero, o0RegP idx, o7RegP o7 ) %{ */
+/*   match(Set pcc (CmpP (PartialSubtypeCheck sub super) zero)); */
+/*   ins_pipe(partial_subtype_check_pipe); */
+/* %} */
+
+
+// ============================================================================
+// inlined locking and unlocking
+
+#ifdef AARCH64
+instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch, iRegP scratch3 )
+#else
+instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch )
+#endif
+%{
+  match(Set pcc (FastLock object box));
+
+#ifdef AARCH64
+  effect(TEMP scratch, TEMP scratch2, TEMP scratch3);
+#else
+  effect(TEMP scratch, TEMP scratch2);
+#endif
+  ins_cost(100);
+
+#ifdef AARCH64
+  format %{ "FASTLOCK  $object, $box; KILL $scratch, $scratch2, $scratch3" %}
+  ins_encode %{
+    __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$Register);
+  %}
+#else
+  format %{ "FASTLOCK  $object, $box; KILL $scratch, $scratch2" %}
+  ins_encode %{
+    __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
+  %}
+#endif
+  ins_pipe(long_memory_op);
+%}
+
+
+#ifdef AARCH64
+instruct cmpFastUnlock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch, iRegP scratch3 ) %{
+  match(Set pcc (FastUnlock object box));
+  effect(TEMP scratch, TEMP scratch2, TEMP scratch3);
+  ins_cost(100);
+
+  format %{ "FASTUNLOCK  $object, $box; KILL $scratch, $scratch2, $scratch3" %}
+  ins_encode %{
+    __ fast_unlock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$Register);
+  %}
+  ins_pipe(long_memory_op);
+%}
+#else
+instruct cmpFastUnlock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch ) %{
+  match(Set pcc (FastUnlock object box));
+  effect(TEMP scratch, TEMP scratch2);
+  ins_cost(100);
+
+  format %{ "FASTUNLOCK  $object, $box; KILL $scratch, $scratch2" %}
+  ins_encode %{
+    __ fast_unlock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
+  %}
+  ins_pipe(long_memory_op);
+%}
+#endif
+
+#ifdef AARCH64
+// TODO: add version that takes immI cnt?
+instruct clear_array(iRegX cnt, iRegP base, iRegP ptr, iRegX temp, Universe dummy, flagsReg cpsr) %{
+  match(Set dummy (ClearArray cnt base));
+  effect(TEMP temp, TEMP ptr, KILL cpsr);
+  ins_cost(300);
+  format %{
+      "        MOV    $temp,$cnt\n"
+      "        ADD    $ptr,$base,$cnt\n"
+      "        SUBS   $temp,$temp,16\t! Count down dword pair in bytes\n"
+      "        B.lt   done16\n"
+      "loop:   STP    ZR,ZR,[$ptr,-16]!\n"
+      "        SUBS   $temp,$temp,16\t! Count down dword pair in bytes\n"
+      "        B.ge   loop\t! Clearing loop\n"
+      "done16: ADDS   $temp,$temp,8\t! Room for 1 more long?\n"
+      "        B.lt   done\n"
+      "        STR    ZR,[$base+$temp]\n"
+      "done:"
+  %}
+  ins_encode %{
+    // TODO: preload?
+    __ mov($temp$$Register, $cnt$$Register);
+    __ add($ptr$$Register, $base$$Register, $cnt$$Register);
+    Label loop, done, done16;
+    __ subs($temp$$Register, $temp$$Register, 16);
+    __ b(done16, lt);
+    __ bind(loop);
+    __ stp(ZR, ZR, Address($ptr$$Register, -16, pre_indexed));
+    __ subs($temp$$Register, $temp$$Register, 16);
+    __ b(loop, ge);
+    __ bind(done16);
+    __ adds($temp$$Register, $temp$$Register, 8);
+    __ b(done, lt);
+    // $temp should be 0 here
+    __ str(ZR, Address($base$$Register, $temp$$Register));
+    __ bind(done);
+  %}
+  ins_pipe(long_memory_op);
+%}
+#else
+// Count and Base registers are fixed because the allocator cannot
+// kill unknown registers.  The encodings are generic.
+instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dummy, flagsReg cpsr) %{
+  match(Set dummy (ClearArray cnt base));
+  effect(TEMP temp, TEMP zero, KILL cpsr);
+  ins_cost(300);
+  format %{ "MOV    $zero,0\n"
+      "        MOV    $temp,$cnt\n"
+      "loop:   SUBS   $temp,$temp,4\t! Count down a dword of bytes\n"
+      "        STR.ge $zero,[$base+$temp]\t! delay slot"
+      "        B.gt   loop\t\t! Clearing loop\n" %}
+  ins_encode %{
+    __ mov($zero$$Register, 0);
+    __ mov($temp$$Register, $cnt$$Register);
+    Label(loop);
+    __ bind(loop);
+    __ subs($temp$$Register, $temp$$Register, 4);
+    __ str($zero$$Register, Address($base$$Register, $temp$$Register), ge);
+    __ b(loop, gt);
+  %}
+  ins_pipe(long_memory_op);
+%}
+#endif
+
+#ifdef XXX
+// FIXME: Why R0/R1/R2/R3?
+instruct string_compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result,
+                        iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
+  predicate(!CompactStrings);
+  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, TEMP tmp1, TEMP tmp2);
+  ins_cost(300);
+  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   // TEMP $tmp1, $tmp2" %}
+  ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2) );
+
+  ins_pipe(long_memory_op);
+%}
+
+// FIXME: Why R0/R1/R2?
+instruct string_equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2,
+                       flagsReg ccr) %{
+  predicate(!CompactStrings);
+  match(Set result (StrEquals (Binary str1 str2) cnt));
+  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp1, TEMP tmp2, TEMP result, KILL ccr);
+
+  ins_cost(300);
+  format %{ "String Equals $str1,$str2,$cnt -> $result   // TEMP $tmp1, $tmp2" %}
+  ins_encode( enc_String_Equals(str1, str2, cnt, result, tmp1, tmp2) );
+  ins_pipe(long_memory_op);
+%}
+
+// FIXME: Why R0/R1?
+instruct array_equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result,
+                      flagsReg ccr) %{
+  predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
+  match(Set result (AryEq ary1 ary2));
+  effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP result, KILL ccr);
+
+  ins_cost(300);
+  format %{ "Array Equals $ary1,$ary2 -> $result   // TEMP $tmp1,$tmp2,$tmp3" %}
+  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, result));
+  ins_pipe(long_memory_op);
+%}
+#endif
+
+//---------- Zeros Count Instructions ------------------------------------------
+
+instruct countLeadingZerosI(iRegI dst, iRegI src) %{
+  match(Set dst (CountLeadingZerosI src));
+  size(4);
+  format %{ "CLZ_32 $dst,$src" %}
+  ins_encode %{
+    __ clz_32($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifdef AARCH64
+instruct countLeadingZerosL(iRegI dst, iRegL src) %{
+  match(Set dst (CountLeadingZerosL src));
+  size(4);
+  format %{ "CLZ $dst,$src" %}
+  ins_encode %{
+    __ clz($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#else
+instruct countLeadingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
+  match(Set dst (CountLeadingZerosL src));
+  effect(TEMP tmp, TEMP dst, KILL ccr);
+  size(16);
+  format %{ "CLZ    $dst,$src.hi\n\t"
+            "TEQ    $dst,32\n\t"
+            "CLZ.eq $tmp,$src.lo\n\t"
+            "ADD.eq $dst, $dst, $tmp\n\t" %}
+  ins_encode %{
+    __ clz($dst$$Register, $src$$Register->successor());
+    __ teq($dst$$Register, 32);
+    __ clz($tmp$$Register, $src$$Register, eq);
+    __ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+instruct countTrailingZerosI(iRegI dst, iRegI src, iRegI tmp) %{
+  match(Set dst (CountTrailingZerosI src));
+  effect(TEMP tmp);
+  size(8);
+  format %{ "RBIT_32 $tmp, $src\n\t"
+            "CLZ_32  $dst,$tmp" %}
+  ins_encode %{
+    __ rbit_32($tmp$$Register, $src$$Register);
+    __ clz_32($dst$$Register, $tmp$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+
+#ifdef AARCH64
+instruct countTrailingZerosL(iRegI dst, iRegL src, iRegL tmp) %{
+  match(Set dst (CountTrailingZerosL src));
+  effect(TEMP tmp);
+  size(8);
+  format %{ "RBIT $tmp, $src\n\t"
+            "CLZ  $dst,$tmp" %}
+  ins_encode %{
+    __ rbit($tmp$$Register, $src$$Register);
+    __ clz($dst$$Register, $tmp$$Register);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#else
+instruct countTrailingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
+  match(Set dst (CountTrailingZerosL src));
+  effect(TEMP tmp, TEMP dst, KILL ccr);
+  size(24);
+  format %{ "RBIT   $tmp,$src.lo\n\t"
+            "CLZ    $dst,$tmp\n\t"
+            "TEQ    $dst,32\n\t"
+            "RBIT   $tmp,$src.hi\n\t"
+            "CLZ.eq $tmp,$tmp\n\t"
+            "ADD.eq $dst,$dst,$tmp\n\t" %}
+  ins_encode %{
+    __ rbit($tmp$$Register, $src$$Register);
+    __ clz($dst$$Register, $tmp$$Register);
+    __ teq($dst$$Register, 32);
+    __ rbit($tmp$$Register, $src$$Register->successor());
+    __ clz($tmp$$Register, $tmp$$Register, eq);
+    __ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+
+//---------- Population Count Instructions -------------------------------------
+
+#ifdef AARCH64
+instruct popCountI(iRegI dst, iRegI src, regD_low tmp) %{
+  predicate(UsePopCountInstruction);
+  match(Set dst (PopCountI src));
+  effect(TEMP tmp);
+  size(20);
+
+  format %{ "MOV_W      $dst,$src\n\t"
+            "FMOV_dx    $tmp,$dst\n\t"
+            "VCNT       $tmp.8B,$tmp.8B\n\t"
+            "ADDV       $tmp.B,$tmp.8B\n\t"
+            "FMRS       $dst,$tmp" %}
+
+  ins_encode %{
+    __ mov_w($dst$$Register, $src$$Register);
+    __ fmov_dx($tmp$$FloatRegister, $dst$$Register);
+    int quad = 0;
+    int cnt_size = 0; // VELEM_SIZE_8
+    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister, quad, cnt_size);
+    int add_size = 0; // VELEM_SIZE_8
+    __ addv($tmp$$FloatRegister, $tmp$$FloatRegister, quad, add_size);
+    __ fmrs($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#else
+instruct popCountI(iRegI dst, iRegI src, regD_low tmp) %{
+  predicate(UsePopCountInstruction);
+  match(Set dst (PopCountI src));
+  effect(TEMP tmp);
+
+  format %{ "FMSR       $tmp,$src\n\t"
+            "VCNT.8     $tmp,$tmp\n\t"
+            "VPADDL.U8  $tmp,$tmp\n\t"
+            "VPADDL.U16 $tmp,$tmp\n\t"
+            "FMRS       $dst,$tmp" %}
+  size(20);
+
+  ins_encode %{
+    __ fmsr($tmp$$FloatRegister, $src$$Register);
+    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
+    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
+    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
+    __ fmrs($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif
+
+#ifdef AARCH64
+instruct popCountL(iRegI dst, iRegL src, regD tmp) %{
+  predicate(UsePopCountInstruction);
+  match(Set dst (PopCountL src));
+  effect(TEMP tmp);
+  size(16);
+
+  format %{ "FMOV_dx    $tmp,$src\n\t"
+            "VCNT       $tmp.8B,$tmp.8B\n\t"
+            "ADDV       $tmp.B,$tmp.8B\n\t"
+            "FMOV_ws    $dst,$tmp" %}
+
+  ins_encode %{
+    __ fmov_dx($tmp$$FloatRegister, $src$$Register);
+    int quad = 0;
+    int cnt_size = 0;
+    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister, quad, cnt_size);
+    int add_size = 0;
+    __ addv($tmp$$FloatRegister, $tmp$$FloatRegister, quad, add_size);
+    __ fmov_ws($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#else
+// Note: Long.bitCount(long) returns an int.
+instruct popCountL(iRegI dst, iRegL src, regD_low tmp) %{
+  predicate(UsePopCountInstruction);
+  match(Set dst (PopCountL src));
+  effect(TEMP tmp);
+
+  format %{ "FMDRR       $tmp,$src.lo,$src.hi\n\t"
+            "VCNT.8      $tmp,$tmp\n\t"
+            "VPADDL.U8   $tmp,$tmp\n\t"
+            "VPADDL.U16  $tmp,$tmp\n\t"
+            "VPADDL.U32  $tmp,$tmp\n\t"
+            "FMRS        $dst,$tmp" %}
+
+  size(32);
+
+  ins_encode %{
+    __ fmdrr($tmp$$FloatRegister, $src$$Register, $src$$Register->successor());
+    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
+    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
+    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
+    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 32, 0);
+    __ fmrs($dst$$Register, $tmp$$FloatRegister);
+  %}
+  ins_pipe(ialu_reg);
+%}
+#endif
+
+
+// ============================================================================
+//------------Bytes reverse--------------------------------------------------
+
+instruct bytes_reverse_int(iRegI dst, iRegI src) %{
+  match(Set dst (ReverseBytesI src));
+
+  size(4);
+  format %{ "REV32 $dst,$src" %}
+  ins_encode %{
+#ifdef AARCH64
+    __ rev_w($dst$$Register, $src$$Register);
+    // high 32 bits zeroed, not sign extended
+#else
+    __ rev($dst$$Register, $src$$Register);
+#endif
+  %}
+  ins_pipe( iload_mem ); // FIXME
+%}
+
+instruct bytes_reverse_long(iRegL dst, iRegL src) %{
+  match(Set dst (ReverseBytesL src));
+#ifdef AARCH64
+//size(4);
+  format %{ "REV $dst,$src"  %}
+  ins_encode %{
+    __ rev($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg_reg); // FIXME
+#else
+  effect(TEMP dst);
+  size(8);
+  format %{ "REV $dst.lo,$src.lo\n\t"
+            "REV $dst.hi,$src.hi" %}
+  ins_encode %{
+    __ rev($dst$$Register, $src$$Register->successor());
+    __ rev($dst$$Register->successor(), $src$$Register);
+  %}
+  ins_pipe( iload_mem ); // FIXME
+#endif
+%}
+
+instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{
+  match(Set dst (ReverseBytesUS src));
+#ifdef AARCH64
+  size(4);
+  format %{ "REV16_W $dst,$src" %}
+  ins_encode %{
+    __ rev16_w($dst$$Register, $src$$Register);
+    // high 32 bits zeroed
+  %}
+#else
+  size(4);
+  format %{ "REV16 $dst,$src" %}
+  ins_encode %{
+    __ rev16($dst$$Register, $src$$Register);
+  %}
+#endif
+  ins_pipe( iload_mem ); // FIXME
+%}
+
+instruct bytes_reverse_short(iRegI dst, iRegI src) %{
+  match(Set dst (ReverseBytesS src));
+#ifdef AARCH64
+  size(8);
+  format %{ "REV16_W $dst,$src\n\t"
+            "SIGN_EXT16 $dst" %}
+  ins_encode %{
+    __ rev16_w($dst$$Register, $src$$Register);
+    __ sign_extend($dst$$Register, $dst$$Register, 16);
+  %}
+#else
+  size(4);
+  format %{ "REVSH $dst,$src" %}
+  ins_encode %{
+    __ revsh($dst$$Register, $src$$Register);
+  %}
+#endif
+  ins_pipe( iload_mem ); // FIXME
+%}
+
+
+// ====================VECTOR INSTRUCTIONS=====================================
+
+// Load Aligned Packed values into a Double Register
+instruct loadV8(vecD dst, memoryD mem) %{
+  predicate(n->as_LoadVector()->memory_size() == 8);
+  match(Set dst (LoadVector mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "FLDD   $mem,$dst\t! load vector (8 bytes)" %}
+  ins_encode %{
+    __ ldr_double($dst$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(floadD_mem);
+%}
+
+// Load Aligned Packed values into a Double Register Pair
+instruct loadV16(vecX dst, memoryvld mem) %{
+  predicate(n->as_LoadVector()->memory_size() == 16);
+  match(Set dst (LoadVector mem));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "VLD1   $mem,$dst.Q\t! load vector (16 bytes)" %}
+  ins_encode %{
+    __ vld1($dst$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
+  %}
+  ins_pipe(floadD_mem); // FIXME
+%}
+
+// Store Vector in Double register to memory
+instruct storeV8(memoryD mem, vecD src) %{
+  predicate(n->as_StoreVector()->memory_size() == 8);
+  match(Set mem (StoreVector mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "FSTD   $src,$mem\t! store vector (8 bytes)" %}
+  ins_encode %{
+    __ str_double($src$$FloatRegister, $mem$$Address);
+  %}
+  ins_pipe(fstoreD_mem_reg);
+%}
+
+// Store Vector in Double Register Pair to memory
+instruct storeV16(memoryvld mem, vecX src) %{
+  predicate(n->as_StoreVector()->memory_size() == 16);
+  match(Set mem (StoreVector mem src));
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+  format %{ "VST1   $src,$mem\t! store vector (16 bytes)" %}
+  ins_encode %{
+    __ vst1($src$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
+  %}
+  ins_pipe(fstoreD_mem_reg); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar to packed byte values in Double register
+instruct Repl8B_reg(vecD dst, iRegI src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (ReplicateB src));
+  ins_cost(DEFAULT_COST*4);
+  effect(TEMP tmp);
+  size(16);
+
+  // FIXME: could use PKH instruction instead?
+  format %{ "LSL      $tmp, $src, 24 \n\t"
+            "OR       $tmp, $tmp, ($tmp >> 8) \n\t"
+            "OR       $tmp, $tmp, ($tmp >> 16) \n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode %{
+    __ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 24));
+    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 8));
+    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
+    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar to packed byte values in Double register
+instruct Repl8B_reg_simd(vecD dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateB src));
+  size(4);
+
+  format %{ "VDUP.8 $dst,$src\t" %}
+  ins_encode %{
+    bool quad = false;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// Replicate scalar to packed byte values in Double register pair
+instruct Repl16B_reg(vecX dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16);
+  match(Set dst (ReplicateB src));
+  size(4);
+
+  format %{ "VDUP.8 $dst.Q,$src\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar constant to packed byte values in Double register
+instruct Repl8B_immI(vecD dst, immI src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (ReplicateB src));
+  ins_cost(DEFAULT_COST*2);
+  effect(TEMP tmp);
+  size(12);
+
+  format %{ "MOV      $tmp, Repl4($src))\n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode( LdReplImmI(src, dst, tmp, (4), (1)) );
+  ins_pipe(loadConFD); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar constant to packed byte values in Double register
+// TODO: support negative constants with MVNI?
+instruct Repl8B_immU8(vecD dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateB src));
+  size(4);
+
+  format %{ "VMOV.U8  $dst,$src" %}
+  ins_encode %{
+    bool quad = false;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+// Replicate scalar constant to packed byte values in Double register pair
+instruct Repl16B_immU8(vecX dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateB src));
+  size(4);
+
+  format %{ "VMOV.U8  $dst.Q,$src" %}
+  ins_encode %{
+    bool quad = true;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar to packed short/char values into Double register
+instruct Repl4S_reg(vecD dst, iRegI src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (ReplicateS src));
+  ins_cost(DEFAULT_COST*3);
+  effect(TEMP tmp);
+  size(12);
+
+  // FIXME: could use PKH instruction instead?
+  format %{ "LSL      $tmp, $src, 16 \n\t"
+            "OR       $tmp, $tmp, ($tmp >> 16) \n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode %{
+    __ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 16));
+    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
+    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar to packed byte values in Double register
+instruct Repl4S_reg_simd(vecD dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateS src));
+  size(4);
+
+  format %{ "VDUP.16 $dst,$src\t" %}
+  ins_encode %{
+    bool quad = false;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// Replicate scalar to packed byte values in Double register pair
+instruct Repl8S_reg(vecX dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateS src));
+  size(4);
+
+  format %{ "VDUP.16 $dst.Q,$src\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+
+#ifndef AARCH64
+// Replicate scalar constant to packed short/char values in Double register
+instruct Repl4S_immI(vecD dst, immI src, iRegP tmp) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (ReplicateS src));
+  effect(TEMP tmp);
+  size(12);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "MOV      $tmp, Repl2($src))\n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode( LdReplImmI(src, dst, tmp, (2), (2)) );
+  ins_pipe(loadConFD); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar constant to packed byte values in Double register
+instruct Repl4S_immU8(vecD dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateS src));
+  size(4);
+
+  format %{ "VMOV.U16  $dst,$src" %}
+  ins_encode %{
+    bool quad = false;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+// Replicate scalar constant to packed byte values in Double register pair
+instruct Repl8S_immU8(vecX dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateS src));
+  size(4);
+
+  format %{ "VMOV.U16  $dst.Q,$src" %}
+  ins_encode %{
+    bool quad = true;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar to packed int values in Double register
+instruct Repl2I_reg(vecD dst, iRegI src) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateI src));
+  size(4);
+
+  format %{ "FMDRR    $dst,$src,$src\t" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// Replicate scalar to packed int values in Double register pair
+instruct Repl4I_reg(vecX dst, iRegI src) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (ReplicateI src));
+  ins_cost(DEFAULT_COST*2);
+  size(8);
+
+  format %{ "FMDRR    $dst.lo,$src,$src\n\t"
+            "FMDRR    $dst.hi,$src,$src" %}
+
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
+    __ fmdrr($dst$$FloatRegister->successor()->successor(),
+             $src$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar to packed int values in Double register
+instruct Repl2I_reg_simd(vecD dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateI src));
+  size(4);
+
+  format %{ "VDUP.32 $dst.D,$src\t" %}
+  ins_encode %{
+    bool quad = false;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// Replicate scalar to packed int values in Double register pair
+instruct Repl4I_reg_simd(vecX dst, iRegI src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateI src));
+  size(4);
+
+  format %{ "VDUP.32 $dst.Q,$src\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+
+#ifndef AARCH64
+// Replicate scalar zero constant to packed int values in Double register
+instruct Repl2I_immI(vecD dst, immI src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateI src));
+  effect(TEMP tmp);
+  size(12);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "MOV      $tmp, Repl1($src))\n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode( LdReplImmI(src, dst, tmp, (1), (4)) );
+  ins_pipe(loadConFD); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar constant to packed byte values in Double register
+instruct Repl2I_immU8(vecD dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateI src));
+  size(4);
+
+  format %{ "VMOV.I32  $dst.D,$src" %}
+  ins_encode %{
+    bool quad = false;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+// Replicate scalar constant to packed byte values in Double register pair
+instruct Repl4I_immU8(vecX dst, immU8 src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateI src));
+  size(4);
+
+  format %{ "VMOV.I32  $dst.Q,$src" %}
+  ins_encode %{
+    bool quad = true;
+    __ vmovI($dst$$FloatRegister, $src$$constant,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe(loadConFD); // FIXME
+%}
+
+#ifdef AARCH64
+// Replicate scalar to packed byte values in Double register pair
+instruct Repl2L_reg(vecX dst, iRegL src) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateL src));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "VDUP.2D $dst.Q,$src\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupI($dst$$FloatRegister, $src$$Register,
+             MacroAssembler::VELEM_SIZE_64, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#else /* !AARCH64 */
+// Replicate scalar to packed byte values in Double register pair
+instruct Repl2L_reg(vecX dst, iRegL src) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateL src));
+  size(8);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FMDRR $dst.D,$src.lo,$src.hi\t\n"
+            "FMDRR $dst.D.next,$src.lo,$src.hi" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
+    __ fmdrr($dst$$FloatRegister->successor()->successor(),
+             $src$$Register, $src$$Register->successor());
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+
+// Replicate scalar to packed float values in Double register
+instruct Repl2F_regI(vecD dst, iRegI src) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateF src));
+  size(4);
+
+  format %{ "FMDRR    $dst.D,$src,$src\t" %}
+  ins_encode %{
+    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// Replicate scalar to packed float values in Double register
+instruct Repl2F_reg_vfp(vecD dst, regF src) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateF src));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  expand %{
+    iRegI tmp;
+    MoveF2I_reg_reg(tmp, src);
+    Repl2F_regI(dst,tmp);
+  %}
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar to packed float values in Double register
+instruct Repl2F_reg_simd(vecD dst, regF src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (ReplicateF src));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+
+  format %{ "VDUP.32  $dst.D,$src.D\t" %}
+  ins_encode %{
+    bool quad = false;
+    __ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar to packed float values in Double register pair
+instruct Repl4F_reg(vecX dst, regF src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (ReplicateF src));
+  effect(TEMP tmp);
+  size(4*3);
+  ins_cost(DEFAULT_COST*3); // FIXME
+
+  format %{ "FMRS     $tmp,$src\n\t"
+            "FMDRR    $dst.D,$tmp,$tmp\n\t"
+            "FMDRR    $dst.D.next,$tmp,$tmp\t" %}
+  ins_encode %{
+    __ fmrs($tmp$$Register, $src$$FloatRegister);
+    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
+    __ fmdrr($dst$$FloatRegister->successor()->successor(),
+             $tmp$$Register, $tmp$$Register);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+#endif /* !AARCH64 */
+
+// Replicate scalar to packed float values in Double register pair
+instruct Repl4F_reg_simd(vecX dst, regF src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (ReplicateF src));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+
+  format %{ "VDUP.32  $dst.Q,$src.D\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
+  %}
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+#ifndef AARCH64
+// Replicate scalar zero constant to packed float values in Double register
+instruct Repl2F_immI(vecD dst, immF src, iRegI tmp) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateF src));
+  effect(TEMP tmp);
+  size(12);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "MOV      $tmp, Repl1($src))\n\t"
+            "FMDRR    $dst,$tmp,$tmp\t" %}
+  ins_encode( LdReplImmF(src, dst, tmp) );
+  ins_pipe(loadConFD); // FIXME
+%}
+#endif /* !AAARCH64 */
+
+// Replicate scalar to packed double float values in Double register pair
+instruct Repl2D_reg(vecX dst, regD src) %{
+#ifdef AARCH64
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (ReplicateD src));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "VDUP     $dst.2D,$src\t" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupD($dst$$FloatRegister, $src$$FloatRegister, quad);
+  %}
+#else
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (ReplicateD src));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FCPYD    $dst.D.a,$src\n\t"
+            "FCPYD    $dst.D.b,$src\t" %}
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src = $src$$FloatRegister;
+    __ fcpyd(dsta, src);
+    FloatRegister dstb = dsta->successor()->successor();
+    __ fcpyd(dstb, src);
+  %}
+#endif
+  ins_pipe(ialu_reg); // FIXME
+%}
+
+// ====================VECTOR ARITHMETIC=======================================
+
+// --------------------------------- ADD --------------------------------------
+
+// Bytes vector add
+instruct vadd8B_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (AddVB src1 src2));
+  format %{ "VADD.I8 $dst,$src1,$src2\t! add packed8B" %}
+  size(4);
+  ins_encode %{
+    bool quad = false;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (AddVB src1 src2));
+  size(4);
+  format %{ "VADD.I8 $dst.Q,$src1.Q,$src2.Q\t! add packed16B" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts/Chars vector add
+instruct vadd4S_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (AddVS src1 src2));
+  size(4);
+  format %{ "VADD.I16 $dst,$src1,$src2\t! add packed4S" %}
+  ins_encode %{
+    bool quad = false;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (AddVS src1 src2));
+  size(4);
+  format %{ "VADD.I16 $dst.Q,$src1.Q,$src2.Q\t! add packed8S" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector add
+instruct vadd2I_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (AddVI src1 src2));
+  size(4);
+  format %{ "VADD.I32 $dst.D,$src1.D,$src2.D\t! add packed2I" %}
+  ins_encode %{
+    bool quad = false;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vadd4I_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (AddVI src1 src2));
+  size(4);
+  format %{ "VADD.I32 $dst.Q,$src1.Q,$src2.Q\t! add packed4I" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector add
+instruct vadd2L_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (AddVL src1 src2));
+  size(4);
+  format %{ "VADD.I64 $dst.Q,$src1.Q,$src2.Q\t! add packed2L" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_64, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Floats vector add
+instruct vadd2F_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
+  match(Set dst (AddVF src1 src2));
+  size(4);
+  format %{ "VADD.F32 $dst,$src1,$src2\t! add packed2F" %}
+  ins_encode %{
+    bool quad = false;
+    __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+  ins_pipe( faddD_reg_reg ); // FIXME
+%}
+
+#ifndef AARCH64
+instruct vadd2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (AddVF src1 src2));
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  size(4*2);
+  format %{ "FADDS  $dst.a,$src1.a,$src2.a\n\t"
+            "FADDS  $dst.b,$src1.b,$src2.b" %}
+  ins_encode %{
+    __ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+    __ add_float($dst$$FloatRegister->successor(),
+             $src1$$FloatRegister->successor(),
+             $src2$$FloatRegister->successor());
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+#endif
+
+instruct vadd4F_reg_simd(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
+  match(Set dst (AddVF src1 src2));
+  size(4);
+  format %{ "VADD.F32 $dst.Q,$src1.Q,$src2.Q\t! add packed4F" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+  ins_pipe( faddD_reg_reg ); // FIXME
+%}
+
+#ifdef AARCH64
+instruct vadd2D_reg_simd(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
+  match(Set dst (AddVD src1 src2));
+  size(4);
+  format %{ "VADD.F64 $dst.Q,$src1.Q,$src2.Q\t! add packed2D" %}
+  ins_encode %{
+    bool quad = true;
+    __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F64, quad);
+  %}
+  ins_pipe( faddD_reg_reg ); // FIXME
+%}
+#else
+instruct vadd4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (AddVF src1 src2));
+  size(4*4);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "FADDS  $dst.a,$src1.a,$src2.a\n\t"
+            "FADDS  $dst.b,$src1.b,$src2.b\n\t"
+            "FADDS  $dst.c,$src1.c,$src2.c\n\t"
+            "FADDS  $dst.d,$src1.d,$src2.d" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ add_float(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor();
+    FloatRegister src1b = src1a->successor();
+    FloatRegister src2b = src2a->successor();
+    __ add_float(dstb, src1b, src2b);
+    FloatRegister dstc = dstb->successor();
+    FloatRegister src1c = src1b->successor();
+    FloatRegister src2c = src2b->successor();
+    __ add_float(dstc, src1c, src2c);
+    FloatRegister dstd = dstc->successor();
+    FloatRegister src1d = src1c->successor();
+    FloatRegister src2d = src2c->successor();
+    __ add_float(dstd, src1d, src2d);
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+
+instruct vadd2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (AddVD src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FADDD  $dst.a,$src1.a,$src2.a\n\t"
+            "FADDD  $dst.b,$src1.b,$src2.b" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ add_double(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor()->successor();
+    FloatRegister src1b = src1a->successor()->successor();
+    FloatRegister src2b = src2a->successor()->successor();
+    __ add_double(dstb, src1b, src2b);
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+#endif
+
+
+// Bytes vector sub
+instruct vsub8B_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (SubVB src1 src2));
+  size(4);
+  format %{ "VSUB.I8 $dst,$src1,$src2\t! sub packed8B" %}
+  ins_encode %{
+    bool quad = false;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (SubVB src1 src2));
+  size(4);
+  format %{ "VSUB.I8 $dst.Q,$src1.Q,$src2.Q\t! sub packed16B" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts/Chars vector sub
+instruct vsub4S_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (SubVS src1 src2));
+  size(4);
+  format %{ "VSUB.I16 $dst,$src1,$src2\t! sub packed4S" %}
+  ins_encode %{
+    bool quad = false;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsub16S_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (SubVS src1 src2));
+  size(4);
+  format %{ "VSUB.I16 $dst.Q,$src1.Q,$src2.Q\t! sub packed8S" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector sub
+instruct vsub2I_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (SubVI src1 src2));
+  size(4);
+  format %{ "VSUB.I32 $dst,$src1,$src2\t! sub packed2I" %}
+  ins_encode %{
+    bool quad = false;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsub4I_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (SubVI src1 src2));
+  size(4);
+  format %{ "VSUB.I32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4I" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector sub
+instruct vsub2L_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (SubVL src1 src2));
+  size(4);
+  format %{ "VSUB.I64 $dst.Q,$src1.Q,$src2.Q\t! sub packed2L" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_64, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Floats vector sub
+instruct vsub2F_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
+  match(Set dst (SubVF src1 src2));
+  size(4);
+  format %{ "VSUB.F32 $dst,$src1,$src2\t! sub packed2F" %}
+  ins_encode %{
+    bool quad = false;
+    __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+  ins_pipe( faddF_reg_reg ); // FIXME
+%}
+
+#ifndef AARCH64
+instruct vsub2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (SubVF src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FSUBS  $dst.a,$src1.a,$src2.a\n\t"
+            "FSUBS  $dst.b,$src1.b,$src2.b" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ sub_float(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor();
+    FloatRegister src1b = src1a->successor();
+    FloatRegister src2b = src2a->successor();
+    __ sub_float(dstb, src1b, src2b);
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+#endif
+
+
+instruct vsub4F_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
+  match(Set dst (SubVF src1 src2));
+  size(4);
+  format %{ "VSUB.F32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4F" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+  ins_pipe( faddF_reg_reg ); // FIXME
+%}
+
+#ifdef AARCH64
+instruct vsub2D_reg_simd(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
+  match(Set dst (SubVD src1 src2));
+  size(4);
+  format %{ "VSUB.F64 $dst.Q,$src1.Q,$src2.Q\t! add packed2D" %}
+  ins_encode %{
+    bool quad = true;
+    __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F64, quad);
+  %}
+  ins_pipe( faddD_reg_reg ); // FIXME
+%}
+#else
+instruct vsub4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (SubVF src1 src2));
+  size(4*4);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "FSUBS  $dst.a,$src1.a,$src2.a\n\t"
+            "FSUBS  $dst.b,$src1.b,$src2.b\n\t"
+            "FSUBS  $dst.c,$src1.c,$src2.c\n\t"
+            "FSUBS  $dst.d,$src1.d,$src2.d" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ sub_float(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor();
+    FloatRegister src1b = src1a->successor();
+    FloatRegister src2b = src2a->successor();
+    __ sub_float(dstb, src1b, src2b);
+    FloatRegister dstc = dstb->successor();
+    FloatRegister src1c = src1b->successor();
+    FloatRegister src2c = src2b->successor();
+    __ sub_float(dstc, src1c, src2c);
+    FloatRegister dstd = dstc->successor();
+    FloatRegister src1d = src1c->successor();
+    FloatRegister src2d = src2c->successor();
+    __ sub_float(dstd, src1d, src2d);
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+
+instruct vsub2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (SubVD src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FSUBD  $dst.a,$src1.a,$src2.a\n\t"
+            "FSUBD  $dst.b,$src1.b,$src2.b" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ sub_double(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor()->successor();
+    FloatRegister src1b = src1a->successor()->successor();
+    FloatRegister src2b = src2a->successor()->successor();
+    __ sub_double(dstb, src1b, src2b);
+  %}
+
+  ins_pipe(faddF_reg_reg); // FIXME
+%}
+#endif
+
+// Shorts/Chars vector mul
+instruct vmul4S_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (MulVS src1 src2));
+  size(4);
+  format %{ "VMUL.I16 $dst,$src1,$src2\t! mul packed4S" %}
+  ins_encode %{
+    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, 0);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (MulVS src1 src2));
+  size(4);
+  format %{ "VMUL.I16 $dst.Q,$src1.Q,$src2.Q\t! mul packed8S" %}
+  ins_encode %{
+    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_16, 1);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector mul
+instruct vmul2I_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (MulVI src1 src2));
+  size(4);
+  format %{ "VMUL.I32 $dst,$src1,$src2\t! mul packed2I" %}
+  ins_encode %{
+    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, 0);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vmul4I_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (MulVI src1 src2));
+  size(4);
+  format %{ "VMUL.I32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4I" %}
+  ins_encode %{
+    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VELEM_SIZE_32, 1);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Floats vector mul
+instruct vmul2F_reg(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
+  match(Set dst (MulVF src1 src2));
+  size(4);
+  format %{ "VMUL.F32 $dst,$src1,$src2\t! mul packed2F" %}
+  ins_encode %{
+    __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, 0);
+  %}
+  ins_pipe( fmulF_reg_reg ); // FIXME
+%}
+
+#ifndef AARCH64
+instruct vmul2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (MulVF src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FMULS  $dst.a,$src1.a,$src2.a\n\t"
+            "FMULS  $dst.b,$src1.b,$src2.b" %}
+  ins_encode %{
+    __ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+    __ mul_float($dst$$FloatRegister->successor(),
+             $src1$$FloatRegister->successor(),
+             $src2$$FloatRegister->successor());
+  %}
+
+  ins_pipe(fmulF_reg_reg); // FIXME
+%}
+#endif
+
+instruct vmul4F_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
+  match(Set dst (MulVF src1 src2));
+  size(4);
+  format %{ "VMUL.F32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4F" %}
+  ins_encode %{
+    __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, 1);
+  %}
+  ins_pipe( fmulF_reg_reg ); // FIXME
+%}
+
+#ifndef AARCH64
+instruct vmul4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
+  match(Set dst (MulVF src1 src2));
+  size(4*4);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "FMULS  $dst.a,$src1.a,$src2.a\n\t"
+            "FMULS  $dst.b,$src1.b,$src2.b\n\t"
+            "FMULS  $dst.c,$src1.c,$src2.c\n\t"
+            "FMULS  $dst.d,$src1.d,$src2.d" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ mul_float(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor();
+    FloatRegister src1b = src1a->successor();
+    FloatRegister src2b = src2a->successor();
+    __ mul_float(dstb, src1b, src2b);
+    FloatRegister dstc = dstb->successor();
+    FloatRegister src1c = src1b->successor();
+    FloatRegister src2c = src2b->successor();
+    __ mul_float(dstc, src1c, src2c);
+    FloatRegister dstd = dstc->successor();
+    FloatRegister src1d = src1c->successor();
+    FloatRegister src2d = src2c->successor();
+    __ mul_float(dstd, src1d, src2d);
+  %}
+
+  ins_pipe(fmulF_reg_reg); // FIXME
+%}
+#endif
+
+#ifdef AARCH64
+instruct vmul2D_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (MulVD src1 src2));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "FMUL.2D $dst,$src1,$src2\t! double[2]" %}
+  ins_encode %{
+    int quad = 1;
+    __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F64, quad);
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+%}
+#else
+instruct vmul2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (MulVD src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FMULD  $dst.D.a,$src1.D.a,$src2.D.a\n\t"
+            "FMULD  $dst.D.b,$src1.D.b,$src2.D.b" %}
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ mul_double(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor()->successor();
+    FloatRegister src1b = src1a->successor()->successor();
+    FloatRegister src2b = src2a->successor()->successor();
+    __ mul_double(dstb, src1b, src2b);
+  %}
+
+  ins_pipe(fmulD_reg_reg); // FIXME
+%}
+#endif
+
+
+// Floats vector div
+instruct vdiv2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (DivVF src1 src2));
+#ifdef AARCH64
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "FDIV.2S $dst,$src1,$src2\t! float[2]" %}
+  ins_encode %{
+    int quad = 0;
+    __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+#else
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FDIVS  $dst.a,$src1.a,$src2.a\n\t"
+            "FDIVS  $dst.b,$src1.b,$src2.b" %}
+  ins_encode %{
+    __ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
+    __ div_float($dst$$FloatRegister->successor(),
+             $src1$$FloatRegister->successor(),
+             $src2$$FloatRegister->successor());
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+#endif
+%}
+
+instruct vdiv4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (DivVF src1 src2));
+#ifdef AARCH64
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "FDIV.4S $dst,$src1,$src2\t! float[4]" %}
+  ins_encode %{
+    int quad = 1;
+    __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F32, quad);
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+#else
+  size(4*4);
+  ins_cost(DEFAULT_COST*4); // FIXME
+
+  format %{ "FDIVS  $dst.a,$src1.a,$src2.a\n\t"
+            "FDIVS  $dst.b,$src1.b,$src2.b\n\t"
+            "FDIVS  $dst.c,$src1.c,$src2.c\n\t"
+            "FDIVS  $dst.d,$src1.d,$src2.d" %}
+
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ div_float(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor();
+    FloatRegister src1b = src1a->successor();
+    FloatRegister src2b = src2a->successor();
+    __ div_float(dstb, src1b, src2b);
+    FloatRegister dstc = dstb->successor();
+    FloatRegister src1c = src1b->successor();
+    FloatRegister src2c = src2b->successor();
+    __ div_float(dstc, src1c, src2c);
+    FloatRegister dstd = dstc->successor();
+    FloatRegister src1d = src1c->successor();
+    FloatRegister src2d = src2c->successor();
+    __ div_float(dstd, src1d, src2d);
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+#endif
+%}
+
+#ifdef AARCH64
+instruct vdiv2D_reg(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (DivVD src1 src2));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+
+  format %{ "FDIV.2D $dst,$src1,$src2\t! double[2]" %}
+  ins_encode %{
+    int quad = 1;
+    __ vdivF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             MacroAssembler::VFA_SIZE_F64, quad);
+  %}
+
+  ins_pipe(fdivF_reg_reg); // FIXME
+%}
+#else
+instruct vdiv2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (DivVD src1 src2));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "FDIVD  $dst.D.a,$src1.D.a,$src2.D.a\n\t"
+            "FDIVD  $dst.D.b,$src1.D.b,$src2.D.b" %}
+  ins_encode %{
+    FloatRegister dsta = $dst$$FloatRegister;
+    FloatRegister src1a = $src1$$FloatRegister;
+    FloatRegister src2a = $src2$$FloatRegister;
+    __ div_double(dsta, src1a, src2a);
+    FloatRegister dstb = dsta->successor()->successor();
+    FloatRegister src1b = src1a->successor()->successor();
+    FloatRegister src2b = src2a->successor()->successor();
+    __ div_double(dstb, src1b, src2b);
+  %}
+
+  ins_pipe(fdivD_reg_reg); // FIXME
+%}
+#endif
+
+// --------------------------------- NEG --------------------------------------
+
+instruct vneg8B_reg(vecD dst, vecD src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8);
+  effect(DEF dst, USE src);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{ "VNEG.S8 $dst.D,$src.D\t! neg packed8B" %}
+  ins_encode %{
+    bool quad = false;
+    __ vnegI($dst$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vneg16B_reg(vecX dst, vecX src) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16);
+  effect(DEF dst, USE src);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{ "VNEG.S8 $dst.Q,$src.Q\t! neg0 packed16B" %}
+  ins_encode %{
+    bool _float = false;
+    bool quad = true;
+    __ vnegI($dst$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// ------------------------------ Shift ---------------------------------------
+
+instruct vslcntD(vecD dst, iRegI cnt) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (LShiftCntV cnt));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    Repl8B_reg_simd(dst, cnt);
+  %}
+%}
+
+instruct vslcntX(vecX dst, iRegI cnt) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (LShiftCntV cnt));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    Repl16B_reg(dst, cnt);
+  %}
+%}
+
+// Low bits of vector "shift" elements are used, so it
+// doesn't matter if we treat it as ints or bytes here.
+instruct vsrcntD(vecD dst, iRegI cnt) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
+  match(Set dst (RShiftCntV cnt));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+
+  format %{ "VDUP.8 $dst.D,$cnt\n\t"
+            "VNEG.S8 $dst.D,$dst.D\t! neg packed8B" %}
+  ins_encode %{
+    bool quad = false;
+    __ vdupI($dst$$FloatRegister, $cnt$$Register,
+             MacroAssembler::VELEM_SIZE_8, quad);
+    __ vnegI($dst$$FloatRegister, $dst$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsrcntX(vecX dst, iRegI cnt) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
+  match(Set dst (RShiftCntV cnt));
+  size(4*2);
+  ins_cost(DEFAULT_COST*2); // FIXME
+  format %{ "VDUP.8 $dst.Q,$cnt\n\t"
+            "VNEG.S8 $dst.Q,$dst.Q\t! neg packed16B" %}
+  ins_encode %{
+    bool quad = true;
+    __ vdupI($dst$$FloatRegister, $cnt$$Register,
+             MacroAssembler::VELEM_SIZE_8, quad);
+    __ vnegI($dst$$FloatRegister, $dst$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Byte vector logical left/right shift based on sign
+instruct vsh8B_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U8 $dst.D,$src.D,$shift.D\t! logical left/right shift packed8B"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsh16B_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U8 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed16B"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts/Char vector logical left/right shift based on sign
+instruct vsh4S_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U16 $dst.D,$src.D,$shift.D\t! logical left/right shift packed4S"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsh8S_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U16 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed8S"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector logical left/right shift based on sign
+instruct vsh2I_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U32 $dst.D,$src.D,$shift.D\t! logical left/right shift packed2I"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsh4I_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U32 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed4I"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector logical left/right shift based on sign
+instruct vsh2L_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.U64 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed2L"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_64, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// ------------------------------ LeftShift -----------------------------------
+
+// Byte vector left shift
+instruct vsl8B_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (LShiftVB src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh8B_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl16B_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (LShiftVB src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh16B_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (LShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I8 $dst.D,$src.D,$shift\t! logical left shift packed8B"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (LShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I8 $dst.Q,$src.Q,$shift\t! logical left shift packed16B"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts/Chars vector logical left/right shift
+instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (LShiftVS src shift));
+  match(Set dst (URShiftVS src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh4S_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (LShiftVS src shift));
+  match(Set dst (URShiftVS src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh8S_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (LShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I16 $dst.D,$src.D,$shift\t! logical left shift packed4S"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsl8S_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (LShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I16 $dst.Q,$src.Q,$shift\t! logical left shift packed8S"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector logical left/right shift
+instruct vsl2I_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (LShiftVI src shift));
+  match(Set dst (URShiftVI src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh2I_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl4I_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd());
+  match(Set dst (LShiftVI src shift));
+  match(Set dst (URShiftVI src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh4I_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl2I_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (LShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I32 $dst.D,$src.D,$shift\t! logical left shift packed2I"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd());
+  match(Set dst (LShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I32 $dst.Q,$src.Q,$shift\t! logical left shift packed4I"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector logical left/right shift
+instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (LShiftVL src shift));
+  match(Set dst (URShiftVL src shift));
+  size(4*1);
+  ins_cost(DEFAULT_COST*1); // FIXME
+  expand %{
+    vsh2L_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (LShiftVL src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.I64 $dst.Q,$src.Q,$shift\t! logical left shift packed2L"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// ----------------------- LogicalRightShift -----------------------------------
+
+// Bytes/Shorts vector logical right shift produces incorrect Java result
+// for negative data because java code convert short value into int with
+// sign extension before a shift.
+
+// Chars vector logical right shift
+instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (URShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.U16 $dst.D,$src.D,$shift\t! logical right shift packed4S"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (URShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.U16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector logical right shift
+instruct vsrl2I_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
+  match(Set dst (URShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.U32 $dst.D,$src.D,$shift\t! logical right shift packed2I"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd());
+  match(Set dst (URShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.U32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector logical right shift
+instruct vsrl2L_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (URShiftVL src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.U64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// ------------------- ArithmeticRightShift -----------------------------------
+
+// Bytes vector arithmetic left/right shift based on sign
+instruct vsha8B_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S8 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed8B"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsha16B_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S8 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed16B"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_8, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts vector arithmetic left/right shift based on sign
+instruct vsha4S_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S16 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed4S"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsha8S_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S16 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed8S"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_16, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector arithmetic left/right shift based on sign
+instruct vsha2I_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S32 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed2I"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsha4I_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S32 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed4I"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_32, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector arithmetic left/right shift based on sign
+instruct vsha2L_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  effect(DEF dst, USE src, USE shift);
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHL.S64 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed2L"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
+              MacroAssembler::VELEM_SIZE_64, quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Byte vector arithmetic right shift
+
+instruct vsra8B_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (RShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha8B_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsrl16B_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (RShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha16B_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsrl8B_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (RShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S8 $dst.D,$src.D,$shift\t! logical right shift packed8B"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsrl16B_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 16);
+  match(Set dst (RShiftVB src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S8 $dst.Q,$src.Q,$shift\t! logical right shift packed16B"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Shorts vector arithmetic right shift
+instruct vsra4S_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (RShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha4S_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsra8S_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (RShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha8S_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (RShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S16 $dst.D,$src.D,$shift\t! logical right shift packed4S"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsra8S_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 8);
+  match(Set dst (RShiftVS src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Integers vector arithmetic right shift
+instruct vsra2I_reg(vecD dst, vecD src, vecD shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (RShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha2I_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsra4I_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (RShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha4I_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (RShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S32 $dst.D,$src.D,$shift\t! logical right shift packed2I"
+  %}
+  ins_encode %{
+    bool quad = false;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vsra4I_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 4);
+  match(Set dst (RShiftVI src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// Longs vector arithmetic right shift
+instruct vsra2L_reg(vecX dst, vecX src, vecX shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (RShiftVL src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  expand %{
+    vsha2L_reg(dst, src, shift);
+  %}
+%}
+
+instruct vsra2L_immI(vecX dst, vecX src, immI shift) %{
+  predicate(n->as_Vector()->length() == 2);
+  match(Set dst (RShiftVL src shift));
+  size(4);
+  ins_cost(DEFAULT_COST); // FIXME
+  format %{
+    "VSHR.S64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L"
+  %}
+  ins_encode %{
+    bool quad = true;
+    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// --------------------------------- AND --------------------------------------
+
+instruct vandD(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8);
+  match(Set dst (AndV src1 src2));
+  format %{ "VAND    $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
+  ins_encode %{
+    bool quad = false;
+    __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vandX(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16);
+  match(Set dst (AndV src1 src2));
+  format %{ "VAND    $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
+  ins_encode %{
+    bool quad = true;
+    __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// --------------------------------- OR ---------------------------------------
+
+instruct vorD(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8);
+  match(Set dst (OrV src1 src2));
+  format %{ "VOR     $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
+  ins_encode %{
+    bool quad = false;
+    __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+            quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vorX(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16);
+  match(Set dst (OrV src1 src2));
+  format %{ "VOR     $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
+  ins_encode %{
+    bool quad = true;
+    __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+            quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+// --------------------------------- XOR --------------------------------------
+
+instruct vxorD(vecD dst, vecD src1, vecD src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 8);
+  match(Set dst (XorV src1 src2));
+  format %{ "VXOR    $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
+  ins_encode %{
+    bool quad = false;
+    __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+instruct vxorX(vecX dst, vecX src1, vecX src2) %{
+  predicate(n->as_Vector()->length_in_bytes() == 16);
+  match(Set dst (XorV src1 src2));
+  format %{ "VXOR    $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
+  ins_encode %{
+    bool quad = true;
+    __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
+             quad);
+  %}
+  ins_pipe( ialu_reg_reg ); // FIXME
+%}
+
+
+//----------PEEPHOLE RULES-----------------------------------------------------
+// These must follow all instruction definitions as they use the names
+// defined in the instructions definitions.
+//
+// peepmatch ( root_instr_name [preceding_instruction]* );
+//
+// peepconstraint %{
+// (instruction_number.operand_name relational_op instruction_number.operand_name
+//  [, ...] );
+// // instruction numbers are zero-based using left to right order in peepmatch
+//
+// peepreplace ( instr_name  ( [instruction_number.operand_name]* ) );
+// // provide an instruction_number.operand_name for each operand that appears
+// // in the replacement instruction's match rule
+//
+// ---------VM FLAGS---------------------------------------------------------
+//
+// All peephole optimizations can be turned off using -XX:-OptoPeephole
+//
+// Each peephole rule is given an identifying number starting with zero and
+// increasing by one in the order seen by the parser.  An individual peephole
+// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=#
+// on the command-line.
+//
+// ---------CURRENT LIMITATIONS----------------------------------------------
+//
+// Only match adjacent instructions in same basic block
+// Only equality constraints
+// Only constraints between operands, not (0.dest_reg == EAX_enc)
+// Only one replacement instruction
+//
+// ---------EXAMPLE----------------------------------------------------------
+//
+// // pertinent parts of existing instructions in architecture description
+// instruct movI(eRegI dst, eRegI src) %{
+//   match(Set dst (CopyI src));
+// %}
+//
+// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{
+//   match(Set dst (AddI dst src));
+//   effect(KILL cr);
+// %}
+//
+// // Change (inc mov) to lea
+// peephole %{
+//   // increment preceeded by register-register move
+//   peepmatch ( incI_eReg movI );
+//   // require that the destination register of the increment
+//   // match the destination register of the move
+//   peepconstraint ( 0.dst == 1.dst );
+//   // construct a replacement instruction that sets
+//   // the destination to ( move's source register + one )
+//   peepreplace ( incI_eReg_immI1( 0.dst 1.src 0.src ) );
+// %}
+//
+
+// // Change load of spilled value to only a spill
+// instruct storeI(memory mem, eRegI src) %{
+//   match(Set mem (StoreI mem src));
+// %}
+//
+// instruct loadI(eRegI dst, memory mem) %{
+//   match(Set dst (LoadI mem));
+// %}
+//
+// peephole %{
+//   peepmatch ( loadI storeI );
+//   peepconstraint ( 1.src == 0.dst, 1.mem == 0.mem );
+//   peepreplace ( storeI( 1.mem 1.mem 1.src ) );
+// %}
+
+//----------SMARTSPILL RULES---------------------------------------------------
+// These must follow all instruction definitions as they use the names
+// defined in the instructions definitions.
+//
+// ARM will probably not have any of these rules due to RISC instruction set.
+
+//----------PIPELINE-----------------------------------------------------------
+// Rules which define the behavior of the target architectures pipeline.
diff --git a/hotspot/src/cpu/arm/vm/arm_32.ad b/hotspot/src/cpu/arm/vm/arm_32.ad
new file mode 100644
index 0000000..d8131ff
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/arm_32.ad
@@ -0,0 +1,586 @@
+//
+// Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code 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 General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+// ARM Architecture Description File
+
+//----------REGISTER DEFINITION BLOCK------------------------------------------
+// This information is used by the matcher and the register allocator to
+// describe individual registers and classes of registers within the target
+// archtecture.
+register %{
+//----------Architecture Description Register Definitions----------------------
+// General Registers
+// "reg_def"  name ( register save type, C convention save type,
+//                   ideal register type, encoding, vm name );
+// Register Save Types:
+//
+// NS  = No-Save:       The register allocator assumes that these registers
+//                      can be used without saving upon entry to the method, &
+//                      that they do not need to be saved at call sites.
+//
+// SOC = Save-On-Call:  The register allocator assumes that these registers
+//                      can be used without saving upon entry to the method,
+//                      but that they must be saved at call sites.
+//
+// SOE = Save-On-Entry: The register allocator assumes that these registers
+//                      must be saved before using them upon entry to the
+//                      method, but they do not need to be saved at call
+//                      sites.
+//
+// AS  = Always-Save:   The register allocator assumes that these registers
+//                      must be saved before using them upon entry to the
+//                      method, & that they must be saved at call sites.
+//
+// Ideal Register Type is used to determine how to save & restore a
+// register.  Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get
+// spilled with LoadP/StoreP.  If the register supports both, use Op_RegI.
+//
+// The encoding number is the actual bit-pattern placed into the opcodes.
+
+
+// ----------------------------
+// Integer/Long Registers
+// ----------------------------
+
+reg_def R_R0 (SOC, SOC, Op_RegI,  0,  R(0)->as_VMReg());
+reg_def R_R1 (SOC, SOC, Op_RegI,  1,  R(1)->as_VMReg());
+reg_def R_R2 (SOC, SOC, Op_RegI,  2,  R(2)->as_VMReg());
+reg_def R_R3 (SOC, SOC, Op_RegI,  3,  R(3)->as_VMReg());
+reg_def R_R4 (SOC, SOE, Op_RegI,  4,  R(4)->as_VMReg());
+reg_def R_R5 (SOC, SOE, Op_RegI,  5,  R(5)->as_VMReg());
+reg_def R_R6 (SOC, SOE, Op_RegI,  6,  R(6)->as_VMReg());
+reg_def R_R7 (SOC, SOE, Op_RegI,  7,  R(7)->as_VMReg());
+reg_def R_R8 (SOC, SOE, Op_RegI,  8,  R(8)->as_VMReg());
+reg_def R_R9 (SOC, SOE, Op_RegI,  9,  R(9)->as_VMReg());
+reg_def R_R10(NS,  SOE, Op_RegI, 10, R(10)->as_VMReg());
+reg_def R_R11(NS,  SOE, Op_RegI, 11, R(11)->as_VMReg());
+reg_def R_R12(SOC, SOC, Op_RegI, 12, R(12)->as_VMReg());
+reg_def R_R13(NS,  NS,  Op_RegI, 13, R(13)->as_VMReg());
+reg_def R_R14(SOC, SOC, Op_RegI, 14, R(14)->as_VMReg());
+reg_def R_R15(NS,  NS,  Op_RegI, 15, R(15)->as_VMReg());
+
+// ----------------------------
+// Float/Double Registers
+// ----------------------------
+
+// Float Registers
+
+reg_def R_S0 ( SOC, SOC, Op_RegF,  0, S0->as_VMReg());
+reg_def R_S1 ( SOC, SOC, Op_RegF,  1, S1_reg->as_VMReg());
+reg_def R_S2 ( SOC, SOC, Op_RegF,  2, S2_reg->as_VMReg());
+reg_def R_S3 ( SOC, SOC, Op_RegF,  3, S3_reg->as_VMReg());
+reg_def R_S4 ( SOC, SOC, Op_RegF,  4, S4_reg->as_VMReg());
+reg_def R_S5 ( SOC, SOC, Op_RegF,  5, S5_reg->as_VMReg());
+reg_def R_S6 ( SOC, SOC, Op_RegF,  6, S6_reg->as_VMReg());
+reg_def R_S7 ( SOC, SOC, Op_RegF,  7, S7->as_VMReg());
+reg_def R_S8 ( SOC, SOC, Op_RegF,  8, S8->as_VMReg());
+reg_def R_S9 ( SOC, SOC, Op_RegF,  9, S9->as_VMReg());
+reg_def R_S10( SOC, SOC, Op_RegF, 10,S10->as_VMReg());
+reg_def R_S11( SOC, SOC, Op_RegF, 11,S11->as_VMReg());
+reg_def R_S12( SOC, SOC, Op_RegF, 12,S12->as_VMReg());
+reg_def R_S13( SOC, SOC, Op_RegF, 13,S13->as_VMReg());
+reg_def R_S14( SOC, SOC, Op_RegF, 14,S14->as_VMReg());
+reg_def R_S15( SOC, SOC, Op_RegF, 15,S15->as_VMReg());
+reg_def R_S16( SOC, SOE, Op_RegF, 16,S16->as_VMReg());
+reg_def R_S17( SOC, SOE, Op_RegF, 17,S17->as_VMReg());
+reg_def R_S18( SOC, SOE, Op_RegF, 18,S18->as_VMReg());
+reg_def R_S19( SOC, SOE, Op_RegF, 19,S19->as_VMReg());
+reg_def R_S20( SOC, SOE, Op_RegF, 20,S20->as_VMReg());
+reg_def R_S21( SOC, SOE, Op_RegF, 21,S21->as_VMReg());
+reg_def R_S22( SOC, SOE, Op_RegF, 22,S22->as_VMReg());
+reg_def R_S23( SOC, SOE, Op_RegF, 23,S23->as_VMReg());
+reg_def R_S24( SOC, SOE, Op_RegF, 24,S24->as_VMReg());
+reg_def R_S25( SOC, SOE, Op_RegF, 25,S25->as_VMReg());
+reg_def R_S26( SOC, SOE, Op_RegF, 26,S26->as_VMReg());
+reg_def R_S27( SOC, SOE, Op_RegF, 27,S27->as_VMReg());
+reg_def R_S28( SOC, SOE, Op_RegF, 28,S28->as_VMReg());
+reg_def R_S29( SOC, SOE, Op_RegF, 29,S29->as_VMReg());
+reg_def R_S30( SOC, SOE, Op_RegF, 30,S30->as_VMReg());
+reg_def R_S31( SOC, SOE, Op_RegF, 31,S31->as_VMReg());
+
+// Double Registers
+// The rules of ADL require that double registers be defined in pairs.
+// Each pair must be two 32-bit values, but not necessarily a pair of
+// single float registers.  In each pair, ADLC-assigned register numbers
+// must be adjacent, with the lower number even.  Finally, when the
+// CPU stores such a register pair to memory, the word associated with
+// the lower ADLC-assigned number must be stored to the lower address.
+
+reg_def R_D16 (SOC, SOC, Op_RegD, 32, D16->as_VMReg());
+reg_def R_D16x(SOC, SOC, Op_RegD,255, D16->as_VMReg()->next());
+reg_def R_D17 (SOC, SOC, Op_RegD, 34, D17->as_VMReg());
+reg_def R_D17x(SOC, SOC, Op_RegD,255, D17->as_VMReg()->next());
+reg_def R_D18 (SOC, SOC, Op_RegD, 36, D18->as_VMReg());
+reg_def R_D18x(SOC, SOC, Op_RegD,255, D18->as_VMReg()->next());
+reg_def R_D19 (SOC, SOC, Op_RegD, 38, D19->as_VMReg());
+reg_def R_D19x(SOC, SOC, Op_RegD,255, D19->as_VMReg()->next());
+reg_def R_D20 (SOC, SOC, Op_RegD, 40, D20->as_VMReg());
+reg_def R_D20x(SOC, SOC, Op_RegD,255, D20->as_VMReg()->next());
+reg_def R_D21 (SOC, SOC, Op_RegD, 42, D21->as_VMReg());
+reg_def R_D21x(SOC, SOC, Op_RegD,255, D21->as_VMReg()->next());
+reg_def R_D22 (SOC, SOC, Op_RegD, 44, D22->as_VMReg());
+reg_def R_D22x(SOC, SOC, Op_RegD,255, D22->as_VMReg()->next());
+reg_def R_D23 (SOC, SOC, Op_RegD, 46, D23->as_VMReg());
+reg_def R_D23x(SOC, SOC, Op_RegD,255, D23->as_VMReg()->next());
+reg_def R_D24 (SOC, SOC, Op_RegD, 48, D24->as_VMReg());
+reg_def R_D24x(SOC, SOC, Op_RegD,255, D24->as_VMReg()->next());
+reg_def R_D25 (SOC, SOC, Op_RegD, 50, D25->as_VMReg());
+reg_def R_D25x(SOC, SOC, Op_RegD,255, D25->as_VMReg()->next());
+reg_def R_D26 (SOC, SOC, Op_RegD, 52, D26->as_VMReg());
+reg_def R_D26x(SOC, SOC, Op_RegD,255, D26->as_VMReg()->next());
+reg_def R_D27 (SOC, SOC, Op_RegD, 54, D27->as_VMReg());
+reg_def R_D27x(SOC, SOC, Op_RegD,255, D27->as_VMReg()->next());
+reg_def R_D28 (SOC, SOC, Op_RegD, 56, D28->as_VMReg());
+reg_def R_D28x(SOC, SOC, Op_RegD,255, D28->as_VMReg()->next());
+reg_def R_D29 (SOC, SOC, Op_RegD, 58, D29->as_VMReg());
+reg_def R_D29x(SOC, SOC, Op_RegD,255, D29->as_VMReg()->next());
+reg_def R_D30 (SOC, SOC, Op_RegD, 60, D30->as_VMReg());
+reg_def R_D30x(SOC, SOC, Op_RegD,255, D30->as_VMReg()->next());
+reg_def R_D31 (SOC, SOC, Op_RegD, 62, D31->as_VMReg());
+reg_def R_D31x(SOC, SOC, Op_RegD,255, D31->as_VMReg()->next());
+
+// ----------------------------
+// Special Registers
+// Condition Codes Flag Registers
+reg_def APSR (SOC, SOC,  Op_RegFlags, 0, VMRegImpl::Bad());
+reg_def FPSCR(SOC, SOC,  Op_RegFlags, 0, VMRegImpl::Bad());
+
+// ----------------------------
+// Specify the enum values for the registers.  These enums are only used by the
+// OptoReg "class". We can convert these enum values at will to VMReg when needed
+// for visibility to the rest of the vm. The order of this enum influences the
+// register allocator so having the freedom to set this order and not be stuck
+// with the order that is natural for the rest of the vm is worth it.
+
+// registers in that order so that R11/R12 is an aligned pair that can be used for longs
+alloc_class chunk0(
+                   R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R10, R_R13, R_R14, R_R15, R_R0, R_R1, R_R2, R_R3);
+
+// Note that a register is not allocatable unless it is also mentioned
+// in a widely-used reg_class below.
+
+alloc_class chunk1(
+                   R_S16, R_S17, R_S18, R_S19, R_S20, R_S21, R_S22, R_S23,
+                   R_S24, R_S25, R_S26, R_S27, R_S28, R_S29, R_S30, R_S31,
+                   R_S0,  R_S1,  R_S2,  R_S3,  R_S4,  R_S5,  R_S6,  R_S7, 
+                   R_S8,  R_S9,  R_S10, R_S11, R_S12, R_S13, R_S14, R_S15,
+                   R_D16, R_D16x,R_D17, R_D17x,R_D18, R_D18x,R_D19, R_D19x, 
+                   R_D20, R_D20x,R_D21, R_D21x,R_D22, R_D22x,R_D23, R_D23x, 
+                   R_D24, R_D24x,R_D25, R_D25x,R_D26, R_D26x,R_D27, R_D27x, 
+                   R_D28, R_D28x,R_D29, R_D29x,R_D30, R_D30x,R_D31, R_D31x
+);
+
+alloc_class chunk2(APSR, FPSCR);
+
+//----------Architecture Description Register Classes--------------------------
+// Several register classes are automatically defined based upon information in
+// this architecture description.
+// 1) reg_class inline_cache_reg           ( as defined in frame section )
+// 2) reg_class interpreter_method_oop_reg ( as defined in frame section )
+// 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ )
+//
+
+// ----------------------------
+// Integer Register Classes
+// ----------------------------
+// Exclusions from i_reg:
+// SP (R13), PC (R15)
+// R10: reserved by HotSpot to the TLS register (invariant within Java)
+reg_class int_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R14);
+
+reg_class R0_regI(R_R0);
+reg_class R1_regI(R_R1);
+reg_class R2_regI(R_R2);
+reg_class R3_regI(R_R3);
+reg_class R12_regI(R_R12);
+
+// ----------------------------
+// Pointer Register Classes
+// ----------------------------
+reg_class ptr_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R14);
+// Special class for storeP instructions, which can store SP or RPC to TLS.
+// It is also used for memory addressing, allowing direct TLS addressing.
+reg_class sp_ptr_reg(R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R11, R_R12, R_R14, R_R10 /* TLS*/, R_R13 /* SP*/);
+
+#define R_Ricklass R_R8
+#define R_Rmethod  R_R9
+#define R_Rthread  R_R10
+#define R_Rexception_obj R_R4
+
+// Other special pointer regs
+reg_class R0_regP(R_R0);
+reg_class R1_regP(R_R1);
+reg_class R2_regP(R_R2);
+reg_class R4_regP(R_R4);
+reg_class Rexception_regP(R_Rexception_obj);
+reg_class Ricklass_regP(R_Ricklass);
+reg_class Rmethod_regP(R_Rmethod);
+reg_class Rthread_regP(R_Rthread);
+reg_class IP_regP(R_R12);
+reg_class LR_regP(R_R14);
+
+reg_class FP_regP(R_R11);
+
+// ----------------------------
+// Long Register Classes
+// ----------------------------
+reg_class long_reg (             R_R0,R_R1, R_R2,R_R3, R_R4,R_R5, R_R6,R_R7, R_R8,R_R9, R_R11,R_R12);
+// for ldrexd, strexd: first reg of pair must be even
+reg_class long_reg_align (       R_R0,R_R1, R_R2,R_R3, R_R4,R_R5, R_R6,R_R7, R_R8,R_R9);
+
+reg_class R0R1_regL(R_R0,R_R1);
+reg_class R2R3_regL(R_R2,R_R3);
+
+// ----------------------------
+// Special Class for Condition Code Flags Register
+reg_class int_flags(APSR);
+reg_class float_flags(FPSCR);
+
+
+// ----------------------------
+// Float Point Register Classes
+// ----------------------------
+// Skip S14/S15, they are reserved for mem-mem copies
+reg_class sflt_reg(R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7, R_S8, R_S9, R_S10, R_S11, R_S12, R_S13,
+                   R_S16, R_S17, R_S18, R_S19, R_S20, R_S21, R_S22, R_S23, R_S24, R_S25, R_S26, R_S27, R_S28, R_S29, R_S30, R_S31);
+
+// Paired floating point registers--they show up in the same order as the floats,
+// but they are used with the "Op_RegD" type, and always occur in even/odd pairs.
+reg_class dflt_reg(R_S0,R_S1, R_S2,R_S3, R_S4,R_S5, R_S6,R_S7, R_S8,R_S9, R_S10,R_S11, R_S12,R_S13,
+                   R_S16,R_S17, R_S18,R_S19, R_S20,R_S21, R_S22,R_S23, R_S24,R_S25, R_S26,R_S27, R_S28,R_S29, R_S30,R_S31,
+                   R_D16,R_D16x, R_D17,R_D17x, R_D18,R_D18x, R_D19,R_D19x, R_D20,R_D20x, R_D21,R_D21x, R_D22,R_D22x,
+                   R_D23,R_D23x, R_D24,R_D24x, R_D25,R_D25x, R_D26,R_D26x, R_D27,R_D27x, R_D28,R_D28x, R_D29,R_D29x,
+                   R_D30,R_D30x, R_D31,R_D31x);
+
+reg_class dflt_low_reg(R_S0,R_S1, R_S2,R_S3, R_S4,R_S5, R_S6,R_S7, R_S8,R_S9, R_S10,R_S11, R_S12,R_S13,
+                       R_S16,R_S17, R_S18,R_S19, R_S20,R_S21, R_S22,R_S23, R_S24,R_S25, R_S26,R_S27, R_S28,R_S29, R_S30,R_S31);
+
+
+reg_class actual_dflt_reg %{
+  if (VM_Version::has_vfp3_32()) {
+    return DFLT_REG_mask();
+  } else {
+    return DFLT_LOW_REG_mask();
+  }
+%}
+
+reg_class S0_regF(R_S0);
+reg_class D0_regD(R_S0,R_S1);
+reg_class D1_regD(R_S2,R_S3);
+reg_class D2_regD(R_S4,R_S5);
+reg_class D3_regD(R_S6,R_S7);
+reg_class D4_regD(R_S8,R_S9);
+reg_class D5_regD(R_S10,R_S11);
+reg_class D6_regD(R_S12,R_S13);
+reg_class D7_regD(R_S14,R_S15);
+
+reg_class D16_regD(R_D16,R_D16x);
+reg_class D17_regD(R_D17,R_D17x);
+reg_class D18_regD(R_D18,R_D18x);
+reg_class D19_regD(R_D19,R_D19x);
+reg_class D20_regD(R_D20,R_D20x);
+reg_class D21_regD(R_D21,R_D21x);
+reg_class D22_regD(R_D22,R_D22x);
+reg_class D23_regD(R_D23,R_D23x);
+reg_class D24_regD(R_D24,R_D24x);
+reg_class D25_regD(R_D25,R_D25x);
+reg_class D26_regD(R_D26,R_D26x);
+reg_class D27_regD(R_D27,R_D27x);
+reg_class D28_regD(R_D28,R_D28x);
+reg_class D29_regD(R_D29,R_D29x);
+reg_class D30_regD(R_D30,R_D30x);
+reg_class D31_regD(R_D31,R_D31x);
+
+reg_class vectorx_reg(R_S0,R_S1,R_S2,R_S3, R_S4,R_S5,R_S6,R_S7,
+                      R_S8,R_S9,R_S10,R_S11, /* skip S14/S15 */
+                      R_S16,R_S17,R_S18,R_S19, R_S20,R_S21,R_S22,R_S23,
+                      R_S24,R_S25,R_S26,R_S27, R_S28,R_S29,R_S30,R_S31,
+                      R_D16,R_D16x,R_D17,R_D17x, R_D18,R_D18x,R_D19,R_D19x,
+                      R_D20,R_D20x,R_D21,R_D21x, R_D22,R_D22x,R_D23,R_D23x,
+                      R_D24,R_D24x,R_D25,R_D25x, R_D26,R_D26x,R_D27,R_D27x,
+                      R_D28,R_D28x,R_D29,R_D29x, R_D30,R_D30x,R_D31,R_D31x);
+
+%}
+
+source_hpp %{
+// FIXME
+const MachRegisterNumbers R_mem_copy_lo_num = R_S14_num;
+const MachRegisterNumbers R_mem_copy_hi_num = R_S15_num;
+const FloatRegister Rmemcopy = S14;
+const MachRegisterNumbers R_hf_ret_lo_num = R_S0_num;
+const MachRegisterNumbers R_hf_ret_hi_num = R_S1_num;
+
+const MachRegisterNumbers R_Ricklass_num = R_R8_num;
+const MachRegisterNumbers R_Rmethod_num  = R_R9_num;
+
+#define LDR_DOUBLE "FLDD"
+#define LDR_FLOAT  "FLDS"
+#define STR_DOUBLE "FSTD"
+#define STR_FLOAT  "FSTS"
+#define LDR_64     "LDRD"
+#define STR_64     "STRD"
+#define LDR_32     "LDR"
+#define STR_32     "STR"
+#define MOV_DOUBLE "FCPYD"
+#define MOV_FLOAT  "FCPYS"
+#define FMSR       "FMSR"
+#define FMRS       "FMRS"
+#define LDREX      "ldrex "
+#define STREX      "strex "
+
+#define str_64     strd
+#define ldr_64     ldrd
+#define ldr_32     ldr
+#define ldrex      ldrex
+#define strex      strex
+
+static inline bool is_memoryD(int offset) {
+  return offset < 1024 && offset > -1024;
+}
+
+static inline bool is_memoryfp(int offset) {
+  return offset < 1024 && offset > -1024;
+}
+
+static inline bool is_memoryI(int offset) {
+  return offset < 4096 && offset > -4096;
+}
+
+static inline bool is_memoryP(int offset) {
+  return offset < 4096 && offset > -4096;
+}
+
+static inline bool is_memoryHD(int offset) {
+  return offset < 256 && offset > -256;
+}
+
+static inline bool is_aimm(int imm) {
+  return AsmOperand::is_rotated_imm(imm);
+}
+
+static inline bool is_limmI(jint imm) {
+  return AsmOperand::is_rotated_imm(imm);
+}
+
+static inline bool is_limmI_low(jint imm, int n) {
+  int imml = imm & right_n_bits(n);
+  return is_limmI(imml) || is_limmI(imm);
+}
+
+static inline int limmI_low(jint imm, int n) {
+  int imml = imm & right_n_bits(n);
+  return is_limmI(imml) ? imml : imm;
+}
+
+%}
+
+source %{
+
+// Given a register encoding, produce a Integer Register object
+static Register reg_to_register_object(int register_encoding) {
+  assert(R0->encoding() == R_R0_enc && R15->encoding() == R_R15_enc, "right coding");
+  return as_Register(register_encoding);
+}
+
+// Given a register encoding, produce a single-precision Float Register object
+static FloatRegister reg_to_FloatRegister_object(int register_encoding) {
+  assert(S0->encoding() == R_S0_enc && S31->encoding() == R_S31_enc, "right coding");
+  return as_FloatRegister(register_encoding);
+}
+
+void Compile::pd_compiler2_init() {
+  // Umimplemented
+}
+
+// Location of compiled Java return values.  Same as C
+OptoRegPair c2::return_value(int ideal_reg) {
+  assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" );
+#ifndef __ABI_HARD__
+  static int lo[Op_RegL+1] = { 0, 0, OptoReg::Bad, R_R0_num,     R_R0_num,     R_R0_num,     R_R0_num, R_R0_num };
+  static int hi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_R1_num, R_R1_num };
+#else
+  static int lo[Op_RegL+1] = { 0, 0, OptoReg::Bad, R_R0_num,     R_R0_num,     R_hf_ret_lo_num,  R_hf_ret_lo_num, R_R0_num };
+  static int hi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad,     R_hf_ret_hi_num, R_R1_num };
+#endif
+  return OptoRegPair( hi[ideal_reg], lo[ideal_reg]);
+}
+
+// !!!!! Special hack to get all type of calls to specify the byte offset
+//       from the start of the call to the point where the return address
+//       will point.
+
+int MachCallStaticJavaNode::ret_addr_offset() {
+  bool far = (_method == NULL) ? maybe_far_call(this) : !cache_reachable();
+  return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) *
+    NativeInstruction::instruction_size;
+}
+
+int MachCallDynamicJavaNode::ret_addr_offset() {
+  bool far = !cache_reachable();
+  // mov_oop is always 2 words
+  return (2 + (far ? 3 : 1)) * NativeInstruction::instruction_size; 
+}
+
+int MachCallRuntimeNode::ret_addr_offset() {
+  // bl or movw; movt; blx
+  bool far = maybe_far_call(this);
+  return (far ? 3 : 1) * NativeInstruction::instruction_size;
+}
+%}
+
+// The intptr_t operand types, defined by textual substitution.
+// (Cf. opto/type.hpp.  This lets us avoid many, many other ifdefs.)
+#define immX      immI
+#define immXRot   immIRot
+#define iRegX     iRegI
+#define aimmX     aimmI
+#define limmX     limmI
+#define immX10x2  immI10x2
+#define LShiftX   LShiftI
+#define shimmX    immU5
+
+// Compatibility interface
+#define aimmP     immPRot
+#define immIMov   immIRot
+
+#define store_RegL     iRegL
+#define store_RegLd    iRegLd
+#define store_RegI     iRegI
+#define store_ptr_RegP iRegP
+
+//----------ATTRIBUTES---------------------------------------------------------
+//----------Operand Attributes-------------------------------------------------
+op_attrib op_cost(1);          // Required cost attribute
+
+//----------OPERANDS-----------------------------------------------------------
+// Operand definitions must precede instruction definitions for correct parsing
+// in the ADLC because operands constitute user defined types which are used in
+// instruction definitions.
+
+//----------Simple Operands----------------------------------------------------
+// Immediate Operands
+
+operand immIRot() %{
+  predicate(AsmOperand::is_rotated_imm(n->get_int()));
+  match(ConI);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immIRotn() %{
+  predicate(n->get_int() != 0 && AsmOperand::is_rotated_imm(~n->get_int()));
+  match(ConI);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immIRotneg() %{
+  // if AsmOperand::is_rotated_imm() is true for this constant, it is
+  // a immIRot and an optimal instruction combination exists to handle the
+  // constant as an immIRot
+  predicate(!AsmOperand::is_rotated_imm(n->get_int()) && AsmOperand::is_rotated_imm(-n->get_int()));
+  match(ConI);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Non-negative integer immediate that is encodable using the rotation scheme,
+// and that when expanded fits in 31 bits.
+operand immU31Rot() %{
+  predicate((0 <= n->get_int()) && AsmOperand::is_rotated_imm(n->get_int()));
+  match(ConI);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immPRot() %{
+  predicate(n->get_ptr() == 0 || (AsmOperand::is_rotated_imm(n->get_ptr()) && ((ConPNode*)n)->type()->reloc() == relocInfo::none));
+
+  match(ConP);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immLlowRot() %{
+  predicate(n->get_long() >> 32 == 0 && AsmOperand::is_rotated_imm((int)n->get_long()));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immLRot2() %{
+  predicate(AsmOperand::is_rotated_imm((int)(n->get_long() >> 32)) &&
+            AsmOperand::is_rotated_imm((int)(n->get_long())));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 12-bit - for addressing mode
+operand immI12() %{
+  predicate((-4096 < n->get_int()) && (n->get_int() < 4096));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 10-bit disp and disp+4 - for addressing float pair
+operand immI10x2() %{
+  predicate((-1024 < n->get_int()) && (n->get_int() < 1024 - 4));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: 12-bit disp and disp+4 - for addressing word pair
+operand immI12x2() %{
+  predicate((-4096 < n->get_int()) && (n->get_int() < 4096 - 4));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
diff --git a/hotspot/src/cpu/arm/vm/arm_64.ad b/hotspot/src/cpu/arm/vm/arm_64.ad
new file mode 100644
index 0000000..5d5a6c8
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/arm_64.ad
@@ -0,0 +1,998 @@
+//
+// Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code 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 General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+// ARM Architecture Description File
+
+//----------REGISTER DEFINITION BLOCK------------------------------------------
+// This information is used by the matcher and the register allocator to
+// describe individual registers and classes of registers within the target
+// archtecture.
+register %{
+//----------Architecture Description Register Definitions----------------------
+// General Registers
+// "reg_def"  name ( register save type, C convention save type,
+//                   ideal register type, encoding, vm name );
+// Register Save Types:
+//
+// NS  = No-Save:       The register allocator assumes that these registers
+//                      can be used without saving upon entry to the method, &
+//                      that they do not need to be saved at call sites.
+//
+// SOC = Save-On-Call:  The register allocator assumes that these registers
+//                      can be used without saving upon entry to the method,
+//                      but that they must be saved at call sites.
+//
+// SOE = Save-On-Entry: The register allocator assumes that these registers
+//                      must be saved before using them upon entry to the
+//                      method, but they do not need to be saved at call
+//                      sites.
+//
+// AS  = Always-Save:   The register allocator assumes that these registers
+//                      must be saved before using them upon entry to the
+//                      method, & that they must be saved at call sites.
+//
+// Ideal Register Type is used to determine how to save & restore a
+// register.  Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get
+// spilled with LoadP/StoreP.  If the register supports both, use Op_RegI.
+// FIXME: above comment seems wrong.  Spill done through MachSpillCopyNode
+//
+// The encoding number is the actual bit-pattern placed into the opcodes.
+
+
+// ----------------------------
+// Integer/Long Registers
+// ----------------------------
+
+// TODO: would be nice to keep track of high-word state:
+// zeroRegI --> RegL
+// signedRegI --> RegL
+// junkRegI --> RegL
+// how to tell C2 to treak RegI as RegL, or RegL as RegI?
+reg_def R_R0  (SOC, SOC, Op_RegI,   0, R0->as_VMReg());
+reg_def R_R0x (SOC, SOC, Op_RegI, 255, R0->as_VMReg()->next());
+reg_def R_R1  (SOC, SOC, Op_RegI,   1, R1->as_VMReg());
+reg_def R_R1x (SOC, SOC, Op_RegI, 255, R1->as_VMReg()->next());
+reg_def R_R2  (SOC, SOC, Op_RegI,   2, R2->as_VMReg());
+reg_def R_R2x (SOC, SOC, Op_RegI, 255, R2->as_VMReg()->next());
+reg_def R_R3  (SOC, SOC, Op_RegI,   3, R3->as_VMReg());
+reg_def R_R3x (SOC, SOC, Op_RegI, 255, R3->as_VMReg()->next());
+reg_def R_R4  (SOC, SOC, Op_RegI,   4, R4->as_VMReg());
+reg_def R_R4x (SOC, SOC, Op_RegI, 255, R4->as_VMReg()->next());
+reg_def R_R5  (SOC, SOC, Op_RegI,   5, R5->as_VMReg());
+reg_def R_R5x (SOC, SOC, Op_RegI, 255, R5->as_VMReg()->next());
+reg_def R_R6  (SOC, SOC, Op_RegI,   6, R6->as_VMReg());
+reg_def R_R6x (SOC, SOC, Op_RegI, 255, R6->as_VMReg()->next());
+reg_def R_R7  (SOC, SOC, Op_RegI,   7, R7->as_VMReg());
+reg_def R_R7x (SOC, SOC, Op_RegI, 255, R7->as_VMReg()->next());
+
+reg_def R_R8  (SOC, SOC, Op_RegI,   8, R8->as_VMReg());
+reg_def R_R8x (SOC, SOC, Op_RegI, 255, R8->as_VMReg()->next());
+reg_def R_R9  (SOC, SOC, Op_RegI,   9, R9->as_VMReg());
+reg_def R_R9x (SOC, SOC, Op_RegI, 255, R9->as_VMReg()->next());
+reg_def R_R10 (SOC, SOC, Op_RegI,  10, R10->as_VMReg());
+reg_def R_R10x(SOC, SOC, Op_RegI, 255, R10->as_VMReg()->next());
+reg_def R_R11 (SOC, SOC, Op_RegI,  11, R11->as_VMReg());
+reg_def R_R11x(SOC, SOC, Op_RegI, 255, R11->as_VMReg()->next());
+reg_def R_R12 (SOC, SOC, Op_RegI,  12, R12->as_VMReg());
+reg_def R_R12x(SOC, SOC, Op_RegI, 255, R12->as_VMReg()->next());
+reg_def R_R13 (SOC, SOC, Op_RegI,  13, R13->as_VMReg());
+reg_def R_R13x(SOC, SOC, Op_RegI, 255, R13->as_VMReg()->next());
+reg_def R_R14 (SOC, SOC, Op_RegI,  14, R14->as_VMReg());
+reg_def R_R14x(SOC, SOC, Op_RegI, 255, R14->as_VMReg()->next());
+reg_def R_R15 (SOC, SOC, Op_RegI,  15, R15->as_VMReg());
+reg_def R_R15x(SOC, SOC, Op_RegI, 255, R15->as_VMReg()->next());
+
+reg_def R_R16 (SOC, SOC, Op_RegI,  16, R16->as_VMReg()); // IP0
+reg_def R_R16x(SOC, SOC, Op_RegI, 255, R16->as_VMReg()->next());
+reg_def R_R17 (SOC, SOC, Op_RegI,  17, R17->as_VMReg()); // IP1
+reg_def R_R17x(SOC, SOC, Op_RegI, 255, R17->as_VMReg()->next());
+reg_def R_R18 (SOC, SOC, Op_RegI,  18, R18->as_VMReg()); // Platform Register
+reg_def R_R18x(SOC, SOC, Op_RegI, 255, R18->as_VMReg()->next());
+
+reg_def R_R19 (SOC, SOE, Op_RegI,  19, R19->as_VMReg());
+reg_def R_R19x(SOC, SOE, Op_RegI, 255, R19->as_VMReg()->next());
+reg_def R_R20 (SOC, SOE, Op_RegI,  20, R20->as_VMReg());
+reg_def R_R20x(SOC, SOE, Op_RegI, 255, R20->as_VMReg()->next());
+reg_def R_R21 (SOC, SOE, Op_RegI,  21, R21->as_VMReg());
+reg_def R_R21x(SOC, SOE, Op_RegI, 255, R21->as_VMReg()->next());
+reg_def R_R22 (SOC, SOE, Op_RegI,  22, R22->as_VMReg());
+reg_def R_R22x(SOC, SOE, Op_RegI, 255, R22->as_VMReg()->next());
+reg_def R_R23 (SOC, SOE, Op_RegI,  23, R23->as_VMReg());
+reg_def R_R23x(SOC, SOE, Op_RegI, 255, R23->as_VMReg()->next());
+reg_def R_R24 (SOC, SOE, Op_RegI,  24, R24->as_VMReg());
+reg_def R_R24x(SOC, SOE, Op_RegI, 255, R24->as_VMReg()->next());
+reg_def R_R25 (SOC, SOE, Op_RegI,  25, R25->as_VMReg());
+reg_def R_R25x(SOC, SOE, Op_RegI, 255, R25->as_VMReg()->next());
+reg_def R_R26 (SOC, SOE, Op_RegI,  26, R26->as_VMReg());
+reg_def R_R26x(SOC, SOE, Op_RegI, 255, R26->as_VMReg()->next());
+reg_def R_R27 (SOC, SOE, Op_RegI,  27, R27->as_VMReg());         // Rheap_base
+reg_def R_R27x(SOC, SOE, Op_RegI, 255, R27->as_VMReg()->next()); // Rheap_base
+reg_def R_R28 ( NS, SOE, Op_RegI,  28, R28->as_VMReg());         // TLS
+reg_def R_R28x( NS, SOE, Op_RegI, 255, R28->as_VMReg()->next()); // TLS
+
+reg_def R_R29 ( NS, SOE, Op_RegI,  29, R29->as_VMReg());         // FP
+reg_def R_R29x( NS, SOE, Op_RegI, 255, R29->as_VMReg()->next()); // FP
+reg_def R_R30 (SOC, SOC, Op_RegI,  30, R30->as_VMReg());         // LR
+reg_def R_R30x(SOC, SOC, Op_RegI, 255, R30->as_VMReg()->next()); // LR
+
+reg_def R_ZR ( NS,  NS, Op_RegI,  31, ZR->as_VMReg());  // ZR
+reg_def R_ZRx( NS,  NS, Op_RegI, 255, ZR->as_VMReg()->next()); // ZR
+
+// FIXME
+//reg_def R_SP ( NS,  NS, Op_RegP,  32, SP->as_VMReg());
+reg_def R_SP ( NS,  NS, Op_RegI,  32, SP->as_VMReg());
+//reg_def R_SPx( NS, NS, Op_RegP, 255, SP->as_VMReg()->next());
+reg_def R_SPx( NS,  NS, Op_RegI, 255, SP->as_VMReg()->next());
+
+// ----------------------------
+// Float/Double/Vector Registers
+// ----------------------------
+
+reg_def  R_V0(SOC, SOC, Op_RegF,  0,  V0->as_VMReg());
+reg_def  R_V1(SOC, SOC, Op_RegF,  1,  V1->as_VMReg());
+reg_def  R_V2(SOC, SOC, Op_RegF,  2,  V2->as_VMReg());
+reg_def  R_V3(SOC, SOC, Op_RegF,  3,  V3->as_VMReg());
+reg_def  R_V4(SOC, SOC, Op_RegF,  4,  V4->as_VMReg());
+reg_def  R_V5(SOC, SOC, Op_RegF,  5,  V5->as_VMReg());
+reg_def  R_V6(SOC, SOC, Op_RegF,  6,  V6->as_VMReg());
+reg_def  R_V7(SOC, SOC, Op_RegF,  7,  V7->as_VMReg());
+reg_def  R_V8(SOC, SOC, Op_RegF,  8,  V8->as_VMReg());
+reg_def  R_V9(SOC, SOC, Op_RegF,  9,  V9->as_VMReg());
+reg_def R_V10(SOC, SOC, Op_RegF, 10, V10->as_VMReg());
+reg_def R_V11(SOC, SOC, Op_RegF, 11, V11->as_VMReg());
+reg_def R_V12(SOC, SOC, Op_RegF, 12, V12->as_VMReg());
+reg_def R_V13(SOC, SOC, Op_RegF, 13, V13->as_VMReg());
+reg_def R_V14(SOC, SOC, Op_RegF, 14, V14->as_VMReg());
+reg_def R_V15(SOC, SOC, Op_RegF, 15, V15->as_VMReg());
+reg_def R_V16(SOC, SOC, Op_RegF, 16, V16->as_VMReg());
+reg_def R_V17(SOC, SOC, Op_RegF, 17, V17->as_VMReg());
+reg_def R_V18(SOC, SOC, Op_RegF, 18, V18->as_VMReg());
+reg_def R_V19(SOC, SOC, Op_RegF, 19, V19->as_VMReg());
+reg_def R_V20(SOC, SOC, Op_RegF, 20, V20->as_VMReg());
+reg_def R_V21(SOC, SOC, Op_RegF, 21, V21->as_VMReg());
+reg_def R_V22(SOC, SOC, Op_RegF, 22, V22->as_VMReg());
+reg_def R_V23(SOC, SOC, Op_RegF, 23, V23->as_VMReg());
+reg_def R_V24(SOC, SOC, Op_RegF, 24, V24->as_VMReg());
+reg_def R_V25(SOC, SOC, Op_RegF, 25, V25->as_VMReg());
+reg_def R_V26(SOC, SOC, Op_RegF, 26, V26->as_VMReg());
+reg_def R_V27(SOC, SOC, Op_RegF, 27, V27->as_VMReg());
+reg_def R_V28(SOC, SOC, Op_RegF, 28, V28->as_VMReg());
+reg_def R_V29(SOC, SOC, Op_RegF, 29, V29->as_VMReg());
+reg_def R_V30(SOC, SOC, Op_RegF, 30, V30->as_VMReg());
+reg_def R_V31(SOC, SOC, Op_RegF, 31, V31->as_VMReg());
+
+reg_def  R_V0b(SOC, SOC, Op_RegF, 255, V0->as_VMReg()->next(1));
+reg_def  R_V1b(SOC, SOC, Op_RegF, 255, V1->as_VMReg()->next(1));
+reg_def  R_V2b(SOC, SOC, Op_RegF, 255, V2->as_VMReg()->next(1));
+reg_def  R_V3b(SOC, SOC, Op_RegF,  3,  V3->as_VMReg()->next(1));
+reg_def  R_V4b(SOC, SOC, Op_RegF,  4,  V4->as_VMReg()->next(1));
+reg_def  R_V5b(SOC, SOC, Op_RegF,  5,  V5->as_VMReg()->next(1));
+reg_def  R_V6b(SOC, SOC, Op_RegF,  6,  V6->as_VMReg()->next(1));
+reg_def  R_V7b(SOC, SOC, Op_RegF,  7,  V7->as_VMReg()->next(1));
+reg_def  R_V8b(SOC, SOC, Op_RegF, 255, V8->as_VMReg()->next(1));
+reg_def  R_V9b(SOC, SOC, Op_RegF,  9,  V9->as_VMReg()->next(1));
+reg_def R_V10b(SOC, SOC, Op_RegF, 10, V10->as_VMReg()->next(1));
+reg_def R_V11b(SOC, SOC, Op_RegF, 11, V11->as_VMReg()->next(1));
+reg_def R_V12b(SOC, SOC, Op_RegF, 12, V12->as_VMReg()->next(1));
+reg_def R_V13b(SOC, SOC, Op_RegF, 13, V13->as_VMReg()->next(1));
+reg_def R_V14b(SOC, SOC, Op_RegF, 14, V14->as_VMReg()->next(1));
+reg_def R_V15b(SOC, SOC, Op_RegF, 15, V15->as_VMReg()->next(1));
+reg_def R_V16b(SOC, SOC, Op_RegF, 16, V16->as_VMReg()->next(1));
+reg_def R_V17b(SOC, SOC, Op_RegF, 17, V17->as_VMReg()->next(1));
+reg_def R_V18b(SOC, SOC, Op_RegF, 18, V18->as_VMReg()->next(1));
+reg_def R_V19b(SOC, SOC, Op_RegF, 19, V19->as_VMReg()->next(1));
+reg_def R_V20b(SOC, SOC, Op_RegF, 20, V20->as_VMReg()->next(1));
+reg_def R_V21b(SOC, SOC, Op_RegF, 21, V21->as_VMReg()->next(1));
+reg_def R_V22b(SOC, SOC, Op_RegF, 22, V22->as_VMReg()->next(1));
+reg_def R_V23b(SOC, SOC, Op_RegF, 23, V23->as_VMReg()->next(1));
+reg_def R_V24b(SOC, SOC, Op_RegF, 24, V24->as_VMReg()->next(1));
+reg_def R_V25b(SOC, SOC, Op_RegF, 25, V25->as_VMReg()->next(1));
+reg_def R_V26b(SOC, SOC, Op_RegF, 26, V26->as_VMReg()->next(1));
+reg_def R_V27b(SOC, SOC, Op_RegF, 27, V27->as_VMReg()->next(1));
+reg_def R_V28b(SOC, SOC, Op_RegF, 28, V28->as_VMReg()->next(1));
+reg_def R_V29b(SOC, SOC, Op_RegF, 29, V29->as_VMReg()->next(1));
+reg_def R_V30b(SOC, SOC, Op_RegD, 30, V30->as_VMReg()->next(1));
+reg_def R_V31b(SOC, SOC, Op_RegF, 31, V31->as_VMReg()->next(1));
+
+reg_def  R_V0c(SOC, SOC, Op_RegF,  0,  V0->as_VMReg()->next(2));
+reg_def  R_V1c(SOC, SOC, Op_RegF,  1,  V1->as_VMReg()->next(2));
+reg_def  R_V2c(SOC, SOC, Op_RegF,  2,  V2->as_VMReg()->next(2));
+reg_def  R_V3c(SOC, SOC, Op_RegF,  3,  V3->as_VMReg()->next(2));
+reg_def  R_V4c(SOC, SOC, Op_RegF,  4,  V4->as_VMReg()->next(2));
+reg_def  R_V5c(SOC, SOC, Op_RegF,  5,  V5->as_VMReg()->next(2));
+reg_def  R_V6c(SOC, SOC, Op_RegF,  6,  V6->as_VMReg()->next(2));
+reg_def  R_V7c(SOC, SOC, Op_RegF,  7,  V7->as_VMReg()->next(2));
+reg_def  R_V8c(SOC, SOC, Op_RegF,  8,  V8->as_VMReg()->next(2));
+reg_def  R_V9c(SOC, SOC, Op_RegF,  9,  V9->as_VMReg()->next(2));
+reg_def R_V10c(SOC, SOC, Op_RegF, 10, V10->as_VMReg()->next(2));
+reg_def R_V11c(SOC, SOC, Op_RegF, 11, V11->as_VMReg()->next(2));
+reg_def R_V12c(SOC, SOC, Op_RegF, 12, V12->as_VMReg()->next(2));
+reg_def R_V13c(SOC, SOC, Op_RegF, 13, V13->as_VMReg()->next(2));
+reg_def R_V14c(SOC, SOC, Op_RegF, 14, V14->as_VMReg()->next(2));
+reg_def R_V15c(SOC, SOC, Op_RegF, 15, V15->as_VMReg()->next(2));
+reg_def R_V16c(SOC, SOC, Op_RegF, 16, V16->as_VMReg()->next(2));
+reg_def R_V17c(SOC, SOC, Op_RegF, 17, V17->as_VMReg()->next(2));
+reg_def R_V18c(SOC, SOC, Op_RegF, 18, V18->as_VMReg()->next(2));
+reg_def R_V19c(SOC, SOC, Op_RegF, 19, V19->as_VMReg()->next(2));
+reg_def R_V20c(SOC, SOC, Op_RegF, 20, V20->as_VMReg()->next(2));
+reg_def R_V21c(SOC, SOC, Op_RegF, 21, V21->as_VMReg()->next(2));
+reg_def R_V22c(SOC, SOC, Op_RegF, 22, V22->as_VMReg()->next(2));
+reg_def R_V23c(SOC, SOC, Op_RegF, 23, V23->as_VMReg()->next(2));
+reg_def R_V24c(SOC, SOC, Op_RegF, 24, V24->as_VMReg()->next(2));
+reg_def R_V25c(SOC, SOC, Op_RegF, 25, V25->as_VMReg()->next(2));
+reg_def R_V26c(SOC, SOC, Op_RegF, 26, V26->as_VMReg()->next(2));
+reg_def R_V27c(SOC, SOC, Op_RegF, 27, V27->as_VMReg()->next(2));
+reg_def R_V28c(SOC, SOC, Op_RegF, 28, V28->as_VMReg()->next(2));
+reg_def R_V29c(SOC, SOC, Op_RegF, 29, V29->as_VMReg()->next(2));
+reg_def R_V30c(SOC, SOC, Op_RegF, 30, V30->as_VMReg()->next(2));
+reg_def R_V31c(SOC, SOC, Op_RegF, 31, V31->as_VMReg()->next(2));
+
+reg_def  R_V0d(SOC, SOC, Op_RegF,  0,  V0->as_VMReg()->next(3));
+reg_def  R_V1d(SOC, SOC, Op_RegF,  1,  V1->as_VMReg()->next(3));
+reg_def  R_V2d(SOC, SOC, Op_RegF,  2,  V2->as_VMReg()->next(3));
+reg_def  R_V3d(SOC, SOC, Op_RegF,  3,  V3->as_VMReg()->next(3));
+reg_def  R_V4d(SOC, SOC, Op_RegF,  4,  V4->as_VMReg()->next(3));
+reg_def  R_V5d(SOC, SOC, Op_RegF,  5,  V5->as_VMReg()->next(3));
+reg_def  R_V6d(SOC, SOC, Op_RegF,  6,  V6->as_VMReg()->next(3));
+reg_def  R_V7d(SOC, SOC, Op_RegF,  7,  V7->as_VMReg()->next(3));
+reg_def  R_V8d(SOC, SOC, Op_RegF,  8,  V8->as_VMReg()->next(3));
+reg_def  R_V9d(SOC, SOC, Op_RegF,  9,  V9->as_VMReg()->next(3));
+reg_def R_V10d(SOC, SOC, Op_RegF, 10, V10->as_VMReg()->next(3));
+reg_def R_V11d(SOC, SOC, Op_RegF, 11, V11->as_VMReg()->next(3));
+reg_def R_V12d(SOC, SOC, Op_RegF, 12, V12->as_VMReg()->next(3));
+reg_def R_V13d(SOC, SOC, Op_RegF, 13, V13->as_VMReg()->next(3));
+reg_def R_V14d(SOC, SOC, Op_RegF, 14, V14->as_VMReg()->next(3));
+reg_def R_V15d(SOC, SOC, Op_RegF, 15, V15->as_VMReg()->next(3));
+reg_def R_V16d(SOC, SOC, Op_RegF, 16, V16->as_VMReg()->next(3));
+reg_def R_V17d(SOC, SOC, Op_RegF, 17, V17->as_VMReg()->next(3));
+reg_def R_V18d(SOC, SOC, Op_RegF, 18, V18->as_VMReg()->next(3));
+reg_def R_V19d(SOC, SOC, Op_RegF, 19, V19->as_VMReg()->next(3));
+reg_def R_V20d(SOC, SOC, Op_RegF, 20, V20->as_VMReg()->next(3));
+reg_def R_V21d(SOC, SOC, Op_RegF, 21, V21->as_VMReg()->next(3));
+reg_def R_V22d(SOC, SOC, Op_RegF, 22, V22->as_VMReg()->next(3));
+reg_def R_V23d(SOC, SOC, Op_RegF, 23, V23->as_VMReg()->next(3));
+reg_def R_V24d(SOC, SOC, Op_RegF, 24, V24->as_VMReg()->next(3));
+reg_def R_V25d(SOC, SOC, Op_RegF, 25, V25->as_VMReg()->next(3));
+reg_def R_V26d(SOC, SOC, Op_RegF, 26, V26->as_VMReg()->next(3));
+reg_def R_V27d(SOC, SOC, Op_RegF, 27, V27->as_VMReg()->next(3));
+reg_def R_V28d(SOC, SOC, Op_RegF, 28, V28->as_VMReg()->next(3));
+reg_def R_V29d(SOC, SOC, Op_RegF, 29, V29->as_VMReg()->next(3));
+reg_def R_V30d(SOC, SOC, Op_RegF, 30, V30->as_VMReg()->next(3));
+reg_def R_V31d(SOC, SOC, Op_RegF, 31, V31->as_VMReg()->next(3));
+
+// ----------------------------
+// Special Registers
+// Condition Codes Flag Registers
+reg_def APSR (SOC, SOC,  Op_RegFlags, 255, VMRegImpl::Bad());
+reg_def FPSCR(SOC, SOC,  Op_RegFlags, 255, VMRegImpl::Bad());
+
+// ----------------------------
+// Specify the enum values for the registers.  These enums are only used by the
+// OptoReg "class". We can convert these enum values at will to VMReg when needed
+// for visibility to the rest of the vm. The order of this enum influences the
+// register allocator so having the freedom to set this order and not be stuck
+// with the order that is natural for the rest of the vm is worth it.
+
+// Quad vector must be aligned here, so list them first.
+alloc_class fprs(
+    R_V8,  R_V8b,  R_V8c,  R_V8d,  R_V9,  R_V9b,  R_V9c,  R_V9d,
+    R_V10, R_V10b, R_V10c, R_V10d, R_V11, R_V11b, R_V11c, R_V11d,
+    R_V12, R_V12b, R_V12c, R_V12d, R_V13, R_V13b, R_V13c, R_V13d,
+    R_V14, R_V14b, R_V14c, R_V14d, R_V15, R_V15b, R_V15c, R_V15d,
+    R_V16, R_V16b, R_V16c, R_V16d, R_V17, R_V17b, R_V17c, R_V17d,
+    R_V18, R_V18b, R_V18c, R_V18d, R_V19, R_V19b, R_V19c, R_V19d,
+    R_V20, R_V20b, R_V20c, R_V20d, R_V21, R_V21b, R_V21c, R_V21d,
+    R_V22, R_V22b, R_V22c, R_V22d, R_V23, R_V23b, R_V23c, R_V23d,
+    R_V24, R_V24b, R_V24c, R_V24d, R_V25, R_V25b, R_V25c, R_V25d,
+    R_V26, R_V26b, R_V26c, R_V26d, R_V27, R_V27b, R_V27c, R_V27d,
+    R_V28, R_V28b, R_V28c, R_V28d, R_V29, R_V29b, R_V29c, R_V29d,
+    R_V30, R_V30b, R_V30c, R_V30d, R_V31, R_V31b, R_V31c, R_V31d,
+    R_V0,  R_V0b,  R_V0c,  R_V0d,  R_V1,  R_V1b,  R_V1c,  R_V1d,
+    R_V2,  R_V2b,  R_V2c,  R_V2d,  R_V3,  R_V3b,  R_V3c,  R_V3d,
+    R_V4,  R_V4b,  R_V4c,  R_V4d,  R_V5,  R_V5b,  R_V5c,  R_V5d,
+    R_V6,  R_V6b,  R_V6c,  R_V6d,  R_V7,  R_V7b,  R_V7c,  R_V7d
+);
+
+// Need double-register alignment here.
+// We are already quad-register aligned because of vectors above.
+alloc_class gprs(
+    R_R0,  R_R0x,  R_R1,  R_R1x,  R_R2,  R_R2x,  R_R3,  R_R3x,
+    R_R4,  R_R4x,  R_R5,  R_R5x,  R_R6,  R_R6x,  R_R7,  R_R7x,
+    R_R8,  R_R8x,  R_R9,  R_R9x,  R_R10, R_R10x, R_R11, R_R11x,
+    R_R12, R_R12x, R_R13, R_R13x, R_R14, R_R14x, R_R15, R_R15x,
+    R_R16, R_R16x, R_R17, R_R17x, R_R18, R_R18x, R_R19, R_R19x,
+    R_R20, R_R20x, R_R21, R_R21x, R_R22, R_R22x, R_R23, R_R23x,
+    R_R24, R_R24x, R_R25, R_R25x, R_R26, R_R26x, R_R27, R_R27x,
+    R_R28, R_R28x, R_R29, R_R29x, R_R30, R_R30x
+);
+// Continuing with double-reigister alignment...
+alloc_class chunk2(APSR, FPSCR);
+alloc_class chunk3(R_SP, R_SPx);
+alloc_class chunk4(R_ZR, R_ZRx);
+
+//----------Architecture Description Register Classes--------------------------
+// Several register classes are automatically defined based upon information in
+// this architecture description.
+// 1) reg_class inline_cache_reg           ( as defined in frame section )
+// 2) reg_class interpreter_method_oop_reg ( as defined in frame section )
+// 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ )
+//
+
+// ----------------------------
+// Integer Register Classes
+// ----------------------------
+reg_class int_reg_all(R_R0,  R_R1,  R_R2,  R_R3,  R_R4,  R_R5,  R_R6,  R_R7,
+                      R_R8,  R_R9,  R_R10, R_R11, R_R12, R_R13, R_R14, R_R15,
+                      R_R16, R_R17, R_R18, R_R19, R_R20, R_R21, R_R22, R_R23,
+                      R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30
+);
+
+// Exclusions from i_reg:
+// SP (R31)
+// Rthread/R28: reserved by HotSpot to the TLS register (invariant within Java)
+reg_class int_reg %{
+    return _INT_REG_mask;
+%}
+reg_class ptr_reg %{
+    return _PTR_REG_mask;
+%}
+reg_class vectorx_reg %{
+    return _VECTORX_REG_mask;
+%}
+
+reg_class R0_regI(R_R0);
+reg_class R1_regI(R_R1);
+reg_class R2_regI(R_R2);
+reg_class R3_regI(R_R3);
+//reg_class R12_regI(R_R12);
+
+// ----------------------------
+// Pointer Register Classes
+// ----------------------------
+
+// Special class for storeP instructions, which can store SP or RPC to TLS.
+// It is also used for memory addressing, allowing direct TLS addressing.
+
+reg_class sp_ptr_reg %{
+    return _SP_PTR_REG_mask;
+%}
+
+reg_class store_reg %{
+    return _STR_REG_mask;
+%}
+
+reg_class store_ptr_reg %{
+    return _STR_PTR_REG_mask;
+%}
+
+reg_class spillP_reg %{
+    return _SPILLP_REG_mask;
+%}
+
+// Other special pointer regs
+reg_class R0_regP(R_R0, R_R0x);
+reg_class R1_regP(R_R1, R_R1x);
+reg_class R2_regP(R_R2, R_R2x);
+reg_class Rexception_regP(R_R19, R_R19x);
+reg_class Ricklass_regP(R_R8, R_R8x);
+reg_class Rmethod_regP(R_R27, R_R27x);
+
+reg_class Rthread_regP(R_R28, R_R28x);
+reg_class IP_regP(R_R16, R_R16x);
+#define RtempRegP IPRegP
+reg_class LR_regP(R_R30, R_R30x);
+
+reg_class SP_regP(R_SP,  R_SPx);
+reg_class FP_regP(R_R29, R_R29x);
+
+reg_class ZR_regP(R_ZR, R_ZRx);
+reg_class ZR_regI(R_ZR);
+
+// ----------------------------
+// Long Register Classes
+// ----------------------------
+reg_class long_reg %{ return _PTR_REG_mask; %}
+// for ldrexd, strexd: first reg of pair must be even
+reg_class long_reg_align %{ return LONG_REG_mask(); %}
+
+reg_class R0_regL(R_R0,R_R0x); // arg 1 or return value
+
+// ----------------------------
+// Special Class for Condition Code Flags Register
+reg_class int_flags(APSR);
+reg_class float_flags(FPSCR);
+
+
+// ----------------------------
+// Float Point Register Classes
+// ----------------------------
+reg_class sflt_reg_0(
+  R_V0,  R_V1,  R_V2,  R_V3,  R_V4,  R_V5,  R_V6,  R_V7,
+  R_V8,  R_V9,  R_V10, R_V11, R_V12, R_V13, R_V14, R_V15,
+  R_V16, R_V17, R_V18, R_V19, R_V20, R_V21, R_V22, R_V23,
+  R_V24, R_V25, R_V26, R_V27, R_V28, R_V29, R_V30, R_V31);
+
+reg_class sflt_reg %{
+    return _SFLT_REG_mask;
+%}
+
+reg_class dflt_low_reg %{
+    return _DFLT_REG_mask;
+%}
+
+reg_class actual_dflt_reg %{
+    return _DFLT_REG_mask;
+%}
+
+reg_class vectorx_reg_0(
+  R_V0,  R_V1,  R_V2,  R_V3,  R_V4,  R_V5, R_V6, R_V7,
+  R_V8,  R_V9,  R_V10, R_V11, R_V12, R_V13, R_V14, R_V15,
+  R_V16, R_V17, R_V18, R_V19, R_V20, R_V21, R_V22, R_V23,
+  R_V24, R_V25, R_V26, R_V27, R_V28, R_V29, R_V30, /*R_V31,*/
+  R_V0b,  R_V1b,  R_V2b,  R_V3b,  R_V4b,  R_V5b,  R_V6b,  R_V7b,
+  R_V8b,  R_V9b,  R_V10b, R_V11b, R_V12b, R_V13b, R_V14b, R_V15b,
+  R_V16b, R_V17b, R_V18b, R_V19b, R_V20b, R_V21b, R_V22b, R_V23b,
+  R_V24b, R_V25b, R_V26b, R_V27b, R_V28b, R_V29b, R_V30b, /*R_V31b,*/
+  R_V0c,  R_V1c,  R_V2c,  R_V3c,  R_V4c,  R_V5c,  R_V6c,  R_V7c,
+  R_V8c,  R_V9c,  R_V10c, R_V11c, R_V12c, R_V13c, R_V14c, R_V15c,
+  R_V16c, R_V17c, R_V18c, R_V19c, R_V20c, R_V21c, R_V22c, R_V23c,
+  R_V24c, R_V25c, R_V26c, R_V27c, R_V28c, R_V29c, R_V30c, /*R_V31c,*/
+  R_V0d,  R_V1d,  R_V2d,  R_V3d,  R_V4d,  R_V5d,  R_V6d,  R_V7d,
+  R_V8d,  R_V9d,  R_V10d, R_V11d, R_V12d, R_V13d, R_V14d, R_V15d,
+  R_V16d, R_V17d, R_V18d, R_V19d, R_V20d, R_V21d, R_V22d, R_V23d,
+  R_V24d, R_V25d, R_V26d, R_V27d, R_V28d, R_V29d, R_V30d, /*R_V31d*/);
+
+reg_class Rmemcopy_reg %{
+    return _RMEMCOPY_REG_mask;
+%}
+
+%}
+
+source_hpp %{
+
+const MachRegisterNumbers R_mem_copy_lo_num = R_V31_num;
+const MachRegisterNumbers R_mem_copy_hi_num = R_V31b_num;
+const FloatRegister Rmemcopy = V31;
+
+const MachRegisterNumbers R_hf_ret_lo_num = R_V0_num;
+const MachRegisterNumbers R_hf_ret_hi_num = R_V0b_num;
+const FloatRegister Rhfret = V0;
+
+extern OptoReg::Name R_Ricklass_num;
+extern OptoReg::Name R_Rmethod_num;
+extern OptoReg::Name R_tls_num;
+extern OptoReg::Name R_Rheap_base_num;
+
+extern RegMask _INT_REG_mask;
+extern RegMask _PTR_REG_mask;
+extern RegMask _SFLT_REG_mask;
+extern RegMask _DFLT_REG_mask;
+extern RegMask _VECTORX_REG_mask;
+extern RegMask _RMEMCOPY_REG_mask;
+extern RegMask _SP_PTR_REG_mask;
+extern RegMask _SPILLP_REG_mask;
+extern RegMask _STR_REG_mask;
+extern RegMask _STR_PTR_REG_mask;
+
+#define LDR_DOUBLE "LDR_D"
+#define LDR_FLOAT  "LDR_S"
+#define STR_DOUBLE "STR_D"
+#define STR_FLOAT  "STR_S"
+#define STR_64     "STR"
+#define LDR_64     "LDR"
+#define STR_32     "STR_W"
+#define LDR_32     "LDR_W"
+#define MOV_DOUBLE "FMOV_D"
+#define MOV_FLOAT  "FMOV_S"
+#define FMSR       "FMOV_SW"
+#define FMRS       "FMOV_WS"
+#define LDREX      "ldxr  "
+#define STREX      "stxr  "
+
+#define str_64     str
+#define ldr_64     ldr
+#define ldr_32     ldr_w
+#define ldrex      ldxr
+#define strex      stxr
+
+#define fmsr       fmov_sw
+#define fmrs       fmov_ws
+#define fconsts    fmov_s
+#define fconstd    fmov_d
+
+static inline bool is_uimm12(jlong imm, int shift) {
+  return Assembler::is_unsigned_imm_in_range(imm, 12, shift);
+}
+
+static inline bool is_memoryD(int offset) {
+  int scale = 3; // LogBytesPerDouble
+  return is_uimm12(offset, scale);
+}
+
+static inline bool is_memoryfp(int offset) {
+  int scale = LogBytesPerInt; // include 32-bit word accesses
+  return is_uimm12(offset, scale);
+}
+
+static inline bool is_memoryI(int offset) {
+  int scale = LogBytesPerInt;
+  return is_uimm12(offset, scale);
+}
+
+static inline bool is_memoryP(int offset) {
+  int scale = LogBytesPerWord;
+  return is_uimm12(offset, scale);
+}
+
+static inline bool is_memoryHD(int offset) {
+  int scale = LogBytesPerInt; // include 32-bit word accesses
+  return is_uimm12(offset, scale);
+}
+
+uintx limmL_low(uintx imm, int n);
+
+static inline bool Xis_aimm(int imm) {
+  return Assembler::ArithmeticImmediate(imm).is_encoded();
+}
+
+static inline bool is_aimm(intptr_t imm) {
+  return Assembler::ArithmeticImmediate(imm).is_encoded();
+}
+
+static inline bool is_limmL(uintptr_t imm) {
+  return Assembler::LogicalImmediate(imm).is_encoded();
+}
+
+static inline bool is_limmL_low(intptr_t imm, int n) {
+  return is_limmL(limmL_low(imm, n));
+}
+
+static inline bool is_limmI(jint imm) {
+  return Assembler::LogicalImmediate(imm, true).is_encoded();
+}
+
+static inline uintx limmI_low(jint imm, int n) {
+  return limmL_low(imm, n);
+}
+
+static inline bool is_limmI_low(jint imm, int n) {
+  return is_limmL_low(imm, n);
+}
+
+%}
+
+source %{
+
+// Given a register encoding, produce a Integer Register object
+static Register reg_to_register_object(int register_encoding) {
+  assert(R0->encoding() == R_R0_enc && R30->encoding() == R_R30_enc, "right coding");
+  assert(Rthread->encoding() == R_R28_enc, "right coding");
+  assert(SP->encoding() == R_SP_enc, "right coding");
+  return as_Register(register_encoding);
+}
+
+// Given a register encoding, produce a single-precision Float Register object
+static FloatRegister reg_to_FloatRegister_object(int register_encoding) {
+  assert(V0->encoding() == R_V0_enc && V31->encoding() == R_V31_enc, "right coding");
+  return as_FloatRegister(register_encoding);
+}
+
+RegMask _INT_REG_mask;
+RegMask _PTR_REG_mask;
+RegMask _SFLT_REG_mask;
+RegMask _DFLT_REG_mask;
+RegMask _VECTORX_REG_mask;
+RegMask _RMEMCOPY_REG_mask;
+RegMask _SP_PTR_REG_mask;
+RegMask _SPILLP_REG_mask;
+RegMask _STR_REG_mask;
+RegMask _STR_PTR_REG_mask;
+
+OptoReg::Name R_Ricklass_num = -1;
+OptoReg::Name R_Rmethod_num  = -1;
+OptoReg::Name R_tls_num      = -1;
+OptoReg::Name R_Rtemp_num    = -1;
+OptoReg::Name R_Rheap_base_num = -1;
+
+static int mov_oop_size = -1;
+
+#ifdef ASSERT
+static bool same_mask(const RegMask &a, const RegMask &b) {
+    RegMask a_sub_b = a; a_sub_b.SUBTRACT(b);
+    RegMask b_sub_a = b; b_sub_a.SUBTRACT(a);
+    return a_sub_b.Size() == 0 && b_sub_a.Size() == 0;
+}
+#endif
+
+void Compile::pd_compiler2_init() {
+
+    R_Ricklass_num = OptoReg::as_OptoReg(Ricklass->as_VMReg());
+    R_Rmethod_num  = OptoReg::as_OptoReg(Rmethod->as_VMReg());
+    R_tls_num      = OptoReg::as_OptoReg(Rthread->as_VMReg());
+    R_Rtemp_num    = OptoReg::as_OptoReg(Rtemp->as_VMReg());
+    R_Rheap_base_num = OptoReg::as_OptoReg(Rheap_base->as_VMReg());
+
+    _INT_REG_mask = _INT_REG_ALL_mask;
+    _INT_REG_mask.Remove(R_tls_num);
+    _INT_REG_mask.Remove(R_SP_num);
+    if (UseCompressedOops) {
+      _INT_REG_mask.Remove(R_Rheap_base_num);
+    }
+    // Remove Rtemp because safepoint poll can trash it
+    // (see SharedRuntime::generate_handler_blob)
+    _INT_REG_mask.Remove(R_Rtemp_num);
+
+    _PTR_REG_mask = _INT_REG_mask;
+    _PTR_REG_mask.smear_to_sets(2);
+
+    // STR_REG    = INT_REG+ZR
+    // SPILLP_REG = INT_REG+SP
+    // SP_PTR_REG = INT_REG+SP+TLS
+    _STR_REG_mask = _INT_REG_mask;
+    _SP_PTR_REG_mask = _STR_REG_mask;
+    _STR_REG_mask.Insert(R_ZR_num);
+    _SP_PTR_REG_mask.Insert(R_SP_num);
+    _SPILLP_REG_mask = _SP_PTR_REG_mask;
+    _SP_PTR_REG_mask.Insert(R_tls_num);
+    _STR_PTR_REG_mask = _STR_REG_mask;
+    _STR_PTR_REG_mask.smear_to_sets(2);
+    _SP_PTR_REG_mask.smear_to_sets(2);
+    _SPILLP_REG_mask.smear_to_sets(2);
+
+    _RMEMCOPY_REG_mask = RegMask(R_mem_copy_lo_num);
+assert(OptoReg::as_OptoReg(Rmemcopy->as_VMReg()) == R_mem_copy_lo_num, "!");
+
+    _SFLT_REG_mask = _SFLT_REG_0_mask;
+    _SFLT_REG_mask.SUBTRACT(_RMEMCOPY_REG_mask);
+    _DFLT_REG_mask = _SFLT_REG_mask;
+    _DFLT_REG_mask.smear_to_sets(2);
+    _VECTORX_REG_mask = _SFLT_REG_mask;
+    _VECTORX_REG_mask.smear_to_sets(4);
+    assert(same_mask(_VECTORX_REG_mask, _VECTORX_REG_0_mask), "!");
+
+#ifdef ASSERT
+    RegMask r((RegMask *)&SFLT_REG_mask());
+    r.smear_to_sets(2);
+    assert(same_mask(r, _DFLT_REG_mask), "!");
+#endif
+
+    if (VM_Version::prefer_moves_over_load_literal()) {
+      mov_oop_size = 4;
+    } else {
+      mov_oop_size = 1;
+    }
+
+    assert(Matcher::interpreter_method_oop_reg_encode() == Rmethod->encoding(), "should be");
+}
+
+uintx limmL_low(uintx imm, int n) {
+  // 1: try as is
+  if (is_limmL(imm)) {
+    return imm;
+  }
+  // 2: try low bits + all 0's
+  uintx imm0 = imm & right_n_bits(n);
+  if (is_limmL(imm0)) {
+    return imm0;
+  }
+  // 3: try low bits + all 1's
+  uintx imm1 = imm0 | left_n_bits(BitsPerWord - n);
+  if (is_limmL(imm1)) {
+    return imm1;
+  }
+#if 0
+  // 4: try low bits replicated
+  int field = 1 << log2_intptr(n + n - 1);
+  assert(field >= n, "!");
+  assert(field / n == 1, "!");
+  intptr_t immr = immx;
+  while (field < BitsPerWord) {
+    intrptr_t bits = immr & right_n_bits(field);
+    immr = bits | (bits << field);
+    field = field << 1;
+  }
+  // replicate at power-of-2 boundary
+  if (is_limmL(immr)) {
+    return immr;
+  }
+#endif
+  return imm;
+}
+
+// Convert the raw encoding form into the form expected by the
+// constructor for Address.
+Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) {
+  RelocationHolder rspec;
+  if (disp_reloc != relocInfo::none) {
+    rspec = Relocation::spec_simple(disp_reloc);
+  }
+
+  Register rbase = (base == 0xff) ? SP : as_Register(base);
+  if (index != 0xff) {
+    Register rindex = as_Register(index);
+    if (disp == 0x7fffffff) { // special value to indicate sign-extend
+      Address madr(rbase, rindex, ex_sxtw, scale);
+      madr._rspec = rspec;
+      return madr;
+    } else {
+      assert(disp == 0, "unsupported");
+      Address madr(rbase, rindex, ex_lsl, scale);
+      madr._rspec = rspec;
+      return madr;
+    }
+  } else {
+    assert(scale == 0, "not supported");
+    Address madr(rbase, disp);
+    madr._rspec = rspec;
+    return madr;
+  }
+}
+
+// Location of compiled Java return values.  Same as C
+OptoRegPair c2::return_value(int ideal_reg) {
+  assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" );
+  static int lo[Op_RegL+1] = { 0, 0, OptoReg::Bad, R_R0_num,     R_R0_num,  R_hf_ret_lo_num,  R_hf_ret_lo_num, R_R0_num };
+  static int hi[Op_RegL+1] = { 0, 0, OptoReg::Bad, OptoReg::Bad, R_R0x_num, OptoReg::Bad,     R_hf_ret_hi_num, R_R0x_num };
+  return OptoRegPair( hi[ideal_reg], lo[ideal_reg]);
+}
+
+// !!!!! Special hack to get all type of calls to specify the byte offset
+//       from the start of the call to the point where the return address
+//       will point.
+
+int MachCallStaticJavaNode::ret_addr_offset() {
+  bool far = (_method == NULL) ? maybe_far_call(this) : !cache_reachable();
+  bool patchable = _method != NULL;
+  int call_size = MacroAssembler::call_size(entry_point(), far, patchable);
+  return (call_size + (_method_handle_invoke ? 1 : 0)) * NativeInstruction::instruction_size;
+}
+
+int MachCallDynamicJavaNode::ret_addr_offset() {
+  bool far = !cache_reachable();
+  int call_size = MacroAssembler::call_size(entry_point(), far, true);
+  return (mov_oop_size + call_size) * NativeInstruction::instruction_size; 
+}
+
+int MachCallRuntimeNode::ret_addr_offset() {
+  int call_size = 0;
+  // TODO: check if Leaf nodes also need this
+  if (!is_MachCallLeaf()) {
+    // adr $temp, ret_addr
+    // str $temp, [SP + last_java_pc]
+    call_size += 2;
+  }
+  // bl or mov_slow; blr
+  bool far = maybe_far_call(this);
+  call_size += MacroAssembler::call_size(entry_point(), far, false);
+  return call_size * NativeInstruction::instruction_size;
+}
+
+%}
+
+// The intptr_t operand types, defined by textual substitution.
+// (Cf. opto/type.hpp.  This lets us avoid many, many other ifdefs.)
+#define immX      immL
+#define iRegX     iRegL
+#define aimmX     aimmL
+#define limmX     limmL
+#define immX9     immL9
+#define LShiftX   LShiftL
+#define shimmX    immU6
+
+#define store_RegLd store_RegL
+
+//----------ATTRIBUTES---------------------------------------------------------
+//----------Operand Attributes-------------------------------------------------
+op_attrib op_cost(1);          // Required cost attribute
+
+//----------OPERANDS-----------------------------------------------------------
+// Operand definitions must precede instruction definitions for correct parsing
+// in the ADLC because operands constitute user defined types which are used in
+// instruction definitions.
+
+//----------Simple Operands----------------------------------------------------
+// Immediate Operands
+
+// Integer Immediate: 9-bit (including sign bit), so same as immI8?
+// FIXME: simm9 allows -256, but immI8 doesn't...
+operand simm9() %{
+  predicate(Assembler::is_imm_in_range(n->get_int(), 9, 0));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+
+operand uimm12() %{
+  predicate(Assembler::is_unsigned_imm_in_range(n->get_int(), 12, 0));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand aimmP() %{
+  predicate(n->get_ptr() == 0 || (is_aimm(n->get_ptr()) && ((ConPNode*)n)->type()->reloc() == relocInfo::none));
+  match(ConP);
+
+  op_cost(0);
+  // formats are generated automatically for constants and base registers
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: 12-bit - for addressing mode
+operand immL12() %{
+  predicate((-4096 < n->get_long()) && (n->get_long() < 4096));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Long Immediate: 9-bit - for addressing mode
+operand immL9() %{
+  predicate((-256 <= n->get_long()) && (n->get_long() < 256));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immIMov() %{
+  predicate(n->get_int() >> 16 == 0);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immLMov() %{
+  predicate(n->get_long() >> 16 == 0);
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immUL12() %{
+  predicate(is_uimm12(n->get_long(), 0));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immUL12x2() %{
+  predicate(is_uimm12(n->get_long(), 1));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immUL12x4() %{
+  predicate(is_uimm12(n->get_long(), 2));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immUL12x8() %{
+  predicate(is_uimm12(n->get_long(), 3));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+operand immUL12x16() %{
+  predicate(is_uimm12(n->get_long(), 4));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Used for long shift
+operand immU6() %{
+  predicate(0 <= n->get_int() && (n->get_int() <= 63));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Used for register extended shift
+operand immI_0_4() %{
+  predicate(0 <= n->get_int() && (n->get_int() <= 4));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Compressed Pointer Register
+operand iRegN() %{
+  constraint(ALLOC_IN_RC(int_reg));
+  match(RegN);
+  match(ZRRegN);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand SPRegP() %{
+  constraint(ALLOC_IN_RC(SP_regP));
+  match(RegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand ZRRegP() %{
+  constraint(ALLOC_IN_RC(ZR_regP));
+  match(RegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand ZRRegL() %{
+  constraint(ALLOC_IN_RC(ZR_regP));
+  match(RegL);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand ZRRegI() %{
+  constraint(ALLOC_IN_RC(ZR_regI));
+  match(RegI);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
+operand ZRRegN() %{
+  constraint(ALLOC_IN_RC(ZR_regI));
+  match(RegN);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm.cpp b/hotspot/src/cpu/arm/vm/assembler_arm.cpp
new file mode 100644
index 0000000..e113020
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
+#include "ci/ciEnv.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateInterpreterGenerator.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvm_misc.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/hashtable.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/heapRegion.hpp"
+#endif // INCLUDE_ALL_GCS
+
+int AbstractAssembler::code_fill_byte() {
+  return 0xff; // illegal instruction 0xffffffff
+}
+
+#ifdef ASSERT
+bool AbstractAssembler::pd_check_instruction_mark() { return false; }
+#endif
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm.hpp b/hotspot/src/cpu/arm/vm/assembler_arm.hpp
new file mode 100644
index 0000000..ca1708e
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm.hpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_ASSEMBLER_ARM_HPP
+
+#include "utilities/macros.hpp"
+
+enum AsmCondition {
+  eq, ne, cs, cc, mi, pl, vs, vc,
+  hi, ls, ge, lt, gt, le, al, nv,
+  number_of_conditions,
+  // alternative names
+  hs = cs,
+  lo = cc
+};
+
+enum AsmShift {
+  lsl, lsr, asr, ror
+};
+
+#ifdef AARCH64
+enum AsmExtendOp {
+  ex_uxtb, ex_uxth, ex_uxtw, ex_uxtx,
+  ex_sxtb, ex_sxth, ex_sxtw, ex_sxtx,
+
+  ex_lsl = ex_uxtx
+};
+#endif
+
+enum AsmOffset {
+#ifdef AARCH64
+  basic_offset = 0b00,
+  pre_indexed  = 0b11,
+  post_indexed = 0b01
+#else
+  basic_offset = 1 << 24,
+  pre_indexed  = 1 << 24 | 1 << 21,
+  post_indexed = 0
+#endif
+};
+
+
+#ifndef AARCH64
+enum AsmWriteback {
+  no_writeback,
+  writeback
+};
+
+enum AsmOffsetOp {
+  sub_offset = 0,
+  add_offset = 1
+};
+#endif
+
+
+// ARM Addressing Modes 2 and 3 - Load and store
+class Address VALUE_OBJ_CLASS_SPEC {
+ private:
+  Register  _base;
+  Register  _index;
+  int       _disp;
+  AsmOffset _mode;
+  RelocationHolder   _rspec;
+  int       _shift_imm;
+#ifdef AARCH64
+  AsmExtendOp _extend;
+#else
+  AsmShift  _shift;
+  AsmOffsetOp _offset_op;
+
+  static inline int abs(int x) { return x < 0 ? -x : x; }
+  static inline int up (int x) { return x < 0 ?  0 : 1; }
+#endif
+
+#ifdef AARCH64
+  static const AsmExtendOp LSL = ex_lsl;
+#else
+  static const AsmShift LSL = lsl;
+#endif
+
+ public:
+  Address() : _base(noreg) {}
+
+  Address(Register rn, int offset = 0, AsmOffset mode = basic_offset) {
+    _base = rn;
+    _index = noreg;
+    _disp = offset;
+    _mode = mode;
+    _shift_imm = 0;
+#ifdef AARCH64
+    _extend = ex_lsl;
+#else
+    _shift = lsl;
+    _offset_op = add_offset;
+#endif
+  }
+
+#ifdef ASSERT
+  Address(Register rn, ByteSize offset, AsmOffset mode = basic_offset) {
+    _base = rn;
+    _index = noreg;
+    _disp = in_bytes(offset);
+    _mode = mode;
+    _shift_imm = 0;
+#ifdef AARCH64
+    _extend = ex_lsl;
+#else
+    _shift = lsl;
+    _offset_op = add_offset;
+#endif
+  }
+#endif
+
+#ifdef AARCH64
+  Address(Register rn, Register rm, AsmExtendOp extend = ex_lsl, int shift_imm = 0) {
+    assert ((extend == ex_uxtw) || (extend == ex_lsl) || (extend == ex_sxtw) || (extend == ex_sxtx), "invalid extend for address mode");
+    assert ((0 <= shift_imm) && (shift_imm <= 4), "shift amount is out of range");
+    _base = rn;
+    _index = rm;
+    _disp = 0;
+    _mode = basic_offset;
+    _extend = extend;
+    _shift_imm = shift_imm;
+  }
+#else
+  Address(Register rn, Register rm, AsmShift shift = lsl,
+          int shift_imm = 0, AsmOffset mode = basic_offset,
+          AsmOffsetOp offset_op = add_offset) {
+    _base = rn;
+    _index = rm;
+    _disp = 0;
+    _shift = shift;
+    _shift_imm = shift_imm;
+    _mode = mode;
+    _offset_op = offset_op;
+  }
+
+  Address(Register rn, RegisterOrConstant offset, AsmShift shift = lsl,
+          int shift_imm = 0) {
+    _base = rn;
+    if (offset.is_constant()) {
+      _index = noreg;
+      {
+        int off = (int) offset.as_constant();
+        if (shift_imm != 0) {
+          assert(shift == lsl,"shift not yet encoded");
+          off =  off << shift_imm;
+        }
+        _disp = off;
+      }
+      _shift = lsl;
+      _shift_imm = 0;
+    } else {
+      _index = offset.as_register();
+      _disp = 0;
+      _shift = shift;
+      _shift_imm = shift_imm;
+    }
+    _mode = basic_offset;
+    _offset_op = add_offset;
+  }
+#endif // AARCH64
+
+  // [base + index * wordSize]
+  static Address indexed_ptr(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerWord);
+  }
+
+  // [base + index * BytesPerInt]
+  static Address indexed_32(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerInt);
+  }
+
+  // [base + index * BytesPerHeapOop]
+  static Address indexed_oop(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerHeapOop);
+  }
+
+  Address plus_disp(int disp) const {
+    assert((disp == 0) || (_index == noreg),"can't apply an offset to a register indexed address");
+    Address a = (*this);
+    a._disp += disp;
+    return a;
+  }
+
+  Address rebase(Register new_base) const {
+    Address a = (*this);
+    a._base = new_base;
+    return a;
+  }
+
+#ifdef AARCH64
+  int encoding_simd() const {
+    assert(_index != SP, "encoding constraint");
+    assert(_disp == 0 || _mode == post_indexed,  "encoding constraint");
+    assert(_index == noreg || _mode == basic_offset, "encoding constraint");
+    assert(_mode == basic_offset || _mode == post_indexed, "encoding constraint");
+    assert(_extend == ex_lsl, "encoding constraint");
+    int index;
+    if (_index == noreg) {
+      if (_mode == post_indexed)
+        index = 0b100 << 5 | 31;
+      else
+        index = 0;
+    } else {
+      index = 0b100 << 5 | _index->encoding();
+    }
+    return index << 16 | _base->encoding_with_sp() << 5;
+  }
+#else /* !AARCH64 */
+  int encoding2() const {
+    assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
+    if (_index == noreg) {
+      assert(-4096 < _disp && _disp < 4096, "encoding constraint");
+      return _mode | up(_disp) << 23 | _base->encoding() << 16 | abs(_disp);
+    } else {
+      assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
+      assert(_disp == 0 && (_shift_imm >> 5) == 0, "encoding constraint");
+      return 1 << 25 | _offset_op << 23 | _mode | _base->encoding() << 16 |
+             _shift_imm << 7 | _shift << 5 | _index->encoding();
+    }
+  }
+
+  int encoding3() const {
+    assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
+    if (_index == noreg) {
+      assert(-256 < _disp && _disp < 256, "encoding constraint");
+      return _mode | up(_disp) << 23 | 1 << 22 | _base->encoding() << 16 |
+             (abs(_disp) & 0xf0) << 4 | abs(_disp) & 0x0f;
+    } else {
+      assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
+      assert(_disp == 0 && _shift == lsl && _shift_imm == 0, "encoding constraint");
+      return _mode | _offset_op << 23 | _base->encoding() << 16 | _index->encoding();
+    }
+  }
+
+  int encoding_ex() const {
+    assert(_index == noreg && _disp == 0 && _mode == basic_offset &&
+           _base != PC, "encoding constraint");
+    return _base->encoding() << 16;
+  }
+
+  int encoding_vfp() const {
+    assert(_index == noreg && _mode == basic_offset, "encoding constraint");
+    assert(-1024 < _disp && _disp < 1024 && (_disp & 3) == 0, "encoding constraint");
+    return _base->encoding() << 16 | up(_disp) << 23 | abs(_disp) >> 2;
+  }
+
+  int encoding_simd() const {
+    assert(_base != PC, "encoding constraint");
+    assert(_index != PC && _index != SP, "encoding constraint");
+    assert(_disp == 0, "encoding constraint");
+    assert(_shift == 0, "encoding constraint");
+    assert(_index == noreg || _mode == basic_offset, "encoding constraint");
+    assert(_mode == basic_offset || _mode == post_indexed, "encoding constraint");
+    int index;
+    if (_index == noreg) {
+      if (_mode == post_indexed)
+        index = 13;
+      else
+        index = 15;
+    } else {
+      index = _index->encoding();
+    }
+
+    return _base->encoding() << 16 | index;
+  }
+#endif // !AARCH64
+
+  Register base() const {
+    return _base;
+  }
+
+  Register index() const {
+    return _index;
+  }
+
+  int disp() const {
+    return _disp;
+  }
+
+  AsmOffset mode() const {
+    return _mode;
+  }
+
+  int shift_imm() const {
+    return _shift_imm;
+  }
+
+#ifdef AARCH64
+  AsmExtendOp extend() const {
+    return _extend;
+  }
+#else
+  AsmShift shift() const {
+    return _shift;
+  }
+
+  AsmOffsetOp offset_op() const {
+    return _offset_op;
+  }
+#endif
+
+  bool uses(Register reg) const { return _base == reg || _index == reg; }
+
+  const relocInfo::relocType rtype() { return _rspec.type(); }
+  const RelocationHolder&    rspec() { return _rspec; }
+
+  // Convert the raw encoding form into the form expected by the
+  // constructor for Address.
+  static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
+};
+
+#ifdef COMPILER2
+class VFP VALUE_OBJ_CLASS_SPEC {
+  // Helper classes to detect whether a floating point constant can be
+  // encoded in a fconstd or fconsts instruction
+  // The conversion from the imm8, 8 bit constant, to the floating
+  // point value encoding is done with either:
+  // for single precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19)
+  // or
+  // for double precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,8):imm8<5:0>:Zeros(48)
+
+ private:
+  class fpnum {
+   public:
+    virtual unsigned int f_hi4() const = 0;
+    virtual bool f_lo_is_null() const = 0;
+    virtual int e() const = 0;
+    virtual unsigned int s() const = 0;
+
+    inline bool can_be_imm8() const { return e() >= -3 && e() <= 4 && f_lo_is_null(); }
+    inline unsigned char imm8() const { int v = (s() << 7) | (((e() - 1) & 0x7) << 4) | f_hi4(); assert((v >> 8) == 0, "overflow"); return v; }
+  };
+
+ public:
+  class float_num : public fpnum {
+   public:
+    float_num(float v) {
+      _num.val = v;
+    }
+
+    virtual unsigned int f_hi4() const { return (_num.bits << 9) >> (19+9); }
+    virtual bool f_lo_is_null() const { return (_num.bits & ((1 << 19) - 1)) == 0; }
+    virtual int e() const { return ((_num.bits << 1) >> (23+1)) - 127; }
+    virtual unsigned int s() const { return _num.bits >> 31; }
+
+   private:
+    union {
+      float val;
+      unsigned int bits;
+    } _num;
+  };
+
+  class double_num : public fpnum {
+   public:
+    double_num(double v) {
+      _num.val = v;
+    }
+
+    virtual unsigned int f_hi4() const { return (_num.bits << 12) >> (48+12); }
+    virtual bool f_lo_is_null() const { return (_num.bits & ((1LL << 48) - 1)) == 0; }
+    virtual int e() const { return ((_num.bits << 1) >> (52+1)) - 1023; }
+    virtual unsigned int s() const { return _num.bits >> 63; }
+
+   private:
+    union {
+      double val;
+      unsigned long long bits;
+    } _num;
+  };
+};
+#endif
+
+#ifdef AARCH64
+#include "assembler_arm_64.hpp"
+#else
+#include "assembler_arm_32.hpp"
+#endif
+
+
+#endif // CPU_ARM_VM_ASSEMBLER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm.inline.hpp b/hotspot/src/cpu/arm/vm/assembler_arm.inline.hpp
new file mode 100644
index 0000000..76585f4
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm.inline.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ASSEMBLER_ARM_INLINE_HPP
+#define CPU_ARM_VM_ASSEMBLER_ARM_INLINE_HPP
+
+
+#endif // CPU_ARM_VM_ASSEMBLER_ARM_INLINE_HPP
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm_32.cpp b/hotspot/src/cpu/arm/vm/assembler_arm_32.cpp
new file mode 100644
index 0000000..69a609d
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm_32.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
+#include "ci/ciEnv.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateInterpreterGenerator.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvm_misc.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/hashtable.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/heapRegion.hpp"
+#endif // INCLUDE_ALL_GCS
+
+#ifdef COMPILER2
+// Convert the raw encoding form into the form expected by the
+// constructor for Address.
+Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) {
+  RelocationHolder rspec;
+  if (disp_reloc != relocInfo::none) {
+    rspec = Relocation::spec_simple(disp_reloc);
+  }
+
+  Register rindex = as_Register(index);
+  if (rindex != PC) {
+    assert(disp == 0, "unsupported");
+    Address madr(as_Register(base), rindex, lsl, scale);
+    madr._rspec = rspec;
+    return madr;
+  } else {
+    assert(scale == 0, "not supported");
+    Address madr(as_Register(base), disp);
+    madr._rspec = rspec;
+    return madr;
+  }
+}
+#endif
+
+void AsmOperand::initialize_rotated_imm(unsigned int imm) {
+  for (int shift = 2; shift <= 24; shift += 2) {
+    if ((imm & ~(0xff << shift)) == 0) {
+      _encoding = 1 << 25 | (32 - shift) << 7 | imm >> shift;
+      return;
+    }
+  }
+  assert((imm & 0x0ffffff0) == 0, "too complicated constant: %d (%x)", imm, imm);
+  _encoding = 1 << 25 | 4 << 7 | imm >> 28 | imm << 4;
+}
+
+bool AsmOperand::is_rotated_imm(unsigned int imm) {
+  if ((imm >> 8) == 0) {
+    return true;
+  }
+  for (int shift = 2; shift <= 24; shift += 2) {
+    if ((imm & ~(0xff << shift)) == 0) {
+      return true;
+    }
+  }
+  if ((imm & 0x0ffffff0) == 0) {
+    return true;
+  }
+  return false;
+}
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm_32.hpp b/hotspot/src/cpu/arm/vm/assembler_arm_32.hpp
new file mode 100644
index 0000000..e32f6a9
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm_32.hpp
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ASSEMBLER_ARM_32_HPP
+#define CPU_ARM_VM_ASSEMBLER_ARM_32_HPP
+
+// ARM Addressing Mode 1 - Data processing operands
+class AsmOperand VALUE_OBJ_CLASS_SPEC {
+ private:
+  int _encoding;
+
+  void initialize_rotated_imm(unsigned int imm);
+
+  void encode(int imm_8) {
+    if ((imm_8 >> 8) == 0) {
+      _encoding = 1 << 25 | imm_8;  // the most common case
+    } else {
+      initialize_rotated_imm((unsigned int)imm_8);  // slow case
+    }
+  }
+
+  void encode(Register rm, AsmShift shift, int shift_imm) {
+    assert((shift_imm >> 5) == 0, "encoding constraint");
+    _encoding = shift_imm << 7 | shift << 5 | rm->encoding();
+  }
+
+ public:
+
+  AsmOperand(Register reg) {
+    _encoding = reg->encoding();
+  }
+
+  AsmOperand(int imm_8) {
+    encode(imm_8);
+  }
+
+#ifdef ASSERT
+  AsmOperand(ByteSize bytesize_8) {
+    const int imm_8 = in_bytes(bytesize_8);
+    encode(imm_8);
+  }
+#endif // ASSERT
+
+  AsmOperand(Register rm, AsmShift shift, int shift_imm) {
+    encode(rm,shift,shift_imm);
+  }
+
+  AsmOperand(Register rm, AsmShift shift, Register rs) {
+    assert(rm != PC && rs != PC, "unpredictable instruction");
+    _encoding = rs->encoding() << 8 | shift << 5 | 1 << 4 | rm->encoding();
+  }
+
+  AsmOperand(RegisterOrConstant offset, AsmShift shift = lsl, int shift_imm = 0) {
+    if (offset.is_register()) {
+      encode(offset.as_register(), shift, shift_imm);
+    } else {
+      assert(shift == lsl,"shift type not yet encoded");
+      int imm_8 = ((int)offset.as_constant()) << shift_imm;
+      encode(imm_8);
+    }
+  }
+
+  int encoding() const {
+    return _encoding;
+  }
+
+  bool is_immediate() const {
+    return _encoding & (1 << 25) ? true : false;
+  }
+
+  Register base_register() const {
+    assert(!is_immediate(), "is_immediate, no base reg");
+    return as_Register(_encoding & 15);
+  }
+
+  static bool is_rotated_imm(unsigned int imm);
+};
+
+
+// ARM Addressing Mode 4 - Load and store multiple
+class RegisterSet VALUE_OBJ_CLASS_SPEC {
+ private:
+  int _encoding;
+
+  RegisterSet(int encoding) {
+    _encoding = encoding;
+  }
+
+ public:
+
+  RegisterSet(Register reg) {
+    _encoding = 1 << reg->encoding();
+  }
+
+  RegisterSet() {
+    _encoding = 0;
+  }
+
+  RegisterSet(Register first, Register last) {
+    assert(first < last, "encoding constraint");
+    _encoding = (1 << (last->encoding() + 1)) - (1 << first->encoding());
+  }
+
+  friend RegisterSet operator | (const RegisterSet set1, const RegisterSet set2) {
+    assert((set1._encoding & set2._encoding) == 0,
+           "encoding constraint");
+    return RegisterSet(set1._encoding | set2._encoding);
+  }
+
+  int encoding() const {
+    return _encoding;
+  }
+
+  bool contains(Register reg) const {
+    return (_encoding & (1 << reg->encoding())) != 0;
+  }
+
+  // number of registers in the set
+  int size() const {
+    int count = 0;
+    unsigned int remaining = (unsigned int) _encoding;
+    while (remaining != 0) {
+      if ((remaining & 1) != 0) count++;
+      remaining >>= 1;
+    }
+    return count;
+  }
+};
+
+#if R9_IS_SCRATCHED
+#define R9ifScratched RegisterSet(R9)
+#else
+#define R9ifScratched RegisterSet()
+#endif
+
+// ARM Addressing Mode 5 - Load and store multiple VFP registers
+class FloatRegisterSet VALUE_OBJ_CLASS_SPEC {
+ private:
+  int _encoding;
+
+ public:
+
+  FloatRegisterSet(FloatRegister reg) {
+    if (reg->hi_bit() == 0) {
+      _encoding = reg->hi_bits() << 12 | reg->lo_bit() << 22 | 1;
+    } else {
+      assert (reg->lo_bit() == 0, "impossible encoding");
+      _encoding = reg->hi_bits() << 12 | reg->hi_bit() << 22 | 1;
+    }
+  }
+
+  FloatRegisterSet(FloatRegister first, int count) {
+    assert(count >= 1, "encoding constraint");
+    if (first->hi_bit() == 0) {
+      _encoding = first->hi_bits() << 12 | first->lo_bit() << 22 | count;
+    } else {
+      assert (first->lo_bit() == 0, "impossible encoding");
+      _encoding = first->hi_bits() << 12 | first->hi_bit() << 22 | count;
+    }
+  }
+
+  int encoding_s() const {
+    return _encoding;
+  }
+
+  int encoding_d() const {
+    assert((_encoding & 0xFF) <= 16, "no more than 16 double registers" );
+    return (_encoding & 0xFFFFFF00) | ((_encoding & 0xFF) << 1);
+  }
+
+};
+
+
+class Assembler : public AbstractAssembler  {
+
+ public:
+
+  static const int LogInstructionSize = 2;
+  static const int InstructionSize    = 1 << LogInstructionSize;
+
+  static inline AsmCondition inverse(AsmCondition cond) {
+    assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
+    return (AsmCondition)((int)cond ^ 1);
+  }
+
+  // Returns true if given value can be used as immediate in arithmetic (add/sub/cmp/cmn) instructions.
+  static inline bool is_arith_imm_in_range(intx value) {
+    return AsmOperand::is_rotated_imm(value);
+  }
+
+  // Arithmetic instructions
+
+#define F(mnemonic, opcode) \
+  void mnemonic(Register rd, Register rn, AsmOperand operand, AsmCondition cond = al) {    \
+    emit_int32(cond << 28 | opcode << 21 | rn->encoding() << 16 |                          \
+               rd->encoding() << 12 | operand.encoding());                                 \
+  }                                                                                        \
+  void mnemonic##s(Register rd, Register rn, AsmOperand operand, AsmCondition cond = al) { \
+    emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rn->encoding() << 16 |                \
+               rd->encoding() << 12 | operand.encoding());                                 \
+  }
+
+  F(andr, 0)
+  F(eor,  1)
+  F(sub,  2)
+  F(rsb,  3)
+  F(add,  4)
+  F(adc,  5)
+  F(sbc,  6)
+  F(rsc,  7)
+  F(orr,  12)
+  F(bic,  14)
+#undef F
+
+#define F(mnemonic, opcode) \
+  void mnemonic(Register rn, AsmOperand operand, AsmCondition cond = al) {  \
+    emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rn->encoding() << 16 | \
+              operand.encoding());                                          \
+  }
+
+  F(tst, 8)
+  F(teq, 9)
+  F(cmp, 10)
+  F(cmn, 11)
+#undef F
+
+#define F(mnemonic, opcode) \
+  void mnemonic(Register rd, AsmOperand operand, AsmCondition cond = al) {    \
+    emit_int32(cond << 28 | opcode << 21 | rd->encoding() << 12 |             \
+              operand.encoding());                                            \
+  }                                                                           \
+  void mnemonic##s(Register rd, AsmOperand operand, AsmCondition cond = al) { \
+    emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rd->encoding() << 12 |   \
+              operand.encoding());                                            \
+  }
+
+  F(mov, 13)
+  F(mvn, 15)
+#undef F
+
+  void msr(uint fields, AsmOperand operand, AsmCondition cond = al) {
+    assert((operand.encoding() & (1<<25)) || ((operand.encoding() & 0xff0) == 0), "invalid addressing mode");
+    emit_int32(cond << 28 | 1 << 24 | 1 << 21 | fields << 16 | 0xf << 12 | operand.encoding());
+  }
+
+  void mrs(uint fields, Register Rd, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 1 << 24 | (fields|0xf) << 16 | (Rd->encoding() << 12));
+  }
+
+
+  enum {
+    CPSR = 0x00, CPSR_c = 0x01, CPSR_x = 0x02, CPSR_xc = 0x03,
+    CPSR_s = 0x004, CPSR_sc = 0x05, CPSR_sx = 0x06, CPSR_sxc = 0x07,
+    CPSR_f = 0x08, CPSR_fc = 0x09, CPSR_fx = 0x0a, CPSR_fxc = 0x0b,
+    CPSR_fs = 0x0c, CPSR_fsc = 0x0d, CPSR_fsx = 0x0e, CPSR_fsxc = 0x0f,
+    SPSR = 0x40, SPSR_c = 0x41, SPSR_x = 0x42, SPSR_xc = 0x43,
+    SPSR_s = 0x44, SPSR_sc = 0x45, SPSR_sx = 0x46, SPSR_sxc = 0x47,
+    SPSR_f = 0x48, SPSR_fc = 0x49, SPSR_fx = 0x4a, SPSR_fxc = 0x4b,
+    SPSR_fs = 0x4c, SPSR_fsc = 0x4d, SPSR_fsx = 0x4e, SPSR_fsxc = 0x4f
+  };
+
+#define F(mnemonic, opcode) \
+  void mnemonic(Register rdlo, Register rdhi, Register rm, Register rs,                  \
+                AsmCondition cond = al) {                                                \
+    emit_int32(cond << 28 | opcode << 21 | rdhi->encoding() << 16 |                      \
+              rdlo->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding()); \
+  }                                                                                      \
+  void mnemonic##s(Register rdlo, Register rdhi, Register rm, Register rs,               \
+                   AsmCondition cond = al) {                                             \
+    emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rdhi->encoding() << 16 |            \
+              rdlo->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding()); \
+  }
+
+  F(umull, 4)
+  F(umlal, 5)
+  F(smull, 6)
+  F(smlal, 7)
+#undef F
+
+  void mul(Register rd, Register rm, Register rs, AsmCondition cond = al) {
+    emit_int32(cond << 28 | rd->encoding() << 16 |
+              rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
+  }
+
+  void muls(Register rd, Register rm, Register rs, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 1 << 20 | rd->encoding() << 16 |
+              rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
+  }
+
+  void mla(Register rd, Register rm, Register rs, Register rn, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 1 << 21 | rd->encoding() << 16 |
+              rn->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
+  }
+
+  void mlas(Register rd, Register rm, Register rs, Register rn, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 1 << 21 | 1 << 20 | rd->encoding() << 16 |
+              rn->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
+  }
+
+  // Loads and stores
+
+#define F(mnemonic, l, b) \
+  void mnemonic(Register rd, Address addr, AsmCondition cond = al) { \
+    emit_int32(cond << 28 | 1 << 26 | b << 22 | l << 20 |            \
+              rd->encoding() << 12 | addr.encoding2());              \
+  }
+
+  F(ldr,  1, 0)
+  F(ldrb, 1, 1)
+  F(str,  0, 0)
+  F(strb, 0, 1)
+#undef F
+
+#undef F
+
+#define F(mnemonic, l, sh, even) \
+  void mnemonic(Register rd, Address addr, AsmCondition cond = al) { \
+    assert(!even || (rd->encoding() & 1) == 0, "must be even");      \
+    emit_int32(cond << 28 | l << 20 | rd->encoding() << 12 |         \
+              1 << 7 | sh << 5 | 1 << 4 | addr.encoding3());         \
+  }
+
+  F(strh,  0, 1, false)
+  F(ldrh,  1, 1, false)
+  F(ldrsb, 1, 2, false)
+  F(ldrsh, 1, 3, false)
+  F(strd,  0, 3, true)
+
+#undef F
+
+  void ldrd(Register rd, Address addr, AsmCondition cond = al) {
+    assert((rd->encoding() & 1) == 0, "must be even");
+    assert(!addr.index()->is_valid() ||
+           (addr.index()->encoding() != rd->encoding() &&
+            addr.index()->encoding() != (rd->encoding()+1)), "encoding constraint");
+    emit_int32(cond << 28 | rd->encoding() << 12 | 0xD /* 0b1101 */ << 4 | addr.encoding3());
+  }
+
+#define F(mnemonic, l, pu) \
+  void mnemonic(Register rn, RegisterSet reg_set,                        \
+                AsmWriteback w = no_writeback, AsmCondition cond = al) { \
+    assert(reg_set.encoding() != 0 && (w == no_writeback ||              \
+           (reg_set.encoding() & (1 << rn->encoding())) == 0),           \
+           "unpredictable instruction");                                 \
+    emit_int32(cond << 28 | 4 << 25 | pu << 23 | w << 21 | l << 20 |     \
+              rn->encoding() << 16 | reg_set.encoding());                \
+  }
+
+  F(ldmda, 1, 0)    F(ldmfa, 1, 0)
+  F(ldmia, 1, 1)    F(ldmfd, 1, 1)
+  F(ldmdb, 1, 2)    F(ldmea, 1, 2)
+  F(ldmib, 1, 3)    F(ldmed, 1, 3)
+  F(stmda, 0, 0)    F(stmed, 0, 0)
+  F(stmia, 0, 1)    F(stmea, 0, 1)
+  F(stmdb, 0, 2)    F(stmfd, 0, 2)
+  F(stmib, 0, 3)    F(stmfa, 0, 3)
+#undef F
+
+  void ldrex(Register rd, Address addr, AsmCondition cond = al) {
+    assert(rd != PC, "unpredictable instruction");
+    emit_int32(cond << 28 | 0x19 << 20 | addr.encoding_ex() |
+              rd->encoding()  << 12 | 0xf9f);
+  }
+
+  void strex(Register rs, Register rd, Address addr, AsmCondition cond = al) {
+    assert(rd != PC && rs != PC &&
+           rs != rd && rs != addr.base(), "unpredictable instruction");
+    emit_int32(cond << 28 | 0x18 << 20 | addr.encoding_ex() |
+              rs->encoding()  << 12 | 0xf90 | rd->encoding());
+  }
+
+  void ldrexd(Register rd, Address addr, AsmCondition cond = al) {
+    assert(rd != PC, "unpredictable instruction");
+    emit_int32(cond << 28 | 0x1B << 20 | addr.encoding_ex() |
+              rd->encoding()  << 12 | 0xf9f);
+  }
+
+  void strexd(Register rs, Register rd, Address addr, AsmCondition cond = al) {
+    assert(rd != PC && rs != PC &&
+           rs != rd && rs != addr.base(), "unpredictable instruction");
+    emit_int32(cond << 28 | 0x1A << 20 | addr.encoding_ex() |
+              rs->encoding()  << 12 | 0xf90 | rd->encoding());
+  }
+
+  void clrex() {
+    emit_int32(0xF << 28 | 0x57 << 20 | 0xFF  << 12 | 0x01f);
+  }
+
+  // Miscellaneous instructions
+
+  void clz(Register rd, Register rm, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 0x016f0f10 | rd->encoding() << 12 | rm->encoding());
+  }
+
+  void rev(Register rd, Register rm, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 0x06bf0f30 | rd->encoding() << 12 | rm->encoding());
+  }
+
+  void rev16(Register rd, Register rm, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 0x6bf0fb0 | rd->encoding() << 12 | rm->encoding());
+  }
+
+  void revsh(Register rd, Register rm, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 0x6ff0fb0 | rd->encoding() << 12 | rm->encoding());
+  }
+
+  void rbit(Register rd, Register rm, AsmCondition cond = al) {
+    emit_int32(cond << 28 | 0x6ff0f30 | rd->encoding() << 12 | rm->encoding());
+  }
+
+  void pld(Address addr) {
+    emit_int32(0xf550f000 | addr.encoding2());
+  }
+
+  void pldw(Address addr) {
+    assert(VM_Version::arm_arch() >= 7 && os::is_MP(), "no pldw on this processor");
+    emit_int32(0xf510f000 | addr.encoding2());
+  }
+
+  void svc(int imm_24, AsmCondition cond = al) {
+    assert((imm_24 >> 24) == 0, "encoding constraint");
+    emit_int32(cond << 28 | 0xf << 24 | imm_24);
+  }
+
+  void ubfx(Register rd, Register rn, unsigned int lsb, unsigned int width, AsmCondition cond = al) {
+    assert(VM_Version::arm_arch() >= 7, "no ubfx on this processor");
+    assert(width > 0, "must be");
+    assert(lsb < 32, "must be");
+    emit_int32(cond << 28 | 0x3f << 21 | (width - 1)  << 16 | rd->encoding() << 12 |
+              lsb << 7 | 0x5 << 4 | rn->encoding());
+  }
+
+  void uxtb(Register rd, Register rm, unsigned int rotation = 0, AsmCondition cond = al) {
+    assert(VM_Version::arm_arch() >= 7, "no uxtb on this processor");
+    assert((rotation % 8) == 0 && (rotation <= 24), "encoding constraint");
+    emit_int32(cond << 28 | 0x6e << 20 | 0xf << 16 | rd->encoding() << 12 |
+              (rotation >> 3) << 10 | 0x7 << 4 | rm->encoding());
+  }
+
+  // ARM Memory Barriers
+  //
+  // There are two types of memory barriers defined for the ARM processor
+  // DataSynchronizationBarrier and DataMemoryBarrier
+  //
+  // The Linux kernel uses the DataMemoryBarrier for all of it's
+  // memory barrier operations (smp_mb, smp_rmb, smp_wmb)
+  //
+  // There are two forms of each barrier instruction.
+  // The mcr forms are supported on armv5 and newer architectures
+  //
+  // The dmb, dsb instructions were added in armv7
+  // architectures and are compatible with their mcr
+  // predecessors.
+  //
+  // Here are the encodings for future reference:
+  //
+  // DataSynchronizationBarrier (dsb)
+  // on ARMv7 - emit_int32(0xF57FF04F)
+  //
+  // on ARMv5+ - mcr p15, 0, Rtmp, c7, c10, 4  on earlier processors
+  //             emit_int32(0xe << 28 | 0xe << 24 | 0x7 << 16 | Rtmp->encoding() << 12  |
+  //                       0xf << 8  | 0x9 << 4  | 0xa);
+  //
+  // DataMemoryBarrier (dmb)
+  // on ARMv7 - emit_int32(0xF57FF05F)
+  //
+  // on ARMv5+ - mcr p15, 0, Rtmp, c7, c10, 5 on earlier processors
+  //             emit_int32(0xe << 28 | 0xe << 24 | 0x7 << 16 | Rtmp->encoding() << 12  |
+  //                       0xf << 8  | 0xb << 4  | 0xa);
+  //
+
+  enum DMB_Opt {
+    DMB_all = 0xf,
+    DMB_st  = 0xe,
+  };
+
+  void dmb(DMB_Opt opt, Register reg) {
+    if (VM_Version::arm_arch() >= 7) {
+      emit_int32(0xF57FF050 | opt);
+    } else {
+      bool preserve_tmp = (reg == noreg);
+      if(preserve_tmp) {
+        reg = Rtemp;
+        str(reg, Address(SP, -wordSize, pre_indexed));
+      }
+      mov(reg, 0);
+      // DataMemoryBarrier
+      emit_int32(0xe << 28 |
+                0xe << 24 |
+                0x7 << 16 |
+                reg->encoding() << 12  |
+                0xf << 8  |
+                0xb << 4  |
+                0xa);
+      if(preserve_tmp) {
+        ldr(reg, Address(SP, wordSize, post_indexed));
+      }
+    }
+  }
+
+  void dsb(Register reg) {
+    if (VM_Version::arm_arch() >= 7) {
+      emit_int32(0xF57FF04F);
+    } else {
+      bool preserve_tmp = (reg == noreg);
+      if(preserve_tmp) {
+        reg = Rtemp;
+        str(reg, Address(SP, -wordSize, pre_indexed));
+      }
+      mov(reg, 0);
+      // DataSynchronizationBarrier
+      emit_int32(0xe << 28 |
+                0xe << 24 |
+                0x7 << 16 |
+                reg->encoding() << 12  |
+                0xf << 8  |
+                0x9 << 4  |
+                0xa);
+      if(preserve_tmp) {
+        ldr(reg, Address(SP, wordSize, post_indexed));
+      }
+    }
+  }
+
+
+#define F(mnemonic, b) \
+  void mnemonic(Register rd, Register rm, Register rn, AsmCondition cond = al) { \
+    assert(rn != rm && rn != rd, "unpredictable instruction");                   \
+    emit_int32(cond << 28 | 0x2 << 23 | b << 22 | rn->encoding() << 16 |         \
+              rd->encoding() << 12 | 9 << 4 | rm->encoding());                   \
+  }
+
+  F(swp,  0)
+  F(swpb, 1)
+#undef F
+
+  // Branches
+
+#define F(mnemonic, l) \
+  void mnemonic(Register rm, AsmCondition cond = al) {            \
+    emit_int32(cond << 28 | 0x012fff10 | l << 5 | rm->encoding()); \
+  }
+
+  F(bx,  0)
+  F(blx, 1)
+#undef F
+
+#define F(mnemonic, l)                                                  \
+  void mnemonic(address target, AsmCondition cond = al) {               \
+    unsigned int offset = (unsigned int)(target - pc() - 8);            \
+    assert((offset & 3) == 0, "bad alignment");                         \
+    assert((offset >> 25) == 0 || ((int)offset >> 25) == -1, "offset is too large"); \
+    emit_int32(cond << 28 | l << 24 | offset << 6 >> 8);                \
+  }
+
+  F(b,  0xa)
+  F(bl, 0xb)
+#undef F
+
+  // ARMv7 instructions
+
+#define F(mnemonic, wt) \
+  void mnemonic(Register rd, int imm_16, AsmCondition cond = al) { \
+    assert((imm_16 >> 16) == 0, "encoding constraint");            \
+    emit_int32(cond << 28 | wt << 20 | rd->encoding() << 12 |      \
+              (imm_16 & 0xf000) << 4 | (imm_16 & 0xfff));          \
+  }
+
+  F(movw, 0x30)
+  F(movt, 0x34)
+#undef F
+
+  // VFP Support
+
+// Checks that VFP instructions are not used in SOFTFP mode.
+#ifdef __SOFTFP__
+#define CHECK_VFP_PRESENT ShouldNotReachHere()
+#else
+#define CHECK_VFP_PRESENT
+#endif // __SOFTFP__
+
+  static const int single_cp_num = 0xa00;
+  static const int double_cp_num = 0xb00;
+
+  // Bits P, Q, R, S collectively form the opcode
+#define F(mnemonic, P, Q, R, S) \
+  void mnemonic##d(FloatRegister fd, FloatRegister fn, FloatRegister fm, \
+                   AsmCondition cond = al) {                             \
+    CHECK_VFP_PRESENT;                                                   \
+    assert(fn->lo_bit() == 0 && fd->lo_bit() == 0 && fm->lo_bit() == 0, "single precision register?"); \
+    emit_int32(cond << 28 | 0x7 << 25 | double_cp_num |                  \
+              P << 23 | Q << 21 | R << 20 | S << 6 |                     \
+              fn->hi_bits() << 16 | fn->hi_bit() << 7 |                  \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                 \
+              fm->hi_bits()       | fm->hi_bit() << 5);                  \
+  }                                                                      \
+  void mnemonic##s(FloatRegister fd, FloatRegister fn, FloatRegister fm, \
+                   AsmCondition cond = al) {                             \
+    assert(fn->hi_bit() == 0 && fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
+    CHECK_VFP_PRESENT;                                                   \
+    emit_int32(cond << 28 | 0x7 << 25 | single_cp_num |                  \
+              P << 23 | Q << 21 | R << 20 | S << 6 |                     \
+              fn->hi_bits() << 16 | fn->lo_bit() << 7 |                  \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                 \
+              fm->hi_bits()       | fm->lo_bit() << 5);                  \
+  }
+
+  F(fmac,  0, 0, 0, 0)  // Fd = Fd + (Fn * Fm)
+  F(fnmac, 0, 0, 0, 1)  // Fd = Fd - (Fn * Fm)
+  F(fmsc,  0, 0, 1, 0)  // Fd = -Fd + (Fn * Fm)
+  F(fnmsc, 0, 0, 1, 1)  // Fd = -Fd - (Fn * Fm)
+
+  F(fmul,  0, 1, 0, 0)  // Fd = Fn * Fm
+  F(fnmul, 0, 1, 0, 1)  // Fd = -(Fn * Fm)
+  F(fadd,  0, 1, 1, 0)  // Fd = Fn + Fm
+  F(fsub,  0, 1, 1, 1)  // Fd = Fn - Fm
+  F(fdiv,  1, 0, 0, 0)  // Fd = Fn / Fm
+#undef F
+
+  enum VElem_Size {
+    VELEM_SIZE_8  = 0x00,
+    VELEM_SIZE_16 = 0x01,
+    VELEM_SIZE_32 = 0x02,
+    VELEM_SIZE_64 = 0x03
+  };
+
+  enum VLD_Type {
+    VLD1_TYPE_1_REG  = 0x7 /* 0b0111 */,
+    VLD1_TYPE_2_REGS = 0xA /* 0b1010 */,
+    VLD1_TYPE_3_REGS = 0x6 /* 0b0110 */,
+    VLD1_TYPE_4_REGS = 0x2 /* 0b0010 */
+  };
+
+  enum VFloat_Arith_Size {
+    VFA_SIZE_F32 = 0x0 /* 0b0 */,
+  };
+
+  // Bits P, Q, R, S collectively form the opcode
+#define F(mnemonic, P, Q, R, S) \
+  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
+                int size, int quad) {                                    \
+    CHECK_VFP_PRESENT;                                                   \
+    assert(VM_Version::has_simd(), "simd instruction");                  \
+    assert(fn->lo_bit() == 0 && fd->lo_bit() == 0 && fm->lo_bit() == 0,  \
+           "single precision register?");                                \
+    assert(!quad || ((fn->hi_bits() | fd->hi_bits() | fm->hi_bits()) & 1) == 0, \
+           "quad precision register?");                                  \
+    emit_int32(0xf << 28 | P << 23 | Q << 8 | R << 4 |                   \
+              S << 21 | size << 20 | quad << 6 |                         \
+              fn->hi_bits() << 16 | fn->hi_bit() << 7 |                  \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                 \
+              fm->hi_bits()       | fm->hi_bit() << 5);                  \
+  }
+
+  F(vmulI,  0x4 /* 0b0100 */, 0x9 /* 0b1001 */, 1, 0)  // Vd = Vn * Vm (int)
+  F(vaddI,  0x4 /* 0b0100 */, 0x8 /* 0b1000 */, 0, 0)  // Vd = Vn + Vm (int)
+  F(vsubI,  0x6 /* 0b0110 */, 0x8 /* 0b1000 */, 0, 0)  // Vd = Vn - Vm (int)
+  F(vaddF,  0x4 /* 0b0100 */, 0xD /* 0b1101 */, 0, 0)  // Vd = Vn + Vm (float)
+  F(vsubF,  0x4 /* 0b0100 */, 0xD /* 0b1101 */, 0, 1)  // Vd = Vn - Vm (float)
+  F(vmulF,  0x6 /* 0b0110 */, 0xD /* 0b1101 */, 1, 0)  // Vd = Vn * Vm (float)
+  F(vshlSI, 0x4 /* 0b0100 */, 0x4 /* 0b0100 */, 0, 0)  // Vd = ashift(Vm,Vn) (int)
+  F(vshlUI, 0x6 /* 0b0110 */, 0x4 /* 0b0100 */, 0, 0)  // Vd = lshift(Vm,Vn) (int)
+  F(_vandI, 0x4 /* 0b0100 */, 0x1 /* 0b0001 */, 1, 0)  // Vd = Vn & Vm (int)
+  F(_vorI,  0x4 /* 0b0100 */, 0x1 /* 0b0001 */, 1, 1)  // Vd = Vn | Vm (int)
+  F(_vxorI, 0x6 /* 0b0110 */, 0x1 /* 0b0001 */, 1, 0)  // Vd = Vn ^ Vm (int)
+#undef F
+
+  void vandI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
+    _vandI(fd, fn, fm, 0, quad);
+  }
+  void vorI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
+    _vorI(fd, fn, fm, 0, quad);
+  }
+  void vxorI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
+    _vxorI(fd, fn, fm, 0, quad);
+  }
+
+  void vneg(FloatRegister fd, FloatRegister fm, int size, int flt, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
+           "single precision register?");
+    assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
+           "quad precision register?");
+    emit_int32(0xf << 28 | 0x3B /* 0b00111011 */ << 20 | 0x1 /* 0b01 */ << 16 | 0x7 /* 0b111 */ << 7 |
+               size << 18 | quad << 6 | flt << 10 |
+               fd->hi_bits() << 12 | fd->hi_bit() << 22 |
+               fm->hi_bits() <<  0 | fm->hi_bit() << 5);
+  }
+
+  void vnegI(FloatRegister fd, FloatRegister fm, int size, int quad) {
+    int flt = 0;
+    vneg(fd, fm, size, flt, quad);
+  }
+
+  void vshli(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
+           "single precision register?");
+    assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
+           "quad precision register?");
+
+    if (imm >= size) {
+      // maximum shift gives all zeroes, direction doesn't matter,
+      // but only available for shift right
+      vshri(fd, fm, size, size, true /* unsigned */, quad);
+      return;
+    }
+    assert(imm >= 0 && imm < size, "out of range");
+
+    int imm6 = 0;
+    int L = 0;
+    switch (size) {
+    case 8:
+    case 16:
+    case 32:
+      imm6 = size + imm ;
+      break;
+    case 64:
+      L = 1;
+      imm6 = imm ;
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+    emit_int32(0xf << 28 | 0x5 /* 0b00101 */ << 23 | 0x51 /* 0b01010001 */ << 4 |
+               imm6 << 16 | L << 7 | quad << 6 |
+               fd->hi_bits() << 12 | fd->hi_bit() << 22 |
+               fm->hi_bits() <<  0 | fm->hi_bit() << 5);
+  }
+
+  void vshri(FloatRegister fd, FloatRegister fm, int size, int imm,
+             bool U /* unsigned */, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
+           "single precision register?");
+    assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
+           "quad precision register?");
+    assert(imm > 0, "out of range");
+    if (imm >= size) {
+      // maximum shift (all zeroes)
+      imm = size;
+    }
+    int imm6 = 0;
+    int L = 0;
+    switch (size) {
+    case 8:
+    case 16:
+    case 32:
+      imm6 = 2 * size - imm ;
+      break;
+    case 64:
+      L = 1;
+      imm6 = 64 - imm ;
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+    emit_int32(0xf << 28 | 0x5 /* 0b00101 */ << 23 | 0x1 /* 0b00000001 */ << 4 |
+               imm6 << 16 | L << 7 | quad << 6 | U << 24 |
+               fd->hi_bits() << 12 | fd->hi_bit() << 22 |
+               fm->hi_bits() <<  0 | fm->hi_bit() << 5);
+  }
+  void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
+    vshri(fd, fm, size, imm, true /* unsigned */, quad);
+  }
+  void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
+    vshri(fd, fm, size, imm, false /* signed */, quad);
+  }
+
+  // Extension opcodes where P,Q,R,S = 1 opcode is in Fn
+#define F(mnemonic, N, opcode) \
+  void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->lo_bit() == 0 && fm->hi_bit() == 0, "incorrect register?");        \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              double_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                          \
+              fm->hi_bits()       | fm->lo_bit() << 5);                           \
+  }                                                                               \
+  void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              single_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                          \
+              fm->hi_bits()       | fm->lo_bit() << 5);                           \
+  }
+
+  F(fuito,  0, 0x8)  // Unsigned integer to floating point conversion
+  F(fsito,  1, 0x8)  // Signed integer to floating point conversion
+#undef F
+
+#define F(mnemonic, N, opcode) \
+  void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->hi_bit() == 0 && fm->lo_bit() == 0, "incorrect register?");        \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              double_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                          \
+              fm->hi_bits()       | fm->hi_bit() << 5);                           \
+  }                                                                               \
+  void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              single_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                          \
+              fm->hi_bits()       | fm->lo_bit() << 5);                           \
+  }
+
+  F(ftoui,  0, 0xc)  // Float to unsigned int conversion
+  F(ftouiz, 1, 0xc)  // Float to unsigned int conversion, RZ mode
+  F(ftosi,  0, 0xd)  // Float to signed int conversion
+  F(ftosiz, 1, 0xd)  // Float to signed int conversion, RZ mode
+#undef F
+
+#define F(mnemonic, N, opcode) \
+  void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->hi_bit() == 0 && fm->lo_bit() == 0, "incorrect register?");        \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              double_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                          \
+              fm->hi_bits()       | fm->hi_bit() << 5);                           \
+  }                                                                               \
+  void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->lo_bit() == 0 && fm->hi_bit() == 0, "incorrect register?");        \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              single_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                          \
+              fm->hi_bits()       | fm->lo_bit() << 5);                           \
+  }
+
+  F(fcvtd,  1, 0x7)  // Single->Double conversion
+  F(fcvts,  1, 0x7)  // Double->Single conversion
+#undef F
+
+#define F(mnemonic, N, opcode) \
+  void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->lo_bit() == 0 && fm->lo_bit() == 0, "single precision register?"); \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              double_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                          \
+              fm->hi_bits()       | fm->hi_bit() << 5);                           \
+  }                                                                               \
+  void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                            \
+    assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |         \
+              single_cp_num |                                                     \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                          \
+              fm->hi_bits()       | fm->lo_bit() << 5);                           \
+  }
+
+  F(fcpy,   0, 0x0)  // Fd = Fm
+  F(fabs,   1, 0x0)  // Fd = abs(Fm)
+  F(fneg,   0, 0x1)  // Fd = -Fm
+  F(fsqrt,  1, 0x1)  // Fd = sqrt(Fm)
+  F(fcmp,   0, 0x4)  // Compare Fd with Fm no exceptions on quiet NANs
+  F(fcmpe,  1, 0x4)  // Compare Fd with Fm with exceptions on quiet NANs
+#undef F
+
+  // Opcodes with one operand only
+#define F(mnemonic, N, opcode) \
+  void mnemonic##d(FloatRegister fd, AsmCondition cond = al) {               \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(fd->lo_bit() == 0, "single precision register?");                 \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |    \
+              double_cp_num | fd->hi_bits() << 12 | fd->hi_bit() << 22);     \
+  }                                                                          \
+  void mnemonic##s(FloatRegister fd, AsmCondition cond = al) {               \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(fd->hi_bit() == 0, "double precision register?");                 \
+    emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 |    \
+              single_cp_num | fd->hi_bits() << 12 | fd->lo_bit() << 22);     \
+  }
+
+  F(fcmpz,  0, 0x5)  // Compare Fd with 0, no exceptions quiet NANs
+  F(fcmpez, 1, 0x5)  // Compare Fd with 0, with exceptions quiet NANs
+#undef F
+
+  // Float loads (L==1) and stores (L==0)
+#define F(mnemonic, L) \
+  void mnemonic##d(FloatRegister fd, Address addr, AsmCondition cond = al) { \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(fd->lo_bit() == 0, "single precision register?");                 \
+    emit_int32(cond << 28 | 0xd << 24 | L << 20 |                            \
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 |                     \
+              double_cp_num | addr.encoding_vfp());                          \
+  }                                                                          \
+  void mnemonic##s(FloatRegister fd, Address addr, AsmCondition cond = al) { \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(fd->hi_bit() == 0, "double precision register?");                 \
+    emit_int32(cond << 28 | 0xd << 24 | L << 20 |                            \
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 |                     \
+              single_cp_num | addr.encoding_vfp());                          \
+  }
+
+  F(fst, 0)  // Store 1 register
+  F(fld, 1)  // Load 1 register
+#undef F
+
+  // Float load and store multiple
+#define F(mnemonic, l, pu) \
+  void mnemonic##d(Register rn, FloatRegisterSet reg_set,                    \
+                   AsmWriteback w = no_writeback, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(w == no_writeback || rn != PC, "unpredictable instruction");      \
+    assert(!(w == no_writeback && pu == 2), "encoding constraint");          \
+    assert((reg_set.encoding_d() & 1) == 0, "encoding constraint");          \
+    emit_int32(cond << 28 | 6 << 25 | pu << 23 | w << 21 | l << 20 |         \
+              rn->encoding() << 16 | reg_set.encoding_d() | double_cp_num);  \
+  }                                                                          \
+  void mnemonic##s(Register rn, FloatRegisterSet reg_set,                    \
+                   AsmWriteback w = no_writeback, AsmCondition cond = al) {  \
+    CHECK_VFP_PRESENT;                                                       \
+    assert(w == no_writeback || rn != PC, "unpredictable instruction");      \
+    assert(!(w == no_writeback && pu == 2), "encoding constraint");          \
+    emit_int32(cond << 28 | 6 << 25 | pu << 23 | w << 21 | l << 20 |         \
+              rn->encoding() << 16 | reg_set.encoding_s() | single_cp_num);  \
+  }
+
+  F(fldmia, 1, 1)    F(fldmfd, 1, 1)
+  F(fldmdb, 1, 2)    F(fldmea, 1, 2)
+  F(fstmia, 0, 1)    F(fstmfd, 0, 1)
+  F(fstmdb, 0, 2)    F(fstmea, 0, 2)
+#undef F
+
+  // fconst{s,d} encoding:
+  //  31  28 27   23 22  21 20 19   16 15 12 10  9  8   7    4 3     0
+  // | cond | 11101 | D | 11  | imm4H | Vd  | 101 | sz | 0000 | imm4L |
+  // sz = 0 for single precision, 1 otherwise
+  // Register number is Vd:D for single precision, D:Vd otherwise
+  // immediate value is imm4H:imm4L
+
+  void fconsts(FloatRegister fd, unsigned char imm_8, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->hi_bit() == 0, "double precision register?");
+    emit_int32(cond << 28 | 0xeb << 20 | single_cp_num |
+              fd->hi_bits() << 12 | fd->lo_bit() << 22 | (imm_8 & 0xf) | (imm_8 >> 4) << 16);
+  }
+
+  void fconstd(FloatRegister fd, unsigned char imm_8, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->lo_bit() == 0, "double precision register?");
+    emit_int32(cond << 28 | 0xeb << 20 | double_cp_num |
+              fd->hi_bits() << 12 | fd->hi_bit() << 22 | (imm_8 & 0xf) | (imm_8 >> 4) << 16);
+  }
+
+  // GPR <-> FPR transfers
+  void fmsr(FloatRegister fd, Register rd, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->hi_bit() == 0, "double precision register?");
+    emit_int32(cond << 28 | 0xe0 << 20 | single_cp_num | 1 << 4 |
+              fd->hi_bits() << 16 | fd->lo_bit() << 7 | rd->encoding() << 12);
+  }
+
+  void fmrs(Register rd, FloatRegister fd, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->hi_bit() == 0, "double precision register?");
+    emit_int32(cond << 28 | 0xe1 << 20 | single_cp_num | 1 << 4 |
+              fd->hi_bits() << 16 | fd->lo_bit() << 7 | rd->encoding() << 12);
+  }
+
+  void fmdrr(FloatRegister fd, Register rd, Register rn, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->lo_bit() == 0, "single precision register?");
+    emit_int32(cond << 28 | 0xc4 << 20 | double_cp_num | 1 << 4 |
+              fd->hi_bits() | fd->hi_bit() << 5 |
+              rn->encoding() << 16 | rd->encoding() << 12);
+  }
+
+  void fmrrd(Register rd, Register rn, FloatRegister fd, AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(fd->lo_bit() == 0, "single precision register?");
+    emit_int32(cond << 28 | 0xc5 << 20 | double_cp_num | 1 << 4 |
+              fd->hi_bits() | fd->hi_bit() << 5 |
+              rn->encoding() << 16 | rd->encoding() << 12);
+  }
+
+  void fmstat(AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    emit_int32(cond << 28 | 0xef1fa10);
+  }
+
+  void vmrs(Register rt, VFPSystemRegister sr, AsmCondition cond = al) {
+    assert((sr->encoding() & (~0xf)) == 0, "what system register is that?");
+    emit_int32(cond << 28 | rt->encoding() << 12 | sr->encoding() << 16 | 0xef00a10);
+  }
+
+  void vmsr(VFPSystemRegister sr, Register rt, AsmCondition cond = al) {
+    assert((sr->encoding() & (~0xf)) == 0, "what system register is that?");
+    emit_int32(cond << 28 | rt->encoding() << 12 | sr->encoding() << 16 | 0xee00a10);
+  }
+
+  void vcnt(FloatRegister Dd, FloatRegister Dm) {
+    CHECK_VFP_PRESENT;
+    // emitted at VM startup to detect whether the instruction is available
+    assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0 && Dm->lo_bit() == 0, "single precision registers?");
+    emit_int32(0xf3b00500 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | Dm->hi_bit() << 5 | Dm->hi_bits());
+  }
+
+  void vpaddl(FloatRegister Dd, FloatRegister Dm, int size, bool s) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0 && Dm->lo_bit() == 0, "single precision registers?");
+    assert(size == 8 || size == 16 || size == 32, "unexpected size");
+    emit_int32(0xf3b00200 | Dd->hi_bit() << 22 | (size >> 4) << 18 | Dd->hi_bits() << 12 | (s ? 0 : 1) << 7 | Dm->hi_bit() << 5 | Dm->hi_bits());
+  }
+
+  void vld1(FloatRegister Dd, Address addr, VElem_Size size, int bits) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision registers?");
+    int align = 0;
+    assert(bits == 128, "code assumption");
+    VLD_Type type = VLD1_TYPE_2_REGS; // 2x64
+    emit_int32(0xf4200000 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | type << 8 | size << 6 | align << 4 | addr.encoding_simd());
+  }
+
+  void vst1(FloatRegister Dd, Address addr, VElem_Size size, int bits) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision registers?");
+    int align = 0;
+    assert(bits == 128, "code assumption");
+    VLD_Type type = VLD1_TYPE_2_REGS; // 2x64
+    emit_int32(0xf4000000 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | type << 8 | size << 6 | align << 4 | addr.encoding_simd());
+  }
+
+  void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision register?");
+    assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
+    assert(imm8 >= 0 && imm8 < 256, "out of range");
+    int op;
+    int cmode;
+    switch (size) {
+    case VELEM_SIZE_8:
+      op = 0;
+      cmode = 0xE /* 0b1110 */;
+      break;
+    case VELEM_SIZE_16:
+      op = 0;
+      cmode = 0x8 /* 0b1000 */;
+      break;
+    case VELEM_SIZE_32:
+      op = 0;
+      cmode = 0x0 /* 0b0000 */;
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+    emit_int32(0xf << 28 | 0x1 << 25 | 0x1 << 23 | 0x1 << 4 |
+              (imm8 >> 7) << 24 | ((imm8 & 0x70) >> 4) << 16 | (imm8 & 0xf) |
+              quad << 6 | op << 5 | cmode << 8 |
+              Dd->hi_bits() << 12 | Dd->hi_bit() << 22);
+  }
+
+  void vdupI(FloatRegister Dd, Register Rs, VElem_Size size, int quad,
+             AsmCondition cond = al) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision register?");
+    assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
+    int b;
+    int e;
+    switch (size) {
+    case VELEM_SIZE_8:
+      b = 1;
+      e = 0;
+      break;
+    case VELEM_SIZE_16:
+      b = 0;
+      e = 1;
+      break;
+    case VELEM_SIZE_32:
+      b = 0;
+      e = 0;
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+    emit_int32(cond << 28 | 0x1D /* 0b11101 */ << 23 | 0xB /* 0b1011 */ << 8 | 0x1 << 4 |
+              quad << 21 | b << 22 |  e << 5 | Rs->encoding() << 12 |
+              Dd->hi_bits() << 16 | Dd->hi_bit() << 7);
+  }
+
+  void vdup(FloatRegister Dd, FloatRegister Ds, int index, int size, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision register?");
+    assert(Ds->lo_bit() == 0, "single precision register?");
+    assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
+    int range = 64 / size;
+    assert(index < range, "overflow");
+    int imm4;
+    switch (size) {
+    case 8:
+      assert((index & 0x7 /* 0b111 */) == index, "overflow");
+      imm4 = index << 1 | 0x1 /* 0b0001 */;
+      break;
+    case 16:
+      assert((index & 0x3 /* 0b11 */) == index, "overflow");
+      imm4 = index << 2 | 0x2 /* 0b0010 */;
+      break;
+    case 32:
+      assert((index & 0x1 /* 0b1 */) == index, "overflow");
+      imm4 = index << 3 | 0x4 /* 0b0100 */;
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+    emit_int32(0xF /* 0b1111 */ << 28 | 0x3B /* 0b00111011 */ << 20 | 0x6 /* 0b110 */ << 9 |
+               quad << 6 | imm4 << 16 |
+               Dd->hi_bits() << 12 | Dd->hi_bit() << 22 |
+               Ds->hi_bits() << 00 | Ds->hi_bit() << 5);
+  }
+
+  void vdupF(FloatRegister Dd, FloatRegister Ss, int quad) {
+    int index = 0;
+    FloatRegister Ds = as_FloatRegister(Ss->encoding() & ~1);
+    if (Ss->lo_bit() != 0) {
+      /* odd S register */
+      assert(Ds->successor() == Ss, "bad reg");
+      index = 1;
+    } else {
+      /* even S register */
+      assert(Ds == Ss, "bad reg");
+    }
+    vdup(Dd, Ds, index, 32, quad);
+  }
+
+  void vrev(FloatRegister Dd, FloatRegister Dm, int quad, int region_size, VElem_Size size) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision register?");
+    assert(Dm->lo_bit() == 0, "single precision register?");
+    assert(!quad || ((Dd->hi_bits() | Dm->hi_bits()) & 1) == 0,
+           "quad precision register?");
+    unsigned int op = 0;
+    switch (region_size) {
+      case 16: op = 0x2; /*0b10*/ break;
+      case 32: op = 0x1; /*0b01*/ break;
+      case 64: op = 0x0; /*0b00*/ break;
+      default: assert(false, "encoding constraint");
+    }
+    emit_int32(0xf << 28 | 0x7 << 23 | Dd->hi_bit() << 22 | 0x3 << 20 |
+               size << 18 | Dd->hi_bits() << 12 | op  << 7 | quad << 6 | Dm->hi_bit() << 5 |
+               Dm->hi_bits());
+  }
+
+  void veor(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, int quad) {
+    CHECK_VFP_PRESENT;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Dd->lo_bit() == 0, "single precision register?");
+    assert(Dm->lo_bit() == 0, "single precision register?");
+    assert(Dn->lo_bit() == 0, "single precision register?");
+    assert(!quad || ((Dd->hi_bits() | Dm->hi_bits() | Dn->hi_bits()) & 1) == 0,
+           "quad precision register?");
+
+    emit_int32(0xf << 28 | 0x3 << 24 | Dd->hi_bit() << 22 | Dn->hi_bits() << 16 |
+               Dd->hi_bits() << 12 | 0x1 << 8 | Dn->hi_bit() << 7 | quad << 6 |
+               Dm->hi_bit() << 5 | 0x1 << 4 | Dm->hi_bits());
+  }
+
+
+  Assembler(CodeBuffer* code) : AbstractAssembler(code) {}
+
+#ifdef COMPILER2
+  typedef VFP::double_num double_num;
+  typedef VFP::float_num  float_num;
+#endif
+};
+
+#ifdef __SOFTFP__
+// Soft float function declarations
+extern "C" {
+extern float  __aeabi_fadd(float, float);
+extern float  __aeabi_fmul(float, float);
+extern float  __aeabi_fsub(float, float);
+extern float  __aeabi_fdiv(float, float);
+
+extern double __aeabi_dadd(double, double);
+extern double __aeabi_dmul(double, double);
+extern double __aeabi_dsub(double, double);
+extern double __aeabi_ddiv(double, double);
+
+extern double __aeabi_f2d(float);
+extern float  __aeabi_d2f(double);
+extern float  __aeabi_i2f(int);
+extern double __aeabi_i2d(int);
+extern int    __aeabi_f2iz(float);
+
+extern int  __aeabi_fcmpeq(float, float);
+extern int  __aeabi_fcmplt(float, float);
+extern int  __aeabi_fcmple(float, float);
+extern int  __aeabi_fcmpge(float, float);
+extern int  __aeabi_fcmpgt(float, float);
+
+extern int  __aeabi_dcmpeq(double, double);
+extern int  __aeabi_dcmplt(double, double);
+extern int  __aeabi_dcmple(double, double);
+extern int  __aeabi_dcmpge(double, double);
+extern int  __aeabi_dcmpgt(double, double);
+
+// Imported code from glibc soft-fp bundle for
+// calculation accuracy improvement. See CR 6757269.
+extern double __aeabi_fadd_glibc(float, float);
+extern double __aeabi_fsub_glibc(float, float);
+extern double __aeabi_dadd_glibc(double, double);
+extern double __aeabi_dsub_glibc(double, double);
+};
+#endif // __SOFTFP__
+
+
+#endif // CPU_ARM_VM_ASSEMBLER_ARM_32_HPP
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm_64.cpp b/hotspot/src/cpu/arm/vm/assembler_arm_64.cpp
new file mode 100644
index 0000000..ae8ba66
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm_64.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
+#include "ci/ciEnv.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateInterpreterGenerator.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvm_misc.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/hashtable.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/heapRegion.hpp"
+#endif // INCLUDE_ALL_GCS
+
+// Returns whether given imm has equal bit fields <0:size-1> and <size:2*size-1>.
+inline bool Assembler::LogicalImmediate::has_equal_subpatterns(uintx imm, int size) {
+  uintx mask = right_n_bits(size);
+  uintx subpattern1 = mask_bits(imm, mask);
+  uintx subpattern2 = mask_bits(imm >> size, mask);
+  return subpattern1 == subpattern2;
+}
+
+// Returns least size that is a power of two from 2 to 64 with the proviso that given
+// imm is composed of repeating patterns of this size.
+inline int Assembler::LogicalImmediate::least_pattern_size(uintx imm) {
+  int size = BitsPerWord;
+  while (size > 2 && has_equal_subpatterns(imm, size >> 1)) {
+    size >>= 1;
+  }
+  return size;
+}
+
+// Returns count of set bits in given imm. Based on variable-precision SWAR algorithm.
+inline int Assembler::LogicalImmediate::population_count(uintx x) {
+  x -= ((x >> 1) & 0x5555555555555555L);
+  x = (((x >> 2) & 0x3333333333333333L) + (x & 0x3333333333333333L));
+  x = (((x >> 4) + x) & 0x0f0f0f0f0f0f0f0fL);
+  x += (x >> 8);
+  x += (x >> 16);
+  x += (x >> 32);
+  return(x & 0x7f);
+}
+
+// Let given x be <A:B> where B = 0 and least bit of A = 1. Returns <A:C>, where C is B-size set bits.
+inline uintx Assembler::LogicalImmediate::set_least_zeroes(uintx x) {
+  return x | (x - 1);
+}
+
+
+#ifdef ASSERT
+
+// Restores immediate by encoded bit masks.
+uintx Assembler::LogicalImmediate::decode() {
+  assert (_encoded, "should be");
+
+  int len_code = (_immN << 6) | ((~_imms) & 0x3f);
+  assert (len_code != 0, "should be");
+
+  int len = 6;
+  while (!is_set_nth_bit(len_code, len)) len--;
+  int esize = 1 << len;
+  assert (len > 0, "should be");
+  assert ((_is32bit ? 32 : 64) >= esize, "should be");
+
+  int levels = right_n_bits(len);
+  int S = _imms & levels;
+  int R = _immr & levels;
+
+  assert (S != levels, "should be");
+
+  uintx welem = right_n_bits(S + 1);
+  uintx wmask = (R == 0) ? welem : ((welem >> R) | (welem << (esize - R)));
+
+  for (int size = esize; size < 64; size <<= 1) {
+    wmask |= (wmask << size);
+  }
+
+  return wmask;
+}
+
+#endif
+
+
+// Constructs LogicalImmediate by given imm. Figures out if given imm can be used in AArch64 logical
+// instructions (AND, ANDS, EOR, ORR) and saves its encoding.
+void Assembler::LogicalImmediate::construct(uintx imm, bool is32) {
+  _is32bit = is32;
+
+  if (is32) {
+    assert(((imm >> 32) == 0) || (((intx)imm >> 31) == -1), "32-bit immediate is out of range");
+
+    // Replicate low 32 bits.
+    imm &= 0xffffffff;
+    imm |= imm << 32;
+  }
+
+  // All-zeroes and all-ones can not be encoded.
+  if (imm != 0 && (~imm != 0)) {
+
+    // Let LPS (least pattern size) be the least size (power of two from 2 to 64) of repeating
+    // patterns in the immediate. If immediate value can be encoded, it is encoded by pattern
+    // of exactly LPS size (due to structure of valid patterns). In order to verify
+    // that immediate value can be encoded, LPS is calculated and <LPS-1:0> bits of immediate
+    // are verified to be valid pattern.
+    int lps = least_pattern_size(imm);
+    uintx lps_mask = right_n_bits(lps);
+
+    // A valid pattern has one of the following forms:
+    //  | 0 x A | 1 x B | 0 x C |, where B > 0 and C > 0, or
+    //  | 1 x A | 0 x B | 1 x C |, where B > 0 and C > 0.
+    // For simplicity, the second form of the pattern is inverted into the first form.
+    bool inverted = imm & 0x1;
+    uintx pattern = (inverted ? ~imm : imm) & lps_mask;
+
+    //  | 0 x A | 1 x (B + C)   |
+    uintx without_least_zeroes = set_least_zeroes(pattern);
+
+    // Pattern is valid iff without least zeroes it is a power of two - 1.
+    if ((without_least_zeroes & (without_least_zeroes + 1)) == 0) {
+
+      // Count B as population count of pattern.
+      int bits_count = population_count(pattern);
+
+      // Count B+C as population count of pattern without least zeroes
+      int left_range = population_count(without_least_zeroes);
+
+      // S-prefix is a part of imms field which encodes LPS.
+      //  LPS  |  S prefix
+      //   64  |     not defined
+      //   32  |     0b0
+      //   16  |     0b10
+      //    8  |     0b110
+      //    4  |     0b1110
+      //    2  |     0b11110
+      int s_prefix = (lps == 64) ? 0 : ~set_least_zeroes(lps) & 0x3f;
+
+      // immN bit is set iff LPS == 64.
+      _immN = (lps == 64) ? 1 : 0;
+      assert (!is32 || (_immN == 0), "32-bit immediate should be encoded with zero N-bit");
+
+      // immr is the rotation size.
+      _immr = lps + (inverted ? 0 : bits_count) - left_range;
+
+      // imms is the field that encodes bits count and S-prefix.
+      _imms = ((inverted ? (lps - bits_count) : bits_count) - 1) | s_prefix;
+
+      _encoded = true;
+      assert (decode() == imm, "illegal encoding");
+
+      return;
+    }
+  }
+
+  _encoded = false;
+}
diff --git a/hotspot/src/cpu/arm/vm/assembler_arm_64.hpp b/hotspot/src/cpu/arm/vm/assembler_arm_64.hpp
new file mode 100644
index 0000000..44d0504
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/assembler_arm_64.hpp
@@ -0,0 +1,1717 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
+#define CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
+
+enum AsmShift12 {
+  lsl0, lsl12
+};
+
+enum AsmPrefetchOp {
+    pldl1keep = 0b00000,
+    pldl1strm,
+    pldl2keep,
+    pldl2strm,
+    pldl3keep,
+    pldl3strm,
+
+    plil1keep = 0b01000,
+    plil1strm,
+    plil2keep,
+    plil2strm,
+    plil3keep,
+    plil3strm,
+
+    pstl1keep = 0b10000,
+    pstl1strm,
+    pstl2keep,
+    pstl2strm,
+    pstl3keep,
+    pstl3strm,
+};
+
+// Shifted register operand for data processing instructions.
+class AsmOperand VALUE_OBJ_CLASS_SPEC {
+ private:
+  Register _reg;
+  AsmShift _shift;
+  int _shift_imm;
+
+ public:
+  AsmOperand(Register reg) {
+    assert(reg != SP, "SP is not allowed in shifted register operand");
+    _reg = reg;
+    _shift = lsl;
+    _shift_imm = 0;
+  }
+
+  AsmOperand(Register reg, AsmShift shift, int shift_imm) {
+    assert(reg != SP, "SP is not allowed in shifted register operand");
+    assert(shift_imm >= 0, "shift amount should be non-negative");
+    _reg = reg;
+    _shift = shift;
+    _shift_imm = shift_imm;
+  }
+
+  Register reg() const {
+    return _reg;
+  }
+
+  AsmShift shift() const {
+    return _shift;
+  }
+
+  int shift_imm() const {
+    return _shift_imm;
+  }
+};
+
+
+class Assembler : public AbstractAssembler  {
+
+ public:
+
+  static const int LogInstructionSize = 2;
+  static const int InstructionSize    = 1 << LogInstructionSize;
+
+  Assembler(CodeBuffer* code) : AbstractAssembler(code) {}
+
+  static inline AsmCondition inverse(AsmCondition cond) {
+    assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
+    return (AsmCondition)((int)cond ^ 1);
+  }
+
+  // Returns value of nzcv flags conforming to the given condition.
+  static inline int flags_for_condition(AsmCondition cond) {
+    switch(cond) {            // NZCV
+      case mi: case lt: return 0b1000;
+      case eq: case le: return 0b0100;
+      case hs: case hi: return 0b0010;
+      case vs:          return 0b0001;
+      default:          return 0b0000;
+    }
+  }
+
+  // Immediate, encoded into logical instructions.
+  class LogicalImmediate {
+   private:
+    bool _encoded;
+    bool _is32bit;
+    int _immN;
+    int _immr;
+    int _imms;
+
+    static inline bool has_equal_subpatterns(uintx imm, int size);
+    static inline int least_pattern_size(uintx imm);
+    static inline int population_count(uintx x);
+    static inline uintx set_least_zeroes(uintx x);
+
+#ifdef ASSERT
+    uintx decode();
+#endif
+
+    void construct(uintx imm, bool is32);
+
+   public:
+    LogicalImmediate(uintx imm, bool is32 = false) { construct(imm, is32); }
+
+    // Returns true if given immediate can be used in AArch64 logical instruction.
+    bool is_encoded() const { return _encoded; }
+
+    bool is32bit() const { return _is32bit; }
+    int immN() const { assert(_encoded, "should be"); return _immN; }
+    int immr() const { assert(_encoded, "should be"); return _immr; }
+    int imms() const { assert(_encoded, "should be"); return _imms; }
+  };
+
+  // Immediate, encoded into arithmetic add/sub instructions.
+  class ArithmeticImmediate {
+   private:
+    bool _encoded;
+    int _imm;
+    AsmShift12 _shift;
+
+   public:
+    ArithmeticImmediate(intx x) {
+      if (is_unsigned_imm_in_range(x, 12, 0)) {
+        _encoded = true;
+        _imm = x;
+        _shift = lsl0;
+      } else if (is_unsigned_imm_in_range(x, 12, 12)) {
+        _encoded = true;
+        _imm = x >> 12;
+        _shift = lsl12;
+      } else {
+        _encoded = false;
+      }
+    }
+
+    ArithmeticImmediate(intx x, AsmShift12 sh) {
+      if (is_unsigned_imm_in_range(x, 12, 0)) {
+        _encoded = true;
+        _imm = x;
+        _shift = sh;
+      } else {
+        _encoded = false;
+      }
+    }
+
+    // Returns true if this immediate can be used in AArch64 arithmetic (add/sub/cmp/cmn) instructions.
+    bool is_encoded() const  { return _encoded; }
+
+    int imm() const          { assert(_encoded, "should be"); return _imm; }
+    AsmShift12 shift() const { assert(_encoded, "should be"); return _shift; }
+  };
+
+  static inline bool is_imm_in_range(intx value, int bits, int align_bits) {
+    intx sign_bits = (value >> (bits + align_bits - 1));
+    return ((value & right_n_bits(align_bits)) == 0) && ((sign_bits == 0) || (sign_bits == -1));
+  }
+
+  static inline int encode_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) {
+    assert (is_imm_in_range(value, bits, align_bits), "immediate value is out of range");
+    return ((value >> align_bits) & right_n_bits(bits)) << low_bit_in_encoding;
+  }
+
+  static inline bool is_unsigned_imm_in_range(intx value, int bits, int align_bits) {
+    return (value >= 0) && ((value & right_n_bits(align_bits)) == 0) && ((value >> (align_bits + bits)) == 0);
+  }
+
+  static inline int encode_unsigned_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) {
+    assert (is_unsigned_imm_in_range(value, bits, align_bits), "immediate value is out of range");
+    return (value >> align_bits) << low_bit_in_encoding;
+  }
+
+  static inline bool is_offset_in_range(intx offset, int bits) {
+    assert (bits == 14 || bits == 19 || bits == 26, "wrong bits number");
+    return is_imm_in_range(offset, bits, 2);
+  }
+
+  static inline int encode_offset(intx offset, int bits, int low_bit_in_encoding) {
+    return encode_imm(offset, bits, 2, low_bit_in_encoding);
+  }
+
+  // Returns true if given value can be used as immediate in arithmetic (add/sub/cmp/cmn) instructions.
+  static inline bool is_arith_imm_in_range(intx value) {
+    return ArithmeticImmediate(value).is_encoded();
+  }
+
+
+  // Load/store instructions
+
+#define F(mnemonic, opc) \
+  void mnemonic(Register rd, address literal_addr) {                                                       \
+    intx offset = literal_addr - pc();                                                                     \
+    assert (opc != 0b01 || offset == 0 || ((uintx)literal_addr & 7) == 0, "ldr target should be aligned"); \
+    assert (is_offset_in_range(offset, 19), "offset is out of range");                                     \
+    emit_int32(opc << 30 | 0b011 << 27 | encode_offset(offset, 19, 5) | rd->encoding_with_zr());           \
+  }
+
+  F(ldr_w, 0b00)
+  F(ldr,   0b01)
+  F(ldrsw, 0b10)
+#undef F
+
+#define F(mnemonic, opc) \
+  void mnemonic(FloatRegister rt, address literal_addr) {                                                  \
+    intx offset = literal_addr - pc();                                                                     \
+    assert (offset == 0 || ((uintx)literal_addr & right_n_bits(2 + opc)) == 0, "ldr target should be aligned"); \
+    assert (is_offset_in_range(offset, 19), "offset is out of range");                                     \
+    emit_int32(opc << 30 | 0b011100 << 24 | encode_offset(offset, 19, 5) | rt->encoding());                \
+  }
+
+  F(ldr_s, 0b00)
+  F(ldr_d, 0b01)
+  F(ldr_q, 0b10)
+#undef F
+
+#define F(mnemonic, size, o2, L, o1, o0) \
+  void mnemonic(Register rt, Register rn) {                                                                \
+    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 |               \
+        o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());                  \
+  }
+
+  F(ldxrb,   0b00, 0, 1, 0, 0)
+  F(ldaxrb,  0b00, 0, 1, 0, 1)
+  F(ldarb,   0b00, 1, 1, 0, 1)
+  F(ldxrh,   0b01, 0, 1, 0, 0)
+  F(ldaxrh,  0b01, 0, 1, 0, 1)
+  F(ldarh,   0b01, 1, 1, 0, 1)
+  F(ldxr_w,  0b10, 0, 1, 0, 0)
+  F(ldaxr_w, 0b10, 0, 1, 0, 1)
+  F(ldar_w,  0b10, 1, 1, 0, 1)
+  F(ldxr,    0b11, 0, 1, 0, 0)
+  F(ldaxr,   0b11, 0, 1, 0, 1)
+  F(ldar,    0b11, 1, 1, 0, 1)
+
+  F(stlrb,   0b00, 1, 0, 0, 1)
+  F(stlrh,   0b01, 1, 0, 0, 1)
+  F(stlr_w,  0b10, 1, 0, 0, 1)
+  F(stlr,    0b11, 1, 0, 0, 1)
+#undef F
+
+#define F(mnemonic, size, o2, L, o1, o0) \
+  void mnemonic(Register rs, Register rt, Register rn) {                                                     \
+    assert (rs != rt, "should be different");                                                                \
+    assert (rs != rn, "should be different");                                                                \
+    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 |  \
+        o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());                    \
+  }
+
+  F(stxrb,   0b00, 0, 0, 0, 0)
+  F(stlxrb,  0b00, 0, 0, 0, 1)
+  F(stxrh,   0b01, 0, 0, 0, 0)
+  F(stlxrh,  0b01, 0, 0, 0, 1)
+  F(stxr_w,  0b10, 0, 0, 0, 0)
+  F(stlxr_w, 0b10, 0, 0, 0, 1)
+  F(stxr,    0b11, 0, 0, 0, 0)
+  F(stlxr,   0b11, 0, 0, 0, 1)
+#undef F
+
+#define F(mnemonic, size, o2, L, o1, o0) \
+  void mnemonic(Register rt, Register rt2, Register rn) {                                                  \
+    assert (rt != rt2, "should be different");                                                             \
+    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 |               \
+        o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());  \
+  }
+
+  F(ldxp_w,  0b10, 0, 1, 1, 0)
+  F(ldaxp_w, 0b10, 0, 1, 1, 1)
+  F(ldxp,    0b11, 0, 1, 1, 0)
+  F(ldaxp,   0b11, 0, 1, 1, 1)
+#undef F
+
+#define F(mnemonic, size, o2, L, o1, o0) \
+  void mnemonic(Register rs, Register rt, Register rt2, Register rn) {                                       \
+    assert (rs != rt, "should be different");                                                                \
+    assert (rs != rt2, "should be different");                                                               \
+    assert (rs != rn, "should be different");                                                                \
+    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 |  \
+        o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());    \
+  }
+
+  F(stxp_w,  0b10, 0, 0, 1, 0)
+  F(stlxp_w, 0b10, 0, 0, 1, 1)
+  F(stxp,    0b11, 0, 0, 1, 0)
+  F(stlxp,   0b11, 0, 0, 1, 1)
+#undef F
+
+#define F(mnemonic, opc, V, L) \
+  void mnemonic(Register rt, Register rt2, Register rn, int offset = 0) {                                  \
+    assert (!L || rt != rt2, "should be different");                                                       \
+    int align_bits = 2 + (opc >> 1);                                                                       \
+    assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range");                             \
+    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) |       \
+        rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());             \
+  }
+
+  F(stnp_w,  0b00, 0, 0)
+  F(ldnp_w,  0b00, 0, 1)
+  F(stnp,    0b10, 0, 0)
+  F(ldnp,    0b10, 0, 1)
+#undef F
+
+#define F(mnemonic, opc, V, L) \
+  void mnemonic(FloatRegister rt, FloatRegister rt2, Register rn, int offset = 0) {                        \
+    assert (!L || (rt != rt2), "should be different");                                                     \
+    int align_bits = 2 + opc;                                                                              \
+    assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range");                             \
+    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) |       \
+        rt2->encoding() << 10 | rn->encoding_with_sp() << 5 | rt->encoding());                             \
+  }
+
+  F(stnp_s,  0b00, 1, 0)
+  F(stnp_d,  0b01, 1, 0)
+  F(stnp_q,  0b10, 1, 0)
+  F(ldnp_s,  0b00, 1, 1)
+  F(ldnp_d,  0b01, 1, 1)
+  F(ldnp_q,  0b10, 1, 1)
+#undef F
+
+#define F(mnemonic, size, V, opc) \
+  void mnemonic(Register rt, Address addr) { \
+    assert((addr.mode() == basic_offset) || (rt != addr.base()), "should be different");                    \
+    if (addr.index() == noreg) {                                                                            \
+      if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, size)) {               \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
+           encode_unsigned_imm(addr.disp(), 12, size, 10) |                                                 \
+           addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                                  \
+      } else {                                                                                              \
+        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
+           addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());              \
+      }                                                                                                     \
+    } else {                                                                                                \
+      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
+      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount");               \
+      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
+         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
+         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                       \
+    }                                                                                                       \
+  }
+
+  F(strb,    0b00, 0, 0b00)
+  F(ldrb,    0b00, 0, 0b01)
+  F(ldrsb,   0b00, 0, 0b10)
+  F(ldrsb_w, 0b00, 0, 0b11)
+
+  F(strh,    0b01, 0, 0b00)
+  F(ldrh,    0b01, 0, 0b01)
+  F(ldrsh,   0b01, 0, 0b10)
+  F(ldrsh_w, 0b01, 0, 0b11)
+
+  F(str_w,   0b10, 0, 0b00)
+  F(ldr_w,   0b10, 0, 0b01)
+  F(ldrsw,   0b10, 0, 0b10)
+
+  F(str,     0b11, 0, 0b00)
+  F(ldr,     0b11, 0, 0b01)
+#undef F
+
+#define F(mnemonic, size, V, opc) \
+  void mnemonic(AsmPrefetchOp prfop, Address addr) { \
+    assert (addr.mode() == basic_offset, #mnemonic " supports only basic_offset address mode");             \
+    if (addr.index() == noreg) {                                                                            \
+      if (is_unsigned_imm_in_range(addr.disp(), 12, size)) {                                                \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
+           encode_unsigned_imm(addr.disp(), 12, size, 10) |                                                 \
+           addr.base()->encoding_with_sp() << 5 | prfop);                                                   \
+      } else {                                                                                              \
+        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
+           addr.base()->encoding_with_sp() << 5 | prfop);                                                   \
+      }                                                                                                     \
+    } else {                                                                                                \
+      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
+      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount");               \
+      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
+         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
+         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | prfop);                                        \
+    }                                                                                                       \
+  }
+
+  F(prfm, 0b11, 0, 0b10)
+#undef F
+
+#define F(mnemonic, size, V, opc) \
+  void mnemonic(FloatRegister rt, Address addr) { \
+    int align_bits = (((opc & 0b10) >> 1) << 2) | size;                                                     \
+    if (addr.index() == noreg) {                                                                            \
+      if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, align_bits)) {         \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
+           encode_unsigned_imm(addr.disp(), 12, align_bits, 10) |                                           \
+           addr.base()->encoding_with_sp() << 5 | rt->encoding());                                          \
+      } else {                                                                                              \
+        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
+        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
+           addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding());                      \
+      }                                                                                                     \
+    } else {                                                                                                \
+      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
+      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == align_bits), "invalid shift amount");         \
+      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
+         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
+         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding());                               \
+    }                                                                                                       \
+  }
+
+  F(str_b, 0b00, 1, 0b00)
+  F(ldr_b, 0b00, 1, 0b01)
+  F(str_h, 0b01, 1, 0b00)
+  F(ldr_h, 0b01, 1, 0b01)
+  F(str_s, 0b10, 1, 0b00)
+  F(ldr_s, 0b10, 1, 0b01)
+  F(str_d, 0b11, 1, 0b00)
+  F(ldr_d, 0b11, 1, 0b01)
+  F(str_q, 0b00, 1, 0b10)
+  F(ldr_q, 0b00, 1, 0b11)
+#undef F
+
+#define F(mnemonic, opc, V, L) \
+  void mnemonic(Register rt, Register rt2, Address addr) {                                                         \
+    assert((addr.mode() == basic_offset) || ((rt != addr.base()) && (rt2 != addr.base())), "should be different"); \
+    assert(!L || (rt != rt2), "should be different");                                                              \
+    assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair");                \
+    int align_bits = 2 + (opc >> 1);                                                                               \
+    int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode();                                        \
+    assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range");                                 \
+    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 |                                 \
+       encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding_with_zr() << 10 |                                \
+       addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                                             \
+  }
+
+  F(stp_w, 0b00, 0, 0)
+  F(ldp_w, 0b00, 0, 1)
+  F(ldpsw, 0b01, 0, 1)
+  F(stp,   0b10, 0, 0)
+  F(ldp,   0b10, 0, 1)
+#undef F
+
+#define F(mnemonic, opc, V, L) \
+  void mnemonic(FloatRegister rt, FloatRegister rt2, Address addr) {                                                         \
+    assert(!L || (rt != rt2), "should be different");                                                              \
+    assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair");                \
+    int align_bits = 2 + opc;                                                                                      \
+    int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode();                                        \
+    assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range");                                 \
+    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 |                                 \
+       encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding() << 10 |                                        \
+       addr.base()->encoding_with_sp() << 5 | rt->encoding());                                                     \
+  }
+
+  F(stp_s, 0b00, 1, 0)
+  F(ldp_s, 0b00, 1, 1)
+  F(stp_d, 0b01, 1, 0)
+  F(ldp_d, 0b01, 1, 1)
+  F(stp_q, 0b10, 1, 0)
+  F(ldp_q, 0b10, 1, 1)
+#undef F
+
+  // Data processing instructions
+
+#define F(mnemonic, sf, opc) \
+  void mnemonic(Register rd, Register rn, const LogicalImmediate& imm) {                      \
+    assert (imm.is_encoded(), "illegal immediate for logical instruction");                   \
+    assert (imm.is32bit() == (sf == 0), "immediate size does not match instruction size");    \
+    emit_int32(sf << 31 | opc << 29 | 0b100100 << 23 | imm.immN() << 22 | imm.immr() << 16 |  \
+        imm.imms() << 10 | rn->encoding_with_zr() << 5 |                                      \
+        ((opc == 0b11) ? rd->encoding_with_zr() : rd->encoding_with_sp()));                   \
+  }                                                                                           \
+  void mnemonic(Register rd, Register rn, uintx imm) {                                        \
+    LogicalImmediate limm(imm, (sf == 0));                                                    \
+    mnemonic(rd, rn, limm);                                                                   \
+  }                                                                                           \
+  void mnemonic(Register rd, Register rn, unsigned int imm) {                                 \
+    mnemonic(rd, rn, (uintx)imm);                                                             \
+  }
+
+  F(andr_w, 0, 0b00)
+  F(orr_w,  0, 0b01)
+  F(eor_w,  0, 0b10)
+  F(ands_w, 0, 0b11)
+
+  F(andr, 1, 0b00)
+  F(orr,  1, 0b01)
+  F(eor,  1, 0b10)
+  F(ands, 1, 0b11)
+#undef F
+
+  void tst(Register rn, unsigned int imm) {
+    ands(ZR, rn, imm);
+  }
+
+  void tst_w(Register rn, unsigned int imm) {
+    ands_w(ZR, rn, imm);
+  }
+
+#define F(mnemonic, sf, opc, N) \
+  void mnemonic(Register rd, Register rn, AsmOperand operand) { \
+    assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large");          \
+    emit_int32(sf << 31 | opc << 29 | 0b01010 << 24 | operand.shift() << 22 | N << 21 |  \
+        operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 |            \
+        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                           \
+  }
+
+  F(andr_w, 0, 0b00, 0)
+  F(bic_w,  0, 0b00, 1)
+  F(orr_w,  0, 0b01, 0)
+  F(orn_w,  0, 0b01, 1)
+  F(eor_w,  0, 0b10, 0)
+  F(eon_w,  0, 0b10, 1)
+  F(ands_w, 0, 0b11, 0)
+  F(bics_w, 0, 0b11, 1)
+
+  F(andr, 1, 0b00, 0)
+  F(bic,  1, 0b00, 1)
+  F(orr,  1, 0b01, 0)
+  F(orn,  1, 0b01, 1)
+  F(eor,  1, 0b10, 0)
+  F(eon,  1, 0b10, 1)
+  F(ands, 1, 0b11, 0)
+  F(bics, 1, 0b11, 1)
+#undef F
+
+  void tst(Register rn, AsmOperand operand) {
+    ands(ZR, rn, operand);
+  }
+
+  void tst_w(Register rn, AsmOperand operand) {
+    ands_w(ZR, rn, operand);
+  }
+
+  void mvn(Register rd, AsmOperand operand) {
+    orn(rd, ZR, operand);
+  }
+
+  void mvn_w(Register rd, AsmOperand operand) {
+    orn_w(rd, ZR, operand);
+  }
+
+#define F(mnemonic, sf, op, S) \
+  void mnemonic(Register rd, Register rn, const ArithmeticImmediate& imm) {                       \
+    assert(imm.is_encoded(), "immediate is out of range");                                        \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b10001 << 24 | imm.shift() << 22 |                \
+        imm.imm() << 10 | rn->encoding_with_sp() << 5 |                                           \
+        (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp()));                              \
+  }                                                                                               \
+  void mnemonic(Register rd, Register rn, int imm) {                                              \
+    mnemonic(rd, rn, ArithmeticImmediate(imm));                                                   \
+  }                                                                                               \
+  void mnemonic(Register rd, Register rn, int imm, AsmShift12 shift) {                            \
+    mnemonic(rd, rn, ArithmeticImmediate(imm, shift));                                            \
+  }                                                                                               \
+  void mnemonic(Register rd, Register rn, Register rm, AsmExtendOp extend, int shift_imm = 0) {   \
+    assert ((0 <= shift_imm) && (shift_imm <= 4), "shift amount is out of range");                \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011001 << 21 | rm->encoding_with_zr() << 16 |  \
+        extend << 13 | shift_imm << 10 | rn->encoding_with_sp() << 5 |                            \
+        (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp()));                              \
+  }                                                                                               \
+  void mnemonic(Register rd, Register rn, AsmOperand operand) {                                   \
+    assert (operand.shift() != ror, "illegal shift type");                                        \
+    assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large");                   \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011 << 24 | operand.shift() << 22 |            \
+        operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 |                     \
+        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                                    \
+  }
+
+  F(add_w,  0, 0, 0)
+  F(adds_w, 0, 0, 1)
+  F(sub_w,  0, 1, 0)
+  F(subs_w, 0, 1, 1)
+
+  F(add,    1, 0, 0)
+  F(adds,   1, 0, 1)
+  F(sub,    1, 1, 0)
+  F(subs,   1, 1, 1)
+#undef F
+
+  void mov(Register rd, Register rm) {
+    if ((rd == SP) || (rm == SP)) {
+      add(rd, rm, 0);
+    } else {
+      orr(rd, ZR, rm);
+    }
+  }
+
+  void mov_w(Register rd, Register rm) {
+    if ((rd == SP) || (rm == SP)) {
+      add_w(rd, rm, 0);
+    } else {
+      orr_w(rd, ZR, rm);
+    }
+  }
+
+  void cmp(Register rn, int imm) {
+    subs(ZR, rn, imm);
+  }
+
+  void cmp_w(Register rn, int imm) {
+    subs_w(ZR, rn, imm);
+  }
+
+  void cmp(Register rn, Register rm) {
+    assert (rm != SP, "SP should not be used as the 2nd operand of cmp");
+    if (rn == SP) {
+      subs(ZR, rn, rm, ex_uxtx);
+    } else {
+      subs(ZR, rn, rm);
+    }
+  }
+
+  void cmp_w(Register rn, Register rm) {
+    assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp");
+    subs_w(ZR, rn, rm);
+  }
+
+  void cmp(Register rn, AsmOperand operand) {
+    assert (rn != SP, "SP is not allowed in cmp with shifted register (AsmOperand)");
+    subs(ZR, rn, operand);
+  }
+
+  void cmn(Register rn, int imm) {
+    adds(ZR, rn, imm);
+  }
+
+  void cmn_w(Register rn, int imm) {
+    adds_w(ZR, rn, imm);
+  }
+
+  void cmn(Register rn, Register rm) {
+    assert (rm != SP, "SP should not be used as the 2nd operand of cmp");
+    if (rn == SP) {
+      adds(ZR, rn, rm, ex_uxtx);
+    } else {
+      adds(ZR, rn, rm);
+    }
+  }
+
+  void cmn_w(Register rn, Register rm) {
+    assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp");
+    adds_w(ZR, rn, rm);
+  }
+
+  void neg(Register rd, Register rm) {
+    sub(rd, ZR, rm);
+  }
+
+  void neg_w(Register rd, Register rm) {
+    sub_w(rd, ZR, rm);
+  }
+
+#define F(mnemonic, sf, op, S) \
+  void mnemonic(Register rd, Register rn, Register rm) { \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010000 << 21 | rm->encoding_with_zr() << 16 |   \
+        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                                     \
+  }
+
+  F(adc_w,  0, 0, 0)
+  F(adcs_w, 0, 0, 1)
+  F(sbc_w,  0, 1, 0)
+  F(sbcs_w, 0, 1, 1)
+
+  F(adc,    1, 0, 0)
+  F(adcs,   1, 0, 1)
+  F(sbc,    1, 1, 0)
+  F(sbcs,   1, 1, 1)
+#undef F
+
+#define F(mnemonic, sf, N) \
+  void mnemonic(Register rd, Register rn, Register rm, int lsb) { \
+    assert ((lsb >> (5 + sf)) == 0, "illegal least significant bit position");        \
+    emit_int32(sf << 31 | 0b100111 << 23 | N << 22 | rm->encoding_with_zr() << 16 |   \
+        lsb << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());            \
+  }
+
+  F(extr_w,  0, 0)
+  F(extr,    1, 1)
+#undef F
+
+#define F(mnemonic, sf, opc) \
+  void mnemonic(Register rd, int imm, int shift) { \
+    assert ((imm >> 16) == 0, "immediate is out of range");                       \
+    assert (((shift & 0xf) == 0) && ((shift >> (5 + sf)) == 0), "invalid shift"); \
+    emit_int32(sf << 31 | opc << 29 | 0b100101 << 23 | (shift >> 4) << 21 |       \
+        imm << 5 | rd->encoding_with_zr());                                       \
+  }
+
+  F(movn_w,  0, 0b00)
+  F(movz_w,  0, 0b10)
+  F(movk_w,  0, 0b11)
+  F(movn,    1, 0b00)
+  F(movz,    1, 0b10)
+  F(movk,    1, 0b11)
+#undef F
+
+  void mov(Register rd, int imm) {
+    assert ((imm >> 16) == 0, "immediate is out of range");
+    movz(rd, imm, 0);
+  }
+
+  void mov_w(Register rd, int imm) {
+    assert ((imm >> 16) == 0, "immediate is out of range");
+    movz_w(rd, imm, 0);
+  }
+
+#define F(mnemonic, sf, op, S) \
+  void mnemonic(Register rn, int imm, int nzcv, AsmCondition cond) { \
+    assert ((imm >> 5) == 0, "immediate is out of range");                      \
+    assert ((nzcv >> 4) == 0, "illegal nzcv");                                  \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | imm << 16 |   \
+         cond << 12 | 1 << 11 | rn->encoding_with_zr() << 5 | nzcv);            \
+  }
+
+  F(ccmn_w, 0, 0, 1)
+  F(ccmp_w, 0, 1, 1)
+  F(ccmn,   1, 0, 1)
+  F(ccmp,   1, 1, 1)
+#undef F
+
+#define F(mnemonic, sf, op, S) \
+  void mnemonic(Register rn, Register rm, int nzcv, AsmCondition cond) { \
+    assert ((nzcv >> 4) == 0, "illegal nzcv");                                                    \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | rm->encoding_with_zr() << 16 |  \
+        cond << 12 | rn->encoding_with_zr() << 5 | nzcv);                                         \
+  }
+
+  F(ccmn_w, 0, 0, 1)
+  F(ccmp_w, 0, 1, 1)
+  F(ccmn,   1, 0, 1)
+  F(ccmp,   1, 1, 1)
+#undef F
+
+#define F(mnemonic, sf, op, S, op2) \
+  void mnemonic(Register rd, Register rn, Register rm, AsmCondition cond) { \
+    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010100 << 21 | rm->encoding_with_zr() << 16 |  \
+        cond << 12 | op2 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());           \
+  }
+
+  F(csel_w,  0, 0, 0, 0b00)
+  F(csinc_w, 0, 0, 0, 0b01)
+  F(csinv_w, 0, 1, 0, 0b00)
+  F(csneg_w, 0, 1, 0, 0b01)
+
+  F(csel,    1, 0, 0, 0b00)
+  F(csinc,   1, 0, 0, 0b01)
+  F(csinv,   1, 1, 0, 0b00)
+  F(csneg,   1, 1, 0, 0b01)
+#undef F
+
+  void cset(Register rd, AsmCondition cond) {
+    csinc(rd, ZR, ZR, inverse(cond));
+  }
+
+  void cset_w(Register rd, AsmCondition cond) {
+    csinc_w(rd, ZR, ZR, inverse(cond));
+  }
+
+  void csetm(Register rd, AsmCondition cond) {
+    csinv(rd, ZR, ZR, inverse(cond));
+  }
+
+  void csetm_w(Register rd, AsmCondition cond) {
+    csinv_w(rd, ZR, ZR, inverse(cond));
+  }
+
+  void cinc(Register rd, Register rn, AsmCondition cond) {
+    csinc(rd, rn, rn, inverse(cond));
+  }
+
+  void cinc_w(Register rd, Register rn, AsmCondition cond) {
+    csinc_w(rd, rn, rn, inverse(cond));
+  }
+
+  void cinv(Register rd, Register rn, AsmCondition cond) {
+    csinv(rd, rn, rn, inverse(cond));
+  }
+
+  void cinv_w(Register rd, Register rn, AsmCondition cond) {
+    csinv_w(rd, rn, rn, inverse(cond));
+  }
+
+#define F(mnemonic, sf, S, opcode) \
+  void mnemonic(Register rd, Register rn) { \
+    emit_int32(sf << 31 | 1 << 30 | S << 29 | 0b11010110 << 21 | opcode << 10 |  \
+        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                   \
+  }
+
+  F(rbit_w,  0, 0, 0b000000)
+  F(rev16_w, 0, 0, 0b000001)
+  F(rev_w,   0, 0, 0b000010)
+  F(clz_w,   0, 0, 0b000100)
+  F(cls_w,   0, 0, 0b000101)
+
+  F(rbit,    1, 0, 0b000000)
+  F(rev16,   1, 0, 0b000001)
+  F(rev32,   1, 0, 0b000010)
+  F(rev,     1, 0, 0b000011)
+  F(clz,     1, 0, 0b000100)
+  F(cls,     1, 0, 0b000101)
+#undef F
+
+#define F(mnemonic, sf, S, opcode) \
+  void mnemonic(Register rd, Register rn, Register rm) { \
+    emit_int32(sf << 31 | S << 29 | 0b11010110 << 21 | rm->encoding_with_zr() << 16 |  \
+        opcode << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());          \
+  }
+
+  F(udiv_w,  0, 0, 0b000010)
+  F(sdiv_w,  0, 0, 0b000011)
+  F(lslv_w,  0, 0, 0b001000)
+  F(lsrv_w,  0, 0, 0b001001)
+  F(asrv_w,  0, 0, 0b001010)
+  F(rorv_w,  0, 0, 0b001011)
+
+  F(udiv,    1, 0, 0b000010)
+  F(sdiv,    1, 0, 0b000011)
+  F(lslv,    1, 0, 0b001000)
+  F(lsrv,    1, 0, 0b001001)
+  F(asrv,    1, 0, 0b001010)
+  F(rorv,    1, 0, 0b001011)
+#undef F
+
+#define F(mnemonic, sf, op31, o0) \
+  void mnemonic(Register rd, Register rn, Register rm, Register ra) { \
+    emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 |                     \
+        o0 << 15 | ra->encoding_with_zr() << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());  \
+  }
+
+  F(madd_w,  0, 0b000, 0)
+  F(msub_w,  0, 0b000, 1)
+  F(madd,    1, 0b000, 0)
+  F(msub,    1, 0b000, 1)
+
+  F(smaddl,  1, 0b001, 0)
+  F(smsubl,  1, 0b001, 1)
+  F(umaddl,  1, 0b101, 0)
+  F(umsubl,  1, 0b101, 1)
+#undef F
+
+  void mul(Register rd, Register rn, Register rm) {
+      madd(rd, rn, rm, ZR);
+  }
+
+  void mul_w(Register rd, Register rn, Register rm) {
+      madd_w(rd, rn, rm, ZR);
+  }
+
+#define F(mnemonic, sf, op31, o0) \
+  void mnemonic(Register rd, Register rn, Register rm) { \
+    emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 |      \
+        o0 << 15 | 0b11111 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());  \
+  }
+
+  F(smulh,   1, 0b010, 0)
+  F(umulh,   1, 0b110, 0)
+#undef F
+
+#define F(mnemonic, op) \
+  void mnemonic(Register rd, address addr) { \
+    intx offset;                                                        \
+    if (op == 0) {                                                      \
+      offset = addr - pc();                                             \
+    } else {                                                            \
+      offset = (((intx)addr) - (((intx)pc()) & ~0xfff)) >> 12;          \
+    }                                                                   \
+    assert (is_imm_in_range(offset, 21, 0), "offset is out of range");  \
+    emit_int32(op << 31 | (offset & 3) << 29 | 0b10000 << 24 |          \
+        encode_imm(offset >> 2, 19, 0, 5) | rd->encoding_with_zr());    \
+  }                                                                     \
+
+  F(adr,   0)
+  F(adrp,  1)
+#undef F
+
+  void adr(Register rd, Label& L) {
+    adr(rd, target(L));
+  }
+
+#define F(mnemonic, sf, opc, N)                                                \
+  void mnemonic(Register rd, Register rn, int immr, int imms) {                \
+    assert ((immr >> (5 + sf)) == 0, "immr is out of range");                  \
+    assert ((imms >> (5 + sf)) == 0, "imms is out of range");                  \
+    emit_int32(sf << 31 | opc << 29 | 0b100110 << 23 | N << 22 | immr << 16 |  \
+        imms << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());    \
+  }
+
+  F(sbfm_w, 0, 0b00, 0)
+  F(bfm_w,  0, 0b01, 0)
+  F(ubfm_w, 0, 0b10, 0)
+
+  F(sbfm, 1, 0b00, 1)
+  F(bfm,  1, 0b01, 1)
+  F(ubfm, 1, 0b10, 1)
+#undef F
+
+#define F(alias, mnemonic, sf, immr, imms) \
+  void alias(Register rd, Register rn, int lsb, int width) {                        \
+    assert ((lsb >> (5 + sf)) == 0, "lsb is out of range");                         \
+    assert ((1 <= width) && (width <= (32 << sf) - lsb), "width is out of range");  \
+    mnemonic(rd, rn, immr, imms);                                                   \
+  }
+
+  F(bfi_w,   bfm_w,  0, (-lsb) & 0x1f, width - 1)
+  F(bfi,     bfm,    1, (-lsb) & 0x3f, width - 1)
+  F(bfxil_w, bfm_w,  0, lsb,           lsb + width - 1)
+  F(bfxil,   bfm,    1, lsb,           lsb + width - 1)
+  F(sbfiz_w, sbfm_w, 0, (-lsb) & 0x1f, width - 1)
+  F(sbfiz,   sbfm,   1, (-lsb) & 0x3f, width - 1)
+  F(sbfx_w,  sbfm_w, 0, lsb,           lsb + width - 1)
+  F(sbfx,    sbfm,   1, lsb,           lsb + width - 1)
+  F(ubfiz_w, ubfm_w, 0, (-lsb) & 0x1f, width - 1)
+  F(ubfiz,   ubfm,   1, (-lsb) & 0x3f, width - 1)
+  F(ubfx_w,  ubfm_w, 0, lsb,           lsb + width - 1)
+  F(ubfx,    ubfm,   1, lsb,           lsb + width - 1)
+#undef F
+
+#define F(alias, mnemonic, sf, immr, imms) \
+  void alias(Register rd, Register rn, int shift) {              \
+    assert ((shift >> (5 + sf)) == 0, "shift is out of range");  \
+    mnemonic(rd, rn, immr, imms);                                \
+  }
+
+  F(_asr_w, sbfm_w, 0, shift, 31)
+  F(_asr,   sbfm,   1, shift, 63)
+  F(_lsl_w, ubfm_w, 0, (-shift) & 0x1f, 31 - shift)
+  F(_lsl,   ubfm,   1, (-shift) & 0x3f, 63 - shift)
+  F(_lsr_w, ubfm_w, 0, shift, 31)
+  F(_lsr,   ubfm,   1, shift, 63)
+#undef F
+
+#define F(alias, mnemonic, immr, imms) \
+  void alias(Register rd, Register rn) {   \
+    mnemonic(rd, rn, immr, imms);          \
+  }
+
+  F(sxtb_w, sbfm_w, 0, 7)
+  F(sxtb,   sbfm,   0, 7)
+  F(sxth_w, sbfm_w, 0, 15)
+  F(sxth,   sbfm,   0, 15)
+  F(sxtw,   sbfm,   0, 31)
+  F(uxtb_w, ubfm_w, 0, 7)
+  F(uxtb,   ubfm,   0, 7)
+  F(uxth_w, ubfm_w, 0, 15)
+  F(uxth,   ubfm,   0, 15)
+#undef F
+
+  // Branch instructions
+
+#define F(mnemonic, op) \
+  void mnemonic(Register rn) {                                                             \
+    emit_int32(0b1101011 << 25 | op << 21 | 0b11111 << 16 | rn->encoding_with_zr() << 5);  \
+  }
+
+  F(br,  0b00)
+  F(blr, 0b01)
+  F(ret, 0b10)
+#undef F
+
+  void ret() {
+    ret(LR);
+  }
+
+#define F(mnemonic, op) \
+  void mnemonic(address target) {                                         \
+    intx offset = target - pc();                                          \
+    assert (is_offset_in_range(offset, 26), "offset is out of range");    \
+    emit_int32(op << 31 | 0b00101 << 26 | encode_offset(offset, 26, 0));  \
+  }
+
+  F(b,  0)
+  F(bl, 1)
+#undef F
+
+  void b(address target, AsmCondition cond) {
+    if (cond == al) {
+      b(target);
+    } else {
+      intx offset = target - pc();
+      assert (is_offset_in_range(offset, 19), "offset is out of range");
+      emit_int32(0b0101010 << 25 | encode_offset(offset, 19, 5) | cond);
+    }
+  }
+
+
+#define F(mnemonic, sf, op)                                             \
+  void mnemonic(Register rt, address target) {                          \
+    intx offset = target - pc();                                        \
+    assert (is_offset_in_range(offset, 19), "offset is out of range");  \
+    emit_int32(sf << 31 | 0b011010 << 25 | op << 24 | encode_offset(offset, 19, 5) | rt->encoding_with_zr()); \
+  }                                                                     \
+
+  F(cbz_w,  0, 0)
+  F(cbnz_w, 0, 1)
+  F(cbz,    1, 0)
+  F(cbnz,   1, 1)
+#undef F
+
+#define F(mnemonic, op)                                                 \
+  void mnemonic(Register rt, int bit, address target) {                 \
+    intx offset = target - pc();                                        \
+    assert (is_offset_in_range(offset, 14), "offset is out of range");  \
+    assert (0 <= bit && bit < 64, "bit number is out of range");        \
+    emit_int32((bit >> 5) << 31 | 0b011011 << 25 | op << 24 | (bit & 0x1f) << 19 | \
+        encode_offset(offset, 14, 5) | rt->encoding_with_zr());         \
+  }                                                                     \
+
+  F(tbz,  0)
+  F(tbnz, 1)
+#undef F
+
+  // System instructions
+
+  enum DMB_Opt {
+    DMB_ld  = 0b1101,
+    DMB_st  = 0b1110,
+    DMB_all = 0b1111
+  };
+
+#define F(mnemonic, L, op0, op1, CRn, op2, Rt) \
+  void mnemonic(DMB_Opt option) {                                       \
+    emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 |   \
+        CRn << 12 | option << 8 | op2 << 5 | Rt);                       \
+  }
+
+  F(dsb,  0, 0b00, 0b011, 0b0011, 0b100, 0b11111)
+  F(dmb,  0, 0b00, 0b011, 0b0011, 0b101, 0b11111)
+#undef F
+
+#define F(mnemonic, L, op0, op1, CRn, Rt) \
+  void mnemonic(int imm) {                                              \
+    assert ((imm >> 7) == 0, "immediate is out of range");              \
+    emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 |   \
+        CRn << 12 | imm << 5 | Rt);                                     \
+  }
+
+  F(hint, 0, 0b00, 0b011, 0b0010, 0b11111)
+#undef F
+
+  void nop() {
+    hint(0);
+  }
+
+  void yield() {
+    hint(1);
+  }
+
+#define F(mnemonic, opc, op2, LL) \
+  void mnemonic(int imm = 0) {                                           \
+    assert ((imm >> 16) == 0, "immediate is out of range");              \
+    emit_int32(0b11010100 << 24 | opc << 21 | imm << 5 | op2 << 2 | LL); \
+  }
+
+  F(brk, 0b001, 0b000, 0b00)
+  F(hlt, 0b010, 0b000, 0b00)
+#undef F
+
+  enum SystemRegister { // o0<1> op1<3> CRn<4> CRm<4> op2<3>
+    SysReg_NZCV = 0b101101000010000,
+    SysReg_FPCR = 0b101101000100000,
+  };
+
+  void mrs(Register rt, SystemRegister systemReg) {
+    assert ((systemReg >> 15) == 0, "systemReg is out of range");
+    emit_int32(0b110101010011 << 20 | systemReg << 5 | rt->encoding_with_zr());
+  }
+
+  void msr(SystemRegister systemReg, Register rt) {
+    assert ((systemReg >> 15) == 0, "systemReg is out of range");
+    emit_int32(0b110101010001 << 20 | systemReg << 5 | rt->encoding_with_zr());
+  }
+
+  // Floating-point instructions
+
+#define F(mnemonic, M, S, type, opcode2) \
+  void mnemonic(FloatRegister rn, FloatRegister rm) {                         \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
+        rm->encoding() << 16 | 0b1000 << 10 | rn->encoding() << 5 | opcode2); \
+  }
+
+  F(fcmp_s,   0, 0, 0b00, 0b00000)
+  F(fcmpe_s,  0, 0, 0b00, 0b01000)
+  F(fcmp_d,   0, 0, 0b01, 0b00000)
+  F(fcmpe_d,  0, 0, 0b01, 0b10000)
+#undef F
+
+#define F(mnemonic, M, S, type, opcode2) \
+  void mnemonic(FloatRegister rn) {                                           \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
+        0b1000 << 10 | rn->encoding() << 5 | opcode2);                        \
+  }
+
+  F(fcmp0_s,   0, 0, 0b00, 0b01000)
+  F(fcmpe0_s,  0, 0, 0b00, 0b11000)
+  F(fcmp0_d,   0, 0, 0b01, 0b01000)
+  F(fcmpe0_d,  0, 0, 0b01, 0b11000)
+#undef F
+
+#define F(mnemonic, M, S, type, op) \
+  void mnemonic(FloatRegister rn, FloatRegister rm, int nzcv, AsmCondition cond) { \
+    assert ((nzcv >> 4) == 0, "illegal nzcv");                                                  \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
+        rm->encoding() << 16 | cond << 12 | 0b01 << 10 | rn->encoding() << 5 | op << 4 | nzcv); \
+  }
+
+  F(fccmp_s,   0, 0, 0b00, 0)
+  F(fccmpe_s,  0, 0, 0b00, 1)
+  F(fccmp_d,   0, 0, 0b01, 0)
+  F(fccmpe_d,  0, 0, 0b01, 1)
+#undef F
+
+#define F(mnemonic, M, S, type) \
+  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, AsmCondition cond) { \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
+        rm->encoding() << 16 | cond << 12 | 0b11 << 10 | rn->encoding() << 5 | rd->encoding()); \
+  }
+
+  F(fcsel_s,   0, 0, 0b00)
+  F(fcsel_d,   0, 0, 0b01)
+#undef F
+
+#define F(mnemonic, M, S, type, opcode) \
+  void mnemonic(FloatRegister rd, FloatRegister rn) { \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |      \
+        opcode << 15 | 0b10000 << 10 | rn->encoding() << 5 | rd->encoding());  \
+  }
+
+  F(fmov_s,   0, 0, 0b00, 0b000000)
+  F(fabs_s,   0, 0, 0b00, 0b000001)
+  F(fneg_s,   0, 0, 0b00, 0b000010)
+  F(fsqrt_s,  0, 0, 0b00, 0b000011)
+  F(fcvt_ds,  0, 0, 0b00, 0b000101)
+  F(fcvt_hs,  0, 0, 0b00, 0b000111)
+  F(frintn_s, 0, 0, 0b00, 0b001000)
+  F(frintp_s, 0, 0, 0b00, 0b001001)
+  F(frintm_s, 0, 0, 0b00, 0b001010)
+  F(frintz_s, 0, 0, 0b00, 0b001011)
+  F(frinta_s, 0, 0, 0b00, 0b001100)
+  F(frintx_s, 0, 0, 0b00, 0b001110)
+  F(frinti_s, 0, 0, 0b00, 0b001111)
+
+  F(fmov_d,   0, 0, 0b01, 0b000000)
+  F(fabs_d,   0, 0, 0b01, 0b000001)
+  F(fneg_d,   0, 0, 0b01, 0b000010)
+  F(fsqrt_d,  0, 0, 0b01, 0b000011)
+  F(fcvt_sd,  0, 0, 0b01, 0b000100)
+  F(fcvt_hd,  0, 0, 0b01, 0b000111)
+  F(frintn_d, 0, 0, 0b01, 0b001000)
+  F(frintp_d, 0, 0, 0b01, 0b001001)
+  F(frintm_d, 0, 0, 0b01, 0b001010)
+  F(frintz_d, 0, 0, 0b01, 0b001011)
+  F(frinta_d, 0, 0, 0b01, 0b001100)
+  F(frintx_d, 0, 0, 0b01, 0b001110)
+  F(frinti_d, 0, 0, 0b01, 0b001111)
+
+  F(fcvt_sh,  0, 0, 0b11, 0b000100)
+  F(fcvt_dh,  0, 0, 0b11, 0b000101)
+#undef F
+
+#define F(mnemonic, M, S, type, opcode) \
+  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm) { \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                          \
+        rm->encoding() << 16 | opcode << 12 | 0b10 << 10 | rn->encoding() << 5 | rd->encoding());  \
+  }
+
+  F(fmul_s,   0, 0, 0b00, 0b0000)
+  F(fdiv_s,   0, 0, 0b00, 0b0001)
+  F(fadd_s,   0, 0, 0b00, 0b0010)
+  F(fsub_s,   0, 0, 0b00, 0b0011)
+  F(fmax_s,   0, 0, 0b00, 0b0100)
+  F(fmin_s,   0, 0, 0b00, 0b0101)
+  F(fmaxnm_s, 0, 0, 0b00, 0b0110)
+  F(fminnm_s, 0, 0, 0b00, 0b0111)
+  F(fnmul_s,  0, 0, 0b00, 0b1000)
+
+  F(fmul_d,   0, 0, 0b01, 0b0000)
+  F(fdiv_d,   0, 0, 0b01, 0b0001)
+  F(fadd_d,   0, 0, 0b01, 0b0010)
+  F(fsub_d,   0, 0, 0b01, 0b0011)
+  F(fmax_d,   0, 0, 0b01, 0b0100)
+  F(fmin_d,   0, 0, 0b01, 0b0101)
+  F(fmaxnm_d, 0, 0, 0b01, 0b0110)
+  F(fminnm_d, 0, 0, 0b01, 0b0111)
+  F(fnmul_d,  0, 0, 0b01, 0b1000)
+#undef F
+
+#define F(mnemonic, M, S, type, o1, o0) \
+  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, FloatRegister ra) { \
+    emit_int32(M << 31 | S << 29 | 0b11111 << 24 | type << 22 | o1 << 21 | rm->encoding() << 16 |  \
+         o0 << 15 | ra->encoding() << 10 | rn->encoding() << 5 | rd->encoding());                  \
+  }
+
+  F(fmadd_s,  0, 0, 0b00, 0, 0)
+  F(fmsub_s,  0, 0, 0b00, 0, 1)
+  F(fnmadd_s, 0, 0, 0b00, 1, 0)
+  F(fnmsub_s, 0, 0, 0b00, 1, 1)
+
+  F(fmadd_d,  0, 0, 0b01, 0, 0)
+  F(fmsub_d,  0, 0, 0b01, 0, 1)
+  F(fnmadd_d, 0, 0, 0b01, 1, 0)
+  F(fnmsub_d, 0, 0, 0b01, 1, 1)
+#undef F
+
+#define F(mnemonic, M, S, type) \
+  void mnemonic(FloatRegister rd, int imm8) { \
+    assert ((imm8 >> 8) == 0, "immediate is out of range");                \
+    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |  \
+         imm8 << 13 | 0b100 << 10 | rd->encoding());                       \
+  }
+
+  F(fmov_s, 0, 0, 0b00)
+  F(fmov_d, 0, 0, 0b01)
+#undef F
+
+#define F(mnemonic, sf, S, type, rmode, opcode) \
+  void mnemonic(Register rd, FloatRegister rn) {                                     \
+    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
+         rmode << 19 | opcode << 16 | rn->encoding() << 5 | rd->encoding_with_zr()); \
+  }
+
+  F(fcvtns_ws, 0, 0, 0b00, 0b00, 0b000)
+  F(fcvtnu_ws, 0, 0, 0b00, 0b00, 0b001)
+  F(fcvtas_ws, 0, 0, 0b00, 0b00, 0b100)
+  F(fcvtau_ws, 0, 0, 0b00, 0b00, 0b101)
+  F(fmov_ws,   0, 0, 0b00, 0b00, 0b110)
+  F(fcvtps_ws, 0, 0, 0b00, 0b01, 0b000)
+  F(fcvtpu_ws, 0, 0, 0b00, 0b01, 0b001)
+  F(fcvtms_ws, 0, 0, 0b00, 0b10, 0b000)
+  F(fcvtmu_ws, 0, 0, 0b00, 0b10, 0b001)
+  F(fcvtzs_ws, 0, 0, 0b00, 0b11, 0b000)
+  F(fcvtzu_ws, 0, 0, 0b00, 0b11, 0b001)
+
+  F(fcvtns_wd, 0, 0, 0b01, 0b00, 0b000)
+  F(fcvtnu_wd, 0, 0, 0b01, 0b00, 0b001)
+  F(fcvtas_wd, 0, 0, 0b01, 0b00, 0b100)
+  F(fcvtau_wd, 0, 0, 0b01, 0b00, 0b101)
+  F(fcvtps_wd, 0, 0, 0b01, 0b01, 0b000)
+  F(fcvtpu_wd, 0, 0, 0b01, 0b01, 0b001)
+  F(fcvtms_wd, 0, 0, 0b01, 0b10, 0b000)
+  F(fcvtmu_wd, 0, 0, 0b01, 0b10, 0b001)
+  F(fcvtzs_wd, 0, 0, 0b01, 0b11, 0b000)
+  F(fcvtzu_wd, 0, 0, 0b01, 0b11, 0b001)
+
+  F(fcvtns_xs, 1, 0, 0b00, 0b00, 0b000)
+  F(fcvtnu_xs, 1, 0, 0b00, 0b00, 0b001)
+  F(fcvtas_xs, 1, 0, 0b00, 0b00, 0b100)
+  F(fcvtau_xs, 1, 0, 0b00, 0b00, 0b101)
+  F(fcvtps_xs, 1, 0, 0b00, 0b01, 0b000)
+  F(fcvtpu_xs, 1, 0, 0b00, 0b01, 0b001)
+  F(fcvtms_xs, 1, 0, 0b00, 0b10, 0b000)
+  F(fcvtmu_xs, 1, 0, 0b00, 0b10, 0b001)
+  F(fcvtzs_xs, 1, 0, 0b00, 0b11, 0b000)
+  F(fcvtzu_xs, 1, 0, 0b00, 0b11, 0b001)
+
+  F(fcvtns_xd, 1, 0, 0b01, 0b00, 0b000)
+  F(fcvtnu_xd, 1, 0, 0b01, 0b00, 0b001)
+  F(fcvtas_xd, 1, 0, 0b01, 0b00, 0b100)
+  F(fcvtau_xd, 1, 0, 0b01, 0b00, 0b101)
+  F(fmov_xd,   1, 0, 0b01, 0b00, 0b110)
+  F(fcvtps_xd, 1, 0, 0b01, 0b01, 0b000)
+  F(fcvtpu_xd, 1, 0, 0b01, 0b01, 0b001)
+  F(fcvtms_xd, 1, 0, 0b01, 0b10, 0b000)
+  F(fcvtmu_xd, 1, 0, 0b01, 0b10, 0b001)
+  F(fcvtzs_xd, 1, 0, 0b01, 0b11, 0b000)
+  F(fcvtzu_xd, 1, 0, 0b01, 0b11, 0b001)
+
+  F(fmov_xq,   1, 0, 0b10, 0b01, 0b110)
+#undef F
+
+#define F(mnemonic, sf, S, type, rmode, opcode) \
+  void mnemonic(FloatRegister rd, Register rn) {                                     \
+    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
+         rmode << 19 | opcode << 16 | rn->encoding_with_zr() << 5 | rd->encoding()); \
+  }
+
+  F(scvtf_sw,  0, 0, 0b00, 0b00, 0b010)
+  F(ucvtf_sw,  0, 0, 0b00, 0b00, 0b011)
+  F(fmov_sw,   0, 0, 0b00, 0b00, 0b111)
+  F(scvtf_dw,  0, 0, 0b01, 0b00, 0b010)
+  F(ucvtf_dw,  0, 0, 0b01, 0b00, 0b011)
+
+  F(scvtf_sx,  1, 0, 0b00, 0b00, 0b010)
+  F(ucvtf_sx,  1, 0, 0b00, 0b00, 0b011)
+  F(scvtf_dx,  1, 0, 0b01, 0b00, 0b010)
+  F(ucvtf_dx,  1, 0, 0b01, 0b00, 0b011)
+  F(fmov_dx,   1, 0, 0b01, 0b00, 0b111)
+
+  F(fmov_qx,   1, 0, 0b10, 0b01, 0b111)
+#undef F
+
+#define F(mnemonic, opcode) \
+  void mnemonic(FloatRegister Vd, FloatRegister Vn) {                                     \
+    emit_int32( opcode << 10 | Vn->encoding() << 5 | Vd->encoding());             \
+  }
+
+  F(aese, 0b0100111000101000010010);
+  F(aesd, 0b0100111000101000010110);
+  F(aesmc, 0b0100111000101000011010);
+  F(aesimc, 0b0100111000101000011110);
+#undef F
+
+#ifdef COMPILER2
+  typedef VFP::double_num double_num;
+  typedef VFP::float_num  float_num;
+#endif
+
+  void vcnt(FloatRegister Dd, FloatRegister Dn, int quad = 0, int size = 0) {
+    // emitted at VM startup to detect whether the instruction is available
+    assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction");
+    assert(size == 0, "illegal size value");
+    emit_int32(0x0e205800 | quad << 30 | size << 22 | Dn->encoding() << 5 | Dd->encoding());
+  }
+
+#ifdef COMPILER2
+  void addv(FloatRegister Dd, FloatRegister Dm, int quad, int size) {
+    // emitted at VM startup to detect whether the instruction is available
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert((quad & ~1) == 0, "illegal value");
+    assert(size >= 0 && size < 3, "illegal value");
+    assert(((size << 1) | quad) != 4, "illegal values (size 2, quad 0)");
+    emit_int32(0x0e31b800 | quad << 30 | size << 22 | Dm->encoding() << 5 | Dd->encoding());
+  }
+
+  enum VElem_Size {
+    VELEM_SIZE_8  = 0x00,
+    VELEM_SIZE_16 = 0x01,
+    VELEM_SIZE_32 = 0x02,
+    VELEM_SIZE_64 = 0x03
+  };
+
+  enum VLD_Type {
+    VLD1_TYPE_1_REG  = 0b0111,
+    VLD1_TYPE_2_REGS = 0b1010,
+    VLD1_TYPE_3_REGS = 0b0110,
+    VLD1_TYPE_4_REGS = 0b0010
+  };
+
+  enum VFloat_Arith_Size {
+    VFA_SIZE_F32 = 0b0,
+    VFA_SIZE_F64 = 0b1
+  };
+
+#define F(mnemonic, U, S, P) \
+  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
+                int size, int quad) {                                    \
+    assert(VM_Version::has_simd(), "simd instruction");                  \
+    assert(!(size == VFA_SIZE_F64 && !quad), "reserved");                \
+    assert((size & 1) == size, "overflow");                              \
+    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |                    \
+               S << 23 | size << 22 | 1 << 21 | P << 11 | 1 << 10 |      \
+               fm->encoding() << 16 |                                    \
+               fn->encoding() <<  5 |                                    \
+               fd->encoding());                                          \
+  }
+
+  F(vaddF, 0, 0, 0b11010)  // Vd = Vn + Vm (float)
+  F(vsubF, 0, 1, 0b11010)  // Vd = Vn - Vm (float)
+  F(vmulF, 1, 0, 0b11011)  // Vd = Vn - Vm (float)
+  F(vdivF, 1, 0, 0b11111)  // Vd = Vn / Vm (float)
+#undef F
+
+#define F(mnemonic, U) \
+  void mnemonic(FloatRegister fd, FloatRegister fm, FloatRegister fn,    \
+                int size, int quad) {                                    \
+    assert(VM_Version::has_simd(), "simd instruction");                  \
+    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
+    assert((size & 0b11) == size, "overflow");                           \
+    int R = 0; /* rounding */                                            \
+    int S = 0; /* saturating */                                          \
+    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
+               1 << 21 | R << 12 | S << 11 | 0b10001 << 10 |             \
+               fm->encoding() << 16 |                                    \
+               fn->encoding() <<  5 |                                    \
+               fd->encoding());                                          \
+  }
+
+  F(vshlSI, 0)  // Vd = ashift(Vn,Vm) (int)
+  F(vshlUI, 1)  // Vd = lshift(Vn,Vm) (int)
+#undef F
+
+#define F(mnemonic, U, P, M) \
+  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
+                int size, int quad) {                                    \
+    assert(VM_Version::has_simd(), "simd instruction");                  \
+    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
+    assert(!(size == VELEM_SIZE_64 && M), "reserved");                   \
+    assert((size & 0b11) == size, "overflow");                           \
+    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
+               1 << 21 | P << 11 | 1 << 10 |                             \
+               fm->encoding() << 16 |                                    \
+               fn->encoding() <<  5 |                                    \
+               fd->encoding());                                          \
+  }
+
+  F(vmulI, 0, 0b10011,  true)  // Vd = Vn * Vm (int)
+  F(vaddI, 0, 0b10000, false)  // Vd = Vn + Vm (int)
+  F(vsubI, 1, 0b10000, false)  // Vd = Vn - Vm (int)
+#undef F
+
+#define F(mnemonic, U, O) \
+  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
+                int quad) {                                              \
+    assert(VM_Version::has_simd(), "simd instruction");                  \
+    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | O << 22 |          \
+               1 << 21 | 0b00011 << 11 | 1 << 10 |                       \
+               fm->encoding() << 16 |                                    \
+               fn->encoding() <<  5 |                                    \
+               fd->encoding());                                          \
+  }
+
+  F(vandI, 0, 0b00)  // Vd = Vn & Vm (int)
+  F(vorI,  0, 0b10)  // Vd = Vn | Vm (int)
+  F(vxorI, 1, 0b00)  // Vd = Vn ^ Vm (int)
+#undef F
+
+  void vnegI(FloatRegister fd, FloatRegister fn, int size, int quad) {
+    int U = 1;
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(quad || size != VELEM_SIZE_64, "reserved");
+    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |
+              size << 22 | 0b100000101110 << 10 |
+              fn->encoding() << 5 |
+              fd->encoding() << 0);
+  }
+
+  void vshli(FloatRegister fd, FloatRegister fn, int esize, int imm, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+
+    if (imm >= esize) {
+      // maximum shift gives all zeroes, direction doesn't matter,
+      // but only available for shift right
+      vshri(fd, fn, esize, esize, true /* unsigned */, quad);
+      return;
+    }
+    assert(imm >= 0 && imm < esize, "out of range");
+
+    int imm7 = esize + imm;
+    int immh = imm7 >> 3;
+    assert(immh != 0, "encoding constraint");
+    assert((uint)immh < 16, "sanity");
+    assert(((immh >> 2) | quad) != 0b10, "reserved");
+    emit_int32(quad << 30 | 0b011110 << 23 | imm7 << 16 |
+               0b010101 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
+  }
+
+  void vshri(FloatRegister fd, FloatRegister fn, int esize, int imm,
+             bool U /* unsigned */, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(imm > 0, "out of range");
+    if (imm >= esize) {
+      // maximum shift (all zeroes)
+      imm = esize;
+    }
+    int imm7 = 2 * esize - imm ;
+    int immh = imm7 >> 3;
+    assert(immh != 0, "encoding constraint");
+    assert((uint)immh < 16, "sanity");
+    assert(((immh >> 2) | quad) != 0b10, "reserved");
+    emit_int32(quad << 30 | U << 29 | 0b011110 << 23 | imm7 << 16 |
+               0b000001 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
+  }
+  void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
+    vshri(fd, fm, size, imm, true /* unsigned */, quad);
+  }
+  void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
+    vshri(fd, fm, size, imm, false /* signed */, quad);
+  }
+
+  void vld1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 1;
+    int opcode = VLD1_TYPE_1_REG;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vst1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 0;
+    int opcode = VLD1_TYPE_1_REG;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vld1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(Vt->successor() == Vt2, "Registers must be ordered");
+    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 1;
+    int opcode = VLD1_TYPE_2_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vst1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(Vt->successor() == Vt2, "Registers must be ordered");
+    assert(bits == 128, "unsupported");
+    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 0;
+    int opcode = VLD1_TYPE_2_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
+            Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3,
+          "Registers must be ordered");
+    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 1;
+    int opcode = VLD1_TYPE_3_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
+            Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(Vt->successor() == Vt2 &&  Vt2->successor() == Vt3,
+           "Registers must be ordered");
+    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 0;
+    int opcode = VLD1_TYPE_3_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
+            FloatRegister Vt4, Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
+           Vt3->successor() == Vt4, "Registers must be ordered");
+    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 1;
+    int opcode = VLD1_TYPE_4_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
+            FloatRegister Vt4,  Address addr, VElem_Size size, int bits) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(bits == 128, "unsupported");
+    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
+           Vt3->successor() == Vt4, "Registers must be ordered");
+    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
+    int type = 0b11; // 2D
+    int quad = 1;
+    int L = 0;
+    int opcode = VLD1_TYPE_4_REGS;
+    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
+               Vt->encoding() << 0 | addr.encoding_simd());
+  }
+
+  void rev32(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(size == VELEM_SIZE_8 || size == VELEM_SIZE_16, "must be");
+    emit_int32(quad << 30 | 0b101110 << 24 | size << 22 |
+               0b100000000010 << 10 | Vn->encoding() << 5 | Vd->encoding());
+  }
+
+  void eor(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(size == VELEM_SIZE_8, "must be");
+    emit_int32(quad << 30 | 0b101110001 << 21 | Vm->encoding() << 16 |
+               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
+  }
+
+  void orr(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(size == VELEM_SIZE_8, "must be");
+    emit_int32(quad << 30 | 0b001110101 << 21 | Vm->encoding() << 16 |
+               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
+  }
+
+  void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(imm8 >= 0 && imm8 < 256, "out of range");
+    int op;
+    int cmode;
+    switch (size) {
+    case VELEM_SIZE_8:
+      op = 0;
+      cmode = 0b1110;
+      break;
+    case VELEM_SIZE_16:
+      op = 0;
+      cmode = 0b1000;
+      break;
+    case VELEM_SIZE_32:
+      op = 0;
+      cmode = 0b0000;
+      break;
+    default:
+      cmode = 0;
+      ShouldNotReachHere();
+    }
+    int abc = imm8 >> 5;
+    int defgh = imm8 & 0b11111;
+    emit_int32(quad << 30 | op << 29 | 0b1111 << 24 |
+               abc << 16 | cmode << 12 | 0b01 << 10 |
+               defgh << 5 | Dd->encoding() << 0);
+  }
+
+  void vdupI(FloatRegister Dd, Register Rn, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    assert(size <= 3, "unallocated encoding");
+    assert(size != 3 || quad == 1, "reserved");
+    int imm5 = 1 << size;
+#ifdef ASSERT
+    switch (size) {
+    case VELEM_SIZE_8:
+      assert(imm5 == 0b00001, "sanity");
+      break;
+    case VELEM_SIZE_16:
+      assert(imm5 == 0b00010, "sanity");
+      break;
+    case VELEM_SIZE_32:
+      assert(imm5 == 0b00100, "sanity");
+      break;
+    case VELEM_SIZE_64:
+      assert(imm5 == 0b01000, "sanity");
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+#endif
+    emit_int32(quad << 30 | 0b111 << 25 | 0b11 << 10 |
+               imm5 << 16 | Rn->encoding() << 5 |
+               Dd->encoding() << 0);
+  }
+
+  void vdup(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
+    assert(VM_Version::has_simd(), "simd instruction");
+    int index = 0;
+    int bytes = 1 << size;
+    int range = 16 / bytes;
+    assert(index < range, "overflow");
+
+    assert(size != VELEM_SIZE_64 || quad, "reserved");
+    assert(8 << VELEM_SIZE_8  ==  8, "sanity");
+    assert(8 << VELEM_SIZE_16 == 16, "sanity");
+    assert(8 << VELEM_SIZE_32 == 32, "sanity");
+    assert(8 << VELEM_SIZE_64 == 64, "sanity");
+
+    int imm5 = (index << (size + 1)) | bytes;
+
+    emit_int32(quad << 30 | 0b001110000 << 21 | imm5 << 16 | 0b000001 << 10 |
+               Vn->encoding() << 5 | Vd->encoding() << 0);
+  }
+
+  void vdupF(FloatRegister Vd, FloatRegister Vn, int quad) {
+    vdup(Vd, Vn, VELEM_SIZE_32, quad);
+  }
+
+  void vdupD(FloatRegister Vd, FloatRegister Vn, int quad) {
+    vdup(Vd, Vn, VELEM_SIZE_64, quad);
+  }
+#endif
+};
+
+
+#endif // CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
diff --git a/hotspot/src/cpu/arm/vm/bytes_arm.hpp b/hotspot/src/cpu/arm/vm/bytes_arm.hpp
new file mode 100644
index 0000000..0cf7e2a
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/bytes_arm.hpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_BYTES_ARM_HPP
+#define CPU_ARM_VM_BYTES_ARM_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/macros.hpp"
+
+#ifndef VM_LITTLE_ENDIAN
+#define VM_LITTLE_ENDIAN  1
+#endif
+
+class Bytes: AllStatic {
+
+ public:
+  // Returns true if the byte ordering used by Java is different from the native byte ordering
+  // of the underlying machine.
+  static inline bool is_Java_byte_ordering_different() {
+    return VM_LITTLE_ENDIAN != 0;
+  }
+
+  static inline u2 get_Java_u2(address p) {
+    return (u2(p[0]) << 8) | u2(p[1]);
+  }
+
+  static inline u4 get_Java_u4(address p) {
+    return u4(p[0]) << 24 |
+           u4(p[1]) << 16 |
+           u4(p[2]) <<  8 |
+           u4(p[3]);
+  }
+
+  static inline u8 get_Java_u8(address p) {
+    return u8(p[0]) << 56 |
+           u8(p[1]) << 48 |
+           u8(p[2]) << 40 |
+           u8(p[3]) << 32 |
+           u8(p[4]) << 24 |
+           u8(p[5]) << 16 |
+           u8(p[6]) <<  8 |
+           u8(p[7]);
+  }
+
+  static inline void put_Java_u2(address p, u2 x) {
+    p[0] = x >> 8;
+    p[1] = x;
+  }
+
+  static inline void put_Java_u4(address p, u4 x) {
+    ((u1*)p)[0] = x >> 24;
+    ((u1*)p)[1] = x >> 16;
+    ((u1*)p)[2] = x >>  8;
+    ((u1*)p)[3] = x;
+  }
+
+  static inline void put_Java_u8(address p, u8 x) {
+    ((u1*)p)[0] = x >> 56;
+    ((u1*)p)[1] = x >> 48;
+    ((u1*)p)[2] = x >> 40;
+    ((u1*)p)[3] = x >> 32;
+    ((u1*)p)[4] = x >> 24;
+    ((u1*)p)[5] = x >> 16;
+    ((u1*)p)[6] = x >>  8;
+    ((u1*)p)[7] = x;
+  }
+
+#ifdef VM_LITTLE_ENDIAN
+
+  static inline u2 get_native_u2(address p) {
+    return (intptr_t(p) & 1) == 0 ? *(u2*)p : u2(p[0]) | (u2(p[1]) << 8);
+  }
+
+  static inline u4 get_native_u4(address p) {
+    switch (intptr_t(p) & 3) {
+      case 0:  return *(u4*)p;
+      case 2:  return u4(((u2*)p)[0]) |
+                      u4(((u2*)p)[1]) << 16;
+      default: return u4(p[0])       |
+                      u4(p[1]) <<  8 |
+                      u4(p[2]) << 16 |
+                      u4(p[3]) << 24;
+    }
+  }
+
+  static inline u8 get_native_u8(address p) {
+    switch (intptr_t(p) & 7) {
+      case 0:  return *(u8*)p;
+      case 4:  return u8(((u4*)p)[0]) |
+                      u8(((u4*)p)[1]) << 32;
+      case 2:  return u8(((u2*)p)[0])       |
+                      u8(((u2*)p)[1]) << 16 |
+                      u8(((u2*)p)[2]) << 32 |
+                      u8(((u2*)p)[3]) << 48;
+      default: return u8(p[0])       |
+                      u8(p[1]) <<  8 |
+                      u8(p[2]) << 16 |
+                      u8(p[3]) << 24 |
+                      u8(p[4]) << 32 |
+                      u8(p[5]) << 40 |
+                      u8(p[6]) << 48 |
+                      u8(p[7]) << 56;
+    }
+  }
+
+  static inline void put_native_u2(address p, u2 x) {
+    if ((intptr_t(p) & 1) == 0) {
+      *(u2*)p = x;
+    } else {
+      p[0] = x;
+      p[1] = x >> 8;
+    }
+  }
+
+  static inline void put_native_u4(address p, u4 x) {
+    switch (intptr_t(p) & 3) {
+      case 0:  *(u4*)p = x;
+               break;
+      case 2:  ((u2*)p)[0] = x;
+               ((u2*)p)[1] = x >> 16;
+               break;
+      default: ((u1*)p)[0] = x;
+               ((u1*)p)[1] = x >>  8;
+               ((u1*)p)[2] = x >> 16;
+               ((u1*)p)[3] = x >> 24;
+               break;
+    }
+  }
+
+  static inline void put_native_u8(address p, u8 x) {
+    switch (intptr_t(p) & 7) {
+      case 0:  *(u8*)p = x;
+               break;
+      case 4:  ((u4*)p)[0] = x;
+               ((u4*)p)[1] = x >> 32;
+               break;
+      case 2:  ((u2*)p)[0] = x;
+               ((u2*)p)[1] = x >> 16;
+               ((u2*)p)[2] = x >> 32;
+               ((u2*)p)[3] = x >> 48;
+               break;
+      default: ((u1*)p)[0] = x;
+               ((u1*)p)[1] = x >>  8;
+               ((u1*)p)[2] = x >> 16;
+               ((u1*)p)[3] = x >> 24;
+               ((u1*)p)[4] = x >> 32;
+               ((u1*)p)[5] = x >> 40;
+               ((u1*)p)[6] = x >> 48;
+               ((u1*)p)[7] = x >> 56;
+    }
+  }
+
+#else
+
+  static inline u2 get_native_u2(address p) { return get_Java_u2(p); }
+  static inline u4 get_native_u4(address p) { return get_Java_u4(p); }
+  static inline u8 get_native_u8(address p) { return get_Java_u8(p); }
+  static inline void put_native_u2(address p, u2 x) { put_Java_u2(p, x); }
+  static inline void put_native_u4(address p, u4 x) { put_Java_u4(p, x); }
+  static inline void put_native_u8(address p, u8 x) { put_Java_u8(p, x); }
+
+#endif // VM_LITTLE_ENDIAN
+
+  // Efficient swapping of byte ordering
+  static inline u2 swap_u2(u2 x);
+  static inline u4 swap_u4(u4 x);
+  static inline u8 swap_u8(u8 x);
+};
+
+
+// The following header contains the implementations of swap_u2, swap_u4, and swap_u8
+#include OS_CPU_HEADER_INLINE(bytes)
+
+#endif // CPU_ARM_VM_BYTES_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_CodeStubs_arm.cpp b/hotspot/src/cpu/arm/vm/c1_CodeStubs_arm.cpp
new file mode 100644
index 0000000..20cf726
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_CodeStubs_arm.cpp
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "c1/c1_CodeStubs.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "nativeInst_arm.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "utilities/macros.hpp"
+#include "vmreg_arm.inline.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif // INCLUDE_ALL_GCS
+
+#define __ ce->masm()->
+
+void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  ce->store_parameter(_bci, 0);
+  ce->store_parameter(_method->as_constant_ptr()->as_metadata(), 1);
+  __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+
+  __ b(_continuation);
+}
+
+
+// TODO: ARM - is it possible to inline these stubs into the main code stream?
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index,
+                               bool throw_index_out_of_bounds_exception)
+  : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception)
+  , _index(index)
+{
+  _info = info == NULL ? NULL : new CodeEmitInfo(info);
+}
+
+
+void RangeCheckStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+
+  if (_info->deoptimize_on_exception()) {
+#ifdef AARCH64
+    __ NOT_TESTED();
+#endif
+    __ call(Runtime1::entry_for(Runtime1::predicate_failed_trap_id), relocInfo::runtime_call_type);
+    ce->add_call_info_here(_info);
+    ce->verify_oop_map(_info);
+    debug_only(__ should_not_reach_here());
+    return;
+  }
+  // Pass the array index on stack because all registers must be preserved
+  ce->verify_reserved_argument_area_size(1);
+  if (_index->is_cpu_register()) {
+    __ str_32(_index->as_register(), Address(SP));
+  } else {
+    __ mov_slow(Rtemp, _index->as_jint()); // Rtemp should be OK in C1
+    __ str_32(Rtemp, Address(SP));
+  }
+
+  if (_throw_index_out_of_bounds_exception) {
+#ifdef AARCH64
+    __ NOT_TESTED();
+#endif
+    __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type);
+  } else {
+    __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type);
+  }
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  DEBUG_ONLY(STOP("RangeCheck");)
+}
+
+PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
+  _info = new CodeEmitInfo(info);
+}
+
+void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  __ call(Runtime1::entry_for(Runtime1::predicate_failed_trap_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  debug_only(__ should_not_reach_here());
+}
+
+void DivByZeroStub::emit_code(LIR_Assembler* ce) {
+  if (_offset != -1) {
+    ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
+  }
+  __ bind(_entry);
+  __ call(Runtime1::entry_for(Runtime1::throw_div0_exception_id),
+          relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  DEBUG_ONLY(STOP("DivByZero");)
+}
+
+
+// Implementation of NewInstanceStub
+
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+  _result = result;
+  _klass = klass;
+  _klass_reg = klass_reg;
+  _info = new CodeEmitInfo(info);
+  assert(stub_id == Runtime1::new_instance_id                 ||
+         stub_id == Runtime1::fast_new_instance_id            ||
+         stub_id == Runtime1::fast_new_instance_init_check_id,
+         "need new_instance id");
+  _stub_id   = stub_id;
+}
+
+
+void NewInstanceStub::emit_code(LIR_Assembler* ce) {
+  assert(_result->as_register() == R0, "runtime call setup");
+  assert(_klass_reg->as_register() == R1, "runtime call setup");
+  __ bind(_entry);
+  __ call(Runtime1::entry_for(_stub_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
+
+
+// Implementation of NewTypeArrayStub
+
+NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+  _klass_reg = klass_reg;
+  _length = length;
+  _result = result;
+  _info = new CodeEmitInfo(info);
+}
+
+
+void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(_result->as_register() == R0, "runtime call setup");
+  assert(_klass_reg->as_register() == R1, "runtime call setup");
+  assert(_length->as_register() == R2, "runtime call setup");
+  __ bind(_entry);
+  __ call(Runtime1::entry_for(Runtime1::new_type_array_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
+
+
+// Implementation of NewObjectArrayStub
+
+NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+  _klass_reg = klass_reg;
+  _result = result;
+  _length = length;
+  _info = new CodeEmitInfo(info);
+}
+
+
+void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(_result->as_register() == R0, "runtime call setup");
+  assert(_klass_reg->as_register() == R1, "runtime call setup");
+  assert(_length->as_register() == R2, "runtime call setup");
+  __ bind(_entry);
+  __ call(Runtime1::entry_for(Runtime1::new_object_array_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
+
+
+// Implementation of MonitorAccessStubs
+
+MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
+: MonitorAccessStub(obj_reg, lock_reg)
+{
+  _info = new CodeEmitInfo(info);
+}
+
+
+void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  const Register obj_reg = _obj_reg->as_pointer_register();
+  const Register lock_reg = _lock_reg->as_pointer_register();
+
+  ce->verify_reserved_argument_area_size(2);
+#ifdef AARCH64
+  __ stp(obj_reg, lock_reg, Address(SP));
+#else
+  if (obj_reg < lock_reg) {
+    __ stmia(SP, RegisterSet(obj_reg) | RegisterSet(lock_reg));
+  } else {
+    __ str(obj_reg, Address(SP));
+    __ str(lock_reg, Address(SP, BytesPerWord));
+  }
+#endif // AARCH64
+
+  Runtime1::StubID enter_id = ce->compilation()->has_fpu_code() ?
+                              Runtime1::monitorenter_id :
+                              Runtime1::monitorenter_nofpu_id;
+  __ call(Runtime1::entry_for(enter_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
+
+
+void MonitorExitStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  if (_compute_lock) {
+    ce->monitor_address(_monitor_ix, _lock_reg);
+  }
+  const Register lock_reg = _lock_reg->as_pointer_register();
+
+  ce->verify_reserved_argument_area_size(1);
+  __ str(lock_reg, Address(SP));
+
+  // Non-blocking leaf routine - no call info needed
+  Runtime1::StubID exit_id = ce->compilation()->has_fpu_code() ?
+                             Runtime1::monitorexit_id :
+                             Runtime1::monitorexit_nofpu_id;
+  __ call(Runtime1::entry_for(exit_id), relocInfo::runtime_call_type);
+  __ b(_continuation);
+}
+
+
+// Call return is directly after patch word
+int PatchingStub::_patch_info_offset = 0;
+
+void PatchingStub::align_patch_site(MacroAssembler* masm) {
+#if 0
+  // TODO: investigate if we required to implement this
+    ShouldNotReachHere();
+#endif
+}
+
+void PatchingStub::emit_code(LIR_Assembler* ce) {
+  const int patchable_instruction_offset = AARCH64_ONLY(NativeInstruction::instruction_size) NOT_AARCH64(0);
+
+  assert(NativeCall::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF,
+         "not enough room for call");
+  assert((_bytes_to_copy & 3) == 0, "must copy a multiple of four bytes");
+  Label call_patch;
+  bool is_load = (_id == load_klass_id) || (_id == load_mirror_id) || (_id == load_appendix_id);
+
+#ifdef AARCH64
+  assert(nativeInstruction_at(_pc_start)->is_nop(), "required for MT safe patching");
+
+  // Same alignment of reg2mem code and PatchingStub code. Required to make copied bind_literal() code properly aligned.
+  __ align(wordSize);
+#endif // AARCH64
+
+  if (is_load NOT_AARCH64(&& !VM_Version::supports_movw())) {
+    address start = __ pc();
+
+    // The following sequence duplicates code provided in MacroAssembler::patchable_mov_oop()
+    // without creating relocation info entry.
+#ifdef AARCH64
+    // Extra nop for MT safe patching
+    __ nop();
+#endif // AARCH64
+
+    assert((__ pc() - start) == patchable_instruction_offset, "should be");
+#ifdef AARCH64
+    __ ldr(_obj, __ pc());
+#else
+    __ ldr(_obj, Address(PC));
+    // Extra nop to handle case of large offset of oop placeholder (see NativeMovConstReg::set_data).
+    __ nop();
+#endif // AARCH64
+
+#ifdef ASSERT
+    for (int i = 0; i < _bytes_to_copy; i++) {
+      assert(((address)_pc_start)[i] == start[i], "should be the same code");
+    }
+#endif // ASSERT
+  }
+
+  address being_initialized_entry = __ pc();
+  if (CommentedAssembly) {
+    __ block_comment(" patch template");
+  }
+  if (is_load) {
+    address start = __ pc();
+    if (_id == load_mirror_id || _id == load_appendix_id) {
+      __ patchable_mov_oop(_obj, (jobject)Universe::non_oop_word(), _index);
+    } else {
+      __ patchable_mov_metadata(_obj, (Metadata*)Universe::non_oop_word(), _index);
+    }
+#ifdef ASSERT
+    for (int i = 0; i < _bytes_to_copy; i++) {
+      assert(((address)_pc_start)[i] == start[i], "should be the same code");
+    }
+#endif // ASSERT
+  } else {
+    int* start = (int*)_pc_start;
+    int* end = start + (_bytes_to_copy / BytesPerInt);
+    while (start < end) {
+      __ emit_int32(*start++);
+    }
+  }
+  address end_of_patch = __ pc();
+
+  int bytes_to_skip = 0;
+  if (_id == load_mirror_id) {
+    int offset = __ offset();
+    if (CommentedAssembly) {
+      __ block_comment(" being_initialized check");
+    }
+
+    assert(_obj != noreg, "must be a valid register");
+    // Rtemp should be OK in C1
+    __ ldr(Rtemp, Address(_obj, java_lang_Class::klass_offset_in_bytes()));
+    __ ldr(Rtemp, Address(Rtemp, InstanceKlass::init_thread_offset()));
+    __ cmp(Rtemp, Rthread);
+    __ b(call_patch, ne);
+    __ b(_patch_site_continuation);
+
+    bytes_to_skip += __ offset() - offset;
+  }
+
+  if (CommentedAssembly) {
+    __ block_comment("patch data - 3 high bytes of the word");
+  }
+  const int sizeof_patch_record = 4;
+  bytes_to_skip += sizeof_patch_record;
+  int being_initialized_entry_offset = __ pc() - being_initialized_entry + sizeof_patch_record;
+  __ emit_int32(0xff | being_initialized_entry_offset << 8 | bytes_to_skip << 16 | _bytes_to_copy << 24);
+
+  address patch_info_pc = __ pc();
+  assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
+
+  // runtime call will return here
+  Label call_return;
+  __ bind(call_return);
+  ce->add_call_info_here(_info);
+  assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change");
+  __ b(_patch_site_entry);
+
+  address entry = __ pc();
+  NativeGeneralJump::insert_unconditional((address)_pc_start, entry);
+  address target = NULL;
+  relocInfo::relocType reloc_type = relocInfo::none;
+  switch (_id) {
+    case access_field_id:  target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
+    case load_klass_id:    target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
+    case load_mirror_id:   target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+    case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
+    default: ShouldNotReachHere();
+  }
+  __ bind(call_patch);
+
+  if (CommentedAssembly) {
+    __ block_comment("patch entry point");
+  }
+
+  // arrange for call to return just after patch word
+  __ adr(LR, call_return);
+  __ jump(target, relocInfo::runtime_call_type, Rtemp);
+
+  if (is_load) {
+    CodeSection* cs = __ code_section();
+    address pc = (address)_pc_start;
+    RelocIterator iter(cs, pc, pc + 1);
+    relocInfo::change_reloc_info_for_address(&iter, pc, reloc_type, relocInfo::none);
+  }
+}
+
+void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  __ mov_slow(Rtemp, _trap_request);
+  ce->verify_reserved_argument_area_size(1);
+  __ str(Rtemp, Address(SP));
+  __ call(Runtime1::entry_for(Runtime1::deoptimize_id), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  DEBUG_ONLY(__ should_not_reach_here());
+}
+
+
+void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
+  address a;
+  if (_info->deoptimize_on_exception()) {
+    // Deoptimize, do not throw the exception, because it is
+    // probably wrong to do it here.
+    a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+  } else {
+    a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+  }
+  ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
+  __ bind(_entry);
+  __ call(a, relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  DEBUG_ONLY(STOP("ImplicitNullCheck");)
+}
+
+
+void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  // Pass the object on stack because all registers must be preserved
+  if (_obj->is_cpu_register()) {
+    ce->verify_reserved_argument_area_size(1);
+    __ str(_obj->as_pointer_register(), Address(SP));
+  } else {
+    assert(_obj->is_illegal(), "should be");
+  }
+  __ call(Runtime1::entry_for(_stub), relocInfo::runtime_call_type);
+  ce->add_call_info_here(_info);
+  DEBUG_ONLY(STOP("SimpleException");)
+}
+
+
+void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+
+  VMRegPair args[5];
+  BasicType signature[5] = { T_OBJECT, T_INT, T_OBJECT, T_INT, T_INT };
+  SharedRuntime::java_calling_convention(signature, args, 5, true);
+
+  Register r[5];
+  r[0] = src()->as_pointer_register();
+  r[1] = src_pos()->as_register();
+  r[2] = dst()->as_pointer_register();
+  r[3] = dst_pos()->as_register();
+  r[4] = length()->as_register();
+
+  for (int i = 0; i < 5; i++) {
+    VMReg arg = args[i].first();
+    if (arg->is_stack()) {
+      __ str(r[i], Address(SP, arg->reg2stack() * VMRegImpl::stack_slot_size));
+    } else {
+      assert(r[i] == arg->as_Register(), "Calling conventions must match");
+    }
+  }
+
+  ce->emit_static_call_stub();
+  if (ce->compilation()->bailed_out()) {
+    return; // CodeCache is full
+  }
+  int ret_addr_offset = __ patchable_call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type);
+  assert(ret_addr_offset == __ offset(), "embedded return address not allowed");
+  ce->add_call_info_here(info());
+  ce->verify_oop_map(info());
+  __ b(_continuation);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+#if INCLUDE_ALL_GCS
+
+void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
+  // At this point we know that marking is in progress.
+  // If do_load() is true then we have to emit the
+  // load of the previous value; otherwise it has already
+  // been loaded into _pre_val.
+
+  __ bind(_entry);
+  assert(pre_val()->is_register(), "Precondition.");
+
+  Register pre_val_reg = pre_val()->as_register();
+
+  if (do_load()) {
+    ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
+  }
+
+  __ cbz(pre_val_reg, _continuation);
+  ce->verify_reserved_argument_area_size(1);
+  __ str(pre_val_reg, Address(SP));
+  __ call(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id), relocInfo::runtime_call_type);
+
+  __ b(_continuation);
+}
+
+void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
+  __ bind(_entry);
+  assert(addr()->is_register(), "Precondition.");
+  assert(new_val()->is_register(), "Precondition.");
+  Register new_val_reg = new_val()->as_register();
+  __ cbz(new_val_reg, _continuation);
+  ce->verify_reserved_argument_area_size(1);
+  __ str(addr()->as_pointer_register(), Address(SP));
+  __ call(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id), relocInfo::runtime_call_type);
+  __ b(_continuation);
+}
+
+#endif // INCLUDE_ALL_GCS
+/////////////////////////////////////////////////////////////////////////////
+
+#undef __
diff --git a/hotspot/src/cpu/arm/vm/c1_Defs_arm.hpp b/hotspot/src/cpu/arm/vm/c1_Defs_arm.hpp
new file mode 100644
index 0000000..e16bb3d
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_Defs_arm.hpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_DEFS_ARM_HPP
+#define CPU_ARM_VM_C1_DEFS_ARM_HPP
+
+// native word offsets from memory address (little endian)
+enum {
+  pd_lo_word_offset_in_bytes = 0,
+  pd_hi_word_offset_in_bytes = BytesPerWord
+};
+
+// explicit rounding operations are required to implement the strictFP mode
+enum {
+  pd_strict_fp_requires_explicit_rounding = false
+};
+
+#ifdef __SOFTFP__
+#define SOFT(n) n
+#define VFP(n)
+#else  // __SOFTFP__
+#define SOFT(n)
+#define VFP(n)        n
+#endif // __SOFTFP__
+
+
+// registers
+enum {
+  pd_nof_cpu_regs_frame_map             = AARCH64_ONLY(33) NOT_AARCH64(16), // number of registers used during code emission
+  pd_nof_caller_save_cpu_regs_frame_map = AARCH64_ONLY(27) NOT_AARCH64(10), // number of registers killed by calls
+  pd_nof_cpu_regs_reg_alloc             = AARCH64_ONLY(27) NOT_AARCH64(10), // number of registers that are visible to register allocator (including Rheap_base which is visible only if compressed pointers are not enabled)
+  pd_nof_cpu_regs_linearscan = pd_nof_cpu_regs_frame_map,                   // number of registers visible to linear scan
+  pd_nof_cpu_regs_processed_in_linearscan = pd_nof_cpu_regs_reg_alloc + 1,  // number of registers processed in linear scan; includes LR as it is used as temporary register in c1_LIRGenerator_arm
+  pd_first_cpu_reg = 0,
+  pd_last_cpu_reg  = pd_nof_cpu_regs_frame_map - 1,
+
+  pd_nof_fpu_regs_frame_map             = VFP(32) SOFT(0),                               // number of float registers used during code emission
+  pd_nof_caller_save_fpu_regs_frame_map = VFP(32) SOFT(0),                               // number of float registers killed by calls
+  pd_nof_fpu_regs_reg_alloc             = AARCH64_ONLY(32) NOT_AARCH64(VFP(30) SOFT(0)), // number of float registers that are visible to register allocator
+  pd_nof_fpu_regs_linearscan            = pd_nof_fpu_regs_frame_map,                     // number of float registers visible to linear scan
+  pd_first_fpu_reg = pd_nof_cpu_regs_frame_map,
+  pd_last_fpu_reg  = pd_first_fpu_reg + pd_nof_fpu_regs_frame_map - 1,
+
+  pd_nof_xmm_regs_linearscan = 0,
+  pd_nof_caller_save_xmm_regs = 0,
+  pd_first_xmm_reg = -1,
+  pd_last_xmm_reg  = -1
+};
+
+
+// encoding of float value in debug info:
+enum {
+  pd_float_saved_as_double = false
+};
+
+#ifdef AARCH64
+#define PATCHED_ADDR 0xff8
+#else
+#define PATCHED_ADDR (204)
+#endif
+#define CARDTABLEMODREF_POST_BARRIER_HELPER
+#define GENERATE_ADDRESS_IS_PREFERRED
+
+#endif // CPU_ARM_VM_C1_DEFS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.cpp b/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.cpp
new file mode 100644
index 0000000..ac826b4
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_FpuStackSim.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "utilities/array.hpp"
+#include "utilities/ostream.hpp"
+
+// Nothing needed here
diff --git a/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.hpp b/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.hpp
new file mode 100644
index 0000000..babd061
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_FpuStackSim_arm.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_FPUSTACKSIM_ARM_HPP
+#define CPU_ARM_VM_C1_FPUSTACKSIM_ARM_HPP
+
+// Nothing needed here
+
+#endif // CPU_ARM_VM_C1_FPUSTACKSIM_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.cpp b/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.cpp
new file mode 100644
index 0000000..55b5fcc
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "c1/c1_LIR.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_arm.inline.hpp"
+
+LIR_Opr FrameMap::R0_opr;
+LIR_Opr FrameMap::R1_opr;
+LIR_Opr FrameMap::R2_opr;
+LIR_Opr FrameMap::R3_opr;
+LIR_Opr FrameMap::R4_opr;
+LIR_Opr FrameMap::R5_opr;
+
+LIR_Opr FrameMap::R0_oop_opr;
+LIR_Opr FrameMap::R1_oop_opr;
+LIR_Opr FrameMap::R2_oop_opr;
+LIR_Opr FrameMap::R3_oop_opr;
+LIR_Opr FrameMap::R4_oop_opr;
+LIR_Opr FrameMap::R5_oop_opr;
+
+LIR_Opr FrameMap::R0_metadata_opr;
+LIR_Opr FrameMap::R1_metadata_opr;
+LIR_Opr FrameMap::R2_metadata_opr;
+LIR_Opr FrameMap::R3_metadata_opr;
+LIR_Opr FrameMap::R4_metadata_opr;
+LIR_Opr FrameMap::R5_metadata_opr;
+
+#ifdef AARCH64
+LIR_Opr FrameMap::ZR_opr;
+#endif // AARCH64
+
+LIR_Opr FrameMap::LR_opr;
+LIR_Opr FrameMap::LR_oop_opr;
+LIR_Opr FrameMap::LR_ptr_opr;
+LIR_Opr FrameMap::FP_opr;
+LIR_Opr FrameMap::SP_opr;
+LIR_Opr FrameMap::Rthread_opr;
+
+LIR_Opr FrameMap::Int_result_opr;
+LIR_Opr FrameMap::Long_result_opr;
+LIR_Opr FrameMap::Object_result_opr;
+LIR_Opr FrameMap::Float_result_opr;
+LIR_Opr FrameMap::Double_result_opr;
+
+LIR_Opr FrameMap::Exception_oop_opr;
+LIR_Opr FrameMap::Exception_pc_opr;
+
+LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0 };
+LIR_Opr FrameMap::_caller_save_fpu_regs[];  // same as initialize to zero
+
+LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) {
+  LIR_Opr opr = LIR_OprFact::illegalOpr;
+  VMReg r_1 = reg->first();
+  VMReg r_2 = reg->second();
+  if (r_1->is_stack()) {
+    int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
+    opr = LIR_OprFact::address(new LIR_Address(SP_opr, st_off, type));
+  } else if (r_1->is_Register()) {
+    Register reg = r_1->as_Register();
+    if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) {
+#ifdef AARCH64
+      assert(r_1->next() == r_2, "should be the same");
+      opr = as_long_opr(reg);
+#else
+      opr = as_long_opr(reg, r_2->as_Register());
+#endif
+    } else if (type == T_OBJECT || type == T_ARRAY) {
+      opr = as_oop_opr(reg);
+    } else if (type == T_METADATA) {
+      opr = as_metadata_opr(reg);
+    } else {
+      // PreferInterpreterNativeStubs should ensure we never need to
+      // handle a long opr passed as R3+stack_slot
+      assert(! r_2->is_stack(), "missing support for ALIGN_WIDE_ARGUMENTS==0");
+      opr = as_opr(reg);
+    }
+  } else if (r_1->is_FloatRegister()) {
+    FloatRegister reg = r_1->as_FloatRegister();
+    opr = type == T_FLOAT ? as_float_opr(reg) : as_double_opr(reg);
+  } else {
+    ShouldNotReachHere();
+  }
+  return opr;
+}
+
+
+void FrameMap::initialize() {
+  if (_init_done) return;
+
+  int i;
+  int rnum = 0;
+
+  // Registers used for allocation
+#ifdef AARCH64
+  assert(Rthread == R28 && Rheap_base == R27 && Rtemp == R16, "change the code here");
+  for (i = 0; i < 16; i++) {
+    map_register(rnum++, as_Register(i));
+  }
+  for (i = 17; i < 28; i++) {
+    map_register(rnum++, as_Register(i));
+  }
+#else
+  assert(Rthread == R10 && Rtemp == R12, "change the code here");
+  for (i = 0; i < 10; i++) {
+    map_register(rnum++, as_Register(i));
+  }
+#endif // AARCH64
+  assert(rnum == pd_nof_cpu_regs_reg_alloc, "should be");
+
+  // Registers not used for allocation
+  map_register(rnum++, LR); // LR register should be listed first, see c1_LinearScan_arm.hpp::is_processed_reg_num.
+  assert(rnum == pd_nof_cpu_regs_processed_in_linearscan, "should be");
+
+  map_register(rnum++, Rtemp);
+  map_register(rnum++, Rthread);
+  map_register(rnum++, FP); // ARM32: R7 or R11
+  map_register(rnum++, SP);
+#ifdef AARCH64
+  map_register(rnum++, ZR);
+#else
+  map_register(rnum++, PC);
+#endif
+  assert(rnum == pd_nof_cpu_regs_frame_map, "should be");
+
+  _init_done = true;
+
+  R0_opr  = as_opr(R0);   R0_oop_opr = as_oop_opr(R0);    R0_metadata_opr = as_metadata_opr(R0);
+  R1_opr  = as_opr(R1);   R1_oop_opr = as_oop_opr(R1);    R1_metadata_opr = as_metadata_opr(R1);
+  R2_opr  = as_opr(R2);   R2_oop_opr = as_oop_opr(R2);    R2_metadata_opr = as_metadata_opr(R2);
+  R3_opr  = as_opr(R3);   R3_oop_opr = as_oop_opr(R3);    R3_metadata_opr = as_metadata_opr(R3);
+  R4_opr  = as_opr(R4);   R4_oop_opr = as_oop_opr(R4);    R4_metadata_opr = as_metadata_opr(R4);
+  R5_opr  = as_opr(R5);   R5_oop_opr = as_oop_opr(R5);    R5_metadata_opr = as_metadata_opr(R5);
+
+#ifdef AARCH64
+  ZR_opr = as_opr(ZR);
+#endif // AARCH64
+
+  LR_opr      = as_opr(LR);
+  LR_oop_opr  = as_oop_opr(LR);
+  LR_ptr_opr  = as_pointer_opr(LR);
+  FP_opr      = as_pointer_opr(FP);
+  SP_opr      = as_pointer_opr(SP);
+  Rthread_opr = as_pointer_opr(Rthread);
+
+  // LIR operands for result
+  Int_result_opr = R0_opr;
+  Object_result_opr = R0_oop_opr;
+#ifdef AARCH64
+  Long_result_opr = as_long_opr(R0);
+  Float_result_opr = as_float_opr(S0);
+  Double_result_opr = as_double_opr(D0);
+#else
+  Long_result_opr = as_long_opr(R0, R1);
+#ifdef __ABI_HARD__
+  Float_result_opr = as_float_opr(S0);
+  Double_result_opr = as_double_opr(D0);
+#else
+  Float_result_opr = LIR_OprFact::single_softfp(0);
+  Double_result_opr = LIR_OprFact::double_softfp(0, 1);
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+  Exception_oop_opr = as_oop_opr(Rexception_obj);
+  Exception_pc_opr = as_opr(Rexception_pc);
+
+  for (i = 0; i < nof_caller_save_cpu_regs(); i++) {
+    _caller_save_cpu_regs[i] = LIR_OprFact::single_cpu(i);
+  }
+  for (i = 0; i < nof_caller_save_fpu_regs; i++) {
+    _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i);
+  }
+}
+
+
+Address FrameMap::make_new_address(ByteSize sp_offset) const {
+  return Address(SP, sp_offset);
+}
+
+LIR_Opr FrameMap::stack_pointer() {
+  return FrameMap::SP_opr;
+}
+
+LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
+  assert(Rmh_SP_save == FP, "Fix register used for saving SP for MethodHandle calls");
+  return FP_opr;
+}
+
+bool FrameMap::validate_frame() {
+  int max_offset = in_bytes(framesize_in_bytes());
+  int java_index = 0;
+  for (int i = 0; i < _incoming_arguments->length(); i++) {
+    LIR_Opr opr = _incoming_arguments->at(i);
+    if (opr->is_stack()) {
+      int arg_offset = _argument_locations->at(java_index);
+      if (arg_offset > max_offset) {
+        max_offset = arg_offset;
+      }
+    }
+    java_index += type2size[opr->type()];
+  }
+  return max_offset < AARCH64_ONLY(16384) NOT_AARCH64(4096); // TODO-AARCH64 check that LIRAssembler does not generate load/store of byte and half-word with SP as address base
+}
+
+VMReg FrameMap::fpu_regname(int n) {
+  return as_FloatRegister(n)->as_VMReg();
+}
diff --git a/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.hpp b/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.hpp
new file mode 100644
index 0000000..efb2acf
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_FrameMap_arm.hpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_FRAMEMAP_ARM_HPP
+#define CPU_ARM_VM_C1_FRAMEMAP_ARM_HPP
+
+ public:
+
+  enum {
+    first_available_sp_in_frame = 0,
+    frame_pad_in_bytes = 2*wordSize      // Account for FP/LR saved at build_frame().
+  };
+
+  static LIR_Opr R0_opr;
+  static LIR_Opr R1_opr;
+  static LIR_Opr R2_opr;
+  static LIR_Opr R3_opr;
+  static LIR_Opr R4_opr;
+  static LIR_Opr R5_opr;
+  // add more predefined register oprs as needed
+
+  static LIR_Opr R0_oop_opr;
+  static LIR_Opr R1_oop_opr;
+  static LIR_Opr R2_oop_opr;
+  static LIR_Opr R3_oop_opr;
+  static LIR_Opr R4_oop_opr;
+  static LIR_Opr R5_oop_opr;
+
+  static LIR_Opr R0_metadata_opr;
+  static LIR_Opr R1_metadata_opr;
+  static LIR_Opr R2_metadata_opr;
+  static LIR_Opr R3_metadata_opr;
+  static LIR_Opr R4_metadata_opr;
+  static LIR_Opr R5_metadata_opr;
+
+#ifdef AARCH64
+  static LIR_Opr ZR_opr;
+#endif // AARCH64
+
+  static LIR_Opr LR_opr;
+  static LIR_Opr LR_oop_opr;
+  static LIR_Opr LR_ptr_opr;
+
+  static LIR_Opr FP_opr;
+  static LIR_Opr SP_opr;
+  static LIR_Opr Rthread_opr;
+
+  static LIR_Opr Int_result_opr;
+  static LIR_Opr Long_result_opr;
+  static LIR_Opr Object_result_opr;
+  static LIR_Opr Float_result_opr;
+  static LIR_Opr Double_result_opr;
+
+  static LIR_Opr Exception_oop_opr;
+  static LIR_Opr Exception_pc_opr;
+
+#ifdef AARCH64
+  static LIR_Opr as_long_opr(Register r) {
+    return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
+  }
+
+  static LIR_Opr as_pointer_opr(Register r) {
+    return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
+  }
+
+  static LIR_Opr as_double_opr(FloatRegister r) {
+    return LIR_OprFact::double_fpu(r->encoding());
+  }
+#else
+  static LIR_Opr as_long_opr(Register r, Register r2) {
+    return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r2));
+  }
+
+  static LIR_Opr as_pointer_opr(Register r) {
+    return LIR_OprFact::single_cpu(cpu_reg2rnr(r));
+  }
+
+  static LIR_Opr as_double_opr(FloatRegister r) {
+    return LIR_OprFact::double_fpu(r->encoding(), r->successor()->encoding());
+  }
+#endif
+
+  static LIR_Opr as_float_opr(FloatRegister r) {
+    return LIR_OprFact::single_fpu(r->encoding());
+  }
+
+  static VMReg fpu_regname(int n);
+
+  static bool is_caller_save_register(LIR_Opr opr) {
+    return true;
+  }
+
+  static int adjust_reg_range(int range) {
+    // Reduce the number of available regs (to free Rheap_base) in case of compressed oops
+    if (UseCompressedOops || UseCompressedClassPointers) return range - 1;
+    return range;
+  }
+
+  static int nof_caller_save_cpu_regs() {
+    return adjust_reg_range(pd_nof_caller_save_cpu_regs_frame_map);
+  }
+
+  static int last_cpu_reg() {
+    return pd_last_cpu_reg;
+  }
+
+#endif // CPU_ARM_VM_C1_FRAMEMAP_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp
new file mode 100644
index 0000000..4d45cfb
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.cpp
@@ -0,0 +1,3608 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_Compilation.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "c1/c1_ValueStack.hpp"
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciInstance.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_arm.inline.hpp"
+
+#define __ _masm->
+
+// Note: Rtemp usage is this file should not impact C2 and should be
+// correct as long as it is not implicitly used in lower layers (the
+// arm [macro]assembler) and used with care in the other C1 specific
+// files.
+
+bool LIR_Assembler::is_small_constant(LIR_Opr opr) {
+  ShouldNotCallThis(); // Not used on ARM
+  return false;
+}
+
+
+LIR_Opr LIR_Assembler::receiverOpr() {
+  // The first register in Java calling conventions
+  return FrameMap::R0_oop_opr;
+}
+
+LIR_Opr LIR_Assembler::osrBufferPointer() {
+  return FrameMap::as_pointer_opr(R0);
+}
+
+#ifndef PRODUCT
+void LIR_Assembler::verify_reserved_argument_area_size(int args_count) {
+  assert(args_count * wordSize <= frame_map()->reserved_argument_area_size(), "not enough space for arguments");
+}
+#endif // !PRODUCT
+
+void LIR_Assembler::store_parameter(jint c, int offset_from_sp_in_words) {
+  assert(offset_from_sp_in_words >= 0, "invalid offset from sp");
+  int offset_from_sp_in_bytes = offset_from_sp_in_words * BytesPerWord;
+  assert(offset_from_sp_in_bytes < frame_map()->reserved_argument_area_size(), "not enough space");
+  __ mov_slow(Rtemp, c);
+  __ str(Rtemp, Address(SP, offset_from_sp_in_bytes));
+}
+
+void LIR_Assembler::store_parameter(Metadata* m, int offset_from_sp_in_words) {
+  assert(offset_from_sp_in_words >= 0, "invalid offset from sp");
+  int offset_from_sp_in_bytes = offset_from_sp_in_words * BytesPerWord;
+  assert(offset_from_sp_in_bytes < frame_map()->reserved_argument_area_size(), "not enough space");
+  __ mov_metadata(Rtemp, m);
+  __ str(Rtemp, Address(SP, offset_from_sp_in_bytes));
+}
+
+//--------------fpu register translations-----------------------
+
+
+void LIR_Assembler::set_24bit_FPU() {
+  ShouldNotReachHere();
+}
+
+void LIR_Assembler::reset_FPU() {
+  ShouldNotReachHere();
+}
+
+void LIR_Assembler::fpop() {
+  Unimplemented();
+}
+
+void LIR_Assembler::fxch(int i) {
+  Unimplemented();
+}
+
+void LIR_Assembler::fld(int i) {
+  Unimplemented();
+}
+
+void LIR_Assembler::ffree(int i) {
+  Unimplemented();
+}
+
+void LIR_Assembler::breakpoint() {
+  __ breakpoint();
+}
+
+void LIR_Assembler::push(LIR_Opr opr) {
+  Unimplemented();
+}
+
+void LIR_Assembler::pop(LIR_Opr opr) {
+  Unimplemented();
+}
+
+//-------------------------------------------
+Address LIR_Assembler::as_Address(LIR_Address* addr) {
+  Register base = addr->base()->as_pointer_register();
+
+#ifdef AARCH64
+  int align = exact_log2(type2aelembytes(addr->type(), true));
+#endif
+
+  if (addr->index()->is_illegal() || addr->index()->is_constant()) {
+    int offset = addr->disp();
+    if (addr->index()->is_constant()) {
+      offset += addr->index()->as_constant_ptr()->as_jint() << addr->scale();
+    }
+
+#ifdef AARCH64
+    if (!Assembler::is_unsigned_imm_in_range(offset, 12, align) && !Assembler::is_imm_in_range(offset, 9, 0)) {
+      BAILOUT_("offset not in range", Address(base));
+    }
+    assert(UseUnalignedAccesses || (offset & right_n_bits(align)) == 0, "offset should be aligned");
+#else
+    if ((offset <= -4096) || (offset >= 4096)) {
+      BAILOUT_("offset not in range", Address(base));
+    }
+#endif // AARCH64
+
+    return Address(base, offset);
+
+  } else {
+    assert(addr->disp() == 0, "can't have both");
+    int scale = addr->scale();
+
+#ifdef AARCH64
+    assert((scale == 0) || (scale == align), "scale should be zero or equal to embedded shift");
+
+    bool is_index_extended = (addr->index()->type() == T_INT);
+    if (is_index_extended) {
+      assert(addr->index()->is_single_cpu(), "should be");
+      return Address(base, addr->index()->as_register(), ex_sxtw, scale);
+    } else {
+      assert(addr->index()->is_double_cpu(), "should be");
+      return Address(base, addr->index()->as_register_lo(), ex_lsl, scale);
+    }
+#else
+    assert(addr->index()->is_single_cpu(), "should be");
+    return scale >= 0 ? Address(base, addr->index()->as_register(), lsl, scale) :
+                        Address(base, addr->index()->as_register(), lsr, -scale);
+#endif // AARCH64
+  }
+}
+
+Address LIR_Assembler::as_Address_hi(LIR_Address* addr) {
+#ifdef AARCH64
+  ShouldNotCallThis(); // Not used on AArch64
+  return Address();
+#else
+  Address base = as_Address(addr);
+  assert(base.index() == noreg, "must be");
+  if (base.disp() + BytesPerWord >= 4096) { BAILOUT_("offset not in range", Address(base.base(),0)); }
+  return Address(base.base(), base.disp() + BytesPerWord);
+#endif // AARCH64
+}
+
+Address LIR_Assembler::as_Address_lo(LIR_Address* addr) {
+#ifdef AARCH64
+  ShouldNotCallThis(); // Not used on AArch64
+  return Address();
+#else
+  return as_Address(addr);
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::osr_entry() {
+  offsets()->set_value(CodeOffsets::OSR_Entry, code_offset());
+  BlockBegin* osr_entry = compilation()->hir()->osr_entry();
+  ValueStack* entry_state = osr_entry->end()->state();
+  int number_of_locks = entry_state->locks_size();
+
+  __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes());
+  Register OSR_buf = osrBufferPointer()->as_pointer_register();
+
+  assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
+  int monitor_offset = (method()->max_locals() + 2 * (number_of_locks - 1)) * BytesPerWord;
+  for (int i = 0; i < number_of_locks; i++) {
+    int slot_offset = monitor_offset - (i * 2 * BytesPerWord);
+    __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord));
+    __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord));
+    __ str(R1, frame_map()->address_for_monitor_lock(i));
+    __ str(R2, frame_map()->address_for_monitor_object(i));
+  }
+}
+
+
+int LIR_Assembler::check_icache() {
+  Register receiver = LIR_Assembler::receiverOpr()->as_register();
+  int offset = __ offset();
+  __ inline_cache_check(receiver, Ricklass);
+  return offset;
+}
+
+
+void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo* info) {
+  jobject o = (jobject)Universe::non_oop_word();
+  int index = __ oop_recorder()->allocate_oop_index(o);
+
+  PatchingStub* patch = new PatchingStub(_masm, patching_id(info), index);
+
+  __ patchable_mov_oop(reg, o, index);
+  patching_epilog(patch, lir_patch_normal, reg, info);
+}
+
+
+void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo* info) {
+  Metadata* o = (Metadata*)Universe::non_oop_word();
+  int index = __ oop_recorder()->allocate_metadata_index(o);
+  PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index);
+
+  __ patchable_mov_metadata(reg, o, index);
+  patching_epilog(patch, lir_patch_normal, reg, info);
+}
+
+
+int LIR_Assembler::initial_frame_size_in_bytes() const {
+  // Subtracts two words to account for return address and link
+  return frame_map()->framesize()*VMRegImpl::stack_slot_size - 2*wordSize;
+}
+
+
+int LIR_Assembler::emit_exception_handler() {
+  // TODO: ARM
+  __ nop(); // See comments in other ports
+
+  address handler_base = __ start_a_stub(exception_handler_size());
+  if (handler_base == NULL) {
+    bailout("exception handler overflow");
+    return -1;
+  }
+
+  int offset = code_offset();
+
+  // check that there is really an exception
+  __ verify_not_null_oop(Rexception_obj);
+
+  __ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
+  __ should_not_reach_here();
+
+  assert(code_offset() - offset <= exception_handler_size(), "overflow");
+  __ end_a_stub();
+
+  return offset;
+}
+
+// Emit the code to remove the frame from the stack in the exception
+// unwind path.
+int LIR_Assembler::emit_unwind_handler() {
+#ifndef PRODUCT
+  if (CommentedAssembly) {
+    _masm->block_comment("Unwind handler");
+  }
+#endif
+
+  int offset = code_offset();
+
+  // Fetch the exception from TLS and clear out exception related thread state
+  Register zero = __ zero_register(Rtemp);
+  __ ldr(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ str(zero, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ str(zero, Address(Rthread, JavaThread::exception_pc_offset()));
+
+  __ bind(_unwind_handler_entry);
+  __ verify_not_null_oop(Rexception_obj);
+
+  // Preform needed unlocking
+  MonitorExitStub* stub = NULL;
+  if (method()->is_synchronized()) {
+    monitor_address(0, FrameMap::R0_opr);
+    stub = new MonitorExitStub(FrameMap::R0_opr, true, 0);
+    __ unlock_object(R2, R1, R0, Rtemp, *stub->entry());
+    __ bind(*stub->continuation());
+  }
+
+  // remove the activation and dispatch to the unwind handler
+  __ remove_frame(initial_frame_size_in_bytes()); // restores FP and LR
+  __ jump(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type, Rtemp);
+
+  // Emit the slow path assembly
+  if (stub != NULL) {
+    stub->emit_code(this);
+  }
+
+  return offset;
+}
+
+
+int LIR_Assembler::emit_deopt_handler() {
+  address handler_base = __ start_a_stub(deopt_handler_size());
+  if (handler_base == NULL) {
+    bailout("deopt handler overflow");
+    return -1;
+  }
+
+  int offset = code_offset();
+
+  __ mov_relative_address(LR, __ pc());
+#ifdef AARCH64
+  __ raw_push(LR, LR);
+  __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, Rtemp);
+#else
+  __ push(LR); // stub expects LR to be saved
+  __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);
+#endif // AARCH64
+
+  assert(code_offset() - offset <= deopt_handler_size(), "overflow");
+  __ end_a_stub();
+
+  return offset;
+}
+
+
+void LIR_Assembler::return_op(LIR_Opr result) {
+  // Pop the frame before safepoint polling
+  __ remove_frame(initial_frame_size_in_bytes());
+
+  // mov_slow here is usually one or two instruction
+  // TODO-AARCH64 3 instructions on AArch64, so try to load polling page by ldr_literal
+  __ mov_address(Rtemp, os::get_polling_page(), symbolic_Relocation::polling_page_reference);
+  __ relocate(relocInfo::poll_return_type);
+  __ ldr(Rtemp, Address(Rtemp));
+  __ ret();
+}
+
+
+int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
+  __ mov_address(Rtemp, os::get_polling_page(), symbolic_Relocation::polling_page_reference);
+  if (info != NULL) {
+    add_debug_info_for_branch(info);
+  }
+  int offset = __ offset();
+  __ relocate(relocInfo::poll_type);
+  __ ldr(Rtemp, Address(Rtemp));
+  return offset;
+}
+
+
+void LIR_Assembler::move_regs(Register from_reg, Register to_reg) {
+  if (from_reg != to_reg) {
+    __ mov(to_reg, from_reg);
+  }
+}
+
+void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) {
+  assert(src->is_constant() && dest->is_register(), "must be");
+  LIR_Const* c = src->as_constant_ptr();
+
+  switch (c->type()) {
+    case T_ADDRESS:
+    case T_INT:
+      assert(patch_code == lir_patch_none, "no patching handled here");
+      __ mov_slow(dest->as_register(), c->as_jint());
+      break;
+
+    case T_LONG:
+      assert(patch_code == lir_patch_none, "no patching handled here");
+#ifdef AARCH64
+      __ mov_slow(dest->as_pointer_register(), (intptr_t)c->as_jlong());
+#else
+      __ mov_slow(dest->as_register_lo(), c->as_jint_lo());
+      __ mov_slow(dest->as_register_hi(), c->as_jint_hi());
+#endif // AARCH64
+      break;
+
+    case T_OBJECT:
+      if (patch_code == lir_patch_none) {
+        __ mov_oop(dest->as_register(), c->as_jobject());
+      } else {
+        jobject2reg_with_patching(dest->as_register(), info);
+      }
+      break;
+
+    case T_METADATA:
+      if (patch_code == lir_patch_none) {
+        __ mov_metadata(dest->as_register(), c->as_metadata());
+      } else {
+        klass2reg_with_patching(dest->as_register(), info);
+      }
+      break;
+
+    case T_FLOAT:
+      if (dest->is_single_fpu()) {
+        __ mov_float(dest->as_float_reg(), c->as_jfloat());
+      } else {
+#ifdef AARCH64
+        ShouldNotReachHere();
+#else
+        // Simple getters can return float constant directly into r0
+        __ mov_slow(dest->as_register(), c->as_jint_bits());
+#endif // AARCH64
+      }
+      break;
+
+    case T_DOUBLE:
+      if (dest->is_double_fpu()) {
+        __ mov_double(dest->as_double_reg(), c->as_jdouble());
+      } else {
+#ifdef AARCH64
+        ShouldNotReachHere();
+#else
+        // Simple getters can return double constant directly into r1r0
+        __ mov_slow(dest->as_register_lo(), c->as_jint_lo_bits());
+        __ mov_slow(dest->as_register_hi(), c->as_jint_hi_bits());
+#endif // AARCH64
+      }
+      break;
+
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
+  assert(src->is_constant(), "must be");
+  assert(dest->is_stack(), "must be");
+  LIR_Const* c = src->as_constant_ptr();
+
+  switch (c->type()) {
+    case T_INT:  // fall through
+    case T_FLOAT:
+      __ mov_slow(Rtemp, c->as_jint_bits());
+      __ str_32(Rtemp, frame_map()->address_for_slot(dest->single_stack_ix()));
+      break;
+
+    case T_ADDRESS:
+      __ mov_slow(Rtemp, c->as_jint());
+      __ str(Rtemp, frame_map()->address_for_slot(dest->single_stack_ix()));
+      break;
+
+    case T_OBJECT:
+      __ mov_oop(Rtemp, c->as_jobject());
+      __ str(Rtemp, frame_map()->address_for_slot(dest->single_stack_ix()));
+      break;
+
+    case T_LONG:  // fall through
+    case T_DOUBLE:
+#ifdef AARCH64
+      __ mov_slow(Rtemp, c->as_jlong_bits());
+      __ str(Rtemp, frame_map()->address_for_slot(dest->double_stack_ix()));
+#else
+      __ mov_slow(Rtemp, c->as_jint_lo_bits());
+      __ str(Rtemp, frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes));
+      if (c->as_jint_hi_bits() != c->as_jint_lo_bits()) {
+        __ mov_slow(Rtemp, c->as_jint_hi_bits());
+      }
+      __ str(Rtemp, frame_map()->address_for_slot(dest->double_stack_ix(), hi_word_offset_in_bytes));
+#endif // AARCH64
+      break;
+
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type,
+                              CodeEmitInfo* info, bool wide) {
+#ifdef AARCH64
+  assert((src->as_constant_ptr()->type() == T_OBJECT && src->as_constant_ptr()->as_jobject() == NULL) ||
+         (src->as_constant_ptr()->type() == T_INT && src->as_constant_ptr()->as_jint() == 0) ||
+         (src->as_constant_ptr()->type() == T_LONG && src->as_constant_ptr()->as_jlong() == 0) ||
+         (src->as_constant_ptr()->type() == T_FLOAT && src->as_constant_ptr()->as_jint_bits() == 0) ||
+         (src->as_constant_ptr()->type() == T_DOUBLE && src->as_constant_ptr()->as_jlong_bits() == 0),
+        "cannot handle otherwise");
+  assert(dest->as_address_ptr()->type() == type, "should be");
+
+  Address addr = as_Address(dest->as_address_ptr());
+  int null_check_offset = code_offset();
+  switch (type) {
+    case T_OBJECT:  // fall through
+    case T_ARRAY:
+        if (UseCompressedOops && !wide) {
+          __ str_w(ZR, addr);
+        } else {
+          __ str(ZR, addr);
+        }
+        break;
+    case T_ADDRESS: // fall through
+    case T_DOUBLE:  // fall through
+    case T_LONG:    __ str(ZR, addr);   break;
+    case T_FLOAT:   // fall through
+    case T_INT:     __ str_w(ZR, addr); break;
+    case T_BOOLEAN: // fall through
+    case T_BYTE:    __ strb(ZR, addr);  break;
+    case T_CHAR:    // fall through
+    case T_SHORT:   __ strh(ZR, addr);  break;
+    default: ShouldNotReachHere();
+  }
+#else
+  assert((src->as_constant_ptr()->type() == T_OBJECT && src->as_constant_ptr()->as_jobject() == NULL),"cannot handle otherwise");
+  __ mov(Rtemp, 0);
+
+  int null_check_offset = code_offset();
+  __ str(Rtemp, as_Address(dest->as_address_ptr()));
+#endif // AARCH64
+
+  if (info != NULL) {
+#ifndef AARCH64
+    assert(false, "arm32 didn't support this before, investigate if bug");
+#endif
+    add_debug_info_for_null_check(null_check_offset, info);
+  }
+}
+
+void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) {
+  assert(src->is_register() && dest->is_register(), "must be");
+
+  if (src->is_single_cpu()) {
+    if (dest->is_single_cpu()) {
+      move_regs(src->as_register(), dest->as_register());
+#ifdef AARCH64
+    } else if (dest->is_double_cpu()) {
+      assert ((src->type() == T_OBJECT) || (src->type() == T_ARRAY) || (src->type() == T_ADDRESS), "invalid src type");
+      move_regs(src->as_register(), dest->as_register_lo());
+#else
+    } else if (dest->is_single_fpu()) {
+      __ fmsr(dest->as_float_reg(), src->as_register());
+#endif // AARCH64
+    } else {
+      ShouldNotReachHere();
+    }
+  } else if (src->is_double_cpu()) {
+#ifdef AARCH64
+    move_regs(src->as_register_lo(), dest->as_register_lo());
+#else
+    if (dest->is_double_cpu()) {
+      __ long_move(dest->as_register_lo(), dest->as_register_hi(), src->as_register_lo(), src->as_register_hi());
+    } else {
+      __ fmdrr(dest->as_double_reg(), src->as_register_lo(), src->as_register_hi());
+    }
+#endif // AARCH64
+  } else if (src->is_single_fpu()) {
+    if (dest->is_single_fpu()) {
+      __ mov_float(dest->as_float_reg(), src->as_float_reg());
+    } else if (dest->is_single_cpu()) {
+      __ mov_fpr2gpr_float(dest->as_register(), src->as_float_reg());
+    } else {
+      ShouldNotReachHere();
+    }
+  } else if (src->is_double_fpu()) {
+    if (dest->is_double_fpu()) {
+      __ mov_double(dest->as_double_reg(), src->as_double_reg());
+    } else if (dest->is_double_cpu()) {
+#ifdef AARCH64
+      __ fmov_xd(dest->as_register_lo(), src->as_double_reg());
+#else
+      __ fmrrd(dest->as_register_lo(), dest->as_register_hi(), src->as_double_reg());
+#endif // AARCH64
+    } else {
+      ShouldNotReachHere();
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type, bool pop_fpu_stack) {
+  assert(src->is_register(), "should not call otherwise");
+  assert(dest->is_stack(), "should not call otherwise");
+
+  Address addr = dest->is_single_word() ?
+    frame_map()->address_for_slot(dest->single_stack_ix()) :
+    frame_map()->address_for_slot(dest->double_stack_ix());
+
+#ifndef AARCH64
+  assert(lo_word_offset_in_bytes == 0 && hi_word_offset_in_bytes == 4, "little ending");
+  if (src->is_single_fpu() || src->is_double_fpu()) {
+    if (addr.disp() >= 1024) { BAILOUT("Too exotic case to handle here"); }
+  }
+#endif // !AARCH64
+
+  if (src->is_single_cpu()) {
+    switch (type) {
+      case T_OBJECT:
+      case T_ARRAY:    __ verify_oop(src->as_register());   // fall through
+      case T_ADDRESS:
+      case T_METADATA: __ str(src->as_register(), addr);    break;
+      case T_FLOAT:    // used in intBitsToFloat intrinsic implementation, fall through
+      case T_INT:      __ str_32(src->as_register(), addr); break;
+      default:
+        ShouldNotReachHere();
+    }
+  } else if (src->is_double_cpu()) {
+    __ str(src->as_register_lo(), addr);
+#ifndef AARCH64
+    __ str(src->as_register_hi(), frame_map()->address_for_slot(dest->double_stack_ix(), hi_word_offset_in_bytes));
+#endif // !AARCH64
+  } else if (src->is_single_fpu()) {
+    __ str_float(src->as_float_reg(), addr);
+  } else if (src->is_double_fpu()) {
+    __ str_double(src->as_double_reg(), addr);
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type,
+                            LIR_PatchCode patch_code, CodeEmitInfo* info,
+                            bool pop_fpu_stack, bool wide,
+                            bool unaligned) {
+  LIR_Address* to_addr = dest->as_address_ptr();
+  Register base_reg = to_addr->base()->as_pointer_register();
+  const bool needs_patching = (patch_code != lir_patch_none);
+
+  PatchingStub* patch = NULL;
+  if (needs_patching) {
+#ifdef AARCH64
+    // Same alignment of reg2mem code and PatchingStub code. Required to make copied bind_literal() code properly aligned.
+    __ align(wordSize);
+#endif
+    patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+#ifdef AARCH64
+    // Extra nop for MT safe patching
+    __ nop();
+#endif // AARCH64
+  }
+
+  int null_check_offset = code_offset();
+
+  switch (type) {
+    case T_ARRAY:
+    case T_OBJECT:
+      if (UseCompressedOops && !wide) {
+#ifdef AARCH64
+        const Register temp_src = Rtemp;
+        assert_different_registers(temp_src, src->as_register());
+        __ encode_heap_oop(temp_src, src->as_register());
+        null_check_offset = code_offset();
+        __ str_32(temp_src, as_Address(to_addr));
+#else
+        ShouldNotReachHere();
+#endif // AARCH64
+      } else {
+        __ str(src->as_register(), as_Address(to_addr));
+      }
+      break;
+
+    case T_ADDRESS:
+#ifdef AARCH64
+    case T_LONG:
+#endif // AARCH64
+      __ str(src->as_pointer_register(), as_Address(to_addr));
+      break;
+
+    case T_BYTE:
+    case T_BOOLEAN:
+      __ strb(src->as_register(), as_Address(to_addr));
+      break;
+
+    case T_CHAR:
+    case T_SHORT:
+      __ strh(src->as_register(), as_Address(to_addr));
+      break;
+
+    case T_INT:
+#ifdef __SOFTFP__
+    case T_FLOAT:
+#endif // __SOFTFP__
+      __ str_32(src->as_register(), as_Address(to_addr));
+      break;
+
+#ifdef AARCH64
+
+    case T_FLOAT:
+      __ str_s(src->as_float_reg(), as_Address(to_addr));
+      break;
+
+    case T_DOUBLE:
+      __ str_d(src->as_double_reg(), as_Address(to_addr));
+      break;
+
+#else // AARCH64
+
+#ifdef __SOFTFP__
+    case T_DOUBLE:
+#endif // __SOFTFP__
+    case T_LONG: {
+      Register from_lo = src->as_register_lo();
+      Register from_hi = src->as_register_hi();
+      if (to_addr->index()->is_register()) {
+        assert(to_addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        assert(to_addr->disp() == 0, "Not yet supporting both");
+        __ add(Rtemp, base_reg, to_addr->index()->as_register());
+        base_reg = Rtemp;
+        __ str(from_lo, Address(Rtemp));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_low, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_high;
+        }
+        __ str(from_hi, Address(Rtemp, BytesPerWord));
+      } else if (base_reg == from_lo) {
+        __ str(from_hi, as_Address_hi(to_addr));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_high, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_low;
+        }
+        __ str(from_lo, as_Address_lo(to_addr));
+      } else {
+        __ str(from_lo, as_Address_lo(to_addr));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_low, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_high;
+        }
+        __ str(from_hi, as_Address_hi(to_addr));
+      }
+      break;
+    }
+
+#ifndef __SOFTFP__
+    case T_FLOAT:
+      if (to_addr->index()->is_register()) {
+        assert(to_addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        __ add(Rtemp, base_reg, to_addr->index()->as_register());
+        if ((to_addr->disp() <= -4096) || (to_addr->disp() >= 4096)) { BAILOUT("offset not in range"); }
+        __ fsts(src->as_float_reg(), Address(Rtemp, to_addr->disp()));
+      } else {
+        __ fsts(src->as_float_reg(), as_Address(to_addr));
+      }
+      break;
+
+    case T_DOUBLE:
+      if (to_addr->index()->is_register()) {
+        assert(to_addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        __ add(Rtemp, base_reg, to_addr->index()->as_register());
+        if ((to_addr->disp() <= -4096) || (to_addr->disp() >= 4096)) { BAILOUT("offset not in range"); }
+        __ fstd(src->as_double_reg(), Address(Rtemp, to_addr->disp()));
+      } else {
+        __ fstd(src->as_double_reg(), as_Address(to_addr));
+      }
+      break;
+#endif // __SOFTFP__
+
+#endif // AARCH64
+
+    default:
+      ShouldNotReachHere();
+  }
+
+  if (info != NULL) {
+    add_debug_info_for_null_check(null_check_offset, info);
+  }
+
+  if (patch != NULL) {
+    // Offset embeedded into LDR/STR instruction may appear not enough
+    // to address a field. So, provide a space for one more instruction
+    // that will deal with larger offsets.
+    __ nop();
+    patching_epilog(patch, patch_code, base_reg, info);
+  }
+}
+
+
+void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) {
+  assert(src->is_stack(), "should not call otherwise");
+  assert(dest->is_register(), "should not call otherwise");
+
+  Address addr = src->is_single_word() ?
+    frame_map()->address_for_slot(src->single_stack_ix()) :
+    frame_map()->address_for_slot(src->double_stack_ix());
+
+#ifndef AARCH64
+  assert(lo_word_offset_in_bytes == 0 && hi_word_offset_in_bytes == 4, "little ending");
+  if (dest->is_single_fpu() || dest->is_double_fpu()) {
+    if (addr.disp() >= 1024) { BAILOUT("Too exotic case to handle here"); }
+  }
+#endif // !AARCH64
+
+  if (dest->is_single_cpu()) {
+    switch (type) {
+      case T_OBJECT:
+      case T_ARRAY:
+      case T_ADDRESS:
+      case T_METADATA: __ ldr(dest->as_register(), addr); break;
+      case T_FLOAT:    // used in floatToRawIntBits intrinsic implemenation
+      case T_INT:      __ ldr_u32(dest->as_register(), addr); break;
+      default:
+        ShouldNotReachHere();
+    }
+    if ((type == T_OBJECT) || (type == T_ARRAY)) {
+      __ verify_oop(dest->as_register());
+    }
+  } else if (dest->is_double_cpu()) {
+    __ ldr(dest->as_register_lo(), addr);
+#ifndef AARCH64
+    __ ldr(dest->as_register_hi(), frame_map()->address_for_slot(src->double_stack_ix(), hi_word_offset_in_bytes));
+#endif // !AARCH64
+  } else if (dest->is_single_fpu()) {
+    __ ldr_float(dest->as_float_reg(), addr);
+  } else if (dest->is_double_fpu()) {
+    __ ldr_double(dest->as_double_reg(), addr);
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) {
+  if (src->is_single_stack()) {
+    switch (src->type()) {
+      case T_OBJECT:
+      case T_ARRAY:
+      case T_ADDRESS:
+      case T_METADATA:
+        __ ldr(Rtemp, frame_map()->address_for_slot(src->single_stack_ix()));
+        __ str(Rtemp, frame_map()->address_for_slot(dest->single_stack_ix()));
+        break;
+
+      case T_INT:
+      case T_FLOAT:
+        __ ldr_u32(Rtemp, frame_map()->address_for_slot(src->single_stack_ix()));
+        __ str_32(Rtemp, frame_map()->address_for_slot(dest->single_stack_ix()));
+        break;
+
+      default:
+        ShouldNotReachHere();
+    }
+  } else {
+    assert(src->is_double_stack(), "must be");
+    __ ldr(Rtemp, frame_map()->address_for_slot(src->double_stack_ix(), lo_word_offset_in_bytes));
+    __ str(Rtemp, frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes));
+#ifdef AARCH64
+    assert(lo_word_offset_in_bytes == 0, "adjust this code");
+#else
+    __ ldr(Rtemp, frame_map()->address_for_slot(src->double_stack_ix(), hi_word_offset_in_bytes));
+    __ str(Rtemp, frame_map()->address_for_slot(dest->double_stack_ix(), hi_word_offset_in_bytes));
+#endif // AARCH64
+  }
+}
+
+
+void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type,
+                            LIR_PatchCode patch_code, CodeEmitInfo* info,
+                            bool wide, bool unaligned) {
+  assert(src->is_address(), "should not call otherwise");
+  assert(dest->is_register(), "should not call otherwise");
+  LIR_Address* addr = src->as_address_ptr();
+
+  Register base_reg = addr->base()->as_pointer_register();
+
+  PatchingStub* patch = NULL;
+  if (patch_code != lir_patch_none) {
+    patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+#ifdef AARCH64
+    // Extra nop for MT safe patching
+    __ nop();
+#endif // AARCH64
+  }
+  if (info != NULL) {
+    add_debug_info_for_null_check_here(info);
+  }
+
+  switch (type) {
+    case T_OBJECT:  // fall through
+    case T_ARRAY:
+      if (UseCompressedOops && !wide) {
+        __ ldr_u32(dest->as_register(), as_Address(addr));
+      } else {
+        __ ldr(dest->as_register(), as_Address(addr));
+      }
+      break;
+
+    case T_ADDRESS:
+      if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) {
+        __ ldr_u32(dest->as_pointer_register(), as_Address(addr));
+      } else {
+        __ ldr(dest->as_pointer_register(), as_Address(addr));
+      }
+      break;
+
+#ifdef AARCH64
+    case T_LONG:
+#else
+    case T_INT:
+#ifdef __SOFTFP__
+    case T_FLOAT:
+#endif // __SOFTFP__
+#endif // AARCH64
+      __ ldr(dest->as_pointer_register(), as_Address(addr));
+      break;
+
+    case T_BOOLEAN:
+      __ ldrb(dest->as_register(), as_Address(addr));
+      break;
+
+    case T_BYTE:
+      __ ldrsb(dest->as_register(), as_Address(addr));
+      break;
+
+    case T_CHAR:
+      __ ldrh(dest->as_register(), as_Address(addr));
+      break;
+
+    case T_SHORT:
+      __ ldrsh(dest->as_register(), as_Address(addr));
+      break;
+
+#ifdef AARCH64
+
+    case T_INT:
+      __ ldr_w(dest->as_register(), as_Address(addr));
+      break;
+
+    case T_FLOAT:
+      __ ldr_s(dest->as_float_reg(), as_Address(addr));
+      break;
+
+    case T_DOUBLE:
+      __ ldr_d(dest->as_double_reg(), as_Address(addr));
+      break;
+
+#else // AARCH64
+
+#ifdef __SOFTFP__
+    case T_DOUBLE:
+#endif // __SOFTFP__
+    case T_LONG: {
+      Register to_lo = dest->as_register_lo();
+      Register to_hi = dest->as_register_hi();
+      if (addr->index()->is_register()) {
+        assert(addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        assert(addr->disp() == 0, "Not yet supporting both");
+        __ add(Rtemp, base_reg, addr->index()->as_register());
+        base_reg = Rtemp;
+        __ ldr(to_lo, Address(Rtemp));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_low, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_high;
+        }
+        __ ldr(to_hi, Address(Rtemp, BytesPerWord));
+      } else if (base_reg == to_lo) {
+        __ ldr(to_hi, as_Address_hi(addr));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_high, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_low;
+        }
+        __ ldr(to_lo, as_Address_lo(addr));
+      } else {
+        __ ldr(to_lo, as_Address_lo(addr));
+        if (patch != NULL) {
+          patching_epilog(patch, lir_patch_low, base_reg, info);
+          patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+          patch_code = lir_patch_high;
+        }
+        __ ldr(to_hi, as_Address_hi(addr));
+      }
+      break;
+    }
+
+#ifndef __SOFTFP__
+    case T_FLOAT:
+      if (addr->index()->is_register()) {
+        assert(addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        __ add(Rtemp, base_reg, addr->index()->as_register());
+        if ((addr->disp() <= -4096) || (addr->disp() >= 4096)) { BAILOUT("offset not in range"); }
+        __ flds(dest->as_float_reg(), Address(Rtemp, addr->disp()));
+      } else {
+        __ flds(dest->as_float_reg(), as_Address(addr));
+      }
+      break;
+
+    case T_DOUBLE:
+      if (addr->index()->is_register()) {
+        assert(addr->scale() == LIR_Address::times_1,"Unexpected scaled register");
+        __ add(Rtemp, base_reg, addr->index()->as_register());
+        if ((addr->disp() <= -4096) || (addr->disp() >= 4096)) { BAILOUT("offset not in range"); }
+        __ fldd(dest->as_double_reg(), Address(Rtemp, addr->disp()));
+      } else {
+        __ fldd(dest->as_double_reg(), as_Address(addr));
+      }
+      break;
+#endif // __SOFTFP__
+
+#endif // AARCH64
+
+    default:
+      ShouldNotReachHere();
+  }
+
+  if (patch != NULL) {
+    // Offset embeedded into LDR/STR instruction may appear not enough
+    // to address a field. So, provide a space for one more instruction
+    // that will deal with larger offsets.
+    __ nop();
+    patching_epilog(patch, patch_code, base_reg, info);
+  }
+
+#ifdef AARCH64
+  switch (type) {
+    case T_ARRAY:
+    case T_OBJECT:
+      if (UseCompressedOops && !wide) {
+        __ decode_heap_oop(dest->as_register());
+      }
+      __ verify_oop(dest->as_register());
+      break;
+
+    case T_ADDRESS:
+      if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) {
+        __ decode_klass_not_null(dest->as_register());
+      }
+      break;
+  }
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::emit_op3(LIR_Op3* op) {
+  bool is_32 = op->result_opr()->is_single_cpu();
+
+  if (op->code() == lir_idiv && op->in_opr2()->is_constant() && is_32) {
+    int c = op->in_opr2()->as_constant_ptr()->as_jint();
+    assert(is_power_of_2(c), "non power-of-2 constant should be put in a register");
+
+    Register left = op->in_opr1()->as_register();
+    Register dest = op->result_opr()->as_register();
+    if (c == 1) {
+      __ mov(dest, left);
+    } else if (c == 2) {
+      __ add_32(dest, left, AsmOperand(left, lsr, 31));
+      __ asr_32(dest, dest, 1);
+    } else if (c != (int) 0x80000000) {
+      int power = log2_intptr(c);
+      __ asr_32(Rtemp, left, 31);
+      __ add_32(dest, left, AsmOperand(Rtemp, lsr, 32-power)); // dest = left + (left < 0 ? 2^power - 1 : 0);
+      __ asr_32(dest, dest, power);                            // dest = dest >>> power;
+    } else {
+      // x/0x80000000 is a special case, since dividend is a power of two, but is negative.
+      // The only possible result values are 0 and 1, with 1 only for dividend == divisor == 0x80000000.
+      __ cmp_32(left, c);
+#ifdef AARCH64
+      __ cset(dest, eq);
+#else
+      __ mov(dest, 0, ne);
+      __ mov(dest, 1, eq);
+#endif // AARCH64
+    }
+  } else {
+#ifdef AARCH64
+    Register left  = op->in_opr1()->as_pointer_register();
+    Register right = op->in_opr2()->as_pointer_register();
+    Register dest  = op->result_opr()->as_pointer_register();
+
+    switch (op->code()) {
+      case lir_idiv:
+        if (is_32) {
+          __ sdiv_w(dest, left, right);
+        } else {
+          __ sdiv(dest, left, right);
+        }
+        break;
+      case lir_irem: {
+        Register tmp = op->in_opr3()->as_pointer_register();
+        assert_different_registers(left, tmp);
+        assert_different_registers(right, tmp);
+        if (is_32) {
+          __ sdiv_w(tmp, left, right);
+          __ msub_w(dest, right, tmp, left);
+        } else {
+          __ sdiv(tmp, left, right);
+          __ msub(dest, right, tmp, left);
+        }
+        break;
+      }
+      default:
+        ShouldNotReachHere();
+    }
+#else
+    assert(op->code() == lir_idiv || op->code() == lir_irem, "unexpected op3");
+    __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
+    add_debug_info_for_div0_here(op->info());
+#endif // AARCH64
+  }
+}
+
+
+void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
+#ifdef ASSERT
+  assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label");
+  if (op->block() != NULL)  _branch_target_blocks.append(op->block());
+  if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock());
+  assert(op->info() == NULL, "CodeEmitInfo?");
+#endif // ASSERT
+
+#ifdef __SOFTFP__
+  assert (op->code() != lir_cond_float_branch, "this should be impossible");
+#else
+  if (op->code() == lir_cond_float_branch) {
+#ifndef AARCH64
+    __ fmstat();
+#endif // !AARCH64
+    __ b(*(op->ublock()->label()), vs);
+  }
+#endif // __SOFTFP__
+
+  AsmCondition acond = al;
+  switch (op->cond()) {
+    case lir_cond_equal:        acond = eq; break;
+    case lir_cond_notEqual:     acond = ne; break;
+    case lir_cond_less:         acond = lt; break;
+    case lir_cond_lessEqual:    acond = le; break;
+    case lir_cond_greaterEqual: acond = ge; break;
+    case lir_cond_greater:      acond = gt; break;
+    case lir_cond_aboveEqual:   acond = hs; break;
+    case lir_cond_belowEqual:   acond = ls; break;
+    default: assert(op->cond() == lir_cond_always, "must be");
+  }
+  __ b(*(op->label()), acond);
+}
+
+
+void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
+  LIR_Opr src  = op->in_opr();
+  LIR_Opr dest = op->result_opr();
+
+  switch (op->bytecode()) {
+    case Bytecodes::_i2l:
+#ifdef AARCH64
+      __ sign_extend(dest->as_register_lo(), src->as_register(), 32);
+#else
+      move_regs(src->as_register(), dest->as_register_lo());
+      __ mov(dest->as_register_hi(), AsmOperand(src->as_register(), asr, 31));
+#endif // AARCH64
+      break;
+    case Bytecodes::_l2i:
+      move_regs(src->as_register_lo(), dest->as_register());
+      break;
+    case Bytecodes::_i2b:
+      __ sign_extend(dest->as_register(), src->as_register(), 8);
+      break;
+    case Bytecodes::_i2s:
+      __ sign_extend(dest->as_register(), src->as_register(), 16);
+      break;
+    case Bytecodes::_i2c:
+      __ zero_extend(dest->as_register(), src->as_register(), 16);
+      break;
+    case Bytecodes::_f2d:
+      __ convert_f2d(dest->as_double_reg(), src->as_float_reg());
+      break;
+    case Bytecodes::_d2f:
+      __ convert_d2f(dest->as_float_reg(), src->as_double_reg());
+      break;
+    case Bytecodes::_i2f:
+#ifdef AARCH64
+      __ scvtf_sw(dest->as_float_reg(), src->as_register());
+#else
+      __ fmsr(Stemp, src->as_register());
+      __ fsitos(dest->as_float_reg(), Stemp);
+#endif // AARCH64
+      break;
+    case Bytecodes::_i2d:
+#ifdef AARCH64
+      __ scvtf_dw(dest->as_double_reg(), src->as_register());
+#else
+      __ fmsr(Stemp, src->as_register());
+      __ fsitod(dest->as_double_reg(), Stemp);
+#endif // AARCH64
+      break;
+    case Bytecodes::_f2i:
+#ifdef AARCH64
+      __ fcvtzs_ws(dest->as_register(), src->as_float_reg());
+#else
+      __ ftosizs(Stemp, src->as_float_reg());
+      __ fmrs(dest->as_register(), Stemp);
+#endif // AARCH64
+      break;
+    case Bytecodes::_d2i:
+#ifdef AARCH64
+      __ fcvtzs_wd(dest->as_register(), src->as_double_reg());
+#else
+      __ ftosizd(Stemp, src->as_double_reg());
+      __ fmrs(dest->as_register(), Stemp);
+#endif // AARCH64
+      break;
+#ifdef AARCH64
+    case Bytecodes::_l2f:
+      __ scvtf_sx(dest->as_float_reg(), src->as_register_lo());
+      break;
+    case Bytecodes::_l2d:
+      __ scvtf_dx(dest->as_double_reg(), src->as_register_lo());
+      break;
+    case Bytecodes::_f2l:
+      __ fcvtzs_xs(dest->as_register_lo(), src->as_float_reg());
+      break;
+    case Bytecodes::_d2l:
+      __ fcvtzs_xd(dest->as_register_lo(), src->as_double_reg());
+      break;
+#endif // AARCH64
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
+  if (op->init_check()) {
+    Register tmp = op->tmp1()->as_register();
+    __ ldrb(tmp, Address(op->klass()->as_register(), InstanceKlass::init_state_offset()));
+    add_debug_info_for_null_check_here(op->stub()->info());
+    __ cmp(tmp, InstanceKlass::fully_initialized);
+    __ b(*op->stub()->entry(), ne);
+  }
+  __ allocate_object(op->obj()->as_register(),
+                     op->tmp1()->as_register(),
+                     op->tmp2()->as_register(),
+                     op->tmp3()->as_register(),
+                     op->header_size(),
+                     op->object_size(),
+                     op->klass()->as_register(),
+                     *op->stub()->entry());
+  __ bind(*op->stub()->continuation());
+}
+
+void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
+  if (UseSlowPath ||
+      (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) ||
+      (!UseFastNewTypeArray   && (op->type() != T_OBJECT && op->type() != T_ARRAY))) {
+    __ b(*op->stub()->entry());
+  } else {
+    __ allocate_array(op->obj()->as_register(),
+                      op->len()->as_register(),
+                      op->tmp1()->as_register(),
+                      op->tmp2()->as_register(),
+                      op->tmp3()->as_register(),
+                      arrayOopDesc::header_size(op->type()),
+                      type2aelembytes(op->type()),
+                      op->klass()->as_register(),
+                      *op->stub()->entry());
+  }
+  __ bind(*op->stub()->continuation());
+}
+
+void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias,
+                                        ciMethodData *md, ciProfileData *data,
+                                        Register recv, Register tmp1, Label* update_done) {
+  assert_different_registers(mdo, recv, tmp1);
+  uint i;
+  for (i = 0; i < VirtualCallData::row_limit(); i++) {
+    Label next_test;
+    // See if the receiver is receiver[n].
+    Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) -
+                          mdo_offset_bias);
+    __ ldr(tmp1, receiver_addr);
+    __ verify_klass_ptr(tmp1);
+    __ cmp(recv, tmp1);
+    __ b(next_test, ne);
+    Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) -
+                      mdo_offset_bias);
+    __ ldr(tmp1, data_addr);
+    __ add(tmp1, tmp1, DataLayout::counter_increment);
+    __ str(tmp1, data_addr);
+    __ b(*update_done);
+    __ bind(next_test);
+  }
+
+  // Didn't find receiver; find next empty slot and fill it in
+  for (i = 0; i < VirtualCallData::row_limit(); i++) {
+    Label next_test;
+    Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) -
+                      mdo_offset_bias);
+    __ ldr(tmp1, recv_addr);
+    __ cbnz(tmp1, next_test);
+    __ str(recv, recv_addr);
+    __ mov(tmp1, DataLayout::counter_increment);
+    __ str(tmp1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) -
+                         mdo_offset_bias));
+    __ b(*update_done);
+    __ bind(next_test);
+  }
+}
+
+void LIR_Assembler::setup_md_access(ciMethod* method, int bci,
+                                    ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) {
+  md = method->method_data_or_null();
+  assert(md != NULL, "Sanity");
+  data = md->bci_to_data(bci);
+  assert(data != NULL,       "need data for checkcast");
+  assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check");
+  if (md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes() >= 4096) {
+    // The offset is large so bias the mdo by the base of the slot so
+    // that the ldr can use an immediate offset to reference the slots of the data
+    mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset());
+  }
+}
+
+// On 32-bit ARM, code before this helper should test obj for null (ZF should be set if obj is null).
+void LIR_Assembler::typecheck_profile_helper1(ciMethod* method, int bci,
+                                              ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias,
+                                              Register obj, Register mdo, Register data_val, Label* obj_is_null) {
+  assert(method != NULL, "Should have method");
+  assert_different_registers(obj, mdo, data_val);
+  setup_md_access(method, bci, md, data, mdo_offset_bias);
+  Label not_null;
+#ifdef AARCH64
+  __ cbnz(obj, not_null);
+#else
+  __ b(not_null, ne);
+#endif // AARCH64
+  __ mov_metadata(mdo, md->constant_encoding());
+  if (mdo_offset_bias > 0) {
+    __ mov_slow(data_val, mdo_offset_bias);
+    __ add(mdo, mdo, data_val);
+  }
+  Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias);
+  __ ldrb(data_val, flags_addr);
+  __ orr(data_val, data_val, (uint)BitData::null_seen_byte_constant());
+  __ strb(data_val, flags_addr);
+  __ b(*obj_is_null);
+  __ bind(not_null);
+}
+
+void LIR_Assembler::typecheck_profile_helper2(ciMethodData* md, ciProfileData* data, int mdo_offset_bias,
+                                              Register mdo, Register recv, Register value, Register tmp1,
+                                              Label* profile_cast_success, Label* profile_cast_failure,
+                                              Label* success, Label* failure) {
+  assert_different_registers(mdo, value, tmp1);
+  __ bind(*profile_cast_success);
+  __ mov_metadata(mdo, md->constant_encoding());
+  if (mdo_offset_bias > 0) {
+    __ mov_slow(tmp1, mdo_offset_bias);
+    __ add(mdo, mdo, tmp1);
+  }
+  __ load_klass(recv, value);
+  type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, success);
+  __ b(*success);
+  // Cast failure case
+  __ bind(*profile_cast_failure);
+  __ mov_metadata(mdo, md->constant_encoding());
+  if (mdo_offset_bias > 0) {
+    __ mov_slow(tmp1, mdo_offset_bias);
+    __ add(mdo, mdo, tmp1);
+  }
+  Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
+  __ ldr(tmp1, data_addr);
+  __ sub(tmp1, tmp1, DataLayout::counter_increment);
+  __ str(tmp1, data_addr);
+  __ b(*failure);
+}
+
+// Sets `res` to true, if `cond` holds. On AArch64 also sets `res` to false if `cond` does not hold.
+static void set_instanceof_result(MacroAssembler* _masm, Register res, AsmCondition cond) {
+#ifdef AARCH64
+  __ cset(res, cond);
+#else
+  __ mov(res, 1, cond);
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
+  // TODO: ARM - can be more effective with one more register
+  switch (op->code()) {
+    case lir_store_check: {
+      CodeStub* stub = op->stub();
+      Register value = op->object()->as_register();
+      Register array = op->array()->as_register();
+      Register klass_RInfo = op->tmp1()->as_register();
+      Register k_RInfo = op->tmp2()->as_register();
+      assert_different_registers(klass_RInfo, k_RInfo, Rtemp);
+      if (op->should_profile()) {
+        assert_different_registers(value, klass_RInfo, k_RInfo, Rtemp);
+      }
+
+      // check if it needs to be profiled
+      ciMethodData* md;
+      ciProfileData* data;
+      int mdo_offset_bias = 0;
+      Label profile_cast_success, profile_cast_failure, done;
+      Label *success_target = op->should_profile() ? &profile_cast_success : &done;
+      Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry();
+
+      if (op->should_profile()) {
+#ifndef AARCH64
+        __ cmp(value, 0);
+#endif // !AARCH64
+        typecheck_profile_helper1(op->profiled_method(), op->profiled_bci(), md, data, mdo_offset_bias, value, k_RInfo, Rtemp, &done);
+      } else {
+        __ cbz(value, done);
+      }
+      assert_different_registers(k_RInfo, value);
+      add_debug_info_for_null_check_here(op->info_for_exception());
+      __ load_klass(k_RInfo, array);
+      __ load_klass(klass_RInfo, value);
+      __ ldr(k_RInfo, Address(k_RInfo, ObjArrayKlass::element_klass_offset()));
+      __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+      // check for immediate positive hit
+      __ ldr(Rtemp, Address(klass_RInfo, Rtemp));
+      __ cmp(klass_RInfo, k_RInfo);
+      __ cond_cmp(Rtemp, k_RInfo, ne);
+      __ b(*success_target, eq);
+      // check for immediate negative hit
+      __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+      __ cmp(Rtemp, in_bytes(Klass::secondary_super_cache_offset()));
+      __ b(*failure_target, ne);
+      // slow case
+      assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+      __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+      __ cbz(R0, *failure_target);
+      if (op->should_profile()) {
+        Register mdo  = klass_RInfo, recv = k_RInfo, tmp1 = Rtemp;
+        if (mdo == value) {
+          mdo = k_RInfo;
+          recv = klass_RInfo;
+        }
+        typecheck_profile_helper2(md, data, mdo_offset_bias, mdo, recv, value, tmp1,
+                                  &profile_cast_success, &profile_cast_failure,
+                                  &done, stub->entry());
+      }
+      __ bind(done);
+      break;
+    }
+
+    case lir_checkcast: {
+      CodeStub* stub = op->stub();
+      Register obj = op->object()->as_register();
+      Register res = op->result_opr()->as_register();
+      Register klass_RInfo = op->tmp1()->as_register();
+      Register k_RInfo = op->tmp2()->as_register();
+      ciKlass* k = op->klass();
+      assert_different_registers(res, k_RInfo, klass_RInfo, Rtemp);
+
+      // TODO: ARM - Late binding is used to prevent confusion of register allocator
+      assert(stub->is_exception_throw_stub(), "must be");
+      ((SimpleExceptionStub*)stub)->set_obj(op->result_opr());
+
+      ciMethodData* md;
+      ciProfileData* data;
+      int mdo_offset_bias = 0;
+
+      Label done;
+
+      Label profile_cast_failure, profile_cast_success;
+      Label *failure_target = op->should_profile() ? &profile_cast_failure : op->stub()->entry();
+      Label *success_target = op->should_profile() ? &profile_cast_success : &done;
+
+#ifdef AARCH64
+      move_regs(obj, res);
+      if (op->should_profile()) {
+        typecheck_profile_helper1(op->profiled_method(), op->profiled_bci(), md, data, mdo_offset_bias, res, klass_RInfo, Rtemp, &done);
+      } else {
+        __ cbz(obj, done);
+      }
+      if (k->is_loaded()) {
+        __ mov_metadata(k_RInfo, k->constant_encoding());
+      } else {
+        if (res != obj) {
+          op->info_for_patch()->add_register_oop(FrameMap::as_oop_opr(res));
+        }
+        klass2reg_with_patching(k_RInfo, op->info_for_patch());
+      }
+      __ load_klass(klass_RInfo, res);
+
+      if (op->fast_check()) {
+        __ cmp(klass_RInfo, k_RInfo);
+        __ b(*failure_target, ne);
+      } else if (k->is_loaded()) {
+        __ ldr(Rtemp, Address(klass_RInfo, k->super_check_offset()));
+        if (in_bytes(Klass::secondary_super_cache_offset()) != (int) k->super_check_offset()) {
+          __ cmp(Rtemp, k_RInfo);
+          __ b(*failure_target, ne);
+        } else {
+          __ cmp(klass_RInfo, k_RInfo);
+          __ cond_cmp(Rtemp, k_RInfo, ne);
+          __ b(*success_target, eq);
+          assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+          __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+          __ cbz(R0, *failure_target);
+        }
+      } else {
+        __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        // check for immediate positive hit
+        __ ldr(Rtemp, Address(klass_RInfo, Rtemp));
+        __ cmp(klass_RInfo, k_RInfo);
+        __ cond_cmp(Rtemp, k_RInfo, ne);
+        __ b(*success_target, eq);
+        // check for immediate negative hit
+        __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        __ cmp(Rtemp, in_bytes(Klass::secondary_super_cache_offset()));
+        __ b(*failure_target, ne);
+        // slow case
+        assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+        __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+        __ cbz(R0, *failure_target);
+      }
+
+#else // AARCH64
+
+      __ movs(res, obj);
+      if (op->should_profile()) {
+        typecheck_profile_helper1(op->profiled_method(), op->profiled_bci(), md, data, mdo_offset_bias, res, klass_RInfo, Rtemp, &done);
+      } else {
+        __ b(done, eq);
+      }
+      if (k->is_loaded()) {
+        __ mov_metadata(k_RInfo, k->constant_encoding());
+      } else if (k_RInfo != obj) {
+        klass2reg_with_patching(k_RInfo, op->info_for_patch());
+        __ movs(res, obj);
+      } else {
+        // Patching doesn't update "res" register after GC, so do patching first
+        klass2reg_with_patching(Rtemp, op->info_for_patch());
+        __ movs(res, obj);
+        __ mov(k_RInfo, Rtemp);
+      }
+      __ load_klass(klass_RInfo, res, ne);
+
+      if (op->fast_check()) {
+        __ cmp(klass_RInfo, k_RInfo, ne);
+        __ b(*failure_target, ne);
+      } else if (k->is_loaded()) {
+        __ b(*success_target, eq);
+        __ ldr(Rtemp, Address(klass_RInfo, k->super_check_offset()));
+        if (in_bytes(Klass::secondary_super_cache_offset()) != (int) k->super_check_offset()) {
+          __ cmp(Rtemp, k_RInfo);
+          __ b(*failure_target, ne);
+        } else {
+          __ cmp(klass_RInfo, k_RInfo);
+          __ cmp(Rtemp, k_RInfo, ne);
+          __ b(*success_target, eq);
+          assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+          __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+          __ cbz(R0, *failure_target);
+        }
+      } else {
+        __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        __ b(*success_target, eq);
+        // check for immediate positive hit
+        __ ldr(Rtemp, Address(klass_RInfo, Rtemp));
+        __ cmp(klass_RInfo, k_RInfo);
+        __ cmp(Rtemp, k_RInfo, ne);
+        __ b(*success_target, eq);
+        // check for immediate negative hit
+        __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        __ cmp(Rtemp, in_bytes(Klass::secondary_super_cache_offset()));
+        __ b(*failure_target, ne);
+        // slow case
+        assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+        __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+        __ cbz(R0, *failure_target);
+      }
+#endif // AARCH64
+
+      if (op->should_profile()) {
+        Register mdo  = klass_RInfo, recv = k_RInfo, tmp1 = Rtemp;
+        typecheck_profile_helper2(md, data, mdo_offset_bias, mdo, recv, res, tmp1,
+                                  &profile_cast_success, &profile_cast_failure,
+                                  &done, stub->entry());
+      }
+      __ bind(done);
+      break;
+    }
+
+    case lir_instanceof: {
+      Register obj = op->object()->as_register();
+      Register res = op->result_opr()->as_register();
+      Register klass_RInfo = op->tmp1()->as_register();
+      Register k_RInfo = op->tmp2()->as_register();
+      ciKlass* k = op->klass();
+      assert_different_registers(res, klass_RInfo, k_RInfo, Rtemp);
+
+      ciMethodData* md;
+      ciProfileData* data;
+      int mdo_offset_bias = 0;
+
+      Label done;
+
+      Label profile_cast_failure, profile_cast_success;
+      Label *failure_target = op->should_profile() ? &profile_cast_failure : &done;
+      Label *success_target = op->should_profile() ? &profile_cast_success : &done;
+
+#ifdef AARCH64
+      move_regs(obj, res);
+#else
+      __ movs(res, obj);
+#endif // AARCH64
+
+      if (op->should_profile()) {
+        typecheck_profile_helper1(op->profiled_method(), op->profiled_bci(), md, data, mdo_offset_bias, res, klass_RInfo, Rtemp, &done);
+      } else {
+#ifdef AARCH64
+        __ cbz(obj, done); // If obj == NULL, res is false
+#else
+        __ b(done, eq);
+#endif // AARCH64
+      }
+
+      if (k->is_loaded()) {
+        __ mov_metadata(k_RInfo, k->constant_encoding());
+      } else {
+        op->info_for_patch()->add_register_oop(FrameMap::as_oop_opr(res));
+        klass2reg_with_patching(k_RInfo, op->info_for_patch());
+      }
+      __ load_klass(klass_RInfo, res);
+
+#ifndef AARCH64
+      if (!op->should_profile()) {
+        __ mov(res, 0);
+      }
+#endif // !AARCH64
+
+      if (op->fast_check()) {
+        __ cmp(klass_RInfo, k_RInfo);
+        if (!op->should_profile()) {
+          set_instanceof_result(_masm, res, eq);
+        } else {
+          __ b(profile_cast_failure, ne);
+        }
+      } else if (k->is_loaded()) {
+        __ ldr(Rtemp, Address(klass_RInfo, k->super_check_offset()));
+        if (in_bytes(Klass::secondary_super_cache_offset()) != (int) k->super_check_offset()) {
+          __ cmp(Rtemp, k_RInfo);
+          if (!op->should_profile()) {
+            set_instanceof_result(_masm, res, eq);
+          } else {
+            __ b(profile_cast_failure, ne);
+          }
+        } else {
+          __ cmp(klass_RInfo, k_RInfo);
+          __ cond_cmp(Rtemp, k_RInfo, ne);
+          if (!op->should_profile()) {
+            set_instanceof_result(_masm, res, eq);
+          }
+          __ b(*success_target, eq);
+          assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+          __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+          if (!op->should_profile()) {
+            move_regs(R0, res);
+          } else {
+            __ cbz(R0, *failure_target);
+          }
+        }
+      } else {
+        __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        // check for immediate positive hit
+        __ cmp(klass_RInfo, k_RInfo);
+        if (!op->should_profile()) {
+#ifdef AARCH64
+          // TODO-AARCH64 check if separate conditional branch is more efficient than ldr+cond_cmp
+          __ ldr(res, Address(klass_RInfo, Rtemp));
+#else
+          __ ldr(res, Address(klass_RInfo, Rtemp), ne);
+#endif // AARCH64
+          __ cond_cmp(res, k_RInfo, ne);
+          set_instanceof_result(_masm, res, eq);
+        } else {
+#ifdef AARCH64
+          // TODO-AARCH64 check if separate conditional branch is more efficient than ldr+cond_cmp
+          __ ldr(Rtemp, Address(klass_RInfo, Rtemp));
+#else
+          __ ldr(Rtemp, Address(klass_RInfo, Rtemp), ne);
+#endif // AARCH64
+          __ cond_cmp(Rtemp, k_RInfo, ne);
+        }
+        __ b(*success_target, eq);
+        // check for immediate negative hit
+        if (op->should_profile()) {
+          __ ldr_u32(Rtemp, Address(k_RInfo, Klass::super_check_offset_offset()));
+        }
+        __ cmp(Rtemp, in_bytes(Klass::secondary_super_cache_offset()));
+        if (!op->should_profile()) {
+#ifdef AARCH64
+          __ mov(res, 0);
+#else
+          __ mov(res, 0, ne);
+#endif // AARCH64
+        }
+        __ b(*failure_target, ne);
+        // slow case
+        assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
+        __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+        if (!op->should_profile()) {
+          move_regs(R0, res);
+        }
+        if (op->should_profile()) {
+          __ cbz(R0, *failure_target);
+        }
+      }
+
+      if (op->should_profile()) {
+        Label done_ok, done_failure;
+        Register mdo  = klass_RInfo, recv = k_RInfo, tmp1 = Rtemp;
+        typecheck_profile_helper2(md, data, mdo_offset_bias, mdo, recv, res, tmp1,
+                                  &profile_cast_success, &profile_cast_failure,
+                                  &done_ok, &done_failure);
+        __ bind(done_failure);
+        __ mov(res, 0);
+        __ b(done);
+        __ bind(done_ok);
+        __ mov(res, 1);
+      }
+      __ bind(done);
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
+  //   if (*addr == cmpval) {
+  //     *addr = newval;
+  //     dest = 1;
+  //   } else {
+  //     dest = 0;
+  //   }
+#ifdef AARCH64
+  Label retry, done;
+  Register addr = op->addr()->as_pointer_register();
+  Register cmpval = op->cmp_value()->as_pointer_register();
+  Register newval = op->new_value()->as_pointer_register();
+  Register dest = op->result_opr()->as_pointer_register();
+  assert_different_registers(dest, addr, cmpval, newval, Rtemp);
+
+  if (UseCompressedOops && op->code() == lir_cas_obj) {
+    Register tmp1 = op->tmp1()->as_pointer_register();
+    Register tmp2 = op->tmp2()->as_pointer_register();
+    assert_different_registers(dest, addr, cmpval, newval, tmp1, tmp2, Rtemp);
+    __ encode_heap_oop(tmp1, cmpval); cmpval = tmp1;
+    __ encode_heap_oop(tmp2, newval); newval = tmp2;
+  }
+
+  __ mov(dest, ZR);
+  __ bind(retry);
+  if (((op->code() == lir_cas_obj) && !UseCompressedOops) || op->code() == lir_cas_long) {
+    __ ldaxr(Rtemp, addr);
+    __ cmp(Rtemp, cmpval);
+    __ b(done, ne);
+    __ stlxr(Rtemp, newval, addr);
+  } else if (((op->code() == lir_cas_obj) && UseCompressedOops) || op->code() == lir_cas_int) {
+    __ ldaxr_w(Rtemp, addr);
+    __ cmp_w(Rtemp, cmpval);
+    __ b(done, ne);
+    __ stlxr_w(Rtemp, newval, addr);
+  } else {
+    ShouldNotReachHere();
+  }
+  __ cbnz_w(Rtemp, retry);
+  __ mov(dest, 1);
+  __ bind(done);
+#else
+  // FIXME: membar_release
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
+  if (op->code() == lir_cas_int || op->code() == lir_cas_obj) {
+    Register addr = op->addr()->as_register();
+    Register cmpval = op->cmp_value()->as_register();
+    Register newval = op->new_value()->as_register();
+    Register dest = op->result_opr()->as_register();
+    assert_different_registers(dest, addr, cmpval, newval, Rtemp);
+
+    __ atomic_cas_bool(cmpval, newval, addr, 0, Rtemp); // Rtemp free by default at C1 LIR layer
+    __ mov(dest, 1, eq);
+    __ mov(dest, 0, ne);
+  } else if (op->code() == lir_cas_long) {
+    assert(VM_Version::supports_cx8(), "wrong machine");
+    Register addr = op->addr()->as_pointer_register();
+    Register cmp_value_lo = op->cmp_value()->as_register_lo();
+    Register cmp_value_hi = op->cmp_value()->as_register_hi();
+    Register new_value_lo = op->new_value()->as_register_lo();
+    Register new_value_hi = op->new_value()->as_register_hi();
+    Register dest = op->result_opr()->as_register();
+    Register tmp_lo = op->tmp1()->as_register_lo();
+    Register tmp_hi = op->tmp1()->as_register_hi();
+
+    assert_different_registers(tmp_lo, tmp_hi, cmp_value_lo, cmp_value_hi, dest, new_value_lo, new_value_hi, addr);
+    assert(tmp_hi->encoding() == tmp_lo->encoding() + 1, "non aligned register pair");
+    assert(new_value_hi->encoding() == new_value_lo->encoding() + 1, "non aligned register pair");
+    assert((tmp_lo->encoding() & 0x1) == 0, "misaligned register pair");
+    assert((new_value_lo->encoding() & 0x1) == 0, "misaligned register pair");
+    __ atomic_cas64(tmp_lo, tmp_hi, dest, cmp_value_lo, cmp_value_hi,
+                    new_value_lo, new_value_hi, addr, 0);
+  } else {
+    Unimplemented();
+  }
+#endif // AARCH64
+  // FIXME: is full membar really needed instead of just membar_acquire?
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad | MacroAssembler::StoreStore), Rtemp);
+}
+
+
+void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) {
+  AsmCondition acond = al;
+  AsmCondition ncond = nv;
+  if (opr1 != opr2) {
+    switch (condition) {
+      case lir_cond_equal:        acond = eq; ncond = ne; break;
+      case lir_cond_notEqual:     acond = ne; ncond = eq; break;
+      case lir_cond_less:         acond = lt; ncond = ge; break;
+      case lir_cond_lessEqual:    acond = le; ncond = gt; break;
+      case lir_cond_greaterEqual: acond = ge; ncond = lt; break;
+      case lir_cond_greater:      acond = gt; ncond = le; break;
+      case lir_cond_aboveEqual:   acond = hs; ncond = lo; break;
+      case lir_cond_belowEqual:   acond = ls; ncond = hi; break;
+      default: ShouldNotReachHere();
+    }
+  }
+
+#ifdef AARCH64
+
+  // TODO-AARCH64 implement it more efficiently
+
+  if (opr1->is_register()) {
+    reg2reg(opr1, result);
+  } else if (opr1->is_stack()) {
+    stack2reg(opr1, result, result->type());
+  } else if (opr1->is_constant()) {
+    const2reg(opr1, result, lir_patch_none, NULL);
+  } else {
+    ShouldNotReachHere();
+  }
+
+  Label skip;
+  __ b(skip, acond);
+
+  if (opr2->is_register()) {
+    reg2reg(opr2, result);
+  } else if (opr2->is_stack()) {
+    stack2reg(opr2, result, result->type());
+  } else if (opr2->is_constant()) {
+    const2reg(opr2, result, lir_patch_none, NULL);
+  } else {
+    ShouldNotReachHere();
+  }
+
+  __ bind(skip);
+
+#else
+  for (;;) {                         // two iterations only
+    if (opr1 == result) {
+      // do nothing
+    } else if (opr1->is_single_cpu()) {
+      __ mov(result->as_register(), opr1->as_register(), acond);
+    } else if (opr1->is_double_cpu()) {
+      __ long_move(result->as_register_lo(), result->as_register_hi(),
+                   opr1->as_register_lo(), opr1->as_register_hi(), acond);
+    } else if (opr1->is_single_stack()) {
+      __ ldr(result->as_register(), frame_map()->address_for_slot(opr1->single_stack_ix()), acond);
+    } else if (opr1->is_double_stack()) {
+      __ ldr(result->as_register_lo(),
+             frame_map()->address_for_slot(opr1->double_stack_ix(), lo_word_offset_in_bytes), acond);
+      __ ldr(result->as_register_hi(),
+             frame_map()->address_for_slot(opr1->double_stack_ix(), hi_word_offset_in_bytes), acond);
+    } else if (opr1->is_illegal()) {
+      // do nothing: this part of the cmove has been optimized away in the peephole optimizer
+    } else {
+      assert(opr1->is_constant(), "must be");
+      LIR_Const* c = opr1->as_constant_ptr();
+
+      switch (c->type()) {
+        case T_INT:
+          __ mov_slow(result->as_register(), c->as_jint(), acond);
+          break;
+        case T_LONG:
+          __ mov_slow(result->as_register_lo(), c->as_jint_lo(), acond);
+          __ mov_slow(result->as_register_hi(), c->as_jint_hi(), acond);
+          break;
+        case T_OBJECT:
+          __ mov_oop(result->as_register(), c->as_jobject(), 0, acond);
+          break;
+        case T_FLOAT:
+#ifdef __SOFTFP__
+          // not generated now.
+          __ mov_slow(result->as_register(), c->as_jint(), acond);
+#else
+          __ mov_float(result->as_float_reg(), c->as_jfloat(), acond);
+#endif // __SOFTFP__
+          break;
+        case T_DOUBLE:
+#ifdef __SOFTFP__
+          // not generated now.
+          __ mov_slow(result->as_register_lo(), c->as_jint_lo(), acond);
+          __ mov_slow(result->as_register_hi(), c->as_jint_hi(), acond);
+#else
+          __ mov_double(result->as_double_reg(), c->as_jdouble(), acond);
+#endif // __SOFTFP__
+          break;
+        default:
+          ShouldNotReachHere();
+      }
+    }
+
+    // Negate the condition and repeat the algorithm with the second operand
+    if (opr1 == opr2) { break; }
+    opr1 = opr2;
+    acond = ncond;
+  }
+#endif // AARCH64
+}
+
+#if defined(AARCH64) || defined(ASSERT)
+static int reg_size(LIR_Opr op) {
+  switch (op->type()) {
+  case T_FLOAT:
+  case T_INT:      return BytesPerInt;
+  case T_LONG:
+  case T_DOUBLE:   return BytesPerLong;
+  case T_OBJECT:
+  case T_ARRAY:
+  case T_METADATA: return BytesPerWord;
+  case T_ADDRESS:
+  case T_ILLEGAL:  // fall through
+  default: ShouldNotReachHere(); return -1;
+  }
+}
+#endif
+
+void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack) {
+  assert(info == NULL, "unused on this code path");
+  assert(dest->is_register(), "wrong items state");
+
+  if (right->is_address()) {
+    // special case for adding shifted/extended register
+    const Register res = dest->as_pointer_register();
+    const Register lreg = left->as_pointer_register();
+    const LIR_Address* addr = right->as_address_ptr();
+
+    assert(addr->base()->as_pointer_register() == lreg && addr->index()->is_register() && addr->disp() == 0, "must be");
+
+    int scale = addr->scale();
+    AsmShift shift = lsl;
+
+#ifdef AARCH64
+    bool is_index_extended = reg_size(addr->base()) > reg_size(addr->index());
+    if (scale < 0) {
+      scale = -scale;
+      shift = lsr;
+    }
+    assert(shift == lsl || !is_index_extended, "could not have extend and right shift in one operand");
+    assert(0 <= scale && scale <= 63, "scale is too large");
+
+    if (is_index_extended) {
+      assert(scale <= 4, "scale is too large for add with extended register");
+      assert(addr->index()->is_single_cpu(), "should be");
+      assert(addr->index()->type() == T_INT, "should be");
+      assert(dest->is_double_cpu(), "should be");
+      assert(code == lir_add, "special case of add with extended register");
+
+      __ add(res, lreg, addr->index()->as_register(), ex_sxtw, scale);
+      return;
+    } else if (reg_size(dest) == BytesPerInt) {
+      assert(reg_size(addr->base()) == reg_size(addr->index()), "should be");
+      assert(reg_size(addr->base()) == reg_size(dest), "should be");
+
+      AsmOperand operand(addr->index()->as_pointer_register(), shift, scale);
+      switch (code) {
+        case lir_add: __ add_32(res, lreg, operand); break;
+        case lir_sub: __ sub_32(res, lreg, operand); break;
+        default: ShouldNotReachHere();
+      }
+      return;
+    }
+#endif // AARCH64
+
+    assert(reg_size(addr->base()) == reg_size(addr->index()), "should be");
+    assert(reg_size(addr->base()) == reg_size(dest), "should be");
+    assert(reg_size(dest) == wordSize, "should be");
+
+    AsmOperand operand(addr->index()->as_pointer_register(), shift, scale);
+    switch (code) {
+      case lir_add: __ add(res, lreg, operand); break;
+      case lir_sub: __ sub(res, lreg, operand); break;
+      default: ShouldNotReachHere();
+    }
+
+#ifndef AARCH64
+  } else if (left->is_address()) {
+    assert(code == lir_sub && right->is_single_cpu(), "special case used by strength_reduce_multiply()");
+    const LIR_Address* addr = left->as_address_ptr();
+    const Register res = dest->as_register();
+    const Register rreg = right->as_register();
+    assert(addr->base()->as_register() == rreg && addr->index()->is_register() && addr->disp() == 0, "must be");
+    __ rsb(res, rreg, AsmOperand(addr->index()->as_register(), lsl, addr->scale()));
+#endif // !AARCH64
+
+  } else if (dest->is_single_cpu()) {
+    assert(left->is_single_cpu(), "unexpected left operand");
+#ifdef AARCH64
+    assert(dest->type() == T_INT, "unexpected dest type");
+    assert(left->type() == T_INT, "unexpected left type");
+    assert(right->type() == T_INT, "unexpected right type");
+#endif // AARCH64
+
+    const Register res = dest->as_register();
+    const Register lreg = left->as_register();
+
+    if (right->is_single_cpu()) {
+      const Register rreg = right->as_register();
+      switch (code) {
+        case lir_add: __ add_32(res, lreg, rreg); break;
+        case lir_sub: __ sub_32(res, lreg, rreg); break;
+        case lir_mul: __ mul_32(res, lreg, rreg); break;
+        default: ShouldNotReachHere();
+      }
+    } else {
+      assert(right->is_constant(), "must be");
+      const jint c = right->as_constant_ptr()->as_jint();
+      if (!Assembler::is_arith_imm_in_range(c)) {
+        BAILOUT("illegal arithmetic operand");
+      }
+      switch (code) {
+        case lir_add: __ add_32(res, lreg, c); break;
+        case lir_sub: __ sub_32(res, lreg, c); break;
+        default: ShouldNotReachHere();
+      }
+    }
+
+  } else if (dest->is_double_cpu()) {
+#ifdef AARCH64
+    assert(left->is_double_cpu() ||
+           (left->is_single_cpu() && ((left->type() == T_OBJECT) || (left->type() == T_ARRAY) || (left->type() == T_ADDRESS))),
+           "unexpected left operand");
+
+    const Register res = dest->as_register_lo();
+    const Register lreg = left->as_pointer_register();
+
+    if (right->is_constant()) {
+      assert(right->type() == T_LONG, "unexpected right type");
+      assert((right->as_constant_ptr()->as_jlong() >> 24) == 0, "out of range");
+      jint imm = (jint)right->as_constant_ptr()->as_jlong();
+      switch (code) {
+        case lir_add: __ add(res, lreg, imm); break;
+        case lir_sub: __ sub(res, lreg, imm); break;
+        default: ShouldNotReachHere();
+      }
+    } else {
+      assert(right->is_double_cpu() ||
+             (right->is_single_cpu() && ((right->type() == T_OBJECT) || (right->type() == T_ARRAY) || (right->type() == T_ADDRESS))),
+             "unexpected right operand");
+      const Register rreg = right->as_pointer_register();
+      switch (code) {
+        case lir_add: __ add(res, lreg, rreg); break;
+        case lir_sub: __ sub(res, lreg, rreg); break;
+        case lir_mul: __ mul(res, lreg, rreg); break;
+        default: ShouldNotReachHere();
+      }
+    }
+#else // AARCH64
+    Register res_lo = dest->as_register_lo();
+    Register res_hi = dest->as_register_hi();
+    Register lreg_lo = left->as_register_lo();
+    Register lreg_hi = left->as_register_hi();
+    if (right->is_double_cpu()) {
+      Register rreg_lo = right->as_register_lo();
+      Register rreg_hi = right->as_register_hi();
+      if (res_lo == lreg_hi || res_lo == rreg_hi) {
+        res_lo = Rtemp;
+      }
+      switch (code) {
+        case lir_add:
+          __ adds(res_lo, lreg_lo, rreg_lo);
+          __ adc(res_hi, lreg_hi, rreg_hi);
+          break;
+        case lir_sub:
+          __ subs(res_lo, lreg_lo, rreg_lo);
+          __ sbc(res_hi, lreg_hi, rreg_hi);
+          break;
+        default:
+          ShouldNotReachHere();
+      }
+    } else {
+      assert(right->is_constant(), "must be");
+      assert((right->as_constant_ptr()->as_jlong() >> 32) == 0, "out of range");
+      const jint c = (jint) right->as_constant_ptr()->as_jlong();
+      if (res_lo == lreg_hi) {
+        res_lo = Rtemp;
+      }
+      switch (code) {
+        case lir_add:
+          __ adds(res_lo, lreg_lo, c);
+          __ adc(res_hi, lreg_hi, 0);
+          break;
+        case lir_sub:
+          __ subs(res_lo, lreg_lo, c);
+          __ sbc(res_hi, lreg_hi, 0);
+          break;
+        default:
+          ShouldNotReachHere();
+      }
+    }
+    move_regs(res_lo, dest->as_register_lo());
+#endif // AARCH64
+
+  } else if (dest->is_single_fpu()) {
+    assert(left->is_single_fpu(), "must be");
+    assert(right->is_single_fpu(), "must be");
+    const FloatRegister res = dest->as_float_reg();
+    const FloatRegister lreg = left->as_float_reg();
+    const FloatRegister rreg = right->as_float_reg();
+    switch (code) {
+      case lir_add: __ add_float(res, lreg, rreg); break;
+      case lir_sub: __ sub_float(res, lreg, rreg); break;
+      case lir_mul_strictfp: // fall through
+      case lir_mul: __ mul_float(res, lreg, rreg); break;
+      case lir_div_strictfp: // fall through
+      case lir_div: __ div_float(res, lreg, rreg); break;
+      default: ShouldNotReachHere();
+    }
+  } else if (dest->is_double_fpu()) {
+    assert(left->is_double_fpu(), "must be");
+    assert(right->is_double_fpu(), "must be");
+    const FloatRegister res = dest->as_double_reg();
+    const FloatRegister lreg = left->as_double_reg();
+    const FloatRegister rreg = right->as_double_reg();
+    switch (code) {
+      case lir_add: __ add_double(res, lreg, rreg); break;
+      case lir_sub: __ sub_double(res, lreg, rreg); break;
+      case lir_mul_strictfp: // fall through
+      case lir_mul: __ mul_double(res, lreg, rreg); break;
+      case lir_div_strictfp: // fall through
+      case lir_div: __ div_double(res, lreg, rreg); break;
+      default: ShouldNotReachHere();
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, LIR_Opr dest, LIR_Op* op) {
+  switch (code) {
+    case lir_abs:
+      __ abs_double(dest->as_double_reg(), value->as_double_reg());
+      break;
+    case lir_sqrt:
+      __ sqrt_double(dest->as_double_reg(), value->as_double_reg());
+      break;
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
+  assert(dest->is_register(), "wrong items state");
+  assert(left->is_register(), "wrong items state");
+
+  if (dest->is_single_cpu()) {
+#ifdef AARCH64
+    assert (dest->type() == T_INT, "unexpected result type");
+    assert (left->type() == T_INT, "unexpected left type");
+    assert (right->type() == T_INT, "unexpected right type");
+#endif // AARCH64
+
+    const Register res = dest->as_register();
+    const Register lreg = left->as_register();
+
+    if (right->is_single_cpu()) {
+      const Register rreg = right->as_register();
+      switch (code) {
+        case lir_logic_and: __ and_32(res, lreg, rreg); break;
+        case lir_logic_or:  __ orr_32(res, lreg, rreg); break;
+        case lir_logic_xor: __ eor_32(res, lreg, rreg); break;
+        default: ShouldNotReachHere();
+      }
+    } else {
+      assert(right->is_constant(), "must be");
+      const uint c = (uint)right->as_constant_ptr()->as_jint();
+      switch (code) {
+        case lir_logic_and: __ and_32(res, lreg, c); break;
+        case lir_logic_or:  __ orr_32(res, lreg, c); break;
+        case lir_logic_xor: __ eor_32(res, lreg, c); break;
+        default: ShouldNotReachHere();
+      }
+    }
+  } else {
+    assert(dest->is_double_cpu(), "should be");
+    Register res_lo = dest->as_register_lo();
+
+#ifdef AARCH64
+    assert ((left->is_single_cpu() && left->is_oop_register()) || left->is_double_cpu(), "should be");
+    const Register lreg_lo = left->as_pointer_register();
+#else
+    assert (dest->type() == T_LONG, "unexpected result type");
+    assert (left->type() == T_LONG, "unexpected left type");
+    assert (right->type() == T_LONG, "unexpected right type");
+
+    const Register res_hi = dest->as_register_hi();
+    const Register lreg_lo = left->as_register_lo();
+    const Register lreg_hi = left->as_register_hi();
+#endif // AARCH64
+
+    if (right->is_register()) {
+#ifdef AARCH64
+      assert ((right->is_single_cpu() && right->is_oop_register()) || right->is_double_cpu(), "should be");
+      const Register rreg_lo = right->as_pointer_register();
+      switch (code) {
+        case lir_logic_and: __ andr(res_lo, lreg_lo, rreg_lo); break;
+        case lir_logic_or:  __ orr (res_lo, lreg_lo, rreg_lo); break;
+        case lir_logic_xor: __ eor (res_lo, lreg_lo, rreg_lo); break;
+        default: ShouldNotReachHere();
+      }
+#else
+      const Register rreg_lo = right->as_register_lo();
+      const Register rreg_hi = right->as_register_hi();
+      if (res_lo == lreg_hi || res_lo == rreg_hi) {
+        res_lo = Rtemp; // Temp register helps to avoid overlap between result and input
+      }
+      switch (code) {
+        case lir_logic_and:
+          __ andr(res_lo, lreg_lo, rreg_lo);
+          __ andr(res_hi, lreg_hi, rreg_hi);
+          break;
+        case lir_logic_or:
+          __ orr(res_lo, lreg_lo, rreg_lo);
+          __ orr(res_hi, lreg_hi, rreg_hi);
+          break;
+        case lir_logic_xor:
+          __ eor(res_lo, lreg_lo, rreg_lo);
+          __ eor(res_hi, lreg_hi, rreg_hi);
+          break;
+        default:
+          ShouldNotReachHere();
+      }
+      move_regs(res_lo, dest->as_register_lo());
+#endif // AARCH64
+    } else {
+      assert(right->is_constant(), "must be");
+#ifdef AARCH64
+      const julong c = (julong)right->as_constant_ptr()->as_jlong();
+      Assembler::LogicalImmediate imm(c, false);
+      if (imm.is_encoded()) {
+        switch (code) {
+          case lir_logic_and: __ andr(res_lo, lreg_lo, imm); break;
+          case lir_logic_or:  __ orr (res_lo, lreg_lo, imm); break;
+          case lir_logic_xor: __ eor (res_lo, lreg_lo, imm); break;
+          default: ShouldNotReachHere();
+        }
+      } else {
+        BAILOUT("64 bit constant cannot be inlined");
+      }
+#else
+      const jint c_lo = (jint) right->as_constant_ptr()->as_jlong();
+      const jint c_hi = (jint) (right->as_constant_ptr()->as_jlong() >> 32);
+      // Case for logic_or from do_ClassIDIntrinsic()
+      if (c_hi == 0 && AsmOperand::is_rotated_imm(c_lo)) {
+        switch (code) {
+          case lir_logic_and:
+            __ andr(res_lo, lreg_lo, c_lo);
+            __ mov(res_hi, 0);
+            break;
+          case lir_logic_or:
+            __ orr(res_lo, lreg_lo, c_lo);
+            break;
+          case lir_logic_xor:
+            __ eor(res_lo, lreg_lo, c_lo);
+            break;
+        default:
+          ShouldNotReachHere();
+        }
+      } else if (code == lir_logic_and &&
+                 c_hi == -1 &&
+                 (AsmOperand::is_rotated_imm(c_lo) ||
+                  AsmOperand::is_rotated_imm(~c_lo))) {
+        // Another case which handles logic_and from do_ClassIDIntrinsic()
+        if (AsmOperand::is_rotated_imm(c_lo)) {
+          __ andr(res_lo, lreg_lo, c_lo);
+        } else {
+          __ bic(res_lo, lreg_lo, ~c_lo);
+        }
+        if (res_hi != lreg_hi) {
+          __ mov(res_hi, lreg_hi);
+        }
+      } else {
+        BAILOUT("64 bit constant cannot be inlined");
+      }
+#endif // AARCH64
+    }
+  }
+}
+
+
+#ifdef AARCH64
+
+void LIR_Assembler::long_compare_helper(LIR_Opr opr1, LIR_Opr opr2) {
+  assert(opr1->is_double_cpu(), "should be");
+  Register x = opr1->as_register_lo();
+
+  if (opr2->is_double_cpu()) {
+    Register y = opr2->as_register_lo();
+    __ cmp(x, y);
+
+  } else {
+    assert(opr2->is_constant(), "should be");
+    assert(opr2->as_constant_ptr()->type() == T_LONG, "long constant expected");
+    jlong c = opr2->as_jlong();
+    assert(((c >> 31) == 0) || ((c >> 31) == -1), "immediate is out of range");
+    if (c >= 0) {
+      __ cmp(x, (jint)c);
+    } else {
+      __ cmn(x, (jint)(-c));
+    }
+  }
+}
+
+#endif // AARCH64
+
+void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) {
+  if (opr1->is_single_cpu()) {
+    if (opr2->is_constant()) {
+      switch (opr2->as_constant_ptr()->type()) {
+        case T_INT: {
+          const jint c = opr2->as_constant_ptr()->as_jint();
+          if (Assembler::is_arith_imm_in_range(c)) {
+            __ cmp_32(opr1->as_register(), c);
+          } else if (Assembler::is_arith_imm_in_range(-c)) {
+            __ cmn_32(opr1->as_register(), -c);
+          } else {
+            // This can happen when compiling lookupswitch
+            __ mov_slow(Rtemp, c);
+            __ cmp_32(opr1->as_register(), Rtemp);
+          }
+          break;
+        }
+        case T_OBJECT:
+          assert(opr2->as_constant_ptr()->as_jobject() == NULL, "cannot handle otherwise");
+          __ cmp(opr1->as_register(), 0);
+          break;
+        default:
+          ShouldNotReachHere();
+      }
+    } else if (opr2->is_single_cpu()) {
+      if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY || opr1->type() == T_METADATA || opr1->type() == T_ADDRESS) {
+        assert(opr2->type() == T_OBJECT || opr2->type() == T_ARRAY || opr2->type() == T_METADATA || opr2->type() == T_ADDRESS, "incompatibe type");
+        __ cmp(opr1->as_register(), opr2->as_register());
+      } else {
+        assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY && opr2->type() != T_METADATA && opr2->type() != T_ADDRESS, "incompatibe type");
+        __ cmp_32(opr1->as_register(), opr2->as_register());
+      }
+    } else {
+      ShouldNotReachHere();
+    }
+  } else if (opr1->is_double_cpu()) {
+#ifdef AARCH64
+    long_compare_helper(opr1, opr2);
+#else
+    Register xlo = opr1->as_register_lo();
+    Register xhi = opr1->as_register_hi();
+    if (opr2->is_constant() && opr2->as_jlong() == 0) {
+      assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "cannot handle otherwise");
+      __ orrs(Rtemp, xlo, xhi);
+    } else if (opr2->is_register()) {
+      Register ylo = opr2->as_register_lo();
+      Register yhi = opr2->as_register_hi();
+      if (condition == lir_cond_equal || condition == lir_cond_notEqual) {
+        __ teq(xhi, yhi);
+        __ teq(xlo, ylo, eq);
+      } else {
+        __ subs(xlo, xlo, ylo);
+        __ sbcs(xhi, xhi, yhi);
+      }
+    } else {
+      ShouldNotReachHere();
+    }
+#endif // AARCH64
+  } else if (opr1->is_single_fpu()) {
+    if (opr2->is_constant()) {
+      assert(opr2->as_jfloat() == 0.0f, "cannot handle otherwise");
+      __ cmp_zero_float(opr1->as_float_reg());
+    } else {
+      __ cmp_float(opr1->as_float_reg(), opr2->as_float_reg());
+    }
+  } else if (opr1->is_double_fpu()) {
+    if (opr2->is_constant()) {
+      assert(opr2->as_jdouble() == 0.0, "cannot handle otherwise");
+      __ cmp_zero_double(opr1->as_double_reg());
+    } else {
+      __ cmp_double(opr1->as_double_reg(), opr2->as_double_reg());
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op) {
+  const Register res = dst->as_register();
+  if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) {
+    comp_op(lir_cond_unknown, left, right, op);
+#ifdef AARCH64
+    if (code == lir_ucmp_fd2i) {         // unordered is less
+      __ cset(res, gt);                  // 1 if '>', else 0
+      __ csinv(res, res, ZR, ge);        // previous value if '>=', else -1
+    } else {
+      __ cset(res, hi);                  // 1 if '>' or unordered, else 0
+      __ csinv(res, res, ZR, pl);        // previous value if '>=' or unordered, else -1
+    }
+#else
+    __ fmstat();
+    if (code == lir_ucmp_fd2i) {  // unordered is less
+      __ mvn(res, 0, lt);
+      __ mov(res, 1, ge);
+    } else {                      // unordered is greater
+      __ mov(res, 1, cs);
+      __ mvn(res, 0, cc);
+    }
+    __ mov(res, 0, eq);
+#endif // AARCH64
+
+  } else {
+    assert(code == lir_cmp_l2i, "must be");
+
+#ifdef AARCH64
+    long_compare_helper(left, right);
+
+    __ cset(res, gt);            // 1 if '>', else 0
+    __ csinv(res, res, ZR, ge);  // previous value if '>=', else -1
+#else
+    Label done;
+    const Register xlo = left->as_register_lo();
+    const Register xhi = left->as_register_hi();
+    const Register ylo = right->as_register_lo();
+    const Register yhi = right->as_register_hi();
+    __ cmp(xhi, yhi);
+    __ mov(res, 1, gt);
+    __ mvn(res, 0, lt);
+    __ b(done, ne);
+    __ subs(res, xlo, ylo);
+    __ mov(res, 1, hi);
+    __ mvn(res, 0, lo);
+    __ bind(done);
+#endif // AARCH64
+  }
+}
+
+
+void LIR_Assembler::align_call(LIR_Code code) {
+  // Not needed
+}
+
+
+void LIR_Assembler::call(LIR_OpJavaCall *op, relocInfo::relocType rtype) {
+  int ret_addr_offset = __ patchable_call(op->addr(), rtype);
+  assert(ret_addr_offset == __ offset(), "embedded return address not allowed");
+  add_call_info_here(op->info());
+}
+
+
+void LIR_Assembler::ic_call(LIR_OpJavaCall *op) {
+  bool near_range = __ cache_fully_reachable();
+  address oop_address = pc();
+
+  bool use_movw = AARCH64_ONLY(false) NOT_AARCH64(VM_Version::supports_movw());
+
+  // Ricklass may contain something that is not a metadata pointer so
+  // mov_metadata can't be used
+  InlinedAddress value((address)Universe::non_oop_word());
+  InlinedAddress addr(op->addr());
+  if (use_movw) {
+#ifdef AARCH64
+    ShouldNotReachHere();
+#else
+    __ movw(Ricklass, ((unsigned int)Universe::non_oop_word()) & 0xffff);
+    __ movt(Ricklass, ((unsigned int)Universe::non_oop_word()) >> 16);
+#endif // AARCH64
+  } else {
+    // No movw/movt, must be load a pc relative value but no
+    // relocation so no metadata table to load from.
+    // Use a b instruction rather than a bl, inline constant after the
+    // branch, use a PC relative ldr to load the constant, arrange for
+    // the call to return after the constant(s).
+    __ ldr_literal(Ricklass, value);
+  }
+  __ relocate(virtual_call_Relocation::spec(oop_address));
+  if (near_range && use_movw) {
+    __ bl(op->addr());
+  } else {
+    Label call_return;
+    __ adr(LR, call_return);
+    if (near_range) {
+      __ b(op->addr());
+    } else {
+      __ indirect_jump(addr, Rtemp);
+      __ bind_literal(addr);
+    }
+    if (!use_movw) {
+      __ bind_literal(value);
+    }
+    __ bind(call_return);
+  }
+  add_call_info(code_offset(), op->info());
+}
+
+
+/* Currently, vtable-dispatch is only enabled for sparc platforms */
+void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
+  ShouldNotReachHere();
+}
+
+void LIR_Assembler::emit_static_call_stub() {
+  address call_pc = __ pc();
+  address stub = __ start_a_stub(call_stub_size());
+  if (stub == NULL) {
+    BAILOUT("static call stub overflow");
+  }
+
+  DEBUG_ONLY(int offset = code_offset();)
+
+  InlinedMetadata metadata_literal(NULL);
+  __ relocate(static_stub_Relocation::spec(call_pc));
+  // If not a single instruction, NativeMovConstReg::next_instruction_address()
+  // must jump over the whole following ldr_literal.
+  // (See CompiledStaticCall::set_to_interpreted())
+#ifdef ASSERT
+  address ldr_site = __ pc();
+#endif
+  __ ldr_literal(Rmethod, metadata_literal);
+  assert(nativeMovConstReg_at(ldr_site)->next_instruction_address() == __ pc(), "Fix ldr_literal or its parsing");
+  bool near_range = __ cache_fully_reachable();
+  InlinedAddress dest((address)-1);
+  if (near_range) {
+    address branch_site = __ pc();
+    __ b(branch_site); // b to self maps to special NativeJump -1 destination
+  } else {
+    __ indirect_jump(dest, Rtemp);
+  }
+  __ bind_literal(metadata_literal); // includes spec_for_immediate reloc
+  if (!near_range) {
+    __ bind_literal(dest); // special NativeJump -1 destination
+  }
+
+  assert(code_offset() - offset <= call_stub_size(), "overflow");
+  __ end_a_stub();
+}
+
+void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
+  assert(exceptionOop->as_register() == Rexception_obj, "must match");
+  assert(exceptionPC->as_register()  == Rexception_pc, "must match");
+  info->add_register_oop(exceptionOop);
+
+  Runtime1::StubID handle_id = compilation()->has_fpu_code() ?
+                               Runtime1::handle_exception_id :
+                               Runtime1::handle_exception_nofpu_id;
+  Label return_address;
+  __ adr(Rexception_pc, return_address);
+  __ call(Runtime1::entry_for(handle_id), relocInfo::runtime_call_type);
+  __ bind(return_address);
+  add_call_info_here(info);  // for exception handler
+}
+
+void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) {
+  assert(exceptionOop->as_register() == Rexception_obj, "must match");
+  __ b(_unwind_handler_entry);
+}
+
+void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) {
+#ifdef AARCH64
+  if (dest->is_single_cpu()) {
+    Register res = dest->as_register();
+    Register x = left->as_register();
+    Register y = count->as_register();
+    assert (dest->type() == T_INT, "unexpected result type");
+    assert (left->type() == T_INT, "unexpected left type");
+
+    switch (code) {
+      case lir_shl:  __ lslv_w(res, x, y); break;
+      case lir_shr:  __ asrv_w(res, x, y); break;
+      case lir_ushr: __ lsrv_w(res, x, y); break;
+      default: ShouldNotReachHere();
+    }
+  } else if (dest->is_double_cpu()) {
+    Register res = dest->as_register_lo();
+    Register x = left->as_register_lo();
+    Register y = count->as_register();
+
+    switch (code) {
+      case lir_shl:  __ lslv(res, x, y); break;
+      case lir_shr:  __ asrv(res, x, y); break;
+      case lir_ushr: __ lsrv(res, x, y); break;
+      default: ShouldNotReachHere();
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+#else
+  AsmShift shift = lsl;
+  switch (code) {
+    case lir_shl:  shift = lsl; break;
+    case lir_shr:  shift = asr; break;
+    case lir_ushr: shift = lsr; break;
+    default: ShouldNotReachHere();
+  }
+
+  if (dest->is_single_cpu()) {
+    __ andr(Rtemp, count->as_register(), 31);
+    __ mov(dest->as_register(), AsmOperand(left->as_register(), shift, Rtemp));
+  } else if (dest->is_double_cpu()) {
+    Register dest_lo = dest->as_register_lo();
+    Register dest_hi = dest->as_register_hi();
+    Register src_lo  = left->as_register_lo();
+    Register src_hi  = left->as_register_hi();
+    Register Rcount  = count->as_register();
+    // Resolve possible register conflicts
+    if (shift == lsl && dest_hi == src_lo) {
+      dest_hi = Rtemp;
+    } else if (shift != lsl && dest_lo == src_hi) {
+      dest_lo = Rtemp;
+    } else if (dest_lo == src_lo && dest_hi == src_hi) {
+      dest_lo = Rtemp;
+    } else if (dest_lo == Rcount || dest_hi == Rcount) {
+      Rcount = Rtemp;
+    }
+    __ andr(Rcount, count->as_register(), 63);
+    __ long_shift(dest_lo, dest_hi, src_lo, src_hi, shift, Rcount);
+    move_regs(dest_lo, dest->as_register_lo());
+    move_regs(dest_hi, dest->as_register_hi());
+  } else {
+    ShouldNotReachHere();
+  }
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) {
+#ifdef AARCH64
+  if (dest->is_single_cpu()) {
+    assert (dest->type() == T_INT, "unexpected result type");
+    assert (left->type() == T_INT, "unexpected left type");
+    count &= 31;
+    if (count != 0) {
+      switch (code) {
+        case lir_shl:  __ _lsl_w(dest->as_register(), left->as_register(), count); break;
+        case lir_shr:  __ _asr_w(dest->as_register(), left->as_register(), count); break;
+        case lir_ushr: __ _lsr_w(dest->as_register(), left->as_register(), count); break;
+        default: ShouldNotReachHere();
+      }
+    } else {
+      move_regs(left->as_register(), dest->as_register());
+    }
+  } else if (dest->is_double_cpu()) {
+    count &= 63;
+    if (count != 0) {
+      switch (code) {
+        case lir_shl:  __ _lsl(dest->as_register_lo(), left->as_register_lo(), count); break;
+        case lir_shr:  __ _asr(dest->as_register_lo(), left->as_register_lo(), count); break;
+        case lir_ushr: __ _lsr(dest->as_register_lo(), left->as_register_lo(), count); break;
+        default: ShouldNotReachHere();
+      }
+    } else {
+      move_regs(left->as_register_lo(), dest->as_register_lo());
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+
+#else
+  AsmShift shift = lsl;
+  switch (code) {
+    case lir_shl:  shift = lsl; break;
+    case lir_shr:  shift = asr; break;
+    case lir_ushr: shift = lsr; break;
+    default: ShouldNotReachHere();
+  }
+
+  if (dest->is_single_cpu()) {
+    count &= 31;
+    if (count != 0) {
+      __ mov(dest->as_register(), AsmOperand(left->as_register(), shift, count));
+    } else {
+      move_regs(left->as_register(), dest->as_register());
+    }
+  } else if (dest->is_double_cpu()) {
+    count &= 63;
+    if (count != 0) {
+      Register dest_lo = dest->as_register_lo();
+      Register dest_hi = dest->as_register_hi();
+      Register src_lo  = left->as_register_lo();
+      Register src_hi  = left->as_register_hi();
+      // Resolve possible register conflicts
+      if (shift == lsl && dest_hi == src_lo) {
+        dest_hi = Rtemp;
+      } else if (shift != lsl && dest_lo == src_hi) {
+        dest_lo = Rtemp;
+      }
+      __ long_shift(dest_lo, dest_hi, src_lo, src_hi, shift, count);
+      move_regs(dest_lo, dest->as_register_lo());
+      move_regs(dest_hi, dest->as_register_hi());
+    } else {
+      __ long_move(dest->as_register_lo(), dest->as_register_hi(),
+                   left->as_register_lo(), left->as_register_hi());
+    }
+  } else {
+    ShouldNotReachHere();
+  }
+#endif // AARCH64
+}
+
+
+// Saves 4 given registers in reserved argument area.
+void LIR_Assembler::save_in_reserved_area(Register r1, Register r2, Register r3, Register r4) {
+  verify_reserved_argument_area_size(4);
+#ifdef AARCH64
+  __ stp(r1, r2, Address(SP, 0));
+  __ stp(r3, r4, Address(SP, 2*wordSize));
+#else
+  __ stmia(SP, RegisterSet(r1) | RegisterSet(r2) | RegisterSet(r3) | RegisterSet(r4));
+#endif // AARCH64
+}
+
+// Restores 4 given registers from reserved argument area.
+void LIR_Assembler::restore_from_reserved_area(Register r1, Register r2, Register r3, Register r4) {
+#ifdef AARCH64
+  __ ldp(r1, r2, Address(SP, 0));
+  __ ldp(r3, r4, Address(SP, 2*wordSize));
+#else
+  __ ldmia(SP, RegisterSet(r1) | RegisterSet(r2) | RegisterSet(r3) | RegisterSet(r4), no_writeback);
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
+  ciArrayKlass* default_type = op->expected_type();
+  Register src = op->src()->as_register();
+  Register src_pos = op->src_pos()->as_register();
+  Register dst = op->dst()->as_register();
+  Register dst_pos = op->dst_pos()->as_register();
+  Register length  = op->length()->as_register();
+  Register tmp = op->tmp()->as_register();
+  Register tmp2 = Rtemp;
+
+  assert(src == R0 && src_pos == R1 && dst == R2 && dst_pos == R3, "code assumption");
+#ifdef AARCH64
+  assert(length == R4, "code assumption");
+#endif // AARCH64
+
+  CodeStub* stub = op->stub();
+
+  int flags = op->flags();
+  BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
+  if (basic_type == T_ARRAY) basic_type = T_OBJECT;
+
+  // If we don't know anything or it's an object array, just go through the generic arraycopy
+  if (default_type == NULL) {
+
+    // save arguments, because they will be killed by a runtime call
+    save_in_reserved_area(R0, R1, R2, R3);
+
+#ifdef AARCH64
+    // save length argument, will be killed by a runtime call
+    __ raw_push(length, ZR);
+#else
+    // pass length argument on SP[0]
+    __ str(length, Address(SP, -2*wordSize, pre_indexed));  // 2 words for a proper stack alignment
+#endif // AARCH64
+
+    address copyfunc_addr = StubRoutines::generic_arraycopy();
+    if (copyfunc_addr == NULL) { // Use C version if stub was not generated
+      __ call(CAST_FROM_FN_PTR(address, Runtime1::arraycopy));
+    } else {
+#ifndef PRODUCT
+      if (PrintC1Statistics) {
+        __ inc_counter((address)&Runtime1::_generic_arraycopystub_cnt, tmp, tmp2);
+      }
+#endif // !PRODUCT
+      // the stub is in the code cache so close enough
+      __ call(copyfunc_addr, relocInfo::runtime_call_type);
+    }
+
+#ifdef AARCH64
+    __ raw_pop(length, ZR);
+#else
+    __ add(SP, SP, 2*wordSize);
+#endif // AARCH64
+
+    __ cbz_32(R0, *stub->continuation());
+
+    if (copyfunc_addr != NULL) {
+      __ mvn_32(tmp, R0);
+      restore_from_reserved_area(R0, R1, R2, R3);  // load saved arguments in slow case only
+      __ sub_32(length, length, tmp);
+      __ add_32(src_pos, src_pos, tmp);
+      __ add_32(dst_pos, dst_pos, tmp);
+    } else {
+      restore_from_reserved_area(R0, R1, R2, R3);  // load saved arguments in slow case only
+    }
+
+    __ b(*stub->entry());
+
+    __ bind(*stub->continuation());
+    return;
+  }
+
+  assert(default_type != NULL && default_type->is_array_klass() && default_type->is_loaded(),
+         "must be true at this point");
+  int elem_size = type2aelembytes(basic_type);
+  int shift = exact_log2(elem_size);
+
+  // Check for NULL
+  if (flags & LIR_OpArrayCopy::src_null_check) {
+    if (flags & LIR_OpArrayCopy::dst_null_check) {
+      __ cmp(src, 0);
+      __ cond_cmp(dst, 0, ne);  // make one instruction shorter if both checks are needed
+      __ b(*stub->entry(), eq);
+    } else {
+      __ cbz(src, *stub->entry());
+    }
+  } else if (flags & LIR_OpArrayCopy::dst_null_check) {
+    __ cbz(dst, *stub->entry());
+  }
+
+  // If the compiler was not able to prove that exact type of the source or the destination
+  // of the arraycopy is an array type, check at runtime if the source or the destination is
+  // an instance type.
+  if (flags & LIR_OpArrayCopy::type_check) {
+    if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) {
+      __ load_klass(tmp, dst);
+      __ ldr_u32(tmp2, Address(tmp, in_bytes(Klass::layout_helper_offset())));
+      __ mov_slow(tmp, Klass::_lh_neutral_value);
+      __ cmp_32(tmp2, tmp);
+      __ b(*stub->entry(), ge);
+    }
+
+    if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) {
+      __ load_klass(tmp, src);
+      __ ldr_u32(tmp2, Address(tmp, in_bytes(Klass::layout_helper_offset())));
+      __ mov_slow(tmp, Klass::_lh_neutral_value);
+      __ cmp_32(tmp2, tmp);
+      __ b(*stub->entry(), ge);
+    }
+  }
+
+  // Check if negative
+  const int all_positive_checks = LIR_OpArrayCopy::src_pos_positive_check |
+                                  LIR_OpArrayCopy::dst_pos_positive_check |
+                                  LIR_OpArrayCopy::length_positive_check;
+  switch (flags & all_positive_checks) {
+    case LIR_OpArrayCopy::src_pos_positive_check:
+      __ branch_if_negative_32(src_pos, *stub->entry());
+      break;
+    case LIR_OpArrayCopy::dst_pos_positive_check:
+      __ branch_if_negative_32(dst_pos, *stub->entry());
+      break;
+    case LIR_OpArrayCopy::length_positive_check:
+      __ branch_if_negative_32(length, *stub->entry());
+      break;
+    case LIR_OpArrayCopy::src_pos_positive_check | LIR_OpArrayCopy::dst_pos_positive_check:
+      __ branch_if_any_negative_32(src_pos, dst_pos, tmp, *stub->entry());
+      break;
+    case LIR_OpArrayCopy::src_pos_positive_check | LIR_OpArrayCopy::length_positive_check:
+      __ branch_if_any_negative_32(src_pos, length, tmp, *stub->entry());
+      break;
+    case LIR_OpArrayCopy::dst_pos_positive_check | LIR_OpArrayCopy::length_positive_check:
+      __ branch_if_any_negative_32(dst_pos, length, tmp, *stub->entry());
+      break;
+    case all_positive_checks:
+      __ branch_if_any_negative_32(src_pos, dst_pos, length, tmp, *stub->entry());
+      break;
+    default:
+      assert((flags & all_positive_checks) == 0, "the last option");
+  }
+
+  // Range checks
+  if (flags & LIR_OpArrayCopy::src_range_check) {
+    __ ldr_s32(tmp2, Address(src, arrayOopDesc::length_offset_in_bytes()));
+    __ add_32(tmp, src_pos, length);
+    __ cmp_32(tmp, tmp2);
+    __ b(*stub->entry(), hi);
+  }
+  if (flags & LIR_OpArrayCopy::dst_range_check) {
+    __ ldr_s32(tmp2, Address(dst, arrayOopDesc::length_offset_in_bytes()));
+    __ add_32(tmp, dst_pos, length);
+    __ cmp_32(tmp, tmp2);
+    __ b(*stub->entry(), hi);
+  }
+
+  // Check if src and dst are of the same type
+  if (flags & LIR_OpArrayCopy::type_check) {
+    // We don't know the array types are compatible
+    if (basic_type != T_OBJECT) {
+      // Simple test for basic type arrays
+      if (UseCompressedClassPointers) {
+        // We don't need decode because we just need to compare
+        __ ldr_u32(tmp, Address(src, oopDesc::klass_offset_in_bytes()));
+        __ ldr_u32(tmp2, Address(dst, oopDesc::klass_offset_in_bytes()));
+        __ cmp_32(tmp, tmp2);
+      } else {
+        __ load_klass(tmp, src);
+        __ load_klass(tmp2, dst);
+        __ cmp(tmp, tmp2);
+      }
+      __ b(*stub->entry(), ne);
+    } else {
+      // For object arrays, if src is a sub class of dst then we can
+      // safely do the copy.
+      Label cont, slow;
+
+      address copyfunc_addr = StubRoutines::checkcast_arraycopy();
+
+      __ load_klass(tmp, src);
+      __ load_klass(tmp2, dst);
+
+      // We are at a call so all live registers are saved before we
+      // get here
+      assert_different_registers(tmp, tmp2, R6, altFP_7_11);
+
+      __ check_klass_subtype_fast_path(tmp, tmp2, R6, altFP_7_11, &cont, copyfunc_addr == NULL ? stub->entry() : &slow, NULL);
+
+      __ mov(R6, R0);
+      __ mov(altFP_7_11, R1);
+      __ mov(R0, tmp);
+      __ mov(R1, tmp2);
+      __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); // does not blow any registers except R0, LR and Rtemp
+      __ cmp_32(R0, 0);
+      __ mov(R0, R6);
+      __ mov(R1, altFP_7_11);
+
+      if (copyfunc_addr != NULL) { // use stub if available
+        // src is not a sub class of dst so we have to do a
+        // per-element check.
+
+        __ b(cont, ne);
+
+        __ bind(slow);
+
+        int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
+        if ((flags & mask) != mask) {
+          // Check that at least both of them object arrays.
+          assert(flags & mask, "one of the two should be known to be an object array");
+
+          if (!(flags & LIR_OpArrayCopy::src_objarray)) {
+            __ load_klass(tmp, src);
+          } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
+            __ load_klass(tmp, dst);
+          }
+          int lh_offset = in_bytes(Klass::layout_helper_offset());
+
+          __ ldr_u32(tmp2, Address(tmp, lh_offset));
+
+          jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
+          __ mov_slow(tmp, objArray_lh);
+          __ cmp_32(tmp, tmp2);
+          __ b(*stub->entry(), ne);
+        }
+
+        save_in_reserved_area(R0, R1, R2, R3);
+
+        Register src_ptr = R0;
+        Register dst_ptr = R1;
+        Register len     = R2;
+        Register chk_off = R3;
+        Register super_k = AARCH64_ONLY(R4) NOT_AARCH64(tmp);
+
+        __ add(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type));
+        __ add_ptr_scaled_int32(src_ptr, src_ptr, src_pos, shift);
+
+        __ add(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type));
+        __ add_ptr_scaled_int32(dst_ptr, dst_ptr, dst_pos, shift);
+        __ load_klass(tmp, dst);
+
+        int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+        int sco_offset = in_bytes(Klass::super_check_offset_offset());
+
+#ifdef AARCH64
+        __ raw_push(length, ZR); // Preserve length around *copyfunc_addr call
+
+        __ mov(len, length);
+        __ ldr(super_k, Address(tmp, ek_offset)); // super_k == R4 == length, so this load cannot be performed earlier
+        // TODO-AARCH64: check whether it is faster to load super klass early by using tmp and additional mov.
+        __ ldr_u32(chk_off, Address(super_k, sco_offset));
+#else // AARCH64
+        __ ldr(super_k, Address(tmp, ek_offset));
+
+        __ mov(len, length);
+        __ ldr_u32(chk_off, Address(super_k, sco_offset));
+        __ push(super_k);
+#endif // AARCH64
+
+        __ call(copyfunc_addr, relocInfo::runtime_call_type);
+
+#ifndef PRODUCT
+        if (PrintC1Statistics) {
+          Label failed;
+          __ cbnz_32(R0, failed);
+          __ inc_counter((address)&Runtime1::_arraycopy_checkcast_cnt, tmp, tmp2);
+          __ bind(failed);
+        }
+#endif // PRODUCT
+
+#ifdef AARCH64
+        __ raw_pop(length, ZR);
+#else
+        __ add(SP, SP, wordSize);  // Drop super_k argument
+#endif // AARCH64
+
+        __ cbz_32(R0, *stub->continuation());
+        __ mvn_32(tmp, R0);
+
+        // load saved arguments in slow case only
+        restore_from_reserved_area(R0, R1, R2, R3);
+
+        __ sub_32(length, length, tmp);
+        __ add_32(src_pos, src_pos, tmp);
+        __ add_32(dst_pos, dst_pos, tmp);
+
+#ifndef PRODUCT
+        if (PrintC1Statistics) {
+          __ inc_counter((address)&Runtime1::_arraycopy_checkcast_attempt_cnt, tmp, tmp2);
+        }
+#endif
+
+        __ b(*stub->entry());
+
+        __ bind(cont);
+      } else {
+        __ b(*stub->entry(), eq);
+        __ bind(cont);
+      }
+    }
+  }
+
+#ifndef PRODUCT
+  if (PrintC1Statistics) {
+    address counter = Runtime1::arraycopy_count_address(basic_type);
+    __ inc_counter(counter, tmp, tmp2);
+  }
+#endif // !PRODUCT
+
+  bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
+  bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
+  const char *name;
+  address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
+
+  Register src_ptr = R0;
+  Register dst_ptr = R1;
+  Register len     = R2;
+
+  __ add(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type));
+  __ add_ptr_scaled_int32(src_ptr, src_ptr, src_pos, shift);
+
+  __ add(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type));
+  __ add_ptr_scaled_int32(dst_ptr, dst_ptr, dst_pos, shift);
+
+  __ mov(len, length);
+
+  __ call(entry, relocInfo::runtime_call_type);
+
+  __ bind(*stub->continuation());
+}
+
+#ifdef ASSERT
+ // emit run-time assertion
+void LIR_Assembler::emit_assert(LIR_OpAssert* op) {
+  assert(op->code() == lir_assert, "must be");
+
+#ifdef AARCH64
+  __ NOT_IMPLEMENTED();
+#else
+  if (op->in_opr1()->is_valid()) {
+    assert(op->in_opr2()->is_valid(), "both operands must be valid");
+    comp_op(op->condition(), op->in_opr1(), op->in_opr2(), op);
+  } else {
+    assert(op->in_opr2()->is_illegal(), "both operands must be illegal");
+    assert(op->condition() == lir_cond_always, "no other conditions allowed");
+  }
+
+  Label ok;
+  if (op->condition() != lir_cond_always) {
+    AsmCondition acond;
+    switch (op->condition()) {
+      case lir_cond_equal:        acond = eq; break;
+      case lir_cond_notEqual:     acond = ne; break;
+      case lir_cond_less:         acond = lt; break;
+      case lir_cond_lessEqual:    acond = le; break;
+      case lir_cond_greaterEqual: acond = ge; break;
+      case lir_cond_greater:      acond = gt; break;
+      case lir_cond_aboveEqual:   acond = hs; break;
+      case lir_cond_belowEqual:   acond = ls; break;
+      default:                    ShouldNotReachHere();
+    }
+    __ b(ok, acond);
+  }
+  if (op->halt()) {
+    const char* str = __ code_string(op->msg());
+    __ stop(str);
+  } else {
+    breakpoint();
+  }
+  __ bind(ok);
+#endif // AARCH64
+}
+#endif // ASSERT
+
+void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
+  fatal("CRC32 intrinsic is not implemented on this platform");
+}
+
+void LIR_Assembler::emit_lock(LIR_OpLock* op) {
+  Register obj = op->obj_opr()->as_pointer_register();
+  Register hdr = op->hdr_opr()->as_pointer_register();
+  Register lock = op->lock_opr()->as_pointer_register();
+  Register tmp = op->scratch_opr()->is_illegal() ? noreg :
+                 op->scratch_opr()->as_pointer_register();
+
+  if (!UseFastLocking) {
+    __ b(*op->stub()->entry());
+  } else if (op->code() == lir_lock) {
+    assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
+    int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry());
+    if (op->info() != NULL) {
+      add_debug_info_for_null_check(null_check_offset, op->info());
+    }
+  } else if (op->code() == lir_unlock) {
+    __ unlock_object(hdr, obj, lock, tmp, *op->stub()->entry());
+  } else {
+    ShouldNotReachHere();
+  }
+  __ bind(*op->stub()->continuation());
+}
+
+
+void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
+  ciMethod* method = op->profiled_method();
+  int bci          = op->profiled_bci();
+  ciMethod* callee = op->profiled_callee();
+
+  // Update counter for all call types
+  ciMethodData* md = method->method_data_or_null();
+  assert(md != NULL, "Sanity");
+  ciProfileData* data = md->bci_to_data(bci);
+  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
+  Register mdo  = op->mdo()->as_register();
+  assert(op->tmp1()->is_register(), "tmp1 must be allocated");
+  Register tmp1 = op->tmp1()->as_pointer_register();
+  assert_different_registers(mdo, tmp1);
+  __ mov_metadata(mdo, md->constant_encoding());
+  int mdo_offset_bias = 0;
+  int max_offset = AARCH64_ONLY(4096 << LogBytesPerWord) NOT_AARCH64(4096);
+  if (md->byte_offset_of_slot(data, CounterData::count_offset()) + data->size_in_bytes() >= max_offset) {
+    // The offset is large so bias the mdo by the base of the slot so
+    // that the ldr can use an immediate offset to reference the slots of the data
+    mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset());
+    __ mov_slow(tmp1, mdo_offset_bias);
+    __ add(mdo, mdo, tmp1);
+  }
+
+  Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
+  Bytecodes::Code bc = method->java_code_at_bci(bci);
+  const bool callee_is_static = callee->is_loaded() && callee->is_static();
+  // Perform additional virtual call profiling for invokevirtual and
+  // invokeinterface bytecodes
+  if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) &&
+      !callee_is_static &&  // required for optimized MH invokes
+      C1ProfileVirtualCalls) {
+
+    assert(op->recv()->is_single_cpu(), "recv must be allocated");
+    Register recv = op->recv()->as_register();
+    assert_different_registers(mdo, tmp1, recv);
+    assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls");
+    ciKlass* known_klass = op->known_holder();
+    if (C1OptimizeVirtualCallProfiling && known_klass != NULL) {
+      // We know the type that will be seen at this call site; we can
+      // statically update the MethodData* rather than needing to do
+      // dynamic tests on the receiver type
+
+      // NOTE: we should probably put a lock around this search to
+      // avoid collisions by concurrent compilations
+      ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
+      uint i;
+      for (i = 0; i < VirtualCallData::row_limit(); i++) {
+        ciKlass* receiver = vc_data->receiver(i);
+        if (known_klass->equals(receiver)) {
+          Address data_addr(mdo, md->byte_offset_of_slot(data,
+                                                         VirtualCallData::receiver_count_offset(i)) -
+                            mdo_offset_bias);
+          __ ldr(tmp1, data_addr);
+          __ add(tmp1, tmp1, DataLayout::counter_increment);
+          __ str(tmp1, data_addr);
+          return;
+        }
+      }
+
+      // Receiver type not found in profile data; select an empty slot
+
+      // Note that this is less efficient than it should be because it
+      // always does a write to the receiver part of the
+      // VirtualCallData rather than just the first time
+      for (i = 0; i < VirtualCallData::row_limit(); i++) {
+        ciKlass* receiver = vc_data->receiver(i);
+        if (receiver == NULL) {
+          Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) -
+                            mdo_offset_bias);
+          __ mov_metadata(tmp1, known_klass->constant_encoding());
+          __ str(tmp1, recv_addr);
+          Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) -
+                            mdo_offset_bias);
+          __ ldr(tmp1, data_addr);
+          __ add(tmp1, tmp1, DataLayout::counter_increment);
+          __ str(tmp1, data_addr);
+          return;
+        }
+      }
+    } else {
+      __ load_klass(recv, recv);
+      Label update_done;
+      type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done);
+      // Receiver did not match any saved receiver and there is no empty row for it.
+      // Increment total counter to indicate polymorphic case.
+      __ ldr(tmp1, counter_addr);
+      __ add(tmp1, tmp1, DataLayout::counter_increment);
+      __ str(tmp1, counter_addr);
+
+      __ bind(update_done);
+    }
+  } else {
+    // Static call
+    __ ldr(tmp1, counter_addr);
+    __ add(tmp1, tmp1, DataLayout::counter_increment);
+    __ str(tmp1, counter_addr);
+  }
+}
+
+void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
+  fatal("Type profiling not implemented on this platform");
+}
+
+void LIR_Assembler::emit_delay(LIR_OpDelay*) {
+  Unimplemented();
+}
+
+
+void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) {
+  Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no);
+  __ add_slow(dst->as_pointer_register(), mon_addr.base(), mon_addr.disp());
+}
+
+
+void LIR_Assembler::align_backward_branch_target() {
+  // TODO-AARCH64 review it
+  // Some ARM processors do better with 8-byte branch target alignment
+  __ align(8);
+}
+
+
+void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
+
+  if (left->is_single_cpu()) {
+    assert (dest->type() == T_INT, "unexpected result type");
+    assert (left->type() == T_INT, "unexpected left type");
+    __ neg_32(dest->as_register(), left->as_register());
+  } else if (left->is_double_cpu()) {
+#ifdef AARCH64
+    __ neg(dest->as_register_lo(), left->as_register_lo());
+#else
+    Register dest_lo = dest->as_register_lo();
+    Register dest_hi = dest->as_register_hi();
+    Register src_lo = left->as_register_lo();
+    Register src_hi = left->as_register_hi();
+    if (dest_lo == src_hi) {
+      dest_lo = Rtemp;
+    }
+    __ rsbs(dest_lo, src_lo, 0);
+    __ rsc(dest_hi, src_hi, 0);
+    move_regs(dest_lo, dest->as_register_lo());
+#endif // AARCH64
+  } else if (left->is_single_fpu()) {
+    __ neg_float(dest->as_float_reg(), left->as_float_reg());
+  } else if (left->is_double_fpu()) {
+    __ neg_double(dest->as_double_reg(), left->as_double_reg());
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+
+void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) {
+  LIR_Address* addr = addr_opr->as_address_ptr();
+  if (addr->index()->is_illegal()) {
+    jint c = addr->disp();
+    if (!Assembler::is_arith_imm_in_range(c)) {
+      BAILOUT("illegal arithmetic operand");
+    }
+    __ add(dest->as_pointer_register(), addr->base()->as_pointer_register(), c);
+  } else {
+    assert(addr->disp() == 0, "cannot handle otherwise");
+#ifdef AARCH64
+    assert(addr->index()->is_double_cpu(), "should be");
+#endif // AARCH64
+    __ add(dest->as_pointer_register(), addr->base()->as_pointer_register(),
+           AsmOperand(addr->index()->as_pointer_register(), lsl, addr->scale()));
+  }
+}
+
+
+void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
+  assert(!tmp->is_valid(), "don't need temporary");
+  __ call(dest);
+  if (info != NULL) {
+    add_call_info_here(info);
+  }
+}
+
+
+void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) {
+#ifdef AARCH64
+  Unimplemented(); // TODO-AARCH64: Use stlr/ldar instructions for volatile load/store
+#else
+  assert(src->is_double_cpu() && dest->is_address() ||
+         src->is_address() && dest->is_double_cpu(),
+         "Simple move_op is called for all other cases");
+
+  int null_check_offset;
+  if (dest->is_address()) {
+    // Store
+    const LIR_Address* addr = dest->as_address_ptr();
+    const Register src_lo = src->as_register_lo();
+    const Register src_hi = src->as_register_hi();
+    assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
+
+    if (src_lo < src_hi) {
+      null_check_offset = __ offset();
+      __ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(src_hi));
+    } else {
+      assert(src_lo < Rtemp, "Rtemp is higher than any allocatable register");
+      __ mov(Rtemp, src_hi);
+      null_check_offset = __ offset();
+      __ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(Rtemp));
+    }
+  } else {
+    // Load
+    const LIR_Address* addr = src->as_address_ptr();
+    const Register dest_lo = dest->as_register_lo();
+    const Register dest_hi = dest->as_register_hi();
+    assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
+
+    null_check_offset = __ offset();
+    if (dest_lo < dest_hi) {
+      __ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(dest_hi));
+    } else {
+      assert(dest_lo < Rtemp, "Rtemp is higher than any allocatable register");
+      __ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(Rtemp));
+      __ mov(dest_hi, Rtemp);
+    }
+  }
+
+  if (info != NULL) {
+    add_debug_info_for_null_check(null_check_offset, info);
+  }
+#endif // AARCH64
+}
+
+
+void LIR_Assembler::membar() {
+  __ membar(MacroAssembler::StoreLoad, Rtemp);
+}
+
+void LIR_Assembler::membar_acquire() {
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
+}
+
+void LIR_Assembler::membar_release() {
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
+}
+
+void LIR_Assembler::membar_loadload() {
+  __ membar(MacroAssembler::LoadLoad, Rtemp);
+}
+
+void LIR_Assembler::membar_storestore() {
+  __ membar(MacroAssembler::StoreStore, Rtemp);
+}
+
+void LIR_Assembler::membar_loadstore() {
+  __ membar(MacroAssembler::LoadStore, Rtemp);
+}
+
+void LIR_Assembler::membar_storeload() {
+  __ membar(MacroAssembler::StoreLoad, Rtemp);
+}
+
+void LIR_Assembler::on_spin_wait() {
+  Unimplemented();
+}
+
+void LIR_Assembler::get_thread(LIR_Opr result_reg) {
+  // Not used on ARM
+  Unimplemented();
+}
+
+void LIR_Assembler::peephole(LIR_List* lir) {
+#ifdef AARCH64
+  return; // TODO-AARCH64 implement peephole optimizations
+#endif
+  LIR_OpList* inst = lir->instructions_list();
+  const int inst_length = inst->length();
+  for (int i = 0; i < inst_length; i++) {
+    LIR_Op* op = inst->at(i);
+    switch (op->code()) {
+      case lir_cmp: {
+        // Replace:
+        //   cmp rX, y
+        //   cmove [EQ] y, z, rX
+        // with
+        //   cmp rX, y
+        //   cmove [EQ] illegalOpr, z, rX
+        //
+        // or
+        //   cmp rX, y
+        //   cmove [NE] z, y, rX
+        // with
+        //   cmp rX, y
+        //   cmove [NE] z, illegalOpr, rX
+        //
+        // moves from illegalOpr should be removed when converting LIR to native assembly
+
+        LIR_Op2* cmp = op->as_Op2();
+        assert(cmp != NULL, "cmp LIR instruction is not an op2");
+
+        if (i + 1 < inst_length) {
+          LIR_Op2* cmove = inst->at(i + 1)->as_Op2();
+          if (cmove != NULL && cmove->code() == lir_cmove) {
+            LIR_Opr cmove_res = cmove->result_opr();
+            bool res_is_op1 = cmove_res == cmp->in_opr1();
+            bool res_is_op2 = cmove_res == cmp->in_opr2();
+            LIR_Opr cmp_res, cmp_arg;
+            if (res_is_op1) {
+              cmp_res = cmp->in_opr1();
+              cmp_arg = cmp->in_opr2();
+            } else if (res_is_op2) {
+              cmp_res = cmp->in_opr2();
+              cmp_arg = cmp->in_opr1();
+            } else {
+              cmp_res = LIR_OprFact::illegalOpr;
+              cmp_arg = LIR_OprFact::illegalOpr;
+            }
+
+            if (cmp_res != LIR_OprFact::illegalOpr) {
+              LIR_Condition cond = cmove->condition();
+              if (cond == lir_cond_equal && cmove->in_opr1() == cmp_arg) {
+                cmove->set_in_opr1(LIR_OprFact::illegalOpr);
+              } else if (cond == lir_cond_notEqual && cmove->in_opr2() == cmp_arg) {
+                cmove->set_in_opr2(LIR_OprFact::illegalOpr);
+              }
+            }
+          }
+        }
+        break;
+      }
+
+      default:
+        break;
+    }
+  }
+}
+
+void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) {
+  Register ptr = src->as_pointer_register();
+
+  if (code == lir_xchg) {
+#ifdef AARCH64
+    if (UseCompressedOops && data->is_oop()) {
+      __ encode_heap_oop(tmp->as_pointer_register(), data->as_register());
+    }
+#endif // AARCH64
+  } else {
+    assert (!data->is_oop(), "xadd for oops");
+  }
+
+#ifndef AARCH64
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
+#endif // !AARCH64
+
+  Label retry;
+  __ bind(retry);
+
+  if ((data->type() == T_INT) || (data->is_oop() AARCH64_ONLY(&& UseCompressedOops))) {
+    Register dst = dest->as_register();
+    Register new_val = noreg;
+#ifdef AARCH64
+    __ ldaxr_w(dst, ptr);
+#else
+    __ ldrex(dst, Address(ptr));
+#endif
+    if (code == lir_xadd) {
+      Register tmp_reg = tmp->as_register();
+      if (data->is_constant()) {
+        assert_different_registers(dst, ptr, tmp_reg);
+        __ add_32(tmp_reg, dst, data->as_constant_ptr()->as_jint());
+      } else {
+        assert_different_registers(dst, ptr, tmp_reg, data->as_register());
+        __ add_32(tmp_reg, dst, data->as_register());
+      }
+      new_val = tmp_reg;
+    } else {
+      if (UseCompressedOops && data->is_oop()) {
+        new_val = tmp->as_pointer_register();
+      } else {
+        new_val = data->as_register();
+      }
+      assert_different_registers(dst, ptr, new_val);
+    }
+#ifdef AARCH64
+    __ stlxr_w(Rtemp, new_val, ptr);
+#else
+    __ strex(Rtemp, new_val, Address(ptr));
+#endif // AARCH64
+
+#ifdef AARCH64
+  } else if ((data->type() == T_LONG) || (data->is_oop() && !UseCompressedOops)) {
+    Register dst = dest->as_pointer_register();
+    Register new_val = noreg;
+    __ ldaxr(dst, ptr);
+    if (code == lir_xadd) {
+      Register tmp_reg = tmp->as_pointer_register();
+      if (data->is_constant()) {
+        assert_different_registers(dst, ptr, tmp_reg);
+        jlong c = data->as_constant_ptr()->as_jlong();
+        assert((jlong)((jint)c) == c, "overflow");
+        __ add(tmp_reg, dst, (jint)c);
+      } else {
+        assert_different_registers(dst, ptr, tmp_reg, data->as_pointer_register());
+        __ add(tmp_reg, dst, data->as_pointer_register());
+      }
+      new_val = tmp_reg;
+    } else {
+      new_val = data->as_pointer_register();
+      assert_different_registers(dst, ptr, new_val);
+    }
+    __ stlxr(Rtemp, new_val, ptr);
+#else
+  } else if (data->type() == T_LONG) {
+    Register dst_lo = dest->as_register_lo();
+    Register new_val_lo = noreg;
+    Register dst_hi = dest->as_register_hi();
+
+    assert(dst_hi->encoding() == dst_lo->encoding() + 1, "non aligned register pair");
+    assert((dst_lo->encoding() & 0x1) == 0, "misaligned register pair");
+
+    __ bind(retry);
+    __ ldrexd(dst_lo, Address(ptr));
+    if (code == lir_xadd) {
+      Register tmp_lo = tmp->as_register_lo();
+      Register tmp_hi = tmp->as_register_hi();
+
+      assert(tmp_hi->encoding() == tmp_lo->encoding() + 1, "non aligned register pair");
+      assert((tmp_lo->encoding() & 0x1) == 0, "misaligned register pair");
+
+      if (data->is_constant()) {
+        jlong c = data->as_constant_ptr()->as_jlong();
+        assert((jlong)((jint)c) == c, "overflow");
+        assert_different_registers(dst_lo, dst_hi, ptr, tmp_lo, tmp_hi);
+        __ adds(tmp_lo, dst_lo, (jint)c);
+        __ adc(tmp_hi, dst_hi, 0);
+      } else {
+        Register new_val_lo = data->as_register_lo();
+        Register new_val_hi = data->as_register_hi();
+        __ adds(tmp_lo, dst_lo, new_val_lo);
+        __ adc(tmp_hi, dst_hi, new_val_hi);
+        assert_different_registers(dst_lo, dst_hi, ptr, tmp_lo, tmp_hi, new_val_lo, new_val_hi);
+      }
+      new_val_lo = tmp_lo;
+    } else {
+      new_val_lo = data->as_register_lo();
+      Register new_val_hi = data->as_register_hi();
+
+      assert_different_registers(dst_lo, dst_hi, ptr, new_val_lo, new_val_hi);
+      assert(new_val_hi->encoding() == new_val_lo->encoding() + 1, "non aligned register pair");
+      assert((new_val_lo->encoding() & 0x1) == 0, "misaligned register pair");
+    }
+    __ strexd(Rtemp, new_val_lo, Address(ptr));
+#endif // AARCH64
+  } else {
+    ShouldNotReachHere();
+  }
+
+  __ cbnz_32(Rtemp, retry);
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad | MacroAssembler::StoreStore), Rtemp);
+
+#ifdef AARCH64
+  if (UseCompressedOops && data->is_oop()) {
+    __ decode_heap_oop(dest->as_register());
+  }
+#endif // AARCH64
+}
+
+#undef __
diff --git a/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.hpp
new file mode 100644
index 0000000..83abf67
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LIRAssembler_arm.hpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_LIRASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_C1_LIRASSEMBLER_ARM_HPP
+
+ private:
+
+  // Record the type of the receiver in ReceiverTypeData
+  void type_profile_helper(Register mdo, int mdo_offset_bias,
+                           ciMethodData *md, ciProfileData *data,
+                           Register recv, Register tmp1, Label* update_done);
+  // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot.
+  void setup_md_access(ciMethod* method, int bci,
+                       ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias);
+
+  void typecheck_profile_helper1(ciMethod* method, int bci,
+                                 ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias,
+                                 Register obj, Register mdo, Register data_val, Label* obj_is_null);
+
+  void typecheck_profile_helper2(ciMethodData* md, ciProfileData* data, int mdo_offset_bias,
+                                 Register mdo, Register recv, Register value, Register tmp1,
+                                 Label* profile_cast_success, Label* profile_cast_failure,
+                                 Label* success, Label* failure);
+
+#ifdef AARCH64
+  void long_compare_helper(LIR_Opr opr1, LIR_Opr opr2);
+#endif // AARCH64
+
+  // Saves 4 given registers in reserved argument area.
+  void save_in_reserved_area(Register r1, Register r2, Register r3, Register r4);
+
+  // Restores 4 given registers from reserved argument area.
+  void restore_from_reserved_area(Register r1, Register r2, Register r3, Register r4);
+
+  enum {
+    _call_stub_size = AARCH64_ONLY(32) NOT_AARCH64(16),
+    _call_aot_stub_size = 0,
+    _exception_handler_size = PRODUCT_ONLY(AARCH64_ONLY(256) NOT_AARCH64(68)) NOT_PRODUCT(AARCH64_ONLY(256+216) NOT_AARCH64(68+60)),
+    _deopt_handler_size = AARCH64_ONLY(32) NOT_AARCH64(16)
+  };
+
+ public:
+
+  void verify_reserved_argument_area_size(int args_count) PRODUCT_RETURN;
+
+  void store_parameter(jint c,      int offset_from_sp_in_words);
+  void store_parameter(Metadata* m, int offset_from_sp_in_words);
+
+#endif // CPU_ARM_VM_C1_LIRASSEMBLER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp b/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp
new file mode 100644
index 0000000..539a8fa
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.cpp
@@ -0,0 +1,1767 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_Compilation.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "c1/c1_Instruction.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_LIRGenerator.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "c1/c1_ValueStack.hpp"
+#include "ci/ciArray.hpp"
+#include "ci/ciObjArrayKlass.hpp"
+#include "ci/ciTypeArrayKlass.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "vmreg_arm.inline.hpp"
+
+#ifdef ASSERT
+#define __ gen()->lir(__FILE__, __LINE__)->
+#else
+#define __ gen()->lir()->
+#endif
+
+void LIRItem::load_byte_item() {
+  load_item();
+}
+
+void LIRItem::load_nonconstant() {
+  LIR_Opr r = value()->operand();
+  if (_gen->can_inline_as_constant(value())) {
+    if (!r->is_constant()) {
+      r = LIR_OprFact::value_type(value()->type());
+    }
+    _result = r;
+  } else {
+    load_item();
+  }
+}
+
+//--------------------------------------------------------------
+//               LIRGenerator
+//--------------------------------------------------------------
+
+
+LIR_Opr LIRGenerator::exceptionOopOpr() {
+  return FrameMap::Exception_oop_opr;
+}
+
+LIR_Opr LIRGenerator::exceptionPcOpr()  {
+  return FrameMap::Exception_pc_opr;
+}
+
+LIR_Opr LIRGenerator::syncLockOpr()     {
+  return new_register(T_INT);
+}
+
+LIR_Opr LIRGenerator::syncTempOpr()     {
+  return new_register(T_OBJECT);
+}
+
+LIR_Opr LIRGenerator::getThreadTemp()   {
+  return LIR_OprFact::illegalOpr;
+}
+
+LIR_Opr LIRGenerator::atomicLockOpr() {
+  return LIR_OprFact::illegalOpr;
+}
+
+LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) {
+  LIR_Opr opr;
+  switch (type->tag()) {
+    case intTag:     opr = FrameMap::Int_result_opr;    break;
+    case objectTag:  opr = FrameMap::Object_result_opr; break;
+    case longTag:    opr = FrameMap::Long_result_opr;   break;
+    case floatTag:   opr = FrameMap::Float_result_opr;  break;
+    case doubleTag:  opr = FrameMap::Double_result_opr; break;
+    case addressTag:
+    default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr;
+  }
+  assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch");
+  return opr;
+}
+
+
+LIR_Opr LIRGenerator::rlock_byte(BasicType type) {
+  return new_register(T_INT);
+}
+
+
+//--------- loading items into registers --------------------------------
+
+
+bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const {
+#ifdef AARCH64
+  if (v->type()->as_IntConstant() != NULL) {
+    return v->type()->as_IntConstant()->value() == 0;
+  } else if (v->type()->as_LongConstant() != NULL) {
+    return v->type()->as_LongConstant()->value() == 0;
+  } else if (v->type()->as_ObjectConstant() != NULL) {
+    return v->type()->as_ObjectConstant()->value()->is_null_object();
+  } else if (v->type()->as_FloatConstant() != NULL) {
+    return jint_cast(v->type()->as_FloatConstant()->value()) == 0;
+  } else if (v->type()->as_DoubleConstant() != NULL) {
+    return jlong_cast(v->type()->as_DoubleConstant()->value()) == 0;
+  }
+#endif // AARCH64
+  return false;
+}
+
+
+bool LIRGenerator::can_inline_as_constant(Value v) const {
+  if (v->type()->as_IntConstant() != NULL) {
+    return Assembler::is_arith_imm_in_range(v->type()->as_IntConstant()->value());
+  } else if (v->type()->as_ObjectConstant() != NULL) {
+    return v->type()->as_ObjectConstant()->value()->is_null_object();
+#ifdef AARCH64
+  } else if (v->type()->as_LongConstant() != NULL) {
+    return Assembler::is_arith_imm_in_range(v->type()->as_LongConstant()->value());
+#else
+  } else if (v->type()->as_FloatConstant() != NULL) {
+    return v->type()->as_FloatConstant()->value() == 0.0f;
+  } else if (v->type()->as_DoubleConstant() != NULL) {
+    return v->type()->as_DoubleConstant()->value() == 0.0;
+#endif // AARCH64
+  }
+  return false;
+}
+
+
+bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const {
+  ShouldNotCallThis(); // Not used on ARM
+  return false;
+}
+
+
+#ifdef AARCH64
+
+static bool can_inline_as_constant_in_cmp(Value v) {
+  jlong constant;
+  if (v->type()->as_IntConstant() != NULL) {
+    constant = v->type()->as_IntConstant()->value();
+  } else if (v->type()->as_LongConstant() != NULL) {
+    constant = v->type()->as_LongConstant()->value();
+  } else if (v->type()->as_ObjectConstant() != NULL) {
+    return v->type()->as_ObjectConstant()->value()->is_null_object();
+  } else if (v->type()->as_FloatConstant() != NULL) {
+    return v->type()->as_FloatConstant()->value() == 0.0f;
+  } else if (v->type()->as_DoubleConstant() != NULL) {
+    return v->type()->as_DoubleConstant()->value() == 0.0;
+  } else {
+    return false;
+  }
+
+  return Assembler::is_arith_imm_in_range(constant) || Assembler::is_arith_imm_in_range(-constant);
+}
+
+
+static bool can_inline_as_constant_in_logic(Value v) {
+  if (v->type()->as_IntConstant() != NULL) {
+    return Assembler::LogicalImmediate(v->type()->as_IntConstant()->value(), true).is_encoded();
+  } else if (v->type()->as_LongConstant() != NULL) {
+    return Assembler::LogicalImmediate(v->type()->as_LongConstant()->value(), false).is_encoded();
+  }
+  return false;
+}
+
+
+#endif // AARCH64
+
+
+LIR_Opr LIRGenerator::safepoint_poll_register() {
+  return LIR_OprFact::illegalOpr;
+}
+
+
+static LIR_Opr make_constant(BasicType type, jlong c) {
+  switch (type) {
+    case T_ADDRESS:
+    case T_OBJECT:  return LIR_OprFact::intptrConst(c);
+    case T_LONG:    return LIR_OprFact::longConst(c);
+    case T_INT:     return LIR_OprFact::intConst(c);
+    default: ShouldNotReachHere();
+    return LIR_OprFact::intConst(-1);
+  }
+}
+
+#ifdef AARCH64
+
+void LIRGenerator::add_constant(LIR_Opr src, jlong c, LIR_Opr dest) {
+  if (c == 0) {
+    __ move(src, dest);
+    return;
+  }
+
+  BasicType type = src->type();
+  bool is_neg = (c < 0);
+  c = ABS(c);
+
+  if ((c >> 24) == 0) {
+    for (int shift = 0; shift <= 12; shift += 12) {
+      int part = ((int)c) & (right_n_bits(12) << shift);
+      if (part != 0) {
+        if (is_neg) {
+          __ sub(src, make_constant(type, part), dest);
+        } else {
+          __ add(src, make_constant(type, part), dest);
+        }
+        src = dest;
+      }
+    }
+  } else {
+    __ move(make_constant(type, c), dest);
+    if (is_neg) {
+      __ sub(src, dest, dest);
+    } else {
+      __ add(src, dest, dest);
+    }
+  }
+}
+
+#endif // AARCH64
+
+
+void LIRGenerator::add_large_constant(LIR_Opr src, int c, LIR_Opr dest) {
+  assert(c != 0, "must be");
+#ifdef AARCH64
+  add_constant(src, c, dest);
+#else
+  // Find first non-zero bit
+  int shift = 0;
+  while ((c & (3 << shift)) == 0) {
+    shift += 2;
+  }
+  // Add the least significant part of the constant
+  int mask = 0xff << shift;
+  __ add(src, LIR_OprFact::intConst(c & mask), dest);
+  // Add up to 3 other parts of the constant;
+  // each of them can be represented as rotated_imm
+  if (c & (mask << 8)) {
+    __ add(dest, LIR_OprFact::intConst(c & (mask << 8)), dest);
+  }
+  if (c & (mask << 16)) {
+    __ add(dest, LIR_OprFact::intConst(c & (mask << 16)), dest);
+  }
+  if (c & (mask << 24)) {
+    __ add(dest, LIR_OprFact::intConst(c & (mask << 24)), dest);
+  }
+#endif // AARCH64
+}
+
+static LIR_Address* make_address(LIR_Opr base, LIR_Opr index, LIR_Address::Scale scale, BasicType type) {
+  return new LIR_Address(base, index, scale, 0, type);
+}
+
+LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
+                                            int shift, int disp, BasicType type) {
+  assert(base->is_register(), "must be");
+
+  if (index->is_constant()) {
+    disp += index->as_constant_ptr()->as_jint() << shift;
+    index = LIR_OprFact::illegalOpr;
+  }
+
+#ifndef AARCH64
+  if (base->type() == T_LONG) {
+    LIR_Opr tmp = new_register(T_INT);
+    __ convert(Bytecodes::_l2i, base, tmp);
+    base = tmp;
+  }
+  if (index != LIR_OprFact::illegalOpr && index->type() == T_LONG) {
+    LIR_Opr tmp = new_register(T_INT);
+    __ convert(Bytecodes::_l2i, index, tmp);
+    index = tmp;
+  }
+  // At this point base and index should be all ints and not constants
+  assert(base->is_single_cpu() && !base->is_constant(), "base should be an non-constant int");
+  assert(index->is_illegal() || (index->type() == T_INT && !index->is_constant()), "index should be an non-constant int");
+#endif
+
+  int max_disp;
+  bool disp_is_in_range;
+  bool embedded_shift;
+
+#ifdef AARCH64
+  int align = exact_log2(type2aelembytes(type, true));
+  assert((disp & right_n_bits(align)) == 0, "displacement is not aligned");
+  assert(shift == 0 || shift == align, "shift should be zero or equal to embedded align");
+  max_disp = (1 << 12) << align;
+
+  if (disp >= 0) {
+    disp_is_in_range = Assembler::is_unsigned_imm_in_range(disp, 12, align);
+  } else {
+    disp_is_in_range = Assembler::is_imm_in_range(disp, 9, 0);
+  }
+
+  embedded_shift = true;
+#else
+  switch (type) {
+    case T_BYTE:
+    case T_SHORT:
+    case T_CHAR:
+      max_disp = 256;          // ldrh, ldrsb encoding has 8-bit offset
+      embedded_shift = false;
+      break;
+    case T_FLOAT:
+    case T_DOUBLE:
+      max_disp = 1024;         // flds, fldd have 8-bit offset multiplied by 4
+      embedded_shift = false;
+      break;
+    case T_LONG:
+      max_disp = 4096;
+      embedded_shift = false;
+      break;
+    default:
+      max_disp = 4096;         // ldr, ldrb allow 12-bit offset
+      embedded_shift = true;
+  }
+
+  disp_is_in_range = (-max_disp < disp && disp < max_disp);
+#endif // !AARCH64
+
+  if (index->is_register()) {
+    LIR_Opr tmp = new_pointer_register();
+    if (!disp_is_in_range) {
+      add_large_constant(base, disp, tmp);
+      base = tmp;
+      disp = 0;
+    }
+    LIR_Address* addr = make_address(base, index, (LIR_Address::Scale)shift, type);
+    if (disp == 0 && embedded_shift) {
+      // can use ldr/str instruction with register index
+      return addr;
+    } else {
+      LIR_Opr tmp = new_pointer_register();
+      __ add(base, LIR_OprFact::address(addr), tmp); // add with shifted/extended register
+      return new LIR_Address(tmp, disp, type);
+    }
+  }
+
+  // If the displacement is too large to be inlined into LDR instruction,
+  // generate large constant with additional sequence of ADD instructions
+  int excess_disp = disp & ~(max_disp - 1);
+  if (excess_disp != 0) {
+    LIR_Opr tmp = new_pointer_register();
+    add_large_constant(base, excess_disp, tmp);
+    base = tmp;
+  }
+  return new LIR_Address(base, disp & (max_disp - 1), type);
+}
+
+
+LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
+                                              BasicType type, bool needs_card_mark) {
+  int base_offset = arrayOopDesc::base_offset_in_bytes(type);
+  int elem_size = type2aelembytes(type);
+
+  if (index_opr->is_constant()) {
+    int offset = base_offset + index_opr->as_constant_ptr()->as_jint() * elem_size;
+    if (needs_card_mark) {
+      LIR_Opr base_opr = new_pointer_register();
+      add_large_constant(array_opr, offset, base_opr);
+      return new LIR_Address(base_opr, (intx)0, type);
+    } else {
+      return generate_address(array_opr, offset, type);
+    }
+  } else {
+    assert(index_opr->is_register(), "must be");
+    int scale = exact_log2(elem_size);
+    if (needs_card_mark) {
+      LIR_Opr base_opr = new_pointer_register();
+      LIR_Address* addr = make_address(base_opr, index_opr, (LIR_Address::Scale)scale, type);
+      __ add(array_opr, LIR_OprFact::intptrConst(base_offset), base_opr);
+      __ add(base_opr, LIR_OprFact::address(addr), base_opr); // add with shifted/extended register
+      return new LIR_Address(base_opr, type);
+    } else {
+      return generate_address(array_opr, index_opr, scale, base_offset, type);
+    }
+  }
+}
+
+
+LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
+  assert(type == T_LONG || type == T_INT, "should be");
+  LIR_Opr r = make_constant(type, x);
+#ifdef AARCH64
+  bool imm_in_range = Assembler::LogicalImmediate(x, type == T_INT).is_encoded();
+#else
+  bool imm_in_range = AsmOperand::is_rotated_imm(x);
+#endif // AARCH64
+  if (!imm_in_range) {
+    LIR_Opr tmp = new_register(type);
+    __ move(r, tmp);
+    return tmp;
+  }
+  return r;
+}
+
+
+void LIRGenerator::increment_counter(address counter, BasicType type, int step) {
+  LIR_Opr pointer = new_pointer_register();
+  __ move(LIR_OprFact::intptrConst(counter), pointer);
+  LIR_Address* addr = new LIR_Address(pointer, type);
+  increment_counter(addr, step);
+}
+
+
+void LIRGenerator::increment_counter(LIR_Address* addr, int step) {
+  LIR_Opr temp = new_register(addr->type());
+  __ move(addr, temp);
+  __ add(temp, make_constant(addr->type(), step), temp);
+  __ move(temp, addr);
+}
+
+
+void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) {
+  __ load(new LIR_Address(base, disp, T_INT), FrameMap::LR_opr, info);
+  __ cmp(condition, FrameMap::LR_opr, c);
+}
+
+
+void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, int disp, BasicType type, CodeEmitInfo* info) {
+  __ load(new LIR_Address(base, disp, type), FrameMap::LR_opr, info);
+  __ cmp(condition, reg, FrameMap::LR_opr);
+}
+
+
+bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) {
+  assert(left != result, "should be different registers");
+  if (is_power_of_2(c + 1)) {
+#ifdef AARCH64
+    __ shift_left(left, log2_intptr(c + 1), result);
+    __ sub(result, left, result);
+#else
+    LIR_Address::Scale scale = (LIR_Address::Scale) log2_intptr(c + 1);
+    LIR_Address* addr = new LIR_Address(left, left, scale, 0, T_INT);
+    __ sub(LIR_OprFact::address(addr), left, result); // rsb with shifted register
+#endif // AARCH64
+    return true;
+  } else if (is_power_of_2(c - 1)) {
+    LIR_Address::Scale scale = (LIR_Address::Scale) log2_intptr(c - 1);
+    LIR_Address* addr = new LIR_Address(left, left, scale, 0, T_INT);
+    __ add(left, LIR_OprFact::address(addr), result); // add with shifted register
+    return true;
+  }
+  return false;
+}
+
+
+void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp) {
+  assert(item->type() == T_INT, "other types are not expected");
+  __ store(item, new LIR_Address(FrameMap::SP_opr, in_bytes(offset_from_sp), item->type()));
+}
+
+void LIRGenerator::set_card(LIR_Opr value, LIR_Address* card_addr) {
+  assert(CardTableModRefBS::dirty_card_val() == 0,
+    "Cannot use ZR register (aarch64) or the register containing the card table base address directly (aarch32) otherwise");
+#ifdef AARCH64
+  // AARCH64 has a register that is constant zero. We can use that one to set the
+  // value in the card table to dirty.
+  __ move(FrameMap::ZR_opr, card_addr);
+#else // AARCH64
+  CardTableModRefBS* ct = (CardTableModRefBS*)_bs;
+  if(((intx)ct->byte_map_base & 0xff) == 0) {
+    // If the card table base address is aligned to 256 bytes, we can use the register
+    // that contains the card_table_base_address.
+    __ move(value, card_addr);
+  } else {
+    // Otherwise we need to create a register containing that value.
+    LIR_Opr tmp_zero = new_register(T_INT);
+    __ move(LIR_OprFact::intConst(CardTableModRefBS::dirty_card_val()), tmp_zero);
+    __ move(tmp_zero, card_addr);
+  }
+#endif // AARCH64
+}
+
+void LIRGenerator::CardTableModRef_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base) {
+  assert(addr->is_register(), "must be a register at this point");
+
+  LIR_Opr tmp = FrameMap::LR_ptr_opr;
+
+  // TODO-AARCH64: check performance
+  bool load_card_table_base_const = AARCH64_ONLY(false) NOT_AARCH64(VM_Version::supports_movw());
+  if (load_card_table_base_const) {
+    __ move((LIR_Opr)card_table_base, tmp);
+  } else {
+    __ move(new LIR_Address(FrameMap::Rthread_opr, in_bytes(JavaThread::card_table_base_offset()), T_ADDRESS), tmp);
+  }
+
+#ifdef AARCH64
+  LIR_Address* shifted_reg_operand = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTableModRefBS::card_shift, 0, T_BYTE);
+  LIR_Opr tmp2 = tmp;
+  __ add(tmp, LIR_OprFact::address(shifted_reg_operand), tmp2); // tmp2 = tmp + (addr >> CardTableModRefBS::card_shift)
+  LIR_Address* card_addr = new LIR_Address(tmp2, T_BYTE);
+#else
+  // Use unsigned type T_BOOLEAN here rather than (signed) T_BYTE since signed load
+  // byte instruction does not support the addressing mode we need.
+  LIR_Address* card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTableModRefBS::card_shift, 0, T_BOOLEAN);
+#endif
+  if (UseCondCardMark) {
+    if (UseConcMarkSweepGC) {
+      __ membar_storeload();
+    }
+    LIR_Opr cur_value = new_register(T_INT);
+    __ move(card_addr, cur_value);
+
+    LabelObj* L_already_dirty = new LabelObj();
+    __ cmp(lir_cond_equal, cur_value, LIR_OprFact::intConst(CardTableModRefBS::dirty_card_val()));
+    __ branch(lir_cond_equal, T_BYTE, L_already_dirty->label());
+    set_card(tmp, card_addr);
+    __ branch_destination(L_already_dirty->label());
+  } else {
+    if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+      __ membar_storestore();
+    }
+    set_card(tmp, card_addr);
+  }
+}
+
+//----------------------------------------------------------------------
+//             visitor functions
+//----------------------------------------------------------------------
+
+
+void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
+  assert(x->is_pinned(),"");
+  bool needs_range_check = x->compute_needs_range_check();
+  bool use_length = x->length() != NULL;
+  bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
+  bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
+                                         !get_jobject_constant(x->value())->is_null_object() ||
+                                         x->should_profile());
+
+  LIRItem array(x->array(), this);
+  LIRItem index(x->index(), this);
+  LIRItem value(x->value(), this);
+  LIRItem length(this);
+
+  array.load_item();
+  index.load_nonconstant();
+
+  if (use_length && needs_range_check) {
+    length.set_instruction(x->length());
+    length.load_item();
+  }
+  if (needs_store_check || x->check_boolean()) {
+    value.load_item();
+  } else {
+    value.load_for_store(x->elt_type());
+  }
+
+  set_no_result(x);
+
+  // the CodeEmitInfo must be duplicated for each different
+  // LIR-instruction because spilling can occur anywhere between two
+  // instructions and so the debug information must be different
+  CodeEmitInfo* range_check_info = state_for(x);
+  CodeEmitInfo* null_check_info = NULL;
+  if (x->needs_null_check()) {
+    null_check_info = new CodeEmitInfo(range_check_info);
+  }
+
+  // emit array address setup early so it schedules better
+  LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
+
+  if (GenerateRangeChecks && needs_range_check) {
+    if (use_length) {
+      __ cmp(lir_cond_belowEqual, length.result(), index.result());
+      __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
+    } else {
+      array_range_check(array.result(), index.result(), null_check_info, range_check_info);
+      // range_check also does the null check
+      null_check_info = NULL;
+    }
+  }
+
+  if (GenerateArrayStoreCheck && needs_store_check) {
+    LIR_Opr tmp1 = FrameMap::R0_oop_opr;
+    LIR_Opr tmp2 = FrameMap::R1_oop_opr;
+    CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
+    __ store_check(value.result(), array.result(), tmp1, tmp2,
+                   LIR_OprFact::illegalOpr, store_check_info,
+                   x->profiled_method(), x->profiled_bci());
+  }
+
+#if INCLUDE_ALL_GCS
+  if (obj_store) {
+    // Needs GC write barriers.
+    pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
+                true /* do_load */, false /* patch */, NULL);
+  }
+#endif // INCLUDE_ALL_GCS
+
+  LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
+  __ move(result, array_addr, null_check_info);
+  if (obj_store) {
+    post_barrier(LIR_OprFact::address(array_addr), value.result());
+  }
+}
+
+
+void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
+  assert(x->is_pinned(),"");
+  LIRItem obj(x->obj(), this);
+  obj.load_item();
+  set_no_result(x);
+
+  LIR_Opr lock = new_pointer_register();
+  LIR_Opr hdr  = new_pointer_register();
+
+  // Need a scratch register for biased locking on arm
+  LIR_Opr scratch = LIR_OprFact::illegalOpr;
+  if(UseBiasedLocking) {
+    scratch = new_pointer_register();
+  } else {
+    scratch = atomicLockOpr();
+  }
+
+  CodeEmitInfo* info_for_exception = NULL;
+  if (x->needs_null_check()) {
+    info_for_exception = state_for(x);
+  }
+
+  CodeEmitInfo* info = state_for(x, x->state(), true);
+  monitor_enter(obj.result(), lock, hdr, scratch,
+                x->monitor_no(), info_for_exception, info);
+}
+
+
+void LIRGenerator::do_MonitorExit(MonitorExit* x) {
+  assert(x->is_pinned(),"");
+  LIRItem obj(x->obj(), this);
+  obj.dont_load_item();
+  set_no_result(x);
+
+  LIR_Opr obj_temp = new_pointer_register();
+  LIR_Opr lock     = new_pointer_register();
+  LIR_Opr hdr      = new_pointer_register();
+
+  monitor_exit(obj_temp, lock, hdr, atomicLockOpr(), x->monitor_no());
+}
+
+
+// _ineg, _lneg, _fneg, _dneg
+void LIRGenerator::do_NegateOp(NegateOp* x) {
+#ifdef __SOFTFP__
+  address runtime_func = NULL;
+  ValueTag tag = x->type()->tag();
+  if (tag == floatTag) {
+    runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::fneg);
+  } else if (tag == doubleTag) {
+    runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dneg);
+  }
+  if (runtime_func != NULL) {
+    set_result(x, call_runtime(x->x(), runtime_func, x->type(), NULL));
+    return;
+  }
+#endif // __SOFTFP__
+  LIRItem value(x->x(), this);
+  value.load_item();
+  LIR_Opr reg = rlock_result(x);
+  __ negate(value.result(), reg);
+}
+
+
+// for  _fadd, _fmul, _fsub, _fdiv, _frem
+//      _dadd, _dmul, _dsub, _ddiv, _drem
+void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
+  address runtime_func;
+  switch (x->op()) {
+    case Bytecodes::_frem:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::frem);
+      break;
+    case Bytecodes::_drem:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::drem);
+      break;
+#ifdef __SOFTFP__
+    // Call function compiled with -msoft-float.
+
+      // __aeabi_XXXX_glibc: Imported code from glibc soft-fp bundle for calculation accuracy improvement. See CR 6757269.
+
+    case Bytecodes::_fadd:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_fadd_glibc);
+      break;
+    case Bytecodes::_fmul:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_fmul);
+      break;
+    case Bytecodes::_fsub:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_fsub_glibc);
+      break;
+    case Bytecodes::_fdiv:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_fdiv);
+      break;
+    case Bytecodes::_dadd:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_dadd_glibc);
+      break;
+    case Bytecodes::_dmul:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_dmul);
+      break;
+    case Bytecodes::_dsub:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_dsub_glibc);
+      break;
+    case Bytecodes::_ddiv:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_ddiv);
+      break;
+    default:
+      ShouldNotReachHere();
+#else // __SOFTFP__
+    default: {
+      LIRItem left(x->x(), this);
+      LIRItem right(x->y(), this);
+      left.load_item();
+      right.load_item();
+      rlock_result(x);
+      arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp());
+      return;
+    }
+#endif // __SOFTFP__
+  }
+
+  LIR_Opr result = call_runtime(x->x(), x->y(), runtime_func, x->type(), NULL);
+  set_result(x, result);
+}
+
+
+void LIRGenerator::make_div_by_zero_check(LIR_Opr right_arg, BasicType type, CodeEmitInfo* info) {
+  assert(right_arg->is_register(), "must be");
+  __ cmp(lir_cond_equal, right_arg, make_constant(type, 0));
+  __ branch(lir_cond_equal, type, new DivByZeroStub(info));
+}
+
+
+// for  _ladd, _lmul, _lsub, _ldiv, _lrem
+void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
+  CodeEmitInfo* info = NULL;
+  if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) {
+    info = state_for(x);
+  }
+
+#ifdef AARCH64
+  LIRItem left(x->x(), this);
+  LIRItem right(x->y(), this);
+  LIRItem* left_arg = &left;
+  LIRItem* right_arg = &right;
+
+  // Test if instr is commutative and if we should swap
+  if (x->is_commutative() && left.is_constant()) {
+    left_arg = &right;
+    right_arg = &left;
+  }
+
+  left_arg->load_item();
+  switch (x->op()) {
+    case Bytecodes::_ldiv:
+      right_arg->load_item();
+      make_div_by_zero_check(right_arg->result(), T_LONG, info);
+      __ idiv(left_arg->result(), right_arg->result(), rlock_result(x), LIR_OprFact::illegalOpr, NULL);
+      break;
+
+    case Bytecodes::_lrem: {
+      right_arg->load_item();
+      make_div_by_zero_check(right_arg->result(), T_LONG, info);
+      // a % b is implemented with 2 instructions:
+      // tmp = a/b       (sdiv)
+      // res = a - b*tmp (msub)
+      LIR_Opr tmp = FrameMap::as_long_opr(Rtemp);
+      __ irem(left_arg->result(), right_arg->result(), rlock_result(x), tmp, NULL);
+      break;
+    }
+
+    case Bytecodes::_lmul:
+      if (right_arg->is_constant() && is_power_of_2_long(right_arg->get_jlong_constant())) {
+        right_arg->dont_load_item();
+        __ shift_left(left_arg->result(), exact_log2_long(right_arg->get_jlong_constant()), rlock_result(x));
+      } else {
+        right_arg->load_item();
+        __ mul(left_arg->result(), right_arg->result(), rlock_result(x));
+      }
+      break;
+
+    case Bytecodes::_ladd:
+    case Bytecodes::_lsub:
+      if (right_arg->is_constant()) {
+        jlong c = right_arg->get_jlong_constant();
+        add_constant(left_arg->result(), (x->op() == Bytecodes::_ladd) ? c : -c, rlock_result(x));
+      } else {
+        right_arg->load_item();
+        arithmetic_op_long(x->op(), rlock_result(x), left_arg->result(), right_arg->result(), NULL);
+      }
+      break;
+
+    default:
+      ShouldNotReachHere();
+  }
+#else
+  switch (x->op()) {
+    case Bytecodes::_ldiv:
+    case Bytecodes::_lrem: {
+      LIRItem right(x->y(), this);
+      right.load_item();
+      make_div_by_zero_check(right.result(), T_LONG, info);
+    }
+    // Fall through
+    case Bytecodes::_lmul: {
+      address entry;
+      switch (x->op()) {
+      case Bytecodes::_lrem:
+        entry = CAST_FROM_FN_PTR(address, SharedRuntime::lrem);
+        break;
+      case Bytecodes::_ldiv:
+        entry = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv);
+        break;
+      case Bytecodes::_lmul:
+        entry = CAST_FROM_FN_PTR(address, SharedRuntime::lmul);
+        break;
+      default:
+        ShouldNotReachHere();
+      }
+      LIR_Opr result = call_runtime(x->y(), x->x(), entry, x->type(), NULL);
+      set_result(x, result);
+      break;
+    }
+    case Bytecodes::_ladd:
+    case Bytecodes::_lsub: {
+      LIRItem left(x->x(), this);
+      LIRItem right(x->y(), this);
+      left.load_item();
+      right.load_item();
+      rlock_result(x);
+      arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL);
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+#endif // AARCH64
+}
+
+
+// for: _iadd, _imul, _isub, _idiv, _irem
+void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
+  bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem;
+  LIRItem left(x->x(), this);
+  LIRItem right(x->y(), this);
+  LIRItem* left_arg = &left;
+  LIRItem* right_arg = &right;
+
+  // Test if instr is commutative and if we should swap
+  if (x->is_commutative() && left.is_constant()) {
+    left_arg = &right;
+    right_arg = &left;
+  }
+
+  if (is_div_rem) {
+    CodeEmitInfo* info = state_for(x);
+    if (x->op() == Bytecodes::_idiv && right_arg->is_constant() && is_power_of_2(right_arg->get_jint_constant())) {
+      left_arg->load_item();
+      right_arg->dont_load_item();
+      LIR_Opr tmp = LIR_OprFact::illegalOpr;
+      LIR_Opr result = rlock_result(x);
+      __ idiv(left_arg->result(), right_arg->result(), result, tmp, info);
+    } else {
+#ifdef AARCH64
+      left_arg->load_item();
+      right_arg->load_item();
+      make_div_by_zero_check(right_arg->result(), T_INT, info);
+      if (x->op() == Bytecodes::_idiv) {
+        __ idiv(left_arg->result(), right_arg->result(), rlock_result(x), LIR_OprFact::illegalOpr, NULL);
+      } else {
+        // a % b is implemented with 2 instructions:
+        // tmp = a/b       (sdiv)
+        // res = a - b*tmp (msub)
+        LIR_Opr tmp = FrameMap::as_opr(Rtemp);
+        __ irem(left_arg->result(), right_arg->result(), rlock_result(x), tmp, NULL);
+      }
+#else
+      left_arg->load_item_force(FrameMap::R0_opr);
+      right_arg->load_item_force(FrameMap::R2_opr);
+      LIR_Opr tmp = FrameMap::R1_opr;
+      LIR_Opr result = rlock_result(x);
+      LIR_Opr out_reg;
+      if (x->op() == Bytecodes::_irem) {
+        out_reg = FrameMap::R0_opr;
+        __ irem(left_arg->result(), right_arg->result(), out_reg, tmp, info);
+      } else if (x->op() == Bytecodes::_idiv) {
+        out_reg = FrameMap::R1_opr;
+        __ idiv(left_arg->result(), right_arg->result(), out_reg, tmp, info);
+      }
+      __ move(out_reg, result);
+#endif // AARCH64
+    }
+
+#ifdef AARCH64
+  } else if (((x->op() == Bytecodes::_iadd) || (x->op() == Bytecodes::_isub)) && right_arg->is_constant()) {
+    left_arg->load_item();
+    jint c = right_arg->get_jint_constant();
+    right_arg->dont_load_item();
+    add_constant(left_arg->result(), (x->op() == Bytecodes::_iadd) ? c : -c, rlock_result(x));
+#endif // AARCH64
+
+  } else {
+    left_arg->load_item();
+    if (x->op() == Bytecodes::_imul && right_arg->is_constant()) {
+      int c = right_arg->get_jint_constant();
+      if (c > 0 && (is_power_of_2(c) || is_power_of_2(c - 1) || is_power_of_2(c + 1))) {
+        right_arg->dont_load_item();
+      } else {
+        right_arg->load_item();
+      }
+    } else {
+      AARCH64_ONLY(assert(!right_arg->is_constant(), "constant right_arg is already handled by this moment");)
+      right_arg->load_nonconstant();
+    }
+    rlock_result(x);
+    assert(right_arg->is_constant() || right_arg->is_register(), "wrong state of right");
+    arithmetic_op_int(x->op(), x->operand(), left_arg->result(), right_arg->result(), NULL);
+  }
+}
+
+
+void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
+  ValueTag tag = x->type()->tag();
+  assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters");
+  switch (tag) {
+    case floatTag:
+    case doubleTag:  do_ArithmeticOp_FPU(x);  return;
+    case longTag:    do_ArithmeticOp_Long(x); return;
+    case intTag:     do_ArithmeticOp_Int(x);  return;
+  }
+  ShouldNotReachHere();
+}
+
+
+// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
+void LIRGenerator::do_ShiftOp(ShiftOp* x) {
+  LIRItem value(x->x(), this);
+  LIRItem count(x->y(), this);
+
+#ifndef AARCH64
+  if (value.type()->is_long()) {
+    count.set_destroys_register();
+  }
+#endif // !AARCH64
+
+  if (count.is_constant()) {
+    assert(count.type()->as_IntConstant() != NULL, "should be");
+    count.dont_load_item();
+  } else {
+    count.load_item();
+  }
+  value.load_item();
+
+  LIR_Opr res = rlock_result(x);
+  shift_op(x->op(), res, value.result(), count.result(), LIR_OprFact::illegalOpr);
+}
+
+
+// _iand, _land, _ior, _lor, _ixor, _lxor
+void LIRGenerator::do_LogicOp(LogicOp* x) {
+  LIRItem left(x->x(), this);
+  LIRItem right(x->y(), this);
+
+  left.load_item();
+
+#ifdef AARCH64
+  if (right.is_constant() && can_inline_as_constant_in_logic(right.value())) {
+    right.dont_load_item();
+  } else {
+    right.load_item();
+  }
+#else
+  right.load_nonconstant();
+#endif // AARCH64
+
+  logic_op(x->op(), rlock_result(x), left.result(), right.result());
+}
+
+
+// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg
+void LIRGenerator::do_CompareOp(CompareOp* x) {
+#ifdef __SOFTFP__
+  address runtime_func;
+  switch (x->op()) {
+    case Bytecodes::_fcmpl:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::fcmpl);
+      break;
+    case Bytecodes::_fcmpg:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::fcmpg);
+      break;
+    case Bytecodes::_dcmpl:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dcmpl);
+      break;
+    case Bytecodes::_dcmpg:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dcmpg);
+      break;
+    case Bytecodes::_lcmp: {
+        LIRItem left(x->x(), this);
+        LIRItem right(x->y(), this);
+        left.load_item();
+        right.load_nonconstant();
+        LIR_Opr reg = rlock_result(x);
+         __ lcmp2int(left.result(), right.result(), reg);
+        return;
+      }
+    default:
+      ShouldNotReachHere();
+  }
+  LIR_Opr result = call_runtime(x->x(), x->y(), runtime_func, x->type(), NULL);
+  set_result(x, result);
+#else // __SOFTFP__
+  LIRItem left(x->x(), this);
+  LIRItem right(x->y(), this);
+  left.load_item();
+
+#ifdef AARCH64
+  if (right.is_constant() && can_inline_as_constant_in_cmp(right.value())) {
+    right.dont_load_item();
+  } else {
+    right.load_item();
+  }
+#else
+  right.load_nonconstant();
+#endif // AARCH64
+
+  LIR_Opr reg = rlock_result(x);
+
+  if (x->x()->type()->is_float_kind()) {
+    Bytecodes::Code code = x->op();
+    __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl));
+  } else if (x->x()->type()->tag() == longTag) {
+    __ lcmp2int(left.result(), right.result(), reg);
+  } else {
+    ShouldNotReachHere();
+  }
+#endif // __SOFTFP__
+}
+
+
+void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
+  assert(x->number_of_arguments() == 4, "wrong type");
+  LIRItem obj   (x->argument_at(0), this);  // object
+  LIRItem offset(x->argument_at(1), this);  // offset of field
+  LIRItem cmp   (x->argument_at(2), this);  // value to compare with field
+  LIRItem val   (x->argument_at(3), this);  // replace field with val if matches cmp
+
+  LIR_Opr addr = new_pointer_register();
+  LIR_Opr tmp1 = LIR_OprFact::illegalOpr;
+  LIR_Opr tmp2 = LIR_OprFact::illegalOpr;
+
+  // get address of field
+  obj.load_item();
+  offset.load_item();
+  cmp.load_item();
+  val.load_item();
+
+  __ add(obj.result(), offset.result(), addr);
+  LIR_Opr result = rlock_result(x);
+
+  if (type == objectType) {
+#if INCLUDE_ALL_GCS
+    // Do the pre-write barrier, if any.
+    pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
+                true /* do_load */, false /* patch */, NULL);
+#endif // INCLUDE_ALL_GCS
+#ifdef AARCH64
+    if (UseCompressedOops) {
+      tmp1 = new_pointer_register();
+      tmp2 = new_pointer_register();
+    }
+#endif // AARCH64
+    __ cas_obj(addr, cmp.result(), val.result(), tmp1, tmp2, result);
+    post_barrier(addr, val.result());
+  }
+  else if (type == intType) {
+    __ cas_int(addr, cmp.result(), val.result(), tmp1, tmp1, result);
+  }
+  else if (type == longType) {
+#ifndef AARCH64
+    tmp1 = new_register(T_LONG);
+#endif // !AARCH64
+    __ cas_long(addr, cmp.result(), val.result(), tmp1, tmp2, result);
+  }
+  else {
+    ShouldNotReachHere();
+  }
+}
+
+
+void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
+  address runtime_func;
+  switch (x->id()) {
+    case vmIntrinsics::_dabs: {
+#ifdef __SOFTFP__
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dabs);
+      break;
+#else
+      assert(x->number_of_arguments() == 1, "wrong type");
+      LIRItem value(x->argument_at(0), this);
+      value.load_item();
+      __ abs(value.result(), rlock_result(x), LIR_OprFact::illegalOpr);
+      return;
+#endif // __SOFTFP__
+    }
+    case vmIntrinsics::_dsqrt: {
+#ifdef __SOFTFP__
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt);
+      break;
+#else
+      assert(x->number_of_arguments() == 1, "wrong type");
+      LIRItem value(x->argument_at(0), this);
+      value.load_item();
+      __ sqrt(value.result(), rlock_result(x), LIR_OprFact::illegalOpr);
+      return;
+#endif // __SOFTFP__
+    }
+    case vmIntrinsics::_dsin:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
+      break;
+    case vmIntrinsics::_dcos:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
+      break;
+    case vmIntrinsics::_dtan:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
+      break;
+    case vmIntrinsics::_dlog:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
+      break;
+    case vmIntrinsics::_dlog10:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
+      break;
+    case vmIntrinsics::_dexp:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
+      break;
+    case vmIntrinsics::_dpow:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::dpow);
+      break;
+    default:
+      ShouldNotReachHere();
+      return;
+  }
+
+  LIR_Opr result;
+  if (x->number_of_arguments() == 1) {
+    result = call_runtime(x->argument_at(0), runtime_func, x->type(), NULL);
+  } else {
+    assert(x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow, "unexpected intrinsic");
+    result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_func, x->type(), NULL);
+  }
+  set_result(x, result);
+}
+
+void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
+  fatal("FMA intrinsic is not implemented on this platform");
+}
+
+void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
+  fatal("vectorizedMismatch intrinsic is not implemented on this platform");
+}
+
+void LIRGenerator::do_ArrayCopy(Intrinsic* x) {
+  CodeEmitInfo* info = state_for(x, x->state());
+  assert(x->number_of_arguments() == 5, "wrong type");
+  LIRItem src(x->argument_at(0), this);
+  LIRItem src_pos(x->argument_at(1), this);
+  LIRItem dst(x->argument_at(2), this);
+  LIRItem dst_pos(x->argument_at(3), this);
+  LIRItem length(x->argument_at(4), this);
+
+  // We put arguments into the same registers which are used for a Java call.
+  // Note: we used fixed registers for all arguments because all registers
+  // are caller-saved, so register allocator treats them all as used.
+  src.load_item_force    (FrameMap::R0_oop_opr);
+  src_pos.load_item_force(FrameMap::R1_opr);
+  dst.load_item_force    (FrameMap::R2_oop_opr);
+  dst_pos.load_item_force(FrameMap::R3_opr);
+  length.load_item_force (FrameMap::R4_opr);
+  LIR_Opr tmp =          (FrameMap::R5_opr);
+  set_no_result(x);
+
+  int flags;
+  ciArrayKlass* expected_type;
+  arraycopy_helper(x, &flags, &expected_type);
+  __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(),
+               tmp, expected_type, flags, info);
+}
+
+void LIRGenerator::do_update_CRC32(Intrinsic* x) {
+  fatal("CRC32 intrinsic is not implemented on this platform");
+}
+
+void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
+  Unimplemented();
+}
+
+void LIRGenerator::do_Convert(Convert* x) {
+  address runtime_func;
+  switch (x->op()) {
+#ifndef AARCH64
+    case Bytecodes::_l2f:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::l2f);
+      break;
+    case Bytecodes::_l2d:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::l2d);
+      break;
+    case Bytecodes::_f2l:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::f2l);
+      break;
+    case Bytecodes::_d2l:
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::d2l);
+      break;
+#ifdef __SOFTFP__
+    case Bytecodes::_f2d:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_f2d);
+      break;
+    case Bytecodes::_d2f:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_d2f);
+      break;
+    case Bytecodes::_i2f:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_i2f);
+      break;
+    case Bytecodes::_i2d:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_i2d);
+      break;
+    case Bytecodes::_f2i:
+      runtime_func = CAST_FROM_FN_PTR(address, __aeabi_f2iz);
+      break;
+    case Bytecodes::_d2i:
+      // This is implemented in hard float in assembler on arm but a call
+      // on other platforms.
+      runtime_func = CAST_FROM_FN_PTR(address, SharedRuntime::d2i);
+      break;
+#endif // __SOFTFP__
+#endif // !AARCH64
+    default: {
+      LIRItem value(x->value(), this);
+      value.load_item();
+      LIR_Opr reg = rlock_result(x);
+      __ convert(x->op(), value.result(), reg, NULL);
+      return;
+    }
+  }
+
+  LIR_Opr result = call_runtime(x->value(), runtime_func, x->type(), NULL);
+  set_result(x, result);
+}
+
+
+void LIRGenerator::do_NewInstance(NewInstance* x) {
+  print_if_not_loaded(x);
+
+  CodeEmitInfo* info = state_for(x, x->state());
+  LIR_Opr reg = result_register_for(x->type());  // R0 is required by runtime call in NewInstanceStub::emit_code
+  LIR_Opr klass_reg = FrameMap::R1_metadata_opr; // R1 is required by runtime call in NewInstanceStub::emit_code
+  LIR_Opr tmp1 = new_register(objectType);
+  LIR_Opr tmp2 = new_register(objectType);
+  LIR_Opr tmp3 = FrameMap::LR_oop_opr;
+
+  new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3,
+               LIR_OprFact::illegalOpr, klass_reg, info);
+
+  LIR_Opr result = rlock_result(x);
+  __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
+  // Evaluate state_for() first, because it can emit code
+  // with the same fixed registers that are used here (R1, R2)
+  CodeEmitInfo* info = state_for(x, x->state());
+  LIRItem length(x->length(), this);
+
+  length.load_item_force(FrameMap::R2_opr);      // R2 is required by runtime call in NewTypeArrayStub::emit_code
+  LIR_Opr len = length.result();
+
+  LIR_Opr reg = result_register_for(x->type());  // R0 is required by runtime call in NewTypeArrayStub::emit_code
+  LIR_Opr klass_reg = FrameMap::R1_metadata_opr; // R1 is required by runtime call in NewTypeArrayStub::emit_code
+
+  LIR_Opr tmp1 = new_register(objectType);
+  LIR_Opr tmp2 = new_register(objectType);
+  LIR_Opr tmp3 = FrameMap::LR_oop_opr;
+  LIR_Opr tmp4 = LIR_OprFact::illegalOpr;
+
+  BasicType elem_type = x->elt_type();
+  __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
+
+  CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
+  __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);
+
+  LIR_Opr result = rlock_result(x);
+  __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewObjectArray(NewObjectArray* x) {
+  // Evaluate state_for() first, because it can emit code
+  // with the same fixed registers that are used here (R1, R2)
+  CodeEmitInfo* info = state_for(x, x->state());
+  LIRItem length(x->length(), this);
+
+  length.load_item_force(FrameMap::R2_opr);           // R2 is required by runtime call in NewObjectArrayStub::emit_code
+  LIR_Opr len = length.result();
+
+  CodeEmitInfo* patching_info = NULL;
+  if (!x->klass()->is_loaded() || PatchALot) {
+    patching_info = state_for(x, x->state_before());
+  }
+
+  LIR_Opr reg = result_register_for(x->type());       // R0 is required by runtime call in NewObjectArrayStub::emit_code
+  LIR_Opr klass_reg = FrameMap::R1_metadata_opr;      // R1 is required by runtime call in NewObjectArrayStub::emit_code
+
+  LIR_Opr tmp1 = new_register(objectType);
+  LIR_Opr tmp2 = new_register(objectType);
+  LIR_Opr tmp3 = FrameMap::LR_oop_opr;
+  LIR_Opr tmp4 = LIR_OprFact::illegalOpr;
+
+  CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info);
+  ciMetadata* obj = ciObjArrayKlass::make(x->klass());
+  if (obj == ciEnv::unloaded_ciobjarrayklass()) {
+    BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error");
+  }
+  klass2reg_with_patching(klass_reg, obj, patching_info);
+  __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path);
+
+  LIR_Opr result = rlock_result(x);
+  __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
+  Values* dims = x->dims();
+  int i = dims->length();
+  LIRItemList* items = new LIRItemList(i, i, NULL);
+  while (i-- > 0) {
+    LIRItem* size = new LIRItem(dims->at(i), this);
+    items->at_put(i, size);
+  }
+
+  // Need to get the info before, as the items may become invalid through item_free
+  CodeEmitInfo* patching_info = NULL;
+  if (!x->klass()->is_loaded() || PatchALot) {
+    patching_info = state_for(x, x->state_before());
+
+    // Cannot re-use same xhandlers for multiple CodeEmitInfos, so
+    // clone all handlers (NOTE: Usually this is handled transparently
+    // by the CodeEmitInfo cloning logic in CodeStub constructors but
+    // is done explicitly here because a stub isn't being used).
+    x->set_exception_handlers(new XHandlers(x->exception_handlers()));
+  }
+
+  i = dims->length();
+  while (i-- > 0) {
+    LIRItem* size = items->at(i);
+    size->load_item();
+    LIR_Opr sz = size->result();
+    assert(sz->type() == T_INT, "should be");
+    store_stack_parameter(sz, in_ByteSize(i * BytesPerInt));
+  }
+
+  CodeEmitInfo* info = state_for(x, x->state());
+  LIR_Opr klass_reg = FrameMap::R0_metadata_opr;
+  klass2reg_with_patching(klass_reg, x->klass(), patching_info);
+
+  LIR_Opr rank = FrameMap::R2_opr;
+  __ move(LIR_OprFact::intConst(x->rank()), rank);
+  LIR_Opr varargs = FrameMap::SP_opr;
+  LIR_OprList* args = new LIR_OprList(3);
+  args->append(klass_reg);
+  args->append(rank);
+  args->append(varargs);
+  LIR_Opr reg = result_register_for(x->type());
+  __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+                  LIR_OprFact::illegalOpr, reg, args, info);
+
+  LIR_Opr result = rlock_result(x);
+  __ move(reg, result);
+}
+
+
+void LIRGenerator::do_BlockBegin(BlockBegin* x) {
+  // nothing to do for now
+}
+
+
+void LIRGenerator::do_CheckCast(CheckCast* x) {
+  LIRItem obj(x->obj(), this);
+  CodeEmitInfo* patching_info = NULL;
+  if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) {
+    patching_info = state_for(x, x->state_before());
+  }
+
+  obj.load_item();
+
+  CodeEmitInfo* info_for_exception = state_for(x);
+  CodeStub* stub;
+  if (x->is_incompatible_class_change_check()) {
+    assert(patching_info == NULL, "can't patch this");
+    stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
+                                   LIR_OprFact::illegalOpr, info_for_exception);
+  } else {
+    stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id,
+                                   LIR_OprFact::illegalOpr, info_for_exception);
+  }
+
+  LIR_Opr out_reg = rlock_result(x);
+  LIR_Opr tmp1 = FrameMap::R0_oop_opr;
+  LIR_Opr tmp2 = FrameMap::R1_oop_opr;
+  LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
+
+  __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, x->direct_compare(),
+               info_for_exception, patching_info, stub, x->profiled_method(), x->profiled_bci());
+}
+
+
+void LIRGenerator::do_InstanceOf(InstanceOf* x) {
+  LIRItem obj(x->obj(), this);
+  CodeEmitInfo* patching_info = NULL;
+  if (!x->klass()->is_loaded() || PatchALot) {
+    patching_info = state_for(x, x->state_before());
+  }
+
+  obj.load_item();
+  LIR_Opr out_reg = rlock_result(x);
+  LIR_Opr tmp1 = FrameMap::R0_oop_opr;
+  LIR_Opr tmp2 = FrameMap::R1_oop_opr;
+  LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
+
+  __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3,
+                x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
+}
+
+
+#ifdef __SOFTFP__
+// Turn operator if (f <op> g) into runtime call:
+//     call _aeabi_fcmp<op>(f, g)
+//     cmp(eq, 1)
+//     branch(eq, true path).
+void LIRGenerator::do_soft_float_compare(If* x) {
+  assert(x->number_of_sux() == 2, "inconsistency");
+  ValueTag tag = x->x()->type()->tag();
+  If::Condition cond = x->cond();
+  address runtime_func;
+  // unordered comparison gets the wrong answer because aeabi functions
+  //  return false.
+  bool unordered_is_true = x->unordered_is_true();
+  // reverse of condition for ne
+  bool compare_to_zero = false;
+  switch (lir_cond(cond)) {
+    case lir_cond_notEqual:
+      compare_to_zero = true;  // fall through
+    case lir_cond_equal:
+      runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, __aeabi_fcmpeq):
+          CAST_FROM_FN_PTR(address, __aeabi_dcmpeq);
+      break;
+    case lir_cond_less:
+      if (unordered_is_true) {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_fcmplt):
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_dcmplt);
+      } else {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, __aeabi_fcmplt):
+          CAST_FROM_FN_PTR(address, __aeabi_dcmplt);
+      }
+      break;
+    case lir_cond_lessEqual:
+      if (unordered_is_true) {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_fcmple):
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_dcmple);
+      } else {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, __aeabi_fcmple):
+          CAST_FROM_FN_PTR(address, __aeabi_dcmple);
+      }
+      break;
+    case lir_cond_greaterEqual:
+      if (unordered_is_true) {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_fcmpge):
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_dcmpge);
+      } else {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, __aeabi_fcmpge):
+          CAST_FROM_FN_PTR(address, __aeabi_dcmpge);
+      }
+      break;
+    case lir_cond_greater:
+      if (unordered_is_true) {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_fcmpgt):
+          CAST_FROM_FN_PTR(address, SharedRuntime::unordered_dcmpgt);
+      } else {
+        runtime_func = tag == floatTag ?
+          CAST_FROM_FN_PTR(address, __aeabi_fcmpgt):
+          CAST_FROM_FN_PTR(address, __aeabi_dcmpgt);
+      }
+      break;
+    case lir_cond_aboveEqual:
+    case lir_cond_belowEqual:
+      ShouldNotReachHere();  // We're not going to get these.
+    default:
+      assert(lir_cond(cond) == lir_cond_always, "must be");
+      ShouldNotReachHere();
+  }
+  set_no_result(x);
+
+  // add safepoint before generating condition code so it can be recomputed
+  if (x->is_safepoint()) {
+    increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci());
+    __ safepoint(LIR_OprFact::illegalOpr, state_for(x, x->state_before()));
+  }
+  // Call float compare function, returns (1,0) if true or false.
+  LIR_Opr result = call_runtime(x->x(), x->y(), runtime_func, intType, NULL);
+  __ cmp(lir_cond_equal, result,
+         compare_to_zero ?
+           LIR_OprFact::intConst(0) : LIR_OprFact::intConst(1));
+  profile_branch(x, cond);
+  move_to_phi(x->state());
+  __ branch(lir_cond_equal, T_INT, x->tsux());
+}
+#endif // __SOFTFP__
+
+void LIRGenerator::do_If(If* x) {
+  assert(x->number_of_sux() == 2, "inconsistency");
+  ValueTag tag = x->x()->type()->tag();
+
+#ifdef __SOFTFP__
+  if (tag == floatTag || tag == doubleTag) {
+    do_soft_float_compare(x);
+    assert(x->default_sux() == x->fsux(), "wrong destination above");
+    __ jump(x->default_sux());
+    return;
+  }
+#endif // __SOFTFP__
+
+  LIRItem xitem(x->x(), this);
+  LIRItem yitem(x->y(), this);
+  LIRItem* xin = &xitem;
+  LIRItem* yin = &yitem;
+  If::Condition cond = x->cond();
+
+#ifndef AARCH64
+  if (tag == longTag) {
+    if (cond == If::gtr || cond == If::leq) {
+      cond = Instruction::mirror(cond);
+      xin = &yitem;
+      yin = &xitem;
+    }
+    xin->set_destroys_register();
+  }
+#endif // !AARCH64
+
+  xin->load_item();
+  LIR_Opr left = xin->result();
+  LIR_Opr right;
+
+#ifdef AARCH64
+  if (yin->is_constant() && can_inline_as_constant_in_cmp(yin->value())) {
+    yin->dont_load_item();
+  } else {
+    yin->load_item();
+  }
+  right = yin->result();
+#else
+  if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 &&
+      (cond == If::eql || cond == If::neq)) {
+    // inline long zero
+    right = LIR_OprFact::value_type(yin->value()->type());
+  } else {
+    yin->load_nonconstant();
+    right = yin->result();
+  }
+#endif // AARCH64
+
+  set_no_result(x);
+
+  // add safepoint before generating condition code so it can be recomputed
+  if (x->is_safepoint()) {
+    increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci());
+    __ safepoint(LIR_OprFact::illegalOpr, state_for(x, x->state_before()));
+  }
+
+  __ cmp(lir_cond(cond), left, right);
+  profile_branch(x, cond);
+  move_to_phi(x->state());
+  if (x->x()->type()->is_float_kind()) {
+    __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
+  } else {
+    __ branch(lir_cond(cond), right->type(), x->tsux());
+  }
+  assert(x->default_sux() == x->fsux(), "wrong destination above");
+  __ jump(x->default_sux());
+}
+
+
+LIR_Opr LIRGenerator::getThreadPointer() {
+  return FrameMap::Rthread_opr;
+}
+
+void LIRGenerator::trace_block_entry(BlockBegin* block) {
+  __ move(LIR_OprFact::intConst(block->block_id()), FrameMap::R0_opr);
+  LIR_OprList* args = new LIR_OprList(1);
+  args->append(FrameMap::R0_opr);
+  address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry);
+  __ call_runtime_leaf(func, getThreadTemp(), LIR_OprFact::illegalOpr, args);
+}
+
+
+void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address,
+                                        CodeEmitInfo* info) {
+#ifndef AARCH64
+  if (value->is_double_cpu()) {
+    assert(address->index()->is_illegal(), "should have a constant displacement");
+    LIR_Opr tmp = new_pointer_register();
+    add_large_constant(address->base(), address->disp(), tmp);
+    __ volatile_store_mem_reg(value, new LIR_Address(tmp, (intx)0, address->type()), info);
+    return;
+  }
+#endif // !AARCH64
+  // TODO-AARCH64 implement with stlr instruction
+  __ store(value, address, info, lir_patch_none);
+}
+
+void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
+                                       CodeEmitInfo* info) {
+#ifndef AARCH64
+  if (result->is_double_cpu()) {
+    assert(address->index()->is_illegal(), "should have a constant displacement");
+    LIR_Opr tmp = new_pointer_register();
+    add_large_constant(address->base(), address->disp(), tmp);
+    __ volatile_load_mem_reg(new LIR_Address(tmp, (intx)0, address->type()), result, info);
+    return;
+  }
+#endif // !AARCH64
+  // TODO-AARCH64 implement with ldar instruction
+  __ load(address, result, info, lir_patch_none);
+}
+
+void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
+                                     BasicType type, bool is_volatile) {
+#ifdef AARCH64
+  __ load(new LIR_Address(src, offset, type), dst);
+#else
+  assert(offset->is_single_cpu(), "must be");
+  if (is_volatile && dst->is_double_cpu()) {
+    LIR_Opr tmp = new_pointer_register();
+    __ add(src, offset, tmp);
+    __ volatile_load_mem_reg(new LIR_Address(tmp, (intx)0, type), dst, NULL);
+  } else if (type == T_FLOAT || type == T_DOUBLE) {
+    // fld doesn't have indexed addressing mode
+    LIR_Opr tmp = new_register(T_INT);
+    __ add(src, offset, tmp);
+    __ load(new LIR_Address(tmp, (intx)0, type), dst);
+  } else {
+    __ load(new LIR_Address(src, offset, type), dst);
+  }
+#endif // AARCH64
+}
+
+void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
+                                     BasicType type, bool is_volatile) {
+#ifdef AARCH64
+  LIR_Address* addr = new LIR_Address(src, offset, type);
+  if (type == T_ARRAY || type == T_OBJECT) {
+    pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
+                true /* do_load */, false /* patch */, NULL);
+    __ move(data, addr);
+    assert(src->is_register(), "must be register");
+    post_barrier(LIR_OprFact::address(addr), data);
+  } else {
+    __ move(data, addr);
+  }
+#else
+  assert(offset->is_single_cpu(), "must be");
+  if (is_volatile && data->is_double_cpu()) {
+    LIR_Opr tmp = new_register(T_INT);
+    __ add(src, offset, tmp);
+    __ volatile_store_mem_reg(data, new LIR_Address(tmp, (intx)0, type), NULL);
+  } else if (type == T_FLOAT || type == T_DOUBLE) {
+    // fst doesn't have indexed addressing mode
+    LIR_Opr tmp = new_register(T_INT);
+    __ add(src, offset, tmp);
+    __ move(data, new LIR_Address(tmp, (intx)0, type));
+  } else {
+    LIR_Address* addr = new LIR_Address(src, offset, type);
+    bool is_obj = (type == T_ARRAY || type == T_OBJECT);
+#if INCLUDE_ALL_GCS
+    if (is_obj) {
+      // Do the pre-write barrier, if any.
+      pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
+                  true /* do_load */, false /* patch */, NULL);
+    }
+#endif // INCLUDE_ALL_GCS
+    __ move(data, addr);
+    if (is_obj) {
+      assert(src->is_register(), "must be register");
+      post_barrier(LIR_OprFact::address(addr), data);
+    }
+  }
+#endif // AARCH64
+}
+
+void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
+  BasicType type = x->basic_type();
+  LIRItem src(x->object(), this);
+  LIRItem off(x->offset(), this);
+  LIRItem value(x->value(), this);
+
+  src.load_item();
+  if (x->is_add()) {
+    value.load_nonconstant();
+  } else {
+    value.load_item();
+  }
+  off.load_nonconstant();
+
+  LIR_Opr dst = rlock_result(x, type);
+  LIR_Opr data = value.result();
+  bool is_obj = (type == T_ARRAY || type == T_OBJECT);
+
+  assert (type == T_INT || type == T_LONG || (!x->is_add() && is_obj), "unexpected type");
+  LIR_Opr addr_ptr = new_pointer_register();
+
+  __ add(src.result(), off.result(), addr_ptr);
+
+  LIR_Address* addr = new LIR_Address(addr_ptr, (intx)0, type);
+
+  if (x->is_add()) {
+    LIR_Opr tmp = new_register(type);
+    __ xadd(addr_ptr, data, dst, tmp);
+  } else {
+    LIR_Opr tmp = (UseCompressedOops && is_obj) ? new_pointer_register() : LIR_OprFact::illegalOpr;
+    if (is_obj) {
+      // Do the pre-write barrier, if any.
+      pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
+                  true /* do_load */, false /* patch */, NULL);
+    }
+    __ xchg(addr_ptr, data, dst, tmp);
+    if (is_obj) {
+      // Seems to be a precise address
+      post_barrier(LIR_OprFact::address(addr), data);
+    }
+  }
+}
diff --git a/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.hpp b/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.hpp
new file mode 100644
index 0000000..24552cb
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LIRGenerator_arm.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+  // Helper to set the card at the given address to the given value.
+  void set_card(LIR_Opr value, LIR_Address* card_addr);
+
+  void make_div_by_zero_check(LIR_Opr right_arg, BasicType type, CodeEmitInfo* info);
+
+#ifdef AARCH64
+  // the helper for arithmetic
+  void add_constant(LIR_Opr src, jlong c, LIR_Opr dest);
+#endif // AARCH64
diff --git a/hotspot/src/cpu/arm/vm/c1_LIR_arm.cpp b/hotspot/src/cpu/arm/vm/c1_LIR_arm.cpp
new file mode 100644
index 0000000..806da32
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LIR_arm.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_LIR.hpp"
+
+FloatRegister LIR_OprDesc::as_float_reg() const {
+  return as_FloatRegister(fpu_regnr());
+}
+
+FloatRegister LIR_OprDesc::as_double_reg() const {
+  return as_FloatRegister(fpu_regnrLo());
+}
+
+#ifdef AARCH64
+// Reg2 unused.
+LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
+  assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform");
+  return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) |
+                             (reg1 << LIR_OprDesc::reg2_shift) |
+                             LIR_OprDesc::double_type          |
+                             LIR_OprDesc::fpu_register         |
+                             LIR_OprDesc::double_size);
+}
+#else
+LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
+  assert(as_FloatRegister(reg2) != fnoreg, "Arm32 holds double in two regs.");
+  return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) |
+                             (reg2 << LIR_OprDesc::reg2_shift) |
+                             LIR_OprDesc::double_type          |
+                             LIR_OprDesc::fpu_register         |
+                             LIR_OprDesc::double_size);
+}
+#endif
+
+#ifndef PRODUCT
+void LIR_Address::verify() const {
+#ifdef _LP64
+  assert(base()->is_cpu_register(), "wrong base operand");
+#endif
+#ifdef AARCH64
+  if (base()->type() == T_INT) {
+    assert(index()->is_single_cpu() && (index()->type() == T_INT), "wrong index operand");
+  } else {
+    assert(index()->is_illegal() || index()->is_double_cpu() ||
+           (index()->is_single_cpu() && (index()->is_oop_register() || index()->type() == T_INT)), "wrong index operand");
+    assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA, "wrong type for addresses");
+  }
+#else
+  assert(disp() == 0 || index()->is_illegal(), "can't have both");
+  // Note: offsets higher than 4096 must not be rejected here. They can
+  // be handled by the back-end or will be rejected if not.
+#ifdef _LP64
+  assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
+  assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
+         "wrong type for addresses");
+#else
+  assert(base()->is_single_cpu(), "wrong base operand");
+  assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand");
+  assert(base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
+         "wrong type for addresses");
+#endif
+#endif // AARCH64
+}
+#endif // PRODUCT
diff --git a/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.cpp b/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.cpp
new file mode 100644
index 0000000..21030b9
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_Instruction.hpp"
+#include "c1/c1_LinearScan.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+void LinearScan::allocate_fpu_stack() {
+  // No FPU stack on ARM
+}
diff --git a/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.hpp b/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.hpp
new file mode 100644
index 0000000..d67643c
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_LinearScan_arm.hpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_LINEARSCAN_ARM_HPP
+#define CPU_ARM_VM_C1_LINEARSCAN_ARM_HPP
+
+inline bool LinearScan::is_processed_reg_num(int reg_num) {
+  return reg_num < pd_nof_cpu_regs_processed_in_linearscan ||
+         reg_num >= pd_nof_cpu_regs_frame_map;
+}
+
+inline int LinearScan::num_physical_regs(BasicType type) {
+#ifndef AARCH64
+  if (type == T_LONG || type == T_DOUBLE) return 2;
+#endif // !AARCH64
+  return 1;
+}
+
+
+inline bool LinearScan::requires_adjacent_regs(BasicType type) {
+#ifdef AARCH64
+  return false;
+#else
+  return type == T_DOUBLE || type == T_LONG;
+#endif // AARCH64
+}
+
+inline bool LinearScan::is_caller_save(int assigned_reg) {
+  assert(assigned_reg >= 0 && assigned_reg < nof_regs, "should call this only for registers");
+  // TODO-AARCH64 try to add callee-saved registers
+  return true;
+}
+
+
+inline void LinearScan::pd_add_temps(LIR_Op* op) {
+  // No extra temporals on ARM
+}
+
+
+// Implementation of LinearScanWalker
+
+inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) {
+#ifndef __SOFTFP__
+  if (cur->type() == T_FLOAT || cur->type() == T_DOUBLE) {
+    _first_reg = pd_first_fpu_reg;
+    _last_reg = pd_first_fpu_reg + pd_nof_fpu_regs_reg_alloc - 1;
+    return true;
+  }
+#endif // !__SOFTFP__
+
+  // Use allocatable CPU registers otherwise
+  _first_reg = pd_first_cpu_reg;
+  _last_reg = pd_first_cpu_reg + FrameMap::adjust_reg_range(pd_nof_cpu_regs_reg_alloc) - 1;
+  return true;
+}
+
+#endif // CPU_ARM_VM_C1_LINEARSCAN_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.cpp
new file mode 100644
index 0000000..bc60571
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "interpreter/interpreter.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/markOop.hpp"
+#include "runtime/basicLock.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+
+// Note: Rtemp usage is this file should not impact C2 and should be
+// correct as long as it is not implicitly used in lower layers (the
+// arm [macro]assembler) and used with care in the other C1 specific
+// files.
+
+void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {
+  Label verified;
+  load_klass(Rtemp, receiver);
+  cmp(Rtemp, iCache);
+  b(verified, eq); // jump over alignment no-ops
+#ifdef AARCH64
+  jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp);
+#else
+  jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type);
+#endif
+  align(CodeEntryAlignment);
+  bind(verified);
+}
+
+void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) {
+  assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect");
+  assert((frame_size_in_bytes % StackAlignmentInBytes) == 0, "frame size should be aligned");
+
+#ifdef AARCH64
+  // Extra nop for MT-safe patching in NativeJump::patch_verified_entry
+  nop();
+#endif // AARCH64
+
+  arm_stack_overflow_check(bang_size_in_bytes, Rtemp);
+
+  // FP can no longer be used to memorize SP. It may be modified
+  // if this method contains a methodHandle call site
+  raw_push(FP, LR);
+  sub_slow(SP, SP, frame_size_in_bytes);
+}
+
+void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) {
+  add_slow(SP, SP, frame_size_in_bytes);
+  raw_pop(FP, LR);
+}
+
+void C1_MacroAssembler::verified_entry() {
+  if (C1Breakpoint) {
+    breakpoint();
+  }
+}
+
+// Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`.
+void C1_MacroAssembler::try_allocate(Register obj, Register obj_end, Register tmp1, Register tmp2,
+                                     RegisterOrConstant size_expression, Label& slow_case) {
+  if (UseTLAB) {
+    tlab_allocate(obj, obj_end, tmp1, size_expression, slow_case);
+  } else {
+    eden_allocate(obj, obj_end, tmp1, tmp2, size_expression, slow_case);
+    incr_allocated_bytes(size_expression, tmp1);
+  }
+}
+
+
+void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register tmp) {
+  assert_different_registers(obj, klass, len, tmp);
+
+  if(UseBiasedLocking && !len->is_valid()) {
+    ldr(tmp, Address(klass, Klass::prototype_header_offset()));
+  } else {
+    mov(tmp, (intptr_t)markOopDesc::prototype());
+  }
+
+#ifdef AARCH64
+  if (UseCompressedClassPointers) {
+    str(tmp, Address(obj, oopDesc::mark_offset_in_bytes()));
+    encode_klass_not_null(tmp, klass);          // Take care not to kill klass
+    str_w(tmp, Address(obj, oopDesc::klass_offset_in_bytes()));
+  } else {
+    assert(oopDesc::mark_offset_in_bytes() + wordSize == oopDesc::klass_offset_in_bytes(), "adjust this code");
+    stp(tmp, klass, Address(obj, oopDesc::mark_offset_in_bytes()));
+  }
+#else
+  str(tmp, Address(obj, oopDesc::mark_offset_in_bytes()));
+  str(klass, Address(obj, oopDesc::klass_offset_in_bytes()));
+#endif // AARCH64
+
+  if (len->is_valid()) {
+    str_32(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));
+  }
+#ifdef AARCH64
+  else if (UseCompressedClassPointers) {
+    store_klass_gap(obj);
+  }
+#endif // AARCH64
+}
+
+
+// Cleans object body [base..obj_end]. Clobbers `base` and `tmp` registers.
+void C1_MacroAssembler::initialize_body(Register base, Register obj_end, Register tmp) {
+  zero_memory(base, obj_end, tmp);
+}
+
+
+void C1_MacroAssembler::initialize_object(Register obj, Register obj_end, Register klass,
+                                          Register len, Register tmp1, Register tmp2,
+                                          RegisterOrConstant header_size, int obj_size_in_bytes,
+                                          bool is_tlab_allocated)
+{
+  assert_different_registers(obj, obj_end, klass, len, tmp1, tmp2);
+  initialize_header(obj, klass, len, tmp1);
+
+  const Register ptr = tmp2;
+
+  if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) {
+#ifdef AARCH64
+    if (obj_size_in_bytes < 0) {
+      add_rc(ptr, obj, header_size);
+      initialize_body(ptr, obj_end, tmp1);
+
+    } else {
+      int base = instanceOopDesc::header_size() * HeapWordSize;
+      assert(obj_size_in_bytes >= base, "should be");
+
+      const int zero_bytes = obj_size_in_bytes - base;
+      assert((zero_bytes % wordSize) == 0, "should be");
+
+      if ((zero_bytes % (2*wordSize)) != 0) {
+        str(ZR, Address(obj, base));
+        base += wordSize;
+      }
+
+      const int stp_count = zero_bytes / (2*wordSize);
+
+      if (zero_bytes > 8 * wordSize) {
+        Label loop;
+        add(ptr, obj, base);
+        mov(tmp1, stp_count);
+        bind(loop);
+        subs(tmp1, tmp1, 1);
+        stp(ZR, ZR, Address(ptr, 2*wordSize, post_indexed));
+        b(loop, gt);
+      } else {
+        for (int i = 0; i < stp_count; i++) {
+          stp(ZR, ZR, Address(obj, base + i * 2 * wordSize));
+        }
+      }
+    }
+#else
+    if (obj_size_in_bytes >= 0 && obj_size_in_bytes <= 8 * BytesPerWord) {
+      mov(tmp1, 0);
+      const int base = instanceOopDesc::header_size() * HeapWordSize;
+      for (int i = base; i < obj_size_in_bytes; i += wordSize) {
+        str(tmp1, Address(obj, i));
+      }
+    } else {
+      assert(header_size.is_constant() || header_size.as_register() == ptr, "code assumption");
+      add(ptr, obj, header_size);
+      initialize_body(ptr, obj_end, tmp1);
+    }
+#endif // AARCH64
+  }
+
+  // StoreStore barrier required after complete initialization
+  // (headers + content zeroing), before the object may escape.
+  membar(MacroAssembler::StoreStore, tmp1);
+}
+
+void C1_MacroAssembler::allocate_object(Register obj, Register tmp1, Register tmp2, Register tmp3,
+                                        int header_size, int object_size,
+                                        Register klass, Label& slow_case) {
+  assert_different_registers(obj, tmp1, tmp2, tmp3, klass, Rtemp);
+  assert(header_size >= 0 && object_size >= header_size, "illegal sizes");
+  const int object_size_in_bytes = object_size * BytesPerWord;
+
+  const Register obj_end = tmp1;
+  const Register len = noreg;
+
+  if (Assembler::is_arith_imm_in_range(object_size_in_bytes)) {
+    try_allocate(obj, obj_end, tmp2, tmp3, object_size_in_bytes, slow_case);
+  } else {
+    // Rtemp should be free at c1 LIR level
+    mov_slow(Rtemp, object_size_in_bytes);
+    try_allocate(obj, obj_end, tmp2, tmp3, Rtemp, slow_case);
+  }
+  initialize_object(obj, obj_end, klass, len, tmp2, tmp3, instanceOopDesc::header_size() * HeapWordSize, object_size_in_bytes, /* is_tlab_allocated */ UseTLAB);
+}
+
+void C1_MacroAssembler::allocate_array(Register obj, Register len,
+                                       Register tmp1, Register tmp2, Register tmp3,
+                                       int header_size, int element_size,
+                                       Register klass, Label& slow_case) {
+  assert_different_registers(obj, len, tmp1, tmp2, tmp3, klass, Rtemp);
+  const int header_size_in_bytes = header_size * BytesPerWord;
+  const int scale_shift = exact_log2(element_size);
+  const Register obj_size = Rtemp; // Rtemp should be free at c1 LIR level
+
+#ifdef AARCH64
+  mov_slow(Rtemp, max_array_allocation_length);
+  cmp_32(len, Rtemp);
+#else
+  cmp_32(len, max_array_allocation_length);
+#endif // AARCH64
+  b(slow_case, hs);
+
+  bool align_header = ((header_size_in_bytes | element_size) & MinObjAlignmentInBytesMask) != 0;
+  assert(align_header || ((header_size_in_bytes & MinObjAlignmentInBytesMask) == 0), "must be");
+  assert(align_header || ((element_size & MinObjAlignmentInBytesMask) == 0), "must be");
+
+  mov(obj_size, header_size_in_bytes + (align_header ? (MinObjAlignmentInBytes - 1) : 0));
+  add_ptr_scaled_int32(obj_size, obj_size, len, scale_shift);
+
+  if (align_header) {
+    align_reg(obj_size, obj_size, MinObjAlignmentInBytes);
+  }
+
+  try_allocate(obj, tmp1, tmp2, tmp3, obj_size, slow_case);
+  initialize_object(obj, tmp1, klass, len, tmp2, tmp3, header_size_in_bytes, -1, /* is_tlab_allocated */ UseTLAB);
+}
+
+int C1_MacroAssembler::lock_object(Register hdr, Register obj,
+                                   Register disp_hdr, Register tmp1,
+                                   Label& slow_case) {
+  Label done, fast_lock, fast_lock_done;
+  int null_check_offset = 0;
+
+  const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level
+  assert_different_registers(hdr, obj, disp_hdr, tmp1, tmp2);
+
+  assert(BasicObjectLock::lock_offset_in_bytes() == 0, "ajust this code");
+  const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
+  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
+
+  if (UseBiasedLocking) {
+    // load object
+    str(obj, Address(disp_hdr, obj_offset));
+    null_check_offset = biased_locking_enter(obj, hdr/*scratched*/, tmp1, false, tmp2, done, slow_case);
+  }
+
+  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
+
+#ifdef AARCH64
+
+  str(obj, Address(disp_hdr, obj_offset));
+
+  if (!UseBiasedLocking) {
+    null_check_offset = offset();
+  }
+  ldr(hdr, obj);
+
+  // Test if object is already locked
+  assert(markOopDesc::unlocked_value == 1, "adjust this code");
+  tbnz(hdr, exact_log2(markOopDesc::unlocked_value), fast_lock);
+
+  // Check for recursive locking
+  // See comments in InterpreterMacroAssembler::lock_object for
+  // explanations on the fast recursive locking check.
+  intptr_t mask = ((intptr_t)3) - ((intptr_t)os::vm_page_size());
+  Assembler::LogicalImmediate imm(mask, false);
+  mov(tmp2, SP);
+  sub(tmp2, hdr, tmp2);
+  ands(tmp2, tmp2, imm);
+  b(slow_case, ne);
+
+  // Recursive locking: store 0 into a lock record
+  str(ZR, Address(disp_hdr, mark_offset));
+  b(fast_lock_done);
+
+#else // AARCH64
+
+  if (!UseBiasedLocking) {
+    null_check_offset = offset();
+  }
+
+  // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
+  // That would be acceptable as ether CAS or slow case path is taken in that case.
+
+  // Must be the first instruction here, because implicit null check relies on it
+  ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
+
+  str(obj, Address(disp_hdr, obj_offset));
+  tst(hdr, markOopDesc::unlocked_value);
+  b(fast_lock, ne);
+
+  // Check for recursive locking
+  // See comments in InterpreterMacroAssembler::lock_object for
+  // explanations on the fast recursive locking check.
+  // -1- test low 2 bits
+  movs(tmp2, AsmOperand(hdr, lsl, 30));
+  // -2- test (hdr - SP) if the low two bits are 0
+  sub(tmp2, hdr, SP, eq);
+  movs(tmp2, AsmOperand(tmp2, lsr, exact_log2(os::vm_page_size())), eq);
+  // If 'eq' then OK for recursive fast locking: store 0 into a lock record.
+  str(tmp2, Address(disp_hdr, mark_offset), eq);
+  b(fast_lock_done, eq);
+  // else need slow case
+  b(slow_case);
+
+#endif // AARCH64
+
+  bind(fast_lock);
+  // Save previous object header in BasicLock structure and update the header
+  str(hdr, Address(disp_hdr, mark_offset));
+
+  cas_for_lock_acquire(hdr, disp_hdr, obj, tmp2, slow_case);
+
+  bind(fast_lock_done);
+
+#ifndef PRODUCT
+  if (PrintBiasedLockingStatistics) {
+    cond_atomic_inc32(al, BiasedLocking::fast_path_entry_count_addr());
+  }
+#endif // !PRODUCT
+
+  bind(done);
+
+  return null_check_offset;
+}
+
+void C1_MacroAssembler::unlock_object(Register hdr, Register obj,
+                                      Register disp_hdr, Register tmp,
+                                      Label& slow_case) {
+  // Note: this method is not using its 'tmp' argument
+
+  assert_different_registers(hdr, obj, disp_hdr, Rtemp);
+  Register tmp2 = Rtemp;
+
+  assert(BasicObjectLock::lock_offset_in_bytes() == 0, "ajust this code");
+  const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
+  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
+
+  Label done;
+  if (UseBiasedLocking) {
+    // load object
+    ldr(obj, Address(disp_hdr, obj_offset));
+    biased_locking_exit(obj, hdr, done);
+  }
+
+  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
+  Label retry;
+
+  // Load displaced header and object from the lock
+  ldr(hdr, Address(disp_hdr, mark_offset));
+  // If hdr is NULL, we've got recursive locking and there's nothing more to do
+  cbz(hdr, done);
+
+  if(!UseBiasedLocking) {
+    // load object
+    ldr(obj, Address(disp_hdr, obj_offset));
+  }
+
+  // Restore the object header
+  cas_for_lock_release(disp_hdr, hdr, obj, tmp2, slow_case);
+
+  bind(done);
+}
+
+
+#ifndef PRODUCT
+
+void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
+  if (!VerifyOops) return;
+  verify_oop_addr(Address(SP, stack_offset));
+}
+
+void C1_MacroAssembler::verify_not_null_oop(Register r) {
+  Label not_null;
+  cbnz(r, not_null);
+  stop("non-null oop required");
+  bind(not_null);
+  if (!VerifyOops) return;
+  verify_oop(r);
+}
+
+#endif // !PRODUCT
diff --git a/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.hpp
new file mode 100644
index 0000000..b3d2457
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_MacroAssembler_arm.hpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_MACROASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_C1_MACROASSEMBLER_ARM_HPP
+
+ private:
+
+  void pd_init() { /* not used */ }
+
+ public:
+
+  // Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`.
+  // `size_expression` should be a register or constant which can be used as immediate in "add" instruction.
+  void try_allocate(Register obj, Register obj_end, Register tmp1, Register tmp2,
+                    RegisterOrConstant size_expression, Label& slow_case);
+
+  void initialize_header(Register obj, Register klass, Register len, Register tmp);
+
+  // Cleans object body [base..obj_end]. Clobbers `base` and `tmp` registers.
+  void initialize_body(Register base, Register obj_end, Register tmp);
+
+  void initialize_object(Register obj, Register obj_end, Register klass,
+                         Register len, Register tmp1, Register tmp2,
+                         RegisterOrConstant header_size_expression, int obj_size_in_bytes,
+                         bool is_tlab_allocated);
+
+  void allocate_object(Register obj, Register tmp1, Register tmp2, Register tmp3,
+                       int header_size, int object_size,
+                       Register klass, Label& slow_case);
+
+  void allocate_array(Register obj, Register len,
+                      Register tmp1, Register tmp2, Register tmp3,
+                      int header_size, int element_size,
+                      Register klass, Label& slow_case);
+
+  enum {
+    max_array_allocation_length = 0x01000000
+  };
+
+  int lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case);
+
+  void unlock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case);
+
+  // This platform only uses signal-based null checks. The Label is not needed.
+  void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); }
+
+#endif // CPU_ARM_VM_C1_MACROASSEMBLER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp
new file mode 100644
index 0000000..937dfe9
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp
@@ -0,0 +1,1226 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "c1/c1_Defs.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "interpreter/interpreter.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/compiledICHolder.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "register_arm.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/signature.hpp"
+#include "runtime/vframeArray.hpp"
+#include "vmreg_arm.inline.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif
+
+// Note: Rtemp usage is this file should not impact C2 and should be
+// correct as long as it is not implicitly used in lower layers (the
+// arm [macro]assembler) and used with care in the other C1 specific
+// files.
+
+// Implementation of StubAssembler
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) {
+  mov(R0, Rthread);
+
+  int call_offset = set_last_Java_frame(SP, FP, false, Rtemp);
+
+  call(entry);
+  if (call_offset == -1) { // PC not saved
+    call_offset = offset();
+  }
+  reset_last_Java_frame(Rtemp);
+
+  assert(frame_size() != no_frame_size, "frame must be fixed");
+  if (_stub_id != Runtime1::forward_exception_id) {
+    ldr(R3, Address(Rthread, Thread::pending_exception_offset()));
+  }
+
+  if (oop_result1->is_valid()) {
+    assert_different_registers(oop_result1, R3, Rtemp);
+    get_vm_result(oop_result1, Rtemp);
+  }
+  if (metadata_result->is_valid()) {
+    assert_different_registers(metadata_result, R3, Rtemp);
+    get_vm_result_2(metadata_result, Rtemp);
+  }
+
+  // Check for pending exception
+  // unpack_with_exception_in_tls path is taken through
+  // Runtime1::exception_handler_for_pc
+  if (_stub_id != Runtime1::forward_exception_id) {
+    assert(frame_size() != no_frame_size, "cannot directly call forward_exception_id");
+#ifdef AARCH64
+    Label skip;
+    cbz(R3, skip);
+    jump(Runtime1::entry_for(Runtime1::forward_exception_id), relocInfo::runtime_call_type, Rtemp);
+    bind(skip);
+#else
+    cmp(R3, 0);
+    jump(Runtime1::entry_for(Runtime1::forward_exception_id), relocInfo::runtime_call_type, Rtemp, ne);
+#endif // AARCH64
+  } else {
+#ifdef ASSERT
+    // Should not have pending exception in forward_exception stub
+    ldr(R3, Address(Rthread, Thread::pending_exception_offset()));
+    cmp(R3, 0);
+    breakpoint(ne);
+#endif // ASSERT
+  }
+  return call_offset;
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) {
+  if (arg1 != R1) {
+    mov(R1, arg1);
+  }
+  return call_RT(oop_result1, metadata_result, entry, 1);
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) {
+  assert(arg1 == R1 && arg2 == R2, "cannot handle otherwise");
+  return call_RT(oop_result1, metadata_result, entry, 2);
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) {
+  assert(arg1 == R1 && arg2 == R2 && arg3 == R3, "cannot handle otherwise");
+  return call_RT(oop_result1, metadata_result, entry, 3);
+}
+
+
+#define __ sasm->
+
+// TODO: ARM - does this duplicate RegisterSaver in SharedRuntime?
+#ifdef AARCH64
+
+  //
+  // On AArch64 registers save area has the following layout:
+  //
+  // |---------------------|
+  // | return address (LR) |
+  // | FP                  |
+  // |---------------------|
+  // | D31                 |
+  // | ...                 |
+  // | D0                  |
+  // |---------------------|
+  // | padding             |
+  // |---------------------|
+  // | R28                 |
+  // | ...                 |
+  // | R0                  |
+  // |---------------------| <-- SP
+  //
+
+enum RegisterLayout {
+  number_of_saved_gprs = 29,
+  number_of_saved_fprs = FloatRegisterImpl::number_of_registers,
+
+  R0_offset  = 0,
+  D0_offset  = R0_offset + number_of_saved_gprs + 1,
+  FP_offset  = D0_offset + number_of_saved_fprs,
+  LR_offset  = FP_offset + 1,
+
+  reg_save_size = LR_offset + 1,
+
+  arg1_offset = reg_save_size * wordSize,
+  arg2_offset = (reg_save_size + 1) * wordSize
+};
+
+#else
+
+enum RegisterLayout {
+  fpu_save_size = pd_nof_fpu_regs_reg_alloc,
+#ifndef __SOFTFP__
+  D0_offset = 0,
+#endif
+  R0_offset = fpu_save_size,
+  R1_offset,
+  R2_offset,
+  R3_offset,
+  R4_offset,
+  R5_offset,
+  R6_offset,
+#if (FP_REG_NUM != 7)
+  R7_offset,
+#endif
+  R8_offset,
+  R9_offset,
+  R10_offset,
+#if (FP_REG_NUM != 11)
+  R11_offset,
+#endif
+  R12_offset,
+  FP_offset,
+  LR_offset,
+  reg_save_size,
+  arg1_offset = reg_save_size * wordSize,
+  arg2_offset = (reg_save_size + 1) * wordSize
+};
+
+#endif // AARCH64
+
+static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers = HaveVFP) {
+  sasm->set_frame_size(reg_save_size /* in words */);
+
+  // Record saved value locations in an OopMap.
+  // Locations are offsets from sp after runtime call.
+  OopMap* map = new OopMap(VMRegImpl::slots_per_word * reg_save_size, 0);
+
+#ifdef AARCH64
+  for (int i = 0; i < number_of_saved_gprs; i++) {
+    map->set_callee_saved(VMRegImpl::stack2reg((R0_offset + i) * VMRegImpl::slots_per_word), as_Register(i)->as_VMReg());
+  }
+  map->set_callee_saved(VMRegImpl::stack2reg(FP_offset * VMRegImpl::slots_per_word), FP->as_VMReg());
+  map->set_callee_saved(VMRegImpl::stack2reg(LR_offset * VMRegImpl::slots_per_word), LR->as_VMReg());
+
+  if (save_fpu_registers) {
+    for (int i = 0; i < number_of_saved_fprs; i++) {
+      map->set_callee_saved(VMRegImpl::stack2reg((D0_offset + i) * VMRegImpl::slots_per_word), as_FloatRegister(i)->as_VMReg());
+    }
+  }
+#else
+  int j=0;
+  for (int i = R0_offset; i < R10_offset; i++) {
+    if (j == FP_REG_NUM) {
+      // skip the FP register, saved below
+      j++;
+    }
+    map->set_callee_saved(VMRegImpl::stack2reg(i), as_Register(j)->as_VMReg());
+    j++;
+  }
+  assert(j == R10->encoding(), "must be");
+#if (FP_REG_NUM != 11)
+  // add R11, if not saved as FP
+  map->set_callee_saved(VMRegImpl::stack2reg(R11_offset), R11->as_VMReg());
+#endif
+  map->set_callee_saved(VMRegImpl::stack2reg(FP_offset), FP->as_VMReg());
+  map->set_callee_saved(VMRegImpl::stack2reg(LR_offset), LR->as_VMReg());
+
+  if (save_fpu_registers) {
+    for (int i = 0; i < fpu_save_size; i++) {
+      map->set_callee_saved(VMRegImpl::stack2reg(i), as_FloatRegister(i)->as_VMReg());
+    }
+  }
+#endif // AARCH64
+
+  return map;
+}
+
+static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = HaveVFP) {
+  __ block_comment("save_live_registers");
+  sasm->set_frame_size(reg_save_size /* in words */);
+
+#ifdef AARCH64
+  assert((reg_save_size * wordSize) % StackAlignmentInBytes == 0, "SP should be aligned");
+
+  __ raw_push(FP, LR);
+
+  __ sub(SP, SP, (reg_save_size - 2) * wordSize);
+
+  for (int i = 0; i < round_down(number_of_saved_gprs, 2); i += 2) {
+    __ stp(as_Register(i), as_Register(i+1), Address(SP, (R0_offset + i) * wordSize));
+  }
+
+  if (is_odd(number_of_saved_gprs)) {
+    int i = number_of_saved_gprs - 1;
+    __ str(as_Register(i), Address(SP, (R0_offset + i) * wordSize));
+  }
+
+  if (save_fpu_registers) {
+    assert (is_even(number_of_saved_fprs), "adjust this code");
+    for (int i = 0; i < number_of_saved_fprs; i += 2) {
+      __ stp_d(as_FloatRegister(i), as_FloatRegister(i+1), Address(SP, (D0_offset + i) * wordSize));
+    }
+  }
+#else
+  __ push(RegisterSet(FP) | RegisterSet(LR));
+  __ push(RegisterSet(R0, R6) | RegisterSet(R8, R10) | R12 | altFP_7_11);
+  if (save_fpu_registers) {
+    __ fstmdbd(SP, FloatRegisterSet(D0, fpu_save_size / 2), writeback);
+  } else {
+    __ sub(SP, SP, fpu_save_size * wordSize);
+  }
+#endif // AARCH64
+
+  return generate_oop_map(sasm, save_fpu_registers);
+}
+
+
+static void restore_live_registers(StubAssembler* sasm,
+                                   bool restore_R0,
+                                   bool restore_FP_LR,
+                                   bool do_return,
+                                   bool restore_fpu_registers = HaveVFP) {
+  __ block_comment("restore_live_registers");
+
+#ifdef AARCH64
+  if (restore_R0) {
+    __ ldr(R0, Address(SP, R0_offset * wordSize));
+  }
+
+  assert(is_odd(number_of_saved_gprs), "adjust this code");
+  for (int i = 1; i < number_of_saved_gprs; i += 2) {
+    __ ldp(as_Register(i), as_Register(i+1), Address(SP, (R0_offset + i) * wordSize));
+  }
+
+  if (restore_fpu_registers) {
+    assert (is_even(number_of_saved_fprs), "adjust this code");
+    for (int i = 0; i < number_of_saved_fprs; i += 2) {
+      __ ldp_d(as_FloatRegister(i), as_FloatRegister(i+1), Address(SP, (D0_offset + i) * wordSize));
+    }
+  }
+
+  __ add(SP, SP, (reg_save_size - 2) * wordSize);
+
+  if (restore_FP_LR) {
+    __ raw_pop(FP, LR);
+    if (do_return) {
+      __ ret();
+    }
+  } else {
+    assert (!do_return, "return without restoring FP/LR");
+  }
+#else
+  if (restore_fpu_registers) {
+    __ fldmiad(SP, FloatRegisterSet(D0, fpu_save_size / 2), writeback);
+    if (!restore_R0) {
+      __ add(SP, SP, (R1_offset - fpu_save_size) * wordSize);
+    }
+  } else {
+    __ add(SP, SP, (restore_R0 ? fpu_save_size : R1_offset) * wordSize);
+  }
+  __ pop(RegisterSet((restore_R0 ? R0 : R1), R6) | RegisterSet(R8, R10) | R12 | altFP_7_11);
+  if (restore_FP_LR) {
+    __ pop(RegisterSet(FP) | RegisterSet(do_return ? PC : LR));
+  } else {
+    assert (!do_return, "return without restoring FP/LR");
+  }
+#endif // AARCH64
+}
+
+
+static void restore_live_registers_except_R0(StubAssembler* sasm, bool restore_fpu_registers = HaveVFP) {
+  restore_live_registers(sasm, false, true, true, restore_fpu_registers);
+}
+
+static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = HaveVFP) {
+  restore_live_registers(sasm, true, true, true, restore_fpu_registers);
+}
+
+#ifndef AARCH64
+static void restore_live_registers_except_FP_LR(StubAssembler* sasm, bool restore_fpu_registers = HaveVFP) {
+  restore_live_registers(sasm, true, false, false, restore_fpu_registers);
+}
+#endif // !AARCH64
+
+static void restore_live_registers_without_return(StubAssembler* sasm, bool restore_fpu_registers = HaveVFP) {
+  restore_live_registers(sasm, true, true, false, restore_fpu_registers);
+}
+
+
+void Runtime1::initialize_pd() {
+}
+
+
+OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
+  OopMap* oop_map = save_live_registers(sasm);
+
+  if (has_argument) {
+    __ ldr(R1, Address(SP, arg1_offset));
+  }
+
+  int call_offset = __ call_RT(noreg, noreg, target);
+  OopMapSet* oop_maps = new OopMapSet();
+  oop_maps->add_gc_map(call_offset, oop_map);
+
+  DEBUG_ONLY(STOP("generate_exception_throw");)  // Should not reach here
+  return oop_maps;
+}
+
+
+static void restore_sp_for_method_handle(StubAssembler* sasm) {
+  // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site.
+  __ ldr_s32(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset()));
+#ifdef AARCH64
+  Label skip;
+  __ cbz(Rtemp, skip);
+  __ mov(SP, Rmh_SP_save);
+  __ bind(skip);
+#else
+  __ cmp(Rtemp, 0);
+  __ mov(SP, Rmh_SP_save, ne);
+#endif // AARCH64
+}
+
+
+OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
+  __ block_comment("generate_handle_exception");
+
+  bool save_fpu_registers = false;
+
+  // Save registers, if required.
+  OopMapSet* oop_maps = new OopMapSet();
+  OopMap* oop_map = NULL;
+
+  switch (id) {
+  case forward_exception_id: {
+    save_fpu_registers = HaveVFP;
+    oop_map = generate_oop_map(sasm);
+    __ ldr(Rexception_obj, Address(Rthread, Thread::pending_exception_offset()));
+    __ ldr(Rexception_pc, Address(SP, LR_offset * wordSize));
+    Register zero = __ zero_register(Rtemp);
+    __ str(zero, Address(Rthread, Thread::pending_exception_offset()));
+    break;
+  }
+  case handle_exception_id:
+    save_fpu_registers = HaveVFP;
+    // fall-through
+  case handle_exception_nofpu_id:
+    // At this point all registers MAY be live.
+    oop_map = save_live_registers(sasm, save_fpu_registers);
+    break;
+  case handle_exception_from_callee_id:
+    // At this point all registers except exception oop (R4/R19) and
+    // exception pc (R5/R20) are dead.
+    oop_map = save_live_registers(sasm);  // TODO it's not required to save all registers
+    break;
+  default:  ShouldNotReachHere();
+  }
+
+  __ str(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ str(Rexception_pc, Address(Rthread, JavaThread::exception_pc_offset()));
+
+  __ str(Rexception_pc, Address(SP, LR_offset * wordSize)); // patch throwing pc into return address
+
+  int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
+  oop_maps->add_gc_map(call_offset, oop_map);
+
+  // Exception handler found
+  __ str(R0, Address(SP, LR_offset * wordSize)); // patch the return address
+
+  // Restore the registers that were saved at the beginning, remove
+  // frame and jump to the exception handler.
+  switch (id) {
+  case forward_exception_id:
+  case handle_exception_nofpu_id:
+  case handle_exception_id:
+    restore_live_registers(sasm, save_fpu_registers);
+    // Note: the restore live registers includes the jump to LR (patched to R0)
+    break;
+  case handle_exception_from_callee_id:
+    restore_live_registers_without_return(sasm); // must not jump immediatly to handler
+    restore_sp_for_method_handle(sasm);
+    __ ret();
+    break;
+  default:  ShouldNotReachHere();
+  }
+
+  DEBUG_ONLY(STOP("generate_handle_exception");)  // Should not reach here
+
+  return oop_maps;
+}
+
+
+void Runtime1::generate_unwind_exception(StubAssembler* sasm) {
+  // FP no longer used to find the frame start
+  // on entry, remove_frame() has already been called (restoring FP and LR)
+
+  // search the exception handler address of the caller (using the return address)
+  __ mov(c_rarg0, Rthread);
+  __ mov(Rexception_pc, LR);
+  __ mov(c_rarg1, LR);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), c_rarg0, c_rarg1);
+
+  // Exception oop should be still in Rexception_obj and pc in Rexception_pc
+  // Jump to handler
+  __ verify_not_null_oop(Rexception_obj);
+
+  // JSR292 extension
+  restore_sp_for_method_handle(sasm);
+
+  __ jump(R0);
+}
+
+
+OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
+  OopMap* oop_map = save_live_registers(sasm);
+
+  // call the runtime patching routine, returns non-zero if nmethod got deopted.
+  int call_offset = __ call_RT(noreg, noreg, target);
+  OopMapSet* oop_maps = new OopMapSet();
+  oop_maps->add_gc_map(call_offset, oop_map);
+
+  DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+  assert(deopt_blob != NULL, "deoptimization blob must have been created");
+
+  __ cmp_32(R0, 0);
+
+#ifdef AARCH64
+  Label call_deopt;
+
+  restore_live_registers_without_return(sasm);
+  __ b(call_deopt, ne);
+  __ ret();
+
+  __ bind(call_deopt);
+#else
+  restore_live_registers_except_FP_LR(sasm);
+  __ pop(RegisterSet(FP) | RegisterSet(PC), eq);
+
+  // Deoptimization needed
+  // TODO: ARM - no need to restore FP & LR because unpack_with_reexecution() stores them back
+  __ pop(RegisterSet(FP) | RegisterSet(LR));
+#endif // AARCH64
+
+  __ jump(deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type, Rtemp);
+
+  DEBUG_ONLY(STOP("generate_patching");)  // Should not reach here
+  return oop_maps;
+}
+
+
+OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+  const bool must_gc_arguments = true;
+  const bool dont_gc_arguments = false;
+
+  OopMapSet* oop_maps = NULL;
+  bool save_fpu_registers = HaveVFP;
+
+  switch (id) {
+    case forward_exception_id:
+      {
+        oop_maps = generate_handle_exception(id, sasm);
+        // does not return on ARM
+      }
+      break;
+
+#if INCLUDE_ALL_GCS
+    case g1_pre_barrier_slow_id:
+      {
+        // Input:
+        // - pre_val pushed on the stack
+
+        __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
+
+        // save at least the registers that need saving if the runtime is called
+#ifdef AARCH64
+        __ raw_push(R0, R1);
+        __ raw_push(R2, R3);
+        const int nb_saved_regs = 4;
+#else // AARCH64
+        const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
+        const int nb_saved_regs = 6;
+        assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
+        __ push(saved_regs);
+#endif // AARCH64
+
+        const Register r_pre_val_0  = R0; // must be R0, to be ready for the runtime call
+        const Register r_index_1    = R1;
+        const Register r_buffer_2   = R2;
+
+        Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                              SATBMarkQueue::byte_offset_of_index()));
+        Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                         SATBMarkQueue::byte_offset_of_buf()));
+
+        Label done;
+        Label runtime;
+
+        __ ldr(r_index_1, queue_index);
+        __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
+        __ ldr(r_buffer_2, buffer);
+
+        __ subs(r_index_1, r_index_1, wordSize);
+        __ b(runtime, lt);
+
+        __ str(r_index_1, queue_index);
+        __ str(r_pre_val_0, Address(r_buffer_2, r_index_1));
+
+        __ bind(done);
+
+#ifdef AARCH64
+        __ raw_pop(R2, R3);
+        __ raw_pop(R0, R1);
+#else // AARCH64
+        __ pop(saved_regs);
+#endif // AARCH64
+
+        __ ret();
+
+        __ bind(runtime);
+
+        save_live_registers(sasm);
+
+        assert(r_pre_val_0 == c_rarg0, "pre_val should be in R0");
+        __ mov(c_rarg1, Rthread);
+        __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), c_rarg0, c_rarg1);
+
+        restore_live_registers_without_return(sasm);
+
+        __ b(done);
+      }
+      break;
+    case g1_post_barrier_slow_id:
+      {
+        // Input:
+        // - store_addr, pushed on the stack
+
+        __ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
+
+        BarrierSet* bs = Universe::heap()->barrier_set();
+        CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
+        Label done;
+        Label recheck;
+        Label runtime;
+
+        Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
+                                              DirtyCardQueue::byte_offset_of_index()));
+        Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
+                                         DirtyCardQueue::byte_offset_of_buf()));
+
+        AddressLiteral cardtable((address)ct->byte_map_base);
+        assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+
+        // save at least the registers that need saving if the runtime is called
+#ifdef AARCH64
+        __ raw_push(R0, R1);
+        __ raw_push(R2, R3);
+        const int nb_saved_regs = 4;
+#else // AARCH64
+        const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
+        const int nb_saved_regs = 6;
+        assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
+        __ push(saved_regs);
+#endif // AARCH64
+
+        const Register r_card_addr_0 = R0; // must be R0 for the slow case
+        const Register r_obj_0 = R0;
+        const Register r_card_base_1 = R1;
+        const Register r_tmp2 = R2;
+        const Register r_index_2 = R2;
+        const Register r_buffer_3 = R3;
+        const Register tmp1 = Rtemp;
+
+        __ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize));
+        // Note: there is a comment in x86 code about not using
+        // ExternalAddress / lea, due to relocation not working
+        // properly for that address. Should be OK for arm, where we
+        // explicitly specify that 'cartable' has a relocInfo::none
+        // type.
+        __ lea(r_card_base_1, cardtable);
+        __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTableModRefBS::card_shift));
+
+        // first quick check without barrier
+        __ ldrb(r_tmp2, Address(r_card_addr_0));
+
+        __ cmp(r_tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val());
+        __ b(recheck, ne);
+
+        __ bind(done);
+
+#ifdef AARCH64
+        __ raw_pop(R2, R3);
+        __ raw_pop(R0, R1);
+#else // AARCH64
+        __ pop(saved_regs);
+#endif // AARCH64
+
+        __ ret();
+
+        __ bind(recheck);
+
+        __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1);
+
+        // reload card state after the barrier that ensures the stored oop was visible
+        __ ldrb(r_tmp2, Address(r_card_addr_0));
+
+        assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code");
+        __ cbz(r_tmp2, done);
+
+        // storing region crossing non-NULL, card is clean.
+        // dirty card and log.
+
+        assert(0 == (int)CardTableModRefBS::dirty_card_val(), "adjust this code");
+        if (((intptr_t)ct->byte_map_base & 0xff) == 0) {
+          // Card table is aligned so the lowest byte of the table address base is zero.
+          __ strb(r_card_base_1, Address(r_card_addr_0));
+        } else {
+          __ strb(__ zero_register(r_tmp2), Address(r_card_addr_0));
+        }
+
+        __ ldr(r_index_2, queue_index);
+        __ ldr(r_buffer_3, buffer);
+
+        __ subs(r_index_2, r_index_2, wordSize);
+        __ b(runtime, lt); // go to runtime if now negative
+
+        __ str(r_index_2, queue_index);
+
+        __ str(r_card_addr_0, Address(r_buffer_3, r_index_2));
+
+        __ b(done);
+
+        __ bind(runtime);
+
+        save_live_registers(sasm);
+
+        assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0");
+        __ mov(c_rarg1, Rthread);
+        __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), c_rarg0, c_rarg1);
+
+        restore_live_registers_without_return(sasm);
+
+        __ b(done);
+      }
+      break;
+#endif // INCLUDE_ALL_GCS
+    case new_instance_id:
+    case fast_new_instance_id:
+    case fast_new_instance_init_check_id:
+      {
+        const Register result = R0;
+        const Register klass  = R1;
+
+        if (UseTLAB && FastTLABRefill && id != new_instance_id) {
+          // We come here when TLAB allocation failed.
+          // In this case we either refill TLAB or allocate directly from eden.
+          Label retry_tlab, try_eden, slow_case, slow_case_no_pop;
+
+          // Make sure the class is fully initialized
+          if (id == fast_new_instance_init_check_id) {
+            __ ldrb(result, Address(klass, InstanceKlass::init_state_offset()));
+            __ cmp(result, InstanceKlass::fully_initialized);
+            __ b(slow_case_no_pop, ne);
+          }
+
+          // Free some temporary registers
+          const Register obj_size = R4;
+          const Register tmp1     = R5;
+          const Register tmp2     = LR;
+          const Register obj_end  = Rtemp;
+
+          __ raw_push(R4, R5, LR);
+
+          __ tlab_refill(result, obj_size, tmp1, tmp2, obj_end, try_eden, slow_case);
+
+          __ bind(retry_tlab);
+          __ ldr_u32(obj_size, Address(klass, Klass::layout_helper_offset()));
+          __ tlab_allocate(result, obj_end, tmp1, obj_size, slow_case);              // initializes result and obj_end
+          __ initialize_object(result, obj_end, klass, noreg /* len */, tmp1, tmp2,
+                               instanceOopDesc::header_size() * HeapWordSize, -1,
+                               /* is_tlab_allocated */ true);
+          __ raw_pop_and_ret(R4, R5);
+
+          __ bind(try_eden);
+          __ ldr_u32(obj_size, Address(klass, Klass::layout_helper_offset()));
+          __ eden_allocate(result, obj_end, tmp1, tmp2, obj_size, slow_case);        // initializes result and obj_end
+          __ incr_allocated_bytes(obj_size, tmp2);
+          __ initialize_object(result, obj_end, klass, noreg /* len */, tmp1, tmp2,
+                               instanceOopDesc::header_size() * HeapWordSize, -1,
+                               /* is_tlab_allocated */ false);
+          __ raw_pop_and_ret(R4, R5);
+
+          __ bind(slow_case);
+          __ raw_pop(R4, R5, LR);
+
+          __ bind(slow_case_no_pop);
+        }
+
+        OopMap* map = save_live_registers(sasm);
+        int call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_instance), klass);
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, map);
+
+        // MacroAssembler::StoreStore useless (included in the runtime exit path)
+
+        restore_live_registers_except_R0(sasm);
+      }
+      break;
+
+    case counter_overflow_id:
+      {
+        OopMap* oop_map = save_live_registers(sasm);
+        __ ldr(R1, Address(SP, arg1_offset));
+        __ ldr(R2, Address(SP, arg2_offset));
+        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), R1, R2);
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, oop_map);
+        restore_live_registers(sasm);
+      }
+      break;
+
+    case new_type_array_id:
+    case new_object_array_id:
+      {
+        if (id == new_type_array_id) {
+          __ set_info("new_type_array", dont_gc_arguments);
+        } else {
+          __ set_info("new_object_array", dont_gc_arguments);
+        }
+
+        const Register result = R0;
+        const Register klass  = R1;
+        const Register length = R2;
+
+        if (UseTLAB && FastTLABRefill) {
+          // We come here when TLAB allocation failed.
+          // In this case we either refill TLAB or allocate directly from eden.
+          Label retry_tlab, try_eden, slow_case, slow_case_no_pop;
+
+#ifdef AARCH64
+          __ mov_slow(Rtemp, C1_MacroAssembler::max_array_allocation_length);
+          __ cmp_32(length, Rtemp);
+#else
+          __ cmp_32(length, C1_MacroAssembler::max_array_allocation_length);
+#endif // AARCH64
+          __ b(slow_case_no_pop, hs);
+
+          // Free some temporary registers
+          const Register arr_size = R4;
+          const Register tmp1     = R5;
+          const Register tmp2     = LR;
+          const Register tmp3     = Rtemp;
+          const Register obj_end  = tmp3;
+
+          __ raw_push(R4, R5, LR);
+
+          __ tlab_refill(result, arr_size, tmp1, tmp2, tmp3, try_eden, slow_case);
+
+          __ bind(retry_tlab);
+          // Get the allocation size: round_up((length << (layout_helper & 0xff)) + header_size)
+          __ ldr_u32(tmp1, Address(klass, Klass::layout_helper_offset()));
+          __ mov(arr_size, MinObjAlignmentInBytesMask);
+          __ and_32(tmp2, tmp1, (unsigned int)(Klass::_lh_header_size_mask << Klass::_lh_header_size_shift));
+
+#ifdef AARCH64
+          __ lslv_w(tmp3, length, tmp1);
+          __ add(arr_size, arr_size, tmp3);
+#else
+          __ add(arr_size, arr_size, AsmOperand(length, lsl, tmp1));
+#endif // AARCH64
+
+          __ add(arr_size, arr_size, AsmOperand(tmp2, lsr, Klass::_lh_header_size_shift));
+          __ align_reg(arr_size, arr_size, MinObjAlignmentInBytes);
+
+          // tlab_allocate initializes result and obj_end, and preserves tmp2 which contains header_size
+          __ tlab_allocate(result, obj_end, tmp1, arr_size, slow_case);
+
+          assert_different_registers(result, obj_end, klass, length, tmp1, tmp2);
+          __ initialize_header(result, klass, length, tmp1);
+
+          __ add(tmp2, result, AsmOperand(tmp2, lsr, Klass::_lh_header_size_shift));
+          if (!ZeroTLAB) {
+            __ initialize_body(tmp2, obj_end, tmp1);
+          }
+
+          __ membar(MacroAssembler::StoreStore, tmp1);
+
+          __ raw_pop_and_ret(R4, R5);
+
+          __ bind(try_eden);
+          // Get the allocation size: round_up((length << (layout_helper & 0xff)) + header_size)
+          __ ldr_u32(tmp1, Address(klass, Klass::layout_helper_offset()));
+          __ mov(arr_size, MinObjAlignmentInBytesMask);
+          __ and_32(tmp2, tmp1, (unsigned int)(Klass::_lh_header_size_mask << Klass::_lh_header_size_shift));
+
+#ifdef AARCH64
+          __ lslv_w(tmp3, length, tmp1);
+          __ add(arr_size, arr_size, tmp3);
+#else
+          __ add(arr_size, arr_size, AsmOperand(length, lsl, tmp1));
+#endif // AARCH64
+
+          __ add(arr_size, arr_size, AsmOperand(tmp2, lsr, Klass::_lh_header_size_shift));
+          __ align_reg(arr_size, arr_size, MinObjAlignmentInBytes);
+
+          // eden_allocate destroys tmp2, so reload header_size after allocation
+          // eden_allocate initializes result and obj_end
+          __ eden_allocate(result, obj_end, tmp1, tmp2, arr_size, slow_case);
+          __ incr_allocated_bytes(arr_size, tmp2);
+          __ ldrb(tmp2, Address(klass, in_bytes(Klass::layout_helper_offset()) +
+                                       Klass::_lh_header_size_shift / BitsPerByte));
+          __ initialize_object(result, obj_end, klass, length, tmp1, tmp2, tmp2, -1, /* is_tlab_allocated */ false);
+          __ raw_pop_and_ret(R4, R5);
+
+          __ bind(slow_case);
+          __ raw_pop(R4, R5, LR);
+          __ bind(slow_case_no_pop);
+        }
+
+        OopMap* map = save_live_registers(sasm);
+        int call_offset;
+        if (id == new_type_array_id) {
+          call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
+        } else {
+          call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
+        }
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, map);
+
+        // MacroAssembler::StoreStore useless (included in the runtime exit path)
+
+        restore_live_registers_except_R0(sasm);
+      }
+      break;
+
+    case new_multi_array_id:
+      {
+        __ set_info("new_multi_array", dont_gc_arguments);
+
+        // R0: klass
+        // R2: rank
+        // SP: address of 1st dimension
+        const Register result = R0;
+        OopMap* map = save_live_registers(sasm);
+
+        __ mov(R1, R0);
+        __ add(R3, SP, arg1_offset);
+        int call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_multi_array), R1, R2, R3);
+
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, map);
+
+        // MacroAssembler::StoreStore useless (included in the runtime exit path)
+
+        restore_live_registers_except_R0(sasm);
+      }
+      break;
+
+    case register_finalizer_id:
+      {
+        __ set_info("register_finalizer", dont_gc_arguments);
+
+        // Do not call runtime if JVM_ACC_HAS_FINALIZER flag is not set
+        __ load_klass(Rtemp, R0);
+        __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset()));
+
+#ifdef AARCH64
+        Label L;
+        __ tbnz(Rtemp, exact_log2(JVM_ACC_HAS_FINALIZER), L);
+        __ ret();
+        __ bind(L);
+#else
+        __ tst(Rtemp, JVM_ACC_HAS_FINALIZER);
+        __ bx(LR, eq);
+#endif // AARCH64
+
+        // Call VM
+        OopMap* map = save_live_registers(sasm);
+        oop_maps = new OopMapSet();
+        int call_offset = __ call_RT(noreg, noreg,
+                                     CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), R0);
+        oop_maps->add_gc_map(call_offset, map);
+        restore_live_registers(sasm);
+      }
+      break;
+
+    case throw_range_check_failed_id:
+      {
+        __ set_info("range_check_failed", dont_gc_arguments);
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
+      }
+      break;
+
+    case throw_index_exception_id:
+      {
+        __ set_info("index_range_check_failed", dont_gc_arguments);
+#ifdef AARCH64
+        __ NOT_TESTED();
+#endif
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
+      }
+      break;
+
+    case throw_div0_exception_id:
+      {
+        __ set_info("throw_div0_exception", dont_gc_arguments);
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
+      }
+      break;
+
+    case throw_null_pointer_exception_id:
+      {
+        __ set_info("throw_null_pointer_exception", dont_gc_arguments);
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
+      }
+      break;
+
+    case handle_exception_nofpu_id:
+    case handle_exception_id:
+      {
+        __ set_info("handle_exception", dont_gc_arguments);
+        oop_maps = generate_handle_exception(id, sasm);
+      }
+      break;
+
+    case handle_exception_from_callee_id:
+      {
+        __ set_info("handle_exception_from_callee", dont_gc_arguments);
+        oop_maps = generate_handle_exception(id, sasm);
+      }
+      break;
+
+    case unwind_exception_id:
+      {
+        __ set_info("unwind_exception", dont_gc_arguments);
+        generate_unwind_exception(sasm);
+      }
+      break;
+
+    case throw_array_store_exception_id:
+      {
+        __ set_info("throw_array_store_exception", dont_gc_arguments);
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
+      }
+      break;
+
+    case throw_class_cast_exception_id:
+      {
+        __ set_info("throw_class_cast_exception", dont_gc_arguments);
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
+      }
+      break;
+
+    case throw_incompatible_class_change_error_id:
+      {
+        __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
+#ifdef AARCH64
+        __ NOT_TESTED();
+#endif
+        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
+      }
+      break;
+
+    case slow_subtype_check_id:
+      {
+        // (in)  R0 - sub, destroyed,
+        // (in)  R1 - super, not changed
+        // (out) R0 - result: 1 if check passed, 0 otherwise
+        __ raw_push(R2, R3, LR);
+
+        // Load an array of secondary_supers
+        __ ldr(R2, Address(R0, Klass::secondary_supers_offset()));
+        // Length goes to R3
+        __ ldr_s32(R3, Address(R2, Array<Klass*>::length_offset_in_bytes()));
+        __ add(R2, R2, Array<Klass*>::base_offset_in_bytes());
+
+        Label loop, miss;
+        __ bind(loop);
+        __ cbz(R3, miss);
+        __ ldr(LR, Address(R2, wordSize, post_indexed));
+        __ sub(R3, R3, 1);
+        __ cmp(LR, R1);
+        __ b(loop, ne);
+
+        // We get here if an equal cache entry is found
+        __ str(R1, Address(R0, Klass::secondary_super_cache_offset()));
+        __ mov(R0, 1);
+        __ raw_pop_and_ret(R2, R3);
+
+        // A cache entry not found - return false
+        __ bind(miss);
+        __ mov(R0, 0);
+        __ raw_pop_and_ret(R2, R3);
+      }
+      break;
+
+    case monitorenter_nofpu_id:
+      save_fpu_registers = false;
+      // fall through
+    case monitorenter_id:
+      {
+        __ set_info("monitorenter", dont_gc_arguments);
+        const Register obj  = R1;
+        const Register lock = R2;
+        OopMap* map = save_live_registers(sasm, save_fpu_registers);
+        __ ldr(obj, Address(SP, arg1_offset));
+        __ ldr(lock, Address(SP, arg2_offset));
+        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), obj, lock);
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, map);
+        restore_live_registers(sasm, save_fpu_registers);
+      }
+      break;
+
+    case monitorexit_nofpu_id:
+      save_fpu_registers = false;
+      // fall through
+    case monitorexit_id:
+      {
+        __ set_info("monitorexit", dont_gc_arguments);
+        const Register lock = R1;
+        OopMap* map = save_live_registers(sasm, save_fpu_registers);
+        __ ldr(lock, Address(SP, arg1_offset));
+        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), lock);
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, map);
+        restore_live_registers(sasm, save_fpu_registers);
+      }
+      break;
+
+    case deoptimize_id:
+      {
+        __ set_info("deoptimize", dont_gc_arguments);
+        OopMap* oop_map = save_live_registers(sasm);
+        const Register trap_request = R1;
+        __ ldr(trap_request, Address(SP, arg1_offset));
+        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize), trap_request);
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, oop_map);
+        restore_live_registers_without_return(sasm);
+        DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+        assert(deopt_blob != NULL, "deoptimization blob must have been created");
+        __ jump(deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type, AARCH64_ONLY(Rtemp) NOT_AARCH64(noreg));
+      }
+      break;
+
+    case access_field_patching_id:
+      {
+        __ set_info("access_field_patching", dont_gc_arguments);
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
+      }
+      break;
+
+    case load_klass_patching_id:
+      {
+        __ set_info("load_klass_patching", dont_gc_arguments);
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
+      }
+      break;
+
+    case load_appendix_patching_id:
+      {
+        __ set_info("load_appendix_patching", dont_gc_arguments);
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
+      }
+      break;
+
+    case load_mirror_patching_id:
+      {
+        __ set_info("load_mirror_patching", dont_gc_arguments);
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
+      }
+      break;
+
+    case predicate_failed_trap_id:
+      {
+        __ set_info("predicate_failed_trap", dont_gc_arguments);
+
+        OopMap* oop_map = save_live_registers(sasm);
+        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap));
+
+        oop_maps = new OopMapSet();
+        oop_maps->add_gc_map(call_offset, oop_map);
+
+        restore_live_registers_without_return(sasm);
+
+        DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+        assert(deopt_blob != NULL, "deoptimization blob must have been created");
+        __ jump(deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type, Rtemp);
+      }
+      break;
+
+    default:
+      {
+        __ set_info("unimplemented entry", dont_gc_arguments);
+        STOP("unimplemented entry");
+      }
+      break;
+  }
+  return oop_maps;
+}
+
+#undef __
+
+#ifdef __SOFTFP__
+const char *Runtime1::pd_name_for_address(address entry) {
+
+#define FUNCTION_CASE(a, f) \
+  if ((intptr_t)a == CAST_FROM_FN_PTR(intptr_t, f))  return #f
+
+  FUNCTION_CASE(entry, __aeabi_fadd_glibc);
+  FUNCTION_CASE(entry, __aeabi_fmul);
+  FUNCTION_CASE(entry, __aeabi_fsub_glibc);
+  FUNCTION_CASE(entry, __aeabi_fdiv);
+
+  // __aeabi_XXXX_glibc: Imported code from glibc soft-fp bundle for calculation accuracy improvement. See CR 6757269.
+  FUNCTION_CASE(entry, __aeabi_dadd_glibc);
+  FUNCTION_CASE(entry, __aeabi_dmul);
+  FUNCTION_CASE(entry, __aeabi_dsub_glibc);
+  FUNCTION_CASE(entry, __aeabi_ddiv);
+
+  FUNCTION_CASE(entry, __aeabi_f2d);
+  FUNCTION_CASE(entry, __aeabi_d2f);
+  FUNCTION_CASE(entry, __aeabi_i2f);
+  FUNCTION_CASE(entry, __aeabi_i2d);
+  FUNCTION_CASE(entry, __aeabi_f2iz);
+
+  FUNCTION_CASE(entry, SharedRuntime::fcmpl);
+  FUNCTION_CASE(entry, SharedRuntime::fcmpg);
+  FUNCTION_CASE(entry, SharedRuntime::dcmpl);
+  FUNCTION_CASE(entry, SharedRuntime::dcmpg);
+
+  FUNCTION_CASE(entry, SharedRuntime::unordered_fcmplt);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_dcmplt);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_fcmple);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_dcmple);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_fcmpge);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_dcmpge);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_fcmpgt);
+  FUNCTION_CASE(entry, SharedRuntime::unordered_dcmpgt);
+
+  FUNCTION_CASE(entry, SharedRuntime::fneg);
+  FUNCTION_CASE(entry, SharedRuntime::dneg);
+
+  FUNCTION_CASE(entry, __aeabi_fcmpeq);
+  FUNCTION_CASE(entry, __aeabi_fcmplt);
+  FUNCTION_CASE(entry, __aeabi_fcmple);
+  FUNCTION_CASE(entry, __aeabi_fcmpge);
+  FUNCTION_CASE(entry, __aeabi_fcmpgt);
+
+  FUNCTION_CASE(entry, __aeabi_dcmpeq);
+  FUNCTION_CASE(entry, __aeabi_dcmplt);
+  FUNCTION_CASE(entry, __aeabi_dcmple);
+  FUNCTION_CASE(entry, __aeabi_dcmpge);
+  FUNCTION_CASE(entry, __aeabi_dcmpgt);
+#undef FUNCTION_CASE
+  return "";
+}
+#else  // __SOFTFP__
+const char *Runtime1::pd_name_for_address(address entry) {
+  return "<unknown function>";
+}
+#endif // __SOFTFP__
diff --git a/hotspot/src/cpu/arm/vm/c1_globals_arm.hpp b/hotspot/src/cpu/arm/vm/c1_globals_arm.hpp
new file mode 100644
index 0000000..96a93bf
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c1_globals_arm.hpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C1_GLOBALS_ARM_HPP
+#define CPU_ARM_VM_C1_GLOBALS_ARM_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for platform dependent flags used by the client compiler.
+// (see c1_globals.hpp)
+//
+
+#ifndef COMPILER2 // avoid duplicated definitions, favoring C2 version
+define_pd_global(bool, BackgroundCompilation,        true );
+define_pd_global(bool, UseTLAB,                      true );
+define_pd_global(bool, ResizeTLAB,                   true );
+define_pd_global(bool, InlineIntrinsics,             false); // TODO: ARM
+define_pd_global(bool, PreferInterpreterNativeStubs, false);
+define_pd_global(bool, ProfileTraps,                 false);
+define_pd_global(bool, UseOnStackReplacement,        true );
+define_pd_global(bool, TieredCompilation,            false);
+define_pd_global(intx, CompileThreshold,             1500 );
+
+define_pd_global(intx, OnStackReplacePercentage,     933  );
+define_pd_global(intx, FreqInlineSize,               325  );
+define_pd_global(size_t, NewSizeThreadIncrease,      4*K  );
+define_pd_global(size_t, InitialCodeCacheSize,       160*K);
+define_pd_global(size_t, ReservedCodeCacheSize,      32*M );
+define_pd_global(size_t, NonProfiledCodeHeapSize,    13*M );
+define_pd_global(size_t, ProfiledCodeHeapSize,       14*M );
+define_pd_global(size_t, NonNMethodCodeHeapSize,     5*M  );
+define_pd_global(bool, ProfileInterpreter,           false);
+define_pd_global(size_t, CodeCacheExpansionSize,     32*K );
+define_pd_global(uintx, CodeCacheMinBlockLength,     1);
+define_pd_global(size_t, CodeCacheMinimumUseSpace,   400*K);
+define_pd_global(size_t, MetaspaceSize,              12*M );
+define_pd_global(bool, NeverActAsServerClassMachine, true);
+define_pd_global(uint64_t, MaxRAM,                   1ULL*G);
+define_pd_global(bool, CICompileOSR,                 true );
+#endif // COMPILER2
+define_pd_global(bool, UseTypeProfile,               false);
+define_pd_global(bool, RoundFPResults,               false);
+
+
+define_pd_global(bool, LIRFillDelaySlots,            false);
+define_pd_global(bool, OptimizeSinglePrecision,      true);
+define_pd_global(bool, CSEArrayLength,               true);
+define_pd_global(bool, TwoOperandLIRForm,            false);
+
+#endif // CPU_ARM_VM_C1_GLOBALS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/c2_globals_arm.hpp b/hotspot/src/cpu/arm/vm/c2_globals_arm.hpp
new file mode 100644
index 0000000..4b424ed
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/c2_globals_arm.hpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_C2_GLOBALS_ARM_HPP
+#define CPU_ARM_VM_C2_GLOBALS_ARM_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for platform dependent flags used by the server compiler.
+// (see c2_globals.hpp).  Alpha-sorted.
+
+define_pd_global(bool, BackgroundCompilation,        true);
+define_pd_global(bool, CICompileOSR,                 true);
+define_pd_global(bool, InlineIntrinsics,             false);
+define_pd_global(bool, PreferInterpreterNativeStubs, false);
+define_pd_global(bool, ProfileTraps,                 true);
+define_pd_global(bool, UseOnStackReplacement,        true);
+define_pd_global(bool, ProfileInterpreter,           true);
+#ifdef AARCH64
+define_pd_global(bool, TieredCompilation,            trueInTiered);
+#else
+define_pd_global(bool, TieredCompilation,            false);
+#endif
+define_pd_global(intx, CompileThreshold,             10000);
+
+define_pd_global(intx, OnStackReplacePercentage,     140);
+define_pd_global(intx, ConditionalMoveLimit,         4);
+// C2 gets to use all the float/double registers
+#ifdef AARCH64
+define_pd_global(intx, FLOATPRESSURE,                31);
+#else
+define_pd_global(intx, FLOATPRESSURE,                30);
+#endif
+define_pd_global(intx, FreqInlineSize,               175);
+#ifdef AARCH64
+define_pd_global(intx, INTPRESSURE,                  27);
+#else
+define_pd_global(intx, INTPRESSURE,                  12);
+#endif
+define_pd_global(intx, InteriorEntryAlignment,       16);  // = CodeEntryAlignment
+define_pd_global(size_t, NewSizeThreadIncrease,      ScaleForWordSize(4*K));
+// The default setting 16/16 seems to work best.
+// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
+//define_pd_global(intx, OptoLoopAlignment,            16);  // = 4*wordSize
+define_pd_global(intx, RegisterCostAreaRatio,        16000);
+define_pd_global(bool, UseTLAB,                      true);
+define_pd_global(bool, ResizeTLAB,                   true);
+define_pd_global(intx, LoopUnrollLimit,              60); // Design center runs on 1.3.1
+define_pd_global(intx, LoopPercentProfileLimit,      10);
+define_pd_global(intx, PostLoopMultiversioning,      false);
+define_pd_global(intx, MinJumpTableSize,             16);
+
+// Peephole and CISC spilling both break the graph, and so makes the
+// scheduler sick.
+define_pd_global(bool, OptoPeephole,                 false);
+define_pd_global(bool, UseCISCSpill,                 false);
+define_pd_global(bool, OptoBundling,                 false);
+define_pd_global(bool, OptoScheduling,               true);
+define_pd_global(bool, OptoRegScheduling,            false);
+define_pd_global(bool, SuperWordLoopUnrollAnalysis,  false);
+define_pd_global(bool, IdealizeClearArrayNode,       true);
+
+#ifdef _LP64
+// We need to make sure that all generated code is within
+// 2 gigs of the libjvm.so runtime routines so we can use
+// the faster "call" instruction rather than the expensive
+// sequence of instructions to load a 64 bit pointer.
+//
+// InitialCodeCacheSize derived from specjbb2000 run.
+define_pd_global(size_t, InitialCodeCacheSize,       2048*K); // Integral multiple of CodeCacheExpansionSize
+define_pd_global(size_t, ReservedCodeCacheSize,      48*M);
+define_pd_global(size_t, NonProfiledCodeHeapSize,    21*M);
+define_pd_global(size_t, ProfiledCodeHeapSize,       22*M);
+define_pd_global(size_t, NonNMethodCodeHeapSize,     5*M );
+define_pd_global(size_t, CodeCacheExpansionSize,     64*K);
+
+// Ergonomics related flags
+define_pd_global(uint64_t, MaxRAM,                   128ULL*G);
+#else
+// InitialCodeCacheSize derived from specjbb2000 run.
+define_pd_global(size_t, InitialCodeCacheSize,       1536*K); // Integral multiple of CodeCacheExpansionSize
+define_pd_global(size_t, ReservedCodeCacheSize,      32*M);
+define_pd_global(size_t, NonProfiledCodeHeapSize,    13*M);
+define_pd_global(size_t, ProfiledCodeHeapSize,       14*M);
+define_pd_global(size_t, NonNMethodCodeHeapSize,     5*M );
+define_pd_global(size_t, CodeCacheExpansionSize,     32*K);
+// Ergonomics related flags
+define_pd_global(uint64_t, MaxRAM,                   4ULL*G);
+#endif
+define_pd_global(uintx, CodeCacheMinBlockLength,     4);
+define_pd_global(size_t, CodeCacheMinimumUseSpace,   400*K);
+
+define_pd_global(bool,  TrapBasedRangeChecks,        false); // Not needed
+
+// Heap related flags
+define_pd_global(size_t, MetaspaceSize,              ScaleForWordSize(16*M));
+
+// Ergonomics related flags
+define_pd_global(bool, NeverActAsServerClassMachine, false);
+
+#endif // CPU_ARM_VM_C2_GLOBALS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/codeBuffer_arm.hpp b/hotspot/src/cpu/arm/vm/codeBuffer_arm.hpp
new file mode 100644
index 0000000..90534fd
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/codeBuffer_arm.hpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_CODEBUFFER_ARM_HPP
+#define CPU_ARM_VM_CODEBUFFER_ARM_HPP
+
+private:
+  void pd_initialize() {}
+
+public:
+  void flush_bundle(bool start_new_bundle) {}
+
+#endif // CPU_ARM_VM_CODEBUFFER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/compiledIC_arm.cpp b/hotspot/src/cpu/arm/vm/compiledIC_arm.cpp
new file mode 100644
index 0000000..de7249f
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/compiledIC_arm.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nativeInst.hpp"
+#include "code/nmethod.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+
+// ----------------------------------------------------------------------------
+#if defined(COMPILER2) || INCLUDE_JVMCI
+#define __ _masm.
+// emit call stub, compiled java to interpreter
+address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) {
+  // Stub is fixed up when the corresponding call is converted from calling
+  // compiled code to calling interpreted code.
+  // set (empty), R9
+  // b -1
+
+  if (mark == NULL) {
+    mark = cbuf.insts_mark();  // get mark within main instrs section
+  }
+
+  MacroAssembler _masm(&cbuf);
+
+  address base = __ start_a_stub(to_interp_stub_size());
+  if (base == NULL) {
+    return NULL;  // CodeBuffer::expand failed
+  }
+
+  // static stub relocation stores the instruction address of the call
+  __ relocate(static_stub_Relocation::spec(mark));
+
+  InlinedMetadata object_literal(NULL);
+  // single instruction, see NativeMovConstReg::next_instruction_address() in
+  // CompiledStaticCall::set_to_interpreted()
+  __ ldr_literal(Rmethod, object_literal);
+
+  __ set_inst_mark(); // Who uses this?
+
+  bool near_range = __ cache_fully_reachable();
+  InlinedAddress dest((address)-1);
+  address branch_site = __ pc();
+  if (near_range) {
+    __ b(branch_site); // special NativeJump -1 destination
+  } else {
+    // Can't trash LR, FP, or argument registers
+    __ indirect_jump(dest, Rtemp);
+  }
+  __ bind_literal(object_literal); // includes spec_for_immediate reloc
+  if (!near_range) {
+    __ bind_literal(dest); // special NativeJump -1 destination
+  }
+
+  assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size");
+
+  // Update current stubs pointer and restore code_end.
+  __ end_a_stub();
+  return base;
+}
+#undef __
+
+// size of C2 call stub, compiled java to interpretor
+int CompiledStaticCall::to_interp_stub_size() {
+  return 8 * NativeInstruction::instruction_size;
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+  return 10;  // 4 in emit_to_interp_stub + 1 in Java_Static_Call
+}
+#endif // COMPILER2 || JVMCI
+
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(/*is_aot*/ false);
+  guarantee(stub != NULL, "stub not found");
+
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+                  p2i(instruction_address()),
+                  callee->name_and_sig_as_C_string());
+  }
+
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+#ifdef ASSERT
+  // read the value once
+  volatile intptr_t data = method_holder->data();
+  volatile address destination = jump->jump_destination();
+  assert(data == 0 || data == (intptr_t)callee(),
+         "a) MT-unsafe modification of inline cache");
+  assert(destination == (address)-1 || destination == entry,
+         "b) MT-unsafe modification of inline cache");
+#endif
+
+  // Update stub.
+  method_holder->set_data((intptr_t)callee());
+  jump->set_jump_destination(entry);
+
+  // Update jump to call.
+  set_destination_mt_safe(stub);
+}
+
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  // Reset stub.
+  address stub = static_stub->addr();
+  assert(stub != NULL, "stub not found");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+  method_holder->set_data(0);
+  jump->set_jump_destination((address)-1);
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code
+#ifndef PRODUCT
+
+void CompiledDirectStaticCall::verify() {
+  // Verify call.
+  _call->verify();
+  if (os::is_MP()) {
+    _call->verify_alignment();
+  }
+
+  // Verify stub.
+  address stub = find_stub(/*is_aot*/ false);
+  assert(stub != NULL, "no stub found for static call");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+  // Verify state.
+  assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+
+#endif // !PRODUCT
diff --git a/hotspot/src/cpu/arm/vm/copy_arm.hpp b/hotspot/src/cpu/arm/vm/copy_arm.hpp
new file mode 100644
index 0000000..47cef1f
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/copy_arm.hpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_COPY_ARM_HPP
+#define CPU_ARM_VM_COPY_ARM_HPP
+
+#include "utilities/macros.hpp"
+
+// Inline functions for memory copy and fill.
+
+// Contains inline asm implementations
+#include OS_CPU_HEADER_INLINE(copy)
+
+static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
+  juint* to = (juint*)tohw;
+  count *= HeapWordSize / BytesPerInt;
+  while (count-- > 0) {
+    *to++ = value;
+  }
+}
+
+static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
+  pd_fill_to_words(tohw, count, value);
+}
+
+static void pd_fill_to_bytes(void* to, size_t count, jubyte value) {
+  memset(to, value, count);
+}
+
+static void pd_zero_to_words(HeapWord* tohw, size_t count) {
+  pd_fill_to_words(tohw, count, 0);
+}
+
+static void pd_zero_to_bytes(void* to, size_t count) {
+  memset(to, 0, count);
+}
+
+#endif // CPU_ARM_VM_COPY_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/debug_arm.cpp b/hotspot/src/cpu/arm/vm/debug_arm.cpp
new file mode 100644
index 0000000..ba3e67a
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/debug_arm.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "code/codeCache.hpp"
+#include "code/nmethod.hpp"
+#include "runtime/frame.hpp"
+#include "runtime/init.hpp"
+#include "runtime/os.hpp"
+#include "utilities/debug.hpp"
+
+void pd_ps(frame f) {}
diff --git a/hotspot/src/cpu/arm/vm/depChecker_arm.cpp b/hotspot/src/cpu/arm/vm/depChecker_arm.cpp
new file mode 100644
index 0000000..4a7f2b4
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/depChecker_arm.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "compiler/disassembler.hpp"
+#include "depChecker_arm.hpp"
+
+// Nothing to do
diff --git a/hotspot/src/cpu/arm/vm/depChecker_arm.hpp b/hotspot/src/cpu/arm/vm/depChecker_arm.hpp
new file mode 100644
index 0000000..6a7161d
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/depChecker_arm.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_DEPCHECKER_ARM_HPP
+#define CPU_ARM_VM_DEPCHECKER_ARM_HPP
+
+// Nothing to do
+
+#endif // CPU_ARM_VM_DEPCHECKER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/disassembler_arm.hpp b/hotspot/src/cpu/arm/vm/disassembler_arm.hpp
new file mode 100644
index 0000000..ea201d7
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/disassembler_arm.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_DISASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_DISASSEMBLER_ARM_HPP
+
+  static int pd_instruction_alignment() {
+    return sizeof(int);
+  }
+
+  static const char* pd_cpu_opts() {
+    return "";
+  }
+
+#endif // CPU_ARM_VM_DISASSEMBLER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/frame_arm.cpp b/hotspot/src/cpu/arm/vm/frame_arm.cpp
new file mode 100644
index 0000000..55f468f
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/frame_arm.cpp
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/markOop.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/monitorChunk.hpp"
+#include "runtime/signature.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "vmreg_arm.inline.hpp"
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#include "runtime/vframeArray.hpp"
+#endif
+#include "prims/methodHandles.hpp"
+
+#ifdef ASSERT
+void RegisterMap::check_location_valid() {
+}
+#endif
+
+
+// Profiling/safepoint support
+
+bool frame::safe_for_sender(JavaThread *thread) {
+  address   sp = (address)_sp;
+  address   fp = (address)_fp;
+  address   unextended_sp = (address)_unextended_sp;
+
+  static size_t stack_guard_size = os::uses_stack_guard_pages() ?
+    (JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size()) : 0;
+  size_t usable_stack_size = thread->stack_size() - stack_guard_size;
+
+  // sp must be within the usable part of the stack (not in guards)
+  bool sp_safe = (sp != NULL &&
+                 (sp <= thread->stack_base()) &&
+                 (sp >= thread->stack_base() - usable_stack_size));
+
+  if (!sp_safe) {
+    return false;
+  }
+
+  bool unextended_sp_safe = (unextended_sp != NULL &&
+                             (unextended_sp <= thread->stack_base()) &&
+                             (unextended_sp >= sp));
+  if (!unextended_sp_safe) {
+    return false;
+  }
+
+  // We know sp/unextended_sp are safe. Only fp is questionable here.
+
+  bool fp_safe = (fp != NULL &&
+                  (fp <= thread->stack_base()) &&
+                  fp >= sp);
+
+  if (_cb != NULL ) {
+
+    // First check if frame is complete and tester is reliable
+    // Unfortunately we can only check frame complete for runtime stubs and nmethod
+    // other generic buffer blobs are more problematic so we just assume they are
+    // ok. adapter blobs never have a frame complete and are never ok.
+
+    if (!_cb->is_frame_complete_at(_pc)) {
+      if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
+        return false;
+      }
+    }
+
+    // Could just be some random pointer within the codeBlob
+    if (!_cb->code_contains(_pc)) {
+      return false;
+    }
+
+    // Entry frame checks
+    if (is_entry_frame()) {
+      // an entry frame must have a valid fp.
+      return fp_safe && is_entry_frame_valid(thread);
+    }
+
+    intptr_t* sender_sp = NULL;
+    address   sender_pc = NULL;
+
+    if (is_interpreted_frame()) {
+      // fp must be safe
+      if (!fp_safe) {
+        return false;
+      }
+
+      sender_pc = (address) this->fp()[return_addr_offset];
+      sender_sp = (intptr_t*) addr_at(sender_sp_offset);
+
+    } else {
+      // must be some sort of compiled/runtime frame
+      // fp does not have to be safe (although it could be check for c1?)
+
+      sender_sp = _unextended_sp + _cb->frame_size();
+      // Is sender_sp safe?
+      if ((address)sender_sp >= thread->stack_base()) {
+        return false;
+      }
+      // With our calling conventions, the return_address should
+      // end up being the word on the stack
+      sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset);
+    }
+
+    // We must always be able to find a recognizable pc
+    CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
+    if (sender_pc == NULL || sender_blob == NULL) {
+      return false;
+    }
+
+
+    // If the potential sender is the interpreter then we can do some more checking
+    if (Interpreter::contains(sender_pc)) {
+
+      // FP is always saved in a recognizable place in any code we generate. However
+      // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved FP
+      // is really a frame pointer.
+
+      intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset + link_offset);
+      bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
+
+      if (!saved_fp_safe) {
+        return false;
+      }
+
+      // construct the potential sender
+
+      frame sender(sender_sp, saved_fp, sender_pc);
+
+      return sender.is_interpreted_frame_valid(thread);
+    }
+
+    if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
+      return false;
+    }
+
+    // Could just be some random pointer within the codeBlob
+    if (!sender_blob->code_contains(sender_pc)) {
+      return false;
+    }
+
+    // We should never be able to see an adapter if the current frame is something from code cache
+    if (sender_blob->is_adapter_blob()) {
+      return false;
+    }
+
+    // Could be the call_stub
+    if (StubRoutines::returns_to_call_stub(sender_pc)) {
+      intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset + link_offset);
+      bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp >= sender_sp);
+
+      if (!saved_fp_safe) {
+        return false;
+      }
+
+      // construct the potential sender
+
+      frame sender(sender_sp, saved_fp, sender_pc);
+
+      // Validate the JavaCallWrapper an entry frame must have
+      address jcw = (address)sender.entry_frame_call_wrapper();
+
+      bool jcw_safe = (jcw <= thread->stack_base()) && (jcw > (address)sender.fp());
+
+      return jcw_safe;
+    }
+
+    // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
+    // because the return address counts against the callee's frame.
+
+    if (sender_blob->frame_size() <= 0) {
+      assert(!sender_blob->is_compiled(), "should count return address at least");
+      return false;
+    }
+
+    // We should never be able to see anything here except an nmethod. If something in the
+    // code cache (current frame) is called by an entity within the code cache that entity
+    // should not be anything but the call stub (already covered), the interpreter (already covered)
+    // or an nmethod.
+
+    if (!sender_blob->is_compiled()) {
+      return false;
+    }
+
+    // Could put some more validation for the potential non-interpreted sender
+    // frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
+
+    // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
+
+    // We've validated the potential sender that would be created
+    return true;
+  }
+
+  // Must be native-compiled frame. Since sender will try and use fp to find
+  // linkages it must be safe
+
+  if (!fp_safe) {
+    return false;
+  }
+
+  // Will the pc we fetch be non-zero (which we'll find at the oldest frame)
+
+  if ((address) this->fp()[return_addr_offset] == NULL) return false;
+
+
+  // could try and do some more potential verification of native frame if we could think of some...
+
+  return true;
+}
+
+
+void frame::patch_pc(Thread* thread, address pc) {
+  address* pc_addr = &((address *)sp())[-sender_sp_offset+return_addr_offset];
+  if (TracePcPatching) {
+    tty->print_cr("patch_pc at address" INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "] ",
+                  p2i(pc_addr), p2i(*pc_addr), p2i(pc));
+  }
+  *pc_addr = pc;
+  _cb = CodeCache::find_blob(pc);
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
+  if (original_pc != NULL) {
+    assert(original_pc == _pc, "expected original PC to be stored before patching");
+    _deopt_state = is_deoptimized;
+    // leave _pc as is
+  } else {
+    _deopt_state = not_deoptimized;
+    _pc = pc;
+  }
+}
+
+bool frame::is_interpreted_frame() const  {
+  return Interpreter::contains(pc());
+}
+
+int frame::frame_size(RegisterMap* map) const {
+  frame sender = this->sender(map);
+  return sender.sp() - sp();
+}
+
+intptr_t* frame::entry_frame_argument_at(int offset) const {
+  assert(is_entry_frame(), "entry frame expected");
+  // convert offset to index to deal with tsi
+  int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
+  // Entry frame's arguments are always in relation to unextended_sp()
+  return &unextended_sp()[index];
+}
+
+// sender_sp
+intptr_t* frame::interpreter_frame_sender_sp() const {
+  assert(is_interpreted_frame(), "interpreted frame expected");
+  return (intptr_t*) at(interpreter_frame_sender_sp_offset);
+}
+
+void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) {
+  assert(is_interpreted_frame(), "interpreted frame expected");
+  ptr_at_put(interpreter_frame_sender_sp_offset, (intptr_t) sender_sp);
+}
+
+
+// monitor elements
+
+BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
+  return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset);
+}
+
+BasicObjectLock* frame::interpreter_frame_monitor_end() const {
+  BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
+  // make sure the pointer points inside the frame
+  assert((intptr_t) fp() >  (intptr_t) result, "result must <  than frame pointer");
+  assert((intptr_t) sp() <= (intptr_t) result, "result must >= than stack pointer");
+  return result;
+}
+
+void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) {
+  *((BasicObjectLock**)addr_at(interpreter_frame_monitor_block_top_offset)) = value;
+}
+
+#ifdef AARCH64
+
+// Used by template based interpreter deoptimization
+void frame::interpreter_frame_set_stack_top(intptr_t* stack_top) {
+  *((intptr_t**)addr_at(interpreter_frame_stack_top_offset)) = stack_top;
+}
+
+// Used by template based interpreter deoptimization
+void frame::interpreter_frame_set_extended_sp(intptr_t* sp) {
+  *((intptr_t**)addr_at(interpreter_frame_extended_sp_offset)) = sp;
+}
+
+#else
+
+// Used by template based interpreter deoptimization
+void frame::interpreter_frame_set_last_sp(intptr_t* sp) {
+    *((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = sp;
+}
+
+#endif // AARCH64
+
+frame frame::sender_for_entry_frame(RegisterMap* map) const {
+  assert(map != NULL, "map must be set");
+  // Java frame called from C; skip all C frames and return top C
+  // frame of that chunk as the sender
+  JavaFrameAnchor* jfa = entry_frame_call_wrapper()->anchor();
+  assert(!entry_frame_is_first(), "next Java fp must be non zero");
+  assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack");
+  map->clear();
+  assert(map->include_argument_oops(), "should be set by clear");
+#ifdef AARCH64
+  assert (jfa->last_Java_pc() != NULL, "pc should be stored");
+  frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc());
+  return fr;
+#else
+  if (jfa->last_Java_pc() != NULL) {
+    frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc());
+    return fr;
+  }
+  frame fr(jfa->last_Java_sp(), jfa->last_Java_fp());
+  return fr;
+#endif // AARCH64
+}
+
+//------------------------------------------------------------------------------
+// frame::verify_deopt_original_pc
+//
+// Verifies the calculated original PC of a deoptimization PC for the
+// given unextended SP.  The unextended SP might also be the saved SP
+// for MethodHandle call sites.
+#ifdef ASSERT
+void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
+  frame fr;
+
+  // This is ugly but it's better than to change {get,set}_original_pc
+  // to take an SP value as argument.  And it's only a debugging
+  // method anyway.
+  fr._unextended_sp = unextended_sp;
+
+  address original_pc = nm->get_original_pc(&fr);
+  assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
+  assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
+}
+#endif
+
+//------------------------------------------------------------------------------
+// frame::adjust_unextended_sp
+void frame::adjust_unextended_sp() {
+  // same as on x86
+
+  // If we are returning to a compiled MethodHandle call site, the
+  // saved_fp will in fact be a saved value of the unextended SP.  The
+  // simplest way to tell whether we are returning to such a call site
+  // is as follows:
+
+  CompiledMethod* sender_cm = (_cb == NULL) ? NULL : _cb->as_compiled_method_or_null();
+  if (sender_cm != NULL) {
+    // If the sender PC is a deoptimization point, get the original
+    // PC.  For MethodHandle call site the unextended_sp is stored in
+    // saved_fp.
+    if (sender_cm->is_deopt_mh_entry(_pc)) {
+      DEBUG_ONLY(verify_deopt_mh_original_pc(sender_cm, _fp));
+      _unextended_sp = _fp;
+    }
+    else if (sender_cm->is_deopt_entry(_pc)) {
+      DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
+    }
+    else if (sender_cm->is_method_handle_return(_pc)) {
+      _unextended_sp = _fp;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// frame::update_map_with_saved_link
+void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
+  // see x86 for comments
+  map->set_location(FP->as_VMReg(), (address) link_addr);
+#ifdef AARCH64
+  // also adjust a high part of register
+  map->set_location(FP->as_VMReg()->next(), (address) link_addr);
+#endif // AARCH64
+}
+
+frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
+  // SP is the raw SP from the sender after adapter or interpreter
+  // extension.
+  intptr_t* sender_sp = this->sender_sp();
+
+  // This is the sp before any possible extension (adapter/locals).
+  intptr_t* unextended_sp = interpreter_frame_sender_sp();
+
+#ifdef COMPILER2
+  if (map->update_map()) {
+    update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset));
+  }
+#endif // COMPILER2
+
+  return frame(sender_sp, unextended_sp, link(), sender_pc());
+}
+
+frame frame::sender_for_compiled_frame(RegisterMap* map) const {
+  assert(map != NULL, "map must be set");
+
+  // frame owned by optimizing compiler
+  assert(_cb->frame_size() >= 0, "must have non-zero frame size");
+  intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
+  intptr_t* unextended_sp = sender_sp;
+
+  address sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset);
+
+  // This is the saved value of FP which may or may not really be an FP.
+  // It is only an FP if the sender is an interpreter frame (or C1?).
+  intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - sender_sp_offset + link_offset);
+
+  if (map->update_map()) {
+    // Tell GC to use argument oopmaps for some runtime stubs that need it.
+    // For C1, the runtime stub might not have oop maps, so set this flag
+    // outside of update_register_map.
+    map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
+    if (_cb->oop_maps() != NULL) {
+      OopMapSet::update_register_map(this, map);
+    }
+
+    // Since the prolog does the save and restore of FP there is no oopmap
+    // for it so we must fill in its location as if there was an oopmap entry
+    // since if our caller was compiled code there could be live jvm state in it.
+    update_map_with_saved_link(map, saved_fp_addr);
+  }
+
+  assert(sender_sp != sp(), "must have changed");
+  return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
+}
+
+frame frame::sender(RegisterMap* map) const {
+  // Default is we done have to follow them. The sender_for_xxx will
+  // update it accordingly
+  map->set_include_argument_oops(false);
+
+  if (is_entry_frame())       return sender_for_entry_frame(map);
+  if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
+  assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
+
+  if (_cb != NULL) {
+    return sender_for_compiled_frame(map);
+  }
+
+  assert(false, "should not be called for a C frame");
+  return frame();
+}
+
+bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
+  assert(is_interpreted_frame(), "Not an interpreted frame");
+  // These are reasonable sanity checks
+  if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) {
+    return false;
+  }
+  if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
+    return false;
+  }
+  if (fp() + interpreter_frame_initial_sp_offset < sp()) {
+    return false;
+  }
+  // These are hacks to keep us out of trouble.
+  // The problem with these is that they mask other problems
+  if (fp() <= sp()) {        // this attempts to deal with unsigned comparison above
+    return false;
+  }
+  // do some validation of frame elements
+
+  // first the method
+
+  Method* m = *interpreter_frame_method_addr();
+
+  // validate the method we'd find in this potential sender
+  if (!m->is_valid_method()) return false;
+
+  // stack frames shouldn't be much larger than max_stack elements
+
+  if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) {
+    return false;
+  }
+
+  // validate bci/bcp
+
+  address bcp = interpreter_frame_bcp();
+  if (m->validate_bci_from_bcp(bcp) < 0) {
+    return false;
+  }
+
+  // validate ConstantPoolCache*
+  ConstantPoolCache* cp = *interpreter_frame_cache_addr();
+  if (cp == NULL || !cp->is_metaspace_object()) return false;
+
+  // validate locals
+
+  address locals =  (address) *interpreter_frame_locals_addr();
+
+  if (locals > thread->stack_base() || locals < (address) fp()) return false;
+
+  // We'd have to be pretty unlucky to be mislead at this point
+
+  return true;
+}
+
+BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) {
+  assert(is_interpreted_frame(), "interpreted frame expected");
+  Method* method = interpreter_frame_method();
+  BasicType type = method->result_type();
+
+  intptr_t* res_addr;
+  if (method->is_native()) {
+    // Prior to calling into the runtime to report the method_exit both of
+    // the possible return value registers are saved.
+#ifdef AARCH64
+    // Return value registers are saved into the frame
+    if (type == T_FLOAT || type == T_DOUBLE) {
+      res_addr = addr_at(interpreter_frame_fp_saved_result_offset);
+    } else {
+      res_addr = addr_at(interpreter_frame_gp_saved_result_offset);
+    }
+#else
+    // Return value registers are pushed to the native stack
+    res_addr = (intptr_t*)sp();
+#ifdef __ABI_HARD__
+    // FP result is pushed onto a stack along with integer result registers
+    if (type == T_FLOAT || type == T_DOUBLE) {
+      res_addr += 2;
+    }
+#endif // __ABI_HARD__
+#endif // AARCH64
+  } else {
+    res_addr = (intptr_t*)interpreter_frame_tos_address();
+  }
+
+  switch (type) {
+    case T_OBJECT  :
+    case T_ARRAY   : {
+      oop obj;
+      if (method->is_native()) {
+        obj = cast_to_oop(at(interpreter_frame_oop_temp_offset));
+      } else {
+        obj = *(oop*)res_addr;
+      }
+      assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check");
+      *oop_result = obj;
+      break;
+    }
+    case T_BOOLEAN : value_result->z = *(jboolean*)res_addr; break;
+    case T_BYTE    : value_result->b = *(jbyte*)res_addr; break;
+    case T_CHAR    : value_result->c = *(jchar*)res_addr; break;
+    case T_SHORT   : value_result->s = *(jshort*)res_addr; break;
+    case T_INT     : value_result->i = *(jint*)res_addr; break;
+    case T_LONG    : value_result->j = *(jlong*)res_addr; break;
+    case T_FLOAT   : value_result->f = *(jfloat*)res_addr; break;
+    case T_DOUBLE  : value_result->d = *(jdouble*)res_addr; break;
+    case T_VOID    : /* Nothing to do */ break;
+    default        : ShouldNotReachHere();
+  }
+
+  return type;
+}
+
+
+intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
+  int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
+  return &interpreter_frame_tos_address()[index];
+}
+
+#ifndef PRODUCT
+
+#define DESCRIBE_FP_OFFSET(name) \
+  values.describe(frame_no, fp() + frame::name##_offset, #name)
+
+void frame::describe_pd(FrameValues& values, int frame_no) {
+  if (is_interpreted_frame()) {
+    DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp);
+#ifdef AARCH64
+    DESCRIBE_FP_OFFSET(interpreter_frame_stack_top);
+    DESCRIBE_FP_OFFSET(interpreter_frame_extended_sp);
+#else
+    DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
+#endif // AARCH64
+    DESCRIBE_FP_OFFSET(interpreter_frame_method);
+    DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
+    DESCRIBE_FP_OFFSET(interpreter_frame_cache);
+    DESCRIBE_FP_OFFSET(interpreter_frame_locals);
+    DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
+    DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
+  }
+}
+
+// This is a generic constructor which is only used by pns() in debug.cpp.
+frame::frame(void* sp, void* fp, void* pc) {
+  init((intptr_t*)sp, (intptr_t*)fp, (address)pc);
+}
+#endif
+
+intptr_t *frame::initial_deoptimization_info() {
+  // used to reset the saved FP
+  return fp();
+}
+
+intptr_t* frame::real_fp() const {
+#ifndef AARCH64
+  if (is_entry_frame()) {
+    // Work-around: FP (currently) does not conform to the ABI for entry
+    // frames (see generate_call_stub). Might be worth fixing as another CR.
+    // Following code assumes (and asserts) this has not yet been fixed.
+    assert(frame::entry_frame_call_wrapper_offset == 0, "adjust this code");
+    intptr_t* new_fp = fp();
+    new_fp += 5; // saved R0,R1,R2,R4,R10
+#ifndef __SOFTFP__
+    new_fp += 8*2; // saved D8..D15
+#endif
+    return new_fp;
+  }
+#endif // !AARCH64
+  if (_cb != NULL) {
+    // use the frame size if valid
+    int size = _cb->frame_size();
+    if (size > 0) {
+      return unextended_sp() + size;
+    }
+  }
+  // else rely on fp()
+  assert(! is_compiled_frame(), "unknown compiled frame size");
+  return fp();
+}
diff --git a/hotspot/src/cpu/arm/vm/frame_arm.hpp b/hotspot/src/cpu/arm/vm/frame_arm.hpp
new file mode 100644
index 0000000..ee770c0
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/frame_arm.hpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_FRAME_ARM_HPP
+#define CPU_ARM_VM_FRAME_ARM_HPP
+
+#include "runtime/synchronizer.hpp"
+
+ public:
+  enum {
+    pc_return_offset                                 =  0,
+    // All frames
+    link_offset                                      =  0,
+    return_addr_offset                               =  1,
+    // non-interpreter frames
+    sender_sp_offset                                 =  2,
+
+    // Interpreter frames
+#ifdef AARCH64
+    interpreter_frame_gp_saved_result_offset         =  4, // for native calls only
+    interpreter_frame_fp_saved_result_offset         =  3, // for native calls only
+#endif
+    interpreter_frame_oop_temp_offset                =  2, // for native calls only
+
+    interpreter_frame_sender_sp_offset               = -1,
+#ifdef AARCH64
+    interpreter_frame_stack_top_offset               = interpreter_frame_sender_sp_offset - 1,
+    interpreter_frame_extended_sp_offset             = interpreter_frame_stack_top_offset - 1,
+    interpreter_frame_method_offset                  = interpreter_frame_extended_sp_offset - 1,
+#else
+    // outgoing sp before a call to an invoked method
+    interpreter_frame_last_sp_offset                 = interpreter_frame_sender_sp_offset - 1,
+    interpreter_frame_method_offset                  = interpreter_frame_last_sp_offset - 1,
+#endif // AARCH64
+    interpreter_frame_mirror_offset                  = interpreter_frame_method_offset - 1,
+    interpreter_frame_mdp_offset                     = interpreter_frame_mirror_offset - 1,
+    interpreter_frame_cache_offset                   = interpreter_frame_mdp_offset - 1,
+    interpreter_frame_locals_offset                  = interpreter_frame_cache_offset - 1,
+    interpreter_frame_bcp_offset                     = interpreter_frame_locals_offset - 1,
+    interpreter_frame_initial_sp_offset              = interpreter_frame_bcp_offset - 1,
+
+    interpreter_frame_monitor_block_top_offset       = interpreter_frame_initial_sp_offset,
+    interpreter_frame_monitor_block_bottom_offset    = interpreter_frame_initial_sp_offset,
+
+    // Entry frames
+    entry_frame_call_wrapper_offset                  =  AARCH64_ONLY(2) NOT_AARCH64(0)
+  };
+
+  intptr_t ptr_at(int offset) const {
+    return *ptr_at_addr(offset);
+  }
+
+  void ptr_at_put(int offset, intptr_t value) {
+    *ptr_at_addr(offset) = value;
+  }
+
+ private:
+  // an additional field beyond _sp and _pc:
+  intptr_t* _fp; // frame pointer
+  // The interpreter and adapters will extend the frame of the caller.
+  // Since oopMaps are based on the sp of the caller before extension
+  // we need to know that value. However in order to compute the address
+  // of the return address we need the real "raw" sp. Since sparc already
+  // uses sp() to mean "raw" sp and unextended_sp() to mean the caller's
+  // original sp we use that convention.
+
+  intptr_t* _unextended_sp;
+  void adjust_unextended_sp();
+
+  intptr_t* ptr_at_addr(int offset) const {
+    return (intptr_t*) addr_at(offset);
+  }
+
+#ifdef ASSERT
+  // Used in frame::sender_for_{interpreter,compiled}_frame
+  static void verify_deopt_original_pc(   CompiledMethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
+  static void verify_deopt_mh_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) {
+    verify_deopt_original_pc(nm, unextended_sp, true);
+  }
+#endif
+
+ public:
+  // Constructors
+
+  frame(intptr_t* sp, intptr_t* fp, address pc);
+
+  frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
+
+#ifndef AARCH64
+  frame(intptr_t* sp, intptr_t* fp);
+#endif // !AARCH64
+
+  void init(intptr_t* sp, intptr_t* fp, address pc);
+
+  // accessors for the instance variables
+  // Note: not necessarily the real 'frame pointer' (see real_fp)
+  intptr_t* fp() const { return _fp; }
+
+  inline address* sender_pc_addr() const;
+
+#ifdef AARCH64
+  // Used by template based interpreter deoptimization
+  void interpreter_frame_set_stack_top(intptr_t* stack_top);
+  void interpreter_frame_set_extended_sp(intptr_t* sp);
+
+#else
+  // expression stack tos if we are nested in a java call
+  intptr_t* interpreter_frame_last_sp() const;
+
+  // deoptimization support
+  void interpreter_frame_set_last_sp(intptr_t* sp);
+#endif // AARCH64
+
+  // helper to update a map with callee-saved FP
+  static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr);
+
+#endif // CPU_ARM_VM_FRAME_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp
new file mode 100644
index 0000000..589d75b
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_FRAME_ARM_INLINE_HPP
+#define CPU_ARM_VM_FRAME_ARM_INLINE_HPP
+
+#include "code/codeCache.hpp"
+#include "code/vmreg.inline.hpp"
+
+// Inline functions for ARM frames:
+
+// Constructors:
+
+inline frame::frame() {
+  _pc = NULL;
+  _sp = NULL;
+  _unextended_sp = NULL;
+  _fp = NULL;
+  _cb = NULL;
+  _deopt_state = unknown;
+}
+
+inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
+  _sp = sp;
+  _unextended_sp = sp;
+  _fp = fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = CodeCache::find_blob(pc);
+  adjust_unextended_sp();
+
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
+  if (original_pc != NULL) {
+    _pc = original_pc;
+    _deopt_state = is_deoptimized;
+  } else {
+    _deopt_state = not_deoptimized;
+  }
+}
+
+inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
+  init(sp, fp, pc);
+}
+
+inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
+  _sp = sp;
+  _unextended_sp = unextended_sp;
+  _fp = fp;
+  _pc = pc;
+  assert(pc != NULL, "no pc?");
+  _cb = CodeCache::find_blob(pc);
+  adjust_unextended_sp();
+
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
+  if (original_pc != NULL) {
+    _pc = original_pc;
+    assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod");
+    _deopt_state = is_deoptimized;
+  } else {
+    _deopt_state = not_deoptimized;
+  }
+}
+
+#ifndef AARCH64
+
+inline frame::frame(intptr_t* sp, intptr_t* fp) {
+  _sp = sp;
+  _unextended_sp = sp;
+  _fp = fp;
+  assert(sp != NULL,"null SP ?");
+  _pc = (address)(sp[-1]);
+  // assert(_pc != NULL, "no pc?"); // see comments in x86
+  _cb = CodeCache::find_blob(_pc);
+  adjust_unextended_sp();
+
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
+  if (original_pc != NULL) {
+    _pc = original_pc;
+    _deopt_state = is_deoptimized;
+  } else {
+    _deopt_state = not_deoptimized;
+  }
+}
+
+#endif // !AARCH64
+
+// Accessors
+
+inline bool frame::equal(frame other) const {
+  bool ret =  sp() == other.sp()
+              && unextended_sp() == other.unextended_sp()
+              && fp() == other.fp()
+              && pc() == other.pc();
+  assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
+  return ret;
+}
+
+// Return unique id for this frame. The id must have a value where we can distinguish
+// identity and younger/older relationship. NULL represents an invalid (incomparable)
+// frame.
+inline intptr_t* frame::id(void) const { return unextended_sp(); }
+
+// Relationals on frames based
+// Return true if the frame is younger (more recent activation) than the frame represented by id
+inline bool frame::is_younger(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id");
+                                                    return this->id() < id ; }
+
+// Return true if the frame is older (less recent activation) than the frame represented by id
+inline bool frame::is_older(intptr_t* id) const   { assert(this->id() != NULL && id != NULL, "NULL frame id");
+                                                    return this->id() > id ; }
+
+
+
+inline intptr_t* frame::link() const              { return (intptr_t*) *(intptr_t **)addr_at(link_offset); }
+
+inline intptr_t* frame::unextended_sp() const     { return _unextended_sp; }
+
+// Return address:
+
+inline address* frame::sender_pc_addr()      const { return (address*) addr_at(return_addr_offset); }
+inline address  frame::sender_pc()           const { return *sender_pc_addr(); }
+
+inline intptr_t* frame::sender_sp() const { return addr_at(sender_sp_offset); }
+
+inline intptr_t** frame::interpreter_frame_locals_addr() const {
+  return (intptr_t**)addr_at(interpreter_frame_locals_offset);
+}
+
+#ifndef AARCH64
+inline intptr_t* frame::interpreter_frame_last_sp() const {
+  return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
+}
+#endif // !AARCH64
+
+inline intptr_t* frame::interpreter_frame_bcp_addr() const {
+  return (intptr_t*)addr_at(interpreter_frame_bcp_offset);
+}
+
+inline intptr_t* frame::interpreter_frame_mdp_addr() const {
+  return (intptr_t*)addr_at(interpreter_frame_mdp_offset);
+}
+
+
+// Constant pool cache
+
+inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
+  return (ConstantPoolCache**)addr_at(interpreter_frame_cache_offset);
+}
+
+// Method
+
+inline Method** frame::interpreter_frame_method_addr() const {
+  return (Method**)addr_at(interpreter_frame_method_offset);
+}
+
+inline oop* frame::interpreter_frame_mirror_addr() const {
+  return (oop*)addr_at(interpreter_frame_mirror_offset);
+}
+
+// top of expression stack
+inline intptr_t* frame::interpreter_frame_tos_address() const {
+#ifdef AARCH64
+  intptr_t* stack_top = (intptr_t*)*addr_at(interpreter_frame_stack_top_offset);
+  assert(stack_top != NULL, "should be stored before call");
+  assert(stack_top <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos");
+  return stack_top;
+#else
+  intptr_t* last_sp = interpreter_frame_last_sp();
+  if (last_sp == NULL ) {
+    return sp();
+  } else {
+    // sp() may have been extended or shrunk by an adapter.  At least
+    // check that we don't fall behind the legal region.
+    // For top deoptimized frame last_sp == interpreter_frame_monitor_end.
+    assert(last_sp <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos");
+    return last_sp;
+  }
+#endif // AARCH64
+}
+
+inline oop* frame::interpreter_frame_temp_oop_addr() const {
+  return (oop *)(fp() + interpreter_frame_oop_temp_offset);
+}
+
+inline int frame::interpreter_frame_monitor_size() {
+  return BasicObjectLock::size();
+}
+
+
+// expression stack
+// (the max_stack arguments are used by the GC; see class FrameClosure)
+
+inline intptr_t* frame::interpreter_frame_expression_stack() const {
+  intptr_t* monitor_end = (intptr_t*) interpreter_frame_monitor_end();
+  return monitor_end-1;
+}
+
+
+inline jint frame::interpreter_frame_expression_stack_direction() { return -1; }
+
+
+// Entry frames
+
+inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
+ return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset);
+}
+
+
+// Compiled frames
+
+inline bool frame::volatile_across_calls(Register reg) {
+  return true;
+}
+
+inline oop frame::saved_oop_result(RegisterMap* map) const {
+  oop* result_adr = (oop*) map->location(R0->as_VMReg());
+  guarantee(result_adr != NULL, "bad register save location");
+  return (*result_adr);
+}
+
+inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
+  oop* result_adr = (oop*) map->location(R0->as_VMReg());
+  guarantee(result_adr != NULL, "bad register save location");
+  *result_adr = obj;
+}
+
+#endif // CPU_ARM_VM_FRAME_ARM_INLINE_HPP
diff --git a/hotspot/src/cpu/arm/vm/globalDefinitions_arm.hpp b/hotspot/src/cpu/arm/vm/globalDefinitions_arm.hpp
new file mode 100644
index 0000000..0ede3bf
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/globalDefinitions_arm.hpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_GLOBALDEFINITIONS_ARM_HPP
+#define CPU_ARM_VM_GLOBALDEFINITIONS_ARM_HPP
+
+#ifdef AARCH64
+#define AARCH64_ONLY(code) code
+#define AARCH64_ONLY_ARG(arg) , arg
+#define NOT_AARCH64(code)
+#define NOT_AARCH64_ARG(arg)
+#else
+#define AARCH64_ONLY(code)
+#define AARCH64_ONLY_ARG(arg)
+#define NOT_AARCH64(code) code
+#define NOT_AARCH64_ARG(arg) , arg
+#endif
+
+const int StackAlignmentInBytes = AARCH64_ONLY(16) NOT_AARCH64(8);
+
+// Indicates whether the C calling conventions require that
+// 32-bit integer argument values are extended to 64 bits.
+const bool CCallingConventionRequiresIntsAsLongs = false;
+
+#ifdef __SOFTFP__
+const bool HaveVFP = false;
+#else
+const bool HaveVFP = true;
+#endif
+
+#if defined(__ARM_PCS_VFP) || defined(AARCH64)
+#define __ABI_HARD__
+#endif
+
+#if defined(__ARM_ARCH_7A__) || defined(AARCH64)
+#define SUPPORTS_NATIVE_CX8
+#endif
+
+#define STUBROUTINES_MD_HPP    "stubRoutines_arm.hpp"
+#define INTERP_MASM_MD_HPP     "interp_masm_arm.hpp"
+#define TEMPLATETABLE_MD_HPP   "templateTable_arm.hpp"
+#ifdef AARCH64
+#define ADGLOBALS_MD_HPP       "adfiles/adGlobals_arm_64.hpp"
+#define AD_MD_HPP              "adfiles/ad_arm_64.hpp"
+#else
+#define ADGLOBALS_MD_HPP       "adfiles/adGlobals_arm_32.hpp"
+#define AD_MD_HPP              "adfiles/ad_arm_32.hpp"
+#endif
+#define C1_LIRGENERATOR_MD_HPP "c1_LIRGenerator_arm.hpp"
+
+#ifdef TARGET_COMPILER_gcc
+#ifdef ARM32
+#undef BREAKPOINT
+#define BREAKPOINT __asm__ volatile ("bkpt")
+#endif
+#endif
+
+#endif // CPU_ARM_VM_GLOBALDEFINITIONS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/globals_arm.hpp b/hotspot/src/cpu/arm/vm/globals_arm.hpp
new file mode 100644
index 0000000..04c0b34
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/globals_arm.hpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_GLOBALS_ARM_HPP
+#define CPU_ARM_VM_GLOBALS_ARM_HPP
+
+//
+// Sets the default values for platform dependent flags used by the runtime system.
+// (see globals.hpp)
+//
+
+define_pd_global(bool,  ShareVtableStubs,         true);
+
+define_pd_global(bool,  ImplicitNullChecks,       true);  // Generate code for implicit null checks
+define_pd_global(bool,  UncommonNullCast,         true);  // Uncommon-trap NULLs past to check cast
+define_pd_global(bool,  TrapBasedNullChecks,      false); // Not needed
+
+define_pd_global(uintx, CodeCacheSegmentSize, 64 TIERED_ONLY(+64)); // Tiered compilation has large code-entry alignment.
+define_pd_global(intx,  CodeEntryAlignment,       16);
+define_pd_global(intx,  OptoLoopAlignment,        16);
+
+define_pd_global(bool,  NeedsDeoptSuspend,        false); // only register window machines need this
+
+#define DEFAULT_STACK_YELLOW_PAGES (2)
+#define DEFAULT_STACK_RED_PAGES (1)
+#define DEFAULT_STACK_SHADOW_PAGES (5 DEBUG_ONLY(+1))
+#define DEFAULT_STACK_RESERVED_PAGES (0)
+
+#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
+#define MIN_STACK_RED_PAGES    DEFAULT_STACK_RED_PAGES
+#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
+#define MIN_STACK_RESERVED_PAGES (0)
+
+define_pd_global(intx,  StackYellowPages,         DEFAULT_STACK_YELLOW_PAGES);
+define_pd_global(intx,  StackRedPages,            DEFAULT_STACK_RED_PAGES);
+define_pd_global(intx,  StackShadowPages,         DEFAULT_STACK_SHADOW_PAGES);
+define_pd_global(intx,  StackReservedPages,       DEFAULT_STACK_RESERVED_PAGES);
+
+define_pd_global(intx,  InlineFrequencyCount,     50);
+#if  defined(COMPILER1) || defined(COMPILER2)
+define_pd_global(intx,  InlineSmallCode,          1500);
+#endif
+
+define_pd_global(bool,  RewriteBytecodes,         true);
+define_pd_global(bool,  RewriteFrequentPairs,     true);
+
+define_pd_global(bool,  UseMembar,                true);
+
+define_pd_global(bool,  PreserveFramePointer,     false);
+
+// GC Ergo Flags
+define_pd_global(size_t, CMSYoungGenPerWorker,    16*M);  // default max size of CMS young gen, per GC worker thread
+
+define_pd_global(uintx, TypeProfileLevel, 0);
+
+// No performance work done here yet.
+define_pd_global(bool, CompactStrings, false);
+
+define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
+
+#define ARCH_FLAGS(develop, \
+                   product, \
+                   diagnostic, \
+                   experimental, \
+                   notproduct, \
+                   range, \
+                   constraint, \
+                   writeable) \
+                                                                                        \
+  develop(bool, VerifyInterpreterStackTop, false,                                       \
+          "Verify interpreter stack top at every stack expansion (AArch64 only)")       \
+                                                                                        \
+  develop(bool, ZapHighNonSignificantBits, false,                                       \
+          "Zap high non-significant bits of values (AArch64 only)")                     \
+                                                                                        \
+
+#endif // CPU_ARM_VM_GLOBALS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/icBuffer_arm.cpp b/hotspot/src/cpu/arm/vm/icBuffer_arm.cpp
new file mode 100644
index 0000000..b158572
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/icBuffer_arm.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/icBuffer.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/bytecodes.hpp"
+#include "memory/resourceArea.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/oop.inline.hpp"
+
+#define __ masm->
+
+int InlineCacheBuffer::ic_stub_code_size() {
+  return (AARCH64_ONLY(8) NOT_AARCH64(4)) * Assembler::InstructionSize;
+}
+
+void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) {
+  ResourceMark rm;
+  CodeBuffer code(code_begin, ic_stub_code_size());
+  MacroAssembler* masm = new MacroAssembler(&code);
+
+  InlinedAddress oop_literal((address) cached_value);
+  __ ldr_literal(Ricklass, oop_literal);
+  // FIXME: OK to remove reloc here?
+  __ patchable_jump(entry_point, relocInfo::runtime_call_type, Rtemp);
+  __ bind_literal(oop_literal);
+  __ flush();
+}
+
+address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) {
+  address jump_address;
+  jump_address = code_begin + NativeInstruction::instruction_size;
+  NativeJump* jump = nativeJump_at(jump_address);
+  return jump->jump_destination();
+}
+
+void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) {
+  NativeMovConstReg* move = nativeMovConstReg_at(code_begin);
+  return (void*)move->data();
+}
+
+#undef __
diff --git a/hotspot/src/cpu/arm/vm/icache_arm.cpp b/hotspot/src/cpu/arm/vm/icache_arm.cpp
new file mode 100644
index 0000000..ae16361
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/icache_arm.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "runtime/icache.hpp"
+
+#define __ _masm->
+
+#ifdef AARCH64
+
+static int icache_flush(address addr, int lines, int magic) {
+  // TODO-AARCH64 Figure out actual cache line size (mrs Xt, CTR_EL0)
+
+  address p = addr;
+  for (int i = 0; i < lines; i++, p += ICache::line_size) {
+    __asm__ volatile(
+      " dc cvau, %[p]"
+      :
+      : [p] "r" (p)
+      : "memory");
+  }
+
+  __asm__ volatile(
+    " dsb ish"
+    : : : "memory");
+
+  p = addr;
+  for (int i = 0; i < lines; i++, p += ICache::line_size) {
+    __asm__ volatile(
+      " ic ivau, %[p]"
+      :
+      : [p] "r" (p)
+      : "memory");
+  }
+
+  __asm__ volatile(
+    " dsb ish\n\t"
+    " isb\n\t"
+    : : : "memory");
+
+  return magic;
+}
+
+#else
+
+static int icache_flush(address addr, int lines, int magic) {
+  __builtin___clear_cache(addr, addr + (lines << ICache::log2_line_size));
+  return magic;
+}
+
+#endif // AARCH64
+
+void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) {
+  address start = (address)icache_flush;
+
+  *flush_icache_stub = (ICache::flush_icache_stub_t)start;
+
+  // ICache::invalidate_range() contains explicit condition that the first
+  // call is invoked on the generated icache flush stub code range.
+  ICache::invalidate_range(start, 0);
+
+  {
+    // dummy code mark to make the shared code happy
+    // (fields that would need to be modified to emulate the correct
+    // mark are not accessible)
+    StubCodeMark mark(this, "ICache", "fake_stub_for_inlined_icache_flush");
+    __ ret();
+  }
+}
+
+#undef __
diff --git a/hotspot/src/cpu/arm/vm/icache_arm.hpp b/hotspot/src/cpu/arm/vm/icache_arm.hpp
new file mode 100644
index 0000000..6b8c585
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/icache_arm.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ICACHE_ARM_HPP
+#define CPU_ARM_VM_ICACHE_ARM_HPP
+
+// Interface for updating the instruction cache.  Whenever the VM modifies
+// code, part of the processor instruction cache potentially has to be flushed.
+
+class ICache : public AbstractICache {
+ public:
+  enum {
+    stub_size      = 32,                // Size of the icache flush stub in bytes
+    line_size      = BytesPerWord,      // conservative
+    log2_line_size = LogBytesPerWord    // log2(line_size)
+  };
+};
+
+#endif // CPU_ARM_VM_ICACHE_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp
new file mode 100644
index 0000000..2f41b10
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp
@@ -0,0 +1,2272 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/shared/barrierSet.inline.hpp"
+#include "gc/shared/cardTableModRefBS.inline.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "interp_masm_arm.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "logging/log.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/markOop.hpp"
+#include "oops/method.hpp"
+#include "oops/methodData.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/basicLock.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/sharedRuntime.hpp"
+
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/heapRegion.hpp"
+#endif // INCLUDE_ALL_GCS
+
+//--------------------------------------------------------------------
+// Implementation of InterpreterMacroAssembler
+
+
+
+
+InterpreterMacroAssembler::InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {
+}
+
+void InterpreterMacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
+#if defined(ASSERT) && !defined(AARCH64)
+  // Ensure that last_sp is not filled.
+  { Label L;
+    ldr(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+    cbz(Rtemp, L);
+    stop("InterpreterMacroAssembler::call_VM_helper: last_sp != NULL");
+    bind(L);
+  }
+#endif // ASSERT && !AARCH64
+
+  // Rbcp must be saved/restored since it may change due to GC.
+  save_bcp();
+
+#ifdef AARCH64
+  check_no_cached_stack_top(Rtemp);
+  save_stack_top();
+  check_extended_sp(Rtemp);
+  cut_sp_before_call();
+#endif // AARCH64
+
+  // super call
+  MacroAssembler::call_VM_helper(oop_result, entry_point, number_of_arguments, check_exceptions);
+
+#ifdef AARCH64
+  // Restore SP to extended SP
+  restore_sp_after_call(Rtemp);
+  check_stack_top();
+  clear_cached_stack_top();
+#endif // AARCH64
+
+  // Restore interpreter specific registers.
+  restore_bcp();
+  restore_method();
+}
+
+void InterpreterMacroAssembler::jump_to_entry(address entry) {
+  assert(entry, "Entry must have been generated by now");
+  b(entry);
+}
+
+void InterpreterMacroAssembler::check_and_handle_popframe() {
+  if (can_pop_frame()) {
+    Label L;
+    const Register popframe_cond = R2_tmp;
+
+    // Initiate popframe handling only if it is not already being processed.  If the flag
+    // has the popframe_processing bit set, it means that this code is called *during* popframe
+    // handling - we don't want to reenter.
+
+    ldr_s32(popframe_cond, Address(Rthread, JavaThread::popframe_condition_offset()));
+    tbz(popframe_cond, exact_log2(JavaThread::popframe_pending_bit), L);
+    tbnz(popframe_cond, exact_log2(JavaThread::popframe_processing_bit), L);
+
+    // Call Interpreter::remove_activation_preserving_args_entry() to get the
+    // address of the same-named entrypoint in the generated interpreter code.
+    call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry));
+
+    // Call indirectly to avoid generation ordering problem.
+    jump(R0);
+
+    bind(L);
+  }
+}
+
+
+// Blows R2, Rtemp. Sets TOS cached value.
+void InterpreterMacroAssembler::load_earlyret_value(TosState state) {
+  const Register thread_state = R2_tmp;
+
+  ldr(thread_state, Address(Rthread, JavaThread::jvmti_thread_state_offset()));
+
+  const Address tos_addr(thread_state, JvmtiThreadState::earlyret_tos_offset());
+  const Address oop_addr(thread_state, JvmtiThreadState::earlyret_oop_offset());
+  const Address val_addr(thread_state, JvmtiThreadState::earlyret_value_offset());
+#ifndef AARCH64
+  const Address val_addr_hi(thread_state, JvmtiThreadState::earlyret_value_offset()
+                             + in_ByteSize(wordSize));
+#endif // !AARCH64
+
+  Register zero = zero_register(Rtemp);
+
+  switch (state) {
+    case atos: ldr(R0_tos, oop_addr);
+               str(zero, oop_addr);
+               interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+               break;
+
+#ifdef AARCH64
+    case ltos: ldr(R0_tos, val_addr);              break;
+#else
+    case ltos: ldr(R1_tos_hi, val_addr_hi);        // fall through
+#endif // AARCH64
+    case btos:                                     // fall through
+    case ztos:                                     // fall through
+    case ctos:                                     // fall through
+    case stos:                                     // fall through
+    case itos: ldr_s32(R0_tos, val_addr);          break;
+#ifdef __SOFTFP__
+    case dtos: ldr(R1_tos_hi, val_addr_hi);        // fall through
+    case ftos: ldr(R0_tos, val_addr);              break;
+#else
+    case ftos: ldr_float (S0_tos, val_addr);       break;
+    case dtos: ldr_double(D0_tos, val_addr);       break;
+#endif // __SOFTFP__
+    case vtos: /* nothing to do */                 break;
+    default  : ShouldNotReachHere();
+  }
+  // Clean up tos value in the thread object
+  str(zero, val_addr);
+#ifndef AARCH64
+  str(zero, val_addr_hi);
+#endif // !AARCH64
+
+  mov(Rtemp, (int) ilgl);
+  str_32(Rtemp, tos_addr);
+}
+
+
+// Blows R2, Rtemp.
+void InterpreterMacroAssembler::check_and_handle_earlyret() {
+  if (can_force_early_return()) {
+    Label L;
+    const Register thread_state = R2_tmp;
+
+    ldr(thread_state, Address(Rthread, JavaThread::jvmti_thread_state_offset()));
+    cbz(thread_state, L); // if (thread->jvmti_thread_state() == NULL) exit;
+
+    // Initiate earlyret handling only if it is not already being processed.
+    // If the flag has the earlyret_processing bit set, it means that this code
+    // is called *during* earlyret handling - we don't want to reenter.
+
+    ldr_s32(Rtemp, Address(thread_state, JvmtiThreadState::earlyret_state_offset()));
+    cmp(Rtemp, JvmtiThreadState::earlyret_pending);
+    b(L, ne);
+
+    // Call Interpreter::remove_activation_early_entry() to get the address of the
+    // same-named entrypoint in the generated interpreter code.
+
+    ldr_s32(R0, Address(thread_state, JvmtiThreadState::earlyret_tos_offset()));
+    call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), R0);
+
+    jump(R0);
+
+    bind(L);
+  }
+}
+
+
+// Sets reg. Blows Rtemp.
+void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset) {
+  assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode");
+  assert(reg != Rtemp, "should be different registers");
+
+  ldrb(Rtemp, Address(Rbcp, bcp_offset));
+  ldrb(reg, Address(Rbcp, bcp_offset+1));
+  orr(reg, reg, AsmOperand(Rtemp, lsl, BitsPerByte));
+}
+
+void InterpreterMacroAssembler::get_index_at_bcp(Register index, int bcp_offset, Register tmp_reg, size_t index_size) {
+  assert_different_registers(index, tmp_reg);
+  if (index_size == sizeof(u2)) {
+    // load bytes of index separately to avoid unaligned access
+    ldrb(index, Address(Rbcp, bcp_offset+1));
+    ldrb(tmp_reg, Address(Rbcp, bcp_offset));
+    orr(index, tmp_reg, AsmOperand(index, lsl, BitsPerByte));
+  } else if (index_size == sizeof(u4)) {
+    // TODO-AARCH64: consider using unaligned access here
+    ldrb(index, Address(Rbcp, bcp_offset+3));
+    ldrb(tmp_reg, Address(Rbcp, bcp_offset+2));
+    orr(index, tmp_reg, AsmOperand(index, lsl, BitsPerByte));
+    ldrb(tmp_reg, Address(Rbcp, bcp_offset+1));
+    orr(index, tmp_reg, AsmOperand(index, lsl, BitsPerByte));
+    ldrb(tmp_reg, Address(Rbcp, bcp_offset));
+    orr(index, tmp_reg, AsmOperand(index, lsl, BitsPerByte));
+    // Check if the secondary index definition is still ~x, otherwise
+    // we have to change the following assembler code to calculate the
+    // plain index.
+    assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line");
+    mvn_32(index, index);  // convert to plain index
+  } else if (index_size == sizeof(u1)) {
+    ldrb(index, Address(Rbcp, bcp_offset));
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
+// Sets cache, index.
+void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size) {
+  assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+  assert_different_registers(cache, index);
+
+  get_index_at_bcp(index, bcp_offset, cache, index_size);
+
+  // load constant pool cache pointer
+  ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize));
+
+  // convert from field index to ConstantPoolCacheEntry index
+  assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
+  // TODO-AARCH64 merge this shift with shift "add(..., Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord))" after this method is called
+  logical_shift_left(index, index, 2);
+}
+
+// Sets cache, index, bytecode.
+void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size) {
+  get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size);
+  // caution index and bytecode can be the same
+  add(bytecode, cache, AsmOperand(index, lsl, LogBytesPerWord));
+#ifdef AARCH64
+  add(bytecode, bytecode, (1 + byte_no) + in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()));
+  ldarb(bytecode, bytecode);
+#else
+  ldrb(bytecode, Address(bytecode, (1 + byte_no) + in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())));
+  TemplateTable::volatile_barrier(MacroAssembler::LoadLoad, noreg, true);
+#endif // AARCH64
+}
+
+// Sets cache. Blows reg_tmp.
+void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register reg_tmp, int bcp_offset, size_t index_size) {
+  assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+  assert_different_registers(cache, reg_tmp);
+
+  get_index_at_bcp(reg_tmp, bcp_offset, cache, index_size);
+
+  // load constant pool cache pointer
+  ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize));
+
+  // skip past the header
+  add(cache, cache, in_bytes(ConstantPoolCache::base_offset()));
+  // convert from field index to ConstantPoolCacheEntry index
+  // and from word offset to byte offset
+  assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
+  add(cache, cache, AsmOperand(reg_tmp, lsl, 2 + LogBytesPerWord));
+}
+
+// Load object from cpool->resolved_references(index)
+void InterpreterMacroAssembler::load_resolved_reference_at_index(
+                                           Register result, Register index) {
+  assert_different_registers(result, index);
+  get_constant_pool(result);
+
+  Register cache = result;
+  // load pointer for resolved_references[] objArray
+  ldr(cache, Address(result, ConstantPool::resolved_references_offset_in_bytes()));
+  // JNIHandles::resolve(result)
+  ldr(cache, Address(cache, 0));
+  // Add in the index
+  // convert from field index to resolved_references() index and from
+  // word index to byte offset. Since this is a java object, it can be compressed
+  add(cache, cache, AsmOperand(index, lsl, LogBytesPerHeapOop));
+  load_heap_oop(result, Address(cache, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
+}
+
+// Generate a subtype check: branch to not_subtype if sub_klass is
+// not a subtype of super_klass.
+// Profiling code for the subtype check failure (profile_typecheck_failed)
+// should be explicitly generated by the caller in the not_subtype case.
+// Blows Rtemp, tmp1, tmp2.
+void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
+                                                  Register Rsuper_klass,
+                                                  Label &not_subtype,
+                                                  Register tmp1,
+                                                  Register tmp2) {
+
+  assert_different_registers(Rsub_klass, Rsuper_klass, tmp1, tmp2, Rtemp);
+  Label ok_is_subtype, loop, update_cache;
+
+  const Register super_check_offset = tmp1;
+  const Register cached_super = tmp2;
+
+  // Profile the not-null value's klass.
+  profile_typecheck(tmp1, Rsub_klass);
+
+  // Load the super-klass's check offset into
+  ldr_u32(super_check_offset, Address(Rsuper_klass, Klass::super_check_offset_offset()));
+
+  // Check for self
+  cmp(Rsub_klass, Rsuper_klass);
+
+  // Load from the sub-klass's super-class display list, or a 1-word cache of
+  // the secondary superclass list, or a failing value with a sentinel offset
+  // if the super-klass is an interface or exceptionally deep in the Java
+  // hierarchy and we have to scan the secondary superclass list the hard way.
+  // See if we get an immediate positive hit
+  ldr(cached_super, Address(Rsub_klass, super_check_offset));
+
+  cond_cmp(Rsuper_klass, cached_super, ne);
+  b(ok_is_subtype, eq);
+
+  // Check for immediate negative hit
+  cmp(super_check_offset, in_bytes(Klass::secondary_super_cache_offset()));
+  b(not_subtype, ne);
+
+  // Now do a linear scan of the secondary super-klass chain.
+  const Register supers_arr = tmp1;
+  const Register supers_cnt = tmp2;
+  const Register cur_super  = Rtemp;
+
+  // Load objArrayOop of secondary supers.
+  ldr(supers_arr, Address(Rsub_klass, Klass::secondary_supers_offset()));
+
+  ldr_u32(supers_cnt, Address(supers_arr, Array<Klass*>::length_offset_in_bytes())); // Load the array length
+#ifdef AARCH64
+  cbz(supers_cnt, not_subtype);
+  add(supers_arr, supers_arr, Array<Klass*>::base_offset_in_bytes());
+#else
+  cmp(supers_cnt, 0);
+
+  // Skip to the start of array elements and prefetch the first super-klass.
+  ldr(cur_super, Address(supers_arr, Array<Klass*>::base_offset_in_bytes(), pre_indexed), ne);
+  b(not_subtype, eq);
+#endif // AARCH64
+
+  bind(loop);
+
+#ifdef AARCH64
+  ldr(cur_super, Address(supers_arr, wordSize, post_indexed));
+#endif // AARCH64
+
+  cmp(cur_super, Rsuper_klass);
+  b(update_cache, eq);
+
+  subs(supers_cnt, supers_cnt, 1);
+
+#ifndef AARCH64
+  ldr(cur_super, Address(supers_arr, wordSize, pre_indexed), ne);
+#endif // !AARCH64
+
+  b(loop, ne);
+
+  b(not_subtype);
+
+  bind(update_cache);
+  // Must be equal but missed in cache.  Update cache.
+  str(Rsuper_klass, Address(Rsub_klass, Klass::secondary_super_cache_offset()));
+
+  bind(ok_is_subtype);
+}
+
+
+// The 1st part of the store check.
+// Sets card_table_base register.
+void InterpreterMacroAssembler::store_check_part1(Register card_table_base) {
+  // Check barrier set type (should be card table) and element size
+  BarrierSet* bs = Universe::heap()->barrier_set();
+  assert(bs->kind() == BarrierSet::CardTableForRS ||
+         bs->kind() == BarrierSet::CardTableExtension,
+         "Wrong barrier set kind");
+
+  CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
+  assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "Adjust store check code");
+
+  // Load card table base address.
+
+  /* Performance note.
+
+     There is an alternative way of loading card table base address
+     from thread descriptor, which may look more efficient:
+
+     ldr(card_table_base, Address(Rthread, JavaThread::card_table_base_offset()));
+
+     However, performance measurements of micro benchmarks and specJVM98
+     showed that loading of card table base from thread descriptor is
+     7-18% slower compared to loading of literal embedded into the code.
+     Possible cause is a cache miss (card table base address resides in a
+     rarely accessed area of thread descriptor).
+  */
+  // TODO-AARCH64 Investigate if mov_slow is faster than ldr from Rthread on AArch64
+  mov_address(card_table_base, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference);
+}
+
+// The 2nd part of the store check.
+void InterpreterMacroAssembler::store_check_part2(Register obj, Register card_table_base, Register tmp) {
+  assert_different_registers(obj, card_table_base, tmp);
+
+  assert(CardTableModRefBS::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations.");
+#ifdef AARCH64
+  add(card_table_base, card_table_base, AsmOperand(obj, lsr, CardTableModRefBS::card_shift));
+  Address card_table_addr(card_table_base);
+#else
+  Address card_table_addr(card_table_base, obj, lsr, CardTableModRefBS::card_shift);
+#endif
+
+  if (UseCondCardMark) {
+    if (UseConcMarkSweepGC) {
+      membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
+    }
+    Label already_dirty;
+
+    ldrb(tmp, card_table_addr);
+    cbz(tmp, already_dirty);
+
+    set_card(card_table_base, card_table_addr, tmp);
+    bind(already_dirty);
+
+  } else {
+    if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+      membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
+    }
+    set_card(card_table_base, card_table_addr, tmp);
+  }
+}
+
+void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_table_addr, Register tmp) {
+#ifdef AARCH64
+  strb(ZR, card_table_addr);
+#else
+  CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(Universe::heap()->barrier_set());
+  if ((((uintptr_t)ct->byte_map_base & 0xff) == 0)) {
+    // Card table is aligned so the lowest byte of the table address base is zero.
+    // This works only if the code is not saved for later use, possibly
+    // in a context where the base would no longer be aligned.
+    strb(card_table_base, card_table_addr);
+  } else {
+    mov(tmp, 0);
+    strb(tmp, card_table_addr);
+  }
+#endif // AARCH64
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+#if INCLUDE_ALL_GCS
+
+// G1 pre-barrier.
+// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+// If store_addr != noreg, then previous value is loaded from [store_addr];
+// in such case store_addr and new_val registers are preserved;
+// otherwise pre_val register is preserved.
+void InterpreterMacroAssembler::g1_write_barrier_pre(Register store_addr,
+                                                     Register new_val,
+                                                     Register pre_val,
+                                                     Register tmp1,
+                                                     Register tmp2) {
+  Label done;
+  Label runtime;
+
+  if (store_addr != noreg) {
+    assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
+  } else {
+    assert (new_val == noreg, "should be");
+    assert_different_registers(pre_val, tmp1, tmp2, noreg);
+  }
+
+  Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                        SATBMarkQueue::byte_offset_of_active()));
+  Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                  SATBMarkQueue::byte_offset_of_index()));
+  Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                   SATBMarkQueue::byte_offset_of_buf()));
+
+  // Is marking active?
+  assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
+  ldrb(tmp1, in_progress);
+  cbz(tmp1, done);
+
+  // Do we need to load the previous value?
+  if (store_addr != noreg) {
+    load_heap_oop(pre_val, Address(store_addr, 0));
+  }
+
+  // Is the previous value null?
+  cbz(pre_val, done);
+
+  // Can we store original value in the thread's buffer?
+  // Is index == 0?
+  // (The index field is typed as size_t.)
+
+  ldr(tmp1, index);           // tmp1 := *index_adr
+  ldr(tmp2, buffer);
+
+  subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
+  b(runtime, lt);             // If negative, goto runtime
+
+  str(tmp1, index);           // *index_adr := tmp1
+
+  // Record the previous value
+  str(pre_val, Address(tmp2, tmp1));
+  b(done);
+
+  bind(runtime);
+
+  // save the live input values
+#ifdef AARCH64
+  if (store_addr != noreg) {
+    raw_push(store_addr, new_val);
+  } else {
+    raw_push(pre_val, ZR);
+  }
+#else
+  if (store_addr != noreg) {
+    // avoid raw_push to support any ordering of store_addr and new_val
+    push(RegisterSet(store_addr) | RegisterSet(new_val));
+  } else {
+    push(pre_val);
+  }
+#endif // AARCH64
+
+  if (pre_val != R0) {
+    mov(R0, pre_val);
+  }
+  mov(R1, Rthread);
+
+  call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
+
+#ifdef AARCH64
+  if (store_addr != noreg) {
+    raw_pop(store_addr, new_val);
+  } else {
+    raw_pop(pre_val, ZR);
+  }
+#else
+  if (store_addr != noreg) {
+    pop(RegisterSet(store_addr) | RegisterSet(new_val));
+  } else {
+    pop(pre_val);
+  }
+#endif // AARCH64
+
+  bind(done);
+}
+
+// G1 post-barrier.
+// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+void InterpreterMacroAssembler::g1_write_barrier_post(Register store_addr,
+                                                      Register new_val,
+                                                      Register tmp1,
+                                                      Register tmp2,
+                                                      Register tmp3) {
+
+  Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
+                                        DirtyCardQueue::byte_offset_of_index()));
+  Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
+                                   DirtyCardQueue::byte_offset_of_buf()));
+
+  BarrierSet* bs = Universe::heap()->barrier_set();
+  CardTableModRefBS* ct = (CardTableModRefBS*)bs;
+  Label done;
+  Label runtime;
+
+  // Does store cross heap regions?
+
+  eor(tmp1, store_addr, new_val);
+#ifdef AARCH64
+  logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
+  cbz(tmp1, done);
+#else
+  movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
+  b(done, eq);
+#endif
+
+  // crosses regions, storing NULL?
+
+  cbz(new_val, done);
+
+  // storing region crossing non-NULL, is card already dirty?
+  const Register card_addr = tmp1;
+  assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+
+  mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference);
+  add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift));
+
+  ldrb(tmp2, Address(card_addr));
+  cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val());
+  b(done, eq);
+
+  membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
+
+  assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code");
+  ldrb(tmp2, Address(card_addr));
+  cbz(tmp2, done);
+
+  // storing a region crossing, non-NULL oop, card is clean.
+  // dirty card and log.
+
+  strb(zero_register(tmp2), Address(card_addr));
+
+  ldr(tmp2, queue_index);
+  ldr(tmp3, buffer);
+
+  subs(tmp2, tmp2, wordSize);
+  b(runtime, lt); // go to runtime if now negative
+
+  str(tmp2, queue_index);
+
+  str(card_addr, Address(tmp3, tmp2));
+  b(done);
+
+  bind(runtime);
+
+  if (card_addr != R0) {
+    mov(R0, card_addr);
+  }
+  mov(R1, Rthread);
+  call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
+
+  bind(done);
+}
+
+#endif // INCLUDE_ALL_GCS
+//////////////////////////////////////////////////////////////////////////////////
+
+
+// Java Expression Stack
+
+void InterpreterMacroAssembler::pop_ptr(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  ldr(r, Address(Rstack_top, wordSize, post_indexed));
+}
+
+void InterpreterMacroAssembler::pop_i(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  ldr_s32(r, Address(Rstack_top, wordSize, post_indexed));
+  zap_high_non_significant_bits(r);
+}
+
+#ifdef AARCH64
+void InterpreterMacroAssembler::pop_l(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  ldr(r, Address(Rstack_top, 2*wordSize, post_indexed));
+}
+#else
+void InterpreterMacroAssembler::pop_l(Register lo, Register hi) {
+  assert_different_registers(lo, hi);
+  assert(lo < hi, "lo must be < hi");
+  pop(RegisterSet(lo) | RegisterSet(hi));
+}
+#endif // AARCH64
+
+void InterpreterMacroAssembler::pop_f(FloatRegister fd) {
+#ifdef AARCH64
+  ldr_s(fd, Address(Rstack_top, wordSize, post_indexed));
+#else
+  fpops(fd);
+#endif // AARCH64
+}
+
+void InterpreterMacroAssembler::pop_d(FloatRegister fd) {
+#ifdef AARCH64
+  ldr_d(fd, Address(Rstack_top, 2*wordSize, post_indexed));
+#else
+  fpopd(fd);
+#endif // AARCH64
+}
+
+
+// Transition vtos -> state. Blows R0, R1. Sets TOS cached value.
+void InterpreterMacroAssembler::pop(TosState state) {
+  switch (state) {
+    case atos: pop_ptr(R0_tos);                              break;
+    case btos:                                               // fall through
+    case ztos:                                               // fall through
+    case ctos:                                               // fall through
+    case stos:                                               // fall through
+    case itos: pop_i(R0_tos);                                break;
+#ifdef AARCH64
+    case ltos: pop_l(R0_tos);                                break;
+#else
+    case ltos: pop_l(R0_tos_lo, R1_tos_hi);                  break;
+#endif // AARCH64
+#ifdef __SOFTFP__
+    case ftos: pop_i(R0_tos);                                break;
+    case dtos: pop_l(R0_tos_lo, R1_tos_hi);                  break;
+#else
+    case ftos: pop_f(S0_tos);                                break;
+    case dtos: pop_d(D0_tos);                                break;
+#endif // __SOFTFP__
+    case vtos: /* nothing to do */                           break;
+    default  : ShouldNotReachHere();
+  }
+  interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+}
+
+void InterpreterMacroAssembler::push_ptr(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  str(r, Address(Rstack_top, -wordSize, pre_indexed));
+  check_stack_top_on_expansion();
+}
+
+void InterpreterMacroAssembler::push_i(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  str_32(r, Address(Rstack_top, -wordSize, pre_indexed));
+  check_stack_top_on_expansion();
+}
+
+#ifdef AARCH64
+void InterpreterMacroAssembler::push_l(Register r) {
+  assert(r != Rstack_top, "unpredictable instruction");
+  stp(r, ZR, Address(Rstack_top, -2*wordSize, pre_indexed));
+  check_stack_top_on_expansion();
+}
+#else
+void InterpreterMacroAssembler::push_l(Register lo, Register hi) {
+  assert_different_registers(lo, hi);
+  assert(lo < hi, "lo must be < hi");
+  push(RegisterSet(lo) | RegisterSet(hi));
+}
+#endif // AARCH64
+
+void InterpreterMacroAssembler::push_f() {
+#ifdef AARCH64
+  str_s(S0_tos, Address(Rstack_top, -wordSize, pre_indexed));
+  check_stack_top_on_expansion();
+#else
+  fpushs(S0_tos);
+#endif // AARCH64
+}
+
+void InterpreterMacroAssembler::push_d() {
+#ifdef AARCH64
+  str_d(D0_tos, Address(Rstack_top, -2*wordSize, pre_indexed));
+  check_stack_top_on_expansion();
+#else
+  fpushd(D0_tos);
+#endif // AARCH64
+}
+
+// Transition state -> vtos. Blows Rtemp.
+void InterpreterMacroAssembler::push(TosState state) {
+  interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+  switch (state) {
+    case atos: push_ptr(R0_tos);                              break;
+    case btos:                                                // fall through
+    case ztos:                                                // fall through
+    case ctos:                                                // fall through
+    case stos:                                                // fall through
+    case itos: push_i(R0_tos);                                break;
+#ifdef AARCH64
+    case ltos: push_l(R0_tos);                                break;
+#else
+    case ltos: push_l(R0_tos_lo, R1_tos_hi);                  break;
+#endif // AARCH64
+#ifdef __SOFTFP__
+    case ftos: push_i(R0_tos);                                break;
+    case dtos: push_l(R0_tos_lo, R1_tos_hi);                  break;
+#else
+    case ftos: push_f();                                      break;
+    case dtos: push_d();                                      break;
+#endif // __SOFTFP__
+    case vtos: /* nothing to do */                            break;
+    default  : ShouldNotReachHere();
+  }
+}
+
+
+#ifndef AARCH64
+
+// Converts return value in R0/R1 (interpreter calling conventions) to TOS cached value.
+void InterpreterMacroAssembler::convert_retval_to_tos(TosState state) {
+#if (!defined __SOFTFP__ && !defined __ABI_HARD__)
+  // According to interpreter calling conventions, result is returned in R0/R1,
+  // but templates expect ftos in S0, and dtos in D0.
+  if (state == ftos) {
+    fmsr(S0_tos, R0);
+  } else if (state == dtos) {
+    fmdrr(D0_tos, R0, R1);
+  }
+#endif // !__SOFTFP__ && !__ABI_HARD__
+}
+
+// Converts TOS cached value to return value in R0/R1 (according to interpreter calling conventions).
+void InterpreterMacroAssembler::convert_tos_to_retval(TosState state) {
+#if (!defined __SOFTFP__ && !defined __ABI_HARD__)
+  // According to interpreter calling conventions, result is returned in R0/R1,
+  // so ftos (S0) and dtos (D0) are moved to R0/R1.
+  if (state == ftos) {
+    fmrs(R0, S0_tos);
+  } else if (state == dtos) {
+    fmrrd(R0, R1, D0_tos);
+  }
+#endif // !__SOFTFP__ && !__ABI_HARD__
+}
+
+#endif // !AARCH64
+
+
+// Helpers for swap and dup
+void InterpreterMacroAssembler::load_ptr(int n, Register val) {
+  ldr(val, Address(Rstack_top, Interpreter::expr_offset_in_bytes(n)));
+}
+
+void InterpreterMacroAssembler::store_ptr(int n, Register val) {
+  str(val, Address(Rstack_top, Interpreter::expr_offset_in_bytes(n)));
+}
+
+
+void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
+#ifdef AARCH64
+  check_no_cached_stack_top(Rtemp);
+  save_stack_top();
+  cut_sp_before_call();
+  mov(Rparams, Rstack_top);
+#endif // AARCH64
+
+  // set sender sp
+  mov(Rsender_sp, SP);
+
+#ifndef AARCH64
+  // record last_sp
+  str(Rsender_sp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // !AARCH64
+}
+
+// Jump to from_interpreted entry of a call unless single stepping is possible
+// in this thread in which case we must call the i2i entry
+void InterpreterMacroAssembler::jump_from_interpreted(Register method) {
+  assert_different_registers(method, Rtemp);
+
+  prepare_to_jump_from_interpreted();
+
+  if (can_post_interpreter_events()) {
+    // JVMTI events, such as single-stepping, are implemented partly by avoiding running
+    // compiled code in threads for which the event is enabled.  Check here for
+    // interp_only_mode if these events CAN be enabled.
+
+    ldr_s32(Rtemp, Address(Rthread, JavaThread::interp_only_mode_offset()));
+#ifdef AARCH64
+    {
+      Label not_interp_only_mode;
+
+      cbz(Rtemp, not_interp_only_mode);
+      indirect_jump(Address(method, Method::interpreter_entry_offset()), Rtemp);
+
+      bind(not_interp_only_mode);
+    }
+#else
+    cmp(Rtemp, 0);
+    ldr(PC, Address(method, Method::interpreter_entry_offset()), ne);
+#endif // AARCH64
+  }
+
+  indirect_jump(Address(method, Method::from_interpreted_offset()), Rtemp);
+}
+
+
+void InterpreterMacroAssembler::restore_dispatch() {
+  mov_slow(RdispatchTable, (address)Interpreter::dispatch_table(vtos));
+}
+
+
+// The following two routines provide a hook so that an implementation
+// can schedule the dispatch in two parts.
+void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) {
+  // Nothing ARM-specific to be done here.
+}
+
+void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) {
+  dispatch_next(state, step);
+}
+
+void InterpreterMacroAssembler::dispatch_base(TosState state,
+                                              DispatchTableMode table_mode,
+                                              bool verifyoop) {
+  if (VerifyActivationFrameSize) {
+    Label L;
+#ifdef AARCH64
+    mov(Rtemp, SP);
+    sub(Rtemp, FP, Rtemp);
+#else
+    sub(Rtemp, FP, SP);
+#endif // AARCH64
+    int min_frame_size = (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * wordSize;
+    cmp(Rtemp, min_frame_size);
+    b(L, ge);
+    stop("broken stack frame");
+    bind(L);
+  }
+
+  if (verifyoop) {
+    interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+  }
+
+  if((state == itos) || (state == btos) || (state == ztos) || (state == ctos) || (state == stos)) {
+    zap_high_non_significant_bits(R0_tos);
+  }
+
+#ifdef ASSERT
+  Label L;
+  mov_slow(Rtemp, (address)Interpreter::dispatch_table(vtos));
+  cmp(Rtemp, RdispatchTable);
+  b(L, eq);
+  stop("invalid RdispatchTable");
+  bind(L);
+#endif
+
+  if (table_mode == DispatchDefault) {
+    if (state == vtos) {
+      indirect_jump(Address::indexed_ptr(RdispatchTable, R3_bytecode), Rtemp);
+    } else {
+#ifdef AARCH64
+      sub(Rtemp, R3_bytecode, (Interpreter::distance_from_dispatch_table(vtos) -
+                           Interpreter::distance_from_dispatch_table(state)));
+      indirect_jump(Address::indexed_ptr(RdispatchTable, Rtemp), Rtemp);
+#else
+      // on 32-bit ARM this method is faster than the one above.
+      sub(Rtemp, RdispatchTable, (Interpreter::distance_from_dispatch_table(vtos) -
+                           Interpreter::distance_from_dispatch_table(state)) * wordSize);
+      indirect_jump(Address::indexed_ptr(Rtemp, R3_bytecode), Rtemp);
+#endif
+    }
+  } else {
+    assert(table_mode == DispatchNormal, "invalid dispatch table mode");
+    address table = (address) Interpreter::normal_table(state);
+    mov_slow(Rtemp, table);
+    indirect_jump(Address::indexed_ptr(Rtemp, R3_bytecode), Rtemp);
+  }
+
+  nop(); // to avoid filling CPU pipeline with invalid instructions
+  nop();
+}
+
+void InterpreterMacroAssembler::dispatch_only(TosState state) {
+  dispatch_base(state, DispatchDefault);
+}
+
+
+void InterpreterMacroAssembler::dispatch_only_normal(TosState state) {
+  dispatch_base(state, DispatchNormal);
+}
+
+void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) {
+  dispatch_base(state, DispatchNormal, false);
+}
+
+void InterpreterMacroAssembler::dispatch_next(TosState state, int step) {
+  // load next bytecode and advance Rbcp
+  ldrb(R3_bytecode, Address(Rbcp, step, pre_indexed));
+  dispatch_base(state, DispatchDefault);
+}
+
+void InterpreterMacroAssembler::narrow(Register result) {
+  // mask integer result to narrower return type.
+  const Register Rtmp = R2;
+
+  // get method type
+  ldr(Rtmp, Address(Rmethod, Method::const_offset()));
+  ldrb(Rtmp, Address(Rtmp, ConstMethod::result_type_offset()));
+
+  Label notBool, notByte, notChar, done;
+  cmp(Rtmp, T_INT);
+  b(done, eq);
+
+  cmp(Rtmp, T_BOOLEAN);
+  b(notBool, ne);
+  and_32(result, result, 1);
+  b(done);
+
+  bind(notBool);
+  cmp(Rtmp, T_BYTE);
+  b(notByte, ne);
+  sign_extend(result, result, 8);
+  b(done);
+
+  bind(notByte);
+  cmp(Rtmp, T_CHAR);
+  b(notChar, ne);
+  zero_extend(result, result, 16);
+  b(done);
+
+  bind(notChar);
+  // cmp(Rtmp, T_SHORT);
+  // b(done, ne);
+  sign_extend(result, result, 16);
+
+  // Nothing to do
+  bind(done);
+}
+
+// remove activation
+//
+// Unlock the receiver if this is a synchronized method.
+// Unlock any Java monitors from syncronized blocks.
+// Remove the activation from the stack.
+//
+// If there are locked Java monitors
+//    If throw_monitor_exception
+//       throws IllegalMonitorStateException
+//    Else if install_monitor_exception
+//       installs IllegalMonitorStateException
+//    Else
+//       no error processing
+void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_addr,
+                                                  bool throw_monitor_exception,
+                                                  bool install_monitor_exception,
+                                                  bool notify_jvmdi) {
+  Label unlock, unlocked, no_unlock;
+
+  // Note: Registers R0, R1, S0 and D0 (TOS cached value) may be in use for the result.
+
+  const Address do_not_unlock_if_synchronized(Rthread,
+                         JavaThread::do_not_unlock_if_synchronized_offset());
+
+  const Register Rflag = R2;
+  const Register Raccess_flags = R3;
+
+  restore_method();
+
+  ldrb(Rflag, do_not_unlock_if_synchronized);
+
+  // get method access flags
+  ldr_u32(Raccess_flags, Address(Rmethod, Method::access_flags_offset()));
+
+  strb(zero_register(Rtemp), do_not_unlock_if_synchronized); // reset the flag
+
+  // check if method is synchronized
+
+  tbz(Raccess_flags, JVM_ACC_SYNCHRONIZED_BIT, unlocked);
+
+  // Don't unlock anything if the _do_not_unlock_if_synchronized flag is set.
+  cbnz(Rflag, no_unlock);
+
+  // unlock monitor
+  push(state);                                   // save result
+
+  // BasicObjectLock will be first in list, since this is a synchronized method. However, need
+  // to check that the object has not been unlocked by an explicit monitorexit bytecode.
+
+  const Register Rmonitor = R1;                  // fixed in unlock_object()
+  const Register Robj = R2;
+
+  // address of first monitor
+  sub(Rmonitor, FP, - frame::interpreter_frame_monitor_block_bottom_offset * wordSize + (int)sizeof(BasicObjectLock));
+
+  ldr(Robj, Address(Rmonitor, BasicObjectLock::obj_offset_in_bytes()));
+  cbnz(Robj, unlock);
+
+  pop(state);
+
+  if (throw_monitor_exception) {
+    // Entry already unlocked, need to throw exception
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+    should_not_reach_here();
+  } else {
+    // Monitor already unlocked during a stack unroll.
+    // If requested, install an illegal_monitor_state_exception.
+    // Continue with stack unrolling.
+    if (install_monitor_exception) {
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
+    }
+    b(unlocked);
+  }
+
+
+  // Exception case for the check that all monitors are unlocked.
+  const Register Rcur = R2;
+  Label restart_check_monitors_unlocked, exception_monitor_is_still_locked;
+
+  bind(exception_monitor_is_still_locked);
+  // Monitor entry is still locked, need to throw exception.
+  // Rcur: monitor entry.
+
+  if (throw_monitor_exception) {
+    // Throw exception
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+    should_not_reach_here();
+  } else {
+    // Stack unrolling. Unlock object and install illegal_monitor_exception
+    // Unlock does not block, so don't have to worry about the frame
+
+    push(state);
+    mov(R1, Rcur);
+    unlock_object(R1);
+
+    if (install_monitor_exception) {
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
+    }
+
+    pop(state);
+    b(restart_check_monitors_unlocked);
+  }
+
+  bind(unlock);
+  unlock_object(Rmonitor);
+  pop(state);
+
+  // Check that for block-structured locking (i.e., that all locked objects has been unlocked)
+  bind(unlocked);
+
+  // Check that all monitors are unlocked
+  {
+    Label loop;
+
+    const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+    const Register Rbottom = R3;
+    const Register Rcur_obj = Rtemp;
+
+    bind(restart_check_monitors_unlocked);
+
+    ldr(Rcur, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                 // points to current entry, starting with top-most entry
+    sub(Rbottom, FP, -frame::interpreter_frame_monitor_block_bottom_offset * wordSize);
+                                 // points to word before bottom of monitor block
+
+    cmp(Rcur, Rbottom);          // check if there are no monitors
+#ifndef AARCH64
+    ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+                                 // prefetch monitor's object
+#endif // !AARCH64
+    b(no_unlock, eq);
+
+    bind(loop);
+#ifdef AARCH64
+    ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()));
+#endif // AARCH64
+    // check if current entry is used
+    cbnz(Rcur_obj, exception_monitor_is_still_locked);
+
+    add(Rcur, Rcur, entry_size);      // otherwise advance to next entry
+    cmp(Rcur, Rbottom);               // check if bottom reached
+#ifndef AARCH64
+    ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+                                      // prefetch monitor's object
+#endif // !AARCH64
+    b(loop, ne);                      // if not at bottom then check this entry
+  }
+
+  bind(no_unlock);
+
+  // jvmti support
+  if (notify_jvmdi) {
+    notify_method_exit(state, NotifyJVMTI);     // preserve TOSCA
+  } else {
+    notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA
+  }
+
+  // remove activation
+#ifdef AARCH64
+  ldr(Rtemp, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+  ldp(FP, LR, Address(FP));
+  mov(SP, Rtemp);
+#else
+  mov(Rtemp, FP);
+  ldmia(FP, RegisterSet(FP) | RegisterSet(LR));
+  ldr(SP, Address(Rtemp, frame::interpreter_frame_sender_sp_offset * wordSize));
+#endif
+
+  if (ret_addr != LR) {
+    mov(ret_addr, LR);
+  }
+}
+
+
+// At certain points in the method invocation the monitor of
+// synchronized methods hasn't been entered yet.
+// To correctly handle exceptions at these points, we set the thread local
+// variable _do_not_unlock_if_synchronized to true. The remove_activation will
+// check this flag.
+void InterpreterMacroAssembler::set_do_not_unlock_if_synchronized(bool flag, Register tmp) {
+  const Address do_not_unlock_if_synchronized(Rthread,
+                         JavaThread::do_not_unlock_if_synchronized_offset());
+  if (flag) {
+    mov(tmp, 1);
+    strb(tmp, do_not_unlock_if_synchronized);
+  } else {
+    strb(zero_register(tmp), do_not_unlock_if_synchronized);
+  }
+}
+
+// Lock object
+//
+// Argument: R1 : Points to BasicObjectLock to be used for locking.
+// Must be initialized with object to lock.
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR. Calls VM.
+void InterpreterMacroAssembler::lock_object(Register Rlock) {
+  assert(Rlock == R1, "the second argument");
+
+  if (UseHeavyMonitors) {
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
+  } else {
+    Label done;
+
+    const Register Robj = R2;
+    const Register Rmark = R3;
+    assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
+
+    const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
+    const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
+    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
+
+    Label already_locked, slow_case;
+
+    // Load object pointer
+    ldr(Robj, Address(Rlock, obj_offset));
+
+    if (UseBiasedLocking) {
+      biased_locking_enter(Robj, Rmark/*scratched*/, R0, false, Rtemp, done, slow_case);
+    }
+
+#ifdef AARCH64
+    assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
+    ldr(Rmark, Robj);
+
+    // Test if object is already locked
+    assert(markOopDesc::unlocked_value == 1, "adjust this code");
+    tbz(Rmark, exact_log2(markOopDesc::unlocked_value), already_locked);
+
+#else // AARCH64
+
+    // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
+    // That would be acceptable as ether CAS or slow case path is taken in that case.
+    // Exception to that is if the object is locked by the calling thread, then the recursive test will pass (guaranteed as
+    // loads are satisfied from a store queue if performed on the same processor).
+
+    assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
+    ldr(Rmark, Address(Robj, oopDesc::mark_offset_in_bytes()));
+
+    // Test if object is already locked
+    tst(Rmark, markOopDesc::unlocked_value);
+    b(already_locked, eq);
+
+#endif // !AARCH64
+    // Save old object->mark() into BasicLock's displaced header
+    str(Rmark, Address(Rlock, mark_offset));
+
+    cas_for_lock_acquire(Rmark, Rlock, Robj, Rtemp, slow_case);
+
+#ifndef PRODUCT
+    if (PrintBiasedLockingStatistics) {
+      cond_atomic_inc32(al, BiasedLocking::fast_path_entry_count_addr());
+    }
+#endif //!PRODUCT
+
+    b(done);
+
+    // If we got here that means the object is locked by ether calling thread or another thread.
+    bind(already_locked);
+    // Handling of locked objects: recursive locks and slow case.
+
+    // Fast check for recursive lock.
+    //
+    // Can apply the optimization only if this is a stack lock
+    // allocated in this thread. For efficiency, we can focus on
+    // recently allocated stack locks (instead of reading the stack
+    // base and checking whether 'mark' points inside the current
+    // thread stack):
+    //  1) (mark & 3) == 0
+    //  2) SP <= mark < SP + os::pagesize()
+    //
+    // Warning: SP + os::pagesize can overflow the stack base. We must
+    // neither apply the optimization for an inflated lock allocated
+    // just above the thread stack (this is why condition 1 matters)
+    // nor apply the optimization if the stack lock is inside the stack
+    // of another thread. The latter is avoided even in case of overflow
+    // because we have guard pages at the end of all stacks. Hence, if
+    // we go over the stack base and hit the stack of another thread,
+    // this should not be in a writeable area that could contain a
+    // stack lock allocated by that thread. As a consequence, a stack
+    // lock less than page size away from SP is guaranteed to be
+    // owned by the current thread.
+    //
+    // Note: assuming SP is aligned, we can check the low bits of
+    // (mark-SP) instead of the low bits of mark. In that case,
+    // assuming page size is a power of 2, we can merge the two
+    // conditions into a single test:
+    // => ((mark - SP) & (3 - os::pagesize())) == 0
+
+#ifdef AARCH64
+    // Use the single check since the immediate is OK for AARCH64
+    sub(R0, Rmark, Rstack_top);
+    intptr_t mask = ((intptr_t)3) - ((intptr_t)os::vm_page_size());
+    Assembler::LogicalImmediate imm(mask, false);
+    ands(R0, R0, imm);
+
+    // For recursive case store 0 into lock record.
+    // It is harmless to store it unconditionally as lock record contains some garbage
+    // value in its _displaced_header field by this moment.
+    str(ZR, Address(Rlock, mark_offset));
+
+#else // AARCH64
+    // (3 - os::pagesize()) cannot be encoded as an ARM immediate operand.
+    // Check independently the low bits and the distance to SP.
+    // -1- test low 2 bits
+    movs(R0, AsmOperand(Rmark, lsl, 30));
+    // -2- test (mark - SP) if the low two bits are 0
+    sub(R0, Rmark, SP, eq);
+    movs(R0, AsmOperand(R0, lsr, exact_log2(os::vm_page_size())), eq);
+    // If still 'eq' then recursive locking OK: store 0 into lock record
+    str(R0, Address(Rlock, mark_offset), eq);
+
+#endif // AARCH64
+
+#ifndef PRODUCT
+    if (PrintBiasedLockingStatistics) {
+      cond_atomic_inc32(eq, BiasedLocking::fast_path_entry_count_addr());
+    }
+#endif // !PRODUCT
+
+    b(done, eq);
+
+    bind(slow_case);
+
+    // Call the runtime routine for slow case
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
+
+    bind(done);
+  }
+}
+
+
+// Unlocks an object. Used in monitorexit bytecode and remove_activation.
+//
+// Argument: R1: Points to BasicObjectLock structure for lock
+// Throw an IllegalMonitorException if object is not locked by current thread
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR. Calls VM.
+void InterpreterMacroAssembler::unlock_object(Register Rlock) {
+  assert(Rlock == R1, "the second argument");
+
+  if (UseHeavyMonitors) {
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
+  } else {
+    Label done, slow_case;
+
+    const Register Robj = R2;
+    const Register Rmark = R3;
+    const Register Rresult = R0;
+    assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
+
+    const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
+    const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
+    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
+
+    const Register Rzero = zero_register(Rtemp);
+
+    // Load oop into Robj
+    ldr(Robj, Address(Rlock, obj_offset));
+
+    // Free entry
+    str(Rzero, Address(Rlock, obj_offset));
+
+    if (UseBiasedLocking) {
+      biased_locking_exit(Robj, Rmark, done);
+    }
+
+    // Load the old header from BasicLock structure
+    ldr(Rmark, Address(Rlock, mark_offset));
+
+    // Test for recursion (zero mark in BasicLock)
+    cbz(Rmark, done);
+
+    bool allow_fallthrough_on_failure = true;
+
+    cas_for_lock_release(Rlock, Rmark, Robj, Rtemp, slow_case, allow_fallthrough_on_failure);
+
+    b(done, eq);
+
+    bind(slow_case);
+
+    // Call the runtime routine for slow case.
+    str(Robj, Address(Rlock, obj_offset)); // restore obj
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
+
+    bind(done);
+  }
+}
+
+
+// Test ImethodDataPtr.  If it is null, continue at the specified label
+void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, Label& zero_continue) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  ldr(mdp, Address(FP, frame::interpreter_frame_mdp_offset * wordSize));
+  cbz(mdp, zero_continue);
+}
+
+
+// Set the method data pointer for the current bcp.
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR.
+void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  Label set_mdp;
+
+  // Test MDO to avoid the call if it is NULL.
+  ldr(Rtemp, Address(Rmethod, Method::method_data_offset()));
+  cbz(Rtemp, set_mdp);
+
+  mov(R0, Rmethod);
+  mov(R1, Rbcp);
+  call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), R0, R1);
+  // R0/W0: mdi
+
+  // mdo is guaranteed to be non-zero here, we checked for it before the call.
+  ldr(Rtemp, Address(Rmethod, Method::method_data_offset()));
+  add(Rtemp, Rtemp, in_bytes(MethodData::data_offset()));
+  add_ptr_scaled_int32(Rtemp, Rtemp, R0, 0);
+
+  bind(set_mdp);
+  str(Rtemp, Address(FP, frame::interpreter_frame_mdp_offset * wordSize));
+}
+
+
+void InterpreterMacroAssembler::verify_method_data_pointer() {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+#ifdef ASSERT
+  Label verify_continue;
+  save_caller_save_registers();
+
+  const Register Rmdp = R2;
+  test_method_data_pointer(Rmdp, verify_continue); // If mdp is zero, continue
+
+  // If the mdp is valid, it will point to a DataLayout header which is
+  // consistent with the bcp.  The converse is highly probable also.
+
+  ldrh(R3, Address(Rmdp, DataLayout::bci_offset()));
+  ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+  add(R3, R3, Rtemp);
+  add(R3, R3, in_bytes(ConstMethod::codes_offset()));
+  cmp(R3, Rbcp);
+  b(verify_continue, eq);
+
+  mov(R0, Rmethod);
+  mov(R1, Rbcp);
+  call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), R0, R1, Rmdp);
+
+  bind(verify_continue);
+  restore_caller_save_registers();
+#endif // ASSERT
+}
+
+
+void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, int offset, Register value) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert_different_registers(mdp_in, value);
+  str(value, Address(mdp_in, offset));
+}
+
+
+// Increments mdp data. Sets bumped_count register to adjusted counter.
+void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in,
+                                                      int offset,
+                                                      Register bumped_count,
+                                                      bool decrement) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+
+  // Counter address
+  Address data(mdp_in, offset);
+  assert_different_registers(mdp_in, bumped_count);
+
+  increment_mdp_data_at(data, bumped_count, decrement);
+}
+
+void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, int flag_byte_constant) {
+  assert_different_registers(mdp_in, Rtemp);
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert((0 < flag_byte_constant) && (flag_byte_constant < (1 << BitsPerByte)), "flag mask is out of range");
+
+  // Set the flag
+  ldrb(Rtemp, Address(mdp_in, in_bytes(DataLayout::flags_offset())));
+  orr(Rtemp, Rtemp, (unsigned)flag_byte_constant);
+  strb(Rtemp, Address(mdp_in, in_bytes(DataLayout::flags_offset())));
+}
+
+
+// Increments mdp data. Sets bumped_count register to adjusted counter.
+void InterpreterMacroAssembler::increment_mdp_data_at(Address data,
+                                                      Register bumped_count,
+                                                      bool decrement) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+
+  ldr(bumped_count, data);
+  if (decrement) {
+    // Decrement the register. Set condition codes.
+    subs(bumped_count, bumped_count, DataLayout::counter_increment);
+    // Avoid overflow.
+#ifdef AARCH64
+    assert(DataLayout::counter_increment == 1, "required for cinc");
+    cinc(bumped_count, bumped_count, pl);
+#else
+    add(bumped_count, bumped_count, DataLayout::counter_increment, pl);
+#endif // AARCH64
+  } else {
+    // Increment the register. Set condition codes.
+    adds(bumped_count, bumped_count, DataLayout::counter_increment);
+    // Avoid overflow.
+#ifdef AARCH64
+    assert(DataLayout::counter_increment == 1, "required for cinv");
+    cinv(bumped_count, bumped_count, mi); // inverts 0x80..00 back to 0x7f..ff
+#else
+    sub(bumped_count, bumped_count, DataLayout::counter_increment, mi);
+#endif // AARCH64
+  }
+  str(bumped_count, data);
+}
+
+
+void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in,
+                                                 int offset,
+                                                 Register value,
+                                                 Register test_value_out,
+                                                 Label& not_equal_continue) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert_different_registers(mdp_in, test_value_out, value);
+
+  ldr(test_value_out, Address(mdp_in, offset));
+  cmp(test_value_out, value);
+
+  b(not_equal_continue, ne);
+}
+
+
+void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, int offset_of_disp, Register reg_temp) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert_different_registers(mdp_in, reg_temp);
+
+  ldr(reg_temp, Address(mdp_in, offset_of_disp));
+  add(mdp_in, mdp_in, reg_temp);
+  str(mdp_in, Address(FP, frame::interpreter_frame_mdp_offset * wordSize));
+}
+
+
+void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, Register reg_offset, Register reg_tmp) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert_different_registers(mdp_in, reg_offset, reg_tmp);
+
+  ldr(reg_tmp, Address(mdp_in, reg_offset));
+  add(mdp_in, mdp_in, reg_tmp);
+  str(mdp_in, Address(FP, frame::interpreter_frame_mdp_offset * wordSize));
+}
+
+
+void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, int constant) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  add(mdp_in, mdp_in, constant);
+  str(mdp_in, Address(FP, frame::interpreter_frame_mdp_offset * wordSize));
+}
+
+
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) {
+  assert(ProfileInterpreter, "must be profiling interpreter");
+  assert_different_registers(return_bci, R0, R1, R2, R3, Rtemp);
+
+  mov(R1, return_bci);
+  call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), R1);
+}
+
+
+// Sets mdp, bumped_count registers, blows Rtemp.
+void InterpreterMacroAssembler::profile_taken_branch(Register mdp, Register bumped_count) {
+  assert_different_registers(mdp, bumped_count);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    // Otherwise, assign to mdp
+    test_method_data_pointer(mdp, profile_continue);
+
+    // We are taking a branch. Increment the taken count.
+    increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset()), bumped_count);
+
+    // The method data pointer needs to be updated to reflect the new target.
+    update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset()), Rtemp);
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
+  assert_different_registers(mdp, Rtemp);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // We are taking a branch.  Increment the not taken count.
+    increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset()), Rtemp);
+
+    // The method data pointer needs to be updated to correspond to the next bytecode
+    update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size()));
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_call(Register mdp) {
+  assert_different_registers(mdp, Rtemp);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // We are making a call.  Increment the count.
+    increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), Rtemp);
+
+    // The method data pointer needs to be updated to reflect the new target.
+    update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size()));
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_final_call(Register mdp) {
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // We are making a call.  Increment the count.
+    increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), Rtemp);
+
+    // The method data pointer needs to be updated to reflect the new target.
+    update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_virtual_call(Register mdp, Register receiver, bool receiver_can_be_null) {
+  assert_different_registers(mdp, receiver, Rtemp);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    Label skip_receiver_profile;
+    if (receiver_can_be_null) {
+      Label not_null;
+      cbnz(receiver, not_null);
+      // We are making a call.  Increment the count for null receiver.
+      increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), Rtemp);
+      b(skip_receiver_profile);
+      bind(not_null);
+    }
+
+    // Record the receiver type.
+    record_klass_in_profile(receiver, mdp, Rtemp, true);
+    bind(skip_receiver_profile);
+
+    // The method data pointer needs to be updated to reflect the new target.
+    update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
+    bind(profile_continue);
+  }
+}
+
+
+void InterpreterMacroAssembler::record_klass_in_profile_helper(
+                                        Register receiver, Register mdp,
+                                        Register reg_tmp,
+                                        int start_row, Label& done, bool is_virtual_call) {
+  if (TypeProfileWidth == 0)
+    return;
+
+  assert_different_registers(receiver, mdp, reg_tmp);
+
+  int last_row = VirtualCallData::row_limit() - 1;
+  assert(start_row <= last_row, "must be work left to do");
+  // Test this row for both the receiver and for null.
+  // Take any of three different outcomes:
+  //   1. found receiver => increment count and goto done
+  //   2. found null => keep looking for case 1, maybe allocate this cell
+  //   3. found something else => keep looking for cases 1 and 2
+  // Case 3 is handled by a recursive call.
+  for (int row = start_row; row <= last_row; row++) {
+    Label next_test;
+
+    // See if the receiver is receiver[n].
+    int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
+
+    test_mdp_data_at(mdp, recvr_offset, receiver, reg_tmp, next_test);
+
+    // The receiver is receiver[n].  Increment count[n].
+    int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
+    increment_mdp_data_at(mdp, count_offset, reg_tmp);
+    b(done);
+
+    bind(next_test);
+    // reg_tmp now contains the receiver from the CallData.
+
+    if (row == start_row) {
+      Label found_null;
+      // Failed the equality check on receiver[n]...  Test for null.
+      if (start_row == last_row) {
+        // The only thing left to do is handle the null case.
+        if (is_virtual_call) {
+          cbz(reg_tmp, found_null);
+          // Receiver did not match any saved receiver and there is no empty row for it.
+          // Increment total counter to indicate polymorphic case.
+          increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), reg_tmp);
+          b(done);
+          bind(found_null);
+        } else {
+          cbnz(reg_tmp, done);
+        }
+        break;
+      }
+      // Since null is rare, make it be the branch-taken case.
+      cbz(reg_tmp, found_null);
+
+      // Put all the "Case 3" tests here.
+      record_klass_in_profile_helper(receiver, mdp, reg_tmp, start_row + 1, done, is_virtual_call);
+
+      // Found a null.  Keep searching for a matching receiver,
+      // but remember that this is an empty (unused) slot.
+      bind(found_null);
+    }
+  }
+
+  // In the fall-through case, we found no matching receiver, but we
+  // observed the receiver[start_row] is NULL.
+
+  // Fill in the receiver field and increment the count.
+  int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row));
+  set_mdp_data_at(mdp, recvr_offset, receiver);
+  int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
+  mov(reg_tmp, DataLayout::counter_increment);
+  set_mdp_data_at(mdp, count_offset, reg_tmp);
+  if (start_row > 0) {
+    b(done);
+  }
+}
+
+void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
+                                                        Register mdp,
+                                                        Register reg_tmp,
+                                                        bool is_virtual_call) {
+  assert(ProfileInterpreter, "must be profiling");
+  assert_different_registers(receiver, mdp, reg_tmp);
+
+  Label done;
+
+  record_klass_in_profile_helper(receiver, mdp, reg_tmp, 0, done, is_virtual_call);
+
+  bind (done);
+}
+
+// Sets mdp, blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+void InterpreterMacroAssembler::profile_ret(Register mdp, Register return_bci) {
+  assert_different_registers(mdp, return_bci, Rtemp, R0, R1, R2, R3);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+    uint row;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // Update the total ret count.
+    increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), Rtemp);
+
+    for (row = 0; row < RetData::row_limit(); row++) {
+      Label next_test;
+
+      // See if return_bci is equal to bci[n]:
+      test_mdp_data_at(mdp, in_bytes(RetData::bci_offset(row)), return_bci,
+                       Rtemp, next_test);
+
+      // return_bci is equal to bci[n].  Increment the count.
+      increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row)), Rtemp);
+
+      // The method data pointer needs to be updated to reflect the new target.
+      update_mdp_by_offset(mdp, in_bytes(RetData::bci_displacement_offset(row)), Rtemp);
+      b(profile_continue);
+      bind(next_test);
+    }
+
+    update_mdp_for_ret(return_bci);
+
+    bind(profile_continue);
+  }
+}
+
+
+// Sets mdp.
+void InterpreterMacroAssembler::profile_null_seen(Register mdp) {
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    set_mdp_flag_at(mdp, BitData::null_seen_byte_constant());
+
+    // The method data pointer needs to be updated.
+    int mdp_delta = in_bytes(BitData::bit_data_size());
+    if (TypeProfileCasts) {
+      mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+    }
+    update_mdp_by_constant(mdp, mdp_delta);
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) {
+  assert_different_registers(mdp, Rtemp);
+
+  if (ProfileInterpreter && TypeProfileCasts) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    int count_offset = in_bytes(CounterData::count_offset());
+    // Back up the address, since we have already bumped the mdp.
+    count_offset -= in_bytes(VirtualCallData::virtual_call_data_size());
+
+    // *Decrement* the counter.  We expect to see zero or small negatives.
+    increment_mdp_data_at(mdp, count_offset, Rtemp, true);
+
+    bind (profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass)
+{
+  assert_different_registers(mdp, klass, Rtemp);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // The method data pointer needs to be updated.
+    int mdp_delta = in_bytes(BitData::bit_data_size());
+    if (TypeProfileCasts) {
+      mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+
+      // Record the object type.
+      record_klass_in_profile(klass, mdp, Rtemp, false);
+    }
+    update_mdp_by_constant(mdp, mdp_delta);
+
+    bind(profile_continue);
+  }
+}
+
+
+// Sets mdp, blows Rtemp.
+void InterpreterMacroAssembler::profile_switch_default(Register mdp) {
+  assert_different_registers(mdp, Rtemp);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // Update the default case count
+    increment_mdp_data_at(mdp, in_bytes(MultiBranchData::default_count_offset()), Rtemp);
+
+    // The method data pointer needs to be updated.
+    update_mdp_by_offset(mdp, in_bytes(MultiBranchData::default_displacement_offset()), Rtemp);
+
+    bind(profile_continue);
+  }
+}
+
+
+// Sets mdp. Blows reg_tmp1, reg_tmp2. Index could be the same as reg_tmp2.
+void InterpreterMacroAssembler::profile_switch_case(Register mdp, Register index, Register reg_tmp1, Register reg_tmp2) {
+  assert_different_registers(mdp, reg_tmp1, reg_tmp2);
+  assert_different_registers(mdp, reg_tmp1, index);
+
+  if (ProfileInterpreter) {
+    Label profile_continue;
+
+    const int count_offset = in_bytes(MultiBranchData::case_array_offset()) +
+                              in_bytes(MultiBranchData::relative_count_offset());
+
+    const int displacement_offset = in_bytes(MultiBranchData::case_array_offset()) +
+                              in_bytes(MultiBranchData::relative_displacement_offset());
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+
+    // Build the base (index * per_case_size_in_bytes())
+    logical_shift_left(reg_tmp1, index, exact_log2(in_bytes(MultiBranchData::per_case_size())));
+
+    // Update the case count
+    add(reg_tmp1, reg_tmp1, count_offset);
+    increment_mdp_data_at(Address(mdp, reg_tmp1), reg_tmp2);
+
+    // The method data pointer needs to be updated.
+    add(reg_tmp1, reg_tmp1, displacement_offset - count_offset);
+    update_mdp_by_offset(mdp, reg_tmp1, reg_tmp2);
+
+    bind (profile_continue);
+  }
+}
+
+
+void InterpreterMacroAssembler::byteswap_u32(Register r, Register rtmp1, Register rtmp2) {
+#ifdef AARCH64
+  rev_w(r, r);
+#else
+  if (VM_Version::supports_rev()) {
+    rev(r, r);
+  } else {
+    eor(rtmp1, r, AsmOperand(r, ror, 16));
+    mvn(rtmp2, 0x0000ff00);
+    andr(rtmp1, rtmp2, AsmOperand(rtmp1, lsr, 8));
+    eor(r, rtmp1, AsmOperand(r, ror, 8));
+  }
+#endif // AARCH64
+}
+
+
+void InterpreterMacroAssembler::inc_global_counter(address address_of_counter, int offset, Register tmp1, Register tmp2, bool avoid_overflow) {
+  const intx addr = (intx) (address_of_counter + offset);
+
+  assert ((addr & 0x3) == 0, "address of counter should be aligned");
+  const intx offset_mask = right_n_bits(AARCH64_ONLY(12 + 2) NOT_AARCH64(12));
+
+  const address base = (address) (addr & ~offset_mask);
+  const int offs = (int) (addr & offset_mask);
+
+  const Register addr_base = tmp1;
+  const Register val = tmp2;
+
+  mov_slow(addr_base, base);
+  ldr_s32(val, Address(addr_base, offs));
+
+  if (avoid_overflow) {
+    adds_32(val, val, 1);
+#ifdef AARCH64
+    Label L;
+    b(L, mi);
+    str_32(val, Address(addr_base, offs));
+    bind(L);
+#else
+    str(val, Address(addr_base, offs), pl);
+#endif // AARCH64
+  } else {
+    add_32(val, val, 1);
+    str_32(val, Address(addr_base, offs));
+  }
+}
+
+void InterpreterMacroAssembler::interp_verify_oop(Register reg, TosState state, const char *file, int line) {
+  if (state == atos) { MacroAssembler::_verify_oop(reg, "broken oop", file, line); }
+}
+
+// Inline assembly for:
+//
+// if (thread is in interp_only_mode) {
+//   InterpreterRuntime::post_method_entry();
+// }
+// if (DTraceMethodProbes) {
+//   SharedRuntime::dtrace_method_entry(method, receiver);
+// }
+// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+//   SharedRuntime::rc_trace_method_entry(method, receiver);
+// }
+
+void InterpreterMacroAssembler::notify_method_entry() {
+  // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to
+  // track stack depth.  If it is possible to enter interp_only_mode we add
+  // the code to check if the event should be sent.
+  if (can_post_interpreter_events()) {
+    Label L;
+
+    ldr_s32(Rtemp, Address(Rthread, JavaThread::interp_only_mode_offset()));
+    cbz(Rtemp, L);
+
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry));
+
+    bind(L);
+  }
+
+  // Note: Disable DTrace runtime check for now to eliminate overhead on each method entry
+  if (DTraceMethodProbes) {
+    Label Lcontinue;
+
+    ldrb_global(Rtemp, (address)&DTraceMethodProbes);
+    cbz(Rtemp, Lcontinue);
+
+    mov(R0, Rthread);
+    mov(R1, Rmethod);
+    call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), R0, R1);
+
+    bind(Lcontinue);
+  }
+  // RedefineClasses() tracing support for obsolete method entry
+  if (log_is_enabled(Trace, redefine, class, obsolete)) {
+    mov(R0, Rthread);
+    mov(R1, Rmethod);
+    call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+                 R0, R1);
+  }
+}
+
+
+void InterpreterMacroAssembler::notify_method_exit(
+                 TosState state, NotifyMethodExitMode mode,
+                 bool native, Register result_lo, Register result_hi, FloatRegister result_fp) {
+  // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to
+  // track stack depth.  If it is possible to enter interp_only_mode we add
+  // the code to check if the event should be sent.
+  if (mode == NotifyJVMTI && can_post_interpreter_events()) {
+    Label L;
+    // Note: frame::interpreter_frame_result has a dependency on how the
+    // method result is saved across the call to post_method_exit. If this
+    // is changed then the interpreter_frame_result implementation will
+    // need to be updated too.
+
+    ldr_s32(Rtemp, Address(Rthread, JavaThread::interp_only_mode_offset()));
+    cbz(Rtemp, L);
+
+    if (native) {
+      // For c++ and template interpreter push both result registers on the
+      // stack in native, we don't know the state.
+      // On AArch64 result registers are stored into the frame at known locations.
+      // See frame::interpreter_frame_result for code that gets the result values from here.
+      assert(result_lo != noreg, "result registers should be defined");
+
+#ifdef AARCH64
+      assert(result_hi == noreg, "result_hi is not used on AArch64");
+      assert(result_fp != fnoreg, "FP result register must be defined");
+
+      str_d(result_fp, Address(FP, frame::interpreter_frame_fp_saved_result_offset * wordSize));
+      str(result_lo, Address(FP, frame::interpreter_frame_gp_saved_result_offset * wordSize));
+#else
+      assert(result_hi != noreg, "result registers should be defined");
+
+#ifdef __ABI_HARD__
+      assert(result_fp != fnoreg, "FP result register must be defined");
+      sub(SP, SP, 2 * wordSize);
+      fstd(result_fp, Address(SP));
+#endif // __ABI_HARD__
+
+      push(RegisterSet(result_lo) | RegisterSet(result_hi));
+#endif // AARCH64
+
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit));
+
+#ifdef AARCH64
+      ldr_d(result_fp, Address(FP, frame::interpreter_frame_fp_saved_result_offset * wordSize));
+      ldr(result_lo, Address(FP, frame::interpreter_frame_gp_saved_result_offset * wordSize));
+#else
+      pop(RegisterSet(result_lo) | RegisterSet(result_hi));
+#ifdef __ABI_HARD__
+      fldd(result_fp, Address(SP));
+      add(SP, SP, 2 * wordSize);
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+    } else {
+      // For the template interpreter, the value on tos is the size of the
+      // state. (c++ interpreter calls jvmti somewhere else).
+      push(state);
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit));
+      pop(state);
+    }
+
+    bind(L);
+  }
+
+  // Note: Disable DTrace runtime check for now to eliminate overhead on each method exit
+  if (DTraceMethodProbes) {
+    Label Lcontinue;
+
+    ldrb_global(Rtemp, (address)&DTraceMethodProbes);
+    cbz(Rtemp, Lcontinue);
+
+    push(state);
+
+    mov(R0, Rthread);
+    mov(R1, Rmethod);
+
+    call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), R0, R1);
+
+    pop(state);
+
+    bind(Lcontinue);
+  }
+}
+
+
+#ifndef PRODUCT
+
+void InterpreterMacroAssembler::trace_state(const char* msg) {
+  int push_size = save_caller_save_registers();
+
+  Label Lcontinue;
+  InlinedString Lmsg0("%s: FP=" INTPTR_FORMAT ", SP=" INTPTR_FORMAT "\n");
+  InlinedString Lmsg(msg);
+  InlinedAddress Lprintf((address)printf);
+
+  ldr_literal(R0, Lmsg0);
+  ldr_literal(R1, Lmsg);
+  mov(R2, FP);
+  add(R3, SP, push_size);  // original SP (without saved registers)
+  ldr_literal(Rtemp, Lprintf);
+  call(Rtemp);
+
+  b(Lcontinue);
+
+  bind_literal(Lmsg0);
+  bind_literal(Lmsg);
+  bind_literal(Lprintf);
+
+
+  bind(Lcontinue);
+
+  restore_caller_save_registers();
+}
+
+#endif
+
+// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
+void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
+                                                        int increment, Address mask_addr,
+                                                        Register scratch, Register scratch2,
+                                                        AsmCondition cond, Label* where) {
+  // caution: scratch2 and base address of counter_addr can be the same
+  assert_different_registers(scratch, scratch2);
+  ldr_u32(scratch, counter_addr);
+  add(scratch, scratch, increment);
+  str_32(scratch, counter_addr);
+
+#ifdef AARCH64
+  ldr_u32(scratch2, mask_addr);
+  ands_w(ZR, scratch, scratch2);
+#else
+  ldr(scratch2, mask_addr);
+  andrs(scratch, scratch, scratch2);
+#endif // AARCH64
+  b(*where, cond);
+}
+
+void InterpreterMacroAssembler::get_method_counters(Register method,
+                                                    Register Rcounters,
+                                                    Label& skip) {
+  const Address method_counters(method, Method::method_counters_offset());
+  Label has_counters;
+
+  ldr(Rcounters, method_counters);
+  cbnz(Rcounters, has_counters);
+
+#ifdef AARCH64
+  const Register tmp = Rcounters;
+  const int saved_regs_size = 20*wordSize;
+
+  // Note: call_VM will cut SP according to Rstack_top value before call, and restore SP to
+  // extended_sp value from frame after the call.
+  // So make sure there is enough stack space to save registers and adjust Rstack_top accordingly.
+  {
+    Label enough_stack_space;
+    check_extended_sp(tmp);
+    sub(Rstack_top, Rstack_top, saved_regs_size);
+    cmp(SP, Rstack_top);
+    b(enough_stack_space, ls);
+
+    align_reg(tmp, Rstack_top, StackAlignmentInBytes);
+    mov(SP, tmp);
+    str(tmp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
+
+    bind(enough_stack_space);
+    check_stack_top();
+
+    int offset = 0;
+    stp(R0,  R1,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R2,  R3,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R4,  R5,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R6,  R7,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R8,  R9,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
+    stp(R18, LR,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    assert (offset == saved_regs_size, "should be");
+  }
+#else
+  push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
+#endif // AARCH64
+
+  mov(R1, method);
+  call_VM(noreg, CAST_FROM_FN_PTR(address,
+          InterpreterRuntime::build_method_counters), R1);
+
+#ifdef AARCH64
+  {
+    int offset = 0;
+    ldp(R0,  R1,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R2,  R3,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R4,  R5,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R6,  R7,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R8,  R9,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
+    ldp(R18, LR,  Address(Rstack_top, offset)); offset += 2*wordSize;
+    assert (offset == saved_regs_size, "should be");
+
+    add(Rstack_top, Rstack_top, saved_regs_size);
+  }
+#else
+  pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
+#endif // AARCH64
+
+  ldr(Rcounters, method_counters);
+  cbz(Rcounters, skip); // No MethodCounters created, OutOfMemory
+
+  bind(has_counters);
+}
diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp
new file mode 100644
index 0000000..5c75375
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_INTERP_MASM_ARM_HPP
+#define CPU_ARM_VM_INTERP_MASM_ARM_HPP
+
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "interpreter/invocationCounter.hpp"
+#include "runtime/frame.hpp"
+#include "prims/jvmtiExport.hpp"
+
+// This file specializes the assember with interpreter-specific macros
+
+
+class InterpreterMacroAssembler: public MacroAssembler {
+
+ public:
+
+  // allow JvmtiExport checks to be extended
+  bool can_force_early_return()       { return JvmtiExport::can_force_early_return(); }
+  bool can_post_interpreter_events()  { return JvmtiExport::can_post_interpreter_events(); }
+  bool can_pop_frame()                { return JvmtiExport::can_pop_frame(); }
+  bool can_post_breakpoint()          { return JvmtiExport::can_post_breakpoint(); }
+  bool can_post_field_access()        { return JvmtiExport::can_post_field_access(); }
+  bool can_post_field_modification()  { return JvmtiExport::can_post_field_modification(); }
+  // flags controlled by JVMTI settings
+  bool rewrite_frequent_pairs()       { return RewriteFrequentPairs; }
+
+ protected:
+
+  // Template interpreter specific version of call_VM_helper
+  virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
+
+  virtual void check_and_handle_popframe();
+  virtual void check_and_handle_earlyret();
+
+  // base routine for all dispatches
+  typedef enum { DispatchDefault, DispatchNormal } DispatchTableMode;
+  void dispatch_base(TosState state, DispatchTableMode table_mode, bool verifyoop = true);
+
+ public:
+  InterpreterMacroAssembler(CodeBuffer* code);
+
+  // Interpreter-specific registers
+#if defined(AARCH64) && defined(ASSERT)
+
+#define check_stack_top()               _check_stack_top("invalid Rstack_top at " __FILE__ ":" XSTR(__LINE__))
+#define check_stack_top_on_expansion()  _check_stack_top("invalid Rstack_top at " __FILE__ ":" XSTR(__LINE__), VerifyInterpreterStackTop)
+#define check_extended_sp(tmp)          _check_extended_sp(tmp, "SP does not match extended SP in frame at " __FILE__ ":" XSTR(__LINE__))
+#define check_no_cached_stack_top(tmp)  _check_no_cached_stack_top(tmp, "stack_top is already cached in frame at " __FILE__ ":" XSTR(__LINE__))
+
+  void _check_stack_top(const char* msg, bool enabled = true) {
+      if (enabled) {
+          Label L;
+          cmp(SP, Rstack_top);
+          b(L, ls);
+          stop(msg);
+          bind(L);
+      }
+  }
+
+  void _check_extended_sp(Register tmp, const char* msg) {
+      Label L;
+      ldr(tmp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
+      cmp(SP, tmp);
+      b(L, eq);
+      stop(msg);
+      bind(L);
+  }
+
+  void _check_no_cached_stack_top(Register tmp, const char* msg) {
+      Label L;
+      ldr(tmp, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize));
+      cbz(tmp, L);
+      stop(msg);
+      bind(L);
+  }
+
+#else
+
+  inline void check_stack_top() {}
+  inline void check_stack_top_on_expansion() {}
+  inline void check_extended_sp(Register tmp) {}
+  inline void check_no_cached_stack_top(Register tmp) {}
+
+#endif // AARCH64 && ASSERT
+
+  void save_bcp()                                          { str(Rbcp, Address(FP, frame::interpreter_frame_bcp_offset * wordSize)); }
+  void restore_bcp()                                       { ldr(Rbcp, Address(FP, frame::interpreter_frame_bcp_offset * wordSize)); }
+  void restore_locals()                                    { ldr(Rlocals, Address(FP, frame::interpreter_frame_locals_offset * wordSize)); }
+  void restore_method()                                    { ldr(Rmethod, Address(FP, frame::interpreter_frame_method_offset * wordSize)); }
+  void restore_dispatch();
+
+#ifdef AARCH64
+  void save_stack_top()                                    { check_stack_top(); str(Rstack_top, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize)); }
+  void clear_cached_stack_top()                            { str(ZR, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize)); }
+  void restore_stack_top()                                 { ldr(Rstack_top, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize)); clear_cached_stack_top(); check_stack_top(); }
+  void cut_sp_before_call()                                { align_reg(SP, Rstack_top, StackAlignmentInBytes); }
+  void restore_sp_after_call(Register tmp)                 { ldr(tmp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize)); mov(SP, tmp); }
+#endif
+
+  // Helpers for runtime call arguments/results
+  void get_const(Register reg)                             { ldr(reg, Address(Rmethod, Method::const_offset())); }
+  void get_constant_pool(Register reg)                     { get_const(reg); ldr(reg, Address(reg, ConstMethod::constants_offset())); }
+  void get_constant_pool_cache(Register reg)               { get_constant_pool(reg); ldr(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); }
+  void get_cpool_and_tags(Register cpool, Register tags)   { get_constant_pool(cpool); ldr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); }
+
+  // Sets reg. Blows Rtemp.
+  void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset);
+
+  // Sets index. Blows reg_tmp.
+  void get_index_at_bcp(Register index, int bcp_offset, Register reg_tmp, size_t index_size = sizeof(u2));
+  // Sets cache, index.
+  void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size = sizeof(u2));
+  void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
+  // Sets cache. Blows reg_tmp.
+  void get_cache_entry_pointer_at_bcp(Register cache, Register reg_tmp, int bcp_offset, size_t index_size = sizeof(u2));
+
+  // Load object from cpool->resolved_references(*bcp+1)
+  void load_resolved_reference_at_index(Register result, Register tmp);
+
+  void store_check_part1(Register card_table_base);                // Sets card_table_base register.
+  void store_check_part2(Register obj, Register card_table_base, Register tmp);
+
+  void set_card(Register card_table_base, Address card_table_addr, Register tmp);
+
+#if INCLUDE_ALL_GCS
+  // G1 pre-barrier.
+  // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+  // If store_addr != noreg, then previous value is loaded from [store_addr];
+  // in such case store_addr and new_val registers are preserved;
+  // otherwise pre_val register is preserved.
+  void g1_write_barrier_pre(Register store_addr,
+                            Register new_val,
+                            Register pre_val,
+                            Register tmp1,
+                            Register tmp2);
+
+  // G1 post-barrier.
+  // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+  void g1_write_barrier_post(Register store_addr,
+                             Register new_val,
+                             Register tmp1,
+                             Register tmp2,
+                             Register tmp3);
+#endif // INCLUDE_ALL_GCS
+
+  void pop_ptr(Register r);
+  void pop_i(Register r = R0_tos);
+#ifdef AARCH64
+  void pop_l(Register r = R0_tos);
+#else
+  void pop_l(Register lo = R0_tos_lo, Register hi = R1_tos_hi);
+#endif
+  void pop_f(FloatRegister fd);
+  void pop_d(FloatRegister fd);
+
+  void push_ptr(Register r);
+  void push_i(Register r = R0_tos);
+#ifdef AARCH64
+  void push_l(Register r = R0_tos);
+#else
+  void push_l(Register lo = R0_tos_lo, Register hi = R1_tos_hi);
+#endif
+  void push_f();
+  void push_d();
+
+  // Transition vtos -> state. Blows R0, R1. Sets TOS cached value.
+  void pop(TosState state);
+  // Transition state -> vtos. Blows Rtemp.
+  void push(TosState state);
+
+#ifndef AARCH64
+  // The following methods are overridden to allow overloaded calls to
+  //   MacroAssembler::push/pop(Register)
+  //   MacroAssembler::push/pop(RegisterSet)
+  //   InterpreterMacroAssembler::push/pop(TosState)
+  void push(Register rd, AsmCondition cond = al)         { MacroAssembler::push(rd, cond);      }
+  void pop(Register rd, AsmCondition cond = al)          { MacroAssembler::pop(rd, cond);       }
+
+  void push(RegisterSet reg_set, AsmCondition cond = al) { MacroAssembler::push(reg_set, cond); }
+  void pop(RegisterSet reg_set, AsmCondition cond = al)  { MacroAssembler::pop(reg_set, cond);  }
+
+  // Converts return value in R0/R1 (interpreter calling conventions) to TOS cached value.
+  void convert_retval_to_tos(TosState state);
+  // Converts TOS cached value to return value in R0/R1 (according to interpreter calling conventions).
+  void convert_tos_to_retval(TosState state);
+#endif
+
+  // JVMTI ForceEarlyReturn support
+  void load_earlyret_value(TosState state);
+
+  void jump_to_entry(address entry);
+
+  // Blows Rtemp.
+  void empty_expression_stack() {
+      ldr(Rstack_top, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+      check_stack_top();
+#ifdef AARCH64
+      clear_cached_stack_top();
+#else
+      // NULL last_sp until next java call
+      str(zero_register(Rtemp), Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+  }
+
+  // Helpers for swap and dup
+  void load_ptr(int n, Register val);
+  void store_ptr(int n, Register val);
+
+  // Generate a subtype check: branch to not_subtype if sub_klass is
+  // not a subtype of super_klass.
+  // Profiling code for the subtype check failure (profile_typecheck_failed)
+  // should be explicitly generated by the caller in the not_subtype case.
+  // Blows Rtemp, tmp1, tmp2.
+  void gen_subtype_check(Register Rsub_klass, Register Rsuper_klass,
+                         Label &not_subtype, Register tmp1, Register tmp2);
+
+  // Dispatching
+  void dispatch_prolog(TosState state, int step = 0);
+  void dispatch_epilog(TosState state, int step = 0);
+  void dispatch_only(TosState state);                      // dispatch by R3_bytecode
+  void dispatch_only_normal(TosState state);               // dispatch normal table by R3_bytecode
+  void dispatch_only_noverify(TosState state);
+  void dispatch_next(TosState state, int step = 0);        // load R3_bytecode from [Rbcp + step] and dispatch by R3_bytecode
+
+  // jump to an invoked target
+  void prepare_to_jump_from_interpreted();
+  void jump_from_interpreted(Register method);
+
+  void narrow(Register result);
+
+  // Returning from interpreted functions
+  //
+  // Removes the current activation (incl. unlocking of monitors)
+  // and sets up the return address.  This code is also used for
+  // exception unwindwing. In that case, we do not want to throw
+  // IllegalMonitorStateExceptions, since that might get us into an
+  // infinite rethrow exception loop.
+  // Additionally this code is used for popFrame and earlyReturn.
+  // In popFrame case we want to skip throwing an exception,
+  // installing an exception, and notifying jvmdi.
+  // In earlyReturn case we only want to skip throwing an exception
+  // and installing an exception.
+  void remove_activation(TosState state, Register ret_addr,
+                         bool throw_monitor_exception = true,
+                         bool install_monitor_exception = true,
+                         bool notify_jvmdi = true);
+
+  // At certain points in the method invocation the monitor of
+  // synchronized methods hasn't been entered yet.
+  // To correctly handle exceptions at these points, we set the thread local
+  // variable _do_not_unlock_if_synchronized to true. The remove_activation will
+  // check this flag.
+  void set_do_not_unlock_if_synchronized(bool flag, Register tmp);
+
+  // Debugging
+  void interp_verify_oop(Register reg, TosState state, const char* file, int line);    // only if +VerifyOops && state == atos
+
+  void verify_FPU(int stack_depth, TosState state = ftos) {
+    // No VFP state verification is required for ARM
+  }
+
+  // Object locking
+  void lock_object  (Register lock_reg);
+  void unlock_object(Register lock_reg);
+
+  // Interpreter profiling operations
+  void set_method_data_pointer_for_bcp(); // Blows R0-R3/R0-R18, Rtemp, LR
+  void test_method_data_pointer(Register mdp, Label& zero_continue);
+  void verify_method_data_pointer();
+
+  void set_mdp_data_at(Register mdp_in, int offset, Register value);
+
+  // Increments mdp data. Sets bumped_count register to adjusted counter.
+  void increment_mdp_data_at(Address data, Register bumped_count, bool decrement = false);
+  // Increments mdp data. Sets bumped_count register to adjusted counter.
+  void increment_mdp_data_at(Register mdp_in, int offset, Register bumped_count, bool decrement = false);
+  void increment_mask_and_jump(Address counter_addr,
+                               int increment, Address mask_addr,
+                               Register scratch, Register scratch2,
+                               AsmCondition cond, Label* where);
+  void set_mdp_flag_at(Register mdp_in, int flag_constant);
+
+  void test_mdp_data_at(Register mdp_in, int offset, Register value,
+                        Register test_value_out,
+                        Label& not_equal_continue);
+
+  void record_klass_in_profile(Register receiver, Register mdp,
+                               Register reg_tmp, bool is_virtual_call);
+  void record_klass_in_profile_helper(Register receiver, Register mdp,
+                                      Register reg_tmp,
+                                      int start_row, Label& done, bool is_virtual_call);
+
+  void update_mdp_by_offset(Register mdp_in, int offset_of_offset, Register reg_tmp);
+  void update_mdp_by_offset(Register mdp_in, Register reg_offset, Register reg_tmp);
+  void update_mdp_by_constant(Register mdp_in, int constant);
+  void update_mdp_for_ret(Register return_bci);                   // Blows R0-R3/R0-R18, Rtemp, LR
+
+  void profile_taken_branch(Register mdp, Register bumped_count); // Sets mdp, bumped_count registers, blows Rtemp.
+  void profile_not_taken_branch(Register mdp);                    // Sets mdp, blows Rtemp.
+
+  void profile_call(Register mdp);                                // Sets mdp, blows Rtemp.
+  void profile_final_call(Register mdp);                          // Sets mdp, blows Rtemp.
+  void profile_virtual_call(Register mdp, Register receiver,      // Sets mdp, blows Rtemp.
+                            bool receiver_can_be_null = false);
+  void profile_ret(Register mdp, Register return_bci);            // Sets mdp, blows R0-R3/R0-R18, Rtemp, LR
+  void profile_null_seen(Register mdp);                           // Sets mdp.
+  void profile_typecheck(Register mdp, Register klass);           // Sets mdp, blows Rtemp.
+
+  void profile_typecheck_failed(Register mdp);                    // Sets mdp, blows Rtemp.
+  void profile_switch_default(Register mdp);                      // Sets mdp, blows Rtemp.
+
+  // Sets mdp. Blows reg_tmp1, reg_tmp2. Index could be the same as reg_tmp2.
+  void profile_switch_case(Register mdp, Register index, Register reg_tmp1, Register reg_tmp2);
+
+  void byteswap_u32(Register r, Register rtmp1, Register rtmp2);
+
+  void inc_global_counter(address address_of_counter, int offset_in_bytes, Register tmp1, Register tmp2, bool avoid_overflow);
+
+  typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode;
+
+  // support for jvmti
+  void notify_method_entry();
+  void notify_method_exit(TosState state, NotifyMethodExitMode mode,
+                          bool native = false, Register result_lo = noreg, Register result_hi = noreg, FloatRegister result_fp = fnoreg);
+
+  void trace_state(const char* msg) PRODUCT_RETURN;
+
+  void get_method_counters(Register method, Register Rcounters, Label& skip);
+};
+
+#endif // CPU_ARM_VM_INTERP_MASM_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/interpreterRT_arm.cpp b/hotspot/src/cpu/arm/vm/interpreterRT_arm.cpp
new file mode 100644
index 0000000..4925f63
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/interpreterRT_arm.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/universe.inline.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/signature.hpp"
+
+#define __ _masm->
+
+#ifdef SHARING_FAST_NATIVE_FINGERPRINTS
+// mapping from SignatureIterator param to (common) type of parsing
+static const u1 shared_type[] = {
+  (u1) SignatureIterator::int_parm, // bool
+  (u1) SignatureIterator::int_parm, // byte
+  (u1) SignatureIterator::int_parm, // char
+  (u1) SignatureIterator::int_parm, // short
+  (u1) SignatureIterator::int_parm, // int
+  (u1) SignatureIterator::long_parm, // long
+#ifndef __ABI_HARD__
+  (u1) SignatureIterator::int_parm, // float, passed as int
+  (u1) SignatureIterator::long_parm, // double, passed as long
+#else
+  (u1) SignatureIterator::float_parm, // float
+  (u1) SignatureIterator::double_parm, // double
+#endif
+  (u1) SignatureIterator::obj_parm, // obj
+  (u1) SignatureIterator::done_parm // done
+};
+
+uint64_t InterpreterRuntime::normalize_fast_native_fingerprint(uint64_t fingerprint) {
+  if (fingerprint == UCONST64(-1)) {
+    // special signature used when the argument list cannot be encoded in a 64 bits value
+    return fingerprint;
+  }
+  int shift = SignatureIterator::static_feature_size;
+  uint64_t result = fingerprint & ((1 << shift) - 1);
+  fingerprint >>= shift;
+
+  BasicType ret_type = (BasicType) (fingerprint & SignatureIterator::result_feature_mask);
+  // For ARM, the fast signature handler only needs to know whether
+  // the return value must be unboxed. T_OBJECT and T_ARRAY need not
+  // be distinguished from each other and all other return values
+  // behave like integers with respect to the handler.
+  bool unbox = (ret_type == T_OBJECT) || (ret_type == T_ARRAY);
+  if (unbox) {
+    ret_type = T_OBJECT;
+  } else {
+    ret_type = T_INT;
+  }
+  result |= ((uint64_t) ret_type) << shift;
+  shift += SignatureIterator::result_feature_size;
+  fingerprint >>= SignatureIterator::result_feature_size;
+
+  while (true) {
+    uint32_t type = (uint32_t) (fingerprint & SignatureIterator::parameter_feature_mask);
+    if (type == SignatureIterator::done_parm) {
+      result |= ((uint64_t) SignatureIterator::done_parm) << shift;
+      return result;
+    }
+    assert((type >= SignatureIterator::bool_parm) && (type <= SignatureIterator::obj_parm), "check fingerprint encoding");
+    int shared = shared_type[type - SignatureIterator::bool_parm];
+    result |= ((uint64_t) shared) << shift;
+    shift += SignatureIterator::parameter_feature_size;
+    fingerprint >>= SignatureIterator::parameter_feature_size;
+  }
+}
+#endif // SHARING_FAST_NATIVE_FINGERPRINTS
+
+// Implementation of SignatureHandlerGenerator
+void InterpreterRuntime::SignatureHandlerGenerator::pass_int() {
+  if (_ireg < GPR_PARAMS) {
+    Register dst = as_Register(_ireg);
+    __ ldr_s32(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    _ireg++;
+  } else {
+    __ ldr_s32(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ str_32(Rtemp, Address(SP, _abi_offset * wordSize));
+    _abi_offset++;
+  }
+}
+
+void InterpreterRuntime::SignatureHandlerGenerator::pass_long() {
+#ifdef AARCH64
+  if (_ireg < GPR_PARAMS) {
+    Register dst = as_Register(_ireg);
+    __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1)));
+    _ireg++;
+  } else {
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1)));
+    __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+    _abi_offset++;
+  }
+#else
+  if (_ireg <= 2) {
+#if (ALIGN_WIDE_ARGUMENTS == 1)
+    if ((_ireg & 1) != 0) {
+      // 64-bit values should be 8-byte aligned
+      _ireg++;
+    }
+#endif
+    Register dst1 = as_Register(_ireg);
+    Register dst2 = as_Register(_ireg+1);
+    __ ldr(dst1, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1)));
+    __ ldr(dst2, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    _ireg += 2;
+#if (ALIGN_WIDE_ARGUMENTS == 0)
+  } else if (_ireg == 3) {
+    // uses R3 + one stack slot
+    Register dst1 = as_Register(_ireg);
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ ldr(dst1, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1)));
+    __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+    _ireg += 1;
+    _abi_offset += 1;
+#endif
+  } else {
+#if (ALIGN_WIDE_ARGUMENTS == 1)
+    if(_abi_offset & 1) _abi_offset++;
+#endif
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1)));
+    __ str(Rtemp, Address(SP, (_abi_offset) * wordSize));
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ str(Rtemp, Address(SP, (_abi_offset+1) * wordSize));
+    _abi_offset += 2;
+    _ireg = 4;
+  }
+#endif // AARCH64
+}
+
+void InterpreterRuntime::SignatureHandlerGenerator::pass_object() {
+#ifdef AARCH64
+  __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+  __ cmp(Rtemp, 0);
+  __ sub(Rtemp, Rlocals, -Interpreter::local_offset_in_bytes(offset()));
+  if (_ireg < GPR_PARAMS) {
+    Register dst = as_Register(_ireg);
+    __ csel(dst, ZR, Rtemp, eq);
+    _ireg++;
+  } else {
+    __ csel(Rtemp, ZR, Rtemp, eq);
+    __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+    _abi_offset++;
+  }
+#else
+  if (_ireg < 4) {
+    Register dst = as_Register(_ireg);
+    __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ cmp(dst, 0);
+    __ sub(dst, Rlocals, -Interpreter::local_offset_in_bytes(offset()), ne);
+    _ireg++;
+  } else {
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ cmp(Rtemp, 0);
+    __ sub(Rtemp, Rlocals, -Interpreter::local_offset_in_bytes(offset()), ne);
+    __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+    _abi_offset++;
+  }
+#endif // AARCH64
+}
+
+#ifndef __ABI_HARD__
+void InterpreterRuntime::SignatureHandlerGenerator::pass_float() {
+  if (_ireg < 4) {
+    Register dst = as_Register(_ireg);
+    __ ldr(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    _ireg++;
+  } else {
+    __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+    __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+    _abi_offset++;
+  }
+}
+
+#else
+#ifndef __SOFTFP__
+void InterpreterRuntime::SignatureHandlerGenerator::pass_float() {
+#ifdef AARCH64
+    if (_freg < FPR_PARAMS) {
+      FloatRegister dst = as_FloatRegister(_freg);
+      __ ldr_s(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+      _freg++;
+    } else {
+      __ ldr_u32(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+      __ str_32(Rtemp, Address(SP, _abi_offset * wordSize));
+      _abi_offset++;
+    }
+#else
+    if((_fp_slot < 16) || (_single_fpr_slot & 1)) {
+      if ((_single_fpr_slot & 1) == 0) {
+        _single_fpr_slot = _fp_slot;
+        _fp_slot += 2;
+      }
+      __ flds(as_FloatRegister(_single_fpr_slot), Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+      _single_fpr_slot++;
+    } else {
+      __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+      __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+      _abi_offset++;
+    }
+#endif // AARCH64
+}
+
+void InterpreterRuntime::SignatureHandlerGenerator::pass_double() {
+#ifdef AARCH64
+    if (_freg < FPR_PARAMS) {
+      FloatRegister dst = as_FloatRegister(_freg);
+      __ ldr_d(dst, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1)));
+      _freg++;
+    } else {
+      __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset() + 1)));
+      __ str(Rtemp, Address(SP, _abi_offset * wordSize));
+      _abi_offset++;
+    }
+#else
+    if(_fp_slot <= 14) {
+      __ fldd(as_FloatRegister(_fp_slot), Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1)));
+      _fp_slot += 2;
+    } else {
+      __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset()+1)));
+      __ str(Rtemp, Address(SP, (_abi_offset) * wordSize));
+      __ ldr(Rtemp, Address(Rlocals, Interpreter::local_offset_in_bytes(offset())));
+      __ str(Rtemp, Address(SP, (_abi_offset+1) * wordSize));
+      _abi_offset += 2;
+      _single_fpr_slot = 16;
+    }
+#endif // AARCH64
+}
+#endif // __SOFTFP__
+#endif // __ABI_HARD__
+
+void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
+  iterate(fingerprint);
+
+  BasicType result_type = SignatureIterator::return_type(fingerprint);
+
+  address result_handler = Interpreter::result_handler(result_type);
+
+#ifdef AARCH64
+  __ mov_slow(R0, (address)result_handler);
+#else
+  // Check that result handlers are not real handler on ARM (0 or -1).
+  // This ensures the signature handlers do not need symbolic information.
+  assert((result_handler == NULL)||(result_handler==(address)0xffffffff),"");
+  __ mov_slow(R0, (intptr_t)result_handler);
+#endif
+
+  __ ret();
+}
+
+
+// Implementation of SignatureHandlerLibrary
+
+void SignatureHandlerLibrary::pd_set_handler(address handler) {}
+
+class SlowSignatureHandler: public NativeSignatureIterator {
+ private:
+  address   _from;
+  intptr_t* _to;
+
+#ifndef __ABI_HARD__
+  virtual void pass_int() {
+    *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    _from -= Interpreter::stackElementSize;
+  }
+
+  virtual void pass_float() {
+    *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    _from -= Interpreter::stackElementSize;
+  }
+
+  virtual void pass_long() {
+#if (ALIGN_WIDE_ARGUMENTS == 1)
+    if (((intptr_t)_to & 7) != 0) {
+      // 64-bit values should be 8-byte aligned
+      _to++;
+    }
+#endif
+    _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+    _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0));
+    _to += 2;
+    _from -= 2*Interpreter::stackElementSize;
+  }
+
+  virtual void pass_object() {
+    intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0));
+    *_to++ = (*(intptr_t*)from_addr == 0) ? (intptr_t)NULL : from_addr;
+    _from -= Interpreter::stackElementSize;
+   }
+
+#else
+
+  intptr_t* _toFP;
+  intptr_t* _toGP;
+  int       _last_gp;
+  int       _last_fp;
+#ifndef AARCH64
+  int       _last_single_fp;
+#endif // !AARCH64
+
+  virtual void pass_int() {
+    if(_last_gp < GPR_PARAMS) {
+      _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    } else {
+      *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    }
+    _from -= Interpreter::stackElementSize;
+  }
+
+  virtual void pass_long() {
+#ifdef AARCH64
+    if(_last_gp < GPR_PARAMS) {
+      _toGP[_last_gp++] = *(jlong *)(_from+Interpreter::local_offset_in_bytes(1));
+    } else {
+      *_to++ = *(jlong *)(_from+Interpreter::local_offset_in_bytes(1));
+    }
+#else
+    assert(ALIGN_WIDE_ARGUMENTS == 1, "ABI_HARD not supported with unaligned wide arguments");
+    if (_last_gp <= 2) {
+      if(_last_gp & 1) _last_gp++;
+      _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(1));
+      _toGP[_last_gp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    } else {
+      if (((intptr_t)_to & 7) != 0) {
+        // 64-bit values should be 8-byte aligned
+        _to++;
+      }
+      _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+      _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0));
+      _to += 2;
+      _last_gp = 4;
+    }
+#endif // AARCH64
+    _from -= 2*Interpreter::stackElementSize;
+  }
+
+  virtual void pass_object() {
+    intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0));
+    if(_last_gp < GPR_PARAMS) {
+      _toGP[_last_gp++] = (*(intptr_t*)from_addr == 0) ? NULL : from_addr;
+    } else {
+      *_to++ = (*(intptr_t*)from_addr == 0) ? NULL : from_addr;
+    }
+    _from -= Interpreter::stackElementSize;
+  }
+
+  virtual void pass_float() {
+#ifdef AARCH64
+    if(_last_fp < FPR_PARAMS) {
+      _toFP[_last_fp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    } else {
+      *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    }
+#else
+    if((_last_fp < 16) || (_last_single_fp & 1)) {
+      if ((_last_single_fp & 1) == 0) {
+        _last_single_fp = _last_fp;
+        _last_fp += 2;
+      }
+
+      _toFP[_last_single_fp++] = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    } else {
+      *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
+    }
+#endif // AARCH64
+    _from -= Interpreter::stackElementSize;
+  }
+
+  virtual void pass_double() {
+#ifdef AARCH64
+    if(_last_fp < FPR_PARAMS) {
+      _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+    } else {
+      *_to++ = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+    }
+#else
+    assert(ALIGN_WIDE_ARGUMENTS == 1, "ABI_HARD not supported with unaligned wide arguments");
+    if(_last_fp <= 14) {
+      _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+      _toFP[_last_fp++] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0));
+    } else {
+      if (((intptr_t)_to & 7) != 0) {      // 64-bit values should be 8-byte aligned
+        _to++;
+      }
+      _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
+      _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0));
+      _to += 2;
+      _last_single_fp = 16;
+    }
+#endif // AARCH64
+    _from -= 2*Interpreter::stackElementSize;
+  }
+
+#endif // !__ABI_HARD__
+
+ public:
+  SlowSignatureHandler(methodHandle method, address from, intptr_t* to) :
+    NativeSignatureIterator(method) {
+    _from = from;
+
+#ifdef __ABI_HARD__
+    _toGP  = to;
+    _toFP = _toGP + GPR_PARAMS;
+    _to   = _toFP + AARCH64_ONLY(FPR_PARAMS) NOT_AARCH64(8*2);
+    _last_gp = (is_static() ? 2 : 1);
+    _last_fp = 0;
+#ifndef AARCH64
+    _last_single_fp = 0;
+#endif // !AARCH64
+#else
+    _to   = to + (is_static() ? 2 : 1);
+#endif // __ABI_HARD__
+  }
+};
+
+IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to))
+  methodHandle m(thread, (Method*)method);
+  assert(m->is_native(), "sanity check");
+  SlowSignatureHandler(m, (address)from, to).iterate(UCONST64(-1));
+  return Interpreter::result_handler(m->result_type());
+IRT_END
diff --git a/hotspot/src/cpu/arm/vm/interpreterRT_arm.hpp b/hotspot/src/cpu/arm/vm/interpreterRT_arm.hpp
new file mode 100644
index 0000000..fa1e0dc
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/interpreterRT_arm.hpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_INTERPRETERRT_ARM_HPP
+#define CPU_ARM_VM_INTERPRETERRT_ARM_HPP
+
+#include "memory/allocation.hpp"
+
+// native method calls
+
+class SignatureHandlerGenerator: public NativeSignatureIterator {
+ private:
+  MacroAssembler* _masm;
+  int _abi_offset;
+  int  _ireg;
+
+#ifdef __ABI_HARD__
+#ifdef AARCH64
+  int _freg;
+#else
+  int _fp_slot; // number of FPR's with arguments loaded
+  int _single_fpr_slot;
+#endif
+#endif
+
+  void move(int from_offset, int to_offset);
+  void box(int from_offset, int to_offset);
+
+  void pass_int();
+  void pass_long();
+  void pass_float();
+  void pass_object();
+#ifdef __ABI_HARD__
+  void pass_double();
+#endif
+ public:
+  // Creation
+  SignatureHandlerGenerator(methodHandle method, CodeBuffer* buffer) : NativeSignatureIterator(method) {
+    _masm = new MacroAssembler(buffer);
+    _abi_offset = 0;
+    _ireg = is_static() ? 2 : 1;
+#ifdef __ABI_HARD__
+#ifdef AARCH64
+    _freg = 0;
+#else
+    _fp_slot = 0;
+    _single_fpr_slot = 0;
+#endif
+#endif
+  }
+
+  // Code generation
+  void generate(uint64_t fingerprint);
+
+};
+
+#ifndef AARCH64
+// ARM provides a normalized fingerprint for native calls (to increase
+// sharing). See normalize_fast_native_fingerprint
+#define SHARING_FAST_NATIVE_FINGERPRINTS
+#endif
+
+#endif // CPU_ARM_VM_INTERPRETERRT_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/javaFrameAnchor_arm.hpp b/hotspot/src/cpu/arm/vm/javaFrameAnchor_arm.hpp
new file mode 100644
index 0000000..b8ac0b1
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/javaFrameAnchor_arm.hpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_JAVAFRAMEANCHOR_ARM_HPP
+#define CPU_ARM_VM_JAVAFRAMEANCHOR_ARM_HPP
+
+private:
+
+  // FP value associated with _last_Java_sp:
+  intptr_t* volatile        _last_Java_fp;           // pointer is volatile not what it points to
+
+public:
+  // Each arch must define reset, save, restore
+  // These are used by objects that only care about:
+  //  1 - initializing a new state (thread creation, javaCalls)
+  //  2 - saving a current state (javaCalls)
+  //  3 - restoring an old state (javaCalls)
+
+  void clear(void) {
+    // clearing _last_Java_sp must be first
+    _last_Java_sp = NULL;
+    // fence?
+    _last_Java_fp = NULL;
+    _last_Java_pc = NULL;
+  }
+
+  void copy(JavaFrameAnchor* src) {
+    // In order to make sure the transition state is valid for "this"
+    // We must clear _last_Java_sp before copying the rest of the new data
+    //
+    // Hack Alert: Temporary bugfix for 4717480/4721647
+    // To act like previous version (pd_cache_state) don't NULL _last_Java_sp
+    // unless the value is changing
+    //
+    if (_last_Java_sp != src->_last_Java_sp)
+      _last_Java_sp = NULL;
+
+    _last_Java_fp = src->_last_Java_fp;
+    _last_Java_pc = src->_last_Java_pc;
+    // Must be last so profiler will always see valid frame if has_last_frame() is true
+    _last_Java_sp = src->_last_Java_sp;
+  }
+
+  // Always walkable
+  bool walkable(void) { return true; }
+  // Never any thing to do since we are always walkable and can find address of return addresses
+  void make_walkable(JavaThread* thread) { }
+
+  intptr_t* last_Java_sp(void) const             { return _last_Java_sp; }
+
+  address last_Java_pc(void)                     { return _last_Java_pc; }
+
+private:
+
+  static ByteSize last_Java_fp_offset()          { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); }
+
+public:
+
+  void set_last_Java_sp(intptr_t* sp)            { _last_Java_sp = sp; }
+
+  intptr_t*   last_Java_fp(void)                     { return _last_Java_fp; }
+  // Assert (last_Java_sp == NULL || fp == NULL)
+  void set_last_Java_fp(intptr_t* fp)                { _last_Java_fp = fp; }
+
+#endif // CPU_ARM_VM_JAVAFRAMEANCHOR_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp
new file mode 100644
index 0000000..f9bd9f3
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm_misc.hpp"
+#include "runtime/safepoint.hpp"
+
+#define __ masm->
+
+#define BUFFER_SIZE  96
+
+address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
+  const char* name = NULL;
+  address slow_case_addr = NULL;
+  switch (type) {
+    case T_BOOLEAN:
+      name = "jni_fast_GetBooleanField";
+      slow_case_addr = jni_GetBooleanField_addr();
+      break;
+    case T_BYTE:
+      name = "jni_fast_GetByteField";
+      slow_case_addr = jni_GetByteField_addr();
+      break;
+    case T_CHAR:
+      name = "jni_fast_GetCharField";
+      slow_case_addr = jni_GetCharField_addr();
+      break;
+    case T_SHORT:
+      name = "jni_fast_GetShortField";
+      slow_case_addr = jni_GetShortField_addr();
+      break;
+    case T_INT:
+      name = "jni_fast_GetIntField";
+      slow_case_addr = jni_GetIntField_addr();
+      break;
+    case T_LONG:
+      name = "jni_fast_GetLongField";
+      slow_case_addr = jni_GetLongField_addr();
+      break;
+    case T_FLOAT:
+      name = "jni_fast_GetFloatField";
+      slow_case_addr = jni_GetFloatField_addr();
+      break;
+    case T_DOUBLE:
+      name = "jni_fast_GetDoubleField";
+      slow_case_addr = jni_GetDoubleField_addr();
+      break;
+    default:
+      ShouldNotReachHere();
+  }
+
+  // R0 - jni env
+  // R1 - object handle
+  // R2 - jfieldID
+
+  const Register Rsafepoint_counter_addr = AARCH64_ONLY(R4) NOT_AARCH64(R3);
+  const Register Robj = AARCH64_ONLY(R5) NOT_AARCH64(R1);
+  const Register Rres = AARCH64_ONLY(R6) NOT_AARCH64(R0);
+#ifndef AARCH64
+  const Register Rres_hi = R1;
+#endif // !AARCH64
+  const Register Rsafept_cnt = Rtemp;
+  const Register Rsafept_cnt2 = Rsafepoint_counter_addr;
+  const Register Rtmp1 = AARCH64_ONLY(R7) NOT_AARCH64(R3); // same as Rsafepoint_counter_addr on 32-bit ARM
+  const Register Rtmp2 = AARCH64_ONLY(R8) NOT_AARCH64(R2); // same as jfieldID on 32-bit ARM
+
+#ifdef AARCH64
+  assert_different_registers(Rsafepoint_counter_addr, Rsafept_cnt, Robj, Rres, Rtmp1, Rtmp2, R0, R1, R2, LR);
+  assert_different_registers(Rsafept_cnt2, Rsafept_cnt, Rres, R0, R1, R2, LR);
+#else
+  assert_different_registers(Rsafepoint_counter_addr, Rsafept_cnt, Robj, Rres, LR);
+  assert_different_registers(Rsafept_cnt, R1, R2, Rtmp1, LR);
+  assert_different_registers(Rsafepoint_counter_addr, Rsafept_cnt, Rres, Rres_hi, Rtmp2, LR);
+  assert_different_registers(Rsafept_cnt2, Rsafept_cnt, Rres, Rres_hi, LR);
+#endif // AARCH64
+
+  address fast_entry;
+
+  ResourceMark rm;
+  BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE);
+  CodeBuffer cbuf(blob);
+  MacroAssembler* masm = new MacroAssembler(&cbuf);
+  fast_entry = __ pc();
+
+  // Safepoint check
+  InlinedAddress safepoint_counter_addr(SafepointSynchronize::safepoint_counter_addr());
+  Label slow_case;
+  __ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
+
+#ifndef AARCH64
+  __ push(RegisterSet(R0, R3));  // save incoming arguments for slow case
+#endif // !AARCH64
+
+  __ ldr_s32(Rsafept_cnt, Address(Rsafepoint_counter_addr));
+  __ tbnz(Rsafept_cnt, 0, slow_case);
+
+  if (os::is_MP()) {
+    // Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
+    __ andr(Rtmp1, Rsafept_cnt, (unsigned)1);
+    __ ldr(Robj, Address(R1, Rtmp1));
+  } else {
+    __ ldr(Robj, Address(R1));
+  }
+
+#ifdef AARCH64
+  __ add(Robj, Robj, AsmOperand(R2, lsr, 2));
+  Address field_addr = Address(Robj);
+#else
+  Address field_addr;
+  if (type != T_BOOLEAN
+      && type != T_INT
+#ifndef __ABI_HARD__
+      && type != T_FLOAT
+#endif // !__ABI_HARD__
+      ) {
+    // Only ldr and ldrb support embedded shift, other loads do not
+    __ add(Robj, Robj, AsmOperand(R2, lsr, 2));
+    field_addr = Address(Robj);
+  } else {
+    field_addr = Address(Robj, R2, lsr, 2);
+  }
+#endif // AARCH64
+  assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
+  speculative_load_pclist[count] = __ pc();
+
+  switch (type) {
+    case T_BOOLEAN:
+      __ ldrb(Rres, field_addr);
+      break;
+    case T_BYTE:
+      __ ldrsb(Rres, field_addr);
+      break;
+    case T_CHAR:
+      __ ldrh(Rres, field_addr);
+      break;
+    case T_SHORT:
+      __ ldrsh(Rres, field_addr);
+      break;
+    case T_INT:
+#ifndef __ABI_HARD__
+    case T_FLOAT:
+#endif
+      __ ldr_s32(Rres, field_addr);
+      break;
+    case T_LONG:
+#ifndef __ABI_HARD__
+    case T_DOUBLE:
+#endif
+#ifdef AARCH64
+      __ ldr(Rres, field_addr);
+#else
+      // Safe to use ldrd since long and double fields are 8-byte aligned
+      __ ldrd(Rres, field_addr);
+#endif // AARCH64
+      break;
+#ifdef __ABI_HARD__
+    case T_FLOAT:
+      __ ldr_float(S0, field_addr);
+      break;
+    case T_DOUBLE:
+      __ ldr_double(D0, field_addr);
+      break;
+#endif // __ABI_HARD__
+    default:
+      ShouldNotReachHere();
+  }
+
+  if(os::is_MP()) {
+      // Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
+#if defined(__ABI_HARD__) && !defined(AARCH64)
+    if (type == T_FLOAT || type == T_DOUBLE) {
+      __ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
+      __ fmrrd(Rres, Rres_hi, D0);
+      __ eor(Rtmp2, Rres, Rres);
+      __ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
+    } else
+#endif // __ABI_HARD__ && !AARCH64
+    {
+#ifndef AARCH64
+      __ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
+#endif // !AARCH64
+      __ eor(Rtmp2, Rres, Rres);
+      __ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
+    }
+  } else {
+    __ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr));
+  }
+  __ cmp(Rsafept_cnt2, Rsafept_cnt);
+#ifdef AARCH64
+  __ b(slow_case, ne);
+  __ mov(R0, Rres);
+  __ ret();
+#else
+  // discards saved R0 R1 R2 R3
+  __ add(SP, SP, 4 * wordSize, eq);
+  __ bx(LR, eq);
+#endif // AARCH64
+
+  slowcase_entry_pclist[count++] = __ pc();
+
+  __ bind(slow_case);
+#ifndef AARCH64
+  __ pop(RegisterSet(R0, R3));
+#endif // !AARCH64
+  // thumb mode switch handled by MacroAssembler::jump if needed
+  __ jump(slow_case_addr, relocInfo::none, Rtemp);
+
+  __ bind_literal(safepoint_counter_addr);
+
+  __ flush();
+
+  guarantee((__ pc() - fast_entry) <= BUFFER_SIZE, "BUFFER_SIZE too small");
+
+  return fast_entry;
+}
+
+address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
+  ShouldNotReachHere();
+  return NULL;
+}
+
+address JNI_FastGetField::generate_fast_get_boolean_field() {
+  return generate_fast_get_int_field0(T_BOOLEAN);
+}
+
+address JNI_FastGetField::generate_fast_get_byte_field() {
+  return generate_fast_get_int_field0(T_BYTE);
+}
+
+address JNI_FastGetField::generate_fast_get_char_field() {
+  return generate_fast_get_int_field0(T_CHAR);
+}
+
+address JNI_FastGetField::generate_fast_get_short_field() {
+  return generate_fast_get_int_field0(T_SHORT);
+}
+
+address JNI_FastGetField::generate_fast_get_int_field() {
+  return generate_fast_get_int_field0(T_INT);
+}
+
+address JNI_FastGetField::generate_fast_get_long_field() {
+  return generate_fast_get_int_field0(T_LONG);
+}
+
+address JNI_FastGetField::generate_fast_get_float_field() {
+  return generate_fast_get_int_field0(T_FLOAT);
+}
+
+address JNI_FastGetField::generate_fast_get_double_field() {
+  return generate_fast_get_int_field0(T_DOUBLE);
+}
diff --git a/hotspot/src/cpu/arm/vm/jniTypes_arm.hpp b/hotspot/src/cpu/arm/vm/jniTypes_arm.hpp
new file mode 100644
index 0000000..7b23ccf
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/jniTypes_arm.hpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_JNITYPES_ARM_HPP
+#define CPU_ARM_VM_JNITYPES_ARM_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/oop.hpp"
+#include "prims/jni.h"
+
+// This file holds platform-dependent routines used to write primitive jni
+// types to the array of arguments passed into JavaCalls::call
+
+class JNITypes : AllStatic {
+  // These functions write a java primitive type (in native format)
+  // to a java stack slot array to be passed as an argument to JavaCalls:calls.
+  // I.e., they are functionally 'push' operations if they have a 'pos'
+  // formal parameter.  Note that jlong's and jdouble's are written
+  // _in reverse_ of the order in which they appear in the interpreter
+  // stack.  This is because call stubs (see stubGenerator_arm.cpp)
+  // reverse the argument list constructed by JavaCallArguments (see
+  // javaCalls.hpp).
+
+private:
+
+#ifndef AARCH64
+  // 32bit Helper routines.
+  static inline void put_int2r(jint *from, intptr_t *to)           { *(jint *)(to++) = from[1];
+                                                                        *(jint *)(to  ) = from[0]; }
+  static inline void put_int2r(jint *from, intptr_t *to, int& pos) { put_int2r(from, to + pos); pos += 2; }
+#endif
+
+public:
+  // Ints are stored in native format in one JavaCallArgument slot at *to.
+  static inline void put_int(jint  from, intptr_t *to)           { *(jint *)(to +   0  ) =  from; }
+  static inline void put_int(jint  from, intptr_t *to, int& pos) { *(jint *)(to + pos++) =  from; }
+  static inline void put_int(jint *from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = *from; }
+
+#ifdef AARCH64
+  // Longs are stored in native format in one JavaCallArgument slot at *(to+1).
+  static inline void put_long(jlong  from, intptr_t *to)           { *(jlong *)(to + 1 +   0) =  from; }
+  static inline void put_long(jlong  from, intptr_t *to, int& pos) { *(jlong *)(to + 1 + pos) =  from; pos += 2; }
+  static inline void put_long(jlong *from, intptr_t *to, int& pos) { *(jlong *)(to + 1 + pos) = *from; pos += 2; }
+#else
+  // Longs are stored in big-endian word format in two JavaCallArgument slots at *to.
+  // The high half is in *to and the low half in *(to+1).
+  static inline void put_long(jlong  from, intptr_t *to)           { put_int2r((jint *)&from, to); }
+  static inline void put_long(jlong  from, intptr_t *to, int& pos) { put_int2r((jint *)&from, to, pos); }
+  static inline void put_long(jlong *from, intptr_t *to, int& pos) { put_int2r((jint *) from, to, pos); }
+#endif
+
+  // Oops are stored in native format in one JavaCallArgument slot at *to.
+  static inline void put_obj(oop  from, intptr_t *to)           { *(oop *)(to +   0  ) =  from; }
+  static inline void put_obj(oop  from, intptr_t *to, int& pos) { *(oop *)(to + pos++) =  from; }
+  static inline void put_obj(oop *from, intptr_t *to, int& pos) { *(oop *)(to + pos++) = *from; }
+
+  // Floats are stored in native format in one JavaCallArgument slot at *to.
+  static inline void put_float(jfloat  from, intptr_t *to)           { *(jfloat *)(to +   0  ) =  from;  }
+  static inline void put_float(jfloat  from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) =  from; }
+  static inline void put_float(jfloat *from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = *from; }
+
+#ifdef AARCH64
+  // Doubles are stored in native word format in one JavaCallArgument slot at *(to+1).
+  static inline void put_double(jdouble  from, intptr_t *to)           { *(jdouble *)(to + 1 +   0) =  from; }
+  static inline void put_double(jdouble  from, intptr_t *to, int& pos) { *(jdouble *)(to + 1 + pos) =  from; pos += 2; }
+  static inline void put_double(jdouble *from, intptr_t *to, int& pos) { *(jdouble *)(to + 1 + pos) = *from; pos += 2; }
+#else
+  // Doubles are stored in big-endian word format in two JavaCallArgument slots at *to.
+  // The high half is in *to and the low half in *(to+1).
+  static inline void put_double(jdouble  from, intptr_t *to)           { put_int2r((jint *)&from, to); }
+  static inline void put_double(jdouble  from, intptr_t *to, int& pos) { put_int2r((jint *)&from, to, pos); }
+  static inline void put_double(jdouble *from, intptr_t *to, int& pos) { put_int2r((jint *) from, to, pos); }
+#endif
+
+};
+
+#endif // CPU_ARM_VM_JNITYPES_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/jni_arm.h b/hotspot/src/cpu/arm/vm/jni_arm.h
new file mode 100644
index 0000000..2a1d4f7
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/jni_arm.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef _JAVASOFT_JNI_MD_H_
+#define _JAVASOFT_JNI_MD_H_
+
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
+  #define JNIEXPORT     __attribute__((externally_visible,visibility("default")))
+  #define JNIIMPORT     __attribute__((externally_visible,visibility("default")))
+#else
+  #define JNIEXPORT
+  #define JNIIMPORT
+#endif
+
+#define JNICALL
+
+typedef int jint;
+#if defined(_LP64)
+  typedef long jlong;
+#else
+  typedef long long jlong;
+#endif
+typedef signed char jbyte;
+
+#endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/hotspot/src/cpu/arm/vm/jvmciCodeInstaller_arm.cpp b/hotspot/src/cpu/arm/vm/jvmciCodeInstaller_arm.cpp
new file mode 100644
index 0000000..dc225a2
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/jvmciCodeInstaller_arm.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "jvmci/jvmciCodeInstaller.hpp"
+#include "jvmci/jvmciRuntime.hpp"
+#include "jvmci/jvmciCompilerToVM.hpp"
+#include "jvmci/jvmciJavaClasses.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_arm.inline.hpp"
+
+jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) {
+  Unimplemented();
+  return 0;
+}
+
+void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
+  Unimplemented();
+}
+
+void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
+  Unimplemented();
+}
+
+void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) {
+  Unimplemented();
+}
+
+void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) {
+  Unimplemented();
+}
+
+void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) {
+  Unimplemented();
+}
+
+void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) {
+  Unimplemented();
+}
+
+// convert JVMCI register indices (as used in oop maps) to HotSpot registers
+VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) {
+  return NULL;
+}
+
+bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
+  return false;
+}
diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp
new file mode 100644
index 0000000..ada7d3f
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp
@@ -0,0 +1,3120 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "ci/ciEnv.hpp"
+#include "code/nativeInst.hpp"
+#include "compiler/disassembler.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/klass.inline.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/heapRegion.hpp"
+#endif
+
+// Implementation of AddressLiteral
+
+void AddressLiteral::set_rspec(relocInfo::relocType rtype) {
+  switch (rtype) {
+  case relocInfo::oop_type:
+    // Oops are a special case. Normally they would be their own section
+    // but in cases like icBuffer they are literals in the code stream that
+    // we don't have a section for. We use none so that we get a literal address
+    // which is always patchable.
+    break;
+  case relocInfo::external_word_type:
+    _rspec = external_word_Relocation::spec(_target);
+    break;
+  case relocInfo::internal_word_type:
+    _rspec = internal_word_Relocation::spec(_target);
+    break;
+  case relocInfo::opt_virtual_call_type:
+    _rspec = opt_virtual_call_Relocation::spec();
+    break;
+  case relocInfo::static_call_type:
+    _rspec = static_call_Relocation::spec();
+    break;
+  case relocInfo::runtime_call_type:
+    _rspec = runtime_call_Relocation::spec();
+    break;
+  case relocInfo::poll_type:
+  case relocInfo::poll_return_type:
+    _rspec = Relocation::spec_simple(rtype);
+    break;
+  case relocInfo::none:
+    break;
+  default:
+    ShouldNotReachHere();
+    break;
+  }
+}
+
+// Initially added to the Assembler interface as a pure virtual:
+//   RegisterConstant delayed_value(..)
+// for:
+//   6812678 macro assembler needs delayed binding of a few constants (for 6655638)
+// this was subsequently modified to its present name and return type
+RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
+                                                      Register tmp,
+                                                      int offset) {
+  ShouldNotReachHere();
+  return RegisterOrConstant(-1);
+}
+
+
+#ifdef AARCH64
+// Note: ARM32 version is OS dependent
+void MacroAssembler::breakpoint(AsmCondition cond) {
+  if (cond == al) {
+    brk();
+  } else {
+    Label L;
+    b(L, inverse(cond));
+    brk();
+    bind(L);
+  }
+}
+#endif // AARCH64
+
+
+// virtual method calling
+void MacroAssembler::lookup_virtual_method(Register recv_klass,
+                                           Register vtable_index,
+                                           Register method_result) {
+  const int base_offset = in_bytes(Klass::vtable_start_offset()) + vtableEntry::method_offset_in_bytes();
+  assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+  add(recv_klass, recv_klass, AsmOperand(vtable_index, lsl, LogBytesPerWord));
+  ldr(method_result, Address(recv_klass, base_offset));
+}
+
+
+// Simplified, combined version, good for typical uses.
+// Falls through on failure.
+void MacroAssembler::check_klass_subtype(Register sub_klass,
+                                         Register super_klass,
+                                         Register temp_reg,
+                                         Register temp_reg2,
+                                         Register temp_reg3,
+                                         Label& L_success) {
+  Label L_failure;
+  check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, temp_reg2, &L_success, &L_failure, NULL);
+  check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, temp_reg2, temp_reg3, &L_success, NULL);
+  bind(L_failure);
+};
+
+void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
+                                                   Register super_klass,
+                                                   Register temp_reg,
+                                                   Register temp_reg2,
+                                                   Label* L_success,
+                                                   Label* L_failure,
+                                                   Label* L_slow_path) {
+
+  assert_different_registers(sub_klass, super_klass, temp_reg, temp_reg2, noreg);
+  const Register super_check_offset = temp_reg2;
+
+  Label L_fallthrough;
+  int label_nulls = 0;
+  if (L_success == NULL)   { L_success   = &L_fallthrough; label_nulls++; }
+  if (L_failure == NULL)   { L_failure   = &L_fallthrough; label_nulls++; }
+  if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
+  assert(label_nulls <= 1, "at most one NULL in the batch");
+
+  int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+  int sco_offset = in_bytes(Klass::super_check_offset_offset());
+  Address super_check_offset_addr(super_klass, sco_offset);
+
+  // If the pointers are equal, we are done (e.g., String[] elements).
+  // This self-check enables sharing of secondary supertype arrays among
+  // non-primary types such as array-of-interface.  Otherwise, each such
+  // type would need its own customized SSA.
+  // We move this check to the front of the fast path because many
+  // type checks are in fact trivially successful in this manner,
+  // so we get a nicely predicted branch right at the start of the check.
+  cmp(sub_klass, super_klass);
+  b(*L_success, eq);
+
+  // Check the supertype display:
+  ldr_u32(super_check_offset, super_check_offset_addr);
+
+  Address super_check_addr(sub_klass, super_check_offset);
+  ldr(temp_reg, super_check_addr);
+  cmp(super_klass, temp_reg); // load displayed supertype
+
+  // This check has worked decisively for primary supers.
+  // Secondary supers are sought in the super_cache ('super_cache_addr').
+  // (Secondary supers are interfaces and very deeply nested subtypes.)
+  // This works in the same check above because of a tricky aliasing
+  // between the super_cache and the primary super display elements.
+  // (The 'super_check_addr' can address either, as the case requires.)
+  // Note that the cache is updated below if it does not help us find
+  // what we need immediately.
+  // So if it was a primary super, we can just fail immediately.
+  // Otherwise, it's the slow path for us (no success at this point).
+
+  b(*L_success, eq);
+  cmp_32(super_check_offset, sc_offset);
+  if (L_failure == &L_fallthrough) {
+    b(*L_slow_path, eq);
+  } else {
+    b(*L_failure, ne);
+    if (L_slow_path != &L_fallthrough) {
+      b(*L_slow_path);
+    }
+  }
+
+  bind(L_fallthrough);
+}
+
+
+void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
+                                                   Register super_klass,
+                                                   Register temp_reg,
+                                                   Register temp2_reg,
+                                                   Register temp3_reg,
+                                                   Label* L_success,
+                                                   Label* L_failure,
+                                                   bool set_cond_codes) {
+#ifdef AARCH64
+  NOT_IMPLEMENTED();
+#else
+  // Note: if used by code that expects a register to be 0 on success,
+  // this register must be temp_reg and set_cond_codes must be true
+
+  Register saved_reg = noreg;
+
+  // get additional tmp registers
+  if (temp3_reg == noreg) {
+    saved_reg = temp3_reg = LR;
+    push(saved_reg);
+  }
+
+  assert(temp2_reg != noreg, "need all the temporary registers");
+  assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg, temp3_reg);
+
+  Register cmp_temp = temp_reg;
+  Register scan_temp = temp3_reg;
+  Register count_temp = temp2_reg;
+
+  Label L_fallthrough;
+  int label_nulls = 0;
+  if (L_success == NULL)   { L_success   = &L_fallthrough; label_nulls++; }
+  if (L_failure == NULL)   { L_failure   = &L_fallthrough; label_nulls++; }
+  assert(label_nulls <= 1, "at most one NULL in the batch");
+
+  // a couple of useful fields in sub_klass:
+  int ss_offset = in_bytes(Klass::secondary_supers_offset());
+  int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+  Address secondary_supers_addr(sub_klass, ss_offset);
+  Address super_cache_addr(     sub_klass, sc_offset);
+
+#ifndef PRODUCT
+  inc_counter((address)&SharedRuntime::_partial_subtype_ctr, scan_temp, count_temp);
+#endif
+
+  // We will consult the secondary-super array.
+  ldr(scan_temp, Address(sub_klass, ss_offset));
+
+  assert(! UseCompressedOops, "search_key must be the compressed super_klass");
+  // else search_key is the
+  Register search_key = super_klass;
+
+  // Load the array length.
+  ldr(count_temp, Address(scan_temp, Array<Klass*>::length_offset_in_bytes()));
+  add(scan_temp, scan_temp, Array<Klass*>::base_offset_in_bytes());
+
+  add(count_temp, count_temp, 1);
+
+  Label L_loop, L_setnz_and_fail, L_fail;
+
+  // Top of search loop
+  bind(L_loop);
+  // Notes:
+  //  scan_temp starts at the array elements
+  //  count_temp is 1+size
+  subs(count_temp, count_temp, 1);
+  if ((L_failure != &L_fallthrough) && (! set_cond_codes) && (saved_reg == noreg)) {
+    // direct jump to L_failure if failed and no cleanup needed
+    b(*L_failure, eq); // not found and
+  } else {
+    b(L_fail, eq); // not found in the array
+  }
+
+  // Load next super to check
+  // In the array of super classes elements are pointer sized.
+  int element_size = wordSize;
+  ldr(cmp_temp, Address(scan_temp, element_size, post_indexed));
+
+  // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
+  subs(cmp_temp, cmp_temp, search_key);
+
+  // A miss means we are NOT a subtype and need to keep looping
+  b(L_loop, ne);
+
+  // Falling out the bottom means we found a hit; we ARE a subtype
+
+  // Note: temp_reg/cmp_temp is already 0 and flag Z is set
+
+  // Success.  Cache the super we found and proceed in triumph.
+  str(super_klass, Address(sub_klass, sc_offset));
+
+  if (saved_reg != noreg) {
+    // Return success
+    pop(saved_reg);
+  }
+
+  b(*L_success);
+
+  bind(L_fail);
+  // Note1: check "b(*L_failure, eq)" above if adding extra instructions here
+  if (set_cond_codes) {
+    movs(temp_reg, sub_klass); // clears Z and sets temp_reg to non-0 if needed
+  }
+  if (saved_reg != noreg) {
+    pop(saved_reg);
+  }
+  if (L_failure != &L_fallthrough) {
+    b(*L_failure);
+  }
+
+  bind(L_fallthrough);
+#endif
+}
+
+// Returns address of receiver parameter, using tmp as base register. tmp and params_count can be the same.
+Address MacroAssembler::receiver_argument_address(Register params_base, Register params_count, Register tmp) {
+  assert_different_registers(params_base, params_count);
+  add(tmp, params_base, AsmOperand(params_count, lsl, Interpreter::logStackElementSize));
+  return Address(tmp, -Interpreter::stackElementSize);
+}
+
+
+void MacroAssembler::align(int modulus) {
+  while (offset() % modulus != 0) {
+    nop();
+  }
+}
+
+int MacroAssembler::set_last_Java_frame(Register last_java_sp,
+                                        Register last_java_fp,
+                                        bool save_last_java_pc,
+                                        Register tmp) {
+  int pc_offset;
+  if (last_java_fp != noreg) {
+    // optional
+    str(last_java_fp, Address(Rthread, JavaThread::last_Java_fp_offset()));
+    _fp_saved = true;
+  } else {
+    _fp_saved = false;
+  }
+  if (AARCH64_ONLY(true) NOT_AARCH64(save_last_java_pc)) { // optional on 32-bit ARM
+#ifdef AARCH64
+    pc_offset = mov_pc_to(tmp);
+    str(tmp, Address(Rthread, JavaThread::last_Java_pc_offset()));
+#else
+    str(PC, Address(Rthread, JavaThread::last_Java_pc_offset()));
+    pc_offset = offset() + VM_Version::stored_pc_adjustment();
+#endif
+    _pc_saved = true;
+  } else {
+    _pc_saved = false;
+    pc_offset = -1;
+  }
+  // According to comment in javaFrameAnchorm SP must be saved last, so that other
+  // entries are valid when SP is set.
+
+  // However, this is probably not a strong constrainst since for instance PC is
+  // sometimes read from the stack at SP... but is pushed later (by the call). Hence,
+  // we now write the fields in the expected order but we have not added a StoreStore
+  // barrier.
+
+  // XXX: if the ordering is really important, PC should always be saved (without forgetting
+  // to update oop_map offsets) and a StoreStore barrier might be needed.
+
+  if (last_java_sp == noreg) {
+    last_java_sp = SP; // always saved
+  }
+#ifdef AARCH64
+  if (last_java_sp == SP) {
+    mov(tmp, SP);
+    str(tmp, Address(Rthread, JavaThread::last_Java_sp_offset()));
+  } else {
+    str(last_java_sp, Address(Rthread, JavaThread::last_Java_sp_offset()));
+  }
+#else
+  str(last_java_sp, Address(Rthread, JavaThread::last_Java_sp_offset()));
+#endif
+
+  return pc_offset; // for oopmaps
+}
+
+void MacroAssembler::reset_last_Java_frame(Register tmp) {
+  const Register Rzero = zero_register(tmp);
+  str(Rzero, Address(Rthread, JavaThread::last_Java_sp_offset()));
+  if (_fp_saved) {
+    str(Rzero, Address(Rthread, JavaThread::last_Java_fp_offset()));
+  }
+  if (_pc_saved) {
+    str(Rzero, Address(Rthread, JavaThread::last_Java_pc_offset()));
+  }
+}
+
+
+// Implementation of call_VM versions
+
+void MacroAssembler::call_VM_leaf_helper(address entry_point, int number_of_arguments) {
+  assert(number_of_arguments >= 0, "cannot have negative number of arguments");
+  assert(number_of_arguments <= 4, "cannot have more than 4 arguments");
+
+#ifndef AARCH64
+  // Safer to save R9 here since callers may have been written
+  // assuming R9 survives. This is suboptimal but is not worth
+  // optimizing for the few platforms where R9 is scratched.
+  push(RegisterSet(R4) | R9ifScratched);
+  mov(R4, SP);
+  bic(SP, SP, StackAlignmentInBytes - 1);
+#endif // AARCH64
+  call(entry_point, relocInfo::runtime_call_type);
+#ifndef AARCH64
+  mov(SP, R4);
+  pop(RegisterSet(R4) | R9ifScratched);
+#endif // AARCH64
+}
+
+
+void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
+  assert(number_of_arguments >= 0, "cannot have negative number of arguments");
+  assert(number_of_arguments <= 3, "cannot have more than 3 arguments");
+
+  const Register tmp = Rtemp;
+  assert_different_registers(oop_result, tmp);
+
+  set_last_Java_frame(SP, FP, true, tmp);
+
+#ifdef ASSERT
+  AARCH64_ONLY(if (UseCompressedOops || UseCompressedClassPointers) { verify_heapbase("call_VM_helper: heap base corrupted?"); });
+#endif // ASSERT
+
+#ifndef AARCH64
+#if R9_IS_SCRATCHED
+  // Safer to save R9 here since callers may have been written
+  // assuming R9 survives. This is suboptimal but is not worth
+  // optimizing for the few platforms where R9 is scratched.
+
+  // Note: cannot save R9 above the saved SP (some calls expect for
+  // instance the Java stack top at the saved SP)
+  // => once saved (with set_last_Java_frame), decrease SP before rounding to
+  // ensure the slot at SP will be free for R9).
+  sub(SP, SP, 4);
+  bic(SP, SP, StackAlignmentInBytes - 1);
+  str(R9, Address(SP, 0));
+#else
+  bic(SP, SP, StackAlignmentInBytes - 1);
+#endif // R9_IS_SCRATCHED
+#endif
+
+  mov(R0, Rthread);
+  call(entry_point, relocInfo::runtime_call_type);
+
+#ifndef AARCH64
+#if R9_IS_SCRATCHED
+  ldr(R9, Address(SP, 0));
+#endif
+  ldr(SP, Address(Rthread, JavaThread::last_Java_sp_offset()));
+#endif
+
+  reset_last_Java_frame(tmp);
+
+  // C++ interp handles this in the interpreter
+  check_and_handle_popframe();
+  check_and_handle_earlyret();
+
+  if (check_exceptions) {
+    // check for pending exceptions
+    ldr(tmp, Address(Rthread, Thread::pending_exception_offset()));
+#ifdef AARCH64
+    Label L;
+    cbz(tmp, L);
+    mov_pc_to(Rexception_pc);
+    b(StubRoutines::forward_exception_entry());
+    bind(L);
+#else
+    cmp(tmp, 0);
+    mov(Rexception_pc, PC, ne);
+    b(StubRoutines::forward_exception_entry(), ne);
+#endif // AARCH64
+  }
+
+  // get oop result if there is one and reset the value in the thread
+  if (oop_result->is_valid()) {
+    get_vm_result(oop_result, tmp);
+  }
+}
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) {
+  call_VM_helper(oop_result, entry_point, 0, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) {
+  assert (arg_1 == R1, "fixed register for arg_1");
+  call_VM_helper(oop_result, entry_point, 1, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
+  assert (arg_1 == R1, "fixed register for arg_1");
+  assert (arg_2 == R2, "fixed register for arg_2");
+  call_VM_helper(oop_result, entry_point, 2, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
+  assert (arg_1 == R1, "fixed register for arg_1");
+  assert (arg_2 == R2, "fixed register for arg_2");
+  assert (arg_3 == R3, "fixed register for arg_3");
+  call_VM_helper(oop_result, entry_point, 3, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) {
+  // Not used on ARM
+  Unimplemented();
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions) {
+  // Not used on ARM
+  Unimplemented();
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
+// Not used on ARM
+  Unimplemented();
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
+  // Not used on ARM
+  Unimplemented();
+}
+
+// Raw call, without saving/restoring registers, exception handling, etc.
+// Mainly used from various stubs.
+void MacroAssembler::call_VM(address entry_point, bool save_R9_if_scratched) {
+  const Register tmp = Rtemp; // Rtemp free since scratched by call
+  set_last_Java_frame(SP, FP, true, tmp);
+#if R9_IS_SCRATCHED
+  if (save_R9_if_scratched) {
+    // Note: Saving also R10 for alignment.
+    push(RegisterSet(R9, R10));
+  }
+#endif
+  mov(R0, Rthread);
+  call(entry_point, relocInfo::runtime_call_type);
+#if R9_IS_SCRATCHED
+  if (save_R9_if_scratched) {
+    pop(RegisterSet(R9, R10));
+  }
+#endif
+  reset_last_Java_frame(tmp);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point) {
+  call_VM_leaf_helper(entry_point, 0);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_1) {
+  assert (arg_1 == R0, "fixed register for arg_1");
+  call_VM_leaf_helper(entry_point, 1);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_1, Register arg_2) {
+  assert (arg_1 == R0, "fixed register for arg_1");
+  assert (arg_2 == R1, "fixed register for arg_2");
+  call_VM_leaf_helper(entry_point, 2);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3) {
+  assert (arg_1 == R0, "fixed register for arg_1");
+  assert (arg_2 == R1, "fixed register for arg_2");
+  assert (arg_3 == R2, "fixed register for arg_3");
+  call_VM_leaf_helper(entry_point, 3);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4) {
+  assert (arg_1 == R0, "fixed register for arg_1");
+  assert (arg_2 == R1, "fixed register for arg_2");
+  assert (arg_3 == R2, "fixed register for arg_3");
+  assert (arg_4 == R3, "fixed register for arg_4");
+  call_VM_leaf_helper(entry_point, 4);
+}
+
+void MacroAssembler::get_vm_result(Register oop_result, Register tmp) {
+  assert_different_registers(oop_result, tmp);
+  ldr(oop_result, Address(Rthread, JavaThread::vm_result_offset()));
+  str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_offset()));
+  verify_oop(oop_result);
+}
+
+void MacroAssembler::get_vm_result_2(Register metadata_result, Register tmp) {
+  assert_different_registers(metadata_result, tmp);
+  ldr(metadata_result, Address(Rthread, JavaThread::vm_result_2_offset()));
+  str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_2_offset()));
+}
+
+void MacroAssembler::add_rc(Register dst, Register arg1, RegisterOrConstant arg2) {
+  if (arg2.is_register()) {
+    add(dst, arg1, arg2.as_register());
+  } else {
+    add(dst, arg1, arg2.as_constant());
+  }
+}
+
+void MacroAssembler::add_slow(Register rd, Register rn, int c) {
+#ifdef AARCH64
+  if (c == 0) {
+    if (rd != rn) {
+      mov(rd, rn);
+    }
+    return;
+  }
+  if (c < 0) {
+    sub_slow(rd, rn, -c);
+    return;
+  }
+  if (c > right_n_bits(24)) {
+    guarantee(rd != rn, "no large add_slow with only one register");
+    mov_slow(rd, c);
+    add(rd, rn, rd);
+  } else {
+    int lo = c & right_n_bits(12);
+    int hi = (c >> 12) & right_n_bits(12);
+    if (lo != 0) {
+      add(rd, rn, lo, lsl0);
+    }
+    if (hi != 0) {
+      add(rd, (lo == 0) ? rn : rd, hi, lsl12);
+    }
+  }
+#else
+  // This function is used in compiler for handling large frame offsets
+  if ((c < 0) && (((-c) & ~0x3fc) == 0)) {
+    return sub(rd, rn, (-c));
+  }
+  int low = c & 0x3fc;
+  if (low != 0) {
+    add(rd, rn, low);
+    rn = rd;
+  }
+  if (c & ~0x3fc) {
+    assert(AsmOperand::is_rotated_imm(c & ~0x3fc), "unsupported add_slow offset %d", c);
+    add(rd, rn, c & ~0x3fc);
+  } else if (rd != rn) {
+    assert(c == 0, "");
+    mov(rd, rn); // need to generate at least one move!
+  }
+#endif // AARCH64
+}
+
+void MacroAssembler::sub_slow(Register rd, Register rn, int c) {
+#ifdef AARCH64
+  if (c <= 0) {
+    add_slow(rd, rn, -c);
+    return;
+  }
+  if (c > right_n_bits(24)) {
+    guarantee(rd != rn, "no large sub_slow with only one register");
+    mov_slow(rd, c);
+    sub(rd, rn, rd);
+  } else {
+    int lo = c & right_n_bits(12);
+    int hi = (c >> 12) & right_n_bits(12);
+    if (lo != 0) {
+      sub(rd, rn, lo, lsl0);
+    }
+    if (hi != 0) {
+      sub(rd, (lo == 0) ? rn : rd, hi, lsl12);
+    }
+  }
+#else
+  // This function is used in compiler for handling large frame offsets
+  if ((c < 0) && (((-c) & ~0x3fc) == 0)) {
+    return add(rd, rn, (-c));
+  }
+  int low = c & 0x3fc;
+  if (low != 0) {
+    sub(rd, rn, low);
+    rn = rd;
+  }
+  if (c & ~0x3fc) {
+    assert(AsmOperand::is_rotated_imm(c & ~0x3fc), "unsupported sub_slow offset %d", c);
+    sub(rd, rn, c & ~0x3fc);
+  } else if (rd != rn) {
+    assert(c == 0, "");
+    mov(rd, rn); // need to generate at least one move!
+  }
+#endif // AARCH64
+}
+
+void MacroAssembler::mov_slow(Register rd, address addr) {
+  // do *not* call the non relocated mov_related_address
+  mov_slow(rd, (intptr_t)addr);
+}
+
+void MacroAssembler::mov_slow(Register rd, const char *str) {
+  mov_slow(rd, (intptr_t)str);
+}
+
+#ifdef AARCH64
+
+// Common code for mov_slow and instr_count_for_mov_slow.
+// Returns number of instructions of mov_slow pattern,
+// generating it if non-null MacroAssembler is given.
+int MacroAssembler::mov_slow_helper(Register rd, intptr_t c, MacroAssembler* masm) {
+  // This code pattern is matched in NativeIntruction::is_mov_slow.
+  // Update it at modifications.
+
+  const intx mask = right_n_bits(16);
+  // 1 movz instruction
+  for (int base_shift = 0; base_shift < 64; base_shift += 16) {
+    if ((c & ~(mask << base_shift)) == 0) {
+      if (masm != NULL) {
+        masm->movz(rd, ((uintx)c) >> base_shift, base_shift);
+      }
+      return 1;
+    }
+  }
+  // 1 movn instruction
+  for (int base_shift = 0; base_shift < 64; base_shift += 16) {
+    if (((~c) & ~(mask << base_shift)) == 0) {
+      if (masm != NULL) {
+        masm->movn(rd, ((uintx)(~c)) >> base_shift, base_shift);
+      }
+      return 1;
+    }
+  }
+  // 1 orr instruction
+  {
+    LogicalImmediate imm(c, false);
+    if (imm.is_encoded()) {
+      if (masm != NULL) {
+        masm->orr(rd, ZR, imm);
+      }
+      return 1;
+    }
+  }
+  // 1 movz/movn + up to 3 movk instructions
+  int zeroes = 0;
+  int ones = 0;
+  for (int base_shift = 0; base_shift < 64; base_shift += 16) {
+    int part = (c >> base_shift) & mask;
+    if (part == 0) {
+      ++zeroes;
+    } else if (part == mask) {
+      ++ones;
+    }
+  }
+  int def_bits = 0;
+  if (ones > zeroes) {
+    def_bits = mask;
+  }
+  int inst_count = 0;
+  for (int base_shift = 0; base_shift < 64; base_shift += 16) {
+    int part = (c >> base_shift) & mask;
+    if (part != def_bits) {
+      if (masm != NULL) {
+        if (inst_count > 0) {
+          masm->movk(rd, part, base_shift);
+        } else {
+          if (def_bits == 0) {
+            masm->movz(rd, part, base_shift);
+          } else {
+            masm->movn(rd, ~part & mask, base_shift);
+          }
+        }
+      }
+      inst_count++;
+    }
+  }
+  assert((1 <= inst_count) && (inst_count <= 4), "incorrect number of instructions");
+  return inst_count;
+}
+
+void MacroAssembler::mov_slow(Register rd, intptr_t c) {
+#ifdef ASSERT
+  int off = offset();
+#endif
+  (void) mov_slow_helper(rd, c, this);
+  assert(offset() - off == instr_count_for_mov_slow(c) * InstructionSize, "size mismatch");
+}
+
+// Counts instructions generated by mov_slow(rd, c).
+int MacroAssembler::instr_count_for_mov_slow(intptr_t c) {
+  return mov_slow_helper(noreg, c, NULL);
+}
+
+int MacroAssembler::instr_count_for_mov_slow(address c) {
+  return mov_slow_helper(noreg, (intptr_t)c, NULL);
+}
+
+#else
+
+void MacroAssembler::mov_slow(Register rd, intptr_t c, AsmCondition cond) {
+  if (AsmOperand::is_rotated_imm(c)) {
+    mov(rd, c, cond);
+  } else if (AsmOperand::is_rotated_imm(~c)) {
+    mvn(rd, ~c, cond);
+  } else if (VM_Version::supports_movw()) {
+    movw(rd, c & 0xffff, cond);
+    if ((unsigned int)c >> 16) {
+      movt(rd, (unsigned int)c >> 16, cond);
+    }
+  } else {
+    // Find first non-zero bit
+    int shift = 0;
+    while ((c & (3 << shift)) == 0) {
+      shift += 2;
+    }
+    // Put the least significant part of the constant
+    int mask = 0xff << shift;
+    mov(rd, c & mask, cond);
+    // Add up to 3 other parts of the constant;
+    // each of them can be represented as rotated_imm
+    if (c & (mask << 8)) {
+      orr(rd, rd, c & (mask << 8), cond);
+    }
+    if (c & (mask << 16)) {
+      orr(rd, rd, c & (mask << 16), cond);
+    }
+    if (c & (mask << 24)) {
+      orr(rd, rd, c & (mask << 24), cond);
+    }
+  }
+}
+
+#endif // AARCH64
+
+void MacroAssembler::mov_oop(Register rd, jobject o, int oop_index,
+#ifdef AARCH64
+                             bool patchable
+#else
+                             AsmCondition cond
+#endif
+                             ) {
+
+  if (o == NULL) {
+#ifdef AARCH64
+    if (patchable) {
+      nop();
+    }
+    mov(rd, ZR);
+#else
+    mov(rd, 0, cond);
+#endif
+    return;
+  }
+
+  if (oop_index == 0) {
+    oop_index = oop_recorder()->allocate_oop_index(o);
+  }
+  relocate(oop_Relocation::spec(oop_index));
+
+#ifdef AARCH64
+  if (patchable) {
+    nop();
+  }
+  ldr(rd, pc());
+#else
+  if (VM_Version::supports_movw()) {
+    movw(rd, 0, cond);
+    movt(rd, 0, cond);
+  } else {
+    ldr(rd, Address(PC), cond);
+    // Extra nop to handle case of large offset of oop placeholder (see NativeMovConstReg::set_data).
+    nop();
+  }
+#endif
+}
+
+void MacroAssembler::mov_metadata(Register rd, Metadata* o, int metadata_index AARCH64_ONLY_ARG(bool patchable)) {
+  if (o == NULL) {
+#ifdef AARCH64
+    if (patchable) {
+      nop();
+    }
+#endif
+    mov(rd, 0);
+    return;
+  }
+
+  if (metadata_index == 0) {
+    metadata_index = oop_recorder()->allocate_metadata_index(o);
+  }
+  relocate(metadata_Relocation::spec(metadata_index));
+
+#ifdef AARCH64
+  if (patchable) {
+    nop();
+  }
+#ifdef COMPILER2
+  if (!patchable && VM_Version::prefer_moves_over_load_literal()) {
+    mov_slow(rd, (address)o);
+    return;
+  }
+#endif
+  ldr(rd, pc());
+#else
+  if (VM_Version::supports_movw()) {
+    movw(rd, ((int)o) & 0xffff);
+    movt(rd, (unsigned int)o >> 16);
+  } else {
+    ldr(rd, Address(PC));
+    // Extra nop to handle case of large offset of metadata placeholder (see NativeMovConstReg::set_data).
+    nop();
+  }
+#endif // AARCH64
+}
+
+void MacroAssembler::mov_float(FloatRegister fd, jfloat c NOT_AARCH64_ARG(AsmCondition cond)) {
+  Label skip_constant;
+  union {
+    jfloat f;
+    jint i;
+  } accessor;
+  accessor.f = c;
+
+#ifdef AARCH64
+  // TODO-AARCH64 - try to optimize loading of float constants with fmov and/or mov_slow
+  Label L;
+  ldr_s(fd, target(L));
+  b(skip_constant);
+  bind(L);
+  emit_int32(accessor.i);
+  bind(skip_constant);
+#else
+  flds(fd, Address(PC), cond);
+  b(skip_constant);
+  emit_int32(accessor.i);
+  bind(skip_constant);
+#endif // AARCH64
+}
+
+void MacroAssembler::mov_double(FloatRegister fd, jdouble c NOT_AARCH64_ARG(AsmCondition cond)) {
+  Label skip_constant;
+  union {
+    jdouble d;
+    jint i[2];
+  } accessor;
+  accessor.d = c;
+
+#ifdef AARCH64
+  // TODO-AARCH64 - try to optimize loading of double constants with fmov
+  Label L;
+  ldr_d(fd, target(L));
+  b(skip_constant);
+  align(wordSize);
+  bind(L);
+  emit_int32(accessor.i[0]);
+  emit_int32(accessor.i[1]);
+  bind(skip_constant);
+#else
+  fldd(fd, Address(PC), cond);
+  b(skip_constant);
+  emit_int32(accessor.i[0]);
+  emit_int32(accessor.i[1]);
+  bind(skip_constant);
+#endif // AARCH64
+}
+
+void MacroAssembler::ldr_global_s32(Register reg, address address_of_global) {
+  intptr_t addr = (intptr_t) address_of_global;
+#ifdef AARCH64
+  assert((addr & 0x3) == 0, "address should be aligned");
+
+  // FIXME: TODO
+  if (false && page_reachable_from_cache(address_of_global)) {
+    assert(false,"TODO: relocate");
+    //relocate();
+    adrp(reg, address_of_global);
+    ldrsw(reg, Address(reg, addr & 0xfff));
+  } else {
+    mov_slow(reg, addr & ~0x3fff);
+    ldrsw(reg, Address(reg, addr & 0x3fff));
+  }
+#else
+  mov_slow(reg, addr & ~0xfff);
+  ldr(reg, Address(reg, addr & 0xfff));
+#endif
+}
+
+void MacroAssembler::ldr_global_ptr(Register reg, address address_of_global) {
+#ifdef AARCH64
+  intptr_t addr = (intptr_t) address_of_global;
+  assert ((addr & 0x7) == 0, "address should be aligned");
+  mov_slow(reg, addr & ~0x7fff);
+  ldr(reg, Address(reg, addr & 0x7fff));
+#else
+  ldr_global_s32(reg, address_of_global);
+#endif
+}
+
+void MacroAssembler::ldrb_global(Register reg, address address_of_global) {
+  intptr_t addr = (intptr_t) address_of_global;
+  mov_slow(reg, addr & ~0xfff);
+  ldrb(reg, Address(reg, addr & 0xfff));
+}
+
+void MacroAssembler::zero_extend(Register rd, Register rn, int bits) {
+#ifdef AARCH64
+  switch (bits) {
+    case  8: uxtb(rd, rn); break;
+    case 16: uxth(rd, rn); break;
+    case 32: mov_w(rd, rn); break;
+    default: ShouldNotReachHere();
+  }
+#else
+  if (bits <= 8) {
+    andr(rd, rn, (1 << bits) - 1);
+  } else if (bits >= 24) {
+    bic(rd, rn, -1 << bits);
+  } else {
+    mov(rd, AsmOperand(rn, lsl, 32 - bits));
+    mov(rd, AsmOperand(rd, lsr, 32 - bits));
+  }
+#endif
+}
+
+void MacroAssembler::sign_extend(Register rd, Register rn, int bits) {
+#ifdef AARCH64
+  switch (bits) {
+    case  8: sxtb(rd, rn); break;
+    case 16: sxth(rd, rn); break;
+    case 32: sxtw(rd, rn); break;
+    default: ShouldNotReachHere();
+  }
+#else
+  mov(rd, AsmOperand(rn, lsl, 32 - bits));
+  mov(rd, AsmOperand(rd, asr, 32 - bits));
+#endif
+}
+
+#ifndef AARCH64
+
+void MacroAssembler::long_move(Register rd_lo, Register rd_hi,
+                               Register rn_lo, Register rn_hi,
+                               AsmCondition cond) {
+  if (rd_lo != rn_hi) {
+    if (rd_lo != rn_lo) { mov(rd_lo, rn_lo, cond); }
+    if (rd_hi != rn_hi) { mov(rd_hi, rn_hi, cond); }
+  } else if (rd_hi != rn_lo) {
+    if (rd_hi != rn_hi) { mov(rd_hi, rn_hi, cond); }
+    if (rd_lo != rn_lo) { mov(rd_lo, rn_lo, cond); }
+  } else {
+    eor(rd_lo, rd_hi, rd_lo, cond);
+    eor(rd_hi, rd_lo, rd_hi, cond);
+    eor(rd_lo, rd_hi, rd_lo, cond);
+  }
+}
+
+void MacroAssembler::long_shift(Register rd_lo, Register rd_hi,
+                                Register rn_lo, Register rn_hi,
+                                AsmShift shift, Register count) {
+  Register tmp;
+  if (rd_lo != rn_lo && rd_lo != rn_hi && rd_lo != count) {
+    tmp = rd_lo;
+  } else {
+    tmp = rd_hi;
+  }
+  assert_different_registers(tmp, count, rn_lo, rn_hi);
+
+  subs(tmp, count, 32);
+  if (shift == lsl) {
+    assert_different_registers(rd_hi, rn_lo);
+    assert_different_registers(count, rd_hi);
+    mov(rd_hi, AsmOperand(rn_lo, shift, tmp), pl);
+    rsb(tmp, count, 32, mi);
+    if (rd_hi == rn_hi) {
+      mov(rd_hi, AsmOperand(rn_hi, lsl, count), mi);
+      orr(rd_hi, rd_hi, AsmOperand(rn_lo, lsr, tmp), mi);
+    } else {
+      mov(rd_hi, AsmOperand(rn_lo, lsr, tmp), mi);
+      orr(rd_hi, rd_hi, AsmOperand(rn_hi, lsl, count), mi);
+    }
+    mov(rd_lo, AsmOperand(rn_lo, shift, count));
+  } else {
+    assert_different_registers(rd_lo, rn_hi);
+    assert_different_registers(rd_lo, count);
+    mov(rd_lo, AsmOperand(rn_hi, shift, tmp), pl);
+    rsb(tmp, count, 32, mi);
+    if (rd_lo == rn_lo) {
+      mov(rd_lo, AsmOperand(rn_lo, lsr, count), mi);
+      orr(rd_lo, rd_lo, AsmOperand(rn_hi, lsl, tmp), mi);
+    } else {
+      mov(rd_lo, AsmOperand(rn_hi, lsl, tmp), mi);
+      orr(rd_lo, rd_lo, AsmOperand(rn_lo, lsr, count), mi);
+    }
+    mov(rd_hi, AsmOperand(rn_hi, shift, count));
+  }
+}
+
+void MacroAssembler::long_shift(Register rd_lo, Register rd_hi,
+                                Register rn_lo, Register rn_hi,
+                                AsmShift shift, int count) {
+  assert(count != 0 && (count & ~63) == 0, "must be");
+
+  if (shift == lsl) {
+    assert_different_registers(rd_hi, rn_lo);
+    if (count >= 32) {
+      mov(rd_hi, AsmOperand(rn_lo, lsl, count - 32));
+      mov(rd_lo, 0);
+    } else {
+      mov(rd_hi, AsmOperand(rn_hi, lsl, count));
+      orr(rd_hi, rd_hi, AsmOperand(rn_lo, lsr, 32 - count));
+      mov(rd_lo, AsmOperand(rn_lo, lsl, count));
+    }
+  } else {
+    assert_different_registers(rd_lo, rn_hi);
+    if (count >= 32) {
+      if (count == 32) {
+        mov(rd_lo, rn_hi);
+      } else {
+        mov(rd_lo, AsmOperand(rn_hi, shift, count - 32));
+      }
+      if (shift == asr) {
+        mov(rd_hi, AsmOperand(rn_hi, asr, 0));
+      } else {
+        mov(rd_hi, 0);
+      }
+    } else {
+      mov(rd_lo, AsmOperand(rn_lo, lsr, count));
+      orr(rd_lo, rd_lo, AsmOperand(rn_hi, lsl, 32 - count));
+      mov(rd_hi, AsmOperand(rn_hi, shift, count));
+    }
+  }
+}
+#endif // !AARCH64
+
+void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, int line) {
+  // This code pattern is matched in NativeIntruction::skip_verify_oop.
+  // Update it at modifications.
+  if (!VerifyOops) return;
+
+  char buffer[64];
+#ifdef COMPILER1
+  if (CommentedAssembly) {
+    snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset());
+    block_comment(buffer);
+  }
+#endif
+  const char* msg_buffer = NULL;
+  {
+    ResourceMark rm;
+    stringStream ss;
+    ss.print("%s at offset %d (%s:%d)", s, offset(), file, line);
+    msg_buffer = code_string(ss.as_string());
+  }
+
+  save_all_registers();
+
+  if (reg != R2) {
+      mov(R2, reg);                              // oop to verify
+  }
+  mov(R1, SP);                                   // register save area
+
+  Label done;
+  InlinedString Lmsg(msg_buffer);
+  ldr_literal(R0, Lmsg);                         // message
+
+  // call indirectly to solve generation ordering problem
+  ldr_global_ptr(Rtemp, StubRoutines::verify_oop_subroutine_entry_address());
+  call(Rtemp);
+
+  restore_all_registers();
+
+  b(done);
+#ifdef COMPILER2
+  int off = offset();
+#endif
+  bind_literal(Lmsg);
+#ifdef COMPILER2
+  if (offset() - off == 1 * wordSize) {
+    // no padding, so insert nop for worst-case sizing
+    nop();
+  }
+#endif
+  bind(done);
+}
+
+void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* file, int line) {
+  if (!VerifyOops) return;
+
+  const char* msg_buffer = NULL;
+  {
+    ResourceMark rm;
+    stringStream ss;
+    if ((addr.base() == SP) && (addr.index()==noreg)) {
+      ss.print("verify_oop_addr SP[%d]: %s", (int)addr.disp(), s);
+    } else {
+      ss.print("verify_oop_addr: %s", s);
+    }
+    ss.print(" (%s:%d)", file, line);
+    msg_buffer = code_string(ss.as_string());
+  }
+
+  int push_size = save_all_registers();
+
+  if (addr.base() == SP) {
+    // computes an addr that takes into account the push
+    if (addr.index() != noreg) {
+      Register new_base = addr.index() == R2 ? R1 : R2; // avoid corrupting the index
+      add(new_base, SP, push_size);
+      addr = addr.rebase(new_base);
+    } else {
+      addr = addr.plus_disp(push_size);
+    }
+  }
+
+  ldr(R2, addr);                                 // oop to verify
+  mov(R1, SP);                                   // register save area
+
+  Label done;
+  InlinedString Lmsg(msg_buffer);
+  ldr_literal(R0, Lmsg);                         // message
+
+  // call indirectly to solve generation ordering problem
+  ldr_global_ptr(Rtemp, StubRoutines::verify_oop_subroutine_entry_address());
+  call(Rtemp);
+
+  restore_all_registers();
+
+  b(done);
+  bind_literal(Lmsg);
+  bind(done);
+}
+
+void MacroAssembler::null_check(Register reg, Register tmp, int offset) {
+  if (needs_explicit_null_check(offset)) {
+#ifdef AARCH64
+    ldr(ZR, Address(reg));
+#else
+    assert_different_registers(reg, tmp);
+    if (tmp == noreg) {
+      tmp = Rtemp;
+      assert((! Thread::current()->is_Compiler_thread()) ||
+             (! (ciEnv::current()->task() == NULL)) ||
+             (! (ciEnv::current()->comp_level() == CompLevel_full_optimization)),
+             "Rtemp not available in C2"); // explicit tmp register required
+      // XXX: could we mark the code buffer as not compatible with C2 ?
+    }
+    ldr(tmp, Address(reg));
+#endif
+  }
+}
+
+// Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`.
+void MacroAssembler::eden_allocate(Register obj, Register obj_end, Register tmp1, Register tmp2,
+                                 RegisterOrConstant size_expression, Label& slow_case) {
+  if (!Universe::heap()->supports_inline_contig_alloc()) {
+    b(slow_case);
+    return;
+  }
+
+  CollectedHeap* ch = Universe::heap();
+
+  const Register top_addr = tmp1;
+  const Register heap_end = tmp2;
+
+  if (size_expression.is_register()) {
+    assert_different_registers(obj, obj_end, top_addr, heap_end, size_expression.as_register());
+  } else {
+    assert_different_registers(obj, obj_end, top_addr, heap_end);
+  }
+
+  bool load_const = AARCH64_ONLY(false) NOT_AARCH64(VM_Version::supports_movw() ); // TODO-AARCH64 check performance
+  if (load_const) {
+    mov_address(top_addr, (address)Universe::heap()->top_addr(), symbolic_Relocation::eden_top_reference);
+  } else {
+    ldr(top_addr, Address(Rthread, JavaThread::heap_top_addr_offset()));
+  }
+  // Calculate new heap_top by adding the size of the object
+  Label retry;
+  bind(retry);
+
+#ifdef AARCH64
+  ldxr(obj, top_addr);
+#else
+  ldr(obj, Address(top_addr));
+#endif // AARCH64
+
+  ldr(heap_end, Address(top_addr, (intptr_t)ch->end_addr() - (intptr_t)ch->top_addr()));
+  add_rc(obj_end, obj, size_expression);
+  // Check if obj_end wrapped around, i.e., obj_end < obj. If yes, jump to the slow case.
+  cmp(obj_end, obj);
+  b(slow_case, lo);
+  // Update heap_top if allocation succeeded
+  cmp(obj_end, heap_end);
+  b(slow_case, hi);
+
+#ifdef AARCH64
+  stxr(heap_end/*scratched*/, obj_end, top_addr);
+  cbnz_w(heap_end, retry);
+#else
+  atomic_cas_bool(obj, obj_end, top_addr, 0, heap_end/*scratched*/);
+  b(retry, ne);
+#endif // AARCH64
+}
+
+// Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`.
+void MacroAssembler::tlab_allocate(Register obj, Register obj_end, Register tmp1,
+                                 RegisterOrConstant size_expression, Label& slow_case) {
+  const Register tlab_end = tmp1;
+  assert_different_registers(obj, obj_end, tlab_end);
+
+  ldr(obj, Address(Rthread, JavaThread::tlab_top_offset()));
+  ldr(tlab_end, Address(Rthread, JavaThread::tlab_end_offset()));
+  add_rc(obj_end, obj, size_expression);
+  cmp(obj_end, tlab_end);
+  b(slow_case, hi);
+  str(obj_end, Address(Rthread, JavaThread::tlab_top_offset()));
+}
+
+void MacroAssembler::tlab_refill(Register top, Register tmp1, Register tmp2,
+                                 Register tmp3, Register tmp4,
+                               Label& try_eden, Label& slow_case) {
+  if (!Universe::heap()->supports_inline_contig_alloc()) {
+    b(slow_case);
+    return;
+  }
+
+  InlinedAddress intArrayKlass_addr((address)Universe::intArrayKlassObj_addr());
+  Label discard_tlab, do_refill;
+  ldr(top,  Address(Rthread, JavaThread::tlab_top_offset()));
+  ldr(tmp1, Address(Rthread, JavaThread::tlab_end_offset()));
+  ldr(tmp2, Address(Rthread, JavaThread::tlab_refill_waste_limit_offset()));
+
+  // Calculate amount of free space
+  sub(tmp1, tmp1, top);
+  // Retain tlab and allocate in shared space
+  // if the amount of free space in tlab is too large to discard
+  cmp(tmp2, AsmOperand(tmp1, lsr, LogHeapWordSize));
+  b(discard_tlab, ge);
+
+  // Increment waste limit to prevent getting stuck on this slow path
+  mov_slow(tmp3, ThreadLocalAllocBuffer::refill_waste_limit_increment());
+  add(tmp2, tmp2, tmp3);
+  str(tmp2, Address(Rthread, JavaThread::tlab_refill_waste_limit_offset()));
+  if (TLABStats) {
+    ldr_u32(tmp2, Address(Rthread, JavaThread::tlab_slow_allocations_offset()));
+    add_32(tmp2, tmp2, 1);
+    str_32(tmp2, Address(Rthread, JavaThread::tlab_slow_allocations_offset()));
+  }
+  b(try_eden);
+  bind_literal(intArrayKlass_addr);
+
+  bind(discard_tlab);
+  if (TLABStats) {
+    ldr_u32(tmp2, Address(Rthread, JavaThread::tlab_number_of_refills_offset()));
+    ldr_u32(tmp3, Address(Rthread, JavaThread::tlab_fast_refill_waste_offset()));
+    add_32(tmp2, tmp2, 1);
+    add_32(tmp3, tmp3, AsmOperand(tmp1, lsr, LogHeapWordSize));
+    str_32(tmp2, Address(Rthread, JavaThread::tlab_number_of_refills_offset()));
+    str_32(tmp3, Address(Rthread, JavaThread::tlab_fast_refill_waste_offset()));
+  }
+  // If tlab is currently allocated (top or end != null)
+  // then fill [top, end + alignment_reserve) with array object
+  cbz(top, do_refill);
+
+  // Set up the mark word
+  mov_slow(tmp2, (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2));
+  str(tmp2, Address(top, oopDesc::mark_offset_in_bytes()));
+  // Set klass to intArrayKlass and the length to the remaining space
+  ldr_literal(tmp2, intArrayKlass_addr);
+  add(tmp1, tmp1, ThreadLocalAllocBuffer::alignment_reserve_in_bytes() -
+      typeArrayOopDesc::header_size(T_INT) * HeapWordSize);
+  Register klass = tmp2;
+  ldr(klass, Address(tmp2));
+  logical_shift_right(tmp1, tmp1, LogBytesPerInt); // divide by sizeof(jint)
+  str_32(tmp1, Address(top, arrayOopDesc::length_offset_in_bytes()));
+  store_klass(klass, top); // blows klass:
+  klass = noreg;
+
+  ldr(tmp1, Address(Rthread, JavaThread::tlab_start_offset()));
+  sub(tmp1, top, tmp1); // size of tlab's allocated portion
+  incr_allocated_bytes(tmp1, tmp2);
+
+  bind(do_refill);
+  // Refill the tlab with an eden allocation
+  ldr(tmp1, Address(Rthread, JavaThread::tlab_size_offset()));
+  logical_shift_left(tmp4, tmp1, LogHeapWordSize);
+  eden_allocate(top, tmp1, tmp2, tmp3, tmp4, slow_case);
+  str(top, Address(Rthread, JavaThread::tlab_start_offset()));
+  str(top, Address(Rthread, JavaThread::tlab_top_offset()));
+
+#ifdef ASSERT
+  // Verify that tmp1 contains tlab_end
+  ldr(tmp2, Address(Rthread, JavaThread::tlab_size_offset()));
+  add(tmp2, top, AsmOperand(tmp2, lsl, LogHeapWordSize));
+  cmp(tmp1, tmp2);
+  breakpoint(ne);
+#endif
+
+  sub(tmp1, tmp1, ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
+  str(tmp1, Address(Rthread, JavaThread::tlab_end_offset()));
+
+  if (ZeroTLAB) {
+    // clobbers start and tmp
+    // top must be preserved!
+    add(tmp1, tmp1, ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
+    ldr(tmp2, Address(Rthread, JavaThread::tlab_start_offset()));
+    zero_memory(tmp2, tmp1, tmp3);
+  }
+}
+
+// Fills memory regions [start..end] with zeroes. Clobbers `start` and `tmp` registers.
+void MacroAssembler::zero_memory(Register start, Register end, Register tmp) {
+  Label loop;
+  const Register ptr = start;
+
+#ifdef AARCH64
+  // TODO-AARCH64 - compare performance of 2x word zeroing with simple 1x
+  const Register size = tmp;
+  Label remaining, done;
+
+  sub(size, end, start);
+
+#ifdef ASSERT
+  { Label L;
+    tst(size, wordSize - 1);
+    b(L, eq);
+    stop("size is not a multiple of wordSize");
+    bind(L);
+  }
+#endif // ASSERT
+
+  subs(size, size, wordSize);
+  b(remaining, le);
+
+  // Zero by 2 words per iteration.
+  bind(loop);
+  subs(size, size, 2*wordSize);
+  stp(ZR, ZR, Address(ptr, 2*wordSize, post_indexed));
+  b(loop, gt);
+
+  bind(remaining);
+  b(done, ne);
+  str(ZR, Address(ptr));
+  bind(done);
+#else
+  mov(tmp, 0);
+  bind(loop);
+  cmp(ptr, end);
+  str(tmp, Address(ptr, wordSize, post_indexed), lo);
+  b(loop, lo);
+#endif // AARCH64
+}
+
+void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register tmp) {
+#ifdef AARCH64
+  ldr(tmp, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())));
+  add_rc(tmp, tmp, size_in_bytes);
+  str(tmp, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())));
+#else
+  // Bump total bytes allocated by this thread
+  Label done;
+
+  ldr(tmp, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())));
+  adds(tmp, tmp, size_in_bytes);
+  str(tmp, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())), cc);
+  b(done, cc);
+
+  // Increment the high word and store single-copy atomically (that is an unlikely scenario on typical embedded systems as it means >4GB has been allocated)
+  // To do so ldrd/strd instructions used which require an even-odd pair of registers. Such a request could be difficult to satisfy by
+  // allocating those registers on a higher level, therefore the routine is ready to allocate a pair itself.
+  Register low, high;
+  // Select ether R0/R1 or R2/R3
+
+  if (size_in_bytes.is_register() && (size_in_bytes.as_register() == R0 || size_in_bytes.as_register() == R1)) {
+    low = R2;
+    high  = R3;
+  } else {
+    low = R0;
+    high  = R1;
+  }
+  push(RegisterSet(low, high));
+
+  ldrd(low, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())));
+  adds(low, low, size_in_bytes);
+  adc(high, high, 0);
+  strd(low, Address(Rthread, in_bytes(JavaThread::allocated_bytes_offset())));
+
+  pop(RegisterSet(low, high));
+
+  bind(done);
+#endif // AARCH64
+}
+
+void MacroAssembler::arm_stack_overflow_check(int frame_size_in_bytes, Register tmp) {
+  // Version of AbstractAssembler::generate_stack_overflow_check optimized for ARM
+  if (UseStackBanging) {
+    const int page_size = os::vm_page_size();
+
+    sub_slow(tmp, SP, JavaThread::stack_shadow_zone_size());
+    strb(R0, Address(tmp));
+#ifdef AARCH64
+    for (; frame_size_in_bytes >= page_size; frame_size_in_bytes -= page_size) {
+      sub(tmp, tmp, page_size);
+      strb(R0, Address(tmp));
+    }
+#else
+    for (; frame_size_in_bytes >= page_size; frame_size_in_bytes -= 0xff0) {
+      strb(R0, Address(tmp, -0xff0, pre_indexed));
+    }
+#endif // AARCH64
+  }
+}
+
+void MacroAssembler::arm_stack_overflow_check(Register Rsize, Register tmp) {
+  if (UseStackBanging) {
+    Label loop;
+
+    mov(tmp, SP);
+    add_slow(Rsize, Rsize, JavaThread::stack_shadow_zone_size() - os::vm_page_size());
+#ifdef AARCH64
+    sub(tmp, tmp, Rsize);
+    bind(loop);
+    subs(Rsize, Rsize, os::vm_page_size());
+    strb(ZR, Address(tmp, Rsize));
+#else
+    bind(loop);
+    subs(Rsize, Rsize, 0xff0);
+    strb(R0, Address(tmp, -0xff0, pre_indexed));
+#endif // AARCH64
+    b(loop, hi);
+  }
+}
+
+void MacroAssembler::stop(const char* msg) {
+  // This code pattern is matched in NativeIntruction::is_stop.
+  // Update it at modifications.
+#ifdef COMPILER1
+  if (CommentedAssembly) {
+    block_comment("stop");
+  }
+#endif
+
+  InlinedAddress Ldebug(CAST_FROM_FN_PTR(address, MacroAssembler::debug));
+  InlinedString Lmsg(msg);
+
+  // save all registers for further inspection
+  save_all_registers();
+
+  ldr_literal(R0, Lmsg);                     // message
+  mov(R1, SP);                               // register save area
+
+#ifdef AARCH64
+  ldr_literal(Rtemp, Ldebug);
+  br(Rtemp);
+#else
+  ldr_literal(PC, Ldebug);                   // call MacroAssembler::debug
+#endif // AARCH64
+
+#if defined(COMPILER2) && defined(AARCH64)
+  int off = offset();
+#endif
+  bind_literal(Lmsg);
+  bind_literal(Ldebug);
+#if defined(COMPILER2) && defined(AARCH64)
+  if (offset() - off == 2 * wordSize) {
+    // no padding, so insert nop for worst-case sizing
+    nop();
+  }
+#endif
+}
+
+void MacroAssembler::warn(const char* msg) {
+#ifdef COMPILER1
+  if (CommentedAssembly) {
+    block_comment("warn");
+  }
+#endif
+
+  InlinedAddress Lwarn(CAST_FROM_FN_PTR(address, warning));
+  InlinedString Lmsg(msg);
+  Label done;
+
+  int push_size = save_caller_save_registers();
+
+#ifdef AARCH64
+  // TODO-AARCH64 - get rid of extra debug parameters
+  mov(R1, LR);
+  mov(R2, FP);
+  add(R3, SP, push_size);
+#endif
+
+  ldr_literal(R0, Lmsg);                    // message
+  ldr_literal(LR, Lwarn);                   // call warning
+
+  call(LR);
+
+  restore_caller_save_registers();
+
+  b(done);
+  bind_literal(Lmsg);
+  bind_literal(Lwarn);
+  bind(done);
+}
+
+
+int MacroAssembler::save_all_registers() {
+  // This code pattern is matched in NativeIntruction::is_save_all_registers.
+  // Update it at modifications.
+#ifdef AARCH64
+  const Register tmp = Rtemp;
+  raw_push(R30, ZR);
+  for (int i = 28; i >= 0; i -= 2) {
+      raw_push(as_Register(i), as_Register(i+1));
+  }
+  mov_pc_to(tmp);
+  str(tmp, Address(SP, 31*wordSize));
+  ldr(tmp, Address(SP, tmp->encoding()*wordSize));
+  return 32*wordSize;
+#else
+  push(RegisterSet(R0, R12) | RegisterSet(LR) | RegisterSet(PC));
+  return 15*wordSize;
+#endif // AARCH64
+}
+
+void MacroAssembler::restore_all_registers() {
+#ifdef AARCH64
+  for (int i = 0; i <= 28; i += 2) {
+    raw_pop(as_Register(i), as_Register(i+1));
+  }
+  raw_pop(R30, ZR);
+#else
+  pop(RegisterSet(R0, R12) | RegisterSet(LR));   // restore registers
+  add(SP, SP, wordSize);                         // discard saved PC
+#endif // AARCH64
+}
+
+int MacroAssembler::save_caller_save_registers() {
+#ifdef AARCH64
+  for (int i = 0; i <= 16; i += 2) {
+    raw_push(as_Register(i), as_Register(i+1));
+  }
+  raw_push(R18, LR);
+  return 20*wordSize;
+#else
+#if R9_IS_SCRATCHED
+  // Save also R10 to preserve alignment
+  push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR) | RegisterSet(R9,R10));
+  return 8*wordSize;
+#else
+  push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR));
+  return 6*wordSize;
+#endif
+#endif // AARCH64
+}
+
+void MacroAssembler::restore_caller_save_registers() {
+#ifdef AARCH64
+  raw_pop(R18, LR);
+  for (int i = 16; i >= 0; i -= 2) {
+    raw_pop(as_Register(i), as_Register(i+1));
+  }
+#else
+#if R9_IS_SCRATCHED
+  pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR) | RegisterSet(R9,R10));
+#else
+  pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR));
+#endif
+#endif // AARCH64
+}
+
+void MacroAssembler::debug(const char* msg, const intx* registers) {
+  // In order to get locks to work, we need to fake a in_VM state
+  JavaThread* thread = JavaThread::current();
+  thread->set_thread_state(_thread_in_vm);
+
+  if (ShowMessageBoxOnError) {
+    ttyLocker ttyl;
+    if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
+      BytecodeCounter::print();
+    }
+    if (os::message_box(msg, "Execution stopped, print registers?")) {
+#ifdef AARCH64
+      // saved registers: R0-R30, PC
+      const int nregs = 32;
+#else
+      // saved registers: R0-R12, LR, PC
+      const int nregs = 15;
+      const Register regs[nregs] = {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, PC};
+#endif // AARCH64
+
+      for (int i = 0; i < nregs AARCH64_ONLY(-1); i++) {
+        tty->print_cr("%s = " INTPTR_FORMAT, AARCH64_ONLY(as_Register(i)) NOT_AARCH64(regs[i])->name(), registers[i]);
+      }
+
+#ifdef AARCH64
+      tty->print_cr("pc = " INTPTR_FORMAT, registers[nregs-1]);
+#endif // AARCH64
+
+      // derive original SP value from the address of register save area
+      tty->print_cr("%s = " INTPTR_FORMAT, SP->name(), p2i(&registers[nregs]));
+    }
+    BREAKPOINT;
+  } else {
+    ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
+  }
+  assert(false, "DEBUG MESSAGE: %s", msg);
+  fatal("%s", msg); // returning from MacroAssembler::debug is not supported
+}
+
+void MacroAssembler::unimplemented(const char* what) {
+  const char* buf = NULL;
+  {
+    ResourceMark rm;
+    stringStream ss;
+    ss.print("unimplemented: %s", what);
+    buf = code_string(ss.as_string());
+  }
+  stop(buf);
+}
+
+
+// Implementation of FixedSizeCodeBlock
+
+FixedSizeCodeBlock::FixedSizeCodeBlock(MacroAssembler* masm, int size_in_instrs, bool enabled) :
+_masm(masm), _start(masm->pc()), _size_in_instrs(size_in_instrs), _enabled(enabled) {
+}
+
+FixedSizeCodeBlock::~FixedSizeCodeBlock() {
+  if (_enabled) {
+    address curr_pc = _masm->pc();
+
+    assert(_start < curr_pc, "invalid current pc");
+    guarantee(curr_pc <= _start + _size_in_instrs * Assembler::InstructionSize, "code block is too long");
+
+    int nops_count = (_start - curr_pc) / Assembler::InstructionSize + _size_in_instrs;
+    for (int i = 0; i < nops_count; i++) {
+      _masm->nop();
+    }
+  }
+}
+
+#ifdef AARCH64
+
+// Serializes memory.
+// tmp register is not used on AArch64, this parameter is provided solely for better compatibility with 32-bit ARM
+void MacroAssembler::membar(Membar_mask_bits order_constraint, Register tmp) {
+  if (!os::is_MP()) return;
+
+  // TODO-AARCH64 investigate dsb vs dmb effects
+  if (order_constraint == StoreStore) {
+    dmb(DMB_st);
+  } else if ((order_constraint & ~(LoadLoad | LoadStore)) == 0) {
+    dmb(DMB_ld);
+  } else {
+    dmb(DMB_all);
+  }
+}
+
+#else
+
+// Serializes memory. Potentially blows flags and reg.
+// tmp is a scratch for v6 co-processor write op (could be noreg for other architecure versions)
+// preserve_flags takes a longer path in LoadStore case (dmb rather then control dependency) to preserve status flags. Optional.
+// load_tgt is an ordered load target in a LoadStore case only, to create dependency between the load operation and conditional branch. Optional.
+void MacroAssembler::membar(Membar_mask_bits order_constraint,
+                            Register tmp,
+                            bool preserve_flags,
+                            Register load_tgt) {
+  if (!os::is_MP()) return;
+
+  if (order_constraint == StoreStore) {
+    dmb(DMB_st, tmp);
+  } else if ((order_constraint & StoreLoad)  ||
+             (order_constraint & LoadLoad)   ||
+             (order_constraint & StoreStore) ||
+             (load_tgt == noreg)             ||
+             preserve_flags) {
+    dmb(DMB_all, tmp);
+  } else {
+    // LoadStore: speculative stores reordeing is prohibited
+
+    // By providing an ordered load target register, we avoid an extra memory load reference
+    Label not_taken;
+    bind(not_taken);
+    cmp(load_tgt, load_tgt);
+    b(not_taken, ne);
+  }
+}
+
+#endif // AARCH64
+
+// If "allow_fallthrough_on_failure" is false, we always branch to "slow_case"
+// on failure, so fall-through can only mean success.
+// "one_shot" controls whether we loop and retry to mitigate spurious failures.
+// This is only needed for C2, which for some reason does not rety,
+// while C1/interpreter does.
+// TODO: measure if it makes a difference
+
+void MacroAssembler::cas_for_lock_acquire(Register oldval, Register newval,
+  Register base, Register tmp, Label &slow_case,
+  bool allow_fallthrough_on_failure, bool one_shot)
+{
+
+  bool fallthrough_is_success = false;
+
+  // ARM Litmus Test example does prefetching here.
+  // TODO: investigate if it helps performance
+
+  // The last store was to the displaced header, so to prevent
+  // reordering we must issue a StoreStore or Release barrier before
+  // the CAS store.
+
+#ifdef AARCH64
+
+  Register Rscratch = tmp;
+  Register Roop = base;
+  Register mark = oldval;
+  Register Rbox = newval;
+  Label loop;
+
+  assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
+
+  // Instead of StoreStore here, we use store-release-exclusive below
+
+  bind(loop);
+
+  ldaxr(tmp, base);  // acquire
+  cmp(tmp, oldval);
+  b(slow_case, ne);
+  stlxr(tmp, newval, base); // release
+  if (one_shot) {
+    cmp_w(tmp, 0);
+  } else {
+    cbnz_w(tmp, loop);
+    fallthrough_is_success = true;
+  }
+
+  // MemBarAcquireLock would normally go here, but
+  // we already do ldaxr+stlxr above, which has
+  // Sequential Consistency
+
+#else
+  membar(MacroAssembler::StoreStore, noreg);
+
+  if (one_shot) {
+    ldrex(tmp, Address(base, oopDesc::mark_offset_in_bytes()));
+    cmp(tmp, oldval);
+    strex(tmp, newval, Address(base, oopDesc::mark_offset_in_bytes()), eq);
+    cmp(tmp, 0, eq);
+  } else {
+    atomic_cas_bool(oldval, newval, base, oopDesc::mark_offset_in_bytes(), tmp);
+  }
+
+  // MemBarAcquireLock barrier
+  // According to JSR-133 Cookbook, this should be LoadLoad | LoadStore,
+  // but that doesn't prevent a load or store from floating up between
+  // the load and store in the CAS sequence, so play it safe and
+  // do a full fence.
+  membar(Membar_mask_bits(LoadLoad | LoadStore | StoreStore | StoreLoad), noreg);
+#endif
+  if (!fallthrough_is_success && !allow_fallthrough_on_failure) {
+    b(slow_case, ne);
+  }
+}
+
+void MacroAssembler::cas_for_lock_release(Register oldval, Register newval,
+  Register base, Register tmp, Label &slow_case,
+  bool allow_fallthrough_on_failure, bool one_shot)
+{
+
+  bool fallthrough_is_success = false;
+
+  assert_different_registers(oldval,newval,base,tmp);
+
+#ifdef AARCH64
+  Label loop;
+
+  assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
+
+  bind(loop);
+  ldxr(tmp, base);
+  cmp(tmp, oldval);
+  b(slow_case, ne);
+  // MemBarReleaseLock barrier
+  stlxr(tmp, newval, base);
+  if (one_shot) {
+    cmp_w(tmp, 0);
+  } else {
+    cbnz_w(tmp, loop);
+    fallthrough_is_success = true;
+  }
+#else
+  // MemBarReleaseLock barrier
+  // According to JSR-133 Cookbook, this should be StoreStore | LoadStore,
+  // but that doesn't prevent a load or store from floating down between
+  // the load and store in the CAS sequence, so play it safe and
+  // do a full fence.
+  membar(Membar_mask_bits(LoadLoad | LoadStore | StoreStore | StoreLoad), tmp);
+
+  if (one_shot) {
+    ldrex(tmp, Address(base, oopDesc::mark_offset_in_bytes()));
+    cmp(tmp, oldval);
+    strex(tmp, newval, Address(base, oopDesc::mark_offset_in_bytes()), eq);
+    cmp(tmp, 0, eq);
+  } else {
+    atomic_cas_bool(oldval, newval, base, oopDesc::mark_offset_in_bytes(), tmp);
+  }
+#endif
+  if (!fallthrough_is_success && !allow_fallthrough_on_failure) {
+    b(slow_case, ne);
+  }
+
+  // ExitEnter
+  // According to JSR-133 Cookbook, this should be StoreLoad, the same
+  // barrier that follows volatile store.
+  // TODO: Should be able to remove on armv8 if volatile loads
+  // use the load-acquire instruction.
+  membar(StoreLoad, noreg);
+}
+
+#ifndef PRODUCT
+
+// Preserves flags and all registers.
+// On SMP the updated value might not be visible to external observers without a sychronization barrier
+void MacroAssembler::cond_atomic_inc32(AsmCondition cond, int* counter_addr) {
+  if (counter_addr != NULL) {
+    InlinedAddress counter_addr_literal((address)counter_addr);
+    Label done, retry;
+    if (cond != al) {
+      b(done, inverse(cond));
+    }
+
+#ifdef AARCH64
+    raw_push(R0, R1);
+    raw_push(R2, ZR);
+
+    ldr_literal(R0, counter_addr_literal);
+
+    bind(retry);
+    ldxr_w(R1, R0);
+    add_w(R1, R1, 1);
+    stxr_w(R2, R1, R0);
+    cbnz_w(R2, retry);
+
+    raw_pop(R2, ZR);
+    raw_pop(R0, R1);
+#else
+    push(RegisterSet(R0, R3) | RegisterSet(Rtemp));
+    ldr_literal(R0, counter_addr_literal);
+
+    mrs(CPSR, Rtemp);
+
+    bind(retry);
+    ldr_s32(R1, Address(R0));
+    add(R2, R1, 1);
+    atomic_cas_bool(R1, R2, R0, 0, R3);
+    b(retry, ne);
+
+    msr(CPSR_fsxc, Rtemp);
+
+    pop(RegisterSet(R0, R3) | RegisterSet(Rtemp));
+#endif // AARCH64
+
+    b(done);
+    bind_literal(counter_addr_literal);
+
+    bind(done);
+  }
+}
+
+#endif // !PRODUCT
+
+
+// Building block for CAS cases of biased locking: makes CAS and records statistics.
+// The slow_case label is used to transfer control if CAS fails. Otherwise leaves condition codes set.
+void MacroAssembler::biased_locking_enter_with_cas(Register obj_reg, Register old_mark_reg, Register new_mark_reg,
+                                                 Register tmp, Label& slow_case, int* counter_addr) {
+
+  cas_for_lock_acquire(old_mark_reg, new_mark_reg, obj_reg, tmp, slow_case);
+#ifdef ASSERT
+  breakpoint(ne); // Fallthrough only on success
+#endif
+#ifndef PRODUCT
+  if (counter_addr != NULL) {
+    cond_atomic_inc32(al, counter_addr);
+  }
+#endif // !PRODUCT
+}
+
+int MacroAssembler::biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
+                                         bool swap_reg_contains_mark,
+                                         Register tmp2,
+                                         Label& done, Label& slow_case,
+                                         BiasedLockingCounters* counters) {
+  // obj_reg must be preserved (at least) if the bias locking fails
+  // tmp_reg is a temporary register
+  // swap_reg was used as a temporary but contained a value
+  //   that was used afterwards in some call pathes. Callers
+  //   have been fixed so that swap_reg no longer needs to be
+  //   saved.
+  // Rtemp in no longer scratched
+
+  assert(UseBiasedLocking, "why call this otherwise?");
+  assert_different_registers(obj_reg, swap_reg, tmp_reg, tmp2);
+  guarantee(swap_reg!=tmp_reg, "invariant");
+  assert(tmp_reg != noreg, "must supply tmp_reg");
+
+#ifndef PRODUCT
+  if (PrintBiasedLockingStatistics && (counters == NULL)) {
+    counters = BiasedLocking::counters();
+  }
+#endif
+
+  assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
+  Address mark_addr(obj_reg, oopDesc::mark_offset_in_bytes());
+
+  // Biased locking
+  // See whether the lock is currently biased toward our thread and
+  // whether the epoch is still valid
+  // Note that the runtime guarantees sufficient alignment of JavaThread
+  // pointers to allow age to be placed into low bits
+  // First check to see whether biasing is even enabled for this object
+  Label cas_label;
+
+  // The null check applies to the mark loading, if we need to load it.
+  // If the mark has already been loaded in swap_reg then it has already
+  // been performed and the offset is irrelevant.
+  int null_check_offset = offset();
+  if (!swap_reg_contains_mark) {
+    ldr(swap_reg, mark_addr);
+  }
+
+  // On MP platform loads could return 'stale' values in some cases.
+  // That is acceptable since either CAS or slow case path is taken in the worst case.
+
+  andr(tmp_reg, swap_reg, (uintx)markOopDesc::biased_lock_mask_in_place);
+  cmp(tmp_reg, markOopDesc::biased_lock_pattern);
+
+  b(cas_label, ne);
+
+  // The bias pattern is present in the object's header. Need to check
+  // whether the bias owner and the epoch are both still current.
+  load_klass(tmp_reg, obj_reg);
+  ldr(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset()));
+  orr(tmp_reg, tmp_reg, Rthread);
+  eor(tmp_reg, tmp_reg, swap_reg);
+
+#ifdef AARCH64
+  ands(tmp_reg, tmp_reg, ~((uintx) markOopDesc::age_mask_in_place));
+#else
+  bics(tmp_reg, tmp_reg, ((int) markOopDesc::age_mask_in_place));
+#endif // AARCH64
+
+#ifndef PRODUCT
+  if (counters != NULL) {
+    cond_atomic_inc32(eq, counters->biased_lock_entry_count_addr());
+  }
+#endif // !PRODUCT
+
+  b(done, eq);
+
+  Label try_revoke_bias;
+  Label try_rebias;
+
+  // At this point we know that the header has the bias pattern and
+  // that we are not the bias owner in the current epoch. We need to
+  // figure out more details about the state of the header in order to
+  // know what operations can be legally performed on the object's
+  // header.
+
+  // If the low three bits in the xor result aren't clear, that means
+  // the prototype header is no longer biased and we have to revoke
+  // the bias on this object.
+  tst(tmp_reg, (uintx)markOopDesc::biased_lock_mask_in_place);
+  b(try_revoke_bias, ne);
+
+  // Biasing is still enabled for this data type. See whether the
+  // epoch of the current bias is still valid, meaning that the epoch
+  // bits of the mark word are equal to the epoch bits of the
+  // prototype header. (Note that the prototype header's epoch bits
+  // only change at a safepoint.) If not, attempt to rebias the object
+  // toward the current thread. Note that we must be absolutely sure
+  // that the current epoch is invalid in order to do this because
+  // otherwise the manipulations it performs on the mark word are
+  // illegal.
+  tst(tmp_reg, (uintx)markOopDesc::epoch_mask_in_place);
+  b(try_rebias, ne);
+
+  // tmp_reg has the age, epoch and pattern bits cleared
+  // The remaining (owner) bits are (Thread ^ current_owner)
+
+  // The epoch of the current bias is still valid but we know nothing
+  // about the owner; it might be set or it might be clear. Try to
+  // acquire the bias of the object using an atomic operation. If this
+  // fails we will go in to the runtime to revoke the object's bias.
+  // Note that we first construct the presumed unbiased header so we
+  // don't accidentally blow away another thread's valid bias.
+
+  // Note that we know the owner is not ourself. Hence, success can
+  // only happen when the owner bits is 0
+
+#ifdef AARCH64
+  // Bit mask biased_lock + age + epoch is not a valid AArch64 logical immediate, as it has
+  // cleared bit in the middle (cms bit). So it is loaded with separate instruction.
+  mov(tmp2, (markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place));
+  andr(swap_reg, swap_reg, tmp2);
+#else
+  // until the assembler can be made smarter, we need to make some assumptions about the values
+  // so we can optimize this:
+  assert((markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place) == 0x1ff, "biased bitmasks changed");
+
+  mov(swap_reg, AsmOperand(swap_reg, lsl, 23));
+  mov(swap_reg, AsmOperand(swap_reg, lsr, 23)); // markOop with thread bits cleared (for CAS)
+#endif // AARCH64
+
+  orr(tmp_reg, swap_reg, Rthread); // new mark
+
+  biased_locking_enter_with_cas(obj_reg, swap_reg, tmp_reg, tmp2, slow_case,
+        (counters != NULL) ? counters->anonymously_biased_lock_entry_count_addr() : NULL);
+
+  // If the biasing toward our thread failed, this means that
+  // another thread succeeded in biasing it toward itself and we
+  // need to revoke that bias. The revocation will occur in the
+  // interpreter runtime in the slow case.
+
+  b(done);
+
+  bind(try_rebias);
+
+  // At this point we know the epoch has expired, meaning that the
+  // current "bias owner", if any, is actually invalid. Under these
+  // circumstances _only_, we are allowed to use the current header's
+  // value as the comparison value when doing the cas to acquire the
+  // bias in the current epoch. In other words, we allow transfer of
+  // the bias from one thread to another directly in this situation.
+
+  // tmp_reg low (not owner) bits are (age: 0 | pattern&epoch: prototype^swap_reg)
+
+  eor(tmp_reg, tmp_reg, swap_reg); // OK except for owner bits (age preserved !)
+
+  // owner bits 'random'. Set them to Rthread.
+#ifdef AARCH64
+  mov(tmp2, (markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place));
+  andr(tmp_reg, tmp_reg, tmp2);
+#else
+  mov(tmp_reg, AsmOperand(tmp_reg, lsl, 23));
+  mov(tmp_reg, AsmOperand(tmp_reg, lsr, 23));
+#endif // AARCH64
+
+  orr(tmp_reg, tmp_reg, Rthread); // new mark
+
+  biased_locking_enter_with_cas(obj_reg, swap_reg, tmp_reg, tmp2, slow_case,
+        (counters != NULL) ? counters->rebiased_lock_entry_count_addr() : NULL);
+
+  // If the biasing toward our thread failed, then another thread
+  // succeeded in biasing it toward itself and we need to revoke that
+  // bias. The revocation will occur in the runtime in the slow case.
+
+  b(done);
+
+  bind(try_revoke_bias);
+
+  // The prototype mark in the klass doesn't have the bias bit set any
+  // more, indicating that objects of this data type are not supposed
+  // to be biased any more. We are going to try to reset the mark of
+  // this object to the prototype value and fall through to the
+  // CAS-based locking scheme. Note that if our CAS fails, it means
+  // that another thread raced us for the privilege of revoking the
+  // bias of this particular object, so it's okay to continue in the
+  // normal locking code.
+
+  // tmp_reg low (not owner) bits are (age: 0 | pattern&epoch: prototype^swap_reg)
+
+  eor(tmp_reg, tmp_reg, swap_reg); // OK except for owner bits (age preserved !)
+
+  // owner bits 'random'. Clear them
+#ifdef AARCH64
+  mov(tmp2, (markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place));
+  andr(tmp_reg, tmp_reg, tmp2);
+#else
+  mov(tmp_reg, AsmOperand(tmp_reg, lsl, 23));
+  mov(tmp_reg, AsmOperand(tmp_reg, lsr, 23));
+#endif // AARCH64
+
+  biased_locking_enter_with_cas(obj_reg, swap_reg, tmp_reg, tmp2, cas_label,
+        (counters != NULL) ? counters->revoked_lock_entry_count_addr() : NULL);
+
+  // Fall through to the normal CAS-based lock, because no matter what
+  // the result of the above CAS, some thread must have succeeded in
+  // removing the bias bit from the object's header.
+
+  bind(cas_label);
+
+  return null_check_offset;
+}
+
+
+void MacroAssembler::biased_locking_exit(Register obj_reg, Register tmp_reg, Label& done) {
+  assert(UseBiasedLocking, "why call this otherwise?");
+
+  // Check for biased locking unlock case, which is a no-op
+  // Note: we do not have to check the thread ID for two reasons.
+  // First, the interpreter checks for IllegalMonitorStateException at
+  // a higher level. Second, if the bias was revoked while we held the
+  // lock, the object could not be rebiased toward another thread, so
+  // the bias bit would be clear.
+  ldr(tmp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
+
+  andr(tmp_reg, tmp_reg, (uintx)markOopDesc::biased_lock_mask_in_place);
+  cmp(tmp_reg, markOopDesc::biased_lock_pattern);
+  b(done, eq);
+}
+
+#ifdef AARCH64
+
+void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) {
+  switch (size_in_bytes) {
+    case  8: ldr(dst, src); break;
+    case  4: is_signed ? ldr_s32(dst, src) : ldr_u32(dst, src); break;
+    case  2: is_signed ? ldrsh(dst, src) : ldrh(dst, src); break;
+    case  1: is_signed ? ldrsb(dst, src) : ldrb(dst, src); break;
+    default: ShouldNotReachHere();
+  }
+}
+
+void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes) {
+  switch (size_in_bytes) {
+    case  8: str(src, dst);    break;
+    case  4: str_32(src, dst); break;
+    case  2: strh(src, dst);   break;
+    case  1: strb(src, dst);   break;
+    default: ShouldNotReachHere();
+  }
+}
+
+#else
+
+void MacroAssembler::load_sized_value(Register dst, Address src,
+                                    size_t size_in_bytes, bool is_signed, AsmCondition cond) {
+  switch (size_in_bytes) {
+    case  4: ldr(dst, src, cond); break;
+    case  2: is_signed ? ldrsh(dst, src, cond) : ldrh(dst, src, cond); break;
+    case  1: is_signed ? ldrsb(dst, src, cond) : ldrb(dst, src, cond); break;
+    default: ShouldNotReachHere();
+  }
+}
+
+
+void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes, AsmCondition cond) {
+  switch (size_in_bytes) {
+    case  4: str(src, dst, cond); break;
+    case  2: strh(src, dst, cond);   break;
+    case  1: strb(src, dst, cond);   break;
+    default: ShouldNotReachHere();
+  }
+}
+#endif // AARCH64
+
+// Look up the method for a megamorphic invokeinterface call.
+// The target method is determined by <Rinterf, Rindex>.
+// The receiver klass is in Rklass.
+// On success, the result will be in method_result, and execution falls through.
+// On failure, execution transfers to the given label.
+void MacroAssembler::lookup_interface_method(Register Rklass,
+                                             Register Rinterf,
+                                             Register Rindex,
+                                             Register method_result,
+                                             Register temp_reg1,
+                                             Register temp_reg2,
+                                             Label& L_no_such_interface) {
+
+  assert_different_registers(Rklass, Rinterf, temp_reg1, temp_reg2, Rindex);
+
+  Register Ritable = temp_reg1;
+
+  // Compute start of first itableOffsetEntry (which is at the end of the vtable)
+  const int base = in_bytes(Klass::vtable_start_offset());
+  const int scale = exact_log2(vtableEntry::size_in_bytes());
+  ldr_s32(temp_reg2, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable
+  add(Ritable, Rklass, base);
+  add(Ritable, Ritable, AsmOperand(temp_reg2, lsl, scale));
+
+  Label entry, search;
+
+  b(entry);
+
+  bind(search);
+  add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize);
+
+  bind(entry);
+
+  // Check that the entry is non-null.  A null entry means that the receiver
+  // class doesn't implement the interface, and wasn't the same as the
+  // receiver class checked when the interface was resolved.
+
+  ldr(temp_reg2, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes()));
+  cbz(temp_reg2, L_no_such_interface);
+
+  cmp(Rinterf, temp_reg2);
+  b(search, ne);
+
+  ldr_s32(temp_reg2, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes()));
+  add(temp_reg2, temp_reg2, Rklass); // Add offset to Klass*
+  assert(itableMethodEntry::size() * HeapWordSize == wordSize, "adjust the scaling in the code below");
+  assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust the offset in the code below");
+
+  ldr(method_result, Address::indexed_ptr(temp_reg2, Rindex));
+}
+
+#ifdef COMPILER2
+// TODO: 8 bytes at a time? pre-fetch?
+// Compare char[] arrays aligned to 4 bytes.
+void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
+                                        Register limit, Register result,
+                                      Register chr1, Register chr2, Label& Ldone) {
+  Label Lvector, Lloop;
+
+  // Note: limit contains number of bytes (2*char_elements) != 0.
+  tst(limit, 0x2); // trailing character ?
+  b(Lvector, eq);
+
+  // compare the trailing char
+  sub(limit, limit, sizeof(jchar));
+  ldrh(chr1, Address(ary1, limit));
+  ldrh(chr2, Address(ary2, limit));
+  cmp(chr1, chr2);
+  mov(result, 0, ne);     // not equal
+  b(Ldone, ne);
+
+  // only one char ?
+  tst(limit, limit);
+  mov(result, 1, eq);
+  b(Ldone, eq);
+
+  // word by word compare, dont't need alignment check
+  bind(Lvector);
+
+  // Shift ary1 and ary2 to the end of the arrays, negate limit
+  add(ary1, limit, ary1);
+  add(ary2, limit, ary2);
+  neg(limit, limit);
+
+  bind(Lloop);
+  ldr_u32(chr1, Address(ary1, limit));
+  ldr_u32(chr2, Address(ary2, limit));
+  cmp_32(chr1, chr2);
+  mov(result, 0, ne);     // not equal
+  b(Ldone, ne);
+  adds(limit, limit, 2*sizeof(jchar));
+  b(Lloop, ne);
+
+  // Caller should set it:
+  // mov(result_reg, 1);  //equal
+}
+#endif
+
+void MacroAssembler::inc_counter(address counter_addr, Register tmpreg1, Register tmpreg2) {
+  mov_slow(tmpreg1, counter_addr);
+  ldr_s32(tmpreg2, tmpreg1);
+  add_32(tmpreg2, tmpreg2, 1);
+  str_32(tmpreg2, tmpreg1);
+}
+
+void MacroAssembler::floating_cmp(Register dst) {
+#ifdef AARCH64
+  NOT_TESTED();
+  cset(dst, gt);            // 1 if '>', else 0
+  csinv(dst, dst, ZR, ge);  // previous value if '>=', else -1
+#else
+  vmrs(dst, FPSCR);
+  orr(dst, dst, 0x08000000);
+  eor(dst, dst, AsmOperand(dst, lsl, 3));
+  mov(dst, AsmOperand(dst, asr, 30));
+#endif
+}
+
+void MacroAssembler::restore_default_fp_mode() {
+#ifdef AARCH64
+  msr(SysReg_FPCR, ZR);
+#else
+#ifndef __SOFTFP__
+  // Round to Near mode, IEEE compatible, masked exceptions
+  mov(Rtemp, 0);
+  vmsr(FPSCR, Rtemp);
+#endif // !__SOFTFP__
+#endif // AARCH64
+}
+
+#ifndef AARCH64
+// 24-bit word range == 26-bit byte range
+bool check26(int offset) {
+  // this could be simplified, but it mimics encoding and decoding
+  // an actual branch insrtuction
+  int off1 = offset << 6 >> 8;
+  int encoded = off1 & ((1<<24)-1);
+  int decoded = encoded << 8 >> 6;
+  return offset == decoded;
+}
+#endif // !AARCH64
+
+// Perform some slight adjustments so the default 32MB code cache
+// is fully reachable.
+static inline address first_cache_address() {
+  return CodeCache::low_bound() + sizeof(HeapBlock::Header);
+}
+static inline address last_cache_address() {
+  return CodeCache::high_bound() - Assembler::InstructionSize;
+}
+
+#ifdef AARCH64
+// Can we reach target using ADRP?
+bool MacroAssembler::page_reachable_from_cache(address target) {
+  intptr_t cl = (intptr_t)first_cache_address() & ~0xfff;
+  intptr_t ch = (intptr_t)last_cache_address() & ~0xfff;
+  intptr_t addr = (intptr_t)target & ~0xfff;
+
+  intptr_t loffset = addr - cl;
+  intptr_t hoffset = addr - ch;
+  return is_imm_in_range(loffset >> 12, 21, 0) && is_imm_in_range(hoffset >> 12, 21, 0);
+}
+#endif
+
+// Can we reach target using unconditional branch or call from anywhere
+// in the code cache (because code can be relocated)?
+bool MacroAssembler::_reachable_from_cache(address target) {
+#ifdef __thumb__
+  if ((1 & (intptr_t)target) != 0) {
+    // Return false to avoid 'b' if we need switching to THUMB mode.
+    return false;
+  }
+#endif
+
+  address cl = first_cache_address();
+  address ch = last_cache_address();
+
+  if (ForceUnreachable) {
+    // Only addresses from CodeCache can be treated as reachable.
+    if (target < CodeCache::low_bound() || CodeCache::high_bound() < target) {
+      return false;
+    }
+  }
+
+  intptr_t loffset = (intptr_t)target - (intptr_t)cl;
+  intptr_t hoffset = (intptr_t)target - (intptr_t)ch;
+
+#ifdef AARCH64
+  return is_offset_in_range(loffset, 26) && is_offset_in_range(hoffset, 26);
+#else
+  return check26(loffset - 8) && check26(hoffset - 8);
+#endif
+}
+
+bool MacroAssembler::reachable_from_cache(address target) {
+  assert(CodeCache::contains(pc()), "not supported");
+  return _reachable_from_cache(target);
+}
+
+// Can we reach the entire code cache from anywhere else in the code cache?
+bool MacroAssembler::_cache_fully_reachable() {
+  address cl = first_cache_address();
+  address ch = last_cache_address();
+  return _reachable_from_cache(cl) && _reachable_from_cache(ch);
+}
+
+bool MacroAssembler::cache_fully_reachable() {
+  assert(CodeCache::contains(pc()), "not supported");
+  return _cache_fully_reachable();
+}
+
+void MacroAssembler::jump(address target, relocInfo::relocType rtype, Register scratch NOT_AARCH64_ARG(AsmCondition cond)) {
+  assert((rtype == relocInfo::runtime_call_type) || (rtype == relocInfo::none), "not supported");
+  if (reachable_from_cache(target)) {
+    relocate(rtype);
+    b(target NOT_AARCH64_ARG(cond));
+    return;
+  }
+
+  // Note: relocate is not needed for the code below,
+  // encoding targets in absolute format.
+  if (ignore_non_patchable_relocations()) {
+    rtype = relocInfo::none;
+  }
+
+#ifdef AARCH64
+  assert (scratch != noreg, "should be specified");
+  InlinedAddress address_literal(target, rtype);
+  ldr_literal(scratch, address_literal);
+  br(scratch);
+  int off = offset();
+  bind_literal(address_literal);
+#ifdef COMPILER2
+  if (offset() - off == wordSize) {
+    // no padding, so insert nop for worst-case sizing
+    nop();
+  }
+#endif
+#else
+  if (VM_Version::supports_movw() && (scratch != noreg) && (rtype == relocInfo::none)) {
+    // Note: this version cannot be (atomically) patched
+    mov_slow(scratch, (intptr_t)target, cond);
+    bx(scratch, cond);
+  } else {
+    Label skip;
+    InlinedAddress address_literal(target);
+    if (cond != al) {
+      b(skip, inverse(cond));
+    }
+    relocate(rtype);
+    ldr_literal(PC, address_literal);
+    bind_literal(address_literal);
+    bind(skip);
+  }
+#endif // AARCH64
+}
+
+// Similar to jump except that:
+// - near calls are valid only if any destination in the cache is near
+// - no movt/movw (not atomically patchable)
+void MacroAssembler::patchable_jump(address target, relocInfo::relocType rtype, Register scratch NOT_AARCH64_ARG(AsmCondition cond)) {
+  assert((rtype == relocInfo::runtime_call_type) || (rtype == relocInfo::none), "not supported");
+  if (cache_fully_reachable()) {
+    // Note: this assumes that all possible targets (the initial one
+    // and the addressed patched to) are all in the code cache.
+    assert(CodeCache::contains(target), "target might be too far");
+    relocate(rtype);
+    b(target NOT_AARCH64_ARG(cond));
+    return;
+  }
+
+  // Discard the relocation information if not needed for CacheCompiledCode
+  // since the next encodings are all in absolute format.
+  if (ignore_non_patchable_relocations()) {
+    rtype = relocInfo::none;
+  }
+
+#ifdef AARCH64
+  assert (scratch != noreg, "should be specified");
+  InlinedAddress address_literal(target);
+  relocate(rtype);
+  ldr_literal(scratch, address_literal);
+  br(scratch);
+  int off = offset();
+  bind_literal(address_literal);
+#ifdef COMPILER2
+  if (offset() - off == wordSize) {
+    // no padding, so insert nop for worst-case sizing
+    nop();
+  }
+#endif
+#else
+  {
+    Label skip;
+    InlinedAddress address_literal(target);
+    if (cond != al) {
+      b(skip, inverse(cond));
+    }
+    relocate(rtype);
+    ldr_literal(PC, address_literal);
+    bind_literal(address_literal);
+    bind(skip);
+  }
+#endif // AARCH64
+}
+
+void MacroAssembler::call(address target, RelocationHolder rspec NOT_AARCH64_ARG(AsmCondition cond)) {
+  Register scratch = LR;
+  assert(rspec.type() == relocInfo::runtime_call_type || rspec.type() == relocInfo::none, "not supported");
+  if (reachable_from_cache(target)) {
+    relocate(rspec);
+    bl(target NOT_AARCH64_ARG(cond));
+    return;
+  }
+
+  // Note: relocate is not needed for the code below,
+  // encoding targets in absolute format.
+  if (ignore_non_patchable_relocations()) {
+    // This assumes the information was needed only for relocating the code.
+    rspec = RelocationHolder::none;
+  }
+
+#ifndef AARCH64
+  if (VM_Version::supports_movw() && (rspec.type() == relocInfo::none)) {
+    // Note: this version cannot be (atomically) patched
+    mov_slow(scratch, (intptr_t)target, cond);
+    blx(scratch, cond);
+    return;
+  }
+#endif
+
+  {
+    Label ret_addr;
+#ifndef AARCH64
+    if (cond != al) {
+      b(ret_addr, inverse(cond));
+    }
+#endif
+
+
+#ifdef AARCH64
+    // TODO-AARCH64: make more optimal implementation
+    // [ Keep in sync with MacroAssembler::call_size ]
+    assert(rspec.type() == relocInfo::none, "call reloc not implemented");
+    mov_slow(scratch, target);
+    blr(scratch);
+#else
+    InlinedAddress address_literal(target);
+    relocate(rspec);
+    adr(LR, ret_addr);
+    ldr_literal(PC, address_literal);
+
+    bind_literal(address_literal);
+    bind(ret_addr);
+#endif
+  }
+}
+
+#if defined(AARCH64) && defined(COMPILER2)
+int MacroAssembler::call_size(address target, bool far, bool patchable) {
+  // FIXME: mov_slow is variable-length
+  if (!far) return 1; // bl
+  if (patchable) return 2;  // ldr; blr
+  return instr_count_for_mov_slow((intptr_t)target) + 1;
+}
+#endif
+
+int MacroAssembler::patchable_call(address target, RelocationHolder const& rspec, bool c2) {
+  assert(rspec.type() == relocInfo::static_call_type ||
+         rspec.type() == relocInfo::none ||
+         rspec.type() == relocInfo::opt_virtual_call_type, "not supported");
+
+  // Always generate the relocation information, needed for patching
+  relocate(rspec); // used by NativeCall::is_call_before()
+  if (cache_fully_reachable()) {
+    // Note: this assumes that all possible targets (the initial one
+    // and the addresses patched to) are all in the code cache.
+    assert(CodeCache::contains(target), "target might be too far");
+    bl(target);
+  } else {
+#if defined(AARCH64) && defined(COMPILER2)
+    if (c2) {
+      // return address needs to match call_size().
+      // no need to trash Rtemp
+      int off = offset();
+      Label skip_literal;
+      InlinedAddress address_literal(target);
+      ldr_literal(LR, address_literal);
+      blr(LR);
+      int ret_addr_offset = offset();
+      assert(offset() - off == call_size(target, true, true) * InstructionSize, "need to fix call_size()");
+      b(skip_literal);
+      int off2 = offset();
+      bind_literal(address_literal);
+      if (offset() - off2 == wordSize) {
+        // no padding, so insert nop for worst-case sizing
+        nop();
+      }
+      bind(skip_literal);
+      return ret_addr_offset;
+    }
+#endif
+    Label ret_addr;
+    InlinedAddress address_literal(target);
+#ifdef AARCH64
+    ldr_literal(Rtemp, address_literal);
+    adr(LR, ret_addr);
+    br(Rtemp);
+#else
+    adr(LR, ret_addr);
+    ldr_literal(PC, address_literal);
+#endif
+    bind_literal(address_literal);
+    bind(ret_addr);
+  }
+  return offset();
+}
+
+
+void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) {
+  const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+  ldr(tmp, Address(method, Method::const_offset()));
+  ldr(tmp, Address(tmp,  ConstMethod::constants_offset()));
+  ldr(tmp, Address(tmp, ConstantPool::pool_holder_offset_in_bytes()));
+  ldr(mirror, Address(tmp, mirror_offset));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Compressed pointers
+
+#ifdef AARCH64
+
+void MacroAssembler::load_klass(Register dst_klass, Register src_oop) {
+  if (UseCompressedClassPointers) {
+    ldr_w(dst_klass, Address(src_oop, oopDesc::klass_offset_in_bytes()));
+    decode_klass_not_null(dst_klass);
+  } else {
+    ldr(dst_klass, Address(src_oop, oopDesc::klass_offset_in_bytes()));
+  }
+}
+
+#else
+
+void MacroAssembler::load_klass(Register dst_klass, Register src_oop, AsmCondition cond) {
+  ldr(dst_klass, Address(src_oop, oopDesc::klass_offset_in_bytes()), cond);
+}
+
+#endif // AARCH64
+
+// Blows src_klass.
+void MacroAssembler::store_klass(Register src_klass, Register dst_oop) {
+#ifdef AARCH64
+  if (UseCompressedClassPointers) {
+    assert(src_klass != dst_oop, "not enough registers");
+    encode_klass_not_null(src_klass);
+    str_w(src_klass, Address(dst_oop, oopDesc::klass_offset_in_bytes()));
+    return;
+  }
+#endif // AARCH64
+  str(src_klass, Address(dst_oop, oopDesc::klass_offset_in_bytes()));
+}
+
+#ifdef AARCH64
+
+void MacroAssembler::store_klass_gap(Register dst) {
+  if (UseCompressedClassPointers) {
+    str_w(ZR, Address(dst, oopDesc::klass_gap_offset_in_bytes()));
+  }
+}
+
+#endif // AARCH64
+
+
+void MacroAssembler::load_heap_oop(Register dst, Address src) {
+#ifdef AARCH64
+  if (UseCompressedOops) {
+    ldr_w(dst, src);
+    decode_heap_oop(dst);
+    return;
+  }
+#endif // AARCH64
+  ldr(dst, src);
+}
+
+// Blows src and flags.
+void MacroAssembler::store_heap_oop(Register src, Address dst) {
+#ifdef AARCH64
+  if (UseCompressedOops) {
+    assert(!dst.uses(src), "not enough registers");
+    encode_heap_oop(src);
+    str_w(src, dst);
+    return;
+  }
+#endif // AARCH64
+  str(src, dst);
+}
+
+void MacroAssembler::store_heap_oop_null(Register src, Address dst) {
+#ifdef AARCH64
+  if (UseCompressedOops) {
+    str_w(src, dst);
+    return;
+  }
+#endif // AARCH64
+  str(src, dst);
+}
+
+
+#ifdef AARCH64
+
+// Algorithm must match oop.inline.hpp encode_heap_oop.
+void MacroAssembler::encode_heap_oop(Register dst, Register src) {
+  // This code pattern is matched in NativeIntruction::skip_encode_heap_oop.
+  // Update it at modifications.
+  assert (UseCompressedOops, "must be compressed");
+  assert (Universe::heap() != NULL, "java heap should be initialized");
+#ifdef ASSERT
+  verify_heapbase("MacroAssembler::encode_heap_oop: heap base corrupted?");
+#endif
+  verify_oop(src);
+  if (Universe::narrow_oop_base() == NULL) {
+    if (Universe::narrow_oop_shift() != 0) {
+      assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+      _lsr(dst, src, Universe::narrow_oop_shift());
+    } else if (dst != src) {
+      mov(dst, src);
+    }
+  } else {
+    tst(src, src);
+    csel(dst, Rheap_base, src, eq);
+    sub(dst, dst, Rheap_base);
+    if (Universe::narrow_oop_shift() != 0) {
+      assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+      _lsr(dst, dst, Universe::narrow_oop_shift());
+    }
+  }
+}
+
+// Same algorithm as oop.inline.hpp decode_heap_oop.
+void MacroAssembler::decode_heap_oop(Register dst, Register src) {
+#ifdef ASSERT
+  verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?");
+#endif
+  assert(Universe::narrow_oop_shift() == 0 || LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+  if (Universe::narrow_oop_base() != NULL) {
+    tst(src, src);
+    add(dst, Rheap_base, AsmOperand(src, lsl, Universe::narrow_oop_shift()));
+    csel(dst, dst, ZR, ne);
+  } else {
+    _lsl(dst, src, Universe::narrow_oop_shift());
+  }
+  verify_oop(dst);
+}
+
+#ifdef COMPILER2
+// Algorithm must match oop.inline.hpp encode_heap_oop.
+// Must preserve condition codes, or C2 encodeHeapOop_not_null rule
+// must be changed.
+void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) {
+  assert (UseCompressedOops, "must be compressed");
+  assert (Universe::heap() != NULL, "java heap should be initialized");
+#ifdef ASSERT
+  verify_heapbase("MacroAssembler::encode_heap_oop: heap base corrupted?");
+#endif
+  verify_oop(src);
+  if (Universe::narrow_oop_base() == NULL) {
+    if (Universe::narrow_oop_shift() != 0) {
+      assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+      _lsr(dst, src, Universe::narrow_oop_shift());
+    } else if (dst != src) {
+          mov(dst, src);
+    }
+  } else {
+    sub(dst, src, Rheap_base);
+    if (Universe::narrow_oop_shift() != 0) {
+      assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+      _lsr(dst, dst, Universe::narrow_oop_shift());
+    }
+  }
+}
+
+// Same algorithm as oops.inline.hpp decode_heap_oop.
+// Must preserve condition codes, or C2 decodeHeapOop_not_null rule
+// must be changed.
+void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) {
+#ifdef ASSERT
+  verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?");
+#endif
+  assert(Universe::narrow_oop_shift() == 0 || LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+  if (Universe::narrow_oop_base() != NULL) {
+    add(dst, Rheap_base, AsmOperand(src, lsl, Universe::narrow_oop_shift()));
+  } else {
+    _lsl(dst, src, Universe::narrow_oop_shift());
+  }
+  verify_oop(dst);
+}
+
+void MacroAssembler::set_narrow_klass(Register dst, Klass* k) {
+  assert(UseCompressedClassPointers, "should only be used for compressed header");
+  assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+  int klass_index = oop_recorder()->find_index(k);
+  RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+
+  // Relocation with special format (see relocInfo_arm.hpp).
+  relocate(rspec);
+  narrowKlass encoded_k = Klass::encode_klass(k);
+  movz(dst, encoded_k & 0xffff, 0);
+  movk(dst, (encoded_k >> 16) & 0xffff, 16);
+}
+
+void MacroAssembler::set_narrow_oop(Register dst, jobject obj) {
+  assert(UseCompressedOops, "should only be used for compressed header");
+  assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+  int oop_index = oop_recorder()->find_index(obj);
+  RelocationHolder rspec = oop_Relocation::spec(oop_index);
+
+  relocate(rspec);
+  movz(dst, 0xffff, 0);
+  movk(dst, 0xffff, 16);
+}
+
+#endif // COMPILER2
+
+// Must preserve condition codes, or C2 encodeKlass_not_null rule
+// must be changed.
+void MacroAssembler::encode_klass_not_null(Register r) {
+  if (Universe::narrow_klass_base() != NULL) {
+    // Use Rheap_base as a scratch register in which to temporarily load the narrow_klass_base.
+    assert(r != Rheap_base, "Encoding a klass in Rheap_base");
+    mov_slow(Rheap_base, Universe::narrow_klass_base());
+    sub(r, r, Rheap_base);
+  }
+  if (Universe::narrow_klass_shift() != 0) {
+    assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+    _lsr(r, r, Universe::narrow_klass_shift());
+  }
+  if (Universe::narrow_klass_base() != NULL) {
+    reinit_heapbase();
+  }
+}
+
+// Must preserve condition codes, or C2 encodeKlass_not_null rule
+// must be changed.
+void MacroAssembler::encode_klass_not_null(Register dst, Register src) {
+  if (dst == src) {
+    encode_klass_not_null(src);
+    return;
+  }
+  if (Universe::narrow_klass_base() != NULL) {
+    mov_slow(dst, (int64_t)Universe::narrow_klass_base());
+    sub(dst, src, dst);
+    if (Universe::narrow_klass_shift() != 0) {
+      assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+      _lsr(dst, dst, Universe::narrow_klass_shift());
+    }
+  } else {
+    if (Universe::narrow_klass_shift() != 0) {
+      assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+      _lsr(dst, src, Universe::narrow_klass_shift());
+    } else {
+      mov(dst, src);
+    }
+  }
+}
+
+// Function instr_count_for_decode_klass_not_null() counts the instructions
+// generated by decode_klass_not_null(register r) and reinit_heapbase(),
+// when (Universe::heap() != NULL).  Hence, if the instructions they
+// generate change, then this method needs to be updated.
+int MacroAssembler::instr_count_for_decode_klass_not_null() {
+  assert(UseCompressedClassPointers, "only for compressed klass ptrs");
+  assert(Universe::heap() != NULL, "java heap should be initialized");
+  if (Universe::narrow_klass_base() != NULL) {
+    return instr_count_for_mov_slow(Universe::narrow_klass_base()) + // mov_slow
+      1 +                                                                 // add
+      instr_count_for_mov_slow(Universe::narrow_ptrs_base());   // reinit_heapbase() = mov_slow
+  } else {
+    if (Universe::narrow_klass_shift() != 0) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+// Must preserve condition codes, or C2 decodeKlass_not_null rule
+// must be changed.
+void MacroAssembler::decode_klass_not_null(Register r) {
+  int off = offset();
+  assert(UseCompressedClassPointers, "should only be used for compressed headers");
+  assert(Universe::heap() != NULL, "java heap should be initialized");
+  assert(r != Rheap_base, "Decoding a klass in Rheap_base");
+  // Cannot assert, instr_count_for_decode_klass_not_null() counts instructions.
+  // Also do not verify_oop as this is called by verify_oop.
+  if (Universe::narrow_klass_base() != NULL) {
+    // Use Rheap_base as a scratch register in which to temporarily load the narrow_klass_base.
+    mov_slow(Rheap_base, Universe::narrow_klass_base());
+    add(r, Rheap_base, AsmOperand(r, lsl, Universe::narrow_klass_shift()));
+    reinit_heapbase();
+  } else {
+    if (Universe::narrow_klass_shift() != 0) {
+      assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+      _lsl(r, r, Universe::narrow_klass_shift());
+    }
+  }
+  assert((offset() - off) == (instr_count_for_decode_klass_not_null() * InstructionSize), "need to fix instr_count_for_decode_klass_not_null");
+}
+
+// Must preserve condition codes, or C2 decodeKlass_not_null rule
+// must be changed.
+void MacroAssembler::decode_klass_not_null(Register dst, Register src) {
+  if (src == dst) {
+    decode_klass_not_null(src);
+    return;
+  }
+
+  assert(UseCompressedClassPointers, "should only be used for compressed headers");
+  assert(Universe::heap() != NULL, "java heap should be initialized");
+  assert(src != Rheap_base, "Decoding a klass in Rheap_base");
+  assert(dst != Rheap_base, "Decoding a klass into Rheap_base");
+  // Also do not verify_oop as this is called by verify_oop.
+  if (Universe::narrow_klass_base() != NULL) {
+    mov_slow(dst, Universe::narrow_klass_base());
+    add(dst, dst, AsmOperand(src, lsl, Universe::narrow_klass_shift()));
+  } else {
+    _lsl(dst, src, Universe::narrow_klass_shift());
+  }
+}
+
+
+void MacroAssembler::reinit_heapbase() {
+  if (UseCompressedOops || UseCompressedClassPointers) {
+    if (Universe::heap() != NULL) {
+      mov_slow(Rheap_base, Universe::narrow_ptrs_base());
+    } else {
+      ldr_global_ptr(Rheap_base, (address)Universe::narrow_ptrs_base_addr());
+    }
+  }
+}
+
+#ifdef ASSERT
+void MacroAssembler::verify_heapbase(const char* msg) {
+  // This code pattern is matched in NativeIntruction::skip_verify_heapbase.
+  // Update it at modifications.
+  assert (UseCompressedOops, "should be compressed");
+  assert (Universe::heap() != NULL, "java heap should be initialized");
+  if (CheckCompressedOops) {
+    Label ok;
+    str(Rthread, Address(Rthread, in_bytes(JavaThread::in_top_frame_unsafe_section_offset())));
+    raw_push(Rtemp, ZR);
+    mrs(Rtemp, Assembler::SysReg_NZCV);
+    str(Rtemp, Address(SP, 1 * wordSize));
+    mov_slow(Rtemp, Universe::narrow_ptrs_base());
+    cmp(Rheap_base, Rtemp);
+    b(ok, eq);
+    stop(msg);
+    bind(ok);
+    ldr(Rtemp, Address(SP, 1 * wordSize));
+    msr(Assembler::SysReg_NZCV, Rtemp);
+    raw_pop(Rtemp, ZR);
+    str(ZR, Address(Rthread, in_bytes(JavaThread::in_top_frame_unsafe_section_offset())));
+  }
+}
+#endif // ASSERT
+
+#endif // AARCH64
+
+#ifdef COMPILER2
+void MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratch, Register Rscratch2 AARCH64_ONLY_ARG(Register Rscratch3))
+{
+  assert(VM_Version::supports_ldrex(), "unsupported, yet?");
+
+  Register Rmark      = Rscratch2;
+
+  assert(Roop != Rscratch, "");
+  assert(Roop != Rmark, "");
+  assert(Rbox != Rscratch, "");
+  assert(Rbox != Rmark, "");
+
+  Label fast_lock, done;
+
+  if (UseBiasedLocking && !UseOptoBiasInlining) {
+    Label failed;
+#ifdef AARCH64
+    biased_locking_enter(Roop, Rmark, Rscratch, false, Rscratch3, done, failed);
+#else
+    biased_locking_enter(Roop, Rmark, Rscratch, false, noreg, done, failed);
+#endif
+    bind(failed);
+  }
+
+  ldr(Rmark, Address(Roop, oopDesc::mark_offset_in_bytes()));
+  tst(Rmark, markOopDesc::unlocked_value);
+  b(fast_lock, ne);
+
+  // Check for recursive lock
+  // See comments in InterpreterMacroAssembler::lock_object for
+  // explanations on the fast recursive locking check.
+#ifdef AARCH64
+  intptr_t mask = ((intptr_t)3) - ((intptr_t)os::vm_page_size());
+  Assembler::LogicalImmediate imm(mask, false);
+  mov(Rscratch, SP);
+  sub(Rscratch, Rmark, Rscratch);
+  ands(Rscratch, Rscratch, imm);
+  b(done, ne); // exit with failure
+  str(Rscratch, Address(Rbox, BasicLock::displaced_header_offset_in_bytes())); // set to zero
+  b(done);
+
+#else
+  // -1- test low 2 bits
+  movs(Rscratch, AsmOperand(Rmark, lsl, 30));
+  // -2- test (hdr - SP) if the low two bits are 0
+  sub(Rscratch, Rmark, SP, eq);
+  movs(Rscratch, AsmOperand(Rscratch, lsr, exact_log2(os::vm_page_size())), eq);
+  // If still 'eq' then recursive locking OK
+  str(Rscratch, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()), eq); // set to zero
+  b(done);
+#endif
+
+  bind(fast_lock);
+  str(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
+
+  bool allow_fallthrough_on_failure = true;
+  bool one_shot = true;
+  cas_for_lock_acquire(Rmark, Rbox, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
+
+  bind(done);
+
+}
+
+void MacroAssembler::fast_unlock(Register Roop, Register Rbox, Register Rscratch, Register Rscratch2  AARCH64_ONLY_ARG(Register Rscratch3))
+{
+  assert(VM_Version::supports_ldrex(), "unsupported, yet?");
+
+  Register Rmark      = Rscratch2;
+
+  assert(Roop != Rscratch, "");
+  assert(Roop != Rmark, "");
+  assert(Rbox != Rscratch, "");
+  assert(Rbox != Rmark, "");
+
+  Label done;
+
+  if (UseBiasedLocking && !UseOptoBiasInlining) {
+    biased_locking_exit(Roop, Rscratch, done);
+  }
+
+  ldr(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
+  // If hdr is NULL, we've got recursive locking and there's nothing more to do
+  cmp(Rmark, 0);
+  b(done, eq);
+
+  // Restore the object header
+  bool allow_fallthrough_on_failure = true;
+  bool one_shot = true;
+  cas_for_lock_release(Rmark, Rbox, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
+
+  bind(done);
+
+}
+#endif // COMPILER2
+
diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp
new file mode 100644
index 0000000..770bba6
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp
@@ -0,0 +1,1390 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_MACROASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_MACROASSEMBLER_ARM_HPP
+
+#include "code/relocInfo.hpp"
+#include "code/relocInfo_ext.hpp"
+
+class BiasedLockingCounters;
+
+// Introduced AddressLiteral and its subclasses to ease portability from
+// x86 and avoid relocation issues
+class AddressLiteral VALUE_OBJ_CLASS_SPEC {
+  RelocationHolder _rspec;
+  // Typically we use AddressLiterals we want to use their rval
+  // However in some situations we want the lval (effect address) of the item.
+  // We provide a special factory for making those lvals.
+  bool _is_lval;
+
+  address          _target;
+
+ private:
+  static relocInfo::relocType reloc_for_target(address target) {
+    // Used for ExternalAddress or when the type is not specified
+    // Sometimes ExternalAddress is used for values which aren't
+    // exactly addresses, like the card table base.
+    // external_word_type can't be used for values in the first page
+    // so just skip the reloc in that case.
+    return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
+  }
+
+  void set_rspec(relocInfo::relocType rtype);
+
+ protected:
+  // creation
+  AddressLiteral()
+    : _is_lval(false),
+      _target(NULL)
+  {}
+
+  public:
+
+  AddressLiteral(address target, relocInfo::relocType rtype) {
+    _is_lval = false;
+    _target = target;
+    set_rspec(rtype);
+  }
+
+  AddressLiteral(address target, RelocationHolder const& rspec)
+    : _rspec(rspec),
+      _is_lval(false),
+      _target(target)
+  {}
+
+  AddressLiteral(address target) {
+    _is_lval = false;
+    _target = target;
+    set_rspec(reloc_for_target(target));
+  }
+
+  AddressLiteral addr() {
+    AddressLiteral ret = *this;
+    ret._is_lval = true;
+    return ret;
+  }
+
+ private:
+
+  address target() { return _target; }
+  bool is_lval() { return _is_lval; }
+
+  relocInfo::relocType reloc() const { return _rspec.type(); }
+  const RelocationHolder& rspec() const { return _rspec; }
+
+  friend class Assembler;
+  friend class MacroAssembler;
+  friend class Address;
+  friend class LIR_Assembler;
+  friend class InlinedAddress;
+};
+
+class ExternalAddress: public AddressLiteral {
+
+  public:
+
+  ExternalAddress(address target) : AddressLiteral(target) {}
+
+};
+
+class InternalAddress: public AddressLiteral {
+
+  public:
+
+  InternalAddress(address target) : AddressLiteral(target, relocInfo::internal_word_type) {}
+
+};
+
+// Inlined constants, for use with ldr_literal / bind_literal
+// Note: InlinedInteger not supported (use move_slow(Register,int[,cond]))
+class InlinedLiteral: StackObj {
+ public:
+  Label label; // need to be public for direct access with &
+  InlinedLiteral() {
+  }
+};
+
+class InlinedMetadata: public InlinedLiteral {
+ private:
+  Metadata *_data;
+
+ public:
+  InlinedMetadata(Metadata *data): InlinedLiteral() {
+    _data = data;
+  }
+  Metadata *data() { return _data; }
+};
+
+// Currently unused
+// class InlinedOop: public InlinedLiteral {
+//  private:
+//   jobject _jobject;
+//
+//  public:
+//   InlinedOop(jobject target): InlinedLiteral() {
+//     _jobject = target;
+//   }
+//   jobject jobject() { return _jobject; }
+// };
+
+class InlinedAddress: public InlinedLiteral {
+ private:
+  AddressLiteral _literal;
+
+ public:
+
+  InlinedAddress(jobject object): InlinedLiteral(), _literal((address)object, relocInfo::oop_type) {
+    ShouldNotReachHere(); // use mov_oop (or implement InlinedOop)
+  }
+
+  InlinedAddress(Metadata *data): InlinedLiteral(), _literal((address)data, relocInfo::metadata_type) {
+    ShouldNotReachHere(); // use InlinedMetadata or mov_metadata
+  }
+
+  InlinedAddress(address target, const RelocationHolder &rspec): InlinedLiteral(), _literal(target, rspec) {
+    assert(rspec.type() != relocInfo::oop_type, "Do not use InlinedAddress for oops");
+    assert(rspec.type() != relocInfo::metadata_type, "Do not use InlinedAddress for metadatas");
+  }
+
+  InlinedAddress(address target, relocInfo::relocType rtype): InlinedLiteral(), _literal(target, rtype) {
+    assert(rtype != relocInfo::oop_type, "Do not use InlinedAddress for oops");
+    assert(rtype != relocInfo::metadata_type, "Do not use InlinedAddress for metadatas");
+  }
+
+  // Note: default is relocInfo::none for InlinedAddress
+  InlinedAddress(address target): InlinedLiteral(), _literal(target, relocInfo::none) {
+  }
+
+  address target() { return _literal.target(); }
+
+  const RelocationHolder& rspec() const { return _literal.rspec(); }
+};
+
+class InlinedString: public InlinedLiteral {
+ private:
+  const char* _msg;
+
+ public:
+  InlinedString(const char* msg): InlinedLiteral() {
+    _msg = msg;
+  }
+  const char* msg() { return _msg; }
+};
+
+class MacroAssembler: public Assembler {
+protected:
+
+  // Support for VM calls
+  //
+
+  // This is the base routine called by the different versions of call_VM_leaf.
+  void call_VM_leaf_helper(address entry_point, int number_of_arguments);
+
+  // This is the base routine called by the different versions of call_VM. The interpreter
+  // may customize this version by overriding it for its purposes (e.g., to save/restore
+  // additional registers when doing a VM call).
+  virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
+
+  // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
+  // The implementation is only non-empty for the InterpreterMacroAssembler,
+  // as only the interpreter handles PopFrame and ForceEarlyReturn requests.
+  virtual void check_and_handle_popframe() {}
+  virtual void check_and_handle_earlyret() {}
+
+public:
+
+  MacroAssembler(CodeBuffer* code) : Assembler(code) {}
+
+  // By default, we do not need relocation information for non
+  // patchable absolute addresses. However, when needed by some
+  // extensions, ignore_non_patchable_relocations can be modified,
+  // returning false to preserve all relocation information.
+  inline bool ignore_non_patchable_relocations() { return true; }
+
+  // Initially added to the Assembler interface as a pure virtual:
+  //   RegisterConstant delayed_value(..)
+  // for:
+  //   6812678 macro assembler needs delayed binding of a few constants (for 6655638)
+  // this was subsequently modified to its present name and return type
+  virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
+
+#ifdef AARCH64
+# define NOT_IMPLEMENTED() unimplemented("NYI at " __FILE__ ":" XSTR(__LINE__))
+# define NOT_TESTED()      warn("Not tested at " __FILE__ ":" XSTR(__LINE__))
+#endif
+
+  void align(int modulus);
+
+  // Support for VM calls
+  //
+  // It is imperative that all calls into the VM are handled via the call_VM methods.
+  // They make sure that the stack linkage is setup correctly. call_VM's correspond
+  // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
+
+  void call_VM(Register oop_result, address entry_point, bool check_exceptions = true);
+  void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true);
+  void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
+  void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
+
+  // The following methods are required by templateTable.cpp,
+  // but not used on ARM.
+  void call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
+  void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true);
+  void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
+  void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
+
+  // Note: The super_call_VM calls are not used on ARM
+
+  // Raw call, without saving/restoring registers, exception handling, etc.
+  // Mainly used from various stubs.
+  // Note: if 'save_R9_if_scratched' is true, call_VM may on some
+  // platforms save values on the stack. Set it to false (and handle
+  // R9 in the callers) if the top of the stack must not be modified
+  // by call_VM.
+  void call_VM(address entry_point, bool save_R9_if_scratched);
+
+  void call_VM_leaf(address entry_point);
+  void call_VM_leaf(address entry_point, Register arg_1);
+  void call_VM_leaf(address entry_point, Register arg_1, Register arg_2);
+  void call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3);
+  void call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4);
+
+  void get_vm_result(Register oop_result, Register tmp);
+  void get_vm_result_2(Register metadata_result, Register tmp);
+
+  // Always sets/resets sp, which default to SP if (last_sp == noreg)
+  // Optionally sets/resets fp (use noreg to avoid setting it)
+  // Always sets/resets pc on AArch64; optionally sets/resets pc on 32-bit ARM depending on save_last_java_pc flag
+  // Note: when saving PC, set_last_Java_frame returns PC's offset in the code section
+  //       (for oop_maps offset computation)
+  int set_last_Java_frame(Register last_sp, Register last_fp, bool save_last_java_pc, Register tmp);
+  void reset_last_Java_frame(Register tmp);
+  // status set in set_last_Java_frame for reset_last_Java_frame
+  bool _fp_saved;
+  bool _pc_saved;
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#define STOP(error) __ stop(error)
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#define STOP(error) __ block_comment(error); __ stop(error)
+#endif
+
+  void lookup_virtual_method(Register recv_klass,
+                             Register vtable_index,
+                             Register method_result);
+
+  // Test sub_klass against super_klass, with fast and slow paths.
+
+  // The fast path produces a tri-state answer: yes / no / maybe-slow.
+  // One of the three labels can be NULL, meaning take the fall-through.
+  // No registers are killed, except temp_regs.
+  void check_klass_subtype_fast_path(Register sub_klass,
+                                     Register super_klass,
+                                     Register temp_reg,
+                                     Register temp_reg2,
+                                     Label* L_success,
+                                     Label* L_failure,
+                                     Label* L_slow_path);
+
+  // The rest of the type check; must be wired to a corresponding fast path.
+  // It does not repeat the fast path logic, so don't use it standalone.
+  // temp_reg3 can be noreg, if no temps are available.
+  // Updates the sub's secondary super cache as necessary.
+  // If set_cond_codes:
+  // - condition codes will be Z on success, NZ on failure.
+  // - temp_reg will be 0 on success, non-0 on failure
+  void check_klass_subtype_slow_path(Register sub_klass,
+                                     Register super_klass,
+                                     Register temp_reg,
+                                     Register temp_reg2,
+                                     Register temp_reg3, // auto assigned if noreg
+                                     Label* L_success,
+                                     Label* L_failure,
+                                     bool set_cond_codes = false);
+
+  // Simplified, combined version, good for typical uses.
+  // temp_reg3 can be noreg, if no temps are available. It is used only on slow path.
+  // Falls through on failure.
+  void check_klass_subtype(Register sub_klass,
+                           Register super_klass,
+                           Register temp_reg,
+                           Register temp_reg2,
+                           Register temp_reg3, // auto assigned on slow path if noreg
+                           Label& L_success);
+
+  // Returns address of receiver parameter, using tmp as base register. tmp and params_count can be the same.
+  Address receiver_argument_address(Register params_base, Register params_count, Register tmp);
+
+  void _verify_oop(Register reg, const char* s, const char* file, int line);
+  void _verify_oop_addr(Address addr, const char * s, const char* file, int line);
+
+  // TODO: verify method and klass metadata (compare against vptr?)
+  void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
+  void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line) {}
+
+#define verify_oop(reg) _verify_oop(reg, "broken oop " #reg, __FILE__, __LINE__)
+#define verify_oop_addr(addr) _verify_oop_addr(addr, "broken oop ", __FILE__, __LINE__)
+#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
+#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
+
+  void null_check(Register reg, Register tmp, int offset = -1);
+  inline void null_check(Register reg) { null_check(reg, noreg, -1); } // for C1 lir_null_check
+
+  // Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`.
+  void eden_allocate(Register obj, Register obj_end, Register tmp1, Register tmp2,
+                     RegisterOrConstant size_expression, Label& slow_case);
+  void tlab_allocate(Register obj, Register obj_end, Register tmp1,
+                     RegisterOrConstant size_expression, Label& slow_case);
+
+  void tlab_refill(Register top, Register tmp1, Register tmp2, Register tmp3, Register tmp4,
+                   Label& try_eden, Label& slow_case);
+  void zero_memory(Register start, Register end, Register tmp);
+
+  void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register tmp);
+
+  static bool needs_explicit_null_check(intptr_t offset);
+
+  void arm_stack_overflow_check(int frame_size_in_bytes, Register tmp);
+  void arm_stack_overflow_check(Register Rsize, Register tmp);
+
+  void bang_stack_with_offset(int offset) {
+    ShouldNotReachHere();
+  }
+
+  // Biased locking support
+  // lock_reg and obj_reg must be loaded up with the appropriate values.
+  // swap_reg must be supplied.
+  // tmp_reg must be supplied.
+  // Optional slow case is for implementations (interpreter and C1) which branch to
+  // slow case directly. If slow_case is NULL, then leaves condition
+  // codes set (for C2's Fast_Lock node) and jumps to done label.
+  // Falls through for the fast locking attempt.
+  // Returns offset of first potentially-faulting instruction for null
+  // check info (currently consumed only by C1). If
+  // swap_reg_contains_mark is true then returns -1 as it is assumed
+  // the calling code has already passed any potential faults.
+  // Notes:
+  // - swap_reg and tmp_reg are scratched
+  // - Rtemp was (implicitly) scratched and can now be specified as the tmp2
+  int biased_locking_enter(Register obj_reg, Register swap_reg, Register tmp_reg,
+                           bool swap_reg_contains_mark,
+                           Register tmp2,
+                           Label& done, Label& slow_case,
+                           BiasedLockingCounters* counters = NULL);
+  void biased_locking_exit(Register obj_reg, Register temp_reg, Label& done);
+
+  // Building block for CAS cases of biased locking: makes CAS and records statistics.
+  // Optional slow_case label is used to transfer control if CAS fails. Otherwise leaves condition codes set.
+  void biased_locking_enter_with_cas(Register obj_reg, Register old_mark_reg, Register new_mark_reg,
+                                     Register tmp, Label& slow_case, int* counter_addr);
+
+#ifndef AARCH64
+  void nop() {
+    mov(R0, R0);
+  }
+
+  void push(Register rd, AsmCondition cond = al) {
+    assert(rd != SP, "unpredictable instruction");
+    str(rd, Address(SP, -wordSize, pre_indexed), cond);
+  }
+
+  void push(RegisterSet reg_set, AsmCondition cond = al) {
+    assert(!reg_set.contains(SP), "unpredictable instruction");
+    stmdb(SP, reg_set, writeback, cond);
+  }
+
+  void pop(Register rd, AsmCondition cond = al) {
+    assert(rd != SP, "unpredictable instruction");
+    ldr(rd, Address(SP, wordSize, post_indexed), cond);
+  }
+
+  void pop(RegisterSet reg_set, AsmCondition cond = al) {
+    assert(!reg_set.contains(SP), "unpredictable instruction");
+    ldmia(SP, reg_set, writeback, cond);
+  }
+
+  void fpushd(FloatRegister fd, AsmCondition cond = al) {
+    fstmdbd(SP, FloatRegisterSet(fd), writeback, cond);
+  }
+
+  void fpushs(FloatRegister fd, AsmCondition cond = al) {
+    fstmdbs(SP, FloatRegisterSet(fd), writeback, cond);
+  }
+
+  void fpopd(FloatRegister fd, AsmCondition cond = al) {
+    fldmiad(SP, FloatRegisterSet(fd), writeback, cond);
+  }
+
+  void fpops(FloatRegister fd, AsmCondition cond = al) {
+    fldmias(SP, FloatRegisterSet(fd), writeback, cond);
+  }
+#endif // !AARCH64
+
+  // Order access primitives
+  enum Membar_mask_bits {
+    StoreStore = 1 << 3,
+    LoadStore  = 1 << 2,
+    StoreLoad  = 1 << 1,
+    LoadLoad   = 1 << 0
+  };
+
+#ifdef AARCH64
+  // tmp register is not used on AArch64, this parameter is provided solely for better compatibility with 32-bit ARM
+  void membar(Membar_mask_bits order_constraint, Register tmp = noreg);
+#else
+  void membar(Membar_mask_bits mask,
+              Register tmp,
+              bool preserve_flags = true,
+              Register load_tgt = noreg);
+#endif
+
+  void breakpoint(AsmCondition cond = al);
+  void stop(const char* msg);
+  // prints msg and continues
+  void warn(const char* msg);
+  void unimplemented(const char* what = "");
+  void should_not_reach_here()                   { stop("should not reach here"); }
+  static void debug(const char* msg, const intx* registers);
+
+  // Create a walkable frame to help tracking down who called this code.
+  // Returns the frame size in words.
+  int should_not_call_this() {
+    raw_push(FP, LR);
+    should_not_reach_here();
+    flush();
+    return 2; // frame_size_in_words (FP+LR)
+  }
+
+  int save_all_registers();
+  void restore_all_registers();
+  int save_caller_save_registers();
+  void restore_caller_save_registers();
+
+  void add_rc(Register dst, Register arg1, RegisterOrConstant arg2);
+
+  // add_slow and mov_slow are used to manipulate offsets larger than 1024,
+  // these functions are not expected to handle all possible constants,
+  // only those that can really occur during compilation
+  void add_slow(Register rd, Register rn, int c);
+  void sub_slow(Register rd, Register rn, int c);
+
+#ifdef AARCH64
+  static int mov_slow_helper(Register rd, intptr_t c, MacroAssembler* masm /* optional */);
+#endif
+
+  void mov_slow(Register rd, intptr_t c NOT_AARCH64_ARG(AsmCondition cond = al));
+  void mov_slow(Register rd, const char *string);
+  void mov_slow(Register rd, address addr);
+
+  void patchable_mov_oop(Register rd, jobject o, int oop_index) {
+    mov_oop(rd, o, oop_index AARCH64_ONLY_ARG(true));
+  }
+  void mov_oop(Register rd, jobject o, int index = 0
+               AARCH64_ONLY_ARG(bool patchable = false)
+               NOT_AARCH64_ARG(AsmCondition cond = al));
+
+
+  void patchable_mov_metadata(Register rd, Metadata* o, int index) {
+    mov_metadata(rd, o, index AARCH64_ONLY_ARG(true));
+  }
+  void mov_metadata(Register rd, Metadata* o, int index = 0 AARCH64_ONLY_ARG(bool patchable = false));
+
+  void mov_float(FloatRegister fd, jfloat c NOT_AARCH64_ARG(AsmCondition cond = al));
+  void mov_double(FloatRegister fd, jdouble c NOT_AARCH64_ARG(AsmCondition cond = al));
+
+#ifdef AARCH64
+  int mov_pc_to(Register rd) {
+    Label L;
+    adr(rd, L);
+    bind(L);
+    return offset();
+  }
+#endif
+
+  // Note: this variant of mov_address assumes the address moves with
+  // the code. Do *not* implement it with non-relocated instructions,
+  // unless PC-relative.
+#ifdef AARCH64
+  void mov_relative_address(Register rd, address addr) {
+    adr(rd, addr);
+  }
+#else
+  void mov_relative_address(Register rd, address addr, AsmCondition cond = al) {
+    int offset = addr - pc() - 8;
+    assert((offset & 3) == 0, "bad alignment");
+    if (offset >= 0) {
+      assert(AsmOperand::is_rotated_imm(offset), "addr too far");
+      add(rd, PC, offset, cond);
+    } else {
+      assert(AsmOperand::is_rotated_imm(-offset), "addr too far");
+      sub(rd, PC, -offset, cond);
+    }
+  }
+#endif // AARCH64
+
+  // Runtime address that may vary from one execution to another. The
+  // symbolic_reference describes what the address is, allowing
+  // the address to be resolved in a different execution context.
+  // Warning: do not implement as a PC relative address.
+  void mov_address(Register rd, address addr, symbolic_Relocation::symbolic_reference t) {
+    mov_address(rd, addr, RelocationHolder::none);
+  }
+
+  // rspec can be RelocationHolder::none (for ignored symbolic_Relocation).
+  // In that case, the address is absolute and the generated code need
+  // not be relocable.
+  void mov_address(Register rd, address addr, RelocationHolder const& rspec) {
+    assert(rspec.type() != relocInfo::runtime_call_type, "do not use mov_address for runtime calls");
+    assert(rspec.type() != relocInfo::static_call_type, "do not use mov_address for relocable calls");
+    if (rspec.type() == relocInfo::none) {
+      // absolute address, relocation not needed
+      mov_slow(rd, (intptr_t)addr);
+      return;
+    }
+#ifndef AARCH64
+    if (VM_Version::supports_movw()) {
+      relocate(rspec);
+      int c = (int)addr;
+      movw(rd, c & 0xffff);
+      if ((unsigned int)c >> 16) {
+        movt(rd, (unsigned int)c >> 16);
+      }
+      return;
+    }
+#endif
+    Label skip_literal;
+    InlinedAddress addr_literal(addr, rspec);
+    ldr_literal(rd, addr_literal);
+    b(skip_literal);
+    bind_literal(addr_literal);
+    // AARCH64 WARNING: because of alignment padding, extra padding
+    // may be required to get a consistent size for C2, or rules must
+    // overestimate size see MachEpilogNode::size
+    bind(skip_literal);
+  }
+
+  // Note: Do not define mov_address for a Label
+  //
+  // Load from addresses potentially within the code are now handled
+  // InlinedLiteral subclasses (to allow more flexibility on how the
+  // ldr_literal is performed).
+
+  void ldr_literal(Register rd, InlinedAddress& L) {
+    assert(L.rspec().type() != relocInfo::runtime_call_type, "avoid ldr_literal for calls");
+    assert(L.rspec().type() != relocInfo::static_call_type, "avoid ldr_literal for calls");
+    relocate(L.rspec());
+#ifdef AARCH64
+    ldr(rd, target(L.label));
+#else
+    ldr(rd, Address(PC, target(L.label) - pc() - 8));
+#endif
+  }
+
+  void ldr_literal(Register rd, InlinedString& L) {
+    const char* msg = L.msg();
+    if (code()->consts()->contains((address)msg)) {
+      // string address moves with the code
+#ifdef AARCH64
+      ldr(rd, (address)msg);
+#else
+      ldr(rd, Address(PC, ((address)msg) - pc() - 8));
+#endif
+      return;
+    }
+    // Warning: use external strings with care. They are not relocated
+    // if the code moves. If needed, use code_string to move them
+    // to the consts section.
+#ifdef AARCH64
+    ldr(rd, target(L.label));
+#else
+    ldr(rd, Address(PC, target(L.label) - pc() - 8));
+#endif
+  }
+
+  void ldr_literal(Register rd, InlinedMetadata& L) {
+    // relocation done in the bind_literal for metadatas
+#ifdef AARCH64
+    ldr(rd, target(L.label));
+#else
+    ldr(rd, Address(PC, target(L.label) - pc() - 8));
+#endif
+  }
+
+  void bind_literal(InlinedAddress& L) {
+    AARCH64_ONLY(align(wordSize));
+    bind(L.label);
+    assert(L.rspec().type() != relocInfo::metadata_type, "Must use InlinedMetadata");
+    // We currently do not use oop 'bound' literals.
+    // If the code evolves and the following assert is triggered,
+    // we need to implement InlinedOop (see InlinedMetadata).
+    assert(L.rspec().type() != relocInfo::oop_type, "Inlined oops not supported");
+    // Note: relocation is handled by relocate calls in ldr_literal
+    AbstractAssembler::emit_address((address)L.target());
+  }
+
+  void bind_literal(InlinedString& L) {
+    const char* msg = L.msg();
+    if (code()->consts()->contains((address)msg)) {
+      // The Label should not be used; avoid binding it
+      // to detect errors.
+      return;
+    }
+    AARCH64_ONLY(align(wordSize));
+    bind(L.label);
+    AbstractAssembler::emit_address((address)L.msg());
+  }
+
+  void bind_literal(InlinedMetadata& L) {
+    AARCH64_ONLY(align(wordSize));
+    bind(L.label);
+    relocate(metadata_Relocation::spec_for_immediate());
+    AbstractAssembler::emit_address((address)L.data());
+  }
+
+  void load_mirror(Register mirror, Register method, Register tmp);
+
+  // Porting layer between 32-bit ARM and AArch64
+
+#define COMMON_INSTR_1(common_mnemonic, aarch64_mnemonic, arm32_mnemonic, arg_type) \
+  void common_mnemonic(arg_type arg) { \
+      AARCH64_ONLY(aarch64_mnemonic) NOT_AARCH64(arm32_mnemonic) (arg); \
+  }
+
+#define COMMON_INSTR_2(common_mnemonic, aarch64_mnemonic, arm32_mnemonic, arg1_type, arg2_type) \
+  void common_mnemonic(arg1_type arg1, arg2_type arg2) { \
+      AARCH64_ONLY(aarch64_mnemonic) NOT_AARCH64(arm32_mnemonic) (arg1, arg2); \
+  }
+
+#define COMMON_INSTR_3(common_mnemonic, aarch64_mnemonic, arm32_mnemonic, arg1_type, arg2_type, arg3_type) \
+  void common_mnemonic(arg1_type arg1, arg2_type arg2, arg3_type arg3) { \
+      AARCH64_ONLY(aarch64_mnemonic) NOT_AARCH64(arm32_mnemonic) (arg1, arg2, arg3); \
+  }
+
+  COMMON_INSTR_1(jump, br,  bx,  Register)
+  COMMON_INSTR_1(call, blr, blx, Register)
+
+  COMMON_INSTR_2(cbz_32,  cbz_w,  cbz,  Register, Label&)
+  COMMON_INSTR_2(cbnz_32, cbnz_w, cbnz, Register, Label&)
+
+  COMMON_INSTR_2(ldr_u32, ldr_w,  ldr,  Register, Address)
+  COMMON_INSTR_2(ldr_s32, ldrsw,  ldr,  Register, Address)
+  COMMON_INSTR_2(str_32,  str_w,  str,  Register, Address)
+
+  COMMON_INSTR_2(mvn_32,  mvn_w,  mvn,  Register, Register)
+  COMMON_INSTR_2(cmp_32,  cmp_w,  cmp,  Register, Register)
+  COMMON_INSTR_2(neg_32,  neg_w,  neg,  Register, Register)
+  COMMON_INSTR_2(clz_32,  clz_w,  clz,  Register, Register)
+  COMMON_INSTR_2(rbit_32, rbit_w, rbit, Register, Register)
+
+  COMMON_INSTR_2(cmp_32,  cmp_w,  cmp,  Register, int)
+  COMMON_INSTR_2(cmn_32,  cmn_w,  cmn,  Register, int)
+
+  COMMON_INSTR_3(add_32,  add_w,  add,  Register, Register, Register)
+  COMMON_INSTR_3(sub_32,  sub_w,  sub,  Register, Register, Register)
+  COMMON_INSTR_3(subs_32, subs_w, subs, Register, Register, Register)
+  COMMON_INSTR_3(mul_32,  mul_w,  mul,  Register, Register, Register)
+  COMMON_INSTR_3(and_32,  andr_w, andr, Register, Register, Register)
+  COMMON_INSTR_3(orr_32,  orr_w,  orr,  Register, Register, Register)
+  COMMON_INSTR_3(eor_32,  eor_w,  eor,  Register, Register, Register)
+
+  COMMON_INSTR_3(add_32,  add_w,  add,  Register, Register, AsmOperand)
+  COMMON_INSTR_3(sub_32,  sub_w,  sub,  Register, Register, AsmOperand)
+  COMMON_INSTR_3(orr_32,  orr_w,  orr,  Register, Register, AsmOperand)
+  COMMON_INSTR_3(eor_32,  eor_w,  eor,  Register, Register, AsmOperand)
+  COMMON_INSTR_3(and_32,  andr_w, andr, Register, Register, AsmOperand)
+
+
+  COMMON_INSTR_3(add_32,  add_w,  add,  Register, Register, int)
+  COMMON_INSTR_3(adds_32, adds_w, adds, Register, Register, int)
+  COMMON_INSTR_3(sub_32,  sub_w,  sub,  Register, Register, int)
+  COMMON_INSTR_3(subs_32, subs_w, subs, Register, Register, int)
+
+  COMMON_INSTR_2(tst_32,  tst_w,  tst,  Register, unsigned int)
+  COMMON_INSTR_2(tst_32,  tst_w,  tst,  Register, AsmOperand)
+
+  COMMON_INSTR_3(and_32,  andr_w, andr, Register, Register, uint)
+  COMMON_INSTR_3(orr_32,  orr_w,  orr,  Register, Register, uint)
+  COMMON_INSTR_3(eor_32,  eor_w,  eor,  Register, Register, uint)
+
+  COMMON_INSTR_1(cmp_zero_float,  fcmp0_s, fcmpzs, FloatRegister)
+  COMMON_INSTR_1(cmp_zero_double, fcmp0_d, fcmpzd, FloatRegister)
+
+  COMMON_INSTR_2(ldr_float,   ldr_s,   flds,   FloatRegister, Address)
+  COMMON_INSTR_2(str_float,   str_s,   fsts,   FloatRegister, Address)
+  COMMON_INSTR_2(mov_float,   fmov_s,  fcpys,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(neg_float,   fneg_s,  fnegs,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(abs_float,   fabs_s,  fabss,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(sqrt_float,  fsqrt_s, fsqrts, FloatRegister, FloatRegister)
+  COMMON_INSTR_2(cmp_float,   fcmp_s,  fcmps,  FloatRegister, FloatRegister)
+
+  COMMON_INSTR_3(add_float,   fadd_s,  fadds,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(sub_float,   fsub_s,  fsubs,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(mul_float,   fmul_s,  fmuls,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(div_float,   fdiv_s,  fdivs,  FloatRegister, FloatRegister, FloatRegister)
+
+  COMMON_INSTR_2(ldr_double,  ldr_d,   fldd,   FloatRegister, Address)
+  COMMON_INSTR_2(str_double,  str_d,   fstd,   FloatRegister, Address)
+  COMMON_INSTR_2(mov_double,  fmov_d,  fcpyd,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(neg_double,  fneg_d,  fnegd,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(cmp_double,  fcmp_d,  fcmpd,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(abs_double,  fabs_d,  fabsd,  FloatRegister, FloatRegister)
+  COMMON_INSTR_2(sqrt_double, fsqrt_d, fsqrtd, FloatRegister, FloatRegister)
+
+  COMMON_INSTR_3(add_double,  fadd_d,  faddd,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(sub_double,  fsub_d,  fsubd,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(mul_double,  fmul_d,  fmuld,  FloatRegister, FloatRegister, FloatRegister)
+  COMMON_INSTR_3(div_double,  fdiv_d,  fdivd,  FloatRegister, FloatRegister, FloatRegister)
+
+  COMMON_INSTR_2(convert_f2d, fcvt_ds, fcvtds, FloatRegister, FloatRegister)
+  COMMON_INSTR_2(convert_d2f, fcvt_sd, fcvtsd, FloatRegister, FloatRegister)
+
+  COMMON_INSTR_2(mov_fpr2gpr_float, fmov_ws, fmrs, Register, FloatRegister)
+
+#undef COMMON_INSTR_1
+#undef COMMON_INSTR_2
+#undef COMMON_INSTR_3
+
+
+#ifdef AARCH64
+
+  void mov(Register dst, Register src, AsmCondition cond) {
+    if (cond == al) {
+      mov(dst, src);
+    } else {
+      csel(dst, src, dst, cond);
+    }
+  }
+
+  // Propagate other overloaded "mov" methods from Assembler.
+  void mov(Register dst, Register src)    { Assembler::mov(dst, src); }
+  void mov(Register rd, int imm)          { Assembler::mov(rd, imm);  }
+
+  void mov(Register dst, int imm, AsmCondition cond) {
+    assert(imm == 0 || imm == 1, "");
+    if (imm == 0) {
+      mov(dst, ZR, cond);
+    } else if (imm == 1) {
+      csinc(dst, dst, ZR, inverse(cond));
+    } else if (imm == -1) {
+      csinv(dst, dst, ZR, inverse(cond));
+    } else {
+      fatal("illegal mov(R%d,%d,cond)", dst->encoding(), imm);
+    }
+  }
+
+  void movs(Register dst, Register src)    { adds(dst, src, 0); }
+
+#else // AARCH64
+
+  void tbz(Register rt, int bit, Label& L) {
+    assert(0 <= bit && bit < BitsPerWord, "bit number is out of range");
+    tst(rt, 1 << bit);
+    b(L, eq);
+  }
+
+  void tbnz(Register rt, int bit, Label& L) {
+    assert(0 <= bit && bit < BitsPerWord, "bit number is out of range");
+    tst(rt, 1 << bit);
+    b(L, ne);
+  }
+
+  void cbz(Register rt, Label& L) {
+    cmp(rt, 0);
+    b(L, eq);
+  }
+
+  void cbz(Register rt, address target) {
+    cmp(rt, 0);
+    b(target, eq);
+  }
+
+  void cbnz(Register rt, Label& L) {
+    cmp(rt, 0);
+    b(L, ne);
+  }
+
+  void ret(Register dst = LR) {
+    bx(dst);
+  }
+
+#endif // AARCH64
+
+  Register zero_register(Register tmp) {
+#ifdef AARCH64
+    return ZR;
+#else
+    mov(tmp, 0);
+    return tmp;
+#endif
+  }
+
+  void logical_shift_left(Register dst, Register src, int shift) {
+#ifdef AARCH64
+    _lsl(dst, src, shift);
+#else
+    mov(dst, AsmOperand(src, lsl, shift));
+#endif
+  }
+
+  void logical_shift_left_32(Register dst, Register src, int shift) {
+#ifdef AARCH64
+    _lsl_w(dst, src, shift);
+#else
+    mov(dst, AsmOperand(src, lsl, shift));
+#endif
+  }
+
+  void logical_shift_right(Register dst, Register src, int shift) {
+#ifdef AARCH64
+    _lsr(dst, src, shift);
+#else
+    mov(dst, AsmOperand(src, lsr, shift));
+#endif
+  }
+
+  void arith_shift_right(Register dst, Register src, int shift) {
+#ifdef AARCH64
+    _asr(dst, src, shift);
+#else
+    mov(dst, AsmOperand(src, asr, shift));
+#endif
+  }
+
+  void asr_32(Register dst, Register src, int shift) {
+#ifdef AARCH64
+    _asr_w(dst, src, shift);
+#else
+    mov(dst, AsmOperand(src, asr, shift));
+#endif
+  }
+
+  // If <cond> holds, compares r1 and r2. Otherwise, flags are set so that <cond> does not hold.
+  void cond_cmp(Register r1, Register r2, AsmCondition cond) {
+#ifdef AARCH64
+    ccmp(r1, r2, flags_for_condition(inverse(cond)), cond);
+#else
+    cmp(r1, r2, cond);
+#endif
+  }
+
+  // If <cond> holds, compares r and imm. Otherwise, flags are set so that <cond> does not hold.
+  void cond_cmp(Register r, int imm, AsmCondition cond) {
+#ifdef AARCH64
+    ccmp(r, imm, flags_for_condition(inverse(cond)), cond);
+#else
+    cmp(r, imm, cond);
+#endif
+  }
+
+  void align_reg(Register dst, Register src, int align) {
+    assert (is_power_of_2(align), "should be");
+#ifdef AARCH64
+    andr(dst, src, ~(uintx)(align-1));
+#else
+    bic(dst, src, align-1);
+#endif
+  }
+
+  void prefetch_read(Address addr) {
+#ifdef AARCH64
+    prfm(pldl1keep, addr);
+#else
+    pld(addr);
+#endif
+  }
+
+  void raw_push(Register r1, Register r2) {
+#ifdef AARCH64
+    stp(r1, r2, Address(SP, -2*wordSize, pre_indexed));
+#else
+    assert(r1->encoding() < r2->encoding(), "should be ordered");
+    push(RegisterSet(r1) | RegisterSet(r2));
+#endif
+  }
+
+  void raw_pop(Register r1, Register r2) {
+#ifdef AARCH64
+    ldp(r1, r2, Address(SP, 2*wordSize, post_indexed));
+#else
+    assert(r1->encoding() < r2->encoding(), "should be ordered");
+    pop(RegisterSet(r1) | RegisterSet(r2));
+#endif
+  }
+
+  void raw_push(Register r1, Register r2, Register r3) {
+#ifdef AARCH64
+    raw_push(r1, r2);
+    raw_push(r3, ZR);
+#else
+    assert(r1->encoding() < r2->encoding() && r2->encoding() < r3->encoding(), "should be ordered");
+    push(RegisterSet(r1) | RegisterSet(r2) | RegisterSet(r3));
+#endif
+  }
+
+  void raw_pop(Register r1, Register r2, Register r3) {
+#ifdef AARCH64
+    raw_pop(r3, ZR);
+    raw_pop(r1, r2);
+#else
+    assert(r1->encoding() < r2->encoding() && r2->encoding() < r3->encoding(), "should be ordered");
+    pop(RegisterSet(r1) | RegisterSet(r2) | RegisterSet(r3));
+#endif
+  }
+
+  // Restores registers r1 and r2 previously saved by raw_push(r1, r2, ret_addr) and returns by ret_addr. Clobbers LR.
+  void raw_pop_and_ret(Register r1, Register r2) {
+#ifdef AARCH64
+    raw_pop(r1, r2, LR);
+    ret();
+#else
+    raw_pop(r1, r2, PC);
+#endif
+  }
+
+  void indirect_jump(Address addr, Register scratch) {
+#ifdef AARCH64
+    ldr(scratch, addr);
+    br(scratch);
+#else
+    ldr(PC, addr);
+#endif
+  }
+
+  void indirect_jump(InlinedAddress& literal, Register scratch) {
+#ifdef AARCH64
+    ldr_literal(scratch, literal);
+    br(scratch);
+#else
+    ldr_literal(PC, literal);
+#endif
+  }
+
+#ifndef AARCH64
+  void neg(Register dst, Register src) {
+    rsb(dst, src, 0);
+  }
+#endif
+
+  void branch_if_negative_32(Register r, Label& L) {
+    // Note about branch_if_negative_32() / branch_if_any_negative_32() implementation for AArch64:
+    // tbnz is not used instead of tst & b.mi because destination may be out of tbnz range (+-32KB)
+    // since these methods are used in LIR_Assembler::emit_arraycopy() to jump to stub entry.
+    tst_32(r, r);
+    b(L, mi);
+  }
+
+  void branch_if_any_negative_32(Register r1, Register r2, Register tmp, Label& L) {
+#ifdef AARCH64
+    orr_32(tmp, r1, r2);
+    tst_32(tmp, tmp);
+#else
+    orrs(tmp, r1, r2);
+#endif
+    b(L, mi);
+  }
+
+  void branch_if_any_negative_32(Register r1, Register r2, Register r3, Register tmp, Label& L) {
+    orr_32(tmp, r1, r2);
+#ifdef AARCH64
+    orr_32(tmp, tmp, r3);
+    tst_32(tmp, tmp);
+#else
+    orrs(tmp, tmp, r3);
+#endif
+    b(L, mi);
+  }
+
+  void add_ptr_scaled_int32(Register dst, Register r1, Register r2, int shift) {
+#ifdef AARCH64
+      add(dst, r1, r2, ex_sxtw, shift);
+#else
+      add(dst, r1, AsmOperand(r2, lsl, shift));
+#endif
+  }
+
+  void sub_ptr_scaled_int32(Register dst, Register r1, Register r2, int shift) {
+#ifdef AARCH64
+    sub(dst, r1, r2, ex_sxtw, shift);
+#else
+    sub(dst, r1, AsmOperand(r2, lsl, shift));
+#endif
+  }
+
+
+    // klass oop manipulations if compressed
+
+#ifdef AARCH64
+  void load_klass(Register dst_klass, Register src_oop);
+#else
+  void load_klass(Register dst_klass, Register src_oop, AsmCondition cond = al);
+#endif // AARCH64
+
+  void store_klass(Register src_klass, Register dst_oop);
+
+#ifdef AARCH64
+  void store_klass_gap(Register dst);
+#endif // AARCH64
+
+    // oop manipulations
+
+  void load_heap_oop(Register dst, Address src);
+  void store_heap_oop(Register src, Address dst);
+  void store_heap_oop(Address dst, Register src) {
+    store_heap_oop(src, dst);
+  }
+  void store_heap_oop_null(Register src, Address dst);
+
+#ifdef AARCH64
+  void encode_heap_oop(Register dst, Register src);
+  void encode_heap_oop(Register r) {
+    encode_heap_oop(r, r);
+  }
+  void decode_heap_oop(Register dst, Register src);
+  void decode_heap_oop(Register r) {
+      decode_heap_oop(r, r);
+  }
+
+#ifdef COMPILER2
+  void encode_heap_oop_not_null(Register dst, Register src);
+  void decode_heap_oop_not_null(Register dst, Register src);
+
+  void set_narrow_klass(Register dst, Klass* k);
+  void set_narrow_oop(Register dst, jobject obj);
+#endif
+
+  void encode_klass_not_null(Register r);
+  void encode_klass_not_null(Register dst, Register src);
+  void decode_klass_not_null(Register r);
+  void decode_klass_not_null(Register dst, Register src);
+
+  void reinit_heapbase();
+
+#ifdef ASSERT
+  void verify_heapbase(const char* msg);
+#endif // ASSERT
+
+  static int instr_count_for_mov_slow(intptr_t c);
+  static int instr_count_for_mov_slow(address addr);
+  static int instr_count_for_decode_klass_not_null();
+#endif // AARCH64
+
+  void ldr_global_ptr(Register reg, address address_of_global);
+  void ldr_global_s32(Register reg, address address_of_global);
+  void ldrb_global(Register reg, address address_of_global);
+
+  // address_placeholder_instruction is invalid instruction and is used
+  // as placeholder in code for address of label
+  enum { address_placeholder_instruction = 0xFFFFFFFF };
+
+  void emit_address(Label& L) {
+    assert(!L.is_bound(), "otherwise address will not be patched");
+    target(L);       // creates relocation which will be patched later
+
+    assert ((offset() & (wordSize-1)) == 0, "should be aligned by word size");
+
+#ifdef AARCH64
+    emit_int32(address_placeholder_instruction);
+    emit_int32(address_placeholder_instruction);
+#else
+    AbstractAssembler::emit_address((address)address_placeholder_instruction);
+#endif
+  }
+
+  void b(address target, AsmCondition cond = al) {
+    Assembler::b(target, cond);                 \
+  }
+  void b(Label& L, AsmCondition cond = al) {
+    // internal jumps
+    Assembler::b(target(L), cond);
+  }
+
+  void bl(address target NOT_AARCH64_ARG(AsmCondition cond = al)) {
+    Assembler::bl(target NOT_AARCH64_ARG(cond));
+  }
+  void bl(Label& L NOT_AARCH64_ARG(AsmCondition cond = al)) {
+    // internal calls
+    Assembler::bl(target(L)  NOT_AARCH64_ARG(cond));
+  }
+
+#ifndef AARCH64
+  void adr(Register dest, Label& L, AsmCondition cond = al) {
+    int delta = target(L) - pc() - 8;
+    if (delta >= 0) {
+      add(dest, PC, delta, cond);
+    } else {
+      sub(dest, PC, -delta, cond);
+    }
+  }
+#endif // !AARCH64
+
+  // Variable-length jump and calls. We now distinguish only the
+  // patchable case from the other cases. Patchable must be
+  // distinguised from relocable. Relocable means the generated code
+  // containing the jump/call may move. Patchable means that the
+  // targeted address may be changed later.
+
+  // Non patchable versions.
+  // - used only for relocInfo::runtime_call_type and relocInfo::none
+  // - may use relative or absolute format (do not use relocInfo::none
+  //   if the generated code may move)
+  // - the implementation takes into account switch to THUMB mode if the
+  //   destination is a THUMB address
+  // - the implementation supports far targets
+  //
+  // To reduce regression risk, scratch still defaults to noreg on
+  // arm32. This results in patchable instructions. However, if
+  // patching really matters, the call sites should be modified and
+  // use patchable_call or patchable_jump. If patching is not required
+  // and if a register can be cloberred, it should be explicitly
+  // specified to allow future optimizations.
+  void jump(address target,
+            relocInfo::relocType rtype = relocInfo::runtime_call_type,
+            Register scratch = AARCH64_ONLY(Rtemp) NOT_AARCH64(noreg)
+#ifndef AARCH64
+            , AsmCondition cond = al
+#endif
+            );
+
+  void call(address target,
+            RelocationHolder rspec
+            NOT_AARCH64_ARG(AsmCondition cond = al));
+
+  void call(address target,
+            relocInfo::relocType rtype = relocInfo::runtime_call_type
+            NOT_AARCH64_ARG(AsmCondition cond = al)) {
+    call(target, Relocation::spec_simple(rtype) NOT_AARCH64_ARG(cond));
+  }
+
+  void jump(AddressLiteral dest) {
+    jump(dest.target(), dest.reloc());
+  }
+#ifndef AARCH64
+  void jump(address dest, relocInfo::relocType rtype, AsmCondition cond) {
+    jump(dest, rtype, Rtemp, cond);
+  }
+#endif
+
+  void call(AddressLiteral dest) {
+    call(dest.target(), dest.reloc());
+  }
+
+  // Patchable version:
+  // - set_destination can be used to atomically change the target
+  //
+  // The targets for patchable_jump and patchable_call must be in the
+  // code cache.
+  // [ including possible extensions of the code cache, like AOT code ]
+  //
+  // To reduce regression risk, scratch still defaults to noreg on
+  // arm32. If a register can be cloberred, it should be explicitly
+  // specified to allow future optimizations.
+  void patchable_jump(address target,
+                      relocInfo::relocType rtype = relocInfo::runtime_call_type,
+                      Register scratch = AARCH64_ONLY(Rtemp) NOT_AARCH64(noreg)
+#ifndef AARCH64
+                      , AsmCondition cond = al
+#endif
+                      );
+
+  // patchable_call may scratch Rtemp
+  int patchable_call(address target,
+                     RelocationHolder const& rspec,
+                     bool c2 = false);
+
+  int patchable_call(address target,
+                     relocInfo::relocType rtype,
+                     bool c2 = false) {
+    return patchable_call(target, Relocation::spec_simple(rtype), c2);
+  }
+
+#if defined(AARCH64) && defined(COMPILER2)
+  static int call_size(address target, bool far, bool patchable);
+#endif
+
+#ifdef AARCH64
+  static bool page_reachable_from_cache(address target);
+#endif
+  static bool _reachable_from_cache(address target);
+  static bool _cache_fully_reachable();
+  bool cache_fully_reachable();
+  bool reachable_from_cache(address target);
+
+  void zero_extend(Register rd, Register rn, int bits);
+  void sign_extend(Register rd, Register rn, int bits);
+
+  inline void zap_high_non_significant_bits(Register r) {
+#ifdef AARCH64
+    if(ZapHighNonSignificantBits) {
+      movk(r, 0xBAAD, 48);
+      movk(r, 0xF00D, 32);
+    }
+#endif
+  }
+
+#ifndef AARCH64
+  void long_move(Register rd_lo, Register rd_hi,
+                 Register rn_lo, Register rn_hi,
+                 AsmCondition cond = al);
+  void long_shift(Register rd_lo, Register rd_hi,
+                  Register rn_lo, Register rn_hi,
+                  AsmShift shift, Register count);
+  void long_shift(Register rd_lo, Register rd_hi,
+                  Register rn_lo, Register rn_hi,
+                  AsmShift shift, int count);
+
+  void atomic_cas(Register tmpreg1, Register tmpreg2, Register oldval, Register newval, Register base, int offset);
+  void atomic_cas_bool(Register oldval, Register newval, Register base, int offset, Register tmpreg);
+  void atomic_cas64(Register temp_lo, Register temp_hi, Register temp_result, Register oldval_lo, Register oldval_hi, Register newval_lo, Register newval_hi, Register base, int offset);
+#endif // !AARCH64
+
+  void cas_for_lock_acquire(Register oldval, Register newval, Register base, Register tmp, Label &slow_case, bool allow_fallthrough_on_failure = false, bool one_shot = false);
+  void cas_for_lock_release(Register oldval, Register newval, Register base, Register tmp, Label &slow_case, bool allow_fallthrough_on_failure = false, bool one_shot = false);
+
+#ifndef PRODUCT
+  // Preserves flags and all registers.
+  // On SMP the updated value might not be visible to external observers without a sychronization barrier
+  void cond_atomic_inc32(AsmCondition cond, int* counter_addr);
+#endif // !PRODUCT
+
+  // unconditional non-atomic increment
+  void inc_counter(address counter_addr, Register tmpreg1, Register tmpreg2);
+  void inc_counter(int* counter_addr, Register tmpreg1, Register tmpreg2) {
+    inc_counter((address) counter_addr, tmpreg1, tmpreg2);
+  }
+
+  void pd_patch_instruction(address branch, address target);
+
+  // Loading and storing values by size and signed-ness;
+  // size must not exceed wordSize (i.e. 8-byte values are not supported on 32-bit ARM);
+  // each of these calls generates exactly one load or store instruction,
+  // so src can be pre- or post-indexed address.
+#ifdef AARCH64
+  void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed);
+  void store_sized_value(Register src, Address dst, size_t size_in_bytes);
+#else
+  // 32-bit ARM variants also support conditional execution
+  void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, AsmCondition cond = al);
+  void store_sized_value(Register src, Address dst, size_t size_in_bytes, AsmCondition cond = al);
+#endif
+
+  void lookup_interface_method(Register recv_klass,
+                               Register intf_klass,
+                               Register itable_index,
+                               Register method_result,
+                               Register temp_reg1,
+                               Register temp_reg2,
+                               Label& L_no_such_interface);
+
+  // Compare char[] arrays aligned to 4 bytes.
+  void char_arrays_equals(Register ary1, Register ary2,
+                          Register limit, Register result,
+                          Register chr1, Register chr2, Label& Ldone);
+
+
+  void floating_cmp(Register dst);
+
+  // improved x86 portability (minimizing source code changes)
+
+  void ldr_literal(Register rd, AddressLiteral addr) {
+    relocate(addr.rspec());
+#ifdef AARCH64
+    ldr(rd, addr.target());
+#else
+    ldr(rd, Address(PC, addr.target() - pc() - 8));
+#endif
+  }
+
+  void lea(Register Rd, AddressLiteral addr) {
+    // Never dereferenced, as on x86 (lval status ignored)
+    mov_address(Rd, addr.target(), addr.rspec());
+  }
+
+  void restore_default_fp_mode();
+
+#ifdef COMPILER2
+#ifdef AARCH64
+  // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file.
+  void fast_lock(Register obj, Register box, Register scratch, Register scratch2, Register scratch3);
+  void fast_unlock(Register obj, Register box, Register scratch, Register scratch2, Register scratch3);
+#else
+  void fast_lock(Register obj, Register box, Register scratch, Register scratch2);
+  void fast_unlock(Register obj, Register box, Register scratch, Register scratch2);
+#endif
+#endif
+
+#ifdef AARCH64
+
+#define F(mnemonic)                                             \
+  void mnemonic(Register rt, address target) {                  \
+    Assembler::mnemonic(rt, target);                            \
+  }                                                             \
+  void mnemonic(Register rt, Label& L) {                        \
+    Assembler::mnemonic(rt, target(L));                         \
+  }
+
+  F(cbz_w);
+  F(cbnz_w);
+  F(cbz);
+  F(cbnz);
+
+#undef F
+
+#define F(mnemonic)                                             \
+  void mnemonic(Register rt, int bit, address target) {         \
+    Assembler::mnemonic(rt, bit, target);                       \
+  }                                                             \
+  void mnemonic(Register rt, int bit, Label& L) {               \
+    Assembler::mnemonic(rt, bit, target(L));                    \
+  }
+
+  F(tbz);
+  F(tbnz);
+#undef F
+
+#endif // AARCH64
+
+};
+
+
+// The purpose of this class is to build several code fragments of the same size
+// in order to allow fast table branch.
+
+class FixedSizeCodeBlock VALUE_OBJ_CLASS_SPEC {
+public:
+  FixedSizeCodeBlock(MacroAssembler* masm, int size_in_instrs, bool enabled);
+  ~FixedSizeCodeBlock();
+
+private:
+  MacroAssembler* _masm;
+  address _start;
+  int _size_in_instrs;
+  bool _enabled;
+};
+
+
+#endif // CPU_ARM_VM_MACROASSEMBLER_ARM_HPP
+
diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.inline.hpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.inline.hpp
new file mode 100644
index 0000000..14c844c
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.inline.hpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_MACROASSEMBLER_ARM_INLINE_HPP
+#define CPU_ARM_VM_MACROASSEMBLER_ARM_INLINE_HPP
+
+#include "asm/assembler.inline.hpp"
+#include "asm/codeBuffer.hpp"
+#include "code/codeCache.hpp"
+#include "runtime/handles.inline.hpp"
+
+inline void MacroAssembler::pd_patch_instruction(address branch, address target) {
+  int instr = *(int*)branch;
+  int new_offset = (int)(target - branch NOT_AARCH64(- 8));
+  assert((new_offset & 3) == 0, "bad alignment");
+
+#ifdef AARCH64
+  if ((instr & (0x1f << 26)) == (0b00101 << 26)) {
+    // Unconditional B or BL
+    assert (is_offset_in_range(new_offset, 26), "offset is too large");
+    *(int*)branch = (instr & ~right_n_bits(26)) | encode_offset(new_offset, 26, 0);
+  } else if ((instr & (0xff << 24)) == (0b01010100 << 24) && (instr & (1 << 4)) == 0) {
+    // Conditional B
+    assert (is_offset_in_range(new_offset, 19), "offset is too large");
+    *(int*)branch = (instr & ~(right_n_bits(19) << 5)) | encode_offset(new_offset, 19, 5);
+  } else if ((instr & (0b111111 << 25)) == (0b011010 << 25)) {
+    // Compare & branch CBZ/CBNZ
+    assert (is_offset_in_range(new_offset, 19), "offset is too large");
+    *(int*)branch = (instr & ~(right_n_bits(19) << 5)) | encode_offset(new_offset, 19, 5);
+  } else if ((instr & (0b111111 << 25)) == (0b011011 << 25)) {
+    // Test & branch TBZ/TBNZ
+    assert (is_offset_in_range(new_offset, 14), "offset is too large");
+    *(int*)branch = (instr & ~(right_n_bits(14) << 5)) | encode_offset(new_offset, 14, 5);
+  } else if ((instr & (0b111011 << 24)) == (0b011000 << 24)) {
+    // LDR (literal)
+    unsigned opc = ((unsigned)instr >> 30);
+    assert (opc != 0b01 || ((uintx)target & 7) == 0, "ldr target should be aligned");
+    assert (is_offset_in_range(new_offset, 19), "offset is too large");
+    *(int*)branch = (instr & ~(right_n_bits(19) << 5)) | encode_offset(new_offset, 19, 5);
+  } else if (((instr & (1 << 31)) == 0) && ((instr & (0b11111 << 24)) == (0b10000 << 24))) {
+    // ADR
+    assert (is_imm_in_range(new_offset, 21, 0), "offset is too large");
+    instr = (instr & ~(right_n_bits(2) << 29)) | (new_offset & 3) << 29;
+    *(int*)branch = (instr & ~(right_n_bits(19) << 5)) | encode_imm(new_offset >> 2, 19, 0, 5);
+  } else if((unsigned int)instr == address_placeholder_instruction) {
+    // address
+    assert (*(unsigned int *)(branch + InstructionSize) == address_placeholder_instruction, "address placeholder occupies two instructions");
+    *(intx*)branch = (intx)target;
+  } else {
+    ::tty->print_cr("=============== instruction: 0x%x ================\n", instr);
+    Unimplemented(); // TODO-AARCH64
+  }
+#else
+  if ((instr & 0x0e000000) == 0x0a000000) {
+    // B or BL instruction
+    assert(new_offset < 0x2000000 && new_offset > -0x2000000, "encoding constraint");
+    *(int*)branch = (instr & 0xff000000) | ((unsigned int)new_offset << 6 >> 8);
+  } else if((unsigned int)instr == address_placeholder_instruction) {
+    // address
+    *(int*)branch = (int)target;
+  } else if ((instr & 0x0fff0000) == 0x028f0000 || ((instr & 0x0fff0000) == 0x024f0000)) {
+    // ADR
+    int encoding = 0x8 << 20; // ADD
+    if (new_offset < 0) {
+      encoding = 0x4 << 20; // SUB
+      new_offset = -new_offset;
+    }
+    AsmOperand o(new_offset);
+    *(int*)branch = (instr & 0xff0ff000) | encoding | o.encoding();
+  } else {
+    // LDR Rd, [PC, offset] instruction
+    assert((instr & 0x0f7f0000) == 0x051f0000, "Must be ldr_literal");
+    assert(new_offset < 4096 && new_offset > -4096, "encoding constraint");
+    if (new_offset >= 0) {
+      *(int*)branch = (instr & 0xff0ff000) | 9 << 20 | new_offset;
+    } else {
+      *(int*)branch = (instr & 0xff0ff000) | 1 << 20 | -new_offset;
+    }
+  }
+#endif // AARCH64
+}
+
+#endif // CPU_ARM_VM_MACROASSEMBLER_ARM_INLINE_HPP
diff --git a/hotspot/src/cpu/arm/vm/metaspaceShared_arm.cpp b/hotspot/src/cpu/arm/vm/metaspaceShared_arm.cpp
new file mode 100644
index 0000000..1cda4df
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/metaspaceShared_arm.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "memory/metaspaceShared.hpp"
+
+// Generate the self-patching vtable method:
+//
+// This method will be called (as any other Klass virtual method) with
+// the Klass itself as the first argument.  Example:
+//
+//      oop obj;
+//      int size = obj->klass()->oop_size(this);
+//
+// for which the virtual method call is Klass::oop_size();
+//
+// The dummy method is called with the Klass object as the first
+// operand, and an object as the second argument.
+//
+
+//=====================================================================
+
+// All of the dummy methods in the vtable are essentially identical,
+// differing only by an ordinal constant, and they bear no relationship
+// to the original method which the caller intended. Also, there needs
+// to be 'vtbl_list_size' instances of the vtable in order to
+// differentiate between the 'vtable_list_size' original Klass objects.
+
+#define __ masm->
+
+void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
+                                                   void** vtable,
+                                                   char** md_top,
+                                                   char* md_end,
+                                                   char** mc_top,
+                                                   char* mc_end) {
+  intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
+  *(intptr_t *)(*md_top) = vtable_bytes;
+  *md_top += sizeof(intptr_t);
+  void** dummy_vtable = (void**)*md_top;
+  *vtable = dummy_vtable;
+  *md_top += vtable_bytes;
+
+  CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
+  MacroAssembler* masm = new MacroAssembler(&cb);
+
+  for (int i = 0; i < vtbl_list_size; ++i) {
+    Label common_code;
+    for (int j = 0; j < num_virtuals; ++j) {
+      dummy_vtable[num_virtuals * i + j] = (void*) __ pc();
+      __ mov(Rtemp, j);  // Rtemp contains an index of a virtual method in the table
+      __ b(common_code);
+    }
+
+    InlinedAddress vtable_address((address)&vtbl_list[i]);
+    __ bind(common_code);
+    const Register tmp2 = AARCH64_ONLY(Rtemp2) NOT_AARCH64(R4);
+    assert_different_registers(Rtemp, tmp2);
+#ifndef AARCH64
+    __ push(tmp2);
+#endif // !AARCH64
+    // Do not use ldr_global since the code must be portable across all ARM architectures
+    __ ldr_literal(tmp2, vtable_address);
+    __ ldr(tmp2, Address(tmp2));                              // get correct vtable address
+    __ ldr(Rtemp, Address::indexed_ptr(tmp2, Rtemp));         // get real method pointer
+    __ str(tmp2, Address(R0));                                // update vtable. R0 = "this"
+#ifndef AARCH64
+    __ pop(tmp2);
+#endif // !AARCH64
+    __ jump(Rtemp);
+    __ bind_literal(vtable_address);
+  }
+
+  __ flush();
+  *mc_top = (char*) __ pc();
+}
diff --git a/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp b/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp
new file mode 100644
index 0000000..1531796
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This file mirror as much as possible methodHandles_x86.cpp to ease
+// cross platform development for JSR292.
+// Last synchronization: changeset f8c9417e3571
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/methodHandles.hpp"
+
+#define __ _masm->
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
+
+#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
+
+void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp1, Register temp2) {
+  if (VerifyMethodHandles) {
+    verify_klass(_masm, klass_reg, temp1, temp2, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class),
+                 "MH argument is a Class");
+  }
+  __ ldr(klass_reg, Address(klass_reg, java_lang_Class::klass_offset_in_bytes()));
+}
+
+#ifdef ASSERT
+static int check_nonzero(const char* xname, int x) {
+  assert(x != 0, "%s should be nonzero", xname);
+  return x;
+}
+#define NONZERO(x) check_nonzero(#x, x)
+#else //ASSERT
+#define NONZERO(x) (x)
+#endif //ASSERT
+
+#ifdef ASSERT
+void MethodHandles::verify_klass(MacroAssembler* _masm,
+                                 Register obj, Register temp1, Register temp2, SystemDictionary::WKID klass_id,
+                                 const char* error_message) {
+  InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
+  KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
+  Label L_ok, L_bad;
+  BLOCK_COMMENT("verify_klass {");
+  __ verify_oop(obj);
+  __ cbz(obj, L_bad);
+  __ load_klass(temp1, obj);
+  __ lea(temp2, ExternalAddress((address) klass_addr));
+  __ ldr(temp2, temp2); // the cmpptr on x86 dereferences the AddressLiteral (not lea)
+  __ cmp(temp1, temp2);
+  __ b(L_ok, eq);
+  intptr_t super_check_offset = klass->super_check_offset();
+  __ ldr(temp1, Address(temp1, super_check_offset));
+  __ cmp(temp1, temp2);
+  __ b(L_ok, eq);
+
+  __ bind(L_bad);
+  __ stop(error_message);
+  __ BIND(L_ok);
+  BLOCK_COMMENT("} verify_klass");
+}
+
+void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {
+  Label L;
+  BLOCK_COMMENT("verify_ref_kind {");
+  __ ldr_u32(temp, Address(member_reg, NONZERO(java_lang_invoke_MemberName::flags_offset_in_bytes())));
+  __ logical_shift_right(temp, temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT);
+  __ andr(temp, temp, (unsigned)java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK);
+  __ cmp(temp, ref_kind);
+  __ b(L, eq);
+  { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal);
+  jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind);
+  if (ref_kind == JVM_REF_invokeVirtual ||
+      ref_kind == JVM_REF_invokeSpecial)
+    // could do this for all ref_kinds, but would explode assembly code size
+    trace_method_handle(_masm, buf);
+  __ stop(buf);
+  }
+  BLOCK_COMMENT("} verify_ref_kind");
+  __ bind(L);
+}
+
+#endif //ASSERT
+
+void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, bool for_compiler_entry) {
+  Label L_no_such_method;
+  __ cbz(Rmethod, L_no_such_method);
+
+  // Note: JVMTI overhead seems small enough compared to invocation
+  // cost and is not worth the complexity or code size overhead of
+  // supporting several variants of each adapter.
+  if (!for_compiler_entry && (JvmtiExport::can_post_interpreter_events())) {
+    // JVMTI events, such as single-stepping, are implemented partly by avoiding running
+    // compiled code in threads for which the event is enabled.  Check here for
+    // interp_only_mode if these events CAN be enabled.
+    __ ldr_s32(Rtemp, Address(Rthread, JavaThread::interp_only_mode_offset()));
+#ifdef AARCH64
+    Label L;
+    __ cbz(Rtemp, L);
+    __ indirect_jump(Address(Rmethod, Method::interpreter_entry_offset()), Rtemp);
+    __ bind(L);
+#else
+    __ cmp(Rtemp, 0);
+    __ ldr(PC, Address(Rmethod, Method::interpreter_entry_offset()), ne);
+#endif // AARCH64
+  }
+  const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
+                                                     Method::from_interpreted_offset();
+
+  __ indirect_jump(Address(Rmethod, entry_offset), Rtemp);
+
+  __ bind(L_no_such_method);
+  // throw exception
+  __ jump(StubRoutines::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp);
+}
+
+void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
+                                        Register recv, Register tmp,
+                                        bool for_compiler_entry) {
+  BLOCK_COMMENT("jump_to_lambda_form {");
+  // This is the initial entry point of a lazy method handle.
+  // After type checking, it picks up the invoker from the LambdaForm.
+  assert_different_registers(recv, tmp, Rmethod);
+
+  // Load the invoker, as MH -> MH.form -> LF.vmentry
+  __ load_heap_oop(tmp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())));
+  __ verify_oop(tmp);
+
+  __ load_heap_oop(tmp, Address(tmp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())));
+  __ verify_oop(tmp);
+
+  // the following assumes that a Method* is normally compressed in the vmtarget field:
+  __ ldr(Rmethod, Address(tmp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())));
+
+  if (VerifyMethodHandles && !for_compiler_entry) {
+    // make sure recv is already on stack
+    __ ldr(tmp, Address(Rmethod, Method::const_offset()));
+    __ load_sized_value(tmp,
+                        Address(tmp, ConstMethod::size_of_parameters_offset()),
+                        sizeof(u2), /*is_signed*/ false);
+    // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
+    Label L;
+    __ ldr(tmp, __ receiver_argument_address(Rparams, tmp, tmp));
+    __ cmp(tmp, recv);
+    __ b(L, eq);
+    __ stop("receiver not on stack");
+    __ bind(L);
+  }
+
+  jump_from_method_handle(_masm, for_compiler_entry);
+  BLOCK_COMMENT("} jump_to_lambda_form");
+}
+
+
+// Code generation
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
+                                                                vmIntrinsics::ID iid) {
+  const bool not_for_compiler_entry = false;  // this is the interpreter entry
+  assert(is_signature_polymorphic(iid), "expected invoke iid");
+  if (iid == vmIntrinsics::_invokeGeneric ||
+      iid == vmIntrinsics::_compiledLambdaForm) {
+    // Perhaps surprisingly, the user-visible names, and linkToCallSite, are not directly used.
+    // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod.
+    // They all require an extra argument.
+    __ should_not_reach_here();           // empty stubs make SG sick
+    return NULL;
+  }
+
+  // Rmethod: Method*
+  // Rparams (SP on 32-bit ARM): pointer to parameters
+  // Rsender_sp (R4/R19): sender SP (must preserve; see prepare_to_jump_from_interpreted)
+  // R5_mh: receiver method handle (must load from sp[MethodTypeForm.vmslots])
+  // R1, R2, Rtemp: garbage temp, blown away
+
+  // Use same name as x86 to ease future merges
+  Register rdx_temp       = R2_tmp;
+  Register rdx_param_size = rdx_temp;  // size of parameters
+  Register rax_temp       = R1_tmp;
+  Register rcx_mh         = R5_mh;     // MH receiver; dies quickly and is recycled
+  Register rbx_method     = Rmethod;   // eventual target of this invocation
+  Register rdi_temp       = Rtemp;
+
+  // here's where control starts out:
+  __ align(CodeEntryAlignment);
+  address entry_point = __ pc();
+
+  if (VerifyMethodHandles) {
+    Label L;
+    BLOCK_COMMENT("verify_intrinsic_id {");
+    __ ldrh(rdi_temp, Address(rbx_method, Method::intrinsic_id_offset_in_bytes()));
+    __ sub_slow(rdi_temp, rdi_temp, (int) iid);
+    __ cbz(rdi_temp, L);
+    if (iid == vmIntrinsics::_linkToVirtual ||
+        iid == vmIntrinsics::_linkToSpecial) {
+      // could do this for all kinds, but would explode assembly code size
+      trace_method_handle(_masm, "bad Method*::intrinsic_id");
+    }
+    __ stop("bad Method*::intrinsic_id");
+    __ bind(L);
+    BLOCK_COMMENT("} verify_intrinsic_id");
+  }
+
+  // First task:  Find out how big the argument list is.
+  Address rdx_first_arg_addr;
+  int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid);
+  assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic");
+  if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) {
+    __ ldr(rdx_param_size, Address(rbx_method, Method::const_offset()));
+    __ load_sized_value(rdx_param_size,
+                        Address(rdx_param_size, ConstMethod::size_of_parameters_offset()),
+                        sizeof(u2), /*is_signed*/ false);
+    // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
+    rdx_first_arg_addr = __ receiver_argument_address(Rparams, rdx_param_size, rdi_temp);
+  } else {
+    DEBUG_ONLY(rdx_param_size = noreg);
+  }
+
+  if (!is_signature_polymorphic_static(iid)) {
+    __ ldr(rcx_mh, rdx_first_arg_addr);
+    DEBUG_ONLY(rdx_param_size = noreg);
+  }
+
+  // rdx_first_arg_addr is live!
+
+  trace_method_handle_interpreter_entry(_masm, iid);
+
+  if (iid == vmIntrinsics::_invokeBasic) {
+    generate_method_handle_dispatch(_masm, iid, rcx_mh, noreg, not_for_compiler_entry);
+
+  } else {
+    // Adjust argument list by popping the trailing MemberName argument.
+    Register rcx_recv = noreg;
+    if (MethodHandles::ref_kind_has_receiver(ref_kind)) {
+      // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack.
+      __ ldr(rcx_recv = rcx_mh, rdx_first_arg_addr);
+      DEBUG_ONLY(rdx_param_size = noreg);
+    }
+    Register rbx_member = rbx_method;  // MemberName ptr; incoming method ptr is dead now
+#ifdef AARCH64
+    __ ldr(rbx_member, Address(Rparams, Interpreter::stackElementSize, post_indexed));
+#else
+    __ pop(rbx_member);
+#endif
+    generate_method_handle_dispatch(_masm, iid, rcx_recv, rbx_member, not_for_compiler_entry);
+  }
+  return entry_point;
+}
+
+void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
+                                                    vmIntrinsics::ID iid,
+                                                    Register receiver_reg,
+                                                    Register member_reg,
+                                                    bool for_compiler_entry) {
+  assert(is_signature_polymorphic(iid), "expected invoke iid");
+  // Use same name as x86 to ease future merges
+  Register rbx_method = Rmethod;   // eventual target of this invocation
+  // temps used in this code are not used in *either* compiled or interpreted calling sequences
+  Register temp1 = (for_compiler_entry ? saved_last_sp_register() : R1_tmp);
+  Register temp2 = AARCH64_ONLY(R9) NOT_AARCH64(R8);
+  Register temp3 = Rtemp; // R12/R16
+  Register temp4 = AARCH64_ONLY(Rtemp2) NOT_AARCH64(R5);
+  if (for_compiler_entry) {
+    assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment");
+#ifdef AARCH64
+    assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
+    assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
+    assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
+    assert_different_registers(temp4, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
+#else
+    assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
+    assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
+    assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
+    assert_different_registers(temp4, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
+#endif // AARCH64
+  }
+  assert_different_registers(temp1, temp2, temp3, receiver_reg);
+  assert_different_registers(temp1, temp2, temp3, temp4, member_reg);
+  if (!for_compiler_entry)
+    assert_different_registers(temp1, temp2, temp3, temp4, saved_last_sp_register());  // don't trash lastSP
+
+  if (iid == vmIntrinsics::_invokeBasic) {
+    // indirect through MH.form.exactInvoker.vmtarget
+    jump_to_lambda_form(_masm, receiver_reg, temp3, for_compiler_entry);
+
+  } else {
+    // The method is a member invoker used by direct method handles.
+    if (VerifyMethodHandles) {
+      // make sure the trailing argument really is a MemberName (caller responsibility)
+      verify_klass(_masm, member_reg, temp2, temp3, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MemberName),
+                   "MemberName required for invokeVirtual etc.");
+    }
+
+    Address member_clazz(   member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()));
+    Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes()));
+    Address member_vmtarget(member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()));
+
+    Register temp1_recv_klass = temp1;
+    if (iid != vmIntrinsics::_linkToStatic) {
+      if (iid == vmIntrinsics::_linkToSpecial) {
+        // Don't actually load the klass; just null-check the receiver.
+        __ null_check(receiver_reg, temp3);
+      } else {
+        // load receiver klass itself
+        __ null_check(receiver_reg, temp3, oopDesc::klass_offset_in_bytes());
+        __ load_klass(temp1_recv_klass, receiver_reg);
+        __ verify_klass_ptr(temp1_recv_klass);
+      }
+      BLOCK_COMMENT("check_receiver {");
+      // The receiver for the MemberName must be in receiver_reg.
+      // Check the receiver against the MemberName.clazz
+      if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) {
+        // Did not load it above...
+        __ load_klass(temp1_recv_klass, receiver_reg);
+        __ verify_klass_ptr(temp1_recv_klass);
+      }
+      // Check the receiver against the MemberName.clazz
+      if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) {
+        Label L_ok;
+        Register temp2_defc = temp2;
+        __ load_heap_oop(temp2_defc, member_clazz);
+        load_klass_from_Class(_masm, temp2_defc, temp3, temp4);
+        __ verify_klass_ptr(temp2_defc);
+#ifdef AARCH64
+        // TODO-AARCH64
+        __ b(L_ok);
+#else
+        __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, noreg, L_ok);
+#endif
+        // If we get here, the type check failed!
+        __ stop("receiver class disagrees with MemberName.clazz");
+        __ bind(L_ok);
+      }
+      BLOCK_COMMENT("} check_receiver");
+    }
+    if (iid == vmIntrinsics::_linkToSpecial ||
+        iid == vmIntrinsics::_linkToStatic) {
+      DEBUG_ONLY(temp1_recv_klass = noreg);  // these guys didn't load the recv_klass
+    }
+
+    // Live registers at this point:
+    //  member_reg - MemberName that was the extra argument
+    //  temp1_recv_klass - klass of stacked receiver, if needed
+
+    Label L_incompatible_class_change_error;
+    switch (iid) {
+    case vmIntrinsics::_linkToSpecial:
+      if (VerifyMethodHandles) {
+        verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3);
+      }
+      __ ldr(Rmethod, member_vmtarget);
+      break;
+
+    case vmIntrinsics::_linkToStatic:
+      if (VerifyMethodHandles) {
+        verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3);
+      }
+      __ ldr(Rmethod, member_vmtarget);
+      break;
+
+    case vmIntrinsics::_linkToVirtual:
+    {
+      // same as TemplateTable::invokevirtual,
+      // minus the CP setup and profiling:
+
+      if (VerifyMethodHandles) {
+        verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3);
+      }
+
+      // pick out the vtable index from the MemberName, and then we can discard it:
+      Register temp2_index = temp2;
+      __ ldr(temp2_index, member_vmindex);
+
+      if (VerifyMethodHandles) {
+        Label L_index_ok;
+        __ cmp(temp2_index, 0);
+        __ b(L_index_ok, ge);
+        __ stop("no virtual index");
+        __ bind(L_index_ok);
+      }
+
+      // Note:  The verifier invariants allow us to ignore MemberName.clazz and vmtarget
+      // at this point.  And VerifyMethodHandles has already checked clazz, if needed.
+
+      // get target Method* & entry point
+      __ lookup_virtual_method(temp1_recv_klass, temp2_index, Rmethod);
+      break;
+    }
+
+    case vmIntrinsics::_linkToInterface:
+    {
+      // same as TemplateTable::invokeinterface
+      // (minus the CP setup and profiling, with different argument motion)
+      if (VerifyMethodHandles) {
+        verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3);
+      }
+
+      Register temp3_intf = temp3;
+      __ load_heap_oop(temp3_intf, member_clazz);
+      load_klass_from_Class(_masm, temp3_intf, temp2, temp4);
+      __ verify_klass_ptr(temp3_intf);
+
+      Register rbx_index = rbx_method;
+      __ ldr(rbx_index, member_vmindex);
+      if (VerifyMethodHandles) {
+        Label L;
+        __ cmp(rbx_index, 0);
+        __ b(L, ge);
+        __ stop("invalid vtable index for MH.invokeInterface");
+        __ bind(L);
+      }
+
+      // given intf, index, and recv klass, dispatch to the implementation method
+      Label L_no_such_interface;
+      __ lookup_interface_method(temp1_recv_klass, temp3_intf,
+                                 // note: next two args must be the same:
+                                 rbx_index, rbx_method,
+                                 temp2, temp4,
+                                 L_incompatible_class_change_error);
+      break;
+    }
+
+    default:
+      fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid));
+      break;
+    }
+
+    // Live at this point:
+    //   Rmethod (target method)
+    //   Rsender_sp, Rparams (if interpreted)
+    //   register arguments (if compiled)
+
+    // After figuring out which concrete method to call, jump into it.
+    __ verify_method_ptr(Rmethod);
+    jump_from_method_handle(_masm, for_compiler_entry);
+
+    if (iid == vmIntrinsics::_linkToInterface) {
+      __ bind(L_incompatible_class_change_error);
+      __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp);
+    }
+  }
+}
+
+
+#ifndef PRODUCT
+enum {
+  ARG_LIMIT = 255, SLOP = 4,
+  // use this parameter for checking for garbage stack movements:
+  UNREASONABLE_STACK_MOVE = (ARG_LIMIT + SLOP)
+  // the slop defends against false alarms due to fencepost errors
+};
+
+#ifdef AARCH64
+const int trace_mh_nregs = 32; // R0-R30, PC
+#else
+const int trace_mh_nregs = 15;
+const Register trace_mh_regs[trace_mh_nregs] =
+  {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, PC};
+#endif // AARCH64
+
+void trace_method_handle_stub(const char* adaptername,
+                              intptr_t* saved_regs,
+                              intptr_t* saved_bp,
+                              oop mh) {
+  // called as a leaf from native code: do not block the JVM!
+  bool has_mh = (strstr(adaptername, "/static") == NULL &&
+                 strstr(adaptername, "linkTo") == NULL);    // static linkers don't have MH
+  intptr_t* entry_sp = (intptr_t*) &saved_regs[trace_mh_nregs]; // just after the saved regs
+  intptr_t* saved_sp = (intptr_t*)  saved_regs[Rsender_sp->encoding()]; // save of Rsender_sp
+  intptr_t* last_sp  = (intptr_t*)  saved_bp[AARCH64_ONLY(frame::interpreter_frame_stack_top_offset) NOT_AARCH64(frame::interpreter_frame_last_sp_offset)];
+  intptr_t* base_sp  = last_sp;
+
+  intptr_t    mh_reg = (intptr_t)saved_regs[R5_mh->encoding()];
+  const char* mh_reg_name = "R5_mh";
+  if (!has_mh)  mh_reg_name = "R5";
+  tty->print_cr("MH %s %s=" PTR_FORMAT " sp=(" PTR_FORMAT "+" INTX_FORMAT ") stack_size=" INTX_FORMAT " bp=" PTR_FORMAT,
+                adaptername, mh_reg_name, mh_reg,
+                (intptr_t)entry_sp, (intptr_t)saved_sp - (intptr_t)entry_sp, (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
+
+  if (last_sp != saved_sp && last_sp != NULL)
+    tty->print_cr("*** last_sp=" INTPTR_FORMAT, p2i(last_sp));
+  if (Verbose) {
+    tty->print(" reg dump: ");
+    int i;
+    for (i = 0; i < trace_mh_nregs; i++) {
+      if (i > 0 && i % AARCH64_ONLY(2) NOT_AARCH64(4) == 0)
+        tty->print("\n   + dump: ");
+#ifdef AARCH64
+      const char* reg_name = (i == trace_mh_nregs-1) ? "pc" : as_Register(i)->name();
+#else
+      const char* reg_name = trace_mh_regs[i]->name();
+#endif
+      tty->print(" %s: " INTPTR_FORMAT, reg_name, p2i((void *)saved_regs[i]));
+    }
+    tty->cr();
+  }
+
+  if (Verbose) {
+    // dump last frame (from JavaThread::print_frame_layout)
+
+    // Note: code is robust but the dumped informationm may not be
+    // 100% correct, particularly with respect to the dumped
+    // "unextended_sp". Getting it right for all trace_method_handle
+    // call paths is not worth the complexity/risk. The correct slot
+    // will be identified by *Rsender_sp anyway in the dump.
+    JavaThread* p = JavaThread::active();
+
+    ResourceMark rm;
+    PRESERVE_EXCEPTION_MARK;
+    FrameValues values;
+
+    intptr_t* dump_fp = (intptr_t *) saved_bp;
+    address dump_pc = (address) saved_regs[trace_mh_nregs-2]; // LR (with LR,PC last in saved_regs)
+    frame dump_frame((intptr_t *)entry_sp, dump_fp, dump_pc);
+
+    dump_frame.describe(values, 1);
+    // mark Rsender_sp if seems valid
+    if (has_mh) {
+      if ((saved_sp >= entry_sp - UNREASONABLE_STACK_MOVE) && (saved_sp < dump_fp)) {
+        values.describe(-1, saved_sp, "*Rsender_sp");
+      }
+    }
+
+    // Note: the unextended_sp may not be correct
+    tty->print_cr("  stack layout:");
+    values.print(p);
+  }
+  if (Verbose) {
+    if (has_mh && mh->is_oop()) {
+      mh->print();
+      if (java_lang_invoke_MethodHandle::is_instance(mh)) {
+        if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
+          java_lang_invoke_MethodHandle::form(mh)->print();
+      }
+    }
+  }
+}
+
+void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
+  if (!TraceMethodHandles)  return;
+  BLOCK_COMMENT("trace_method_handle {");
+  // register saving
+  //  must correspond to trace_mh_nregs and trace_mh_regs defined above
+  int push_size = __ save_all_registers();
+  assert(trace_mh_nregs*wordSize == push_size,"saved register count mismatch");
+
+  __ mov_slow(R0, adaptername);
+  __ mov(R1, SP); // entry_sp (after pushes)
+  __ mov(R2, FP);
+  if (R5_mh != R3) {
+    assert_different_registers(R0, R1, R2, R5_mh);
+    __ mov(R3, R5_mh);
+  }
+
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), R0, R1, R2, R3);
+
+  __ restore_all_registers();
+  BLOCK_COMMENT("} trace_method_handle");
+}
+#endif //PRODUCT
diff --git a/hotspot/src/cpu/arm/vm/methodHandles_arm.hpp b/hotspot/src/cpu/arm/vm/methodHandles_arm.hpp
new file mode 100644
index 0000000..c03ac03
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/methodHandles_arm.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// Platform-specific definitions for method handles.
+// These definitions are inlined into class MethodHandles.
+
+// Adapters
+enum /* platform_dependent_constants */ {
+  adapter_code_size = 18000 NOT_PRODUCT(+ 30000)
+};
+
+// Additional helper methods for MethodHandles code generation:
+public:
+  static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp1, Register temp2);
+
+  static void verify_klass(MacroAssembler* _masm,
+                           Register obj, Register temp1, Register temp2, SystemDictionary::WKID klass_id,
+                           const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
+
+  static void verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) NOT_DEBUG_RETURN;
+
+  // Similar to InterpreterMacroAssembler::jump_from_interpreted.
+  // Takes care of special dispatch from single stepping too.
+  // Rmethod should contain target methodOop.
+  static void jump_from_method_handle(MacroAssembler* _masm, bool for_compiler_entry);
+
+  static void jump_to_lambda_form(MacroAssembler* _masm,
+                                  Register recv, Register tmp,
+                                  bool for_compiler_entry);
+
+  static Register saved_last_sp_register() {
+    // Should be in sharedRuntime, not here.
+    return Rsender_sp;
+  }
diff --git a/hotspot/src/cpu/arm/vm/nativeInst_arm.hpp b/hotspot/src/cpu/arm/vm/nativeInst_arm.hpp
new file mode 100644
index 0000000..88bcee9
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/nativeInst_arm.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_NATIVEINST_ARM_HPP
+#define CPU_ARM_VM_NATIVEINST_ARM_HPP
+
+#include "asm/macroAssembler.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/os.hpp"
+
+
+#ifdef AARCH64
+#include "nativeInst_arm_64.hpp"
+#else
+#include "nativeInst_arm_32.hpp"
+#endif
+
+
+#endif // CPU_ARM_VM_NATIVEINST_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/nativeInst_arm_32.cpp b/hotspot/src/cpu/arm/vm/nativeInst_arm_32.cpp
new file mode 100644
index 0000000..77694f6
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/nativeInst_arm_32.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/ostream.hpp"
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#endif
+#include "code/icBuffer.hpp"
+
+int NativeMovRegMem::offset() const {
+  switch (kind()) {
+    case instr_ldr_str:
+      return encoding() & 0xfff;
+    case instr_ldrh_strh:
+      return (encoding() & 0x0f) | ((encoding() >> 4) & 0xf0);
+    case instr_fld_fst:
+      return (encoding() & 0xff) << 2;
+    default:
+      ShouldNotReachHere();
+      return 0;
+  }
+}
+
+void NativeMovRegMem::set_offset(int x) {
+  assert(x >= 0 && x < 65536, "encoding constraint");
+  const int Rt = Rtemp->encoding();
+
+  // If offset is too large to be placed into single ldr/str instruction, we replace
+  //   ldr  Rd, [Rn, #offset]
+  //   nop
+  // with
+  //   add  Rtemp, Rn, #offset_hi
+  //   ldr  Rd, [Rtemp, #offset_lo]
+  switch (kind()) {
+    case instr_ldr_str:
+      if (x < 4096) {
+        set_encoding((encoding() & 0xfffff000) | x);
+      } else {
+        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
+        assert(next->is_nop(), "must be");
+        next->set_encoding((encoding() & 0xfff0f000) | Rt << 16 | (x & 0xfff));
+        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 12 | 0xe2800a00);
+      }
+      break;
+    case instr_ldrh_strh:
+      if (x < 256) {
+        set_encoding((encoding() & 0xfffff0f0) | (x & 0x0f) | (x & 0xf0) << 4);
+      } else {
+        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
+        assert(next->is_nop(), "must be");
+        next->set_encoding((encoding() & 0xfff0f0f0) | Rt << 16 | (x & 0x0f) | (x & 0xf0) << 4);
+        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 8 | 0xe2800c00);
+      }
+      break;
+    case instr_fld_fst:
+      if (x < 1024) {
+        set_encoding((encoding() & 0xffffff00) | (x >> 2));
+      } else {
+        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
+        assert(next->is_nop(), "must be");
+        next->set_encoding((encoding() & 0xfff0ff00) | Rt << 16 | ((x >> 2) & 0xff));
+        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 10 | 0xe2800b00);
+      }
+      break;
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+intptr_t NativeMovConstReg::data() const {
+  RawNativeInstruction* next = next_raw();
+  if (is_movw()) {
+    // Oop embedded in movw/movt instructions
+    assert(VM_Version::supports_movw(), "must be");
+    return (this->encoding() & 0x00000fff)       | (this->encoding() & 0x000f0000) >> 4 |
+           (next->encoding() & 0x00000fff) << 16 | (next->encoding() & 0x000f0000) << 12;
+  } else {
+    // Oop is loaded from oops section or inlined in the code
+    int oop_offset;
+    if (is_ldr_literal()) {
+      //   ldr  Rd, [PC, #offset]
+      oop_offset = ldr_offset();
+    } else {
+      assert(next->is_ldr(), "must be");
+      oop_offset = (this->encoding() & 0xff) << 12 | (next->encoding() & 0xfff);
+      if (is_add_pc()) {
+        //   add  Rd, PC, #offset_hi
+        //   ldr  Rd, [Rd, #offset_lo]
+        assert(next->encoding() & (1 << 23), "sign mismatch");
+        // offset OK (both positive)
+      } else {
+        assert(is_sub_pc(), "must be");
+        //   sub  Rd, PC, #offset_hi
+        //   ldr  Rd, [Rd, -#offset_lo]
+        assert(!(next->encoding() & (1 << 23)), "sign mismatch");
+        // negative offsets
+        oop_offset = -oop_offset;
+      }
+    }
+    return *(int*)(instruction_address() + 8 + oop_offset);
+  }
+}
+
+void NativeMovConstReg::set_data(intptr_t x, address pc) {
+  // Find and replace the oop corresponding to this instruction in oops section
+  RawNativeInstruction* next = next_raw();
+  oop* oop_addr = NULL;
+  Metadata** metadata_addr = NULL;
+  CodeBlob* cb = CodeCache::find_blob(instruction_address());
+  if (cb != NULL) {
+    nmethod* nm = cb->as_nmethod_or_null();
+    if (nm != NULL) {
+      RelocIterator iter(nm, instruction_address(), next->instruction_address());
+      while (iter.next()) {
+        if (iter.type() == relocInfo::oop_type) {
+          oop_addr = iter.oop_reloc()->oop_addr();
+          *oop_addr = cast_to_oop(x);
+          break;
+        } else if (iter.type() == relocInfo::metadata_type) {
+          metadata_addr = iter.metadata_reloc()->metadata_addr();
+          *metadata_addr = (Metadata*)x;
+          break;
+        }
+      }
+    }
+  }
+
+  if (is_movw()) {
+    // data embedded in movw/movt instructions
+    assert(VM_Version::supports_movw(), "must be");
+    unsigned int lo = (unsigned int)x;
+    unsigned int hi = (unsigned int)(x >> 16);
+    this->set_encoding((this->encoding() & 0xfff0f000) | (lo & 0xf000) << 4 | (lo & 0xfff));
+    next->set_encoding((next->encoding() & 0xfff0f000) | (hi & 0xf000) << 4 | (hi & 0xfff));
+  } else if (oop_addr == NULL & metadata_addr == NULL) {
+    // A static ldr_literal (without oop or metadata relocation)
+    assert(is_ldr_literal(), "must be");
+    int offset = ldr_offset();
+    oop_addr = (oop*)(instruction_address() + 8 + offset);
+    *oop_addr = cast_to_oop(x);
+  } else {
+    // data is loaded from oop or metadata section
+    int offset;
+
+    address addr = oop_addr != NULL ? (address)oop_addr : (address)metadata_addr;
+
+    if(pc == 0) {
+      offset = addr - instruction_address() - 8;
+    } else {
+      offset = addr - pc - 8;
+    }
+
+    int sign = (offset >= 0) ? (1 << 23) : 0;
+    int delta = (offset >= 0) ? offset : (-offset);
+    assert(delta < 0x100000, "within accessible range");
+    if (is_ldr_literal()) {
+      // fix the ldr with the real offset to the oop/metadata table
+      assert(next->is_nop(), "must be");
+      if (delta < 4096) {
+        //   ldr  Rd, [PC, #offset]
+        set_encoding((encoding() & 0xff7ff000) | delta | sign);
+        assert(ldr_offset() == offset, "check encoding");
+      } else {
+        int cc = encoding() & 0xf0000000;
+        int Rd = (encoding() >> 12) & 0xf;
+        int Rt = Rd;
+        assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp
+        // move the ldr, fixing delta_lo and the source register
+        next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign);
+        assert(next->is_ldr(), "must be");
+        if (offset > 0) {
+          //   add  Rt, PC, #delta_hi
+          //   ldr  Rd, [Rt, #delta_lo]
+          this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc);
+          assert(is_add_pc(), "must be");
+        } else {
+          //   sub Rt, PC, #delta_hi
+          //   ldr  Rd, [Rt, -#delta_lo]
+          this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc);
+          assert(is_sub_pc(), "must be");
+        }
+      }
+    } else {
+      assert(is_pc_rel(), "must be");
+      assert(next->is_ldr(), "must be");
+      if (offset > 0) {
+        //   add Rt, PC, #delta_hi
+        this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
+        assert(is_add_pc(), "must be");
+      } else {
+        //   sub Rt, PC, #delta_hi
+        this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
+        assert(is_sub_pc(), "must be");
+      }
+      //    ldr Rd, Rt, #delta_lo (or -#delta_lo)
+      next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
+    }
+  }
+}
+
+void NativeMovConstReg::set_pc_relative_offset(address addr, address pc) {
+  int offset;
+  if (pc == 0) {
+    offset = addr - instruction_address() - 8;
+  } else {
+    offset = addr - pc - 8;
+  }
+
+  RawNativeInstruction* next = next_raw();
+
+  int sign = (offset >= 0) ? (1 << 23) : 0;
+  int delta = (offset >= 0) ? offset : (-offset);
+  assert(delta < 0x100000, "within accessible range");
+  if (is_ldr_literal()) {
+    if (delta < 4096) {
+      //   ldr  Rd, [PC, #offset]
+      set_encoding((encoding() & 0xff7ff000) | delta | sign);
+      assert(ldr_offset() == offset, "check encoding");
+    } else {
+      assert(next->is_nop(), "must be");
+      int cc = encoding() & 0xf0000000;
+      int Rd = (encoding() >> 12) & 0xf;
+      int Rt = Rd;
+      assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp
+      // move the ldr, fixing delta_lo and the source register
+      next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign);
+      assert(next->is_ldr(), "must be");
+      if (offset > 0) {
+        //   add  Rt, PC, #delta_hi
+        //   ldr  Rd, [Rt, #delta_lo]
+        this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc);
+        assert(is_add_pc(), "must be");
+      } else {
+        //   sub Rt, PC, #delta_hi
+        //   ldr Rd, [Rt, -#delta_lo]
+        this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc);
+        assert(is_sub_pc(), "must be");
+      }
+    }
+  } else {
+    assert(is_pc_rel(), "must be");
+    assert(next->is_ldr(), "must be");
+    if (offset > 0) {
+      //   add Rt, PC, #delta_hi
+      this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
+      assert(is_add_pc(), "must be");
+    } else {
+      //   sub Rt, PC, #delta_hi
+      this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
+      assert(is_sub_pc(), "must be");
+    }
+    //    ldr Rd, Rt, #delta_lo (or -#delta_lo)
+    next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
+  }
+}
+
+void RawNativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
+}
+
+void RawNativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
+  assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be");
+  int *a = (int *)verified_entry;
+  a[0] = zombie_illegal_instruction; // always illegal
+  ICache::invalidate_range((address)&a[0], sizeof a[0]);
+}
+
+void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
+  int offset = (int)(entry - code_pos - 8);
+  assert(offset < 0x2000000 && offset > -0x2000000, "encoding constraint");
+  nativeInstruction_at(code_pos)->set_encoding(0xea000000 | ((unsigned int)offset << 6 >> 8));
+}
+
+static address raw_call_for(address return_address) {
+  CodeBlob* cb = CodeCache::find_blob(return_address);
+  nmethod* nm = cb->as_nmethod_or_null();
+  if (nm == NULL) {
+    ShouldNotReachHere();
+    return NULL;
+  }
+  // Look back 4 instructions, to allow for ic_call
+  address begin = MAX2(return_address - 4*NativeInstruction::instruction_size, nm->code_begin());
+  RelocIterator iter(nm, begin, return_address);
+  while (iter.next()) {
+    Relocation* reloc = iter.reloc();
+    if (reloc->is_call()) {
+      address call = reloc->addr();
+      if (nativeInstruction_at(call)->is_call()) {
+        if (nativeCall_at(call)->return_address() == return_address) {
+          return call;
+        }
+      } else {
+        // Some "calls" are really jumps
+        assert(nativeInstruction_at(call)->is_jump(), "must be call or jump");
+      }
+    }
+  }
+  return NULL;
+}
+
+bool RawNativeCall::is_call_before(address return_address) {
+  return (raw_call_for(return_address) != NULL);
+}
+
+NativeCall* rawNativeCall_before(address return_address) {
+  address call = raw_call_for(return_address);
+  assert(call != NULL, "must be");
+  return nativeCall_at(call);
+}
+
diff --git a/hotspot/src/cpu/arm/vm/nativeInst_arm_32.hpp b/hotspot/src/cpu/arm/vm/nativeInst_arm_32.hpp
new file mode 100644
index 0000000..45a32c9
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/nativeInst_arm_32.hpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_NATIVEINST_ARM_32_HPP
+#define CPU_ARM_VM_NATIVEINST_ARM_32_HPP
+
+#include "asm/macroAssembler.hpp"
+#include "code/codeCache.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.hpp"
+#include "register_arm.hpp"
+
+// -------------------------------------------------------------------
+
+// Some experimental projects extend the ARM back-end by implementing
+// what the front-end usually assumes is a single native instruction
+// with a sequence of instructions.
+//
+// The 'Raw' variants are the low level initial code (usually one
+// instruction wide but some of them were already composed
+// instructions). They should be used only by the back-end.
+//
+// The non-raw classes are the front-end entry point, hiding potential
+// back-end extensions or the actual instructions size.
+class NativeInstruction;
+
+class RawNativeInstruction VALUE_OBJ_CLASS_SPEC {
+ public:
+
+  enum ARM_specific {
+    instruction_size = Assembler::InstructionSize
+  };
+
+  enum InstructionKind {
+    instr_ldr_str    = 0x50,
+    instr_ldrh_strh  = 0x10,
+    instr_fld_fst    = 0xd0
+  };
+
+  // illegal instruction used by NativeJump::patch_verified_entry
+  // permanently undefined (UDF): 0xe << 28 | 0b1111111 << 20 | 0b1111 << 4
+  static const int zombie_illegal_instruction = 0xe7f000f0;
+
+  static int decode_rotated_imm12(int encoding) {
+    int base = encoding & 0xff;
+    int right_rotation = (encoding & 0xf00) >> 7;
+    int left_rotation = 32 - right_rotation;
+    int val = (base >> right_rotation) | (base << left_rotation);
+    return val;
+  }
+
+  address addr_at(int offset)        const { return (address)this + offset; }
+  address instruction_address()      const { return addr_at(0); }
+  address next_raw_instruction_address() const { return addr_at(instruction_size); }
+
+  static RawNativeInstruction* at(address address) {
+    return (RawNativeInstruction*)address;
+  }
+  RawNativeInstruction* next_raw() const {
+    return at(next_raw_instruction_address());
+  }
+
+ public:
+  int encoding()                     const { return *(int*)this; }
+
+  void set_encoding(int value) {
+    int old = *(int*)this;
+    if (old != value) {
+      *(int*)this = value;
+      ICache::invalidate_word((address)this);
+    }
+  }
+
+  InstructionKind kind() const {
+    return (InstructionKind) ((encoding() >> 20) & 0xf2);
+  }
+
+  bool is_nop()            const { return encoding() == (int)0xe1a00000; }
+  bool is_b()              const { return (encoding() & 0x0f000000) == 0x0a000000; }
+  bool is_bx()             const { return (encoding() & 0x0ffffff0) == 0x012fff10; }
+  bool is_bl()             const { return (encoding() & 0x0f000000) == 0x0b000000; }
+  bool is_blx()            const { return (encoding() & 0x0ffffff0) == 0x012fff30; }
+  bool is_fat_call()       const {
+    return (is_add_lr() && next_raw()->is_jump());
+  }
+  bool is_ldr_call()       const {
+    return (is_add_lr() && next_raw()->is_ldr_pc());
+  }
+  bool is_jump()           const { return is_b() || is_ldr_pc(); }
+  bool is_call()           const { return is_bl() || is_fat_call(); }
+  bool is_branch()         const { return is_b() || is_bl(); }
+  bool is_far_branch()     const { return is_movw() || is_ldr_literal(); }
+  bool is_ldr_literal()    const {
+    // ldr Rx, [PC, #offset] for positive or negative offsets
+    return (encoding() & 0x0f7f0000) == 0x051f0000;
+  }
+  bool is_ldr()    const {
+    // ldr Rd, [Rn, #offset] for positive or negative offsets
+    return (encoding() & 0x0f700000) == 0x05100000;
+  }
+  int ldr_offset() const {
+    assert(is_ldr(), "must be");
+    int offset = encoding() & 0xfff;
+    if (encoding() & (1 << 23)) {
+      // positive offset
+    } else {
+      // negative offset
+      offset = -offset;
+    }
+    return offset;
+  }
+  // is_ldr_pc: ldr PC, PC, #offset
+  bool is_ldr_pc()         const { return (encoding() & 0x0f7ff000) == 0x051ff000; }
+  // is_setting_pc(): ldr PC, Rxx, #offset
+  bool is_setting_pc()         const { return (encoding() & 0x0f70f000) == 0x0510f000; }
+  bool is_add_lr()         const { return (encoding() & 0x0ffff000) == 0x028fe000; }
+  bool is_add_pc()         const { return (encoding() & 0x0fff0000) == 0x028f0000; }
+  bool is_sub_pc()         const { return (encoding() & 0x0fff0000) == 0x024f0000; }
+  bool is_pc_rel()         const { return is_add_pc() || is_sub_pc(); }
+  bool is_movw()           const { return (encoding() & 0x0ff00000) == 0x03000000; }
+  bool is_movt()           const { return (encoding() & 0x0ff00000) == 0x03400000; }
+  // c2 doesn't use fixed registers for safepoint poll address
+  bool is_safepoint_poll() const { return (encoding() & 0xfff0ffff) == 0xe590c000; }
+  // For unit tests
+  static void test() {}
+
+};
+
+inline RawNativeInstruction* rawNativeInstruction_at(address address) {
+  return (RawNativeInstruction*)address;
+}
+
+// Base class exported to the front-end
+class NativeInstruction: public RawNativeInstruction {
+public:
+  static NativeInstruction* at(address address) {
+    return (NativeInstruction*)address;
+  }
+
+public:
+  // No need to consider indirections while parsing NativeInstruction
+  address next_instruction_address() const {
+    return next_raw_instruction_address();
+  }
+
+  // next() is no longer defined to avoid confusion.
+  //
+  // The front end and most classes except for those defined in nativeInst_arm
+  // or relocInfo_arm should only use next_instruction_address(), skipping
+  // over composed instruction and ignoring back-end extensions.
+  //
+  // The back-end can use next_raw() when it knows the instruction sequence
+  // and only wants to skip a single native instruction.
+};
+
+inline NativeInstruction* nativeInstruction_at(address address) {
+  return (NativeInstruction*)address;
+}
+
+// -------------------------------------------------------------------
+// Raw b() or bl() instructions, not used by the front-end.
+class RawNativeBranch: public RawNativeInstruction {
+ public:
+
+  address destination(int adj = 0) const {
+    return instruction_address() + (encoding() << 8 >> 6) + 8 + adj;
+  }
+
+  void set_destination(address dest) {
+    int new_offset = (int)(dest - instruction_address() - 8);
+    assert(new_offset < 0x2000000 && new_offset > -0x2000000, "encoding constraint");
+    set_encoding((encoding() & 0xff000000) | ((unsigned int)new_offset << 6 >> 8));
+  }
+};
+
+inline RawNativeBranch* rawNativeBranch_at(address address) {
+  assert(rawNativeInstruction_at(address)->is_branch(), "must be");
+  return (RawNativeBranch*)address;
+}
+
+class NativeBranch: public RawNativeBranch {
+};
+
+inline NativeBranch* nativeBranch_at(address address) {
+  return (NativeBranch *) rawNativeBranch_at(address);
+}
+
+// -------------------------------------------------------------------
+// NativeGeneralJump is for patchable internal (near) jumps
+// It is used directly by the front-end and must be a single instruction wide
+// (to support patching to other kind of instructions).
+class NativeGeneralJump: public RawNativeInstruction {
+ public:
+
+  address jump_destination() const {
+    return rawNativeBranch_at(instruction_address())->destination();
+  }
+
+  void set_jump_destination(address dest) {
+    return rawNativeBranch_at(instruction_address())->set_destination(dest);
+  }
+
+  static void insert_unconditional(address code_pos, address entry);
+
+  static void replace_mt_safe(address instr_addr, address code_buffer) {
+    assert(((int)instr_addr & 3) == 0 && ((int)code_buffer & 3) == 0, "must be aligned");
+    // Writing a word is atomic on ARM, so no MT-safe tricks are needed
+    rawNativeInstruction_at(instr_addr)->set_encoding(*(int*)code_buffer);
+  }
+};
+
+inline NativeGeneralJump* nativeGeneralJump_at(address address) {
+  assert(rawNativeInstruction_at(address)->is_jump(), "must be");
+  return (NativeGeneralJump*)address;
+}
+
+// -------------------------------------------------------------------
+class RawNativeJump: public NativeInstruction {
+ public:
+
+  address jump_destination(int adj = 0) const {
+    address a;
+    if (is_b()) {
+      a = rawNativeBranch_at(instruction_address())->destination(adj);
+      // Jump destination -1 is encoded as a jump to self
+      if (a == instruction_address()) {
+        return (address)-1;
+      }
+    } else {
+      assert(is_ldr_pc(), "must be");
+      int offset = this->ldr_offset();
+      a = *(address*)(instruction_address() + 8 + offset);
+    }
+    return a;
+  }
+
+  void set_jump_destination(address dest) {
+    address a;
+    if (is_b()) {
+      // Jump destination -1 is encoded as a jump to self
+      if (dest == (address)-1) {
+        dest = instruction_address();
+      }
+      rawNativeBranch_at(instruction_address())->set_destination(dest);
+    } else {
+      assert(is_ldr_pc(), "must be");
+      int offset = this->ldr_offset();
+      *(address*)(instruction_address() + 8 + offset) = dest;
+      OrderAccess::storeload(); // overkill if caller holds lock?
+    }
+  }
+
+  static void check_verified_entry_alignment(address entry, address verified_entry);
+
+  static void patch_verified_entry(address entry, address verified_entry, address dest);
+
+};
+
+inline RawNativeJump* rawNativeJump_at(address address) {
+  assert(rawNativeInstruction_at(address)->is_jump(), "must be");
+  return (RawNativeJump*)address;
+}
+
+// -------------------------------------------------------------------
+class RawNativeCall: public NativeInstruction {
+  // See IC calls in LIR_Assembler::ic_call(): ARM v5/v6 doesn't use a
+  // single bl for IC calls.
+
+ public:
+
+  address return_address() const {
+    if (is_bl()) {
+      return addr_at(instruction_size);
+    } else {
+      assert(is_fat_call(), "must be");
+      int offset = encoding() & 0xff;
+      return addr_at(offset + 8);
+    }
+  }
+
+  address destination(int adj = 0) const {
+    if (is_bl()) {
+      return rawNativeBranch_at(instruction_address())->destination(adj);
+    } else {
+      assert(is_add_lr(), "must be"); // fat_call
+      RawNativeJump *next = rawNativeJump_at(next_raw_instruction_address());
+      return next->jump_destination(adj);
+    }
+  }
+
+  void set_destination(address dest) {
+    if (is_bl()) {
+      return rawNativeBranch_at(instruction_address())->set_destination(dest);
+    } else {
+      assert(is_add_lr(), "must be"); // fat_call
+      RawNativeJump *next = rawNativeJump_at(next_raw_instruction_address());
+      return next->set_jump_destination(dest);
+    }
+  }
+
+  void set_destination_mt_safe(address dest) {
+    assert(CodeCache::contains(dest), "external destination might be too far");
+    set_destination(dest);
+  }
+
+  void verify() {
+    assert(RawNativeInstruction::is_call() || (!VM_Version::supports_movw() && RawNativeInstruction::is_jump()), "must be");
+  }
+
+  void verify_alignment() {
+    // Nothing to do on ARM
+  }
+
+  static bool is_call_before(address return_address);
+};
+
+inline RawNativeCall* rawNativeCall_at(address address) {
+  assert(rawNativeInstruction_at(address)->is_call(), "must be");
+  return (RawNativeCall*)address;
+}
+
+NativeCall* rawNativeCall_before(address return_address);
+
+// -------------------------------------------------------------------
+// NativeMovRegMem need not be extended with indirection support.
+// (field access patching is handled differently in that case)
+class NativeMovRegMem: public NativeInstruction {
+ public:
+
+  int offset() const;
+  void set_offset(int x);
+
+  void add_offset_in_bytes(int add_offset) {
+    set_offset(offset() + add_offset);
+  }
+
+};
+
+inline NativeMovRegMem* nativeMovRegMem_at(address address) {
+  NativeMovRegMem* instr = (NativeMovRegMem*)address;
+  assert(instr->kind() == NativeInstruction::instr_ldr_str   ||
+         instr->kind() == NativeInstruction::instr_ldrh_strh ||
+         instr->kind() == NativeInstruction::instr_fld_fst, "must be");
+  return instr;
+}
+
+// -------------------------------------------------------------------
+// NativeMovConstReg is primarily for loading oops and metadata
+class NativeMovConstReg: public NativeInstruction {
+ public:
+
+  intptr_t data() const;
+  void set_data(intptr_t x, address pc = 0);
+  bool is_pc_relative() {
+    return !is_movw();
+  }
+  void set_pc_relative_offset(address addr, address pc);
+  address next_instruction_address() const {
+    // NOTE: CompiledStaticCall::set_to_interpreted() calls this but
+    // are restricted to single-instruction ldr. No need to jump over
+    // several instructions.
+    assert(is_ldr_literal(), "Should only use single-instructions load");
+    return next_raw_instruction_address();
+  }
+};
+
+inline NativeMovConstReg* nativeMovConstReg_at(address address) {
+  NativeInstruction* ni = nativeInstruction_at(address);
+  assert(ni->is_ldr_literal() || ni->is_pc_rel() ||
+         ni->is_movw() && VM_Version::supports_movw(), "must be");
+  return (NativeMovConstReg*)address;
+}
+
+// -------------------------------------------------------------------
+// Front end classes, hiding experimental back-end extensions.
+
+// Extension to support indirections
+class NativeJump: public RawNativeJump {
+ public:
+};
+
+inline NativeJump* nativeJump_at(address address) {
+  assert(nativeInstruction_at(address)->is_jump(), "must be");
+  return (NativeJump*)address;
+}
+
+class NativeCall: public RawNativeCall {
+public:
+  // NativeCall::next_instruction_address() is used only to define the
+  // range where to look for the relocation information. We need not
+  // walk over composed instructions (as long as the relocation information
+  // is associated to the first instruction).
+  address next_instruction_address() const {
+    return next_raw_instruction_address();
+  }
+
+};
+
+inline NativeCall* nativeCall_at(address address) {
+  assert(nativeInstruction_at(address)->is_call() ||
+         (!VM_Version::supports_movw() && nativeInstruction_at(address)->is_jump()), "must be");
+  return (NativeCall*)address;
+}
+
+inline NativeCall* nativeCall_before(address return_address) {
+  return (NativeCall *) rawNativeCall_before(return_address);
+}
+
+#endif // CPU_ARM_VM_NATIVEINST_ARM_32_HPP
diff --git a/hotspot/src/cpu/arm/vm/nativeInst_arm_64.cpp b/hotspot/src/cpu/arm/vm/nativeInst_arm_64.cpp
new file mode 100644
index 0000000..fe1b8be
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/nativeInst_arm_64.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/ostream.hpp"
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#endif
+
+void RawNativeInstruction::verify() {
+  // make sure code pattern is actually an instruction address
+  address addr = instruction_address();
+  if (addr == NULL || ((intptr_t)addr & (instruction_size - 1)) != 0) {
+    fatal("not an instruction address");
+  }
+}
+
+void NativeMovRegMem::set_offset(int x) {
+  int scale = get_offset_scale();
+  assert((x & right_n_bits(scale)) == 0, "offset should be aligned");
+  guarantee((x >> 24) == 0, "encoding constraint");
+
+  if (Assembler::is_unsigned_imm_in_range(x, 12, scale)) {
+    set_unsigned_imm(x, 12, get_offset_scale(), 10);
+    return;
+  }
+
+  // If offset is too large to be placed into single ldr/str instruction, we replace
+  //   ldr/str  Rt, [Rn, #offset]
+  //   nop
+  // with
+  //   add  LR, Rn, #offset_hi
+  //   ldr/str  Rt, [LR, #offset_lo]
+
+  // Note: Rtemp cannot be used as a temporary register as it could be used
+  // for value being stored (see LIR_Assembler::reg2mem).
+  // Patchable NativeMovRegMem instructions are generated in LIR_Assembler::mem2reg and LIR_Assembler::reg2mem
+  // which do not use LR, so it is free. Also, it does not conflict with LR usages in c1_LIRGenerator_arm.cpp.
+  const int tmp = LR->encoding();
+  const int rn = (encoding() >> 5) & 0x1f;
+
+  NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
+  assert(next->is_nop(), "must be");
+
+  next->set_encoding((encoding() & 0xffc0001f) | Assembler::encode_unsigned_imm((x & 0xfff), 12, scale, 10) | tmp << 5);
+  this->set_encoding(0x91400000 | Assembler::encode_unsigned_imm((x >> 12), 12, 0, 10) | rn << 5 | tmp);
+}
+
+intptr_t NativeMovConstReg::_data() const {
+#ifdef COMPILER2
+  if (is_movz()) {
+    // narrow constant or ic call cached value
+    RawNativeInstruction* ni = next_raw();
+    assert(ni->is_movk(), "movz;movk expected");
+    uint lo16 = (encoding() >> 5) & 0xffff;
+    intptr_t hi = 0;
+    int i = 0;
+    while (ni->is_movk() && i < 3) {
+      uint hi16 = (ni->encoding() >> 5) & 0xffff;
+      int shift = ((ni->encoding() >> 21) & 0x3) << 4;
+      hi |= (intptr_t)hi16 << shift;
+      ni = ni->next_raw();
+      ++i;
+    }
+    return lo16 | hi;
+  }
+#endif
+  return (intptr_t)(nativeLdrLiteral_at(instruction_address())->literal_value());
+}
+
+static void raw_set_data(RawNativeInstruction* si, intptr_t x, oop* oop_addr, Metadata** metadata_addr) {
+#ifdef COMPILER2
+  if (si->is_movz()) {
+    // narrow constant or ic call cached value
+    uintptr_t nx = 0;
+    int val_size = 32;
+    if (oop_addr != NULL) {
+      narrowOop encoded_oop = oopDesc::encode_heap_oop(*oop_addr);
+      nx = encoded_oop;
+    } else if (metadata_addr != NULL) {
+      assert((*metadata_addr)->is_klass(), "expected Klass");
+      narrowKlass encoded_k = Klass::encode_klass((Klass *)*metadata_addr);
+      nx = encoded_k;
+    } else {
+      nx = x;
+      val_size = 64;
+    }
+    RawNativeInstruction* ni = si->next_raw();
+    uint lo16 = nx & 0xffff;
+    int shift = 16;
+    int imm16 = 0xffff << 5;
+    si->set_encoding((si->encoding() & ~imm16) | (lo16 << 5));
+    while (shift < val_size) {
+      assert(ni->is_movk(), "movk expected");
+      assert((((ni->encoding() >> 21) & 0x3) << 4) == shift, "wrong shift");
+      uint hi16 = (nx >> shift) & 0xffff;
+      ni->set_encoding((ni->encoding() & ~imm16) | (hi16 << 5));
+      shift += 16;
+      ni = ni->next_raw();
+    }
+    return;
+  }
+#endif
+
+  assert(si->is_ldr_literal(), "should be");
+
+  if (oop_addr == NULL && metadata_addr == NULL) {
+    // A static ldr_literal without oop_relocation
+    nativeLdrLiteral_at(si->instruction_address())->set_literal_value((address)x);
+  } else {
+    // Oop is loaded from oops section
+    address addr = oop_addr != NULL ? (address)oop_addr : (address)metadata_addr;
+    int offset = addr - si->instruction_address();
+
+    assert((((intptr_t)addr) & 0x7) == 0, "target address should be aligned");
+    assert((offset & 0x3) == 0, "offset should be aligned");
+
+    guarantee(Assembler::is_offset_in_range(offset, 19), "offset is not in range");
+    nativeLdrLiteral_at(si->instruction_address())->set_literal_address(si->instruction_address() + offset);
+  }
+}
+
+void NativeMovConstReg::set_data(intptr_t x) {
+  // Find and replace the oop corresponding to this instruction in oops section
+  oop* oop_addr = NULL;
+  Metadata** metadata_addr = NULL;
+  CodeBlob* cb = CodeCache::find_blob(instruction_address());
+  {
+    nmethod* nm = cb->as_nmethod_or_null();
+    if (nm != NULL) {
+      RelocIterator iter(nm, instruction_address(), next_raw()->instruction_address());
+      while (iter.next()) {
+        if (iter.type() == relocInfo::oop_type) {
+          oop_addr = iter.oop_reloc()->oop_addr();
+          *oop_addr = cast_to_oop(x);
+          break;
+        } else if (iter.type() == relocInfo::metadata_type) {
+          metadata_addr = iter.metadata_reloc()->metadata_addr();
+          *metadata_addr = (Metadata*)x;
+          break;
+        }
+      }
+    }
+  }
+  raw_set_data(adjust(this), x, oop_addr,  metadata_addr);
+}
+
+void NativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
+}
+
+void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
+  assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be");
+
+  NativeInstruction* instr = nativeInstruction_at(verified_entry);
+  assert(instr->is_nop() || instr->encoding() == zombie_illegal_instruction, "required for MT-safe patching");
+  instr->set_encoding(zombie_illegal_instruction);
+}
+
+void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
+  assert (nativeInstruction_at(instr_addr)->is_b(), "MT-safe patching of arbitrary instructions is not allowed");
+  assert (nativeInstruction_at(code_buffer)->is_nop(), "MT-safe patching of arbitrary instructions is not allowed");
+  nativeInstruction_at(instr_addr)->set_encoding(*(int*)code_buffer);
+}
+
+void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
+  // Insert at code_pos unconditional B instruction jumping to entry
+  intx offset = entry - code_pos;
+  assert (Assembler::is_offset_in_range(offset, 26), "offset is out of range");
+
+  NativeInstruction* instr = nativeInstruction_at(code_pos);
+  assert (instr->is_b() || instr->is_nop(), "MT-safe patching of arbitrary instructions is not allowed");
+
+  instr->set_encoding(0x5 << 26 | Assembler::encode_offset(offset, 26, 0));
+}
+
+static address call_for(address return_address) {
+  CodeBlob* cb = CodeCache::find_blob(return_address);
+  nmethod* nm = cb->as_nmethod_or_null();
+  if (nm == NULL) {
+    ShouldNotReachHere();
+    return NULL;
+  }
+
+  // Look back 8 instructions (for LIR_Assembler::ic_call and MacroAssembler::patchable_call)
+  address begin = return_address - 8*NativeInstruction::instruction_size;
+  if (begin < nm->code_begin()) {
+    begin = nm->code_begin();
+  }
+  RelocIterator iter(nm, begin, return_address);
+  while (iter.next()) {
+    Relocation* reloc = iter.reloc();
+    if (reloc->is_call()) {
+      address call = reloc->addr();
+      if (nativeInstruction_at(call)->is_call()) {
+        if (nativeCall_at(call)->return_address() == return_address) {
+          return call;
+        }
+      }
+    }
+  }
+
+  return NULL;
+}
+
+bool NativeCall::is_call_before(address return_address) {
+  return (call_for(return_address) != NULL);
+}
+
+NativeCall* nativeCall_before(address return_address) {
+  assert(NativeCall::is_call_before(return_address), "must be");
+  return nativeCall_at(call_for(return_address));
+}
+
diff --git a/hotspot/src/cpu/arm/vm/nativeInst_arm_64.hpp b/hotspot/src/cpu/arm/vm/nativeInst_arm_64.hpp
new file mode 100644
index 0000000..159d5df
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/nativeInst_arm_64.hpp
@@ -0,0 +1,772 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_NATIVEINST_ARM_64_HPP
+#define CPU_ARM_VM_NATIVEINST_ARM_64_HPP
+
+#include "asm/macroAssembler.hpp"
+#include "code/codeCache.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/os.hpp"
+
+// -------------------------------------------------------------------
+
+// Some experimental projects extend the ARM back-end by implementing
+// what the front-end usually assumes is a single native instruction
+// with a sequence of instructions.
+//
+// The 'Raw' variants are the low level initial code (usually one
+// instruction wide but some of them were already composed
+// instructions). They should be used only by the back-end.
+//
+// The non-raw classes are the front-end entry point, hiding potential
+// back-end extensions or the actual instructions size.
+class NativeInstruction;
+
+class RawNativeInstruction VALUE_OBJ_CLASS_SPEC {
+ public:
+
+  enum ARM_specific {
+    instruction_size = Assembler::InstructionSize,
+    instruction_size_in_bits = instruction_size * BitsPerByte,
+  };
+
+  // illegal instruction used by NativeJump::patch_verified_entry
+  static const int zombie_illegal_instruction = 0xd4000542; // hvc #42
+
+  address addr_at(int offset)        const { return (address)this + offset; }
+  address instruction_address()      const { return addr_at(0); }
+  address next_raw_instruction_address() const { return addr_at(instruction_size); }
+
+  static RawNativeInstruction* at(address address) {
+    return (RawNativeInstruction*)address;
+  }
+
+  RawNativeInstruction* next_raw() const {
+    return at(next_raw_instruction_address());
+  }
+
+  int encoding() const {
+    return *(int*)this;
+  }
+
+  void set_encoding(int value) {
+    int old = encoding();
+    if (old != value) {
+      *(int*)this = value;
+      ICache::invalidate_word((address)this);
+    }
+  }
+
+  bool is_nop()                      const { return encoding() == (int)0xd503201f; }
+  bool is_b()                        const { return (encoding() & 0xfc000000) == 0x14000000; } // unconditional branch
+  bool is_b_cond()                   const { return (encoding() & 0xff000010) == 0x54000000; } // conditional branch
+  bool is_bl()                       const { return (encoding() & 0xfc000000) == 0x94000000; }
+  bool is_br()                       const { return (encoding() & 0xfffffc1f) == 0xd61f0000; }
+  bool is_blr()                      const { return (encoding() & 0xfffffc1f) == 0xd63f0000; }
+  bool is_ldr_literal()              const { return (encoding() & 0xff000000) == 0x58000000; }
+  bool is_adr_aligned()              const { return (encoding() & 0xff000000) == 0x10000000; } // adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
+  bool is_adr_aligned_lr()           const { return (encoding() & 0xff00001f) == 0x1000001e; } // adr LR, <label>, where label is aligned to 4 bytes (address of instruction).
+
+  bool is_ldr_str_gp_reg_unsigned_imm()   const { return (encoding() & 0x3f000000) == 0x39000000; } // ldr/str{b, sb, h, sh, _w, sw} Rt, [Rn, #imm]
+  bool is_ldr_str_fp_reg_unsigned_imm()   const { return (encoding() & 0x3f000000) == 0x3D000000; } // ldr/str Rt(SIMD), [Rn, #imm]
+  bool is_ldr_str_reg_unsigned_imm()      const { return is_ldr_str_gp_reg_unsigned_imm() || is_ldr_str_fp_reg_unsigned_imm(); }
+
+  bool is_stp_preindex()             const { return (encoding() & 0xffc00000) == 0xa9800000; } // stp Xt1, Xt2, [Xn, #imm]!
+  bool is_ldp_postindex()            const { return (encoding() & 0xffc00000) == 0xa8c00000; } // ldp Xt1, Xt2, [Xn] #imm
+  bool is_mov_sp()                   const { return (encoding() & 0xfffffc00) == 0x91000000; } // mov <Xn|SP>, <Xm|SP>
+  bool is_movn()                     const { return (encoding() & 0x7f800000) == 0x12800000; }
+  bool is_movz()                     const { return (encoding() & 0x7f800000) == 0x52800000; }
+  bool is_movk()                     const { return (encoding() & 0x7f800000) == 0x72800000; }
+  bool is_orr_imm()                  const { return (encoding() & 0x7f800000) == 0x32000000; }
+  bool is_cmp_rr()                   const { return (encoding() & 0x7fe00000) == 0x6b000000; }
+  bool is_csel()                     const { return (encoding() & 0x7fe00000) == 0x1a800000; }
+  bool is_sub_shift()                const { return (encoding() & 0x7f200000) == 0x4b000000; } // sub Rd, Rn, shift (Rm, imm)
+  bool is_mov()                      const { return (encoding() & 0x7fe0ffe0) == 0x2a0003e0; } // mov Rd, Rm (orr Rd, ZR, shift (Rm, 0))
+  bool is_tst()                      const { return (encoding() & 0x7f20001f) == 0x6a00001f; } // tst Rn, shift (Rm, imm) (ands ZR, Rn, shift(Rm, imm))
+  bool is_lsr_imm()                  const { return (encoding() & 0x7f807c00) == 0x53007c00; } // lsr Rd, Rn, imm (ubfm Rd, Rn, imm, 31/63)
+
+  bool is_far_jump()                 const { return is_ldr_literal() && next_raw()->is_br(); }
+  bool is_fat_call()                 const {
+    return
+#ifdef COMPILER2
+      (is_blr() && next_raw()->is_b()) ||
+#endif
+      (is_adr_aligned_lr() && next_raw()->is_br());
+  }
+  bool is_far_call()                 const {
+    return is_ldr_literal() && next_raw()->is_fat_call();
+  }
+
+  bool is_ic_near_call()             const { return is_adr_aligned_lr() && next_raw()->is_b(); }
+  bool is_ic_far_call()              const { return is_adr_aligned_lr() && next_raw()->is_ldr_literal() && next_raw()->next_raw()->is_br(); }
+  bool is_ic_call()                  const { return is_ic_near_call() || is_ic_far_call(); }
+
+  bool is_jump()                     const { return is_b() || is_far_jump(); }
+  bool is_call()                     const { return is_bl() || is_far_call() || is_ic_call(); }
+  bool is_branch()                   const { return is_b() || is_bl(); }
+
+  // c2 doesn't use fixed registers for safepoint poll address
+  bool is_safepoint_poll() const {
+    return true;
+  }
+
+  bool is_save_all_registers(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    if (!current->is_stp_preindex()) return false; current = current->next_raw();
+    for (int i = 28; i >= 0; i -= 2) {
+      if (!current->is_stp_preindex()) return false; current = current->next_raw();
+    }
+
+    if (!current->is_adr_aligned())                 return false; current = current->next_raw();
+    if (!current->is_ldr_str_gp_reg_unsigned_imm()) return false; current = current->next_raw();
+    if (!current->is_ldr_str_gp_reg_unsigned_imm()) return false; current = current->next_raw();
+
+    *next = (RawNativeInstruction*) current;
+    return true;
+  }
+
+  bool is_restore_all_registers(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    for (int i = 0; i <= 28; i += 2) {
+      if (!current->is_ldp_postindex()) return false; current = current->next_raw();
+    }
+    if (!current->is_ldp_postindex()) return false; current = current->next_raw();
+
+    *next = (RawNativeInstruction*) current;
+    return true;
+  }
+
+  const RawNativeInstruction* skip_bind_literal() const {
+    const RawNativeInstruction* current = this;
+    if (((uintptr_t)current) % wordSize != 0) {
+      assert(current->is_nop(), "should be");
+      current = current->next_raw();
+    }
+    assert(((uintptr_t)current) % wordSize == 0, "should be"); // bound literal should be aligned
+    current = current->next_raw()->next_raw();
+    return current;
+  }
+
+  bool is_stop(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    if (!current->is_save_all_registers(&current)) return false;
+    if (!current->is_ldr_literal())                return false; current = current->next_raw();
+    if (!current->is_mov_sp())                     return false; current = current->next_raw();
+    if (!current->is_ldr_literal())                return false; current = current->next_raw();
+    if (!current->is_br())                         return false; current = current->next_raw();
+
+    current = current->skip_bind_literal();
+    current = current->skip_bind_literal();
+
+    *next = (RawNativeInstruction*) current;
+    return true;
+  }
+
+  bool is_mov_slow(const RawNativeInstruction** next = NULL) const {
+    const RawNativeInstruction* current = this;
+
+    if (current->is_orr_imm()) {
+      current = current->next_raw();
+
+    } else if (current->is_movn() || current->is_movz()) {
+      current = current->next_raw();
+      int movkCount = 0;
+      while (current->is_movk()) {
+        movkCount++;
+        if (movkCount > 3) return false;
+        current = current->next_raw();
+      }
+
+    } else {
+      return false;
+    }
+
+    if (next != NULL) {
+      *next = (RawNativeInstruction*)current;
+    }
+    return true;
+  }
+
+#ifdef ASSERT
+  void skip_verify_heapbase(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    if (CheckCompressedOops) {
+      if (!current->is_ldr_str_gp_reg_unsigned_imm()) return; current = current->next_raw();
+      if (!current->is_stp_preindex())      return; current = current->next_raw();
+      // NOTE: temporary workaround, remove with m6-01?
+      // skip saving condition flags
+      current = current->next_raw();
+      current = current->next_raw();
+
+      if (!current->is_mov_slow(&current))  return;
+      if (!current->is_cmp_rr())            return; current = current->next_raw();
+      if (!current->is_b_cond())            return; current = current->next_raw();
+      if (!current->is_stop(&current))      return;
+
+#ifdef COMPILER2
+      if (current->is_nop()) current = current->next_raw();
+#endif
+      // NOTE: temporary workaround, remove with m6-01?
+      // skip restoring condition flags
+      current = current->next_raw();
+      current = current->next_raw();
+
+      if (!current->is_ldp_postindex())     return; current = current->next_raw();
+      if (!current->is_ldr_str_gp_reg_unsigned_imm()) return; current = current->next_raw();
+    }
+
+    *next = (RawNativeInstruction*) current;
+  }
+#endif // ASSERT
+
+  bool is_ldr_global_ptr(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    if (!current->is_mov_slow(&current))            return false;
+    if (!current->is_ldr_str_gp_reg_unsigned_imm()) return false; current = current->next_raw();
+
+    *next = (RawNativeInstruction*) current;
+    return true;
+  }
+
+  void skip_verify_oop(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    if (VerifyOops) {
+      if (!current->is_save_all_registers(&current)) return;
+
+      if (current->is_mov()) {
+        current = current->next_raw();
+      }
+
+      if (!current->is_mov_sp())                        return; current = current->next_raw();
+      if (!current->is_ldr_literal())                   return; current = current->next_raw();
+      if (!current->is_ldr_global_ptr(&current))        return;
+      if (!current->is_blr())                           return; current = current->next_raw();
+      if (!current->is_restore_all_registers(&current)) return;
+      if (!current->is_b())                             return; current = current->next_raw();
+
+      current = current->skip_bind_literal();
+    }
+
+    *next = (RawNativeInstruction*) current;
+  }
+
+  void skip_encode_heap_oop(const RawNativeInstruction** next) const {
+    const RawNativeInstruction* current = this;
+
+    assert (Universe::heap() != NULL, "java heap should be initialized");
+#ifdef ASSERT
+    current->skip_verify_heapbase(&current);
+#endif // ASSERT
+    current->skip_verify_oop(&current);
+
+    if (Universe::narrow_oop_base() == NULL) {
+      if (Universe::narrow_oop_shift() != 0) {
+        if (!current->is_lsr_imm()) return; current = current->next_raw();
+      } else {
+        if (current->is_mov()) {
+          current = current->next_raw();
+        }
+      }
+    } else {
+      if (!current->is_tst())       return; current = current->next_raw();
+      if (!current->is_csel())      return; current = current->next_raw();
+      if (!current->is_sub_shift()) return; current = current->next_raw();
+      if (Universe::narrow_oop_shift() != 0) {
+        if (!current->is_lsr_imm())  return; current = current->next_raw();
+      }
+    }
+
+    *next = (RawNativeInstruction*) current;
+  }
+
+  void verify();
+
+  // For unit tests
+  static void test() {}
+
+ private:
+
+  void check_bits_range(int bits, int scale, int low_bit) const {
+    assert((0 <= low_bit) && (0 < bits) && (low_bit + bits <= instruction_size_in_bits), "invalid bits range");
+    assert((0 <= scale) && (scale <= 4), "scale is out of range");
+  }
+
+  void set_imm(int imm_encoding, int bits, int low_bit) {
+    int imm_mask = right_n_bits(bits) << low_bit;
+    assert((imm_encoding & ~imm_mask) == 0, "invalid imm encoding");
+    set_encoding((encoding() & ~imm_mask) | imm_encoding);
+  }
+
+ protected:
+
+  // Returns signed immediate from [low_bit .. low_bit + bits - 1] bits of this instruction, scaled by given scale.
+  int get_signed_imm(int bits, int scale, int low_bit) const {
+    check_bits_range(bits, scale, low_bit);
+    int high_bits_to_clean = (instruction_size_in_bits - (low_bit + bits));
+    return encoding() << high_bits_to_clean >> (high_bits_to_clean + low_bit) << scale;
+  }
+
+  // Puts given signed immediate into the [low_bit .. low_bit + bits - 1] bits of this instruction.
+  void set_signed_imm(int value, int bits, int scale, int low_bit) {
+    set_imm(Assembler::encode_imm(value, bits, scale, low_bit), bits, low_bit);
+  }
+
+  // Returns unsigned immediate from [low_bit .. low_bit + bits - 1] bits of this instruction, scaled by given scale.
+  int get_unsigned_imm(int bits, int scale, int low_bit) const {
+    check_bits_range(bits, scale, low_bit);
+    return ((encoding() >> low_bit) & right_n_bits(bits)) << scale;
+  }
+
+  // Puts given unsigned immediate into the [low_bit .. low_bit + bits - 1] bits of this instruction.
+  void set_unsigned_imm(int value, int bits, int scale, int low_bit) {
+    set_imm(Assembler::encode_unsigned_imm(value, bits, scale, low_bit), bits, low_bit);
+  }
+
+  int get_signed_offset(int bits, int low_bit) const {
+    return get_signed_imm(bits, 2, low_bit);
+  }
+
+  void set_signed_offset(int offset, int bits, int low_bit) {
+    set_signed_imm(offset, bits, 2, low_bit);
+  }
+};
+
+inline RawNativeInstruction* rawNativeInstruction_at(address address) {
+  RawNativeInstruction* instr = RawNativeInstruction::at(address);
+#ifdef ASSERT
+  instr->verify();
+#endif // ASSERT
+  return instr;
+}
+
+// -------------------------------------------------------------------
+
+// Load/store register (unsigned scaled immediate)
+class NativeMovRegMem: public RawNativeInstruction {
+ private:
+  int get_offset_scale() const {
+    return get_unsigned_imm(2, 0, 30);
+  }
+
+ public:
+  int offset() const {
+    return get_unsigned_imm(12, get_offset_scale(), 10);
+  }
+
+  void set_offset(int x);
+
+  void add_offset_in_bytes(int add_offset) {
+    set_offset(offset() + add_offset);
+  }
+};
+
+inline NativeMovRegMem* nativeMovRegMem_at(address address) {
+  const RawNativeInstruction* instr = rawNativeInstruction_at(address);
+
+#ifdef COMPILER1
+    // NOP required for C1 patching
+    if (instr->is_nop()) {
+      instr = instr->next_raw();
+    }
+#endif
+
+  instr->skip_encode_heap_oop(&instr);
+
+  assert(instr->is_ldr_str_reg_unsigned_imm(), "must be");
+  return (NativeMovRegMem*)instr;
+}
+
+// -------------------------------------------------------------------
+
+class NativeInstruction : public RawNativeInstruction {
+public:
+  static NativeInstruction* at(address address) {
+    return (NativeInstruction*)address;
+  }
+
+public:
+  // No need to consider indirections while parsing NativeInstruction
+  address next_instruction_address() const {
+    return next_raw_instruction_address();
+  }
+
+  // next() is no longer defined to avoid confusion.
+  //
+  // The front end and most classes except for those defined in nativeInst_arm
+  // or relocInfo_arm should only use next_instruction_address(), skipping
+  // over composed instruction and ignoring back-end extensions.
+  //
+  // The back-end can use next_raw() when it knows the instruction sequence
+  // and only wants to skip a single native instruction.
+};
+
+inline NativeInstruction* nativeInstruction_at(address address) {
+  NativeInstruction* instr = NativeInstruction::at(address);
+#ifdef ASSERT
+  instr->verify();
+#endif // ASSERT
+  return instr;
+}
+
+// -------------------------------------------------------------------
+class NativeInstructionLdrLiteral: public NativeInstruction {
+ public:
+  address literal_address() {
+    address la = instruction_address() + get_signed_offset(19, 5);
+    assert(la != instruction_address(), "literal points to instruction");
+    return la;
+  }
+
+  address after_literal_address() {
+    return literal_address() + wordSize;
+  }
+
+  void set_literal_address(address addr, address pc) {
+    assert(is_ldr_literal(), "must be");
+    int opc = (encoding() >> 30) & 0x3;
+    assert (opc != 0b01 || addr == pc || ((uintx)addr & 7) == 0, "ldr target should be aligned");
+    set_signed_offset(addr - pc, 19, 5);
+  }
+
+  void set_literal_address(address addr) {
+    set_literal_address(addr, instruction_address());
+  }
+
+  address literal_value() {
+    return *(address*)literal_address();
+  }
+
+  void set_literal_value(address dest) {
+    *(address*)literal_address() = dest;
+  }
+};
+
+inline NativeInstructionLdrLiteral* nativeLdrLiteral_at(address address) {
+  assert(nativeInstruction_at(address)->is_ldr_literal(), "must be");
+  return (NativeInstructionLdrLiteral*)address;
+}
+
+// -------------------------------------------------------------------
+// Common class for branch instructions with 26-bit immediate offset: B (unconditional) and BL
+class NativeInstructionBranchImm26: public NativeInstruction {
+ public:
+  address destination(int adj = 0) const {
+    return instruction_address() + get_signed_offset(26, 0) + adj;
+  }
+
+  void set_destination(address dest) {
+    intptr_t offset = (intptr_t)(dest - instruction_address());
+    assert((offset & 0x3) == 0, "should be aligned");
+    set_signed_offset(offset, 26, 0);
+  }
+};
+
+inline NativeInstructionBranchImm26* nativeB_at(address address) {
+  assert(nativeInstruction_at(address)->is_b(), "must be");
+  return (NativeInstructionBranchImm26*)address;
+}
+
+inline NativeInstructionBranchImm26* nativeBL_at(address address) {
+  assert(nativeInstruction_at(address)->is_bl(), "must be");
+  return (NativeInstructionBranchImm26*)address;
+}
+
+// -------------------------------------------------------------------
+class NativeInstructionAdrLR: public NativeInstruction {
+ public:
+  // Returns address which is loaded into LR by this instruction.
+  address target_lr_value() {
+    return instruction_address() + get_signed_offset(19, 5);
+  }
+};
+
+inline NativeInstructionAdrLR* nativeAdrLR_at(address address) {
+  assert(nativeInstruction_at(address)->is_adr_aligned_lr(), "must be");
+  return (NativeInstructionAdrLR*)address;
+}
+
+// -------------------------------------------------------------------
+class RawNativeCall: public NativeInstruction {
+ public:
+
+  address return_address() const {
+    if (is_bl()) {
+      return next_raw_instruction_address();
+
+    } else if (is_far_call()) {
+#ifdef COMPILER2
+      if (next_raw()->is_blr()) {
+        // ldr_literal; blr; ret_addr: b skip_literal;
+        return addr_at(2 * instruction_size);
+      }
+#endif
+      assert(next_raw()->is_adr_aligned_lr() && next_raw()->next_raw()->is_br(), "must be");
+      return nativeLdrLiteral_at(instruction_address())->after_literal_address();
+
+    } else if (is_ic_call()) {
+      return nativeAdrLR_at(instruction_address())->target_lr_value();
+
+    } else {
+      ShouldNotReachHere();
+      return NULL;
+    }
+  }
+
+  address destination(int adj = 0) const {
+    if (is_bl()) {
+      return nativeBL_at(instruction_address())->destination(adj);
+
+    } else if (is_far_call()) {
+      return nativeLdrLiteral_at(instruction_address())->literal_value();
+
+    } else if (is_adr_aligned_lr()) {
+      RawNativeInstruction *next = next_raw();
+      if (next->is_b()) {
+        // ic_near_call
+        return nativeB_at(next->instruction_address())->destination(adj);
+      } else if (next->is_far_jump()) {
+        // ic_far_call
+        return nativeLdrLiteral_at(next->instruction_address())->literal_value();
+      }
+    }
+    ShouldNotReachHere();
+    return NULL;
+  }
+
+  void set_destination(address dest) {
+    if (is_bl()) {
+      nativeBL_at(instruction_address())->set_destination(dest);
+      return;
+    }
+    if (is_far_call()) {
+      nativeLdrLiteral_at(instruction_address())->set_literal_value(dest);
+      OrderAccess::storeload(); // overkill if caller holds lock?
+      return;
+    }
+    if (is_adr_aligned_lr()) {
+      RawNativeInstruction *next = next_raw();
+      if (next->is_b()) {
+        // ic_near_call
+        nativeB_at(next->instruction_address())->set_destination(dest);
+        return;
+      }
+      if (next->is_far_jump()) {
+        // ic_far_call
+        nativeLdrLiteral_at(next->instruction_address())->set_literal_value(dest);
+        OrderAccess::storeload(); // overkill if caller holds lock?
+        return;
+      }
+    }
+    ShouldNotReachHere();
+  }
+
+  void set_destination_mt_safe(address dest) {
+    assert(CodeCache::contains(dest), "call target should be from code cache (required by ic_call and patchable_call)");
+    set_destination(dest);
+  }
+
+  void verify() {
+    assert(RawNativeInstruction::is_call(), "should be");
+  }
+
+  void verify_alignment() {
+    // Nothing to do on ARM
+  }
+};
+
+inline RawNativeCall* rawNativeCall_at(address address) {
+  RawNativeCall * call = (RawNativeCall*)address;
+  call->verify();
+  return call;
+}
+
+class NativeCall: public RawNativeCall {
+ public:
+
+  // NativeCall::next_instruction_address() is used only to define the
+  // range where to look for the relocation information. We need not
+  // walk over composed instructions (as long as the relocation information
+  // is associated to the first instruction).
+  address next_instruction_address() const {
+    return next_raw_instruction_address();
+  }
+
+  static bool is_call_before(address return_address);
+};
+
+inline NativeCall* nativeCall_at(address address) {
+  NativeCall * call = (NativeCall*)address;
+  call->verify();
+  return call;
+}
+
+NativeCall* nativeCall_before(address return_address);
+
+// -------------------------------------------------------------------
+class NativeGeneralJump: public NativeInstruction {
+ public:
+
+  address jump_destination() const {
+    return nativeB_at(instruction_address())->destination();
+  }
+
+  static void replace_mt_safe(address instr_addr, address code_buffer);
+
+  static void insert_unconditional(address code_pos, address entry);
+
+};
+
+inline NativeGeneralJump* nativeGeneralJump_at(address address) {
+  assert(nativeInstruction_at(address)->is_b(), "must be");
+  return (NativeGeneralJump*)address;
+}
+
+// -------------------------------------------------------------------
+class RawNativeJump: public NativeInstruction {
+ public:
+
+  address jump_destination(int adj = 0) const {
+    if (is_b()) {
+      address a = nativeB_at(instruction_address())->destination(adj);
+      // Jump destination -1 is encoded as a jump to self
+      if (a == instruction_address()) {
+        return (address)-1;
+      }
+      return a;
+    } else {
+      assert(is_far_jump(), "should be");
+      return nativeLdrLiteral_at(instruction_address())->literal_value();
+    }
+  }
+
+  void set_jump_destination(address dest) {
+    if (is_b()) {
+      // Jump destination -1 is encoded as a jump to self
+      if (dest == (address)-1) {
+        dest = instruction_address();
+      }
+      nativeB_at(instruction_address())->set_destination(dest);
+    } else {
+      assert(is_far_jump(), "should be");
+      nativeLdrLiteral_at(instruction_address())->set_literal_value(dest);
+    }
+  }
+};
+
+inline RawNativeJump* rawNativeJump_at(address address) {
+  assert(rawNativeInstruction_at(address)->is_jump(), "must be");
+  return (RawNativeJump*)address;
+}
+
+// -------------------------------------------------------------------
+class NativeMovConstReg: public NativeInstruction {
+
+  NativeMovConstReg *adjust() const {
+    return (NativeMovConstReg *)adjust(this);
+  }
+
+ public:
+
+  static RawNativeInstruction *adjust(const RawNativeInstruction *ni) {
+#ifdef COMPILER1
+    // NOP required for C1 patching
+    if (ni->is_nop()) {
+      return ni->next_raw();
+    }
+#endif
+    return (RawNativeInstruction *)ni;
+  }
+
+  intptr_t _data() const;
+  void set_data(intptr_t x);
+
+  intptr_t data() const {
+    return adjust()->_data();
+  }
+
+  bool is_pc_relative() {
+    return adjust()->is_ldr_literal();
+  }
+
+  void _set_pc_relative_offset(address addr, address pc) {
+    assert(is_ldr_literal(), "must be");
+    nativeLdrLiteral_at(instruction_address())->set_literal_address(addr, pc);
+  }
+
+  void set_pc_relative_offset(address addr, address pc) {
+    NativeMovConstReg *ni = adjust();
+    int dest_adj = ni->instruction_address() - instruction_address();
+    ni->_set_pc_relative_offset(addr, pc + dest_adj);
+  }
+
+  address _next_instruction_address() const {
+#ifdef COMPILER2
+    if (is_movz()) {
+      // narrow constant
+      RawNativeInstruction* ni = next_raw();
+      assert(ni->is_movk(), "movz;movk expected");
+      return ni->next_raw_instruction_address();
+    }
+#endif
+    assert(is_ldr_literal(), "must be");
+    return NativeInstruction::next_raw_instruction_address();
+  }
+
+  address next_instruction_address() const {
+    return adjust()->_next_instruction_address();
+  }
+};
+
+inline NativeMovConstReg* nativeMovConstReg_at(address address) {
+  RawNativeInstruction* ni = rawNativeInstruction_at(address);
+
+  ni = NativeMovConstReg::adjust(ni);
+
+  assert(ni->is_mov_slow() || ni->is_ldr_literal(), "must be");
+  return (NativeMovConstReg*)address;
+}
+
+// -------------------------------------------------------------------
+class NativeJump: public RawNativeJump {
+ public:
+
+  static void check_verified_entry_alignment(address entry, address verified_entry);
+
+  static void patch_verified_entry(address entry, address verified_entry, address dest);
+};
+
+inline NativeJump* nativeJump_at(address address) {
+  assert(nativeInstruction_at(address)->is_jump(), "must be");
+  return (NativeJump*)address;
+}
+
+#endif // CPU_ARM_VM_NATIVEINST_ARM_64_HPP
diff --git a/hotspot/src/cpu/arm/vm/registerMap_arm.hpp b/hotspot/src/cpu/arm/vm/registerMap_arm.hpp
new file mode 100644
index 0000000..a19e594
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/registerMap_arm.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_REGISTERMAP_ARM_HPP
+#define CPU_ARM_VM_REGISTERMAP_ARM_HPP
+
+// machine-dependent implemention for register maps
+  friend class frame;
+
+ private:
+  // This is the hook for finding a register in an "well-known" location,
+  // such as a register block of a predetermined format.
+  // Since there is none, we just return NULL.
+  // See registerMap_sparc.hpp for an example of grabbing registers
+  // from register save areas of a standard layout.
+   address pd_location(VMReg reg) const {return NULL;}
+
+  // no PD state to clear or copy:
+  void pd_clear() {}
+  void pd_initialize() {}
+  void pd_initialize_from(const RegisterMap* map) {}
+
+#endif // CPU_ARM_VM_REGISTERMAP_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/register_arm.cpp b/hotspot/src/cpu/arm/vm/register_arm.cpp
new file mode 100644
index 0000000..9e75b68
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/register_arm.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "register_arm.hpp"
+#include "utilities/debug.hpp"
+
+const int ConcreteRegisterImpl::max_gpr = ConcreteRegisterImpl::num_gpr;
+const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::num_fpr +
+                                          ConcreteRegisterImpl::max_gpr;
+
+const char* RegisterImpl::name() const {
+  const char* names[number_of_registers] = {
+#ifdef AARCH64
+    "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
+    "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
+    "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+    "x24", "x25", "x26", "x27", "x28", "fp",  "lr",  "xzr", "sp"
+#else
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6",
+#if (FP_REG_NUM == 7)
+    "fp",
+#else
+    "r7",
+#endif
+    "r8", "r9", "r10",
+#if (FP_REG_NUM == 11)
+    "fp",
+#else
+    "r11",
+#endif
+    "r12", "sp", "lr", "pc"
+#endif // AARCH64
+  };
+  return is_valid() ? names[encoding()] : "noreg";
+}
+
+const char* FloatRegisterImpl::name() const {
+  const char* names[number_of_registers] = {
+#ifdef AARCH64
+    "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
+    "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
+    "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+    "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+#else
+     "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
+     "s8",  "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+    "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+    "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
+#ifdef COMPILER2
+   ,"s32", "s33?","s34", "s35?","s36", "s37?","s38", "s39?",
+    "s40", "s41?","s42", "s43?","s44", "s45?","s46", "s47?",
+    "s48", "s49?","s50", "s51?","s52", "s53?","s54", "s55?",
+    "s56", "s57?","s58", "s59?","s60", "s61?","s62", "s63?"
+#endif
+#endif // AARCH64
+  };
+  return is_valid() ? names[encoding()] : "fnoreg";
+}
diff --git a/hotspot/src/cpu/arm/vm/register_arm.hpp b/hotspot/src/cpu/arm/vm/register_arm.hpp
new file mode 100644
index 0000000..87ea7f5
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/register_arm.hpp
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_REGISTER_ARM_HPP
+#define CPU_ARM_VM_REGISTER_ARM_HPP
+
+#include "asm/register.hpp"
+#include "vm_version_arm.hpp"
+
+class VMRegImpl;
+typedef VMRegImpl* VMReg;
+
+// These are declared ucontext.h
+#undef R0
+#undef R1
+#undef R2
+#undef R3
+#undef R4
+#undef R5
+#undef R6
+#undef R7
+#undef R8
+#undef R9
+#undef R10
+#undef R11
+#undef R12
+#undef R13
+#undef R14
+#undef R15
+
+#define R(r)   ((Register)(r))
+
+/////////////////////////////////
+// Support for different ARM ABIs
+// Note: default ABI is for linux
+
+
+// R9_IS_SCRATCHED
+//
+// The ARM ABI does not guarantee that R9 is callee saved.
+// Set R9_IS_SCRATCHED to 1 to ensure it is properly saved/restored by
+// the caller.
+#ifndef R9_IS_SCRATCHED
+// Default: R9 is callee saved
+#define R9_IS_SCRATCHED 0
+#endif
+
+#ifndef AARCH64
+// FP_REG_NUM
+//
+// The ARM ABI does not state which register is used for the frame pointer.
+// Note: for the ABIs we are currently aware of, FP is currently
+// either R7 or R11. Code may have to be extended if a third register
+// register must be supported (see altFP_7_11).
+#ifndef FP_REG_NUM
+// Default: FP is R11
+#define FP_REG_NUM 11
+#endif
+#endif // AARCH64
+
+// ALIGN_WIDE_ARGUMENTS
+//
+// The ARM ABI requires 64-bits arguments to be aligned on 4 words
+// or on even registers. Set ALIGN_WIDE_ARGUMENTS to 1 for that behavior.
+//
+// Unfortunately, some platforms do not endorse that part of the ABI.
+//
+// We are aware of one which expects 64-bit arguments to only be 4
+// bytes aligned and can for instance use R3 + a stack slot for such
+// an argument.
+//
+// This is the behavor implemented if (ALIGN_WIDE_ARGUMENTS == 0)
+#ifndef  ALIGN_WIDE_ARGUMENTS
+// Default: align on 8 bytes and avoid using <r3+stack>
+#define ALIGN_WIDE_ARGUMENTS 1
+#endif
+
+#define R0     ((Register)0)
+#define R1     ((Register)1)
+#define R2     ((Register)2)
+#define R3     ((Register)3)
+#define R4     ((Register)4)
+#define R5     ((Register)5)
+#define R6     ((Register)6)
+#define R7     ((Register)7)
+#define R8     ((Register)8)
+#define R9     ((Register)9)
+#define R10    ((Register)10)
+#define R11    ((Register)11)
+#define R12    ((Register)12)
+#define R13    ((Register)13)
+#define R14    ((Register)14)
+#define R15    ((Register)15)
+
+#ifdef AARCH64
+
+#define R16    ((Register)16)
+#define R17    ((Register)17)
+#define R18    ((Register)18)
+#define R19    ((Register)19)
+#define R20    ((Register)20)
+#define R21    ((Register)21)
+#define R22    ((Register)22)
+#define R23    ((Register)23)
+#define R24    ((Register)24)
+#define R25    ((Register)25)
+#define R26    ((Register)26)
+#define R27    ((Register)27)
+#define R28    ((Register)28)
+#define R29    ((Register)29)
+#define R30    ((Register)30)
+#define ZR     ((Register)31)
+#define SP     ((Register)32)
+
+#define FP     R29
+#define LR     R30
+
+#define altFP_7_11 R7
+
+#else // !AARCH64
+
+#define FP     ((Register)FP_REG_NUM)
+
+// Safe use of registers which may be FP on some platforms.
+//
+// altFP_7_11: R7 if not equal to FP, else R11 (the default FP)
+//
+// Note: add additional altFP_#_11 for each register potentially used
+// as FP on supported ABIs (and replace R# by altFP_#_11). altFP_#_11
+// must be #define to R11 if and only if # is FP_REG_NUM.
+#if (FP_REG_NUM == 7)
+#define altFP_7_11     ((Register)11)
+#else
+#define altFP_7_11     ((Register)7)
+#endif
+#define SP     R13
+#define LR     R14
+#define PC     R15
+
+#endif // !AARCH64
+
+
+class RegisterImpl;
+typedef RegisterImpl* Register;
+
+inline Register as_Register(int encoding) {
+  return (Register)(intptr_t)encoding;
+}
+
+class RegisterImpl : public AbstractRegisterImpl {
+ public:
+  enum {
+#ifdef AARCH64
+    number_of_gprs = 31,
+    zr_sp_encoding = 31,
+#endif
+    number_of_registers = AARCH64_ONLY(number_of_gprs + 2) NOT_AARCH64(16)
+  };
+
+  Register successor() const      { return as_Register(encoding() + 1); }
+
+  inline friend Register as_Register(int encoding);
+
+  VMReg as_VMReg();
+
+  // accessors
+  int   encoding() const          { assert(is_valid(), "invalid register"); return value(); }
+  const char* name() const;
+
+#ifdef AARCH64
+  int encoding_with_zr() const   { assert (is_valid_gpr_or_zr(), "invalid register"); return (this == ZR) ? zr_sp_encoding : value(); }
+  int encoding_with_sp() const   { assert (is_valid_gpr_or_sp(), "invalid register"); return (this == SP) ? zr_sp_encoding : value(); }
+#endif
+
+  // testers
+  bool is_valid() const           { return 0 <= value() && value() < number_of_registers; }
+
+#ifdef AARCH64
+  bool is_valid_gpr()       const  { return (0 <= value() && value() < number_of_gprs); }
+  bool is_valid_gpr_or_zr() const  { return is_valid_gpr() || (this == ZR); }
+  bool is_valid_gpr_or_sp() const  { return is_valid_gpr() || (this == SP); }
+#endif
+};
+
+CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1));
+
+
+// Use FloatRegister as shortcut
+class FloatRegisterImpl;
+typedef FloatRegisterImpl* FloatRegister;
+
+inline FloatRegister as_FloatRegister(int encoding) {
+  return (FloatRegister)(intptr_t)encoding;
+}
+
+class FloatRegisterImpl : public AbstractRegisterImpl {
+ public:
+  enum {
+#ifdef AARCH64
+    number_of_registers = 32
+#else
+    number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64)
+#endif
+  };
+
+  inline friend FloatRegister as_FloatRegister(int encoding);
+
+  VMReg as_VMReg();
+
+  int   encoding() const          { assert(is_valid(), "invalid register"); return value(); }
+  bool  is_valid() const          { return 0 <= (intx)this && (intx)this < number_of_registers; }
+  FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
+
+  const char* name() const;
+
+#ifndef AARCH64
+  int hi_bits() const {
+    return (encoding() >> 1) & 0xf;
+  }
+
+  int lo_bit() const {
+    return encoding() & 1;
+  }
+
+  int hi_bit() const {
+    return encoding() >> 5;
+  }
+#endif // !AARCH64
+};
+
+CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg, (-1));
+
+#ifdef AARCH64
+
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V0,     ( 0));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V1,     ( 1));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V2,     ( 2));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V3,     ( 3));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V4,     ( 4));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V5,     ( 5));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V6,     ( 6));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V7,     ( 7));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V8,     ( 8));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V9,     ( 9));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V10,    (10));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V11,    (11));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V12,    (12));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V13,    (13));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V14,    (14));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V15,    (15));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V16,    (16));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V17,    (17));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V18,    (18));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V19,    (19));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V20,    (20));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V21,    (21));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V22,    (22));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V23,    (23));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V24,    (24));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V25,    (25));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V26,    (26));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V27,    (27));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V28,    (28));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V29,    (29));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V30,    (30));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, V31,    (31));
+
+#define S0       V0
+#define S1_reg   V1
+#define Stemp    V31
+
+#define D0       V0
+#define D1       V1
+
+#else // AARCH64
+
+/*
+ * S1-S6 are named with "_reg" suffix to avoid conflict with
+ * constants defined in sharedRuntimeTrig.cpp
+ */
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S0,     ( 0));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S1_reg, ( 1));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S2_reg, ( 2));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S3_reg, ( 3));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S4_reg, ( 4));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S5_reg, ( 5));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S6_reg, ( 6));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S7,     ( 7));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S8,     ( 8));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S9,     ( 9));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S10,    (10));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S11,    (11));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S12,    (12));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S13,    (13));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S14,    (14));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S15,    (15));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S16,    (16));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S17,    (17));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S18,    (18));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S19,    (19));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S20,    (20));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S21,    (21));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S22,    (22));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S23,    (23));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S24,    (24));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S25,    (25));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S26,    (26));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S27,    (27));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S28,    (28));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S29,    (29));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S30,    (30));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, S31,    (31));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, Stemp,  (30));
+
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D0,     ( 0));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D1,     ( 2));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D2,     ( 4));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D3,     ( 6));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D4,     ( 8));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D5,     ( 10));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D6,     ( 12));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D7,     ( 14));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D8,     ( 16));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D9,     ( 18));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D10,    ( 20));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D11,    ( 22));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D12,    ( 24));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D13,    ( 26));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D14,    ( 28));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D15,    (30));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D16,    (32));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D17,    (34));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D18,    (36));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D19,    (38));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D20,    (40));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D21,    (42));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D22,    (44));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D23,    (46));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D24,    (48));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D25,    (50));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D26,    (52));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D27,    (54));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D28,    (56));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D29,    (58));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D30,    (60));
+CONSTANT_REGISTER_DECLARATION(FloatRegister, D31,    (62));
+
+#endif // AARCH64
+
+class ConcreteRegisterImpl : public AbstractRegisterImpl {
+ public:
+  enum {
+    log_vmregs_per_word = LogBytesPerWord - LogBytesPerInt, // VMRegs are of 4-byte size
+#ifdef COMPILER2
+    log_bytes_per_fpr  = AARCH64_ONLY(4) NOT_AARCH64(2), // quad vectors
+#else
+    log_bytes_per_fpr  = AARCH64_ONLY(3) NOT_AARCH64(2), // double vectors
+#endif
+    log_words_per_fpr  = log_bytes_per_fpr - LogBytesPerWord,
+    words_per_fpr      = 1 << log_words_per_fpr,
+    log_vmregs_per_fpr = log_bytes_per_fpr - LogBytesPerInt,
+    log_vmregs_per_gpr = log_vmregs_per_word,
+    vmregs_per_gpr = 1 << log_vmregs_per_gpr,
+    vmregs_per_fpr = 1 << log_vmregs_per_fpr,
+
+    num_gpr  = RegisterImpl::number_of_registers << log_vmregs_per_gpr,
+    max_gpr0 = num_gpr,
+    num_fpr  = FloatRegisterImpl::number_of_registers << log_vmregs_per_fpr,
+    max_fpr0 = max_gpr0 + num_fpr,
+    number_of_registers = num_gpr + num_fpr +
+                          // TODO-AARCH64 revise
+                          1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers
+  };
+
+  static const int max_gpr;
+  static const int max_fpr;
+};
+
+// TODO-AARCH64 revise the following definitions
+
+class VFPSystemRegisterImpl;
+typedef VFPSystemRegisterImpl* VFPSystemRegister;
+class VFPSystemRegisterImpl : public AbstractRegisterImpl {
+ public:
+  int   encoding() const          { return value(); }
+};
+
+#define FPSID     ((VFPSystemRegister)0)
+#define FPSCR     ((VFPSystemRegister)1)
+#define MVFR0     ((VFPSystemRegister)0x6)
+#define MVFR1     ((VFPSystemRegister)0x7)
+
+/*
+ * Register definitions shared across interpreter and compiler
+ */
+#define Rexception_obj   AARCH64_ONLY(R19) NOT_AARCH64(R4)
+#define Rexception_pc    AARCH64_ONLY(R20) NOT_AARCH64(R5)
+
+#ifdef AARCH64
+#define Rheap_base       R27
+#endif // AARCH64
+
+/*
+ * Interpreter register definitions common to C++ and template interpreters.
+ */
+#ifdef AARCH64
+#define Rlocals          R23
+#define Rmethod          R26
+#define Rthread          R28
+#define Rtemp            R16
+#define Rtemp2           R17
+#else
+#define Rlocals          R8
+#define Rmethod          R9
+#define Rthread          R10
+#define Rtemp            R12
+#endif // AARCH64
+
+// Interpreter calling conventions
+
+#define Rparams          AARCH64_ONLY(R8)  NOT_AARCH64(SP)
+#define Rsender_sp       AARCH64_ONLY(R19) NOT_AARCH64(R4)
+
+// JSR292
+//  Note: R5_mh is needed only during the call setup, including adapters
+//  This does not seem to conflict with Rexception_pc
+//  In case of issues, R3 might be OK but adapters calling the runtime would have to save it
+#define R5_mh            R5 // MethodHandle register, used during the call setup
+#define Rmh_SP_save      FP // for C1
+
+/*
+ * C++ Interpreter Register Defines
+ */
+#define Rsave0   R4
+#define Rsave1   R5
+#define Rsave2   R6
+#define Rstate   altFP_7_11 // R7 or R11
+#define Ricklass R8
+
+/*
+ * TemplateTable Interpreter Register Usage
+ */
+
+// Temporary registers
+#define R0_tmp                 R0
+#define R1_tmp                 R1
+#define R2_tmp                 R2
+#define R3_tmp                 R3
+#define R4_tmp                 R4
+#define R5_tmp                 R5
+#define R12_tmp                R12
+#define LR_tmp                 LR
+
+#define S0_tmp                 S0
+#define S1_tmp                 S1_reg
+
+#define D0_tmp                 D0
+#define D1_tmp                 D1
+
+// Temporary registers saved across VM calls (according to C calling conventions)
+#define Rtmp_save0             AARCH64_ONLY(R19) NOT_AARCH64(R4)
+#define Rtmp_save1             AARCH64_ONLY(R20) NOT_AARCH64(R5)
+
+// Cached TOS value
+#define R0_tos                 R0
+
+#ifndef AARCH64
+#define R0_tos_lo              R0
+#define R1_tos_hi              R1
+#endif
+
+#define S0_tos                 S0
+#define D0_tos                 D0
+
+// Dispatch table
+#define RdispatchTable         AARCH64_ONLY(R22) NOT_AARCH64(R6)
+
+// Bytecode pointer
+#define Rbcp                   AARCH64_ONLY(R24) NOT_AARCH64(altFP_7_11)
+
+// Pre-loaded next bytecode for the dispatch
+#define R3_bytecode            R3
+
+// Conventions between bytecode templates and stubs
+#define R2_ClassCastException_obj        R2
+#define R4_ArrayIndexOutOfBounds_index   R4
+
+// Interpreter expression stack top
+#define Rstack_top             AARCH64_ONLY(R25) NOT_AARCH64(SP)
+
+/*
+ * Linux 32-bit ARM C ABI Register calling conventions
+ *
+ *   REG         use                     callee/caller saved
+ *
+ *   R0         First argument reg            caller
+ *              result register
+ *   R1         Second argument reg           caller
+ *              result register
+ *   R2         Third argument reg            caller
+ *   R3         Fourth argument reg           caller
+ *
+ *   R4 - R8    Local variable registers      callee
+ *   R9
+ *   R10, R11   Local variable registers      callee
+ *
+ *   R12 (IP)   Scratch register used in inter-procedural calling
+ *   R13 (SP)   Stack Pointer                 callee
+ *   R14 (LR)   Link register
+ *   R15 (PC)   Program Counter
+ *
+ * TODO-AARCH64: document AArch64 ABI
+ *
+ */
+#define c_rarg0  R0
+#define c_rarg1  R1
+#define c_rarg2  R2
+#define c_rarg3  R3
+
+#ifdef AARCH64
+#define c_rarg4  R4
+#define c_rarg5  R5
+#define c_rarg6  R6
+#define c_rarg7  R7
+#endif
+
+#ifdef AARCH64
+#define GPR_PARAMS    8
+#define FPR_PARAMS    8
+#else
+#define GPR_PARAMS    4
+#endif
+
+
+// Java ABI
+// XXX Is this correct?
+#define j_rarg0  c_rarg0
+#define j_rarg1  c_rarg1
+#define j_rarg2  c_rarg2
+#define j_rarg3  c_rarg3
+
+#ifdef AARCH64
+#define j_rarg4  c_rarg4
+#define j_rarg5  c_rarg5
+#define j_rarg6  c_rarg6
+#define j_rarg7  c_rarg7
+#endif
+
+#endif // CPU_ARM_VM_REGISTER_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/register_definitions_arm.cpp b/hotspot/src/cpu/arm/vm/register_definitions_arm.cpp
new file mode 100644
index 0000000..53fa4a2
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/register_definitions_arm.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/register.hpp"
+#include "interp_masm_arm.hpp"
+#include "register_arm.hpp"
+
+REGISTER_DEFINITION(Register, noreg);
+REGISTER_DEFINITION(FloatRegister, fnoreg);
+
+#ifdef AARCH64
+
+REGISTER_DEFINITION(FloatRegister, V0);
+REGISTER_DEFINITION(FloatRegister, V1);
+REGISTER_DEFINITION(FloatRegister, V2);
+REGISTER_DEFINITION(FloatRegister, V3);
+REGISTER_DEFINITION(FloatRegister, V4);
+REGISTER_DEFINITION(FloatRegister, V5);
+REGISTER_DEFINITION(FloatRegister, V6);
+REGISTER_DEFINITION(FloatRegister, V7);
+REGISTER_DEFINITION(FloatRegister, V8);
+REGISTER_DEFINITION(FloatRegister, V9);
+REGISTER_DEFINITION(FloatRegister, V10);
+REGISTER_DEFINITION(FloatRegister, V11);
+REGISTER_DEFINITION(FloatRegister, V12);
+REGISTER_DEFINITION(FloatRegister, V13);
+REGISTER_DEFINITION(FloatRegister, V14);
+REGISTER_DEFINITION(FloatRegister, V15);
+REGISTER_DEFINITION(FloatRegister, V16);
+REGISTER_DEFINITION(FloatRegister, V17);
+REGISTER_DEFINITION(FloatRegister, V18);
+REGISTER_DEFINITION(FloatRegister, V19);
+REGISTER_DEFINITION(FloatRegister, V20);
+REGISTER_DEFINITION(FloatRegister, V21);
+REGISTER_DEFINITION(FloatRegister, V22);
+REGISTER_DEFINITION(FloatRegister, V23);
+REGISTER_DEFINITION(FloatRegister, V24);
+REGISTER_DEFINITION(FloatRegister, V25);
+REGISTER_DEFINITION(FloatRegister, V26);
+REGISTER_DEFINITION(FloatRegister, V27);
+REGISTER_DEFINITION(FloatRegister, V28);
+REGISTER_DEFINITION(FloatRegister, V29);
+REGISTER_DEFINITION(FloatRegister, V30);
+REGISTER_DEFINITION(FloatRegister, V31);
+
+#else // AARCH64
+
+REGISTER_DEFINITION(FloatRegister, S0);
+REGISTER_DEFINITION(FloatRegister, S1_reg);
+REGISTER_DEFINITION(FloatRegister, S2_reg);
+REGISTER_DEFINITION(FloatRegister, S3_reg);
+REGISTER_DEFINITION(FloatRegister, S4_reg);
+REGISTER_DEFINITION(FloatRegister, S5_reg);
+REGISTER_DEFINITION(FloatRegister, S6_reg);
+REGISTER_DEFINITION(FloatRegister, S7);
+REGISTER_DEFINITION(FloatRegister, S8);
+REGISTER_DEFINITION(FloatRegister, S9);
+REGISTER_DEFINITION(FloatRegister, S10);
+REGISTER_DEFINITION(FloatRegister, S11);
+REGISTER_DEFINITION(FloatRegister, S12);
+REGISTER_DEFINITION(FloatRegister, S13);
+REGISTER_DEFINITION(FloatRegister, S14);
+REGISTER_DEFINITION(FloatRegister, S15);
+REGISTER_DEFINITION(FloatRegister, S16);
+REGISTER_DEFINITION(FloatRegister, S17);
+REGISTER_DEFINITION(FloatRegister, S18);
+REGISTER_DEFINITION(FloatRegister, S19);
+REGISTER_DEFINITION(FloatRegister, S20);
+REGISTER_DEFINITION(FloatRegister, S21);
+REGISTER_DEFINITION(FloatRegister, S22);
+REGISTER_DEFINITION(FloatRegister, S23);
+REGISTER_DEFINITION(FloatRegister, S24);
+REGISTER_DEFINITION(FloatRegister, S25);
+REGISTER_DEFINITION(FloatRegister, S26);
+REGISTER_DEFINITION(FloatRegister, S27);
+REGISTER_DEFINITION(FloatRegister, S28);
+REGISTER_DEFINITION(FloatRegister, S29);
+REGISTER_DEFINITION(FloatRegister, S30);
+REGISTER_DEFINITION(FloatRegister, S31);
+REGISTER_DEFINITION(FloatRegister, Stemp);
+REGISTER_DEFINITION(FloatRegister, D0);
+REGISTER_DEFINITION(FloatRegister, D1);
+REGISTER_DEFINITION(FloatRegister, D2);
+REGISTER_DEFINITION(FloatRegister, D3);
+REGISTER_DEFINITION(FloatRegister, D4);
+REGISTER_DEFINITION(FloatRegister, D5);
+REGISTER_DEFINITION(FloatRegister, D6);
+REGISTER_DEFINITION(FloatRegister, D7);
+REGISTER_DEFINITION(FloatRegister, D8);
+REGISTER_DEFINITION(FloatRegister, D9);
+REGISTER_DEFINITION(FloatRegister, D10);
+REGISTER_DEFINITION(FloatRegister, D11);
+REGISTER_DEFINITION(FloatRegister, D12);
+REGISTER_DEFINITION(FloatRegister, D13);
+REGISTER_DEFINITION(FloatRegister, D14);
+REGISTER_DEFINITION(FloatRegister, D15);
+REGISTER_DEFINITION(FloatRegister, D16);
+REGISTER_DEFINITION(FloatRegister, D17);
+REGISTER_DEFINITION(FloatRegister, D18);
+REGISTER_DEFINITION(FloatRegister, D19);
+REGISTER_DEFINITION(FloatRegister, D20);
+REGISTER_DEFINITION(FloatRegister, D21);
+REGISTER_DEFINITION(FloatRegister, D22);
+REGISTER_DEFINITION(FloatRegister, D23);
+REGISTER_DEFINITION(FloatRegister, D24);
+REGISTER_DEFINITION(FloatRegister, D25);
+REGISTER_DEFINITION(FloatRegister, D26);
+REGISTER_DEFINITION(FloatRegister, D27);
+REGISTER_DEFINITION(FloatRegister, D28);
+REGISTER_DEFINITION(FloatRegister, D29);
+REGISTER_DEFINITION(FloatRegister, D30);
+REGISTER_DEFINITION(FloatRegister, D31);
+
+#endif //AARCH64
diff --git a/hotspot/src/cpu/arm/vm/relocInfo_arm.cpp b/hotspot/src/cpu/arm/vm/relocInfo_arm.cpp
new file mode 100644
index 0000000..e17c584
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/relocInfo_arm.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.inline.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/relocInfo.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/safepoint.hpp"
+
+void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
+
+  NativeMovConstReg* ni = nativeMovConstReg_at(addr());
+#if defined(AARCH64) && defined(COMPILER2)
+  if (ni->is_movz()) {
+    assert(type() == relocInfo::oop_type, "!");
+    if (verify_only) {
+      uintptr_t d = ni->data();
+      guarantee((d >> 32) == 0, "not narrow oop");
+      narrowOop no = d;
+      oop o = oopDesc::decode_heap_oop(no);
+      guarantee(cast_from_oop<intptr_t>(o) == (intptr_t)x, "instructions must match");
+    } else {
+      ni->set_data((intptr_t)x);
+    }
+    return;
+  }
+#endif
+  if (verify_only) {
+    guarantee(ni->data() == (intptr_t)(x + o), "instructions must match");
+  } else {
+    ni->set_data((intptr_t)(x + o));
+  }
+}
+
+address Relocation::pd_call_destination(address orig_addr) {
+  address pc = addr();
+
+  int adj = 0;
+  if (orig_addr != NULL) {
+    // We just moved this call instruction from orig_addr to addr().
+    // This means that, when relative, its target will appear to have grown by addr() - orig_addr.
+    adj = orig_addr - pc;
+  }
+
+  RawNativeInstruction* ni = rawNativeInstruction_at(pc);
+
+#if (!defined(AARCH64))
+  if (NOT_AARCH64(ni->is_add_lr()) AARCH64_ONLY(ni->is_adr_aligned_lr())) {
+    // On arm32, skip the optional 'add LR, PC, #offset'
+    // (Allowing the jump support code to handle fat_call)
+    pc = ni->next_raw_instruction_address();
+    ni = nativeInstruction_at(pc);
+  }
+#endif
+
+  if (AARCH64_ONLY(ni->is_call()) NOT_AARCH64(ni->is_bl())) {
+    // For arm32, fat_call are handled by is_jump for the new 'ni',
+    // requiring only to support is_bl.
+    //
+    // For AARCH64, skipping a leading adr is not sufficient
+    // to reduce calls to a simple bl.
+    return rawNativeCall_at(pc)->destination(adj);
+  }
+
+  if (ni->is_jump()) {
+    return rawNativeJump_at(pc)->jump_destination(adj);
+  }
+  ShouldNotReachHere();
+  return NULL;
+}
+
+void Relocation::pd_set_call_destination(address x) {
+  address pc = addr();
+  NativeInstruction* ni = nativeInstruction_at(pc);
+
+#if (!defined(AARCH64))
+  if (NOT_AARCH64(ni->is_add_lr()) AARCH64_ONLY(ni->is_adr_aligned_lr())) {
+    // On arm32, skip the optional 'add LR, PC, #offset'
+    // (Allowing the jump support code to handle fat_call)
+    pc = ni->next_raw_instruction_address();
+    ni = nativeInstruction_at(pc);
+  }
+#endif
+
+  if (AARCH64_ONLY(ni->is_call()) NOT_AARCH64(ni->is_bl())) {
+    // For arm32, fat_call are handled by is_jump for the new 'ni',
+    // requiring only to support is_bl.
+    //
+    // For AARCH64, skipping a leading adr is not sufficient
+    // to reduce calls to a simple bl.
+    rawNativeCall_at(pc)->set_destination(x);
+    return;
+  }
+
+  if (ni->is_jump()) { // raw jump
+    rawNativeJump_at(pc)->set_jump_destination(x);
+    return;
+  }
+  ShouldNotReachHere();
+}
+
+
+address* Relocation::pd_address_in_code() {
+  return (address*)addr();
+}
+
+address Relocation::pd_get_address_from_code() {
+  return *pd_address_in_code();
+}
+
+void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
+}
+
+void metadata_Relocation::pd_fix_value(address x) {
+  assert(! addr_in_const(), "Do not use");
+#ifdef AARCH64
+#ifdef COMPILER2
+  NativeMovConstReg* ni = nativeMovConstReg_at(addr());
+  if (ni->is_movz()) {
+    return;
+  }
+#endif
+  set_value(x);
+#else
+  if (!VM_Version::supports_movw()) {
+    set_value(x);
+#ifdef ASSERT
+  } else {
+    // the movw/movt data should be correct
+    NativeMovConstReg* ni = nativeMovConstReg_at(addr());
+    assert(ni->is_movw(), "not a movw");
+    // The following assert should be correct but the shared code
+    // currently 'fixes' the metadata instructions before the
+    // metadata_table is copied in the new method (see
+    // JDK-8042845). This means that 'x' (which comes from the table)
+    // does not match the value inlined in the code (which is
+    // correct). Failure can be temporarily ignored since the code is
+    // correct and the table is copied shortly afterward.
+    //
+    // assert(ni->data() == (int)x, "metadata relocation mismatch");
+#endif
+  }
+#endif // !AARCH64
+}
diff --git a/hotspot/src/cpu/arm/vm/relocInfo_arm.hpp b/hotspot/src/cpu/arm/vm/relocInfo_arm.hpp
new file mode 100644
index 0000000..3c16eed
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/relocInfo_arm.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_RELOCINFO_ARM_HPP
+#define CPU_ARM_VM_RELOCINFO_ARM_HPP
+
+ private:
+
+  enum {
+    offset_unit  = 4,
+    format_width = 0
+  };
+
+#endif // CPU_ARM_VM_RELOCINFO_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/runtime_arm.cpp b/hotspot/src/cpu/arm/vm/runtime_arm.cpp
new file mode 100644
index 0000000..8916207
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/runtime_arm.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#ifdef COMPILER2
+#include "asm/assembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "code/vmreg.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/resourceArea.hpp"
+#include "nativeInst_arm.hpp"
+#include "opto/runtime.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "vmreg_arm.inline.hpp"
+#endif
+
+#define __ masm->
+
+//------------------------------ generate_exception_blob ---------------------------
+// creates exception blob at the end
+// Using exception blob, this code is jumped from a compiled method.
+// (see emit_exception_handler in sparc.ad file)
+//
+// Given an exception pc at a call we call into the runtime for the
+// handler in this method. This handler might merely restore state
+// (i.e. callee save registers) unwind the frame and jump to the
+// exception handler for the nmethod if there is no Java level handler
+// for the nmethod.
+//
+// This code is entered with a jmp.
+//
+// Arguments:
+//   Rexception_obj (R4/R19): exception oop
+//   Rexception_pc  (R5/R20): exception pc
+//
+// Results:
+//   Rexception_obj (R4/R19): exception oop
+//   O1: exception pc in caller or ???
+//   destination: exception handler of caller
+//
+// Note: the exception pc MUST be at a call (precise debug information)
+//
+void OptoRuntime::generate_exception_blob() {
+  // allocate space for code
+  ResourceMark rm;
+  int pad = VerifyThread ? 256 : 0;// Extra slop space for more verify code
+
+  // setup code generation tools
+  // Measured 8/7/03 at 256 in 32bit debug build (no VerifyThread)
+  // Measured 8/7/03 at 528 in 32bit debug build (VerifyThread)
+  CodeBuffer buffer("exception_blob", 600+pad, 512);
+  MacroAssembler* masm     = new MacroAssembler(&buffer);
+
+  int framesize_in_words = 2; // FP + LR
+  int framesize_in_bytes = framesize_in_words * wordSize;
+  int framesize_in_slots = framesize_in_bytes / sizeof(jint);
+
+  int start = __ offset();
+
+  __ str(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ str(Rexception_pc, Address(Rthread, JavaThread::exception_pc_offset()));
+
+  // This call does all the hard work. It checks if an exception catch
+  // exists in the method.
+  // If so, it returns the handler address.
+  // If the nmethod has been deoptimized and it had a handler the handler
+  // address is the deopt blob unpack_with_exception entry.
+  //
+  // If no handler exists it prepares for stack-unwinding, restoring the callee-save
+  // registers of the frame being removed.
+  //
+  __ mov(LR, Rexception_pc);
+  __ raw_push(FP, LR);
+  int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
+
+  __ mov(R0, Rthread);
+
+  // This call can block at exit and nmethod can be deoptimized at that
+  // point. If the nmethod had a catch point we would jump to the
+  // now deoptimized catch point and fall thru the vanilla deopt
+  // path and lose the exception
+  // Sure would be simpler if this call didn't block!
+  __ call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C));
+  if (pc_offset == -1) {
+    pc_offset = __ offset();
+  }
+
+  // Set an oopmap for the call site.  This oopmap will only be used if we
+  // are unwinding the stack.  Hence, all locations will be dead.
+  // Callee-saved registers will be the same as the frame above (i.e.,
+  // handle_exception_stub), since they were restored when we got the
+  // exception.
+
+  OopMapSet *oop_maps = new OopMapSet();
+  oop_maps->add_gc_map(pc_offset - start, new OopMap(framesize_in_slots, 0));
+
+  __ reset_last_Java_frame(Rtemp);
+
+  __ raw_pop(FP, LR);
+
+  // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site.
+  __ ldr(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset()));
+#ifdef AARCH64
+  Label skip;
+  __ cbz(Rtemp, skip);
+  __ mov(SP, Rmh_SP_save);
+  __ bind(skip);
+#else
+  __ cmp(Rtemp, 0);
+  __ mov(SP, Rmh_SP_save, ne);
+#endif
+
+  // R0 contains handler address
+  // Since this may be the deopt blob we must set R5 to look like we returned
+  // from the original pc that threw the exception
+
+  __ ldr(Rexception_pc,  Address(Rthread, JavaThread::exception_pc_offset()));  // R5/R20
+
+  __ ldr(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset())); // R4/R19
+  __ mov(Rtemp, 0);
+#ifdef ASSERT
+  __ str(Rtemp, Address(Rthread, JavaThread::exception_handler_pc_offset()));
+  __ str(Rtemp, Address(Rthread, JavaThread::exception_pc_offset()));
+#endif
+  // Clear the exception oop so GC no longer processes it as a root.
+  __ str(Rtemp, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ jump(R0);
+
+  // -------------
+  // make sure all code is generated
+  masm->flush();
+
+  _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words);
+}
diff --git a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp
new file mode 100644
index 0000000..7096d9b
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp
@@ -0,0 +1,2501 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/debugInfoRec.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/compiledICHolder.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/vframeArray.hpp"
+#include "vmreg_arm.inline.hpp"
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#endif
+#ifdef COMPILER2
+#include "opto/runtime.hpp"
+#endif
+#ifdef SHARK
+#include "compiler/compileBroker.hpp"
+#include "shark/sharkCompiler.hpp"
+#endif
+
+#define __ masm->
+
+class RegisterSaver {
+public:
+
+  // Special registers:
+  //              32-bit ARM     64-bit ARM
+  //  Rthread:       R10            R28
+  //  LR:            R14            R30
+
+  // Rthread is callee saved in the C ABI and never changed by compiled code:
+  // no need to save it.
+
+  // 2 slots for LR: the one at LR_offset and an other one at R14/R30_offset.
+  // The one at LR_offset is a return address that is needed by stack walking.
+  // A c2 method uses LR as a standard register so it may be live when we
+  // branch to the runtime. The slot at R14/R30_offset is for the value of LR
+  // in case it's live in the method we are coming from.
+
+#ifdef AARCH64
+
+  //
+  // On AArch64 registers save area has the following layout:
+  //
+  // |---------------------|
+  // | return address (LR) |
+  // | FP                  |
+  // |---------------------|
+  // | V31                 |
+  // | ...                 |
+  // | V0                  |
+  // |---------------------|
+  // | padding             |
+  // | R30 (LR live value) |
+  // |---------------------|
+  // | R27                 |
+  // | ...                 |
+  // | R0                  |
+  // |---------------------| <-- SP
+  //
+
+  enum RegisterLayout {
+    number_of_saved_gprs = 28,
+    number_of_saved_fprs = FloatRegisterImpl::number_of_registers,
+    words_per_fpr = ConcreteRegisterImpl::words_per_fpr,
+
+    R0_offset  = 0,
+    R30_offset = R0_offset + number_of_saved_gprs,
+    D0_offset  = R30_offset + 2,
+    FP_offset  = D0_offset + number_of_saved_fprs * words_per_fpr,
+    LR_offset  = FP_offset + 1,
+
+    reg_save_size = LR_offset + 1,
+  };
+
+  static const int Rmethod_offset;
+  static const int Rtemp_offset;
+
+#else
+
+  enum RegisterLayout {
+    fpu_save_size = FloatRegisterImpl::number_of_registers,
+#ifndef __SOFTFP__
+    D0_offset = 0,
+#endif
+    R0_offset = fpu_save_size,
+    R1_offset,
+    R2_offset,
+    R3_offset,
+    R4_offset,
+    R5_offset,
+    R6_offset,
+#if (FP_REG_NUM != 7)
+    // if not saved as FP
+    R7_offset,
+#endif
+    R8_offset,
+    R9_offset,
+#if (FP_REG_NUM != 11)
+    // if not saved as FP
+    R11_offset,
+#endif
+    R12_offset,
+    R14_offset,
+    FP_offset,
+    LR_offset,
+    reg_save_size,
+
+    Rmethod_offset = R9_offset,
+    Rtemp_offset = R12_offset,
+  };
+
+  // all regs but Rthread (R10), FP (R7 or R11), SP and PC
+  // (altFP_7_11 is the one amoung R7 and R11 which is not FP)
+#define SAVED_BASE_REGS (RegisterSet(R0, R6) | RegisterSet(R8, R9) | RegisterSet(R12) | R14 | altFP_7_11)
+
+#endif // AARCH64
+
+  //  When LR may be live in the nmethod from which we are comming
+  //  then lr_saved is true, the return address is saved before the
+  //  call to save_live_register by the caller and LR contains the
+  //  live value.
+
+  static OopMap* save_live_registers(MacroAssembler* masm,
+                                     int* total_frame_words,
+                                     bool lr_saved = false);
+  static void restore_live_registers(MacroAssembler* masm, bool restore_lr = true);
+
+};
+
+
+#ifdef AARCH64
+const int RegisterSaver::Rmethod_offset = RegisterSaver::R0_offset + Rmethod->encoding();
+const int RegisterSaver::Rtemp_offset   = RegisterSaver::R0_offset + Rtemp->encoding();
+#endif // AARCH64
+
+
+OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm,
+                                           int* total_frame_words,
+                                           bool lr_saved) {
+  *total_frame_words = reg_save_size;
+
+  OopMapSet *oop_maps = new OopMapSet();
+  OopMap* map = new OopMap(VMRegImpl::slots_per_word * (*total_frame_words), 0);
+
+#ifdef AARCH64
+  assert((reg_save_size * wordSize) % StackAlignmentInBytes == 0, "SP should be aligned");
+
+  if (lr_saved) {
+    // LR was stashed here, so that jump could use it as a scratch reg
+    __ ldr(LR, Address(SP, 0));
+    // There are two words on the stack top:
+    //  [SP + 0]: placeholder for FP
+    //  [SP + wordSize]: saved return address
+    __ str(FP, Address(SP, 0));
+  } else {
+    __ raw_push(FP, LR);
+  }
+
+  __ sub(SP, SP, (reg_save_size - 2) * wordSize);
+
+  for (int i = 0; i < number_of_saved_gprs; i += 2) {
+    int offset = R0_offset + i;
+    __ stp(as_Register(i), as_Register(i+1), Address(SP, offset * wordSize));
+    map->set_callee_saved(VMRegImpl::stack2reg((offset + 0) * VMRegImpl::slots_per_word), as_Register(i)->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg((offset + 1) * VMRegImpl::slots_per_word), as_Register(i+1)->as_VMReg());
+  }
+
+  __ str(R30, Address(SP, R30_offset * wordSize));
+  map->set_callee_saved(VMRegImpl::stack2reg(R30_offset * VMRegImpl::slots_per_word), R30->as_VMReg());
+
+  for (int i = 0; i < number_of_saved_fprs; i += 2) {
+    int offset1 = D0_offset + i * words_per_fpr;
+    int offset2 = offset1 + words_per_fpr;
+    Address base(SP, offset1 * wordSize);
+    if (words_per_fpr == 2) {
+      // pair of "wide" quad vector registers
+      __ stp_q(as_FloatRegister(i), as_FloatRegister(i+1), base);
+    } else {
+      // pair of double vector registers
+      __ stp_d(as_FloatRegister(i), as_FloatRegister(i+1), base);
+    }
+    map->set_callee_saved(VMRegImpl::stack2reg(offset1 * VMRegImpl::slots_per_word), as_FloatRegister(i)->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(offset2 * VMRegImpl::slots_per_word), as_FloatRegister(i+1)->as_VMReg());
+  }
+#else
+  if (lr_saved) {
+    __ push(RegisterSet(FP));
+  } else {
+    __ push(RegisterSet(FP) | RegisterSet(LR));
+  }
+  __ push(SAVED_BASE_REGS);
+  if (HaveVFP) {
+    if (VM_Version::has_vfp3_32()) {
+      __ fstmdbd(SP, FloatRegisterSet(D16, 16), writeback);
+    } else {
+      if (FloatRegisterImpl::number_of_registers > 32) {
+        assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
+        __ sub(SP, SP, 32 * wordSize);
+      }
+    }
+    __ fstmdbd(SP, FloatRegisterSet(D0, 16), writeback);
+  } else {
+    __ sub(SP, SP, fpu_save_size * wordSize);
+  }
+
+  int i;
+  int j=0;
+  for (i = R0_offset; i <= R9_offset; i++) {
+    if (j == FP_REG_NUM) {
+      // skip the FP register, managed below.
+      j++;
+    }
+    map->set_callee_saved(VMRegImpl::stack2reg(i), as_Register(j)->as_VMReg());
+    j++;
+  }
+  assert(j == R10->encoding(), "must be");
+#if (FP_REG_NUM != 11)
+  // add R11, if not managed as FP
+  map->set_callee_saved(VMRegImpl::stack2reg(R11_offset), R11->as_VMReg());
+#endif
+  map->set_callee_saved(VMRegImpl::stack2reg(R12_offset), R12->as_VMReg());
+  map->set_callee_saved(VMRegImpl::stack2reg(R14_offset), R14->as_VMReg());
+  if (HaveVFP) {
+    for (i = 0; i < (VM_Version::has_vfp3_32() ? 64 : 32); i+=2) {
+      map->set_callee_saved(VMRegImpl::stack2reg(i), as_FloatRegister(i)->as_VMReg());
+      map->set_callee_saved(VMRegImpl::stack2reg(i + 1), as_FloatRegister(i)->as_VMReg()->next());
+    }
+  }
+#endif // AARCH64
+
+  return map;
+}
+
+void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_lr) {
+#ifdef AARCH64
+  for (int i = 0; i < number_of_saved_gprs; i += 2) {
+    __ ldp(as_Register(i), as_Register(i+1), Address(SP, (R0_offset + i) * wordSize));
+  }
+
+  __ ldr(R30, Address(SP, R30_offset * wordSize));
+
+  for (int i = 0; i < number_of_saved_fprs; i += 2) {
+    Address base(SP, (D0_offset + i * words_per_fpr) * wordSize);
+    if (words_per_fpr == 2) {
+      // pair of "wide" quad vector registers
+      __ ldp_q(as_FloatRegister(i), as_FloatRegister(i+1), base);
+    } else {
+      // pair of double vector registers
+      __ ldp_d(as_FloatRegister(i), as_FloatRegister(i+1), base);
+    }
+  }
+
+  __ add(SP, SP, (reg_save_size - 2) * wordSize);
+
+  if (restore_lr) {
+    __ raw_pop(FP, LR);
+  } else {
+    __ ldr(FP, Address(SP, 0));
+  }
+#else
+  if (HaveVFP) {
+    __ fldmiad(SP, FloatRegisterSet(D0, 16), writeback);
+    if (VM_Version::has_vfp3_32()) {
+      __ fldmiad(SP, FloatRegisterSet(D16, 16), writeback);
+    } else {
+      if (FloatRegisterImpl::number_of_registers > 32) {
+        assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
+        __ add(SP, SP, 32 * wordSize);
+      }
+    }
+  } else {
+    __ add(SP, SP, fpu_save_size * wordSize);
+  }
+  __ pop(SAVED_BASE_REGS);
+  if (restore_lr) {
+    __ pop(RegisterSet(FP) | RegisterSet(LR));
+  } else {
+    __ pop(RegisterSet(FP));
+  }
+#endif // AARCH64
+}
+
+#ifdef AARCH64
+
+static void push_result_registers(MacroAssembler* masm, BasicType ret_type) {
+  if (ret_type == T_DOUBLE || ret_type == T_FLOAT) {
+    __ str_d(D0, Address(SP, -2*wordSize, pre_indexed));
+  } else {
+    __ raw_push(R0, ZR);
+  }
+}
+
+static void pop_result_registers(MacroAssembler* masm, BasicType ret_type) {
+  if (ret_type == T_DOUBLE || ret_type == T_FLOAT) {
+    __ ldr_d(D0, Address(SP, 2*wordSize, post_indexed));
+  } else {
+    __ raw_pop(R0, ZR);
+  }
+}
+
+static void push_param_registers(MacroAssembler* masm, int fp_regs_in_arguments) {
+  __ raw_push(R0, R1);
+  __ raw_push(R2, R3);
+  __ raw_push(R4, R5);
+  __ raw_push(R6, R7);
+
+  assert(FPR_PARAMS == 8, "adjust this code");
+  assert((0 <= fp_regs_in_arguments) && (fp_regs_in_arguments <= FPR_PARAMS), "should be");
+
+  if (fp_regs_in_arguments > 6) __ stp_d(V6, V7, Address(SP, -2 * wordSize, pre_indexed));
+  if (fp_regs_in_arguments > 4) __ stp_d(V4, V5, Address(SP, -2 * wordSize, pre_indexed));
+  if (fp_regs_in_arguments > 2) __ stp_d(V2, V3, Address(SP, -2 * wordSize, pre_indexed));
+  if (fp_regs_in_arguments > 0) __ stp_d(V0, V1, Address(SP, -2 * wordSize, pre_indexed));
+}
+
+static void pop_param_registers(MacroAssembler* masm, int fp_regs_in_arguments) {
+  assert(FPR_PARAMS == 8, "adjust this code");
+  assert((0 <= fp_regs_in_arguments) && (fp_regs_in_arguments <= FPR_PARAMS), "should be");
+
+  if (fp_regs_in_arguments > 0) __ ldp_d(V0, V1, Address(SP, 2 * wordSize, post_indexed));
+  if (fp_regs_in_arguments > 2) __ ldp_d(V2, V3, Address(SP, 2 * wordSize, post_indexed));
+  if (fp_regs_in_arguments > 4) __ ldp_d(V4, V5, Address(SP, 2 * wordSize, post_indexed));
+  if (fp_regs_in_arguments > 6) __ ldp_d(V6, V7, Address(SP, 2 * wordSize, post_indexed));
+
+  __ raw_pop(R6, R7);
+  __ raw_pop(R4, R5);
+  __ raw_pop(R2, R3);
+  __ raw_pop(R0, R1);
+}
+
+#else // AARCH64
+
+static void push_result_registers(MacroAssembler* masm, BasicType ret_type) {
+#ifdef __ABI_HARD__
+  if (ret_type == T_DOUBLE || ret_type == T_FLOAT) {
+    __ sub(SP, SP, 8);
+    __ fstd(D0, Address(SP));
+    return;
+  }
+#endif // __ABI_HARD__
+  __ raw_push(R0, R1);
+}
+
+static void pop_result_registers(MacroAssembler* masm, BasicType ret_type) {
+#ifdef __ABI_HARD__
+  if (ret_type == T_DOUBLE || ret_type == T_FLOAT) {
+    __ fldd(D0, Address(SP));
+    __ add(SP, SP, 8);
+    return;
+  }
+#endif // __ABI_HARD__
+  __ raw_pop(R0, R1);
+}
+
+static void push_param_registers(MacroAssembler* masm, int fp_regs_in_arguments) {
+  // R1-R3 arguments need to be saved, but we push 4 registers for 8-byte alignment
+  __ push(RegisterSet(R0, R3));
+
+#ifdef __ABI_HARD__
+  // preserve arguments
+  // Likely not needed as the locking code won't probably modify volatile FP registers,
+  // but there is no way to guarantee that
+  if (fp_regs_in_arguments) {
+    // convert fp_regs_in_arguments to a number of double registers
+    int double_regs_num = (fp_regs_in_arguments + 1) >> 1;
+    __ fstmdbd(SP, FloatRegisterSet(D0, double_regs_num), writeback);
+  }
+#endif // __ ABI_HARD__
+}
+
+static void pop_param_registers(MacroAssembler* masm, int fp_regs_in_arguments) {
+#ifdef __ABI_HARD__
+  if (fp_regs_in_arguments) {
+    int double_regs_num = (fp_regs_in_arguments + 1) >> 1;
+    __ fldmiad(SP, FloatRegisterSet(D0, double_regs_num), writeback);
+  }
+#endif // __ABI_HARD__
+
+  __ pop(RegisterSet(R0, R3));
+}
+
+#endif // AARCH64
+
+
+// Is vector's size (in bytes) bigger than a size saved by default?
+// All vector registers are saved by default on ARM.
+bool SharedRuntime::is_wide_vector(int size) {
+  return false;
+}
+
+size_t SharedRuntime::trampoline_size() {
+  return 16;
+}
+
+void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
+  InlinedAddress dest(destination);
+  __ indirect_jump(dest, Rtemp);
+  __ bind_literal(dest);
+}
+
+int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
+                                        VMRegPair *regs,
+                                        VMRegPair *regs2,
+                                        int total_args_passed) {
+  assert(regs2 == NULL, "not needed on arm");
+#ifdef AARCH64
+  int slot = 0; // counted in 32-bit VMReg slots
+  int reg = 0;
+  int fp_reg = 0;
+  for (int i = 0; i < total_args_passed; i++) {
+    switch (sig_bt[i]) {
+    case T_SHORT:
+    case T_CHAR:
+    case T_BYTE:
+    case T_BOOLEAN:
+    case T_INT:
+      if (reg < GPR_PARAMS) {
+        Register r = as_Register(reg);
+        regs[i].set1(r->as_VMReg());
+        reg++;
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot));
+        slot+=2;
+      }
+      break;
+    case T_LONG:
+      assert(sig_bt[i+1] == T_VOID, "missing Half" );
+      // fall through
+    case T_ARRAY:
+    case T_OBJECT:
+    case T_ADDRESS:
+      if (reg < GPR_PARAMS) {
+        Register r = as_Register(reg);
+        regs[i].set2(r->as_VMReg());
+        reg++;
+      } else {
+        regs[i].set2(VMRegImpl::stack2reg(slot));
+        slot+=2;
+      }
+      break;
+    case T_FLOAT:
+      if (fp_reg < FPR_PARAMS) {
+        FloatRegister r = as_FloatRegister(fp_reg);
+        regs[i].set1(r->as_VMReg());
+        fp_reg++;
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot));
+        slot+=2;
+      }
+      break;
+    case T_DOUBLE:
+      assert(sig_bt[i+1] == T_VOID, "missing Half" );
+      if (fp_reg < FPR_PARAMS) {
+        FloatRegister r = as_FloatRegister(fp_reg);
+        regs[i].set2(r->as_VMReg());
+        fp_reg++;
+      } else {
+        regs[i].set2(VMRegImpl::stack2reg(slot));
+        slot+=2;
+      }
+      break;
+    case T_VOID:
+      assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half");
+      regs[i].set_bad();
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  return slot;
+
+#else // AARCH64
+
+  int slot = 0;
+  int ireg = 0;
+#ifdef __ABI_HARD__
+  int fp_slot = 0;
+  int single_fpr_slot = 0;
+#endif // __ABI_HARD__
+  for (int i = 0; i < total_args_passed; i++) {
+    switch (sig_bt[i]) {
+    case T_SHORT:
+    case T_CHAR:
+    case T_BYTE:
+    case T_BOOLEAN:
+    case T_INT:
+    case T_ARRAY:
+    case T_OBJECT:
+    case T_ADDRESS:
+#ifndef __ABI_HARD__
+    case T_FLOAT:
+#endif // !__ABI_HARD__
+      if (ireg < 4) {
+        Register r = as_Register(ireg);
+        regs[i].set1(r->as_VMReg());
+        ireg++;
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot));
+        slot++;
+      }
+      break;
+    case T_LONG:
+#ifndef __ABI_HARD__
+    case T_DOUBLE:
+#endif // !__ABI_HARD__
+      assert(sig_bt[i+1] == T_VOID, "missing Half" );
+      if (ireg <= 2) {
+#if (ALIGN_WIDE_ARGUMENTS == 1)
+        if(ireg & 1) ireg++;  // Aligned location required
+#endif
+        Register r1 = as_Register(ireg);
+        Register r2 = as_Register(ireg + 1);
+        regs[i].set_pair(r2->as_VMReg(), r1->as_VMReg());
+        ireg += 2;
+#if (ALIGN_WIDE_ARGUMENTS == 0)
+      } else if (ireg == 3) {
+        // uses R3 + one stack slot
+        Register r = as_Register(ireg);
+        regs[i].set_pair(VMRegImpl::stack2reg(slot), r->as_VMReg());
+        ireg += 1;
+        slot += 1;
+#endif
+      } else {
+        if (slot & 1) slot++; // Aligned location required
+        regs[i].set_pair(VMRegImpl::stack2reg(slot+1), VMRegImpl::stack2reg(slot));
+        slot += 2;
+        ireg = 4;
+      }
+      break;
+    case T_VOID:
+      regs[i].set_bad();
+      break;
+#ifdef __ABI_HARD__
+    case T_FLOAT:
+      if ((fp_slot < 16)||(single_fpr_slot & 1)) {
+        if ((single_fpr_slot & 1) == 0) {
+          single_fpr_slot = fp_slot;
+          fp_slot += 2;
+        }
+        FloatRegister r = as_FloatRegister(single_fpr_slot);
+        single_fpr_slot++;
+        regs[i].set1(r->as_VMReg());
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot));
+        slot++;
+      }
+      break;
+    case T_DOUBLE:
+      assert(ALIGN_WIDE_ARGUMENTS == 1, "ABI_HARD not supported with unaligned wide arguments");
+      if (fp_slot <= 14) {
+        FloatRegister r1 = as_FloatRegister(fp_slot);
+        FloatRegister r2 = as_FloatRegister(fp_slot+1);
+        regs[i].set_pair(r2->as_VMReg(), r1->as_VMReg());
+        fp_slot += 2;
+      } else {
+        if(slot & 1) slot++;
+        regs[i].set_pair(VMRegImpl::stack2reg(slot+1), VMRegImpl::stack2reg(slot));
+        slot += 2;
+        single_fpr_slot = 16;
+      }
+      break;
+#endif // __ABI_HARD__
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  return slot;
+#endif // AARCH64
+}
+
+int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
+                                           VMRegPair *regs,
+                                           int total_args_passed,
+                                           int is_outgoing) {
+#ifdef AARCH64
+  // C calling convention on AArch64 is good enough.
+  return c_calling_convention(sig_bt, regs, NULL, total_args_passed);
+#else
+#ifdef __SOFTFP__
+  // soft float is the same as the C calling convention.
+  return c_calling_convention(sig_bt, regs, NULL, total_args_passed);
+#endif // __SOFTFP__
+  (void) is_outgoing;
+  int slot = 0;
+  int ireg = 0;
+  int freg = 0;
+  int single_fpr = 0;
+
+  for (int i = 0; i < total_args_passed; i++) {
+    switch (sig_bt[i]) {
+    case T_SHORT:
+    case T_CHAR:
+    case T_BYTE:
+    case T_BOOLEAN:
+    case T_INT:
+    case T_ARRAY:
+    case T_OBJECT:
+    case T_ADDRESS:
+      if (ireg < 4) {
+        Register r = as_Register(ireg++);
+        regs[i].set1(r->as_VMReg());
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot++));
+      }
+      break;
+    case T_FLOAT:
+      // C2 utilizes S14/S15 for mem-mem moves
+      if ((freg < 16 COMPILER2_PRESENT(-2)) || (single_fpr & 1)) {
+        if ((single_fpr & 1) == 0) {
+          single_fpr = freg;
+          freg += 2;
+        }
+        FloatRegister r = as_FloatRegister(single_fpr++);
+        regs[i].set1(r->as_VMReg());
+      } else {
+        regs[i].set1(VMRegImpl::stack2reg(slot++));
+      }
+      break;
+    case T_DOUBLE:
+      // C2 utilizes S14/S15 for mem-mem moves
+      if (freg <= 14 COMPILER2_PRESENT(-2)) {
+        FloatRegister r1 = as_FloatRegister(freg);
+        FloatRegister r2 = as_FloatRegister(freg + 1);
+        regs[i].set_pair(r2->as_VMReg(), r1->as_VMReg());
+        freg += 2;
+      } else {
+        // Keep internally the aligned calling convention,
+        // ignoring ALIGN_WIDE_ARGUMENTS
+        if (slot & 1) slot++;
+        regs[i].set_pair(VMRegImpl::stack2reg(slot + 1), VMRegImpl::stack2reg(slot));
+        slot += 2;
+        single_fpr = 16;
+      }
+      break;
+    case T_LONG:
+      // Keep internally the aligned calling convention,
+      // ignoring ALIGN_WIDE_ARGUMENTS
+      if (ireg <= 2) {
+        if (ireg & 1) ireg++;
+        Register r1 = as_Register(ireg);
+        Register r2 = as_Register(ireg + 1);
+        regs[i].set_pair(r2->as_VMReg(), r1->as_VMReg());
+        ireg += 2;
+      } else {
+        if (slot & 1) slot++;
+        regs[i].set_pair(VMRegImpl::stack2reg(slot + 1), VMRegImpl::stack2reg(slot));
+        slot += 2;
+        ireg = 4;
+      }
+      break;
+    case T_VOID:
+      regs[i].set_bad();
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+
+  if (slot & 1) slot++;
+  return slot;
+#endif // AARCH64
+}
+
+static void patch_callers_callsite(MacroAssembler *masm) {
+  Label skip;
+
+  __ ldr(Rtemp, Address(Rmethod, Method::code_offset()));
+  __ cbz(Rtemp, skip);
+
+#ifdef AARCH64
+  push_param_registers(masm, FPR_PARAMS);
+  __ raw_push(LR, ZR);
+#else
+  // Pushing an even number of registers for stack alignment.
+  // Selecting R9, which had to be saved anyway for some platforms.
+  __ push(RegisterSet(R0, R3) | R9 | LR);
+#endif // AARCH64
+
+  __ mov(R0, Rmethod);
+  __ mov(R1, LR);
+  __ call(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite));
+
+#ifdef AARCH64
+  __ raw_pop(LR, ZR);
+  pop_param_registers(masm, FPR_PARAMS);
+#else
+  __ pop(RegisterSet(R0, R3) | R9 | LR);
+#endif // AARCH64
+
+  __ bind(skip);
+}
+
+void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
+                                    int total_args_passed, int comp_args_on_stack,
+                                    const BasicType *sig_bt, const VMRegPair *regs) {
+  // TODO: ARM - May be can use ldm to load arguments
+  const Register tmp = Rtemp; // avoid erasing R5_mh
+
+  // Next assert may not be needed but safer. Extra analysis required
+  // if this there is not enough free registers and we need to use R5 here.
+  assert_different_registers(tmp, R5_mh);
+
+  // 6243940 We might end up in handle_wrong_method if
+  // the callee is deoptimized as we race thru here. If that
+  // happens we don't want to take a safepoint because the
+  // caller frame will look interpreted and arguments are now
+  // "compiled" so it is much better to make this transition
+  // invisible to the stack walking code. Unfortunately if
+  // we try and find the callee by normal means a safepoint
+  // is possible. So we stash the desired callee in the thread
+  // and the vm will find there should this case occur.
+  Address callee_target_addr(Rthread, JavaThread::callee_target_offset());
+  __ str(Rmethod, callee_target_addr);
+
+#ifdef AARCH64
+
+  assert_different_registers(tmp, R0, R1, R2, R3, R4, R5, R6, R7, Rsender_sp, Rmethod);
+  assert_different_registers(tmp, R0, R1, R2, R3, R4, R5, R6, R7, Rsender_sp, Rparams);
+
+  if (comp_args_on_stack) {
+    __ sub_slow(SP, SP, round_to(comp_args_on_stack * VMRegImpl::stack_slot_size, StackAlignmentInBytes));
+  }
+
+  for (int i = 0; i < total_args_passed; i++) {
+    if (sig_bt[i] == T_VOID) {
+      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+      continue;
+    }
+    assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "must be ordered");
+
+    int expr_slots_count = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? 2 : 1;
+    Address source_addr(Rparams, Interpreter::expr_offset_in_bytes(total_args_passed - expr_slots_count - i));
+
+    VMReg r = regs[i].first();
+    bool full_word = regs[i].second()->is_valid();
+
+    if (r->is_stack()) {
+      if (full_word) {
+        __ ldr(tmp, source_addr);
+        __ str(tmp, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size));
+      } else {
+        __ ldr_w(tmp, source_addr);
+        __ str_w(tmp, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size));
+      }
+    } else if (r->is_Register()) {
+      if (full_word) {
+        __ ldr(r->as_Register(), source_addr);
+      } else {
+        __ ldr_w(r->as_Register(), source_addr);
+      }
+    } else if (r->is_FloatRegister()) {
+      if (sig_bt[i] == T_DOUBLE) {
+        __ ldr_d(r->as_FloatRegister(), source_addr);
+      } else {
+        __ ldr_s(r->as_FloatRegister(), source_addr);
+      }
+    } else {
+      assert(!r->is_valid() && !regs[i].second()->is_valid(), "must be");
+    }
+  }
+
+  __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset()));
+  __ br(tmp);
+
+#else
+
+  assert_different_registers(tmp, R0, R1, R2, R3, Rsender_sp, Rmethod);
+
+  const Register initial_sp = Rmethod; // temporarily scratched
+
+  // Old code was modifying R4 but this looks unsafe (particularly with JSR292)
+  assert_different_registers(tmp, R0, R1, R2, R3, Rsender_sp, initial_sp);
+
+  __ mov(initial_sp, SP);
+
+  if (comp_args_on_stack) {
+    __ sub_slow(SP, SP, comp_args_on_stack * VMRegImpl::stack_slot_size);
+  }
+  __ bic(SP, SP, StackAlignmentInBytes - 1);
+
+  for (int i = 0; i < total_args_passed; i++) {
+    if (sig_bt[i] == T_VOID) {
+      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+      continue;
+    }
+    assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "must be ordered");
+    int arg_offset = Interpreter::expr_offset_in_bytes(total_args_passed - 1 - i);
+
+    VMReg r_1 = regs[i].first();
+    VMReg r_2 = regs[i].second();
+    if (r_1->is_stack()) {
+      int stack_offset = r_1->reg2stack() * VMRegImpl::stack_slot_size;
+      if (!r_2->is_valid()) {
+        __ ldr(tmp, Address(initial_sp, arg_offset));
+        __ str(tmp, Address(SP, stack_offset));
+      } else {
+        __ ldr(tmp, Address(initial_sp, arg_offset - Interpreter::stackElementSize));
+        __ str(tmp, Address(SP, stack_offset));
+        __ ldr(tmp, Address(initial_sp, arg_offset));
+        __ str(tmp, Address(SP, stack_offset + wordSize));
+      }
+    } else if (r_1->is_Register()) {
+      if (!r_2->is_valid()) {
+        __ ldr(r_1->as_Register(), Address(initial_sp, arg_offset));
+      } else {
+        __ ldr(r_1->as_Register(), Address(initial_sp, arg_offset - Interpreter::stackElementSize));
+        __ ldr(r_2->as_Register(), Address(initial_sp, arg_offset));
+      }
+    } else if (r_1->is_FloatRegister()) {
+#ifdef __SOFTFP__
+      ShouldNotReachHere();
+#endif // __SOFTFP__
+      if (!r_2->is_valid()) {
+        __ flds(r_1->as_FloatRegister(), Address(initial_sp, arg_offset));
+      } else {
+        __ fldd(r_1->as_FloatRegister(), Address(initial_sp, arg_offset - Interpreter::stackElementSize));
+      }
+    } else {
+      assert(!r_1->is_valid() && !r_2->is_valid(), "must be");
+    }
+  }
+
+  // restore Rmethod (scratched for initial_sp)
+  __ ldr(Rmethod, callee_target_addr);
+  __ ldr(PC, Address(Rmethod, Method::from_compiled_offset()));
+
+#endif // AARCH64
+}
+
+static void gen_c2i_adapter(MacroAssembler *masm,
+                            int total_args_passed,  int comp_args_on_stack,
+                            const BasicType *sig_bt, const VMRegPair *regs,
+                            Label& skip_fixup) {
+  // TODO: ARM - May be can use stm to deoptimize arguments
+  const Register tmp = Rtemp;
+
+  patch_callers_callsite(masm);
+  __ bind(skip_fixup);
+
+  __ mov(Rsender_sp, SP); // not yet saved
+
+#ifdef AARCH64
+
+  int extraspace = round_to(total_args_passed * Interpreter::stackElementSize, StackAlignmentInBytes);
+  if (extraspace) {
+    __ sub(SP, SP, extraspace);
+  }
+
+  for (int i = 0; i < total_args_passed; i++) {
+    if (sig_bt[i] == T_VOID) {
+      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+      continue;
+    }
+
+    int expr_slots_count = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? 2 : 1;
+    Address dest_addr(SP, Interpreter::expr_offset_in_bytes(total_args_passed - expr_slots_count - i));
+
+    VMReg r = regs[i].first();
+    bool full_word = regs[i].second()->is_valid();
+
+    if (r->is_stack()) {
+      if (full_word) {
+        __ ldr(tmp, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size + extraspace));
+        __ str(tmp, dest_addr);
+      } else {
+        __ ldr_w(tmp, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size + extraspace));
+        __ str_w(tmp, dest_addr);
+      }
+    } else if (r->is_Register()) {
+      if (full_word) {
+        __ str(r->as_Register(), dest_addr);
+      } else {
+        __ str_w(r->as_Register(), dest_addr);
+      }
+    } else if (r->is_FloatRegister()) {
+      if (sig_bt[i] == T_DOUBLE) {
+        __ str_d(r->as_FloatRegister(), dest_addr);
+      } else {
+        __ str_s(r->as_FloatRegister(), dest_addr);
+      }
+    } else {
+      assert(!r->is_valid() && !regs[i].second()->is_valid(), "must be");
+    }
+  }
+
+  __ mov(Rparams, SP);
+
+  __ ldr(tmp, Address(Rmethod, Method::interpreter_entry_offset()));
+  __ br(tmp);
+
+#else
+
+  int extraspace = total_args_passed * Interpreter::stackElementSize;
+  if (extraspace) {
+    __ sub_slow(SP, SP, extraspace);
+  }
+
+  for (int i = 0; i < total_args_passed; i++) {
+    if (sig_bt[i] == T_VOID) {
+      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+      continue;
+    }
+    int stack_offset = (total_args_passed - 1 - i) * Interpreter::stackElementSize;
+
+    VMReg r_1 = regs[i].first();
+    VMReg r_2 = regs[i].second();
+    if (r_1->is_stack()) {
+      int arg_offset = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace;
+      if (!r_2->is_valid()) {
+        __ ldr(tmp, Address(SP, arg_offset));
+        __ str(tmp, Address(SP, stack_offset));
+      } else {
+        __ ldr(tmp, Address(SP, arg_offset));
+        __ str(tmp, Address(SP, stack_offset - Interpreter::stackElementSize));
+        __ ldr(tmp, Address(SP, arg_offset + wordSize));
+        __ str(tmp, Address(SP, stack_offset));
+      }
+    } else if (r_1->is_Register()) {
+      if (!r_2->is_valid()) {
+        __ str(r_1->as_Register(), Address(SP, stack_offset));
+      } else {
+        __ str(r_1->as_Register(), Address(SP, stack_offset - Interpreter::stackElementSize));
+        __ str(r_2->as_Register(), Address(SP, stack_offset));
+      }
+    } else if (r_1->is_FloatRegister()) {
+#ifdef __SOFTFP__
+      ShouldNotReachHere();
+#endif // __SOFTFP__
+      if (!r_2->is_valid()) {
+        __ fsts(r_1->as_FloatRegister(), Address(SP, stack_offset));
+      } else {
+        __ fstd(r_1->as_FloatRegister(), Address(SP, stack_offset - Interpreter::stackElementSize));
+      }
+    } else {
+      assert(!r_1->is_valid() && !r_2->is_valid(), "must be");
+    }
+  }
+
+  __ ldr(PC, Address(Rmethod, Method::interpreter_entry_offset()));
+
+#endif // AARCH64
+}
+
+AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
+                                                            int total_args_passed,
+                                                            int comp_args_on_stack,
+                                                            const BasicType *sig_bt,
+                                                            const VMRegPair *regs,
+                                                            AdapterFingerPrint* fingerprint) {
+  address i2c_entry = __ pc();
+  gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
+
+  address c2i_unverified_entry = __ pc();
+  Label skip_fixup;
+  const Register receiver       = R0;
+  const Register holder_klass   = Rtemp; // XXX should be OK for C2 but not 100% sure
+  const Register receiver_klass = AARCH64_ONLY(R8) NOT_AARCH64(R4);
+
+  __ load_klass(receiver_klass, receiver);
+  __ ldr(holder_klass, Address(Ricklass, CompiledICHolder::holder_klass_offset()));
+  __ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_method_offset()));
+  __ cmp(receiver_klass, holder_klass);
+
+#ifdef AARCH64
+  Label ic_miss;
+  __ b(ic_miss, ne);
+  __ ldr(Rtemp, Address(Rmethod, Method::code_offset()));
+  __ cbz(Rtemp, skip_fixup);
+  __ bind(ic_miss);
+  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp);
+#else
+  __ ldr(Rtemp, Address(Rmethod, Method::code_offset()), eq);
+  __ cmp(Rtemp, 0, eq);
+  __ b(skip_fixup, eq);
+  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
+#endif // AARCH64
+
+  address c2i_entry = __ pc();
+  gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
+
+  __ flush();
+  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+}
+
+
+static int reg2offset_in(VMReg r) {
+  // Account for saved FP and LR
+  return r->reg2stack() * VMRegImpl::stack_slot_size + 2*wordSize;
+}
+
+static int reg2offset_out(VMReg r) {
+  return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
+}
+
+
+static void verify_oop_args(MacroAssembler* masm,
+                            methodHandle method,
+                            const BasicType* sig_bt,
+                            const VMRegPair* regs) {
+  Register temp_reg = Rmethod;  // not part of any compiled calling seq
+  if (VerifyOops) {
+    for (int i = 0; i < method->size_of_parameters(); i++) {
+      if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) {
+        VMReg r = regs[i].first();
+        assert(r->is_valid(), "bad oop arg");
+        if (r->is_stack()) {
+          __ ldr(temp_reg, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size));
+          __ verify_oop(temp_reg);
+        } else {
+          __ verify_oop(r->as_Register());
+        }
+      }
+    }
+  }
+}
+
+static void gen_special_dispatch(MacroAssembler* masm,
+                                 methodHandle method,
+                                 const BasicType* sig_bt,
+                                 const VMRegPair* regs) {
+  verify_oop_args(masm, method, sig_bt, regs);
+  vmIntrinsics::ID iid = method->intrinsic_id();
+
+  // Now write the args into the outgoing interpreter space
+  bool     has_receiver   = false;
+  Register receiver_reg   = noreg;
+  int      member_arg_pos = -1;
+  Register member_reg     = noreg;
+  int      ref_kind       = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid);
+  if (ref_kind != 0) {
+    member_arg_pos = method->size_of_parameters() - 1;  // trailing MemberName argument
+    member_reg = Rmethod;  // known to be free at this point
+    has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind);
+  } else if (iid == vmIntrinsics::_invokeBasic) {
+    has_receiver = true;
+  } else {
+    fatal("unexpected intrinsic id %d", iid);
+  }
+
+  if (member_reg != noreg) {
+    // Load the member_arg into register, if necessary.
+    SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs);
+    VMReg r = regs[member_arg_pos].first();
+    if (r->is_stack()) {
+      __ ldr(member_reg, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size));
+    } else {
+      // no data motion is needed
+      member_reg = r->as_Register();
+    }
+  }
+
+  if (has_receiver) {
+    // Make sure the receiver is loaded into a register.
+    assert(method->size_of_parameters() > 0, "oob");
+    assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object");
+    VMReg r = regs[0].first();
+    assert(r->is_valid(), "bad receiver arg");
+    if (r->is_stack()) {
+      // Porting note:  This assumes that compiled calling conventions always
+      // pass the receiver oop in a register.  If this is not true on some
+      // platform, pick a temp and load the receiver from stack.
+      assert(false, "receiver always in a register");
+      receiver_reg = j_rarg0;  // known to be free at this point
+      __ ldr(receiver_reg, Address(SP, r->reg2stack() * VMRegImpl::stack_slot_size));
+    } else {
+      // no data motion is needed
+      receiver_reg = r->as_Register();
+    }
+  }
+
+  // Figure out which address we are really jumping to:
+  MethodHandles::generate_method_handle_dispatch(masm, iid,
+                                                 receiver_reg, member_reg, /*for_compiler_entry:*/ true);
+}
+
+// ---------------------------------------------------------------------------
+// Generate a native wrapper for a given method.  The method takes arguments
+// in the Java compiled code convention, marshals them to the native
+// convention (handlizes oops, etc), transitions to native, makes the call,
+// returns to java state (possibly blocking), unhandlizes any result and
+// returns.
+nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
+                                                const methodHandle& method,
+                                                int compile_id,
+                                                BasicType* in_sig_bt,
+                                                VMRegPair* in_regs,
+                                                BasicType ret_type) {
+  if (method->is_method_handle_intrinsic()) {
+    vmIntrinsics::ID iid = method->intrinsic_id();
+    intptr_t start = (intptr_t)__ pc();
+    int vep_offset = ((intptr_t)__ pc()) - start;
+    gen_special_dispatch(masm,
+                         method,
+                         in_sig_bt,
+                         in_regs);
+    int frame_complete = ((intptr_t)__ pc()) - start;  // not complete, period
+    __ flush();
+    int stack_slots = SharedRuntime::out_preserve_stack_slots();  // no out slots at all, actually
+    return nmethod::new_native_nmethod(method,
+                                       compile_id,
+                                       masm->code(),
+                                       vep_offset,
+                                       frame_complete,
+                                       stack_slots / VMRegImpl::slots_per_word,
+                                       in_ByteSize(-1),
+                                       in_ByteSize(-1),
+                                       (OopMapSet*)NULL);
+  }
+  // Arguments for JNI method include JNIEnv and Class if static
+
+  // Usage of Rtemp should be OK since scratched by native call
+
+  bool is_static = method->is_static();
+
+  const int total_in_args = method->size_of_parameters();
+  int total_c_args = total_in_args + 1;
+  if (is_static) {
+    total_c_args++;
+  }
+
+  BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args);
+  VMRegPair* out_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args);
+
+  int argc = 0;
+  out_sig_bt[argc++] = T_ADDRESS;
+  if (is_static) {
+    out_sig_bt[argc++] = T_OBJECT;
+  }
+
+  int i;
+  for (i = 0; i < total_in_args; i++) {
+    out_sig_bt[argc++] = in_sig_bt[i];
+  }
+
+  int out_arg_slots = c_calling_convention(out_sig_bt, out_regs, NULL, total_c_args);
+  int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots;
+  // Since object arguments need to be wrapped, we must preserve space
+  // for those object arguments which come in registers (GPR_PARAMS maximum)
+  // plus one more slot for Klass handle (for static methods)
+  int oop_handle_offset = stack_slots;
+  stack_slots += (GPR_PARAMS + 1) * VMRegImpl::slots_per_word;
+
+  // Plus a lock if needed
+  int lock_slot_offset = 0;
+  if (method->is_synchronized()) {
+    lock_slot_offset = stack_slots;
+    assert(sizeof(BasicLock) == wordSize, "adjust this code");
+    stack_slots += VMRegImpl::slots_per_word;
+  }
+
+  // Space to save return address and FP
+  stack_slots += 2 * VMRegImpl::slots_per_word;
+
+  // Calculate the final stack size taking account of alignment
+  stack_slots = round_to(stack_slots, StackAlignmentInBytes / VMRegImpl::stack_slot_size);
+  int stack_size = stack_slots * VMRegImpl::stack_slot_size;
+  int lock_slot_fp_offset = stack_size - 2 * wordSize -
+    lock_slot_offset * VMRegImpl::stack_slot_size;
+
+  // Unverified entry point
+  address start = __ pc();
+
+  // Inline cache check, same as in C1_MacroAssembler::inline_cache_check()
+  const Register receiver = R0; // see receiverOpr()
+  __ load_klass(Rtemp, receiver);
+  __ cmp(Rtemp, Ricklass);
+  Label verified;
+
+  __ b(verified, eq); // jump over alignment no-ops too
+  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp);
+  __ align(CodeEntryAlignment);
+
+  // Verified entry point
+  __ bind(verified);
+  int vep_offset = __ pc() - start;
+
+#ifdef AARCH64
+  // Extra nop for MT-safe patching in NativeJump::patch_verified_entry
+  __ nop();
+#endif // AARCH64
+
+  if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) {
+    // Object.hashCode, System.identityHashCode can pull the hashCode from the header word
+    // instead of doing a full VM transition once it's been computed.
+    Label slow_case;
+    const Register obj_reg = R0;
+
+    // Unlike for Object.hashCode, System.identityHashCode is static method and
+    // gets object as argument instead of the receiver.
+    if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) {
+      assert(method->is_static(), "method should be static");
+      // return 0 for null reference input, return val = R0 = obj_reg = 0
+#ifdef AARCH64
+      Label Continue;
+      __ cbnz(obj_reg, Continue);
+      __ ret();
+      __ bind(Continue);
+#else
+      __ cmp(obj_reg, 0);
+      __ bx(LR, eq);
+#endif
+    }
+
+    __ ldr(Rtemp, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
+
+    assert(markOopDesc::unlocked_value == 1, "adjust this code");
+    __ tbz(Rtemp, exact_log2(markOopDesc::unlocked_value), slow_case);
+
+    if (UseBiasedLocking) {
+      assert(is_power_of_2(markOopDesc::biased_lock_bit_in_place), "adjust this code");
+      __ tbnz(Rtemp, exact_log2(markOopDesc::biased_lock_bit_in_place), slow_case);
+    }
+
+#ifdef AARCH64
+    __ ands(Rtemp, Rtemp, (uintx)markOopDesc::hash_mask_in_place);
+    __ b(slow_case, eq);
+    __ logical_shift_right(R0, Rtemp, markOopDesc::hash_shift);
+    __ ret();
+#else
+    __ bics(Rtemp, Rtemp, ~markOopDesc::hash_mask_in_place);
+    __ mov(R0, AsmOperand(Rtemp, lsr, markOopDesc::hash_shift), ne);
+    __ bx(LR, ne);
+#endif // AARCH64
+
+    __ bind(slow_case);
+  }
+
+  // Bang stack pages
+  __ arm_stack_overflow_check(stack_size, Rtemp);
+
+  // Setup frame linkage
+  __ raw_push(FP, LR);
+  __ mov(FP, SP);
+  __ sub_slow(SP, SP, stack_size - 2*wordSize);
+
+  int frame_complete = __ pc() - start;
+
+  OopMapSet* oop_maps = new OopMapSet();
+  OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/);
+  const int extra_args = is_static ? 2 : 1;
+  int receiver_offset = -1;
+  int fp_regs_in_arguments = 0;
+
+  for (i = total_in_args; --i >= 0; ) {
+    switch (in_sig_bt[i]) {
+    case T_ARRAY:
+    case T_OBJECT: {
+      VMReg src = in_regs[i].first();
+      VMReg dst = out_regs[i + extra_args].first();
+      if (src->is_stack()) {
+        assert(dst->is_stack(), "must be");
+        assert(i != 0, "Incoming receiver is always in a register");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src)));
+        __ cmp(Rtemp, 0);
+#ifdef AARCH64
+        __ add(Rtemp, FP, reg2offset_in(src));
+        __ csel(Rtemp, ZR, Rtemp, eq);
+#else
+        __ add(Rtemp, FP, reg2offset_in(src), ne);
+#endif // AARCH64
+        __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+        int offset_in_older_frame = src->reg2stack() + SharedRuntime::out_preserve_stack_slots();
+        map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + stack_slots));
+      } else {
+        int offset = oop_handle_offset * VMRegImpl::stack_slot_size;
+        __ str(src->as_Register(), Address(SP, offset));
+        map->set_oop(VMRegImpl::stack2reg(oop_handle_offset));
+        if ((i == 0) && (!is_static)) {
+          receiver_offset = offset;
+        }
+        oop_handle_offset += VMRegImpl::slots_per_word;
+
+#ifdef AARCH64
+        __ cmp(src->as_Register(), 0);
+        __ add(Rtemp, SP, offset);
+        __ csel(dst->is_stack() ? Rtemp : dst->as_Register(), ZR, Rtemp, eq);
+        if (dst->is_stack()) {
+          __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+        }
+#else
+        if (dst->is_stack()) {
+          __ movs(Rtemp, src->as_Register());
+          __ add(Rtemp, SP, offset, ne);
+          __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+        } else {
+          __ movs(dst->as_Register(), src->as_Register());
+          __ add(dst->as_Register(), SP, offset, ne);
+        }
+#endif // AARCH64
+      }
+    }
+
+    case T_VOID:
+      break;
+
+#ifdef AARCH64
+    case T_FLOAT:
+    case T_DOUBLE: {
+      VMReg src = in_regs[i].first();
+      VMReg dst = out_regs[i + extra_args].first();
+      if (src->is_stack()) {
+        assert(dst->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+      } else {
+        assert(src->is_FloatRegister() && dst->is_FloatRegister(), "must be");
+        assert(src->as_FloatRegister() == dst->as_FloatRegister(), "must be");
+        fp_regs_in_arguments++;
+      }
+      break;
+    }
+#else // AARCH64
+
+#ifdef __SOFTFP__
+    case T_DOUBLE:
+#endif
+    case T_LONG: {
+      VMReg src_1 = in_regs[i].first();
+      VMReg src_2 = in_regs[i].second();
+      VMReg dst_1 = out_regs[i + extra_args].first();
+      VMReg dst_2 = out_regs[i + extra_args].second();
+#if (ALIGN_WIDE_ARGUMENTS == 0)
+      // C convention can mix a register and a stack slot for a
+      // 64-bits native argument.
+
+      // Note: following code should work independently of whether
+      // the Java calling convention follows C convention or whether
+      // it aligns 64-bit values.
+      if (dst_2->is_Register()) {
+        if (src_1->as_Register() != dst_1->as_Register()) {
+          assert(src_1->as_Register() != dst_2->as_Register() &&
+                 src_2->as_Register() != dst_2->as_Register(), "must be");
+          __ mov(dst_2->as_Register(), src_2->as_Register());
+          __ mov(dst_1->as_Register(), src_1->as_Register());
+        } else {
+          assert(src_2->as_Register() == dst_2->as_Register(), "must be");
+        }
+      } else if (src_2->is_Register()) {
+        if (dst_1->is_Register()) {
+          // dst mixes a register and a stack slot
+          assert(dst_2->is_stack() && src_1->is_Register() && src_2->is_Register(), "must be");
+          assert(src_1->as_Register() != dst_1->as_Register(), "must be");
+          __ str(src_2->as_Register(), Address(SP, reg2offset_out(dst_2)));
+          __ mov(dst_1->as_Register(), src_1->as_Register());
+        } else {
+          // registers to stack slots
+          assert(dst_2->is_stack() && src_1->is_Register() && src_2->is_Register(), "must be");
+          __ str(src_1->as_Register(), Address(SP, reg2offset_out(dst_1)));
+          __ str(src_2->as_Register(), Address(SP, reg2offset_out(dst_2)));
+        }
+      } else if (src_1->is_Register()) {
+        if (dst_1->is_Register()) {
+          // src and dst must be R3 + stack slot
+          assert(dst_1->as_Register() == src_1->as_Register(), "must be");
+          __ ldr(Rtemp,    Address(FP, reg2offset_in(src_2)));
+          __ str(Rtemp,    Address(SP, reg2offset_out(dst_2)));
+        } else {
+          // <R3,stack> -> <stack,stack>
+          assert(dst_2->is_stack() && src_2->is_stack(), "must be");
+          __ ldr(LR, Address(FP, reg2offset_in(src_2)));
+          __ str(src_1->as_Register(), Address(SP, reg2offset_out(dst_1)));
+          __ str(LR, Address(SP, reg2offset_out(dst_2)));
+        }
+      } else {
+        assert(src_2->is_stack() && dst_1->is_stack() && dst_2->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src_1)));
+        __ ldr(LR,    Address(FP, reg2offset_in(src_2)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst_1)));
+        __ str(LR,    Address(SP, reg2offset_out(dst_2)));
+      }
+#else // ALIGN_WIDE_ARGUMENTS
+      if (src_1->is_stack()) {
+        assert(src_2->is_stack() && dst_1->is_stack() && dst_2->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src_1)));
+        __ ldr(LR,    Address(FP, reg2offset_in(src_2)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst_1)));
+        __ str(LR,    Address(SP, reg2offset_out(dst_2)));
+      } else if (dst_1->is_stack()) {
+        assert(dst_2->is_stack() && src_1->is_Register() && src_2->is_Register(), "must be");
+        __ str(src_1->as_Register(), Address(SP, reg2offset_out(dst_1)));
+        __ str(src_2->as_Register(), Address(SP, reg2offset_out(dst_2)));
+      } else if (src_1->as_Register() == dst_1->as_Register()) {
+        assert(src_2->as_Register() == dst_2->as_Register(), "must be");
+      } else {
+        assert(src_1->as_Register() != dst_2->as_Register() &&
+               src_2->as_Register() != dst_2->as_Register(), "must be");
+        __ mov(dst_2->as_Register(), src_2->as_Register());
+        __ mov(dst_1->as_Register(), src_1->as_Register());
+      }
+#endif // ALIGN_WIDE_ARGUMENTS
+      break;
+    }
+
+#if (!defined __SOFTFP__ && !defined __ABI_HARD__)
+    case T_FLOAT: {
+      VMReg src = in_regs[i].first();
+      VMReg dst = out_regs[i + extra_args].first();
+      if (src->is_stack()) {
+        assert(dst->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+      } else if (dst->is_stack()) {
+        __ fsts(src->as_FloatRegister(), Address(SP, reg2offset_out(dst)));
+      } else {
+        assert(src->is_FloatRegister() && dst->is_Register(), "must be");
+        __ fmrs(dst->as_Register(), src->as_FloatRegister());
+      }
+      break;
+    }
+
+    case T_DOUBLE: {
+      VMReg src_1 = in_regs[i].first();
+      VMReg src_2 = in_regs[i].second();
+      VMReg dst_1 = out_regs[i + extra_args].first();
+      VMReg dst_2 = out_regs[i + extra_args].second();
+      if (src_1->is_stack()) {
+        assert(src_2->is_stack() && dst_1->is_stack() && dst_2->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src_1)));
+        __ ldr(LR,    Address(FP, reg2offset_in(src_2)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst_1)));
+        __ str(LR,    Address(SP, reg2offset_out(dst_2)));
+      } else if (dst_1->is_stack()) {
+        assert(dst_2->is_stack() && src_1->is_FloatRegister(), "must be");
+        __ fstd(src_1->as_FloatRegister(), Address(SP, reg2offset_out(dst_1)));
+#if (ALIGN_WIDE_ARGUMENTS == 0)
+      } else if (dst_2->is_stack()) {
+        assert(! src_2->is_stack(), "must be"); // assuming internal java convention is aligned
+        // double register must go into R3 + one stack slot
+        __ fmrrd(dst_1->as_Register(), Rtemp, src_1->as_FloatRegister());
+        __ str(Rtemp, Address(SP, reg2offset_out(dst_2)));
+#endif
+      } else {
+        assert(src_1->is_FloatRegister() && dst_1->is_Register() && dst_2->is_Register(), "must be");
+        __ fmrrd(dst_1->as_Register(), dst_2->as_Register(), src_1->as_FloatRegister());
+      }
+      break;
+    }
+#endif // __SOFTFP__
+
+#ifdef __ABI_HARD__
+    case T_FLOAT: {
+      VMReg src = in_regs[i].first();
+      VMReg dst = out_regs[i + extra_args].first();
+      if (src->is_stack()) {
+        if (dst->is_stack()) {
+          __ ldr(Rtemp, Address(FP, reg2offset_in(src)));
+          __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+        } else {
+          // C2 Java calling convention does not populate S14 and S15, therefore
+          // those need to be loaded from stack here
+          __ flds(dst->as_FloatRegister(), Address(FP, reg2offset_in(src)));
+          fp_regs_in_arguments++;
+        }
+      } else {
+        assert(src->is_FloatRegister(), "must be");
+        fp_regs_in_arguments++;
+      }
+      break;
+    }
+    case T_DOUBLE: {
+      VMReg src_1 = in_regs[i].first();
+      VMReg src_2 = in_regs[i].second();
+      VMReg dst_1 = out_regs[i + extra_args].first();
+      VMReg dst_2 = out_regs[i + extra_args].second();
+      if (src_1->is_stack()) {
+        if (dst_1->is_stack()) {
+          assert(dst_2->is_stack(), "must be");
+          __ ldr(Rtemp, Address(FP, reg2offset_in(src_1)));
+          __ ldr(LR,    Address(FP, reg2offset_in(src_2)));
+          __ str(Rtemp, Address(SP, reg2offset_out(dst_1)));
+          __ str(LR,    Address(SP, reg2offset_out(dst_2)));
+        } else {
+          // C2 Java calling convention does not populate S14 and S15, therefore
+          // those need to be loaded from stack here
+          __ fldd(dst_1->as_FloatRegister(), Address(FP, reg2offset_in(src_1)));
+          fp_regs_in_arguments += 2;
+        }
+      } else {
+        assert(src_1->is_FloatRegister() && src_2->is_FloatRegister(), "must be");
+        fp_regs_in_arguments += 2;
+      }
+      break;
+    }
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+    default: {
+      assert(in_sig_bt[i] != T_ADDRESS, "found T_ADDRESS in java args");
+      VMReg src = in_regs[i].first();
+      VMReg dst = out_regs[i + extra_args].first();
+      if (src->is_stack()) {
+        assert(dst->is_stack(), "must be");
+        __ ldr(Rtemp, Address(FP, reg2offset_in(src)));
+        __ str(Rtemp, Address(SP, reg2offset_out(dst)));
+      } else if (dst->is_stack()) {
+        __ str(src->as_Register(), Address(SP, reg2offset_out(dst)));
+      } else {
+        assert(src->is_Register() && dst->is_Register(), "must be");
+        __ mov(dst->as_Register(), src->as_Register());
+      }
+    }
+    }
+  }
+
+  // Get Klass mirror
+  int klass_offset = -1;
+  if (is_static) {
+    klass_offset = oop_handle_offset * VMRegImpl::stack_slot_size;
+    __ mov_oop(Rtemp, JNIHandles::make_local(method->method_holder()->java_mirror()));
+    __ add(c_rarg1, SP, klass_offset);
+    __ str(Rtemp, Address(SP, klass_offset));
+    map->set_oop(VMRegImpl::stack2reg(oop_handle_offset));
+  }
+
+  // the PC offset given to add_gc_map must match the PC saved in set_last_Java_frame
+  int pc_offset = __ set_last_Java_frame(SP, FP, true, Rtemp);
+  assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+  oop_maps->add_gc_map(pc_offset, map);
+
+#ifndef AARCH64
+  // Order last_Java_pc store with the thread state transition (to _thread_in_native)
+  __ membar(MacroAssembler::StoreStore, Rtemp);
+#endif // !AARCH64
+
+  // RedefineClasses() tracing support for obsolete method entry
+  if (log_is_enabled(Trace, redefine, class, obsolete)) {
+#ifdef AARCH64
+    __ NOT_TESTED();
+#endif
+    __ save_caller_save_registers();
+    __ mov(R0, Rthread);
+    __ mov_metadata(R1, method());
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), R0, R1);
+    __ restore_caller_save_registers();
+  }
+
+  const Register sync_handle = AARCH64_ONLY(R20) NOT_AARCH64(R5);
+  const Register sync_obj    = AARCH64_ONLY(R21) NOT_AARCH64(R6);
+  const Register disp_hdr    = AARCH64_ONLY(R22) NOT_AARCH64(altFP_7_11);
+  const Register tmp         = AARCH64_ONLY(R23) NOT_AARCH64(R8);
+
+  Label slow_lock, slow_lock_biased, lock_done, fast_lock, leave;
+  if (method->is_synchronized()) {
+    // The first argument is a handle to sync object (a class or an instance)
+    __ ldr(sync_obj, Address(R1));
+    // Remember the handle for the unlocking code
+    __ mov(sync_handle, R1);
+
+    if(UseBiasedLocking) {
+      __ biased_locking_enter(sync_obj, tmp, disp_hdr/*scratched*/, false, Rtemp, lock_done, slow_lock_biased);
+    }
+
+    const Register mark = tmp;
+#ifdef AARCH64
+    __ sub(disp_hdr, FP, lock_slot_fp_offset);
+    assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
+
+    __ ldr(mark, sync_obj);
+
+    // Test if object is already locked
+    assert(markOopDesc::unlocked_value == 1, "adjust this code");
+    __ tbnz(mark, exact_log2(markOopDesc::unlocked_value), fast_lock);
+
+    // Check for recursive lock
+    // See comments in InterpreterMacroAssembler::lock_object for
+    // explanations on the fast recursive locking check.
+    __ mov(Rtemp, SP);
+    __ sub(Rtemp, mark, Rtemp);
+    intptr_t mask = ((intptr_t)3) - ((intptr_t)os::vm_page_size());
+    Assembler::LogicalImmediate imm(mask, false);
+    __ ands(Rtemp, Rtemp, imm);
+    __ b(slow_lock, ne);
+
+    // Recursive locking: store 0 into a lock record
+    __ str(ZR, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
+    __ b(lock_done);
+
+    __ bind(fast_lock);
+    __ str(mark, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
+
+    __ cas_for_lock_acquire(mark, disp_hdr, sync_obj, Rtemp, slow_lock);
+#else
+    // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
+    // That would be acceptable as either CAS or slow case path is taken in that case
+
+    __ ldr(mark, Address(sync_obj, oopDesc::mark_offset_in_bytes()));
+    __ sub(disp_hdr, FP, lock_slot_fp_offset);
+    __ tst(mark, markOopDesc::unlocked_value);
+    __ b(fast_lock, ne);
+
+    // Check for recursive lock
+    // See comments in InterpreterMacroAssembler::lock_object for
+    // explanations on the fast recursive locking check.
+    // Check independently the low bits and the distance to SP
+    // -1- test low 2 bits
+    __ movs(Rtemp, AsmOperand(mark, lsl, 30));
+    // -2- test (hdr - SP) if the low two bits are 0
+    __ sub(Rtemp, mark, SP, eq);
+    __ movs(Rtemp, AsmOperand(Rtemp, lsr, exact_log2(os::vm_page_size())), eq);
+    // If still 'eq' then recursive locking OK: set displaced header to 0
+    __ str(Rtemp, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()), eq);
+    __ b(lock_done, eq);
+    __ b(slow_lock);
+
+    __ bind(fast_lock);
+    __ str(mark, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
+
+    __ cas_for_lock_acquire(mark, disp_hdr, sync_obj, Rtemp, slow_lock);
+#endif // AARCH64
+
+    __ bind(lock_done);
+  }
+
+  // Get JNIEnv*
+  __ add(c_rarg0, Rthread, in_bytes(JavaThread::jni_environment_offset()));
+
+  // Perform thread state transition
+  __ mov(Rtemp, _thread_in_native);
+#ifdef AARCH64
+  // stlr instruction is used to force all preceding writes to be observed prior to thread state change
+  __ add(Rtemp2, Rthread, in_bytes(JavaThread::thread_state_offset()));
+  __ stlr_w(Rtemp, Rtemp2);
+#else
+  __ str(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+#endif // AARCH64
+
+  // Finally, call the native method
+  __ call(method->native_function());
+
+  // Set FPSCR/FPCR to a known state
+  if (AlwaysRestoreFPU) {
+    __ restore_default_fp_mode();
+  }
+
+  // Do a safepoint check while thread is in transition state
+  InlinedAddress safepoint_state(SafepointSynchronize::address_of_state());
+  Label call_safepoint_runtime, return_to_java;
+  __ mov(Rtemp, _thread_in_native_trans);
+  __ ldr_literal(R2, safepoint_state);
+  __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+
+  // make sure the store is observed before reading the SafepointSynchronize state and further mem refs
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad | MacroAssembler::StoreStore), Rtemp);
+
+  __ ldr_s32(R2, Address(R2));
+  __ ldr_u32(R3, Address(Rthread, JavaThread::suspend_flags_offset()));
+  __ cmp(R2, SafepointSynchronize::_not_synchronized);
+  __ cond_cmp(R3, 0, eq);
+  __ b(call_safepoint_runtime, ne);
+  __ bind(return_to_java);
+
+  // Perform thread state transition and reguard stack yellow pages if needed
+  Label reguard, reguard_done;
+  __ mov(Rtemp, _thread_in_Java);
+  __ ldr_s32(R2, Address(Rthread, JavaThread::stack_guard_state_offset()));
+  __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+
+  __ cmp(R2, JavaThread::stack_guard_yellow_reserved_disabled);
+  __ b(reguard, eq);
+  __ bind(reguard_done);
+
+  Label slow_unlock, unlock_done, retry;
+  if (method->is_synchronized()) {
+    __ ldr(sync_obj, Address(sync_handle));
+
+    if(UseBiasedLocking) {
+      __ biased_locking_exit(sync_obj, Rtemp, unlock_done);
+      // disp_hdr may not have been saved on entry with biased locking
+      __ sub(disp_hdr, FP, lock_slot_fp_offset);
+    }
+
+    // See C1_MacroAssembler::unlock_object() for more comments
+    __ ldr(R2, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
+    __ cbz(R2, unlock_done);
+
+    __ cas_for_lock_release(disp_hdr, R2, sync_obj, Rtemp, slow_unlock);
+
+    __ bind(unlock_done);
+  }
+
+  // Set last java frame and handle block to zero
+  __ ldr(LR, Address(Rthread, JavaThread::active_handles_offset()));
+  __ reset_last_Java_frame(Rtemp); // sets Rtemp to 0 on 32-bit ARM
+
+#ifdef AARCH64
+  __ str_32(ZR, Address(LR, JNIHandleBlock::top_offset_in_bytes()));
+  if (CheckJNICalls) {
+    __ str(ZR, Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
+  }
+
+
+  switch (ret_type) {
+  case T_BOOLEAN:
+    __ tst(R0, 0xff);
+    __ cset(R0, ne);
+    break;
+  case T_CHAR   : __ zero_extend(R0, R0, 16);  break;
+  case T_BYTE   : __ sign_extend(R0, R0,  8);  break;
+  case T_SHORT  : __ sign_extend(R0, R0, 16);  break;
+  case T_INT    : // fall through
+  case T_LONG   : // fall through
+  case T_VOID   : // fall through
+  case T_FLOAT  : // fall through
+  case T_DOUBLE : /* nothing to do */          break;
+  case T_OBJECT : // fall through
+  case T_ARRAY  : {
+    Label L;
+    __ cbz(R0, L);
+    __ ldr(R0, Address(R0));
+    __ verify_oop(R0);
+    __ bind(L);
+    break;
+  }
+  default:
+    ShouldNotReachHere();
+  }
+#else
+  __ str_32(Rtemp, Address(LR, JNIHandleBlock::top_offset_in_bytes()));
+  if (CheckJNICalls) {
+    __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
+  }
+
+  // Unhandle the result
+  if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
+    __ cmp(R0, 0);
+    __ ldr(R0, Address(R0), ne);
+  }
+#endif // AARCH64
+
+  // Any exception pending?
+  __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
+  __ mov(SP, FP);
+
+#ifdef AARCH64
+  Label except;
+  __ cbnz(Rtemp, except);
+  __ raw_pop(FP, LR);
+  __ ret();
+
+  __ bind(except);
+  // Pop the frame and forward the exception. Rexception_pc contains return address.
+  __ raw_pop(FP, Rexception_pc);
+#else
+  __ cmp(Rtemp, 0);
+  // Pop the frame and return if no exception pending
+  __ pop(RegisterSet(FP) | RegisterSet(PC), eq);
+  // Pop the frame and forward the exception. Rexception_pc contains return address.
+  __ ldr(FP, Address(SP, wordSize, post_indexed), ne);
+  __ ldr(Rexception_pc, Address(SP, wordSize, post_indexed), ne);
+#endif // AARCH64
+  __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+
+  // Safepoint operation and/or pending suspend request is in progress.
+  // Save the return values and call the runtime function by hand.
+  __ bind(call_safepoint_runtime);
+  push_result_registers(masm, ret_type);
+  __ mov(R0, Rthread);
+  __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans));
+  pop_result_registers(masm, ret_type);
+  __ b(return_to_java);
+
+  __ bind_literal(safepoint_state);
+
+  // Reguard stack pages. Save native results around a call to C runtime.
+  __ bind(reguard);
+  push_result_registers(masm, ret_type);
+  __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages));
+  pop_result_registers(masm, ret_type);
+  __ b(reguard_done);
+
+  if (method->is_synchronized()) {
+    // Locking slow case
+    if(UseBiasedLocking) {
+      __ bind(slow_lock_biased);
+      __ sub(disp_hdr, FP, lock_slot_fp_offset);
+    }
+
+    __ bind(slow_lock);
+
+    push_param_registers(masm, fp_regs_in_arguments);
+
+    // last_Java_frame is already set, so do call_VM manually; no exception can occur
+    __ mov(R0, sync_obj);
+    __ mov(R1, disp_hdr);
+    __ mov(R2, Rthread);
+    __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C));
+
+    pop_param_registers(masm, fp_regs_in_arguments);
+
+    __ b(lock_done);
+
+    // Unlocking slow case
+    __ bind(slow_unlock);
+
+    push_result_registers(masm, ret_type);
+
+    // Clear pending exception before reentering VM.
+    // Can store the oop in register since it is a leaf call.
+    assert_different_registers(Rtmp_save1, sync_obj, disp_hdr);
+    __ ldr(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
+    Register zero = __ zero_register(Rtemp);
+    __ str(zero, Address(Rthread, Thread::pending_exception_offset()));
+    __ mov(R0, sync_obj);
+    __ mov(R1, disp_hdr);
+    __ mov(R2, Rthread);
+    __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C));
+    __ str(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset()));
+
+    pop_result_registers(masm, ret_type);
+
+    __ b(unlock_done);
+  }
+
+  __ flush();
+  return nmethod::new_native_nmethod(method,
+                                     compile_id,
+                                     masm->code(),
+                                     vep_offset,
+                                     frame_complete,
+                                     stack_slots / VMRegImpl::slots_per_word,
+                                     in_ByteSize(is_static ? klass_offset : receiver_offset),
+                                     in_ByteSize(lock_slot_offset * VMRegImpl::stack_slot_size),
+                                     oop_maps);
+}
+
+// this function returns the adjust size (in number of words) to a c2i adapter
+// activation for use during deoptimization
+int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) {
+  int extra_locals_size = (callee_locals - callee_parameters) * Interpreter::stackElementWords;
+#ifdef AARCH64
+  extra_locals_size = round_to(extra_locals_size, StackAlignmentInBytes/BytesPerWord);
+#endif // AARCH64
+  return extra_locals_size;
+}
+
+
+uint SharedRuntime::out_preserve_stack_slots() {
+  return 0;
+}
+
+
+//------------------------------generate_deopt_blob----------------------------
+void SharedRuntime::generate_deopt_blob() {
+  ResourceMark rm;
+#ifdef AARCH64
+  CodeBuffer buffer("deopt_blob", 1024+256, 1);
+#else
+  CodeBuffer buffer("deopt_blob", 1024, 1024);
+#endif
+  int frame_size_in_words;
+  OopMapSet* oop_maps;
+  int reexecute_offset;
+  int exception_in_tls_offset;
+  int exception_offset;
+
+  MacroAssembler* masm = new MacroAssembler(&buffer);
+  Label cont;
+  const Register Rkind   = AARCH64_ONLY(R21) NOT_AARCH64(R9); // caller-saved on 32bit
+  const Register Rublock = AARCH64_ONLY(R22) NOT_AARCH64(R6);
+  const Register Rsender = AARCH64_ONLY(R23) NOT_AARCH64(altFP_7_11);
+  assert_different_registers(Rkind, Rublock, Rsender, Rexception_obj, Rexception_pc, R0, R1, R2, R3, R8, Rtemp);
+
+  address start = __ pc();
+
+  oop_maps = new OopMapSet();
+  // LR saved by caller (can be live in c2 method)
+
+  // A deopt is a case where LR may be live in the c2 nmethod. So it's
+  // not possible to call the deopt blob from the nmethod and pass the
+  // address of the deopt handler of the nmethod in LR. What happens
+  // now is that the caller of the deopt blob pushes the current
+  // address so the deopt blob doesn't have to do it. This way LR can
+  // be preserved, contains the live value from the nmethod and is
+  // saved at R14/R30_offset here.
+  OopMap* map = RegisterSaver::save_live_registers(masm, &frame_size_in_words, true);
+  __ mov(Rkind, Deoptimization::Unpack_deopt);
+  __ b(cont);
+
+  exception_offset = __ pc() - start;
+
+  // Transfer Rexception_obj & Rexception_pc in TLS and fall thru to the
+  // exception_in_tls_offset entry point.
+  __ str(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ str(Rexception_pc, Address(Rthread, JavaThread::exception_pc_offset()));
+  // Force return value to NULL to avoid confusing the escape analysis
+  // logic. Everything is dead here anyway.
+  __ mov(R0, 0);
+
+  exception_in_tls_offset = __ pc() - start;
+
+  // Exception data is in JavaThread structure
+  // Patch the return address of the current frame
+  __ ldr(LR, Address(Rthread, JavaThread::exception_pc_offset()));
+  (void) RegisterSaver::save_live_registers(masm, &frame_size_in_words);
+  {
+    const Register Rzero = __ zero_register(Rtemp); // XXX should be OK for C2 but not 100% sure
+    __ str(Rzero, Address(Rthread, JavaThread::exception_pc_offset()));
+  }
+  __ mov(Rkind, Deoptimization::Unpack_exception);
+  __ b(cont);
+
+  reexecute_offset = __ pc() - start;
+
+  (void) RegisterSaver::save_live_registers(masm, &frame_size_in_words);
+  __ mov(Rkind, Deoptimization::Unpack_reexecute);
+
+  // Calculate UnrollBlock and save the result in Rublock
+  __ bind(cont);
+  __ mov(R0, Rthread);
+  __ mov(R1, Rkind);
+
+  int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); // note: FP may not need to be saved (not on x86)
+  assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+  __ call(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info));
+  if (pc_offset == -1) {
+    pc_offset = __ offset();
+  }
+  oop_maps->add_gc_map(pc_offset, map);
+  __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+  __ mov(Rublock, R0);
+
+  // Reload Rkind from the UnrollBlock (might have changed)
+  __ ldr_s32(Rkind, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()));
+  Label noException;
+  __ cmp_32(Rkind, Deoptimization::Unpack_exception);   // Was exception pending?
+  __ b(noException, ne);
+  // handle exception case
+#ifdef ASSERT
+  // assert that exception_pc is zero in tls
+  { Label L;
+    __ ldr(Rexception_pc, Address(Rthread, JavaThread::exception_pc_offset()));
+    __ cbz(Rexception_pc, L);
+    __ stop("exception pc should be null");
+    __ bind(L);
+  }
+#endif
+  __ ldr(Rexception_obj, Address(Rthread, JavaThread::exception_oop_offset()));
+  __ verify_oop(Rexception_obj);
+  {
+    const Register Rzero = __ zero_register(Rtemp);
+    __ str(Rzero, Address(Rthread, JavaThread::exception_oop_offset()));
+  }
+
+  __ bind(noException);
+
+  // This frame is going away.  Fetch return value, so we can move it to
+  // a new frame.
+  __ ldr(R0, Address(SP, RegisterSaver::R0_offset * wordSize));
+#ifndef AARCH64
+  __ ldr(R1, Address(SP, RegisterSaver::R1_offset * wordSize));
+#endif // !AARCH64
+#ifndef __SOFTFP__
+  __ ldr_double(D0, Address(SP, RegisterSaver::D0_offset * wordSize));
+#endif
+  // pop frame
+  __ add(SP, SP, RegisterSaver::reg_save_size * wordSize);
+
+  // Set initial stack state before pushing interpreter frames
+  __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes()));
+  __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes()));
+  __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes()));
+
+#ifdef AARCH64
+  // Pop deoptimized frame. Make sure to restore the initial saved FP/LR of the caller.
+  // They are needed for correct stack walking during stack overflow handling.
+  // Also, restored FP is saved in the bottom interpreter frame (LR is reloaded from unroll block).
+  __ sub(Rtemp, Rtemp, 2*wordSize);
+  __ add(SP, SP, Rtemp, ex_uxtx);
+  __ raw_pop(FP, LR);
+
+#ifdef ASSERT
+  { Label L;
+    __ ldr(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+    __ cmp(FP, Rtemp);
+    __ b(L, eq);
+    __ stop("FP restored from deoptimized frame does not match FP stored in unroll block");
+    __ bind(L);
+  }
+  { Label L;
+    __ ldr(Rtemp, Address(R2));
+    __ cmp(LR, Rtemp);
+    __ b(L, eq);
+    __ stop("LR restored from deoptimized frame does not match the 1st PC in unroll block");
+    __ bind(L);
+  }
+#endif // ASSERT
+
+#else
+  __ add(SP, SP, Rtemp);
+#endif // AARCH64
+
+#ifdef ASSERT
+  // Compilers generate code that bang the stack by as much as the
+  // interpreter would need. So this stack banging should never
+  // trigger a fault. Verify that it does not on non product builds.
+  // See if it is enough stack to push deoptimized frames
+  if (UseStackBanging) {
+#ifndef AARCH64
+    // The compiled method that we are deoptimizing was popped from the stack.
+    // If the stack bang results in a stack overflow, we don't return to the
+    // method that is being deoptimized. The stack overflow exception is
+    // propagated to the caller of the deoptimized method. Need to get the pc
+    // from the caller in LR and restore FP.
+    __ ldr(LR, Address(R2, 0));
+    __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+#endif // !AARCH64
+    __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes()));
+    __ arm_stack_overflow_check(R8, Rtemp);
+  }
+#endif
+  __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes()));
+
+#ifndef AARCH64
+  // Pick up the initial fp we should save
+  // XXX Note: was ldr(FP, Address(FP));
+
+  // The compiler no longer uses FP as a frame pointer for the
+  // compiled code. It can be used by the allocator in C2 or to
+  // memorize the original SP for JSR292 call sites.
+
+  // Hence, ldr(FP, Address(FP)) is probably not correct. For x86,
+  // Deoptimization::fetch_unroll_info computes the right FP value and
+  // stores it in Rublock.initial_info. This has been activated for ARM.
+  __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+#endif // !AARCH64
+
+  __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset_in_bytes()));
+  __ mov(Rsender, SP);
+#ifdef AARCH64
+  __ sub(SP, SP, Rtemp, ex_uxtx);
+#else
+  __ sub(SP, SP, Rtemp);
+#endif // AARCH64
+
+  // Push interpreter frames in a loop
+  Label loop;
+  __ bind(loop);
+  __ ldr(LR, Address(R2, wordSize, post_indexed));         // load frame pc
+  __ ldr(Rtemp, Address(R3, wordSize, post_indexed));      // load frame size
+
+  __ raw_push(FP, LR);                                     // create new frame
+  __ mov(FP, SP);
+  __ sub(Rtemp, Rtemp, 2*wordSize);
+
+#ifdef AARCH64
+  __ sub(SP, SP, Rtemp, ex_uxtx);
+#else
+  __ sub(SP, SP, Rtemp);
+#endif // AARCH64
+
+  __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+#ifdef AARCH64
+  __ str(ZR, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize));
+#else
+  __ mov(LR, 0);
+  __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ subs(R8, R8, 1);                               // decrement counter
+  __ mov(Rsender, SP);
+  __ b(loop, ne);
+
+  // Re-push self-frame
+  __ ldr(LR, Address(R2));
+  __ raw_push(FP, LR);
+  __ mov(FP, SP);
+  __ sub(SP, SP, (frame_size_in_words - 2) * wordSize);
+
+  // Restore frame locals after moving the frame
+  __ str(R0, Address(SP, RegisterSaver::R0_offset * wordSize));
+#ifndef AARCH64
+  __ str(R1, Address(SP, RegisterSaver::R1_offset * wordSize));
+#endif // !AARCH64
+
+#ifndef __SOFTFP__
+  __ str_double(D0, Address(SP, RegisterSaver::D0_offset * wordSize));
+#endif // !__SOFTFP__
+
+#ifndef AARCH64
+#ifdef ASSERT
+  // Reload Rkind from the UnrollBlock and check that it was not overwritten (Rkind is not callee-saved)
+  { Label L;
+    __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()));
+    __ cmp_32(Rkind, Rtemp);
+    __ b(L, eq);
+    __ stop("Rkind was overwritten");
+    __ bind(L);
+  }
+#endif
+#endif
+
+  // Call unpack_frames with proper arguments
+  __ mov(R0, Rthread);
+  __ mov(R1, Rkind);
+
+  pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
+  assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+  __ call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
+  if (pc_offset == -1) {
+    pc_offset = __ offset();
+  }
+  oop_maps->add_gc_map(pc_offset, new OopMap(frame_size_in_words * VMRegImpl::slots_per_word, 0));
+  __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+  // Collect return values, pop self-frame and jump to interpreter
+  __ ldr(R0, Address(SP, RegisterSaver::R0_offset * wordSize));
+#ifndef AARCH64
+  __ ldr(R1, Address(SP, RegisterSaver::R1_offset * wordSize));
+#endif // !AARCH64
+  // Interpreter floats controlled by __SOFTFP__, but compiler
+  // float return value registers controlled by __ABI_HARD__
+  // This matters for vfp-sflt builds.
+#ifndef __SOFTFP__
+  // Interpreter hard float
+#ifdef __ABI_HARD__
+  // Compiler float return value in FP registers
+  __ ldr_double(D0, Address(SP, RegisterSaver::D0_offset * wordSize));
+#else
+  // Compiler float return value in integer registers,
+  // copy to D0 for interpreter (S0 <-- R0)
+  __ fmdrr(D0_tos, R0, R1);
+#endif
+#endif // !__SOFTFP__
+  __ mov(SP, FP);
+
+#ifdef AARCH64
+  __ raw_pop(FP, LR);
+  __ ret();
+#else
+  __ pop(RegisterSet(FP) | RegisterSet(PC));
+#endif // AARCH64
+
+  __ flush();
+
+  _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset,
+                                           reexecute_offset, frame_size_in_words);
+  _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
+}
+
+#ifdef COMPILER2
+
+//------------------------------generate_uncommon_trap_blob--------------------
+// Ought to generate an ideal graph & compile, but here's some SPARC ASM
+// instead.
+void SharedRuntime::generate_uncommon_trap_blob() {
+  // allocate space for the code
+  ResourceMark rm;
+
+  // setup code generation tools
+  int pad = VerifyThread ? 512 : 0;
+#ifdef _LP64
+  CodeBuffer buffer("uncommon_trap_blob", 2700+pad, 512);
+#else
+  // Measured 8/7/03 at 660 in 32bit debug build (no VerifyThread)
+  // Measured 8/7/03 at 1028 in 32bit debug build (VerifyThread)
+  CodeBuffer buffer("uncommon_trap_blob", 2000+pad, 512);
+#endif
+  // bypassed when code generation useless
+  MacroAssembler* masm               = new MacroAssembler(&buffer);
+  const Register Rublock = AARCH64_ONLY(R22) NOT_AARCH64(R6);
+  const Register Rsender = AARCH64_ONLY(R23) NOT_AARCH64(altFP_7_11);
+  assert_different_registers(Rublock, Rsender, Rexception_obj, R0, R1, R2, R3, R8, Rtemp);
+
+  //
+  // This is the entry point for all traps the compiler takes when it thinks
+  // it cannot handle further execution of compilation code. The frame is
+  // deoptimized in these cases and converted into interpreter frames for
+  // execution
+  // The steps taken by this frame are as follows:
+  //   - push a fake "unpack_frame"
+  //   - call the C routine Deoptimization::uncommon_trap (this function
+  //     packs the current compiled frame into vframe arrays and returns
+  //     information about the number and size of interpreter frames which
+  //     are equivalent to the frame which is being deoptimized)
+  //   - deallocate the "unpack_frame"
+  //   - deallocate the deoptimization frame
+  //   - in a loop using the information returned in the previous step
+  //     push interpreter frames;
+  //   - create a dummy "unpack_frame"
+  //   - call the C routine: Deoptimization::unpack_frames (this function
+  //     lays out values on the interpreter frame which was just created)
+  //   - deallocate the dummy unpack_frame
+  //   - return to the interpreter entry point
+  //
+  //  Refer to the following methods for more information:
+  //   - Deoptimization::uncommon_trap
+  //   - Deoptimization::unpack_frame
+
+  // the unloaded class index is in R0 (first parameter to this blob)
+
+  __ raw_push(FP, LR);
+  __ set_last_Java_frame(SP, FP, false, Rtemp);
+  __ mov(R2, Deoptimization::Unpack_uncommon_trap);
+  __ mov(R1, R0);
+  __ mov(R0, Rthread);
+  __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
+  __ mov(Rublock, R0);
+  __ reset_last_Java_frame(Rtemp);
+  __ raw_pop(FP, LR);
+
+#ifdef ASSERT
+  { Label L;
+    __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()));
+    __ cmp_32(Rtemp, Deoptimization::Unpack_uncommon_trap);
+    __ b(L, eq);
+    __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+    __ bind(L);
+  }
+#endif
+
+
+  // Set initial stack state before pushing interpreter frames
+  __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes()));
+  __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes()));
+  __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes()));
+
+#ifdef AARCH64
+  // Pop deoptimized frame. Make sure to restore the initial saved FP/LR of the caller.
+  // They are needed for correct stack walking during stack overflow handling.
+  // Also, restored FP is saved in the bottom interpreter frame (LR is reloaded from unroll block).
+  __ sub(Rtemp, Rtemp, 2*wordSize);
+  __ add(SP, SP, Rtemp, ex_uxtx);
+  __ raw_pop(FP, LR);
+
+#ifdef ASSERT
+  { Label L;
+    __ ldr(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+    __ cmp(FP, Rtemp);
+    __ b(L, eq);
+    __ stop("FP restored from deoptimized frame does not match FP stored in unroll block");
+    __ bind(L);
+  }
+  { Label L;
+    __ ldr(Rtemp, Address(R2));
+    __ cmp(LR, Rtemp);
+    __ b(L, eq);
+    __ stop("LR restored from deoptimized frame does not match the 1st PC in unroll block");
+    __ bind(L);
+  }
+#endif // ASSERT
+
+#else
+  __ add(SP, SP, Rtemp);
+#endif //AARCH64
+
+  // See if it is enough stack to push deoptimized frames
+#ifdef ASSERT
+  // Compilers generate code that bang the stack by as much as the
+  // interpreter would need. So this stack banging should never
+  // trigger a fault. Verify that it does not on non product builds.
+  if (UseStackBanging) {
+#ifndef AARCH64
+    // The compiled method that we are deoptimizing was popped from the stack.
+    // If the stack bang results in a stack overflow, we don't return to the
+    // method that is being deoptimized. The stack overflow exception is
+    // propagated to the caller of the deoptimized method. Need to get the pc
+    // from the caller in LR and restore FP.
+    __ ldr(LR, Address(R2, 0));
+    __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+#endif // !AARCH64
+    __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes()));
+    __ arm_stack_overflow_check(R8, Rtemp);
+  }
+#endif
+  __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes()));
+  __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset_in_bytes()));
+  __ mov(Rsender, SP);
+#ifdef AARCH64
+  __ sub(SP, SP, Rtemp, ex_uxtx);
+#else
+  __ sub(SP, SP, Rtemp);
+#endif
+#ifndef AARCH64
+  //  __ ldr(FP, Address(FP));
+  __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset_in_bytes()));
+#endif // AARCH64
+
+  // Push interpreter frames in a loop
+  Label loop;
+  __ bind(loop);
+  __ ldr(LR, Address(R2, wordSize, post_indexed));         // load frame pc
+  __ ldr(Rtemp, Address(R3, wordSize, post_indexed));      // load frame size
+
+  __ raw_push(FP, LR);                                     // create new frame
+  __ mov(FP, SP);
+  __ sub(Rtemp, Rtemp, 2*wordSize);
+
+#ifdef AARCH64
+  __ sub(SP, SP, Rtemp, ex_uxtx);
+#else
+  __ sub(SP, SP, Rtemp);
+#endif // AARCH64
+
+  __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+#ifdef AARCH64
+  __ str(ZR, Address(FP, frame::interpreter_frame_stack_top_offset * wordSize));
+#else
+  __ mov(LR, 0);
+  __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+  __ subs(R8, R8, 1);                               // decrement counter
+  __ mov(Rsender, SP);
+  __ b(loop, ne);
+
+  // Re-push self-frame
+  __ ldr(LR, Address(R2));
+  __ raw_push(FP, LR);
+  __ mov(FP, SP);
+
+  // Call unpack_frames with proper arguments
+  __ mov(R0, Rthread);
+  __ mov(R1, Deoptimization::Unpack_uncommon_trap);
+  __ set_last_Java_frame(SP, FP, false, Rtemp);
+  __ call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
+  //  oop_maps->add_gc_map(__ pc() - start, new OopMap(frame_size_in_words, 0));
+  __ reset_last_Java_frame(Rtemp);
+
+  __ mov(SP, FP);
+#ifdef AARCH64
+  __ raw_pop(FP, LR);
+  __ ret();
+#else
+  __ pop(RegisterSet(FP) | RegisterSet(PC));
+#endif
+
+  masm->flush();
+  _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, NULL, 2 /* LR+FP */);
+}
+
+#endif // COMPILER2
+
+//------------------------------generate_handler_blob------
+//
+// Generate a special Compile2Runtime blob that saves all registers,
+// setup oopmap, and calls safepoint code to stop the compiled code for
+// a safepoint.
+//
+SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+  assert(StubRoutines::forward_exception_entry() != NULL, "must be generated before");
+
+  ResourceMark rm;
+  CodeBuffer buffer("handler_blob", 256, 256);
+  int frame_size_words;
+  OopMapSet* oop_maps;
+
+  bool cause_return = (poll_type == POLL_AT_RETURN);
+
+  MacroAssembler* masm = new MacroAssembler(&buffer);
+  address start = __ pc();
+  oop_maps = new OopMapSet();
+
+  if (!cause_return) {
+#ifdef AARCH64
+    __ raw_push(LR, LR);
+#else
+    __ sub(SP, SP, 4); // make room for LR which may still be live
+                       // here if we are coming from a c2 method
+#endif // AARCH64
+  }
+
+  OopMap* map = RegisterSaver::save_live_registers(masm, &frame_size_words, !cause_return);
+  if (!cause_return) {
+    // update saved PC with correct value
+    // need 2 steps because LR can be live in c2 method
+    __ ldr(LR, Address(Rthread, JavaThread::saved_exception_pc_offset()));
+    __ str(LR, Address(SP, RegisterSaver::LR_offset * wordSize));
+  }
+
+  __ mov(R0, Rthread);
+  int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); // note: FP may not need to be saved (not on x86)
+  assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+  __ call(call_ptr);
+  if (pc_offset == -1) {
+    pc_offset = __ offset();
+  }
+  oop_maps->add_gc_map(pc_offset, map);
+  __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+  // Check for pending exception
+  __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
+  __ cmp(Rtemp, 0);
+
+#ifdef AARCH64
+  RegisterSaver::restore_live_registers(masm, cause_return);
+  Register ret_addr = cause_return ? LR : Rtemp;
+  if (!cause_return) {
+    __ raw_pop(FP, ret_addr);
+  }
+
+  Label throw_exception;
+  __ b(throw_exception, ne);
+  __ br(ret_addr);
+
+  __ bind(throw_exception);
+  __ mov(Rexception_pc, ret_addr);
+#else // AARCH64
+  if (!cause_return) {
+    RegisterSaver::restore_live_registers(masm, false);
+    __ pop(PC, eq);
+    __ pop(Rexception_pc);
+  } else {
+    RegisterSaver::restore_live_registers(masm);
+    __ bx(LR, eq);
+    __ mov(Rexception_pc, LR);
+  }
+#endif // AARCH64
+
+  __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+
+  __ flush();
+
+  return SafepointBlob::create(&buffer, oop_maps, frame_size_words);
+}
+
+RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+  assert(StubRoutines::forward_exception_entry() != NULL, "must be generated before");
+
+  ResourceMark rm;
+  CodeBuffer buffer(name, 1000, 512);
+  int frame_size_words;
+  OopMapSet *oop_maps;
+  int frame_complete;
+
+  MacroAssembler* masm = new MacroAssembler(&buffer);
+  Label pending_exception;
+
+  int start = __ offset();
+
+  oop_maps = new OopMapSet();
+  OopMap* map = RegisterSaver::save_live_registers(masm, &frame_size_words);
+
+  frame_complete = __ offset();
+
+  __ mov(R0, Rthread);
+
+  int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
+  assert(start == 0, "warning: start differs from code_begin");
+  __ call(destination);
+  if (pc_offset == -1) {
+    pc_offset = __ offset();
+  }
+  oop_maps->add_gc_map(pc_offset, map);
+  __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+  __ ldr(R1, Address(Rthread, Thread::pending_exception_offset()));
+  __ cbnz(R1, pending_exception);
+
+  // Overwrite saved register values
+
+  // Place metadata result of VM call into Rmethod
+  __ get_vm_result_2(R1, Rtemp);
+  __ str(R1, Address(SP, RegisterSaver::Rmethod_offset * wordSize));
+
+  // Place target address (VM call result) into Rtemp
+  __ str(R0, Address(SP, RegisterSaver::Rtemp_offset * wordSize));
+
+  RegisterSaver::restore_live_registers(masm);
+  __ jump(Rtemp);
+
+  __ bind(pending_exception);
+
+  RegisterSaver::restore_live_registers(masm);
+  const Register Rzero = __ zero_register(Rtemp);
+  __ str(Rzero, Address(Rthread, JavaThread::vm_result_2_offset()));
+  __ mov(Rexception_pc, LR);
+  __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+
+  __ flush();
+
+  return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
+}
diff --git a/hotspot/src/cpu/arm/vm/stubGenerator_arm.cpp b/hotspot/src/cpu/arm/vm/stubGenerator_arm.cpp
new file mode 100644
index 0000000..7d8c8d4
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/stubGenerator_arm.cpp
@@ -0,0 +1,4510 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "nativeInst_arm.hpp"
+#include "oops/instanceOop.hpp"
+#include "oops/method.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "runtime/stubRoutines.hpp"
+#ifdef COMPILER2
+#include "opto/runtime.hpp"
+#endif
+
+// Declaration and definition of StubGenerator (no .hpp file).
+// For a more detailed description of the stub routine structure
+// see the comment in stubRoutines.hpp
+
+#define __ _masm->
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
+
+#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
+
+// -------------------------------------------------------------------------------------------------------------------------
+// Stub Code definitions
+
+// Platform dependent parameters for array copy stubs
+
+// Note: we have noticed a huge change in behavior on a microbenchmark
+// from platform to platform depending on the configuration.
+
+// Instead of adding a series of command line options (which
+// unfortunately have to be done in the shared file and cannot appear
+// only in the ARM port), the tested result are hard-coded here in a set
+// of options, selected by specifying 'ArmCopyPlatform'
+
+// Currently, this 'platform' is hardcoded to a value that is a good
+// enough trade-off.  However, one can easily modify this file to test
+// the hard-coded configurations or create new ones. If the gain is
+// significant, we could decide to either add command line options or
+// add code to automatically choose a configuration.
+
+// see comments below for the various configurations created
+#define DEFAULT_ARRAYCOPY_CONFIG 0
+#define TEGRA2_ARRAYCOPY_CONFIG 1
+#define IMX515_ARRAYCOPY_CONFIG 2
+
+// Hard coded choices (XXX: could be changed to a command line option)
+#define ArmCopyPlatform DEFAULT_ARRAYCOPY_CONFIG
+
+#ifdef AARCH64
+#define ArmCopyCacheLineSize 64
+#else
+#define ArmCopyCacheLineSize 32 // not worth optimizing to 64 according to measured gains
+#endif // AARCH64
+
+// TODO-AARCH64: tune and revise AArch64 arraycopy optimizations
+
+// configuration for each kind of loop
+typedef struct {
+  int pld_distance;       // prefetch distance (0 => no prefetch, <0: prefetch_before);
+#ifndef AARCH64
+  bool split_ldm;         // if true, split each STM in STMs with fewer registers
+  bool split_stm;         // if true, split each LTM in LTMs with fewer registers
+#endif // !AARCH64
+} arraycopy_loop_config;
+
+// configuration for all loops
+typedef struct {
+  // const char *description;
+  arraycopy_loop_config forward_aligned;
+  arraycopy_loop_config backward_aligned;
+  arraycopy_loop_config forward_shifted;
+  arraycopy_loop_config backward_shifted;
+} arraycopy_platform_config;
+
+// configured platforms
+static arraycopy_platform_config arraycopy_configurations[] = {
+  // configuration parameters for arraycopy loops
+#ifdef AARCH64
+  {
+    {-256 }, // forward aligned
+    {-128 }, // backward aligned
+    {-256 }, // forward shifted
+    {-128 }  // backward shifted
+  }
+#else
+
+  // Configurations were chosen based on manual analysis of benchmark
+  // results, minimizing overhead with respect to best results on the
+  // different test cases.
+
+  // Prefetch before is always favored since it avoids dirtying the
+  // cache uselessly for small copies. Code for prefetch after has
+  // been kept in case the difference is significant for some
+  // platforms but we might consider dropping it.
+
+  // distance, ldm, stm
+  {
+    // default: tradeoff tegra2/imx515/nv-tegra2,
+    // Notes on benchmarking:
+    // - not far from optimal configuration on nv-tegra2
+    // - within 5% of optimal configuration except for backward aligned on IMX
+    // - up to 40% from optimal configuration for backward shifted and backward align for tegra2
+    //   but still on par with the operating system copy
+    {-256, true,  true  }, // forward aligned
+    {-256, true,  true  }, // backward aligned
+    {-256, false, false }, // forward shifted
+    {-256, true,  true  } // backward shifted
+  },
+  {
+    // configuration tuned on tegra2-4.
+    // Warning: should not be used on nv-tegra2 !
+    // Notes:
+    // - prefetch after gives 40% gain on backward copies on tegra2-4,
+    //   resulting in better number than the operating system
+    //   copy. However, this can lead to a 300% loss on nv-tegra and has
+    //   more impact on the cache (fetches futher than what is
+    //   copied). Use this configuration with care, in case it improves
+    //   reference benchmarks.
+    {-256, true,  true  }, // forward aligned
+    {96,   false, false }, // backward aligned
+    {-256, false, false }, // forward shifted
+    {96,   false, false } // backward shifted
+  },
+  {
+    // configuration tuned on imx515
+    // Notes:
+    // - smaller prefetch distance is sufficient to get good result and might be more stable
+    // - refined backward aligned options within 5% of optimal configuration except for
+    //   tests were the arrays fit in the cache
+    {-160, false, false }, // forward aligned
+    {-160, false, false }, // backward aligned
+    {-160, false, false }, // forward shifted
+    {-160, true,  true  } // backward shifted
+  }
+#endif // AARCH64
+};
+
+class StubGenerator: public StubCodeGenerator {
+
+#ifdef PRODUCT
+#define inc_counter_np(a,b,c) ((void)0)
+#else
+#define inc_counter_np(counter, t1, t2) \
+  BLOCK_COMMENT("inc_counter " #counter); \
+  __ inc_counter(&counter, t1, t2);
+#endif
+
+ private:
+
+  address generate_call_stub(address& return_address) {
+    StubCodeMark mark(this, "StubRoutines", "call_stub");
+    address start = __ pc();
+
+#ifdef AARCH64
+    const int saved_regs_size = 192;
+
+    __ stp(FP, LR, Address(SP, -saved_regs_size, pre_indexed));
+    __ mov(FP, SP);
+
+    int sp_offset = 16;
+    assert(frame::entry_frame_call_wrapper_offset * wordSize == sp_offset, "adjust this code");
+    __ stp(R0,  ZR,  Address(SP, sp_offset)); sp_offset += 16;
+
+    const int saved_result_and_result_type_offset = sp_offset;
+    __ stp(R1,  R2,  Address(SP, sp_offset)); sp_offset += 16;
+    __ stp(R19, R20, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp(R21, R22, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp(R23, R24, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp(R25, R26, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp(R27, R28, Address(SP, sp_offset)); sp_offset += 16;
+
+    __ stp_d(V8,  V9,  Address(SP, sp_offset)); sp_offset += 16;
+    __ stp_d(V10, V11, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp_d(V12, V13, Address(SP, sp_offset)); sp_offset += 16;
+    __ stp_d(V14, V15, Address(SP, sp_offset)); sp_offset += 16;
+    assert (sp_offset == saved_regs_size, "adjust this code");
+
+    __ mov(Rmethod, R3);
+    __ mov(Rthread, R7);
+    __ reinit_heapbase();
+
+    { // Pass parameters
+      Label done_parameters, pass_parameters;
+
+      __ mov(Rparams, SP);
+      __ cbz_w(R6, done_parameters);
+
+      __ sub(Rtemp, SP, R6, ex_uxtw, LogBytesPerWord);
+      __ align_reg(SP, Rtemp, StackAlignmentInBytes);
+      __ add(Rparams, SP, R6, ex_uxtw, LogBytesPerWord);
+
+      __ bind(pass_parameters);
+      __ subs_w(R6, R6, 1);
+      __ ldr(Rtemp, Address(R5, wordSize, post_indexed));
+      __ str(Rtemp, Address(Rparams, -wordSize, pre_indexed));
+      __ b(pass_parameters, ne);
+
+      __ bind(done_parameters);
+
+#ifdef ASSERT
+      {
+        Label L;
+        __ cmp(SP, Rparams);
+        __ b(L, eq);
+        __ stop("SP does not match Rparams");
+        __ bind(L);
+      }
+#endif
+    }
+
+    __ mov(Rsender_sp, SP);
+    __ blr(R4);
+    return_address = __ pc();
+
+    __ mov(SP, FP);
+
+    __ ldp(R1, R2, Address(SP, saved_result_and_result_type_offset));
+
+    { // Handle return value
+      Label cont;
+      __ str(R0, Address(R1));
+
+      __ cmp_w(R2, T_DOUBLE);
+      __ ccmp_w(R2, T_FLOAT, Assembler::flags_for_condition(eq), ne);
+      __ b(cont, ne);
+
+      __ str_d(V0, Address(R1));
+      __ bind(cont);
+    }
+
+    sp_offset = saved_result_and_result_type_offset + 16;
+    __ ldp(R19, R20, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp(R21, R22, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp(R23, R24, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp(R25, R26, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp(R27, R28, Address(SP, sp_offset)); sp_offset += 16;
+
+    __ ldp_d(V8,  V9,  Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp_d(V10, V11, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp_d(V12, V13, Address(SP, sp_offset)); sp_offset += 16;
+    __ ldp_d(V14, V15, Address(SP, sp_offset)); sp_offset += 16;
+    assert (sp_offset == saved_regs_size, "adjust this code");
+
+    __ ldp(FP, LR, Address(SP, saved_regs_size, post_indexed));
+    __ ret();
+
+#else // AARCH64
+
+    assert(frame::entry_frame_call_wrapper_offset == 0, "adjust this code");
+
+    __ mov(Rtemp, SP);
+    __ push(RegisterSet(FP) | RegisterSet(LR));
+#ifndef __SOFTFP__
+    __ fstmdbd(SP, FloatRegisterSet(D8, 8), writeback);
+#endif
+    __ stmdb(SP, RegisterSet(R0, R2) | RegisterSet(R4, R6) | RegisterSet(R8, R10) | altFP_7_11, writeback);
+    __ mov(Rmethod, R3);
+    __ ldmia(Rtemp, RegisterSet(R1, R3) | Rthread); // stacked arguments
+
+    // XXX: TODO
+    // Would be better with respect to native tools if the following
+    // setting of FP was changed to conform to the native ABI, with FP
+    // pointing to the saved FP slot (and the corresponding modifications
+    // for entry_frame_call_wrapper_offset and frame::real_fp).
+    __ mov(FP, SP);
+
+    {
+      Label no_parameters, pass_parameters;
+      __ cmp(R3, 0);
+      __ b(no_parameters, eq);
+
+      __ bind(pass_parameters);
+      __ ldr(Rtemp, Address(R2, wordSize, post_indexed)); // Rtemp OK, unused and scratchable
+      __ subs(R3, R3, 1);
+      __ push(Rtemp);
+      __ b(pass_parameters, ne);
+      __ bind(no_parameters);
+    }
+
+    __ mov(Rsender_sp, SP);
+    __ blx(R1);
+    return_address = __ pc();
+
+    __ add(SP, FP, wordSize); // Skip link to JavaCallWrapper
+    __ pop(RegisterSet(R2, R3));
+#ifndef __ABI_HARD__
+    __ cmp(R3, T_LONG);
+    __ cmp(R3, T_DOUBLE, ne);
+    __ str(R0, Address(R2));
+    __ str(R1, Address(R2, wordSize), eq);
+#else
+    Label cont, l_float, l_double;
+
+    __ cmp(R3, T_DOUBLE);
+    __ b(l_double, eq);
+
+    __ cmp(R3, T_FLOAT);
+    __ b(l_float, eq);
+
+    __ cmp(R3, T_LONG);
+    __ str(R0, Address(R2));
+    __ str(R1, Address(R2, wordSize), eq);
+    __ b(cont);
+
+
+    __ bind(l_double);
+    __ fstd(D0, Address(R2));
+    __ b(cont);
+
+    __ bind(l_float);
+    __ fsts(S0, Address(R2));
+
+    __ bind(cont);
+#endif
+
+    __ pop(RegisterSet(R4, R6) | RegisterSet(R8, R10) | altFP_7_11);
+#ifndef __SOFTFP__
+    __ fldmiad(SP, FloatRegisterSet(D8, 8), writeback);
+#endif
+    __ pop(RegisterSet(FP) | RegisterSet(PC));
+
+#endif // AARCH64
+    return start;
+  }
+
+
+  // (in) Rexception_obj: exception oop
+  address generate_catch_exception() {
+    StubCodeMark mark(this, "StubRoutines", "catch_exception");
+    address start = __ pc();
+
+    __ str(Rexception_obj, Address(Rthread, Thread::pending_exception_offset()));
+    __ b(StubRoutines::_call_stub_return_address);
+
+    return start;
+  }
+
+
+  // (in) Rexception_pc: return address
+  address generate_forward_exception() {
+    StubCodeMark mark(this, "StubRoutines", "forward exception");
+    address start = __ pc();
+
+    __ mov(c_rarg0, Rthread);
+    __ mov(c_rarg1, Rexception_pc);
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address,
+                         SharedRuntime::exception_handler_for_return_address),
+                         c_rarg0, c_rarg1);
+    __ ldr(Rexception_obj, Address(Rthread, Thread::pending_exception_offset()));
+    const Register Rzero = __ zero_register(Rtemp); // Rtemp OK (cleared by above call)
+    __ str(Rzero, Address(Rthread, Thread::pending_exception_offset()));
+
+#ifdef ASSERT
+    // make sure exception is set
+    { Label L;
+      __ cbnz(Rexception_obj, L);
+      __ stop("StubRoutines::forward exception: no pending exception (2)");
+      __ bind(L);
+    }
+#endif
+
+    // Verify that there is really a valid exception in RAX.
+    __ verify_oop(Rexception_obj);
+
+    __ jump(R0); // handler is returned in R0 by runtime function
+    return start;
+  }
+
+
+#ifndef AARCH64
+
+  // Integer division shared routine
+  //   Input:
+  //     R0  - dividend
+  //     R2  - divisor
+  //   Output:
+  //     R0  - remainder
+  //     R1  - quotient
+  //   Destroys:
+  //     R2
+  //     LR
+  address generate_idiv_irem() {
+    Label positive_arguments, negative_or_zero, call_slow_path;
+    Register dividend  = R0;
+    Register divisor   = R2;
+    Register remainder = R0;
+    Register quotient  = R1;
+    Register tmp       = LR;
+    assert(dividend == remainder, "must be");
+
+    address start = __ pc();
+
+    // Check for special cases: divisor <= 0 or dividend < 0
+    __ cmp(divisor, 0);
+    __ orrs(quotient, dividend, divisor, ne);
+    __ b(negative_or_zero, le);
+
+    __ bind(positive_arguments);
+    // Save return address on stack to free one extra register
+    __ push(LR);
+    // Approximate the mamximum order of the quotient
+    __ clz(tmp, dividend);
+    __ clz(quotient, divisor);
+    __ subs(tmp, quotient, tmp);
+    __ mov(quotient, 0);
+    // Jump to the appropriate place in the unrolled loop below
+    __ ldr(PC, Address(PC, tmp, lsl, 2), pl);
+    // If divisor is greater than dividend, return immediately
+    __ pop(PC);
+
+    // Offset table
+    Label offset_table[32];
+    int i;
+    for (i = 0; i <= 31; i++) {
+      __ emit_address(offset_table[i]);
+    }
+
+    // Unrolled loop of 32 division steps
+    for (i = 31; i >= 0; i--) {
+      __ bind(offset_table[i]);
+      __ cmp(remainder, AsmOperand(divisor, lsl, i));
+      __ sub(remainder, remainder, AsmOperand(divisor, lsl, i), hs);
+      __ add(quotient, quotient, 1 << i, hs);
+    }
+    __ pop(PC);
+
+    __ bind(negative_or_zero);
+    // Find the combination of argument signs and jump to corresponding handler
+    __ andr(quotient, dividend, 0x80000000, ne);
+    __ orr(quotient, quotient, AsmOperand(divisor, lsr, 31), ne);
+    __ add(PC, PC, AsmOperand(quotient, ror, 26), ne);
+    __ str(LR, Address(Rthread, JavaThread::saved_exception_pc_offset()));
+
+    // The leaf runtime function can destroy R0-R3 and R12 registers which are still alive
+    RegisterSet saved_registers = RegisterSet(R3) | RegisterSet(R12);
+#if R9_IS_SCRATCHED
+    // Safer to save R9 here since callers may have been written
+    // assuming R9 survives. This is suboptimal but may not be worth
+    // revisiting for this slow case.
+
+    // save also R10 for alignment
+    saved_registers = saved_registers | RegisterSet(R9, R10);
+#endif
+    {
+      // divisor == 0
+      FixedSizeCodeBlock zero_divisor(_masm, 8, true);
+      __ push(saved_registers);
+      __ mov(R0, Rthread);
+      __ mov(R1, LR);
+      __ mov(R2, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
+      __ b(call_slow_path);
+    }
+
+    {
+      // divisor > 0 && dividend < 0
+      FixedSizeCodeBlock positive_divisor_negative_dividend(_masm, 8, true);
+      __ push(LR);
+      __ rsb(dividend, dividend, 0);
+      __ bl(positive_arguments);
+      __ rsb(remainder, remainder, 0);
+      __ rsb(quotient, quotient, 0);
+      __ pop(PC);
+    }
+
+    {
+      // divisor < 0 && dividend > 0
+      FixedSizeCodeBlock negative_divisor_positive_dividend(_masm, 8, true);
+      __ push(LR);
+      __ rsb(divisor, divisor, 0);
+      __ bl(positive_arguments);
+      __ rsb(quotient, quotient, 0);
+      __ pop(PC);
+    }
+
+    {
+      // divisor < 0 && dividend < 0
+      FixedSizeCodeBlock negative_divisor_negative_dividend(_masm, 8, true);
+      __ push(LR);
+      __ rsb(dividend, dividend, 0);
+      __ rsb(divisor, divisor, 0);
+      __ bl(positive_arguments);
+      __ rsb(remainder, remainder, 0);
+      __ pop(PC);
+    }
+
+    __ bind(call_slow_path);
+    __ call(CAST_FROM_FN_PTR(address, SharedRuntime::continuation_for_implicit_exception));
+    __ pop(saved_registers);
+    __ bx(R0);
+
+    return start;
+  }
+
+
+ // As per atomic.hpp the Atomic read-modify-write operations must be logically implemented as:
+ //  <fence>; <op>; <membar StoreLoad|StoreStore>
+ // But for load-linked/store-conditional based systems a fence here simply means
+ // no load/store can be reordered with respect to the initial load-linked, so we have:
+ // <membar storeload|loadload> ; load-linked; <op>; store-conditional; <membar storeload|storestore>
+ // There are no memory actions in <op> so nothing further is needed.
+ //
+ // So we define the following for convenience:
+#define MEMBAR_ATOMIC_OP_PRE \
+    MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad|MacroAssembler::LoadLoad)
+#define MEMBAR_ATOMIC_OP_POST \
+    MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad|MacroAssembler::StoreStore)
+
+  // Note: JDK 9 only supports ARMv7+ so we always have ldrexd available even though the
+  // code below allows for it to be otherwise. The else clause indicates an ARMv5 system
+  // for which we do not support MP and so membars are not necessary. This ARMv5 code will
+  // be removed in the future.
+
+  // Support for jint Atomic::add(jint add_value, volatile jint *dest)
+  //
+  // Arguments :
+  //
+  //      add_value:      R0
+  //      dest:           R1
+  //
+  // Results:
+  //
+  //     R0: the new stored in dest
+  //
+  // Overwrites:
+  //
+  //     R1, R2, R3
+  //
+  address generate_atomic_add() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_add");
+    Label retry;
+    start = __ pc();
+    Register addval    = R0;
+    Register dest      = R1;
+    Register prev      = R2;
+    Register ok        = R2;
+    Register newval    = R3;
+
+    if (VM_Version::supports_ldrex()) {
+      __ membar(MEMBAR_ATOMIC_OP_PRE, prev);
+      __ bind(retry);
+      __ ldrex(newval, Address(dest));
+      __ add(newval, addval, newval);
+      __ strex(ok, newval, Address(dest));
+      __ cmp(ok, 0);
+      __ b(retry, ne);
+      __ mov (R0, newval);
+      __ membar(MEMBAR_ATOMIC_OP_POST, prev);
+    } else {
+      __ bind(retry);
+      __ ldr (prev, Address(dest));
+      __ add(newval, addval, prev);
+      __ atomic_cas_bool(prev, newval, dest, 0, noreg/*ignored*/);
+      __ b(retry, ne);
+      __ mov (R0, newval);
+    }
+    __ bx(LR);
+
+    return start;
+  }
+
+  // Support for jint Atomic::xchg(jint exchange_value, volatile jint *dest)
+  //
+  // Arguments :
+  //
+  //      exchange_value: R0
+  //      dest:           R1
+  //
+  // Results:
+  //
+  //     R0: the value previously stored in dest
+  //
+  // Overwrites:
+  //
+  //     R1, R2, R3
+  //
+  address generate_atomic_xchg() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_xchg");
+    start = __ pc();
+    Register newval    = R0;
+    Register dest      = R1;
+    Register prev      = R2;
+
+    Label retry;
+
+    if (VM_Version::supports_ldrex()) {
+      Register ok=R3;
+      __ membar(MEMBAR_ATOMIC_OP_PRE, prev);
+      __ bind(retry);
+      __ ldrex(prev, Address(dest));
+      __ strex(ok, newval, Address(dest));
+      __ cmp(ok, 0);
+      __ b(retry, ne);
+      __ mov (R0, prev);
+      __ membar(MEMBAR_ATOMIC_OP_POST, prev);
+    } else {
+      __ bind(retry);
+      __ ldr (prev, Address(dest));
+      __ atomic_cas_bool(prev, newval, dest, 0, noreg/*ignored*/);
+      __ b(retry, ne);
+      __ mov (R0, prev);
+    }
+    __ bx(LR);
+
+    return start;
+  }
+
+  // Support for jint Atomic::cmpxchg(jint exchange_value, volatile jint *dest, jint compare_value)
+  //
+  // Arguments :
+  //
+  //      compare_value:  R0
+  //      exchange_value: R1
+  //      dest:           R2
+  //
+  // Results:
+  //
+  //     R0: the value previously stored in dest
+  //
+  // Overwrites:
+  //
+  //     R0, R1, R2, R3, Rtemp
+  //
+  address generate_atomic_cmpxchg() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg");
+    start = __ pc();
+    Register cmp       = R0;
+    Register newval    = R1;
+    Register dest      = R2;
+    Register temp1     = R3;
+    Register temp2     = Rtemp; // Rtemp free (native ABI)
+
+    __ membar(MEMBAR_ATOMIC_OP_PRE, temp1);
+
+    // atomic_cas returns previous value in R0
+    __ atomic_cas(temp1, temp2, cmp, newval, dest, 0);
+
+    __ membar(MEMBAR_ATOMIC_OP_POST, temp1);
+
+    __ bx(LR);
+
+    return start;
+  }
+
+  // Support for jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong *dest, jlong compare_value)
+  // reordered before by a wrapper to (jlong compare_value, jlong exchange_value, volatile jlong *dest)
+  //
+  // Arguments :
+  //
+  //      compare_value:  R1 (High), R0 (Low)
+  //      exchange_value: R3 (High), R2 (Low)
+  //      dest:           SP+0
+  //
+  // Results:
+  //
+  //     R0:R1: the value previously stored in dest
+  //
+  // Overwrites:
+  //
+  address generate_atomic_cmpxchg_long() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_long");
+    start = __ pc();
+    Register cmp_lo      = R0;
+    Register cmp_hi      = R1;
+    Register newval_lo   = R2;
+    Register newval_hi   = R3;
+    Register addr        = Rtemp;  /* After load from stack */
+    Register temp_lo     = R4;
+    Register temp_hi     = R5;
+    Register temp_result = R8;
+    assert_different_registers(cmp_lo, newval_lo, temp_lo, addr, temp_result, R7);
+    assert_different_registers(cmp_hi, newval_hi, temp_hi, addr, temp_result, R7);
+
+    __ membar(MEMBAR_ATOMIC_OP_PRE, Rtemp); // Rtemp free (native ABI)
+
+    // Stack is unaligned, maintain double word alignment by pushing
+    // odd number of regs.
+    __ push(RegisterSet(temp_result) | RegisterSet(temp_lo, temp_hi));
+    __ ldr(addr, Address(SP, 12));
+
+    // atomic_cas64 returns previous value in temp_lo, temp_hi
+    __ atomic_cas64(temp_lo, temp_hi, temp_result, cmp_lo, cmp_hi,
+                    newval_lo, newval_hi, addr, 0);
+    __ mov(R0, temp_lo);
+    __ mov(R1, temp_hi);
+
+    __ pop(RegisterSet(temp_result) | RegisterSet(temp_lo, temp_hi));
+
+    __ membar(MEMBAR_ATOMIC_OP_POST, Rtemp); // Rtemp free (native ABI)
+    __ bx(LR);
+
+    return start;
+  }
+
+  address generate_atomic_load_long() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_load_long");
+    start = __ pc();
+    Register result_lo = R0;
+    Register result_hi = R1;
+    Register src       = R0;
+
+    if (!os::is_MP()) {
+      __ ldmia(src, RegisterSet(result_lo, result_hi));
+      __ bx(LR);
+    } else if (VM_Version::supports_ldrexd()) {
+      __ ldrexd(result_lo, Address(src));
+      __ clrex(); // FIXME: safe to remove?
+      __ bx(LR);
+    } else {
+      __ stop("Atomic load(jlong) unsupported on this platform");
+      __ bx(LR);
+    }
+
+    return start;
+  }
+
+  address generate_atomic_store_long() {
+    address start;
+
+    StubCodeMark mark(this, "StubRoutines", "atomic_store_long");
+    start = __ pc();
+    Register newval_lo = R0;
+    Register newval_hi = R1;
+    Register dest      = R2;
+    Register scratch_lo    = R2;
+    Register scratch_hi    = R3;  /* After load from stack */
+    Register result    = R3;
+
+    if (!os::is_MP()) {
+      __ stmia(dest, RegisterSet(newval_lo, newval_hi));
+      __ bx(LR);
+    } else if (VM_Version::supports_ldrexd()) {
+      __ mov(Rtemp, dest);  // get dest to Rtemp
+      Label retry;
+      __ bind(retry);
+      __ ldrexd(scratch_lo, Address(Rtemp));
+      __ strexd(result, R0, Address(Rtemp));
+      __ rsbs(result, result, 1);
+      __ b(retry, eq);
+      __ bx(LR);
+    } else {
+      __ stop("Atomic store(jlong) unsupported on this platform");
+      __ bx(LR);
+    }
+
+    return start;
+  }
+
+
+#endif // AARCH64
+
+#ifdef COMPILER2
+  // Support for uint StubRoutine::Arm::partial_subtype_check( Klass sub, Klass super );
+  // Arguments :
+  //
+  //      ret  : R0, returned
+  //      icc/xcc: set as R0 (depending on wordSize)
+  //      sub  : R1, argument, not changed
+  //      super: R2, argument, not changed
+  //      raddr: LR, blown by call
+  address generate_partial_subtype_check() {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "partial_subtype_check");
+    address start = __ pc();
+
+    // based on SPARC check_klass_subtype_[fast|slow]_path (without CompressedOops)
+
+    // R0 used as tmp_reg (in addition to return reg)
+    Register sub_klass = R1;
+    Register super_klass = R2;
+    Register tmp_reg2 = R3;
+    Register tmp_reg3 = R4;
+#define saved_set tmp_reg2, tmp_reg3
+
+    Label L_loop, L_fail;
+
+    int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+
+    // fast check should be redundant
+
+    // slow check
+    {
+      __ raw_push(saved_set);
+
+      // a couple of useful fields in sub_klass:
+      int ss_offset = in_bytes(Klass::secondary_supers_offset());
+
+      // Do a linear scan of the secondary super-klass chain.
+      // This code is rarely used, so simplicity is a virtue here.
+
+      inc_counter_np(SharedRuntime::_partial_subtype_ctr, tmp_reg2, tmp_reg3);
+
+      Register scan_temp = tmp_reg2;
+      Register count_temp = tmp_reg3;
+
+      // We will consult the secondary-super array.
+      __ ldr(scan_temp, Address(sub_klass, ss_offset));
+
+      Register search_key = super_klass;
+
+      // Load the array length.
+      __ ldr_s32(count_temp, Address(scan_temp, Array<Klass*>::length_offset_in_bytes()));
+      __ add(scan_temp, scan_temp, Array<Klass*>::base_offset_in_bytes());
+
+      __ add(count_temp, count_temp, 1);
+
+      // Top of search loop
+      __ bind(L_loop);
+      // Notes:
+      //  scan_temp starts at the array elements
+      //  count_temp is 1+size
+      __ subs(count_temp, count_temp, 1);
+      __ b(L_fail, eq); // not found in the array
+
+      // Load next super to check
+      // In the array of super classes elements are pointer sized.
+      int element_size = wordSize;
+      __ ldr(R0, Address(scan_temp, element_size, post_indexed));
+
+      // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
+      __ subs(R0, R0, search_key); // set R0 to 0 on success (and flags to eq)
+
+      // A miss means we are NOT a subtype and need to keep looping
+      __ b(L_loop, ne);
+
+      // Falling out the bottom means we found a hit; we ARE a subtype
+
+      // Success.  Cache the super we found and proceed in triumph.
+      __ str(super_klass, Address(sub_klass, sc_offset));
+
+      // Return success
+      // R0 is already 0 and flags are already set to eq
+      __ raw_pop(saved_set);
+      __ ret();
+
+      // Return failure
+      __ bind(L_fail);
+#ifdef AARCH64
+      // count_temp is 0, can't use ZR here
+      __ adds(R0, count_temp, 1); // sets the flags
+#else
+      __ movs(R0, 1); // sets the flags
+#endif
+      __ raw_pop(saved_set);
+      __ ret();
+    }
+    return start;
+  }
+#undef saved_set
+#endif // COMPILER2
+
+
+  //----------------------------------------------------------------------------------------------------
+  // Non-destructive plausibility checks for oops
+
+  address generate_verify_oop() {
+    StubCodeMark mark(this, "StubRoutines", "verify_oop");
+    address start = __ pc();
+
+    // Incoming arguments:
+    //
+    // R0: error message (char* )
+    // R1: address of register save area
+    // R2: oop to verify
+    //
+    // All registers are saved before calling this stub. However, condition flags should be saved here.
+
+    const Register oop   = R2;
+    const Register klass = R3;
+    const Register tmp1  = R6;
+    const Register tmp2  = R8;
+
+    const Register flags     = Rtmp_save0; // R4/R19
+    const Register ret_addr  = Rtmp_save1; // R5/R20
+    assert_different_registers(oop, klass, tmp1, tmp2, flags, ret_addr, R7);
+
+    Label exit, error;
+    InlinedAddress verify_oop_count((address) StubRoutines::verify_oop_count_addr());
+
+#ifdef AARCH64
+    __ mrs(flags, Assembler::SysReg_NZCV);
+#else
+    __ mrs(Assembler::CPSR, flags);
+#endif // AARCH64
+
+    __ ldr_literal(tmp1, verify_oop_count);
+    __ ldr_s32(tmp2, Address(tmp1));
+    __ add(tmp2, tmp2, 1);
+    __ str_32(tmp2, Address(tmp1));
+
+    // make sure object is 'reasonable'
+    __ cbz(oop, exit);                           // if obj is NULL it is ok
+
+    // Check if the oop is in the right area of memory
+    // Note: oop_mask and oop_bits must be updated if the code is saved/reused
+    const address oop_mask = (address) Universe::verify_oop_mask();
+    const address oop_bits = (address) Universe::verify_oop_bits();
+    __ mov_address(tmp1, oop_mask, symbolic_Relocation::oop_mask_reference);
+    __ andr(tmp2, oop, tmp1);
+    __ mov_address(tmp1, oop_bits, symbolic_Relocation::oop_bits_reference);
+    __ cmp(tmp2, tmp1);
+    __ b(error, ne);
+
+    // make sure klass is 'reasonable'
+    __ load_klass(klass, oop);                   // get klass
+    __ cbz(klass, error);                        // if klass is NULL it is broken
+
+    // return if everything seems ok
+    __ bind(exit);
+
+#ifdef AARCH64
+    __ msr(Assembler::SysReg_NZCV, flags);
+#else
+    __ msr(Assembler::CPSR_f, flags);
+#endif // AARCH64
+
+    __ ret();
+
+    // handle errors
+    __ bind(error);
+
+    __ mov(ret_addr, LR);                      // save return address
+
+    // R0: error message
+    // R1: register save area
+    __ call(CAST_FROM_FN_PTR(address, MacroAssembler::debug));
+
+    __ mov(LR, ret_addr);
+    __ b(exit);
+
+    __ bind_literal(verify_oop_count);
+
+    return start;
+  }
+
+  //----------------------------------------------------------------------------------------------------
+  // Array copy stubs
+
+  //
+  //  Generate overlap test for array copy stubs
+  //
+  //  Input:
+  //    R0    -  array1
+  //    R1    -  array2
+  //    R2    -  element count, 32-bit int
+  //
+  //  input registers are preserved
+  //
+  void array_overlap_test(address no_overlap_target, int log2_elem_size, Register tmp1, Register tmp2) {
+    assert(no_overlap_target != NULL, "must be generated");
+    array_overlap_test(no_overlap_target, NULL, log2_elem_size, tmp1, tmp2);
+  }
+  void array_overlap_test(Label& L_no_overlap, int log2_elem_size, Register tmp1, Register tmp2) {
+    array_overlap_test(NULL, &L_no_overlap, log2_elem_size, tmp1, tmp2);
+  }
+  void array_overlap_test(address no_overlap_target, Label* NOLp, int log2_elem_size, Register tmp1, Register tmp2) {
+    const Register from       = R0;
+    const Register to         = R1;
+    const Register count      = R2;
+    const Register to_from    = tmp1; // to - from
+#ifndef AARCH64
+    const Register byte_count = (log2_elem_size == 0) ? count : tmp2; // count << log2_elem_size
+#endif // AARCH64
+    assert_different_registers(from, to, count, tmp1, tmp2);
+
+    // no_overlap version works if 'to' lower (unsigned) than 'from'
+    // and or 'to' more than (count*size) from 'from'
+
+    BLOCK_COMMENT("Array Overlap Test:");
+    __ subs(to_from, to, from);
+#ifndef AARCH64
+    if (log2_elem_size != 0) {
+      __ mov(byte_count, AsmOperand(count, lsl, log2_elem_size));
+    }
+#endif // !AARCH64
+    if (NOLp == NULL)
+      __ b(no_overlap_target,lo);
+    else
+      __ b((*NOLp), lo);
+#ifdef AARCH64
+    __ subs(ZR, to_from, count, ex_sxtw, log2_elem_size);
+#else
+    __ cmp(to_from, byte_count);
+#endif // AARCH64
+    if (NOLp == NULL)
+      __ b(no_overlap_target, ge);
+    else
+      __ b((*NOLp), ge);
+  }
+
+#ifdef AARCH64
+  // TODO-AARCH64: revise usages of bulk_* methods (probably ldp`s and stp`s should interlace)
+
+  // Loads [from, from + count*wordSize) into regs[0], regs[1], ..., regs[count-1]
+  // and increases 'from' by count*wordSize.
+  void bulk_load_forward(Register from, const Register regs[], int count) {
+    assert (count > 0 && count % 2 == 0, "count must be positive even number");
+    int bytes = count * wordSize;
+
+    int offset = 0;
+    __ ldp(regs[0], regs[1], Address(from, bytes, post_indexed));
+    offset += 2*wordSize;
+
+    for (int i = 2; i < count; i += 2) {
+      __ ldp(regs[i], regs[i+1], Address(from, -bytes + offset));
+      offset += 2*wordSize;
+    }
+
+    assert (offset == bytes, "must be");
+  }
+
+  // Stores regs[0], regs[1], ..., regs[count-1] to [to, to + count*wordSize)
+  // and increases 'to' by count*wordSize.
+  void bulk_store_forward(Register to, const Register regs[], int count) {
+    assert (count > 0 && count % 2 == 0, "count must be positive even number");
+    int bytes = count * wordSize;
+
+    int offset = 0;
+    __ stp(regs[0], regs[1], Address(to, bytes, post_indexed));
+    offset += 2*wordSize;
+
+    for (int i = 2; i < count; i += 2) {
+      __ stp(regs[i], regs[i+1], Address(to, -bytes + offset));
+      offset += 2*wordSize;
+    }
+
+    assert (offset == bytes, "must be");
+  }
+
+  // Loads [from - count*wordSize, from) into regs[0], regs[1], ..., regs[count-1]
+  // and decreases 'from' by count*wordSize.
+  // Note that the word with lowest address goes to regs[0].
+  void bulk_load_backward(Register from, const Register regs[], int count) {
+    assert (count > 0 && count % 2 == 0, "count must be positive even number");
+    int bytes = count * wordSize;
+
+    int offset = 0;
+
+    for (int i = count - 2; i > 0; i -= 2) {
+      offset += 2*wordSize;
+      __ ldp(regs[i], regs[i+1], Address(from, -offset));
+    }
+
+    offset += 2*wordSize;
+    __ ldp(regs[0], regs[1], Address(from, -bytes, pre_indexed));
+
+    assert (offset == bytes, "must be");
+  }
+
+  // Stores regs[0], regs[1], ..., regs[count-1] into [to - count*wordSize, to)
+  // and decreases 'to' by count*wordSize.
+  // Note that regs[0] value goes into the memory with lowest address.
+  void bulk_store_backward(Register to, const Register regs[], int count) {
+    assert (count > 0 && count % 2 == 0, "count must be positive even number");
+    int bytes = count * wordSize;
+
+    int offset = 0;
+
+    for (int i = count - 2; i > 0; i -= 2) {
+      offset += 2*wordSize;
+      __ stp(regs[i], regs[i+1], Address(to, -offset));
+    }
+
+    offset += 2*wordSize;
+    __ stp(regs[0], regs[1], Address(to, -bytes, pre_indexed));
+
+    assert (offset == bytes, "must be");
+  }
+#endif // AARCH64
+
+  // TODO-AARCH64: rearrange in-loop prefetches:
+  //   probably we should choose between "prefetch-store before or after store", not "before or after load".
+  void prefetch(Register from, Register to, int offset, int to_delta = 0) {
+    __ prefetch_read(Address(from, offset));
+#ifdef AARCH64
+  // Next line commented out to avoid significant loss of performance in memory copy - JDK-8078120
+  // __ prfm(pstl1keep, Address(to, offset + to_delta));
+#endif // AARCH64
+  }
+
+  // Generate the inner loop for forward aligned array copy
+  //
+  // Arguments
+  //      from:      src address, 64 bits  aligned
+  //      to:        dst address, wordSize aligned
+  //      count:     number of elements (32-bit int)
+  //      bytes_per_count: number of bytes for each unit of 'count'
+  //
+  // Return the minimum initial value for count
+  //
+  // Notes:
+  // - 'from' aligned on 64-bit (recommended for 32-bit ARM in case this speeds up LDMIA, required for AArch64)
+  // - 'to' aligned on wordSize
+  // - 'count' must be greater or equal than the returned value
+  //
+  // Increases 'from' and 'to' by count*bytes_per_count.
+  //
+  // Scratches 'count', R3.
+  // On AArch64 also scratches R4-R10; on 32-bit ARM R4-R10 are preserved (saved/restored).
+  //
+  int generate_forward_aligned_copy_loop(Register from, Register to, Register count, int bytes_per_count) {
+    assert (from == R0 && to == R1 && count == R2, "adjust the implementation below");
+
+    const int bytes_per_loop = 8*wordSize; // 8 registers are read and written on every loop iteration
+    arraycopy_loop_config *config=&arraycopy_configurations[ArmCopyPlatform].forward_aligned;
+    int pld_offset = config->pld_distance;
+    const int count_per_loop = bytes_per_loop / bytes_per_count;
+
+#ifndef AARCH64
+    bool split_read= config->split_ldm;
+    bool split_write= config->split_stm;
+
+    // XXX optim: use VLDM/VSTM when available (Neon) with PLD
+    //  NEONCopyPLD
+    //      PLD [r1, #0xC0]
+    //      VLDM r1!,{d0-d7}
+    //      VSTM r0!,{d0-d7}
+    //      SUBS r2,r2,#0x40
+    //      BGE NEONCopyPLD
+
+    __ push(RegisterSet(R4,R10));
+#endif // !AARCH64
+
+    const bool prefetch_before = pld_offset < 0;
+    const bool prefetch_after = pld_offset > 0;
+
+    Label L_skip_pld;
+
+    // predecrease to exit when there is less than count_per_loop
+    __ sub_32(count, count, count_per_loop);
+
+    if (pld_offset != 0) {
+      pld_offset = (pld_offset < 0) ? -pld_offset : pld_offset;
+
+      prefetch(from, to, 0);
+
+      if (prefetch_before) {
+        // If prefetch is done ahead, final PLDs that overflow the
+        // copied area can be easily avoided. 'count' is predecreased
+        // by the prefetch distance to optimize the inner loop and the
+        // outer loop skips the PLD.
+        __ subs_32(count, count, (bytes_per_loop+pld_offset)/bytes_per_count);
+
+        // skip prefetch for small copies
+        __ b(L_skip_pld, lt);
+      }
+
+      int offset = ArmCopyCacheLineSize;
+      while (offset <= pld_offset) {
+        prefetch(from, to, offset);
+        offset += ArmCopyCacheLineSize;
+      };
+    }
+
+#ifdef AARCH64
+    const Register data_regs[8] = {R3, R4, R5, R6, R7, R8, R9, R10};
+#endif // AARCH64
+    {
+      // LDM (32-bit ARM) / LDP (AArch64) copy of 'bytes_per_loop' bytes
+
+      // 32-bit ARM note: we have tried implementing loop unrolling to skip one
+      // PLD with 64 bytes cache line but the gain was not significant.
+
+      Label L_copy_loop;
+      __ align(OptoLoopAlignment);
+      __ BIND(L_copy_loop);
+
+      if (prefetch_before) {
+        prefetch(from, to, bytes_per_loop + pld_offset);
+        __ BIND(L_skip_pld);
+      }
+
+#ifdef AARCH64
+      bulk_load_forward(from, data_regs, 8);
+#else
+      if (split_read) {
+        // Split the register set in two sets so that there is less
+        // latency between LDM and STM (R3-R6 available while R7-R10
+        // still loading) and less register locking issue when iterating
+        // on the first LDM.
+        __ ldmia(from, RegisterSet(R3, R6), writeback);
+        __ ldmia(from, RegisterSet(R7, R10), writeback);
+      } else {
+        __ ldmia(from, RegisterSet(R3, R10), writeback);
+      }
+#endif // AARCH64
+
+      __ subs_32(count, count, count_per_loop);
+
+      if (prefetch_after) {
+        prefetch(from, to, pld_offset, bytes_per_loop);
+      }
+
+#ifdef AARCH64
+      bulk_store_forward(to, data_regs, 8);
+#else
+      if (split_write) {
+        __ stmia(to, RegisterSet(R3, R6), writeback);
+        __ stmia(to, RegisterSet(R7, R10), writeback);
+      } else {
+        __ stmia(to, RegisterSet(R3, R10), writeback);
+      }
+#endif // AARCH64
+
+      __ b(L_copy_loop, ge);
+
+      if (prefetch_before) {
+        // the inner loop may end earlier, allowing to skip PLD for the last iterations
+        __ cmn_32(count, (bytes_per_loop + pld_offset)/bytes_per_count);
+        __ b(L_skip_pld, ge);
+      }
+    }
+    BLOCK_COMMENT("Remaining bytes:");
+    // still 0..bytes_per_loop-1 aligned bytes to copy, count already decreased by (at least) bytes_per_loop bytes
+
+    // __ add(count, count, ...); // addition useless for the bit tests
+    assert (pld_offset % bytes_per_loop == 0, "decreasing count by pld_offset before loop must not change tested bits");
+
+#ifdef AARCH64
+    assert (bytes_per_loop == 64, "adjust the code below");
+    assert (bytes_per_count <= 8, "adjust the code below");
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(32/bytes_per_count), L);
+
+      bulk_load_forward(from, data_regs, 4);
+      bulk_store_forward(to, data_regs, 4);
+
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(16/bytes_per_count), L);
+
+      bulk_load_forward(from, data_regs, 2);
+      bulk_store_forward(to, data_regs, 2);
+
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(8/bytes_per_count), L);
+
+      __ ldr(R3, Address(from, 8, post_indexed));
+      __ str(R3, Address(to,   8, post_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 4) {
+      Label L;
+      __ tbz(count, exact_log2(4/bytes_per_count), L);
+
+      __ ldr_w(R3, Address(from, 4, post_indexed));
+      __ str_w(R3, Address(to,   4, post_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 2) {
+      Label L;
+      __ tbz(count, exact_log2(2/bytes_per_count), L);
+
+      __ ldrh(R3, Address(from, 2, post_indexed));
+      __ strh(R3, Address(to,   2, post_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 1) {
+      Label L;
+      __ tbz(count, 0, L);
+
+      __ ldrb(R3, Address(from, 1, post_indexed));
+      __ strb(R3, Address(to,   1, post_indexed));
+
+      __ bind(L);
+    }
+#else
+    __ tst(count, 16 / bytes_per_count);
+    __ ldmia(from, RegisterSet(R3, R6), writeback, ne); // copy 16 bytes
+    __ stmia(to, RegisterSet(R3, R6), writeback, ne);
+
+    __ tst(count, 8 / bytes_per_count);
+    __ ldmia(from, RegisterSet(R3, R4), writeback, ne); // copy 8 bytes
+    __ stmia(to, RegisterSet(R3, R4), writeback, ne);
+
+    if (bytes_per_count <= 4) {
+      __ tst(count, 4 / bytes_per_count);
+      __ ldr(R3, Address(from, 4, post_indexed), ne); // copy 4 bytes
+      __ str(R3, Address(to, 4, post_indexed), ne);
+    }
+
+    if (bytes_per_count <= 2) {
+      __ tst(count, 2 / bytes_per_count);
+      __ ldrh(R3, Address(from, 2, post_indexed), ne); // copy 2 bytes
+      __ strh(R3, Address(to, 2, post_indexed), ne);
+    }
+
+    if (bytes_per_count == 1) {
+      __ tst(count, 1);
+      __ ldrb(R3, Address(from, 1, post_indexed), ne);
+      __ strb(R3, Address(to, 1, post_indexed), ne);
+    }
+
+    __ pop(RegisterSet(R4,R10));
+#endif // AARCH64
+
+    return count_per_loop;
+  }
+
+
+  // Generate the inner loop for backward aligned array copy
+  //
+  // Arguments
+  //      end_from:      src end address, 64 bits  aligned
+  //      end_to:        dst end address, wordSize aligned
+  //      count:         number of elements (32-bit int)
+  //      bytes_per_count: number of bytes for each unit of 'count'
+  //
+  // Return the minimum initial value for count
+  //
+  // Notes:
+  // - 'end_from' aligned on 64-bit (recommended for 32-bit ARM in case this speeds up LDMIA, required for AArch64)
+  // - 'end_to' aligned on wordSize
+  // - 'count' must be greater or equal than the returned value
+  //
+  // Decreases 'end_from' and 'end_to' by count*bytes_per_count.
+  //
+  // Scratches 'count', R3.
+  // On AArch64 also scratches R4-R10; on 32-bit ARM R4-R10 are preserved (saved/restored).
+  //
+  int generate_backward_aligned_copy_loop(Register end_from, Register end_to, Register count, int bytes_per_count) {
+    assert (end_from == R0 && end_to == R1 && count == R2, "adjust the implementation below");
+
+    const int bytes_per_loop = 8*wordSize; // 8 registers are read and written on every loop iteration
+    const int count_per_loop = bytes_per_loop / bytes_per_count;
+
+    arraycopy_loop_config *config=&arraycopy_configurations[ArmCopyPlatform].backward_aligned;
+    int pld_offset = config->pld_distance;
+
+#ifndef AARCH64
+    bool split_read= config->split_ldm;
+    bool split_write= config->split_stm;
+
+    // See the forward copy variant for additional comments.
+
+    __ push(RegisterSet(R4,R10));
+#endif // !AARCH64
+
+    __ sub_32(count, count, count_per_loop);
+
+    const bool prefetch_before = pld_offset < 0;
+    const bool prefetch_after = pld_offset > 0;
+
+    Label L_skip_pld;
+
+    if (pld_offset != 0) {
+      pld_offset = (pld_offset < 0) ? -pld_offset : pld_offset;
+
+      prefetch(end_from, end_to, -wordSize);
+
+      if (prefetch_before) {
+        __ subs_32(count, count, (bytes_per_loop + pld_offset) / bytes_per_count);
+        __ b(L_skip_pld, lt);
+      }
+
+      int offset = ArmCopyCacheLineSize;
+      while (offset <= pld_offset) {
+        prefetch(end_from, end_to, -(wordSize + offset));
+        offset += ArmCopyCacheLineSize;
+      };
+    }
+
+#ifdef AARCH64
+    const Register data_regs[8] = {R3, R4, R5, R6, R7, R8, R9, R10};
+#endif // AARCH64
+    {
+      // LDM (32-bit ARM) / LDP (AArch64) copy of 'bytes_per_loop' bytes
+
+      // 32-bit ARM note: we have tried implementing loop unrolling to skip one
+      // PLD with 64 bytes cache line but the gain was not significant.
+
+      Label L_copy_loop;
+      __ align(OptoLoopAlignment);
+      __ BIND(L_copy_loop);
+
+      if (prefetch_before) {
+        prefetch(end_from, end_to, -(wordSize + bytes_per_loop + pld_offset));
+        __ BIND(L_skip_pld);
+      }
+
+#ifdef AARCH64
+      bulk_load_backward(end_from, data_regs, 8);
+#else
+      if (split_read) {
+        __ ldmdb(end_from, RegisterSet(R7, R10), writeback);
+        __ ldmdb(end_from, RegisterSet(R3, R6), writeback);
+      } else {
+        __ ldmdb(end_from, RegisterSet(R3, R10), writeback);
+      }
+#endif // AARCH64
+
+      __ subs_32(count, count, count_per_loop);
+
+      if (prefetch_after) {
+        prefetch(end_from, end_to, -(wordSize + pld_offset), -bytes_per_loop);
+      }
+
+#ifdef AARCH64
+      bulk_store_backward(end_to, data_regs, 8);
+#else
+      if (split_write) {
+        __ stmdb(end_to, RegisterSet(R7, R10), writeback);
+        __ stmdb(end_to, RegisterSet(R3, R6), writeback);
+      } else {
+        __ stmdb(end_to, RegisterSet(R3, R10), writeback);
+      }
+#endif // AARCH64
+
+      __ b(L_copy_loop, ge);
+
+      if (prefetch_before) {
+        __ cmn_32(count, (bytes_per_loop + pld_offset)/bytes_per_count);
+        __ b(L_skip_pld, ge);
+      }
+    }
+    BLOCK_COMMENT("Remaining bytes:");
+    // still 0..bytes_per_loop-1 aligned bytes to copy, count already decreased by (at least) bytes_per_loop bytes
+
+    // __ add(count, count, ...); // addition useless for the bit tests
+    assert (pld_offset % bytes_per_loop == 0, "decreasing count by pld_offset before loop must not change tested bits");
+
+#ifdef AARCH64
+    assert (bytes_per_loop == 64, "adjust the code below");
+    assert (bytes_per_count <= 8, "adjust the code below");
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(32/bytes_per_count), L);
+
+      bulk_load_backward(end_from, data_regs, 4);
+      bulk_store_backward(end_to, data_regs, 4);
+
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(16/bytes_per_count), L);
+
+      bulk_load_backward(end_from, data_regs, 2);
+      bulk_store_backward(end_to, data_regs, 2);
+
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(8/bytes_per_count), L);
+
+      __ ldr(R3, Address(end_from, -8, pre_indexed));
+      __ str(R3, Address(end_to,   -8, pre_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 4) {
+      Label L;
+      __ tbz(count, exact_log2(4/bytes_per_count), L);
+
+      __ ldr_w(R3, Address(end_from, -4, pre_indexed));
+      __ str_w(R3, Address(end_to,   -4, pre_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 2) {
+      Label L;
+      __ tbz(count, exact_log2(2/bytes_per_count), L);
+
+      __ ldrh(R3, Address(end_from, -2, pre_indexed));
+      __ strh(R3, Address(end_to,   -2, pre_indexed));
+
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 1) {
+      Label L;
+      __ tbz(count, 0, L);
+
+      __ ldrb(R3, Address(end_from, -1, pre_indexed));
+      __ strb(R3, Address(end_to,   -1, pre_indexed));
+
+      __ bind(L);
+    }
+#else
+    __ tst(count, 16 / bytes_per_count);
+    __ ldmdb(end_from, RegisterSet(R3, R6), writeback, ne); // copy 16 bytes
+    __ stmdb(end_to, RegisterSet(R3, R6), writeback, ne);
+
+    __ tst(count, 8 / bytes_per_count);
+    __ ldmdb(end_from, RegisterSet(R3, R4), writeback, ne); // copy 8 bytes
+    __ stmdb(end_to, RegisterSet(R3, R4), writeback, ne);
+
+    if (bytes_per_count <= 4) {
+      __ tst(count, 4 / bytes_per_count);
+      __ ldr(R3, Address(end_from, -4, pre_indexed), ne); // copy 4 bytes
+      __ str(R3, Address(end_to, -4, pre_indexed), ne);
+    }
+
+    if (bytes_per_count <= 2) {
+      __ tst(count, 2 / bytes_per_count);
+      __ ldrh(R3, Address(end_from, -2, pre_indexed), ne); // copy 2 bytes
+      __ strh(R3, Address(end_to, -2, pre_indexed), ne);
+    }
+
+    if (bytes_per_count == 1) {
+      __ tst(count, 1);
+      __ ldrb(R3, Address(end_from, -1, pre_indexed), ne);
+      __ strb(R3, Address(end_to, -1, pre_indexed), ne);
+    }
+
+    __ pop(RegisterSet(R4,R10));
+#endif // AARCH64
+
+    return count_per_loop;
+  }
+
+
+  // Generate the inner loop for shifted forward array copy (unaligned copy).
+  // It can be used when bytes_per_count < wordSize, i.e.
+  //  byte/short copy on 32-bit ARM, byte/short/int/compressed-oop copy on AArch64.
+  //
+  // Arguments
+  //      from:      start src address, 64 bits aligned
+  //      to:        start dst address, (now) wordSize aligned
+  //      count:     number of elements (32-bit int)
+  //      bytes_per_count: number of bytes for each unit of 'count'
+  //      lsr_shift: shift applied to 'old' value to skipped already written bytes
+  //      lsl_shift: shift applied to 'new' value to set the high bytes of the next write
+  //
+  // Return the minimum initial value for count
+  //
+  // Notes:
+  // - 'from' aligned on 64-bit (recommended for 32-bit ARM in case this speeds up LDMIA, required for AArch64)
+  // - 'to' aligned on wordSize
+  // - 'count' must be greater or equal than the returned value
+  // - 'lsr_shift' + 'lsl_shift' = BitsPerWord
+  // - 'bytes_per_count' is 1 or 2 on 32-bit ARM; 1, 2 or 4 on AArch64
+  //
+  // Increases 'to' by count*bytes_per_count.
+  //
+  // Scratches 'from' and 'count', R3-R10, R12
+  //
+  // On entry:
+  // - R12 is preloaded with the first 'BitsPerWord' bits read just before 'from'
+  // - (R12 >> lsr_shift) is the part not yet written (just before 'to')
+  // --> (*to) = (R12 >> lsr_shift) | (*from) << lsl_shift); ...
+  //
+  // This implementation may read more bytes than required.
+  // Actually, it always reads exactly all data from the copied region with upper bound aligned up by wordSize,
+  // so excessive read do not cross a word bound and is thus harmless.
+  //
+  int generate_forward_shifted_copy_loop(Register from, Register to, Register count, int bytes_per_count, int lsr_shift, int lsl_shift) {
+    assert (from == R0 && to == R1 && count == R2, "adjust the implementation below");
+
+    const int bytes_per_loop = 8*wordSize; // 8 registers are read and written on every loop iter
+    const int count_per_loop = bytes_per_loop / bytes_per_count;
+
+    arraycopy_loop_config *config=&arraycopy_configurations[ArmCopyPlatform].forward_shifted;
+    int pld_offset = config->pld_distance;
+
+#ifndef AARCH64
+    bool split_read= config->split_ldm;
+    bool split_write= config->split_stm;
+#endif // !AARCH64
+
+    const bool prefetch_before = pld_offset < 0;
+    const bool prefetch_after = pld_offset > 0;
+    Label L_skip_pld, L_last_read, L_done;
+    if (pld_offset != 0) {
+
+      pld_offset = (pld_offset < 0) ? -pld_offset : pld_offset;
+
+      prefetch(from, to, 0);
+
+      if (prefetch_before) {
+        __ cmp_32(count, count_per_loop);
+        __ b(L_last_read, lt);
+        // skip prefetch for small copies
+        // warning: count is predecreased by the prefetch distance to optimize the inner loop
+        __ subs_32(count, count, ((bytes_per_loop + pld_offset) / bytes_per_count) + count_per_loop);
+        __ b(L_skip_pld, lt);
+      }
+
+      int offset = ArmCopyCacheLineSize;
+      while (offset <= pld_offset) {
+        prefetch(from, to, offset);
+        offset += ArmCopyCacheLineSize;
+      };
+    }
+
+    Label L_shifted_loop;
+
+    __ align(OptoLoopAlignment);
+    __ BIND(L_shifted_loop);
+
+    if (prefetch_before) {
+      // do it early if there might be register locking issues
+      prefetch(from, to, bytes_per_loop + pld_offset);
+      __ BIND(L_skip_pld);
+    } else {
+      __ cmp_32(count, count_per_loop);
+      __ b(L_last_read, lt);
+    }
+
+#ifdef AARCH64
+    const Register data_regs[9] = {R3, R4, R5, R6, R7, R8, R9, R10, R12};
+    __ logical_shift_right(R3, R12, lsr_shift); // part of R12 not yet written
+    __ subs_32(count, count, count_per_loop);
+    bulk_load_forward(from, &data_regs[1], 8);
+#else
+    // read 32 bytes
+    if (split_read) {
+      // if write is not split, use less registers in first set to reduce locking
+      RegisterSet set1 = split_write ? RegisterSet(R4, R7) : RegisterSet(R4, R5);
+      RegisterSet set2 = (split_write ? RegisterSet(R8, R10) : RegisterSet(R6, R10)) | R12;
+      __ ldmia(from, set1, writeback);
+      __ mov(R3, AsmOperand(R12, lsr, lsr_shift)); // part of R12 not yet written
+      __ ldmia(from, set2, writeback);
+      __ subs(count, count, count_per_loop); // XXX: should it be before the 2nd LDM ? (latency vs locking)
+    } else {
+      __ mov(R3, AsmOperand(R12, lsr, lsr_shift)); // part of R12 not yet written
+      __ ldmia(from, RegisterSet(R4, R10) | R12, writeback); // Note: small latency on R4
+      __ subs(count, count, count_per_loop);
+    }
+#endif // AARCH64
+
+    if (prefetch_after) {
+      // do it after the 1st ldm/ldp anyway  (no locking issues with early STM/STP)
+      prefetch(from, to, pld_offset, bytes_per_loop);
+    }
+
+    // prepare (shift) the values in R3..R10
+    __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift)); // merged below low bytes of next val
+    __ logical_shift_right(R4, R4, lsr_shift); // unused part of next val
+    __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift)); // ...
+    __ logical_shift_right(R5, R5, lsr_shift);
+    __ orr(R5, R5, AsmOperand(R6, lsl, lsl_shift));
+    __ logical_shift_right(R6, R6, lsr_shift);
+    __ orr(R6, R6, AsmOperand(R7, lsl, lsl_shift));
+#ifndef AARCH64
+    if (split_write) {
+      // write the first half as soon as possible to reduce stm locking
+      __ stmia(to, RegisterSet(R3, R6), writeback, prefetch_before ? gt : ge);
+    }
+#endif // !AARCH64
+    __ logical_shift_right(R7, R7, lsr_shift);
+    __ orr(R7, R7, AsmOperand(R8, lsl, lsl_shift));
+    __ logical_shift_right(R8, R8, lsr_shift);
+    __ orr(R8, R8, AsmOperand(R9, lsl, lsl_shift));
+    __ logical_shift_right(R9, R9, lsr_shift);
+    __ orr(R9, R9, AsmOperand(R10, lsl, lsl_shift));
+    __ logical_shift_right(R10, R10, lsr_shift);
+    __ orr(R10, R10, AsmOperand(R12, lsl, lsl_shift));
+
+#ifdef AARCH64
+    bulk_store_forward(to, data_regs, 8);
+#else
+    if (split_write) {
+      __ stmia(to, RegisterSet(R7, R10), writeback, prefetch_before ? gt : ge);
+    } else {
+      __ stmia(to, RegisterSet(R3, R10), writeback, prefetch_before ? gt : ge);
+    }
+#endif // AARCH64
+    __ b(L_shifted_loop, gt); // no need to loop if 0 (when count need not be precise modulo bytes_per_loop)
+
+    if (prefetch_before) {
+      // the first loop may end earlier, allowing to skip pld at the end
+      __ cmn_32(count, (bytes_per_loop + pld_offset)/bytes_per_count);
+#ifndef AARCH64
+      __ stmia(to, RegisterSet(R3, R10), writeback); // stmia was skipped
+#endif // !AARCH64
+      __ b(L_skip_pld, ge);
+      __ adds_32(count, count, ((bytes_per_loop + pld_offset) / bytes_per_count) + count_per_loop);
+    }
+
+    __ BIND(L_last_read);
+    __ b(L_done, eq);
+
+#ifdef AARCH64
+    assert(bytes_per_count < 8, "adjust the code below");
+
+    __ logical_shift_right(R3, R12, lsr_shift);
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(32/bytes_per_count), L);
+      bulk_load_forward(from, &data_regs[1], 4);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift));
+      __ logical_shift_right(R4, R4, lsr_shift);
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift));
+      __ logical_shift_right(R5, R5, lsr_shift);
+      __ orr(R5, R5, AsmOperand(R6, lsl, lsl_shift));
+      __ logical_shift_right(R6, R6, lsr_shift);
+      __ orr(R6, R6, AsmOperand(R7, lsl, lsl_shift));
+      bulk_store_forward(to, data_regs, 4);
+      __ logical_shift_right(R3, R7, lsr_shift);
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(16/bytes_per_count), L);
+      bulk_load_forward(from, &data_regs[1], 2);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift));
+      __ logical_shift_right(R4, R4, lsr_shift);
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift));
+      bulk_store_forward(to, data_regs, 2);
+      __ logical_shift_right(R3, R5, lsr_shift);
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(8/bytes_per_count), L);
+      __ ldr(R4, Address(from, 8, post_indexed));
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift));
+      __ str(R3, Address(to, 8, post_indexed));
+      __ logical_shift_right(R3, R4, lsr_shift);
+      __ bind(L);
+    }
+
+    const int have_bytes = lsl_shift/BitsPerByte; // number of already read bytes in R3
+
+    // It remains less than wordSize to write.
+    // Do not check count if R3 already has maximal number of loaded elements (one less than wordSize).
+    if (have_bytes < wordSize - bytes_per_count) {
+      Label L;
+      __ andr(count, count, (uintx)(8/bytes_per_count-1)); // make count exact
+      __ cmp_32(count, have_bytes/bytes_per_count); // do we have enough bytes to store?
+      __ b(L, le);
+      __ ldr(R4, Address(from, 8, post_indexed));
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift));
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(4/bytes_per_count), L);
+      __ str_w(R3, Address(to, 4, post_indexed));
+      if (bytes_per_count < 4) {
+        __ logical_shift_right(R3, R3, 4*BitsPerByte);
+      }
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 2) {
+      Label L;
+      __ tbz(count, exact_log2(2/bytes_per_count), L);
+      __ strh(R3, Address(to, 2, post_indexed));
+      if (bytes_per_count < 2) {
+        __ logical_shift_right(R3, R3, 2*BitsPerByte);
+      }
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 1) {
+      Label L;
+      __ tbz(count, exact_log2(1/bytes_per_count), L);
+      __ strb(R3, Address(to, 1, post_indexed));
+      __ bind(L);
+    }
+#else
+    switch (bytes_per_count) {
+    case 2:
+      __ mov(R3, AsmOperand(R12, lsr, lsr_shift));
+      __ tst(count, 8);
+      __ ldmia(from, RegisterSet(R4, R7), writeback, ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne); // merged below low bytes of next val
+      __ mov(R4, AsmOperand(R4, lsr, lsr_shift), ne); // unused part of next val
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift), ne); // ...
+      __ mov(R5, AsmOperand(R5, lsr, lsr_shift), ne);
+      __ orr(R5, R5, AsmOperand(R6, lsl, lsl_shift), ne);
+      __ mov(R6, AsmOperand(R6, lsr, lsr_shift), ne);
+      __ orr(R6, R6, AsmOperand(R7, lsl, lsl_shift), ne);
+      __ stmia(to, RegisterSet(R3, R6), writeback, ne);
+      __ mov(R3, AsmOperand(R7, lsr, lsr_shift), ne);
+
+      __ tst(count, 4);
+      __ ldmia(from, RegisterSet(R4, R5), writeback, ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne); // merged below low bytes of next val
+      __ mov(R4, AsmOperand(R4, lsr, lsr_shift), ne); // unused part of next val
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift), ne); // ...
+      __ stmia(to, RegisterSet(R3, R4), writeback, ne);
+      __ mov(R3, AsmOperand(R5, lsr, lsr_shift), ne);
+
+      __ tst(count, 2);
+      __ ldr(R4, Address(from, 4, post_indexed), ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne);
+      __ str(R3, Address(to, 4, post_indexed), ne);
+      __ mov(R3, AsmOperand(R4, lsr, lsr_shift), ne);
+
+      __ tst(count, 1);
+      __ strh(R3, Address(to, 2, post_indexed), ne); // one last short
+      break;
+
+    case 1:
+      __ mov(R3, AsmOperand(R12, lsr, lsr_shift));
+      __ tst(count, 16);
+      __ ldmia(from, RegisterSet(R4, R7), writeback, ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne); // merged below low bytes of next val
+      __ mov(R4, AsmOperand(R4, lsr, lsr_shift), ne); // unused part of next val
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift), ne); // ...
+      __ mov(R5, AsmOperand(R5, lsr, lsr_shift), ne);
+      __ orr(R5, R5, AsmOperand(R6, lsl, lsl_shift), ne);
+      __ mov(R6, AsmOperand(R6, lsr, lsr_shift), ne);
+      __ orr(R6, R6, AsmOperand(R7, lsl, lsl_shift), ne);
+      __ stmia(to, RegisterSet(R3, R6), writeback, ne);
+      __ mov(R3, AsmOperand(R7, lsr, lsr_shift), ne);
+
+      __ tst(count, 8);
+      __ ldmia(from, RegisterSet(R4, R5), writeback, ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne); // merged below low bytes of next val
+      __ mov(R4, AsmOperand(R4, lsr, lsr_shift), ne); // unused part of next val
+      __ orr(R4, R4, AsmOperand(R5, lsl, lsl_shift), ne); // ...
+      __ stmia(to, RegisterSet(R3, R4), writeback, ne);
+      __ mov(R3, AsmOperand(R5, lsr, lsr_shift), ne);
+
+      __ tst(count, 4);
+      __ ldr(R4, Address(from, 4, post_indexed), ne);
+      __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ne);
+      __ str(R3, Address(to, 4, post_indexed), ne);
+      __ mov(R3, AsmOperand(R4, lsr, lsr_shift), ne);
+
+      __ andr(count, count, 3);
+      __ cmp(count, 2);
+
+      // Note: R3 might contain enough bytes ready to write (3 needed at most),
+      // thus load on lsl_shift==24 is not needed (in fact forces reading
+      // beyond source buffer end boundary)
+      if (lsl_shift == 8) {
+        __ ldr(R4, Address(from, 4, post_indexed), ge);
+        __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), ge);
+      } else if (lsl_shift == 16) {
+        __ ldr(R4, Address(from, 4, post_indexed), gt);
+        __ orr(R3, R3, AsmOperand(R4, lsl, lsl_shift), gt);
+      }
+
+      __ strh(R3, Address(to, 2, post_indexed), ge); // two last bytes
+      __ mov(R3, AsmOperand(R3, lsr, 16), gt);
+
+      __ tst(count, 1);
+      __ strb(R3, Address(to, 1, post_indexed), ne); // one last byte
+      break;
+    }
+#endif // AARCH64
+
+    __ BIND(L_done);
+    return 0; // no minimum
+  }
+
+  // Generate the inner loop for shifted backward array copy (unaligned copy).
+  // It can be used when bytes_per_count < wordSize, i.e.
+  //  byte/short copy on 32-bit ARM, byte/short/int/compressed-oop copy on AArch64.
+  //
+  // Arguments
+  //      end_from:  end src address, 64 bits aligned
+  //      end_to:    end dst address, (now) wordSize aligned
+  //      count:     number of elements (32-bit int)
+  //      bytes_per_count: number of bytes for each unit of 'count'
+  //      lsl_shift: shift applied to 'old' value to skipped already written bytes
+  //      lsr_shift: shift applied to 'new' value to set the low bytes of the next write
+  //
+  // Return the minimum initial value for count
+  //
+  // Notes:
+  // - 'end_from' aligned on 64-bit (recommended for 32-bit ARM in case this speeds up LDMIA, required for AArch64)
+  // - 'end_to' aligned on wordSize
+  // - 'count' must be greater or equal than the returned value
+  // - 'lsr_shift' + 'lsl_shift' = 'BitsPerWord'
+  // - 'bytes_per_count' is 1 or 2 on 32-bit ARM; 1, 2 or 4 on AArch64
+  //
+  // Decreases 'end_to' by count*bytes_per_count.
+  //
+  // Scratches 'end_from', 'count', R3-R10, R12
+  //
+  // On entry:
+  // - R3 is preloaded with the first 'BitsPerWord' bits read just after 'from'
+  // - (R3 << lsl_shift) is the part not yet written
+  // --> (*--to) = (R3 << lsl_shift) | (*--from) >> lsr_shift); ...
+  //
+  // This implementation may read more bytes than required.
+  // Actually, it always reads exactly all data from the copied region with beginning aligned down by wordSize,
+  // so excessive read do not cross a word bound and is thus harmless.
+  //
+  int generate_backward_shifted_copy_loop(Register end_from, Register end_to, Register count, int bytes_per_count, int lsr_shift, int lsl_shift) {
+    assert (end_from == R0 && end_to == R1 && count == R2, "adjust the implementation below");
+
+    const int bytes_per_loop = 8*wordSize; // 8 registers are read and written on every loop iter
+    const int count_per_loop = bytes_per_loop / bytes_per_count;
+
+    arraycopy_loop_config *config=&arraycopy_configurations[ArmCopyPlatform].backward_shifted;
+    int pld_offset = config->pld_distance;
+
+#ifndef AARCH64
+    bool split_read= config->split_ldm;
+    bool split_write= config->split_stm;
+#endif // !AARCH64
+
+
+    const bool prefetch_before = pld_offset < 0;
+    const bool prefetch_after = pld_offset > 0;
+
+    Label L_skip_pld, L_done, L_last_read;
+    if (pld_offset != 0) {
+
+      pld_offset = (pld_offset < 0) ? -pld_offset : pld_offset;
+
+      prefetch(end_from, end_to, -wordSize);
+
+      if (prefetch_before) {
+        __ cmp_32(count, count_per_loop);
+        __ b(L_last_read, lt);
+
+        // skip prefetch for small copies
+        // warning: count is predecreased by the prefetch distance to optimize the inner loop
+        __ subs_32(count, count, ((bytes_per_loop + pld_offset)/bytes_per_count) + count_per_loop);
+        __ b(L_skip_pld, lt);
+      }
+
+      int offset = ArmCopyCacheLineSize;
+      while (offset <= pld_offset) {
+        prefetch(end_from, end_to, -(wordSize + offset));
+        offset += ArmCopyCacheLineSize;
+      };
+    }
+
+    Label L_shifted_loop;
+    __ align(OptoLoopAlignment);
+    __ BIND(L_shifted_loop);
+
+    if (prefetch_before) {
+      // do the 1st ldm/ldp first anyway (no locking issues with early STM/STP)
+      prefetch(end_from, end_to, -(wordSize + bytes_per_loop + pld_offset));
+      __ BIND(L_skip_pld);
+    } else {
+      __ cmp_32(count, count_per_loop);
+      __ b(L_last_read, lt);
+    }
+
+#ifdef AARCH64
+    __ logical_shift_left(R12, R3, lsl_shift);
+    const Register data_regs[9] = {R3, R4, R5, R6, R7, R8, R9, R10, R12};
+    bulk_load_backward(end_from, data_regs, 8);
+#else
+    if (split_read) {
+      __ ldmdb(end_from, RegisterSet(R7, R10), writeback);
+      __ mov(R12, AsmOperand(R3, lsl, lsl_shift)); // part of R3 not yet written
+      __ ldmdb(end_from, RegisterSet(R3, R6), writeback);
+    } else {
+      __ mov(R12, AsmOperand(R3, lsl, lsl_shift)); // part of R3 not yet written
+      __ ldmdb(end_from, RegisterSet(R3, R10), writeback);
+    }
+#endif // AARCH64
+
+    __ subs_32(count, count, count_per_loop);
+
+    if (prefetch_after) { // do prefetch during ldm/ldp latency
+      prefetch(end_from, end_to, -(wordSize + pld_offset), -bytes_per_loop);
+    }
+
+    // prepare the values in R4..R10,R12
+    __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift)); // merged above high  bytes of prev val
+    __ logical_shift_left(R10, R10, lsl_shift); // unused part of prev val
+    __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift)); // ...
+    __ logical_shift_left(R9, R9, lsl_shift);
+    __ orr(R9, R9, AsmOperand(R8, lsr, lsr_shift));
+    __ logical_shift_left(R8, R8, lsl_shift);
+    __ orr(R8, R8, AsmOperand(R7, lsr, lsr_shift));
+    __ logical_shift_left(R7, R7, lsl_shift);
+    __ orr(R7, R7, AsmOperand(R6, lsr, lsr_shift));
+    __ logical_shift_left(R6, R6, lsl_shift);
+    __ orr(R6, R6, AsmOperand(R5, lsr, lsr_shift));
+#ifndef AARCH64
+    if (split_write) {
+      // store early to reduce locking issues
+      __ stmdb(end_to, RegisterSet(R6, R10) | R12, writeback, prefetch_before ? gt : ge);
+    }
+#endif // !AARCH64
+    __ logical_shift_left(R5, R5, lsl_shift);
+    __ orr(R5, R5, AsmOperand(R4, lsr, lsr_shift));
+    __ logical_shift_left(R4, R4, lsl_shift);
+    __ orr(R4, R4, AsmOperand(R3, lsr, lsr_shift));
+
+#ifdef AARCH64
+    bulk_store_backward(end_to, &data_regs[1], 8);
+#else
+    if (split_write) {
+      __ stmdb(end_to, RegisterSet(R4, R5), writeback, prefetch_before ? gt : ge);
+    } else {
+      __ stmdb(end_to, RegisterSet(R4, R10) | R12, writeback, prefetch_before ? gt : ge);
+    }
+#endif // AARCH64
+
+    __ b(L_shifted_loop, gt); // no need to loop if 0 (when count need not be precise modulo bytes_per_loop)
+
+    if (prefetch_before) {
+      // the first loop may end earlier, allowing to skip pld at the end
+      __ cmn_32(count, ((bytes_per_loop + pld_offset)/bytes_per_count));
+#ifndef AARCH64
+      __ stmdb(end_to, RegisterSet(R4, R10) | R12, writeback); // stmdb was skipped
+#endif // !AARCH64
+      __ b(L_skip_pld, ge);
+      __ adds_32(count, count, ((bytes_per_loop + pld_offset) / bytes_per_count) + count_per_loop);
+    }
+
+    __ BIND(L_last_read);
+    __ b(L_done, eq);
+
+#ifdef AARCH64
+    assert(bytes_per_count < 8, "adjust the code below");
+
+    __ logical_shift_left(R12, R3, lsl_shift);
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(32/bytes_per_count), L);
+      bulk_load_backward(end_from, &data_regs[4], 4);
+
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift));
+      __ logical_shift_left(R10, R10, lsl_shift);
+      __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift));
+      __ logical_shift_left(R9, R9, lsl_shift);
+      __ orr(R9, R9, AsmOperand(R8, lsr, lsr_shift));
+      __ logical_shift_left(R8, R8, lsl_shift);
+      __ orr(R8, R8, AsmOperand(R7, lsr, lsr_shift));
+
+      bulk_store_backward(end_to, &data_regs[5], 4);
+      __ logical_shift_left(R12, R7, lsl_shift);
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(16/bytes_per_count), L);
+      bulk_load_backward(end_from, &data_regs[6], 2);
+
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift));
+      __ logical_shift_left(R10, R10, lsl_shift);
+      __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift));
+
+      bulk_store_backward(end_to, &data_regs[7], 2);
+      __ logical_shift_left(R12, R9, lsl_shift);
+      __ bind(L);
+    }
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(8/bytes_per_count), L);
+      __ ldr(R10, Address(end_from, -8, pre_indexed));
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift));
+      __ str(R12, Address(end_to, -8, pre_indexed));
+      __ logical_shift_left(R12, R10, lsl_shift);
+      __ bind(L);
+    }
+
+    const int have_bytes = lsr_shift/BitsPerByte; // number of already read bytes in R12
+
+    // It remains less than wordSize to write.
+    // Do not check count if R12 already has maximal number of loaded elements (one less than wordSize).
+    if (have_bytes < wordSize - bytes_per_count) {
+      Label L;
+      __ andr(count, count, (uintx)(8/bytes_per_count-1)); // make count exact
+      __ cmp_32(count, have_bytes/bytes_per_count); // do we have enough bytes to store?
+      __ b(L, le);
+      __ ldr(R10, Address(end_from, -8, pre_indexed));
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift));
+      __ bind(L);
+    }
+
+    assert (bytes_per_count <= 4, "must be");
+
+    {
+      Label L;
+      __ tbz(count, exact_log2(4/bytes_per_count), L);
+      __ logical_shift_right(R9, R12, (wordSize-4)*BitsPerByte);
+      __ str_w(R9, Address(end_to, -4, pre_indexed)); // Write 4 MSB
+      if (bytes_per_count < 4) {
+        __ logical_shift_left(R12, R12, 4*BitsPerByte); // Promote remaining bytes to MSB
+      }
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 2) {
+      Label L;
+      __ tbz(count, exact_log2(2/bytes_per_count), L);
+      __ logical_shift_right(R9, R12, (wordSize-2)*BitsPerByte);
+      __ strh(R9, Address(end_to, -2, pre_indexed)); // Write 2 MSB
+      if (bytes_per_count < 2) {
+        __ logical_shift_left(R12, R12, 2*BitsPerByte); // Promote remaining bytes to MSB
+      }
+      __ bind(L);
+    }
+
+    if (bytes_per_count <= 1) {
+      Label L;
+      __ tbz(count, exact_log2(1/bytes_per_count), L);
+      __ logical_shift_right(R9, R12, (wordSize-1)*BitsPerByte);
+      __ strb(R9, Address(end_to, -1, pre_indexed)); // Write 1 MSB
+      __ bind(L);
+    }
+#else
+      switch(bytes_per_count) {
+      case 2:
+      __ mov(R12, AsmOperand(R3, lsl, lsl_shift)); // part of R3 not yet written
+      __ tst(count, 8);
+      __ ldmdb(end_from, RegisterSet(R7,R10), writeback, ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ mov(R10, AsmOperand(R10, lsl, lsl_shift),ne); // unused part of prev val
+      __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift),ne); // ...
+      __ mov(R9, AsmOperand(R9, lsl, lsl_shift),ne);
+      __ orr(R9, R9, AsmOperand(R8, lsr, lsr_shift),ne);
+      __ mov(R8, AsmOperand(R8, lsl, lsl_shift),ne);
+      __ orr(R8, R8, AsmOperand(R7, lsr, lsr_shift),ne);
+      __ stmdb(end_to, RegisterSet(R8,R10)|R12, writeback, ne);
+      __ mov(R12, AsmOperand(R7, lsl, lsl_shift), ne);
+
+      __ tst(count, 4);
+      __ ldmdb(end_from, RegisterSet(R9, R10), writeback, ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ mov(R10, AsmOperand(R10, lsl, lsl_shift),ne); // unused part of prev val
+      __ orr(R10, R10, AsmOperand(R9, lsr,lsr_shift),ne); // ...
+      __ stmdb(end_to, RegisterSet(R10)|R12, writeback, ne);
+      __ mov(R12, AsmOperand(R9, lsl, lsl_shift), ne);
+
+      __ tst(count, 2);
+      __ ldr(R10, Address(end_from, -4, pre_indexed), ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ str(R12, Address(end_to, -4, pre_indexed), ne);
+      __ mov(R12, AsmOperand(R10, lsl, lsl_shift), ne);
+
+      __ tst(count, 1);
+      __ mov(R12, AsmOperand(R12, lsr, lsr_shift),ne);
+      __ strh(R12, Address(end_to, -2, pre_indexed), ne); // one last short
+      break;
+
+      case 1:
+      __ mov(R12, AsmOperand(R3, lsl, lsl_shift)); // part of R3 not yet written
+      __ tst(count, 16);
+      __ ldmdb(end_from, RegisterSet(R7,R10), writeback, ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ mov(R10, AsmOperand(R10, lsl, lsl_shift),ne); // unused part of prev val
+      __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift),ne); // ...
+      __ mov(R9, AsmOperand(R9, lsl, lsl_shift),ne);
+      __ orr(R9, R9, AsmOperand(R8, lsr, lsr_shift),ne);
+      __ mov(R8, AsmOperand(R8, lsl, lsl_shift),ne);
+      __ orr(R8, R8, AsmOperand(R7, lsr, lsr_shift),ne);
+      __ stmdb(end_to, RegisterSet(R8,R10)|R12, writeback, ne);
+      __ mov(R12, AsmOperand(R7, lsl, lsl_shift), ne);
+
+      __ tst(count, 8);
+      __ ldmdb(end_from, RegisterSet(R9,R10), writeback, ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ mov(R10, AsmOperand(R10, lsl, lsl_shift),ne); // unused part of prev val
+      __ orr(R10, R10, AsmOperand(R9, lsr, lsr_shift),ne); // ...
+      __ stmdb(end_to, RegisterSet(R10)|R12, writeback, ne);
+      __ mov(R12, AsmOperand(R9, lsl, lsl_shift), ne);
+
+      __ tst(count, 4);
+      __ ldr(R10, Address(end_from, -4, pre_indexed), ne);
+      __ orr(R12, R12, AsmOperand(R10, lsr, lsr_shift), ne);
+      __ str(R12, Address(end_to, -4, pre_indexed), ne);
+      __ mov(R12, AsmOperand(R10, lsl, lsl_shift), ne);
+
+      __ tst(count, 2);
+      if (lsr_shift != 24) {
+        // avoid useless reading R10 when we already have 3 bytes ready in R12
+        __ ldr(R10, Address(end_from, -4, pre_indexed), ne);
+        __ orr(R12, R12, AsmOperand(R10, lsr,lsr_shift), ne);
+      }
+
+      // Note: R12 contains enough bytes ready to write (3 needed at most)
+      // write the 2 MSBs
+      __ mov(R9, AsmOperand(R12, lsr, 16), ne);
+      __ strh(R9, Address(end_to, -2, pre_indexed), ne);
+      // promote remaining to MSB
+      __ mov(R12, AsmOperand(R12, lsl, 16), ne);
+
+      __ tst(count, 1);
+      // write the MSB of R12
+      __ mov(R12, AsmOperand(R12, lsr, 24), ne);
+      __ strb(R12, Address(end_to, -1, pre_indexed), ne);
+
+      break;
+      }
+#endif // AARCH64
+
+    __ BIND(L_done);
+    return 0; // no minimum
+  }
+
+  // This method is very useful for merging forward/backward implementations
+  Address get_addr_with_indexing(Register base, int delta, bool forward) {
+    if (forward) {
+      return Address(base, delta, post_indexed);
+    } else {
+      return Address(base, -delta, pre_indexed);
+    }
+  }
+
+#ifdef AARCH64
+  // Loads one 'size_in_bytes'-sized value from 'from' in given direction, i.e.
+  //   if forward:  loads value at from and increases from by size
+  //   if !forward: loads value at from-size_in_bytes and decreases from by size
+  void load_one(Register rd, Register from, int size_in_bytes, bool forward) {
+    assert_different_registers(from, rd);
+    Address addr = get_addr_with_indexing(from, size_in_bytes, forward);
+    __ load_sized_value(rd, addr, size_in_bytes, false);
+  }
+
+  // Stores one 'size_in_bytes'-sized value to 'to' in given direction (see load_one)
+  void store_one(Register rd, Register to, int size_in_bytes, bool forward) {
+    assert_different_registers(to, rd);
+    Address addr = get_addr_with_indexing(to, size_in_bytes, forward);
+    __ store_sized_value(rd, addr, size_in_bytes);
+  }
+#else
+  // load_one and store_one are the same as for AArch64 except for
+  //   *) Support for condition execution
+  //   *) Second value register argument for 8-byte values
+
+  void load_one(Register rd, Register from, int size_in_bytes, bool forward, AsmCondition cond = al, Register rd2 = noreg) {
+    assert_different_registers(from, rd, rd2);
+    if (size_in_bytes < 8) {
+      Address addr = get_addr_with_indexing(from, size_in_bytes, forward);
+      __ load_sized_value(rd, addr, size_in_bytes, false, cond);
+    } else {
+      assert (rd2 != noreg, "second value register must be specified");
+      assert (rd->encoding() < rd2->encoding(), "wrong value register set");
+
+      if (forward) {
+        __ ldmia(from, RegisterSet(rd) | rd2, writeback, cond);
+      } else {
+        __ ldmdb(from, RegisterSet(rd) | rd2, writeback, cond);
+      }
+    }
+  }
+
+  void store_one(Register rd, Register to, int size_in_bytes, bool forward, AsmCondition cond = al, Register rd2 = noreg) {
+    assert_different_registers(to, rd, rd2);
+    if (size_in_bytes < 8) {
+      Address addr = get_addr_with_indexing(to, size_in_bytes, forward);
+      __ store_sized_value(rd, addr, size_in_bytes, cond);
+    } else {
+      assert (rd2 != noreg, "second value register must be specified");
+      assert (rd->encoding() < rd2->encoding(), "wrong value register set");
+
+      if (forward) {
+        __ stmia(to, RegisterSet(rd) | rd2, writeback, cond);
+      } else {
+        __ stmdb(to, RegisterSet(rd) | rd2, writeback, cond);
+      }
+    }
+  }
+#endif // AARCH64
+
+  // Copies data from 'from' to 'to' in specified direction to align 'from' by 64 bits.
+  // (on 32-bit ARM 64-bit alignment is better for LDM).
+  //
+  // Arguments:
+  //     from:              beginning (if forward) or upper bound (if !forward) of the region to be read
+  //     to:                beginning (if forward) or upper bound (if !forward) of the region to be written
+  //     count:             32-bit int, maximum number of elements which can be copied
+  //     bytes_per_count:   size of an element
+  //     forward:           specifies copy direction
+  //
+  // Notes:
+  //   'from' and 'to' must be aligned by 'bytes_per_count'
+  //   'count' must not be less than the returned value
+  //   shifts 'from' and 'to' by the number of copied bytes in corresponding direction
+  //   decreases 'count' by the number of elements copied
+  //
+  // Returns maximum number of bytes which may be copied.
+  int align_src(Register from, Register to, Register count, Register tmp, int bytes_per_count, bool forward) {
+    assert_different_registers(from, to, count, tmp);
+#ifdef AARCH64
+    // TODO-AARCH64: replace by simple loop?
+    Label Laligned_by_2, Laligned_by_4, Laligned_by_8;
+
+    if (bytes_per_count == 1) {
+      __ tbz(from, 0, Laligned_by_2);
+      __ sub_32(count, count, 1);
+      load_one(tmp, from, 1, forward);
+      store_one(tmp, to, 1, forward);
+    }
+
+    __ BIND(Laligned_by_2);
+
+    if (bytes_per_count <= 2) {
+      __ tbz(from, 1, Laligned_by_4);
+      __ sub_32(count, count, 2/bytes_per_count);
+      load_one(tmp, from, 2, forward);
+      store_one(tmp, to, 2, forward);
+    }
+
+    __ BIND(Laligned_by_4);
+
+    if (bytes_per_count <= 4) {
+      __ tbz(from, 2, Laligned_by_8);
+      __ sub_32(count, count, 4/bytes_per_count);
+      load_one(tmp, from, 4, forward);
+      store_one(tmp, to, 4, forward);
+    }
+    __ BIND(Laligned_by_8);
+#else // AARCH64
+    if (bytes_per_count < 8) {
+      Label L_align_src;
+      __ BIND(L_align_src);
+      __ tst(from, 7);
+      // ne => not aligned: copy one element and (if bytes_per_count < 4) loop
+      __ sub(count, count, 1, ne);
+      load_one(tmp, from, bytes_per_count, forward, ne);
+      store_one(tmp, to, bytes_per_count, forward, ne);
+      if (bytes_per_count < 4) {
+        __ b(L_align_src, ne); // if bytes_per_count == 4, then 0 or 1 loop iterations are enough
+      }
+    }
+#endif // AARCH64
+    return 7/bytes_per_count;
+  }
+
+  // Copies 'count' of 'bytes_per_count'-sized elements in the specified direction.
+  //
+  // Arguments:
+  //     from:              beginning (if forward) or upper bound (if !forward) of the region to be read
+  //     to:                beginning (if forward) or upper bound (if !forward) of the region to be written
+  //     count:             32-bit int, number of elements to be copied
+  //     entry:             copy loop entry point
+  //     bytes_per_count:   size of an element
+  //     forward:           specifies copy direction
+  //
+  // Notes:
+  //     shifts 'from' and 'to'
+  void copy_small_array(Register from, Register to, Register count, Register tmp, Register tmp2, int bytes_per_count, bool forward, Label & entry) {
+    assert_different_registers(from, to, count, tmp);
+
+    __ align(OptoLoopAlignment);
+#ifdef AARCH64
+    Label L_small_array_done, L_small_array_loop;
+    __ BIND(entry);
+    __ cbz_32(count, L_small_array_done);
+
+    __ BIND(L_small_array_loop);
+    __ subs_32(count, count, 1);
+    load_one(tmp, from, bytes_per_count, forward);
+    store_one(tmp, to, bytes_per_count, forward);
+    __ b(L_small_array_loop, gt);
+
+    __ BIND(L_small_array_done);
+#else
+    Label L_small_loop;
+    __ BIND(L_small_loop);
+    store_one(tmp, to, bytes_per_count, forward, al, tmp2);
+    __ BIND(entry); // entry point
+    __ subs(count, count, 1);
+    load_one(tmp, from, bytes_per_count, forward, ge, tmp2);
+    __ b(L_small_loop, ge);
+#endif // AARCH64
+  }
+
+  // Aligns 'to' by reading one word from 'from' and writting its part to 'to'.
+  //
+  // Arguments:
+  //     to:                beginning (if forward) or upper bound (if !forward) of the region to be written
+  //     count:             32-bit int, number of elements allowed to be copied
+  //     to_remainder:      remainder of dividing 'to' by wordSize
+  //     bytes_per_count:   size of an element
+  //     forward:           specifies copy direction
+  //     Rval:              contains an already read but not yet written word;
+  //                        its' LSBs (if forward) or MSBs (if !forward) are to be written to align 'to'.
+  //
+  // Notes:
+  //     'count' must not be less then the returned value
+  //     'to' must be aligned by bytes_per_count but must not be aligned by wordSize
+  //     shifts 'to' by the number of written bytes (so that it becomes the bound of memory to be written)
+  //     decreases 'count' by the the number of elements written
+  //     Rval's MSBs or LSBs remain to be written further by generate_{forward,backward}_shifted_copy_loop
+  int align_dst(Register to, Register count, Register Rval, Register tmp,
+                                        int to_remainder, int bytes_per_count, bool forward) {
+    assert_different_registers(to, count, tmp, Rval);
+
+    assert (0 < to_remainder && to_remainder < wordSize, "to_remainder is not valid");
+    assert (to_remainder % bytes_per_count == 0, "to must be aligned by bytes_per_count");
+
+    int bytes_to_write = forward ? (wordSize - to_remainder) : to_remainder;
+
+    int offset = 0;
+
+    for (int l = 0; l < LogBytesPerWord; ++l) {
+      int s = (1 << l);
+      if (bytes_to_write & s) {
+        int new_offset = offset + s*BitsPerByte;
+        if (forward) {
+          if (offset == 0) {
+            store_one(Rval, to, s, forward);
+          } else {
+            __ logical_shift_right(tmp, Rval, offset);
+            store_one(tmp, to, s, forward);
+          }
+        } else {
+          __ logical_shift_right(tmp, Rval, BitsPerWord - new_offset);
+          store_one(tmp, to, s, forward);
+        }
+
+        offset = new_offset;
+      }
+    }
+
+    assert (offset == bytes_to_write * BitsPerByte, "all bytes must be copied");
+
+    __ sub_32(count, count, bytes_to_write/bytes_per_count);
+
+    return bytes_to_write / bytes_per_count;
+  }
+
+  // Copies 'count' of elements using shifted copy loop
+  //
+  // Arguments:
+  //     from:              beginning (if forward) or upper bound (if !forward) of the region to be read
+  //     to:                beginning (if forward) or upper bound (if !forward) of the region to be written
+  //     count:             32-bit int, number of elements to be copied
+  //     to_remainder:      remainder of dividing 'to' by wordSize
+  //     bytes_per_count:   size of an element
+  //     forward:           specifies copy direction
+  //     Rval:              contains an already read but not yet written word
+  //
+  //
+  // Notes:
+  //     'count' must not be less then the returned value
+  //     'from' must be aligned by wordSize
+  //     'to' must be aligned by bytes_per_count but must not be aligned by wordSize
+  //     shifts 'to' by the number of copied bytes
+  //
+  // Scratches R3-R10, R12
+  int align_dst_and_generate_shifted_copy_loop(Register from, Register to, Register count, Register Rval,
+                                                        int to_remainder, int bytes_per_count, bool forward) {
+
+    assert (0 < to_remainder && to_remainder < wordSize, "to_remainder is invalid");
+
+    const Register tmp  = forward ? R3 : R12; // TODO-AARCH64: on cojoint_short R4 was used for tmp
+    assert_different_registers(from, to, count, Rval, tmp);
+
+    int required_to_align = align_dst(to, count, Rval, tmp, to_remainder, bytes_per_count, forward);
+
+    int lsr_shift = (wordSize - to_remainder) * BitsPerByte;
+    int lsl_shift = to_remainder * BitsPerByte;
+
+    int min_copy;
+    if (forward) {
+      min_copy = generate_forward_shifted_copy_loop(from, to, count, bytes_per_count, lsr_shift, lsl_shift);
+    } else {
+      min_copy = generate_backward_shifted_copy_loop(from, to, count, bytes_per_count, lsr_shift, lsl_shift);
+    }
+
+    return min_copy + required_to_align;
+  }
+
+  // Copies 'count' of elements using shifted copy loop
+  //
+  // Arguments:
+  //     from:              beginning (if forward) or upper bound (if !forward) of the region to be read
+  //     to:                beginning (if forward) or upper bound (if !forward) of the region to be written
+  //     count:             32-bit int, number of elements to be copied
+  //     bytes_per_count:   size of an element
+  //     forward:           specifies copy direction
+  //
+  // Notes:
+  //     'count' must not be less then the returned value
+  //     'from' must be aligned by wordSize
+  //     'to' must be aligned by bytes_per_count but must not be aligned by wordSize
+  //     shifts 'to' by the number of copied bytes
+  //
+  // Scratches 'from', 'count', R3 and R12.
+  // On AArch64 also scratches R4-R10, on 32-bit ARM saves them to use.
+  int align_dst_and_generate_shifted_copy_loop(Register from, Register to, Register count, int bytes_per_count, bool forward) {
+
+    const Register Rval = forward ? R12 : R3; // as generate_{forward,backward}_shifted_copy_loop expect
+
+    int min_copy = 0;
+
+    // Note: if {seq} is a sequence of numbers, L{seq} means that if the execution reaches this point,
+    // then the remainder of 'to' divided by wordSize is one of elements of {seq}.
+
+#ifdef AARCH64
+    // TODO-AARCH64: simplify, tune
+
+    load_one(Rval, from, wordSize, forward);
+
+    Label L_loop_finished;
+
+    switch (bytes_per_count) {
+      case 4:
+        min_copy = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 4, bytes_per_count, forward);
+        break;
+      case 2:
+      {
+        Label L2, L4, L6;
+
+        __ tbz(to, 1, L4);
+        __ tbz(to, 2, L2);
+
+        __ BIND(L6);
+        int min_copy6 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 6, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L2);
+        int min_copy2 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 2, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L4);
+        int min_copy4 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 4, bytes_per_count, forward);
+
+        min_copy = MAX2(MAX2(min_copy2, min_copy4), min_copy6);
+        break;
+      }
+      case 1:
+      {
+        Label L1, L2, L3, L4, L5, L6, L7;
+        Label L15, L26;
+        Label L246;
+
+        __ tbz(to, 0, L246);
+        __ tbz(to, 1, L15);
+        __ tbz(to, 2, L3);
+
+        __ BIND(L7);
+        int min_copy7 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 7, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L246);
+        __ tbnz(to, 1, L26);
+
+        __ BIND(L4);
+        int min_copy4 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 4, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L15);
+        __ tbz(to, 2, L1);
+
+        __ BIND(L5);
+        int min_copy5 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 5, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L3);
+        int min_copy3 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 3, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L26);
+        __ tbz(to, 2, L2);
+
+        __ BIND(L6);
+        int min_copy6 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 6, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L1);
+        int min_copy1 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 1, bytes_per_count, forward);
+        __ b(L_loop_finished);
+
+        __ BIND(L2);
+        int min_copy2 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 2, bytes_per_count, forward);
+
+
+        min_copy = MAX2(min_copy1, min_copy2);
+        min_copy = MAX2(min_copy,  min_copy3);
+        min_copy = MAX2(min_copy,  min_copy4);
+        min_copy = MAX2(min_copy,  min_copy5);
+        min_copy = MAX2(min_copy,  min_copy6);
+        min_copy = MAX2(min_copy,  min_copy7);
+        break;
+      }
+      default:
+        ShouldNotReachHere();
+        break;
+    }
+    __ BIND(L_loop_finished);
+
+#else
+    __ push(RegisterSet(R4,R10));
+    load_one(Rval, from, wordSize, forward);
+
+    switch (bytes_per_count) {
+      case 2:
+        min_copy = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 2, bytes_per_count, forward);
+        break;
+      case 1:
+      {
+        Label L1, L2, L3;
+        int min_copy1, min_copy2, min_copy3;
+
+        Label L_loop_finished;
+
+        if (forward) {
+            __ tbz(to, 0, L2);
+            __ tbz(to, 1, L1);
+
+            __ BIND(L3);
+            min_copy3 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 3, bytes_per_count, forward);
+            __ b(L_loop_finished);
+
+            __ BIND(L1);
+            min_copy1 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 1, bytes_per_count, forward);
+            __ b(L_loop_finished);
+
+            __ BIND(L2);
+            min_copy2 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 2, bytes_per_count, forward);
+        } else {
+            __ tbz(to, 0, L2);
+            __ tbnz(to, 1, L3);
+
+            __ BIND(L1);
+            min_copy1 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 1, bytes_per_count, forward);
+            __ b(L_loop_finished);
+
+             __ BIND(L3);
+            min_copy3 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 3, bytes_per_count, forward);
+            __ b(L_loop_finished);
+
+           __ BIND(L2);
+            min_copy2 = align_dst_and_generate_shifted_copy_loop(from, to, count, Rval, 2, bytes_per_count, forward);
+        }
+
+        min_copy = MAX2(MAX2(min_copy1, min_copy2), min_copy3);
+
+        __ BIND(L_loop_finished);
+
+        break;
+      }
+      default:
+        ShouldNotReachHere();
+        break;
+    }
+
+    __ pop(RegisterSet(R4,R10));
+#endif // AARCH64
+
+    return min_copy;
+  }
+
+#ifndef PRODUCT
+  int * get_arraycopy_counter(int bytes_per_count) {
+    switch (bytes_per_count) {
+      case 1:
+        return &SharedRuntime::_jbyte_array_copy_ctr;
+      case 2:
+        return &SharedRuntime::_jshort_array_copy_ctr;
+      case 4:
+        return &SharedRuntime::_jint_array_copy_ctr;
+      case 8:
+        return &SharedRuntime::_jlong_array_copy_ctr;
+      default:
+        ShouldNotReachHere();
+        return NULL;
+    }
+  }
+#endif // !PRODUCT
+
+  //
+  //  Generate stub for primitive array copy.  If "aligned" is true, the
+  //  "from" and "to" addresses are assumed to be heapword aligned.
+  //
+  //  If "disjoint" is true, arrays are assumed to be disjoint, otherwise they may overlap and
+  //  "nooverlap_target" must be specified as the address to jump if they don't.
+  //
+  // Arguments for generated stub:
+  //      from:  R0
+  //      to:    R1
+  //      count: R2 treated as signed 32-bit int
+  //
+  address generate_primitive_copy(bool aligned, const char * name, bool status, int bytes_per_count, bool disjoint, address nooverlap_target = NULL) {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", name);
+    address start = __ pc();
+
+    const Register from  = R0;   // source array address
+    const Register to    = R1;   // destination array address
+    const Register count = R2;   // elements count
+    const Register tmp1  = R3;
+    const Register tmp2  = R12;
+
+    if (!aligned)  {
+      BLOCK_COMMENT("Entry:");
+    }
+
+    __ zap_high_non_significant_bits(R2);
+
+    if (!disjoint) {
+      assert (nooverlap_target != NULL, "must be specified for conjoint case");
+      array_overlap_test(nooverlap_target, exact_log2(bytes_per_count), tmp1, tmp2);
+    }
+
+    inc_counter_np(*get_arraycopy_counter(bytes_per_count), tmp1, tmp2);
+
+    // Conjoint case: since execution reaches this point, the arrays overlap, so performing backward copy
+    // Disjoint case: perform forward copy
+    bool forward = disjoint;
+
+
+    if (!forward) {
+      // Set 'from' and 'to' to upper bounds
+      int log_bytes_per_count = exact_log2(bytes_per_count);
+      __ add_ptr_scaled_int32(to,   to,   count, log_bytes_per_count);
+      __ add_ptr_scaled_int32(from, from, count, log_bytes_per_count);
+    }
+
+    // There are two main copy loop implementations:
+    //  *) The huge and complex one applicable only for large enough arrays
+    //  *) The small and simple one applicable for any array (but not efficient for large arrays).
+    // Currently "small" implementation is used if and only if the "large" one could not be used.
+    // XXX optim: tune the limit higher ?
+    // Large implementation lower applicability bound is actually determined by
+    // aligned copy loop which require <=7 bytes for src alignment, and 8 words for aligned copy loop.
+    const int small_copy_limit = (8*wordSize + 7) / bytes_per_count;
+
+    Label L_small_array;
+    __ cmp_32(count, small_copy_limit);
+    __ b(L_small_array, le); // TODO-AARCH64: le vs lt
+
+    // Otherwise proceed with large implementation.
+
+    bool from_is_aligned = (bytes_per_count >= 8);
+    if (aligned && forward && (HeapWordSize % 8 == 0)) {
+        // if 'from' is heapword aligned and HeapWordSize is divisible by 8,
+        //  then from is aligned by 8
+        from_is_aligned = true;
+    }
+
+    int count_required_to_align = from_is_aligned ? 0 : align_src(from, to, count, tmp1, bytes_per_count, forward);
+    assert (small_copy_limit >= count_required_to_align, "alignment could exhaust count");
+
+    // now 'from' is aligned
+
+    bool to_is_aligned = false;
+
+    if (bytes_per_count >= wordSize) {
+      // 'to' is aligned by bytes_per_count, so it is aligned by wordSize
+      to_is_aligned = true;
+    } else {
+      if (aligned && (8 % HeapWordSize == 0) && (HeapWordSize % wordSize == 0)) {
+        // Originally 'from' and 'to' were heapword aligned;
+        // (from - to) has not been changed, so since now 'from' is 8-byte aligned, then it is also heapword aligned,
+        //  so 'to' is also heapword aligned and thus aligned by wordSize.
+        to_is_aligned = true;
+      }
+    }
+
+    Label L_unaligned_dst;
+
+    if (!to_is_aligned) {
+      BLOCK_COMMENT("Check dst alignment:");
+      __ tst(to, wordSize - 1);
+      __ b(L_unaligned_dst, ne); // 'to' is not aligned
+    }
+
+    // 'from' and 'to' are properly aligned
+
+    int min_copy;
+    if (forward) {
+      min_copy = generate_forward_aligned_copy_loop (from, to, count, bytes_per_count);
+    } else {
+      min_copy = generate_backward_aligned_copy_loop(from, to, count, bytes_per_count);
+    }
+    assert(small_copy_limit >= count_required_to_align + min_copy, "first loop might exhaust count");
+
+    if (status) {
+      __ mov(R0, 0); // OK
+    }
+
+    __ ret();
+
+    {
+      copy_small_array(from, to, count, tmp1, tmp2, bytes_per_count, forward, L_small_array /* entry */);
+
+      if (status) {
+        __ mov(R0, 0); // OK
+      }
+
+      __ ret();
+    }
+
+    if (! to_is_aligned) {
+      __ BIND(L_unaligned_dst);
+      int min_copy_shifted = align_dst_and_generate_shifted_copy_loop(from, to, count, bytes_per_count, forward);
+      assert (small_copy_limit >= count_required_to_align + min_copy_shifted, "first loop might exhaust count");
+
+      if (status) {
+        __ mov(R0, 0); // OK
+      }
+
+      __ ret();
+    }
+
+    return start;
+  }
+
+#if INCLUDE_ALL_GCS
+  //
+  //  Generate pre-write barrier for array.
+  //
+  //  Input:
+  //     addr     - register containing starting address
+  //     count    - register containing element count, 32-bit int
+  //     callee_saved_regs -
+  //                the call must preserve this number of registers: R0, R1, ..., R[callee_saved_regs-1]
+  //
+  //  callee_saved_regs must include addr and count
+  //  Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR) except for callee_saved_regs.
+  void gen_write_ref_array_pre_barrier(Register addr, Register count, int callee_saved_regs) {
+    BarrierSet* bs = Universe::heap()->barrier_set();
+    if (bs->has_write_ref_pre_barrier()) {
+      assert(bs->has_write_ref_array_pre_opt(),
+             "Else unsupported barrier set.");
+
+      assert( addr->encoding() < callee_saved_regs, "addr must be saved");
+      assert(count->encoding() < callee_saved_regs, "count must be saved");
+
+      BLOCK_COMMENT("PreBarrier");
+
+#ifdef AARCH64
+      callee_saved_regs = round_to(callee_saved_regs, 2);
+      for (int i = 0; i < callee_saved_regs; i += 2) {
+        __ raw_push(as_Register(i), as_Register(i+1));
+      }
+#else
+      RegisterSet saved_regs = RegisterSet(R0, as_Register(callee_saved_regs-1));
+      __ push(saved_regs | R9ifScratched);
+#endif // AARCH64
+
+      if (addr != R0) {
+        assert_different_registers(count, R0);
+        __ mov(R0, addr);
+      }
+#ifdef AARCH64
+      __ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_pre takes size_t
+#else
+      if (count != R1) {
+        __ mov(R1, count);
+      }
+#endif // AARCH64
+
+      __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre));
+
+#ifdef AARCH64
+      for (int i = callee_saved_regs - 2; i >= 0; i -= 2) {
+        __ raw_pop(as_Register(i), as_Register(i+1));
+      }
+#else
+      __ pop(saved_regs | R9ifScratched);
+#endif // AARCH64
+    }
+  }
+#endif // INCLUDE_ALL_GCS
+
+  //
+  //  Generate post-write barrier for array.
+  //
+  //  Input:
+  //     addr     - register containing starting address (can be scratched)
+  //     count    - register containing element count, 32-bit int (can be scratched)
+  //     tmp      - scratch register
+  //
+  //  Note: LR can be scratched but might be equal to addr, count or tmp
+  //  Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+  void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp) {
+    assert_different_registers(addr, count, tmp);
+    BarrierSet* bs = Universe::heap()->barrier_set();
+
+    switch (bs->kind()) {
+    case BarrierSet::G1SATBCTLogging:
+      {
+        BLOCK_COMMENT("G1PostBarrier");
+        if (addr != R0) {
+          assert_different_registers(count, R0);
+          __ mov(R0, addr);
+        }
+#ifdef AARCH64
+        __ zero_extend(R1, count, 32); // BarrierSet::static_write_ref_array_post takes size_t
+#else
+        if (count != R1) {
+          __ mov(R1, count);
+        }
+#if R9_IS_SCRATCHED
+        // Safer to save R9 here since callers may have been written
+        // assuming R9 survives. This is suboptimal but is not in
+        // general worth optimizing for the few platforms where R9
+        // is scratched. Note that the optimization might not be to
+        // difficult for this particular call site.
+        __ push(R9);
+#endif
+#endif // !AARCH64
+        __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post));
+#ifndef AARCH64
+#if R9_IS_SCRATCHED
+        __ pop(R9);
+#endif
+#endif // !AARCH64
+      }
+      break;
+    case BarrierSet::CardTableForRS:
+    case BarrierSet::CardTableExtension:
+      {
+        BLOCK_COMMENT("CardTablePostBarrier");
+        CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
+        assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+
+        Label L_cardtable_loop;
+
+        __ add_ptr_scaled_int32(count, addr, count, LogBytesPerHeapOop);
+        __ sub(count, count, BytesPerHeapOop);                            // last addr
+
+        __ logical_shift_right(addr, addr, CardTableModRefBS::card_shift);
+        __ logical_shift_right(count, count, CardTableModRefBS::card_shift);
+        __ sub(count, count, addr); // nb of cards
+
+        // warning: Rthread has not been preserved
+        __ mov_address(tmp, (address) ct->byte_map_base, symbolic_Relocation::card_table_reference);
+        __ add(addr,tmp, addr);
+
+        Register zero = __ zero_register(tmp);
+
+        __ BIND(L_cardtable_loop);
+        __ strb(zero, Address(addr, 1, post_indexed));
+        __ subs(count, count, 1);
+        __ b(L_cardtable_loop, ge);
+      }
+      break;
+    case BarrierSet::ModRef:
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+
+  // Generates pattern of code to be placed after raw data copying in generate_oop_copy
+  // Includes return from arraycopy stub.
+  //
+  // Arguments:
+  //     to:       destination pointer after copying.
+  //               if 'forward' then 'to' == upper bound, else 'to' == beginning of the modified region
+  //     count:    total number of copied elements, 32-bit int
+  //
+  // Blows all volatile (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR) and 'to', 'count', 'tmp' registers.
+  void oop_arraycopy_stub_epilogue_helper(Register to, Register count, Register tmp, bool status, bool forward) {
+    assert_different_registers(to, count, tmp);
+
+    if (forward) {
+      // 'to' is upper bound of the modified region
+      // restore initial dst:
+      __ sub_ptr_scaled_int32(to, to, count, LogBytesPerHeapOop);
+    }
+
+    // 'to' is the beginning of the region
+
+    gen_write_ref_array_post_barrier(to, count, tmp);
+
+    if (status) {
+      __ mov(R0, 0); // OK
+    }
+
+#ifdef AARCH64
+    __ raw_pop(LR, ZR);
+    __ ret();
+#else
+    __ pop(PC);
+#endif // AARCH64
+  }
+
+
+  //  Generate stub for assign-compatible oop copy.  If "aligned" is true, the
+  //  "from" and "to" addresses are assumed to be heapword aligned.
+  //
+  //  If "disjoint" is true, arrays are assumed to be disjoint, otherwise they may overlap and
+  //  "nooverlap_target" must be specified as the address to jump if they don't.
+  //
+  // Arguments for generated stub:
+  //      from:  R0
+  //      to:    R1
+  //      count: R2 treated as signed 32-bit int
+  //
+  address generate_oop_copy(bool aligned, const char * name, bool status, bool disjoint, address nooverlap_target = NULL) {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", name);
+    address start = __ pc();
+
+    Register from  = R0;
+    Register to    = R1;
+    Register count = R2;
+    Register tmp1  = R3;
+    Register tmp2  = R12;
+
+
+    if (!aligned) {
+      BLOCK_COMMENT("Entry:");
+    }
+
+    __ zap_high_non_significant_bits(R2);
+
+    if (!disjoint) {
+      assert (nooverlap_target != NULL, "must be specified for conjoint case");
+      array_overlap_test(nooverlap_target, LogBytesPerHeapOop, tmp1, tmp2);
+    }
+
+    inc_counter_np(SharedRuntime::_oop_array_copy_ctr, tmp1, tmp2);
+
+    // Conjoint case: since execution reaches this point, the arrays overlap, so performing backward copy
+    // Disjoint case: perform forward copy
+    bool forward = disjoint;
+
+    const int bytes_per_count = BytesPerHeapOop;
+    const int log_bytes_per_count = LogBytesPerHeapOop;
+
+    const Register saved_count = LR;
+    const int callee_saved_regs = 3; // R0-R2
+
+    // LR is used later to save barrier args
+#ifdef AARCH64
+    __ raw_push(LR, ZR);
+#else
+    __ push(LR);
+#endif // AARCH64
+
+#if INCLUDE_ALL_GCS
+    gen_write_ref_array_pre_barrier(to, count, callee_saved_regs);
+#endif // INCLUDE_ALL_GCS
+
+    // save arguments for barrier generation (after the pre barrier)
+    __ mov(saved_count, count);
+
+    if (!forward) {
+      __ add_ptr_scaled_int32(to,   to,   count, log_bytes_per_count);
+      __ add_ptr_scaled_int32(from, from, count, log_bytes_per_count);
+    }
+
+    // for short arrays, just do single element copy
+    Label L_small_array;
+    const int small_copy_limit = (8*wordSize + 7)/bytes_per_count; // XXX optim: tune the limit higher ?
+    __ cmp_32(count, small_copy_limit);
+    __ b(L_small_array, le);
+
+    bool from_is_aligned = (bytes_per_count >= 8);
+    if (aligned && forward && (HeapWordSize % 8 == 0)) {
+        // if 'from' is heapword aligned and HeapWordSize is divisible by 8,
+        //  then from is aligned by 8
+        from_is_aligned = true;
+    }
+
+    int count_required_to_align = from_is_aligned ? 0 : align_src(from, to, count, tmp1, bytes_per_count, forward);
+    assert (small_copy_limit >= count_required_to_align, "alignment could exhaust count");
+
+    // now 'from' is aligned
+
+    bool to_is_aligned = false;
+
+    if (bytes_per_count >= wordSize) {
+      // 'to' is aligned by bytes_per_count, so it is aligned by wordSize
+      to_is_aligned = true;
+    } else {
+      if (aligned && (8 % HeapWordSize == 0) && (HeapWordSize % wordSize == 0)) {
+        // Originally 'from' and 'to' were heapword aligned;
+        // (from - to) has not been changed, so since now 'from' is 8-byte aligned, then it is also heapword aligned,
+        //  so 'to' is also heapword aligned and thus aligned by wordSize.
+        to_is_aligned = true;
+      }
+    }
+
+    Label L_unaligned_dst;
+
+    if (!to_is_aligned) {
+      BLOCK_COMMENT("Check dst alignment:");
+      __ tst(to, wordSize - 1);
+      __ b(L_unaligned_dst, ne); // 'to' is not aligned
+    }
+
+    int min_copy;
+    if (forward) {
+      min_copy = generate_forward_aligned_copy_loop(from, to, count, bytes_per_count);
+    } else {
+      min_copy = generate_backward_aligned_copy_loop(from, to, count, bytes_per_count);
+    }
+    assert(small_copy_limit >= count_required_to_align + min_copy, "first loop might exhaust count");
+
+    oop_arraycopy_stub_epilogue_helper(to, saved_count, /* tmp */ tmp1, status, forward);
+
+    {
+      copy_small_array(from, to, count, tmp1, noreg, bytes_per_count, forward, L_small_array);
+
+      oop_arraycopy_stub_epilogue_helper(to, saved_count, /* tmp */ tmp1, status, forward);
+    }
+
+    if (!to_is_aligned) {
+      // !to_is_aligned <=> UseCompressedOops && AArch64
+      __ BIND(L_unaligned_dst);
+#ifdef AARCH64
+      assert (UseCompressedOops, "unaligned oop array copy may be requested only with UseCompressedOops");
+#else
+      ShouldNotReachHere();
+#endif // AARCH64
+      int min_copy_shifted = align_dst_and_generate_shifted_copy_loop(from, to, count, bytes_per_count, forward);
+      assert (small_copy_limit >= count_required_to_align + min_copy_shifted, "first loop might exhaust count");
+
+      oop_arraycopy_stub_epilogue_helper(to, saved_count, /* tmp */ tmp1, status, forward);
+    }
+
+    return start;
+  }
+
+  //  Generate 'unsafe' array copy stub
+  //  Though just as safe as the other stubs, it takes an unscaled
+  //  size_t argument instead of an element count.
+  //
+  // Arguments for generated stub:
+  //      from:  R0
+  //      to:    R1
+  //      count: R2 byte count, treated as ssize_t, can be zero
+  //
+  // Examines the alignment of the operands and dispatches
+  // to a long, int, short, or byte copy loop.
+  //
+  address generate_unsafe_copy(const char* name) {
+
+    const Register R0_from   = R0;      // source array address
+    const Register R1_to     = R1;      // destination array address
+    const Register R2_count  = R2;      // elements count
+
+    const Register R3_bits   = R3;      // test copy of low bits
+
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", name);
+    address start = __ pc();
+#ifdef AARCH64
+    __ NOT_IMPLEMENTED();
+    start = NULL;
+#else
+    const Register tmp = Rtemp;
+
+    // bump this on entry, not on exit:
+    inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, R3, tmp);
+
+    __ orr(R3_bits, R0_from, R1_to);
+    __ orr(R3_bits, R2_count, R3_bits);
+
+    __ tst(R3_bits, BytesPerLong-1);
+    __ mov(R2_count,AsmOperand(R2_count,asr,LogBytesPerLong), eq);
+    __ jump(StubRoutines::_jlong_arraycopy, relocInfo::runtime_call_type, tmp, eq);
+
+    __ tst(R3_bits, BytesPerInt-1);
+    __ mov(R2_count,AsmOperand(R2_count,asr,LogBytesPerInt), eq);
+    __ jump(StubRoutines::_jint_arraycopy, relocInfo::runtime_call_type, tmp, eq);
+
+    __ tst(R3_bits, BytesPerShort-1);
+    __ mov(R2_count,AsmOperand(R2_count,asr,LogBytesPerShort), eq);
+    __ jump(StubRoutines::_jshort_arraycopy, relocInfo::runtime_call_type, tmp, eq);
+
+    __ jump(StubRoutines::_jbyte_arraycopy, relocInfo::runtime_call_type, tmp);
+#endif
+    return start;
+  }
+
+  // Helper for generating a dynamic type check.
+  // Smashes only the given temp registers.
+  void generate_type_check(Register sub_klass,
+                           Register super_check_offset,
+                           Register super_klass,
+                           Register tmp1,
+                           Register tmp2,
+                           Register tmp3,
+                           Label& L_success) {
+    assert_different_registers(sub_klass, super_check_offset, super_klass, tmp1, tmp2, tmp3);
+
+    BLOCK_COMMENT("type_check:");
+
+    // If the pointers are equal, we are done (e.g., String[] elements).
+
+    __ cmp(super_klass, sub_klass);
+    __ b(L_success, eq); // fast success
+
+
+    Label L_loop, L_fail;
+
+    int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+
+    // Check the supertype display:
+    __ ldr(tmp1, Address(sub_klass, super_check_offset));
+    __ cmp(tmp1, super_klass);
+    __ b(L_success, eq);
+
+    __ cmp(super_check_offset, sc_offset);
+    __ b(L_fail, ne); // failure
+
+    BLOCK_COMMENT("type_check_slow_path:");
+
+    // a couple of useful fields in sub_klass:
+    int ss_offset = in_bytes(Klass::secondary_supers_offset());
+
+    // Do a linear scan of the secondary super-klass chain.
+
+#ifndef PRODUCT
+    int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
+    __ inc_counter((address) pst_counter, tmp1, tmp2);
+#endif
+
+    Register scan_temp = tmp1;
+    Register count_temp = tmp2;
+
+    // We will consult the secondary-super array.
+    __ ldr(scan_temp, Address(sub_klass, ss_offset));
+
+    Register search_key = super_klass;
+
+    // Load the array length.
+    __ ldr_s32(count_temp, Address(scan_temp, Array<Klass*>::length_offset_in_bytes()));
+    __ add(scan_temp, scan_temp, Array<Klass*>::base_offset_in_bytes());
+
+    __ add(count_temp, count_temp, 1);
+
+    // Top of search loop
+    __ bind(L_loop);
+    // Notes:
+    //  scan_temp starts at the array elements
+    //  count_temp is 1+size
+
+    __ subs(count_temp, count_temp, 1);
+    __ b(L_fail, eq); // not found
+
+    // Load next super to check
+    // In the array of super classes elements are pointer sized.
+    int element_size = wordSize;
+    __ ldr(tmp3, Address(scan_temp, element_size, post_indexed));
+
+    // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
+    __ cmp(tmp3, search_key);
+
+    // A miss means we are NOT a subtype and need to keep looping
+    __ b(L_loop, ne);
+
+    // Falling out the bottom means we found a hit; we ARE a subtype
+
+    // Success.  Cache the super we found and proceed in triumph.
+    __ str(super_klass, Address(sub_klass, sc_offset));
+
+    // Jump to success
+    __ b(L_success);
+
+    // Fall through on failure!
+    __ bind(L_fail);
+  }
+
+  //  Generate stub for checked oop copy.
+  //
+  // Arguments for generated stub:
+  //      from:  R0
+  //      to:    R1
+  //      count: R2 treated as signed 32-bit int
+  //      ckoff: R3 (super_check_offset)
+  //      ckval: R4 (AArch64) / SP[0] (32-bit ARM) (super_klass)
+  //      ret:   R0 zero for success; (-1^K) where K is partial transfer count (32-bit)
+  //
+  address generate_checkcast_copy(const char * name) {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", name);
+    address start = __ pc();
+
+    const Register from  = R0;  // source array address
+    const Register to    = R1;  // destination array address
+    const Register count = R2;  // elements count
+
+    const Register R3_ckoff  = R3;      // super_check_offset
+    const Register R4_ckval  = R4;      // super_klass
+
+    const int callee_saved_regs = AARCH64_ONLY(5) NOT_AARCH64(4); // LR saved differently
+
+    Label load_element, store_element, do_card_marks, fail;
+
+    BLOCK_COMMENT("Entry:");
+
+    __ zap_high_non_significant_bits(R2);
+
+#ifdef AARCH64
+    __ raw_push(LR, ZR);
+    __ raw_push(R19, R20);
+#else
+    int pushed = 0;
+    __ push(LR);
+    pushed+=1;
+#endif // AARCH64
+
+#if INCLUDE_ALL_GCS
+    gen_write_ref_array_pre_barrier(to, count, callee_saved_regs);
+#endif // INCLUDE_ALL_GCS
+
+#ifndef AARCH64
+    const RegisterSet caller_saved_regs = RegisterSet(R4,R6) | RegisterSet(R8,R9) | altFP_7_11;
+    __ push(caller_saved_regs);
+    assert(caller_saved_regs.size() == 6, "check the count");
+    pushed+=6;
+
+    __ ldr(R4_ckval,Address(SP, wordSize*pushed)); // read the argument that was on the stack
+#endif // !AARCH64
+
+    // Save arguments for barrier generation (after the pre barrier):
+    // - must be a caller saved register and not LR
+    // - ARM32: avoid R10 in case RThread is needed
+    const Register saved_count = AARCH64_ONLY(R19) NOT_AARCH64(altFP_7_11);
+#ifdef AARCH64
+    __ mov_w(saved_count, count);
+    __ cbnz_w(count, load_element); // and test count
+#else
+    __ movs(saved_count, count); // and test count
+    __ b(load_element,ne);
+#endif // AARCH64
+
+    // nothing to copy
+    __ mov(R0, 0);
+
+#ifdef AARCH64
+    __ raw_pop(R19, R20);
+    __ raw_pop(LR, ZR);
+    __ ret();
+#else
+    __ pop(caller_saved_regs);
+    __ pop(PC);
+#endif // AARCH64
+
+    // ======== begin loop ========
+    // (Loop is rotated; its entry is load_element.)
+    __ align(OptoLoopAlignment);
+    __ BIND(store_element);
+    if (UseCompressedOops) {
+      __ store_heap_oop(R5, Address(to, BytesPerHeapOop, post_indexed));  // store the oop, changes flags
+      __ subs_32(count,count,1);
+    } else {
+      __ subs_32(count,count,1);
+      __ str(R5, Address(to, BytesPerHeapOop, post_indexed));             // store the oop
+    }
+    __ b(do_card_marks, eq); // count exhausted
+
+    // ======== loop entry is here ========
+    __ BIND(load_element);
+    __ load_heap_oop(R5, Address(from, BytesPerHeapOop, post_indexed));  // load the oop
+    __ cbz(R5, store_element); // NULL
+
+    __ load_klass(R6, R5);
+
+    generate_type_check(R6, R3_ckoff, R4_ckval, /*tmps*/ R12, R8, R9,
+                        // branch to this on success:
+                        store_element);
+    // ======== end loop ========
+
+    // It was a real error; we must depend on the caller to finish the job.
+    // Register count has number of *remaining* oops, saved_count number of *total* oops.
+    // Emit GC store barriers for the oops we have copied
+    // and report their number to the caller (0 or (-1^n))
+    __ BIND(fail);
+
+    // Note: fail marked by the fact that count differs from saved_count
+
+    __ BIND(do_card_marks);
+
+    Register copied = AARCH64_ONLY(R20) NOT_AARCH64(R4); // saved
+    Label L_not_copied;
+
+    __ subs_32(copied, saved_count, count); // copied count (in saved reg)
+    __ b(L_not_copied, eq); // nothing was copied, skip post barrier
+    __ sub(to, to, AsmOperand(copied, lsl, LogBytesPerHeapOop)); // initial to value
+    __ mov(R12, copied); // count arg scratched by post barrier
+
+    gen_write_ref_array_post_barrier(to, R12, R3);
+
+    assert_different_registers(R3,R12,LR,copied,saved_count);
+    inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, R3, R12);
+
+    __ BIND(L_not_copied);
+    __ cmp_32(copied, saved_count); // values preserved in saved registers
+
+#ifdef AARCH64
+    __ csinv(R0, ZR, copied, eq); // 0 if all copied else NOT(copied)
+    __ raw_pop(R19, R20);
+    __ raw_pop(LR, ZR);
+    __ ret();
+#else
+    __ mov(R0, 0, eq); // 0 if all copied
+    __ mvn(R0, copied, ne); // else NOT(copied)
+    __ pop(caller_saved_regs);
+    __ pop(PC);
+#endif // AARCH64
+
+    return start;
+  }
+
+  // Perform range checks on the proposed arraycopy.
+  // Kills the two temps, but nothing else.
+  void arraycopy_range_checks(Register src,     // source array oop
+                              Register src_pos, // source position (32-bit int)
+                              Register dst,     // destination array oop
+                              Register dst_pos, // destination position (32-bit int)
+                              Register length,  // length of copy (32-bit int)
+                              Register temp1, Register temp2,
+                              Label& L_failed) {
+
+    BLOCK_COMMENT("arraycopy_range_checks:");
+
+    //  if (src_pos + length > arrayOop(src)->length() ) FAIL;
+
+    const Register array_length = temp1;  // scratch
+    const Register end_pos      = temp2;  // scratch
+
+    __ add_32(end_pos, length, src_pos);  // src_pos + length
+    __ ldr_s32(array_length, Address(src, arrayOopDesc::length_offset_in_bytes()));
+    __ cmp_32(end_pos, array_length);
+    __ b(L_failed, hi);
+
+    //  if (dst_pos + length > arrayOop(dst)->length() ) FAIL;
+    __ add_32(end_pos, length, dst_pos); // dst_pos + length
+    __ ldr_s32(array_length, Address(dst, arrayOopDesc::length_offset_in_bytes()));
+    __ cmp_32(end_pos, array_length);
+    __ b(L_failed, hi);
+
+    BLOCK_COMMENT("arraycopy_range_checks done");
+  }
+
+  //
+  //  Generate generic array copy stubs
+  //
+  //  Input:
+  //    R0    -  src oop
+  //    R1    -  src_pos (32-bit int)
+  //    R2    -  dst oop
+  //    R3    -  dst_pos (32-bit int)
+  //    R4 (AArch64) / SP[0] (32-bit ARM) -  element count (32-bit int)
+  //
+  //  Output: (32-bit int)
+  //    R0 ==  0  -  success
+  //    R0 <   0  -  need to call System.arraycopy
+  //
+  address generate_generic_copy(const char *name) {
+    Label L_failed, L_objArray;
+
+    // Input registers
+    const Register src      = R0;  // source array oop
+    const Register src_pos  = R1;  // source position
+    const Register dst      = R2;  // destination array oop
+    const Register dst_pos  = R3;  // destination position
+
+    // registers used as temp
+    const Register R5_src_klass = R5; // source array klass
+    const Register R6_dst_klass = R6; // destination array klass
+    const Register R_lh         = AARCH64_ONLY(R7) NOT_AARCH64(altFP_7_11); // layout handler
+    const Register R8_temp      = R8;
+
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", name);
+    address start = __ pc();
+
+    __ zap_high_non_significant_bits(R1);
+    __ zap_high_non_significant_bits(R3);
+    __ zap_high_non_significant_bits(R4);
+
+#ifndef AARCH64
+    int pushed = 0;
+    const RegisterSet saved_regs = RegisterSet(R4,R6) | RegisterSet(R8,R9) | altFP_7_11;
+    __ push(saved_regs);
+    assert(saved_regs.size() == 6, "check the count");
+    pushed+=6;
+#endif // !AARCH64
+
+    // bump this on entry, not on exit:
+    inc_counter_np(SharedRuntime::_generic_array_copy_ctr, R5, R12);
+
+    const Register length   = R4;  // elements count
+#ifndef AARCH64
+    __ ldr(length, Address(SP,4*pushed));
+#endif // !AARCH64
+
+
+    //-----------------------------------------------------------------------
+    // Assembler stubs will be used for this call to arraycopy
+    // if the following conditions are met:
+    //
+    // (1) src and dst must not be null.
+    // (2) src_pos must not be negative.
+    // (3) dst_pos must not be negative.
+    // (4) length  must not be negative.
+    // (5) src klass and dst klass should be the same and not NULL.
+    // (6) src and dst should be arrays.
+    // (7) src_pos + length must not exceed length of src.
+    // (8) dst_pos + length must not exceed length of dst.
+    BLOCK_COMMENT("arraycopy initial argument checks");
+
+    //  if (src == NULL) return -1;
+    __ cbz(src, L_failed);
+
+    //  if (src_pos < 0) return -1;
+    __ cmp_32(src_pos, 0);
+    __ b(L_failed, lt);
+
+    //  if (dst == NULL) return -1;
+    __ cbz(dst, L_failed);
+
+    //  if (dst_pos < 0) return -1;
+    __ cmp_32(dst_pos, 0);
+    __ b(L_failed, lt);
+
+    //  if (length < 0) return -1;
+    __ cmp_32(length, 0);
+    __ b(L_failed, lt);
+
+    BLOCK_COMMENT("arraycopy argument klass checks");
+    //  get src->klass()
+    __ load_klass(R5_src_klass, src);
+
+    // Load layout helper
+    //
+    //  |array_tag|     | header_size | element_type |     |log2_element_size|
+    // 32        30    24            16              8     2                 0
+    //
+    //   array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0
+    //
+
+    int lh_offset = in_bytes(Klass::layout_helper_offset());
+    __ ldr_u32(R_lh, Address(R5_src_klass, lh_offset));
+
+    __ load_klass(R6_dst_klass, dst);
+
+    // Handle objArrays completely differently...
+    juint objArray_lh = Klass::array_layout_helper(T_OBJECT);
+    __ mov_slow(R8_temp, objArray_lh);
+    __ cmp_32(R_lh, R8_temp);
+    __ b(L_objArray,eq);
+
+    //  if (src->klass() != dst->klass()) return -1;
+    __ cmp(R5_src_klass, R6_dst_klass);
+    __ b(L_failed, ne);
+
+    //  if (!src->is_Array()) return -1;
+    __ cmp_32(R_lh, Klass::_lh_neutral_value); // < 0
+    __ b(L_failed, ge);
+
+    arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+                           R8_temp, R6_dst_klass, L_failed);
+
+    {
+      // TypeArrayKlass
+      //
+      // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize);
+      // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize);
+      //
+
+      const Register R6_offset = R6_dst_klass;    // array offset
+      const Register R12_elsize = R12;            // log2 element size
+
+      __ logical_shift_right(R6_offset, R_lh, Klass::_lh_header_size_shift);
+      __ andr(R6_offset, R6_offset, (unsigned int)Klass::_lh_header_size_mask); // array_offset
+      __ add(src, src, R6_offset);       // src array offset
+      __ add(dst, dst, R6_offset);       // dst array offset
+      __ andr(R12_elsize, R_lh, (unsigned int)Klass::_lh_log2_element_size_mask); // log2 element size
+
+      // next registers should be set before the jump to corresponding stub
+      const Register from     = R0;  // source array address
+      const Register to       = R1;  // destination array address
+      const Register count    = R2;  // elements count
+
+      // 'from', 'to', 'count' registers should be set in this order
+      // since they are the same as 'src', 'src_pos', 'dst'.
+
+#ifdef AARCH64
+
+      BLOCK_COMMENT("choose copy loop based on element size and scale indexes");
+      Label Lbyte, Lshort, Lint, Llong;
+
+      __ cbz(R12_elsize, Lbyte);
+
+      assert (LogBytesPerShort < LogBytesPerInt && LogBytesPerInt < LogBytesPerLong, "must be");
+      __ cmp(R12_elsize, LogBytesPerInt);
+      __ b(Lint,  eq);
+      __ b(Llong, gt);
+
+      __ BIND(Lshort);
+      __ add_ptr_scaled_int32(from, src, src_pos, LogBytesPerShort);
+      __ add_ptr_scaled_int32(to,   dst, dst_pos, LogBytesPerShort);
+      __ mov(count, length);
+      __ b(StubRoutines::_jshort_arraycopy);
+
+      __ BIND(Lint);
+      __ add_ptr_scaled_int32(from, src, src_pos, LogBytesPerInt);
+      __ add_ptr_scaled_int32(to,   dst, dst_pos, LogBytesPerInt);
+      __ mov(count, length);
+      __ b(StubRoutines::_jint_arraycopy);
+
+      __ BIND(Lbyte);
+      __ add_ptr_scaled_int32(from, src, src_pos, 0);
+      __ add_ptr_scaled_int32(to,   dst, dst_pos, 0);
+      __ mov(count, length);
+      __ b(StubRoutines::_jbyte_arraycopy);
+
+      __ BIND(Llong);
+      __ add_ptr_scaled_int32(from, src, src_pos, LogBytesPerLong);
+      __ add_ptr_scaled_int32(to,   dst, dst_pos, LogBytesPerLong);
+      __ mov(count, length);
+      __ b(StubRoutines::_jlong_arraycopy);
+
+#else // AARCH64
+
+      BLOCK_COMMENT("scale indexes to element size");
+      __ add(from, src, AsmOperand(src_pos, lsl, R12_elsize));       // src_addr
+      __ add(to, dst, AsmOperand(dst_pos, lsl, R12_elsize));         // dst_addr
+
+      __ mov(count, length);  // length
+
+      // XXX optim: avoid later push in arraycopy variants ?
+
+      __ pop(saved_regs);
+
+      BLOCK_COMMENT("choose copy loop based on element size");
+      __ cmp(R12_elsize, 0);
+      __ b(StubRoutines::_jbyte_arraycopy,eq);
+
+      __ cmp(R12_elsize, LogBytesPerShort);
+      __ b(StubRoutines::_jshort_arraycopy,eq);
+
+      __ cmp(R12_elsize, LogBytesPerInt);
+      __ b(StubRoutines::_jint_arraycopy,eq);
+
+      __ b(StubRoutines::_jlong_arraycopy);
+
+#endif // AARCH64
+    }
+
+    // ObjArrayKlass
+    __ BIND(L_objArray);
+    // live at this point:  R5_src_klass, R6_dst_klass, src[_pos], dst[_pos], length
+
+    Label L_plain_copy, L_checkcast_copy;
+    //  test array classes for subtyping
+    __ cmp(R5_src_klass, R6_dst_klass);         // usual case is exact equality
+    __ b(L_checkcast_copy, ne);
+
+    BLOCK_COMMENT("Identically typed arrays");
+    {
+      // Identically typed arrays can be copied without element-wise checks.
+      arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+                             R8_temp, R_lh, L_failed);
+
+      // next registers should be set before the jump to corresponding stub
+      const Register from     = R0;  // source array address
+      const Register to       = R1;  // destination array address
+      const Register count    = R2;  // elements count
+
+      __ add(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset
+      __ add(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset
+      __ add_ptr_scaled_int32(from, src, src_pos, LogBytesPerHeapOop);         // src_addr
+      __ add_ptr_scaled_int32(to, dst, dst_pos, LogBytesPerHeapOop);           // dst_addr
+      __ BIND(L_plain_copy);
+      __ mov(count, length);
+
+#ifndef AARCH64
+      __ pop(saved_regs); // XXX optim: avoid later push in oop_arraycopy ?
+#endif // !AARCH64
+      __ b(StubRoutines::_oop_arraycopy);
+    }
+
+    {
+      __ BIND(L_checkcast_copy);
+      // live at this point:  R5_src_klass, R6_dst_klass
+
+      // Before looking at dst.length, make sure dst is also an objArray.
+      __ ldr_u32(R8_temp, Address(R6_dst_klass, lh_offset));
+      __ cmp_32(R_lh, R8_temp);
+      __ b(L_failed, ne);
+
+      // It is safe to examine both src.length and dst.length.
+
+      arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+                             R8_temp, R_lh, L_failed);
+
+      // next registers should be set before the jump to corresponding stub
+      const Register from     = R0;  // source array address
+      const Register to       = R1;  // destination array address
+      const Register count    = R2;  // elements count
+
+      // Marshal the base address arguments now, freeing registers.
+      __ add(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset
+      __ add(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset
+      __ add_ptr_scaled_int32(from, src, src_pos, LogBytesPerHeapOop);         // src_addr
+      __ add_ptr_scaled_int32(to, dst, dst_pos, LogBytesPerHeapOop);           // dst_addr
+
+      __ mov(count, length); // length (reloaded)
+
+      Register sco_temp = R3;                   // this register is free now
+      assert_different_registers(from, to, count, sco_temp,
+                                 R6_dst_klass, R5_src_klass);
+
+      // Generate the type check.
+      int sco_offset = in_bytes(Klass::super_check_offset_offset());
+      __ ldr_u32(sco_temp, Address(R6_dst_klass, sco_offset));
+      generate_type_check(R5_src_klass, sco_temp, R6_dst_klass,
+                          R8_temp, R9,
+                          AARCH64_ONLY(R10) NOT_AARCH64(R12),
+                          L_plain_copy);
+
+      // Fetch destination element klass from the ObjArrayKlass header.
+      int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+
+      // the checkcast_copy loop needs two extra arguments:
+      const Register Rdst_elem_klass = AARCH64_ONLY(R4) NOT_AARCH64(R3);
+      __ ldr(Rdst_elem_klass, Address(R6_dst_klass, ek_offset));   // dest elem klass
+#ifndef AARCH64
+      __ pop(saved_regs); // XXX optim: avoid later push in oop_arraycopy ?
+      __ str(Rdst_elem_klass, Address(SP,0));    // dest elem klass argument
+#endif // !AARCH64
+      __ ldr_u32(R3, Address(Rdst_elem_klass, sco_offset));  // sco of elem klass
+      __ b(StubRoutines::_checkcast_arraycopy);
+    }
+
+    __ BIND(L_failed);
+
+#ifndef AARCH64
+    __ pop(saved_regs);
+#endif // !AARCH64
+    __ mvn(R0, 0); // failure, with 0 copied
+    __ ret();
+
+    return start;
+  }
+
+  // Safefetch stubs.
+  void generate_safefetch(const char* name, int size, address* entry, address* fault_pc, address* continuation_pc) {
+    // safefetch signatures:
+    //   int      SafeFetch32(int*      adr, int      errValue);
+    //   intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue);
+    //
+    // arguments:
+    //   R0 = adr
+    //   R1 = errValue
+    //
+    // result:
+    //   R0  = *adr or errValue
+
+    StubCodeMark mark(this, "StubRoutines", name);
+
+    // Entry point, pc or function descriptor.
+    *entry = __ pc();
+
+    // Load *adr into c_rarg2, may fault.
+    *fault_pc = __ pc();
+
+    switch (size) {
+      case 4: // int32_t
+        __ ldr_s32(R1, Address(R0));
+        break;
+
+      case 8: // int64_t
+#ifdef AARCH64
+        __ ldr(R1, Address(R0));
+#else
+        Unimplemented();
+#endif // AARCH64
+        break;
+
+      default:
+        ShouldNotReachHere();
+    }
+
+    // return errValue or *adr
+    *continuation_pc = __ pc();
+    __ mov(R0, R1);
+    __ ret();
+  }
+
+  void generate_arraycopy_stubs() {
+
+    // Note:  the disjoint stubs must be generated first, some of
+    //        the conjoint stubs use them.
+
+    bool status = false; // non failing C2 stubs need not return a status in R0
+
+#ifdef TEST_C2_GENERIC_ARRAYCOPY /* Internal development flag */
+    // With this flag, the C2 stubs are tested by generating calls to
+    // generic_arraycopy instead of Runtime1::arraycopy
+
+    // Runtime1::arraycopy return a status in R0 (0 if OK, else ~copied)
+    // and the result is tested to see whether the arraycopy stub should
+    // be called.
+
+    // When we test arraycopy this way, we must generate extra code in the
+    // arraycopy methods callable from C2 generic_arraycopy to set the
+    // status to 0 for those who always succeed (calling the slow path stub might
+    // lead to errors since the copy has already been performed).
+
+    status = true; // generate a status compatible with C1 calls
+#endif
+
+    // these need always status in case they are called from generic_arraycopy
+    StubRoutines::_jbyte_disjoint_arraycopy  = generate_primitive_copy(false, "jbyte_disjoint_arraycopy",  true, 1, true);
+    StubRoutines::_jshort_disjoint_arraycopy = generate_primitive_copy(false, "jshort_disjoint_arraycopy", true, 2, true);
+    StubRoutines::_jint_disjoint_arraycopy   = generate_primitive_copy(false, "jint_disjoint_arraycopy",   true, 4, true);
+    StubRoutines::_jlong_disjoint_arraycopy  = generate_primitive_copy(false, "jlong_disjoint_arraycopy",  true, 8, true);
+    StubRoutines::_oop_disjoint_arraycopy    = generate_oop_copy      (false, "oop_disjoint_arraycopy",    true,    true);
+
+    StubRoutines::_arrayof_jbyte_disjoint_arraycopy  = generate_primitive_copy(true, "arrayof_jbyte_disjoint_arraycopy", status, 1, true);
+    StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_primitive_copy(true, "arrayof_jshort_disjoint_arraycopy",status, 2, true);
+    StubRoutines::_arrayof_jint_disjoint_arraycopy   = generate_primitive_copy(true, "arrayof_jint_disjoint_arraycopy",  status, 4, true);
+    StubRoutines::_arrayof_jlong_disjoint_arraycopy  = generate_primitive_copy(true, "arrayof_jlong_disjoint_arraycopy", status, 8, true);
+    StubRoutines::_arrayof_oop_disjoint_arraycopy    = generate_oop_copy      (true, "arrayof_oop_disjoint_arraycopy",   status,    true);
+
+    // these need always status in case they are called from generic_arraycopy
+    StubRoutines::_jbyte_arraycopy  = generate_primitive_copy(false, "jbyte_arraycopy",  true, 1, false, StubRoutines::_jbyte_disjoint_arraycopy);
+    StubRoutines::_jshort_arraycopy = generate_primitive_copy(false, "jshort_arraycopy", true, 2, false, StubRoutines::_jshort_disjoint_arraycopy);
+    StubRoutines::_jint_arraycopy   = generate_primitive_copy(false, "jint_arraycopy",   true, 4, false, StubRoutines::_jint_disjoint_arraycopy);
+    StubRoutines::_jlong_arraycopy  = generate_primitive_copy(false, "jlong_arraycopy",  true, 8, false, StubRoutines::_jlong_disjoint_arraycopy);
+    StubRoutines::_oop_arraycopy    = generate_oop_copy      (false, "oop_arraycopy",    true,    false, StubRoutines::_oop_disjoint_arraycopy);
+
+    StubRoutines::_arrayof_jbyte_arraycopy    = generate_primitive_copy(true, "arrayof_jbyte_arraycopy",  status, 1, false, StubRoutines::_arrayof_jbyte_disjoint_arraycopy);
+    StubRoutines::_arrayof_jshort_arraycopy   = generate_primitive_copy(true, "arrayof_jshort_arraycopy", status, 2, false, StubRoutines::_arrayof_jshort_disjoint_arraycopy);
+#ifdef _LP64
+    // since sizeof(jint) < sizeof(HeapWord), there's a different flavor:
+    StubRoutines::_arrayof_jint_arraycopy     = generate_primitive_copy(true, "arrayof_jint_arraycopy",   status, 4, false, StubRoutines::_arrayof_jint_disjoint_arraycopy);
+#else
+    StubRoutines::_arrayof_jint_arraycopy     = StubRoutines::_jint_arraycopy;
+#endif
+    if (BytesPerHeapOop < HeapWordSize) {
+      StubRoutines::_arrayof_oop_arraycopy    = generate_oop_copy      (true, "arrayof_oop_arraycopy",    status,    false, StubRoutines::_arrayof_oop_disjoint_arraycopy);
+    } else {
+      StubRoutines::_arrayof_oop_arraycopy    = StubRoutines::_oop_arraycopy;
+    }
+    StubRoutines::_arrayof_jlong_arraycopy    = StubRoutines::_jlong_arraycopy;
+
+    StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy");
+    StubRoutines::_unsafe_arraycopy    = generate_unsafe_copy("unsafe_arraycopy");
+    StubRoutines::_generic_arraycopy   = generate_generic_copy("generic_arraycopy");
+
+
+  }
+
+#ifndef AARCH64
+#define COMPILE_CRYPTO
+#include "stubRoutinesCrypto_arm.cpp"
+#else
+
+#ifdef COMPILER2
+  // Arguments:
+  //
+  // Inputs:
+  //   c_rarg0   - source byte array address
+  //   c_rarg1   - destination byte array address
+  //   c_rarg2   - K (key) in little endian int array
+  //
+  address generate_aescrypt_encryptBlock() {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock");
+
+    Label L_doLast;
+
+    const Register from        = c_rarg0;  // source array address
+    const Register to          = c_rarg1;  // destination array address
+    const Register key         = c_rarg2;  // key array address
+    const Register keylen      = R8;
+
+    address start = __ pc();
+    __ stp(FP, LR, Address(SP, -2 * wordSize, pre_indexed));
+    __ mov(FP, SP);
+
+    __ ldr_w(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+    __ vld1(V0, Address(from), MacroAssembler::VELEM_SIZE_8, 128); // get 16 bytes of input
+
+    __ vld1(V1, V2, V3, V4, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+
+    int quad = 1;
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V3, V3, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V4, V4, MacroAssembler::VELEM_SIZE_8, quad);
+    __ aese(V0, V1);
+    __ aesmc(V0, V0);
+    __ aese(V0, V2);
+    __ aesmc(V0, V0);
+    __ aese(V0, V3);
+    __ aesmc(V0, V0);
+    __ aese(V0, V4);
+    __ aesmc(V0, V0);
+
+    __ vld1(V1, V2, V3, V4, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V3, V3, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V4, V4, MacroAssembler::VELEM_SIZE_8, quad);
+    __ aese(V0, V1);
+    __ aesmc(V0, V0);
+    __ aese(V0, V2);
+    __ aesmc(V0, V0);
+    __ aese(V0, V3);
+    __ aesmc(V0, V0);
+    __ aese(V0, V4);
+    __ aesmc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ cmp_w(keylen, 44);
+    __ b(L_doLast, eq);
+
+    __ aese(V0, V1);
+    __ aesmc(V0, V0);
+    __ aese(V0, V2);
+    __ aesmc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ cmp_w(keylen, 52);
+    __ b(L_doLast, eq);
+
+    __ aese(V0, V1);
+    __ aesmc(V0, V0);
+    __ aese(V0, V2);
+    __ aesmc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ BIND(L_doLast);
+
+    __ aese(V0, V1);
+    __ aesmc(V0, V0);
+    __ aese(V0, V2);
+
+    __ vld1(V1, Address(key), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ eor(V0, V0, V1, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ vst1(V0, Address(to), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ mov(R0, 0);
+
+    __ mov(SP, FP);
+    __ ldp(FP, LR, Address(SP, 2 * wordSize, post_indexed));
+    __ ret(LR);
+
+    return start;
+  }
+
+  // Arguments:
+  //
+  // Inputs:
+  //   c_rarg0   - source byte array address
+  //   c_rarg1   - destination byte array address
+  //   c_rarg2   - K (key) in little endian int array
+  //
+  address generate_aescrypt_decryptBlock() {
+    assert(UseAES, "need AES instructions and misaligned SSE support");
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock");
+    Label L_doLast;
+
+    const Register from        = c_rarg0;  // source array address
+    const Register to          = c_rarg1;  // destination array address
+    const Register key         = c_rarg2;  // key array address
+    const Register keylen      = R8;
+
+    address start = __ pc();
+    __ stp(FP, LR, Address(SP, -2 * wordSize, pre_indexed));
+    __ mov(FP, SP);
+
+    __ ldr_w(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+    __ vld1(V0, Address(from), MacroAssembler::VELEM_SIZE_8, 128); // get 16 bytes of input
+
+    __ vld1(V5, Address(key, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+
+    int quad = 1;
+    __ rev32(V5, V5, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ vld1(V1, V2, V3, V4, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V3, V3, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V4, V4, MacroAssembler::VELEM_SIZE_8, quad);
+    __ aesd(V0, V1);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V2);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V3);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V4);
+    __ aesimc(V0, V0);
+
+    __ vld1(V1, V2, V3, V4, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V3, V3, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V4, V4, MacroAssembler::VELEM_SIZE_8, quad);
+    __ aesd(V0, V1);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V2);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V3);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V4);
+    __ aesimc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ cmp_w(keylen, 44);
+    __ b(L_doLast, eq);
+
+    __ aesd(V0, V1);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V2);
+    __ aesimc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ cmp_w(keylen, 52);
+    __ b(L_doLast, eq);
+
+    __ aesd(V0, V1);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V2);
+    __ aesimc(V0, V0);
+
+    __ vld1(V1, V2, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V2, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ BIND(L_doLast);
+
+    __ aesd(V0, V1);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V2);
+
+    __ eor(V0, V0, V5, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ vst1(V0, Address(to), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ mov(R0, 0);
+
+    __ mov(SP, FP);
+    __ ldp(FP, LR, Address(SP, 2 * wordSize, post_indexed));
+    __ ret(LR);
+
+
+    return start;
+  }
+
+  // Arguments:
+  //
+  // Inputs:
+  //   c_rarg0   - source byte array address
+  //   c_rarg1   - destination byte array address
+  //   c_rarg2   - K (key) in little endian int array
+  //   c_rarg3   - r vector byte array address
+  //   c_rarg4   - input length
+  //
+  // Output:
+  //   x0        - input length
+  //
+  address generate_cipherBlockChaining_encryptAESCrypt() {
+    assert(UseAES, "need AES instructions and misaligned SSE support");
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
+
+    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
+
+    const Register from        = c_rarg0;  // source array address
+    const Register to          = c_rarg1;  // destination array address
+    const Register key         = c_rarg2;  // key array address
+    const Register rvec        = c_rarg3;  // r byte array initialized from initvector array address
+                                           // and left with the results of the last encryption block
+    const Register len_reg     = c_rarg4;  // src len (must be multiple of blocksize 16)
+    const Register keylen      = R8;
+
+    address start = __ pc();
+    __ stp(FP, LR, Address(SP, -2 * wordSize, pre_indexed));
+    __ mov(FP, SP);
+
+    __ mov(R9, len_reg);
+    __ ldr_w(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+    __ vld1(V0, Address(rvec), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ cmp_w(keylen, 52);
+    __ b(L_loadkeys_44, cc);
+    __ b(L_loadkeys_52, eq);
+
+    __ vld1(V17, V18, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+
+    int quad = 1;
+    __ rev32(V17, V17, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V18, V18, MacroAssembler::VELEM_SIZE_8, quad);
+    __ BIND(L_loadkeys_52);
+    __ vld1(V19, V20, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V19, V19, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V20, V20, MacroAssembler::VELEM_SIZE_8, quad);
+    __ BIND(L_loadkeys_44);
+    __ vld1(V21, V22, V23, V24, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V21, V21, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V22, V22, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V23, V23, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V24, V24, MacroAssembler::VELEM_SIZE_8, quad);
+    __ vld1(V25, V26, V27, V28, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V25, V25, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V26, V26, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V27, V27, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V28, V28, MacroAssembler::VELEM_SIZE_8, quad);
+    __ vld1(V29, V30, V31, Address(key), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V29, V29, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V30, V30, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V31, V31, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ BIND(L_aes_loop);
+    __ vld1(V1, Address(from, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ eor(V0, V0, V1, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ b(L_rounds_44, cc);
+    __ b(L_rounds_52, eq);
+
+    __ aese(V0, V17);
+    __ aesmc(V0, V0);
+    __ aese(V0, V18);
+    __ aesmc(V0, V0);
+    __ BIND(L_rounds_52);
+    __ aese(V0, V19);
+    __ aesmc(V0, V0);
+    __ aese(V0, V20);
+    __ aesmc(V0, V0);
+    __ BIND(L_rounds_44);
+    __ aese(V0, V21);
+    __ aesmc(V0, V0);
+    __ aese(V0, V22);
+    __ aesmc(V0, V0);
+    __ aese(V0, V23);
+    __ aesmc(V0, V0);
+    __ aese(V0, V24);
+    __ aesmc(V0, V0);
+    __ aese(V0, V25);
+    __ aesmc(V0, V0);
+    __ aese(V0, V26);
+    __ aesmc(V0, V0);
+    __ aese(V0, V27);
+    __ aesmc(V0, V0);
+    __ aese(V0, V28);
+    __ aesmc(V0, V0);
+    __ aese(V0, V29);
+    __ aesmc(V0, V0);
+    __ aese(V0, V30);
+    __ eor(V0, V0, V31, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ vst1(V0, Address(to, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ sub(len_reg, len_reg, 16);
+    __ cbnz(len_reg, L_aes_loop);
+
+    __ vst1(V0, Address(rvec), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ mov(R0, R9);
+
+    __ mov(SP, FP);
+    __ ldp(FP, LR, Address(SP, 2 * wordSize, post_indexed));
+    __ ret(LR);
+
+    return start;
+  }
+
+  // Arguments:
+  //
+  // Inputs:
+  //   c_rarg0   - source byte array address
+  //   c_rarg1   - destination byte array address
+  //   c_rarg2   - K (key) in little endian int array
+  //   c_rarg3   - r vector byte array address
+  //   c_rarg4   - input length
+  //
+  // Output:
+  //   rax       - input length
+  //
+  address generate_cipherBlockChaining_decryptAESCrypt() {
+    assert(UseAES, "need AES instructions and misaligned SSE support");
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
+
+    Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
+
+    const Register from        = c_rarg0;  // source array address
+    const Register to          = c_rarg1;  // destination array address
+    const Register key         = c_rarg2;  // key array address
+    const Register rvec        = c_rarg3;  // r byte array initialized from initvector array address
+                                           // and left with the results of the last encryption block
+    const Register len_reg     = c_rarg4;  // src len (must be multiple of blocksize 16)
+    const Register keylen      = R8;
+
+    address start = __ pc();
+    __ stp(FP, LR, Address(SP, -2 * wordSize, pre_indexed));
+    __ mov(FP, SP);
+
+    __ mov(R9, len_reg);
+    __ ldr_w(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+    __ vld1(V2, Address(rvec), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ vld1(V31, Address(key, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+
+    int quad = 1;
+    __ rev32(V31, V31, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ cmp_w(keylen, 52);
+    __ b(L_loadkeys_44, cc);
+    __ b(L_loadkeys_52, eq);
+
+    __ vld1(V17, V18, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V17, V17, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V18, V18, MacroAssembler::VELEM_SIZE_8, quad);
+    __ BIND(L_loadkeys_52);
+    __ vld1(V19, V20, Address(key, 32, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V19, V19, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V20, V20, MacroAssembler::VELEM_SIZE_8, quad);
+    __ BIND(L_loadkeys_44);
+    __ vld1(V21, V22, V23, V24, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V21, V21, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V22, V22, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V23, V23, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V24, V24, MacroAssembler::VELEM_SIZE_8, quad);
+    __ vld1(V25, V26, V27, V28, Address(key, 64, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V25, V25, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V26, V26, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V27, V27, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V28, V28, MacroAssembler::VELEM_SIZE_8, quad);
+    __ vld1(V29, V30, Address(key), MacroAssembler::VELEM_SIZE_8, 128);
+    __ rev32(V29, V29, MacroAssembler::VELEM_SIZE_8, quad);
+    __ rev32(V30, V30, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ BIND(L_aes_loop);
+    __ vld1(V0, Address(from, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ orr(V1, V0, V0, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ b(L_rounds_44, cc);
+    __ b(L_rounds_52, eq);
+
+    __ aesd(V0, V17);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V17);
+    __ aesimc(V0, V0);
+    __ BIND(L_rounds_52);
+    __ aesd(V0, V19);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V20);
+    __ aesimc(V0, V0);
+    __ BIND(L_rounds_44);
+    __ aesd(V0, V21);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V22);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V23);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V24);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V25);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V26);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V27);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V28);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V29);
+    __ aesimc(V0, V0);
+    __ aesd(V0, V30);
+    __ eor(V0, V0, V31, MacroAssembler::VELEM_SIZE_8, quad);
+    __ eor(V0, V0, V2, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ vst1(V0, Address(to, 16, post_indexed), MacroAssembler::VELEM_SIZE_8, 128);
+    __ orr(V2, V1, V1, MacroAssembler::VELEM_SIZE_8, quad);
+
+    __ sub(len_reg, len_reg, 16);
+    __ cbnz(len_reg, L_aes_loop);
+
+    __ vst1(V2, Address(rvec), MacroAssembler::VELEM_SIZE_8, 128);
+
+    __ mov(R0, R9);
+
+    __ mov(SP, FP);
+    __ ldp(FP, LR, Address(SP, 2 * wordSize, post_indexed));
+    __ ret(LR);
+
+    return start;
+  }
+
+#endif // COMPILER2
+#endif // AARCH64
+
+ private:
+
+#undef  __
+#define __ masm->
+
+  //------------------------------------------------------------------------------------------------------------------------
+  // Continuation point for throwing of implicit exceptions that are not handled in
+  // the current activation. Fabricates an exception oop and initiates normal
+  // exception dispatching in this frame.
+  address generate_throw_exception(const char* name, address runtime_entry) {
+    int insts_size = 128;
+    int locs_size  = 32;
+    CodeBuffer code(name, insts_size, locs_size);
+    OopMapSet* oop_maps;
+    int frame_size;
+    int frame_complete;
+
+    oop_maps = new OopMapSet();
+    MacroAssembler* masm = new MacroAssembler(&code);
+
+    address start = __ pc();
+
+    frame_size = 2;
+    __ mov(Rexception_pc, LR);
+    __ raw_push(FP, LR);
+
+    frame_complete = __ pc() - start;
+
+    // Any extra arguments are already supposed to be R1 and R2
+    __ mov(R0, Rthread);
+
+    int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
+    assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+    __ call(runtime_entry);
+    if (pc_offset == -1) {
+      pc_offset = __ offset();
+    }
+
+    // Generate oop map
+    OopMap* map =  new OopMap(frame_size*VMRegImpl::slots_per_word, 0);
+    oop_maps->add_gc_map(pc_offset, map);
+    __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+    __ raw_pop(FP, LR);
+    __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+
+    RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+                                                      frame_size, oop_maps, false);
+    return stub->entry_point();
+  }
+
+  //---------------------------------------------------------------------------
+  // Initialization
+
+  void generate_initial() {
+    // Generates all stubs and initializes the entry points
+
+    //------------------------------------------------------------------------------------------------------------------------
+    // entry points that exist in all platforms
+    // Note: This is code that could be shared among different platforms - however the benefit seems to be smaller than
+    //       the disadvantage of having a much more complicated generator structure. See also comment in stubRoutines.hpp.
+    StubRoutines::_forward_exception_entry      = generate_forward_exception();
+
+    StubRoutines::_call_stub_entry              =
+      generate_call_stub(StubRoutines::_call_stub_return_address);
+    // is referenced by megamorphic call
+    StubRoutines::_catch_exception_entry        = generate_catch_exception();
+
+    // stub for throwing stack overflow error used both by interpreter and compiler
+    StubRoutines::_throw_StackOverflowError_entry  = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
+
+#ifndef AARCH64
+    // integer division used both by interpreter and compiler
+    StubRoutines::Arm::_idiv_irem_entry = generate_idiv_irem();
+
+    StubRoutines::_atomic_add_entry = generate_atomic_add();
+    StubRoutines::_atomic_xchg_entry = generate_atomic_xchg();
+    StubRoutines::_atomic_cmpxchg_entry = generate_atomic_cmpxchg();
+    StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long();
+    StubRoutines::_atomic_load_long_entry = generate_atomic_load_long();
+    StubRoutines::_atomic_store_long_entry = generate_atomic_store_long();
+#endif // !AARCH64
+  }
+
+  void generate_all() {
+    // Generates all stubs and initializes the entry points
+
+#ifdef COMPILER2
+    // Generate partial_subtype_check first here since its code depends on
+    // UseZeroBaseCompressedOops which is defined after heap initialization.
+    StubRoutines::Arm::_partial_subtype_check                = generate_partial_subtype_check();
+#endif
+    // These entry points require SharedInfo::stack0 to be set up in non-core builds
+    // and need to be relocatable, so they each fabricate a RuntimeStub internally.
+    StubRoutines::_throw_AbstractMethodError_entry         = generate_throw_exception("AbstractMethodError throw_exception",          CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError));
+    StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError));
+    StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call));
+
+    //------------------------------------------------------------------------------------------------------------------------
+    // entry points that are platform specific
+
+    // support for verify_oop (must happen after universe_init)
+    StubRoutines::_verify_oop_subroutine_entry     = generate_verify_oop();
+
+    // arraycopy stubs used by compilers
+    generate_arraycopy_stubs();
+
+    // Safefetch stubs.
+    generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
+                                                   &StubRoutines::_safefetch32_fault_pc,
+                                                   &StubRoutines::_safefetch32_continuation_pc);
+#ifdef AARCH64
+    generate_safefetch("SafeFetchN", wordSize, &StubRoutines::_safefetchN_entry,
+                                               &StubRoutines::_safefetchN_fault_pc,
+                                               &StubRoutines::_safefetchN_continuation_pc);
+#ifdef COMPILER2
+    if (UseAESIntrinsics) {
+      StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
+      StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
+      StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
+      StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt();
+    }
+#endif
+#else
+    assert (sizeof(int) == wordSize, "32-bit architecture");
+    StubRoutines::_safefetchN_entry           = StubRoutines::_safefetch32_entry;
+    StubRoutines::_safefetchN_fault_pc        = StubRoutines::_safefetch32_fault_pc;
+    StubRoutines::_safefetchN_continuation_pc = StubRoutines::_safefetch32_continuation_pc;
+#endif // AARCH64
+
+#ifdef COMPILE_CRYPTO
+    // generate AES intrinsics code
+    if (UseAESIntrinsics) {
+      aes_init();
+      StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
+      StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
+      StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
+      StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt();
+    }
+#endif // COMPILE_CRYPTO
+  }
+
+
+ public:
+  StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
+    if (all) {
+      generate_all();
+    } else {
+      generate_initial();
+    }
+  }
+}; // end class declaration
+
+void StubGenerator_generate(CodeBuffer* code, bool all) {
+  StubGenerator g(code, all);
+}
diff --git a/hotspot/src/cpu/arm/vm/stubRoutinesCrypto_arm.cpp b/hotspot/src/cpu/arm/vm/stubRoutinesCrypto_arm.cpp
new file mode 100644
index 0000000..c82fa6c
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/stubRoutinesCrypto_arm.cpp
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifdef COMPILE_CRYPTO
+
+// The Rijndael S-box and inverted S-box are embedded here for a faster access.
+//
+// Note about lookup tables (T1...T4 and T5..T8):
+// The tables (boxes) combine ahead-of-time precalculated transposition and mixing steps as
+// an alternative to a runtime calculation.
+// The tables are statically generated in com/sun/crypto/provider/AESCrypt class.
+// Only the first table reference is passed to AES methods below. The other 3 tables
+// in ecryption and decryption are calculated in runtime by rotating the T1 result accordingly.
+// It is a free operation on ARM with embedded register-shifted-register EOR capability.
+// The table reference is passed in a form of a last argument on the parametes list.
+// The tables lookup method proves to perform better then a runtime Galois Field caclulation,
+// due to a lack of HW acceleration for the later.
+
+unsigned char * SBox;
+unsigned char * SInvBox;
+
+void  aes_init() {
+
+  const static unsigned char Si[256] =
+    {
+      0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
+      0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
+      0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+      0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
+      0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
+      0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+      0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
+      0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
+      0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+      0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
+      0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
+      0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+      0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
+      0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
+      0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+      0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
+      0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
+      0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+      0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
+      0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
+      0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+      0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
+      0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
+      0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+      0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
+      0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
+      0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+      0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
+      0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
+      0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+      0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
+      0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
+    };
+
+  static const unsigned char S[256]={
+      0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
+      0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
+      0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+      0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
+      0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
+      0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+      0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
+      0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
+      0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+      0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
+      0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
+      0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+      0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
+      0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
+      0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+      0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
+      0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
+      0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+      0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
+      0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
+      0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+      0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
+      0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
+      0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+      0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
+      0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
+      0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+      0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
+      0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
+      0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+      0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
+      0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
+  };
+
+  SBox = (unsigned char*)S;
+  SInvBox = (unsigned char*)Si;
+}
+
+address generate_aescrypt_encryptBlock() {
+  __ align(CodeEntryAlignment);
+  StubCodeMark mark(this, "StubRoutines", "aesencryptBlock");
+
+  address start = __ pc();
+
+  //    Register from = R0; // source byte array
+  //    Register to = R1;   // destination byte array
+  //    Register key = R2;  // expanded key array
+  //    Register tbox = R3; // transposition box reference
+
+  __ push (RegisterSet(R4, R12) | LR);
+  __ fstmdbd(SP, FloatRegisterSet(D0, 4), writeback);
+  __ sub(SP, SP, 32);
+
+  // preserve TBox references
+  __ add(R3, R3, arrayOopDesc::base_offset_in_bytes(T_INT));
+  __ str(R3, Address(SP, 16));
+
+  // retrieve key length. The length is used to determine the number of subsequent rounds (10, 12 or 14)
+  __ ldr(R9, Address(R2, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+  __ ldr(R5, Address(R0));
+  __ ldr(R10, Address(R2, 4, post_indexed));
+  __ rev(R5, R5);
+  __ eor(R5, R5, R10);
+  __ ldr(R6, Address(R0, 4));
+  __ ldr(R10, Address(R2, 4, post_indexed));
+  __ rev(R6, R6);
+  __ eor(R6, R6, R10);
+  __ ldr(R7, Address(R0, 8));
+  __ ldr(R10, Address(R2, 4, post_indexed));
+  __ rev(R7, R7);
+  __ eor(R7, R7, R10);
+  __ ldr(R8, Address(R0, 12));
+  __ ldr(R10, Address(R2, 4, post_indexed));
+  __ rev(R8, R8);
+  __ eor(R8, R8, R10);
+
+  // Store the key size; However before doing that adjust the key to compensate for the Initial and Last rounds
+  __ sub(R9, R9, 8);
+  __ fmsr(S7, R1);
+
+  // load first transporistion box (T1)
+  __ ldr(R0, Address(SP, 16));
+
+  __ mov(LR, R2);
+
+  Label round;
+
+  __ bind(round);
+
+  // Utilize a Transposition Box lookup along with subsequent shift and EOR with a round key.
+  // instructions ordering is rearranged to minimize ReadAferWrite dependency. Not that important on A15 target
+  // with register renaming but performs ~10% better on A9.
+  __ mov(R12, AsmOperand(R5, lsr, 24));
+  __ ubfx(R4, R6, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R7, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R8);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R10, R1, R12);
+
+  __ mov(R12, AsmOperand(R6, lsr, 24));
+  __ ubfx(R4, R7, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R8, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R5);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R11, R1, R12);
+
+  __ mov(R12, AsmOperand(R7, lsr, 24));
+  __ ubfx(R4, R8, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R5, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R6);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R3, R1, R12);
+  __ str(R3, Address(SP, 0));
+
+  __ mov(R12, AsmOperand(R8, lsr, 24));
+  __ ubfx(R4, R5, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R6, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R7);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R8, R1, R12);
+
+  // update round count
+  __ subs(R9, R9, 4);
+
+  __ mov(R5, R10);
+  __ mov(R6, R11);
+  __ ldr(R7, Address(SP, 0));
+
+  __ b(round, gt);
+
+
+  // last round - a special case, no MixColumn
+  __ mov_slow(R10, (int)SBox);
+
+
+  // output buffer pointer
+  __ fmrs(R9, S7);
+
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  __ ldrb(R0, Address(R10, R5, lsr, 24));
+  __ ubfx(R12, R6, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R7, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R8);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+  __ str(R0, Address(R9, 4, post_indexed));
+
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  __ ldrb(R0, Address(R10, R6, lsr, 24));
+  __ ubfx(R12, R7, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R8, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R5);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+
+  __ str(R0, Address(R9, 4, post_indexed));
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  __ ldrb(R0, Address(R10, R7, lsr, 24));
+  __ ubfx(R12, R8, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R5, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R6);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+
+  __ str(R0, Address(R9, 4, post_indexed));
+  __ ldr(R11, Address(LR));
+  __ ldrb(R0, Address(R10, R8, lsr, 24));
+  __ ubfx(R12, R5, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R6, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R7);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+
+  __ str(R0, Address(R9));
+
+  __ add(SP, SP, 32);
+  __ fldmiad(SP, FloatRegisterSet(D0, 4), writeback);;
+
+  __ pop(RegisterSet(R4, R12) | PC);
+  return start;
+}
+
+address generate_aescrypt_decryptBlock() {
+  __ align(CodeEntryAlignment);
+  StubCodeMark mark(this, "StubRoutines", "aesdecryptBlock");
+
+  address start = __ pc();
+
+  //    Register from = R0; // source byte array
+  //    Register to = R1;   // destination byte array
+  //    Register key = R2;  // expanded key array
+  //    Register tbox = R3; // transposition box reference
+
+  __ push (RegisterSet(R4, R12) | LR);
+  __ fstmdbd(SP, FloatRegisterSet(D0, 4), writeback);
+  __ sub(SP, SP, 32);
+
+  // retrieve key length
+  __ ldr(R9, Address(R2, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+  // preserve TBox references
+  __ add(R3, R3, arrayOopDesc::base_offset_in_bytes(T_INT));
+  __ str(R3, Address(SP, 16));
+
+
+  // Preserve the expanded key pointer
+  __ fmsr(S8, R2);
+
+  // The first key round is applied to the last round
+  __ add(LR, R2, 16);
+
+
+  __ ldr(R5, Address(R0));
+  __ ldr(R10, Address(LR, 4, post_indexed));
+  __ rev(R5, R5);
+  __ eor(R5, R5, R10);
+  __ ldr(R6, Address(R0, 4));
+  __ ldr(R10, Address(LR, 4, post_indexed));
+  __ rev(R6, R6);
+  __ eor(R6, R6, R10);
+  __ ldr(R7, Address(R0, 8));
+  __ ldr(R10, Address(LR, 4, post_indexed));
+  __ rev(R7, R7);
+  __ eor(R7, R7, R10);
+  __ ldr(R8, Address(R0, 12));
+  __ ldr(R10, Address(LR, 4, post_indexed));
+  __ rev(R8, R8);
+  __ eor(R8, R8, R10);
+
+
+  // Store the key size; However before doing that adjust the key to compensate for the Initial and Last rounds
+  __ sub(R9, R9, 8);
+  __ fmsr(S7, R1);
+
+  // load transporistion box (T5)
+  __ ldr(R0, Address(SP, 16));
+
+  Label round;
+
+  __ bind(round);
+  // each sub-block is treated similary:
+
+  // combine SubBytes|ShiftRows|MixColumn through a precalculated set of tables
+  // Utilize a Transposition Box lookup along with subsequent shift and EOR with a round key.
+  // instructions ordering is rearranged to minimize ReadAferWrite dependency. Not that important on A15 target
+  // with register renaming but performs ~10% better on A9.
+  __ mov(R12, AsmOperand(R5, lsr, 24));
+  __ ubfx(R4, R8, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R7, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R6);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R10, R1, R12);
+
+  __ mov(R12, AsmOperand(R6, lsr, 24));
+  __ ubfx(R4, R5, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R8, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R7);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R11, R1, R12);
+
+  __ mov(R12, AsmOperand(R7, lsr, 24));
+  __ ubfx(R4, R6, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R5, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R8);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R3, R1, R12);
+  __ str(R3, Address(SP, 0));
+
+  __ mov(R12, AsmOperand(R8, lsr, 24));
+  __ ubfx(R4, R7, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R6, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R5);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R8, R1, R12);
+
+  // update round count
+  __ subs(R9, R9, 4);
+
+  __ mov(R5, R10);
+  __ mov(R6, R11);
+  __ ldr(R7, Address(SP, 0));
+
+  __ b(round, gt);
+
+  // last round - a special case, no MixColumn:
+
+  // Retrieve expanded key pointer
+  __ fmrs(LR, S8);
+
+  __ mov_slow(R10, (int)SInvBox);
+
+  // output buffer pointer
+  __ fmrs(R9, S7);
+
+  // process each sub-block in a similar manner:
+  // 1. load a corresponding round key
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  // 2. combine SubBytes and ShiftRows stages
+  __ ldrb(R0, Address(R10, R5, lsr, 24));
+  __ ubfx(R12, R8, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R7, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R6);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R3, R3, AsmOperand(R0, lsl, 8));
+  // 3. AddRoundKey stage
+  __ eor(R0, R3, R11);
+  // 4. convert the result to LE representation
+  __ rev(R0, R0);
+  // 5. store in the output buffer
+  __ str(R0, Address(R9, 4, post_indexed));
+
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  __ ldrb(R0, Address(R10, R6, lsr, 24));
+  __ ubfx(R12, R5, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R8, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R7);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+  __ str(R0, Address(R9, 4, post_indexed));
+
+  __ ldr(R11, Address(LR, 4, post_indexed));
+  __ ldrb(R0, Address(R10, R7, lsr, 24));
+  __ ubfx(R12, R6, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R5, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R8);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+  __ str(R0, Address(R9, 4, post_indexed));
+
+  __ ldr(R11, Address(LR));
+  __ ldrb(R0, Address(R10, R8, lsr, 24));
+  __ ubfx(R12, R7, 16, 8);
+  __ ldrb(R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R6, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb (R12, R5);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ eor(R0, R0, R11);
+  __ rev(R0, R0);
+  __ str(R0, Address(R9));
+
+  __ add(SP, SP, 32);
+  __ fldmiad(SP, FloatRegisterSet(D0, 4), writeback);;
+  __ pop(RegisterSet(R4, R12) | PC);
+
+  return start;
+}
+
+address generate_cipherBlockChaining_encryptAESCrypt() {
+  // R0 - plain
+  // R1 - cipher
+  // R2 - expanded key
+  // R3 - Initialization Vector (IV)
+  // [sp+0] - cipher len
+  // [sp+4] Transposition Box reference
+
+  __ align(CodeEntryAlignment);
+  StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
+
+  address start = __ pc();
+
+  __ push(RegisterSet(R4, R12) | LR);
+  // load cipher length (which is first element on the original calling stack)
+  __ ldr(R4, Address(SP, 40));
+
+  __ sub(SP, SP, 32);
+
+  // preserve some arguments
+  __ mov(R5, R1);
+  __ mov(R6, R2);
+
+  // load IV
+  __ ldmia(R3, RegisterSet(R9, R12), writeback);
+
+  // preserve original source buffer on stack
+  __ str(R0, Address(SP, 16));
+
+  Label loop;
+  __ bind(loop);
+  __ ldmia(R0, RegisterSet(R0, R1) | RegisterSet(R7, R8));
+
+  __ eor(R0, R0, R9);
+  __ eor(R1, R1, R10);
+  __ eor(R7, R7, R11);
+  __ eor(R8, R8, R12);
+  __ stmia(SP, RegisterSet(R0, R1) | RegisterSet(R7, R8));
+
+  __ mov(R0, SP);
+  __ mov(R1, R5);
+  __ mov(R2, R6);
+  __ ldr(R3, Address(SP, 40+32+4));
+
+  // near call is sufficient since the target is also in the stubs
+  __ bl(StubRoutines::_aescrypt_encryptBlock);
+
+  __ subs(R4, R4, 16);
+  __ ldr(R0, Address(SP, 16), gt);
+  __ ldmia(R5, RegisterSet(R9, R12), writeback);
+  __ add(R0, R0, 16, gt);
+  __ str(R0, Address(SP, 16), gt);
+  __ b(loop, gt);
+
+  __ add(SP, SP, 32);
+  __ pop(RegisterSet(R4, R12) | LR);
+  // return cipher len (copied from the original argument)
+  __ ldr(R0, Address(SP));
+  __ bx(LR);
+
+  return start;
+}
+
+
+// The CBC decryption could benefit from parallel processing as the blocks could be
+// decrypted separatly from each other.
+// NEON is utilized (if available) to perform parallel execution on 8 blocks at a time.
+// Since Transposition Box (tbox) is used the parallel execution will only apply to an
+// Initial Round and the last round. It's not practical to use NEON for a table lookup
+// larger than 128 bytes. It also appears to be faster performing  tbox lookup
+// sequentially then execute Galois Field calculation in parallel.
+
+address generate_cipherBlockChaining_decryptAESCrypt() {
+  __ align(CodeEntryAlignment);
+  StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
+
+  address start = __ pc();
+
+  Label single_block_done, single_block, cbc_done;
+  // R0 - cipher
+  // R1 - plain
+  // R2 - expanded key
+  // R3 - Initialization Vector (iv)
+  // [sp+0] - cipher len
+  // [sp+4] - Transpotition Box reference
+
+  __ push(RegisterSet(R4, R12) | LR);
+
+  // load cipher len: must be modulo 16
+  __ ldr(R4, Address(SP, 40));
+
+  if (VM_Version::has_simd()) {
+    __ andrs(R4, R4, 0x7f);
+  }
+
+  // preserve registers based arguments
+  __ mov(R7, R2);
+  __ mov(R8, R3);
+
+  if (VM_Version::has_simd()) {
+    __ b(single_block_done, eq);
+  }
+
+  __ bind(single_block);
+  // preserve args
+  __ mov(R5, R0);
+  __ mov(R6, R1);
+
+  // reload arguments
+  __ mov(R2, R7);
+  __ ldr(R3, Address(SP, 40+4));
+
+  // near call is sufficient as the method is part of the StubGenerator
+  __ bl((address)StubRoutines::_aescrypt_decryptBlock);
+
+  // check remainig cipher size (for individual block processing)
+  __ subs(R4, R4, 16);
+  if (VM_Version::has_simd()) {
+    __ tst(R4, 0x7f);
+  }
+
+  // load IV (changes based on a CBC schedule)
+  __ ldmia(R8, RegisterSet(R9, R12));
+
+  // load plaintext from the previous block processing
+  __ ldmia(R6, RegisterSet(R0, R3));
+
+  // perform IV addition and save the plaintext for good now
+  __ eor(R0, R0, R9);
+  __ eor(R1, R1, R10);
+  __ eor(R2, R2, R11);
+  __ eor(R3, R3, R12);
+  __ stmia(R6, RegisterSet(R0, R3));
+
+  // adjust pointers for next block processing
+  __ mov(R8, R5);
+  __ add(R0, R5, 16);
+  __ add(R1, R6, 16);
+  __ b(single_block, ne);
+
+  __ bind(single_block_done);
+  if (!VM_Version::has_simd()) {
+    __ b(cbc_done);
+  } else {
+  // done with single blocks.
+  // check if any 8 block chunks are available for parallel processing
+  __ ldr(R4, Address(SP, 40));
+  __ bics(R4, R4, 0x7f);
+  __ b(cbc_done, eq);
+
+  Label decrypt_8_blocks;
+  int quad = 1;
+  // Process 8 blocks in parallel
+  __ fstmdbd(SP, FloatRegisterSet(D8, 8), writeback);
+  __ sub(SP, SP, 40);
+
+  // record output buffer end address (used as a block counter)
+  Address output_buffer_end(SP, 16);
+  __ add(R5, R1, R4);
+  __ str(R5, output_buffer_end);
+
+  // preserve key pointer
+  Address rounds_key(SP, 28);
+  __ str(R7, rounds_key);
+  // in decryption the first 16 bytes of expanded key are used in the last round
+  __ add(LR, R7, 16);
+
+
+  // Record the end of the key which is used to indicate a last round
+  __ ldr(R3, Address(R7, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+  __ add(R9, R7, AsmOperand(R3, lsl, 2));
+
+  // preserve IV
+  Address iv(SP, 36);
+  __ str(R8, iv);
+
+  __ bind(decrypt_8_blocks);
+  __ mov(R5, R1);
+
+  // preserve original source pointer
+  Address original_src(SP, 32);
+  __ str(R0, original_src);
+
+  // Apply ShiftRow for 8 block at once:
+  // use output buffer for a temp storage to preload it into cache
+
+  __ vld1(D18, LR, MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vld1(D0, Address(R0, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D0, D0, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D0, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D2, Address(R0, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D2, D2, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D2, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D4, Address(R0, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D4, D4, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D4, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D6, Address(R0, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D6, D6, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D6, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D8, Address(R0, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D8, D8, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D8, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D10, Address(R0, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D10, D10, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D10, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D12, Address(R0, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D12, D12, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D12, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D14, Address(R0, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D14, D14, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ veor(D20, D14, D18, quad);
+  __ vst1(D20, Address(R5, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+
+  // Local frame map:
+  // sp+20 - ouput buffer pointer
+  // sp+28 - key pointer
+  // sp+32 - original source
+  // sp+36 - block counter
+
+
+  // preserve output buffer pointer
+  Address block_current_output_buffer(SP, 20);
+  __ str(R1, block_current_output_buffer);
+
+  // individual rounds in block processing are executed sequentially .
+  Label block_start;
+
+  // record end of the output buffer
+  __ add(R0, R1, 128);
+  __ str(R0, Address(SP, 12));
+
+  __ bind(block_start);
+
+  // load transporistion box reference (T5)
+  // location of the reference (6th incoming argument, second slot on the stack):
+  // 10 scalar registers on stack
+  //  8 double-precision FP registers
+  // 40 bytes frame size for local storage
+  //  4 bytes offset to the original arguments list
+  __ ldr(R0, Address(SP, 40+64+40+4));
+  __ add(R0, R0, arrayOopDesc::base_offset_in_bytes(T_INT));
+
+  // load rounds key and compensate for the first and last rounds
+  __ ldr(LR, rounds_key);
+  __ add(LR, LR, 32);
+
+  // load block data out buffer
+  __ ldr(R2, block_current_output_buffer);
+  __ ldmia(R2, RegisterSet(R5, R8));
+
+  Label round;
+  __ bind(round);
+
+  // Utilize a Transposition Box lookup along with subsequent shift and EOR with a round key.
+  // instructions ordering is rearranged to minimize ReadAferWrite dependency. Not that important on A15 target
+  // with register renaming but performs ~10% better on A9.
+  __ mov(R12, AsmOperand(R5, lsr, 24));
+  __ ubfx(R4, R8, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R7, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R6);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R10, R1, R12);
+
+  __ mov(R12, AsmOperand(R6, lsr, 24));
+  __ ubfx(R4, R5, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R8, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R7);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R11, R1, R12);
+
+  __ mov(R12, AsmOperand(R7, lsr, 24));
+  __ ubfx(R4, R6, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R5, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R8);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R3, R1, R12);
+  __ str(R3, Address(SP, 0));
+
+  __ mov(R12, AsmOperand(R8, lsr, 24));
+  __ ubfx(R4, R7, 16, 8);
+  __ ldr (R1, Address(R0, R12, lsl, 2));
+  __ ldr(R2, Address(R0, R4, lsl, 2));
+  __ ubfx(R3, R6, 8, 8);
+  __ eor(R1, R1, AsmOperand(R2, ror, 8));
+  __ uxtb(R4, R5);
+  __ ldr(R3, Address(R0, R3, lsl, 2));
+  __ ldr(R4, Address(R0, R4, lsl, 2));
+  __ ldr(R12, Address(LR, 4, post_indexed));
+  __ eor(R1, R1, AsmOperand(R3, ror, 16));
+  __ eor(R12, R12, AsmOperand(R4, ror, 24));
+  __ eor(R8, R1, R12);
+
+  // see if we reached the key array end
+  __ cmp(R9, LR);
+
+  //  load processed data
+  __ mov(R5, R10);
+  __ mov(R6, R11);
+  __ ldr(R7, Address(SP, 0));
+
+  __ b(round, gt);
+
+
+  // last round is special
+  // this round could be implemented through vtbl instruction in NEON. However vtbl is limited to a 32-byte wide table (4 vectors),
+  // thus it requires 8 lookup rounds to cover 256-byte wide Si table. On the other hand scalar lookup is independent of the
+  // lookup table size and thus proves to be faster.
+  __ ldr(LR, block_current_output_buffer);
+
+  // cipher counter
+  __ ldr(R11, Address(SP, 12));
+
+  __ mov_slow(R10, (int)SInvBox);
+  __ ldrb(R0, Address(R10, R5, lsr, 24));
+  __ ubfx(R12, R8, 16, 8);
+  __ ldrb (R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R7, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb(R12, R6);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ str(R0, Address(LR, 4, post_indexed));
+
+  __ ldrb(R0, Address(R10, R6, lsr, 24));
+  __ ubfx(R12, R5, 16, 8);
+  __ ldrb (R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R8, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb(R12, R7);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ str(R0, Address(LR, 4, post_indexed));
+
+
+  __ ldrb(R0, Address(R10, R7, lsr, 24));
+  __ ubfx(R12, R6, 16, 8);
+  __ ldrb (R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R5, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb(R12, R8);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ str(R0, Address(LR, 4, post_indexed));
+
+
+  __ ldrb(R0, Address(R10, R8, lsr, 24));
+  __ ubfx(R12, R7, 16, 8);
+  __ ldrb (R1, Address(R10, R12));
+  __ orr(R0, R1, AsmOperand(R0, lsl, 8));
+  __ ubfx(R12, R6, 8, 8);
+  __ ldrb(R2, Address(R10, R12));
+  __ orr(R0, R2, AsmOperand(R0, lsl, 8));
+  __ uxtb(R12, R5);
+  __ ldrb(R3, Address(R10, R12));
+  __ orr(R0, R3, AsmOperand(R0, lsl, 8));
+  __ str(R0, Address(LR, 4, post_indexed));
+
+
+  // preserve current scratch buffer pointer
+  __ cmp(R11, LR);
+  __ str(LR, block_current_output_buffer);
+
+  // go to the next block processing
+  __ b(block_start, ne);
+
+
+
+  // Perform last round AddRoundKey state on all 8 blocks
+
+  // load key pointer (remember that [sp+24]  points to a byte #32 at the key array)
+  // last round is processed with the key[0 ..3]
+  __ ldr(LR, rounds_key);
+
+  // retireve original output buffer pointer
+  __ ldr(R1, block_current_output_buffer);
+  __ sub(R1, R1, 128);
+  __ mov(R5, R1);
+
+
+  // retrieve original cipher (source) pointer
+  __ ldr(R0, original_src);
+
+  // retrieve IV (second argument on stack)
+  __ ldr(R6, iv);
+
+  __ vld1(D20, R6, MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ vrev(D20, D20, quad, 32, MacroAssembler::VELEM_SIZE_8);
+
+  // perform last AddRoundKey and IV addition
+  __ vld1(D18, Address(LR, 0, post_indexed), MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D20, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D0, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D2, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D4, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D6, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D8, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D10, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+  __ vld1(D22, Address(R1, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+  __ veor(D22, D22, D18, quad);
+  __ veor(D22, D22, D12, quad);
+  __ vrev(D22, D22, quad, 32, MacroAssembler::VELEM_SIZE_8);
+  __ vst1(D22, Address(R5, 0, post_indexed),  MacroAssembler::VELEM_SIZE_8, MacroAssembler::VLD1_TYPE_2_REGS);
+
+
+  // check if we're done
+  __ ldr(R4, output_buffer_end);
+  __ cmp(R4, R1);
+  __ add(R0, R0, 128-16);
+  __ str(R0, iv);
+  __ add(R0, R0, 16);
+
+  __ b(decrypt_8_blocks, ne);
+
+  __ add(SP, SP, 40);
+  __ fldmiad(SP, FloatRegisterSet(D8, 8), writeback);;
+  }
+
+  __ bind(cbc_done);
+  __ pop(RegisterSet(R4, R12) | LR);
+  __ ldr(R0, Address(SP));
+  __ bx(LR);
+
+  return start;
+}
+#endif // USE_CRYPTO
diff --git a/hotspot/src/cpu/arm/vm/stubRoutines_arm.cpp b/hotspot/src/cpu/arm/vm/stubRoutines_arm.cpp
new file mode 100644
index 0000000..a7e56c1
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/stubRoutines_arm.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/stubRoutines.hpp"
+
+#ifndef AARCH64
+address StubRoutines::Arm::_idiv_irem_entry = NULL;
+#endif
+
+address StubRoutines::Arm::_partial_subtype_check = NULL;
+
+#ifndef AARCH64
+address StubRoutines::_atomic_load_long_entry = NULL;
+address StubRoutines::_atomic_store_long_entry = NULL;
+#endif
diff --git a/hotspot/src/cpu/arm/vm/stubRoutines_arm.hpp b/hotspot/src/cpu/arm/vm/stubRoutines_arm.hpp
new file mode 100644
index 0000000..a94897a
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/stubRoutines_arm.hpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_STUBROUTINES_ARM_HPP
+#define CPU_ARM_VM_STUBROUTINES_ARM_HPP
+
+// This file holds the platform specific parts of the StubRoutines
+// definition. See stubRoutines.hpp for a description on how to
+// extend it.
+
+enum platform_dependent_constants {
+  code_size1 =  9000,           // simply increase if too small (assembler will crash if too small)
+  code_size2 = 22000            // simply increase if too small (assembler will crash if too small)
+};
+
+class Arm {
+ friend class StubGenerator;
+ friend class VMStructs;
+
+ private:
+
+#ifndef AARCH64
+  static address _idiv_irem_entry;
+#endif
+  static address _partial_subtype_check;
+
+ public:
+
+#ifndef AARCH64
+  static address idiv_irem_entry() { return _idiv_irem_entry; }
+#endif
+  static address partial_subtype_check() { return _partial_subtype_check; }
+};
+
+  static bool returns_to_call_stub(address return_pc) {
+    return return_pc == _call_stub_return_address;
+  }
+
+#ifndef AARCH64
+  static address _atomic_load_long_entry;
+  static address _atomic_store_long_entry;
+
+  static address atomic_load_long_entry()                  { return _atomic_load_long_entry; }
+  static address atomic_store_long_entry()                 { return _atomic_store_long_entry; }
+#endif
+
+
+#endif // CPU_ARM_VM_STUBROUTINES_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp
new file mode 100644
index 0000000..743510e
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp
@@ -0,0 +1,1976 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateInterpreterGenerator.hpp"
+#include "interpreter/templateTable.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+// Size of interpreter code.  Increase if too small.  Interpreter will
+// fail with a guarantee ("not enough space for interpreter generation");
+// if too small.
+// Run with +PrintInterpreter to get the VM to print out the size.
+// Max size with JVMTI
+int TemplateInterpreter::InterpreterCodeSize = 180 * 1024;
+
+#define __ _masm->
+
+//------------------------------------------------------------------------------------------------------------------------
+
+address TemplateInterpreterGenerator::generate_slow_signature_handler() {
+  address entry = __ pc();
+
+  // callee-save register for saving LR, shared with generate_native_entry
+  const Register Rsaved_ret_addr = AARCH64_ONLY(R21) NOT_AARCH64(Rtmp_save0);
+
+  __ mov(Rsaved_ret_addr, LR);
+
+  __ mov(R1, Rmethod);
+  __ mov(R2, Rlocals);
+  __ mov(R3, SP);
+
+#ifdef AARCH64
+  // expand expr. stack and extended SP to avoid cutting SP in call_VM
+  __ mov(Rstack_top, SP);
+  __ str(Rstack_top, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
+  __ check_stack_top();
+
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), R1, R2, R3, false);
+
+  __ ldp(ZR,      c_rarg1, Address(SP, 2*wordSize, post_indexed));
+  __ ldp(c_rarg2, c_rarg3, Address(SP, 2*wordSize, post_indexed));
+  __ ldp(c_rarg4, c_rarg5, Address(SP, 2*wordSize, post_indexed));
+  __ ldp(c_rarg6, c_rarg7, Address(SP, 2*wordSize, post_indexed));
+
+  __ ldp_d(V0, V1, Address(SP, 2*wordSize, post_indexed));
+  __ ldp_d(V2, V3, Address(SP, 2*wordSize, post_indexed));
+  __ ldp_d(V4, V5, Address(SP, 2*wordSize, post_indexed));
+  __ ldp_d(V6, V7, Address(SP, 2*wordSize, post_indexed));
+#else
+
+  // Safer to save R9 (when scratched) since callers may have been
+  // written assuming R9 survives. This is suboptimal but
+  // probably not important for this slow case call site.
+  // Note for R9 saving: slow_signature_handler may copy register
+  // arguments above the current SP (passed as R3). It is safe for
+  // call_VM to use push and pop to protect additional values on the
+  // stack if needed.
+  __ call_VM(CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), true /* save R9 if needed*/);
+  __ add(SP, SP, wordSize);     // Skip R0
+  __ pop(RegisterSet(R1, R3));  // Load arguments passed in registers
+#ifdef __ABI_HARD__
+  // Few alternatives to an always-load-FP-registers approach:
+  // - parse method signature to detect FP arguments
+  // - keep a counter/flag on a stack indicationg number of FP arguments in the method.
+  // The later has been originally implemented and tested but a conditional path could
+  // eliminate any gain imposed by avoiding 8 double word loads.
+  __ fldmiad(SP, FloatRegisterSet(D0, 8), writeback);
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+  __ ret(Rsaved_ret_addr);
+
+  return entry;
+}
+
+
+//
+// Various method entries (that c++ and asm interpreter agree upon)
+//------------------------------------------------------------------------------------------------------------------------
+//
+//
+
+// Abstract method entry
+// Attempt to execute abstract method. Throw exception
+address TemplateInterpreterGenerator::generate_abstract_entry(void) {
+  address entry_point = __ pc();
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp);
+  __ restore_stack_top();
+#endif
+
+  __ empty_expression_stack();
+
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
+
+  DEBUG_ONLY(STOP("generate_abstract_entry");) // Should not reach here
+  return entry_point;
+}
+
+address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
+  if (!InlineIntrinsics) return NULL; // Generate a vanilla entry
+
+  // TODO: ARM
+  return NULL;
+
+  address entry_point = __ pc();
+  STOP("generate_math_entry");
+  return entry_point;
+}
+
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+  address entry = __ pc();
+
+  // Note: There should be a minimal interpreter frame set up when stack
+  // overflow occurs since we check explicitly for it now.
+  //
+#ifdef ASSERT
+  { Label L;
+    __ sub(Rtemp, FP, - frame::interpreter_frame_monitor_block_top_offset * wordSize);
+    __ cmp(SP, Rtemp);  // Rtemp = maximal SP for current FP,
+                        //  (stack grows negative)
+    __ b(L, ls); // check if frame is complete
+    __ stop ("interpreter frame not set up");
+    __ bind(L);
+  }
+#endif // ASSERT
+
+  // Restore bcp under the assumption that the current frame is still
+  // interpreted
+  __ restore_bcp();
+
+  // expression stack must be empty before entering the VM if an exception
+  // happened
+  __ empty_expression_stack();
+
+  // throw exception
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
+
+  __ should_not_reach_here();
+
+  return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
+  address entry = __ pc();
+
+  // index is in R4_ArrayIndexOutOfBounds_index
+
+  InlinedString Lname(name);
+
+  // expression stack must be empty before entering the VM if an exception happened
+  __ empty_expression_stack();
+
+  // setup parameters
+  __ ldr_literal(R1, Lname);
+  __ mov(R2, R4_ArrayIndexOutOfBounds_index);
+
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), R1, R2);
+
+  __ nop(); // to avoid filling CPU pipeline with invalid instructions
+  __ nop();
+  __ should_not_reach_here();
+  __ bind_literal(Lname);
+
+  return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+  address entry = __ pc();
+
+  // object is in R2_ClassCastException_obj
+
+  // expression stack must be empty before entering the VM if an exception
+  // happened
+  __ empty_expression_stack();
+
+  __ mov(R1, R2_ClassCastException_obj);
+  __ call_VM(noreg,
+             CAST_FROM_FN_PTR(address,
+                              InterpreterRuntime::throw_ClassCastException),
+             R1);
+
+  __ should_not_reach_here();
+
+  return entry;
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
+  assert(!pass_oop || message == NULL, "either oop or message but not both");
+  address entry = __ pc();
+
+  InlinedString Lname(name);
+  InlinedString Lmessage(message);
+
+  if (pass_oop) {
+    // object is at TOS
+    __ pop_ptr(R2);
+  }
+
+  // expression stack must be empty before entering the VM if an exception happened
+  __ empty_expression_stack();
+
+  // setup parameters
+  __ ldr_literal(R1, Lname);
+
+  if (pass_oop) {
+    __ call_VM(Rexception_obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), R1, R2);
+  } else {
+    if (message != NULL) {
+      __ ldr_literal(R2, Lmessage);
+    } else {
+      __ mov(R2, 0);
+    }
+    __ call_VM(Rexception_obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), R1, R2);
+  }
+
+  // throw exception
+  __ b(Interpreter::throw_exception_entry());
+
+  __ nop(); // to avoid filling CPU pipeline with invalid instructions
+  __ nop();
+  __ bind_literal(Lname);
+  if (!pass_oop && (message != NULL)) {
+    __ bind_literal(Lmessage);
+  }
+
+  return entry;
+}
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+  // Not used.
+  STOP("generate_continuation_for");
+  return NULL;
+}
+
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+  address entry = __ pc();
+
+  __ interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp);  // Restore SP to extended SP
+  __ restore_stack_top();
+#else
+  // Restore stack bottom in case i2c adjusted stack
+  __ ldr(SP, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+  // and NULL it as marker that SP is now tos until next java call
+  __ mov(Rtemp, (int)NULL_WORD);
+  __ str(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ restore_method();
+  __ restore_bcp();
+  __ restore_dispatch();
+  __ restore_locals();
+
+  const Register Rcache = R2_tmp;
+  const Register Rindex = R3_tmp;
+  __ get_cache_and_index_at_bcp(Rcache, Rindex, 1, index_size);
+
+  __ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldrb(Rtemp, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
+  __ check_stack_top();
+  __ add(Rstack_top, Rstack_top, AsmOperand(Rtemp, lsl, Interpreter::logStackElementSize));
+
+#ifndef AARCH64
+  __ convert_retval_to_tos(state);
+#endif // !AARCH64
+
+  __ dispatch_next(state, step);
+
+  return entry;
+}
+
+
+address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
+  address entry = __ pc();
+
+  __ interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp);  // Restore SP to extended SP
+  __ restore_stack_top();
+#else
+  // The stack is not extended by deopt but we must NULL last_sp as this
+  // entry is like a "return".
+  __ mov(Rtemp, 0);
+  __ str(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ restore_method();
+  __ restore_bcp();
+  __ restore_dispatch();
+  __ restore_locals();
+
+  // handle exceptions
+  { Label L;
+    __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
+    __ cbz(Rtemp, L);
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
+    __ should_not_reach_here();
+    __ bind(L);
+  }
+
+  __ dispatch_next(state, step);
+
+  return entry;
+}
+
+address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
+#ifdef AARCH64
+  address entry = __ pc();
+  switch (type) {
+    case T_BOOLEAN:
+      __ tst(R0, 0xff);
+      __ cset(R0, ne);
+      break;
+    case T_CHAR   : __ zero_extend(R0, R0, 16);  break;
+    case T_BYTE   : __ sign_extend(R0, R0,  8);  break;
+    case T_SHORT  : __ sign_extend(R0, R0, 16);  break;
+    case T_INT    : // fall through
+    case T_LONG   : // fall through
+    case T_VOID   : // fall through
+    case T_FLOAT  : // fall through
+    case T_DOUBLE : /* nothing to do */          break;
+    case T_OBJECT :
+      // retrieve result from frame
+      __ ldr(R0, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize));
+      // and verify it
+      __ verify_oop(R0);
+      break;
+    default       : ShouldNotReachHere();
+  }
+  __ ret();
+  return entry;
+#else
+  // Result handlers are not used on 32-bit ARM
+  // since the returned value is already in appropriate format.
+  __ should_not_reach_here();  // to avoid empty code block
+
+  // The result handler non-zero indicates an object is returned and this is
+  // used in the native entry code.
+  return type == T_OBJECT ? (address)(-1) : NULL;
+#endif // AARCH64
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
+  address entry = __ pc();
+  __ push(state);
+  __ call_VM(noreg, runtime_entry);
+
+  // load current bytecode
+  __ ldrb(R3_bytecode, Address(Rbcp));
+  __ dispatch_only_normal(vtos);
+  return entry;
+}
+
+
+// Helpers for commoning out cases in the various type of method entries.
+//
+
+// increment invocation count & check for overflow
+//
+// Note: checking for negative value instead of overflow
+//       so we have a 'sticky' overflow test
+//
+// In: Rmethod.
+//
+// Uses R0, R1, Rtemp.
+//
+void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow,
+                                                 Label* profile_method,
+                                                 Label* profile_method_continue) {
+  Label done;
+  const Register Rcounters = Rtemp;
+  const Address invocation_counter(Rcounters,
+                MethodCounters::invocation_counter_offset() +
+                InvocationCounter::counter_offset());
+
+  // Note: In tiered we increment either counters in MethodCounters* or
+  // in MDO depending if we're profiling or not.
+  if (TieredCompilation) {
+    int increment = InvocationCounter::count_increment;
+    Label no_mdo;
+    if (ProfileInterpreter) {
+      // Are we profiling?
+      __ ldr(R1_tmp, Address(Rmethod, Method::method_data_offset()));
+      __ cbz(R1_tmp, no_mdo);
+      // Increment counter in the MDO
+      const Address mdo_invocation_counter(R1_tmp,
+                    in_bytes(MethodData::invocation_counter_offset()) +
+                    in_bytes(InvocationCounter::counter_offset()));
+      const Address mask(R1_tmp, in_bytes(MethodData::invoke_mask_offset()));
+      __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, R0_tmp, Rtemp, eq, overflow);
+      __ b(done);
+    }
+    __ bind(no_mdo);
+    __ get_method_counters(Rmethod, Rcounters, done);
+    const Address mask(Rcounters, in_bytes(MethodCounters::invoke_mask_offset()));
+    __ increment_mask_and_jump(invocation_counter, increment, mask, R0_tmp, R1_tmp, eq, overflow);
+    __ bind(done);
+  } else { // not TieredCompilation
+    const Address backedge_counter(Rcounters,
+                  MethodCounters::backedge_counter_offset() +
+                  InvocationCounter::counter_offset());
+
+    const Register Ricnt = R0_tmp;  // invocation counter
+    const Register Rbcnt = R1_tmp;  // backedge counter
+
+    __ get_method_counters(Rmethod, Rcounters, done);
+
+    if (ProfileInterpreter) {
+      const Register Riic = R1_tmp;
+      __ ldr_s32(Riic, Address(Rcounters, MethodCounters::interpreter_invocation_counter_offset()));
+      __ add(Riic, Riic, 1);
+      __ str_32(Riic, Address(Rcounters, MethodCounters::interpreter_invocation_counter_offset()));
+    }
+
+    // Update standard invocation counters
+
+    __ ldr_u32(Ricnt, invocation_counter);
+    __ ldr_u32(Rbcnt, backedge_counter);
+
+    __ add(Ricnt, Ricnt, InvocationCounter::count_increment);
+
+#ifdef AARCH64
+    __ andr(Rbcnt, Rbcnt, (unsigned int)InvocationCounter::count_mask_value); // mask out the status bits
+#else
+    __ bic(Rbcnt, Rbcnt, ~InvocationCounter::count_mask_value); // mask out the status bits
+#endif // AARCH64
+
+    __ str_32(Ricnt, invocation_counter);            // save invocation count
+    __ add(Ricnt, Ricnt, Rbcnt);                     // add both counters
+
+    // profile_method is non-null only for interpreted method so
+    // profile_method != NULL == !native_call
+    // BytecodeInterpreter only calls for native so code is elided.
+
+    if (ProfileInterpreter && profile_method != NULL) {
+      assert(profile_method_continue != NULL, "should be non-null");
+
+      // Test to see if we should create a method data oop
+      // Reuse R1_tmp as we don't need backedge counters anymore.
+      Address profile_limit(Rcounters, in_bytes(MethodCounters::interpreter_profile_limit_offset()));
+      __ ldr_s32(R1_tmp, profile_limit);
+      __ cmp_32(Ricnt, R1_tmp);
+      __ b(*profile_method_continue, lt);
+
+      // if no method data exists, go to profile_method
+      __ test_method_data_pointer(R1_tmp, *profile_method);
+    }
+
+    Address invoke_limit(Rcounters, in_bytes(MethodCounters::interpreter_invocation_limit_offset()));
+    __ ldr_s32(R1_tmp, invoke_limit);
+    __ cmp_32(Ricnt, R1_tmp);
+    __ b(*overflow, hs);
+    __ bind(done);
+  }
+}
+
+void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) {
+  // InterpreterRuntime::frequency_counter_overflow takes one argument
+  // indicating if the counter overflow occurs at a backwards branch (non-NULL bcp).
+  // The call returns the address of the verified entry point for the method or NULL
+  // if the compilation did not complete (either went background or bailed out).
+  __ mov(R1, (int)false);
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R1);
+
+  // jump to the interpreted entry.
+  __ b(do_continue);
+}
+
+void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {
+  // Check if we've got enough room on the stack for
+  //  - overhead;
+  //  - locals;
+  //  - expression stack.
+  //
+  // Registers on entry:
+  //
+  // R3 = number of additional locals
+  // R11 = max expression stack slots (AArch64 only)
+  // Rthread
+  // Rmethod
+  // Registers used: R0, R1, R2, Rtemp.
+
+  const Register Radditional_locals = R3;
+  const Register RmaxStack = AARCH64_ONLY(R11) NOT_AARCH64(R2);
+
+  // monitor entry size
+  const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+
+  // total overhead size: entry_size + (saved registers, thru expr stack bottom).
+  // be sure to change this if you add/subtract anything to/from the overhead area
+  const int overhead_size = (frame::sender_sp_offset - frame::interpreter_frame_initial_sp_offset)*wordSize + entry_size;
+
+  // Pages reserved for VM runtime calls and subsequent Java calls.
+  const int reserved_pages = JavaThread::stack_shadow_zone_size();
+
+  // Thread::stack_size() includes guard pages, and they should not be touched.
+  const int guard_pages = JavaThread::stack_guard_zone_size();
+
+  __ ldr(R0, Address(Rthread, Thread::stack_base_offset()));
+  __ ldr(R1, Address(Rthread, Thread::stack_size_offset()));
+#ifndef AARCH64
+  __ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+  __ ldrh(RmaxStack, Address(Rtemp, ConstMethod::max_stack_offset()));
+#endif // !AARCH64
+  __ sub_slow(Rtemp, SP, overhead_size + reserved_pages + guard_pages + Method::extra_stack_words());
+
+  // reserve space for additional locals
+  __ sub(Rtemp, Rtemp, AsmOperand(Radditional_locals, lsl, Interpreter::logStackElementSize));
+
+  // stack size
+  __ sub(R0, R0, R1);
+
+  // reserve space for expression stack
+  __ sub(Rtemp, Rtemp, AsmOperand(RmaxStack, lsl, Interpreter::logStackElementSize));
+
+  __ cmp(Rtemp, R0);
+
+#ifdef AARCH64
+  Label L;
+  __ b(L, hi);
+  __ mov(SP, Rsender_sp);  // restore SP
+  __ b(StubRoutines::throw_StackOverflowError_entry());
+  __ bind(L);
+#else
+  __ mov(SP, Rsender_sp, ls);  // restore SP
+  __ b(StubRoutines::throw_StackOverflowError_entry(), ls);
+#endif // AARCH64
+}
+
+
+// Allocate monitor and lock method (asm interpreter)
+//
+void TemplateInterpreterGenerator::lock_method() {
+  // synchronize method
+
+  const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
+  assert ((entry_size % StackAlignmentInBytes) == 0, "should keep stack alignment");
+
+  #ifdef ASSERT
+    { Label L;
+      __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+      __ tbnz(Rtemp, JVM_ACC_SYNCHRONIZED_BIT, L);
+      __ stop("method doesn't need synchronization");
+      __ bind(L);
+    }
+  #endif // ASSERT
+
+  // get synchronization object
+  { Label done;
+    __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+#ifdef AARCH64
+    __ ldr(R0, Address(Rlocals, Interpreter::local_offset_in_bytes(0))); // get receiver (assume this is frequent case)
+    __ tbz(Rtemp, JVM_ACC_STATIC_BIT, done);
+#else
+    __ tst(Rtemp, JVM_ACC_STATIC);
+    __ ldr(R0, Address(Rlocals, Interpreter::local_offset_in_bytes(0)), eq); // get receiver (assume this is frequent case)
+    __ b(done, eq);
+#endif // AARCH64
+    __ load_mirror(R0, Rmethod, Rtemp);
+    __ bind(done);
+  }
+
+  // add space for monitor & lock
+
+#ifdef AARCH64
+  __ check_extended_sp(Rtemp);
+  __ sub(SP, SP, entry_size);                  // adjust extended SP
+  __ mov(Rtemp, SP);
+  __ str(Rtemp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ sub(Rstack_top, Rstack_top, entry_size);
+  __ check_stack_top_on_expansion();
+                                              // add space for a monitor entry
+  __ str(Rstack_top, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                              // set new monitor block top
+  __ str(R0, Address(Rstack_top, BasicObjectLock::obj_offset_in_bytes()));
+                                              // store object
+  __ mov(R1, Rstack_top);                     // monitor entry address
+  __ lock_object(R1);
+}
+
+#ifdef AARCH64
+
+//
+// Generate a fixed interpreter frame. This is identical setup for interpreted methods
+// and for native methods hence the shared code.
+//
+// On entry:
+//   R10 = ConstMethod
+//   R11 = max expr. stack (in slots), if !native_call
+//
+// On exit:
+//   Rbcp, Rstack_top are initialized, SP is extended
+//
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
+  // Incoming registers
+  const Register RconstMethod = R10;
+  const Register RmaxStack = R11;
+  // Temporary registers
+  const Register RextendedSP = R0;
+  const Register Rcache = R1;
+  const Register Rmdp = ProfileInterpreter ? R2 : ZR;
+
+  // Generates the following stack layout (stack grows up in this picture):
+  //
+  // [ expr. stack bottom ]
+  // [ saved Rbcp         ]
+  // [ current Rlocals    ]
+  // [ cache              ]
+  // [ mdx                ]
+  // [ mirror             ]
+  // [ Method*            ]
+  // [ extended SP        ]
+  // [ expr. stack top    ]
+  // [ sender_sp          ]
+  // [ saved FP           ] <--- FP
+  // [ saved LR           ]
+
+  // initialize fixed part of activation frame
+  __ stp(FP, LR, Address(SP, -2*wordSize, pre_indexed));
+  __ mov(FP, SP);                                     // establish new FP
+
+  // setup Rbcp
+  if (native_call) {
+    __ mov(Rbcp, ZR);                                 // bcp = 0 for native calls
+  } else {
+    __ add(Rbcp, RconstMethod, in_bytes(ConstMethod::codes_offset())); // get codebase
+  }
+
+  // Rstack_top & RextendedSP
+  __ sub(Rstack_top, SP, 10*wordSize);
+  if (native_call) {
+    __ sub(RextendedSP, Rstack_top, round_to(wordSize, StackAlignmentInBytes));    // reserve 1 slot for exception handling
+  } else {
+    __ sub(RextendedSP, Rstack_top, AsmOperand(RmaxStack, lsl, Interpreter::logStackElementSize));
+    __ align_reg(RextendedSP, RextendedSP, StackAlignmentInBytes);
+  }
+  __ mov(SP, RextendedSP);
+  __ check_stack_top();
+
+  // Load Rmdp
+  if (ProfileInterpreter) {
+    __ ldr(Rtemp, Address(Rmethod, Method::method_data_offset()));
+    __ tst(Rtemp, Rtemp);
+    __ add(Rtemp, Rtemp, in_bytes(MethodData::data_offset()));
+    __ csel(Rmdp, ZR, Rtemp, eq);
+  }
+
+  // Load Rcache
+  __ ldr(Rtemp, Address(RconstMethod, ConstMethod::constants_offset()));
+  __ ldr(Rcache, Address(Rtemp, ConstantPool::cache_offset_in_bytes()));
+  // Get mirror and store it in the frame as GC root for this Method*
+  __ load_mirror(Rtemp, Rmethod, Rtemp);
+
+  // Build fixed frame
+  __ stp(Rstack_top, Rbcp, Address(FP, -10*wordSize));
+  __ stp(Rlocals, Rcache,  Address(FP,  -8*wordSize));
+  __ stp(Rmdp, Rtemp,          Address(FP,  -6*wordSize));
+  __ stp(Rmethod, RextendedSP, Address(FP,  -4*wordSize));
+  __ stp(ZR, Rsender_sp,   Address(FP,  -2*wordSize));
+  assert(frame::interpreter_frame_initial_sp_offset == -10, "interpreter frame broken");
+  assert(frame::interpreter_frame_stack_top_offset  == -2, "stack top broken");
+}
+
+#else // AARCH64
+
+//
+// Generate a fixed interpreter frame. This is identical setup for interpreted methods
+// and for native methods hence the shared code.
+
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
+  // Generates the following stack layout:
+  //
+  // [ expr. stack bottom ]
+  // [ saved Rbcp         ]
+  // [ current Rlocals    ]
+  // [ cache              ]
+  // [ mdx                ]
+  // [ Method*            ]
+  // [ last_sp            ]
+  // [ sender_sp          ]
+  // [ saved FP           ] <--- FP
+  // [ saved LR           ]
+
+  // initialize fixed part of activation frame
+  __ push(LR);                                        // save return address
+  __ push(FP);                                        // save FP
+  __ mov(FP, SP);                                     // establish new FP
+
+  __ push(Rsender_sp);
+
+  __ mov(R0, 0);
+  __ push(R0);                                        // leave last_sp as null
+
+  // setup Rbcp
+  if (native_call) {
+    __ mov(Rbcp, 0);                                  // bcp = 0 for native calls
+  } else {
+    __ ldr(Rtemp, Address(Rmethod, Method::const_offset())); // get ConstMethod*
+    __ add(Rbcp, Rtemp, ConstMethod::codes_offset()); // get codebase
+  }
+
+  __ push(Rmethod);                                    // save Method*
+  // Get mirror and store it in the frame as GC root for this Method*
+  __ load_mirror(Rtemp, Rmethod, Rtemp);
+  __ push(Rtemp);
+
+  if (ProfileInterpreter) {
+    __ ldr(Rtemp, Address(Rmethod, Method::method_data_offset()));
+    __ tst(Rtemp, Rtemp);
+    __ add(Rtemp, Rtemp, in_bytes(MethodData::data_offset()), ne);
+    __ push(Rtemp);                                    // set the mdp (method data pointer)
+  } else {
+    __ push(R0);
+  }
+
+  __ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+  __ ldr(Rtemp, Address(Rtemp, ConstMethod::constants_offset()));
+  __ ldr(Rtemp, Address(Rtemp, ConstantPool::cache_offset_in_bytes()));
+  __ push(Rtemp);                                      // set constant pool cache
+  __ push(Rlocals);                                    // set locals pointer
+  __ push(Rbcp);                                       // set bcp
+  __ push(R0);                                         // reserve word for pointer to expression stack bottom
+  __ str(SP, Address(SP, 0));                          // set expression stack bottom
+}
+
+#endif // AARCH64
+
+// End of helpers
+
+//------------------------------------------------------------------------------------------------------------------------
+// Entry points
+//
+// Here we generate the various kind of entries into the interpreter.
+// The two main entry type are generic bytecode methods and native call method.
+// These both come in synchronized and non-synchronized versions but the
+// frame layout they create is very similar. The other method entry
+// types are really just special purpose entries that are really entry
+// and interpretation all in one. These are for trivial methods like
+// accessor, empty, or special math methods.
+//
+// When control flow reaches any of the entry types for the interpreter
+// the following holds ->
+//
+// Arguments:
+//
+// Rmethod: Method*
+// Rthread: thread
+// Rsender_sp:  sender sp
+// Rparams (SP on 32-bit ARM): pointer to method parameters
+//
+// LR: return address
+//
+// Stack layout immediately at entry
+//
+// [ optional padding(*)] <--- SP (AArch64)
+// [ parameter n        ] <--- Rparams (SP on 32-bit ARM)
+//   ...
+// [ parameter 1        ]
+// [ expression stack   ] (caller's java expression stack)
+
+// Assuming that we don't go to one of the trivial specialized
+// entries the stack will look like below when we are ready to execute
+// the first bytecode (or call the native routine). The register usage
+// will be as the template based interpreter expects.
+//
+// local variables follow incoming parameters immediately; i.e.
+// the return address is saved at the end of the locals.
+//
+// [ reserved stack (*) ] <--- SP (AArch64)
+// [ expr. stack        ] <--- Rstack_top (SP on 32-bit ARM)
+// [ monitor entry      ]
+//   ...
+// [ monitor entry      ]
+// [ expr. stack bottom ]
+// [ saved Rbcp         ]
+// [ current Rlocals    ]
+// [ cache              ]
+// [ mdx                ]
+// [ mirror             ]
+// [ Method*            ]
+//
+// 32-bit ARM:
+// [ last_sp            ]
+//
+// AArch64:
+// [ extended SP (*)    ]
+// [ stack top (*)      ]
+//
+// [ sender_sp          ]
+// [ saved FP           ] <--- FP
+// [ saved LR           ]
+// [ optional padding(*)]
+// [ local variable m   ]
+//   ...
+// [ local variable 1   ]
+// [ parameter n        ]
+//   ...
+// [ parameter 1        ] <--- Rlocals
+//
+// (*) - AArch64 only
+//
+
+address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
+#if INCLUDE_ALL_GCS
+  if (UseG1GC) {
+    // Code: _aload_0, _getfield, _areturn
+    // parameter size = 1
+    //
+    // The code that gets generated by this routine is split into 2 parts:
+    //    1. The "intrinsified" code for G1 (or any SATB based GC),
+    //    2. The slow path - which is an expansion of the regular method entry.
+    //
+    // Notes:-
+    // * In the G1 code we do not check whether we need to block for
+    //   a safepoint. If G1 is enabled then we must execute the specialized
+    //   code for Reference.get (except when the Reference object is null)
+    //   so that we can log the value in the referent field with an SATB
+    //   update buffer.
+    //   If the code for the getfield template is modified so that the
+    //   G1 pre-barrier code is executed when the current method is
+    //   Reference.get() then going through the normal method entry
+    //   will be fine.
+    // * The G1 code can, however, check the receiver object (the instance
+    //   of java.lang.Reference) and jump to the slow path if null. If the
+    //   Reference object is null then we obviously cannot fetch the referent
+    //   and so we don't need to call the G1 pre-barrier. Thus we can use the
+    //   regular method entry code to generate the NPE.
+    //
+    // This code is based on generate_accessor_enty.
+    //
+    // Rmethod: Method*
+    // Rthread: thread
+    // Rsender_sp: sender sp, must be preserved for slow path, set SP to it on fast path
+    // Rparams: parameters
+
+    address entry = __ pc();
+    Label slow_path;
+    const Register Rthis = R0;
+    const Register Rret_addr = Rtmp_save1;
+    assert_different_registers(Rthis, Rret_addr, Rsender_sp);
+
+    const int referent_offset = java_lang_ref_Reference::referent_offset;
+    guarantee(referent_offset > 0, "referent offset not initialized");
+
+    // Check if local 0 != NULL
+    // If the receiver is null then it is OK to jump to the slow path.
+    __ ldr(Rthis, Address(Rparams));
+    __ cbz(Rthis, slow_path);
+
+    // Generate the G1 pre-barrier code to log the value of
+    // the referent field in an SATB buffer.
+
+    // Load the value of the referent field.
+    __ load_heap_oop(R0, Address(Rthis, referent_offset));
+
+    // Preserve LR
+    __ mov(Rret_addr, LR);
+
+    __ g1_write_barrier_pre(noreg,   // store_addr
+                            noreg,   // new_val
+                            R0,      // pre_val
+                            Rtemp,   // tmp1
+                            R1_tmp); // tmp2
+
+    // _areturn
+    __ mov(SP, Rsender_sp);
+    __ ret(Rret_addr);
+
+    // generate a vanilla interpreter entry as the slow path
+    __ bind(slow_path);
+    __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
+    return entry;
+  }
+#endif // INCLUDE_ALL_GCS
+
+  // If G1 is not enabled then attempt to go through the normal entry point
+  return NULL;
+}
+
+// Not supported
+address TemplateInterpreterGenerator::generate_CRC32_update_entry() { return NULL; }
+address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; }
+address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; }
+
+//
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the native method
+// than the typical interpreter frame setup.
+//
+
+address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
+  // determine code generation flags
+  bool inc_counter  = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+  // Incoming registers:
+  //
+  // Rmethod: Method*
+  // Rthread: thread
+  // Rsender_sp: sender sp
+  // Rparams: parameters
+
+  address entry_point = __ pc();
+
+  // Register allocation
+  const Register Rsize_of_params = AARCH64_ONLY(R20) NOT_AARCH64(R6);
+  const Register Rsig_handler    = AARCH64_ONLY(R21) NOT_AARCH64(Rtmp_save0 /* R4 */);
+  const Register Rnative_code    = AARCH64_ONLY(R22) NOT_AARCH64(Rtmp_save1 /* R5 */);
+  const Register Rresult_handler = AARCH64_ONLY(Rsig_handler) NOT_AARCH64(R6);
+
+#ifdef AARCH64
+  const Register RconstMethod = R10; // also used in generate_fixed_frame (should match)
+  const Register Rsaved_result = Rnative_code;
+  const FloatRegister Dsaved_result = V8;
+#else
+  const Register Rsaved_result_lo = Rtmp_save0;  // R4
+  const Register Rsaved_result_hi = Rtmp_save1;  // R5
+  FloatRegister saved_result_fp;
+#endif // AARCH64
+
+
+#ifdef AARCH64
+  __ ldr(RconstMethod, Address(Rmethod, Method::const_offset()));
+  __ ldrh(Rsize_of_params,  Address(RconstMethod, ConstMethod::size_of_parameters_offset()));
+#else
+  __ ldr(Rsize_of_params, Address(Rmethod, Method::const_offset()));
+  __ ldrh(Rsize_of_params,  Address(Rsize_of_params, ConstMethod::size_of_parameters_offset()));
+#endif // AARCH64
+
+  // native calls don't need the stack size check since they have no expression stack
+  // and the arguments are already on the stack and we only add a handful of words
+  // to the stack
+
+  // compute beginning of parameters (Rlocals)
+  __ sub(Rlocals, Rparams, wordSize);
+  __ add(Rlocals, Rlocals, AsmOperand(Rsize_of_params, lsl, Interpreter::logStackElementSize));
+
+#ifdef AARCH64
+  int extra_stack_reserve = 2*wordSize; // extra space for oop_temp
+  if(__ can_post_interpreter_events()) {
+    // extra space for saved results
+    extra_stack_reserve += 2*wordSize;
+  }
+  // reserve extra stack space and nullify oop_temp slot
+  __ stp(ZR, ZR, Address(SP, -extra_stack_reserve, pre_indexed));
+#else
+  // reserve stack space for oop_temp
+  __ mov(R0, 0);
+  __ push(R0);
+#endif // AARCH64
+
+  generate_fixed_frame(true); // Note: R9 is now saved in the frame
+
+  // make sure method is native & not abstract
+#ifdef ASSERT
+  __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+  {
+    Label L;
+    __ tbnz(Rtemp, JVM_ACC_NATIVE_BIT, L);
+    __ stop("tried to execute non-native method as native");
+    __ bind(L);
+  }
+  { Label L;
+    __ tbz(Rtemp, JVM_ACC_ABSTRACT_BIT, L);
+    __ stop("tried to execute abstract method in interpreter");
+    __ bind(L);
+  }
+#endif
+
+  // increment invocation count & check for overflow
+  Label invocation_counter_overflow;
+  if (inc_counter) {
+    if (synchronized) {
+      // Avoid unlocking method's monitor in case of exception, as it has not
+      // been locked yet.
+      __ set_do_not_unlock_if_synchronized(true, Rtemp);
+    }
+    generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+  }
+
+  Label continue_after_compile;
+  __ bind(continue_after_compile);
+
+  if (inc_counter && synchronized) {
+    __ set_do_not_unlock_if_synchronized(false, Rtemp);
+  }
+
+  // check for synchronized methods
+  // Must happen AFTER invocation_counter check and stack overflow check,
+  // so method is not locked if overflows.
+  //
+  if (synchronized) {
+    lock_method();
+  } else {
+    // no synchronization necessary
+#ifdef ASSERT
+      { Label L;
+        __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+        __ tbz(Rtemp, JVM_ACC_SYNCHRONIZED_BIT, L);
+        __ stop("method needs synchronization");
+        __ bind(L);
+      }
+#endif
+  }
+
+  // start execution
+#ifdef ASSERT
+  { Label L;
+    __ ldr(Rtemp, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+    __ cmp(Rtemp, Rstack_top);
+    __ b(L, eq);
+    __ stop("broken stack frame setup in interpreter");
+    __ bind(L);
+  }
+#endif
+  __ check_extended_sp(Rtemp);
+
+  // jvmti/dtrace support
+  __ notify_method_entry();
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+
+  {
+    Label L;
+    __ ldr(Rsig_handler, Address(Rmethod, Method::signature_handler_offset()));
+    __ cbnz(Rsig_handler, L);
+    __ mov(R1, Rmethod);
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R1, true);
+    __ ldr(Rsig_handler, Address(Rmethod, Method::signature_handler_offset()));
+    __ bind(L);
+  }
+
+  {
+    Label L;
+    __ ldr(Rnative_code, Address(Rmethod, Method::native_function_offset()));
+    __ cbnz(Rnative_code, L);
+    __ mov(R1, Rmethod);
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R1);
+    __ ldr(Rnative_code, Address(Rmethod, Method::native_function_offset()));
+    __ bind(L);
+  }
+
+  // Allocate stack space for arguments
+
+#ifdef AARCH64
+  __ sub(Rtemp, SP, Rsize_of_params, ex_uxtw, LogBytesPerWord);
+  __ align_reg(SP, Rtemp, StackAlignmentInBytes);
+
+  // Allocate more stack space to accomodate all arguments passed on GP and FP registers:
+  // 8 * wordSize for GPRs
+  // 8 * wordSize for FPRs
+  int reg_arguments = round_to(8*wordSize + 8*wordSize, StackAlignmentInBytes);
+#else
+
+  // C functions need aligned stack
+  __ bic(SP, SP, StackAlignmentInBytes - 1);
+  // Multiply by BytesPerLong instead of BytesPerWord, because calling convention
+  // may require empty slots due to long alignment, e.g. func(int, jlong, int, jlong)
+  __ sub(SP, SP, AsmOperand(Rsize_of_params, lsl, LogBytesPerLong));
+
+#ifdef __ABI_HARD__
+  // Allocate more stack space to accomodate all GP as well as FP registers:
+  // 4 * wordSize
+  // 8 * BytesPerLong
+  int reg_arguments = round_to((4*wordSize) + (8*BytesPerLong), StackAlignmentInBytes);
+#else
+  // Reserve at least 4 words on the stack for loading
+  // of parameters passed on registers (R0-R3).
+  // See generate_slow_signature_handler().
+  // It is also used for JNIEnv & class additional parameters.
+  int reg_arguments = 4 * wordSize;
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+  __ sub(SP, SP, reg_arguments);
+
+
+  // Note: signature handler blows R4 (32-bit ARM) or R21 (AArch64) besides all scratch registers.
+  // See AbstractInterpreterGenerator::generate_slow_signature_handler().
+  __ call(Rsig_handler);
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+  __ mov(Rresult_handler, R0);
+
+  // Pass JNIEnv and mirror for static methods
+  {
+    Label L;
+    __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+    __ add(R0, Rthread, in_bytes(JavaThread::jni_environment_offset()));
+    __ tbz(Rtemp, JVM_ACC_STATIC_BIT, L);
+    __ load_mirror(Rtemp, Rmethod, Rtemp);
+    __ add(R1, FP, frame::interpreter_frame_oop_temp_offset * wordSize);
+    __ str(Rtemp, Address(R1, 0));
+    __ bind(L);
+  }
+
+  __ set_last_Java_frame(SP, FP, true, Rtemp);
+
+  // Changing state to _thread_in_native must be the last thing to do
+  // before the jump to native code. At this moment stack must be
+  // safepoint-safe and completely prepared for stack walking.
+#ifdef ASSERT
+  {
+    Label L;
+    __ ldr_u32(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+    __ cmp_32(Rtemp, _thread_in_Java);
+    __ b(L, eq);
+    __ stop("invalid thread state");
+    __ bind(L);
+  }
+#endif
+
+#ifdef AARCH64
+  __ mov(Rtemp, _thread_in_native);
+  __ add(Rtemp2, Rthread, in_bytes(JavaThread::thread_state_offset()));
+  // STLR is used to force all preceding writes to be observed prior to thread state change
+  __ stlr_w(Rtemp, Rtemp2);
+#else
+  // Force all preceding writes to be observed prior to thread state change
+  __ membar(MacroAssembler::StoreStore, Rtemp);
+
+  __ mov(Rtemp, _thread_in_native);
+  __ str(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+#endif // AARCH64
+
+  __ call(Rnative_code);
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+
+  // Set FPSCR/FPCR to a known state
+  if (AlwaysRestoreFPU) {
+    __ restore_default_fp_mode();
+  }
+
+  // Do safepoint check
+  __ mov(Rtemp, _thread_in_native_trans);
+  __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+
+    // Force this write out before the read below
+  __ membar(MacroAssembler::StoreLoad, Rtemp);
+
+  __ ldr_global_s32(Rtemp, SafepointSynchronize::address_of_state());
+
+  // Protect the return value in the interleaved code: save it to callee-save registers.
+#ifdef AARCH64
+  __ mov(Rsaved_result, R0);
+  __ fmov_d(Dsaved_result, D0);
+#else
+  __ mov(Rsaved_result_lo, R0);
+  __ mov(Rsaved_result_hi, R1);
+#ifdef __ABI_HARD__
+  // preserve native FP result in a callee-saved register
+  saved_result_fp = D8;
+  __ fcpyd(saved_result_fp, D0);
+#else
+  saved_result_fp = fnoreg;
+#endif // __ABI_HARD__
+#endif // AARCH64
+
+  {
+    __ ldr_u32(R3, Address(Rthread, JavaThread::suspend_flags_offset()));
+    __ cmp(Rtemp, SafepointSynchronize::_not_synchronized);
+    __ cond_cmp(R3, 0, eq);
+
+#ifdef AARCH64
+    Label L;
+    __ b(L, eq);
+    __ mov(R0, Rthread);
+    __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), relocInfo::none);
+    __ bind(L);
+#else
+  __ mov(R0, Rthread, ne);
+  __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), relocInfo::none, ne);
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+#endif // AARCH64
+  }
+
+  // Perform Native->Java thread transition
+  __ mov(Rtemp, _thread_in_Java);
+  __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset()));
+
+  // Zero handles and last_java_sp
+  __ reset_last_Java_frame(Rtemp);
+  __ ldr(R3, Address(Rthread, JavaThread::active_handles_offset()));
+  __ str_32(__ zero_register(Rtemp), Address(R3, JNIHandleBlock::top_offset_in_bytes()));
+  if (CheckJNICalls) {
+    __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
+  }
+
+  // Unbox if the result is non-zero object
+#ifdef AARCH64
+  {
+    Label L, Lnull;
+    __ mov_slow(Rtemp, AbstractInterpreter::result_handler(T_OBJECT));
+    __ cmp(Rresult_handler, Rtemp);
+    __ b(L, ne);
+    __ cbz(Rsaved_result, Lnull);
+    __ ldr(Rsaved_result, Address(Rsaved_result));
+    __ bind(Lnull);
+    // Store oop on the stack for GC
+    __ str(Rsaved_result, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize));
+    __ bind(L);
+  }
+#else
+  __ tst(Rsaved_result_lo, Rresult_handler);
+  __ ldr(Rsaved_result_lo, Address(Rsaved_result_lo), ne);
+
+  // Store oop on the stack for GC
+  __ cmp(Rresult_handler, 0);
+  __ str(Rsaved_result_lo, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize), ne);
+#endif // AARCH64
+
+#ifdef AARCH64
+  // Restore SP (drop native parameters area), to keep SP in sync with extended_sp in frame
+  __ restore_sp_after_call(Rtemp);
+  __ check_stack_top();
+#endif // AARCH64
+
+  // reguard stack if StackOverflow exception happened while in native.
+  {
+    __ ldr_u32(Rtemp, Address(Rthread, JavaThread::stack_guard_state_offset()));
+    __ cmp_32(Rtemp, JavaThread::stack_guard_yellow_reserved_disabled);
+#ifdef AARCH64
+    Label L;
+    __ b(L, ne);
+    __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), relocInfo::none);
+    __ bind(L);
+#else
+  __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), relocInfo::none, eq);
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+#endif // AARCH64
+  }
+
+  // check pending exceptions
+  {
+    __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
+#ifdef AARCH64
+    Label L;
+    __ cbz(Rtemp, L);
+    __ mov_pc_to(Rexception_pc);
+    __ b(StubRoutines::forward_exception_entry());
+    __ bind(L);
+#else
+    __ cmp(Rtemp, 0);
+    __ mov(Rexception_pc, PC, ne);
+    __ b(StubRoutines::forward_exception_entry(), ne);
+#endif // AARCH64
+  }
+
+  if (synchronized) {
+    // address of first monitor
+    __ sub(R1, FP, - (frame::interpreter_frame_monitor_block_bottom_offset - frame::interpreter_frame_monitor_size()) * wordSize);
+    __ unlock_object(R1);
+  }
+
+  // jvmti/dtrace support
+  // Note: This must happen _after_ handling/throwing any exceptions since
+  //       the exception handler code notifies the runtime of method exits
+  //       too. If this happens before, method entry/exit notifications are
+  //       not properly paired (was bug - gri 11/22/99).
+#ifdef AARCH64
+  __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI, true, Rsaved_result, noreg, Dsaved_result);
+#else
+  __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI, true, Rsaved_result_lo, Rsaved_result_hi, saved_result_fp);
+#endif // AARCH64
+
+  // Restore the result. Oop result is restored from the stack.
+#ifdef AARCH64
+  __ mov(R0, Rsaved_result);
+  __ fmov_d(D0, Dsaved_result);
+
+  __ blr(Rresult_handler);
+#else
+  __ cmp(Rresult_handler, 0);
+  __ ldr(R0, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize), ne);
+  __ mov(R0, Rsaved_result_lo, eq);
+  __ mov(R1, Rsaved_result_hi);
+
+#ifdef __ABI_HARD__
+  // reload native FP result
+  __ fcpyd(D0, D8);
+#endif // __ABI_HARD__
+
+#ifdef ASSERT
+  if (VerifyOops) {
+    Label L;
+    __ cmp(Rresult_handler, 0);
+    __ b(L, eq);
+    __ verify_oop(R0);
+    __ bind(L);
+  }
+#endif // ASSERT
+#endif // AARCH64
+
+  // Restore FP/LR, sender_sp and return
+#ifdef AARCH64
+  __ ldr(Rtemp, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+  __ ldp(FP, LR, Address(FP));
+  __ mov(SP, Rtemp);
+#else
+  __ mov(Rtemp, FP);
+  __ ldmia(FP, RegisterSet(FP) | RegisterSet(LR));
+  __ ldr(SP, Address(Rtemp, frame::interpreter_frame_sender_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ ret();
+
+  if (inc_counter) {
+    // Handle overflow of counter and compile method
+    __ bind(invocation_counter_overflow);
+    generate_counter_overflow(continue_after_compile);
+  }
+
+  return entry_point;
+}
+
+//
+// Generic interpreted method entry to (asm) interpreter
+//
+address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
+  // determine code generation flags
+  bool inc_counter  = UseCompiler || CountCompiledCalls || LogTouchedMethods;
+
+  // Rmethod: Method*
+  // Rthread: thread
+  // Rsender_sp: sender sp (could differ from SP if we were called via c2i)
+  // Rparams: pointer to the last parameter in the stack
+
+  address entry_point = __ pc();
+
+  const Register RconstMethod = AARCH64_ONLY(R10) NOT_AARCH64(R3);
+
+#ifdef AARCH64
+  const Register RmaxStack = R11;
+  const Register RlocalsBase = R12;
+#endif // AARCH64
+
+  __ ldr(RconstMethod, Address(Rmethod, Method::const_offset()));
+
+  __ ldrh(R2, Address(RconstMethod, ConstMethod::size_of_parameters_offset()));
+  __ ldrh(R3, Address(RconstMethod, ConstMethod::size_of_locals_offset()));
+
+  // setup Rlocals
+  __ sub(Rlocals, Rparams, wordSize);
+  __ add(Rlocals, Rlocals, AsmOperand(R2, lsl, Interpreter::logStackElementSize));
+
+  __ sub(R3, R3, R2); // number of additional locals
+
+#ifdef AARCH64
+  // setup RmaxStack
+  __ ldrh(RmaxStack, Address(RconstMethod, ConstMethod::max_stack_offset()));
+  __ add(RmaxStack, RmaxStack, MAX2(1, Method::extra_stack_entries())); // reserve slots for exception handler and JSR292 appendix argument
+#endif // AARCH64
+
+  // see if we've got enough room on the stack for locals plus overhead.
+  generate_stack_overflow_check();
+
+#ifdef AARCH64
+
+  // allocate space for locals
+  {
+    __ sub(RlocalsBase, Rparams, AsmOperand(R3, lsl, Interpreter::logStackElementSize));
+    __ align_reg(SP, RlocalsBase, StackAlignmentInBytes);
+  }
+
+  // explicitly initialize locals
+  {
+    Label zero_loop, done;
+    __ cbz(R3, done);
+
+    __ tbz(R3, 0, zero_loop);
+    __ subs(R3, R3, 1);
+    __ str(ZR, Address(RlocalsBase, wordSize, post_indexed));
+    __ b(done, eq);
+
+    __ bind(zero_loop);
+    __ subs(R3, R3, 2);
+    __ stp(ZR, ZR, Address(RlocalsBase, 2*wordSize, post_indexed));
+    __ b(zero_loop, ne);
+
+    __ bind(done);
+  }
+
+#else
+  // allocate space for locals
+  // explicitly initialize locals
+
+  // Loop is unrolled 4 times
+  Label loop;
+  __ mov(R0, 0);
+  __ bind(loop);
+
+  // #1
+  __ subs(R3, R3, 1);
+  __ push(R0, ge);
+
+  // #2
+  __ subs(R3, R3, 1, ge);
+  __ push(R0, ge);
+
+  // #3
+  __ subs(R3, R3, 1, ge);
+  __ push(R0, ge);
+
+  // #4
+  __ subs(R3, R3, 1, ge);
+  __ push(R0, ge);
+
+  __ b(loop, gt);
+#endif // AARCH64
+
+  // initialize fixed part of activation frame
+  generate_fixed_frame(false);
+
+  __ restore_dispatch();
+
+  // make sure method is not native & not abstract
+#ifdef ASSERT
+  __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+  {
+    Label L;
+    __ tbz(Rtemp, JVM_ACC_NATIVE_BIT, L);
+    __ stop("tried to execute native method as non-native");
+    __ bind(L);
+  }
+  { Label L;
+    __ tbz(Rtemp, JVM_ACC_ABSTRACT_BIT, L);
+    __ stop("tried to execute abstract method in interpreter");
+    __ bind(L);
+  }
+#endif
+
+  // increment invocation count & check for overflow
+  Label invocation_counter_overflow;
+  Label profile_method;
+  Label profile_method_continue;
+  if (inc_counter) {
+    if (synchronized) {
+      // Avoid unlocking method's monitor in case of exception, as it has not
+      // been locked yet.
+      __ set_do_not_unlock_if_synchronized(true, Rtemp);
+    }
+    generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
+    if (ProfileInterpreter) {
+      __ bind(profile_method_continue);
+    }
+  }
+  Label continue_after_compile;
+  __ bind(continue_after_compile);
+
+  if (inc_counter && synchronized) {
+    __ set_do_not_unlock_if_synchronized(false, Rtemp);
+  }
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+
+  // check for synchronized methods
+  // Must happen AFTER invocation_counter check and stack overflow check,
+  // so method is not locked if overflows.
+  //
+  if (synchronized) {
+    // Allocate monitor and lock method
+    lock_method();
+  } else {
+    // no synchronization necessary
+#ifdef ASSERT
+      { Label L;
+        __ ldr_u32(Rtemp, Address(Rmethod, Method::access_flags_offset()));
+        __ tbz(Rtemp, JVM_ACC_SYNCHRONIZED_BIT, L);
+        __ stop("method needs synchronization");
+        __ bind(L);
+      }
+#endif
+  }
+
+  // start execution
+#ifdef ASSERT
+  { Label L;
+    __ ldr(Rtemp, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+    __ cmp(Rtemp, Rstack_top);
+    __ b(L, eq);
+    __ stop("broken stack frame setup in interpreter");
+    __ bind(L);
+  }
+#endif
+  __ check_extended_sp(Rtemp);
+
+  // jvmti support
+  __ notify_method_entry();
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+
+  __ dispatch_next(vtos);
+
+  // invocation counter overflow
+  if (inc_counter) {
+    if (ProfileInterpreter) {
+      // We have decided to profile this method in the interpreter
+      __ bind(profile_method);
+
+      __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+      __ set_method_data_pointer_for_bcp();
+
+      __ b(profile_method_continue);
+    }
+
+    // Handle overflow of counter and compile method
+    __ bind(invocation_counter_overflow);
+    generate_counter_overflow(continue_after_compile);
+  }
+
+  return entry_point;
+}
+
+//------------------------------------------------------------------------------------------------------------------------
+// Exceptions
+
+void TemplateInterpreterGenerator::generate_throw_exception() {
+  // Entry point in previous activation (i.e., if the caller was interpreted)
+  Interpreter::_rethrow_exception_entry = __ pc();
+  // Rexception_obj: exception
+
+#ifndef AARCH64
+  // Clear interpreter_frame_last_sp.
+  __ mov(Rtemp, 0);
+  __ str(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // !AARCH64
+
+#if R9_IS_SCRATCHED
+  __ restore_method();
+#endif
+  __ restore_bcp();
+  __ restore_dispatch();
+  __ restore_locals();
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp);
+#endif // AARCH64
+
+  // Entry point for exceptions thrown within interpreter code
+  Interpreter::_throw_exception_entry = __ pc();
+
+  // expression stack is undefined here
+  // Rexception_obj: exception
+  // Rbcp: exception bcp
+  __ verify_oop(Rexception_obj);
+
+  // expression stack must be empty before entering the VM in case of an exception
+  __ empty_expression_stack();
+  // find exception handler address and preserve exception oop
+  __ mov(R1, Rexception_obj);
+  __ call_VM(Rexception_obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), R1);
+  // R0: exception handler entry point
+  // Rexception_obj: preserved exception oop
+  // Rbcp: bcp for exception handler
+  __ push_ptr(Rexception_obj);                    // push exception which is now the only value on the stack
+  __ jump(R0);                                    // jump to exception handler (may be _remove_activation_entry!)
+
+  // If the exception is not handled in the current frame the frame is removed and
+  // the exception is rethrown (i.e. exception continuation is _rethrow_exception).
+  //
+  // Note: At this point the bci is still the bxi for the instruction which caused
+  //       the exception and the expression stack is empty. Thus, for any VM calls
+  //       at this point, GC will find a legal oop map (with empty expression stack).
+
+  // In current activation
+  // tos: exception
+  // Rbcp: exception bcp
+
+  //
+  // JVMTI PopFrame support
+  //
+   Interpreter::_remove_activation_preserving_args_entry = __ pc();
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp); // restore SP to extended SP
+#endif // AARCH64
+
+  __ empty_expression_stack();
+
+  // Set the popframe_processing bit in _popframe_condition indicating that we are
+  // currently handling popframe, so that call_VMs that may happen later do not trigger new
+  // popframe handling cycles.
+
+  __ ldr_s32(Rtemp, Address(Rthread, JavaThread::popframe_condition_offset()));
+  __ orr(Rtemp, Rtemp, (unsigned)JavaThread::popframe_processing_bit);
+  __ str_32(Rtemp, Address(Rthread, JavaThread::popframe_condition_offset()));
+
+  {
+    // Check to see whether we are returning to a deoptimized frame.
+    // (The PopFrame call ensures that the caller of the popped frame is
+    // either interpreted or compiled and deoptimizes it if compiled.)
+    // In this case, we can't call dispatch_next() after the frame is
+    // popped, but instead must save the incoming arguments and restore
+    // them after deoptimization has occurred.
+    //
+    // Note that we don't compare the return PC against the
+    // deoptimization blob's unpack entry because of the presence of
+    // adapter frames in C2.
+    Label caller_not_deoptimized;
+    __ ldr(R0, Address(FP, frame::return_addr_offset * wordSize));
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), R0);
+    __ cbnz_32(R0, caller_not_deoptimized);
+#ifdef AARCH64
+    __ NOT_TESTED();
+#endif
+
+    // Compute size of arguments for saving when returning to deoptimized caller
+    __ restore_method();
+    __ ldr(R0, Address(Rmethod, Method::const_offset()));
+    __ ldrh(R0, Address(R0, ConstMethod::size_of_parameters_offset()));
+
+    __ logical_shift_left(R1, R0, Interpreter::logStackElementSize);
+    // Save these arguments
+    __ restore_locals();
+    __ sub(R2, Rlocals, R1);
+    __ add(R2, R2, wordSize);
+    __ mov(R0, Rthread);
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R0, R1, R2);
+
+    __ remove_activation(vtos, LR,
+                         /* throw_monitor_exception */ false,
+                         /* install_monitor_exception */ false,
+                         /* notify_jvmdi */ false);
+
+    // Inform deoptimization that it is responsible for restoring these arguments
+    __ mov(Rtemp, JavaThread::popframe_force_deopt_reexecution_bit);
+    __ str_32(Rtemp, Address(Rthread, JavaThread::popframe_condition_offset()));
+
+    // Continue in deoptimization handler
+    __ ret();
+
+    __ bind(caller_not_deoptimized);
+  }
+
+  __ remove_activation(vtos, R4,
+                       /* throw_monitor_exception */ false,
+                       /* install_monitor_exception */ false,
+                       /* notify_jvmdi */ false);
+
+#ifndef AARCH64
+  // Finish with popframe handling
+  // A previous I2C followed by a deoptimization might have moved the
+  // outgoing arguments further up the stack. PopFrame expects the
+  // mutations to those outgoing arguments to be preserved and other
+  // constraints basically require this frame to look exactly as
+  // though it had previously invoked an interpreted activation with
+  // no space between the top of the expression stack (current
+  // last_sp) and the top of stack. Rather than force deopt to
+  // maintain this kind of invariant all the time we call a small
+  // fixup routine to move the mutated arguments onto the top of our
+  // expression stack if necessary.
+  __ mov(R1, SP);
+  __ ldr(R2, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+  // PC must point into interpreter here
+  __ set_last_Java_frame(SP, FP, true, Rtemp);
+  __ mov(R0, Rthread);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), R0, R1, R2);
+  __ reset_last_Java_frame(Rtemp);
+#endif // !AARCH64
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp);
+  __ restore_stack_top();
+#else
+  // Restore the last_sp and null it out
+  __ ldr(SP, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+  __ mov(Rtemp, (int)NULL_WORD);
+  __ str(Rtemp, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+#endif // AARCH64
+
+  __ restore_bcp();
+  __ restore_dispatch();
+  __ restore_locals();
+  __ restore_method();
+
+  // The method data pointer was incremented already during
+  // call profiling. We have to restore the mdp for the current bcp.
+  if (ProfileInterpreter) {
+    __ set_method_data_pointer_for_bcp();
+  }
+
+  // Clear the popframe condition flag
+  assert(JavaThread::popframe_inactive == 0, "adjust this code");
+  __ str_32(__ zero_register(Rtemp), Address(Rthread, JavaThread::popframe_condition_offset()));
+
+#if INCLUDE_JVMTI
+  {
+    Label L_done;
+
+    __ ldrb(Rtemp, Address(Rbcp, 0));
+    __ cmp(Rtemp, Bytecodes::_invokestatic);
+    __ b(L_done, ne);
+
+    // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
+    // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
+
+    // get local0
+    __ ldr(R1, Address(Rlocals, 0));
+    __ mov(R2, Rmethod);
+    __ mov(R3, Rbcp);
+    __ call_VM(R0, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), R1, R2, R3);
+
+    __ cbz(R0, L_done);
+
+    __ str(R0, Address(Rstack_top));
+    __ bind(L_done);
+  }
+#endif // INCLUDE_JVMTI
+
+  __ dispatch_next(vtos);
+  // end of PopFrame support
+
+  Interpreter::_remove_activation_entry = __ pc();
+
+  // preserve exception over this code sequence
+  __ pop_ptr(R0_tos);
+  __ str(R0_tos, Address(Rthread, JavaThread::vm_result_offset()));
+  // remove the activation (without doing throws on illegalMonitorExceptions)
+  __ remove_activation(vtos, Rexception_pc, false, true, false);
+  // restore exception
+  __ get_vm_result(Rexception_obj, Rtemp);
+
+  // Inbetween activations - previous activation type unknown yet
+  // compute continuation point - the continuation point expects
+  // the following registers set up:
+  //
+  // Rexception_obj: exception
+  // Rexception_pc: return address/pc that threw exception
+  // SP: expression stack of caller
+  // FP: frame pointer of caller
+  __ mov(c_rarg0, Rthread);
+  __ mov(c_rarg1, Rexception_pc);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), c_rarg0, c_rarg1);
+  // Note that an "issuing PC" is actually the next PC after the call
+
+  __ jump(R0);                             // jump to exception handler of caller
+}
+
+
+//
+// JVMTI ForceEarlyReturn support
+//
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+  address entry = __ pc();
+
+#ifdef AARCH64
+  __ restore_sp_after_call(Rtemp); // restore SP to extended SP
+#endif // AARCH64
+
+  __ restore_bcp();
+  __ restore_dispatch();
+  __ restore_locals();
+
+  __ empty_expression_stack();
+
+  __ load_earlyret_value(state);
+
+  // Clear the earlyret state
+  __ ldr(Rtemp, Address(Rthread, JavaThread::jvmti_thread_state_offset()));
+
+  assert(JvmtiThreadState::earlyret_inactive == 0, "adjust this code");
+  __ str_32(__ zero_register(R2), Address(Rtemp, JvmtiThreadState::earlyret_state_offset()));
+
+  __ remove_activation(state, LR,
+                       false, /* throw_monitor_exception */
+                       false, /* install_monitor_exception */
+                       true); /* notify_jvmdi */
+
+#ifndef AARCH64
+  // According to interpreter calling conventions, result is returned in R0/R1,
+  // so ftos (S0) and dtos (D0) are moved to R0/R1.
+  // This conversion should be done after remove_activation, as it uses
+  // push(state) & pop(state) to preserve return value.
+  __ convert_tos_to_retval(state);
+#endif // !AARCH64
+  __ ret();
+
+  return entry;
+} // end of ForceEarlyReturn support
+
+
+//------------------------------------------------------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
+  assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+  Label L;
+
+#ifdef __SOFTFP__
+  dep = __ pc();                // fall through
+#else
+  fep = __ pc(); __ push(ftos); __ b(L);
+  dep = __ pc(); __ push(dtos); __ b(L);
+#endif // __SOFTFP__
+
+  lep = __ pc(); __ push(ltos); __ b(L);
+
+  if (AARCH64_ONLY(true) NOT_AARCH64(VerifyOops)) {  // can't share atos entry with itos on AArch64 or if VerifyOops
+    aep = __ pc(); __ push(atos); __ b(L);
+  } else {
+    aep = __ pc();              // fall through
+  }
+
+#ifdef __SOFTFP__
+  fep = __ pc();                // fall through
+#endif // __SOFTFP__
+
+  bep = cep = sep =             // fall through
+  iep = __ pc(); __ push(itos); // fall through
+  vep = __ pc(); __ bind(L);    // fall through
+  generate_and_dispatch(t);
+}
+
+//------------------------------------------------------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+  address entry = __ pc();
+
+  // prepare expression stack
+  __ push(state);       // save tosca
+
+  // pass tosca registers as arguments
+  __ mov(R2, R0_tos);
+#ifdef AARCH64
+  __ mov(R3, ZR);
+#else
+  __ mov(R3, R1_tos_hi);
+#endif // AARCH64
+  __ mov(R1, LR);       // save return address
+
+  // call tracer
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), R1, R2, R3);
+
+  __ mov(LR, R0);       // restore return address
+  __ pop(state);        // restore tosca
+
+  // return
+  __ ret();
+
+  return entry;
+}
+
+
+void TemplateInterpreterGenerator::count_bytecode() {
+  __ inc_global_counter((address) &BytecodeCounter::_counter_value, 0, Rtemp, R2_tmp, true);
+}
+
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
+  __ inc_global_counter((address)&BytecodeHistogram::_counters[0], sizeof(BytecodeHistogram::_counters[0]) * t->bytecode(), Rtemp, R2_tmp, true);
+}
+
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
+  const Register Rindex_addr = R2_tmp;
+  Label Lcontinue;
+  InlinedAddress Lcounters((address)BytecodePairHistogram::_counters);
+  InlinedAddress Lindex((address)&BytecodePairHistogram::_index);
+  const Register Rcounters_addr = R2_tmp;
+  const Register Rindex = R4_tmp;
+
+  // calculate new index for counter:
+  // index = (_index >> log2_number_of_codes) | (bytecode << log2_number_of_codes).
+  // (_index >> log2_number_of_codes) is previous bytecode
+
+  __ ldr_literal(Rindex_addr, Lindex);
+  __ ldr_s32(Rindex, Address(Rindex_addr));
+  __ mov_slow(Rtemp, ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes);
+  __ orr(Rindex, Rtemp, AsmOperand(Rindex, lsr, BytecodePairHistogram::log2_number_of_codes));
+  __ str_32(Rindex, Address(Rindex_addr));
+
+  // Rindex (R4) contains index of counter
+
+  __ ldr_literal(Rcounters_addr, Lcounters);
+  __ ldr_s32(Rtemp, Address::indexed_32(Rcounters_addr, Rindex));
+  __ adds_32(Rtemp, Rtemp, 1);
+  __ b(Lcontinue, mi);                           // avoid overflow
+  __ str_32(Rtemp, Address::indexed_32(Rcounters_addr, Rindex));
+
+  __ b(Lcontinue);
+
+  __ bind_literal(Lindex);
+  __ bind_literal(Lcounters);
+
+  __ bind(Lcontinue);
+}
+
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+  // Call a little run-time stub to avoid blow-up for each bytecode.
+  // The run-time runtime saves the right registers, depending on
+  // the tosca in-state for the given template.
+  assert(Interpreter::trace_code(t->tos_in()) != NULL,
+         "entry must have been generated");
+  address trace_entry = Interpreter::trace_code(t->tos_in());
+  __ call(trace_entry, relocInfo::none);
+}
+
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+  Label Lcontinue;
+  const Register stop_at = R2_tmp;
+
+  __ ldr_global_s32(Rtemp, (address) &BytecodeCounter::_counter_value);
+  __ mov_slow(stop_at, StopInterpreterAt);
+
+  // test bytecode counter
+  __ cmp(Rtemp, stop_at);
+  __ b(Lcontinue, ne);
+
+  __ trace_state("stop_interpreter_at");
+  __ breakpoint();
+
+  __ bind(Lcontinue);
+}
+#endif // !PRODUCT
diff --git a/hotspot/src/cpu/arm/vm/templateTable_arm.cpp b/hotspot/src/cpu/arm/vm/templateTable_arm.cpp
new file mode 100644
index 0000000..c8711b8
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/templateTable_arm.cpp
@@ -0,0 +1,5030 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "interpreter/interp_masm.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateTable.hpp"
+#include "memory/universe.inline.hpp"
+#include "oops/cpCache.hpp"
+#include "oops/methodData.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+
+#define __ _masm->
+
+//----------------------------------------------------------------------------------------------------
+// Platform-dependent initialization
+
+void TemplateTable::pd_initialize() {
+  // No arm specific initialization
+}
+
+//----------------------------------------------------------------------------------------------------
+// Address computation
+
+// local variables
+static inline Address iaddress(int n)            {
+  return Address(Rlocals, Interpreter::local_offset_in_bytes(n));
+}
+
+static inline Address laddress(int n)            { return iaddress(n + 1); }
+#ifndef AARCH64
+static inline Address haddress(int n)            { return iaddress(n + 0); }
+#endif // !AARCH64
+
+static inline Address faddress(int n)            { return iaddress(n); }
+static inline Address daddress(int n)            { return laddress(n); }
+static inline Address aaddress(int n)            { return iaddress(n); }
+
+
+void TemplateTable::get_local_base_addr(Register r, Register index) {
+  __ sub(r, Rlocals, AsmOperand(index, lsl, Interpreter::logStackElementSize));
+}
+
+Address TemplateTable::load_iaddress(Register index, Register scratch) {
+#ifdef AARCH64
+  get_local_base_addr(scratch, index);
+  return Address(scratch);
+#else
+  return Address(Rlocals, index, lsl, Interpreter::logStackElementSize, basic_offset, sub_offset);
+#endif // AARCH64
+}
+
+Address TemplateTable::load_aaddress(Register index, Register scratch) {
+  return load_iaddress(index, scratch);
+}
+
+Address TemplateTable::load_faddress(Register index, Register scratch) {
+#ifdef __SOFTFP__
+  return load_iaddress(index, scratch);
+#else
+  get_local_base_addr(scratch, index);
+  return Address(scratch);
+#endif // __SOFTFP__
+}
+
+Address TemplateTable::load_daddress(Register index, Register scratch) {
+  get_local_base_addr(scratch, index);
+  return Address(scratch, Interpreter::local_offset_in_bytes(1));
+}
+
+// At top of Java expression stack which may be different than SP.
+// It isn't for category 1 objects.
+static inline Address at_tos() {
+  return Address(Rstack_top, Interpreter::expr_offset_in_bytes(0));
+}
+
+static inline Address at_tos_p1() {
+  return Address(Rstack_top, Interpreter::expr_offset_in_bytes(1));
+}
+
+static inline Address at_tos_p2() {
+  return Address(Rstack_top, Interpreter::expr_offset_in_bytes(2));
+}
+
+
+// 32-bit ARM:
+// Loads double/long local into R0_tos_lo/R1_tos_hi with two
+// separate ldr instructions (supports nonadjacent values).
+// Used for longs in all modes, and for doubles in SOFTFP mode.
+//
+// AArch64: loads long local into R0_tos.
+//
+void TemplateTable::load_category2_local(Register Rlocal_index, Register tmp) {
+  const Register Rlocal_base = tmp;
+  assert_different_registers(Rlocal_index, tmp);
+
+  get_local_base_addr(Rlocal_base, Rlocal_index);
+#ifdef AARCH64
+  __ ldr(R0_tos, Address(Rlocal_base, Interpreter::local_offset_in_bytes(1)));
+#else
+  __ ldr(R0_tos_lo, Address(Rlocal_base, Interpreter::local_offset_in_bytes(1)));
+  __ ldr(R1_tos_hi, Address(Rlocal_base, Interpreter::local_offset_in_bytes(0)));
+#endif // AARCH64
+}
+
+
+// 32-bit ARM:
+// Stores R0_tos_lo/R1_tos_hi to double/long local with two
+// separate str instructions (supports nonadjacent values).
+// Used for longs in all modes, and for doubles in SOFTFP mode
+//
+// AArch64: stores R0_tos to long local.
+//
+void TemplateTable::store_category2_local(Register Rlocal_index, Register tmp) {
+  const Register Rlocal_base = tmp;
+  assert_different_registers(Rlocal_index, tmp);
+
+  get_local_base_addr(Rlocal_base, Rlocal_index);
+#ifdef AARCH64
+  __ str(R0_tos, Address(Rlocal_base, Interpreter::local_offset_in_bytes(1)));
+#else
+  __ str(R0_tos_lo, Address(Rlocal_base, Interpreter::local_offset_in_bytes(1)));
+  __ str(R1_tos_hi, Address(Rlocal_base, Interpreter::local_offset_in_bytes(0)));
+#endif // AARCH64
+}
+
+// Returns address of Java array element using temp register as address base.
+Address TemplateTable::get_array_elem_addr(BasicType elemType, Register array, Register index, Register temp) {
+  int logElemSize = exact_log2(type2aelembytes(elemType));
+  __ add_ptr_scaled_int32(temp, array, index, logElemSize);
+  return Address(temp, arrayOopDesc::base_offset_in_bytes(elemType));
+}
+
+//----------------------------------------------------------------------------------------------------
+// Condition conversion
+AsmCondition convNegCond(TemplateTable::Condition cc) {
+  switch (cc) {
+    case TemplateTable::equal        : return ne;
+    case TemplateTable::not_equal    : return eq;
+    case TemplateTable::less         : return ge;
+    case TemplateTable::less_equal   : return gt;
+    case TemplateTable::greater      : return le;
+    case TemplateTable::greater_equal: return lt;
+  }
+  ShouldNotReachHere();
+  return nv;
+}
+
+//----------------------------------------------------------------------------------------------------
+// Miscelaneous helper routines
+
+// Store an oop (or NULL) at the address described by obj.
+// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+// Also destroys new_val and obj.base().
+static void do_oop_store(InterpreterMacroAssembler* _masm,
+                         Address obj,
+                         Register new_val,
+                         Register tmp1,
+                         Register tmp2,
+                         Register tmp3,
+                         BarrierSet::Name barrier,
+                         bool precise,
+                         bool is_null) {
+
+  assert_different_registers(obj.base(), new_val, tmp1, tmp2, tmp3, noreg);
+  switch (barrier) {
+#if INCLUDE_ALL_GCS
+    case BarrierSet::G1SATBCTLogging:
+      {
+        // flatten object address if needed
+        assert (obj.mode() == basic_offset, "pre- or post-indexing is not supported here");
+
+        const Register store_addr = obj.base();
+        if (obj.index() != noreg) {
+          assert (obj.disp() == 0, "index or displacement, not both");
+#ifdef AARCH64
+          __ add(store_addr, obj.base(), obj.index(), obj.extend(), obj.shift_imm());
+#else
+          assert(obj.offset_op() == add_offset, "addition is expected");
+          __ add(store_addr, obj.base(), AsmOperand(obj.index(), obj.shift(), obj.shift_imm()));
+#endif // AARCH64
+        } else if (obj.disp() != 0) {
+          __ add(store_addr, obj.base(), obj.disp());
+        }
+
+        __ g1_write_barrier_pre(store_addr, new_val, tmp1, tmp2, tmp3);
+        if (is_null) {
+          __ store_heap_oop_null(new_val, Address(store_addr));
+        } else {
+          // G1 barrier needs uncompressed oop for region cross check.
+          Register val_to_store = new_val;
+          if (UseCompressedOops) {
+            val_to_store = tmp1;
+            __ mov(val_to_store, new_val);
+          }
+          __ store_heap_oop(val_to_store, Address(store_addr)); // blows val_to_store:
+          val_to_store = noreg;
+          __ g1_write_barrier_post(store_addr, new_val, tmp1, tmp2, tmp3);
+        }
+      }
+      break;
+#endif // INCLUDE_ALL_GCS
+    case BarrierSet::CardTableForRS:
+    case BarrierSet::CardTableExtension:
+      {
+        if (is_null) {
+          __ store_heap_oop_null(new_val, obj);
+        } else {
+          assert (!precise || (obj.index() == noreg && obj.disp() == 0),
+                  "store check address should be calculated beforehand");
+
+          __ store_check_part1(tmp1);
+          __ store_heap_oop(new_val, obj); // blows new_val:
+          new_val = noreg;
+          __ store_check_part2(obj.base(), tmp1, tmp2);
+        }
+      }
+      break;
+    case BarrierSet::ModRef:
+      ShouldNotReachHere();
+      break;
+    default:
+      ShouldNotReachHere();
+      break;
+  }
+}
+
+Address TemplateTable::at_bcp(int offset) {
+  assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
+  return Address(Rbcp, offset);
+}
+
+
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR.
+void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
+                                   Register temp_reg, bool load_bc_into_bc_reg/*=true*/,
+                                   int byte_no) {
+  assert_different_registers(bc_reg, temp_reg);
+  if (!RewriteBytecodes)  return;
+  Label L_patch_done;
+
+  switch (bc) {
+  case Bytecodes::_fast_aputfield:
+  case Bytecodes::_fast_bputfield:
+  case Bytecodes::_fast_zputfield:
+  case Bytecodes::_fast_cputfield:
+  case Bytecodes::_fast_dputfield:
+  case Bytecodes::_fast_fputfield:
+  case Bytecodes::_fast_iputfield:
+  case Bytecodes::_fast_lputfield:
+  case Bytecodes::_fast_sputfield:
+    {
+      // We skip bytecode quickening for putfield instructions when
+      // the put_code written to the constant pool cache is zero.
+      // This is required so that every execution of this instruction
+      // calls out to InterpreterRuntime::resolve_get_put to do
+      // additional, required work.
+      assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
+      assert(load_bc_into_bc_reg, "we use bc_reg as temp");
+      __ get_cache_and_index_and_bytecode_at_bcp(bc_reg, temp_reg, temp_reg, byte_no, 1, sizeof(u2));
+      __ mov(bc_reg, bc);
+      __ cbz(temp_reg, L_patch_done);  // test if bytecode is zero
+    }
+    break;
+  default:
+    assert(byte_no == -1, "sanity");
+    // the pair bytecodes have already done the load.
+    if (load_bc_into_bc_reg) {
+      __ mov(bc_reg, bc);
+    }
+  }
+
+  if (__ can_post_breakpoint()) {
+    Label L_fast_patch;
+    // if a breakpoint is present we can't rewrite the stream directly
+    __ ldrb(temp_reg, at_bcp(0));
+    __ cmp(temp_reg, Bytecodes::_breakpoint);
+    __ b(L_fast_patch, ne);
+    if (bc_reg != R3) {
+      __ mov(R3, bc_reg);
+    }
+    __ mov(R1, Rmethod);
+    __ mov(R2, Rbcp);
+    // Let breakpoint table handling rewrite to quicker bytecode
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), R1, R2, R3);
+    __ b(L_patch_done);
+    __ bind(L_fast_patch);
+  }
+
+#ifdef ASSERT
+  Label L_okay;
+  __ ldrb(temp_reg, at_bcp(0));
+  __ cmp(temp_reg, (int)Bytecodes::java_code(bc));
+  __ b(L_okay, eq);
+  __ cmp(temp_reg, bc_reg);
+  __ b(L_okay, eq);
+  __ stop("patching the wrong bytecode");
+  __ bind(L_okay);
+#endif
+
+  // patch bytecode
+  __ strb(bc_reg, at_bcp(0));
+  __ bind(L_patch_done);
+}
+
+//----------------------------------------------------------------------------------------------------
+// Individual instructions
+
+void TemplateTable::nop() {
+  transition(vtos, vtos);
+  // nothing to do
+}
+
+void TemplateTable::shouldnotreachhere() {
+  transition(vtos, vtos);
+  __ stop("shouldnotreachhere bytecode");
+}
+
+
+
+void TemplateTable::aconst_null() {
+  transition(vtos, atos);
+  __ mov(R0_tos, 0);
+}
+
+
+void TemplateTable::iconst(int value) {
+  transition(vtos, itos);
+  __ mov_slow(R0_tos, value);
+}
+
+
+void TemplateTable::lconst(int value) {
+  transition(vtos, ltos);
+  assert((value == 0) || (value == 1), "unexpected long constant");
+  __ mov(R0_tos, value);
+#ifndef AARCH64
+  __ mov(R1_tos_hi, 0);
+#endif // !AARCH64
+}
+
+
+void TemplateTable::fconst(int value) {
+  transition(vtos, ftos);
+#ifdef AARCH64
+  switch(value) {
+  case 0:   __ fmov_sw(S0_tos, ZR);    break;
+  case 1:   __ fmov_s (S0_tos, 0x70);  break;
+  case 2:   __ fmov_s (S0_tos, 0x00);  break;
+  default:  ShouldNotReachHere();      break;
+  }
+#else
+  const int zero = 0;         // 0.0f
+  const int one = 0x3f800000; // 1.0f
+  const int two = 0x40000000; // 2.0f
+
+  switch(value) {
+  case 0:   __ mov(R0_tos, zero);   break;
+  case 1:   __ mov(R0_tos, one);    break;
+  case 2:   __ mov(R0_tos, two);    break;
+  default:  ShouldNotReachHere();   break;
+  }
+
+#ifndef __SOFTFP__
+  __ fmsr(S0_tos, R0_tos);
+#endif // !__SOFTFP__
+#endif // AARCH64
+}
+
+
+void TemplateTable::dconst(int value) {
+  transition(vtos, dtos);
+#ifdef AARCH64
+  switch(value) {
+  case 0:   __ fmov_dx(D0_tos, ZR);    break;
+  case 1:   __ fmov_d (D0_tos, 0x70);  break;
+  default:  ShouldNotReachHere();      break;
+  }
+#else
+  const int one_lo = 0;            // low part of 1.0
+  const int one_hi = 0x3ff00000;   // high part of 1.0
+
+  if (value == 0) {
+#ifdef __SOFTFP__
+    __ mov(R0_tos_lo, 0);
+    __ mov(R1_tos_hi, 0);
+#else
+    __ mov(R0_tmp, 0);
+    __ fmdrr(D0_tos, R0_tmp, R0_tmp);
+#endif // __SOFTFP__
+  } else if (value == 1) {
+    __ mov(R0_tos_lo, one_lo);
+    __ mov_slow(R1_tos_hi, one_hi);
+#ifndef __SOFTFP__
+    __ fmdrr(D0_tos, R0_tos_lo, R1_tos_hi);
+#endif // !__SOFTFP__
+  } else {
+    ShouldNotReachHere();
+  }
+#endif // AARCH64
+}
+
+
+void TemplateTable::bipush() {
+  transition(vtos, itos);
+  __ ldrsb(R0_tos, at_bcp(1));
+}
+
+
+void TemplateTable::sipush() {
+  transition(vtos, itos);
+  __ ldrsb(R0_tmp, at_bcp(1));
+  __ ldrb(R1_tmp, at_bcp(2));
+  __ orr(R0_tos, R1_tmp, AsmOperand(R0_tmp, lsl, BitsPerByte));
+}
+
+
+void TemplateTable::ldc(bool wide) {
+  transition(vtos, vtos);
+  Label fastCase, Done;
+
+  const Register Rindex = R1_tmp;
+  const Register Rcpool = R2_tmp;
+  const Register Rtags  = R3_tmp;
+  const Register RtagType = R3_tmp;
+
+  if (wide) {
+    __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+  } else {
+    __ ldrb(Rindex, at_bcp(1));
+  }
+  __ get_cpool_and_tags(Rcpool, Rtags);
+
+  const int base_offset = ConstantPool::header_size() * wordSize;
+  const int tags_offset = Array<u1>::base_offset_in_bytes();
+
+  // get const type
+  __ add(Rtemp, Rtags, tags_offset);
+#ifdef AARCH64
+  __ add(Rtemp, Rtemp, Rindex);
+  __ ldarb(RtagType, Rtemp);  // TODO-AARCH64 figure out if barrier is needed here, or control dependency is enough
+#else
+  __ ldrb(RtagType, Address(Rtemp, Rindex));
+  volatile_barrier(MacroAssembler::LoadLoad, Rtemp);
+#endif // AARCH64
+
+  // unresolved class - get the resolved class
+  __ cmp(RtagType, JVM_CONSTANT_UnresolvedClass);
+
+  // unresolved class in error (resolution failed) - call into runtime
+  // so that the same error from first resolution attempt is thrown.
+#ifdef AARCH64
+  __ mov(Rtemp, JVM_CONSTANT_UnresolvedClassInError); // this constant does not fit into 5-bit immediate constraint
+  __ cond_cmp(RtagType, Rtemp, ne);
+#else
+  __ cond_cmp(RtagType, JVM_CONSTANT_UnresolvedClassInError, ne);
+#endif // AARCH64
+
+  // resolved class - need to call vm to get java mirror of the class
+  __ cond_cmp(RtagType, JVM_CONSTANT_Class, ne);
+
+  __ b(fastCase, ne);
+
+  // slow case - call runtime
+  __ mov(R1, wide);
+  call_VM(R0_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), R1);
+  __ push(atos);
+  __ b(Done);
+
+  // int, float, String
+  __ bind(fastCase);
+#ifdef ASSERT
+  { Label L;
+    __ cmp(RtagType, JVM_CONSTANT_Integer);
+    __ cond_cmp(RtagType, JVM_CONSTANT_Float, ne);
+    __ b(L, eq);
+    __ stop("unexpected tag type in ldc");
+    __ bind(L);
+  }
+#endif // ASSERT
+  // itos, ftos
+  __ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr_u32(R0_tos, Address(Rtemp, base_offset));
+
+  // floats and ints are placed on stack in the same way, so
+  // we can use push(itos) to transfer float value without VFP
+  __ push(itos);
+  __ bind(Done);
+}
+
+// Fast path for caching oop constants.
+void TemplateTable::fast_aldc(bool wide) {
+  transition(vtos, atos);
+  int index_size = wide ? sizeof(u2) : sizeof(u1);
+  Label resolved;
+
+  // We are resolved if the resolved reference cache entry contains a
+  // non-null object (CallSite, etc.)
+  assert_different_registers(R0_tos, R2_tmp);
+  __ get_index_at_bcp(R2_tmp, 1, R0_tos, index_size);
+  __ load_resolved_reference_at_index(R0_tos, R2_tmp);
+  __ cbnz(R0_tos, resolved);
+
+  address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
+
+  // first time invocation - must resolve first
+  __ mov(R1, (int)bytecode());
+  __ call_VM(R0_tos, entry, R1);
+  __ bind(resolved);
+
+  if (VerifyOops) {
+    __ verify_oop(R0_tos);
+  }
+}
+
+void TemplateTable::ldc2_w() {
+  transition(vtos, vtos);
+  const Register Rtags  = R2_tmp;
+  const Register Rindex = R3_tmp;
+  const Register Rcpool = R4_tmp;
+  const Register Rbase  = R5_tmp;
+
+  __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+
+  __ get_cpool_and_tags(Rcpool, Rtags);
+  const int base_offset = ConstantPool::header_size() * wordSize;
+  const int tags_offset = Array<u1>::base_offset_in_bytes();
+
+  __ add(Rbase, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
+
+#ifdef __ABI_HARD__
+  Label Long, exit;
+  // get type from tags
+  __ add(Rtemp, Rtags, tags_offset);
+  __ ldrb(Rtemp, Address(Rtemp, Rindex));
+  __ cmp(Rtemp, JVM_CONSTANT_Double);
+  __ b(Long, ne);
+  __ ldr_double(D0_tos, Address(Rbase, base_offset));
+
+  __ push(dtos);
+  __ b(exit);
+  __ bind(Long);
+#endif
+
+#ifdef AARCH64
+  __ ldr(R0_tos, Address(Rbase, base_offset));
+#else
+  __ ldr(R0_tos_lo, Address(Rbase, base_offset + 0 * wordSize));
+  __ ldr(R1_tos_hi, Address(Rbase, base_offset + 1 * wordSize));
+#endif // AARCH64
+  __ push(ltos);
+
+#ifdef __ABI_HARD__
+  __ bind(exit);
+#endif
+}
+
+
+void TemplateTable::locals_index(Register reg, int offset) {
+  __ ldrb(reg, at_bcp(offset));
+}
+
+void TemplateTable::iload() {
+  iload_internal();
+}
+
+void TemplateTable::nofast_iload() {
+  iload_internal(may_not_rewrite);
+}
+
+void TemplateTable::iload_internal(RewriteControl rc) {
+  transition(vtos, itos);
+
+  if ((rc == may_rewrite) && __ rewrite_frequent_pairs()) {
+    Label rewrite, done;
+    const Register next_bytecode = R1_tmp;
+    const Register target_bytecode = R2_tmp;
+
+    // get next byte
+    __ ldrb(next_bytecode, at_bcp(Bytecodes::length_for(Bytecodes::_iload)));
+    // if _iload, wait to rewrite to iload2.  We only want to rewrite the
+    // last two iloads in a pair.  Comparing against fast_iload means that
+    // the next bytecode is neither an iload or a caload, and therefore
+    // an iload pair.
+    __ cmp(next_bytecode, Bytecodes::_iload);
+    __ b(done, eq);
+
+    __ cmp(next_bytecode, Bytecodes::_fast_iload);
+    __ mov(target_bytecode, Bytecodes::_fast_iload2);
+    __ b(rewrite, eq);
+
+    // if _caload, rewrite to fast_icaload
+    __ cmp(next_bytecode, Bytecodes::_caload);
+    __ mov(target_bytecode, Bytecodes::_fast_icaload);
+    __ b(rewrite, eq);
+
+    // rewrite so iload doesn't check again.
+    __ mov(target_bytecode, Bytecodes::_fast_iload);
+
+    // rewrite
+    // R2: fast bytecode
+    __ bind(rewrite);
+    patch_bytecode(Bytecodes::_iload, target_bytecode, Rtemp, false);
+    __ bind(done);
+  }
+
+  // Get the local value into tos
+  const Register Rlocal_index = R1_tmp;
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(R0_tos, local);
+}
+
+
+void TemplateTable::fast_iload2() {
+  transition(vtos, itos);
+  const Register Rlocal_index = R1_tmp;
+
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(R0_tos, local);
+  __ push(itos);
+
+  locals_index(Rlocal_index, 3);
+  local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(R0_tos, local);
+}
+
+void TemplateTable::fast_iload() {
+  transition(vtos, itos);
+  const Register Rlocal_index = R1_tmp;
+
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(R0_tos, local);
+}
+
+
+void TemplateTable::lload() {
+  transition(vtos, ltos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+  load_category2_local(Rlocal_index, R3_tmp);
+}
+
+
+void TemplateTable::fload() {
+  transition(vtos, ftos);
+  const Register Rlocal_index = R2_tmp;
+
+  // Get the local value into tos
+  locals_index(Rlocal_index);
+  Address local = load_faddress(Rlocal_index, Rtemp);
+#ifdef __SOFTFP__
+  __ ldr(R0_tos, local);
+#else
+  __ ldr_float(S0_tos, local);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dload() {
+  transition(vtos, dtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+
+#ifdef __SOFTFP__
+  load_category2_local(Rlocal_index, R3_tmp);
+#else
+  __ ldr_double(D0_tos, load_daddress(Rlocal_index, Rtemp));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::aload() {
+  transition(vtos, atos);
+  const Register Rlocal_index = R1_tmp;
+
+  locals_index(Rlocal_index);
+  Address local = load_aaddress(Rlocal_index, Rtemp);
+  __ ldr(R0_tos, local);
+}
+
+
+void TemplateTable::locals_index_wide(Register reg) {
+  assert_different_registers(reg, Rtemp);
+  __ ldrb(Rtemp, at_bcp(2));
+  __ ldrb(reg, at_bcp(3));
+  __ orr(reg, reg, AsmOperand(Rtemp, lsl, 8));
+}
+
+
+void TemplateTable::wide_iload() {
+  transition(vtos, itos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index_wide(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(R0_tos, local);
+}
+
+
+void TemplateTable::wide_lload() {
+  transition(vtos, ltos);
+  const Register Rlocal_index = R2_tmp;
+  const Register Rlocal_base = R3_tmp;
+
+  locals_index_wide(Rlocal_index);
+  load_category2_local(Rlocal_index, R3_tmp);
+}
+
+
+void TemplateTable::wide_fload() {
+  transition(vtos, ftos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index_wide(Rlocal_index);
+  Address local = load_faddress(Rlocal_index, Rtemp);
+#ifdef __SOFTFP__
+  __ ldr(R0_tos, local);
+#else
+  __ ldr_float(S0_tos, local);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::wide_dload() {
+  transition(vtos, dtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index_wide(Rlocal_index);
+#ifdef __SOFTFP__
+  load_category2_local(Rlocal_index, R3_tmp);
+#else
+  __ ldr_double(D0_tos, load_daddress(Rlocal_index, Rtemp));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::wide_aload() {
+  transition(vtos, atos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index_wide(Rlocal_index);
+  Address local = load_aaddress(Rlocal_index, Rtemp);
+  __ ldr(R0_tos, local);
+}
+
+void TemplateTable::index_check(Register array, Register index) {
+  // Pop ptr into array
+  __ pop_ptr(array);
+  index_check_without_pop(array, index);
+}
+
+void TemplateTable::index_check_without_pop(Register array, Register index) {
+  assert_different_registers(array, index, Rtemp);
+  // check array
+  __ null_check(array, Rtemp, arrayOopDesc::length_offset_in_bytes());
+  // check index
+  __ ldr_s32(Rtemp, Address(array, arrayOopDesc::length_offset_in_bytes()));
+  __ cmp_32(index, Rtemp);
+  if (index != R4_ArrayIndexOutOfBounds_index) {
+    // convention with generate_ArrayIndexOutOfBounds_handler()
+    __ mov(R4_ArrayIndexOutOfBounds_index, index, hs);
+  }
+  __ b(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, hs);
+}
+
+
+void TemplateTable::iaload() {
+  transition(itos, itos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+  __ ldr_s32(R0_tos, get_array_elem_addr(T_INT, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::laload() {
+  transition(itos, ltos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+
+#ifdef AARCH64
+  __ ldr(R0_tos, get_array_elem_addr(T_LONG, Rarray, Rindex, Rtemp));
+#else
+  __ add(Rtemp, Rarray, AsmOperand(Rindex, lsl, LogBytesPerLong));
+  __ add(Rtemp, Rtemp, arrayOopDesc::base_offset_in_bytes(T_LONG));
+  __ ldmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+}
+
+
+void TemplateTable::faload() {
+  transition(itos, ftos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+
+  Address addr = get_array_elem_addr(T_FLOAT, Rarray, Rindex, Rtemp);
+#ifdef __SOFTFP__
+  __ ldr(R0_tos, addr);
+#else
+  __ ldr_float(S0_tos, addr);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::daload() {
+  transition(itos, dtos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+
+#ifdef __SOFTFP__
+  __ add(Rtemp, Rarray, AsmOperand(Rindex, lsl, LogBytesPerLong));
+  __ add(Rtemp, Rtemp, arrayOopDesc::base_offset_in_bytes(T_DOUBLE));
+  __ ldmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#else
+  __ ldr_double(D0_tos, get_array_elem_addr(T_DOUBLE, Rarray, Rindex, Rtemp));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::aaload() {
+  transition(itos, atos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+  __ load_heap_oop(R0_tos, get_array_elem_addr(T_OBJECT, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::baload() {
+  transition(itos, itos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+  __ ldrsb(R0_tos, get_array_elem_addr(T_BYTE, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::caload() {
+  transition(itos, itos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+  __ ldrh(R0_tos, get_array_elem_addr(T_CHAR, Rarray, Rindex, Rtemp));
+}
+
+
+// iload followed by caload frequent pair
+void TemplateTable::fast_icaload() {
+  transition(vtos, itos);
+  const Register Rlocal_index = R1_tmp;
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R4_tmp; // index_check prefers index on R4
+  assert_different_registers(Rlocal_index, Rindex);
+  assert_different_registers(Rarray, Rindex);
+
+  // load index out of locals
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(Rindex, local);
+
+  // get array element
+  index_check(Rarray, Rindex);
+  __ ldrh(R0_tos, get_array_elem_addr(T_CHAR, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::saload() {
+  transition(itos, itos);
+  const Register Rarray = R1_tmp;
+  const Register Rindex = R0_tos;
+
+  index_check(Rarray, Rindex);
+  __ ldrsh(R0_tos, get_array_elem_addr(T_SHORT, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::iload(int n) {
+  transition(vtos, itos);
+  __ ldr_s32(R0_tos, iaddress(n));
+}
+
+
+void TemplateTable::lload(int n) {
+  transition(vtos, ltos);
+#ifdef AARCH64
+  __ ldr(R0_tos, laddress(n));
+#else
+  __ ldr(R0_tos_lo, laddress(n));
+  __ ldr(R1_tos_hi, haddress(n));
+#endif // AARCH64
+}
+
+
+void TemplateTable::fload(int n) {
+  transition(vtos, ftos);
+#ifdef __SOFTFP__
+  __ ldr(R0_tos, faddress(n));
+#else
+  __ ldr_float(S0_tos, faddress(n));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dload(int n) {
+  transition(vtos, dtos);
+#ifdef __SOFTFP__
+  __ ldr(R0_tos_lo, laddress(n));
+  __ ldr(R1_tos_hi, haddress(n));
+#else
+  __ ldr_double(D0_tos, daddress(n));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::aload(int n) {
+  transition(vtos, atos);
+  __ ldr(R0_tos, aaddress(n));
+}
+
+void TemplateTable::aload_0() {
+  aload_0_internal();
+}
+
+void TemplateTable::nofast_aload_0() {
+  aload_0_internal(may_not_rewrite);
+}
+
+void TemplateTable::aload_0_internal(RewriteControl rc) {
+  transition(vtos, atos);
+  // According to bytecode histograms, the pairs:
+  //
+  // _aload_0, _fast_igetfield
+  // _aload_0, _fast_agetfield
+  // _aload_0, _fast_fgetfield
+  //
+  // occur frequently. If RewriteFrequentPairs is set, the (slow) _aload_0
+  // bytecode checks if the next bytecode is either _fast_igetfield,
+  // _fast_agetfield or _fast_fgetfield and then rewrites the
+  // current bytecode into a pair bytecode; otherwise it rewrites the current
+  // bytecode into _fast_aload_0 that doesn't do the pair check anymore.
+  //
+  // Note: If the next bytecode is _getfield, the rewrite must be delayed,
+  //       otherwise we may miss an opportunity for a pair.
+  //
+  // Also rewrite frequent pairs
+  //   aload_0, aload_1
+  //   aload_0, iload_1
+  // These bytecodes with a small amount of code are most profitable to rewrite
+  if ((rc == may_rewrite) && __ rewrite_frequent_pairs()) {
+    Label rewrite, done;
+    const Register next_bytecode = R1_tmp;
+    const Register target_bytecode = R2_tmp;
+
+    // get next byte
+    __ ldrb(next_bytecode, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)));
+
+    // if _getfield then wait with rewrite
+    __ cmp(next_bytecode, Bytecodes::_getfield);
+    __ b(done, eq);
+
+    // if _igetfield then rewrite to _fast_iaccess_0
+    assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ cmp(next_bytecode, Bytecodes::_fast_igetfield);
+    __ mov(target_bytecode, Bytecodes::_fast_iaccess_0);
+    __ b(rewrite, eq);
+
+    // if _agetfield then rewrite to _fast_aaccess_0
+    assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ cmp(next_bytecode, Bytecodes::_fast_agetfield);
+    __ mov(target_bytecode, Bytecodes::_fast_aaccess_0);
+    __ b(rewrite, eq);
+
+    // if _fgetfield then rewrite to _fast_faccess_0, else rewrite to _fast_aload0
+    assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition");
+
+    __ cmp(next_bytecode, Bytecodes::_fast_fgetfield);
+#ifdef AARCH64
+    __ mov(Rtemp, Bytecodes::_fast_faccess_0);
+    __ mov(target_bytecode, Bytecodes::_fast_aload_0);
+    __ mov(target_bytecode, Rtemp, eq);
+#else
+    __ mov(target_bytecode, Bytecodes::_fast_faccess_0, eq);
+    __ mov(target_bytecode, Bytecodes::_fast_aload_0, ne);
+#endif // AARCH64
+
+    // rewrite
+    __ bind(rewrite);
+    patch_bytecode(Bytecodes::_aload_0, target_bytecode, Rtemp, false);
+
+    __ bind(done);
+  }
+
+  aload(0);
+}
+
+void TemplateTable::istore() {
+  transition(itos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ str_32(R0_tos, local);
+}
+
+
+void TemplateTable::lstore() {
+  transition(ltos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+  store_category2_local(Rlocal_index, R3_tmp);
+}
+
+
+void TemplateTable::fstore() {
+  transition(ftos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+  Address local = load_faddress(Rlocal_index, Rtemp);
+#ifdef __SOFTFP__
+  __ str(R0_tos, local);
+#else
+  __ str_float(S0_tos, local);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dstore() {
+  transition(dtos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  locals_index(Rlocal_index);
+
+#ifdef __SOFTFP__
+  store_category2_local(Rlocal_index, R3_tmp);
+#else
+  __ str_double(D0_tos, load_daddress(Rlocal_index, Rtemp));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::astore() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R1_tmp;
+
+  __ pop_ptr(R0_tos);
+  locals_index(Rlocal_index);
+  Address local = load_aaddress(Rlocal_index, Rtemp);
+  __ str(R0_tos, local);
+}
+
+
+void TemplateTable::wide_istore() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  __ pop_i(R0_tos);
+  locals_index_wide(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ str_32(R0_tos, local);
+}
+
+
+void TemplateTable::wide_lstore() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R2_tmp;
+  const Register Rlocal_base = R3_tmp;
+
+#ifdef AARCH64
+  __ pop_l(R0_tos);
+#else
+  __ pop_l(R0_tos_lo, R1_tos_hi);
+#endif // AARCH64
+
+  locals_index_wide(Rlocal_index);
+  store_category2_local(Rlocal_index, R3_tmp);
+}
+
+
+void TemplateTable::wide_fstore() {
+  wide_istore();
+}
+
+
+void TemplateTable::wide_dstore() {
+  wide_lstore();
+}
+
+
+void TemplateTable::wide_astore() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R2_tmp;
+
+  __ pop_ptr(R0_tos);
+  locals_index_wide(Rlocal_index);
+  Address local = load_aaddress(Rlocal_index, Rtemp);
+  __ str(R0_tos, local);
+}
+
+
+void TemplateTable::iastore() {
+  transition(itos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // R0_tos: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+  __ str_32(R0_tos, get_array_elem_addr(T_INT, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::lastore() {
+  transition(ltos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // R0_tos_lo:R1_tos_hi: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+
+#ifdef AARCH64
+  __ str(R0_tos, get_array_elem_addr(T_LONG, Rarray, Rindex, Rtemp));
+#else
+  __ add(Rtemp, Rarray, AsmOperand(Rindex, lsl, LogBytesPerLong));
+  __ add(Rtemp, Rtemp, arrayOopDesc::base_offset_in_bytes(T_LONG));
+  __ stmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+}
+
+
+void TemplateTable::fastore() {
+  transition(ftos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // S0_tos/R0_tos: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+  Address addr = get_array_elem_addr(T_FLOAT, Rarray, Rindex, Rtemp);
+
+#ifdef __SOFTFP__
+  __ str(R0_tos, addr);
+#else
+  __ str_float(S0_tos, addr);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dastore() {
+  transition(dtos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // D0_tos / R0_tos_lo:R1_to_hi: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+
+#ifdef __SOFTFP__
+  __ add(Rtemp, Rarray, AsmOperand(Rindex, lsl, LogBytesPerLong));
+  __ add(Rtemp, Rtemp, arrayOopDesc::base_offset_in_bytes(T_DOUBLE));
+  __ stmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#else
+  __ str_double(D0_tos, get_array_elem_addr(T_DOUBLE, Rarray, Rindex, Rtemp));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::aastore() {
+  transition(vtos, vtos);
+  Label is_null, throw_array_store, done;
+
+  const Register Raddr_1   = R1_tmp;
+  const Register Rvalue_2  = R2_tmp;
+  const Register Rarray_3  = R3_tmp;
+  const Register Rindex_4  = R4_tmp;   // preferred by index_check_without_pop()
+  const Register Rsub_5    = R5_tmp;
+  const Register Rsuper_LR = LR_tmp;
+
+  // stack: ..., array, index, value
+  __ ldr(Rvalue_2, at_tos());     // Value
+  __ ldr_s32(Rindex_4, at_tos_p1());  // Index
+  __ ldr(Rarray_3, at_tos_p2());  // Array
+
+  index_check_without_pop(Rarray_3, Rindex_4);
+
+  // Compute the array base
+  __ add(Raddr_1, Rarray_3, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
+
+  // do array store check - check for NULL value first
+  __ cbz(Rvalue_2, is_null);
+
+  // Load subklass
+  __ load_klass(Rsub_5, Rvalue_2);
+  // Load superklass
+  __ load_klass(Rtemp, Rarray_3);
+  __ ldr(Rsuper_LR, Address(Rtemp, ObjArrayKlass::element_klass_offset()));
+
+  __ gen_subtype_check(Rsub_5, Rsuper_LR, throw_array_store, R0_tmp, R3_tmp);
+  // Come here on success
+
+  // Store value
+  __ add(Raddr_1, Raddr_1, AsmOperand(Rindex_4, lsl, LogBytesPerHeapOop));
+
+  // Now store using the appropriate barrier
+  do_oop_store(_masm, Raddr_1, Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, false);
+  __ b(done);
+
+  __ bind(throw_array_store);
+
+  // Come here on failure of subtype check
+  __ profile_typecheck_failed(R0_tmp);
+
+  // object is at TOS
+  __ b(Interpreter::_throw_ArrayStoreException_entry);
+
+  // Have a NULL in Rvalue_2, store NULL at array[index].
+  __ bind(is_null);
+  __ profile_null_seen(R0_tmp);
+
+  // Store a NULL
+  do_oop_store(_masm, Address::indexed_oop(Raddr_1, Rindex_4), Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, true);
+
+  // Pop stack arguments
+  __ bind(done);
+  __ add(Rstack_top, Rstack_top, 3 * Interpreter::stackElementSize);
+}
+
+
+void TemplateTable::bastore() {
+  transition(itos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // R0_tos: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+
+  // Need to check whether array is boolean or byte
+  // since both types share the bastore bytecode.
+  __ load_klass(Rtemp, Rarray);
+  __ ldr_u32(Rtemp, Address(Rtemp, Klass::layout_helper_offset()));
+  Label L_skip;
+  __ tst(Rtemp, Klass::layout_helper_boolean_diffbit());
+  __ b(L_skip, eq);
+  __ and_32(R0_tos, R0_tos, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1
+  __ bind(L_skip);
+  __ strb(R0_tos, get_array_elem_addr(T_BYTE, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::castore() {
+  transition(itos, vtos);
+  const Register Rindex = R4_tmp; // index_check prefers index in R4
+  const Register Rarray = R3_tmp;
+  // R0_tos: value
+
+  __ pop_i(Rindex);
+  index_check(Rarray, Rindex);
+
+  __ strh(R0_tos, get_array_elem_addr(T_CHAR, Rarray, Rindex, Rtemp));
+}
+
+
+void TemplateTable::sastore() {
+  assert(arrayOopDesc::base_offset_in_bytes(T_CHAR) ==
+           arrayOopDesc::base_offset_in_bytes(T_SHORT),
+         "base offsets for char and short should be equal");
+  castore();
+}
+
+
+void TemplateTable::istore(int n) {
+  transition(itos, vtos);
+  __ str_32(R0_tos, iaddress(n));
+}
+
+
+void TemplateTable::lstore(int n) {
+  transition(ltos, vtos);
+#ifdef AARCH64
+  __ str(R0_tos, laddress(n));
+#else
+  __ str(R0_tos_lo, laddress(n));
+  __ str(R1_tos_hi, haddress(n));
+#endif // AARCH64
+}
+
+
+void TemplateTable::fstore(int n) {
+  transition(ftos, vtos);
+#ifdef __SOFTFP__
+  __ str(R0_tos, faddress(n));
+#else
+  __ str_float(S0_tos, faddress(n));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dstore(int n) {
+  transition(dtos, vtos);
+#ifdef __SOFTFP__
+  __ str(R0_tos_lo, laddress(n));
+  __ str(R1_tos_hi, haddress(n));
+#else
+  __ str_double(D0_tos, daddress(n));
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::astore(int n) {
+  transition(vtos, vtos);
+  __ pop_ptr(R0_tos);
+  __ str(R0_tos, aaddress(n));
+}
+
+
+void TemplateTable::pop() {
+  transition(vtos, vtos);
+  __ add(Rstack_top, Rstack_top, Interpreter::stackElementSize);
+}
+
+
+void TemplateTable::pop2() {
+  transition(vtos, vtos);
+  __ add(Rstack_top, Rstack_top, 2*Interpreter::stackElementSize);
+}
+
+
+void TemplateTable::dup() {
+  transition(vtos, vtos);
+  // stack: ..., a
+  __ load_ptr(0, R0_tmp);
+  __ push_ptr(R0_tmp);
+  // stack: ..., a, a
+}
+
+
+void TemplateTable::dup_x1() {
+  transition(vtos, vtos);
+  // stack: ..., a, b
+  __ load_ptr(0, R0_tmp);  // load b
+  __ load_ptr(1, R2_tmp);  // load a
+  __ store_ptr(1, R0_tmp); // store b
+  __ store_ptr(0, R2_tmp); // store a
+  __ push_ptr(R0_tmp);     // push b
+  // stack: ..., b, a, b
+}
+
+
+void TemplateTable::dup_x2() {
+  transition(vtos, vtos);
+  // stack: ..., a, b, c
+  __ load_ptr(0, R0_tmp);   // load c
+  __ load_ptr(1, R2_tmp);   // load b
+  __ load_ptr(2, R4_tmp);   // load a
+
+  __ push_ptr(R0_tmp);      // push c
+
+  // stack: ..., a, b, c, c
+  __ store_ptr(1, R2_tmp);  // store b
+  __ store_ptr(2, R4_tmp);  // store a
+  __ store_ptr(3, R0_tmp);  // store c
+  // stack: ..., c, a, b, c
+}
+
+
+void TemplateTable::dup2() {
+  transition(vtos, vtos);
+  // stack: ..., a, b
+  __ load_ptr(1, R0_tmp);  // load a
+  __ push_ptr(R0_tmp);     // push a
+  __ load_ptr(1, R0_tmp);  // load b
+  __ push_ptr(R0_tmp);     // push b
+  // stack: ..., a, b, a, b
+}
+
+
+void TemplateTable::dup2_x1() {
+  transition(vtos, vtos);
+
+  // stack: ..., a, b, c
+  __ load_ptr(0, R4_tmp);  // load c
+  __ load_ptr(1, R2_tmp);  // load b
+  __ load_ptr(2, R0_tmp);  // load a
+
+  __ push_ptr(R2_tmp);     // push b
+  __ push_ptr(R4_tmp);     // push c
+
+  // stack: ..., a, b, c, b, c
+
+  __ store_ptr(2, R0_tmp);  // store a
+  __ store_ptr(3, R4_tmp);  // store c
+  __ store_ptr(4, R2_tmp);  // store b
+
+  // stack: ..., b, c, a, b, c
+}
+
+
+void TemplateTable::dup2_x2() {
+  transition(vtos, vtos);
+  // stack: ..., a, b, c, d
+  __ load_ptr(0, R0_tmp);  // load d
+  __ load_ptr(1, R2_tmp);  // load c
+  __ push_ptr(R2_tmp);     // push c
+  __ push_ptr(R0_tmp);     // push d
+  // stack: ..., a, b, c, d, c, d
+  __ load_ptr(4, R4_tmp);  // load b
+  __ store_ptr(4, R0_tmp); // store d in b
+  __ store_ptr(2, R4_tmp); // store b in d
+  // stack: ..., a, d, c, b, c, d
+  __ load_ptr(5, R4_tmp);  // load a
+  __ store_ptr(5, R2_tmp); // store c in a
+  __ store_ptr(3, R4_tmp); // store a in c
+  // stack: ..., c, d, a, b, c, d
+}
+
+
+void TemplateTable::swap() {
+  transition(vtos, vtos);
+  // stack: ..., a, b
+  __ load_ptr(1, R0_tmp);  // load a
+  __ load_ptr(0, R2_tmp);  // load b
+  __ store_ptr(0, R0_tmp); // store a in b
+  __ store_ptr(1, R2_tmp); // store b in a
+  // stack: ..., b, a
+}
+
+
+void TemplateTable::iop2(Operation op) {
+  transition(itos, itos);
+  const Register arg1 = R1_tmp;
+  const Register arg2 = R0_tos;
+
+  __ pop_i(arg1);
+  switch (op) {
+    case add  : __ add_32 (R0_tos, arg1, arg2); break;
+    case sub  : __ sub_32 (R0_tos, arg1, arg2); break;
+    case mul  : __ mul_32 (R0_tos, arg1, arg2); break;
+    case _and : __ and_32 (R0_tos, arg1, arg2); break;
+    case _or  : __ orr_32 (R0_tos, arg1, arg2); break;
+    case _xor : __ eor_32 (R0_tos, arg1, arg2); break;
+#ifdef AARCH64
+    case shl  : __ lslv_w (R0_tos, arg1, arg2); break;
+    case shr  : __ asrv_w (R0_tos, arg1, arg2); break;
+    case ushr : __ lsrv_w (R0_tos, arg1, arg2); break;
+#else
+    case shl  : __ andr(arg2, arg2, 0x1f); __ mov (R0_tos, AsmOperand(arg1, lsl, arg2)); break;
+    case shr  : __ andr(arg2, arg2, 0x1f); __ mov (R0_tos, AsmOperand(arg1, asr, arg2)); break;
+    case ushr : __ andr(arg2, arg2, 0x1f); __ mov (R0_tos, AsmOperand(arg1, lsr, arg2)); break;
+#endif // AARCH64
+    default   : ShouldNotReachHere();
+  }
+}
+
+
+void TemplateTable::lop2(Operation op) {
+  transition(ltos, ltos);
+#ifdef AARCH64
+  const Register arg1 = R1_tmp;
+  const Register arg2 = R0_tos;
+
+  __ pop_l(arg1);
+  switch (op) {
+    case add  : __ add (R0_tos, arg1, arg2); break;
+    case sub  : __ sub (R0_tos, arg1, arg2); break;
+    case _and : __ andr(R0_tos, arg1, arg2); break;
+    case _or  : __ orr (R0_tos, arg1, arg2); break;
+    case _xor : __ eor (R0_tos, arg1, arg2); break;
+    default   : ShouldNotReachHere();
+  }
+#else
+  const Register arg1_lo = R2_tmp;
+  const Register arg1_hi = R3_tmp;
+  const Register arg2_lo = R0_tos_lo;
+  const Register arg2_hi = R1_tos_hi;
+
+  __ pop_l(arg1_lo, arg1_hi);
+  switch (op) {
+    case add : __ adds(R0_tos_lo, arg1_lo, arg2_lo); __ adc (R1_tos_hi, arg1_hi, arg2_hi); break;
+    case sub : __ subs(R0_tos_lo, arg1_lo, arg2_lo); __ sbc (R1_tos_hi, arg1_hi, arg2_hi); break;
+    case _and: __ andr(R0_tos_lo, arg1_lo, arg2_lo); __ andr(R1_tos_hi, arg1_hi, arg2_hi); break;
+    case _or : __ orr (R0_tos_lo, arg1_lo, arg2_lo); __ orr (R1_tos_hi, arg1_hi, arg2_hi); break;
+    case _xor: __ eor (R0_tos_lo, arg1_lo, arg2_lo); __ eor (R1_tos_hi, arg1_hi, arg2_hi); break;
+    default : ShouldNotReachHere();
+  }
+#endif // AARCH64
+}
+
+
+void TemplateTable::idiv() {
+  transition(itos, itos);
+#ifdef AARCH64
+  const Register divisor = R0_tos;
+  const Register dividend = R1_tmp;
+
+  __ cbz_w(divisor, Interpreter::_throw_ArithmeticException_entry);
+  __ pop_i(dividend);
+  __ sdiv_w(R0_tos, dividend, divisor);
+#else
+  __ mov(R2, R0_tos);
+  __ pop_i(R0);
+  // R0 - dividend
+  // R2 - divisor
+  __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::none);
+  // R1 - result
+  __ mov(R0_tos, R1);
+#endif // AARCH64
+}
+
+
+void TemplateTable::irem() {
+  transition(itos, itos);
+#ifdef AARCH64
+  const Register divisor = R0_tos;
+  const Register dividend = R1_tmp;
+  const Register quotient = R2_tmp;
+
+  __ cbz_w(divisor, Interpreter::_throw_ArithmeticException_entry);
+  __ pop_i(dividend);
+  __ sdiv_w(quotient, dividend, divisor);
+  __ msub_w(R0_tos, divisor, quotient, dividend);
+#else
+  __ mov(R2, R0_tos);
+  __ pop_i(R0);
+  // R0 - dividend
+  // R2 - divisor
+  __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::none);
+  // R0 - remainder
+#endif // AARCH64
+}
+
+
+void TemplateTable::lmul() {
+  transition(ltos, ltos);
+#ifdef AARCH64
+  const Register arg1 = R0_tos;
+  const Register arg2 = R1_tmp;
+
+  __ pop_l(arg2);
+  __ mul(R0_tos, arg1, arg2);
+#else
+  const Register arg1_lo = R0_tos_lo;
+  const Register arg1_hi = R1_tos_hi;
+  const Register arg2_lo = R2_tmp;
+  const Register arg2_hi = R3_tmp;
+
+  __ pop_l(arg2_lo, arg2_hi);
+
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lmul), arg1_lo, arg1_hi, arg2_lo, arg2_hi);
+#endif // AARCH64
+}
+
+
+void TemplateTable::ldiv() {
+  transition(ltos, ltos);
+#ifdef AARCH64
+  const Register divisor = R0_tos;
+  const Register dividend = R1_tmp;
+
+  __ cbz(divisor, Interpreter::_throw_ArithmeticException_entry);
+  __ pop_l(dividend);
+  __ sdiv(R0_tos, dividend, divisor);
+#else
+  const Register x_lo = R2_tmp;
+  const Register x_hi = R3_tmp;
+  const Register y_lo = R0_tos_lo;
+  const Register y_hi = R1_tos_hi;
+
+  __ pop_l(x_lo, x_hi);
+
+  // check if y = 0
+  __ orrs(Rtemp, y_lo, y_hi);
+  __ call(Interpreter::_throw_ArithmeticException_entry, relocInfo::none, eq);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv), y_lo, y_hi, x_lo, x_hi);
+#endif // AARCH64
+}
+
+
+void TemplateTable::lrem() {
+  transition(ltos, ltos);
+#ifdef AARCH64
+  const Register divisor = R0_tos;
+  const Register dividend = R1_tmp;
+  const Register quotient = R2_tmp;
+
+  __ cbz(divisor, Interpreter::_throw_ArithmeticException_entry);
+  __ pop_l(dividend);
+  __ sdiv(quotient, dividend, divisor);
+  __ msub(R0_tos, divisor, quotient, dividend);
+#else
+  const Register x_lo = R2_tmp;
+  const Register x_hi = R3_tmp;
+  const Register y_lo = R0_tos_lo;
+  const Register y_hi = R1_tos_hi;
+
+  __ pop_l(x_lo, x_hi);
+
+  // check if y = 0
+  __ orrs(Rtemp, y_lo, y_hi);
+  __ call(Interpreter::_throw_ArithmeticException_entry, relocInfo::none, eq);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem), y_lo, y_hi, x_lo, x_hi);
+#endif // AARCH64
+}
+
+
+void TemplateTable::lshl() {
+  transition(itos, ltos);
+#ifdef AARCH64
+  const Register val = R1_tmp;
+  const Register shift_cnt = R0_tos;
+  __ pop_l(val);
+  __ lslv(R0_tos, val, shift_cnt);
+#else
+  const Register shift_cnt = R4_tmp;
+  const Register val_lo = R2_tmp;
+  const Register val_hi = R3_tmp;
+
+  __ pop_l(val_lo, val_hi);
+  __ andr(shift_cnt, R0_tos, 63);
+  __ long_shift(R0_tos_lo, R1_tos_hi, val_lo, val_hi, lsl, shift_cnt);
+#endif // AARCH64
+}
+
+
+void TemplateTable::lshr() {
+  transition(itos, ltos);
+#ifdef AARCH64
+  const Register val = R1_tmp;
+  const Register shift_cnt = R0_tos;
+  __ pop_l(val);
+  __ asrv(R0_tos, val, shift_cnt);
+#else
+  const Register shift_cnt = R4_tmp;
+  const Register val_lo = R2_tmp;
+  const Register val_hi = R3_tmp;
+
+  __ pop_l(val_lo, val_hi);
+  __ andr(shift_cnt, R0_tos, 63);
+  __ long_shift(R0_tos_lo, R1_tos_hi, val_lo, val_hi, asr, shift_cnt);
+#endif // AARCH64
+}
+
+
+void TemplateTable::lushr() {
+  transition(itos, ltos);
+#ifdef AARCH64
+  const Register val = R1_tmp;
+  const Register shift_cnt = R0_tos;
+  __ pop_l(val);
+  __ lsrv(R0_tos, val, shift_cnt);
+#else
+  const Register shift_cnt = R4_tmp;
+  const Register val_lo = R2_tmp;
+  const Register val_hi = R3_tmp;
+
+  __ pop_l(val_lo, val_hi);
+  __ andr(shift_cnt, R0_tos, 63);
+  __ long_shift(R0_tos_lo, R1_tos_hi, val_lo, val_hi, lsr, shift_cnt);
+#endif // AARCH64
+}
+
+
+void TemplateTable::fop2(Operation op) {
+  transition(ftos, ftos);
+#ifdef __SOFTFP__
+  __ mov(R1, R0_tos);
+  __ pop_i(R0);
+  switch (op) {
+    case add: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_fadd_glibc), R0, R1); break;
+    case sub: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_fsub_glibc), R0, R1); break;
+    case mul: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_fmul), R0, R1); break;
+    case div: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_fdiv), R0, R1); break;
+    case rem: __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), R0, R1); break;
+    default : ShouldNotReachHere();
+  }
+#else
+  const FloatRegister arg1 = S1_tmp;
+  const FloatRegister arg2 = S0_tos;
+
+  switch (op) {
+    case add: __ pop_f(arg1); __ add_float(S0_tos, arg1, arg2); break;
+    case sub: __ pop_f(arg1); __ sub_float(S0_tos, arg1, arg2); break;
+    case mul: __ pop_f(arg1); __ mul_float(S0_tos, arg1, arg2); break;
+    case div: __ pop_f(arg1); __ div_float(S0_tos, arg1, arg2); break;
+    case rem:
+#ifndef __ABI_HARD__
+      __ pop_f(arg1);
+      __ fmrs(R0, arg1);
+      __ fmrs(R1, arg2);
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), R0, R1);
+      __ fmsr(S0_tos, R0);
+#else
+      __ mov_float(S1_reg, arg2);
+      __ pop_f(S0);
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem));
+#endif // !__ABI_HARD__
+      break;
+    default : ShouldNotReachHere();
+  }
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dop2(Operation op) {
+  transition(dtos, dtos);
+#ifdef __SOFTFP__
+  __ mov(R2, R0_tos_lo);
+  __ mov(R3, R1_tos_hi);
+  __ pop_l(R0, R1);
+  switch (op) {
+    // __aeabi_XXXX_glibc: Imported code from glibc soft-fp bundle for calculation accuracy improvement. See CR 6757269.
+    case add: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_dadd_glibc), R0, R1, R2, R3); break;
+    case sub: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_dsub_glibc), R0, R1, R2, R3); break;
+    case mul: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_dmul), R0, R1, R2, R3); break;
+    case div: __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_ddiv), R0, R1, R2, R3); break;
+    case rem: __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), R0, R1, R2, R3); break;
+    default : ShouldNotReachHere();
+  }
+#else
+  const FloatRegister arg1 = D1_tmp;
+  const FloatRegister arg2 = D0_tos;
+
+  switch (op) {
+    case add: __ pop_d(arg1); __ add_double(D0_tos, arg1, arg2); break;
+    case sub: __ pop_d(arg1); __ sub_double(D0_tos, arg1, arg2); break;
+    case mul: __ pop_d(arg1); __ mul_double(D0_tos, arg1, arg2); break;
+    case div: __ pop_d(arg1); __ div_double(D0_tos, arg1, arg2); break;
+    case rem:
+#ifndef __ABI_HARD__
+      __ pop_d(arg1);
+      __ fmrrd(R0, R1, arg1);
+      __ fmrrd(R2, R3, arg2);
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), R0, R1, R2, R3);
+      __ fmdrr(D0_tos, R0, R1);
+#else
+      __ mov_double(D1, arg2);
+      __ pop_d(D0);
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem));
+#endif // !__ABI_HARD__
+      break;
+    default : ShouldNotReachHere();
+  }
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::ineg() {
+  transition(itos, itos);
+  __ neg_32(R0_tos, R0_tos);
+}
+
+
+void TemplateTable::lneg() {
+  transition(ltos, ltos);
+#ifdef AARCH64
+  __ neg(R0_tos, R0_tos);
+#else
+  __ rsbs(R0_tos_lo, R0_tos_lo, 0);
+  __ rsc (R1_tos_hi, R1_tos_hi, 0);
+#endif // AARCH64
+}
+
+
+void TemplateTable::fneg() {
+  transition(ftos, ftos);
+#ifdef __SOFTFP__
+  // Invert sign bit
+  const int sign_mask = 0x80000000;
+  __ eor(R0_tos, R0_tos, sign_mask);
+#else
+  __ neg_float(S0_tos, S0_tos);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::dneg() {
+  transition(dtos, dtos);
+#ifdef __SOFTFP__
+  // Invert sign bit in the high part of the double
+  const int sign_mask_hi = 0x80000000;
+  __ eor(R1_tos_hi, R1_tos_hi, sign_mask_hi);
+#else
+  __ neg_double(D0_tos, D0_tos);
+#endif // __SOFTFP__
+}
+
+
+void TemplateTable::iinc() {
+  transition(vtos, vtos);
+  const Register Rconst = R2_tmp;
+  const Register Rlocal_index = R1_tmp;
+  const Register Rval = R0_tmp;
+
+  __ ldrsb(Rconst, at_bcp(2));
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(Rval, local);
+  __ add(Rval, Rval, Rconst);
+  __ str_32(Rval, local);
+}
+
+
+void TemplateTable::wide_iinc() {
+  transition(vtos, vtos);
+  const Register Rconst = R2_tmp;
+  const Register Rlocal_index = R1_tmp;
+  const Register Rval = R0_tmp;
+
+  // get constant in Rconst
+  __ ldrsb(R2_tmp, at_bcp(4));
+  __ ldrb(R3_tmp, at_bcp(5));
+  __ orr(Rconst, R3_tmp, AsmOperand(R2_tmp, lsl, 8));
+
+  locals_index_wide(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(Rval, local);
+  __ add(Rval, Rval, Rconst);
+  __ str_32(Rval, local);
+}
+
+
+void TemplateTable::convert() {
+  // Checking
+#ifdef ASSERT
+  { TosState tos_in  = ilgl;
+    TosState tos_out = ilgl;
+    switch (bytecode()) {
+      case Bytecodes::_i2l: // fall through
+      case Bytecodes::_i2f: // fall through
+      case Bytecodes::_i2d: // fall through
+      case Bytecodes::_i2b: // fall through
+      case Bytecodes::_i2c: // fall through
+      case Bytecodes::_i2s: tos_in = itos; break;
+      case Bytecodes::_l2i: // fall through
+      case Bytecodes::_l2f: // fall through
+      case Bytecodes::_l2d: tos_in = ltos; break;
+      case Bytecodes::_f2i: // fall through
+      case Bytecodes::_f2l: // fall through
+      case Bytecodes::_f2d: tos_in = ftos; break;
+      case Bytecodes::_d2i: // fall through
+      case Bytecodes::_d2l: // fall through
+      case Bytecodes::_d2f: tos_in = dtos; break;
+      default             : ShouldNotReachHere();
+    }
+    switch (bytecode()) {
+      case Bytecodes::_l2i: // fall through
+      case Bytecodes::_f2i: // fall through
+      case Bytecodes::_d2i: // fall through
+      case Bytecodes::_i2b: // fall through
+      case Bytecodes::_i2c: // fall through
+      case Bytecodes::_i2s: tos_out = itos; break;
+      case Bytecodes::_i2l: // fall through
+      case Bytecodes::_f2l: // fall through
+      case Bytecodes::_d2l: tos_out = ltos; break;
+      case Bytecodes::_i2f: // fall through
+      case Bytecodes::_l2f: // fall through
+      case Bytecodes::_d2f: tos_out = ftos; break;
+      case Bytecodes::_i2d: // fall through
+      case Bytecodes::_l2d: // fall through
+      case Bytecodes::_f2d: tos_out = dtos; break;
+      default             : ShouldNotReachHere();
+    }
+    transition(tos_in, tos_out);
+  }
+#endif // ASSERT
+
+  // Conversion
+  switch (bytecode()) {
+    case Bytecodes::_i2l:
+#ifdef AARCH64
+      __ sign_extend(R0_tos, R0_tos, 32);
+#else
+      __ mov(R1_tos_hi, AsmOperand(R0_tos, asr, BitsPerWord-1));
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_i2f:
+#ifdef AARCH64
+      __ scvtf_sw(S0_tos, R0_tos);
+#else
+#ifdef __SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_i2f), R0_tos);
+#else
+      __ fmsr(S0_tmp, R0_tos);
+      __ fsitos(S0_tos, S0_tmp);
+#endif // __SOFTFP__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_i2d:
+#ifdef AARCH64
+      __ scvtf_dw(D0_tos, R0_tos);
+#else
+#ifdef __SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_i2d), R0_tos);
+#else
+      __ fmsr(S0_tmp, R0_tos);
+      __ fsitod(D0_tos, S0_tmp);
+#endif // __SOFTFP__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_i2b:
+      __ sign_extend(R0_tos, R0_tos, 8);
+      break;
+
+    case Bytecodes::_i2c:
+      __ zero_extend(R0_tos, R0_tos, 16);
+      break;
+
+    case Bytecodes::_i2s:
+      __ sign_extend(R0_tos, R0_tos, 16);
+      break;
+
+    case Bytecodes::_l2i:
+      /* nothing to do */
+      break;
+
+    case Bytecodes::_l2f:
+#ifdef AARCH64
+      __ scvtf_sx(S0_tos, R0_tos);
+#else
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f), R0_tos_lo, R1_tos_hi);
+#if !defined(__SOFTFP__) && !defined(__ABI_HARD__)
+      __ fmsr(S0_tos, R0);
+#endif // !__SOFTFP__ && !__ABI_HARD__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_l2d:
+#ifdef AARCH64
+      __ scvtf_dx(D0_tos, R0_tos);
+#else
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2d), R0_tos_lo, R1_tos_hi);
+#if !defined(__SOFTFP__) && !defined(__ABI_HARD__)
+      __ fmdrr(D0_tos, R0, R1);
+#endif // !__SOFTFP__ && !__ABI_HARD__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_f2i:
+#ifdef AARCH64
+      __ fcvtzs_ws(R0_tos, S0_tos);
+#else
+#ifndef __SOFTFP__
+      __ ftosizs(S0_tos, S0_tos);
+      __ fmrs(R0_tos, S0_tos);
+#else
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2i), R0_tos);
+#endif // !__SOFTFP__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_f2l:
+#ifdef AARCH64
+      __ fcvtzs_xs(R0_tos, S0_tos);
+#else
+#ifndef __SOFTFP__
+      __ fmrs(R0_tos, S0_tos);
+#endif // !__SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), R0_tos);
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_f2d:
+#ifdef __SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_f2d), R0_tos);
+#else
+      __ convert_f2d(D0_tos, S0_tos);
+#endif // __SOFTFP__
+      break;
+
+    case Bytecodes::_d2i:
+#ifdef AARCH64
+      __ fcvtzs_wd(R0_tos, D0_tos);
+#else
+#ifndef __SOFTFP__
+      __ ftosizd(Stemp, D0);
+      __ fmrs(R0, Stemp);
+#else
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), R0_tos_lo, R1_tos_hi);
+#endif // !__SOFTFP__
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_d2l:
+#ifdef AARCH64
+      __ fcvtzs_xd(R0_tos, D0_tos);
+#else
+#ifndef __SOFTFP__
+      __ fmrrd(R0_tos_lo, R1_tos_hi, D0_tos);
+#endif // !__SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), R0_tos_lo, R1_tos_hi);
+#endif // AARCH64
+      break;
+
+    case Bytecodes::_d2f:
+#ifdef __SOFTFP__
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, __aeabi_d2f), R0_tos_lo, R1_tos_hi);
+#else
+      __ convert_d2f(S0_tos, D0_tos);
+#endif // __SOFTFP__
+      break;
+
+    default:
+      ShouldNotReachHere();
+  }
+}
+
+
+void TemplateTable::lcmp() {
+  transition(ltos, itos);
+#ifdef AARCH64
+  const Register arg1 = R1_tmp;
+  const Register arg2 = R0_tos;
+
+  __ pop_l(arg1);
+
+  __ cmp(arg1, arg2);
+  __ cset(R0_tos, gt);               // 1 if '>', else 0
+  __ csinv(R0_tos, R0_tos, ZR, ge);  // previous value if '>=', else -1
+#else
+  const Register arg1_lo = R2_tmp;
+  const Register arg1_hi = R3_tmp;
+  const Register arg2_lo = R0_tos_lo;
+  const Register arg2_hi = R1_tos_hi;
+  const Register res = R4_tmp;
+
+  __ pop_l(arg1_lo, arg1_hi);
+
+  // long compare arg1 with arg2
+  // result is -1/0/+1 if '<'/'='/'>'
+  Label done;
+
+  __ mov (res, 0);
+  __ cmp (arg1_hi, arg2_hi);
+  __ mvn (res, 0, lt);
+  __ mov (res, 1, gt);
+  __ b(done, ne);
+  __ cmp (arg1_lo, arg2_lo);
+  __ mvn (res, 0, lo);
+  __ mov (res, 1, hi);
+  __ bind(done);
+  __ mov (R0_tos, res);
+#endif // AARCH64
+}
+
+
+void TemplateTable::float_cmp(bool is_float, int unordered_result) {
+  assert((unordered_result == 1) || (unordered_result == -1), "invalid unordered result");
+
+#ifdef AARCH64
+  if (is_float) {
+    transition(ftos, itos);
+    __ pop_f(S1_tmp);
+    __ fcmp_s(S1_tmp, S0_tos);
+  } else {
+    transition(dtos, itos);
+    __ pop_d(D1_tmp);
+    __ fcmp_d(D1_tmp, D0_tos);
+  }
+
+  if (unordered_result < 0) {
+    __ cset(R0_tos, gt);               // 1 if '>', else 0
+    __ csinv(R0_tos, R0_tos, ZR, ge);  // previous value if '>=', else -1
+  } else {
+    __ cset(R0_tos, hi);               // 1 if '>' or unordered, else 0
+    __ csinv(R0_tos, R0_tos, ZR, pl);  // previous value if '>=' or unordered, else -1
+  }
+
+#else
+
+#ifdef __SOFTFP__
+
+  if (is_float) {
+    transition(ftos, itos);
+    const Register Rx = R0;
+    const Register Ry = R1;
+
+    __ mov(Ry, R0_tos);
+    __ pop_i(Rx);
+
+    if (unordered_result == 1) {
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::fcmpg), Rx, Ry);
+    } else {
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::fcmpl), Rx, Ry);
+    }
+
+  } else {
+
+    transition(dtos, itos);
+    const Register Rx_lo = R0;
+    const Register Rx_hi = R1;
+    const Register Ry_lo = R2;
+    const Register Ry_hi = R3;
+
+    __ mov(Ry_lo, R0_tos_lo);
+    __ mov(Ry_hi, R1_tos_hi);
+    __ pop_l(Rx_lo, Rx_hi);
+
+    if (unordered_result == 1) {
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dcmpg), Rx_lo, Rx_hi, Ry_lo, Ry_hi);
+    } else {
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dcmpl), Rx_lo, Rx_hi, Ry_lo, Ry_hi);
+    }
+  }
+
+#else
+
+  if (is_float) {
+    transition(ftos, itos);
+    __ pop_f(S1_tmp);
+    __ fcmps(S1_tmp, S0_tos);
+  } else {
+    transition(dtos, itos);
+    __ pop_d(D1_tmp);
+    __ fcmpd(D1_tmp, D0_tos);
+  }
+
+  __ fmstat();
+
+  // comparison result | flag N | flag Z | flag C | flag V
+  // "<"               |   1    |   0    |   0    |   0
+  // "=="              |   0    |   1    |   1    |   0
+  // ">"               |   0    |   0    |   1    |   0
+  // unordered         |   0    |   0    |   1    |   1
+
+  if (unordered_result < 0) {
+    __ mov(R0_tos, 1);           // result ==  1 if greater
+    __ mvn(R0_tos, 0, lt);       // result == -1 if less or unordered (N!=V)
+  } else {
+    __ mov(R0_tos, 1);           // result ==  1 if greater or unordered
+    __ mvn(R0_tos, 0, mi);       // result == -1 if less (N=1)
+  }
+  __ mov(R0_tos, 0, eq);         // result ==  0 if equ (Z=1)
+#endif // __SOFTFP__
+#endif // AARCH64
+}
+
+
+void TemplateTable::branch(bool is_jsr, bool is_wide) {
+
+  const Register Rdisp = R0_tmp;
+  const Register Rbumped_taken_count = R5_tmp;
+
+  __ profile_taken_branch(R0_tmp, Rbumped_taken_count); // R0 holds updated MDP, Rbumped_taken_count holds bumped taken count
+
+  const ByteSize be_offset = MethodCounters::backedge_counter_offset() +
+                             InvocationCounter::counter_offset();
+  const ByteSize inv_offset = MethodCounters::invocation_counter_offset() +
+                              InvocationCounter::counter_offset();
+  const int method_offset = frame::interpreter_frame_method_offset * wordSize;
+
+  // Load up R0 with the branch displacement
+  if (is_wide) {
+    __ ldrsb(R0_tmp, at_bcp(1));
+    __ ldrb(R1_tmp, at_bcp(2));
+    __ ldrb(R2_tmp, at_bcp(3));
+    __ ldrb(R3_tmp, at_bcp(4));
+    __ orr(R0_tmp, R1_tmp, AsmOperand(R0_tmp, lsl, BitsPerByte));
+    __ orr(R0_tmp, R2_tmp, AsmOperand(R0_tmp, lsl, BitsPerByte));
+    __ orr(Rdisp, R3_tmp, AsmOperand(R0_tmp, lsl, BitsPerByte));
+  } else {
+    __ ldrsb(R0_tmp, at_bcp(1));
+    __ ldrb(R1_tmp, at_bcp(2));
+    __ orr(Rdisp, R1_tmp, AsmOperand(R0_tmp, lsl, BitsPerByte));
+  }
+
+  // Handle all the JSR stuff here, then exit.
+  // It's much shorter and cleaner than intermingling with the
+  // non-JSR normal-branch stuff occuring below.
+  if (is_jsr) {
+    // compute return address as bci in R1
+    const Register Rret_addr = R1_tmp;
+    assert_different_registers(Rdisp, Rret_addr, Rtemp);
+
+    __ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+    __ sub(Rret_addr, Rbcp, - (is_wide ? 5 : 3) + in_bytes(ConstMethod::codes_offset()));
+    __ sub(Rret_addr, Rret_addr, Rtemp);
+
+    // Load the next target bytecode into R3_bytecode and advance Rbcp
+#ifdef AARCH64
+    __ add(Rbcp, Rbcp, Rdisp);
+    __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+    __ ldrb(R3_bytecode, Address(Rbcp, Rdisp, lsl, 0, pre_indexed));
+#endif // AARCH64
+
+    // Push return address
+    __ push_i(Rret_addr);
+    // jsr returns vtos
+    __ dispatch_only_noverify(vtos);
+    return;
+  }
+
+  // Normal (non-jsr) branch handling
+
+  // Adjust the bcp by the displacement in Rdisp and load next bytecode.
+#ifdef AARCH64
+  __ add(Rbcp, Rbcp, Rdisp);
+  __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+  __ ldrb(R3_bytecode, Address(Rbcp, Rdisp, lsl, 0, pre_indexed));
+#endif // AARCH64
+
+  assert(UseLoopCounter || !UseOnStackReplacement, "on-stack-replacement requires loop counters");
+  Label backedge_counter_overflow;
+  Label profile_method;
+  Label dispatch;
+
+  if (UseLoopCounter) {
+    // increment backedge counter for backward branches
+    // Rdisp (R0): target offset
+
+    const Register Rcnt = R2_tmp;
+    const Register Rcounters = R1_tmp;
+
+    // count only if backward branch
+#ifdef AARCH64
+    __ tbz(Rdisp, (BitsPerWord - 1), dispatch); // TODO-AARCH64: check performance of this variant on 32-bit ARM
+#else
+    __ tst(Rdisp, Rdisp);
+    __ b(dispatch, pl);
+#endif // AARCH64
+
+    if (TieredCompilation) {
+      Label no_mdo;
+      int increment = InvocationCounter::count_increment;
+      if (ProfileInterpreter) {
+        // Are we profiling?
+        __ ldr(Rtemp, Address(Rmethod, Method::method_data_offset()));
+        __ cbz(Rtemp, no_mdo);
+        // Increment the MDO backedge counter
+        const Address mdo_backedge_counter(Rtemp, in_bytes(MethodData::backedge_counter_offset()) +
+                                                  in_bytes(InvocationCounter::counter_offset()));
+        const Address mask(Rtemp, in_bytes(MethodData::backedge_mask_offset()));
+        __ increment_mask_and_jump(mdo_backedge_counter, increment, mask,
+                                   Rcnt, R4_tmp, eq, &backedge_counter_overflow);
+        __ b(dispatch);
+      }
+      __ bind(no_mdo);
+      // Increment backedge counter in MethodCounters*
+      __ get_method_counters(Rmethod, Rcounters, dispatch);
+      const Address mask(Rcounters, in_bytes(MethodCounters::backedge_mask_offset()));
+      __ increment_mask_and_jump(Address(Rcounters, be_offset), increment, mask,
+                                 Rcnt, R4_tmp, eq, &backedge_counter_overflow);
+    } else {
+      // increment counter
+      __ get_method_counters(Rmethod, Rcounters, dispatch);
+      __ ldr_u32(Rtemp, Address(Rcounters, be_offset));           // load backedge counter
+      __ add(Rtemp, Rtemp, InvocationCounter::count_increment);   // increment counter
+      __ str_32(Rtemp, Address(Rcounters, be_offset));            // store counter
+
+      __ ldr_u32(Rcnt, Address(Rcounters, inv_offset));           // load invocation counter
+#ifdef AARCH64
+      __ andr(Rcnt, Rcnt, (unsigned int)InvocationCounter::count_mask_value);  // and the status bits
+#else
+      __ bic(Rcnt, Rcnt, ~InvocationCounter::count_mask_value);  // and the status bits
+#endif // AARCH64
+      __ add(Rcnt, Rcnt, Rtemp);                                 // add both counters
+
+      if (ProfileInterpreter) {
+        // Test to see if we should create a method data oop
+        const Address profile_limit(Rcounters, in_bytes(MethodCounters::interpreter_profile_limit_offset()));
+        __ ldr_s32(Rtemp, profile_limit);
+        __ cmp_32(Rcnt, Rtemp);
+        __ b(dispatch, lt);
+
+        // if no method data exists, go to profile method
+        __ test_method_data_pointer(R4_tmp, profile_method);
+
+        if (UseOnStackReplacement) {
+          // check for overflow against Rbumped_taken_count, which is the MDO taken count
+          const Address backward_branch_limit(Rcounters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()));
+          __ ldr_s32(Rtemp, backward_branch_limit);
+          __ cmp(Rbumped_taken_count, Rtemp);
+          __ b(dispatch, lo);
+
+          // When ProfileInterpreter is on, the backedge_count comes from the
+          // MethodData*, which value does not get reset on the call to
+          // frequency_counter_overflow().  To avoid excessive calls to the overflow
+          // routine while the method is being compiled, add a second test to make
+          // sure the overflow function is called only once every overflow_frequency.
+          const int overflow_frequency = 1024;
+
+#ifdef AARCH64
+          __ tst(Rbumped_taken_count, (unsigned)(overflow_frequency-1));
+#else
+          // was '__ andrs(...,overflow_frequency-1)', testing if lowest 10 bits are 0
+          assert(overflow_frequency == (1 << 10),"shift by 22 not correct for expected frequency");
+          __ movs(Rbumped_taken_count, AsmOperand(Rbumped_taken_count, lsl, 22));
+#endif // AARCH64
+
+          __ b(backedge_counter_overflow, eq);
+        }
+      } else {
+        if (UseOnStackReplacement) {
+          // check for overflow against Rcnt, which is the sum of the counters
+          const Address backward_branch_limit(Rcounters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()));
+          __ ldr_s32(Rtemp, backward_branch_limit);
+          __ cmp_32(Rcnt, Rtemp);
+          __ b(backedge_counter_overflow, hs);
+
+        }
+      }
+    }
+    __ bind(dispatch);
+  }
+
+  if (!UseOnStackReplacement) {
+    __ bind(backedge_counter_overflow);
+  }
+
+  // continue with the bytecode @ target
+  __ dispatch_only(vtos);
+
+  if (UseLoopCounter) {
+    if (ProfileInterpreter) {
+      // Out-of-line code to allocate method data oop.
+      __ bind(profile_method);
+
+      __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+      __ set_method_data_pointer_for_bcp();
+      // reload next bytecode
+      __ ldrb(R3_bytecode, Address(Rbcp));
+      __ b(dispatch);
+    }
+
+    if (UseOnStackReplacement) {
+      // invocation counter overflow
+      __ bind(backedge_counter_overflow);
+
+      __ sub(R1, Rbcp, Rdisp);                   // branch bcp
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R1);
+
+      // R0: osr nmethod (osr ok) or NULL (osr not possible)
+      const Register Rnmethod = R0;
+
+      __ ldrb(R3_bytecode, Address(Rbcp));       // reload next bytecode
+
+      __ cbz(Rnmethod, dispatch);                // test result, no osr if null
+
+      // nmethod may have been invalidated (VM may block upon call_VM return)
+      __ ldrb(R1_tmp, Address(Rnmethod, nmethod::state_offset()));
+      __ cmp(R1_tmp, nmethod::in_use);
+      __ b(dispatch, ne);
+
+      // We have the address of an on stack replacement routine in Rnmethod,
+      // We need to prepare to execute the OSR method. First we must
+      // migrate the locals and monitors off of the stack.
+
+      __ mov(Rtmp_save0, Rnmethod);                      // save the nmethod
+
+      call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));
+
+      // R0 is OSR buffer
+
+      __ ldr(R1_tmp, Address(Rtmp_save0, nmethod::osr_entry_point_offset()));
+      __ ldr(Rtemp, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+
+#ifdef AARCH64
+      __ ldp(FP, LR, Address(FP));
+      __ mov(SP, Rtemp);
+#else
+      __ ldmia(FP, RegisterSet(FP) | RegisterSet(LR));
+      __ bic(SP, Rtemp, StackAlignmentInBytes - 1);     // Remove frame and align stack
+#endif // AARCH64
+
+      __ jump(R1_tmp);
+    }
+  }
+}
+
+
+void TemplateTable::if_0cmp(Condition cc) {
+  transition(itos, vtos);
+  // assume branch is more often taken than not (loops use backward branches)
+  Label not_taken;
+#ifdef AARCH64
+  if (cc == equal) {
+    __ cbnz_w(R0_tos, not_taken);
+  } else if (cc == not_equal) {
+    __ cbz_w(R0_tos, not_taken);
+  } else {
+    __ cmp_32(R0_tos, 0);
+    __ b(not_taken, convNegCond(cc));
+  }
+#else
+  __ cmp_32(R0_tos, 0);
+  __ b(not_taken, convNegCond(cc));
+#endif // AARCH64
+  branch(false, false);
+  __ bind(not_taken);
+  __ profile_not_taken_branch(R0_tmp);
+}
+
+
+void TemplateTable::if_icmp(Condition cc) {
+  transition(itos, vtos);
+  // assume branch is more often taken than not (loops use backward branches)
+  Label not_taken;
+  __ pop_i(R1_tmp);
+  __ cmp_32(R1_tmp, R0_tos);
+  __ b(not_taken, convNegCond(cc));
+  branch(false, false);
+  __ bind(not_taken);
+  __ profile_not_taken_branch(R0_tmp);
+}
+
+
+void TemplateTable::if_nullcmp(Condition cc) {
+  transition(atos, vtos);
+  assert(cc == equal || cc == not_equal, "invalid condition");
+
+  // assume branch is more often taken than not (loops use backward branches)
+  Label not_taken;
+  if (cc == equal) {
+    __ cbnz(R0_tos, not_taken);
+  } else {
+    __ cbz(R0_tos, not_taken);
+  }
+  branch(false, false);
+  __ bind(not_taken);
+  __ profile_not_taken_branch(R0_tmp);
+}
+
+
+void TemplateTable::if_acmp(Condition cc) {
+  transition(atos, vtos);
+  // assume branch is more often taken than not (loops use backward branches)
+  Label not_taken;
+  __ pop_ptr(R1_tmp);
+  __ cmp(R1_tmp, R0_tos);
+  __ b(not_taken, convNegCond(cc));
+  branch(false, false);
+  __ bind(not_taken);
+  __ profile_not_taken_branch(R0_tmp);
+}
+
+
+void TemplateTable::ret() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R1_tmp;
+  const Register Rret_bci = Rtmp_save0; // R4/R19
+
+  locals_index(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(Rret_bci, local);          // get return bci, compute return bcp
+  __ profile_ret(Rtmp_save1, Rret_bci);
+  __ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+  __ add(Rtemp, Rtemp, in_bytes(ConstMethod::codes_offset()));
+  __ add(Rbcp, Rtemp, Rret_bci);
+  __ dispatch_next(vtos);
+}
+
+
+void TemplateTable::wide_ret() {
+  transition(vtos, vtos);
+  const Register Rlocal_index = R1_tmp;
+  const Register Rret_bci = Rtmp_save0; // R4/R19
+
+  locals_index_wide(Rlocal_index);
+  Address local = load_iaddress(Rlocal_index, Rtemp);
+  __ ldr_s32(Rret_bci, local);               // get return bci, compute return bcp
+  __ profile_ret(Rtmp_save1, Rret_bci);
+  __ ldr(Rtemp, Address(Rmethod, Method::const_offset()));
+  __ add(Rtemp, Rtemp, in_bytes(ConstMethod::codes_offset()));
+  __ add(Rbcp, Rtemp, Rret_bci);
+  __ dispatch_next(vtos);
+}
+
+
+void TemplateTable::tableswitch() {
+  transition(itos, vtos);
+
+  const Register Rindex  = R0_tos;
+#ifndef AARCH64
+  const Register Rtemp2  = R1_tmp;
+#endif // !AARCH64
+  const Register Rabcp   = R2_tmp;  // aligned bcp
+  const Register Rlow    = R3_tmp;
+  const Register Rhigh   = R4_tmp;
+  const Register Roffset = R5_tmp;
+
+  // align bcp
+  __ add(Rtemp, Rbcp, 1 + (2*BytesPerInt-1));
+  __ align_reg(Rabcp, Rtemp, BytesPerInt);
+
+  // load lo & hi
+#ifdef AARCH64
+  __ ldp_w(Rlow, Rhigh, Address(Rabcp, 2*BytesPerInt, post_indexed));
+#else
+  __ ldmia(Rabcp, RegisterSet(Rlow) | RegisterSet(Rhigh), writeback);
+#endif // AARCH64
+  __ byteswap_u32(Rlow, Rtemp, Rtemp2);
+  __ byteswap_u32(Rhigh, Rtemp, Rtemp2);
+
+  // compare index with high bound
+  __ cmp_32(Rhigh, Rindex);
+
+#ifdef AARCH64
+  Label default_case, do_dispatch;
+  __ ccmp_w(Rindex, Rlow, Assembler::flags_for_condition(lt), ge);
+  __ b(default_case, lt);
+
+  __ sub_w(Rindex, Rindex, Rlow);
+  __ ldr_s32(Roffset, Address(Rabcp, Rindex, ex_sxtw, LogBytesPerInt));
+  if(ProfileInterpreter) {
+    __ sxtw(Rindex, Rindex);
+    __ profile_switch_case(Rabcp, Rindex, Rtemp2, R0_tmp);
+  }
+  __ b(do_dispatch);
+
+  __ bind(default_case);
+  __ ldr_s32(Roffset, Address(Rabcp, -3 * BytesPerInt));
+  if(ProfileInterpreter) {
+    __ profile_switch_default(R0_tmp);
+  }
+
+  __ bind(do_dispatch);
+#else
+
+  // if Rindex <= Rhigh then calculate index in table (Rindex - Rlow)
+  __ subs(Rindex, Rindex, Rlow, ge);
+
+  // if Rindex <= Rhigh and (Rindex - Rlow) >= 0
+  // ("ge" status accumulated from cmp and subs instructions) then load
+  // offset from table, otherwise load offset for default case
+
+  if(ProfileInterpreter) {
+    Label default_case, continue_execution;
+
+    __ b(default_case, lt);
+    __ ldr(Roffset, Address(Rabcp, Rindex, lsl, LogBytesPerInt));
+    __ profile_switch_case(Rabcp, Rindex, Rtemp2, R0_tmp);
+    __ b(continue_execution);
+
+    __ bind(default_case);
+    __ profile_switch_default(R0_tmp);
+    __ ldr(Roffset, Address(Rabcp, -3 * BytesPerInt));
+
+    __ bind(continue_execution);
+  } else {
+    __ ldr(Roffset, Address(Rabcp, -3 * BytesPerInt), lt);
+    __ ldr(Roffset, Address(Rabcp, Rindex, lsl, LogBytesPerInt), ge);
+  }
+#endif // AARCH64
+
+  __ byteswap_u32(Roffset, Rtemp, Rtemp2);
+
+  // load the next bytecode to R3_bytecode and advance Rbcp
+#ifdef AARCH64
+  __ add(Rbcp, Rbcp, Roffset, ex_sxtw);
+  __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+  __ ldrb(R3_bytecode, Address(Rbcp, Roffset, lsl, 0, pre_indexed));
+#endif // AARCH64
+  __ dispatch_only(vtos);
+
+}
+
+
+void TemplateTable::lookupswitch() {
+  transition(itos, itos);
+  __ stop("lookupswitch bytecode should have been rewritten");
+}
+
+
+void TemplateTable::fast_linearswitch() {
+  transition(itos, vtos);
+  Label loop, found, default_case, continue_execution;
+
+  const Register Rkey     = R0_tos;
+  const Register Rabcp    = R2_tmp;  // aligned bcp
+  const Register Rdefault = R3_tmp;
+  const Register Rcount   = R4_tmp;
+  const Register Roffset  = R5_tmp;
+
+  // bswap Rkey, so we can avoid bswapping the table entries
+  __ byteswap_u32(Rkey, R1_tmp, Rtemp);
+
+  // align bcp
+  __ add(Rtemp, Rbcp, 1 + (BytesPerInt-1));
+  __ align_reg(Rabcp, Rtemp, BytesPerInt);
+
+  // load default & counter
+#ifdef AARCH64
+  __ ldp_w(Rdefault, Rcount, Address(Rabcp, 2*BytesPerInt, post_indexed));
+#else
+  __ ldmia(Rabcp, RegisterSet(Rdefault) | RegisterSet(Rcount), writeback);
+#endif // AARCH64
+  __ byteswap_u32(Rcount, R1_tmp, Rtemp);
+
+#ifdef AARCH64
+  __ cbz_w(Rcount, default_case);
+#else
+  __ cmp_32(Rcount, 0);
+  __ ldr(Rtemp, Address(Rabcp, 2*BytesPerInt, post_indexed), ne);
+  __ b(default_case, eq);
+#endif // AARCH64
+
+  // table search
+  __ bind(loop);
+#ifdef AARCH64
+  __ ldr_s32(Rtemp, Address(Rabcp, 2*BytesPerInt, post_indexed));
+#endif // AARCH64
+  __ cmp_32(Rtemp, Rkey);
+  __ b(found, eq);
+  __ subs(Rcount, Rcount, 1);
+#ifndef AARCH64
+  __ ldr(Rtemp, Address(Rabcp, 2*BytesPerInt, post_indexed), ne);
+#endif // !AARCH64
+  __ b(loop, ne);
+
+  // default case
+  __ bind(default_case);
+  __ profile_switch_default(R0_tmp);
+  __ mov(Roffset, Rdefault);
+  __ b(continue_execution);
+
+  // entry found -> get offset
+  __ bind(found);
+  // Rabcp is already incremented and points to the next entry
+  __ ldr_s32(Roffset, Address(Rabcp, -BytesPerInt));
+  if (ProfileInterpreter) {
+    // Calculate index of the selected case.
+    assert_different_registers(Roffset, Rcount, Rtemp, R0_tmp, R1_tmp, R2_tmp);
+
+    // align bcp
+    __ add(Rtemp, Rbcp, 1 + (BytesPerInt-1));
+    __ align_reg(R2_tmp, Rtemp, BytesPerInt);
+
+    // load number of cases
+    __ ldr_u32(R2_tmp, Address(R2_tmp, BytesPerInt));
+    __ byteswap_u32(R2_tmp, R1_tmp, Rtemp);
+
+    // Selected index = <number of cases> - <current loop count>
+    __ sub(R1_tmp, R2_tmp, Rcount);
+    __ profile_switch_case(R0_tmp, R1_tmp, Rtemp, R1_tmp);
+  }
+
+  // continue execution
+  __ bind(continue_execution);
+  __ byteswap_u32(Roffset, R1_tmp, Rtemp);
+
+  // load the next bytecode to R3_bytecode and advance Rbcp
+#ifdef AARCH64
+  __ add(Rbcp, Rbcp, Roffset, ex_sxtw);
+  __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+  __ ldrb(R3_bytecode, Address(Rbcp, Roffset, lsl, 0, pre_indexed));
+#endif // AARCH64
+  __ dispatch_only(vtos);
+}
+
+
+void TemplateTable::fast_binaryswitch() {
+  transition(itos, vtos);
+  // Implementation using the following core algorithm:
+  //
+  // int binary_search(int key, LookupswitchPair* array, int n) {
+  //   // Binary search according to "Methodik des Programmierens" by
+  //   // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985.
+  //   int i = 0;
+  //   int j = n;
+  //   while (i+1 < j) {
+  //     // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q)
+  //     // with      Q: for all i: 0 <= i < n: key < a[i]
+  //     // where a stands for the array and assuming that the (inexisting)
+  //     // element a[n] is infinitely big.
+  //     int h = (i + j) >> 1;
+  //     // i < h < j
+  //     if (key < array[h].fast_match()) {
+  //       j = h;
+  //     } else {
+  //       i = h;
+  //     }
+  //   }
+  //   // R: a[i] <= key < a[i+1] or Q
+  //   // (i.e., if key is within array, i is the correct index)
+  //   return i;
+  // }
+
+  // register allocation
+  const Register key    = R0_tos;                // already set (tosca)
+  const Register array  = R1_tmp;
+  const Register i      = R2_tmp;
+  const Register j      = R3_tmp;
+  const Register h      = R4_tmp;
+  const Register val    = R5_tmp;
+  const Register temp1  = Rtemp;
+  const Register temp2  = LR_tmp;
+  const Register offset = R3_tmp;
+
+  // set 'array' = aligned bcp + 2 ints
+  __ add(temp1, Rbcp, 1 + (BytesPerInt-1) + 2*BytesPerInt);
+  __ align_reg(array, temp1, BytesPerInt);
+
+  // initialize i & j
+  __ mov(i, 0);                                  // i = 0;
+  __ ldr_s32(j, Address(array, -BytesPerInt));   // j = length(array);
+  // Convert j into native byteordering
+  __ byteswap_u32(j, temp1, temp2);
+
+  // and start
+  Label entry;
+  __ b(entry);
+
+  // binary search loop
+  { Label loop;
+    __ bind(loop);
+    // int h = (i + j) >> 1;
+    __ add(h, i, j);                             // h = i + j;
+    __ logical_shift_right(h, h, 1);             // h = (i + j) >> 1;
+    // if (key < array[h].fast_match()) {
+    //   j = h;
+    // } else {
+    //   i = h;
+    // }
+#ifdef AARCH64
+    __ add(temp1, array, AsmOperand(h, lsl, 1+LogBytesPerInt));
+    __ ldr_s32(val, Address(temp1));
+#else
+    __ ldr_s32(val, Address(array, h, lsl, 1+LogBytesPerInt));
+#endif // AARCH64
+    // Convert array[h].match to native byte-ordering before compare
+    __ byteswap_u32(val, temp1, temp2);
+    __ cmp_32(key, val);
+    __ mov(j, h, lt);   // j = h if (key <  array[h].fast_match())
+    __ mov(i, h, ge);   // i = h if (key >= array[h].fast_match())
+    // while (i+1 < j)
+    __ bind(entry);
+    __ add(temp1, i, 1);                             // i+1
+    __ cmp(temp1, j);                                // i+1 < j
+    __ b(loop, lt);
+  }
+
+  // end of binary search, result index is i (must check again!)
+  Label default_case;
+  // Convert array[i].match to native byte-ordering before compare
+#ifdef AARCH64
+  __ add(temp1, array, AsmOperand(i, lsl, 1+LogBytesPerInt));
+  __ ldr_s32(val, Address(temp1));
+#else
+  __ ldr_s32(val, Address(array, i, lsl, 1+LogBytesPerInt));
+#endif // AARCH64
+  __ byteswap_u32(val, temp1, temp2);
+  __ cmp_32(key, val);
+  __ b(default_case, ne);
+
+  // entry found
+  __ add(temp1, array, AsmOperand(i, lsl, 1+LogBytesPerInt));
+  __ ldr_s32(offset, Address(temp1, 1*BytesPerInt));
+  __ profile_switch_case(R0, i, R1, i);
+  __ byteswap_u32(offset, temp1, temp2);
+#ifdef AARCH64
+  __ add(Rbcp, Rbcp, offset, ex_sxtw);
+  __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+  __ ldrb(R3_bytecode, Address(Rbcp, offset, lsl, 0, pre_indexed));
+#endif // AARCH64
+  __ dispatch_only(vtos);
+
+  // default case
+  __ bind(default_case);
+  __ profile_switch_default(R0);
+  __ ldr_s32(offset, Address(array, -2*BytesPerInt));
+  __ byteswap_u32(offset, temp1, temp2);
+#ifdef AARCH64
+  __ add(Rbcp, Rbcp, offset, ex_sxtw);
+  __ ldrb(R3_bytecode, Address(Rbcp));
+#else
+  __ ldrb(R3_bytecode, Address(Rbcp, offset, lsl, 0, pre_indexed));
+#endif // AARCH64
+  __ dispatch_only(vtos);
+}
+
+
+void TemplateTable::_return(TosState state) {
+  transition(state, state);
+  assert(_desc->calls_vm(), "inconsistent calls_vm information"); // call in remove_activation
+
+  if (_desc->bytecode() == Bytecodes::_return_register_finalizer) {
+    Label skip_register_finalizer;
+    assert(state == vtos, "only valid state");
+    __ ldr(R1, aaddress(0));
+    __ load_klass(Rtemp, R1);
+    __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset()));
+    __ tbz(Rtemp, exact_log2(JVM_ACC_HAS_FINALIZER), skip_register_finalizer);
+
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R1);
+
+    __ bind(skip_register_finalizer);
+  }
+
+  // Narrow result if state is itos but result type is smaller.
+  // Need to narrow in the return bytecode rather than in generate_return_entry
+  // since compiled code callers expect the result to already be narrowed.
+  if (state == itos) {
+    __ narrow(R0_tos);
+  }
+  __ remove_activation(state, LR);
+
+  __ interp_verify_oop(R0_tos, state, __FILE__, __LINE__);
+
+#ifndef AARCH64
+  // According to interpreter calling conventions, result is returned in R0/R1,
+  // so ftos (S0) and dtos (D0) are moved to R0/R1.
+  // This conversion should be done after remove_activation, as it uses
+  // push(state) & pop(state) to preserve return value.
+  __ convert_tos_to_retval(state);
+#endif // !AARCH64
+
+  __ ret();
+
+  __ nop(); // to avoid filling CPU pipeline with invalid instructions
+  __ nop();
+}
+
+
+// ----------------------------------------------------------------------------
+// Volatile variables demand their effects be made known to all CPU's in
+// order.  Store buffers on most chips allow reads & writes to reorder; the
+// JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
+// memory barrier (i.e., it's not sufficient that the interpreter does not
+// reorder volatile references, the hardware also must not reorder them).
+//
+// According to the new Java Memory Model (JMM):
+// (1) All volatiles are serialized wrt to each other.
+// ALSO reads & writes act as aquire & release, so:
+// (2) A read cannot let unrelated NON-volatile memory refs that happen after
+// the read float up to before the read.  It's OK for non-volatile memory refs
+// that happen before the volatile read to float down below it.
+// (3) Similar a volatile write cannot let unrelated NON-volatile memory refs
+// that happen BEFORE the write float down to after the write.  It's OK for
+// non-volatile memory refs that happen after the volatile write to float up
+// before it.
+//
+// We only put in barriers around volatile refs (they are expensive), not
+// _between_ memory refs (that would require us to track the flavor of the
+// previous memory refs).  Requirements (2) and (3) require some barriers
+// before volatile stores and after volatile loads.  These nearly cover
+// requirement (1) but miss the volatile-store-volatile-load case.  This final
+// case is placed after volatile-stores although it could just as well go
+// before volatile-loads.
+// TODO-AARCH64: consider removing extra unused parameters
+void TemplateTable::volatile_barrier(MacroAssembler::Membar_mask_bits order_constraint,
+                                     Register tmp,
+                                     bool preserve_flags,
+                                     Register load_tgt) {
+#ifdef AARCH64
+  __ membar(order_constraint);
+#else
+  __ membar(order_constraint, tmp, preserve_flags, load_tgt);
+#endif
+}
+
+// Blows all volatile registers: R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR.
+void TemplateTable::resolve_cache_and_index(int byte_no,
+                                            Register Rcache,
+                                            Register Rindex,
+                                            size_t index_size) {
+  assert_different_registers(Rcache, Rindex, Rtemp);
+
+  Label resolved;
+  Bytecodes::Code code = bytecode();
+  switch (code) {
+  case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
+  case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
+  }
+
+  assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
+  __ get_cache_and_index_and_bytecode_at_bcp(Rcache, Rindex, Rtemp, byte_no, 1, index_size);
+  __ cmp(Rtemp, code);  // have we resolved this bytecode?
+  __ b(resolved, eq);
+
+  // resolve first time through
+  address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
+  __ mov(R1, code);
+  __ call_VM(noreg, entry, R1);
+  // Update registers with resolved info
+  __ get_cache_and_index_at_bcp(Rcache, Rindex, 1, index_size);
+  __ bind(resolved);
+}
+
+
+// The Rcache and Rindex registers must be set before call
+void TemplateTable::load_field_cp_cache_entry(Register Rcache,
+                                              Register Rindex,
+                                              Register Roffset,
+                                              Register Rflags,
+                                              Register Robj,
+                                              bool is_static = false) {
+
+  assert_different_registers(Rcache, Rindex, Rtemp);
+  assert_different_registers(Roffset, Rflags, Robj, Rtemp);
+
+  ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+
+  __ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+
+  // Field offset
+  __ ldr(Roffset, Address(Rtemp,
+           cp_base_offset + ConstantPoolCacheEntry::f2_offset()));
+
+  // Flags
+  __ ldr_u32(Rflags, Address(Rtemp,
+           cp_base_offset + ConstantPoolCacheEntry::flags_offset()));
+
+  if (is_static) {
+    __ ldr(Robj, Address(Rtemp,
+             cp_base_offset + ConstantPoolCacheEntry::f1_offset()));
+    const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+    __ ldr(Robj, Address(Robj, mirror_offset));
+  }
+}
+
+
+// Blows all volatile registers: R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR.
+void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
+                                               Register method,
+                                               Register itable_index,
+                                               Register flags,
+                                               bool is_invokevirtual,
+                                               bool is_invokevfinal/*unused*/,
+                                               bool is_invokedynamic) {
+  // setup registers
+  const Register cache = R2_tmp;
+  const Register index = R3_tmp;
+  const Register temp_reg = Rtemp;
+  assert_different_registers(cache, index, temp_reg);
+  assert_different_registers(method, itable_index, temp_reg);
+
+  // determine constant pool cache field offsets
+  assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
+  const int method_offset = in_bytes(
+    ConstantPoolCache::base_offset() +
+      ((byte_no == f2_byte)
+       ? ConstantPoolCacheEntry::f2_offset()
+       : ConstantPoolCacheEntry::f1_offset()
+      )
+    );
+  const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
+                                    ConstantPoolCacheEntry::flags_offset());
+  // access constant pool cache fields
+  const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
+                                    ConstantPoolCacheEntry::f2_offset());
+
+  size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
+  resolve_cache_and_index(byte_no, cache, index, index_size);
+    __ add(temp_reg, cache, AsmOperand(index, lsl, LogBytesPerWord));
+    __ ldr(method, Address(temp_reg, method_offset));
+
+  if (itable_index != noreg) {
+    __ ldr(itable_index, Address(temp_reg, index_offset));
+  }
+  __ ldr_u32(flags, Address(temp_reg, flags_offset));
+}
+
+
+// The registers cache and index expected to be set before call, and should not be Rtemp.
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR,
+// except cache and index registers which are preserved.
+void TemplateTable::jvmti_post_field_access(Register Rcache,
+                                            Register Rindex,
+                                            bool is_static,
+                                            bool has_tos) {
+  assert_different_registers(Rcache, Rindex, Rtemp);
+
+  if (__ can_post_field_access()) {
+    // Check to see if a field access watch has been set before we take
+    // the time to call into the VM.
+
+    Label Lcontinue;
+
+    __ ldr_global_s32(Rtemp, (address)JvmtiExport::get_field_access_count_addr());
+    __ cbz(Rtemp, Lcontinue);
+
+    // cache entry pointer
+    __ add(R2, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+    __ add(R2, R2, in_bytes(ConstantPoolCache::base_offset()));
+    if (is_static) {
+      __ mov(R1, 0);        // NULL object reference
+    } else {
+      __ pop(atos);         // Get the object
+      __ mov(R1, R0_tos);
+      __ verify_oop(R1);
+      __ push(atos);        // Restore stack state
+    }
+    // R1: object pointer or NULL
+    // R2: cache entry pointer
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access),
+               R1, R2);
+    __ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
+
+    __ bind(Lcontinue);
+  }
+}
+
+
+void TemplateTable::pop_and_check_object(Register r) {
+  __ pop_ptr(r);
+  __ null_check(r, Rtemp);  // for field access must check obj.
+  __ verify_oop(r);
+}
+
+
+void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
+  transition(vtos, vtos);
+
+  const Register Roffset  = R2_tmp;
+  const Register Robj     = R3_tmp;
+  const Register Rcache   = R4_tmp;
+  const Register Rflagsav = Rtmp_save0;  // R4/R19
+  const Register Rindex   = R5_tmp;
+  const Register Rflags   = R5_tmp;
+
+  const bool gen_volatile_check = os::is_MP();
+
+  resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
+  jvmti_post_field_access(Rcache, Rindex, is_static, false);
+  load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
+
+  if (gen_volatile_check) {
+    __ mov(Rflagsav, Rflags);
+  }
+
+  if (!is_static) pop_and_check_object(Robj);
+
+  Label Done, Lint, Ltable, shouldNotReachHere;
+  Label Lbtos, Lztos, Lctos, Lstos, Litos, Lltos, Lftos, Ldtos, Latos;
+
+  // compute type
+  __ logical_shift_right(Rflags, Rflags, ConstantPoolCacheEntry::tos_state_shift);
+  // Make sure we don't need to mask flags after the above shift
+  ConstantPoolCacheEntry::verify_tos_state_shift();
+
+  // There are actually two versions of implementation of getfield/getstatic:
+  //
+  // 32-bit ARM:
+  // 1) Table switch using add(PC,...) instruction (fast_version)
+  // 2) Table switch using ldr(PC,...) instruction
+  //
+  // AArch64:
+  // 1) Table switch using adr/add/br instructions (fast_version)
+  // 2) Table switch using adr/ldr/br instructions
+  //
+  // First version requires fixed size of code block for each case and
+  // can not be used in RewriteBytecodes and VerifyOops
+  // modes.
+
+  // Size of fixed size code block for fast_version
+  const int log_max_block_size = 2;
+  const int max_block_size = 1 << log_max_block_size;
+
+  // Decide if fast version is enabled
+  bool fast_version = (is_static || !RewriteBytecodes) && !VerifyOops && !VerifyInterpreterStackTop;
+
+  // On 32-bit ARM atos and itos cases can be merged only for fast version, because
+  // atos requires additional processing in slow version.
+  // On AArch64 atos and itos cannot be merged.
+  bool atos_merged_with_itos = AARCH64_ONLY(false) NOT_AARCH64(fast_version);
+
+  assert(number_of_states == 10, "number of tos states should be equal to 9");
+
+  __ cmp(Rflags, itos);
+#ifdef AARCH64
+  __ b(Lint, eq);
+
+  if(fast_version) {
+    __ adr(Rtemp, Lbtos);
+    __ add(Rtemp, Rtemp, AsmOperand(Rflags, lsl, log_max_block_size + Assembler::LogInstructionSize));
+    __ br(Rtemp);
+  } else {
+    __ adr(Rtemp, Ltable);
+    __ ldr(Rtemp, Address::indexed_ptr(Rtemp, Rflags));
+    __ br(Rtemp);
+  }
+#else
+  if(atos_merged_with_itos) {
+    __ cmp(Rflags, atos, ne);
+  }
+
+  // table switch by type
+  if(fast_version) {
+    __ add(PC, PC, AsmOperand(Rflags, lsl, log_max_block_size + Assembler::LogInstructionSize), ne);
+  } else {
+    __ ldr(PC, Address(PC, Rflags, lsl, LogBytesPerWord), ne);
+  }
+
+  // jump to itos/atos case
+  __ b(Lint);
+#endif // AARCH64
+
+  // table with addresses for slow version
+  if (fast_version) {
+    // nothing to do
+  } else  {
+    AARCH64_ONLY(__ align(wordSize));
+    __ bind(Ltable);
+    __ emit_address(Lbtos);
+    __ emit_address(Lztos);
+    __ emit_address(Lctos);
+    __ emit_address(Lstos);
+    __ emit_address(Litos);
+    __ emit_address(Lltos);
+    __ emit_address(Lftos);
+    __ emit_address(Ldtos);
+    __ emit_address(Latos);
+  }
+
+#ifdef ASSERT
+  int seq = 0;
+#endif
+  // btos
+  {
+    assert(btos == seq++, "btos has unexpected value");
+    FixedSizeCodeBlock btos_block(_masm, max_block_size, fast_version);
+    __ bind(Lbtos);
+    __ ldrsb(R0_tos, Address(Robj, Roffset));
+    __ push(btos);
+    // Rewrite bytecode to be faster
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_bgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // ztos (same as btos for getfield)
+  {
+    assert(ztos == seq++, "btos has unexpected value");
+    FixedSizeCodeBlock ztos_block(_masm, max_block_size, fast_version);
+    __ bind(Lztos);
+    __ ldrsb(R0_tos, Address(Robj, Roffset));
+    __ push(ztos);
+    // Rewrite bytecode to be faster (use btos fast getfield)
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_bgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // ctos
+  {
+    assert(ctos == seq++, "ctos has unexpected value");
+    FixedSizeCodeBlock ctos_block(_masm, max_block_size, fast_version);
+    __ bind(Lctos);
+    __ ldrh(R0_tos, Address(Robj, Roffset));
+    __ push(ctos);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_cgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // stos
+  {
+    assert(stos == seq++, "stos has unexpected value");
+    FixedSizeCodeBlock stos_block(_masm, max_block_size, fast_version);
+    __ bind(Lstos);
+    __ ldrsh(R0_tos, Address(Robj, Roffset));
+    __ push(stos);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_sgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // itos
+  {
+    assert(itos == seq++, "itos has unexpected value");
+    FixedSizeCodeBlock itos_block(_masm, max_block_size, fast_version);
+    __ bind(Litos);
+    __ b(shouldNotReachHere);
+  }
+
+  // ltos
+  {
+    assert(ltos == seq++, "ltos has unexpected value");
+    FixedSizeCodeBlock ltos_block(_masm, max_block_size, fast_version);
+    __ bind(Lltos);
+#ifdef AARCH64
+    __ ldr(R0_tos, Address(Robj, Roffset));
+#else
+    __ add(Roffset, Robj, Roffset);
+    __ ldmia(Roffset, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+    __ push(ltos);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_lgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // ftos
+  {
+    assert(ftos == seq++, "ftos has unexpected value");
+    FixedSizeCodeBlock ftos_block(_masm, max_block_size, fast_version);
+    __ bind(Lftos);
+    // floats and ints are placed on stack in same way, so
+    // we can use push(itos) to transfer value without using VFP
+    __ ldr_u32(R0_tos, Address(Robj, Roffset));
+    __ push(itos);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_fgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // dtos
+  {
+    assert(dtos == seq++, "dtos has unexpected value");
+    FixedSizeCodeBlock dtos_block(_masm, max_block_size, fast_version);
+    __ bind(Ldtos);
+    // doubles and longs are placed on stack in the same way, so
+    // we can use push(ltos) to transfer value without using VFP
+#ifdef AARCH64
+    __ ldr(R0_tos, Address(Robj, Roffset));
+#else
+    __ add(Rtemp, Robj, Roffset);
+    __ ldmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+    __ push(ltos);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_dgetfield, R0_tmp, Rtemp);
+    }
+    __ b(Done);
+  }
+
+  // atos
+  {
+    assert(atos == seq++, "atos has unexpected value");
+
+    // atos case for AArch64 and slow version on 32-bit ARM
+    if(!atos_merged_with_itos) {
+      __ bind(Latos);
+      __ load_heap_oop(R0_tos, Address(Robj, Roffset));
+      __ push(atos);
+      // Rewrite bytecode to be faster
+      if (!is_static && rc == may_rewrite) {
+        patch_bytecode(Bytecodes::_fast_agetfield, R0_tmp, Rtemp);
+      }
+      __ b(Done);
+    }
+  }
+
+  assert(vtos == seq++, "vtos has unexpected value");
+
+  __ bind(shouldNotReachHere);
+  __ should_not_reach_here();
+
+  // itos and atos cases are frequent so it makes sense to move them out of table switch
+  // atos case can be merged with itos case (and thus moved out of table switch) on 32-bit ARM, fast version only
+
+  __ bind(Lint);
+  __ ldr_s32(R0_tos, Address(Robj, Roffset));
+  __ push(itos);
+  // Rewrite bytecode to be faster
+  if (!is_static && rc == may_rewrite) {
+    patch_bytecode(Bytecodes::_fast_igetfield, R0_tmp, Rtemp);
+  }
+
+  __ bind(Done);
+
+  if (gen_volatile_check) {
+    // Check for volatile field
+    Label notVolatile;
+    __ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
+
+    __ bind(notVolatile);
+  }
+
+}
+
+void TemplateTable::getfield(int byte_no) {
+  getfield_or_static(byte_no, false);
+}
+
+void TemplateTable::nofast_getfield(int byte_no) {
+  getfield_or_static(byte_no, false, may_not_rewrite);
+}
+
+void TemplateTable::getstatic(int byte_no) {
+  getfield_or_static(byte_no, true);
+}
+
+
+// The registers cache and index expected to be set before call, and should not be R1 or Rtemp.
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR,
+// except cache and index registers which are preserved.
+void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rindex, bool is_static) {
+  ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+  assert_different_registers(Rcache, Rindex, R1, Rtemp);
+
+  if (__ can_post_field_modification()) {
+    // Check to see if a field modification watch has been set before we take
+    // the time to call into the VM.
+    Label Lcontinue;
+
+    __ ldr_global_s32(Rtemp, (address)JvmtiExport::get_field_modification_count_addr());
+    __ cbz(Rtemp, Lcontinue);
+
+    if (is_static) {
+      // Life is simple.  Null out the object pointer.
+      __ mov(R1, 0);
+    } else {
+      // Life is harder. The stack holds the value on top, followed by the object.
+      // We don't know the size of the value, though; it could be one or two words
+      // depending on its type. As a result, we must find the type to determine where
+      // the object is.
+
+      __ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+      __ ldr_u32(Rtemp, Address(Rtemp, cp_base_offset + ConstantPoolCacheEntry::flags_offset()));
+
+      __ logical_shift_right(Rtemp, Rtemp, ConstantPoolCacheEntry::tos_state_shift);
+      // Make sure we don't need to mask Rtemp after the above shift
+      ConstantPoolCacheEntry::verify_tos_state_shift();
+
+      __ cmp(Rtemp, ltos);
+      __ cond_cmp(Rtemp, dtos, ne);
+#ifdef AARCH64
+      __ mov(Rtemp, Interpreter::expr_offset_in_bytes(2));
+      __ mov(R1, Interpreter::expr_offset_in_bytes(1));
+      __ mov(R1, Rtemp, eq);
+      __ ldr(R1, Address(Rstack_top, R1));
+#else
+      // two word value (ltos/dtos)
+      __ ldr(R1, Address(SP, Interpreter::expr_offset_in_bytes(2)), eq);
+
+      // one word value (not ltos, dtos)
+      __ ldr(R1, Address(SP, Interpreter::expr_offset_in_bytes(1)), ne);
+#endif // AARCH64
+    }
+
+    // cache entry pointer
+    __ add(R2, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+    __ add(R2, R2, in_bytes(cp_base_offset));
+
+    // object (tos)
+    __ mov(R3, Rstack_top);
+
+    // R1: object pointer set up above (NULL if static)
+    // R2: cache entry pointer
+    // R3: value object on the stack
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification),
+               R1, R2, R3);
+    __ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
+
+    __ bind(Lcontinue);
+  }
+}
+
+
+void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
+  transition(vtos, vtos);
+
+  const Register Roffset  = R2_tmp;
+  const Register Robj     = R3_tmp;
+  const Register Rcache   = R4_tmp;
+  const Register Rflagsav = Rtmp_save0;  // R4/R19
+  const Register Rindex   = R5_tmp;
+  const Register Rflags   = R5_tmp;
+
+  const bool gen_volatile_check = os::is_MP();
+
+  resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
+  jvmti_post_field_mod(Rcache, Rindex, is_static);
+  load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
+
+  if (gen_volatile_check) {
+    // Check for volatile field
+    Label notVolatile;
+    __ mov(Rflagsav, Rflags);
+    __ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
+
+    __ bind(notVolatile);
+  }
+
+  Label Done, Lint, shouldNotReachHere;
+  Label Ltable, Lbtos, Lztos, Lctos, Lstos, Litos, Lltos, Lftos, Ldtos, Latos;
+
+  // compute type
+  __ logical_shift_right(Rflags, Rflags, ConstantPoolCacheEntry::tos_state_shift);
+  // Make sure we don't need to mask flags after the above shift
+  ConstantPoolCacheEntry::verify_tos_state_shift();
+
+  // There are actually two versions of implementation of putfield/putstatic:
+  //
+  // 32-bit ARM:
+  // 1) Table switch using add(PC,...) instruction (fast_version)
+  // 2) Table switch using ldr(PC,...) instruction
+  //
+  // AArch64:
+  // 1) Table switch using adr/add/br instructions (fast_version)
+  // 2) Table switch using adr/ldr/br instructions
+  //
+  // First version requires fixed size of code block for each case and
+  // can not be used in RewriteBytecodes and VerifyOops
+  // modes.
+
+  // Size of fixed size code block for fast_version (in instructions)
+  const int log_max_block_size = AARCH64_ONLY(is_static ? 2 : 3) NOT_AARCH64(3);
+  const int max_block_size = 1 << log_max_block_size;
+
+  // Decide if fast version is enabled
+  bool fast_version = (is_static || !RewriteBytecodes) && !VerifyOops && !ZapHighNonSignificantBits;
+
+  assert(number_of_states == 10, "number of tos states should be equal to 9");
+
+  // itos case is frequent and is moved outside table switch
+  __ cmp(Rflags, itos);
+
+#ifdef AARCH64
+  __ b(Lint, eq);
+
+  if (fast_version) {
+    __ adr(Rtemp, Lbtos);
+    __ add(Rtemp, Rtemp, AsmOperand(Rflags, lsl, log_max_block_size + Assembler::LogInstructionSize));
+    __ br(Rtemp);
+  } else {
+    __ adr(Rtemp, Ltable);
+    __ ldr(Rtemp, Address::indexed_ptr(Rtemp, Rflags));
+    __ br(Rtemp);
+  }
+#else
+  // table switch by type
+  if (fast_version) {
+    __ add(PC, PC, AsmOperand(Rflags, lsl, log_max_block_size + Assembler::LogInstructionSize), ne);
+  } else  {
+    __ ldr(PC, Address(PC, Rflags, lsl, LogBytesPerWord), ne);
+  }
+
+  // jump to itos case
+  __ b(Lint);
+#endif // AARCH64
+
+  // table with addresses for slow version
+  if (fast_version) {
+    // nothing to do
+  } else  {
+    AARCH64_ONLY(__ align(wordSize));
+    __ bind(Ltable);
+    __ emit_address(Lbtos);
+    __ emit_address(Lztos);
+    __ emit_address(Lctos);
+    __ emit_address(Lstos);
+    __ emit_address(Litos);
+    __ emit_address(Lltos);
+    __ emit_address(Lftos);
+    __ emit_address(Ldtos);
+    __ emit_address(Latos);
+  }
+
+#ifdef ASSERT
+  int seq = 0;
+#endif
+  // btos
+  {
+    assert(btos == seq++, "btos has unexpected value");
+    FixedSizeCodeBlock btos_block(_masm, max_block_size, fast_version);
+    __ bind(Lbtos);
+    __ pop(btos);
+    if (!is_static) pop_and_check_object(Robj);
+    __ strb(R0_tos, Address(Robj, Roffset));
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_bputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // ztos
+  {
+    assert(ztos == seq++, "ztos has unexpected value");
+    FixedSizeCodeBlock ztos_block(_masm, max_block_size, fast_version);
+    __ bind(Lztos);
+    __ pop(ztos);
+    if (!is_static) pop_and_check_object(Robj);
+    __ and_32(R0_tos, R0_tos, 1);
+    __ strb(R0_tos, Address(Robj, Roffset));
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_zputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // ctos
+  {
+    assert(ctos == seq++, "ctos has unexpected value");
+    FixedSizeCodeBlock ctos_block(_masm, max_block_size, fast_version);
+    __ bind(Lctos);
+    __ pop(ctos);
+    if (!is_static) pop_and_check_object(Robj);
+    __ strh(R0_tos, Address(Robj, Roffset));
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_cputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // stos
+  {
+    assert(stos == seq++, "stos has unexpected value");
+    FixedSizeCodeBlock stos_block(_masm, max_block_size, fast_version);
+    __ bind(Lstos);
+    __ pop(stos);
+    if (!is_static) pop_and_check_object(Robj);
+    __ strh(R0_tos, Address(Robj, Roffset));
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_sputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // itos
+  {
+    assert(itos == seq++, "itos has unexpected value");
+    FixedSizeCodeBlock itos_block(_masm, max_block_size, fast_version);
+    __ bind(Litos);
+    __ b(shouldNotReachHere);
+  }
+
+  // ltos
+  {
+    assert(ltos == seq++, "ltos has unexpected value");
+    FixedSizeCodeBlock ltos_block(_masm, max_block_size, fast_version);
+    __ bind(Lltos);
+    __ pop(ltos);
+    if (!is_static) pop_and_check_object(Robj);
+#ifdef AARCH64
+    __ str(R0_tos, Address(Robj, Roffset));
+#else
+    __ add(Roffset, Robj, Roffset);
+    __ stmia(Roffset, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_lputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // ftos
+  {
+    assert(ftos == seq++, "ftos has unexpected value");
+    FixedSizeCodeBlock ftos_block(_masm, max_block_size, fast_version);
+    __ bind(Lftos);
+    // floats and ints are placed on stack in the same way, so
+    // we can use pop(itos) to transfer value without using VFP
+    __ pop(itos);
+    if (!is_static) pop_and_check_object(Robj);
+    __ str_32(R0_tos, Address(Robj, Roffset));
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_fputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // dtos
+  {
+    assert(dtos == seq++, "dtos has unexpected value");
+    FixedSizeCodeBlock dtos_block(_masm, max_block_size, fast_version);
+    __ bind(Ldtos);
+    // doubles and longs are placed on stack in the same way, so
+    // we can use pop(ltos) to transfer value without using VFP
+    __ pop(ltos);
+    if (!is_static) pop_and_check_object(Robj);
+#ifdef AARCH64
+    __ str(R0_tos, Address(Robj, Roffset));
+#else
+    __ add(Rtemp, Robj, Roffset);
+    __ stmia(Rtemp, RegisterSet(R0_tos_lo, R1_tos_hi));
+#endif // AARCH64
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_dputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  // atos
+  {
+    assert(atos == seq++, "dtos has unexpected value");
+    __ bind(Latos);
+    __ pop(atos);
+    if (!is_static) pop_and_check_object(Robj);
+    // Store into the field
+    do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R5_tmp, _bs->kind(), false, false);
+    if (!is_static && rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_aputfield, R0_tmp, Rtemp, true, byte_no);
+    }
+    __ b(Done);
+  }
+
+  __ bind(shouldNotReachHere);
+  __ should_not_reach_here();
+
+  // itos case is frequent and is moved outside table switch
+  __ bind(Lint);
+  __ pop(itos);
+  if (!is_static) pop_and_check_object(Robj);
+  __ str_32(R0_tos, Address(Robj, Roffset));
+  if (!is_static && rc == may_rewrite) {
+    patch_bytecode(Bytecodes::_fast_iputfield, R0_tmp, Rtemp, true, byte_no);
+  }
+
+  __ bind(Done);
+
+  if (gen_volatile_check) {
+    Label notVolatile;
+    if (is_static) {
+      // Just check for volatile. Memory barrier for static final field
+      // is handled by class initialization.
+      __ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+      volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
+      __ bind(notVolatile);
+    } else {
+      // Check for volatile field and final field
+      Label skipMembar;
+
+      __ tst(Rflagsav, 1 << ConstantPoolCacheEntry::is_volatile_shift |
+                       1 << ConstantPoolCacheEntry::is_final_shift);
+      __ b(skipMembar, eq);
+
+      __ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+      // StoreLoad barrier after volatile field write
+      volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
+      __ b(skipMembar);
+
+      // StoreStore barrier after final field write
+      __ bind(notVolatile);
+      volatile_barrier(MacroAssembler::StoreStore, Rtemp);
+
+      __ bind(skipMembar);
+    }
+  }
+
+}
+
+void TemplateTable::putfield(int byte_no) {
+  putfield_or_static(byte_no, false);
+}
+
+void TemplateTable::nofast_putfield(int byte_no) {
+  putfield_or_static(byte_no, false, may_not_rewrite);
+}
+
+void TemplateTable::putstatic(int byte_no) {
+  putfield_or_static(byte_no, true);
+}
+
+
+void TemplateTable::jvmti_post_fast_field_mod() {
+  // This version of jvmti_post_fast_field_mod() is not used on ARM
+  Unimplemented();
+}
+
+// Blows volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64), Rtemp, LR,
+// but preserves tosca with the given state.
+void TemplateTable::jvmti_post_fast_field_mod(TosState state) {
+  if (__ can_post_field_modification()) {
+    // Check to see if a field modification watch has been set before we take
+    // the time to call into the VM.
+    Label done;
+
+    __ ldr_global_s32(R2, (address)JvmtiExport::get_field_modification_count_addr());
+    __ cbz(R2, done);
+
+    __ pop_ptr(R3);               // copy the object pointer from tos
+    __ verify_oop(R3);
+    __ push_ptr(R3);              // put the object pointer back on tos
+
+    __ push(state);               // save value on the stack
+
+    // access constant pool cache entry
+    __ get_cache_entry_pointer_at_bcp(R2, R1, 1);
+
+    __ mov(R1, R3);
+    assert(Interpreter::expr_offset_in_bytes(0) == 0, "adjust this code");
+    __ mov(R3, Rstack_top); // put tos addr into R3
+
+    // R1: object pointer copied above
+    // R2: cache entry pointer
+    // R3: jvalue object on the stack
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), R1, R2, R3);
+
+    __ pop(state);                // restore value
+
+    __ bind(done);
+  }
+}
+
+
+void TemplateTable::fast_storefield(TosState state) {
+  transition(state, vtos);
+
+  ByteSize base = ConstantPoolCache::base_offset();
+
+  jvmti_post_fast_field_mod(state);
+
+  const Register Rcache  = R2_tmp;
+  const Register Rindex  = R3_tmp;
+  const Register Roffset = R3_tmp;
+  const Register Rflags  = Rtmp_save0; // R4/R19
+  const Register Robj    = R5_tmp;
+
+  const bool gen_volatile_check = os::is_MP();
+
+  // access constant pool cache
+  __ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
+
+  __ add(Rcache, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+
+  if (gen_volatile_check) {
+    // load flags to test volatile
+    __ ldr_u32(Rflags, Address(Rcache, base + ConstantPoolCacheEntry::flags_offset()));
+  }
+
+  // replace index with field offset from cache entry
+  __ ldr(Roffset, Address(Rcache, base + ConstantPoolCacheEntry::f2_offset()));
+
+  if (gen_volatile_check) {
+    // Check for volatile store
+    Label notVolatile;
+    __ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    // TODO-AARCH64 on AArch64, store-release instructions can be used to get rid of this explict barrier
+    volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
+
+    __ bind(notVolatile);
+  }
+
+  // Get object from stack
+  pop_and_check_object(Robj);
+
+  // access field
+  switch (bytecode()) {
+    case Bytecodes::_fast_zputfield: __ and_32(R0_tos, R0_tos, 1);
+                                     // fall through
+    case Bytecodes::_fast_bputfield: __ strb(R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_sputfield: // fall through
+    case Bytecodes::_fast_cputfield: __ strh(R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_iputfield: __ str_32(R0_tos, Address(Robj, Roffset)); break;
+#ifdef AARCH64
+    case Bytecodes::_fast_lputfield: __ str  (R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_fputfield: __ str_s(S0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_dputfield: __ str_d(D0_tos, Address(Robj, Roffset)); break;
+#else
+    case Bytecodes::_fast_lputfield: __ add(Robj, Robj, Roffset);
+                                     __ stmia(Robj, RegisterSet(R0_tos_lo, R1_tos_hi)); break;
+
+#ifdef __SOFTFP__
+    case Bytecodes::_fast_fputfield: __ str(R0_tos, Address(Robj, Roffset));  break;
+    case Bytecodes::_fast_dputfield: __ add(Robj, Robj, Roffset);
+                                     __ stmia(Robj, RegisterSet(R0_tos_lo, R1_tos_hi)); break;
+#else
+    case Bytecodes::_fast_fputfield: __ add(Robj, Robj, Roffset);
+                                     __ fsts(S0_tos, Address(Robj));          break;
+    case Bytecodes::_fast_dputfield: __ add(Robj, Robj, Roffset);
+                                     __ fstd(D0_tos, Address(Robj));          break;
+#endif // __SOFTFP__
+#endif // AARCH64
+
+    case Bytecodes::_fast_aputfield:
+      do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R2_tmp, _bs->kind(), false, false);
+      break;
+
+    default:
+      ShouldNotReachHere();
+  }
+
+  if (gen_volatile_check) {
+    Label notVolatile;
+    Label skipMembar;
+    __ tst(Rflags, 1 << ConstantPoolCacheEntry::is_volatile_shift |
+                   1 << ConstantPoolCacheEntry::is_final_shift);
+    __ b(skipMembar, eq);
+
+    __ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    // StoreLoad barrier after volatile field write
+    volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
+    __ b(skipMembar);
+
+    // StoreStore barrier after final field write
+    __ bind(notVolatile);
+    volatile_barrier(MacroAssembler::StoreStore, Rtemp);
+
+    __ bind(skipMembar);
+  }
+}
+
+
+void TemplateTable::fast_accessfield(TosState state) {
+  transition(atos, state);
+
+  // do the JVMTI work here to avoid disturbing the register state below
+  if (__ can_post_field_access()) {
+    // Check to see if a field access watch has been set before we take
+    // the time to call into the VM.
+    Label done;
+    __ ldr_global_s32(R2, (address) JvmtiExport::get_field_access_count_addr());
+    __ cbz(R2, done);
+    // access constant pool cache entry
+    __ get_cache_entry_pointer_at_bcp(R2, R1, 1);
+    __ push_ptr(R0_tos);  // save object pointer before call_VM() clobbers it
+    __ verify_oop(R0_tos);
+    __ mov(R1, R0_tos);
+    // R1: object pointer copied above
+    // R2: cache entry pointer
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), R1, R2);
+    __ pop_ptr(R0_tos);   // restore object pointer
+
+    __ bind(done);
+  }
+
+  const Register Robj    = R0_tos;
+  const Register Rcache  = R2_tmp;
+  const Register Rflags  = R2_tmp;
+  const Register Rindex  = R3_tmp;
+  const Register Roffset = R3_tmp;
+
+  const bool gen_volatile_check = os::is_MP();
+
+  // access constant pool cache
+  __ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
+  // replace index with field offset from cache entry
+  __ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
+
+  if (gen_volatile_check) {
+    // load flags to test volatile
+    __ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
+  }
+
+  __ verify_oop(Robj);
+  __ null_check(Robj, Rtemp);
+
+  // access field
+  switch (bytecode()) {
+    case Bytecodes::_fast_bgetfield: __ ldrsb(R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_sgetfield: __ ldrsh(R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_cgetfield: __ ldrh (R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_igetfield: __ ldr_s32(R0_tos, Address(Robj, Roffset)); break;
+#ifdef AARCH64
+    case Bytecodes::_fast_lgetfield: __ ldr  (R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_fgetfield: __ ldr_s(S0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_dgetfield: __ ldr_d(D0_tos, Address(Robj, Roffset)); break;
+#else
+    case Bytecodes::_fast_lgetfield: __ add(Roffset, Robj, Roffset);
+                                     __ ldmia(Roffset, RegisterSet(R0_tos_lo, R1_tos_hi)); break;
+#ifdef __SOFTFP__
+    case Bytecodes::_fast_fgetfield: __ ldr  (R0_tos, Address(Robj, Roffset)); break;
+    case Bytecodes::_fast_dgetfield: __ add(Roffset, Robj, Roffset);
+                                     __ ldmia(Roffset, RegisterSet(R0_tos_lo, R1_tos_hi)); break;
+#else
+    case Bytecodes::_fast_fgetfield: __ add(Roffset, Robj, Roffset); __ flds(S0_tos, Address(Roffset)); break;
+    case Bytecodes::_fast_dgetfield: __ add(Roffset, Robj, Roffset); __ fldd(D0_tos, Address(Roffset)); break;
+#endif // __SOFTFP__
+#endif // AARCH64
+    case Bytecodes::_fast_agetfield: __ load_heap_oop(R0_tos, Address(Robj, Roffset)); __ verify_oop(R0_tos); break;
+    default:
+      ShouldNotReachHere();
+  }
+
+  if (gen_volatile_check) {
+    // Check for volatile load
+    Label notVolatile;
+    __ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    // TODO-AARCH64 on AArch64, load-acquire instructions can be used to get rid of this explict barrier
+    volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
+
+    __ bind(notVolatile);
+  }
+}
+
+
+void TemplateTable::fast_xaccess(TosState state) {
+  transition(vtos, state);
+
+  const Register Robj = R1_tmp;
+  const Register Rcache = R2_tmp;
+  const Register Rindex = R3_tmp;
+  const Register Roffset = R3_tmp;
+  const Register Rflags = R4_tmp;
+  Label done;
+
+  // get receiver
+  __ ldr(Robj, aaddress(0));
+
+  // access constant pool cache
+  __ get_cache_and_index_at_bcp(Rcache, Rindex, 2);
+  __ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
+
+  const bool gen_volatile_check = os::is_MP();
+
+  if (gen_volatile_check) {
+    // load flags to test volatile
+    __ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
+  }
+
+  // make sure exception is reported in correct bcp range (getfield is next instruction)
+  __ add(Rbcp, Rbcp, 1);
+  __ null_check(Robj, Rtemp);
+  __ sub(Rbcp, Rbcp, 1);
+
+#ifdef AARCH64
+  if (gen_volatile_check) {
+    Label notVolatile;
+    __ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    __ add(Rtemp, Robj, Roffset);
+
+    if (state == itos) {
+      __ ldar_w(R0_tos, Rtemp);
+    } else if (state == atos) {
+      if (UseCompressedOops) {
+        __ ldar_w(R0_tos, Rtemp);
+        __ decode_heap_oop(R0_tos);
+      } else {
+        __ ldar(R0_tos, Rtemp);
+      }
+      __ verify_oop(R0_tos);
+    } else if (state == ftos) {
+      __ ldar_w(R0_tos, Rtemp);
+      __ fmov_sw(S0_tos, R0_tos);
+    } else {
+      ShouldNotReachHere();
+    }
+    __ b(done);
+
+    __ bind(notVolatile);
+  }
+#endif // AARCH64
+
+  if (state == itos) {
+    __ ldr_s32(R0_tos, Address(Robj, Roffset));
+  } else if (state == atos) {
+    __ load_heap_oop(R0_tos, Address(Robj, Roffset));
+    __ verify_oop(R0_tos);
+  } else if (state == ftos) {
+#ifdef AARCH64
+    __ ldr_s(S0_tos, Address(Robj, Roffset));
+#else
+#ifdef __SOFTFP__
+    __ ldr(R0_tos, Address(Robj, Roffset));
+#else
+    __ add(Roffset, Robj, Roffset);
+    __ flds(S0_tos, Address(Roffset));
+#endif // __SOFTFP__
+#endif // AARCH64
+  } else {
+    ShouldNotReachHere();
+  }
+
+#ifndef AARCH64
+  if (gen_volatile_check) {
+    // Check for volatile load
+    Label notVolatile;
+    __ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
+
+    volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
+
+    __ bind(notVolatile);
+  }
+#endif // !AARCH64
+
+  __ bind(done);
+}
+
+
+
+//----------------------------------------------------------------------------------------------------
+// Calls
+
+void TemplateTable::count_calls(Register method, Register temp) {
+  // implemented elsewhere
+  ShouldNotReachHere();
+}
+
+
+void TemplateTable::prepare_invoke(int byte_no,
+                                   Register method,  // linked method (or i-klass)
+                                   Register index,   // itable index, MethodType, etc.
+                                   Register recv,    // if caller wants to see it
+                                   Register flags    // if caller wants to test it
+                                   ) {
+  // determine flags
+  const Bytecodes::Code code = bytecode();
+  const bool is_invokeinterface  = code == Bytecodes::_invokeinterface;
+  const bool is_invokedynamic    = code == Bytecodes::_invokedynamic;
+  const bool is_invokehandle     = code == Bytecodes::_invokehandle;
+  const bool is_invokevirtual    = code == Bytecodes::_invokevirtual;
+  const bool is_invokespecial    = code == Bytecodes::_invokespecial;
+  const bool load_receiver       = (recv != noreg);
+  assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
+  assert(recv  == noreg || recv  == R2, "");
+  assert(flags == noreg || flags == R3, "");
+
+  // setup registers & access constant pool cache
+  if (recv  == noreg)  recv  = R2;
+  if (flags == noreg)  flags = R3;
+  const Register temp = Rtemp;
+  const Register ret_type = R1_tmp;
+  assert_different_registers(method, index, flags, recv, LR, ret_type, temp);
+
+  // save 'interpreter return address'
+  __ save_bcp();
+
+  load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
+
+  // maybe push extra argument
+  if (is_invokedynamic || is_invokehandle) {
+    Label L_no_push;
+    __ tbz(flags, ConstantPoolCacheEntry::has_appendix_shift, L_no_push);
+    __ mov(temp, index);
+    assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0");
+    __ load_resolved_reference_at_index(index, temp);
+    __ verify_oop(index);
+    __ push_ptr(index);  // push appendix (MethodType, CallSite, etc.)
+    __ bind(L_no_push);
+  }
+
+  // load receiver if needed (after extra argument is pushed so parameter size is correct)
+  if (load_receiver) {
+    __ andr(temp, flags, (uintx)ConstantPoolCacheEntry::parameter_size_mask);  // get parameter size
+    Address recv_addr = __ receiver_argument_address(Rstack_top, temp, recv);
+    __ ldr(recv, recv_addr);
+    __ verify_oop(recv);
+  }
+
+  // compute return type
+  __ logical_shift_right(ret_type, flags, ConstantPoolCacheEntry::tos_state_shift);
+  // Make sure we don't need to mask flags after the above shift
+  ConstantPoolCacheEntry::verify_tos_state_shift();
+  // load return address
+  { const address table = (address) Interpreter::invoke_return_entry_table_for(code);
+    __ mov_slow(temp, table);
+    __ ldr(LR, Address::indexed_ptr(temp, ret_type));
+  }
+}
+
+
+void TemplateTable::invokevirtual_helper(Register index,
+                                         Register recv,
+                                         Register flags) {
+
+  const Register recv_klass = R2_tmp;
+
+  assert_different_registers(index, recv, flags, Rtemp);
+  assert_different_registers(index, recv_klass, R0_tmp, Rtemp);
+
+  // Test for an invoke of a final method
+  Label notFinal;
+  __ tbz(flags, ConstantPoolCacheEntry::is_vfinal_shift, notFinal);
+
+  assert(index == Rmethod, "Method* must be Rmethod, for interpreter calling convention");
+
+  // do the call - the index is actually the method to call
+
+  // It's final, need a null check here!
+  __ null_check(recv, Rtemp);
+
+  // profile this call
+  __ profile_final_call(R0_tmp);
+
+  __ jump_from_interpreted(Rmethod);
+
+  __ bind(notFinal);
+
+  // get receiver klass
+  __ null_check(recv, Rtemp, oopDesc::klass_offset_in_bytes());
+  __ load_klass(recv_klass, recv);
+
+  // profile this call
+  __ profile_virtual_call(R0_tmp, recv_klass);
+
+  // get target Method* & entry point
+  const int base = in_bytes(Klass::vtable_start_offset());
+  assert(vtableEntry::size() == 1, "adjust the scaling in the code below");
+  __ add(Rtemp, recv_klass, AsmOperand(index, lsl, LogHeapWordSize));
+  __ ldr(Rmethod, Address(Rtemp, base + vtableEntry::method_offset_in_bytes()));
+  __ jump_from_interpreted(Rmethod);
+}
+
+void TemplateTable::invokevirtual(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f2_byte, "use this argument");
+
+  const Register Rrecv  = R2_tmp;
+  const Register Rflags = R3_tmp;
+
+  prepare_invoke(byte_no, Rmethod, noreg, Rrecv, Rflags);
+
+  // Rmethod: index
+  // Rrecv:   receiver
+  // Rflags:  flags
+  // LR:      return address
+
+  invokevirtual_helper(Rmethod, Rrecv, Rflags);
+}
+
+
+void TemplateTable::invokespecial(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f1_byte, "use this argument");
+  const Register Rrecv  = R2_tmp;
+  prepare_invoke(byte_no, Rmethod, noreg, Rrecv);
+  __ verify_oop(Rrecv);
+  __ null_check(Rrecv, Rtemp);
+  // do the call
+  __ profile_call(Rrecv);
+  __ jump_from_interpreted(Rmethod);
+}
+
+
+void TemplateTable::invokestatic(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f1_byte, "use this argument");
+  prepare_invoke(byte_no, Rmethod);
+  // do the call
+  __ profile_call(R2_tmp);
+  __ jump_from_interpreted(Rmethod);
+}
+
+
+void TemplateTable::fast_invokevfinal(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f2_byte, "use this argument");
+  __ stop("fast_invokevfinal is not used on ARM");
+}
+
+
+void TemplateTable::invokeinterface(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f1_byte, "use this argument");
+
+  const Register Ritable = R1_tmp;
+  const Register Rrecv   = R2_tmp;
+  const Register Rinterf = R5_tmp;
+  const Register Rindex  = R4_tmp;
+  const Register Rflags  = R3_tmp;
+  const Register Rklass  = R3_tmp;
+
+  prepare_invoke(byte_no, Rinterf, Rindex, Rrecv, Rflags);
+
+  // Special case of invokeinterface called for virtual method of
+  // java.lang.Object.  See cpCacheOop.cpp for details.
+  // This code isn't produced by javac, but could be produced by
+  // another compliant java compiler.
+  Label notMethod;
+  __ tbz(Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift, notMethod);
+
+  __ mov(Rmethod, Rindex);
+  invokevirtual_helper(Rmethod, Rrecv, Rflags);
+  __ bind(notMethod);
+
+  // Get receiver klass into Rklass - also a null check
+  __ load_klass(Rklass, Rrecv);
+
+  // profile this call
+  __ profile_virtual_call(R0_tmp, Rklass);
+
+  // Compute start of first itableOffsetEntry (which is at the end of the vtable)
+  const int base = in_bytes(Klass::vtable_start_offset());
+  assert(vtableEntry::size() == 1, "adjust the scaling in the code below");
+  __ ldr_s32(Rtemp, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable
+  __ add(Ritable, Rklass, base);
+  __ add(Ritable, Ritable, AsmOperand(Rtemp, lsl, LogBytesPerWord));
+
+  Label entry, search, interface_ok;
+
+  __ b(entry);
+
+  __ bind(search);
+  __ add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize);
+
+  __ bind(entry);
+
+  // Check that the entry is non-null.  A null entry means that the receiver
+  // class doesn't implement the interface, and wasn't the same as the
+  // receiver class checked when the interface was resolved.
+
+  __ ldr(Rtemp, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes()));
+  __ cbnz(Rtemp, interface_ok);
+
+  // throw exception
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address,
+                   InterpreterRuntime::throw_IncompatibleClassChangeError));
+
+  // the call_VM checks for exception, so we should never return here.
+  __ should_not_reach_here();
+
+  __ bind(interface_ok);
+
+  __ cmp(Rinterf, Rtemp);
+  __ b(search, ne);
+
+  __ ldr_s32(Rtemp, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes()));
+  __ add(Rtemp, Rtemp, Rklass); // Add offset to Klass*
+  assert(itableMethodEntry::size() == 1, "adjust the scaling in the code below");
+
+  __ ldr(Rmethod, Address::indexed_ptr(Rtemp, Rindex));
+
+  // Rmethod: Method* to call
+
+  // Check for abstract method error
+  // Note: This should be done more efficiently via a throw_abstract_method_error
+  //       interpreter entry point and a conditional jump to it in case of a null
+  //       method.
+  { Label L;
+    __ cbnz(Rmethod, L);
+    // throw exception
+    // note: must restore interpreter registers to canonical
+    //       state for exception handling to work correctly!
+    __ restore_method();
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
+    // the call_VM checks for exception, so we should never return here.
+    __ should_not_reach_here();
+    __ bind(L);
+  }
+
+  // do the call
+  __ jump_from_interpreted(Rmethod);
+}
+
+void TemplateTable::invokehandle(int byte_no) {
+  transition(vtos, vtos);
+
+  // TODO-AARCH64 review register usage
+  const Register Rrecv  = R2_tmp;
+  const Register Rmtype = R4_tmp;
+  const Register R5_method = R5_tmp;  // can't reuse Rmethod!
+
+  prepare_invoke(byte_no, R5_method, Rmtype, Rrecv);
+  __ null_check(Rrecv, Rtemp);
+
+  // Rmtype:  MethodType object (from cpool->resolved_references[f1], if necessary)
+  // Rmethod: MH.invokeExact_MT method (from f2)
+
+  // Note:  Rmtype is already pushed (if necessary) by prepare_invoke
+
+  // do the call
+  __ profile_final_call(R3_tmp);  // FIXME: profile the LambdaForm also
+  __ mov(Rmethod, R5_method);
+  __ jump_from_interpreted(Rmethod);
+}
+
+void TemplateTable::invokedynamic(int byte_no) {
+  transition(vtos, vtos);
+
+  // TODO-AARCH64 review register usage
+  const Register Rcallsite = R4_tmp;
+  const Register R5_method = R5_tmp;  // can't reuse Rmethod!
+
+  prepare_invoke(byte_no, R5_method, Rcallsite);
+
+  // Rcallsite: CallSite object (from cpool->resolved_references[f1])
+  // Rmethod:   MH.linkToCallSite method (from f2)
+
+  // Note:  Rcallsite is already pushed by prepare_invoke
+
+  if (ProfileInterpreter) {
+    __ profile_call(R2_tmp);
+  }
+
+  // do the call
+  __ mov(Rmethod, R5_method);
+  __ jump_from_interpreted(Rmethod);
+}
+
+//----------------------------------------------------------------------------------------------------
+// Allocation
+
+void TemplateTable::_new() {
+  transition(vtos, atos);
+
+  const Register Robj   = R0_tos;
+  const Register Rcpool = R1_tmp;
+  const Register Rindex = R2_tmp;
+  const Register Rtags  = R3_tmp;
+  const Register Rsize  = R3_tmp;
+
+  Register Rklass = R4_tmp;
+  assert_different_registers(Rcpool, Rindex, Rtags, Rklass, Rtemp);
+  assert_different_registers(Rcpool, Rindex, Rklass, Rsize);
+
+  Label slow_case;
+  Label done;
+  Label initialize_header;
+  Label initialize_object;  // including clearing the fields
+  Label allocate_shared;
+
+  const bool allow_shared_alloc =
+    Universe::heap()->supports_inline_contig_alloc();
+
+  // Literals
+  InlinedAddress Lheap_top_addr(allow_shared_alloc ? (address)Universe::heap()->top_addr() : NULL);
+
+  __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+  __ get_cpool_and_tags(Rcpool, Rtags);
+
+  // Make sure the class we're about to instantiate has been resolved.
+  // This is done before loading InstanceKlass to be consistent with the order
+  // how Constant Pool is updated (see ConstantPool::klass_at_put)
+  const int tags_offset = Array<u1>::base_offset_in_bytes();
+  __ add(Rtemp, Rtags, Rindex);
+
+#ifdef AARCH64
+  __ add(Rtemp, Rtemp, tags_offset);
+  __ ldarb(Rtemp, Rtemp);
+#else
+  __ ldrb(Rtemp, Address(Rtemp, tags_offset));
+
+  // use Rklass as a scratch
+  volatile_barrier(MacroAssembler::LoadLoad, Rklass);
+#endif // AARCH64
+
+  // get InstanceKlass
+  __ add(Rklass, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr(Rklass, Address(Rklass, sizeof(ConstantPool)));
+  __ cmp(Rtemp, JVM_CONSTANT_Class);
+  __ b(slow_case, ne);
+
+  // make sure klass is initialized & doesn't have finalizer
+  // make sure klass is fully initialized
+  __ ldrb(Rtemp, Address(Rklass, InstanceKlass::init_state_offset()));
+  __ cmp(Rtemp, InstanceKlass::fully_initialized);
+  __ b(slow_case, ne);
+
+  // get instance_size in InstanceKlass (scaled to a count of bytes)
+  __ ldr_u32(Rsize, Address(Rklass, Klass::layout_helper_offset()));
+
+  // test to see if it has a finalizer or is malformed in some way
+  // Klass::_lh_instance_slow_path_bit is really a bit mask, not bit number
+  __ tbnz(Rsize, exact_log2(Klass::_lh_instance_slow_path_bit), slow_case);
+
+  //
+  // Allocate the instance
+  // 1) Try to allocate in the TLAB
+  // 2) if fail and the object is large allocate in the shared Eden
+  // 3) if the above fails (or is not applicable), go to a slow case
+  // (creates a new TLAB, etc.)
+
+  if (UseTLAB) {
+    const Register Rtlab_top = R1_tmp;
+    const Register Rtlab_end = R2_tmp;
+    assert_different_registers(Robj, Rsize, Rklass, Rtlab_top, Rtlab_end);
+
+    __ ldr(Robj, Address(Rthread, JavaThread::tlab_top_offset()));
+    __ ldr(Rtlab_end, Address(Rthread, in_bytes(JavaThread::tlab_end_offset())));
+    __ add(Rtlab_top, Robj, Rsize);
+    __ cmp(Rtlab_top, Rtlab_end);
+    __ b(allow_shared_alloc ? allocate_shared : slow_case, hi);
+    __ str(Rtlab_top, Address(Rthread, JavaThread::tlab_top_offset()));
+    if (ZeroTLAB) {
+      // the fields have been already cleared
+      __ b(initialize_header);
+    } else {
+      // initialize both the header and fields
+      __ b(initialize_object);
+    }
+  }
+
+  // Allocation in the shared Eden, if allowed.
+  if (allow_shared_alloc) {
+    __ bind(allocate_shared);
+
+    const Register Rheap_top_addr = R2_tmp;
+    const Register Rheap_top = R5_tmp;
+    const Register Rheap_end = Rtemp;
+    assert_different_registers(Robj, Rklass, Rsize, Rheap_top_addr, Rheap_top, Rheap_end, LR);
+
+    // heap_end now (re)loaded in the loop since also used as a scratch register in the CAS
+    __ ldr_literal(Rheap_top_addr, Lheap_top_addr);
+
+    Label retry;
+    __ bind(retry);
+
+#ifdef AARCH64
+    __ ldxr(Robj, Rheap_top_addr);
+#else
+    __ ldr(Robj, Address(Rheap_top_addr));
+#endif // AARCH64
+
+    __ ldr(Rheap_end, Address(Rheap_top_addr, (intptr_t)Universe::heap()->end_addr()-(intptr_t)Universe::heap()->top_addr()));
+    __ add(Rheap_top, Robj, Rsize);
+    __ cmp(Rheap_top, Rheap_end);
+    __ b(slow_case, hi);
+
+    // Update heap top atomically.
+    // If someone beats us on the allocation, try again, otherwise continue.
+#ifdef AARCH64
+    __ stxr(Rtemp2, Rheap_top, Rheap_top_addr);
+    __ cbnz_w(Rtemp2, retry);
+#else
+    __ atomic_cas_bool(Robj, Rheap_top, Rheap_top_addr, 0, Rheap_end/*scratched*/);
+    __ b(retry, ne);
+#endif // AARCH64
+
+    __ incr_allocated_bytes(Rsize, Rtemp);
+  }
+
+  if (UseTLAB || allow_shared_alloc) {
+    const Register Rzero0 = R1_tmp;
+    const Register Rzero1 = R2_tmp;
+    const Register Rzero_end = R5_tmp;
+    const Register Rzero_cur = Rtemp;
+    assert_different_registers(Robj, Rsize, Rklass, Rzero0, Rzero1, Rzero_cur, Rzero_end);
+
+    // The object is initialized before the header.  If the object size is
+    // zero, go directly to the header initialization.
+    __ bind(initialize_object);
+    __ subs(Rsize, Rsize, sizeof(oopDesc));
+    __ add(Rzero_cur, Robj, sizeof(oopDesc));
+    __ b(initialize_header, eq);
+
+#ifdef ASSERT
+    // make sure Rsize is a multiple of 8
+    Label L;
+    __ tst(Rsize, 0x07);
+    __ b(L, eq);
+    __ stop("object size is not multiple of 8 - adjust this code");
+    __ bind(L);
+#endif
+
+#ifdef AARCH64
+    {
+      Label loop;
+      // Step back by 1 word if object size is not a multiple of 2*wordSize.
+      assert(wordSize <= sizeof(oopDesc), "oop header should contain at least one word");
+      __ andr(Rtemp2, Rsize, (uintx)wordSize);
+      __ sub(Rzero_cur, Rzero_cur, Rtemp2);
+
+      // Zero by 2 words per iteration.
+      __ bind(loop);
+      __ subs(Rsize, Rsize, 2*wordSize);
+      __ stp(ZR, ZR, Address(Rzero_cur, 2*wordSize, post_indexed));
+      __ b(loop, gt);
+    }
+#else
+    __ mov(Rzero0, 0);
+    __ mov(Rzero1, 0);
+    __ add(Rzero_end, Rzero_cur, Rsize);
+
+    // initialize remaining object fields: Rsize was a multiple of 8
+    { Label loop;
+      // loop is unrolled 2 times
+      __ bind(loop);
+      // #1
+      __ stmia(Rzero_cur, RegisterSet(Rzero0) | RegisterSet(Rzero1), writeback);
+      __ cmp(Rzero_cur, Rzero_end);
+      // #2
+      __ stmia(Rzero_cur, RegisterSet(Rzero0) | RegisterSet(Rzero1), writeback, ne);
+      __ cmp(Rzero_cur, Rzero_end, ne);
+      __ b(loop, ne);
+    }
+#endif // AARCH64
+
+    // initialize object header only.
+    __ bind(initialize_header);
+    if (UseBiasedLocking) {
+      __ ldr(Rtemp, Address(Rklass, Klass::prototype_header_offset()));
+    } else {
+      __ mov_slow(Rtemp, (intptr_t)markOopDesc::prototype());
+    }
+    // mark
+    __ str(Rtemp, Address(Robj, oopDesc::mark_offset_in_bytes()));
+
+    // klass
+#ifdef AARCH64
+    __ store_klass_gap(Robj);
+#endif // AARCH64
+    __ store_klass(Rklass, Robj); // blows Rklass:
+    Rklass = noreg;
+
+    // Note: Disable DTrace runtime check for now to eliminate overhead on each allocation
+    if (DTraceAllocProbes) {
+      // Trigger dtrace event for fastpath
+      Label Lcontinue;
+
+      __ ldrb_global(Rtemp, (address)&DTraceAllocProbes);
+      __ cbz(Rtemp, Lcontinue);
+
+      __ push(atos);
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), Robj);
+      __ pop(atos);
+
+      __ bind(Lcontinue);
+    }
+
+    __ b(done);
+  } else {
+    // jump over literals
+    __ b(slow_case);
+  }
+
+  if (allow_shared_alloc) {
+    __ bind_literal(Lheap_top_addr);
+  }
+
+  // slow case
+  __ bind(slow_case);
+  __ get_constant_pool(Rcpool);
+  __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+  __ call_VM(Robj, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), Rcpool, Rindex);
+
+  // continue
+  __ bind(done);
+
+  // StoreStore barrier required after complete initialization
+  // (headers + content zeroing), before the object may escape.
+  __ membar(MacroAssembler::StoreStore, R1_tmp);
+}
+
+
+void TemplateTable::newarray() {
+  transition(itos, atos);
+  __ ldrb(R1, at_bcp(1));
+  __ mov(R2, R0_tos);
+  call_VM(R0_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), R1, R2);
+  // MacroAssembler::StoreStore useless (included in the runtime exit path)
+}
+
+
+void TemplateTable::anewarray() {
+  transition(itos, atos);
+  __ get_unsigned_2_byte_index_at_bcp(R2, 1);
+  __ get_constant_pool(R1);
+  __ mov(R3, R0_tos);
+  call_VM(R0_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), R1, R2, R3);
+  // MacroAssembler::StoreStore useless (included in the runtime exit path)
+}
+
+
+void TemplateTable::arraylength() {
+  transition(atos, itos);
+  __ null_check(R0_tos, Rtemp, arrayOopDesc::length_offset_in_bytes());
+  __ ldr_s32(R0_tos, Address(R0_tos, arrayOopDesc::length_offset_in_bytes()));
+}
+
+
+void TemplateTable::checkcast() {
+  transition(atos, atos);
+  Label done, is_null, quicked, resolved, throw_exception;
+
+  const Register Robj = R0_tos;
+  const Register Rcpool = R2_tmp;
+  const Register Rtags = R3_tmp;
+  const Register Rindex = R4_tmp;
+  const Register Rsuper = R3_tmp;
+  const Register Rsub   = R4_tmp;
+  const Register Rsubtype_check_tmp1 = R1_tmp;
+  const Register Rsubtype_check_tmp2 = LR_tmp;
+
+  __ cbz(Robj, is_null);
+
+  // Get cpool & tags index
+  __ get_cpool_and_tags(Rcpool, Rtags);
+  __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+
+  // See if bytecode has already been quicked
+  __ add(Rtemp, Rtags, Rindex);
+#ifdef AARCH64
+  // TODO-AARCH64: investigate if LoadLoad barrier is needed here or control dependency is enough
+  __ add(Rtemp, Rtemp, Array<u1>::base_offset_in_bytes());
+  __ ldarb(Rtemp, Rtemp); // acts as LoadLoad memory barrier
+#else
+  __ ldrb(Rtemp, Address(Rtemp, Array<u1>::base_offset_in_bytes()));
+#endif // AARCH64
+
+  __ cmp(Rtemp, JVM_CONSTANT_Class);
+
+#ifndef AARCH64
+  volatile_barrier(MacroAssembler::LoadLoad, Rtemp, true);
+#endif // !AARCH64
+
+  __ b(quicked, eq);
+
+  __ push(atos);
+  call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
+  // vm_result_2 has metadata result
+  __ get_vm_result_2(Rsuper, Robj);
+  __ pop_ptr(Robj);
+  __ b(resolved);
+
+  __ bind(throw_exception);
+  // Come here on failure of subtype check
+  __ profile_typecheck_failed(R1_tmp);
+  __ mov(R2_ClassCastException_obj, Robj);             // convention with generate_ClassCastException_handler()
+  __ b(Interpreter::_throw_ClassCastException_entry);
+
+  // Get superklass in Rsuper and subklass in Rsub
+  __ bind(quicked);
+  __ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool)));
+
+  __ bind(resolved);
+  __ load_klass(Rsub, Robj);
+
+  // Generate subtype check. Blows both tmps and Rtemp.
+  assert_different_registers(Robj, Rsub, Rsuper, Rsubtype_check_tmp1, Rsubtype_check_tmp2, Rtemp);
+  __ gen_subtype_check(Rsub, Rsuper, throw_exception, Rsubtype_check_tmp1, Rsubtype_check_tmp2);
+
+  // Come here on success
+
+  // Collect counts on whether this check-cast sees NULLs a lot or not.
+  if (ProfileInterpreter) {
+    __ b(done);
+    __ bind(is_null);
+    __ profile_null_seen(R1_tmp);
+  } else {
+    __ bind(is_null);   // same as 'done'
+  }
+  __ bind(done);
+}
+
+
+void TemplateTable::instanceof() {
+  // result = 0: obj == NULL or  obj is not an instanceof the specified klass
+  // result = 1: obj != NULL and obj is     an instanceof the specified klass
+
+  transition(atos, itos);
+  Label done, is_null, not_subtype, quicked, resolved;
+
+  const Register Robj = R0_tos;
+  const Register Rcpool = R2_tmp;
+  const Register Rtags = R3_tmp;
+  const Register Rindex = R4_tmp;
+  const Register Rsuper = R3_tmp;
+  const Register Rsub   = R4_tmp;
+  const Register Rsubtype_check_tmp1 = R0_tmp;
+  const Register Rsubtype_check_tmp2 = R1_tmp;
+
+  __ cbz(Robj, is_null);
+
+  __ load_klass(Rsub, Robj);
+
+  // Get cpool & tags index
+  __ get_cpool_and_tags(Rcpool, Rtags);
+  __ get_unsigned_2_byte_index_at_bcp(Rindex, 1);
+
+  // See if bytecode has already been quicked
+  __ add(Rtemp, Rtags, Rindex);
+#ifdef AARCH64
+  // TODO-AARCH64: investigate if LoadLoad barrier is needed here or control dependency is enough
+  __ add(Rtemp, Rtemp, Array<u1>::base_offset_in_bytes());
+  __ ldarb(Rtemp, Rtemp); // acts as LoadLoad memory barrier
+#else
+  __ ldrb(Rtemp, Address(Rtemp, Array<u1>::base_offset_in_bytes()));
+#endif // AARCH64
+  __ cmp(Rtemp, JVM_CONSTANT_Class);
+
+#ifndef AARCH64
+  volatile_barrier(MacroAssembler::LoadLoad, Rtemp, true);
+#endif // !AARCH64
+
+  __ b(quicked, eq);
+
+  __ push(atos);
+  call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
+  // vm_result_2 has metadata result
+  __ get_vm_result_2(Rsuper, Robj);
+  __ pop_ptr(Robj);
+  __ b(resolved);
+
+  // Get superklass in Rsuper and subklass in Rsub
+  __ bind(quicked);
+  __ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
+  __ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool)));
+
+  __ bind(resolved);
+  __ load_klass(Rsub, Robj);
+
+  // Generate subtype check. Blows both tmps and Rtemp.
+  __ gen_subtype_check(Rsub, Rsuper, not_subtype, Rsubtype_check_tmp1, Rsubtype_check_tmp2);
+
+  // Come here on success
+  __ mov(R0_tos, 1);
+  __ b(done);
+
+  __ bind(not_subtype);
+  // Come here on failure
+  __ profile_typecheck_failed(R1_tmp);
+  __ mov(R0_tos, 0);
+
+  // Collect counts on whether this test sees NULLs a lot or not.
+  if (ProfileInterpreter) {
+    __ b(done);
+    __ bind(is_null);
+    __ profile_null_seen(R1_tmp);
+  } else {
+    __ bind(is_null);   // same as 'done'
+  }
+  __ bind(done);
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Breakpoints
+void TemplateTable::_breakpoint() {
+
+  // Note: We get here even if we are single stepping..
+  // jbug inists on setting breakpoints at every bytecode
+  // even if we are in single step mode.
+
+  transition(vtos, vtos);
+
+  // get the unpatched byte code
+  __ mov(R1, Rmethod);
+  __ mov(R2, Rbcp);
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), R1, R2);
+#ifdef AARCH64
+  __ sxtw(Rtmp_save0, R0);
+#else
+  __ mov(Rtmp_save0, R0);
+#endif // AARCH64
+
+  // post the breakpoint event
+  __ mov(R1, Rmethod);
+  __ mov(R2, Rbcp);
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), R1, R2);
+
+  // complete the execution of original bytecode
+  __ mov(R3_bytecode, Rtmp_save0);
+  __ dispatch_only_normal(vtos);
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Exceptions
+
+void TemplateTable::athrow() {
+  transition(atos, vtos);
+  __ mov(Rexception_obj, R0_tos);
+  __ null_check(Rexception_obj, Rtemp);
+  __ b(Interpreter::throw_exception_entry());
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Synchronization
+//
+// Note: monitorenter & exit are symmetric routines; which is reflected
+//       in the assembly code structure as well
+//
+// Stack layout:
+//
+// [expressions  ] <--- Rstack_top        = expression stack top
+// ..
+// [expressions  ]
+// [monitor entry] <--- monitor block top = expression stack bot
+// ..
+// [monitor entry]
+// [frame data   ] <--- monitor block bot
+// ...
+// [saved FP     ] <--- FP
+
+
+void TemplateTable::monitorenter() {
+  transition(atos, vtos);
+
+  const Register Robj = R0_tos;
+  const Register Rentry = R1_tmp;
+
+  // check for NULL object
+  __ null_check(Robj, Rtemp);
+
+  const int entry_size = (frame::interpreter_frame_monitor_size() * wordSize);
+  assert (entry_size % StackAlignmentInBytes == 0, "keep stack alignment");
+  Label allocate_monitor, allocated;
+
+  // initialize entry pointer
+  __ mov(Rentry, 0);                             // points to free slot or NULL
+
+  // find a free slot in the monitor block (result in Rentry)
+  { Label loop, exit;
+    const Register Rcur = R2_tmp;
+    const Register Rcur_obj = Rtemp;
+    const Register Rbottom = R3_tmp;
+    assert_different_registers(Robj, Rentry, Rcur, Rbottom, Rcur_obj);
+
+    __ ldr(Rcur, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                 // points to current entry, starting with top-most entry
+    __ sub(Rbottom, FP, -frame::interpreter_frame_monitor_block_bottom_offset * wordSize);
+                                 // points to word before bottom of monitor block
+
+    __ cmp(Rcur, Rbottom);                       // check if there are no monitors
+#ifndef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+                                                 // prefetch monitor's object for the first iteration
+#endif // !AARCH64
+    __ b(allocate_monitor, eq);                  // there are no monitors, skip searching
+
+    __ bind(loop);
+#ifdef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()));
+#endif // AARCH64
+    __ cmp(Rcur_obj, 0);                         // check if current entry is used
+    __ mov(Rentry, Rcur, eq);                    // if not used then remember entry
+
+    __ cmp(Rcur_obj, Robj);                      // check if current entry is for same object
+    __ b(exit, eq);                              // if same object then stop searching
+
+    __ add(Rcur, Rcur, entry_size);              // otherwise advance to next entry
+
+    __ cmp(Rcur, Rbottom);                       // check if bottom reached
+#ifndef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+                                                 // prefetch monitor's object for the next iteration
+#endif // !AARCH64
+    __ b(loop, ne);                              // if not at bottom then check this entry
+    __ bind(exit);
+  }
+
+  __ cbnz(Rentry, allocated);                    // check if a slot has been found; if found, continue with that one
+
+  __ bind(allocate_monitor);
+
+  // allocate one if there's no free slot
+  { Label loop;
+    assert_different_registers(Robj, Rentry, R2_tmp, Rtemp);
+
+    // 1. compute new pointers
+
+#ifdef AARCH64
+    __ check_extended_sp(Rtemp);
+    __ sub(SP, SP, entry_size);                  // adjust extended SP
+    __ mov(Rtemp, SP);
+    __ str(Rtemp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
+#endif // AARCH64
+
+    __ ldr(Rentry, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                                 // old monitor block top / expression stack bottom
+
+    __ sub(Rstack_top, Rstack_top, entry_size);  // move expression stack top
+    __ check_stack_top_on_expansion();
+
+    __ sub(Rentry, Rentry, entry_size);          // move expression stack bottom
+
+    __ mov(R2_tmp, Rstack_top);                  // set start value for copy loop
+
+    __ str(Rentry, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                                 // set new monitor block top
+
+    // 2. move expression stack contents
+
+    __ cmp(R2_tmp, Rentry);                                 // check if expression stack is empty
+#ifndef AARCH64
+    __ ldr(Rtemp, Address(R2_tmp, entry_size), ne);         // load expression stack word from old location
+#endif // !AARCH64
+    __ b(allocated, eq);
+
+    __ bind(loop);
+#ifdef AARCH64
+    __ ldr(Rtemp, Address(R2_tmp, entry_size));             // load expression stack word from old location
+#endif // AARCH64
+    __ str(Rtemp, Address(R2_tmp, wordSize, post_indexed)); // store expression stack word at new location
+                                                            // and advance to next word
+    __ cmp(R2_tmp, Rentry);                                 // check if bottom reached
+#ifndef AARCH64
+    __ ldr(Rtemp, Address(R2, entry_size), ne);             // load expression stack word from old location
+#endif // !AARCH64
+    __ b(loop, ne);                                         // if not at bottom then copy next word
+  }
+
+  // call run-time routine
+
+  // Rentry: points to monitor entry
+  __ bind(allocated);
+
+  // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly.
+  // The object has already been poped from the stack, so the expression stack looks correct.
+  __ add(Rbcp, Rbcp, 1);
+
+  __ str(Robj, Address(Rentry, BasicObjectLock::obj_offset_in_bytes()));     // store object
+  __ lock_object(Rentry);
+
+  // check to make sure this monitor doesn't cause stack overflow after locking
+  __ save_bcp();  // in case of exception
+  __ arm_stack_overflow_check(0, Rtemp);
+
+  // The bcp has already been incremented. Just need to dispatch to next instruction.
+  __ dispatch_next(vtos);
+}
+
+
+void TemplateTable::monitorexit() {
+  transition(atos, vtos);
+
+  const Register Robj = R0_tos;
+  const Register Rcur = R1_tmp;
+  const Register Rbottom = R2_tmp;
+  const Register Rcur_obj = Rtemp;
+
+  // check for NULL object
+  __ null_check(Robj, Rtemp);
+
+  const int entry_size = (frame::interpreter_frame_monitor_size() * wordSize);
+  Label found, throw_exception;
+
+  // find matching slot
+  { Label loop;
+    assert_different_registers(Robj, Rcur, Rbottom, Rcur_obj);
+
+    __ ldr(Rcur, Address(FP, frame::interpreter_frame_monitor_block_top_offset * wordSize));
+                                 // points to current entry, starting with top-most entry
+    __ sub(Rbottom, FP, -frame::interpreter_frame_monitor_block_bottom_offset * wordSize);
+                                 // points to word before bottom of monitor block
+
+    __ cmp(Rcur, Rbottom);                       // check if bottom reached
+#ifndef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+                                                 // prefetch monitor's object for the first iteration
+#endif // !AARCH64
+    __ b(throw_exception, eq);                   // throw exception if there are now monitors
+
+    __ bind(loop);
+#ifdef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()));
+#endif // AARCH64
+    // check if current entry is for same object
+    __ cmp(Rcur_obj, Robj);
+    __ b(found, eq);                             // if same object then stop searching
+    __ add(Rcur, Rcur, entry_size);              // otherwise advance to next entry
+    __ cmp(Rcur, Rbottom);                       // check if bottom reached
+#ifndef AARCH64
+    __ ldr(Rcur_obj, Address(Rcur, BasicObjectLock::obj_offset_in_bytes()), ne);
+#endif // !AARCH64
+    __ b (loop, ne);                             // if not at bottom then check this entry
+  }
+
+  // error handling. Unlocking was not block-structured
+  __ bind(throw_exception);
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+  __ should_not_reach_here();
+
+  // call run-time routine
+  // Rcur: points to monitor entry
+  __ bind(found);
+  __ push_ptr(Robj);                             // make sure object is on stack (contract with oopMaps)
+  __ unlock_object(Rcur);
+  __ pop_ptr(Robj);                              // discard object
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Wide instructions
+
+void TemplateTable::wide() {
+  transition(vtos, vtos);
+  __ ldrb(R3_bytecode, at_bcp(1));
+
+  InlinedAddress Ltable((address)Interpreter::_wentry_point);
+  __ ldr_literal(Rtemp, Ltable);
+  __ indirect_jump(Address::indexed_ptr(Rtemp, R3_bytecode), Rtemp);
+
+  __ nop(); // to avoid filling CPU pipeline with invalid instructions
+  __ nop();
+  __ bind_literal(Ltable);
+}
+
+
+//----------------------------------------------------------------------------------------------------
+// Multi arrays
+
+void TemplateTable::multianewarray() {
+  transition(vtos, atos);
+  __ ldrb(Rtmp_save0, at_bcp(3));   // get number of dimensions
+
+  // last dim is on top of stack; we want address of first one:
+  // first_addr = last_addr + ndims * stackElementSize - 1*wordsize
+  // the latter wordSize to point to the beginning of the array.
+  __ add(Rtemp, Rstack_top, AsmOperand(Rtmp_save0, lsl, Interpreter::logStackElementSize));
+  __ sub(R1, Rtemp, wordSize);
+
+  call_VM(R0, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), R1);
+  __ add(Rstack_top, Rstack_top, AsmOperand(Rtmp_save0, lsl, Interpreter::logStackElementSize));
+  // MacroAssembler::StoreStore useless (included in the runtime exit path)
+}
diff --git a/hotspot/src/cpu/arm/vm/templateTable_arm.hpp b/hotspot/src/cpu/arm/vm/templateTable_arm.hpp
new file mode 100644
index 0000000..06698b2
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/templateTable_arm.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_TEMPLATETABLE_ARM_HPP
+#define CPU_ARM_VM_TEMPLATETABLE_ARM_HPP
+
+  static void prepare_invoke(int byte_no,
+                             Register method,         // linked method (or i-klass)
+                             Register index = noreg,  // itable index, MethodType, etc.
+                             Register recv  = noreg,  // if caller wants to see it
+                             Register flags = noreg   // if caller wants to test it
+                             );
+
+  static void invokevirtual_helper(Register index, Register recv,
+                                   Register flags);
+
+  static void volatile_barrier(MacroAssembler::Membar_mask_bits order_constraint,
+                               Register tmp,
+                               bool preserve_flags = false,
+                               Register load_tgt = noreg);
+
+  // Helpers
+  static void index_check(Register array, Register index);
+  static void index_check_without_pop(Register array, Register index);
+
+  static void get_local_base_addr(Register r, Register index);
+
+  static Address load_iaddress(Register index, Register scratch);
+  static Address load_aaddress(Register index, Register scratch);
+  static Address load_faddress(Register index, Register scratch);
+  static Address load_daddress(Register index, Register scratch);
+
+  static void load_category2_local(Register Rlocal_index, Register tmp);
+  static void store_category2_local(Register Rlocal_index, Register tmp);
+
+  static Address get_array_elem_addr(BasicType elemType, Register array, Register index, Register temp);
+
+  static void jvmti_post_fast_field_mod(TosState state);
+
+#endif // CPU_ARM_VM_TEMPLATETABLE_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/vmStructs_arm.hpp b/hotspot/src/cpu/arm/vm/vmStructs_arm.hpp
new file mode 100644
index 0000000..901af78
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vmStructs_arm.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_VMSTRUCTS_ARM_HPP
+#define CPU_ARM_VM_VMSTRUCTS_ARM_HPP
+
+// These are the CPU-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+                                                                                                                                     \
+  /******************************/                                                                                                   \
+  /* JavaCallWrapper            */                                                                                                   \
+  /******************************/                                                                                                   \
+  /******************************/                                                                                                   \
+  /* JavaFrameAnchor            */                                                                                                   \
+  /******************************/                                                                                                   \
+  volatile_nonstatic_field(JavaFrameAnchor,     _last_Java_fp,                                    intptr_t*)
+
+#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+
+#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#endif // CPU_ARM_VM_VMSTRUCTS_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/vm_version_arm.hpp b/hotspot/src/cpu/arm/vm/vm_version_arm.hpp
new file mode 100644
index 0000000..e2770f0
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vm_version_arm.hpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_VM_VERSION_ARM_HPP
+#define CPU_ARM_VM_VM_VERSION_ARM_HPP
+
+#include "runtime/globals_extension.hpp"
+#include "runtime/vm_version.hpp"
+
+class VM_Version: public Abstract_VM_Version {
+  friend class JVMCIVMStructs;
+
+  static bool _has_simd;
+
+ protected:
+  // Are we done with vm version initialization
+  static bool _is_initialized;
+
+ public:
+  static void initialize();
+  static bool is_initialized()      { return _is_initialized; }
+
+#ifdef AARCH64
+
+ public:
+  static bool supports_ldrex()         { return true; }
+  static bool supports_ldrexd()        { return true; }
+  static bool supports_movw()          { return true; }
+
+  // Override Abstract_VM_Version implementation
+  static bool use_biased_locking();
+
+  static bool has_simd()               { return _has_simd; }
+  static bool has_vfp()                { return has_simd(); }
+  static bool simd_math_is_compliant() { return true; }
+
+  static bool prefer_moves_over_load_literal() { return true; }
+
+#else
+
+ protected:
+  enum Feature_Flag {
+    vfp = 0,
+    vfp3_32 = 1,
+    simd = 2,
+  };
+
+  enum Feature_Flag_Set {
+    unknown_m           = 0,
+    all_features_m      = -1,
+
+    vfp_m     = 1 << vfp,
+    vfp3_32_m = 1 << vfp3_32,
+    simd_m    = 1 << simd,
+  };
+
+  // The value stored by "STR PC, [addr]" instruction can be either
+  // (address of this instruction + 8) or (address of this instruction + 12)
+  // depending on hardware implementation.
+  // This adjustment is calculated in runtime.
+  static int _stored_pc_adjustment;
+
+  // ARM architecture version: 5 = ARMv5, 6 = ARMv6, 7 = ARMv7 etc.
+  static int _arm_arch;
+
+  // linux kernel atomic helper function version info
+  // __kuser_cmpxchg() if version >= 2
+  // __kuser_cmpxchg64() if version >= 5
+  static int _kuser_helper_version;
+
+#define KUSER_HELPER_VERSION_ADDR 0xffff0ffc
+#define KUSER_VERSION_CMPXCHG32 2
+#define KUSER_VERSION_CMPXCHG64 5
+
+  // Read additional info using OS-specific interfaces
+  static void get_os_cpu_info();
+
+ public:
+  static void early_initialize();
+
+  static int arm_arch()             { return _arm_arch; }
+  static int stored_pc_adjustment() { return _stored_pc_adjustment; }
+  static bool supports_rev()        { return _arm_arch >= 6; }
+  static bool supports_ldrex()      { return _arm_arch >= 6; }
+  static bool supports_movw()       { return _arm_arch >= 7; }
+  static bool supports_ldrexd()     { return _arm_arch >= 7; }
+  static bool supports_compare_and_exchange() { return true; }
+  static bool supports_kuser_cmpxchg32() { return _kuser_helper_version >= KUSER_VERSION_CMPXCHG32; }
+  static bool supports_kuser_cmpxchg64() { return _kuser_helper_version >= KUSER_VERSION_CMPXCHG64; }
+  // Override Abstract_VM_Version implementation
+  static bool use_biased_locking();
+  static const char* vm_info_string();
+
+  static bool has_vfp()             { return (_features & vfp_m) != 0; }
+  static bool has_vfp3_32()         { return (_features & vfp3_32_m) != 0; }
+  static bool has_simd()            { return (_features & simd_m) != 0; }
+
+  static bool simd_math_is_compliant() { return false; }
+
+  static bool prefer_moves_over_load_literal() { return supports_movw(); }
+
+  friend class VM_Version_StubGenerator;
+
+#endif // AARCH64
+};
+
+#endif // CPU_ARM_VM_VM_VERSION_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/vm_version_arm_32.cpp b/hotspot/src/cpu/arm/vm/vm_version_arm_32.cpp
new file mode 100644
index 0000000..10a2408
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vm_version_arm_32.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/java.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "vm_version_arm.hpp"
+
+int  VM_Version::_stored_pc_adjustment = 4;
+int  VM_Version::_arm_arch             = 5;
+bool VM_Version::_is_initialized       = false;
+int VM_Version::_kuser_helper_version  = 0;
+
+extern "C" {
+  typedef int (*get_cpu_info_t)();
+  typedef bool (*check_vfp_t)(double *d);
+  typedef bool (*check_simd_t)();
+}
+
+#define __ _masm->
+
+class VM_Version_StubGenerator: public StubCodeGenerator {
+ public:
+
+  VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
+
+  address generate_get_cpu_info() {
+    StubCodeMark mark(this, "VM_Version", "get_cpu_info");
+    address start = __ pc();
+
+    __ mov(R0, PC);
+    __ push(PC);
+    __ pop(R1);
+    __ sub(R0, R1, R0);
+    // return the result in R0
+    __ bx(LR);
+
+    return start;
+  };
+
+  address generate_check_vfp() {
+    StubCodeMark mark(this, "VM_Version", "check_vfp");
+    address start = __ pc();
+
+    __ fstd(D0, Address(R0));
+    __ mov(R0, 1);
+    __ bx(LR);
+
+    return start;
+  };
+
+  address generate_check_vfp3_32() {
+    StubCodeMark mark(this, "VM_Version", "check_vfp3_32");
+    address start = __ pc();
+
+    __ fstd(D16, Address(R0));
+    __ mov(R0, 1);
+    __ bx(LR);
+
+    return start;
+  };
+
+  address generate_check_simd() {
+    StubCodeMark mark(this, "VM_Version", "check_simd");
+    address start = __ pc();
+
+    __ vcnt(Stemp, Stemp);
+    __ mov(R0, 1);
+    __ bx(LR);
+
+    return start;
+  };
+};
+
+#undef __
+
+
+extern "C" address check_vfp3_32_fault_instr;
+extern "C" address check_vfp_fault_instr;
+extern "C" address check_simd_fault_instr;
+
+void VM_Version::initialize() {
+  ResourceMark rm;
+
+  // Making this stub must be FIRST use of assembler
+  const int stub_size = 128;
+  BufferBlob* stub_blob = BufferBlob::create("get_cpu_info", stub_size);
+  if (stub_blob == NULL) {
+    vm_exit_during_initialization("Unable to allocate get_cpu_info stub");
+  }
+
+  CodeBuffer c(stub_blob);
+  VM_Version_StubGenerator g(&c);
+  address get_cpu_info_pc = g.generate_get_cpu_info();
+  get_cpu_info_t get_cpu_info = CAST_TO_FN_PTR(get_cpu_info_t, get_cpu_info_pc);
+
+  int pc_adjustment = get_cpu_info();
+
+  VM_Version::_stored_pc_adjustment = pc_adjustment;
+
+#ifndef __SOFTFP__
+  address check_vfp_pc = g.generate_check_vfp();
+  check_vfp_t check_vfp = CAST_TO_FN_PTR(check_vfp_t, check_vfp_pc);
+
+  check_vfp_fault_instr = (address)check_vfp;
+  double dummy;
+  if (check_vfp(&dummy)) {
+    _features |= vfp_m;
+  }
+
+#ifdef COMPILER2
+  if (has_vfp()) {
+    address check_vfp3_32_pc = g.generate_check_vfp3_32();
+    check_vfp_t check_vfp3_32 = CAST_TO_FN_PTR(check_vfp_t, check_vfp3_32_pc);
+    check_vfp3_32_fault_instr = (address)check_vfp3_32;
+    double dummy;
+    if (check_vfp3_32(&dummy)) {
+      _features |= vfp3_32_m;
+    }
+
+    address check_simd_pc =g.generate_check_simd();
+    check_simd_t check_simd = CAST_TO_FN_PTR(check_simd_t, check_simd_pc);
+    check_simd_fault_instr = (address)check_simd;
+    if (check_simd()) {
+      _features |= simd_m;
+    }
+  }
+#endif
+#endif
+
+
+  if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+    warning("AES intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+  }
+
+  if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
+    warning("AES instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAES, false);
+  }
+
+  if (UseAESCTRIntrinsics) {
+    warning("AES/CTR intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+  }
+
+  if (UseFMA) {
+    warning("FMA instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseFMA, false);
+  }
+
+  if (UseSHA) {
+    warning("SHA instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseSHA, false);
+  }
+
+  if (UseSHA1Intrinsics) {
+    warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
+  }
+
+  if (UseSHA256Intrinsics) {
+    warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
+  }
+
+  if (UseSHA512Intrinsics) {
+    warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
+  }
+
+  if (UseCRC32Intrinsics) {
+    if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics))
+      warning("CRC32 intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
+  }
+
+  if (UseCRC32CIntrinsics) {
+    if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
+      warning("CRC32C intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+  }
+
+  if (UseAdler32Intrinsics) {
+    warning("Adler32 intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
+  }
+
+  if (UseVectorizedMismatchIntrinsic) {
+    warning("vectorizedMismatch intrinsic is not available on this CPU.");
+    FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
+  }
+
+  get_os_cpu_info();
+
+  _kuser_helper_version = *(int*)KUSER_HELPER_VERSION_ADDR;
+
+#ifdef COMPILER2
+  // C2 is only supported on v7+ VFP at this time
+  if (_arm_arch < 7 || !has_vfp()) {
+    vm_exit_during_initialization("Server VM is only supported on ARMv7+ VFP");
+  }
+#endif
+
+  // armv7 has the ldrexd instruction that can be used to implement cx8
+  // armv5 with linux >= 3.1 can use kernel helper routine
+  _supports_cx8 = (supports_ldrexd() || supports_kuser_cmpxchg64());
+  // ARM doesn't have special instructions for these but ldrex/ldrexd
+  // enable shorter instruction sequences that the ones based on cas.
+  _supports_atomic_getset4 = supports_ldrex();
+  _supports_atomic_getadd4 = supports_ldrex();
+  _supports_atomic_getset8 = supports_ldrexd();
+  _supports_atomic_getadd8 = supports_ldrexd();
+
+#ifdef COMPILER2
+  assert(_supports_cx8 && _supports_atomic_getset4 && _supports_atomic_getadd4
+         && _supports_atomic_getset8 && _supports_atomic_getadd8, "C2: atomic operations must be supported");
+#endif
+  char buf[512];
+  jio_snprintf(buf, sizeof(buf), "(ARMv%d)%s%s%s",
+               _arm_arch,
+               (has_vfp() ? ", vfp" : ""),
+               (has_vfp3_32() ? ", vfp3-32" : ""),
+               (has_simd() ? ", simd" : ""));
+
+  // buf is started with ", " or is empty
+  _features_string = os::strdup(buf);
+
+  if (has_simd()) {
+    if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
+      FLAG_SET_DEFAULT(UsePopCountInstruction, true);
+    }
+  }
+
+  AllocatePrefetchDistance = 128;
+
+#ifdef COMPILER2
+  FLAG_SET_DEFAULT(UseFPUForSpilling, true);
+
+  if (FLAG_IS_DEFAULT(MaxVectorSize)) {
+    // FLAG_SET_DEFAULT(MaxVectorSize, has_simd() ? 16 : 8);
+    // SIMD/NEON can use 16, but default is 8 because currently
+    // larger than 8 will disable instruction scheduling
+    FLAG_SET_DEFAULT(MaxVectorSize, 8);
+  }
+
+  if (MaxVectorSize > 16) {
+    FLAG_SET_DEFAULT(MaxVectorSize, 8);
+  }
+#endif
+
+  if (FLAG_IS_DEFAULT(Tier4CompileThreshold)) {
+    Tier4CompileThreshold = 10000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3InvocationThreshold)) {
+    Tier3InvocationThreshold = 1000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3CompileThreshold)) {
+    Tier3CompileThreshold = 5000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3MinInvocationThreshold)) {
+    Tier3MinInvocationThreshold = 500;
+  }
+
+  FLAG_SET_DEFAULT(TypeProfileLevel, 0); // unsupported
+
+  // This machine does not allow unaligned memory accesses
+  if (UseUnalignedAccesses) {
+    if (!FLAG_IS_DEFAULT(UseUnalignedAccesses))
+      warning("Unaligned memory access is not available on this CPU");
+    FLAG_SET_DEFAULT(UseUnalignedAccesses, false);
+  }
+
+  _is_initialized = true;
+}
+
+bool VM_Version::use_biased_locking() {
+  get_os_cpu_info();
+  // The cost of CAS on uniprocessor ARM v6 and later is low compared to the
+  // overhead related to slightly longer Biased Locking execution path.
+  // Testing shows no improvement when running with Biased Locking enabled
+  // on an ARMv6 and higher uniprocessor systems.  The situation is different on
+  // ARMv5 and MP systems.
+  //
+  // Therefore the Biased Locking is enabled on ARMv5 and ARM MP only.
+  //
+  return (!os::is_MP() && (arm_arch() > 5)) ? false : true;
+}
+
+#define EXP
+
+// Temporary override for experimental features
+// Copied from Abstract_VM_Version
+const char* VM_Version::vm_info_string() {
+  switch (Arguments::mode()) {
+    case Arguments::_int:
+      return UseSharedSpaces ? "interpreted mode, sharing" EXP : "interpreted mode" EXP;
+    case Arguments::_mixed:
+      return UseSharedSpaces ? "mixed mode, sharing" EXP    :  "mixed mode" EXP;
+    case Arguments::_comp:
+      return UseSharedSpaces ? "compiled mode, sharing" EXP   : "compiled mode" EXP;
+  };
+  ShouldNotReachHere();
+  return "";
+}
diff --git a/hotspot/src/cpu/arm/vm/vm_version_arm_64.cpp b/hotspot/src/cpu/arm/vm/vm_version_arm_64.cpp
new file mode 100644
index 0000000..7f25255
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vm_version_arm_64.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/java.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/stubCodeGenerator.hpp"
+#include "vm_version_arm.hpp"
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+
+#ifndef HWCAP_AES
+#define HWCAP_AES 1 << 3
+#endif
+
+bool VM_Version::_is_initialized = false;
+bool VM_Version::_has_simd = false;
+
+extern "C" {
+  typedef bool (*check_simd_t)();
+}
+
+
+#ifdef COMPILER2
+
+#define __ _masm->
+
+class VM_Version_StubGenerator: public StubCodeGenerator {
+ public:
+
+  VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
+
+  address generate_check_simd() {
+    StubCodeMark mark(this, "VM_Version", "check_simd");
+    address start = __ pc();
+
+    __ vcnt(Stemp, Stemp);
+    __ mov(R0, 1);
+    __ ret(LR);
+
+    return start;
+  };
+};
+
+#undef __
+
+#endif
+
+
+
+extern "C" address check_simd_fault_instr;
+
+
+void VM_Version::initialize() {
+  ResourceMark rm;
+
+  // Making this stub must be FIRST use of assembler
+  const int stub_size = 128;
+  BufferBlob* stub_blob = BufferBlob::create("get_cpu_info", stub_size);
+  if (stub_blob == NULL) {
+    vm_exit_during_initialization("Unable to allocate get_cpu_info stub");
+  }
+
+  if (UseFMA) {
+    warning("FMA instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseFMA, false);
+  }
+
+  if (UseSHA) {
+    warning("SHA instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseSHA, false);
+  }
+
+  if (UseSHA1Intrinsics) {
+    warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
+  }
+
+  if (UseSHA256Intrinsics) {
+    warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
+  }
+
+  if (UseSHA512Intrinsics) {
+    warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
+    FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
+  }
+
+  if (UseCRC32Intrinsics) {
+    if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics))
+      warning("CRC32 intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
+  }
+
+  if (UseCRC32CIntrinsics) {
+    if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
+      warning("CRC32C intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+  }
+
+  if (UseAdler32Intrinsics) {
+    warning("Adler32 intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
+  }
+
+  if (UseVectorizedMismatchIntrinsic) {
+    warning("vectorizedMismatch intrinsic is not available on this CPU.");
+    FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
+  }
+
+  CodeBuffer c(stub_blob);
+
+#ifdef COMPILER2
+  VM_Version_StubGenerator g(&c);
+
+  address check_simd_pc = g.generate_check_simd();
+  if (check_simd_pc != NULL) {
+    check_simd_t check_simd = CAST_TO_FN_PTR(check_simd_t, check_simd_pc);
+    check_simd_fault_instr = (address)check_simd;
+    _has_simd = check_simd();
+  } else {
+    assert(! _has_simd, "default _has_simd value must be 'false'");
+  }
+#endif
+
+  unsigned long auxv = getauxval(AT_HWCAP);
+
+  char buf[512];
+  jio_snprintf(buf, sizeof(buf), "AArch64%s",
+               ((auxv & HWCAP_AES) ? ", aes" : ""));
+
+  _features_string = os::strdup(buf);
+
+#ifdef COMPILER2
+  if (auxv & HWCAP_AES) {
+    if (FLAG_IS_DEFAULT(UseAES)) {
+      FLAG_SET_DEFAULT(UseAES, true);
+    }
+    if (!UseAES) {
+      if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+        warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
+      }
+      FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+    } else {
+      if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+        FLAG_SET_DEFAULT(UseAESIntrinsics, true);
+      }
+    }
+  } else
+#endif
+  if (UseAES || UseAESIntrinsics) {
+    if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
+      warning("AES instructions are not available on this CPU");
+      FLAG_SET_DEFAULT(UseAES, false);
+    }
+    if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+      warning("AES intrinsics are not available on this CPU");
+      FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+    }
+  }
+
+  if (UseAESCTRIntrinsics) {
+    warning("AES/CTR intrinsics are not available on this CPU");
+    FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+  }
+
+  _supports_cx8 = true;
+  _supports_atomic_getset4 = true;
+  _supports_atomic_getadd4 = true;
+  _supports_atomic_getset8 = true;
+  _supports_atomic_getadd8 = true;
+
+  // TODO-AARCH64 revise C2 flags
+
+  if (has_simd()) {
+    if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
+      FLAG_SET_DEFAULT(UsePopCountInstruction, true);
+    }
+  }
+
+  AllocatePrefetchDistance = 128;
+
+#ifdef COMPILER2
+  FLAG_SET_DEFAULT(UseFPUForSpilling, true);
+
+  if (FLAG_IS_DEFAULT(MaxVectorSize)) {
+    // FLAG_SET_DEFAULT(MaxVectorSize, has_simd() ? 16 : 8);
+    // SIMD/NEON can use 16, but default is 8 because currently
+    // larger than 8 will disable instruction scheduling
+    FLAG_SET_DEFAULT(MaxVectorSize, 8);
+  }
+
+  if (MaxVectorSize > 16) {
+    FLAG_SET_DEFAULT(MaxVectorSize, 8);
+  }
+#endif
+
+  if (FLAG_IS_DEFAULT(Tier4CompileThreshold)) {
+    Tier4CompileThreshold = 10000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3InvocationThreshold)) {
+    Tier3InvocationThreshold = 1000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3CompileThreshold)) {
+    Tier3CompileThreshold = 5000;
+  }
+  if (FLAG_IS_DEFAULT(Tier3MinInvocationThreshold)) {
+    Tier3MinInvocationThreshold = 500;
+  }
+
+  FLAG_SET_DEFAULT(TypeProfileLevel, 0); // unsupported
+
+  // This machine does not allow unaligned memory accesses
+  if (UseUnalignedAccesses) {
+    if (!FLAG_IS_DEFAULT(UseUnalignedAccesses))
+      warning("Unaligned memory access is not available on this CPU");
+    FLAG_SET_DEFAULT(UseUnalignedAccesses, false);
+  }
+
+  _is_initialized = true;
+}
+
+bool VM_Version::use_biased_locking() {
+  // TODO-AARCH64 measure performance and revise
+
+  // The cost of CAS on uniprocessor ARM v6 and later is low compared to the
+  // overhead related to slightly longer Biased Locking execution path.
+  // Testing shows no improvement when running with Biased Locking enabled
+  // on an ARMv6 and higher uniprocessor systems.  The situation is different on
+  // ARMv5 and MP systems.
+  //
+  // Therefore the Biased Locking is enabled on ARMv5 and ARM MP only.
+  //
+  return os::is_MP();
+}
diff --git a/hotspot/src/cpu/arm/vm/vmreg_arm.cpp b/hotspot/src/cpu/arm/vm/vmreg_arm.cpp
new file mode 100644
index 0000000..027fcdd
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vmreg_arm.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "code/vmreg.hpp"
+
+void VMRegImpl::set_regName() {
+  Register reg = ::as_Register(0);
+  int i;
+  for (i = 0; i < ConcreteRegisterImpl::max_gpr; reg = reg->successor()) {
+    for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_gpr); j++) {
+      regName[i++] = reg->name();
+    }
+  }
+#ifndef __SOFTFP__
+  FloatRegister freg = ::as_FloatRegister(0);
+  for ( ; i < ConcreteRegisterImpl::max_fpr ; ) {
+    for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_fpr); j++) {
+      regName[i++] = freg->name();
+    }
+    freg = freg->successor();
+  }
+#endif
+
+  for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {
+    regName[i] = "NON-GPR-FPR";
+  }
+}
diff --git a/hotspot/src/cpu/arm/vm/vmreg_arm.hpp b/hotspot/src/cpu/arm/vm/vmreg_arm.hpp
new file mode 100644
index 0000000..3db677c
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vmreg_arm.hpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_VMREG_ARM_HPP
+#define CPU_ARM_VM_VMREG_ARM_HPP
+
+  inline bool is_Register() {
+    return (unsigned int) value() < (unsigned int) ConcreteRegisterImpl::max_gpr;
+  }
+
+  inline bool is_FloatRegister() {
+    return value() >= ConcreteRegisterImpl::max_gpr && value() < ConcreteRegisterImpl::max_fpr;
+  }
+
+  inline Register as_Register() {
+    assert(is_Register(), "must be");
+    assert(is_concrete(), "concrete register expected");
+    return ::as_Register(value() >> ConcreteRegisterImpl::log_vmregs_per_gpr);
+  }
+
+  inline FloatRegister as_FloatRegister() {
+    assert(is_FloatRegister(), "must be");
+    assert(is_concrete(), "concrete register expected");
+    return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> ConcreteRegisterImpl::log_vmregs_per_fpr);
+  }
+
+  inline bool is_concrete() {
+    if (is_Register()) {
+      return ((value() & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_gpr)) == 0);
+    } else if (is_FloatRegister()) {
+      return (((value() - ConcreteRegisterImpl::max_gpr) & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_fpr)) == 0);
+    } else {
+      return false;
+    }
+  }
+
+#endif // CPU_ARM_VM_VMREG_ARM_HPP
diff --git a/hotspot/src/cpu/arm/vm/vmreg_arm.inline.hpp b/hotspot/src/cpu/arm/vm/vmreg_arm.inline.hpp
new file mode 100644
index 0000000..bf8e86b
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vmreg_arm.inline.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_VMREG_ARM_INLINE_HPP
+#define CPU_ARM_VM_VMREG_ARM_INLINE_HPP
+
+inline VMReg RegisterImpl::as_VMReg() {
+  return VMRegImpl::as_VMReg(encoding() << ConcreteRegisterImpl::log_vmregs_per_gpr);
+}
+
+inline VMReg FloatRegisterImpl::as_VMReg() {
+  return VMRegImpl::as_VMReg((encoding() << ConcreteRegisterImpl::log_vmregs_per_fpr) + ConcreteRegisterImpl::max_gpr);
+}
+#endif // CPU_ARM_VM_VMREG_ARM_INLINE_HPP
diff --git a/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp b/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp
new file mode 100644
index 0000000..8b980ab
--- /dev/null
+++ b/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "assembler_arm.inline.hpp"
+#include "code/vtableStubs.hpp"
+#include "interp_masm_arm.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/klassVtable.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_arm.inline.hpp"
+#ifdef COMPILER2
+#include "opto/runtime.hpp"
+#endif
+
+// machine-dependent part of VtableStubs: create VtableStub of correct size and
+// initialize its code
+
+#define __ masm->
+
+#ifndef PRODUCT
+extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
+#endif
+
+VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
+  const int code_length = VtableStub::pd_code_size_limit(true);
+  VtableStub* s = new(code_length) VtableStub(true, vtable_index);
+  // Can be NULL if there is no free space in the code cache.
+  if (s == NULL) {
+    return NULL;
+  }
+
+  ResourceMark rm;
+  CodeBuffer cb(s->entry_point(), code_length);
+  MacroAssembler* masm = new MacroAssembler(&cb);
+
+  assert(VtableStub::receiver_location() == R0->as_VMReg(), "receiver expected in R0");
+
+  const Register tmp = Rtemp; // Rtemp OK, should be free at call sites
+
+  address npe_addr = __ pc();
+  __ load_klass(tmp, R0);
+
+  {
+  int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index * vtableEntry::size_in_bytes();
+  int method_offset = vtableEntry::method_offset_in_bytes() + entry_offset;
+
+  assert ((method_offset & (wordSize - 1)) == 0, "offset should be aligned");
+  int offset_mask = AARCH64_ONLY(0xfff << LogBytesPerWord) NOT_AARCH64(0xfff);
+  if (method_offset & ~offset_mask) {
+    __ add(tmp, tmp, method_offset & ~offset_mask);
+  }
+  __ ldr(Rmethod, Address(tmp, method_offset & offset_mask));
+  }
+
+  address ame_addr = __ pc();
+#ifdef AARCH64
+  __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset()));
+  __ br(tmp);
+#else
+  __ ldr(PC, Address(Rmethod, Method::from_compiled_offset()));
+#endif // AARCH64
+
+  masm->flush();
+
+  if (PrintMiscellaneous && (WizardMode || Verbose)) {
+    tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
+                  vtable_index, p2i(s->entry_point()),
+                  (int)(s->code_end() - s->entry_point()),
+                  (int)(s->code_end() - __ pc()));
+  }
+  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // FIXME ARM: need correct 'slop' - below is x86 code
+  // shut the door on sizing bugs
+  //int slop = 8;  // 32-bit offset is this much larger than a 13-bit one
+  //assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
+
+  s->set_exception_points(npe_addr, ame_addr);
+  return s;
+}
+
+VtableStub* VtableStubs::create_itable_stub(int itable_index) {
+  const int code_length = VtableStub::pd_code_size_limit(false);
+  VtableStub* s = new(code_length) VtableStub(false, itable_index);
+  // Can be NULL if there is no free space in the code cache.
+  if (s == NULL) {
+    return NULL;
+  }
+
+  ResourceMark rm;
+  CodeBuffer cb(s->entry_point(), code_length);
+  MacroAssembler* masm = new MacroAssembler(&cb);
+
+  assert(VtableStub::receiver_location() == R0->as_VMReg(), "receiver expected in R0");
+
+  // R0-R3 / R0-R7 registers hold the arguments and cannot be spoiled
+  const Register Rclass  = AARCH64_ONLY(R9)  NOT_AARCH64(R4);
+  const Register Rlength = AARCH64_ONLY(R10)  NOT_AARCH64(R5);
+  const Register Rscan   = AARCH64_ONLY(R11) NOT_AARCH64(R6);
+  const Register tmp     = Rtemp;
+
+  assert_different_registers(Ricklass, Rclass, Rlength, Rscan, tmp);
+
+  // Calculate the start of itable (itable goes after vtable)
+  const int scale = exact_log2(vtableEntry::size_in_bytes());
+  address npe_addr = __ pc();
+  __ load_klass(Rclass, R0);
+  __ ldr_s32(Rlength, Address(Rclass, Klass::vtable_length_offset()));
+
+  __ add(Rscan, Rclass, in_bytes(Klass::vtable_start_offset()));
+  __ add(Rscan, Rscan, AsmOperand(Rlength, lsl, scale));
+
+  // Search through the itable for an interface equal to incoming Ricklass
+  // itable looks like [intface][offset][intface][offset][intface][offset]
+  const int entry_size = itableOffsetEntry::size() * HeapWordSize;
+  assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience");
+
+  Label loop;
+  __ bind(loop);
+  __ ldr(tmp, Address(Rscan, entry_size, post_indexed));
+#ifdef AARCH64
+  Label found;
+  __ cmp(tmp, Ricklass);
+  __ b(found, eq);
+  __ cbnz(tmp, loop);
+#else
+  __ cmp(tmp, Ricklass);  // set ZF and CF if interface is found
+  __ cmn(tmp, 0, ne);     // check if tmp == 0 and clear CF if it is
+  __ b(loop, ne);
+#endif // AARCH64
+
+  assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "Check initialization order");
+#ifdef AARCH64
+  __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, tmp);
+  __ bind(found);
+#else
+  // CF == 0 means we reached the end of itable without finding icklass
+  __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, noreg, cc);
+#endif // !AARCH64
+
+  // Interface found at previous position of Rscan, now load the method oop
+  __ ldr_s32(tmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size));
+  {
+    const int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index +
+      itableMethodEntry::method_offset_in_bytes();
+    __ add_slow(Rmethod, Rclass, method_offset);
+  }
+  __ ldr(Rmethod, Address(Rmethod, tmp));
+
+  address ame_addr = __ pc();
+
+#ifdef AARCH64
+  __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset()));
+  __ br(tmp);
+#else
+  __ ldr(PC, Address(Rmethod, Method::from_compiled_offset()));
+#endif // AARCH64
+
+  masm->flush();
+
+  if (PrintMiscellaneous && (WizardMode || Verbose)) {
+    tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
+                  itable_index, p2i(s->entry_point()),
+                  (int)(s->code_end() - s->entry_point()),
+                  (int)(s->code_end() - __ pc()));
+  }
+  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // FIXME ARM: need correct 'slop' - below is x86 code
+  // shut the door on sizing bugs
+  //int slop = 8;  // 32-bit offset is this much larger than a 13-bit one
+  //assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
+
+  s->set_exception_points(npe_addr, ame_addr);
+  return s;
+}
+
+int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
+  int instr_count;
+
+  if (is_vtable_stub) {
+    // vtable stub size
+    instr_count = NOT_AARCH64(4) AARCH64_ONLY(5);
+  } else {
+    // itable stub size
+    instr_count = NOT_AARCH64(20) AARCH64_ONLY(20);
+  }
+
+#ifdef AARCH64
+  if (UseCompressedClassPointers) {
+    instr_count += MacroAssembler::instr_count_for_decode_klass_not_null();
+  }
+#endif // AARCH64
+
+  return instr_count * Assembler::InstructionSize;
+}
+
+int VtableStub::pd_code_alignment() {
+  return 8;
+}
diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp
index d9e1721..bba0c6d 100644
--- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp
@@ -153,7 +153,7 @@
   __ nop();
 
   // Generate code for the exception handler.
-  address handler_base = __ start_a_stub(exception_handler_size);
+  address handler_base = __ start_a_stub(exception_handler_size());
 
   if (handler_base == NULL) {
     // Not enough space left for the handler.
@@ -168,7 +168,7 @@
   __ mtctr(R0);
   __ bctr();
 
-  guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -233,7 +233,7 @@
   __ nop();
 
   // Generate code for deopt handler.
-  address handler_base = __ start_a_stub(deopt_handler_size);
+  address handler_base = __ start_a_stub(deopt_handler_size());
 
   if (handler_base == NULL) {
     // Not enough space left for the handler.
@@ -244,7 +244,7 @@
   int offset = code_offset();
   __ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type);
 
-  guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -1307,7 +1307,7 @@
 
 void LIR_Assembler::emit_static_call_stub() {
   address call_pc = __ pc();
-  address stub = __ start_a_stub(max_static_call_stub_size);
+  address stub = __ start_a_stub(static_call_stub_size());
   if (stub == NULL) {
     bailout("static call stub overflow");
     return;
@@ -1346,7 +1346,7 @@
     return;
   }
 
-  assert(__ offset() - start <= max_static_call_stub_size, "stub too big");
+  assert(__ offset() - start <= static_call_stub_size(), "stub too big");
   __ end_a_stub();
 }
 
diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp
index 543156c..ab4688e 100644
--- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp
@@ -60,10 +60,21 @@
   bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg);
 
 enum {
-  max_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size,
-  call_stub_size = max_static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
-  exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
-  deopt_handler_size = MacroAssembler::bl64_patchable_size
+  _static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, // or smaller
+  _call_stub_size = _static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
+  _call_aot_stub_size = 0,
+  _exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
+  _deopt_handler_size = MacroAssembler::bl64_patchable_size
 };
 
+  // '_static_call_stub_size' is only used on ppc (see LIR_Assembler::emit_static_call_stub()
+  // in c1_LIRAssembler_ppc.cpp. The other, shared getters are defined in c1_LIRAssembler.hpp
+  static int static_call_stub_size() {
+    if (UseAOT) {
+      return _static_call_stub_size + _call_aot_stub_size;
+    } else {
+      return _static_call_stub_size;
+    }
+  }
+
 #endif // CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP
diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp
index dc2c40d..377680a 100644
--- a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp
@@ -238,72 +238,15 @@
                                         int obj_size_in_bytes, int hdr_size_in_bytes) {
   const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize;
 
-  const int cl_size         = VM_Version::L1_data_cache_line_size(),
-            cl_dwords       = cl_size>>3,
-            cl_dw_addr_bits = exact_log2(cl_dwords);
-
-  const Register tmp = R0,
-                 base_ptr = tmp1,
-                 cnt_dwords = tmp2;
-
-  if (index <= 6) {
-    // Use explicit NULL stores.
-    if (index > 0) { li(tmp, 0); }
-    for (int i = 0; i < index; ++i) { std(tmp, hdr_size_in_bytes + i * HeapWordSize, obj); }
-
-  } else if (index < (2<<cl_dw_addr_bits)-1) {
-    // simple loop
-    Label loop;
-
-    li(cnt_dwords, index);
-    addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
-    li(tmp, 0);
-    mtctr(cnt_dwords);                      // Load counter.
-  bind(loop);
-    std(tmp, 0, base_ptr);                  // Clear 8byte aligned block.
-    addi(base_ptr, base_ptr, 8);
-    bdnz(loop);
-
+  // 2x unrolled loop is shorter with more than 9 HeapWords.
+  if (index <= 9) {
+    clear_memory_unrolled(obj, index, R0, hdr_size_in_bytes);
   } else {
-    // like clear_memory_doubleword
-    Label startloop, fast, fastloop, restloop, done;
+    const Register base_ptr = tmp1,
+                   cnt_dwords = tmp2;
 
-    addi(base_ptr, obj, hdr_size_in_bytes);           // Compute address of first element.
-    load_const_optimized(cnt_dwords, index);
-    rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
-    beq(CCR0, fast);                                  // Already 128byte aligned.
-
-    subfic(tmp, tmp, cl_dwords);
-    mtctr(tmp);                        // Set ctr to hit 128byte boundary (0<ctr<cl_dwords).
-    subf(cnt_dwords, tmp, cnt_dwords); // rest.
-    li(tmp, 0);
-
-  bind(startloop);                     // Clear at the beginning to reach 128byte boundary.
-    std(tmp, 0, base_ptr);             // Clear 8byte aligned block.
-    addi(base_ptr, base_ptr, 8);
-    bdnz(startloop);
-
-  bind(fast);                                  // Clear 128byte blocks.
-    srdi(tmp, cnt_dwords, cl_dw_addr_bits);    // Loop count for 128byte loop (>0).
-    andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords.
-    mtctr(tmp);                                // Load counter.
-
-  bind(fastloop);
-    dcbz(base_ptr);                    // Clear 128byte aligned block.
-    addi(base_ptr, base_ptr, cl_size);
-    bdnz(fastloop);
-
-    cmpdi(CCR0, cnt_dwords, 0);        // size 0?
-    beq(CCR0, done);                   // rest == 0
-    li(tmp, 0);
-    mtctr(cnt_dwords);                 // Load counter.
-
-  bind(restloop);                      // Clear rest.
-    std(tmp, 0, base_ptr);             // Clear 8byte aligned block.
-    addi(base_ptr, base_ptr, 8);
-    bdnz(restloop);
-
-  bind(done);
+    addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
+    clear_memory_doubleword(base_ptr, cnt_dwords, R0, index);
   }
 }
 
diff --git a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp
index 6ff77e0..4635ec7 100644
--- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp
@@ -37,7 +37,7 @@
 
 // ----------------------------------------------------------------------------
 
-// A PPC CompiledStaticCall looks like this:
+// A PPC CompiledDirectStaticCall looks like this:
 //
 // >>>> consts
 //
@@ -163,13 +163,13 @@
   return 5;
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub = find_stub();
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(/*is_aot*/ false);
   guarantee(stub != NULL, "stub not found");
 
   if (TraceICs) {
     ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                   p2i(instruction_address()),
                   callee->name_and_sig_as_C_string());
   }
@@ -196,7 +196,7 @@
   set_destination_mt_safe(stub);
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   // Reset stub.
   address stub = static_stub->addr();
@@ -212,15 +212,15 @@
 // Non-product mode code
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   // Verify call.
-  NativeCall::verify();
+  _call->verify();
   if (os::is_MP()) {
-    verify_alignment();
+    _call->verify_alignment();
   }
 
   // Verify stub.
-  address stub = find_stub();
+  address stub = find_stub(/*is_aot*/ false);
   assert(stub != NULL, "no stub found for static call");
   // Creation also verifies the object.
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + IC_pos_in_java_to_interp_stub);
diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp
index 953a4d2..4173008 100644
--- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp
@@ -77,7 +77,8 @@
 
 define_pd_global(bool, CompactStrings, true);
 
-define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
+// 2x unrolled loop is shorter with more than 9 HeapWords.
+define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong);
 
 // Platform dependent flag handling: flags only defined on this platform.
 #define ARCH_FLAGS(develop, \
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
index 110ed85..2d1f0c7 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
@@ -3332,53 +3332,90 @@
 }
 
 // Clear Array
+// For very short arrays. tmp == R0 is allowed.
+void MacroAssembler::clear_memory_unrolled(Register base_ptr, int cnt_dwords, Register tmp, int offset) {
+  if (cnt_dwords > 0) { li(tmp, 0); }
+  for (int i = 0; i < cnt_dwords; ++i) { std(tmp, offset + i * 8, base_ptr); }
+}
+
+// Version for constant short array length. Kills base_ptr. tmp == R0 is allowed.
+void MacroAssembler::clear_memory_constlen(Register base_ptr, int cnt_dwords, Register tmp) {
+  if (cnt_dwords < 8) {
+    clear_memory_unrolled(base_ptr, cnt_dwords, tmp);
+    return;
+  }
+
+  Label loop;
+  const long loopcnt   = cnt_dwords >> 1,
+             remainder = cnt_dwords & 1;
+
+  li(tmp, loopcnt);
+  mtctr(tmp);
+  li(tmp, 0);
+  bind(loop);
+    std(tmp, 0, base_ptr);
+    std(tmp, 8, base_ptr);
+    addi(base_ptr, base_ptr, 16);
+    bdnz(loop);
+  if (remainder) { std(tmp, 0, base_ptr); }
+}
+
 // Kills both input registers. tmp == R0 is allowed.
-void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) {
+void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp, long const_cnt) {
   // Procedure for large arrays (uses data cache block zero instruction).
     Label startloop, fast, fastloop, small_rest, restloop, done;
     const int cl_size         = VM_Version::L1_data_cache_line_size(),
-              cl_dwords       = cl_size>>3,
+              cl_dwords       = cl_size >> 3,
               cl_dw_addr_bits = exact_log2(cl_dwords),
-              dcbz_min        = 1;                     // Min count of dcbz executions, needs to be >0.
+              dcbz_min        = 1,  // Min count of dcbz executions, needs to be >0.
+              min_cnt         = ((dcbz_min + 1) << cl_dw_addr_bits) - 1;
 
-//2:
-    cmpdi(CCR1, cnt_dwords, ((dcbz_min+1)<<cl_dw_addr_bits)-1); // Big enough? (ensure >=dcbz_min lines included).
-    blt(CCR1, small_rest);                                      // Too small.
-    rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits);           // Extract dword offset within first cache line.
-    beq(CCR0, fast);                                            // Already 128byte aligned.
+  if (const_cnt >= 0) {
+    // Constant case.
+    if (const_cnt < min_cnt) {
+      clear_memory_constlen(base_ptr, const_cnt, tmp);
+      return;
+    }
+    load_const_optimized(cnt_dwords, const_cnt, tmp);
+  } else {
+    // cnt_dwords already loaded in register. Need to check size.
+    cmpdi(CCR1, cnt_dwords, min_cnt); // Big enough? (ensure >= dcbz_min lines included).
+    blt(CCR1, small_rest);
+  }
+    rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
+    beq(CCR0, fast);                                  // Already 128byte aligned.
 
     subfic(tmp, tmp, cl_dwords);
     mtctr(tmp);                        // Set ctr to hit 128byte boundary (0<ctr<cl_dwords).
     subf(cnt_dwords, tmp, cnt_dwords); // rest.
     li(tmp, 0);
-//10:
+
   bind(startloop);                     // Clear at the beginning to reach 128byte boundary.
     std(tmp, 0, base_ptr);             // Clear 8byte aligned block.
     addi(base_ptr, base_ptr, 8);
     bdnz(startloop);
-//13:
+
   bind(fast);                                  // Clear 128byte blocks.
     srdi(tmp, cnt_dwords, cl_dw_addr_bits);    // Loop count for 128byte loop (>0).
     andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords.
     mtctr(tmp);                                // Load counter.
-//16:
+
   bind(fastloop);
     dcbz(base_ptr);                    // Clear 128byte aligned block.
     addi(base_ptr, base_ptr, cl_size);
     bdnz(fastloop);
-    if (InsertEndGroupPPC64) { endgroup(); } else { nop(); }
-//20:
+
   bind(small_rest);
     cmpdi(CCR0, cnt_dwords, 0);        // size 0?
     beq(CCR0, done);                   // rest == 0
     li(tmp, 0);
     mtctr(cnt_dwords);                 // Load counter.
-//24:
+
   bind(restloop);                      // Clear rest.
     std(tmp, 0, base_ptr);             // Clear 8byte aligned block.
     addi(base_ptr, base_ptr, 8);
     bdnz(restloop);
-//27:
+
   bind(done);
 }
 
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
index 7763c86..11b966a 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
@@ -755,7 +755,9 @@
            is_trap_range_check_g(x) || is_trap_range_check_ge(x);
   }
 
-  void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0);
+  void clear_memory_unrolled(Register base_ptr, int cnt_dwords, Register tmp = R0, int offset = 0);
+  void clear_memory_constlen(Register base_ptr, int cnt_dwords, Register tmp = R0);
+  void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0, long const_cnt = -1);
 
 #ifdef COMPILER2
   // Intrinsics for CompactStrings
diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad
index 4c50b9b..a8c42b7 100644
--- a/hotspot/src/cpu/ppc/vm/ppc.ad
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad
@@ -965,10 +965,7 @@
 // is the number of bytes (not instructions) which will be inserted before
 // the instruction. The padding must match the size of a NOP instruction.
 
-int inlineCallClearArrayNode::compute_padding(int current_offset) const {
-  int desired_padding = (2*4-current_offset)&31; // see MacroAssembler::clear_memory_doubleword
-  return (desired_padding <= 3*4) ? desired_padding : 0;
-}
+// Currently not used on this platform.
 
 //=============================================================================
 
@@ -4066,6 +4063,14 @@
   interface(CONST_INTER);
 %}
 
+operand immLmax30() %{
+  predicate((n->get_long() <= 30));
+  match(ConL);
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Long Immediate: 16-bit
 operand immL16() %{
   predicate(Assembler::is_simm(n->get_long(), 16));
@@ -9580,6 +9585,19 @@
   ins_pipe(pipe_class_default);
 %}
 
+// Left shifted Immediate And
+instruct andI_reg_immIhi16(iRegIdst dst, iRegIsrc src1, immIhi16  src2, flagsRegCR0 cr0) %{
+  match(Set dst (AndI src1 src2));
+  effect(KILL cr0);
+  format %{ "ANDIS   $dst, $src1, $src2.hi" %}
+  size(4);
+  ins_encode %{
+    // TODO: PPC port $archOpcode(ppc64Opcode_andis_);
+    __ andis_($dst$$Register, $src1$$Register, (int)((unsigned short)(($src2$$constant & 0xFFFF0000) >> 16)));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
 // Immediate And
 instruct andI_reg_uimm16(iRegIdst dst, iRegIsrc src1, uimmI16 src2, flagsRegCR0 cr0) %{
   match(Set dst (AndI src1 src2));
@@ -11722,18 +11740,44 @@
   ins_pipe(pipe_class_default);
 %}
 
-// Clear-array with dynamic array-size.
-instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
+// Clear-array with constant short array length. The versions below can use dcbz with cnt > 30.
+instruct inlineCallClearArrayShort(immLmax30 cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
   match(Set dummy (ClearArray cnt base));
-  effect(USE_KILL cnt, USE_KILL base, KILL ctr);
-  ins_cost(MEMORY_REF_COST);
-
-  ins_alignment(4); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
+  effect(USE_KILL base, KILL ctr);
+  ins_cost(2 * MEMORY_REF_COST);
 
   format %{ "ClearArray $cnt, $base" %}
   ins_encode %{
     // TODO: PPC port $archOpcode(ppc64Opcode_compound);
-    __ clear_memory_doubleword($base$$Register, $cnt$$Register); // kills cnt, base, R0
+    __ clear_memory_constlen($base$$Register, $cnt$$constant, R0); // kills base, R0
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// Clear-array with constant large array length.
+instruct inlineCallClearArrayLarge(immL cnt, rarg2RegP base, Universe dummy, iRegLdst tmp, regCTR ctr) %{
+  match(Set dummy (ClearArray cnt base));
+  effect(USE_KILL base, TEMP tmp, KILL ctr);
+  ins_cost(3 * MEMORY_REF_COST);
+
+  format %{ "ClearArray $cnt, $base \t// KILL $tmp" %}
+  ins_encode %{
+    // TODO: PPC port $archOpcode(ppc64Opcode_compound);
+    __ clear_memory_doubleword($base$$Register, $tmp$$Register, R0, $cnt$$constant); // kills base, R0
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// Clear-array with dynamic array length.
+instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, regCTR ctr) %{
+  match(Set dummy (ClearArray cnt base));
+  effect(USE_KILL cnt, USE_KILL base, KILL ctr);
+  ins_cost(4 * MEMORY_REF_COST);
+
+  format %{ "ClearArray $cnt, $base" %}
+  ins_encode %{
+    // TODO: PPC port $archOpcode(ppc64Opcode_compound);
+    __ clear_memory_doubleword($base$$Register, $cnt$$Register, R0); // kills cnt, base, R0
   %}
   ins_pipe(pipe_class_default);
 %}
diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
index b7d5063..4299728 100644
--- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
@@ -153,7 +153,7 @@
   __ nop();
 
   // Generate code for exception handler.
-  address handler_base = __ start_a_stub(exception_handler_size);
+  address handler_base = __ start_a_stub(exception_handler_size());
   if (handler_base == NULL) {
     // Not enough space left for the handler.
     bailout("exception handler overflow");
@@ -166,7 +166,7 @@
   address call_addr = emit_call_c(a);
   CHECK_BAILOUT_(-1);
   __ should_not_reach_here();
-  guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -251,7 +251,7 @@
   __ nop();
 
   // Generate code for exception handler.
-  address handler_base = __ start_a_stub(deopt_handler_size);
+  address handler_base = __ start_a_stub(deopt_handler_size());
   if (handler_base == NULL) {
     // Not enough space left for the handler.
     bailout("deopt handler overflow");
@@ -260,7 +260,7 @@
   // Size must be constant (see HandlerImpl::emit_deopt_handler).
   __ load_const(Z_R1_scratch, SharedRuntime::deopt_blob()->unpack());
   __ call(Z_R1_scratch);
-  guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -1075,8 +1075,7 @@
       {
         if (UseCompressedOops && !wide) {
           Register compressed_src = Z_R14;
-          __ z_lgr(compressed_src, from->as_register());
-          __ encode_heap_oop(compressed_src);
+          __ oop_encoder(compressed_src, from->as_register(), true, (disp_reg != Z_R1) ? Z_R1 : Z_R0, -1, true);
           offset = code_offset();
           if (short_disp) {
             __ z_st(compressed_src,  disp_value, disp_reg, dest);
@@ -1158,7 +1157,7 @@
   // compiled code to calling interpreted code.
 
   address call_pc = __ pc();
-  address stub = __ start_a_stub(call_stub_size);
+  address stub = __ start_a_stub(call_stub_size());
   if (stub == NULL) {
     bailout("static call stub overflow");
     return;
@@ -1181,7 +1180,7 @@
   }
 
   __ z_br(Z_R1);
-  assert(__ offset() - start <= call_stub_size, "stub too big");
+  assert(__ offset() - start <= call_stub_size(), "stub too big");
   __ end_a_stub(); // Update current stubs pointer and restore insts_end.
 }
 
diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp
index eed0679..2414001 100644
--- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.hpp
@@ -46,9 +46,10 @@
   }
 
   enum {
-    call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub.
-    exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
-    deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
+    _call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub.
+    _call_aot_stub_size = 0,
+    _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
+    _deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
   };
 
 #endif // CPU_S390_VM_C1_LIRASSEMBLER_S390_HPP
diff --git a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp
index 33e383b..b183404 100644
--- a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp
@@ -90,19 +90,19 @@
   return 5; // 4 in emit_java_to_interp + 1 in Java_Static_Call
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub = find_stub();
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(/*is_aot*/ false);
   guarantee(stub != NULL, "stub not found");
 
   if (TraceICs) {
     ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                   p2i(instruction_address()),
                   callee->name_and_sig_as_C_string());
   }
 
   // Creation also verifies the object.
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
   NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
 
   // A generated lambda form might be deleted from the Lambdaform
@@ -123,13 +123,13 @@
   set_destination_mt_safe(stub);
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   // Reset stub.
   address stub = static_stub->addr();
   assert(stub != NULL, "stub not found");
   // Creation also verifies the object.
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
   NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
   method_holder->set_data(0);
   jump->set_jump_destination((address)-1);
@@ -139,18 +139,18 @@
 
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   // Verify call.
-  NativeCall::verify();
+  _call->verify();
   if (os::is_MP()) {
-    verify_alignment();
+    _call->verify_alignment();
   }
 
   // Verify stub.
-  address stub = find_stub();
+  address stub = find_stub(/*is_aot*/ false);
   assert(stub != NULL, "no stub found for static call");
   // Creation also verifies the object.
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + get_IC_pos_in_java_to_interp_stub());
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
   NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
 
   // Verify state.
diff --git a/hotspot/src/cpu/s390/vm/frame_s390.cpp b/hotspot/src/cpu/s390/vm/frame_s390.cpp
index 89a45c5..bf5cc5f 100644
--- a/hotspot/src/cpu/s390/vm/frame_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/frame_s390.cpp
@@ -156,7 +156,7 @@
   }
   own_abi()->return_pc = (uint64_t)pc;
   _cb = CodeCache::find_blob(pc);
-  address original_pc = nmethod::get_deopt_original_pc(this);
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     assert(original_pc == _pc, "expected original to be stored before patching");
     _deopt_state = is_deoptimized;
diff --git a/hotspot/src/cpu/s390/vm/frame_s390.inline.hpp b/hotspot/src/cpu/s390/vm/frame_s390.inline.hpp
index 9f56814..3231daf 100644
--- a/hotspot/src/cpu/s390/vm/frame_s390.inline.hpp
+++ b/hotspot/src/cpu/s390/vm/frame_s390.inline.hpp
@@ -39,7 +39,7 @@
 
   _fp = (intptr_t *) own_abi()->callers_sp;
 
-  address original_pc = nmethod::get_deopt_original_pc(this);
+  address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
     _deopt_state = is_deoptimized;
diff --git a/hotspot/src/cpu/s390/vm/globals_s390.hpp b/hotspot/src/cpu/s390/vm/globals_s390.hpp
index 707534a..fcd3ff4 100644
--- a/hotspot/src/cpu/s390/vm/globals_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp
@@ -92,9 +92,6 @@
   product(bool, ReoptimizeCallSequences, true,                                \
           "Reoptimize code-sequences of calls at runtime.")                   \
                                                                               \
-  product(bool, UseCountLeadingZerosInstruction, true,                        \
-          "Use count leading zeros instruction.")                             \
-                                                                              \
   product(bool, UseByteReverseInstruction, true,                              \
           "Use byte reverse instruction.")                                    \
                                                                               \
diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
index 73a9818..c954086 100644
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
@@ -574,6 +574,7 @@
   static int call_far_patchable_ret_addr_offset() { return call_far_patchable_size(); }
 
   static bool call_far_patchable_requires_alignment_nop(address pc) {
+    if (!os::is_MP()) return false;
     int size = call_far_patchable_size();
     return ((intptr_t)(pc + size) & 0x03L) != 0;
   }
diff --git a/hotspot/src/cpu/s390/vm/nativeInst_s390.cpp b/hotspot/src/cpu/s390/vm/nativeInst_s390.cpp
index d84785b..6d3eccd 100644
--- a/hotspot/src/cpu/s390/vm/nativeInst_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/nativeInst_s390.cpp
@@ -256,11 +256,7 @@
 address NativeFarCall::destination() {
   assert(MacroAssembler::is_call_far_patchable_at((address)this), "unexpected call type");
   address ctable = NULL;
-  if (MacroAssembler::call_far_patchable_requires_alignment_nop((address)this)) {
-    return MacroAssembler::get_dest_of_call_far_patchable_at(((address)this)+MacroAssembler::nop_size(), ctable);
-  } else {
-    return MacroAssembler::get_dest_of_call_far_patchable_at((address)this, ctable);
-  }
+  return MacroAssembler::get_dest_of_call_far_patchable_at((address)this, ctable);
 }
 
 
@@ -610,20 +606,20 @@
   unsigned long inst1;
   Assembler::get_instruction(l2, &inst1);
 
-  if (!Assembler::is_z_lb(inst1)                         &&
-      !Assembler::is_z_llgh(inst1)                       &&
-      !Assembler::is_z_lh(inst1)                         &&
-      !Assembler::is_z_l(inst1)                          &&
-      !Assembler::is_z_llgf(inst1)                       &&
-      !Assembler::is_z_lg(inst1)                         &&
-      !Assembler::is_z_le(inst1)                         &&
-      !Assembler::is_z_ld(inst1)                         &&
-      !Assembler::is_z_stc(inst1)                        &&
-      !Assembler::is_z_sth(inst1)                        &&
-      !Assembler::is_z_st(inst1)                         &&
-      !(Assembler::is_z_lgr(inst1) && UseCompressedOops) &&
-      !Assembler::is_z_stg(inst1)                        &&
-      !Assembler::is_z_ste(inst1)                        &&
+  if (!Assembler::is_z_lb(inst1)   &&
+      !Assembler::is_z_llgh(inst1) &&
+      !Assembler::is_z_lh(inst1)   &&
+      !Assembler::is_z_l(inst1)    &&
+      !Assembler::is_z_llgf(inst1) &&
+      !Assembler::is_z_lg(inst1)   &&
+      !Assembler::is_z_le(inst1)   &&
+      !Assembler::is_z_ld(inst1)   &&
+      !Assembler::is_z_stc(inst1)  &&
+      !Assembler::is_z_sth(inst1)  &&
+      !Assembler::is_z_st(inst1)   &&
+      !UseCompressedOops           &&
+      !Assembler::is_z_stg(inst1)  &&
+      !Assembler::is_z_ste(inst1)  &&
       !Assembler::is_z_std(inst1)) {
     tty->cr();
     tty->print_cr("NativeMovRegMem::verify(): verifying addr " PTR_FORMAT
diff --git a/hotspot/src/cpu/s390/vm/relocInfo_s390.cpp b/hotspot/src/cpu/s390/vm/relocInfo_s390.cpp
index 5ac5929..fd1437c 100644
--- a/hotspot/src/cpu/s390/vm/relocInfo_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/relocInfo_s390.cpp
@@ -102,11 +102,8 @@
     if (orig_addr == NULL) {
       call = nativeFarCall_at(inst_addr);
     } else {
-      if (MacroAssembler::is_call_far_patchable_pcrelative_at(inst_addr)) {
-        call = nativeFarCall_at(orig_addr);
-      } else {
-        call = nativeFarCall_at(orig_addr);  // must access location (in CP) where destination is stored in unmoved code, because load from CP is pc-relative
-      }
+      // must access location (in CP) where destination is stored in unmoved code, because load from CP is pc-relative
+      call = nativeFarCall_at(orig_addr);
     }
     return call->destination();
   }
diff --git a/hotspot/src/cpu/s390/vm/s390.ad b/hotspot/src/cpu/s390/vm/s390.ad
index 9385cbc..f242833 100644
--- a/hotspot/src/cpu/s390/vm/s390.ad
+++ b/hotspot/src/cpu/s390/vm/s390.ad
@@ -1489,8 +1489,8 @@
     case Op_CountLeadingZerosL:
     case Op_CountTrailingZerosI:
     case Op_CountTrailingZerosL:
-      // Implementation requires FLOGR instruction.
-      return UseCountLeadingZerosInstruction;
+      // Implementation requires FLOGR instruction, which is available since z9.
+      return true;
 
     case Op_ReverseBytesI:
     case Op_ReverseBytesL:
@@ -9897,7 +9897,6 @@
 
 // String IndexOfChar
 instruct indexOfChar_U(iRegP haystack, iRegI haycnt, iRegI ch, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
-  predicate(CompactStrings);
   match(Set result (StrIndexOfChar (Binary haystack haycnt) ch));
   effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
   ins_cost(200);
@@ -10590,7 +10589,6 @@
 instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
   match(Set dst (CountLeadingZerosI src));
   effect(KILL tmp, KILL cr);
-  predicate(UseCountLeadingZerosInstruction);  // See Matcher::match_rule_supported
   ins_cost(3 * DEFAULT_COST);
   size(14);
   format %{ "SLLG    $dst,$src,32\t# no need to always count 32 zeroes first\n\t"
@@ -10629,7 +10627,6 @@
 instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr) %{
   match(Set dst (CountLeadingZerosL src));
   effect(KILL tmp, KILL cr);
-  predicate(UseCountLeadingZerosInstruction);  // See Matcher::match_rule_supported
   ins_cost(DEFAULT_COST);
   size(4);
   format %{ "FLOGR   $dst,$src \t# count leading zeros (long)\n\t" %}
@@ -10655,7 +10652,6 @@
 instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
   match(Set dst (CountTrailingZerosI src));
   effect(TEMP_DEF dst, TEMP tmp, KILL cr);
-  predicate(UseCountLeadingZerosInstruction);  // See Matcher::match_rule_supported
   ins_cost(8 * DEFAULT_COST);
   // TODO: s390 port size(FIXED_SIZE);  // Emitted code depends on PreferLAoverADD being on/off.
   format %{ "LLGFR   $dst,$src  \t# clear upper 32 bits (we are dealing with int)\n\t"
@@ -10709,7 +10705,6 @@
 instruct countTrailingZerosL(revenRegI dst, iRegL src, roddRegL tmp, flagsReg cr) %{
   match(Set dst (CountTrailingZerosL src));
   effect(TEMP_DEF dst, KILL tmp, KILL cr);
-  predicate(UseCountLeadingZerosInstruction);  // See Matcher::match_rule_supported
   ins_cost(8 * DEFAULT_COST);
   // TODO: s390 port size(FIXED_SIZE);  // Emitted code depends on PreferLAoverADD being on/off.
   format %{ "LCGR    $dst,$src  \t# preserve src\n\t"
diff --git a/hotspot/src/cpu/s390/vm/templateTable_s390.cpp b/hotspot/src/cpu/s390/vm/templateTable_s390.cpp
index aa02fd1..83d707d 100644
--- a/hotspot/src/cpu/s390/vm/templateTable_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/templateTable_s390.cpp
@@ -3831,17 +3831,17 @@
 
   // Call runtime.
   __ z_llgc(Z_ARG2, at_bcp(1));   // type
-  // size in Z_tos
+  __ z_lgfr(Z_ARG3, Z_tos);       // size
   call_VM(Z_RET,
           CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray),
-          Z_ARG2, Z_tos);
+          Z_ARG2, Z_ARG3);
 }
 
 void TemplateTable::anewarray() {
   transition(itos, atos);
   __ get_2_byte_integer_at_bcp(Z_ARG3, 1, InterpreterMacroAssembler::Unsigned);
   __ get_constant_pool(Z_ARG2);
-  __ z_llgfr(Z_ARG4, Z_tos);
+  __ z_lgfr(Z_ARG4, Z_tos);
   call_VM(Z_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray),
           Z_ARG2, Z_ARG3, Z_ARG4);
 }
diff --git a/hotspot/src/cpu/s390/vm/vm_version_s390.cpp b/hotspot/src/cpu/s390/vm/vm_version_s390.cpp
index 37e1da9..7c40162 100644
--- a/hotspot/src/cpu/s390/vm/vm_version_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/vm_version_s390.cpp
@@ -271,6 +271,31 @@
     tty->print_cr("                oldest detected generation is %s", _features_string);
     _features_string = "z/Architecture (ambiguous detection)";
   }
+
+  if (has_Crypto_AES()) {
+    char buf[256];
+    assert(strlen(_features_string) + 4 + 3*4 + 1 < sizeof(buf), "increase buffer size");
+    jio_snprintf(buf, sizeof(buf), "%s aes%s%s%s", // String 'aes' must be surrounded by spaces so that jtreg tests recognize it.
+                 _features_string,
+                 has_Crypto_AES128() ? " 128" : "",
+                 has_Crypto_AES192() ? " 192" : "",
+                 has_Crypto_AES256() ? " 256" : "");
+    _features_string = os::strdup(buf);
+  }
+
+  if (has_Crypto_SHA()) {
+    char buf[256];
+    assert(strlen(_features_string) + 4 + 2 + 2*4 + 6 + 1 < sizeof(buf), "increase buffer size");
+    // String 'sha1' etc must be surrounded by spaces so that jtreg tests recognize it.
+    jio_snprintf(buf, sizeof(buf), "%s %s%s%s%s",
+                 _features_string,
+                 has_Crypto_SHA1()   ? " sha1"   : "",
+                 has_Crypto_SHA256() ? " sha256" : "",
+                 has_Crypto_SHA512() ? " sha512" : "",
+                 has_Crypto_GHASH()  ? " ghash"  : "");
+    if (has_Crypto_AES()) { os::free((void *)_features_string); }
+    _features_string = os::strdup(buf);
+  }
 }
 
 // featureBuffer - bit array indicating availability of various features
@@ -369,7 +394,7 @@
 
     if (has_Crypto()) {
       tty->cr();
-      tty->print_cr("detailled availability of %s capabilities:", "CryptoFacility");
+      tty->print_cr("detailed availability of %s capabilities:", "CryptoFacility");
       if (test_feature_bit(&_cipher_features[0], -1, 2*Cipher::_featureBits)) {
         tty->cr();
         tty->print_cr("  available: %s", "Message Cipher Functions");
@@ -479,7 +504,6 @@
   }
 }
 
-
 void VM_Version::set_features_z900(bool reset) {
   reset_features(reset);
 
diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
index a0f1982..97fb274 100644
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
@@ -287,7 +287,7 @@
   // generate code for exception handler
   ciMethod* method = compilation()->method();
 
-  address handler_base = __ start_a_stub(exception_handler_size);
+  address handler_base = __ start_a_stub(exception_handler_size());
 
   if (handler_base == NULL) {
     // not enough space left for the handler
@@ -300,7 +300,7 @@
   __ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
   __ delayed()->nop();
   __ should_not_reach_here();
-  guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -375,7 +375,7 @@
 
   // generate code for deopt handler
   ciMethod* method = compilation()->method();
-  address handler_base = __ start_a_stub(deopt_handler_size);
+  address handler_base = __ start_a_stub(deopt_handler_size());
   if (handler_base == NULL) {
     // not enough space left for the handler
     bailout("deopt handler overflow");
@@ -386,7 +386,7 @@
   AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
   __ JUMP(deopt_blob, G3_scratch, 0); // sethi;jmp
   __ delayed()->nop();
-  guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -1493,7 +1493,7 @@
 
 void LIR_Assembler::emit_static_call_stub() {
   address call_pc = __ pc();
-  address stub = __ start_a_stub(call_stub_size);
+  address stub = __ start_a_stub(call_stub_size());
   if (stub == NULL) {
     bailout("static call stub overflow");
     return;
@@ -1508,7 +1508,7 @@
   __ jump_to(addrlit, G3);
   __ delayed()->nop();
 
-  assert(__ offset() - start <= call_stub_size, "stub too big");
+  assert(__ offset() - start <= call_stub_size(), "stub too big");
   __ end_a_stub();
 }
 
diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp
index 1b13f28..c46d000 100644
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp
@@ -59,17 +59,20 @@
   // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot.
   void setup_md_access(ciMethod* method, int bci,
                        ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias);
+
+  enum {
+#ifdef _LP64
+    _call_stub_size = 68,
+#else
+    _call_stub_size = 20,
+#endif // _LP64
+    _call_aot_stub_size = 0,
+    _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
+    _deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
+  };
+
  public:
   void   pack64(LIR_Opr src, LIR_Opr dst);
   void unpack64(LIR_Opr src, LIR_Opr dst);
 
-enum {
-#ifdef _LP64
-         call_stub_size = 68,
-#else
-         call_stub_size = 20,
-#endif // _LP64
-         exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
-         deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)  };
-
 #endif // CPU_SPARC_VM_C1_LIRASSEMBLER_SPARC_HPP
diff --git a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp
index 4602434..3be40c8 100644
--- a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp
@@ -85,13 +85,13 @@
   return 10;  // 4 in emit_java_to_interp + 1 in Java_Static_Call
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub = find_stub();
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(/*is_aot*/ false);
   guarantee(stub != NULL, "stub not found");
 
   if (TraceICs) {
     ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                   p2i(instruction_address()),
                   callee->name_and_sig_as_C_string());
   }
@@ -118,7 +118,7 @@
   set_destination_mt_safe(stub);
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   // Reset stub.
   address stub = static_stub->addr();
@@ -134,15 +134,15 @@
 // Non-product mode code
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   // Verify call.
-  NativeCall::verify();
+  _call->verify();
   if (os::is_MP()) {
-    verify_alignment();
+    _call->verify_alignment();
   }
 
   // Verify stub.
-  address stub = find_stub();
+  address stub = find_stub(/*is_aot*/ false);
   assert(stub != NULL, "no stub found for static call");
   // Creation also verifies the object.
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp
index 51f7939..770ca6b 100644
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp
@@ -89,8 +89,18 @@
     if (is_niagara_plus()) {
       if (has_blk_init() && (cache_line_size > 0) && UseTLAB &&
           FLAG_IS_DEFAULT(AllocatePrefetchInstr)) {
-        // Use BIS instruction for TLAB allocation prefetch.
-        FLAG_SET_DEFAULT(AllocatePrefetchInstr, 1);
+        if (!has_sparc5_instr()) {
+          // Use BIS instruction for TLAB allocation prefetch
+          // on Niagara plus processors other than those based on CoreS4
+          FLAG_SET_DEFAULT(AllocatePrefetchInstr, 1);
+        } else {
+          // On CoreS4 processors use prefetch instruction
+          // to avoid partial RAW issue, also use prefetch style 3
+          FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0);
+          if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
+            FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
+          }
+        }
       }
       if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
         if (AllocatePrefetchInstr == 0) {
@@ -351,7 +361,7 @@
       FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
     }
   } else if (UseCRC32Intrinsics) {
-    warning("SPARC CRC32 intrinsics require VIS3 insructions support. Intriniscs will be disabled");
+    warning("SPARC CRC32 intrinsics require VIS3 instructions support. Intrinsics will be disabled");
     FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
   }
 
diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
index eb016ad..c819ffe 100644
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
@@ -4285,8 +4285,7 @@
 
 void Assembler::sha1rnds4(XMMRegister dst, XMMRegister src, int imm8) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, /* rex_w */ false);
   emit_int8((unsigned char)0xCC);
   emit_int8((unsigned char)(0xC0 | encode));
   emit_int8((unsigned char)imm8);
@@ -4294,24 +4293,21 @@
 
 void Assembler::sha1nexte(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xC8);
   emit_int8((unsigned char)(0xC0 | encode));
 }
 
 void Assembler::sha1msg1(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xC9);
   emit_int8((unsigned char)(0xC0 | encode));
 }
 
 void Assembler::sha1msg2(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xCA);
   emit_int8((unsigned char)(0xC0 | encode));
 }
@@ -4319,24 +4315,21 @@
 // xmm0 is implicit additional source to this instruction.
 void Assembler::sha256rnds2(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xCB);
   emit_int8((unsigned char)(0xC0 | encode));
 }
 
 void Assembler::sha256msg1(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xCC);
   emit_int8((unsigned char)(0xC0 | encode));
 }
 
 void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) {
   assert(VM_Version::supports_sha(), "");
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false);
-  int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
+  int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
   emit_int8((unsigned char)0xCD);
   emit_int8((unsigned char)(0xC0 | encode));
 }
diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
index 43e1e00..8aa4aec 100644
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
@@ -393,7 +393,7 @@
   __ nop();
 
   // generate code for exception handler
-  address handler_base = __ start_a_stub(exception_handler_size);
+  address handler_base = __ start_a_stub(exception_handler_size());
   if (handler_base == NULL) {
     // not enough space left for the handler
     bailout("exception handler overflow");
@@ -412,7 +412,7 @@
   // search an exception handler (rax: exception oop, rdx: throwing pc)
   __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
   __ should_not_reach_here();
-  guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -490,7 +490,7 @@
   __ nop();
 
   // generate code for exception handler
-  address handler_base = __ start_a_stub(deopt_handler_size);
+  address handler_base = __ start_a_stub(deopt_handler_size());
   if (handler_base == NULL) {
     // not enough space left for the handler
     bailout("deopt handler overflow");
@@ -502,7 +502,7 @@
 
   __ pushptr(here.addr());
   __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
-  guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
   __ end_a_stub();
 
   return offset;
@@ -2805,7 +2805,7 @@
 
 void LIR_Assembler::emit_static_call_stub() {
   address call_pc = __ pc();
-  address stub = __ start_a_stub(call_stub_size);
+  address stub = __ start_a_stub(call_stub_size());
   if (stub == NULL) {
     bailout("static call stub overflow");
     return;
@@ -2816,14 +2816,24 @@
     // make sure that the displacement word of the call ends up word aligned
     __ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size + NativeCall::displacement_offset);
   }
-  __ relocate(static_stub_Relocation::spec(call_pc));
+  __ relocate(static_stub_Relocation::spec(call_pc, false /* is_aot */));
   __ mov_metadata(rbx, (Metadata*)NULL);
   // must be set to -1 at code generation time
   assert(!os::is_MP() || ((__ offset() + 1) % BytesPerWord) == 0, "must be aligned on MP");
   // On 64bit this will die since it will take a movq & jmp, must be only a jmp
   __ jump(RuntimeAddress(__ pc()));
 
-  assert(__ offset() - start <= call_stub_size, "stub too big");
+  if (UseAOT) {
+    // Trampoline to aot code
+    __ relocate(static_stub_Relocation::spec(call_pc, true /* is_aot */));
+#ifdef _LP64
+    __ mov64(rax, CONST64(0));  // address is zapped till fixup time.
+#else
+    __ movl(rax, 0xdeadffff);  // address is zapped till fixup time.
+#endif
+    __ jmp(rax);
+  }
+  assert(__ offset() - start <= call_stub_size(), "stub too big");
   __ end_a_stub();
 }
 
diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
index f9514ed..680793b 100644
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
@@ -47,6 +47,14 @@
   void type_profile_helper(Register mdo,
                            ciMethodData *md, ciProfileData *data,
                            Register recv, Label* update_done);
+
+  enum {
+    _call_stub_size = NOT_LP64(15) LP64_ONLY(28),
+    _call_aot_stub_size = NOT_LP64(7) LP64_ONLY(12),
+    _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
+    _deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
+  };
+
 public:
 
   void store_parameter(Register r,  int offset_from_esp_in_words);
@@ -54,9 +62,4 @@
   void store_parameter(jobject c,   int offset_from_esp_in_words);
   void store_parameter(Metadata* c, int offset_from_esp_in_words);
 
-  enum { call_stub_size = NOT_LP64(15) LP64_ONLY(28),
-         exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
-         deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
-       };
-
 #endif // CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
diff --git a/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp b/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp
new file mode 100644
index 0000000..6b71150
--- /dev/null
+++ b/hotspot/src/cpu/x86/vm/compiledIC_aot_x86_64.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "aot/compiledIC_aot.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+
+void CompiledDirectStaticCall::set_to_far(const methodHandle& callee, address entry) {
+  address stub = find_stub(true /* is_far */);
+  guarantee(stub != NULL, "stub not found");
+
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_far %s",
+                  p2i(instruction_address()),
+                  callee->name_and_sig_as_C_string());
+  }
+
+  // Creation also verifies the object.
+  // mov rax,imm_aot_addr
+  // jmp rax
+  NativeMovConstReg* destination_holder = nativeMovConstReg_at(stub);
+
+#ifdef ASSERT
+  // read the value once
+  intptr_t data = destination_holder->data();
+  assert(data == 0 || data == (intptr_t)entry,
+         "MT-unsafe modification of inline cache");
+#endif
+
+  // Update stub.
+  destination_holder->set_data((intptr_t)entry);
+
+  // Update jump to call.
+  set_destination_mt_safe(stub);
+}
+
+void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub();
+  guarantee(stub != NULL, "stub not found");
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("CompiledPltStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+                  p2i(instruction_address()),
+                  callee->name_and_sig_as_C_string());
+  }
+
+  // Creation also verifies the object.
+  NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+  NativeGotJump* jump          = nativeGotJump_at(method_loader->next_instruction_address());
+
+  intptr_t data = method_loader->data();
+  address destination = jump->destination();
+  assert(data == 0 || data == (intptr_t)callee(),
+         "a) MT-unsafe modification of inline cache");
+  assert(destination == (address)-1 || destination == entry,
+         "b) MT-unsafe modification of inline cache");
+
+  // Update stub.
+  method_loader->set_data((intptr_t)callee());
+  jump->set_jump_destination(entry);
+
+  // Update jump to call.
+  set_destination_mt_safe(stub);
+}
+
+#ifdef NEVER_CALLED
+void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  // Reset stub.
+  address stub = static_stub->addr();
+  assert(stub != NULL, "stub not found");
+  // Creation also verifies the object.
+  NativeLoadGot* method_loader = nativeLoadGot_at(stub);
+  NativeGotJump* jump          = nativeGotJump_at(method_loader->next_instruction_address());
+  method_loader->set_data(0);
+  jump->set_jump_destination((address)-1);
+}
+#endif
+
+#ifndef PRODUCT
+void CompiledPltStaticCall::verify() {
+  // Verify call.
+  _call->verify();
+
+#ifdef ASSERT
+  CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
+  assert(cb && cb->is_aot(), "CompiledPltStaticCall can only be used on AOTCompiledMethod");
+#endif
+
+  // Verify stub.
+  address stub = find_stub();
+  assert(stub != NULL, "no stub found for static call");
+  // Creation also verifies the object.
+  NativeLoadGot*     method_loader = nativeLoadGot_at(stub);
+  NativeGotJump*     jump          = nativeGotJump_at(method_loader->next_instruction_address());
+  // Verify state.
+  assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+#endif // !PRODUCT
diff --git a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp
index 6d4c06f..0e8f146 100644
--- a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "asm/macroAssembler.inline.hpp"
+#include "code/codeCache.hpp"
 #include "code/compiledIC.hpp"
 #include "code/icBuffer.hpp"
 #include "code/nmethod.hpp"
@@ -53,7 +54,7 @@
     return NULL;  // CodeBuffer::expand failed.
   }
   // Static stub relocation stores the instruction address of the call.
-  __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
+  __ relocate(static_stub_Relocation::spec(mark, false), Assembler::imm_operand);
   // Static stub relocation also tags the Method* in the code-stream.
   __ mov_metadata(rbx, (Metadata*) NULL);  // Method is zapped till fixup time.
   // This is recognized as unresolved by relocs/nativeinst/ic code.
@@ -77,13 +78,73 @@
   return 4; // 3 in emit_to_interp_stub + 1 in emit_call
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub = find_stub();
+#if INCLUDE_AOT
+#define __ _masm.
+void CompiledStaticCall::emit_to_aot_stub(CodeBuffer &cbuf, address mark) {
+  if (!UseAOT) {
+    return;
+  }
+  // Stub is fixed up when the corresponding call is converted from
+  // calling compiled code to calling aot code.
+  // movq rax, imm64_aot_code_address
+  // jmp  rax
+
+  if (mark == NULL) {
+    mark = cbuf.insts_mark();  // Get mark within main instrs section.
+  }
+
+  // Note that the code buffer's insts_mark is always relative to insts.
+  // That's why we must use the macroassembler to generate a stub.
+  MacroAssembler _masm(&cbuf);
+
+  address base =
+  __ start_a_stub(to_aot_stub_size());
+  guarantee(base != NULL, "out of space");
+
+  // Static stub relocation stores the instruction address of the call.
+  __ relocate(static_stub_Relocation::spec(mark, true /* is_aot */), Assembler::imm_operand);
+  // Load destination AOT code address.
+#ifdef _LP64
+  __ mov64(rax, CONST64(0));  // address is zapped till fixup time.
+#else
+  __ movl(rax, 0);  // address is zapped till fixup time.
+#endif
+  // This is recognized as unresolved by relocs/nativeinst/ic code.
+  __ jmp(rax);
+
+  assert(__ pc() - base <= to_aot_stub_size(), "wrong stub size");
+
+  // Update current stubs pointer and restore insts_end.
+  __ end_a_stub();
+}
+#undef __
+
+int CompiledStaticCall::to_aot_stub_size() {
+  if (UseAOT) {
+    return NOT_LP64(7)    // movl; jmp
+           LP64_ONLY(12);  // movq (1+1+8); jmp (2)
+  } else {
+    return 0;
+  }
+}
+
+// Relocation entries for call stub, compiled java to aot.
+int CompiledStaticCall::reloc_to_aot_stub() {
+  if (UseAOT) {
+    return 2; // 1 in emit_to_aot_stub + 1 in emit_call
+  } else {
+    return 0;
+  }
+}
+#endif // INCLUDE_AOT
+
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
+  address stub = find_stub(false /* is_aot */);
   guarantee(stub != NULL, "stub not found");
 
   if (TraceICs) {
     ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+    tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
                   p2i(instruction_address()),
                   callee->name_and_sig_as_C_string());
   }
@@ -110,7 +171,7 @@
   set_destination_mt_safe(stub);
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   // Reset stub.
   address stub = static_stub->addr();
@@ -118,8 +179,10 @@
   // Creation also verifies the object.
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
   method_holder->set_data(0);
-  NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
-  jump->set_jump_destination((address)-1);
+  if (!static_stub->is_aot()) {
+    NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+    jump->set_jump_destination((address)-1);
+  }
 }
 
 
@@ -127,15 +190,20 @@
 // Non-product mode code
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   // Verify call.
-  NativeCall::verify();
+  _call->verify();
   if (os::is_MP()) {
-    verify_alignment();
+    _call->verify_alignment();
   }
 
+#ifdef ASSERT
+  CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
+  assert(cb && !cb->is_aot(), "CompiledDirectStaticCall cannot be used on AOTCompiledMethod");
+#endif
+
   // Verify stub.
-  address stub = find_stub();
+  address stub = find_stub(false /* is_aot */);
   assert(stub != NULL, "no stub found for static call");
   // Creation also verifies the object.
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
diff --git a/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp b/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp
index dc45fa7..58451eb 100644
--- a/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/icBuffer_x86.cpp
@@ -33,12 +33,18 @@
 #include "oops/oop.inline.hpp"
 
 int InlineCacheBuffer::ic_stub_code_size() {
-  return NativeMovConstReg::instruction_size +
-         NativeJump::instruction_size +
-         1;
-  // so that code_end can be set in CodeBuffer
-  // 64bit 16 = 5 + 10 bytes + 1 byte
-  // 32bit 11 = 10 bytes + 1 byte
+  // Worst case, if destination is not a near call:
+  // lea rax, lit1
+  // lea scratch, lit2
+  // jmp scratch
+
+  // Best case
+  // lea rax, lit1
+  // jmp lit2
+
+  int best = NativeMovConstReg::instruction_size + NativeJump::instruction_size;
+  int worst = 2 * NativeMovConstReg::instruction_size + 3;
+  return MAX2(best, worst);
 }
 
 
@@ -59,8 +65,16 @@
 
 address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) {
   NativeMovConstReg* move = nativeMovConstReg_at(code_begin);   // creation also verifies the object
-  NativeJump*        jump = nativeJump_at(move->next_instruction_address());
-  return jump->jump_destination();
+  address jmp = move->next_instruction_address();
+  NativeInstruction* ni = nativeInstruction_at(jmp);
+  if (ni->is_jump()) {
+    NativeJump*        jump = nativeJump_at(jmp);
+    return jump->jump_destination();
+  } else {
+    assert(ni->is_far_jump(), "unexpected instruction");
+    NativeFarJump*     jump = nativeFarJump_at(jmp);
+    return jump->jump_destination();
+  }
 }
 
 
@@ -68,7 +82,14 @@
   // creation also verifies the object
   NativeMovConstReg* move = nativeMovConstReg_at(code_begin);
   // Verifies the jump
-  NativeJump*        jump = nativeJump_at(move->next_instruction_address());
+  address jmp = move->next_instruction_address();
+  NativeInstruction* ni = nativeInstruction_at(jmp);
+  if (ni->is_jump()) {
+    NativeJump*        jump = nativeJump_at(jmp);
+  } else {
+    assert(ni->is_far_jump(), "unexpected instruction");
+    NativeFarJump*     jump = nativeFarJump_at(jmp);
+  }
   void* o = (void*)move->data();
   return o;
 }
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
index 99286ea..3d4dee7 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -10773,16 +10773,13 @@
   // save length for return
   push(len);
 
-  // 8165287: EVEX version disabled for now, needs to be refactored as
-  // it is returning incorrect results.
   if ((UseAVX > 2) && // AVX512
-    0 &&
     VM_Version::supports_avx512vlbw() &&
     VM_Version::supports_bmi2()) {
 
     set_vector_masking();  // opening of the stub context for programming mask registers
 
-    Label copy_32_loop, copy_loop_tail, copy_just_portion_of_candidates;
+    Label copy_32_loop, copy_loop_tail, restore_k1_return_zero;
 
     // alignement
     Label post_alignement;
@@ -10797,16 +10794,16 @@
     movl(result, 0x00FF);
     evpbroadcastw(tmp2Reg, result, Assembler::AVX_512bit);
 
-    testl(len, -64);
-    jcc(Assembler::zero, post_alignement);
-
     // Save k1
     kmovql(k3, k1);
 
+    testl(len, -64);
+    jcc(Assembler::zero, post_alignement);
+
     movl(tmp5, dst);
-    andl(tmp5, (64 - 1));
+    andl(tmp5, (32 - 1));
     negl(tmp5);
-    andl(tmp5, (64 - 1));
+    andl(tmp5, (32 - 1));
 
     // bail out when there is nothing to be done
     testl(tmp5, 0xFFFFFFFF);
@@ -10816,13 +10813,12 @@
     movl(result, 0xFFFFFFFF);
     shlxl(result, result, tmp5);
     notl(result);
-
     kmovdl(k1, result);
 
     evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
     evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
     ktestd(k2, k1);
-    jcc(Assembler::carryClear, copy_just_portion_of_candidates);
+    jcc(Assembler::carryClear, restore_k1_return_zero);
 
     evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
 
@@ -10835,7 +10831,7 @@
     // end of alignement
 
     movl(tmp5, len);
-    andl(tmp5, (32 - 1));   // tail count (in chars)
+    andl(tmp5, (32 - 1));    // tail count (in chars)
     andl(len, ~(32 - 1));    // vector count (in chars)
     jcc(Assembler::zero, copy_loop_tail);
 
@@ -10847,7 +10843,7 @@
     evmovdquw(tmp1Reg, Address(src, len, Address::times_2), Assembler::AVX_512bit);
     evpcmpuw(k2, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
     kortestdl(k2, k2);
-    jcc(Assembler::carryClear, copy_just_portion_of_candidates);
+    jcc(Assembler::carryClear, restore_k1_return_zero);
 
     // All elements in current processed chunk are valid candidates for
     // compression. Write a truncated byte elements to the memory.
@@ -10858,11 +10854,10 @@
     bind(copy_loop_tail);
     // bail out when there is nothing to be done
     testl(tmp5, 0xFFFFFFFF);
+    // Restore k1
+    kmovql(k1, k3);
     jcc(Assembler::zero, return_length);
 
-    // Save k1
-    kmovql(k3, k1);
-
     movl(len, tmp5);
 
     // ~(~0 << len), where len is the # of remaining elements to process
@@ -10875,30 +10870,16 @@
     evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
     evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
     ktestd(k2, k1);
-    jcc(Assembler::carryClear, copy_just_portion_of_candidates);
+    jcc(Assembler::carryClear, restore_k1_return_zero);
 
     evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
     // Restore k1
     kmovql(k1, k3);
-
     jmp(return_length);
 
-    bind(copy_just_portion_of_candidates);
-    kmovdl(tmp5, k2);
-    tzcntl(tmp5, tmp5);
-
-    // ~(~0 << tmp5), where tmp5 is a number of elements in an array from the
-    // result to the first element larger than 0xFF
-    movl(result, 0xFFFFFFFF);
-    shlxl(result, result, tmp5);
-    notl(result);
-
-    kmovdl(k1, result);
-
-    evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
+    bind(restore_k1_return_zero);
     // Restore k1
     kmovql(k1, k3);
-
     jmp(return_zero);
 
     clear_vector_masking();   // closing of the stub context for programming mask registers
diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp
index 26c6f33..cb8c08f 100644
--- a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp
@@ -39,6 +39,124 @@
   ICache::invalidate_word(addr_at(offset));
 }
 
+void NativeLoadGot::report_and_fail() const {
+  tty->print_cr("Addr: " INTPTR_FORMAT, p2i(instruction_address()));
+  fatal("not a indirect rip mov to rbx");
+}
+
+void NativeLoadGot::verify() const {
+  if (has_rex) {
+    int rex = ubyte_at(0);
+    if (rex != rex_prefix) {
+      report_and_fail();
+    }
+  }
+
+  int inst = ubyte_at(rex_size);
+  if (inst != instruction_code) {
+    report_and_fail();
+  }
+  int modrm = ubyte_at(rex_size + 1);
+  if (modrm != modrm_rbx_code && modrm != modrm_rax_code) {
+    report_and_fail();
+  }
+}
+
+intptr_t NativeLoadGot::data() const {
+  return *(intptr_t *) got_address();
+}
+
+address NativePltCall::destination() const {
+  NativeGotJump* jump = nativeGotJump_at(plt_jump());
+  return jump->destination();
+}
+
+address NativePltCall::plt_entry() const {
+  return return_address() + displacement();
+}
+
+address NativePltCall::plt_jump() const {
+  address entry = plt_entry();
+  // Virtual PLT code has move instruction first
+  if (((NativeGotJump*)entry)->is_GotJump()) {
+    return entry;
+  } else {
+    return nativeLoadGot_at(entry)->next_instruction_address();
+  }
+}
+
+address NativePltCall::plt_load_got() const {
+  address entry = plt_entry();
+  if (!((NativeGotJump*)entry)->is_GotJump()) {
+    // Virtual PLT code has move instruction first
+    return entry;
+  } else {
+    // Static PLT code has move instruction second (from c2i stub)
+    return nativeGotJump_at(entry)->next_instruction_address();
+  }
+}
+
+address NativePltCall::plt_c2i_stub() const {
+  address entry = plt_load_got();
+  // This method should be called only for static calls which has C2I stub.
+  NativeLoadGot* load = nativeLoadGot_at(entry);
+  return entry;
+}
+
+address NativePltCall::plt_resolve_call() const {
+  NativeGotJump* jump = nativeGotJump_at(plt_jump());
+  address entry = jump->next_instruction_address();
+  if (((NativeGotJump*)entry)->is_GotJump()) {
+    return entry;
+  } else {
+    // c2i stub 2 instructions
+    entry = nativeLoadGot_at(entry)->next_instruction_address();
+    return nativeGotJump_at(entry)->next_instruction_address();
+  }
+}
+
+void NativePltCall::reset_to_plt_resolve_call() {
+  set_destination_mt_safe(plt_resolve_call());
+}
+
+void NativePltCall::set_destination_mt_safe(address dest) {
+  // rewriting the value in the GOT, it should always be aligned
+  NativeGotJump* jump = nativeGotJump_at(plt_jump());
+  address* got = (address *) jump->got_address();
+  *got = dest;
+}
+
+void NativePltCall::set_stub_to_clean() {
+  NativeLoadGot* method_loader = nativeLoadGot_at(plt_c2i_stub());
+  NativeGotJump* jump          = nativeGotJump_at(method_loader->next_instruction_address());
+  method_loader->set_data(0);
+  jump->set_jump_destination((address)-1);
+}
+
+void NativePltCall::verify() const {
+  // Make sure code pattern is actually a call rip+off32 instruction.
+  int inst = ubyte_at(0);
+  if (inst != instruction_code) {
+    tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
+                                                        inst);
+    fatal("not a call rip+off32");
+  }
+}
+
+address NativeGotJump::destination() const {
+  address *got_entry = (address *) got_address();
+  return *got_entry;
+}
+
+void NativeGotJump::verify() const {
+  int inst = ubyte_at(0);
+  if (inst != instruction_code) {
+    tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
+                                                        inst);
+    fatal("not a indirect rip jump");
+  }
+}
+
 void NativeCall::verify() {
   // Make sure code pattern is actually a call imm32 instruction.
   int inst = ubyte_at(0);
@@ -422,7 +540,12 @@
 
 void NativeJump::verify() {
   if (*(u_char*)instruction_address() != instruction_code) {
-    fatal("not a jump instruction");
+    // far jump
+    NativeMovConstReg* mov = nativeMovConstReg_at(instruction_address());
+    NativeInstruction* jmp = nativeInstruction_at(mov->next_instruction_address());
+    if (!jmp->is_jump_reg()) {
+      fatal("not a jump instruction");
+    }
   }
 }
 
@@ -514,6 +637,20 @@
 
 }
 
+address NativeFarJump::jump_destination() const          {
+  NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0));
+  return (address)mov->data();
+}
+
+void NativeFarJump::verify() {
+  if (is_far_jump()) {
+    NativeMovConstReg* mov = nativeMovConstReg_at(addr_at(0));
+    NativeInstruction* jmp = nativeInstruction_at(mov->next_instruction_address());
+    if (jmp->is_jump_reg()) return;
+  }
+  fatal("not a jump instruction");
+}
+
 void NativePopReg::insert(address code_pos, Register reg) {
   assert(reg->encoding() < 8, "no space for REX");
   assert(NativePopReg::instruction_size == sizeof(char), "right address unit for update");
diff --git a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp
index 1bb1c6c..7db3ccb 100644
--- a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp
@@ -38,6 +38,7 @@
 // - - NativeMovRegMem
 // - - NativeMovRegMemPatching
 // - - NativeJump
+// - - NativeFarJump
 // - - NativeIllegalOpCode
 // - - NativeGeneralJump
 // - - NativeReturn
@@ -63,6 +64,8 @@
   inline bool is_illegal();
   inline bool is_return();
   inline bool is_jump();
+  inline bool is_jump_reg();
+  inline bool is_far_jump();
   inline bool is_cond_jump();
   inline bool is_safepoint_poll();
   inline bool is_mov_literal64();
@@ -105,6 +108,47 @@
   return inst;
 }
 
+class NativePltCall: public NativeInstruction {
+public:
+  enum Intel_specific_constants {
+    instruction_code           = 0xE8,
+    instruction_size           =    5,
+    instruction_offset         =    0,
+    displacement_offset        =    1,
+    return_address_offset      =    5
+  };
+  address instruction_address() const { return addr_at(instruction_offset); }
+  address next_instruction_address() const { return addr_at(return_address_offset); }
+  address displacement_address() const { return addr_at(displacement_offset); }
+  int displacement() const { return (jint) int_at(displacement_offset); }
+  address return_address() const { return addr_at(return_address_offset); }
+  address destination() const;
+  address plt_entry() const;
+  address plt_jump() const;
+  address plt_load_got() const;
+  address plt_resolve_call() const;
+  address plt_c2i_stub() const;
+  void set_stub_to_clean();
+
+  void  reset_to_plt_resolve_call();
+  void  set_destination_mt_safe(address dest);
+
+  void verify() const;
+};
+
+inline NativePltCall* nativePltCall_at(address address) {
+  NativePltCall* call = (NativePltCall*) address;
+#ifdef ASSERT
+  call->verify();
+#endif
+  return call;
+}
+
+inline NativePltCall* nativePltCall_before(address addr) {
+  address at = addr - NativePltCall::instruction_size;
+  return nativePltCall_at(at);
+}
+
 inline NativeCall* nativeCall_at(address address);
 // The NativeCall is an abstraction for accessing/manipulating native call imm32/rel32off
 // instructions (used to manipulate inline caches, primitive & dll calls, etc.).
@@ -129,9 +173,8 @@
   address destination() const;
   void  set_destination(address dest)       {
 #ifdef AMD64
-    assert((labs((intptr_t) dest - (intptr_t) return_address())  &
-            0xFFFFFFFF00000000) == 0,
-           "must be 32bit offset");
+    intptr_t disp = dest - return_address();
+    guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset");
 #endif // AMD64
     set_int_at(displacement_offset, dest - return_address());
   }
@@ -158,6 +201,13 @@
       nativeCall_at(instr)->destination() == target;
   }
 
+#if INCLUDE_AOT
+  static bool is_far_call(address instr, address target) {
+    intptr_t disp = target - (instr + sizeof(int32_t));
+    return !Assembler::is_simm32(disp);
+  }
+#endif
+
   // MT-safe patching of a call instruction.
   static void insert(address code_pos, address entry);
 
@@ -380,6 +430,51 @@
   }
 };
 
+// destination is rbx or rax
+// mov rbx, [rip + offset]
+class NativeLoadGot: public NativeInstruction {
+#ifdef AMD64
+  static const bool has_rex = true;
+  static const int rex_size = 1;
+#else
+  static const bool has_rex = false;
+  static const int rex_size = 0;
+#endif
+public:
+  enum Intel_specific_constants {
+    rex_prefix = 0x48,
+    instruction_code = 0x8b,
+    modrm_rbx_code = 0x1d,
+    modrm_rax_code = 0x05,
+    instruction_length = 6 + rex_size,
+    offset_offset = 2 + rex_size
+  };
+
+  address instruction_address() const { return addr_at(0); }
+  address rip_offset_address() const { return addr_at(offset_offset); }
+  int rip_offset() const { return int_at(offset_offset); }
+  address return_address() const { return addr_at(instruction_length); }
+  address got_address() const { return return_address() + rip_offset(); }
+  address next_instruction_address() const { return return_address(); }
+  intptr_t data() const;
+  void set_data(intptr_t data) {
+    intptr_t *addr = (intptr_t *) got_address();
+    *addr = data;
+  }
+
+  void verify() const;
+private:
+  void report_and_fail() const;
+};
+
+inline NativeLoadGot* nativeLoadGot_at(address addr) {
+  NativeLoadGot* load = (NativeLoadGot*) addr;
+#ifdef ASSERT
+  load->verify();
+#endif
+  return load;
+}
+
 // jump rel32off
 
 class NativeJump: public NativeInstruction {
@@ -440,6 +535,29 @@
   return jump;
 }
 
+// far jump reg
+class NativeFarJump: public NativeInstruction {
+ public:
+  address jump_destination() const;
+
+  // Creation
+  inline friend NativeFarJump* nativeFarJump_at(address address);
+
+  void verify();
+
+  // Unit testing stuff
+  static void test() {}
+
+};
+
+inline NativeFarJump* nativeFarJump_at(address address) {
+  NativeFarJump* jump = (NativeFarJump*)(address);
+#ifdef ASSERT
+  jump->verify();
+#endif
+  return jump;
+}
+
 // Handles all kinds of jump on Intel. Long/far, conditional/unconditional
 class NativeGeneralJump: public NativeInstruction {
  public:
@@ -473,6 +591,36 @@
   return jump;
 }
 
+class NativeGotJump: public NativeInstruction {
+public:
+  enum Intel_specific_constants {
+    instruction_code = 0xff,
+    instruction_offset = 0,
+    instruction_size = 6,
+    rip_offset = 2
+  };
+
+  void verify() const;
+  address instruction_address() const { return addr_at(instruction_offset); }
+  address destination() const;
+  address return_address() const { return addr_at(instruction_size); }
+  int got_offset() const { return (jint) int_at(rip_offset); }
+  address got_address() const { return return_address() + got_offset(); }
+  address next_instruction_address() const { return addr_at(instruction_size); }
+  bool is_GotJump() const { return ubyte_at(0) == instruction_code; }
+
+  void set_jump_destination(address dest)  {
+    address *got_entry = (address *) got_address();
+    *got_entry = dest;
+  }
+};
+
+inline NativeGotJump* nativeGotJump_at(address addr) {
+  NativeGotJump* jump = (NativeGotJump*)(addr);
+  debug_only(jump->verify());
+  return jump;
+}
+
 class NativePopReg : public NativeInstruction {
  public:
   enum Intel_specific_constants {
@@ -544,6 +692,12 @@
                                                           ubyte_at(0) == NativeReturnX::instruction_code; }
 inline bool NativeInstruction::is_jump()         { return ubyte_at(0) == NativeJump::instruction_code ||
                                                           ubyte_at(0) == 0xEB; /* short jump */ }
+inline bool NativeInstruction::is_jump_reg()     {
+  int pos = 0;
+  if (ubyte_at(0) == Assembler::REX_B) pos = 1;
+  return ubyte_at(pos) == 0xFF && (ubyte_at(pos + 1) & 0xF0) == 0xE0;
+}
+inline bool NativeInstruction::is_far_jump()     { return is_mov_literal64(); }
 inline bool NativeInstruction::is_cond_jump()    { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ ||
                                                           (ubyte_at(0) & 0xF0) == 0x70;  /* short jump */ }
 inline bool NativeInstruction::is_safepoint_poll() {
diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
index 180a3ab..195c681 100644
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
@@ -800,7 +800,7 @@
   __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset())));
 
 #if INCLUDE_JVMCI
-  if (EnableJVMCI) {
+  if (EnableJVMCI || UseAOT) {
     // check if this call should be routed towards a specific entry point
     __ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0);
     Label no_alternative_target;
@@ -2758,7 +2758,7 @@
   // Setup code generation tools
   int pad = 0;
 #if INCLUDE_JVMCI
-  if (EnableJVMCI) {
+  if (EnableJVMCI || UseAOT) {
     pad += 512; // Increase the buffer size when compiling for JVMCI
   }
 #endif
@@ -2832,7 +2832,7 @@
   int implicit_exception_uncommon_trap_offset = 0;
   int uncommon_trap_offset = 0;
 
-  if (EnableJVMCI) {
+  if (EnableJVMCI || UseAOT) {
     implicit_exception_uncommon_trap_offset = __ pc() - start;
 
     __ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
@@ -2947,7 +2947,7 @@
   __ reset_last_Java_frame(false);
 
 #if INCLUDE_JVMCI
-  if (EnableJVMCI) {
+  if (EnableJVMCI || UseAOT) {
     __ bind(after_fetch_unroll_info_call);
   }
 #endif
@@ -3112,7 +3112,7 @@
   _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
   _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
 #if INCLUDE_JVMCI
-  if (EnableJVMCI) {
+  if (EnableJVMCI || UseAOT) {
     _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
     _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
   }
diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp
index c52be1e..d32917a 100644
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp
@@ -3857,7 +3857,7 @@
       StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table;
       StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul);
     }
-    if (VM_Version::supports_sse2() && UseLibmIntrinsic) {
+    if (VM_Version::supports_sse2() && UseLibmIntrinsic && InlineIntrinsics) {
       if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) ||
           vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) ||
           vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) {
diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
index 7ffe08b..1853cf9 100644
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
@@ -5017,7 +5017,7 @@
       StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table;
       StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul);
     }
-    if (VM_Version::supports_sse2() && UseLibmIntrinsic) {
+    if (VM_Version::supports_sse2() && UseLibmIntrinsic && InlineIntrinsics) {
       if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) ||
           vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) ||
           vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) {
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
index e82c70d..eb5661b 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
@@ -256,7 +256,7 @@
 #if INCLUDE_JVMCI
   // Check if we need to take lock at entry of synchronized method.  This can
   // only occur on method entry so emit it only for vtos with step 0.
-  if (UseJVMCICompiler && state == vtos && step == 0) {
+  if ((UseJVMCICompiler || UseAOT) && state == vtos && step == 0) {
     Label L;
     __ cmpb(Address(thread, JavaThread::pending_monitorenter_offset()), 0);
     __ jcc(Assembler::zero, L);
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp
index 98b52c7..8614031 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp
@@ -342,6 +342,9 @@
   //        [ hi(arg) ]
   //
   if (kind == Interpreter::java_lang_math_fmaD) {
+    if (!UseFMA) {
+      return NULL; // Generate a vanilla entry
+    }
     __ movdbl(xmm2, Address(rsp, 5 * wordSize));
     __ movdbl(xmm1, Address(rsp, 3 * wordSize));
     __ movdbl(xmm0, Address(rsp, 1 * wordSize));
@@ -352,6 +355,9 @@
 
     return entry_point;
   } else if (kind == Interpreter::java_lang_math_fmaF) {
+    if (!UseFMA) {
+      return NULL; // Generate a vanilla entry
+    }
     __ movflt(xmm2, Address(rsp, 3 * wordSize));
     __ movflt(xmm1, Address(rsp, 2 * wordSize));
     __ movflt(xmm0, Address(rsp, 1 * wordSize));
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp
index 6cdf3c6..99e859f 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp
@@ -370,11 +370,17 @@
   //
 
   if (kind == Interpreter::java_lang_math_fmaD) {
+    if (!UseFMA) {
+      return NULL; // Generate a vanilla entry
+    }
     __ movdbl(xmm0, Address(rsp, wordSize));
     __ movdbl(xmm1, Address(rsp, 3 * wordSize));
     __ movdbl(xmm2, Address(rsp, 5 * wordSize));
     __ fmad(xmm0, xmm1, xmm2, xmm0);
   } else if (kind == Interpreter::java_lang_math_fmaF) {
+    if (!UseFMA) {
+      return NULL; // Generate a vanilla entry
+    }
     __ movflt(xmm0, Address(rsp, wordSize));
     __ movflt(xmm1, Address(rsp, 2 * wordSize));
     __ movflt(xmm2, Address(rsp, 3 * wordSize));
diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
index 93c6e58..7bed107 100644
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
@@ -65,6 +65,7 @@
     const int      CPU_FAMILY_SHIFT = 8;
     const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
     const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
+    bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
 
     Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
     Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup;
@@ -358,36 +359,39 @@
     __ cmpl(rax, 0xE0);
     __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
 
-    // EVEX setup: run in lowest evex mode
-    VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
-    UseAVX = 3;
-    UseSSE = 2;
+    // If UseAVX is unitialized or is set by the user to include EVEX
+    if (use_evex) {
+      // EVEX setup: run in lowest evex mode
+      VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
+      UseAVX = 3;
+      UseSSE = 2;
 #ifdef _WINDOWS
-    // xmm5-xmm15 are not preserved by caller on windows
-    // https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
-    __ subptr(rsp, 64);
-    __ evmovdqul(Address(rsp, 0), xmm7, Assembler::AVX_512bit);
+      // xmm5-xmm15 are not preserved by caller on windows
+      // https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
+      __ subptr(rsp, 64);
+      __ evmovdqul(Address(rsp, 0), xmm7, Assembler::AVX_512bit);
 #ifdef _LP64
-    __ subptr(rsp, 64);
-    __ evmovdqul(Address(rsp, 0), xmm8, Assembler::AVX_512bit);
-    __ subptr(rsp, 64);
-    __ evmovdqul(Address(rsp, 0), xmm31, Assembler::AVX_512bit);
+      __ subptr(rsp, 64);
+      __ evmovdqul(Address(rsp, 0), xmm8, Assembler::AVX_512bit);
+      __ subptr(rsp, 64);
+      __ evmovdqul(Address(rsp, 0), xmm31, Assembler::AVX_512bit);
 #endif // _LP64
 #endif // _WINDOWS
 
-    // load value into all 64 bytes of zmm7 register
-    __ movl(rcx, VM_Version::ymm_test_value());
-    __ movdl(xmm0, rcx);
-    __ movl(rcx, 0xffff);
-    __ kmovwl(k1, rcx);
-    __ evpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
-    __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
+      // load value into all 64 bytes of zmm7 register
+      __ movl(rcx, VM_Version::ymm_test_value());
+      __ movdl(xmm0, rcx);
+      __ movl(rcx, 0xffff);
+      __ kmovwl(k1, rcx);
+      __ evpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
+      __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
 #ifdef _LP64
-    __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit);
-    __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit);
+      __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit);
+      __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit);
 #endif
-    VM_Version::clean_cpuFeatures();
-    __ jmp(save_restore_except);
+      VM_Version::clean_cpuFeatures();
+      __ jmp(save_restore_except);
+    }
 
     __ bind(legacy_setup);
     // AVX setup
@@ -441,32 +445,35 @@
     __ cmpl(rax, 0xE0);
     __ jccb(Assembler::notEqual, legacy_save_restore);
 
-    // EVEX check: run in lowest evex mode
-    VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
-    UseAVX = 3;
-    UseSSE = 2;
-    __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset())));
-    __ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit);
-    __ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit);
+    // If UseAVX is unitialized or is set by the user to include EVEX
+    if (use_evex) {
+      // EVEX check: run in lowest evex mode
+      VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
+      UseAVX = 3;
+      UseSSE = 2;
+      __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset())));
+      __ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit);
+      __ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit);
 #ifdef _LP64
-    __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit);
-    __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit);
+      __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit);
+      __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit);
 #endif
 
 #ifdef _WINDOWS
 #ifdef _LP64
-    __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit);
-    __ addptr(rsp, 64);
-    __ evmovdqul(xmm8, Address(rsp, 0), Assembler::AVX_512bit);
-    __ addptr(rsp, 64);
+      __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit);
+      __ addptr(rsp, 64);
+      __ evmovdqul(xmm8, Address(rsp, 0), Assembler::AVX_512bit);
+      __ addptr(rsp, 64);
 #endif // _LP64
-    __ evmovdqul(xmm7, Address(rsp, 0), Assembler::AVX_512bit);
-    __ addptr(rsp, 64);
+      __ evmovdqul(xmm7, Address(rsp, 0), Assembler::AVX_512bit);
+      __ addptr(rsp, 64);
 #endif // _WINDOWS
-    VM_Version::clean_cpuFeatures();
-    UseAVX = saved_useavx;
-    UseSSE = saved_usesse;
-    __ jmp(wrapup);
+      VM_Version::clean_cpuFeatures();
+      UseAVX = saved_useavx;
+      UseSSE = saved_usesse;
+      __ jmp(wrapup);
+    }
 
     __ bind(legacy_save_restore);
     // AVX check
diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad
index dd8e5be..99ae5f5 100644
--- a/hotspot/src/cpu/x86/vm/x86_64.ad
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad
@@ -2147,6 +2147,9 @@
         ciEnv::current()->record_failure("CodeCache is full");
         return;
       }
+#if INCLUDE_AOT
+      CompiledStaticCall::emit_to_aot_stub(cbuf, mark);
+#endif
     }
   %}
 
diff --git a/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp
index 8f912db..1dbe952 100644
--- a/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp
+++ b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp
@@ -60,11 +60,11 @@
   return 0;
 }
 
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
   ShouldNotReachHere(); // Only needed for COMPILER2.
 }
 
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
   ShouldNotReachHere(); // Only needed for COMPILER2.
 }
 
@@ -72,7 +72,7 @@
 // Non-product mode code.
 #ifndef PRODUCT
 
-void CompiledStaticCall::verify() {
+void CompiledDirectStaticCall::verify() {
   ShouldNotReachHere(); // Only needed for COMPILER2.
 }
 
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
new file mode 100644
index 0000000..7be7a80
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+
+/**
+ * A format-agnostic container class that holds various components of a binary.
+ *
+ * <p>
+ * This class holds information necessary to create platform-specific binary containers such as
+ * ELFContainer for Linux and Solaris operating systems or yet-to be created MachOContainer for Mac
+ * OS or PEContainer for MS Windows operating systems.
+ *
+ * <p>
+ * Method APIs provided by this class are used to construct and populate platform-independent
+ * contents of a binary as the first step to create a binary representation of code generated by a
+ * compiler backend such as Graal.
+ *
+ * <p>
+ * Methods to record and access code section contents, symbols and relocations are provided.
+ */
+public class BinaryContainer implements SymbolTable {
+
+    private final int codeSegmentSize;
+
+    private final int codeEntryAlignment;
+
+    /**
+     * Container holding code bits and any other related information.
+     */
+    private final CodeContainer codeContainer;
+
+    /**
+     * Container holding external hotspot linkage bits (PLT entries).
+     */
+    private final CodeContainer extLinkageContainer;
+
+    /**
+     * Container holding global offset data for hotspot linkage.
+     */
+    private final ByteContainer extLinkageGOTContainer;
+
+    /**
+     * Patched by HotSpot, contains metaspace pointers.
+     */
+    private final ByteContainer metaspaceGotContainer;
+
+    /**
+     * Patched lazily by hotspot, contains klass/method pointers.
+     */
+    private final ByteContainer metadataGotContainer;
+
+    /**
+     * BSS container, contains method state array.
+     */
+    private final ByteContainer methodStateContainer;
+
+    /**
+     * Patched by hotspot, contains java object pointers.
+     */
+    private final ByteContainer oopGotContainer;
+
+    // Containers holding read-only data
+    private final ReadOnlyDataContainer configContainer;
+    private final ReadOnlyDataContainer metaspaceNamesContainer;
+    private final ReadOnlyDataContainer methodsOffsetsContainer;
+    private final ReadOnlyDataContainer klassesOffsetsContainer;
+    private final ReadOnlyDataContainer klassesDependenciesContainer;
+    private final HeaderContainer headerContainer;
+    private final ReadOnlyDataContainer stubsOffsetsContainer;
+    private final ReadOnlyDataContainer codeSegmentsContainer;
+
+    // This cannot be read only since we need to patch the metadata at runtime..
+    private final ReadOnlyDataContainer methodMetadataContainer;
+
+    /**
+     * Container containing constant data used by code.
+     */
+    private final ReadOnlyDataContainer constantDataContainer;
+
+    /**
+     * Map holding the Strings table.
+     */
+    private final Map<String, Integer> offsetStringTable = new HashMap<>();
+
+    private final Map<String, Integer> metaspaceNames = new HashMap<>();
+
+    // List of relocation table entries - (symbolName, relocationInfo)
+    private final Map<String, Symbol> symbolTable = new HashMap<>();
+    private final Map<Symbol, List<Relocation>> relocationTable = new HashMap<>();
+    private final Map<Symbol, Relocation> uniqueRelocationTable = new HashMap<>();
+
+    /**
+     * Mapping of local VM function names to known global symbols generated in the output binary.
+     */
+    private static final HashMap<String, String> functionNamesToAOTSymbols = new HashMap<>();
+
+    private static final String[][] map = {
+//@formatter:off
+        {"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack",        "_aot_deopt_blob_unpack"},
+        {"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"},
+        {"CompilerToVM::Data::SharedRuntime_ic_miss_stub",             "_aot_ic_miss_stub"},
+        {"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"},
+        {"SharedRuntime::exception_handler_for_return_address",        "_aot_exception_handler_for_return_address"},
+        {"SharedRuntime::register_finalizer",                          "_aot_register_finalizer"},
+        {"SharedRuntime::OSR_migration_end",                           "_aot_OSR_migration_end"},
+        {"CompilerRuntime::resolve_string_by_symbol",                  "_aot_resolve_string_by_symbol"},
+        {"CompilerRuntime::resolve_klass_by_symbol",                   "_aot_resolve_klass_by_symbol"},
+        {"CompilerRuntime::resolve_method_by_symbol_and_load_counters","_aot_resolve_method_by_symbol_and_load_counters"},
+        {"CompilerRuntime::initialize_klass_by_symbol",                "_aot_initialize_klass_by_symbol"},
+        {"CompilerRuntime::invocation_event",                          "_aot_invocation_event"},
+        {"CompilerRuntime::backedge_event",                            "_aot_backedge_event"},
+
+        {"CompilerToVM::Data::dpow", "_aot_shared_runtime_dpow"},
+        {"CompilerToVM::Data::dexp", "_aot_shared_runtime_dexp"},
+        {"CompilerToVM::Data::dcos", "_aot_shared_runtime_dcos"},
+        {"CompilerToVM::Data::dsin", "_aot_shared_runtime_dsin"},
+        {"CompilerToVM::Data::dtan", "_aot_shared_runtime_dtan"},
+        {"CompilerToVM::Data::dlog", "_aot_shared_runtime_dlog"},
+        {"CompilerToVM::Data::dlog10", "_aot_shared_runtime_dlog10"},
+
+        {"StubRoutines::_jbyte_arraycopy", "_aot_stub_routines_jbyte_arraycopy"},
+        {"StubRoutines::_jshort_arraycopy", "_aot_stub_routines_jshort_arraycopy"},
+        {"StubRoutines::_jint_arraycopy", "_aot_stub_routines_jint_arraycopy"},
+        {"StubRoutines::_jlong_arraycopy", "_aot_stub_routines_jlong_arraycopy"},
+        {"StubRoutines::_oop_arraycopy", "_aot_stub_routines_oop_arraycopy"},
+        {"StubRoutines::_oop_arraycopy_uninit", "_aot_stub_routines_oop_arraycopy_uninit"},
+
+        {"StubRoutines::_jbyte_disjoint_arraycopy", "_aot_stub_routines_jbyte_disjoint_arraycopy"},
+        {"StubRoutines::_jshort_disjoint_arraycopy", "_aot_stub_routines_jshort_disjoint_arraycopy"},
+        {"StubRoutines::_jint_disjoint_arraycopy", "_aot_stub_routines_jint_disjoint_arraycopy"},
+        {"StubRoutines::_jlong_disjoint_arraycopy", "_aot_stub_routines_jlong_disjoint_arraycopy"},
+        {"StubRoutines::_oop_disjoint_arraycopy", "_aot_stub_routines_oop_disjoint_arraycopy"},
+        {"StubRoutines::_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_oop_disjoint_arraycopy_uninit"},
+
+        {"StubRoutines::_arrayof_jbyte_arraycopy", "_aot_stub_routines_arrayof_jbyte_arraycopy"},
+        {"StubRoutines::_arrayof_jshort_arraycopy", "_aot_stub_routines_arrayof_jshort_arraycopy"},
+        {"StubRoutines::_arrayof_jint_arraycopy", "_aot_stub_routines_arrayof_jint_arraycopy"},
+        {"StubRoutines::_arrayof_jlong_arraycopy", "_aot_stub_routines_arrayof_jlong_arraycopy"},
+        {"StubRoutines::_arrayof_oop_arraycopy", "_aot_stub_routines_arrayof_oop_arraycopy"},
+        {"StubRoutines::_arrayof_oop_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_arraycopy_uninit"},
+
+        {"StubRoutines::_arrayof_jbyte_disjoint_arraycopy", "_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy"},
+        {"StubRoutines::_arrayof_jshort_disjoint_arraycopy", "_aot_stub_routines_arrayof_jshort_disjoint_arraycopy"},
+        {"StubRoutines::_arrayof_jint_disjoint_arraycopy", "_aot_stub_routines_arrayof_jint_disjoint_arraycopy"},
+        {"StubRoutines::_arrayof_jlong_disjoint_arraycopy", "_aot_stub_routines_arrayof_jlong_disjoint_arraycopy"},
+        {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
+        {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
+
+        {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
+
+
+
+
+        {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
+        {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
+        {"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
+        {"StubRoutines::_cipherBlockChaining_decryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_decryptAESCrypt"},
+        {"StubRoutines::_updateBytesCRC32", "_aot_stub_routines_update_bytes_crc32"},
+        {"StubRoutines::_crc_table_adr", "_aot_stub_routines_crc_table_adr"},
+
+        {"StubRoutines::_sha1_implCompress", "_aot_stub_routines_sha1_implCompress" },
+        {"StubRoutines::_sha1_implCompressMB", "_aot_stub_routines_sha1_implCompressMB" },
+        {"StubRoutines::_sha256_implCompress", "_aot_stub_routines_sha256_implCompress" },
+        {"StubRoutines::_sha256_implCompressMB", "_aot_stub_routines_sha256_implCompressMB" },
+        {"StubRoutines::_sha512_implCompress", "_aot_stub_routines_sha512_implCompress" },
+        {"StubRoutines::_sha512_implCompressMB", "_aot_stub_routines_sha512_implCompressMB" },
+        {"StubRoutines::_multiplyToLen", "_aot_stub_routines_multiplyToLen" },
+
+        {"StubRoutines::_counterMode_AESCrypt", "_aot_stub_routines_counterMode_AESCrypt" },
+        {"StubRoutines::_ghash_processBlocks", "_aot_stub_routines_ghash_processBlocks" },
+        {"StubRoutines::_crc32c_table_addr", "_aot_stub_routines_crc32c_table_addr" },
+        {"StubRoutines::_updateBytesCRC32C", "_aot_stub_routines_updateBytesCRC32C" },
+        {"StubRoutines::_updateBytesAdler32", "_aot_stub_routines_updateBytesAdler32" },
+        {"StubRoutines::_squareToLen", "_aot_stub_routines_squareToLen" },
+        {"StubRoutines::_mulAdd", "_aot_stub_routines_mulAdd" },
+        {"StubRoutines::_montgomeryMultiply", "_aot_stub_routines_montgomeryMultiply" },
+        {"StubRoutines::_montgomerySquare", "_aot_stub_routines_montgomerySquare" },
+        {"StubRoutines::_vectorizedMismatch", "_aot_stub_routines_vectorizedMismatch" },
+
+        {"StubRoutines::_throw_delayed_StackOverflowError_entry", "_aot_stub_routines_throw_delayed_StackOverflowError_entry" },
+
+
+        {"os::javaTimeMillis", "_aot_os_javaTimeMillis"},
+        {"os::javaTimeNanos", "_aot_os_javaTimeNanos"},
+
+        {"JVMCIRuntime::monitorenter", "_aot_jvmci_runtime_monitorenter"},
+        {"JVMCIRuntime::monitorexit", "_aot_jvmci_runtime_monitorexit"},
+        {"JVMCIRuntime::log_object", "_aot_jvmci_runtime_log_object"},
+        {"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"},
+        {"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"},
+        {"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"},
+        {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"},
+        {"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"},
+        {"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"},
+        {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"},
+        {"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"},
+        {"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"},
+        {"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"},
+        {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"},
+        {"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"},
+        {"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"},
+        {"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"},
+
+        {"JVMCIRuntime::throw_and_post_jvmti_exception",      "_aot_jvmci_runtime_throw_and_post_jvmti_exception"},
+        {"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"},
+        {"JVMCIRuntime::throw_class_cast_exception",          "_aot_jvmci_runtime_throw_class_cast_exception"},
+
+        {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"},
+        {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"}
+        //@formatter:on
+    };
+
+    static {
+        for (String[] entry : map) {
+            functionNamesToAOTSymbols.put(entry[0], entry[1]);
+        }
+    }
+
+    /**
+     * Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
+     * prefix {@code prefix}. It also initializes internal code container, symbol table and
+     * relocation tables.
+     */
+    public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) {
+        this.codeSegmentSize = config.codeSegmentSize;
+        this.codeEntryAlignment = config.codeEntryAlignment;
+
+        // read only, code
+        codeContainer = new CodeContainer(".text", this);
+        extLinkageContainer = new CodeContainer(".hotspot.linkage.plt", this);
+
+        // read only, info
+        configContainer = new ReadOnlyDataContainer(".config", this);
+        metaspaceNamesContainer = new ReadOnlyDataContainer(".metaspace.names", this);
+        methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this);
+        klassesOffsetsContainer = new ReadOnlyDataContainer(".klasses.offsets", this);
+        klassesDependenciesContainer = new ReadOnlyDataContainer(".klasses.dependencies", this);
+
+        headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
+        stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
+        codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
+        constantDataContainer = new ReadOnlyDataContainer(".method.constdata", this);
+
+        // needs relocation patching at load time by the loader
+        methodMetadataContainer = new ReadOnlyDataContainer(".method.metadata", this);
+
+        // writable sections
+        metaspaceGotContainer = new ByteContainer(".metaspace.got", this);
+        metadataGotContainer = new ByteContainer(".metadata.got", this);
+        methodStateContainer = new ByteContainer(".method.state", this);
+        oopGotContainer = new ByteContainer(".oop.got", this);
+        extLinkageGOTContainer = new ByteContainer(".hotspot.linkage.got", this);
+
+        addGlobalSymbols();
+
+        recordConfiguration(config);
+    }
+
+    private void recordConfiguration(GraalHotSpotVMConfig config) {
+        // @formatter:off
+        boolean[] booleanFlags = { config.cAssertions, // Debug VM
+                                   config.useCompressedOops,
+                                   config.useCompressedClassPointers,
+                                   config.compactFields,
+                                   config.useG1GC,
+                                   config.useCMSGC,
+                                   config.useTLAB,
+                                   config.useBiasedLocking,
+                                   TieredAOT.getValue(),
+                                   config.enableContended,
+                                   config.restrictContended,
+        };
+
+        int[] intFlags         = { config.narrowOopShift,
+                                   config.narrowKlassShift,
+                                   config.contendedPaddingWidth,
+                                   config.fieldsAllocationStyle,
+                                   config.objectAlignment,
+                                   config.codeSegmentSize,
+        };
+        // @formatter:on
+
+        byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags);
+        int size0 = configContainer.getByteStreamSize();
+
+        // @formatter:off
+        int computedSize = booleanFlagsAsBytes.length * Byte.BYTES    + // size of boolean flags
+                           intFlags.length            * Integer.BYTES + // size of int flags
+                           Integer.BYTES;                               // size of the "computedSize"
+
+        configContainer.appendInt(computedSize).
+                        appendInts(intFlags).
+                        appendBytes(booleanFlagsAsBytes);
+        // @formatter:on
+
+        int size = configContainer.getByteStreamSize() - size0;
+        assert size == computedSize;
+    }
+
+    private static byte[] flagsToByteArray(boolean[] flags) {
+        byte[] byteArray = new byte[flags.length];
+        for (int i = 0; i < flags.length; ++i) {
+            byteArray[i] = boolToByte(flags[i]);
+        }
+        return byteArray;
+    }
+
+    private static byte boolToByte(boolean flag) {
+        return (byte) (flag ? 1 : 0);
+    }
+
+    /**
+     * Free some memory.
+     */
+    public void freeMemory() {
+        offsetStringTable.clear();
+        metaspaceNames.clear();
+    }
+
+    /*
+     * Global symbol names in generated DSO corresponding to VM's symbols. VM needs to look up this
+     * symbol in DSO and link it with VM's corresponding symbol: store VM's symbol address or value
+     * in the named GOT cell.
+     */
+
+    public String getCardTableAddressSymbolName() {
+        return "_aot_card_table_address";
+    }
+
+    public String getHeapTopAddressSymbolName() {
+        return "_aot_heap_top_address";
+    }
+
+    public String getHeapEndAddressSymbolName() {
+        return "_aot_heap_end_address";
+    }
+
+    public String getCrcTableAddressSymbolName() {
+        return "_aot_stub_routines_crc_table_adr";
+    }
+
+    public String getPollingPageSymbolName() {
+        return "_aot_polling_page";
+    }
+
+    public String getResolveStaticEntrySymbolName() {
+        return "_resolve_static_entry";
+    }
+
+    public String getResolveVirtualEntrySymbolName() {
+        return "_resolve_virtual_entry";
+    }
+
+    public String getResolveOptVirtualEntrySymbolName() {
+        return "_resolve_opt_virtual_entry";
+    }
+
+    public String getNarrowKlassBaseAddressSymbolName() {
+        return "_aot_narrow_klass_base_address";
+    }
+
+    public String getLogOfHeapRegionGrainBytesSymbolName() {
+        return "_aot_log_of_heap_region_grain_bytes";
+    }
+
+    public String getInlineContiguousAllocationSupportedSymbolName() {
+        return "_aot_inline_contiguous_allocation_supported";
+    }
+
+    public int getCodeSegmentSize() {
+        return codeSegmentSize;
+    }
+
+    public int getCodeEntryAlignment() {
+        return codeEntryAlignment;
+    }
+
+    /**
+     * Gets the global AOT symbol associated with the function name.
+     *
+     * @param functionName function name
+     * @return AOT symbol for the given function name, or null if there is no mapping.
+     */
+    public String getAOTSymbolForVMFunctionName(String functionName) {
+        return functionNamesToAOTSymbols.get(functionName);
+    }
+
+    private void addGlobalSymbols() {
+        // Create global symbols for all containers.
+        createContainerSymbol(codeContainer);
+        createContainerSymbol(configContainer);
+        createContainerSymbol(methodsOffsetsContainer);
+        createContainerSymbol(klassesOffsetsContainer);
+        createContainerSymbol(klassesDependenciesContainer);
+        createContainerSymbol(metaspaceGotContainer);
+        createContainerSymbol(metadataGotContainer);
+        createContainerSymbol(methodStateContainer);
+        createContainerSymbol(oopGotContainer);
+        createContainerSymbol(metaspaceNamesContainer);
+        createContainerSymbol(methodMetadataContainer);
+        createContainerSymbol(stubsOffsetsContainer);
+        createContainerSymbol(headerContainer.getContainer());
+        createContainerSymbol(codeSegmentsContainer);
+
+        createGotSymbol(getResolveStaticEntrySymbolName());
+        createGotSymbol(getResolveVirtualEntrySymbolName());
+        createGotSymbol(getResolveOptVirtualEntrySymbolName());
+        createGotSymbol(getCardTableAddressSymbolName());
+        createGotSymbol(getHeapTopAddressSymbolName());
+        createGotSymbol(getHeapEndAddressSymbolName());
+        createGotSymbol(getNarrowKlassBaseAddressSymbolName());
+        createGotSymbol(getPollingPageSymbolName());
+        createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
+        createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
+
+        for (HashMap.Entry<String, String> entry : functionNamesToAOTSymbols.entrySet()) {
+            createGotSymbol(entry.getValue());
+        }
+    }
+
+    /**
+     * Creates a global symbol of the form {@code "JVM" + container name}.
+     *
+     * @param container container to create a symbol for
+     */
+    private static void createContainerSymbol(ByteContainer container) {
+        container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName());
+    }
+
+    /**
+     * Creates a global GOT symbol of the form {@code "got." + name}.
+     *
+     * @param name name for the GOT symbol
+     */
+    private void createGotSymbol(String name) {
+        String s = "got." + name;
+        Symbol gotSymbol = extLinkageGOTContainer.createGotSymbol(s);
+        extLinkageGOTContainer.createSymbol(gotSymbol.getOffset(), Kind.OBJECT, Binding.GLOBAL, 8, name);
+    }
+
+    /**
+     * Create a platform-specific binary file representing the content of the
+     * {@code BinaryContainer} object.
+     *
+     * This method is called after creating and performing any necessary changes to the contents of
+     * code stream, symbol tables and relocation tables is completely finalized
+     *
+     * @param outputFileName name of output file
+     *
+     * @throws IOException in case of file creation failure
+     */
+    public void createBinary(String outputFileName, String aotVersion) throws IOException {
+        String osName = System.getProperty("os.name");
+        switch (osName) {
+            case "Linux":
+            case "SunOS":
+                JELFRelocObject elfso = new JELFRelocObject(this, outputFileName, aotVersion);
+                elfso.createELFRelocObject(relocationTable, symbolTable.values());
+                break;
+            default:
+                throw new InternalError("Unsupported platform: " + osName);
+        }
+    }
+
+    /**
+     * Add symbol to the symbol table. If the existing symbol is undefined and the specified symbol
+     * is not undefined, replace the existing symbol information with that specified.
+     *
+     * @param symInfo symbol information to be added
+     */
+    public void addSymbol(Symbol symInfo) {
+        if (symInfo.getName().startsWith("got.") && !(symInfo instanceof GotSymbol)) {
+            throw new InternalError("adding got. without being GotSymbol");
+        }
+        if (symbolTable.containsKey(symInfo.getName())) {
+            throw new InternalError("Symbol: " + symInfo.getName() + " already exists in SymbolTable");
+        } else {
+            // System.out.println("# Symbol [" + name + "] [" + symInfo.getValue() + "] [" +
+            // symInfo.getSection().getContainerName() + "] [" + symInfo.getSize() + "]");
+            symbolTable.put(symInfo.getName(), symInfo);
+        }
+    }
+
+    public boolean addStringOffset(String name, Integer offset) {
+        offsetStringTable.put(name, offset);
+        return true;
+    }
+
+    /**
+     * Add relocation entry for {@code symName}. Multiple relocation entries for a given symbol may
+     * exist.
+     *
+     * @param info relocation information to be added
+     */
+    public void addRelocation(Relocation info) {
+        // System.out.println("# Relocation [" + symName + "] [" + info.getOffset() + "] [" +
+        // info.getSection().getContainerName() + "] [" + info.getSymbol().getName() + "] [" +
+        // info.getSymbol().getOffset() + " @ " + info.getSymbol().getSection().getContainerName() +
+        // "]");
+        if (relocationTable.containsKey(info.getSymbol())) {
+            relocationTable.get(info.getSymbol()).add(info);
+        } else if (uniqueRelocationTable.containsKey(info.getSymbol())) {
+            // promote
+            ArrayList<Relocation> list = new ArrayList<>(2);
+            list.add(uniqueRelocationTable.get(info.getSymbol()));
+            list.add(info);
+            relocationTable.put(info.getSymbol(), list);
+            uniqueRelocationTable.remove(info.getSymbol());
+        } else {
+            uniqueRelocationTable.put(info.getSymbol(), info);
+        }
+    }
+
+    /**
+     * Get symbol with name {@code symName}.
+     *
+     * @param symName name of symbol for which symbol table information is being queried
+     * @return success or failure of insertion operation
+     */
+    @Override
+    public Symbol getSymbol(String symName) {
+        return symbolTable.get(symName);
+    }
+
+    @Override
+    public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
+        if (kind != Kind.NATIVE_FUNCTION) {
+            throw new UnsupportedOperationException("Must be external functions: " + name);
+        }
+        Symbol symbol = new Symbol(offset, kind, binding, null, size, name);
+        addSymbol(symbol);
+        return symbol;
+    }
+
+    /**
+     * Get offset in got section with name {@code symName}.
+     *
+     * @param name for which String table information is being queried
+     * @return success or failure of insertion operation
+     */
+    public Integer getStringOffset(String name) {
+        return offsetStringTable.get(name);
+    }
+
+    /**
+     * Insert {@code targetCode} to code stream with {@code size} at {@code offset}.
+     *
+     * @param targetCode byte array of native code
+     * @param offset offset at which {@code targetCode} is to be inserted
+     * @param size size of {@code targetCode}
+     */
+    private static void appendBytes(ByteContainer byteContainer, byte[] targetCode, int offset, int size) {
+        byteContainer.appendBytes(targetCode, offset, size);
+    }
+
+    public void appendCodeBytes(byte[] targetCode, int offset, int size) {
+        appendBytes(codeContainer, targetCode, offset, size);
+    }
+
+    public void appendIntToCode(int value) {
+        codeContainer.appendInt(value);
+    }
+
+    public int appendExtLinkageGotBytes(byte[] bytes, int offset, int size) {
+        int startOffset = extLinkageGOTContainer.getByteStreamSize();
+        appendBytes(extLinkageGOTContainer, bytes, offset, size);
+        return startOffset;
+    }
+
+    public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) {
+        int startOffset = metaspaceGotContainer.getByteStreamSize();
+        appendBytes(metaspaceGotContainer, bytes, offset, size);
+        return startOffset;
+    }
+
+    public void addMetadataGotEntry(int offset) {
+        metadataGotContainer.appendLong(offset);
+    }
+
+    public int addMetaspaceName(String name) {
+        Integer value = metaspaceNames.get(name);
+        if (value != null) {
+            return value.intValue();
+        }
+        // Get the current length of the stubsNameContainer
+        // align on 8-byte boundary
+        int nameOffset = alignUp(metaspaceNamesContainer, 8);
+
+        try {
+            // Add the name of the symbol to the .stubs.names section
+            // Modify them to sequence of utf8 strings with length:
+            // "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            DataOutputStream out = new DataOutputStream(bout);
+            int len = name.length();
+            if (name.startsWith("Stub")) { // Stub
+                out.writeUTF(name);
+            } else { // Method or Klass
+                int parenthesesIndex = name.lastIndexOf('(', len - 1);
+                if (parenthesesIndex > 0) {  // Method name
+                    int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1);
+                    assert dotIndex > 0 : "method's full name should have '.' : " + name;
+                    String klassName = name.substring(0, dotIndex);
+                    out.writeUTF(klassName);
+                    String methodName = name.substring(dotIndex + 1, parenthesesIndex);
+                    out.writeUTF(methodName);
+                    String signature = name.substring(parenthesesIndex, len);
+                    out.writeUTF(signature);
+                } else {
+                    out.writeUTF(name); // Klass
+                }
+            }
+            out.writeShort(0); // Terminate by 0.
+            byte[] b = bout.toByteArray();
+            metaspaceNamesContainer.appendBytes(b, 0, b.length);
+
+            metaspaceNames.put(name, nameOffset);
+            return nameOffset;
+        } catch (IOException e) {
+            throw new InternalError("Failed to append bytes to stubs sections", e);
+        }
+    }
+
+    /**
+     * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
+     * patch.
+     *
+     * @param oopName name of the oop symbol
+     */
+    public Integer addOopSymbol(String oopName) {
+        Integer oopGotOffset = getStringOffset(oopName);
+        if (oopGotOffset != null) {
+            return oopGotOffset;
+        }
+        return newOopSymbol(oopName);
+    }
+
+    private Integer newOopSymbol(String oopName) {
+        // Reference to String resolution (ldc).
+        int offset = oopGotContainer.getByteStreamSize();
+        String gotName = "got.ldc." + offset;
+        Symbol relocationSymbol = oopGotContainer.createGotSymbol(gotName);
+
+        if (offset != relocationSymbol.getOffset()) {
+            throw new InternalError("offset must equal! (" + offset + " vs " + relocationSymbol.getOffset());
+        }
+
+        addStringOffset(oopName, relocationSymbol.getOffset());
+        return relocationSymbol.getOffset();
+    }
+
+    public int addMetaspaceSymbol(String metaspaceName) {
+        String gotName = "got." + metaspaceName;
+        Symbol relocationSymbol = getGotSymbol(gotName);
+        int metaspaceOffset = -1;
+        if (relocationSymbol == null) {
+            // Add slots when asked in the .metaspace.got section:
+            metaspaceGotContainer.createGotSymbol(gotName);
+        }
+        return metaspaceOffset;
+    }
+
+    public Symbol getGotSymbol(String name) {
+        assert name.startsWith("got.");
+        return symbolTable.get(name);
+    }
+
+    /**
+     * Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section -
+     * Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got
+     * section with another slot for the VM to patch
+     *
+     * @param metaspaceName name of the metaspace symbol
+     * @return the got offset in the metaspace.got of the metaspace symbol
+     */
+    public int addTwoSlotMetaspaceSymbol(String metaspaceName) {
+        String gotName = "got." + metaspaceName;
+        Symbol previous = getGotSymbol(gotName);
+        assert previous == null : "should be called only once for: " + metaspaceName;
+        // Add slots when asked in the .metaspace.got section:
+        // First slot
+        String gotInitName = "got.init." + metaspaceName;
+        GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName);
+        GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName);
+
+        slot1Symbol.getIndex(); // check alignment and ignore result
+        // Get the index (offset/8) to the got in the .metaspace.got section
+        return slot2Symbol.getIndex();
+    }
+
+    public int addMethodsCount(int count, ReadOnlyDataContainer container) {
+        return appendInt(count, container);
+    }
+
+    private static int appendInt(int count, ReadOnlyDataContainer container) {
+        int offset = container.getByteStreamSize();
+        container.appendInt(count);
+        return offset;
+    }
+
+    /**
+     * Add constant data as follows. - Adding the data to the method.constdata section
+     *
+     * @param data
+     * @param alignment
+     * @return the offset in the method.constdata of the data
+     */
+    public int addConstantData(byte[] data, int alignment) {
+        // Get the current length of the metaspaceNameContainer
+        int constantDataOffset = alignUp(constantDataContainer, alignment);
+        constantDataContainer.appendBytes(data, 0, data.length);
+        alignUp(constantDataContainer, alignment); // Post alignment
+        return constantDataOffset;
+    }
+
+    public int alignUp(ByteContainer container, int alignment) {
+        if (Integer.bitCount(alignment) != 1) {
+            throw new IllegalArgumentException("Must be a power of 2");
+        }
+        int offset = container.getByteStreamSize();
+        int aligned = (offset + (alignment - 1)) & -alignment;
+        if (aligned < offset || (aligned & (alignment - 1)) != 0) {
+            throw new RuntimeException("Error aligning: " + offset + " -> " + aligned);
+        }
+        if (aligned != offset) {
+            int nullArraySz = aligned - offset;
+            byte[] nullArray = new byte[nullArraySz];
+            container.appendBytes(nullArray, 0, nullArraySz);
+            offset = aligned;
+        }
+        return offset;
+    }
+
+    public void addCodeSegments(int start, int end) {
+        assert (start % codeSegmentSize) == 0 : "not aligned code";
+        int currentOffset = codeSegmentsContainer.getByteStreamSize();
+        int offset = start / codeSegmentSize;
+        int emptySize = offset - currentOffset;
+        // add empty segments if needed
+        if (emptySize > 0) {
+            byte[] emptyArray = new byte[emptySize];
+            for (int i = 0; i < emptySize; i++) {
+                emptyArray[i] = (byte) 0xff;
+            }
+            appendBytes(codeSegmentsContainer, emptyArray, 0, emptySize);
+        }
+        int alignedEnd = (end + (codeSegmentSize - 1)) & -codeSegmentSize;
+        int segmentsCount = (alignedEnd / codeSegmentSize) - offset;
+        byte[] segments = new byte[segmentsCount];
+        int idx = 0;
+        for (int i = 0; i < segmentsCount; i++) {
+            segments[i] = (byte) idx;
+            idx = (idx == 0xfe) ? 1 : (idx + 1);
+        }
+        appendBytes(codeSegmentsContainer, segments, 0, segmentsCount);
+    }
+
+    public CodeContainer getExtLinkageContainer() {
+        return extLinkageContainer;
+    }
+
+    public ByteContainer getExtLinkageGOTContainer() {
+        return extLinkageGOTContainer;
+    }
+
+    public ByteContainer getMethodMetadataContainer() {
+        return methodMetadataContainer;
+    }
+
+    public ReadOnlyDataContainer getMetaspaceNamesContainer() {
+        return metaspaceNamesContainer;
+    }
+
+    public ReadOnlyDataContainer getMethodsOffsetsContainer() {
+        return methodsOffsetsContainer;
+    }
+
+    public ReadOnlyDataContainer getKlassesOffsetsContainer() {
+        return klassesOffsetsContainer;
+    }
+
+    public ReadOnlyDataContainer getKlassesDependenciesContainer() {
+        return klassesDependenciesContainer;
+    }
+
+    public ReadOnlyDataContainer getStubsOffsetsContainer() {
+        return stubsOffsetsContainer;
+    }
+
+    public ReadOnlyDataContainer getCodeSegmentsContainer() {
+        return codeSegmentsContainer;
+    }
+
+    public ReadOnlyDataContainer getConstantDataContainer() {
+        return constantDataContainer;
+    }
+
+    public ByteContainer getMetaspaceGotContainer() {
+        return metaspaceGotContainer;
+    }
+
+    public ByteContainer getMetadataGotContainer() {
+        return metadataGotContainer;
+    }
+
+    public ByteContainer getMethodStateContainer() {
+        return methodStateContainer;
+    }
+
+    public ByteContainer getOopGotContainer() {
+        return oopGotContainer;
+    }
+
+    public CodeContainer getCodeContainer() {
+        return codeContainer;
+    }
+
+    public ReadOnlyDataContainer getConfigContainer() {
+        return configContainer;
+    }
+
+    public Map<Symbol, Relocation> getUniqueRelocationTable() {
+        return uniqueRelocationTable;
+    }
+
+    public HeaderContainer getHeaderContainer() {
+        return headerContainer;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java
new file mode 100644
index 0000000..12daa9f
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ByteContainer.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.jnilibelf.ELFContainer;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Base class that represents content of all sections with byte-level granularity. The ByteContainer
+ * class is backed by a ByteArrayOutputStream. This class supports writing all desired byte content
+ * to the container using the method {@code appendBytes} and accessing the byte array using the
+ * method {@code getByteArray}.
+ *
+ * The method {@code putIntAt} updates the content of {@code contentBytes}. Changes are not
+ * reflected in {@code contentStream}.
+ */
+public class ByteContainer implements ELFContainer {
+    /**
+     * {@code ByteBuffer} representation of {@code BinaryContainer}.
+     */
+    private ByteBuffer contentBytes;
+
+    /**
+     * {@code ByteArrayoutputStream} to which all appends are done.
+     */
+    private ByteArrayOutputStream contentStream;
+
+    /**
+     * Boolean to indicate if contentBytes was modified.
+     */
+    private boolean bufferModified;
+
+    /**
+     * Boolean to indicate if this section contains any relocations.
+     */
+    private boolean hasRelocations;
+
+    /**
+     * Name of this container, used as section name.
+     */
+    private String containerName;
+    private final SymbolTable symbolTable;
+
+    /**
+     * Contains a unique id.
+     */
+    private int sectionId = -1;
+
+    /**
+     * Construct a {@code ByteContainer} object.
+     */
+    public ByteContainer(String containerName, SymbolTable symbolTable) {
+        this.containerName = containerName;
+        this.symbolTable = symbolTable;
+        this.contentBytes = null;
+        this.bufferModified = false;
+        this.hasRelocations = false;
+        this.contentStream = new ByteArrayOutputStream();
+    }
+
+    /**
+     * Update byte buffer to reflect the current contents of byte stream.
+     *
+     * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+     */
+    private void updateByteBuffer() {
+        if (!bufferModified) {
+            contentBytes = ByteBuffer.wrap(contentStream.toByteArray());
+            // Default byte order of ByteBuffer is BIG_ENDIAN.
+            // Set it appropriately
+            this.contentBytes.order(ByteOrder.nativeOrder());
+        } else {
+            throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+        }
+    }
+
+    /**
+     * Get the byte array of {@code ByteContainer}.
+     *
+     * @return byte array
+     * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+     */
+    public byte[] getByteArray() {
+        if (!bufferModified) {
+            updateByteBuffer();
+        }
+        return contentBytes.array();
+    }
+
+    /**
+     * Append to byte stream. It is an error to append to stream if the byte buffer version is
+     * changed.
+     *
+     * @param newBytes new content
+     * @param off offset start offset in {@code newBytes}
+     * @param len length of data to write
+     * @throws InternalError throws {@code InternalError} if buffer byte array was modified
+     */
+    public ByteContainer appendBytes(byte[] newBytes, int off, int len) {
+        if (bufferModified) {
+            throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+        }
+        contentStream.write(newBytes, off, len);
+        return this;
+    }
+
+    public ByteContainer appendBytes(byte[] newBytes) {
+        appendBytes(newBytes, 0, newBytes.length);
+        return this;
+    }
+
+    public ByteContainer appendInt(int i) {
+        if (bufferModified) {
+            throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+        }
+        ByteBuffer b = ByteBuffer.allocate(Integer.BYTES);
+        b.order(ByteOrder.nativeOrder());
+        b.putInt(i);
+        byte[] result = b.array();
+        contentStream.write(result, 0, result.length);
+        return this;
+    }
+
+    public ByteContainer appendInts(int[] newInts) {
+        if (bufferModified) {
+            throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+        }
+        ByteBuffer b = ByteBuffer.allocate(Integer.BYTES * newInts.length).order(ByteOrder.nativeOrder());
+        Arrays.stream(newInts).forEach(i -> b.putInt(i));
+        byte[] result = b.array();
+        contentStream.write(result, 0, result.length);
+        return this;
+    }
+
+    public void appendLong(long l) {
+        if (bufferModified) {
+            throw new InternalError("Backing byte buffer no longer in sync with byte stream");
+        }
+        ByteBuffer b = ByteBuffer.allocate(8);
+        b.order(ByteOrder.nativeOrder());
+        b.putLong(l);
+        byte[] result = b.array();
+        contentStream.write(result, 0, result.length);
+    }
+
+    /**
+     * Return the current size of byte stream backing the BinaryContainer.
+     *
+     * @return size of buffer stream
+     */
+    public int getByteStreamSize() {
+        return contentStream.size();
+    }
+
+    /**
+     * Return the name of this container.
+     *
+     * @return string containing name
+     */
+    public String getContainerName() {
+        return containerName;
+    }
+
+    /**
+     * Modify the byte buffer version of the byte output stream. Note that after calling this method
+     * all further updates to BinaryContainer will be out of sync with byte buffer content.
+     *
+     * @param index index of byte to be changed
+     * @param value new value
+     */
+    public void putIntAt(int index, int value) {
+        if (!bufferModified) {
+            updateByteBuffer();
+        }
+        contentBytes.putInt(index, value);
+        bufferModified = true;
+    }
+
+    public void putLongAt(int index, long value) {
+        if (!bufferModified) {
+            updateByteBuffer();
+        }
+        contentBytes.putLong(index, value);
+        bufferModified = true;
+    }
+
+    public void setSectionId(int id) {
+        if (sectionId != -1) {
+            throw new InternalError("Assigning new sectionId (old: " + sectionId + ", new: " + id + ")");
+        }
+        sectionId = id;
+    }
+
+    public int getSectionId() {
+        if (sectionId == -1) {
+            throw new InternalError("Using sectionId before assigned");
+        }
+        return sectionId;
+    }
+
+    public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) {
+        Symbol symbol = new Symbol(offset, kind, binding, this, size, name);
+        symbolTable.addSymbol(symbol);
+        return symbol;
+    }
+
+    public GotSymbol createGotSymbol(String name) {
+        GotSymbol symbol = new GotSymbol(Kind.OBJECT, Binding.LOCAL, this, name);
+        symbolTable.addSymbol(symbol);
+        return symbol;
+    }
+
+    public GotSymbol createGotSymbol(int offset, String name) {
+        GotSymbol symbol = new GotSymbol(offset, Kind.OBJECT, Binding.LOCAL, this, name);
+        symbolTable.addSymbol(symbol);
+        return symbol;
+    }
+
+    public void clear() {
+        this.contentBytes = null;
+        this.contentStream = null;
+    }
+
+    public void setHasRelocations() {
+        this.hasRelocations = true;
+    }
+
+    public boolean hasRelocations() {
+        return this.hasRelocations;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java
new file mode 100644
index 0000000..e562d35
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+/**
+ * A container that holds information about code section. This is simply a ByteContainer.
+ */
+public class CodeContainer extends ByteContainer {
+
+    public CodeContainer(String containerName, SymbolTable symbolTable) {
+        super(containerName, symbolTable);
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java
new file mode 100644
index 0000000..3d77e79
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+public class GotSymbol extends Symbol {
+
+    private static final int GOT_SIZE = 8;
+
+    public int getIndex() {
+        int offset = getOffset();
+        assert (offset % GOT_SIZE) == 0 : "got cells should be aligned: " + offset;
+        return offset / GOT_SIZE;
+    }
+
+    public GotSymbol(Kind type, Binding binding, ByteContainer container, String name) {
+        this(container.getByteStreamSize(), type, binding, container, name);
+        container.appendBytes(new byte[GOT_SIZE], 0, GOT_SIZE);
+    }
+
+    /**
+     * Create symbol info.
+     *
+     * @param offset section offset for the defined symbol
+     * @param type type of the symbol (UNDEFINED, FUNC, etc)
+     * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+     * @param sec section in which this symbol is "defined"
+     */
+    public GotSymbol(int offset, Kind type, Binding binding, ByteContainer sec, String name) {
+        super(offset, type, binding, sec, GOT_SIZE, name);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java
new file mode 100644
index 0000000..85250d3
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class HeaderContainer {
+
+    private static final int CURRENT_VERSION = 1;
+    private final ReadOnlyDataContainer container;
+    // int _version;
+    // int _class_count;
+    // int _method_count;
+    // int _metaspace_got_size;
+    // int _metadata_got_size;
+    // int _oop_got_size;
+    // int _jvm_version_offset;
+
+    public HeaderContainer(String jvmVersion, ReadOnlyDataContainer container) {
+        try {
+            byte[] filler = new byte[4 * 7];
+            container.appendBytes(filler);
+
+            // Store JVM version string at the end of header section.
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            DataOutputStream out = new DataOutputStream(bout);
+            out.writeUTF(jvmVersion);
+            out.writeShort(0); // Terminate by 0.
+            byte[] b = bout.toByteArray();
+            container.appendBytes(b, 0, b.length);
+        } catch (IOException e) {
+            throw new InternalError("Failed to append bytes to header section", e);
+        }
+
+        this.container = container;
+        this.container.putIntAt(0 * 4, CURRENT_VERSION);
+        this.container.putIntAt(6 * 4, 7 * 4); // JVM version string offset
+    }
+
+    public String getContainerName() {
+        return container.getContainerName();
+    }
+
+    public ReadOnlyDataContainer getContainer() {
+        return container;
+    }
+
+    public void setClassesCount(int count) {
+        this.container.putIntAt(1 * 4, count);
+    }
+
+    public void setMethodsCount(int count) {
+        this.container.putIntAt(2 * 4, count);
+    }
+
+    public void setMetaspaceGotSize(int size) {
+        this.container.putIntAt(3 * 4, size);
+    }
+
+    public void setMetadataGotSize(int size) {
+        this.container.putIntAt(4 * 4, size);
+    }
+
+    public void setOopGotSize(int size) {
+        this.container.putIntAt(5 * 4, size);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java
new file mode 100644
index 0000000..fe72f06
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+public class ReadOnlyDataContainer extends ByteContainer {
+
+    public ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) {
+        super(containerName, symbolTable);
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java
new file mode 100644
index 0000000..e7d1e3f
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+public class Relocation {
+
+    public enum RelocType {
+        UNDEFINED,
+        JAVA_CALL_INDIRECT,
+        JAVA_CALL_DIRECT,
+        FOREIGN_CALL_INDIRECT,
+        FOREIGN_CALL_INDIRECT_GOT, // Call to address in GOT cell
+        FOREIGN_CALL_DIRECT,
+        FOREIGN_CALL_DIRECT_FAR,
+        STUB_CALL_DIRECT,
+        STUB_CALL_INDIRECT,
+        EXTERNAL_DATA_REFERENCE_FAR,
+        METASPACE_GOT_REFERENCE,
+        EXTERNAL_GOT_TO_PLT,
+        EXTERNAL_PLT_TO_GOT,
+        STATIC_STUB_TO_STATIC_METHOD,
+        STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT,
+        LOADTIME_ADDRESS
+    }
+
+    private final RelocType type;
+
+    /**
+     * Byte offset from the beginning of the file affected by relocation.
+     */
+    private final int offset;
+
+    /**
+     * Size of relocation.
+     */
+    private final int size;
+
+    /**
+     * Symbol associated with this relocation.
+     */
+    private final Symbol symbol;
+
+    /**
+     * Section this relocation entry modifies.
+     */
+    private final ByteContainer section;
+
+    public Relocation(int offset, RelocType type, int size, ByteContainer section, Symbol sym) {
+        if (sym == null) {
+            throw new InternalError("must have symbol");
+        }
+        this.offset = offset;
+        this.type = type;
+        this.size = size;
+        this.symbol = sym;
+        this.section = section;
+        section.setHasRelocations();
+    }
+
+    public RelocType getType() {
+        return type;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public Symbol getSymbol() {
+        return symbol;
+    }
+
+    public ByteContainer getSection() {
+        return section;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java
new file mode 100644
index 0000000..ba0f909
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+import java.util.Objects;
+
+import jdk.tools.jaotc.jnilibelf.ELFSymbol;
+
+public class Symbol {
+
+    public enum Binding {
+        UNDEFINED,
+        LOCAL,
+        GLOBAL
+    }
+
+    public enum Kind {
+        UNDEFINED,
+        NATIVE_FUNCTION,
+        JAVA_FUNCTION,
+        STATIC_STUB_CALL, // static call stub inside the text section
+        OBJECT,
+        NOTYPE
+    }
+
+    private final String name;
+    private final int size;
+    private final int offset;
+    private final Binding binding;
+    private final Kind kind;
+
+    private ByteContainer section;
+    private ELFSymbol elfSymbol;
+
+    /**
+     * Create symbol info.
+     *
+     * @param offset section offset for the defined symbol
+     * @param kind kind of the symbol (UNDEFINED, FUNC, etc)
+     * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+     * @param section section in which this symbol is "defined"
+     * @param size size of the symbol
+     * @param name name of the symbol
+     */
+
+    public Symbol(int offset, Kind kind, Binding binding, ByteContainer section, int size, String name) {
+        this.binding = binding;
+        this.kind = kind;
+        this.section = section;
+        this.size = size;
+        this.offset = offset;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ELFSymbol getElfSymbol() {
+        return elfSymbol;
+    }
+
+    public void setElfSymbol(ELFSymbol elfSymbol) {
+        this.elfSymbol = elfSymbol;
+    }
+
+    public Binding getBinding() {
+        return binding;
+    }
+
+    public Kind getKind() {
+        return kind;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public ByteContainer getSection() {
+        return section;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Symbol)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        Symbol symbol = (Symbol) obj;
+
+        if (size != symbol.size) {
+            return false;
+        }
+        if (offset != symbol.offset) {
+            return false;
+        }
+        if (!name.equals(symbol.name)) {
+            return false;
+        }
+        if (binding != symbol.binding) {
+            return false;
+        }
+        if (kind != symbol.kind) {
+            return false;
+        }
+        return !(section != null ? !section.equals(symbol.section) : symbol.section != null);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(name, binding, kind, section);
+        result = 31 * result + size;
+        result = 31 * result + offset;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "[" + name + ", " + size + ", " + offset + ", " + binding + ", " + kind + ", " + section + "]";
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java
new file mode 100644
index 0000000..d5d690c
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/SymbolTable.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat;
+
+public interface SymbolTable {
+    void addSymbol(Symbol symInfo);
+
+    Symbol getSymbol(String symName);
+
+    Symbol createSymbol(int offset, Symbol.Kind kind, Symbol.Binding binding, int size, String name);
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java
new file mode 100644
index 0000000..82bac0c
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.binformat.elf;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.jnilibelf.ELFContainer;
+import jdk.tools.jaotc.jnilibelf.ELFSymbol;
+import jdk.tools.jaotc.jnilibelf.JNIELFContainer;
+import jdk.tools.jaotc.jnilibelf.JNIELFRelocation;
+import jdk.tools.jaotc.jnilibelf.JNIELFTargetInfo;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
+import jdk.tools.jaotc.jnilibelf.Pointer;
+
+public class JELFRelocObject {
+
+    private final BinaryContainer binContainer;
+
+    private final JNIELFContainer elfContainer;
+
+    private final int segmentSize;
+
+    public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
+        this.binContainer = binContainer;
+        this.elfContainer = new JNIELFContainer(outputFileName, aotVersion);
+        this.segmentSize = binContainer.getCodeSegmentSize();
+    }
+
+    private void createByteSection(ByteContainer c, int scnFlags) {
+        byte[] scnData = c.getByteArray();
+        int scnType = ELF.SHT_PROGBITS;
+        boolean zeros = !c.hasRelocations();
+        if (zeros) {
+            for (byte b : scnData) {
+                if (b != 0) {
+                    zeros = false;
+                    break;
+                }
+            }
+            if (zeros) {
+                scnType = ELF.SHT_NOBITS;
+            }
+        }
+
+        int sectionId = elfContainer.createSection(c.getContainerName(), scnData, Elf_Type.ELF_T_BYTE, segmentSize, scnType, scnFlags, ELF.SHN_UNDEF, 0);
+        c.setSectionId(sectionId);
+        // Clear out code section data to allow for GC
+        c.clear();
+    }
+
+    private void createCodeSection(CodeContainer c) {
+        createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_EXECINSTR);
+    }
+
+    private void createReadOnlySection(ReadOnlyDataContainer c) {
+        createByteSection(c, ELF.SHF_ALLOC);
+    }
+
+    private void createReadWriteSection(ByteContainer c) {
+        createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_WRITE);
+    }
+
+    /**
+     * Create an ELF relocatable object using jdk.tools.jaotc.jnilibelf API.
+     *
+     * @param relocationTable
+     * @param symbols
+     * @throws IOException throws {@code IOException} as a result of file system access failures.
+     */
+    public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
+        // Allocate ELF Header
+        elfContainer.createELFHeader(ELF.ET_REL);
+
+        // Create text section
+        createCodeSection(binContainer.getCodeContainer());
+        createReadOnlySection(binContainer.getMetaspaceNamesContainer());
+        createReadOnlySection(binContainer.getKlassesOffsetsContainer());
+        createReadOnlySection(binContainer.getMethodsOffsetsContainer());
+        createReadOnlySection(binContainer.getKlassesDependenciesContainer());
+        createReadWriteSection(binContainer.getMetaspaceGotContainer());
+        createReadWriteSection(binContainer.getMetadataGotContainer());
+        createReadWriteSection(binContainer.getMethodStateContainer());
+        createReadWriteSection(binContainer.getOopGotContainer());
+        createReadWriteSection(binContainer.getMethodMetadataContainer());
+        createReadOnlySection(binContainer.getStubsOffsetsContainer());
+        createReadOnlySection(binContainer.getHeaderContainer().getContainer());
+        createReadOnlySection(binContainer.getCodeSegmentsContainer());
+        createReadOnlySection(binContainer.getConstantDataContainer());
+        createReadOnlySection(binContainer.getConfigContainer());
+
+        // createExternalLinkage();
+
+        createCodeSection(binContainer.getExtLinkageContainer());
+        createReadWriteSection(binContainer.getExtLinkageGOTContainer());
+
+        // Get ELF symbol data from BinaryContainer object's symbol tables
+        createELFSymbolTables(symbols);
+
+        // Create string table section and symbol table sections in
+        // that order since symtab section needs to set the index of strtab in sh_link field
+        int strTabSectionIndex = elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
+
+        // Now create .symtab section with the symtab data constructed. On Linux, sh_link of symtab
+        // contains the index of string table its symbols reference and
+        // sh_info contains the index of first non-local symbol
+        int scnInfo = elfContainer.getFirstNonLocalSymbolIndex();
+        int symTabSectionIndex = elfContainer.createSection(".symtab", getELFSymbolTableData(), Elf_Type.ELF_T_SYM, 8, ELF.SHT_SYMTAB, ELF.SHF_ALLOC, strTabSectionIndex, scnInfo);
+
+        buildRelocations(relocationTable, symTabSectionIndex);
+
+        // Now, finally, after creating all sections, create shstrtab section
+        elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
+
+        // Run elf_update
+        elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL);
+
+        // Run elfUpdate again to write it out.
+        elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE);
+        // Finish ELF processing
+        elfContainer.elfEnd();
+    }
+
+    private void buildRelocations(Map<Symbol, List<Relocation>> relocationTable, final int symTabSectionIndex) {
+        /*
+         * Create relocation sections. This needs to be done after symbol table sections were
+         * created since relocation entries will need indices of sections to which they apply.
+         */
+        createELFRelocationTables(relocationTable);
+        createAllRelocationSections(new SymTabELFContainer(symTabSectionIndex));
+    }
+
+    /**
+     * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
+     * symbol table and ELF symbol table are created from BinaryContainer's symbol info.
+     *
+     * @param symbols
+     */
+    private void createELFSymbolTables(Collection<Symbol> symbols) {
+        // First, create the initial null symbol. This is a local symbol.
+        elfContainer.createELFSymbolEntry("", 0, 0, ELF.SHN_UNDEF, 0, 0, true);
+
+        // Now create ELF symbol entries for all symbols.
+        for (Symbol symbol : symbols) {
+            // Get the index of section this symbol is defined in.
+            int secHdrIndex = symbol.getSection().getSectionId();
+            boolean isLocal = (symbol.getBinding() == Binding.LOCAL);
+            ELFSymbol elfSymbol = elfContainer.createELFSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), secHdrIndex, symbol.getSize(), symbol.getOffset(), isLocal);
+            symbol.setElfSymbol(elfSymbol);
+        }
+    }
+
+    /**
+     * Construct ELF symbol data from BinaryContainer object's symbol tables.
+     *
+     * @return a byte array containing the symbol table
+     */
+    private byte[] getELFSymbolTableData() {
+        final int entrySize = JNIELFTargetInfo.sizeOfSymtabEntry();
+
+        // First, add all local symbols.
+        List<ELFSymbol> localSymbols = elfContainer.getLocalSymbols();
+        List<ELFSymbol> globalSymbols = elfContainer.getGlobalSymbols();
+
+        int localSymCount = localSymbols.size();
+        int globalSymCount = globalSymbols.size();
+        byte[] sectionDataArray = new byte[(localSymCount + globalSymCount) * entrySize];
+
+        for (int i = 0; i < localSymCount; i++) {
+            ELFSymbol symbol = localSymbols.get(i);
+            Pointer address = symbol.getAddress();
+            address.copyBytesTo(sectionDataArray, entrySize, i * entrySize);
+        }
+
+        // Next, add all global symbols.
+
+        for (int i = 0; i < globalSymCount; i++) {
+            ELFSymbol symbol = globalSymbols.get(i);
+            Pointer address = symbol.getAddress();
+            address.copyBytesTo(sectionDataArray, entrySize, (localSymCount + i) * entrySize);
+        }
+
+        return sectionDataArray;
+    }
+
+    private static int getELFTypeOf(Symbol sym) {
+        Kind kind = sym.getKind();
+        if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
+            return ELF.STT_FUNC;
+        } else if (kind == Symbol.Kind.OBJECT) {
+            return ELF.STT_OBJECT;
+        }
+        return ELF.STT_NOTYPE;
+    }
+
+    private static int getELFBindOf(Symbol sym) {
+        Binding binding = sym.getBinding();
+        if (binding == Symbol.Binding.GLOBAL) {
+            return ELF.STB_GLOBAL;
+        }
+        return ELF.STB_LOCAL;
+    }
+
+    /**
+     * Construct ELF relocation section data from BinaryContainer object's relocation tables.
+     *
+     * @param relocationTable
+     */
+    private void createELFRelocationTables(Map<Symbol, List<Relocation>> relocationTable) {
+        /*
+         * For each of the symbols with associated relocation records, create an ELF relocation
+         * entry.
+         */
+        for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
+            List<Relocation> relocs = entry.getValue();
+            Symbol symbol = entry.getKey();
+
+            for (Relocation reloc : relocs) {
+                createRelocation(symbol, reloc);
+            }
+        }
+
+        for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
+            createRelocation(entry.getKey(), entry.getValue());
+        }
+    }
+
+    private void createRelocation(Symbol symbol, Relocation reloc) {
+        RelocType relocType = reloc.getType();
+        int elfRelocType = getELFRelocationType(relocType);
+
+        switch (relocType) {
+            case FOREIGN_CALL_DIRECT:
+            case JAVA_CALL_DIRECT:
+            case STUB_CALL_DIRECT:
+            case FOREIGN_CALL_INDIRECT_GOT: {
+                // Create relocation entry
+                int addend = -4; // Size in bytes of the patch location
+                // Relocation should be applied at the location after call operand
+                int offset = reloc.getOffset() + reloc.getSize() + addend;
+                elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
+                break;
+            }
+            case FOREIGN_CALL_DIRECT_FAR: {
+                // Create relocation entry
+                int addend = -8; // Size in bytes of the patch location
+                // Relocation should be applied at the location after call operand
+                // 10 = 2 (jmp [r]) + 8 (imm64)
+                int offset = reloc.getOffset() + reloc.getSize() + addend - 2;
+                elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
+                break;
+            }
+            case FOREIGN_CALL_INDIRECT:
+            case JAVA_CALL_INDIRECT:
+            case STUB_CALL_INDIRECT: {
+                // Do nothing.
+                break;
+            }
+            case EXTERNAL_DATA_REFERENCE_FAR: {
+                // Create relocation entry
+                int addend = -4; // Size of 32-bit address of the GOT
+                /*
+                 * Relocation should be applied before the test instruction to the move instruction.
+                 * reloc.getOffset() points to the test instruction after the instruction that loads
+                 * the address of polling page. So set the offset appropriately.
+                 */
+                int offset = reloc.getOffset() + addend;
+                elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
+                break;
+            }
+            case METASPACE_GOT_REFERENCE:
+            case EXTERNAL_PLT_TO_GOT:
+            case STATIC_STUB_TO_STATIC_METHOD:
+            case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
+                int addend = -4; // Size of 32-bit address of the GOT
+                /*
+                 * Relocation should be applied before the test instruction to the move instruction.
+                 * reloc.getOffset() points to the test instruction after the instruction that loads
+                 * the address of polling page. So set the offset appropriately.
+                 */
+                int offset = reloc.getOffset() + addend;
+                elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
+                break;
+            }
+            case EXTERNAL_GOT_TO_PLT:
+            case LOADTIME_ADDRESS: {
+                // this is load time relocations
+                elfContainer.createELFRelocationEntry(reloc.getSection(), reloc.getOffset(), elfRelocType, 0, symbol.getElfSymbol());
+                break;
+            }
+            default:
+                throw new InternalError("Unhandled relocation type: " + relocType);
+        }
+    }
+
+    // TODO: Populate the mapping of RelocType to ELF relocation types
+    private static int getELFRelocationType(RelocType relocType) {
+        int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
+        switch (JNIELFTargetInfo.getELFArch()) {
+            case ELF.EM_X64_64:
+                // Return R_X86_64_* entries based on relocType
+                if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PLT32;
+                } else if (relocType == RelocType.STUB_CALL_DIRECT) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
+                } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
+                } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_NONE;
+                } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_GOTPCREL;
+                } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
+                                relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
+                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
+                    elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
+                } else {
+                    assert false : "Unhandled relocation type: " + relocType;
+                }
+                break;
+            default:
+                System.out.println("Relocation Type mapping: Unhandled architecture");
+        }
+        return elfRelocType;
+    }
+
+    private void createAllRelocationSections(ELFContainer symtab) {
+        for (Map.Entry<ELFContainer, ArrayList<Pointer>> entry : elfContainer.getRelocTables().entrySet()) {
+            createRelocationSection(entry.getKey(), entry.getValue(), symtab);
+        }
+    }
+
+    private void createRelocationSection(ELFContainer container, ArrayList<Pointer> relocations, ELFContainer symtab) {
+        String secName = container.getContainerName();
+        int entrySize = JNIELFTargetInfo.sizeOfRelocEntry();
+        int numEntries = relocations.size();
+        byte[] sectionDataBytes = new byte[numEntries * entrySize];
+
+        for (int index = 0; index < relocations.size(); index++) {
+            Pointer entry = relocations.get(index);
+            entry.copyBytesTo(sectionDataBytes, entrySize, index * entrySize);
+        }
+        String fullSecName;
+        // If relocDat is non-null create section
+        if (sectionDataBytes.length > 0) {
+            int scnType;
+            Elf_Type dataType;
+            if (JNIELFTargetInfo.createReloca() == 0) {
+                scnType = ELF.SHT_REL;
+                dataType = Elf_Type.ELF_T_REL;
+                fullSecName = ".rel" + secName;
+            } else {
+                scnType = ELF.SHT_RELA;
+                dataType = Elf_Type.ELF_T_RELA;
+                fullSecName = ".rela" + secName;
+            }
+            // assert compareBytes(relocData.toByteArray(), sectionDataBytes) : "******* Bad array
+            // copy";
+            // sh_link holds the index of section header of symbol table associated with this
+            // relocation table.
+            // sh_info holds the index of section header to which this relocation table applies
+            // to.
+            elfContainer.createSection(fullSecName, sectionDataBytes, dataType, 8, scnType, ELF.SHF_ALLOC, symtab.getSectionId(), container.getSectionId());
+        }
+    }
+
+    private static class SymTabELFContainer implements ELFContainer {
+        private final int symTabSectionIndex;
+
+        public SymTabELFContainer(int symTabSectionIndex) {
+            this.symTabSectionIndex = symTabSectionIndex;
+        }
+
+        @Override
+        public String getContainerName() {
+            return ".symtab";
+        }
+
+        @Override
+        public int getSectionId() {
+            return symTabSectionIndex;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java
new file mode 100644
index 0000000..b65b6ae
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFContainer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+public interface ELFContainer {
+
+    String getContainerName();
+
+    int getSectionId();
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java
new file mode 100644
index 0000000..ddad5a0
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/ELFSymbol.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+/**
+ * This class represents a {@code Elf32_Sym} or {@code Elf64_Sym} as defined in {@code elf.h}.
+ */
+public class ELFSymbol {
+    /** Symbol name. */
+    private final String name;
+
+    /** String table index. */
+    private final int index;
+
+    /** Native memory address of ELF sym entry. */
+    private final Pointer address;
+    private final boolean isLocal;
+
+    public ELFSymbol(String name, int index, Pointer address, boolean isLocal) {
+        this.name = name;
+        this.index = index;
+        this.address = address;
+        this.isLocal = isLocal;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the index
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * @return the address
+     */
+    public Pointer getAddress() {
+        return address;
+    }
+
+    @Override
+    public String toString() {
+        return "name=" + name + ", index=" + index + ", address=" + address;
+    }
+
+    public boolean isLocal() {
+        return isLocal;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java
new file mode 100644
index 0000000..64d699f
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFContainer.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+import static jdk.tools.jaotc.jnilibelf.UnsafeAccess.UNSAFE;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
+
+/**
+ * A class abstraction of an ELF file.
+ *
+ */
+public class JNIELFContainer {
+
+    private String outputFileName;
+    private File outFile;
+    private int outFileDesc;
+
+    /**
+     * Pointer to Elf file. This is the same as struct Elf found in libelf.h
+     */
+    private Pointer elfPtr;
+
+    /**
+     * Class of the ELF container - one of ELFCLASS32 or ELFCLASS64.
+     */
+    private final int elfClass;
+
+    /**
+     * Pointer to ELF Header.
+     */
+    private Pointer ehdrPtr;
+
+    /**
+     * Pointer to Program Header.
+     */
+    private Pointer phdrPtr;
+
+    /**
+     * String holding .shstrtab contents.
+     */
+    private String shStrTabContent = "";
+
+    /**
+     * Map of local symbol indexes to ELF symbol entries.
+     */
+    private List<ELFSymbol> localSymbolIndex = new ArrayList<>();
+
+    /**
+     * Map of global symbol indexes to ELF symbol entries.
+     */
+    private List<ELFSymbol> globalSymbolIndex = new ArrayList<>();
+
+    /**
+     * String holding .strtab contents.
+     */
+    private StringBuilder strTabContent = new StringBuilder();
+
+    /**
+     * Keeps track of nr of bytes in .strtab since strTabContent.length() is number of chars, not
+     * bytes.
+     */
+    private int strTabNrOfBytes = 0;
+
+    /**
+     * A hashtable that holds (section-name, relocation-table) pairs. For example, [(".rela.text",
+     * rela-text-reloc-entries), (".rela.plt", rela-plt-reloc-entries), ...].
+     */
+    private Map<ELFContainer, ArrayList<Pointer>> relocTables = new HashMap<>();
+
+    /**
+     * Create reloca; 0 => false and non-zero => true.
+     */
+    private final int createReloca;
+
+    /**
+     * Construct an ELFContainer in preparation for a disk image with file {@code prefix}.
+     *
+     * @param fileName name of ELF file to be created
+     */
+    public JNIELFContainer(String fileName, String aotVersion) {
+        // Check for version compatibility
+        if (!JNILibELFAPI.elfshim_version().equals(aotVersion)) {
+            throw new InternalError("libelfshim version mismatch: " + JNILibELFAPI.elfshim_version() + " vs " + aotVersion);
+        }
+
+        elfClass = JNIELFTargetInfo.getELFClass();
+        createReloca = JNIELFTargetInfo.createReloca();
+        outputFileName = fileName;
+    }
+
+    /**
+     * Get the local ELF symbol table.
+     *
+     * @return local symbol table
+     */
+    public List<ELFSymbol> getLocalSymbols() {
+        return localSymbolIndex;
+    }
+
+    /**
+     * Get the global ELF symbol table.
+     *
+     * @return list of global ELF symbol table entries
+     */
+    public List<ELFSymbol> getGlobalSymbols() {
+        return globalSymbolIndex;
+    }
+
+    /**
+     * Get string table content (.strtab).
+     *
+     * @return string table content
+     */
+    public String getStrTabContent() {
+        return strTabContent.toString();
+    }
+
+    /**
+     * Get section header string table content (.shstrtab).
+     *
+     * @return section header string table content
+     */
+    public String getShStrTabContent() {
+        return shStrTabContent;
+    }
+
+    /**
+     * Get relocation tables.
+     *
+     * @return relocation tables
+     */
+    public Map<ELFContainer, ArrayList<Pointer>> getRelocTables() {
+        return relocTables;
+    }
+
+    /**
+     * Get the index of first non-local symbol in symbol table.
+     *
+     * @return symbol table index
+     */
+    public int getFirstNonLocalSymbolIndex() {
+        return localSymbolIndex.size();
+    }
+
+    /**
+     * Create ELF header of type {@code ececType}.
+     *
+     * @param type type of ELF executable
+     */
+    public void createELFHeader(int type) {
+        // Check for version compatibility
+        if (JNILibELFAPI.elf_version(ELF.EV_CURRENT) == ELF.EV_NONE) {
+            throw new InternalError("ELF version mismatch");
+        }
+
+        outFile = constructRelocFile(outputFileName);
+        // Open a temporary file for the shared library to be created
+        // TODO: Revisit file permissions; need to add execute permission
+        outFileDesc = JNILibELFAPI.open_rw(outFile.getPath());
+
+        if (outFileDesc == -1) {
+            System.out.println("Failed to open file " + outFile.getPath() + " to write relocatable object.");
+        }
+
+        elfPtr = JNILibELFAPI.elf_begin(outFileDesc, LibELF.Elf_Cmd.ELF_C_WRITE.intValue(), new Pointer(0L));
+        if (elfPtr == null) {
+            throw new InternalError("elf_begin failed");
+        }
+
+        // Allocate new Ehdr of current architecture class
+
+        ehdrPtr = JNILibELFAPI.gelf_newehdr(elfPtr, elfClass);
+
+        JNILibELFAPI.ehdr_set_data_encoding(ehdrPtr, JNIELFTargetInfo.getELFEndian());
+        JNILibELFAPI.set_Ehdr_e_machine(elfClass, ehdrPtr, JNIELFTargetInfo.getELFArch());
+        JNILibELFAPI.set_Ehdr_e_type(elfClass, ehdrPtr, type);
+        JNILibELFAPI.set_Ehdr_e_version(elfClass, ehdrPtr, ELF.EV_CURRENT);
+    }
+
+    /**
+     * If the file name has a .so extension, replace it with .o extension. Else just add .o
+     * extension
+     *
+     * @param fileName
+     * @return File object
+     */
+    private static File constructRelocFile(String fileName) {
+        File relocFile = new File(fileName);
+        if (relocFile.exists()) {
+            if (!relocFile.delete()) {
+                throw new InternalError("Failed to delete existing " + fileName + " file");
+            }
+        }
+        return relocFile;
+    }
+
+    /**
+     * Create {@code count} number of Program headers.
+     *
+     * @param count number of program headers to create
+     * @return true upon success; false upon failure
+     */
+    public boolean createProgramHeader(int count) {
+        phdrPtr = JNILibELFAPI.gelf_newphdr(elfPtr, count);
+        if (phdrPtr == null) {
+            System.out.println("gelf_newphdr error");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set program header to be of type self.
+     *
+     * @return true
+     */
+    public boolean setProgHdrTypeToSelf() {
+        // Set program header to be of type self
+        JNILibELFAPI.phdr_set_type_self(elfClass, ehdrPtr, phdrPtr);
+        // And thus mark it as dirty so that elfUpdate can recompute the structures
+        JNILibELFAPI.elf_flagphdr(elfPtr, LibELF.Elf_Cmd.ELF_C_SET.intValue(), LibELF.ELF_F_DIRTY);
+        // TODO: Error checking; look at the return value of elf_update
+        // and call elf_errmsg appropriately.
+        return true;
+    }
+
+    /**
+     * Create a section. The corresponding section header and section data are created by calling
+     * the necessary libelf APIs. The section that is created is inserted into the ELF container.
+     *
+     * @param secName name of the section
+     * @param scnData section data
+     * @param dataType data type
+     * @param align section alignment
+     * @param scnType section type
+     * @param scnFlags section flags
+     * @param scnLink sh_link field of Elf{32,64}_Shdr
+     * @param scnInfo sh_info field of Elf{32,64}_Shdr
+     * @return section index
+     */
+    public int createSection(String secName, byte[] scnData, Elf_Type dataType, int align, int scnType, int scnFlags, int scnLink, int scnInfo) {
+        // Create a new section
+        Pointer scnPtr = JNILibELFAPI.elf_newscn(elfPtr);
+        if (scnPtr == null) {
+            throw new InternalError("elf_newscn error");
+        }
+
+        // Allocate section data for the section
+        Pointer scnDataPtr = JNILibELFAPI.elf_newdata(scnPtr);
+        if (scnDataPtr == null) {
+            String errMsg = JNILibELFAPI.elf_errmsg(-1);
+            throw new InternalError("elf_newdata error: " + errMsg);
+        }
+
+        // Get the pointer to section header associated with the new section
+        Pointer scnHdrPtr = JNILibELFAPI.elf64_getshdr(scnPtr);
+
+        // Add name of the section to section name string
+        // If secName is null, point the name to the 0th index
+        // that holds `\0'
+        byte[] modScnData;
+        if (secName.isEmpty()) {
+            JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, 0);
+            modScnData = scnData;
+        } else {
+            if (secName.equals(".shstrtab")) {
+                // Modify .shstrtab data by inserting '\0' at index 0
+                String shstrtabSecName = ".shstrtab" + '\0';
+                // Additional byte for the '\0' at position 0
+                ByteBuffer nbuf = ByteBuffer.allocate(scnData.length + 1 + shstrtabSecName.length());
+                nbuf.put(0, (byte) 0);
+                nbuf.position(1);
+                nbuf.put(scnData);
+                nbuf.position(scnData.length + 1);
+                // Add the section name ".shstrtab" to its own data
+                nbuf.put(shstrtabSecName.getBytes(StandardCharsets.UTF_8));
+                modScnData = nbuf.array();
+                JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, scnData.length + 1);
+                // Set strtab section index
+                JNILibELFAPI.set_Ehdr_e_shstrndx(elfClass, ehdrPtr, JNILibELFAPI.elf_ndxscn(scnPtr));
+            } else if (secName.equals(".strtab")) {
+                // Modify strtab section data to insert '\0' at position 0.
+                // Additional byte for the '\0' at position 0
+                ByteBuffer nbuf = ByteBuffer.allocate(scnData.length + 1);
+                nbuf.put(0, (byte) 0);
+                nbuf.position(1);
+                nbuf.put(scnData);
+                modScnData = nbuf.array();
+                // Set the sh_name
+                JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, shStrTabContent.length() + 1);
+                // Add scnName to stringList
+                shStrTabContent += secName + '\0';
+            } else {
+                // Set the sh_name
+                JNILibELFAPI.set_Shdr_sh_name(elfClass, scnHdrPtr, shStrTabContent.length() + 1);
+                // Add scnName to stringList
+                shStrTabContent += secName + '\0';
+                modScnData = scnData;
+            }
+        }
+
+        final int scnDataBufSize = modScnData.length;
+
+        Pointer scnDataBufPtr = null;
+        if (scnType != ELF.SHT_NOBITS) {
+        // Allocate native memory for section data
+          final long address = UNSAFE.allocateMemory(scnDataBufSize + 1);
+          scnDataBufPtr = new Pointer(address);
+          scnDataBufPtr.put(modScnData);
+        } else {
+          scnDataBufPtr = new Pointer(0L);
+        }
+
+        // Set data descriptor fields
+        JNILibELFAPI.set_Data_d_align(scnDataPtr, align);
+        JNILibELFAPI.set_Data_d_buf(scnDataPtr, scnDataBufPtr);
+        JNILibELFAPI.set_Data_d_size(scnDataPtr, scnDataBufSize);
+        JNILibELFAPI.set_Data_d_off(scnDataPtr, 0);
+        JNILibELFAPI.set_Data_d_type(scnDataPtr, dataType.intValue());
+        JNILibELFAPI.set_Data_d_version(scnDataPtr, ELF.EV_CURRENT);
+
+        JNILibELFAPI.set_Shdr_sh_type(elfClass, scnHdrPtr, scnType);
+        JNILibELFAPI.set_Shdr_sh_flags(elfClass, scnHdrPtr, scnFlags);
+        JNILibELFAPI.set_Shdr_sh_entsize(elfClass, scnHdrPtr, 0); // TODO: Is this right??
+        JNILibELFAPI.set_Shdr_sh_link(elfClass, scnHdrPtr, scnLink);
+        JNILibELFAPI.set_Shdr_sh_info(elfClass, scnHdrPtr, scnInfo);
+
+        // Add hash section to section pointer list
+        int index = JNILibELFAPI.elf_ndxscn(scnPtr);
+        return index;
+    }
+
+    /**
+     * Create an ELF symbol entry for a symbol with the given properties.
+     *
+     * @param name name of the section in which symName is referenced
+     * @param type type of symName
+     * @param bind binding of symName
+     * @param secHdrIndex section header index of the section in which symName is referenced
+     *            (st_shndx of ELF symbol entry)
+     * @param size symName size (st_size of ELF symbol entry)
+     * @param value symName value (st_value of ELF symbol entry)
+     * @param isLocal true if symbol is local.
+     */
+    public ELFSymbol createELFSymbolEntry(String name, int type, int bind, int secHdrIndex, int size, int value, boolean isLocal) {
+        // Get the current symbol index and append symbol name to string table.
+        int index;
+        if (name.isEmpty()) {
+            index = 0;
+        } else {
+            // NOTE: The +1 comes from the null symbol!
+            // We can't trust strTabContent.length() since that is chars (UTF16), keep track of
+            // bytes on our own.
+            index = strTabNrOfBytes + 1;
+            strTabContent.append(name).append('\0');
+            strTabNrOfBytes += name.getBytes(StandardCharsets.UTF_8).length + 1;
+        }
+
+        // Create ELF symbol entry
+        long address = JNILibELFAPI.create_sym_entry(elfClass, index, type, bind, secHdrIndex, size, value);
+        if (address == 0) {
+            throw new InternalError("create_sym_entry failed");
+        }
+        Pointer ptr = new Pointer(address);
+
+        if (isLocal) {
+            final int localIndex = localSymbolIndex.size();
+            ELFSymbol symbol = new ELFSymbol(name, localIndex, ptr, isLocal);
+            localSymbolIndex.add(symbol);
+            return symbol;
+        } else {
+            final int globalIndex = globalSymbolIndex.size();
+            ELFSymbol symbol = new ELFSymbol(name, globalIndex, ptr, isLocal);
+            globalSymbolIndex.add(symbol);
+            return symbol;
+        }
+    }
+
+    /**
+     * Create an ELF relocation entry for given symbol {@code name} to section {@code secname}.
+     *
+     * @param container the section
+     * @param offset offset into the section contents at which the relocation needs to be applied
+     * @param type ELF type of the relocation entry
+     * @param addend Addend for for relocation of type reloca
+     */
+    public void createELFRelocationEntry(ELFContainer container, int offset, int type, int addend, ELFSymbol elfSymbol) {
+        // Get the index of the symbol.
+        int index;
+        if (elfSymbol.isLocal()) {
+            index = elfSymbol.getIndex();
+        } else {
+            /*
+             * For global symbol entries the index will be offset by the number of local symbols
+             * which will be listed first in the symbol table.
+             */
+            index = elfSymbol.getIndex() + localSymbolIndex.size();
+        }
+
+        long address = JNILibELFAPI.create_reloc_entry(elfClass, offset, index, type, addend, createReloca);
+        if (address == 0) {
+            throw new InternalError("create_reloc_entry failed");
+        }
+        Pointer ptr = new Pointer(address);
+        /*
+         * If section name associated with this symbol is set to undefined i.e., secname is null,
+         * symIndex is undef i.e., 0.
+         */
+        if (relocTables.get(container) == null) {
+            // Allocate a new table and add it to the hash table of reloc tables
+            relocTables.put(container, new ArrayList<>());
+        }
+
+        // Add the entry
+        relocTables.get(container).add(ptr);
+    }
+
+    /**
+     * Invokes native libelf function loff_t elf_update (Elf *elfPtr, Elf_Cmd cmd).
+     *
+     * @param cmd command
+     * @return return value of the native function called
+     */
+    public boolean elfUpdate(LibELF.Elf_Cmd cmd) {
+        JNILibELFAPI.elf_update(elfPtr, cmd.intValue());
+        // TODO: Error checking; look at the return value of elf_update
+        // and call elf_errmsg appropriately.
+        return true;
+    }
+
+    /**
+     * Wrapper function that invokes int elf_end (Elf *elfPtr). and closes ELF output file
+     * descriptor
+     *
+     * @return true
+     */
+    public boolean elfEnd() {
+        // Finish ELF processing
+        JNILibELFAPI.elf_end(elfPtr);
+        // Close file descriptor
+        JNILibELFAPI.close(outFileDesc);
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java
new file mode 100644
index 0000000..4c4cffd
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFRelocation.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+/**
+ * Class that abstracts ELF relocations.
+ *
+ */
+public interface JNIELFRelocation {
+    int R_UNDEF = -1;
+
+    /**
+     * x86-specific relocation types.
+     *
+     */
+    public interface I386 {
+        /* i386 relocs. */
+
+        int R_386_NONE = 0; /* No reloc */
+        int R_386_32 = 1; /* Direct 32 bit */
+        int R_386_PC32 = 2; /* PC relative 32 bit */
+        int R_386_GOT32 = 3; /* 32 bit GOT entry */
+        int R_386_PLT32 = 4; /* 32 bit PLT address */
+        int R_386_COPY = 5; /* Copy symbol at runtime */
+        int R_386_GLOB_DAT = 6; /* Create GOT entry */
+        int R_386_JMP_SLOT = 7; /* Create PLT entry */
+        int R_386_RELATIVE = 8; /* Adjust by program base */
+        int R_386_GOTOFF = 9; /* 32 bit offset to GOT */
+        int R_386_GOTPC = 10; /* 32 bit PC relative offset to GOT */
+        int R_386_32PLT = 11;
+        int R_386_TLS_TPOFF = 14; /* Offset in static TLS block */
+        int R_386_TLS_IE = 15; /* Address of GOT entry for static TLS block offset */
+        int R_386_TLS_GOTIE = 16; /* GOT entry for static TLS block offset */
+        int R_386_TLS_LE = 17; /* Offset relative to static TLS block */
+        int R_386_TLS_GD = 18; /* Direct 32 bit for GNU version of general dynamic thread local data */
+        int R_386_TLS_LDM = 19; /*
+                                 * Direct 32 bit for GNU version of local dynamic thread local data
+                                 * in LE code
+                                 */
+        int R_386_16 = 20;
+        int R_386_PC16 = 21;
+        int R_386_8 = 22;
+        int R_386_PC8 = 23;
+        int R_386_TLS_GD_32 = 24; /* Direct 32 bit for general dynamic thread local data */
+        int R_386_TLS_GD_PUSH = 25; /* Tag for pushl in GD TLS code */
+        int R_386_TLS_GD_CALL = 26; /* Relocation for call to __tls_get_addr() */
+        int R_386_TLS_GD_POP = 27; /* Tag for popl in GD TLS code */
+        int R_386_TLS_LDM_32 = 28; /* Direct 32 bit for local dynamic thread local data in LE code */
+        int R_386_TLS_LDM_PUSH = 29; /* Tag for pushl in LDM TLS code */
+        int R_386_TLS_LDM_CALL = 30; /* Relocation for call to __tls_get_addr() in LDM code */
+        int R_386_TLS_LDM_POP = 31; /* Tag for popl in LDM TLS code */
+        int R_386_TLS_LDO_32 = 32; /* Offset relative to TLS block */
+        int R_386_TLS_IE_32 = 33; /* GOT entry for negated static TLS block offset */
+        int R_386_TLS_LE_32 = 34; /* Negated offset relative to static TLS block */
+        int R_386_TLS_DTPMOD32 = 35; /* ID of module containing symbol */
+        int R_386_TLS_DTPOFF32 = 36; /* Offset in TLS block */
+        int R_386_TLS_TPOFF32 = 37; /* Negated offset in static TLS block */
+        int R_386_SIZE32 = 38; /* 32-bit symbol size */
+        int R_386_TLS_GOTDESC = 39; /* GOT offset for TLS descriptor. */
+        int R_386_TLS_DESC_CALL = 40; /* Marker of call through TLS descriptor for relaxation. */
+        int R_386_TLS_DESC = 41; /*
+                                  * TLS descriptor containing pointer to code and to argument,
+                                  * returning the TLS offset for the symbol.
+                                  */
+        int R_386_IRELATIVE = 42; /* Adjust indirectly by program base */
+        /* Keep this the last entry. */
+        int R_386_NUM = 43;
+    }
+
+    /**
+     * x86_64-specific relocation types.
+     */
+    public interface X86_64 {
+        /* AMD x86-64 relocations. */
+        int R_X86_64_NONE = 0; /* No reloc */
+        int R_X86_64_64 = 1; /* Direct 64 bit */
+        int R_X86_64_PC32 = 2; /* PC relative 32 bit signed */
+        int R_X86_64_GOT32 = 3; /* 32 bit GOT entry */
+        int R_X86_64_PLT32 = 4; /* 32 bit PLT address */
+        int R_X86_64_COPY = 5; /* Copy symbol at runtime */
+        int R_X86_64_GLOB_DAT = 6; /* Create GOT entry */
+        int R_X86_64_JUMP_SLOT = 7; /* Create PLT entry */
+        int R_X86_64_RELATIVE = 8; /* Adjust by program base */
+        int R_X86_64_GOTPCREL = 9; /* 32 bit signed PC relative offset to GOT */
+        int R_X86_64_32 = 10; /* Direct 32 bit zero extended */
+        int R_X86_64_32S = 11; /* Direct 32 bit sign extended */
+        int R_X86_64_16 = 12; /* Direct 16 bit zero extended */
+        int R_X86_64_PC16 = 13; /* 16 bit sign extended pc relative */
+        int R_X86_64_8 = 14; /* Direct 8 bit sign extended */
+        int R_X86_64_PC8 = 15; /* 8 bit sign extended pc relative */
+        int R_X86_64_DTPMOD64 = 16; /* ID of module containing symbol */
+        int R_X86_64_DTPOFF64 = 17; /* Offset in module's TLS block */
+        int R_X86_64_TPOFF64 = 18; /* Offset in initial TLS block */
+        int R_X86_64_TLSGD = 19; /*
+                                  * 32 bit signed PC relative offset to two GOT entries for GD
+                                  * symbol
+                                  */
+        int R_X86_64_TLSLD = 20; /*
+                                  * 32 bit signed PC relative offset to two GOT entries for LD
+                                  * symbol
+                                  */
+        int R_X86_64_DTPOFF32 = 21; /* Offset in TLS block */
+        int R_X86_64_GOTTPOFF = 22; /*
+                                     * 32 bit signed PC relative offset to GOT entry for IE symbol
+                                     */
+        int R_X86_64_TPOFF32 = 23; /* Offset in initial TLS block */
+        int R_X86_64_PC64 = 24; /* PC relative 64 bit */
+        int R_X86_64_GOTOFF64 = 25; /* 64 bit offset to GOT */
+        int R_X86_64_GOTPC32 = 26; /* 32 bit signed pc relative offset to GOT */
+        int R_X86_64_GOT64 = 27; /* 64-bit GOT entry offset */
+        int R_X86_64_GOTPCREL64 = 28; /* 64-bit PC relative offset to GOT entry */
+        int R_X86_64_GOTPC64 = 29; /* 64-bit PC relative offset to GOT */
+        int R_X86_64_GOTPLT64 = 30; /* like GOT64, says PLT entry needed */
+        int R_X86_64_PLTOFF64 = 31; /* 64-bit GOT relative offset to PLT entry */
+        int R_X86_64_SIZE32 = 32; /* Size of symbol plus 32-bit addend */
+        int R_X86_64_SIZE64 = 33; /* Size of symbol plus 64-bit addend */
+        int R_X86_64_GOTPC32_TLSDESC = 34; /* GOT offset for TLS descriptor. */
+        int R_X86_64_TLSDESC_CALL = 35; /*
+                                         * Marker for call through TLS descriptor.
+                                         */
+        int R_X86_64_TLSDESC = 36; /* TLS descriptor. */
+        int R_X86_64_IRELATIVE = 37; /* Adjust indirectly by program base */
+        int R_X86_64_RELATIVE64 = 38; /* 64-bit adjust by program base */
+
+        int R_X86_64_NUM = 39;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java
new file mode 100644
index 0000000..8248d6f
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNIELFTargetInfo.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+import java.nio.ByteOrder;
+
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
+
+/**
+ * Class that abstracts ELF target details.
+ *
+ */
+public class JNIELFTargetInfo {
+    /**
+     * ELF Class of the target.
+     */
+    private static final int elfClass;
+    /**
+     * Target architecture.
+     */
+    private static final int arch;
+    /**
+     * Architecture endian-ness.
+     */
+    private static final int endian;
+
+    /**
+     * Target OS string.
+     */
+    private static final String osName;
+
+    static {
+        // Find the target arch details
+        String archStr = System.getProperty("os.arch").toLowerCase();
+        String datamodelStr = System.getProperty("sun.arch.data.model");
+
+        if (datamodelStr.equals("32")) {
+            elfClass = ELF.ELFCLASS32;
+        } else if (datamodelStr.equals("64")) {
+            elfClass = ELF.ELFCLASS64;
+        } else {
+            System.out.println("Failed to discover ELF class!");
+            elfClass = ELF.ELFCLASSNONE;
+        }
+
+        ByteOrder bo = ByteOrder.nativeOrder();
+        if (bo == ByteOrder.LITTLE_ENDIAN) {
+            endian = ELF.ELFDATA2LSB;
+        } else if (bo == ByteOrder.BIG_ENDIAN) {
+            endian = ELF.ELFDATA2MSB;
+        } else {
+            System.out.println("Failed to discover endian-ness!");
+            endian = ELF.ELFDATANONE;
+        }
+
+        if (archStr.equals("x86")) {
+            arch = ELF.EM_386;
+        } else if (archStr.equals("amd64") || archStr.equals("x86_64")) {
+            arch = ELF.EM_X64_64;
+        } else if (archStr.equals("sparcv9")) {
+            arch = ELF.EM_SPARCV9;
+        } else {
+            System.out.println("Unsupported architecture " + archStr);
+            arch = ELF.EM_NONE;
+        }
+
+        osName = System.getProperty("os.name").toLowerCase();
+    }
+
+    public static int getELFArch() {
+        return arch;
+    }
+
+    public static int getELFClass() {
+        return elfClass;
+    }
+
+    public static int getELFEndian() {
+        return endian;
+    }
+
+    public static String getOsName() {
+        return osName;
+    }
+
+    public static int createReloca() {
+        switch (arch) {
+            case ELF.EM_X64_64:
+                return 1;
+            default:
+                return 0;
+        }
+    }
+
+    public static int sizeOfSymtabEntry() {
+        return JNILibELFAPI.size_of_Sym(elfClass);
+    }
+
+    public static int sizeOfRelocEntry() {
+        if (createReloca() == 1) {
+            return JNILibELFAPI.size_of_Rela(elfClass);
+        } else {
+            return JNILibELFAPI.size_of_Rel(elfClass);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java
new file mode 100644
index 0000000..5dc277b
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/JNILibELFAPI.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+public class JNILibELFAPI {
+
+    static {
+        System.loadLibrary("jelfshim");
+    }
+
+    /**
+     * Definitions for file open.
+     */
+    public static enum OpenFlags {
+        O_RDONLY(0x0),
+        O_WRONLY(0x1),
+        O_RDWR(0x2),
+        O_CREAT(0x40);
+
+        private final int intVal;
+
+        private OpenFlags(int v) {
+            intVal = v;
+        }
+
+        public int intValue() {
+            return intVal;
+        }
+    }
+
+    /**
+     * Definitions reflecting those in elf.h.
+     *
+     */
+    public interface ELF {
+        int EI_NIDENT = 16;
+
+        int EI_CLASS = 4; /* File class byte index */
+        int ELFCLASSNONE = 0; /* Invalid class */
+        int ELFCLASS32 = 1; /* 32-bit objects */
+        int ELFCLASS64 = 2; /* 64-bit objects */
+        int ELFCLASSNUM = 3;
+
+        int EI_DATA = 5; /* Data encoding byte index */
+        int ELFDATANONE = 0; /* Invalid data encoding */
+        int ELFDATA2LSB = 1; /* 2's complement, little endian */
+        int ELFDATA2MSB = 2; /* 2's complement, big endian */
+        int ELFDATANUM = 3;
+
+        // Legal architecture values for e_machine (add others as needed)
+        int EM_NONE = 0; /* No machine */
+        int EM_SPARC = 2; /* SUN SPARC */
+        int EM_386 = 3; /* Intel 80386 */
+        int EM_SPARCV9 = 43; /* SPARC v9 64-bit */
+        int EM_X64_64 = 62; /* AMD x86-64 architecture */
+
+        /* Legal values for e_type (object file type). */
+
+        int ET_NONE = 0; /* No file type */
+        int ET_REL = 1; /* Relocatable file */
+        int ET_EXEC = 2; /* Executable file */
+        int ET_DYN = 3; /* Shared object file */
+        int ET_CORE = 4; /* Core file */
+        int ET_NUM = 5; /* Number of defined types */
+        int ET_LOOS = 0xfe00; /* OS-specific range start */
+        int ET_HIOS = 0xfeff; /* OS-specific range end */
+        int ET_LOPROC = 0xff00; /* Processor-specific range start */
+        int ET_HIPROC = 0xffff; /* Processor-specific range end */
+
+        /* Legal values for e_version (version). */
+
+        int EV_NONE = 0; /* Invalid ELF version */
+        int EV_CURRENT = 1; /* Current version */
+        int EV_NUM = 2;
+
+        /* Legal values for p_type (segment type). */
+
+        int PT_NULL = 0; /* Program header table entry unused */
+        int PT_LOAD = 1; /* Loadable program segment */
+        int PT_DYNAMIC = 2; /* Dynamic linking information */
+        int PT_INTERP = 3; /* Program interpreter */
+        int PT_NOTE = 4; /* Auxiliary information */
+        int PT_SHLIB = 5; /* Reserved */
+        int PT_PHDR = 6; /* Entry for header table itself */
+        int PT_TLS = 7; /* Thread-local storage segment */
+        int PT_NUM = 8; /* Number of defined types */
+        int PT_LOOS = 0x60000000; /* Start of OS-specific */
+        int PT_GNU_EH_FRAME = 0x6474e550; /* GCC .eh_frame_hdr segment */
+        int PT_GNU_STACK = 0x6474e551; /* Indicates stack executability */
+        int PT_GNU_RELRO = 0x6474e552; /* Read-only after relocation */
+        int PT_LOSUNW = 0x6ffffffa;
+        int PT_SUNWBSS = 0x6ffffffa; /* Sun Specific segment */
+        int PT_SUNWSTACK = 0x6ffffffb; /* Stack segment */
+        int PT_HISUNW = 0x6fffffff;
+        int PT_HIOS = 0x6fffffff; /* End of OS-specific */
+        int PT_LOPROC = 0x70000000; /* Start of processor-specific */
+        int PT_HIPROC = 0x7fffffff; /* End of processor-specific */
+
+        /* Special section indices. */
+
+        int SHN_UNDEF = 0; /* Undefined section */
+        int SHN_LORESERVE = 0xff00; /* Start of reserved indices */
+        int SHN_LOPROC = 0xff00; /* Start of processor-specific */
+        int SHN_BEFORE = 0xff00; /* Order section before all others (Solaris). */
+        int SHN_AFTER = 0xff01; /* Order section after all others (Solaris). */
+        int SHN_HIPROC = 0xff1f; /* End of processor-specific */
+        int SHN_LOOS = 0xff20; /* Start of OS-specific */
+        int SHN_HIOS = 0xff3f; /* End of OS-specific */
+        int SHN_ABS = 0xfff1; /* Associated symbol is absolute */
+        int SHN_COMMON = 0xfff2; /* Associated symbol is common */
+        int SHN_XINDEX = 0xffff; /* Index is in extra table. */
+        int SHN_HIRESERVE = 0xffff; /* End of reserved indices */
+
+        /* Legal values for sh_type (section type). */
+
+        int SHT_NULL = 0; /* Section header table entry unused */
+        int SHT_PROGBITS = 1; /* Program data */
+        int SHT_SYMTAB = 2; /* Symbol table */
+        int SHT_STRTAB = 3; /* String table */
+        int SHT_RELA = 4; /* Relocation entries with addends */
+        int SHT_HASH = 5; /* Symbol hash table */
+        int SHT_DYNAMIC = 6; /* Dynamic linking information */
+        int SHT_NOTE = 7; /* Notes */
+        int SHT_NOBITS = 8; /* Program space with no data (bss) */
+        int SHT_REL = 9; /* Relocation entries, no addends */
+        int SHT_SHLIB = 10; /* Reserved */
+        int SHT_DYNSYM = 11; /* Dynamic linker symbol table */
+        int SHT_INIT_ARRAY = 14; /* Array of constructors */
+        int SHT_FINI_ARRAY = 15; /* Array of destructors */
+        int SHT_PREINIT_ARRAY = 16; /* Array of pre-constructors */
+        int SHT_GROUP = 17; /* Section group */
+        int SHT_SYMTAB_SHNDX = 18; /* Extended section indeces */
+        int SHT_NUM = 19; /* Number of defined types. */
+        int SHT_LOOS = 0x60000000; /* Start OS-specific. */
+        int SHT_GNU_ATTRIBUTES = 0x6ffffff5; /* Object attributes. */
+        int SHT_GNU_HASH = 0x6ffffff6; /* GNU-style hash table. */
+        int SHT_GNU_LIBLIST = 0x6ffffff7; /* Prelink library list */
+        int SHT_CHECKSUM = 0x6ffffff8; /* Checksum for DSO content. */
+        int SHT_LOSUNW = 0x6ffffffa; /* Sun-specific low bound. */
+        int SHT_SUNW_move = 0x6ffffffa;
+        int SHT_SUNW_COMDAT = 0x6ffffffb;
+        int SHT_SUNW_syminfo = 0x6ffffffc;
+        int SHT_GNU_verdef = 0x6ffffffd; /* Version definition section. */
+        int SHT_GNU_verneed = 0x6ffffffe; /* Version needs section. */
+        int SHT_GNU_versym = 0x6fffffff; /* Version symbol table. */
+        int SHT_HISUNW = 0x6fffffff; /* Sun-specific high bound. */
+        int SHT_HIOS = 0x6fffffff; /* End OS-specific type */
+        int SHT_LOPROC = 0x70000000; /* Start of processor-specific */
+        int SHT_HIPROC = 0x7fffffff; /* End of processor-specific */
+        int SHT_LOUSER = 0x80000000; /* Start of application-specific */
+        int SHT_HIUSER = 0x8fffffff; /* End of application-specific */
+
+        /* Legal values for sh_flags (section flags). */
+
+        int SHF_WRITE = (1 << 0); /* Writable */
+        int SHF_ALLOC = (1 << 1); /* Occupies memory during execution */
+        int SHF_EXECINSTR = (1 << 2); /* Executable */
+        int SHF_MERGE = (1 << 4); /* Might be merged */
+        int SHF_STRINGS = (1 << 5); /* Contains nul-terminated strings */
+        int SHF_INFO_LINK = (1 << 6); /* `sh_info' contains SHT index */
+        int SHF_LINK_ORDER = (1 << 7); /* Preserve order after combining */
+        int SHF_OS_NONCONFORMING = (1 << 8); /* Non-standard OS specific handling required */
+        int SHF_GROUP = (1 << 9); /* Section is member of a group. */
+        int SHF_TLS = (1 << 10); /* Section hold thread-local data. */
+        int SHF_MASKOS = 0x0ff00000; /* OS-specific. */
+        int SHF_MASKPROC = 0xf0000000; /* Processor-specific */
+        int SHF_ORDERED = (1 << 30); /* Special ordering requirement (Solaris). */
+        int SHF_EXCLUDE = (1 << 31); /*
+                                      * Section is excluded unless referenced or allocated
+                                      * (Solaris).
+                                      */
+
+        /* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+        int STB_LOCAL = 0; /* Local symbol */
+        int STB_GLOBAL = 1; /* Global symbol */
+        int STB_WEAK = 2; /* Weak symbol */
+        int STB_NUM = 3; /* Number of defined types. */
+        int STB_LOOS = 10; /* Start of OS-specific */
+        int STB_GNU_UNIQUE = 10; /* Unique symbol. */
+        int STB_HIOS = 12; /* End of OS-specific */
+        int STB_LOPROC = 13; /* Start of processor-specific */
+        int STB_HIPROC = 15; /* End of processor-specific */
+
+        /* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+        int STT_NOTYPE = 0; /* Symbol type is unspecified */
+        int STT_OBJECT = 1; /* Symbol is a data object */
+        int STT_FUNC = 2; /* Symbol is a code object */
+        int STT_SECTION = 3; /* Symbol associated with a section */
+        int STT_FILE = 4; /* Symbol's name is file name */
+        int STT_COMMON = 5; /* Symbol is a common data object */
+        int STT_TLS = 6; /* Symbol is thread-local data object */
+        int STT_NUM = 7; /* Number of defined types. */
+        int STT_LOOS = 10; /* Start of OS-specific */
+        int STT_GNU_IFUNC = 10; /* Symbol is indirect code object */
+        int STT_HIOS = 12; /* End of OS-specific */
+        int STT_LOPROC = 13; /* Start of processor-specific */
+        int STT_HIPROC = 15; /* End of processor-specific */
+    }
+
+    /**
+     * Definitions reflecting those in libelf.h.
+     *
+     */
+    public interface LibELF {
+
+        public static enum Elf_Cmd {
+            ELF_C_NULL("NULL"), /* Nothing, terminate, or compute only. */
+            ELF_C_READ("READ"), /* Read .. */
+            ELF_C_RDWR("RDWR"), /* Read and write .. */
+            ELF_C_WRITE("WRITE"), /* Write .. */
+            ELF_C_CLR("CLR"), /* Clear flag. */
+            ELF_C_SET("SET"), /* Set flag. */
+            ELF_C_FDDONE("FDDONE"), /*
+                                     * Signal that file descriptor will not be used anymore.
+                                     */
+            ELF_C_FDREAD("FDREAD"), /*
+                                     * Read rest of data so that file descriptor is not used
+                                     * anymore.
+                                     */
+            /* The following are Linux-only extensions. */
+            ELF_C_READ_MMAP("READ_MMAP"), /* Read, but mmap the file if possible. */
+            ELF_C_RDWR_MMAP("RDWR_MMAP"), /* Read and write, with mmap. */
+            ELF_C_WRITE_MMAP("WRITE_MMAP"), /* Write, with mmap. */
+            ELF_C_READ_MMAP_PRIVATE("READ_MMAP_PRIVATE"), /*
+                                                           * Read, but memory is writable, results
+                                                           * are not written to the file.
+                                                           */
+            ELF_C_EMPTY("EMPTY"), /* Copy basic file data but not the content. */
+            /* The following are SunOS-only enums */
+            ELF_C_WRIMAGE("WRIMAGE"),
+            ELF_C_IMAGE("IMAGE"),
+            /* Common last entry. */
+            ELF_C_NUM("NUM");
+            private final int intVal;
+            private final String name;
+
+            private Elf_Cmd(String cmd) {
+                name = "ELF_C_" + cmd;
+                switch (cmd) {
+                    case "NULL":
+                        // ELF_C_NULL has the same enum ordinal on both Linux and SunOS
+                        intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_NULL.ordinal();
+                        break;
+
+                    case "READ":
+                        // ELF_C_READ has the same enum ordinal on both Linux and SunOS
+                        intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ.ordinal();
+                        break;
+
+                    // Enums defined in libelf.h of both Linux and SunOS
+                    // but with different ordinals
+                    case "RDWR":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_RDWR.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_RDWR.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "WRITE":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_WRITE.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_WRITE.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "CLR":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_CLR.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_CLR.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "SET":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_SET.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_SET.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "FDDONE":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_FDDONE.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_FDDONE.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "FDREAD":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_FDREAD.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_FDREAD.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "NUM":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_NUM.ordinal();
+                        } else if (JNIELFTargetInfo.getOsName().equals("sunos")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_NUM.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    // Linux-only Elf_Cmd enums
+                    case "READ_MMAP":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ_MMAP.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "RDWR_MMAP":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_RDWR_MMAP.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "WRITE_MMAP":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_WRITE_MMAP.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "READ_MMAP_PRIVATE":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_READ_MMAP_PRIVATE.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+
+                    case "EMPTY":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.linux.Elf_Cmd.ELF_C_EMPTY.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+                    // SunOS-only Elf_Cmd enums
+                    case "WRIMAGE":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_WRIMAGE.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+                    case "IMAGE":
+                        if (JNIELFTargetInfo.getOsName().equals("linux")) {
+                            intVal = jdk.tools.jaotc.jnilibelf.sunos.Elf_Cmd.ELF_C_IMAGE.ordinal();
+                        } else {
+                            // Unsupported platform
+                            intVal = -1;
+                        }
+                        break;
+                    default:
+                        intVal = -1;
+                }
+            }
+
+            public int intValue() {
+                assert intVal != -1 : "enum " + name + "not supported on " + JNIELFTargetInfo.getOsName();
+                return intVal;
+            }
+
+            public String getName() {
+                return name;
+            }
+        }
+
+        public static enum Elf_Type {
+            ELF_T_BYTE(0), /* unsigned char */
+            ELF_T_ADDR(1), /* Elf32_Addr, Elf64_Addr, ... */
+            ELF_T_DYN(2), /* Dynamic section record. */
+            ELF_T_EHDR(3), /* ELF header. */
+            ELF_T_HALF(4), /* Elf32_Half, Elf64_Half, ... */
+            ELF_T_OFF(5), /* Elf32_Off, Elf64_Off, ... */
+            ELF_T_PHDR(6), /* Program header. */
+            ELF_T_RELA(7), /* Relocation entry with addend. */
+            ELF_T_REL(8), /* Relocation entry. */
+            ELF_T_SHDR(9), /* Section header. */
+            ELF_T_SWORD(10), /* Elf32_Sword, Elf64_Sword, ... */
+            ELF_T_SYM(11), /* Symbol record. */
+            ELF_T_WORD(12), /* Elf32_Word, Elf64_Word, ... */
+            ELF_T_XWORD(13), /* Elf32_Xword, Elf64_Xword, ... */
+            ELF_T_SXWORD(14), /* Elf32_Sxword, Elf64_Sxword, ... */
+            ELF_T_VDEF(15), /* Elf32_Verdef, Elf64_Verdef, ... */
+            ELF_T_VDAUX(16), /* Elf32_Verdaux, Elf64_Verdaux, ... */
+            ELF_T_VNEED(17), /* Elf32_Verneed, Elf64_Verneed, ... */
+            ELF_T_VNAUX(18), /* Elf32_Vernaux, Elf64_Vernaux, ... */
+            ELF_T_NHDR(19), /* Elf32_Nhdr, Elf64_Nhdr, ... */
+            ELF_T_SYMINFO(20), /* Elf32_Syminfo, Elf64_Syminfo, ... */
+            ELF_T_MOVE(21), /* Elf32_Move, Elf64_Move, ... */
+            ELF_T_LIB(22), /* Elf32_Lib, Elf64_Lib, ... */
+            ELF_T_GNUHASH(23), /* GNU-style hash section. */
+            ELF_T_AUXV(24), /* Elf32_auxv_t, Elf64_auxv_t, ... */
+            /* Keep this the last entry. */
+            ELF_T_NUM(25);
+
+            private final int intVal;
+
+            private Elf_Type(int v) {
+                intVal = v;
+            }
+
+            public int intValue() {
+                return intVal;
+            }
+        }
+
+        /* Flags for the ELF structures. */
+        int ELF_F_DIRTY = 0x1;
+        int ELF_F_LAYOUT = 0x4;
+        int ELF_F_PERMISSIVE = 0x8;
+
+        public static enum Elf_Kind {
+            ELF_K_NONE(0), /* Unknown. */
+            ELF_K_AR(1), /* Archive. */
+            ELF_K_COFF(2), /* Stupid old COFF. */
+            ELF_K_ELF(3), /* ELF file. */
+            /* Keep this the last entry. */
+            ELF_K_NUM(4);
+            private final int intVal;
+
+            private Elf_Kind(int v) {
+                intVal = v;
+            }
+
+            public int intValue() {
+                return intVal;
+            }
+        }
+    }
+
+    /**
+     * Invoke native libelf function unsigned int elf_version (unsigned int v).
+     *
+     * @param v version
+     * @return return value of native call
+     */
+    // Checkstyle: stop method name check
+    static native int elf_version(int v);
+
+    /**
+     * Return version recorded in libelfshim.
+     *
+     * @return return version string
+     */
+    // Checkstyle: stop method name check
+    static native String elfshim_version();
+
+    /**
+     * Invoke native libelf function Elf *elf_begin (int fildes, Elf_Cmd cmd, Elf *elfPtr).
+     *
+     * @param fildes open file descriptor
+     * @param elfCRead command
+     * @param elfHdrPtr pointer to ELF header
+     * @return return value of native call
+     */
+    static native Pointer elf_begin(int fildes, int elfCRead, Pointer elfHdrPtr);
+
+    /**
+     * Invoke native libelf function elf_end (Elf *elfPtr).
+     *
+     * @param elfPtr pointer to ELF header
+     * @return return value of native call
+     */
+    static native int elf_end(Pointer elfPtr);
+
+    /**
+     * Invoke native libelf function elf_end (Elf *elfPtr).
+     *
+     * @param elfPtr pointer to ELF header
+     * @return return value of native call
+     */
+    static native int elf_kind(Pointer elfPtr);
+
+    /**
+     * Invoke native libelf function unsigned int elf_flagphdr (Elf *elf, Elf_Cmd cmd, unsigned int
+     * flags).
+     *
+     * @param elfPtr Pointer to ELF descriptor
+     * @param cmd command
+     * @param flags flags
+     * @return return value of native call
+     */
+    static native int elf_flagphdr(Pointer elfPtr, int cmd, int flags);
+
+    /**
+     * Invoke native libelf function Elf_Scn *elf_newscn (Elf *elfPtr).
+     *
+     * @param elfPtr Elf header pointer
+     * @return return value of native call
+     */
+    static native Pointer elf_newscn(Pointer elfPtr);
+
+    /**
+     * Invoke native libelf function Elf_Data *elf_newdata (Elf_Scn *scn).
+     *
+     * @param scnPtr pointer to section for which the new data descriptor is to be created
+     * @return return value of native call
+     */
+    static native Pointer elf_newdata(Pointer scnPtr);
+
+    /**
+     * Invoke native libelf function Elf64_Shdr *elf64_getshdr (Elf_Scn *scnPtr).
+     *
+     * @param scnPtr pointer to section whose header information is to be retrieved
+     * @return return value of native call
+     */
+    static native Pointer elf64_getshdr(Pointer scnPtr);
+
+    /**
+     * Invoke native libelf function loff_t elf_update (Elf *elfPtr, Elf_Cmd cmd).
+     *
+     * @param elfPtr Pointer to ELF descriptor
+     * @param cmd command
+     * @return return value of native call
+     */
+    static native long elf_update(Pointer elfPtr, int cmd);
+
+    /**
+     * Invoke native libelf function char *elf_errmsg (int error).
+     *
+     * @param error error
+     * @return return value of native call
+     */
+    static native String elf_errmsg(int error);
+
+    /**
+     * Invoke native libelf function size_t elf_ndxscn (Elf_Scn *scn).
+     *
+     * @param scn section pointer
+     * @return return value of native call
+     */
+    static native int elf_ndxscn(Pointer scn);
+
+    /**
+     * GELF interfaces
+     */
+    /**
+     * Invoke native libelf function unsigned long int gelf_newehdr (Elf *elf, int elfClass).
+     *
+     * @param elf ELF Header pointer
+     * @param elfclass ELF class
+     * @return return value of native call boxed as a pointer
+     */
+    static native Pointer gelf_newehdr(Pointer elf, int elfclass);
+
+    /**
+     * Invoke native libelf function unsigned long int gelf_newphdr (Elf *elf, size_t phnum).
+     *
+     * @param elf ELF header pointer
+     * @param phnum number of program headers
+     * @return return value of native call boxed as a pointer
+     */
+    static native Pointer gelf_newphdr(Pointer elf, int phnum);
+
+    /**
+     * Miscellaneous convenience native methods that help peek and poke ELF data structures.
+     */
+    static native int size_of_Sym(int elfClass);
+
+    static native int size_of_Rela(int elfClass);
+
+    static native int size_of_Rel(int elfClass);
+
+    static native void ehdr_set_data_encoding(Pointer ehdr, int val);
+
+    static native void set_Ehdr_e_machine(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Ehdr_e_type(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Ehdr_e_version(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Ehdr_e_shstrndx(int elfclass, Pointer structPtr, int val);
+
+    static native void phdr_set_type_self(int elfclass, Pointer ehdr, Pointer phdr);
+
+    static native void set_Shdr_sh_name(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Shdr_sh_type(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Shdr_sh_flags(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Shdr_sh_entsize(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Shdr_sh_link(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Shdr_sh_info(int elfclass, Pointer structPtr, int val);
+
+    static native void set_Data_d_align(Pointer structPtr, int val);
+
+    static native void set_Data_d_off(Pointer structPtr, int val);
+
+    static native void set_Data_d_buf(Pointer structPtr, Pointer val);
+
+    static native void set_Data_d_type(Pointer structPtr, int val);
+
+    static native void set_Data_d_size(Pointer structPtr, int val);
+
+    static native void set_Data_d_version(Pointer structPtr, int val);
+
+    static native long create_sym_entry(int elfclass, int index, int type, int bind, int shndx, int size, int value);
+
+    static native long create_reloc_entry(int elfclass, int roffset, int symtabIdx, int relocType, int raddend, int reloca);
+
+    /**
+     * File Operations.
+     */
+    static native int open_rw(String fileName);
+
+    static native int open(String fileName, int flags);
+
+    static native int open(String fileName, int flags, int mode);
+
+    static native int close(int fd);
+    // Checkstyle: resume method name check
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java
new file mode 100644
index 0000000..a569584
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/Pointer.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+import jdk.internal.misc.Unsafe;
+
+import static jdk.tools.jaotc.jnilibelf.UnsafeAccess.UNSAFE;
+
+public class Pointer {
+
+    private final long address;
+
+    public Pointer(long val) {
+        address = val;
+    }
+
+    /**
+     * Put (i.e., copy) content of byte array at consecutive addresses beginning at this Pointer.
+     *
+     * @param src source byte array
+     */
+    public void put(byte[] src) {
+        UNSAFE.copyMemory(src, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, address, src.length);
+    }
+
+    /**
+     * Get (i.e., copy) content at this Pointer to the given byte array.
+     *
+     * @param dst destination byte array
+     */
+    public void get(byte[] dst) {
+        UNSAFE.copyMemory(null, address, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET, dst.length);
+    }
+
+    /**
+     * Read {@code readSize} number of bytes to copy them starting at {@code startIndex} of
+     * {@code byteArray}
+     *
+     * @param byteArray target array to copy bytes
+     * @param readSize number of bytes to copy
+     * @param startIndex index of the array to start copy at
+     */
+    public void copyBytesTo(byte[] byteArray, int readSize, int startIndex) {
+        long end = (long)startIndex + (long)readSize;
+        if (end > byteArray.length) {
+            throw new IllegalArgumentException("writing beyond array bounds");
+        }
+        UNSAFE.copyMemory(null, address, byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET+startIndex, readSize);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java
new file mode 100644
index 0000000..08e2710
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/UnsafeAccess.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf;
+
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java
new file mode 100644
index 0000000..a32d202
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/linux/Elf_Cmd.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf.linux;
+
+/**
+ * Represent Elf_Cmd enums defined in libelf.h on Linux as they slightly different from libelf.h on
+ * SunOS.
+ */
+public enum Elf_Cmd {
+    /** Nothing, terminate, or compute only. */
+    ELF_C_NULL,
+
+    /** Read. */
+    ELF_C_READ,
+
+    /** Read and write. */
+    ELF_C_RDWR,
+
+    /** Write. */
+    ELF_C_WRITE,
+
+    /** Clear flag. */
+    ELF_C_CLR,
+
+    /** Set flag. */
+    ELF_C_SET,
+
+    /**
+     * Signal that file descriptor will not be used anymore.
+     */
+    ELF_C_FDDONE,
+
+    /**
+     * Read rest of data so that file descriptor is not used anymore.
+     */
+    ELF_C_FDREAD,
+
+    /* The following are extensions. */
+
+    /** Read, but mmap the file if possible. */
+    ELF_C_READ_MMAP,
+
+    /** Read and write, with mmap. */
+    ELF_C_RDWR_MMAP,
+
+    /** Write, with mmap. */
+    ELF_C_WRITE_MMAP,
+
+    /**
+     * Read, but memory is writable, results are not written to the file.
+     */
+    ELF_C_READ_MMAP_PRIVATE,
+
+    /** Copy basic file data but not the content. */
+    ELF_C_EMPTY,
+
+    /** Keep this the last entry. */
+    ELF_C_NUM;
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java
new file mode 100644
index 0000000..be7423c
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.jnilibelf/src/jdk/tools/jaotc/jnilibelf/sunos/Elf_Cmd.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf.sunos;
+
+/**
+ * Represent Elf_Cmd enums defined in libelf.h on SunOS as they slightly different from libelf.h on
+ * Linux.
+ */
+public enum Elf_Cmd {
+    /** Must be first, 0. */
+    ELF_C_NULL,
+
+    ELF_C_READ,
+    ELF_C_WRITE,
+    ELF_C_CLR,
+    ELF_C_SET,
+    ELF_C_FDDONE,
+    ELF_C_FDREAD,
+    ELF_C_RDWR,
+    ELF_C_WRIMAGE,
+    ELF_C_IMAGE,
+
+    /** Must be last. */
+    ELF_C_NUM
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
new file mode 100644
index 0000000..b5d081a
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+
+import java.util.ListIterator;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+public class AOTBackend {
+
+    private final Main main;
+
+    private final HotSpotBackend backend;
+
+    private final HotSpotProviders providers;
+    private final HotSpotCodeCacheProvider codeCache;
+    private final PhaseSuite<HighTierContext> graphBuilderSuite;
+    private final HighTierContext highTierContext;
+    private final GraalFilters filters;
+
+    public AOTBackend(Main main, HotSpotBackend backend, GraalFilters filters) {
+        this.main = main;
+        this.backend = backend;
+        this.filters = filters;
+        providers = backend.getProviders();
+        codeCache = providers.getCodeCache();
+        graphBuilderSuite = initGraphBuilderSuite(backend);
+        highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
+    }
+
+    private Suites getSuites() {
+        // create suites every time, as we modify options for the compiler
+        return backend.getSuites().getDefaultSuites();
+    }
+
+    private LIRSuites getLirSuites() {
+        // create suites every time, as we modify options for the compiler
+        return backend.getSuites().getDefaultLIRSuites();
+    }
+
+    @SuppressWarnings("try")
+    public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod) {
+        try (OverrideScope s = OptionValue.override(ImmutableCode, true, GeneratePIC, true)) {
+            StructuredGraph graph = buildStructuredGraph(resolvedMethod);
+            if (graph != null) {
+                return compileGraph(resolvedMethod, graph);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Build a structured graph for the member.
+     *
+     * @param javaMethod method for whose code the graph is to be created
+     * @return structured graph
+     */
+    @SuppressWarnings("try")
+    private StructuredGraph buildStructuredGraph(ResolvedJavaMethod javaMethod) {
+        try (Scope s = Debug.scope("AOTParseMethod")) {
+            StructuredGraph graph = new StructuredGraph(javaMethod, StructuredGraph.AllowAssumptions.NO, false, CompilationIdentifier.INVALID_COMPILATION_ID);
+            graphBuilderSuite.apply(graph, highTierContext);
+            return graph;
+        } catch (Throwable e) {
+            handleError(javaMethod, e, " (building graph)");
+        }
+        return null;
+    }
+
+    @SuppressWarnings("try")
+    private CompilationResult compileGraph(ResolvedJavaMethod resolvedMethod, StructuredGraph graph) {
+        try (Scope s = Debug.scope("AOTCompileMethod")) {
+            ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
+
+            final boolean isImmutablePIC = true;
+            CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC);
+
+            return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
+                            compilationResult, CompilationResultBuilderFactory.Default);
+
+        } catch (Throwable e) {
+            handleError(resolvedMethod, e, " (compiling graph)");
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether the VM is a debug build.
+     *
+     * @return true is debug VM, false otherwise
+     */
+    public boolean isDebugVM() {
+        return backend.getRuntime().getVMConfig().cAssertions;
+    }
+
+    private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend) {
+        PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
+        ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
+        GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
+
+        // Use all default plugins.
+        Plugins plugins = baseConfig.getPlugins();
+        GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+
+        iterator.next();
+        iterator.remove();
+        iterator.add(new GraphBuilderPhase(aotConfig));
+
+        return graphBuilderSuite;
+    }
+
+    private void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
+        String methodName = MiscUtils.uniqueMethodName(resolvedMethod);
+
+        if (main.options.debug) {
+            main.printError("Failed compilation: " + methodName + ": " + e);
+        }
+
+        // Ignore some exceptions when meta-compiling Graal.
+        if (filters.shouldIgnoreException(e)) {
+            return;
+        }
+
+        Main.writeLog("Failed compilation of method " + methodName + message);
+
+        if (!main.options.debug) {
+            main.printError("Failed compilation: " + methodName + ": " + e);
+        }
+
+        if (main.options.verbose) {
+            e.printStackTrace(main.log);
+        }
+
+        if (main.options.exitOnError) {
+            System.exit(1);
+        }
+    }
+
+    public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
+        // This is really not installing the method.
+        InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult), null, null);
+        String disassembly = codeCache.disassemble(installedCode);
+        if (disassembly != null) {
+            main.printlnDebug(disassembly);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java
new file mode 100644
index 0000000..f92ead4
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompilerOptions;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.Management;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.DebugScope;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * Represents a task in the compile queue.
+ *
+ * This class encapsulates all Graal-specific information that is used during offline AOT
+ * compilation of classes. It also defines methods that parse compilation result of Graal to create
+ * target-independent representation {@code BinaryContainer} of the intended target binary.
+ */
+public class AOTCompilationTask implements Runnable, Comparable<Object> {
+
+    private static final AtomicInteger ids = new AtomicInteger();
+
+    private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean();
+
+    private final Main main;
+
+    /**
+     * The compilation id of this task.
+     */
+    private final int id;
+
+    private final AOTCompiledClass holder;
+
+    /**
+     * Method this task represents.
+     */
+    private final ResolvedJavaMethod method;
+
+    private final AOTBackend aotBackend;
+
+    /**
+     * The result of this compilation task.
+     */
+    private CompiledMethodInfo result;
+
+    public AOTCompilationTask(Main main, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
+        this.main = main;
+        this.id = ids.getAndIncrement();
+        this.holder = holder;
+        this.method = method;
+        this.aotBackend = aotBackend;
+    }
+
+    /**
+     * Compile a method or a constructor.
+     */
+    public void run() {
+        // Ensure a JVMCI runtime is initialized prior to Debug being initialized as the former
+        // may include processing command line options used by the latter.
+        HotSpotJVMCIRuntime.runtime();
+
+        // Ensure a debug configuration for this thread is initialized
+        if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+            DebugEnvironment.initialize(TTY.out);
+        }
+        AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
+
+        final long threadId = Thread.currentThread().getId();
+
+        final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue() && !TTY.isSuppressed();
+        final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue() && !TTY.isSuppressed();
+        if (printCompilation) {
+            TTY.println(getMethodDescription() + "...");
+        }
+
+        final long start;
+        final long allocatedBytesBefore;
+        if (printAfterCompilation || printCompilation) {
+            start = System.currentTimeMillis();
+            allocatedBytesBefore = printAfterCompilation || printCompilation ? threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
+        } else {
+            start = 0L;
+            allocatedBytesBefore = 0L;
+        }
+
+        final long startTime = System.currentTimeMillis();
+        CompilationResult compResult = aotBackend.compileMethod(method);
+        final long endTime = System.currentTimeMillis();
+
+        if (printAfterCompilation || printCompilation) {
+            final long stop = System.currentTimeMillis();
+            final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1;
+            final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId);
+            final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
+
+            if (printAfterCompilation) {
+                TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
+            } else if (printCompilation) {
+                TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dkB", getId(), "", "", "", stop - start, targetCodeSize, allocatedBytes));
+            }
+        }
+
+        if (compResult == null) {
+            result = null;
+            return;
+        }
+
+        // For now precision to the nearest second is sufficient.
+        Main.writeLog("    Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
+        if (main.options.debug) {
+            aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
+        }
+
+        result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method));
+    }
+
+    private String getMethodDescription() {
+        return String.format("%-6d JVMCI %-70s %-45s %-50s %s", getId(), method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
+                        getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
+    }
+
+    private int getId() {
+        return id;
+    }
+
+    public int getEntryBCI() {
+        return JVMCICompiler.INVOCATION_ENTRY_BCI;
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    /**
+     * Returns the holder of this method as a {@link AOTCompiledClass}.
+     *
+     * @return the holder of this method
+     */
+    public AOTCompiledClass getHolder() {
+        return holder;
+    }
+
+    /**
+     * Returns the result of this compilation task.
+     *
+     * @return result of this compilation task
+     */
+    public CompiledMethodInfo getResult() {
+        return result;
+    }
+
+    @Override
+    public int compareTo(Object obj) {
+        AOTCompilationTask other = (AOTCompilationTask) obj;
+        return this.id - other.id;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AOTCompilationTask other = (AOTCompilationTask) obj;
+        return (this.id == other.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 + id;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
new file mode 100644
index 0000000..cbf2629
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods
+ * of a class {@code className} are maintained in an array list.
+ */
+public class AOTCompiledClass {
+
+    public static class AOTKlassData {
+        int gotIndex; // Index (offset/8) to the got in the .metaspace.got section
+        int classId;  // Unique ID
+        // Offset to compiled methods data in the .methods.offsets section.
+        int compiledMethodsOffset;
+        // Offset to dependent methods data.
+        int dependentMethodsOffset;
+        long fingerprint;           // Class fingerprint
+
+        private final String name;
+        private boolean isArray;
+
+        /**
+         * List of dependent compiled methods which have a reference to this class.
+         */
+        private ArrayList<CompiledMethodInfo> dependentMethods;
+
+        public AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) {
+            this.dependentMethods = new ArrayList<>();
+            this.classId = classId;
+            this.fingerprint = fingerprint;
+            this.gotIndex = binaryContainer.addTwoSlotMetaspaceSymbol(name);
+            this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods.
+            this.dependentMethodsOffset = -1;
+            this.name = name;
+            this.isArray = name.length() > 0 && name.charAt(0) == '[';
+        }
+
+        public long getFingerprint() {
+            return fingerprint;
+        }
+
+        /**
+         * Add a method to the list of dependent methods.
+         */
+        public synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
+            return dependentMethods.add(cm);
+        }
+
+        /**
+         * Return the array list of dependent class methods.
+         *
+         * @return array list of dependent methods
+         */
+        public ArrayList<CompiledMethodInfo> getDependentMethods() {
+            return dependentMethods;
+        }
+
+        /**
+         * Returns if this class has dependent methods.
+         *
+         * @return true if dependent methods exist, false otherwise
+         */
+        public boolean hasDependentMethods() {
+            return !dependentMethods.isEmpty();
+        }
+
+        public void setCompiledMethodsOffset(int offset) {
+            compiledMethodsOffset = offset;
+        }
+
+        protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
+            int cntDepMethods = dependentMethods.size();
+            // Create array of dependent methods IDs. First word is count.
+            ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer();
+            this.dependentMethodsOffset = binaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
+            for (CompiledMethodInfo methodInfo : dependentMethods) {
+                dependenciesContainer.appendInt(methodInfo.getCodeId());
+            }
+            verify();
+
+            // @formatter:off
+            /*
+             * The offsets layout should match AOTKlassData structure in AOT JVM runtime
+             */
+            int offset = container.getByteStreamSize();
+            container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name);
+                      // Add index (offset/8) to the got in the .metaspace.got section
+            container.appendInt(gotIndex).
+                      // Add unique ID
+                      appendInt(classId).
+                      // Add the offset to compiled methods data in the .metaspace.offsets section.
+                      appendInt(compiledMethodsOffset).
+                      // Add the offset to dependent methods data in the .metaspace.offsets section.
+                      appendInt(dependentMethodsOffset).
+                      // Add fingerprint.
+                      appendLong(fingerprint);
+            // @formatter:on
+        }
+
+        private void verify() {
+            assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name;
+            assert isArray || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name;
+            assert compiledMethodsOffset >= -1 : "incorrect compiledMethodsOffset: " + compiledMethodsOffset + " for klass: " + name;
+            assert dependentMethodsOffset >= -1 : "incorrect dependentMethodsOffset: " + dependentMethodsOffset + " for klass: " + name;
+            assert classId >= 0 : "incorrect classId: " + classId + " for klass: " + name;
+        }
+
+    }
+
+    private final HotSpotResolvedObjectType resolvedJavaType;
+
+    /**
+     * List of all collected class data.
+     */
+    private static Map<String, AOTKlassData> klassData = new HashMap<>();
+
+    /**
+     * List of all methods to be compiled.
+     */
+    private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>();
+
+    /**
+     * List of all compiled class methods.
+     */
+    private ArrayList<CompiledMethodInfo> compiledMethods;
+
+    /**
+     * If this class represents Graal stub code.
+     */
+    private final boolean representsStubs;
+
+    /**
+     * Classes count used to generate unique global method id.
+     */
+    private static int classesCount = 0;
+
+    /**
+     * Construct an object with compiled methods. Intended to be used for code with no corresponding
+     * Java method name in the user application.
+     *
+     * @param compiledMethods AOT compiled methods
+     */
+    public AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
+        this.resolvedJavaType = null;
+        this.compiledMethods = compiledMethods;
+        this.representsStubs = true;
+    }
+
+    /**
+     * Construct an object with compiled versions of the named class.
+     */
+    public AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
+        this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType;
+        this.compiledMethods = new ArrayList<>();
+        this.representsStubs = false;
+    }
+
+    /**
+     * @return the ResolvedJavaType of this class
+     */
+    public ResolvedJavaType getResolvedJavaType() {
+        return resolvedJavaType;
+    }
+
+    /**
+     * Get the list of methods which should be compiled.
+     */
+    public ArrayList<ResolvedJavaMethod> getMethods() {
+        ArrayList<ResolvedJavaMethod> m = methods;
+        methods = null; // Free - it is not used after that.
+        return m;
+    }
+
+    /**
+     * Get the number of all AOT classes.
+     */
+    public static int getClassesCount() {
+        return classesCount;
+    }
+
+    /**
+     * Get the number of methods which should be compiled.
+     *
+     * @return number of methods which should be compiled
+     */
+    public int getMethodCount() {
+        return methods.size();
+    }
+
+    /**
+     * Add a method to the list of methods to be compiled.
+     */
+    public void addMethod(ResolvedJavaMethod method) {
+        methods.add(method);
+    }
+
+    /**
+     * Returns if this class has methods which should be compiled.
+     *
+     * @return true if this class contains methods which should be compiled, false otherwise
+     */
+    public boolean hasMethods() {
+        return !methods.isEmpty();
+    }
+
+    /**
+     * Add a method to the list of compiled methods. This method needs to be thread-safe.
+     */
+    public synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
+        return compiledMethods.add(cm);
+    }
+
+    /**
+     * Return the array list of compiled class methods.
+     *
+     * @return array list of compiled methods
+     */
+    public ArrayList<CompiledMethodInfo> getCompiledMethods() {
+        return compiledMethods;
+    }
+
+    /**
+     * Returns if this class has successfully compiled methods.
+     *
+     * @return true if methods were compiled, false otherwise
+     */
+    public boolean hasCompiledMethods() {
+        return !compiledMethods.isEmpty();
+    }
+
+    /**
+     * Add a klass data.
+     */
+    public synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+        String name = type.getName();
+        long fingerprint = type.getFingerprint();
+        AOTKlassData data = klassData.get(name);
+        if (data != null) {
+            assert data.getFingerprint() == fingerprint : "incorrect fingerprint data for klass: " + name;
+        } else {
+            data = new AOTKlassData(binaryContainer, name, fingerprint, classesCount++);
+            klassData.put(name, data);
+        }
+        return data;
+    }
+
+    public synchronized static AOTKlassData getAOTKlassData(String name) {
+        return klassData.get(name);
+    }
+
+    public synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
+        return getAOTKlassData(type.getName());
+    }
+
+    public void addAOTKlassData(BinaryContainer binaryContainer) {
+        for (CompiledMethodInfo methodInfo : compiledMethods) {
+            // Record methods holder
+            methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
+            // Record inlinee classes
+            for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) {
+                methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+            }
+            // Record classes of fields that were accessed
+            for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) {
+                methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+            }
+        }
+    }
+
+    public synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+        if (type.isArray()) {
+            return addAOTKlassData(binaryContainer, type);
+        }
+        assert type.getFingerprint() != 0 : "no fingerprint for " + type.getName();
+        AOTKlassData old = getAOTKlassData(type);
+        if (old != null) {
+            boolean assertsEnabled = false;
+            assert assertsEnabled = true;
+            if (assertsEnabled) {
+                HotSpotResolvedObjectType s = type.getSuperclass();
+                if (s != null) {
+                    assert getAOTKlassData(s) != null : "fingerprint super " + s.getName() + " needed for " + type.getName();
+                }
+                for (HotSpotResolvedObjectType i : type.getInterfaces()) {
+                    assert getAOTKlassData(i) != null : "fingerprint super " + i.getName() + " needed for " + type.getName();
+                }
+            }
+            return old;
+        }
+
+        // Fingerprinting requires super classes and super interfaces
+        HotSpotResolvedObjectType s = type.getSuperclass();
+        if (s != null) {
+            addFingerprintKlassData(binaryContainer, s);
+        }
+        for (HotSpotResolvedObjectType i : type.getInterfaces()) {
+            addFingerprintKlassData(binaryContainer, i);
+        }
+
+        return addAOTKlassData(binaryContainer, type);
+    }
+
+    /*
+     * Put methods data to contained.
+     */
+    public void putMethodsData(BinaryContainer binaryContainer) {
+        ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer();
+        int cntMethods = compiledMethods.size();
+        int startMethods = binaryContainer.addMethodsCount(cntMethods, container);
+        for (CompiledMethodInfo methodInfo : compiledMethods) {
+            methodInfo.addMethodOffsets(binaryContainer, container);
+        }
+        String name = resolvedJavaType.getName();
+        AOTKlassData data = klassData.get(name);
+        assert data != null : "missing data for klass: " + name;
+        assert data.getFingerprint() == resolvedJavaType.getFingerprint() : "incorrect fingerprint for klass: " + name;
+        int cntDepMethods = data.dependentMethods.size();
+        assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name;
+        data.setCompiledMethodsOffset(startMethods);
+    }
+
+    public static void putAOTKlassData(BinaryContainer binaryContainer) {
+        ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer();
+        for (AOTKlassData data : klassData.values()) {
+            data.putAOTKlassData(binaryContainer, container);
+        }
+    }
+
+    public boolean representsStubs() {
+        return representsStubs;
+    }
+
+    public void clear() {
+        for (CompiledMethodInfo c : compiledMethods) {
+            c.clear();
+        }
+        this.compiledMethods = null;
+        this.methods = null;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java
new file mode 100644
index 0000000..12a72c4
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class AOTCompiler {
+
+    private final Main main;
+
+    private CompileQueue compileQueue;
+
+    private final AOTBackend backend;
+
+    /**
+     * Compile queue.
+     */
+    private class CompileQueue extends ThreadPoolExecutor {
+
+        /**
+         * Time of the start of this queue.
+         */
+        private final long startTime;
+
+        /**
+         * Method counter for successful compilations.
+         */
+        private final AtomicInteger successfulMethodCount = new AtomicInteger();
+
+        /**
+         * Method counter for failed compilations.
+         */
+        private final AtomicInteger failedMethodCount = new AtomicInteger();
+
+        /**
+         * Create a compile queue with the given number of threads.
+         */
+        public CompileQueue(final int threads) {
+            super(threads, threads, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>());
+            startTime = System.currentTimeMillis();
+        }
+
+        @Override
+        protected void afterExecute(Runnable r, Throwable t) {
+            AOTCompilationTask task = (AOTCompilationTask) r;
+            if (task.getResult() != null) {
+                final int count = successfulMethodCount.incrementAndGet();
+                if (count % 100 == 0) {
+                    main.printInfo(".");
+                }
+                CompiledMethodInfo result = task.getResult();
+                if (result != null) {
+                    task.getHolder().addCompiledMethod(result);
+                }
+            } else {
+                failedMethodCount.incrementAndGet();
+                main.printlnVerbose("");
+                ResolvedJavaMethod method = task.getMethod();
+                main.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor());
+            }
+        }
+
+        @Override
+        protected void terminated() {
+            final long endTime = System.currentTimeMillis();
+            final int success = successfulMethodCount.get();
+            final int failed = failedMethodCount.get();
+            main.printlnInfo("");
+            main.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)");
+        }
+
+    }
+
+    /**
+     * @param main
+     * @param aotBackend
+     * @param threads number of compilation threads
+     */
+    public AOTCompiler(Main main, AOTBackend aotBackend, final int threads) {
+        this.main = main;
+        this.compileQueue = new CompileQueue(threads);
+        this.backend = aotBackend;
+    }
+
+    /**
+     * Compile all methods in all classes passed.
+     *
+     * @param classes a list of class to compile
+     * @throws InterruptedException
+     */
+    public List<AOTCompiledClass> compileClasses(List<AOTCompiledClass> classes) throws InterruptedException {
+        main.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads");
+        main.printInfo("."); // Compilation progress indication.
+
+        for (AOTCompiledClass c : classes) {
+            for (ResolvedJavaMethod m : c.getMethods()) {
+                enqueueMethod(c, m);
+            }
+        }
+
+        // Shutdown queue and wait for all tasks to complete.
+        compileQueue.shutdown();
+        compileQueue.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+
+        List<AOTCompiledClass> compiledClasses = new ArrayList<>();
+        for (AOTCompiledClass compiledClass : classes) {
+            if (compiledClass.hasCompiledMethods()) {
+                compiledClasses.add(compiledClass);
+            }
+        }
+        return compiledClasses;
+    }
+
+    /**
+     * Enqueue a method in the {@link #compileQueue}.
+     *
+     * @param method method to be enqueued
+     */
+    private void enqueueMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method) {
+        AOTCompilationTask task = new AOTCompilationTask(main, aotClass, method, backend);
+        try {
+            compileQueue.execute(task);
+        } catch (RejectedExecutionException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void logCompilation(String methodName, String message) {
+        Main.writeLog(message + " " + methodName);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java
new file mode 100644
index 0000000..865ef46
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
+
+    private final HotSpotResolvedJavaMethod method;
+
+    public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method) {
+        this.method = method;
+    }
+
+    public String getSymbolName() {
+        return MiscUtils.uniqueMethodName(method);
+    }
+
+    public String getNameAndSignature() {
+        String className = method.getDeclaringClass().getName();
+        return className + "." + method.getName() + method.getSignature().toMethodDescriptor();
+    }
+
+    public HotSpotCompiledCode compiledCode(CompilationResult result) {
+        return HotSpotCompiledCodeBuilder.createCompiledCode(method, null, result);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java
new file mode 100644
index 0000000..b7ba5e8
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+
+public class AOTStub implements JavaMethodInfo {
+
+    private final Stub stub;
+    private final Backend backend;
+
+    public AOTStub(Stub stub, Backend backend) {
+        this.stub = stub;
+        this.backend = backend;
+    }
+
+    public String getSymbolName() {
+        return stub.toString();
+    }
+
+    public String getNameAndSignature() {
+        return stub.toString();
+    }
+
+    public HotSpotCompiledCode compiledCode(CompilationResult result) {
+        return stub.getCompiledCode(backend);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java
new file mode 100644
index 0000000..72d9e53
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+
+/**
+ * Describes a call site relocation. Contains a name of the callee and a relocation type, describing
+ * which relocation to use at the call site.
+ */
+abstract class CallSiteRelocationInfo {
+
+    public final String targetSymbol;
+    public final RelocType type;
+
+    public CallSiteRelocationInfo(String targetSymbol, RelocType type) {
+        this.targetSymbol = targetSymbol;
+        this.type = type;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java
new file mode 100644
index 0000000..68f86ef
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+/**
+ * Describes a relocation symbol of a call site. That is, WHERE to do a relocation.
+ */
+abstract class CallSiteRelocationSymbol {
+
+    public final Symbol symbol;
+
+    public CallSiteRelocationSymbol(Symbol symbol) {
+        assert symbol != null;
+        this.symbol = symbol;
+    }
+
+    protected static Symbol createCodeContainerSymbol(BinaryContainer binaryContainer, String symbolName, int symbolOffset) {
+        return binaryContainer.getCodeContainer().createSymbol(symbolOffset, Kind.OBJECT, Binding.LOCAL, 0, symbolName);
+    }
+
+    protected static void addCodeContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) {
+        Symbol symbol = createCodeContainerSymbol(binaryContainer, symbolName, symbolOffset);
+        addExternalGotToPltRelocation(binaryContainer, symbol, relocationOffset);
+    }
+
+    protected static void addExtLinkageGotContainerRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) {
+        ByteContainer container = binaryContainer.getExtLinkageGOTContainer();
+        Symbol symbol = container.createGotSymbol(symbolOffset, symbolName);
+        addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset);
+    }
+
+    protected static void addMetaspaceGotRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) {
+        ByteContainer container = binaryContainer.getMetaspaceGotContainer();
+        Symbol symbol = container.createGotSymbol(symbolOffset, symbolName);
+        addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset);
+    }
+
+    /**
+     * Add an {@link RelocType#EXTERNAL_GOT_TO_PLT} relocation to the
+     * {@link BinaryContainer#getExtLinkageGOTContainer()}.
+     */
+    private static void addExternalGotToPltRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) {
+        ByteContainer container = binaryContainer.getExtLinkageGOTContainer();
+        Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_GOT_TO_PLT, 8, container, symbol);
+        binaryContainer.addRelocation(relocation);
+    }
+
+    /**
+     * Add an {@link RelocType#EXTERNAL_PLT_TO_GOT} relocation to the
+     * {@link BinaryContainer#getCodeContainer()}.
+     */
+    protected static void addExternalPltToGotRelocation(BinaryContainer binaryContainer, Symbol symbol, int relocationOffset) {
+        CodeContainer container = binaryContainer.getCodeContainer();
+        Relocation relocation = new Relocation(relocationOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, container, symbol);
+        binaryContainer.addRelocation(relocation);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java
new file mode 100644
index 0000000..35e54ca
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.List;
+
+import jdk.vm.ci.code.site.Mark;
+
+public final class CodeOffsets {
+    private final int entry;
+    private final int verifiedEntry;
+    private final int exceptionHandler;
+    private final int deoptHandler;
+
+    private CodeOffsets(int entry, int verifiedEntry, int exceptionHandler, int deoptHandler) {
+        this.entry = entry;
+        this.verifiedEntry = verifiedEntry;
+        this.exceptionHandler = exceptionHandler;
+        this.deoptHandler = deoptHandler;
+    }
+
+    public static CodeOffsets buildFrom(List<Mark> marks) {
+        int entry = 0;
+        int verifiedEntry = 0;
+        int exceptionHandler = -1;
+        int deoptHandler = -1;
+
+        for (Mark mark : marks) {
+            if (mark.id instanceof Integer) {
+                MarkId markId = MarkId.getEnum((int) mark.id);
+                switch (markId) {
+                    case UNVERIFIED_ENTRY:
+                        entry = mark.pcOffset;
+                        break;
+                    case VERIFIED_ENTRY:
+                        verifiedEntry = mark.pcOffset;
+                        break;
+                    case OSR_ENTRY:
+                        // Unhandled
+                        break;
+                    case EXCEPTION_HANDLER_ENTRY:
+                        exceptionHandler = mark.pcOffset;
+                        break;
+                    case DEOPT_HANDLER_ENTRY:
+                        deoptHandler = mark.pcOffset;
+                        break;
+                    default:
+                        break; // Ignore others
+                }
+            }
+        }
+        return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler);
+    }
+
+    public int entry() {
+        return entry;
+    }
+
+    public int verifiedEntry() {
+        return verifiedEntry;
+    }
+
+    public int exceptionHandler() {
+        return exceptionHandler;
+    }
+
+    public int deoptHandler() {
+        return deoptHandler;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java
new file mode 100644
index 0000000..d106458
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.CodeContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+class CodeSectionProcessor {
+
+    private final TargetDescription target;
+
+    private final BinaryContainer binaryContainer;
+
+    CodeSectionProcessor(DataBuilder dataBuilder) {
+        this.target = dataBuilder.getBackend().getTarget();
+        this.binaryContainer = dataBuilder.getBinaryContainer();
+    }
+
+    /**
+     * Method that looks at code section of a compiled result {@code compClass} and records function
+     * entry point symbols along with the text section contents. Note that the text section contents
+     * are not yet ready to be written in the form of a binary text section since the contents may
+     * need to be patched with references to other sections.
+     *
+     * @param compClass Graal compilation result.
+     */
+    void process(AOTCompiledClass compClass) {
+        ArrayList<CompiledMethodInfo> compiledMethods = compClass.getCompiledMethods();
+
+        for (CompiledMethodInfo methodInfo : compiledMethods) {
+            CompilationResult compResult = methodInfo.getCompilationResult();
+
+            byte[] targetCode = compResult.getTargetCode();
+            int targetCodeSize = compResult.getTargetCodeSize();
+            JavaMethodInfo compMethod = methodInfo.getMethodInfo();
+
+            // Step through all foreign calls, for every call, clear destination.
+            // Otherwise libelf may not patch them correctly.
+            for (Infopoint infopoint : compResult.getInfopoints()) {
+                if (infopoint.reason == InfopointReason.CALL) {
+                    final Call callInfopoint = (Call) infopoint;
+                    if (callInfopoint.target instanceof HotSpotForeignCallLinkage) {
+                        // TODO 4 is x86 size of relative displacement.
+                        // For SPARC need something different.
+                        int destOffset = infopoint.pcOffset + callInfopoint.size - 4;
+                        targetCode[destOffset + 0] = 0;
+                        targetCode[destOffset + 1] = 0;
+                        targetCode[destOffset + 2] = 0;
+                        targetCode[destOffset + 3] = 0;
+                    }
+                }
+            }
+
+            String entry = compMethod.getSymbolName();
+            assert entry != null : "missing name for compiled method";
+
+            // Align and pad method entry
+            CodeContainer codeSection = binaryContainer.getCodeContainer();
+            int codeIdOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize());
+            // Store CodeId into code. It will be use by find_aot() using code.segments
+            methodInfo.setCodeId();
+            binaryContainer.appendIntToCode(methodInfo.getCodeId());
+            int textBaseOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment());
+
+            codeSection.createSymbol(textBaseOffset, Symbol.Kind.JAVA_FUNCTION, Symbol.Binding.LOCAL, targetCodeSize, entry);
+
+            // Set the offset at which the text section of this method would be layed out
+            methodInfo.setTextSectionOffset(textBaseOffset);
+
+            // Write code bytes of the current method into byte stream
+            binaryContainer.appendCodeBytes(targetCode, 0, targetCodeSize);
+            int currentStubOffset = binaryContainer.alignUp(codeSection, 8);
+            // Set the offset at which stubs of this method would be laid out
+            methodInfo.setStubsOffset(currentStubOffset - textBaseOffset);
+            // step through all calls, for every call, add a stub
+            for (Infopoint infopoint : compResult.getInfopoints()) {
+                if (infopoint.reason == InfopointReason.CALL) {
+                    final Call callInfopoint = (Call) infopoint;
+                    if (callInfopoint.target instanceof ResolvedJavaMethod) {
+                        ResolvedJavaMethod call = (ResolvedJavaMethod) callInfopoint.target;
+                        StubInformation stub = addCallStub(MiscUtils.isVirtualCall(methodInfo, callInfopoint));
+                        // Get the targetSymbol. A symbol for this will be created later during plt
+                        // creation
+                        String targetSymbol = MiscUtils.uniqueMethodName(call) + ".at." + infopoint.pcOffset;
+                        methodInfo.addStubCode(targetSymbol, stub);
+                        currentStubOffset += stub.getSize();
+                    }
+                }
+            }
+            assert currentStubOffset == codeSection.getByteStreamSize() : "wrong offset";
+            binaryContainer.addCodeSegments(codeIdOffset, currentStubOffset);
+        }
+    }
+
+    private StubInformation addCallStub(boolean isVirtualCall) {
+        final int startOffset = binaryContainer.getCodeContainer().getByteStreamSize();
+        StubInformation stub = new StubInformation(startOffset, isVirtualCall);
+        ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(target);
+        byte[] code;
+        if (isVirtualCall) {
+            code = masm.getPLTVirtualEntryCode(stub);
+        } else {
+            code = masm.getPLTStaticEntryCode(stub);
+        }
+        binaryContainer.appendCodeBytes(code, 0, code.length);
+        return stub;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java
new file mode 100644
index 0000000..b42199d
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A class encapsulating any user-specified compilation restrictions.
+ */
+public class CompilationSpec {
+
+    /**
+     * Set of method names to restrict compilation to.
+     */
+    private HashSet<String> compileOnlyStrings = new HashSet<>();
+    private HashSet<Pattern> compileOnlyPatterns = new HashSet<>();
+
+    /**
+     * Set of method names that should be excluded from compilation.
+     */
+    private HashSet<String> excludeStrings = new HashSet<>();
+    private HashSet<Pattern> excludePatterns = new HashSet<>();
+
+    /**
+     * Add a {@code compileOnly} directive to the compile-only list.
+     *
+     * @param pattern regex or non-regex pattern string
+     */
+    public void addCompileOnlyPattern(String pattern) {
+        if (pattern.contains("*")) {
+            compileOnlyPatterns.add(Pattern.compile(pattern));
+        } else {
+            compileOnlyStrings.add(pattern);
+        }
+    }
+
+    /**
+     * Add an {@code exclude} directive to the exclude list.
+     *
+     * @param pattern regex or non-regex pattern string
+     */
+    public void addExcludePattern(String pattern) {
+        if (pattern.contains("*")) {
+            excludePatterns.add(Pattern.compile(pattern));
+        } else {
+            excludeStrings.add(pattern);
+        }
+    }
+
+    /**
+     * Check if a given method is part of a restrictive compilation.
+     *
+     * @param method method to be checked
+     * @return true or false
+     */
+    public boolean shouldCompileMethod(ResolvedJavaMethod method) {
+        if (compileWithRestrictions()) {
+            // If there are user-specified compileOnly patterns, default action
+            // is not to compile the method.
+            boolean compileMethod = compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty();
+
+            // Check if the method matches with any of the specified compileOnly patterns.
+            String methodName = MiscUtils.uniqueMethodName(method);
+
+            // compileOnly
+            if (!compileMethod) {
+                compileMethod = compileOnlyStrings.contains(methodName);
+            }
+            if (!compileMethod) {
+                Iterator<Pattern> it = compileOnlyPatterns.iterator();
+                while (!compileMethod && it.hasNext()) {
+                    Pattern pattern = it.next();
+                    compileMethod = pattern.matcher(methodName).matches();
+                }
+            }
+
+            // exclude
+            if (compileMethod) {
+                compileMethod = !excludeStrings.contains(methodName);
+            }
+            if (compileMethod) {
+                Iterator<Pattern> it = excludePatterns.iterator();
+                while (compileMethod && it.hasNext()) {
+                    Pattern pattern = it.next();
+                    compileMethod = !(pattern.matcher(methodName).matches());
+                }
+            }
+            return compileMethod;
+        }
+        return true;
+    }
+
+    /**
+     * Return true if compilation restrictions are specified.
+     */
+    private boolean compileWithRestrictions() {
+        return !(compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty() && excludeStrings.isEmpty() && excludePatterns.isEmpty());
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java
new file mode 100644
index 0000000..2ccafbf
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
+import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
+import org.graalvm.compiler.code.CompilationResult;
+
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.code.site.Site;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+
+public class CompiledMethodInfo {
+
+    public static class StubInformation {
+        int stubOffset;         // the offset inside the code (text + stubOffset)
+        int stubSize;           // the stub size
+        int dispatchJumpOffset; // offset after main dispatch jump instruction
+        int resolveJumpOffset;  // offset after jump instruction to runtime call resolution
+                               // function.
+        int resolveJumpStart;   // offset of jump instruction to VM runtime call resolution
+                              // function.
+        int c2iJumpOffset;      // offset after jump instruction to c2i adapter for static calls.
+        int movOffset; // offset after move instruction which loads from got cell:
+                       // - Method* for static call
+                       // - Klass* for virtual call
+
+        boolean isVirtual;  // virtual call stub
+
+        // maybe add type of stub as well, right now we only have static stubs
+
+        public StubInformation(int stubOffset, boolean isVirtual) {
+            this.stubOffset = stubOffset;
+            this.isVirtual = isVirtual;
+            this.stubSize = -1;
+            this.movOffset = -1;
+            this.c2iJumpOffset = -1;
+            this.resolveJumpOffset = -1;
+            this.resolveJumpStart = -1;
+            this.dispatchJumpOffset = -1;
+        }
+
+        public int getOffset() {
+            return stubOffset;
+        }
+
+        public boolean isVirtual() {
+            return isVirtual;
+        }
+
+        public void setSize(int stubSize) {
+            this.stubSize = stubSize;
+        }
+
+        public int getSize() {
+            return stubSize;
+        }
+
+        public void setMovOffset(int movOffset) {
+            this.movOffset = movOffset + stubOffset;
+        }
+
+        public int getMovOffset() {
+            return movOffset;
+        }
+
+        public void setC2IJumpOffset(int c2iJumpOffset) {
+            this.c2iJumpOffset = c2iJumpOffset + stubOffset;
+        }
+
+        public int getC2IJumpOffset() {
+            return c2iJumpOffset;
+        }
+
+        public void setResolveJumpOffset(int resolveJumpOffset) {
+            this.resolveJumpOffset = resolveJumpOffset + stubOffset;
+        }
+
+        public int getResolveJumpOffset() {
+            return resolveJumpOffset;
+        }
+
+        public void setResolveJumpStart(int resolveJumpStart) {
+            this.resolveJumpStart = resolveJumpStart + stubOffset;
+        }
+
+        public int getResolveJumpStart() {
+            return resolveJumpStart;
+        }
+
+        public void setDispatchJumpOffset(int dispatchJumpOffset) {
+            this.dispatchJumpOffset = dispatchJumpOffset + stubOffset;
+        }
+
+        public int getDispatchJumpOffset() {
+            return dispatchJumpOffset;
+        }
+
+        public void verify() {
+            assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset;
+            assert stubSize > 0 : "incorrect stubSize: " + stubSize;
+            assert movOffset > 0 : "incorrect movOffset: " + movOffset;
+            assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset;
+            assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart;
+            assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset;
+            if (!isVirtual) {
+                assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset;
+            }
+        }
+    }
+
+    private static final int UNINITIALIZED_OFFSET = -1;
+
+    private static class AOTMethodOffsets {
+        /**
+         * Offset in metaspace names section.
+         */
+        private int nameOffset;
+
+        /**
+         * Offset in the text section at which compiled code starts.
+         */
+        private int textSectionOffset;
+
+        /**
+         * Offset in the metadata section.
+         */
+        private int metadataOffset;
+
+        /**
+         * Offset to the metadata in the GOT table.
+         */
+        private int metadataGotOffset;
+
+        /**
+         * Size of the metadata.
+         */
+        private int metadataGotSize;
+
+        /**
+         * The sequential number corresponding to the order of methods code in code buffer.
+         */
+        private int codeId;
+
+        public AOTMethodOffsets() {
+            this.nameOffset = UNINITIALIZED_OFFSET;
+            this.textSectionOffset = UNINITIALIZED_OFFSET;
+            this.metadataOffset = UNINITIALIZED_OFFSET;
+            this.metadataGotOffset = UNINITIALIZED_OFFSET;
+            this.metadataGotSize = -1;
+            this.codeId = -1;
+        }
+
+        protected void addMethodOffsets(ReadOnlyDataContainer container, String name) {
+            verify(name);
+            // @formatter:off
+            /*
+             * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime
+             */
+                      // Add the offset to the name in the .metaspace.names section
+            container.appendInt(nameOffset).
+                      // Add the offset to the code in the .text section
+                      appendInt(textSectionOffset).
+                      // Add the offset to the metadata in the .method.metadata section
+                      appendInt(metadataOffset).
+                      // Add the offset to the metadata in the .metadata.got section
+                      appendInt(metadataGotOffset).
+                      // Add the size of the metadata
+                      appendInt(metadataGotSize).
+                      // Add code ID.
+                      appendInt(codeId);
+            // @formatter:on
+        }
+
+        private void verify(String name) {
+            assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name;
+            assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name;
+            assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name;
+            assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name;
+            assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name;
+            assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name;
+        }
+
+        protected void setNameOffset(int offset) {
+            nameOffset = offset;
+        }
+
+        protected void setTextSectionOffset(int textSectionOffset) {
+            this.textSectionOffset = textSectionOffset;
+        }
+
+        protected int getTextSectionOffset() {
+            return textSectionOffset;
+        }
+
+        protected void setCodeId(int codeId) {
+            this.codeId = codeId;
+        }
+
+        protected int getCodeId() {
+            return codeId;
+        }
+
+        protected void setMetadataOffset(int offset) {
+            metadataOffset = offset;
+        }
+
+        protected void setMetadataGotOffset(int metadataGotOffset) {
+            this.metadataGotOffset = metadataGotOffset;
+        }
+
+        protected void setMetadataGotSize(int length) {
+            this.metadataGotSize = length;
+        }
+    }
+
+    /**
+     * Method name
+     */
+    private String name;
+
+    /**
+     * Result of graal compilation.
+     */
+    private CompilationResult compilationResult;
+
+    /**
+     * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result.
+     */
+    private JavaMethodInfo methodInfo;
+
+    /**
+     * Compiled code from installation.
+     */
+    private HotSpotCompiledCode code;
+
+    /**
+     * Offset to stubs.
+     */
+    private int stubsOffset;
+
+    /**
+     * The total size in bytes of the stub section.
+     */
+    private int totalStubSize;
+
+    /**
+     * Method's offsets.
+     */
+    private AOTMethodOffsets methodOffsets;
+
+    /**
+     * List of stubs (PLT trampoline).
+     */
+    private Map<String, StubInformation> stubs = new HashMap<>();
+
+    /**
+     * List of referenced classes.
+     */
+    private Map<String, AOTKlassData> dependentKlasses = new HashMap<>();
+
+    /**
+     * Methods count used to generate unique global method id.
+     */
+    private static final AtomicInteger methodsCount = new AtomicInteger();
+
+    public CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) {
+        this.name = methodInfo.getNameAndSignature();
+        this.compilationResult = compilationResult;
+        this.methodInfo = methodInfo;
+        this.stubsOffset = UNINITIALIZED_OFFSET;
+        this.methodOffsets = new AOTMethodOffsets();
+    }
+
+    public String name() {
+        return name;
+    }
+
+    public void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
+        this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name));
+        this.methodOffsets.addMethodOffsets(container, name);
+        for (AOTKlassData data : dependentKlasses.values()) {
+            data.addDependentMethod(this);
+        }
+    }
+
+    public CompilationResult getCompilationResult() {
+        return compilationResult;
+    }
+
+    public JavaMethodInfo getMethodInfo() {
+        return methodInfo;
+    }
+
+    public void setTextSectionOffset(int textSectionOffset) {
+        methodOffsets.setTextSectionOffset(textSectionOffset);
+    }
+
+    public int getTextSectionOffset() {
+        return methodOffsets.getTextSectionOffset();
+    }
+
+    public void setCodeId() {
+        methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId());
+    }
+
+    public int getCodeId() {
+        return this.methodOffsets.getCodeId();
+    }
+
+    public static int getMethodsCount() {
+        return methodsCount.get();
+    }
+
+    public static int getNextCodeId() {
+        return methodsCount.getAndIncrement();
+    }
+
+    public int getCodeSize() {
+        return stubsOffset + getStubCodeSize();
+    }
+
+    public int getStubCodeSize() {
+        return totalStubSize;
+    }
+
+    public void setMetadataOffset(int offset) {
+        this.methodOffsets.setMetadataOffset(offset);
+    }
+
+    /**
+     * Offset into the code of this method where the stub section starts.
+     */
+    public void setStubsOffset(int offset) {
+        stubsOffset = offset;
+    }
+
+    public int getStubsOffset() {
+        return stubsOffset;
+    }
+
+    public void setMetadataGotOffset(int metadataGotOffset) {
+        this.methodOffsets.setMetadataGotOffset(metadataGotOffset);
+    }
+
+    public void setMetadataGotSize(int length) {
+        this.methodOffsets.setMetadataGotSize(length);
+    }
+
+    public void addStubCode(String call, StubInformation stub) {
+        stubs.put(call, stub);
+        totalStubSize += stub.getSize();
+    }
+
+    public StubInformation getStubFor(String call) {
+        StubInformation stub = stubs.get(call);
+        assert stub != null : "missing stub for call " + call;
+        stub.verify();
+        return stub;
+    }
+
+    public void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+        AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type);
+        String klassName = type.getName();
+
+        if (dependentKlasses.containsKey(klassName)) {
+            assert dependentKlasses.get(klassName) == klassData : "duplicated data for klass: " + klassName;
+        } else {
+            dependentKlasses.put(klassName, klassData);
+        }
+    }
+
+    public AOTKlassData getDependentKlassData(String klassName) {
+        return dependentKlasses.get(klassName);
+    }
+
+    public boolean hasMark(Site call, MarkId id) {
+        for (Mark m : compilationResult.getMarks()) {
+            // TODO: X64-specific code.
+            // Call instructions are aligned to 8
+            // bytes - 1 on x86 to patch address atomically,
+            int adjOffset = (m.pcOffset & (-8)) + 7;
+            // Mark points before aligning nops.
+            if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String asTag() {
+        return "[" + methodInfo.getSymbolName() + "]";
+    }
+
+    public HotSpotCompiledCode compiledCode() {
+        if (code == null) {
+            code = methodInfo.compiledCode(compilationResult);
+        }
+        return code;
+    }
+
+    // Free memory
+    public void clear() {
+        this.dependentKlasses = null;
+        this.name = null;
+    }
+
+    public void clearCompileData() {
+        this.code = null;
+        this.stubs = null;
+        this.compilationResult = null;
+        this.methodInfo = null;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java
new file mode 100644
index 0000000..350ee46
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.HeaderContainer;
+import jdk.tools.jaotc.utils.Timer;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+import jdk.vm.ci.hotspot.VMField;
+
+class DataBuilder {
+
+    private final Main main;
+
+    private final HotSpotHostBackend backend;
+
+    private final List<AOTCompiledClass> classes;
+
+    /**
+     * Target-independent container in which text symbols and code bytes are created.
+     */
+    private final BinaryContainer binaryContainer;
+
+    private final HashMap<Long, String> vmAddresses = new HashMap<>();
+
+    public DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) {
+        this.main = main;
+        this.backend = backend;
+        this.classes = classes;
+        this.binaryContainer = binaryContainer;
+        fillVMAddresses(HotSpotJVMCIRuntime.runtime().getConfigStore());
+    }
+
+    /**
+     * Returns a value-name map of all {@link VMField} fields.
+     */
+    private void fillVMAddresses(HotSpotVMConfigStore config) {
+        for (VMField vmField : config.getFields().values()) {
+            if (vmField.value != null) {
+                final long address = vmField.value;
+                String value = vmField.name;
+                /*
+                 * Some fields don't contain addresses but integer values. At least don't add zero
+                 * entries to avoid matching null addresses.
+                 */
+                if (address != 0) {
+                    vmAddresses.put(address, value);
+                }
+            }
+        }
+        for (Entry<String, Long> vmAddress : config.getAddresses().entrySet()) {
+            final long address = vmAddress.getValue();
+            String value = vmAddress.getKey();
+            String old = vmAddresses.put(address, value);
+            if (old != null) {
+                throw new InternalError("already in map: address: " + address + ", current: " + value + ", old: " + old);
+            }
+        }
+    }
+
+    /**
+     * Get the C/C++ function name associated with the foreign call target {@code address}.
+     *
+     * @param address native address
+     * @return C/C++ functio name associated with the native address
+     */
+    public String getVMFunctionNameForAddress(long address) {
+        return vmAddresses.get(address);
+    }
+
+    /**
+     * Returns the host backend used for this compilation.
+     *
+     * @return host backend
+     */
+    public HotSpotHostBackend getBackend() {
+        return backend;
+    }
+
+    /**
+     * Returns the binary container for this compilation.
+     *
+     * @return binary container
+     */
+    public BinaryContainer getBinaryContainer() {
+        return binaryContainer;
+    }
+
+    /**
+     * Prepare data with all compiled classes and stubs.
+     *
+     * @throws Exception
+     */
+    @SuppressWarnings("try")
+    public void prepareData() throws Exception {
+        try (Timer t = new Timer(main, "Parsing compiled code")) {
+            /*
+             * Copy compiled code into code section container and calls stubs (PLT trampoline).
+             */
+            CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
+            for (AOTCompiledClass c : classes) {
+                // For each class we need 2 GOT slots:
+                // first - for initialized klass
+                // second - only for loaded klass
+                c.addAOTKlassData(binaryContainer);
+                codeSectionProcessor.process(c);
+            }
+        }
+
+        AOTCompiledClass stubCompiledCode = retrieveStubCode();
+
+        // Free memory!
+        try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
+            main.printMemoryUsage();
+            System.gc();
+        }
+
+        MetadataBuilder metadataBuilder = null;
+        try (Timer t = new Timer(main, "Processing metadata")) {
+            /*
+             * Generate metadata for compiled code and copy it into metadata section. Create
+             * relocation information for all references (call, constants, etc) in compiled code.
+             */
+            metadataBuilder = new MetadataBuilder(this);
+            metadataBuilder.processMetadata(classes, stubCompiledCode);
+        }
+
+        // Free memory!
+        try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
+            main.printMemoryUsage();
+            System.gc();
+        }
+
+        try (Timer t = new Timer(main, "Preparing stubs binary")) {
+            prepareStubsBinary(stubCompiledCode);
+        }
+        try (Timer t = new Timer(main, "Preparing compiled binary")) {
+            // Should be called after Stubs because they can set dependent klasses.
+            prepareCompiledBinary(metadataBuilder);
+        }
+    }
+
+    /**
+     * Get all stubs from Graal and add them to the code section.
+     */
+    @SuppressWarnings("try")
+    private AOTCompiledClass retrieveStubCode() {
+        ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
+        for (Stub stub : Stub.getStubs()) {
+            try (Scope scope = Debug.scope("CompileStubs")) {
+                CompilationResult result = stub.getCompilationResult(backend);
+                CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend));
+                stubs.add(cm);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+        AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs);
+        CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
+        codeSectionProcessor.process(stubCompiledCode);
+        return stubCompiledCode;
+    }
+
+    /**
+     * Prepare metaspace.offsets section.
+     */
+    private void prepareCompiledBinary(MetadataBuilder metadataBuilder) {
+        for (AOTCompiledClass c : classes) {
+            // Create records for compiled AOT methods.
+            c.putMethodsData(binaryContainer);
+        }
+        // Create records for compiled AOT classes.
+        AOTCompiledClass.putAOTKlassData(binaryContainer);
+
+        // Fill in AOTHeader
+        HeaderContainer header = binaryContainer.getHeaderContainer();
+        header.setClassesCount(AOTCompiledClass.getClassesCount());
+        header.setMethodsCount(CompiledMethodInfo.getMethodsCount());
+        // Record size of got sections
+        ByteContainer bc = binaryContainer.getMetaspaceGotContainer();
+        header.setMetaspaceGotSize((bc.getByteStreamSize() / 8));
+        bc = binaryContainer.getMetadataGotContainer();
+        header.setMetadataGotSize((bc.getByteStreamSize() / 8));
+        bc = binaryContainer.getOopGotContainer();
+        header.setOopGotSize((bc.getByteStreamSize() / 8));
+    }
+
+    /**
+     * Prepare stubs.offsets section.
+     */
+    private void prepareStubsBinary(AOTCompiledClass compiledClass) {
+        // For each of the compiled stubs, create records holding information about
+        // them.
+        ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods();
+        int cntStubs = compiledStubs.size();
+        binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
+        for (CompiledMethodInfo methodInfo : compiledStubs) {
+            // Note, stubs have different offsets container.
+            methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer());
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java
new file mode 100644
index 0000000..baf1c7b
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
+import org.graalvm.compiler.code.DataSection;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.code.site.Reference;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
+import jdk.vm.ci.meta.VMConstant;
+
+class DataPatchProcessor {
+
+    private final TargetDescription target;
+
+    private final BinaryContainer binaryContainer;
+
+    DataPatchProcessor(DataBuilder dataBuilder) {
+        this.target = dataBuilder.getBackend().getTarget();
+        this.binaryContainer = dataBuilder.getBinaryContainer();
+    }
+
+    /**
+     * Process a {@link DataPatch} generated by the compiler and create all needed binary section
+     * constructs.
+     */
+    void process(CompiledMethodInfo methodInfo, DataPatch dataPatch) {
+        Reference reference = dataPatch.reference;
+        if (reference instanceof ConstantReference) {
+            processConstantReference(dataPatch, methodInfo);
+        } else if (reference instanceof DataSectionReference) {
+            processDataSectionReference(dataPatch, methodInfo);
+        } else {
+            throw new InternalError("Unknown data patch reference: " + reference);
+        }
+    }
+
+    private void processConstantReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
+        HotSpotConstantLoadAction action = (HotSpotConstantLoadAction) dataPatch.note;
+        ConstantReference constantReference = (ConstantReference) dataPatch.reference;
+        assert action != null : "action should be set";
+
+        VMConstant constant = constantReference.getConstant();
+        String targetSymbol = null;
+        String gotName = null;
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
+            if (metaspaceConstant.asResolvedJavaType() != null) {
+                HotSpotResolvedObjectType type = metaspaceConstant.asResolvedJavaType();
+                targetSymbol = type.getName();
+                gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol;
+                methodInfo.addDependentKlassData(binaryContainer, type);
+            } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) {
+                targetSymbol = "counters." + MiscUtils.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod());
+                gotName = "got." + targetSymbol;
+                binaryContainer.addMetaspaceSymbol(targetSymbol);
+            }
+        } else if (constant instanceof HotSpotObjectConstant) {
+            // String constant.
+            HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) constant;
+            targetSymbol = "ldc." + oopConstant.toValueString();
+            Integer offset = binaryContainer.addOopSymbol(targetSymbol);
+            gotName = "got.ldc." + offset;
+        } else if (constant instanceof HotSpotSentinelConstant) {
+            targetSymbol = "state.M" + methodInfo.getCodeId();
+            gotName = "got." + targetSymbol;
+        }
+
+        assert gotName != null : "Unknown constant type: " + constant;
+
+        InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
+        decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
+        int instructionEndOffset = decoder.currentEndOfInstruction();
+
+        int textBaseOffset = methodInfo.getTextSectionOffset();
+        int relocOffset = textBaseOffset + instructionEndOffset;
+
+        Symbol relocationSymbol = binaryContainer.getSymbol(gotName);
+        assert relocationSymbol != null : "symbol for " + gotName + " missing";
+        Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
+        binaryContainer.addRelocation(reloc);
+    }
+
+    private void processDataSectionReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
+        DataSectionReference dataReference = (DataSectionReference) dataPatch.reference;
+
+        InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
+        decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
+        int instructionEndOffset = decoder.currentEndOfInstruction();
+
+        int textBaseOffset = methodInfo.getTextSectionOffset();
+        int relocOffset = textBaseOffset + instructionEndOffset;
+        int dataOffset = dataReference.getOffset();
+
+        DataSection dataSection = methodInfo.getCompilationResult().getDataSection();
+        DataSection.Data data = dataSection.findData(dataReference);
+        int size = data.getSize();
+        int alignment = data.getAlignment();
+        byte[] value = new byte[size];
+        ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder());
+        DataSection.emit(buffer, data, p -> {
+        });
+        String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset;
+        Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol);
+        if (relocationSymbol == null) {
+            int symSize = Math.max(8, size);
+            int symAlig = Math.max(8, alignment);
+            int offsetInConstantDataSection = binaryContainer.addConstantData(value, symAlig);
+            relocationSymbol = binaryContainer.getConstantDataContainer().createSymbol(offsetInConstantDataSection, Kind.OBJECT, Binding.LOCAL, symSize, targetSymbol);
+        }
+        Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
+        binaryContainer.addRelocation(reloc);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java
new file mode 100644
index 0000000..18ff7af
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.amd64.AMD64ELFMacroAssembler;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.TargetDescription;
+
+public interface ELFMacroAssembler {
+
+    public static ELFMacroAssembler getELFMacroAssembler(TargetDescription target) {
+        Architecture architecture = target.arch;
+        if (architecture instanceof AMD64) {
+            return new AMD64ELFMacroAssembler(target);
+        } else {
+            throw new InternalError("Unsupported architecture " + architecture);
+        }
+    }
+
+    public int currentEndOfInstruction();
+
+    public byte[] getPLTJumpCode();
+
+    public byte[] getPLTStaticEntryCode(StubInformation stub);
+
+    public byte[] getPLTVirtualEntryCode(StubInformation stub);
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java
new file mode 100644
index 0000000..50c5e4f
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+
+import jdk.vm.ci.code.site.Call;
+
+/**
+ * This is a foreign call site. This means either a call to the VM or a call to a Graal stub. If
+ * it's a call directly to the VM, mangle the name. The call should go through regular .plt used by
+ * the system loader, at least for now. If it's a call to a Graal stub, it should always be a direct
+ * call, since the Graal stubs are contained within the .so file.
+ */
+final class ForeignCallSiteRelocationInfo extends CallSiteRelocationInfo {
+
+    ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) {
+        super(getTargetSymbol(call, callTarget, dataBuilder), getRelocType(callTarget));
+    }
+
+    private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) {
+        // If it specifies a foreign call linkage, find the symbol corresponding to the address in
+        // HotSpotVMConfig's fields.
+        final long foreignCallTargetAddress = callTarget.getAddress();
+
+        // Get the C/C++ function name associated with the foreign call target address.
+        String functionName = dataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress);
+        if (functionName != null) {
+            // Use the known global AOT symbol associated with function name, if one exists
+            BinaryContainer binaryContainer = dataBuilder.getBinaryContainer();
+            String aotSymbol = binaryContainer.getAOTSymbolForVMFunctionName(functionName);
+            if (aotSymbol == null) {
+                throw new InternalError("no global symbol found for: " + functionName);
+            }
+            return aotSymbol;
+        }
+
+        // Is it a Graal stub we are calling?
+        if (callTarget.isCompiledStub()) {
+            assert call.direct : "Should always be a direct call to stubs";
+            return callTarget.getSymbol();
+        }
+
+        throw new InternalError("no symbol found for: " + callTarget);
+    }
+
+    private static RelocType getRelocType(HotSpotForeignCallLinkage callTarget) {
+        return callTarget.isCompiledStub() ? RelocType.STUB_CALL_DIRECT : RelocType.FOREIGN_CALL_INDIRECT_GOT;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java
new file mode 100644
index 0000000..e1fdbe1
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+
+/**
+ * Native function call, symbol is to a VM method.
+ */
+final class ForeignCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+    public ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+        super(binaryContainer.createSymbol(0, Kind.NATIVE_FUNCTION, Binding.GLOBAL, 0, callSiteRelocation.targetSymbol));
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java
new file mode 100644
index 0000000..6b55f28
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+
+import jdk.vm.ci.code.site.Call;
+
+final class ForeignGotCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+    public ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) {
+        super(createPltSymbol(dataBuilder, mi, call, callSiteRelocation));
+    }
+
+    private static Symbol createPltSymbol(DataBuilder dataBuilder, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+        BinaryContainer binaryContainer = dataBuilder.getBinaryContainer();
+        String vmSymbolName = callSiteRelocation.targetSymbol;
+
+        // Add relocation to GOT cell for call resolution jump.
+        String pltSymbolName = "plt." + vmSymbolName;
+        Symbol pltSymbol = binaryContainer.getSymbol(pltSymbolName);
+
+        if (pltSymbol == null) {
+            String gotSymbolName = "got." + vmSymbolName;
+            Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName);
+            assert gotSymbol != null : "undefined VM got symbol '" + gotSymbolName + "' for call at " + call.pcOffset + " in " + mi.getMethodInfo().getSymbolName();
+
+            // Generate PLT jump (do it only once).
+            final int pltStartOffset = binaryContainer.getCodeContainer().getByteStreamSize();
+            final int pltEndOffset = pltStartOffset + addPltJump(dataBuilder);
+
+            // Link GOT cell to PLT jump.
+            pltSymbol = createCodeContainerSymbol(binaryContainer, pltSymbolName, pltStartOffset);
+            addExternalPltToGotRelocation(binaryContainer, gotSymbol, pltEndOffset);
+        }
+
+        return pltSymbol;
+    }
+
+    private static int addPltJump(DataBuilder dataBuilder) {
+        ELFMacroAssembler masm = ELFMacroAssembler.getELFMacroAssembler(dataBuilder.getBackend().getTarget());
+        byte[] code = masm.getPLTJumpCode(); // It includes alignment nops.
+        int size = masm.currentEndOfInstruction();
+        dataBuilder.getBinaryContainer().appendCodeBytes(code, 0, code.length);
+        return size;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
new file mode 100644
index 0000000..d9cb0b2
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
+import org.graalvm.compiler.hotspot.word.MetaspacePointer;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.WordBase;
+
+public class GraalFilters {
+    private List<ResolvedJavaType> specialClasses;
+    private List<ResolvedJavaType> specialArgumentAndReturnTypes;
+
+    private static Set<Class<?>> skipAnnotations = new HashSet<>();
+
+    static {
+        skipAnnotations.add(NodeIntrinsic.class);
+        skipAnnotations.add(Snippet.class);
+        skipAnnotations.add(MethodSubstitution.class);
+    }
+
+    public boolean shouldCompileMethod(ResolvedJavaMethod method) {
+        // NodeIntrinsics cannot be compiled.
+        if (hasExcludedAnnotation(method)) {
+            return false;
+        }
+
+        ResolvedJavaType declaringClass = method.getDeclaringClass();
+        // Check for special magical types in the signature, like Word or MetaspacePointer. Those
+        // are definitely snippets.
+        List<ResolvedJavaType> signatureTypes = Arrays.asList(method.toParameterTypes()).stream().map(p -> p.resolve(declaringClass)).collect(Collectors.toList());
+        signatureTypes.add(method.getSignature().getReturnType(null).resolve(declaringClass));
+        if (signatureTypes.stream().flatMap(t -> specialArgumentAndReturnTypes.stream().filter(s -> s.isAssignableFrom(t))).findAny().isPresent()) {
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean hasExcludedAnnotation(ResolvedJavaMethod method) {
+        for (Annotation annotation : method.getAnnotations()) {
+            if (skipAnnotations.contains(annotation.annotationType())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
+        if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) {
+            return false;
+        }
+        return true;
+    }
+
+    // Don't compile methods in classes and their subtypes that are in the list.
+    private static List<ResolvedJavaType> getSpecialClasses(MetaAccessProvider meta) {
+        // @formatter:off
+        return Arrays.asList(meta.lookupJavaType(Snippets.class),
+            meta.lookupJavaType(HotSpotClassSubstitutions.class),
+            meta.lookupJavaType(GraalDirectives.class),
+            meta.lookupJavaType(ClassSubstitution.class));
+        // @formatter:on
+    }
+
+    // Don't compile methods that have have the listed class or their subtypes in their signature.
+    private static List<ResolvedJavaType> getSpecialArgumentAndReturnTypes(MetaAccessProvider meta) {
+        // @formatter:off
+        return Arrays.asList(meta.lookupJavaType(WordBase.class),
+            meta.lookupJavaType(MetaspacePointer.class));
+        // @formatter:on
+    }
+
+    GraalFilters(MetaAccessProvider metaAccess) {
+        specialClasses = getSpecialClasses(metaAccess);
+        specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess);
+    }
+
+    public boolean shouldIgnoreException(Throwable e) {
+        if (e instanceof GraalError) {
+            String m = e.getMessage();
+            if (m.contains("ArrayKlass::_component_mirror")) {
+                // When compiling Graal, ignore errors in JDK8 snippets.
+                return true;
+            }
+        }
+
+        if (e instanceof org.graalvm.compiler.java.BytecodeParser.BytecodeParserError) {
+            Throwable cause = e.getCause();
+            if (cause instanceof GraalError) {
+                String m = cause.getMessage();
+                // When compiling Graal suppress attempts to compile snippet fragments that bottom
+                // out with node intrinsics. These are unfortunately not explicitly marked, so we
+                // have to try to compile them and bail out if we think it's a snippet.
+                if (m.contains("@NodeIntrinsic method") && m.contains("must only be called from within a replacement")) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java
new file mode 100644
index 0000000..9f68df2
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.InvokeTarget;
+
+class InfopointProcessor {
+
+    private final DataBuilder dataBuilder;
+
+    private final BinaryContainer binaryContainer;
+
+    InfopointProcessor(DataBuilder dataBuilder) {
+        this.dataBuilder = dataBuilder;
+        this.binaryContainer = dataBuilder.getBinaryContainer();
+    }
+
+    /**
+     * Parse an {@link Infopoint} generated by the compiler and create all needed binary section
+     * constructs.
+     *
+     * @param methodInfo compiled method info
+     * @param info info point being processed
+     */
+    void process(CompiledMethodInfo methodInfo, Infopoint info) {
+        switch (info.reason) {
+            case CALL:
+                // All calls in compiled code need a symbol and relocation entry.
+                processCallInfoPoint(methodInfo, (Call) info);
+                break;
+            case SAFEPOINT:
+            case IMPLICIT_EXCEPTION:
+            case METHOD_START:
+            case METHOD_END:
+            case BYTECODE_POSITION:
+                break;
+            default:
+                throw new InternalError("Unknown info point reason: " + info.reason);
+        }
+        if (info.debugInfo == null) return;
+        BytecodePosition bcp = info.debugInfo.getBytecodePosition();
+        if (bcp == null) return;
+        recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping());
+    }
+
+    private void recordScopeKlasses(CompiledMethodInfo methodInfo, BytecodePosition bcp, VirtualObject[] vos) {
+        BytecodePosition caller = bcp.getCaller();
+        if (caller != null) {
+            recordScopeKlasses(methodInfo, caller, vos);
+        }
+
+        HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)bcp.getMethod();
+        HotSpotResolvedObjectType klass = m.getDeclaringClass();
+        methodInfo.addDependentKlassData(binaryContainer, klass);
+
+        if (vos == null) return;
+
+        for (VirtualObject vo : vos) {
+            HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType)vo.getType();
+            methodInfo.addDependentKlassData(binaryContainer, vk);
+        }
+
+    }
+
+    /**
+     * Process Call info points in Graal generated compilation result. We want to create one of the
+     * following relocations: .text -> .hotspot.plt.linkage - Java method to Java method call .text
+     * -> .text - Java method / Graal stub to Graal stub call .text -> .plt - Java method / Graal
+     * stub to VM method call.
+     *
+     * @param methodInfo compiled method info
+     * @param call call
+     */
+    private void processCallInfoPoint(CompiledMethodInfo methodInfo, Call call) {
+        CallSiteRelocationInfo callSiteRelocation = getCallSiteRelocationInfo(call);
+        CallSiteRelocationSymbol callSiteRelocationSymbol = getCallSiteRelocationSymbol(methodInfo, call, callSiteRelocation);
+
+        Relocation relocation = new Relocation(methodInfo.getTextSectionOffset() + call.pcOffset, callSiteRelocation.type, call.size, binaryContainer.getCodeContainer(),
+                        callSiteRelocationSymbol.symbol);
+        binaryContainer.addRelocation(relocation);
+    }
+
+    /**
+     * Get information about the call site. Name of the callee and relocation call type.
+     */
+    private CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) {
+        InvokeTarget callTarget = call.target;
+        if (callTarget instanceof HotSpotResolvedJavaMethod) {
+            return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget);
+        } else if (callTarget instanceof HotSpotForeignCallLinkage) {
+            return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget, dataBuilder);
+        } else {
+            throw new InternalError("Unhandled call type found in infopoint: " + callTarget);
+        }
+    }
+
+    /**
+     * Return a relocation symbol for the given call site.
+     */
+    private CallSiteRelocationSymbol getCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+        switch (callSiteRelocation.type) {
+            case STUB_CALL_DIRECT:
+                return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
+            case FOREIGN_CALL_INDIRECT_GOT:
+                return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder);
+            case FOREIGN_CALL_DIRECT:
+            case FOREIGN_CALL_DIRECT_FAR:
+            case FOREIGN_CALL_INDIRECT:
+                return new ForeignCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
+            default:
+                return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java
new file mode 100644
index 0000000..979e0cb
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InstructionDecoder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.amd64.AMD64InstructionDecoder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.TargetDescription;
+
+public abstract class InstructionDecoder {
+
+    public static InstructionDecoder getInstructionDecoder(TargetDescription target) {
+        Architecture architecture = target.arch;
+        if (architecture instanceof AMD64) {
+            return new AMD64InstructionDecoder(target);
+        } else {
+            throw new InternalError("Unsupported architecture " + architecture);
+        }
+    }
+
+    public abstract void decodePosition(final byte[] code, int pcOffset);
+
+    public abstract int currentEndOfInstruction();
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java
new file mode 100644
index 0000000..cd2db80
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+/**
+ * This is a Java call site. Get the Java method name and correct call relocation type. All static
+ * Java calls should be direct. All virtual Java calls should be indirect.
+ */
+final class JavaCallSiteRelocationInfo extends CallSiteRelocationInfo {
+
+    public JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) {
+        super(MiscUtils.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java
new file mode 100644
index 0000000..a14049d
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol;
+import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+/**
+ * Symbol for a regular Java call. This method also creates additional relocations for {@code .plt}
+ * to {@code .got} and {@code .got} to {@code .plt}.
+ */
+final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+    private static final byte[] zeroSlot = new byte[8];
+    private static final byte[] minusOneSlot = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+    public JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+        super(createPltEntrySymbol(binaryContainer, mi, call, callSiteRelocation));
+        StubInformation stub = getStub(mi, call);
+        addRelocations(mi, stub, binaryContainer, call, callSiteRelocation);
+    }
+
+    /**
+     * Returns a unique symbol name with the {@code suffix} appended.
+     */
+    private static String relocationSymbolName(String suffix, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+        return "M" + mi.getCodeId() + "_" + call.pcOffset + "_" + callSiteRelocation.targetSymbol + "_" + suffix;
+    }
+
+    private static Symbol createPltEntrySymbol(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
+        String symbolName = relocationSymbolName("plt.entry", mi, call, callSiteRelocation);
+        StubInformation stub = getStub(mi, call);
+        return createCodeContainerSymbol(binaryContainer, symbolName, stub.getOffset());
+    }
+
+    private static StubInformation getStub(CompiledMethodInfo mi, Call call) {
+        HotSpotResolvedJavaMethod callTarget = (HotSpotResolvedJavaMethod) call.target;
+        String callTargetSymbol = MiscUtils.uniqueMethodName(callTarget) + ".at." + call.pcOffset;
+        return mi.getStubFor(callTargetSymbol);
+    }
+
+    /**
+     * Add all the required relocations.
+     */
+    private static void addRelocations(CompiledMethodInfo mi, StubInformation stub, BinaryContainer binaryContainer, Call call, CallSiteRelocationInfo callSiteRelocation) {
+        final boolean isVirtualCall = MiscUtils.isVirtualCall(mi, call);
+
+        final int gotStartOffset = binaryContainer.appendExtLinkageGotBytes(zeroSlot, 0, zeroSlot.length);
+        if (isVirtualCall) {
+            // Nothing.
+        } else {
+            // For c2i stub we need slot with -1 value.
+            binaryContainer.appendExtLinkageGotBytes(minusOneSlot, 0, minusOneSlot.length);
+        }
+
+        // Add relocation to GOT cell for call resolution jump.
+        String gotSymbolName = "got." + getResolveSymbolName(binaryContainer, mi, call);
+        Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName);
+        addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset());
+
+        // Add relocation to resolve call jump instruction address for GOT cell.
+        String pltJmpSymbolName = relocationSymbolName("plt.jmp", mi, call, callSiteRelocation);
+        addCodeContainerRelocation(binaryContainer, pltJmpSymbolName, stub.getResolveJumpStart(), gotStartOffset);
+
+        // Add relocation to GOT cell for dispatch jump.
+        String gotEntrySymbolName = relocationSymbolName("got.entry", mi, call, callSiteRelocation);
+        addExtLinkageGotContainerRelocation(binaryContainer, gotEntrySymbolName, gotStartOffset, stub.getDispatchJumpOffset());
+
+        // Virtual call needs initial -1 value.
+        byte[] slot = isVirtualCall ? minusOneSlot : zeroSlot;
+        final int gotMetaOffset = binaryContainer.appendMetaspaceGotBytes(slot, 0, slot.length);
+
+        // Add relocation to GOT cell for move instruction (Klass* for virtual, Method* otherwise).
+        String gotMoveSymbolName = relocationSymbolName("got.move", mi, call, callSiteRelocation);
+        addMetaspaceGotRelocation(binaryContainer, gotMoveSymbolName, gotMetaOffset, stub.getMovOffset());
+
+        if (isVirtualCall) {
+            // Nothing.
+        } else {
+            // Add relocation to GOT cell for c2i adapter jump.
+            String gotC2ISymbolName = relocationSymbolName("got.c2i", mi, call, callSiteRelocation);
+            addExtLinkageGotContainerRelocation(binaryContainer, gotC2ISymbolName, gotStartOffset + 8, stub.getC2IJumpOffset());
+        }
+    }
+
+    /**
+     * Returns the name of the resolve method for this particular call.
+     */
+    private static String getResolveSymbolName(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call) {
+        String resolveSymbolName;
+        if (MiscUtils.isStaticCall(call)) {
+            resolveSymbolName = binaryContainer.getResolveStaticEntrySymbolName();
+        } else if (MiscUtils.isSpecialCall(call)) {
+            resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName();
+        } else if (MiscUtils.isOptVirtualCall(mi, call)) {
+            resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName();
+        } else if (MiscUtils.isVirtualCall(mi, call)) {
+            resolveSymbolName = binaryContainer.getResolveVirtualEntrySymbolName();
+        } else {
+            throw new InternalError("Unknown call type in " + mi.asTag() + " @ " + call.pcOffset + " for call" + call.target);
+        }
+        return resolveSymbolName;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java
new file mode 100644
index 0000000..908d5b0
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.code.CompilationResult;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+
+public interface JavaMethodInfo {
+
+    /**
+     * @return unique symbol name for this method.
+     */
+    String getSymbolName();
+
+    /**
+     * Name a java method with J.L.S. class name and signature.
+     *
+     * @return unique name for this method including class and signature
+     */
+    String getNameAndSignature();
+
+    HotSpotCompiledCode compiledCode(CompilationResult result);
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java
new file mode 100644
index 0000000..5885dea
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+public interface LogPrinter {
+    void printInfo(String s);
+
+    void printlnVerbose(String s);
+
+    void printlnInfo(String s);
+
+    void printError(String s);
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
new file mode 100644
index 0000000..a1257b7
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryUsage;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.collect.ClassCollector;
+import jdk.tools.jaotc.utils.Timer;
+
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.runtime.JVMCI;
+
+public class Main implements LogPrinter {
+    static {
+        GeneratePIC.setValue(true);
+        ImmutableCode.setValue(true);
+    }
+
+    static class BadArgs extends Exception {
+        private static final long serialVersionUID = 1L;
+        final String key;
+        final Object[] args;
+        boolean showUsage;
+
+        BadArgs(String key, Object... args) {
+            super(MessageFormat.format(key, args));
+            this.key = key;
+            this.args = args;
+        }
+
+        BadArgs showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+    }
+
+    abstract static class Option {
+        final String help;
+        final boolean hasArg;
+        final String[] aliases;
+
+        Option(String help, boolean hasArg, String... aliases) {
+            this.help = help;
+            this.hasArg = hasArg;
+            this.aliases = aliases;
+        }
+
+        boolean isHidden() {
+            return false;
+        }
+
+        boolean matches(String opt) {
+            for (String a : aliases) {
+                if (a.equals(opt)) {
+                    return true;
+                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean ignoreRest() {
+            return false;
+        }
+
+        abstract void process(Main task, String opt, String arg) throws BadArgs;
+    }
+
+    static Option[] recognizedOptions = {new Option("  --module <name>            Module to compile", true, "--module") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.module = arg;
+        }
+    }, new Option("  --module-path <path>       Specify where to find module to compile", true, "--module-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.modulepath = arg;
+        }
+    }, new Option("  --output <file>            Output file name", true, "--output") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            String name = arg;
+            if (name.endsWith(".so")) {
+                name = name.substring(0, name.length() - ".so".length());
+            }
+            task.options.outputName = name;
+        }
+    }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.methodList = arg;
+        }
+    }, new Option("  --compile-for-tiered       Generated profiling code for tiered compilation", false, "--compile-for-tiered") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            TieredAOT.setValue(true);
+        }
+    }, new Option("  --classpath <path>         Specify where to find user class files", true, "--classpath", "--class-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.classpath = arg;
+        }
+    }, new Option("  --threads <number>         Number of compilation threads to be used", true, "--threads") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            int threads = Integer.parseInt(arg);
+            final int available = Runtime.getRuntime().availableProcessors();
+            if (threads <= 0) {
+                task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
+                threads = available;
+            }
+            if (threads > available) {
+                task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
+            }
+            task.options.threads = Integer.min(threads, available);
+        }
+    }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.ignoreClassLoadingErrors = true;
+        }
+    }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.exitOnError = true;
+        }
+    }, new Option("  --info                     Print information during compilation", false, "--info") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+        }
+    }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+        }
+    }, new Option("  --debug                    Print debug information", false, "--debug") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+            task.options.debug = true;
+        }
+    }, new Option("  --help                     Print this usage message", false, "--help") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.help = true;
+        }
+    }, new Option("  --version                  Version information", false, "--version") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.version = true;
+        }
+    }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
+        @Override
+        void process(Main task, String opt, String arg) {
+        }
+    }};
+
+    public static class Options {
+        public List<String> files = new LinkedList<>();
+        public String module = null;
+        public String modulepath = "modules";
+        public String outputName = "unnamed";
+        public String methodList;
+        public String classpath = ".";
+
+        /**
+         * We don't see scaling beyond 16 threads.
+         */
+        private static final int COMPILER_THREADS = 16;
+
+        int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+
+        public boolean ignoreClassLoadingErrors;
+        public boolean exitOnError;
+        boolean info;
+        boolean verbose;
+        boolean debug;
+        boolean help;
+        boolean version;
+    }
+
+    /* package */final Options options = new Options();
+
+    /**
+     * Logfile.
+     */
+    private static FileWriter logFile = null;
+
+    private static final int EXIT_OK = 0;        // No errors.
+    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
+    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
+
+    private static final String PROGNAME = "jaotc";
+
+    private static final String JVM_VERSION = System.getProperty("java.runtime.version");
+
+    public static void main(String[] args) throws Exception {
+        Main t = new Main();
+        final int exitCode = t.run(args);
+        System.exit(exitCode);
+    }
+
+    private int run(String[] args) {
+        if (log == null) {
+            log = new PrintWriter(System.out);
+        }
+
+        try {
+            handleOptions(args);
+            if (options.help) {
+                showHelp();
+                return EXIT_OK;
+            }
+            if (options.version) {
+                showVersion();
+                return EXIT_OK;
+            }
+
+            printlnInfo("Compiling " + options.outputName + "...");
+            final long start = System.currentTimeMillis();
+            run();
+            final long end = System.currentTimeMillis();
+            printlnInfo("Total time: " + (end - start) + " ms");
+
+            return EXIT_OK;
+        } catch (BadArgs e) {
+            reportError(e.key, e.args);
+            if (e.showUsage) {
+                showUsage();
+            }
+            return EXIT_CMDERR;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return EXIT_ABNORMAL;
+        } finally {
+            log.flush();
+        }
+    }
+
+    private static String humanReadableByteCount(long bytes) {
+        int unit = 1024;
+
+        if (bytes < unit) {
+            return bytes + " B";
+        }
+
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        char pre = "KMGTPE".charAt(exp - 1);
+        return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
+    }
+
+    void printMemoryUsage() {
+        if (options.verbose) {
+            MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+            float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
+            log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
+                            humanReadableByteCount(memusage.getUsed()),
+                            humanReadableByteCount(memusage.getCommitted()),
+                            freeratio * 100);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void run() throws Exception {
+        openLog();
+
+        try {
+            CompilationSpec compilationRestrictions = collectSpecifiedMethods();
+
+            Set<Class<?>> classesToCompile;
+
+            try (Timer t = new Timer(this, "")) {
+                ClassCollector collector = new ClassCollector(this.options, this);
+                classesToCompile = collector.collectClassesToCompile();
+                printInfo(classesToCompile.size() + " classes found");
+            }
+
+            GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler();
+            HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
+            HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
+            MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
+            GraalFilters filters = new GraalFilters(metaAccess);
+
+            List<AOTCompiledClass> classes;
+
+            try (Timer t = new Timer(this, "")) {
+                classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess);
+            }
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                compilationRestrictions = null;
+                classesToCompile = null;
+                System.gc();
+            }
+
+            AOTBackend aotBackend = new AOTBackend(this, backend, filters);
+            AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
+            classes = compiler.compileClasses(classes);
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                aotBackend = null;
+                compiler = null;
+                System.gc();
+            }
+
+            BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION);
+            DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
+            dataBuilder.prepareData();
+
+            // Print information about section sizes
+            printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
+            printContainerInfo(binaryContainer.getConfigContainer());
+            printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
+            printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
+            printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
+            printContainerInfo(binaryContainer.getStubsOffsetsContainer());
+            printContainerInfo(binaryContainer.getMethodMetadataContainer());
+            printContainerInfo(binaryContainer.getCodeContainer());
+            printContainerInfo(binaryContainer.getCodeSegmentsContainer());
+            printContainerInfo(binaryContainer.getConstantDataContainer());
+            printContainerInfo(binaryContainer.getMetaspaceGotContainer());
+            printContainerInfo(binaryContainer.getMetadataGotContainer());
+            printContainerInfo(binaryContainer.getMethodStateContainer());
+            printContainerInfo(binaryContainer.getOopGotContainer());
+            printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                backend = null;
+                for (AOTCompiledClass aotCompClass : classes) {
+                    aotCompClass.clear();
+                }
+                classes.clear();
+                classes = null;
+                dataBuilder = null;
+                binaryContainer.freeMemory();
+                System.gc();
+            }
+
+            String objectFileName = options.outputName + ".o";
+            String libraryFileName = options.outputName + ".so";
+
+            try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
+                binaryContainer.createBinary(objectFileName, JVM_VERSION);
+            }
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                binaryContainer = null;
+                System.gc();
+            }
+
+            try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) {
+                Process p = Runtime.getRuntime().exec("ld -shared -z noexecstack -o " + libraryFileName + " " + objectFileName);
+                final int exitCode = p.waitFor();
+                if (exitCode != 0) {
+                    InputStream stderr = p.getErrorStream();
+                    BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
+                    Stream<String> lines = br.lines();
+                    StringBuilder sb = new StringBuilder();
+                    lines.iterator().forEachRemaining(e -> sb.append(e));
+                    throw new InternalError(sb.toString());
+                }
+                File objFile = new File(objectFileName);
+                if (objFile.exists()) {
+                    if (!objFile.delete()) {
+                        throw new InternalError("Failed to delete " + objectFileName + " file");
+                    }
+                }
+                // Make non-executable for all.
+                File libFile = new File(libraryFileName);
+                if (libFile.exists()) {
+                    if (!libFile.setExecutable(false, false)) {
+                        throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
+                    }
+                }
+            }
+
+            printVerbose("Final memory  ");
+            printMemoryUsage();
+            printlnVerbose("");
+
+        } finally {
+            closeLog();
+        }
+    }
+
+    private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
+        for (ResolvedJavaMethod m : methods) {
+            addMethod(aotClass, m, compilationRestrictions, filters);
+        }
+    }
+
+    private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) {
+        // Don't compile native or abstract methods.
+        if (!method.hasBytecodes()) {
+            return;
+        }
+        if (!compilationRestrictions.shouldCompileMethod(method)) {
+            return;
+        }
+        if (!filters.shouldCompileMethod(method)) {
+            return;
+        }
+
+        aotClass.addMethod(method);
+        printlnVerbose("  added " + method.getName() + method.getSignature().toMethodDescriptor());
+    }
+
+    private void printContainerInfo(ByteContainer container) {
+        printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
+    }
+
+    PrintWriter log;
+
+    private void handleOptions(String[] args) throws BadArgs {
+        if (args.length == 0) {
+            options.help = true;
+            return;
+        }
+
+        // Make checkstyle happy.
+        int i = 0;
+        for (; i < args.length; i++) {
+            String arg = args[i];
+
+            if (arg.charAt(0) == '-') {
+                Option option = getOption(arg);
+                String param = null;
+
+                if (option.hasArg) {
+                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
+                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
+                    } else if (i + 1 < args.length) {
+                        param = args[++i];
+                    }
+
+                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
+                        throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
+                    }
+                }
+
+                option.process(this, arg, param);
+
+                if (option.ignoreRest()) {
+                    break;
+                }
+            } else {
+                options.files.add(arg);
+            }
+        }
+    }
+
+    private static Option getOption(String name) throws BadArgs {
+        for (Option o : recognizedOptions) {
+            if (o.matches(name)) {
+                return o;
+            }
+        }
+        throw new BadArgs("unknown option: {0}", name).showUsage(true);
+    }
+
+    public void printInfo(String message) {
+        if (options.info) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnInfo(String message) {
+        if (options.info) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printVerbose(String message) {
+        if (options.verbose) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnVerbose(String message) {
+        if (options.verbose) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printDebug(String message) {
+        if (options.debug) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnDebug(String message) {
+        if (options.debug) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printError(String message) {
+        log.println("Error: " + message);
+        log.flush();
+    }
+
+    private void reportError(String key, Object... args) {
+        printError(MessageFormat.format(key, args));
+    }
+
+    private void warning(String key, Object... args) {
+        log.println("Warning: " + MessageFormat.format(key, args));
+        log.flush();
+    }
+
+    private void showUsage() {
+        log.println("Usage: " + PROGNAME + " <options> list...");
+        log.println("use --help for a list of possible options");
+    }
+
+    private void showHelp() {
+        log.println("Usage: " + PROGNAME + " <options> <--module name> | <list...>");
+        log.println();
+        log.println("  list       A list of class files, jar files or directories which");
+        log.println("             contains class files.");
+        log.println();
+        log.println("where possible options include:");
+        for (Option o : recognizedOptions) {
+            String name = o.aliases[0].substring(1); // there must always be at least one name
+            name = name.charAt(0) == '-' ? name.substring(1) : name;
+            if (o.isHidden() || name.equals("h")) {
+                continue;
+            }
+            log.println(o.help);
+        }
+    }
+
+    private void showVersion() {
+        log.println(PROGNAME + " " + JVM_VERSION);
+    }
+
+    /**
+     * Collect all method we should compile.
+     *
+     * @return array list of AOT classes which have compiled methods.
+     */
+    private List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) {
+        int total = 0;
+        int count = 0;
+        List<AOTCompiledClass> classes = new ArrayList<>();
+
+        for (Class<?> c : classesToCompile) {
+            ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
+            if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
+                AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
+                printlnVerbose(" Scanning " + c.getName());
+
+                // Constructors
+                try {
+                    ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
+                    addMethods(aotClass, ctors, compilationRestrictions, filters);
+                    total += ctors.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Methods
+                try {
+                    ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
+                    addMethods(aotClass, methods, compilationRestrictions, filters);
+                    total += methods.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Class initializer
+                try {
+                    ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
+                    if (clinit != null) {
+                        addMethod(aotClass, clinit, compilationRestrictions, filters);
+                        total++;
+                    }
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Found any methods to compile? Add the class.
+                if (aotClass.hasMethods()) {
+                    classes.add(aotClass);
+                    count += aotClass.getMethodCount();
+                }
+            }
+        }
+        printInfo(total + " methods total, " + count + " methods to compile");
+        return classes;
+    }
+
+    /**
+     * If a file with compilation limitations is specified using the java property
+     * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions.
+     */
+    private CompilationSpec collectSpecifiedMethods() {
+        CompilationSpec compilationRestrictions = new CompilationSpec();
+        String methodListFileName = options.methodList;
+
+        if (methodListFileName != null && !methodListFileName.equals("")) {
+            try {
+                FileReader methListFile = new FileReader(methodListFileName);
+                BufferedReader readBuf = new BufferedReader(methListFile);
+                String line = null;
+                while ((line = readBuf.readLine()) != null) {
+                    String trimmedLine = line.trim();
+                    if (!trimmedLine.startsWith("#")) {
+                        String[] components = trimmedLine.split(" ");
+                        if (components.length == 2) {
+                            String directive = components[0];
+                            String pattern = components[1];
+                            switch (directive) {
+                                case "compileOnly":
+                                    compilationRestrictions.addCompileOnlyPattern(pattern);
+                                    break;
+                                case "exclude":
+                                    compilationRestrictions.addExcludePattern(pattern);
+                                    break;
+                                default:
+                                    System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
+                            }
+                        } else {
+                            if (!trimmedLine.equals("")) {
+                                System.out.println("Ignoring malformed line:\n\t " + line + "\n");
+                            }
+                        }
+                    }
+                }
+                readBuf.close();
+            } catch (FileNotFoundException e) {
+                throw new InternalError("Unable to open method list file: " + methodListFileName, e);
+            } catch (IOException e) {
+                throw new InternalError("Unable to read method list file: " + methodListFileName, e);
+            }
+        }
+
+        return compilationRestrictions;
+    }
+
+    private static void openLog() {
+        int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
+        if (v == 0) {
+            logFile = null;
+            return;
+        }
+        // Create log file in current directory
+        String fileName = "aot_compilation" + new Date().getTime() + ".log";
+        Path logFilePath = Paths.get("./", fileName);
+        String logFileName = logFilePath.toString();
+        try {
+            // Create file to which we do not append
+            logFile = new FileWriter(logFileName, false);
+        } catch (IOException e) {
+            System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
+            logFile = null;
+        }
+    }
+
+    public static void writeLog(String str) {
+        if (logFile != null) {
+            try {
+                logFile.write(str + "\n");
+                logFile.flush();
+            } catch (IOException e) {
+                // Print to console
+                System.out.println(str + "\n");
+            }
+        }
+    }
+
+    public static void closeLog() {
+        if (logFile != null) {
+            try {
+                logFile.close();
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java
new file mode 100644
index 0000000..4bbd466
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+
+/**
+ * Constants used to mark special positions in code being installed into the code cache by Graal C++
+ * code.
+ */
+enum MarkId {
+    VERIFIED_ENTRY("CodeInstaller::VERIFIED_ENTRY"),
+    UNVERIFIED_ENTRY("CodeInstaller::UNVERIFIED_ENTRY"),
+    OSR_ENTRY("CodeInstaller::OSR_ENTRY"),
+    EXCEPTION_HANDLER_ENTRY("CodeInstaller::EXCEPTION_HANDLER_ENTRY"),
+    DEOPT_HANDLER_ENTRY("CodeInstaller::DEOPT_HANDLER_ENTRY"),
+    INVOKEINTERFACE("CodeInstaller::INVOKEINTERFACE"),
+    INVOKEVIRTUAL("CodeInstaller::INVOKEVIRTUAL"),
+    INVOKESTATIC("CodeInstaller::INVOKESTATIC"),
+    INVOKESPECIAL("CodeInstaller::INVOKESPECIAL"),
+    INLINE_INVOKE("CodeInstaller::INLINE_INVOKE"),
+    POLL_NEAR("CodeInstaller::POLL_NEAR"),
+    POLL_RETURN_NEAR("CodeInstaller::POLL_RETURN_NEAR"),
+    POLL_FAR("CodeInstaller::POLL_FAR"),
+    POLL_RETURN_FAR("CodeInstaller::POLL_RETURN_FAR"),
+    CARD_TABLE_ADDRESS("CodeInstaller::CARD_TABLE_ADDRESS"),
+    HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"),
+    HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"),
+    NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"),
+    CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"),
+    LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"),
+    INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
+
+    private final int value;
+
+    private MarkId(String name) {
+        this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name);
+    }
+
+    public static MarkId getEnum(int value) {
+        for (MarkId e : values()) {
+            if (e.value == value) {
+                return e;
+            }
+        }
+        throw new InternalError("Unknown enum value: " + value);
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
new file mode 100644
index 0000000..1e1944b
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Relocation;
+import jdk.tools.jaotc.binformat.Relocation.RelocType;
+import jdk.tools.jaotc.binformat.Symbol;
+
+import jdk.vm.ci.code.site.Mark;
+
+class MarkProcessor {
+
+    private final BinaryContainer binaryContainer;
+
+    MarkProcessor(DataBuilder dataBuilder) {
+        binaryContainer = dataBuilder.getBinaryContainer();
+    }
+
+    /**
+     * Parse a {@link Mark} generated by the compiler and create all needed binary section
+     * constructs.
+     *
+     * @param methodInfo compiled method info
+     * @param mark mark being processed
+     */
+    void process(CompiledMethodInfo methodInfo, Mark mark) {
+        MarkId markId = MarkId.getEnum((int) mark.id);
+        switch (markId) {
+            case EXCEPTION_HANDLER_ENTRY:
+            case DEOPT_HANDLER_ENTRY:
+                break;
+            case POLL_FAR:
+            case POLL_RETURN_FAR:
+            case CARD_TABLE_ADDRESS:
+            case HEAP_TOP_ADDRESS:
+            case HEAP_END_ADDRESS:
+            case NARROW_KLASS_BASE_ADDRESS:
+            case CRC_TABLE_ADDRESS:
+            case LOG_OF_HEAP_REGION_GRAIN_BYTES:
+            case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
+                String vmSymbolName;
+                switch (markId) {
+                    case POLL_FAR:
+                    case POLL_RETURN_FAR:
+                        vmSymbolName = binaryContainer.getPollingPageSymbolName();
+                        break;
+                    case CARD_TABLE_ADDRESS:
+                        vmSymbolName = binaryContainer.getCardTableAddressSymbolName();
+                        break;
+                    case HEAP_TOP_ADDRESS:
+                        vmSymbolName = binaryContainer.getHeapTopAddressSymbolName();
+                        break;
+                    case HEAP_END_ADDRESS:
+                        vmSymbolName = binaryContainer.getHeapEndAddressSymbolName();
+                        break;
+                    case NARROW_KLASS_BASE_ADDRESS:
+                        vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName();
+                        break;
+                    case CRC_TABLE_ADDRESS:
+                        vmSymbolName = binaryContainer.getCrcTableAddressSymbolName();
+                        break;
+                    case LOG_OF_HEAP_REGION_GRAIN_BYTES:
+                        vmSymbolName = binaryContainer.getLogOfHeapRegionGrainBytesSymbolName();
+                        break;
+                    case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
+                        vmSymbolName = binaryContainer.getInlineContiguousAllocationSupportedSymbolName();
+                        break;
+                    default:
+                        throw new InternalError("Unhandled mark: " + mark);
+                }
+                String s = "got." + vmSymbolName;
+                Symbol gotSymbol = binaryContainer.getGotSymbol(s);
+                assert gotSymbol != null : " Processing Mark: Encountered undefined got symbol for  " + mark;
+                final int textBaseOffset = methodInfo.getTextSectionOffset();
+                final int textOffset = textBaseOffset + mark.pcOffset;
+                Relocation reloc = new Relocation(textOffset, RelocType.EXTERNAL_PLT_TO_GOT, 8, binaryContainer.getCodeContainer(), gotSymbol);
+                binaryContainer.addRelocation(reloc);
+                break;
+            case VERIFIED_ENTRY:
+            case UNVERIFIED_ENTRY:
+            case OSR_ENTRY:
+            case INVOKEINTERFACE:
+            case INVOKEVIRTUAL:
+            case INVOKESTATIC:
+            case INVOKESPECIAL:
+            case INLINE_INVOKE:
+            case POLL_NEAR:
+            case POLL_RETURN_NEAR:
+                // Nothing to do.
+                break;
+            default:
+                throw new InternalError("Unexpected mark found: " + mark);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java
new file mode 100644
index 0000000..9a8726b
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+import jdk.tools.jaotc.binformat.Symbol.Kind;
+import jdk.tools.jaotc.binformat.GotSymbol;
+import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
+import jdk.tools.jaotc.utils.NativeOrderOutputStream;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotMetaData;
+
+class MetadataBuilder {
+
+    private final DataBuilder dataBuilder;
+
+    private final BinaryContainer binaryContainer;
+
+    MetadataBuilder(DataBuilder dataBuilder) {
+        this.dataBuilder = dataBuilder;
+        this.binaryContainer = dataBuilder.getBinaryContainer();
+    }
+
+    /**
+     * Process compiled methods and create method metadata.
+     */
+    void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
+        binaryContainer.getMethodMetadataContainer().createSymbol(0, Kind.OBJECT, Binding.LOCAL, 0, "metaStart");
+
+        for (AOTCompiledClass c : classes) {
+            processMetadataClass(c);
+        }
+        processMetadataClass(stubCompiledCode);
+    }
+
+    private void processMetadataClass(AOTCompiledClass c) {
+        processInfopointsAndMarks(c);
+        createMethodMetadata(c);
+    }
+
+    /**
+     * Add metadata for each of the compiled methods in {@code compiledClass} to read-only section
+     * of {@code binaryContainer}.
+     *
+     * @param compiledClass AOT Graal compilation result
+     */
+    private void createMethodMetadata(AOTCompiledClass compiledClass) {
+        HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
+        ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
+
+        // For each of the compiled java methods, create records holding information about them.
+        for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
+            // Get the current offset in the methodmetadata container.
+            final int startOffset = methodMetadataContainer.getByteStreamSize();
+            assert startOffset % 8 == 0 : "Must be aligned on 8";
+
+            methodInfo.setMetadataOffset(startOffset);
+
+            HotSpotCompiledCode compiledMethod = methodInfo.compiledCode();
+            // pc and scope description
+            HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod);
+
+            byte[] pcDesc = metaData.pcDescBytes();
+            byte[] scopeDesc = metaData.scopesDescBytes();
+            byte[] relocationInfo = metaData.relocBytes();
+            byte[] oopMapInfo = metaData.oopMaps();
+
+            // create a global symbol at this position for this method
+            NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
+
+            // get the code size
+            int codeSize = methodInfo.getCodeSize();
+
+            // get code offsets
+            CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks());
+            int unverifiedEntry = co.entry();
+            int verifiedEntry = co.verifiedEntry();
+            int exceptionHandler = co.exceptionHandler();
+            int deoptHandler = co.deoptHandler();
+            int frameSize = methodInfo.getCompilationResult().getTotalFrameSize();
+            StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea();
+            int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1;
+
+            // get stubs offset
+            int stubsOffset = methodInfo.getStubsOffset();
+
+            int offset = addMetadataEntries(binaryContainer, metaData, methodInfo);
+            methodInfo.setMetadataGotOffset(offset);
+            methodInfo.setMetadataGotSize(metaData.metadataEntries().length);
+            int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0;
+            try {
+                // calculate total size of the container
+                NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt();
+
+                // @formatter:off
+                metadataStream.putInt(codeSize).
+                               putInt(unverifiedEntry).
+                               putInt(verifiedEntry).
+                               putInt(exceptionHandler).
+                               putInt(deoptHandler).
+                               putInt(stubsOffset).
+                               putInt(frameSize).
+                               putInt(origPcOffset).
+                               putInt(unsafeAccess);
+                // @formatter:on
+
+                NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt();
+                NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
+                NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
+                NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
+                NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
+                metadataStream.align(8);
+
+                pcDescOffset.set(metadataStream.position());
+                metadataStream.put(pcDesc).align(8);
+
+                scopeOffset.set(metadataStream.position());
+                metadataStream.put(scopeDesc).align(8);
+
+                relocationOffset.set(metadataStream.position());
+                metadataStream.put(relocationInfo).align(8);
+
+                exceptionOffset.set(metadataStream.position());
+                metadataStream.put(metaData.exceptionBytes()).align(8);
+
+                // oopmaps should be last
+                oopMapOffset.set(metadataStream.position());
+                metadataStream.put(oopMapInfo).align(8);
+
+                totalSize.set(metadataStream.position());
+
+                byte[] data = metadataStream.array();
+
+                methodMetadataContainer.appendBytes(data, 0, data.length);
+            } catch (Exception e) {
+                throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e);
+            }
+            methodInfo.clearCompileData(); // Clear unused anymore compilation data
+        }
+    }
+
+    private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) {
+        String[] metaDataEntries = metaData.metadataEntries();
+
+        if (metaDataEntries.length == 0) {
+            return 0;
+        }
+
+        int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length);
+
+        for (int index = 0; index < metaDataEntries.length; index++) {
+            String name = metaDataEntries[index];
+            addMetadataEntry(binaryContainer, name);
+            // Create GOT cells for klasses referenced in metadata
+            String klassName = name;
+            int len = name.length();
+            int parenthesesIndex = name.lastIndexOf('(', len - 1);
+            if (parenthesesIndex > 0) {  // Method name
+                int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1);
+                assert dotIndex > 0 : "method's full name should have '.' : " + name;
+                klassName = name.substring(0, dotIndex);
+            }
+            // We should already have added entries for this klass
+            assert AOTCompiledClass.getAOTKlassData(klassName) != null;
+            assert methodInfo.getDependentKlassData(klassName) != null;
+        }
+
+        return metadataGotSlotsStart;
+    }
+
+    private static void addMetadataEntry(BinaryContainer binaryContainer, String name) {
+        int stringOffset = binaryContainer.addMetaspaceName(name);
+        binaryContainer.addMetadataGotEntry(stringOffset);
+    }
+
+    /**
+     * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler
+     * to create all needed binary section constructs.
+     *
+     * @param compiledClass compilation result
+     */
+    private void processInfopointsAndMarks(AOTCompiledClass compiledClass) {
+        ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods();
+
+        MarkProcessor markProcessor = new MarkProcessor(dataBuilder);
+        DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder);
+        InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder);
+
+        for (CompiledMethodInfo methodInfo : compiledMethods) {
+            CompilationResult compilationResult = methodInfo.getCompilationResult();
+            String targetSymbol = "state.M" + methodInfo.getCodeId();
+            String gotName = "got." + targetSymbol;
+            GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName);
+            assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset";
+
+            for (Infopoint infoPoint : compilationResult.getInfopoints()) {
+                infopointProcessor.process(methodInfo, infoPoint);
+            }
+
+            for (Mark mark : compilationResult.getMarks()) {
+                markProcessor.process(methodInfo, mark);
+            }
+
+            for (DataPatch dataPatch : compilationResult.getDataPatches()) {
+                dataPatchProcessor.process(methodInfo, dataPatch);
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java
new file mode 100644
index 0000000..1503b9d
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MiscUtils {
+
+    /**
+     * Name a java method with class and signature to make it unique.
+     *
+     * @param method to generate unique identifier for
+     * @return Unique name for this method including class and signature
+     **/
+    public static String uniqueMethodName(ResolvedJavaMethod method) {
+        String className = method.getDeclaringClass().toClassName();
+        String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor();
+        return name;
+    }
+
+    public static boolean isStaticCall(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC);
+        }
+        return false;
+    }
+
+    public static boolean isSpecialCall(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL);
+        }
+        return false;
+    }
+
+    private static boolean isInvokeVirtual(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE);
+        }
+        return false;
+    }
+
+    public static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+        return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
+    }
+
+    public static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+        return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
+    }
+
+    private static boolean isJavaCall(Call call) {
+        // If there is no associated debug info return false
+        if (call.debugInfo == null) {
+            return false;
+        }
+        BytecodePosition bcpos = call.debugInfo.getBytecodePosition();
+        ResolvedJavaMethod method = bcpos.getMethod();
+        // If bytecode position indicates a special value (negative value) it is
+        // not a normal java call
+        if (bcpos.getBCI() < 0) {
+            return false;
+        }
+        // If there is no method associated with the debuginfo, return false
+        if (method == null) {
+            return false;
+        }
+        assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call";
+        return true;
+    }
+
+    private static byte getByteCode(Call call) {
+        ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod();
+        int callPosition = call.debugInfo.getBytecodePosition().getBCI();
+        byte[] code = m.getCode();
+        return code[callPosition];
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java
new file mode 100644
index 0000000..50826f7
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.Symbol.Binding;
+
+/**
+ * Call to a Graal stub, the symbol name should be direct.
+ */
+final class StubDirectCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
+
+    public StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+        super(binaryContainer.getSymbol(callSiteRelocation.targetSymbol));
+        assert symbol != null && symbol.getBinding() == Binding.LOCAL : "Stub symbol must exist and must be LOCAL";
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java
new file mode 100644
index 0000000..8ec0903
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.amd64.AMD64.rip;
+
+import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.ELFMacroAssembler;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class AMD64ELFMacroAssembler extends AMD64MacroAssembler implements ELFMacroAssembler {
+
+    private int currentEndOfInstruction;
+
+    public AMD64ELFMacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    @Override
+    public int currentEndOfInstruction() {
+        return currentEndOfInstruction;
+    }
+
+    @Override
+    public byte[] getPLTJumpCode() {
+        // The main dispatch instruction
+        // jmpq *0x00000000(%rip)
+        jmp(new AMD64Address(rip, 0));
+        currentEndOfInstruction = position();
+
+        // Align to 8 bytes
+        align(8);
+
+        return close(true);
+    }
+
+    @Override
+    public byte[] getPLTStaticEntryCode(StubInformation stub) {
+        // The main dispatch instruction
+        // jmpq *0x00000000(%rip)
+        jmp(new AMD64Address(rip, 0));
+        stub.setDispatchJumpOffset(position());
+
+        // C2I stub used to call interpreter.
+        // mov 0x00000000(%rip),%rbx Loading Method*
+        movq(rbx, new AMD64Address(rip, 0));
+        stub.setMovOffset(position());
+
+        // jmpq *0x00000000(%rip) [c2i addr]
+        jmp(new AMD64Address(rip, 0));
+        stub.setC2IJumpOffset(position());
+
+        // Call to VM runtime to resolve the call.
+        // jmpq *0x00000000(%rip)
+        stub.setResolveJumpStart(position());
+        jmp(new AMD64Address(rip, 0));
+        stub.setResolveJumpOffset(position());
+        currentEndOfInstruction = position();
+
+        // Align to 8 bytes
+        align(8);
+        stub.setSize(position());
+
+        return close(true);
+    }
+
+    @Override
+    public byte[] getPLTVirtualEntryCode(StubInformation stub) {
+        // Klass loading instruction
+        // mov 0x00000000(%rip),%rax
+        movq(rax, new AMD64Address(rip, 0));
+        stub.setMovOffset(position());
+
+        // The main dispatch instruction
+        // jmpq *0x00000000(%rip)
+        jmp(new AMD64Address(rip, 0));
+        stub.setDispatchJumpOffset(position());
+
+        // Call to VM runtime to resolve the call.
+        // jmpq *0x00000000(%rip)
+        stub.setResolveJumpStart(position());
+        jmp(new AMD64Address(rip, 0));
+        stub.setResolveJumpOffset(position());
+        currentEndOfInstruction = position();
+
+        // Align to 8 bytes
+        align(8);
+        stub.setSize(position());
+
+        return close(true);
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java
new file mode 100644
index 0000000..9c08463
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.amd64;
+
+import jdk.tools.jaotc.InstructionDecoder;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class AMD64InstructionDecoder extends InstructionDecoder {
+
+    private boolean targetIs64Bit;
+    private int currentEndOfInstruction;
+
+    private static class Prefix {
+
+        // segment overrides
+        public static final int CSSegment = 0x2e;
+        public static final int SSSegment = 0x36;
+        public static final int DSSegment = 0x3e;
+        public static final int ESSegment = 0x26;
+        public static final int FSSegment = 0x64;
+        public static final int GSSegment = 0x65;
+        public static final int REX = 0x40;
+        public static final int REXB = 0x41;
+        public static final int REXX = 0x42;
+        public static final int REXXB = 0x43;
+        public static final int REXR = 0x44;
+        public static final int REXRB = 0x45;
+        public static final int REXRX = 0x46;
+        public static final int REXRXB = 0x47;
+        public static final int REXW = 0x48;
+        public static final int REXWB = 0x49;
+        public static final int REXWX = 0x4A;
+        public static final int REXWXB = 0x4B;
+        public static final int REXWR = 0x4C;
+        public static final int REXWRB = 0x4D;
+        public static final int REXWRX = 0x4E;
+        public static final int REXWRXB = 0x4F;
+        public static final int VEX_3BYTES = 0xC4;
+        public static final int VEX_2BYTES = 0xC5;
+    }
+
+    public static class VexPrefix {
+        public static final int VEX_R = 0x80;
+        public static final int VEX_W = 0x80;
+    }
+
+    public static class VexOpcode {
+        public static final int VEX_OPCODE_NONE = 0x0;
+        public static final int VEX_OPCODE_0F = 0x1;
+        public static final int VEX_OPCODE_0F_38 = 0x2;
+        public static final int VEX_OPCODE_0F_3A = 0x3;
+        public static final int VEX_OPCODE_MASK = 0x1F;
+    }
+
+    public AMD64InstructionDecoder(TargetDescription target) {
+        this.targetIs64Bit = target.wordSize == 8;
+    }
+
+    @Override
+    public int currentEndOfInstruction() {
+        return currentEndOfInstruction;
+    }
+
+    @Override
+    @SuppressWarnings("fallthrough")
+    public void decodePosition(final byte[] code, int pcOffset) {
+        assert pcOffset >= 0 && pcOffset < code.length;
+
+        // Decode the given instruction, and return the Pointer of
+        // an embedded 32-bit operand word.
+
+        // If "which" is WhichOperand.disp32operand, selects the displacement portion
+        // of an effective Pointer specifier.
+        // If "which" is imm64Operand, selects the trailing immediate constant.
+        // If "which" is WhichOperand.call32operand, selects the displacement of a call or jump.
+        // Caller is responsible for ensuring that there is such an operand,
+        // and that it is 32/64 bits wide.
+
+        // If "which" is endPcOperand, find the end of the instruction.
+
+        int ip = pcOffset;
+        boolean is64bit = false;
+
+        boolean hasDisp32 = false;
+        int tailSize = 0; // other random bytes (#32, #16, etc.) at end of insn
+
+        boolean againAfterPrefix = true;
+
+        while (againAfterPrefix) {
+            againAfterPrefix = false;
+            switch (0xFF & code[ip++]) {
+
+                // These convenience macros generate groups of "case" labels for the switch.
+
+                case Prefix.CSSegment:
+                case Prefix.SSSegment:
+                case Prefix.DSSegment:
+                case Prefix.ESSegment:
+                case Prefix.FSSegment:
+                case Prefix.GSSegment:
+                    // Seems dubious
+                    assert !targetIs64Bit : "shouldn't have that prefix";
+                    assert ip == pcOffset + 1 : "only one prefix allowed";
+                    againAfterPrefix = true;
+                    break;
+
+                case 0x67:
+                case Prefix.REX:
+                case Prefix.REXB:
+                case Prefix.REXX:
+                case Prefix.REXXB:
+                case Prefix.REXR:
+                case Prefix.REXRB:
+                case Prefix.REXRX:
+                case Prefix.REXRXB:
+                    assert targetIs64Bit : "64bit prefixes";
+                    againAfterPrefix = true;
+                    break;
+
+                case Prefix.REXW:
+                case Prefix.REXWB:
+                case Prefix.REXWX:
+                case Prefix.REXWXB:
+                case Prefix.REXWR:
+                case Prefix.REXWRB:
+                case Prefix.REXWRX:
+                case Prefix.REXWRXB:
+                    assert targetIs64Bit : "64bit prefixes";
+                    is64bit = true;
+                    againAfterPrefix = true;
+                    break;
+
+                case 0xFF: // pushq a; decl a; incl a; call a; jmp a
+                case 0x88: // movb a, r
+                case 0x89: // movl a, r
+                case 0x8A: // movb r, a
+                case 0x8B: // movl r, a
+                case 0x8F: // popl a
+                    hasDisp32 = true;
+                    break;
+
+                case 0x68: // pushq #32
+                    currentEndOfInstruction = ip + 4;
+                    return; // not produced by emitOperand
+
+                case 0x66: // movw ... (size prefix)
+                    boolean againAfterSizePrefix2 = true;
+                    while (againAfterSizePrefix2) {
+                        againAfterSizePrefix2 = false;
+                        switch (0xFF & code[ip++]) {
+                            case Prefix.REX:
+                            case Prefix.REXB:
+                            case Prefix.REXX:
+                            case Prefix.REXXB:
+                            case Prefix.REXR:
+                            case Prefix.REXRB:
+                            case Prefix.REXRX:
+                            case Prefix.REXRXB:
+                            case Prefix.REXW:
+                            case Prefix.REXWB:
+                            case Prefix.REXWX:
+                            case Prefix.REXWXB:
+                            case Prefix.REXWR:
+                            case Prefix.REXWRB:
+                            case Prefix.REXWRX:
+                            case Prefix.REXWRXB:
+                                assert targetIs64Bit : "64bit prefix found";
+                                againAfterSizePrefix2 = true;
+                                break;
+                            case 0x8B: // movw r, a
+                            case 0x89: // movw a, r
+                                hasDisp32 = true;
+                                break;
+                            case 0xC7: // movw a, #16
+                                hasDisp32 = true;
+                                tailSize = 2; // the imm16
+                                break;
+                            case 0x0F: // several SSE/SSE2 variants
+                                ip--; // reparse the 0x0F
+                                againAfterPrefix = true;
+                                break;
+                            default:
+                                throw new InternalError("should not reach here");
+                        }
+                    }
+                    break;
+
+                case 0xB8: // movl/q r, #32/#64(oop?)
+                case 0xB9:
+                case 0xBA:
+                case 0xBB:
+                case 0xBC:
+                case 0xBD:
+                case 0xBE:
+                case 0xBF:
+                    currentEndOfInstruction = ip + (is64bit ? 8 : 4);
+                    return;
+
+                case 0x69: // imul r, a, #32
+                case 0xC7: // movl a, #32(oop?)
+                    tailSize = 4;
+                    hasDisp32 = true; // has both kinds of operands!
+                    break;
+
+                case 0x0F: // movx..., etc.
+                    switch (0xFF & code[ip++]) {
+                        case 0x3A: // pcmpestri
+                            ip++; // skip opcode
+                            tailSize = 1;
+                            hasDisp32 = true; // has both kinds of operands!
+                            break;
+
+                        case 0x38: // ptest, pmovzxbw
+                            ip++; // skip opcode
+                            hasDisp32 = true; // has both kinds of operands!
+                            break;
+
+                        case 0x70: // pshufd r, r/a, #8
+                            hasDisp32 = true; // has both kinds of operands!
+                            tailSize = 1;
+                            break;
+
+                        case 0x73: // psrldq r, #8
+                            tailSize = 1;
+                            break;
+
+                        case 0x12: // movlps
+                        case 0x28: // movaps
+                        case 0x2E: // ucomiss
+                        case 0x2F: // comiss
+                        case 0x54: // andps
+                        case 0x55: // andnps
+                        case 0x56: // orps
+                        case 0x57: // xorps
+                        case 0x58: // addpd
+                        case 0x59: // mulpd
+                        case 0x6E: // movd
+                        case 0x7E: // movd
+                        case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush
+                        case 0xFE: // paddd
+                            // 64bit side says it these have both operands but that doesn't
+                            // appear to be true
+                            hasDisp32 = true;
+                            break;
+
+                        case 0xAD: // shrd r, a, %cl
+                        case 0xAF: // imul r, a
+                        case 0xBE: // movsbl r, a (movsxb)
+                        case 0xBF: // movswl r, a (movsxw)
+                        case 0xB6: // movzbl r, a (movzxb)
+                        case 0xB7: // movzwl r, a (movzxw)
+                        case 0x40: // cmovl cc, r, a
+                        case 0x41:
+                        case 0x42:
+                        case 0x43:
+                        case 0x44:
+                        case 0x45:
+                        case 0x46:
+                        case 0x47:
+                        case 0x48:
+                        case 0x49:
+                        case 0x4A:
+                        case 0x4B:
+                        case 0x4C:
+                        case 0x4D:
+                        case 0x4E:
+                        case 0x4F:
+                        case 0xB0: // cmpxchgb
+                        case 0xB1: // cmpxchg
+                        case 0xC1: // xaddl
+                        case 0xC7: // cmpxchg8
+                        case 0x90: // setcc a
+                        case 0x91:
+                        case 0x92:
+                        case 0x93:
+                        case 0x94:
+                        case 0x95:
+                        case 0x96:
+                        case 0x97:
+                        case 0x98:
+                        case 0x99:
+                        case 0x9A:
+                        case 0x9B:
+                        case 0x9C:
+                        case 0x9D:
+                        case 0x9E:
+                        case 0x9F:
+                            hasDisp32 = true;
+                            // fall out of the switch to decode the Pointer
+                            break;
+
+                        case 0xC4: // pinsrw r, a, #8
+                            hasDisp32 = true;
+                            tailSize = 1;  // the imm8
+                            break;
+
+                        case 0xC5: // pextrw r, r, #8
+                            tailSize = 1;  // the imm8
+                            break;
+
+                        case 0xAC: // shrd r, a, #8
+                            hasDisp32 = true;
+                            tailSize = 1; // the imm8
+                            break;
+
+                        case 0x80: // jcc rdisp32
+                        case 0x81:
+                        case 0x82:
+                        case 0x83:
+                        case 0x84:
+                        case 0x85:
+                        case 0x86:
+                        case 0x87:
+                        case 0x88:
+                        case 0x89:
+                        case 0x8A:
+                        case 0x8B:
+                        case 0x8C:
+                        case 0x8D:
+                        case 0x8E:
+                        case 0x8F:
+                            currentEndOfInstruction = ip + 4;
+                            return;
+                        default:
+                            throw new InternalError("should not reach here");
+                    }
+                    break;
+
+                case 0x81: // addl a, #32; addl r, #32
+                    // also: orl, adcl, sbbl, andl, subl, xorl, cmpl
+                    // on 32bit in the case of cmpl, the imm might be an oop
+                    tailSize = 4;
+                    hasDisp32 = true; // has both kinds of operands!
+                    break;
+
+                case 0x83: // addl a, #8; addl r, #8
+                    // also: orl, adcl, sbbl, andl, subl, xorl, cmpl
+                    hasDisp32 = true; // has both kinds of operands!
+                    tailSize = 1;
+                    break;
+
+                case 0x9B:
+                    switch (0xFF & code[ip++]) {
+                        case 0xD9: // fnstcw a
+                            hasDisp32 = true;
+                            break;
+                        default:
+                            throw new InternalError("should not reach here");
+                    }
+                    break;
+
+                case 0x00: // addb a, r; addl a, r; addb r, a; addl r, a
+                case 0x01:
+                case 0x02:
+                case 0x03:
+                case 0x10: // adc...
+                case 0x11:
+                case 0x12:
+                case 0x13:
+                case 0x20: // and...
+                case 0x21:
+                case 0x22:
+                case 0x23:
+                case 0x30: // xor...
+                case 0x31:
+                case 0x32:
+                case 0x33:
+                case 0x08: // or...
+                case 0x09:
+                case 0x0a:
+                case 0x0b:
+                case 0x18: // sbb...
+                case 0x19:
+                case 0x1a:
+                case 0x1b:
+                case 0x28: // sub...
+                case 0x29:
+                case 0x2a:
+                case 0x2b:
+                case 0xF7: // mull a
+                case 0x8D: // lea r, a
+                case 0x87: // xchg r, a
+                case 0x38: // cmp...
+                case 0x39:
+                case 0x3a:
+                case 0x3b:
+                case 0x85: // test r, a
+                    hasDisp32 = true; // has both kinds of operands!
+                    break;
+
+                case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8
+                case 0xC6: // movb a, #8
+                case 0x80: // cmpb a, #8
+                case 0x6B: // imul r, a, #8
+                    hasDisp32 = true; // has both kinds of operands!
+                    tailSize = 1; // the imm8
+                    break;
+
+                case Prefix.VEX_3BYTES:
+                case Prefix.VEX_2BYTES:
+                    assert ip == pcOffset + 1 : "no prefixes allowed";
+                    int vex_opcode;
+                    // First byte
+                    if ((code[pcOffset] & 0xFF) == Prefix.VEX_3BYTES) {
+                        vex_opcode = VexOpcode.VEX_OPCODE_MASK & code[ip];
+                        ip++; // third byte
+                        is64bit = ((VexPrefix.VEX_W & code[ip]) == VexPrefix.VEX_W);
+                    } else {
+                        vex_opcode = VexOpcode.VEX_OPCODE_0F;
+                    }
+                    ip++; // opcode
+                    // To find the end of instruction (which == end_pc_operand).
+                    switch (vex_opcode) {
+                        case VexOpcode.VEX_OPCODE_0F:
+                            switch (0xFF & code[ip]) {
+                                case 0x70: // pshufd r, r/a, #8
+                                case 0x71: // ps[rl|ra|ll]w r, #8
+                                case 0x72: // ps[rl|ra|ll]d r, #8
+                                case 0x73: // ps[rl|ra|ll]q r, #8
+                                case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8
+                                case 0xC4: // pinsrw r, r, r/a, #8
+                                case 0xC5: // pextrw r/a, r, #8
+                                case 0xC6: // shufp[s|d] r, r, r/a, #8
+                                    tailSize = 1;  // the imm8
+                                    break;
+                                default:
+                                    ; // no imm8
+                            }
+                            break;
+                        case VexOpcode.VEX_OPCODE_0F_3A:
+                            tailSize = 1;
+                            break;
+                        default:
+                            throw new InternalError("should not reach here");
+                    }
+                    ip++; // skip opcode
+                    hasDisp32 = true;
+                    break;
+
+                case 0xE8: // call rdisp32
+                case 0xE9: // jmp rdisp32
+                    currentEndOfInstruction = ip + 4;
+                    return;
+
+                case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1
+                case 0xD3: // sal a, %cl; sar a, %cl; shl a, %cl; shr a, %cl
+                case 0xD9: // fldS a; fstS a; fstpS a; fldcw a
+                case 0xDD: // fldD a; fstD a; fstpD a
+                case 0xDB: // fildS a; fistpS a; fldX a; fstpX a
+                case 0xDF: // fildD a; fistpD a
+                case 0xD8: // faddS a; fsubrS a; fmulS a; fdivrS a; fcompS a
+                case 0xDC: // faddD a; fsubrD a; fmulD a; fdivrD a; fcompD a
+                case 0xDE: // faddpD a; fsubrpD a; fmulpD a; fdivrpD a; fcomppD a
+                    hasDisp32 = true;
+                    break;
+
+                case 0xF0: // Lock
+                    againAfterPrefix = true;
+                    break;
+
+                case 0xF3: // For SSE
+                case 0xF2: // For SSE2
+                    switch (0xFF & code[ip++]) {
+                        case Prefix.REX:
+                        case Prefix.REXB:
+                        case Prefix.REXX:
+                        case Prefix.REXXB:
+                        case Prefix.REXR:
+                        case Prefix.REXRB:
+                        case Prefix.REXRX:
+                        case Prefix.REXRXB:
+                        case Prefix.REXW:
+                        case Prefix.REXWB:
+                        case Prefix.REXWX:
+                        case Prefix.REXWXB:
+                        case Prefix.REXWR:
+                        case Prefix.REXWRB:
+                        case Prefix.REXWRX:
+                        case Prefix.REXWRXB:
+                            assert targetIs64Bit : "found 64bit prefix";
+                            ip++;
+                            ip++;
+                            break;
+                        default:
+                            ip++;
+                    }
+                    hasDisp32 = true; // has both kinds of operands!
+                    break;
+
+                default:
+                    throw new InternalError("should not reach here");
+            }
+        }
+
+        assert hasDisp32 : "(tw) not sure if this holds: instruction has no disp32 field";
+
+        // parse the output of emitOperand
+        int op2 = 0xFF & code[ip++];
+        int base = op2 & 0x07;
+        int op3 = -1;
+        int b100 = 4;
+        int b101 = 5;
+        if (base == b100 && (op2 >> 6) != 3) {
+            op3 = 0xFF & code[ip++];
+            base = op3 & 0x07; // refetch the base
+        }
+        // now ip points at the disp (if any)
+
+        switch (op2 >> 6) {
+            case 0:
+                // [00 reg 100][ss index base]
+                // [00 reg 100][00 100 esp]
+                // [00 reg base]
+                // [00 reg 100][ss index 101][disp32]
+                // [00 reg 101] [disp32]
+                if (base == b101) {
+                    ip += 4; // skip the disp32
+                }
+                break;
+
+            case 1:
+                // [01 reg 100][ss index base][disp8]
+                // [01 reg 100][00 100 esp][disp8]
+                // [01 reg base] [disp8]
+                ip += 1; // skip the disp8
+                break;
+
+            case 2:
+                // [10 reg 100][ss index base][disp32]
+                // [10 reg 100][00 100 esp][disp32]
+                // [10 reg base] [disp32]
+                ip += 4; // skip the disp32
+                break;
+
+            case 3:
+                // [11 reg base] (not a memory addressing mode)
+                break;
+        }
+
+        currentEndOfInstruction = ip + tailSize;
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java
new file mode 100644
index 0000000..c46b3bf
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.collect;
+
+import jdk.tools.jaotc.LogPrinter;
+import jdk.tools.jaotc.Main;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.*;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+public class ClassCollector {
+    private final Main.Options options;
+    private final LogPrinter log;
+
+    public ClassCollector(Main.Options options, LogPrinter log) {
+        this.options = options;
+        this.log = log;
+    }
+
+    /**
+     * Collect all class names passed by the user.
+     *
+     * @return array list of classes
+     */
+    public Set<Class<?>> collectClassesToCompile() {
+        Set<Class<?>> classes = new HashSet<>();
+        List<String> filesToScan = new LinkedList<>(options.files);
+
+        if (options.module != null) {
+            classes.addAll(scanModule(filesToScan));
+        }
+
+        classes.addAll(scanFiles(filesToScan));
+        return classes;
+    }
+
+    private Set<Class<?>> scanModule(List<String> filesToScan) {
+        String module = options.module;
+        // Search module in standard JDK installation.
+        Path dir = getModuleDirectory(options.modulepath, module);
+
+        if (Files.isDirectory(dir)) {
+            return loadFromModuleDirectory(dir);
+        } else {
+            findFilesToScan(filesToScan, module);
+            return new HashSet<>();
+        }
+    }
+
+    private Set<Class<?>> loadFromModuleDirectory(Path dir) {
+        log.printInfo("Scanning module: " + dir + " ...");
+        log.printlnVerbose(" "); // Break line
+
+        FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString()));
+        Set<Class<?>> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder);
+        log.printlnInfo(" " + cls.size() + " classes loaded.");
+        return cls;
+    }
+
+    private void findFilesToScan(List<String> filesToScan, String module) {
+        // Try to search regular directory, .jar or .class files
+        Path path = Paths.get(options.modulepath, module);
+
+        if (Files.isDirectory(path)) {
+            filesToScan.add(".");
+            options.classpath = path.toString();
+        } else if (path.endsWith(".jar") || path.endsWith(".class")) {
+            filesToScan.add(path.toString());
+        } else {
+            path = Paths.get(options.modulepath, module + ".jar");
+            if (Files.exists(path)) {
+                filesToScan.add(path.toString());
+            } else {
+                path = Paths.get(options.modulepath, module + ".class");
+                if (Files.exists(path)) {
+                    filesToScan.add(path.toString());
+                } else {
+                    throw new InternalError("Expecting a .class, .jar or directory: " + path);
+                }
+            }
+        }
+    }
+
+    private boolean entryIsClassFile(String entry) {
+        return entry.endsWith(".class") && !entry.endsWith("module-info.class");
+    }
+
+    private Set<Class<?>> scanFiles(List<String> filesToScan) {
+        Set<Class<?>> classes = new HashSet<>();
+        for (String fileName : filesToScan) {
+            Set<Class<?>> loaded = scanFile(fileName);
+            log.printlnInfo(" " + loaded.size() + " classes loaded.");
+            classes.addAll(loaded);
+        }
+        return classes;
+    }
+
+    interface ClassLoaderFactory {
+        ClassLoader create() throws IOException;
+    }
+
+    private Set<Class<?>> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) {
+        ClassLoader loader = null;
+        try {
+            loader = factory.create();
+            return loadClassFiles(root, finder, loader);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        } finally {
+            if (loader instanceof AutoCloseable) {
+                try {
+                    ((AutoCloseable) loader).close();
+                } catch (Exception e) {
+                    throw new InternalError(e);
+                }
+            }
+        }
+    }
+
+    private Set<Class<?>> scanFile(String fileName) {
+        log.printInfo("Scanning: " + fileName + " ...");
+        log.printlnVerbose(" "); // Break line
+
+        if (fileName.endsWith(".jar")) {
+            return loadFromJarFile(fileName);
+        } else if (fileName.endsWith(".class")) {
+            Set<Class<?>> classes = new HashSet<>();
+            loadFromClassFile(fileName, classes);
+            return classes;
+        } else {
+            return scanClassPath(fileName);
+        }
+    }
+
+    private Set<Class<?>> loadFromJarFile(String fileName) {
+        FileSystem fs = makeFileSystem(fileName);
+        FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString()));
+        return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder);
+    }
+
+    private void loadFromClassFile(String fileName, Set<Class<?>> classes) {
+        Class<?> result;
+        File file = new File(options.classpath);
+        try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
+            result = loadClassFile(loader, fileName);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+        Class<?> c = result;
+        addClass(classes, fileName, c);
+    }
+
+    private Set<Class<?>> scanClassPath(String fileName) {
+        Path classPath = Paths.get(options.classpath);
+        if (!Files.exists(classPath)) {
+            throw new InternalError("Path does not exist: " + classPath);
+        }
+        if (!Files.isDirectory(classPath)) {
+            throw new InternalError("Path must be a directory: " + classPath);
+        }
+
+        // Combine class path and file name and see what it is.
+        Path combinedPath = Paths.get(options.classpath + File.separator + fileName);
+        if (combinedPath.endsWith(".class")) {
+            throw new InternalError("unimplemented");
+        } else if (Files.isDirectory(combinedPath)) {
+            return scanDirectory(classPath, combinedPath);
+        } else {
+            throw new InternalError("Expecting a .class, .jar or directory: " + fileName);
+        }
+    }
+
+    private FileSystem makeFileSystem(String fileName) {
+        try {
+            return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>());
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private URI makeJarFileURI(String fileName) {
+        try {
+            return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/");
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private PathMatcher combine(PathMatcher m1, PathMatcher m2) {
+        return path -> m1.matches(path) && m2.matches(path);
+    }
+
+    private Set<Class<?>> scanDirectory(Path classPath, Path combinedPath) {
+        String dir = options.classpath;
+
+        FileSystem fileSystem = FileSystems.getDefault();
+        PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class");
+        FileSystemFinder finder = new FileSystemFinder(combinedPath,
+            combine(matcher, pathname -> entryIsClassFile(pathname.toString())));
+
+        File file = new File(dir);
+        try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
+            return loadClassFiles(classPath, finder, loader);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private Set<Class<?>> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) {
+        Set<Class<?>> classes = new HashSet<>();
+        for (Path name : finder.done()) {
+            // Now relativize to the class path so we get the actual class names.
+            String entry = root.relativize(name).normalize().toString();
+            Class<?> c = loadClassFile(loader, entry);
+            addClass(classes, entry, c);
+        }
+        return classes;
+    }
+
+    private void addClass(Set<Class<?>> classes, String name, Class<?> c) {
+        if (c != null) {
+            classes.add(c);
+            log.printlnVerbose(" loaded " + name);
+        }
+    }
+
+    private URL[] buildUrls(String fileName) throws MalformedURLException {
+        return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") };
+    }
+
+    private URL[] buildUrls(File file) throws MalformedURLException {
+        return new URL[] {file.toURI().toURL() };
+    }
+
+    private Path getModuleDirectory(String modulepath, String module) {
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        return fs.getPath(modulepath, module);
+    }
+
+    /**
+     * Loads a class with the given file name from the specified {@link URLClassLoader}.
+     */
+    private Class<?> loadClassFile(final ClassLoader loader, final String fileName) {
+        int start = 0;
+        if (fileName.startsWith("/")) {
+            start = 1;
+        }
+        String className = fileName.substring(start, fileName.length() - ".class".length());
+        className = className.replace('/', '.');
+        try {
+            return loader.loadClass(className);
+        } catch (Throwable e) {
+            // If we are running in JCK mode we ignore all exceptions.
+            if (options.ignoreClassLoadingErrors) {
+                log.printError(className + ": " + e);
+                return null;
+            }
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * {@link FileVisitor} implementation to find class files recursively.
+     */
+    private static class FileSystemFinder extends SimpleFileVisitor<Path> {
+        private final ArrayList<Path> fileNames = new ArrayList<>();
+        private final PathMatcher filter;
+
+        FileSystemFinder(Path combinedPath, PathMatcher filter) {
+            this.filter = filter;
+            try {
+                Files.walkFileTree(combinedPath, this);
+            } catch (IOException e) {
+                throw new InternalError(e);
+            }
+        }
+
+        /**
+         * Compares the glob pattern against the file name.
+         */
+        void find(Path file) {
+            Path name = file.getFileName();
+            if (name != null && filter.matches(name)) {
+                fileNames.add(file);
+            }
+        }
+
+        List<Path> done() {
+            return fileNames;
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+            find(file);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+            find(dir);
+            return CONTINUE;
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java
new file mode 100644
index 0000000..f1166a2
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NativeOrderOutputStream {
+    private final PatchableByteOutputStream os = new PatchableByteOutputStream();
+    private final byte[] backingArray = new byte[8];
+    private final ByteBuffer buffer;
+    private final List<Patchable> patches = new ArrayList<>();
+    private int size;
+
+    public NativeOrderOutputStream() {
+        buffer = ByteBuffer.wrap(backingArray);
+        buffer.order(ByteOrder.nativeOrder());
+    }
+
+    public static int alignUp(int value, int alignment) {
+        if (Integer.bitCount(alignment) != 1) {
+            throw new IllegalArgumentException("Must be a power of 2");
+        }
+
+        int aligned = (value + (alignment - 1)) & -alignment;
+
+        if (aligned < value || (aligned & (alignment - 1)) != 0) {
+            throw new RuntimeException("Error aligning: " + value + " -> " + aligned);
+        }
+        return aligned;
+    }
+
+    public NativeOrderOutputStream putLong(long value) {
+        fillLong(value);
+        os.write(backingArray, 0, 8);
+        size += 8;
+        return this;
+    }
+
+    public NativeOrderOutputStream putInt(int value) {
+        fillInt(value);
+        os.write(backingArray, 0, 4);
+        size += 4;
+        return this;
+    }
+
+    public NativeOrderOutputStream align(int alignment) {
+        int aligned = alignUp(position(), alignment);
+
+        int diff = aligned - position();
+        if (diff > 0) {
+            byte[] b = new byte[diff];
+            os.write(b, 0, b.length);
+            size += diff;
+        }
+
+        assert aligned == position();
+        return this;
+    }
+
+    public int position() {
+        return os.size();
+    }
+
+    private void fillInt(int value) {
+        buffer.putInt(0, value);
+    }
+
+    private void fillLong(long value) {
+        buffer.putLong(0, value);
+    }
+
+    private NativeOrderOutputStream putAt(byte[] data, int length, int position) {
+        os.writeAt(data, length, position);
+        return this;
+    }
+
+    public NativeOrderOutputStream put(byte[] data) {
+        os.write(data, 0, data.length);
+        size += data.length;
+        return this;
+    }
+
+    public byte[] array() {
+        checkPatches();
+        byte[] bytes = os.toByteArray();
+        assert size == bytes.length;
+        return bytes;
+    }
+
+    private void checkPatches() {
+        for (Patchable patch : patches) {
+            if (!patch.patched()) {
+                throw new RuntimeException("Not all patches patched, missing at offset: " + patch);
+            }
+        }
+    }
+
+    public PatchableInt patchableInt() {
+        int position = os.size();
+        PatchableInt patchableInt = new PatchableInt(position);
+        putInt(0);
+        patches.add(patchableInt);
+        return patchableInt;
+    }
+
+    public abstract class Patchable {
+        private final int position;
+        private boolean patched = false;
+
+        Patchable(int position) {
+            this.position = position;
+        }
+
+        protected boolean patched() {
+            return patched;
+        }
+
+        protected void patch(int length) {
+            putAt(backingArray, length, position);
+            patched = true;
+        }
+
+        public int position() {
+            return position;
+        }
+    }
+
+    public class PatchableInt extends Patchable {
+        private int value = 0;
+
+        public PatchableInt(int position) {
+            super(position);
+        }
+
+        public void set(int value) {
+            this.value = value;
+            fillInt(value);
+            patch(4);
+        }
+
+        public int value() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PatchableInt{");
+            sb.append("position=").append(super.position()).append(", ");
+            sb.append("patched=").append(patched()).append(", ");
+            sb.append("value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    private static class PatchableByteOutputStream extends ByteArrayOutputStream {
+
+        public void writeAt(byte[] data, int length, int position) {
+            long end = (long)position + (long)length;
+            if (buf.length < end) {
+                throw new IllegalArgumentException("Array not properly sized");
+            }
+            System.arraycopy(data, 0, buf, position, length);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java
new file mode 100644
index 0000000..627c4d3
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.utils;
+
+import jdk.tools.jaotc.Main;
+
+public class Timer implements AutoCloseable {
+
+    private final Main main;
+    private final long start;
+
+    public Timer(Main main, String message) {
+        this.main = main;
+        start = System.currentTimeMillis();
+        main.printInfo(message);
+    }
+
+    public void close() {
+        final long end = System.currentTimeMillis();
+        main.printlnInfo(" (" + (end - start) + " ms)");
+    }
+
+}
diff --git a/hotspot/src/jdk.aot/share/classes/module-info.java b/hotspot/src/jdk.aot/share/classes/module-info.java
new file mode 100644
index 0000000..3105d8b
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/module-info.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.aot {
+    requires jdk.management;
+    requires jdk.vm.ci;
+    requires jdk.vm.compiler;
+}
diff --git a/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c
new file mode 100644
index 0000000..d6d69cb
--- /dev/null
+++ b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jdk_tools_jaotc_jnilibelf_JNILibELFAPI.h"
+
+// For file open and close
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+// For libelf interfaces
+#include <libelf.h>
+#include <gelf.h>
+
+// Convenience macro to shut the compiler warnings
+#ifdef UNUSED
+#elif defined(__GNUC__)
+# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+# define UNUSED(x) /*@unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
+
+/**
+ * libelfshim version
+ */
+#ifndef AOT_VERSION_STRING
+  #error AOT_VERSION_STRING must be defined
+#endif
+
+JNIEXPORT jstring JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elfshim_1version
+(JNIEnv* env, jclass UNUSED(c))  {
+   const char* ver = AOT_VERSION_STRING;
+   return (*env)->NewStringUTF(env, ver);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1version
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint v)  {
+    return elf_version(v);
+}
+
+/**
+ * Unbox the Pointer object the encapsulated native address.
+ */
+
+static jlong getNativeAddress(JNIEnv* env, jobject ptrObj) {
+   jclass ptrClass;
+   jfieldID fidNumber;
+   jlong nativeAddress = -1;
+    assert (ptrObj != NULL);
+   // Get a reference to ptr object's class
+   ptrClass = (*env)->GetObjectClass(env, ptrObj);
+
+   // Get the Field ID of the instance variables "address"
+   fidNumber = (*env)->GetFieldID(env, ptrClass, "address", "J");
+   if (fidNumber != NULL) {
+       // Get the long given the Field ID
+       nativeAddress = (*env)->GetLongField(env, ptrObj, fidNumber);
+   }
+   // fprintf(stderr, "Native address : %lx\n", nativeAddress);
+   return nativeAddress;
+}
+
+/**
+ * Box the nativeAddress as a Pointer object.
+ */
+static jobject makePointerObject(JNIEnv* env, jlong nativeAddr) {
+   jclass ptrClass = (*env)->FindClass(env, "jdk/tools/jaotc/jnilibelf/Pointer");
+   // Call back constructor to allocate a Pointer object, with an int argument
+   jmethodID constructorId = (*env)->GetMethodID(env, ptrClass, "<init>", "(J)V");
+   jobject retObj = (*env)->NewObject(env, ptrClass, constructorId, nativeAddr);
+   return retObj;
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1begin
+(JNIEnv* env, jclass UNUSED(class), jint filedes, jint cmd, jobject ptrObj) {
+
+   Elf* elfPtr = NULL;
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((elfPtr = elf_begin(filedes, cmd, (Elf *) addr)) == NULL) {
+           errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_begin()\n");
+   }
+
+   return makePointerObject(env, (jlong) elfPtr);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1end
+(JNIEnv* env, jclass UNUSED(class), jobject ptrObj) {
+
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       return elf_end((Elf *) addr);
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_end()\n");
+       return -1;
+   }
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1kind
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) {
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       return elf_kind((Elf *) addr);
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_kind()\n");
+       return -1;
+   }
+}
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1flagphdr
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint cmd, jint flags) {
+
+   jlong addr = getNativeAddress(env, ptrObj);
+   unsigned int retVal = 0;
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((retVal = elf_flagphdr((Elf *) addr, cmd, flags)) == 0) {
+           errx(EX_SOFTWARE, "elf_flagphdr() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_flagphdr()\n");
+   }
+   return retVal;
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1newscn
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) {
+
+   Elf_Scn* elfSecPtr = NULL;
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((elfSecPtr = elf_newscn((Elf *) addr)) == NULL) {
+           errx(EX_SOFTWARE, "elf_newscn() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_newscn()\n");
+   }
+
+   return makePointerObject(env, (jlong) elfSecPtr);
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1newdata
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) {
+
+   Elf_Data* elfDataPtr = NULL;
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((elfDataPtr = elf_newdata((Elf_Scn *) addr)) == NULL) {
+           errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_newdata()\n");
+   }
+   return makePointerObject(env, (jlong) elfDataPtr);
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf64_1getshdr
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) {
+
+   Elf64_Shdr* elf64ShdrPtr = NULL;
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((elf64ShdrPtr = elf64_getshdr((Elf_Scn *) addr)) == NULL) {
+           errx(EX_SOFTWARE, "elf64_getshdr() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_getshdr()\n");
+   }
+   return makePointerObject(env, (jlong) elf64ShdrPtr);
+}
+
+JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1update
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint cmd) {
+
+   off_t size = -1;
+   jlong addr = getNativeAddress(env, ptrObj);
+
+   if (addr != -1) {
+       // Call libelf function
+       if ((size = elf_update((Elf*) addr, cmd)) == -1) {
+           errx(EX_SOFTWARE, "elf_update() failed: %s size (%d) cmd (%d).", elf_errmsg(-1), (int)size, cmd);
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_update()\n");
+   }
+   return size;
+}
+
+JNIEXPORT jstring JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1errmsg
+(JNIEnv* env, jclass UNUSED(c), jint errno) {
+
+   const char * retPtr = NULL;
+   // Call libelf function
+   if ((retPtr = elf_errmsg(errno)) == NULL) {
+       errx(EX_SOFTWARE, "elf_errmsg() failed: %s.", elf_errmsg(-1));
+   }
+   return (*env)->NewStringUTF(env, retPtr);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1ndxscn
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj) {
+   jint secnum = SHN_UNDEF;
+   jlong addr = getNativeAddress(env, ptrObj);
+   if (addr != -1) {
+       // Call libelf function
+       secnum = elf_ndxscn((Elf_Scn*) addr);
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_ndxscn()\n");
+   }
+   return secnum;
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_gelf_1newehdr
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint elfClass) {
+   unsigned long int retPtr = 0;
+   jlong addr = getNativeAddress(env, ptrObj);
+   if (addr != -1) {
+       // Call libelf function
+       if ((retPtr = gelf_newehdr((Elf*) addr, elfClass)) == 0) {
+           errx(EX_SOFTWARE, "gelf_newehdr() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_newehdr()\n");
+   }
+   return makePointerObject(env, (jlong) retPtr);
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_gelf_1newphdr
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint phnum) {
+   unsigned long int retPtr = 0;
+   jlong addr = getNativeAddress(env, ptrObj);
+   if (addr != -1) {
+       // Call libelf function
+       if ((retPtr = gelf_newphdr((Elf*) addr, phnum)) == 0) {
+           errx(EX_SOFTWARE, "gelf_newphdr() failed: %s.", elf_errmsg(-1));
+       }
+   } else {
+       fprintf(stderr, "Failed to get native address to call elf_newphdr()\n");
+   }
+   return makePointerObject(env, (jlong) retPtr);
+}
+
+
+/* File operations */
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open_1rw
+(JNIEnv * env, jclass UNUSED(class), jstring jfileName)  {
+    int flags = O_RDWR | O_CREAT | O_TRUNC;
+    int mode  = 0666;
+    int retVal;
+    const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL);
+    if (cfileName == NULL) {
+        return -1;
+    }
+    retVal = open(cfileName, flags, mode);
+    if (retVal < 0) {
+       err(EX_NOINPUT, "open %s failed", cfileName);
+    }
+    (*env)->ReleaseStringUTFChars(env, jfileName, cfileName);
+
+    return retVal;
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open__Ljava_lang_String_2I
+(JNIEnv * env, jclass UNUSED(class), jstring jfileName, jint flags)  {
+    int retVal;
+    const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL);
+    if (cfileName == NULL) {
+        return -1;
+    }
+    retVal = open(cfileName, flags);
+    if (retVal < 0) {
+       err(EX_NOINPUT, "open %s failed", cfileName);
+    }
+    (*env)->ReleaseStringUTFChars(env, jfileName, cfileName);
+
+    return retVal;
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_open__Ljava_lang_String_2II
+(JNIEnv * env, jclass UNUSED(class), jstring jfileName, jint flags, jint mode)  {
+    int retVal;
+    const char* cfileName = (*env)->GetStringUTFChars(env, jfileName, NULL);
+    if (cfileName == NULL) {
+        return -1;
+    }
+    retVal = open(cfileName, flags, mode);
+    if (retVal < 0) {
+       err(EX_NOINPUT, "open %s failed", cfileName);
+    }
+    (*env)->ReleaseStringUTFChars(env, jfileName, cfileName);
+
+    return retVal;
+}
+
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_close
+(JNIEnv* UNUSED(env), jclass UNUSED(class), jint fd) {
+    return close(fd);
+}
+
+/**
+ * Miscellaneous ELF data structure peek-poke functions in
+ * shim_functions.c. No corresponding .h file exists yet.
+ * So each function needs to be declared as extern
+ */
+
+extern int size_of_Sym(int elfclass);
+extern int size_of_Rel(int elfclass);
+extern int size_of_Rela(int elfclass);
+
+extern void ehdr_set_data_encoding(void * ehdr, int val);
+extern void set_Ehdr_e_machine(int elfclass, void * structPtr, int val);
+extern void set_Ehdr_e_type(int elfclass, void * structPtr, int val);
+extern void set_Ehdr_e_version(int elfclass, void * structPtr, int val);
+extern void set_Ehdr_e_shstrndx(int elfclass, void * structPtr, int val);
+
+extern void phdr_set_type_self(int elfclass, void * ehdr, void * phdr);
+extern void phdr_set_type_self(int elfclass, void * ehdr, void * phdr);
+
+extern void set_Shdr_sh_name(int elfclass, void* structPtr, int val);
+extern void set_Shdr_sh_type(int elfclass, void* structPtr, int val);
+extern void set_Shdr_sh_flags(int elfclass, void* structPtr, int val);
+extern void set_Shdr_sh_entsize(int elfclass, void* structPtr, int val);
+extern void set_Shdr_sh_link(int elfclass, void* structPtr, int val);
+extern void set_Shdr_sh_info(int elfclass, void* structPtr, int val);
+
+extern void set_Data_d_align(void* structPtr, int val);
+extern void set_Data_d_off(void* structPtr, int val);
+extern void set_Data_d_buf(void* structPtr, void* val);
+extern void set_Data_d_type(void* structPtr, int val);
+extern void set_Data_d_size(void* structPtr, int val);
+extern void set_Data_d_version(void* structPtr, int val);
+
+extern void* create_sym_entry(int elfclass, int index, int type, int bind,
+                               int shndx, int size, int value);
+extern void * create_reloc_entry(int elfclass, int roffset, int symtabIdx,
+                                 int relocType, int raddend, int reloca);
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Sym
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) {
+    return size_of_Sym(elfClass);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Rela
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) {
+    return size_of_Rela(elfClass);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_size_1of_1Rel
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass) {
+    return size_of_Rel(elfClass);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_ehdr_1set_1data_1encoding
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* ehdr = (void*) getNativeAddress(env, ptrObj);
+    ehdr_set_data_encoding(ehdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1machine
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* ehdr = (void*) getNativeAddress(env, ptrObj);
+    set_Ehdr_e_machine(elfClass, ehdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1type
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* ehdr = (void*) getNativeAddress(env, ptrObj);
+    set_Ehdr_e_type(elfClass, ehdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1version
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* ehdr = (void*) getNativeAddress(env, ptrObj);
+    set_Ehdr_e_version(elfClass, ehdr, val);
+}
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Ehdr_1e_1shstrndx
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Ehdr_e_shstrndx(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_phdr_1set_1type_1self
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ehdrPtr, jobject phdrPtr) {
+    void* ehdr = (void*) getNativeAddress(env, ehdrPtr);
+    void* phdr = (void*) getNativeAddress(env, phdrPtr);
+    phdr_set_type_self(elfClass, ehdr, phdr);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1name
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_name(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1type
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_type(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1flags
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_flags(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1entsize
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_entsize(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1info
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_info(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Shdr_1sh_1link
+(JNIEnv* env, jclass UNUSED(c), jint elfClass, jobject ptrObj, jint val) {
+    void* shdr = (void*) getNativeAddress(env, ptrObj);
+    set_Shdr_sh_link(elfClass, shdr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1align
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    set_Data_d_align(dptr, val);
+}
+
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1off
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    set_Data_d_off(dptr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1buf
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jobject bufPtr) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    void* bptr = (void*) getNativeAddress(env, bufPtr);
+    set_Data_d_buf(dptr, bptr);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1type
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    set_Data_d_type(dptr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1size
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    set_Data_d_size(dptr, val);
+}
+
+JNIEXPORT void JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_set_1Data_1d_1version
+(JNIEnv* env, jclass UNUSED(c), jobject ptrObj, jint val) {
+    void* dptr = (void*) getNativeAddress(env, ptrObj);
+    set_Data_d_version(dptr, val);
+}
+
+JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_create_1sym_1entry
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass, jint index, jint type,
+ jint bind, jint shndx, jint size, jint value) {
+   void * retVal = create_sym_entry(elfClass, index, type, bind,
+                                    shndx, size, value);
+   return (jlong)retVal;
+}
+
+JNIEXPORT jlong JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_create_1reloc_1entry
+(JNIEnv* UNUSED(env), jclass UNUSED(c), jint elfClass, jint roffset,
+ jint symTabIdx, jint relocType, jint raddend, jint reloca) {
+   void * retVal = create_reloc_entry(elfClass, roffset, symTabIdx,
+                                      relocType, raddend, reloca);
+   return (jlong)retVal;
+}
+
diff --git a/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c b/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c
new file mode 100644
index 0000000..e405b0d
--- /dev/null
+++ b/hotspot/src/jdk.aot/unix/native/libjelfshim/shim_functions.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <libelf.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * TODO: This is an intial and crude attempt to access structure
+ * fields of some ELF structrures. Need to figure out a way to access the
+ * given field of a given structure instead of writing one shim function
+ * per access of each of the structure field.
+ **/
+
+#define STRINGIFYHELPER(x) #x
+#define STRINGIFY(x) STRINGIFYHELPER(x)
+#define FUNC_NAME(S, F) set_ ## S ## _ ## F
+#define CAST_STRUCT(S, F) ((Elf_ ## S *) structPtr)
+#define CAST_STRUCT32(S, F) ((Elf32_ ## S *) structPtr)
+#define CAST_STRUCT64(S, F) ((Elf64_ ## S *) structPtr)
+#define ACCESS_FIELD(S, F) CAST_STRUCT(S, F)-> F
+#define ACCESS_FIELD32(S, F) CAST_STRUCT32(S, F)-> F
+#define ACCESS_FIELD64(S, F) CAST_STRUCT64(S, F)-> F
+
+/*
+   Example:
+   SET_TYPE_BASED_FIELD(Ehdr, e_machine, int)
+   expands to
+   set_Ehdr_e_machine(int elfclass, void * strPtr, int val) {
+}
+*/
+
+#define SET_TYPE_BASED_FIELD(S, F, T)                               \
+    void FUNC_NAME(S, F)(int elfclass, void * structPtr, T val) {   \
+       if (elfclass == ELFCLASS32)  {                               \
+           ACCESS_FIELD32(S, F) = val;                    \
+       } else if (elfclass == ELFCLASS64) {               \
+           ACCESS_FIELD64(S, F) = val;                    \
+       } else {                                           \
+           printf("%s: Unknown ELF Class %d provided\n", STRINGIFY(FUNC_NAME(S, F)), elfclass); \
+    }  \
+    return; \
+}
+
+/*
+   Example:
+   SET_FIELD(Ehdr, e_machine, int)
+   expands to
+   set_Ehdr_e_machine(void * strPtr, int val) {
+}
+*/
+
+#define SET_FIELD(S, F, T)                               \
+    void FUNC_NAME(S, F)(void * structPtr, T val) {      \
+       ACCESS_FIELD(S, F) = val;                         \
+       return; \
+}
+
+int size_of_Sym(int elfclass) {
+    if (elfclass == ELFCLASS32)  {
+        return sizeof(Elf32_Sym);
+    } else if (elfclass == ELFCLASS64) {
+        return sizeof(Elf64_Sym);
+    } else {
+        printf("Unknown ELF Class %d provided\n", elfclass);
+    }
+    return -1;
+}
+
+int size_of_Rela(int elfclass) {
+    if (elfclass == ELFCLASS32)  {
+        return sizeof(Elf32_Rela);
+    } else if (elfclass == ELFCLASS64) {
+        return sizeof(Elf64_Rela);
+    } else {
+        printf("Unknown ELF Class %d provided\n", elfclass);
+    }
+    return -1;
+}
+
+int size_of_Rel(int elfclass) {
+    if (elfclass == ELFCLASS32)  {
+        return sizeof(Elf32_Rel);
+    } else if (elfclass == ELFCLASS64) {
+        return sizeof(Elf64_Rel);
+    } else {
+        printf("Unknown ELF Class %d provided\n", elfclass);
+    }
+    return -1;
+}
+
+/* ELF Header field access */
+
+void ehdr_set_data_encoding(void * ehdr, int val)  {
+    ((Elf32_Ehdr *) ehdr)->e_ident[EI_DATA] = val;
+    return;
+}
+
+SET_TYPE_BASED_FIELD(Ehdr, e_machine, int)
+SET_TYPE_BASED_FIELD(Ehdr, e_type, int)
+SET_TYPE_BASED_FIELD(Ehdr, e_version, int)
+SET_TYPE_BASED_FIELD(Ehdr, e_shstrndx, int)
+
+/* Data descriptor field access */
+SET_FIELD(Data, d_align, int)
+SET_FIELD(Data, d_off, int)
+SET_FIELD(Data, d_buf, void*)
+SET_FIELD(Data, d_type, int)
+SET_FIELD(Data, d_size, int)
+SET_FIELD(Data, d_version, int)
+
+/* Section Header Access functions */
+SET_TYPE_BASED_FIELD(Shdr, sh_name, int)
+SET_TYPE_BASED_FIELD(Shdr, sh_type, int)
+SET_TYPE_BASED_FIELD(Shdr, sh_flags, int)
+SET_TYPE_BASED_FIELD(Shdr, sh_entsize, int)
+SET_TYPE_BASED_FIELD(Shdr, sh_link, int)
+SET_TYPE_BASED_FIELD(Shdr, sh_info, int)
+
+/* Set the Program Header to be of PH_PHDR type and initialize other
+   related fields of the program header.
+*/
+void phdr_set_type_self(int elfclass, void * ehdr, void * phdr)  {
+    if (elfclass == ELFCLASS32) {
+        Elf32_Ehdr * ehdr32 = (Elf32_Ehdr *) ehdr;
+        Elf32_Phdr * phdr32 = (Elf32_Phdr *) phdr;
+        phdr32->p_type = PT_PHDR;
+        phdr32->p_offset = ehdr32->e_phoff;
+        phdr32->p_filesz = elf32_fsize(ELF_T_PHDR, 1, EV_CURRENT);
+    } else if (elfclass == ELFCLASS64) {
+        Elf64_Ehdr * ehdr64 = (Elf64_Ehdr *) ehdr;
+        Elf64_Phdr * phdr64 = (Elf64_Phdr *) phdr;
+        phdr64->p_type = PT_PHDR;
+        phdr64->p_offset = ehdr64->e_phoff;
+        phdr64->p_filesz = elf64_fsize(ELF_T_PHDR, 1, EV_CURRENT);
+    } else {
+        printf("phdr_set_type_self: Unknown ELF Class %d provided\n", elfclass);
+    }
+    return;
+}
+
+/*
+  Create symbol table entry with given type and binding
+*/
+void * create_sym_entry(int elfclass, int index, int type, int bind,
+                        int shndx, int size, int value) {
+  void * symentry = NULL;
+    if (elfclass == ELFCLASS32) {
+      Elf32_Sym * sym32 = (Elf32_Sym *) malloc(sizeof(Elf32_Sym));
+      sym32->st_name = index;
+      sym32->st_value = value;
+      sym32->st_size = size;
+      sym32->st_info = ELF32_ST_INFO(bind, type);
+      sym32->st_other = 0;  // TODO: Add an argument to get this value ??
+      sym32->st_shndx = shndx;
+      symentry = sym32;
+    } else if (elfclass == ELFCLASS64) {
+      Elf64_Sym * sym64 = (Elf64_Sym *) malloc(sizeof(Elf64_Sym));
+      sym64->st_name = index;
+      sym64->st_value = value;
+      sym64->st_size = size;
+      sym64->st_info = ELF64_ST_INFO(bind, type);
+      sym64->st_other = 0;  // TODO: Add an argument to get this value ??
+      sym64->st_shndx = shndx;
+      symentry = sym64;
+    } else {
+        printf("create_sym_entry: Unknown ELF Class %d provided\n", elfclass);
+    }
+    return (void *) symentry;
+}
+
+// Create a reloc (or reloca entry if argument reloca is non-zero)
+void * create_reloc_entry(int elfclass, int roffset, int symtabIdx,
+                          int relocType, int raddend, int reloca) {
+  void * relocentry = NULL;
+  if (elfclass == ELFCLASS32) {
+    if (reloca) {
+      Elf32_Rela * rela32 = (Elf32_Rela *) malloc(sizeof(Elf32_Rela));
+      rela32->r_offset = roffset;
+      rela32->r_info = ELF32_R_INFO(symtabIdx, relocType);
+      rela32->r_addend = raddend;
+      relocentry = rela32;
+    } else {
+      Elf32_Rel * rel32 = (Elf32_Rel *) malloc(sizeof(Elf32_Rel));
+      rel32->r_offset = roffset;
+      rel32->r_info = ELF32_R_INFO(symtabIdx, relocType);
+      relocentry = rel32;
+    }
+  } else if (elfclass == ELFCLASS64) {
+    if (reloca) {
+      Elf64_Rela * rela64 = (Elf64_Rela *) malloc(sizeof(Elf64_Rela));
+      rela64->r_offset = roffset;
+      rela64->r_info = ELF64_R_INFO(symtabIdx, relocType);
+      rela64->r_addend = raddend;
+      relocentry = rela64;
+    } else {
+      Elf64_Rel * rel64 = (Elf64_Rel *) malloc(sizeof(Elf64_Rel));
+      rel64->r_offset = roffset;
+      rel64->r_info = ELF64_R_INFO(symtabIdx, relocType);
+      relocentry = rel64;
+    }
+  } else {
+    printf("create_reloc_entry: Unknown ELF Class %d provided\n", elfclass);
+  }
+  return (void *) relocentry;
+}
diff --git a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h
index 007ea53..0214a16 100644
--- a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h
+++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h
@@ -72,9 +72,12 @@
 #include <asm/ptrace.h>
 #define user_regs_struct  pt_regs
 #endif
-#if defined(aarch64)
+#if defined(aarch64) || defined(arm64)
 #include <asm/ptrace.h>
 #define user_regs_struct user_pt_regs
+#elif defined(arm)
+#include <asm/ptrace.h>
+#define user_regs_struct  pt_regs
 #endif
 #if defined(s390x)
 #include <asm/ptrace.h>
diff --git a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
index 1c96cf3..45299fd 100644
--- a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
+++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
@@ -387,8 +387,8 @@
 
     if (shdr->sh_type == sym_section) {
       ELF_SYM  *syms;
-      int j, n, rslt;
-      size_t size;
+      int rslt;
+      size_t size, n, j, htab_sz;
 
       // FIXME: there could be multiple data buffers associated with the
       // same ELF section. Here we can handle only one buffer. See man page
@@ -407,6 +407,15 @@
 
       // create hash table, we use hcreate_r, hsearch_r and hdestroy_r to
       // manipulate the hash table.
+
+      // NOTES section in the man page of hcreate_r says
+      // "Hash table implementations are usually more efficient when
+      // the table contains enough free space to minimize collisions.
+      // Typically, this means that nel should be at least 25% larger
+      // than the maximum number of elements that the caller expects
+      // to store in the table."
+      htab_sz = n*1.25;
+
       symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data));
       rslt = hcreate_r(n, symtab->hash_table);
       // guarantee(rslt, "unexpected failure: hcreate_r");
@@ -452,7 +461,6 @@
         symtab->symbols[j].offset = sym_value - baseaddr;
         item.key = sym_name;
         item.data = (void *)&(symtab->symbols[j]);
-
         hsearch_r(item, ENTER, &ret, symtab->hash_table);
       }
     }
diff --git a/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
index 6e4c65e..b4dacf6 100644
--- a/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
+++ b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -697,14 +697,8 @@
 }
 
 /**local function **/
-bool exists(const char *fname)
-{
-  int fd;
-  if ((fd = open(fname, O_RDONLY)) > 0) {
-    close(fd);
-    return true;
-  }
-  return false;
+bool exists(const char *fname) {
+  return access(fname, F_OK) == 0;
 }
 
 // we check: 1. lib
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java
index 916cb44..ec8b0ac 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java
@@ -1957,7 +1957,7 @@
         if (doit == null) {
             out.println("Unrecognized command.  Try help...");
         } else if (!debugger.isAttached() && !doit.okIfDisconnected) {
-            out.println("Command not valid until the attached to a VM");
+            out.println("Command not valid until attached to a VM");
         } else {
             try {
                 doit.doit(args);
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
index 6b3455b..4a70944 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1474,7 +1474,7 @@
                   return attached;
               }
               public void attach(String pid) {
-                  attach(pid);
+                  HSDB.this.attach(pid);
               }
               public void attach(String java, String core) {
               }
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java
index 19eae4e..4c40054 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java
@@ -102,4 +102,17 @@
     }
     return null;
   }
+
+  public boolean contains(Klass c, Oop classLoader) {
+    long hash = computeHash(c.getName(), classLoader);
+    int index = hashToIndex(hash);
+
+    for (DictionaryEntry entry = (DictionaryEntry) bucket(index); entry != null;
+                                    entry = (DictionaryEntry) entry.next()) {
+      if (entry.literalValue().equals(c.getAddress())) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index 99dbadf..742ec9a 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -29,6 +29,7 @@
 import sun.jvm.hotspot.classfile.ClassLoaderData;
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.memory.Dictionary;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.types.*;
 import sun.jvm.hotspot.utilities.*;
@@ -64,6 +65,21 @@
   private static int CLASS_STATE_FULLY_INITIALIZED;
   private static int CLASS_STATE_INITIALIZATION_ERROR;
 
+  // _misc_flags constants
+  private static int MISC_REWRITTEN;
+  private static int MISC_HAS_NONSTATIC_FIELDS;
+  private static int MISC_SHOULD_VERIFY_CLASS;
+  private static int MISC_IS_ANONYMOUS;
+  private static int MISC_IS_CONTENDED;
+  private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS;
+  private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS;
+  private static int MISC_HAS_BEEN_REDEFINED;
+  private static int MISC_HAS_PASSED_FINGERPRINT_CHECK;
+  private static int MISC_IS_SCRATCH_CLASS;
+  private static int MISC_IS_SHARED_BOOT_CLASS;
+  private static int MISC_IS_SHARED_PLATFORM_CLASS;
+  private static int MISC_IS_SHARED_APP_CLASS;
+
   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
     Type type            = db.lookupType("InstanceKlass");
     arrayKlasses         = new MetadataField(type.getAddressField("_array_klasses"), 0);
@@ -90,6 +106,7 @@
       breakpoints        = type.getAddressField("_breakpoints");
     }
     genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
+    miscFlags            = new CIntField(type.getCIntegerField("_misc_flags"), 0);
     majorVersion         = new CIntField(type.getCIntegerField("_major_version"), 0);
     minorVersion         = new CIntField(type.getCIntegerField("_minor_version"), 0);
     headerSize           = type.getSize();
@@ -114,6 +131,19 @@
     CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue();
     CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue();
 
+    MISC_REWRITTEN                    = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue();
+    MISC_HAS_NONSTATIC_FIELDS         = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue();
+    MISC_SHOULD_VERIFY_CLASS          = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue();
+    MISC_IS_ANONYMOUS                 = db.lookupIntConstant("InstanceKlass::_misc_is_anonymous").intValue();
+    MISC_IS_CONTENDED                 = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue();
+    MISC_HAS_NONSTATIC_CONCRETE_METHODS      = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue();
+    MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue();
+    MISC_HAS_BEEN_REDEFINED           = db.lookupIntConstant("InstanceKlass::_misc_has_been_redefined").intValue();
+    MISC_HAS_PASSED_FINGERPRINT_CHECK = db.lookupIntConstant("InstanceKlass::_misc_has_passed_fingerprint_check").intValue();
+    MISC_IS_SCRATCH_CLASS             = db.lookupIntConstant("InstanceKlass::_misc_is_scratch_class").intValue();
+    MISC_IS_SHARED_BOOT_CLASS         = db.lookupIntConstant("InstanceKlass::_misc_is_shared_boot_class").intValue();
+    MISC_IS_SHARED_PLATFORM_CLASS     = db.lookupIntConstant("InstanceKlass::_misc_is_shared_platform_class").intValue();
+    MISC_IS_SHARED_APP_CLASS          = db.lookupIntConstant("InstanceKlass::_misc_is_shared_app_class").intValue();
   }
 
   public InstanceKlass(Address addr) {
@@ -149,6 +179,7 @@
   private static CIntField itableLen;
   private static AddressField breakpoints;
   private static CIntField genericSignatureIndex;
+  private static CIntField miscFlags;
   private static CIntField majorVersion;
   private static CIntField minorVersion;
 
@@ -243,7 +274,7 @@
     return getSizeHelper() * VM.getVM().getAddressSize();
   }
 
-  public long getSize() {
+  public long getSize() { // in number of bytes
     long wordLength = VM.getVM().getBytesPerWord();
     long size = getHeaderSize() +
                 (getVtableLen() +
@@ -252,9 +283,59 @@
     if (isInterface()) {
       size += wordLength;
     }
+    if (isAnonymous()) {
+      size += wordLength;
+    }
+    if (hasStoredFingerprint()) {
+      size += 8; // uint64_t
+    }
     return alignSize(size);
   }
 
+  private int getMiscFlags() {
+    return (int) miscFlags.getValue(this);
+  }
+
+  public boolean isAnonymous() {
+    return (getMiscFlags() & MISC_IS_ANONYMOUS) != 0;
+  }
+
+  public static boolean shouldStoreFingerprint() {
+    VM vm = VM.getVM();
+    if (vm.getCommandLineBooleanFlag("EnableJVMCI") && !vm.getCommandLineBooleanFlag("UseJVMCICompiler")) {
+      return true;
+    }
+    if (vm.getCommandLineBooleanFlag("DumpSharedSpaces")) {
+      return true;
+    }
+    return false;
+  }
+
+  public boolean hasStoredFingerprint() {
+    return shouldStoreFingerprint() || isShared();
+  }
+
+  public boolean isShared() {
+    VM vm = VM.getVM();
+    if (vm.isSharingEnabled()) {
+      // This is not the same implementation as the C++ function MetaspaceObj::is_shared()
+      //     bool MetaspaceObj::is_shared() const {
+      //       return MetaspaceShared::is_in_shared_space(this);
+      //     }
+      // However, MetaspaceShared::is_in_shared_space is complicated and hard to emulate in
+      // Java code, so let's do this by looking up from the shared dictionary. Of course,
+      // this works for shared InstanceKlass only and does not work for other types of
+      // MetaspaceObj in the CDS shared archive.
+      Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary();
+      if (sharedDictionary != null) {
+        if (sharedDictionary.contains(this, null)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   public static long getHeaderSize() { return headerSize; }
 
   public short getFieldAccessFlags(int index) {
@@ -975,7 +1056,7 @@
     while (l <= h) {
       int mid = (l + h) >> 1;
       Method m = methods.at(mid);
-      int res = m.getName().fastCompare(name);
+      long res = m.getName().fastCompare(name);
       if (res == 0) {
         // found matching name; do linear search to find matching signature
         // first, quick check for common case
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java
index 89502c4..2a32164 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -139,8 +139,8 @@
       time-invariant order Since Symbol* are in C_HEAP, their
       relative order in memory never changes, so use address
       comparison for speed. */
-  public int fastCompare(Symbol other) {
-    return (int) addr.minus(other.addr);
+  public long fastCompare(Symbol other) {
+    return addr.minus(other.addr);
   }
 
   private static String readModifiedUTF8(byte[] buf) throws IOException {
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java
index b0cc278..f2c7abf 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,7 @@
     if (!swap)
       return x;
 
-    return (swapShort((short) x) << 16) | (swapShort((short) (x >> 16)) & 0xFFFF);
+    return ((int)swapShort((short) x) << 16) | (swapShort((short) (x >> 16)) & 0xFFFF);
   }
 
   /** Should only swap if the hardware's underlying byte order is
@@ -60,6 +60,6 @@
     if (!swap)
       return x;
 
-    return (swapInt((int) x) << 32) | (swapInt((int) (x >> 32)) & 0xFFFFFFFF);
+    return ((long)swapInt((int) x) << 32) | (swapInt((int) (x >> 32)) & 0xFFFFFFFF);
   }
 }
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
index a69b3ce..22bdcf9 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
@@ -861,6 +861,12 @@
       return (flag == null) ? false: flag.getBool();
   }
 
+  public boolean getCommandLineBooleanFlag(String name) {
+    Flag flag = getCommandLineFlag(name);
+    return (flag == null) ? Boolean.FALSE:
+      (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
+  }
+
   // returns null, if not available.
   public Flag[] getCommandLineFlags() {
     if (commandLineFlags == null) {
diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java
index 52e0412..87e6688 100644
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -177,14 +177,14 @@
                         JSJavaObject k = jk.getJSJavaClass();
                         JSJavaObject l = factory.newJSJavaObject(loader);
                         if (k != null) {
-                         if (k != null) {
-                       try {
-                               finalFunc.call(new Object[] { k, l });
-                       } catch (ScriptException exp) {
-                         throw new RuntimeException(exp);
+                          if (l != null) {
+                            try {
+                              finalFunc.call(new Object[] { k, l });
+                            } catch (ScriptException exp) {
+                              throw new RuntimeException(exp);
+                            }
+                          }
                        }
-                           }
-                        }
                     }
                 });
 
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java
index a21f084..8bfdb50 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java
@@ -84,6 +84,10 @@
 
     public static final Register lr = r30;
 
+    // Used by runtime code: cannot be compiler-allocated.
+    public static final Register rscratch1 = r8;
+    public static final Register rscratch2 = r9;
+
     // @formatter:off
     public static final RegisterArray cpuRegisters = new RegisterArray(
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java
index 0638d13..da5a6a0 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java
@@ -40,7 +40,7 @@
 
     private final BytecodePosition bytecodePosition;
     private ReferenceMap referenceMap;
-    @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping;
+    private final VirtualObject[] virtualObjectMapping;
     private RegisterSaveLayout calleeSaveInfo;
 
     /**
@@ -102,6 +102,10 @@
         return referenceMap;
     }
 
+    public VirtualObject[] getVirtualObjectMapping() {
+        return virtualObjectMapping;
+    }
+
     /**
      * Sets the map from the registers (in the caller's frame) to the slots where they are saved in
      * the current frame.
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java
index 24f4e02..bb02b53 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java
@@ -25,18 +25,19 @@
 import static jdk.vm.ci.aarch64.AArch64.lr;
 import static jdk.vm.ci.aarch64.AArch64.r0;
 import static jdk.vm.ci.aarch64.AArch64.r1;
-import static jdk.vm.ci.aarch64.AArch64.r12;
 import static jdk.vm.ci.aarch64.AArch64.r2;
-import static jdk.vm.ci.aarch64.AArch64.r27;
-import static jdk.vm.ci.aarch64.AArch64.r28;
-import static jdk.vm.ci.aarch64.AArch64.r29;
 import static jdk.vm.ci.aarch64.AArch64.r3;
-import static jdk.vm.ci.aarch64.AArch64.r31;
 import static jdk.vm.ci.aarch64.AArch64.r4;
 import static jdk.vm.ci.aarch64.AArch64.r5;
 import static jdk.vm.ci.aarch64.AArch64.r6;
 import static jdk.vm.ci.aarch64.AArch64.r7;
-import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.rscratch1;
+import static jdk.vm.ci.aarch64.AArch64.rscratch2;
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.aarch64.AArch64.r27;
+import static jdk.vm.ci.aarch64.AArch64.r28;
+import static jdk.vm.ci.aarch64.AArch64.r29;
+import static jdk.vm.ci.aarch64.AArch64.r31;
 import static jdk.vm.ci.aarch64.AArch64.sp;
 import static jdk.vm.ci.aarch64.AArch64.v0;
 import static jdk.vm.ci.aarch64.AArch64.v1;
@@ -114,7 +115,7 @@
     private final RegisterArray nativeGeneralParameterRegisters = new RegisterArray(r0, r1, r2, r3, r4, r5, r6, r7);
     private final RegisterArray simdParameterRegisters = new RegisterArray(v0, v1, v2, v3, v4, v5, v6, v7);
 
-    public static final Register inlineCacheRegister = r9;
+    public static final Register inlineCacheRegister = rscratch2;
 
     /**
      * Vtable stubs expect the metaspace Method in r12.
@@ -125,7 +126,8 @@
     public static final Register threadRegister = r28;
     public static final Register fp = r29;
 
-    private static final RegisterArray reservedRegisters = new RegisterArray(threadRegister, fp, lr, r31, zr, sp);
+    private static final RegisterArray reservedRegisters
+        = new RegisterArray(rscratch1, rscratch2, threadRegister, fp, lr, r31, zr, sp);
 
     private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         RegisterArray allRegisters = arch.getAvailableValueRegisters();
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
index 1be9c65..f92f91b 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
@@ -333,7 +333,7 @@
      *         {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}.
      * @throws JVMCIError if there is something wrong with the compiled code or the metadata
      */
-    public native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData);
+    native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData);
 
     /**
      * Resets all compilation statistics.
@@ -605,6 +605,14 @@
     native int methodDataProfileDataSize(long metaspaceMethodData, int position);
 
     /**
+     * Gets the fingerprint for a given Klass*
+     *
+     * @param metaspaceKlass
+     * @return the value of the fingerprint (zero for arrays and synthetic classes).
+     */
+    native long getFingerprint(long metaspaceKlass);
+
+    /**
      * Return the amount of native stack required for the interpreter frames represented by
      * {@code frame}. This is used when emitting the stack banging code to ensure that there is
      * enough space for the frames during deoptimization.
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
index 95c4b44..f6c97ec 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
@@ -96,7 +96,8 @@
         TraceMethodDataFilter(String.class, null,
                         "Enables tracing of profiling info when read by JVMCI.",
                         "Empty value: trace all methods",
-                        "Non-empty value: trace methods whose fully qualified name contains the value.");
+                        "Non-empty value: trace methods whose fully qualified name contains the value."),
+        UseProfilingInformation(Boolean.class, true, "");
         // @formatter:on
 
         /**
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java
index 300e57b..5bd5014 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java
@@ -22,38 +22,51 @@
  */
 package jdk.vm.ci.hotspot;
 
-/**
- * Encapsulates the VM metadata generated by {@link CompilerToVM#getMetadata}.
- */
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
+
+import jdk.vm.ci.code.TargetDescription;
+
 public class HotSpotMetaData {
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] pcDescBytes;
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] scopesDescBytes;
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] relocBytes;
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] exceptionBytes;
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] oopMaps;
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private String[] metadata;
+    private byte[] pcDescBytes;
+    private byte[] scopesDescBytes;
+    private byte[] relocBytes;
+    private byte[] exceptionBytes;
+    private byte[] oopMaps;
+    private String[] metadata;
+
+    public HotSpotMetaData(TargetDescription target, HotSpotCompiledCode compiledMethod) {
+        // Assign the fields default values...
+        pcDescBytes = new byte[0];
+        scopesDescBytes = new byte[0];
+        relocBytes = new byte[0];
+        exceptionBytes = new byte[0];
+        oopMaps = new byte[0];
+        metadata = new String[0];
+        // ...some of them will be overwritten by the VM:
+        runtime().getCompilerToVM().getMetadata(target, compiledMethod, this);
+    }
 
     public byte[] pcDescBytes() {
-        return pcDescBytes != null ? pcDescBytes : new byte[0];
+        return pcDescBytes;
     }
 
     public byte[] scopesDescBytes() {
-        return scopesDescBytes != null ? scopesDescBytes : new byte[0];
+        return scopesDescBytes;
     }
 
     public byte[] relocBytes() {
-        return relocBytes != null ? relocBytes : new byte[0];
+        return relocBytes;
     }
 
     public byte[] exceptionBytes() {
-        return exceptionBytes != null ? exceptionBytes : new byte[0];
+        return exceptionBytes;
     }
 
     public byte[] oopMaps() {
-        return oopMaps != null ? oopMaps : new byte[0];
+        return oopMaps;
     }
 
     public String[] metadataEntries() {
-        return metadata != null ? metadata : new String[0];
+        return metadata;
     }
 }
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
index eaace1b..ad4c67d 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
@@ -430,7 +430,7 @@
     public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
         ProfilingInfo info;
 
-        if (methodData == null) {
+        if (Option.UseProfilingInformation.getBoolean() && methodData == null) {
             long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData, this);
@@ -472,7 +472,8 @@
         Parameter[] res = new Parameter[javaParameters.length];
         for (int i = 0; i < res.length; i++) {
             java.lang.reflect.Parameter src = javaParameters[i];
-            res[i] = new Parameter(src.getName(), src.getModifiers(), this, i);
+            String paramName = src.isNamePresent() ? src.getName() : null;
+            res[i] = new Parameter(paramName, src.getModifiers(), this, i);
         }
         return res;
     }
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java
index 4ee2991..9028194 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java
@@ -103,6 +103,8 @@
 
     int layoutHelper();
 
+    long getFingerprint();
+
     HotSpotResolvedObjectType getEnclosingType();
 
     ResolvedJavaMethod getClassInitializer();
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java
index a7af6a6..a0a3bc7 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java
@@ -478,6 +478,11 @@
         return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset);
     }
 
+    @Override
+    public long getFingerprint() {
+        return compilerToVM().getFingerprint(getMetaspaceKlass());
+    }
+
     synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) {
         HotSpotResolvedJavaMethodImpl method = null;
         if (methodCache == null) {
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
index 545b44b..6d13d91 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
@@ -177,7 +177,7 @@
     /**
      * A {@code Parameter} provides information about method parameters.
      */
-    public static class Parameter implements AnnotatedElement {
+    class Parameter implements AnnotatedElement {
         private final String name;
         private final ResolvedJavaMethod method;
         private final int modifiers;
@@ -186,7 +186,9 @@
         /**
          * Constructor for {@code Parameter}.
          *
-         * @param name the name of the parameter
+         * @param name the name of the parameter or {@code null} if there is no
+         *            {@literal MethodParameters} class file attribute providing a non-empty name
+         *            for the parameter
          * @param modifiers the modifier flags for the parameter
          * @param method the method which defines this parameter
          * @param index the index of the parameter
@@ -195,6 +197,7 @@
                         int modifiers,
                         ResolvedJavaMethod method,
                         int index) {
+            assert name == null || !name.isEmpty();
             this.name = name;
             this.modifiers = modifiers;
             this.method = method;
@@ -202,10 +205,20 @@
         }
 
         /**
-         * Gets the name of the parameter.
+         * Gets the name of the parameter. If the parameter's name is {@linkplain #isNamePresent()
+         * present}, then this method returns the name provided by the class file. Otherwise, this
+         * method synthesizes a name of the form argN, where N is the index of the parameter in the
+         * descriptor of the method which declares the parameter.
+         *
+         * @return the name of the parameter, either provided by the class file or synthesized if
+         *         the class file does not provide a name
          */
         public String getName() {
-            return name;
+            if (name == null) {
+                return "arg" + index;
+            } else {
+                return name;
+            }
         }
 
         /**
@@ -216,7 +229,7 @@
         }
 
         /**
-         * Get the modifier flags for the parameter
+         * Get the modifier flags for the parameter.
          */
         public int getModifiers() {
             return modifiers;
@@ -244,6 +257,16 @@
         }
 
         /**
+         * Determines if the parameter has a name according to a {@literal MethodParameters} class
+         * file attribute.
+         *
+         * @return true if and only if the parameter has a name according to the class file.
+         */
+        public boolean isNamePresent() {
+            return name != null;
+        }
+
+        /**
          * Determines if the parameter represents a variable argument list.
          */
         public boolean isVarArgs() {
diff --git a/hotspot/src/jdk.vm.ci/share/classes/module-info.java b/hotspot/src/jdk.vm.ci/share/classes/module-info.java
index e62eed3..744442b 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/module-info.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/module-info.java
@@ -33,4 +33,37 @@
         jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory,
         jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory,
         jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory;
+
+    exports jdk.vm.ci.aarch64 to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.amd64 to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.code to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.code.site to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.code.stack to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.common to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.hotspot to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.hotspot.aarch64 to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.hotspot.amd64 to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.hotspot.sparc to
+        jdk.vm.compiler;
+    exports jdk.vm.ci.meta to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.runtime to
+        jdk.aot,
+        jdk.vm.compiler;
+    exports jdk.vm.ci.sparc to
+        jdk.vm.compiler;
 }
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/.project b/hotspot/src/jdk.vm.compiler/.mx.graal/.project
new file mode 100644
index 0000000..b0404db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/.project
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mx.graal</name>
+	<comment></comment>
+	<projects>
+		<project>mx</project>
+		<project>mx.jvmci</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject b/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject
new file mode 100644
index 0000000..c2a81b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/.pydevproject
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/mx.graal</path>
+<path>/mx.graal</path>
+<path>/mx.graal</path>
+</pydev_pathproperty>
+
+</pydev_project>
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs b/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1c652f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/eclipse-settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1 @@
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py
new file mode 100644
index 0000000..906d8e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal.py
@@ -0,0 +1,33 @@
+#
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# ----------------------------------------------------------------------------------------------------
+
+import mx
+if mx.get_jdk(tag='default').javaCompliance < "1.9":
+    mx.abort('JAVA_HOME is not a JDK9: ' + mx.get_jdk(tag='default').home)
+
+from mx_graal_9 import mx_post_parse_cmd_line, run_vm, get_vm, isJVMCIEnabled # pylint: disable=unused-import
+
+import mx_graal_bench # pylint: disable=unused-import
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py
new file mode 100644
index 0000000..2d93ed0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_9.py
@@ -0,0 +1,436 @@
+#
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# ----------------------------------------------------------------------------------------------------
+
+import os
+from os.path import join, dirname, basename, exists, abspath
+from argparse import ArgumentParser
+import sanitycheck
+import re
+
+import mx
+from mx_gate import Task
+from sanitycheck import _noneAsEmptyList
+
+from mx_unittest import unittest
+from mx_graal_bench import dacapo
+import mx_gate
+import mx_unittest
+
+_suite = mx.suite('graal')
+
+_jdk = mx.get_jdk(tag='default')
+assert _jdk.javaCompliance >= "1.9"
+
+def isJVMCIEnabled(vm):
+    return True
+
+_jvmciModes = {
+    'hosted' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'],
+    'jit' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI', '-XX:+UseJVMCICompiler'],
+    'disabled' : []
+}
+
+def get_vm():
+    """
+    Gets the name of the currently selected JVM variant.
+    """
+    return 'server'
+
+class JVMCIMode:
+    """
+    A context manager for setting the current JVMCI mode.
+    """
+    def __init__(self, jvmciMode=None):
+        self.update(jvmciMode)
+
+    def update(self, jvmciMode=None):
+        assert jvmciMode is None or jvmciMode in _jvmciModes, jvmciMode
+        self.jvmciMode = jvmciMode or _vm.jvmciMode
+
+    def __enter__(self):
+        global _vm
+        self.previousVm = _vm
+        _vm = self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        global _vm
+        _vm = self.previousVm
+
+_vm = JVMCIMode(jvmciMode='jit')
+
+class BootClasspathDist(object):
+    """
+    Extra info for a Distribution that must be put onto the boot class path.
+    """
+    def __init__(self, name):
+        self._name = name
+
+    def dist(self):
+        return mx.distribution(self._name)
+
+    def get_classpath_repr(self):
+        return self.dist().classpath_repr()
+
+_compilers = ['graal-economy', 'graal']
+_bootClasspathDists = [
+    BootClasspathDist('GRAAL'),
+]
+
+def add_compiler(compilerName):
+    _compilers.append(compilerName)
+
+def add_boot_classpath_dist(dist):
+    _bootClasspathDists.append(dist)
+
+mx_gate.add_jacoco_includes(['org.graalvm.compiler.*'])
+mx_gate.add_jacoco_excluded_annotations(['@Snippet', '@ClassSubstitution'])
+
+# This is different than the 'jmh' commmand in that it
+# looks for internal JMH benchmarks (i.e. those that
+# depend on the JMH library).
+def microbench(args):
+    """run JMH microbenchmark projects"""
+    parser = ArgumentParser(prog='mx microbench', description=microbench.__doc__,
+                            usage="%(prog)s [command options|VM options] [-- [JMH options]]")
+    parser.add_argument('--jar', help='Explicitly specify micro-benchmark location')
+    known_args, args = parser.parse_known_args(args)
+
+    vmArgs, jmhArgs = mx.extract_VM_args(args, useDoubleDash=True)
+
+    # look for -f in JMH arguments
+    forking = True
+    for i in range(len(jmhArgs)):
+        arg = jmhArgs[i]
+        if arg.startswith('-f'):
+            if arg == '-f' and (i+1) < len(jmhArgs):
+                arg += jmhArgs[i+1]
+            try:
+                if int(arg[2:]) == 0:
+                    forking = False
+            except ValueError:
+                pass
+
+    if known_args.jar:
+        # use the specified jar
+        args = ['-jar', known_args.jar]
+        if not forking:
+            args += vmArgs
+    else:
+        # find all projects with a direct JMH dependency
+        jmhProjects = []
+        for p in mx.projects_opt_limit_to_suites():
+            if 'JMH' in [x.name for x in p.deps]:
+                jmhProjects.append(p.name)
+        cp = mx.classpath(jmhProjects)
+
+        # execute JMH runner
+        args = ['-cp', cp]
+        if not forking:
+            args += vmArgs
+        args += ['org.openjdk.jmh.Main']
+
+    if forking:
+        jvm = get_vm()
+        def quoteSpace(s):
+            if " " in s:
+                return '"' + s + '"'
+            return s
+
+        forkedVmArgs = map(quoteSpace, _parseVmArgs(_jdk, vmArgs))
+        args += ['--jvmArgsPrepend', ' '.join(['-' + jvm] + forkedVmArgs)]
+    run_vm(args + jmhArgs)
+
+def ctw(args, extraVMarguments=None):
+    """run CompileTheWorld"""
+
+    defaultCtwopts = '-Inline'
+
+    parser = ArgumentParser(prog='mx ctw')
+    parser.add_argument('--ctwopts', action='store', help='space separated JVMCI options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='<options>')
+    parser.add_argument('--cp', '--jar', action='store', help='jar or class path denoting classes to compile', metavar='<path>')
+
+    args, vmargs = parser.parse_known_args(args)
+
+    if args.ctwopts:
+        # Replace spaces  with '#' since -G: options cannot contain spaces
+        vmargs.append('-G:CompileTheWorldConfig=' + re.sub(r'\s+', '#', args.ctwopts))
+
+    if args.cp:
+        cp = os.path.abspath(args.cp)
+    else:
+        cp = join(_jdk.home, 'lib', 'modules', 'bootmodules.jimage')
+        vmargs.append('-G:CompileTheWorldExcludeMethodFilter=sun.awt.X11.*.*')
+
+    # suppress menubar and dock when running on Mac; exclude x11 classes as they may cause vm crashes (on Solaris)
+    vmargs = ['-Djava.awt.headless=true'] + vmargs
+
+    if _vm.jvmciMode == 'disabled':
+        vmargs += ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + cp]
+    else:
+        if _vm.jvmciMode == 'jit':
+            vmargs += ['-XX:+BootstrapJVMCI']
+        vmargs += ['-G:CompileTheWorldClasspath=' + cp, 'org.graalvm.compiler.hotspot.CompileTheWorld']
+
+    run_vm(vmargs + _noneAsEmptyList(extraVMarguments))
+
+class UnitTestRun:
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def run(self, suites, tasks, extraVMarguments=None):
+        for suite in suites:
+            with Task(self.name + ': hosted-release ' + suite, tasks) as t:
+                if t: unittest(['--suite', suite, '--enable-timing', '--verbose', '--fail-fast'] + self.args + _noneAsEmptyList(extraVMarguments))
+
+class BootstrapTest:
+    def __init__(self, name, args, suppress=None):
+        self.name = name
+        self.args = args
+        self.suppress = suppress
+
+    def run(self, tasks, extraVMarguments=None):
+        with JVMCIMode('jit'):
+            with Task(self.name, tasks) as t:
+                if t:
+                    if self.suppress:
+                        out = mx.DuplicateSuppressingStream(self.suppress).write
+                    else:
+                        out = None
+                    run_vm(self.args + _noneAsEmptyList(extraVMarguments) + ['-XX:-TieredCompilation', '-XX:+BootstrapJVMCI', '-version'], out=out)
+
+class MicrobenchRun:
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def run(self, tasks, extraVMarguments=None):
+        with Task(self.name + ': hosted-product ', tasks) as t:
+            if t: microbench(_noneAsEmptyList(extraVMarguments) + ['--'] + self.args)
+
+def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVMarguments=None):
+
+    # Run unit tests in hosted mode
+    with JVMCIMode('hosted'):
+        for r in unit_test_runs:
+            r.run(suites, tasks, extraVMarguments)
+
+    # Run microbench in hosted mode (only for testing the JMH setup)
+    with JVMCIMode('hosted'):
+        for r in [MicrobenchRun('Microbench', ['TestJMH'])]:
+            r.run(tasks, extraVMarguments)
+
+    # Run ctw against rt.jar on server-hosted-jvmci
+    with JVMCIMode('hosted'):
+        with Task('CTW:hosted', tasks) as t:
+            if t: ctw(['--ctwopts', '-Inline +ExitVMOnException', '-esa', '-G:+CompileTheWorldMultiThreaded', '-G:-InlineDuringParsing', '-G:-CompileTheWorldVerbose', '-XX:ReservedCodeCacheSize=300m'], _noneAsEmptyList(extraVMarguments))
+
+    # bootstrap tests
+    for b in bootstrap_tests:
+        b.run(tasks, extraVMarguments)
+
+    # run dacapo sanitychecks
+    for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel='release', extraVmArguments=extraVMarguments) \
+            + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel='release', extraVmArguments=extraVMarguments):
+        with Task(str(test) + ':' + 'release', tasks) as t:
+            if t and not test.test('jvmci'):
+                t.abort(test.name + ' Failed')
+
+    # ensure -Xbatch still works
+    with JVMCIMode('jit'):
+        with Task('DaCapo_pmd:BatchMode', tasks) as t:
+            if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-Xbatch', 'pmd'])
+
+    # ensure benchmark counters still work
+    with JVMCIMode('jit'):
+        with Task('DaCapo_pmd:BenchmarkCounters:product', tasks) as t:
+            if t: dacapo(_noneAsEmptyList(extraVMarguments) + ['-G:+LIRProfileMoves', '-G:+GenericDynamicCounters', '-XX:JVMCICounterSize=10', 'pmd'])
+
+    # ensure -Xcomp still works
+    with JVMCIMode('jit'):
+        with Task('XCompMode:product', tasks) as t:
+            if t: run_vm(_noneAsEmptyList(extraVMarguments) + ['-Xcomp', '-version'])
+
+
+graal_unit_test_runs = [
+    UnitTestRun('UnitTests', []),
+]
+
+_registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if mx.get_arch() == 'sparcv9' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14'
+
+graal_bootstrap_tests = [
+    BootstrapTest('BootstrapWithSystemAssertions', ['-esa']),
+    BootstrapTest('BootstrapWithSystemAssertionsNoCoop', ['-esa', '-XX:-UseCompressedOops', '-G:+ExitVMOnException']),
+    BootstrapTest('BootstrapWithGCVerification', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapWithG1GCVerification', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapEconomyWithSystemAssertions', ['-esa', '-Djvmci.compiler=graal-economy', '-G:+ExitVMOnException']),
+    BootstrapTest('BootstrapWithExceptionEdges', ['-esa', '-G:+StressInvokeWithExceptionNode', '-G:+ExitVMOnException']),
+    BootstrapTest('BootstrapWithRegisterPressure', ['-esa', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException', '-G:+LIRUnlockBackendRestart']),
+    BootstrapTest('BootstrapTraceRAWithRegisterPressure', ['-esa', '-G:+TraceRA', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException', '-G:+LIRUnlockBackendRestart']),
+    BootstrapTest('BootstrapWithImmutableCode', ['-esa', '-G:+ImmutableCode', '-G:+VerifyPhases', '-G:+ExitVMOnException']),
+]
+
+def _graal_gate_runner(args, tasks):
+    compiler_gate_runner(['graal'], graal_unit_test_runs, graal_bootstrap_tests, tasks, args.extra_vm_argument)
+
+mx_gate.add_gate_runner(_suite, _graal_gate_runner)
+mx_gate.add_gate_argument('--extra-vm-argument', action='append', help='add extra vm argument to gate tasks if applicable (multiple occurrences allowed)')
+
+def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs):
+    run_vm(vmArgs + [mainClass] + mainClassArgs)
+
+mx_unittest.set_vm_launcher('JDK9 VM launcher', _unittest_vm_launcher)
+
+def _parseVmArgs(jdk, args, addDefaultArgs=True):
+    args = mx.expand_project_in_args(args, insitu=False)
+    jacocoArgs = mx_gate.get_jacoco_agent_args()
+    if jacocoArgs:
+        args = jacocoArgs + args
+
+    # Support for -G: options
+    def translateGOption(arg):
+        if arg.startswith('-G:+'):
+            if '=' in arg:
+                mx.abort('Mixing + and = in -G: option specification: ' + arg)
+            arg = '-Dgraal.' + arg[len('-G:+'):] + '=true'
+        elif arg.startswith('-G:-'):
+            if '=' in arg:
+                mx.abort('Mixing - and = in -G: option specification: ' + arg)
+            arg = '-Dgraal.' + arg[len('-G:+'):] + '=false'
+        elif arg.startswith('-G:'):
+            if '=' not in arg:
+                mx.abort('Missing "=" in non-boolean -G: option specification: ' + arg)
+            arg = '-Dgraal.' + arg[len('-G:'):]
+        return arg
+    args = map(translateGOption, args)
+
+    if '-G:+PrintFlags' in args and '-Xcomp' not in args:
+        mx.warn('Using -G:+PrintFlags may have no effect without -Xcomp as Graal initialization is lazy')
+
+    bcp = []
+    if _jvmciModes[_vm.jvmciMode]:
+        if _add_jvmci_to_bootclasspath:
+            bcp.append(mx.library('JVMCI').classpath_repr())
+        bcp.extend([d.get_classpath_repr() for d in _bootClasspathDists])
+    if bcp:
+        args = ['-Xbootclasspath/p:' + os.pathsep.join(bcp)] + args
+
+    # Remove JVMCI from class path. It's only there to support compilation.
+    cpIndex, cp = mx.find_classpath_arg(args)
+    if cp:
+        jvmciLib = mx.library('JVMCI').path
+        cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e != jvmciLib])
+        args[cpIndex] = cp
+
+    # Set the default JVMCI compiler
+    jvmciCompiler = _compilers[-1]
+    args = ['-Djvmci.compiler=' + jvmciCompiler] + args
+
+    if '-version' in args:
+        ignoredArgs = args[args.index('-version') + 1:]
+        if  len(ignoredArgs) > 0:
+            mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs))
+    return jdk.processArgs(args, addDefaultArgs=addDefaultArgs)
+
+def run_java(jdk, args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True):
+
+    args = _parseVmArgs(jdk, args, addDefaultArgs=addDefaultArgs)
+
+    jvmciModeArgs = _jvmciModes[_vm.jvmciMode]
+    cmd = [jdk.java] + ['-' + get_vm()] + jvmciModeArgs + args
+    return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd)
+
+_JVMCI_JDK_TAG = 'jvmci'
+
+class GraalJVMCI9JDKConfig(mx.JDKConfig):
+    def __init__(self, original):
+        self._original = original
+        mx.JDKConfig.__init__(self, original.home, tag=_JVMCI_JDK_TAG)
+
+    def run_java(self, args, **kwArgs):
+        run_java(self._original, args, **kwArgs)
+
+class GraalJDKFactory(mx.JDKFactory):
+    def getJDKConfig(self):
+        return GraalJVMCI9JDKConfig(_jdk)
+
+    def description(self):
+        return "JVMCI JDK with Graal"
+
+# This will override the 'generic' JVMCI JDK with a Graal JVMCI JDK that has
+# support for -G style Graal options.
+mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), GraalJDKFactory())
+
+def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None):
+    """run a Java program by executing the java executable in a JVMCI JDK"""
+
+    return run_java(_jdk, args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
+
+class GraalArchiveParticipant:
+    def __init__(self, dist):
+        self.dist = dist
+
+    def __opened__(self, arc, srcArc, services):
+        self.services = services
+        self.arc = arc
+
+    def __add__(self, arcname, contents):
+        if arcname.startswith('META-INF/providers/'):
+            provider = arcname[len('META-INF/providers/'):]
+            for service in contents.strip().split(os.linesep):
+                assert service
+                self.services.setdefault(service, []).append(provider)
+            return True
+        elif arcname.endswith('_OptionDescriptors.class'):
+            # Need to create service files for the providers of the
+            # jdk.vm.ci.options.Options service created by
+            # jdk.vm.ci.options.processor.OptionProcessor.
+            provider = arcname[:-len('.class'):].replace('/', '.')
+            self.services.setdefault('org.graalvm.compiler.options.OptionDescriptors', []).append(provider)
+        return False
+
+    def __addsrc__(self, arcname, contents):
+        return False
+
+    def __closing__(self):
+        pass
+
+mx.update_commands(_suite, {
+    'vm': [run_vm, '[-options] class [args...]'],
+    'ctw': [ctw, '[-vmoptions|noinline|nocomplex|full]'],
+    'microbench' : [microbench, '[VM options] [-- [JMH options]]'],
+})
+
+mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')')
+
+def mx_post_parse_cmd_line(opts):
+    if opts.jvmci_mode is not None:
+        _vm.update(opts.jvmci_mode)
+    for dist in [d.dist() for d in _bootClasspathDists]:
+        dist.set_archiveparticipant(GraalArchiveParticipant(dist))
+
+_add_jvmci_to_bootclasspath = False
+
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py
new file mode 100644
index 0000000..e99e6de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/mx_graal_bench.py
@@ -0,0 +1,256 @@
+#
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# ----------------------------------------------------------------------------------------------------
+
+import sanitycheck
+import itertools
+import json
+
+import mx
+import mx_graal
+
+def _run_benchmark(args, availableBenchmarks, runBenchmark):
+
+    vmOpts, benchmarksAndOptions = mx.extract_VM_args(args, useDoubleDash=availableBenchmarks is None)
+
+    if availableBenchmarks is None:
+        harnessArgs = benchmarksAndOptions
+        return runBenchmark(None, harnessArgs, vmOpts)
+
+    if len(benchmarksAndOptions) == 0:
+        mx.abort('at least one benchmark name or "all" must be specified')
+    benchmarks = list(itertools.takewhile(lambda x: not x.startswith('-'), benchmarksAndOptions))
+    harnessArgs = benchmarksAndOptions[len(benchmarks):]
+
+    if 'all' in benchmarks:
+        benchmarks = availableBenchmarks
+    else:
+        for bm in benchmarks:
+            if bm not in availableBenchmarks:
+                mx.abort('unknown benchmark: ' + bm + '\nselect one of: ' + str(availableBenchmarks))
+
+    failed = []
+    for bm in benchmarks:
+        if not runBenchmark(bm, harnessArgs, vmOpts):
+            failed.append(bm)
+
+    if len(failed) != 0:
+        mx.abort('Benchmark failures: ' + str(failed))
+
+def deoptalot(args):
+    """bootstrap a VM with DeoptimizeALot and VerifyOops on
+
+    If the first argument is a number, the process will be repeated
+    this number of times. All other arguments are passed to the VM."""
+    count = 1
+    if len(args) > 0 and args[0].isdigit():
+        count = int(args[0])
+        del args[0]
+
+    for _ in range(count):
+        if not mx_graal.run_vm(['-XX:-TieredCompilation', '-XX:+DeoptimizeALot', '-XX:+VerifyOops'] + args + ['-version']) == 0:
+            mx.abort("Failed")
+
+def longtests(args):
+
+    deoptalot(['15', '-Xmx48m'])
+
+    dacapo(['100', 'eclipse', '-esa'])
+
+def dacapo(args):
+    """run one or more DaCapo benchmarks"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        return sanitycheck.getDacapo(bm, harnessArgs).test(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    _run_benchmark(args, sanitycheck.dacapoSanityWarmup.keys(), launcher)
+
+def scaladacapo(args):
+    """run one or more Scala DaCapo benchmarks"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        return sanitycheck.getScalaDacapo(bm, harnessArgs).test(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    _run_benchmark(args, sanitycheck.dacapoScalaSanityWarmup.keys(), launcher)
+
+
+"""
+Extra benchmarks to run from 'bench()'.
+"""
+extraBenchmarks = []
+
+def bench(args):
+    """run benchmarks and parse their output for results
+
+    Results are JSON formated : {group : {benchmark : score}}."""
+    resultFile = None
+    if '-resultfile' in args:
+        index = args.index('-resultfile')
+        if index + 1 < len(args):
+            resultFile = args[index + 1]
+            del args[index]
+            del args[index]
+        else:
+            mx.abort('-resultfile must be followed by a file name')
+    resultFileCSV = None
+    if '-resultfilecsv' in args:
+        index = args.index('-resultfilecsv')
+        if index + 1 < len(args):
+            resultFileCSV = args[index + 1]
+            del args[index]
+            del args[index]
+        else:
+            mx.abort('-resultfilecsv must be followed by a file name')
+    vm = mx_graal.get_vm()
+    if len(args) is 0:
+        args = ['all']
+
+    vmArgs = [arg for arg in args if arg.startswith('-')]
+
+    def benchmarks_in_group(group):
+        prefix = group + ':'
+        return [a[len(prefix):] for a in args if a.startswith(prefix)]
+
+    results = {}
+    benchmarks = []
+    # DaCapo
+    if 'dacapo' in args or 'all' in args:
+        benchmarks += sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Benchmark)
+    else:
+        dacapos = benchmarks_in_group('dacapo')
+        for dacapo in dacapos:
+            if dacapo not in sanitycheck.dacapoSanityWarmup.keys():
+                mx.abort('Unknown DaCapo : ' + dacapo)
+            iterations = sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark]
+            if iterations > 0:
+                benchmarks += [sanitycheck.getDacapo(dacapo, ['-n', str(iterations)])]
+
+    if 'scaladacapo' in args or 'all' in args:
+        benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark)
+    else:
+        scaladacapos = benchmarks_in_group('scaladacapo')
+        for scaladacapo in scaladacapos:
+            if scaladacapo not in sanitycheck.dacapoScalaSanityWarmup.keys():
+                mx.abort('Unknown Scala DaCapo : ' + scaladacapo)
+            iterations = sanitycheck.dacapoScalaSanityWarmup[scaladacapo][sanitycheck.SanityCheckLevel.Benchmark]
+            if iterations > 0:
+                benchmarks += [sanitycheck.getScalaDacapo(scaladacapo, ['-n', str(iterations)])]
+
+    # Bootstrap
+    if 'bootstrap' in args or 'all' in args:
+        benchmarks += sanitycheck.getBootstraps()
+    # SPECjvm2008
+    if 'specjvm2008' in args or 'all' in args:
+        benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120'])]
+    else:
+        specjvms = benchmarks_in_group('specjvm2008')
+        for specjvm in specjvms:
+            benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120', specjvm])]
+
+    if 'specjbb2005' in args or 'all' in args:
+        benchmarks += [sanitycheck.getSPECjbb2005()]
+
+    if 'specjbb2013' in args:  # or 'all' in args //currently not in default set
+        benchmarks += [sanitycheck.getSPECjbb2013()]
+
+    if 'ctw-full' in args:
+        benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.Full))
+    if 'ctw-noinline' in args:
+        benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.NoInline))
+
+    for f in extraBenchmarks:
+        f(args, vm, benchmarks)
+
+    for test in benchmarks:
+        for (groupName, res) in test.bench(vm, extraVmOpts=vmArgs).items():
+            group = results.setdefault(groupName, {})
+            group.update(res)
+    mx.log(json.dumps(results))
+    if resultFile:
+        with open(resultFile, 'w') as f:
+            f.write(json.dumps(results))
+    if resultFileCSV:
+        with open(resultFileCSV, 'w') as f:
+            for key1, value1 in results.iteritems():
+                f.write('%s;\n' % (str(key1)))
+                for key2, value2 in sorted(value1.iteritems()):
+                    f.write('%s; %s;\n' % (str(key2), str(value2)))
+
+def specjvm2008(args):
+    """run one or more SPECjvm2008 benchmarks"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        return sanitycheck.getSPECjvm2008(harnessArgs + [bm]).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    availableBenchmarks = set(sanitycheck.specjvm2008Names)
+    if "all" not in args:
+        # only add benchmark groups if we are not running "all"
+        for name in sanitycheck.specjvm2008Names:
+            parts = name.rsplit('.', 1)
+            if len(parts) > 1:
+                assert len(parts) == 2
+                group = parts[0]
+                availableBenchmarks.add(group)
+
+    _run_benchmark(args, sorted(availableBenchmarks), launcher)
+
+def specjbb2013(args):
+    """run the composite SPECjbb2013 benchmark"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        assert bm is None
+        return sanitycheck.getSPECjbb2013(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    _run_benchmark(args, None, launcher)
+
+def specjbb2015(args):
+    """run the composite SPECjbb2015 benchmark"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        assert bm is None
+        return sanitycheck.getSPECjbb2015(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    _run_benchmark(args, None, launcher)
+
+def specjbb2005(args):
+    """run the composite SPECjbb2005 benchmark"""
+
+    def launcher(bm, harnessArgs, extraVmOpts):
+        assert bm is None
+        return sanitycheck.getSPECjbb2005(harnessArgs).bench(mx_graal.get_vm(), extraVmOpts=extraVmOpts)
+
+    _run_benchmark(args, None, launcher)
+
+mx.update_commands(mx.suite('graal'), {
+    'dacapo': [dacapo, '[VM options] benchmarks...|"all" [DaCapo options]'],
+    'scaladacapo': [scaladacapo, '[VM options] benchmarks...|"all" [Scala DaCapo options]'],
+    'specjvm2008': [specjvm2008, '[VM options] benchmarks...|"all" [SPECjvm2008 options]'],
+    'specjbb2013': [specjbb2013, '[VM options] [-- [SPECjbb2013 options]]'],
+    'specjbb2015': [specjbb2015, '[VM options] [-- [SPECjbb2015 options]]'],
+    'specjbb2005': [specjbb2005, '[VM options] [-- [SPECjbb2005 options]]'],
+    'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
+    'deoptalot' : [deoptalot, '[n]'],
+    'longtests' : [longtests, ''],
+})
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py b/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py
new file mode 100644
index 0000000..c2dbd6f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/outputparser.py
@@ -0,0 +1,71 @@
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# ----------------------------------------------------------------------------------------------------
+
+import re
+
+class OutputParser:
+
+    def __init__(self):
+        self.matchers = []
+
+    def addMatcher(self, matcher):
+        self.matchers.append(matcher)
+
+    def parse(self, output):
+        valueMaps = []
+        for matcher in self.matchers:
+            matcher.parse(output, valueMaps)
+        return valueMaps
+
+"""
+Produces a value map for each match of a given regular expression
+in some text. The value map is specified by a template map
+where each key and value in the template map is either a constant
+value or a named group in the regular expression. The latter is
+given as the group name enclosed in '<' and '>'.
+"""
+class ValuesMatcher:
+
+    def __init__(self, regex, valuesTemplate):
+        assert isinstance(valuesTemplate, dict)
+        self.regex = regex
+        self.valuesTemplate = valuesTemplate
+
+    def parse(self, text, valueMaps):
+        for match in self.regex.finditer(text):
+            valueMap = {}
+            for keyTemplate, valueTemplate in self.valuesTemplate.items():
+                key = self.get_template_value(match, keyTemplate)
+                value = self.get_template_value(match, valueTemplate)
+                assert not valueMap.has_key(key), key
+                valueMap[key] = value
+            valueMaps.append(valueMap)
+
+    def get_template_value(self, match, template):
+        def replace_var(m):
+            groupName = m.group(1)
+            return match.group(groupName)
+
+        return re.sub(r'<([\w]+)>', replace_var, template)
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py b/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py
new file mode 100644
index 0000000..7d9533c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/sanitycheck.py
@@ -0,0 +1,453 @@
+# ----------------------------------------------------------------------------------------------------
+#
+# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# ----------------------------------------------------------------------------------------------------
+
+from outputparser import OutputParser, ValuesMatcher
+import re, mx, mx_graal, os, sys, StringIO, subprocess
+from os.path import isfile, join, exists
+
+gc = 'UseSerialGC'
+
+dacapoSanityWarmup = {
+    'avrora':     [0, 0, 3, 6, 13],
+    'batik':      [0, 0, 5, 5, 20],
+    'eclipse':    [0, 0, 0, 0, 0],
+    'fop':        [4, 8, 10, 20, 30],
+    'h2':         [0, 0, 5, 5, 8],
+    'jython':     [0, 0, 5, 10, 13],
+    'luindex':    [0, 0, 5, 10, 10],
+    'lusearch':   [0, 4, 5, 5, 8],
+    'pmd':        [0, 0, 5, 10, 13],
+    'sunflow':    [0, 2, 5, 10, 15],
+    'tomcat':     [0, 0, 5, 10, 15],
+    'tradebeans': [0, 0, 5, 10, 13],
+    'tradesoap':  [0, 0, 5, 10, 15],
+    'xalan':      [0, 0, 5, 10, 18],
+}
+
+dacapoScalaSanityWarmup = {
+    'actors':     [0, 0, 2, 5, 5],
+    'apparat':    [0, 0, 2, 5, 5],
+    'factorie':   [0, 0, 2, 5, 5],
+    'kiama':      [0, 4, 3, 13, 15],
+    'scalac':     [0, 0, 5, 15, 20],
+    'scaladoc':   [0, 0, 5, 15, 15],
+    'scalap':     [0, 0, 5, 15, 20],
+    'scalariform':[0, 0, 6, 15, 20],
+    'scalatest':  [0, 0, 2, 10, 12],
+    'scalaxb':    [0, 0, 5, 15, 25],
+# (gdub) specs sometimes returns a non-zero value event though there is no apparent failure
+    'specs':      [0, 0, 0, 0, 0],
+    'tmt':        [0, 0, 3, 10, 12]
+}
+
+dacapoGateBuildLevels = {
+    'avrora':     ['product', 'fastdebug', 'debug'],
+    'batik':      ['product', 'fastdebug', 'debug'],
+    # (lewurm): does not work with JDK8
+    'eclipse':    [],
+    'fop':        ['fastdebug', 'debug'],
+    'h2':         ['product', 'fastdebug', 'debug'],
+    'jython':     ['product', 'fastdebug', 'debug'],
+    'luindex':    ['product', 'fastdebug', 'debug'],
+    'lusearch':   ['product'],
+    'pmd':        ['product', 'fastdebug', 'debug'],
+    'sunflow':    ['fastdebug', 'debug'],
+    'tomcat':     ['product', 'fastdebug', 'debug'],
+    'tradebeans': ['product', 'fastdebug', 'debug'],
+    # tradesoap is too unreliable for the gate, often crashing with concurrency problems:
+    # http://sourceforge.net/p/dacapobench/bugs/99/
+    'tradesoap':  [],
+    'xalan':      ['product', 'fastdebug', 'debug'],
+}
+
+dacapoScalaGateBuildLevels = {
+    'actors':     ['product', 'fastdebug', 'debug'],
+    'apparat':    ['product', 'fastdebug', 'debug'],
+    'factorie':   ['product', 'fastdebug', 'debug'],
+    'kiama':      ['fastdebug', 'debug'],
+    'scalac':     ['product', 'fastdebug', 'debug'],
+    'scaladoc':   ['product', 'fastdebug', 'debug'],
+    'scalap':     ['product', 'fastdebug', 'debug'],
+    'scalariform':['product', 'fastdebug', 'debug'],
+    'scalatest':  ['product', 'fastdebug', 'debug'],
+    'scalaxb':    ['product', 'fastdebug', 'debug'],
+    'specs':      ['product', 'fastdebug', 'debug'],
+    'tmt':        ['product', 'fastdebug', 'debug'],
+}
+
+specjvm2008Names = [
+    'startup.helloworld',
+    'startup.compiler.compiler',
+    'startup.compiler.sunflow',
+    'startup.compress',
+    'startup.crypto.aes',
+    'startup.crypto.rsa',
+    'startup.crypto.signverify',
+    'startup.mpegaudio',
+    'startup.scimark.fft',
+    'startup.scimark.lu',
+    'startup.scimark.monte_carlo',
+    'startup.scimark.sor',
+    'startup.scimark.sparse',
+    'startup.serial',
+    'startup.sunflow',
+    'startup.xml.transform',
+    'startup.xml.validation',
+    'compiler.compiler',
+    'compiler.sunflow',
+    'compress',
+    'crypto.aes',
+    'crypto.rsa',
+    'crypto.signverify',
+    'derby',
+    'mpegaudio',
+    'scimark.fft.large',
+    'scimark.lu.large',
+    'scimark.sor.large',
+    'scimark.sparse.large',
+    'scimark.fft.small',
+    'scimark.lu.small',
+    'scimark.sor.small',
+    'scimark.sparse.small',
+    'scimark.monte_carlo',
+    'serial',
+    'sunflow',
+    'xml.transform',
+    'xml.validation'
+]
+
+def _noneAsEmptyList(a):
+    if a is None:
+        return []
+    return a
+
+class SanityCheckLevel:
+    Fast, Gate, Normal, Extensive, Benchmark = range(5)
+
+def getSPECjbb2005(benchArgs=None):
+    benchArgs = [] if benchArgs is None else benchArgs
+
+    specjbb2005 = mx.get_env('SPECJBB2005')
+    if specjbb2005 is None or not exists(join(specjbb2005, 'jbb.jar')):
+        mx.abort('Please set the SPECJBB2005 environment variable to a SPECjbb2005 directory')
+
+    score = re.compile(r"^Valid run, Score is  (?P<score>[0-9]+)$", re.MULTILINE)
+    error = re.compile(r"VALIDATION ERROR")
+    success = re.compile(r"^Valid run, Score is  [0-9]+$", re.MULTILINE)
+    matcher = ValuesMatcher(score, {'group' : 'SPECjbb2005', 'name' : 'score', 'score' : '<score>'})
+    classpath = ['jbb.jar', 'check.jar']
+    return Test("SPECjbb2005", ['spec.jbb.JBBmain', '-propfile', 'SPECjbb.props'] + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+' + gc, '-XX:-UseCompressedOops', '-cp', os.pathsep.join(classpath)], defaultCwd=specjbb2005)
+
+def getSPECjbb2013(benchArgs=None):
+
+    specjbb2013 = mx.get_env('SPECJBB2013')
+    if specjbb2013 is None or not exists(join(specjbb2013, 'specjbb2013.jar')):
+        mx.abort('Please set the SPECJBB2013 environment variable to a SPECjbb2013 directory')
+
+    jops = re.compile(r"^RUN RESULT: hbIR \(max attempted\) = [0-9]+, hbIR \(settled\) = [0-9]+, max-jOPS = (?P<max>[0-9]+), critical-jOPS = (?P<critical>[0-9]+)$", re.MULTILINE)
+    # error?
+    success = re.compile(r"org.spec.jbb.controller: Run finished", re.MULTILINE)
+    matcherMax = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'max', 'score' : '<max>'})
+    matcherCritical = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'critical', 'score' : '<critical>'})
+    return Test("SPECjbb2013", ['-jar', 'specjbb2013.jar', '-m', 'composite'] +
+                _noneAsEmptyList(benchArgs), [success], [], [matcherCritical, matcherMax],
+                vmOpts=['-Xmx6g', '-Xms6g', '-Xmn3g', '-XX:+UseParallelOldGC', '-XX:-UseAdaptiveSizePolicy', '-XX:-UseBiasedLocking', '-XX:-UseCompressedOops'], defaultCwd=specjbb2013)
+
+def getSPECjbb2015(benchArgs=None):
+
+    specjbb2015 = mx.get_env('SPECJBB2015')
+    if specjbb2015 is None or not exists(join(specjbb2015, 'specjbb2015.jar')):
+        mx.abort('Please set the SPECJBB2015 environment variable to a SPECjbb2015 directory')
+
+    jops = re.compile(r"^RUN RESULT: hbIR \(max attempted\) = [0-9]+, hbIR \(settled\) = [0-9]+, max-jOPS = (?P<max>[0-9]+), critical-jOPS = (?P<critical>[0-9]+)$", re.MULTILINE)
+    # error?
+    success = re.compile(r"org.spec.jbb.controller: Run finished", re.MULTILINE)
+    matcherMax = ValuesMatcher(jops, {'group' : 'SPECjbb2015', 'name' : 'max', 'score' : '<max>'})
+    matcherCritical = ValuesMatcher(jops, {'group' : 'SPECjbb2015', 'name' : 'critical', 'score' : '<critical>'})
+    return Test("SPECjbb2015", ['-jar', 'specjbb2015.jar', '-m', 'composite'] +
+                _noneAsEmptyList(benchArgs), [success], [], [matcherCritical, matcherMax],
+                vmOpts=['-Xmx6g', '-Xms6g', '-Xmn3g', '-XX:+UseParallelOldGC', '-XX:-UseAdaptiveSizePolicy', '-XX:-UseBiasedLocking', '-XX:-UseCompressedOops'], defaultCwd=specjbb2015)
+
+def getSPECjvm2008(benchArgs=None):
+
+    specjvm2008 = mx.get_env('SPECJVM2008')
+    if specjvm2008 is None or not exists(join(specjvm2008, 'SPECjvm2008.jar')):
+        mx.abort('Please set the SPECJVM2008 environment variable to a SPECjvm2008 directory')
+
+    score = re.compile(r"^(Score on|Noncompliant) (?P<benchmark>[a-zA-Z0-9\._]+)( result)?: (?P<score>[0-9]+((,|\.)[0-9]+)?)( SPECjvm2008 Base)? ops/m$", re.MULTILINE)
+    error = re.compile(r"^Errors in benchmark: ", re.MULTILINE)
+    # The ' ops/m' at the end of the success string is important : it's how you can tell valid and invalid runs apart
+    success = re.compile(r"^(Noncompliant c|C)omposite result: [0-9]+((,|\.)[0-9]+)?( SPECjvm2008 (Base|Peak))? ops/m$", re.MULTILINE)
+    matcher = ValuesMatcher(score, {'group' : 'SPECjvm2008', 'name' : '<benchmark>', 'score' : '<score>'})
+
+    return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + _noneAsEmptyList(benchArgs), [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+' + gc, '-XX:-UseCompressedOops'], defaultCwd=specjvm2008)
+
+def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=None, extraVmArguments=None):
+    checks = []
+
+    for (bench, ns) in dacapoSanityWarmup.items():
+        if ns[level] > 0:
+            if gateBuildLevel is None or gateBuildLevel in dacapoGateBuildLevels[bench]:
+                checks.append(getDacapo(bench, ['-n', str(ns[level])] + _noneAsEmptyList(dacapoArgs), extraVmArguments=extraVmArguments))
+
+    return checks
+
+def getDacapo(name, dacapoArgs=None, extraVmArguments=None):
+    dacapo = mx.get_env('DACAPO_CP')
+    if dacapo is None:
+        l = mx.library('DACAPO', False)
+        if l is not None:
+            dacapo = l.get_path(True)
+        else:
+            mx.abort('DaCapo 9.12 jar file must be specified with DACAPO_CP environment variable or as DACAPO library')
+
+    if not isfile(dacapo) or not dacapo.endswith('.jar'):
+        mx.abort('Specified DaCapo jar file does not exist or is not a jar file: ' + dacapo)
+
+    dacapoSuccess = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====", re.MULTILINE)
+    dacapoFail = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) FAILED (warmup|) =====", re.MULTILINE)
+    dacapoTime = re.compile(r"===== DaCapo 9\.12 (?P<benchmark>[a-zA-Z0-9_]+) PASSED in (?P<time>[0-9]+) msec =====")
+    dacapoTime1 = re.compile(r"===== DaCapo 9\.12 (?P<benchmark>[a-zA-Z0-9_]+) completed warmup 1 in (?P<time>[0-9]+) msec =====")
+
+    dacapoMatcher = ValuesMatcher(dacapoTime, {'group' : 'DaCapo', 'name' : '<benchmark>', 'score' : '<time>'})
+    dacapoMatcher1 = ValuesMatcher(dacapoTime1, {'group' : 'DaCapo-1stRun', 'name' : '<benchmark>', 'score' : '<time>'})
+
+    # Use ipv4 stack for dacapos; tomcat+solaris+ipv6_interface fails (see also: JDK-8072384)
+    return Test("DaCapo-" + name, ['-jar', mx._cygpathU2W(dacapo), name] + _noneAsEmptyList(dacapoArgs), [dacapoSuccess], [dacapoFail],
+                [dacapoMatcher, dacapoMatcher1],
+                ['-Xms2g', '-XX:+' + gc, '-XX:-UseCompressedOops', "-Djava.net.preferIPv4Stack=true", '-G:+ExitVMOnException'] +
+                _noneAsEmptyList(extraVmArguments))
+
+def getScalaDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=None, extraVmArguments=None):
+    checks = []
+
+    for (bench, ns) in dacapoScalaSanityWarmup.items():
+        if ns[level] > 0:
+            if gateBuildLevel is None or gateBuildLevel in dacapoScalaGateBuildLevels[bench]:
+                checks.append(getScalaDacapo(bench, ['-n', str(ns[level])] + _noneAsEmptyList(dacapoArgs), extraVmArguments=extraVmArguments))
+
+    return checks
+
+def getScalaDacapo(name, dacapoArgs=None, extraVmArguments=None):
+    dacapo = mx.get_env('DACAPO_SCALA_CP')
+    if dacapo is None:
+        l = mx.library('DACAPO_SCALA', False)
+        if l is not None:
+            dacapo = l.get_path(True)
+        else:
+            mx.abort('Scala DaCapo 0.1.0 jar file must be specified with DACAPO_SCALA_CP environment variable or as DACAPO_SCALA library')
+
+    if not isfile(dacapo) or not dacapo.endswith('.jar'):
+        mx.abort('Specified Scala DaCapo jar file does not exist or is not a jar file: ' + dacapo)
+
+    dacapoSuccess = re.compile(r"^===== DaCapo 0\.1\.0(-SNAPSHOT)? ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====", re.MULTILINE)
+    dacapoFail = re.compile(r"^===== DaCapo 0\.1\.0(-SNAPSHOT)? ([a-zA-Z0-9_]+) FAILED (warmup|) =====", re.MULTILINE)
+    dacapoTime = re.compile(r"===== DaCapo 0\.1\.0(-SNAPSHOT)? (?P<benchmark>[a-zA-Z0-9_]+) PASSED in (?P<time>[0-9]+) msec =====")
+
+    dacapoMatcher = ValuesMatcher(dacapoTime, {'group' : "Scala-DaCapo", 'name' : '<benchmark>', 'score' : '<time>'})
+
+    return Test("Scala-DaCapo-" + name, ['-jar', mx._cygpathU2W(dacapo), name] + _noneAsEmptyList(dacapoArgs), [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:+' + gc, '-XX:-UseCompressedOops'] + _noneAsEmptyList(extraVmArguments))
+
+def getBootstraps():
+    time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms( \(compiled (?P<methods>[0-9]+) methods\))?")
+    scoreMatcher = ValuesMatcher(time, {'group' : 'Bootstrap', 'name' : 'BootstrapTime', 'score' : '<time>'})
+    methodMatcher = ValuesMatcher(time, {'group' : 'Bootstrap', 'name' : 'BootstrapMethods', 'score' : '<methods>'})
+    scoreMatcherBig = ValuesMatcher(time, {'group' : 'Bootstrap-bigHeap', 'name' : 'BootstrapTime', 'score' : '<time>'})
+    methodMatcherBig = ValuesMatcher(time, {'group' : 'Bootstrap-bigHeap', 'name' : 'BootstrapMethods', 'score' : '<methods>'})
+
+    tests = []
+    tests.append(Test("Bootstrap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher, methodMatcher], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
+    tests.append(Test("Bootstrap-bigHeap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcherBig, methodMatcherBig], vmOpts=['-Xms2g'], ignoredVMs=['client', 'server'], benchmarkCompilationRate=False))
+    return tests
+
+class CTWMode:
+    Full, NoInline = range(2)
+
+def getCTW(vm, mode):
+    time = re.compile(r"CompileTheWorld : Done \([0-9]+ classes, [0-9]+ methods, (?P<time>[0-9]+) ms\)")
+    scoreMatcher = ValuesMatcher(time, {'group' : 'CompileTheWorld', 'name' : 'CompileTime', 'score' : '<time>'})
+
+    jre = os.environ.get('JAVA_HOME')
+    if exists(join(jre, 'jre')):
+        jre = join(jre, 'jre')
+    rtjar = join(jre, 'lib', 'rt.jar')
+
+
+    args = ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + rtjar]
+    if vm == 'jvmci':
+        args += ['-XX:+BootstrapGraal']
+    if mode >= CTWMode.NoInline:
+        if not mx_graal.isJVMCIEnabled(vm):
+            args.append('-XX:-Inline')
+        else:
+            args.append('-G:CompileTheWordConfig=-Inline')
+
+    return Test("CompileTheWorld", args, successREs=[time], scoreMatchers=[scoreMatcher], benchmarkCompilationRate=False)
+
+
+class Tee:
+    def __init__(self):
+        self.output = StringIO.StringIO()
+    def eat(self, line):
+        self.output.write(line)
+        sys.stdout.write(line)
+
+"""
+Encapsulates a single program that is a sanity test and/or a benchmark.
+"""
+class Test:
+    def __init__(self, name, cmd, successREs=None, failureREs=None, scoreMatchers=None, vmOpts=None, defaultCwd=None, ignoredVMs=None, benchmarkCompilationRate=False):
+
+        self.name = name
+        self.successREs = _noneAsEmptyList(successREs)
+        self.failureREs = _noneAsEmptyList(failureREs) + [re.compile(r"Exception occurred in scope: ")]
+        self.scoreMatchers = _noneAsEmptyList(scoreMatchers)
+        self.vmOpts = _noneAsEmptyList(vmOpts)
+        self.cmd = cmd
+        self.defaultCwd = defaultCwd
+        self.ignoredVMs = _noneAsEmptyList(ignoredVMs)
+        self.benchmarkCompilationRate = benchmarkCompilationRate
+        if benchmarkCompilationRate:
+            self.vmOpts = self.vmOpts + ['-XX:+CITime']
+
+    def __str__(self):
+        return self.name
+
+    def test(self, vm, cwd=None, extraVmOpts=None, vmbuild=None):
+        """
+        Run this program as a sanity test.
+        """
+        if vm in self.ignoredVMs:
+            return True
+        if cwd is None:
+            cwd = self.defaultCwd
+        parser = OutputParser()
+        jvmError = re.compile(r"(?P<jvmerror>([A-Z]:|/).*[/\\]hs_err_pid[0-9]+\.log)")
+        parser.addMatcher(ValuesMatcher(jvmError, {'jvmError' : '<jvmerror>'}))
+
+        for successRE in self.successREs:
+            parser.addMatcher(ValuesMatcher(successRE, {'passed' : '1'}))
+        for failureRE in self.failureREs:
+            parser.addMatcher(ValuesMatcher(failureRE, {'failed' : '1'}))
+
+        tee = Tee()
+        retcode = mx_graal.run_vm(self.vmOpts + _noneAsEmptyList(extraVmOpts) + self.cmd, vm, nonZeroIsFatal=False, out=tee.eat, err=subprocess.STDOUT, cwd=cwd, debugLevel=vmbuild)
+        output = tee.output.getvalue()
+        valueMaps = parser.parse(output)
+
+        if len(valueMaps) == 0:
+            return False
+
+        record = {}
+        for valueMap in valueMaps:
+            for key, value in valueMap.items():
+                if record.has_key(key) and record[key] != value:
+                    mx.abort('Inconsistant values returned by test machers : ' + str(valueMaps))
+                record[key] = value
+
+        jvmErrorFile = record.get('jvmError')
+        if jvmErrorFile:
+            mx.log('/!\\JVM Error : dumping error log...')
+            with open(jvmErrorFile, 'rb') as fp:
+                mx.log(fp.read())
+            os.unlink(jvmErrorFile)
+            return False
+
+        if record.get('failed') == '1':
+            return False
+
+        return retcode == 0 and record.get('passed') == '1'
+
+    def bench(self, vm, cwd=None, extraVmOpts=None, vmbuild=None):
+        """
+        Run this program as a benchmark.
+        """
+        if vm in self.ignoredVMs:
+            return {}
+        if cwd is None:
+            cwd = self.defaultCwd
+        parser = OutputParser()
+
+        for successRE in self.successREs:
+            parser.addMatcher(ValuesMatcher(successRE, {'passed' : '1'}))
+        for failureRE in self.failureREs:
+            parser.addMatcher(ValuesMatcher(failureRE, {'failed' : '1'}))
+        for scoreMatcher in self.scoreMatchers:
+            parser.addMatcher(scoreMatcher)
+
+        if self.benchmarkCompilationRate:
+            if vm == 'jvmci':
+                bps = re.compile(r"ParsedBytecodesPerSecond@final: (?P<rate>[0-9]+)")
+                ibps = re.compile(r"InlinedBytecodesPerSecond@final: (?P<rate>[0-9]+)")
+                parser.addMatcher(ValuesMatcher(bps, {'group' : 'ParsedBytecodesPerSecond', 'name' : self.name, 'score' : '<rate>'}))
+                parser.addMatcher(ValuesMatcher(ibps, {'group' : 'InlinedBytecodesPerSecond', 'name' : self.name, 'score' : '<rate>'}))
+            else:
+                ibps = re.compile(r"(?P<compiler>[\w]+) compilation speed: +(?P<rate>[0-9]+) bytes/s {standard")
+                parser.addMatcher(ValuesMatcher(ibps, {'group' : 'InlinedBytecodesPerSecond', 'name' : '<compiler>:' + self.name, 'score' : '<rate>'}))
+
+        startDelim = 'START: ' + self.name
+        endDelim = 'END: ' + self.name
+
+        outputfile = os.environ.get('BENCH_OUTPUT', None)
+        if outputfile:
+            # Used only to debug output parsing
+            with open(outputfile) as fp:
+                output = fp.read()
+                start = output.find(startDelim)
+                end = output.find(endDelim, start)
+                if start == -1 and end == -1:
+                    return {}
+                output = output[start + len(startDelim + os.linesep): end]
+                mx.log(startDelim)
+                mx.log(output)
+                mx.log(endDelim)
+        else:
+            tee = Tee()
+            mx.log(startDelim)
+            if mx_graal.run_vm(self.vmOpts + _noneAsEmptyList(extraVmOpts) + self.cmd, vm, nonZeroIsFatal=False, out=tee.eat, err=subprocess.STDOUT, cwd=cwd, debugLevel=vmbuild) != 0:
+                mx.abort("Benchmark failed (non-zero retcode)")
+            mx.log(endDelim)
+            output = tee.output.getvalue()
+
+        groups = {}
+        passed = False
+        for valueMap in parser.parse(output):
+            assert (valueMap.has_key('name') and valueMap.has_key('score') and valueMap.has_key('group')) or valueMap.has_key('passed') or valueMap.has_key('failed'), valueMap
+            if valueMap.get('failed') == '1':
+                mx.abort("Benchmark failed")
+            if valueMap.get('passed') == '1':
+                passed = True
+            groupName = valueMap.get('group')
+            if groupName:
+                group = groups.setdefault(groupName, {})
+                name = valueMap.get('name')
+                score = valueMap.get('score')
+                if name and score:
+                    group[name] = score
+
+        if not passed:
+            mx.abort("Benchmark failed (not passed)")
+
+        return groups
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py
new file mode 100644
index 0000000..402eae2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py
@@ -0,0 +1,1211 @@
+suite = {
+  "mxversion" : "5.6.5",
+  "name" : "graal",
+
+  "defaultLicense" : "GPLv2-CPE",
+
+  # This puts mx/ as a sibling of the JDK build configuration directories
+  # (e.g., macosx-x86_64-normal-server-release).
+  "outputRoot" : "../../../build/mx/hotspot",
+
+  "libraries" : {
+
+    # ------------- Libraries -------------
+
+    "JAVA_ALLOCATION_INSTRUMENTER" : {
+      "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar"],
+      "sha1" : "476d9a44cd19d6b55f81571077dfa972a4f8a083",
+      "bootClassPathAgent" : "true",
+    },
+  },
+
+  "projects" : {
+
+    # ------------- Graal -------------
+    "org.graalvm.compiler.common" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.serviceprovider" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.serviceprovider.processor" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.serviceprovider"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Codegen",
+    },
+
+    "org.graalvm.compiler.options" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.options.processor" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.options",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Codegen",
+    },
+
+    "org.graalvm.compiler.options.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.options",
+        "mx:JUNIT",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.debug" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "dependencies" : [
+        "org.graalvm.compiler.serviceprovider",
+        "org.graalvm.compiler.options"
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Debug",
+    },
+
+    "org.graalvm.compiler.debug.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+        "org.graalvm.compiler.debug",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Debug,Test",
+    },
+
+    "org.graalvm.compiler.code" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.graph",
+        "org.graalvm.compiler.common",
+      ],
+      "annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.api.collections" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.api.directives" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.api.directives.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "dependencies" : [
+        "org.graalvm.compiler.core.test",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.api.runtime" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.api.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+        "org.graalvm.compiler.api.runtime",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal,Test",
+    },
+
+    "org.graalvm.compiler.api.replacements" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal,Replacements",
+    },
+
+    "org.graalvm.compiler.hotspot" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.runtime",
+        "org.graalvm.compiler.replacements",
+        "org.graalvm.compiler.runtime",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_COMPILER_MATCH_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot",
+    },
+
+    "org.graalvm.compiler.hotspot.aarch64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core.aarch64",
+        "org.graalvm.compiler.hotspot",
+        "org.graalvm.compiler.replacements.aarch64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AArch64",
+    },
+
+    "org.graalvm.compiler.hotspot.amd64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core.amd64",
+        "org.graalvm.compiler.hotspot",
+        "org.graalvm.compiler.replacements.amd64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AMD64",
+    },
+
+    "org.graalvm.compiler.hotspot.sparc" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.hotspot",
+        "org.graalvm.compiler.core.sparc",
+        "org.graalvm.compiler.replacements.sparc",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,SPARC",
+    },
+
+    "org.graalvm.compiler.hotspot.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.replacements.test",
+        "org.graalvm.compiler.hotspot",
+      ],
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,Test",
+    },
+
+    "org.graalvm.compiler.hotspot.lir.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.hotspot",
+        "org.graalvm.compiler.lir.jtt",
+        "org.graalvm.compiler.lir.test",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,Test",
+    },
+
+    "org.graalvm.compiler.hotspot.aarch64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.aarch64",
+        "org.graalvm.compiler.hotspot.test",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AArch64,Test",
+    },
+
+    "org.graalvm.compiler.hotspot.amd64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.amd64",
+        "org.graalvm.compiler.hotspot.test",
+        "org.graalvm.compiler.lir.amd64",
+        "org.graalvm.compiler.lir.jtt",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AMD64,Test",
+    },
+
+    "org.graalvm.compiler.nodeinfo" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.nodeinfo.processor" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "dependencies" : [
+        "org.graalvm.compiler.nodeinfo",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.graph" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.nodeinfo",
+        "org.graalvm.compiler.core.common",
+        "org.graalvm.compiler.api.collections",
+      ],
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.graph.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "dependencies" : [
+        "mx:JUNIT",
+        "org.graalvm.compiler.api.test",
+        "org.graalvm.compiler.graph",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Graph,Test",
+    },
+
+    "org.graalvm.compiler.asm" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler",
+    },
+
+    "org.graalvm.compiler.asm.aarch64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.debug",
+        "org.graalvm.compiler.asm",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AArch64",
+    },
+
+    "org.graalvm.compiler.asm.amd64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AMD64",
+    },
+
+    "org.graalvm.compiler.asm.sparc" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.debug",
+        "org.graalvm.compiler.asm",
+        "org.graalvm.compiler.common"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,SPARC",
+    },
+
+    "org.graalvm.compiler.asm.sparc.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.test",
+        "org.graalvm.compiler.asm.sparc",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,SPARC,Test",
+    },
+
+    "org.graalvm.compiler.bytecode" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Java",
+    },
+
+    "org.graalvm.compiler.asm.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.test",
+        "org.graalvm.compiler.code",
+        "org.graalvm.compiler.runtime",
+        "org.graalvm.compiler.test",
+        "org.graalvm.compiler.debug",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,Test",
+    },
+
+    "org.graalvm.compiler.asm.aarch64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.test",
+        "org.graalvm.compiler.asm.aarch64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AArch64,Test",
+    },
+
+    "org.graalvm.compiler.asm.amd64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.test",
+        "org.graalvm.compiler.asm.amd64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AMD64,Test",
+    },
+
+    "org.graalvm.compiler.lir" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm",
+        "org.graalvm.compiler.code",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR",
+    },
+
+    "org.graalvm.compiler.lir.jtt" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.jtt",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR",
+      "findbugs" : "false",
+    },
+
+    "org.graalvm.compiler.lir.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+        "org.graalvm.compiler.lir",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR",
+    },
+
+    "org.graalvm.compiler.lir.aarch64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.lir",
+        "org.graalvm.compiler.asm.aarch64",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR,AArch64",
+    },
+
+    "org.graalvm.compiler.lir.amd64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.lir",
+        "org.graalvm.compiler.asm.amd64",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR,AMD64",
+    },
+
+    "org.graalvm.compiler.lir.sparc" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.asm.sparc",
+        "org.graalvm.compiler.lir",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR,SPARC",
+    },
+
+    "org.graalvm.compiler.word" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.nodes"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "workingSets" : "API,Graal",
+    },
+
+    "org.graalvm.compiler.replacements" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.directives",
+        "org.graalvm.compiler.java",
+        "org.graalvm.compiler.loop.phases",
+        "org.graalvm.compiler.word",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+        "GRAAL_NODEINFO_PROCESSOR",
+      ],
+      "workingSets" : "Graal,Replacements",
+    },
+
+    "org.graalvm.compiler.replacements.aarch64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+          "org.graalvm.compiler.replacements",
+          "org.graalvm.compiler.lir.aarch64",
+          ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+      ],
+      "workingSets" : "Graal,Replacements,AArch64",
+    },
+
+    "org.graalvm.compiler.replacements.amd64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+          "org.graalvm.compiler.replacements",
+          "org.graalvm.compiler.lir.amd64",
+          ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+      ],
+      "workingSets" : "Graal,Replacements,AMD64",
+    },
+
+    "org.graalvm.compiler.replacements.sparc" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+          "org.graalvm.compiler.replacements",
+          ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Replacements,SPARC",
+    },
+
+    "org.graalvm.compiler.replacements.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core.test",
+        "org.graalvm.compiler.replacements",
+      ],
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Replacements,Test",
+      "jacoco" : "exclude",
+    },
+
+    "org.graalvm.compiler.replacements.verifier" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.replacements",
+        "org.graalvm.compiler.graph",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Replacements",
+    },
+
+    "org.graalvm.compiler.nodes" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.replacements",
+        "org.graalvm.compiler.bytecode",
+        "org.graalvm.compiler.lir",
+      ],
+      "generatedDependencies" : ["org.graalvm.compiler.serviceprovider"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+      ],
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.nodes.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.core.test"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.phases" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.nodes"],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Phases",
+    },
+
+    "org.graalvm.compiler.phases.common" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.phases"],
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_OPTIONS_PROCESSOR"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Phases",
+    },
+
+    "org.graalvm.compiler.phases.common.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.test",
+        "org.graalvm.compiler.runtime",
+        "mx:JUNIT",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Test",
+    },
+
+    "org.graalvm.compiler.virtual" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.phases.common"],
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Phases",
+    },
+
+    "org.graalvm.compiler.loop" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.nodes"],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.loop.phases" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+         "org.graalvm.compiler.loop",
+         "org.graalvm.compiler.phases.common",
+       ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Phases",
+    },
+
+    "org.graalvm.compiler.core" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.virtual",
+        "org.graalvm.compiler.loop.phases",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+        "GRAAL_OPTIONS_PROCESSOR",
+      ],
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.core.match.processor" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Codegen",
+    },
+
+    "org.graalvm.compiler.core.aarch64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+        "org.graalvm.compiler.lir.aarch64",
+        "org.graalvm.compiler.java",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_COMPILER_MATCH_PROCESSOR",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AArch64",
+    },
+
+    "org.graalvm.compiler.core.aarch64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.lir.jtt",
+        "org.graalvm.compiler.lir.aarch64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AArch64,Test",
+    },
+
+    "org.graalvm.compiler.core.amd64" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+        "org.graalvm.compiler.lir.amd64",
+        "org.graalvm.compiler.java",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_COMPILER_MATCH_PROCESSOR",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AMD64",
+    },
+
+    "org.graalvm.compiler.core.amd64.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.lir.jtt",
+        "org.graalvm.compiler.lir.amd64",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AMD64,Test",
+    },
+
+    "org.graalvm.compiler.core.sparc" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+        "org.graalvm.compiler.lir.sparc",
+        "org.graalvm.compiler.java"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_COMPILER_MATCH_PROCESSOR",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,SPARC",
+    },
+
+    "org.graalvm.compiler.core.sparc.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.lir.jtt",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,SPARC,Test",
+    },
+
+    "org.graalvm.compiler.runtime" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.core"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "org.graalvm.compiler.java" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.phases",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Java",
+    },
+
+    "org.graalvm.compiler.core.common" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.debug",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Java",
+    },
+
+    "org.graalvm.compiler.printer" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+        "org.graalvm.compiler.java",
+      ],
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR"
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Graph",
+    },
+
+    "org.graalvm.compiler.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Test",
+    },
+
+    "org.graalvm.compiler.core.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.api.directives",
+        "org.graalvm.compiler.java",
+        "org.graalvm.compiler.test",
+        "org.graalvm.compiler.runtime",
+        "org.graalvm.compiler.graph.test",
+        "org.graalvm.compiler.printer",
+        "JAVA_ALLOCATION_INSTRUMENTER",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Test",
+      "jacoco" : "exclude",
+    },
+
+    "org.graalvm.compiler.jtt" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.compiler.core.test",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Test",
+      "jacoco" : "exclude",
+      "findbugs" : "false",
+    },
+
+    # ------------- Salver -------------
+
+    "org.graalvm.compiler.salver" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["org.graalvm.compiler.phases"],
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
+      "checkstyle" : "org.graalvm.compiler.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    # ------------- AOT -------------
+
+    "jdk.tools.jaotc" : {
+      "subDir" : "../jdk.aot/share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "jdk.tools.jaotc.binformat",
+        "org.graalvm.compiler.asm.amd64",
+      ],
+      "checkstyle" : "jdk.tools.jaotc",
+      "javaCompliance" : "1.8",
+    },
+
+    "jdk.tools.jaotc.test" : {
+      "subDir" : "../../test/compiler/aot",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+        "jdk.tools.jaotc",
+      ],
+      "checkstyle" : "jdk.tools.jaotc",
+      "javaCompliance" : "1.8",
+    },
+
+    "jdk.tools.jaotc.binformat" : {
+      "subDir" : "../jdk.aot/share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "jdk.tools.jaotc.jnilibelf",
+      ],
+      "generatedDependencies" : [
+        "org.graalvm.compiler.hotspot",
+      ],
+      "checkstyle" : "jdk.tools.jaotc",
+      "javaCompliance" : "1.8",
+    },
+
+    "jdk.tools.jaotc.jnilibelf" : {
+      "subDir" : "../jdk.aot/share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [],
+      "checkstyle" : "jdk.tools.jaotc",
+      "javaCompliance" : "1.8",
+    },
+
+    "jdk.tools.jaotc.jnilibelf.test" : {
+      "subDir" : "../../test/compiler/aot",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "jdk.tools.jaotc.jnilibelf",
+      ],
+      "checkstyle" : "jdk.tools.jaotc",
+      "javaCompliance" : "1.8",
+    },
+
+  },
+
+  "distributions" : {
+
+    # ------------- Distributions -------------
+
+    "GRAAL_OPTIONS" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.options"],
+      "distDependencies" : [
+      ],
+    },
+
+    "GRAAL_OPTIONS_PROCESSOR" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.options.processor"],
+      "distDependencies" : [
+        "GRAAL_OPTIONS",
+      ],
+    },
+
+    "GRAAL_NODEINFO" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.nodeinfo",
+      ],
+    },
+
+    "GRAAL_SERVICEPROVIDER" : {
+      "subDir" : "graal",
+      "dependencies" : ["org.graalvm.compiler.serviceprovider"],
+      "distDependencies" : [
+        "GRAAL_NODEINFO",
+      ],
+    },
+
+    "GRAAL_API" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.api.replacements",
+        "org.graalvm.compiler.api.runtime",
+        "org.graalvm.compiler.graph",
+      ],
+      "distDependencies" : [
+        "GRAAL_NODEINFO",
+        "GRAAL_OPTIONS",
+        "GRAAL_SERVICEPROVIDER",
+      ],
+    },
+
+    "GRAAL_COMPILER" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.core",
+      ],
+      "distDependencies" : [
+        "GRAAL_API",
+        "GRAAL_SERVICEPROVIDER",
+      ],
+    },
+
+    "GRAAL_RUNTIME" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.replacements",
+        "org.graalvm.compiler.runtime",
+        "org.graalvm.compiler.code",
+        "org.graalvm.compiler.printer",
+        "org.graalvm.compiler.core.aarch64",
+        "org.graalvm.compiler.replacements.aarch64",
+        "org.graalvm.compiler.core.amd64",
+        "org.graalvm.compiler.replacements.amd64",
+        "org.graalvm.compiler.core.sparc",
+        "org.graalvm.compiler.replacements.sparc",
+        "org.graalvm.compiler.salver",
+      ],
+      "distDependencies" : [
+        "GRAAL_API",
+        "GRAAL_COMPILER",
+      ],
+    },
+
+    "GRAAL_HOTSPOT" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.hotspot.aarch64",
+        "org.graalvm.compiler.hotspot.amd64",
+        "org.graalvm.compiler.hotspot.sparc",
+        "org.graalvm.compiler.hotspot",
+      ],
+      "distDependencies" : [
+        "GRAAL_COMPILER",
+        "GRAAL_RUNTIME",
+      ],
+    },
+
+    "GRAAL_TEST" : {
+      "subDir" : "share/classes",
+      "dependencies" : [
+        "org.graalvm.compiler.api.test",
+        "org.graalvm.compiler.api.directives.test",
+        "org.graalvm.compiler.asm.sparc.test",
+        "org.graalvm.compiler.asm.aarch64.test",
+        "org.graalvm.compiler.asm.amd64.test",
+        "org.graalvm.compiler.core.aarch64.test",
+        "org.graalvm.compiler.core.amd64.test",
+        "org.graalvm.compiler.core.sparc.test",
+        "org.graalvm.compiler.debug.test",
+        "org.graalvm.compiler.hotspot.aarch64.test",
+        "org.graalvm.compiler.hotspot.amd64.test",
+        "org.graalvm.compiler.hotspot.lir.test",
+        "org.graalvm.compiler.options.test",
+        "org.graalvm.compiler.jtt",
+        "org.graalvm.compiler.lir.jtt",
+        "org.graalvm.compiler.lir.test",
+        "org.graalvm.compiler.nodes.test",
+        "org.graalvm.compiler.phases.common.test",
+      ],
+      "distDependencies" : [
+        "GRAAL_HOTSPOT",
+      ],
+      "exclude" : [
+        "mx:JUNIT",
+        "JAVA_ALLOCATION_INSTRUMENTER",
+      ],
+    },
+
+    "GRAAL_SERVICEPROVIDER" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.serviceprovider"],
+      "distDependencies" : [
+        "GRAAL_NODEINFO",
+      ],
+    },
+
+    "GRAAL_SERVICEPROVIDER_PROCESSOR" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.serviceprovider.processor"],
+      "distDependencies" : [
+        "GRAAL_SERVICEPROVIDER",
+      ],
+    },
+
+    "GRAAL_NODEINFO_PROCESSOR" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.nodeinfo.processor"],
+      "distDependencies" : [
+        "GRAAL_NODEINFO",
+      ],
+    },
+
+    "GRAAL_REPLACEMENTS_VERIFIER" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.replacements.verifier"],
+      "distDependencies" : [
+        "GRAAL_API",
+        "GRAAL_SERVICEPROVIDER",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
+    },
+
+    "GRAAL_COMPILER_MATCH_PROCESSOR" : {
+      "subDir" : "share/classes",
+      "dependencies" : ["org.graalvm.compiler.core.match.processor"],
+      "distDependencies" : [
+        "GRAAL_COMPILER",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ]
+    },
+
+    "GRAAL" : {
+      "subDir" : "share/classes",
+      "overlaps" : [
+        "GRAAL_OPTIONS",
+        "GRAAL_NODEINFO",
+        "GRAAL_API",
+        "GRAAL_COMPILER",
+        "GRAAL_RUNTIME",
+        "GRAAL_HOTSPOT",
+        "GRAAL_SERVICEPROVIDER",
+      ],
+      "dependencies" : [
+        "org.graalvm.compiler.options",
+        "org.graalvm.compiler.nodeinfo",
+        "org.graalvm.compiler.api.replacements",
+        "org.graalvm.compiler.api.runtime",
+        "org.graalvm.compiler.graph",
+        "org.graalvm.compiler.core",
+        "org.graalvm.compiler.replacements",
+        "org.graalvm.compiler.runtime",
+        "org.graalvm.compiler.code",
+        "org.graalvm.compiler.printer",
+        "org.graalvm.compiler.core.aarch64",
+        "org.graalvm.compiler.replacements.aarch64",
+        "org.graalvm.compiler.core.amd64",
+        "org.graalvm.compiler.replacements.amd64",
+        "org.graalvm.compiler.core.sparc",
+        "org.graalvm.compiler.replacements.sparc",
+        "org.graalvm.compiler.salver",
+        "org.graalvm.compiler.hotspot.aarch64",
+        "org.graalvm.compiler.hotspot.amd64",
+        "org.graalvm.compiler.hotspot.sparc",
+        "org.graalvm.compiler.hotspot",
+      ],
+      "distDependencies" : [
+      ]
+    },
+
+
+  },
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/module-info.java b/hotspot/src/jdk.vm.compiler/share/classes/module-info.java
new file mode 100644
index 0000000..7c45648
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/module-info.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.vm.compiler {
+    requires java.instrument;
+    requires java.management;
+    requires jdk.management;
+    requires jdk.vm.ci;
+
+    // sun.misc.Unsafe is used
+    requires jdk.unsupported;
+
+    uses org.graalvm.compiler.code.DisassemblerProvider;
+    uses org.graalvm.compiler.core.match.MatchStatementSet;
+    uses org.graalvm.compiler.debug.DebugConfigCustomizer;
+    uses org.graalvm.compiler.debug.DebugInitializationParticipant;
+    uses org.graalvm.compiler.debug.TTYStreamProvider;
+    uses org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
+    uses org.graalvm.compiler.hotspot.HotSpotBackendFactory;
+    uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
+
+    exports org.graalvm.compiler.api.directives         to jdk.aot;
+    exports org.graalvm.compiler.api.runtime            to jdk.aot;
+    exports org.graalvm.compiler.api.replacements       to jdk.aot;
+    exports org.graalvm.compiler.asm.amd64              to jdk.aot;
+    exports org.graalvm.compiler.bytecode               to jdk.aot;
+    exports org.graalvm.compiler.code                   to jdk.aot;
+    exports org.graalvm.compiler.core                   to jdk.aot;
+    exports org.graalvm.compiler.core.common            to jdk.aot;
+    exports org.graalvm.compiler.core.target            to jdk.aot;
+    exports org.graalvm.compiler.debug                  to jdk.aot;
+    exports org.graalvm.compiler.debug.internal         to jdk.aot;
+    exports org.graalvm.compiler.graph                  to jdk.aot;
+    exports org.graalvm.compiler.hotspot                to jdk.aot;
+    exports org.graalvm.compiler.hotspot.meta           to jdk.aot;
+    exports org.graalvm.compiler.hotspot.replacements   to jdk.aot;
+    exports org.graalvm.compiler.hotspot.stubs          to jdk.aot;
+    exports org.graalvm.compiler.hotspot.word           to jdk.aot;
+    exports org.graalvm.compiler.java                   to jdk.aot;
+    exports org.graalvm.compiler.lir.asm                to jdk.aot;
+    exports org.graalvm.compiler.lir.phases             to jdk.aot;
+    exports org.graalvm.compiler.nodes                  to jdk.aot;
+    exports org.graalvm.compiler.nodes.graphbuilderconf to jdk.aot;
+    exports org.graalvm.compiler.options                to jdk.aot;
+    exports org.graalvm.compiler.phases                 to jdk.aot;
+    exports org.graalvm.compiler.phases.tiers           to jdk.aot;
+    exports org.graalvm.compiler.runtime                to jdk.aot;
+    exports org.graalvm.compiler.replacements           to jdk.aot;
+    exports org.graalvm.compiler.word                   to jdk.aot;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/CollectionsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/CollectionsProvider.java
new file mode 100644
index 0000000..f8c0088
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/CollectionsProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.collections;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A factory for creating collections.
+ */
+public interface CollectionsProvider {
+
+    /**
+     * Creates a set that uses reference-equality in place of object-equality when comparing
+     * entries.
+     */
+    <E> Set<E> newIdentitySet();
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     */
+    <K, V> Map<K, V> newIdentityMap();
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     *
+     * @param expectedMaxSize the expected maximum size of the map
+     */
+    <K, V> Map<K, V> newIdentityMap(int expectedMaxSize);
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     *
+     * @param initFrom the returned map is populated with the entries in this map
+     */
+    <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/DefaultCollectionsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/DefaultCollectionsProvider.java
new file mode 100644
index 0000000..d334560
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.collections/src/org/graalvm/compiler/api/collections/DefaultCollectionsProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.collections;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A default implementation of {@link CollectionsProvider} that creates standard JDK collection
+ * class objects.
+ */
+public class DefaultCollectionsProvider implements CollectionsProvider {
+
+    @Override
+    public <E> Set<E> newIdentitySet() {
+        return Collections.newSetFromMap(newIdentityMap());
+    }
+
+    @Override
+    public <K, V> Map<K, V> newIdentityMap() {
+        return new IdentityHashMap<>();
+    }
+
+    @Override
+    public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
+        return new IdentityHashMap<>(expectedMaxSize);
+    }
+
+    @Override
+    public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
+        return new IdentityHashMap<>(initFrom);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/AllocationInstrumentationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/AllocationInstrumentationTest.java
new file mode 100644
index 0000000..03bd8a7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/AllocationInstrumentationTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@SuppressWarnings("try")
+public class AllocationInstrumentationTest extends GraalCompilerTest {
+
+    private TinyInstrumentor instrumentor;
+
+    public AllocationInstrumentationTest() {
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
+        method.setNotInlineable();
+
+        try {
+            instrumentor = new TinyInstrumentor(AllocationInstrumentationTest.class, "instrumentation");
+        } catch (IOException e) {
+            Assert.fail("unable to initialize the instrumentor: " + e);
+        }
+    }
+
+    public static class ClassA {
+        // This method should be marked as not inlineable
+        public void notInlinedMethod() {
+        }
+    }
+
+    public static boolean allocationWasExecuted;
+
+    private static void resetFlag() {
+        allocationWasExecuted = false;
+    }
+
+    static void instrumentation() {
+        GraalDirectives.instrumentationBeginForPredecessor();
+        allocationWasExecuted = true;
+        GraalDirectives.instrumentationEnd();
+    }
+
+    public static void notEscapeSnippet() {
+        @SuppressWarnings("unused")
+        ClassA a = new ClassA(); // a does not escape
+    }
+
+    @Test
+    public void testNotEscape() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "notEscapeSnippet", Opcodes.NEW);
+            ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "notEscapeSnippet");
+            executeExpected(method, null); // ensure the method is fully resolved
+            resetFlag();
+            // The allocation in the snippet does not escape and will be optimized away. We expect
+            // the instrumentation is removed.
+            InstalledCode code = getCode(method);
+            code.executeVarargs();
+            Assert.assertFalse("allocation should not take place", allocationWasExecuted);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static void mustEscapeSnippet() {
+        ClassA a = new ClassA();
+        a.notInlinedMethod(); // a escapses
+    }
+
+    @Test
+    public void testMustEscape() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "mustEscapeSnippet", Opcodes.NEW);
+            ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "mustEscapeSnippet");
+            executeExpected(method, null); // ensure the method is fully resolved
+            resetFlag();
+            // The allocation in the snippet escapes. We expect the instrumentation is preserved.
+            InstalledCode code = getCode(method);
+            code.executeVarargs();
+            Assert.assertTrue("allocation should take place", allocationWasExecuted);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static void partialEscapeSnippet(boolean condition) {
+        ClassA a = new ClassA();
+
+        if (condition) {
+            a.notInlinedMethod(); // a escapes in the then-clause
+        }
+    }
+
+    @Test
+    public void testPartialEscape() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "partialEscapeSnippet", Opcodes.NEW);
+            ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "partialEscapeSnippet");
+            executeExpected(method, null, true); // ensure the method is fully resolved
+            resetFlag();
+            // The allocation in the snippet escapes in the then-clause, and will be relocated to
+            // this branch. We expect the instrumentation follows and will only be effective when
+            // the then-clause is taken.
+            InstalledCode code = getCode(method);
+            code.executeVarargs(false);
+            Assert.assertFalse("allocation should not take place", allocationWasExecuted);
+            code.executeVarargs(true);
+            Assert.assertTrue("allocation should take place", allocationWasExecuted);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java
new file mode 100644
index 0000000..e6ed6ec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * Tests for {@link GraalDirectives#blackhole}.
+ *
+ * There are two snippets for each kind:
+ * <ul>
+ * <li>blackhole&lt;Kind&gt;Snippet verifies that dead code elimination is prevented by the
+ * blackhole directive.
+ * <li>&lt;kind&gt;Snippet verifies that dead code elimination does happen if the blackhole
+ * directive is not there.
+ * </ul>
+ *
+ */
+public class BlackholeDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface BlackholeSnippet {
+        boolean expectParameterUsage();
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int booleanSnippet(int arg) {
+        boolean b = arg > 3;
+        if (b) {
+            return 1;
+        } else {
+            return 1;
+        }
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeBooleanSnippet(int arg) {
+        boolean b = arg > 3;
+        GraalDirectives.blackhole(b);
+        if (b) {
+            return 1;
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testBoolean() {
+        test("booleanSnippet", 5);
+        test("blackholeBooleanSnippet", 5);
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int intSnippet(int arg) {
+        int x = 42 + arg;
+        return x - arg;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeIntSnippet(int arg) {
+        int x = 42 + arg;
+        GraalDirectives.blackhole(x);
+        return x - arg;
+    }
+
+    @Test
+    public void testInt() {
+        test("intSnippet", 17);
+        test("blackholeIntSnippet", 17);
+    }
+
+    private static class Dummy {
+        private int x = 42;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = false)
+    public static int objectSnippet(int arg) {
+        Dummy obj = new Dummy();
+        int ret = obj.x;
+        obj.x = arg;
+        return ret;
+    }
+
+    @BlackholeSnippet(expectParameterUsage = true)
+    public static int blackholeObjectSnippet(int arg) {
+        Dummy obj = new Dummy();
+        int ret = obj.x;
+        obj.x = arg;
+        GraalDirectives.blackhole(obj);
+        return ret;
+    }
+
+    @Test
+    public void testObject() {
+        test("objectSnippet", 37);
+        test("blackholeObjectSnippet", 37);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);
+        ParameterNode arg = graph.getParameter(0);
+        if (snippet.expectParameterUsage()) {
+            Assert.assertNotNull("couldn't find ParameterNode(0)", arg);
+            Assert.assertFalse("expected usages of " + arg, arg.hasNoUsages());
+        } else {
+            Assert.assertTrue("expected no usages of ParameterNode", arg == null || arg.hasNoUsages());
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java
new file mode 100644
index 0000000..57eaeef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    @Repeatable(AnchorSnippet.class)
+    private @interface NodeCount {
+
+        Class<? extends Node> nodeClass();
+
+        int expectedCount();
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface AnchorSnippet {
+        NodeCount[] value();
+    }
+
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
+    public static int verifyMergeSnippet(int arg) {
+        if (arg > 5) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2)
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
+    public static int preventMergeSnippet(int arg) {
+        if (arg > 5) {
+            GraalDirectives.controlFlowAnchor();
+            return 1;
+        } else {
+            GraalDirectives.controlFlowAnchor();
+            return 2;
+        }
+    }
+
+    @Test
+    public void testMerge() {
+        test("verifyMergeSnippet", 42);
+        test("preventMergeSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
+    public static int verifyDuplicateSnippet(int arg) {
+        int ret;
+        if (arg > 5) {
+            ret = 17;
+        } else {
+            ret = arg;
+        }
+        return 42 / ret;
+    }
+
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
+    public static int preventDuplicateSnippet(int arg) {
+        int ret;
+        if (arg > 5) {
+            ret = 17;
+        } else {
+            ret = arg;
+        }
+        GraalDirectives.controlFlowAnchor();
+        return 42 / ret;
+    }
+
+    @Test
+    public void testDuplicate() {
+        // test("verifyDuplicateSnippet", 42);
+        test("preventDuplicateSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0)
+    public static int verifyFullUnrollSnippet(int arg) {
+        int ret = arg;
+        for (int i = 0; i < 5; i++) {
+            ret = ret * 3 + 1;
+        }
+        return ret;
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
+    public static int preventFullUnrollSnippet(int arg) {
+        int ret = arg;
+        for (int i = 0; i < 5; i++) {
+            GraalDirectives.controlFlowAnchor();
+            ret = ret * 3 + 1;
+        }
+        return ret;
+    }
+
+    @Test
+    public void testFullUnroll() {
+        test("verifyFullUnrollSnippet", 42);
+        test("preventFullUnrollSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = IfNode.class, expectedCount = 4)
+    public static void verifyPeelSnippet(int arg) {
+        int ret = arg;
+        while (ret > 1) {
+            if (ret % 2 == 0) {
+                ret /= 2;
+            } else {
+                ret = 3 * ret + 1;
+            }
+        }
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = IfNode.class, expectedCount = 2)
+    public static void preventPeelSnippet(int arg) {
+        int ret = arg;
+        while (ret > 1) {
+            GraalDirectives.controlFlowAnchor();
+            if (ret % 2 == 0) {
+                GraalDirectives.controlFlowAnchor();
+                ret /= 2;
+            } else {
+                ret = 3 * ret + 1;
+            }
+        }
+    }
+
+    @Test
+    public void testPeel() {
+        test("preventPeelSnippet", 42);
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 2)
+    public static void verifyUnswitchSnippet(int arg, boolean flag) {
+        int ret = arg;
+        while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) {
+            if (flag) {
+                ret = ret * 2 + 1;
+            } else {
+                ret = ret * 3 + 1;
+            }
+        }
+    }
+
+    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
+    @NodeCount(nodeClass = IfNode.class, expectedCount = 2)
+    public static void preventUnswitchSnippet(int arg, boolean flag) {
+        int ret = arg;
+        while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) {
+            if (flag) {
+                GraalDirectives.controlFlowAnchor();
+                ret++;
+            } else {
+                ret += 2;
+            }
+        }
+    }
+
+    @Test
+    public void testUnswitch() {
+        test("verifyUnswitchSnippet", 0, false);
+        test("preventUnswitchSnippet", 0, false);
+    }
+
+    /**
+     * Cloning a ControlFlowAnchorNode is not allowed but cloning a whole graph containing one is
+     * ok.
+     */
+    @Test
+    public void testClone() {
+        StructuredGraph g = parseEager("preventPeelSnippet", AllowAssumptions.NO);
+        g.copy();
+    }
+
+    private static List<NodeCount> getNodeCountAnnotations(StructuredGraph graph) {
+        ResolvedJavaMethod method = graph.method();
+        AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class);
+        if (snippet != null) {
+            return Arrays.asList(snippet.value());
+        }
+
+        NodeCount single = method.getAnnotation(NodeCount.class);
+        if (single != null) {
+            return Collections.singletonList(single);
+        }
+
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
+        for (int i = 0; i < anchors.size(); i++) {
+            ControlFlowAnchorNode a = anchors.get(i);
+            for (int j = i + 1; j < anchors.size(); j++) {
+                ControlFlowAnchorNode b = anchors.get(j);
+                if (a.valueEquals(b)) {
+                    Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")");
+                }
+            }
+        }
+
+        for (NodeCount nodeCount : getNodeCountAnnotations(graph)) {
+            NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass());
+            Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count());
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/DeoptimizeDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/DeoptimizeDirectiveTest.java
new file mode 100644
index 0000000..91a14d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/DeoptimizeDirectiveTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+public class DeoptimizeDirectiveTest extends GraalCompilerTest {
+
+    public static boolean inCompiledCode() {
+        return GraalDirectives.inCompiledCode();
+    }
+
+    @Test
+    public void testInCompiledCode() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("inCompiledCode");
+
+        Result interpreted = executeExpected(method, null);
+        assertEquals(new Result(false, null), interpreted);
+
+        Result compiled = executeActual(method, null);
+        assertEquals(new Result(true, null), compiled);
+    }
+
+    public static boolean deoptimizeSnippet() {
+        GraalDirectives.deoptimize();
+        return GraalDirectives.inCompiledCode(); // should always return false
+    }
+
+    public static boolean deoptimizeAndInvalidateSnippet() {
+        GraalDirectives.deoptimizeAndInvalidate();
+        return GraalDirectives.inCompiledCode(); // should always return false
+    }
+
+    @Test
+    public void testDeoptimize() {
+        test("deoptimizeSnippet");
+    }
+
+    private boolean testDeoptimizeCheckValid(ResolvedJavaMethod method) {
+        Result expected = executeExpected(method, null);
+
+        InstalledCode code = getCode(method);
+        Result actual;
+        try {
+            actual = new Result(code.executeVarargs(), null);
+        } catch (Throwable e) {
+            actual = new Result(null, e);
+        }
+
+        assertEquals(expected, actual);
+        return code.isValid();
+    }
+
+    @Test
+    public void testDeoptimizeAndInvalidate() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeAndInvalidateSnippet");
+        boolean valid = testDeoptimizeCheckValid(method);
+        Assert.assertFalse("code should be invalidated", valid);
+    }
+
+    @Test
+    public void testDeoptimizeDontInvalidate() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeSnippet");
+        boolean valid = testDeoptimizeCheckValid(method);
+        Assert.assertTrue("code should still be valid", valid);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IsMethodInlineDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IsMethodInlineDirectiveTest.java
new file mode 100644
index 0000000..48a1f10
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IsMethodInlineDirectiveTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class IsMethodInlineDirectiveTest extends GraalCompilerTest {
+
+    public IsMethodInlineDirectiveTest() {
+        HotSpotResolvedJavaMethod calleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeSnippet");
+        calleeSnippet.shouldBeInlined();
+
+        HotSpotResolvedJavaMethod calleeWithInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeWithInstrumentationSnippet");
+        calleeWithInstrumentationSnippet.shouldBeInlined();
+    }
+
+    public static boolean rootMethodSnippet() {
+        return GraalDirectives.isMethodInlined();
+    }
+
+    @SuppressWarnings("try")
+    @Test
+    public void testRootMethod() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("rootMethodSnippet");
+        executeExpected(method, null); // ensure the method is fully resolved
+        // The target method is not inlined. We expect the result to be false.
+        InstalledCode code = getCode(method);
+        try {
+            Result result = new Result(code.executeVarargs(), null);
+            assertEquals(new Result(false, null), result);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static boolean calleeSnippet() {
+        return GraalDirectives.isMethodInlined();
+    }
+
+    public static boolean callerSnippet() {
+        return calleeSnippet();
+    }
+
+    @Test
+    public void testInlinedCallee() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
+        executeExpected(method, null); // ensure the method is fully resolved
+        // calleeSnippet will be inlined. We expect the result to be true.
+        InstalledCode code = getCode(method);
+        try {
+            Result result = new Result(code.executeVarargs(), null);
+            assertEquals(new Result(true, null), result);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    static boolean isCalleeInlined;
+    static boolean isCallerInlined;
+
+    public static void calleeWithInstrumentationSnippet() {
+        GraalDirectives.instrumentationBegin();
+        isCalleeInlined = GraalDirectives.isMethodInlined();
+        GraalDirectives.instrumentationEnd();
+    }
+
+    public static void callerSnippet1() {
+        calleeWithInstrumentationSnippet();
+
+        GraalDirectives.instrumentationBegin();
+        isCallerInlined = GraalDirectives.isMethodInlined();
+        GraalDirectives.instrumentationEnd();
+    }
+
+    @SuppressWarnings("try")
+    @Test
+    public void testInlinedCalleeWithInstrumentation() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
+            executeExpected(method, null); // ensure the method is fully resolved
+            isCalleeInlined = false;
+            isCallerInlined = false;
+            // calleeWithInstrumentationSnippet will be inlined. We expect the flag1 set in
+            // calleeWithInstrumentationSnippet to be true, and the flag2 set in callerSnippet1 to
+            // be false.
+            InstalledCode code = getCode(method);
+            code.executeVarargs();
+            assertTrue("calleWithInstrumentationSnippet should be inlined", isCalleeInlined);
+            assertFalse("callerSnippet1 should not be inlined", isCallerInlined);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java
new file mode 100644
index 0000000..651f33e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public class IterationDirectiveTest extends GraalCompilerTest {
+
+    public static int loopFrequencySnippet(int arg) {
+        int x = arg;
+        while (GraalDirectives.injectIterationCount(128, x > 1)) {
+            GraalDirectives.controlFlowAnchor(); // prevent loop peeling or unrolling
+            if (x % 2 == 0) {
+                x /= 2;
+            } else {
+                x = 3 * x + 1;
+            }
+        }
+        return x;
+    }
+
+    @Test
+    public void testLoopFrequency() {
+        test("loopFrequencySnippet", 7);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.TYPE);
+        Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count());
+
+        LoopBeginNode loopBeginNode = loopBeginNodes.first();
+        Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0);
+
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/LockInstrumentationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/LockInstrumentationTest.java
new file mode 100644
index 0000000..244e2d6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/LockInstrumentationTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@SuppressWarnings("try")
+public class LockInstrumentationTest extends GraalCompilerTest {
+
+    private TinyInstrumentor instrumentor;
+
+    public LockInstrumentationTest() {
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
+        method.setNotInlineable();
+
+        try {
+            instrumentor = new TinyInstrumentor(LockInstrumentationTest.class, "instrumentation");
+        } catch (IOException e) {
+            Assert.fail("unable to initialize the instrumentor: " + e);
+        }
+    }
+
+    public static class ClassA {
+
+        // This method should be marked as not inlineable
+        public void notInlinedMethod() {
+        }
+
+    }
+
+    public static final Object lock = new Object();
+    public static boolean lockAfterCheckPoint;
+    public static boolean checkpoint;
+
+    private static void resetFlags() {
+        lockAfterCheckPoint = false;
+        checkpoint = false;
+    }
+
+    static void instrumentation() {
+        GraalDirectives.instrumentationBeginForPredecessor();
+        lockAfterCheckPoint = checkpoint;
+        GraalDirectives.instrumentationEnd();
+    }
+
+    public static void lockSnippet() {
+        synchronized (lock) {
+            checkpoint = true;
+            ClassA a = new ClassA();
+            a.notInlinedMethod();
+        }
+    }
+
+    @Test
+    public void testLock() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "lockSnippet", Opcodes.MONITORENTER);
+            ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "lockSnippet");
+            executeExpected(method, null); // ensure the method is fully resolved
+            resetFlags();
+            // The monitorenter anchors. We expect the instrumentation set the flag before passing
+            // the checkpoint.
+            InstalledCode code = getCode(method);
+            code.executeVarargs();
+            Assert.assertFalse("expected lock was performed before checkpoint", lockAfterCheckPoint);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static void postponeLockSnippet() {
+        ClassA a = new ClassA();
+
+        synchronized (a) {
+            checkpoint = true;
+            a.notInlinedMethod();
+        }
+
+    }
+
+    @Test
+    public void testNonEscapeLock() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "postponeLockSnippet", Opcodes.MONITORENTER);
+            ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "postponeLockSnippet");
+            executeExpected(method, null); // ensure the method is fully resolved
+            resetFlags();
+            // The lock in the snippet will be relocated before the invocation to
+            // notInlinedMethod(), i.e., after the checkpoint. We expect the instrumentation follows
+            // and flag will be set to true.
+            InstalledCode code = getCode(method);
+            code.executeVarargs();
+            Assert.assertTrue("expected lock was performed after checkpoint", lockAfterCheckPoint);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java
new file mode 100644
index 0000000..64e9cc4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+
+/**
+ * Tests for {@link GraalDirectives#opaque}.
+ *
+ * There are two snippets for each kind:
+ * <ul>
+ * <li>opaque&lt;Kind&gt;Snippet verifies that constant folding is prevented by the opaque
+ * directive.
+ * <li>&lt;kind&gt;Snippet verifies that constant folding does happen if the opaque directive is not
+ * there.
+ * </ul>
+ *
+ */
+public class OpaqueDirectiveTest extends GraalCompilerTest {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    private @interface OpaqueSnippet {
+        Class<?> expectedReturnNode();
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static boolean booleanSnippet() {
+        return 5 > 3;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
+    public static boolean opaqueBooleanSnippet() {
+        return 5 > GraalDirectives.opaque(3);
+    }
+
+    @Test
+    public void testBoolean() {
+        test("booleanSnippet");
+        test("opaqueBooleanSnippet");
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static int intSnippet() {
+        return 5 + 3;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = AddNode.class)
+    public static int opaqueIntSnippet() {
+        return 5 + GraalDirectives.opaque(3);
+    }
+
+    @Test
+    public void testInt() {
+        test("intSnippet");
+        test("opaqueIntSnippet");
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static double doubleSnippet() {
+        return 5. + 3.;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = AddNode.class)
+    public static double opaqueDoubleSnippet() {
+        return 5. + GraalDirectives.opaque(3.);
+    }
+
+    @Test
+    public void testDouble() {
+        test("doubleSnippet");
+        test("opaqueDoubleSnippet");
+    }
+
+    private static class Dummy {
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConstantNode.class)
+    public static boolean objectSnippet() {
+        Object obj = new Dummy();
+        return obj == null;
+    }
+
+    @OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
+    public static boolean opaqueObjectSnippet() {
+        Object obj = new Dummy();
+        return GraalDirectives.opaque(obj) == null;
+    }
+
+    @Test
+    public void testObject() {
+        test("objectSnippet");
+        test("opaqueObjectSnippet");
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
+            Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass());
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java
new file mode 100644
index 0000000..fe5ef07
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public class ProbabilityDirectiveTest extends GraalCompilerTest {
+
+    public static int branchProbabilitySnippet(int arg) {
+        if (GraalDirectives.injectBranchProbability(0.125, arg > 0)) {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 1;
+        } else {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 2;
+        }
+    }
+
+    @Test
+    public void testBranchProbability() {
+        test("branchProbabilitySnippet", 5);
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
+        Assert.assertEquals("IfNode count", 1, ifNodes.count());
+
+        IfNode ifNode = ifNodes.first();
+        AbstractBeginNode trueSuccessor = ifNode.trueSuccessor();
+        Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0);
+
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/RootNameDirectiveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/RootNameDirectiveTest.java
new file mode 100644
index 0000000..a22ac2e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/RootNameDirectiveTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Objects;
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.printer.IdealGraphPrinter;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class RootNameDirectiveTest extends GraalCompilerTest {
+
+    public RootNameDirectiveTest() {
+        HotSpotResolvedJavaMethod rootNameAtCalleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameAtCalleeSnippet");
+        rootNameAtCalleeSnippet.shouldBeInlined();
+
+        HotSpotResolvedJavaMethod rootNameWithinInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameWithinInstrumentationSnippet");
+        rootNameWithinInstrumentationSnippet.shouldBeInlined();
+    }
+
+    private static String toString(ResolvedJavaMethod method) {
+        return method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor();
+    }
+
+    public static String rootNameSnippet() {
+        return GraalDirectives.rootName();
+    }
+
+    @Test
+    public void testRootName() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("rootNameSnippet");
+        executeExpected(method, null); // ensure the method is fully resolved
+        // The target snippet is already the root method. We expect the name of the target snippet
+        // is returned.
+        InstalledCode code = getCode(method);
+        try {
+            Result result = new Result(code.executeVarargs(), null);
+            assertEquals(new Result(toString(method), null), result);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static String rootNameAtCalleeSnippet() {
+        return GraalDirectives.rootName();
+    }
+
+    public static String callerSnippet() {
+        return rootNameAtCalleeSnippet();
+    }
+
+    @Test
+    public void testRootNameAtCallee() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
+        executeExpected(method, null); // ensure the method is fully resolved
+        // The target snippet is the compilation root of rootNameAtCalleeSnippet() because the later
+        // will be inlined. We expect the name of the target snippet is returned.
+        InstalledCode code = getCode(method);
+        try {
+            Result result = new Result(code.executeVarargs(), null);
+            assertEquals(new Result(toString(method), null), result);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    static String rootNameInCallee;
+    static String rootNameInCaller;
+
+    @BytecodeParserForceInline
+    public static void rootNameWithinInstrumentationSnippet() {
+        GraalDirectives.instrumentationBegin();
+        rootNameInCallee = GraalDirectives.rootName();
+        GraalDirectives.instrumentationEnd();
+    }
+
+    public static void callerSnippet1() {
+        rootNameWithinInstrumentationSnippet();
+
+        GraalDirectives.instrumentationBegin();
+        rootNameInCaller = GraalDirectives.rootName();
+        GraalDirectives.instrumentationEnd();
+    }
+
+    @SuppressWarnings("try")
+    private void assertEquals(StructuredGraph graph, InstalledCode code, Object expected, Object actual) {
+        if (!Objects.equal(expected, actual)) {
+            Formatter buf = new Formatter();
+
+            try (Scope s = Debug.sandbox("PrintingGraph", null)) {
+                Map<Object, Object> properties = new HashMap<>();
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                IdealGraphPrinter printer = new IdealGraphPrinter(baos, true, getSnippetReflection());
+                printer.beginGroup("RootNameDirectiveTest", "RootNameDirectiveTest", graph.method(), -1, null);
+                properties.put("graph", graph.toString());
+                properties.put("scope", Debug.currentScope());
+                printer.print(graph, graph.method().format("%H.%n(%p)"), properties);
+                printer.endGroup();
+                printer.close();
+                buf.format("-- Graph -- %n%s", baos.toString());
+            } catch (Throwable e) {
+                buf.format("%nError printing graph: %s", e);
+            }
+            try {
+                CodeCacheProvider codeCache = getCodeCache();
+                Method disassemble = codeCache.getClass().getMethod("disassemble", InstalledCode.class);
+                buf.format("%n-- Code -- %n%s", disassemble.invoke(codeCache, code));
+            } catch (NoSuchMethodException e) {
+                // Not a HotSpotCodeCacheProvider
+            } catch (Exception e) {
+                buf.format("%nError disassembling code: %s", e);
+            }
+            Assert.assertEquals(buf.toString(), expected, actual);
+        }
+    }
+
+    @SuppressWarnings("try")
+    @Test
+    public void testRootNameWithinInstrumentationAtCallee() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
+            ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
+            executeExpected(method, null); // ensure the method is fully resolved
+            rootNameInCallee = null;
+            rootNameInCaller = null;
+            // We expect both rootName1 and rootName2 are set to the name of the target snippet.
+            StructuredGraph graph = parseForCompile(method);
+            InstalledCode code = getCode(method, graph);
+            code.executeVarargs();
+            assertEquals(graph, code, toString(method), rootNameInCallee);
+            assertEquals(graph, code, rootNameInCallee, rootNameInCaller);
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/TinyInstrumentor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/TinyInstrumentor.java
new file mode 100644
index 0000000..d8cf15a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/TinyInstrumentor.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives.test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.test.ExportingClassLoader;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
+import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
+import jdk.internal.org.objectweb.asm.tree.InsnList;
+import jdk.internal.org.objectweb.asm.tree.JumpInsnNode;
+import jdk.internal.org.objectweb.asm.tree.LabelNode;
+import jdk.internal.org.objectweb.asm.tree.LineNumberNode;
+import jdk.internal.org.objectweb.asm.tree.MethodNode;
+import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
+
+/**
+ * The {@code TinyInstrumentor} is a bytecode instrumentor using ASM bytecode manipulation
+ * framework. It injects given code snippet into a target method and creates a temporary class as
+ * the container. Because the target method is cloned into the temporary class, it is required that
+ * the target method is public static. Any referred method/field in the target method or the
+ * instrumentation snippet should be made public as well.
+ */
+public class TinyInstrumentor implements Opcodes {
+
+    private InsnList instrumentationInstructions;
+    private int instrumentationMaxLocal;
+
+    /**
+     * Create a instrumentor with a instrumentation snippet. The snippet is specified with the given
+     * class {@code instrumentationClass} and the given method name {@code methodName}.
+     */
+    public TinyInstrumentor(Class<?> instrumentationClass, String methodName) throws IOException {
+        MethodNode instrumentationMethod = getMethodNode(instrumentationClass, methodName);
+        assert instrumentationMethod != null;
+        assert (instrumentationMethod.access | ACC_STATIC) != 0;
+        assert "()V".equals(instrumentationMethod.desc);
+        instrumentationInstructions = cloneInstructions(instrumentationMethod.instructions);
+        instrumentationMaxLocal = instrumentationMethod.maxLocals;
+        // replace return instructions with a goto unless there is a single return at the end. In
+        // that case, simply remove the return.
+        List<AbstractInsnNode> returnInstructions = new ArrayList<>();
+        for (AbstractInsnNode instruction : selectAll(instrumentationInstructions)) {
+            if (instruction instanceof LineNumberNode) {
+                instrumentationInstructions.remove(instruction);
+            } else if (instruction.getOpcode() == RETURN) {
+                returnInstructions.add(instruction);
+            }
+        }
+        LabelNode exit = new LabelNode();
+        if (returnInstructions.size() == 1) {
+            AbstractInsnNode returnInstruction = returnInstructions.get(0);
+            if (instrumentationInstructions.getLast() != returnInstruction) {
+                instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
+            }
+            instrumentationInstructions.remove(returnInstruction);
+        } else {
+            for (AbstractInsnNode returnInstruction : returnInstructions) {
+                instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
+                instrumentationInstructions.remove(returnInstruction);
+            }
+        }
+        instrumentationInstructions.add(exit);
+    }
+
+    /**
+     * @return a {@link MethodNode} called {@code methodName} in the given class.
+     */
+    private static MethodNode getMethodNode(Class<?> clazz, String methodName) throws IOException {
+        ClassReader classReader = new ClassReader(clazz.getName());
+        ClassNode classNode = new ClassNode();
+        classReader.accept(classNode, ClassReader.SKIP_FRAMES);
+
+        for (MethodNode methodNode : classNode.methods) {
+            if (methodNode.name.equals(methodName)) {
+                return methodNode;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create a {@link ClassNode} with empty constructor.
+     */
+    private static ClassNode emptyClass(String name) {
+        ClassNode classNode = new ClassNode();
+        classNode.visit(52, ACC_SUPER | ACC_PUBLIC, name.replace('.', '/'), null, "java/lang/Object", new String[]{});
+
+        MethodVisitor mv = classNode.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+
+        return classNode;
+    }
+
+    /**
+     * Helper method for iterating the given {@link InsnList}.
+     */
+    private static Iterable<AbstractInsnNode> selectAll(InsnList instructions) {
+        return new Iterable<AbstractInsnNode>() {
+            @Override
+            public Iterator<AbstractInsnNode> iterator() {
+                return instructions.iterator();
+            }
+        };
+    }
+
+    /**
+     * Make a clone of the given {@link InsnList}.
+     */
+    private static InsnList cloneInstructions(InsnList instructions) {
+        Map<LabelNode, LabelNode> labelMap = new HashMap<>();
+        for (AbstractInsnNode instruction : selectAll(instructions)) {
+            if (instruction instanceof LabelNode) {
+                LabelNode clone = new LabelNode(new Label());
+                LabelNode original = (LabelNode) instruction;
+                labelMap.put(original, clone);
+            }
+        }
+        InsnList clone = new InsnList();
+        for (AbstractInsnNode insn : selectAll(instructions)) {
+            clone.add(insn.clone(labelMap));
+        }
+        return clone;
+    }
+
+    /**
+     * Shifts all local variable slot references by a specified amount.
+     */
+    private static void shiftLocalSlots(InsnList instructions, int offset) {
+        for (AbstractInsnNode insn : selectAll(instructions)) {
+            if (insn instanceof VarInsnNode) {
+                VarInsnNode varInsn = (VarInsnNode) insn;
+                varInsn.var += offset;
+
+            } else if (insn instanceof IincInsnNode) {
+                IincInsnNode iincInsn = (IincInsnNode) insn;
+                iincInsn.var += offset;
+            }
+        }
+    }
+
+    /**
+     * Instrument the target method specified by the class {@code targetClass} and the method name
+     * {@code methodName}. For each occurrence of the {@code opcode}, the instrumentor injects a
+     * copy of the instrumentation snippet.
+     */
+    public Class<?> instrument(Class<?> targetClass, String methodName, int opcode) throws IOException, ClassNotFoundException {
+        return instrument(targetClass, methodName, opcode, true);
+    }
+
+    public Class<?> instrument(Class<?> targetClass, String methodName, int opcode, boolean insertAfter) throws IOException, ClassNotFoundException {
+        // create a container class
+        String className = targetClass.getName() + "$$" + methodName;
+        ClassNode classNode = emptyClass(className);
+        // duplicate the target method and add to the container class
+        MethodNode methodNode = getMethodNode(targetClass, methodName);
+        MethodNode newMethodNode = new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]));
+        methodNode.accept(newMethodNode);
+        classNode.methods.add(newMethodNode);
+        // perform bytecode instrumentation
+        for (AbstractInsnNode instruction : selectAll(newMethodNode.instructions)) {
+            if (instruction.getOpcode() == opcode) {
+                InsnList instrumentation = cloneInstructions(instrumentationInstructions);
+                shiftLocalSlots(instrumentation, newMethodNode.maxLocals);
+                newMethodNode.maxLocals += instrumentationMaxLocal;
+                if (insertAfter) {
+                    newMethodNode.instructions.insert(instruction, instrumentation);
+                } else {
+                    newMethodNode.instructions.insertBefore(instruction, instrumentation);
+                }
+            }
+        }
+        // dump a byte array and load the class with a dedicated loader to separate the namespace
+        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+        classNode.accept(classWriter);
+        byte[] bytes = classWriter.toByteArray();
+        return new Loader(className, bytes).findClass(className);
+    }
+
+    private static class Loader extends ExportingClassLoader {
+
+        private String className;
+        private byte[] bytes;
+
+        Loader(String className, byte[] bytes) {
+            super(TinyInstrumentor.class.getClassLoader());
+            this.className = className;
+            this.bytes = bytes;
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(className)) {
+                return defineClass(name, bytes, 0, bytes.length);
+            } else {
+                return super.findClass(name);
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java
new file mode 100644
index 0000000..35bb668
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.directives;
+
+import java.nio.charset.Charset;
+
+// JaCoCo Exclude
+
+/**
+ * Directives that influence the compilation of methods by Graal. They don't influence the semantics
+ * of the code, but they are useful for unit testing and benchmarking.
+ */
+public final class GraalDirectives {
+
+    public static final double LIKELY_PROBABILITY = 0.75;
+    public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY;
+
+    public static final double SLOWPATH_PROBABILITY = 0.0001;
+    public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY;
+
+    /**
+     * Directive for the compiler to fall back to the bytecode interpreter at this point.
+     */
+    public static void deoptimize() {
+    }
+
+    /**
+     * Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate
+     * the compiled code and reprofile the method.
+     */
+    public static void deoptimizeAndInvalidate() {
+    }
+
+    /**
+     * Returns a boolean value indicating whether the method is executed in Graal-compiled code.
+     */
+    public static boolean inCompiledCode() {
+        return false;
+    }
+
+    /**
+     * A call to this method will never be duplicated by control flow optimizations in the compiler.
+     */
+    public static void controlFlowAnchor() {
+    }
+
+    /**
+     * Injects a probability for the given condition into the profiling information of a branch
+     * instruction. The probability must be a value between 0.0 and 1.0 (inclusive).
+     *
+     * Example usage (it specifies that the likelihood for a to be greater than b is 90%):
+     *
+     * <code>
+     * if (injectBranchProbability(0.9, a &gt; b)) {
+     *    // ...
+     * }
+     * </code>
+     *
+     * There are predefined constants for commonly used probabilities (see
+     * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY},
+     * {@link #FASTPATH_PROBABILITY} ).
+     *
+     * @param probability the probability value between 0.0 and 1.0 that should be injected
+     */
+    public static boolean injectBranchProbability(double probability, boolean condition) {
+        assert probability >= 0.0 && probability <= 1.0;
+        return condition;
+    }
+
+    /**
+     * Injects an average iteration count of a loop into the probability information of a loop exit
+     * condition. The iteration count specifies how often the condition is checked, i.e. in for and
+     * while loops it is one more than the body iteration count, and in do-while loops it is equal
+     * to the body iteration count. The iteration count must be >= 1.0.
+     *
+     * Example usage (it specifies that the expected iteration count of the loop condition is 500,
+     * so the iteration count of the loop body is 499):
+     *
+     * <code>
+     * for (int i = 0; injectIterationCount(500, i < array.length); i++) {
+     *     // ...
+     * }
+     * </code>
+     *
+     * @param iterations the expected number of iterations that should be injected
+     */
+    public static boolean injectIterationCount(double iterations, boolean condition) {
+        return injectBranchProbability(1. - 1. / iterations, condition);
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(boolean value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(byte value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(short value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(char value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(int value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(long value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(float value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(double value) {
+    }
+
+    /**
+     * Consume a value, making sure the compiler doesn't optimize away the computation of this
+     * value, even if it is otherwise unused.
+     */
+    @SuppressWarnings("unused")
+    public static void blackhole(Object value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(boolean value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(byte value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(short value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(char value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(int value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(long value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(float value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(double value) {
+    }
+
+    /**
+     * Forces a value to be kept in a register.
+     */
+    @SuppressWarnings("unused")
+    public static void bindToRegister(Object value) {
+    }
+
+    /**
+     * Spills all caller saved registers.
+     */
+    public static void spillRegisters() {
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static boolean opaque(boolean value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static byte opaque(byte value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static short opaque(short value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static char opaque(char value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static int opaque(int value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static long opaque(long value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static float opaque(float value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static double opaque(double value) {
+        return value;
+    }
+
+    /**
+     * Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
+     *
+     * For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
+     * opaque(3) will result in a real multiplication, because the compiler will not see that
+     * opaque(3) is a constant.
+     */
+    public static <T> T opaque(T value) {
+        return value;
+    }
+
+    public static <T> T guardingNonNull(T value) {
+        if (value == null) {
+            deoptimize();
+        }
+        return value;
+    }
+
+    /**
+     * Ensures that the given object will be virtual (escape analyzed) at all points that are
+     * dominated by the current position.
+     */
+    public static void ensureVirtualized(@SuppressWarnings("unused") Object object) {
+    }
+
+    /**
+     * Ensures that the given object will be virtual at the current position.
+     */
+    public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
+    }
+
+    /**
+     * Marks the beginning of an instrumentation boundary. The instrumentation code will be folded
+     * during compilation and will not affect inlining heuristics regarding graph size except one on
+     * compiled low-level graph size (e.g., {@code GraalOptions.SmallCompiledLowLevelGraphSize}).
+     */
+    public static void instrumentationBegin() {
+    }
+
+    /**
+     * Marks the beginning of an instrumentation boundary and associates the instrumentation with
+     * the preceding bytecode. If the instrumented instruction is {@code new}, then instrumentation
+     * will adapt to optimizations concerning allocation, and only be executed if allocation really
+     * happens.
+     *
+     * Example (the instrumentation is associated with {@code new}):
+     *
+     * <blockquote>
+     *
+     * <pre>
+     *  0  new java.lang.Object
+     *  3  invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationBeginForPredecessor() : void
+     *  6  invokestatic AllocationProfiler.countActualAllocation() : void
+     *  9  invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationEnd() : void
+     * 12  invokespecial java.lang.Object()
+     * </pre>
+     *
+     * </blockquote>
+     *
+     * @see #instrumentationBegin()
+     */
+    public static void instrumentationBeginForPredecessor() {
+    }
+
+    /**
+     * Marks the end of the instrumentation boundary.
+     *
+     * @see #instrumentationBegin()
+     */
+    public static void instrumentationEnd() {
+    }
+
+    /**
+     * @return true if the enclosing method is inlined.
+     */
+    public static boolean isMethodInlined() {
+        return false;
+    }
+
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    /**
+     * @return the name of the root method for the current compilation task. If the enclosing method
+     *         is inlined, it returns the name of the method into which it is inlined.
+     */
+    public static String rootName() {
+        return new String(rawRootName(), UTF8);
+    }
+
+    public static byte[] rawRootName() {
+        return new byte[0];
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java
new file mode 100644
index 0000000..ec35bac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes a class that substitutes methods of another specified class. The substitute methods are
+ * exactly those annotated by {@link MethodSubstitution}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ClassSubstitution {
+
+    /**
+     * Specifies the original class.
+     * <p>
+     * If the default value is specified for this element, then a non-default value must be given
+     * for the {@link #className()} element.
+     */
+    Class<?> value() default ClassSubstitution.class;
+
+    /**
+     * Specifies the original class or classes if a single class is being used for multiple
+     * substitutions.
+     * <p>
+     * This method is provided for cases where the original class is not accessible (according to
+     * Java language access control rules).
+     * <p>
+     * If the default value is specified for this element, then a non-default value must be given
+     * for the {@link #value()} element.
+     */
+    String[] className() default {};
+
+    /**
+     * Determines if the substitutions are for classes that may not be part of the runtime.
+     * Substitutions for such classes are omitted if the original classes cannot be found.
+     */
+    boolean optional() default false;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Fold.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Fold.java
new file mode 100644
index 0000000..817354f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Fold.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated method
+ * is replaced with a constant obtained by calling the annotated method via reflection.
+ *
+ * All arguments to such a method (including the receiver if applicable) must be compile-time
+ * constants.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Fold {
+
+    /**
+     * Annotates a parameter to an {@link Fold}-annotated method. This parameter will be
+     * automatically injected by the compiler. The caller should always pass {@code null}.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.PARAMETER)
+    public @interface InjectedParameter {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java
new file mode 100644
index 0000000..4992965
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * Denotes a method whose body is used by a compiler as the substitute (or intrinsification) of
+ * another method. The exact method used to do the substitution is compiler dependent but every
+ * compiler should require substitute methods to be annotated with {@link MethodSubstitution}. In
+ * addition, a compiler is recommended to implement {@link MethodSubstitutionRegistry} to advertise
+ * the mechanism by which it supports registration of method substitutes.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface MethodSubstitution {
+
+    /**
+     * Gets the name of the original method.
+     * <p>
+     * If the default value is specified for this element, then the name of the original method is
+     * same as the substitute method.
+     */
+    String value() default "";
+
+    /**
+     * Determines if the original method is static.
+     */
+    boolean isStatic() default true;
+
+    /**
+     * Gets the {@linkplain Signature#toMethodDescriptor signature} of the original method.
+     * <p>
+     * If the default value is specified for this element, then the signature of the original method
+     * is the same as the substitute method.
+     */
+    String signature() default "";
+
+    /**
+     * Determines if the substitution is for a method that may not be part of the runtime. For
+     * example, a method introduced in a later JDK version. Substitutions for such methods are
+     * omitted if the original method cannot be found.
+     */
+    boolean optional() default false;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java
new file mode 100644
index 0000000..507c7d5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.lang.reflect.Type;
+
+/**
+ * A registry for {@link MethodSubstitution}s.
+ */
+public interface MethodSubstitutionRegistry {
+
+    /**
+     * Gets the type representing the receiver (i.e., {@code this}) argument in a non-static method.
+     */
+    Class<?> getReceiverType();
+
+    /**
+     * Registers a substitution method.
+     *
+     * @param substituteDeclaringClass the class declaring the substitute method
+     * @param name the name of both the original and substitute method
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be
+     *            {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0
+     *            will have been rewritten to {@code declaringClass}.
+     */
+    default void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
+        registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
+    }
+
+    /**
+     * Registers a substitution method.
+     *
+     * @param substituteDeclaringClass the class declaring the substitute method
+     * @param name the name of both the original method
+     * @param substituteName the name of the substitute method
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be
+     *            {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0
+     *            will have been rewritten to {@code declaringClass}.
+     */
+    void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java
new file mode 100644
index 0000000..8b904f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering
+ * nodes that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode).
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Snippet {
+
+    /**
+     * Denotes a snippet parameter representing 0 or more arguments that will be bound during
+     * snippet template instantiation. During snippet template creation, its value must be an array
+     * whose length specifies the number of arguments (the contents of the array are ignored) bound
+     * to the parameter during instantiation.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.PARAMETER)
+    public @interface VarargsParameter {
+    }
+
+    /**
+     * Denotes a snippet parameter that will bound to a constant value during snippet template
+     * instantiation.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.PARAMETER)
+    public @interface ConstantParameter {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java
new file mode 100644
index 0000000..ea9791a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+import java.util.Objects;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Reflection operations on values represented as {@linkplain JavaConstant constants} for the
+ * processing of snippets. Snippets need a direct access to the value of object constants, which is
+ * not allowed in other parts of Graal to enforce compiler-VM separation.
+ * <p>
+ * This interface must not be used in Graal code that is not related to snippet processing.
+ */
+public interface SnippetReflectionProvider {
+
+    /**
+     * Creates a boxed {@link JavaKind#Object object} constant.
+     *
+     * @param object the object value to box
+     * @return a constant containing {@code object}
+     */
+    JavaConstant forObject(Object object);
+
+    /**
+     * Gets the object reference a given constant represents if it is of a given type. The constant
+     * must have kind {@link JavaKind#Object}.
+     *
+     * @param type the expected type of the object represented by {@code constant}. If the object is
+     *            required to be of this type, then wrap the call to this method in
+     *            {@link Objects#requireNonNull(Object)}.
+     * @param constant an object constant
+     * @return the object value represented by {@code constant} cast to {@code type} if it is an
+     *         {@link Class#isInstance(Object) instance of} {@code type} otherwise {@code null}
+     */
+    <T> T asObject(Class<T> type, JavaConstant constant);
+
+    /**
+     * Gets the object reference a given constant represents if it is of a given type. The constant
+     * must have kind {@link JavaKind#Object}.
+     *
+     * @param type the expected type of the object represented by {@code constant}. If the object is
+     *            required to be of this type, then wrap the call to this method in
+     *            {@link Objects#requireNonNull(Object)}.
+     * @param constant an object constant
+     * @return the object value represented by {@code constant} if it is an
+     *         {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise
+     *         {@code null}
+     */
+    Object asObject(ResolvedJavaType type, JavaConstant constant);
+
+    /**
+     * Creates a boxed constant for the given kind from an Object. The object needs to be of the
+     * Java boxed type corresponding to the kind.
+     *
+     * @param kind the kind of the constant to create
+     * @param value the Java boxed value: a {@link Byte} instance for {@link JavaKind#Byte}, etc.
+     * @return the boxed copy of {@code value}
+     */
+    JavaConstant forBoxed(JavaKind kind, Object value);
+
+    /**
+     * Gets the value to bind to an injected parameter in a node intrinsic.
+     *
+     * @param type the type of a parameter in a node intrinsic constructor
+     * @return the value that should be bound to the parameter when invoking the constructor or null
+     *         if this provider cannot provide a value of the requested type
+     */
+    <T> T getInjectedNodeIntrinsicParameter(Class<T> type);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetTemplateCache.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetTemplateCache.java
new file mode 100644
index 0000000..b805318
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetTemplateCache.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.replacements;
+
+/**
+ * Marker interface for classes that cache snippet templates.
+ */
+public interface SnippetTemplateCache {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalJVMCICompiler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalJVMCICompiler.java
new file mode 100644
index 0000000..a4e075f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalJVMCICompiler.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.runtime;
+
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * Graal specific extension of the {@link JVMCICompiler} interface.
+ */
+public interface GraalJVMCICompiler extends JVMCICompiler {
+
+    GraalRuntime getGraalRuntime();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java
new file mode 100644
index 0000000..d38ac6c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.runtime;
+
+public interface GraalRuntime {
+
+    String getName();
+
+    <T> T getCapability(Class<T> clazz);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java
new file mode 100644
index 0000000..01746c7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.test;
+
+import java.util.Formatter;
+
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.runtime.JVMCICompiler;
+import jdk.vm.ci.services.Services;
+
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.api.runtime.GraalRuntime;
+
+/**
+ * Access point for {@linkplain #getRuntime() retrieving} the {@link GraalRuntime} instance of the
+ * system compiler from unit tests.
+ */
+public class Graal {
+
+    private static final GraalRuntime runtime = initializeRuntime();
+
+    private static GraalRuntime initializeRuntime() {
+        Services.exportJVMCITo(Graal.class);
+        JVMCICompiler compiler = JVMCI.getRuntime().getCompiler();
+        if (compiler instanceof GraalJVMCICompiler) {
+            GraalJVMCICompiler graal = (GraalJVMCICompiler) compiler;
+            return graal.getGraalRuntime();
+        } else {
+            return new InvalidGraalRuntime();
+        }
+    }
+
+    /**
+     * Gets the singleton {@link GraalRuntime} instance available to unit tests.
+     */
+    public static GraalRuntime getRuntime() {
+        return runtime;
+    }
+
+    /**
+     * Gets a capability provided by the {@link GraalRuntime} instance available to the application.
+     *
+     * @throws UnsupportedOperationException if the capability is not available
+     */
+    public static <T> T getRequiredCapability(Class<T> clazz) {
+        T t = getRuntime().getCapability(clazz);
+        if (t == null) {
+            String javaHome = System.getProperty("java.home");
+            String vmName = System.getProperty("java.vm.name");
+            Formatter errorMessage = new Formatter();
+            if (getRuntime().getClass() == InvalidGraalRuntime.class) {
+                errorMessage.format("The VM does not support the Graal API.%n");
+            } else {
+                errorMessage.format("The VM does not expose required Graal capability %s.%n", clazz.getName());
+            }
+            errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
+            errorMessage.format("Currently used VM configuration is: %s", vmName);
+            throw new UnsupportedOperationException(errorMessage.toString());
+        }
+        return t;
+    }
+
+    private static final class InvalidGraalRuntime implements GraalRuntime {
+
+        @Override
+        public String getName() {
+            return "";
+        }
+
+        @Override
+        public <T> T getCapability(Class<T> clazz) {
+            return null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/GraalAPITest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/GraalAPITest.java
new file mode 100644
index 0000000..4e044e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/GraalAPITest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.api.test;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+public class GraalAPITest {
+
+    @Test
+    public void testRuntimeAvailable() {
+        assertNotNull(Graal.getRuntime());
+    }
+
+    @Test
+    public void testRuntimeNamed() {
+        assertNotNull(Graal.getRuntime().getName());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64MacroAssemblerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64MacroAssemblerTest.java
new file mode 100644
index 0000000..8bc7e55
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/AArch64MacroAssemblerTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.asm.aarch64.test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.EnumSet;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64.CPUFeature;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+public class AArch64MacroAssemblerTest extends GraalTest {
+
+    private AArch64MacroAssembler masm;
+    private TestProtectedAssembler asm;
+    private Register base;
+    private Register index;
+    private Register scratch;
+
+    private static EnumSet<AArch64.CPUFeature> computeFeatures() {
+        EnumSet<AArch64.CPUFeature> features = EnumSet.noneOf(AArch64.CPUFeature.class);
+        features.add(CPUFeature.FP);
+        return features;
+    }
+
+    private static EnumSet<AArch64.Flag> computeFlags() {
+        EnumSet<AArch64.Flag> flags = EnumSet.noneOf(AArch64.Flag.class);
+        return flags;
+    }
+
+    private static TargetDescription createTarget() {
+        final int stackFrameAlignment = 16;
+        final int implicitNullCheckLimit = 4096;
+        final boolean inlineObjects = true;
+        Architecture arch = new AArch64(computeFeatures(), computeFlags());
+        return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+    }
+
+    @Before
+    public void setupEnvironment() {
+        TargetDescription target = createTarget();
+        masm = new AArch64MacroAssembler(target);
+        asm = new TestProtectedAssembler(target);
+        base = AArch64.r10;
+        index = AArch64.r13;
+        scratch = AArch64.r15;
+    }
+
+    @Test
+    public void testGenerateAddressPlan() {
+        AddressGenerationPlan plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(8) - 1, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 2, false, 4);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(9), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-(NumUtil.getNbitNumberInt(12) << 12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+    }
+
+    @Test
+    public void testMakeAddressNoAction() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12) << 3, AArch64.zr, false, 8, null, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.IMMEDIATE_SCALED && address.getBase().equals(base) &&
+                        address.getOffset().equals(AArch64.zr) && address.getImmediateRaw() == NumUtil.getNbitNumberInt(12));
+        // No code generated.
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndex() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(scratch));
+        asm.add(64, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBaseNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(scratch) && address.getOffset().equals(index));
+        asm.add(64, scratch, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBase() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, base, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwriteExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(scratch) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(index) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled2() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, -NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.sub(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(12));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(9) << 3);
+        asm.add(64, dst, dst, NumUtil.getNbitNumberInt(3) << 12);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledLowerOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(5));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(5) << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledHigherOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, 1 << 11);
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, 1 << 11 << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, false);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, true);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, false, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, true, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 2);
+        compareAssembly();
+    }
+
+    /**
+     * Compares assembly generated by the macro assembler to the hand-generated assembly.
+     */
+    private void compareAssembly() {
+        byte[] expected = asm.close(true);
+        byte[] actual = masm.close(true);
+        assertArrayEquals(expected, actual);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java
new file mode 100644
index 0000000..9934218
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.asm.aarch64.test;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Cheat so that we can test protected functions of assembler.
+ */
+class TestProtectedAssembler extends AArch64Assembler {
+
+    TestProtectedAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        super.cbnz(size, reg, imm21, pos);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        super.cbz(size, reg, imm21, pos);
+    }
+
+    @Override
+    public void ands(int size, Register dst, Register src, long bimm) {
+        super.ands(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21) {
+        super.b(condition, imm21);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        super.b(condition, imm21, pos);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21) {
+        super.cbnz(size, reg, imm21);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21) {
+        super.cbz(size, reg, imm21);
+    }
+
+    @Override
+    protected void b(int imm28) {
+        super.b(imm28);
+    }
+
+    @Override
+    protected void b(int imm28, int pos) {
+        super.b(imm28, pos);
+    }
+
+    @Override
+    public void bl(int imm28) {
+        super.bl(imm28);
+    }
+
+    @Override
+    public void blr(Register reg) {
+        super.blr(reg);
+    }
+
+    @Override
+    protected void br(Register reg) {
+        super.br(reg);
+    }
+
+    @Override
+    public void ret(Register reg) {
+        super.ret(reg);
+    }
+
+    @Override
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        super.ldr(srcSize, rt, address);
+    }
+
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        super.ldrs(targetSize, srcSize, rt, address);
+    }
+
+    @Override
+    public void str(int destSize, Register rt, AArch64Address address) {
+        super.str(destSize, rt, address);
+    }
+
+    @Override
+    protected void ldxr(int size, Register rt, Register rn) {
+        super.ldxr(size, rt, rn);
+    }
+
+    @Override
+    protected void stxr(int size, Register rs, Register rt, Register rn) {
+        super.stxr(size, rs, rt, rn);
+    }
+
+    @Override
+    protected void ldar(int size, Register rt, Register rn) {
+        super.ldar(size, rt, rn);
+    }
+
+    @Override
+    protected void stlr(int size, Register rt, Register rn) {
+        super.stlr(size, rt, rn);
+    }
+
+    @Override
+    public void ldaxr(int size, Register rt, Register rn) {
+        super.ldaxr(size, rt, rn);
+    }
+
+    @Override
+    public void stlxr(int size, Register rs, Register rt, Register rn) {
+        super.stlxr(size, rs, rt, rn);
+    }
+
+    @Override
+    public void adr(Register dst, int imm21) {
+        super.adr(dst, imm21);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src, int aimm) {
+        super.add(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        super.adds(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        super.sub(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        super.subs(size, dst, src, aimm);
+    }
+
+    @Override
+    public void and(int size, Register dst, Register src, long bimm) {
+        super.and(size, dst, src, bimm);
+    }
+
+    @Override
+    public void eor(int size, Register dst, Register src, long bimm) {
+        super.eor(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movz(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movn(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        super.movk(size, dst, uimm16, pos);
+    }
+
+    @Override
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        super.bfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        super.ubfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        super.sbfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        super.extr(size, dst, src1, src2, lsb);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.adds(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.subs(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.add(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.sub(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.add(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.adds(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.sub(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.subs(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.and(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.ands(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bic(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bics(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eon(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eor(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orr(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orn(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        super.asr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        super.lsl(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        super.lsr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        super.ror(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void cls(int size, Register dst, Register src) {
+        super.cls(size, dst, src);
+    }
+
+    @Override
+    public void clz(int size, Register dst, Register src) {
+        super.clz(size, dst, src);
+    }
+
+    @Override
+    protected void rbit(int size, Register dst, Register src) {
+        super.rbit(size, dst, src);
+    }
+
+    @Override
+    public void rev(int size, Register dst, Register src) {
+        super.rev(size, dst, src);
+    }
+
+    @Override
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csneg(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csinc(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.madd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.msub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        super.sdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        super.udiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fldr(int size, Register rt, AArch64Address address) {
+        super.fldr(size, rt, address);
+    }
+
+    @Override
+    public void fstr(int size, Register rt, AArch64Address address) {
+        super.fstr(size, rt, address);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, Register src) {
+        super.fmov(size, dst, src);
+    }
+
+    @Override
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        super.fmovFpu2Cpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        super.fmovCpu2Fpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, double imm) {
+        super.fmov(size, dst, imm);
+    }
+
+    @Override
+    public void fcvt(int srcSize, Register dst, Register src) {
+        super.fcvt(srcSize, dst, src);
+    }
+
+    @Override
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        super.fcvtzs(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        super.scvtf(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    protected void frintz(int size, Register dst, Register src) {
+        super.frintz(size, dst, src);
+    }
+
+    @Override
+    public void fabs(int size, Register dst, Register src) {
+        super.fabs(size, dst, src);
+    }
+
+    @Override
+    public void fneg(int size, Register dst, Register src) {
+        super.fneg(size, dst, src);
+    }
+
+    @Override
+    public void fsqrt(int size, Register dst, Register src) {
+        super.fsqrt(size, dst, src);
+    }
+
+    @Override
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        super.fadd(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        super.fsub(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        super.fmul(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        super.fdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmadd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmsub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void fcmp(int size, Register src1, Register src2) {
+        super.fcmp(size, src1, src2);
+    }
+
+    @Override
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        super.fccmp(size, src1, src2, uimm4, condition);
+    }
+
+    @Override
+    public void fcmpZero(int size, Register src) {
+        super.fcmpZero(size, src);
+    }
+
+    @Override
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.fcsel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void hlt(int uimm16) {
+        super.hlt(uimm16);
+    }
+
+    @Override
+    protected void brk(int uimm16) {
+        super.brk(uimm16);
+    }
+
+    @Override
+    protected void hint(SystemHint hint) {
+        super.hint(hint);
+    }
+
+    @Override
+    protected void clrex() {
+        super.clrex();
+    }
+
+    @Override
+    public void dmb(BarrierKind barrierKind) {
+        super.dmb(barrierKind);
+    }
+
+    @Override
+    public void align(int modulus) {
+    }
+
+    @Override
+    public void jmp(Label l) {
+    }
+
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+
+    }
+
+    @Override
+    public AbstractAddress makeAddress(Register base, int displacement) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder(int instructionStartPosition) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void ensureUniquePC() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java
new file mode 100644
index 0000000..31d07c5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+
+/**
+ * Represents an address in target machine memory, specified using one of the different addressing
+ * modes of the AArch64 ISA. - Base register only - Base register + immediate or register with
+ * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value
+ * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are
+ * written back to base register, value used in instruction is base only - Literal: PC + 19-bit
+ * signed word aligned offset
+ * <p>
+ * Not all addressing modes are supported for all instructions.
+ */
+public final class AArch64Address extends AbstractAddress {
+    // Placeholder for addresses that get patched later.
+    public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0);
+
+    public enum AddressingMode {
+        /**
+         * base + uimm12 << log2(memory_transfer_size).
+         */
+        IMMEDIATE_SCALED,
+        /**
+         * base + imm9.
+         */
+        IMMEDIATE_UNSCALED,
+        /**
+         * base.
+         */
+        BASE_REGISTER_ONLY,
+        /**
+         * base + offset [<< log2(memory_transfer_size)].
+         */
+        REGISTER_OFFSET,
+        /**
+         * base + extend(offset) [<< log2(memory_transfer_size)].
+         */
+        EXTENDED_REGISTER_OFFSET,
+        /**
+         * PC + imm21 (word aligned).
+         */
+        PC_LITERAL,
+        /**
+         * address = base. base is updated to base + imm9
+         */
+        IMMEDIATE_POST_INDEXED,
+        /**
+         * address = base + imm9. base is updated to base + imm9
+         */
+        IMMEDIATE_PRE_INDEXED,
+        AddressingMode,
+    }
+
+    private final Register base;
+    private final Register offset;
+    private final int immediate;
+    /**
+     * Should register offset be scaled or not.
+     */
+    private final boolean scaled;
+    private final AArch64Assembler.ExtendType extendType;
+    private final AddressingMode addressingMode;
+
+    /**
+     * General address generation mechanism. Accepted values for all parameters depend on the
+     * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a
+     * register the register has to be the zero-register. extendType has to be null for every
+     * addressingMode except EXTENDED_REGISTER_OFFSET.
+     */
+    public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9-bit immediate value.
+     * @return an address specifying a post-indexed immediate address pointing to base. After
+     *         ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9-bit immediate value.
+     * @return an address specifying a pre-indexed immediate address pointing to base + imm9. After
+     *         ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm12 Unsigned 12-bit immediate value. This is scaled by the word access size. This
+     *            means if this address is used to load/store a word, the immediate is shifted by 2
+     *            (log2Ceil(4)).
+     * @return an address specifying a signed address of the form base + imm12 <<
+     *         log2(memory_transfer_size).
+     */
+    public static AArch64Address createScaledImmediateAddress(Register base, int imm12) {
+        return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9-bit immediate value.
+     * @return an address specifying an unscaled immediate address of the form base + imm9
+     */
+    public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+    }
+
+    /**
+     * @param base May not be null or the zero register.
+     * @return an address specifying the address pointed to by base.
+     */
+    public static AArch64Address createBaseRegisterOnlyAddress(Register base) {
+        return createRegisterOffsetAddress(base, zr, false);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size.
+     *            May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @return an address specifying a register offset address of the form base + offset [<< log2
+     *         (memory_transfer_size)]
+     */
+    public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) {
+        return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm7 Signed 7-bit immediate value.
+     * @return an address specifying an unscaled immediate address of the form base + imm7
+     */
+    public static AArch64Address createPairUnscaledImmediateAddress(Register base, int imm7) {
+        return new AArch64Address(base, zr, imm7, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Word register specifying some offset, optionally scaled by the
+     *            memory_transfer_size. May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @param extendType Describes whether register is zero- or sign-extended. May not be null.
+     * @return an address specifying an extended register offset of the form base +
+     *         extendType(offset) [<< log2(memory_transfer_size)]
+     */
+    public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET);
+    }
+
+    /**
+     * @param imm21 Signed 21-bit offset, word aligned.
+     * @return AArch64Address specifying a PC-literal address of the form PC + offset
+     */
+    public static AArch64Address createPcLiteralAddress(int imm21) {
+        return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL);
+    }
+
+    private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) {
+        this.base = base;
+        this.offset = offset;
+        if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) {
+            this.addressingMode = AddressingMode.BASE_REGISTER_ONLY;
+        } else {
+            this.addressingMode = addressingMode;
+        }
+        this.immediate = immediate;
+        this.scaled = scaled;
+        this.extendType = extendType;
+        assert verify();
+    }
+
+    private boolean verify() {
+        assert addressingMode != null;
+        assert base.getRegisterCategory().equals(AArch64.CPU);
+        assert offset.getRegisterCategory().equals(AArch64.CPU);
+
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                assert !base.equals(zr);
+                assert offset.equals(zr);
+                assert extendType == null;
+                assert NumUtil.isUnsignedNbit(12, immediate);
+                break;
+            case IMMEDIATE_UNSCALED:
+                assert !base.equals(zr);
+                assert offset.equals(zr);
+                assert extendType == null;
+                assert NumUtil.isSignedNbit(9, immediate);
+                break;
+            case BASE_REGISTER_ONLY:
+                assert !base.equals(zr);
+                assert offset.equals(zr);
+                assert extendType == null;
+                assert immediate == 0;
+                break;
+            case REGISTER_OFFSET:
+                assert !base.equals(zr);
+                assert offset.getRegisterCategory().equals(AArch64.CPU);
+                assert extendType == null;
+                assert immediate == 0;
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                assert !base.equals(zr);
+                assert offset.getRegisterCategory().equals(AArch64.CPU);
+                assert (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW);
+                assert immediate == 0;
+                break;
+            case PC_LITERAL:
+                assert base.equals(zr);
+                assert offset.equals(zr);
+                assert extendType == null;
+                assert NumUtil.isSignedNbit(21, immediate);
+                assert ((immediate & 0x3) == 0);
+                break;
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                assert !base.equals(zr);
+                assert offset.equals(zr);
+                assert extendType == null;
+                assert NumUtil.isSignedNbit(9, immediate);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+
+        return true;
+    }
+
+    public Register getBase() {
+        return base;
+    }
+
+    public Register getOffset() {
+        return offset;
+    }
+
+    /**
+     * @return immediate in correct representation for the given addressing mode. For example in
+     *         case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
+     *         as the 9bit signed representation.
+     */
+    public int getImmediate() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                // 9-bit signed value
+                return immediate & NumUtil.getNbitNumberInt(9);
+            case IMMEDIATE_SCALED:
+                // Unsigned value can be returned as-is.
+                return immediate;
+            case PC_LITERAL:
+                // 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
+                return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
+            default:
+                throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    /**
+     * @return Raw immediate as a 32-bit signed value.
+     */
+    public int getImmediateRaw() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_SCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+            case PC_LITERAL:
+                return immediate;
+            default:
+                throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    public boolean isScaled() {
+        return scaled;
+    }
+
+    public AArch64Assembler.ExtendType getExtendType() {
+        return extendType;
+    }
+
+    public AddressingMode getAddressingMode() {
+        return addressingMode;
+    }
+
+    public String toString(int log2TransferSize) {
+        int shiftVal = scaled ? log2TransferSize : 0;
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize);
+            case IMMEDIATE_UNSCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate);
+            case BASE_REGISTER_ONLY:
+                return String.format("[X%d]", base.encoding);
+            case EXTENDED_REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal);
+                } else {
+                    return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name());
+                }
+            case REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal);
+                } else {
+                    // LSL 0 may be optional, but still encoded differently so we always leave it
+                    // off
+                    return String.format("[X%d, X%d]", base.encoding, offset.encoding);
+                }
+            case PC_LITERAL:
+                return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate);
+            case IMMEDIATE_POST_INDEXED:
+                return String.format("[X%d],%d", base.encoding, immediate);
+            case IMMEDIATE_PRE_INDEXED:
+                return String.format("[X%d,%d]!", base.encoding, immediate);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java
new file mode 100644
index 0000000..02a7eb2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java
@@ -0,0 +1,2499 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.aarch64;
+
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADD;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADDS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ADR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.AND;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ANDS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ASRV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BFM;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BIC;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BICS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BLR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSEL;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSINC;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSNEG;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DMB;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EON;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EOR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EXTR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FABS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FADD;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCCMP;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMP;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCMPZERO;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCSEL;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTDS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTSD;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FCVTZS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FDIV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMADD;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMOV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDRS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDXR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSLV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LSRV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MADD;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVK;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVN;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVZ;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MSUB;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORN;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RBIT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RET;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVW;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.REVX;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.RORV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SBFM;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SCVTF;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SDIV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STLXR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STXR;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUB;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.SUBS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UBFM;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.UDIV;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP32;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.FP64;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General32;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.General64;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.SIMD;
+import static jdk.vm.ci.aarch64.AArch64.r0;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+public abstract class AArch64Assembler extends Assembler {
+
+    public static class LogicalImmediateTable {
+
+        private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable();
+
+        private static final int ImmediateOffset = 10;
+        private static final int ImmediateRotateOffset = 16;
+        private static final int ImmediateSizeOffset = 22;
+
+        /**
+         * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction
+         * (SIXTY_FOUR_BIT_ONLY) or not at all (NO).
+         */
+        enum Representable {
+            YES,
+            SIXTY_FOUR_BIT_ONLY,
+            NO
+        }
+
+        /**
+         * Tests whether an immediate can be encoded for logical instructions.
+         *
+         * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a
+         *            64-bit instruction to load the 32-bit pattern into a register.
+         * @return enum specifying whether immediate can be used for 32- and 64-bit logical
+         *         instructions ({@code #Representable.YES}), for 64-bit instructions only (
+         *         {@link Representable#SIXTY_FOUR_BIT_ONLY}) or not at all (
+         *         {@link Representable#NO}).
+         */
+        public static Representable isRepresentable(boolean is64bit, long immediate) {
+            int pos = getLogicalImmTablePos(is64bit, immediate);
+            if (pos < 0) {
+                // if 32bit instruction we can try again as 64bit immediate which may succeed.
+                // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one.
+                if (!is64bit) {
+                    assert NumUtil.isUnsignedNbit(32, immediate);
+                    pos = getLogicalImmTablePos(true, immediate);
+                    return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO;
+                }
+                return Representable.NO;
+            }
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES;
+        }
+
+        public static Representable isRepresentable(int immediate) {
+            return isRepresentable(false, immediate & 0xFFFF_FFFFL);
+        }
+
+        public static int getLogicalImmEncoding(boolean is64bit, long value) {
+            int pos = getLogicalImmTablePos(is64bit, value);
+            assert pos >= 0 : "Value cannot be represented as logical immediate: " + value + ", is64bit=" + is64bit;
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified";
+            return IMMEDIATE_TABLE[pos].encoding;
+        }
+
+        /**
+         * @param is64bit if true also allow 64-bit only encodings to be returned.
+         * @return If positive the return value is the position into the IMMEDIATE_TABLE for the
+         *         given immediate, if negative the immediate cannot be encoded.
+         */
+        private static int getLogicalImmTablePos(boolean is64bit, long value) {
+            Immediate imm;
+            if (!is64bit) {
+                // 32bit instructions can only have 32bit immediates.
+                if (!NumUtil.isUnsignedNbit(32, value)) {
+                    return -1;
+                }
+                // If we have a 32bit instruction (and therefore immediate) we have to duplicate it
+                // across 64bit to find it in the table.
+                imm = new Immediate(value << 32 | value);
+            } else {
+                imm = new Immediate(value);
+            }
+            int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm);
+            if (pos < 0) {
+                return -1;
+            }
+            if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) {
+                return -1;
+            }
+            return pos;
+        }
+
+        /**
+         * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of
+         * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each
+         * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by
+         * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting
+         * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the
+         * number of set bits and the pattern size. The pattern size is encoded as follows (x is
+         * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32
+         * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern?
+         */
+        private static final class Immediate implements Comparable<Immediate> {
+            public final long imm;
+            public final int encoding;
+
+            Immediate(long imm, boolean is64, int s, int r) {
+                this.imm = imm;
+                this.encoding = computeEncoding(is64, s, r);
+            }
+
+            // Used to be able to binary search for an immediate in the table.
+            Immediate(long imm) {
+                this(imm, false, 0, 0);
+            }
+
+            /**
+             * Returns true if this pattern is only representable as 64bit.
+             */
+            public boolean only64bit() {
+                return (encoding & (1 << ImmediateSizeOffset)) != 0;
+            }
+
+            private static int computeEncoding(boolean is64, int s, int r) {
+                int sf = is64 ? 1 : 0;
+                return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset;
+            }
+
+            @Override
+            public int compareTo(Immediate o) {
+                return Long.compare(imm, o.imm);
+            }
+        }
+
+        private static Immediate[] buildImmediateTable() {
+            final int nrImmediates = 5334;
+            final Immediate[] table = new Immediate[nrImmediates];
+            int nrImms = 0;
+            for (int logE = 1; logE <= 6; logE++) {
+                int e = 1 << logE;
+                long mask = NumUtil.getNbitNumberLong(e);
+                for (int nrOnes = 1; nrOnes < e; nrOnes++) {
+                    long val = (1L << nrOnes) - 1;
+                    // r specifies how much we rotate the value
+                    for (int r = 0; r < e; r++) {
+                        long immediate = (val >>> r | val << (e - r)) & mask;
+                        // Duplicate pattern to fill whole 64bit range.
+                        switch (logE) {
+                            case 1:
+                                immediate |= immediate << 2;
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 2:
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 3:
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 4:
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 5:
+                                immediate |= immediate << 32;
+                                break;
+                        }
+                        // 5 - logE can underflow to -1, but we shift this bogus result
+                        // out of the masked area.
+                        int sizeEncoding = (1 << (5 - logE)) - 1;
+                        int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1);
+                        table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r);
+                    }
+                }
+            }
+            Arrays.sort(table);
+            assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table.";
+            assert checkDuplicates(table) : "Duplicate values in table.";
+            return table;
+        }
+
+        private static boolean checkDuplicates(Immediate[] table) {
+            for (int i = 0; i < table.length - 1; i++) {
+                if (table[i].imm >= table[i + 1].imm) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static final int RdOffset = 0;
+    private static final int Rs1Offset = 5;
+    private static final int Rs2Offset = 16;
+    private static final int Rs3Offset = 10;
+    private static final int RtOffset = 0;
+    private static final int RnOffset = 5;
+    private static final int Rt2Offset = 10;
+
+    /* Helper functions */
+    private static int rd(Register reg) {
+        return reg.encoding << RdOffset;
+    }
+
+    private static int rs1(Register reg) {
+        return reg.encoding << Rs1Offset;
+    }
+
+    private static int rs2(Register reg) {
+        return reg.encoding << Rs2Offset;
+    }
+
+    private static int rs3(Register reg) {
+        return reg.encoding << Rs3Offset;
+    }
+
+    private static int rt(Register reg) {
+        return reg.encoding << RtOffset;
+    }
+
+    private static int rt2(Register reg) {
+        return reg.encoding << Rt2Offset;
+    }
+
+    private static int rn(Register reg) {
+        return reg.encoding << RnOffset;
+    }
+
+    /**
+     * Enumeration of all different instruction kinds: General32/64 are the general instructions
+     * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for
+     * the 32/64bit float operations
+     */
+    protected enum InstructionType {
+        General32(0b00 << 30, 32, true),
+        General64(0b10 << 30, 64, true),
+        FP32(0x00000000, 32, false),
+        FP64(0x00400000, 64, false);
+
+        public final int encoding;
+        public final int width;
+        public final boolean isGeneral;
+
+        InstructionType(int encoding, int width, boolean isGeneral) {
+            this.encoding = encoding;
+            this.width = width;
+            this.isGeneral = isGeneral;
+        }
+
+        public static InstructionType generalFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? General32 : General64;
+        }
+
+        public static InstructionType floatFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? FP32 : FP64;
+        }
+
+    }
+
+    private static final int ImmediateOffset = 10;
+    private static final int ImmediateRotateOffset = 16;
+    private static final int ImmediateSizeOffset = 22;
+    private static final int ExtendTypeOffset = 13;
+
+    private static final int AddSubImmOp = 0x11000000;
+    private static final int AddSubShift12 = 0b01 << 22;
+    private static final int AddSubSetFlag = 0x20000000;
+
+    private static final int LogicalImmOp = 0x12000000;
+
+    private static final int MoveWideImmOp = 0x12800000;
+    private static final int MoveWideImmOffset = 5;
+    private static final int MoveWideShiftOffset = 21;
+
+    private static final int BitfieldImmOp = 0x13000000;
+
+    private static final int AddSubShiftedOp = 0x0B000000;
+    private static final int ShiftTypeOffset = 22;
+
+    private static final int AddSubExtendedOp = 0x0B200000;
+
+    private static final int MulOp = 0x1B000000;
+    private static final int DataProcessing1SourceOp = 0x5AC00000;
+    private static final int DataProcessing2SourceOp = 0x1AC00000;
+
+    private static final int Fp1SourceOp = 0x1E204000;
+    private static final int Fp2SourceOp = 0x1E200800;
+    private static final int Fp3SourceOp = 0x1F000000;
+
+    private static final int FpConvertOp = 0x1E200000;
+    private static final int FpImmOp = 0x1E201000;
+    private static final int FpImmOffset = 13;
+
+    private static final int FpCmpOp = 0x1E202000;
+
+    private static final int PcRelImmHiOffset = 5;
+    private static final int PcRelImmLoOffset = 29;
+
+    private static final int PcRelImmOp = 0x10000000;
+
+    private static final int UnconditionalBranchImmOp = 0x14000000;
+    private static final int UnconditionalBranchRegOp = 0xD6000000;
+    private static final int CompareBranchOp = 0x34000000;
+
+    private static final int ConditionalBranchImmOffset = 5;
+
+    private static final int ConditionalSelectOp = 0x1A800000;
+    private static final int ConditionalConditionOffset = 12;
+
+    private static final int LoadStoreScaledOp = 0b111_0_01_00 << 22;
+    private static final int LoadStoreUnscaledOp = 0b111_0_00_00 << 22;
+
+    private static final int LoadStoreRegisterOp = 0b111_0_00_00_1 << 21 | 0b10 << 10;
+
+    private static final int LoadLiteralOp = 0x18000000;
+
+    private static final int LoadStorePostIndexedOp = 0b111_0_00_00_0 << 21 | 0b01 << 10;
+    private static final int LoadStorePreIndexedOp = 0b111_0_00_00_0 << 21 | 0b11 << 10;
+
+    private static final int LoadStoreUnscaledImmOffset = 12;
+    private static final int LoadStoreScaledImmOffset = 10;
+    private static final int LoadStoreScaledRegOffset = 12;
+    private static final int LoadStoreIndexedImmOffset = 12;
+    private static final int LoadStoreTransferSizeOffset = 30;
+    private static final int LoadStoreFpFlagOffset = 26;
+    private static final int LoadLiteralImmeOffset = 5;
+
+    private static final int LoadStorePairOp = 0b101_0_010 << 23;
+    @SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23;
+    @SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23;
+    private static final int LoadStorePairImm7Offset = 15;
+
+    private static final int LogicalShiftOp = 0x0A000000;
+
+    private static final int ExceptionOp = 0xD4000000;
+    private static final int SystemImmediateOffset = 5;
+
+    @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16;
+
+    private static final int BarrierOp = 0xD503301F;
+    private static final int BarrierKindOffset = 8;
+
+    /**
+     * Encoding for all instructions.
+     */
+    public enum Instruction {
+        BCOND(0x54000000),
+        CBNZ(0x01000000),
+        CBZ(0x00000000),
+
+        B(0x00000000),
+        BL(0x80000000),
+        BR(0x001F0000),
+        BLR(0x003F0000),
+        RET(0x005F0000),
+
+        LDR(0x00000000),
+        LDRS(0x00800000),
+        LDXR(0x081f7c00),
+        LDAR(0x8dffc00),
+        LDAXR(0x85ffc00),
+
+        STR(0x00000000),
+        STXR(0x08007c00),
+        STLR(0x089ffc00),
+        STLXR(0x0800fc00),
+
+        LDP(0b1 << 22),
+        STP(0b0 << 22),
+
+        ADR(0x00000000),
+        ADRP(0x80000000),
+
+        ADD(0x00000000),
+        ADDS(ADD.encoding | AddSubSetFlag),
+        SUB(0x40000000),
+        SUBS(SUB.encoding | AddSubSetFlag),
+
+        NOT(0x00200000),
+        AND(0x00000000),
+        BIC(AND.encoding | NOT.encoding),
+        ORR(0x20000000),
+        ORN(ORR.encoding | NOT.encoding),
+        EOR(0x40000000),
+        EON(EOR.encoding | NOT.encoding),
+        ANDS(0x60000000),
+        BICS(ANDS.encoding | NOT.encoding),
+
+        ASRV(0x00002800),
+        RORV(0x00002C00),
+        LSRV(0x00002400),
+        LSLV(0x00002000),
+
+        CLS(0x00001400),
+        CLZ(0x00001000),
+        RBIT(0x00000000),
+        REVX(0x00000C00),
+        REVW(0x00000800),
+
+        MOVN(0x00000000),
+        MOVZ(0x40000000),
+        MOVK(0x60000000),
+
+        CSEL(0x00000000),
+        CSNEG(0x40000400),
+        CSINC(0x00000400),
+
+        BFM(0x20000000),
+        SBFM(0x00000000),
+        UBFM(0x40000000),
+        EXTR(0x13800000),
+
+        MADD(0x00000000),
+        MSUB(0x00008000),
+        SDIV(0x00000C00),
+        UDIV(0x00000800),
+
+        FMOV(0x00000000),
+        FMOVCPU2FPU(0x00070000),
+        FMOVFPU2CPU(0x00060000),
+
+        FCVTDS(0x00028000),
+        FCVTSD(0x00020000),
+
+        FCVTZS(0x00180000),
+        SCVTF(0x00020000),
+
+        FABS(0x00008000),
+        FSQRT(0x00018000),
+        FNEG(0x00010000),
+
+        FRINTZ(0x00058000),
+
+        FADD(0x00002000),
+        FSUB(0x00003000),
+        FMUL(0x00000000),
+        FDIV(0x00001000),
+        FMAX(0x00004000),
+        FMIN(0x00005000),
+
+        FMADD(0x00000000),
+        FMSUB(0x00008000),
+
+        FCMP(0x00000000),
+        FCMPZERO(0x00000008),
+        FCCMP(0x1E200400),
+        FCSEL(0x1E200C00),
+
+        INS(0x4e081c00),
+        UMOV(0x4e083c00),
+
+        CNT(0xe205800),
+        USRA(0x6f001400),
+
+        HLT(0x00400000),
+        BRK(0x00200000),
+
+        CLREX(0xd5033f5f),
+        HINT(0xD503201F),
+        DMB(0x000000A0),
+
+        BLR_NATIVE(0xc0000000);
+
+        public final int encoding;
+
+        Instruction(int encoding) {
+            this.encoding = encoding;
+        }
+
+    }
+
+    public enum ShiftType {
+        LSL(0),
+        LSR(1),
+        ASR(2),
+        ROR(3);
+
+        public final int encoding;
+
+        ShiftType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    public enum ExtendType {
+        UXTB(0),
+        UXTH(1),
+        UXTW(2),
+        UXTX(3),
+        SXTB(4),
+        SXTH(5),
+        SXTW(6),
+        SXTX(7);
+
+        public final int encoding;
+
+        ExtendType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Condition Flags for branches. See 4.3
+     */
+    public enum ConditionFlag {
+        // Integer | Floating-point meanings
+        /** Equal | Equal. */
+        EQ(0x0),
+
+        /** Not Equal | Not equal or unordered. */
+        NE(0x1),
+
+        /** Unsigned Higher or Same | Greater than, equal or unordered. */
+        HS(0x2),
+
+        /** Unsigned lower | less than. */
+        LO(0x3),
+
+        /** Minus (negative) | less than. */
+        MI(0x4),
+
+        /** Plus (positive or zero) | greater than, equal or unordered. */
+        PL(0x5),
+
+        /** Overflow set | unordered. */
+        VS(0x6),
+
+        /** Overflow clear | ordered. */
+        VC(0x7),
+
+        /** Unsigned higher | greater than or unordered. */
+        HI(0x8),
+
+        /** Unsigned lower or same | less than or equal. */
+        LS(0x9),
+
+        /** Signed greater than or equal | greater than or equal. */
+        GE(0xA),
+
+        /** Signed less than | less than or unordered. */
+        LT(0xB),
+
+        /** Signed greater than | greater than. */
+        GT(0xC),
+
+        /** Signed less than or equal | less than, equal or unordered. */
+        LE(0xD),
+
+        /** Always | always. */
+        AL(0xE),
+
+        /** Always | always (identical to AL, just to have valid 0b1111 encoding). */
+        NV(0xF);
+
+        public final int encoding;
+
+        ConditionFlag(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return ConditionFlag specified by decoding.
+         */
+        public static ConditionFlag fromEncoding(int encoding) {
+            return values()[encoding];
+        }
+
+        public ConditionFlag negate() {
+            switch (this) {
+                case EQ:
+                    return NE;
+                case NE:
+                    return EQ;
+                case HS:
+                    return LO;
+                case LO:
+                    return HS;
+                case MI:
+                    return PL;
+                case PL:
+                    return MI;
+                case VS:
+                    return VC;
+                case VC:
+                    return VS;
+                case HI:
+                    return LS;
+                case LS:
+                    return HI;
+                case GE:
+                    return LT;
+                case LT:
+                    return GE;
+                case GT:
+                    return LE;
+                case LE:
+                    return GT;
+                case AL:
+                case NV:
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public AArch64Assembler(TargetDescription target) {
+        super(target);
+    }
+
+    /* Conditional Branch (5.2.1) */
+
+    /**
+     * Branch conditionally.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void b(ConditionFlag condition, int imm21) {
+        b(condition, imm21, -1);
+    }
+
+    /**
+     * Branch conditionally. Inserts instruction into code buffer at pos.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        if (pos == -1) {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding);
+        } else {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos);
+        }
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbnz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1);
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos);
+    }
+
+    /**
+     * Compare and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1);
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos);
+    }
+
+    private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) {
+        assert reg.getRegisterCategory().equals(CPU);
+        int instrEncoding = instr.encoding | CompareBranchOp;
+        if (pos == -1) {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg));
+        } else {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos);
+        }
+    }
+
+    private static int getConditionalBranchImm(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned";
+        int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2;
+        return imm << ConditionalBranchImmOffset;
+    }
+
+    /* Unconditional Branch (immediate) (5.2.2) */
+
+    /**
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    protected void b(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, -1);
+    }
+
+    /**
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     * @param pos Position where instruction is inserted into code buffer.
+     */
+    protected void b(int imm28, int pos) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, pos);
+    }
+
+    /**
+     * Branch and link return address to register X30.
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    public void bl(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.BL, -1);
+    }
+
+    private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) {
+        assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned";
+        int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2;
+        int instrEncoding = instr.encoding | UnconditionalBranchImmOp;
+        if (pos == -1) {
+            emitInt(instrEncoding | imm);
+        } else {
+            emitInt(instrEncoding | imm, pos);
+        }
+    }
+
+    /* Unconditional Branch (register) (5.2.3) */
+
+    /**
+     * Branches to address in register and writes return address into register X30.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void blr(Register reg) {
+        unconditionalBranchRegInstruction(BLR, reg);
+    }
+
+    /**
+     * Branches to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    protected void br(Register reg) {
+        unconditionalBranchRegInstruction(BR, reg);
+    }
+
+    /**
+     * Return to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void ret(Register reg) {
+        unconditionalBranchRegInstruction(RET, reg);
+    }
+
+    private void unconditionalBranchRegInstruction(Instruction instr, Register reg) {
+        assert reg.getRegisterCategory().equals(CPU);
+        assert !reg.equals(zr);
+        assert !reg.equals(sp);
+        emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg));
+    }
+
+    /* Load-Store Single Register (5.3.1) */
+
+    /**
+     * Loads a srcSize value from address into rt zero-extending it.
+     *
+     * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(LDR, rt, address, General32, transferSize);
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(LDRS, rt, address, generalFromSize(targetSize), transferSize);
+    }
+
+    /**
+     * Stores register rt into memory pointed by address.
+     *
+     * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void str(int destSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64;
+        int transferSize = NumUtil.log2Ceil(destSize / 8);
+        loadStoreInstruction(STR, rt, address, General64, transferSize);
+    }
+
+    private void loadStoreInstruction(Instruction instr, Register reg, AArch64Address address, InstructionType type, int log2TransferSize) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0;
+        int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0;
+        int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase()));
+                break;
+            case IMMEDIATE_UNSCALED:
+                emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase()));
+                break;
+            case BASE_REGISTER_ONLY:
+                emitInt(memop | LoadStoreScaledOp | rs1(address.getBase()));
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+            case REGISTER_OFFSET:
+                ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX;
+                boolean shouldScale = address.isScaled() && log2TransferSize != 0;
+                emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase()));
+                break;
+            case PC_LITERAL:
+                assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger";
+                transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset;
+                emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset);
+                break;
+            case IMMEDIATE_POST_INDEXED:
+                emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            case IMMEDIATE_PRE_INDEXED:
+                emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode());
+        }
+    }
+
+    /**
+     *
+     */
+    public void ldp(int size, Register rt, Register rt2, AArch64Address address) {
+        assert size == 32 || size == 64;
+        loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size));
+    }
+
+    /**
+     * Store Pair of Registers calculates an address from a base register value and an immediate
+     * offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from
+     * two registers.
+     */
+    public void stp(int size, Register rt, Register rt2, AArch64Address address) {
+        assert size == 32 || size == 64;
+        loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size));
+    }
+
+    private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) {
+        int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_UNSCALED:
+                emitInt(memop | LoadStorePairOp);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode());
+        }
+    }
+
+    /* Load-Store Exclusive (5.3.6) */
+
+    /**
+     * Load address exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    protected void ldxr(int size, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(LDXR, rt, rn, transferSize);
+    }
+
+    /**
+     * Store address exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    protected void stxr(int size, Register rs, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(STXR, rs, rt, rn, transferSize);
+    }
+
+    /* Load-Acquire/Store-Release (5.3.7) */
+
+    /* non exclusive access */
+    /**
+     * Load acquire. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    protected void ldar(int size, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(LDAR, rt, rn, transferSize);
+    }
+
+    /**
+     * Store-release. Natural alignment of address is required.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    protected void stlr(int size, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        // Hack: Passing the zero-register means it is ignored when building the encoding.
+        exclusiveStoreInstruction(STLR, r0, rt, rn, transferSize);
+    }
+
+    /* exclusive access */
+    /**
+     * Load acquire exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    public void ldaxr(int size, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(LDAXR, rt, rn, transferSize);
+    }
+
+    /**
+     * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param rn general purpose register.
+     */
+    public void stlxr(int size, Register rs, Register rt, Register rn) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(STLXR, rs, rt, rn, transferSize);
+    }
+
+    private void exclusiveLoadInstruction(Instruction instr, Register reg, Register rn, int log2TransferSize) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert reg.getRegisterCategory().equals(CPU);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        emitInt(transferSizeEncoding | instr.encoding | 1 << ImmediateSizeOffset | rn(rn) | rt(reg));
+    }
+
+    /**
+     * Stores data from rt into address and sets rs to the returned exclusive access status.
+     *
+     * @param rs general purpose register into which the exclusive access status is written. May not
+     *            be null.
+     * @param rt general purpose register containing data to be written to memory at address. May
+     *            not be null
+     * @param rn general purpose register containing the address specifying where rt is written to.
+     * @param log2TransferSize log2Ceil of memory transfer size.
+     */
+    private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt));
+    }
+
+    /* PC-relative Address Calculation (5.4.4) */
+
+    /**
+     * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of
+     * the PC with its bottom 12-bits cleared, writing the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm Signed 33-bit offset with lower 12bits clear.
+     */
+    // protected void adrp(Register dst, long imm) {
+    // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero.";
+    // assert NumUtil.isSignedNbit(33, imm);
+    // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP);
+    // }
+
+    /**
+     * Adds a 21-bit signed offset to the program counter and writes the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm21 Signed 21-bit offset.
+     */
+    public void adr(Register dst, int imm21) {
+        emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21));
+    }
+
+    public void adr(Register dst, int imm21, int pos) {
+        emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos);
+    }
+
+    private static int getPcRelativeImmEncoding(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21);
+        int imm = imm21 & NumUtil.getNbitNumberInt(21);
+        // higher 19 bit
+        int immHi = (imm >> 2) << PcRelImmHiOffset;
+        // lower 2 bit
+        int immLo = (imm & 0x3) << PcRelImmLoOffset;
+        return immHi | immLo;
+    }
+
+    /* Arithmetic (Immediate) (5.4.1) */
+
+    /**
+     * dst = src + aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void add(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(ADD, dst, src, aimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(ADDS, dst, src, aimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src - aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(SUB, dst, src, aimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(SUBS, dst, src, aimm, generalFromSize(size));
+    }
+
+    private void addSubImmInstruction(Instruction instr, Register dst, Register src, int aimm, InstructionType type) {
+        emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src));
+    }
+
+    /**
+     * Encodes arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12-bit value or an unsigned 24-bit value
+     *            with the lower 12 bits zero.
+     * @return Representation of immediate for use with arithmetic instructions.
+     */
+    private static int encodeAimm(int imm) {
+        assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm;
+        if (NumUtil.isUnsignedNbit(12, imm)) {
+            return imm << ImmediateOffset;
+        } else {
+            // First 12-bit are zero, so shift immediate 12-bit and set flag to indicate
+            // shifted immediate value.
+            return (imm >>> 12 << ImmediateOffset) | AddSubShift12;
+        }
+    }
+
+    /**
+     * Checks whether immediate can be encoded as an arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with
+     *            the lower 12 bits 0.
+     * @return true if valid arithmetic immediate, false otherwise.
+     */
+    protected static boolean isAimm(int imm) {
+        return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0;
+    }
+
+    /* Logical (immediate) (5.4.2) */
+
+    /**
+     * dst = src & bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void and(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(AND, dst, src, bimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src & bimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void ands(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(sp);
+        logicalImmInstruction(ANDS, dst, src, bimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src ^ bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void eor(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(EOR, dst, src, bimm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(ORR, dst, src, bimm, generalFromSize(size));
+    }
+
+    private void logicalImmInstruction(Instruction instr, Register dst, Register src, long bimm, InstructionType type) {
+        // Mask higher bits off, since we always pass longs around even for the 32-bit instruction.
+        long bimmValue;
+        if (type == General32) {
+            assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1.";
+            bimmValue = bimm & NumUtil.getNbitNumberLong(32);
+        } else {
+            bimmValue = bimm;
+        }
+        int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == General64, bimmValue);
+        emitInt(type.encoding | instr.encoding | LogicalImmOp | immEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Move (wide immediate) (5.4.3) */
+
+    /**
+     * dst = uimm16 << shiftAmt.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(MOVZ, dst, uimm16, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = ~(uimm16 << shiftAmt).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(MOVN, dst, uimm16, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst<pos+15:pos> = uimm16.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than
+     *            size.
+     */
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        moveWideImmInstruction(MOVK, dst, uimm16, pos, generalFromSize(size));
+    }
+
+    private void moveWideImmInstruction(Instruction instr, Register dst, int uimm16, int shiftAmt, InstructionType type) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit";
+        assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt;
+        int shiftValue = shiftAmt >> 4;
+        emitInt(type.encoding | instr.encoding | MoveWideImmOp | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset);
+    }
+
+    /* Bitfield Operations (5.4.5) */
+
+    /**
+     * Bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size));
+    }
+
+    /**
+     * Unsigned bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size));
+    }
+
+    /**
+     * Signed bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(SBFM, dst, src, r, s, generalFromSize(size));
+    }
+
+    private void bitfieldInstruction(Instruction instr, Register dst, Register src, int r, int s, InstructionType type) {
+        assert !dst.equals(sp) && !dst.equals(zr);
+        assert !src.equals(sp) && !src.equals(zr);
+        assert s >= 0 && s < type.width && r >= 0 && r < type.width;
+        int sf = type == General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | instr.encoding | BitfieldImmOp | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src));
+    }
+
+    /* Extract (Immediate) (5.4.6) */
+
+    /**
+     * Extract. dst = src1:src2<lsb+31:lsb>
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param lsb must be in range 0 to size - 1.
+     */
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        InstructionType type = generalFromSize(size);
+        assert lsb >= 0 && lsb < type.width;
+        int sf = type == General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (shifted register) (5.5.1) */
+
+    /**
+     * dst = src1 + shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(ADD, dst, src1, src2, shiftType, imm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(SUB, dst, src1, src2, shiftType, imm, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size));
+    }
+
+    private void addSubShiftedInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type) {
+        assert shiftType != ShiftType.ROR;
+        assert imm >= 0 && imm < type.width;
+        emitInt(type.encoding | instr.encoding | AddSubShiftedOp | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (extended register) (5.5.2) */
+    /**
+     * dst = src1 + extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(ADD, dst, src1, src2, extendType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 + extendType(src2) << imm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(ADDS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(SUB, dst, src1, src2, extendType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm and sets flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(SUBS, dst, src1, src2, extendType, shiftAmt, generalFromSize(size));
+    }
+
+    private void addSubExtendedInstruction(Instruction instr, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type) {
+        assert shiftAmt >= 0 && shiftAmt <= 4;
+        emitInt(type.encoding | instr.encoding | AddSubExtendedOp | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Logical (shifted register) (5.5.3) */
+    /**
+     * dst = src1 & shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(AND, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 & shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(ANDS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(BIC, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(BICS, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 ^ ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(EON, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 ^ shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(EOR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 | shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(ORR, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 | ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(ORN, dst, src1, src2, shiftType, shiftAmt, generalFromSize(size));
+    }
+
+    private void logicalRegInstruction(Instruction instr, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert shiftAmt >= 0 && shiftAmt < type.width;
+        emitInt(type.encoding | instr.encoding | LogicalShiftOp | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Variable Shift (5.5.4) */
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(ASRV, dst, src1, src2, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 << (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(LSLV, dst, src1, src2, generalFromSize(size));
+    }
+
+    /**
+     * dst = src1 >>> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(LSRV, dst, src1, src2, generalFromSize(size));
+    }
+
+    /**
+     * dst = rotateRight(src1, (src2 & log2(size))).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(RORV, dst, src1, src2, generalFromSize(size));
+    }
+
+    /* Bit Operations (5.5.5) */
+
+    /**
+     * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit
+     * in dst, that are the same as the topmost bit. The count does not include the topmost bit
+     * itself , so the result will be in the range 0 to size-1 inclusive.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void cls(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(CLS, dst, src, generalFromSize(size));
+    }
+
+    /**
+     * Counts leading zeros.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    public void clz(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(CLZ, dst, src, generalFromSize(size));
+    }
+
+    /**
+     * Reverses bits.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void rbit(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size));
+    }
+
+    /**
+     * Reverses bytes.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src source register. May not be null or the stackpointer.
+     */
+    public void rev(int size, Register dst, Register src) {
+        if (size == 64) {
+            dataProcessing1SourceOp(REVX, dst, src, generalFromSize(size));
+        } else {
+            assert size == 32;
+            dataProcessing1SourceOp(REVW, dst, src, generalFromSize(size));
+        }
+    }
+
+    /* Conditional Data Processing (5.5.6) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(CSEL, dst, src1, src2, condition, generalFromSize(size));
+    }
+
+    /**
+     * Conditional select negate. dst = src1 if condition else -src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(CSNEG, dst, src1, src2, condition, generalFromSize(size));
+    }
+
+    /**
+     * Conditional increase. dst = src1 if condition else src2 + 1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(CSINC, dst, src1, src2, condition, generalFromSize(size));
+    }
+
+    private void conditionalSelectInstruction(Instruction instr, Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(type.encoding | instr.encoding | ConditionalSelectOp | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Integer Multiply/Divide (5.6) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(MADD, dst, src1, src2, src3, generalFromSize(size));
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(MSUB, dst, src1, src2, src3, generalFromSize(size));
+    }
+
+    /**
+     * Signed multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011010 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011110 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset);
+    }
+
+    /**
+     * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011101 << 21 | dst.encoding | rs1(src1) | rs2(src2) | 0b011111 << ImmediateOffset);
+    }
+
+    /**
+     * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /**
+     * Signed divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(SDIV, dst, src1, src2, generalFromSize(size));
+    }
+
+    /**
+     * Unsigned divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(UDIV, dst, src1, src2, generalFromSize(size));
+    }
+
+    private void dataProcessing1SourceOp(Instruction instr, Register dst, Register src, InstructionType type) {
+        emitInt(type.encoding | instr.encoding | DataProcessing1SourceOp | rd(dst) | rs1(src));
+    }
+
+    private void dataProcessing2SourceOp(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(type.encoding | instr.encoding | DataProcessing2SourceOp | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Floating point operations */
+
+    /* Load-Store Single FP register (5.7.1.1) */
+    /**
+     * Floating point load.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fldr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(LDR, rt, address, InstructionType.FP32, transferSize);
+    }
+
+    /**
+     * Floating point store.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fstr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(STR, rt, address, InstructionType.FP64, transferSize);
+    }
+
+    /* Floating-point Move (register) (5.7.2) */
+
+    /**
+     * Floating point move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void fmov(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FMOV, dst, src, floatFromSize(size));
+    }
+
+    /**
+     * Move size bits from floating point register unchanged to general purpose register.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param dst general purpose register. May not be null, stack-pointer or zero-register
+     * @param src floating point register. May not be null.
+     */
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert src.getRegisterCategory().equals(SIMD);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU);
+    }
+
+    /**
+     * Move size bits from general purpose register unchanged to floating point register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or stack-pointer.
+     */
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(CPU);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU);
+    }
+
+    private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) {
+        int sf = is64bit ? FP64.encoding | General64.encoding : FP32.encoding | General32.encoding;
+        emitInt(sf | instr.encoding | FpConvertOp | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Move (immediate) (5.7.3) */
+
+    /**
+     * Move immediate into register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    protected void fmov(int size, Register dst, double imm) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        int immEncoding;
+        if (type == FP64) {
+            immEncoding = getDoubleImmediate(imm);
+        } else {
+            assert imm == (float) imm : "float mov must use an immediate that can be represented using a float.";
+            immEncoding = getFloatImmediate((float) imm);
+        }
+        emitInt(type.encoding | FMOV.encoding | FpImmOp | immEncoding | rd(dst));
+    }
+
+    private static int getDoubleImmediate(double imm) {
+        assert isDoubleImmediate(imm);
+        // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long repr = Double.doubleToRawLongBits(imm);
+        int a = (int) (repr >>> 63) << 7;
+        int b = (int) ((repr >>> 61) & 0x1) << 6;
+        int cToH = (int) (repr >>> 48) & 0x3f;
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isDoubleImmediate(double imm) {
+        // Valid values will have the form:
+        // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long bits = Double.doubleToRawLongBits(imm);
+        // lower 48 bits are cleared
+        if ((bits & NumUtil.getNbitNumberLong(48)) != 0) {
+            return false;
+        }
+        // bits[61..54] are all set or all cleared.
+        long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) {
+            return false;
+        }
+        // bits[62] and bits[61] are opposites.
+        return ((bits ^ (bits << 1)) & (1L << 62)) != 0;
+    }
+
+    private static int getFloatImmediate(float imm) {
+        assert isFloatImmediate(imm);
+        // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int repr = Float.floatToRawIntBits(imm);
+        int a = (repr >>> 31) << 7;
+        int b = ((repr >>> 29) & 0x1) << 6;
+        int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6);
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isFloatImmediate(float imm) {
+        // Valid values will have the form:
+        // aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int bits = Float.floatToRawIntBits(imm);
+        // lower 20 bits are cleared.
+        if ((bits & NumUtil.getNbitNumberInt(19)) != 0) {
+            return false;
+        }
+        // bits[29..25] are all set or all cleared
+        int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) {
+            return false;
+        }
+        // bits[29] and bits[30] have to be opposite
+        return ((bits ^ (bits << 1)) & (1 << 30)) != 0;
+    }
+
+    /* Convert Floating-point Precision (5.7.4.1) */
+    /* Converts float to double and vice-versa */
+
+    /**
+     * Convert float to double and vice-versa.
+     *
+     * @param srcSize size of source register in bits.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvt(int srcSize, Register dst, Register src) {
+        if (srcSize == 32) {
+            fpDataProcessing1Source(FCVTDS, dst, src, floatFromSize(srcSize));
+        } else {
+            fpDataProcessing1Source(FCVTSD, dst, src, floatFromSize(srcSize));
+        }
+    }
+
+    /* Convert to Integer (5.7.4.2) */
+
+    /**
+     * Convert floating point to integer. Rounds towards zero.
+     *
+     * @param targetSize size of integer register. 32 or 64.
+     * @param srcSize size of floating point register. 32 or 64.
+     * @param dst general purpose register. May not be null, the zero-register or the stackpointer.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        assert !dst.equals(zr) && !dst.equals(sp);
+        assert src.getRegisterCategory().equals(SIMD);
+        fcvtCpuFpuInstruction(FCVTZS, dst, src, generalFromSize(targetSize), floatFromSize(srcSize));
+    }
+
+    /* Convert from Integer (5.7.4.2) */
+    /**
+     * Converts integer to floating point. Uses rounding mode defined by FCPR.
+     *
+     * @param targetSize size of floating point register. 32 or 64.
+     * @param srcSize size of integer register. 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or the stackpointer.
+     */
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert !src.equals(sp);
+        fcvtCpuFpuInstruction(SCVTF, dst, src, floatFromSize(targetSize), generalFromSize(srcSize));
+    }
+
+    private void fcvtCpuFpuInstruction(Instruction instr, Register dst, Register src, InstructionType type1, InstructionType type2) {
+        emitInt(type1.encoding | type2.encoding | instr.encoding | FpConvertOp | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Round to Integral (5.7.5) */
+
+    /**
+     * Rounds floating-point to integral. Rounds towards zero.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void frintz(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size));
+    }
+
+    /* Floating-point Arithmetic (1 source) (5.7.6) */
+
+    /**
+     * dst = |src|.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fabs(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FABS, dst, src, floatFromSize(size));
+    }
+
+    /**
+     * dst = -neg.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fneg(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FNEG, dst, src, floatFromSize(size));
+    }
+
+    /**
+     * dst = Sqrt(src).
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fsqrt(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FSQRT, dst, src, floatFromSize(size));
+    }
+
+    private void fpDataProcessing1Source(Instruction instr, Register dst, Register src, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | instr.encoding | Fp1SourceOp | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Arithmetic (2 source) (5.7.7) */
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(FADD, dst, src1, src2, floatFromSize(size));
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(FSUB, dst, src1, src2, floatFromSize(size));
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(FMUL, dst, src1, src2, floatFromSize(size));
+    }
+
+    /**
+     * dst = src1 / src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(FDIV, dst, src1, src2, floatFromSize(size));
+    }
+
+    private void fpDataProcessing2Source(Instruction instr, Register dst, Register src1, Register src2, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | instr.encoding | Fp2SourceOp | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Floating-point Multiply-Add (5.7.9) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(FMADD, dst, src1, src2, src3, floatFromSize(size));
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(FMSUB, dst, src1, src2, src3, floatFromSize(size));
+    }
+
+    private void fpDataProcessing3Source(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        assert src3.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | instr.encoding | Fp3SourceOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /* Floating-point Comparison (5.7.10) */
+
+    /**
+     * Compares src1 to src2.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fcmp(int size, Register src1, Register src2) {
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCMP.encoding | FpCmpOp | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param uimm4 condition flags that are used if condition is false.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        assert NumUtil.isUnsignedNbit(4, uimm4);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Compare register to 0.0 .
+     *
+     * @param size register size.
+     * @param src floating point register. May not be null.
+     */
+    public void fcmpZero(int size, Register src) {
+        assert src.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src));
+    }
+
+    /* Floating-point Conditional Select (5.7.11) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Debug exceptions (5.9.1.2) */
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void hlt(int uimm16) {
+        exceptionInstruction(HLT, uimm16);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void brk(int uimm16) {
+        exceptionInstruction(BRK, uimm16);
+    }
+
+    private void exceptionInstruction(Instruction instr, int uimm16) {
+        assert NumUtil.isUnsignedNbit(16, uimm16);
+        emitInt(instr.encoding | ExceptionOp | uimm16 << SystemImmediateOffset);
+    }
+
+    /* Architectural hints (5.9.4) */
+    public enum SystemHint {
+        NOP(0x0),
+        YIELD(0x1),
+        WFE(0x2),
+        WFI(0x3),
+        SEV(0x4),
+        SEVL(0x5);
+
+        private final int encoding;
+
+        SystemHint(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Architectural hints.
+     *
+     * @param hint Can be any of the defined hints. May not be null.
+     */
+    protected void hint(SystemHint hint) {
+        emitInt(HINT.encoding | hint.encoding << SystemImmediateOffset);
+    }
+
+    /**
+     * Clear Exclusive: clears the local record of the executing processor that an address has had a
+     * request for an exclusive access.
+     */
+    protected void clrex() {
+        emitInt(CLREX.encoding);
+    }
+
+    /**
+     * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying
+     * barrier.
+     *
+     * We only need synchronization across the inner shareable domain (see B2-90 in the Reference
+     * documentation).
+     */
+    public enum BarrierKind {
+        LOAD_LOAD(0x9, "ISHLD"),
+        LOAD_STORE(0x9, "ISHLD"),
+        STORE_STORE(0xA, "ISHST"),
+        ANY_ANY(0xB, "ISH");
+
+        public final int encoding;
+        public final String optionName;
+
+        BarrierKind(int encoding, String optionName) {
+            this.encoding = encoding;
+            this.optionName = optionName;
+        }
+    }
+
+    /**
+     * Data Memory Barrier.
+     *
+     * @param barrierKind barrier that is issued. May not be null.
+     */
+    public void dmb(BarrierKind barrierKind) {
+        emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java
new file mode 100644
index 0000000..7c0d184
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java
@@ -0,0 +1,1407 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.asm.aarch64;
+
+import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.BASE_REGISTER_ONLY;
+import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET;
+import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED;
+import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED;
+import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET;
+import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE;
+import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX;
+import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+public class AArch64MacroAssembler extends AArch64Assembler {
+
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(r8), new ScratchRegister(r9)};
+
+    // Points to the next free scratch register
+    private int nextFreeScratchRegister = 0;
+
+    public AArch64MacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    public class ScratchRegister implements AutoCloseable {
+        private final Register register;
+
+        public ScratchRegister(Register register) {
+            this.register = register;
+        }
+
+        public Register getRegister() {
+            return register;
+        }
+
+        @Override
+        public void close() {
+            assert nextFreeScratchRegister > 0 : "Close called too often";
+            nextFreeScratchRegister--;
+        }
+    }
+
+    public ScratchRegister getScratchRegister() {
+        return scratchRegister[nextFreeScratchRegister++];
+    }
+
+    /**
+     * Specifies what actions have to be taken to turn an arbitrary address of the form
+     * {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address.
+     */
+    public static class AddressGenerationPlan {
+        public final WorkPlan workPlan;
+        public final AArch64Address.AddressingMode addressingMode;
+        public final boolean needsScratch;
+
+        public enum WorkPlan {
+            /**
+             * Can be used as-is without extra work.
+             */
+            NO_WORK,
+            /**
+             * Add scaled displacement to index register.
+             */
+            ADD_TO_INDEX,
+            /**
+             * Add unscaled displacement to base register.
+             */
+            ADD_TO_BASE,
+        }
+
+        /**
+         * @param workPlan Work necessary to generate a valid address.
+         * @param addressingMode Addressing mode of generated address.
+         * @param needsScratch True if generating address needs a scatch register, false otherwise.
+         */
+        public AddressGenerationPlan(WorkPlan workPlan, AArch64Address.AddressingMode addressingMode, boolean needsScratch) {
+            this.workPlan = workPlan;
+            this.addressingMode = addressingMode;
+            this.needsScratch = needsScratch;
+        }
+    }
+
+    /**
+     * Generates an addressplan for an address of the form
+     * {@code base + displacement [+ index [<< log2(transferSize)]]} with the index register and
+     * scaling being optional.
+     *
+     * @param displacement an arbitrary displacement.
+     * @param hasIndexRegister true if the address uses an index register, false otherwise. non null
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AddressGenerationPlan that specifies the actions necessary to generate a valid
+     *         AArch64Address for the given parameters.
+     */
+    public static AddressGenerationPlan generateAddressPlan(long displacement, boolean hasIndexRegister, int transferSize) {
+        assert transferSize == 0 || transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        boolean indexScaled = transferSize != 0;
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        boolean displacementScalable = indexScaled && (displacement & (transferSize - 1)) == 0;
+        if (displacement == 0) {
+            // register offset without any work beforehand.
+            return new AddressGenerationPlan(NO_WORK, REGISTER_OFFSET, false);
+        } else {
+            if (hasIndexRegister) {
+                if (displacementScalable) {
+                    boolean needsScratch = !isArithmeticImmediate(scaledDisplacement);
+                    return new AddressGenerationPlan(ADD_TO_INDEX, REGISTER_OFFSET, needsScratch);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            } else {
+                if (NumUtil.isSignedNbit(9, displacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_UNSCALED, false);
+                } else if (displacementScalable && NumUtil.isUnsignedNbit(12, scaledDisplacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_SCALED, false);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns an AArch64Address pointing to
+     * {@code base + displacement + index << log2(transferSize)}.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param index general purpose register. May not be null or the stack pointer.
+     * @param signExtendIndex if true consider index register a word register that should be
+     *            sign-extended before being added.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be null
+     *            or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at
+     *         {@code base + displacement + index << log2(transferSize)}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register index, boolean signExtendIndex, int transferSize, Register additionalReg, boolean allowOverwrite) {
+        AddressGenerationPlan plan = generateAddressPlan(displacement, !index.equals(zr), transferSize);
+        assert allowOverwrite || !zr.equals(additionalReg) || plan.workPlan == NO_WORK;
+        assert !plan.needsScratch || !zr.equals(additionalReg);
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        Register newIndex = index;
+        Register newBase = base;
+        int immediate;
+        switch (plan.workPlan) {
+            case NO_WORK:
+                if (plan.addressingMode == IMMEDIATE_SCALED) {
+                    immediate = (int) scaledDisplacement;
+                } else {
+                    immediate = (int) displacement;
+                }
+                break;
+            case ADD_TO_INDEX:
+                newIndex = allowOverwrite ? index : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, scaledDisplacement);
+                    add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg);
+                } else {
+                    add(signExtendIndex ? 32 : 64, newIndex, index, (int) scaledDisplacement);
+                }
+                immediate = 0;
+                break;
+            case ADD_TO_BASE:
+                newBase = allowOverwrite ? base : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, displacement);
+                    add(64, newBase, base, additionalReg);
+                } else {
+                    add(64, newBase, base, (int) displacement);
+                }
+                immediate = 0;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        AArch64Address.AddressingMode addressingMode = plan.addressingMode;
+        ExtendType extendType = null;
+        if (addressingMode == REGISTER_OFFSET) {
+            if (newIndex.equals(zr)) {
+                addressingMode = BASE_REGISTER_ONLY;
+            } else if (signExtendIndex) {
+                addressingMode = EXTENDED_REGISTER_OFFSET;
+                extendType = ExtendType.SXTW;
+            }
+        }
+        return AArch64Address.createAddress(addressingMode, newBase, newIndex, immediate, transferSize != 0, extendType);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Specifies the memory
+     * transfer size to allow some optimizations when building the address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be
+     *            null, zero register or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register additionalReg, int transferSize, boolean allowOverwrite) {
+        assert additionalReg.getRegisterCategory().equals(CPU);
+        return makeAddress(base, displacement, zr, /* sign-extend */false, transferSize, additionalReg, allowOverwrite);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Fails if address cannot be
+     * represented without overwriting base register or using a scratch register.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, int transferSize) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false);
+    }
+
+    /**
+     * Loads memory address into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param address address whose value is loaded into dst. May not be null,
+     *            {@link org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_POST_INDEXED
+     *            POST_INDEXED} or
+     *            {@link org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_PRE_INDEXED
+     *            IMMEDIATE_PRE_INDEXED}
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. Can be 1, 2, 4 or 8.
+     */
+    public void loadAddress(Register dst, AArch64Address address, int transferSize) {
+        assert transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        assert dst.getRegisterCategory().equals(CPU);
+        int shiftAmt = NumUtil.log2Ceil(transferSize);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                int scaledImmediate = address.getImmediateRaw() << shiftAmt;
+                int lowerBits = scaledImmediate & NumUtil.getNbitNumberInt(12);
+                int higherBits = scaledImmediate & ~NumUtil.getNbitNumberInt(12);
+                boolean firstAdd = true;
+                if (lowerBits != 0) {
+                    add(64, dst, address.getBase(), lowerBits);
+                    firstAdd = false;
+                }
+                if (higherBits != 0) {
+                    Register src = firstAdd ? address.getBase() : dst;
+                    add(64, dst, src, higherBits);
+                }
+                break;
+            case IMMEDIATE_UNSCALED:
+                int immediate = address.getImmediateRaw();
+                add(64, dst, address.getBase(), immediate);
+                break;
+            case REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), ShiftType.LSL, address.isScaled() ? shiftAmt : 0);
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0);
+                break;
+            case PC_LITERAL:
+                super.adr(dst, address.getImmediateRaw());
+                break;
+            case BASE_REGISTER_ONLY:
+                movx(dst, address.getBase());
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public void movx(Register dst, Register src) {
+        mov(64, dst, src);
+    }
+
+    public void mov(int size, Register dst, Register src) {
+        if (dst.equals(sp) || src.equals(sp)) {
+            add(size, dst, src, 0);
+        } else {
+            or(size, dst, zr, src);
+        }
+    }
+
+    /**
+     * Generates a 64-bit immediate move code sequence.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param imm
+     */
+    private void mov64(Register dst, long imm) {
+        // We have to move all non zero parts of the immediate in 16-bit chunks
+        boolean firstMove = true;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (chunk == 0) {
+                continue;
+            }
+            if (firstMove) {
+                movz(64, dst, chunk, offset);
+                firstMove = false;
+            } else {
+                movk(64, dst, chunk, offset);
+            }
+        }
+        assert !firstMove;
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, long imm) {
+        assert dst.getRegisterCategory().equals(CPU);
+        if (imm == 0L) {
+            movx(dst, zr);
+        } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            or(64, dst, zr, imm);
+        } else if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            mov(dst, (int) imm);
+            sxt(64, 32, dst, dst);
+        } else {
+            mov64(dst, imm);
+        }
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, int imm) {
+        mov(dst, imm & 0xFFFF_FFFFL);
+    }
+
+    /**
+     * Generates a 48-bit immediate move code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * In AArch64 mode the virtual address space is 48-bits in size, so we only need three
+     * instructions to create a patchable instruction sequence that can reach anywhere.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param imm
+     */
+    public void movNativeAddress(Register dst, long imm) {
+        assert (imm & 0xFFFF_0000_0000_0000L) == 0;
+        // We have to move all non zero parts of the immediate in 16-bit chunks
+        boolean firstMove = true;
+        for (int offset = 0; offset < 48; offset += 16) {
+            int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (firstMove) {
+                movz(64, dst, chunk, offset);
+                firstMove = false;
+            } else {
+                movk(64, dst, chunk, offset);
+            }
+        }
+        assert !firstMove;
+    }
+
+    /**
+     * @return Number of instructions necessary to load immediate into register.
+     */
+    public static int nrInstructionsToMoveImmediate(long imm) {
+        if (imm == 0L || LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            return 1;
+        }
+        if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            return 2;
+        }
+        int nrInstructions = 0;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int part = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (part != 0) {
+                nrInstructions++;
+            }
+        }
+        return nrInstructions;
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it if necessary.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert targetSize == 32 || targetSize == 64;
+        assert srcSize <= targetSize;
+        if (targetSize == srcSize) {
+            super.ldr(srcSize, rt, address);
+        } else {
+            super.ldrs(targetSize, srcSize, rt, address);
+        }
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param result general purpose register. May not be null or the stackpointer.
+     * @param trueValue general purpose register. May not be null or the stackpointer.
+     * @param falseValue general purpose register. May not be null or the stackpointer.
+     * @param cond any condition flag. May not be null.
+     */
+    public void cmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag cond) {
+        super.csel(size, result, trueValue, falseValue, cond);
+    }
+
+    /**
+     * Conditional set. dst = 1 if condition else 0.
+     *
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param condition any condition. May not be null.
+     */
+    public void cset(Register dst, ConditionFlag condition) {
+        super.csinc(32, dst, zr, zr, condition.negate());
+    }
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void add(int size, Register dst, Register src1, Register src2) {
+        super.add(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void adds(int size, Register dst, Register src1, Register src2) {
+        super.adds(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * dst = src1 - src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void subs(int size, Register dst, Register src1, Register src2) {
+        super.subs(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * Returns the ExtendType for the given size that corresponds to a no-op.
+     *
+     * I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX.
+     *
+     * @param size
+     */
+    private static ExtendType getNopExtendType(int size) {
+        if (size == 64) {
+            return ExtendType.UXTX;
+        } else if (size == 32) {
+            return ExtendType.UXTW;
+        } else {
+            throw GraalError.shouldNotReachHere("No-op ");
+        }
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void sub(int size, Register dst, Register src1, Register src2) {
+        super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.add(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sub(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = -src1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void neg(int size, Register dst, Register src) {
+        sub(size, dst, zr, src);
+    }
+
+    /**
+     * dst = src + immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void add(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            sub(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.add(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void adds(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            subs(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.adds(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void sub(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            add(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void subs(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            adds(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void mul(int size, Register dst, Register src1, Register src2) {
+        super.madd(size, dst, src1, src2, zr);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void umulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.umulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.umaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * signed multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void smulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.smulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.smaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * dst = src1 % src2. Signed.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void rem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d if nd >= 0
+        // n % d = n - Ceil(n / d) * d else
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.sdiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * dst = src1 % src2. Unsigned.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void urem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.udiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * Add/subtract instruction encoding supports 12-bit immediate values.
+     *
+     * @param imm immediate value to be tested.
+     * @return true if immediate can be used directly for arithmetic instructions (add/sub), false
+     *         otherwise.
+     */
+    public static boolean isArithmeticImmediate(long imm) {
+        // If we have a negative immediate we just use the opposite operator. I.e.: x - (-5) == x +
+        // 5.
+        return NumUtil.isInt(Math.abs(imm)) && isAimm((int) Math.abs(imm));
+    }
+
+    /**
+     * Compare instructions are add/subtract instructions and so support 12-bit immediate values.
+     *
+     * @param imm immediate value to be tested.
+     * @return true if immediate can be used directly with comparison instructions, false otherwise.
+     */
+    public static boolean isComparisonImmediate(long imm) {
+        return isArithmeticImmediate(imm);
+    }
+
+    /**
+     * Move wide immediate instruction encoding supports 16-bit immediate values which can be
+     * optionally-shifted by multiples of 16 (i.e. 0, 16, 32, 48).
+     *
+     * @return true if immediate can be moved directly into a register, false otherwise.
+     */
+    public static boolean isMovableImmediate(long imm) {
+        // // Positions of first, respectively last set bit.
+        // int start = Long.numberOfTrailingZeros(imm);
+        // int end = 64 - Long.numberOfLeadingZeros(imm);
+        // int length = end - start;
+        // if (length > 16) {
+        // return false;
+        // }
+        // // We can shift the necessary part of the immediate (i.e. everything between the first
+        // and
+        // // last set bit) by as much as 16 - length around to arrive at a valid shift amount
+        // int tolerance = 16 - length;
+        // int prevMultiple = NumUtil.roundDown(start, 16);
+        // int nextMultiple = NumUtil.roundUp(start, 16);
+        // return start - prevMultiple <= tolerance || nextMultiple - start <= tolerance;
+        /*
+         * This is a bit optimistic because the constant could also be for an arithmetic instruction
+         * which only supports 12-bits. That case needs to be handled in the backend.
+         */
+        return NumUtil.isInt(Math.abs(imm)) && NumUtil.isUnsignedNbit(16, (int) Math.abs(imm));
+    }
+
+    /**
+     * dst = src << (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void shl(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, (size - shift) & (size - 1), size - 1 - shift);
+    }
+
+    /**
+     * dst = src1 << (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void shl(int size, Register dst, Register src, Register shift) {
+        super.lsl(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >>> (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void lshr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >>> (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void lshr(int size, Register dst, Register src, Register shift) {
+        super.lsr(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >> (shiftAmt & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void ashr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sbfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void ashr(int size, Register dst, Register src, Register shift) {
+        super.asr(size, dst, src, shift);
+    }
+
+    /**
+     * Clamps shiftAmt into range 0 <= shiftamt < size according to JLS.
+     *
+     * @param size size of operation.
+     * @param shiftAmt arbitrary shift amount.
+     * @return value between 0 and size - 1 inclusive that is equivalent to shiftAmt according to
+     *         JLS.
+     */
+    private static int clampShiftAmt(int size, long shiftAmt) {
+        return (int) (shiftAmt & (size - 1));
+    }
+
+    /**
+     * dst = src1 & src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void and(int size, Register dst, Register src1, Register src2) {
+        super.and(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 ^ src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void eor(int size, Register dst, Register src1, Register src2) {
+        super.eor(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 | src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void or(int size, Register dst, Register src1, Register src2) {
+        super.orr(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link AArch64Assembler.LogicalImmediateTable} for exact
+     *            definition.
+     */
+    public void or(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    /**
+     * dst = ~src.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void not(int size, Register dst, Register src) {
+        super.orn(size, dst, zr, src, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Sign-extend value from src into dst.
+     *
+     * @param destSize destination register size. Has to be 32 or 64.
+     * @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     */
+    public void sxt(int destSize, int srcSize, Register dst, Register src) {
+        assert (destSize == 32 || destSize == 64) && srcSize < destSize;
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32;
+        int[] srcSizeValues = {7, 15, 31};
+        super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]);
+    }
+
+    /**
+     * dst = src if condition else -src.
+     *
+     * @param size register size. Must be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src general purpose register. May not be null or the stackpointer.
+     * @param condition any condition except AV or NV. May not be null.
+     */
+    public void csneg(int size, Register dst, Register src, ConditionFlag condition) {
+        super.csneg(size, dst, src, src, condition.negate());
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 64-bit instructions.
+     */
+    public static boolean isLogicalImmediate(long imm) {
+        return LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO;
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 32-bit instructions.
+     */
+    public static boolean isLogicalImmediate(int imm) {
+        return LogicalImmediateTable.isRepresentable(imm) == LogicalImmediateTable.Representable.YES;
+    }
+
+    /* Float instructions */
+
+    /**
+     * Moves integer to float, float to integer, or float to float. Does not support integer to
+     * integer moves.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer or zero register. Cannot be null in any case.
+     * @param src Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer. Cannot be null in any case.
+     */
+    @Override
+    public void fmov(int size, Register dst, Register src) {
+        assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) : "src and dst cannot both be integer registers.";
+        if (dst.getRegisterCategory().equals(CPU)) {
+            super.fmovFpu2Cpu(size, dst, src);
+        } else if (src.getRegisterCategory().equals(CPU)) {
+            super.fmovCpu2Fpu(size, dst, src);
+        } else {
+            super.fmov(size, dst, src);
+        }
+    }
+
+    /**
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    @Override
+    public void fmov(int size, Register dst, double imm) {
+        if (imm == 0.0) {
+            assert Double.doubleToRawLongBits(imm) == 0L : "-0.0 is no valid immediate.";
+            super.fmovCpu2Fpu(size, dst, zr);
+        } else {
+            super.fmov(size, dst, imm);
+        }
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isDoubleImmediate(double imm) {
+        return Double.doubleToRawLongBits(imm) == 0L || AArch64Assembler.isDoubleImmediate(imm);
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isFloatImmediate(float imm) {
+        return Float.floatToRawIntBits(imm) == 0 || AArch64Assembler.isFloatImmediate(imm);
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param result floating point register. May not be null.
+     * @param trueValue floating point register. May not be null.
+     * @param falseValue floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fcmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag condition) {
+        super.fcsel(size, result, trueValue, falseValue, condition);
+    }
+
+    /**
+     * dst = src1 % src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating-point register. May not be null.
+     * @param n numerator. Floating-point register. May not be null.
+     * @param d denominator. Floating-point register. May not be null.
+     */
+    public void frem(int size, Register dst, Register n, Register d) {
+        // There is no frem instruction, instead we compute the remainder using the relation:
+        // rem = n - Truncating(n / d) * d
+        super.fdiv(size, dst, n, d);
+        super.frintz(size, dst, dst);
+        super.fmsub(size, dst, dst, d, n);
+    }
+
+    /* Branches */
+
+    /**
+     * Compares x and y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void cmp(int size, Register x, Register y) {
+        super.subs(size, zr, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Compares x to y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it.
+     */
+    public void cmp(int size, Register x, int y) {
+        if (y < 0) {
+            super.adds(size, zr, x, -y);
+        } else {
+            super.subs(size, zr, x, y);
+        }
+    }
+
+    /**
+     * Sets condition flags according to result of x & y.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void ands(int size, Register dst, Register x, Register y) {
+        super.ands(size, dst, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * When patching up Labels we have to know what kind of code to generate.
+     */
+    public enum PatchLabelKind {
+        BRANCH_CONDITIONALLY(0x0),
+        BRANCH_UNCONDITIONALLY(0x1),
+        BRANCH_NONZERO(0x2),
+        BRANCH_ZERO(0x3),
+        JUMP_ADDRESS(0x4),
+        ADR(0x5);
+
+        /**
+         * Offset by which additional information for branch conditionally, branch zero and branch
+         * non zero has to be shifted.
+         */
+        public static final int INFORMATION_OFFSET = 5;
+
+        public final int encoding;
+
+        PatchLabelKind(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return PatchLabelKind with given encoding.
+         */
+        private static PatchLabelKind fromEncoding(int encoding) {
+            return values()[encoding & NumUtil.getNbitNumberInt(INFORMATION_OFFSET)];
+        }
+
+    }
+
+    public void adr(Register dst, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.adr(dst, offset);
+        } else {
+            label.addPatchAt(position());
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.ADR.encoding | dst.encoding << PatchLabelKind.INFORMATION_OFFSET);
+        }
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbnz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbnz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_NONZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_ZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Branches to label if condition is true.
+     *
+     * @param condition any condition value allowed. Non null.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(condition, offset);
+        } else {
+            label.addPatchAt(position());
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_CONDITIONALLY.encoding | condition.encoding << PatchLabelKind.INFORMATION_OFFSET);
+        }
+    }
+
+    /**
+     * Branches if condition is true. Address of jump is patched up by HotSpot c++ code.
+     *
+     * @param condition any condition value allowed. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition) {
+        // Correct offset is fixed up by HotSpot later.
+        super.b(condition, 0);
+    }
+
+    /**
+     * Jumps to label.
+     *
+     * param label Can only handle signed 28-bit offsets. May be unbound. Non null.
+     */
+    @Override
+    public void jmp(Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(offset);
+        } else {
+            label.addPatchAt(position());
+            emitInt(PatchLabelKind.BRANCH_UNCONDITIONALLY.encoding);
+        }
+    }
+
+    /**
+     * Jump to address in dest.
+     *
+     * @param dest General purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void jmp(Register dest) {
+        super.br(dest);
+    }
+
+    /**
+     * Immediate jump instruction fixed up by HotSpot c++ code.
+     */
+    public void jmp() {
+        // Offset has to be fixed up by c++ code.
+        super.b(0);
+    }
+
+    /**
+     *
+     * @return true if immediate offset can be used in a single branch instruction.
+     */
+    public static boolean isBranchImmediateOffset(long imm) {
+        return NumUtil.isSignedNbit(28, imm);
+    }
+
+    /* system instructions */
+
+    /**
+     * Exception codes used when calling hlt instruction.
+     */
+    public enum AArch64ExceptionCode {
+        NO_SWITCH_TARGET(0x0),
+        BREAKPOINT(0x1);
+
+        public final int encoding;
+
+        AArch64ExceptionCode(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param exceptionCode exception code specifying why halt was called. Non null.
+     */
+    public void hlt(AArch64ExceptionCode exceptionCode) {
+        super.hlt(exceptionCode.encoding);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param exceptionCode exception code specifying why break was called. Non null.
+     */
+    public void brk(AArch64ExceptionCode exceptionCode) {
+        super.brk(exceptionCode.encoding);
+    }
+
+    public void pause() {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Executes no-op instruction. No registers or flags are updated, except for PC.
+     */
+    public void nop() {
+        super.hint(SystemHint.NOP);
+    }
+
+    /**
+     * Same as {@link #nop()}.
+     */
+    @Override
+    public void ensureUniquePC() {
+        nop();
+    }
+
+    /**
+     * Aligns PC.
+     *
+     * @param modulus Has to be positive multiple of 4.
+     */
+    @Override
+    public void align(int modulus) {
+        assert modulus > 0 && (modulus & 0x3) == 0 : "Modulus has to be a positive multiple of 4.";
+        if (position() % modulus == 0) {
+            return;
+        }
+        int offset = modulus - position() % modulus;
+        for (int i = 0; i < offset; i += 4) {
+            nop();
+        }
+    }
+
+    /**
+     * Patches jump targets when label gets bound.
+     */
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+        int instruction = getInt(branch);
+        int branchOffset = jumpTarget - branch;
+        PatchLabelKind type = PatchLabelKind.fromEncoding(instruction);
+        switch (type) {
+            case BRANCH_CONDITIONALLY:
+                ConditionFlag cf = ConditionFlag.fromEncoding(instruction >>> PatchLabelKind.INFORMATION_OFFSET);
+                super.b(cf, branchOffset, branch);
+                break;
+            case BRANCH_UNCONDITIONALLY:
+                super.b(branchOffset, branch);
+                break;
+            case JUMP_ADDRESS:
+                emitInt(jumpTarget, branch);
+                break;
+            case BRANCH_NONZERO:
+            case BRANCH_ZERO: {
+                int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
+                int sizeEncoding = information & 1;
+                int regEncoding = information >>> 1;
+                Register reg = AArch64.cpuRegisters.get(regEncoding);
+                // 1 => 64; 0 => 32
+                int size = sizeEncoding * 32 + 32;
+                switch (type) {
+                    case BRANCH_NONZERO:
+                        super.cbnz(size, reg, branchOffset, branch);
+                        break;
+                    case BRANCH_ZERO:
+                        super.cbz(size, reg, branchOffset, branch);
+                        break;
+                }
+                break;
+            }
+            case ADR: {
+                int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
+                int regEncoding = information;
+                Register reg = AArch64.cpuRegisters.get(regEncoding);
+                super.adr(reg, branchOffset, branch);
+                break;
+            }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Generates an address of the form {@code base + displacement}.
+     *
+     * Does not change base register to fulfill this requirement. Will fail if displacement cannot
+     * be represented directly as address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @return AArch64Address referencing memory at {@code base + displacement}.
+     */
+    @Override
+    public AArch64Address makeAddress(Register base, int displacement) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false);
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder(int instructionStartPosition) {
+        return AArch64Address.PLACEHOLDER;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/BitOpsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/BitOpsTest.java
new file mode 100644
index 0000000..7db75bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/BitOpsTest.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.asm.amd64.test;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static org.junit.Assume.assumeTrue;
+
+import java.lang.reflect.Field;
+import java.util.EnumSet;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler;
+import org.graalvm.compiler.asm.test.AssemblerTest;
+import org.graalvm.compiler.code.CompilationResult;
+
+public class BitOpsTest extends AssemblerTest {
+    private static boolean lzcntSupported;
+    private static boolean tzcntSupported;
+
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
+        EnumSet<CPUFeature> features = ((AMD64) codeCache.getTarget().arch).getFeatures();
+        lzcntSupported = features.contains(CPUFeature.LZCNT);
+        tzcntSupported = features.contains(CPUFeature.BMI1);
+    }
+
+    @Test
+    public void lzcntlTest() {
+        if (lzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    Register arg = asRegister(cc.getArgument(0));
+                    LZCNT.emit(asm, DWORD, ret, arg);
+                    asm.ret(0);
+                    return asm.close(true);
+                }
+            };
+            assertReturn("intStub", test, 31, 1);
+        }
+    }
+
+    @Test
+    public void lzcntlMemTest() {
+        if (lzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    try {
+                        Field f = IntField.class.getDeclaredField("x");
+                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                        LZCNT.emit(asm, DWORD, ret, arg);
+                        asm.ret(0);
+                        return asm.close(true);
+                    } catch (Exception e) {
+                        throw new RuntimeException("exception while trying to generate field access:", e);
+                    }
+                }
+            };
+            assertReturn("intFieldStub", test, 31, new IntField(1));
+        }
+    }
+
+    @Test
+    public void lzcntqTest() {
+        if (lzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    Register arg = asRegister(cc.getArgument(0));
+                    LZCNT.emit(asm, QWORD, ret, arg);
+                    asm.ret(0);
+                    return asm.close(true);
+                }
+            };
+            assertReturn("longStub", test, 63, 1L);
+        }
+    }
+
+    @Test
+    public void lzcntqMemTest() {
+        if (lzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    try {
+                        Field f = LongField.class.getDeclaredField("x");
+                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                        LZCNT.emit(asm, QWORD, ret, arg);
+                        asm.ret(0);
+                        return asm.close(true);
+                    } catch (Exception e) {
+                        throw new RuntimeException("exception while trying to generate field access:", e);
+                    }
+                }
+            };
+            assertReturn("longFieldStub", test, 63, new LongField(1));
+        }
+    }
+
+    @Test
+    public void tzcntlTest() {
+        if (tzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    Register arg = asRegister(cc.getArgument(0));
+                    TZCNT.emit(asm, DWORD, ret, arg);
+                    asm.ret(0);
+                    return asm.close(true);
+                }
+            };
+            assertReturn("intStub", test, 31, 0x8000_0000);
+        }
+    }
+
+    @Test
+    public void tzcntlMemTest() {
+        if (tzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    try {
+                        Field f = IntField.class.getDeclaredField("x");
+                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                        TZCNT.emit(asm, DWORD, ret, arg);
+                        asm.ret(0);
+                        return asm.close(true);
+                    } catch (Exception e) {
+                        throw new RuntimeException("exception while trying to generate field access:", e);
+                    }
+                }
+            };
+            assertReturn("intFieldStub", test, 31, new IntField(0x8000_0000));
+        }
+    }
+
+    @Test
+    public void tzcntqTest() {
+        if (tzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    Register arg = asRegister(cc.getArgument(0));
+                    TZCNT.emit(asm, QWORD, ret, arg);
+                    asm.ret(0);
+                    return asm.close(true);
+                }
+            };
+            assertReturn("longStub", test, 63, 0x8000_0000_0000_0000L);
+        }
+    }
+
+    @Test
+    public void tzcntqMemTest() {
+        if (tzcntSupported) {
+            CodeGenTest test = new CodeGenTest() {
+
+                @Override
+                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                    AMD64Assembler asm = new AMD64Assembler(target);
+                    Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                    try {
+                        Field f = LongField.class.getDeclaredField("x");
+                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                        TZCNT.emit(asm, QWORD, ret, arg);
+                        asm.ret(0);
+                        return asm.close(true);
+                    } catch (Exception e) {
+                        throw new RuntimeException("exception while trying to generate field access:", e);
+                    }
+                }
+            };
+            assertReturn("longFieldStub", test, 63, new LongField(0x8000_0000_0000_0000L));
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int intStub(int arg) {
+        return 0;
+    }
+
+    @SuppressWarnings("unused")
+    public static int longStub(long arg) {
+        return 0;
+    }
+
+    public static class IntField {
+        public int x;
+
+        IntField(int x) {
+            this.x = x;
+        }
+    }
+
+    public static class LongField {
+        public long x;
+
+        LongField(long x) {
+            this.x = x;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int intFieldStub(IntField arg) {
+        return 0;
+    }
+
+    @SuppressWarnings("unused")
+    public static int longFieldStub(LongField arg) {
+        return 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/IncrementDecrementMacroTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/IncrementDecrementMacroTest.java
new file mode 100644
index 0000000..6c8c443
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/IncrementDecrementMacroTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64.test;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static org.junit.Assume.assumeTrue;
+
+import java.lang.reflect.Field;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.asm.test.AssemblerTest;
+import org.graalvm.compiler.code.CompilationResult;
+
+public class IncrementDecrementMacroTest extends AssemblerTest {
+
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
+    }
+
+    public static class LongField {
+        public long x;
+
+        LongField(long x) {
+            this.x = x;
+        }
+    }
+
+    private static class IncrementCodeGenTest implements CodeGenTest {
+        final int value;
+
+        IncrementCodeGenTest(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+            AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
+            Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+            try {
+                Field f = LongField.class.getDeclaredField("x");
+                AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                asm.incrementq(arg, value);
+                asm.movq(ret, arg);
+                asm.ret(0);
+                return asm.close(true);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to generate field access:", e);
+            }
+        }
+    }
+
+    private void assertIncrement(long initValue, int increment) {
+        assertReturn("longFieldStubIncrement", new IncrementCodeGenTest(increment), initValue + increment, new LongField(initValue));
+    }
+
+    private void assertIncrements(int increment) {
+        assertIncrement(0x4242_4242_4242_4242L, increment);
+    }
+
+    @SuppressWarnings("unused")
+    public static long longFieldStubIncrement(LongField arg) {
+        return 0;
+    }
+
+    private static class DecrementCodeGenTest implements CodeGenTest {
+        final int value;
+
+        DecrementCodeGenTest(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+            AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
+            Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+            try {
+                Field f = LongField.class.getDeclaredField("x");
+                AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
+                asm.decrementq(arg, value);
+                asm.movq(ret, arg);
+                asm.ret(0);
+                return asm.close(true);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to generate field access:", e);
+            }
+        }
+    }
+
+    private void assertDecrement(long initValue, int increment) {
+        assertReturn("longFieldStubDecrement", new DecrementCodeGenTest(increment), initValue - increment, new LongField(initValue));
+    }
+
+    private void assertDecrements(int increment) {
+        assertDecrement(0x4242_4242_4242_4242L, increment);
+    }
+
+    @SuppressWarnings("unused")
+    public static long longFieldStubDecrement(LongField arg) {
+        return 0;
+    }
+
+    @Test
+    public void incrementMemTest0() {
+        int increment = 0;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest1() {
+        int increment = 1;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest2() {
+        int increment = 2;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest3() {
+        int increment = Integer.MAX_VALUE;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest4() {
+        int increment = Integer.MIN_VALUE;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest5() {
+        int increment = -1;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest6() {
+        int increment = -2;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void incrementMemTest7() {
+        int increment = -0x1000_0000;
+        assertIncrements(increment);
+    }
+
+    @Test
+    public void decrementMemTest0() {
+        int decrement = 0;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest1() {
+        int decrement = 1;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest2() {
+        int decrement = 2;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest3() {
+        int decrement = Integer.MAX_VALUE;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest4() {
+        int decrement = Integer.MIN_VALUE;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest5() {
+        int decrement = -1;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest6() {
+        int decrement = -2;
+        assertDecrements(decrement);
+    }
+
+    @Test
+    public void decrementMemTest7() {
+        int decrement = -0x1000_0000;
+        assertDecrements(decrement);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java
new file mode 100644
index 0000000..a7af5e7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.asm.test.AssemblerTest;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.code.DataSection.RawData;
+import org.graalvm.compiler.code.DataSection.SerializableData;
+
+public class SimpleAssemblerTest extends AssemblerTest {
+
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
+    }
+
+    @Test
+    public void intTest() {
+        CodeGenTest test = new CodeGenTest() {
+
+            @Override
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                AMD64Assembler asm = new AMD64Assembler(target);
+                Register ret = registerConfig.getReturnRegister(JavaKind.Int);
+                asm.movl(ret, 8472);
+                asm.ret(0);
+                return asm.close(true);
+            }
+        };
+        assertReturn("intStub", test, 8472);
+    }
+
+    @Test
+    public void doubleTest() {
+        CodeGenTest test = new CodeGenTest() {
+
+            @Override
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
+                Register ret = registerConfig.getReturnRegister(JavaKind.Double);
+                Data data = new SerializableData(JavaConstant.forDouble(84.72), 8);
+                DataSectionReference ref = compResult.getDataSection().insertData(data);
+                compResult.recordDataPatch(asm.position(), ref);
+                asm.movdbl(ret, asm.getPlaceholder(-1));
+                asm.ret(0);
+                return asm.close(true);
+            }
+        };
+        assertReturn("doubleStub", test, 84.72);
+    }
+
+    @Test
+    public void rawDoubleTest() {
+        CodeGenTest test = new CodeGenTest() {
+
+            @Override
+            public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
+                AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
+                Register ret = registerConfig.getReturnRegister(JavaKind.Double);
+
+                byte[] rawBytes = new byte[8];
+                ByteBuffer.wrap(rawBytes).order(ByteOrder.nativeOrder()).putDouble(84.72);
+                Data data = new RawData(rawBytes, 8);
+                DataSectionReference ref = compResult.getDataSection().insertData(data);
+                compResult.recordDataPatch(asm.position(), ref);
+                asm.movdbl(ret, asm.getPlaceholder(-1));
+                asm.ret(0);
+                return asm.close(true);
+            }
+        };
+        assertReturn("doubleStub", test, 84.72);
+    }
+
+    public static int intStub() {
+        return 0;
+    }
+
+    public static double doubleStub() {
+        return 0.0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Address.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Address.java
new file mode 100644
index 0000000..1ff59f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Address.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64;
+
+import jdk.vm.ci.code.Register;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base
+ * register, an index register, a displacement and a scale. Note that the base and index registers
+ * may be a variable that will get a register assigned later by the register allocator.
+ */
+public final class AMD64Address extends AbstractAddress {
+
+    private final Register base;
+    private final Register index;
+    private final Scale scale;
+    private final int displacement;
+
+    /**
+     * The start of the instruction, i.e., the value that is used as the key for looking up
+     * placeholder patching information. Only used for {@link AMD64Assembler#getPlaceholder
+     * placeholder addresses}.
+     */
+    final int instructionStartPosition;
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
+     *
+     * @param base the base register
+     */
+    public AMD64Address(Register base) {
+        this(base, Register.None, Scale.Times1, 0);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and a given
+     * displacement.
+     *
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, int displacement) {
+        this(base, Register.None, Scale.Times1, displacement);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base and index registers, scaling and
+     * displacement. This is the most general constructor.
+     *
+     * @param base the base register
+     * @param index the index register
+     * @param scale the scaling factor
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, Register index, Scale scale, int displacement) {
+        this(base, index, scale, displacement, -1);
+    }
+
+    AMD64Address(Register base, Register index, Scale scale, int displacement, int instructionStartPosition) {
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+        this.instructionStartPosition = instructionStartPosition;
+
+        assert scale != null;
+    }
+
+    /**
+     * A scaling factor used in the SIB addressing mode.
+     */
+    public enum Scale {
+        Times1(1, 0),
+        Times2(2, 1),
+        Times4(4, 2),
+        Times8(8, 3);
+
+        Scale(int value, int log2) {
+            this.value = value;
+            this.log2 = log2;
+        }
+
+        /**
+         * The value (or multiplier) of this scale.
+         */
+        public final int value;
+
+        /**
+         * The {@linkplain #value value} of this scale log 2.
+         */
+        public final int log2;
+
+        public static Scale fromInt(int scale) {
+            switch (scale) {
+                case 1:
+                    return Times1;
+                case 2:
+                    return Times2;
+                case 4:
+                    return Times4;
+                case 8:
+                    return Times8;
+                default:
+                    return null;
+            }
+        }
+
+        public static Scale fromShift(int shift) {
+            switch (shift) {
+                case 0:
+                    return Times1;
+                case 1:
+                    return Times2;
+                case 2:
+                    return Times4;
+                case 3:
+                    return Times8;
+                default:
+                    return null;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("[");
+        String sep = "";
+        if (!getBase().equals(Register.None)) {
+            s.append(getBase());
+            sep = " + ";
+        }
+        if (!getIndex().equals(Register.None)) {
+            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
+            sep = " + ";
+        }
+        if (getDisplacement() < 0) {
+            s.append(" - ").append(-getDisplacement());
+        } else if (getDisplacement() > 0) {
+            s.append(sep).append(getDisplacement());
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Register#None}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to
+     *         {@link #getBase}. If not present, is denoted by {@link Register#None}.
+     */
+    public Register getIndex() {
+        return index;
+    }
+
+    /**
+     * @return Scaling factor for indexing, dependent on target operand size.
+     */
+    public Scale getScale() {
+        return scale;
+    }
+
+    /**
+     * @return Optional additive displacement.
+     */
+    public int getDisplacement() {
+        return displacement;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java
new file mode 100644
index 0000000..f704572
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64;
+
+public class AMD64AsmOptions {
+    public static final boolean UseNormalNop = false;
+    public static final boolean UseAddressNop = true;
+    public static final boolean UseIncDec = true;
+    public static final boolean UseXmmLoadAndClearUpper = true;
+    public static final boolean UseXmmRegToRegMoveAll = true;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
new file mode 100644
index 0000000..a69eb78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
@@ -0,0 +1,3750 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64;
+
+import static org.graalvm.compiler.asm.NumUtil.isByte;
+import static org.graalvm.compiler.asm.NumUtil.isInt;
+import static org.graalvm.compiler.asm.NumUtil.isShiftCount;
+import static org.graalvm.compiler.asm.NumUtil.isUByte;
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SBB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.DEC;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.INC;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NEG;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.BYTE;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
+import static jdk.vm.ci.amd64.AMD64.CPU;
+import static jdk.vm.ci.amd64.AMD64.XMM;
+import static jdk.vm.ci.amd64.AMD64.r12;
+import static jdk.vm.ci.amd64.AMD64.r13;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.amd64.AMD64.rip;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * This class implements an assembler that can encode most X86 instructions.
+ */
+public class AMD64Assembler extends Assembler {
+
+    private static final int MinEncodingNeedsRex = 8;
+
+    /**
+     * The x86 condition codes used for conditional jumps/moves.
+     */
+    public enum ConditionFlag {
+        Zero(0x4, "|zero|"),
+        NotZero(0x5, "|nzero|"),
+        Equal(0x4, "="),
+        NotEqual(0x5, "!="),
+        Less(0xc, "<"),
+        LessEqual(0xe, "<="),
+        Greater(0xf, ">"),
+        GreaterEqual(0xd, ">="),
+        Below(0x2, "|<|"),
+        BelowEqual(0x6, "|<=|"),
+        Above(0x7, "|>|"),
+        AboveEqual(0x3, "|>=|"),
+        Overflow(0x0, "|of|"),
+        NoOverflow(0x1, "|nof|"),
+        CarrySet(0x2, "|carry|"),
+        CarryClear(0x3, "|ncarry|"),
+        Negative(0x8, "|neg|"),
+        Positive(0x9, "|pos|"),
+        Parity(0xa, "|par|"),
+        NoParity(0xb, "|npar|");
+
+        private final int value;
+        private final String operator;
+
+        ConditionFlag(int value, String operator) {
+            this.value = value;
+            this.operator = operator;
+        }
+
+        public ConditionFlag negate() {
+            switch (this) {
+                case Zero:
+                    return NotZero;
+                case NotZero:
+                    return Zero;
+                case Equal:
+                    return NotEqual;
+                case NotEqual:
+                    return Equal;
+                case Less:
+                    return GreaterEqual;
+                case LessEqual:
+                    return Greater;
+                case Greater:
+                    return LessEqual;
+                case GreaterEqual:
+                    return Less;
+                case Below:
+                    return AboveEqual;
+                case BelowEqual:
+                    return Above;
+                case Above:
+                    return BelowEqual;
+                case AboveEqual:
+                    return Below;
+                case Overflow:
+                    return NoOverflow;
+                case NoOverflow:
+                    return Overflow;
+                case CarrySet:
+                    return CarryClear;
+                case CarryClear:
+                    return CarrySet;
+                case Negative:
+                    return Positive;
+                case Positive:
+                    return Negative;
+                case Parity:
+                    return NoParity;
+                case NoParity:
+                    return Parity;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            return operator;
+        }
+    }
+
+    /**
+     * Constants for X86 prefix bytes.
+     */
+    private static class Prefix {
+        private static final int REX = 0x40;
+        private static final int REXB = 0x41;
+        private static final int REXX = 0x42;
+        private static final int REXXB = 0x43;
+        private static final int REXR = 0x44;
+        private static final int REXRB = 0x45;
+        private static final int REXRX = 0x46;
+        private static final int REXRXB = 0x47;
+        private static final int REXW = 0x48;
+        private static final int REXWB = 0x49;
+        private static final int REXWX = 0x4A;
+        private static final int REXWXB = 0x4B;
+        private static final int REXWR = 0x4C;
+        private static final int REXWRB = 0x4D;
+        private static final int REXWRX = 0x4E;
+        private static final int REXWRXB = 0x4F;
+        private static final int VEX_3BYTES = 0xC4;
+        private static final int VEX_2BYTES = 0xC5;
+    }
+
+    private static class VexPrefix {
+        private static final int VEX_R = 0x80;
+        private static final int VEX_W = 0x80;
+    }
+
+    private static class AvxVectorLen {
+        private static final int AVX_128bit = 0x0;
+        private static final int AVX_256bit = 0x1;
+    }
+
+    private static class VexSimdPrefix {
+        private static final int VEX_SIMD_NONE = 0x0;
+        private static final int VEX_SIMD_66 = 0x1;
+        private static final int VEX_SIMD_F3 = 0x2;
+        private static final int VEX_SIMD_F2 = 0x3;
+    }
+
+    private static class VexOpcode {
+        private static final int VEX_OPCODE_NONE = 0x0;
+        private static final int VEX_OPCODE_0F = 0x1;
+        private static final int VEX_OPCODE_0F_38 = 0x2;
+        private static final int VEX_OPCODE_0F_3A = 0x3;
+    }
+
+    private AMD64InstructionAttr curAttributes;
+
+    AMD64InstructionAttr getCurAttributes() {
+        return curAttributes;
+    }
+
+    void setCurAttributes(AMD64InstructionAttr attributes) {
+        curAttributes = attributes;
+    }
+
+    /**
+     * The x86 operand sizes.
+     */
+    public enum OperandSize {
+        BYTE(1) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                assert imm == (byte) imm;
+                asm.emitByte(imm);
+            }
+
+            @Override
+            protected int immediateSize() {
+                return 1;
+            }
+        },
+
+        WORD(2, 0x66) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                assert imm == (short) imm;
+                asm.emitShort(imm);
+            }
+
+            @Override
+            protected int immediateSize() {
+                return 2;
+            }
+        },
+
+        DWORD(4) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                asm.emitInt(imm);
+            }
+
+            @Override
+            protected int immediateSize() {
+                return 4;
+            }
+        },
+
+        QWORD(8) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                asm.emitInt(imm);
+            }
+
+            @Override
+            protected int immediateSize() {
+                return 4;
+            }
+        },
+
+        SS(4, 0xF3, true),
+
+        SD(8, 0xF2, true),
+
+        PS(16, true),
+
+        PD(16, 0x66, true);
+
+        private final int sizePrefix;
+
+        private final int bytes;
+        private final boolean xmm;
+
+        OperandSize(int bytes) {
+            this(bytes, 0);
+        }
+
+        OperandSize(int bytes, int sizePrefix) {
+            this(bytes, sizePrefix, false);
+        }
+
+        OperandSize(int bytes, boolean xmm) {
+            this(bytes, 0, xmm);
+        }
+
+        OperandSize(int bytes, int sizePrefix, boolean xmm) {
+            this.sizePrefix = sizePrefix;
+            this.bytes = bytes;
+            this.xmm = xmm;
+        }
+
+        public int getBytes() {
+            return bytes;
+        }
+
+        public boolean isXmmType() {
+            return xmm;
+        }
+
+        /**
+         * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
+         * as sign-extended 32-bit values.
+         *
+         * @param asm
+         * @param imm
+         */
+        protected void emitImmediate(AMD64Assembler asm, int imm) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected int immediateSize() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Operand size and register type constraints.
+     */
+    private enum OpAssertion {
+        ByteAssertion(CPU, CPU, BYTE),
+        IntegerAssertion(CPU, CPU, WORD, DWORD, QWORD),
+        No16BitAssertion(CPU, CPU, DWORD, QWORD),
+        No32BitAssertion(CPU, CPU, WORD, QWORD),
+        QwordOnlyAssertion(CPU, CPU, QWORD),
+        FloatingAssertion(XMM, XMM, SS, SD, PS, PD),
+        PackedFloatingAssertion(XMM, XMM, PS, PD),
+        SingleAssertion(XMM, XMM, SS),
+        DoubleAssertion(XMM, XMM, SD),
+        PackedDoubleAssertion(XMM, XMM, PD),
+        IntToFloatingAssertion(XMM, CPU, DWORD, QWORD),
+        FloatingToIntAssertion(CPU, XMM, DWORD, QWORD);
+
+        private final RegisterCategory resultCategory;
+        private final RegisterCategory inputCategory;
+        private final OperandSize[] allowedSizes;
+
+        OpAssertion(RegisterCategory resultCategory, RegisterCategory inputCategory, OperandSize... allowedSizes) {
+            this.resultCategory = resultCategory;
+            this.inputCategory = inputCategory;
+            this.allowedSizes = allowedSizes;
+        }
+
+        protected boolean checkOperands(AMD64Op op, OperandSize size, Register resultReg, Register inputReg) {
+            assert resultReg == null || resultCategory.equals(resultReg.getRegisterCategory()) : "invalid result register " + resultReg + " used in " + op;
+            assert inputReg == null || inputCategory.equals(inputReg.getRegisterCategory()) : "invalid input register " + inputReg + " used in " + op;
+
+            for (OperandSize s : allowedSizes) {
+                if (size == s) {
+                    return true;
+                }
+            }
+
+            assert false : "invalid operand size " + size + " used in " + op;
+            return false;
+        }
+    }
+
+    public abstract static class OperandDataAnnotation extends CodeAnnotation {
+        /**
+         * The position (bytes from the beginning of the method) of the operand.
+         */
+        public final int operandPosition;
+        /**
+         * The size of the operand, in bytes.
+         */
+        public final int operandSize;
+        /**
+         * The position (bytes from the beginning of the method) of the next instruction. On AMD64,
+         * RIP-relative operands are relative to this position.
+         */
+        public final int nextInstructionPosition;
+
+        OperandDataAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
+            super(instructionPosition);
+
+            this.operandPosition = operandPosition;
+            this.operandSize = operandSize;
+            this.nextInstructionPosition = nextInstructionPosition;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + " instruction [" + instructionPosition + ", " + nextInstructionPosition + "[ operand at " + operandPosition + " size " + operandSize;
+        }
+    }
+
+    /**
+     * Annotation that stores additional information about the displacement of a
+     * {@link Assembler#getPlaceholder placeholder address} that needs patching.
+     */
+    public static class AddressDisplacementAnnotation extends OperandDataAnnotation {
+        AddressDisplacementAnnotation(int instructionPosition, int operandPosition, int operndSize, int nextInstructionPosition) {
+            super(instructionPosition, operandPosition, operndSize, nextInstructionPosition);
+        }
+    }
+
+    /**
+     * Annotation that stores additional information about the immediate operand, e.g., of a call
+     * instruction, that needs patching.
+     */
+    public static class ImmediateOperandAnnotation extends OperandDataAnnotation {
+        ImmediateOperandAnnotation(int instructionPosition, int operandPosition, int operndSize, int nextInstructionPosition) {
+            super(instructionPosition, operandPosition, operndSize, nextInstructionPosition);
+        }
+    }
+
+    /**
+     * Constructs an assembler for the AMD64 architecture.
+     */
+    public AMD64Assembler(TargetDescription target) {
+        super(target);
+    }
+
+    public boolean supports(CPUFeature feature) {
+        return ((AMD64) target.arch).getFeatures().contains(feature);
+    }
+
+    private static int encode(Register r) {
+        assert r.encoding < 16 && r.encoding >= 0 : "encoding out of range: " + r.encoding;
+        return r.encoding & 0x7;
+    }
+
+    /**
+     * Get RXB bits for register-register instruction. In that encoding, ModRM.rm contains a
+     * register index. The R bit extends the ModRM.reg field and the B bit extends the ModRM.rm
+     * field. The X bit must be 0.
+     */
+    protected static int getRXB(Register reg, Register rm) {
+        int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
+        rxb |= (rm == null ? 0 : rm.encoding & 0x08) >> 3;
+        return rxb;
+    }
+
+    /**
+     * Get RXB bits for register-memory instruction. The R bit extends the ModRM.reg field. There
+     * are two cases for the memory operand:<br>
+     * ModRM.rm contains the base register: In that case, B extends the ModRM.rm field and X = 0.
+     * <br>
+     * There is an SIB byte: In that case, X extends SIB.index and B extends SIB.base.
+     */
+    protected static int getRXB(Register reg, AMD64Address rm) {
+        int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
+        if (!rm.getIndex().equals(Register.None)) {
+            rxb |= (rm.getIndex().encoding & 0x08) >> 2;
+        }
+        if (!rm.getBase().equals(Register.None)) {
+            rxb |= (rm.getBase().encoding & 0x08) >> 3;
+        }
+        return rxb;
+    }
+
+    /**
+     * Emit the ModR/M byte for one register operand and an opcode extension in the R field.
+     * <p>
+     * Format: [ 11 reg r/m ]
+     */
+    protected void emitModRM(int reg, Register rm) {
+        assert (reg & 0x07) == reg;
+        emitByte(0xC0 | (reg << 3) | (rm.encoding & 0x07));
+    }
+
+    /**
+     * Emit the ModR/M byte for two register operands.
+     * <p>
+     * Format: [ 11 reg r/m ]
+     */
+    protected void emitModRM(Register reg, Register rm) {
+        emitModRM(reg.encoding & 0x07, rm);
+    }
+
+    protected void emitOperandHelper(Register reg, AMD64Address addr, int additionalInstructionSize) {
+        assert !reg.equals(Register.None);
+        emitOperandHelper(encode(reg), addr, false, additionalInstructionSize);
+    }
+
+    /**
+     * Emits the ModR/M byte and optionally the SIB byte for one register and one memory operand.
+     *
+     * @param force4Byte use 4 byte encoding for displacements that would normally fit in a byte
+     */
+    protected void emitOperandHelper(Register reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize) {
+        assert !reg.equals(Register.None);
+        emitOperandHelper(encode(reg), addr, force4Byte, additionalInstructionSize);
+    }
+
+    protected void emitOperandHelper(int reg, AMD64Address addr, int additionalInstructionSize) {
+        emitOperandHelper(reg, addr, false, additionalInstructionSize);
+    }
+
+    /**
+     * Emits the ModR/M byte and optionally the SIB byte for one memory operand and an opcode
+     * extension in the R field.
+     *
+     * @param force4Byte use 4 byte encoding for displacements that would normally fit in a byte
+     * @param additionalInstructionSize the number of bytes that will be emitted after the operand,
+     *            so that the start position of the next instruction can be computed even though
+     *            this instruction has not been completely emitted yet.
+     */
+    protected void emitOperandHelper(int reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize) {
+        assert (reg & 0x07) == reg;
+        int regenc = reg << 3;
+
+        Register base = addr.getBase();
+        Register index = addr.getIndex();
+
+        AMD64Address.Scale scale = addr.getScale();
+        int disp = addr.getDisplacement();
+
+        if (base.equals(AMD64.rip)) { // also matches addresses returned by getPlaceholder()
+            // [00 000 101] disp32
+            assert index.equals(Register.None) : "cannot use RIP relative addressing with index register";
+            emitByte(0x05 | regenc);
+            if (codePatchingAnnotationConsumer != null && addr.instructionStartPosition >= 0) {
+                codePatchingAnnotationConsumer.accept(new AddressDisplacementAnnotation(addr.instructionStartPosition, position(), 4, position() + 4 + additionalInstructionSize));
+            }
+            emitInt(disp);
+        } else if (base.isValid()) {
+            int baseenc = base.isValid() ? encode(base) : 0;
+            if (index.isValid()) {
+                int indexenc = encode(index) << 3;
+                // [base + indexscale + disp]
+                if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
+                    // [base + indexscale]
+                    // [00 reg 100][ss index base]
+                    assert !index.equals(rsp) : "illegal addressing mode";
+                    emitByte(0x04 | regenc);
+                    emitByte(scale.log2 << 6 | indexenc | baseenc);
+                } else if (isByte(disp) && !force4Byte) {
+                    // [base + indexscale + imm8]
+                    // [01 reg 100][ss index base] imm8
+                    assert !index.equals(rsp) : "illegal addressing mode";
+                    emitByte(0x44 | regenc);
+                    emitByte(scale.log2 << 6 | indexenc | baseenc);
+                    emitByte(disp & 0xFF);
+                } else {
+                    // [base + indexscale + disp32]
+                    // [10 reg 100][ss index base] disp32
+                    assert !index.equals(rsp) : "illegal addressing mode";
+                    emitByte(0x84 | regenc);
+                    emitByte(scale.log2 << 6 | indexenc | baseenc);
+                    emitInt(disp);
+                }
+            } else if (base.equals(rsp) || base.equals(r12)) {
+                // [rsp + disp]
+                if (disp == 0) {
+                    // [rsp]
+                    // [00 reg 100][00 100 100]
+                    emitByte(0x04 | regenc);
+                    emitByte(0x24);
+                } else if (isByte(disp) && !force4Byte) {
+                    // [rsp + imm8]
+                    // [01 reg 100][00 100 100] disp8
+                    emitByte(0x44 | regenc);
+                    emitByte(0x24);
+                    emitByte(disp & 0xFF);
+                } else {
+                    // [rsp + imm32]
+                    // [10 reg 100][00 100 100] disp32
+                    emitByte(0x84 | regenc);
+                    emitByte(0x24);
+                    emitInt(disp);
+                }
+            } else {
+                // [base + disp]
+                assert !base.equals(rsp) && !base.equals(r12) : "illegal addressing mode";
+                if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
+                    // [base]
+                    // [00 reg base]
+                    emitByte(0x00 | regenc | baseenc);
+                } else if (isByte(disp) && !force4Byte) {
+                    // [base + disp8]
+                    // [01 reg base] disp8
+                    emitByte(0x40 | regenc | baseenc);
+                    emitByte(disp & 0xFF);
+                } else {
+                    // [base + disp32]
+                    // [10 reg base] disp32
+                    emitByte(0x80 | regenc | baseenc);
+                    emitInt(disp);
+                }
+            }
+        } else {
+            if (index.isValid()) {
+                int indexenc = encode(index) << 3;
+                // [indexscale + disp]
+                // [00 reg 100][ss index 101] disp32
+                assert !index.equals(rsp) : "illegal addressing mode";
+                emitByte(0x04 | regenc);
+                emitByte(scale.log2 << 6 | indexenc | 0x05);
+                emitInt(disp);
+            } else {
+                // [disp] ABSOLUTE
+                // [00 reg 100][00 100 101] disp32
+                emitByte(0x04 | regenc);
+                emitByte(0x25);
+                emitInt(disp);
+            }
+        }
+        setCurAttributes(null);
+    }
+
+    /**
+     * Base class for AMD64 opcodes.
+     */
+    public static class AMD64Op {
+
+        protected static final int P_0F = 0x0F;
+        protected static final int P_0F38 = 0x380F;
+        protected static final int P_0F3A = 0x3A0F;
+
+        private final String opcode;
+
+        protected final int prefix1;
+        protected final int prefix2;
+        protected final int op;
+
+        private final boolean dstIsByte;
+        private final boolean srcIsByte;
+
+        private final OpAssertion assertion;
+        private final CPUFeature feature;
+
+        protected AMD64Op(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, prefix1, prefix2, op, assertion == OpAssertion.ByteAssertion, assertion == OpAssertion.ByteAssertion, assertion, feature);
+        }
+
+        protected AMD64Op(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) {
+            this.opcode = opcode;
+            this.prefix1 = prefix1;
+            this.prefix2 = prefix2;
+            this.op = op;
+
+            this.dstIsByte = dstIsByte;
+            this.srcIsByte = srcIsByte;
+
+            this.assertion = assertion;
+            this.feature = feature;
+        }
+
+        protected final void emitOpcode(AMD64Assembler asm, OperandSize size, int rxb, int dstEnc, int srcEnc) {
+            if (prefix1 != 0) {
+                asm.emitByte(prefix1);
+            }
+            if (size.sizePrefix != 0) {
+                asm.emitByte(size.sizePrefix);
+            }
+            int rexPrefix = 0x40 | rxb;
+            if (size == QWORD) {
+                rexPrefix |= 0x08;
+            }
+            if (rexPrefix != 0x40 || (dstIsByte && dstEnc >= 4) || (srcIsByte && srcEnc >= 4)) {
+                asm.emitByte(rexPrefix);
+            }
+            if (prefix2 > 0xFF) {
+                asm.emitShort(prefix2);
+            } else if (prefix2 > 0) {
+                asm.emitByte(prefix2);
+            }
+            asm.emitByte(op);
+        }
+
+        protected final boolean verify(AMD64Assembler asm, OperandSize size, Register resultReg, Register inputReg) {
+            assert feature == null || asm.supports(feature) : String.format("unsupported feature %s required for %s", feature, opcode);
+            assert assertion.checkOperands(this, size, resultReg, inputReg);
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return opcode;
+        }
+    }
+
+    /**
+     * Base class for AMD64 opcodes with immediate operands.
+     */
+    public static class AMD64ImmOp extends AMD64Op {
+
+        private final boolean immIsByte;
+
+        protected AMD64ImmOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, assertion, null);
+            this.immIsByte = immIsByte;
+        }
+
+        protected final void emitImmediate(AMD64Assembler asm, OperandSize size, int imm) {
+            if (immIsByte) {
+                assert imm == (byte) imm;
+                asm.emitByte(imm);
+            } else {
+                size.emitImmediate(asm, imm);
+            }
+        }
+
+        protected final int immediateSize(OperandSize size) {
+            if (immIsByte) {
+                return 1;
+            } else {
+                return size.bytes;
+            }
+        }
+    }
+
+    /**
+     * Opcode with operand order of either RM or MR for 2 address forms.
+     */
+    public abstract static class AMD64RROp extends AMD64Op {
+
+        protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature);
+        }
+
+        public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src);
+    }
+
+    /**
+     * Opcode with operand order of either RM or MR for 3 address forms.
+     */
+    public abstract static class AMD64RRROp extends AMD64Op {
+
+        protected AMD64RRROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        protected AMD64RRROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature);
+        }
+
+        public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, Register src);
+    }
+
+    /**
+     * Opcode with operand order of RM.
+     */
+    public static class AMD64RMOp extends AMD64RROp {
+        // @formatter:off
+        public static final AMD64RMOp IMUL   = new AMD64RMOp("IMUL",         P_0F, 0xAF);
+        public static final AMD64RMOp BSF    = new AMD64RMOp("BSF",          P_0F, 0xBC);
+        public static final AMD64RMOp BSR    = new AMD64RMOp("BSR",          P_0F, 0xBD);
+        public static final AMD64RMOp POPCNT = new AMD64RMOp("POPCNT", 0xF3, P_0F, 0xB8, CPUFeature.POPCNT);
+        public static final AMD64RMOp TZCNT  = new AMD64RMOp("TZCNT",  0xF3, P_0F, 0xBC, CPUFeature.BMI1);
+        public static final AMD64RMOp LZCNT  = new AMD64RMOp("LZCNT",  0xF3, P_0F, 0xBD, CPUFeature.LZCNT);
+        public static final AMD64RMOp MOVZXB = new AMD64RMOp("MOVZXB",       P_0F, 0xB6, false, true, OpAssertion.IntegerAssertion);
+        public static final AMD64RMOp MOVZX  = new AMD64RMOp("MOVZX",        P_0F, 0xB7, OpAssertion.No16BitAssertion);
+        public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB",       P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion);
+        public static final AMD64RMOp MOVSX  = new AMD64RMOp("MOVSX",        P_0F, 0xBF, OpAssertion.No16BitAssertion);
+        public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD",             0x63, OpAssertion.QwordOnlyAssertion);
+        public static final AMD64RMOp MOVB   = new AMD64RMOp("MOVB",               0x8A, OpAssertion.ByteAssertion);
+        public static final AMD64RMOp MOV    = new AMD64RMOp("MOV",                0x8B);
+
+        // MOVD/MOVQ and MOVSS/MOVSD are the same opcode, just with different operand size prefix
+        public static final AMD64RMOp MOVD   = new AMD64RMOp("MOVD",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64RMOp MOVQ   = new AMD64RMOp("MOVQ",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64RMOp MOVSS  = new AMD64RMOp("MOVSS",        P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+        public static final AMD64RMOp MOVSD  = new AMD64RMOp("MOVSD",        P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+
+        // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient.
+        public static final AMD64RMOp TESTB  = new AMD64RMOp("TEST",               0x84, OpAssertion.ByteAssertion);
+        public static final AMD64RMOp TEST   = new AMD64RMOp("TEST",               0x85);
+        // @formatter:on
+
+        protected AMD64RMOp(String opcode, int op) {
+            this(opcode, 0, op);
+        }
+
+        protected AMD64RMOp(String opcode, int op, OpAssertion assertion) {
+            this(opcode, 0, op, assertion);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op) {
+            this(opcode, 0, prefix, op, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, 0, prefix, op, assertion, feature);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) {
+            this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        @Override
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) {
+            assert verify(asm, size, dst, src);
+            boolean isSimd = false;
+            boolean noNds = false;
+
+            switch (op) {
+                case 0x2A:
+                case 0x2C:
+                case 0x2E:
+                case 0x5A:
+                case 0x6E:
+                    isSimd = true;
+                    noNds = true;
+                    break;
+                case 0x10:
+                case 0x51:
+                case 0x54:
+                case 0x55:
+                case 0x56:
+                case 0x57:
+                case 0x58:
+                case 0x59:
+                case 0x5C:
+                case 0x5D:
+                case 0x5E:
+                case 0x5F:
+                    isSimd = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                boolean rexVexW = (size == QWORD) ? true : false;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+                int encode;
+                if (noNds) {
+                    encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes);
+                } else {
+                    encode = asm.simdPrefixAndEncode(dst, dst, src, pre, opc, attributes);
+                }
+                asm.emitByte(op);
+                asm.emitByte(0xC0 | encode);
+            } else {
+                emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding);
+                asm.emitModRM(dst, src);
+            }
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src) {
+            assert verify(asm, size, dst, null);
+            boolean isSimd = false;
+            boolean noNds = false;
+
+            switch (op) {
+                case 0x10:
+                case 0x2A:
+                case 0x2C:
+                case 0x2E:
+                case 0x6E:
+                    isSimd = true;
+                    noNds = true;
+                    break;
+                case 0x51:
+                case 0x54:
+                case 0x55:
+                case 0x56:
+                case 0x57:
+                case 0x58:
+                case 0x59:
+                case 0x5C:
+                case 0x5D:
+                case 0x5E:
+                case 0x5F:
+                    isSimd = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                boolean rexVexW = (size == QWORD) ? true : false;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+                if (noNds) {
+                    asm.simdPrefix(dst, Register.None, src, pre, opc, attributes);
+                } else {
+                    asm.simdPrefix(dst, dst, src, pre, opc, attributes);
+                }
+                asm.emitByte(op);
+                asm.emitOperandHelper(dst, src, 0);
+            } else {
+                emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0);
+                asm.emitOperandHelper(dst, src, 0);
+            }
+        }
+    }
+
+    /**
+     * Opcode with operand order of RM.
+     */
+    public static class AMD64RRMOp extends AMD64RRROp {
+        protected AMD64RRMOp(String opcode, int op) {
+            this(opcode, 0, op);
+        }
+
+        protected AMD64RRMOp(String opcode, int op, OpAssertion assertion) {
+            this(opcode, 0, op, assertion);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix, int op) {
+            this(opcode, 0, prefix, op, null);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion, null);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, 0, prefix, op, assertion, feature);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) {
+            this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature);
+        }
+
+        protected AMD64RRMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        @Override
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, Register src) {
+            assert verify(asm, size, dst, src);
+            int pre;
+            int opc;
+            boolean rexVexW = (size == QWORD) ? true : false;
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+            int curPrefix = size.sizePrefix | prefix1;
+            switch (curPrefix) {
+                case 0x66:
+                    pre = VexSimdPrefix.VEX_SIMD_66;
+                    break;
+                case 0xF2:
+                    pre = VexSimdPrefix.VEX_SIMD_F2;
+                    break;
+                case 0xF3:
+                    pre = VexSimdPrefix.VEX_SIMD_F3;
+                    break;
+                default:
+                    pre = VexSimdPrefix.VEX_SIMD_NONE;
+                    break;
+            }
+            switch (prefix2) {
+                case P_0F:
+                    opc = VexOpcode.VEX_OPCODE_0F;
+                    break;
+                case P_0F38:
+                    opc = VexOpcode.VEX_OPCODE_0F_38;
+                    break;
+                case P_0F3A:
+                    opc = VexOpcode.VEX_OPCODE_0F_3A;
+                    break;
+                default:
+                    opc = VexOpcode.VEX_OPCODE_NONE;
+                    break;
+            }
+            int encode;
+            encode = asm.simdPrefixAndEncode(dst, nds, src, pre, opc, attributes);
+            asm.emitByte(op);
+            asm.emitByte(0xC0 | encode);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register nds, AMD64Address src) {
+            assert verify(asm, size, dst, null);
+            int pre;
+            int opc;
+            boolean rexVexW = (size == QWORD) ? true : false;
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+            int curPrefix = size.sizePrefix | prefix1;
+            switch (curPrefix) {
+                case 0x66:
+                    pre = VexSimdPrefix.VEX_SIMD_66;
+                    break;
+                case 0xF2:
+                    pre = VexSimdPrefix.VEX_SIMD_F2;
+                    break;
+                case 0xF3:
+                    pre = VexSimdPrefix.VEX_SIMD_F3;
+                    break;
+                default:
+                    pre = VexSimdPrefix.VEX_SIMD_NONE;
+                    break;
+            }
+            switch (prefix2) {
+                case P_0F:
+                    opc = VexOpcode.VEX_OPCODE_0F;
+                    break;
+                case P_0F38:
+                    opc = VexOpcode.VEX_OPCODE_0F_38;
+                    break;
+                case P_0F3A:
+                    opc = VexOpcode.VEX_OPCODE_0F_3A;
+                    break;
+                default:
+                    opc = VexOpcode.VEX_OPCODE_NONE;
+                    break;
+            }
+            asm.simdPrefix(dst, nds, src, pre, opc, attributes);
+            asm.emitByte(op);
+            asm.emitOperandHelper(dst, src, 0);
+        }
+    }
+
+    /**
+     * Opcode with operand order of MR.
+     */
+    public static class AMD64MROp extends AMD64RROp {
+        // @formatter:off
+        public static final AMD64MROp MOVB   = new AMD64MROp("MOVB",               0x88, OpAssertion.ByteAssertion);
+        public static final AMD64MROp MOV    = new AMD64MROp("MOV",                0x89);
+
+        // MOVD and MOVQ are the same opcode, just with different operand size prefix
+        // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used.
+        public static final AMD64MROp MOVD   = new AMD64MROp("MOVD",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64MROp MOVQ   = new AMD64MROp("MOVQ",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+
+        // MOVSS and MOVSD are the same opcode, just with different operand size prefix
+        public static final AMD64MROp MOVSS  = new AMD64MROp("MOVSS",        P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+        public static final AMD64MROp MOVSD  = new AMD64MROp("MOVSD",        P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+        // @formatter:on
+
+        protected AMD64MROp(String opcode, int op) {
+            this(opcode, 0, op);
+        }
+
+        protected AMD64MROp(String opcode, int op, OpAssertion assertion) {
+            this(opcode, 0, op, assertion);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op) {
+            this(opcode, prefix, op, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, prefix, op, assertion, null);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, 0, prefix, op, assertion, feature);
+        }
+
+        protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        @Override
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) {
+            assert verify(asm, size, src, dst);
+            boolean isSimd = false;
+            boolean noNds = false;
+
+            switch (op) {
+                case 0x7E:
+                    isSimd = true;
+                    noNds = true;
+                    break;
+                case 0x11:
+                    isSimd = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                boolean rexVexW = (size == QWORD) ? true : false;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+                int encode;
+                if (noNds) {
+                    encode = asm.simdPrefixAndEncode(src, Register.None, dst, pre, opc, attributes);
+                } else {
+                    encode = asm.simdPrefixAndEncode(src, src, dst, pre, opc, attributes);
+                }
+                asm.emitByte(op);
+                asm.emitByte(0xC0 | encode);
+            } else {
+                emitOpcode(asm, size, getRXB(src, dst), src.encoding, dst.encoding);
+                asm.emitModRM(src, dst);
+            }
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, Register src) {
+            assert verify(asm, size, null, src);
+            boolean isSimd = false;
+
+            switch (op) {
+                case 0x7E:
+                case 0x11:
+                    isSimd = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                boolean rexVexW = (size == QWORD) ? true : false;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+                asm.simdPrefix(src, Register.None, dst, pre, opc, attributes);
+                asm.emitByte(op);
+                asm.emitOperandHelper(src, dst, 0);
+            } else {
+                emitOpcode(asm, size, getRXB(src, dst), src.encoding, 0);
+                asm.emitOperandHelper(src, dst, 0);
+            }
+        }
+    }
+
+    /**
+     * Opcodes with operand order of M.
+     */
+    public static class AMD64MOp extends AMD64Op {
+        // @formatter:off
+        public static final AMD64MOp NOT  = new AMD64MOp("NOT",  0xF7, 2);
+        public static final AMD64MOp NEG  = new AMD64MOp("NEG",  0xF7, 3);
+        public static final AMD64MOp MUL  = new AMD64MOp("MUL",  0xF7, 4);
+        public static final AMD64MOp IMUL = new AMD64MOp("IMUL", 0xF7, 5);
+        public static final AMD64MOp DIV  = new AMD64MOp("DIV",  0xF7, 6);
+        public static final AMD64MOp IDIV = new AMD64MOp("IDIV", 0xF7, 7);
+        public static final AMD64MOp INC  = new AMD64MOp("INC",  0xFF, 0);
+        public static final AMD64MOp DEC  = new AMD64MOp("DEC",  0xFF, 1);
+        public static final AMD64MOp PUSH = new AMD64MOp("PUSH", 0xFF, 6);
+        public static final AMD64MOp POP  = new AMD64MOp("POP",  0x8F, 0, OpAssertion.No32BitAssertion);
+        // @formatter:on
+
+        private final int ext;
+
+        protected AMD64MOp(String opcode, int op, int ext) {
+            this(opcode, 0, op, ext);
+        }
+
+        protected AMD64MOp(String opcode, int prefix, int op, int ext) {
+            this(opcode, prefix, op, ext, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MOp(String opcode, int op, int ext, OpAssertion assertion) {
+            this(opcode, 0, op, ext, assertion);
+        }
+
+        protected AMD64MOp(String opcode, int prefix, int op, int ext, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, assertion, null);
+            this.ext = ext;
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding);
+            asm.emitModRM(ext, dst);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst) {
+            assert verify(asm, size, null, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, 0);
+            asm.emitOperandHelper(ext, dst, 0);
+        }
+    }
+
+    /**
+     * Opcodes with operand order of MI.
+     */
+    public static class AMD64MIOp extends AMD64ImmOp {
+        // @formatter:off
+        public static final AMD64MIOp MOVB = new AMD64MIOp("MOVB", true,  0xC6, 0, OpAssertion.ByteAssertion);
+        public static final AMD64MIOp MOV  = new AMD64MIOp("MOV",  false, 0xC7, 0);
+        public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0);
+        // @formatter:on
+
+        private final int ext;
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) {
+            this(opcode, immIsByte, op, ext, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext, OpAssertion assertion) {
+            this(opcode, immIsByte, 0, op, ext, assertion);
+        }
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) {
+            super(opcode, immIsByte, prefix, op, assertion);
+            this.ext = ext;
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, int imm) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding);
+            asm.emitModRM(ext, dst);
+            emitImmediate(asm, size, imm);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, int imm) {
+            assert verify(asm, size, null, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, 0);
+            asm.emitOperandHelper(ext, dst, immediateSize(size));
+            emitImmediate(asm, size, imm);
+        }
+    }
+
+    /**
+     * Opcodes with operand order of RMI.
+     *
+     * We only have one form of round as the operation is always treated with single variant input,
+     * making its extension to 3 address forms redundant.
+     */
+    public static class AMD64RMIOp extends AMD64ImmOp {
+        // @formatter:off
+        public static final AMD64RMIOp IMUL    = new AMD64RMIOp("IMUL", false, 0x69);
+        public static final AMD64RMIOp IMUL_SX = new AMD64RMIOp("IMUL", true,  0x6B);
+        public static final AMD64RMIOp ROUNDSS = new AMD64RMIOp("ROUNDSS", true, P_0F3A, 0x0A, OpAssertion.PackedDoubleAssertion);
+        public static final AMD64RMIOp ROUNDSD = new AMD64RMIOp("ROUNDSD", true, P_0F3A, 0x0B, OpAssertion.PackedDoubleAssertion);
+        // @formatter:on
+
+        protected AMD64RMIOp(String opcode, boolean immIsByte, int op) {
+            this(opcode, immIsByte, 0, op, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64RMIOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) {
+            super(opcode, immIsByte, prefix, op, assertion);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src, int imm) {
+            assert verify(asm, size, dst, src);
+            boolean isSimd = false;
+            boolean noNds = false;
+
+            switch (op) {
+                case 0x0A:
+                case 0x0B:
+                    isSimd = true;
+                    noNds = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+                int encode;
+                if (noNds) {
+                    encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes);
+                } else {
+                    encode = asm.simdPrefixAndEncode(dst, dst, src, pre, opc, attributes);
+                }
+                asm.emitByte(op);
+                asm.emitByte(0xC0 | encode);
+                emitImmediate(asm, size, imm);
+            } else {
+                emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding);
+                asm.emitModRM(dst, src);
+                emitImmediate(asm, size, imm);
+            }
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src, int imm) {
+            assert verify(asm, size, dst, null);
+
+            boolean isSimd = false;
+            boolean noNds = false;
+
+            switch (op) {
+                case 0x0A:
+                case 0x0B:
+                    isSimd = true;
+                    noNds = true;
+                    break;
+            }
+
+            if (isSimd) {
+                int pre;
+                int opc;
+                AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
+                int curPrefix = size.sizePrefix | prefix1;
+                switch (curPrefix) {
+                    case 0x66:
+                        pre = VexSimdPrefix.VEX_SIMD_66;
+                        break;
+                    case 0xF2:
+                        pre = VexSimdPrefix.VEX_SIMD_F2;
+                        break;
+                    case 0xF3:
+                        pre = VexSimdPrefix.VEX_SIMD_F3;
+                        break;
+                    default:
+                        pre = VexSimdPrefix.VEX_SIMD_NONE;
+                        break;
+                }
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
+                        break;
+                }
+
+                if (noNds) {
+                    asm.simdPrefix(dst, Register.None, src, pre, opc, attributes);
+                } else {
+                    asm.simdPrefix(dst, dst, src, pre, opc, attributes);
+                }
+                asm.emitByte(op);
+                asm.emitOperandHelper(dst, src, immediateSize(size));
+                emitImmediate(asm, size, imm);
+            } else {
+                emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0);
+                asm.emitOperandHelper(dst, src, immediateSize(size));
+                emitImmediate(asm, size, imm);
+            }
+        }
+    }
+
+    public static class SSEOp extends AMD64RMOp {
+        // @formatter:off
+        public static final SSEOp CVTSI2SS  = new SSEOp("CVTSI2SS",  0xF3, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion);
+        public static final SSEOp CVTSI2SD  = new SSEOp("CVTSI2SS",  0xF2, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion);
+        public static final SSEOp CVTTSS2SI = new SSEOp("CVTTSS2SI", 0xF3, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion);
+        public static final SSEOp CVTTSD2SI = new SSEOp("CVTTSD2SI", 0xF2, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion);
+        public static final SSEOp UCOMIS    = new SSEOp("UCOMIS",          P_0F, 0x2E, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp SQRT      = new SSEOp("SQRT",            P_0F, 0x51);
+        public static final SSEOp AND       = new SSEOp("AND",             P_0F, 0x54, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp ANDN      = new SSEOp("ANDN",            P_0F, 0x55, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp OR        = new SSEOp("OR",              P_0F, 0x56, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp XOR       = new SSEOp("XOR",             P_0F, 0x57, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp ADD       = new SSEOp("ADD",             P_0F, 0x58);
+        public static final SSEOp MUL       = new SSEOp("MUL",             P_0F, 0x59);
+        public static final SSEOp CVTSS2SD  = new SSEOp("CVTSS2SD",        P_0F, 0x5A, OpAssertion.SingleAssertion);
+        public static final SSEOp CVTSD2SS  = new SSEOp("CVTSD2SS",        P_0F, 0x5A, OpAssertion.DoubleAssertion);
+        public static final SSEOp SUB       = new SSEOp("SUB",             P_0F, 0x5C);
+        public static final SSEOp MIN       = new SSEOp("MIN",             P_0F, 0x5D);
+        public static final SSEOp DIV       = new SSEOp("DIV",             P_0F, 0x5E);
+        public static final SSEOp MAX       = new SSEOp("MAX",             P_0F, 0x5F);
+        // @formatter:on
+
+        protected SSEOp(String opcode, int prefix, int op) {
+            this(opcode, prefix, op, OpAssertion.FloatingAssertion);
+        }
+
+        protected SSEOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion);
+        }
+
+        protected SSEOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) {
+            super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.SSE2);
+        }
+    }
+
+    public static class AVXOp extends AMD64RRMOp {
+        // @formatter:off
+        public static final AVXOp AND       = new AVXOp("AND",             P_0F, 0x54, OpAssertion.PackedFloatingAssertion);
+        public static final AVXOp ANDN      = new AVXOp("ANDN",            P_0F, 0x55, OpAssertion.PackedFloatingAssertion);
+        public static final AVXOp OR        = new AVXOp("OR",              P_0F, 0x56, OpAssertion.PackedFloatingAssertion);
+        public static final AVXOp XOR       = new AVXOp("XOR",             P_0F, 0x57, OpAssertion.PackedFloatingAssertion);
+        public static final AVXOp ADD       = new AVXOp("ADD",             P_0F, 0x58);
+        public static final AVXOp MUL       = new AVXOp("MUL",             P_0F, 0x59);
+        public static final AVXOp SUB       = new AVXOp("SUB",             P_0F, 0x5C);
+        public static final AVXOp MIN       = new AVXOp("MIN",             P_0F, 0x5D);
+        public static final AVXOp DIV       = new AVXOp("DIV",             P_0F, 0x5E);
+        public static final AVXOp MAX       = new AVXOp("MAX",             P_0F, 0x5F);
+        // @formatter:on
+
+        protected AVXOp(String opcode, int prefix, int op) {
+            this(opcode, prefix, op, OpAssertion.FloatingAssertion);
+        }
+
+        protected AVXOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion);
+        }
+
+        protected AVXOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) {
+            super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.AVX);
+        }
+    }
+
+    /**
+     * Arithmetic operation with operand order of RM, MR or MI.
+     */
+    public static final class AMD64BinaryArithmetic {
+        // @formatter:off
+        public static final AMD64BinaryArithmetic ADD = new AMD64BinaryArithmetic("ADD", 0);
+        public static final AMD64BinaryArithmetic OR  = new AMD64BinaryArithmetic("OR",  1);
+        public static final AMD64BinaryArithmetic ADC = new AMD64BinaryArithmetic("ADC", 2);
+        public static final AMD64BinaryArithmetic SBB = new AMD64BinaryArithmetic("SBB", 3);
+        public static final AMD64BinaryArithmetic AND = new AMD64BinaryArithmetic("AND", 4);
+        public static final AMD64BinaryArithmetic SUB = new AMD64BinaryArithmetic("SUB", 5);
+        public static final AMD64BinaryArithmetic XOR = new AMD64BinaryArithmetic("XOR", 6);
+        public static final AMD64BinaryArithmetic CMP = new AMD64BinaryArithmetic("CMP", 7);
+        // @formatter:on
+
+        private final AMD64MIOp byteImmOp;
+        private final AMD64MROp byteMrOp;
+        private final AMD64RMOp byteRmOp;
+
+        private final AMD64MIOp immOp;
+        private final AMD64MIOp immSxOp;
+        private final AMD64MROp mrOp;
+        private final AMD64RMOp rmOp;
+
+        private AMD64BinaryArithmetic(String opcode, int code) {
+            int baseOp = code << 3;
+
+            byteImmOp = new AMD64MIOp(opcode, true, 0, 0x80, code, OpAssertion.ByteAssertion);
+            byteMrOp = new AMD64MROp(opcode, 0, baseOp, OpAssertion.ByteAssertion);
+            byteRmOp = new AMD64RMOp(opcode, 0, baseOp | 0x02, OpAssertion.ByteAssertion);
+
+            immOp = new AMD64MIOp(opcode, false, 0, 0x81, code, OpAssertion.IntegerAssertion);
+            immSxOp = new AMD64MIOp(opcode, true, 0, 0x83, code, OpAssertion.IntegerAssertion);
+            mrOp = new AMD64MROp(opcode, 0, baseOp | 0x01, OpAssertion.IntegerAssertion);
+            rmOp = new AMD64RMOp(opcode, 0, baseOp | 0x03, OpAssertion.IntegerAssertion);
+        }
+
+        public AMD64MIOp getMIOpcode(OperandSize size, boolean sx) {
+            if (size == BYTE) {
+                return byteImmOp;
+            } else if (sx) {
+                return immSxOp;
+            } else {
+                return immOp;
+            }
+        }
+
+        public AMD64MROp getMROpcode(OperandSize size) {
+            if (size == BYTE) {
+                return byteMrOp;
+            } else {
+                return mrOp;
+            }
+        }
+
+        public AMD64RMOp getRMOpcode(OperandSize size) {
+            if (size == BYTE) {
+                return byteRmOp;
+            } else {
+                return rmOp;
+            }
+        }
+    }
+
+    /**
+     * Shift operation with operand order of M1, MC or MI.
+     */
+    public static final class AMD64Shift {
+        // @formatter:off
+        public static final AMD64Shift ROL = new AMD64Shift("ROL", 0);
+        public static final AMD64Shift ROR = new AMD64Shift("ROR", 1);
+        public static final AMD64Shift RCL = new AMD64Shift("RCL", 2);
+        public static final AMD64Shift RCR = new AMD64Shift("RCR", 3);
+        public static final AMD64Shift SHL = new AMD64Shift("SHL", 4);
+        public static final AMD64Shift SHR = new AMD64Shift("SHR", 5);
+        public static final AMD64Shift SAR = new AMD64Shift("SAR", 7);
+        // @formatter:on
+
+        public final AMD64MOp m1Op;
+        public final AMD64MOp mcOp;
+        public final AMD64MIOp miOp;
+
+        private AMD64Shift(String opcode, int code) {
+            m1Op = new AMD64MOp(opcode, 0, 0xD1, code, OpAssertion.IntegerAssertion);
+            mcOp = new AMD64MOp(opcode, 0, 0xD3, code, OpAssertion.IntegerAssertion);
+            miOp = new AMD64MIOp(opcode, true, 0, 0xC1, code, OpAssertion.IntegerAssertion);
+        }
+    }
+
+    public final void addl(AMD64Address dst, int imm32) {
+        ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void addl(Register dst, int imm32) {
+        ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void addl(Register dst, Register src) {
+        ADD.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void addpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x58);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void addpd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x58);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void addsd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x58);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void addsd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x58);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    private void addrNop4() {
+        // 4 bytes: NOP DWORD PTR [EAX+0]
+        emitByte(0x0F);
+        emitByte(0x1F);
+        emitByte(0x40); // emitRm(cbuf, 0x1, EAXEnc, EAXEnc);
+        emitByte(0); // 8-bits offset (1 byte)
+    }
+
+    private void addrNop5() {
+        // 5 bytes: NOP DWORD PTR [EAX+EAX*0+0] 8-bits offset
+        emitByte(0x0F);
+        emitByte(0x1F);
+        emitByte(0x44); // emitRm(cbuf, 0x1, EAXEnc, 0x4);
+        emitByte(0x00); // emitRm(cbuf, 0x0, EAXEnc, EAXEnc);
+        emitByte(0); // 8-bits offset (1 byte)
+    }
+
+    private void addrNop7() {
+        // 7 bytes: NOP DWORD PTR [EAX+0] 32-bits offset
+        emitByte(0x0F);
+        emitByte(0x1F);
+        emitByte(0x80); // emitRm(cbuf, 0x2, EAXEnc, EAXEnc);
+        emitInt(0); // 32-bits offset (4 bytes)
+    }
+
+    private void addrNop8() {
+        // 8 bytes: NOP DWORD PTR [EAX+EAX*0+0] 32-bits offset
+        emitByte(0x0F);
+        emitByte(0x1F);
+        emitByte(0x84); // emitRm(cbuf, 0x2, EAXEnc, 0x4);
+        emitByte(0x00); // emitRm(cbuf, 0x0, EAXEnc, EAXEnc);
+        emitInt(0); // 32-bits offset (4 bytes)
+    }
+
+    public final void andl(Register dst, int imm32) {
+        AND.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void andl(Register dst, Register src) {
+        AND.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void andpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x54);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void andpd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x54);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void bsrl(Register dst, Register src) {
+        int encode = prefixAndEncode(dst.encoding(), src.encoding());
+        emitByte(0x0F);
+        emitByte(0xBD);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void bswapl(Register reg) {
+        int encode = prefixAndEncode(reg.encoding);
+        emitByte(0x0F);
+        emitByte(0xC8 | encode);
+    }
+
+    public final void cdql() {
+        emitByte(0x99);
+    }
+
+    public final void cmovl(ConditionFlag cc, Register dst, Register src) {
+        int encode = prefixAndEncode(dst.encoding, src.encoding);
+        emitByte(0x0F);
+        emitByte(0x40 | cc.getValue());
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cmovl(ConditionFlag cc, Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0x40 | cc.getValue());
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void cmpl(Register dst, int imm32) {
+        CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void cmpl(Register dst, Register src) {
+        CMP.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void cmpl(Register dst, AMD64Address src) {
+        CMP.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void cmpl(AMD64Address dst, int imm32) {
+        CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax,
+    // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,.
+    // The ZF is set if the compared values were equal, and cleared otherwise.
+    public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg
+        prefix(adr, reg);
+        emitByte(0x0F);
+        emitByte(0xB1);
+        emitOperandHelper(reg, adr, 0);
+    }
+
+    public final void cvtsi2sdl(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x2A);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cvttsd2sil(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x2C);
+        emitByte(0xC0 | encode);
+    }
+
+    protected final void decl(AMD64Address dst) {
+        prefix(dst);
+        emitByte(0xFF);
+        emitOperandHelper(1, dst, 0);
+    }
+
+    public final void divsd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x5E);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void hlt() {
+        emitByte(0xF4);
+    }
+
+    public final void imull(Register dst, Register src, int value) {
+        if (isByte(value)) {
+            AMD64RMIOp.IMUL_SX.emit(this, DWORD, dst, src, value);
+        } else {
+            AMD64RMIOp.IMUL.emit(this, DWORD, dst, src, value);
+        }
+    }
+
+    protected final void incl(AMD64Address dst) {
+        prefix(dst);
+        emitByte(0xFF);
+        emitOperandHelper(0, dst, 0);
+    }
+
+    public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
+        int shortSize = 2;
+        int longSize = 6;
+        long disp = jumpTarget - position();
+        if (!forceDisp32 && isByte(disp - shortSize)) {
+            // 0111 tttn #8-bit disp
+            emitByte(0x70 | cc.getValue());
+            emitByte((int) ((disp - shortSize) & 0xFF));
+        } else {
+            // 0000 1111 1000 tttn #32-bit disp
+            assert isInt(disp - longSize) : "must be 32bit offset (call4)";
+            emitByte(0x0F);
+            emitByte(0x80 | cc.getValue());
+            emitInt((int) (disp - longSize));
+        }
+    }
+
+    public final void jcc(ConditionFlag cc, Label l) {
+        assert (0 <= cc.getValue()) && (cc.getValue() < 16) : "illegal cc";
+        if (l.isBound()) {
+            jcc(cc, l.position(), false);
+        } else {
+            // Note: could eliminate cond. jumps to this jump if condition
+            // is the same however, seems to be rather unlikely case.
+            // Note: use jccb() if label to be bound is very close to get
+            // an 8-bit displacement
+            l.addPatchAt(position());
+            emitByte(0x0F);
+            emitByte(0x80 | cc.getValue());
+            emitInt(0);
+        }
+
+    }
+
+    public final void jccb(ConditionFlag cc, Label l) {
+        if (l.isBound()) {
+            int shortSize = 2;
+            int entry = l.position();
+            assert isByte(entry - (position() + shortSize)) : "Dispacement too large for a short jmp";
+            long disp = entry - position();
+            // 0111 tttn #8-bit disp
+            emitByte(0x70 | cc.getValue());
+            emitByte((int) ((disp - shortSize) & 0xFF));
+        } else {
+            l.addPatchAt(position());
+            emitByte(0x70 | cc.getValue());
+            emitByte(0);
+        }
+    }
+
+    public final void jmp(int jumpTarget, boolean forceDisp32) {
+        int shortSize = 2;
+        int longSize = 5;
+        long disp = jumpTarget - position();
+        if (!forceDisp32 && isByte(disp - shortSize)) {
+            emitByte(0xEB);
+            emitByte((int) ((disp - shortSize) & 0xFF));
+        } else {
+            emitByte(0xE9);
+            emitInt((int) (disp - longSize));
+        }
+    }
+
+    @Override
+    public final void jmp(Label l) {
+        if (l.isBound()) {
+            jmp(l.position(), false);
+        } else {
+            // By default, forward jumps are always 32-bit displacements, since
+            // we can't yet know where the label will be bound. If you're sure that
+            // the forward jump will not run beyond 256 bytes, use jmpb to
+            // force an 8-bit displacement.
+
+            l.addPatchAt(position());
+            emitByte(0xE9);
+            emitInt(0);
+        }
+    }
+
+    public final void jmp(Register entry) {
+        int encode = prefixAndEncode(entry.encoding);
+        emitByte(0xFF);
+        emitByte(0xE0 | encode);
+    }
+
+    public final void jmp(AMD64Address adr) {
+        prefix(adr);
+        emitByte(0xFF);
+        emitOperandHelper(rsp, adr, 0);
+    }
+
+    public final void jmpb(Label l) {
+        if (l.isBound()) {
+            int shortSize = 2;
+            int entry = l.position();
+            assert isByte((entry - position()) + shortSize) : "Dispacement too large for a short jmp";
+            long offs = entry - position();
+            emitByte(0xEB);
+            emitByte((int) ((offs - shortSize) & 0xFF));
+        } else {
+
+            l.addPatchAt(position());
+            emitByte(0xEB);
+            emitByte(0);
+        }
+    }
+
+    public final void leaq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x8D);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void leave() {
+        emitByte(0xC9);
+    }
+
+    public final void lock() {
+        emitByte(0xF0);
+    }
+
+    public final void movapd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x28);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movaps(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x28);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movb(AMD64Address dst, int imm8) {
+        prefix(dst);
+        emitByte(0xC6);
+        emitOperandHelper(0, dst, 1);
+        emitByte(imm8);
+    }
+
+    public final void movb(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.CPU) : "must have byte register";
+        prefix(dst, src, true);
+        emitByte(0x88);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void movl(Register dst, int imm32) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xB8 | encode);
+        emitInt(imm32);
+    }
+
+    public final void movl(Register dst, Register src) {
+        int encode = prefixAndEncode(dst.encoding, src.encoding);
+        emitByte(0x8B);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x8B);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movl(AMD64Address dst, int imm32) {
+        prefix(dst);
+        emitByte(0xC7);
+        emitOperandHelper(0, dst, 4);
+        emitInt(imm32);
+    }
+
+    public final void movl(AMD64Address dst, Register src) {
+        prefix(dst, src);
+        emitByte(0x89);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    /**
+     * New CPUs require use of movsd and movss to avoid partial register stall when loading from
+     * memory. But for old Opteron use movlpd instead of movsd. The selection is done in
+     * {@link AMD64MacroAssembler#movdbl(Register, AMD64Address)} and
+     * {@link AMD64MacroAssembler#movflt(Register, Register)}.
+     */
+    public final void movlpd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x12);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movlhps(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, src, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x16);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movq(Register dst, AMD64Address src) {
+        movq(dst, src, false);
+    }
+
+    public final void movq(Register dst, AMD64Address src, boolean wide) {
+        if (dst.getRegisterCategory().equals(AMD64.XMM)) {
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ wide, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x7E);
+            emitOperandHelper(dst, src, wide, 0);
+        } else {
+            // gpr version of movq
+            prefixq(src, dst);
+            emitByte(0x8B);
+            emitOperandHelper(dst, src, wide, 0);
+        }
+    }
+
+    public final void movq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x8B);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movq(AMD64Address dst, Register src) {
+        if (src.getRegisterCategory().equals(AMD64.XMM)) {
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0xD6);
+            emitOperandHelper(src, dst, 0);
+        } else {
+            // gpr version of movq
+            prefixq(dst, src);
+            emitByte(0x89);
+            emitOperandHelper(src, dst, 0);
+        }
+    }
+
+    public final void movsbl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0xBE);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movsbl(Register dst, Register src) {
+        int encode = prefixAndEncode(dst.encoding, false, src.encoding, true);
+        emitByte(0x0F);
+        emitByte(0xBE);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movsbq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x0F);
+        emitByte(0xBE);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movsbq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x0F);
+        emitByte(0xBE);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movsd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x10);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movsd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x10);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movsd(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x11);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void movss(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x10);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movss(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x10);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movss(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x11);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void mulpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x59);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mulpd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x59);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void mulsd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x59);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mulsd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x59);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void mulss(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x59);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movswl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0xBF);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movw(AMD64Address dst, int imm16) {
+        emitByte(0x66); // switch to 16-bit mode
+        prefix(dst);
+        emitByte(0xC7);
+        emitOperandHelper(0, dst, 2);
+        emitShort(imm16);
+    }
+
+    public final void movw(AMD64Address dst, Register src) {
+        emitByte(0x66);
+        prefix(dst, src);
+        emitByte(0x89);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void movzbl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0xB6);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movzwl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0xB7);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void negl(Register dst) {
+        NEG.emit(this, DWORD, dst);
+    }
+
+    public final void notl(Register dst) {
+        NOT.emit(this, DWORD, dst);
+    }
+
+    @Override
+    public final void ensureUniquePC() {
+        nop();
+    }
+
+    public final void nop() {
+        nop(1);
+    }
+
+    public void nop(int count) {
+        int i = count;
+        if (UseNormalNop) {
+            assert i > 0 : " ";
+            // The fancy nops aren't currently recognized by debuggers making it a
+            // pain to disassemble code while debugging. If assert are on clearly
+            // speed is not an issue so simply use the single byte traditional nop
+            // to do alignment.
+
+            for (; i > 0; i--) {
+                emitByte(0x90);
+            }
+            return;
+        }
+
+        if (UseAddressNop) {
+            //
+            // Using multi-bytes nops "0x0F 0x1F [Address]" for AMD.
+            // 1: 0x90
+            // 2: 0x66 0x90
+            // 3: 0x66 0x66 0x90 (don't use "0x0F 0x1F 0x00" - need patching safe padding)
+            // 4: 0x0F 0x1F 0x40 0x00
+            // 5: 0x0F 0x1F 0x44 0x00 0x00
+            // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00
+            // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+            // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+            // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+            // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+            // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+
+            // The rest coding is AMD specific - use consecutive Address nops
+
+            // 12: 0x66 0x0F 0x1F 0x44 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
+            // 13: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
+            // 14: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+            // 15: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+            // 16: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+            // Size prefixes (0x66) are added for larger sizes
+
+            while (i >= 22) {
+                i -= 11;
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                addrNop8();
+            }
+            // Generate first nop for size between 21-12
+            switch (i) {
+                case 21:
+                    i -= 11;
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 20:
+                case 19:
+                    i -= 10;
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 18:
+                case 17:
+                    i -= 9;
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 16:
+                case 15:
+                    i -= 8;
+                    addrNop8();
+                    break;
+                case 14:
+                case 13:
+                    i -= 7;
+                    addrNop7();
+                    break;
+                case 12:
+                    i -= 6;
+                    emitByte(0x66); // size prefix
+                    addrNop5();
+                    break;
+                default:
+                    assert i < 12;
+            }
+
+            // Generate second nop for size between 11-1
+            switch (i) {
+                case 11:
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 10:
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 9:
+                    emitByte(0x66); // size prefix
+                    addrNop8();
+                    break;
+                case 8:
+                    addrNop8();
+                    break;
+                case 7:
+                    addrNop7();
+                    break;
+                case 6:
+                    emitByte(0x66); // size prefix
+                    addrNop5();
+                    break;
+                case 5:
+                    addrNop5();
+                    break;
+                case 4:
+                    addrNop4();
+                    break;
+                case 3:
+                    // Don't use "0x0F 0x1F 0x00" - need patching safe padding
+                    emitByte(0x66); // size prefix
+                    emitByte(0x66); // size prefix
+                    emitByte(0x90); // nop
+                    break;
+                case 2:
+                    emitByte(0x66); // size prefix
+                    emitByte(0x90); // nop
+                    break;
+                case 1:
+                    emitByte(0x90); // nop
+                    break;
+                default:
+                    assert i == 0;
+            }
+            return;
+        }
+
+        // Using nops with size prefixes "0x66 0x90".
+        // From AMD Optimization Guide:
+        // 1: 0x90
+        // 2: 0x66 0x90
+        // 3: 0x66 0x66 0x90
+        // 4: 0x66 0x66 0x66 0x90
+        // 5: 0x66 0x66 0x90 0x66 0x90
+        // 6: 0x66 0x66 0x90 0x66 0x66 0x90
+        // 7: 0x66 0x66 0x66 0x90 0x66 0x66 0x90
+        // 8: 0x66 0x66 0x66 0x90 0x66 0x66 0x66 0x90
+        // 9: 0x66 0x66 0x90 0x66 0x66 0x90 0x66 0x66 0x90
+        // 10: 0x66 0x66 0x66 0x90 0x66 0x66 0x90 0x66 0x66 0x90
+        //
+        while (i > 12) {
+            i -= 4;
+            emitByte(0x66); // size prefix
+            emitByte(0x66);
+            emitByte(0x66);
+            emitByte(0x90); // nop
+        }
+        // 1 - 12 nops
+        if (i > 8) {
+            if (i > 9) {
+                i -= 1;
+                emitByte(0x66);
+            }
+            i -= 3;
+            emitByte(0x66);
+            emitByte(0x66);
+            emitByte(0x90);
+        }
+        // 1 - 8 nops
+        if (i > 4) {
+            if (i > 6) {
+                i -= 1;
+                emitByte(0x66);
+            }
+            i -= 3;
+            emitByte(0x66);
+            emitByte(0x66);
+            emitByte(0x90);
+        }
+        switch (i) {
+            case 4:
+                emitByte(0x66);
+                emitByte(0x66);
+                emitByte(0x66);
+                emitByte(0x90);
+                break;
+            case 3:
+                emitByte(0x66);
+                emitByte(0x66);
+                emitByte(0x90);
+                break;
+            case 2:
+                emitByte(0x66);
+                emitByte(0x90);
+                break;
+            case 1:
+                emitByte(0x90);
+                break;
+            default:
+                assert i == 0;
+        }
+    }
+
+    public final void orl(Register dst, Register src) {
+        OR.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void orl(Register dst, int imm32) {
+        OR.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void pop(Register dst) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0x58 | encode);
+    }
+
+    public void popfq() {
+        emitByte(0x9D);
+    }
+
+    public final void ptest(Register dst, Register src) {
+        assert supports(CPUFeature.SSE4_1);
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
+        emitByte(0x17);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void vptest(Register dst, Register src) {
+        assert supports(CPUFeature.AVX);
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
+        emitByte(0x17);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void push(Register src) {
+        int encode = prefixAndEncode(src.encoding);
+        emitByte(0x50 | encode);
+    }
+
+    public void pushfq() {
+        emitByte(0x9c);
+    }
+
+    public final void paddd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xFE);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void paddq(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xD4);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void pextrw(Register dst, Register src, int imm8) {
+        assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xC5);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void pinsrw(Register dst, Register src, int imm8) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xC4);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void por(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xEB);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void pand(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xDB);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void pxor(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xEF);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void vpxor(Register dst, Register nds, Register src) {
+        assert supports(CPUFeature.AVX);
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = vexPrefixAndEncode(dst, nds, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xEF);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void pslld(Register dst, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        // XMM6 is for /6 encoding: 66 0F 72 /6 ib
+        int encode = simdPrefixAndEncode(AMD64.xmm6, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x72);
+        emitByte(0xC0 | encode);
+        emitByte(imm8 & 0xFF);
+    }
+
+    public final void psllq(Register dst, Register shift) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && shift.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, shift, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xF3);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void psllq(Register dst, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        // XMM6 is for /6 encoding: 66 0F 73 /6 ib
+        int encode = simdPrefixAndEncode(AMD64.xmm6, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x73);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void psrad(Register dst, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        // XMM4 is for /2 encoding: 66 0F 72 /4 ib
+        int encode = simdPrefixAndEncode(AMD64.xmm4, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x72);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void psrld(Register dst, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        // XMM2 is for /2 encoding: 66 0F 72 /2 ib
+        int encode = simdPrefixAndEncode(AMD64.xmm2, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x72);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void psrlq(Register dst, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        // XMM2 is for /2 encoding: 66 0F 73 /2 ib
+        int encode = simdPrefixAndEncode(AMD64.xmm2, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x73);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void pshufd(Register dst, Register src, int imm8) {
+        assert isUByte(imm8) : "invalid value";
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x70);
+        emitByte(0xC0 | encode);
+        emitByte(imm8);
+    }
+
+    public final void psubd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xFA);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void rcpps(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ true, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x53);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void ret(int imm16) {
+        if (imm16 == 0) {
+            emitByte(0xC3);
+        } else {
+            emitByte(0xC2);
+            emitShort(imm16);
+        }
+    }
+
+    public final void sarl(Register dst, int imm8) {
+        int encode = prefixAndEncode(dst.encoding);
+        assert isShiftCount(imm8 >> 1) : "illegal shift count";
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xF8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xF8 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void shll(Register dst, int imm8) {
+        assert isShiftCount(imm8 >> 1) : "illegal shift count";
+        int encode = prefixAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xE0 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xE0 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void shll(Register dst) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xE0 | encode);
+    }
+
+    public final void shrl(Register dst, int imm8) {
+        assert isShiftCount(imm8 >> 1) : "illegal shift count";
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xC1);
+        emitByte(0xE8 | encode);
+        emitByte(imm8);
+    }
+
+    public final void shrl(Register dst) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xE8 | encode);
+    }
+
+    public final void subl(AMD64Address dst, int imm32) {
+        SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void subl(Register dst, int imm32) {
+        SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
+    }
+
+    public final void subl(Register dst, Register src) {
+        SUB.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void subpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x5C);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void subsd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x5C);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void subsd(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x5C);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void testl(Register dst, int imm32) {
+        // not using emitArith because test
+        // doesn't support sign-extension of
+        // 8bit operands
+        int encode = dst.encoding;
+        if (encode == 0) {
+            emitByte(0xA9);
+        } else {
+            encode = prefixAndEncode(encode);
+            emitByte(0xF7);
+            emitByte(0xC0 | encode);
+        }
+        emitInt(imm32);
+    }
+
+    public final void testl(Register dst, Register src) {
+        int encode = prefixAndEncode(dst.encoding, src.encoding);
+        emitByte(0x85);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void testl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x85);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void unpckhpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x15);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void unpcklpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x14);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void xorl(Register dst, Register src) {
+        XOR.rmOp.emit(this, DWORD, dst, src);
+    }
+
+    public final void xorpd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x57);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void xorps(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x57);
+        emitByte(0xC0 | encode);
+    }
+
+    protected final void decl(Register dst) {
+        // Use two-byte form (one-byte form is a REX prefix in 64-bit mode)
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xFF);
+        emitByte(0xC8 | encode);
+    }
+
+    protected final void incl(Register dst) {
+        // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xFF);
+        emitByte(0xC0 | encode);
+    }
+
+    private int prefixAndEncode(int regEnc) {
+        return prefixAndEncode(regEnc, false);
+    }
+
+    private int prefixAndEncode(int regEnc, boolean byteinst) {
+        if (regEnc >= 8) {
+            emitByte(Prefix.REXB);
+            return regEnc - 8;
+        } else if (byteinst && regEnc >= 4) {
+            emitByte(Prefix.REX);
+        }
+        return regEnc;
+    }
+
+    private int prefixqAndEncode(int regEnc) {
+        if (regEnc < 8) {
+            emitByte(Prefix.REXW);
+            return regEnc;
+        } else {
+            emitByte(Prefix.REXWB);
+            return regEnc - 8;
+        }
+    }
+
+    private int prefixAndEncode(int dstEnc, int srcEnc) {
+        return prefixAndEncode(dstEnc, false, srcEnc, false);
+    }
+
+    private int prefixAndEncode(int dstEncoding, boolean dstIsByte, int srcEncoding, boolean srcIsByte) {
+        int srcEnc = srcEncoding;
+        int dstEnc = dstEncoding;
+        if (dstEnc < 8) {
+            if (srcEnc >= 8) {
+                emitByte(Prefix.REXB);
+                srcEnc -= 8;
+            } else if ((srcIsByte && srcEnc >= 4) || (dstIsByte && dstEnc >= 4)) {
+                emitByte(Prefix.REX);
+            }
+        } else {
+            if (srcEnc < 8) {
+                emitByte(Prefix.REXR);
+            } else {
+                emitByte(Prefix.REXRB);
+                srcEnc -= 8;
+            }
+            dstEnc -= 8;
+        }
+        return dstEnc << 3 | srcEnc;
+    }
+
+    /**
+     * Creates prefix and the encoding of the lower 6 bits of the ModRM-Byte. It emits an operand
+     * prefix. If the given operands exceed 3 bits, the 4th bit is encoded in the prefix.
+     *
+     * @param regEncoding the encoding of the register part of the ModRM-Byte
+     * @param rmEncoding the encoding of the r/m part of the ModRM-Byte
+     * @return the lower 6 bits of the ModRM-Byte that should be emitted
+     */
+    private int prefixqAndEncode(int regEncoding, int rmEncoding) {
+        int rmEnc = rmEncoding;
+        int regEnc = regEncoding;
+        if (regEnc < 8) {
+            if (rmEnc < 8) {
+                emitByte(Prefix.REXW);
+            } else {
+                emitByte(Prefix.REXWB);
+                rmEnc -= 8;
+            }
+        } else {
+            if (rmEnc < 8) {
+                emitByte(Prefix.REXWR);
+            } else {
+                emitByte(Prefix.REXWRB);
+                rmEnc -= 8;
+            }
+            regEnc -= 8;
+        }
+        return regEnc << 3 | rmEnc;
+    }
+
+    private void vexPrefix(int rxb, int ndsEncoding, int pre, int opc, AMD64InstructionAttr attributes) {
+        int vectorLen = attributes.getVectorLen();
+        boolean vexW = attributes.isRexVexW();
+        boolean isXorB = ((rxb & 0x3) > 0);
+        if (isXorB || vexW || (opc == VexOpcode.VEX_OPCODE_0F_38) || (opc == VexOpcode.VEX_OPCODE_0F_3A)) {
+            emitByte(Prefix.VEX_3BYTES);
+
+            int byte1 = (rxb << 5);
+            byte1 = ((~byte1) & 0xE0) | opc;
+            emitByte(byte1);
+
+            int byte2 = ((~ndsEncoding) & 0xf) << 3;
+            byte2 |= (vexW ? VexPrefix.VEX_W : 0) | ((vectorLen > 0) ? 4 : 0) | pre;
+            emitByte(byte2);
+        } else {
+            emitByte(Prefix.VEX_2BYTES);
+
+            int byte1 = ((rxb & 0x4) > 0) ? VexPrefix.VEX_R : 0;
+            byte1 = (~byte1) & 0x80;
+            byte1 |= ((~ndsEncoding) & 0xf) << 3;
+            byte1 |= ((vectorLen > 0) ? 4 : 0) | pre;
+            emitByte(byte1);
+        }
+    }
+
+    private void vexPrefix(AMD64Address adr, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) {
+        int rxb = getRXB(src, adr);
+        int ndsEncoding = nds.isValid() ? nds.encoding : 0;
+        vexPrefix(rxb, ndsEncoding, pre, opc, attributes);
+        setCurAttributes(attributes);
+    }
+
+    private int vexPrefixAndEncode(Register dst, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) {
+        int rxb = getRXB(dst, src);
+        int ndsEncoding = nds.isValid() ? nds.encoding : 0;
+        vexPrefix(rxb, ndsEncoding, pre, opc, attributes);
+        // return modrm byte components for operands
+        return (((dst.encoding & 7) << 3) | (src.encoding & 7));
+    }
+
+    private void simdPrefix(Register xreg, Register nds, AMD64Address adr, int pre, int opc, AMD64InstructionAttr attributes) {
+        if (supports(CPUFeature.AVX)) {
+            vexPrefix(adr, nds, xreg, pre, opc, attributes);
+        } else {
+            switch (pre) {
+                case VexSimdPrefix.VEX_SIMD_66:
+                    emitByte(0x66);
+                    break;
+                case VexSimdPrefix.VEX_SIMD_F2:
+                    emitByte(0xF2);
+                    break;
+                case VexSimdPrefix.VEX_SIMD_F3:
+                    emitByte(0xF3);
+                    break;
+            }
+            if (attributes.isRexVexW()) {
+                prefixq(adr, xreg);
+            } else {
+                prefix(adr, xreg);
+            }
+            switch (opc) {
+                case VexOpcode.VEX_OPCODE_0F:
+                    emitByte(0x0F);
+                    break;
+                case VexOpcode.VEX_OPCODE_0F_38:
+                    emitByte(0x0F);
+                    emitByte(0x38);
+                    break;
+                case VexOpcode.VEX_OPCODE_0F_3A:
+                    emitByte(0x0F);
+                    emitByte(0x3A);
+                    break;
+            }
+        }
+    }
+
+    private int simdPrefixAndEncode(Register dst, Register nds, Register src, int pre, int opc, AMD64InstructionAttr attributes) {
+        if (supports(CPUFeature.AVX)) {
+            return vexPrefixAndEncode(dst, nds, src, pre, opc, attributes);
+        } else {
+            switch (pre) {
+                case VexSimdPrefix.VEX_SIMD_66:
+                    emitByte(0x66);
+                    break;
+                case VexSimdPrefix.VEX_SIMD_F2:
+                    emitByte(0xF2);
+                    break;
+                case VexSimdPrefix.VEX_SIMD_F3:
+                    emitByte(0xF3);
+                    break;
+            }
+            int encode;
+            int dstEncoding = dst.encoding;
+            int srcEncoding = src.encoding;
+            if (attributes.isRexVexW()) {
+                encode = prefixqAndEncode(dstEncoding, srcEncoding);
+            } else {
+                encode = prefixAndEncode(dstEncoding, srcEncoding);
+            }
+            switch (opc) {
+                case VexOpcode.VEX_OPCODE_0F:
+                    emitByte(0x0F);
+                    break;
+                case VexOpcode.VEX_OPCODE_0F_38:
+                    emitByte(0x0F);
+                    emitByte(0x38);
+                    break;
+                case VexOpcode.VEX_OPCODE_0F_3A:
+                    emitByte(0x0F);
+                    emitByte(0x3A);
+                    break;
+            }
+            return encode;
+        }
+    }
+
+    private static boolean needsRex(Register reg) {
+        return reg.encoding >= MinEncodingNeedsRex;
+    }
+
+    private void prefix(AMD64Address adr) {
+        if (needsRex(adr.getBase())) {
+            if (needsRex(adr.getIndex())) {
+                emitByte(Prefix.REXXB);
+            } else {
+                emitByte(Prefix.REXB);
+            }
+        } else {
+            if (needsRex(adr.getIndex())) {
+                emitByte(Prefix.REXX);
+            }
+        }
+    }
+
+    private void prefixq(AMD64Address adr) {
+        if (needsRex(adr.getBase())) {
+            if (needsRex(adr.getIndex())) {
+                emitByte(Prefix.REXWXB);
+            } else {
+                emitByte(Prefix.REXWB);
+            }
+        } else {
+            if (needsRex(adr.getIndex())) {
+                emitByte(Prefix.REXWX);
+            } else {
+                emitByte(Prefix.REXW);
+            }
+        }
+    }
+
+    private void prefix(AMD64Address adr, Register reg) {
+        prefix(adr, reg, false);
+    }
+
+    private void prefix(AMD64Address adr, Register reg, boolean byteinst) {
+        if (reg.encoding < 8) {
+            if (needsRex(adr.getBase())) {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXXB);
+                } else {
+                    emitByte(Prefix.REXB);
+                }
+            } else {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXX);
+                } else if (byteinst && reg.encoding >= 4) {
+                    emitByte(Prefix.REX);
+                }
+            }
+        } else {
+            if (needsRex(adr.getBase())) {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXRXB);
+                } else {
+                    emitByte(Prefix.REXRB);
+                }
+            } else {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXRX);
+                } else {
+                    emitByte(Prefix.REXR);
+                }
+            }
+        }
+    }
+
+    private void prefixq(AMD64Address adr, Register src) {
+        if (src.encoding < 8) {
+            if (needsRex(adr.getBase())) {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXWXB);
+                } else {
+                    emitByte(Prefix.REXWB);
+                }
+            } else {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXWX);
+                } else {
+                    emitByte(Prefix.REXW);
+                }
+            }
+        } else {
+            if (needsRex(adr.getBase())) {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXWRXB);
+                } else {
+                    emitByte(Prefix.REXWRB);
+                }
+            } else {
+                if (needsRex(adr.getIndex())) {
+                    emitByte(Prefix.REXWRX);
+                } else {
+                    emitByte(Prefix.REXWR);
+                }
+            }
+        }
+    }
+
+    public final void addq(Register dst, int imm32) {
+        ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void addq(AMD64Address dst, int imm32) {
+        ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void addq(Register dst, Register src) {
+        ADD.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void addq(AMD64Address dst, Register src) {
+        ADD.mrOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void andq(Register dst, int imm32) {
+        AND.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void bsrq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding(), src.encoding());
+        emitByte(0x0F);
+        emitByte(0xBD);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void bswapq(Register reg) {
+        int encode = prefixqAndEncode(reg.encoding);
+        emitByte(0x0F);
+        emitByte(0xC8 | encode);
+    }
+
+    public final void cdqq() {
+        emitByte(Prefix.REXW);
+        emitByte(0x99);
+    }
+
+    public final void cmovq(ConditionFlag cc, Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x0F);
+        emitByte(0x40 | cc.getValue());
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cmovq(ConditionFlag cc, Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x0F);
+        emitByte(0x40 | cc.getValue());
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void cmpq(Register dst, int imm32) {
+        CMP.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void cmpq(Register dst, Register src) {
+        CMP.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void cmpq(Register dst, AMD64Address src) {
+        CMP.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void cmpxchgq(Register reg, AMD64Address adr) {
+        prefixq(adr, reg);
+        emitByte(0x0F);
+        emitByte(0xB1);
+        emitOperandHelper(reg, adr, 0);
+    }
+
+    public final void cvtdq2pd(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xE6);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cvtsi2sdq(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, dst, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x2A);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cvttsd2siq(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.CPU) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x2C);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void cvttpd2dq(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xE6);
+        emitByte(0xC0 | encode);
+    }
+
+    protected final void decq(Register dst) {
+        // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xFF);
+        emitByte(0xC8 | encode);
+    }
+
+    public final void decq(AMD64Address dst) {
+        DEC.emit(this, QWORD, dst);
+    }
+
+    public final void imulq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x0F);
+        emitByte(0xAF);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void incq(Register dst) {
+        // Don't use it directly. Use Macroincrementq() instead.
+        // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xFF);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void incq(AMD64Address dst) {
+        INC.emit(this, QWORD, dst);
+    }
+
+    public final void movq(Register dst, long imm64) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xB8 | encode);
+        emitLong(imm64);
+    }
+
+    public final void movslq(Register dst, int imm32) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xC7);
+        emitByte(0xC0 | encode);
+        emitInt(imm32);
+    }
+
+    public final void movdq(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x6E);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movdq(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.XMM);
+        // swap src/dst to get correct prefix
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x7E);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void movdq(Register dst, Register src) {
+        if (dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU)) {
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x6E);
+            emitByte(0xC0 | encode);
+        } else if (src.getRegisterCategory().equals(AMD64.XMM) && dst.getRegisterCategory().equals(AMD64.CPU)) {
+            // swap src/dst to get correct prefix
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ true, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            int encode = simdPrefixAndEncode(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x7E);
+            emitByte(0xC0 | encode);
+        } else {
+            throw new InternalError("should not reach here");
+        }
+    }
+
+    public final void movdl(Register dst, Register src) {
+        if (dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.CPU)) {
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x6E);
+            emitByte(0xC0 | encode);
+        } else if (src.getRegisterCategory().equals(AMD64.XMM) && dst.getRegisterCategory().equals(AMD64.CPU)) {
+            // swap src/dst to get correct prefix
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+            int encode = simdPrefixAndEncode(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x7E);
+            emitByte(0xC0 | encode);
+        } else {
+            throw new InternalError("should not reach here");
+        }
+    }
+
+    public final void movddup(Register dst, Register src) {
+        assert supports(CPUFeature.SSE3);
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x12);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void movdqu(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x6F);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movdqu(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x6F);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void vmovdqu(Register dst, AMD64Address src) {
+        assert supports(CPUFeature.AVX);
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x6F);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void vzeroupper() {
+        assert supports(CPUFeature.AVX);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
+        vexPrefixAndEncode(AMD64.xmm0, AMD64.xmm0, AMD64.xmm0, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x77);
+    }
+
+    public final void movslq(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0xC7);
+        emitOperandHelper(0, dst, 4);
+        emitInt(imm32);
+    }
+
+    public final void movslq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x63);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void movslq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x63);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void negq(Register dst) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xF7);
+        emitByte(0xD8 | encode);
+    }
+
+    public final void orq(Register dst, Register src) {
+        OR.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void shlq(Register dst, int imm8) {
+        assert isShiftCount(imm8 >> 1) : "illegal shift count";
+        int encode = prefixqAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xE0 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xE0 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void shlq(Register dst) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xE0 | encode);
+    }
+
+    public final void shrq(Register dst, int imm8) {
+        assert isShiftCount(imm8 >> 1) : "illegal shift count";
+        int encode = prefixqAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xE8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xE8 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void shrq(Register dst) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xE8 | encode);
+    }
+
+    public final void sbbq(Register dst, Register src) {
+        SBB.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void subq(Register dst, int imm32) {
+        SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void subq(AMD64Address dst, int imm32) {
+        SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void subqWide(Register dst, int imm32) {
+        // don't use the sign-extending version, forcing a 32-bit immediate
+        SUB.getMIOpcode(QWORD, false).emit(this, QWORD, dst, imm32);
+    }
+
+    public final void subq(Register dst, Register src) {
+        SUB.rmOp.emit(this, QWORD, dst, src);
+    }
+
+    public final void testq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding, src.encoding);
+        emitByte(0x85);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void xaddl(AMD64Address dst, Register src) {
+        prefix(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC1);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void xaddq(AMD64Address dst, Register src) {
+        prefixq(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC1);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void xchgl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x87);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void xchgq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x87);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void membar(int barriers) {
+        if (target.isMP) {
+            // We only have to handle StoreLoad
+            if ((barriers & STORE_LOAD) != 0) {
+                // All usable chips support "locked" instructions which suffice
+                // as barriers, and are much faster than the alternative of
+                // using cpuid instruction. We use here a locked add [rsp],0.
+                // This is conveniently otherwise a no-op except for blowing
+                // flags.
+                // Any change to this code may need to revisit other places in
+                // the code where this idiom is used, in particular the
+                // orderAccess code.
+                lock();
+                addl(new AMD64Address(rsp, 0), 0); // Assert the lock# signal here
+            }
+        }
+    }
+
+    @Override
+    protected final void patchJumpTarget(int branch, int branchTarget) {
+        int op = getByte(branch);
+        assert op == 0xE8 // call
+                        ||
+                        op == 0x00 // jump table entry
+                        || op == 0xE9 // jmp
+                        || op == 0xEB // short jmp
+                        || (op & 0xF0) == 0x70 // short jcc
+                        || op == 0x0F && (getByte(branch + 1) & 0xF0) == 0x80 // jcc
+        : "Invalid opcode at patch point branch=" + branch + ", branchTarget=" + branchTarget + ", op=" + op;
+
+        if (op == 0x00) {
+            int offsetToJumpTableBase = getShort(branch + 1);
+            int jumpTableBase = branch - offsetToJumpTableBase;
+            int imm32 = branchTarget - jumpTableBase;
+            emitInt(imm32, branch);
+        } else if (op == 0xEB || (op & 0xF0) == 0x70) {
+
+            // short offset operators (jmp and jcc)
+            final int imm8 = branchTarget - (branch + 2);
+            /*
+             * Since a wrongly patched short branch can potentially lead to working but really bad
+             * behaving code we should always fail with an exception instead of having an assert.
+             */
+            if (!NumUtil.isByte(imm8)) {
+                throw new InternalError("branch displacement out of range: " + imm8);
+            }
+            emitByte(imm8, branch + 1);
+
+        } else {
+
+            int off = 1;
+            if (op == 0x0F) {
+                off = 2;
+            }
+
+            int imm32 = branchTarget - (branch + 4 + off);
+            emitInt(imm32, branch + off);
+        }
+    }
+
+    public void nullCheck(AMD64Address address) {
+        testl(AMD64.rax, address);
+    }
+
+    @Override
+    public void align(int modulus) {
+        if (position() % modulus != 0) {
+            nop(modulus - (position() % modulus));
+        }
+    }
+
+    /**
+     * Emits a direct call instruction. Note that the actual call target is not specified, because
+     * all calls need patching anyway. Therefore, 0 is emitted as the call target, and the user is
+     * responsible to add the call address to the appropriate patching tables.
+     */
+    public final void call() {
+        if (codePatchingAnnotationConsumer != null) {
+            int pos = position();
+            codePatchingAnnotationConsumer.accept(new ImmediateOperandAnnotation(pos, pos + 1, 4, pos + 5));
+        }
+        emitByte(0xE8);
+        emitInt(0);
+    }
+
+    public final void call(Register src) {
+        int encode = prefixAndEncode(src.encoding);
+        emitByte(0xFF);
+        emitByte(0xD0 | encode);
+    }
+
+    public final void int3() {
+        emitByte(0xCC);
+    }
+
+    public final void pause() {
+        emitByte(0xF3);
+        emitByte(0x90);
+    }
+
+    private void emitx87(int b1, int b2, int i) {
+        assert 0 <= i && i < 8 : "illegal stack offset";
+        emitByte(b1);
+        emitByte(b2 + i);
+    }
+
+    public final void fldd(AMD64Address src) {
+        emitByte(0xDD);
+        emitOperandHelper(0, src, 0);
+    }
+
+    public final void flds(AMD64Address src) {
+        emitByte(0xD9);
+        emitOperandHelper(0, src, 0);
+    }
+
+    public final void fldln2() {
+        emitByte(0xD9);
+        emitByte(0xED);
+    }
+
+    public final void fldlg2() {
+        emitByte(0xD9);
+        emitByte(0xEC);
+    }
+
+    public final void fyl2x() {
+        emitByte(0xD9);
+        emitByte(0xF1);
+    }
+
+    public final void fstps(AMD64Address src) {
+        emitByte(0xD9);
+        emitOperandHelper(3, src, 0);
+    }
+
+    public final void fstpd(AMD64Address src) {
+        emitByte(0xDD);
+        emitOperandHelper(3, src, 0);
+    }
+
+    private void emitFPUArith(int b1, int b2, int i) {
+        assert 0 <= i && i < 8 : "illegal FPU register: " + i;
+        emitByte(b1);
+        emitByte(b2 + i);
+    }
+
+    public void ffree(int i) {
+        emitFPUArith(0xDD, 0xC0, i);
+    }
+
+    public void fincstp() {
+        emitByte(0xD9);
+        emitByte(0xF7);
+    }
+
+    public void fxch(int i) {
+        emitFPUArith(0xD9, 0xC8, i);
+    }
+
+    public void fnstswAX() {
+        emitByte(0xDF);
+        emitByte(0xE0);
+    }
+
+    public void fwait() {
+        emitByte(0x9B);
+    }
+
+    public void fprem() {
+        emitByte(0xD9);
+        emitByte(0xF8);
+    }
+
+    public final void fsin() {
+        emitByte(0xD9);
+        emitByte(0xFE);
+    }
+
+    public final void fcos() {
+        emitByte(0xD9);
+        emitByte(0xFF);
+    }
+
+    public final void fptan() {
+        emitByte(0xD9);
+        emitByte(0xF2);
+    }
+
+    public final void fstp(int i) {
+        emitx87(0xDD, 0xD8, i);
+    }
+
+    @Override
+    public AMD64Address makeAddress(Register base, int displacement) {
+        return new AMD64Address(base, displacement);
+    }
+
+    @Override
+    public AMD64Address getPlaceholder(int instructionStartPosition) {
+        return new AMD64Address(rip, Register.None, Scale.Times1, 0, instructionStartPosition);
+    }
+
+    private void prefetchPrefix(AMD64Address src) {
+        prefix(src);
+        emitByte(0x0F);
+    }
+
+    public void prefetchnta(AMD64Address src) {
+        prefetchPrefix(src);
+        emitByte(0x18);
+        emitOperandHelper(0, src, 0);
+    }
+
+    void prefetchr(AMD64Address src) {
+        assert supports(CPUFeature.AMD_3DNOW_PREFETCH);
+        prefetchPrefix(src);
+        emitByte(0x0D);
+        emitOperandHelper(0, src, 0);
+    }
+
+    public void prefetcht0(AMD64Address src) {
+        assert supports(CPUFeature.SSE);
+        prefetchPrefix(src);
+        emitByte(0x18);
+        emitOperandHelper(1, src, 0);
+    }
+
+    public void prefetcht1(AMD64Address src) {
+        assert supports(CPUFeature.SSE);
+        prefetchPrefix(src);
+        emitByte(0x18);
+        emitOperandHelper(2, src, 0);
+    }
+
+    public void prefetcht2(AMD64Address src) {
+        assert supports(CPUFeature.SSE);
+        prefix(src);
+        emitByte(0x0f);
+        emitByte(0x18);
+        emitOperandHelper(3, src, 0);
+    }
+
+    public void prefetchw(AMD64Address src) {
+        assert supports(CPUFeature.AMD_3DNOW_PREFETCH);
+        prefix(src);
+        emitByte(0x0f);
+        emitByte(0x0D);
+        emitOperandHelper(1, src, 0);
+    }
+
+    public void rdtsc() {
+        emitByte(0x0F);
+        emitByte(0x31);
+    }
+
+    /**
+     * Emits an instruction which is considered to be illegal. This is used if we deliberately want
+     * to crash the program (debugging etc.).
+     */
+    public void illegal() {
+        emitByte(0x0f);
+        emitByte(0x0b);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64InstructionAttr.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64InstructionAttr.java
new file mode 100644
index 0000000..7dba7d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64InstructionAttr.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Attributes for instructions for SSE through EVEX, also including address components.
+ */
+public class AMD64InstructionAttr {
+    AMD64InstructionAttr(
+                    int inVectorLen,
+                    boolean inRexVexW,
+                    boolean inLegacyMode,
+                    boolean inNoRegMask,
+                    boolean inUsesVl,
+                    TargetDescription target) {
+        avxVectorLen = inVectorLen;
+        rexVexW = inRexVexW;
+        this.target = target;
+        legacyMode = (!supports(CPUFeature.AVX512F)) ? true : inLegacyMode;
+        noRegMask = inNoRegMask;
+        usesVl = inUsesVl;
+        rexVexWReverted = false;
+        tupleType = 0;
+        inputSizeInBits = 0;
+        isEvexInstruction = false;
+        evexEncoding = 0;
+        isClearContext = false;
+        isExtendedContext = false;
+    }
+
+    private TargetDescription target;
+    private int avxVectorLen;
+    private boolean rexVexW;
+    private boolean rexVexWReverted;
+    private boolean legacyMode;
+    private boolean noRegMask;
+    private boolean usesVl;
+    private int tupleType;
+    private int inputSizeInBits;
+    private boolean isEvexInstruction;
+    private int evexEncoding;
+    private boolean isClearContext;
+    private boolean isExtendedContext;
+
+    public int getVectorLen() {
+        return avxVectorLen;
+    }
+
+    public boolean isRexVexW() {
+        return rexVexW;
+    }
+
+    public boolean isRexVexWReverted() {
+        return rexVexWReverted;
+    }
+
+    public boolean isLegacyMode() {
+        return legacyMode;
+    }
+
+    public boolean isNoRegMask() {
+        return noRegMask;
+    }
+
+    public boolean usesVl() {
+        return usesVl;
+    }
+
+    public int getTupleType() {
+        return tupleType;
+    }
+
+    public int getInputSize() {
+        return inputSizeInBits;
+    }
+
+    public boolean isEvexInstruction() {
+        return isEvexInstruction;
+    }
+
+    public int getEvexEncoding() {
+        return evexEncoding;
+    }
+
+    public boolean isClearContext() {
+        return isClearContext;
+    }
+
+    public boolean isExtendedContext() {
+        return isExtendedContext;
+    }
+
+    /**
+     * Set the vector length of a given instruction.
+     *
+     * @param vectorLen
+     */
+    public void setVectorLen(int vectorLen) {
+        avxVectorLen = vectorLen;
+    }
+
+    /**
+     * In EVEX it is possible in blended code generation to revert the encoding width for AVX.
+     */
+    public void setRexVexWReverted() {
+        rexVexWReverted = true;
+    }
+
+    /**
+     * Alter the current encoding width.
+     *
+     * @param state
+     */
+    public void setRexVexW(boolean state) {
+        rexVexW = state;
+    }
+
+    /**
+     * Alter the current instructions legacy mode. Blended code generation will use this.
+     */
+    public void setLegacyMode() {
+        legacyMode = true;
+    }
+
+    /**
+     * During emit or during definition of an instruction, mark if it is EVEX.
+     */
+    public void setIsEvexInstruction() {
+        isEvexInstruction = true;
+    }
+
+    /**
+     * Set the current encoding attributes to be used in address calculations for EVEX.
+     *
+     * @param value
+     */
+    public void setEvexEncoding(int value) {
+        evexEncoding = value;
+    }
+
+    /**
+     * Use clear context for this instruction in EVEX, defaults is merge(false).
+     */
+    public void setIsClearContext() {
+        isClearContext = true;
+    }
+
+    /**
+     * Set the address attributes for configuring displacement calculations in EVEX.
+     */
+    public void setAddressAttributes(int inTupleType, int inInputSizeInBits) {
+        if (supports(CPUFeature.AVX512F)) {
+            tupleType = inTupleType;
+            inputSizeInBits = inInputSizeInBits;
+        }
+    }
+
+    private boolean supports(CPUFeature feature) {
+        return ((AMD64) target.arch).getFeatures().contains(feature);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java
new file mode 100644
index 0000000..fc4f7e7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec;
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper;
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
+
+import org.graalvm.compiler.asm.NumUtil;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * This class implements commonly used X86 code patterns.
+ */
+public class AMD64MacroAssembler extends AMD64Assembler {
+
+    public AMD64MacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    public final void decrementq(Register reg, int value) {
+        if (value == Integer.MIN_VALUE) {
+            subq(reg, value);
+            return;
+        }
+        if (value < 0) {
+            incrementq(reg, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            decq(reg);
+        } else {
+            subq(reg, value);
+        }
+    }
+
+    public final void decrementq(AMD64Address dst, int value) {
+        if (value == Integer.MIN_VALUE) {
+            subq(dst, value);
+            return;
+        }
+        if (value < 0) {
+            incrementq(dst, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            decq(dst);
+        } else {
+            subq(dst, value);
+        }
+    }
+
+    public void incrementq(Register reg, int value) {
+        if (value == Integer.MIN_VALUE) {
+            addq(reg, value);
+            return;
+        }
+        if (value < 0) {
+            decrementq(reg, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            incq(reg);
+        } else {
+            addq(reg, value);
+        }
+    }
+
+    public final void incrementq(AMD64Address dst, int value) {
+        if (value == Integer.MIN_VALUE) {
+            addq(dst, value);
+            return;
+        }
+        if (value < 0) {
+            decrementq(dst, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            incq(dst);
+        } else {
+            addq(dst, value);
+        }
+    }
+
+    public final void movptr(Register dst, AMD64Address src) {
+        movq(dst, src);
+    }
+
+    public final void movptr(AMD64Address dst, Register src) {
+        movq(dst, src);
+    }
+
+    public final void movptr(AMD64Address dst, int src) {
+        movslq(dst, src);
+    }
+
+    public final void cmpptr(Register src1, Register src2) {
+        cmpq(src1, src2);
+    }
+
+    public final void cmpptr(Register src1, AMD64Address src2) {
+        cmpq(src1, src2);
+    }
+
+    public final void decrementl(Register reg, int value) {
+        if (value == Integer.MIN_VALUE) {
+            subl(reg, value);
+            return;
+        }
+        if (value < 0) {
+            incrementl(reg, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            decl(reg);
+        } else {
+            subl(reg, value);
+        }
+    }
+
+    public final void decrementl(AMD64Address dst, int value) {
+        if (value == Integer.MIN_VALUE) {
+            subl(dst, value);
+            return;
+        }
+        if (value < 0) {
+            incrementl(dst, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            decl(dst);
+        } else {
+            subl(dst, value);
+        }
+    }
+
+    public final void incrementl(Register reg, int value) {
+        if (value == Integer.MIN_VALUE) {
+            addl(reg, value);
+            return;
+        }
+        if (value < 0) {
+            decrementl(reg, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            incl(reg);
+        } else {
+            addl(reg, value);
+        }
+    }
+
+    public final void incrementl(AMD64Address dst, int value) {
+        if (value == Integer.MIN_VALUE) {
+            addl(dst, value);
+            return;
+        }
+        if (value < 0) {
+            decrementl(dst, -value);
+            return;
+        }
+        if (value == 0) {
+            return;
+        }
+        if (value == 1 && UseIncDec) {
+            incl(dst);
+        } else {
+            addl(dst, value);
+        }
+    }
+
+    public void movflt(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        if (UseXmmRegToRegMoveAll) {
+            movaps(dst, src);
+        } else {
+            movss(dst, src);
+        }
+    }
+
+    public void movflt(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        movss(dst, src);
+    }
+
+    public void movflt(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.XMM);
+        movss(dst, src);
+    }
+
+    public void movdbl(Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
+        if (UseXmmRegToRegMoveAll) {
+            movapd(dst, src);
+        } else {
+            movsd(dst, src);
+        }
+    }
+
+    public void movdbl(Register dst, AMD64Address src) {
+        assert dst.getRegisterCategory().equals(AMD64.XMM);
+        if (UseXmmLoadAndClearUpper) {
+            movsd(dst, src);
+        } else {
+            movlpd(dst, src);
+        }
+    }
+
+    public void movdbl(AMD64Address dst, Register src) {
+        assert src.getRegisterCategory().equals(AMD64.XMM);
+        movsd(dst, src);
+    }
+
+    /**
+     * Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a
+     * volatile field!
+     */
+    public final void movlong(AMD64Address dst, long src) {
+        if (NumUtil.isInt(src)) {
+            AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src);
+        } else {
+            AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
+            movl(dst, (int) (src & 0xFFFFFFFF));
+            movl(high, (int) (src >> 32));
+        }
+
+    }
+
+    public final void flog(Register dest, Register value, boolean base10) {
+        if (base10) {
+            fldlg2();
+        } else {
+            fldln2();
+        }
+        AMD64Address tmp = trigPrologue(value);
+        fyl2x();
+        trigEpilogue(dest, tmp);
+    }
+
+    public final void fsin(Register dest, Register value) {
+        AMD64Address tmp = trigPrologue(value);
+        fsin();
+        trigEpilogue(dest, tmp);
+    }
+
+    public final void fcos(Register dest, Register value) {
+        AMD64Address tmp = trigPrologue(value);
+        fcos();
+        trigEpilogue(dest, tmp);
+    }
+
+    public final void ftan(Register dest, Register value) {
+        AMD64Address tmp = trigPrologue(value);
+        fptan();
+        fstp(0); // ftan pushes 1.0 in addition to the actual result, pop
+        trigEpilogue(dest, tmp);
+    }
+
+    public final void fpop() {
+        ffree(0);
+        fincstp();
+    }
+
+    private AMD64Address trigPrologue(Register value) {
+        assert value.getRegisterCategory().equals(AMD64.XMM);
+        AMD64Address tmp = new AMD64Address(AMD64.rsp);
+        subq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
+        movdbl(tmp, value);
+        fldd(tmp);
+        return tmp;
+    }
+
+    private void trigEpilogue(Register dest, AMD64Address tmp) {
+        assert dest.getRegisterCategory().equals(AMD64.XMM);
+        fstpd(tmp);
+        movdbl(dest, tmp);
+        addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java
new file mode 100644
index 0000000..313c2dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.BitSpec;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CompositeBitSpec;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ContinousBitSpec;
+
+public class BitSpecTest {
+
+    private static final BitSpec d4hi = new ContinousBitSpec(23, 20, true, "d4hi");
+    private static final BitSpec d4lo = new ContinousBitSpec(7, 4, false, "d4lo");
+    private static final BitSpec d8 = new CompositeBitSpec(d4hi, d4lo);
+
+    @Test
+    public void testContinousSignExtend() {
+        testSetGet(d4hi, 0x00700000, 0x00000007);
+        testSetGet(d4hi, 0x00800000, 0xFFFFFFF8);
+    }
+
+    @Test
+    public void testContinousZeroExtend() {
+        testSetGet(d4lo, 0x000000F0, 0x0000000F);
+        testSetGet(d4lo, 0x00000070, 0x00000007);
+    }
+
+    public void testSetGet(BitSpec bs, int encoded, int decoded) {
+        assertTrue(bs.valueFits(decoded));
+        assertEquals(encoded, bs.setBits(0, decoded));
+        assertEquals(decoded, bs.getBits(encoded));
+    }
+
+    @Test
+    public void testContinousSignExtendValueFits() {
+        assertFalse(d4hi.valueFits(0xf));
+        assertFalse(d4hi.valueFits(0x10));
+        assertFalse(d4hi.valueFits(0x17));
+    }
+
+    @Test
+    public void testContinousZeroExtendValueFits() {
+        assertFalse(d4lo.valueFits(0x10));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testContinousSignExtendSetFail1() {
+        d4hi.setBits(0, 0xf);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testContinousSignExtendSetFail2() {
+        d4hi.setBits(0, 0xFFFFFFF0);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testContinousZeroExtendSetFail1() {
+        d4lo.setBits(0, 0x10);
+    }
+
+    @Test
+    public void testCompositeSignExtended() {
+        testSetGet(d8, 0x00f000c0, 0xfffffffc);
+        testSetGet(d8, 0x008000c0, 0xffffff8c);
+        testSetGet(d8, 0x007000c0, 0x7c);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testCompositeSignExtendedFail1() {
+        d8.setBits(0, 0x00000080);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testCompositeSignExtendedFail2() {
+        d8.setBits(0, 0xEFFFFF80);
+    }
+
+    @Test
+    public void testCompositeValueFits() {
+        assertTrue(d8.valueFits(0xfffffffc));
+        assertTrue(d8.valueFits(0xffffff8c));
+        assertTrue(d8.valueFits(0x7c));
+        assertFalse(d8.valueFits(0x8c));
+        assertFalse(d8.valueFits(0xEFFFFF80));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java
new file mode 100644
index 0000000..2ead9f2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc.test;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BR;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.CarryClear;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
+import static jdk.vm.ci.sparc.SPARC.g0;
+
+import java.util.EnumSet;
+import java.util.function.Consumer;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.sparc.SPARC;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ControlTransferOp;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.SPARCOp;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.test.GraalTest;
+
+public class SPARCAssemblerTest extends GraalTest {
+    private SPARCMacroAssembler masm;
+
+    private static EnumSet<SPARC.CPUFeature> computeFeatures() {
+        EnumSet<SPARC.CPUFeature> features = EnumSet.noneOf(SPARC.CPUFeature.class);
+        features.add(SPARC.CPUFeature.CBCOND);
+        return features;
+    }
+
+    private static TargetDescription createTarget() {
+        final int stackFrameAlignment = 16;
+        final int implicitNullCheckLimit = 4096;
+        final boolean inlineObjects = true;
+        Architecture arch = new SPARC(computeFeatures());
+        return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+    }
+
+    @Before
+    public void setup() {
+        TargetDescription target = createTarget();
+        masm = new SPARCMacroAssembler(target);
+    }
+
+    @Test
+    public void testPatchCbcod() {
+        testControlTransferOp(l -> CBCOND.emit(masm, CarryClear, false, g0, 3, l), -512, 511);
+    }
+
+    @Test
+    public void testPatchBpcc() {
+        int maxDisp = 1 << 18;
+        testControlTransferOp(l -> BPCC.emit(masm, Xcc, Equal, ANNUL, PREDICT_NOT_TAKEN, l), -maxDisp,
+                        maxDisp - 1);
+    }
+
+    @Test
+    public void testPatchBpr() {
+        int maxDisp = 1 << 15;
+        testControlTransferOp(l -> BPR.emit(masm, Rc_z, ANNUL, PREDICT_NOT_TAKEN, g0, l), -maxDisp,
+                        maxDisp - 1);
+    }
+
+    @Test
+    public void testPatchBr() {
+        int maxDisp = 1 << 21;
+        testControlTransferOp(l -> BR.emit(masm, Equal, ANNUL, l), -maxDisp,
+                        maxDisp - 1);
+    }
+
+    @Test(expected = BailoutException.class)
+    public void testControlTransferInvalidDisp() {
+        int cbcondInstruction = 0x12f83f60;
+        CBCOND.setDisp(cbcondInstruction, 0x2ff);
+    }
+
+    public void testControlTransferOp(Consumer<Label> opCreator, int minDisp, int maxDisp) {
+        doTestControlTransferOp(opCreator, minDisp, maxDisp);
+        try {
+            doTestControlTransferOp(opCreator, minDisp - 1, maxDisp);
+            fail("minDisp out of bound must not assemble correctly");
+        } catch (BailoutException e) {
+            // ignored
+        }
+        try {
+            doTestControlTransferOp(opCreator, minDisp, maxDisp + 1);
+            fail("maxDisp out of bound must not assemble correctly");
+        } catch (BailoutException e) {
+            // ignored
+        }
+    }
+
+    /**
+     * Assembles the control transfer op and then verifies the expected disp value against the disp
+     * field provided by the disassembler.
+     */
+    public void doTestControlTransferOp(Consumer<Label> opCreator, int minDisp, int maxDisp) {
+        Label lBack = new Label();
+        Label lForward = new Label();
+        masm.bind(lBack);
+        for (int i = 0; i < -minDisp; i++) {
+            masm.nop();
+        }
+        int backPos = masm.position();
+        opCreator.accept(lBack);
+        masm.nop(); // Nop required to separate the two control transfer instructions
+        int forwardPos = masm.position();
+        opCreator.accept(lForward);
+        for (int i = 0; i < maxDisp - 1; i++) {
+            masm.nop();
+        }
+        masm.bind(lForward);
+
+        int condBack = masm.getInt(backPos);
+        SPARCOp backOp = SPARCAssembler.getSPARCOp(condBack);
+        int dispBack = ((ControlTransferOp) backOp).getDisp(condBack);
+        Assert.assertEquals(minDisp, dispBack);
+
+        int condFwd = masm.getInt(forwardPos);
+        SPARCOp fwdOp = SPARCAssembler.getSPARCOp(condFwd);
+        int dispFwd = ((ControlTransferOp) fwdOp).getDisp(condFwd);
+        Assert.assertEquals(maxDisp, dispFwd);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAddress.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAddress.java
new file mode 100644
index 0000000..58cf095
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAddress.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.STACK_BIAS;
+import static jdk.vm.ci.sparc.SPARC.fp;
+import static jdk.vm.ci.sparc.SPARC.sp;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.sparc.SPARC;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+
+public class SPARCAddress extends AbstractAddress {
+
+    private final Register base;
+    private final Register index;
+    private final int displacement;
+
+    /**
+     * Creates an {@link SPARCAddress} with given base register, no scaling and a given
+     * displacement.
+     *
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public SPARCAddress(Register base, int displacement) {
+        this.base = base;
+        this.index = Register.None;
+        this.displacement = displacement;
+    }
+
+    /**
+     * Creates an {@link SPARCAddress} with given base register, no scaling and a given index.
+     *
+     * @param base the base register
+     * @param index the index register
+     */
+    public SPARCAddress(Register base, Register index) {
+        this.base = base;
+        this.index = index;
+        this.displacement = 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("[");
+        String sep = "";
+        if (!getBase().equals(Register.None)) {
+            s.append(getBase());
+            sep = " + ";
+        }
+        if (!getIndex().equals(Register.None)) {
+            s.append(sep).append(getIndex());
+            sep = " + ";
+        } else {
+            if (getDisplacement() < 0) {
+                s.append(" - ").append(-getDisplacement());
+            } else if (getDisplacement() > 0) {
+                s.append(sep).append(getDisplacement());
+            }
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Register#None}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Index register, the value of which is added to {@link #getBase}. If not present, is
+     *         denoted by {@link Register#None}.
+     */
+    public Register getIndex() {
+        return index;
+    }
+
+    /**
+     * @return true if this address has an index register
+     */
+    public boolean hasIndex() {
+        return !getIndex().equals(Register.None);
+    }
+
+    /**
+     * This method adds the stack-bias to the displacement if the base register is either
+     * {@link SPARC#sp} or {@link SPARC#fp}.
+     *
+     * @return Optional additive displacement.
+     */
+    public int getDisplacement() {
+        if (hasIndex()) {
+            throw new InternalError("address has index register");
+        }
+        // TODO Should we also hide the register save area size here?
+        if (getBase().equals(sp) || getBase().equals(fp)) {
+            return displacement + STACK_BIAS;
+        }
+        return displacement;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java
new file mode 100644
index 0000000..68cde9d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java
@@ -0,0 +1,2694 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andn;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andncc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Casa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Casxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Flushw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Fpop1;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Fpop2;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Impdep1;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Jmpl;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lddf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsb;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsh;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldub;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduh;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduwa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Membar;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Movcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Or;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Popc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Prefetch;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Rd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Restore;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Save;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sll;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srlx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stb;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stdf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sth;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Wr;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xor;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xorcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fabsd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fabss;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdivd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdivs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtoi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmovd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmovs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fpadd32;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsmuld;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsqrtd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsqrts;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsrc2d;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsrc2s;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstoi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsubd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsubs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fzerod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fzeros;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movdtox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movstosw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movwtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movxtod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Ops.ArithOp;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Ops.LdstOp;
+import static java.lang.String.format;
+import static jdk.vm.ci.sparc.SPARC.CPU;
+import static jdk.vm.ci.sparc.SPARC.FPUd;
+import static jdk.vm.ci.sparc.SPARC.FPUs;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.g2;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.g7;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * This class implements an assembler that can encode most SPARC instructions.
+ */
+public abstract class SPARCAssembler extends Assembler {
+
+    /**
+     * Constructs an assembler for the SPARC architecture.
+     */
+    public SPARCAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    /**
+     * Size of an SPARC assembler instruction in Bytes.
+     */
+    public static final int INSTRUCTION_SIZE = 4;
+
+    /**
+     * Size in bytes which are cleared by stxa %g0, [%rd] ASI_ST_BLKINIT_PRIMARY.
+     */
+    public static final int BLOCK_ZERO_LENGTH = 64;
+
+    public static final int CCR_ICC_SHIFT = 0;
+    public static final int CCR_XCC_SHIFT = 4;
+    public static final int CCR_V_SHIFT = 1;
+
+    public static final int MEMBAR_LOAD_LOAD = 1;
+    public static final int MEMBAR_STORE_LOAD = 2;
+    public static final int MEMBAR_LOAD_STORE = 3;
+    public static final int MEMBAR_STORE_STORE = 4;
+
+    private static final Ops[] OPS;
+    private static final Op2s[] OP2S;
+    private static final Op3s[][] OP3S;
+
+    private ArrayList<Integer> delaySlotOptimizationPoints = new ArrayList<>(5);
+
+    static {
+        Ops[] ops = Ops.values();
+        OPS = new Ops[ops.length];
+        for (Ops op : ops) {
+            OPS[op.value] = op;
+        }
+        Op2s[] op2s = Op2s.values();
+        OP2S = new Op2s[op2s.length];
+        for (Op2s op2 : op2s) {
+            OP2S[op2.value] = op2;
+        }
+        OP3S = new Op3s[2][64];
+        for (Op3s op3 : Op3s.values()) {
+            if (op3.value >= 1 << 6) {
+                throw new RuntimeException("Error " + op3 + " " + op3.value);
+            }
+            OP3S[op3.op.value & 1][op3.value] = op3;
+        }
+    }
+
+    public enum Ops {
+        // @formatter:off
+        BranchOp(0b00),
+        CallOp(0b01),
+        ArithOp(0b10),
+        LdstOp(0b11);
+        // @formatter:on
+
+        private final int value;
+
+        Ops(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public boolean appliesTo(int instructionWord) {
+            int opShift = 30;
+            return (instructionWord >>> opShift) == value;
+        }
+    }
+
+    public enum Op2s {
+        // Checkstyle: stop
+        // @formatter:off
+        Illtrap(0b000),
+        Bpr    (0b011),
+        Fb     (0b110),
+        Fbp    (0b101),
+        Br     (0b010),
+        Bp     (0b001),
+        Cb     (0b111),
+        Sethi  (0b100);
+        // @formatter:on
+        // Checkstyle: resume
+
+        private final int value;
+
+        Op2s(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Op2s byValue(int value) {
+            return OP2S[value];
+        }
+    }
+
+    private static final int COMMUTATIVE = 1;
+    private static final int BINARY = 2;
+    private static final int UNARY = 4;
+    private static final int VOID_IN = 8;
+
+    public enum Op3s {
+        // Checkstyle: stop
+        // @formatter:off
+        Add(0x00, "add", ArithOp, BINARY | COMMUTATIVE),
+        And(0x01, "and", ArithOp, BINARY | COMMUTATIVE),
+        Or(0x02, "or", ArithOp, BINARY | COMMUTATIVE),
+        Xor(0x03, "xor", ArithOp, BINARY | COMMUTATIVE),
+        Sub(0x04, "sub", ArithOp, BINARY),
+        Andn(0x05, "andn", ArithOp, BINARY | COMMUTATIVE),
+        Orn(0x06, "orn", ArithOp, BINARY | COMMUTATIVE),
+        Xnor(0x07, "xnor", ArithOp, BINARY | COMMUTATIVE),
+        Addc(0x08, "addc", ArithOp, BINARY | COMMUTATIVE),
+        Mulx(0x09, "mulx", ArithOp, BINARY | COMMUTATIVE),
+        Umul(0x0A, "umul", ArithOp, BINARY | COMMUTATIVE),
+        Smul(0x0B, "smul", ArithOp, BINARY | COMMUTATIVE),
+        Subc(0x0C, "subc", ArithOp, BINARY),
+        Udivx(0x0D, "udivx", ArithOp, BINARY),
+        Udiv(0x0E, "udiv", ArithOp, BINARY),
+        Sdiv(0x0F, "sdiv", ArithOp, BINARY),
+
+        Addcc(0x10, "addcc", ArithOp, BINARY | COMMUTATIVE),
+        Andcc(0x11, "andcc", ArithOp, BINARY | COMMUTATIVE),
+        Orcc(0x12, "orcc", ArithOp, BINARY | COMMUTATIVE),
+        Xorcc(0x13, "xorcc", ArithOp, BINARY | COMMUTATIVE),
+        Subcc(0x14, "subcc", ArithOp, BINARY),
+        Andncc(0x15, "andncc", ArithOp, BINARY | COMMUTATIVE),
+        Orncc(0x16, "orncc", ArithOp, BINARY | COMMUTATIVE),
+        Xnorcc(0x17, "xnorcc", ArithOp, BINARY | COMMUTATIVE),
+        Addccc(0x18, "addccc", ArithOp, BINARY | COMMUTATIVE),
+
+        Umulcc(0x1A, "umulcc", ArithOp, BINARY | COMMUTATIVE),
+        Smulcc(0x1B, "smulcc", ArithOp, BINARY | COMMUTATIVE),
+        Subccc(0x1C, "subccc", ArithOp, BINARY),
+        Udivcc(0x1E, "udivcc", ArithOp, BINARY),
+        Sdivcc(0x1F, "sdivcc", ArithOp, BINARY),
+
+        Mulscc(0x24, "mulscc", ArithOp, BINARY | COMMUTATIVE),
+        Sll(0x25, "sll", ArithOp, BINARY),
+        Sllx(0x25, "sllx", ArithOp, BINARY),
+        Srl(0x26, "srl", ArithOp, BINARY),
+        Srlx(0x26, "srlx", ArithOp, BINARY),
+        Sra(0x27, "srax", ArithOp, BINARY),
+        Srax(0x27, "srax", ArithOp, BINARY),
+        Membar(0x28, "membar", ArithOp),
+
+        Flushw(0x2B, "flushw", ArithOp),
+        Movcc(0x2C, "movcc", ArithOp),
+        Sdivx(0x2D, "sdivx", ArithOp, BINARY),
+        Popc(0x2E, "popc", ArithOp, UNARY),
+        Movr(0x2F, "movr", ArithOp, BINARY),
+
+        Fpop1(0b11_0100, "fpop1", ArithOp),
+        Fpop2(0b11_0101, "fpop2", ArithOp),
+        Impdep1(0b11_0110, "impdep1", ArithOp),
+        Impdep2(0b11_0111, "impdep2", ArithOp),
+        Jmpl(0x38, "jmpl", ArithOp),
+        Rett(0x39, "rett", ArithOp),
+        Trap(0x3a, "trap", ArithOp),
+        Flush(0x3b, "flush", ArithOp),
+        Save(0x3c, "save", ArithOp),
+        Restore(0x3d, "restore", ArithOp),
+        Retry(0x3e, "retry", ArithOp),
+
+
+        Casa(0b111100, "casa", LdstOp),
+        Casxa(0b111110, "casxa", LdstOp),
+        Prefetch(0b101101, "prefetch", LdstOp),
+        Prefetcha(0b111101, "prefetcha", LdstOp),
+
+        Lduw  (0b00_0000, "lduw", LdstOp),
+        Ldub  (0b00_0001, "ldub", LdstOp),
+        Lduh  (0b00_0010, "lduh", LdstOp),
+        Stw   (0b00_0100, "stw", LdstOp),
+        Stb   (0b00_0101, "stb", LdstOp),
+        Sth   (0b00_0110, "sth", LdstOp),
+        Ldsw  (0b00_1000, "ldsw", LdstOp),
+        Ldsb  (0b00_1001, "ldsb", LdstOp),
+        Ldsh  (0b00_1010, "ldsh", LdstOp),
+        Ldx   (0b00_1011, "ldx", LdstOp),
+        Stx   (0b00_1110, "stx", LdstOp),
+
+        Ldf   (0b10_0000, "ldf", LdstOp),
+        Ldfsr (0b10_0001, "ldfsr", LdstOp),
+        Ldaf  (0b10_0010, "ldaf", LdstOp),
+        Lddf  (0b10_0011, "lddf", LdstOp),
+        Stf   (0b10_0100, "stf", LdstOp),
+        Stfsr (0b10_0101, "stfsr", LdstOp),
+        Staf  (0b10_0110, "staf", LdstOp),
+        Stdf  (0b10_0111, "stdf", LdstOp),
+
+        Stba  (0b01_0101, "stba", LdstOp),
+        Stha  (0b01_0110, "stha", LdstOp),
+        Stwa  (0b01_0100, "stwa", LdstOp),
+        Stxa  (0b01_1110, "stxa", LdstOp),
+
+        Ldsba  (0b01_1001, "ldsba", LdstOp),
+        Ldsha  (0b01_1010, "ldsha", LdstOp),
+        Ldswa  (0b01_1000, "ldswa", LdstOp),
+        Lduba  (0b01_0001, "lduba", LdstOp),
+        Lduha  (0b01_0010, "lduha", LdstOp),
+        Lduwa (0b01_0000, "lduwa", LdstOp),
+
+        Ldxa  (0b01_1011, "ldxa", LdstOp),
+
+        Rd    (0b10_1000, "rd", ArithOp),
+        Wr    (0b11_0000, "wr", ArithOp),
+
+        Tcc(0b11_1010, "tcc", ArithOp);
+
+        // @formatter:on
+        // Checkstyle: resume
+
+        private final int value;
+        private final String operator;
+        private final Ops op;
+        private final int flags;
+
+        Op3s(int value, String name, Ops op) {
+            this(value, name, op, 0);
+        }
+
+        Op3s(int value, String name, Ops op, int flags) {
+            this.value = value;
+            this.operator = name;
+            this.op = op;
+            this.flags = flags;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public boolean throwsException() {
+            if (op == LdstOp) {
+                return true;
+            }
+            switch (this) {
+                case Udiv:
+                case Udivx:
+                case Sdiv:
+                case Sdivx:
+                case Udivcc:
+                case Sdivcc:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public boolean isBinary() {
+            return (flags & BINARY) != 0;
+        }
+
+        public boolean isUnary() {
+            return (flags & UNARY) != 0;
+        }
+
+        public boolean isCommutative() {
+            return (flags & COMMUTATIVE) != 0;
+        }
+    }
+
+    public enum Opfs {
+        // @formatter:off
+
+        Fmovs(0b0_0000_0001, "fmovs", Fpop1, UNARY),
+        Fmovd(0b0_0000_0010, "fmovd", Fpop1, UNARY),
+        Fmovq(0b0_0000_0011, "fmovq", Fpop1, UNARY),
+        Fnegs(0x05, "fnegs", Fpop1, UNARY),
+        Fnegd(0x06, "fnegd", Fpop1, UNARY),
+        Fnegq(0x07, "fnegq", Fpop1, UNARY),
+        Fabss(0x09, "fabss", Fpop1, UNARY),
+        Fabsd(0x0A, "fabsd", Fpop1, UNARY),
+        Fabsq(0x0B, "fabsq", Fpop1, UNARY),
+
+        // start VIS1
+        Fpadd32(0x52, "fpadd32", Impdep1, BINARY | COMMUTATIVE),
+        Fzerod(0x60, "fzerod", Impdep1, VOID_IN),
+        Fzeros(0x61, "fzeros", Impdep1, VOID_IN),
+        Fsrc2d(0x78, "fsrc2d", Impdep1, UNARY),
+        Fsrc2s(0x79, "fsrc2s", Impdep1, UNARY),
+        // end VIS1
+
+        // start VIS3
+        Movdtox(0x110, "movdtox", Impdep1, UNARY),
+        Movstouw(0x111, "movstouw", Impdep1, UNARY),
+        Movstosw(0x113, "movstosw", Impdep1, UNARY),
+        Movxtod(0x118, "movxtod", Impdep1, UNARY),
+        Movwtos(0b1_0001_1001, "movwtos", Impdep1, UNARY),
+        UMulxhi(0b0_0001_0110, "umulxhi", Impdep1, BINARY | COMMUTATIVE),
+        // end VIS3
+
+        Fadds(0x41, "fadds", Fpop1, BINARY | COMMUTATIVE),
+        Faddd(0x42, "faddd", Fpop1, BINARY | COMMUTATIVE),
+        Fsubs(0x45, "fsubs", Fpop1, BINARY),
+        Fsubd(0x46, "fsubd", Fpop1, BINARY),
+        Fmuls(0x49, "fmuls", Fpop1, BINARY | COMMUTATIVE),
+        Fmuld(0x4A, "fmuld", Fpop1, BINARY | COMMUTATIVE),
+        Fdivs(0x4D, "fdivs", Fpop1, BINARY),
+        Fdivd(0x4E, "fdivd", Fpop1, BINARY),
+
+        Fsqrts(0x29, "fsqrts", Fpop1, UNARY),
+        Fsqrtd(0x2A, "fsqrtd", Fpop1, UNARY),
+
+        Fsmuld(0x69, "fsmuld", Fpop1, BINARY | COMMUTATIVE),
+
+        Fstoi(0xD1, "fstoi", Fpop1, UNARY),
+        Fdtoi(0xD2, "fdtoi", Fpop1, UNARY),
+        Fstox(0x81, "fstox", Fpop1, UNARY),
+        Fdtox(0x82, "fdtox", Fpop1, UNARY),
+        Fxtos(0x84, "fxtos", Fpop1, UNARY),
+        Fxtod(0x88, "fxtod", Fpop1, UNARY),
+        Fitos(0xC4, "fitos", Fpop1, UNARY),
+        Fdtos(0xC6, "fdtos", Fpop1, UNARY),
+        Fitod(0xC8, "fitod", Fpop1, UNARY),
+        Fstod(0xC9, "fstod", Fpop1, UNARY),
+
+
+        Fcmps(0x51, "fcmps", Fpop2, BINARY),
+        Fcmpd(0x52, "fcmpd", Fpop2, BINARY);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private final Op3s op3;
+        private final int flags;
+
+        Opfs(int value, String op, Op3s op3, int flags) {
+            this.value = value;
+            this.operator = op;
+            this.op3 = op3;
+            this.flags = flags;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public boolean isBinary() {
+            return (flags & BINARY) != 0;
+        }
+
+        public boolean isUnary() {
+            return (flags & UNARY) != 0;
+        }
+
+        public boolean isCommutative() {
+            return (flags & COMMUTATIVE) != 0;
+        }
+    }
+
+    public enum OpfLow {
+        Fmovscc(0b00_0001, "fmovscc", Fpop2),
+        Fmovdcc(0b00_0010, "fmovdcc", Fpop2);
+
+        private final int value;
+        private final String operator;
+        private final Op3s op3;
+
+        OpfLow(int value, String op, Op3s op3) {
+            this.value = value;
+            this.operator = op;
+            this.op3 = op3;
+        }
+
+        @Override
+        public String toString() {
+            return operator;
+        }
+    }
+
+    public enum Annul {
+        ANNUL(1),
+        NOT_ANNUL(0);
+        public final int flag;
+
+        Annul(int flag) {
+            this.flag = flag;
+        }
+    }
+
+    public enum BranchPredict {
+        PREDICT_TAKEN(1),
+        PREDICT_NOT_TAKEN(0);
+        public final int flag;
+
+        BranchPredict(int flag) {
+            this.flag = flag;
+        }
+    }
+
+    public enum MembarMask {
+        // @formatter:off
+
+        StoreStore(1 << 3, "storestore"),
+        LoadStore(1 << 2, "loadstore"),
+        StoreLoad(1 << 1, "storeload"),
+        LoadLoad(1 << 0, "loadload"),
+        Sync(1 << 6, "sync"),
+        MemIssue(1 << 5, "memissue"),
+        LookAside(1 << 4, "lookaside");
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+
+        MembarMask(int value, String op) {
+            this.value = value;
+            this.operator = op;
+        }
+
+        public int getValue() {
+            return value | 0x2000;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    /**
+     * Condition Codes to use for instruction.
+     */
+    public enum CC {
+        // @formatter:off
+        /**
+         * Condition is considered as 32bit operation condition.
+         */
+        Icc(0b00, "icc", false),
+        /**
+         * Condition is considered as 64bit operation condition.
+         */
+        Xcc(0b10, "xcc", false),
+        Fcc0(0b00, "fcc0", true),
+        Fcc1(0b01, "fcc1", true),
+        Fcc2(0b10, "fcc2", true),
+        Fcc3(0b11, "fcc3", true);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private boolean isFloat;
+
+        CC(int value, String op, boolean isFloat) {
+            this.value = value;
+            this.operator = op;
+            this.isFloat = isFloat;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public static CC forKind(PlatformKind kind) {
+            if (kind.equals(SPARCKind.XWORD)) {
+                return Xcc;
+            } else if (kind.equals(SPARCKind.WORD)) {
+                return Icc;
+            } else if (kind.equals(SPARCKind.SINGLE) || kind.equals(SPARCKind.DOUBLE)) {
+                return Fcc0;
+            } else {
+                throw new IllegalArgumentException("Unknown kind: " + kind);
+            }
+        }
+    }
+
+    public enum ConditionFlag {
+        // @formatter:off
+
+        // for FBfcc & FBPfcc instruction
+        F_Never(0, "f_never"),
+        F_NotEqual(1, "f_notEqual"),
+        F_LessOrGreater(2, "f_lessOrGreater"),
+        F_UnorderedOrLess(3, "f_unorderedOrLess"),
+        F_Less(4, "f_less"),
+        F_UnorderedOrGreater(5, "f_unorderedOrGreater"),
+        F_Greater(6, "f_greater"),
+        F_Unordered(7, "f_unordered"),
+        F_Always(8, "f_always"),
+        F_Equal(9, "f_equal"),
+        F_UnorderedOrEqual(10, "f_unorderedOrEqual"),
+        F_GreaterOrEqual(11, "f_greaterOrEqual"),
+        F_UnorderedGreaterOrEqual(12, "f_unorderedGreaterOrEqual"),
+        F_LessOrEqual(13, "f_lessOrEqual"),
+        F_UnorderedOrLessOrEqual(14, "f_unorderedOrLessOrEqual"),
+        F_Ordered(15, "f_ordered"),
+
+        // for integers
+        Never(0, "never"),
+        Equal(1, "equal", true),
+        Zero(1, "zero"),
+        LessEqual(2, "lessEqual", true),
+        Less(3, "less", true),
+        LessEqualUnsigned(4, "lessEqualUnsigned", true),
+        LessUnsigned(5, "lessUnsigned", true),
+        CarrySet(5, "carrySet"),
+        Negative(6, "negative", true),
+        OverflowSet(7, "overflowSet", true),
+        Always(8, "always"),
+        NotEqual(9, "notEqual", true),
+        NotZero(9, "notZero"),
+        Greater(10, "greater", true),
+        GreaterEqual(11, "greaterEqual", true),
+        GreaterUnsigned(12, "greaterUnsigned", true),
+        GreaterEqualUnsigned(13, "greaterEqualUnsigned", true),
+        CarryClear(13, "carryClear"),
+        Positive(14, "positive", true),
+        OverflowClear(15, "overflowClear", true);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private boolean forCBcond = false;
+
+        ConditionFlag(int value, String op) {
+            this(value, op, false);
+        }
+
+        ConditionFlag(int value, String op, boolean cbcond) {
+            this.value = value;
+            this.operator = op;
+            this.forCBcond = cbcond;
+        }
+
+        public boolean isCBCond() {
+            return forCBcond;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public ConditionFlag negate() {
+            //@formatter:off
+            switch (this) {
+                case F_Never                  : return F_Always;
+                case F_Always                 : return F_Never;
+                case F_NotEqual               : return F_Equal;
+                case F_Equal                  : return F_NotEqual;
+                case F_LessOrGreater          : return F_UnorderedOrEqual;
+                case F_UnorderedOrEqual       : return F_LessOrGreater;
+                case F_Less                   : return F_UnorderedGreaterOrEqual;
+                case F_UnorderedGreaterOrEqual: return F_Less;
+                case F_LessOrEqual            : return F_UnorderedOrGreater;
+                case F_UnorderedOrGreater     : return F_LessOrEqual;
+                case F_Greater                : return F_UnorderedOrLessOrEqual;
+                case F_UnorderedOrLessOrEqual : return F_Greater;
+                case F_GreaterOrEqual         : return F_UnorderedOrLess;
+                case F_UnorderedOrLess        : return F_GreaterOrEqual;
+                case F_Unordered              : return F_Ordered;
+                case F_Ordered                : return F_Unordered;
+                case Never                    : return Always;
+                case Always                   : return Never;
+                case Equal                    : return NotEqual;
+                case NotEqual                 : return Equal;
+                case Zero                     : return NotZero;
+                case NotZero                  : return Zero;
+                case LessEqual                : return Greater;
+                case Greater                  : return LessEqual;
+                case Less                     : return GreaterEqual;
+                case GreaterEqual             : return Less;
+                case LessEqualUnsigned        : return GreaterUnsigned;
+                case GreaterUnsigned          : return LessEqualUnsigned;
+                case LessUnsigned             : return GreaterEqualUnsigned;
+                case GreaterEqualUnsigned     : return LessUnsigned;
+                case CarrySet                 : return CarryClear;
+                case CarryClear               : return CarrySet;
+                case Negative                 : return Positive;
+                case Positive                 : return Negative;
+                case OverflowSet              : return OverflowClear;
+                case OverflowClear            : return OverflowSet;
+                default:
+                    throw new InternalError();
+            }
+            //@formatter:on
+        }
+
+        public ConditionFlag mirror() {
+            switch (this) {
+            //@formatter:off
+                case F_Less                   : return F_Greater;
+                case F_Greater                : return F_Less;
+                case F_LessOrEqual            : return F_GreaterOrEqual;
+                case F_UnorderedGreaterOrEqual: return F_UnorderedOrLessOrEqual;
+                case F_UnorderedOrGreater     : return F_UnorderedOrLess;
+                case F_UnorderedOrLessOrEqual : return F_UnorderedGreaterOrEqual;
+                case F_GreaterOrEqual         : return F_LessOrEqual;
+                case F_UnorderedOrLess        : return F_UnorderedOrGreater;
+                case LessEqual                : return GreaterEqual;
+                case Greater                  : return Less;
+                case Less                     : return Greater;
+                case GreaterEqual             : return LessEqual;
+                case LessEqualUnsigned        : return GreaterEqualUnsigned;
+                case GreaterUnsigned          : return LessUnsigned;
+                case LessUnsigned             : return GreaterUnsigned;
+                case GreaterEqualUnsigned     : return LessEqualUnsigned;
+                default:
+                    return this;
+                //@formatter:on
+            }
+        }
+
+    }
+
+    public enum RCondition {
+        // @formatter:off
+
+        Rc_z(0b001, "rc_z"),
+        Rc_lez(0b010, "rc_lez"),
+        Rc_lz(0b011, "rc_lz"),
+        Rc_nz(0b101, "rc_nz"),
+        Rc_gz(0b110, "rc_gz"),
+        Rc_gez(0b111, "rc_gez"),
+        Rc_last(Rc_gez.getValue(), "rc_last");
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+
+        RCondition(int value, String op) {
+            this.value = value;
+            this.operator = op;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    /**
+     * Represents the <b>Address Space Identifier</b> defined in the SPARC architecture.
+     */
+    public enum Asi {
+        // @formatter:off
+
+        INVALID(-1),
+        ASI_PRIMARY(0x80),
+        ASI_PRIMARY_NOFAULT(0x82),
+        ASI_PRIMARY_LITTLE(0x88),
+        // Block initializing store
+        ASI_ST_BLKINIT_PRIMARY(0xE2),
+        // Most-Recently-Used (MRU) BIS variant
+        ASI_ST_BLKINIT_MRU_PRIMARY(0xF2);
+
+        // @formatter:on
+
+        private final int value;
+
+        Asi(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public boolean isValid() {
+            return value != INVALID.getValue();
+        }
+    }
+
+    public enum Fcn {
+        SeveralWritesAndPossiblyReads(2),
+        SeveralReadsWeak(0),
+        OneRead(1),
+        OneWrite(3),
+        Page(4),
+        NearestUnifiedCache(17),
+        SeveralReadsStrong(20),
+        OneReadStrong(21),
+        SeveralWritesAndPossiblyReadsStrong(22),
+        OneWriteStrong(23);
+
+        private final int value;
+
+        Fcn(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * Specifies various bit fields used in SPARC instructions.
+     */
+    @SuppressWarnings("unused")
+    public abstract static class BitSpec {
+        private static final BitSpec op = new ContinousBitSpec(31, 30, "op");
+        private static final BitSpec op2 = new ContinousBitSpec(24, 22, "op2");
+        private static final BitSpec op3 = new ContinousBitSpec(24, 19, "op3");
+        private static final BitSpec opf = new ContinousBitSpec(13, 5, "opf");
+        private static final BitSpec opfLow = new ContinousBitSpec(10, 5, "opfLow");
+        private static final BitSpec opfCC = new ContinousBitSpec(13, 11, "opfCC");
+        private static final BitSpec opfCond = new ContinousBitSpec(17, 14, "opfCond");
+        private static final BitSpec rd = new ContinousBitSpec(29, 25, "rd");
+        private static final BitSpec rs1 = new ContinousBitSpec(18, 14, "rs1");
+        private static final BitSpec rs2 = new ContinousBitSpec(4, 0, "rs2");
+        private static final BitSpec simm13 = new ContinousBitSpec(12, 0, true, "simm13");
+        private static final BitSpec shcnt32 = new ContinousBitSpec(4, 0, "shcnt32");
+        private static final BitSpec shcnt64 = new ContinousBitSpec(5, 0, "shcnt64");
+        private static final BitSpec imm22 = new ContinousBitSpec(21, 0, "imm22");
+        private static final BitSpec immAsi = new ContinousBitSpec(12, 5, "immASI");
+        private static final BitSpec i = new ContinousBitSpec(13, 13, "i");
+        private static final BitSpec disp19 = new ContinousBitSpec(18, 0, true, "disp19");
+        private static final BitSpec disp22 = new ContinousBitSpec(21, 0, true, "disp22");
+        private static final BitSpec disp30 = new ContinousBitSpec(29, 0, true, "disp30");
+        private static final BitSpec a = new ContinousBitSpec(29, 29, "a");
+        private static final BitSpec p = new ContinousBitSpec(19, 19, "p");
+        private static final BitSpec x = new ContinousBitSpec(12, 12, "x");
+        private static final BitSpec cond = new ContinousBitSpec(28, 25, "cond");
+        private static final BitSpec rcond = new ContinousBitSpec(27, 25, "rcond");
+        private static final BitSpec cc = new ContinousBitSpec(21, 20, "cc");
+        private static final BitSpec fcc = new ContinousBitSpec(26, 25, "cc");
+        private static final BitSpec d16lo = new ContinousBitSpec(13, 0, "d16lo");
+        private static final BitSpec d16hi = new ContinousBitSpec(21, 20, true, "d16hi");
+        private static final BitSpec d16 = new CompositeBitSpec(d16hi, d16lo);
+        // Movcc
+        private static final BitSpec movccLo = new ContinousBitSpec(12, 11, "cc_lo");
+        private static final BitSpec movccHi = new ContinousBitSpec(18, 18, "cc_hi");
+        private static final BitSpec movccCond = new ContinousBitSpec(17, 14, "cond");
+        private static final BitSpec simm11 = new ContinousBitSpec(10, 0, true, "simm11");
+
+        // CBCond
+        private static final BitSpec cLo = new ContinousBitSpec(27, 25, "cLo");
+        private static final BitSpec cHi = new ContinousBitSpec(29, 29, "cHi");
+        private static final BitSpec c = new CompositeBitSpec(cHi, cLo);
+        private static final BitSpec cbcond = new ContinousBitSpec(28, 28, "cbcond");
+        private static final BitSpec cc2 = new ContinousBitSpec(21, 21, "cc2");
+        private static final BitSpec d10Lo = new ContinousBitSpec(12, 5, "d10Lo");
+        private static final BitSpec d10Hi = new ContinousBitSpec(20, 19, true, "d10Hi");
+        private static final BitSpec d10 = new CompositeBitSpec(d10Hi, d10Lo);
+        private static final BitSpec simm5 = new ContinousBitSpec(4, 0, true, "simm5");
+
+        protected final boolean signExtend;
+
+        public BitSpec(boolean signExtend) {
+            super();
+            this.signExtend = signExtend;
+        }
+
+        public final boolean isSignExtend() {
+            return signExtend;
+        }
+
+        public abstract int setBits(int word, int value);
+
+        public abstract int getBits(int word);
+
+        public abstract int getWidth();
+
+        public abstract boolean valueFits(int value);
+    }
+
+    public static final class ContinousBitSpec extends BitSpec {
+        private final int hiBit;
+        private final int lowBit;
+        private final int width;
+        private final int mask;
+        private final String name;
+
+        public ContinousBitSpec(int hiBit, int lowBit, String name) {
+            this(hiBit, lowBit, false, name);
+        }
+
+        public ContinousBitSpec(int hiBit, int lowBit, boolean signExt, String name) {
+            super(signExt);
+            this.hiBit = hiBit;
+            this.lowBit = lowBit;
+            this.width = hiBit - lowBit + 1;
+            mask = ((1 << width) - 1) << lowBit;
+            this.name = name;
+        }
+
+        @Override
+        public int setBits(int word, int value) {
+            assert valueFits(value) : String.format("Value 0x%x for field %s does not fit.", value, this);
+            return (word & ~mask) | ((value << lowBit) & mask);
+        }
+
+        @Override
+        public int getBits(int word) {
+            if (signExtend) {
+                return ((word & mask) << (31 - hiBit)) >> (32 - width);
+            } else {
+                return (word & mask) >>> lowBit;
+            }
+        }
+
+        @Override
+        public int getWidth() {
+            return width;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s [%d:%d]", name, hiBit, lowBit);
+        }
+
+        @Override
+        public boolean valueFits(int value) {
+            if (signExtend) {
+                return isSimm(value, getWidth());
+            } else {
+                return isImm(value, getWidth());
+            }
+        }
+    }
+
+    public static final class CompositeBitSpec extends BitSpec {
+        private final BitSpec left;
+        private final int leftWidth;
+        private final BitSpec right;
+        private final int rightWidth;
+        private final int width;
+
+        public CompositeBitSpec(BitSpec left, BitSpec right) {
+            super(left.isSignExtend());
+            assert !right.isSignExtend() : String.format("Right field %s must not be sign extended", right);
+            this.left = left;
+            this.leftWidth = left.getWidth();
+            this.right = right;
+            this.rightWidth = right.getWidth();
+            this.width = leftWidth + rightWidth;
+        }
+
+        @Override
+        public int getBits(int word) {
+            int l = left.getBits(word);
+            int r = right.getBits(word);
+            return (l << rightWidth) | r;
+        }
+
+        @Override
+        public int setBits(int word, int value) {
+            int l = leftBits(value);
+            int r = rightBits(value);
+            return left.setBits(right.setBits(word, r), l);
+        }
+
+        private int leftBits(int value) {
+            return getBits(value, width - 1, rightWidth, signExtend);
+        }
+
+        private int rightBits(int value) {
+            return getBits(value, rightWidth - 1, 0, false);
+        }
+
+        @Override
+        public int getWidth() {
+            return width;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("CompositeBitSpec[%s, %s]", left, right);
+        }
+
+        @Override
+        public boolean valueFits(int value) {
+            int l = leftBits(value);
+            int r = rightBits(value);
+            return left.valueFits(l) && right.valueFits(r);
+        }
+
+        private static int getBits(int inst, int hiBit, int lowBit, boolean signExtended) {
+            int shifted = inst >> lowBit;
+            if (signExtended) {
+                return shifted;
+            } else {
+                return shifted & ((1 << (hiBit - lowBit + 1)) - 1);
+            }
+        }
+    }
+
+    public static class BitKey {
+        private final BitSpec spec;
+        private final int value;
+
+        public BitKey(BitSpec spec, int value) {
+            super();
+            this.spec = spec;
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("BitKey %s=%s", spec, value);
+        }
+    }
+
+    /**
+     * Represents a prefix tree of {@link BitSpec} objects to find the most accurate SPARCOp.
+     */
+    public static final class BitKeyIndex {
+        private final BitSpec spec;
+        private final Map<Integer, BitKeyIndex> nodes;
+        private SPARCOp op;
+
+        public BitKeyIndex(SPARCOp op) {
+            assert op != null;
+            this.op = op;
+            this.nodes = null;
+            this.spec = null;
+        }
+
+        public BitKeyIndex(BitSpec spec) {
+            assert spec != null;
+            this.op = null;
+            this.nodes = new HashMap<>(4);
+            this.spec = spec;
+        }
+
+        /**
+         * Adds operation to the index.
+         *
+         * @param keys Ordered by the importance
+         * @param operation Operation represented by this list of keys
+         */
+        private void addOp(List<BitKey[]> keys, SPARCOp operation) {
+            assert keys.size() > 0;
+            BitKey[] firstKeys = keys.get(0);
+            for (BitKey first : firstKeys) {
+                assert first.spec.equals(spec) : first.spec + " " + spec;
+                BitKeyIndex node;
+                if (keys.size() == 1) {
+                    if (nodes.containsKey(first.value)) {
+                        node = nodes.get(first.value);
+                        assert node.op == null : node + " " + keys;
+                        node.op = operation;
+                    } else {
+                        assert !nodes.containsKey(first.value) : "Index must be unique. Existing key: " + nodes.get(first.value);
+                        node = new BitKeyIndex(operation);
+                    }
+                } else {
+                    node = nodes.get(first.value);
+                    BitKey[] next = keys.get(1);
+                    if (node == null) {
+                        for (int i = 1; i < next.length; i++) {
+                            assert next[i - 1].spec.equals(next[i].spec) : "All spec on this node must equal";
+                        }
+                        node = new BitKeyIndex(next[0].spec);
+                    }
+                    node.addOp(keys.subList(1, keys.size()), operation);
+                }
+                nodes.put(first.value, node);
+            }
+        }
+
+        /**
+         * Finds the best matching {@link SPARCOp} for this instruction.
+         */
+        public SPARCOp find(int inst) {
+            if (nodes != null) {
+                int key = spec.getBits(inst);
+                BitKeyIndex sub = nodes.get(key);
+                if (sub == null) {
+                    if (op != null) {
+                        return op;
+                    } else {
+                        throw new RuntimeException(String.format("%s 0x%x, 0x%x %s", spec, inst, key, nodes));
+                    }
+                }
+                return sub.find(inst);
+            } else {
+                return this.op;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return this.op == null ? this.spec + ": " + this.nodes : this.op.toString();
+        }
+    }
+
+    public static final Bpcc BPCC = new Bpcc(Op2s.Bp);
+    public static final Bpcc FBPCC = new Bpcc(Op2s.Fbp);
+    public static final CBCond CBCOND = new CBCond();
+    public static final Bpr BPR = new Bpr();
+    public static final Br BR = new Br();
+    public static final Sethi SETHI = new Sethi();
+    public static final FMOVcc FMOVSCC = new FMOVcc(OpfLow.Fmovscc);
+    public static final FMOVcc FMOVDCC = new FMOVcc(OpfLow.Fmovdcc);
+    public static final MOVicc MOVicc = new MOVicc();
+    public static final OpfOp OPF = new OpfOp();
+    public static final Op3Op OP3 = new Op3Op();
+    public static final SPARCOp LDST = new SPARCOp(Ops.LdstOp);
+    public static final SPARCOp BRANCH = new SPARCOp(Ops.BranchOp);
+    public static final SPARCOp CALL = new SPARCOp(Ops.CallOp);
+    private static final BitKeyIndex INDEX = new BitKeyIndex(BitSpec.op);
+
+    static {
+        for (SPARCOp op : SPARCOp.OPS) {
+            INDEX.addOp(op.getKeys(), op);
+        }
+    }
+
+    public static SPARCOp getSPARCOp(int inst) {
+        return INDEX.find(inst);
+    }
+
+    /**
+     * Represents a class of SPARC instruction and gives methods to modify its fields.
+     */
+    public static class SPARCOp {
+        private final Ops op;
+        private final BitKey opKey;
+        private List<BitKey[]> keyFields;
+        private static final List<SPARCOp> OPS = new ArrayList<>();
+
+        public SPARCOp(Ops op) {
+            super();
+            this.op = op;
+            this.opKey = new BitKey(BitSpec.op, op.value);
+            OPS.add(this);
+        }
+
+        protected int setBits(int word) {
+            return BitSpec.op.setBits(word, op.value);
+        }
+
+        public boolean match(int inst) {
+            for (BitKey[] keys : keyFields) {
+                for (BitKey k : keys) {
+                    if (k.spec.getBits(inst) != k.value) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        protected List<BitKey[]> getKeys() {
+            if (keyFields == null) {
+                keyFields = new ArrayList<>(4);
+                keyFields.add(new BitKey[]{opKey});
+            }
+            return keyFields;
+        }
+
+        public Ops getOp(int inst) {
+            return SPARCAssembler.OPS[BitSpec.op.getBits(inst)];
+        }
+
+        @Override
+        public String toString() {
+            String name = getClass().getName();
+            name = name.substring(name.lastIndexOf(".") + 1);
+            return name + "[op: " + op + "]";
+        }
+    }
+
+    /**
+     * Base class for control transfer operations; provides access to the disp field.
+     */
+    public abstract static class ControlTransferOp extends SPARCOp {
+        private final Op2s op2;
+        private final boolean delaySlot;
+        private final BitSpec disp;
+        private final BitKey[] op2Key;
+
+        private ControlTransferOp(Ops op, Op2s op2, boolean delaySlot, BitSpec disp) {
+            super(op);
+            this.op2 = op2;
+            this.delaySlot = delaySlot;
+            this.disp = disp;
+            this.op2Key = new BitKey[]{new BitKey(BitSpec.op2, op2.value)};
+        }
+
+        public boolean hasDelaySlot() {
+            return delaySlot;
+        }
+
+        @Override
+        protected int setBits(int word) {
+            return BitSpec.op2.setBits(super.setBits(word), op2.value);
+        }
+
+        protected int setDisp(int inst, SPARCMacroAssembler masm, Label lab) {
+            if (lab.isBound()) {
+                int d = (lab.position() - masm.position()) / 4;
+                return setDisp(inst, d);
+            } else {
+                masm.patchUnbound(lab);
+                return inst;
+            }
+        }
+
+        public int setDisp(int inst, int d) {
+            assert this.match(inst);
+            if (!isValidDisp(d)) {
+                throw new PermanentBailoutException("Too large displacement 0x%x in field %s in instruction %s", d, this.disp, this);
+            }
+            return this.disp.setBits(inst, d);
+        }
+
+        public boolean isValidDisp(int d) {
+            return this.disp.valueFits(d);
+        }
+
+        public int setAnnul(int inst, boolean a) {
+            return BitSpec.a.setBits(inst, a ? 1 : 0);
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(op2Key);
+            return keys;
+        }
+
+        public int getDisp(int inst) {
+            return this.disp.getBits(inst);
+        }
+
+        public abstract boolean isAnnulable(int inst);
+
+        public abstract boolean isConditional(int inst);
+    }
+
+    public static final class Bpcc extends ControlTransferOp {
+        public Bpcc(Op2s op2) {
+            super(Ops.BranchOp, op2, true, BitSpec.disp19);
+        }
+
+        public void emit(SPARCMacroAssembler masm, CC cc, ConditionFlag cf, Annul annul, BranchPredict p, Label lab) {
+            int inst = setBits(0);
+            inst = BitSpec.a.setBits(inst, annul.flag);
+            inst = BitSpec.cond.setBits(inst, cf.value);
+            inst = BitSpec.cc.setBits(inst, cc.value);
+            inst = BitSpec.p.setBits(inst, p.flag);
+            masm.insertNopAfterCBCond();
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+    }
+
+    public static final class Br extends ControlTransferOp {
+        public Br() {
+            super(Ops.BranchOp, Op2s.Br, true, BitSpec.disp22);
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+
+        public void emit(SPARCMacroAssembler masm, ConditionFlag cond, Annul a, Label lab) {
+            int inst = setBits(0);
+            inst = BitSpec.cond.setBits(inst, cond.value);
+            inst = BitSpec.a.setBits(inst, a.flag);
+            masm.insertNopAfterCBCond();
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+    }
+
+    public static final class Bpr extends ControlTransferOp {
+        private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 0);
+
+        public Bpr() {
+            super(Ops.BranchOp, Op2s.Bpr, true, BitSpec.d16);
+        }
+
+        public void emit(SPARCMacroAssembler masm, RCondition rcond, Annul a, BranchPredict p, Register rs1, Label lab) {
+            int inst = setBits(0);
+            inst = BitSpec.rcond.setBits(inst, rcond.value);
+            inst = BitSpec.a.setBits(inst, a.flag);
+            inst = BitSpec.p.setBits(inst, p.flag);
+            inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+            masm.insertNopAfterCBCond();
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(new BitKey[]{CBCOND_KEY});
+            return keys;
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return isConditional(inst);
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            int cond = BitSpec.cond.getBits(inst);
+            return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+        }
+    }
+
+    public static final class CBCond extends ControlTransferOp {
+        private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 1);
+
+        private CBCond() {
+            super(Ops.BranchOp, Op2s.Bpr, false, BitSpec.d10);
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(new BitKey[]{CBCOND_KEY});
+            return keys;
+        }
+
+        public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, Register rs2, Label lab) {
+            int inst = setBits(0, cf, cc2, rs1);
+            inst = BitSpec.rs2.setBits(inst, rs2.encoding);
+            inst = BitSpec.i.setBits(inst, 0);
+            masm.insertNopAfterCBCond();
+            emit(masm, lab, inst);
+        }
+
+        public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, int simm5, Label lab) {
+            int inst = setBits(0, cf, cc2, rs1);
+            inst = BitSpec.simm5.setBits(inst, simm5);
+            inst = BitSpec.i.setBits(inst, 1);
+            emit(masm, lab, inst);
+        }
+
+        private void emit(SPARCMacroAssembler masm, Label lab, int baseInst) {
+            int inst = baseInst;
+            masm.insertNopAfterCBCond();
+            masm.emitInt(setDisp(inst, masm, lab));
+        }
+
+        private int setBits(int base, ConditionFlag cf, boolean cc2, Register rs1) {
+            int inst = super.setBits(base);
+            inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+            inst = BitSpec.cc2.setBits(inst, cc2 ? 1 : 0);
+            inst = BitSpec.c.setBits(inst, cf.value);
+            return BitSpec.cbcond.setBits(inst, 1);
+        }
+
+        @Override
+        public boolean isAnnulable(int inst) {
+            return false;
+        }
+
+        @Override
+        public boolean isConditional(int inst) {
+            return true;
+        }
+    }
+
+    public static class Op2Op extends SPARCOp {
+        private final Op2s op2;
+        private final BitKey op2Key;
+
+        public Op2Op(Ops op, Op2s op2) {
+            super(op);
+            this.op2 = op2;
+            op2Key = new BitKey(BitSpec.op2, op2.value);
+        }
+
+        @Override
+        protected int setBits(int word) {
+            int result = super.setBits(word);
+            return BitSpec.op2.setBits(result, op2.value);
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(new BitKey[]{op2Key});
+            return keys;
+        }
+    }
+
+    public static final class Sethi extends Op2Op {
+        public Sethi() {
+            super(Ops.BranchOp, Op2s.Sethi);
+        }
+
+        public static Register getRS1(int word) {
+            int regNum = BitSpec.rs1.getBits(word);
+            return SPARC.cpuRegisters.get(regNum);
+        }
+
+        public static int getImm22(int word) {
+            return BitSpec.imm22.getBits(word);
+        }
+
+        public static boolean isNop(int inst) {
+            return getRS1(inst).equals(g0) && getImm22(inst) == 0;
+        }
+    }
+
+    public static final class Op3Op extends SPARCOp {
+        public Op3Op() {
+            super(ArithOp);
+        }
+
+        public Op3s getOp3(int inst) {
+            assert match(inst);
+            return OP3S[ArithOp.value & 1][BitSpec.op3.getBits(inst)];
+        }
+
+        public static void emit(SPARCMacroAssembler masm, Op3s opcode, Register rs1, Register rs2, Register rd) {
+            int instruction = setBits(0, opcode, rs1, rd);
+            instruction = BitSpec.rs2.setBits(instruction, rs2.encoding);
+            instruction = BitSpec.i.setBits(instruction, 0);
+            masm.emitInt(instruction);
+        }
+
+        public static void emit(SPARCMacroAssembler masm, Op3s opcode, Register rs1, int simm13, Register rd) {
+            int instruction = setBits(0, opcode, rs1, rd);
+            instruction = BitSpec.i.setBits(instruction, 1);
+            BitSpec immediateSpec;
+            switch (opcode) {
+                case Sllx:
+                case Srlx:
+                case Srax:
+                    immediateSpec = BitSpec.shcnt64;
+                    break;
+                case Sll:
+                case Srl:
+                case Sra:
+                    immediateSpec = BitSpec.shcnt32;
+                    break;
+                default:
+                    immediateSpec = BitSpec.simm13;
+                    break;
+            }
+            instruction = immediateSpec.setBits(instruction, simm13);
+            masm.emitInt(instruction);
+        }
+
+        private static int setBits(int instruction, Op3s op3, Register rs1, Register rd) {
+            assert op3.op.equals(ArithOp);
+            int tmp = BitSpec.op3.setBits(instruction, op3.value);
+            switch (op3) {
+                case Sllx:
+                case Srlx:
+                case Srax:
+                    tmp = BitSpec.x.setBits(tmp, 1);
+                    break;
+            }
+            tmp = BitSpec.op.setBits(tmp, op3.op.value);
+            tmp = BitSpec.rd.setBits(tmp, rd.encoding);
+            return BitSpec.rs1.setBits(tmp, rs1.encoding);
+        }
+    }
+
+    /**
+     * Used for interfacing FP and GP conditional move instructions.
+     */
+    public interface CMOV {
+        void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd);
+
+        void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd);
+    }
+
+    public static final class MOVicc extends SPARCOp implements CMOV {
+        private static final Op3s op3 = Movcc;
+
+        public MOVicc() {
+            super(ArithOp);
+        }
+
+        @Override
+        public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd) {
+            int inst = setBits(0, condition, cc, rd);
+            inst = BitSpec.rs2.setBits(inst, rs2.encoding());
+            masm.emitInt(inst);
+        }
+
+        @Override
+        public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd) {
+            int inst = setBits(0, condition, cc, rd);
+            inst = BitSpec.i.setBits(inst, 1);
+            inst = BitSpec.simm11.setBits(inst, simm11);
+            masm.emitInt(inst);
+        }
+
+        protected int setBits(int word, ConditionFlag condition, CC cc, Register rd) {
+            int inst = super.setBits(word);
+            inst = BitSpec.rd.setBits(inst, rd.encoding());
+            inst = BitSpec.op3.setBits(inst, op3.value);
+            inst = BitSpec.movccCond.setBits(inst, condition.value);
+            inst = BitSpec.movccLo.setBits(inst, cc.value);
+            return BitSpec.movccHi.setBits(inst, cc.isFloat ? 0 : 1);
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(new BitKey[]{new BitKey(BitSpec.op3, op3.value)});
+            return keys;
+        }
+    }
+
+    public static final class FMOVcc extends SPARCOp implements CMOV {
+        private OpfLow opfLow;
+
+        public FMOVcc(OpfLow opfLow) {
+            super(ArithOp);
+            this.opfLow = opfLow;
+        }
+
+        @Override
+        public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd) {
+            int inst = setBits(0);
+            inst = BitSpec.rd.setBits(inst, rd.encoding());
+            inst = BitSpec.op3.setBits(inst, opfLow.op3.value);
+            inst = BitSpec.opfCond.setBits(inst, condition.value);
+            inst = BitSpec.opfCC.setBits(inst, cc.value);
+            inst = BitSpec.opfLow.setBits(inst, opfLow.value);
+            inst = BitSpec.rs2.setBits(inst, rs2.encoding());
+            masm.emitInt(inst);
+        }
+
+        @Override
+        public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd) {
+            throw new IllegalArgumentException("FMOVCC cannot be used with immediate value");
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(new BitKey[]{new BitKey(BitSpec.op3, opfLow.op3.value)});
+            keys.add(new BitKey[]{new BitKey(BitSpec.opfLow, opfLow.value)});
+            return keys;
+        }
+    }
+
+    public static final class OpfOp extends SPARCOp {
+
+        private BitKey[] op3Keys;
+
+        public OpfOp(BitKey... op3Keys) {
+            super(ArithOp);
+            this.op3Keys = op3Keys;
+        }
+
+        public OpfOp() {
+            // @formatter:off
+            this(new BitKey[]{
+                            new BitKey(BitSpec.op3, Op3s.Fpop1.value),
+                            new BitKey(BitSpec.op3, Op3s.Fpop2.value),
+                            new BitKey(BitSpec.op3, Op3s.Impdep1.value),
+                            new BitKey(BitSpec.op3, Op3s.Impdep2.value)});
+            // @formatter:on
+        }
+
+        public static void emit(SPARCMacroAssembler masm, Opfs opf, Register rs1, Register rs2, Register rd) {
+            int instruction = setBits(0, opf, rs1, rs2);
+            instruction = BitSpec.rd.setBits(instruction, rd.encoding);
+            instruction = BitSpec.i.setBits(instruction, 0);
+            masm.emitInt(instruction);
+        }
+
+        public static void emitFcmp(SPARCMacroAssembler masm, Opfs opf, CC cc, Register rs1, Register rs2) {
+            assert opf.equals(Opfs.Fcmpd) || opf.equals(Opfs.Fcmps) : opf;
+            int instruction = setBits(0, opf, rs1, rs2);
+            instruction = BitSpec.fcc.setBits(instruction, cc.value);
+            masm.emitInt(instruction);
+        }
+
+        private static int setBits(int instruction, Opfs opf, Register rs1, Register rs2) {
+            int tmp = BitSpec.op.setBits(instruction, opf.op3.op.value);
+            tmp = BitSpec.op3.setBits(tmp, opf.op3.value);
+            tmp = BitSpec.opf.setBits(tmp, opf.value);
+            tmp = BitSpec.rs1.setBits(tmp, rs1.encoding);
+            return BitSpec.rs2.setBits(tmp, rs2.encoding);
+        }
+
+        @Override
+        protected List<BitKey[]> getKeys() {
+            List<BitKey[]> keys = super.getKeys();
+            keys.add(op3Keys);
+            // @formatter:on
+            return keys;
+        }
+    }
+
+    public static boolean isCPURegister(Register... regs) {
+        for (Register reg : regs) {
+            if (!isCPURegister(reg)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isCPURegister(Register r) {
+        return r.getRegisterCategory().equals(CPU);
+    }
+
+    public static boolean isGlobalRegister(Register r) {
+        return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number;
+    }
+
+    public static boolean isSingleFloatRegister(Register r) {
+        return r.getRegisterCategory().equals(FPUs);
+    }
+
+    public static boolean isDoubleFloatRegister(Register r) {
+        return r.getRegisterCategory().equals(FPUd);
+    }
+
+    public boolean hasFeature(CPUFeature feature) {
+        return ((SPARC) this.target.arch).features.contains(feature);
+    }
+
+    public static final int simm(int x, int nbits) {
+        // assert_signed_range(x, nbits);
+        return x & ((1 << nbits) - 1);
+    }
+
+    public static final boolean isImm(int x, int nbits) {
+        // assert_signed_range(x, nbits);
+        return simm(x, nbits) == x;
+    }
+
+    /**
+     * Minimum value for signed immediate ranges.
+     */
+    public static long minSimm(long nbits) {
+        return -(1L << (nbits - 1));
+    }
+
+    /**
+     * Maximum value for signed immediate ranges.
+     */
+    public static long maxSimm(long nbits) {
+        return (1L << (nbits - 1)) - 1;
+    }
+
+    /**
+     * Test if imm is within signed immediate range for nbits.
+     */
+    public static boolean isSimm(long imm, int nbits) {
+        return minSimm(nbits) <= imm && imm <= maxSimm(nbits);
+    }
+
+    public static boolean isSimm10(long imm) {
+        return isSimm(imm, 10);
+    }
+
+    public static boolean isSimm11(long imm) {
+        return isSimm(imm, 11);
+    }
+
+    public static boolean isSimm11(JavaConstant constant) {
+        return constant.isNull() || isSimm11(constant.asLong());
+    }
+
+    public static boolean isSimm5(JavaConstant constant) {
+        return constant.isNull() || isSimm(constant.asLong(), 5);
+    }
+
+    public static boolean isSimm13(int imm) {
+        return isSimm(imm, 13);
+    }
+
+    public static boolean isSimm13(JavaConstant constant) {
+        long bits;
+        switch (constant.getJavaKind()) {
+            case Double:
+                bits = Double.doubleToRawLongBits(constant.asDouble());
+                break;
+            case Float:
+                bits = Float.floatToRawIntBits(constant.asFloat());
+                break;
+            case Object:
+                return constant.isNull();
+            default:
+                bits = constant.asLong();
+                break;
+        }
+        return constant.isNull() || isSimm13(bits);
+    }
+
+    public static boolean isSimm13(long imm) {
+        return NumUtil.isInt(imm) && isSimm(imm, 13);
+    }
+
+    public static boolean isWordDisp30(long imm) {
+        return isSimm(imm, 30 + 2);
+    }
+
+    public static final int hi22(int x) {
+        return x >>> 10;
+    }
+
+    public static final int lo10(int x) {
+        return x & ((1 << 10) - 1);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for Fmt00 instructions. This abstraction is needed as it
+     * makes the patching easier later on.
+     * <pre>
+     * | 00  |    a   | op2 |               b                         |
+     * |31 30|29    25|24 22|21                                      0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt00(int a, int op2, int b) {
+        assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b);
+        int word = 0;
+        BitSpec.op.setBits(word, 0);
+        BitSpec.rd.setBits(word, a);
+        BitSpec.op2.setBits(word, op2);
+        BitSpec.imm22.setBits(word, b);
+        emitInt(a << 25 | op2 << 22 | b);
+    }
+
+    private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) {
+        int b = opf.value << 5 | (rs2 == null ? 0 : rs2.encoding);
+        fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b);
+    }
+
+    protected void op3(Op3s op3, Register rs1, Register rs2, Register rd) {
+        int b = rs2 == null ? 0 : rs2.encoding;
+        int xBit = getXBit(op3);
+        fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit);
+    }
+
+    protected void op3(Op3s op3, Register rs1, int simm13, Register rd) {
+        assert isSimm13(simm13) : simm13;
+        int i = 1 << 13;
+        int simm13WithX = simm13 | getXBit(op3);
+        fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1));
+    }
+
+    public void insertNopAfterCBCond() {
+        int pos = position() - INSTRUCTION_SIZE;
+        if (pos == 0) {
+            return;
+        }
+        int inst = getInt(pos);
+        if (CBCOND.match(inst)) {
+            nop();
+        }
+    }
+
+    protected int patchUnbound(Label label) {
+        label.addPatchAt(position());
+        return 0;
+    }
+
+    // @formatter:off
+    /**
+     * NOP.
+     * <pre>
+     * | 00  |00000| 100 |                0                    |
+     * |31 30|29 25|24 22|21                                  0|
+     * </pre>
+     */
+    // @formatter:on
+    public void nop() {
+        emitInt(1 << 24);
+    }
+
+    public void sethi(int imm22, Register dst) {
+        fmt00(dst.encoding, Op2s.Sethi.value, imm22);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for calls.
+     * <pre>
+     * | 01  |                      disp30                             |
+     * |31 30|29                                                      0|
+     * </pre>
+     *
+     * @return Position of the call instruction
+     */
+    // @formatter:on
+    public int call(int disp30) {
+        assert isImm(disp30, 30);
+        insertNopAfterCBCond();
+        int before = position();
+        int instr = 1 << 30;
+        instr |= disp30;
+        emitInt(instr);
+        return before;
+    }
+
+    public void add(Register rs1, Register rs2, Register rd) {
+        op3(Add, rs1, rs2, rd);
+    }
+
+    public void add(Register rs1, int simm13, Register rd) {
+        op3(Add, rs1, simm13, rd);
+    }
+
+    public void addc(Register rs1, Register rs2, Register rd) {
+        op3(Addc, rs1, rs2, rd);
+    }
+
+    public void addc(Register rs1, int simm13, Register rd) {
+        op3(Addc, rs1, simm13, rd);
+    }
+
+    public void addcc(Register rs1, Register rs2, Register rd) {
+        op3(Addcc, rs1, rs2, rd);
+    }
+
+    public void addcc(Register rs1, int simm13, Register rd) {
+        op3(Addcc, rs1, simm13, rd);
+    }
+
+    public void and(Register rs1, Register rs2, Register rd) {
+        op3(And, rs1, rs2, rd);
+    }
+
+    public void and(Register rs1, int simm13, Register rd) {
+        op3(And, rs1, simm13, rd);
+    }
+
+    public void andcc(Register rs1, Register rs2, Register rd) {
+        op3(Andcc, rs1, rs2, rd);
+    }
+
+    public void andcc(Register rs1, int simm13, Register rd) {
+        op3(Andcc, rs1, simm13, rd);
+    }
+
+    public void andn(Register rs1, Register rs2, Register rd) {
+        op3(Andn, rs1, rs2, rd);
+    }
+
+    public void andn(Register rs1, int simm13, Register rd) {
+        op3(Andn, rs1, simm13, rd);
+    }
+
+    public void andncc(Register rs1, Register rs2, Register rd) {
+        op3(Andncc, rs1, rs2, rd);
+    }
+
+    public void andncc(Register rs1, int simm13, Register rd) {
+        op3(Andncc, rs1, simm13, rd);
+    }
+
+    public void movwtos(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rd) && isCPURegister(rs2) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movwtos, null, rs2, rd);
+    }
+
+    public void umulxhi(Register rs1, Register rs2, Register rd) {
+        op3(Impdep1, UMulxhi, rs1, rs2, rd);
+    }
+
+    public void fdtos(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rd) && isDoubleFloatRegister(rs2) : String.format("%s %s", rs2, rd);
+        op3(Fpop1, Fdtos, null, rs2, rd);
+    }
+
+    public void movstouw(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movstosw, null, rs2, rd);
+    }
+
+    public void movstosw(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movstosw, null, rs2, rd);
+    }
+
+    public void movdtox(Register rs2, Register rd) {
+        assert isDoubleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movdtox, null, rs2, rd);
+    }
+
+    public void movxtod(Register rs2, Register rd) {
+        assert isCPURegister(rs2) && isDoubleFloatRegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movxtod, null, rs2, rd);
+    }
+
+    public void fadds(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fadds, rs1, rs2, rd);
+    }
+
+    public void faddd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Faddd, rs1, rs2, rd);
+    }
+
+    public void fdivs(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fdivs, rs1, rs2, rd);
+    }
+
+    public void fdivd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fdivd, rs1, rs2, rd);
+    }
+
+    public void fmovs(Register rs2, Register rd) {
+        op3(Fpop1, Fmovs, null, rs2, rd);
+    }
+
+    public void fmovd(Register rs2, Register rd) {
+        op3(Fpop1, Fmovd, null, rs2, rd);
+    }
+
+    public void fsrc2s(Register rs2, Register rd) {
+        op3(Impdep1, Fsrc2s, null, rs2, rd);
+    }
+
+    public void fsrc2d(Register rs2, Register rd) {
+        op3(Impdep1, Fsrc2d, null, rs2, rd);
+    }
+
+    public void fmuls(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fmuls, rs1, rs2, rd);
+    }
+
+    public void fsmuld(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsmuld, rs1, rs2, rd);
+    }
+
+    public void fmuld(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fmuld, rs1, rs2, rd);
+    }
+
+    public void fnegs(Register rs2, Register rd) {
+        op3(Fpop1, Fnegs, null, rs2, rd);
+    }
+
+    public void fnegd(Register rs2, Register rd) {
+        op3(Fpop1, Fnegd, null, rs2, rd);
+    }
+
+    /**
+     * Helper method to determine if the instruction needs the X bit set.
+     */
+    private static int getXBit(Op3s op3) {
+        switch (op3) {
+            case Sllx:
+            case Srax:
+            case Srlx:
+                return 1 << 12;
+            default:
+                return 0;
+        }
+    }
+
+    public void fstoi(Register rs2, Register rd) {
+        op3(Fpop1, Fstoi, null, rs2, rd);
+    }
+
+    public void fstox(Register rs2, Register rd) {
+        op3(Fpop1, Fstox, null, rs2, rd);
+    }
+
+    public void fdtox(Register rs2, Register rd) {
+        op3(Fpop1, Fdtox, null, rs2, rd);
+    }
+
+    public void fstod(Register rs2, Register rd) {
+        op3(Fpop1, Fstod, null, rs2, rd);
+    }
+
+    public void fdtoi(Register rs2, Register rd) {
+        op3(Fpop1, Fdtoi, null, rs2, rd);
+    }
+
+    public void fitos(Register rs2, Register rd) {
+        op3(Fpop1, Fitos, null, rs2, rd);
+    }
+
+    public void fitod(Register rs2, Register rd) {
+        op3(Fpop1, Fitod, null, rs2, rd);
+    }
+
+    public void fxtos(Register rs2, Register rd) {
+        op3(Fpop1, Fxtos, null, rs2, rd);
+    }
+
+    public void fxtod(Register rs2, Register rd) {
+        op3(Fpop1, Fxtod, null, rs2, rd);
+    }
+
+    public void fzeros(Register rd) {
+        op3(Impdep1, Fzeros, null, null, rd);
+    }
+
+    public void fzerod(Register rd) {
+        op3(Impdep1, Fzerod, null, null, rd);
+    }
+
+    public void flushw() {
+        op3(Flushw, g0, g0, g0);
+    }
+
+    public void fsqrtd(Register rs2, Register rd) {
+        op3(Fpop1, Fsqrtd, null, rs2, rd);
+    }
+
+    public void fsqrts(Register rs2, Register rd) {
+        op3(Fpop1, Fsqrts, null, rs2, rd);
+    }
+
+    public void fabss(Register rs2, Register rd) {
+        op3(Fpop1, Fabss, null, rs2, rd);
+    }
+
+    public void fabsd(Register rs2, Register rd) {
+        op3(Fpop1, Fabsd, null, rs2, rd);
+    }
+
+    public void fsubs(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsubs, rs1, rs2, rd);
+    }
+
+    public void fsubd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsubd, rs1, rs2, rd);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for fcmp.
+     * <pre>
+     * | 10  | --- |cc1|cc0|desc |   rs1   |   opf  | rs2 |
+     * |31 30|29 27|26 |25 |24 19|18     14|13     5|4   0|
+     * </pre>
+     */
+    // @formatter:on
+    public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) {
+        int a = cc.value;
+        int b = opf.value << 5 | rs2.encoding;
+        delaySlotOptimizationPoints.add(position());
+        fmt10(a, Fpop2.value, rs1.encoding, b);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for most arithmetic stuff.
+     * <pre>
+     * |  10 | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt10(int rd, int op3, int rs1, int b) {
+        fmt(0b10, rd, op3, rs1, b);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for most arithmetic stuff.
+     * <pre>
+     * |  op | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt(int op, int rd, int op3, int rs1, int b) {
+        assert isImm(rd, 5) && isImm(op3, 6) && isImm(b, 14) : String.format("rd: 0x%x op3: 0x%x b: 0x%x", rd, op3, b);
+        int instr = op << 30 | rd << 25 | op3 << 19 | rs1 << 14 | b;
+        emitInt(instr);
+    }
+
+    public void illtrap(int const22) {
+        fmt00(0, Op2s.Illtrap.value, const22);
+    }
+
+    public void jmpl(Register rs1, Register rs2, Register rd) {
+        insertNopAfterCBCond();
+        op3(Jmpl, rs1, rs2, rd);
+    }
+
+    /**
+     * @return Position of the jmpl instruction
+     */
+    public int jmpl(Register rs1, int simm13, Register rd) {
+        insertNopAfterCBCond();
+        int before = position();
+        op3(Jmpl, rs1, simm13, rd);
+        return before;
+    }
+
+    public void fmovdcc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+        fmovcc(cond, cc, rs2, rd, OpfLow.Fmovdcc.value);
+    }
+
+    public void fmovscc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+        fmovcc(cond, cc, rs2, rd, OpfLow.Fmovscc.value);
+    }
+
+    private void fmovcc(ConditionFlag cond, CC cc, Register rs2, Register rd, int opfLow) {
+        int opfCC = cc.value;
+        int a = opfCC << 11 | opfLow << 5 | rs2.encoding;
+        fmt10(rd.encoding, Fpop2.value, cond.value, a);
+    }
+
+    public void movcc(ConditionFlag conditionFlag, CC cc, Register rs2, Register rd) {
+        movcc(conditionFlag, cc, 0, rs2.encoding, rd);
+    }
+
+    public void movcc(ConditionFlag conditionFlag, CC cc, int simm11, Register rd) {
+        assert isSimm11(simm11);
+        movcc(conditionFlag, cc, 1, simm11 & ((1 << 11) - 1), rd);
+    }
+
+    private void movcc(ConditionFlag conditionFlag, CC cc, int i, int imm, Register rd) {
+        int cc01 = 0b11 & cc.value;
+        int cc2 = cc.isFloat ? 0 : 1;
+        int a = cc2 << 4 | conditionFlag.value;
+        int b = cc01 << 11 | i << 13 | imm;
+        fmt10(rd.encoding, Movcc.value, a, b);
+    }
+
+    public void mulx(Register rs1, Register rs2, Register rd) {
+        op3(Mulx, rs1, rs2, rd);
+    }
+
+    public void mulx(Register rs1, int simm13, Register rd) {
+        op3(Mulx, rs1, simm13, rd);
+    }
+
+    public void or(Register rs1, Register rs2, Register rd) {
+        assert isCPURegister(rs1, rs2, rd) : String.format("%s %s %s", rs1, rs2, rd);
+        op3(Or, rs1, rs2, rd);
+    }
+
+    public void or(Register rs1, int simm13, Register rd) {
+        assert isCPURegister(rs1, rd) : String.format("%s %s", rs1, rd);
+        op3(Or, rs1, simm13, rd);
+    }
+
+    public void popc(Register rs2, Register rd) {
+        op3(Popc, g0, rs2, rd);
+    }
+
+    public void popc(int simm13, Register rd) {
+        op3(Popc, g0, simm13, rd);
+    }
+
+    public void prefetch(SPARCAddress addr, Fcn fcn) {
+        Register rs1 = addr.getBase();
+        if (addr.getIndex().equals(Register.None)) {
+            int dis = addr.getDisplacement();
+            assert isSimm13(dis);
+            fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1));
+        } else {
+            Register rs2 = addr.getIndex();
+            fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding);
+        }
+    }
+
+    // A.44 Read State Register
+
+    public void rdpc(Register rd) {
+        op3(Rd, g5, g0, rd);
+    }
+
+    public void restore(Register rs1, Register rs2, Register rd) {
+        op3(Restore, rs1, rs2, rd);
+    }
+
+    public static final int PC_RETURN_OFFSET = 8;
+
+    public void save(Register rs1, Register rs2, Register rd) {
+        op3(Save, rs1, rs2, rd);
+    }
+
+    public void save(Register rs1, int simm13, Register rd) {
+        op3(Save, rs1, simm13, rd);
+    }
+
+    public void sdivx(Register rs1, Register rs2, Register rd) {
+        op3(Sdivx, rs1, rs2, rd);
+    }
+
+    public void sdivx(Register rs1, int simm13, Register rd) {
+        op3(Sdivx, rs1, simm13, rd);
+    }
+
+    public void udivx(Register rs1, Register rs2, Register rd) {
+        op3(Udivx, rs1, rs2, rd);
+    }
+
+    public void udivx(Register rs1, int simm13, Register rd) {
+        op3(Udivx, rs1, simm13, rd);
+    }
+
+    public void sll(Register rs1, Register rs2, Register rd) {
+        op3(Sll, rs1, rs2, rd);
+    }
+
+    public void sll(Register rs1, int shcnt32, Register rd) {
+        assert isImm(shcnt32, 5);
+        op3(Sll, rs1, shcnt32, rd);
+    }
+
+    public void sllx(Register rs1, Register rs2, Register rd) {
+        op3(Sllx, rs1, rs2, rd);
+    }
+
+    public void sllx(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Sllx, rs1, shcnt64, rd);
+    }
+
+    public void sra(Register rs1, Register rs2, Register rd) {
+        op3(Sra, rs1, rs2, rd);
+    }
+
+    public void sra(Register rs1, int simm13, Register rd) {
+        op3(Sra, rs1, simm13, rd);
+    }
+
+    public void srax(Register rs1, Register rs2, Register rd) {
+        op3(Srax, rs1, rs2, rd);
+    }
+
+    public void srax(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Srax, rs1, shcnt64, rd);
+    }
+
+    public void srl(Register rs1, Register rs2, Register rd) {
+        op3(Srl, rs1, rs2, rd);
+    }
+
+    public void srl(Register rs1, int simm13, Register rd) {
+        op3(Srl, rs1, simm13, rd);
+    }
+
+    public void srlx(Register rs1, Register rs2, Register rd) {
+        op3(Srlx, rs1, rs2, rd);
+    }
+
+    public void srlx(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Srlx, rs1, shcnt64, rd);
+    }
+
+    public void sub(Register rs1, Register rs2, Register rd) {
+        op3(Sub, rs1, rs2, rd);
+    }
+
+    public void sub(Register rs1, int simm13, Register rd) {
+        op3(Sub, rs1, simm13, rd);
+    }
+
+    public void subcc(Register rs1, Register rs2, Register rd) {
+        op3(Subcc, rs1, rs2, rd);
+    }
+
+    public void subcc(Register rs1, int simm13, Register rd) {
+        op3(Subcc, rs1, simm13, rd);
+    }
+
+    public void ta(int trap) {
+        tcc(Icc, Always, trap);
+    }
+
+    public void pause() {
+        // Maybe fmt10(rd=0b1_1011, op3=0b11_0000, rs1=0, i=1, simm13=1), or
+        // maybe op3(Wr, g0, 1, %pause).
+        // What should the count be?
+        GraalError.unimplemented("The SPARC pause instruction is not yet implemented.");
+    }
+
+    public void tcc(CC cc, ConditionFlag flag, int trap) {
+        assert isImm(trap, 8);
+        int b = cc.value << 11;
+        b |= 1 << 13;
+        b |= trap;
+        fmt10(flag.value, Op3s.Tcc.getValue(), 0, b);
+    }
+
+    public void wrccr(Register rs1, Register rs2) {
+        op3(Wr, rs1, rs2, g2);
+    }
+
+    public void wrccr(Register rs1, int simm13) {
+        op3(Wr, rs1, simm13, g2);
+    }
+
+    public void xor(Register rs1, Register rs2, Register rd) {
+        op3(Xor, rs1, rs2, rd);
+    }
+
+    public void xor(Register rs1, int simm13, Register rd) {
+        op3(Xor, rs1, simm13, rd);
+    }
+
+    public void xorcc(Register rs1, Register rs2, Register rd) {
+        op3(Xorcc, rs1, rs2, rd);
+    }
+
+    public void xorcc(Register rs1, int simm13, Register rd) {
+        op3(Xorcc, rs1, simm13, rd);
+    }
+
+    public void xnor(Register rs1, Register rs2, Register rd) {
+        op3(Xnor, rs1, rs2, rd);
+    }
+
+    public void xnor(Register rs1, int simm13, Register rd) {
+        op3(Xnor, rs1, simm13, rd);
+    }
+
+    /*
+     * Load/Store
+     */
+    protected void ld(Op3s op3, SPARCAddress addr, Register rd, Asi asi) {
+        Register rs1 = addr.getBase();
+        if (!addr.getIndex().equals(Register.None)) {
+            Register rs2 = addr.getIndex();
+            if (asi != null) {
+                int b = rs2.encoding;
+                b |= asi.value << 5;
+                fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, b);
+            } else {
+                op3(op3, rs1, rs2, rd);
+            }
+        } else {
+            int imm = addr.getDisplacement();
+            op3(op3, rs1, imm, rd);
+        }
+    }
+
+    protected void ld(Op3s op3, SPARCAddress addr, Register rd) {
+        ld(op3, addr, rd, null);
+    }
+
+    public void lddf(SPARCAddress src, Register dst) {
+        assert isDoubleFloatRegister(dst) : dst;
+        ld(Lddf, src, dst);
+    }
+
+    public void ldf(SPARCAddress src, Register dst) {
+        assert isSingleFloatRegister(dst) : dst;
+        ld(Ldf, src, dst);
+    }
+
+    public void lduh(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Lduh, src, dst);
+    }
+
+    public void ldsh(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsh, src, dst);
+    }
+
+    public void ld(SPARCAddress src, Register dst, int bytes, boolean signExtend) {
+        if (isCPURegister(dst)) {
+            if (signExtend) {
+                switch (bytes) {
+                    case 1:
+                        ld(Ldsb, src, dst);
+                        break;
+                    case 2:
+                        ld(Ldsh, src, dst);
+                        break;
+                    case 4:
+                        ld(Ldsw, src, dst);
+                        break;
+                    case 8:
+                        ld(Ldx, src, dst);
+                        break;
+                    default:
+                        throw new InternalError();
+                }
+            } else {
+                switch (bytes) {
+                    case 1:
+                        ld(Ldub, src, dst);
+                        break;
+                    case 2:
+                        ld(Lduh, src, dst);
+                        break;
+                    case 4:
+                        ld(Lduw, src, dst);
+                        break;
+                    case 8:
+                        ld(Ldx, src, dst);
+                        break;
+                    default:
+                        throw new InternalError();
+                }
+            }
+        } else if (isDoubleFloatRegister(dst) && bytes == 8) {
+            assert !signExtend;
+            ld(Lddf, src, dst);
+        } else if (isSingleFloatRegister(dst) && bytes == 4) {
+            assert !signExtend;
+            ld(Ldf, src, dst);
+        } else {
+            throw new InternalError(String.format("src: %s dst: %s bytes: %d signExtend: %b", src, dst, bytes, signExtend));
+        }
+    }
+
+    public void st(Register src, SPARCAddress dst, int bytes) {
+        if (isCPURegister(src)) {
+            switch (bytes) {
+                case 1:
+                    st(Stb, src, dst);
+                    break;
+                case 2:
+                    st(Sth, src, dst);
+                    break;
+                case 4:
+                    st(Stw, src, dst);
+                    break;
+                case 8:
+                    st(Stx, src, dst);
+                    break;
+                default:
+                    throw new InternalError(Integer.toString(bytes));
+            }
+        } else if (isDoubleFloatRegister(src) && bytes == 8) {
+            st(Stdf, src, dst);
+        } else if (isSingleFloatRegister(src) && bytes == 4) {
+            st(Stf, src, dst);
+        } else {
+            throw new InternalError(String.format("src: %s dst: %s bytes: %d", src, dst, bytes));
+        }
+    }
+
+    public void ldub(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldub, src, dst);
+    }
+
+    public void ldsb(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsb, src, dst);
+    }
+
+    public void lduw(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Lduw, src, dst);
+    }
+
+    public void ldsw(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsw, src, dst);
+    }
+
+    public void ldx(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldx, src, dst);
+    }
+
+    public void ldxa(Register rs1, Register rs2, Register rd, Asi asi) {
+        assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+        ld(Ldxa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    public void lduwa(Register rs1, Register rs2, Register rd, Asi asi) {
+        assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+        ld(Lduwa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    public void stxa(Register rd, Register rs1, Register rs2, Asi asi) {
+        assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+        ld(Stxa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    protected void st(Op3s op3, Register rs1, SPARCAddress dest) {
+        ld(op3, dest, rs1);
+    }
+
+    public void stdf(Register rd, SPARCAddress addr) {
+        assert isDoubleFloatRegister(rd) : rd;
+        st(Stdf, rd, addr);
+    }
+
+    public void stf(Register rd, SPARCAddress addr) {
+        assert isSingleFloatRegister(rd) : rd;
+        st(Stf, rd, addr);
+    }
+
+    public void stb(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stb, rd, addr);
+    }
+
+    public void sth(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Sth, rd, addr);
+    }
+
+    public void stw(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stw, rd, addr);
+    }
+
+    public void stx(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stx, rd, addr);
+    }
+
+    public void membar(int barriers) {
+        op3(Membar, o7, barriers, g0);
+    }
+
+    public void casa(Register rs1, Register rs2, Register rd, Asi asi) {
+        ld(Casa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    public void casxa(Register rs1, Register rs2, Register rd, Asi asi) {
+        ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    @Override
+    public InstructionCounter getInstructionCounter() {
+        return new SPARCInstructionCounter(this);
+    }
+
+    public void patchAddImmediate(int position, int simm13) {
+        int inst = getInt(position);
+        assert SPARCAssembler.isSimm13(simm13) : simm13;
+        assert (inst >>> 30) == 0b10 : String.format("0x%x", inst);
+        assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst);
+        assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst);
+        inst = inst & (~((1 << 13) - 1));
+        inst |= simm13 & ((1 << 12) - 1);
+        emitInt(inst, position);
+    }
+
+    public void fpadd32(Register rs1, Register rs2, Register rd) {
+        op3(Impdep1, Fpadd32, rs1, rs2, rd);
+    }
+
+    /**
+     * Does peephole optimization on code generated by this assembler. This method should be called
+     * at the end of code generation.
+     * <p>
+     * It searches for conditional branch instructions which has nop in the delay slot then looks at
+     * the instruction at branch target; if it is an arithmetic instruction, which does not throw an
+     * exception (e.g. division), it pulls this instruction into the delay slot and increments the
+     * displacement by 1.
+     */
+    public void peephole() {
+        for (int i : delaySlotOptimizationPoints) {
+            optimizeDelaySlot(i);
+        }
+    }
+
+    /**
+     * Optimizes branch instruction <i>b</t> which has a nop in the delay slot. It tries to stuff
+     * the instruction at <i>b</i>s branch target into the delay slot of <i>b</i>, set the annul
+     * flag and increments <i>b</i>s disp field by 1;
+     * <p>
+     * If <i>b</i>s branch target instruction is an unconditional branch <i>t</i>, then it tries to
+     * put <i>t</i>s delayed instruction into the delay slot of <i>b</i> and add the <i>t</i>s disp
+     * field to <i>b</i>s disp field.
+     */
+    private void optimizeDelaySlot(int i) {
+        int delaySlotAbsolute = i + INSTRUCTION_SIZE;
+        int nextInst = getInt(delaySlotAbsolute);
+        SPARCOp nextOp = getSPARCOp(nextInst);
+        if (nextOp instanceof Sethi && Sethi.isNop(nextInst)) {
+            int inst = getInt(i);
+            SPARCOp op = getSPARCOp(inst);
+            if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) {
+                ControlTransferOp ctOp = (ControlTransferOp) op;
+                int disp = ctOp.getDisp(inst);
+                int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE;
+                int branchTargetInst = getInt(branchTargetAbsolute);
+                SPARCOp branchTargetOp = getSPARCOp(branchTargetInst);
+                if (branchTargetOp instanceof Op3Op) {
+                    Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst);
+                    if (!op3.throwsException()) {
+                        inst = ctOp.setDisp(inst, disp + 1); // Increment the offset
+                        inst = ctOp.setAnnul(inst, true);
+                        emitInt(inst, i);
+                        emitInt(branchTargetInst, delaySlotAbsolute);
+                    }
+                } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) {
+                    // If branchtarget is a unconditional branch
+                    ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp;
+                    int btDisp = branchTargetOpBranch.getDisp(branchTargetInst);
+                    int newDisp = disp + btDisp;
+                    if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size
+                        int instAfter = ctOp.setDisp(inst, newDisp);
+                        instAfter = ctOp.setAnnul(instAfter, true);
+                        branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE);
+                        branchTargetOp = getSPARCOp(branchTargetInst);
+                        if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) {
+                            emitInt(instAfter, i);
+                            emitInt(branchTargetInst, delaySlotAbsolute);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java
new file mode 100644
index 0000000..7e0a75a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc;
+
+import java.util.TreeMap;
+
+import org.graalvm.compiler.asm.Assembler.InstructionCounter;
+
+public class SPARCInstructionCounter implements InstructionCounter {
+    // Use a treemap to keep the order in the output
+    private static final TreeMap<String, SPARCInstructionMatch> INSTRUCTION_MATCHER = new TreeMap<>();
+
+    static {
+        // @formatter:off
+        INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000));
+        INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf));
+        INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd));
+        INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0));
+        // @formatter:on
+    }
+
+    private final SPARCAssembler asm;
+
+    public SPARCInstructionCounter(SPARCAssembler asm) {
+        super();
+        this.asm = asm;
+    }
+
+    @Override
+    public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) {
+        SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length];
+        for (int i = 0; i < instructionTypes.length; i++) {
+            String typeName = instructionTypes[i];
+            matchers[i] = INSTRUCTION_MATCHER.get(typeName);
+            if (matchers[i] == null) {
+                throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet()));
+            }
+        }
+        return countBetween(matchers, beginPc, endPc);
+    }
+
+    private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) {
+        int[] counts = new int[matchers.length];
+        for (int p = startPc; p < endPc; p += 4) {
+            int instr = asm.getInt(p);
+            for (int i = 0; i < matchers.length; i++) {
+                SPARCInstructionMatch matcher = matchers[i];
+                if (matcher.matches(instr)) {
+                    counts[i]++;
+                }
+            }
+        }
+        return counts;
+    }
+
+    @Override
+    public String[] getSupportedInstructionTypes() {
+        return INSTRUCTION_MATCHER.keySet().toArray(new String[0]);
+    }
+
+    /**
+     * Tests the lower 3 bits of the op3 field.
+     */
+    private static class OP3LowBitsMatcher extends SPARCInstructionMatch {
+        private final int[] op3b03;
+        private final int op;
+
+        OP3LowBitsMatcher(int op, int... op3b03) {
+            super(0, 0);
+            this.op = op;
+            this.op3b03 = op3b03;
+        }
+
+        @Override
+        public boolean matches(int instruction) {
+            if (instruction >>> 30 != op) {
+                return false;
+            }
+            int op3lo = (instruction >> 19) & ((1 << 4) - 1);
+            for (int op3Part : op3b03) {
+                if (op3Part == op3lo) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private static class SPARCInstructionMatch {
+        private final int mask;
+        private final int[] patterns;
+
+        SPARCInstructionMatch(int mask, int... patterns) {
+            super();
+            this.mask = mask;
+            this.patterns = patterns;
+        }
+
+        public boolean matches(int instruction) {
+            for (int pattern : patterns) {
+                if ((instruction & mask) == pattern) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java
new file mode 100644
index 0000000..4761511
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.g3;
+import static jdk.vm.ci.sparc.SPARC.i7;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+import org.graalvm.compiler.asm.Label;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+
+public class SPARCMacroAssembler extends SPARCAssembler {
+
+    /**
+     * A sentinel value used as a place holder in an instruction stream for an address that will be
+     * patched.
+     */
+    private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)};
+    // Points to the next free scratch register
+    private int nextFreeScratchRegister = 0;
+    /**
+     * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the
+     * constant table does not exceed simm13).
+     */
+    private boolean immediateConstantLoad;
+
+    public SPARCMacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    /**
+     * @see #immediateConstantLoad
+     */
+    public void setImmediateConstantLoad(boolean immediateConstantLoad) {
+        this.immediateConstantLoad = immediateConstantLoad;
+    }
+
+    @Override
+    public void align(int modulus) {
+        while (position() % modulus != 0) {
+            nop();
+        }
+    }
+
+    @Override
+    public void jmp(Label l) {
+        BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l);
+        nop();  // delay slot
+    }
+
+    @Override
+    protected final void patchJumpTarget(int branch, int branchTarget) {
+        final int disp = (branchTarget - branch) / 4;
+        final int inst = getInt(branch);
+        ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst);
+        int newInst = op.setDisp(inst, disp);
+        emitInt(newInst, branch);
+    }
+
+    @Override
+    public AbstractAddress makeAddress(Register base, int displacement) {
+        return new SPARCAddress(base, displacement);
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder(int instructionStartPosition) {
+        return Placeholder;
+    }
+
+    @Override
+    public final void ensureUniquePC() {
+        nop();
+    }
+
+    public void cas(Register rs1, Register rs2, Register rd) {
+        casa(rs1, rs2, rd, Asi.ASI_PRIMARY);
+    }
+
+    public void casx(Register rs1, Register rs2, Register rd) {
+        casxa(rs1, rs2, rd, Asi.ASI_PRIMARY);
+    }
+
+    public void clr(Register dst) {
+        or(g0, g0, dst);
+    }
+
+    public void clrb(SPARCAddress addr) {
+        stb(g0, addr);
+    }
+
+    public void clrh(SPARCAddress addr) {
+        sth(g0, addr);
+    }
+
+    public void clrx(SPARCAddress addr) {
+        stx(g0, addr);
+    }
+
+    public void cmp(Register rs1, Register rs2) {
+        subcc(rs1, rs2, g0);
+    }
+
+    public void cmp(Register rs1, int simm13) {
+        subcc(rs1, simm13, g0);
+    }
+
+    public void dec(Register rd) {
+        sub(rd, 1, rd);
+    }
+
+    public void dec(int simm13, Register rd) {
+        sub(rd, simm13, rd);
+    }
+
+    public void jmp(SPARCAddress address) {
+        jmpl(address.getBase(), address.getDisplacement(), g0);
+    }
+
+    public void jmp(Register rd) {
+        jmpl(rd, 0, g0);
+    }
+
+    public void neg(Register rs1, Register rd) {
+        sub(g0, rs1, rd);
+    }
+
+    public void neg(Register rd) {
+        sub(g0, rd, rd);
+    }
+
+    public void mov(Register rs, Register rd) {
+        or(g0, rs, rd);
+    }
+
+    public void mov(int simm13, Register rd) {
+        or(g0, simm13, rd);
+    }
+
+    public void not(Register rs1, Register rd) {
+        xnor(rs1, g0, rd);
+    }
+
+    public void not(Register rd) {
+        xnor(rd, g0, rd);
+    }
+
+    public void restoreWindow() {
+        restore(g0, g0, g0);
+    }
+
+    public void ret() {
+        jmpl(i7, 8, g0);
+    }
+
+    /**
+     * Generates sethi hi22(value), dst; or dst, lo10(value), dst; code.
+     */
+    public void setw(int value, Register dst, boolean forceRelocatable) {
+        if (!forceRelocatable && isSimm13(value)) {
+            or(g0, value, dst);
+        } else {
+            sethi(hi22(value), dst);
+            or(dst, lo10(value), dst);
+        }
+    }
+
+    public void setx(long value, Register dst, boolean forceRelocatable) {
+        int lo = (int) (value & ~0);
+        sethix(value, dst, forceRelocatable);
+        if (lo10(lo) != 0 || forceRelocatable) {
+            add(dst, lo10(lo), dst);
+        }
+    }
+
+    public void sethix(long value, Register dst, boolean forceRelocatable) {
+        final int hi = (int) (value >> 32);
+        final int lo = (int) (value & ~0);
+
+        // This is the same logic as MacroAssembler::internal_set.
+        final int startPc = position();
+        if (hi == 0 && lo >= 0) {
+            sethi(hi22(lo), dst);
+        } else if (hi == -1) {
+            sethi(hi22(~lo), dst);
+            xor(dst, ~lo10(~0), dst);
+        } else {
+            final int shiftcnt;
+            final int shiftcnt2;
+            sethi(hi22(hi), dst);
+            if ((hi & 0x3ff) != 0) {                                  // Any bits?
+                // msb 32-bits are now in lsb 32
+                or(dst, hi & 0x3ff, dst);
+            }
+            if ((lo & 0xFFFFFC00) != 0) {                             // done?
+                if (((lo >> 20) & 0xfff) != 0) {                      // Any bits set?
+                    // Make room for next 12 bits
+                    sllx(dst, 12, dst);
+                    // Or in next 12
+                    or(dst, (lo >> 20) & 0xfff, dst);
+                    shiftcnt = 0;                                     // We already shifted
+                } else {
+                    shiftcnt = 12;
+                }
+                if (((lo >> 10) & 0x3ff) != 0) {
+                    // Make room for last 10 bits
+                    sllx(dst, shiftcnt + 10, dst);
+                    // Or in next 10
+                    or(dst, (lo >> 10) & 0x3ff, dst);
+                    shiftcnt2 = 0;
+                } else {
+                    shiftcnt2 = 10;
+                }
+                // Shift leaving disp field 0'd
+                sllx(dst, shiftcnt2 + 10, dst);
+            } else {
+                sllx(dst, 32, dst);
+            }
+        }
+        // Pad out the instruction sequence so it can be patched later.
+        if (forceRelocatable) {
+            while (position() < (startPc + (INSTRUCTION_SIZE * 7))) {
+                nop();
+            }
+        }
+    }
+
+    public void signx(Register rs, Register rd) {
+        sra(rs, g0, rd);
+    }
+
+    public void signx(Register rd) {
+        sra(rd, g0, rd);
+    }
+
+    public boolean isImmediateConstantLoad() {
+        return immediateConstantLoad;
+    }
+
+    public ScratchRegister getScratchRegister() {
+        return scratchRegister[nextFreeScratchRegister++];
+    }
+
+    public class ScratchRegister implements AutoCloseable {
+        private final Register register;
+
+        public ScratchRegister(Register register) {
+            super();
+            this.register = register;
+        }
+
+        public Register getRegister() {
+            return register;
+        }
+
+        @Override
+        public void close() {
+            assert nextFreeScratchRegister > 0 : "Close called too often";
+            nextFreeScratchRegister--;
+        }
+    }
+
+    public void compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
+        assert isCPURegister(rs1, rs2);
+        assert ccRegister == Icc || ccRegister == Xcc;
+        if (hasFeature(CPUFeature.CBCOND)) {
+            if (delaySlotInstruction != null) {
+                delaySlotInstruction.run();
+            }
+            CBCOND.emit(this, cond, ccRegister == Xcc, rs1, rs2, label);
+        } else {
+            if (cond == Equal && rs1.equals(g0)) {
+                BPR.emit(this, Rc_z, NOT_ANNUL, predict, rs1, label);
+            } else {
+                cmp(rs1, rs2);
+                BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
+            }
+            if (delaySlotInstruction != null) {
+                int positionBefore = position();
+                delaySlotInstruction.run();
+                int positionAfter = position();
+                assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
+            } else {
+                nop();
+            }
+        }
+    }
+
+    public void compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
+        assert isCPURegister(rs1);
+        assert ccRegister == Icc || ccRegister == Xcc;
+        if (hasFeature(CPUFeature.CBCOND)) {
+            if (delaySlotInstruction != null) {
+                delaySlotInstruction.run();
+            }
+            CBCOND.emit(this, cond, ccRegister == Xcc, rs1, simm, label);
+        } else {
+            if (cond == Equal && simm == 0) {
+                BPR.emit(this, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, rs1, label);
+            } else {
+                cmp(rs1, simm);
+                BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
+            }
+            if (delaySlotInstruction != null) {
+                int positionBefore = position();
+                delaySlotInstruction.run();
+                int positionAfter = position();
+                assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
+            } else {
+                nop();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java
new file mode 100644
index 0000000..a7c1fb0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.test;
+
+import static org.graalvm.compiler.core.common.CompilationRequestIdentifier.asCompilationRequest;
+
+import java.lang.reflect.Method;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+public abstract class AssemblerTest extends GraalTest {
+
+    private final MetaAccessProvider metaAccess;
+    protected final CodeCacheProvider codeCache;
+    private final Backend backend;
+
+    public interface CodeGenTest {
+        byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
+    }
+
+    public AssemblerTest() {
+        JVMCIBackend providers = JVMCI.getRuntime().getHostJVMCIBackend();
+        this.metaAccess = providers.getMetaAccess();
+        this.codeCache = providers.getCodeCache();
+        this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @SuppressWarnings("try")
+    protected InstalledCode assembleMethod(Method m, CodeGenTest test) {
+        ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(m);
+        try (Scope s = Debug.scope("assembleMethod", method, codeCache)) {
+            RegisterConfig registerConfig = codeCache.getRegisterConfig();
+            CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
+            CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, new StructuredGraph(method, AllowAssumptions.NO, compilationId), null).getCallingConvention();
+
+            CompilationResult compResult = new CompilationResult();
+            byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
+            compResult.setTargetCode(targetCode, targetCode.length);
+            compResult.setTotalFrameSize(0);
+            compResult.close();
+
+            InstalledCode code = backend.addInstalledCode(method, asCompilationRequest(compilationId), compResult);
+
+            for (DisassemblerProvider dis : GraalServices.load(DisassemblerProvider.class)) {
+                String disasm1 = dis.disassembleCompiledCode(codeCache, compResult);
+                Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0);
+                String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code);
+                Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0);
+            }
+            return code;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected Object runTest(String methodName, CodeGenTest test, Object... args) {
+        Method method = getMethod(methodName);
+        InstalledCode code = assembleMethod(method, test);
+        try {
+            return code.executeVarargs(args);
+        } catch (InvalidInstalledCodeException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void assertReturn(String methodName, CodeGenTest test, Object expected, Object... args) {
+        Object actual = runTest(methodName, test, args);
+        Assert.assertEquals("unexpected return value", expected, actual);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AbstractAddress.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AbstractAddress.java
new file mode 100644
index 0000000..c2cf398
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AbstractAddress.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+/**
+ * Abstract base class that represents a platform specific address.
+ */
+public abstract class AbstractAddress {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AsmOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AsmOptions.java
new file mode 100644
index 0000000..ec55a24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/AsmOptions.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+public class AsmOptions {
+
+    public static int InitialCodeBufferSize = 232;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java
new file mode 100644
index 0000000..ab51d8e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * The platform-independent base class for the assembler.
+ */
+public abstract class Assembler {
+
+    public abstract static class CodeAnnotation {
+        /**
+         * The position (bytes from the beginning of the method) of the annotated instruction.
+         */
+        public final int instructionPosition;
+
+        protected CodeAnnotation(int instructionStartPosition) {
+            this.instructionPosition = instructionStartPosition;
+        }
+    }
+
+    public final TargetDescription target;
+    private List<LabelHint> jumpDisplacementHints;
+
+    /**
+     * Backing code buffer.
+     */
+    private final Buffer codeBuffer;
+
+    protected Consumer<CodeAnnotation> codePatchingAnnotationConsumer;
+
+    public Assembler(TargetDescription target) {
+        this.target = target;
+        this.codeBuffer = new Buffer(target.arch.getByteOrder());
+    }
+
+    public void setCodePatchingAnnotationConsumer(Consumer<CodeAnnotation> codeAnnotationConsumer) {
+        assert this.codePatchingAnnotationConsumer == null : "overwriting existing value";
+        this.codePatchingAnnotationConsumer = codeAnnotationConsumer;
+    }
+
+    /**
+     * Returns the current position of the underlying code buffer.
+     *
+     * @return current position in code buffer
+     */
+    public int position() {
+        return codeBuffer.position();
+    }
+
+    public final void emitByte(int x) {
+        codeBuffer.emitByte(x);
+    }
+
+    public final void emitShort(int x) {
+        codeBuffer.emitShort(x);
+    }
+
+    public final void emitInt(int x) {
+        codeBuffer.emitInt(x);
+    }
+
+    public final void emitLong(long x) {
+        codeBuffer.emitLong(x);
+    }
+
+    public final void emitByte(int b, int pos) {
+        codeBuffer.emitByte(b, pos);
+    }
+
+    public final void emitShort(int b, int pos) {
+        codeBuffer.emitShort(b, pos);
+    }
+
+    public final void emitInt(int b, int pos) {
+        codeBuffer.emitInt(b, pos);
+    }
+
+    public final void emitLong(long b, int pos) {
+        codeBuffer.emitLong(b, pos);
+    }
+
+    public final int getByte(int pos) {
+        return codeBuffer.getByte(pos);
+    }
+
+    public final int getShort(int pos) {
+        return codeBuffer.getShort(pos);
+    }
+
+    public final int getInt(int pos) {
+        return codeBuffer.getInt(pos);
+    }
+
+    private static final String NEWLINE = System.getProperty("line.separator");
+
+    /**
+     * Some GPU architectures have a text based encoding.
+     */
+    public final void emitString(String x) {
+        emitString0("\t");  // XXX REMOVE ME pretty-printing
+        emitString0(x);
+        emitString0(NEWLINE);
+    }
+
+    // XXX for pretty-printing
+    public final void emitString0(String x) {
+        codeBuffer.emitBytes(x.getBytes(), 0, x.length());
+    }
+
+    public void emitString(String s, int pos) {
+        codeBuffer.emitBytes(s.getBytes(), pos);
+    }
+
+    /**
+     * Closes this assembler. No extra data can be written to this assembler after this call.
+     *
+     * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
+     *            including) {@code position()} is returned
+     * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
+     */
+    public byte[] close(boolean trimmedCopy) {
+        return codeBuffer.close(trimmedCopy);
+    }
+
+    public void bind(Label l) {
+        assert !l.isBound() : "can bind label only once";
+        l.bind(position());
+        l.patchInstructions(this);
+    }
+
+    public abstract void align(int modulus);
+
+    public abstract void jmp(Label l);
+
+    protected abstract void patchJumpTarget(int branch, int jumpTarget);
+
+    private Map<Label, String> nameMap;
+
+    /**
+     * Creates a name for a label.
+     *
+     * @param l the label for which a name is being created
+     * @param id a label identifier that is unique with the scope of this assembler
+     * @return a label name in the form of "L123"
+     */
+    protected String createLabelName(Label l, int id) {
+        return "L" + id;
+    }
+
+    /**
+     * Gets a name for a label, creating it if it does not yet exist. By default, the returned name
+     * is only unique with the scope of this assembler.
+     */
+    public String nameOf(Label l) {
+        if (nameMap == null) {
+            nameMap = new HashMap<>();
+        }
+        String name = nameMap.get(l);
+        if (name == null) {
+            name = createLabelName(l, nameMap.size());
+            nameMap.put(l, name);
+        }
+        return name;
+    }
+
+    /**
+     * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an
+     * {@link AbstractAddress}.
+     */
+    public abstract AbstractAddress makeAddress(Register base, int displacement);
+
+    /**
+     * Returns a target specific placeholder address that can be used for code patching.
+     *
+     * @param instructionStartPosition The start of the instruction, i.e., the value that is used as
+     *            the key for looking up placeholder patching information.
+     */
+    public abstract AbstractAddress getPlaceholder(int instructionStartPosition);
+
+    /**
+     * Emits a NOP instruction to advance the current PC.
+     */
+    public abstract void ensureUniquePC();
+
+    public void reset() {
+        codeBuffer.reset();
+        captureLabelPositions();
+    }
+
+    private void captureLabelPositions() {
+        if (jumpDisplacementHints == null) {
+            return;
+        }
+        for (LabelHint request : this.jumpDisplacementHints) {
+            request.capture();
+        }
+    }
+
+    public LabelHint requestLabelHint(Label label) {
+        if (jumpDisplacementHints == null) {
+            jumpDisplacementHints = new ArrayList<>();
+        }
+        LabelHint hint = new LabelHint(label, position());
+        this.jumpDisplacementHints.add(hint);
+        return hint;
+    }
+
+    public InstructionCounter getInstructionCounter() {
+        throw new UnsupportedOperationException("Instruction counter is not implemented for " + this);
+    }
+
+    public static class LabelHint {
+        private Label label;
+        private int forPosition;
+        private int capturedTarget = -1;
+
+        protected LabelHint(Label label, int lastPosition) {
+            super();
+            this.label = label;
+            this.forPosition = lastPosition;
+        }
+
+        protected void capture() {
+            this.capturedTarget = label.position();
+        }
+
+        public int getTarget() {
+            assert isValid();
+            return capturedTarget;
+        }
+
+        public int getPosition() {
+            assert isValid();
+            return forPosition;
+        }
+
+        public boolean isValid() {
+            return capturedTarget >= 0;
+        }
+    }
+
+    /**
+     * Instruction counter class which gives the user of the assembler to count different kinds of
+     * instructions in the generated assembler code.
+     */
+    public interface InstructionCounter {
+        String[] getSupportedInstructionTypes();
+
+        int[] countInstructions(String[] instructionTypes, int beginPc, int endPc);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java
new file mode 100644
index 0000000..d6df783
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Code buffer management for the assembler.
+ */
+final class Buffer {
+
+    protected ByteBuffer data;
+
+    Buffer(ByteOrder order) {
+        data = ByteBuffer.allocate(AsmOptions.InitialCodeBufferSize);
+        data.order(order);
+    }
+
+    public int position() {
+        return data.position();
+    }
+
+    public void setPosition(int position) {
+        assert position >= 0 && position <= data.limit();
+        data.position(position);
+    }
+
+    /**
+     * Closes this buffer. Any further operations on a closed buffer will result in a
+     * {@link NullPointerException}.
+     *
+     * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
+     *            including) {@code position()} is returned
+     * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
+     */
+    public byte[] close(boolean trimmedCopy) {
+        byte[] result = data.array();
+        if (trimmedCopy) {
+            // Make a copy even if result.length == data.position() since
+            // the API for trimmedCopy states a copy is always made
+            result = Arrays.copyOf(result, data.position());
+        }
+        data = null;
+        return result;
+    }
+
+    public byte[] copyData(int start, int end) {
+        if (data == null) {
+            return null;
+        }
+        return Arrays.copyOfRange(data.array(), start, end);
+    }
+
+    /**
+     * Copies the data from this buffer into a given array.
+     *
+     * @param dst the destination array
+     * @param off starting position in {@code dst}
+     * @param len number of bytes to copy
+     */
+    public void copyInto(byte[] dst, int off, int len) {
+        System.arraycopy(data.array(), 0, dst, off, len);
+    }
+
+    protected void ensureSize(int length) {
+        if (length >= data.limit()) {
+            byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
+            ByteBuffer newData = ByteBuffer.wrap(newBuf);
+            newData.order(data.order());
+            newData.position(data.position());
+            data = newData;
+        }
+    }
+
+    public void emitBytes(byte[] arr, int off, int len) {
+        ensureSize(data.position() + len);
+        data.put(arr, off, len);
+    }
+
+    public void emitByte(int b) {
+        assert NumUtil.isUByte(b) || NumUtil.isByte(b);
+        ensureSize(data.position() + 1);
+        data.put((byte) (b & 0xFF));
+    }
+
+    public void emitShort(int b) {
+        assert NumUtil.isUShort(b) || NumUtil.isShort(b);
+        ensureSize(data.position() + 2);
+        data.putShort((short) b);
+    }
+
+    public void emitInt(int b) {
+        ensureSize(data.position() + 4);
+        data.putInt(b);
+    }
+
+    public void emitLong(long b) {
+        ensureSize(data.position() + 8);
+        data.putLong(b);
+    }
+
+    public void emitBytes(byte[] arr, int pos) {
+        final int len = arr.length;
+        ensureSize(pos + len);
+        // Write directly into the underlying array so as to not
+        // change the ByteBuffer's position
+        System.arraycopy(arr, 0, data.array(), pos, len);
+    }
+
+    public void emitByte(int b, int pos) {
+        assert NumUtil.isUByte(b) || NumUtil.isByte(b);
+        ensureSize(pos + 1);
+        data.put(pos, (byte) (b & 0xFF));
+    }
+
+    public void emitShort(int b, int pos) {
+        assert NumUtil.isUShort(b) || NumUtil.isShort(b);
+        ensureSize(pos + 2);
+        data.putShort(pos, (short) b).position();
+    }
+
+    public void emitInt(int b, int pos) {
+        ensureSize(pos + 4);
+        data.putInt(pos, b).position();
+    }
+
+    public void emitLong(long b, int pos) {
+        ensureSize(pos + 8);
+        data.putLong(pos, b).position();
+    }
+
+    public int getByte(int pos) {
+        int b = data.get(pos);
+        return b & 0xff;
+    }
+
+    public int getShort(int pos) {
+        short s = data.getShort(pos);
+        return s & 0xffff;
+    }
+
+    public int getInt(int pos) {
+        return data.getInt(pos);
+    }
+
+    public void reset() {
+        data.clear();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java
new file mode 100644
index 0000000..8200f79
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+import java.util.ArrayList;
+
+/**
+ * This class represents a label within assembly code.
+ */
+public final class Label {
+
+    private int position = -1;
+    private int blockId = -1;
+
+    /**
+     * References to instructions that jump to this unresolved label. These instructions need to be
+     * patched when the label is bound using the {@link #patchInstructions(Assembler)} method.
+     */
+    private ArrayList<Integer> patchPositions = null;
+
+    /**
+     * Returns the position of this label in the code buffer.
+     *
+     * @return the position
+     */
+    public int position() {
+        assert position >= 0 : "Unbound label is being referenced";
+        return position;
+    }
+
+    public Label() {
+    }
+
+    public Label(int id) {
+        blockId = id;
+    }
+
+    public int getBlockId() {
+        return blockId;
+    }
+
+    /**
+     * Binds the label to the specified position.
+     *
+     * @param pos the position
+     */
+    protected void bind(int pos) {
+        this.position = pos;
+        assert isBound();
+    }
+
+    public boolean isBound() {
+        return position >= 0;
+    }
+
+    public void addPatchAt(int branchLocation) {
+        assert !isBound() : "Label is already bound " + this + " " + branchLocation + " at position " + position;
+        if (patchPositions == null) {
+            patchPositions = new ArrayList<>(2);
+        }
+        patchPositions.add(branchLocation);
+    }
+
+    protected void patchInstructions(Assembler masm) {
+        assert isBound() : "Label should be bound";
+        if (patchPositions != null) {
+            int target = position;
+            for (int i = 0; i < patchPositions.size(); ++i) {
+                int pos = patchPositions.get(i);
+                masm.patchJumpTarget(pos, target);
+            }
+        }
+    }
+
+    public void reset() {
+        if (this.patchPositions != null) {
+            this.patchPositions.clear();
+        }
+        this.position = -1;
+    }
+
+    @Override
+    public String toString() {
+        return isBound() ? String.valueOf(position()) : "?";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/NumUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/NumUtil.java
new file mode 100644
index 0000000..5966c04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/NumUtil.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm;
+
+// JaCoCo Exclude
+
+/**
+ * A collection of static utility functions that check ranges of numbers.
+ */
+public class NumUtil {
+
+    public static boolean isShiftCount(int x) {
+        return 0 <= x && x < 32;
+    }
+
+    /**
+     * Determines if a given {@code int} value is the range of unsigned byte values.
+     */
+    public static boolean isUByte(int x) {
+        return (x & 0xff) == x;
+    }
+
+    /**
+     * Determines if a given {@code int} value is the range of signed byte values.
+     */
+    public static boolean isByte(int x) {
+        return (byte) x == x;
+    }
+
+    /**
+     * Determines if a given {@code long} value is the range of unsigned byte values.
+     */
+    public static boolean isUByte(long x) {
+        return (x & 0xffL) == x;
+    }
+
+    /**
+     * Determines if a given {@code long} value is the range of signed byte values.
+     */
+    public static boolean isByte(long l) {
+        return (byte) l == l;
+    }
+
+    /**
+     * Determines if a given {@code long} value is the range of unsigned int values.
+     */
+    public static boolean isUInt(long x) {
+        return (x & 0xffffffffL) == x;
+    }
+
+    /**
+     * Determines if a given {@code long} value is the range of signed int values.
+     */
+    public static boolean isInt(long l) {
+        return (int) l == l;
+    }
+
+    /**
+     * Determines if a given {@code int} value is the range of signed short values.
+     */
+    public static boolean isShort(int x) {
+        return (short) x == x;
+    }
+
+    /**
+     * Determines if a given {@code long} value is the range of signed short values.
+     */
+    public static boolean isShort(long x) {
+        return (short) x == x;
+    }
+
+    public static boolean isUShort(int s) {
+        return s == (s & 0xFFFF);
+    }
+
+    public static boolean isUShort(long s) {
+        return s == (s & 0xFFFF);
+    }
+
+    public static boolean is32bit(long x) {
+        return -0x80000000L <= x && x < 0x80000000L;
+    }
+
+    public static short safeToShort(int v) {
+        assert isShort(v);
+        return (short) v;
+    }
+
+    public static int roundUp(int number, int mod) {
+        return ((number + mod - 1) / mod) * mod;
+    }
+
+    public static long roundUp(long number, long mod) {
+        return ((number + mod - 1L) / mod) * mod;
+    }
+
+    public static int roundDown(int number, int mod) {
+        return number / mod * mod;
+    }
+
+    public static long roundDown(long number, long mod) {
+        return number / mod * mod;
+    }
+
+    public static int log2Ceil(int val) {
+        int x = 1;
+        int log2 = 0;
+        while (x < val) {
+            log2++;
+            x *= 2;
+        }
+        return log2;
+    }
+
+    public static boolean isUnsignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        return 32 - Integer.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isUnsignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        return 64 - Long.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isSignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        int min = -(1 << (n - 1));
+        int max = (1 << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    public static boolean isSignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        long min = -(1L << (n - 1));
+        long max = (1L << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static int getNbitNumberInt(int n) {
+        assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n;
+        if (n < 32) {
+            return (1 << n) - 1;
+        } else {
+            return 0xFFFFFFFF;
+        }
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 64 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static long getNbitNumberLong(int n) {
+        assert n >= 0 && n <= 64;
+        if (n < 64) {
+            return (1L << n) - 1;
+        } else {
+            return 0xFFFFFFFFFFFFFFFFL;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BridgeMethodUtils.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BridgeMethodUtils.java
new file mode 100644
index 0000000..9cd58f0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BridgeMethodUtils.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+
+import java.lang.annotation.Annotation;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Utilities for working around the absence of method annotations and parameter annotations on
+ * bridge methods where the bridged methods have method annotations or parameter annotations. Not
+ * all Java compilers copy method annotations and parameter annotations to bridge methods.
+ *
+ * @see <a href="http://bugs.java.com/view_bug.do?bug_id=6695379">6695379</a>
+ * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=495396">495396</a>
+ * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=427745">427745</a>
+ */
+public class BridgeMethodUtils {
+
+    /**
+     * Gets the method bridged to by a {@linkplain ResolvedJavaMethod#isBridge() bridge} method. The
+     * value returned is the method called by {@code method} that has the same name as
+     * {@code bridge}.
+     *
+     * @param bridge a bridge method
+     * @return the method called by {@code bridge} whose name is the same as
+     *         {@code bridge.getName()}
+     */
+    public static ResolvedJavaMethod getBridgedMethod(ResolvedJavaMethod bridge) {
+        assert bridge.isBridge();
+        Bytecode code = new ResolvedJavaMethodBytecode(bridge);
+        BytecodeStream stream = new BytecodeStream(code.getCode());
+        int opcode = stream.currentBC();
+        ResolvedJavaMethod bridged = null;
+        boolean calledAbstractMethodErrorConstructor = false;
+        while (opcode != Bytecodes.END) {
+            switch (opcode) {
+                case INVOKEVIRTUAL:
+                case INVOKESPECIAL:
+                case INVOKESTATIC:
+                case INVOKEINTERFACE: {
+                    int cpi = stream.readCPI();
+                    ConstantPool cp = code.getConstantPool();
+                    cp.loadReferencedType(cpi, opcode);
+                    ResolvedJavaMethod method = (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode);
+                    if (method.getName().equals(bridge.getName())) {
+                        if (!assertionsEnabled()) {
+                            return method;
+                        }
+                        assert bridged == null || bridged.equals(method) : String.format("Found calls to different methods named %s in bridge method %s%n  callee 1: %s%n  callee 2: %s",
+                                        bridge.getName(), bridge.format("%R %H.%n(%P)"), bridged.format("%R %H.%n(%P)"), method.format("%R %H.%n(%P)"));
+                        bridged = method;
+                    } else if (method.getName().equals("<init>") && method.getDeclaringClass().getName().equals("Ljava/lang/AbstractMethodError;")) {
+                        calledAbstractMethodErrorConstructor = true;
+                    }
+                    break;
+                }
+                case ATHROW: {
+                    if (calledAbstractMethodErrorConstructor) {
+                        // This is a miranda method
+                        return null;
+                    }
+                }
+            }
+            stream.next();
+            opcode = stream.currentBC();
+        }
+        if (bridged == null) {
+            String dis = new BytecodeDisassembler().disassemble(bridge);
+            throw new InternalError(String.format("Couldn't find method bridged by %s:%n%s", bridge.format("%R %H.%n(%P)"), dis));
+        }
+        return bridged;
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled;
+    }
+
+    /**
+     * A helper for {@link ResolvedJavaMethod#getAnnotation(Class)} that handles the absence of
+     * annotations on bridge methods where the bridged method has annotations.
+     */
+    public static <T extends Annotation> T getAnnotation(Class<T> annotationClass, ResolvedJavaMethod method) {
+        T a = method.getAnnotation(annotationClass);
+        if (a == null && method.isBridge()) {
+            ResolvedJavaMethod bridged = getBridgedMethod(method);
+            if (bridged != null) {
+                a = bridged.getAnnotation(annotationClass);
+            }
+        }
+        return a;
+    }
+
+    /**
+     * A helper for {@link ResolvedJavaMethod#getAnnotations()} that handles the absence of
+     * annotations on bridge methods where the bridged method has annotations.
+     */
+    public static Annotation[] getAnnotations(ResolvedJavaMethod method) {
+        Annotation[] a = method.getAnnotations();
+        if (a.length == 0 && method.isBridge()) {
+            ResolvedJavaMethod bridged = getBridgedMethod(method);
+            if (bridged != null) {
+                a = bridged.getAnnotations();
+            }
+        }
+        return a;
+    }
+
+    /**
+     * A helper for {@link ResolvedJavaMethod#getDeclaredAnnotations()} that handles the absence of
+     * annotations on bridge methods where the bridged method has annotations.
+     */
+    public static Annotation[] getDeclaredAnnotations(ResolvedJavaMethod method) {
+        Annotation[] a = method.getAnnotations();
+        if (a.length == 0 && method.isBridge()) {
+            ResolvedJavaMethod bridged = getBridgedMethod(method);
+            if (bridged != null) {
+                a = bridged.getDeclaredAnnotations();
+            }
+        }
+        return a;
+    }
+
+    /**
+     * A helper for {@link ResolvedJavaMethod#getParameterAnnotations()} that handles the absence of
+     * parameter annotations on bridge methods where the bridged method has parameter annotations.
+     */
+    public static Annotation[][] getParameterAnnotations(ResolvedJavaMethod method) {
+        Annotation[][] a = method.getParameterAnnotations();
+        if (a.length == 0 && method.isBridge()) {
+            ResolvedJavaMethod bridged = getBridgedMethod(method);
+            if (bridged != null) {
+                a = bridged.getParameterAnnotations();
+            }
+        }
+        return a;
+    }
+
+    /**
+     * A helper for {@link ResolvedJavaMethod#getParameterAnnotation(Class, int)} that handles the
+     * absence of parameter annotations on bridge methods where the bridged method has parameter
+     * annotations.
+     */
+    public static <T extends Annotation> T getParameterAnnotation(Class<T> annotationClass, int parameterIndex, ResolvedJavaMethod method) {
+        T a = method.getParameterAnnotation(annotationClass, parameterIndex);
+        if (a == null && method.isBridge()) {
+            ResolvedJavaMethod bridged = getBridgedMethod(method);
+            if (bridged != null) {
+                a = bridged.getParameterAnnotation(annotationClass, parameterIndex);
+            }
+        }
+        return a;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java
new file mode 100644
index 0000000..60f0b52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.ExceptionHandler;
+import jdk.vm.ci.meta.LineNumberTable;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * An interface for accessing the bytecode properties of a {@link ResolvedJavaMethod} that allows
+ * for different properties than those returned by {@link ResolvedJavaMethod}. Since the bytecode
+ * accessed directly from {@link ResolvedJavaMethod} may have been subject to bytecode
+ * instrumentation and VM rewriting, this indirection can be used to enable access to the original
+ * bytecode of a method (i.e., as defined in a class file).
+ */
+public interface Bytecode {
+
+    /**
+     * Gets the method this object supplies bytecode for.
+     */
+    ResolvedJavaMethod getMethod();
+
+    byte[] getCode();
+
+    int getCodeSize();
+
+    int getMaxStackSize();
+
+    int getMaxLocals();
+
+    ConstantPool getConstantPool();
+
+    LineNumberTable getLineNumberTable();
+
+    LocalVariableTable getLocalVariableTable();
+
+    StackTraceElement asStackTraceElement(int bci);
+
+    ProfilingInfo getProfilingInfo();
+
+    ExceptionHandler[] getExceptionHandlers();
+
+    static String toLocation(Bytecode bytecode, int bci) {
+        return appendLocation(new StringBuilder(), bytecode, bci).toString();
+    }
+
+    static StringBuilder appendLocation(StringBuilder sb, Bytecode bytecode, int bci) {
+        if (bytecode != null) {
+            StackTraceElement ste = bytecode.asStackTraceElement(bci);
+            if (ste.getFileName() != null && ste.getLineNumber() > 0) {
+                sb.append(ste);
+            } else {
+                sb.append(bytecode.getMethod().format("%H.%n(%p)"));
+            }
+        } else {
+            sb.append("Null method");
+        }
+        return sb.append(" [bci: ").append(bci).append(']');
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java
new file mode 100644
index 0000000..c295dae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.INSTANCEOF;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEW;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.RET;
+import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Utility for producing a {@code javap}-like disassembly of bytecode.
+ */
+public class BytecodeDisassembler {
+
+    /**
+     * Specifies if the disassembly for a single instruction can span multiple lines.
+     */
+    private final boolean multiline;
+
+    private final boolean newLine;
+
+    public BytecodeDisassembler(boolean multiline, boolean newLine) {
+        this.multiline = multiline;
+        this.newLine = newLine;
+    }
+
+    public BytecodeDisassembler(boolean multiline) {
+        this(multiline, true);
+    }
+
+    public BytecodeDisassembler() {
+        this(true, true);
+    }
+
+    public static String disassembleOne(ResolvedJavaMethod method, int bci) {
+        return new BytecodeDisassembler(false, false).disassemble(method, bci, bci);
+    }
+
+    /**
+     * Disassembles the bytecode of a given method in a {@code javap}-like format.
+     *
+     * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
+     */
+    public String disassemble(ResolvedJavaMethod method) {
+        return disassemble(method, 0, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Disassembles the bytecode of a given method in a {@code javap}-like format.
+     *
+     * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
+     */
+    public String disassemble(ResolvedJavaMethod method, int startBci, int endBci) {
+        return disassemble(new ResolvedJavaMethodBytecode(method), startBci, endBci);
+    }
+
+    /**
+     * Disassembles {@code code} in a {@code javap}-like format.
+     */
+    public String disassemble(Bytecode code) {
+        return disassemble(code, 0, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Disassembles {@code code} in a {@code javap}-like format.
+     */
+    public String disassemble(Bytecode code, int startBci, int endBci) {
+        if (code.getCode() == null) {
+            return null;
+        }
+        ResolvedJavaMethod method = code.getMethod();
+        ConstantPool cp = code.getConstantPool();
+        BytecodeStream stream = new BytecodeStream(code.getCode());
+        StringBuilder buf = new StringBuilder();
+        int opcode = stream.currentBC();
+        try {
+            while (opcode != Bytecodes.END) {
+                int bci = stream.currentBCI();
+                if (bci >= startBci && bci <= endBci) {
+                    String mnemonic = Bytecodes.nameOf(opcode);
+                    buf.append(String.format("%4d: %-14s", bci, mnemonic));
+                    if (stream.nextBCI() > bci + 1) {
+                        decodeOperand(buf, stream, cp, method, bci, opcode);
+                    }
+                    if (newLine) {
+                        buf.append(String.format("%n"));
+                    }
+                }
+                stream.next();
+                opcode = stream.currentBC();
+            }
+        } catch (RuntimeException e) {
+            throw new RuntimeException(String.format("Error disassembling %s%nPartial disassembly:%n%s", method.format("%H.%n(%p)"), buf.toString()), e);
+        }
+        return buf.toString();
+    }
+
+    private void decodeOperand(StringBuilder buf, BytecodeStream stream, ConstantPool cp, ResolvedJavaMethod method, int bci, int opcode) {
+        // @formatter:off
+        switch (opcode) {
+            case BIPUSH         : buf.append(stream.readByte()); break;
+            case SIPUSH         : buf.append(stream.readShort()); break;
+            case NEW            :
+            case CHECKCAST      :
+            case INSTANCEOF     :
+            case ANEWARRAY      : {
+                int cpi = stream.readCPI();
+                JavaType type = cp.lookupType(cpi, opcode);
+                buf.append(String.format("#%-10d // %s", cpi, type.toJavaName()));
+                break;
+            }
+            case GETSTATIC      :
+            case PUTSTATIC      :
+            case GETFIELD       :
+            case PUTFIELD       : {
+                int cpi = stream.readCPI();
+                JavaField field = cp.lookupField(cpi, method, opcode);
+                String fieldDesc = field.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? field.format("%n:%T") : field.format("%H.%n:%T");
+                buf.append(String.format("#%-10d // %s", cpi, fieldDesc));
+                break;
+            }
+            case INVOKEVIRTUAL  :
+            case INVOKESPECIAL  :
+            case INVOKESTATIC   : {
+                int cpi = stream.readCPI();
+                JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
+                buf.append(String.format("#%-10d // %s", cpi, calleeDesc));
+                break;
+            }
+            case INVOKEINTERFACE: {
+                int cpi = stream.readCPI();
+                JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
+                buf.append(String.format("#%-10s // %s", cpi + ", " + stream.readUByte(bci + 3), calleeDesc));
+                break;
+            }
+            case INVOKEDYNAMIC: {
+                int cpi = stream.readCPI4();
+                JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
+                buf.append(String.format("#%-10d // %s", cpi, calleeDesc));
+                break;
+            }
+            case LDC            :
+            case LDC_W          :
+            case LDC2_W         : {
+                int cpi = stream.readCPI();
+                Object constant = cp.lookupConstant(cpi);
+                String desc = null;
+                if (constant instanceof JavaConstant) {
+                    JavaConstant c = ((JavaConstant) constant);
+                    desc = c.toValueString();
+                } else {
+                    desc = constant.toString();
+                }
+                if (!multiline) {
+                    desc = desc.replaceAll("\\n", "");
+                }
+                buf.append(String.format("#%-10d // %s", cpi, desc));
+                break;
+            }
+            case RET            :
+            case ILOAD          :
+            case LLOAD          :
+            case FLOAD          :
+            case DLOAD          :
+            case ALOAD          :
+            case ISTORE         :
+            case LSTORE         :
+            case FSTORE         :
+            case DSTORE         :
+            case ASTORE         : {
+                buf.append(String.format("%d", stream.readLocalIndex()));
+                break;
+            }
+            case IFEQ           :
+            case IFNE           :
+            case IFLT           :
+            case IFGE           :
+            case IFGT           :
+            case IFLE           :
+            case IF_ICMPEQ      :
+            case IF_ICMPNE      :
+            case IF_ICMPLT      :
+            case IF_ICMPGE      :
+            case IF_ICMPGT      :
+            case IF_ICMPLE      :
+            case IF_ACMPEQ      :
+            case IF_ACMPNE      :
+            case GOTO           :
+            case JSR            :
+            case IFNULL         :
+            case IFNONNULL      :
+            case GOTO_W         :
+            case JSR_W          : {
+                buf.append(String.format("%d", stream.readBranchDest()));
+                break;
+            }
+            case LOOKUPSWITCH   :
+            case TABLESWITCH    : {
+                BytecodeSwitch bswitch = opcode == LOOKUPSWITCH ? new BytecodeLookupSwitch(stream, bci) : new BytecodeTableSwitch(stream, bci);
+                if (multiline) {
+                    buf.append("{ // " + bswitch.numberOfCases());
+                    for (int i = 0; i < bswitch.numberOfCases(); i++) {
+                        buf.append(String.format("%n           %7d: %d", bswitch.keyAt(i), bswitch.targetAt(i)));
+                    }
+                    buf.append(String.format("%n           default: %d", bswitch.defaultTarget()));
+                    buf.append(String.format("%n      }"));
+                } else {
+                    buf.append("[" + bswitch.numberOfCases()).append("] {");
+                    for (int i = 0; i < bswitch.numberOfCases(); i++) {
+                        buf.append(String.format("%d: %d", bswitch.keyAt(i), bswitch.targetAt(i)));
+                        if (i != bswitch.numberOfCases() - 1) {
+                            buf.append(", ");
+                        }
+                    }
+                    buf.append(String.format("} default: %d", bswitch.defaultTarget()));
+                }
+                break;
+            }
+            case NEWARRAY       : {
+                int typecode = stream.readLocalIndex();
+                // Checkstyle: stop
+                switch (typecode) {
+                    case 4:  buf.append("boolean"); break;
+                    case 5:  buf.append("char"); break;
+                    case 6:  buf.append("float"); break;
+                    case 7:  buf.append("double"); break;
+                    case 8:  buf.append("byte"); break;
+                    case 9:  buf.append("short"); break;
+                    case 10: buf.append("int"); break;
+                    case 11: buf.append("long"); break;
+                }
+                // Checkstyle: resume
+
+                break;
+            }
+            case MULTIANEWARRAY : {
+                int cpi = stream.readCPI();
+                JavaType type = cp.lookupType(cpi, opcode);
+                buf.append(String.format("#%-10s // %s", cpi + ", " + stream.readUByte(bci + 3), type.toJavaName()));
+                break;
+            }
+        }
+        // @formatter:on
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeLookupSwitch.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeLookupSwitch.java
new file mode 100644
index 0000000..7863f6c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeLookupSwitch.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+/**
+ * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes.
+ */
+public class BytecodeLookupSwitch extends BytecodeSwitch {
+
+    private static final int OFFSET_TO_NUMBER_PAIRS = 4;
+    private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8;
+    private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12;
+    private static final int PAIR_SIZE = 8;
+
+    /**
+     * Constructor for a {@link BytecodeStream}.
+     *
+     * @param stream the {@code BytecodeStream} containing the switch instruction
+     * @param bci the index in the stream of the switch instruction
+     */
+    public BytecodeLookupSwitch(BytecodeStream stream, int bci) {
+        super(stream, bci);
+    }
+
+    @Override
+    public int offsetAt(int i) {
+        return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_OFFSET + PAIR_SIZE * i);
+    }
+
+    @Override
+    public int keyAt(int i) {
+        return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * i);
+    }
+
+    @Override
+    public int numberOfCases() {
+        return stream.readInt(alignedBci + OFFSET_TO_NUMBER_PAIRS);
+    }
+
+    @Override
+    public int size() {
+        return alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * numberOfCases() - bci;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeProvider.java
new file mode 100644
index 0000000..210cacb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Provides a {@link Bytecode} object for interposing on the bytecode of a
+ * {@link ResolvedJavaMethod} (i.e., potentially getting bytecode different than
+ * {@link ResolvedJavaMethod#getCode()}).
+ */
+public interface BytecodeProvider {
+
+    /**
+     * Gets a {@link Bytecode} object that supplies bytecode properties for {@code method}.
+     */
+    Bytecode getBytecode(ResolvedJavaMethod method);
+
+    /**
+     * Determines if this provider supports the INVOKEDYNAMIC bytecode.
+     */
+    boolean supportsInvokedynamic();
+
+    /**
+     * Determines if methods parsed using this provider should be recorded so that method
+     * redefinition can invalidate the resulting code.
+     */
+    boolean shouldRecordMethodDependencies();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeStream.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeStream.java
new file mode 100644
index 0000000..b4accd6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeStream.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+/**
+ * A utility class that makes iterating over bytecodes and reading operands simpler and less error
+ * prone. For example, it handles the {@link Bytecodes#WIDE} instruction and wide variants of
+ * instructions internally.
+ */
+public final class BytecodeStream {
+
+    private final byte[] code;
+    private int opcode;
+    private int curBCI;
+    private int nextBCI;
+
+    /**
+     * Creates a new {@code BytecodeStream} for the specified bytecode.
+     *
+     * @param code the array of bytes that contains the bytecode
+     */
+    public BytecodeStream(byte[] code) {
+        assert code != null;
+        this.code = code;
+        setBCI(0);
+    }
+
+    /**
+     * Advances to the next bytecode.
+     */
+    public void next() {
+        setBCI(nextBCI);
+    }
+
+    /**
+     * Gets the next bytecode index (no side-effects).
+     *
+     * @return the next bytecode index
+     */
+    public int nextBCI() {
+        return nextBCI;
+    }
+
+    /**
+     * Gets the current bytecode index.
+     *
+     * @return the current bytecode index
+     */
+    public int currentBCI() {
+        return curBCI;
+    }
+
+    /**
+     * Gets the bytecode index of the end of the code.
+     *
+     * @return the index of the end of the code
+     */
+    public int endBCI() {
+        return code.length;
+    }
+
+    /**
+     * Gets the current opcode. This method will never return the {@link Bytecodes#WIDE WIDE}
+     * opcode, but will instead return the opcode that is modified by the {@code WIDE} opcode.
+     *
+     * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code
+     */
+    public int currentBC() {
+        if (opcode == Bytecodes.WIDE) {
+            return Bytes.beU1(code, curBCI + 1);
+        } else {
+            return opcode;
+        }
+    }
+
+    /**
+     * Reads the index of a local variable for one of the load or store instructions. The WIDE
+     * modifier is handled internally.
+     *
+     * @return the index of the local variable
+     */
+    public int readLocalIndex() {
+        // read local variable index for load/store
+        if (opcode == Bytecodes.WIDE) {
+            return Bytes.beU2(code, curBCI + 2);
+        }
+        return Bytes.beU1(code, curBCI + 1);
+    }
+
+    /**
+     * Read the delta for an {@link Bytecodes#IINC} bytecode.
+     *
+     * @return the delta for the {@code IINC}
+     */
+    public int readIncrement() {
+        // read the delta for the iinc bytecode
+        if (opcode == Bytecodes.WIDE) {
+            return Bytes.beS2(code, curBCI + 4);
+        }
+        return Bytes.beS1(code, curBCI + 2);
+    }
+
+    /**
+     * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions.
+     *
+     * @return the destination bytecode index
+     */
+    public int readBranchDest() {
+        // reads the destination for a branch bytecode
+        if (opcode == Bytecodes.GOTO_W || opcode == Bytecodes.JSR_W) {
+            return curBCI + Bytes.beS4(code, curBCI + 1);
+        } else {
+            return curBCI + Bytes.beS2(code, curBCI + 1);
+        }
+    }
+
+    /**
+     * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index.
+     *
+     * @param bci the bytecode index
+     * @return the integer value
+     */
+    public int readInt(int bci) {
+        // reads a 4-byte signed value
+        return Bytes.beS4(code, bci);
+    }
+
+    /**
+     * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index.
+     *
+     * @param bci the bytecode index
+     * @return the byte
+     */
+    public int readUByte(int bci) {
+        return Bytes.beU1(code, bci);
+    }
+
+    /**
+     * Reads a constant pool index for the current instruction.
+     *
+     * @return the constant pool index
+     */
+    public char readCPI() {
+        if (opcode == Bytecodes.LDC) {
+            return (char) Bytes.beU1(code, curBCI + 1);
+        }
+        return (char) Bytes.beU2(code, curBCI + 1);
+    }
+
+    /**
+     * Reads a constant pool index for an invokedynamic instruction.
+     *
+     * @return the constant pool index
+     */
+    public int readCPI4() {
+        assert opcode == Bytecodes.INVOKEDYNAMIC;
+        return Bytes.beS4(code, curBCI + 1);
+    }
+
+    /**
+     * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH).
+     *
+     * @return the byte
+     */
+    public byte readByte() {
+        return code[curBCI + 1];
+    }
+
+    /**
+     * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH).
+     *
+     * @return the short value
+     */
+    public short readShort() {
+        return (short) Bytes.beS2(code, curBCI + 1);
+    }
+
+    /**
+     * Sets the bytecode index to the specified value. If {@code bci} is beyond the end of the
+     * array, {@link #currentBC} will return {@link Bytecodes#END} and other methods may throw
+     * {@link ArrayIndexOutOfBoundsException}.
+     *
+     * @param bci the new bytecode index
+     */
+    public void setBCI(int bci) {
+        curBCI = bci;
+        if (curBCI < code.length) {
+            opcode = Bytes.beU1(code, bci);
+            assert opcode < Bytecodes.BREAKPOINT : "illegal bytecode";
+            nextBCI = bci + lengthOf();
+        } else {
+            opcode = Bytecodes.END;
+            nextBCI = curBCI;
+        }
+    }
+
+    /**
+     * Gets the length of the current bytecode.
+     */
+    private int lengthOf() {
+        int length = Bytecodes.lengthOf(opcode);
+        if (length == 0) {
+            switch (opcode) {
+                case Bytecodes.TABLESWITCH: {
+                    return new BytecodeTableSwitch(this, curBCI).size();
+                }
+                case Bytecodes.LOOKUPSWITCH: {
+                    return new BytecodeLookupSwitch(this, curBCI).size();
+                }
+                case Bytecodes.WIDE: {
+                    int opc = Bytes.beU1(code, curBCI + 1);
+                    if (opc == Bytecodes.RET) {
+                        return 4;
+                    } else if (opc == Bytecodes.IINC) {
+                        return 6;
+                    } else {
+                        return 4; // a load or store bytecode
+                    }
+                }
+                default:
+                    throw new Error("unknown variable-length bytecode: " + opcode);
+            }
+        }
+        return length;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeSwitch.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeSwitch.java
new file mode 100644
index 0000000..facaf4a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeSwitch.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+/**
+ * An abstract class that provides the state and methods common to {@link Bytecodes#LOOKUPSWITCH}
+ * and {@link Bytecodes#TABLESWITCH} instructions.
+ */
+public abstract class BytecodeSwitch {
+
+    /**
+     * The {@link BytecodeStream} containing the bytecode array.
+     */
+    protected final BytecodeStream stream;
+    /**
+     * Index of start of switch instruction.
+     */
+    protected final int bci;
+    /**
+     * Index of the start of the additional data for the switch instruction, aligned to a multiple
+     * of four from the method start.
+     */
+    protected final int alignedBci;
+
+    /**
+     * Constructor for a {@link BytecodeStream}.
+     *
+     * @param stream the {@code BytecodeStream} containing the switch instruction
+     * @param bci the index in the stream of the switch instruction
+     */
+    public BytecodeSwitch(BytecodeStream stream, int bci) {
+        this.stream = stream;
+        this.bci = bci;
+        this.alignedBci = (bci + 4) & 0xfffffffc;
+    }
+
+    /**
+     * Gets the current bytecode index.
+     *
+     * @return the current bytecode index
+     */
+    public int bci() {
+        return bci;
+    }
+
+    /**
+     * Gets the index of the instruction denoted by the {@code i}'th switch target.
+     *
+     * @param i index of the switch target
+     * @return the index of the instruction denoted by the {@code i}'th switch target
+     */
+    public int targetAt(int i) {
+        return bci + offsetAt(i);
+    }
+
+    /**
+     * Gets the index of the instruction for the default switch target.
+     *
+     * @return the index of the instruction for the default switch target
+     */
+    public int defaultTarget() {
+        return bci + defaultOffset();
+    }
+
+    /**
+     * Gets the offset from the start of the switch instruction to the default switch target.
+     *
+     * @return the offset to the default switch target
+     */
+    public int defaultOffset() {
+        return stream.readInt(alignedBci);
+    }
+
+    /**
+     * Gets the key at {@code i}'th switch target index.
+     *
+     * @param i the switch target index
+     * @return the key at {@code i}'th switch target index
+     */
+    public abstract int keyAt(int i);
+
+    /**
+     * Gets the offset from the start of the switch instruction for the {@code i}'th switch target.
+     *
+     * @param i the switch target index
+     * @return the offset to the {@code i}'th switch target
+     */
+    public abstract int offsetAt(int i);
+
+    /**
+     * Gets the number of switch targets.
+     *
+     * @return the number of switch targets
+     */
+    public abstract int numberOfCases();
+
+    /**
+     * Gets the total size in bytes of the switch instruction.
+     *
+     * @return the total size in bytes of the switch instruction
+     */
+    public abstract int size();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeTableSwitch.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeTableSwitch.java
new file mode 100644
index 0000000..5e2d048
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeTableSwitch.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+/**
+ * A utility for processing {@link Bytecodes#TABLESWITCH} bytecodes.
+ */
+public class BytecodeTableSwitch extends BytecodeSwitch {
+
+    private static final int OFFSET_TO_LOW_KEY = 4;
+    private static final int OFFSET_TO_HIGH_KEY = 8;
+    private static final int OFFSET_TO_FIRST_JUMP_OFFSET = 12;
+    private static final int JUMP_OFFSET_SIZE = 4;
+
+    /**
+     * Constructor for a {@link BytecodeStream}.
+     *
+     * @param stream the {@code BytecodeStream} containing the switch instruction
+     * @param bci the index in the stream of the switch instruction
+     */
+    public BytecodeTableSwitch(BytecodeStream stream, int bci) {
+        super(stream, bci);
+    }
+
+    /**
+     * Gets the low key of the table switch.
+     *
+     * @return the low key
+     */
+    public int lowKey() {
+        return stream.readInt(alignedBci + OFFSET_TO_LOW_KEY);
+    }
+
+    /**
+     * Gets the high key of the table switch.
+     *
+     * @return the high key
+     */
+    public int highKey() {
+        return stream.readInt(alignedBci + OFFSET_TO_HIGH_KEY);
+    }
+
+    @Override
+    public int keyAt(int i) {
+        return lowKey() + i;
+    }
+
+    @Override
+    public int offsetAt(int i) {
+        return stream.readInt(alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * i);
+    }
+
+    @Override
+    public int numberOfCases() {
+        return highKey() - lowKey() + 1;
+    }
+
+    @Override
+    public int size() {
+        return alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * numberOfCases() - bci;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java
new file mode 100644
index 0000000..d2d0436
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java
@@ -0,0 +1,840 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.ASSOCIATIVE;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.BRANCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.COMMUTATIVE;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FALL_THROUGH;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FIELD_READ;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.FIELD_WRITE;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.INVOKE;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.LOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.STOP;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.STORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.Flags.TRAP;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * Definitions of the standard Java bytecodes defined by
+ * <a href= "http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html"> Java
+ * Virtual Machine Specification</a>.
+ */
+public class Bytecodes {
+
+    // @formatter:off
+    public static final int NOP                  =   0; // 0x00
+    public static final int ACONST_NULL          =   1; // 0x01
+    public static final int ICONST_M1            =   2; // 0x02
+    public static final int ICONST_0             =   3; // 0x03
+    public static final int ICONST_1             =   4; // 0x04
+    public static final int ICONST_2             =   5; // 0x05
+    public static final int ICONST_3             =   6; // 0x06
+    public static final int ICONST_4             =   7; // 0x07
+    public static final int ICONST_5             =   8; // 0x08
+    public static final int LCONST_0             =   9; // 0x09
+    public static final int LCONST_1             =  10; // 0x0A
+    public static final int FCONST_0             =  11; // 0x0B
+    public static final int FCONST_1             =  12; // 0x0C
+    public static final int FCONST_2             =  13; // 0x0D
+    public static final int DCONST_0             =  14; // 0x0E
+    public static final int DCONST_1             =  15; // 0x0F
+    public static final int BIPUSH               =  16; // 0x10
+    public static final int SIPUSH               =  17; // 0x11
+    public static final int LDC                  =  18; // 0x12
+    public static final int LDC_W                =  19; // 0x13
+    public static final int LDC2_W               =  20; // 0x14
+    public static final int ILOAD                =  21; // 0x15
+    public static final int LLOAD                =  22; // 0x16
+    public static final int FLOAD                =  23; // 0x17
+    public static final int DLOAD                =  24; // 0x18
+    public static final int ALOAD                =  25; // 0x19
+    public static final int ILOAD_0              =  26; // 0x1A
+    public static final int ILOAD_1              =  27; // 0x1B
+    public static final int ILOAD_2              =  28; // 0x1C
+    public static final int ILOAD_3              =  29; // 0x1D
+    public static final int LLOAD_0              =  30; // 0x1E
+    public static final int LLOAD_1              =  31; // 0x1F
+    public static final int LLOAD_2              =  32; // 0x20
+    public static final int LLOAD_3              =  33; // 0x21
+    public static final int FLOAD_0              =  34; // 0x22
+    public static final int FLOAD_1              =  35; // 0x23
+    public static final int FLOAD_2              =  36; // 0x24
+    public static final int FLOAD_3              =  37; // 0x25
+    public static final int DLOAD_0              =  38; // 0x26
+    public static final int DLOAD_1              =  39; // 0x27
+    public static final int DLOAD_2              =  40; // 0x28
+    public static final int DLOAD_3              =  41; // 0x29
+    public static final int ALOAD_0              =  42; // 0x2A
+    public static final int ALOAD_1              =  43; // 0x2B
+    public static final int ALOAD_2              =  44; // 0x2C
+    public static final int ALOAD_3              =  45; // 0x2D
+    public static final int IALOAD               =  46; // 0x2E
+    public static final int LALOAD               =  47; // 0x2F
+    public static final int FALOAD               =  48; // 0x30
+    public static final int DALOAD               =  49; // 0x31
+    public static final int AALOAD               =  50; // 0x32
+    public static final int BALOAD               =  51; // 0x33
+    public static final int CALOAD               =  52; // 0x34
+    public static final int SALOAD               =  53; // 0x35
+    public static final int ISTORE               =  54; // 0x36
+    public static final int LSTORE               =  55; // 0x37
+    public static final int FSTORE               =  56; // 0x38
+    public static final int DSTORE               =  57; // 0x39
+    public static final int ASTORE               =  58; // 0x3A
+    public static final int ISTORE_0             =  59; // 0x3B
+    public static final int ISTORE_1             =  60; // 0x3C
+    public static final int ISTORE_2             =  61; // 0x3D
+    public static final int ISTORE_3             =  62; // 0x3E
+    public static final int LSTORE_0             =  63; // 0x3F
+    public static final int LSTORE_1             =  64; // 0x40
+    public static final int LSTORE_2             =  65; // 0x41
+    public static final int LSTORE_3             =  66; // 0x42
+    public static final int FSTORE_0             =  67; // 0x43
+    public static final int FSTORE_1             =  68; // 0x44
+    public static final int FSTORE_2             =  69; // 0x45
+    public static final int FSTORE_3             =  70; // 0x46
+    public static final int DSTORE_0             =  71; // 0x47
+    public static final int DSTORE_1             =  72; // 0x48
+    public static final int DSTORE_2             =  73; // 0x49
+    public static final int DSTORE_3             =  74; // 0x4A
+    public static final int ASTORE_0             =  75; // 0x4B
+    public static final int ASTORE_1             =  76; // 0x4C
+    public static final int ASTORE_2             =  77; // 0x4D
+    public static final int ASTORE_3             =  78; // 0x4E
+    public static final int IASTORE              =  79; // 0x4F
+    public static final int LASTORE              =  80; // 0x50
+    public static final int FASTORE              =  81; // 0x51
+    public static final int DASTORE              =  82; // 0x52
+    public static final int AASTORE              =  83; // 0x53
+    public static final int BASTORE              =  84; // 0x54
+    public static final int CASTORE              =  85; // 0x55
+    public static final int SASTORE              =  86; // 0x56
+    public static final int POP                  =  87; // 0x57
+    public static final int POP2                 =  88; // 0x58
+    public static final int DUP                  =  89; // 0x59
+    public static final int DUP_X1               =  90; // 0x5A
+    public static final int DUP_X2               =  91; // 0x5B
+    public static final int DUP2                 =  92; // 0x5C
+    public static final int DUP2_X1              =  93; // 0x5D
+    public static final int DUP2_X2              =  94; // 0x5E
+    public static final int SWAP                 =  95; // 0x5F
+    public static final int IADD                 =  96; // 0x60
+    public static final int LADD                 =  97; // 0x61
+    public static final int FADD                 =  98; // 0x62
+    public static final int DADD                 =  99; // 0x63
+    public static final int ISUB                 = 100; // 0x64
+    public static final int LSUB                 = 101; // 0x65
+    public static final int FSUB                 = 102; // 0x66
+    public static final int DSUB                 = 103; // 0x67
+    public static final int IMUL                 = 104; // 0x68
+    public static final int LMUL                 = 105; // 0x69
+    public static final int FMUL                 = 106; // 0x6A
+    public static final int DMUL                 = 107; // 0x6B
+    public static final int IDIV                 = 108; // 0x6C
+    public static final int LDIV                 = 109; // 0x6D
+    public static final int FDIV                 = 110; // 0x6E
+    public static final int DDIV                 = 111; // 0x6F
+    public static final int IREM                 = 112; // 0x70
+    public static final int LREM                 = 113; // 0x71
+    public static final int FREM                 = 114; // 0x72
+    public static final int DREM                 = 115; // 0x73
+    public static final int INEG                 = 116; // 0x74
+    public static final int LNEG                 = 117; // 0x75
+    public static final int FNEG                 = 118; // 0x76
+    public static final int DNEG                 = 119; // 0x77
+    public static final int ISHL                 = 120; // 0x78
+    public static final int LSHL                 = 121; // 0x79
+    public static final int ISHR                 = 122; // 0x7A
+    public static final int LSHR                 = 123; // 0x7B
+    public static final int IUSHR                = 124; // 0x7C
+    public static final int LUSHR                = 125; // 0x7D
+    public static final int IAND                 = 126; // 0x7E
+    public static final int LAND                 = 127; // 0x7F
+    public static final int IOR                  = 128; // 0x80
+    public static final int LOR                  = 129; // 0x81
+    public static final int IXOR                 = 130; // 0x82
+    public static final int LXOR                 = 131; // 0x83
+    public static final int IINC                 = 132; // 0x84
+    public static final int I2L                  = 133; // 0x85
+    public static final int I2F                  = 134; // 0x86
+    public static final int I2D                  = 135; // 0x87
+    public static final int L2I                  = 136; // 0x88
+    public static final int L2F                  = 137; // 0x89
+    public static final int L2D                  = 138; // 0x8A
+    public static final int F2I                  = 139; // 0x8B
+    public static final int F2L                  = 140; // 0x8C
+    public static final int F2D                  = 141; // 0x8D
+    public static final int D2I                  = 142; // 0x8E
+    public static final int D2L                  = 143; // 0x8F
+    public static final int D2F                  = 144; // 0x90
+    public static final int I2B                  = 145; // 0x91
+    public static final int I2C                  = 146; // 0x92
+    public static final int I2S                  = 147; // 0x93
+    public static final int LCMP                 = 148; // 0x94
+    public static final int FCMPL                = 149; // 0x95
+    public static final int FCMPG                = 150; // 0x96
+    public static final int DCMPL                = 151; // 0x97
+    public static final int DCMPG                = 152; // 0x98
+    public static final int IFEQ                 = 153; // 0x99
+    public static final int IFNE                 = 154; // 0x9A
+    public static final int IFLT                 = 155; // 0x9B
+    public static final int IFGE                 = 156; // 0x9C
+    public static final int IFGT                 = 157; // 0x9D
+    public static final int IFLE                 = 158; // 0x9E
+    public static final int IF_ICMPEQ            = 159; // 0x9F
+    public static final int IF_ICMPNE            = 160; // 0xA0
+    public static final int IF_ICMPLT            = 161; // 0xA1
+    public static final int IF_ICMPGE            = 162; // 0xA2
+    public static final int IF_ICMPGT            = 163; // 0xA3
+    public static final int IF_ICMPLE            = 164; // 0xA4
+    public static final int IF_ACMPEQ            = 165; // 0xA5
+    public static final int IF_ACMPNE            = 166; // 0xA6
+    public static final int GOTO                 = 167; // 0xA7
+    public static final int JSR                  = 168; // 0xA8
+    public static final int RET                  = 169; // 0xA9
+    public static final int TABLESWITCH          = 170; // 0xAA
+    public static final int LOOKUPSWITCH         = 171; // 0xAB
+    public static final int IRETURN              = 172; // 0xAC
+    public static final int LRETURN              = 173; // 0xAD
+    public static final int FRETURN              = 174; // 0xAE
+    public static final int DRETURN              = 175; // 0xAF
+    public static final int ARETURN              = 176; // 0xB0
+    public static final int RETURN               = 177; // 0xB1
+    public static final int GETSTATIC            = 178; // 0xB2
+    public static final int PUTSTATIC            = 179; // 0xB3
+    public static final int GETFIELD             = 180; // 0xB4
+    public static final int PUTFIELD             = 181; // 0xB5
+    public static final int INVOKEVIRTUAL        = 182; // 0xB6
+    public static final int INVOKESPECIAL        = 183; // 0xB7
+    public static final int INVOKESTATIC         = 184; // 0xB8
+    public static final int INVOKEINTERFACE      = 185; // 0xB9
+    public static final int INVOKEDYNAMIC        = 186; // 0xBA
+    public static final int NEW                  = 187; // 0xBB
+    public static final int NEWARRAY             = 188; // 0xBC
+    public static final int ANEWARRAY            = 189; // 0xBD
+    public static final int ARRAYLENGTH          = 190; // 0xBE
+    public static final int ATHROW               = 191; // 0xBF
+    public static final int CHECKCAST            = 192; // 0xC0
+    public static final int INSTANCEOF           = 193; // 0xC1
+    public static final int MONITORENTER         = 194; // 0xC2
+    public static final int MONITOREXIT          = 195; // 0xC3
+    public static final int WIDE                 = 196; // 0xC4
+    public static final int MULTIANEWARRAY       = 197; // 0xC5
+    public static final int IFNULL               = 198; // 0xC6
+    public static final int IFNONNULL            = 199; // 0xC7
+    public static final int GOTO_W               = 200; // 0xC8
+    public static final int JSR_W                = 201; // 0xC9
+    public static final int BREAKPOINT           = 202; // 0xCA
+
+    public static final int ILLEGAL = 255;
+    public static final int END = 256;
+    // @formatter:on
+
+    /**
+     * The last opcode defined by the JVM specification. To iterate over all JVM bytecodes:
+     *
+     * <pre>
+     * for (int opcode = 0; opcode &lt;= Bytecodes.LAST_JVM_OPCODE; ++opcode) {
+     *     //
+     * }
+     * </pre>
+     */
+    public static final int LAST_JVM_OPCODE = JSR_W;
+
+    /**
+     * A collection of flags describing various bytecode attributes.
+     */
+    static class Flags {
+
+        /**
+         * Denotes an instruction that ends a basic block and does not let control flow fall through
+         * to its lexical successor.
+         */
+        static final int STOP = 0x00000001;
+
+        /**
+         * Denotes an instruction that ends a basic block and may let control flow fall through to
+         * its lexical successor. In practice this means it is a conditional branch.
+         */
+        static final int FALL_THROUGH = 0x00000002;
+
+        /**
+         * Denotes an instruction that has a 2 or 4 byte operand that is an offset to another
+         * instruction in the same method. This does not include the {@link Bytecodes#TABLESWITCH}
+         * or {@link Bytecodes#LOOKUPSWITCH} instructions.
+         */
+        static final int BRANCH = 0x00000004;
+
+        /**
+         * Denotes an instruction that reads the value of a static or instance field.
+         */
+        static final int FIELD_READ = 0x00000008;
+
+        /**
+         * Denotes an instruction that writes the value of a static or instance field.
+         */
+        static final int FIELD_WRITE = 0x00000010;
+
+        /**
+         * Denotes an instruction that can cause a trap.
+         */
+        static final int TRAP = 0x00000080;
+        /**
+         * Denotes an instruction that is commutative.
+         */
+        static final int COMMUTATIVE = 0x00000100;
+        /**
+         * Denotes an instruction that is associative.
+         */
+        static final int ASSOCIATIVE = 0x00000200;
+        /**
+         * Denotes an instruction that loads an operand.
+         */
+        static final int LOAD = 0x00000400;
+        /**
+         * Denotes an instruction that stores an operand.
+         */
+        static final int STORE = 0x00000800;
+        /**
+         * Denotes the 4 INVOKE* instructions.
+         */
+        static final int INVOKE = 0x00001000;
+    }
+
+    // Performs a sanity check that none of the flags overlap.
+    static {
+        int allFlags = 0;
+        try {
+            for (Field field : Flags.class.getDeclaredFields()) {
+                int flagsFilter = Modifier.FINAL | Modifier.STATIC;
+                if ((field.getModifiers() & flagsFilter) == flagsFilter && !field.isSynthetic()) {
+                    assert field.getType() == int.class : "Field is not int : " + field;
+                    final int flag = field.getInt(null);
+                    assert flag != 0;
+                    assert (flag & allFlags) == 0 : field.getName() + " has a value conflicting with another flag";
+                    allFlags |= flag;
+                }
+            }
+        } catch (Exception e) {
+            throw new InternalError(e.toString());
+        }
+    }
+
+    /**
+     * An array that maps from a bytecode value to a {@link String} for the corresponding
+     * instruction mnemonic.
+     */
+    private static final String[] nameArray = new String[256];
+
+    /**
+     * An array that maps from a bytecode value to the set of {@link Flags} for the corresponding
+     * instruction.
+     */
+    private static final int[] flagsArray = new int[256];
+
+    /**
+     * An array that maps from a bytecode value to the length in bytes for the corresponding
+     * instruction.
+     */
+    private static final int[] lengthArray = new int[256];
+
+    /**
+     * An array that maps from a bytecode value to the number of slots pushed on the stack by the
+     * corresponding instruction.
+     */
+    private static final int[] stackEffectArray = new int[256];
+
+    // Checkstyle: stop
+    // @formatter:off
+    static {
+        def(NOP                 , "nop"             , "b"    ,  0);
+        def(ACONST_NULL         , "aconst_null"     , "b"    ,  1);
+        def(ICONST_M1           , "iconst_m1"       , "b"    ,  1);
+        def(ICONST_0            , "iconst_0"        , "b"    ,  1);
+        def(ICONST_1            , "iconst_1"        , "b"    ,  1);
+        def(ICONST_2            , "iconst_2"        , "b"    ,  1);
+        def(ICONST_3            , "iconst_3"        , "b"    ,  1);
+        def(ICONST_4            , "iconst_4"        , "b"    ,  1);
+        def(ICONST_5            , "iconst_5"        , "b"    ,  1);
+        def(LCONST_0            , "lconst_0"        , "b"    ,  2);
+        def(LCONST_1            , "lconst_1"        , "b"    ,  2);
+        def(FCONST_0            , "fconst_0"        , "b"    ,  1);
+        def(FCONST_1            , "fconst_1"        , "b"    ,  1);
+        def(FCONST_2            , "fconst_2"        , "b"    ,  1);
+        def(DCONST_0            , "dconst_0"        , "b"    ,  2);
+        def(DCONST_1            , "dconst_1"        , "b"    ,  2);
+        def(BIPUSH              , "bipush"          , "bc"   ,  1);
+        def(SIPUSH              , "sipush"          , "bcc"  ,  1);
+        def(LDC                 , "ldc"             , "bi"   ,  1, TRAP);
+        def(LDC_W               , "ldc_w"           , "bii"  ,  1, TRAP);
+        def(LDC2_W              , "ldc2_w"          , "bii"  ,  2, TRAP);
+        def(ILOAD               , "iload"           , "bi"   ,  1, LOAD);
+        def(LLOAD               , "lload"           , "bi"   ,  2, LOAD);
+        def(FLOAD               , "fload"           , "bi"   ,  1, LOAD);
+        def(DLOAD               , "dload"           , "bi"   ,  2, LOAD);
+        def(ALOAD               , "aload"           , "bi"   ,  1, LOAD);
+        def(ILOAD_0             , "iload_0"         , "b"    ,  1, LOAD);
+        def(ILOAD_1             , "iload_1"         , "b"    ,  1, LOAD);
+        def(ILOAD_2             , "iload_2"         , "b"    ,  1, LOAD);
+        def(ILOAD_3             , "iload_3"         , "b"    ,  1, LOAD);
+        def(LLOAD_0             , "lload_0"         , "b"    ,  2, LOAD);
+        def(LLOAD_1             , "lload_1"         , "b"    ,  2, LOAD);
+        def(LLOAD_2             , "lload_2"         , "b"    ,  2, LOAD);
+        def(LLOAD_3             , "lload_3"         , "b"    ,  2, LOAD);
+        def(FLOAD_0             , "fload_0"         , "b"    ,  1, LOAD);
+        def(FLOAD_1             , "fload_1"         , "b"    ,  1, LOAD);
+        def(FLOAD_2             , "fload_2"         , "b"    ,  1, LOAD);
+        def(FLOAD_3             , "fload_3"         , "b"    ,  1, LOAD);
+        def(DLOAD_0             , "dload_0"         , "b"    ,  2, LOAD);
+        def(DLOAD_1             , "dload_1"         , "b"    ,  2, LOAD);
+        def(DLOAD_2             , "dload_2"         , "b"    ,  2, LOAD);
+        def(DLOAD_3             , "dload_3"         , "b"    ,  2, LOAD);
+        def(ALOAD_0             , "aload_0"         , "b"    ,  1, LOAD);
+        def(ALOAD_1             , "aload_1"         , "b"    ,  1, LOAD);
+        def(ALOAD_2             , "aload_2"         , "b"    ,  1, LOAD);
+        def(ALOAD_3             , "aload_3"         , "b"    ,  1, LOAD);
+        def(IALOAD              , "iaload"          , "b"    , -1, TRAP);
+        def(LALOAD              , "laload"          , "b"    ,  0, TRAP);
+        def(FALOAD              , "faload"          , "b"    , -1, TRAP);
+        def(DALOAD              , "daload"          , "b"    ,  0, TRAP);
+        def(AALOAD              , "aaload"          , "b"    , -1, TRAP);
+        def(BALOAD              , "baload"          , "b"    , -1, TRAP);
+        def(CALOAD              , "caload"          , "b"    , -1, TRAP);
+        def(SALOAD              , "saload"          , "b"    , -1, TRAP);
+        def(ISTORE              , "istore"          , "bi"   , -1, STORE);
+        def(LSTORE              , "lstore"          , "bi"   , -2, STORE);
+        def(FSTORE              , "fstore"          , "bi"   , -1, STORE);
+        def(DSTORE              , "dstore"          , "bi"   , -2, STORE);
+        def(ASTORE              , "astore"          , "bi"   , -1, STORE);
+        def(ISTORE_0            , "istore_0"        , "b"    , -1, STORE);
+        def(ISTORE_1            , "istore_1"        , "b"    , -1, STORE);
+        def(ISTORE_2            , "istore_2"        , "b"    , -1, STORE);
+        def(ISTORE_3            , "istore_3"        , "b"    , -1, STORE);
+        def(LSTORE_0            , "lstore_0"        , "b"    , -2, STORE);
+        def(LSTORE_1            , "lstore_1"        , "b"    , -2, STORE);
+        def(LSTORE_2            , "lstore_2"        , "b"    , -2, STORE);
+        def(LSTORE_3            , "lstore_3"        , "b"    , -2, STORE);
+        def(FSTORE_0            , "fstore_0"        , "b"    , -1, STORE);
+        def(FSTORE_1            , "fstore_1"        , "b"    , -1, STORE);
+        def(FSTORE_2            , "fstore_2"        , "b"    , -1, STORE);
+        def(FSTORE_3            , "fstore_3"        , "b"    , -1, STORE);
+        def(DSTORE_0            , "dstore_0"        , "b"    , -2, STORE);
+        def(DSTORE_1            , "dstore_1"        , "b"    , -2, STORE);
+        def(DSTORE_2            , "dstore_2"        , "b"    , -2, STORE);
+        def(DSTORE_3            , "dstore_3"        , "b"    , -2, STORE);
+        def(ASTORE_0            , "astore_0"        , "b"    , -1, STORE);
+        def(ASTORE_1            , "astore_1"        , "b"    , -1, STORE);
+        def(ASTORE_2            , "astore_2"        , "b"    , -1, STORE);
+        def(ASTORE_3            , "astore_3"        , "b"    , -1, STORE);
+        def(IASTORE             , "iastore"         , "b"    , -3, TRAP);
+        def(LASTORE             , "lastore"         , "b"    , -4, TRAP);
+        def(FASTORE             , "fastore"         , "b"    , -3, TRAP);
+        def(DASTORE             , "dastore"         , "b"    , -4, TRAP);
+        def(AASTORE             , "aastore"         , "b"    , -3, TRAP);
+        def(BASTORE             , "bastore"         , "b"    , -3, TRAP);
+        def(CASTORE             , "castore"         , "b"    , -3, TRAP);
+        def(SASTORE             , "sastore"         , "b"    , -3, TRAP);
+        def(POP                 , "pop"             , "b"    , -1);
+        def(POP2                , "pop2"            , "b"    , -2);
+        def(DUP                 , "dup"             , "b"    ,  1);
+        def(DUP_X1              , "dup_x1"          , "b"    ,  1);
+        def(DUP_X2              , "dup_x2"          , "b"    ,  1);
+        def(DUP2                , "dup2"            , "b"    ,  2);
+        def(DUP2_X1             , "dup2_x1"         , "b"    ,  2);
+        def(DUP2_X2             , "dup2_x2"         , "b"    ,  2);
+        def(SWAP                , "swap"            , "b"    ,  0);
+        def(IADD                , "iadd"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(LADD                , "ladd"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(FADD                , "fadd"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(DADD                , "dadd"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(ISUB                , "isub"            , "b"    , -1);
+        def(LSUB                , "lsub"            , "b"    , -2);
+        def(FSUB                , "fsub"            , "b"    , -1);
+        def(DSUB                , "dsub"            , "b"    , -2);
+        def(IMUL                , "imul"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(LMUL                , "lmul"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(FMUL                , "fmul"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(DMUL                , "dmul"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(IDIV                , "idiv"            , "b"    , -1, TRAP);
+        def(LDIV                , "ldiv"            , "b"    , -2, TRAP);
+        def(FDIV                , "fdiv"            , "b"    , -1);
+        def(DDIV                , "ddiv"            , "b"    , -2);
+        def(IREM                , "irem"            , "b"    , -1, TRAP);
+        def(LREM                , "lrem"            , "b"    , -2, TRAP);
+        def(FREM                , "frem"            , "b"    , -1);
+        def(DREM                , "drem"            , "b"    , -2);
+        def(INEG                , "ineg"            , "b"    ,  0);
+        def(LNEG                , "lneg"            , "b"    ,  0);
+        def(FNEG                , "fneg"            , "b"    ,  0);
+        def(DNEG                , "dneg"            , "b"    ,  0);
+        def(ISHL                , "ishl"            , "b"    , -1);
+        def(LSHL                , "lshl"            , "b"    , -1);
+        def(ISHR                , "ishr"            , "b"    , -1);
+        def(LSHR                , "lshr"            , "b"    , -1);
+        def(IUSHR               , "iushr"           , "b"    , -1);
+        def(LUSHR               , "lushr"           , "b"    , -1);
+        def(IAND                , "iand"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(LAND                , "land"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(IOR                 , "ior"             , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(LOR                 , "lor"             , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(IXOR                , "ixor"            , "b"    , -1, COMMUTATIVE | ASSOCIATIVE);
+        def(LXOR                , "lxor"            , "b"    , -2, COMMUTATIVE | ASSOCIATIVE);
+        def(IINC                , "iinc"            , "bic"  ,  0, LOAD | STORE);
+        def(I2L                 , "i2l"             , "b"    ,  1);
+        def(I2F                 , "i2f"             , "b"    ,  0);
+        def(I2D                 , "i2d"             , "b"    ,  1);
+        def(L2I                 , "l2i"             , "b"    , -1);
+        def(L2F                 , "l2f"             , "b"    , -1);
+        def(L2D                 , "l2d"             , "b"    ,  0);
+        def(F2I                 , "f2i"             , "b"    ,  0);
+        def(F2L                 , "f2l"             , "b"    ,  1);
+        def(F2D                 , "f2d"             , "b"    ,  1);
+        def(D2I                 , "d2i"             , "b"    , -1);
+        def(D2L                 , "d2l"             , "b"    ,  0);
+        def(D2F                 , "d2f"             , "b"    , -1);
+        def(I2B                 , "i2b"             , "b"    ,  0);
+        def(I2C                 , "i2c"             , "b"    ,  0);
+        def(I2S                 , "i2s"             , "b"    ,  0);
+        def(LCMP                , "lcmp"            , "b"    , -3);
+        def(FCMPL               , "fcmpl"           , "b"    , -1);
+        def(FCMPG               , "fcmpg"           , "b"    , -1);
+        def(DCMPL               , "dcmpl"           , "b"    , -3);
+        def(DCMPG               , "dcmpg"           , "b"    , -3);
+        def(IFEQ                , "ifeq"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFNE                , "ifne"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFLT                , "iflt"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFGE                , "ifge"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFGT                , "ifgt"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFLE                , "ifle"            , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IF_ICMPEQ           , "if_icmpeq"       , "boo"  , -2, COMMUTATIVE | FALL_THROUGH | BRANCH);
+        def(IF_ICMPNE           , "if_icmpne"       , "boo"  , -2, COMMUTATIVE | FALL_THROUGH | BRANCH);
+        def(IF_ICMPLT           , "if_icmplt"       , "boo"  , -2, FALL_THROUGH | BRANCH);
+        def(IF_ICMPGE           , "if_icmpge"       , "boo"  , -2, FALL_THROUGH | BRANCH);
+        def(IF_ICMPGT           , "if_icmpgt"       , "boo"  , -2, FALL_THROUGH | BRANCH);
+        def(IF_ICMPLE           , "if_icmple"       , "boo"  , -2, FALL_THROUGH | BRANCH);
+        def(IF_ACMPEQ           , "if_acmpeq"       , "boo"  , -2, COMMUTATIVE | FALL_THROUGH | BRANCH);
+        def(IF_ACMPNE           , "if_acmpne"       , "boo"  , -2, COMMUTATIVE | FALL_THROUGH | BRANCH);
+        def(GOTO                , "goto"            , "boo"  ,  0, STOP | BRANCH);
+        def(JSR                 , "jsr"             , "boo"  ,  0, STOP | BRANCH);
+        def(RET                 , "ret"             , "bi"   ,  0, STOP);
+        def(TABLESWITCH         , "tableswitch"     , ""     , -1, STOP);
+        def(LOOKUPSWITCH        , "lookupswitch"    , ""     , -1, STOP);
+        def(IRETURN             , "ireturn"         , "b"    , -1, TRAP | STOP);
+        def(LRETURN             , "lreturn"         , "b"    , -2, TRAP | STOP);
+        def(FRETURN             , "freturn"         , "b"    , -1, TRAP | STOP);
+        def(DRETURN             , "dreturn"         , "b"    , -2, TRAP | STOP);
+        def(ARETURN             , "areturn"         , "b"    , -1, TRAP | STOP);
+        def(RETURN              , "return"          , "b"    ,  0, TRAP | STOP);
+        def(GETSTATIC           , "getstatic"       , "bjj"  ,  1, TRAP | FIELD_READ);
+        def(PUTSTATIC           , "putstatic"       , "bjj"  , -1, TRAP | FIELD_WRITE);
+        def(GETFIELD            , "getfield"        , "bjj"  ,  0, TRAP | FIELD_READ);
+        def(PUTFIELD            , "putfield"        , "bjj"  , -2, TRAP | FIELD_WRITE);
+        def(INVOKEVIRTUAL       , "invokevirtual"   , "bjj"  , -1, TRAP | INVOKE);
+        def(INVOKESPECIAL       , "invokespecial"   , "bjj"  , -1, TRAP | INVOKE);
+        def(INVOKESTATIC        , "invokestatic"    , "bjj"  ,  0, TRAP | INVOKE);
+        def(INVOKEINTERFACE     , "invokeinterface" , "bjja_", -1, TRAP | INVOKE);
+        def(INVOKEDYNAMIC       , "invokedynamic"   , "bjjjj",  0, TRAP | INVOKE);
+        def(NEW                 , "new"             , "bii"  ,  1, TRAP);
+        def(NEWARRAY            , "newarray"        , "bc"   ,  0, TRAP);
+        def(ANEWARRAY           , "anewarray"       , "bii"  ,  0, TRAP);
+        def(ARRAYLENGTH         , "arraylength"     , "b"    ,  0, TRAP);
+        def(ATHROW              , "athrow"          , "b"    , -1, TRAP | STOP);
+        def(CHECKCAST           , "checkcast"       , "bii"  ,  0, TRAP);
+        def(INSTANCEOF          , "instanceof"      , "bii"  ,  0, TRAP);
+        def(MONITORENTER        , "monitorenter"    , "b"    , -1, TRAP);
+        def(MONITOREXIT         , "monitorexit"     , "b"    , -1, TRAP);
+        def(WIDE                , "wide"            , ""     ,  0);
+        def(MULTIANEWARRAY      , "multianewarray"  , "biic" ,  1, TRAP);
+        def(IFNULL              , "ifnull"          , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(IFNONNULL           , "ifnonnull"       , "boo"  , -1, FALL_THROUGH | BRANCH);
+        def(GOTO_W              , "goto_w"          , "boooo",  0, STOP | BRANCH);
+        def(JSR_W               , "jsr_w"           , "boooo",  0, STOP | BRANCH);
+        def(BREAKPOINT          , "breakpoint"      , "b"    ,  0, TRAP);
+    }
+    // @formatter:on
+    // Checkstyle: resume
+
+    /**
+     * Determines if an opcode is commutative.
+     *
+     * @param opcode the opcode to check
+     * @return {@code true} iff commutative
+     */
+    public static boolean isCommutative(int opcode) {
+        return (flagsArray[opcode & 0xff] & COMMUTATIVE) != 0;
+    }
+
+    /**
+     * Gets the length of an instruction denoted by a given opcode.
+     *
+     * @param opcode an instruction opcode
+     * @return the length of the instruction denoted by {@code opcode}. If {@code opcode} is an
+     *         illegal instruction or denotes a variable length instruction (e.g.
+     *         {@link #TABLESWITCH}), then 0 is returned.
+     */
+    public static int lengthOf(int opcode) {
+        return lengthArray[opcode & 0xff];
+    }
+
+    /**
+     * Gets the effect on the depth of the expression stack of an instruction denoted by a given
+     * opcode.
+     *
+     * @param opcode an instruction opcode
+     * @return the change in the stack caused by the instruction denoted by {@code opcode}. If
+     *         {@code opcode} is an illegal instruction then 0 is returned. Note that invoke
+     *         instructions may pop more arguments so this value is a minimum stack effect.
+     */
+    public static int stackEffectOf(int opcode) {
+        return stackEffectArray[opcode & 0xff];
+    }
+
+    /**
+     * Gets the lower-case mnemonic for a given opcode.
+     *
+     * @param opcode an opcode
+     * @return the mnemonic for {@code opcode} or {@code "<illegal opcode: " + opcode + ">"} if
+     *         {@code opcode} is not a legal opcode
+     */
+    public static String nameOf(int opcode) throws IllegalArgumentException {
+        String name = nameArray[opcode & 0xff];
+        if (name == null) {
+            return "<illegal opcode: " + opcode + ">";
+        }
+        return name;
+    }
+
+    /**
+     * Allocation-free version of {@linkplain #nameOf(int)}.
+     *
+     * @param opcode an opcode.
+     * @return the mnemonic for {@code opcode} or {@code "<illegal opcode>"} if {@code opcode} is
+     *         not a legal opcode.
+     */
+    public static String baseNameOf(int opcode) {
+        String name = nameArray[opcode & 0xff];
+        if (name == null) {
+            return "<illegal opcode>";
+        }
+        return name;
+    }
+
+    /**
+     * Gets the opcode corresponding to a given mnemonic.
+     *
+     * @param name an opcode mnemonic
+     * @return the opcode corresponding to {@code mnemonic}
+     * @throws IllegalArgumentException if {@code name} does not denote a valid opcode
+     */
+    public static int valueOf(String name) {
+        for (int opcode = 0; opcode < nameArray.length; ++opcode) {
+            if (name.equalsIgnoreCase(nameArray[opcode])) {
+                return opcode;
+            }
+        }
+        throw new IllegalArgumentException("No opcode for " + name);
+    }
+
+    /**
+     * Determines if a given opcode denotes an instruction that can cause an implicit exception.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} can cause an implicit exception, {@code false}
+     *         otherwise
+     */
+    public static boolean canTrap(int opcode) {
+        return (flagsArray[opcode & 0xff] & TRAP) != 0;
+    }
+
+    /**
+     * Determines if a given opcode denotes an instruction that loads a local variable to the
+     * operand stack.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} loads a local variable to the operand stack,
+     *         {@code false} otherwise
+     */
+    public static boolean isLoad(int opcode) {
+        return (flagsArray[opcode & 0xff] & LOAD) != 0;
+    }
+
+    /**
+     * Determines if a given opcode denotes an instruction that ends a basic block and does not let
+     * control flow fall through to its lexical successor.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} properly ends a basic block
+     */
+    public static boolean isStop(int opcode) {
+        return (flagsArray[opcode & 0xff] & STOP) != 0;
+    }
+
+    /**
+     * Determines if a given opcode denotes an instruction that stores a value to a local variable
+     * after popping it from the operand stack.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false}
+     *         otherwise
+     */
+    public static boolean isInvoke(int opcode) {
+        return (flagsArray[opcode & 0xff] & INVOKE) != 0;
+    }
+
+    /**
+     * Determines if a given opcode denotes an instruction that stores a value to a local variable
+     * after popping it from the operand stack.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false}
+     *         otherwise
+     */
+    public static boolean isStore(int opcode) {
+        return (flagsArray[opcode & 0xff] & STORE) != 0;
+    }
+
+    /**
+     * Determines if a given opcode is an instruction that delimits a basic block.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} delimits a basic block
+     */
+    public static boolean isBlockEnd(int opcode) {
+        return (flagsArray[opcode & 0xff] & (STOP | FALL_THROUGH)) != 0;
+    }
+
+    /**
+     * Determines if a given opcode is an instruction that has a 2 or 4 byte operand that is an
+     * offset to another instruction in the same method. This does not include the
+     * {@linkplain #TABLESWITCH switch} instructions.
+     *
+     * @param opcode an opcode to test
+     * @return {@code true} iff {@code opcode} is a branch instruction with a single operand
+     */
+    public static boolean isBranch(int opcode) {
+        return (flagsArray[opcode & 0xff] & BRANCH) != 0;
+    }
+
+    /**
+     * Determines if a given opcode denotes a conditional branch.
+     *
+     * @param opcode
+     * @return {@code true} iff {@code opcode} is a conditional branch
+     */
+    public static boolean isConditionalBranch(int opcode) {
+        return (flagsArray[opcode & 0xff] & FALL_THROUGH) != 0;
+    }
+
+    /**
+     * Gets the arithmetic operator name for a given opcode. If {@code opcode} does not denote an
+     * arithmetic instruction, then the {@linkplain #nameOf(int) name} of the opcode is returned
+     * instead.
+     *
+     * @param op an opcode
+     * @return the arithmetic operator name
+     */
+    public static String operator(int op) {
+        // Checkstyle: stop
+        switch (op) {
+            // arithmetic ops
+            case IADD: // fall through
+            case LADD: // fall through
+            case FADD: // fall through
+            case DADD:
+                return "+";
+            case ISUB: // fall through
+            case LSUB: // fall through
+            case FSUB: // fall through
+            case DSUB:
+                return "-";
+            case IMUL: // fall through
+            case LMUL: // fall through
+            case FMUL: // fall through
+            case DMUL:
+                return "*";
+            case IDIV: // fall through
+            case LDIV: // fall through
+            case FDIV: // fall through
+            case DDIV:
+                return "/";
+            case IREM: // fall through
+            case LREM: // fall through
+            case FREM: // fall through
+            case DREM:
+                return "%";
+            // shift ops
+            case ISHL: // fall through
+            case LSHL:
+                return "<<";
+            case ISHR: // fall through
+            case LSHR:
+                return ">>";
+            case IUSHR: // fall through
+            case LUSHR:
+                return ">>>";
+            // logic ops
+            case IAND: // fall through
+            case LAND:
+                return "&";
+            case IOR: // fall through
+            case LOR:
+                return "|";
+            case IXOR: // fall through
+            case LXOR:
+                return "^";
+        }
+        // Checkstyle: resume
+        return nameOf(op);
+    }
+
+    /**
+     * Defines a bytecode by entering it into the arrays that record its name, length and flags.
+     *
+     * @param name instruction name (should be lower case)
+     * @param format encodes the length of the instruction
+     */
+    private static void def(int opcode, String name, String format, int stackEffect) {
+        def(opcode, name, format, stackEffect, 0);
+    }
+
+    /**
+     * Defines a bytecode by entering it into the arrays that record its name, length and flags.
+     *
+     * @param name instruction name (lower case)
+     * @param format encodes the length of the instruction
+     * @param flags the set of {@link Flags} associated with the instruction
+     */
+    private static void def(int opcode, String name, String format, int stackEffect, int flags) {
+        assert nameArray[opcode] == null : "opcode " + opcode + " is already bound to name " + nameArray[opcode];
+        nameArray[opcode] = name;
+        int instructionLength = format.length();
+        lengthArray[opcode] = instructionLength;
+        stackEffectArray[opcode] = stackEffect;
+        Bytecodes.flagsArray[opcode] = flags;
+
+        assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytes.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytes.java
new file mode 100644
index 0000000..e3f2044
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytes.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+/**
+ * A collection of utility methods for dealing with bytes, particularly in byte arrays.
+ */
+public class Bytes {
+
+    /**
+     * Gets a signed 1-byte value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @return the signed 1-byte value at index {@code bci} in array {@code data}
+     */
+    public static int beS1(byte[] data, int bci) {
+        return data[bci];
+    }
+
+    /**
+     * Gets a signed 2-byte big-endian value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @return the signed 2-byte, big-endian, value at index {@code bci} in array {@code data}
+     */
+    public static int beS2(byte[] data, int bci) {
+        return (data[bci] << 8) | (data[bci + 1] & 0xff);
+    }
+
+    /**
+     * Gets an unsigned 1-byte value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @return the unsigned 1-byte value at index {@code bci} in array {@code data}
+     */
+    public static int beU1(byte[] data, int bci) {
+        return data[bci] & 0xff;
+    }
+
+    /**
+     * Gets an unsigned 2-byte big-endian value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @return the unsigned 2-byte, big-endian, value at index {@code bci} in array {@code data}
+     */
+    public static int beU2(byte[] data, int bci) {
+        return ((data[bci] & 0xff) << 8) | (data[bci + 1] & 0xff);
+    }
+
+    /**
+     * Gets a signed 4-byte big-endian value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @return the signed 4-byte, big-endian, value at index {@code bci} in array {@code data}
+     */
+    public static int beS4(byte[] data, int bci) {
+        return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff);
+    }
+
+    /**
+     * Gets either a signed 2-byte or a signed 4-byte big-endian value.
+     *
+     * @param data the array containing the data
+     * @param bci the start index of the value to retrieve
+     * @param fourByte if true, this method will return a 4-byte value
+     * @return the signed 2 or 4-byte, big-endian, value at index {@code bci} in array {@code data}
+     */
+    public static int beSVar(byte[] data, int bci, boolean fourByte) {
+        if (fourByte) {
+            return beS4(data, bci);
+        } else {
+            return beS2(data, bci);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java
new file mode 100644
index 0000000..39b6e83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.ExceptionHandler;
+import jdk.vm.ci.meta.LineNumberTable;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Direct access to the bytecode of a {@link ResolvedJavaMethod} that will reflect any
+ * instrumentation and rewriting performed on the {@link ResolvedJavaMethod}.
+ */
+public class ResolvedJavaMethodBytecode implements Bytecode {
+
+    private final ResolvedJavaMethod method;
+
+    public ResolvedJavaMethodBytecode(ResolvedJavaMethod method) {
+        this.method = method;
+    }
+
+    @Override
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    @Override
+    public byte[] getCode() {
+        return method.getCode();
+    }
+
+    @Override
+    public int getCodeSize() {
+        return method.getCodeSize();
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return method.getMaxStackSize();
+    }
+
+    @Override
+    public int getMaxLocals() {
+        return method.getMaxLocals();
+    }
+
+    @Override
+    public ConstantPool getConstantPool() {
+        return method.getConstantPool();
+    }
+
+    @Override
+    public LineNumberTable getLineNumberTable() {
+        return method.getLineNumberTable();
+    }
+
+    @Override
+    public LocalVariableTable getLocalVariableTable() {
+        return method.getLocalVariableTable();
+    }
+
+    @Override
+    public ExceptionHandler[] getExceptionHandlers() {
+        return method.getExceptionHandlers();
+    }
+
+    @Override
+    public StackTraceElement asStackTraceElement(int bci) {
+        return method.asStackTraceElement(bci);
+    }
+
+    @Override
+    public ProfilingInfo getProfilingInfo() {
+        return method.getProfilingInfo();
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + method.format("<%h.%n(%p)>");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java
new file mode 100644
index 0000000..b2f0409
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.bytecode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * {@link BytecodeProvider} that returns {@link ResolvedJavaMethodBytecode} objects.
+ */
+public class ResolvedJavaMethodBytecodeProvider implements BytecodeProvider {
+
+    @Override
+    public Bytecode getBytecode(ResolvedJavaMethod method) {
+        return new ResolvedJavaMethodBytecode(method);
+    }
+
+    @Override
+    public boolean supportsInvokedynamic() {
+        return true;
+    }
+
+    @Override
+    public boolean shouldRecordMethodDependencies() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java
new file mode 100644
index 0000000..ba1267b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.graalvm.compiler.graph.NodeSourcePosition;
+
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.code.site.ExceptionHandler;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.code.site.Reference;
+import jdk.vm.ci.code.site.Site;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Represents the output from compiling a method, including the compiled machine code, associated
+ * data and references, relocation information, deoptimization information, etc.
+ */
+public class CompilationResult {
+
+    /**
+     * Provides extra information about instructions or data at specific positions in
+     * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to
+     * enhance a disassembly of the code.
+     */
+    public abstract static class CodeAnnotation {
+
+        public final int position;
+
+        public CodeAnnotation(int position) {
+            this.position = position;
+        }
+
+        @Override
+        public final int hashCode() {
+            throw new UnsupportedOperationException("hashCode");
+        }
+
+        @Override
+        public String toString() {
+            return identityHashCodeString(this);
+        }
+
+        @Override
+        public abstract boolean equals(Object obj);
+    }
+
+    /**
+     * A string comment about one or more instructions at a specific position in the code.
+     */
+    public static final class CodeComment extends CodeAnnotation {
+
+        public final String value;
+
+        public CodeComment(int position, String comment) {
+            super(position);
+            this.value = comment;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof CodeComment) {
+                CodeComment that = (CodeComment) obj;
+                if (this.position == that.position && this.value.equals(that.value)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "@" + position + ": " + value;
+        }
+    }
+
+    /**
+     * Describes a table of signed offsets embedded in the code. The offsets are relative to the
+     * starting address of the table. This type of table maybe generated when translating a
+     * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch}
+     * JVM instruction).
+     *
+     * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high}
+     * inclusive.
+     */
+    public static final class JumpTable extends CodeAnnotation {
+
+        /**
+         * The low value in the key range (inclusive).
+         */
+        public final int low;
+
+        /**
+         * The high value in the key range (inclusive).
+         */
+        public final int high;
+
+        /**
+         * The size (in bytes) of each table entry.
+         */
+        public final int entrySize;
+
+        public JumpTable(int position, int low, int high, int entrySize) {
+            super(position);
+            this.low = low;
+            this.high = high;
+            this.entrySize = entrySize;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof JumpTable) {
+                JumpTable that = (JumpTable) obj;
+                if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]";
+        }
+    }
+
+    private boolean closed;
+
+    private int entryBCI = -1;
+
+    private final DataSection dataSection = new DataSection();
+
+    private final List<Infopoint> infopoints = new ArrayList<>();
+    private final List<SourceMapping> sourceMapping = new ArrayList<>();
+    private final List<DataPatch> dataPatches = new ArrayList<>();
+    private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
+    private final List<Mark> marks = new ArrayList<>();
+
+    private int totalFrameSize = -1;
+    private int maxInterpreterFrameSize = -1;
+
+    private StackSlot customStackArea = null;
+
+    private final String name;
+
+    /**
+     * The buffer containing the emitted machine code.
+     */
+    private byte[] targetCode;
+
+    /**
+     * The leading number of bytes in {@link #targetCode} containing the emitted machine code.
+     */
+    private int targetCodeSize;
+
+    private ArrayList<CodeAnnotation> annotations;
+
+    private Assumption[] assumptions;
+
+    /**
+     * The list of the methods whose bytecodes were used as input to the compilation. If
+     * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
+     * element of this array is the root method of the compilation.
+     */
+    private ResolvedJavaMethod[] methods;
+
+    /**
+     * The list of fields that were accessed from the bytecodes.
+     */
+    private ResolvedJavaField[] fields;
+
+    private int bytecodeSize;
+
+    private boolean hasUnsafeAccess;
+
+    private boolean isImmutablePIC;
+
+    public CompilationResult() {
+        this(null, false);
+    }
+
+    public CompilationResult(String name) {
+        this(name, false);
+    }
+
+    public CompilationResult(boolean isImmutablePIC) {
+        this(null, isImmutablePIC);
+    }
+
+    public CompilationResult(String name, boolean isImmutablePIC) {
+        this.name = name;
+        this.isImmutablePIC = isImmutablePIC;
+    }
+
+    @Override
+    public int hashCode() {
+        // CompilationResult instances should not be used as hash map keys
+        throw new UnsupportedOperationException("hashCode");
+    }
+
+    @Override
+    public String toString() {
+        if (methods != null) {
+            return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]";
+        }
+        return identityHashCodeString(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj != null && obj.getClass() == getClass()) {
+            CompilationResult that = (CompilationResult) obj;
+            // @formatter:off
+            if (this.entryBCI == that.entryBCI &&
+                Objects.equals(this.customStackArea, that.customStackArea) &&
+                this.totalFrameSize == that.totalFrameSize &&
+                this.targetCodeSize == that.targetCodeSize &&
+                Objects.equals(this.name, that.name) &&
+                Objects.equals(this.annotations, that.annotations) &&
+                Objects.equals(this.dataSection, that.dataSection) &&
+                Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
+                Objects.equals(this.dataPatches, that.dataPatches) &&
+                Objects.equals(this.infopoints, that.infopoints) &&
+                Objects.equals(this.marks,  that.marks) &&
+                Arrays.equals(this.assumptions, that.assumptions) &&
+                Arrays.equals(targetCode, that.targetCode)) {
+                return true;
+            }
+            // @formatter:on
+        }
+        return false;
+    }
+
+    /**
+     * @return the entryBCI
+     */
+    public int getEntryBCI() {
+        return entryBCI;
+    }
+
+    /**
+     * @param entryBCI the entryBCI to set
+     */
+    public void setEntryBCI(int entryBCI) {
+        checkOpen();
+        this.entryBCI = entryBCI;
+    }
+
+    /**
+     * Sets the assumptions made during compilation.
+     */
+    public void setAssumptions(Assumption[] assumptions) {
+        checkOpen();
+        this.assumptions = assumptions;
+    }
+
+    /**
+     * Gets the assumptions made during compilation.
+     *
+     * The caller must not modify the contents of the returned array.
+     */
+    public Assumption[] getAssumptions() {
+        return assumptions;
+    }
+
+    /**
+     * Sets the methods whose bytecodes were used as input to the compilation.
+     *
+     * @param rootMethod the root method of the compilation
+     * @param inlinedMethods the methods inlined during compilation
+     */
+    public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
+        checkOpen();
+        assert rootMethod != null;
+        assert inlinedMethods != null;
+        if (inlinedMethods.contains(rootMethod)) {
+            methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]);
+            for (int i = 0; i < methods.length; i++) {
+                if (methods[i].equals(rootMethod)) {
+                    if (i != 0) {
+                        ResolvedJavaMethod tmp = methods[0];
+                        methods[0] = methods[i];
+                        methods[i] = tmp;
+                    }
+                    break;
+                }
+            }
+        } else {
+            methods = new ResolvedJavaMethod[1 + inlinedMethods.size()];
+            methods[0] = rootMethod;
+            int i = 1;
+            for (ResolvedJavaMethod m : inlinedMethods) {
+                methods[i++] = m;
+            }
+        }
+    }
+
+    /**
+     * Gets the methods whose bytecodes were used as input to the compilation.
+     *
+     * The caller must not modify the contents of the returned array.
+     *
+     * @return {@code null} if the compilation did not record method dependencies otherwise the
+     *         methods whose bytecodes were used as input to the compilation with the first element
+     *         being the root method of the compilation
+     */
+    public ResolvedJavaMethod[] getMethods() {
+        return methods;
+    }
+
+    /**
+     * Sets the fields that were referenced from the bytecodes that were used as input to the
+     * compilation.
+     *
+     * @param accessedFields the collected set of fields accessed during compilation
+     */
+    public void setFields(Collection<ResolvedJavaField> accessedFields) {
+        assert accessedFields != null;
+        fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
+    }
+
+    /**
+     * Gets the fields that were referenced from bytecodes that were used as input to the
+     * compilation.
+     *
+     * The caller must not modify the contents of the returned array.
+     *
+     * @return {@code null} if the compilation did not record fields dependencies otherwise the
+     *         fields that were accessed from bytecodes were used as input to the compilation.
+     */
+    public ResolvedJavaField[] getFields() {
+        return fields;
+    }
+
+    public void setBytecodeSize(int bytecodeSize) {
+        checkOpen();
+        this.bytecodeSize = bytecodeSize;
+    }
+
+    public int getBytecodeSize() {
+        return bytecodeSize;
+    }
+
+    public DataSection getDataSection() {
+        return dataSection;
+    }
+
+    /**
+     * The total frame size of the method in bytes. This includes the return address pushed onto the
+     * stack, if any.
+     *
+     * @return the frame size
+     */
+    public int getTotalFrameSize() {
+        assert totalFrameSize != -1 : "frame size not yet initialized!";
+        return totalFrameSize;
+    }
+
+    /**
+     * Sets the total frame size in bytes. This includes the return address pushed onto the stack,
+     * if any.
+     *
+     * @param size the size of the frame in bytes
+     */
+    public void setTotalFrameSize(int size) {
+        checkOpen();
+        totalFrameSize = size;
+    }
+
+    public int getMaxInterpreterFrameSize() {
+        return maxInterpreterFrameSize;
+    }
+
+    public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) {
+        checkOpen();
+        this.maxInterpreterFrameSize = maxInterpreterFrameSize;
+    }
+
+    public boolean isImmutablePIC() {
+        return this.isImmutablePIC;
+    }
+
+    /**
+     * Sets the machine that has been generated by the compiler.
+     *
+     * @param code the machine code generated
+     * @param size the size of the machine code
+     */
+    public void setTargetCode(byte[] code, int size) {
+        checkOpen();
+        targetCode = code;
+        targetCodeSize = size;
+    }
+
+    /**
+     * Records a data patch in the code section. The data patch can refer to something in the
+     * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
+     * constant}.
+     *
+     * @param codePos the position in the code that needs to be patched
+     * @param ref the reference that should be inserted in the code
+     */
+    public void recordDataPatch(int codePos, Reference ref) {
+        checkOpen();
+        assert codePos >= 0 && ref != null;
+        dataPatches.add(new DataPatch(codePos, ref));
+    }
+
+    /**
+     * Records a data patch in the code section. The data patch can refer to something in the
+     * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
+     * constant}.
+     *
+     * @param codePos the position in the code that needs to be patched
+     * @param ref the reference that should be inserted in the code
+     * @param note a note attached to data patch for use by post-processing tools
+     */
+    public void recordDataPatchWithNote(int codePos, Reference ref, Object note) {
+        assert codePos >= 0 && ref != null;
+        dataPatches.add(new DataPatch(codePos, ref, note));
+    }
+
+    /**
+     * Records a call in the code array.
+     *
+     * @param codePos the position of the call in the code array
+     * @param size the size of the call instruction
+     * @param target the being called
+     * @param debugInfo the debug info for the call
+     * @param direct specifies if this is a {@linkplain Call#direct direct} call
+     */
+    public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
+        checkOpen();
+        final Call call = new Call(target, codePos, size, direct, debugInfo);
+        addInfopoint(call);
+    }
+
+    /**
+     * Records an exception handler for this method.
+     *
+     * @param codePos the position in the code that is covered by the handler
+     * @param handlerPos the position of the handler
+     */
+    public void recordExceptionHandler(int codePos, int handlerPos) {
+        checkOpen();
+        assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos);
+        exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
+    }
+
+    /**
+     * Validate if the exception handler for codePos already exists and handlerPos is different.
+     *
+     * @param codePos
+     * @param handlerPos
+     * @return true if the validation is successful
+     */
+    private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) {
+        ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos);
+        return exHandler == null || exHandler.handlerPos == handlerPos;
+    }
+
+    /**
+     * Returns the first ExceptionHandler which matches codePos.
+     *
+     * @param codePos position to search for
+     * @return first matching ExceptionHandler
+     */
+    private ExceptionHandler getExceptionHandlerForCodePos(int codePos) {
+        for (ExceptionHandler h : exceptionHandlers) {
+            if (h.pcOffset == codePos) {
+                return h;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Records an infopoint in the code array.
+     *
+     * @param codePos the position of the infopoint in the code array
+     * @param debugInfo the debug info for the infopoint
+     */
+    public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) {
+        addInfopoint(new Infopoint(codePos, debugInfo, reason));
+    }
+
+    /**
+     * Records a custom infopoint in the code section.
+     *
+     * Compiler implementations can use this method to record non-standard infopoints, which are not
+     * handled by dedicated methods like {@link #recordCall}.
+     *
+     * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
+     */
+    public void addInfopoint(Infopoint infopoint) {
+        checkOpen();
+        infopoints.add(infopoint);
+    }
+
+    public void recordSourceMapping(int startOffset, int endOffset, NodeSourcePosition sourcePosition) {
+        checkOpen();
+        sourceMapping.add(new SourceMapping(startOffset, endOffset, sourcePosition));
+    }
+
+    /**
+     * Records an instruction mark within this method.
+     *
+     * @param codePos the position in the code that is covered by the handler
+     * @param markId the identifier for this mark
+     */
+    public Mark recordMark(int codePos, Object markId) {
+        checkOpen();
+        Mark mark = new Mark(codePos, markId);
+        marks.add(mark);
+        return mark;
+    }
+
+    /**
+     * Start of the custom stack area.
+     *
+     * @return the first stack slot of the custom stack area
+     */
+    public StackSlot getCustomStackArea() {
+        return customStackArea;
+    }
+
+    /**
+     * @see #getCustomStackArea()
+     * @param slot
+     */
+    public void setCustomStackAreaOffset(StackSlot slot) {
+        checkOpen();
+        customStackArea = slot;
+    }
+
+    /**
+     * @return the machine code generated for this method
+     */
+    public byte[] getTargetCode() {
+        return targetCode;
+    }
+
+    /**
+     * @return the size of the machine code generated for this method
+     */
+    public int getTargetCodeSize() {
+        return targetCodeSize;
+    }
+
+    /**
+     * @return the code annotations or {@code null} if there are none
+     */
+    public List<CodeAnnotation> getAnnotations() {
+        if (annotations == null) {
+            return Collections.emptyList();
+        }
+        return annotations;
+    }
+
+    public void addAnnotation(CodeAnnotation annotation) {
+        checkOpen();
+        assert annotation != null;
+        if (annotations == null) {
+            annotations = new ArrayList<>();
+        }
+        annotations.add(annotation);
+    }
+
+    /**
+     * @return the list of infopoints, sorted by {@link Site#pcOffset}
+     */
+    public List<Infopoint> getInfopoints() {
+        if (infopoints.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(infopoints);
+    }
+
+    /**
+     * @return the list of data references
+     */
+    public List<DataPatch> getDataPatches() {
+        if (dataPatches.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(dataPatches);
+    }
+
+    /**
+     * @return the list of exception handlers
+     */
+    public List<ExceptionHandler> getExceptionHandlers() {
+        if (exceptionHandlers.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(exceptionHandlers);
+    }
+
+    /**
+     * @return the list of marks
+     */
+    public List<Mark> getMarks() {
+        if (marks.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(marks);
+    }
+
+    /**
+     * @return the list of {@link SourceMapping}s
+     */
+    public List<SourceMapping> getSourceMappings() {
+        if (sourceMapping.isEmpty()) {
+            return emptyList();
+        }
+        return unmodifiableList(sourceMapping);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
+        checkOpen();
+        this.hasUnsafeAccess = hasUnsafeAccess;
+    }
+
+    public boolean hasUnsafeAccess() {
+        return hasUnsafeAccess;
+    }
+
+    /**
+     * Clears the information in this object pertaining to generating code. That is, the
+     * {@linkplain #getMarks() marks}, {@linkplain #getInfopoints() infopoints},
+     * {@linkplain #getExceptionHandlers() exception handlers}, {@linkplain #getDataPatches() data
+     * patches} and {@linkplain #getAnnotations() annotations} recorded in this object are cleared.
+     */
+    public void resetForEmittingCode() {
+        checkOpen();
+        infopoints.clear();
+        sourceMapping.clear();
+        dataPatches.clear();
+        exceptionHandlers.clear();
+        marks.clear();
+        dataSection.clear();
+        if (annotations != null) {
+            annotations.clear();
+        }
+    }
+
+    private void checkOpen() {
+        if (closed) {
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * Closes this compilation result to future updates.
+     */
+    public void close() {
+        if (closed) {
+            throw new IllegalStateException("Cannot re-close compilation result " + this);
+        }
+        dataSection.close();
+        closed = true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java
new file mode 100644
index 0000000..557f959
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+
+import org.graalvm.compiler.code.DataSection.Data;
+
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.meta.SerializableConstant;
+import jdk.vm.ci.meta.VMConstant;
+
+public final class DataSection implements Iterable<Data> {
+
+    public interface Patches {
+
+        void registerPatch(VMConstant c);
+    }
+
+    public abstract static class Data {
+
+        private int alignment;
+        private final int size;
+
+        private DataSectionReference ref;
+
+        protected Data(int alignment, int size) {
+            this.alignment = alignment;
+            this.size = size;
+
+            // initialized in DataSection.insertData(Data)
+            ref = null;
+        }
+
+        protected abstract void emit(ByteBuffer buffer, Patches patches);
+
+        public void updateAlignment(int newAlignment) {
+            if (newAlignment == alignment) {
+                return;
+            }
+            alignment = lcm(alignment, newAlignment);
+        }
+
+        public int getAlignment() {
+            return alignment;
+        }
+
+        public int getSize() {
+            return size;
+        }
+
+        @Override
+        public int hashCode() {
+            // Data instances should not be used as hash map keys
+            throw new UnsupportedOperationException("hashCode");
+        }
+
+        @Override
+        public String toString() {
+            return identityHashCodeString(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            assert ref != null;
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof Data) {
+                Data that = (Data) obj;
+                if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    public static final class RawData extends Data {
+
+        private final byte[] data;
+
+        public RawData(byte[] data, int alignment) {
+            super(alignment, data.length);
+            this.data = data;
+        }
+
+        @Override
+        protected void emit(ByteBuffer buffer, Patches patches) {
+            buffer.put(data);
+        }
+    }
+
+    public static final class SerializableData extends Data {
+
+        private final SerializableConstant constant;
+
+        public SerializableData(SerializableConstant constant) {
+            this(constant, 1);
+        }
+
+        public SerializableData(SerializableConstant constant, int alignment) {
+            super(alignment, constant.getSerializedSize());
+            this.constant = constant;
+        }
+
+        @Override
+        protected void emit(ByteBuffer buffer, Patches patches) {
+            int position = buffer.position();
+            constant.serialize(buffer);
+            assert buffer.position() - position == constant.getSerializedSize() : "wrong number of bytes written";
+        }
+    }
+
+    public static class ZeroData extends Data {
+
+        protected ZeroData(int alignment, int size) {
+            super(alignment, size);
+        }
+
+        public static ZeroData create(int alignment, int size) {
+            switch (size) {
+                case 1:
+                    return new ZeroData(alignment, size) {
+                        @Override
+                        protected void emit(ByteBuffer buffer, Patches patches) {
+                            buffer.put((byte) 0);
+                        }
+                    };
+
+                case 2:
+                    return new ZeroData(alignment, size) {
+                        @Override
+                        protected void emit(ByteBuffer buffer, Patches patches) {
+                            buffer.putShort((short) 0);
+                        }
+                    };
+
+                case 4:
+                    return new ZeroData(alignment, size) {
+                        @Override
+                        protected void emit(ByteBuffer buffer, Patches patches) {
+                            buffer.putInt(0);
+                        }
+                    };
+
+                case 8:
+                    return new ZeroData(alignment, size) {
+                        @Override
+                        protected void emit(ByteBuffer buffer, Patches patches) {
+                            buffer.putLong(0);
+                        }
+                    };
+
+                default:
+                    return new ZeroData(alignment, size);
+            }
+        }
+
+        @Override
+        protected void emit(ByteBuffer buffer, Patches patches) {
+            int rest = getSize();
+            while (rest > 8) {
+                buffer.putLong(0L);
+                rest -= 8;
+            }
+            while (rest > 0) {
+                buffer.put((byte) 0);
+                rest--;
+            }
+        }
+    }
+
+    public static final class PackedData extends Data {
+
+        private final Data[] nested;
+
+        private PackedData(int alignment, int size, Data[] nested) {
+            super(alignment, size);
+            this.nested = nested;
+        }
+
+        public static PackedData create(Data[] nested) {
+            int size = 0;
+            int alignment = 1;
+            for (int i = 0; i < nested.length; i++) {
+                assert size % nested[i].getAlignment() == 0 : "invalid alignment in packed constants";
+                alignment = DataSection.lcm(alignment, nested[i].getAlignment());
+                size += nested[i].getSize();
+            }
+            return new PackedData(alignment, size, nested);
+        }
+
+        @Override
+        protected void emit(ByteBuffer buffer, Patches patches) {
+            for (Data data : nested) {
+                data.emit(buffer, patches);
+            }
+        }
+    }
+
+    private final ArrayList<Data> dataItems = new ArrayList<>();
+
+    private boolean closed;
+    private int sectionAlignment;
+    private int sectionSize;
+
+    @Override
+    public int hashCode() {
+        // DataSection instances should not be used as hash map keys
+        throw new UnsupportedOperationException("hashCode");
+    }
+
+    @Override
+    public String toString() {
+        return identityHashCodeString(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DataSection) {
+            DataSection that = (DataSection) obj;
+            if (this.closed == that.closed && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Inserts a {@link Data} item into the data section. If the item is already in the data
+     * section, the same {@link DataSectionReference} is returned.
+     *
+     * @param data the {@link Data} item to be inserted
+     * @return a unique {@link DataSectionReference} identifying the {@link Data} item
+     */
+    public DataSectionReference insertData(Data data) {
+        checkOpen();
+        synchronized (data) {
+            if (data.ref == null) {
+                data.ref = new DataSectionReference();
+                dataItems.add(data);
+            }
+            return data.ref;
+        }
+    }
+
+    /**
+     * Transfers all {@link Data} from the provided other {@link DataSection} to this
+     * {@link DataSection}, and empties the other section.
+     */
+    public void addAll(DataSection other) {
+        checkOpen();
+        other.checkOpen();
+
+        for (Data data : other.dataItems) {
+            assert data.ref != null;
+            dataItems.add(data);
+        }
+        other.dataItems.clear();
+    }
+
+    /**
+     * Determines if this object has been {@link #close() closed}.
+     */
+    public boolean closed() {
+        return closed;
+    }
+
+    /**
+     * Computes the layout of the data section and closes this object to further updates.
+     *
+     * This must be called exactly once.
+     */
+    public void close() {
+        checkOpen();
+        closed = true;
+
+        // simple heuristic: put items with larger alignment requirement first
+        dataItems.sort((a, b) -> a.alignment - b.alignment);
+
+        int position = 0;
+        int alignment = 1;
+        for (Data d : dataItems) {
+            alignment = lcm(alignment, d.alignment);
+            position = align(position, d.alignment);
+
+            d.ref.setOffset(position);
+            position += d.size;
+        }
+
+        sectionAlignment = alignment;
+        sectionSize = position;
+    }
+
+    /**
+     * Gets the size of the data section.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
+     */
+    public int getSectionSize() {
+        checkClosed();
+        return sectionSize;
+    }
+
+    /**
+     * Gets the minimum alignment requirement of the data section.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
+     */
+    public int getSectionAlignment() {
+        checkClosed();
+        return sectionAlignment;
+    }
+
+    /**
+     * Builds the data section into a given buffer.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
+     *
+     * @param buffer the {@link ByteBuffer} where the data section should be built. The buffer must
+     *            hold at least {@link #getSectionSize()} bytes.
+     * @param patch a {@link Patches} instance to receive {@link VMConstant constants} for
+     *            relocations in the data section
+     */
+    public void buildDataSection(ByteBuffer buffer, Patches patch) {
+        buildDataSection(buffer, patch, (r, s) -> {
+        });
+    }
+
+    /**
+     * Builds the data section into a given buffer.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}. When this
+     * method returns, the buffers' position is just after the last data item.
+     *
+     * @param buffer the {@link ByteBuffer} where the data section should be built. The buffer must
+     *            hold at least {@link #getSectionSize()} bytes.
+     * @param patch a {@link Patches} instance to receive {@link VMConstant constants} for
+     * @param onEmit a function that is called before emitting each data item with the
+     *            {@link DataSectionReference} and the size of the data.
+     */
+    public void buildDataSection(ByteBuffer buffer, Patches patch, BiConsumer<DataSectionReference, Integer> onEmit) {
+        checkClosed();
+        assert buffer.remaining() >= sectionSize;
+        int start = buffer.position();
+        for (Data d : dataItems) {
+            buffer.position(start + d.ref.getOffset());
+            onEmit.accept(d.ref, d.getSize());
+            d.emit(buffer, patch);
+        }
+        buffer.position(start + sectionSize);
+    }
+
+    public Data findData(DataSectionReference ref) {
+        for (Data d : dataItems) {
+            if (d.ref == ref) {
+                return d;
+            }
+        }
+        return null;
+    }
+
+    public static void emit(ByteBuffer buffer, Data data, Patches patch) {
+        data.emit(buffer, patch);
+    }
+
+    @Override
+    public Iterator<Data> iterator() {
+        return dataItems.iterator();
+    }
+
+    private static int lcm(int x, int y) {
+        if (x == 0) {
+            return y;
+        } else if (y == 0) {
+            return x;
+        }
+
+        int a = Math.max(x, y);
+        int b = Math.min(x, y);
+        while (b > 0) {
+            int tmp = a % b;
+            a = b;
+            b = tmp;
+        }
+
+        int gcd = a;
+        return x * y / gcd;
+    }
+
+    private static int align(int position, int alignment) {
+        return ((position + alignment - 1) / alignment) * alignment;
+    }
+
+    private void checkClosed() {
+        if (!closed) {
+            throw new IllegalStateException();
+        }
+    }
+
+    private void checkOpen() {
+        if (closed) {
+            throw new IllegalStateException();
+        }
+    }
+
+    public void clear() {
+        checkOpen();
+        this.dataItems.clear();
+        this.sectionAlignment = 0;
+        this.sectionSize = 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java
new file mode 100644
index 0000000..0b5f6a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+
+/**
+ * Interface providing capability for disassembling machine code.
+ */
+public interface DisassemblerProvider {
+
+    /**
+     * Gets a textual disassembly of a given compilation result.
+     *
+     * @param codeCache the object used for code {@link CodeCacheProvider#addCode code installation}
+     * @param compResult a compilation result
+     * @return a non-zero length string containing a disassembly of {@code compResult} or null it
+     *         could not be disassembled
+     */
+    default String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) {
+        return null;
+    }
+
+    /**
+     * Gets a textual disassembly of a given installed code.
+     *
+     * @param codeCache the object used for code {@link CodeCacheProvider#addCode code installation}
+     * @param compResult a compiled code that was installed to produce {@code installedCode}. This
+     *            will be null if not available.
+     * @param installedCode
+     * @return a non-zero length string containing a disassembly of {@code installedCode} or null if
+     *         {@code installedCode} is {@link InstalledCode#isValid() invalid} or it could not be
+     *         disassembled for some other reason
+     */
+    default String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) {
+        return null;
+    }
+
+    /**
+     * Gets the name denoting the format of the disassmembly return by this object.
+     */
+    String getName();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java
new file mode 100644
index 0000000..7448f86
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
+import org.graalvm.compiler.code.CompilationResult.CodeComment;
+import org.graalvm.compiler.code.CompilationResult.JumpTable;
+
+import jdk.vm.ci.code.CodeUtil;
+
+/**
+ * A HexCodeFile is a textual format for representing a chunk of machine code along with extra
+ * information that can be used to enhance a disassembly of the code.
+ *
+ * A pseudo grammar for a HexCodeFile is given below.
+ *
+ * <pre>
+ *     HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
+ *
+ *     OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
+ *
+ *     Platform ::= "Platform" ISA WordWidth
+ *
+ *     HexCode ::= "HexCode" StartAddress HexDigits
+ *
+ *     Comment ::= "Comment" Position String
+ *
+ *     OperandComment ::= "OperandComment" Position String
+ *
+ *     JumpTable ::= "JumpTable" Position EntrySize Low High
+ *
+ *     LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
+ *
+ *     Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
+ *
+ *     Delim := "&lt;||@"
+ * </pre>
+ *
+ * There must be exactly one HexCode and Platform part in a HexCodeFile. The length of HexDigits
+ * must be even as each pair of digits represents a single byte.
+ * <p>
+ * Below is an example of a valid Code input:
+ *
+ * <pre>
+ *
+ *  Platform AMD64 64  &lt;||@
+ *  HexCode 0 e8000000009090904883ec084889842410d0ffff48893c24e800000000488b3c24488bf0e8000000004883c408c3  &lt;||@
+ *  Comment 24 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 1]
+ *              |0
+ *     locals:  |stack:0:a
+ *     stack:   |stack:0:a
+ *    &lt;||@
+ *  OperandComment 24 {java.util.Locale.getDefault()}  &lt;||@
+ *  Comment 36 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 4]
+ *              |0
+ *     locals:  |stack:0:a
+ *    &lt;||@
+ *  OperandComment 36 {java.lang.String.toLowerCase(Locale)}  lt;||@
+ *
+ * </pre>
+ */
+public class HexCodeFile {
+
+    public static final String NEW_LINE = CodeUtil.NEW_LINE;
+    public static final String SECTION_DELIM = " <||@";
+    public static final String COLUMN_END = " <|@";
+    public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL);
+    public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL);
+    public static final Pattern OPERAND_COMMENT = COMMENT;
+    public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*");
+    public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*");
+    public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?");
+    public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL);
+
+    /**
+     * Delimiter placed before a HexCodeFile when embedded in a string/stream.
+     */
+    public static final String EMBEDDED_HCF_OPEN = "<<<HexCodeFile";
+
+    /**
+     * Delimiter placed after a HexCodeFile when embedded in a string/stream.
+     */
+    public static final String EMBEDDED_HCF_CLOSE = "HexCodeFile>>>";
+
+    /**
+     * Map from a machine code position to a list of comments for the position.
+     */
+    public final Map<Integer, List<String>> comments = new TreeMap<>();
+
+    /**
+     * Map from a machine code position to a comment for the operands of the instruction at the
+     * position.
+     */
+    public final Map<Integer, List<String>> operandComments = new TreeMap<>();
+
+    public final byte[] code;
+
+    public final ArrayList<JumpTable> jumpTables = new ArrayList<>();
+
+    public final String isa;
+
+    public final int wordWidth;
+
+    public final long startAddress;
+
+    public HexCodeFile(byte[] code, long startAddress, String isa, int wordWidth) {
+        this.code = code;
+        this.startAddress = startAddress;
+        this.isa = isa;
+        this.wordWidth = wordWidth;
+    }
+
+    /**
+     * Parses a string in the format produced by {@link #toString()} to produce a
+     * {@link HexCodeFile} object.
+     */
+    public static HexCodeFile parse(String input, int sourceOffset, String source, String sourceName) {
+        return new Parser(input, sourceOffset, source, sourceName).hcf;
+    }
+
+    /**
+     * Formats this HexCodeFile as a string that can be parsed with
+     * {@link #parse(String, int, String, String)}.
+     */
+    @Override
+    public String toString() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        writeTo(baos);
+        return baos.toString();
+    }
+
+    public String toEmbeddedString() {
+        return EMBEDDED_HCF_OPEN + NEW_LINE + toString() + EMBEDDED_HCF_CLOSE;
+    }
+
+    public void writeTo(OutputStream out) {
+        PrintStream ps = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
+        ps.printf("Platform %s %d %s%n", isa, wordWidth, SECTION_DELIM);
+        ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM);
+
+        for (JumpTable table : jumpTables) {
+            ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM);
+        }
+
+        for (Map.Entry<Integer, List<String>> e : comments.entrySet()) {
+            int pos = e.getKey();
+            for (String comment : e.getValue()) {
+                ps.printf("Comment %d %s %s%n", pos, comment, SECTION_DELIM);
+            }
+        }
+
+        for (Map.Entry<Integer, List<String>> e : operandComments.entrySet()) {
+            for (String c : e.getValue()) {
+                ps.printf("OperandComment %d %s %s%n", e.getKey(), c, SECTION_DELIM);
+            }
+        }
+        ps.flush();
+    }
+
+    /**
+     * Formats a byte array as a string of hex digits.
+     */
+    public static String hexCodeString(byte[] code) {
+        if (code == null) {
+            return "";
+        } else {
+            StringBuilder sb = new StringBuilder(code.length * 2);
+            for (int b : code) {
+                String hex = Integer.toHexString(b & 0xff);
+                if (hex.length() == 1) {
+                    sb.append('0');
+                }
+                sb.append(hex);
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Adds a comment to the list of comments for a given position.
+     */
+    public void addComment(int pos, String comment) {
+        List<String> list = comments.get(pos);
+        if (list == null) {
+            list = new ArrayList<>();
+            comments.put(pos, list);
+        }
+        list.add(encodeString(comment));
+    }
+
+    /**
+     * Adds an operand comment for a given position.
+     */
+    public void addOperandComment(int pos, String comment) {
+        List<String> list = comments.get(pos);
+        if (list == null) {
+            list = new ArrayList<>(1);
+            comments.put(pos, list);
+        }
+        list.add(encodeString(comment));
+    }
+
+    /**
+     * Adds any jump tables, lookup tables or code comments from a list of code annotations.
+     */
+    public static void addAnnotations(HexCodeFile hcf, List<CodeAnnotation> annotations) {
+        if (annotations == null || annotations.isEmpty()) {
+            return;
+        }
+        for (CodeAnnotation a : annotations) {
+            if (a instanceof JumpTable) {
+                JumpTable table = (JumpTable) a;
+                hcf.jumpTables.add(table);
+            } else if (a instanceof CodeComment) {
+                CodeComment comment = (CodeComment) a;
+                hcf.addComment(comment.position, comment.value);
+            }
+        }
+    }
+
+    /**
+     * Modifies a string to mangle any substrings matching {@link #SECTION_DELIM} and
+     * {@link #COLUMN_END}.
+     */
+    public static String encodeString(String input) {
+        int index;
+        String s = input;
+        while ((index = s.indexOf(SECTION_DELIM)) != -1) {
+            s = s.substring(0, index) + " < |@" + s.substring(index + SECTION_DELIM.length());
+        }
+        while ((index = s.indexOf(COLUMN_END)) != -1) {
+            s = s.substring(0, index) + " < @" + s.substring(index + COLUMN_END.length());
+        }
+        return s;
+    }
+
+    /**
+     * Helper class to parse a string in the format produced by {@link HexCodeFile#toString()} and
+     * produce a {@link HexCodeFile} object.
+     */
+    static class Parser {
+
+        final String input;
+        final String inputSource;
+        String isa;
+        int wordWidth;
+        byte[] code;
+        long startAddress;
+        HexCodeFile hcf;
+
+        Parser(String input, int sourceOffset, String source, String sourceName) {
+            this.input = input;
+            this.inputSource = sourceName;
+            parseSections(sourceOffset, source);
+        }
+
+        void makeHCF() {
+            if (hcf == null) {
+                if (isa != null && wordWidth != 0 && code != null) {
+                    hcf = new HexCodeFile(code, startAddress, isa, wordWidth);
+                }
+            }
+        }
+
+        void checkHCF(String section, int offset) {
+            check(hcf != null, offset, section + " section must be after Platform and HexCode section");
+        }
+
+        void check(boolean condition, int offset, String message) {
+            if (!condition) {
+                error(offset, message);
+            }
+        }
+
+        Error error(int offset, String message) {
+            throw new Error(errorMessage(offset, message));
+        }
+
+        void warning(int offset, String message) {
+            PrintStream err = System.err;
+            err.println("Warning: " + errorMessage(offset, message));
+        }
+
+        String errorMessage(int offset, String message) {
+            assert offset < input.length();
+            InputPos inputPos = filePos(offset);
+            int lineEnd = input.indexOf(HexCodeFile.NEW_LINE, offset);
+            int lineStart = offset - inputPos.col;
+            String line = lineEnd == -1 ? input.substring(lineStart) : input.substring(lineStart, lineEnd);
+            return String.format("%s:%d: %s%n%s%n%" + (inputPos.col + 1) + "s", inputSource, inputPos.line, message, line, "^");
+        }
+
+        static class InputPos {
+
+            final int line;
+            final int col;
+
+            InputPos(int line, int col) {
+                this.line = line;
+                this.col = col;
+            }
+        }
+
+        InputPos filePos(int index) {
+            assert input != null;
+            int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1;
+
+            String l = input.substring(lineStart, lineStart + 10);
+            PrintStream out = System.out;
+            out.println("YYY" + input.substring(index, index + 10) + "...");
+            out.println("XXX" + l + "...");
+
+            int pos = input.indexOf(HexCodeFile.NEW_LINE, 0);
+            int line = 1;
+            while (pos > 0 && pos < index) {
+                line++;
+                pos = input.indexOf(HexCodeFile.NEW_LINE, pos + 1);
+            }
+            return new InputPos(line, index - lineStart);
+        }
+
+        void parseSections(int offset, String source) {
+            assert input.startsWith(source, offset);
+            int index = 0;
+            int endIndex = source.indexOf(SECTION_DELIM);
+            while (endIndex != -1) {
+                while (source.charAt(index) <= ' ') {
+                    index++;
+                }
+                String section = source.substring(index, endIndex).trim();
+                parseSection(offset + index, section);
+                index = endIndex + SECTION_DELIM.length();
+                endIndex = source.indexOf(SECTION_DELIM, index);
+            }
+        }
+
+        int parseInt(int offset, String value) {
+            try {
+                return Integer.parseInt(value);
+            } catch (NumberFormatException e) {
+                throw error(offset, "Not a valid integer: " + value);
+            }
+        }
+
+        void parseSection(int offset, String section) {
+            if (section.isEmpty()) {
+                return;
+            }
+            assert input.startsWith(section, offset);
+            Matcher m = HexCodeFile.SECTION.matcher(section);
+            check(m.matches(), offset, "Section does not match pattern " + HexCodeFile.SECTION);
+
+            String header = m.group(1);
+            String body = m.group(2);
+            int headerOffset = offset + m.start(1);
+            int bodyOffset = offset + m.start(2);
+
+            if (header.equals("Platform")) {
+                check(isa == null, bodyOffset, "Duplicate Platform section found");
+                m = HexCodeFile.PLATFORM.matcher(body);
+                check(m.matches(), bodyOffset, "Platform does not match pattern " + HexCodeFile.PLATFORM);
+                isa = m.group(1);
+                wordWidth = parseInt(bodyOffset + m.start(2), m.group(2));
+                makeHCF();
+            } else if (header.equals("HexCode")) {
+                check(code == null, bodyOffset, "Duplicate Code section found");
+                m = HexCodeFile.HEX_CODE.matcher(body);
+                check(m.matches(), bodyOffset, "Code does not match pattern " + HexCodeFile.HEX_CODE);
+                String hexAddress = m.group(1);
+                startAddress = Long.valueOf(hexAddress, 16);
+                String hexCode = m.group(2);
+                if (hexCode == null) {
+                    code = new byte[0];
+                } else {
+                    check((hexCode.length() % 2) == 0, bodyOffset, "Hex code length must be even");
+                    code = new byte[hexCode.length() / 2];
+                    for (int i = 0; i < code.length; i++) {
+                        String hexByte = hexCode.substring(i * 2, (i + 1) * 2);
+                        code[i] = (byte) Integer.parseInt(hexByte, 16);
+                    }
+                }
+                makeHCF();
+            } else if (header.equals("Comment")) {
+                checkHCF("Comment", headerOffset);
+                m = HexCodeFile.COMMENT.matcher(body);
+                check(m.matches(), bodyOffset, "Comment does not match pattern " + HexCodeFile.COMMENT);
+                int pos = parseInt(bodyOffset + m.start(1), m.group(1));
+                String comment = m.group(2);
+                hcf.addComment(pos, comment);
+            } else if (header.equals("OperandComment")) {
+                checkHCF("OperandComment", headerOffset);
+                m = HexCodeFile.OPERAND_COMMENT.matcher(body);
+                check(m.matches(), bodyOffset, "OperandComment does not match pattern " + HexCodeFile.OPERAND_COMMENT);
+                int pos = parseInt(bodyOffset + m.start(1), m.group(1));
+                String comment = m.group(2);
+                hcf.addOperandComment(pos, comment);
+            } else if (header.equals("JumpTable")) {
+                checkHCF("JumpTable", headerOffset);
+                m = HexCodeFile.JUMP_TABLE.matcher(body);
+                check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE);
+                int pos = parseInt(bodyOffset + m.start(1), m.group(1));
+                int entrySize = parseInt(bodyOffset + m.start(2), m.group(2));
+                int low = parseInt(bodyOffset + m.start(3), m.group(3));
+                int high = parseInt(bodyOffset + m.start(4), m.group(4));
+                hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize));
+            } else {
+                error(offset, "Unknown section header: " + header);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java
new file mode 100644
index 0000000..dad3a03
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.util.Arrays;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter;
+import jdk.vm.ci.code.CodeUtil.RefMapFormatter;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.ExceptionHandler;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.Mark;
+
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+/**
+ * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}.
+ */
+@ServiceProvider(DisassemblerProvider.class)
+public class HexCodeFileDisassemblerProvider implements DisassemblerProvider {
+
+    @Override
+    public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) {
+        assert compResult != null;
+        return disassemble(codeCache, compResult, null);
+    }
+
+    @Override
+    public String getName() {
+        return "hcf";
+    }
+
+    @Override
+    public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) {
+        assert installedCode != null;
+        return installedCode.isValid() ? disassemble(codeCache, compResult, installedCode) : null;
+    }
+
+    private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) {
+        TargetDescription target = codeCache.getTarget();
+        RegisterConfig regConfig = codeCache.getRegisterConfig();
+        byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode();
+        if (code == null) {
+            // Method was deoptimized/invalidated
+            return "";
+        }
+        long start = installedCode == null ? 0L : installedCode.getStart();
+        HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8);
+        if (compResult != null) {
+            HexCodeFile.addAnnotations(hcf, compResult.getAnnotations());
+            addExceptionHandlersComment(compResult, hcf);
+            Register fp = regConfig.getFrameRegister();
+            RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.wordSize, fp, 0);
+            for (Infopoint infopoint : compResult.getInfopoints()) {
+                if (infopoint instanceof Call) {
+                    Call call = (Call) infopoint;
+                    if (call.debugInfo != null) {
+                        hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString());
+                    }
+                    addOperandComment(hcf, call.pcOffset, "{" + codeCache.getTargetName(call) + "}");
+                } else {
+                    if (infopoint.debugInfo != null) {
+                        hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString());
+                    }
+                    addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}");
+                }
+            }
+            for (DataPatch site : compResult.getDataPatches()) {
+                hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}");
+            }
+            for (Mark mark : compResult.getMarks()) {
+                hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark));
+            }
+        }
+        String hcfEmbeddedString = hcf.toEmbeddedString();
+        return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString);
+    }
+
+    private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) {
+        if (!compResult.getExceptionHandlers().isEmpty()) {
+            String nl = HexCodeFile.NEW_LINE;
+            StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl);
+            for (ExceptionHandler e : compResult.getExceptionHandlers()) {
+                buf.append("    ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl);
+                hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]");
+                hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]");
+            }
+            hcf.addComment(0, buf.toString());
+        }
+    }
+
+    private static void addOperandComment(HexCodeFile hcf, int pos, String comment) {
+        hcf.addOperandComment(pos, comment);
+    }
+
+    /**
+     * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded}
+     * {@link HexCodeFile}.
+     */
+    static class HexCodeFileDisTool {
+        static final MethodHandle processMethod;
+
+        static {
+            MethodHandle toolMethod = null;
+            try {
+                Class<?> toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader());
+                toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class));
+            } catch (Exception e) {
+                // Tool not available on the class path
+            }
+            processMethod = toolMethod;
+        }
+
+        public static String tryDisassemble(String hcfEmbeddedString) {
+            if (processMethod != null) {
+                try {
+                    return (String) processMethod.invokeExact(hcfEmbeddedString);
+                } catch (Throwable e) {
+                    // If the tool is available, for now let's be noisy when it fails
+                    throw new InternalError(e);
+                }
+            }
+            return hcfEmbeddedString;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceMapping.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceMapping.java
new file mode 100644
index 0000000..19b9068
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceMapping.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString;
+
+import org.graalvm.compiler.graph.NodeSourcePosition;
+
+/**
+ * This provides a mapping between a half-open range of PCs in the generated code and a
+ * {@link NodeSourcePosition} in the original program. Depending on the backend this information may
+ * be represented in different ways or not at all.
+ */
+public final class SourceMapping {
+
+    private final int startOffset;
+
+    private final int endOffset;
+
+    private final NodeSourcePosition sourcePosition;
+
+    public SourceMapping(int startOffset, int endOffset, NodeSourcePosition sourcePosition) {
+        this.startOffset = startOffset;
+        this.endOffset = endOffset;
+        this.sourcePosition = sourcePosition;
+    }
+
+    public int getStartOffset() {
+        return startOffset;
+    }
+
+    public int getEndOffset() {
+        return endOffset;
+    }
+
+    public NodeSourcePosition getSourcePosition() {
+        return sourcePosition;
+    }
+
+    @Override
+    public String toString() {
+        return identityHashCodeString(this);
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException("hashCode");
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SourceMapping) {
+            SourceMapping other = (SourceMapping) obj;
+            return other.startOffset == startOffset && other.endOffset == endOffset && other.sourcePosition.equals(sourcePosition);
+        }
+        return false;
+    }
+
+    public boolean contains(int offset) {
+        return startOffset <= offset && offset < endOffset;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java
new file mode 100644
index 0000000..d28ab09
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.code;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+
+/**
+ * Represents a bailout exception with a stack trace in terms of the Java source being compiled
+ * instead of the stack trace of the compiler. The exception of the compiler is saved as the cause
+ * of this exception.
+ */
+public abstract class SourceStackTraceBailoutException extends PermanentBailoutException {
+    private static final long serialVersionUID = 2144811793442316776L;
+
+    public static SourceStackTraceBailoutException create(Throwable cause, String format, StackTraceElement[] elements) {
+        return new SourceStackTraceBailoutException(cause, format) {
+
+            private static final long serialVersionUID = 6279381376051787907L;
+
+            @Override
+            public synchronized Throwable fillInStackTrace() {
+                assert elements != null;
+                setStackTrace(elements);
+                return this;
+            }
+        };
+    }
+
+    private SourceStackTraceBailoutException(Throwable cause, String format) {
+        super(cause, format);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/PermanentBailoutException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/PermanentBailoutException.java
new file mode 100644
index 0000000..52da33ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/PermanentBailoutException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.common;
+
+import jdk.vm.ci.code.BailoutException;
+
+public class PermanentBailoutException extends BailoutException {
+
+    private static final long serialVersionUID = -2683649650135362549L;
+
+    public PermanentBailoutException(String format, Object... args) {
+        super(true, format, args);
+    }
+
+    public PermanentBailoutException(String reason) {
+        super(true, reason);
+    }
+
+    public PermanentBailoutException(Throwable cause, String format, Object... args) {
+        super(cause, format, args);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/RetryableBailoutException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/RetryableBailoutException.java
new file mode 100644
index 0000000..61ef730
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.common/src/org/graalvm/compiler/common/RetryableBailoutException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.common;
+
+import jdk.vm.ci.code.BailoutException;
+
+public class RetryableBailoutException extends BailoutException {
+
+    private static final long serialVersionUID = -7145365025679144525L;
+
+    public RetryableBailoutException(String format, Object... args) {
+        super(false, format, args);
+    }
+
+    public RetryableBailoutException(String reason) {
+        super(false, reason);
+    }
+
+    public RetryableBailoutException(Throwable cause, String format) {
+        super(cause, format);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressLowering.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressLowering.java
new file mode 100644
index 0000000..051b044
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressLowering.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
+
+public class AArch64AddressLowering extends AddressLowering {
+
+    @Override
+    public AddressNode lower(ValueNode address) {
+        return lower(address, null);
+    }
+
+    @Override
+    public AddressNode lower(ValueNode base, ValueNode offset) {
+        AArch64AddressNode ret = new AArch64AddressNode(base, offset);
+        // TODO improve
+        return base.graph().unique(ret);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressNode.java
new file mode 100644
index 0000000..176480d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64AddressNode.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents an address of the form... TODO.
+ */
+@NodeInfo
+public class AArch64AddressNode extends AddressNode implements LIRLowerable {
+
+    public static final NodeClass<AArch64AddressNode> TYPE = NodeClass.create(AArch64AddressNode.class);
+
+    @OptionalInput private ValueNode base;
+
+    @OptionalInput private ValueNode index;
+    private AArch64Address.AddressingMode addressingMode;
+
+    private int displacement;
+
+    public AArch64AddressNode(ValueNode base) {
+        this(base, null);
+    }
+
+    public AArch64AddressNode(ValueNode base, ValueNode index) {
+        super(TYPE);
+        this.base = base;
+        this.index = index;
+        this.addressingMode = AddressingMode.REGISTER_OFFSET;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+
+        AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base));
+        AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index));
+
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue indexReference;
+        if (addressingMode.equals(AddressingMode.IMMEDIATE_UNSCALED)) {
+            indexReference = LIRKind.derivedBaseFromValue(indexValue);
+            throw GraalError.unimplemented();
+        } else {
+            if (LIRKind.isValue(indexValue.getValueKind())) {
+                indexReference = null;
+            } else {
+                indexReference = Value.ILLEGAL;
+            }
+        }
+
+        LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
+        final boolean scaled = false;
+        gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, displacement, scaled, addressingMode));
+    }
+
+    public ValueNode getBase() {
+        return base;
+    }
+
+    public void setBase(ValueNode base) {
+        // allow modification before inserting into the graph
+        if (isAlive()) {
+            updateUsages(this.base, base);
+        }
+        this.base = base;
+    }
+
+    public ValueNode getIndex() {
+        return index;
+    }
+
+    public void setIndex(ValueNode index) {
+        // allow modification before inserting into the graph
+        if (isAlive()) {
+            updateUsages(this.index, index);
+        }
+        this.index = index;
+    }
+
+    public int getDisplacement() {
+        return displacement;
+    }
+
+    public void setDisplacement(int displacement) {
+        this.displacement = displacement;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
new file mode 100644
index 0000000..786b669
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
+import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
+import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp;
+import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
+import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp;
+import org.graalvm.compiler.lir.aarch64.AArch64SignExtendOp;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool {
+
+    @Override
+    public AArch64LIRGenerator getLIRGen() {
+        return (AArch64LIRGenerator) super.getLIRGen();
+    }
+
+    @Override
+    protected boolean isNumericInteger(PlatformKind kind) {
+        return ((AArch64Kind) kind).isInteger();
+    }
+
+    @Override
+    protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.ADDS : AArch64ArithmeticOp.ADD;
+            return emitBinary(resultKind, op, true, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FADD, true, a, b);
+        }
+    }
+
+    @Override
+    protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.SUBS : AArch64ArithmeticOp.SUB;
+            return emitBinary(resultKind, op, false, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FSUB, false, a, b);
+        }
+    }
+
+    @Override
+    public Value emitMul(Value a, Value b, boolean setFlags) {
+        // TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list
+        assert !setFlags : "Set flags on multiplication is not supported";
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b);
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.DIV, AArch64ArithmeticOp.FDIV), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.REM, AArch64ArithmeticOp.FREM), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UDIV, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UREM, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitAnd(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.AND, true, a, b);
+    }
+
+    @Override
+    public Value emitOr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.OR, true, a, b);
+    }
+
+    @Override
+    public Value emitXor(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.XOR, true, a, b);
+    }
+
+    @Override
+    public Value emitShl(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SHL, false, a, b);
+    }
+
+    @Override
+    public Value emitShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ASHR, false, a, b);
+    }
+
+    @Override
+    public Value emitUShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.LSHR, false, a, b);
+    }
+
+    @Override
+    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
+        PlatformKind resultPlatformKind = getFloatConvertResultKind(op);
+        LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind);
+        Variable result = getLIRGen().newVariable(resultLirKind);
+        getLIRGen().append(new AArch64FloatConvertOp(op, result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    private static PlatformKind getFloatConvertResultKind(FloatConvert op) {
+        switch (op) {
+            case F2I:
+            case D2I:
+                return AArch64Kind.DWORD;
+            case F2L:
+            case D2L:
+                return AArch64Kind.QWORD;
+            case I2F:
+            case L2F:
+            case D2F:
+                return AArch64Kind.SINGLE;
+            case I2D:
+            case L2D:
+            case F2D:
+                return AArch64Kind.DOUBLE;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
+        ValueKind<?> from = inputVal.getValueKind();
+        if (to.equals(from)) {
+            return inputVal;
+        }
+        Variable result = getLIRGen().newVariable(to);
+        getLIRGen().append(new AArch64ReinterpretOp(result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    @Override
+    public Value emitNarrow(Value inputVal, int bits) {
+        if (inputVal.getPlatformKind() == AArch64Kind.QWORD && bits <= 32) {
+            LIRKind resultKind = getResultLirKind(bits, inputVal);
+            long mask = NumUtil.getNbitNumberLong(bits);
+            Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+            return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+        } else {
+            return inputVal;
+        }
+    }
+
+    @Override
+    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        long mask = NumUtil.getNbitNumberLong(fromBits);
+        Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+        return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+    }
+
+    @Override
+    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        Variable result = getLIRGen().newVariable(resultKind);
+        getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal), fromBits, toBits));
+        return result;
+    }
+
+    private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) {
+        if (resultBitSize == 64) {
+            return LIRKind.combine(inputValues).changeType(QWORD);
+        } else {
+            assert resultBitSize == 32;
+            return LIRKind.combine(inputValues).changeType(DWORD);
+        }
+    }
+
+    protected Variable emitBinary(ValueKind<?> resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (isValidBinaryConstant(op, a, b)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(a), asJavaConstant(b));
+        } else if (commutative && isValidBinaryConstant(op, b, a)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(b), asJavaConstant(a));
+        } else {
+            emitBinaryVar(result, op, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+        return result;
+    }
+
+    private void emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b) {
+        AllocatableValue x = moveSp(a);
+        AllocatableValue y = moveSp(b);
+        switch (op) {
+            case FREM:
+            case REM:
+            case UREM:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryCompositeOp(op, result, x, y));
+                break;
+            default:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryOp(op, result, x, y));
+                break;
+        }
+    }
+
+    private void emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b) {
+        AllocatableValue x = moveSp(a);
+        getLIRGen().append(new AArch64ArithmeticOp.BinaryConstOp(op, result, x, b));
+    }
+
+    private static boolean isValidBinaryConstant(AArch64ArithmeticOp op, Value a, Value b) {
+        if (!isJavaConstant(b)) {
+            return false;
+        }
+        JavaConstant constValue = asJavaConstant(b);
+        switch (op.category) {
+            case LOGICAL:
+                return isLogicalConstant(constValue);
+            case ARITHMETIC:
+                return isArithmeticConstant(constValue);
+            case SHIFT:
+                assert constValue.asLong() >= 0 && constValue.asLong() < a.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+                return true;
+            case NONE:
+                return false;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static boolean isLogicalConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asInt());
+            case Long:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asLong());
+            default:
+                return false;
+        }
+    }
+
+    protected static boolean isArithmeticConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+            case Long:
+                return AArch64MacroAssembler.isArithmeticImmediate(constValue.asLong());
+            case Object:
+                return constValue.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public Value emitNegate(Value inputVal) {
+        return emitUnary(getOpCode(inputVal, AArch64ArithmeticOp.NEG, AArch64ArithmeticOp.FNEG), inputVal);
+    }
+
+    @Override
+    public Value emitNot(Value input) {
+        assert isNumericInteger(input.getPlatformKind());
+        return emitUnary(AArch64ArithmeticOp.NOT, input);
+    }
+
+    @Override
+    public Value emitMathAbs(Value input) {
+        return emitUnary(getOpCode(input, AArch64ArithmeticOp.ABS, AArch64ArithmeticOp.FABS), input);
+    }
+
+    @Override
+    public Value emitMathSqrt(Value input) {
+        assert input.getPlatformKind() == AArch64Kind.DOUBLE;
+        return emitUnary(AArch64ArithmeticOp.SQRT, input);
+    }
+
+    @Override
+    public Value emitBitScanForward(Value inputVal) {
+        return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal);
+    }
+
+    @Override
+    public Value emitBitCount(Value operand) {
+        throw GraalError.unimplemented("AArch64 ISA does not offer way to implement this more efficiently than a simple Java algorithm.");
+    }
+
+    @Override
+    public Value emitBitScanReverse(Value inputVal) {
+        // TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node
+        // for that though
+        return emitBitManipulation(BitManipulationOpCode.BSR, inputVal);
+    }
+
+    @Override
+    public Value emitCountLeadingZeros(Value value) {
+        return emitBitManipulation(BitManipulationOpCode.CLZ, value);
+    }
+
+    @Override
+    public Value emitCountTrailingZeros(Value value) {
+        throw GraalError.unimplemented();
+    }
+
+    private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) {
+        assert isNumericInteger(inputVal.getPlatformKind());
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64BitManipulationOp(op, result, input));
+        return result;
+    }
+
+    private Variable emitUnary(AArch64ArithmeticOp op, Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64ArithmeticOp.UnaryOp(op, result, input));
+        return result;
+    }
+
+    /**
+     * If val denotes the stackpointer, move it to another location. This is necessary since most
+     * ops cannot handle the stackpointer as input or output.
+     */
+    private AllocatableValue moveSp(AllocatableValue val) {
+        if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) {
+            assert val.getPlatformKind() == AArch64Kind.QWORD : "Stackpointer must be long";
+            return getLIRGen().emitMove(val);
+        }
+        return val;
+    }
+
+    /**
+     * Returns the opcode depending on the platform kind of val.
+     */
+    private AArch64ArithmeticOp getOpCode(Value val, AArch64ArithmeticOp intOp, AArch64ArithmeticOp floatOp) {
+        return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp;
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AArch64AddressValue loadAddress = getLIRGen().asAddressValue(address);
+        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
+        getLIRGen().append(new LoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
+        return result;
+    }
+
+    @Override
+    public void emitStore(ValueKind<?> lirKind, Value address, Value inputVal, LIRFrameState state) {
+        AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address);
+        AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
+
+        if (isJavaConstant(inputVal) && kind.isInteger()) {
+            JavaConstant c = asJavaConstant(inputVal);
+            if (c.isDefaultForKind()) {
+                // We can load 0 directly into integer registers
+                getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state));
+                return;
+            }
+        }
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        getLIRGen().append(new StoreOp(kind, storeAddress, input, state));
+    }
+
+    @Override
+    public Value emitMathLog(Value input, boolean base10) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public Value emitMathCos(Value input) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public Value emitMathSin(Value input) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public Value emitMathTan(Value input) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right) {
+        throw GraalError.unimplemented();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64FloatConvertOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64FloatConvertOp.java
new file mode 100644
index 0000000..2a09890
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64FloatConvertOp.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public final class AArch64FloatConvertOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64FloatConvertOp> TYPE = LIRInstructionClass.create(AArch64FloatConvertOp.class);
+
+    private final FloatConvert op;
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    protected AArch64FloatConvertOp(FloatConvert op, AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        this.op = op;
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        int fromSize = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        int toSize = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        switch (op) {
+            case F2I:
+            case D2I:
+            case F2L:
+            case D2L:
+                masm.fcvtzs(toSize, fromSize, result, input);
+                break;
+            case I2F:
+            case I2D:
+            case L2F:
+            case L2D:
+                masm.scvtf(toSize, fromSize, result, input);
+                break;
+            case D2F:
+            case F2D:
+                masm.fcvt(fromSize, result, input);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java
new file mode 100644
index 0000000..03e777a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.aarch64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+
+import java.util.function.Function;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Compare;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Move;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
+import org.graalvm.compiler.lir.aarch64.AArch64PauseOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public abstract class AArch64LIRGenerator extends LIRGenerator {
+
+    public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
+    }
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected static final boolean canStoreConstant(JavaConstant c) {
+        // Our own code never calls this since we can't make a definite statement about whether or
+        // not we can inline a constant without knowing what kind of operation we execute. Let's be
+        // optimistic here and fix up mistakes later.
+        return true;
+    }
+
+    /**
+     * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
+     */
+    @Override
+    public <K extends ValueKind<K>> K toRegisterKind(K kind) {
+        switch ((AArch64Kind) kind.getPlatformKind()) {
+            case BYTE:
+            case WORD:
+                return kind.changeType(AArch64Kind.DWORD);
+            default:
+                return kind;
+        }
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
+    @Override
+    public Variable emitAddress(AllocatableValue stackslot) {
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new AArch64Move.StackLoadAddressOp(result, stackslot));
+        return result;
+    }
+
+    public AArch64AddressValue asAddressValue(Value address) {
+        if (address instanceof AArch64AddressValue) {
+            return (AArch64AddressValue) address;
+        } else {
+            return new AArch64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, false, AddressingMode.BASE_REGISTER_ONLY);
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        Variable result = newVariable(trueValue.getValueKind());
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
+        return result;
+    }
+
+    @Override
+    public void emitMembar(int barriers) {
+        int necessaryBarriers = target().arch.requiredBarriers(barriers);
+        if (target().isMP && necessaryBarriers != 0) {
+            append(new MembarOp(necessaryBarriers));
+        }
+    }
+
+    @Override
+    public void emitJump(LabelRef label) {
+        assert label != null;
+        append(new StandardOp.JumpOp(label));
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) {
+        append(new AArch64ControlFlow.BranchOp(ConditionFlag.VS, overflow, noOverflow, overflowProbability));
+    }
+
+    /**
+     * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueDestination destination if left & right == 0. Non null.
+     * @param falseDestination destination if left & right != 0. Non null
+     * @param trueSuccessorProbability hoistoric probability that comparison is true
+     */
+    @Override
+    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), AArch64ArithmeticOp.ANDS, true, left, right);
+        append(new AArch64ControlFlow.BranchOp(ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability));
+    }
+
+    /**
+     * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else
+     * falseValue.
+     *
+     * @param left Arbitrary value. Has to have same type as right. Non null.
+     * @param right Arbitrary value. Has to have same type as left. Non null.
+     * @param cond condition that decides whether to move trueValue or falseValue into result. Non
+     *            null.
+     * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
+     *            not. Ignored for integer comparisons.
+     * @param trueValue arbitrary value same type as falseValue. Non null.
+     * @param falseValue arbitrary value same type as trueValue. Non null.
+     * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
+     *         null.
+     */
+    @Override
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        Variable result = newVariable(trueValue.getValueKind());
+        append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));
+        return result;
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
+    }
+
+    private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
+        return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
+    }
+
+    /**
+     * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
+     * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly
+     * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'!
+     */
+    private static ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) {
+        switch (cond) {
+            case LT:
+                return unorderedIsTrue ? ConditionFlag.LT : ConditionFlag.LO;
+            case LE:
+                return unorderedIsTrue ? ConditionFlag.LE : ConditionFlag.LS;
+            case GE:
+                return unorderedIsTrue ? ConditionFlag.PL : ConditionFlag.GE;
+            case GT:
+                return unorderedIsTrue ? ConditionFlag.HI : ConditionFlag.GT;
+            case EQ:
+                return ConditionFlag.EQ;
+            case NE:
+                return ConditionFlag.NE;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Takes a Condition and returns the correct Aarch64 specific ConditionFlag.
+     */
+    private static ConditionFlag toIntConditionFlag(Condition cond) {
+        switch (cond) {
+            case EQ:
+                return ConditionFlag.EQ;
+            case NE:
+                return ConditionFlag.NE;
+            case LT:
+                return ConditionFlag.LT;
+            case LE:
+                return ConditionFlag.LE;
+            case GT:
+                return ConditionFlag.GT;
+            case GE:
+                return ConditionFlag.GE;
+            case AE:
+                return ConditionFlag.HS;
+            case BE:
+                return ConditionFlag.LS;
+            case AT:
+                return ConditionFlag.HI;
+            case BT:
+                return ConditionFlag.LO;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * This method emits the compare instruction, and may reorder the operands. It returns true if
+     * it did so.
+     *
+     * @param a the left operand of the comparison. Has to have same type as b. Non null.
+     * @param b the right operand of the comparison. Has to have same type as a. Non null.
+     * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done).
+     */
+    protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) {
+        Value left;
+        Value right;
+        boolean mirrored;
+        AArch64Kind kind = (AArch64Kind) cmpKind;
+        if (kind.isInteger()) {
+            if (LIRValueUtil.isVariable(b)) {
+                left = load(b);
+                right = loadNonConst(a);
+                mirrored = true;
+            } else {
+                left = load(a);
+                right = loadNonConst(b);
+                mirrored = false;
+            }
+            append(new AArch64Compare.CompareOp(left, loadNonCompareConst(right)));
+        } else if (kind.isSIMD()) {
+            if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) {
+                left = load(b);
+                right = a;
+                mirrored = true;
+            } else if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) {
+                left = load(a);
+                right = b;
+                mirrored = false;
+            } else {
+                left = load(a);
+                right = loadReg(b);
+                mirrored = false;
+            }
+            append(new AArch64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue));
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+        return mirrored;
+    }
+
+    /**
+     * If value is a constant that cannot be used directly with a gpCompare instruction load it into
+     * a register and return the register, otherwise return constant value unchanged.
+     */
+    protected Value loadNonCompareConst(Value value) {
+        if (!isCompareConstant(value)) {
+            return loadReg(value);
+        }
+        return value;
+    }
+
+    /**
+     * Checks whether value can be used directly with a gpCompare instruction. This is <b>not</b>
+     * the same as {@link AArch64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because
+     * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for
+     * floats.
+     *
+     * @param value any type. Non null.
+     * @return true if value can be used directly in comparison instruction, false otherwise.
+     */
+    public boolean isCompareConstant(Value value) {
+        if (isJavaConstant(value)) {
+            JavaConstant constant = asJavaConstant(value);
+            if (constant instanceof PrimitiveConstant) {
+                final long longValue = constant.asLong();
+                long maskedValue;
+                switch (constant.getJavaKind()) {
+                    case Boolean:
+                    case Byte:
+                        maskedValue = longValue & 0xFF;
+                        break;
+                    case Char:
+                    case Short:
+                        maskedValue = longValue & 0xFFFF;
+                        break;
+                    case Int:
+                        maskedValue = longValue & 0xFFFF_FFFF;
+                        break;
+                    case Long:
+                        maskedValue = longValue;
+                        break;
+                    default:
+                        throw GraalError.shouldNotReachHere();
+                }
+                return AArch64MacroAssembler.isArithmeticImmediate(maskedValue);
+            } else {
+                return constant.isDefaultForKind();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Moves trueValue into result if (left & right) == 0, else falseValue.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueValue Integer kind. Non null.
+     * @param falseValue Integer kind. Non null.
+     * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
+     */
+    @Override
+    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
+        assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
+        Variable result = newVariable(trueValue.getValueKind());
+        append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));
+        return result;
+    }
+
+    @Override
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), AArch64LIRGenerator::toIntConditionFlag));
+    }
+
+    protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
+                    Function<Condition, ConditionFlag> converter) {
+        return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
+    }
+
+    @Override
+    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
+        // Make copy of key since the TableSwitch destroys its input.
+        Variable tmp = emitMove(key);
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch));
+    }
+
+    @Override
+    public Variable emitByteSwap(Value operand) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw GraalError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw GraalError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    protected JavaConstant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((AArch64Kind) kind) {
+            case BYTE:
+                return JavaConstant.forByte((byte) dead);
+            case WORD:
+                return JavaConstant.forShort((short) dead);
+            case DWORD:
+                return JavaConstant.forInt((int) dead);
+            case QWORD:
+                return JavaConstant.forLong(dead);
+            case SINGLE:
+                return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
+            case DOUBLE:
+                return JavaConstant.forDouble(Double.longBitsToDouble(dead));
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Loads value into virtual register. Contrary to {@link #load(Value)} this handles
+     * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not
+     * creating an unnecessary move into a virtual register.
+     *
+     * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0,
+     * [x0] instead of: ldr x0, [x19].
+     */
+    protected AllocatableValue loadReg(Value val) {
+        if (!(val instanceof Variable || val instanceof RegisterValue)) {
+            return emitMove(val);
+        }
+        return (AllocatableValue) val;
+    }
+
+    @Override
+    public void emitPause() {
+        append(new AArch64PauseOp());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java
new file mode 100644
index 0000000..101a59d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+
+public class AArch64LIRKindTool implements LIRKindTool {
+
+    @Override
+    public LIRKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return LIRKind.value(AArch64Kind.BYTE);
+        } else if (bits <= 16) {
+            return LIRKind.value(AArch64Kind.WORD);
+        } else if (bits <= 32) {
+            return LIRKind.value(AArch64Kind.DWORD);
+        } else {
+            assert bits <= 64;
+            return LIRKind.value(AArch64Kind.QWORD);
+        }
+    }
+
+    @Override
+    public LIRKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return LIRKind.value(AArch64Kind.SINGLE);
+            case 64:
+                return LIRKind.value(AArch64Kind.DOUBLE);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(AArch64Kind.QWORD);
+    }
+
+    @Override
+    public LIRKind getWordKind() {
+        return LIRKind.value(AArch64Kind.QWORD);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java
new file mode 100644
index 0000000..fe04202
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
+import org.graalvm.compiler.lir.aarch64.AArch64Move;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadAddressOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64MoveFactory implements MoveFactory {
+
+    @Override
+    public LIRInstruction createMove(AllocatableValue dst, Value src) {
+        boolean srcIsSlot = isStackSlotValue(src);
+        boolean dstIsSlot = isStackSlotValue(dst);
+        if (isConstantValue(src)) {
+            return createLoad(dst, asConstant(src));
+        } else if (src instanceof AArch64AddressValue) {
+            return new LoadAddressOp(dst, (AArch64AddressValue) src);
+        } else {
+            assert src instanceof AllocatableValue;
+            if (srcIsSlot && dstIsSlot) {
+                throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass());
+            } else {
+                return new AArch64Move.Move(dst, (AllocatableValue) src);
+            }
+        }
+    }
+
+    @Override
+    public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        return new AArch64Move.Move(result, input);
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (src instanceof JavaConstant) {
+            JavaConstant javaConstant = (JavaConstant) src;
+            if (canInlineConstant(javaConstant)) {
+                return new AArch64Move.LoadInlineConstant(javaConstant, dst);
+            } else {
+                // return new AArch64Move.LoadConstantFromTable(javaConstant,
+                // constantTableBaseProvider.getConstantTableBase(), dst);
+                return new AArch64Move.LoadInlineConstant(javaConstant, dst);
+            }
+        } else if (src instanceof DataPointerConstant) {
+            return new AArch64Move.LoadDataOp(dst, (DataPointerConstant) src);
+        } else {
+            // throw GraalError.shouldNotReachHere(src.getClass().toString());
+            throw GraalError.unimplemented();
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        switch (c.getJavaKind()) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+                return AArch64MacroAssembler.isMovableImmediate(c.asInt());
+            case Long:
+                return AArch64MacroAssembler.isMovableImmediate(c.asLong());
+            case Object:
+                return c.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeLIRBuilder.java
new file mode 100644
index 0000000..fc14c08
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeLIRBuilder.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * This class implements the AArch64 specific portion of the LIR generator.
+ */
+public abstract class AArch64NodeLIRBuilder extends NodeLIRBuilder {
+
+    public AArch64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, AArch64NodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) super.getLIRGeneratorTool();
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        // XXX Maybe we need something like this.
+        // getLIRGeneratorTool().emitLoadConstantTableBase();
+        super.emitPrologue(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java
new file mode 100644
index 0000000..b99cd62
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.memory.Access;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+
+public class AArch64NodeMatchRules extends NodeMatchRules {
+
+    public AArch64NodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AArch64Kind getMemoryKind(Access access) {
+        return (AArch64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) gen;
+    }
+
+    protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
+        return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesProvider.java
new file mode 100644
index 0000000..4eadf9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.aarch64;
+
+import org.graalvm.compiler.java.DefaultSuitesProvider;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+
+public class AArch64SuitesProvider extends DefaultSuitesProvider {
+
+    public AArch64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64AllocatorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64AllocatorTest.java
new file mode 100644
index 0000000..0904f9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64AllocatorTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64.test;
+
+import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
+import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
+import static org.junit.Assume.assumeTrue;
+import jdk.vm.ci.amd64.AMD64;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.backend.AllocatorTest;
+
+public class AMD64AllocatorTest extends AllocatorTest {
+
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+        assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
+        assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
+    }
+
+    @Test
+    public void test1() {
+        testAllocation("test1snippet", 3, 1, 0);
+    }
+
+    public static long test1snippet(long x) {
+        return x + 5;
+    }
+
+    @Test
+    public void test2() {
+        testAllocation("test2snippet", 3, 0, 0);
+    }
+
+    public static long test2snippet(long x) {
+        return x * 5;
+    }
+
+    @Ignore
+    @Test
+    public void test3() {
+        testAllocation("test3snippet", 4, 1, 0);
+    }
+
+    public static long test3snippet(long x) {
+        return x / 3 + x % 3;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/ConstantStackMoveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/ConstantStackMoveTest.java
new file mode 100644
index 0000000..1d0b97d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/ConstantStackMoveTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+public class ConstantStackMoveTest extends LIRTest {
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    private static class LoadConstantStackSpec extends LIRTestSpecification {
+        protected final Object primitive;
+
+        LoadConstantStackSpec(Object primitive) {
+            this.primitive = primitive;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            PrimitiveConstant constantValue = JavaConstant.forBoxedPrimitive(primitive);
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(LIRKind.fromJavaKind(gen.target().arch, constantValue.getJavaKind()));
+            // move stuff around
+            gen.emitMoveConstant(s1, constantValue);
+            gen.emitBlackhole(s1);
+            setResult(gen.emitMove(s1));
+        }
+    }
+
+    private static final class LoadConstantStackSpecByte extends LoadConstantStackSpec {
+        LoadConstantStackSpecByte(byte primitive) {
+            super(primitive);
+        }
+
+        byte get() {
+            return (Byte) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecShort extends LoadConstantStackSpec {
+        LoadConstantStackSpecShort(short primitive) {
+            super(primitive);
+        }
+
+        short get() {
+            return (Short) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecInteger extends LoadConstantStackSpec {
+        LoadConstantStackSpecInteger(int primitive) {
+            super(primitive);
+        }
+
+        int get() {
+            return (Integer) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecLong extends LoadConstantStackSpec {
+        LoadConstantStackSpecLong(long primitive) {
+            super(primitive);
+        }
+
+        long get() {
+            return (Long) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecFloat extends LoadConstantStackSpec {
+        LoadConstantStackSpecFloat(float primitive) {
+            super(primitive);
+        }
+
+        float get() {
+            return (Float) primitive;
+        }
+    }
+
+    private static final class LoadConstantStackSpecDouble extends LoadConstantStackSpec {
+        LoadConstantStackSpecDouble(double primitive) {
+            super(primitive);
+        }
+
+        double get() {
+            return (Double) primitive;
+        }
+    }
+
+    private static final LoadConstantStackSpecByte stackCopyByte = new LoadConstantStackSpecByte(Byte.MAX_VALUE);
+    private static final LoadConstantStackSpecShort stackCopyShort = new LoadConstantStackSpecShort(Short.MAX_VALUE);
+    private static final LoadConstantStackSpecInteger stackCopyInt = new LoadConstantStackSpecInteger(Integer.MAX_VALUE);
+    private static final LoadConstantStackSpecLong stackCopyLong = new LoadConstantStackSpecLong(Long.MAX_VALUE);
+    private static final LoadConstantStackSpecFloat stackCopyFloat = new LoadConstantStackSpecFloat(Float.MAX_VALUE);
+    private static final LoadConstantStackSpecDouble stackCopyDouble = new LoadConstantStackSpecDouble(Double.MAX_VALUE);
+
+    @LIRIntrinsic
+    public static byte testCopyByte(LoadConstantStackSpecByte spec) {
+        return spec.get();
+    }
+
+    public byte testByte() {
+        return testCopyByte(stackCopyByte);
+    }
+
+    @Test
+    public void runByte() throws Throwable {
+        runTest("testByte");
+    }
+
+    @LIRIntrinsic
+    public static short testCopyShort(LoadConstantStackSpecShort spec) {
+        return spec.get();
+    }
+
+    public short testShort() {
+        return testCopyShort(stackCopyShort);
+    }
+
+    @Test
+    public void runShort() throws Throwable {
+        runTest("testShort");
+    }
+
+    @LIRIntrinsic
+    public static int testCopyInt(LoadConstantStackSpecInteger spec) {
+        return spec.get();
+    }
+
+    public int testInt() {
+        return testCopyInt(stackCopyInt);
+    }
+
+    @Test
+    public void runInt() throws Throwable {
+        runTest("testInt");
+    }
+
+    @LIRIntrinsic
+    public static long testCopyLong(LoadConstantStackSpecLong spec) {
+        return spec.get();
+    }
+
+    public long testLong() {
+        return testCopyLong(stackCopyLong);
+    }
+
+    @Test
+    public void runLong() throws Throwable {
+        runTest("testLong");
+    }
+
+    @LIRIntrinsic
+    public static float testCopyFloat(LoadConstantStackSpecFloat spec) {
+        return spec.get();
+    }
+
+    public float testFloat() {
+        return testCopyFloat(stackCopyFloat);
+    }
+
+    @Test
+    public void runFloat() throws Throwable {
+        runTest("testFloat");
+    }
+
+    @LIRIntrinsic
+    public static double testCopyDouble(LoadConstantStackSpecDouble spec) {
+        return spec.get();
+    }
+
+    public double testDouble() {
+        return testCopyDouble(stackCopyDouble);
+    }
+
+    @Test
+    public void runDouble() throws Throwable {
+        runTest("testDouble");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/MatchRuleTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/MatchRuleTest.java
new file mode 100644
index 0000000..a1384c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/MatchRuleTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.TargetDescription;
+
+public class MatchRuleTest extends LIRTest {
+    private static LIR lir;
+
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    public static int test1Snippet(TestClass o, TestClass b, TestClass c) {
+        if (o.x == 42) {
+            return b.z;
+        } else {
+            return c.y;
+        }
+    }
+
+    /**
+     * Verifies, if the match rules in AMD64NodeMatchRules do work on the graphs by compiling and
+     * checking if the expected LIR instruction show up.
+     */
+    @Test
+    public void test1() {
+        getLIRSuites().getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
+        compile(getResolvedJavaMethod("test1Snippet"), null);
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof MemoryConstOp && ((MemoryConstOp) ins).getOpcode().toString().equals("CMP")) {
+                assertFalse("MemoryConstOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("Memory compare must be in the LIR", found);
+    }
+
+    public static class TestClass {
+        public int x;
+        public int y;
+        public int z;
+
+        public TestClass(int x) {
+            super();
+            this.x = x;
+        }
+    }
+
+    public static class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
+        @Override
+        protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
+            lir = lirGenRes.getLIR();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/StackStoreTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/StackStoreTest.java
new file mode 100644
index 0000000..8d25cfe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/StackStoreTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class StackStoreTest extends LIRTest {
+    @Before
+    public void checkAMD64() {
+        assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    private static final LIRTestSpecification stackCopy0 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind());
+            VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD));
+            // move stuff around
+            gen.emitMove(s1, a);
+            gen.emitMoveConstant(s2, JavaConstant.forShort(Short.MIN_VALUE));
+            setResult(gen.emitMove(s1));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    private static final LIRTestSpecification stackCopy1 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind());
+            VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD));
+            // move stuff around
+            gen.emitMove(s1, a);
+            Value v = gen.emitLoadConstant(LIRKind.value(AMD64Kind.WORD), JavaConstant.forShort(Short.MIN_VALUE));
+            gen.emitMove(s2, v);
+            setResult(gen.emitMove(s1));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    private static final LIRTestSpecification stackCopy2 = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(a.getValueKind());
+            VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(AMD64Kind.WORD));
+            // move stuff around
+            gen.emitMoveConstant(s2, JavaConstant.forShort(Short.MIN_VALUE));
+            gen.emitMove(s1, a);
+            setResult(gen.emitMove(s2));
+            gen.emitBlackhole(s1);
+            gen.emitBlackhole(s2);
+        }
+    };
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static int testShortStackSlot(LIRTestSpecification spec, int a) {
+        return a;
+    }
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static short testShortStackSlot2(LIRTestSpecification spec, int a) {
+        return Short.MIN_VALUE;
+    }
+
+    public int test0(int a) {
+        return testShortStackSlot(stackCopy0, a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test0", 0xDEADDEAD);
+    }
+
+    public int test1(int a) {
+        return testShortStackSlot(stackCopy1, a);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test1", 0xDEADDEAD);
+    }
+
+    public int test2(int a) {
+        return testShortStackSlot2(stackCopy2, a);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test2", 0xDEADDEAD);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java
new file mode 100644
index 0000000..a43d034
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
+
+public class AMD64AddressLowering extends AddressLowering {
+
+    @Override
+    public AddressNode lower(ValueNode address) {
+        return lower(address, null);
+    }
+
+    @Override
+    public AddressNode lower(ValueNode base, ValueNode offset) {
+        AMD64AddressNode ret = new AMD64AddressNode(base, offset);
+        boolean changed;
+        do {
+            changed = improve(ret);
+        } while (changed);
+        return base.graph().unique(ret);
+    }
+
+    protected boolean improve(AMD64AddressNode ret) {
+        ValueNode newBase = improveInput(ret, ret.getBase(), 0);
+        if (newBase != ret.getBase()) {
+            ret.setBase(newBase);
+            return true;
+        }
+
+        ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2);
+        if (newIdx != ret.getIndex()) {
+            ret.setIndex(newIdx);
+            return true;
+        }
+
+        if (ret.getIndex() instanceof LeftShiftNode) {
+            LeftShiftNode shift = (LeftShiftNode) ret.getIndex();
+            if (shift.getY().isConstant()) {
+                int amount = ret.getScale().log2 + shift.getY().asJavaConstant().asInt();
+                Scale scale = Scale.fromShift(amount);
+                if (scale != null) {
+                    ret.setIndex(shift.getX());
+                    ret.setScale(scale);
+                    return true;
+                }
+            }
+        }
+
+        if (ret.getScale() == Scale.Times1) {
+            if (ret.getBase() == null || ret.getIndex() == null) {
+                if (ret.getBase() instanceof AddNode) {
+                    AddNode add = (AddNode) ret.getBase();
+                    ret.setBase(add.getX());
+                    ret.setIndex(add.getY());
+                    return true;
+                } else if (ret.getIndex() instanceof AddNode) {
+                    AddNode add = (AddNode) ret.getIndex();
+                    ret.setBase(add.getX());
+                    ret.setIndex(add.getY());
+                    return true;
+                }
+            }
+
+            if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) {
+                ValueNode tmp = ret.getBase();
+                ret.setBase(ret.getIndex());
+                ret.setIndex(tmp);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) {
+        if (node == null) {
+            return null;
+        }
+
+        JavaConstant c = node.asJavaConstant();
+        if (c != null) {
+            return improveConstDisp(address, node, c, null, shift);
+        } else {
+            if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) {
+                if (node instanceof ZeroExtendNode) {
+                    if (((ZeroExtendNode) node).getInputBits() == 32) {
+                        /*
+                         * We can just swallow a zero-extend from 32 bit to 64 bit because the upper
+                         * half of the register will always be zero.
+                         */
+                        return ((ZeroExtendNode) node).getValue();
+                    }
+                } else if (node instanceof AddNode) {
+                    AddNode add = (AddNode) node;
+                    if (add.getX().isConstant()) {
+                        return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift);
+                    } else if (add.getY().isConstant()) {
+                        return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift);
+                    }
+                }
+            }
+        }
+
+        return node;
+    }
+
+    private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) {
+        if (c.getJavaKind().isNumericInteger()) {
+            long disp = address.getDisplacement();
+            disp += c.asLong() << shift;
+            if (NumUtil.isInt(disp)) {
+                address.setDisplacement((int) disp);
+                return other;
+            }
+        }
+        return original;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java
new file mode 100644
index 0000000..1281418
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents an address of the form [base + index*scale + displacement]. Both base and index are
+ * optional.
+ */
+@NodeInfo
+public class AMD64AddressNode extends AddressNode implements LIRLowerable {
+
+    public static final NodeClass<AMD64AddressNode> TYPE = NodeClass.create(AMD64AddressNode.class);
+
+    @OptionalInput private ValueNode base;
+
+    @OptionalInput private ValueNode index;
+    private Scale scale;
+
+    private int displacement;
+
+    public AMD64AddressNode(ValueNode base) {
+        this(base, null);
+    }
+
+    public AMD64AddressNode(ValueNode base, ValueNode index) {
+        super(TYPE);
+        this.base = base;
+        this.index = index;
+        this.scale = Scale.Times1;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+
+        AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base));
+        AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index));
+
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue indexReference;
+        if (scale.equals(Scale.Times1)) {
+            indexReference = LIRKind.derivedBaseFromValue(indexValue);
+        } else {
+            if (LIRKind.isValue(indexValue)) {
+                indexReference = null;
+            } else {
+                indexReference = Value.ILLEGAL;
+            }
+        }
+
+        LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
+        gen.setResult(this, new AMD64AddressValue(kind, baseValue, indexValue, scale, displacement));
+    }
+
+    public ValueNode getBase() {
+        return base;
+    }
+
+    public void setBase(ValueNode base) {
+        // allow modification before inserting into the graph
+        if (isAlive()) {
+            updateUsages(this.base, base);
+        }
+        this.base = base;
+    }
+
+    public ValueNode getIndex() {
+        return index;
+    }
+
+    public void setIndex(ValueNode index) {
+        // allow modification before inserting into the graph
+        if (isAlive()) {
+            updateUsages(this.index, index);
+        }
+        this.index = index;
+    }
+
+    public Scale getScale() {
+        return scale;
+    }
+
+    public void setScale(Scale scale) {
+        this.scale = scale;
+    }
+
+    public int getDisplacement() {
+        return displacement;
+    }
+
+    public void setDisplacement(int displacement) {
+        this.displacement = displacement;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java
new file mode 100644
index 0000000..4eba248
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java
@@ -0,0 +1,1271 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NEG;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSF;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOV;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZX;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZXB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.POPCNT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TEST;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TESTB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROL;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SAR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHL;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.BYTE;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM;
+import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FPDivRemOp;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.amd64.AMD64Binary;
+import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
+import org.graalvm.compiler.lir.amd64.AMD64ClearRegisterOp;
+import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp;
+import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp;
+import org.graalvm.compiler.lir.amd64.AMD64MulDivOp;
+import org.graalvm.compiler.lir.amd64.AMD64ShiftOp;
+import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp;
+import org.graalvm.compiler.lir.amd64.AMD64Unary;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.VMConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * This class implements the AMD64 specific portion of the LIR generator.
+ */
+public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AMD64ArithmeticLIRGeneratorTool {
+
+    private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD));
+
+    @Override
+    public Variable emitNegate(Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) input.getPlatformKind()) {
+            case DWORD:
+                getLIRGen().append(new AMD64Unary.MOp(NEG, DWORD, result, input));
+                break;
+            case QWORD:
+                getLIRGen().append(new AMD64Unary.MOp(NEG, QWORD, result, input));
+                break;
+            case SINGLE:
+                if (isAvx) {
+                    getLIRGen().append(new AMD64Binary.DataThreeOp(AVXOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
+                } else {
+                    getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
+                }
+                break;
+            case DOUBLE:
+                if (isAvx) {
+                    getLIRGen().append(new AMD64Binary.DataThreeOp(AVXOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
+                } else {
+                    getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
+                }
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    @Override
+    public Variable emitNot(Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        switch ((AMD64Kind) input.getPlatformKind()) {
+            case DWORD:
+                getLIRGen().append(new AMD64Unary.MOp(NOT, DWORD, result, input));
+                break;
+            case QWORD:
+                getLIRGen().append(new AMD64Unary.MOp(NOT, QWORD, result, input));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    private Variable emitBinary(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) {
+        if (isJavaConstant(b)) {
+            return emitBinaryConst(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), asConstantValue(b), setFlags);
+        } else if (commutative && isJavaConstant(a)) {
+            return emitBinaryConst(resultKind, op, size, commutative, getLIRGen().asAllocatable(b), asConstantValue(a), setFlags);
+        } else {
+            return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+    }
+
+    private Variable emitBinary(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) {
+        if (isJavaConstant(b)) {
+            return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(a), asJavaConstant(b));
+        } else if (commutative && isJavaConstant(a)) {
+            return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(b), asJavaConstant(a));
+        } else {
+            return emitBinaryVar(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+    }
+
+    private Variable emitBinary(LIRKind resultKind, AMD64RRMOp op, OperandSize size, boolean commutative, Value a, Value b) {
+        if (isJavaConstant(b)) {
+            return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(a), asJavaConstant(b));
+        } else if (commutative && isJavaConstant(a)) {
+            return emitBinaryConst(resultKind, op, size, getLIRGen().asAllocatable(b), asJavaConstant(a));
+        } else {
+            return emitBinaryVar(resultKind, op, size, commutative, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+    }
+
+    private Variable emitBinaryConst(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, ConstantValue b, boolean setFlags) {
+        long value = b.getJavaConstant().asLong();
+        if (NumUtil.isInt(value)) {
+            Variable result = getLIRGen().newVariable(resultKind);
+            int constant = (int) value;
+
+            if (!setFlags) {
+                AMD64MOp mop = getMOp(op, constant);
+                if (mop != null) {
+                    getLIRGen().append(new AMD64Unary.MOp(mop, size, result, a));
+                    return result;
+                }
+            }
+
+            getLIRGen().append(new AMD64Binary.ConstOp(op, size, result, a, constant));
+            return result;
+        } else {
+            return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, a, getLIRGen().asAllocatable(b));
+        }
+    }
+
+    private static AMD64MOp getMOp(AMD64BinaryArithmetic op, int constant) {
+        if (constant == 1) {
+            if (op.equals(AMD64BinaryArithmetic.ADD)) {
+                return AMD64MOp.INC;
+            }
+            if (op.equals(AMD64BinaryArithmetic.SUB)) {
+                return AMD64MOp.DEC;
+            }
+        } else if (constant == -1) {
+            if (op.equals(AMD64BinaryArithmetic.ADD)) {
+                return AMD64MOp.DEC;
+            }
+            if (op.equals(AMD64BinaryArithmetic.SUB)) {
+                return AMD64MOp.INC;
+            }
+        }
+        return null;
+    }
+
+    private Variable emitBinaryConst(LIRKind resultKind, AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        getLIRGen().append(new AMD64Binary.DataTwoOp(op, size, result, a, b));
+        return result;
+    }
+
+    private Variable emitBinaryConst(LIRKind resultKind, AMD64RRMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        getLIRGen().append(new AMD64Binary.DataThreeOp(op, size, result, a, b));
+        return result;
+    }
+
+    private Variable emitBinaryVar(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (commutative) {
+            getLIRGen().append(new AMD64Binary.CommutativeTwoOp(op, size, result, a, b));
+        } else {
+            getLIRGen().append(new AMD64Binary.TwoOp(op, size, result, a, b));
+        }
+        return result;
+    }
+
+    private Variable emitBinaryVar(LIRKind resultKind, AMD64RRMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (commutative) {
+            getLIRGen().append(new AMD64Binary.CommutativeThreeOp(op, size, result, a, b));
+        } else {
+            getLIRGen().append(new AMD64Binary.ThreeOp(op, size, result, a, b));
+        }
+        return result;
+    }
+
+    @Override
+    protected boolean isNumericInteger(PlatformKind kind) {
+        return ((AMD64Kind) kind).isInteger();
+    }
+
+    @Override
+    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitBinary(resultKind, ADD, DWORD, true, a, b, setFlags);
+            case QWORD:
+                return emitBinary(resultKind, ADD, QWORD, true, a, b, setFlags);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.ADD, SS, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.ADD, SS, true, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.ADD, SD, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.ADD, SD, true, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitBinary(resultKind, SUB, DWORD, false, a, b, setFlags);
+            case QWORD:
+                return emitBinary(resultKind, SUB, QWORD, false, a, b, setFlags);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.SUB, SS, false, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.SUB, SS, false, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.SUB, SD, false, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.SUB, SD, false, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private Variable emitIMULConst(OperandSize size, AllocatableValue a, ConstantValue b) {
+        long value = b.getJavaConstant().asLong();
+        if (NumUtil.isInt(value)) {
+            int imm = (int) value;
+            AMD64RMIOp op;
+            if (NumUtil.isByte(imm)) {
+                op = AMD64RMIOp.IMUL_SX;
+            } else {
+                op = AMD64RMIOp.IMUL;
+            }
+
+            Variable ret = getLIRGen().newVariable(LIRKind.combine(a, b));
+            getLIRGen().append(new AMD64Binary.RMIOp(op, size, ret, a, imm));
+            return ret;
+        } else {
+            return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, a, getLIRGen().asAllocatable(b));
+        }
+    }
+
+    private Variable emitIMUL(OperandSize size, Value a, Value b) {
+        if (isJavaConstant(b)) {
+            return emitIMULConst(size, getLIRGen().asAllocatable(a), asConstantValue(b));
+        } else if (isJavaConstant(a)) {
+            return emitIMULConst(size, getLIRGen().asAllocatable(b), asConstantValue(a));
+        } else {
+            return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+    }
+
+    @Override
+    public Variable emitMul(Value a, Value b, boolean setFlags) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitIMUL(DWORD, a, b);
+            case QWORD:
+                return emitIMUL(QWORD, a, b);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.MUL, SS, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.MUL, SS, true, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.MUL, SD, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.MUL, SD, true, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private RegisterValue moveToReg(Register reg, Value v) {
+        RegisterValue ret = reg.asValue(v.getValueKind());
+        getLIRGen().emitMove(ret, v);
+        return ret;
+    }
+
+    private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) {
+        AMD64MulDivOp mulHigh = getLIRGen().append(new AMD64MulDivOp(opcode, size, LIRKind.combine(a, b), moveToReg(AMD64.rax, a), getLIRGen().asAllocatable(b)));
+        return getLIRGen().emitMove(mulHigh.getHighResult());
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b);
+            case QWORD:
+                return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitMulHigh(AMD64MOp.MUL, DWORD, a, b);
+            case QWORD:
+                return emitMulHigh(AMD64MOp.MUL, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a));
+        getLIRGen().append(new AMD64Binary.MemoryTwoOp(op, size, result, a, location, state));
+        return result;
+    }
+
+    public Value emitBinaryMemory(AMD64RRMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a));
+        getLIRGen().append(new AMD64Binary.MemoryThreeOp(op, size, result, a, location, state));
+        return result;
+    }
+
+    protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(LIRKind.value(kind));
+        getLIRGen().append(new AMD64Unary.MemoryOp(op, size, result, address, state));
+        return result;
+    }
+
+    protected Value emitZeroExtendMemory(AMD64Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
+        // Issue a zero extending load of the proper bit size and set the result to
+        // the proper kind.
+        Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD));
+        switch (memoryKind) {
+            case BYTE:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state));
+                break;
+            case WORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state));
+                break;
+            case DWORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state));
+                break;
+            case QWORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
+        LIRKind kind = LIRKind.combine(a, b);
+
+        AMD64SignExtendOp sx = getLIRGen().append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a)));
+        return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), getLIRGen().asAllocatable(b), state));
+    }
+
+    private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
+        LIRKind kind = LIRKind.combine(a, b);
+
+        RegisterValue rax = moveToReg(AMD64.rax, a);
+        RegisterValue rdx = AMD64.rdx.asValue(kind);
+        getLIRGen().append(new AMD64ClearRegisterOp(size, rdx));
+        return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, getLIRGen().asAllocatable(b), state));
+    }
+
+    public Value[] emitSignedDivRem(Value a, Value b, LIRFrameState state) {
+        AMD64MulDivOp op;
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                op = emitIDIV(DWORD, a, b, state);
+                break;
+            case QWORD:
+                op = emitIDIV(QWORD, a, b, state);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())};
+    }
+
+    public Value[] emitUnsignedDivRem(Value a, Value b, LIRFrameState state) {
+        AMD64MulDivOp op;
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                op = emitDIV(DWORD, a, b, state);
+                break;
+            case QWORD:
+                op = emitDIV(QWORD, a, b, state);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())};
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        LIRKind resultKind = LIRKind.combine(a, b);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
+                return getLIRGen().emitMove(op.getQuotient());
+            case QWORD:
+                AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
+                return getLIRGen().emitMove(lop.getQuotient());
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.DIV, SS, false, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.DIV, SS, false, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.DIV, SD, false, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.DIV, SD, false, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
+                return getLIRGen().emitMove(op.getRemainder());
+            case QWORD:
+                AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
+                return getLIRGen().emitMove(lop.getRemainder());
+            case SINGLE: {
+                Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+                getLIRGen().append(new FPDivRemOp(FREM, result, getLIRGen().load(a), getLIRGen().load(b)));
+                return result;
+            }
+            case DOUBLE: {
+                Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+                getLIRGen().append(new FPDivRemOp(DREM, result, getLIRGen().load(a), getLIRGen().load(b)));
+                return result;
+            }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
+        AMD64MulDivOp op;
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                op = emitDIV(DWORD, a, b, state);
+                break;
+            case QWORD:
+                op = emitDIV(QWORD, a, b, state);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return getLIRGen().emitMove(op.getQuotient());
+    }
+
+    @Override
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
+        AMD64MulDivOp op;
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                op = emitDIV(DWORD, a, b, state);
+                break;
+            case QWORD:
+                op = emitDIV(QWORD, a, b, state);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return getLIRGen().emitMove(op.getRemainder());
+    }
+
+    @Override
+    public Variable emitAnd(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitBinary(resultKind, AND, DWORD, true, a, b, false);
+            case QWORD:
+                return emitBinary(resultKind, AND, QWORD, true, a, b, false);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.AND, PS, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.AND, PS, true, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.AND, PD, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.AND, PD, true, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitOr(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitBinary(resultKind, OR, DWORD, true, a, b, false);
+            case QWORD:
+                return emitBinary(resultKind, OR, QWORD, true, a, b, false);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.OR, PS, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.OR, PS, true, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.OR, PD, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.OR, PD, true, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitXor(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        TargetDescription target = getLIRGen().target();
+        boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitBinary(resultKind, XOR, DWORD, true, a, b, false);
+            case QWORD:
+                return emitBinary(resultKind, XOR, QWORD, true, a, b, false);
+            case SINGLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.XOR, PS, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.XOR, PS, true, a, b);
+                }
+            case DOUBLE:
+                if (isAvx) {
+                    return emitBinary(resultKind, AVXOp.XOR, PD, true, a, b);
+                } else {
+                    return emitBinary(resultKind, SSEOp.XOR, PD, true, a, b);
+                }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind()));
+        AllocatableValue input = getLIRGen().asAllocatable(a);
+        if (isJavaConstant(b)) {
+            JavaConstant c = asJavaConstant(b);
+            if (c.asLong() == 1) {
+                getLIRGen().append(new AMD64Unary.MOp(op.m1Op, size, result, input));
+            } else {
+                /*
+                 * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is
+                 * always correct, even without the NumUtil.is32bit() test.
+                 */
+                getLIRGen().append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong()));
+            }
+        } else {
+            getLIRGen().emitMove(RCX_I, b);
+            getLIRGen().append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I));
+        }
+        return result;
+    }
+
+    @Override
+    public Variable emitShl(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitShift(SHL, DWORD, a, b);
+            case QWORD:
+                return emitShift(SHL, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitShr(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitShift(SAR, DWORD, a, b);
+            case QWORD:
+                return emitShift(SAR, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitUShr(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitShift(SHR, DWORD, a, b);
+            case QWORD:
+                return emitShift(SHR, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public Variable emitRol(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitShift(ROL, DWORD, a, b);
+            case QWORD:
+                return emitShift(ROL, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public Variable emitRor(Value a, Value b) {
+        switch ((AMD64Kind) a.getPlatformKind()) {
+            case DWORD:
+                return emitShift(ROR, DWORD, a, b);
+            case QWORD:
+                return emitShift(ROR, QWORD, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) {
+        Variable result = getLIRGen().newVariable(kind);
+        getLIRGen().append(new AMD64Unary.RMOp(op, size, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+    private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) {
+        Variable result = getLIRGen().newVariable(kind);
+        getLIRGen().append(new AMD64Unary.MROp(op, size, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
+        ValueKind<?> from = inputVal.getValueKind();
+        if (to.equals(from)) {
+            return inputVal;
+        }
+
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
+        AMD64Kind fromKind = (AMD64Kind) from.getPlatformKind();
+        switch ((AMD64Kind) to.getPlatformKind()) {
+            case DWORD:
+                switch (fromKind) {
+                    case SINGLE:
+                        return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input);
+                }
+                break;
+            case QWORD:
+                switch (fromKind) {
+                    case DOUBLE:
+                        return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input);
+                }
+                break;
+            case SINGLE:
+                switch (fromKind) {
+                    case DWORD:
+                        return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input);
+                }
+                break;
+            case DOUBLE:
+                switch (fromKind) {
+                    case QWORD:
+                        return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input);
+                }
+                break;
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Value emitFloatConvert(FloatConvert op, Value input) {
+        switch (op) {
+            case D2F:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSD2SS, SD, input);
+            case D2I:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSD2SI, DWORD, input);
+            case D2L:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSD2SI, QWORD, input);
+            case F2D:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSS2SD, SS, input);
+            case F2I:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSS2SI, DWORD, input);
+            case F2L:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSS2SI, QWORD, input);
+            case I2D:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, DWORD, input);
+            case I2F:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, DWORD, input);
+            case L2D:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, QWORD, input);
+            case L2F:
+                return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, QWORD, input);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitNarrow(Value inputVal, int bits) {
+        if (inputVal.getPlatformKind() == AMD64Kind.QWORD && bits <= 32) {
+            // TODO make it possible to reinterpret Long as Int in LIR without move
+            return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), AMD64RMOp.MOV, DWORD, inputVal);
+        } else {
+            return inputVal;
+        }
+    }
+
+    @Override
+    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        if (fromBits == toBits) {
+            return inputVal;
+        } else if (toBits > 32) {
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXB, QWORD, inputVal);
+                case 16:
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSX, QWORD, inputVal);
+                case 32:
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXD, QWORD, inputVal);
+                default:
+                    throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSXB, DWORD, inputVal);
+                case 16:
+                    return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSX, DWORD, inputVal);
+                case 32:
+                    return inputVal;
+                default:
+                    throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+    }
+
+    @Override
+    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        if (fromBits == toBits) {
+            return inputVal;
+        } else if (fromBits > 32) {
+            assert inputVal.getPlatformKind() == AMD64Kind.QWORD;
+            Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal));
+            long mask = CodeUtil.mask(fromBits);
+            getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(QWORD), QWORD, result, getLIRGen().asAllocatable(inputVal), JavaConstant.forLong(mask)));
+            return result;
+        } else {
+            LIRKind resultKind = LIRKind.combine(inputVal);
+            if (toBits > 32) {
+                resultKind = resultKind.changeType(AMD64Kind.QWORD);
+            } else {
+                resultKind = resultKind.changeType(AMD64Kind.DWORD);
+            }
+
+            /*
+             * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD
+             * operations implicitly set the upper half of the register to 0, which is what we want
+             * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is
+             * sometimes one byte shorter.
+             */
+            switch (fromBits) {
+                case 8:
+                    return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal);
+                case 16:
+                    return emitConvertOp(resultKind, MOVZX, DWORD, inputVal);
+                case 32:
+                    return emitConvertOp(resultKind, MOV, DWORD, inputVal);
+            }
+
+            // odd bit count, fall back on manual masking
+            Variable result = getLIRGen().newVariable(resultKind);
+            JavaConstant mask;
+            if (toBits > 32) {
+                mask = JavaConstant.forLong(CodeUtil.mask(fromBits));
+            } else {
+                mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits));
+            }
+            getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(DWORD), DWORD, result, getLIRGen().asAllocatable(inputVal), mask));
+            return result;
+        }
+    }
+
+    @Override
+    public Variable emitBitCount(Value value) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
+        assert ((AMD64Kind) value.getPlatformKind()).isInteger();
+        if (value.getPlatformKind() == AMD64Kind.QWORD) {
+            getLIRGen().append(new AMD64Unary.RMOp(POPCNT, QWORD, result, getLIRGen().asAllocatable(value)));
+        } else {
+            getLIRGen().append(new AMD64Unary.RMOp(POPCNT, DWORD, result, getLIRGen().asAllocatable(value)));
+        }
+        return result;
+    }
+
+    @Override
+    public Variable emitBitScanForward(Value value) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
+        getLIRGen().append(new AMD64Unary.RMOp(BSF, QWORD, result, getLIRGen().asAllocatable(value)));
+        return result;
+    }
+
+    @Override
+    public Variable emitBitScanReverse(Value value) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
+        assert ((AMD64Kind) value.getPlatformKind()).isInteger();
+        if (value.getPlatformKind() == AMD64Kind.QWORD) {
+            getLIRGen().append(new AMD64Unary.RMOp(BSR, QWORD, result, getLIRGen().asAllocatable(value)));
+        } else {
+            getLIRGen().append(new AMD64Unary.RMOp(BSR, DWORD, result, getLIRGen().asAllocatable(value)));
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitCountLeadingZeros(Value value) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
+        assert ((AMD64Kind) value.getPlatformKind()).isInteger();
+        if (value.getPlatformKind() == AMD64Kind.QWORD) {
+            getLIRGen().append(new AMD64Unary.RMOp(LZCNT, QWORD, result, getLIRGen().asAllocatable(value)));
+        } else {
+            getLIRGen().append(new AMD64Unary.RMOp(LZCNT, DWORD, result, getLIRGen().asAllocatable(value)));
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitCountTrailingZeros(Value value) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
+        assert ((AMD64Kind) value.getPlatformKind()).isInteger();
+        if (value.getPlatformKind() == AMD64Kind.QWORD) {
+            getLIRGen().append(new AMD64Unary.RMOp(TZCNT, QWORD, result, getLIRGen().asAllocatable(value)));
+        } else {
+            getLIRGen().append(new AMD64Unary.RMOp(TZCNT, DWORD, result, getLIRGen().asAllocatable(value)));
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitMathAbs(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        switch ((AMD64Kind) input.getPlatformKind()) {
+            case SINGLE:
+                getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PS, result, getLIRGen().asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
+                break;
+            case DOUBLE:
+                getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PD, result, getLIRGen().asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitMathSqrt(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        switch ((AMD64Kind) input.getPlatformKind()) {
+            case SINGLE:
+                getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, getLIRGen().asAllocatable(input)));
+                break;
+            case DOUBLE:
+                getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, getLIRGen().asAllocatable(input)));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitMathLog(Value input, boolean base10) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot));
+        return result;
+    }
+
+    @Override
+    public Value emitMathCos(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot));
+        return result;
+    }
+
+    @Override
+    public Value emitMathSin(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot));
+        return result;
+    }
+
+    @Override
+    public Value emitMathTan(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot));
+        return result;
+    }
+
+    @Override
+    public Value emitMathExp(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), EXP, result, getLIRGen().asAllocatable(input), stackSlot));
+        return result;
+    }
+
+    @Override
+    public Value emitMathPow(Value input1, Value input2) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input1));
+        getLIRGen().append(new AMD64MathIntrinsicBinaryOp(getAMD64LIRGen(), POW, result, getLIRGen().asAllocatable(input1), getLIRGen().asAllocatable(input2)));
+        return result;
+    }
+
+    protected AMD64LIRGenerator getAMD64LIRGen() {
+        return (AMD64LIRGenerator) getLIRGen();
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AMD64AddressValue loadAddress = getAMD64LIRGen().asAddressValue(address);
+        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
+        switch ((AMD64Kind) kind.getPlatformKind()) {
+            case BYTE:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
+                break;
+            case WORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
+                break;
+            case DWORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
+                break;
+            case QWORD:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
+                break;
+            case SINGLE:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
+                break;
+            case DOUBLE:
+                getLIRGen().append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    protected void emitStoreConst(AMD64Kind kind, AMD64AddressValue address, ConstantValue value, LIRFrameState state) {
+        Constant c = value.getConstant();
+        if (JavaConstant.isNull(c)) {
+            assert kind == AMD64Kind.DWORD || kind == AMD64Kind.QWORD;
+            OperandSize size = kind == AMD64Kind.DWORD ? DWORD : QWORD;
+            getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
+            return;
+        } else if (c instanceof VMConstant) {
+            // only 32-bit constants can be patched
+            if (kind == AMD64Kind.DWORD) {
+                if (getLIRGen().target().inlineObjects || !(c instanceof JavaConstant)) {
+                    // if c is a JavaConstant, it's an oop, otherwise it's a metaspace constant
+                    assert !(c instanceof JavaConstant) || ((JavaConstant) c).getJavaKind() == JavaKind.Object;
+                    getLIRGen().append(new AMD64BinaryConsumer.MemoryVMConstOp(AMD64MIOp.MOV, address, (VMConstant) c, state));
+                    return;
+                }
+            }
+        } else {
+            JavaConstant jc = (JavaConstant) c;
+            assert jc.getJavaKind().isPrimitive();
+
+            AMD64MIOp op = AMD64MIOp.MOV;
+            OperandSize size;
+            long imm;
+
+            switch (kind) {
+                case BYTE:
+                    op = AMD64MIOp.MOVB;
+                    size = BYTE;
+                    imm = jc.asInt();
+                    break;
+                case WORD:
+                    size = WORD;
+                    imm = jc.asInt();
+                    break;
+                case DWORD:
+                    size = DWORD;
+                    imm = jc.asInt();
+                    break;
+                case QWORD:
+                    size = QWORD;
+                    imm = jc.asLong();
+                    break;
+                case SINGLE:
+                    size = DWORD;
+                    imm = Float.floatToRawIntBits(jc.asFloat());
+                    break;
+                case DOUBLE:
+                    size = QWORD;
+                    imm = Double.doubleToRawLongBits(jc.asDouble());
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("unexpected kind " + kind);
+            }
+
+            if (NumUtil.isInt(imm)) {
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
+                return;
+            }
+        }
+
+        // fallback: load, then store
+        emitStore(kind, address, getLIRGen().asAllocatable(value), state);
+    }
+
+    protected void emitStore(AMD64Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
+        switch (kind) {
+            case BYTE:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
+                break;
+            case WORD:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
+                break;
+            case DWORD:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
+                break;
+            case QWORD:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
+                break;
+            case SINGLE:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
+                break;
+            case DOUBLE:
+                getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void emitStore(ValueKind<?> lirKind, Value address, Value input, LIRFrameState state) {
+        AMD64AddressValue storeAddress = getAMD64LIRGen().asAddressValue(address);
+        AMD64Kind kind = (AMD64Kind) lirKind.getPlatformKind();
+        if (isConstantValue(input)) {
+            emitStoreConst(kind, storeAddress, asConstantValue(input), state);
+        } else {
+            emitStore(kind, storeAddress, getLIRGen().asAllocatable(input), state);
+        }
+    }
+
+    @Override
+    public void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right) {
+        OperandSize size;
+        switch (cmpKind) {
+            case BYTE:
+                size = BYTE;
+                break;
+            case WORD:
+                size = WORD;
+                break;
+            case DWORD:
+                size = DWORD;
+                break;
+            case QWORD:
+                size = QWORD;
+                break;
+            case SINGLE:
+                getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, getLIRGen().asAllocatable(right)));
+                return;
+            case DOUBLE:
+                getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, getLIRGen().asAllocatable(right)));
+                return;
+            default:
+                throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
+        }
+
+        if (isConstantValue(right)) {
+            Constant c = LIRValueUtil.asConstant(right);
+            if (JavaConstant.isNull(c)) {
+                getLIRGen().append(new AMD64BinaryConsumer.Op(TEST, size, left, left));
+                return;
+            } else if (c instanceof VMConstant) {
+                VMConstant vc = (VMConstant) c;
+                if (size == DWORD && !GeneratePIC.getValue()) {
+                    getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc));
+                } else {
+                    getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc));
+                }
+                return;
+            } else if (c instanceof JavaConstant) {
+                JavaConstant jc = (JavaConstant) c;
+                if (jc.isDefaultForKind()) {
+                    AMD64RMOp op = size == BYTE ? TESTB : TEST;
+                    getLIRGen().append(new AMD64BinaryConsumer.Op(op, size, left, left));
+                    return;
+                } else if (NumUtil.is32bit(jc.asLong())) {
+                    getLIRGen().append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) jc.asLong()));
+                    return;
+                }
+            }
+        }
+
+        // fallback: load, then compare
+        getLIRGen().append(new AMD64BinaryConsumer.Op(CMP.getRMOpcode(size), size, left, getLIRGen().asAllocatable(right)));
+    }
+
+    @Override
+    public Value emitRound(Value value, RoundingMode mode) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(value));
+        assert ((AMD64Kind) value.getPlatformKind()).isXMM();
+        if (value.getPlatformKind() == AMD64Kind.SINGLE) {
+            getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSS, OperandSize.PD, result, getLIRGen().asAllocatable(value), mode.encoding));
+        } else {
+            getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSD, OperandSize.PD, result, getLIRGen().asAllocatable(value), mode.encoding));
+        }
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
new file mode 100644
index 0000000..f9d2f5c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
+import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
+import org.graalvm.compiler.lir.amd64.AMD64ByteSwapOp;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondMoveOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatBranchOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondMoveOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move;
+import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp;
+import org.graalvm.compiler.lir.amd64.AMD64PauseOp;
+import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp;
+import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.VMConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * This class implements the AMD64 specific portion of the LIR generator.
+ */
+public abstract class AMD64LIRGenerator extends LIRGenerator {
+
+    public AMD64LIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
+    }
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected static final boolean canStoreConstant(JavaConstant c) {
+        // there is no immediate move of 64-bit constants on Intel
+        switch (c.getJavaKind()) {
+            case Long: {
+                long l = c.asLong();
+                return (int) l == l;
+            }
+            case Double:
+                return false;
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    protected JavaConstant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((AMD64Kind) kind) {
+            case BYTE:
+                return JavaConstant.forByte((byte) dead);
+            case WORD:
+                return JavaConstant.forShort((short) dead);
+            case DWORD:
+                return JavaConstant.forInt((int) dead);
+            case QWORD:
+                return JavaConstant.forLong(dead);
+            case SINGLE:
+                return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
+            default:
+                // we don't support vector types, so just zap with double for all of them
+                return JavaConstant.forDouble(Double.longBitsToDouble(dead));
+        }
+    }
+
+    public AMD64AddressValue asAddressValue(Value address) {
+        if (address instanceof AMD64AddressValue) {
+            return (AMD64AddressValue) address;
+        } else {
+            if (address instanceof JavaConstant) {
+                long displacement = ((JavaConstant) address).asLong();
+                if (NumUtil.isInt(displacement)) {
+                    return new AMD64AddressValue(address.getValueKind(), Value.ILLEGAL, (int) displacement);
+                }
+            }
+            return new AMD64AddressValue(address.getValueKind(), asAllocatable(address), 0);
+        }
+    }
+
+    @Override
+    public Variable emitAddress(AllocatableValue stackslot) {
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new StackLeaOp(result, stackslot));
+        return result;
+    }
+
+    /**
+     * The AMD64 backend only uses DWORD and QWORD values in registers because of a performance
+     * penalty when accessing WORD or BYTE registers. This function converts small integer kinds to
+     * DWORD.
+     */
+    @Override
+    public <K extends ValueKind<K>> K toRegisterKind(K kind) {
+        switch ((AMD64Kind) kind.getPlatformKind()) {
+            case BYTE:
+            case WORD:
+                return kind.changeType(AMD64Kind.DWORD);
+            default:
+                return kind;
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        ValueKind<?> kind = newValue.getValueKind();
+        assert kind.equals(expectedValue.getValueKind());
+        AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
+
+        AMD64AddressValue addressValue = asAddressValue(address);
+        RegisterValue raxRes = AMD64.rax.asValue(kind);
+        emitMove(raxRes, expectedValue);
+        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
+
+        assert trueValue.getValueKind().equals(falseValue.getValueKind());
+        Variable result = newVariable(trueValue.getValueKind());
+        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndAdd(Value address, Value delta) {
+        ValueKind<?> kind = delta.getValueKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndAddOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(delta)));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        ValueKind<?> kind = newValue.getValueKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndWriteOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
+    @Override
+    public void emitJump(LabelRef label) {
+        assert label != null;
+        append(new JumpOp(label));
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
+        boolean mirrored = emitCompare(cmpKind, left, right);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+        }
+    }
+
+    public void emitCompareBranchMemory(AMD64Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        boolean mirrored = emitCompareMemory(cmpKind, left, right, state);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        if (cmpKind.isXMM()) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+        }
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
+        append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability));
+    }
+
+    @Override
+    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+        emitIntegerTest(left, right);
+        append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability));
+    }
+
+    @Override
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        boolean mirrored = emitCompare(cmpKind, left, right);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+
+        Variable result = newVariable(trueValue.getValueKind());
+        if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
+            append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+        } else {
+            append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
+        }
+        return result;
+    }
+
+    @Override
+    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
+        emitIntegerTest(left, right);
+        Variable result = newVariable(trueValue.getValueKind());
+        append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
+        return result;
+    }
+
+    private void emitIntegerTest(Value a, Value b) {
+        assert ((AMD64Kind) a.getPlatformKind()).isInteger();
+        OperandSize size = a.getPlatformKind() == AMD64Kind.QWORD ? QWORD : DWORD;
+        if (isJavaConstant(b) && NumUtil.is32bit(asJavaConstant(b).asLong())) {
+            append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asJavaConstant(b).asLong()));
+        } else if (isJavaConstant(a) && NumUtil.is32bit(asJavaConstant(a).asLong())) {
+            append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asJavaConstant(a).asLong()));
+        } else if (isAllocatableValue(b)) {
+            append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a)));
+        } else {
+            append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b)));
+        }
+    }
+
+    /**
+     * This method emits the compare against memory instruction, and may reorder the operands. It
+     * returns true if it did so.
+     *
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    private boolean emitCompareMemory(AMD64Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
+        OperandSize size;
+        switch (cmpKind) {
+            case BYTE:
+                size = OperandSize.BYTE;
+                break;
+            case WORD:
+                size = OperandSize.WORD;
+                break;
+            case DWORD:
+                size = OperandSize.DWORD;
+                break;
+            case QWORD:
+                size = OperandSize.QWORD;
+                break;
+            case SINGLE:
+                append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state));
+                return false;
+            case DOUBLE:
+                append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state));
+                return false;
+            default:
+                throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
+        }
+
+        if (isJavaConstant(a)) {
+            return emitCompareMemoryConOp(size, asConstantValue(a), b, state);
+        } else {
+            return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
+        }
+    }
+
+    protected boolean emitCompareMemoryConOp(OperandSize size, ConstantValue a, AMD64AddressValue b, LIRFrameState state) {
+        if (JavaConstant.isNull(a.getConstant())) {
+            append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state));
+            return true;
+        } else if (a.getConstant() instanceof VMConstant && size == DWORD) {
+            VMConstant vc = (VMConstant) a.getConstant();
+            append(new AMD64BinaryConsumer.MemoryVMConstOp(CMP.getMIOpcode(size, false), b, vc, state));
+            return true;
+        } else {
+            long value = a.getJavaConstant().asLong();
+            if (NumUtil.is32bit(value)) {
+                append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) value, state));
+                return true;
+            } else {
+                return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
+            }
+        }
+    }
+
+    private boolean emitCompareRegMemoryOp(OperandSize size, AllocatableValue a, AMD64AddressValue b, LIRFrameState state) {
+        AMD64RMOp op = CMP.getRMOpcode(size);
+        append(new AMD64BinaryConsumer.MemoryRMOp(op, size, a, b, state));
+        return false;
+    }
+
+    /**
+     * This method emits the compare instruction, and may reorder the operands. It returns true if
+     * it did so.
+     *
+     * @param a the left operand of the comparison
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
+        Variable left;
+        Value right;
+        boolean mirrored;
+        if (LIRValueUtil.isVariable(b)) {
+            left = load(b);
+            right = loadNonConst(a);
+            mirrored = true;
+        } else {
+            left = load(a);
+            right = loadNonConst(b);
+            mirrored = false;
+        }
+        ((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, left, right);
+        return mirrored;
+    }
+
+    @Override
+    public void emitMembar(int barriers) {
+        int necessaryBarriers = target().arch.requiredBarriers(barriers);
+        if (target().isMP && necessaryBarriers != 0) {
+            append(new MembarOp(necessaryBarriers));
+        }
+    }
+
+    public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments);
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        long maxOffset = linkage.getMaxCallTargetOffset();
+        if (maxOffset != (int) maxOffset && !GeneratePIC.getValue()) {
+            append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
+        } else {
+            append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
+        }
+    }
+
+    @Override
+    public Variable emitByteSwap(Value input) {
+        Variable result = newVariable(LIRKind.combine(input));
+        append(new AMD64ByteSwapOp(result, input));
+        return result;
+    }
+
+    @Override
+    public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
+        Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
+        append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
+        return result;
+    }
+
+    @Override
+    public void emitReturn(JavaKind kind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(kind, input.getValueKind());
+            emitMove(operand, input);
+        }
+        append(new ReturnOp(operand));
+    }
+
+    protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
+        return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
+    }
+
+    @Override
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        // a temp is needed for loading object constants
+        boolean needsTemp = !LIRKind.isValue(key);
+        append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getValueKind()) : Value.ILLEGAL));
+    }
+
+    @Override
+    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
+        append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
+    }
+
+    @Override
+    public void emitPause() {
+        append(new AMD64PauseOp());
+    }
+
+    @Override
+    public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
+        return new AMD64ZapRegistersOp(zappedRegisters, zapValues);
+    }
+
+    @Override
+    public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
+        return new AMD64ZapStackOp(zappedStack, zapValues);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java
new file mode 100644
index 0000000..7a0ad5b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+
+public class AMD64LIRKindTool implements LIRKindTool {
+
+    @Override
+    public LIRKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return LIRKind.value(AMD64Kind.BYTE);
+        } else if (bits <= 16) {
+            return LIRKind.value(AMD64Kind.WORD);
+        } else if (bits <= 32) {
+            return LIRKind.value(AMD64Kind.DWORD);
+        } else {
+            assert bits <= 64;
+            return LIRKind.value(AMD64Kind.QWORD);
+        }
+    }
+
+    @Override
+    public LIRKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return LIRKind.value(AMD64Kind.SINGLE);
+            case 64:
+                return LIRKind.value(AMD64Kind.DOUBLE);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(AMD64Kind.QWORD);
+    }
+
+    @Override
+    public LIRKind getWordKind() {
+        return LIRKind.value(AMD64Kind.QWORD);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactory.java
new file mode 100644
index 0000000..fb767ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactory.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64StackMove;
+import org.graalvm.compiler.lir.amd64.AMD64Move.LeaDataOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.LeaOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromConstOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.MoveToRegOp;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
+
+    public AMD64MoveFactory(BackupSlotProvider backupSlotProvider) {
+        super(backupSlotProvider);
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        switch (c.getJavaKind()) {
+            case Long:
+                return NumUtil.isInt(c.asLong());
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    public AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
+        if (src instanceof AMD64AddressValue) {
+            return new LeaOp(dst, (AMD64AddressValue) src);
+        } else if (isConstantValue(src)) {
+            return createLoad(dst, asConstant(src));
+        } else if (isRegister(src) || isStackSlotValue(dst)) {
+            return new MoveFromRegOp((AMD64Kind) dst.getPlatformKind(), dst, (AllocatableValue) src);
+        } else {
+            return new MoveToRegOp((AMD64Kind) dst.getPlatformKind(), dst, (AllocatableValue) src);
+        }
+    }
+
+    @Override
+    public AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input, Register scratchRegister, AllocatableValue backupSlot) {
+        return new AMD64StackMove(result, input, scratchRegister, backupSlot);
+    }
+
+    @Override
+    public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (src instanceof JavaConstant) {
+            return new MoveFromConstOp(dst, (JavaConstant) src);
+        } else if (src instanceof DataPointerConstant) {
+            return new LeaDataOp(dst, (DataPointerConstant) src);
+        } else {
+            throw GraalError.shouldNotReachHere(String.format("unsupported constant: %s", src));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java
new file mode 100644
index 0000000..2ff7438
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+
+public abstract class AMD64MoveFactoryBase implements MoveFactory {
+
+    private final BackupSlotProvider backupSlotProvider;
+
+    private static class RegisterBackupPair {
+        public final Register register;
+        public final VirtualStackSlot backupSlot;
+
+        RegisterBackupPair(Register register, VirtualStackSlot backupSlot) {
+            this.register = register;
+            this.backupSlot = backupSlot;
+        }
+    }
+
+    public static final class BackupSlotProvider {
+
+        private final FrameMapBuilder frameMapBuilder;
+        private Map<PlatformKind.Key, RegisterBackupPair> categorized;
+
+        public BackupSlotProvider(FrameMapBuilder frameMapBuilder) {
+            this.frameMapBuilder = frameMapBuilder;
+        }
+
+        protected RegisterBackupPair getScratchRegister(PlatformKind kind) {
+            PlatformKind.Key key = kind.getKey();
+            if (categorized == null) {
+                categorized = new HashMap<>();
+            } else if (categorized.containsKey(key)) {
+                return categorized.get(key);
+            }
+
+            RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig();
+
+            RegisterArray availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters());
+            assert availableRegister != null && availableRegister.size() > 1;
+            Register scratchRegister = availableRegister.get(0);
+
+            Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch;
+            LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory()));
+            VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind);
+
+            RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot);
+            categorized.put(key, value);
+
+            return value;
+        }
+    }
+
+    public AMD64MoveFactoryBase(BackupSlotProvider backupSlotProvider) {
+        this.backupSlotProvider = backupSlotProvider;
+    }
+
+    @Override
+    public final AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        AMD64Kind kind = (AMD64Kind) result.getPlatformKind();
+        switch (kind.getSizeInBytes()) {
+            case 2:
+                return new AMD64PushPopStackMove(WORD, result, input);
+            case 8:
+                return new AMD64PushPopStackMove(QWORD, result, input);
+            default:
+                RegisterBackupPair backup = backupSlotProvider.getScratchRegister(input.getPlatformKind());
+                Register scratchRegister = backup.register;
+                VirtualStackSlot backupSlot = backup.backupSlot;
+                return createStackMove(result, input, scratchRegister, backupSlot);
+        }
+    }
+
+    public abstract AMD64LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input, Register scratchRegister, AllocatableValue backupSlot);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java
new file mode 100644
index 0000000..ea5494a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
+
+    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        Value targetAddressSrc = operand(callTarget.computedAddress());
+        AllocatableValue targetAddress = AMD64.rax.asValue(targetAddressSrc.getValueKind());
+        gen.emitMove(targetAddress, targetAddressSrc);
+        append(new AMD64Call.IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, targetAddress, callState));
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        if (valueNode instanceof IntegerDivRemNode) {
+            AMD64ArithmeticLIRGenerator arithmeticGen = (AMD64ArithmeticLIRGenerator) gen.getArithmetic();
+            IntegerDivRemNode divRem = (IntegerDivRemNode) valueNode;
+            FixedNode node = divRem.next();
+            while (true) {
+                if (node instanceof IfNode) {
+                    IfNode ifNode = (IfNode) node;
+                    double probability = ifNode.getTrueSuccessorProbability();
+                    if (probability == 1.0) {
+                        node = ifNode.trueSuccessor();
+                    } else if (probability == 0.0) {
+                        node = ifNode.falseSuccessor();
+                    } else {
+                        break;
+                    }
+                } else if (!(node instanceof FixedWithNextNode)) {
+                    break;
+                }
+
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                if (fixedWithNextNode instanceof IntegerDivRemNode) {
+                    IntegerDivRemNode otherDivRem = (IntegerDivRemNode) fixedWithNextNode;
+                    if (divRem.getOp() != otherDivRem.getOp() && divRem.getType() == otherDivRem.getType()) {
+                        if (otherDivRem.getX() == divRem.getX() && otherDivRem.getY() == divRem.getY() && !hasOperand(otherDivRem)) {
+                            Value[] results;
+                            switch (divRem.getType()) {
+                                case SIGNED:
+                                    results = arithmeticGen.emitSignedDivRem(operand(divRem.getX()), operand(divRem.getY()), state((DeoptimizingNode) valueNode));
+                                    break;
+                                case UNSIGNED:
+                                    results = arithmeticGen.emitUnsignedDivRem(operand(divRem.getX()), operand(divRem.getY()), state((DeoptimizingNode) valueNode));
+                                    break;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                            switch (divRem.getOp()) {
+                                case DIV:
+                                    assert otherDivRem.getOp() == Op.REM;
+                                    setResult(divRem, results[0]);
+                                    setResult(otherDivRem, results[1]);
+                                    break;
+                                case REM:
+                                    assert otherDivRem.getOp() == Op.DIV;
+                                    setResult(divRem, results[1]);
+                                    setResult(otherDivRem, results[0]);
+                                    break;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                            return true;
+                        }
+                    }
+                }
+                node = fixedWithNextNode.next();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public AMD64LIRGenerator getLIRGeneratorTool() {
+        return (AMD64LIRGenerator) gen;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java
new file mode 100644
index 0000000..7787dd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+import org.graalvm.compiler.core.match.ComplexMatchResult;
+import org.graalvm.compiler.core.match.MatchRule;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.memory.Access;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64NodeMatchRules extends NodeMatchRules {
+
+    public AMD64NodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AMD64Kind getMemoryKind(Access access) {
+        return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
+    }
+
+    protected OperandSize getMemorySize(Access access) {
+        switch (getMemoryKind(access)) {
+            case BYTE:
+                return OperandSize.BYTE;
+            case WORD:
+                return OperandSize.WORD;
+            case DWORD:
+                return OperandSize.DWORD;
+            case QWORD:
+                return OperandSize.QWORD;
+            case SINGLE:
+                return OperandSize.SS;
+            case DOUBLE:
+                return OperandSize.SD;
+            default:
+                throw GraalError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access));
+        }
+    }
+
+    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
+        Condition cond = compare.condition();
+        AMD64Kind kind = getMemoryKind(access);
+
+        if (value.isConstant()) {
+            JavaConstant constant = value.asJavaConstant();
+            if (constant != null && kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            if (kind.isXMM()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return null;
+            }
+        }
+
+        // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+        // that's not true. It might be mirrored again the actual compare is emitted but that's
+        // ok.
+        Condition finalCondition = GraphUtil.unproxify(compare.getX()) == access ? cond.mirror() : cond;
+        return new ComplexMatchResult() {
+            @Override
+            public Value evaluate(NodeLIRBuilder builder) {
+                LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                boolean unorderedIsTrue = compare.unorderedIsTrue();
+                double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                Value other = operand(value);
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
+                return null;
+            }
+        };
+    }
+
+    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
+        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
+        double trueLabelProbability = x.probability(x.trueSuccessor());
+        AMD64Kind kind = getMemoryKind(access);
+        OperandSize size = kind == AMD64Kind.QWORD ? QWORD : DWORD;
+        if (value.isConstant()) {
+            JavaConstant constant = value.asJavaConstant();
+            if (constant != null && kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            return builder -> {
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, address, (int) constant.asLong(), getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        } else {
+            return builder -> {
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), address, getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        }
+    }
+
+    protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
+        return builder -> {
+            AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+            LIRFrameState state = getState(access);
+            return getArithmeticLIRGenerator().emitConvertMemoryOp(kind, op, size, address, state);
+        };
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        AMD64Kind kind = null;
+        AMD64RMOp op;
+        OperandSize size;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            kind = AMD64Kind.QWORD;
+            size = OperandSize.QWORD;
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    op = MOVSXB;
+                    break;
+                case 16:
+                    op = MOVSX;
+                    break;
+                case 32:
+                    op = MOVSXD;
+                    break;
+                default:
+                    throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            kind = AMD64Kind.DWORD;
+            size = OperandSize.DWORD;
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    op = MOVSXB;
+                    break;
+                case 16:
+                    op = MOVSX;
+                    break;
+                case 32:
+                    return null;
+                default:
+                    throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+        if (kind != null && op != null) {
+            return emitConvertMemoryOp(kind, op, size, access);
+        }
+        return null;
+    }
+
+    private Value emitReinterpretMemory(LIRKind to, Access access) {
+        AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+        LIRFrameState state = getState(access);
+        return getArithmeticLIRGenerator().emitLoad(to, address, state);
+    }
+
+    @MatchRule("(If (IntegerTest Read=access value))")
+    @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
+        return emitIntegerTestBranchMemory(root, value, access);
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value Read=access))")
+    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelow=compare value Read=access))")
+    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value Read=access))")
+    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value Read=access))")
+    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (PointerEquals=compare value Read=access))")
+    @MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (ObjectEquals=compare value Read=access))")
+    @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
+    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        return emitCompareBranchMemory(root, compare, value, access);
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
+    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
+        if ((lshift.getShiftAmountMask() & (lshift.getY().asJavaConstant().asInt() + rshift.getY().asJavaConstant().asInt())) == 0) {
+            return builder -> getArithmeticLIRGenerator().emitRol(operand(lshift.getX()), operand(lshift.getY()));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
+        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
+            return builder -> getArithmeticLIRGenerator().emitRor(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))")
+    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
+        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
+            return builder -> getArithmeticLIRGenerator().emitRol(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
+        return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
+                        getState(access));
+    }
+
+    private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, Access access) {
+        return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
+                        getState(access));
+    }
+
+    @MatchRule("(Add value Read=access)")
+    @MatchRule("(Add value FloatingRead=access)")
+    public ComplexMatchResult addMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            TargetDescription target = getLIRGeneratorTool().target();
+            boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+            if (isAvx) {
+                return binaryRead(AVXOp.ADD, size, value, access);
+            } else {
+                return binaryRead(SSEOp.ADD, size, value, access);
+            }
+        } else {
+            return binaryRead(ADD.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Sub value Read=access)")
+    @MatchRule("(Sub value FloatingRead=access)")
+    public ComplexMatchResult subMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            TargetDescription target = getLIRGeneratorTool().target();
+            boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+            if (isAvx) {
+                return binaryRead(AVXOp.SUB, size, value, access);
+            } else {
+                return binaryRead(SSEOp.SUB, size, value, access);
+            }
+        } else {
+            return binaryRead(SUB.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Mul value Read=access)")
+    @MatchRule("(Mul value FloatingRead=access)")
+    public ComplexMatchResult mulMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            TargetDescription target = getLIRGeneratorTool().target();
+            boolean isAvx = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
+            if (isAvx) {
+                return binaryRead(AVXOp.MUL, size, value, access);
+            } else {
+                return binaryRead(SSEOp.MUL, size, value, access);
+            }
+        } else {
+            return binaryRead(AMD64RMOp.IMUL, size, value, access);
+        }
+    }
+
+    @MatchRule("(And value Read=access)")
+    @MatchRule("(And value FloatingRead=access)")
+    public ComplexMatchResult andMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(AND.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    public ComplexMatchResult orMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(OR.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    public ComplexMatchResult xorMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(XOR.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Write object Narrow=narrow)")
+    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
+        return builder -> {
+            LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp());
+            getArithmeticLIRGenerator().emitStore(writeKind, operand(root.getAddress()), operand(narrow.getValue()), state(root));
+            return null;
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        AMD64Kind memoryKind = getMemoryKind(access);
+        return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
+    }
+
+    @MatchRule("(FloatConvert Read=access)")
+    @MatchRule("(FloatConvert FloatingRead=access)")
+    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
+        switch (root.getFloatConvert()) {
+            case D2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
+            case D2I:
+                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSD2SI, DWORD, access);
+            case D2L:
+                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSD2SI, QWORD, access);
+            case F2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSS2SD, SS, access);
+            case F2I:
+                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSS2SI, DWORD, access);
+            case F2L:
+                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSS2SI, QWORD, access);
+            case I2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, DWORD, access);
+            case I2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, DWORD, access);
+            case L2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, QWORD, access);
+            case L2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, QWORD, access);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @MatchRule("(Reinterpret Read=access)")
+    @MatchRule("(Reinterpret FloatingRead=access)")
+    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
+        return builder -> {
+            LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
+            return emitReinterpretMemory(kind, access);
+        };
+
+    }
+
+    @MatchRule("(Write object Reinterpret=reinterpret)")
+    public ComplexMatchResult writeReinterpret(WriteNode root, ReinterpretNode reinterpret) {
+        return builder -> {
+            LIRKind kind = getLIRGeneratorTool().getLIRKind(reinterpret.getValue().stamp());
+            AllocatableValue value = getLIRGeneratorTool().asAllocatable(operand(reinterpret.getValue()));
+
+            AMD64AddressValue address = (AMD64AddressValue) operand(root.getAddress());
+            getArithmeticLIRGenerator().emitStore((AMD64Kind) kind.getPlatformKind(), address, value, getState(root));
+            return null;
+        };
+    }
+
+    @Override
+    public AMD64LIRGenerator getLIRGeneratorTool() {
+        return (AMD64LIRGenerator) gen;
+    }
+
+    protected AMD64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
+        return (AMD64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64SuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64SuitesProvider.java
new file mode 100644
index 0000000..99ecbb7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64SuitesProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.amd64;
+
+import org.graalvm.compiler.java.DefaultSuitesProvider;
+import org.graalvm.compiler.lir.amd64.phases.StackMoveOptimizationPhase;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+
+public class AMD64SuitesProvider extends DefaultSuitesProvider {
+
+    public AMD64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+    @Override
+    public LIRSuites createLIRSuites() {
+        LIRSuites lirSuites = super.createLIRSuites();
+        if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue()) {
+            /* Note: this phase must be inserted <b>after</b> RedundantMoveElimination */
+            lirSuites.getPostAllocationOptimizationStage().appendPhase(new StackMoveOptimizationPhase());
+        }
+        return lirSuites;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CollectionsFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CollectionsFactory.java
new file mode 100644
index 0000000..072372e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CollectionsFactory.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import static org.graalvm.compiler.core.common.CollectionsFactory.Mode.STANDARD;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Factory for creating collection objects used during compilation.
+ */
+public class CollectionsFactory {
+
+    private static final ThreadLocal<Mode> tl = new ThreadLocal<>();
+
+    public static class ModeScope implements AutoCloseable {
+        private final Mode previousMode;
+
+        public ModeScope(Mode previousMode) {
+            this.previousMode = previousMode;
+        }
+
+        @Override
+        public void close() {
+            tl.set(previousMode);
+        }
+    }
+
+    /**
+     * Constants denoting what type of collections are {@link CollectionsFactory#getMode()
+     * currently} returned by the factory.
+     */
+    public enum Mode {
+        /**
+         * Denotes standard collections such as {@link HashSet} and {@link HashMap}.
+         */
+        STANDARD,
+
+        /**
+         * Denotes collections that have a deterministic iteration order over their keys/entries.
+         */
+        DETERMINISTIC_ITERATION_ORDER;
+    }
+
+    /**
+     * Gets the current mode determining the type of collection objects created by this factory.
+     */
+    public static Mode getMode() {
+        Mode mode = tl.get();
+        return mode == null ? Mode.STANDARD : mode;
+    }
+
+    /**
+     * Updates the mode for the current thread.
+     *
+     * @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of
+     *         the current thread to the state before calling this method
+     */
+    public static ModeScope changeMode(Mode mode) {
+        Mode previousMode = tl.get();
+        tl.set(mode);
+        return new ModeScope(previousMode);
+    }
+
+    public static <K, V> HashMap<K, V> newMap() {
+        return getMode() == STANDARD ? new HashMap<>() : new LinkedHashMap<>();
+    }
+
+    public static <K, V> HashMap<K, V> newMap(Map<K, V> m) {
+        return getMode() == STANDARD ? new HashMap<>(m) : new LinkedHashMap<>(m);
+    }
+
+    public static <K, V> HashMap<K, V> newMap(int initialCapacity) {
+        return getMode() == STANDARD ? new HashMap<>(initialCapacity) : new LinkedHashMap<>(initialCapacity);
+    }
+
+    public static <K, V> Map<K, V> newIdentityMap() {
+        return getMode() == STANDARD ? new IdentityHashMap<>() : new LinkedIdentityHashMap<>();
+    }
+
+    public static <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
+        return getMode() == STANDARD ? new IdentityHashMap<>(expectedMaxSize) : new LinkedIdentityHashMap<>();
+    }
+
+    public static <K, V> Map<K, V> newIdentityMap(Map<K, V> m) {
+        return getMode() == STANDARD ? new IdentityHashMap<>(m) : new LinkedIdentityHashMap<>(m);
+    }
+
+    /**
+     * Creates a set. If the current thread is {@linkplain CollectionsFactory#getMode() using}
+     * {@link Mode#DETERMINISTIC_ITERATION_ORDER} collections, the returned set will have an
+     * iteration order determined by the order in which elements are inserted in the set.
+     */
+    public static <E> Set<E> newSet() {
+        return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>() : new LinkedHashSet<>();
+    }
+
+    /**
+     * @see #newSet()
+     */
+    public static <E> Set<E> newSet(Collection<? extends E> c) {
+        return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>(c) : new LinkedHashSet<>(c);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationIdentifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationIdentifier.java
new file mode 100644
index 0000000..4780ab7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationIdentifier.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import jdk.vm.ci.code.CompilationRequest;
+
+/**
+ * A unique identifier for a compilation. Compiled code can be mapped to a single compilation id.
+ * The reverse is not true since the compiler might bailout in which case no code is installed.
+ */
+public interface CompilationIdentifier {
+
+    enum Verbosity {
+        /**
+         * Only the unique identifier of the compilation.
+         */
+        ID,
+        /**
+         * Only the name of the compilation unit.
+         */
+        NAME,
+        /**
+         * {@link #ID} + a readable description.
+         */
+        DETAILED
+    }
+
+    CompilationRequestIdentifier INVALID_COMPILATION_ID = new CompilationRequestIdentifier() {
+
+        @Override
+        public String toString() {
+            return toString(Verbosity.DETAILED);
+        }
+
+        @Override
+        public String toString(Verbosity verbosity) {
+            return "InvalidCompilationID";
+        }
+
+        @Override
+        public CompilationRequest getRequest() {
+            return null;
+        }
+
+    };
+
+    /**
+     * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#DETAILED}.
+     */
+    @Override
+    String toString();
+
+    /**
+     * Creates a String representation for this compilation identifier with a given
+     * {@link Verbosity}.
+     */
+    String toString(Verbosity verbosity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationRequestIdentifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationRequestIdentifier.java
new file mode 100644
index 0000000..a1a8b4a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompilationRequestIdentifier.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import jdk.vm.ci.code.CompilationRequest;
+
+/**
+ * A {@link CompilationIdentifier} based on a {@link CompilationRequest}.
+ */
+public interface CompilationRequestIdentifier extends CompilationIdentifier {
+
+    CompilationRequest getRequest();
+
+    /**
+     * Returns the {@link CompilationRequestIdentifier#getRequest() request} from a
+     * {@link CompilationRequestIdentifier}. Returns {@code null} if the
+     * {@link CompilationIdentifier identifier} does not have one.
+     */
+    static CompilationRequest asCompilationRequest(CompilationIdentifier compilationId) {
+        if (compilationId instanceof CompilationRequestIdentifier) {
+            return ((CompilationRequestIdentifier) compilationId).getRequest();
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldIntrospection.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldIntrospection.java
new file mode 100644
index 0000000..aab62cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldIntrospection.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+public abstract class FieldIntrospection<T> {
+
+    private final Class<T> clazz;
+
+    /**
+     * The set of fields in {@link #clazz} that do long belong to a more specific category.
+     */
+    protected Fields data;
+
+    public FieldIntrospection(Class<T> clazz) {
+        this.clazz = clazz;
+    }
+
+    public Class<T> getClazz() {
+        return clazz;
+    }
+
+    /**
+     * Gets the fields in {@link #getClazz()} that do long belong to specific category.
+     */
+    public Fields getData() {
+        return data;
+    }
+
+    public abstract Fields[] getAllFields();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java
new file mode 100644
index 0000000..78840e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.graalvm.compiler.debug.GraalError;
+
+import sun.misc.Unsafe;
+
+/**
+ * Describes fields in a class, primarily for access via {@link Unsafe}.
+ */
+public class Fields {
+
+    /**
+     * Offsets used with {@link Unsafe} to access the fields.
+     */
+    protected final long[] offsets;
+
+    /**
+     * The names of the fields.
+     */
+    private final String[] names;
+
+    /**
+     * The types of the fields.
+     */
+    private final Class<?>[] types;
+
+    private final Class<?>[] declaringClasses;
+
+    public static Fields forClass(Class<?> clazz, Class<?> endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) {
+        FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset);
+        scanner.scan(clazz, endClazz, includeTransient);
+        return new Fields(scanner.data);
+    }
+
+    public Fields(ArrayList<? extends FieldsScanner.FieldInfo> fields) {
+        Collections.sort(fields);
+        this.offsets = new long[fields.size()];
+        this.names = new String[offsets.length];
+        this.types = new Class<?>[offsets.length];
+        this.declaringClasses = new Class<?>[offsets.length];
+        int index = 0;
+        for (FieldsScanner.FieldInfo f : fields) {
+            offsets[index] = f.offset;
+            names[index] = f.name;
+            types[index] = f.type;
+            declaringClasses[index] = f.declaringClass;
+            index++;
+        }
+    }
+
+    /**
+     * Gets the number of fields represented by this object.
+     */
+    public int getCount() {
+        return offsets.length;
+    }
+
+    public static void translateInto(Fields fields, ArrayList<FieldsScanner.FieldInfo> infos) {
+        for (int index = 0; index < fields.getCount(); index++) {
+            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index]));
+        }
+    }
+
+    /**
+     * Function enabling an object field value to be replaced with another value when being copied
+     * within {@link Fields#copy(Object, Object, ObjectTransformer)}.
+     */
+    @FunctionalInterface
+    public interface ObjectTransformer {
+        Object apply(int index, Object from);
+    }
+
+    /**
+     * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
+     *
+     * @param from the object from which the fields should be copied
+     * @param to the object to which the fields should be copied
+     */
+    public void copy(Object from, Object to) {
+        copy(from, to, null);
+    }
+
+    /**
+     * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
+     *
+     * @param from the object from which the fields should be copied
+     * @param to the object to which the fields should be copied
+     * @param trans function to applied to object field values as they are copied. If {@code null},
+     *            the value is copied unchanged.
+     */
+    public void copy(Object from, Object to, ObjectTransformer trans) {
+        assert from.getClass() == to.getClass();
+        for (int index = 0; index < offsets.length; index++) {
+            long offset = offsets[index];
+            Class<?> type = types[index];
+            if (type.isPrimitive()) {
+                if (type == Integer.TYPE) {
+                    UNSAFE.putInt(to, offset, UNSAFE.getInt(from, offset));
+                } else if (type == Long.TYPE) {
+                    UNSAFE.putLong(to, offset, UNSAFE.getLong(from, offset));
+                } else if (type == Boolean.TYPE) {
+                    UNSAFE.putBoolean(to, offset, UNSAFE.getBoolean(from, offset));
+                } else if (type == Float.TYPE) {
+                    UNSAFE.putFloat(to, offset, UNSAFE.getFloat(from, offset));
+                } else if (type == Double.TYPE) {
+                    UNSAFE.putDouble(to, offset, UNSAFE.getDouble(from, offset));
+                } else if (type == Short.TYPE) {
+                    UNSAFE.putShort(to, offset, UNSAFE.getShort(from, offset));
+                } else if (type == Character.TYPE) {
+                    UNSAFE.putChar(to, offset, UNSAFE.getChar(from, offset));
+                } else if (type == Byte.TYPE) {
+                    UNSAFE.putByte(to, offset, UNSAFE.getByte(from, offset));
+                } else {
+                    assert false : "unhandled property type: " + type;
+                }
+            } else {
+                Object obj = UNSAFE.getObject(from, offset);
+                UNSAFE.putObject(to, offset, trans == null ? obj : trans.apply(index, obj));
+            }
+        }
+    }
+
+    /**
+     * Gets the value of a field for a given object.
+     *
+     * @param object the object whose field is to be read
+     * @param index the index of the field (between 0 and {@link #getCount()})
+     * @return the value of the specified field which will be boxed if the field type is primitive
+     */
+    public Object get(Object object, int index) {
+        long offset = offsets[index];
+        Class<?> type = types[index];
+        Object value = null;
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                value = UNSAFE.getInt(object, offset);
+            } else if (type == Long.TYPE) {
+                value = UNSAFE.getLong(object, offset);
+            } else if (type == Boolean.TYPE) {
+                value = UNSAFE.getBoolean(object, offset);
+            } else if (type == Float.TYPE) {
+                value = UNSAFE.getFloat(object, offset);
+            } else if (type == Double.TYPE) {
+                value = UNSAFE.getDouble(object, offset);
+            } else if (type == Short.TYPE) {
+                value = UNSAFE.getShort(object, offset);
+            } else if (type == Character.TYPE) {
+                value = UNSAFE.getChar(object, offset);
+            } else if (type == Byte.TYPE) {
+                value = UNSAFE.getByte(object, offset);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            value = UNSAFE.getObject(object, offset);
+        }
+        return value;
+    }
+
+    /**
+     * Gets the value of a field for a given object.
+     *
+     * @param object the object whose field is to be read
+     * @param index the index of the field (between 0 and {@link #getCount()})
+     * @return the value of the specified field which will be boxed if the field type is primitive
+     */
+    public long getRawPrimitive(Object object, int index) {
+        long offset = offsets[index];
+        Class<?> type = types[index];
+
+        if (type == Integer.TYPE) {
+            return UNSAFE.getInt(object, offset);
+        } else if (type == Long.TYPE) {
+            return UNSAFE.getLong(object, offset);
+        } else if (type == Boolean.TYPE) {
+            return UNSAFE.getBoolean(object, offset) ? 1 : 0;
+        } else if (type == Float.TYPE) {
+            return Float.floatToRawIntBits(UNSAFE.getFloat(object, offset));
+        } else if (type == Double.TYPE) {
+            return Double.doubleToRawLongBits(UNSAFE.getDouble(object, offset));
+        } else if (type == Short.TYPE) {
+            return UNSAFE.getShort(object, offset);
+        } else if (type == Character.TYPE) {
+            return UNSAFE.getChar(object, offset);
+        } else if (type == Byte.TYPE) {
+            return UNSAFE.getByte(object, offset);
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Determines if a field in the domain of this object is the same as the field denoted by the
+     * same index in another {@link Fields} object.
+     */
+    public boolean isSame(Fields other, int index) {
+        return other.offsets[index] == offsets[index];
+    }
+
+    public long[] getOffsets() {
+        return offsets;
+    }
+
+    /**
+     * Gets the name of a field.
+     *
+     * @param index index of a field
+     */
+    public String getName(int index) {
+        return names[index];
+    }
+
+    /**
+     * Gets the type of a field.
+     *
+     * @param index index of a field
+     */
+    public Class<?> getType(int index) {
+        return types[index];
+    }
+
+    public Class<?> getDeclaringClass(int index) {
+        return declaringClasses[index];
+    }
+
+    /**
+     * Checks that a given field is assignable from a given value.
+     *
+     * @param index the index of the field to check
+     * @param value a value that will be assigned to the field
+     */
+    private boolean checkAssignableFrom(Object object, int index, Object value) {
+        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("Field %s.%s of type %s is not assignable from %s", object.getClass().getSimpleName(),
+                        getName(index), getType(index).getSimpleName(), value.getClass().getSimpleName());
+        return true;
+    }
+
+    public void set(Object object, int index, Object value) {
+        long offset = offsets[index];
+        Class<?> type = types[index];
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                UNSAFE.putInt(object, offset, (Integer) value);
+            } else if (type == Long.TYPE) {
+                UNSAFE.putLong(object, offset, (Long) value);
+            } else if (type == Boolean.TYPE) {
+                UNSAFE.putBoolean(object, offset, (Boolean) value);
+            } else if (type == Float.TYPE) {
+                UNSAFE.putFloat(object, offset, (Float) value);
+            } else if (type == Double.TYPE) {
+                UNSAFE.putDouble(object, offset, (Double) value);
+            } else if (type == Short.TYPE) {
+                UNSAFE.putShort(object, offset, (Short) value);
+            } else if (type == Character.TYPE) {
+                UNSAFE.putChar(object, offset, (Character) value);
+            } else if (type == Byte.TYPE) {
+                UNSAFE.putByte(object, offset, (Byte) value);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            assert checkAssignableFrom(object, index, value);
+            UNSAFE.putObject(object, offset, value);
+        }
+    }
+
+    public void setRawPrimitive(Object object, int index, long value) {
+        long offset = offsets[index];
+        Class<?> type = types[index];
+        if (type == Integer.TYPE) {
+            UNSAFE.putInt(object, offset, (int) value);
+        } else if (type == Long.TYPE) {
+            UNSAFE.putLong(object, offset, value);
+        } else if (type == Boolean.TYPE) {
+            UNSAFE.putBoolean(object, offset, value != 0);
+        } else if (type == Float.TYPE) {
+            UNSAFE.putFloat(object, offset, Float.intBitsToFloat((int) value));
+        } else if (type == Double.TYPE) {
+            UNSAFE.putDouble(object, offset, Double.longBitsToDouble(value));
+        } else if (type == Short.TYPE) {
+            UNSAFE.putShort(object, offset, (short) value);
+        } else if (type == Character.TYPE) {
+            UNSAFE.putChar(object, offset, (char) value);
+        } else if (type == Byte.TYPE) {
+            UNSAFE.putByte(object, offset, (byte) value);
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
+        appendFields(sb);
+        return sb.append(']').toString();
+    }
+
+    public void appendFields(StringBuilder sb) {
+        for (int i = 0; i < offsets.length; i++) {
+            sb.append(i == 0 ? "" : ", ").append(getName(i)).append('@').append(offsets[i]);
+        }
+    }
+
+    public boolean getBoolean(Object n, int i) {
+        assert types[i] == boolean.class;
+        return UNSAFE.getBoolean(n, offsets[i]);
+    }
+
+    public byte getByte(Object n, int i) {
+        assert types[i] == byte.class;
+        return UNSAFE.getByte(n, offsets[i]);
+    }
+
+    public short getShort(Object n, int i) {
+        assert types[i] == short.class;
+        return UNSAFE.getShort(n, offsets[i]);
+    }
+
+    public char getChar(Object n, int i) {
+        assert types[i] == char.class;
+        return UNSAFE.getChar(n, offsets[i]);
+    }
+
+    public int getInt(Object n, int i) {
+        assert types[i] == int.class;
+        return UNSAFE.getInt(n, offsets[i]);
+    }
+
+    public long getLong(Object n, int i) {
+        assert types[i] == long.class;
+        return UNSAFE.getLong(n, offsets[i]);
+    }
+
+    public float getFloat(Object n, int i) {
+        assert types[i] == float.class;
+        return UNSAFE.getFloat(n, offsets[i]);
+    }
+
+    public double getDouble(Object n, int i) {
+        assert types[i] == double.class;
+        return UNSAFE.getDouble(n, offsets[i]);
+    }
+
+    public Object getObject(Object object, int i) {
+        assert !types[i].isPrimitive();
+        return UNSAFE.getObject(object, offsets[i]);
+    }
+
+    public void putObject(Object object, int i, Object value) {
+        assert checkAssignableFrom(object, i, value);
+        UNSAFE.putObject(object, offsets[i], value);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java
new file mode 100644
index 0000000..aa609cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+import sun.misc.Unsafe;
+
+/**
+ * Scans the fields in a class hierarchy.
+ */
+public class FieldsScanner {
+
+    /**
+     * Determines the offset (in bytes) of a field.
+     */
+    public interface CalcOffset {
+
+        long getOffset(Field field);
+    }
+
+    /**
+     * Determines the offset (in bytes) of a field using {@link Unsafe#objectFieldOffset(Field)}.
+     */
+    public static class DefaultCalcOffset implements CalcOffset {
+
+        @Override
+        public long getOffset(Field field) {
+            return UNSAFE.objectFieldOffset(field);
+        }
+    }
+
+    /**
+     * Describes a field in a class during {@linkplain FieldsScanner scanning}.
+     */
+    public static class FieldInfo implements Comparable<FieldInfo> {
+        public final long offset;
+        public final String name;
+        public final Class<?> type;
+        public final Class<?> declaringClass;
+
+        public FieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
+            this.offset = offset;
+            this.name = name;
+            this.type = type;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Sorts fields in ascending order by their {@link #offset}s.
+         */
+        @Override
+        public int compareTo(FieldInfo o) {
+            return offset < o.offset ? -1 : (offset > o.offset ? 1 : 0);
+        }
+
+        @Override
+        public String toString() {
+            return "[" + offset + "]" + name + ":" + type.getSimpleName();
+        }
+    }
+
+    private final FieldsScanner.CalcOffset calc;
+
+    /**
+     * Fields not belonging to a more specific category defined by scanner subclasses are added to
+     * this list.
+     */
+    public final ArrayList<FieldsScanner.FieldInfo> data = new ArrayList<>();
+
+    public FieldsScanner(FieldsScanner.CalcOffset calc) {
+        this.calc = calc;
+    }
+
+    /**
+     * Scans the fields in a class hierarchy.
+     *
+     * @param clazz the class at which to start scanning
+     * @param endClazz scanning stops when this class is encountered (i.e. {@code endClazz} is not
+     *            scanned)
+     */
+    public void scan(Class<?> clazz, Class<?> endClazz, boolean includeTransient) {
+        Class<?> currentClazz = clazz;
+        while (currentClazz != endClazz) {
+            for (Field field : currentClazz.getDeclaredFields()) {
+                if (Modifier.isStatic(field.getModifiers())) {
+                    continue;
+                }
+                if (!includeTransient && Modifier.isTransient(field.getModifiers())) {
+                    continue;
+                }
+                long offset = calc.getOffset(field);
+                scanField(field, offset);
+            }
+            currentClazz = currentClazz.getSuperclass();
+        }
+    }
+
+    protected void scanField(Field field, long offset) {
+        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java
new file mode 100644
index 0000000..68d158d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+
+/**
+ * This class encapsulates options that control the behavior of the Graal compiler.
+ */
+// @formatter:off
+public final class GraalOptions {
+
+    @Option(help = "Use compiler intrinsifications.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
+
+    @Option(help = "Inline calls with monomorphic type profile.", type = OptionType.Expert)
+    public static final OptionValue<Boolean> InlineMonomorphicCalls = new OptionValue<>(true);
+
+    @Option(help = "Inline calls with polymorphic type profile.", type = OptionType.Expert)
+    public static final OptionValue<Boolean> InlinePolymorphicCalls = new OptionValue<>(true);
+
+    @Option(help = "Inline calls with megamorphic type profile (i.e., not all types could be recorded).", type = OptionType.Expert)
+    public static final OptionValue<Boolean> InlineMegamorphicCalls = new OptionValue<>(true);
+
+    @Option(help = "Maximum desired size of the compiler graph in nodes.", type = OptionType.User)
+    public static final OptionValue<Integer> MaximumDesiredSize = new OptionValue<>(20000);
+
+    @Option(help = "Minimum probability for methods to be inlined for megamorphic type profiles.", type = OptionType.Expert)
+    public static final OptionValue<Double> MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D);
+
+    @Option(help = "Maximum level of recursive inlining.", type = OptionType.Expert)
+    public static final OptionValue<Integer> MaximumRecursiveInlining = new OptionValue<>(5);
+
+    @Option(help = "Graphs with less than this number of nodes are trivial and therefore always inlined.", type = OptionType.Expert)
+    public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
+
+    @Option(help = "Inlining is explored up to this number of nodes in the graph for each call site.", type = OptionType.Expert)
+    public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
+
+    @Option(help = "If the previous low-level graph size of the method exceeds the threshold, it is not inlined.", type = OptionType.Expert)
+    public static final OptionValue<Integer> SmallCompiledLowLevelGraphSize = new OptionValue<>(300);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Double> LimitInlinedInvokes = new OptionValue<>(5.0);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> InlineEverything = new OptionValue<>(false);
+
+    // escape analysis settings
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Integer> EscapeAnalysisLoopCutoff = new OptionValue<>(20);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Integer> MaximumEscapeAnalysisArrayLength = new OptionValue<>(32);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PEAInliningHints = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Double> TailDuplicationProbability = new OptionValue<>(0.5);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Integer> TailDuplicationTrivialSize = new OptionValue<>(1);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> LoopPeeling = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ReassociateInvariants = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> FullUnroll = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
+
+    // debugging settings
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ZapStackOnMethodEntry = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> DeoptALot = new OptionValue<>(false);
+
+    @Option(help = "Stress the code emitting explicit exception throwing code.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> StressExplicitExceptionCode = new OptionValue<>(false);
+
+    @Option(help = "Stress the code emitting invokes with explicit exception edges.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> StressInvokeWithExceptionNode = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> VerifyPhases = new OptionValue<>(false);
+
+    // Debug settings:
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
+
+    @Option(help = "Perform platform dependent validation of the Java heap at returns", type = OptionType.Debug)
+    public static final OptionValue<Boolean> VerifyHeapAtReturn = new OptionValue<>(false);
+
+    // Other printing settings
+    @Option(help = "Print profiling information when parsing a method's bytecode", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> TraceEscapeAnalysis = new StableOptionValue<>(false);
+
+    // HotSpot command line options
+    @Option(help = "Print inlining optimizations", type = OptionType.Debug)
+    public static final OptionValue<Boolean> HotSpotPrintInlining = new OptionValue<>(false);
+
+    // Register allocator debugging
+    @Option(help = "Comma separated list of registers that register allocation is limited to.", type = OptionType.Debug)
+    public static final OptionValue<String> RegisterPressure = new OptionValue<>(null);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> RemoveNeverExecutedCode = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseExceptionProbability = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseExceptionProbabilityForOperations = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OmitHotExceptionStacktrace = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> GenSafepoints = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> GenLoopSafepoints = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseTypeCheckHints = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> InlineVTableStubs = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> AlwaysInlineVTableStubs = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ResolveClassBeforeStaticInvoke = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> CanOmitFrame = new OptionValue<>(true);
+
+    // Ahead of time compilation
+    @Option(help = "Try to avoid emitting code where patching is required", type = OptionType.Expert)
+    public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
+
+    @Option(help = "Generate position independent code", type = OptionType.Expert)
+    public static final OptionValue<Boolean> GeneratePIC = new OptionValue<>(false);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
+
+    // Runtime settings
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Expert)
+    public static final OptionValue<Boolean> OptAssumptions = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptConvertDeoptsToGuards = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Integer> ReadEliminationMaxLoopVisits = new OptionValue<>(5);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptClearNonLiveLocals = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptFilterProfiledTypes = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptDevirtualizeInvokesOptimistically = new OptionValue<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
+
+    @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
+
+    @Option(help = "Enable counters for various paths in snippets.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> SnippetCounters = new OptionValue<>(false);
+
+    @Option(help = "Eagerly construct extra snippet info.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> EagerSnippets = new OptionValue<>(false);
+
+    @Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseSnippetGraphCache = new OptionValue<>(true);
+
+    @Option(help = "Enable expensive assertions", type = OptionType.Debug)
+    public static final OptionValue<Boolean> DetailedAsserts = new StableOptionValue<Boolean>() {
+        @Override
+        protected Boolean defaultValue() {
+            boolean enabled = false;
+            // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this)
+            assert (enabled = true) == true;
+            return enabled;
+        }
+    };
+
+    @Option(help = "Enable Graal instrumentation")
+    public static final OptionValue<Boolean> UseGraalInstrumentation = new OptionValue<>(false);
+
+    @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> TraceRA = new OptionValue<>(false);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
new file mode 100644
index 0000000..2b26f8f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import java.util.ArrayList;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the
+ * low level representation of the value, and a {@link #referenceMask} that describes the location
+ * of object references in the value, and optionally a {@link #derivedReferenceBase}.
+ *
+ * <h2>Constructing {@link LIRKind} instances</h2>
+ *
+ * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct
+ * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind
+ * LIRKinds} should be created as follows:
+ *
+ * <p>
+ * If the result value is created from one or more input values, the {@link LIRKind} should be
+ * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind}
+ * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used.
+ * <p>
+ * If the result is an exact copy of one of the inputs, {@link Value#getValueKind()} can be used.
+ * Note that this is only correct for move-like operations, like conditional move or
+ * compare-and-swap. For convert operations, {@link LIRKind#combine} should be used.
+ * <p>
+ * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result
+ * is a valid oop), {@link LIRKind#reference} should be used.
+ * <p>
+ * If it is known that the result will neither be a reference nor be derived from a reference,
+ * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very
+ * likely wrong, and {@link LIRKind#combine} should be used instead.
+ * <p>
+ * If it is known that the result is derived from a reference in a way that the garbage collector
+ * can not track, {@link LIRKind#unknownReference} can be used. In most cases,
+ * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically.
+ */
+public final class LIRKind extends ValueKind<LIRKind> {
+
+    private final int referenceMask;
+
+    private AllocatableValue derivedReferenceBase;
+
+    private static final int UNKNOWN_REFERENCE = -1;
+
+    public static final LIRKind Illegal = unknownReference(ValueKind.Illegal.getPlatformKind());
+
+    private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) {
+        super(platformKind);
+        this.referenceMask = referenceMask;
+        this.derivedReferenceBase = derivedReferenceBase;
+
+        assert derivedReferenceBase == null || !derivedReferenceBase.getValueKind(LIRKind.class).isDerivedReference() : "derived reference can't have another derived reference as base";
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should
+     * be only used when it's guaranteed that the value is not even indirectly derived from a
+     * reference. Otherwise, {@link #combine(Value...)} should be used instead.
+     */
+    public static LIRKind value(PlatformKind platformKind) {
+        return new LIRKind(platformKind, 0, null);
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop
+     * reference.
+     */
+    public static LIRKind reference(PlatformKind platformKind) {
+        return derivedReference(platformKind, null);
+    }
+
+    /**
+     * Create the correct {@link LIRKind} for a given {@link Architecture} and {@link JavaKind}.
+     */
+    public static LIRKind fromJavaKind(Architecture arch, JavaKind javaKind) {
+        PlatformKind platformKind = arch.getPlatformKind(javaKind);
+        if (javaKind.isObject()) {
+            return LIRKind.reference(platformKind);
+        } else {
+            return LIRKind.value(platformKind);
+        }
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference.
+     */
+    public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) {
+        int length = platformKind.getVectorLength();
+        assert 0 < length && length < 32 : "vector of " + length + " references not supported";
+        return new LIRKind(platformKind, (1 << length) - 1, base);
+    }
+
+    /**
+     * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived
+     * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at
+     * safepoints. In most cases, this should not be called directly. {@link #combine} should be
+     * used instead to automatically propagate this information.
+     */
+    public static LIRKind unknownReference(PlatformKind platformKind) {
+        return new LIRKind(platformKind, UNKNOWN_REFERENCE, null);
+    }
+
+    /**
+     * Create a derived reference.
+     *
+     * @param base An {@link AllocatableValue} containing the base pointer of the derived reference.
+     */
+    public LIRKind makeDerivedReference(AllocatableValue base) {
+        assert !isUnknownReference() && derivedReferenceBase == null;
+        if (Value.ILLEGAL.equals(base)) {
+            return makeUnknownReference();
+        } else {
+            if (isValue()) {
+                return derivedReference(getPlatformKind(), base);
+            } else {
+                return new LIRKind(getPlatformKind(), referenceMask, base);
+            }
+        }
+    }
+
+    /**
+     * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the
+     * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown
+     * reference.
+     *
+     * This method should be used to construct the result {@link LIRKind} of any operation that
+     * modifies values (e.g. arithmetics).
+     */
+    public static LIRKind combine(Value... inputs) {
+        assert inputs.length > 0;
+        for (Value input : inputs) {
+            LIRKind kind = input.getValueKind(LIRKind.class);
+            if (kind.isUnknownReference()) {
+                return kind;
+            } else if (!kind.isValue()) {
+                return kind.makeUnknownReference();
+            }
+        }
+
+        // all inputs are values, just return one of them
+        return inputs[0].getValueKind(LIRKind.class);
+    }
+
+    /**
+     * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the
+     * inputs. If all inputs are values (references), the result is a value (reference). Otherwise,
+     * the result is an unknown reference.
+     *
+     * This method should be used to construct the result {@link LIRKind} of merge operation that
+     * does not modify values (e.g. phis).
+     */
+    public static LIRKind merge(Value... inputs) {
+        assert inputs.length > 0;
+        ArrayList<LIRKind> kinds = new ArrayList<>(inputs.length);
+        for (int i = 0; i < inputs.length; i++) {
+            kinds.add(inputs[i].getValueKind(LIRKind.class));
+        }
+        return merge(kinds);
+    }
+
+    /**
+     * Helper method to construct derived reference kinds. Returns the base value of a reference or
+     * derived reference. For values it returns {@code null}, and for unknown references it returns
+     * {@link Value#ILLEGAL}.
+     */
+    public static AllocatableValue derivedBaseFromValue(AllocatableValue value) {
+        ValueKind<?> valueKind = value.getValueKind();
+        if (valueKind instanceof LIRKind) {
+            LIRKind kind = value.getValueKind(LIRKind.class);
+            if (kind.isValue()) {
+                return null;
+            } else if (kind.isDerivedReference()) {
+                return kind.getDerivedReferenceBase();
+            } else if (kind.isUnknownReference()) {
+                return Value.ILLEGAL;
+            } else {
+                // kind is a reference
+                return value;
+            }
+        } else {
+            return Value.ILLEGAL;
+        }
+    }
+
+    /**
+     * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2}
+     * are set, it creates a derived reference using it as the base. If both are set, the result is
+     * an unknown reference.
+     */
+    public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) {
+        if (base1 == null && base2 == null) {
+            return kind;
+        } else if (base1 == null) {
+            return kind.makeDerivedReference(base2);
+        } else if (base2 == null) {
+            return kind.makeDerivedReference(base1);
+        } else {
+            return kind.makeUnknownReference();
+        }
+    }
+
+    /**
+     * @see #merge(Value...)
+     */
+    public static LIRKind merge(Iterable<LIRKind> kinds) {
+        LIRKind mergeKind = null;
+
+        for (LIRKind kind : kinds) {
+
+            if (kind.isUnknownReference()) {
+                /**
+                 * Kind is an unknown reference, therefore the result can only be also an unknown
+                 * reference.
+                 */
+                mergeKind = kind;
+                break;
+            }
+            if (mergeKind == null) {
+                mergeKind = kind;
+                continue;
+            }
+
+            if (kind.isValue()) {
+                /* Kind is a value. */
+                if (mergeKind.referenceMask != 0) {
+                    /*
+                     * Inputs consists of values and references. Make the result an unknown
+                     * reference.
+                     */
+                    mergeKind = mergeKind.makeUnknownReference();
+                    break;
+                }
+                /* Check that other inputs are also values. */
+            } else {
+                /* Kind is a reference. */
+                if (mergeKind.referenceMask != kind.referenceMask) {
+                    /*
+                     * Reference maps do not match so the result can only be an unknown reference.
+                     */
+                    mergeKind = mergeKind.makeUnknownReference();
+                    break;
+                }
+            }
+
+        }
+        assert mergeKind != null && verifyMerge(mergeKind, kinds);
+
+        // all inputs are values or references, just return one of them
+        return mergeKind;
+    }
+
+    private static boolean verifyMerge(LIRKind mergeKind, Iterable<LIRKind> kinds) {
+        for (LIRKind kind : kinds) {
+            assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind);
+        }
+        return true;
+    }
+
+    /**
+     * Create a new {@link LIRKind} with the same reference information and a new
+     * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this,
+     * the new elements are marked as untracked values.
+     */
+    @Override
+    public LIRKind changeType(PlatformKind newPlatformKind) {
+        if (newPlatformKind == getPlatformKind()) {
+            return this;
+        } else if (isUnknownReference()) {
+            return unknownReference(newPlatformKind);
+        } else if (referenceMask == 0) {
+            // value type
+            return LIRKind.value(newPlatformKind);
+        } else {
+            // reference type
+            int newLength = Math.min(32, newPlatformKind.getVectorLength());
+            int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength));
+            assert newReferenceMask != UNKNOWN_REFERENCE;
+            return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase);
+        }
+    }
+
+    /**
+     * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the
+     * new kind is longer than this, the reference positions are repeated to fill the vector.
+     */
+    public LIRKind repeat(PlatformKind newPlatformKind) {
+        if (isUnknownReference()) {
+            return unknownReference(newPlatformKind);
+        } else if (referenceMask == 0) {
+            // value type
+            return LIRKind.value(newPlatformKind);
+        } else {
+            // reference type
+            int oldLength = getPlatformKind().getVectorLength();
+            int newLength = newPlatformKind.getVectorLength();
+            assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0;
+
+            // repeat reference mask to fill new kind
+            int newReferenceMask = 0;
+            for (int i = 0; i < newLength; i += getPlatformKind().getVectorLength()) {
+                newReferenceMask |= referenceMask << i;
+            }
+
+            assert newReferenceMask != UNKNOWN_REFERENCE;
+            return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase);
+        }
+    }
+
+    /**
+     * Create a new {@link LIRKind} with the same type, but marked as containing an
+     * {@link LIRKind#unknownReference}.
+     */
+    public LIRKind makeUnknownReference() {
+        return new LIRKind(getPlatformKind(), UNKNOWN_REFERENCE, null);
+    }
+
+    /**
+     * Check whether this value is a derived reference.
+     */
+    public boolean isDerivedReference() {
+        return getDerivedReferenceBase() != null;
+    }
+
+    /**
+     * Get the base value of a derived reference.
+     */
+    public AllocatableValue getDerivedReferenceBase() {
+        return derivedReferenceBase;
+    }
+
+    /**
+     * Change the base value of a derived reference. This must be called on derived references only.
+     */
+    public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) {
+        assert isDerivedReference();
+        this.derivedReferenceBase = derivedReferenceBase;
+    }
+
+    /**
+     * Check whether this value is derived from a reference in a non-linear way. If this returns
+     * {@code true}, this value must not be live at safepoints.
+     */
+    public boolean isUnknownReference() {
+        return referenceMask == UNKNOWN_REFERENCE;
+    }
+
+    public static boolean isUnknownReference(ValueKind<?> kind) {
+        if (kind instanceof LIRKind) {
+            return ((LIRKind) kind).isUnknownReference();
+        } else {
+            return true;
+        }
+    }
+
+    public static boolean isUnknownReference(Value value) {
+        return isUnknownReference(value.getValueKind());
+    }
+
+    public int getReferenceCount() {
+        assert !isUnknownReference();
+        return Integer.bitCount(referenceMask);
+    }
+
+    /**
+     * Check whether the {@code idx}th part of this value is a reference that must be tracked at
+     * safepoints.
+     *
+     * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar
+     *            kind.
+     */
+    public boolean isReference(int idx) {
+        assert 0 <= idx && idx < getPlatformKind().getVectorLength() : "invalid index " + idx + " in " + this;
+        return !isUnknownReference() && (referenceMask & 1 << idx) != 0;
+    }
+
+    /**
+     * Check whether this kind is a value type that doesn't need to be tracked at safepoints.
+     */
+    public boolean isValue() {
+        return referenceMask == 0;
+    }
+
+    public static boolean isValue(ValueKind<?> kind) {
+        if (kind instanceof LIRKind) {
+            return ((LIRKind) kind).isValue();
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean isValue(Value value) {
+        return isValue(value.getValueKind());
+    }
+
+    @Override
+    public String toString() {
+        if (isValue()) {
+            return getPlatformKind().name();
+        } else if (isUnknownReference()) {
+            return getPlatformKind().name() + "[*]";
+        } else {
+            StringBuilder ret = new StringBuilder();
+            ret.append(getPlatformKind().name());
+            ret.append('[');
+            for (int i = 0; i < getPlatformKind().getVectorLength(); i++) {
+                if (isReference(i)) {
+                    ret.append('.');
+                } else {
+                    ret.append(' ');
+                }
+            }
+            ret.append(']');
+            return ret.toString();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getPlatformKind() == null) ? 0 : getPlatformKind().hashCode());
+        result = prime * result + referenceMask;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof LIRKind)) {
+            return false;
+        }
+
+        LIRKind other = (LIRKind) obj;
+        return getPlatformKind() == other.getPlatformKind() && referenceMask == other.referenceMask;
+    }
+
+    public static boolean verifyMoveKinds(ValueKind<?> dst, ValueKind<?> src) {
+        if (src.equals(dst)) {
+            return true;
+        }
+        if (src.getPlatformKind().equals(dst.getPlatformKind())) {
+            return !isUnknownReference(src) || isUnknownReference(dst);
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LinkedIdentityHashMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LinkedIdentityHashMap.java
new file mode 100644
index 0000000..7c1aca0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LinkedIdentityHashMap.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+/**
+ * A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of
+ * ensuring a deterministic execution order during a capturing compilation.
+ */
+final class LinkedIdentityHashMap<K, V> implements Map<K, V> {
+
+    private final LinkedHashMap<Id<K>, V> map;
+
+    LinkedIdentityHashMap() {
+        map = new LinkedHashMap<>();
+    }
+
+    LinkedIdentityHashMap(Map<K, V> m) {
+        map = new LinkedHashMap<>(m.size());
+        putAll(m);
+    }
+
+    LinkedIdentityHashMap(int expectedMaxSize) {
+        map = new LinkedHashMap<>(expectedMaxSize);
+    }
+
+    /**
+     * Wrapper for an object that gives uses the object's identity for the purpose of equality
+     * comparisons and computing a hash code.
+     */
+    static final class Id<T> {
+        final T object;
+
+        Id(T object) {
+            assert object != null;
+            this.object = object;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof Id && ((Id<T>) obj).object == object;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(object);
+        }
+    }
+
+    @Override
+    public int size() {
+        return map.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return map.containsKey(id(key));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Id<K> id(Object key) {
+        if (key == null) {
+            return null;
+        }
+        return new Id<>((K) key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+        return map.get(id(key));
+    }
+
+    @Override
+    public V put(K key, V value) {
+        return map.put(id(key), value);
+    }
+
+    @Override
+    public V remove(Object key) {
+        return map.remove(id(key));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void putAll(Map<? extends K, ? extends V> m) {
+        if (m == null) {
+            throw new NullPointerException();
+        }
+        if (m.getClass() == getClass()) {
+            LinkedIdentityHashMap<K, V> that = (LinkedIdentityHashMap<K, V>) m;
+            map.putAll(that.map);
+
+        } else {
+            for (K key : m.keySet()) {
+                map.put(id(key), m.get(key));
+            }
+        }
+    }
+
+    @Override
+    public void clear() {
+        map.clear();
+    }
+
+    final class KeySet extends AbstractSet<K> {
+        @Override
+        public int size() {
+            return map.size();
+        }
+
+        @Override
+        public void clear() {
+            map.clear();
+        }
+
+        @Override
+        public Iterator<K> iterator() {
+            return new Iterator<K>() {
+                final Iterator<Id<K>> i = map.keySet().iterator();
+
+                @Override
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                @Override
+                public K next() {
+                    return i.next().object;
+                }
+
+                @Override
+                public void remove() {
+                    i.remove();
+                }
+            };
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            return LinkedIdentityHashMap.this.remove(o) != null;
+        }
+
+        @Override
+        public Spliterator<K> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
+        }
+
+        @Override
+        public void forEach(Consumer<? super K> action) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public Set<K> keySet() {
+        return new KeySet();
+    }
+
+    @Override
+    public Collection<V> values() {
+        return map.values();
+    }
+
+    final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
+        @Override
+        public int size() {
+            return map.size();
+        }
+
+        @Override
+        public void clear() {
+            map.clear();
+        }
+
+        @Override
+        public Iterator<Map.Entry<K, V>> iterator() {
+            return new Iterator<Map.Entry<K, V>>() {
+                final Iterator<Map.Entry<Id<K>, V>> i = map.entrySet().iterator();
+
+                @Override
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                @Override
+                public Map.Entry<K, V> next() {
+                    Map.Entry<Id<K>, V> e = i.next();
+                    return new Map.Entry<K, V>() {
+
+                        @Override
+                        public K getKey() {
+                            return e.getKey().object;
+                        }
+
+                        @Override
+                        public V getValue() {
+                            return e.getValue();
+                        }
+
+                        @Override
+                        public V setValue(V value) {
+                            return e.setValue(value);
+                        }
+                    };
+                }
+
+                @Override
+                public void remove() {
+                    i.remove();
+                }
+            };
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Spliterator<Map.Entry<K, V>> spliterator() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void forEach(Consumer<? super Map.Entry<K, V>> action) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public Set<Map.Entry<K, V>> entrySet() {
+        return new EntrySet();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java
new file mode 100644
index 0000000..38ba381
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import java.util.IdentityHashMap;
+
+// JaCoCo Exclude
+
+/**
+ * Marker interface for location identities. A different location identity of two memory accesses
+ * guarantees that the two accesses do not interfere.
+ *
+ * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
+ * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
+ * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys.
+ */
+public abstract class LocationIdentity {
+
+    private static final class AnyLocationIdentity extends LocationIdentity {
+        @Override
+        public boolean isImmutable() {
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "ANY_LOCATION";
+        }
+    }
+
+    public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
+
+    public static LocationIdentity any() {
+        return ANY_LOCATION;
+    }
+
+    /**
+     * Denotes a location is unchanging in all cases. Not that this is different than the Java
+     * notion of final which only requires definite assignment.
+     */
+    public abstract boolean isImmutable();
+
+    public final boolean isMutable() {
+        return !isImmutable();
+    }
+
+    public final boolean isAny() {
+        return this == ANY_LOCATION;
+    }
+
+    public final boolean isSingle() {
+        return this != ANY_LOCATION;
+    }
+
+    public final boolean overlaps(LocationIdentity other) {
+        return isAny() || other.isAny() || this.equals(other);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SuppressFBWarnings.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SuppressFBWarnings.java
new file mode 100644
index 0000000..bc25840
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SuppressFBWarnings.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+/**
+ * Used to suppress <a href="http://findbugs.sourceforge.net">FindBugs</a> warnings.
+ */
+public @interface SuppressFBWarnings {
+    /**
+     * The set of FindBugs
+     * <a href="http://findbugs.sourceforge.net/bugDescriptions.html">warnings</a> that are to be
+     * suppressed in annotated element. The value can be a bug category, kind or pattern.
+     */
+    String[] value();
+
+    /**
+     * Reason why the warning is suppressed.
+     */
+    String justification();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/UnsafeAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/UnsafeAccess.java
new file mode 100644
index 0000000..14801c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/UnsafeAccess.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java
new file mode 100644
index 0000000..d99cbad
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Deque;
+
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+
+/**
+ * Computes traces by selecting the unhandled block with the highest execution frequency and going
+ * in both directions, up and down, as long as possible.
+ */
+public final class BiDirectionalTraceBuilder {
+
+    public static TraceBuilderResult computeTraces(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        return new BiDirectionalTraceBuilder(blocks).build(startBlock, blocks, pred);
+    }
+
+    private final Deque<AbstractBlockBase<?>> worklist;
+    private final BitSet processed;
+    private final Trace[] blockToTrace;
+
+    private BiDirectionalTraceBuilder(AbstractBlockBase<?>[] blocks) {
+        processed = new BitSet(blocks.length);
+        worklist = createQueue(blocks);
+        blockToTrace = new Trace[blocks.length];
+    }
+
+    private static Deque<AbstractBlockBase<?>> createQueue(AbstractBlockBase<?>[] blocks) {
+        ArrayList<AbstractBlockBase<?>> queue = new ArrayList<>(Arrays.asList(blocks));
+        queue.sort(BiDirectionalTraceBuilder::compare);
+        return new ArrayDeque<>(queue);
+    }
+
+    private static int compare(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        return Double.compare(b.probability(), a.probability());
+    }
+
+    private boolean processed(AbstractBlockBase<?> b) {
+        return processed.get(b.getId());
+    }
+
+    @SuppressWarnings("try")
+    private TraceBuilderResult build(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        try (Indent indent = Debug.logAndIndent("BiDirectionalTraceBuilder: start trace building")) {
+            ArrayList<Trace> traces = buildTraces();
+            assert traces.get(0).getBlocks()[0].equals(startBlock) : "The first traces always contains the start block";
+            return TraceBuilderResult.create(blocks, traces, blockToTrace, pred);
+        }
+    }
+
+    protected ArrayList<Trace> buildTraces() {
+        ArrayList<Trace> traces = new ArrayList<>();
+        // process worklist
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<?> block = worklist.pollFirst();
+            assert block != null;
+            if (!processed(block)) {
+                Trace trace = new Trace(startTrace(block));
+                for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
+                    blockToTrace[traceBlock.getId()] = trace;
+                }
+                trace.setId(traces.size());
+                traces.add(trace);
+            }
+        }
+        return traces;
+    }
+
+    /**
+     * Build a new trace starting at {@code block}.
+     */
+    @SuppressWarnings("try")
+    private Collection<AbstractBlockBase<?>> startTrace(AbstractBlockBase<?> block) {
+        ArrayDeque<AbstractBlockBase<?>> trace = new ArrayDeque<>();
+        try (Indent i = Debug.logAndIndent("StartTrace: %s", block)) {
+            try (Indent indentFront = Debug.logAndIndent("Head:")) {
+                for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) {
+                    addBlockToTrace(currentBlock);
+                    trace.addFirst(currentBlock);
+                }
+            }
+            /* Number head blocks. Can not do this in the loop as we go backwards. */
+            int blockNr = 0;
+            for (AbstractBlockBase<?> b : trace) {
+                b.setLinearScanNumber(blockNr++);
+            }
+
+            try (Indent indentBack = Debug.logAndIndent("Tail:")) {
+                for (AbstractBlockBase<?> currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) {
+                    addBlockToTrace(currentBlock);
+                    trace.addLast(currentBlock);
+                    /* This time we can number the blocks immediately as we go forwards. */
+                    currentBlock.setLinearScanNumber(blockNr++);
+                }
+            }
+        }
+        Debug.log("Trace: %s", trace);
+        return trace;
+    }
+
+    private void addBlockToTrace(AbstractBlockBase<?> currentBlock) {
+        Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
+        processed.set(currentBlock.getId());
+    }
+
+    /**
+     * @return The unprocessed predecessor with the highest probability, or {@code null}.
+     */
+    private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> currentBlock) {
+        AbstractBlockBase<?> next = null;
+        for (AbstractBlockBase<?> pred : currentBlock.getPredecessors()) {
+            if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) {
+                next = pred;
+            }
+        }
+        return next;
+    }
+
+    private static boolean isBackEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+        assert Arrays.asList(from.getSuccessors()).contains(to) : "No edge from " + from + " to " + to;
+        return from.isLoopEnd() && to.isLoopHeader() && from.getLoop().equals(to.getLoop());
+    }
+
+    /**
+     * @return The unprocessed successor with the highest probability, or {@code null}.
+     */
+    private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> currentBlock) {
+        AbstractBlockBase<?> next = null;
+        for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
+            if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
+                next = succ;
+            }
+        }
+        return next;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java
new file mode 100644
index 0000000..b7f3a27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.Loop;
+
+/**
+ * Computes an ordering of the block that can be used by the linear scan register allocator and the
+ * machine code generator. The machine code generation order will start with the first block and
+ * produce a straight sequence always following the most likely successor. Then it will continue
+ * with the most likely path that was left out during this process. The process iteratively
+ * continues until all blocks are scheduled. Additionally, it is guaranteed that all blocks of a
+ * loop are scheduled before any block following the loop is scheduled.
+ *
+ * The machine code generator order includes reordering of loop headers such that the backward jump
+ * is a conditional jump if there is only one loop end block. Additionally, the target of loop
+ * backward jumps are always marked as aligned. Aligning the target of conditional jumps does not
+ * bring a measurable benefit and is therefore avoided to keep the code size small.
+ *
+ * The linear scan register allocator order has an additional mechanism that prevents merge nodes
+ * from being scheduled if there is at least one highly likely predecessor still unscheduled. This
+ * increases the probability that the merge node and the corresponding predecessor are more closely
+ * together in the schedule thus decreasing the probability for inserted phi moves. Also, the
+ * algorithm sets the linear scan order number of the block that corresponds to its index in the
+ * linear scan order.
+ */
+public final class ComputeBlockOrder {
+
+    /**
+     * The initial capacities of the worklists used for iteratively finding the block order.
+     */
+    private static final int INITIAL_WORKLIST_CAPACITY = 10;
+
+    /**
+     * Divisor used for degrading the probability of the current path versus unscheduled paths at a
+     * merge node when calculating the linear scan order. A high value means that predecessors of
+     * merge nodes are more likely to be scheduled before the merge node.
+     */
+    private static final int PENALTY_VERSUS_UNSCHEDULED = 10;
+
+    /**
+     * Computes the block order used for the linear scan register allocator.
+     *
+     * @return sorted list of blocks
+     */
+    public static <T extends AbstractBlockBase<T>> AbstractBlockBase<?>[] computeLinearScanOrder(int blockCount, T startBlock) {
+        List<T> order = new ArrayList<>();
+        BitSet visitedBlocks = new BitSet(blockCount);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
+        computeLinearScanOrder(order, worklist, visitedBlocks);
+        assert checkOrder(order, blockCount);
+        return order.toArray(new AbstractBlockBase<?>[0]);
+    }
+
+    /**
+     * Computes the block order used for code emission.
+     *
+     * @return sorted list of blocks
+     */
+    public static <T extends AbstractBlockBase<T>> AbstractBlockBase<?>[] computeCodeEmittingOrder(int blockCount, T startBlock) {
+        List<T> order = new ArrayList<>();
+        BitSet visitedBlocks = new BitSet(blockCount);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
+        computeCodeEmittingOrder(order, worklist, visitedBlocks);
+        assert checkOrder(order, blockCount);
+        return order.toArray(new AbstractBlockBase<?>[0]);
+    }
+
+    /**
+     * Iteratively adds paths to the code emission block order.
+     */
+    private static <T extends AbstractBlockBase<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+        while (!worklist.isEmpty()) {
+            T nextImportantPath = worklist.poll();
+            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks);
+        }
+    }
+
+    /**
+     * Iteratively adds paths to the linear scan block order.
+     */
+    private static <T extends AbstractBlockBase<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+        while (!worklist.isEmpty()) {
+            T nextImportantPath = worklist.poll();
+            do {
+                nextImportantPath = addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks);
+            } while (nextImportantPath != null);
+        }
+    }
+
+    /**
+     * Initializes the priority queue used for the work list of blocks and adds the start block.
+     */
+    private static <T extends AbstractBlockBase<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks) {
+        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>());
+        result.add(startBlock);
+        visitedBlocks.set(startBlock.getId());
+        return result;
+    }
+
+    /**
+     * Add a linear path to the linear scan order greedily following the most likely successor.
+     */
+    private static <T extends AbstractBlockBase<T>> T addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+        block.setLinearScanNumber(order.size());
+        order.add(block);
+        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
+        enqueueSuccessors(block, worklist, visitedBlocks);
+        if (mostLikelySuccessor != null) {
+            if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) {
+                // We are at a merge. Check probabilities of predecessors that are not yet
+                // scheduled.
+                double unscheduledSum = 0.0;
+                for (T pred : mostLikelySuccessor.getPredecessors()) {
+                    if (pred.getLinearScanNumber() == -1) {
+                        unscheduledSum += pred.probability();
+                    }
+                }
+
+                if (unscheduledSum > block.probability() / PENALTY_VERSUS_UNSCHEDULED) {
+                    // Add this merge only after at least one additional predecessor gets scheduled.
+                    visitedBlocks.clear(mostLikelySuccessor.getId());
+                    return null;
+                }
+            }
+            return mostLikelySuccessor;
+        }
+        return null;
+    }
+
+    /**
+     * Add a linear path to the code emission order greedily following the most likely successor.
+     */
+    private static <T extends AbstractBlockBase<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+        T block = initialBlock;
+        while (block != null) {
+            // Skip loop headers if there is only a single loop end block to
+            // make the backward jump be a conditional jump.
+            if (!skipLoopHeader(block)) {
+
+                // Align unskipped loop headers as they are the target of the backward jump.
+                if (block.isLoopHeader()) {
+                    block.setAlign(true);
+                }
+                addBlock(block, order);
+            }
+
+            Loop<T> loop = block.getLoop();
+            if (block.isLoopEnd() && skipLoopHeader(loop.getHeader())) {
+
+                // This is the only loop end of a skipped loop header.
+                // Add the header immediately afterwards.
+                addBlock(loop.getHeader(), order);
+
+                // Make sure the loop successors of the loop header are aligned
+                // as they are the target
+                // of the backward jump.
+                for (T successor : loop.getHeader().getSuccessors()) {
+                    if (successor.getLoopDepth() == block.getLoopDepth()) {
+                        successor.setAlign(true);
+                    }
+                }
+            }
+
+            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
+            enqueueSuccessors(block, worklist, visitedBlocks);
+            block = mostLikelySuccessor;
+        }
+    }
+
+    /**
+     * Adds a block to the ordering.
+     */
+    private static <T extends AbstractBlockBase<T>> void addBlock(T header, List<T> order) {
+        assert !order.contains(header) : "Cannot insert block twice";
+        order.add(header);
+    }
+
+    /**
+     * Find the highest likely unvisited successor block of a given block.
+     */
+    private static <T extends AbstractBlockBase<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
+        T result = null;
+        for (T successor : block.getSuccessors()) {
+            assert successor.probability() >= 0.0 : "Probabilities must be positive";
+            if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) {
+                result = successor;
+            }
+        }
+        if (result != null) {
+            visitedBlocks.set(result.getId());
+        }
+        return result;
+    }
+
+    /**
+     * Add successor blocks into the given work list if they are not already marked as visited.
+     */
+    private static <T extends AbstractBlockBase<T>> void enqueueSuccessors(T block, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+        for (T successor : block.getSuccessors()) {
+            if (!visitedBlocks.get(successor.getId())) {
+                visitedBlocks.set(successor.getId());
+                worklist.add(successor);
+            }
+        }
+    }
+
+    /**
+     * Skip the loop header block if the loop consists of more than one block and it has only a
+     * single loop end block.
+     */
+    private static <T extends AbstractBlockBase<T>> boolean skipLoopHeader(AbstractBlockBase<T> block) {
+        return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().numBackedges() == 1);
+    }
+
+    /**
+     * Checks that the ordering contains the expected number of blocks.
+     */
+    private static boolean checkOrder(List<? extends AbstractBlockBase<?>> order, int expectedBlockCount) {
+        assert order.size() == expectedBlockCount : String.format("Number of blocks in ordering (%d) does not match expected block count (%d)", order.size(), expectedBlockCount);
+        return true;
+    }
+
+    /**
+     * Comparator for sorting blocks based on loop depth and probability.
+     */
+    private static class BlockOrderComparator<T extends AbstractBlockBase<T>> implements Comparator<T> {
+
+        @Override
+        public int compare(T a, T b) {
+            // Loop blocks before any loop exit block.
+            int diff = b.getLoopDepth() - a.getLoopDepth();
+            if (diff != 0) {
+                return diff;
+            }
+
+            // Blocks with high probability before blocks with low probability.
+            if (a.probability() > b.probability()) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java
new file mode 100644
index 0000000..91ff015
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.meta.PlatformKind;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+
+/**
+ * Configuration for register allocation. This is different to {@link RegisterConfig} as it only
+ * returns registers specified by {@link GraalOptions#RegisterPressure}.
+ */
+public class RegisterAllocationConfig {
+
+    public static final class AllocatableRegisters {
+        public final Register[] allocatableRegisters;
+        public final int minRegisterNumber;
+        public final int maxRegisterNumber;
+
+        public AllocatableRegisters(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
+            this.allocatableRegisters = allocatableRegisters.toArray();
+            this.minRegisterNumber = minRegisterNumber;
+            this.maxRegisterNumber = maxRegisterNumber;
+            assert verify(allocatableRegisters, minRegisterNumber, maxRegisterNumber);
+        }
+
+        private static boolean verify(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
+            int min = Integer.MAX_VALUE;
+            int max = Integer.MIN_VALUE;
+            for (Register reg : allocatableRegisters) {
+                int number = reg.number;
+                if (number < min) {
+                    min = number;
+                }
+                if (number > max) {
+                    max = number;
+                }
+            }
+            assert minRegisterNumber == min;
+            assert maxRegisterNumber == max;
+            return true;
+        }
+    }
+
+    public static final String ALL_REGISTERS = "<all>";
+
+    private static Register findRegister(String name, RegisterArray all) {
+        for (Register reg : all) {
+            if (reg.name.equals(name)) {
+                return reg;
+            }
+        }
+        throw new IllegalArgumentException("register " + name + " is not allocatable");
+    }
+
+    protected RegisterArray initAllocatable(RegisterArray registers) {
+        if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
+            String[] names = RegisterPressure.getValue().split(",");
+            Register[] regs = new Register[names.length];
+            for (int i = 0; i < names.length; i++) {
+                regs[i] = findRegister(names[i], registers);
+            }
+            return new RegisterArray(regs);
+        }
+
+        return registers;
+    }
+
+    protected final RegisterConfig registerConfig;
+    private final Map<PlatformKind.Key, AllocatableRegisters> categorized = new HashMap<>();
+    private RegisterArray cachedRegisters;
+
+    public RegisterAllocationConfig(RegisterConfig registerConfig) {
+        assert registerConfig != null;
+        this.registerConfig = registerConfig;
+    }
+
+    /**
+     * Gets the set of registers that can be used by the register allocator for a value of a
+     * particular kind.
+     */
+    public AllocatableRegisters getAllocatableRegisters(PlatformKind kind) {
+        PlatformKind.Key key = kind.getKey();
+        if (categorized.containsKey(key)) {
+            AllocatableRegisters val = categorized.get(key);
+            return val;
+        }
+        AllocatableRegisters ret = createAllocatableRegisters(registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters()));
+        categorized.put(key, ret);
+        return ret;
+    }
+
+    protected AllocatableRegisters createAllocatableRegisters(RegisterArray registers) {
+        int min = Integer.MAX_VALUE;
+        int max = Integer.MIN_VALUE;
+        for (Register reg : registers) {
+            int number = reg.number;
+            if (number < min) {
+                min = number;
+            }
+            if (number > max) {
+                max = number;
+            }
+        }
+        assert min < max;
+        return new AllocatableRegisters(registers, min, max);
+
+    }
+
+    /**
+     * Gets the set of registers that can be used by the register allocator.
+     */
+    public RegisterArray getAllocatableRegisters() {
+        if (cachedRegisters == null) {
+            cachedRegisters = initAllocatable(registerConfig.getAllocatableRegisters());
+        }
+        assert cachedRegisters != null;
+        return cachedRegisters;
+    }
+
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/SingleBlockTraceBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/SingleBlockTraceBuilder.java
new file mode 100644
index 0000000..960c3b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/SingleBlockTraceBuilder.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+
+/**
+ * Builds traces consisting of a single basic block.
+ */
+public final class SingleBlockTraceBuilder {
+
+    public static TraceBuilderResult computeTraces(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        return build(startBlock, blocks, pred);
+    }
+
+    private static TraceBuilderResult build(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        Trace[] blockToTrace = new Trace[blocks.length];
+        ArrayList<Trace> traces = new ArrayList<>(blocks.length);
+
+        for (AbstractBlockBase<?> block : blocks) {
+            Trace trace = new Trace(new AbstractBlockBase<?>[]{block});
+            blockToTrace[block.getId()] = trace;
+            block.setLinearScanNumber(0);
+            trace.setId(traces.size());
+            traces.add(trace);
+        }
+
+        assert traces.get(0).getBlocks()[0].equals(startBlock) : "The first traces always contains the start block";
+        return TraceBuilderResult.create(blocks, traces, blockToTrace, pred);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/Trace.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/Trace.java
new file mode 100644
index 0000000..498a5be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/Trace.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+
+/**
+ * Represents a list of sequentially executed {@code AbstractBlockBase blocks}.
+ */
+public class Trace {
+    private final AbstractBlockBase<?>[] blocks;
+    private final ArrayList<Trace> successors;
+    private int id = -1;
+
+    public Trace(Collection<AbstractBlockBase<?>> blocks) {
+        this(blocks.toArray(new AbstractBlockBase<?>[0]));
+    }
+
+    public Trace(AbstractBlockBase<?>[] blocks) {
+        this.blocks = blocks;
+        this.successors = new ArrayList<>();
+    }
+
+    public AbstractBlockBase<?>[] getBlocks() {
+        return blocks;
+    }
+
+    public ArrayList<Trace> getSuccessors() {
+        return successors;
+    }
+
+    public int size() {
+        return getBlocks().length;
+    }
+
+    @Override
+    public String toString() {
+        return "Trace" + Arrays.toString(blocks);
+    }
+
+    public int getId() {
+        assert id != -1 : "id not initialized!";
+        return id;
+    }
+
+    void setId(int id) {
+        this.id = id;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceBuilderResult.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceBuilderResult.java
new file mode 100644
index 0000000..da877f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceBuilderResult.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+
+public final class TraceBuilderResult {
+
+    public abstract static class TrivialTracePredicate {
+        public abstract boolean isTrivialTrace(Trace trace);
+    }
+
+    private final ArrayList<Trace> traces;
+    private final Trace[] blockToTrace;
+
+    static TraceBuilderResult create(AbstractBlockBase<?>[] blocks, ArrayList<Trace> traces, Trace[] blockToTrace, TrivialTracePredicate pred) {
+        connect(traces, blockToTrace);
+        ArrayList<Trace> newTraces = reorderTraces(traces, pred);
+        TraceBuilderResult traceBuilderResult = new TraceBuilderResult(newTraces, blockToTrace);
+        traceBuilderResult.numberTraces();
+        assert verify(traceBuilderResult, blocks.length);
+        return traceBuilderResult;
+    }
+
+    private TraceBuilderResult(ArrayList<Trace> traces, Trace[] blockToTrace) {
+        this.traces = traces;
+        this.blockToTrace = blockToTrace;
+    }
+
+    public Trace getTraceForBlock(AbstractBlockBase<?> block) {
+        return blockToTrace[block.getId()];
+    }
+
+    public ArrayList<Trace> getTraces() {
+        return traces;
+    }
+
+    public boolean incomingEdges(Trace trace) {
+        return incomingEdges(trace.getId(), trace.getBlocks(), 0);
+    }
+
+    public boolean incomingSideEdges(Trace trace) {
+        AbstractBlockBase<?>[] traceArr = trace.getBlocks();
+        if (traceArr.length <= 0) {
+            return false;
+        }
+        return incomingEdges(trace.getId(), traceArr, 1);
+    }
+
+    private boolean incomingEdges(int traceNr, AbstractBlockBase<?>[] trace, int index) {
+        /* TODO (je): not efficient. find better solution. */
+        for (int i = index; i < trace.length; i++) {
+            AbstractBlockBase<?> block = trace[1];
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                if (getTraceForBlock(pred).getId() != traceNr) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean verify(TraceBuilderResult traceBuilderResult, int expectedLength) {
+        ArrayList<Trace> traces = traceBuilderResult.getTraces();
+        assert verifyAllBlocksScheduled(traceBuilderResult, expectedLength) : "Not all blocks assigned to traces!";
+        for (int i = 0; i < traces.size(); i++) {
+            Trace trace = traces.get(i);
+            assert trace.getId() == i : "Trace number mismatch: " + trace.getId() + " vs. " + i;
+
+            BitSet suxTraces = new BitSet(traces.size());
+            for (Trace suxTrace : trace.getSuccessors()) {
+                assert !suxTraces.get(suxTrace.getId()) : "Trace twice successors " + suxTrace;
+                suxTraces.set(suxTrace.getId());
+            }
+
+            AbstractBlockBase<?> last = null;
+            int blockNumber = 0;
+            for (AbstractBlockBase<?> current : trace.getBlocks()) {
+                AbstractBlockBase<?> block = current;
+                assert traceBuilderResult.getTraceForBlock(block).getId() == i : "Trace number mismatch for block " + block + ": " + traceBuilderResult.getTraceForBlock(block) + " vs. " + i;
+                assert last == null || Arrays.asList(current.getPredecessors()).contains(last) : "Last block (" + last + ") not a predecessor of " + current;
+                assert current.getLinearScanNumber() == blockNumber : "Blocks not numbered correctly: " + current.getLinearScanNumber() + " vs. " + blockNumber;
+                last = current;
+                blockNumber++;
+                for (AbstractBlockBase<?> sux : block.getSuccessors()) {
+                    Trace suxTrace = traceBuilderResult.getTraceForBlock(sux);
+                    assert suxTraces.get(suxTrace.getId()) : "Successor Trace " + suxTrace + " for block " + sux + " not in successor traces of " + trace;
+                }
+            }
+        }
+        return true;
+    }
+
+    private static boolean verifyAllBlocksScheduled(TraceBuilderResult traceBuilderResult, int expectedLength) {
+        ArrayList<Trace> traces = traceBuilderResult.getTraces();
+        BitSet handled = new BitSet(expectedLength);
+        for (Trace trace : traces) {
+            for (AbstractBlockBase<?> block : trace.getBlocks()) {
+                assert !handled.get(block.getId()) : "Block added twice: " + block;
+                handled.set(block.getId());
+            }
+        }
+        return handled.cardinality() == expectedLength;
+    }
+
+    private void numberTraces() {
+        for (int i = 0; i < traces.size(); i++) {
+            Trace trace = traces.get(i);
+            trace.setId(i);
+        }
+    }
+
+    private static void connect(ArrayList<Trace> traces, Trace[] blockToTrace) {
+        int numTraces = traces.size();
+        for (Trace trace : traces) {
+            BitSet added = new BitSet(numTraces);
+            ArrayList<Trace> successors = trace.getSuccessors();
+            assert successors.size() == 0 : "Can only connect traces once!";
+
+            for (AbstractBlockBase<?> block : trace.getBlocks()) {
+                for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+                    Trace succTrace = blockToTrace[succ.getId()];
+                    int succId = succTrace.getId();
+                    if (!added.get(succId)) {
+                        added.set(succId);
+                        successors.add(succTrace);
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private static ArrayList<Trace> reorderTraces(ArrayList<Trace> oldTraces, TrivialTracePredicate pred) {
+        if (pred == null) {
+            return oldTraces;
+        }
+        try (Indent indent = Debug.logAndIndent("ReorderTrace")) {
+            ArrayList<Trace> newTraces = new ArrayList<>(oldTraces.size());
+            for (int oldTraceIdx = 0; oldTraceIdx < oldTraces.size(); oldTraceIdx++) {
+                Trace currentTrace = oldTraces.get(oldTraceIdx);
+                if (!alreadyProcessed(newTraces, currentTrace)) {
+                    assert currentTrace.getId() == oldTraceIdx : "Index mismatch";
+                    // add current trace
+                    addTrace(newTraces, currentTrace);
+                    for (Trace succTrace : currentTrace.getSuccessors()) {
+                        if (pred.isTrivialTrace(succTrace) && !alreadyProcessed(newTraces, succTrace)) {
+                            Debug.log("Moving trivial trace from %d to %d", succTrace.getId(), newTraces.size());
+                            // add trivial successor trace
+                            addTrace(newTraces, succTrace);
+                        }
+                    }
+                }
+            }
+            assert newTraces.size() == oldTraces.size() : "Lost traces? " + oldTraces.size() + " vs. " + newTraces.size();
+            return newTraces;
+        }
+    }
+
+    private static boolean alreadyProcessed(ArrayList<Trace> newTraces, Trace currentTrace) {
+        int currentTraceId = currentTrace.getId();
+        return currentTraceId < newTraces.size() && currentTrace == newTraces.get(currentTraceId);
+    }
+
+    private static void addTrace(ArrayList<Trace> newTraces, Trace currentTrace) {
+        currentTrace.setId(newTraces.size());
+        newTraces.add(currentTrace);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceMap.java
new file mode 100644
index 0000000..39c6366
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceMap.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+public class TraceMap<T> {
+
+    private final T[] data;
+
+    @SuppressWarnings("unchecked")
+    public TraceMap(TraceBuilderResult traceBuilderResult) {
+        data = (T[]) new Object[traceBuilderResult.getTraces().size()];
+    }
+
+    public T get(Trace trace) {
+        return data[trace.getId()];
+    }
+
+    public void put(Trace trace, T value) {
+        data[trace.getId()] = value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java
new file mode 100644
index 0000000..2e09be8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+
+public final class TraceStatisticsPrinter {
+    private static final String SEP = ";";
+
+    @SuppressWarnings("try")
+    public static void printTraceStatistics(TraceBuilderResult result, String compilationUnitName) {
+        try (Scope s = Debug.scope("DumpTraceStatistics")) {
+            if (Debug.isLogEnabled(Debug.VERBOSE_LOG_LEVEL)) {
+                print(result, compilationUnitName);
+            }
+        } catch (Throwable e) {
+            Debug.handle(e);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected static void print(TraceBuilderResult result, String compilationUnitName) {
+        List<Trace> traces = result.getTraces();
+        int numTraces = traces.size();
+
+        try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "<tracestatistics>")) {
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "<name>%s</name>", compilationUnitName != null ? compilationUnitName : "null");
+            try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "<traces>")) {
+                printRawLine("tracenumber", "total", "min", "max", "numBlocks");
+                for (int i = 0; i < numTraces; i++) {
+                    AbstractBlockBase<?>[] t = traces.get(i).getBlocks();
+                    double total = 0;
+                    double max = Double.NEGATIVE_INFINITY;
+                    double min = Double.POSITIVE_INFINITY;
+                    for (AbstractBlockBase<?> block : t) {
+                        double probability = block.probability();
+                        total += probability;
+                        if (probability < min) {
+                            min = probability;
+                        }
+                        if (probability > max) {
+                            max = probability;
+                        }
+                    }
+                    printLine(i, total, min, max, t.length);
+                }
+            }
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "</traces>");
+        }
+        Debug.log(Debug.VERBOSE_LOG_LEVEL, "</tracestatistics>");
+
+    }
+
+    private static void printRawLine(Object tracenr, Object totalTime, Object minProb, Object maxProb, Object numBlocks) {
+        Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString()));
+    }
+
+    private static void printLine(int tracenr, double totalTime, double minProb, double maxProb, int numBlocks) {
+        printRawLine(tracenr, totalTime, minProb, maxProb, numBlocks);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java
new file mode 100644
index 0000000..5e23826
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.alloc;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.PriorityQueue;
+
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+
+/**
+ * Computes traces by starting at a trace head and keep adding predecessors as long as possible.
+ */
+public final class UniDirectionalTraceBuilder {
+
+    public static TraceBuilderResult computeTraces(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        return new UniDirectionalTraceBuilder(blocks).build(startBlock, blocks, pred);
+    }
+
+    private final PriorityQueue<AbstractBlockBase<?>> worklist;
+    private final BitSet processed;
+    /**
+     * Contains the number of unprocessed predecessors for every {@link AbstractBlockBase#getId()
+     * block}.
+     */
+    private final int[] blocked;
+    private final Trace[] blockToTrace;
+
+    private UniDirectionalTraceBuilder(AbstractBlockBase<?>[] blocks) {
+        processed = new BitSet(blocks.length);
+        worklist = new PriorityQueue<>(UniDirectionalTraceBuilder::compare);
+        assert (worklist != null);
+
+        blocked = new int[blocks.length];
+        blockToTrace = new Trace[blocks.length];
+        for (AbstractBlockBase<?> block : blocks) {
+            blocked[block.getId()] = block.getPredecessorCount();
+        }
+    }
+
+    private static int compare(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        return Double.compare(b.probability(), a.probability());
+    }
+
+    private boolean processed(AbstractBlockBase<?> b) {
+        return processed.get(b.getId());
+    }
+
+    @SuppressWarnings("try")
+    private TraceBuilderResult build(AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
+        try (Indent indent = Debug.logAndIndent("UniDirectionalTraceBuilder: start trace building: %s", startBlock)) {
+            ArrayList<Trace> traces = buildTraces(startBlock);
+            return TraceBuilderResult.create(blocks, traces, blockToTrace, pred);
+        }
+    }
+
+    protected ArrayList<Trace> buildTraces(AbstractBlockBase<?> startBlock) {
+        ArrayList<Trace> traces = new ArrayList<>();
+        // add start block
+        worklist.add(startBlock);
+        // process worklist
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<?> block = worklist.poll();
+            assert block != null;
+            if (!processed(block)) {
+                Trace trace = new Trace(startTrace(block));
+                for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
+                    blockToTrace[traceBlock.getId()] = trace;
+                }
+                trace.setId(traces.size());
+                traces.add(trace);
+            }
+        }
+        return traces;
+    }
+
+    /**
+     * Build a new trace starting at {@code block}.
+     */
+    @SuppressWarnings("try")
+    private List<AbstractBlockBase<?>> startTrace(AbstractBlockBase<?> block) {
+        assert checkPredecessorsProcessed(block);
+        ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>();
+        int blockNumber = 0;
+        try (Indent i = Debug.logAndIndent("StartTrace: %s", block)) {
+            for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) {
+                Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
+                processed.set(currentBlock.getId());
+                trace.add(currentBlock);
+                unblock(currentBlock);
+                currentBlock.setLinearScanNumber(blockNumber++);
+            }
+        }
+        return trace;
+    }
+
+    private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) {
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            if (!processed(pred)) {
+                assert false : "Predecessor unscheduled: " + pred;
+                return false;
+            }
+
+        }
+        return true;
+    }
+
+    /**
+     * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once
+     * the count reaches 0.
+     */
+    private void unblock(AbstractBlockBase<?> currentBlock) {
+        for (AbstractBlockBase<?> successor : currentBlock.getSuccessors()) {
+            if (!processed(successor)) {
+                int blockCount = --blocked[successor.getId()];
+                assert blockCount >= 0;
+                if (blockCount == 0) {
+                    worklist.add(successor);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return The unprocessed predecessor with the highest probability, or {@code null}.
+     */
+    private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> currentBlock) {
+        AbstractBlockBase<?> next = null;
+        for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
+            if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
+                next = succ;
+            }
+        }
+        return next;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java
new file mode 100644
index 0000000..546dbd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.calc;
+
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+/**
+ * Condition codes used in conditionals.
+ */
+public enum Condition {
+    /**
+     * Equal.
+     */
+    EQ("=="),
+
+    /**
+     * Not equal.
+     */
+    NE("!="),
+
+    /**
+     * Signed less than.
+     */
+    LT("<"),
+
+    /**
+     * Signed less than or equal.
+     */
+    LE("<="),
+
+    /**
+     * Signed greater than.
+     */
+    GT(">"),
+
+    /**
+     * Signed greater than or equal.
+     */
+    GE(">="),
+
+    /**
+     * Unsigned greater than or equal ("above than or equal").
+     */
+    AE("|>=|"),
+
+    /**
+     * Unsigned less than or equal ("below than or equal").
+     */
+    BE("|<=|"),
+
+    /**
+     * Unsigned greater than ("above than").
+     */
+    AT("|>|"),
+
+    /**
+     * Unsigned less than ("below than").
+     */
+    BT("|<|");
+
+    public final String operator;
+
+    Condition(String operator) {
+        this.operator = operator;
+    }
+
+    public boolean check(int left, int right) {
+        switch (this) {
+            case EQ:
+                return left == right;
+            case NE:
+                return left != right;
+            case LT:
+                return left < right;
+            case LE:
+                return left <= right;
+            case GT:
+                return left > right;
+            case GE:
+                return left >= right;
+            case AE:
+                return UnsignedMath.aboveOrEqual(left, right);
+            case BE:
+                return UnsignedMath.belowOrEqual(left, right);
+            case AT:
+                return UnsignedMath.aboveThan(left, right);
+            case BT:
+                return UnsignedMath.belowThan(left, right);
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Given a condition and its negation, this method returns true for one of the two and false for
+     * the other one. This can be used to keep comparisons in a canonical form.
+     *
+     * @return true if this condition is considered to be the canonical form, false otherwise.
+     */
+    public boolean isCanonical() {
+        switch (this) {
+            case EQ:
+                return true;
+            case NE:
+                return false;
+            case LT:
+                return true;
+            case LE:
+                return false;
+            case GT:
+                return false;
+            case GE:
+                return false;
+            case BT:
+                return true;
+            case BE:
+                return false;
+            case AT:
+                return false;
+            case AE:
+                return false;
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Returns true if the condition needs to be mirrored to get to a canonical condition. The
+     * result of the mirroring operation might still need to be negated to achieve a canonical form.
+     */
+    public boolean canonicalMirror() {
+        switch (this) {
+            case EQ:
+                return false;
+            case NE:
+                return false;
+            case LT:
+                return false;
+            case LE:
+                return true;
+            case GT:
+                return true;
+            case GE:
+                return false;
+            case BT:
+                return false;
+            case BE:
+                return true;
+            case AT:
+                return true;
+            case AE:
+                return false;
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Returns true if the condition needs to be negated to get to a canonical condition. The result
+     * of the negation might still need to be mirrored to achieve a canonical form.
+     */
+    public boolean canonicalNegate() {
+        switch (this) {
+            case EQ:
+                return false;
+            case NE:
+                return true;
+            case LT:
+                return false;
+            case LE:
+                return true;
+            case GT:
+                return false;
+            case GE:
+                return true;
+            case BT:
+                return false;
+            case BE:
+                return true;
+            case AT:
+                return false;
+            case AE:
+                return true;
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Negate this conditional.
+     *
+     * @return the condition that represents the negation
+     */
+    public final Condition negate() {
+        switch (this) {
+            case EQ:
+                return NE;
+            case NE:
+                return EQ;
+            case LT:
+                return GE;
+            case LE:
+                return GT;
+            case GT:
+                return LE;
+            case GE:
+                return LT;
+            case BT:
+                return AE;
+            case BE:
+                return AT;
+            case AT:
+                return BE;
+            case AE:
+                return BT;
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    public boolean implies(Condition other) {
+        if (other == this) {
+            return true;
+        }
+        switch (this) {
+            case EQ:
+                return other == LE || other == GE || other == BE || other == AE;
+            case NE:
+                return false;
+            case LT:
+                return other == LE || other == NE;
+            case LE:
+                return false;
+            case GT:
+                return other == GE || other == NE;
+            case GE:
+                return false;
+            case BT:
+                return other == BE || other == NE;
+            case BE:
+                return false;
+            case AT:
+                return other == AE || other == NE;
+            case AE:
+                return false;
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Mirror this conditional (i.e. commute "a op b" to "b op' a")
+     *
+     * @return the condition representing the equivalent commuted operation
+     */
+    public final Condition mirror() {
+        switch (this) {
+            case EQ:
+                return EQ;
+            case NE:
+                return NE;
+            case LT:
+                return GT;
+            case LE:
+                return GE;
+            case GT:
+                return LT;
+            case GE:
+                return LE;
+            case BT:
+                return AT;
+            case BE:
+                return AE;
+            case AT:
+                return BT;
+            case AE:
+                return BE;
+        }
+        throw new IllegalArgumentException();
+    }
+
+    /**
+     * Returns true if this condition represents an unsigned comparison. EQ and NE are not
+     * considered to be unsigned.
+     */
+    public final boolean isUnsigned() {
+        return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE;
+    }
+
+    /**
+     * Checks if this conditional operation is commutative.
+     *
+     * @return {@code true} if this operation is commutative
+     */
+    public final boolean isCommutative() {
+        return this == EQ || this == NE;
+    }
+
+    /**
+     * Attempts to fold a comparison between two constants and return the result.
+     *
+     * @param lt the constant on the left side of the comparison
+     * @param rt the constant on the right side of the comparison
+     * @param constantReflection needed to compare constants
+     * @return {@link Boolean#TRUE} if the comparison is known to be true, {@link Boolean#FALSE} if
+     *         the comparison is known to be false
+     */
+    public boolean foldCondition(JavaConstant lt, JavaConstant rt, ConstantReflectionProvider constantReflection) {
+        assert !lt.getJavaKind().isNumericFloat() && !rt.getJavaKind().isNumericFloat();
+        return foldCondition(lt, rt, constantReflection, false);
+    }
+
+    /**
+     * Attempts to fold a comparison between two constants and return the result.
+     *
+     * @param lt the constant on the left side of the comparison
+     * @param rt the constant on the right side of the comparison
+     * @param constantReflection needed to compare constants
+     * @param unorderedIsTrue true if an undecided float comparison should result in "true"
+     * @return true if the comparison is known to be true, false if the comparison is known to be
+     *         false
+     */
+    public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+        if (lt instanceof PrimitiveConstant) {
+            PrimitiveConstant lp = (PrimitiveConstant) lt;
+            PrimitiveConstant rp = (PrimitiveConstant) rt;
+            switch (lp.getJavaKind()) {
+                case Boolean:
+                case Byte:
+                case Char:
+                case Short:
+                case Int: {
+                    int x = lp.asInt();
+                    int y = rp.asInt();
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        case AE:
+                            return UnsignedMath.aboveOrEqual(x, y);
+                        case BE:
+                            return UnsignedMath.belowOrEqual(x, y);
+                        case AT:
+                            return UnsignedMath.aboveThan(x, y);
+                        case BT:
+                            return UnsignedMath.belowThan(x, y);
+                        default:
+                            throw new GraalError("expected condition: %s", this);
+                    }
+                }
+                case Long: {
+                    long x = lp.asLong();
+                    long y = rp.asLong();
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        case AE:
+                            return UnsignedMath.aboveOrEqual(x, y);
+                        case BE:
+                            return UnsignedMath.belowOrEqual(x, y);
+                        case AT:
+                            return UnsignedMath.aboveThan(x, y);
+                        case BT:
+                            return UnsignedMath.belowThan(x, y);
+                        default:
+                            throw new GraalError("expected condition: %s", this);
+                    }
+                }
+                case Float: {
+                    float x = lp.asFloat();
+                    float y = rp.asFloat();
+                    if (Float.isNaN(x) || Float.isNaN(y)) {
+                        return unorderedIsTrue;
+                    }
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        default:
+                            throw new GraalError("expected condition: %s", this);
+                    }
+                }
+                case Double: {
+                    double x = lp.asDouble();
+                    double y = rp.asDouble();
+                    if (Double.isNaN(x) || Double.isNaN(y)) {
+                        return unorderedIsTrue;
+                    }
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        default:
+                            throw new GraalError("expected condition: %s", this);
+                    }
+                }
+                default:
+                    throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this);
+            }
+        } else {
+            Boolean equal = constantReflection.constantEquals(lt, rt);
+            if (equal == null) {
+                throw new GraalError("could not fold %s %s %s", lt, this, rt);
+            }
+            switch (this) {
+                case EQ:
+                    return equal.booleanValue();
+                case NE:
+                    return !equal.booleanValue();
+                default:
+                    throw new GraalError("expected condition: %s", this);
+            }
+        }
+    }
+
+    public Condition join(Condition other) {
+        if (other == this) {
+            return this;
+        }
+        switch (this) {
+            case EQ:
+                if (other == LE || other == GE || other == BE || other == AE) {
+                    return EQ;
+                } else {
+                    return null;
+                }
+            case NE:
+                if (other == LT || other == GT || other == BT || other == AT) {
+                    return other;
+                } else if (other == LE) {
+                    return LT;
+                } else if (other == GE) {
+                    return GT;
+                } else if (other == BE) {
+                    return BT;
+                } else if (other == AE) {
+                    return AT;
+                } else {
+                    return null;
+                }
+            case LE:
+                if (other == GE || other == EQ) {
+                    return EQ;
+                } else if (other == NE || other == LT) {
+                    return LT;
+                } else {
+                    return null;
+                }
+            case LT:
+                if (other == NE || other == LE) {
+                    return LT;
+                } else {
+                    return null;
+                }
+            case GE:
+                if (other == LE || other == EQ) {
+                    return EQ;
+                } else if (other == NE || other == GT) {
+                    return GT;
+                } else {
+                    return null;
+                }
+            case GT:
+                if (other == NE || other == GE) {
+                    return GT;
+                } else {
+                    return null;
+                }
+            case BE:
+                if (other == AE || other == EQ) {
+                    return EQ;
+                } else if (other == NE || other == BT) {
+                    return BT;
+                } else {
+                    return null;
+                }
+            case BT:
+                if (other == NE || other == BE) {
+                    return BT;
+                } else {
+                    return null;
+                }
+            case AE:
+                if (other == BE || other == EQ) {
+                    return EQ;
+                } else if (other == NE || other == AT) {
+                    return AT;
+                } else {
+                    return null;
+                }
+            case AT:
+                if (other == NE || other == AE) {
+                    return AT;
+                } else {
+                    return null;
+                }
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    public Condition meet(Condition other) {
+        if (other == this) {
+            return this;
+        }
+        switch (this) {
+            case EQ:
+                if (other == LE || other == GE || other == BE || other == AE) {
+                    return other;
+                } else if (other == LT) {
+                    return LE;
+                } else if (other == GT) {
+                    return GE;
+                } else if (other == BT) {
+                    return BE;
+                } else if (other == AT) {
+                    return AE;
+                } else {
+                    return null;
+                }
+            case NE:
+                if (other == LT || other == GT || other == BT || other == AT) {
+                    return NE;
+                } else {
+                    return null;
+                }
+            case LE:
+                if (other == EQ || other == LT) {
+                    return LE;
+                } else {
+                    return null;
+                }
+            case LT:
+                if (other == EQ || other == LE) {
+                    return LE;
+                } else if (other == NE || other == GT) {
+                    return NE;
+                } else {
+                    return null;
+                }
+            case GE:
+                if (other == EQ || other == GT) {
+                    return GE;
+                } else {
+                    return null;
+                }
+            case GT:
+                if (other == EQ || other == GE) {
+                    return GE;
+                } else if (other == NE || other == LT) {
+                    return NE;
+                } else {
+                    return null;
+                }
+            case BE:
+                if (other == EQ || other == BT) {
+                    return BE;
+                } else {
+                    return null;
+                }
+            case BT:
+                if (other == EQ || other == BE) {
+                    return BE;
+                } else if (other == NE || other == AT) {
+                    return NE;
+                } else {
+                    return null;
+                }
+            case AE:
+                if (other == EQ || other == AT) {
+                    return AE;
+                } else {
+                    return null;
+                }
+            case AT:
+                if (other == EQ || other == AE) {
+                    return AE;
+                } else if (other == NE || other == BT) {
+                    return NE;
+                } else {
+                    return null;
+                }
+        }
+        throw new IllegalArgumentException(this.toString());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java
new file mode 100644
index 0000000..6c4bd85
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.calc;
+
+import org.graalvm.compiler.debug.GraalError;
+
+public enum FloatConvert {
+    F2I,
+    D2I,
+    F2L,
+    D2L,
+    I2F,
+    L2F,
+    D2F,
+    I2D,
+    L2D,
+    F2D;
+
+    public FloatConvert reverse() {
+        switch (this) {
+            case D2F:
+                return F2D;
+            case D2I:
+                return I2D;
+            case D2L:
+                return L2D;
+            case F2D:
+                return D2F;
+            case F2I:
+                return I2F;
+            case F2L:
+                return L2F;
+            case I2D:
+                return D2I;
+            case I2F:
+                return F2I;
+            case L2D:
+                return D2L;
+            case L2F:
+                return F2L;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/UnsignedMath.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/UnsignedMath.java
new file mode 100644
index 0000000..663dfb6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/UnsignedMath.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.calc;
+
+//JaCoCo Exclude
+
+/**
+ * Utilities for unsigned comparisons. All methods have correct, but slow, standard Java
+ * implementations so that they can be used with compilers not supporting the intrinsics.
+ */
+public class UnsignedMath {
+
+    /**
+     * Unsigned comparison aboveThan for two numbers.
+     */
+    public static boolean aboveThan(int a, int b) {
+        return Integer.compareUnsigned(a, b) > 0;
+    }
+
+    /**
+     * Unsigned comparison aboveOrEqual for two numbers.
+     */
+    public static boolean aboveOrEqual(int a, int b) {
+        return Integer.compareUnsigned(a, b) >= 0;
+    }
+
+    /**
+     * Unsigned comparison belowThan for two numbers.
+     */
+    public static boolean belowThan(int a, int b) {
+        return Integer.compareUnsigned(a, b) < 0;
+    }
+
+    /**
+     * Unsigned comparison belowOrEqual for two numbers.
+     */
+    public static boolean belowOrEqual(int a, int b) {
+        return Integer.compareUnsigned(a, b) <= 0;
+    }
+
+    /**
+     * Unsigned comparison aboveThan for two numbers.
+     */
+    public static boolean aboveThan(long a, long b) {
+        return Long.compareUnsigned(a, b) > 0;
+    }
+
+    /**
+     * Unsigned comparison aboveOrEqual for two numbers.
+     */
+    public static boolean aboveOrEqual(long a, long b) {
+        return Long.compareUnsigned(a, b) >= 0;
+    }
+
+    /**
+     * Unsigned comparison belowThan for two numbers.
+     */
+    public static boolean belowThan(long a, long b) {
+        return Long.compareUnsigned(a, b) < 0;
+    }
+
+    /**
+     * Unsigned comparison belowOrEqual for two numbers.
+     */
+    public static boolean belowOrEqual(long a, long b) {
+        return Long.compareUnsigned(a, b) <= 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java
new file mode 100644
index 0000000..a1d2661
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
+
+    protected int id;
+    protected int domDepth;
+
+    protected T[] predecessors;
+    protected T[] successors;
+
+    private T dominator;
+    private List<T> dominated;
+    private int domNumber;
+    private int maxChildDomNumber;
+
+    private boolean align;
+    private int linearScanNumber;
+
+    protected AbstractBlockBase() {
+        this.id = AbstractControlFlowGraph.BLOCK_ID_INITIAL;
+        this.linearScanNumber = -1;
+        this.domNumber = -1;
+        this.maxChildDomNumber = -1;
+    }
+
+    public void setDominatorNumber(int domNumber) {
+        this.domNumber = domNumber;
+    }
+
+    public void setMaxChildDomNumber(int maxChildDomNumber) {
+        this.maxChildDomNumber = maxChildDomNumber;
+    }
+
+    public int getDominatorNumber() {
+        return domNumber;
+    }
+
+    public int getMaxChildDominatorNumber() {
+        return this.maxChildDomNumber;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public T[] getPredecessors() {
+        return predecessors;
+    }
+
+    public void setPredecessors(T[] predecessors) {
+        this.predecessors = predecessors;
+    }
+
+    public T[] getSuccessors() {
+        return successors;
+    }
+
+    public void setSuccessors(T[] successors) {
+        this.successors = successors;
+    }
+
+    public T getDominator() {
+        return dominator;
+    }
+
+    public void setDominator(T dominator) {
+        this.dominator = dominator;
+        this.domDepth = dominator.domDepth + 1;
+    }
+
+    public int getDominatorDepth() {
+        return domDepth;
+    }
+
+    public List<T> getDominated() {
+        if (dominated == null) {
+            return Collections.emptyList();
+        }
+        return dominated;
+    }
+
+    public void setDominated(List<T> blocks) {
+        dominated = blocks;
+    }
+
+    @Override
+    public String toString() {
+        return "B" + id;
+    }
+
+    public int getPredecessorCount() {
+        return getPredecessors().length;
+    }
+
+    public int getSuccessorCount() {
+        return getSuccessors().length;
+    }
+
+    public int getLinearScanNumber() {
+        return linearScanNumber;
+    }
+
+    public void setLinearScanNumber(int linearScanNumber) {
+        this.linearScanNumber = linearScanNumber;
+    }
+
+    public boolean isAligned() {
+        return align;
+    }
+
+    public void setAlign(boolean align) {
+        this.align = align;
+    }
+
+    public abstract boolean isExceptionEntry();
+
+    public abstract Loop<T> getLoop();
+
+    public abstract int getLoopDepth();
+
+    public abstract void delete();
+
+    public abstract boolean isLoopEnd();
+
+    public abstract boolean isLoopHeader();
+
+    public abstract T getPostdominator();
+
+    public abstract double probability();
+
+    public abstract T getDominator(int distance);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java
new file mode 100644
index 0000000..ccc46e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.Collection;
+
+public interface AbstractControlFlowGraph<T extends AbstractBlockBase<T>> {
+
+    int BLOCK_ID_INITIAL = -1;
+    int BLOCK_ID_VISITED = -2;
+
+    /**
+     * Returns the list blocks contained in this control flow graph.
+     *
+     * It is {@linkplain CFGVerifier guaranteed} that the blocks are numbered and ordered according
+     * to a reverse post order traversal of the control flow graph.
+     *
+     * @see CFGVerifier
+     */
+    T[] getBlocks();
+
+    Collection<Loop<T>> getLoops();
+
+    T getStartBlock();
+
+    /**
+     * True if block {@code a} is dominated by block {@code b}.
+     */
+    static boolean isDominatedBy(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        int domNumberA = a.getDominatorNumber();
+        int domNumberB = b.getDominatorNumber();
+        return domNumberA >= domNumberB && domNumberA <= b.getMaxChildDominatorNumber();
+    }
+
+    /**
+     * True if block {@code a} dominates block {@code b} and {@code a} is not identical block to
+     * {@code b}.
+     */
+    static boolean strictlyDominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        return a != b && dominates(a, b);
+    }
+
+    /**
+     * True if block {@code a} dominates block {@code b}.
+     */
+    static boolean dominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        assert a != null && b != null;
+        return isDominatedBy(b, a);
+    }
+
+    /**
+     * Calculates the common dominator of two blocks.
+     *
+     * Note that this algorithm makes use of special properties regarding the numbering of blocks.
+     *
+     * @see #getBlocks()
+     * @see CFGVerifier
+     */
+    static AbstractBlockBase<?> commonDominator(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        if (a == null) {
+            return b;
+        } else if (b == null) {
+            return a;
+        } else {
+            int aDomDepth = a.getDominatorDepth();
+            int bDomDepth = b.getDominatorDepth();
+            AbstractBlockBase<?> aTemp;
+            AbstractBlockBase<?> bTemp;
+            if (aDomDepth > bDomDepth) {
+                aTemp = a;
+                bTemp = b;
+            } else {
+                aTemp = b;
+                bTemp = a;
+            }
+            return commonDominatorHelper(aTemp, bTemp);
+        }
+    }
+
+    static AbstractBlockBase<?> commonDominatorHelper(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        int domNumberA = a.getDominatorNumber();
+        AbstractBlockBase<?> result = b;
+        while (domNumberA < result.getDominatorNumber()) {
+            result = result.getDominator();
+        }
+        while (domNumberA > result.getMaxChildDominatorNumber()) {
+            result = result.getDominator();
+        }
+        return result;
+    }
+
+    /**
+     * @see AbstractControlFlowGraph#commonDominator(AbstractBlockBase, AbstractBlockBase)
+     */
+    @SuppressWarnings("unchecked")
+    static <T extends AbstractBlockBase<T>> T commonDominatorTyped(T a, T b) {
+        return (T) commonDominator(a, b);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/BlockMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/BlockMap.java
new file mode 100644
index 0000000..e354313
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/BlockMap.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+public class BlockMap<T> {
+
+    private final T[] data;
+
+    @SuppressWarnings("unchecked")
+    public BlockMap(AbstractControlFlowGraph<?> cfg) {
+        data = (T[]) new Object[cfg.getBlocks().length];
+    }
+
+    public T get(AbstractBlockBase<?> block) {
+        return data[block.getId()];
+    }
+
+    public void put(AbstractBlockBase<?> block, T value) {
+        data[block.getId()] = value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/CFGVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/CFGVerifier.java
new file mode 100644
index 0000000..ec9a55f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/CFGVerifier.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+
+public class CFGVerifier {
+
+    public static <T extends AbstractBlockBase<T>, C extends AbstractControlFlowGraph<T>> boolean verify(C cfg) {
+        for (T block : cfg.getBlocks()) {
+            assert block.getId() >= 0;
+            assert cfg.getBlocks()[block.getId()] == block;
+
+            for (T pred : block.getPredecessors()) {
+                assert Arrays.asList(pred.getSuccessors()).contains(block);
+                assert pred.getId() < block.getId() || pred.isLoopEnd();
+            }
+
+            for (T sux : block.getSuccessors()) {
+                assert Arrays.asList(sux.getPredecessors()).contains(block);
+                assert sux.getId() > block.getId() || sux.isLoopHeader();
+            }
+
+            if (block.getDominator() != null) {
+                assert block.getDominator().getId() < block.getId();
+                assert block.getDominator().getDominated().contains(block);
+            }
+            for (T dominated : block.getDominated()) {
+                assert dominated.getId() > block.getId();
+                assert dominated.getDominator() == block;
+            }
+
+            T postDominatorBlock = block.getPostdominator();
+            if (postDominatorBlock != null) {
+                assert block.getSuccessorCount() > 0 : "block has post-dominator block, but no successors";
+
+                BlockMap<Boolean> visitedBlocks = new BlockMap<>(cfg);
+                visitedBlocks.put(block, true);
+
+                Deque<T> stack = new ArrayDeque<>();
+                for (T sux : block.getSuccessors()) {
+                    visitedBlocks.put(sux, true);
+                    stack.push(sux);
+                }
+
+                while (stack.size() > 0) {
+                    T tos = stack.pop();
+                    assert tos.getId() <= postDominatorBlock.getId();
+                    if (tos == postDominatorBlock) {
+                        continue; // found a valid path
+                    }
+                    assert tos.getSuccessorCount() > 0 : "no path found";
+
+                    for (T sux : tos.getSuccessors()) {
+                        if (visitedBlocks.get(sux) == null) {
+                            visitedBlocks.put(sux, true);
+                            stack.push(sux);
+                        }
+                    }
+                }
+            }
+
+            assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().getHeader() == block;
+        }
+
+        if (cfg.getLoops() != null) {
+            for (Loop<T> loop : cfg.getLoops()) {
+                assert loop.getHeader().isLoopHeader();
+
+                for (T block : loop.getBlocks()) {
+                    assert block.getId() >= loop.getHeader().getId();
+
+                    Loop<?> blockLoop = block.getLoop();
+                    while (blockLoop != loop) {
+                        assert blockLoop != null;
+                        blockLoop = blockLoop.getParent();
+                    }
+
+                    if (!(block.isLoopHeader() && block.getLoop() == loop)) {
+                        for (T pred : block.getPredecessors()) {
+                            if (!loop.getBlocks().contains(pred)) {
+                                assert false : "Loop " + loop + " does not contain " + pred;
+                                return false;
+                            }
+                        }
+                    }
+                }
+
+                for (T block : loop.getExits()) {
+                    assert block.getId() >= loop.getHeader().getId();
+
+                    Loop<?> blockLoop = block.getLoop();
+                    while (blockLoop != null) {
+                        blockLoop = blockLoop.getParent();
+                        assert blockLoop != loop;
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/DominatorOptimizationProblem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/DominatorOptimizationProblem.java
new file mode 100644
index 0000000..1492161
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/DominatorOptimizationProblem.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.EnumMap;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * This class represents a dominator tree problem, i.e. a problem which can be solved by traversing
+ * the dominator (sub-)tree.
+ *
+ * @param <E> An enum that describes the flags that can be associated with a block.
+ * @param <C> An arbitrary cost type that is associated with a block. It is intended to carry
+ *            information needed to calculate the solution. Note that {@code C} should not contain
+ *            boolean flags. Use an enum entry in {@code E} instead.
+ */
+public abstract class DominatorOptimizationProblem<E extends Enum<E>, C> {
+
+    private AbstractBlockBase<?>[] blocks;
+    private EnumMap<E, BitSet> flags;
+    private BlockMap<C> costs;
+
+    protected DominatorOptimizationProblem(Class<E> flagType, AbstractControlFlowGraph<?> cfg) {
+        this.blocks = cfg.getBlocks();
+        flags = new EnumMap<>(flagType);
+        costs = new BlockMap<>(cfg);
+        assert verify(blocks);
+    }
+
+    private static boolean verify(AbstractBlockBase<?>[] blocks) {
+        for (int i = 0; i < blocks.length; i++) {
+            AbstractBlockBase<?> block = blocks[i];
+            if (i != block.getId()) {
+                assert false : String.format("Id index mismatch @ %d vs. %s.getId()==%d", i, block, block.getId());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public final AbstractBlockBase<?>[] getBlocks() {
+        return blocks;
+    }
+
+    public final AbstractBlockBase<?> getBlockForId(int id) {
+        AbstractBlockBase<?> block = blocks[id];
+        assert block.getId() == id : "wrong block-to-id mapping";
+        return block;
+    }
+
+    /**
+     * Sets a flag for a block.
+     */
+    public final void set(E flag, AbstractBlockBase<?> block) {
+        BitSet bitSet = flags.get(flag);
+        if (bitSet == null) {
+            bitSet = new BitSet(blocks.length);
+            flags.put(flag, bitSet);
+        }
+        bitSet.set(block.getId());
+    }
+
+    /**
+     * Checks whether a flag is set for a block.
+     */
+    public final boolean get(E flag, AbstractBlockBase<?> block) {
+        BitSet bitSet = flags.get(flag);
+        return bitSet == null ? false : bitSet.get(block.getId());
+    }
+
+    /**
+     * Returns a {@linkplain Stream} of blocks for which {@code flag} is set.
+     */
+    public final Stream<? extends AbstractBlockBase<?>> stream(E flag) {
+        return Arrays.asList(getBlocks()).stream().filter(block -> get(flag, block));
+    }
+
+    /**
+     * Returns the cost object associated with {@code block}. Might return {@code null} if not set.
+     */
+    public final C getCost(AbstractBlockBase<?> block) {
+        C cost = costs.get(block);
+        return cost;
+    }
+
+    /**
+     * Sets the cost for a {@code block}.
+     */
+    public final void setCost(AbstractBlockBase<?> block, C cost) {
+        costs.put(block, cost);
+    }
+
+    /**
+     * Sets {@code flag} for all blocks along the dominator path from {@code block} to the root
+     * until a block it finds a block where {@code flag} is already set.
+     */
+    public final void setDominatorPath(E flag, AbstractBlockBase<?> block) {
+        BitSet bitSet = flags.get(flag);
+        if (bitSet == null) {
+            bitSet = new BitSet(blocks.length);
+            flags.put(flag, bitSet);
+        }
+        for (AbstractBlockBase<?> b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) {
+            // mark block
+            bitSet.set(b.getId());
+        }
+    }
+
+    /**
+     * Returns a {@link Stream} of flags associated with {@code block}.
+     */
+    public final Stream<E> getFlagsForBlock(AbstractBlockBase<?> block) {
+        return getFlags().stream().filter(flag -> get(flag, block));
+    }
+
+    /**
+     * Returns the {@link Set} of flags that can be set for this
+     * {@linkplain DominatorOptimizationProblem problem}.
+     */
+    public final Set<E> getFlags() {
+        return flags.keySet();
+    }
+
+    /**
+     * Returns the name of a flag.
+     */
+    public String getName(E flag) {
+        return flag.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java
new file mode 100644
index 0000000..41d884a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class Loop<T extends AbstractBlockBase<T>> {
+
+    private final Loop<T> parent;
+    private final List<Loop<T>> children;
+
+    private final int depth;
+    private final int index;
+    private final T header;
+    private final List<T> blocks;
+    private final List<T> exits;
+
+    protected Loop(Loop<T> parent, int index, T header) {
+        this.parent = parent;
+        if (parent != null) {
+            this.depth = parent.getDepth() + 1;
+            parent.getChildren().add(this);
+        } else {
+            this.depth = 1;
+        }
+        this.index = index;
+        this.header = header;
+        this.blocks = new ArrayList<>();
+        this.children = new ArrayList<>();
+        this.exits = new ArrayList<>();
+    }
+
+    public abstract long numBackedges();
+
+    @Override
+    public String toString() {
+        return "loop " + index + " depth " + getDepth() + (parent != null ? " outer " + parent.index : "");
+    }
+
+    public Loop<T> getParent() {
+        return parent;
+    }
+
+    public List<Loop<T>> getChildren() {
+        return children;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public T getHeader() {
+        return header;
+    }
+
+    public List<T> getBlocks() {
+        return blocks;
+    }
+
+    public List<T> getExits() {
+        return exits;
+    }
+
+    /**
+     * Determines if one loop is a transitive parent of another loop.
+     *
+     * @param childLoop The loop for which parentLoop might be a transitive parent loop.
+     * @param parentLoop The loop which might be a transitive parent loop of child loop.
+     * @return {@code true} if parentLoop is a (transitive) parent loop of childLoop, {@code false}
+     *         otherwise
+     */
+    public static <T extends AbstractBlockBase<T>> boolean transitiveParentLoop(Loop<T> childLoop, Loop<T> parentLoop) {
+        Loop<T> curr = childLoop;
+        while (curr != null) {
+            if (curr == parentLoop) {
+                return true;
+            }
+            curr = curr.getParent();
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableCFG.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableCFG.java
new file mode 100644
index 0000000..165bc7d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableCFG.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Represents a control-flow graph where each node can be annotated with arbitrary property pairs of
+ * the form ({@linkplain String name}, {@linkplain String value}).
+ */
+public interface PrintableCFG {
+
+    AbstractBlockBase<?>[] getBlocks();
+
+    /**
+     * Applies {@code action} to all extra property pairs (name, value) of {@code block}.
+     *
+     * @param block a block from {@link #getBlocks()}.
+     * @param action a {@link BiConsumer consumer}.
+     */
+    default void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
+        // no extra properties per default
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableDominatorOptimizationProblem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableDominatorOptimizationProblem.java
new file mode 100644
index 0000000..9b9ee98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PrintableDominatorOptimizationProblem.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.function.BiConsumer;
+
+/**
+ * A {@linkplain PrintableCFG printable} {@link DominatorOptimizationProblem}.
+ */
+public abstract class PrintableDominatorOptimizationProblem<E extends Enum<E>, C extends PropertyConsumable> extends DominatorOptimizationProblem<E, C> implements PrintableCFG {
+
+    protected PrintableDominatorOptimizationProblem(Class<E> keyType, AbstractControlFlowGraph<?> cfg) {
+        super(keyType, cfg);
+    }
+
+    @Override
+    public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
+        // for each flag
+        getFlags().forEach(flag -> ((BiConsumer<String, Boolean>) (name, value) -> action.accept(name, value ? "true" : "false")).accept(getName(flag), get(flag, block)));
+        // for each property
+        C cost = getCost(block);
+        if (cost != null) {
+            cost.forEachProperty((name, value) -> action.accept(name, value));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PropertyConsumable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PropertyConsumable.java
new file mode 100644
index 0000000..b6bbffa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/PropertyConsumable.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.cfg;
+
+import java.util.function.BiConsumer;
+
+public interface PropertyConsumable {
+
+    void forEachProperty(BiConsumer<String, String> action);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java
new file mode 100644
index 0000000..5c6299d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * A set of providers which are required for LIR and/or code generation. Some may not be present
+ * (i.e., null).
+ */
+public interface CodeGenProviders {
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    ConstantReflectionProvider getConstantReflection();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java
new file mode 100644
index 0000000..2cc96bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ConstantFieldProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * Implements the logic that decides whether a field read should be constant folded.
+ */
+public interface ConstantFieldProvider {
+
+    public interface ConstantFieldTool<T> {
+
+        JavaConstant readValue();
+
+        JavaConstant getReceiver();
+
+        T foldConstant(JavaConstant ret);
+
+        T foldStableArray(JavaConstant ret, int stableDimensions, boolean isDefaultStable);
+    }
+
+    /**
+     * Decide whether a read from the {@code field} should be constant folded. This should return
+     * {@link ConstantFieldTool#foldConstant} or {@link ConstantFieldTool#foldStableArray} if the
+     * read should be constant folded, or {@code null} otherwise.
+     */
+    <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallDescriptor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallDescriptor.java
new file mode 100644
index 0000000..a300e09
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallDescriptor.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import java.util.Arrays;
+
+/**
+ * The name and signature of a foreign call. A foreign call differs from a normal compiled Java call
+ * in at least one of these aspects:
+ * <ul>
+ * <li>The call is to C/C++/assembler code.</li>
+ * <li>The call uses different conventions for passing parameters or returning values.</li>
+ * <li>The callee has different register saving semantics. For example, the callee may save all
+ * registers (apart from some specified temporaries) in which case the register allocator doesn't
+ * not need to spill all live registers around the call site.</li>
+ * <li>The call does not occur at an INVOKE* bytecode. Such a call could be transformed into a
+ * standard Java call if the foreign routine is a normal Java method and the runtime supports
+ * linking Java calls at arbitrary bytecodes.</li>
+ * </ul>
+ */
+public class ForeignCallDescriptor {
+
+    private final String name;
+    private final Class<?> resultType;
+    private final Class<?>[] argumentTypes;
+
+    public ForeignCallDescriptor(String name, Class<?> resultType, Class<?>... argumentTypes) {
+        this.name = name;
+        this.resultType = resultType;
+        this.argumentTypes = argumentTypes;
+    }
+
+    /**
+     * Gets the name of this foreign call.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the return type of this foreign call.
+     */
+    public Class<?> getResultType() {
+        return resultType;
+    }
+
+    /**
+     * Gets the argument types of this foreign call.
+     */
+    public Class<?>[] getArgumentTypes() {
+        return argumentTypes.clone();
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof ForeignCallDescriptor) {
+            ForeignCallDescriptor other = (ForeignCallDescriptor) obj;
+            return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(name).append('(');
+        String sep = "";
+        for (Class<?> arg : argumentTypes) {
+            sb.append(sep).append(arg.getSimpleName());
+            sep = ",";
+        }
+        return sb.append(')').append(resultType.getSimpleName()).toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallLinkage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallLinkage.java
new file mode 100644
index 0000000..8ce182e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallLinkage.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * The runtime specific details of a {@linkplain ForeignCallDescriptor foreign} call.
+ */
+public interface ForeignCallLinkage extends InvokeTarget {
+
+    /**
+     * Gets the details of where parameters are passed and value(s) are returned from the caller's
+     * perspective.
+     */
+    CallingConvention getOutgoingCallingConvention();
+
+    /**
+     * Gets the details of where parameters are passed and value(s) are returned from the callee's
+     * perspective.
+     */
+    CallingConvention getIncomingCallingConvention();
+
+    /**
+     * Returns the maximum absolute offset of a PC relative call to this stub from any position in
+     * the code cache or -1 when not applicable. Intended for determining the required size of
+     * address/offset fields.
+     */
+    long getMaxCallTargetOffset();
+
+    ForeignCallDescriptor getDescriptor();
+
+    /**
+     * Gets the values used/killed by this foreign call.
+     */
+    Value[] getTemporaries();
+
+    /**
+     * Determines if the foreign call target destroys all registers.
+     *
+     * @return {@code true} if the register allocator must save all live registers around a call to
+     *         this target
+     */
+    boolean destroysRegisters();
+
+    /**
+     * Determines if debug info needs to be associated with this call. Debug info is required if the
+     * function can raise an exception, try to lock, trigger GC or do anything else that requires
+     * the VM to be able to inspect the thread's execution state.
+     */
+    boolean needsDebugInfo();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java
new file mode 100644
index 0000000..58890ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+import jdk.vm.ci.code.ValueKindFactory;
+
+/**
+ * Details about a set of supported {@link ForeignCallDescriptor foreign calls}.
+ */
+public interface ForeignCallsProvider extends ValueKindFactory<LIRKind> {
+
+    /**
+     * Determines if a given foreign call is side-effect free. Deoptimization cannot return
+     * execution to a point before a foreign call that has a side effect.
+     */
+    boolean isReexecutable(ForeignCallDescriptor descriptor);
+
+    /**
+     * Gets the set of memory locations killed by a given foreign call. Returning the special value
+     * {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning
+     * any empty array denotes that the call does not kill any memory locations.
+     */
+    LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor);
+
+    /**
+     * Determines if deoptimization can occur during a given foreign call.
+     */
+    boolean canDeoptimize(ForeignCallDescriptor descriptor);
+
+    /**
+     * Identifies foreign calls which are guaranteed to include a safepoint check.
+     */
+    boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor);
+
+    /**
+     * Gets the linkage for a foreign call.
+     */
+    ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java
new file mode 100644
index 0000000..ae40986
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Utility for default constant folding semantics for Java fields.
+ */
+public abstract class JavaConstantFieldProvider implements ConstantFieldProvider {
+
+    static class Options {
+        @Option(help = "Determines whether to treat final fields with default values as constant.")//
+        public static final OptionValue<Boolean> TrustFinalDefaultFields = new OptionValue<>(true);
+    }
+
+    protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) {
+        try {
+            this.stringValueField = metaAccess.lookupJavaField(String.class.getDeclaredField("value"));
+            this.stringHashField = metaAccess.lookupJavaField(String.class.getDeclaredField("hash"));
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new GraalError(e);
+        }
+    }
+
+    @Override
+    public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) {
+        if (isStableField(field, tool)) {
+            JavaConstant value = tool.readValue();
+            if (value != null && isStableFieldValueConstant(field, value, tool)) {
+                return foldStableArray(value, field, tool);
+            }
+        }
+        if (isFinalField(field, tool)) {
+            JavaConstant value = tool.readValue();
+            if (value != null && isFinalFieldValueConstant(field, value, tool)) {
+                return tool.foldConstant(value);
+            }
+        }
+        return null;
+    }
+
+    protected <T> T foldStableArray(JavaConstant value, ResolvedJavaField field, ConstantFieldTool<T> tool) {
+        return tool.foldStableArray(value, getArrayDimension(field.getType()), isDefaultStableField(field, tool));
+    }
+
+    private static int getArrayDimension(JavaType type) {
+        int dimensions = 0;
+        JavaType componentType = type;
+        while ((componentType = componentType.getComponentType()) != null) {
+            dimensions++;
+        }
+        return dimensions;
+    }
+
+    private static boolean isArray(ResolvedJavaField field) {
+        JavaType fieldType = field.getType();
+        return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray();
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
+        return !value.isDefaultForKind();
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
+        return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue();
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool<?> tool) {
+        if (isSyntheticEnumSwitchMap(field)) {
+            return true;
+        }
+        if (isWellKnownImplicitStableField(field)) {
+            return true;
+        }
+        if (field == stringHashField) {
+            return true;
+        }
+        return false;
+    }
+
+    protected boolean isDefaultStableField(ResolvedJavaField field, ConstantFieldTool<?> tool) {
+        assert isStableField(field, tool);
+        if (isSyntheticEnumSwitchMap(field)) {
+            return true;
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean isFinalField(ResolvedJavaField field, ConstantFieldTool<?> tool) {
+        return field.isFinal();
+    }
+
+    protected boolean isSyntheticEnumSwitchMap(ResolvedJavaField field) {
+        if (field.isSynthetic() && field.isStatic() && isArray(field)) {
+            String name = field.getName();
+            if (field.isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) {
+                // generated int[] field for EnumClass::values()
+                return true;
+            } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) {
+                // javac and ecj generate a static field in an inner class for a switch on an enum
+                // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private final ResolvedJavaField stringValueField;
+    private final ResolvedJavaField stringHashField;
+
+    protected boolean isWellKnownImplicitStableField(ResolvedJavaField field) {
+        return field.equals(stringValueField);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java
new file mode 100644
index 0000000..9a40154
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import org.graalvm.compiler.core.common.LIRKind;
+
+/**
+ * This interface can be used to access platform and VM specific kinds.
+ */
+public interface LIRKindTool {
+
+    /**
+     * Get an architecture specific integer kind of a certain size.
+     */
+    LIRKind getIntegerKind(int bits);
+
+    /**
+     * Get an architecture specific floating point kind of a certain size.
+     */
+    LIRKind getFloatingKind(int bits);
+
+    /**
+     * Get the architecture specific kind used to represent Java objects.
+     */
+    LIRKind getObjectKind();
+
+    /**
+     * Get the architecture specific kind pointer-sized integer kind.
+     */
+    LIRKind getWordKind();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java
new file mode 100644
index 0000000..b84f218
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import java.util.AbstractList;
+import java.util.Objects;
+import java.util.RandomAccess;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Type describing all pointers to Java objects.
+ */
+public abstract class AbstractObjectStamp extends AbstractPointerStamp {
+
+    private final ResolvedJavaType type;
+    private final boolean exactType;
+
+    protected AbstractObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        super(nonNull, alwaysNull);
+        this.type = type;
+        this.exactType = exactType;
+    }
+
+    protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull);
+
+    @Override
+    protected final AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        return copyWith(type, exactType, newNonNull, newAlwaysNull);
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return copyWith(null, false, false, false);
+    }
+
+    @Override
+    public Stamp empty() {
+        return copyWith(null, true, true, false);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        JavaConstant jc = (JavaConstant) c;
+        ResolvedJavaType constType = jc.isNull() ? null : meta.lookupJavaType(jc);
+        return copyWith(constType, jc.isNonNull(), jc.isNonNull(), jc.isNull());
+    }
+
+    @Override
+    public boolean hasValues() {
+        return !exactType || (type != null && (isConcreteType(type)));
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        return JavaKind.Object;
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        if (type != null) {
+            return type;
+        }
+        return metaAccess.lookupJavaType(Object.class);
+    }
+
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    public boolean isExactType() {
+        return exactType && type != null;
+    }
+
+    protected void appendString(StringBuilder str) {
+        if (this.isEmpty()) {
+            str.append(" empty");
+        } else {
+            str.append(nonNull() ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull() ? " NULL" : "");
+        }
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (this == otherStamp) {
+            return this;
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) otherStamp;
+        if (isEmpty()) {
+            return other;
+        } else if (other.isEmpty()) {
+            return this;
+        }
+        ResolvedJavaType meetType;
+        boolean meetExactType;
+        boolean meetNonNull;
+        boolean meetAlwaysNull;
+        if (other.alwaysNull()) {
+            meetType = type();
+            meetExactType = exactType;
+            meetNonNull = false;
+            meetAlwaysNull = alwaysNull();
+        } else if (alwaysNull()) {
+            meetType = other.type();
+            meetExactType = other.exactType;
+            meetNonNull = false;
+            meetAlwaysNull = other.alwaysNull();
+        } else {
+            meetType = meetTypes(type(), other.type());
+            meetExactType = exactType && other.exactType;
+            if (meetExactType && type != null && other.type != null) {
+                // meeting two valid exact types may result in a non-exact type
+                meetExactType = Objects.equals(meetType, type) && Objects.equals(meetType, other.type);
+            }
+            meetNonNull = nonNull() && other.nonNull();
+            meetAlwaysNull = false;
+        }
+
+        if (Objects.equals(meetType, type) && meetExactType == exactType && meetNonNull == nonNull() && meetAlwaysNull == alwaysNull()) {
+            return this;
+        } else if (Objects.equals(meetType, other.type) && meetExactType == other.exactType && meetNonNull == other.nonNull() && meetAlwaysNull == other.alwaysNull()) {
+            return other;
+        } else {
+            return copyWith(meetType, meetExactType, meetNonNull, meetAlwaysNull);
+        }
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        return join0(otherStamp, false);
+    }
+
+    /**
+     * Returns the stamp representing the type of this stamp after a cast to the type represented by
+     * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case
+     * where both types are not obviously related, the cast operation will prefer the type of the
+     * {@code to} stamp. This is necessary as long as ObjectStamps are not able to accurately
+     * represent intersection types.
+     *
+     * For example when joining the {@link RandomAccess} type with the {@link AbstractList} type,
+     * without intersection types, this would result in the most generic type ({@link Object} ). For
+     * this reason, in some cases a {@code castTo} operation is preferable in order to keep at least
+     * the {@link AbstractList} type.
+     *
+     * @param other the stamp this stamp should be casted to
+     * @return the new improved stamp or {@code null} if this stamp cannot be improved
+     */
+    @Override
+    public Stamp improveWith(Stamp other) {
+        return join0(other, true);
+    }
+
+    private Stamp join0(Stamp otherStamp, boolean improve) {
+        if (this == otherStamp) {
+            return this;
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) otherStamp;
+        if (isEmpty()) {
+            return this;
+        } else if (other.isEmpty()) {
+            return other;
+        }
+
+        ResolvedJavaType joinType;
+        boolean joinAlwaysNull = alwaysNull() || other.alwaysNull();
+        boolean joinNonNull = nonNull() || other.nonNull();
+        boolean joinExactType = exactType || other.exactType;
+        if (Objects.equals(type, other.type)) {
+            joinType = type;
+        } else if (type == null && other.type == null) {
+            joinType = null;
+        } else if (type == null) {
+            joinType = other.type;
+        } else if (other.type == null) {
+            joinType = type;
+        } else {
+            // both types are != null and different
+            if (type.isAssignableFrom(other.type)) {
+                joinType = other.type;
+                if (exactType) {
+                    joinAlwaysNull = true;
+                }
+            } else if (other.type.isAssignableFrom(type)) {
+                joinType = type;
+                if (other.exactType) {
+                    joinAlwaysNull = true;
+                }
+            } else {
+                if (improve) {
+                    joinType = type;
+                    joinExactType = exactType;
+                } else {
+                    joinType = null;
+                }
+
+                if (joinExactType || (!isInterfaceOrArrayOfInterface(type) && !isInterfaceOrArrayOfInterface(other.type))) {
+                    joinAlwaysNull = true;
+                }
+            }
+        }
+        if (joinAlwaysNull) {
+            joinType = null;
+            joinExactType = false;
+        }
+        if (joinExactType && joinType == null) {
+            return empty();
+        }
+        if (joinAlwaysNull && joinNonNull) {
+            return empty();
+        } else if (joinExactType && !isConcreteType(joinType)) {
+            return empty();
+        }
+        if (Objects.equals(joinType, type) && joinExactType == exactType && joinNonNull == nonNull() && joinAlwaysNull == alwaysNull()) {
+            return this;
+        } else if (Objects.equals(joinType, other.type) && joinExactType == other.exactType && joinNonNull == other.nonNull() && joinAlwaysNull == other.alwaysNull()) {
+            return other;
+        } else {
+            return copyWith(joinType, joinExactType, joinNonNull, joinAlwaysNull);
+        }
+    }
+
+    private static boolean isInterfaceOrArrayOfInterface(ResolvedJavaType t) {
+        return t.isInterface() || (t.isArray() && t.getElementalType().isInterface());
+    }
+
+    public static boolean isConcreteType(ResolvedJavaType type) {
+        return !(type.isAbstract() && !type.isArray());
+    }
+
+    private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) {
+        if (Objects.equals(a, b)) {
+            return a;
+        } else if (a == null || b == null) {
+            return null;
+        } else {
+            // The `meetTypes` operation must be commutative. One way to achieve this is to totally
+            // order the types and always call `meetOrderedNonNullTypes` in the same order. We
+            // establish the order by first comparing the hash-codes for performance reasons, and
+            // then comparing the internal names of the types.
+            int hashA = a.getName().hashCode();
+            int hashB = b.getName().hashCode();
+            if (hashA < hashB) {
+                return meetOrderedNonNullTypes(a, b);
+            } else if (hashB < hashA) {
+                return meetOrderedNonNullTypes(b, a);
+            } else {
+                int diff = a.getName().compareTo(b.getName());
+                if (diff <= 0) {
+                    return meetOrderedNonNullTypes(a, b);
+                } else {
+                    return meetOrderedNonNullTypes(b, a);
+                }
+            }
+        }
+    }
+
+    private static ResolvedJavaType meetOrderedNonNullTypes(ResolvedJavaType a, ResolvedJavaType b) {
+        ResolvedJavaType result = a.findLeastCommonAncestor(b);
+        if (result.isJavaLangObject() && a.isInterface() && b.isInterface()) {
+            // Both types are incompatible interfaces => search for first possible common
+            // ancestor match among super interfaces.
+            ResolvedJavaType[] interfacesA = a.getInterfaces();
+            ResolvedJavaType[] interfacesB = b.getInterfaces();
+            for (int i = 0; i < interfacesA.length; ++i) {
+                ResolvedJavaType interface1 = interfacesA[i];
+                for (int j = 0; j < interfacesB.length; ++j) {
+                    ResolvedJavaType interface2 = interfacesB[j];
+                    ResolvedJavaType leastCommon = meetTypes(interface1, interface2);
+                    if (leastCommon.isInterface()) {
+                        return leastCommon;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + super.hashCode();
+        result = prime * result + (exactType ? 1231 : 1237);
+        result = prime * result + ((type == null || type.isJavaLangObject()) ? 0 : type.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) obj;
+        if (exactType != other.exactType) {
+            return false;
+        }
+        // null == java.lang.Object
+        if (type == null) {
+            if (other.type != null && !other.type.isJavaLangObject()) {
+                return false;
+            }
+        } else if (other.type == null) {
+            if (type != null && !type.isJavaLangObject()) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        return super.equals(other);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java
new file mode 100644
index 0000000..7debe2c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Abstract base class of all pointer types.
+ */
+public abstract class AbstractPointerStamp extends Stamp {
+
+    private final boolean nonNull;
+    private final boolean alwaysNull;
+
+    protected AbstractPointerStamp(boolean nonNull, boolean alwaysNull) {
+        this.nonNull = nonNull;
+        this.alwaysNull = alwaysNull;
+    }
+
+    public boolean nonNull() {
+        assert !this.isEmpty() || nonNull;
+        return nonNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
+    }
+
+    protected abstract AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull);
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (alwaysNull ? 1231 : 1237);
+        result = prime * result + (nonNull ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public Stamp join(Stamp stamp) {
+        AbstractPointerStamp other = (AbstractPointerStamp) stamp;
+        boolean joinNonNull = this.nonNull || other.nonNull;
+        boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull;
+        if (joinNonNull && joinAlwaysNull) {
+            return empty();
+        } else {
+            return copyWith(joinNonNull, joinAlwaysNull);
+        }
+    }
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        return join(other);
+    }
+
+    @Override
+    public Stamp meet(Stamp stamp) {
+        AbstractPointerStamp other = (AbstractPointerStamp) stamp;
+        boolean meetNonNull = this.nonNull && other.nonNull;
+        boolean meetAlwaysNull = this.alwaysNull && other.alwaysNull;
+        return copyWith(meetNonNull, meetAlwaysNull);
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return copyWith(false, false);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractPointerStamp other = (AbstractPointerStamp) obj;
+        return this.alwaysNull == other.alwaysNull && this.nonNull == other.nonNull;
+    }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull) {
+            return JavaConstant.NULL_POINTER;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        return JavaKind.Illegal;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java
new file mode 100644
index 0000000..af71cb1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import static jdk.vm.ci.meta.MetaUtil.getSimpleName;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
+
+/**
+ * Information about arithmetic operations.
+ */
+public final class ArithmeticOpTable {
+
+    private final UnaryOp<Neg> neg;
+    private final BinaryOp<Add> add;
+    private final BinaryOp<Sub> sub;
+
+    private final BinaryOp<Mul> mul;
+    private final BinaryOp<Div> div;
+    private final BinaryOp<Rem> rem;
+
+    private final UnaryOp<Not> not;
+    private final BinaryOp<And> and;
+    private final BinaryOp<Or> or;
+    private final BinaryOp<Xor> xor;
+
+    private final ShiftOp<Shl> shl;
+    private final ShiftOp<Shr> shr;
+    private final ShiftOp<UShr> ushr;
+
+    private final UnaryOp<Abs> abs;
+    private final UnaryOp<Sqrt> sqrt;
+
+    private final IntegerConvertOp<ZeroExtend> zeroExtend;
+    private final IntegerConvertOp<SignExtend> signExtend;
+    private final IntegerConvertOp<Narrow> narrow;
+
+    private final FloatConvertOp[] floatConvert;
+    private final int hash;
+
+    public static ArithmeticOpTable forStamp(Stamp s) {
+        if (s instanceof ArithmeticStamp) {
+            return ((ArithmeticStamp) s).getOps();
+        } else {
+            return EMPTY;
+        }
+    }
+
+    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
+
+    public ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
+                    BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
+                    IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
+        this(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
+    }
+
+    public interface ArithmeticOpWrapper {
+
+        <OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
+
+        <OP> BinaryOp<OP> wrapBinaryOp(BinaryOp<OP> op);
+
+        <OP> ShiftOp<OP> wrapShiftOp(ShiftOp<OP> op);
+
+        <OP> IntegerConvertOp<OP> wrapIntegerConvertOp(IntegerConvertOp<OP> op);
+
+        FloatConvertOp wrapFloatConvertOp(FloatConvertOp op);
+    }
+
+    private static <T> T wrapIfNonNull(Function<T, T> wrapper, T obj) {
+        if (obj == null) {
+            return null;
+        } else {
+            return wrapper.apply(obj);
+        }
+    }
+
+    public static ArithmeticOpTable wrap(ArithmeticOpWrapper wrapper, ArithmeticOpTable inner) {
+        UnaryOp<Neg> neg = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNeg());
+        BinaryOp<Add> add = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAdd());
+        BinaryOp<Sub> sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub());
+
+        BinaryOp<Mul> mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul());
+        BinaryOp<Div> div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv());
+        BinaryOp<Rem> rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem());
+
+        UnaryOp<Not> not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot());
+        BinaryOp<And> and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd());
+        BinaryOp<Or> or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr());
+        BinaryOp<Xor> xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor());
+
+        ShiftOp<Shl> shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl());
+        ShiftOp<Shr> shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr());
+        ShiftOp<UShr> ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr());
+
+        UnaryOp<Abs> abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs());
+        UnaryOp<Sqrt> sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt());
+
+        IntegerConvertOp<ZeroExtend> zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend());
+        IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
+        IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
+
+        Stream<FloatConvertOp> floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp);
+
+        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
+    }
+
+    private ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
+                    BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
+                    IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, Stream<FloatConvertOp> floatConvert) {
+        this.neg = neg;
+        this.add = add;
+        this.sub = sub;
+        this.mul = mul;
+        this.div = div;
+        this.rem = rem;
+        this.not = not;
+        this.and = and;
+        this.or = or;
+        this.xor = xor;
+        this.shl = shl;
+        this.shr = shr;
+        this.ushr = ushr;
+        this.abs = abs;
+        this.sqrt = sqrt;
+        this.zeroExtend = zeroExtend;
+        this.signExtend = signExtend;
+        this.narrow = narrow;
+        this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
+        floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op);
+
+        this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow);
+    }
+
+    @Override
+    public int hashCode() {
+        return hash;
+    }
+
+    /**
+     * Describes the unary negation operation.
+     */
+    public UnaryOp<Neg> getNeg() {
+        return neg;
+    }
+
+    /**
+     * Describes the addition operation.
+     */
+    public BinaryOp<Add> getAdd() {
+        return add;
+    }
+
+    /**
+     * Describes the subtraction operation.
+     */
+    public BinaryOp<Sub> getSub() {
+        return sub;
+    }
+
+    /**
+     * Describes the multiplication operation.
+     */
+    public BinaryOp<Mul> getMul() {
+        return mul;
+    }
+
+    /**
+     * Describes the division operation.
+     */
+    public BinaryOp<Div> getDiv() {
+        return div;
+    }
+
+    /**
+     * Describes the remainder operation.
+     */
+    public BinaryOp<Rem> getRem() {
+        return rem;
+    }
+
+    /**
+     * Describes the bitwise not operation.
+     */
+    public UnaryOp<Not> getNot() {
+        return not;
+    }
+
+    /**
+     * Describes the bitwise and operation.
+     */
+    public BinaryOp<And> getAnd() {
+        return and;
+    }
+
+    /**
+     * Describes the bitwise or operation.
+     */
+    public BinaryOp<Or> getOr() {
+        return or;
+    }
+
+    /**
+     * Describes the bitwise xor operation.
+     */
+    public BinaryOp<Xor> getXor() {
+        return xor;
+    }
+
+    /**
+     * Describes the shift left operation.
+     */
+    public ShiftOp<Shl> getShl() {
+        return shl;
+    }
+
+    /**
+     * Describes the signed shift right operation.
+     */
+    public ShiftOp<Shr> getShr() {
+        return shr;
+    }
+
+    /**
+     * Describes the unsigned shift right operation.
+     */
+    public ShiftOp<UShr> getUShr() {
+        return ushr;
+    }
+
+    /**
+     * Describes the absolute value operation.
+     */
+    public UnaryOp<Abs> getAbs() {
+        return abs;
+    }
+
+    /**
+     * Describes the square root operation.
+     */
+    public UnaryOp<Sqrt> getSqrt() {
+        return sqrt;
+    }
+
+    /**
+     * Describes the zero extend conversion.
+     */
+    public IntegerConvertOp<ZeroExtend> getZeroExtend() {
+        return zeroExtend;
+    }
+
+    /**
+     * Describes the sign extend conversion.
+     */
+    public IntegerConvertOp<SignExtend> getSignExtend() {
+        return signExtend;
+    }
+
+    /**
+     * Describes the narrowing conversion.
+     */
+    public IntegerConvertOp<Narrow> getNarrow() {
+        return narrow;
+    }
+
+    /**
+     * Describes integer/float/double conversions.
+     */
+    public FloatConvertOp getFloatConvert(FloatConvert op) {
+        return floatConvert[op.ordinal()];
+    }
+
+    public static String toString(Op... ops) {
+        return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(","));
+    }
+
+    private boolean opsEquals(ArithmeticOpTable that) {
+        // @formatter:off
+        return Objects.equals(neg, that.neg) &&
+               Objects.equals(add, that.add) &&
+               Objects.equals(sub, that.sub) &&
+               Objects.equals(mul, that.mul) &&
+               Objects.equals(div, that.div) &&
+               Objects.equals(rem, that.rem) &&
+               Objects.equals(not, that.not) &&
+               Objects.equals(and, that.and) &&
+               Objects.equals(or, that.or) &&
+               Objects.equals(xor, that.xor) &&
+               Objects.equals(shl, that.shl) &&
+               Objects.equals(shr, that.shr) &&
+               Objects.equals(ushr, that.ushr) &&
+               Objects.equals(abs, that.abs) &&
+               Objects.equals(sqrt, that.sqrt) &&
+               Objects.equals(zeroExtend, that.zeroExtend) &&
+               Objects.equals(signExtend, that.signExtend) &&
+               Objects.equals(narrow, that.narrow);
+        // @formatter:on
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ArithmeticOpTable that = (ArithmeticOpTable) obj;
+        if (opsEquals(that)) {
+            if (Arrays.equals(this.floatConvert, that.floatConvert)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" +
+                        toString(floatConvert) + "]]";
+    }
+
+    public abstract static class Op {
+
+        private final String operator;
+
+        protected Op(String operator) {
+            this.operator = operator;
+        }
+
+        @Override
+        public String toString() {
+            return operator;
+        }
+
+        @Override
+        public int hashCode() {
+            return operator.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            Op that = (Op) obj;
+            if (operator.equals(that.operator)) {
+                return true;
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Describes a unary arithmetic operation.
+     */
+    public abstract static class UnaryOp<T> extends Op {
+
+        public abstract static class Neg extends UnaryOp<Neg> {
+
+            protected Neg() {
+                super("-");
+            }
+        }
+
+        public abstract static class Not extends UnaryOp<Not> {
+
+            protected Not() {
+                super("~");
+            }
+        }
+
+        public abstract static class Abs extends UnaryOp<Abs> {
+
+            protected Abs() {
+                super("ABS");
+            }
+        }
+
+        public abstract static class Sqrt extends UnaryOp<Sqrt> {
+
+            protected Sqrt() {
+                super("SQRT");
+            }
+        }
+
+        protected UnaryOp(String operation) {
+            super(operation);
+        }
+
+        /**
+         * Apply the operation to a {@link Constant}.
+         */
+        public abstract Constant foldConstant(Constant value);
+
+        /**
+         * Apply the operation to a {@link Stamp}.
+         */
+        public abstract Stamp foldStamp(Stamp stamp);
+
+        public UnaryOp<T> unwrap() {
+            return this;
+        }
+    }
+
+    /**
+     * Describes a binary arithmetic operation.
+     */
+    public abstract static class BinaryOp<T> extends Op {
+
+        public abstract static class Add extends BinaryOp<Add> {
+
+            protected Add(boolean associative, boolean commutative) {
+                super("+", associative, commutative);
+            }
+        }
+
+        public abstract static class Sub extends BinaryOp<Sub> {
+
+            protected Sub(boolean associative, boolean commutative) {
+                super("-", associative, commutative);
+            }
+        }
+
+        public abstract static class Mul extends BinaryOp<Mul> {
+
+            protected Mul(boolean associative, boolean commutative) {
+                super("*", associative, commutative);
+            }
+        }
+
+        public abstract static class Div extends BinaryOp<Div> {
+
+            protected Div(boolean associative, boolean commutative) {
+                super("/", associative, commutative);
+            }
+        }
+
+        public abstract static class Rem extends BinaryOp<Rem> {
+
+            protected Rem(boolean associative, boolean commutative) {
+                super("%", associative, commutative);
+            }
+        }
+
+        public abstract static class And extends BinaryOp<And> {
+
+            protected And(boolean associative, boolean commutative) {
+                super("&", associative, commutative);
+            }
+        }
+
+        public abstract static class Or extends BinaryOp<Or> {
+
+            protected Or(boolean associative, boolean commutative) {
+                super("|", associative, commutative);
+            }
+        }
+
+        public abstract static class Xor extends BinaryOp<Xor> {
+
+            protected Xor(boolean associative, boolean commutative) {
+                super("^", associative, commutative);
+            }
+        }
+
+        private final boolean associative;
+        private final boolean commutative;
+
+        protected BinaryOp(String operation, boolean associative, boolean commutative) {
+            super(operation);
+            this.associative = associative;
+            this.commutative = commutative;
+        }
+
+        /**
+         * Apply the operation to two {@linkplain Constant Constants}.
+         */
+        public abstract Constant foldConstant(Constant a, Constant b);
+
+        /**
+         * Apply the operation to two {@linkplain Stamp Stamps}.
+         */
+        public abstract Stamp foldStamp(Stamp a, Stamp b);
+
+        /**
+         * Checks whether this operation is associative. An operation is associative when
+         * {@code (a . b) . c == a . (b . c)} for all a, b, c. Note that you still have to be
+         * careful with inverses. For example the integer subtraction operation will report
+         * {@code true} here, since you can still reassociate as long as the correct negations are
+         * inserted.
+         */
+        public final boolean isAssociative() {
+            return associative;
+        }
+
+        /**
+         * Checks whether this operation is commutative. An operation is commutative when
+         * {@code a . b == b . a} for all a, b.
+         */
+        public final boolean isCommutative() {
+            return commutative;
+        }
+
+        /**
+         * Check whether a {@link Constant} is a neutral element for this operation. A neutral
+         * element is any element {@code n} where {@code a . n == a} for all a.
+         *
+         * @param n the {@link Constant} that should be tested
+         * @return true iff for all {@code a}: {@code a . n == a}
+         */
+        public boolean isNeutral(Constant n) {
+            return false;
+        }
+
+        /**
+         * Check whether this operation has a zero {@code z == a . a} for each a. Examples of
+         * operations having such an element are subtraction and exclusive-or. Note that this may be
+         * different from the numbers tested by {@link #isNeutral}.
+         *
+         * @param stamp a {@link Stamp}
+         * @return a unique {@code z} such that {@code z == a . a} for each {@code a} in
+         *         {@code stamp} if it exists, otherwise {@code null}
+         */
+        public Constant getZero(Stamp stamp) {
+            return null;
+        }
+
+        public BinaryOp<T> unwrap() {
+            return this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + (associative ? 1231 : 1237);
+            result = prime * result + (commutative ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            BinaryOp<?> that = (BinaryOp<?>) obj;
+            if (associative != that.associative) {
+                return false;
+            }
+            if (commutative != that.commutative) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            if (associative) {
+                if (commutative) {
+                    return super.toString() + "[AC]";
+                } else {
+                    return super.toString() + "[A]";
+                }
+            } else if (commutative) {
+                return super.toString() + "[C]";
+            }
+            return super.toString();
+        }
+    }
+
+    /**
+     * Describes a shift operation. The right argument of a shift operation always has kind
+     * {@link JavaKind#Int}.
+     */
+    public abstract static class ShiftOp<OP> extends Op {
+
+        public abstract static class Shl extends ShiftOp<Shl> {
+
+            public Shl() {
+                super("<<");
+            }
+        }
+
+        public abstract static class Shr extends ShiftOp<Shr> {
+
+            public Shr() {
+                super(">>");
+            }
+        }
+
+        public abstract static class UShr extends ShiftOp<UShr> {
+
+            public UShr() {
+                super(">>>");
+            }
+        }
+
+        protected ShiftOp(String operation) {
+            super(operation);
+        }
+
+        /**
+         * Apply the shift to a constant.
+         */
+        public abstract Constant foldConstant(Constant c, int amount);
+
+        /**
+         * Apply the shift to a stamp.
+         */
+        public abstract Stamp foldStamp(Stamp s, IntegerStamp amount);
+
+        /**
+         * Get the shift amount mask for a given result stamp.
+         */
+        public abstract int getShiftAmountMask(Stamp s);
+    }
+
+    public abstract static class FloatConvertOp extends UnaryOp<FloatConvertOp> {
+
+        private final FloatConvert op;
+
+        protected FloatConvertOp(FloatConvert op) {
+            super(op.name());
+            this.op = op;
+        }
+
+        public FloatConvert getFloatConvert() {
+            return op;
+        }
+
+        @Override
+        public FloatConvertOp unwrap() {
+            return this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            return prime * super.hashCode() + op.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            FloatConvertOp that = (FloatConvertOp) obj;
+            if (op != that.op) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    public abstract static class IntegerConvertOp<T> extends Op {
+
+        public abstract static class ZeroExtend extends IntegerConvertOp<ZeroExtend> {
+
+            protected ZeroExtend() {
+                super("ZeroExtend");
+            }
+        }
+
+        public abstract static class SignExtend extends IntegerConvertOp<SignExtend> {
+
+            protected SignExtend() {
+                super("SignExtend");
+            }
+        }
+
+        public abstract static class Narrow extends IntegerConvertOp<Narrow> {
+
+            protected Narrow() {
+                super("Narrow");
+            }
+        }
+
+        protected IntegerConvertOp(String op) {
+            super(op);
+        }
+
+        public abstract Constant foldConstant(int inputBits, int resultBits, Constant value);
+
+        public abstract Stamp foldStamp(int inputBits, int resultBits, Stamp stamp);
+
+        public IntegerConvertOp<T> unwrap() {
+            return this;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticStamp.java
new file mode 100644
index 0000000..ee0979f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticStamp.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import jdk.vm.ci.meta.SerializableConstant;
+
+/**
+ * Type describing values that support arithmetic operations.
+ */
+public abstract class ArithmeticStamp extends Stamp {
+
+    private final ArithmeticOpTable ops;
+
+    protected ArithmeticStamp(ArithmeticOpTable ops) {
+        this.ops = ops;
+    }
+
+    public ArithmeticOpTable getOps() {
+        return ops;
+    }
+
+    public abstract SerializableConstant deserialize(ByteBuffer buffer);
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        return this.join(other);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ops.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof ArithmeticStamp)) {
+            return false;
+        }
+        assert Objects.equals(ops, ((ArithmeticStamp) obj).ops);
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/DataPointerConstant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/DataPointerConstant.java
new file mode 100644
index 0000000..8eecb6a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/DataPointerConstant.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.SerializableConstant;
+
+/**
+ * Base class for {@link Constant constants} that represent a pointer to the data section.
+ */
+public abstract class DataPointerConstant implements SerializableConstant {
+
+    private final int alignment;
+
+    protected DataPointerConstant(int alignment) {
+        this.alignment = alignment;
+    }
+
+    /**
+     * Get the minimum alignment of the data in the data section.
+     */
+    public final int getAlignment() {
+        return alignment;
+    }
+
+    @Override
+    public boolean isDefaultForKind() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java
new file mode 100644
index 0000000..c55efe6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import static org.graalvm.compiler.core.common.calc.FloatConvert.D2F;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.D2I;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.D2L;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.F2D;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.F2I;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.F2L;
+
+import java.nio.ByteBuffer;
+import java.util.function.DoubleBinaryOperator;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.SerializableConstant;
+
+public class FloatStamp extends PrimitiveStamp {
+
+    private final double lowerBound;
+    private final double upperBound;
+    private final boolean nonNaN;
+
+    protected FloatStamp(int bits) {
+        this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false);
+    }
+
+    public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
+        super(bits, OPS);
+        assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound));
+        assert Double.isNaN(lowerBound) == Double.isNaN(upperBound);
+        this.lowerBound = lowerBound;
+        this.upperBound = upperBound;
+        this.nonNaN = nonNaN;
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return new FloatStamp(getBits());
+    }
+
+    @Override
+    public Stamp empty() {
+        return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        JavaConstant jc = (JavaConstant) c;
+        assert jc.getJavaKind().isNumericFloat() && jc.getJavaKind().getBitCount() == getBits();
+        return StampFactory.forConstant(jc);
+    }
+
+    @Override
+    public SerializableConstant deserialize(ByteBuffer buffer) {
+        switch (getBits()) {
+            case 32:
+                return JavaConstant.forFloat(buffer.getFloat());
+            case 64:
+                return JavaConstant.forDouble(buffer.getDouble());
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean hasValues() {
+        return lowerBound <= upperBound || !nonNaN;
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        if (getBits() > 32) {
+            return JavaKind.Double;
+        } else {
+            return JavaKind.Float;
+        }
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getFloatingKind(getBits());
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        switch (getBits()) {
+            case 32:
+                return metaAccess.lookupJavaType(Float.TYPE);
+            case 64:
+                return metaAccess.lookupJavaType(Double.TYPE);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * The (inclusive) lower bound on the value described by this stamp.
+     */
+    public double lowerBound() {
+        return lowerBound;
+    }
+
+    /**
+     * The (inclusive) upper bound on the value described by this stamp.
+     */
+    public double upperBound() {
+        return upperBound;
+    }
+
+    /**
+     * Returns true if NaN is non included in the value described by this stamp.
+     */
+    public boolean isNonNaN() {
+        return nonNaN;
+    }
+
+    /**
+     * Returns true if this stamp represents the NaN value.
+     */
+    public boolean isNaN() {
+        return Double.isNaN(lowerBound);
+    }
+
+    public boolean isUnrestricted() {
+        return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
+    }
+
+    public boolean contains(double value) {
+        if (Double.isNaN(value)) {
+            return !nonNaN;
+        } else {
+            /*
+             * Don't use Double.compare for checking the bounds as -0.0 isn't correctly tracked, so
+             * the presence of 0.0 means -0.0 might also exist in the range.
+             */
+            return value >= lowerBound && value <= upperBound;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('f');
+        str.append(getBits());
+        str.append(nonNaN ? "!" : "");
+        if (lowerBound == upperBound) {
+            str.append(" [").append(lowerBound).append(']');
+        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
+            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+        }
+        return str.toString();
+    }
+
+    private static double meetBounds(double a, double b, DoubleBinaryOperator op) {
+        if (Double.isNaN(a)) {
+            return b;
+        } else if (Double.isNaN(b)) {
+            return a;
+        } else {
+            return op.applyAsDouble(a, b);
+        }
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        FloatStamp other = (FloatStamp) otherStamp;
+        assert getBits() == other.getBits();
+        double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
+        double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min);
+        boolean meetNonNaN = nonNaN && other.nonNaN;
+        if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) {
+            return this;
+        } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) {
+            return other;
+        } else {
+            return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
+        }
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        FloatStamp other = (FloatStamp) otherStamp;
+        assert getBits() == other.getBits();
+        double joinUpperBound = Math.min(upperBound, other.upperBound);
+        double joinLowerBound = Math.max(lowerBound, other.lowerBound);
+        boolean joinNonNaN = nonNaN || other.nonNaN;
+        if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) {
+            return this;
+        } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) {
+            return other;
+        } else {
+            return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        result = prime * result + super.hashCode();
+        temp = Double.doubleToLongBits(lowerBound);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        result = prime * result + (nonNaN ? 1231 : 1237);
+        temp = Double.doubleToLongBits(upperBound);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        if (this == stamp) {
+            return true;
+        }
+        if (stamp instanceof FloatStamp) {
+            FloatStamp other = (FloatStamp) stamp;
+            return getBits() == other.getBits();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof PrimitiveConstant) {
+            PrimitiveConstant prim = (PrimitiveConstant) constant;
+            return prim.getJavaKind().isNumericFloat();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
+            return false;
+        }
+        FloatStamp other = (FloatStamp) obj;
+        if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
+            return false;
+        }
+        if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) {
+            return false;
+        }
+        if (nonNaN != other.nonNaN) {
+            return false;
+        }
+        return super.equals(other);
+    }
+
+    @Override
+    public JavaConstant asConstant() {
+        if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
+            switch (getBits()) {
+                case 32:
+                    return JavaConstant.forFloat((float) lowerBound);
+                case 64:
+                    return JavaConstant.forDouble(lowerBound);
+            }
+        }
+        return null;
+    }
+
+    public boolean isConstant() {
+        return (nonNaN && Double.compare(lowerBound, upperBound) == 0);
+    }
+
+    private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
+
+                    new UnaryOp.Neg() {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(-value.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(-value.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp s) {
+                            FloatStamp stamp = (FloatStamp) s;
+                            return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
+                        }
+                    },
+
+                    new BinaryOp.Add(false, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(a.asFloat() + b.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(a.asDouble() + b.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            // TODO
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            switch (n.getJavaKind()) {
+                                case Float:
+                                    return Float.compare(n.asFloat(), -0.0f) == 0;
+                                case Double:
+                                    return Double.compare(n.asDouble(), -0.0) == 0;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Sub(false, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(a.asFloat() - b.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(a.asDouble() - b.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            // TODO
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            switch (n.getJavaKind()) {
+                                case Float:
+                                    return Float.compare(n.asFloat(), 0.0f) == 0;
+                                case Double:
+                                    return Double.compare(n.asDouble(), 0.0) == 0;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Mul(false, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(a.asFloat() * b.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(a.asDouble() * b.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp a, Stamp b) {
+                            // TODO
+                            return a.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            switch (n.getJavaKind()) {
+                                case Float:
+                                    return Float.compare(n.asFloat(), 1.0f) == 0;
+                                case Double:
+                                    return Double.compare(n.asDouble(), 1.0) == 0;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Div(false, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(a.asFloat() / b.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(a.asDouble() / b.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            // TODO
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            switch (n.getJavaKind()) {
+                                case Float:
+                                    return Float.compare(n.asFloat(), 1.0f) == 0;
+                                case Double:
+                                    return Double.compare(n.asDouble(), 1.0) == 0;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Rem(false, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(a.asFloat() % b.asFloat());
+                                case Double:
+                                    return JavaConstant.forDouble(a.asDouble() % b.asDouble());
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            // TODO
+                            return stamp1.unrestricted();
+                        }
+                    },
+
+                    new UnaryOp.Not() {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    int f = Float.floatToRawIntBits(value.asFloat());
+                                    return JavaConstant.forFloat(Float.intBitsToFloat(~f));
+                                case Double:
+                                    long d = Double.doubleToRawLongBits(value.asDouble());
+                                    return JavaConstant.forDouble(Double.longBitsToDouble(~d));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp s) {
+                            return s.unrestricted();
+                        }
+                    },
+
+                    new BinaryOp.And(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    int fa = Float.floatToRawIntBits(a.asFloat());
+                                    int fb = Float.floatToRawIntBits(b.asFloat());
+                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb));
+                                case Double:
+                                    long da = Double.doubleToRawLongBits(a.asDouble());
+                                    long db = Double.doubleToRawLongBits(b.asDouble());
+                                    return JavaConstant.forDouble(Double.longBitsToDouble(da & db));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant n) {
+                            PrimitiveConstant value = (PrimitiveConstant) n;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF;
+                                case Double:
+                                    return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Or(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    int fa = Float.floatToRawIntBits(a.asFloat());
+                                    int fb = Float.floatToRawIntBits(b.asFloat());
+                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb));
+                                case Double:
+                                    long da = Double.doubleToRawLongBits(a.asDouble());
+                                    long db = Double.doubleToRawLongBits(b.asDouble());
+                                    return JavaConstant.forDouble(Double.longBitsToDouble(da | db));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant n) {
+                            PrimitiveConstant value = (PrimitiveConstant) n;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return Float.floatToRawIntBits(value.asFloat()) == 0;
+                                case Double:
+                                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Xor(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            switch (a.getJavaKind()) {
+                                case Float:
+                                    int fa = Float.floatToRawIntBits(a.asFloat());
+                                    int fb = Float.floatToRawIntBits(b.asFloat());
+                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb));
+                                case Double:
+                                    long da = Double.doubleToRawLongBits(a.asDouble());
+                                    long db = Double.doubleToRawLongBits(b.asDouble());
+                                    return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            return stamp1.unrestricted();
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant n) {
+                            PrimitiveConstant value = (PrimitiveConstant) n;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return Float.floatToRawIntBits(value.asFloat()) == 0;
+                                case Double:
+                                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+                    },
+
+                    null, null, null,
+
+                    new UnaryOp.Abs() {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat(Math.abs(value.asFloat()));
+                                case Double:
+                                    return JavaConstant.forDouble(Math.abs(value.asDouble()));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp s) {
+                            FloatStamp stamp = (FloatStamp) s;
+                            if (stamp.isNaN()) {
+                                return stamp;
+                            }
+                            return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN());
+                        }
+                    },
+
+                    new UnaryOp.Sqrt() {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            switch (value.getJavaKind()) {
+                                case Float:
+                                    return JavaConstant.forFloat((float) Math.sqrt(value.asFloat()));
+                                case Double:
+                                    return JavaConstant.forDouble(Math.sqrt(value.asDouble()));
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp s) {
+                            return s.unrestricted();
+                        }
+                    },
+
+                    null, null, null,
+
+                    new FloatConvertOp(F2I) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forInt((int) value.asFloat());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 32;
+                            boolean mustHaveZero = !floatStamp.isNonNaN();
+                            int lowerBound = (int) floatStamp.lowerBound();
+                            int upperBound = (int) floatStamp.upperBound();
+                            if (mustHaveZero) {
+                                if (lowerBound > 0) {
+                                    lowerBound = 0;
+                                } else if (upperBound < 0) {
+                                    upperBound = 0;
+                                }
+                            }
+                            return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound);
+                        }
+                    },
+
+                    new FloatConvertOp(F2L) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forLong((long) value.asFloat());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 32;
+                            boolean mustHaveZero = !floatStamp.isNonNaN();
+                            long lowerBound = (long) floatStamp.lowerBound();
+                            long upperBound = (long) floatStamp.upperBound();
+                            if (mustHaveZero) {
+                                if (lowerBound > 0) {
+                                    lowerBound = 0;
+                                } else if (upperBound < 0) {
+                                    upperBound = 0;
+                                }
+                            }
+                            return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound);
+                        }
+                    },
+
+                    new FloatConvertOp(D2I) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forInt((int) value.asDouble());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 64;
+                            boolean mustHaveZero = !floatStamp.isNonNaN();
+                            int lowerBound = (int) floatStamp.lowerBound();
+                            int upperBound = (int) floatStamp.upperBound();
+                            if (mustHaveZero) {
+                                if (lowerBound > 0) {
+                                    lowerBound = 0;
+                                } else if (upperBound < 0) {
+                                    upperBound = 0;
+                                }
+                            }
+                            return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound);
+                        }
+                    },
+
+                    new FloatConvertOp(D2L) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forLong((long) value.asDouble());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 64;
+                            boolean mustHaveZero = !floatStamp.isNonNaN();
+                            long lowerBound = (long) floatStamp.lowerBound();
+                            long upperBound = (long) floatStamp.upperBound();
+                            if (mustHaveZero) {
+                                if (lowerBound > 0) {
+                                    lowerBound = 0;
+                                } else if (upperBound < 0) {
+                                    upperBound = 0;
+                                }
+                            }
+                            return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound);
+                        }
+                    },
+
+                    new FloatConvertOp(F2D) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forDouble(value.asFloat());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 32;
+                            return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
+                        }
+                    },
+
+                    new FloatConvertOp(D2F) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forFloat((float) value.asDouble());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            FloatStamp floatStamp = (FloatStamp) stamp;
+                            assert floatStamp.getBits() == 64;
+                            return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
+                        }
+                    });
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java
new file mode 100644
index 0000000..b142e2c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * This stamp represents the type of the {@link JavaKind#Illegal} value in the second slot of
+ * {@link JavaKind#Long} and {@link JavaKind#Double} values. It can only appear in framestates or
+ * virtual objects.
+ */
+public final class IllegalStamp extends Stamp {
+
+    private IllegalStamp() {
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        return JavaKind.Illegal;
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return LIRKind.Illegal;
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public Stamp empty() {
+        return this;
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        assert ((PrimitiveConstant) c).getJavaKind() == JavaKind.Illegal;
+        return this;
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        throw GraalError.shouldNotReachHere("illegal stamp has no Java type");
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        assert other instanceof IllegalStamp;
+        return this;
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        assert other instanceof IllegalStamp;
+        return this;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        return stamp instanceof IllegalStamp;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof PrimitiveConstant) {
+            PrimitiveConstant prim = (PrimitiveConstant) constant;
+            return prim.getJavaKind() == JavaKind.Illegal;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "ILLEGAL";
+    }
+
+    @Override
+    public boolean hasValues() {
+        return true;
+    }
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        assert other instanceof IllegalStamp;
+        return this;
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        throw GraalError.shouldNotReachHere("can't read values of illegal stamp");
+    }
+
+    private static final IllegalStamp instance = new IllegalStamp();
+
+    static IllegalStamp getInstance() {
+        return instance;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java
new file mode 100644
index 0000000..c76198d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java
@@ -0,0 +1,1237 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import static org.graalvm.compiler.core.common.calc.FloatConvert.I2D;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.I2F;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.L2D;
+import static org.graalvm.compiler.core.common.calc.FloatConvert.L2F;
+
+import java.nio.ByteBuffer;
+import java.util.Formatter;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.SerializableConstant;
+
+/**
+ * Describes the possible values of a node that produces an int or long result.
+ *
+ * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
+ * (always set) bit-masks.
+ */
+public class IntegerStamp extends PrimitiveStamp {
+
+    private final long lowerBound;
+    private final long upperBound;
+    private final long downMask;
+    private final long upMask;
+
+    public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
+        super(bits, OPS);
+        this.lowerBound = lowerBound;
+        this.upperBound = upperBound;
+        this.downMask = downMask;
+        this.upMask = upMask;
+        assert lowerBound >= CodeUtil.minValue(bits) : this;
+        assert upperBound <= CodeUtil.maxValue(bits) : this;
+        assert (downMask & CodeUtil.mask(bits)) == downMask : this;
+        assert (upMask & CodeUtil.mask(bits)) == upMask : this;
+    }
+
+    public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
+        long lowerBound;
+        long upperBound;
+        if (((upMask >>> (bits - 1)) & 1) == 0) {
+            lowerBound = downMask;
+            upperBound = upMask;
+        } else if (((downMask >>> (bits - 1)) & 1) == 1) {
+            lowerBound = downMask;
+            upperBound = upMask;
+        } else {
+            lowerBound = downMask | (-1L << (bits - 1));
+            upperBound = CodeUtil.maxValue(bits) & upMask;
+        }
+        lowerBound = CodeUtil.convert(lowerBound, bits, false);
+        upperBound = CodeUtil.convert(upperBound, bits, false);
+        return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask);
+    }
+
+    @Override
+    public IntegerStamp unrestricted() {
+        return new IntegerStamp(getBits(), CodeUtil.minValue(getBits()), CodeUtil.maxValue(getBits()), 0, CodeUtil.mask(getBits()));
+    }
+
+    @Override
+    public Stamp empty() {
+        return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        if (c instanceof PrimitiveConstant) {
+            long value = ((PrimitiveConstant) c).asLong();
+            return StampFactory.forInteger(getBits(), value, value);
+        }
+        return this;
+    }
+
+    @Override
+    public SerializableConstant deserialize(ByteBuffer buffer) {
+        switch (getBits()) {
+            case 1:
+                return JavaConstant.forBoolean(buffer.get() != 0);
+            case 8:
+                return JavaConstant.forByte(buffer.get());
+            case 16:
+                return JavaConstant.forShort(buffer.getShort());
+            case 32:
+                return JavaConstant.forInt(buffer.getInt());
+            case 64:
+                return JavaConstant.forLong(buffer.getLong());
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean hasValues() {
+        return lowerBound <= upperBound;
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        if (getBits() > 32) {
+            return JavaKind.Long;
+        } else {
+            return JavaKind.Int;
+        }
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getIntegerKind(getBits());
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        switch (getBits()) {
+            case 1:
+                return metaAccess.lookupJavaType(Boolean.TYPE);
+            case 8:
+                return metaAccess.lookupJavaType(Byte.TYPE);
+            case 16:
+                return metaAccess.lookupJavaType(Short.TYPE);
+            case 32:
+                return metaAccess.lookupJavaType(Integer.TYPE);
+            case 64:
+                return metaAccess.lookupJavaType(Long.TYPE);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * The signed inclusive lower bound on the value described by this stamp.
+     */
+    public long lowerBound() {
+        return lowerBound;
+    }
+
+    /**
+     * The signed inclusive upper bound on the value described by this stamp.
+     */
+    public long upperBound() {
+        return upperBound;
+    }
+
+    /**
+     * This bit-mask describes the bits that are always set in the value described by this stamp.
+     */
+    public long downMask() {
+        return downMask;
+    }
+
+    /**
+     * This bit-mask describes the bits that can be set in the value described by this stamp.
+     */
+    public long upMask() {
+        return upMask;
+    }
+
+    public boolean isUnrestricted() {
+        return lowerBound == CodeUtil.minValue(getBits()) && upperBound == CodeUtil.maxValue(getBits()) && downMask == 0 && upMask == CodeUtil.mask(getBits());
+    }
+
+    public boolean contains(long value) {
+        return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & CodeUtil.mask(getBits()));
+    }
+
+    public boolean isPositive() {
+        return lowerBound() >= 0;
+    }
+
+    public boolean isNegative() {
+        return upperBound() <= 0;
+    }
+
+    public boolean isStrictlyPositive() {
+        return lowerBound() > 0;
+    }
+
+    public boolean isStrictlyNegative() {
+        return upperBound() < 0;
+    }
+
+    public boolean canBePositive() {
+        return upperBound() > 0;
+    }
+
+    public boolean canBeNegative() {
+        return lowerBound() < 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('i');
+        str.append(getBits());
+        if (lowerBound == upperBound) {
+            str.append(" [").append(lowerBound).append(']');
+        } else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
+            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+        }
+        if (downMask != 0) {
+            str.append(" \u21ca");
+            new Formatter(str).format("%016x", downMask);
+        }
+        if (upMask != CodeUtil.mask(getBits())) {
+            str.append(" \u21c8");
+            new Formatter(str).format("%016x", upMask);
+        }
+        return str.toString();
+    }
+
+    private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
+        assert getBits() == other.getBits();
+        if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) {
+            return empty();
+        } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) {
+            return this;
+        } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
+            return other;
+        } else {
+            return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
+        }
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        IntegerStamp other = (IntegerStamp) otherStamp;
+        return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        IntegerStamp other = (IntegerStamp) otherStamp;
+        long newDownMask = downMask | other.downMask;
+        long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
+        long newUpperBound = Math.min(upperBound, other.upperBound);
+        long newUpMask = upMask & other.upMask;
+        IntegerStamp limit = StampFactory.forInteger(getBits(), newLowerBound, newUpperBound);
+        return createStamp(other, newUpperBound, newLowerBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        if (this == stamp) {
+            return true;
+        }
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp other = (IntegerStamp) stamp;
+            return getBits() == other.getBits();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof PrimitiveConstant) {
+            PrimitiveConstant prim = (PrimitiveConstant) constant;
+            return prim.getJavaKind().isNumericInteger();
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + super.hashCode();
+        result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32));
+        result = prime * result + (int) (upperBound ^ (upperBound >>> 32));
+        result = prime * result + (int) (downMask ^ (downMask >>> 32));
+        result = prime * result + (int) (upMask ^ (upMask >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
+            return false;
+        }
+        IntegerStamp other = (IntegerStamp) obj;
+        if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) {
+            return false;
+        }
+        return super.equals(other);
+    }
+
+    public static long upMaskFor(int bits, long lowerBound, long upperBound) {
+        long mask = lowerBound | upperBound;
+        if (mask == 0) {
+            return 0;
+        } else {
+            return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & CodeUtil.mask(bits);
+        }
+    }
+
+    /**
+     * Checks if the 2 stamps represent values of the same sign. Returns true if the two stamps are
+     * both positive of null or if they are both strictly negative
+     *
+     * @return true if the two stamps are both positive of null or if they are both strictly
+     *         negative
+     */
+    public static boolean sameSign(IntegerStamp s1, IntegerStamp s2) {
+        return s1.isPositive() && s2.isPositive() || s1.isStrictlyNegative() && s2.isStrictlyNegative();
+    }
+
+    @Override
+    public JavaConstant asConstant() {
+        if (lowerBound == upperBound) {
+            switch (getBits()) {
+                case 1:
+                    return JavaConstant.forBoolean(lowerBound != 0);
+                case 8:
+                    return JavaConstant.forByte((byte) lowerBound);
+                case 16:
+                    return JavaConstant.forShort((short) lowerBound);
+                case 32:
+                    return JavaConstant.forInt((int) lowerBound);
+                case 64:
+                    return JavaConstant.forLong(lowerBound);
+            }
+        }
+        return null;
+    }
+
+    public static boolean addOverflowsPositively(long x, long y, int bits) {
+        long result = x + y;
+        if (bits == 64) {
+            return (~x & ~y & result) < 0;
+        } else {
+            return result > CodeUtil.maxValue(bits);
+        }
+    }
+
+    public static boolean addOverflowsNegatively(long x, long y, int bits) {
+        long result = x + y;
+        if (bits == 64) {
+            return (x & y & ~result) < 0;
+        } else {
+            return result < CodeUtil.minValue(bits);
+        }
+    }
+
+    public static long carryBits(long x, long y) {
+        return (x + y) ^ x ^ y;
+    }
+
+    private static long saturate(long v, int bits) {
+        if (bits < 64) {
+            long max = CodeUtil.maxValue(bits);
+            if (v > max) {
+                return max;
+            }
+            long min = CodeUtil.minValue(bits);
+            if (v < min) {
+                return min;
+            }
+        }
+        return v;
+    }
+
+    public static boolean multiplicationOverflows(long a, long b, int bits) {
+        assert bits <= 64 && bits >= 0;
+        long result = a * b;
+        // result is positive if the sign is the same
+        boolean positive = (a >= 0 && b >= 0) || (a < 0 && b < 0);
+        if (bits == 64) {
+            if (a > 0 && b > 0) {
+                return a > 0x7FFFFFFF_FFFFFFFFL / b;
+            } else if (a > 0 && b <= 0) {
+                return b < 0x80000000_00000000L / a;
+            } else if (a <= 0 && b > 0) {
+                return a < 0x80000000_00000000L / b;
+            } else {
+                // a<=0 && b <=0
+                return a != 0 && b < 0x7FFFFFFF_FFFFFFFFL / a;
+            }
+        } else {
+            if (positive) {
+                return result > CodeUtil.maxValue(bits);
+            } else {
+                return result < CodeUtil.minValue(bits);
+            }
+        }
+    }
+
+    public static boolean subtractionCanOverflow(IntegerStamp x, IntegerStamp y) {
+        assert x.getBits() == y.getBits();
+        // Checkstyle: stop
+        long x_l = x.lowerBound();
+        long x_h = x.upperBound();
+        long y_l = y.lowerBound();
+        long y_h = y.upperBound();
+        // Checkstyle: resume
+        return subtractionOverflows(x_l, y_h, x.getBits()) || subtractionOverflows(x_h, y_l, x.getBits());
+    }
+
+    public static boolean subtractionOverflows(long x, long y, int bits) {
+        long result = x - y;
+        if (bits == 64) {
+            return (((x ^ y) & (x ^ result)) < 0);
+        }
+        return result < CodeUtil.minValue(bits) || result > CodeUtil.maxValue(bits);
+    }
+
+    public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
+
+                    new UnaryOp.Neg() {
+
+                        @Override
+                        public Constant foldConstant(Constant value) {
+                            PrimitiveConstant c = (PrimitiveConstant) value;
+                            return JavaConstant.forIntegerKind(c.getJavaKind(), -c.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            int bits = stamp.getBits();
+                            if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
+                                // TODO(ls) check if the mask calculation is correct...
+                                return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
+                            } else {
+                                return stamp.unrestricted();
+                            }
+                        }
+                    },
+
+                    new BinaryOp.Add(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() + b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+
+                            int bits = a.getBits();
+                            assert bits == b.getBits();
+
+                            if (a.isUnrestricted()) {
+                                return a;
+                            } else if (b.isUnrestricted()) {
+                                return b;
+                            }
+                            long defaultMask = CodeUtil.mask(bits);
+                            long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+                            long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
+                            long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
+                            long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
+
+                            newDownMask &= defaultMask;
+                            newUpMask &= defaultMask;
+
+                            long newLowerBound;
+                            long newUpperBound;
+                            boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
+                            boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
+                            boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
+                            boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
+                            if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) {
+                                newLowerBound = CodeUtil.minValue(bits);
+                                newUpperBound = CodeUtil.maxValue(bits);
+                            } else {
+                                newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
+                                newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
+                            }
+                            IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+                            newUpMask &= limit.upMask();
+                            newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
+                            newDownMask |= limit.downMask();
+                            newLowerBound |= newDownMask;
+                            return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 0;
+                        }
+                    },
+
+                    new BinaryOp.Sub(true, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() - b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp a, Stamp b) {
+                            return OPS.getAdd().foldStamp(a, OPS.getNeg().foldStamp(b));
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 0;
+                        }
+
+                        @Override
+                        public Constant getZero(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            return JavaConstant.forPrimitiveInt(stamp.getBits(), 0);
+                        }
+                    },
+
+                    new BinaryOp.Mul(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() * b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+
+                            int bits = a.getBits();
+                            assert bits == b.getBits();
+                            // if a==0 or b==0 result of a*b is always 0
+                            if (a.upMask() == 0) {
+                                return a;
+                            } else if (b.upMask() == 0) {
+                                return b;
+                            } else {
+                                // if a has the full range or b, the result will also have it
+                                if (a.isUnrestricted()) {
+                                    return a;
+                                } else if (b.isUnrestricted()) {
+                                    return b;
+                                }
+                                // a!=0 && b !=0 holds
+                                long newLowerBound = Long.MAX_VALUE;
+                                long newUpperBound = Long.MIN_VALUE;
+                                /*
+                                 * Based on the signs of the incoming stamps lower and upper bound
+                                 * of the result of the multiplication may be swapped. LowerBound
+                                 * can become upper bound if both signs are negative, and so on. To
+                                 * determine the new values for lower and upper bound we need to
+                                 * look at the max and min of the cases blow:
+                                 *
+                                 * @formatter:off
+                                 *
+                                 * a.lowerBound * b.lowerBound
+                                 * a.lowerBound * b.upperBound
+                                 * a.upperBound * b.lowerBound
+                                 * a.upperBound * b.upperBound
+                                 *
+                                 * @formatter:on
+                                 *
+                                 * We are only interested in those cases that are relevant due to
+                                 * the sign of the involved stamps (whether a stamp includes
+                                 * negative and / or positive values). Based on the signs, the maximum
+                                 * or minimum of the above multiplications form the new lower and
+                                 * upper bounds.
+                                 *
+                                 * The table below contains the interesting candidates for lower and
+                                 * upper bound after multiplication.
+                                 *
+                                 * For example if we consider two stamps a & b that both contain
+                                 * negative and positive values, the product of minN_a * minN_b
+                                 * (both the smallest negative value for each stamp) can only be the
+                                 * highest positive number. The other candidates can be computed in
+                                 * a similar fashion. Some of them can never be a new minimum or
+                                 * maximum and are therefore excluded.
+                                 *
+                                 *
+                                 * @formatter:off
+                                 *
+                                 *          [x..........0..........y]
+                                 *          -------------------------
+                                 *          [minN   maxN minP   maxP]
+                                 *               where maxN = min(0,y) && minP = max(0,x)
+                                 *
+                                 *
+                                 *                |minN_a  maxN_a    minP_a  maxP_a
+                                 *         _______|________________________________
+                                 *         minN_b |MAX      /     :   /      MIN
+                                 *         maxN_b | /      MIN    :  MAX      /
+                                 *                |---------------+----------------
+                                 *         minP_b | /      MAX    :  MIN      /
+                                 *         maxP_b |MIN      /     :   /      MAX
+                                 *
+                                 * @formatter:on
+                                 */
+                                // We materialize all factors here. If they are needed, the signs of
+                                // the stamp will ensure the correct value is used.
+                                // Checkstyle: stop
+                                long minN_a = a.lowerBound();
+                                long maxN_a = Math.min(0, a.upperBound());
+                                long minP_a = Math.max(0, a.lowerBound());
+                                long maxP_a = a.upperBound();
+
+                                long minN_b = b.lowerBound();
+                                long maxN_b = Math.min(0, b.upperBound());
+                                long minP_b = Math.max(0, b.lowerBound());
+                                long maxP_b = b.upperBound();
+                                // Checkstyle: resume
+
+                                // multiplication has shift semantics
+                                long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
+
+                                if (a.canBePositive()) {
+                                    if (b.canBePositive()) {
+                                        if (multiplicationOverflows(maxP_a, maxP_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long maxCandidate = maxP_a * maxP_b;
+                                        if (multiplicationOverflows(minP_a, minP_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long minCandidate = minP_a * minP_b;
+                                        newLowerBound = Math.min(newLowerBound, minCandidate);
+                                        newUpperBound = Math.max(newUpperBound, maxCandidate);
+                                    }
+                                    if (b.canBeNegative()) {
+                                        if (multiplicationOverflows(minP_a, maxN_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long maxCandidate = minP_a * maxN_b;
+                                        if (multiplicationOverflows(maxP_a, minN_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long minCandidate = maxP_a * minN_b;
+                                        newLowerBound = Math.min(newLowerBound, minCandidate);
+                                        newUpperBound = Math.max(newUpperBound, maxCandidate);
+                                    }
+                                }
+                                if (a.canBeNegative()) {
+                                    if (b.canBePositive()) {
+                                        if (multiplicationOverflows(maxN_a, minP_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long maxCandidate = maxN_a * minP_b;
+                                        if (multiplicationOverflows(minN_a, maxP_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long minCandidate = minN_a * maxP_b;
+                                        newLowerBound = Math.min(newLowerBound, minCandidate);
+                                        newUpperBound = Math.max(newUpperBound, maxCandidate);
+                                    }
+                                    if (b.canBeNegative()) {
+                                        if (multiplicationOverflows(minN_a, minN_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long maxCandidate = minN_a * minN_b;
+                                        if (multiplicationOverflows(maxN_a, maxN_b, bits)) {
+                                            return a.unrestricted();
+                                        }
+                                        long minCandidate = maxN_a * maxN_b;
+                                        newLowerBound = Math.min(newLowerBound, minCandidate);
+                                        newUpperBound = Math.max(newUpperBound, maxCandidate);
+                                    }
+                                }
+
+                                assert newLowerBound <= newUpperBound;
+                                return StampFactory.forIntegerWithMask(bits, newLowerBound, newUpperBound, 0, newUpMask);
+                            }
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 1;
+                        }
+                    },
+
+                    new BinaryOp.Div(true, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() / b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            assert a.getBits() == b.getBits();
+                            if (b.isStrictlyPositive()) {
+                                long newLowerBound = a.lowerBound() / b.upperBound();
+                                long newUpperBound = a.upperBound() / b.lowerBound();
+                                return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+                            } else {
+                                return a.unrestricted();
+                            }
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 1;
+                        }
+                    },
+
+                    new BinaryOp.Rem(false, false) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() % b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            assert a.getBits() == b.getBits();
+                            // zero is always possible
+                            long newLowerBound = Math.min(a.lowerBound(), 0);
+                            long newUpperBound = Math.max(a.upperBound(), 0);
+
+                            /* the maximum absolute value of the result, derived from b */
+                            long magnitude;
+                            if (b.lowerBound() == CodeUtil.minValue(b.getBits())) {
+                                // Math.abs(...) - 1 does not work in a case
+                                magnitude = CodeUtil.maxValue(b.getBits());
+                            } else {
+                                magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1;
+                            }
+                            newLowerBound = Math.max(newLowerBound, -magnitude);
+                            newUpperBound = Math.min(newUpperBound, magnitude);
+
+                            return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+                        }
+                    },
+
+                    new UnaryOp.Not() {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forIntegerKind(value.getJavaKind(), ~value.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp) {
+                            IntegerStamp integerStamp = (IntegerStamp) stamp;
+                            int bits = integerStamp.getBits();
+                            long defaultMask = CodeUtil.mask(bits);
+                            return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
+                        }
+                    },
+
+                    new BinaryOp.And(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() & b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            assert a.getBits() == b.getBits();
+                            return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            int bits = n.getJavaKind().getBitCount();
+                            long mask = CodeUtil.mask(bits);
+                            return (n.asLong() & mask) == mask;
+                        }
+                    },
+
+                    new BinaryOp.Or(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() | b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            assert a.getBits() == b.getBits();
+                            return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 0;
+                        }
+                    },
+
+                    new BinaryOp.Xor(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() ^ b.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            assert a.getBits() == b.getBits();
+
+                            long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+                            long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
+                            long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
+                            return stampForMask(a.getBits(), newDownMask, newUpMask);
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            PrimitiveConstant n = (PrimitiveConstant) value;
+                            return n.asLong() == 0;
+                        }
+
+                        @Override
+                        public Constant getZero(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            return JavaConstant.forPrimitiveInt(stamp.getBits(), 0);
+                        }
+                    },
+
+                    new ShiftOp.Shl() {
+
+                        @Override
+                        public Constant foldConstant(Constant value, int amount) {
+                            PrimitiveConstant c = (PrimitiveConstant) value;
+                            switch (c.getJavaKind()) {
+                                case Int:
+                                    return JavaConstant.forInt(c.asInt() << amount);
+                                case Long:
+                                    return JavaConstant.forLong(c.asLong() << amount);
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+                            IntegerStamp value = (IntegerStamp) stamp;
+                            int bits = value.getBits();
+                            long defaultMask = CodeUtil.mask(bits);
+                            if (value.upMask() == 0) {
+                                return value;
+                            }
+                            int shiftMask = getShiftAmountMask(stamp);
+                            int shiftBits = Integer.bitCount(shiftMask);
+                            if (shift.lowerBound() == shift.upperBound()) {
+                                int shiftAmount = (int) (shift.lowerBound() & shiftMask);
+                                if (shiftAmount == 0) {
+                                    return value;
+                                }
+                                // the mask of bits that will be lost or shifted into the sign bit
+                                long removedBits = -1L << (bits - shiftAmount - 1);
+                                if ((value.lowerBound() & removedBits) == 0 && (value.upperBound() & removedBits) == 0) {
+                                    /*
+                                     * use a better stamp if neither lower nor upper bound can lose
+                                     * bits
+                                     */
+                                    return new IntegerStamp(bits, value.lowerBound() << shiftAmount, value.upperBound() << shiftAmount, value.downMask() << shiftAmount, value.upMask() << shiftAmount);
+                                }
+                            }
+                            if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) {
+                                long downMask = defaultMask;
+                                long upMask = 0;
+                                for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) {
+                                    if (shift.contains(i)) {
+                                        downMask &= value.downMask() << (i & shiftMask);
+                                        upMask |= value.upMask() << (i & shiftMask);
+                                    }
+                                }
+                                Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
+                                return result;
+                            }
+                            return value.unrestricted();
+                        }
+
+                        @Override
+                        public int getShiftAmountMask(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            assert CodeUtil.isPowerOf2(stamp.getBits());
+                            return stamp.getBits() - 1;
+                        }
+                    },
+
+                    new ShiftOp.Shr() {
+
+                        @Override
+                        public Constant foldConstant(Constant value, int amount) {
+                            PrimitiveConstant c = (PrimitiveConstant) value;
+                            switch (c.getJavaKind()) {
+                                case Int:
+                                    return JavaConstant.forInt(c.asInt() >> amount);
+                                case Long:
+                                    return JavaConstant.forLong(c.asLong() >> amount);
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+                            IntegerStamp value = (IntegerStamp) stamp;
+                            int bits = value.getBits();
+                            if (shift.lowerBound() == shift.upperBound()) {
+                                long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
+                                if (shiftCount == 0) {
+                                    return stamp;
+                                }
+
+                                int extraBits = 64 - bits;
+                                long defaultMask = CodeUtil.mask(bits);
+                                // shifting back and forth performs sign extension
+                                long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+                                long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+                                return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask);
+                            }
+                            long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
+                            return IntegerStamp.stampForMask(bits, 0, mask);
+                        }
+
+                        @Override
+                        public int getShiftAmountMask(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            assert CodeUtil.isPowerOf2(stamp.getBits());
+                            return stamp.getBits() - 1;
+                        }
+                    },
+
+                    new ShiftOp.UShr() {
+
+                        @Override
+                        public Constant foldConstant(Constant value, int amount) {
+                            PrimitiveConstant c = (PrimitiveConstant) value;
+                            switch (c.getJavaKind()) {
+                                case Int:
+                                    return JavaConstant.forInt(c.asInt() >>> amount);
+                                case Long:
+                                    return JavaConstant.forLong(c.asLong() >>> amount);
+                                default:
+                                    throw GraalError.shouldNotReachHere();
+                            }
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+                            IntegerStamp value = (IntegerStamp) stamp;
+                            int bits = value.getBits();
+                            if (shift.lowerBound() == shift.upperBound()) {
+                                long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
+                                if (shiftCount == 0) {
+                                    return stamp;
+                                }
+
+                                long downMask = value.downMask() >>> shiftCount;
+                                long upMask = value.upMask() >>> shiftCount;
+                                if (value.lowerBound() < 0) {
+                                    return new IntegerStamp(bits, downMask, upMask, downMask, upMask);
+                                } else {
+                                    return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask);
+                                }
+                            }
+                            long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
+                            return IntegerStamp.stampForMask(bits, 0, mask);
+                        }
+
+                        @Override
+                        public int getShiftAmountMask(Stamp s) {
+                            IntegerStamp stamp = (IntegerStamp) s;
+                            assert CodeUtil.isPowerOf2(stamp.getBits());
+                            return stamp.getBits() - 1;
+                        }
+                    },
+
+                    new UnaryOp.Abs() {
+
+                        @Override
+                        public Constant foldConstant(Constant value) {
+                            PrimitiveConstant c = (PrimitiveConstant) value;
+                            return JavaConstant.forIntegerKind(c.getJavaKind(), Math.abs(c.asLong()));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            int bits = stamp.getBits();
+                            if (stamp.lowerBound() == CodeUtil.minValue(bits)) {
+                                return input.unrestricted();
+                            } else {
+                                long limit = Math.max(-stamp.lowerBound(), stamp.upperBound());
+                                return StampFactory.forInteger(bits, 0, limit);
+                            }
+                        }
+                    },
+
+                    null,
+
+                    new IntegerConvertOp.ZeroExtend() {
+
+                        @Override
+                        public Constant foldConstant(int inputBits, int resultBits, Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.zeroExtend(value.asLong(), inputBits));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert inputBits == stamp.getBits();
+                            assert inputBits <= resultBits;
+
+                            long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
+                            long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
+
+                            if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
+                                /* signed range including 0 and -1 */
+                                /*
+                                 * after sign extension, the whole range from 0 to MAX_INT is
+                                 * possible
+                                 */
+                                return IntegerStamp.stampForMask(resultBits, downMask, upMask);
+                            }
+
+                            long lowerBound = CodeUtil.zeroExtend(stamp.lowerBound(), inputBits);
+                            long upperBound = CodeUtil.zeroExtend(stamp.upperBound(), inputBits);
+
+                            return new IntegerStamp(resultBits, lowerBound, upperBound, downMask, upMask);
+                        }
+                    },
+
+                    new IntegerConvertOp.SignExtend() {
+
+                        @Override
+                        public Constant foldConstant(int inputBits, int resultBits, Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.signExtend(value.asLong(), inputBits));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert inputBits == stamp.getBits();
+                            assert inputBits <= resultBits;
+
+                            long defaultMask = CodeUtil.mask(resultBits);
+                            long downMask = CodeUtil.signExtend(stamp.downMask(), inputBits) & defaultMask;
+                            long upMask = CodeUtil.signExtend(stamp.upMask(), inputBits) & defaultMask;
+
+                            return new IntegerStamp(resultBits, stamp.lowerBound(), stamp.upperBound(), downMask, upMask);
+                        }
+                    },
+
+                    new IntegerConvertOp.Narrow() {
+
+                        @Override
+                        public Constant foldConstant(int inputBits, int resultBits, Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.narrow(value.asLong(), resultBits));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert inputBits == stamp.getBits();
+                            assert resultBits <= inputBits;
+                            if (resultBits == inputBits) {
+                                return stamp;
+                            }
+
+                            final long upperBound;
+                            if (stamp.lowerBound() < CodeUtil.minValue(resultBits)) {
+                                upperBound = CodeUtil.maxValue(resultBits);
+                            } else {
+                                upperBound = saturate(stamp.upperBound(), resultBits);
+                            }
+                            final long lowerBound;
+                            if (stamp.upperBound() > CodeUtil.maxValue(resultBits)) {
+                                lowerBound = CodeUtil.minValue(resultBits);
+                            } else {
+                                lowerBound = saturate(stamp.lowerBound(), resultBits);
+                            }
+
+                            long defaultMask = CodeUtil.mask(resultBits);
+                            long newDownMask = stamp.downMask() & defaultMask;
+                            long newUpMask = stamp.upMask() & defaultMask;
+                            long newLowerBound = CodeUtil.signExtend((lowerBound | newDownMask) & newUpMask, resultBits);
+                            long newUpperBound = CodeUtil.signExtend((upperBound | newDownMask) & newUpMask, resultBits);
+                            return new IntegerStamp(resultBits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+                        }
+                    },
+
+                    new FloatConvertOp(I2F) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forFloat(value.asInt());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert stamp.getBits() == 32;
+                            float lowerBound = stamp.lowerBound();
+                            float upperBound = stamp.upperBound();
+                            return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true);
+                        }
+                    },
+
+                    new FloatConvertOp(L2F) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forFloat(value.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert stamp.getBits() == 64;
+                            float lowerBound = stamp.lowerBound();
+                            float upperBound = stamp.upperBound();
+                            return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true);
+                        }
+                    },
+
+                    new FloatConvertOp(I2D) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forDouble(value.asInt());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert stamp.getBits() == 32;
+                            double lowerBound = stamp.lowerBound();
+                            double upperBound = stamp.upperBound();
+                            return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true);
+                        }
+                    },
+
+                    new FloatConvertOp(L2D) {
+
+                        @Override
+                        public Constant foldConstant(Constant c) {
+                            PrimitiveConstant value = (PrimitiveConstant) c;
+                            return JavaConstant.forDouble(value.asLong());
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp input) {
+                            IntegerStamp stamp = (IntegerStamp) input;
+                            assert stamp.getBits() == 64;
+                            double lowerBound = stamp.lowerBound();
+                            double upperBound = stamp.upperBound();
+                            return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true);
+                        }
+                    });
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java
new file mode 100644
index 0000000..c9df001
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class ObjectStamp extends AbstractObjectStamp {
+
+    public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        super(type, exactType, nonNull, alwaysNull);
+    }
+
+    @Override
+    protected ObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        return new ObjectStamp(type, exactType, nonNull, alwaysNull);
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return StampFactory.object();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('a');
+        appendString(str);
+        return str.toString();
+    }
+
+    @Override
+    public boolean isCompatible(Stamp other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof ObjectStamp) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof JavaConstant) {
+            return ((JavaConstant) constant).getJavaKind().isObject();
+        }
+        return false;
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getObjectKind();
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        return provider.readObjectConstant(base, displacement);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java
new file mode 100644
index 0000000..4bd3e91
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+
+/**
+ * Type describing primitive values.
+ */
+public abstract class PrimitiveStamp extends ArithmeticStamp {
+
+    private final int bits;
+
+    protected PrimitiveStamp(int bits, ArithmeticOpTable ops) {
+        super(ops);
+        this.bits = bits;
+    }
+
+    /**
+     * The width in bits of the value described by this stamp.
+     */
+    public int getBits() {
+        return bits;
+    }
+
+    public static int getBits(Stamp stamp) {
+        if (stamp instanceof PrimitiveStamp) {
+            return ((PrimitiveStamp) stamp).getBits();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        return provider.readPrimitiveConstant(getStackKind(), base, displacement, getBits());
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + bits;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof PrimitiveStamp)) {
+            return false;
+        }
+        PrimitiveStamp other = (PrimitiveStamp) obj;
+        if (bits != other.bits) {
+            return false;
+        }
+        return super.equals(obj);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/RawPointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/RawPointerStamp.java
new file mode 100644
index 0000000..3715d0f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/RawPointerStamp.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Type describing pointers to raw memory. This stamp is used for example for direct pointers to
+ * fields or array elements.
+ */
+public class RawPointerStamp extends AbstractPointerStamp {
+
+    protected RawPointerStamp() {
+        super(false, false);
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getWordKind();
+    }
+
+    @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        // RawPointerStamp is a singleton
+        assert newNonNull == nonNull() && newAlwaysNull == alwaysNull();
+        return this;
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        assert isCompatible(other);
+        return this;
+    }
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        return this;
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        assert isCompatible(other);
+        return this;
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public Stamp empty() {
+        // there is no empty pointer stamp
+        return this;
+    }
+
+    @Override
+    public boolean hasValues() {
+        return true;
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        throw GraalError.shouldNotReachHere("pointer has no Java type");
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        return this;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp other) {
+        return other instanceof RawPointerStamp;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof PrimitiveConstant) {
+            return ((PrimitiveConstant) constant).getJavaKind().isNumericInteger();
+        } else {
+            return constant instanceof DataPointerConstant;
+        }
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        throw GraalError.shouldNotReachHere("can't read raw pointer");
+    }
+
+    @Override
+    public String toString() {
+        return "void*";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
new file mode 100644
index 0000000..0620856
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A stamp is the basis for a type system.
+ */
+public abstract class Stamp {
+
+    protected Stamp() {
+    }
+
+    /**
+     * Returns the type of the stamp, guaranteed to be non-null. In some cases, this requires the
+     * lookup of class meta data, therefore the {@link MetaAccessProvider} is mandatory.
+     */
+    public abstract ResolvedJavaType javaType(MetaAccessProvider metaAccess);
+
+    public boolean alwaysDistinct(Stamp other) {
+        return join(other).isEmpty();
+    }
+
+    /**
+     * Gets a Java {@link JavaKind} that can be used to store a value of this stamp on the Java
+     * bytecode stack. Returns {@link JavaKind#Illegal} if a value of this stamp can not be stored
+     * on the bytecode stack.
+     */
+    public abstract JavaKind getStackKind();
+
+    /**
+     * Gets a platform dependent {@link LIRKind} that can be used to store a value of this stamp.
+     */
+    public abstract LIRKind getLIRKind(LIRKindTool tool);
+
+    /**
+     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
+     * nodes.
+     *
+     * @param other The stamp that will enlarge this stamp.
+     * @return The union of this stamp and the given stamp.
+     */
+    public abstract Stamp meet(Stamp other);
+
+    /**
+     * Returns the intersection of this stamp and the given stamp.
+     *
+     * @param other The stamp that will tighten this stamp.
+     * @return The intersection of this stamp and the given stamp.
+     */
+    public abstract Stamp join(Stamp other);
+
+    /**
+     * Returns a stamp of the same kind, but allowing the full value range of the kind.
+     *
+     * {@link #unrestricted()} is the neutral element of the {@link #join(Stamp)} operation.
+     */
+    public abstract Stamp unrestricted();
+
+    /**
+     * Returns a stamp of the same kind, but with no allowed values.
+     *
+     * {@link #empty()} is the neutral element of the {@link #meet(Stamp)} operation.
+     */
+    public abstract Stamp empty();
+
+    /**
+     * If it is possible to represent single value stamps of this kind, this method returns the
+     * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c.
+     * <p>
+     * If it is not possible to represent single value stamps, this method returns a stamp that
+     * includes c, and is otherwise as narrow as possible.
+     */
+    public abstract Stamp constant(Constant c, MetaAccessProvider meta);
+
+    /**
+     * Test whether two stamps have the same base type.
+     */
+    public abstract boolean isCompatible(Stamp other);
+
+    /**
+     * Check that the constant {@code other} is compatible with this stamp.
+     *
+     * @param constant
+     */
+    public abstract boolean isCompatible(Constant constant);
+
+    /**
+     * Test whether this stamp has legal values.
+     */
+    public abstract boolean hasValues();
+
+    /**
+     * Tests whether this stamp represents an illegal value.
+     */
+    public final boolean isEmpty() {
+        return !hasValues();
+    }
+
+    /**
+     * If this stamp represents a single value, the methods returns this single value. It returns
+     * null otherwise.
+     *
+     * @return the constant corresponding to the single value of this stamp and null if this stamp
+     *         can represent less or more than one value.
+     */
+    public Constant asConstant() {
+        return null;
+    }
+
+    /**
+     * Read a value of this stamp from memory.
+     */
+    public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
+
+    /**
+     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
+     * improved stamp. Otherwise, returns a stamp equal to this.
+     *
+     * @param other the stamp that should be used to improve this stamp
+     * @return the newly improved stamp or a stamp equal to {@code this} if an improvement was not
+     *         possible
+     */
+    public abstract Stamp improveWith(Stamp other);
+
+    /**
+     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
+     * improved stamp. Otherwise, returns null.
+     *
+     * @param other the stamp that should be used to improve this stamp
+     * @return the newly improved stamp or {@code null} if an improvement was not possible
+     */
+    public final Stamp tryImproveWith(Stamp other) {
+        Stamp improved = improveWith(other);
+        if (improved.equals(this)) {
+            return null;
+        }
+        return improved;
+    }
+
+    public boolean neverDistinct(Stamp other) {
+        Constant constant = this.asConstant();
+        if (constant != null) {
+            Constant otherConstant = other.asConstant();
+            return otherConstant != null && constant.equals(otherConstant);
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java
new file mode 100644
index 0000000..7563067
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+public class StampFactory {
+
+    /*
+     * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a
+     * regular ObjectStamp.
+     */
+    static final class NodeIntrinsicStamp extends ObjectStamp {
+        protected static final Stamp SINGLETON = new NodeIntrinsicStamp();
+
+        private NodeIntrinsicStamp() {
+            super(null, false, false, false);
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+    }
+
+    // JaCoCo Exclude
+
+    private static final Stamp[] stampCache = new Stamp[JavaKind.values().length];
+    private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length];
+    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
+    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
+    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
+    private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
+    private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1);
+    private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0);
+    private static final Stamp rawPointer = new RawPointerStamp();
+
+    private static void setCache(JavaKind kind, Stamp stamp) {
+        stampCache[kind.ordinal()] = stamp;
+    }
+
+    private static void setIntCache(JavaKind kind) {
+        int bits = kind.getStackKind().getBitCount();
+        long mask;
+        if (kind.isUnsigned()) {
+            mask = CodeUtil.mask(kind.getBitCount());
+        } else {
+            mask = CodeUtil.mask(bits);
+        }
+        setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
+    }
+
+    private static void setFloatCache(JavaKind kind) {
+        setCache(kind, new FloatStamp(kind.getBitCount()));
+    }
+
+    static {
+        setIntCache(JavaKind.Boolean);
+        setIntCache(JavaKind.Byte);
+        setIntCache(JavaKind.Short);
+        setIntCache(JavaKind.Char);
+        setIntCache(JavaKind.Int);
+        setIntCache(JavaKind.Long);
+
+        setFloatCache(JavaKind.Float);
+        setFloatCache(JavaKind.Double);
+
+        setCache(JavaKind.Object, objectStamp);
+        setCache(JavaKind.Void, VoidStamp.getInstance());
+        setCache(JavaKind.Illegal, IllegalStamp.getInstance());
+
+        for (JavaKind k : JavaKind.values()) {
+            if (stampCache[k.ordinal()] != null) {
+                emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty();
+            }
+        }
+    }
+
+    public static Stamp tautology() {
+        return booleanTrue;
+    }
+
+    public static Stamp contradiction() {
+        return booleanFalse;
+    }
+
+    /**
+     * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
+     */
+    public static Stamp forKind(JavaKind kind) {
+        assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
+        return stampCache[kind.ordinal()];
+    }
+
+    /**
+     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
+     * compared using {@code ==}.
+     */
+    public static Stamp forVoid() {
+        return VoidStamp.getInstance();
+    }
+
+    /**
+     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
+     * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
+     */
+    public static Stamp forNodeIntrinsic() {
+        return NodeIntrinsicStamp.SINGLETON;
+    }
+
+    public static Stamp intValue() {
+        return forKind(JavaKind.Int);
+    }
+
+    public static Stamp positiveInt() {
+        return positiveInt;
+    }
+
+    public static Stamp empty(JavaKind kind) {
+        return emptyStampCache[kind.ordinal()];
+    }
+
+    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
+        return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
+    }
+
+    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
+        return forInteger(kind.getBitCount(), lowerBound, upperBound);
+    }
+
+    /**
+     * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the
+     * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating
+     * any mask information from {@code maskStamp}.
+     *
+     * @param bits
+     * @param newLowerBound
+     * @param newUpperBound
+     * @param maskStamp
+     * @return a new stamp with the appropriate bounds and masks
+     */
+    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
+        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+        return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
+    }
+
+    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
+        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+        return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
+    }
+
+    public static IntegerStamp forInteger(int bits) {
+        return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
+    }
+
+    public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
+        long defaultMask = CodeUtil.mask(bits);
+        if (lowerBound == upperBound) {
+            return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
+        }
+        final long downMask;
+        final long upMask;
+        if (lowerBound >= 0) {
+            int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
+            long differentBits = lowerBound ^ upperBound;
+            int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
+
+            upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
+            downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
+        } else {
+            if (upperBound >= 0) {
+                upMask = defaultMask;
+                downMask = 0;
+            } else {
+                int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
+                long differentBits = lowerBound ^ upperBound;
+                int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
+
+                upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
+                downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
+            }
+        }
+        return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
+    }
+
+    public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {
+        assert kind.isNumericFloat();
+        return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
+    }
+
+    public static Stamp forConstant(JavaConstant value) {
+        JavaKind kind = value.getJavaKind();
+        switch (kind) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+            case Long:
+                long mask = value.asLong() & CodeUtil.mask(kind.getBitCount());
+                return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
+            case Float:
+                return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
+            case Double:
+                return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
+            case Illegal:
+                return forKind(JavaKind.Illegal);
+            case Object:
+                if (value.isNull()) {
+                    return alwaysNull();
+                } else {
+                    return objectNonNull();
+                }
+            default:
+                throw new GraalError("unexpected kind: %s", kind);
+        }
+    }
+
+    public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) {
+        if (value.getJavaKind() == JavaKind.Object) {
+            ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
+            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
+        } else {
+            return forConstant(value);
+        }
+    }
+
+    public static Stamp object() {
+        return objectStamp;
+    }
+
+    public static Stamp objectNonNull() {
+        return objectNonNullStamp;
+    }
+
+    public static Stamp alwaysNull() {
+        return objectAlwaysNullStamp;
+    }
+
+    public static ObjectStamp object(TypeReference type) {
+        return object(type, false);
+    }
+
+    public static ObjectStamp objectNonNull(TypeReference type) {
+        return object(type, true);
+    }
+
+    public static ObjectStamp object(TypeReference type, boolean nonNull) {
+        if (type == null) {
+            return new ObjectStamp(null, false, nonNull, false);
+        } else {
+            return new ObjectStamp(type.getType(), type.isExact(), nonNull, false);
+        }
+    }
+
+    public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) {
+        Signature sig = method.getSignature();
+        Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())];
+        int index = 0;
+
+        if (!method.isStatic()) {
+            result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass()));
+        }
+
+        int max = sig.getParameterCount(false);
+        ResolvedJavaType accessingClass = method.getDeclaringClass();
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass);
+            JavaKind kind = type.getJavaKind();
+            Stamp stamp;
+            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type));
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            result[index++] = stamp;
+        }
+
+        return result;
+    }
+
+    public static Stamp pointer() {
+        return rawPointer;
+    }
+
+    public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) {
+        if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
+            ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType;
+            TypeReference reference = TypeReference.create(assumptions, resolvedJavaType);
+            if (resolvedJavaType.isInterface()) {
+                ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor();
+                if (implementor != null && !resolvedJavaType.equals(implementor)) {
+                    TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor);
+                    return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull));
+                }
+            }
+            return StampPair.createSingle(StampFactory.object(reference, nonNull));
+        } else {
+            return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind()));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampPair.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampPair.java
new file mode 100644
index 0000000..70ecd28
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampPair.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+/**
+ * A pair of stamp with one being the stamp that can be trusted and the other one being a guess that
+ * needs a dynamic check to be used.
+ */
+public final class StampPair {
+
+    private final Stamp trustedStamp;
+    private final Stamp uncheckedStamp;
+
+    private StampPair(Stamp trustedStamp, Stamp uncheckedStamp) {
+        assert trustedStamp != null;
+        this.trustedStamp = trustedStamp;
+        this.uncheckedStamp = uncheckedStamp;
+    }
+
+    public static StampPair create(Stamp trustedStamp, Stamp uncheckedStamp) {
+        return new StampPair(trustedStamp, uncheckedStamp);
+    }
+
+    public static StampPair createSingle(Stamp stamp) {
+        return new StampPair(stamp, null);
+    }
+
+    public Stamp getUncheckedStamp() {
+        return uncheckedStamp;
+    }
+
+    public Stamp getTrustedStamp() {
+        return trustedStamp;
+    }
+
+    @Override
+    public String toString() {
+        if (uncheckedStamp == null) {
+            return trustedStamp.toString();
+        } else {
+            return trustedStamp + " (unchecked=" + uncheckedStamp + ")";
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/TypeReference.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/TypeReference.java
new file mode 100644
index 0000000..a0be329
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/TypeReference.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * This class represents a reference to a Java type and whether this reference is referring only to
+ * the represented type or also to its sub types in the class hierarchy. When creating a type
+ * reference, the following options have to be considered:
+ *
+ * <ul>
+ * <li>The reference should always only refer to the given concrete type. Use
+ * {@link #createExactTrusted(ResolvedJavaType)} for this purpose.</li>
+ * <li>The reference should be created without assumptions about the class hierarchy. The returned
+ * reference is exact only when the type is a leaf type (i.e., it cannot have subclasses). Depending
+ * on whether interface types can be trusted for this type reference use
+ * {@link #createWithoutAssumptions} or {@link #createTrustedWithoutAssumptions}.</li>
+ * <li>The reference should be created using assumptions about the class hierarchy. The returned
+ * reference is also exact, when there is only a single concrete sub type for the given type.
+ * Depending on whether interface types can be trusted for this type reference use {@link #create}
+ * or {@link #createTrusted}.</li>
+ * </ul>
+ *
+ * For the methods with untrusted interface types, a {@code null} reference will be constructed for
+ * untrusted interface types. Examples for interface types that cannot be trusted are types for
+ * parameters, fields, and return values. They are not checked by the Java verifier.
+ *
+ */
+public final class TypeReference {
+    private final ResolvedJavaType type;
+    private final boolean exactReference;
+
+    private TypeReference(ResolvedJavaType type, boolean exactReference) {
+        this.type = type;
+        this.exactReference = exactReference;
+    }
+
+    /**
+     * Creates an exact type reference using the given type.
+     */
+    public static TypeReference createExactTrusted(ResolvedJavaType type) {
+        if (type == null) {
+            return null;
+        }
+        return new TypeReference(type, true);
+    }
+
+    /**
+     * Creates a type reference using the given type without assumptions and without trusting
+     * interface types.
+     */
+    public static TypeReference createWithoutAssumptions(ResolvedJavaType type) {
+        return create(null, type);
+    }
+
+    /**
+     * Creates a type reference using the given type without assumptions and trusting interface
+     * types.
+     */
+    public static TypeReference createTrustedWithoutAssumptions(ResolvedJavaType type) {
+        return createTrusted(null, type);
+    }
+
+    /**
+     * Creates a type reference using the given type with assumptions and without trusting interface
+     * types.
+     */
+    public static TypeReference create(Assumptions assumptions, ResolvedJavaType type) {
+        return createTrusted(assumptions, filterInterfaceTypesOut(type));
+    }
+
+    /**
+     * Create a type reference using the given type with assumptions and trusting interface types.
+     */
+    public static TypeReference createTrusted(Assumptions assumptions, ResolvedJavaType type) {
+        if (type == null) {
+            return null;
+        }
+        ResolvedJavaType exactType = type.isLeaf() ? type : null;
+        if (exactType == null) {
+            Assumptions.AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null && leafConcreteSubtype.canRecordTo(assumptions)) {
+                leafConcreteSubtype.recordTo(assumptions);
+                exactType = leafConcreteSubtype.getResult();
+            }
+        }
+        if (exactType == null) {
+            return new TypeReference(type, false);
+        }
+        return new TypeReference(exactType, true);
+    }
+
+    /**
+     * The type this reference refers to.
+     */
+    public ResolvedJavaType getType() {
+        return type;
+    }
+
+    /**
+     * @return {@code true} if this reference is exact and only refers to the given type and
+     *         {@code false} if it also refers to its sub types.
+     */
+    public boolean isExact() {
+        return exactReference;
+    }
+
+    /**
+     * @return A new reference that is guaranteed to be exact.
+     */
+    public TypeReference asExactReference() {
+        if (isExact()) {
+            return this;
+        }
+        return new TypeReference(type, true);
+    }
+
+    private static ResolvedJavaType filterInterfaceTypesOut(ResolvedJavaType type) {
+        if (type != null) {
+            if (type.isArray()) {
+                ResolvedJavaType componentType = filterInterfaceTypesOut(type.getComponentType());
+                if (componentType != null) {
+                    return componentType.getArrayClass();
+                }
+                // Returns Object[].class
+                return type.getSuperclass().getArrayClass();
+            }
+            if (type.isInterface()) {
+                return null;
+            }
+        }
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return (isExact() ? "#" : "") + type;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java
new file mode 100644
index 0000000..7d3ad60
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Singleton stamp representing the value of type {@code void}.
+ */
+public final class VoidStamp extends Stamp {
+
+    private VoidStamp() {
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public JavaKind getStackKind() {
+        return JavaKind.Void;
+    }
+
+    @Override
+    public Stamp improveWith(Stamp other) {
+        assert other instanceof VoidStamp;
+        return this;
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        throw GraalError.shouldNotReachHere("void stamp has no value");
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        return metaAccess.lookupJavaType(Void.TYPE);
+    }
+
+    @Override
+    public String toString() {
+        return "void";
+    }
+
+    @Override
+    public boolean alwaysDistinct(Stamp other) {
+        return this != other;
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        assert other instanceof VoidStamp;
+        return this;
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        assert other instanceof VoidStamp;
+        return this;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        return stamp instanceof VoidStamp;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        return false;
+    }
+
+    @Override
+    public Stamp empty() {
+        // the void stamp is always empty
+        return this;
+    }
+
+    @Override
+    public boolean hasValues() {
+        return false;
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        throw GraalError.shouldNotReachHere("can't read values of void stamp");
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        throw GraalError.shouldNotReachHere("void stamp has no value");
+    }
+
+    private static final VoidStamp instance = new VoidStamp();
+
+    static VoidStamp getInstance() {
+        return instance;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArrayMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArrayMap.java
new file mode 100644
index 0000000..e9a63ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArrayMap.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+/**
+ * The {@code ArrayMap} class implements an efficient one-level map which is implemented as an
+ * array. Note that because of the one-level array inside, this data structure performs best when
+ * the range of integer keys is small and densely used. Note that the implementation can handle
+ * arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1.
+ */
+public class ArrayMap<T> {
+
+    private static final int INITIAL_SIZE = 5; // how big the initial array should be
+    private static final int EXTRA = 2; // how far on the left or right of a new element to grow
+
+    Object[] map;
+    int low;
+
+    /**
+     * Constructs a new {@code ArrayMap} with no initial assumptions.
+     */
+    public ArrayMap() {
+    }
+
+    /**
+     * Constructs a new {@code ArrayMap} that initially covers the specified interval. Note that
+     * this map will automatically expand if necessary later.
+     *
+     * @param low the low index, inclusive
+     * @param high the high index, exclusive
+     */
+    public ArrayMap(int low, int high) {
+        this.low = low;
+        this.map = new Object[high - low + 1];
+    }
+
+    /**
+     * Puts a new value in the map at the specified index.
+     *
+     * @param i the index at which to store the value
+     * @param value the value to store at the specified index
+     */
+    public void put(int i, T value) {
+        int index = i - low;
+        if (map == null) {
+            // no map yet
+            map = new Object[INITIAL_SIZE];
+            low = index - 2;
+            map[INITIAL_SIZE / 2] = value;
+        } else if (index < 0) {
+            // grow backwards
+            growBackward(i, value);
+        } else if (index >= map.length) {
+            // grow forwards
+            growForward(i, value);
+        } else {
+            // no growth necessary
+            map[index] = value;
+        }
+    }
+
+    /**
+     * Gets the value at the specified index in the map.
+     *
+     * @param i the index
+     * @return the value at the specified index; {@code null} if there is no value at the specified
+     *         index, or if the index is out of the currently stored range
+     */
+    public T get(int i) {
+        int index = i - low;
+        if (map == null || index < 0 || index >= map.length) {
+            return null;
+        }
+        Class<T> type = null;
+        return Util.uncheckedCast(type, map[index]);
+    }
+
+    public int length() {
+        return map.length;
+    }
+
+    private void growBackward(int i, T value) {
+        int nlow = i - EXTRA;
+        Object[] nmap = new Object[low - nlow + map.length];
+        System.arraycopy(map, 0, nmap, low - nlow, map.length);
+        map = nmap;
+        low = nlow;
+        map[i - low] = value;
+    }
+
+    private void growForward(int i, T value) {
+        int nlen = i - low + 1 + EXTRA;
+        Object[] nmap = new Object[nlen];
+        System.arraycopy(map, 0, nmap, 0, map.length);
+        map = nmap;
+        map[i - low] = value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArraySet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArraySet.java
new file mode 100644
index 0000000..cf4a882
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ArraySet.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Mimic a set implementation with an ArrayList. Beneficial for small sets (compared to
+ * {@link HashSet}).
+ */
+public class ArraySet<E> extends ArrayList<E> implements Set<E> {
+    private static final long serialVersionUID = 4476957522387436654L;
+
+    public ArraySet() {
+        super();
+    }
+
+    public ArraySet(int i) {
+        super(i);
+    }
+
+    public ArraySet(Collection<? extends E> c) {
+        super(c);
+    }
+
+    @Override
+    public boolean add(E e) {
+        // avoid duplicated entries
+        if (contains(e)) {
+            return false;
+        }
+        return super.add(e);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/BitMap2D.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/BitMap2D.java
new file mode 100644
index 0000000..d09ccf9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/BitMap2D.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import java.util.BitSet;
+
+/**
+ * This class implements a two-dimensional bitmap.
+ */
+public final class BitMap2D {
+
+    private BitSet map;
+    private final int bitsPerSlot;
+
+    private int bitIndex(int slotIndex, int bitWithinSlotIndex) {
+        return slotIndex * bitsPerSlot + bitWithinSlotIndex;
+    }
+
+    private boolean verifyBitWithinSlotIndex(int index) {
+        assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot;
+        return true;
+    }
+
+    public BitMap2D(int sizeInSlots, int bitsPerSlot) {
+        map = new BitSet(sizeInSlots * bitsPerSlot);
+        this.bitsPerSlot = bitsPerSlot;
+    }
+
+    public int sizeInBits() {
+        return map.size();
+    }
+
+    // Returns number of full slots that have been allocated
+    public int sizeInSlots() {
+        return map.size() / bitsPerSlot;
+    }
+
+    public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) {
+        assert verifyBitWithinSlotIndex(bitWithinSlotIndex);
+        return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits());
+    }
+
+    public boolean at(int slotIndex, int bitWithinSlotIndex) {
+        assert verifyBitWithinSlotIndex(bitWithinSlotIndex);
+        return map.get(bitIndex(slotIndex, bitWithinSlotIndex));
+    }
+
+    public void setBit(int slotIndex, int bitWithinSlotIndex) {
+        assert verifyBitWithinSlotIndex(bitWithinSlotIndex);
+        map.set(bitIndex(slotIndex, bitWithinSlotIndex));
+    }
+
+    public void clearBit(int slotIndex, int bitWithinSlotIndex) {
+        assert verifyBitWithinSlotIndex(bitWithinSlotIndex);
+        map.clear(bitIndex(slotIndex, bitWithinSlotIndex));
+    }
+
+    public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) {
+        int size = sizeInSlots();
+        if (size <= slotIndex) {
+            while (size <= slotIndex) {
+                size *= 2;
+            }
+            BitSet newBitMap = new BitSet(size * bitsPerSlot);
+            newBitMap.or(map);
+            map = newBitMap;
+        }
+
+        if (value) {
+            setBit(slotIndex, bitWithinSlotIndex);
+        } else {
+            clearBit(slotIndex, bitWithinSlotIndex);
+        }
+    }
+
+    public void clear() {
+        map.clear();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/CompilationAlarm.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/CompilationAlarm.java
new file mode 100644
index 0000000..f97b171
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/CompilationAlarm.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Utility class that allows the compiler to monitor compilations that take a very long time.
+ */
+public final class CompilationAlarm implements AutoCloseable {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Time limit in seconds before a compilation expires (0 to disable the limit).", type = OptionType.Debug)
+        public static final OptionValue<Integer> CompilationExpirationPeriod = new OptionValue<>(300);
+        // @formatter:on
+    }
+
+    private CompilationAlarm() {
+    }
+
+    private static boolean enabled() {
+        return Options.CompilationExpirationPeriod.getValue() > 0;
+    }
+
+    /**
+     * Thread local storage for compilation start timestamps. Everytime a compiler thread calls
+     * {@link #trackCompilationPeriod()} it will save the start timestamp of the compilation.
+     */
+    private static final ThreadLocal<Long> compilationStartedTimeStamps = new ThreadLocal<>();
+
+    private static boolean compilationStarted() {
+        if (enabled()) {
+            Long start = compilationStartedTimeStamps.get();
+            if (start == null) {
+                compilationStartedTimeStamps.set(System.currentTimeMillis());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void compilationFinished() {
+        if (enabled()) {
+            assert compilationStartedTimeStamps.get() != null;
+            compilationStartedTimeStamps.set(null);
+        }
+    }
+
+    /**
+     * Determines if the current compilation is expired. A compilation expires if it takes longer
+     * than {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}.
+     *
+     * @return {@code true} if the current compilation already takes longer than
+     *         {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}, {@code false}
+     *         otherwise
+     */
+    public static boolean hasExpired() {
+        if (enabled()) {
+            Long start = compilationStartedTimeStamps.get();
+            if (start != null) {
+                long time = System.currentTimeMillis();
+                assert time >= start;
+                return time - start > Options.CompilationExpirationPeriod.getValue() * 1000;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void close() {
+        compilationFinished();
+    }
+
+    private static final CompilationAlarm INSTANCE = enabled() ? new CompilationAlarm() : null;
+
+    /**
+     * Gets an object that can be used in a try-with-resource statement to set an time limit based
+     * alarm for a compilation.
+     *
+     * @return a {@link CompilationAlarm} instance if there is no current alarm for the calling
+     *         thread otherwise {@code null}
+     */
+    public static CompilationAlarm trackCompilationPeriod() {
+        if (compilationStarted()) {
+            return INSTANCE;
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java
new file mode 100644
index 0000000..7367546
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Creates an array of T objects order by the occurrence frequency of each object. The most
+ * frequently used object is the first one, the least frequently used the last one. If {@code null}
+ * is added, it is always the first element.
+ *
+ * Either object {@link #createIdentityEncoder() identity} or object {@link #createEqualityEncoder()
+ * equality} can be used to build the array and count the frequency.
+ */
+public class FrequencyEncoder<T> {
+
+    static class Entry<T> {
+        protected final T object;
+        protected int frequency;
+        protected int index;
+
+        protected Entry(T object) {
+            this.object = object;
+            this.index = -1;
+        }
+    }
+
+    protected final Map<T, Entry<T>> map;
+    protected boolean containsNull;
+
+    /**
+     * Creates an encoder that uses object identity.
+     */
+    public static <T> FrequencyEncoder<T> createIdentityEncoder() {
+        return new FrequencyEncoder<>(new IdentityHashMap<>());
+    }
+
+    /**
+     * Creates an encoder that uses {@link Object#equals(Object) object equality}.
+     */
+    public static <T> FrequencyEncoder<T> createEqualityEncoder() {
+        return new FrequencyEncoder<>(new HashMap<>());
+    }
+
+    protected FrequencyEncoder(Map<T, Entry<T>> map) {
+        this.map = map;
+    }
+
+    /**
+     * Adds an object to the array.
+     */
+    public void addObject(T object) {
+        if (object == null) {
+            containsNull = true;
+            return;
+        }
+
+        Entry<T> entry = map.get(object);
+        if (entry == null) {
+            entry = new Entry<>(object);
+            map.put(object, entry);
+        }
+        entry.frequency++;
+    }
+
+    /**
+     * Returns the index of an object in the array. The object must have been
+     * {@link #addObject(Object) added} before.
+     */
+    public int getIndex(Object object) {
+        if (object == null) {
+            assert containsNull;
+            return 0;
+        }
+        Entry<T> entry = map.get(object);
+        assert entry != null && entry.index >= 0;
+        return entry.index;
+    }
+
+    /**
+     * Returns the number of distinct objects that have been added, i.e., the length of the array.
+     */
+    public int getLength() {
+        return map.size() + (containsNull ? 1 : 0);
+    }
+
+    /**
+     * Fills the provided array with the added objects. The array must have the {@link #getLength()
+     * correct length}.
+     */
+    public T[] encodeAll(T[] allObjects) {
+        assert allObjects.length == getLength();
+        List<Entry<T>> sortedEntries = new ArrayList<>(map.values());
+        sortedEntries.sort((e1, e2) -> -Integer.compare(e1.frequency, e2.frequency));
+
+        int offset = 0;
+        if (containsNull) {
+            allObjects[0] = null;
+            offset = 1;
+        }
+        for (int i = 0; i < sortedEntries.size(); i++) {
+            Entry<T> entry = sortedEntries.get(i);
+            int index = i + offset;
+            entry.index = index;
+            allObjects[index] = entry.object;
+            assert entry.object != null;
+        }
+        return allObjects;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/IntList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/IntList.java
new file mode 100644
index 0000000..6f58e68
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/IntList.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import java.util.Arrays;
+
+/**
+ * An expandable and indexable list of {@code int}s.
+ *
+ * This class avoids the boxing/unboxing incurred by {@code ArrayList<Integer>}.
+ */
+public final class IntList {
+
+    private int[] array;
+    private int size;
+
+    /**
+     * Creates an int list with a specified initial capacity.
+     *
+     * @param initialCapacity
+     */
+    public IntList(int initialCapacity) {
+        array = new int[initialCapacity];
+    }
+
+    /**
+     * Creates an int list with a specified initial array.
+     *
+     * @param array the initial array used for the list (no copy is made)
+     * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or
+     *            equal to {@code array.length}
+     */
+    public IntList(int[] array, int initialSize) {
+        assert initialSize <= array.length;
+        this.array = array;
+        this.size = initialSize;
+    }
+
+    /**
+     * Makes a new int list by copying a range from a given int list.
+     *
+     * @param other the list from which a range of values is to be copied into the new list
+     * @param startIndex the index in {@code other} at which to start copying
+     * @param length the number of values to copy from {@code other}
+     * @return a new int list whose {@linkplain #size() size} and capacity is {@code length}
+     */
+    public static IntList copy(IntList other, int startIndex, int length) {
+        return copy(other, startIndex, length, length);
+    }
+
+    /**
+     * Makes a new int list by copying a range from a given int list.
+     *
+     * @param other the list from which a range of values is to be copied into the new list
+     * @param startIndex the index in {@code other} at which to start copying
+     * @param length the number of values to copy from {@code other}
+     * @param initialCapacity the initial capacity of the new int list (must be greater or equal to
+     *            {@code length})
+     * @return a new int list whose {@linkplain #size() size} is {@code length}
+     */
+    public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) {
+        assert initialCapacity >= length : "initialCapacity < length";
+        int[] array = new int[initialCapacity];
+        System.arraycopy(other.array, startIndex, array, 0, length);
+        return new IntList(array, length);
+    }
+
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1.
+     *
+     * @param value the value to append
+     */
+    public void add(int value) {
+        if (size == array.length) {
+            int newSize = (size * 3) / 2 + 1;
+            array = Arrays.copyOf(array, newSize);
+        }
+        array[size++] = value;
+    }
+
+    /**
+     * Gets the value in this list at a given index.
+     *
+     * @param index the index of the element to return
+     * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()}
+     */
+    public int get(int index) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+        }
+        return array[index];
+    }
+
+    /**
+     * Sets the size of this list to 0.
+     */
+    public void clear() {
+        size = 0;
+    }
+
+    /**
+     * Sets a value at a given index in this list.
+     *
+     * @param index the index of the element to update
+     * @param value the new value of the element
+     * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()}
+     */
+    public void set(int index, int value) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+        }
+        array[index] = value;
+    }
+
+    /**
+     * Adjusts the {@linkplain #size() size} of this int list.
+     *
+     * If {@code newSize < size()}, the size is changed to {@code newSize}. If
+     * {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} until
+     * {@code size() == newSize}.
+     *
+     * @param newSize the new size of this int list
+     */
+    public void setSize(int newSize) {
+        if (newSize < size) {
+            size = newSize;
+        } else if (newSize > size) {
+            array = Arrays.copyOf(array, newSize);
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (array.length == size) {
+            return Arrays.toString(array);
+        }
+        return Arrays.toString(Arrays.copyOf(array, size));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java
new file mode 100644
index 0000000..240fdc0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Reflection based access to the Module API introduced by JDK 9. This allows the API to be used in
+ * code that must be compiled on a JDK prior to 9. Use of this class must be guarded by a test for
+ * JDK 9 or later. For example:
+ *
+ * <pre>
+ * if (Util.JAVA_SPECIFICATION_VERSION >= 9) {
+ *     // Use of ModuleAPI
+ * }
+ * </pre>
+ */
+public final class ModuleAPI {
+
+    private ModuleAPI(Method method) {
+        this.method = method;
+    }
+
+    private final Method method;
+
+    /**
+     * {@code Class.getModule()}.
+     */
+    public static final ModuleAPI getModule;
+
+    /**
+     * {@code jdk.internal.module.Modules.addExports(Module, String, Module)}.
+     */
+    public static final ModuleAPI addExports;
+
+    /**
+     * {@code java.lang.reflect.Module.getResourceAsStream(String)}.
+     */
+    public static final ModuleAPI getResourceAsStream;
+
+    /**
+     * {@code java.lang.reflect.Module.canRead(Module)}.
+     */
+    public static final ModuleAPI canRead;
+
+    /**
+     * {@code java.lang.reflect.Module.isExported(String)}.
+     */
+    public static final ModuleAPI isExported;
+
+    /**
+     * {@code java.lang.reflect.Module.isExported(String, Module)}.
+     */
+    public static final ModuleAPI isExportedTo;
+
+    /**
+     * Invokes the static Module API method represented by this object.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T invokeStatic(Object... args) {
+        checkAvailability();
+        assert Modifier.isStatic(method.getModifiers());
+        try {
+            return (T) method.invoke(null, args);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Invokes the non-static Module API method represented by this object.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T invoke(Object receiver, Object... args) {
+        checkAvailability();
+        assert !Modifier.isStatic(method.getModifiers());
+        try {
+            return (T) method.invoke(receiver, args);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private void checkAvailability() throws InternalError {
+        if (method == null) {
+            throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
+        }
+    }
+
+    static {
+        if (JAVA_SPECIFICATION_VERSION >= 9) {
+            try {
+                getModule = new ModuleAPI(Class.class.getMethod("getModule"));
+                Class<?> moduleClass = getModule.method.getReturnType();
+                Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
+                getResourceAsStream = new ModuleAPI(moduleClass.getMethod("getResourceAsStream", String.class));
+                canRead = new ModuleAPI(moduleClass.getMethod("canRead", moduleClass));
+                isExported = new ModuleAPI(moduleClass.getMethod("isExported", String.class));
+                isExportedTo = new ModuleAPI(moduleClass.getMethod("isExported", String.class, moduleClass));
+                addExports = new ModuleAPI(modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass));
+            } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
+                throw new InternalError(e);
+            }
+        } else {
+            ModuleAPI unavailable = new ModuleAPI(null);
+            getModule = unavailable;
+            getResourceAsStream = unavailable;
+            canRead = unavailable;
+            isExported = unavailable;
+            isExportedTo = unavailable;
+            addExports = unavailable;
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeConversion.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeConversion.java
new file mode 100644
index 0000000..834adea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeConversion.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+/**
+ * Provides low-level value checks and conversion for signed and unsigned values of size 1, 2, and 4
+ * bytes.
+ */
+public class TypeConversion {
+
+    public static boolean isS1(long value) {
+        return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
+    }
+
+    public static boolean isU1(long value) {
+        return value >= 0 && value <= 0xFF;
+    }
+
+    public static boolean isS2(long value) {
+        return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE;
+    }
+
+    public static boolean isU2(long value) {
+        return value >= 0 && value <= 0xFFFF;
+    }
+
+    public static boolean isS4(long value) {
+        return value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE;
+    }
+
+    public static boolean isU4(long value) {
+        return value >= 0 && value <= 0xFFFFFFFFL;
+    }
+
+    public static byte asS1(long value) {
+        assert isS1(value);
+        return (byte) value;
+    }
+
+    public static byte asU1(long value) {
+        assert isU1(value);
+        return (byte) value;
+    }
+
+    public static short asS2(long value) {
+        assert isS2(value);
+        return (short) value;
+    }
+
+    public static short asU2(long value) {
+        assert isU2(value);
+        return (short) value;
+    }
+
+    public static int asS4(long value) {
+        assert isS4(value);
+        return (int) value;
+    }
+
+    public static int asU4(long value) {
+        assert isU4(value);
+        return (int) value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeReader.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeReader.java
new file mode 100644
index 0000000..c67ed66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeReader.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+/**
+ * Provides low-level read access for signed and unsigned values of size 1, 2, 4, and 8 bytes.
+ */
+public interface TypeReader {
+
+    /** Returns the next byte index to be read. */
+    long getByteIndex();
+
+    /** Sets the next byte index to be read. */
+    void setByteIndex(long byteIndex);
+
+    /** Reads a signed 1 byte value. */
+    int getS1();
+
+    /** Reads an unsigned 1 byte value. */
+    int getU1();
+
+    /** Reads a signed 2 byte value. */
+    int getS2();
+
+    /** Reads an unsigned 2 byte value. */
+    int getU2();
+
+    /** Reads a signed 4 byte value. */
+    int getS4();
+
+    /** Reads an unsigned 4 byte value. */
+    long getU4();
+
+    /** Reads a signed 4 byte value. */
+    long getS8();
+
+    /**
+     * Reads a signed value that has been written using {@link TypeWriter#putSV variable byte size
+     * encoding}.
+     */
+    default long getSV() {
+        long result = 0;
+        int shift = 0;
+        long b;
+        do {
+            b = getU1();
+            result |= (b & 0x7f) << shift;
+            shift += 7;
+        } while ((b & 0x80) != 0);
+
+        if ((b & 0x40) != 0 && shift < 64) {
+            result |= -1L << shift;
+        }
+        return result;
+    }
+
+    /**
+     * Reads a signed variable byte size encoded value that is known to fit into the range of int.
+     */
+    default int getSVInt() {
+        return TypeConversion.asS4(getSV());
+    }
+
+    /**
+     * Reads an unsigned value that has been written using {@link TypeWriter#putSV variable byte
+     * size encoding}.
+     */
+    default long getUV() {
+        long result = 0;
+        int shift = 0;
+        long b;
+        do {
+            b = getU1();
+            result |= (b & 0x7f) << shift;
+            shift += 7;
+        } while ((b & 0x80) != 0);
+
+        return result;
+    }
+
+    /**
+     * Reads an unsigned variable byte size encoded value that is known to fit into the range of
+     * int.
+     */
+    default int getUVInt() {
+        return TypeConversion.asS4(getUV());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeWriter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeWriter.java
new file mode 100644
index 0000000..b4b35ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/TypeWriter.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+/**
+ * Provides low-level sequential write access for signed and unsigned values of size 1, 2, 4, and 8
+ * bytes.
+ */
+public interface TypeWriter {
+
+    /**
+     * Returns the number of bytes that have been written, i.e., the byte index of the next byte to
+     * be written.
+     */
+    long getBytesWritten();
+
+    /** Writes a signed 1 byte value. */
+    void putS1(long value);
+
+    /** Writes an unsigned 1 byte value. */
+    void putU1(long value);
+
+    /** Writes a signed 2 byte value. */
+    void putS2(long value);
+
+    /** Writes an unsigned 2 byte value. */
+    void putU2(long value);
+
+    /** Writes a signed 4 byte value. */
+    void putS4(long value);
+
+    /** Writes an unsigned 4 byte value. */
+    void putU4(long value);
+
+    /** Writes a signed 8 byte value. */
+    void putS8(long value);
+
+    /**
+     * Writes a signed value in a variable byte size encoding.
+     */
+    default void putSV(long value) {
+        long cur = value;
+        while (true) {
+            if (cur >= -64 && cur < 64) {
+                putU1(cur & 0x7f);
+                return;
+            }
+            putU1(0x80 | (cur & 0x7f));
+            cur = cur >> 7;
+        }
+    }
+
+    /**
+     * Writes an unsigned value in a variable byte size encoding.
+     */
+    default void putUV(long value) {
+        long cur = value;
+        while (true) {
+            assert cur >= 0;
+            if (cur < 128) {
+                putU1(cur & 0x7f);
+                return;
+            }
+            putU1(0x80 | (cur & 0x7f));
+            cur = cur >> 7;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java
new file mode 100644
index 0000000..8013ed2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java
new file mode 100644
index 0000000..66b6e8f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import static org.graalvm.compiler.core.common.util.UnsafeAccess.UNSAFE;
+import sun.misc.Unsafe;
+
+/**
+ * Provides low-level read access from a byte[] array for signed and unsigned values of size 1, 2,
+ * 4, and 8 bytes.
+ *
+ * The class can either be instantiated for sequential access to the byte[] array; or static methods
+ * can be used to read values without the overhead of creating an instance.
+ *
+ * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the
+ * hardware architecture: the value {@code true} allows more efficient memory access on
+ * architectures that support unaligned memory accesses; the value {@code false} is the safe
+ * fallback that works on every hardware.
+ */
+public abstract class UnsafeArrayTypeReader implements TypeReader {
+
+    public static int getS1(byte[] data, long byteIndex) {
+        return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES));
+    }
+
+    public static int getU1(byte[] data, long byteIndex) {
+        return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES)) & 0xFF;
+    }
+
+    public static int getS2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        if (supportsUnalignedMemoryAccess) {
+            return UnalignedUnsafeArrayTypeReader.getS2(data, byteIndex);
+        } else {
+            return AlignedUnsafeArrayTypeReader.getS2(data, byteIndex);
+        }
+    }
+
+    public static int getU2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        return getS2(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFF;
+    }
+
+    public static int getS4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        if (supportsUnalignedMemoryAccess) {
+            return UnalignedUnsafeArrayTypeReader.getS4(data, byteIndex);
+        } else {
+            return AlignedUnsafeArrayTypeReader.getS4(data, byteIndex);
+        }
+    }
+
+    public static long getU4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        return getS4(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFFFFFFL;
+    }
+
+    public static long getS8(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        if (supportsUnalignedMemoryAccess) {
+            return UnalignedUnsafeArrayTypeReader.getS8(data, byteIndex);
+        } else {
+            return AlignedUnsafeArrayTypeReader.getS8(data, byteIndex);
+        }
+    }
+
+    protected static long readOffset(byte[] data, long byteIndex, int numBytes) {
+        assert byteIndex >= 0;
+        assert numBytes > 0;
+        assert byteIndex + numBytes <= data.length;
+        assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1;
+
+        return byteIndex + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+    }
+
+    public static UnsafeArrayTypeReader create(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) {
+        if (supportsUnalignedMemoryAccess) {
+            return new UnalignedUnsafeArrayTypeReader(data, byteIndex);
+        } else {
+            return new AlignedUnsafeArrayTypeReader(data, byteIndex);
+        }
+    }
+
+    protected final byte[] data;
+    protected long byteIndex;
+
+    protected UnsafeArrayTypeReader(byte[] data, long byteIndex) {
+        this.data = data;
+        this.byteIndex = byteIndex;
+    }
+
+    @Override
+    public long getByteIndex() {
+        return byteIndex;
+    }
+
+    @Override
+    public void setByteIndex(long byteIndex) {
+        this.byteIndex = byteIndex;
+    }
+
+    @Override
+    public final int getS1() {
+        int result = getS1(data, byteIndex);
+        byteIndex += Byte.BYTES;
+        return result;
+    }
+
+    @Override
+    public final int getU1() {
+        int result = getU1(data, byteIndex);
+        byteIndex += Byte.BYTES;
+        return result;
+    }
+
+    @Override
+    public final int getU2() {
+        return getS2() & 0xFFFF;
+    }
+
+    @Override
+    public final long getU4() {
+        return getS4() & 0xFFFFFFFFL;
+    }
+}
+
+final class UnalignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader {
+    protected static int getS2(byte[] data, long byteIndex) {
+        return UNSAFE.getShort(data, readOffset(data, byteIndex, Short.BYTES));
+    }
+
+    protected static int getS4(byte[] data, long byteIndex) {
+        return UNSAFE.getInt(data, readOffset(data, byteIndex, Integer.BYTES));
+    }
+
+    protected static long getS8(byte[] data, long byteIndex) {
+        return UNSAFE.getLong(data, readOffset(data, byteIndex, Long.BYTES));
+    }
+
+    protected UnalignedUnsafeArrayTypeReader(byte[] data, long byteIndex) {
+        super(data, byteIndex);
+    }
+
+    @Override
+    public int getS2() {
+        int result = getS2(data, byteIndex);
+        byteIndex += Short.BYTES;
+        return result;
+    }
+
+    @Override
+    public int getS4() {
+        int result = getS4(data, byteIndex);
+        byteIndex += Integer.BYTES;
+        return result;
+    }
+
+    @Override
+    public long getS8() {
+        long result = getS8(data, byteIndex);
+        byteIndex += Long.BYTES;
+        return result;
+    }
+}
+
+class AlignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader {
+    protected static int getS2(byte[] data, long byteIndex) {
+        long offset = readOffset(data, byteIndex, Short.BYTES);
+        return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | //
+                        (UNSAFE.getByte(data, offset + 1) << 8);
+    }
+
+    protected static int getS4(byte[] data, long byteIndex) {
+        long offset = readOffset(data, byteIndex, Integer.BYTES);
+        return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | //
+                        ((UNSAFE.getByte(data, offset + 1) & 0xFF) << 8) | //
+                        ((UNSAFE.getByte(data, offset + 2) & 0xFF) << 16) | //
+                        (UNSAFE.getByte(data, offset + 3) << 24);
+    }
+
+    protected static long getS8(byte[] data, long byteIndex) {
+        long offset = readOffset(data, byteIndex, Long.BYTES);
+        return ((long) ((UNSAFE.getByte(data, offset + 0) & 0xFF)) << 0) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 1) & 0xFF)) << 8) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 2) & 0xFF)) << 16) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 3) & 0xFF)) << 24) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 4) & 0xFF)) << 32) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 5) & 0xFF)) << 40) | //
+                        ((long) ((UNSAFE.getByte(data, offset + 6) & 0xFF)) << 48) | //
+                        ((long) (UNSAFE.getByte(data, offset + 7)) << 56);
+    }
+
+    protected AlignedUnsafeArrayTypeReader(byte[] data, long byteIndex) {
+        super(data, byteIndex);
+    }
+
+    @Override
+    public int getS2() {
+        int result = getS2(data, byteIndex);
+        byteIndex += Short.BYTES;
+        return result;
+    }
+
+    @Override
+    public int getS4() {
+        int result = getS4(data, byteIndex);
+        byteIndex += Integer.BYTES;
+        return result;
+    }
+
+    @Override
+    public long getS8() {
+        long result = getS8(data, byteIndex);
+        byteIndex += Long.BYTES;
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java
new file mode 100644
index 0000000..00946ce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import static org.graalvm.compiler.core.common.util.TypeConversion.asS1;
+import static org.graalvm.compiler.core.common.util.TypeConversion.asS2;
+import static org.graalvm.compiler.core.common.util.TypeConversion.asS4;
+import static org.graalvm.compiler.core.common.util.TypeConversion.asU1;
+import static org.graalvm.compiler.core.common.util.TypeConversion.asU2;
+import static org.graalvm.compiler.core.common.util.TypeConversion.asU4;
+import sun.misc.Unsafe;
+
+/**
+ * Provides low-level sequential write access to a byte[] array for signed and unsigned values of
+ * size 1, 2, 4, and 8 bytes. To avoid copying an array when the buffer size is no longer
+ * sufficient, the buffer is split into chunks of a fixed size.
+ *
+ * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the
+ * hardware architecture: the value {@code true} allows more efficient memory access on
+ * architectures that support unaligned memory accesses; the value {@code false} is the safe
+ * fallback that works on every hardware.
+ */
+public abstract class UnsafeArrayTypeWriter implements TypeWriter {
+
+    private static final int MIN_CHUNK_LENGTH = 200;
+    private static final int MAX_CHUNK_LENGTH = 16000;
+
+    static class Chunk {
+        protected final byte[] data;
+        protected int size;
+        protected Chunk next;
+
+        protected Chunk(int arrayLength) {
+            data = new byte[arrayLength];
+        }
+    }
+
+    protected final Chunk firstChunk;
+    protected Chunk writeChunk;
+    protected int totalSize;
+
+    public static UnsafeArrayTypeWriter create(boolean supportsUnalignedMemoryAccess) {
+        if (supportsUnalignedMemoryAccess) {
+            return new UnalignedUnsafeArrayTypeWriter();
+        } else {
+            return new AlignedUnsafeArrayTypeWriter();
+        }
+    }
+
+    protected UnsafeArrayTypeWriter() {
+        firstChunk = new Chunk(MIN_CHUNK_LENGTH);
+        writeChunk = firstChunk;
+    }
+
+    @Override
+    public final long getBytesWritten() {
+        return totalSize;
+    }
+
+    /**
+     * Copies the buffer into the provided byte[] array of length {@link #getBytesWritten()}.
+     */
+    public final byte[] toArray(byte[] result) {
+        assert result.length == totalSize;
+        int resultIdx = 0;
+        for (Chunk cur = firstChunk; cur != null; cur = cur.next) {
+            System.arraycopy(cur.data, 0, result, resultIdx, cur.size);
+            resultIdx += cur.size;
+        }
+        assert resultIdx == totalSize;
+        return result;
+    }
+
+    @Override
+    public final void putS1(long value) {
+        long offset = writeOffset(Byte.BYTES);
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asS1(value));
+    }
+
+    @Override
+    public final void putU1(long value) {
+        long offset = writeOffset(Byte.BYTES);
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asU1(value));
+    }
+
+    @Override
+    public final void putU2(long value) {
+        putS2(asU2(value));
+    }
+
+    @Override
+    public final void putU4(long value) {
+        putS4(asU4(value));
+    }
+
+    protected long writeOffset(int writeBytes) {
+        if (writeChunk.size + writeBytes >= writeChunk.data.length) {
+            Chunk newChunk = new Chunk(Math.min(writeChunk.data.length * 2, MAX_CHUNK_LENGTH));
+            writeChunk.next = newChunk;
+            writeChunk = newChunk;
+        }
+
+        assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1;
+        long result = writeChunk.size + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+
+        totalSize += writeBytes;
+        writeChunk.size += writeBytes;
+        assert writeChunk.size <= writeChunk.data.length;
+
+        return result;
+    }
+}
+
+final class UnalignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter {
+    @Override
+    public void putS2(long value) {
+        long offset = writeOffset(Short.BYTES);
+        UnsafeAccess.UNSAFE.putShort(writeChunk.data, offset, asS2(value));
+    }
+
+    @Override
+    public void putS4(long value) {
+        long offset = writeOffset(Integer.BYTES);
+        UnsafeAccess.UNSAFE.putInt(writeChunk.data, offset, asS4(value));
+    }
+
+    @Override
+    public void putS8(long value) {
+        long offset = writeOffset(Long.BYTES);
+        UnsafeAccess.UNSAFE.putLong(writeChunk.data, offset, value);
+    }
+}
+
+final class AlignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter {
+    @Override
+    public void putS2(long value) {
+        long offset = writeOffset(Short.BYTES);
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+    }
+
+    @Override
+    public void putS4(long value) {
+        long offset = writeOffset(Integer.BYTES);
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
+    }
+
+    @Override
+    public void putS8(long value) {
+        long offset = writeOffset(Long.BYTES);
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 4, (byte) (value >> 32));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 5, (byte) (value >> 40));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 6, (byte) (value >> 48));
+        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 7, (byte) (value >> 56));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java
new file mode 100644
index 0000000..4e29d61
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.util;
+
+import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.graalvm.compiler.debug.TTY;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * The {@code Util} class contains a motley collection of utility methods used throughout the
+ * compiler.
+ */
+public class Util {
+
+    private static int getJavaSpecificationVersion() {
+        String value = System.getProperty("java.specification.version");
+        if (value.startsWith("1.")) {
+            value = value.substring(2);
+        }
+        return Integer.parseInt(value);
+    }
+
+    /**
+     * The integer value corresponding to the value of the {@code java.specification.version} system
+     * property after any leading {@code "1."} has been stripped.
+     */
+    public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
+
+    /**
+     * Determines if the Java runtime is version 8 or earlier.
+     */
+    public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
+
+    /**
+     * Statically cast an object to an arbitrary Object type. Dynamically checked.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T uncheckedCast(@SuppressWarnings("unused") Class<T> type, Object object) {
+        return (T) object;
+    }
+
+    /**
+     * Statically cast an object to an arbitrary Object type. Dynamically checked.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T uncheckedCast(Object object) {
+        return (T) object;
+    }
+
+    public interface Stringify {
+        String apply(Object o);
+    }
+
+    public static String join(Collection<?> c, String sep) {
+        return join(c, sep, "", "", null);
+    }
+
+    public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
+        StringBuilder buf = new StringBuilder(prefix);
+        boolean first = true;
+        for (Object e : c) {
+            if (!first) {
+                buf.append(sep);
+            } else {
+                first = false;
+            }
+            buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
+        }
+        buf.append(suffix);
+        return buf.toString();
+    }
+
+    /**
+     * Sets the element at a given position of a list and ensures that this position exists. If the
+     * list is current shorter than the position, intermediate positions are filled with a given
+     * value.
+     *
+     * @param list the list to put the element into
+     * @param pos the position at which to insert the element
+     * @param x the element that should be inserted
+     * @param filler the filler element that is used for the intermediate positions in case the list
+     *            is shorter than pos
+     */
+    public static <T> void atPutGrow(List<T> list, int pos, T x, T filler) {
+        if (list.size() < pos + 1) {
+            while (list.size() < pos + 1) {
+                list.add(filler);
+            }
+            assert list.size() == pos + 1;
+        }
+
+        assert list.size() >= pos + 1;
+        list.set(pos, x);
+    }
+
+    /**
+     * Prepends the String {@code indentation} to every line in String {@code lines}, including a
+     * possibly non-empty line following the final newline.
+     */
+    public static String indent(String lines, String indentation) {
+        if (lines.length() == 0) {
+            return lines;
+        }
+        final String newLine = "\n";
+        if (lines.endsWith(newLine)) {
+            return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine;
+        }
+        return indentation + lines.replace(newLine, newLine + indentation);
+    }
+
+    /**
+     * Returns the zero value for a given numeric kind.
+     */
+    public static JavaConstant zero(JavaKind kind) {
+        switch (kind) {
+            case Boolean:
+                return JavaConstant.FALSE;
+            case Byte:
+                return JavaConstant.forByte((byte) 0);
+            case Char:
+                return JavaConstant.forChar((char) 0);
+            case Double:
+                return JavaConstant.DOUBLE_0;
+            case Float:
+                return JavaConstant.FLOAT_0;
+            case Int:
+                return JavaConstant.INT_0;
+            case Long:
+                return JavaConstant.LONG_0;
+            case Short:
+                return JavaConstant.forShort((short) 0);
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
+    /**
+     * Returns the one value for a given numeric kind.
+     */
+    public static JavaConstant one(JavaKind kind) {
+        switch (kind) {
+            case Boolean:
+                return JavaConstant.TRUE;
+            case Byte:
+                return JavaConstant.forByte((byte) 1);
+            case Char:
+                return JavaConstant.forChar((char) 1);
+            case Double:
+                return JavaConstant.DOUBLE_1;
+            case Float:
+                return JavaConstant.FLOAT_1;
+            case Int:
+                return JavaConstant.INT_1;
+            case Long:
+                return JavaConstant.LONG_1;
+            case Short:
+                return JavaConstant.forShort((short) 1);
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
+    /**
+     * Print a HotSpot-style inlining message to the console.
+     */
+    public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+        if (HotSpotPrintInlining.getValue()) {
+            StringBuilder sb = new StringBuilder();
+            // 1234567
+            sb.append("        ");     // print timestamp
+            // 1234
+            sb.append("     ");        // print compilation number
+            // % s ! b n
+            sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
+            sb.append("     ");        // more indent
+            sb.append("    ");         // initial inlining indent
+            for (int i = 0; i < inliningDepth; i++) {
+                sb.append("  ");
+            }
+            sb.append(String.format("@ %d  %s   %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
+            TTY.println(sb.toString());
+        }
+    }
+
+    private static String methodName(ResolvedJavaMethod method) {
+        return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..9e715ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.graalvm.compiler.core.match.processor.MatchProcessor
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java
new file mode 100644
index 0000000..5129a50
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java
@@ -0,0 +1,1132 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match.processor;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.AbstractAnnotationValueVisitor7;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+import org.graalvm.compiler.core.match.ComplexMatchResult;
+import org.graalvm.compiler.core.match.MatchRule;
+import org.graalvm.compiler.core.match.MatchRules;
+import org.graalvm.compiler.core.match.MatchStatement;
+import org.graalvm.compiler.core.match.MatchStatementSet;
+import org.graalvm.compiler.core.match.MatchableNode;
+import org.graalvm.compiler.core.match.MatchableNodes;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+/**
+ * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * generated for each top level class containing at least one such field. These service objects can
+ * be retrieved as follows:
+ *
+ * <pre>
+ *     Iterable<MatchStatementSet> sl = GraalServices.load(MatchStatementSet.class);
+ *     for (MatchStatementSet rules : sl) {
+ *         ...
+ *     }
+ * </pre>
+ */
+@SupportedAnnotationTypes({"org.graalvm.compiler.core.match.MatchRule", "org.graalvm.compiler.core.match.MatchRules", "org.graalvm.compiler.core.match.MatchableNode",
+                "org.graalvm.compiler.core.match.MatchableNodes"})
+public class MatchProcessor extends AbstractProcessor {
+
+    public MatchProcessor() {
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processedMatchRule = new HashSet<>();
+    private final Set<Element> processedMatchableNode = new HashSet<>();
+
+    private static class RuleParseError extends RuntimeException {
+        private static final long serialVersionUID = 6456128283609257490L;
+
+        RuleParseError(String format, Object... args) {
+            super(String.format(format, args));
+        }
+    }
+
+    private static final Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
+    private class RuleParser {
+        private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
+
+        private ArrayList<String> capturedNames = new ArrayList<>();
+
+        private final String[] tokens;
+
+        private int current;
+
+        private MatchDescriptor matchDescriptor;
+
+        private final Set<Element> originatingElements = new HashSet<>();
+
+        private Set<String> requiredPackages = new HashSet<>();
+
+        RuleParser(String rule) {
+            Matcher m = tokenizer.matcher(rule);
+            List<String> list = new ArrayList<>();
+            int end = 0;
+            while (m.lookingAt()) {
+                list.add(m.group(1));
+                end = m.end();
+                m.region(m.end(), m.regionEnd());
+            }
+            if (end != m.regionEnd()) {
+                throw new RuleParseError("Unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+            }
+            tokens = list.toArray(new String[0]);
+
+            matchDescriptor = parseExpression();
+            if (!done()) {
+                throw new RuleParseError("didn't consume all tokens");
+            }
+            capturedNames.add(0, "root");
+            capturedTypes.add(0, matchDescriptor.nodeType);
+        }
+
+        String next() {
+            return tokens[current++];
+        }
+
+        String peek(String name) {
+            if (current >= tokens.length) {
+                if (name == null) {
+                    throw new RuleParseError("Out of tokens");
+                }
+                throw new RuleParseError("Out of tokens looking for %s", name);
+            }
+            return tokens[current];
+        }
+
+        boolean done() {
+            return current == tokens.length;
+        }
+
+        private MatchDescriptor parseExpression() {
+            if (peek("(").equals("(")) {
+                next();
+                MatchDescriptor descriptor = parseType(true);
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                    if (peek("(").equals("(")) {
+                        descriptor.inputs[n] = parseExpression();
+                    } else {
+                        descriptor.inputs[n] = parseType(false);
+                    }
+                }
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                    if (descriptor.inputs[n] == null) {
+                        throw new RuleParseError("not enough inputs for " + descriptor.name);
+                    }
+                }
+                if (peek(")").equals(")")) {
+                    next();
+                    return descriptor;
+                }
+                throw new RuleParseError("Too many arguments to " + descriptor.nodeType.nodeClass);
+            }
+            throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
+        }
+
+        private MatchDescriptor parseType(boolean forExpression) {
+            TypeDescriptor type = null;
+            String name = null;
+            if (Character.isUpperCase(peek("node type or name").charAt(0))) {
+                String token = next();
+                type = knownTypes.get(token);
+                if (type == null) {
+                    throw new RuleParseError("Unknown node type: " + token);
+                }
+                if (peek("=").equals("=")) {
+                    next();
+                    name = next();
+                }
+                originatingElements.addAll(type.originatingElements);
+                requiredPackages.add(type.nodePackage);
+            } else if (Character.isLowerCase(peek("name").charAt(0))) {
+                name = next();
+                type = valueType;
+            } else {
+                throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
+            }
+            if (name != null) {
+                if (!capturedNames.contains(name)) {
+                    capturedNames.add(name);
+                    capturedTypes.add(type);
+                } else {
+                    int index = capturedNames.indexOf(name);
+                    if (capturedTypes.get(index) != type) {
+                        throw new RuleParseError("Captured node \"%s\" has differing types", name);
+                    }
+                }
+            }
+            return new MatchDescriptor(type, name, forExpression);
+        }
+
+        List<String> generateVariants() {
+            return matchDescriptor.generateVariants();
+        }
+
+        /**
+         * Recursively accumulate any required Position declarations.
+         */
+        void generatePositionDeclarations(Set<String> declarations) {
+            matchDescriptor.generatePositionDeclarations(declarations);
+        }
+
+        /**
+         *
+         * @return the list of node types which are captured by name
+         */
+        public ArrayList<TypeDescriptor> capturedTypes() {
+            return capturedTypes;
+        }
+
+        public ArrayList<String> capturedNames() {
+            return capturedNames;
+        }
+    }
+
+    /**
+     * Set to true to enable logging to a local file during annotation processing. There's no normal
+     * channel for any debug messages and debugging annotation processors requires some special
+     * setup.
+     */
+    private static final boolean DEBUG = false;
+
+    private PrintWriter log;
+
+    /**
+     * Logging facility for debugging the annotation processor.
+     */
+
+    private PrintWriter getLog() {
+        if (log == null) {
+            try {
+                // Create the log file within the generated source directory so it's easy to find.
+                // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly
+                // on the mac.
+                FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
+                log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+        return log;
+    }
+
+    private void logMessage(String format, Object... args) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            bw.printf(format, args);
+            bw.flush();
+        }
+    }
+
+    private void logException(Throwable t) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            t.printStackTrace(bw);
+            bw.flush();
+        }
+    }
+
+    /**
+     * Bugs in an annotation processor can cause silent failure so try to report any exception
+     * throws as errors.
+     */
+    private void reportExceptionThrow(Element element, Throwable t) {
+        if (element != null) {
+            logMessage("throw for %s:\n", element);
+        }
+        logException(t);
+        errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
+    }
+
+    static class TypeDescriptor {
+        final TypeMirror mirror;
+
+        /**
+         * The name uses in match expressions to refer to this type.
+         */
+        final String shortName;
+
+        /**
+         * The simple name of the {@link ValueNode} class represented by this type.
+         */
+        final String nodeClass;
+
+        /**
+         * The package of {@link ValueNode} class represented by this type.
+         */
+        final String nodePackage;
+
+        /**
+         * The matchable inputs of the node.
+         */
+        final String[] inputs;
+
+        /**
+         * Should swapped variants of this match be generated. The user of the match is expected to
+         * compensate for any ordering differences in compare which are commutative but require
+         * reinterpreting the condition in that case.
+         */
+        final boolean commutative;
+
+        /**
+         * Can multiple users of this node subsume it. Constants can be swallowed into a match even
+         * if there are multiple users.
+         */
+        final boolean shareable;
+
+        final Set<Element> originatingElements = new HashSet<>();
+
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) {
+            this.mirror = mirror;
+            this.shortName = shortName;
+            this.nodeClass = nodeClass;
+            this.nodePackage = nodePackage;
+            this.inputs = inputs;
+            this.commutative = commutative;
+            this.shareable = shareable;
+            assert !commutative || inputs.length == 2;
+        }
+    }
+
+    /**
+     * The types which are know for purpose of parsing MatchRule expressions.
+     */
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
+
+    private TypeDescriptor valueType;
+
+    private TypeMirror matchRulesTypeMirror;
+
+    private TypeMirror matchRuleTypeMirror;
+
+    private TypeMirror matchableNodeTypeMirror;
+
+    private TypeMirror matchableNodesTypeMirror;
+
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) {
+        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
+        descriptor.originatingElements.add(element);
+        knownTypes.put(shortName, descriptor);
+    }
+
+    private String findPackage(Element type) {
+        PackageElement p = processingEnv.getElementUtils().getPackageOf(type);
+        if (p != null) {
+            return p.getQualifiedName().toString();
+        }
+        throw new GraalError("can't find package for %s", type);
+    }
+
+    class MatchDescriptor {
+        TypeDescriptor nodeType;
+        String name;
+        MatchDescriptor[] inputs;
+
+        MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) {
+            this.nodeType = nodeType;
+            this.name = name;
+            if (forExpression) {
+                this.inputs = new MatchDescriptor[nodeType.inputs.length];
+            } else {
+                this.inputs = new MatchDescriptor[0];
+            }
+        }
+
+        public void generatePositionDeclarations(Set<String> declarations) {
+            if (inputs.length == 0) {
+                return;
+            }
+            declarations.add(generatePositionDeclaration());
+            for (MatchDescriptor desc : inputs) {
+                desc.generatePositionDeclarations(declarations);
+            }
+        }
+
+        List<String> recurseVariants(int index) {
+            if (inputs.length == 0) {
+                return new ArrayList<>();
+            }
+            List<String> currentVariants = inputs[index].generateVariants();
+            if (index == inputs.length - 1) {
+                return currentVariants;
+            }
+            List<String> subVariants = recurseVariants(index + 1);
+            List<String> result = new ArrayList<>();
+            for (String current : currentVariants) {
+                for (String sub : subVariants) {
+                    result.add(current + ", " + sub);
+                    if (nodeType.commutative) {
+                        result.add(sub + ", " + current);
+                    }
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Recursively generate all the variants of this rule pattern. Currently that just means to
+         * swap the inputs for commutative rules, producing all possible permutations.
+         *
+         * @return a list of Strings which will construct pattern matchers for this rule.
+         */
+        List<String> generateVariants() {
+            String prefix = formatPrefix();
+            String suffix = formatSuffix();
+            ArrayList<String> variants = new ArrayList<>();
+            if (inputs.length > 0) {
+                for (String var : recurseVariants(0)) {
+                    variants.add(prefix + ", " + var + suffix);
+                }
+            } else {
+                assert inputs.length == 0;
+                variants.add(prefix + suffix);
+            }
+
+            return variants;
+        }
+
+        private String formatPrefix() {
+            if (nodeType == valueType) {
+                return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
+            } else {
+                return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
+            }
+        }
+
+        private String formatSuffix() {
+            if (nodeType != null) {
+                if (inputs.length != nodeType.inputs.length) {
+                    return ", true)";
+                } else {
+                    if (nodeType.inputs.length > 0) {
+                        return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
+                    }
+                    if (nodeType.shareable) {
+                        return ", false)";
+                    }
+                }
+            }
+            return ")";
+        }
+
+        String generatePositionDeclaration() {
+            return String.format("Position[] %s_positions = MatchRuleRegistry.findPositions(%s.TYPE, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
+                            String.join("\", \"", nodeType.inputs));
+        }
+    }
+
+    /**
+     * Strip the package off a class name leaving the full class name including any outer classes.
+     */
+    private String fullClassName(Element element) {
+        assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element;
+        String pkg = findPackage(element);
+        return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1);
+    }
+
+    private void createFiles(MatchRuleDescriptor info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+
+        String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        Types typeUtils = typeUtils();
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// CheckStyle: stop line length check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
+            out.println("import " + NodeMatchRules.class.getName() + ";");
+            out.println("import " + Position.class.getName() + ";");
+            out.println("import " + ServiceProvider.class.getName() + ";");
+            for (String p : info.requiredPackages) {
+                out.println("import " + p + ".*;");
+            }
+            out.println("");
+
+            out.println("@" + ServiceProvider.class.getSimpleName() + "(" + MatchStatementSet.class.getSimpleName() + ".class)");
+            out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+
+            out.println();
+
+            // Generate declarations for the wrapper class to invoke the code generation methods.
+            for (MethodInvokerItem invoker : info.invokers.values()) {
+                StringBuilder args = new StringBuilder();
+                StringBuilder types = new StringBuilder();
+                int count = invoker.fields.size();
+                int index = 0;
+                for (VariableElement arg : invoker.fields) {
+                    args.append('"');
+                    args.append(arg.getSimpleName());
+                    args.append('"');
+                    types.append(String.format("(%s) args[%s]", fullClassName(typeUtils.asElement(arg.asType())), index++));
+                    if (count-- > 1) {
+                        args.append(", ");
+                        types.append(", ");
+                    }
+                }
+                out.printf("    private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
+                out.printf("    private static final class %s implements MatchGenerator {\n", invoker.wrapperClass());
+                out.printf("        static MatchGenerator instance = new %s();\n", invoker.wrapperClass());
+                out.printf("        @Override\n");
+                out.printf("        public ComplexMatchResult match(NodeMatchRules nodeMatchRules, Object...args) {\n");
+                out.printf("            return ((%s) nodeMatchRules).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
+                out.printf("        }\n");
+                out.printf("        @Override\n");
+                out.printf("        public String getName() {\n");
+                out.printf("             return \"%s\";\n", invoker.methodName);
+                out.printf("        }\n");
+                out.printf("    }\n");
+                out.println();
+
+            }
+
+            String desc = MatchStatement.class.getSimpleName();
+
+            out.println("    @Override");
+            out.println("    public Class<? extends NodeMatchRules> forClass() {");
+            out.println("        return " + topDeclaringClass + ".class;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public List<" + desc + "> statements() {");
+            out.println("        // Checkstyle: stop ");
+
+            for (String positionDeclaration : info.positionDeclarations) {
+                out.println("        " + positionDeclaration);
+            }
+            out.println();
+
+            out.println("        List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
+
+            int i = 0;
+            for (MatchRuleItem matchRule : info.matchRules) {
+                String comma = i == info.matchRules.size() - 1 ? "" : ",";
+                out.printf("            %s%s\n", matchRule.ruleBuilder(), comma);
+                i++;
+            }
+            out.println("        ));");
+            out.println("        // Checkstyle: resume");
+            out.println("        return statements;");
+            out.println("    }");
+
+            out.println();
+
+            out.println("}");
+        }
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Used to generate the MatchStatement constructor invocation.
+     */
+    static class MatchRuleItem {
+        private final String matchPattern;
+        private final MethodInvokerItem invoker;
+
+        MatchRuleItem(String matchPattern, MethodInvokerItem invoker) {
+            this.matchPattern = matchPattern;
+            this.invoker = invoker;
+        }
+
+        /**
+         * @return a string which will construct the MatchStatement instance to match this pattern.
+         */
+        public String ruleBuilder() {
+            return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.methodName, matchPattern, invoker.wrapperClass(), invoker.argumentsListName());
+        }
+    }
+
+    /**
+     * Used to generate the wrapper class to invoke the code generation method.
+     */
+    static class MethodInvokerItem {
+        final String methodName;
+        final String nodeLIRBuilderClass;
+        final ExecutableElement method;
+        final List<? extends VariableElement> fields;
+
+        MethodInvokerItem(String methodName, String nodeLIRBuilderClass, ExecutableElement method, List<? extends VariableElement> fields) {
+            this.methodName = methodName;
+            this.nodeLIRBuilderClass = nodeLIRBuilderClass;
+            this.method = method;
+            this.fields = fields;
+        }
+
+        String wrapperClass() {
+            return "MatchGenerator_" + methodName;
+        }
+
+        String argumentsListName() {
+            return methodName + "_arguments";
+        }
+    }
+
+    static class MatchRuleDescriptor {
+
+        final TypeElement topDeclaringType;
+        final List<MatchRuleItem> matchRules = new ArrayList<>();
+        private final Set<Element> originatingElements = new HashSet<>();
+        public Set<String> positionDeclarations = new LinkedHashSet<>();
+
+        /**
+         * The mapping between elements with MatchRules and the wrapper class used invoke the code
+         * generation after the match.
+         */
+        Map<String, MethodInvokerItem> invokers = new LinkedHashMap<>();
+
+        /**
+         * The set of packages which must be imported to refer the classes mention in matchRules.
+         */
+        Set<String> requiredPackages = new HashSet<>();
+
+        MatchRuleDescriptor(TypeElement topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static TypeElement topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return (TypeElement) element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) {
+        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+            if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        logMessage("Starting round %s\n", roundEnv);
+        matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
+        matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
+
+        matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
+        matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
+
+        Element currentElement = null;
+        try {
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
+                logMessage("%s\n", element);
+                processMatchableNode(element);
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodes.class)) {
+                logMessage("%s\n", element);
+                processMatchableNode(element);
+            }
+            // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
+            // table since it shouldn't be mentioned in match rules.
+            TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
+            valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
+
+            Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
+
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+                currentElement = element;
+                processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+                currentElement = element;
+                processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
+            }
+
+            currentElement = null;
+            for (MatchRuleDescriptor info : map.values()) {
+                createFiles(info);
+            }
+
+        } catch (Throwable t) {
+            reportExceptionThrow(currentElement, t);
+        }
+
+        return true;
+    }
+
+    /**
+     * Build up the type table to be used during parsing of the MatchRule.
+     */
+    private void processMatchableNode(Element element) {
+        if (!processedMatchableNode.contains(element)) {
+            try {
+                processedMatchableNode.add(element);
+
+                AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror);
+                if (mirror == null) {
+                    mirror = findAnnotationMirror(element, matchableNodeTypeMirror);
+                }
+                if (mirror == null) {
+                    return;
+                }
+                TypeElement topDeclaringType = topDeclaringType(element);
+                List<AnnotationMirror> mirrors = null;
+                if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) {
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) {
+                    processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    private void processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalError {
+        logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable);
+        String nodeClass;
+        String nodePackage;
+        TypeMirror nodeClassMirror = null;
+        try {
+            matchable.nodeClass();
+        } catch (MirroredTypeException e) {
+            nodeClassMirror = e.getTypeMirror();
+        }
+        if (nodeClassMirror == null) {
+            throw new GraalError("Can't get mirror for node class %s", element);
+        }
+        if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+            nodeClass = topDeclaringType.getQualifiedName().toString();
+        } else {
+            nodeClass = nodeClassMirror.toString();
+        }
+        TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(nodeClass);
+        if (typeElement == null) {
+            errorMessage(element, mirror, "Class \"%s\" cannot be resolved to a type", nodeClass);
+            return;
+        }
+        nodePackage = findPackage(typeElement);
+        assert nodeClass.startsWith(nodePackage);
+        nodeClass = nodeClass.substring(nodePackage.length() + 1);
+        assert nodeClass.endsWith("Node");
+        String shortName = nodeClass.substring(0, nodeClass.length() - 4);
+
+        Types typeUtils = processingEnv.getTypeUtils();
+        TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror);
+        for (String input : matchable.inputs()) {
+            boolean ok = false;
+            TypeElement current = nodeClassElement;
+            while (!ok && current != null) {
+                for (Element fieldElement : ElementFilter.fieldsIn(current.getEnclosedElements())) {
+                    if (fieldElement.getSimpleName().toString().equals(input)) {
+                        ok = true;
+                        break;
+                    }
+                }
+                TypeMirror theSuper = current.getSuperclass();
+                current = (TypeElement) typeUtils.asElement(theSuper);
+            }
+            if (!ok) {
+                errorMessage(element, mirror, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
+            }
+        }
+
+        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
+    }
+
+    private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
+        if (!processedMatchRule.contains(element)) {
+            try {
+                processedMatchRule.add(element);
+
+                // The annotation element type should ensure this is true.
+                assert element instanceof ExecutableElement;
+
+                findMatchableNodes(element);
+
+                TypeElement topDeclaringType = topDeclaringType(element);
+                MatchRuleDescriptor info = map.get(topDeclaringType);
+                if (info == null) {
+                    info = new MatchRuleDescriptor(topDeclaringType);
+                    map.put(topDeclaringType, info);
+                }
+                List<AnnotationMirror> mirrors = null;
+                if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) {
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    /**
+     * Search the super types of element for MatchableNode definitions. Any superclass or super
+     * interface can contain definitions of matchable nodes.
+     *
+     * @param element
+     */
+    private void findMatchableNodes(Element element) {
+        processMatchableNode(element);
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                TypeElement current = (TypeElement) enclosing;
+                while (current != null) {
+                    processMatchableNode(current);
+                    for (TypeMirror intf : current.getInterfaces()) {
+                        Element interfaceElement = typeUtils().asElement(intf);
+                        processMatchableNode(interfaceElement);
+                        // Recurse
+                        findMatchableNodes(interfaceElement);
+                    }
+                    TypeMirror theSuper = current.getSuperclass();
+                    current = (TypeElement) typeUtils().asElement(theSuper);
+                }
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+    }
+
+    private Types typeUtils() {
+        return processingEnv.getTypeUtils();
+    }
+
+    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
+        logMessage("processMethodMatchRule %s %s\n", method, mirror);
+
+        Types typeUtils = typeUtils();
+
+        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
+            errorMessage(method, "MatchRule method %s must be public", method.getSimpleName());
+            return;
+        }
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            errorMessage(method, "MatchRule method %s must be non-static", method.getSimpleName());
+            return;
+        }
+
+        try {
+            TypeMirror returnType = method.getReturnType();
+            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
+                errorMessage(method, "MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+                return;
+            }
+
+            String rule = matchRule.value();
+            RuleParser parser = new RuleParser(rule);
+            ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
+            ArrayList<String> expectedNames = parser.capturedNames();
+            List<? extends VariableElement> actualParameters = method.getParameters();
+            if (expectedTypes.size() + 1 < actualParameters.size()) {
+                errorMessage(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
+                return;
+            }
+
+            // Walk through the parameters to the method and see if they exist in the match rule.
+            // The order doesn't matter but only names mentioned in the rule can be used and they
+            // must be assignment compatible.
+            for (VariableElement parameter : actualParameters) {
+                String name = parameter.getSimpleName().toString();
+                int nameIndex = expectedNames.indexOf(name);
+                if (nameIndex == -1) {
+                    errorMessage(method, "Argument \"%s\" isn't captured in the match rule", name);
+                    return;
+                }
+                TypeMirror type = parameter.asType();
+                if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
+                    errorMessage(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+                    return;
+                }
+            }
+
+            String methodName = method.getSimpleName().toString();
+            MethodInvokerItem invoker = info.invokers.get(methodName);
+            if (invoker == null) {
+                invoker = new MethodInvokerItem(methodName, topDeclaringType(method).getSimpleName().toString(), method, actualParameters);
+                info.invokers.put(methodName, invoker);
+            } else if (invoker.method != method) {
+                // This could be supported but it's easier if they are unique since the names
+                // are used in log output and snippet counters.
+                errorMessage(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(),
+                                invoker.method.getSimpleName());
+                return;
+            }
+
+            Element enclosing = method.getEnclosingElement();
+            String declaringClass = "";
+            String separator = "";
+            Set<Element> originatingElementsList = info.originatingElements;
+            originatingElementsList.add(method);
+            while (enclosing != null) {
+                if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                    if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                        errorMessage(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                        return;
+                    }
+                    originatingElementsList.add(enclosing);
+                    declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                    separator = ".";
+                } else {
+                    assert enclosing.getKind() == ElementKind.PACKAGE;
+                }
+                enclosing = enclosing.getEnclosingElement();
+            }
+
+            originatingElementsList.addAll(parser.originatingElements);
+            info.requiredPackages.addAll(parser.requiredPackages);
+
+            // Accumulate any position declarations.
+            parser.generatePositionDeclarations(info.positionDeclarations);
+
+            List<String> matches = parser.generateVariants();
+            for (String match : matches) {
+                info.matchRules.add(new MatchRuleItem(match, invoker));
+            }
+        } catch (RuleParseError e) {
+            errorMessage(method, mirror, e.getMessage());
+        }
+    }
+
+    private void errorMessage(Element element, String format, Object... args) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
+    }
+
+    private void errorMessage(Element element, AnnotationMirror mirror, String format, Object... args) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element, mirror);
+    }
+
+    // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
+    @SuppressWarnings("unchecked")
+    private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
+        List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
+        List<T> result = new ArrayList<>();
+
+        if (values != null) {
+            for (AnnotationValue value : values) {
+                T annotationValue = resolveAnnotationValue(expectedListType, value);
+                if (annotationValue != null) {
+                    result.add(annotationValue);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
+        return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
+        if (unboxedValue != null) {
+            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
+                return null;
+            }
+            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
+                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
+            }
+        }
+        return (T) unboxedValue;
+    }
+
+    private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
+        ExecutableElement valueMethod = null;
+        for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
+            if (method.getSimpleName().toString().equals(name)) {
+                valueMethod = method;
+                break;
+            }
+        }
+
+        if (valueMethod == null) {
+            return null;
+        }
+
+        AnnotationValue value = mirror.getElementValues().get(valueMethod);
+        if (value == null) {
+            value = valueMethod.getDefaultValue();
+        }
+
+        return value;
+    }
+
+    private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
+
+        @Override
+        public Object visitBoolean(boolean b, Void p) {
+            return Boolean.valueOf(b);
+        }
+
+        @Override
+        public Object visitByte(byte b, Void p) {
+            return Byte.valueOf(b);
+        }
+
+        @Override
+        public Object visitChar(char c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitDouble(double d, Void p) {
+            return d;
+        }
+
+        @Override
+        public Object visitFloat(float f, Void p) {
+            return f;
+        }
+
+        @Override
+        public Object visitInt(int i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitLong(long i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitShort(short s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitString(String s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitType(TypeMirror t, Void p) {
+            return t;
+        }
+
+        @Override
+        public Object visitEnumConstant(VariableElement c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitAnnotation(AnnotationMirror a, Void p) {
+            return a;
+        }
+
+        @Override
+        public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
+            return vals;
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java
new file mode 100644
index 0000000..e0f5745
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.sparc.test;
+
+import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
+import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
+import static org.junit.Assume.assumeTrue;
+import jdk.vm.ci.sparc.SPARC;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.backend.AllocatorTest;
+
+public class SPARCAllocatorTest extends AllocatorTest {
+
+    @Before
+    public void checkSPARC() {
+        assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC);
+        assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
+        assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
+    }
+
+    @Test
+    public void test1() {
+        testAllocation("test1snippet", 2, 0, 0);
+    }
+
+    public static long test1snippet(long x) {
+        return x + 5;
+    }
+
+    @Test
+    public void test2() {
+        testAllocation("test2snippet", 2, 0, 0);
+    }
+
+    public static long test2snippet(long x) {
+        return x * 5;
+    }
+
+    @Test
+    public void test3() {
+        testAllocation("test3snippet", 4, 0, 0);
+    }
+
+    public static long test3snippet(long x) {
+        return x / 3 + x % 3;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java
new file mode 100644
index 0000000..14725bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+public class SPARCAddressLowering extends AddressLowering {
+
+    @Override
+    public AddressNode lower(ValueNode address) {
+        return lower(address, 0);
+    }
+
+    @Override
+    public AddressNode lower(ValueNode base, ValueNode offset) {
+        JavaConstant immBase = asImmediate(base);
+        if (immBase != null && SPARCAssembler.isSimm13(immBase)) {
+            return lower(offset, immBase.asLong());
+        }
+
+        JavaConstant immOffset = asImmediate(offset);
+        if (immOffset != null && SPARCAssembler.isSimm13(immOffset)) {
+            return lower(base, immOffset.asLong());
+        }
+        return base.graph().unique(new SPARCIndexedAddressNode(base, offset));
+    }
+
+    private AddressNode lower(ValueNode base, long displacement) {
+        if (base instanceof AddNode) {
+            AddNode add = (AddNode) base;
+
+            JavaConstant immX = asImmediate(add.getX());
+            if (immX != null && SPARCAssembler.isSimm13(displacement + immX.asLong())) {
+                return lower(add.getY(), displacement + immX.asLong());
+            }
+
+            JavaConstant immY = asImmediate(add.getY());
+            if (immY != null && SPARCAssembler.isSimm13(displacement + immY.asLong())) {
+                return lower(add.getX(), displacement + immY.asLong());
+            }
+
+            if (displacement == 0) {
+                return lower(add.getX(), add.getY());
+            }
+        }
+
+        assert SPARCAssembler.isSimm13(displacement);
+        return base.graph().unique(new SPARCImmediateAddressNode(base, (int) displacement));
+    }
+
+    private static JavaConstant asImmediate(ValueNode value) {
+        JavaConstant c = value.asJavaConstant();
+        if (c != null && c.getJavaKind().isNumericInteger()) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java
new file mode 100644
index 0000000..5edf779
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
+import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM;
+import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF;
+import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR;
+import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR;
+import static jdk.vm.ci.code.CodeUtil.mask;
+import static jdk.vm.ci.meta.JavaConstant.forLong;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
+import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
+import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp;
+import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp;
+import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
+import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
+import org.graalvm.compiler.lir.sparc.SPARCOPFOp;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
+
+    @Override
+    public SPARCLIRGenerator getLIRGen() {
+        return (SPARCLIRGenerator) super.getLIRGen();
+    }
+
+    @Override
+    public Variable emitBitCount(Value operand) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
+        Value usedOperand = operand;
+        if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend
+            usedOperand = getLIRGen().newVariable(operand.getValueKind());
+            getLIRGen().append(new SPARCOP3Op(Op3s.Srl, operand, SPARC.g0.asValue(), usedOperand));
+        }
+        getLIRGen().append(new SPARCOP3Op(Op3s.Popc, SPARC.g0.asValue(), usedOperand, result));
+        return result;
+    }
+
+    @Override
+    public Variable emitBitScanForward(Value operand) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
+        getLIRGen().append(new SPARCBitManipulationOp(BSF, result, getLIRGen().asAllocatable(operand), getLIRGen()));
+        return result;
+    }
+
+    @Override
+    public Variable emitBitScanReverse(Value operand) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
+        if (operand.getPlatformKind() == SPARCKind.XWORD) {
+            getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
+        } else {
+            getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitMathAbs(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        SPARCKind kind = (SPARCKind) input.getPlatformKind();
+        Opfs opf;
+        switch (kind) {
+            case SINGLE:
+                opf = Opfs.Fabss;
+                break;
+            case DOUBLE:
+                opf = Opfs.Fabsd;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("Input kind: " + kind);
+        }
+        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
+        return result;
+    }
+
+    @Override
+    public Value emitMathSqrt(Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        SPARCKind kind = (SPARCKind) input.getPlatformKind();
+        Opfs opf;
+        switch (kind) {
+            case SINGLE:
+                opf = Opfs.Fsqrts;
+                break;
+            case DOUBLE:
+                opf = Opfs.Fsqrtd;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("Input kind: " + kind);
+        }
+        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
+        return result;
+    }
+
+    @Override
+    public Value emitNegate(Value input) {
+        PlatformKind inputKind = input.getPlatformKind();
+        if (isNumericInteger(inputKind)) {
+            return emitUnary(Sub, input);
+        } else {
+            return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input);
+        }
+    }
+
+    @Override
+    public Value emitNot(Value input) {
+        return emitUnary(Xnor, input);
+    }
+
+    private Variable emitUnary(Opfs opf, Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
+        return result;
+    }
+
+    private Variable emitUnary(Op3s op3, Value input) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(SPARCOP3Op.newUnary(op3, input, result));
+        return result;
+    }
+
+    private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b) {
+        return emitBinary(resultKind, opf, a, b, null);
+    }
+
+    private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (opf.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
+            getLIRGen().append(new SPARCOPFOp(opf, b, a, result, state));
+        } else {
+            getLIRGen().append(new SPARCOPFOp(opf, a, b, result, state));
+        }
+        return result;
+    }
+
+    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, int b) {
+        return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b)));
+    }
+
+    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b) {
+        return emitBinary(resultKind, op3, a, b, null);
+    }
+
+    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
+            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), a, result, state));
+        } else {
+            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), b, result, state));
+        }
+        return result;
+    }
+
+    @Override
+    protected boolean isNumericInteger(PlatformKind kind) {
+        return ((SPARCKind) kind).isInteger();
+    }
+
+    @Override
+    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            return emitBinary(resultKind, setFlags ? Addcc : Add, a, b);
+        } else {
+            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
+            return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b);
+        }
+    }
+
+    @Override
+    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b);
+        } else {
+            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
+            return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b);
+        }
+    }
+
+    @Override
+    public Variable emitMul(Value a, Value b, boolean setFlags) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        PlatformKind aKind = a.getPlatformKind();
+        if (isNumericInteger(aKind)) {
+            if (setFlags) {
+                Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+                if (aKind == XWORD) {
+                    getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen()));
+                } else if (aKind == WORD) {
+                    getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b)));
+                } else {
+                    throw GraalError.shouldNotReachHere();
+                }
+                return result;
+            } else {
+                return emitBinary(resultKind, setFlags ? Op3s.Mulscc : Op3s.Mulx, a, b);
+            }
+        } else {
+            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
+            return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b);
+        }
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        MulHigh opcode;
+        switch (((SPARCKind) a.getPlatformKind())) {
+            case WORD:
+                opcode = MulHigh.IMUL;
+                break;
+            case XWORD:
+                opcode = MulHigh.LMUL;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return emitMulHigh(opcode, a, b);
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        switch (((SPARCKind) a.getPlatformKind())) {
+            case WORD:
+                Value aExtended = emitBinary(LIRKind.combine(a), Srl, a, 0);
+                Value bExtended = emitBinary(LIRKind.combine(b), Srl, b, 0);
+                Value result = emitBinary(LIRKind.combine(a, b), Mulx, aExtended, bExtended);
+                return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits());
+            case XWORD:
+                return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private Value emitMulHigh(MulHigh opcode, Value a, Value b) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+        MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b)));
+        getLIRGen().append(mulHigh);
+        return result;
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        PlatformKind aKind = a.getPlatformKind();
+        PlatformKind bKind = b.getPlatformKind();
+        if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero
+            Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD));
+            return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state);
+        } else if (isNumericInteger(aKind)) {
+            Value fixedA = emitSignExtend(a, aKind.getSizeInBytes() * 8, 64);
+            Value fixedB = emitSignExtend(b, bKind.getSizeInBytes() * 8, 64);
+            return emitBinary(resultKind, Op3s.Sdivx, fixedA, fixedB, state);
+        } else {
+            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
+            return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state);
+        }
+    }
+
+    @Override
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+        Value aLoaded;
+        Variable q1; // Intermediate values
+        Variable q2;
+        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
+        switch (aKind) {
+            case WORD:
+                // Sign extend a and b
+                Variable as = emitBinary(result.getValueKind(), Sra, a, g0.asValue(LIRKind.value(WORD)));
+                Variable bs = emitBinary(result.getValueKind(), Sra, b, g0.asValue(LIRKind.value(WORD)));
+                q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state);
+                q2 = emitBinary(q1.getValueKind(), Mulx, q1, bs);
+                result = emitSub(as, q2, false);
+                break;
+            case XWORD:
+                aLoaded = getLIRGen().load(a); // Reuse the loaded value
+                q1 = emitBinary(result.getValueKind(), Sdivx, aLoaded, b, state);
+                q2 = emitBinary(result.getValueKind(), Mulx, q1, b);
+                result = emitSub(aLoaded, q2, false);
+                break;
+            case SINGLE:
+                ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM);
+                result = getLIRGen().emitForeignCall(fremCall, state, a, b);
+                break;
+            case DOUBLE:
+                ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM);
+                result = getLIRGen().emitForeignCall(dremCall, state, a, b);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind());
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
+        Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b));
+        Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b));
+        Rem opcode;
+        switch (((SPARCKind) a.getPlatformKind())) {
+            case WORD:
+                opcode = Rem.IUREM;
+                break;
+            case XWORD:
+                opcode = Rem.LUREM;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        getLIRGen().append(new RemOp(opcode, result, getLIRGen().load(a), getLIRGen().load(b), scratch1, scratch2, state));
+        return result;
+
+    }
+
+    @Override
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
+        Value actualA = a;
+        Value actualB = b;
+        switch (((SPARCKind) a.getPlatformKind())) {
+            case WORD:
+                actualA = emitZeroExtend(actualA, 32, 64);
+                actualB = emitZeroExtend(actualB, 32, 64);
+                break;
+            case XWORD:
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return emitBinary(LIRKind.combine(actualA, actualB), Udivx, actualA, actualB, state);
+    }
+
+    @Override
+    public Variable emitAnd(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        return emitBinary(resultKind, Op3s.And, a, b);
+    }
+
+    @Override
+    public Variable emitOr(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        return emitBinary(resultKind, Op3s.Or, a, b);
+    }
+
+    @Override
+    public Variable emitXor(Value a, Value b) {
+        LIRKind resultKind = LIRKind.combine(a, b);
+        return emitBinary(resultKind, Op3s.Xor, a, b);
+    }
+
+    @Override
+    public Variable emitShl(Value a, Value b) {
+        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
+        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
+        Op3s op;
+        switch (aKind) {
+            case WORD:
+                op = Op3s.Sll;
+                break;
+            case XWORD:
+                op = Op3s.Sllx;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
+        }
+        return emitBinary(resultKind, op, a, b);
+    }
+
+    @Override
+    public Variable emitShr(Value a, Value b) {
+        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
+        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
+        Op3s op;
+        switch (aKind) {
+            case WORD:
+                op = Op3s.Sra;
+                break;
+            case XWORD:
+                op = Op3s.Srax;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return emitBinary(resultKind, op, a, b);
+    }
+
+    @Override
+    public Variable emitUShr(Value a, Value b) {
+        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
+        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
+        Op3s op;
+        switch (aKind) {
+            case WORD:
+                op = Op3s.Srl;
+                break;
+            case XWORD:
+                op = Op3s.Srlx;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return emitBinary(resultKind, op, a, b);
+    }
+
+    private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
+        Variable result = getLIRGen().newVariable(kind);
+        getLIRGen().emitMove(result, input);
+        return result;
+    }
+
+    @Override
+    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Value result;
+        switch (op) {
+            case D2F:
+                result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(SINGLE));
+                getLIRGen().append(new SPARCOPFOp(Fdtos, inputVal, result));
+                break;
+            case F2D:
+                result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(DOUBLE));
+                getLIRGen().append(new SPARCOPFOp(Fstod, inputVal, result));
+                break;
+            case I2F: {
+                AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
+                result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
+                moveBetweenFpGp(intEncodedFloatReg, input);
+                getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
+                break;
+            }
+            case I2D: {
+                // Unfortunately we must do int -> float -> double because fitod has float
+                // and double encoding in one instruction
+                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
+                result = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
+                moveBetweenFpGp(convertedFloatReg, input);
+                getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
+                break;
+            }
+            case L2D: {
+                AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
+                moveBetweenFpGp(longEncodedDoubleReg, input);
+                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
+                getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
+                result = convertedDoubleReg;
+                break;
+            }
+            case D2I: {
+                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
+                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, input, convertedFloatReg));
+                AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
+                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
+                result = convertedIntReg;
+                break;
+            }
+            case F2L: {
+                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
+                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, input, convertedDoubleReg));
+                AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
+                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
+                result = convertedLongReg;
+                break;
+            }
+            case F2I: {
+                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
+                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, input, convertedFloatReg));
+                AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
+                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
+                result = convertedIntReg;
+                break;
+            }
+            case D2L: {
+                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
+                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, input, convertedDoubleReg));
+                AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
+                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
+                result = convertedLongReg;
+                break;
+            }
+            case L2F: {
+                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
+                result = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
+                moveBetweenFpGp(convertedDoubleReg, input);
+                getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
+                break;
+            }
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    protected VirtualStackSlot getTempSlot(LIRKind kind) {
+        return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind);
+    }
+
+    private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
+        AllocatableValue tempSlot;
+        PlatformKind dstKind = dst.getPlatformKind();
+        PlatformKind srcKind = src.getPlatformKind();
+        if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) {
+            tempSlot = AllocatableValue.ILLEGAL;
+        } else {
+            tempSlot = getTempSlot(LIRKind.value(XWORD));
+        }
+        getLIRGen().append(new MoveFpGp(dst, src, tempSlot));
+    }
+
+    @Override
+    public Value emitNarrow(Value inputVal, int bits) {
+        if (inputVal.getPlatformKind() == XWORD && bits <= 32) {
+            LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD);
+            Variable result = getLIRGen().newVariable(resultKind);
+            getLIRGen().emitMove(result, inputVal);
+            return result;
+        } else {
+            return inputVal;
+        }
+    }
+
+    @Override
+    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
+        LIRKind shiftKind = LIRKind.value(WORD);
+        LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
+        Value result;
+        int shiftCount = XWORD.getSizeInBits() - fromBits;
+        if (fromBits == toBits) {
+            result = inputVal;
+        } else if (isJavaConstant(inputVal)) {
+            JavaConstant javaConstant = asJavaConstant(inputVal);
+            long constant;
+            if (javaConstant.isNull()) {
+                constant = 0;
+            } else {
+                constant = javaConstant.asLong();
+            }
+            return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
+        } else if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
+            result = getLIRGen().newVariable(resultKind);
+            getLIRGen().append(new SPARCOP3Op(Sra, inputVal, SPARC.g0.asValue(LIRKind.value(WORD)), result));
+        } else {
+            Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
+            result = getLIRGen().newVariable(resultKind);
+            getLIRGen().append(new SPARCOP3Op(Sllx, inputVal, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
+            getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
+        }
+        return result;
+    }
+
+    @Override
+    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
+        if (fromBits == 32) {
+            getLIRGen().append(new SPARCOP3Op(Srl, inputVal, g0.asValue(), result));
+        } else {
+            Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
+            getLIRGen().append(new SPARCOP3Op(And, inputVal, mask, result));
+        }
+        return result;
+    }
+
+    @Override
+    public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
+        SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind();
+        SPARCKind toKind = (SPARCKind) to.getPlatformKind();
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(to);
+        // These cases require a move between CPU and FPU registers:
+        if (fromKind.isFloat() != toKind.isFloat()) {
+            moveBetweenFpGp(result, input);
+            return result;
+        } else {
+            // Otherwise, just emit an ordinary move instruction.
+            // Instructions that move or generate 32-bit register values also set the upper 32
+            // bits of the register to zero.
+            // Consequently, there is no need for a special zero-extension move.
+            return emitConvertMove(to, input);
+        }
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address);
+        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
+        getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
+        return result;
+    }
+
+    @Override
+    public void emitStore(ValueKind<?> kind, Value address, Value inputVal, LIRFrameState state) {
+        SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address);
+        if (isJavaConstant(inputVal)) {
+            JavaConstant c = asJavaConstant(inputVal);
+            if (c.isDefaultForKind()) {
+                getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state));
+                return;
+            }
+        }
+        Variable input = getLIRGen().load(inputVal);
+        getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java
new file mode 100644
index 0000000..0716b55
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Represents an address of the form [base + simm13].
+ */
+@NodeInfo
+public class SPARCImmediateAddressNode extends AddressNode implements LIRLowerable {
+
+    public static final NodeClass<SPARCImmediateAddressNode> TYPE = NodeClass.create(SPARCImmediateAddressNode.class);
+
+    @Input private ValueNode base;
+    private int displacement;
+
+    public SPARCImmediateAddressNode(ValueNode base, int displacement) {
+        super(TYPE);
+        assert SPARCAssembler.isSimm13(displacement);
+        this.base = base;
+        this.displacement = displacement;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool();
+
+        AllocatableValue baseValue = tool.asAllocatable(gen.operand(base));
+
+        LIRKind kind = tool.getLIRKind(stamp());
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        if (baseReference != null) {
+            kind = kind.makeDerivedReference(baseReference);
+        }
+
+        gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java
new file mode 100644
index 0000000..06c5725
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.sparc.SPARCIndexedAddressValue;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Represents an address of the form [base + index].
+ */
+@NodeInfo
+public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable {
+
+    public static final NodeClass<SPARCIndexedAddressNode> TYPE = NodeClass.create(SPARCIndexedAddressNode.class);
+
+    @Input private ValueNode base;
+    @Input private ValueNode index;
+
+    public SPARCIndexedAddressNode(ValueNode base, ValueNode index) {
+        super(TYPE);
+        this.base = base;
+        this.index = index;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool();
+
+        AllocatableValue baseValue = tool.asAllocatable(gen.operand(base));
+        AllocatableValue indexValue = tool.asAllocatable(gen.operand(index));
+
+        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue indexReference = LIRKind.derivedBaseFromValue(indexValue);
+
+        LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp()), baseReference, indexReference);
+        gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue));
+    }
+
+    public ValueNode getBase() {
+        return base;
+    }
+
+    public void setBase(ValueNode base) {
+        updateUsages(this.base, base);
+        this.base = base;
+    }
+
+    public ValueNode getIndex() {
+        return index;
+    }
+
+    public void setIndex(ValueNode index) {
+        updateUsages(this.index, index);
+        this.index = index;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java
new file mode 100644
index 0000000..9f0cd9f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.phases.Phase;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * SPARC only supports 32 and 64 bit integer compare.
+ *
+ * This phase turns {@link CompareNode}s which have {@link IntegerStamp} as input and its bit-width
+ * is not 32 or 64 bit into either a 32 or 64 bit compare by sign extending the input values.
+ *
+ * Why we do this in the HIR instead in the LIR? This enables the pattern matcher
+ * {@link SPARCNodeMatchRules#signExtend(SignExtendNode, org.graalvm.compiler.nodes.memory.Access)}
+ * to do it's job and replace loads with sign extending ones.
+ */
+public class SPARCIntegerCompareCanonicalizationPhase extends Phase {
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof CompareNode) {
+                CompareNode enode = (CompareNode) n;
+                min32(enode, enode.getX());
+                min32(enode, enode.getY());
+            }
+        }
+    }
+
+    private static void min32(CompareNode enode, ValueNode v) {
+        Stamp s = v.stamp();
+        if (s instanceof IntegerStamp) {
+            int bits = ((IntegerStamp) s).getBits();
+            if (bits != 32 && bits != 64) {
+                if (bits <= 32) {
+                    bits = 32;
+                } else {
+                    bits = 64;
+                }
+                ValueNode replacement;
+                if (v instanceof ConstantNode) {
+                    JavaConstant newConst;
+                    if (bits == 32) {
+                        newConst = JavaConstant.forInt(v.asJavaConstant().asInt());
+                    } else if (bits == 64) {
+                        newConst = JavaConstant.forLong(v.asJavaConstant().asLong());
+                    } else {
+                        throw GraalError.shouldNotReachHere();
+                    }
+                    long mask = CodeUtil.mask(bits);
+                    replacement = v.graph().addOrUnique(new ConstantNode(newConst, IntegerStamp.stampForMask(bits, newConst.asLong() & mask, newConst.asLong() & mask)));
+                } else {
+                    replacement = v.graph().addOrUnique(new SignExtendNode(v, bits));
+                }
+                v.replaceAtUsages(replacement, x -> x == enode);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java
new file mode 100644
index 0000000..0023a12
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVDCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVicc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.NoOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp;
+import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp;
+import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp;
+import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCJumpOp;
+import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp;
+import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
+import org.graalvm.compiler.lir.sparc.SPARCPauseOp;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public abstract class SPARCLIRGenerator extends LIRGenerator {
+
+    private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp;
+    private final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public static final class ConstantTableBaseProvider {
+        private Variable constantTableBase;
+        private boolean useConstantTableBase = false;
+
+        public Variable getConstantTableBase() {
+            useConstantTableBase = true;
+            return constantTableBase;
+        }
+    }
+
+    public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes,
+                    ConstantTableBaseProvider constantTableBaseProvider) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    @Override
+    protected JavaConstant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((SPARCKind) kind) {
+            case BYTE:
+                return JavaConstant.forByte((byte) dead);
+            case HWORD:
+                return JavaConstant.forShort((short) dead);
+            case WORD:
+                return JavaConstant.forInt((int) dead);
+            case XWORD:
+                return JavaConstant.forLong(dead);
+            case SINGLE:
+            case V32_BYTE:
+            case V32_HWORD:
+                return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
+            case DOUBLE:
+            case V64_BYTE:
+            case V64_HWORD:
+            case V64_WORD:
+                return JavaConstant.forDouble(Double.longBitsToDouble(dead));
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
+    /**
+     * The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st
+     * instructions no instruction deals either with 32 or 64 bits. This function converts small
+     * integer kinds to WORD.
+     */
+    @Override
+    public <K extends ValueKind<K>> K toRegisterKind(K kind) {
+        switch ((SPARCKind) kind.getPlatformKind()) {
+            case BYTE:
+            case HWORD:
+                return kind.changeType(SPARCKind.WORD);
+            default:
+                return kind;
+        }
+    }
+
+    public SPARCAddressValue asAddressValue(Value address) {
+        if (address instanceof SPARCAddressValue) {
+            return (SPARCAddressValue) address;
+        } else {
+            ValueKind<?> kind = address.getValueKind();
+            if (address instanceof JavaConstant) {
+                long displacement = ((JavaConstant) address).asLong();
+                if (SPARCAssembler.isSimm13(displacement)) {
+                    return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement);
+                }
+            }
+            return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0);
+        }
+    }
+
+    @Override
+    public Variable emitAddress(AllocatableValue stackslot) {
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new StackLoadAddressOp(result, stackslot));
+        return result;
+    }
+
+    @Override
+    public void emitReturn(JavaKind javaKind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(javaKind, input.getValueKind());
+            emitMove(operand, input);
+        }
+        append(new ReturnOp(operand));
+    }
+
+    @Override
+    public void emitJump(LabelRef label) {
+        append(new SPARCJumpOp(label));
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        Value left;
+        Value right;
+        Condition actualCondition;
+        if (isJavaConstant(x)) {
+            left = load(y);
+            right = loadNonConst(x);
+            actualCondition = cond.mirror();
+        } else {
+            left = load(x);
+            right = loadNonConst(y);
+            actualCondition = cond;
+        }
+        SPARCKind actualCmpKind = (SPARCKind) cmpKind;
+        if (actualCmpKind.isInteger()) {
+            assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind;
+            append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability));
+        } else if (actualCmpKind.isFloat()) {
+            emitFloatCompare(actualCmpKind, x, y, Fcc0);
+            ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue);
+            append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability));
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
+        SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind();
+        append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability));
+    }
+
+    @Override
+    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+        emitIntegerTest(left, right);
+        append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability));
+    }
+
+    private void emitIntegerTest(Value a, Value b) {
+        assert ((SPARCKind) a.getPlatformKind()).isInteger();
+        if (LIRValueUtil.isVariable(b)) {
+            append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadNonConst(a)));
+        } else {
+            append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b)));
+        }
+    }
+
+    private Value loadSimm11(Value value) {
+        if (isJavaConstant(value)) {
+            JavaConstant c = asJavaConstant(value);
+            if (c.isNull() || SPARCAssembler.isSimm11(c)) {
+                return value;
+            }
+        }
+        return load(value);
+    }
+
+    @Override
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        // Emit compare
+        SPARCKind cmpSPARCKind = (SPARCKind) cmpKind;
+        boolean mirrored = emitCompare(cmpSPARCKind, left, right);
+
+        // Emit move
+        Value actualTrueValue = trueValue;
+        Value actualFalseValue = falseValue;
+        SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind();
+        CMOV cmove;
+        if (valueKind.isFloat()) {
+            actualTrueValue = load(trueValue); // Floats cannot be immediate at all
+            actualFalseValue = load(falseValue);
+            cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC;
+        } else if (valueKind.isInteger()) {
+            actualTrueValue = loadSimm11(trueValue);
+            actualFalseValue = loadSimm11(falseValue);
+            cmove = MOVicc;
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+        Variable result = newVariable(trueValue.getValueKind());
+        ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue);
+        CC cc = CC.forKind(cmpSPARCKind);
+        append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result));
+        return result;
+    }
+
+    /**
+     * This method emits the compare instruction, and may reorder the operands. It returns true if
+     * it did so.
+     *
+     * @param cmpKind Kind how a and b have to be compared
+     * @param a the left operand of the comparison
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
+        boolean mirrored;
+        if (cmpKind.isInteger()) { // Integer case
+            mirrored = emitIntegerCompare(cmpKind, a, b);
+        } else if (cmpKind.isFloat()) { // Float case
+            mirrored = false; // No mirroring done on floats
+            emitFloatCompare(cmpKind, a, b, Fcc0);
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+        return mirrored;
+    }
+
+    private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) {
+        boolean mirrored;
+        assert cmpKind.isInteger();
+        Value left;
+        Value right;
+        if (LIRValueUtil.isVariable(b)) {
+            left = load(b);
+            right = loadNonConst(a);
+            mirrored = true;
+        } else {
+            left = load(a);
+            right = loadNonConst(b);
+            mirrored = false;
+        }
+        int compareBytes = cmpKind.getSizeInBytes();
+        // SPARC compares 32 or 64 bits
+        if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
+            left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8);
+        }
+        if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
+            right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8);
+        }
+        append(SPARCOP3Op.newBinaryVoid(Subcc, left, right));
+        return mirrored;
+    }
+
+    private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) {
+        Opfs floatCompareOpcode;
+        assert cmpJavaKind.isFloat();
+        switch (cmpJavaKind) {
+            case DOUBLE:
+                floatCompareOpcode = Fcmpd;
+                break;
+            case SINGLE:
+                floatCompareOpcode = Fcmps;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b)));
+    }
+
+    @Override
+    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
+        emitIntegerTest(left, right);
+        Variable result = newVariable(trueValue.getValueKind());
+        ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false);
+        CC cc = CC.forKind(left.getPlatformKind());
+        append(new CondMoveOp(MOVicc, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result));
+        return result;
+    }
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        long maxOffset = linkage.getMaxCallTargetOffset();
+        if (SPARCAssembler.isWordDisp30(maxOffset)) {
+            append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
+        } else {
+            append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
+        }
+    }
+
+    @Override
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        AllocatableValue scratchValue = newVariable(key.getValueKind());
+        AllocatableValue base = AllocatableValue.ILLEGAL;
+        for (Constant c : strategy.getKeyConstants()) {
+            if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) c)) {
+                base = constantTableBaseProvider.getConstantTableBase();
+                break;
+            }
+        }
+        append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
+    }
+
+    protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) {
+        return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
+    }
+
+    @Override
+    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
+        // Making a copy of the switch value is necessary because jump table destroys the input
+        // value
+        Variable tmp = newVariable(key.getValueKind());
+        emitMove(tmp, key);
+        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind()))));
+    }
+
+    protected SPARC getArchitecture() {
+        return (SPARC) target().arch;
+    }
+
+    @Override
+    public Variable emitByteSwap(Value input) {
+        Variable result = newVariable(LIRKind.combine(input));
+        append(new SPARCByteSwapOp(this, result, input));
+        return result;
+    }
+
+    @Override
+    public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
+        Variable result = newVariable(LIRKind.value(SPARCKind.WORD));
+        append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length)));
+        return result;
+    }
+
+    @Override
+    public void emitMembar(int barriers) {
+        int necessaryBarriers = target().arch.requiredBarriers(barriers);
+        if (target().isMP && necessaryBarriers != 0) {
+            append(new MembarOp(necessaryBarriers));
+        }
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
+        append(new ReturnOp(Value.ILLEGAL));
+    }
+
+    public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
+        SPARCAddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(resultKind);
+        append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true));
+        return result;
+    }
+
+    public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
+        SPARCAddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(resultKind);
+        append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
+        return result;
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        PlatformKind kind = address.getPlatformKind();
+        assert kind == XWORD : address + " - " + kind + " not an object!";
+        append(new NullCheckOp(asAddressValue(address), state));
+    }
+
+    public void emitLoadConstantTableBase() {
+        constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD));
+        int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size();
+        NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition));
+        loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder);
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        LIR lir = getResult().getLIR();
+        loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase);
+    }
+
+    @Override
+    public void emitPause() {
+        append(new SPARCPauseOp());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java
new file mode 100644
index 0000000..c075a51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCLIRKindTool implements LIRKindTool {
+
+    @Override
+    public LIRKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return LIRKind.value(SPARCKind.BYTE);
+        } else if (bits <= 16) {
+            return LIRKind.value(SPARCKind.HWORD);
+        } else if (bits <= 32) {
+            return LIRKind.value(SPARCKind.WORD);
+        } else {
+            assert bits <= 64;
+            return LIRKind.value(SPARCKind.XWORD);
+        }
+    }
+
+    @Override
+    public LIRKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return LIRKind.value(SPARCKind.SINGLE);
+            case 64:
+                return LIRKind.value(SPARCKind.DOUBLE);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(SPARCKind.XWORD);
+    }
+
+    @Override
+    public LIRKind getWordKind() {
+        return LIRKind.value(SPARCKind.XWORD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java
new file mode 100644
index 0000000..1739580
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCMove;
+import org.graalvm.compiler.lir.sparc.SPARCMove.LoadAddressOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.Move;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class SPARCMoveFactory implements MoveFactory {
+
+    protected final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public SPARCMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) {
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    @Override
+    public LIRInstruction createMove(AllocatableValue dst, Value src) {
+        boolean srcIsSlot = isStackSlotValue(src);
+        boolean dstIsSlot = isStackSlotValue(dst);
+        if (isConstantValue(src)) {
+            return createLoad(dst, asConstant(src));
+        } else if (src instanceof SPARCAddressValue) {
+            return new LoadAddressOp(dst, (SPARCAddressValue) src);
+        } else {
+            assert src instanceof AllocatableValue;
+            if (srcIsSlot && dstIsSlot) {
+                throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass());
+            } else {
+                return new Move(dst, (AllocatableValue) src);
+            }
+        }
+    }
+
+    @Override
+    public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        return new SPARCMove.Move(result, input);
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (src instanceof JavaConstant) {
+            JavaConstant javaConstant = (JavaConstant) src;
+            if (canInlineConstant(javaConstant)) {
+                return new SPARCMove.LoadInlineConstant(javaConstant, dst);
+            } else {
+                return new SPARCMove.LoadConstantFromTable(javaConstant, constantTableBaseProvider.getConstantTableBase(), dst);
+            }
+        } else if (src instanceof DataPointerConstant) {
+            return new SPARCMove.LoadDataAddressOp(dst, (DataPointerConstant) src);
+        } else {
+            throw GraalError.shouldNotReachHere(src.getClass().toString());
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        switch (c.getJavaKind()) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+                return SPARCAssembler.isSimm13(c.asInt());
+            case Long:
+                return SPARCAssembler.isSimm13(c.asLong());
+            case Object:
+                return c.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java
new file mode 100644
index 0000000..c7eb902
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.sparc.SPARCJumpOp;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder {
+
+    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    protected JumpOp newJumpOp(LabelRef ref) {
+        return new SPARCJumpOp(ref);
+    }
+
+    @Override
+    public SPARCLIRGenerator getLIRGeneratorTool() {
+        return (SPARCLIRGenerator) super.getLIRGeneratorTool();
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        getLIRGeneratorTool().emitLoadConstantTableBase();
+        super.emitPrologue(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java
new file mode 100644
index 0000000..a8bbdbe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.sparc;
+
+import static jdk.vm.ci.sparc.SPARCKind.BYTE;
+import static jdk.vm.ci.sparc.SPARCKind.HWORD;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+import org.graalvm.compiler.core.match.ComplexMatchResult;
+import org.graalvm.compiler.core.match.MatchRule;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.memory.Access;
+
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public class SPARCNodeMatchRules extends NodeMatchRules {
+
+    public SPARCNodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        SPARCKind toKind = null;
+        SPARCKind fromKind = null;
+        if (fromBits == toBits) {
+            return null;
+        }
+        toKind = toBits > 32 ? XWORD : WORD;
+        switch (fromBits) {
+            case 8:
+                fromKind = BYTE;
+                break;
+            case 16:
+                fromKind = HWORD;
+                break;
+            case 32:
+                fromKind = WORD;
+                break;
+            default:
+                throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+        }
+        SPARCKind localFromKind = fromKind;
+        SPARCKind localToKind = toKind;
+        return builder -> {
+            return getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access));
+        };
+    }
+
+    private ComplexMatchResult emitZeroExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        SPARCKind toKind = null;
+        SPARCKind fromKind = null;
+        if (fromBits == toBits) {
+            return null;
+        }
+        toKind = toBits > 32 ? XWORD : WORD;
+        switch (fromBits) {
+            case 8:
+                fromKind = BYTE;
+                break;
+            case 16:
+                fromKind = HWORD;
+                break;
+            case 32:
+                fromKind = WORD;
+                break;
+            default:
+                throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+        }
+        SPARCKind localFromKind = fromKind;
+        SPARCKind localToKind = toKind;
+        return builder -> {
+            // Loads are always zero extending load
+            return getLIRGeneratorTool().emitZeroExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access));
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @Override
+    public SPARCLIRGenerator getLIRGeneratorTool() {
+        return (SPARCLIRGenerator) super.getLIRGeneratorTool();
+    }
+
+    protected SPARCArithmeticLIRGenerator getArithmeticLIRGenerator() {
+        return (SPARCArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesProvider.java
new file mode 100644
index 0000000..62e7140
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesProvider.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.sparc;
+
+import java.util.ListIterator;
+
+import org.graalvm.compiler.java.DefaultSuitesProvider;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.ExpandLogicPhase;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+public class SPARCSuitesProvider extends DefaultSuitesProvider {
+    public SPARCSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+    @Override
+    public Suites createSuites() {
+        Suites s = super.createSuites();
+        ListIterator<BasePhase<? super LowTierContext>> l = s.getLowTier().findPhase(ExpandLogicPhase.class);
+        while (PhaseSuite.findNextPhase(l, ExpandLogicPhase.class)) {
+            // Search for last occurrence of ExpandLogicPhase
+        }
+        l.previous();
+        l.add(new SPARCIntegerCompareCanonicalizationPhase());
+        return s;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/AllocSpy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/AllocSpy.java
new file mode 100644
index 0000000..034324a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/AllocSpy.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static java.lang.Boolean.parseBoolean;
+import static java.lang.Integer.getInteger;
+import static java.lang.System.getProperty;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.monitoring.runtime.instrumentation.AllocationRecorder;
+import com.google.monitoring.runtime.instrumentation.Sampler;
+
+/**
+ * Tool for analyzing allocations within a scope using the
+ * <a href="https://code.google.com/p/java-allocation-instrumenter/">Java Allocation
+ * Instrumenter</a>. Allocation records are aggregated per stack trace at an allocation site. The
+ * size of the stack trace is governed by the value of the "AllocSpy.ContextSize" system property
+ * (default is 5).
+ * <p>
+ * Using this facility requires using -javaagent on the command line. For example:
+ *
+ * <pre>
+ * mx --vm server unittest -javaagent:lib/java-allocation-instrumenter.jar -dsa -DAllocSpy.ContextSize=6 BC_iadd2
+ * </pre>
+ *
+ * @see #SampleBytes
+ * @see #SampleInstances
+ * @see #HistogramLimit
+ * @see #NameSize
+ * @see #BarSize
+ * @see #NumberSize
+ */
+public final class AllocSpy implements AutoCloseable {
+
+    static ThreadLocal<AllocSpy> current = new ThreadLocal<>();
+
+    private static final boolean ENABLED;
+
+    static {
+        boolean enabled = false;
+        try {
+            Field field = AllocationRecorder.class.getDeclaredField("instrumentation");
+            field.setAccessible(true);
+            enabled = field.get(null) != null;
+        } catch (Exception e) {
+        }
+        ENABLED = enabled;
+        if (ENABLED) {
+            AllocationRecorder.addSampler(new GraalContextSampler());
+        }
+    }
+
+    public static boolean isEnabled() {
+        return ENABLED;
+    }
+
+    static String prop(String sfx) {
+        return AllocSpy.class.getSimpleName() + "." + sfx;
+    }
+
+    /**
+     * Determines if bytes per allocation site are recorded.
+     */
+    private static final boolean SampleBytes = parseBoolean(getProperty(prop("SampleBytes"), "true"));
+
+    /**
+     * Determines if allocations per allocation site are recorded.
+     */
+    private static final boolean SampleInstances = parseBoolean(getProperty(prop("SampleInstances"), "true"));
+
+    /**
+     * The size of context to record for each allocation site in terms of Graal frames.
+     */
+    private static final int ContextSize = getInteger(prop("ContextSize"), 5);
+
+    /**
+     * Only the {@code HistogramLimit} most frequent values are printed.
+     */
+    private static final int HistogramLimit = getInteger(prop("HistogramLimit"), 40);
+
+    /**
+     * The width of the allocation context column.
+     */
+    private static final int NameSize = getInteger(prop("NameSize"), 50);
+
+    /**
+     * The width of the histogram bar column.
+     */
+    private static final int BarSize = getInteger(prop("BarSize"), 100);
+
+    /**
+     * The width of the frequency column.
+     */
+    private static final int NumberSize = getInteger(prop("NumberSize"), 10);
+
+    final Object name;
+    final AllocSpy parent;
+    final Map<String, CountedValue> bytesPerGraalContext = new HashMap<>();
+    final Map<String, CountedValue> instancesPerGraalContext = new HashMap<>();
+
+    public static AllocSpy open(Object name) {
+        if (ENABLED) {
+            return new AllocSpy(name);
+        }
+        return null;
+    }
+
+    private AllocSpy(Object name) {
+        this.name = name;
+        parent = current.get();
+        current.set(this);
+    }
+
+    @Override
+    public void close() {
+        current.set(parent);
+        PrintStream ps = System.out;
+        ps.println("\n\nAllocation histograms for " + name);
+        if (SampleBytes) {
+            print(ps, bytesPerGraalContext, "BytesPerGraalContext", HistogramLimit, NameSize + 60, BarSize);
+        }
+        if (SampleInstances) {
+            print(ps, instancesPerGraalContext, "InstancesPerGraalContext", HistogramLimit, NameSize + 60, BarSize);
+        }
+    }
+
+    private static void printLine(PrintStream printStream, char c, int lineSize) {
+        char[] charArr = new char[lineSize];
+        Arrays.fill(charArr, c);
+        printStream.printf("%s%n", new String(charArr));
+    }
+
+    private static void print(PrintStream ps, Map<String, CountedValue> map, String name, int limit, int nameSize, int barSize) {
+        if (map.isEmpty()) {
+            return;
+        }
+
+        List<CountedValue> list = new ArrayList<>(map.values());
+        Collections.sort(list);
+
+        // Sum up the total number of elements.
+        int total = 0;
+        for (CountedValue cv : list) {
+            total += cv.getCount();
+        }
+
+        // Print header.
+        ps.printf("%s has %d unique elements and %d total elements:%n", name, list.size(), total);
+
+        int max = list.get(0).getCount();
+        final int lineSize = nameSize + NumberSize + barSize + 10;
+        printLine(ps, '-', lineSize);
+        String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            int value = cv.getCount();
+            char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
+            Arrays.fill(bar, '=');
+            String[] lines = String.valueOf(cv.getValue()).split("\\n");
+
+            String objectString = lines[0];
+            if (objectString.length() > nameSize) {
+                objectString = objectString.substring(0, nameSize - 3) + "...";
+            }
+            ps.printf(formatString, objectString, value, new String(bar));
+            for (int j = 1; j < lines.length; j++) {
+                String line = lines[j];
+                if (line.length() > nameSize) {
+                    line = line.substring(0, nameSize - 3) + "...";
+                }
+                ps.printf("|   %-" + (nameSize - 2) + "s | %-" + NumberSize + "s | %-" + barSize + "s |%n", line, " ", " ");
+
+            }
+        }
+        printLine(ps, '-', lineSize);
+    }
+
+    CountedValue bytesPerGraalContext(String context) {
+        return getCounter(context, bytesPerGraalContext);
+    }
+
+    CountedValue instancesPerGraalContext(String context) {
+        return getCounter(context, instancesPerGraalContext);
+    }
+
+    protected static CountedValue getCounter(String desc, Map<String, CountedValue> map) {
+        CountedValue count = map.get(desc);
+        if (count == null) {
+            count = new CountedValue(0, desc);
+            map.put(desc, count);
+        }
+        return count;
+    }
+
+    private static final String[] Excluded = {AllocSpy.class.getName(), AllocationRecorder.class.getName()};
+
+    private static boolean excludeFrame(String className) {
+        for (String e : Excluded) {
+            if (className.startsWith(e)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static class GraalContextSampler implements Sampler {
+
+        @Override
+        public void sampleAllocation(int count, String desc, Object newObj, long size) {
+            AllocSpy scope = current.get();
+            if (scope != null) {
+                StringBuilder sb = new StringBuilder(200);
+                Throwable t = new Throwable();
+                int remainingGraalFrames = ContextSize;
+                for (StackTraceElement e : t.getStackTrace()) {
+                    if (remainingGraalFrames < 0) {
+                        break;
+                    }
+                    String className = e.getClassName();
+                    boolean isGraalFrame = className.contains(".graal.");
+                    if (sb.length() != 0) {
+                        append(sb.append('\n'), e);
+                    } else {
+                        if (!excludeFrame(className)) {
+                            sb.append("type=").append(desc);
+                            if (count != -1) {
+                                sb.append('[').append(count).append(']');
+                            }
+                            append(sb.append('\n'), e);
+                        }
+                    }
+                    if (isGraalFrame) {
+                        remainingGraalFrames--;
+                    }
+                }
+                String context = sb.toString();
+                if (SampleBytes) {
+                    scope.bytesPerGraalContext(context).add((int) size);
+                }
+                if (SampleInstances) {
+                    scope.instancesPerGraalContext(context).inc();
+                }
+            }
+        }
+
+        protected StringBuilder append(StringBuilder sb, StackTraceElement e) {
+            String className = e.getClassName();
+            int period = className.lastIndexOf('.');
+            if (period != -1) {
+                sb.append(className, period + 1, className.length());
+            } else {
+                sb.append(className);
+            }
+            sb.append('.').append(e.getMethodName());
+            if (e.isNativeMethod()) {
+                sb.append("(Native Method)");
+            } else if (e.getFileName() != null && e.getLineNumber() >= 0) {
+                sb.append('(').append(e.getFileName()).append(':').append(e.getLineNumber()).append(")");
+            } else {
+                sb.append("(Unknown Source)");
+            }
+            return sb;
+        }
+    }
+
+    /**
+     * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
+     * values with higher frequencies first.
+     */
+    static class CountedValue implements Comparable<CountedValue> {
+
+        private int count;
+        private final Object value;
+
+        CountedValue(int count, Object value) {
+            this.count = count;
+            this.value = value;
+        }
+
+        @Override
+        public int compareTo(CountedValue o) {
+            if (count < o.count) {
+                return 1;
+            } else if (count > o.count) {
+                return -1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return count + " -> " + value;
+        }
+
+        public void inc() {
+            count++;
+        }
+
+        public void add(int n) {
+            count += n;
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java
new file mode 100644
index 0000000..03ca1c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+/**
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant
+ * 0. Then boxing elimination is applied and it is verified that the resulting graph is equal to the
+ * graph of the method that just has a "return 1" statement in it.
+ */
+public class BoxingEliminationTest extends GraalCompilerTest {
+
+    private static final Short s = 2;
+
+    @SuppressWarnings("all")
+    public static short referenceSnippet1() {
+        return 1;
+    }
+
+    @SuppressWarnings("all")
+    public static short referenceSnippet2() {
+        return 2;
+    }
+
+    public static Short boxedShort() {
+        return 1;
+    }
+
+    public static Object boxedObjectShort() {
+        return (short) 1;
+    }
+
+    public static Object boxedObjectInteger() {
+        return 1;
+    }
+
+    public static Integer boxedInteger() {
+        return 2;
+    }
+
+    public static Short constantBoxedShort() {
+        return s;
+    }
+
+    @Test
+    public void test1() {
+        compareGraphs("test1Snippet", "referenceSnippet1");
+    }
+
+    @SuppressWarnings("all")
+    public static short test1Snippet() {
+        return boxedShort();
+    }
+
+    @Test
+    public void test2() {
+        compareGraphs("test2Snippet", "referenceSnippet1");
+    }
+
+    @SuppressWarnings("all")
+    public static short test2Snippet() {
+        return (Short) boxedObjectShort();
+    }
+
+    @Test
+    public void test3() {
+        compareGraphs("test3Snippet", "referenceSnippet1");
+    }
+
+    @SuppressWarnings("all")
+    public static short test3Snippet() {
+        short b = boxedShort();
+        if (b < 0) {
+            b = boxedShort();
+        }
+        return b;
+    }
+
+    @Test
+    public void test4() {
+        compareGraphs("test4Snippet", "referenceSnippet2");
+    }
+
+    @SuppressWarnings("all")
+    public static short test4Snippet() {
+        return constantBoxedShort();
+    }
+
+    @Ignore
+    @Test
+    public void testLoop() {
+        compareGraphs("testLoopSnippet", "referenceLoopSnippet", false, true);
+    }
+
+    public static int testLoopSnippet(int n, int a) {
+        Integer sum = a;
+        for (Integer i = 0; i < n; i++) {
+            sum += i;
+        }
+        return sum;
+    }
+
+    public static int referenceLoopSnippet(int n, int a) {
+        int sum = a;
+        for (int i = 0; i < n; i++) {
+            sum += i;
+        }
+        return sum;
+    }
+
+    @Test
+    public void testLoop2() {
+        compareGraphs("testLoop2Snippet", "referenceLoop2Snippet", true, true);
+    }
+
+    public static int testLoop2Snippet(int n, Integer a) {
+        Integer sum = a;
+        for (Integer i = 0; i < n; i++) {
+            sum += i;
+        }
+        return sum;
+    }
+
+    public static int referenceLoop2Snippet(int n, Integer a) {
+        Integer sum0;
+        if (n <= 0) {
+            sum0 = a;
+        } else {
+            int sum = a;
+            for (int i = 0; i < n; i++) {
+                sum += i;
+            }
+            sum0 = sum;
+        }
+        return sum0;
+    }
+
+    public static int referenceIfSnippet(int a) {
+        int result;
+        if (a < 0) {
+            result = 2;
+        } else {
+            result = 1;
+        }
+        return result;
+    }
+
+    @Test
+    public void testIf() {
+        compareGraphs("testIfSnippet", "referenceIfSnippet");
+    }
+
+    public static int testIfSnippet(int a) {
+        Integer result;
+        if (a < 0) {
+            result = boxedInteger();
+        } else {
+            result = (Integer) boxedObjectInteger();
+        }
+        return result;
+    }
+
+    @Test
+    public void testComparison() {
+        compareGraphs("testComparison1Snippet", "referenceComparisonSnippet");
+        compareGraphs("testComparison2Snippet", "referenceComparisonSnippet");
+    }
+
+    @SuppressWarnings("cast")
+    public static boolean testComparison1Snippet(int a, int b) {
+        return ((Integer) a) == b;
+    }
+
+    public static boolean testComparison2Snippet(int a, int b) {
+        Integer x = a;
+        Integer y = b;
+        return x == y;
+    }
+
+    public static boolean referenceComparisonSnippet(int a, int b) {
+        return a == b;
+    }
+
+    @Test
+    public void testLateCanonicalization() {
+        compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet");
+    }
+
+    public static boolean testLateCanonicalizationSnippet(int a) {
+        Integer x = a;
+        Integer y = 1000;
+        return x == y;
+    }
+
+    public static boolean referenceLateCanonicalizationSnippet(int a) {
+        return a == 1000;
+    }
+
+    private StructuredGraph graph;
+
+    public static Integer materializeReferenceSnippet(int a) {
+        return Integer.valueOf(a);
+    }
+
+    public static Integer materializeTest1Snippet(int a) {
+        Integer v = a;
+
+        if (v == a) {
+            return v;
+        } else {
+            return null;
+        }
+    }
+
+    @Test
+    public void materializeTest1() {
+        test("materializeTest1Snippet", 1);
+    }
+
+    public static int intTest1Snippet() {
+        return Integer.valueOf(1);
+    }
+
+    @Test
+    public void intTest1() {
+        ValueNode result = getResult("intTest1Snippet");
+        Assert.assertTrue(result.isConstant());
+        Assert.assertEquals(1, result.asJavaConstant().asInt());
+    }
+
+    public static int mergeTest1Snippet(boolean d, int a, int b) {
+        Integer v;
+        if (d) {
+            v = a;
+        } else {
+            v = b;
+        }
+        return v;
+    }
+
+    @Test
+    public void mergeTest1() {
+        processMethod("mergeTest1Snippet");
+    }
+
+    public static boolean equalsTest1Snippet(int x, int y) {
+        Integer a = x;
+        Integer b = y;
+        return a == b;
+    }
+
+    @Test
+    public void equalsTest1() {
+        processMethod("equalsTest1Snippet");
+    }
+
+    public static int loopTest1Snippet(int n, int v) {
+        Integer sum = 0;
+        for (int i = 0; i < n; i++) {
+            sum += v;
+        }
+        return sum;
+    }
+
+    @Test
+    public void loopTest1() {
+        processMethod("loopTest1Snippet");
+
+    }
+
+    final ValueNode getResult(String snippet) {
+        processMethod(snippet);
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        return graph.getNodes(ReturnNode.TYPE).first().result();
+    }
+
+    private void processMethod(final String snippet) {
+        graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
+    }
+
+    private void compareGraphs(final String snippet, final String referenceSnippet) {
+        compareGraphs(snippet, referenceSnippet, false, false);
+    }
+
+    private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
+        graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        if (loopPeeling) {
+            new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context);
+        }
+        new DeadCodeEliminationPhase().apply(graph);
+        canonicalizer.apply(graph, context);
+        new PartialEscapePhase(false, canonicalizer).apply(graph, context);
+
+        new DeadCodeEliminationPhase().apply(graph);
+        canonicalizer.apply(graph, context);
+
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
+        new InliningPhase(new CanonicalizerPhase()).apply(referenceGraph, context);
+        new DeadCodeEliminationPhase().apply(referenceGraph);
+        new CanonicalizerPhase().apply(referenceGraph, context);
+
+        assertEquals(referenceGraph, graph, excludeVirtual, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingTest.java
new file mode 100644
index 0000000..250545a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+public class BoxingTest extends GraalCompilerTest {
+
+    public static Object boxSnippet(int arg) {
+        return arg;
+    }
+
+    @Test
+    public void test0() {
+        test("boxSnippet", 0);
+    }
+
+    @Test
+    public void test5() {
+        test("boxSnippet", 5);
+    }
+
+    @Test
+    public void testMinus5() {
+        test("boxSnippet", -5);
+    }
+
+    @Test
+    public void test300() {
+        test("boxSnippet", 300);
+    }
+
+    @Test
+    public void testMinus300() {
+        test("boxSnippet", -300);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
new file mode 100644
index 0000000..8c8c74f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.CompilerThreadFactory;
+import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.DelegatingDebugConfig;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
+import org.graalvm.compiler.phases.verify.VerifyCallerSensitiveMethods;
+import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
+import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
+import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
+import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Checks that all classes in *graal*.jar and *jvmci*.jar entries on the boot class path comply with
+ * global invariants such as using {@link Object#equals(Object)} to compare certain types instead of
+ * identity comparisons.
+ */
+public class CheckGraalInvariants extends GraalTest {
+
+    private static boolean shouldVerifyEquals(ResolvedJavaMethod m) {
+        if (m.getName().equals("identityEquals")) {
+            ResolvedJavaType c = m.getDeclaringClass();
+            if (c.getName().equals("Ljdk/vm/ci/meta/AbstractValue;") || c.getName().equals("jdk/vm/ci/meta/Value")) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean shouldProcess(String classpathEntry) {
+        if (classpathEntry.endsWith(".jar")) {
+            String name = new File(classpathEntry).getName();
+            return name.contains("jvmci") || name.contains("graal");
+        }
+        return false;
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test() {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+
+        Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
+
+        String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path";
+        String bootclasspath = System.getProperty(propertyName);
+        Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath);
+
+        final List<String> classNames = new ArrayList<>();
+        for (String path : bootclasspath.split(File.pathSeparator)) {
+            if (shouldProcess(path)) {
+                try {
+                    final ZipFile zipFile = new ZipFile(new File(path));
+                    for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) {
+                        final ZipEntry zipEntry = entry.nextElement();
+                        String name = zipEntry.getName();
+                        if (name.endsWith(".class")) {
+                            String className = name.substring(0, name.length() - ".class".length()).replace('/', '.');
+                            classNames.add(className);
+                        }
+                    }
+                } catch (IOException ex) {
+                    Assert.fail(ex.toString());
+                }
+            }
+        }
+        Assert.assertFalse("Could not find graal jars on boot class path: " + bootclasspath, classNames.isEmpty());
+
+        // Allows a subset of methods to be checked through use of a system property
+        String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters");
+        String[] filters = property == null ? null : property.split(",");
+
+        CompilerThreadFactory factory = new CompilerThreadFactory("CheckInvariantsThread", new DebugConfigAccess() {
+            @Override
+            public GraalDebugConfig getDebugConfig() {
+                return DebugEnvironment.initialize(System.out);
+            }
+        });
+        int availableProcessors = Runtime.getRuntime().availableProcessors();
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+
+        List<String> errors = Collections.synchronizedList(new ArrayList<>());
+        // Order outer classes before the inner classes
+        classNames.sort((String a, String b) -> a.compareTo(b));
+        // Initialize classes in single thread to avoid deadlocking issues during initialization
+        List<Class<?>> classes = initializeClasses(classNames);
+        for (Class<?> c : classes) {
+            String className = c.getName();
+            executor.execute(() -> {
+                try {
+                    checkClass(c, metaAccess);
+                } catch (Throwable e) {
+                    errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
+                }
+            });
+
+            for (Method m : c.getDeclaredMethods()) {
+                if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
+                    // ignore
+                } else {
+                    String methodName = className + "." + m.getName();
+                    if (matches(filters, methodName)) {
+                        executor.execute(() -> {
+                            ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                            StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                            try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
+                                graphBuilderSuite.apply(graph, context);
+                                // update phi stamps
+                                graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
+                                checkGraph(context, graph);
+                            } catch (VerificationError e) {
+                                errors.add(e.getMessage());
+                            } catch (LinkageError e) {
+                                // suppress linkages errors resulting from eager resolution
+                            } catch (BailoutException e) {
+                                // Graal bail outs on certain patterns in Java bytecode (e.g.,
+                                // unbalanced monitors introduced by jacoco).
+                            } catch (Throwable e) {
+                                errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
+                            }
+                        });
+                    }
+                }
+            }
+        }
+        executor.shutdown();
+        try {
+            executor.awaitTermination(1, TimeUnit.HOURS);
+        } catch (InterruptedException e1) {
+            throw new RuntimeException(e1);
+        }
+
+        if (!errors.isEmpty()) {
+            StringBuilder msg = new StringBuilder();
+            String nl = String.format("%n");
+            for (String e : errors) {
+                if (msg.length() != 0) {
+                    msg.append(nl);
+                }
+                msg.append(e);
+            }
+            Assert.fail(msg.toString());
+        }
+    }
+
+    private static List<Class<?>> initializeClasses(List<String> classNames) {
+        List<Class<?>> classes = new ArrayList<>(classNames.size());
+        for (String className : classNames) {
+            if (className.equals("module-info")) {
+                continue;
+            }
+            try {
+                Class<?> c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader());
+                classes.add(c);
+            } catch (ClassNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+        return classes;
+    }
+
+    /**
+     * @param metaAccess
+     */
+    private static void checkClass(Class<?> c, MetaAccessProvider metaAccess) {
+        if (Node.class.isAssignableFrom(c)) {
+            if (c.getAnnotation(NodeInfo.class) == null) {
+                throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
+            }
+        }
+    }
+
+    /**
+     * Checks the invariants for a single graph.
+     */
+    private static void checkGraph(HighTierContext context, StructuredGraph graph) {
+        if (shouldVerifyEquals(graph.method())) {
+            new VerifyUsageWithEquals(Value.class).apply(graph, context);
+            new VerifyUsageWithEquals(Register.class).apply(graph, context);
+            new VerifyUsageWithEquals(RegisterCategory.class).apply(graph, context);
+            new VerifyUsageWithEquals(JavaType.class).apply(graph, context);
+            new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context);
+            new VerifyUsageWithEquals(JavaField.class).apply(graph, context);
+            new VerifyUsageWithEquals(LocationIdentity.class).apply(graph, context);
+            new VerifyUsageWithEquals(LIRKind.class).apply(graph, context);
+            new VerifyUsageWithEquals(ArithmeticOpTable.class).apply(graph, context);
+            new VerifyUsageWithEquals(ArithmeticOpTable.Op.class).apply(graph, context);
+        }
+        new VerifyDebugUsage().apply(graph, context);
+        new VerifyCallerSensitiveMethods().apply(graph, context);
+        new VerifyVirtualizableUsage().apply(graph, context);
+        new VerifyUpdateUsages().apply(graph, context);
+        new VerifyBailoutUsage().apply(graph, context);
+        if (graph.method().isBridge()) {
+            BridgeMethodUtils.getBridgedMethod(graph.method());
+        }
+    }
+
+    private static boolean matches(String[] filters, String s) {
+        if (filters == null || filters.length == 0) {
+            return true;
+        }
+        for (String filter : filters) {
+            if (s.contains(filter)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static String printStackTraceToString(Throwable t) {
+        StringWriter sw = new StringWriter();
+        t.printStackTrace(new PrintWriter(sw));
+        return sw.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CommonedConstantsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CommonedConstantsTest.java
new file mode 100644
index 0000000..85cf35b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CommonedConstantsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.reflect.Array;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+
+/**
+ * Tests any optimization that commons loads of non-inlineable constants.
+ */
+public class CommonedConstantsTest extends GraalCompilerTest {
+
+    public static final String[] array = {"1", "2", null};
+
+    // A method where a constant is used on the normal and exception edge of a non-inlined call.
+    // The dominating block of both usages is the block containing the call.
+    public static Object test0Snippet(String[] arr, int i) {
+        Object result = null;
+        try {
+            result = Array.get(arr, i);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            result = array[0];
+        }
+        if (result == null) {
+            result = array[2];
+        }
+        return result;
+    }
+
+    @Test
+    public void test0() {
+        // Ensure the exception path is profiled
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test0Snippet");
+        javaMethod.reprofile();
+        test0Snippet(array, array.length);
+
+        test("test0Snippet", array, 0);
+        test("test0Snippet", array, 2);
+        test("test0Snippet", array, 3);
+        test("test0Snippet", array, 1);
+    }
+
+    public static final char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
+
+    static int noninlineLength(char[] s) {
+        return s.length;
+    }
+
+    /**
+     * A constant with usages before and after a non-inlined call.
+     */
+    public static int test1Snippet(String s) {
+        if (s == null) {
+            return noninlineLength(alphabet) + 1;
+        }
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Test
+    public void test1() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+        test1Snippet(new String(alphabet));
+
+        test("test1Snippet", (Object) null);
+        test("test1Snippet", "test1Snippet");
+        test("test1Snippet", "");
+    }
+
+    /**
+     * A constant with only usage in a loop.
+     */
+    public static int test2Snippet(String s) {
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Test
+    public void test2() {
+        assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
+        test2Snippet(new String(alphabet));
+
+        test("test2Snippet", (Object) null);
+        test("test2Snippet", "test1Snippet");
+        test("test2Snippet", "");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java
new file mode 100644
index 0000000..7c0ba8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerTestNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class CompareCanonicalizerTest extends GraalCompilerTest {
+
+    private StructuredGraph getCanonicalizedGraph(String name) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        return graph;
+    }
+
+    private static ValueNode getResult(StructuredGraph graph) {
+        assertTrue(graph.start().next() instanceof ReturnNode);
+        ReturnNode ret = (ReturnNode) graph.start().next();
+        return ret.result();
+    }
+
+    @Test
+    public void testCanonicalComparison() {
+        StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison", AllowAssumptions.NO);
+        for (int i = 1; i < 4; i++) {
+            StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO);
+            assertEquals(referenceGraph, graph);
+        }
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        for (int i = 1; i < 4; i++) {
+            StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i);
+            assertEquals(referenceGraph, graph);
+        }
+    }
+
+    public static int referenceCanonicalComparison(int a, int b) {
+        if (a < b) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int canonicalCompare1(int a, int b) {
+        if (a >= b) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+
+    public static int canonicalCompare2(int a, int b) {
+        if (b > a) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int canonicalCompare3(int a, int b) {
+        if (b <= a) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testIntegerTest() {
+        for (int i = 1; i <= 4; i++) {
+            StructuredGraph graph = getCanonicalizedGraph("integerTest" + i);
+
+            ReturnNode returnNode = (ReturnNode) graph.start().next();
+            ConditionalNode conditional = (ConditionalNode) returnNode.result();
+            IntegerTestNode test = (IntegerTestNode) conditional.condition();
+            ParameterNode param0 = graph.getParameter(0);
+            ParameterNode param1 = graph.getParameter(1);
+            assertTrue((test.getX() == param0 && test.getY() == param1) || (test.getX() == param1 && test.getY() == param0));
+        }
+    }
+
+    public static boolean integerTest1(int x, int y) {
+        return (x & y) == 0;
+    }
+
+    public static boolean integerTest2(long x, long y) {
+        return 0 == (x & y);
+    }
+
+    public static boolean integerTest3(long x, long y) {
+        int c = 5;
+        return (c - 5) == (x & y);
+    }
+
+    public static boolean integerTest4(int x, int y) {
+        int c = 10;
+        return (x & y) == (10 - c);
+    }
+
+    @Test
+    public void testIntegerTestCanonicalization() {
+        ValueNode result = getResult(getCanonicalizedGraph("integerTestCanonicalization1"));
+        assertTrue(result.isConstant() && result.asJavaConstant().asLong() == 1);
+        result = getResult(getCanonicalizedGraph("integerTestCanonicalization2"));
+        assertTrue(result.isConstant() && result.asJavaConstant().asLong() == 1);
+        StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3");
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        assertTrue(graph.getNodes(ReturnNode.TYPE).first().result() instanceof ConditionalNode);
+    }
+
+    public static int integerTestCanonicalization1(boolean b) {
+        int x = b ? 128 : 256;
+        if ((x & 8) == 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int integerTestCanonicalization2(boolean b) {
+        int x = b ? 128 : 256;
+        int y = b ? 32 : 64;
+        if ((x & y) == 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int integerTestCanonicalization3(boolean b) {
+        int x = b ? 128 : 64;
+        int y = b ? 32 : 64;
+        if ((x & y) == 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConcreteSubtypeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConcreteSubtypeTest.java
new file mode 100644
index 0000000..19499fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConcreteSubtypeTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.Assumptions.ConcreteSubtype;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * Ensure that abstract classes with a single implementor are properly optimized and that loading a
+ * subclass below the leaf type triggers invalidation.
+ */
+public class ConcreteSubtypeTest extends GraalCompilerAssumptionsTest {
+    abstract static class AbstractBase {
+        abstract void check();
+    }
+
+    static class Subclass extends AbstractBase {
+        @Override
+        public void check() {
+            throw new InternalError();
+        }
+    }
+
+    static class SubSubclass extends Subclass {
+        @Override
+        public void check() {
+        }
+    }
+
+    public void callAbstractType(AbstractBase object) {
+        object.check();
+    }
+
+    @Override
+    protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) {
+        super.checkGraph(expectedAssumption, graph);
+        assertTrue(graph.isTrivial());
+    }
+
+    /**
+     * Test that {@link #callAbstractType} gets compiled into an empty method with a
+     * {@link ConcreteSubtype} assumption on {@link AbstractBase} and {@link Subclass}. Then ensures
+     * that loading and initialization of {@link SubSubclass} causes the compiled method to be
+     * invalidated.
+     */
+    @Test
+    public void testLeafAbstractType() {
+        testAssumptionInvalidate("callAbstractType", new ConcreteSubtype(resolveAndInitialize(AbstractBase.class), resolveAndInitialize(Subclass.class)), "SubSubclass");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java
new file mode 100644
index 0000000..1048d72
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Random;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+
+public class ConditionTest {
+
+    @Test
+    public void testImplies() {
+        Random rand = new Random(13);
+        for (Condition c1 : Condition.values()) {
+            for (Condition c2 : Condition.values()) {
+                boolean implies = c1.implies(c2);
+                if (implies) {
+                    for (int i = 0; i < 1000; i++) {
+                        JavaConstant a = JavaConstant.forInt(rand.nextInt());
+                        JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
+                        boolean result1 = c1.foldCondition(a, b, null, false);
+                        boolean result2 = c2.foldCondition(a, b, null, false);
+                        if (result1) {
+                            assertTrue(result2);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testJoin() {
+        Random rand = new Random(13);
+        for (Condition c1 : Condition.values()) {
+            for (Condition c2 : Condition.values()) {
+                Condition join = c1.join(c2);
+                assertEquals(join, c2.join(c1));
+                if (join != null) {
+                    for (int i = 0; i < 1000; i++) {
+                        JavaConstant a = JavaConstant.forInt(rand.nextInt());
+                        JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
+                        boolean result1 = c1.foldCondition(a, b, null, false);
+                        boolean result2 = c2.foldCondition(a, b, null, false);
+                        boolean resultJoin = join.foldCondition(a, b, null, false);
+                        if (result1 && result2) {
+                            assertTrue(resultJoin);
+                        } else {
+                            assertFalse(resultJoin);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testMeet() {
+        Random rand = new Random(13);
+        for (Condition c1 : Condition.values()) {
+            for (Condition c2 : Condition.values()) {
+                Condition meet = c1.meet(c2);
+                assertEquals(meet, c2.meet(c1));
+                if (meet != null) {
+                    for (int i = 0; i < 1000; i++) {
+                        JavaConstant a = JavaConstant.forInt(rand.nextInt());
+                        JavaConstant b = JavaConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
+                        boolean result1 = c1.foldCondition(a, b, null, false);
+                        boolean result2 = c2.foldCondition(a, b, null, false);
+                        boolean resultMeet = meet.foldCondition(a, b, null, false);
+                        if (result1 || result2) {
+                            assertTrue(resultMeet);
+                        } else {
+                            assertFalse(resultMeet);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationLoadFieldConstantFoldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationLoadFieldConstantFoldTest.java
new file mode 100644
index 0000000..b27daf30
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationLoadFieldConstantFoldTest.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.reflect.Field;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+
+import sun.misc.Unsafe;
+
+public class ConditionalEliminationLoadFieldConstantFoldTest extends GraalCompilerTest {
+    public static int intSideEffect;
+
+    public static final B FinalField = new B(10);
+
+    private abstract static class A {
+
+    }
+
+    private static class B extends A {
+        final int a;
+
+        B(int a) {
+            this.a = a;
+        }
+    }
+
+    private static class C extends A {
+        final B b;
+
+        C(B b) {
+            this.b = b;
+        }
+    }
+
+    private static class D extends A {
+        final C c;
+
+        D(C c) {
+            this.c = c;
+        }
+    }
+
+    private static class E extends D {
+        final Object o;
+
+        E(C c, Object o) {
+            super(c);
+            this.o = o;
+        }
+    }
+
+    public static final B CONST_B = new B(10);
+    public static final C CONST_C = new C(CONST_B);
+    public static final D CONST_D = new D(CONST_C);
+
+    public int testReadConstInBranch(B b) {
+        if (b == CONST_B) {
+            if (b.a == 5) {
+                intSideEffect = b.a;
+            } else {
+                intSideEffect = 10;
+            }
+        }
+        return 0;
+    }
+
+    public int testMultipleReadsConstInBranch(D d) {
+        if (d == CONST_D) {
+            C c = d.c;
+            B b = c.b;
+            int res = b.a + 12;
+            if (res == 125) {
+                intSideEffect = 12;
+            }
+        }
+        return 0;
+    }
+
+    public int testLoadFinalInstanceOf(E e) {
+        Object o = e.o;
+        if (o == CONST_C) {
+            if (o instanceof A) {
+                // eliminate, implied by a.x == Const(Subclass)
+                intSideEffect = 1;
+            } else {
+                intSideEffect = 10;
+            }
+        }
+        return 0;
+    }
+
+    public int testLoadFinalTwiceInstanceOf(E e) {
+        if (e.o == CONST_C) {
+            if (e.o instanceof A) {
+                intSideEffect = 1;
+            } else {
+                intSideEffect = 10;
+            }
+        }
+        return 0;
+    }
+
+    static class C1 {
+        final int a;
+
+        C1(int a) {
+            this.a = a;
+        }
+    }
+
+    static class C2 {
+        final C1 c1;
+
+        C2(C1 c1) {
+            this.c1 = c1;
+        }
+    }
+
+    public static int foldThatIsNotAllowed(C2 c2) {
+        // read before, this will be used to load through when folding
+        C1 c1Unknown = c2.c1;
+
+        // be naughty (will be a store field after canonicalization as it has a constant offset, so
+        // we would be able to eliminate the inner if after an early read elimination but we would
+        // fold before and ce the inner if already)
+        //
+        // note: if the offset would not be constant but a parameter we would not even be able to
+        // remove in inner most if as we cannot rewrite the unsafe store to a store field node as
+        // the store might kill ANY_LOCATION
+        UNSAFE.putObject(c2, C2_C1_OFFSET, C1_AFTER_READ_CONST);
+
+        if (c2 == C2_CONST) {
+            if (c1Unknown == C1_CONST) {
+                /*
+                 * This if can be eliminated (as we rewrite the unsafe store with a constant offset
+                 * to a store field node) but the remaining branch must be the false branch. If we
+                 * do not fold through both field loads we will canonicalize the unsafe store to a
+                 * store field, see the new value and can thus eliminate the true branch
+                 *
+                 * if we fold through the load fields we would load from the object read before the
+                 * store so we miss the unsafe update
+                 */
+                if (c2.c1.a == 10) {
+                    intSideEffect = 1;
+                    return 1;
+                } else {
+                    intSideEffect = 2;
+                    return 2;
+                }
+            } else {
+                intSideEffect = -2;
+                return -2;
+            }
+        } else {
+            intSideEffect = -1;
+            return -1;
+        }
+    }
+
+    public int testLoadFinalTwiceNoReadEliminationInstanceOf(E e) {
+        if (e.o == CONST_C) {
+            /*
+             * we cannot eliminate the second read of e.o although it is a final field. the call to
+             * System.gc (or any other memory checkpoint killing ANY_LOCATION) will prohibit the
+             * elimination of the second load, thus we have two different load nodes, we know that
+             * that first load field is a constant but we do not know for the second one, assuming
+             * e.o is final, as it might have been written in between
+             *
+             * this prohibits us to remove the if (fold through all loads to final fields) and the
+             * instance of e.o
+             */
+            System.gc();
+            C c = (C) e.o;
+            if (c.b.a == 10) {
+                intSideEffect = 1;
+            } else {
+                intSideEffect = 10;
+            }
+        }
+        return 0;
+
+    }
+
+    private static final C1 C1_CONST = new C1(0);
+    private static final C2 C2_CONST = new C2(C1_CONST);
+    private static final C1 C1_AFTER_READ_CONST = new C1(10);
+
+    private static Unsafe getUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+
+    private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+    private static final long C2_C1_OFFSET;
+
+    static {
+        try {
+            Field f = C2.class.getDeclaredField("c1");
+            C2_C1_OFFSET = UNSAFE.objectFieldOffset(f);
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void test01() {
+        checkGraph("testReadConstInBranch", 1);
+        test("testReadConstInBranch", new B(1));
+    }
+
+    @Test
+    public void test02() {
+        checkGraph("testMultipleReadsConstInBranch", 1);
+    }
+
+    @Test
+    public void test03() {
+        checkGraph("testLoadFinalInstanceOf", 1);
+    }
+
+    @Test
+    public void test04() {
+        checkGraph("testLoadFinalTwiceInstanceOf", 1);
+    }
+
+    @Test
+    public void test05() {
+        checkGraph("testLoadFinalTwiceNoReadEliminationInstanceOf", 2);
+    }
+
+    @Test(expected = AssertionError.class)
+    @SuppressWarnings("try")
+    public void test06() {
+        Result actual = executeActual(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
+        UNSAFE.putObject(C2_CONST, C2_C1_OFFSET, C1_CONST);
+        Result expected = executeExpected(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
+        Assert.assertEquals(expected.returnValue, actual.returnValue);
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph checkGraph(String name, int nrOfIfsAfter) {
+        StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
+        CanonicalizerPhase c = new CanonicalizerPhase();
+        c.apply(g, getDefaultHighTierContext());
+        new EarlyReadEliminationPhase(c).apply(g, getDefaultHighTierContext());
+        new IterativeConditionalEliminationPhase(c, false).apply(g, getDefaultHighTierContext());
+        Assert.assertEquals("Nr of Ifs left does not match", nrOfIfsAfter, g.getNodes().filter(IfNode.class).count());
+        c.apply(g, getDefaultHighTierContext());
+        return g;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java
new file mode 100644
index 0000000..5f8b980
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class ConditionalEliminationMulTest extends GraalCompilerTest {
+
+    public static void snippet01(int a) {
+        if (a == 2) {
+            if (a * 3 != 6) {
+                shouldBeOptimizedAway();
+            }
+        }
+    }
+
+    public static void snippet02(int a) {
+        if (a == 0) {
+            if (a * 3 != 0) {
+                shouldBeOptimizedAway();
+            }
+        }
+    }
+
+    public static void snippet03(int a) {
+        if (a * 0 == 6) {
+            shouldBeOptimizedAway();
+        }
+    }
+
+    @Test
+    public void testConditionalEliminated01() {
+        assertOptimized("snippet01");
+    }
+
+    @Test
+    public void testConditionalEliminated02() {
+        assertOptimized("snippet02");
+    }
+
+    @Test
+    public void testConditionalEliminated03() {
+        assertOptimized("snippet03");
+    }
+
+    private void assertOptimized(String snippet) {
+        assertOptimizedAway(prepareGraph(snippet));
+    }
+
+    private StructuredGraph prepareGraph(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        CanonicalizerPhase c = new CanonicalizerPhase();
+        c.apply(graph, context);
+        new DominatorConditionalEliminationPhase(false).apply(graph, context);
+        c.apply(graph, context);
+        return graph;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java
new file mode 100644
index 0000000..73a3b98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest1 extends ConditionalEliminationTestBase {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a) {
+        if (a == 0) {
+            return 1;
+        }
+        return 0;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a) {
+        if (a == 0) {
+            if (a == 5) {
+                return 100;
+            }
+            if (a > 100) {
+                if (a == 0) {
+                    return 200;
+                }
+            }
+            if (a != 2) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a) {
+        if (a == 0) {
+            if (a > 100) {
+                if (a == 0) {
+                    return 200;
+                }
+            }
+            if (a != 2) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void test3() {
+        testConditionalElimination("test3Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test3Snippet(int a) {
+        if (a == 0) {
+            if (a < 1) {
+                if (a < 2) {
+                    if (a < 3) {
+                        if (a > -1) {
+                            if (a > -2) {
+                                if (a > -3) {
+                                    if (a == 1) {
+                                        return 42;
+                                    } else {
+                                        return 1;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @SuppressWarnings("all")
+    public static int test4Snippet(int a, int b) {
+        if (b < 1) {
+            GraalDirectives.controlFlowAnchor();
+            if (b < 0) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void test4() {
+        testConditionalElimination("test4Snippet", "test4Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test5Snippet(int a, int b) {
+        if ((b & 3) == 0) {
+            GraalDirectives.controlFlowAnchor();
+            if ((b & 7) == 0) {
+                GraalDirectives.controlFlowAnchor();
+                return 1;
+            }
+        } else {
+            GraalDirectives.controlFlowAnchor();
+            if ((b & 1) == 0) {
+                GraalDirectives.controlFlowAnchor();
+                return 2;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void test5() {
+        testConditionalElimination("test5Snippet", "test5Snippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java
new file mode 100644
index 0000000..30f8db58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * This test checks the combined action of
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} and
+ * {@link org.graalvm.compiler.phases.common.LoweringPhase}. The lowering phase needs to introduce
+ * the null checks at the correct places for the dominator conditional elimination phase to pick
+ * them up.
+ */
+public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase {
+
+    private static class TestClass {
+        int x;
+    }
+
+    @SuppressWarnings("all")
+    public static int testSnippet(int a, TestClass t) {
+        int result = 0;
+        if (a == 0) {
+            GraalDirectives.controlFlowAnchor();
+            result = t.x;
+        }
+        GraalDirectives.controlFlowAnchor();
+        return result + t.x;
+    }
+
+    @Test
+    public void test1() {
+        StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        Assert.assertEquals(2, graph.getNodes().filter(GuardNode.class).count());
+        new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        Assert.assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java
new file mode 100644
index 0000000..5c2b861
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase {
+    public ConditionalEliminationTest11() {
+        // Don't disable simplification
+        super(false);
+    }
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a) {
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", "referenceSnippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a) {
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a) {
+        if ((a & 8) == 0) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", "referenceSnippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test3Snippet(int a) {
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @Test
+    public void test3() {
+        // Test forward elimination of bitwise tests
+        testConditionalElimination("test3Snippet", "referenceSnippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test4Snippet(int a) {
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) == 0) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @Test
+    public void test4() {
+        // Test forward elimination of bitwise tests
+        testConditionalElimination("test4Snippet", "referenceSnippet");
+    }
+
+    public static int test5Snippet(int a) {
+        if ((a & 5) == 5) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 7) != 0) {
+            return 0;
+        }
+        return 1;
+    }
+
+    @Test
+    public void test5() {
+        // Shouldn't be possible to optimize this
+        testConditionalElimination("test5Snippet", "test5Snippet");
+    }
+
+    public static int test6Snippet(int a) {
+        if ((a & 8) != 0) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 15) != 15) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    public static int reference6Snippet(int a) {
+        if ((a & 8) != 0) {
+            GraalDirectives.deoptimize();
+        }
+        GraalDirectives.deoptimize();
+        return 0;
+    }
+
+    @Test
+    public void test6() {
+        testConditionalElimination("test6Snippet", "reference6Snippet");
+    }
+
+    public static int test7Snippet(int a) {
+        if ((a & 15) == 15) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) == 8) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    public static int reference7Snippet(int a) {
+        if ((a & 8) == 8) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    @Test
+    public void test7() {
+        testConditionalElimination("test7Snippet", "reference7Snippet");
+    }
+
+    public static int test8Snippet(int a) {
+        if ((a & 16) == 16) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 44) != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    public static int reference8Snippet(int a) {
+        if ((a & 60) != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    @Ignore("requires merging of bit tests")
+    @Test
+    public void test8() {
+        testConditionalElimination("test8Snippet", "reference8Snippet");
+    }
+
+    public static int test9Snippet(int a) {
+        if ((a & 16) == 16) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 44) != 44) {
+            GraalDirectives.deoptimize();
+        }
+        if (a != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    public static int reference9Snippet(int a) {
+        if (a != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return a;
+    }
+
+    @Test
+    public void test9() {
+        testConditionalElimination("test9Snippet", "reference9Snippet");
+    }
+
+    static class ByteHolder {
+        public byte b;
+
+        byte byteValue() {
+            return b;
+        }
+    }
+
+    public static int test10Snippet(ByteHolder b) {
+        int v = b.byteValue();
+        long a = v & 0xffffffff;
+        if (v != 44) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 16) == 16) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 44) != 44) {
+            GraalDirectives.deoptimize();
+        }
+
+        return v;
+    }
+
+    public static int reference10Snippet(ByteHolder b) {
+        byte v = b.byteValue();
+        if (v != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return v;
+    }
+
+    @Test
+    public void test10() {
+        testConditionalElimination("test10Snippet", "reference10Snippet");
+    }
+
+    public static int test11Snippet(ByteHolder b) {
+        int v = b.byteValue();
+        long a = v & 0xffffffff;
+
+        if ((a & 16) == 16) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 8) != 8) {
+            GraalDirectives.deoptimize();
+        }
+        if ((a & 44) != 44) {
+            GraalDirectives.deoptimize();
+        }
+        if (v != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return v;
+    }
+
+    public static int reference11Snippet(ByteHolder b) {
+        byte v = b.byteValue();
+        if (v != 44) {
+            GraalDirectives.deoptimize();
+        }
+        return v;
+    }
+
+    @Test
+    public void test11() {
+        testConditionalElimination("test11Snippet", "reference11Snippet");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java
new file mode 100644
index 0000000..0e96044
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase {
+
+    public static Object field;
+
+    static class Entry {
+
+        final String name;
+
+        Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+
+        EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry search(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    public static int testRedundantComparesSnippet(int[] array) {
+        if (array == null) {
+            return 0;
+        }
+        return array[0] + array[1] + array[2] + array[3];
+    }
+
+    @Test
+    public void testRedundantCompares() {
+        StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        PhaseContext context = new PhaseContext(getProviders());
+
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    }
+
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
+        }
+        return null;
+    }
+
+    @Test
+    public void testInstanceOfCheckCastLowered() {
+        StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES);
+
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        PhaseContext context = new PhaseContext(getProviders());
+
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java
new file mode 100644
index 0000000..ef8d7c7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest3 extends ConditionalEliminationTestBase {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a, int b) {
+        int sum = 0;
+        outer: for (int i = 0;; ++i) {
+            if (b > 100) {
+                inner: for (int j = 0;; ++j) {
+                    ++sum;
+                    if (sum == 100) {
+                        break inner;
+                    }
+                    if (sum == 1000 && b < 1000) {
+                        break outer;
+                    }
+                }
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a, int b) {
+        int sum = 0;
+        outer: for (int i = 0;; ++i) {
+            if (b > 100) {
+                inner: for (int j = 0;; ++j) {
+                    ++sum;
+                    if (sum == 100) {
+                        break inner;
+                    }
+                    if (sum == 1000 && b < 1000) {
+                        break outer;
+                    }
+                }
+            }
+        }
+        if (b >= 1000) {
+            return 5;
+        }
+        return sum;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a, int b) {
+        int sum = 0;
+        outer: for (int i = 0;; ++i) {
+            if (b > 100) {
+                inner: for (int j = 0;; ++j) {
+                    ++sum;
+                    if (sum == 100) {
+                        break inner;
+                    }
+                    if (sum == 1000 && b < 1000) {
+                        break outer;
+                    }
+                }
+                if (sum != 100) {
+                    return 42;
+                }
+            }
+        }
+        return sum;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java
new file mode 100644
index 0000000..1daf7a5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest4 extends ConditionalEliminationTestBase {
+
+    @SuppressWarnings("all")
+    public static int reference1Snippet(int a, int b) {
+        if (a > b) {
+            return 1;
+        }
+        return 2;
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a, int b) {
+        if (a > b) {
+            if (a > b) {
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", "reference1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int reference2Snippet(int a, int b) {
+        if (a < b) {
+            return 1;
+        }
+        return 2;
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a, int b) {
+        if (a < b) {
+            if (a < b) {
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", "reference2Snippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java
new file mode 100644
index 0000000..255e5a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase {
+
+    interface A {
+    }
+
+    interface B extends A {
+    }
+
+    static final class DistinctA {
+    }
+
+    static final class DistinctB {
+    }
+
+    public static int reference1Snippet(Object a) {
+        if (a instanceof B) {
+            return 1;
+        }
+        return 2;
+    }
+
+    public static int test1Snippet(Object a) {
+        if (a instanceof B) {
+            if (a instanceof A) {
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", "reference1Snippet");
+    }
+
+    public static int reference2Snippet(A a) {
+        if (a instanceof B) {
+            return 1;
+        }
+        return 2;
+    }
+
+    public static int test2Snippet(A a) {
+        if (a instanceof B) {
+            B newVal = (B) a;
+            if (newVal != null) {
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", "reference2Snippet");
+    }
+
+    @SuppressWarnings("unused")
+    public static int reference3Snippet(Object a, Object b) {
+        if (a instanceof DistinctA) {
+            DistinctA proxyA = (DistinctA) a;
+            if (b instanceof DistinctB) {
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @SuppressWarnings("all")
+    public static int test3Snippet(Object a, Object b) {
+        if (a instanceof DistinctA) {
+            DistinctA proxyA = (DistinctA) a;
+            if (b instanceof DistinctB) {
+                if (proxyA == b) {
+                    return 42;
+                }
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void test3() {
+        testConditionalElimination("test3Snippet", "reference3Snippet", true);
+    }
+
+    public static int reference4Snippet(Object a) {
+        if (!(a instanceof B)) {
+            GraalDirectives.deoptimize();
+        }
+        return 1;
+    }
+
+    public static int test4Snippet1(Object a) {
+        if (!(a instanceof B)) {
+            GraalDirectives.deoptimize();
+        }
+        if (!(a instanceof A)) {
+            GraalDirectives.deoptimize();
+        }
+        return 1;
+    }
+
+    public static int test4Snippet2(Object a) {
+        if (!(a instanceof A)) {
+            GraalDirectives.deoptimize();
+        }
+        if (!(a instanceof B)) {
+            GraalDirectives.deoptimize();
+        }
+        return 1;
+    }
+
+    @Test
+    public void test4() {
+        testConditionalElimination("test4Snippet1", "reference4Snippet");
+        testConditionalElimination("test4Snippet2", "reference4Snippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java
new file mode 100644
index 0000000..7617360
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest6 extends ConditionalEliminationTestBase {
+
+    public static final A constA = new A();
+    public static final B constB = new B();
+
+    static class A {
+    }
+
+    static class B {
+    }
+
+    @SuppressWarnings("all")
+    public static B reference1Snippet(Object a, B b) {
+        if (a == constA) {
+            return b;
+        }
+        return null;
+    }
+
+    @SuppressWarnings("all")
+    public static B test1Snippet(Object a, B b) {
+        if (a == constA) {
+            if (a == null) {
+                return null;
+            } else {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", "reference1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static B test2Snippet(Object a, B b) {
+        if (a == constA) {
+            if (a == constB) {
+                return null;
+            } else {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void test2() {
+        testConditionalElimination("test2Snippet", "reference1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static B test3Snippet(Object a, B b) {
+        if (a == constA) {
+            if (a == b) {
+                return null;
+            } else {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void test3() {
+        testConditionalElimination("test3Snippet", "reference1Snippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java
new file mode 100644
index 0000000..a6f69e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest7 extends ConditionalEliminationTestBase {
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a, Object b) {
+        int sum = 0;
+        for (int j = 0;; ++j) {
+            ++sum;
+            if (b instanceof String) {
+                if (sum == 100) {
+                    break;
+                }
+            }
+        }
+        String s = (String) b;
+        return s.length() + sum;
+    }
+
+    @Test
+    public void test1() {
+        // One loop exit is skipped.
+        testProxies("test1Snippet", 1);
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a, Object b) {
+        int sum = 0;
+        for (int j = 0;; ++j) {
+            ++sum;
+            if (b instanceof String) {
+                break;
+            }
+        }
+        String s = (String) b;
+        return s.length() + sum;
+    }
+
+    @Test
+    public void test2() {
+        // The loop exit is the anchor => no proxy necessary.
+        testProxies("test2Snippet", 0);
+    }
+
+    @SuppressWarnings("all")
+    public static int test3Snippet(int a, Object b) {
+        int sum = a;
+        outer: while (true) {
+            sum++;
+            while (sum++ != 20) {
+                while (sum++ != 30) {
+                    while (sum++ != 40) {
+                        while (sum++ != 50) {
+                            if (b instanceof String) {
+                                break outer;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        String s = (String) b;
+        return s.length() + sum;
+    }
+
+    @Test
+    public void test3() {
+        // The break skips over 4 other loops.
+        testProxies("test3Snippet", 4);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java
new file mode 100644
index 0000000..5249811
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest8 extends ConditionalEliminationTestBase {
+
+    private static double value;
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a, Object b) {
+        double sum = 0;
+        if (!(b instanceof String)) {
+            return 42;
+        }
+        for (int j = 0; j < a; ++j) {
+            sum += value;
+        }
+        return ((String) b).length();
+    }
+
+    @Test
+    public void test1() {
+        // One loop exit is skipped, because the condition dominates also the loop begin.
+        testProxies("test1Snippet", 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java
new file mode 100644
index 0000000..2ac03bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest9 extends ConditionalEliminationTestBase {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a) {
+        if (a == 0) {
+            GraalDirectives.deoptimize();
+        }
+        return 0;
+    }
+
+    @Test
+    public void test1() {
+        testConditionalElimination("test1Snippet", REFERENCE_SNIPPET);
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a) {
+        if (a == 0) {
+            if (a == 0) {
+                GraalDirectives.deoptimize();
+            }
+            if (a == 0) {
+                GraalDirectives.deoptimize();
+            }
+        }
+        return 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java
new file mode 100644
index 0000000..32c8f5f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * Collection of tests for
+ * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
+ * that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTestBase extends GraalCompilerTest {
+
+    private final boolean disableSimplification;
+
+    protected ConditionalEliminationTestBase() {
+        disableSimplification = true;
+    }
+
+    protected ConditionalEliminationTestBase(boolean disableSimplification) {
+        this.disableSimplification = disableSimplification;
+    }
+
+    protected void testConditionalElimination(String snippet, String referenceSnippet) {
+        testConditionalElimination(snippet, referenceSnippet, false);
+    }
+
+    @SuppressWarnings("try")
+    protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
+        if (disableSimplification) {
+            /**
+             * Some tests break if simplification is done so only do it when needed.
+             */
+            canonicalizer1.disableSimplification();
+        }
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) {
+            canonicalizer1.apply(graph, context);
+            new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+            // new DominatorConditionalEliminationPhase(true).apply(graph, context);
+            new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+            canonicalizer.apply(graph, context);
+            canonicalizer.apply(graph, context);
+            new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+        } catch (Throwable t) {
+            Debug.handle(t);
+        }
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
+        try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) {
+
+            new ConvertDeoptimizeToGuardPhase().apply(referenceGraph, context);
+            if (applyConditionalEliminationOnReference) {
+                new DominatorConditionalEliminationPhase(true).apply(referenceGraph, context);
+                canonicalizer.apply(referenceGraph, context);
+                canonicalizer.apply(referenceGraph, context);
+            } else {
+                canonicalizer.apply(referenceGraph, context);
+            }
+        } catch (Throwable t) {
+            Debug.handle(t);
+        }
+        assertEquals(referenceGraph, graph);
+    }
+
+    public void testProxies(String snippet, int expectedProxiesCreated) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
+        canonicalizer1.disableSimplification();
+        canonicalizer1.apply(graph, context);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        int baseProxyCount = graph.getNodes().filter(ProxyNode.class).count();
+        new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new SchedulePhase().apply(graph, context);
+        int actualProxiesCreated = graph.getNodes().filter(ProxyNode.class).count() - baseProxyCount;
+        Assert.assertEquals(expectedProxiesCreated, actualProxiesCreated);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConstantArrayReadFoldingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConstantArrayReadFoldingTest.java
new file mode 100644
index 0000000..4bdf5fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConstantArrayReadFoldingTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+public class ConstantArrayReadFoldingTest extends GraalCompilerTest {
+
+    enum E {
+        A(0.001),
+        B(0.01),
+        C(0.5),
+        D(2.0),
+        E(3.0),
+        F(4.0),
+        G(5.0);
+
+        public final double ceiling;
+        public double weight;
+
+        E(double ceiling) {
+            this.ceiling = ceiling;
+        }
+    }
+
+    public Object test1Snippet(double value) {
+        for (E kind : E.values()) {
+            if (value <= kind.ceiling) {
+                return kind;
+            }
+        }
+        throw new IllegalArgumentException();
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", 1.0);
+        test("test1Snippet", 2.0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CooperativePhaseTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CooperativePhaseTest.java
new file mode 100644
index 0000000..c5e2ecb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CooperativePhaseTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.core.common.util.CompilationAlarm;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.Phase;
+
+public class CooperativePhaseTest extends GraalCompilerTest {
+
+    public static void snippet() {
+        // dummy snippet
+    }
+
+    private static class CooperativePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            while (true) {
+                sleep(200);
+                if (CompilationAlarm.hasExpired()) {
+                    return;
+                }
+            }
+        }
+
+    }
+
+    private static class UnCooperativePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            while (true) {
+                sleep(200);
+                if (CompilationAlarm.hasExpired()) {
+                    throw new RetryableBailoutException("Expiring...");
+                }
+            }
+        }
+
+    }
+
+    private static class ParlyCooperativePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            for (int i = 0; i < 10; i++) {
+                sleep(200);
+                if (CompilationAlarm.hasExpired()) {
+                    throw new RuntimeException("Phase must not exit in the timeout path");
+                }
+            }
+        }
+    }
+
+    private static class CooperativePhaseWithoutAlarm extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            if (CompilationAlarm.hasExpired()) {
+                throw new RuntimeException("Phase must not exit in the timeout path");
+            }
+        }
+    }
+
+    private static void sleep(long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+            GraalError.shouldNotReachHere(e.getCause());
+        }
+    }
+
+    @Test(timeout = 60_000)
+    @SuppressWarnings("try")
+    public void test01() {
+        StructuredGraph g = parseEager("snippet", AllowAssumptions.NO);
+        try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 1/* sec */);
+                        CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) {
+            new CooperativePhase().apply(g);
+        }
+    }
+
+    @Test(expected = RetryableBailoutException.class, timeout = 60_000)
+    @SuppressWarnings("try")
+    public void test02() {
+        StructuredGraph g = parseEager("snippet", AllowAssumptions.NO);
+        try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 1/* sec */);
+                        CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) {
+            new UnCooperativePhase().apply(g);
+        }
+    }
+
+    @Test(timeout = 60_000)
+    @SuppressWarnings("try")
+    public void test03() {
+        StructuredGraph g = parseEager("snippet", AllowAssumptions.NO);
+        // 0 disables alarm utility
+        try (OverrideScope o = OptionValue.override(CompilationAlarm.Options.CompilationExpirationPeriod, 0);
+                        CompilationAlarm c1 = CompilationAlarm.trackCompilationPeriod()) {
+            new ParlyCooperativePhase().apply(g);
+        }
+    }
+
+    @Test(timeout = 60_000)
+    @SuppressWarnings("try")
+    public void test04() {
+        StructuredGraph g = parseEager("snippet", AllowAssumptions.NO);
+        new CooperativePhaseWithoutAlarm().apply(g);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java
new file mode 100644
index 0000000..6251a54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.test;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+
+public class CopyOfVirtualizationTest extends GraalCompilerTest {
+
+    @Override
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph);
+        return super.checkMidTierGraph(graph);
+    }
+
+    public byte byteCopyOfVirtualization(int index) {
+        byte[] array = new byte[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public short shortCopyOfVirtualization(int index) {
+        short[] array = new short[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public char charCopyOfVirtualization(int index) {
+        char[] array = new char[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public int intCopyOfVirtualization(int index) {
+        int[] array = new int[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public long longCopyOfVirtualization(int index) {
+        long[] array = new long[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public float floatCopyOfVirtualization(int index) {
+        float[] array = new float[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public double doubleCopyOfVirtualization(int index) {
+        double[] array = new double[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    public Object objectCopyOfVirtualization(int index) {
+        Object[] array = new Object[]{1, 2, 3, 4};
+        return Arrays.copyOf(array, array.length)[index];
+    }
+
+    // @Test
+    public void testCopyOfVirtualization() {
+        test("byteCopyOfVirtualization", 3);
+        test("shortCopyOfVirtualization", 3);
+        test("charCopyOfVirtualization", 3);
+        test("intCopyOfVirtualization", 3);
+        test("longCopyOfVirtualization", 3);
+        test("floatCopyOfVirtualization", 3);
+        test("doubleCopyOfVirtualization", 3);
+        test("objectCopyOfVirtualization", 3);
+    }
+
+    static final byte[] byteArray = new byte[]{1, 2, 3, 4};
+
+    public byte byteCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(byteArray, byteArray.length)[3];
+    }
+
+    static final short[] shortArray = new short[]{1, 2, 3, 4};
+
+    public short shortCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(shortArray, shortArray.length)[3];
+    }
+
+    static final char[] charArray = new char[]{1, 2, 3, 4};
+
+    public char charCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(charArray, charArray.length)[3];
+    }
+
+    static final int[] intArray = new int[]{1, 2, 3, 4};
+
+    public int intCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(intArray, intArray.length)[3];
+    }
+
+    static final long[] longArray = new long[]{1, 2, 3, 4};
+
+    public long longCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(longArray, longArray.length)[3];
+    }
+
+    static final float[] floatArray = new float[]{1, 2, 3, 4};
+
+    public float floatCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(floatArray, floatArray.length)[3];
+    }
+
+    static final double[] doubleArray = new double[]{1, 2, 3, 4};
+
+    public double doubleCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(doubleArray, doubleArray.length)[3];
+    }
+
+    static final Object[] objectArray = new Object[]{1, 2, 3, 4};
+
+    public Object objectCopyOfVirtualizableAllocation() {
+        return Arrays.copyOf(objectArray, objectArray.length)[3];
+    }
+
+    @Test
+    public void testCopyOfVirtualizableAllocation() {
+        test("byteCopyOfVirtualizableAllocation");
+        test("shortCopyOfVirtualizableAllocation");
+        test("charCopyOfVirtualizableAllocation");
+        test("intCopyOfVirtualizableAllocation");
+        test("longCopyOfVirtualizableAllocation");
+        test("floatCopyOfVirtualizableAllocation");
+        test("doubleCopyOfVirtualizableAllocation");
+        test("objectCopyOfVirtualizableAllocation");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java
new file mode 100644
index 0000000..7655e3a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.loop.InductionVariable;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class CountedLoopTest extends GraalCompilerTest {
+
+    @FunctionalInterface
+    private interface IVProperty {
+        ValueNode get(InductionVariable iv);
+    }
+
+    /**
+     * Get a property of an induction variable.
+     *
+     * @param property
+     */
+    private static int get(IVProperty property, int iv) {
+        return iv;
+    }
+
+    private static class Result {
+        public int extremum;
+        public int exitValue;
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + exitValue;
+            result = prime * result + extremum;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Result)) {
+                return false;
+            }
+            Result other = (Result) obj;
+            return extremum == other.extremum && exitValue == other.exitValue;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("extremum = %d, exitValue = %d", extremum, exitValue);
+        }
+    }
+
+    public static Result incrementSnippet(int start, int limit, int step) {
+        int i;
+        int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
+        Result ret = new Result();
+        for (i = start; i < limit; i += inc) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void increment1() {
+        test("incrementSnippet", 0, 256, 1);
+    }
+
+    @Test
+    public void increment2() {
+        test("incrementSnippet", 0, 256, 2);
+    }
+
+    @Test
+    public void increment3() {
+        test("incrementSnippet", 0, 256, 3);
+    }
+
+    public static Result incrementEqSnippet(int start, int limit, int step) {
+        int i;
+        int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
+        Result ret = new Result();
+        for (i = start; i <= limit; i += inc) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void incrementEq1() {
+        test("incrementEqSnippet", 0, 256, 1);
+    }
+
+    @Test
+    public void incrementEq2() {
+        test("incrementEqSnippet", 0, 256, 2);
+    }
+
+    @Test
+    public void incrementEq3() {
+        test("incrementEqSnippet", 0, 256, 3);
+    }
+
+    public static Result decrementSnippet(int start, int limit, int step) {
+        int i;
+        int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
+        Result ret = new Result();
+        for (i = start; i > limit; i -= dec) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void decrement1() {
+        test("decrementSnippet", 256, 0, 1);
+    }
+
+    @Test
+    public void decrement2() {
+        test("decrementSnippet", 256, 0, 2);
+    }
+
+    @Test
+    public void decrement3() {
+        test("decrementSnippet", 256, 0, 3);
+    }
+
+    public static Result decrementEqSnippet(int start, int limit, int step) {
+        int i;
+        int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
+        Result ret = new Result();
+        for (i = start; i >= limit; i -= dec) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void decrementEq1() {
+        test("decrementEqSnippet", 256, 0, 1);
+    }
+
+    @Test
+    public void decrementEq2() {
+        test("decrementEqSnippet", 256, 0, 2);
+    }
+
+    @Test
+    public void decrementEq3() {
+        test("decrementEqSnippet", 256, 0, 3);
+    }
+
+    public static Result twoVariablesSnippet() {
+        Result ret = new Result();
+        int j = 0;
+        for (int i = 0; i < 1024; i++) {
+            j += 5;
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, j);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, j);
+        return ret;
+    }
+
+    @Test
+    public void testTwoVariables() {
+        test("twoVariablesSnippet");
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    private static class IVPropertyNode extends FloatingNode implements LIRLowerable {
+
+        public static final NodeClass<IVPropertyNode> TYPE = NodeClass.create(IVPropertyNode.class);
+
+        private final IVProperty property;
+        @Input private ValueNode iv;
+
+        protected IVPropertyNode(IVProperty property, ValueNode iv) {
+            super(TYPE, iv.stamp().unrestricted());
+            this.property = property;
+            this.iv = iv;
+        }
+
+        public void rewrite(LoopsData loops) {
+            InductionVariable inductionVariable = loops.getInductionVariable(iv);
+            assert inductionVariable != null;
+            ValueNode node = property.get(inductionVariable);
+            replaceAtUsagesAndDelete(node);
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool gen) {
+            gen.setResult(this, gen.operand(iv));
+        }
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), CountedLoopTest.class);
+
+        r.register2("get", IVProperty.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
+                IVProperty property = null;
+                if (arg1.isConstant()) {
+                    property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
+                }
+                if (property != null) {
+                    b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2));
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        });
+
+        return plugins;
+    }
+
+    @Override
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        LoopsData loops = new LoopsData(graph);
+        loops.detectedCountedLoops();
+        for (IVPropertyNode node : graph.getNodes().filter(IVPropertyNode.class)) {
+            node.rewrite(loops);
+        }
+        assert graph.getNodes().filter(IVPropertyNode.class).isEmpty();
+        return true;
+    }
+
+    public static Result incrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = 0; i != posLimit; i++) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void decrementNeq() {
+        test("decrementNeqSnippet", 256);
+    }
+
+    public static Result decrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = posLimit; i != 0; i--) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void incrementNeq() {
+        test("incrementNeqSnippet", 256);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java
new file mode 100644
index 0000000..3ea30c0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+/**
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant
+ * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the
+ * graph of the method that just has a "return 1" statement in it.
+ */
+public class DegeneratedLoopsTest extends GraalCompilerTest {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a) {
+        return a;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    private static class UnresolvedException extends RuntimeException {
+
+        private static final long serialVersionUID = 5215434338750728440L;
+
+        static {
+            if (true) {
+                throw new UnsupportedOperationException("this class may never be initialized");
+            }
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a) {
+        for (;;) {
+            try {
+                test();
+                break;
+            } catch (UnresolvedException e) {
+            }
+        }
+        return a;
+    }
+
+    private static void test() {
+
+    }
+
+    @SuppressWarnings("try")
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            HighTierContext context = getDefaultHighTierContext();
+            new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+            new CanonicalizerPhase().apply(graph, context);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+            StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, referenceGraph, "ReferenceGraph");
+            assertEquals(referenceGraph, graph);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DontReuseArgumentSpaceTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DontReuseArgumentSpaceTest.java
new file mode 100644
index 0000000..776497e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DontReuseArgumentSpaceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public final class DontReuseArgumentSpaceTest extends GraalCompilerTest {
+
+    @Override
+    @SuppressWarnings("try")
+    protected Suites createSuites() {
+        try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) {
+            return super.createSuites();
+        }
+    }
+
+    @BytecodeParserNeverInline
+    public static int killArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+        return a + b + c + d + e + f + g + h + i + j;
+    }
+
+    @BytecodeParserNeverInline
+    public static int callTwice(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+        /*
+         * Call the same method twice so the arguments are in the same place each time and might
+         * appear to be redundant moves.
+         */
+        killArguments(a, b, c, d, e, f, g, h, i, j);
+        return killArguments(a, b, c, d, e, f, g, h, i, j);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        /*
+         * Exercise the methods once so everything is resolved
+         */
+        callTwice(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+
+        /*
+         * Create a standalone compile of killArguments. This test assumes that zapping of argument
+         * space is being performed by the backend.
+         */
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod("killArguments");
+        StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES);
+        CompilationResult compilationResult = compile(javaMethod, graph);
+        getBackend().createDefaultInstalledCode(javaMethod, compilationResult);
+
+        test("callTwice", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java
new file mode 100644
index 0000000..80df81d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+public class EnumSwitchTest extends GraalCompilerTest {
+
+    enum E {
+        E0,
+        E1,
+        E2,
+        E3,
+        E4,
+        E5,
+        E6,
+        E7,
+        E8,
+        E9,
+        E10,
+        E11,
+        E12,
+        E13,
+        E14,
+        E15,
+        E16,
+        E17,
+        E18,
+        E19,
+        E20
+    }
+
+    public int test1Snippet(E e) {
+        switch (e) {
+            case E0:
+                return 0;
+            case E1:
+                return 1;
+            case E2:
+                return 2;
+            case E3:
+                return 3;
+            case E4:
+                return 4;
+            case E5:
+                return 5;
+            case E6:
+                return 6;
+            case E7:
+                return 7;
+            case E8:
+                return 8;
+            case E9:
+                return 9;
+            case E10:
+                return 10;
+            case E11:
+                return 11;
+            case E12:
+                return 12;
+            case E13:
+                return 13;
+            case E14:
+                return 14;
+            case E15:
+                return 15;
+            case E16:
+                return 16;
+            case E17:
+                return 17;
+            case E18:
+                return 18;
+            case E19:
+                return 19;
+            case E20:
+                return 20;
+            default:
+                return -1;
+        }
+    }
+
+    @Test
+    public void test1() {
+        for (E e : E.values()) {
+            test("test1Snippet", e);
+        }
+        test("test1Snippet", new Object[]{null});
+    }
+
+    public int test2Snippet(E e) {
+        switch (e) {
+            case E5:
+            case E19:
+            case E20:
+                return 1;
+            case E8:
+            case E9:
+            case E10:
+                return 2;
+        }
+        return -1;
+    }
+
+    @Test
+    public void test2() {
+        for (E e : E.values()) {
+            test("test2Snippet", e);
+        }
+        test("test2Snippet", new Object[]{null});
+    }
+
+    @Override
+    protected Suites createSuites() {
+        Suites ret = super.createSuites();
+        ret.getHighTier().prependPhase(new Phase() {
+            @Override
+            protected void run(StructuredGraph graph) {
+                /* Array load from the enum switch map. */
+                assertTrue(graph.getNodes().filter(LoadIndexedNode.class).count() == 1);
+                /* The actual switch. */
+                assertTrue(graph.getNodes().filter(IntegerSwitchNode.class).count() == 1);
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "CheckGraphPhase";
+            }
+        });
+        ret.getHighTier().findPhase(RemoveValueProxyPhase.class).add(new Phase() {
+            @Override
+            protected void run(StructuredGraph graph) {
+                /* Re-writing of the switch cases eliminates the array load. */
+                assertTrue(graph.getNodes().filter(LoadIndexedNode.class).count() == 0);
+                /* The switch is still there. */
+                assertTrue(graph.getNodes().filter(IntegerSwitchNode.class).count() == 1);
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "CheckGraphPhase";
+            }
+        });
+        return ret;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java
new file mode 100644
index 0000000..bd5c99f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.Assumptions.LeafType;
+import jdk.vm.ci.meta.Assumptions.NoFinalizableSubclass;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class FinalizableSubclassTest extends GraalCompilerTest {
+
+    /**
+     * used as template to generate class files at runtime.
+     */
+    public static class NoFinalizerEverAAAA {
+    }
+
+    public static class NoFinalizerYetAAAA {
+    }
+
+    public static final class WithFinalizerAAAA extends NoFinalizerYetAAAA {
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+        }
+    }
+
+    private StructuredGraph parseAndProcess(Class<?> cl, AllowAssumptions allowAssumptions) {
+        Constructor<?>[] constructors = cl.getConstructors();
+        Assert.assertTrue(constructors.length == 1);
+        final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]);
+        StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions, NO_PROFILING_INFO, INVALID_COMPILATION_ID);
+
+        GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins());
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf,
+                        OptimisticOptimizations.ALL, null).apply(graph);
+        HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, context);
+        return graph;
+    }
+
+    private void checkForRegisterFinalizeNode(Class<?> cl, boolean shouldContainFinalizer, AllowAssumptions allowAssumptions) {
+        StructuredGraph graph = parseAndProcess(cl, allowAssumptions);
+        Assert.assertTrue(graph.getNodes().filter(RegisterFinalizerNode.class).count() == (shouldContainFinalizer ? 1 : 0));
+        int noFinalizerAssumption = 0;
+        Assumptions assumptions = graph.getAssumptions();
+        if (assumptions != null) {
+            for (Assumption a : assumptions) {
+                if (a instanceof NoFinalizableSubclass) {
+                    noFinalizerAssumption++;
+                } else if (a instanceof LeafType) {
+                    // Need to also allow leaf type assumption instead of no finalizable subclass
+                    // assumption.
+                    noFinalizerAssumption++;
+                }
+            }
+        }
+        Assert.assertTrue(noFinalizerAssumption == (shouldContainFinalizer ? 0 : 1));
+    }
+
+    /**
+     * Use a custom class loader to generate classes, to make sure the given classes are loaded in
+     * correct order.
+     */
+    @Test
+    public void test1() throws ClassNotFoundException {
+        for (int i = 0; i < 2; i++) {
+            ClassTemplateLoader loader = new ClassTemplateLoader();
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, AllowAssumptions.NO);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, AllowAssumptions.YES);
+
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, AllowAssumptions.YES);
+
+            checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, AllowAssumptions.YES);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, AllowAssumptions.YES);
+        }
+    }
+
+    private static class ClassTemplateLoader extends ClassLoader {
+
+        private static int loaderInstance = 0;
+
+        private final String replaceTo;
+        private HashMap<String, Class<?>> cache = new HashMap<>();
+
+        ClassTemplateLoader() {
+            loaderInstance++;
+            replaceTo = String.format("%04d", loaderInstance);
+        }
+
+        @Override
+        protected Class<?> findClass(final String name) throws ClassNotFoundException {
+            String nameReplaced = name.replaceAll("AAAA", replaceTo);
+            if (cache.containsKey(nameReplaced)) {
+                return cache.get(nameReplaced);
+            }
+
+            // copy classfile to byte array
+            byte[] classData = null;
+            try {
+                InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class");
+                assert is != null;
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+                byte[] buf = new byte[1024];
+                int size;
+                while ((size = is.read(buf, 0, buf.length)) != -1) {
+                    baos.write(buf, 0, size);
+                }
+                baos.flush();
+                classData = baos.toByteArray();
+            } catch (IOException e) {
+                Assert.fail("can't access class: " + name);
+            }
+            dumpStringsInByteArray(classData);
+
+            // replace all occurrences of "AAAA" in classfile
+            int index = -1;
+            while ((index = indexOfAAAA(classData, index + 1)) != -1) {
+                replaceAAAA(classData, index, replaceTo);
+            }
+            dumpStringsInByteArray(classData);
+
+            Class<?> c = defineClass(null, classData, 0, classData.length);
+            cache.put(nameReplaced, c);
+            return c;
+        }
+
+        private static int indexOfAAAA(byte[] b, int index) {
+            for (int i = index; i < b.length; i++) {
+                boolean match = true;
+                for (int j = i; j < i + 4; j++) {
+                    if (b[j] != (byte) 'A') {
+                        match = false;
+                        break;
+                    }
+                }
+                if (match) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        private static void replaceAAAA(byte[] b, int index, String replacer) {
+            assert replacer.length() == 4;
+            for (int i = index; i < index + 4; i++) {
+                b[i] = (byte) replacer.charAt(i - index);
+            }
+        }
+
+        private static void dumpStringsInByteArray(byte[] b) {
+            boolean wasChar = true;
+            StringBuilder sb = new StringBuilder();
+            for (Byte x : b) {
+                // check for [a-zA-Z0-9]
+                if ((x >= 0x41 && x <= 0x7a) || (x >= 0x30 && x <= 0x39)) {
+                    if (!wasChar) {
+                        Debug.log(sb + "");
+                        sb.setLength(0);
+                    }
+                    sb.append(String.format("%c", x));
+                    wasChar = true;
+                } else {
+                    wasChar = false;
+                }
+            }
+            Debug.log(sb + "");
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueConcreteMethodBugTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueConcreteMethodBugTest.java
new file mode 100644
index 0000000..4236527
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueConcreteMethodBugTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest {
+
+    // To cause a C1 or C2 crash: -DFindUniqueConcreteMethodBugTest.ITERATIONS=10000
+    private static final int ITERATIONS = Integer.getInteger("FindUniqueConcreteMethodBugTest.ITERATIONS", 100);
+
+    /**
+     * Executing {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)} for the
+     * method {@link Person#getName()} on the type {@link AbstractPerson} should return null as both
+     * {@link PersonImpl} and {@link TenantImpl} provide implementations (namely
+     * {@link PersonImpl#getName()} and {@link Tenant#getName()}).
+     */
+    @Test
+    @Ignore("fix HotSpotResolvedObjectTypeImpl.findUniqueConcreteMethod")
+    public void test() throws NoSuchMethodException {
+        ResolvedJavaMethod ifaceMethod = getMetaAccess().lookupJavaMethod(Person.class.getDeclaredMethod("getName"));
+
+        PersonImpl person = new PersonImpl("maya");
+        TenantImpl tenant = new TenantImpl(0xdeadbeef);
+
+        // Ensure the relevant methods are linked
+        person.getName();
+        tenant.getName();
+
+        for (int i = 0; i < ITERATIONS; i++) {
+            getLabelLength(person);
+            getLabelLength(tenant);
+        }
+
+        // Until HotSpotResolvedObjectTypeImpl.findUniqueConcreteMethod is fixed,
+        // this causes a VM crash as getLabelLength() directly invokes PersonImpl.getName().
+        test("getLabelLength", tenant);
+
+        ResolvedJavaMethod expected = null;
+        AssumptionResult<ResolvedJavaMethod> actual = getMetaAccess().lookupJavaType(AbstractPerson.class).findUniqueConcreteMethod(ifaceMethod);
+        Assert.assertEquals(expected, actual.getResult());
+
+    }
+
+    public int getLabelLength(AbstractPerson person) {
+        return person.getName().length();
+    }
+
+    interface Person {
+        String getName();
+
+        default int getId() {
+            return -1;
+        }
+    }
+
+    interface Tenant extends Person {
+        @Override
+        default String getName() {
+            return getAddress();
+        }
+
+        String getAddress();
+    }
+
+    abstract static class AbstractPerson implements Person {
+    }
+
+    static class PersonImpl extends AbstractPerson {
+        public String name;
+
+        PersonImpl(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    static class TenantImpl extends AbstractPerson implements Tenant {
+        public int id;
+
+        TenantImpl(int id) {
+            this.id = id;
+        }
+
+        @Override
+        public String getAddress() {
+            return String.valueOf(id);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java
new file mode 100644
index 0000000..97851bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+/**
+ * This test illustrates problems and limitations with class hierarchy analysis when default methods
+ * are involved.
+ */
+public class FindUniqueDefaultMethodTest extends GraalCompilerTest {
+
+    interface Interface1 {
+        default int v1() {
+            return 1;
+        }
+    }
+
+    static class Implementor1 implements Interface1 {
+        int callV1() {
+            return v1();
+        }
+    }
+
+    static class Subclass1 extends Implementor1 {
+
+    }
+
+    /**
+     * HotSpot has an internal mismatch with CHA and default methods. The initial query says that
+     * it's a unique method but the verification code that ensures that a dependence of this kind
+     * would pass will fail an assert in debug mode.
+     */
+    @Test
+    public void testFindUnique() {
+        ResolvedJavaType cType = getMetaAccess().lookupJavaType(Implementor1.class);
+        cType.initialize();
+        ResolvedJavaMethod v1Method = getMetaAccess().lookupJavaMethod(this.getMethod(Interface1.class, "v1"));
+        AssumptionResult<ResolvedJavaMethod> method = cType.findUniqueConcreteMethod(v1Method);
+        assertDeepEquals(null, method);
+    }
+
+    interface Interface2 {
+        default int v1() {
+            return 1;
+        }
+    }
+
+    static class Base2 {
+        public int v2() {
+            return 1;
+        }
+    }
+
+    static class Implementor2 extends Base2 implements Interface2 {
+        int callV1() {
+            return v1();
+        }
+
+        int callV2() {
+            return v2();
+        }
+    }
+
+    static class Subclass2 extends Implementor2 {
+
+    }
+
+    /**
+     * This test illustrates a common pattern where a method at the root of a hierarchy is the only
+     * implementation and can be statically inlined.
+     */
+    @SuppressWarnings("unused")
+    @Test
+    public void testInherited() {
+        Subclass2 s = new Subclass2();
+        testConstantReturn("runInherited", 1);
+    }
+
+    /**
+     * Test same pattern as above but using default methods instead. HotSpot doesn't allow this
+     * version to be optimized.
+     */
+    @SuppressWarnings("unused")
+    @Test
+    @Ignore("HotSpot CHA doesn't treat default methods like regular methods")
+    public void testDefault() {
+        Subclass2 s = new Subclass2();
+        testConstantReturn("runDefault", 1);
+    }
+
+    public int runDefault(Implementor2 i) {
+        return i.callV1();
+    }
+
+    public int runInherited(Implementor2 i) {
+        return i.callV2();
+    }
+
+    private void testConstantReturn(String name, Object value) {
+        StructuredGraph result = buildGraph(name);
+        ReturnNode ret = result.getNodes(ReturnNode.TYPE).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count());
+
+        assertDeepEquals(true, ret.result().isConstant());
+        assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
+    }
+
+    @SuppressWarnings("try")
+    protected StructuredGraph buildGraph(final String snippet) {
+        try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatOptimizationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatOptimizationTest.java
new file mode 100644
index 0000000..31c0394
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatOptimizationTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Check for incorrect elimination of 0.0 and -0.0 from computations. They can affect the sign of
+ * the result of an add or substract.
+ */
+public class FloatOptimizationTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test1Snippet(double x) {
+        return x + 0.0;
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test2Snippet(float x) {
+        return x + 0.0f;
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test3Snippet(double x) {
+        return x - -0.0;
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test4Snippet(float x) {
+        return x - -0.0f;
+    }
+
+    @Override
+    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+        if (expected instanceof Double && actual instanceof Double) {
+            double e = (double) expected;
+            double a = (double) actual;
+            if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) {
+                Assert.fail((message == null ? "" : message) + "raw double bits not equal " + Double.doubleToRawLongBits(a) + " != " + Double.doubleToRawLongBits(e));
+            }
+        } else {
+            super.assertDeepEquals(message, expected, actual, delta);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java
new file mode 100644
index 0000000..e75aac3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.extended.MonitorExit;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class FloatingReadTest extends GraphScheduleTest {
+
+    public static class Container {
+
+        public int a;
+    }
+
+    public static void changeField(Container c) {
+        c.a = 0xcafebabe;
+    }
+
+    public static synchronized int test1Snippet() {
+        Container c = new Container();
+        return c.a;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("try")
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
+
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            PhaseContext context = new PhaseContext(getProviders());
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
+
+            ReturnNode returnNode = null;
+            MonitorExit monitorexit = null;
+
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ReturnNode) {
+                    assert returnNode == null;
+                    returnNode = (ReturnNode) n;
+                } else if (n instanceof MonitorExit) {
+                    monitorexit = (MonitorExit) n;
+                }
+            }
+
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering");
+
+            Assert.assertNotNull(returnNode);
+            Assert.assertNotNull(monitorexit);
+            Assert.assertTrue(returnNode.result() instanceof FloatingReadNode);
+
+            FloatingReadNode read = (FloatingReadNode) returnNode.result();
+
+            assertOrderedAfterSchedule(graph, read, (Node) monitorexit);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerAssumptionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerAssumptionsTest.java
new file mode 100644
index 0000000..88fa5d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerAssumptionsTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public abstract class GraalCompilerAssumptionsTest extends GraalCompilerTest {
+
+    public GraalCompilerAssumptionsTest() {
+        super();
+    }
+
+    public GraalCompilerAssumptionsTest(Class<? extends Architecture> arch) {
+        super(arch);
+    }
+
+    protected void testAssumptionInvalidate(String methodName, Assumption expected, String classToLoad) {
+        testAssumption(methodName, expected, classToLoad, true);
+    }
+
+    /**
+     * Checks the behavior of class loading on {@link Assumption invalidation}. {@code methodName}
+     * is compiled and the resulting graph is checked for {@code expectedAssumption}. The code is
+     * installed and optionally {@code classToLoad} is loaded. The class is assumed to be an inner
+     * class of the test class and the name of the class to load is constructed relative to that.
+     *
+     * @param methodName the method to compile
+     * @param expectedAssumption expected {@link Assumption} instance to find in graph
+     * @param classToLoad an optional class to load to trigger an invalidation check
+     * @param willInvalidate true if loading {@code classToLoad} should invalidate the method
+     */
+    protected void testAssumption(String methodName, Assumption expectedAssumption, String classToLoad, boolean willInvalidate) {
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName);
+
+        StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES);
+        assertTrue(!graph.getAssumptions().isEmpty());
+        checkGraph(expectedAssumption, graph);
+
+        CompilationResult compilationResult = compile(javaMethod, graph);
+        final InstalledCode installedCode = getBackend().createDefaultInstalledCode(javaMethod, compilationResult);
+        assertTrue(installedCode.isValid());
+        if (classToLoad != null) {
+            String fullName = getClass().getName() + "$" + classToLoad;
+            try {
+                Class.forName(fullName);
+            } catch (ClassNotFoundException e) {
+                fail("Can't find class %s", fullName);
+            }
+            assertTrue(!willInvalidate == installedCode.isValid(), "method should be %s", willInvalidate ? "invalid" : "valid");
+        }
+    }
+
+    protected void checkGraph(Assumption expectedAssumption, StructuredGraph graph) {
+        boolean found = false;
+        for (Assumption a : graph.getAssumptions()) {
+            if (expectedAssumption.equals(a)) {
+                found = true;
+            }
+        }
+        assertTrue(found, "Can't find assumption %s", expectedAssumption);
+    }
+
+    /**
+     * Converts a {@link Class} to an initialized {@link ResolvedJavaType}.
+     */
+    protected ResolvedJavaType resolveAndInitialize(Class<?> clazz) {
+        ResolvedJavaType type = getMetaAccess().lookupJavaType(clazz);
+        type.initialize();
+        return type;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
new file mode 100644
index 0000000..9332f69
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
@@ -0,0 +1,1189 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation;
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.GraalCompiler.Request;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.java.BytecodeParser;
+import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.options.DerivedOptionValue;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.TargetProvider;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.SpeculationLog;
+
+/**
+ * Base class for Graal compiler unit tests.
+ * <p>
+ * White box tests for Graal compiler transformations use this pattern:
+ * <ol>
+ * <li>Create a graph by {@linkplain #parseEager(String, AllowAssumptions) parsing} a method.</li>
+ * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li>
+ * <li>Apply a transformation to the graph.</li>
+ * <li>Assert that the transformed graph is equal to an expected graph.</li>
+ * </ol>
+ * <p>
+ * See {@link InvokeHintsTest} as an example of a white box test.
+ * <p>
+ * Black box tests use the {@link #test(String, Object...)} or
+ * {@link #testN(int, String, Object...)} to execute some method in the interpreter and compare its
+ * result against that produced by a Graal compiled version of the method.
+ * <p>
+ * These tests will be run by the {@code mx unittest} command.
+ */
+public abstract class GraalCompilerTest extends GraalTest {
+
+    private final Providers providers;
+    private final Backend backend;
+    private final DerivedOptionValue<Suites> suites;
+    private final DerivedOptionValue<LIRSuites> lirSuites;
+
+    /**
+     * Denotes a test method that must be inlined by the {@link BytecodeParser}.
+     */
+    @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface BytecodeParserForceInline {
+    }
+
+    /**
+     * Denotes a test method that must never be inlined by the {@link BytecodeParser}.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+    public @interface BytecodeParserNeverInline {
+        /**
+         * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead
+         * of {@link InvokeNode}.
+         */
+        boolean invokeWithException() default false;
+    }
+
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of HighTier
+     */
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of MidTier
+     */
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of LowTier
+     */
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
+    protected static void breakpoint() {
+    }
+
+    @SuppressWarnings("unused")
+    protected static void breakpoint(int arg0) {
+    }
+
+    protected static void shouldBeOptimizedAway() {
+    }
+
+    protected Suites createSuites() {
+        Suites ret = backend.getSuites().getDefaultSuites().copy();
+        ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true);
+        if (iter == null) {
+            /*
+             * in the economy configuration, we don't have the ConvertDeoptimizeToGuard phase, so we
+             * just select the first CanonicalizerPhase in HighTier
+             */
+            iter = ret.getHighTier().findPhase(CanonicalizerPhase.class);
+        }
+        iter.add(new Phase() {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                ComputeLoopFrequenciesClosure.compute(graph);
+            }
+
+            @Override
+            public float codeSizeIncrease() {
+                return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "ComputeLoopFrequenciesPhase";
+            }
+        });
+        ret.getHighTier().appendPhase(new Phase() {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkHighTierGraph(graph) : "failed HighTier graph check";
+            }
+
+            @Override
+            public float codeSizeIncrease() {
+                return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "CheckGraphPhase";
+            }
+        });
+        ret.getMidTier().appendPhase(new Phase() {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkMidTierGraph(graph) : "failed MidTier graph check";
+            }
+
+            @Override
+            public float codeSizeIncrease() {
+                return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "CheckGraphPhase";
+            }
+        });
+        ret.getLowTier().appendPhase(new Phase() {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkLowTierGraph(graph) : "failed LowTier graph check";
+            }
+
+            @Override
+            public float codeSizeIncrease() {
+                return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "CheckGraphPhase";
+            }
+        });
+        return ret;
+    }
+
+    protected LIRSuites createLIRSuites() {
+        LIRSuites ret = backend.getSuites().getDefaultLIRSuites().copy();
+        return ret;
+    }
+
+    public GraalCompilerTest() {
+        this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        this.providers = getBackend().getProviders();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
+    }
+
+    /**
+     * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} )
+     * whether the desired backend is available.
+     *
+     * @param arch the name of the desired backend architecture
+     */
+    public GraalCompilerTest(Class<? extends Architecture> arch) {
+        RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class);
+        Backend b = runtime.getBackend(arch);
+        if (b != null) {
+            this.backend = b;
+        } else {
+            // Fall back to the default/host backend
+            this.backend = runtime.getHostBackend();
+        }
+        this.providers = backend.getProviders();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
+    }
+
+    /**
+     * Set up a test for a non-default backend.
+     *
+     * @param backend the desired backend
+     */
+    public GraalCompilerTest(Backend backend) {
+        this.backend = backend;
+        this.providers = backend.getProviders();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
+    }
+
+    private Scope debugScope;
+
+    @Before
+    public void beforeTest() {
+        assert debugScope == null;
+        debugScope = Debug.scope(getClass());
+    }
+
+    @After
+    public void afterTest() {
+        if (debugScope != null) {
+            debugScope.close();
+        }
+        debugScope = null;
+    }
+
+    protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
+        assertEquals(expected, graph, false, true);
+    }
+
+    protected int countUnusedConstants(StructuredGraph graph) {
+        int total = 0;
+        for (ConstantNode node : getConstantNodes(graph)) {
+            if (node.hasNoUsages()) {
+                total++;
+            }
+        }
+        return total;
+    }
+
+    protected int getNodeCountExcludingUnusedConstants(StructuredGraph graph) {
+        return graph.getNodeCount() - countUnusedConstants(graph);
+    }
+
+    protected void assertEquals(StructuredGraph expected, StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
+        String expectedString = getCanonicalGraphString(expected, excludeVirtual, checkConstants);
+        String actualString = getCanonicalGraphString(graph, excludeVirtual, checkConstants);
+        String mismatchString = compareGraphStrings(expected, expectedString, graph, actualString);
+
+        if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "Node count not matching - expected");
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Node count not matching - actual");
+            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString);
+        }
+        if (!expectedString.equals(actualString)) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "mismatching graphs - expected");
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "mismatching graphs - actual");
+            Assert.fail(mismatchString);
+        }
+    }
+
+    private static String compareGraphStrings(StructuredGraph expectedGraph, String expectedString, StructuredGraph actualGraph, String actualString) {
+        if (!expectedString.equals(actualString)) {
+            String[] expectedLines = expectedString.split("\n");
+            String[] actualLines = actualString.split("\n");
+            int diffIndex = -1;
+            int limit = Math.min(actualLines.length, expectedLines.length);
+            String marker = " <<<";
+            for (int i = 0; i < limit; i++) {
+                if (!expectedLines[i].equals(actualLines[i])) {
+                    diffIndex = i;
+                    break;
+                }
+            }
+            if (diffIndex == -1) {
+                // Prefix is the same so add some space after the prefix
+                diffIndex = limit;
+                if (actualLines.length == limit) {
+                    actualLines = Arrays.copyOf(actualLines, limit + 1);
+                    actualLines[diffIndex] = "";
+                } else {
+                    assert expectedLines.length == limit;
+                    expectedLines = Arrays.copyOf(expectedLines, limit + 1);
+                    expectedLines[diffIndex] = "";
+                }
+            }
+            // Place a marker next to the first line that differs
+            expectedLines[diffIndex] = expectedLines[diffIndex] + marker;
+            actualLines[diffIndex] = actualLines[diffIndex] + marker;
+            String ediff = String.join("\n", expectedLines);
+            String adiff = String.join("\n", actualLines);
+            return "mismatch in graphs:\n========= expected (" + expectedGraph + ") =========\n" + ediff + "\n\n========= actual (" + actualGraph + ") =========\n" + adiff;
+        } else {
+            return "mismatch in graphs";
+        }
+    }
+
+    protected void assertOptimizedAway(StructuredGraph g) {
+        Assert.assertEquals(0, g.getNodes().filter(NotOptimizedNode.class).count());
+    }
+
+    protected void assertConstantReturn(StructuredGraph graph, int value) {
+        String graphString = getCanonicalGraphString(graph, false, true);
+        Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.TYPE).count(), 1);
+        ValueNode result = graph.getNodes(ReturnNode.TYPE).first().result();
+        Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant());
+        Assert.assertEquals("unexpected ReturnNode result kind: " + graphString, result.asJavaConstant().getJavaKind(), JavaKind.Int);
+        Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asJavaConstant().asInt(), value);
+    }
+
+    protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        ScheduleResult scheduleResult = graph.getLastSchedule();
+
+        NodeMap<Integer> canonicalId = graph.createNodeMap();
+        int nextId = 0;
+
+        List<String> constantsLines = new ArrayList<>();
+
+        StringBuilder result = new StringBuilder();
+        for (Block block : scheduleResult.getCFG().getBlocks()) {
+            result.append("Block " + block + " ");
+            if (block == scheduleResult.getCFG().getStartBlock()) {
+                result.append("* ");
+            }
+            result.append("-> ");
+            for (Block succ : block.getSuccessors()) {
+                result.append(succ + " ");
+            }
+            result.append("\n");
+            for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
+                if (node instanceof ValueNode && node.isAlive()) {
+                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) {
+                        if (node instanceof ConstantNode) {
+                            String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
+                            String str = name + (excludeVirtual ? "\n" : "    (" + filteredUsageCount(node) + ")\n");
+                            constantsLines.add(str);
+                        } else {
+                            int id;
+                            if (canonicalId.get(node) != null) {
+                                id = canonicalId.get(node);
+                            } else {
+                                id = nextId++;
+                                canonicalId.set(node, id);
+                            }
+                            String name = node.getClass().getSimpleName();
+                            String str = "  " + id + "|" + name + (excludeVirtual ? "\n" : "    (" + filteredUsageCount(node) + ")\n");
+                            result.append(str);
+                        }
+                    }
+                }
+            }
+        }
+
+        StringBuilder constantsLinesResult = new StringBuilder();
+        constantsLinesResult.append(constantsLines.size() + " constants:\n");
+        Collections.sort(constantsLines);
+        for (String s : constantsLines) {
+            constantsLinesResult.append(s);
+            constantsLinesResult.append("\n");
+        }
+
+        return constantsLines.toString() + result.toString();
+    }
+
+    /**
+     * @return usage count excluding {@link FrameState} usages
+     */
+    private static int filteredUsageCount(Node node) {
+        return node.usages().filter(n -> !(n instanceof FrameState)).count();
+    }
+
+    /**
+     * @param graph
+     * @return a scheduled textual dump of {@code graph} .
+     */
+    protected static String getScheduledGraphString(StructuredGraph graph) {
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        ScheduleResult scheduleResult = graph.getLastSchedule();
+
+        StringBuilder result = new StringBuilder();
+        Block[] blocks = scheduleResult.getCFG().getBlocks();
+        for (Block block : blocks) {
+            result.append("Block " + block + " ");
+            if (block == scheduleResult.getCFG().getStartBlock()) {
+                result.append("* ");
+            }
+            result.append("-> ");
+            for (Block succ : block.getSuccessors()) {
+                result.append(succ + " ");
+            }
+            result.append("\n");
+            for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
+                result.append(String.format("%1S\n", node));
+            }
+        }
+        return result.toString();
+    }
+
+    protected Backend getBackend() {
+        return backend;
+    }
+
+    protected Suites getSuites() {
+        return suites.getValue();
+    }
+
+    protected LIRSuites getLIRSuites() {
+        return lirSuites.getValue();
+    }
+
+    protected final Providers getProviders() {
+        return providers;
+    }
+
+    protected HighTierContext getDefaultHighTierContext() {
+        return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+    }
+
+    protected SnippetReflectionProvider getSnippetReflection() {
+        return Graal.getRequiredCapability(SnippetReflectionProvider.class);
+    }
+
+    protected TargetDescription getTarget() {
+        return getTargetProvider().getTarget();
+    }
+
+    protected TargetProvider getTargetProvider() {
+        return getBackend();
+    }
+
+    protected CodeCacheProvider getCodeCache() {
+        return getProviders().getCodeCache();
+    }
+
+    protected ConstantReflectionProvider getConstantReflection() {
+        return getProviders().getConstantReflection();
+    }
+
+    protected MetaAccessProvider getMetaAccess() {
+        return getProviders().getMetaAccess();
+    }
+
+    protected LoweringProvider getLowerer() {
+        return getProviders().getLowerer();
+    }
+
+    protected CompilationIdentifier getCompilationId(ResolvedJavaMethod method) {
+        return getBackend().getCompilationIdentifier(method);
+    }
+
+    protected CompilationIdentifier getOrCreateCompilationId(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
+        if (graph != null) {
+            return graph.compilationId();
+        }
+        return getCompilationId(installedCodeOwner);
+    }
+
+    protected void testN(int n, final String name, final Object... args) {
+        final List<Throwable> errors = new ArrayList<>(n);
+        Thread[] threads = new Thread[n];
+        for (int i = 0; i < n; i++) {
+            Thread t = new Thread(i + ":" + name) {
+
+                @Override
+                public void run() {
+                    try {
+                        test(name, args);
+                    } catch (Throwable e) {
+                        errors.add(e);
+                    }
+                }
+            };
+            threads[i] = t;
+            t.start();
+        }
+        for (int i = 0; i < n; i++) {
+            try {
+                threads[i].join();
+            } catch (InterruptedException e) {
+                errors.add(e);
+            }
+        }
+        if (!errors.isEmpty()) {
+            throw new MultiCauseAssertionError(errors.size() + " failures", errors.toArray(new Throwable[errors.size()]));
+        }
+    }
+
+    protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        return invoke(method, receiver, args);
+    }
+
+    protected static class Result {
+
+        public final Object returnValue;
+        public final Throwable exception;
+
+        public Result(Object returnValue, Throwable exception) {
+            this.returnValue = returnValue;
+            this.exception = exception;
+        }
+
+        @Override
+        public String toString() {
+            return exception == null ? returnValue == null ? "null" : returnValue.toString() : "!" + exception;
+        }
+    }
+
+    /**
+     * Called before a test is executed.
+     */
+    protected void before(@SuppressWarnings("unused") ResolvedJavaMethod method) {
+    }
+
+    /**
+     * Called after a test is executed.
+     */
+    protected void after() {
+    }
+
+    protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) {
+        before(method);
+        try {
+            // This gives us both the expected return value as well as ensuring that the method to
+            // be compiled is fully resolved
+            return new Result(referenceInvoke(method, receiver, args), null);
+        } catch (InvocationTargetException e) {
+            return new Result(null, e.getTargetException());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            after();
+        }
+    }
+
+    protected Result executeActual(ResolvedJavaMethod method, Object receiver, Object... args) {
+        before(method);
+        Object[] executeArgs = argsWithReceiver(receiver, args);
+
+        checkArgs(method, executeArgs);
+
+        InstalledCode compiledMethod = getCode(method);
+        try {
+            return new Result(compiledMethod.executeVarargs(executeArgs), null);
+        } catch (Throwable e) {
+            return new Result(null, e);
+        } finally {
+            after();
+        }
+    }
+
+    protected void checkArgs(ResolvedJavaMethod method, Object[] args) {
+        JavaType[] sig = method.toParameterTypes();
+        Assert.assertEquals(sig.length, args.length);
+        for (int i = 0; i < args.length; i++) {
+            JavaType javaType = sig[i];
+            JavaKind kind = javaType.getJavaKind();
+            Object arg = args[i];
+            if (kind == JavaKind.Object) {
+                if (arg != null && javaType instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType;
+                    Assert.assertTrue(resolvedJavaType + " from " + getMetaAccess().lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(getMetaAccess().lookupJavaType(arg.getClass())));
+                }
+            } else {
+                Assert.assertNotNull(arg);
+                Assert.assertEquals(kind.toBoxedJavaClass(), arg.getClass());
+            }
+        }
+    }
+
+    /**
+     * Prepends a non-null receiver argument to a given list or args.
+     *
+     * @param receiver the receiver argument to prepend if it is non-null
+     */
+    protected Object[] argsWithReceiver(Object receiver, Object... args) {
+        Object[] executeArgs;
+        if (receiver == null) {
+            executeArgs = args;
+        } else {
+            executeArgs = new Object[args.length + 1];
+            executeArgs[0] = receiver;
+            for (int i = 0; i < args.length; i++) {
+                executeArgs[i + 1] = args[i];
+            }
+        }
+        return applyArgSuppliers(executeArgs);
+    }
+
+    protected void test(String name, Object... args) {
+        try {
+            ResolvedJavaMethod method = getResolvedJavaMethod(name);
+            Object receiver = method.isStatic() ? null : this;
+            test(method, receiver, args);
+        } catch (AssumptionViolatedException e) {
+            // Suppress so that subsequent calls to this method within the
+            // same Junit @Test annotated method can proceed.
+        }
+    }
+
+    /**
+     * Type denoting a lambda that supplies a fresh value each time it is called. This is useful
+     * when supplying an argument to {@link GraalCompilerTest#test(String, Object...)} where the
+     * test modifies the state of the argument (e.g., updates a field).
+     */
+    @FunctionalInterface
+    public interface ArgSupplier extends Supplier<Object> {
+    }
+
+    /**
+     * Convenience method for using an {@link ArgSupplier} lambda in a varargs list.
+     */
+    public static Object supply(ArgSupplier supplier) {
+        return supplier;
+    }
+
+    protected void test(ResolvedJavaMethod method, Object receiver, Object... args) {
+        Result expect = executeExpected(method, receiver, args);
+        if (getCodeCache() == null) {
+            return;
+        }
+        testAgainstExpected(method, expect, receiver, args);
+    }
+
+    /**
+     * Process a given set of arguments, converting any {@link ArgSupplier} argument to the argument
+     * it supplies.
+     */
+    protected Object[] applyArgSuppliers(Object... args) {
+        Object[] res = args;
+        for (int i = 0; i < args.length; i++) {
+            if (args[i] instanceof ArgSupplier) {
+                if (res == args) {
+                    res = args.clone();
+                }
+                res[i] = ((ArgSupplier) args[i]).get();
+            }
+        }
+        return res;
+    }
+
+    protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Object receiver, Object... args) {
+        testAgainstExpected(method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args);
+    }
+
+    protected Result executeActualCheckDeopt(ResolvedJavaMethod method, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
+        Map<DeoptimizationReason, Integer> deoptCounts = new EnumMap<>(DeoptimizationReason.class);
+        ProfilingInfo profile = method.getProfilingInfo();
+        for (DeoptimizationReason reason : shouldNotDeopt) {
+            deoptCounts.put(reason, profile.getDeoptimizationCount(reason));
+        }
+        Result actual = executeActual(method, receiver, args);
+        profile = method.getProfilingInfo(); // profile can change after execution
+        for (DeoptimizationReason reason : shouldNotDeopt) {
+            Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
+        }
+        return actual;
+    }
+
+    protected void assertEquals(Result expect, Result actual) {
+        if (expect.exception != null) {
+            Assert.assertTrue("expected " + expect.exception, actual.exception != null);
+            Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass());
+            Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage());
+        } else {
+            if (actual.exception != null) {
+                throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception);
+            }
+            assertDeepEquals(expect.returnValue, actual.returnValue);
+        }
+    }
+
+    protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
+        Result actual = executeActualCheckDeopt(method, shouldNotDeopt, receiver, args);
+        assertEquals(expect, actual);
+    }
+
+    private Map<ResolvedJavaMethod, InstalledCode> cache = new HashMap<>();
+
+    /**
+     * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions) eagerly}.
+     */
+    protected InstalledCode getCode(ResolvedJavaMethod method) {
+        return getCode(method, null);
+    }
+
+    /**
+     * Gets installed code for a given method, compiling it first if necessary.
+     *
+     * @param installedCodeOwner the method the compiled code will be associated with when installed
+     * @param graph the graph to be compiled. If null, a graph will be obtained from
+     *            {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
+     */
+    protected InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
+        return getCode(installedCodeOwner, graph, false);
+    }
+
+    protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph0, boolean forceCompile) {
+        return getCode(installedCodeOwner, graph0, forceCompile, false);
+    }
+
+    /**
+     * Gets installed code for a given method and graph, compiling it first if necessary.
+     *
+     * @param installedCodeOwner the method the compiled code will be associated with when installed
+     * @param graph the graph to be compiled. If null, a graph will be obtained from
+     *            {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
+     * @param forceCompile specifies whether to ignore any previous code cached for the (method,
+     *            key) pair
+     * @param installDefault specifies whether to install as the default implementation
+     */
+    @SuppressWarnings("try")
+    protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installDefault) {
+        if (!forceCompile) {
+            InstalledCode cached = cache.get(installedCodeOwner);
+            if (cached != null) {
+                if (cached.isValid()) {
+                    return cached;
+                }
+            }
+        }
+
+        final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph);
+
+        InstalledCode installedCode = null;
+        try (AllocSpy spy = AllocSpy.open(installedCodeOwner); Scope ds = Debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
+            final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
+            if (printCompilation) {
+                TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s ...", id, installedCodeOwner.getDeclaringClass().getName(), installedCodeOwner.getName(), installedCodeOwner.getSignature()));
+            }
+            long start = System.currentTimeMillis();
+            CompilationResult compResult = compile(installedCodeOwner, graph, id);
+            if (printCompilation) {
+                TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
+            }
+
+            try (Scope s = Debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult)) {
+                if (installDefault) {
+                    installedCode = addDefaultMethod(installedCodeOwner, compResult);
+                } else {
+                    installedCode = addMethod(installedCodeOwner, compResult);
+                }
+                if (installedCode == null) {
+                    throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        if (!forceCompile) {
+            cache.put(installedCodeOwner, installedCode);
+        }
+        return installedCode;
+    }
+
+    /**
+     * Used to produce a graph for a method about to be compiled by
+     * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method
+     * is null.
+     *
+     * The default implementation in {@link GraalCompilerTest} is to call
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions)}.
+     */
+    protected final StructuredGraph parseForCompile(ResolvedJavaMethod method) {
+        return parseEager(method, AllowAssumptions.YES);
+    }
+
+    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) {
+        return parseEager(method, AllowAssumptions.YES, compilationId);
+    }
+
+    /**
+     * Compiles a given method.
+     *
+     * @param installedCodeOwner the method the compiled code will be associated with when installed
+     * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will
+     *            be obtained from {@code installedCodeOwner} via
+     *            {@link #parseForCompile(ResolvedJavaMethod)}.
+     */
+    protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
+        return compile(installedCodeOwner, graph, getOrCreateCompilationId(installedCodeOwner, graph));
+    }
+
+    protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
+        return compile(installedCodeOwner, graph, new CompilationResult(), compilationId);
+    }
+
+    /**
+     * Compiles a given method.
+     *
+     * @param installedCodeOwner the method the compiled code will be associated with when installed
+     * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will
+     *            be obtained from {@code installedCodeOwner} via
+     *            {@link #parseForCompile(ResolvedJavaMethod)}.
+     * @param compilationResult
+     * @param compilationId
+     */
+    @SuppressWarnings("try")
+    protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationResult compilationResult, CompilationIdentifier compilationId) {
+        StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, compilationId) : graph;
+        lastCompiledGraph = graphToCompile;
+        try (Scope s = Debug.scope("Compile", graphToCompile)) {
+            Request<CompilationResult> request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
+                            graphToCompile.getProfilingInfo(), getSuites(), getLIRSuites(), compilationResult, CompilationResultBuilderFactory.Default);
+            return GraalCompiler.compile(request);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected StructuredGraph lastCompiledGraph;
+
+    protected SpeculationLog getSpeculationLog() {
+        return null;
+    }
+
+    protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) {
+        return backend.addInstalledCode(method, null, compilationResult);
+    }
+
+    protected InstalledCode addDefaultMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) {
+        return backend.createDefaultInstalledCode(method, compilationResult);
+    }
+
+    private final Map<ResolvedJavaMethod, Method> methodMap = new HashMap<>();
+
+    /**
+     * Converts a reflection {@link Method} to a {@link ResolvedJavaMethod}.
+     */
+    protected ResolvedJavaMethod asResolvedJavaMethod(Method method) {
+        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
+        methodMap.put(javaMethod, method);
+        return javaMethod;
+    }
+
+    protected ResolvedJavaMethod getResolvedJavaMethod(String methodName) {
+        return asResolvedJavaMethod(getMethod(methodName));
+    }
+
+    protected ResolvedJavaMethod getResolvedJavaMethod(Class<?> clazz, String methodName) {
+        return asResolvedJavaMethod(getMethod(clazz, methodName));
+    }
+
+    protected ResolvedJavaMethod getResolvedJavaMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
+        return asResolvedJavaMethod(getMethod(clazz, methodName, parameterTypes));
+    }
+
+    /**
+     * Gets the reflection {@link Method} from which a given {@link ResolvedJavaMethod} was created
+     * or null if {@code javaMethod} does not correspond to a reflection method.
+     */
+    protected Method lookupMethod(ResolvedJavaMethod javaMethod) {
+        return methodMap.get(javaMethod);
+    }
+
+    protected Object invoke(ResolvedJavaMethod javaMethod, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        Method method = lookupMethod(javaMethod);
+        Assert.assertTrue(method != null);
+        if (!method.isAccessible()) {
+            method.setAccessible(true);
+        }
+        return method.invoke(receiver, applyArgSuppliers(args));
+    }
+
+    /**
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
+     * produce a graph.
+     *
+     * @param methodName the name of the method in {@code this.getClass()} to be parsed
+     */
+    protected StructuredGraph parseProfiled(String methodName, AllowAssumptions allowAssumptions) {
+        return parseProfiled(getResolvedJavaMethod(methodName), allowAssumptions);
+    }
+
+    /**
+     * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
+     * produce a graph.
+     */
+    protected final StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parseProfiled(m, allowAssumptions, getCompilationId(m));
+    }
+
+    protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        return parse1(m, getDefaultGraphBuilderSuite(), allowAssumptions, compilationId);
+    }
+
+    /**
+     * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
+     * set to true to produce a graph.
+     *
+     * @param methodName the name of the method in {@code this.getClass()} to be parsed
+     */
+    protected final StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions) {
+        return parseEager(getResolvedJavaMethod(methodName), allowAssumptions);
+    }
+
+    /**
+     * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
+     * set to true to produce a graph.
+     */
+    protected final StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parseEager(m, allowAssumptions, getCompilationId(m));
+    }
+
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)), allowAssumptions, compilationId);
+    }
+
+    /**
+     * Parses a Java method using {@linkplain GraphBuilderConfiguration#withFullInfopoints(boolean)
+     * full debug} set to true to produce a graph.
+     */
+    protected final StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parseDebug(m, allowAssumptions, getCompilationId(m));
+    }
+
+    protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)), allowAssumptions, compilationId);
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
+        StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions, getSpeculationLog(), compilationId);
+        try (Scope ds = Debug.scope("Parsing", javaMethod, graph)) {
+            graphBuilderSuite.apply(graph, getDefaultHighTierContext());
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite();
+        Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins();
+        // defensive copying
+        return new Plugins(defaultPlugins);
+    }
+
+    protected PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
+        // defensive copying
+        return backend.getSuites().getDefaultGraphBuilderSuite().copy();
+    }
+
+    protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) {
+        PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite();
+        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy());
+        iterator.remove();
+        iterator.add(new GraphBuilderPhase(gbConfCopy));
+        return suite;
+    }
+
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        invocationPlugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new BreakpointNode());
+                return true;
+            }
+        }, GraalCompilerTest.class, "breakpoint");
+        invocationPlugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg0) {
+                b.add(new BreakpointNode(arg0));
+                return true;
+            }
+        }, GraalCompilerTest.class, "breakpoint", int.class);
+        invocationPlugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new NotOptimizedNode());
+                return true;
+            }
+        }, GraalCompilerTest.class, "shouldBeOptimizedAway");
+
+        conf.getPlugins().prependInlineInvokePlugin(new InlineInvokePlugin() {
+
+            @Override
+            public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+                BytecodeParserNeverInline neverInline = method.getAnnotation(BytecodeParserNeverInline.class);
+                if (neverInline != null) {
+                    return neverInline.invokeWithException() ? DO_NOT_INLINE_WITH_EXCEPTION : DO_NOT_INLINE_NO_EXCEPTION;
+                }
+                if (method.getAnnotation(BytecodeParserForceInline.class) != null) {
+                    return InlineInfo.createStandardInlineInfo(method);
+                }
+                return bytecodeParserShouldInlineInvoke(b, method, args);
+            }
+        });
+        return conf;
+    }
+
+    /**
+     * Supplements {@link BytecodeParserForceInline} and {@link BytecodeParserNeverInline} in terms
+     * of allowing a test to influence the inlining decision made during bytecode parsing.
+     *
+     * @see InlineInvokePlugin#shouldInlineInvoke(GraphBuilderContext, ResolvedJavaMethod,
+     *      ValueNode[])
+     */
+    @SuppressWarnings("unused")
+    protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return null;
+    }
+
+    @NodeInfo
+    public static class NotOptimizedNode extends FixedWithNextNode {
+        private static final NodeClass<NotOptimizedNode> TYPE = NodeClass.create(NotOptimizedNode.class);
+
+        protected NotOptimizedNode() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+    }
+
+    protected Replacements getReplacements() {
+        return getProviders().getReplacements();
+    }
+
+    /**
+     * Inject a probability for a branch condition into the profiling information of this test case.
+     *
+     * @param p the probability that cond is true
+     * @param cond the condition of the branch
+     * @return cond
+     */
+    protected static boolean branchProbability(double p, boolean cond) {
+        return GraalDirectives.injectBranchProbability(p, cond);
+    }
+
+    /**
+     * Inject an iteration count for a loop condition into the profiling information of this test
+     * case.
+     *
+     * @param i the iteration count of the loop
+     * @param cond the condition of the loop
+     * @return cond
+     */
+    protected static boolean iterationCount(double i, boolean cond) {
+        return GraalDirectives.injectIterationCount(i, cond);
+    }
+
+    /**
+     * Test if the current test runs on the given platform. The name must match the name given in
+     * the {@link Architecture#getName()}.
+     *
+     * @param name The name to test
+     * @return true if we run on the architecture given by name
+     */
+    protected boolean isArchitecture(String name) {
+        return name.equals(backend.getTarget().arch.getName());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java
new file mode 100644
index 0000000..6dd6b2b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.EncodedGraph;
+import org.graalvm.compiler.nodes.GraphEncoder;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class GraphEncoderTest extends GraalCompilerTest {
+
+    @Test
+    public void test01() {
+        testStringMethods(false);
+    }
+
+    @Test
+    public void test02() {
+        testStringMethods(true);
+    }
+
+    public void testStringMethods(boolean canonicalize) {
+        /* Encode and decode all methods of java.lang.String. */
+        List<StructuredGraph> originalGraphs = new ArrayList<>();
+        for (Method method : String.class.getDeclaredMethods()) {
+            ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
+            if (javaMethod.hasBytecodes()) {
+                StructuredGraph originalGraph = parseEager(javaMethod, AllowAssumptions.YES);
+                if (canonicalize) {
+                    PhaseContext context = new PhaseContext(getProviders());
+                    new CanonicalizerPhase().apply(originalGraph, context);
+                }
+                originalGraphs.add(originalGraph);
+            }
+        }
+
+        GraphEncoder encoder = new GraphEncoder(getTarget().arch);
+        for (StructuredGraph originalGraph : originalGraphs) {
+            encoder.prepare(originalGraph);
+        }
+        encoder.finishPrepare();
+        Map<StructuredGraph, Long> startOffsets = new HashMap<>();
+        for (StructuredGraph originalGraph : originalGraphs) {
+            startOffsets.put(originalGraph, encoder.encode(originalGraph));
+        }
+
+        for (StructuredGraph originalGraph : originalGraphs) {
+            EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(),
+                            originalGraph.getMethods());
+            GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java
new file mode 100644
index 0000000..e873962
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.List;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+public class GraphScheduleTest extends GraalCompilerTest {
+
+    protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) {
+        SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST);
+        ibp.apply(graph);
+        assertOrderedAfterSchedule(graph.getLastSchedule(), a, b);
+    }
+
+    protected void assertOrderedAfterSchedule(ScheduleResult ibp, Node a, Node b) {
+        NodeMap<Block> nodeToBlock = ibp.getCFG().getNodeToBlock();
+        Block bBlock = nodeToBlock.get(b);
+        Block aBlock = nodeToBlock.get(a);
+
+        if (bBlock == aBlock) {
+            List<Node> instructions = ibp.nodesFor(bBlock);
+            Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a));
+        } else {
+            Block block = bBlock;
+            while (block != null) {
+                if (block == aBlock) {
+                    return;
+                }
+                block = block.getDominator();
+            }
+            Assert.fail("block of A doesn't dominate the block of B");
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardEliminationCornerCasesTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardEliminationCornerCasesTest.java
new file mode 100644
index 0000000..ee21971
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardEliminationCornerCasesTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class GuardEliminationCornerCasesTest extends GraalCompilerTest {
+
+    static class A {
+
+    }
+
+    static class B extends A {
+
+    }
+
+    static class C extends B {
+
+    }
+
+    static class D extends C {
+
+    }
+
+    @SuppressWarnings({"static-method", "unused"})
+    private int testMethod(Object a) {
+        if (a instanceof A) {
+            if (a instanceof C) {
+                if (a instanceof B) {
+                    B b = (B) a;
+                    if (b instanceof C) {
+                        return 1;
+                    } else {
+                        GraalDirectives.deoptimizeAndInvalidate();
+                    }
+                }
+            } else {
+                GraalDirectives.deoptimizeAndInvalidate();
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void testFloatingGuards() {
+        HighTierContext context = getDefaultHighTierContext();
+        StructuredGraph graph = parseEager("testMethod", AllowAssumptions.YES);
+        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after parsing");
+
+        GuardNode myGuardNode = null;
+        for (Node n : graph.getNodes()) {
+            if (n instanceof GuardNode) {
+                GuardNode guardNode = (GuardNode) n;
+                LogicNode condition = guardNode.getCondition();
+                if (condition instanceof InstanceOfNode) {
+                    InstanceOfNode instanceOfNode = (InstanceOfNode) condition;
+                    if (instanceOfNode.getValue() instanceof ValueProxy) {
+                        myGuardNode = guardNode;
+                        break;
+                    }
+                }
+            }
+        }
+
+        AbstractBeginNode myBegin = (AbstractBeginNode) myGuardNode.getAnchor();
+        AbstractBeginNode prevBegin = BeginNode.prevBegin((FixedNode) myBegin.predecessor());
+        myGuardNode.setAnchor(prevBegin);
+
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after manual modification");
+        graph.reverseUsageOrder();
+        new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST).apply(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java
new file mode 100644
index 0000000..a84872e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.OpaqueNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.LoadMethodNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests use of an intrinsic for virtual methods where the call site is indirect. A prime example is
+ * an intrinsic for {@link Object#hashCode()}. The intrinsic can only be used if the call site would
+ * actually dispatch to {@link Object#hashCode()} and not a method that overrides it.
+ */
+public class GuardedIntrinsicTest extends GraalCompilerTest {
+
+    static class Super {
+        int getAge() {
+            return 11;
+        }
+    }
+
+    public static class Person extends Super {
+        int age;
+
+        public Person(int age) {
+            this.age = age;
+        }
+
+        @Override
+        public int getAge() {
+            return age;
+        }
+    }
+
+    @BytecodeParserForceInline
+    public static final Super createSuper() {
+        return new Super();
+    }
+
+    @BytecodeParserNeverInline
+    public static final Super createPerson() {
+        return new Person(42);
+    }
+
+    public static int getSuperAge(Super s) {
+        return s.getAge();
+    }
+
+    public static int getPersonAge(Person p) {
+        return p.getAge();
+    }
+
+    public static int makeSuperAge() {
+        return createSuper().getAge();
+    }
+
+    public static int makePersonAge() {
+        return createPerson().getAge();
+    }
+
+    @BeforeClass
+    public static void init() {
+        // Ensure classes are initialized
+        new Person(0).toString();
+    }
+
+    private StructuredGraph graph;
+    private StructuredGraph parsedForCompile;
+
+    @Override
+    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) {
+        graph = super.parseForCompile(method, compilationId);
+        parsedForCompile = (StructuredGraph) graph.copy();
+        return graph;
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        Registration r = new Registration(invocationPlugins, Super.class);
+
+        r.register1("getAge", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ConstantNode res = b.add(ConstantNode.forInt(new Super().getAge()));
+                b.add(new OpaqueNode(res));
+                b.push(JavaKind.Int, res);
+                return true;
+            }
+        });
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    public static int referenceMakeSuperAge() {
+        return 11;
+    }
+
+    public static int referenceMakePersonAge() {
+        return 42;
+    }
+
+    @Test
+    public void test01() {
+        Super inheritsHC = new Super();
+        Person overridesHC = new Person(0);
+        test("getSuperAge", inheritsHC);
+        test("getSuperAge", overridesHC);
+
+        // Check that the virtual dispatch test exists after bytecode parsing
+        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
+        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
+
+        // Check for the marker node indicating the intrinsic was applied
+        Assert.assertEquals(1, parsedForCompile.getNodes().filter(OpaqueNode.class).count());
+
+        // Final graph should have a single invoke
+        List<Node> invokes = graph.getNodes().filter(n -> n instanceof Invoke).snapshot();
+        Assert.assertEquals(invokes.toString(), 1, invokes.size());
+    }
+
+    @Test
+    public void test02() {
+        test("getPersonAge", new Person(0));
+
+        // Check that the virtual dispatch test does not exist after bytecode parsing
+        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
+        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
+
+        Assert.assertEquals(0, parsedForCompile.getNodes().filter(InvokeNode.class).count());
+    }
+
+    @Test
+    public void test03() {
+        test("makeSuperAge");
+
+        // Check that the virtual dispatch test does not exist after bytecode parsing
+        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
+        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
+
+        StructuredGraph referenceGraph = parseEager("referenceMakeSuperAge", AllowAssumptions.NO);
+        assertEquals(referenceGraph, graph, true, true);
+    }
+
+    @Test
+    public void test04() {
+        test("makePersonAge");
+
+        // Check that the virtual dispatch test exists after bytecode parsing
+        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
+        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
+
+        StructuredGraph referenceGraph = parseEager("referenceMakePersonAge", AllowAssumptions.NO);
+        assertEquals(referenceGraph, graph, true, true);
+    }
+
+    static final class ReadCacheEntry {
+
+        public final Object identity;
+        public final ValueNode object;
+
+        ReadCacheEntry(Object identity, ValueNode object) {
+            this.identity = identity;
+            this.object = object;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = ((identity == null) ? 0 : identity.hashCode());
+            return result + object.hashCode();
+        }
+    }
+
+    public static int getHashCode(ReadCacheEntry obj) {
+        return obj.hashCode();
+    }
+
+    @Test
+    public void test05() {
+        ReadCacheEntry val1 = new ReadCacheEntry("identity", ConstantNode.forBoolean(false));
+        ReadCacheEntry val2 = new ReadCacheEntry(Integer.valueOf(34), ConstantNode.forInt(42));
+        for (int i = 0; i < 10000; i++) {
+            getHashCode(val2);
+        }
+        test("getHashCode", val1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java
new file mode 100644
index 0000000..eb9b5ce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.core.phases.MidTier;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.LoadMethodNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class HashCodeTest extends GraalCompilerTest {
+
+    static class OverrideHashCode {
+        @Override
+        public int hashCode() {
+            return 42;
+        }
+    }
+
+    static final class DontOverrideHashCode {
+    }
+
+    public static final Object NonOverridingConstant = new Object();
+    public static final Object OverridingConstant = new OverrideHashCode();
+
+    private static void initialize(Class<?> c) {
+        try {
+            Class.forName(c.getName(), true, c.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static final int hashCodeSnippet01(Object o) {
+        return o.hashCode();
+    }
+
+    public static final int systemIdentityHashCodeSnippet01(Object o) {
+        return System.identityHashCode(o);
+    }
+
+    public static final int hashCodeFoldSnippet01() {
+        return NonOverridingConstant.hashCode();
+    }
+
+    public static final int identityHashCodeFoldSnippet01() {
+        return System.identityHashCode(NonOverridingConstant);
+    }
+
+    public static final int hashCodeNoFoldOverridingSnippet01(Object o) {
+        return o.hashCode();
+    }
+
+    public static final int identityHashCodeFoldOverridingSnippet01() {
+        return System.identityHashCode(OverridingConstant);
+    }
+
+    public static final int dontOverrideHashCodeFinalClass(DontOverrideHashCode o) {
+        return o.hashCode();
+    }
+
+    @Test
+    public void test01() {
+        test("hashCodeSnippet01", new Object());
+    }
+
+    @Test
+    public void test02() {
+        test("systemIdentityHashCodeSnippet01", new Object());
+    }
+
+    @Test
+    public void test03() {
+        StructuredGraph g = buildGraphAfterMidTier("hashCodeFoldSnippet01");
+        Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
+    }
+
+    @Test
+    public void test04() {
+        StructuredGraph g = buildGraphAfterMidTier("identityHashCodeFoldSnippet01");
+        Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
+    }
+
+    @Test
+    public void test05() {
+        checkForGuardedIntrinsicPattern("hashCodeNoFoldOverridingSnippet01");
+
+        Object nullObject = null;
+        test("hashCodeNoFoldOverridingSnippet01", nullObject);
+        test("hashCodeNoFoldOverridingSnippet01", new Object());
+        test("hashCodeNoFoldOverridingSnippet01", new DontOverrideHashCode());
+    }
+
+    @Test
+    public void test06() {
+        StructuredGraph g = buildGraphAfterMidTier("identityHashCodeFoldOverridingSnippet01");
+        Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
+    }
+
+    @Test
+    public void test07() {
+        initialize(DontOverrideHashCode.class);
+        StructuredGraph g = buildGraphAfterMidTier("dontOverrideHashCodeFinalClass");
+        Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
+    }
+
+    public static final int hashCodeInterface(Appendable o) {
+        return o.hashCode();
+    }
+
+    @Test
+    public void test08() {
+        initialize(Appendable.class);
+        checkForGuardedIntrinsicPattern("hashCodeInterface");
+        checkForGuardedIntrinsicPattern("hashCodeSnippet01");
+    }
+
+    private void checkForGuardedIntrinsicPattern(String name) {
+        StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
+        Assert.assertEquals(1, g.getNodes().filter(InvokeNode.class).count());
+        Assert.assertEquals(1, g.getNodes().filter(LoadHubNode.class).count());
+        Assert.assertEquals(1, g.getNodes().filter(LoadMethodNode.class).count());
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph buildGraphAfterMidTier(String name) {
+        StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
+        new HighTier().apply(g, getDefaultHighTierContext());
+        new MidTier().apply(g, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, g.getProfilingInfo()));
+        return g;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java
new file mode 100644
index 0000000..0cf12a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant
+ * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the
+ * graph of the method that just has a "return 1" statement in it.
+ */
+public class IfCanonicalizerTest extends GraalCompilerTest {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet(int a) {
+        return 1;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet(int a) {
+        if (a == 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a) {
+        if (a == 0) {
+            if (a == 0) {
+                if (a == 0) {
+                    return 1;
+                }
+            }
+        } else {
+            return 2;
+        }
+        return 3;
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test3Snippet(int a) {
+        if (a == 0) {
+            if (a != 1) {
+                if (a == 1) {
+                    return 3;
+                } else {
+                    if (a >= 0) {
+                        if (a <= 0) {
+                            if (a > -1) {
+                                if (a < 1) {
+                                    return 1;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            return 2;
+        }
+        return 3;
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet");
+    }
+
+    public static int test4Snippet(int a) {
+        if (a == 0) {
+            return 1;
+        }
+        return 1;
+    }
+
+    @Test
+    public void test5() {
+        test("test5Snippet");
+    }
+
+    public static int test5Snippet(int a) {
+        int val = 2;
+        if (a == 0) {
+            val = 1;
+        }
+        if (a * (3 + val) == 0) {
+            return 1;
+        }
+        return 1;
+    }
+
+    @Test
+    public void test6() {
+        testCombinedIf("test6Snippet", 3);
+        test("test6Snippet", new int[]{0});
+    }
+
+    public static int test6Snippet(int[] a) {
+        int i = a[0];
+        if (i >= 0 && i < a.length) {
+            return a[i];
+        }
+        return 1;
+    }
+
+    @Test
+    public void test7() {
+        testCombinedIf("test7Snippet", 1);
+        test("test7Snippet", -1);
+    }
+
+    public static int test7Snippet(int v) {
+        if (v >= 0 && v < 1024) {
+            return v + 1;
+        }
+        return v - 1;
+    }
+
+    @Test
+    public void test8() {
+        testCombinedIf("test8Snippet", 1);
+        test("test8Snippet", -1);
+    }
+
+    public static int test8Snippet(int v) {
+        if (v >= 0 && v <= 1024) {
+            return v + 1;
+        }
+        return v - 1;
+    }
+
+    @Test
+    public void test9() {
+        testCombinedIf("test9Snippet", 2);
+        test("test9Snippet", -1);
+        test("test9Snippet", 1025);
+    }
+
+    public static int test9Snippet(int n) {
+        return (n < 0) ? 1 : (n >= 1024) ? 1024 : n + 1;
+    }
+
+    private void testCombinedIf(String snippet, int count) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+        new GuardLoweringPhase().apply(graph, midContext);
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+        new ValueAnchorCleanupPhase().apply(graph);
+        new CanonicalizerPhase().apply(graph, context);
+        assertDeepEquals(count, graph.getNodes().filter(IfNode.class).count());
+    }
+
+    private void test(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        ParameterNode param = graph.getNodes(ParameterNode.TYPE).iterator().next();
+        ConstantNode constant = ConstantNode.forInt(0, graph);
+        for (Node n : param.usages().snapshot()) {
+            if (!(n instanceof FrameState)) {
+                n.replaceFirstInput(param, constant);
+            }
+        }
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) {
+            fs.replaceFirstInput(param, null);
+            param.safeDelete();
+        }
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfReorderTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfReorderTest.java
new file mode 100644
index 0000000..cb4fd4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfReorderTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+public class IfReorderTest extends GraalCompilerTest {
+
+    private static Object fieldA = Integer.class;
+    private static Object fieldB = Double.class;
+
+    @Test
+    public void test1() {
+        test("test1Snippet", new ArrayList<>());
+    }
+
+    public static Object test1Snippet(Object o) {
+        /*
+         * Serializable and List are not mutually exclusive, so these two IFs should never be
+         * reordered.
+         */
+        if (branchProbability(0.1, o instanceof Serializable)) {
+            return fieldA;
+        }
+        if (branchProbability(0.9, o instanceof List)) {
+            return fieldB;
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java
new file mode 100644
index 0000000..9996633
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * Tests that the hub access and the null check are folded.
+ */
+public class ImplicitNullCheckTest extends GraphScheduleTest {
+
+    public static final class Receiver {
+
+        public int a;
+    }
+
+    public static int test1Snippet(Object o) {
+        if (GraalDirectives.guardingNonNull(o) instanceof Receiver) {
+            return 42;
+        }
+        return 0;
+    }
+
+    @Ignore("temporarily disable until LoadHub lowering is clarified")
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("try")
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            PhaseContext context = new PhaseContext(getProviders());
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
+            MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+            new GuardLoweringPhase().apply(graph, midTierContext);
+
+            Assert.assertEquals(0, graph.getNodes(DeoptimizeNode.TYPE).count());
+            Assert.assertTrue(graph.getNodes().filter(ReadNode.class).first().canNullCheck());
+
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java
new file mode 100644
index 0000000..f93a6f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.GraalCompiler.compileGraph;
+import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions;
+import static org.junit.Assert.assertNotNull;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+/**
+ * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons.
+ */
+public class InfopointReasonTest extends GraalCompilerTest {
+
+    public static final String[] STRINGS = new String[]{"world", "everyone", "you"};
+
+    public String testMethod() {
+        StringBuilder sb = new StringBuilder("Hello ");
+        for (String s : STRINGS) {
+            sb.append(s).append(", ");
+        }
+        sb.replace(sb.length() - 2, sb.length(), "!");
+        return sb.toString();
+    }
+
+    @Test
+    public void callInfopoints() {
+        final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
+        final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
+        final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
+                        getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+        for (Infopoint sp : cr.getInfopoints()) {
+            assertNotNull(sp.reason);
+            if (sp instanceof Call) {
+                assertDeepEquals(InfopointReason.CALL, sp.reason);
+            }
+        }
+    }
+
+    @Test
+    public void lineInfopoints() {
+        final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
+        final StructuredGraph graph = parseDebug(method, AllowAssumptions.from(OptAssumptions.getValue()));
+        int graphLineSPs = 0;
+        for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
+            if (ipn.getReason() == InfopointReason.BYTECODE_POSITION) {
+                ++graphLineSPs;
+            }
+        }
+        assertTrue(graphLineSPs > 0);
+        PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
+        final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(), getSuites(),
+                        getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+        int lineSPs = 0;
+        for (Infopoint sp : cr.getInfopoints()) {
+            assertNotNull(sp.reason);
+            if (sp.reason == InfopointReason.BYTECODE_POSITION) {
+                ++lineSPs;
+            }
+        }
+        assertTrue(lineSPs > 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InstalledCodeInvalidationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InstalledCodeInvalidationTest.java
new file mode 100644
index 0000000..7a450de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InstalledCodeInvalidationTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+public class InstalledCodeInvalidationTest extends GraalCompilerTest {
+
+    public void recurse(InstalledCode code, int depth) throws InvalidInstalledCodeException {
+        if (depth > 1) {
+            /*
+             * Recurse a few times to ensure there are multiple activations.
+             */
+            code.executeVarargs(this, code, depth - 1);
+        } else {
+            /*
+             * Deoptimize this activation and make the compiled code no longer usable.
+             */
+
+            GraalDirectives.deoptimizeAndInvalidate();
+            assert code.isAlive() && !code.isValid();
+            code.invalidate();
+            assert !code.isAlive();
+        }
+        if (GraalDirectives.inCompiledCode()) {
+            /*
+             * If this still in compiled code then the deoptimizeAndInvalidate call above didn't
+             * remove all existing activations.
+             */
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Test that after uncommon trapping in an installed code it's still possible to invalidate all
+     * existing activations of that installed code.
+     *
+     * @throws InvalidInstalledCodeException
+     */
+    @Test
+    public void testInstalledCodeInvalidation() throws InvalidInstalledCodeException {
+        InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(getMethod("recurse")));
+        code.executeVarargs(this, code, 3);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java
new file mode 100644
index 0000000..06bcbd7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest {
+
+    @Test
+    public void testSubtractEqualsZero() {
+        test("testSubtractEqualsZeroSnippet", "testSubtractEqualsZeroReference");
+    }
+
+    public static int testSubtractEqualsZeroReference(int a, int b) {
+        if (a == b) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static int testSubtractEqualsZeroSnippet(int a, int b) {
+        if (a - b == 0) {
+            return 1;
+        }
+        return 0;
+    }
+
+    @Test
+    public void testSubtractEqualsZeroLong() {
+        test("testSubtractEqualsZeroLongSnippet", "testSubtractEqualsZeroLongReference");
+    }
+
+    public static int testSubtractEqualsZeroLongReference(long a, long b) {
+        if (a == b) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static int testSubtractEqualsZeroLongSnippet(long a, long b) {
+        if (a - b == 0) {
+            return 1;
+        }
+        return 0;
+    }
+
+    /**
+     * Tests the canonicalization of (x >>> const) == 0 to x |test| (-1 << const).
+     */
+    @Test
+    public void testShiftEquals() {
+        test("testShiftEqualsSnippet", "testShiftEqualsReference");
+    }
+
+    @SuppressWarnings("unused") private static int field;
+
+    public static void testShiftEqualsSnippet(int x, int[] array, int y) {
+        // optimize
+        field = (x >>> 10) == 0 ? 1 : 0;
+        field = (array.length >> 10) == 0 ? 1 : 0;
+        field = (x << 10) == 0 ? 1 : 0;
+        // don't optimize
+        field = (x >> 10) == 0 ? 1 : 0;
+        field = (x >>> y) == 0 ? 1 : 0;
+        field = (x >> y) == 0 ? 1 : 0;
+        field = (x << y) == 0 ? 1 : 0;
+        field = (x >>> y) == 1 ? 1 : 0;
+        field = (x >> y) == 1 ? 1 : 0;
+        field = (x << y) == 1 ? 1 : 0;
+    }
+
+    public static void testShiftEqualsReference(int x, int[] array, int y) {
+        field = (x & 0xfffffc00) == 0 ? 1 : 0;
+        field = (array.length & 0xfffffc00) == 0 ? 1 : 0;
+        field = (x & 0x3fffff) == 0 ? 1 : 0;
+        // don't optimize signed right shifts
+        field = (x >> 10) == 0 ? 1 : 0;
+        // don't optimize no-constant shift amounts
+        field = (x >>> y) == 0 ? 1 : 0;
+        field = (x >> y) == 0 ? 1 : 0;
+        field = (x << y) == 0 ? 1 : 0;
+        // don't optimize non-zero comparisons
+        field = (x >>> y) == 1 ? 1 : 0;
+        field = (x >> y) == 1 ? 1 : 0;
+        field = (x << y) == 1 ? 1 : 0;
+    }
+
+    @Test
+    public void testCompare() {
+        test("testCompareSnippet", "testCompareReference");
+    }
+
+    public static void testCompareSnippet(int x, int y, int[] array1, int[] array2) {
+        int tempX = x;
+        int array1Length = array1.length;
+        int array2Length = array2.length;
+        // optimize
+        field = x == tempX ? 1 : 0;
+        field = x != tempX ? 1 : 0;
+        field = array1Length != (-1 - array2Length) ? 1 : 0;
+        field = array1Length == (-1 - array2Length) ? 1 : 0;
+        // don't optimize
+        field = x == y ? 1 : 0;
+        field = array1Length == array2Length ? 1 : 0;
+        field = array1Length == (-array2Length) ? 1 : 0;
+    }
+
+    public static void testCompareReference(int x, int y, int[] array1, int[] array2) {
+        int array1Length = array1.length;
+        int array2Length = array2.length;
+        // optimize
+        field = 1;
+        field = 0;
+        field = 1;
+        field = 0;
+        // don't optimize (overlapping value ranges)
+        field = x == y ? 1 : 0;
+        field = array1Length == array2Length ? 1 : 0;
+        field = array1Length == (-array2Length) ? 1 : 0;
+    }
+
+    public static boolean testNormalIntegerTest(int a) {
+        return (a & 8) != 0;
+    }
+
+    public static boolean testAlternateIntegerTest(int a) {
+        return (a & 8) == 8;
+    }
+
+    @Test
+    public void testIntegerTest() {
+        test("testNormalIntegerTest", "testAlternateIntegerTest");
+    }
+
+    private void test(String snippet, String referenceSnippet) {
+        StructuredGraph graph = getCanonicalizedGraph(snippet);
+        StructuredGraph referenceGraph = getCanonicalizedGraph(referenceSnippet);
+        assertEquals(referenceGraph, graph);
+    }
+
+    private StructuredGraph getCanonicalizedGraph(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) {
+            state.replaceAtUsages(null);
+            state.safeDelete();
+        }
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerStampMulFoldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerStampMulFoldTest.java
new file mode 100644
index 0000000..861dac5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerStampMulFoldTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+
+@RunWith(Suite.class)
+@SuiteClasses({IntegerStampMulFoldTest.OverflowTest.class, IntegerStampMulFoldTest.FoldTest.class})
+public class IntegerStampMulFoldTest extends GraalCompilerTest {
+
+    public static class OverflowTest {
+        @Test
+        public void testOverflowCheck() {
+            // a.u * b.u overflows
+            long a = Integer.MIN_VALUE;
+            long b = -1;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck01() {
+            // a.u * b.u overflows
+            long a = Integer.MAX_VALUE;
+            long b = Integer.MAX_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck02() {
+            // a.u * b.u overflows
+            long a = Integer.MIN_VALUE;
+            long b = Integer.MIN_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck03() {
+            // a.u * b.u overflows
+            long a = Integer.MIN_VALUE;
+            long b = 1;
+            Assert.assertFalse(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck04() {
+            // a.u * b.u overflows
+            long a = Integer.MAX_VALUE;
+            long b = 1;
+            Assert.assertFalse(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck05() {
+            // a.u * b.u overflows
+            long a = Integer.MAX_VALUE;
+            long b = Integer.MIN_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 32));
+        }
+
+        @Test
+        public void testOverflowCheck06() {
+            // 31bits*31bits = 62bits + 1 carry is max 63 bits, we can never need 64 bits
+            long a = Integer.MAX_VALUE;
+            long b = Integer.MAX_VALUE;
+            Assert.assertTrue("31bit*31bit overflows 62", IntegerStamp.multiplicationOverflows(a, b, 62));
+            Assert.assertFalse("31bit*31bit does not overflow 63", IntegerStamp.multiplicationOverflows(a, b, 63));
+            Assert.assertFalse("31bit*31bit does not overflow 64", IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+
+        @Test
+        public void testOverflowCheck07() {
+            long a = Long.MAX_VALUE;
+            long b = 2;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+
+        @Test
+        public void testOverflowCheck08() {
+            long a = Long.MAX_VALUE;
+            long b = Long.MAX_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+
+        @Test
+        public void testOverflowCheck09() {
+            long a = -Long.MAX_VALUE;
+            long b = Long.MAX_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+
+        @Test
+        public void testOverflowCheck10() {
+            long a = -Long.MAX_VALUE;
+            long b = -Long.MAX_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+
+        @Test
+        public void testOverflowCheck11() {
+            long a = Long.MAX_VALUE;
+            long b = -Long.MAX_VALUE;
+            Assert.assertTrue(IntegerStamp.multiplicationOverflows(a, b, 64));
+        }
+    }
+
+    @RunWith(Parameterized.class)
+    public static class FoldTest {
+        @Parameter(0) public long lowerBound1;
+        @Parameter(1) public long upperBound1;
+        @Parameter(2) public long lowerBound2;
+        @Parameter(3) public long upperBound2;
+        @Parameter(4) public int bits;
+
+        @Test
+        public void computeStamp() {
+            IntegerStamp a = StampFactory.forInteger(bits, lowerBound1, upperBound1);
+            IntegerStamp b = StampFactory.forInteger(bits, lowerBound2, upperBound2);
+            IntegerStamp result = foldMul(a, b);
+            for (long l1 = lowerBound1; l1 <= upperBound1; l1++) {
+                for (long l2 = lowerBound2; l2 <= upperBound2; l2++) {
+                    long res = 0;
+                    if (bits == 8) {
+                        res = (byte) (l1 * l2);
+                    } else if (bits == 16) {
+                        res = (short) (l1 * l2);
+                    } else if (bits == 32) {
+                        res = (int) (l1 * l2);
+                    } else if (bits == 64) {
+                        res = l1 * l2;
+                    }
+                    Assert.assertTrue(result.contains(res));
+                    if (l2 == Long.MAX_VALUE) {
+                        // do not want to overflow the check loop
+                        break;
+                    }
+                }
+                if (l1 == Long.MAX_VALUE) {
+                    // do not want to overflow the check loop
+                    break;
+                }
+            }
+        }
+
+        @Parameters(name = "a[{0} - {1}] b[{2} - {3}] bits=32")
+        public static Collection<Object[]> data() {
+            ArrayList<Object[]> tests = new ArrayList<>();
+
+            // zero related
+            addTest(tests, -2, 2, 3, 3, 8);
+            addTest(tests, 0, 0, 1, 1, 8);
+            addTest(tests, 1, 1, 0, 0, 8);
+            addTest(tests, -1, 1, 0, 1, 8);
+            addTest(tests, -1, 1, 1, 1, 8);
+            addTest(tests, -1, 1, -1, 1, 8);
+
+            addTest(tests, -2, 2, 3, 3, 16);
+            addTest(tests, 0, 0, 1, 1, 16);
+            addTest(tests, 1, 1, 0, 0, 16);
+            addTest(tests, -1, 1, 0, 1, 16);
+            addTest(tests, -1, 1, 1, 1, 16);
+            addTest(tests, -1, 1, -1, 1, 16);
+
+            addTest(tests, -2, 2, 3, 3, 32);
+            addTest(tests, 0, 0, 1, 1, 32);
+            addTest(tests, 1, 1, 0, 0, 32);
+            addTest(tests, -1, 1, 0, 1, 32);
+            addTest(tests, -1, 1, 1, 1, 32);
+            addTest(tests, -1, 1, -1, 1, 32);
+
+            addTest(tests, 0, 0, 1, 1, 64);
+            addTest(tests, 1, 1, 0, 0, 64);
+            addTest(tests, -1, 1, 0, 1, 64);
+            addTest(tests, -1, 1, 1, 1, 64);
+            addTest(tests, -1, 1, -1, 1, 64);
+
+            // bounds
+            addTest(tests, Byte.MIN_VALUE, Byte.MIN_VALUE + 1, Byte.MAX_VALUE - 1, Byte.MAX_VALUE, 8);
+            addTest(tests, Byte.MIN_VALUE, Byte.MIN_VALUE + 1, -1, -1, 8);
+            addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF,
+                            Integer.MAX_VALUE, 32);
+            addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 32);
+            addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF,
+                            Integer.MAX_VALUE, 64);
+            addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 64);
+            addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE + 0xFFF, -1, -1, 64);
+
+            // constants
+            addTest(tests, 2, 2, 2, 2, 32);
+            addTest(tests, 1, 1, 2, 2, 32);
+            addTest(tests, 2, 2, 4, 4, 32);
+            addTest(tests, 3, 3, 3, 3, 32);
+            addTest(tests, -4, -4, 3, 3, 32);
+            addTest(tests, -4, -4, -3, -3, 32);
+            addTest(tests, 4, 4, -3, -3, 32);
+
+            addTest(tests, 2, 2, 2, 2, 64);
+            addTest(tests, 1, 1, 2, 2, 64);
+            addTest(tests, 3, 3, 3, 3, 64);
+
+            addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, 1, 1, 64);
+            addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, -1, -1, 64);
+            addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, -1, -1, 64);
+            addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, 1, 1, 64);
+
+            return tests;
+        }
+
+        private static void addTest(ArrayList<Object[]> tests, long lowerBound1, long upperBound1, long lowerBound2, long upperBound2, int bits) {
+            tests.add(new Object[]{lowerBound1, upperBound1, lowerBound2, upperBound2, bits});
+        }
+
+    }
+
+    private static IntegerStamp foldMul(IntegerStamp a, IntegerStamp b) {
+        return (IntegerStamp) IntegerStamp.OPS.getMul().foldStamp(a, b);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java
new file mode 100644
index 0000000..f580313
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.test.ExportingClassLoader;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public final class InterfaceMethodHandleTest extends GraalCompilerTest implements Opcodes {
+    private static final MethodHandle INTERFACE_HANDLE_M;
+    private static final MethodHandle INTERFACE_HANDLE_M2;
+
+    public interface I {
+        int m();
+
+        int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j);
+    }
+
+    static class A implements I {
+        @Override
+        public int m() {
+            return 0;
+        }
+
+        @Override
+        public int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+            return 1;
+        }
+
+    }
+
+    static class M2Thrower implements I {
+        @Override
+        public int m() {
+            return 0;
+        }
+
+        @Override
+        public int m2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+            throw new InternalError();
+        }
+
+    }
+
+    static {
+        try {
+            MethodType type = MethodType.fromMethodDescriptorString("()I", I.class.getClassLoader());
+            INTERFACE_HANDLE_M = MethodHandles.lookup().findVirtual(I.class, "m", type);
+            MethodType type2 = MethodType.fromMethodDescriptorString("(IIIIIIIIII)I", I.class.getClassLoader());
+            INTERFACE_HANDLE_M2 = MethodHandles.lookup().findVirtual(I.class, "m2", type2);
+        } catch (IllegalAccessException | NoSuchMethodException e) {
+            throw new RuntimeException("unable to initialize method handle", e);
+        }
+    }
+
+    public static Object invokeInterfaceHandle(I o) throws Throwable {
+        return (int) INTERFACE_HANDLE_M.invokeExact(o);
+    }
+
+    @Test
+    public void testInvokeInterface01() {
+        test("invokeInterfaceHandle", new A());
+
+    }
+
+    @Test
+    public void testInvokeInterface02() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        test("invokeInterfaceHandle", loader.findClass(NAME).newInstance());
+    }
+
+    public static Object invokeInterfaceHandle2(I o, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) throws Throwable {
+        return (int) INTERFACE_HANDLE_M2.invokeExact(o, a, b, c, d, e, f, g, h, i, j);
+    }
+
+    @Override
+    protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
+        if (method.getDeclaringClass().equals(getMetaAccess().lookupJavaType(M2Thrower.class))) {
+            // Make sure M2Thrower.m2 is invoked from normal code
+            return getBackend().createDefaultInstalledCode(method, compResult);
+        }
+        return super.addMethod(method, compResult);
+    }
+
+    /**
+     * Try to exercise a mixed calling sequence with regular JIT code calling a method handle that
+     * can't be inlined with an implementation compiled by Graal that throws an exception.
+     */
+    @Test
+    public void testInvokeInterface03() throws Throwable {
+        A goodInstance = new A();
+        I badInstance = new M2Thrower();
+        getCode(getMetaAccess().lookupJavaMethod(getMethod(M2Thrower.class, "m2")));
+        for (int x = 0; x < 1000; x++) {
+            final int limit = 20000;
+            for (int i = 0; i <= limit; i++) {
+                try {
+                    invokeInterfaceHandle2(i < limit - 1 ? goodInstance : badInstance, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+                } catch (InternalError e) {
+
+                }
+            }
+        }
+    }
+
+    private static final String BASENAME = InterfaceMethodHandleTest.class.getName();
+    private static final String NAME = BASENAME + "_B";
+    private AsmLoader loader = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader());
+
+    /**
+     * Construct a type which claims to implement {@link I} but with incorrect access on {@link I#m}
+     * so that an exception must be thrown.
+     */
+    public static byte[] bytesForB() {
+
+        ClassWriter cw = new ClassWriter(0);
+        MethodVisitor mv;
+        String jvmName = NAME.replace('.', '/');
+        cw.visit(52, ACC_SUPER | ACC_PUBLIC, jvmName, null, "java/lang/Object", new String[]{BASENAME.replace('.', '/') + "$I"});
+
+        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PRIVATE, "m", "()I", null, null);
+        mv.visitCode();
+        l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitInsn(ICONST_0);
+        mv.visitInsn(IRETURN);
+        l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+
+        cw.visitEnd();
+
+        mv = cw.visitMethod(ACC_PRIVATE, "m2", "(IIIIIIIIII)I", null, null);
+        mv.visitCode();
+        l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitInsn(ICONST_0);
+        mv.visitInsn(IRETURN);
+        l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitMaxs(1, 11);
+        mv.visitEnd();
+
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+
+    public static class AsmLoader extends ExportingClassLoader {
+        Class<?> loaded;
+
+        public AsmLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(NAME)) {
+                if (loaded != null) {
+                    return loaded;
+                }
+                byte[] bytes = bytesForB();
+                return (loaded = defineClass(name, bytes, 0, bytes.length));
+            } else {
+                return super.findClass(name);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java
new file mode 100644
index 0000000..303f8fc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class InvokeExceptionTest extends GraalCompilerTest {
+
+    public static synchronized void throwException(int i) {
+        if (i == 1) {
+            throw new RuntimeException();
+        }
+    }
+
+    @Test
+    public void test1() {
+        // fill the profiling data...
+        for (int i = 0; i < 10000; i++) {
+            try {
+                throwException(i & 1);
+                test1Snippet(0);
+            } catch (Throwable t) {
+                // nothing to do...
+            }
+        }
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static void test1Snippet(int a) {
+        throwException(a);
+    }
+
+    private void test(String snippet) {
+        StructuredGraph graph = parseProfiled(snippet, AllowAssumptions.NO);
+        Map<Invoke, Double> hints = new HashMap<>();
+        for (Invoke invoke : graph.getInvokes()) {
+            hints.put(invoke, 1000d);
+        }
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, context);
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java
new file mode 100644
index 0000000..9cd5f11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class InvokeHintsTest extends GraalCompilerTest {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    public static int const1() {
+        return 1;
+    }
+
+    public static int const7() {
+        return 7;
+    }
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet() {
+        return 7;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test1Snippet() {
+        return const7();
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet() {
+        return const1() + const1() + const1() + const1() + const1() + const1() + const1();
+    }
+
+    private void test(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        Map<Invoke, Double> hints = new HashMap<>();
+        for (Invoke invoke : graph.getInvokes()) {
+            hints.put(invoke, 1000d);
+        }
+
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, context);
+        new DeadCodeEliminationPhase().apply(graph);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO);
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java
new file mode 100644
index 0000000..9e0d5a9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.LockEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class LockEliminationTest extends GraalCompilerTest {
+
+    static class A {
+
+        int value;
+
+        public synchronized int getValue() {
+            return value;
+        }
+    }
+
+    static int field1;
+    static int field2;
+
+    public static void testSynchronizedSnippet(A x, A y) {
+        synchronized (x) {
+            field1 = x.value;
+        }
+        synchronized (x) {
+            field2 = y.value;
+        }
+    }
+
+    @Test
+    public void testLock() {
+        test("testSynchronizedSnippet", new A(), new A());
+
+        StructuredGraph graph = getGraph("testSynchronizedSnippet");
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new LockEliminationPhase().apply(graph);
+        assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+    }
+
+    public static void testSynchronizedMethodSnippet(A x) {
+        int value1 = x.getValue();
+        int value2 = x.getValue();
+        field1 = value1;
+        field2 = value2;
+    }
+
+    @Test
+    public void testSynchronizedMethod() {
+        test("testSynchronizedMethodSnippet", new A());
+
+        StructuredGraph graph = getGraph("testSynchronizedMethodSnippet");
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new LockEliminationPhase().apply(graph);
+        assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+    }
+
+    private StructuredGraph getGraph(String snippet) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
+        StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
+        HighTierContext context = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(graph, context);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, context);
+        new DeadCodeEliminationPhase().apply(graph);
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new ValueAnchorCleanupPhase().apply(graph);
+        new LockEliminationPhase().apply(graph);
+        return graph;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java
new file mode 100644
index 0000000..75c5d71
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.debug.OpaqueNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class LongNodeChainTest extends GraalCompilerTest {
+
+    public static final int N = 10000;
+
+    private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST};
+
+    @Test
+    public void testLongAddChain() {
+        longAddChain(true);
+        longAddChain(false);
+    }
+
+    private void longAddChain(boolean reverse) {
+        HighTierContext context = getDefaultHighTierContext();
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO, INVALID_COMPILATION_ID);
+        ValueNode constant = graph.unique(ConstantNode.forPrimitive(JavaConstant.INT_1));
+        ValueNode value = null;
+        if (reverse) {
+            // Make sure the constant's stamp is not used to infer the add node's stamp.
+            OpaqueNode opaque = graph.unique(new OpaqueNode(constant));
+            constant = opaque;
+            AddNode addNode = graph.unique(new AddNode(constant, constant));
+            value = addNode;
+            for (int i = 1; i < N; ++i) {
+                AddNode newAddNode = graph.addWithoutUnique(new AddNode(constant, constant));
+                addNode.setY(newAddNode);
+                addNode = newAddNode;
+            }
+            opaque.replaceAndDelete(opaque.getValue());
+        } else {
+            value = constant;
+            for (int i = 0; i < N; ++i) {
+                value = graph.unique(new AddNode(constant, value));
+            }
+        }
+        ReturnNode returnNode = graph.add(new ReturnNode(value));
+        graph.start().setNext(returnNode);
+
+        for (SchedulingStrategy s : Strategies) {
+            new SchedulePhase(s).apply(graph);
+        }
+
+        new CanonicalizerPhase().apply(graph, context);
+        JavaConstant asConstant = (JavaConstant) returnNode.result().asConstant();
+        Assert.assertEquals(N + 1, asConstant.asInt());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java
new file mode 100644
index 0000000..3c4e124
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class LoopUnswitchTest extends GraalCompilerTest {
+
+    public static int referenceSnippet1(int a) {
+        int sum = 0;
+        if (a > 2) {
+            for (int i = 0; i < 1000; i++) {
+                sum += 2;
+            }
+        } else {
+            for (int i = 0; i < 1000; i++) {
+                sum += a;
+            }
+        }
+        return sum;
+    }
+
+    public static int test1Snippet(int a) {
+        int sum = 0;
+        for (int i = 0; i < 1000; i++) {
+            if (a > 2) {
+                sum += 2;
+            } else {
+                sum += a;
+            }
+        }
+        return sum;
+    }
+
+    public static int referenceSnippet2(int a) {
+        int sum = 0;
+        switch (a) {
+            case 0:
+                for (int i = 0; i < 1000; i++) {
+                    sum += System.currentTimeMillis();
+                }
+                break;
+            case 1:
+                for (int i = 0; i < 1000; i++) {
+                    sum += 1;
+                    sum += 5;
+                }
+                break;
+            case 55:
+                for (int i = 0; i < 1000; i++) {
+                    sum += 5;
+                }
+                break;
+            default:
+                for (int i = 0; i < 1000; i++) {
+                    // nothing
+                }
+                break;
+        }
+        return sum;
+    }
+
+    @SuppressWarnings("fallthrough")
+    public static int test2Snippet(int a) {
+        int sum = 0;
+        for (int i = 0; i < 1000; i++) {
+            switch (a) {
+                case 0:
+                    sum += System.currentTimeMillis();
+                    break;
+                case 1:
+                    sum += 1;
+                    // fall through
+                case 55:
+                    sum += 5;
+                    break;
+                default:
+                    // nothing
+                    break;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "referenceSnippet1");
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", "referenceSnippet2");
+    }
+
+    @SuppressWarnings("try")
+    private void test(String snippet, String referenceSnippet) {
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+
+        new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph);
+
+        // Framestates create comparison problems
+        graph.clearAllStateAfter();
+        referenceGraph.clearAllStateAfter();
+
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        try (Scope s = Debug.scope("Test", new DebugDumpScope("Test:" + snippet))) {
+            assertEquals(referenceGraph, graph);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java
new file mode 100644
index 0000000..1d07d3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class MarkUnsafeAccessTest extends GraalCompilerTest {
+
+    public static Unsafe unsafe;
+
+    public void getRaw() {
+        unsafe.getInt(0L);
+    }
+
+    public void get() {
+        unsafe.getInt(null, 0L);
+    }
+
+    public void putRaw() {
+        unsafe.putInt(0L, 0);
+    }
+
+    public void put() {
+        unsafe.putInt(null, 0L, 0);
+    }
+
+    public void cas() {
+        unsafe.compareAndSwapInt(null, 0, 0, 0);
+    }
+
+    public void noAccess() {
+        unsafe.addressSize();
+        unsafe.pageSize();
+    }
+
+    private void assertHasUnsafe(String name, boolean hasUnsafe) {
+        Assert.assertEquals(hasUnsafe, compile(getResolvedJavaMethod(name), null).hasUnsafeAccess());
+    }
+
+    @Test
+    public void testGet() {
+        assertHasUnsafe("get", true);
+        assertHasUnsafe("getRaw", true);
+    }
+
+    @Test
+    public void testPut() {
+        assertHasUnsafe("put", true);
+        assertHasUnsafe("putRaw", true);
+    }
+
+    @Test
+    public void testCas() {
+        assertHasUnsafe("cas", true);
+    }
+
+    @Test
+    public void testNoAcces() {
+        assertHasUnsafe("noAccess", false);
+    }
+
+    @FunctionalInterface
+    private interface MappedByteBufferGetter {
+        byte get(MappedByteBuffer mbb);
+    }
+
+    @Test
+    public void testStandard() throws IOException {
+        testMappedByteBuffer(MappedByteBuffer::get);
+    }
+
+    @Test
+    public void testCompiled() throws IOException {
+        ResolvedJavaMethod getMethod = asResolvedJavaMethod(getMethod(ByteBuffer.class, "get", new Class<?>[]{}));
+        ResolvedJavaType mbbClass = getMetaAccess().lookupJavaType(MappedByteBuffer.class);
+        ResolvedJavaMethod getMethodImpl = mbbClass.findUniqueConcreteMethod(getMethod).getResult();
+        Assert.assertNotNull(getMethodImpl);
+        StructuredGraph graph = parseForCompile(getMethodImpl);
+        HighTierContext highContext = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(graph, highContext);
+        new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
+        InstalledCode compiledCode = getCode(getMethodImpl, graph);
+        testMappedByteBuffer(mbb -> {
+            try {
+                return (byte) compiledCode.executeVarargs(mbb);
+            } catch (InvalidInstalledCodeException e) {
+                Assert.fail();
+                return 0;
+            }
+        });
+    }
+
+    private static final int BLOCK_SIZE = 512;
+    private static final int BLOCK_COUNT = 16;
+
+    public void testMappedByteBuffer(MappedByteBufferGetter getter) throws IOException {
+        Path tmp = Files.createTempFile(null, null);
+        tmp.toFile().deleteOnExit();
+        FileChannel tmpFileChannel = FileChannel.open(tmp, READ, WRITE);
+        ByteBuffer bb = ByteBuffer.allocate(BLOCK_SIZE);
+        while (bb.remaining() >= 4) {
+            bb.putInt(0xA8A8A8A8);
+        }
+        for (int i = 0; i < BLOCK_COUNT; ++i) {
+            bb.flip();
+            while (bb.hasRemaining()) {
+                tmpFileChannel.write(bb);
+            }
+        }
+        tmpFileChannel.force(true);
+        MappedByteBuffer mbb = tmpFileChannel.map(MapMode.READ_WRITE, 0, BLOCK_SIZE * BLOCK_COUNT);
+        Assert.assertEquals((byte) 0xA8, mbb.get());
+        mbb.position(mbb.position() + BLOCK_SIZE);
+        Assert.assertEquals((byte) 0xA8, mbb.get());
+        boolean truncated = false;
+        try {
+            tmpFileChannel.truncate(0);
+            tmpFileChannel.force(true);
+            truncated = true;
+        } catch (IOException e) {
+            // not all platforms support truncating memory-mapped files
+        }
+        Assume.assumeTrue(truncated);
+        try {
+            mbb.position(BLOCK_SIZE);
+            getter.get(mbb);
+            System.currentTimeMillis(); // materialize async exception
+        } catch (InternalError e) {
+            return;
+        }
+        Assert.fail("Expected exception");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryArithmeticTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryArithmeticTest.java
new file mode 100644
index 0000000..ae12cbf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryArithmeticTest.java
@@ -0,0 +1,4337 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public class MemoryArithmeticTest extends GraalCompilerTest {
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
+        return getCode(method, graph, true);
+    }
+
+    /**
+     * Called before a test is executed.
+     */
+    @Override
+    protected void before(ResolvedJavaMethod method) {
+        // don't let any null exception tracking change the generated code.
+        method.reprofile();
+    }
+
+    /**
+     * A dummy field used by some tests to create side effects.
+     */
+    protected static int count;
+
+    static class FieldObject {
+        boolean booleanValue;
+        byte byteValue;
+        short shortValue;
+        char charValue;
+        int intValue;
+        float floatValue;
+        long longValue;
+        double doubleValue;
+        Object objectValue;
+    }
+
+    static FieldObject maxObject = new FieldObject();
+    static FieldObject minObject;
+
+    static final boolean booleanTestValue1 = false;
+    static final byte byteTestValue1 = 0;
+    static final short shortTestValue1 = 0;
+    static final char charTestValue1 = 0;
+    static final int intTestValue1 = 0;
+    static final float floatTestValue1 = 0;
+    static final long longTestValue1 = 0;
+    static final double doubleTestValue1 = 0;
+    static final Object objectTestValue1 = null;
+
+    static final boolean booleanTestValue2 = true;
+    static final byte byteTestValue2 = Byte.MAX_VALUE;
+    static final short shortTestValue2 = Short.MAX_VALUE;
+    static final char charTestValue2 = Character.MAX_VALUE;
+    static final int intTestValue2 = Integer.MAX_VALUE;
+    static final float floatTestValue2 = Float.MAX_VALUE;
+    static final long longTestValue2 = Long.MAX_VALUE;
+    static final double doubleTestValue2 = Double.MAX_VALUE;
+    static final Object objectTestValue2 = "String";
+
+    static {
+        maxObject.booleanValue = true;
+        maxObject.byteValue = Byte.MAX_VALUE;
+        maxObject.shortValue = Short.MAX_VALUE;
+        maxObject.charValue = Character.MAX_VALUE;
+        maxObject.intValue = Integer.MAX_VALUE;
+        maxObject.floatValue = Float.MAX_VALUE;
+        maxObject.longValue = Long.MAX_VALUE;
+        maxObject.doubleValue = Double.MAX_VALUE;
+        maxObject.objectValue = "String";
+    }
+
+    public static Object testBooleanCompare(FieldObject f, boolean booleanValue) {
+        if (f.booleanValue == booleanValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant1(FieldObject f) {
+        if (f.booleanValue == booleanTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant2(FieldObject f) {
+        if (f.booleanValue == booleanTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testBooleanCompares() {
+        FieldObject f = new FieldObject();
+        test("testBooleanCompare", f, booleanTestValue1);
+        test("testBooleanCompareConstant1", f);
+        test("testBooleanCompareConstant2", f);
+    }
+
+    @Test
+    public void testBooleanNullCompares() {
+        test("testBooleanCompare", null, booleanTestValue1);
+    }
+
+    @Test
+    public void testBooleanNullCompares1() {
+        test("testBooleanCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testBooleanNullCompares2() {
+        test("testBooleanCompareConstant2", (Object) null);
+    }
+
+    public static Object testByteCompare(FieldObject f, byte byteValue) {
+        if (f.byteValue == byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant1(FieldObject f) {
+        if (f.byteValue == byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant2(FieldObject f) {
+        if (f.byteValue == byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteCompares() {
+        FieldObject f = new FieldObject();
+        test("testByteCompare", f, byteTestValue1);
+        test("testByteCompareConstant1", f);
+        test("testByteCompareConstant2", f);
+    }
+
+    @Test
+    public void testByteNullCompares() {
+        test("testByteCompare", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullCompares1() {
+        test("testByteCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullCompares2() {
+        test("testByteCompareConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareLess(FieldObject f, byte byteValue) {
+        if (f.byteValue < byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessConstant1(FieldObject f) {
+        if (f.byteValue < byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessConstant2(FieldObject f) {
+        if (f.byteValue < byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareLess", f, byteTestValue1);
+        test("testByteCompareLessConstant1", f);
+        test("testByteCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesLess() {
+        test("testByteCompareLess", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesLess1() {
+        test("testByteCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesLess2() {
+        test("testByteCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareLess(FieldObject f, byte byteValue) {
+        if (byteValue < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessConstant1(FieldObject f) {
+        if (byteTestValue1 < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessConstant2(FieldObject f) {
+        if (byteTestValue2 < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareLess", f, byteTestValue1);
+        test("testByteSwappedCompareLessConstant1", f);
+        test("testByteSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess() {
+        test("testByteSwappedCompareLess", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess1() {
+        test("testByteSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess2() {
+        test("testByteSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareLessEqual(FieldObject f, byte byteValue) {
+        if (f.byteValue <= byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessEqualConstant1(FieldObject f) {
+        if (f.byteValue <= byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessEqualConstant2(FieldObject f) {
+        if (f.byteValue <= byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareLessEqual", f, byteTestValue1);
+        test("testByteCompareLessEqualConstant1", f);
+        test("testByteCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual() {
+        test("testByteCompareLessEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual1() {
+        test("testByteCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual2() {
+        test("testByteCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareLessEqual(FieldObject f, byte byteValue) {
+        if (byteValue <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (byteTestValue1 <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (byteTestValue2 <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareLessEqual", f, byteTestValue1);
+        test("testByteSwappedCompareLessEqualConstant1", f);
+        test("testByteSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual() {
+        test("testByteSwappedCompareLessEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual1() {
+        test("testByteSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual2() {
+        test("testByteSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareGreater(FieldObject f, byte byteValue) {
+        if (f.byteValue > byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterConstant1(FieldObject f) {
+        if (f.byteValue > byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterConstant2(FieldObject f) {
+        if (f.byteValue > byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareGreater", f, byteTestValue1);
+        test("testByteCompareGreaterConstant1", f);
+        test("testByteCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesGreater() {
+        test("testByteCompareGreater", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesGreater1() {
+        test("testByteCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesGreater2() {
+        test("testByteCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareGreater(FieldObject f, byte byteValue) {
+        if (byteValue > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterConstant1(FieldObject f) {
+        if (byteTestValue1 > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterConstant2(FieldObject f) {
+        if (byteTestValue2 > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareGreater", f, byteTestValue1);
+        test("testByteSwappedCompareGreaterConstant1", f);
+        test("testByteSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater() {
+        test("testByteSwappedCompareGreater", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater1() {
+        test("testByteSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater2() {
+        test("testByteSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareGreaterEqual(FieldObject f, byte byteValue) {
+        if (f.byteValue >= byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.byteValue >= byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.byteValue >= byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareGreaterEqual", f, byteTestValue1);
+        test("testByteCompareGreaterEqualConstant1", f);
+        test("testByteCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual() {
+        test("testByteCompareGreaterEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual1() {
+        test("testByteCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual2() {
+        test("testByteCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareGreaterEqual(FieldObject f, byte byteValue) {
+        if (byteValue >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (byteTestValue1 >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (byteTestValue2 >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareGreaterEqual", f, byteTestValue1);
+        test("testByteSwappedCompareGreaterEqualConstant1", f);
+        test("testByteSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual() {
+        test("testByteSwappedCompareGreaterEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual1() {
+        test("testByteSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual2() {
+        test("testByteSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortCompare(FieldObject f, short shortValue) {
+        if (f.shortValue == shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant1(FieldObject f) {
+        if (f.shortValue == shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant2(FieldObject f) {
+        if (f.shortValue == shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortCompares() {
+        FieldObject f = new FieldObject();
+        test("testShortCompare", f, shortTestValue1);
+        test("testShortCompareConstant1", f);
+        test("testShortCompareConstant2", f);
+    }
+
+    @Test
+    public void testShortNullCompares() {
+        test("testShortCompare", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullCompares1() {
+        test("testShortCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullCompares2() {
+        test("testShortCompareConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareLess(FieldObject f, short shortValue) {
+        if (f.shortValue < shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessConstant1(FieldObject f) {
+        if (f.shortValue < shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessConstant2(FieldObject f) {
+        if (f.shortValue < shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareLess", f, shortTestValue1);
+        test("testShortCompareLessConstant1", f);
+        test("testShortCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesLess() {
+        test("testShortCompareLess", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesLess1() {
+        test("testShortCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesLess2() {
+        test("testShortCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareLess(FieldObject f, short shortValue) {
+        if (shortValue < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessConstant1(FieldObject f) {
+        if (shortTestValue1 < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessConstant2(FieldObject f) {
+        if (shortTestValue2 < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareLess", f, shortTestValue1);
+        test("testShortSwappedCompareLessConstant1", f);
+        test("testShortSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess() {
+        test("testShortSwappedCompareLess", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess1() {
+        test("testShortSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess2() {
+        test("testShortSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareLessEqual(FieldObject f, short shortValue) {
+        if (f.shortValue <= shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessEqualConstant1(FieldObject f) {
+        if (f.shortValue <= shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessEqualConstant2(FieldObject f) {
+        if (f.shortValue <= shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareLessEqual", f, shortTestValue1);
+        test("testShortCompareLessEqualConstant1", f);
+        test("testShortCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual() {
+        test("testShortCompareLessEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual1() {
+        test("testShortCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual2() {
+        test("testShortCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareLessEqual(FieldObject f, short shortValue) {
+        if (shortValue <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (shortTestValue1 <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (shortTestValue2 <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareLessEqual", f, shortTestValue1);
+        test("testShortSwappedCompareLessEqualConstant1", f);
+        test("testShortSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual() {
+        test("testShortSwappedCompareLessEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual1() {
+        test("testShortSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual2() {
+        test("testShortSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareGreater(FieldObject f, short shortValue) {
+        if (f.shortValue > shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterConstant1(FieldObject f) {
+        if (f.shortValue > shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterConstant2(FieldObject f) {
+        if (f.shortValue > shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareGreater", f, shortTestValue1);
+        test("testShortCompareGreaterConstant1", f);
+        test("testShortCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesGreater() {
+        test("testShortCompareGreater", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesGreater1() {
+        test("testShortCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesGreater2() {
+        test("testShortCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareGreater(FieldObject f, short shortValue) {
+        if (shortValue > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterConstant1(FieldObject f) {
+        if (shortTestValue1 > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterConstant2(FieldObject f) {
+        if (shortTestValue2 > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareGreater", f, shortTestValue1);
+        test("testShortSwappedCompareGreaterConstant1", f);
+        test("testShortSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater() {
+        test("testShortSwappedCompareGreater", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater1() {
+        test("testShortSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater2() {
+        test("testShortSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareGreaterEqual(FieldObject f, short shortValue) {
+        if (f.shortValue >= shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.shortValue >= shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.shortValue >= shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareGreaterEqual", f, shortTestValue1);
+        test("testShortCompareGreaterEqualConstant1", f);
+        test("testShortCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual() {
+        test("testShortCompareGreaterEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual1() {
+        test("testShortCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual2() {
+        test("testShortCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareGreaterEqual(FieldObject f, short shortValue) {
+        if (shortValue >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (shortTestValue1 >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (shortTestValue2 >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareGreaterEqual", f, shortTestValue1);
+        test("testShortSwappedCompareGreaterEqualConstant1", f);
+        test("testShortSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual() {
+        test("testShortSwappedCompareGreaterEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual1() {
+        test("testShortSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual2() {
+        test("testShortSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharCompare(FieldObject f, char charValue) {
+        if (f.charValue == charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant1(FieldObject f) {
+        if (f.charValue == charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant2(FieldObject f) {
+        if (f.charValue == charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharCompares() {
+        FieldObject f = new FieldObject();
+        test("testCharCompare", f, charTestValue1);
+        test("testCharCompareConstant1", f);
+        test("testCharCompareConstant2", f);
+    }
+
+    @Test
+    public void testCharNullCompares() {
+        test("testCharCompare", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullCompares1() {
+        test("testCharCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullCompares2() {
+        test("testCharCompareConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareLess(FieldObject f, char charValue) {
+        if (f.charValue < charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessConstant1(FieldObject f) {
+        if (f.charValue < charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessConstant2(FieldObject f) {
+        if (f.charValue < charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareLess", f, charTestValue1);
+        test("testCharCompareLessConstant1", f);
+        test("testCharCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesLess() {
+        test("testCharCompareLess", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesLess1() {
+        test("testCharCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesLess2() {
+        test("testCharCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareLess(FieldObject f, char charValue) {
+        if (charValue < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessConstant1(FieldObject f) {
+        if (charTestValue1 < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessConstant2(FieldObject f) {
+        if (charTestValue2 < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareLess", f, charTestValue1);
+        test("testCharSwappedCompareLessConstant1", f);
+        test("testCharSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess() {
+        test("testCharSwappedCompareLess", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess1() {
+        test("testCharSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess2() {
+        test("testCharSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareLessEqual(FieldObject f, char charValue) {
+        if (f.charValue <= charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessEqualConstant1(FieldObject f) {
+        if (f.charValue <= charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessEqualConstant2(FieldObject f) {
+        if (f.charValue <= charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareLessEqual", f, charTestValue1);
+        test("testCharCompareLessEqualConstant1", f);
+        test("testCharCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual() {
+        test("testCharCompareLessEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual1() {
+        test("testCharCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual2() {
+        test("testCharCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareLessEqual(FieldObject f, char charValue) {
+        if (charValue <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (charTestValue1 <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (charTestValue2 <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareLessEqual", f, charTestValue1);
+        test("testCharSwappedCompareLessEqualConstant1", f);
+        test("testCharSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual() {
+        test("testCharSwappedCompareLessEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual1() {
+        test("testCharSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual2() {
+        test("testCharSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareGreater(FieldObject f, char charValue) {
+        if (f.charValue > charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterConstant1(FieldObject f) {
+        if (f.charValue > charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterConstant2(FieldObject f) {
+        if (f.charValue > charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareGreater", f, charTestValue1);
+        test("testCharCompareGreaterConstant1", f);
+        test("testCharCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesGreater() {
+        test("testCharCompareGreater", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesGreater1() {
+        test("testCharCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesGreater2() {
+        test("testCharCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareGreater(FieldObject f, char charValue) {
+        if (charValue > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterConstant1(FieldObject f) {
+        if (charTestValue1 > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterConstant2(FieldObject f) {
+        if (charTestValue2 > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareGreater", f, charTestValue1);
+        test("testCharSwappedCompareGreaterConstant1", f);
+        test("testCharSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater() {
+        test("testCharSwappedCompareGreater", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater1() {
+        test("testCharSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater2() {
+        test("testCharSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareGreaterEqual(FieldObject f, char charValue) {
+        if (f.charValue >= charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.charValue >= charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.charValue >= charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareGreaterEqual", f, charTestValue1);
+        test("testCharCompareGreaterEqualConstant1", f);
+        test("testCharCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual() {
+        test("testCharCompareGreaterEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual1() {
+        test("testCharCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual2() {
+        test("testCharCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareGreaterEqual(FieldObject f, char charValue) {
+        if (charValue >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (charTestValue1 >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (charTestValue2 >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareGreaterEqual", f, charTestValue1);
+        test("testCharSwappedCompareGreaterEqualConstant1", f);
+        test("testCharSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual() {
+        test("testCharSwappedCompareGreaterEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual1() {
+        test("testCharSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual2() {
+        test("testCharSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntCompare(FieldObject f, int intValue) {
+        if (f.intValue == intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant1(FieldObject f) {
+        if (f.intValue == intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant2(FieldObject f) {
+        if (f.intValue == intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntCompares() {
+        FieldObject f = new FieldObject();
+        test("testIntCompare", f, intTestValue1);
+        test("testIntCompareConstant1", f);
+        test("testIntCompareConstant2", f);
+    }
+
+    @Test
+    public void testIntNullCompares() {
+        test("testIntCompare", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullCompares1() {
+        test("testIntCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullCompares2() {
+        test("testIntCompareConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareLess(FieldObject f, int intValue) {
+        if (f.intValue < intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessConstant1(FieldObject f) {
+        if (f.intValue < intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessConstant2(FieldObject f) {
+        if (f.intValue < intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareLess", f, intTestValue1);
+        test("testIntCompareLessConstant1", f);
+        test("testIntCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesLess() {
+        test("testIntCompareLess", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesLess1() {
+        test("testIntCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesLess2() {
+        test("testIntCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareLess(FieldObject f, int intValue) {
+        if (intValue < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessConstant1(FieldObject f) {
+        if (intTestValue1 < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessConstant2(FieldObject f) {
+        if (intTestValue2 < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareLess", f, intTestValue1);
+        test("testIntSwappedCompareLessConstant1", f);
+        test("testIntSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess() {
+        test("testIntSwappedCompareLess", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess1() {
+        test("testIntSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess2() {
+        test("testIntSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareLessEqual(FieldObject f, int intValue) {
+        if (f.intValue <= intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessEqualConstant1(FieldObject f) {
+        if (f.intValue <= intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessEqualConstant2(FieldObject f) {
+        if (f.intValue <= intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareLessEqual", f, intTestValue1);
+        test("testIntCompareLessEqualConstant1", f);
+        test("testIntCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual() {
+        test("testIntCompareLessEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual1() {
+        test("testIntCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual2() {
+        test("testIntCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareLessEqual(FieldObject f, int intValue) {
+        if (intValue <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (intTestValue1 <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (intTestValue2 <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareLessEqual", f, intTestValue1);
+        test("testIntSwappedCompareLessEqualConstant1", f);
+        test("testIntSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual() {
+        test("testIntSwappedCompareLessEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual1() {
+        test("testIntSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual2() {
+        test("testIntSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareGreater(FieldObject f, int intValue) {
+        if (f.intValue > intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterConstant1(FieldObject f) {
+        if (f.intValue > intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterConstant2(FieldObject f) {
+        if (f.intValue > intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareGreater", f, intTestValue1);
+        test("testIntCompareGreaterConstant1", f);
+        test("testIntCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesGreater() {
+        test("testIntCompareGreater", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesGreater1() {
+        test("testIntCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesGreater2() {
+        test("testIntCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareGreater(FieldObject f, int intValue) {
+        if (intValue > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterConstant1(FieldObject f) {
+        if (intTestValue1 > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterConstant2(FieldObject f) {
+        if (intTestValue2 > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareGreater", f, intTestValue1);
+        test("testIntSwappedCompareGreaterConstant1", f);
+        test("testIntSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater() {
+        test("testIntSwappedCompareGreater", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater1() {
+        test("testIntSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater2() {
+        test("testIntSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareGreaterEqual(FieldObject f, int intValue) {
+        if (f.intValue >= intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.intValue >= intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.intValue >= intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareGreaterEqual", f, intTestValue1);
+        test("testIntCompareGreaterEqualConstant1", f);
+        test("testIntCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual() {
+        test("testIntCompareGreaterEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual1() {
+        test("testIntCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual2() {
+        test("testIntCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareGreaterEqual(FieldObject f, int intValue) {
+        if (intValue >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (intTestValue1 >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (intTestValue2 >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareGreaterEqual", f, intTestValue1);
+        test("testIntSwappedCompareGreaterEqualConstant1", f);
+        test("testIntSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual() {
+        test("testIntSwappedCompareGreaterEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual1() {
+        test("testIntSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual2() {
+        test("testIntSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompare(FieldObject f, float floatValue) {
+        if (f.floatValue == floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant1(FieldObject f) {
+        if (f.floatValue == floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant2(FieldObject f) {
+        if (f.floatValue == floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatCompares() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompare", f, floatTestValue1);
+        test("testFloatCompareConstant1", f);
+        test("testFloatCompareConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullCompares() {
+        test("testFloatCompare", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullCompares1() {
+        test("testFloatCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullCompares2() {
+        test("testFloatCompareConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareLess(FieldObject f, float floatValue) {
+        if (f.floatValue < floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessConstant1(FieldObject f) {
+        if (f.floatValue < floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessConstant2(FieldObject f) {
+        if (f.floatValue < floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareLess", f, floatTestValue1);
+        test("testFloatCompareLessConstant1", f);
+        test("testFloatCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesLess() {
+        test("testFloatCompareLess", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesLess1() {
+        test("testFloatCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesLess2() {
+        test("testFloatCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareLess(FieldObject f, float floatValue) {
+        if (floatValue < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessConstant1(FieldObject f) {
+        if (floatTestValue1 < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessConstant2(FieldObject f) {
+        if (floatTestValue2 < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareLess", f, floatTestValue1);
+        test("testFloatSwappedCompareLessConstant1", f);
+        test("testFloatSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess() {
+        test("testFloatSwappedCompareLess", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess1() {
+        test("testFloatSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess2() {
+        test("testFloatSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareLessEqual(FieldObject f, float floatValue) {
+        if (f.floatValue <= floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessEqualConstant1(FieldObject f) {
+        if (f.floatValue <= floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessEqualConstant2(FieldObject f) {
+        if (f.floatValue <= floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareLessEqual", f, floatTestValue1);
+        test("testFloatCompareLessEqualConstant1", f);
+        test("testFloatCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual() {
+        test("testFloatCompareLessEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual1() {
+        test("testFloatCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual2() {
+        test("testFloatCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareLessEqual(FieldObject f, float floatValue) {
+        if (floatValue <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (floatTestValue1 <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (floatTestValue2 <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareLessEqual", f, floatTestValue1);
+        test("testFloatSwappedCompareLessEqualConstant1", f);
+        test("testFloatSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual() {
+        test("testFloatSwappedCompareLessEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual1() {
+        test("testFloatSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual2() {
+        test("testFloatSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareGreater(FieldObject f, float floatValue) {
+        if (f.floatValue > floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterConstant1(FieldObject f) {
+        if (f.floatValue > floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterConstant2(FieldObject f) {
+        if (f.floatValue > floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareGreater", f, floatTestValue1);
+        test("testFloatCompareGreaterConstant1", f);
+        test("testFloatCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater() {
+        test("testFloatCompareGreater", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater1() {
+        test("testFloatCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater2() {
+        test("testFloatCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareGreater(FieldObject f, float floatValue) {
+        if (floatValue > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterConstant1(FieldObject f) {
+        if (floatTestValue1 > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterConstant2(FieldObject f) {
+        if (floatTestValue2 > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareGreater", f, floatTestValue1);
+        test("testFloatSwappedCompareGreaterConstant1", f);
+        test("testFloatSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater() {
+        test("testFloatSwappedCompareGreater", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater1() {
+        test("testFloatSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater2() {
+        test("testFloatSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareGreaterEqual(FieldObject f, float floatValue) {
+        if (f.floatValue >= floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.floatValue >= floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.floatValue >= floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareGreaterEqual", f, floatTestValue1);
+        test("testFloatCompareGreaterEqualConstant1", f);
+        test("testFloatCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual() {
+        test("testFloatCompareGreaterEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual1() {
+        test("testFloatCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual2() {
+        test("testFloatCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqual(FieldObject f, float floatValue) {
+        if (floatValue >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (floatTestValue1 >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (floatTestValue2 >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareGreaterEqual", f, floatTestValue1);
+        test("testFloatSwappedCompareGreaterEqualConstant1", f);
+        test("testFloatSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual() {
+        test("testFloatSwappedCompareGreaterEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual1() {
+        test("testFloatSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual2() {
+        test("testFloatSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongCompare(FieldObject f, long longValue) {
+        if (f.longValue == longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant1(FieldObject f) {
+        if (f.longValue == longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant2(FieldObject f) {
+        if (f.longValue == longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongCompares() {
+        FieldObject f = new FieldObject();
+        test("testLongCompare", f, longTestValue1);
+        test("testLongCompareConstant1", f);
+        test("testLongCompareConstant2", f);
+    }
+
+    @Test
+    public void testLongNullCompares() {
+        test("testLongCompare", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullCompares1() {
+        test("testLongCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullCompares2() {
+        test("testLongCompareConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareLess(FieldObject f, long longValue) {
+        if (f.longValue < longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessConstant1(FieldObject f) {
+        if (f.longValue < longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessConstant2(FieldObject f) {
+        if (f.longValue < longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareLess", f, longTestValue1);
+        test("testLongCompareLessConstant1", f);
+        test("testLongCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesLess() {
+        test("testLongCompareLess", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesLess1() {
+        test("testLongCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesLess2() {
+        test("testLongCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareLess(FieldObject f, long longValue) {
+        if (longValue < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessConstant1(FieldObject f) {
+        if (longTestValue1 < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessConstant2(FieldObject f) {
+        if (longTestValue2 < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareLess", f, longTestValue1);
+        test("testLongSwappedCompareLessConstant1", f);
+        test("testLongSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess() {
+        test("testLongSwappedCompareLess", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess1() {
+        test("testLongSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess2() {
+        test("testLongSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareLessEqual(FieldObject f, long longValue) {
+        if (f.longValue <= longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessEqualConstant1(FieldObject f) {
+        if (f.longValue <= longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessEqualConstant2(FieldObject f) {
+        if (f.longValue <= longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareLessEqual", f, longTestValue1);
+        test("testLongCompareLessEqualConstant1", f);
+        test("testLongCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual() {
+        test("testLongCompareLessEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual1() {
+        test("testLongCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual2() {
+        test("testLongCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareLessEqual(FieldObject f, long longValue) {
+        if (longValue <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (longTestValue1 <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (longTestValue2 <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareLessEqual", f, longTestValue1);
+        test("testLongSwappedCompareLessEqualConstant1", f);
+        test("testLongSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual() {
+        test("testLongSwappedCompareLessEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual1() {
+        test("testLongSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual2() {
+        test("testLongSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareGreater(FieldObject f, long longValue) {
+        if (f.longValue > longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterConstant1(FieldObject f) {
+        if (f.longValue > longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterConstant2(FieldObject f) {
+        if (f.longValue > longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareGreater", f, longTestValue1);
+        test("testLongCompareGreaterConstant1", f);
+        test("testLongCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesGreater() {
+        test("testLongCompareGreater", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesGreater1() {
+        test("testLongCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesGreater2() {
+        test("testLongCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareGreater(FieldObject f, long longValue) {
+        if (longValue > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterConstant1(FieldObject f) {
+        if (longTestValue1 > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterConstant2(FieldObject f) {
+        if (longTestValue2 > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareGreater", f, longTestValue1);
+        test("testLongSwappedCompareGreaterConstant1", f);
+        test("testLongSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater() {
+        test("testLongSwappedCompareGreater", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater1() {
+        test("testLongSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater2() {
+        test("testLongSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareGreaterEqual(FieldObject f, long longValue) {
+        if (f.longValue >= longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.longValue >= longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.longValue >= longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareGreaterEqual", f, longTestValue1);
+        test("testLongCompareGreaterEqualConstant1", f);
+        test("testLongCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual() {
+        test("testLongCompareGreaterEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual1() {
+        test("testLongCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual2() {
+        test("testLongCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareGreaterEqual(FieldObject f, long longValue) {
+        if (longValue >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (longTestValue1 >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (longTestValue2 >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareGreaterEqual", f, longTestValue1);
+        test("testLongSwappedCompareGreaterEqualConstant1", f);
+        test("testLongSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual() {
+        test("testLongSwappedCompareGreaterEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual1() {
+        test("testLongSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual2() {
+        test("testLongSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompare(FieldObject f, double doubleValue) {
+        if (f.doubleValue == doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant1(FieldObject f) {
+        if (f.doubleValue == doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant2(FieldObject f) {
+        if (f.doubleValue == doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleCompares() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompare", f, doubleTestValue1);
+        test("testDoubleCompareConstant1", f);
+        test("testDoubleCompareConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullCompares() {
+        test("testDoubleCompare", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullCompares1() {
+        test("testDoubleCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullCompares2() {
+        test("testDoubleCompareConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareLess(FieldObject f, double doubleValue) {
+        if (f.doubleValue < doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessConstant1(FieldObject f) {
+        if (f.doubleValue < doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessConstant2(FieldObject f) {
+        if (f.doubleValue < doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareLess", f, doubleTestValue1);
+        test("testDoubleCompareLessConstant1", f);
+        test("testDoubleCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess() {
+        test("testDoubleCompareLess", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess1() {
+        test("testDoubleCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess2() {
+        test("testDoubleCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareLess(FieldObject f, double doubleValue) {
+        if (doubleValue < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessConstant1(FieldObject f) {
+        if (doubleTestValue1 < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessConstant2(FieldObject f) {
+        if (doubleTestValue2 < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareLess", f, doubleTestValue1);
+        test("testDoubleSwappedCompareLessConstant1", f);
+        test("testDoubleSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess() {
+        test("testDoubleSwappedCompareLess", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess1() {
+        test("testDoubleSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess2() {
+        test("testDoubleSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareLessEqual(FieldObject f, double doubleValue) {
+        if (f.doubleValue <= doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessEqualConstant1(FieldObject f) {
+        if (f.doubleValue <= doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessEqualConstant2(FieldObject f) {
+        if (f.doubleValue <= doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareLessEqual", f, doubleTestValue1);
+        test("testDoubleCompareLessEqualConstant1", f);
+        test("testDoubleCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual() {
+        test("testDoubleCompareLessEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual1() {
+        test("testDoubleCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual2() {
+        test("testDoubleCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareLessEqual(FieldObject f, double doubleValue) {
+        if (doubleValue <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (doubleTestValue1 <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (doubleTestValue2 <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareLessEqual", f, doubleTestValue1);
+        test("testDoubleSwappedCompareLessEqualConstant1", f);
+        test("testDoubleSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual() {
+        test("testDoubleSwappedCompareLessEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual1() {
+        test("testDoubleSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual2() {
+        test("testDoubleSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareGreater(FieldObject f, double doubleValue) {
+        if (f.doubleValue > doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterConstant1(FieldObject f) {
+        if (f.doubleValue > doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterConstant2(FieldObject f) {
+        if (f.doubleValue > doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareGreater", f, doubleTestValue1);
+        test("testDoubleCompareGreaterConstant1", f);
+        test("testDoubleCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater() {
+        test("testDoubleCompareGreater", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater1() {
+        test("testDoubleCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater2() {
+        test("testDoubleCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareGreater(FieldObject f, double doubleValue) {
+        if (doubleValue > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterConstant1(FieldObject f) {
+        if (doubleTestValue1 > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterConstant2(FieldObject f) {
+        if (doubleTestValue2 > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareGreater", f, doubleTestValue1);
+        test("testDoubleSwappedCompareGreaterConstant1", f);
+        test("testDoubleSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater() {
+        test("testDoubleSwappedCompareGreater", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater1() {
+        test("testDoubleSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater2() {
+        test("testDoubleSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareGreaterEqual(FieldObject f, double doubleValue) {
+        if (f.doubleValue >= doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.doubleValue >= doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.doubleValue >= doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareGreaterEqual", f, doubleTestValue1);
+        test("testDoubleCompareGreaterEqualConstant1", f);
+        test("testDoubleCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual() {
+        test("testDoubleCompareGreaterEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual1() {
+        test("testDoubleCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual2() {
+        test("testDoubleCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqual(FieldObject f, double doubleValue) {
+        if (doubleValue >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (doubleTestValue1 >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (doubleTestValue2 >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareGreaterEqual", f, doubleTestValue1);
+        test("testDoubleSwappedCompareGreaterEqualConstant1", f);
+        test("testDoubleSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual() {
+        test("testDoubleSwappedCompareGreaterEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual1() {
+        test("testDoubleSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual2() {
+        test("testDoubleSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testObjectCompare(FieldObject f, Object objectValue) {
+        if (f.objectValue == objectValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant1(FieldObject f) {
+        if (f.objectValue == objectTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant2(FieldObject f) {
+        if (f.objectValue == objectTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testObjectCompares() {
+        FieldObject f = new FieldObject();
+        test("testObjectCompare", f, objectTestValue1);
+        test("testObjectCompareConstant1", f);
+        test("testObjectCompareConstant2", f);
+    }
+
+    @Test
+    public void testObjectNullCompares() {
+        test("testObjectCompare", null, objectTestValue1);
+    }
+
+    @Test
+    public void testObjectNullCompares1() {
+        test("testObjectCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testObjectNullCompares2() {
+        test("testObjectCompareConstant2", (Object) null);
+    }
+
+    public static int testByteAdd(FieldObject f, byte byteValue) {
+        return f.byteValue + byteValue;
+    }
+
+    public static int testByteAddConstant1(FieldObject f) {
+        return f.byteValue + byteTestValue1;
+    }
+
+    public static int testByteAddConstant2(FieldObject f) {
+        return f.byteValue + byteTestValue2;
+    }
+
+    @Test
+    public void testByteAdds() {
+        FieldObject f = new FieldObject();
+        test("testByteAdd", f, byteTestValue1);
+        test("testByteAddConstant1", f);
+        test("testByteAddConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAdd() {
+        test("testByteAdd", null, byteTestValue1);
+    }
+
+    public static int testShortAdd(FieldObject f, short shortValue) {
+        return f.shortValue + shortValue;
+    }
+
+    public static int testShortAddConstant1(FieldObject f) {
+        return f.shortValue + shortTestValue1;
+    }
+
+    public static int testShortAddConstant2(FieldObject f) {
+        return f.shortValue + shortTestValue2;
+    }
+
+    @Test
+    public void testShortAdds() {
+        FieldObject f = new FieldObject();
+        test("testShortAdd", f, shortTestValue1);
+        test("testShortAddConstant1", f);
+        test("testShortAddConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAdd() {
+        test("testShortAdd", null, shortTestValue1);
+    }
+
+    public static int testCharAdd(FieldObject f, char charValue) {
+        return f.charValue + charValue;
+    }
+
+    public static int testCharAddConstant1(FieldObject f) {
+        return f.charValue + charTestValue1;
+    }
+
+    public static int testCharAddConstant2(FieldObject f) {
+        return f.charValue + charTestValue2;
+    }
+
+    @Test
+    public void testCharAdds() {
+        FieldObject f = new FieldObject();
+        test("testCharAdd", f, charTestValue1);
+        test("testCharAddConstant1", f);
+        test("testCharAddConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAdd() {
+        test("testCharAdd", null, charTestValue1);
+    }
+
+    public static int testIntAdd(FieldObject f, int intValue) {
+        return f.intValue + intValue;
+    }
+
+    public static int testIntAddConstant1(FieldObject f) {
+        return f.intValue + intTestValue1;
+    }
+
+    public static int testIntAddConstant2(FieldObject f) {
+        return f.intValue + intTestValue2;
+    }
+
+    @Test
+    public void testIntAdds() {
+        FieldObject f = new FieldObject();
+        test("testIntAdd", f, intTestValue1);
+        test("testIntAddConstant1", f);
+        test("testIntAddConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAdd() {
+        test("testIntAdd", null, intTestValue1);
+    }
+
+    public static long testLongAdd(FieldObject f, long longValue) {
+        return f.longValue + longValue;
+    }
+
+    public static long testLongAddConstant1(FieldObject f) {
+        return f.longValue + longTestValue1;
+    }
+
+    public static long testLongAddConstant2(FieldObject f) {
+        return f.longValue + longTestValue2;
+    }
+
+    @Test
+    public void testLongAdds() {
+        FieldObject f = new FieldObject();
+        test("testLongAdd", f, longTestValue1);
+        test("testLongAddConstant1", f);
+        test("testLongAddConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAdd() {
+        test("testLongAdd", null, longTestValue1);
+    }
+
+    public static float testFloatAdd(FieldObject f, float floatValue) {
+        return f.floatValue + floatValue;
+    }
+
+    public static float testFloatAddConstant1(FieldObject f) {
+        return f.floatValue + floatTestValue1;
+    }
+
+    public static float testFloatAddConstant2(FieldObject f) {
+        return f.floatValue + floatTestValue2;
+    }
+
+    @Test
+    public void testFloatAdds() {
+        FieldObject f = new FieldObject();
+        test("testFloatAdd", f, floatTestValue1);
+        test("testFloatAddConstant1", f);
+        test("testFloatAddConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullAdd() {
+        test("testFloatAdd", null, floatTestValue1);
+    }
+
+    public static double testDoubleAdd(FieldObject f, double doubleValue) {
+        return f.doubleValue + doubleValue;
+    }
+
+    public static double testDoubleAddConstant1(FieldObject f) {
+        return f.doubleValue + doubleTestValue1;
+    }
+
+    public static double testDoubleAddConstant2(FieldObject f) {
+        return f.doubleValue + doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleAdds() {
+        FieldObject f = new FieldObject();
+        test("testDoubleAdd", f, doubleTestValue1);
+        test("testDoubleAddConstant1", f);
+        test("testDoubleAddConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullAdd() {
+        test("testDoubleAdd", null, doubleTestValue1);
+    }
+
+    public static int testByteSub(FieldObject f, byte byteValue) {
+        return f.byteValue - byteValue;
+    }
+
+    public static int testByteSubConstant1(FieldObject f) {
+        return f.byteValue - byteTestValue1;
+    }
+
+    public static int testByteSubConstant2(FieldObject f) {
+        return f.byteValue - byteTestValue2;
+    }
+
+    @Test
+    public void testByteSubs() {
+        FieldObject f = new FieldObject();
+        test("testByteSub", f, byteTestValue1);
+        test("testByteSubConstant1", f);
+        test("testByteSubConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSub() {
+        test("testByteSub", null, byteTestValue1);
+    }
+
+    public static int testShortSub(FieldObject f, short shortValue) {
+        return f.shortValue - shortValue;
+    }
+
+    public static int testShortSubConstant1(FieldObject f) {
+        return f.shortValue - shortTestValue1;
+    }
+
+    public static int testShortSubConstant2(FieldObject f) {
+        return f.shortValue - shortTestValue2;
+    }
+
+    @Test
+    public void testShortSubs() {
+        FieldObject f = new FieldObject();
+        test("testShortSub", f, shortTestValue1);
+        test("testShortSubConstant1", f);
+        test("testShortSubConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSub() {
+        test("testShortSub", null, shortTestValue1);
+    }
+
+    public static int testCharSub(FieldObject f, char charValue) {
+        return f.charValue - charValue;
+    }
+
+    public static int testCharSubConstant1(FieldObject f) {
+        return f.charValue - charTestValue1;
+    }
+
+    public static int testCharSubConstant2(FieldObject f) {
+        return f.charValue - charTestValue2;
+    }
+
+    @Test
+    public void testCharSubs() {
+        FieldObject f = new FieldObject();
+        test("testCharSub", f, charTestValue1);
+        test("testCharSubConstant1", f);
+        test("testCharSubConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSub() {
+        test("testCharSub", null, charTestValue1);
+    }
+
+    public static int testIntSub(FieldObject f, int intValue) {
+        return f.intValue - intValue;
+    }
+
+    public static int testIntSubConstant1(FieldObject f) {
+        return f.intValue - intTestValue1;
+    }
+
+    public static int testIntSubConstant2(FieldObject f) {
+        return f.intValue - intTestValue2;
+    }
+
+    @Test
+    public void testIntSubs() {
+        FieldObject f = new FieldObject();
+        test("testIntSub", f, intTestValue1);
+        test("testIntSubConstant1", f);
+        test("testIntSubConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSub() {
+        test("testIntSub", null, intTestValue1);
+    }
+
+    public static long testLongSub(FieldObject f, long longValue) {
+        return f.longValue - longValue;
+    }
+
+    public static long testLongSubConstant1(FieldObject f) {
+        return f.longValue - longTestValue1;
+    }
+
+    public static long testLongSubConstant2(FieldObject f) {
+        return f.longValue - longTestValue2;
+    }
+
+    @Test
+    public void testLongSubs() {
+        FieldObject f = new FieldObject();
+        test("testLongSub", f, longTestValue1);
+        test("testLongSubConstant1", f);
+        test("testLongSubConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSub() {
+        test("testLongSub", null, longTestValue1);
+    }
+
+    public static float testFloatSub(FieldObject f, float floatValue) {
+        return f.floatValue - floatValue;
+    }
+
+    public static float testFloatSubConstant1(FieldObject f) {
+        return f.floatValue - floatTestValue1;
+    }
+
+    public static float testFloatSubConstant2(FieldObject f) {
+        return f.floatValue - floatTestValue2;
+    }
+
+    @Test
+    public void testFloatSubs() {
+        FieldObject f = new FieldObject();
+        test("testFloatSub", f, floatTestValue1);
+        test("testFloatSubConstant1", f);
+        test("testFloatSubConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSub() {
+        test("testFloatSub", null, floatTestValue1);
+    }
+
+    public static double testDoubleSub(FieldObject f, double doubleValue) {
+        return f.doubleValue - doubleValue;
+    }
+
+    public static double testDoubleSubConstant1(FieldObject f) {
+        return f.doubleValue - doubleTestValue1;
+    }
+
+    public static double testDoubleSubConstant2(FieldObject f) {
+        return f.doubleValue - doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleSubs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSub", f, doubleTestValue1);
+        test("testDoubleSubConstant1", f);
+        test("testDoubleSubConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSub() {
+        test("testDoubleSub", null, doubleTestValue1);
+    }
+
+    public static int testByteMul(FieldObject f, byte byteValue) {
+        return f.byteValue * byteValue;
+    }
+
+    public static int testByteMulConstant1(FieldObject f) {
+        return f.byteValue * byteTestValue1;
+    }
+
+    public static int testByteMulConstant2(FieldObject f) {
+        return f.byteValue * byteTestValue2;
+    }
+
+    @Test
+    public void testByteMuls() {
+        FieldObject f = new FieldObject();
+        test("testByteMul", f, byteTestValue1);
+        test("testByteMulConstant1", f);
+        test("testByteMulConstant2", f);
+    }
+
+    @Test
+    public void testByteNullMul() {
+        test("testByteMul", null, byteTestValue1);
+    }
+
+    public static int testShortMul(FieldObject f, short shortValue) {
+        return f.shortValue * shortValue;
+    }
+
+    public static int testShortMulConstant1(FieldObject f) {
+        return f.shortValue * shortTestValue1;
+    }
+
+    public static int testShortMulConstant2(FieldObject f) {
+        return f.shortValue * shortTestValue2;
+    }
+
+    @Test
+    public void testShortMuls() {
+        FieldObject f = new FieldObject();
+        test("testShortMul", f, shortTestValue1);
+        test("testShortMulConstant1", f);
+        test("testShortMulConstant2", f);
+    }
+
+    @Test
+    public void testShortNullMul() {
+        test("testShortMul", null, shortTestValue1);
+    }
+
+    public static int testCharMul(FieldObject f, char charValue) {
+        return f.charValue * charValue;
+    }
+
+    public static int testCharMulConstant1(FieldObject f) {
+        return f.charValue * charTestValue1;
+    }
+
+    public static int testCharMulConstant2(FieldObject f) {
+        return f.charValue * charTestValue2;
+    }
+
+    @Test
+    public void testCharMuls() {
+        FieldObject f = new FieldObject();
+        test("testCharMul", f, charTestValue1);
+        test("testCharMulConstant1", f);
+        test("testCharMulConstant2", f);
+    }
+
+    @Test
+    public void testCharNullMul() {
+        test("testCharMul", null, charTestValue1);
+    }
+
+    public static int testIntMul(FieldObject f, int intValue) {
+        return f.intValue * intValue;
+    }
+
+    public static int testIntMulConstant1(FieldObject f) {
+        return f.intValue * intTestValue1;
+    }
+
+    public static int testIntMulConstant2(FieldObject f) {
+        return f.intValue * intTestValue2;
+    }
+
+    @Test
+    public void testIntMuls() {
+        FieldObject f = new FieldObject();
+        test("testIntMul", f, intTestValue1);
+        test("testIntMulConstant1", f);
+        test("testIntMulConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMul() {
+        test("testIntMul", null, intTestValue1);
+    }
+
+    public static long testLongMul(FieldObject f, long longValue) {
+        return f.longValue * longValue;
+    }
+
+    public static long testLongMulConstant1(FieldObject f) {
+        return f.longValue * longTestValue1;
+    }
+
+    public static long testLongMulConstant2(FieldObject f) {
+        return f.longValue * longTestValue2;
+    }
+
+    @Test
+    public void testLongMuls() {
+        FieldObject f = new FieldObject();
+        test("testLongMul", f, longTestValue1);
+        test("testLongMulConstant1", f);
+        test("testLongMulConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMul() {
+        test("testLongMul", null, longTestValue1);
+    }
+
+    public static float testFloatMul(FieldObject f, float floatValue) {
+        return f.floatValue * floatValue;
+    }
+
+    public static float testFloatMulConstant1(FieldObject f) {
+        return f.floatValue * floatTestValue1;
+    }
+
+    public static float testFloatMulConstant2(FieldObject f) {
+        return f.floatValue * floatTestValue2;
+    }
+
+    @Test
+    public void testFloatMuls() {
+        FieldObject f = new FieldObject();
+        test("testFloatMul", f, floatTestValue1);
+        test("testFloatMulConstant1", f);
+        test("testFloatMulConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullMul() {
+        test("testFloatMul", null, floatTestValue1);
+    }
+
+    public static double testDoubleMul(FieldObject f, double doubleValue) {
+        return f.doubleValue * doubleValue;
+    }
+
+    public static double testDoubleMulConstant1(FieldObject f) {
+        return f.doubleValue * doubleTestValue1;
+    }
+
+    public static double testDoubleMulConstant2(FieldObject f) {
+        return f.doubleValue * doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleMuls() {
+        FieldObject f = new FieldObject();
+        test("testDoubleMul", f, doubleTestValue1);
+        test("testDoubleMulConstant1", f);
+        test("testDoubleMulConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullMul() {
+        test("testDoubleMul", null, doubleTestValue1);
+    }
+
+    public static int testByteDiv(FieldObject f, byte byteValue) {
+        return f.byteValue / byteValue;
+    }
+
+    @SuppressWarnings("divzero")
+    public static int testByteDivConstant1(FieldObject f) {
+        return f.byteValue / byteTestValue1;
+    }
+
+    public static int testByteDivConstant2(FieldObject f) {
+        return f.byteValue / byteTestValue2;
+    }
+
+    @Test
+    public void testByteDivs() {
+        FieldObject f = new FieldObject();
+        test("testByteDiv", f, byteTestValue1);
+        test("testByteDivConstant1", f);
+        test("testByteDivConstant2", f);
+    }
+
+    @Test
+    public void testByteNullDiv() {
+        test("testByteDiv", null, byteTestValue1);
+    }
+
+    public static int testShortDiv(FieldObject f, short shortValue) {
+        return f.shortValue / shortValue;
+    }
+
+    @SuppressWarnings("divzero")
+    public static int testShortDivConstant1(FieldObject f) {
+        return f.shortValue / shortTestValue1;
+    }
+
+    public static int testShortDivConstant2(FieldObject f) {
+        return f.shortValue / shortTestValue2;
+    }
+
+    @Test
+    public void testShortDivs() {
+        FieldObject f = new FieldObject();
+        test("testShortDiv", f, shortTestValue1);
+        test("testShortDivConstant1", f);
+        test("testShortDivConstant2", f);
+    }
+
+    @Test
+    public void testShortNullDiv() {
+        test("testShortDiv", null, shortTestValue1);
+    }
+
+    public static int testCharDiv(FieldObject f, char charValue) {
+        return f.charValue / charValue;
+    }
+
+    @SuppressWarnings("divzero")
+    public static int testCharDivConstant1(FieldObject f) {
+        return f.charValue / charTestValue1;
+    }
+
+    public static int testCharDivConstant2(FieldObject f) {
+        return f.charValue / charTestValue2;
+    }
+
+    @Test
+    public void testCharDivs() {
+        FieldObject f = new FieldObject();
+        test("testCharDiv", f, charTestValue1);
+        test("testCharDivConstant1", f);
+        test("testCharDivConstant2", f);
+    }
+
+    @Test
+    public void testCharNullDiv() {
+        test("testCharDiv", null, charTestValue1);
+    }
+
+    public static int testIntDiv(FieldObject f, int intValue) {
+        return f.intValue / intValue;
+    }
+
+    @SuppressWarnings("divzero")
+    public static int testIntDivConstant1(FieldObject f) {
+        return f.intValue / intTestValue1;
+    }
+
+    public static int testIntDivConstant2(FieldObject f) {
+        return f.intValue / intTestValue2;
+    }
+
+    @Test
+    public void testIntDivs() {
+        FieldObject f = new FieldObject();
+        test("testIntDiv", f, intTestValue1);
+        test("testIntDivConstant1", f);
+        test("testIntDivConstant2", f);
+    }
+
+    @Test
+    public void testIntNullDiv() {
+        test("testIntDiv", null, intTestValue1);
+    }
+
+    public static long testLongDiv(FieldObject f, long longValue) {
+        return f.longValue / longValue;
+    }
+
+    @SuppressWarnings("divzero")
+    public static long testLongDivConstant1(FieldObject f) {
+        return f.longValue / longTestValue1;
+    }
+
+    public static long testLongDivConstant2(FieldObject f) {
+        return f.longValue / longTestValue2;
+    }
+
+    @Test
+    public void testLongDivs() {
+        FieldObject f = new FieldObject();
+        test("testLongDiv", f, longTestValue1);
+        test("testLongDivConstant1", f);
+        test("testLongDivConstant2", f);
+    }
+
+    @Test
+    public void testLongNullDiv() {
+        test("testLongDiv", null, longTestValue1);
+    }
+
+    public static float testFloatDiv(FieldObject f, float floatValue) {
+        return f.floatValue / floatValue;
+    }
+
+    public static float testFloatDivConstant1(FieldObject f) {
+        return f.floatValue / floatTestValue1;
+    }
+
+    public static float testFloatDivConstant2(FieldObject f) {
+        return f.floatValue / floatTestValue2;
+    }
+
+    @Test
+    public void testFloatDivs() {
+        FieldObject f = new FieldObject();
+        test("testFloatDiv", f, floatTestValue1);
+        test("testFloatDivConstant1", f);
+        test("testFloatDivConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullDiv() {
+        test("testFloatDiv", null, floatTestValue1);
+    }
+
+    public static double testDoubleDiv(FieldObject f, double doubleValue) {
+        return f.doubleValue / doubleValue;
+    }
+
+    public static double testDoubleDivConstant1(FieldObject f) {
+        return f.doubleValue / doubleTestValue1;
+    }
+
+    public static double testDoubleDivConstant2(FieldObject f) {
+        return f.doubleValue / doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleDivs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleDiv", f, doubleTestValue1);
+        test("testDoubleDivConstant1", f);
+        test("testDoubleDivConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullDiv() {
+        test("testDoubleDiv", null, doubleTestValue1);
+    }
+
+    public static int testByteOr(FieldObject f, byte byteValue) {
+        return f.byteValue | byteValue;
+    }
+
+    public static int testByteOrConstant1(FieldObject f) {
+        return f.byteValue | byteTestValue1;
+    }
+
+    public static int testByteOrConstant2(FieldObject f) {
+        return f.byteValue | byteTestValue2;
+    }
+
+    @Test
+    public void testByteOrs() {
+        FieldObject f = new FieldObject();
+        test("testByteOr", f, byteTestValue1);
+        test("testByteOrConstant1", f);
+        test("testByteOrConstant2", f);
+    }
+
+    @Test
+    public void testByteNullOr() {
+        test("testByteOr", null, byteTestValue1);
+    }
+
+    public static int testShortOr(FieldObject f, short shortValue) {
+        return f.shortValue | shortValue;
+    }
+
+    public static int testShortOrConstant1(FieldObject f) {
+        return f.shortValue | shortTestValue1;
+    }
+
+    public static int testShortOrConstant2(FieldObject f) {
+        return f.shortValue | shortTestValue2;
+    }
+
+    @Test
+    public void testShortOrs() {
+        FieldObject f = new FieldObject();
+        test("testShortOr", f, shortTestValue1);
+        test("testShortOrConstant1", f);
+        test("testShortOrConstant2", f);
+    }
+
+    @Test
+    public void testShortNullOr() {
+        test("testShortOr", null, shortTestValue1);
+    }
+
+    public static int testCharOr(FieldObject f, char charValue) {
+        return f.charValue | charValue;
+    }
+
+    public static int testCharOrConstant1(FieldObject f) {
+        return f.charValue | charTestValue1;
+    }
+
+    public static int testCharOrConstant2(FieldObject f) {
+        return f.charValue | charTestValue2;
+    }
+
+    @Test
+    public void testCharOrs() {
+        FieldObject f = new FieldObject();
+        test("testCharOr", f, charTestValue1);
+        test("testCharOrConstant1", f);
+        test("testCharOrConstant2", f);
+    }
+
+    @Test
+    public void testCharNullOr() {
+        test("testCharOr", null, charTestValue1);
+    }
+
+    public static int testIntOr(FieldObject f, int intValue) {
+        return f.intValue | intValue;
+    }
+
+    public static int testIntOrConstant1(FieldObject f) {
+        return f.intValue | intTestValue1;
+    }
+
+    public static int testIntOrConstant2(FieldObject f) {
+        return f.intValue | intTestValue2;
+    }
+
+    @Test
+    public void testIntOrs() {
+        FieldObject f = new FieldObject();
+        test("testIntOr", f, intTestValue1);
+        test("testIntOrConstant1", f);
+        test("testIntOrConstant2", f);
+    }
+
+    @Test
+    public void testIntNullOr() {
+        test("testIntOr", null, intTestValue1);
+    }
+
+    public static long testLongOr(FieldObject f, long longValue) {
+        return f.longValue | longValue;
+    }
+
+    public static long testLongOrConstant1(FieldObject f) {
+        return f.longValue | longTestValue1;
+    }
+
+    public static long testLongOrConstant2(FieldObject f) {
+        return f.longValue | longTestValue2;
+    }
+
+    @Test
+    public void testLongOrs() {
+        FieldObject f = new FieldObject();
+        test("testLongOr", f, longTestValue1);
+        test("testLongOrConstant1", f);
+        test("testLongOrConstant2", f);
+    }
+
+    @Test
+    public void testLongNullOr() {
+        test("testLongOr", null, longTestValue1);
+    }
+
+    public static int testByteXor(FieldObject f, byte byteValue) {
+        return f.byteValue ^ byteValue;
+    }
+
+    public static int testByteXorConstant1(FieldObject f) {
+        return f.byteValue ^ byteTestValue1;
+    }
+
+    public static int testByteXorConstant2(FieldObject f) {
+        return f.byteValue ^ byteTestValue2;
+    }
+
+    @Test
+    public void testByteXors() {
+        FieldObject f = new FieldObject();
+        test("testByteXor", f, byteTestValue1);
+        test("testByteXorConstant1", f);
+        test("testByteXorConstant2", f);
+    }
+
+    @Test
+    public void testByteNullXor() {
+        test("testByteXor", null, byteTestValue1);
+    }
+
+    public static int testShortXor(FieldObject f, short shortValue) {
+        return f.shortValue ^ shortValue;
+    }
+
+    public static int testShortXorConstant1(FieldObject f) {
+        return f.shortValue ^ shortTestValue1;
+    }
+
+    public static int testShortXorConstant2(FieldObject f) {
+        return f.shortValue ^ shortTestValue2;
+    }
+
+    @Test
+    public void testShortXors() {
+        FieldObject f = new FieldObject();
+        test("testShortXor", f, shortTestValue1);
+        test("testShortXorConstant1", f);
+        test("testShortXorConstant2", f);
+    }
+
+    @Test
+    public void testShortNullXor() {
+        test("testShortXor", null, shortTestValue1);
+    }
+
+    public static int testCharXor(FieldObject f, char charValue) {
+        return f.charValue ^ charValue;
+    }
+
+    public static int testCharXorConstant1(FieldObject f) {
+        return f.charValue ^ charTestValue1;
+    }
+
+    public static int testCharXorConstant2(FieldObject f) {
+        return f.charValue ^ charTestValue2;
+    }
+
+    @Test
+    public void testCharXors() {
+        FieldObject f = new FieldObject();
+        test("testCharXor", f, charTestValue1);
+        test("testCharXorConstant1", f);
+        test("testCharXorConstant2", f);
+    }
+
+    @Test
+    public void testCharNullXor() {
+        test("testCharXor", null, charTestValue1);
+    }
+
+    public static int testIntXor(FieldObject f, int intValue) {
+        return f.intValue ^ intValue;
+    }
+
+    public static int testIntXorConstant1(FieldObject f) {
+        return f.intValue ^ intTestValue1;
+    }
+
+    public static int testIntXorConstant2(FieldObject f) {
+        return f.intValue ^ intTestValue2;
+    }
+
+    @Test
+    public void testIntXors() {
+        FieldObject f = new FieldObject();
+        test("testIntXor", f, intTestValue1);
+        test("testIntXorConstant1", f);
+        test("testIntXorConstant2", f);
+    }
+
+    @Test
+    public void testIntNullXor() {
+        test("testIntXor", null, intTestValue1);
+    }
+
+    public static long testLongXor(FieldObject f, long longValue) {
+        return f.longValue ^ longValue;
+    }
+
+    public static long testLongXorConstant1(FieldObject f) {
+        return f.longValue ^ longTestValue1;
+    }
+
+    public static long testLongXorConstant2(FieldObject f) {
+        return f.longValue ^ longTestValue2;
+    }
+
+    @Test
+    public void testLongXors() {
+        FieldObject f = new FieldObject();
+        test("testLongXor", f, longTestValue1);
+        test("testLongXorConstant1", f);
+        test("testLongXorConstant2", f);
+    }
+
+    @Test
+    public void testLongNullXor() {
+        test("testLongXor", null, longTestValue1);
+    }
+
+    public static int testByteAnd(FieldObject f, byte byteValue) {
+        return f.byteValue & byteValue;
+    }
+
+    public static int testByteAndConstant1(FieldObject f) {
+        return f.byteValue & byteTestValue1;
+    }
+
+    public static int testByteAndConstant2(FieldObject f) {
+        return f.byteValue & byteTestValue2;
+    }
+
+    @Test
+    public void testByteAnds() {
+        FieldObject f = new FieldObject();
+        test("testByteAnd", f, byteTestValue1);
+        test("testByteAndConstant1", f);
+        test("testByteAndConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAnd() {
+        test("testByteAnd", null, byteTestValue1);
+    }
+
+    public static int testShortAnd(FieldObject f, short shortValue) {
+        return f.shortValue & shortValue;
+    }
+
+    public static int testShortAndConstant1(FieldObject f) {
+        return f.shortValue & shortTestValue1;
+    }
+
+    public static int testShortAndConstant2(FieldObject f) {
+        return f.shortValue & shortTestValue2;
+    }
+
+    @Test
+    public void testShortAnds() {
+        FieldObject f = new FieldObject();
+        test("testShortAnd", f, shortTestValue1);
+        test("testShortAndConstant1", f);
+        test("testShortAndConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAnd() {
+        test("testShortAnd", null, shortTestValue1);
+    }
+
+    public static int testCharAnd(FieldObject f, char charValue) {
+        return f.charValue & charValue;
+    }
+
+    public static int testCharAndConstant1(FieldObject f) {
+        return f.charValue & charTestValue1;
+    }
+
+    public static int testCharAndConstant2(FieldObject f) {
+        return f.charValue & charTestValue2;
+    }
+
+    @Test
+    public void testCharAnds() {
+        FieldObject f = new FieldObject();
+        test("testCharAnd", f, charTestValue1);
+        test("testCharAndConstant1", f);
+        test("testCharAndConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAnd() {
+        test("testCharAnd", null, charTestValue1);
+    }
+
+    public static int testIntAnd(FieldObject f, int intValue) {
+        return f.intValue & intValue;
+    }
+
+    public static int testIntAndConstant1(FieldObject f) {
+        return f.intValue & intTestValue1;
+    }
+
+    public static int testIntAndConstant2(FieldObject f) {
+        return f.intValue & intTestValue2;
+    }
+
+    @Test
+    public void testIntAnds() {
+        FieldObject f = new FieldObject();
+        test("testIntAnd", f, intTestValue1);
+        test("testIntAndConstant1", f);
+        test("testIntAndConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAnd() {
+        test("testIntAnd", null, intTestValue1);
+    }
+
+    public static long testLongAnd(FieldObject f, long longValue) {
+        return f.longValue & longValue;
+    }
+
+    public static long testLongAndConstant1(FieldObject f) {
+        return f.longValue & longTestValue1;
+    }
+
+    public static long testLongAndConstant2(FieldObject f) {
+        return f.longValue & longTestValue2;
+    }
+
+    @Test
+    public void testLongAnds() {
+        FieldObject f = new FieldObject();
+        test("testLongAnd", f, longTestValue1);
+        test("testLongAndConstant1", f);
+        test("testLongAndConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAnd() {
+        test("testLongAnd", null, longTestValue1);
+    }
+
+    public static boolean testIntMask(FieldObject f, int intValue) {
+        if ((f.intValue & intValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testIntMaskConstant1(FieldObject f) {
+        return (f.intValue & intTestValue1) != 0;
+    }
+
+    public static boolean testIntMaskConstant2(FieldObject f) {
+        return (f.intValue & intTestValue2) != 0;
+    }
+
+    @Test
+    public void testIntMasks() {
+        FieldObject f = new FieldObject();
+        test("testIntMask", f, intTestValue1);
+        test("testIntMaskConstant1", f);
+        test("testIntMaskConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMask() {
+        test("testIntMask", null, intTestValue1);
+    }
+
+    public static boolean testLongMask(FieldObject f, long longValue) {
+        if ((f.longValue & longValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testLongMaskConstant1(FieldObject f) {
+        return (f.longValue & longTestValue1) != 0;
+    }
+
+    public static boolean testLongMaskConstant2(FieldObject f) {
+        return (f.longValue & longTestValue2) != 0;
+    }
+
+    @Test
+    public void testLongMasks() {
+        FieldObject f = new FieldObject();
+        test("testLongMask", f, longTestValue1);
+        test("testLongMaskConstant1", f);
+        test("testLongMaskConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMask() {
+        test("testLongMask", null, longTestValue1);
+    }
+
+    public static int doConvertByteInt(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteInt() {
+        test("doConvertByteInt", maxObject);
+        test("doConvertByteInt", (FieldObject) null);
+    }
+
+    public static int doConvertShortInt(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortInt() {
+        test("doConvertShortInt", maxObject);
+        test("doConvertShortInt", (FieldObject) null);
+    }
+
+    public static int doConvertCharInt(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharInt() {
+        test("doConvertCharInt", maxObject);
+        test("doConvertCharInt", (FieldObject) null);
+    }
+
+    public static int doConvertLongInt(FieldObject f) {
+        return (int) f.longValue;
+    }
+
+    @Test
+    public void testConvertLongInt() {
+        test("doConvertLongInt", maxObject);
+        test("doConvertLongInt", (FieldObject) null);
+    }
+
+    public static int doConvertFloatInt(FieldObject f) {
+        return (int) f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatInt() {
+        test("doConvertFloatInt", maxObject);
+        test("doConvertFloatInt", (FieldObject) null);
+    }
+
+    public static int doConvertDoubleInt(FieldObject f) {
+        return (int) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleInt() {
+        test("doConvertDoubleInt", maxObject);
+        test("doConvertDoubleInt", (FieldObject) null);
+    }
+
+    public static long doConvertByteLong(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteLong() {
+        test("doConvertByteLong", maxObject);
+        test("doConvertByteLong", (FieldObject) null);
+    }
+
+    public static long doConvertShortLong(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortLong() {
+        test("doConvertShortLong", maxObject);
+        test("doConvertShortLong", (FieldObject) null);
+    }
+
+    public static long doConvertCharLong(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharLong() {
+        test("doConvertCharLong", maxObject);
+        test("doConvertCharLong", (FieldObject) null);
+    }
+
+    public static long doConvertIntLong(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntLong() {
+        test("doConvertIntLong", maxObject);
+        test("doConvertIntLong", (FieldObject) null);
+    }
+
+    public static long doConvertFloatLong(FieldObject f) {
+        return (long) f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatLong() {
+        test("doConvertFloatLong", maxObject);
+        test("doConvertFloatLong", (FieldObject) null);
+    }
+
+    public static long doConvertDoubleLong(FieldObject f) {
+        return (long) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleLong() {
+        test("doConvertDoubleLong", maxObject);
+        test("doConvertDoubleLong", (FieldObject) null);
+    }
+
+    public static float doConvertByteFloat(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteFloat() {
+        test("doConvertByteFloat", maxObject);
+        test("doConvertByteFloat", (FieldObject) null);
+    }
+
+    public static float doConvertShortFloat(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortFloat() {
+        test("doConvertShortFloat", maxObject);
+        test("doConvertShortFloat", (FieldObject) null);
+    }
+
+    public static float doConvertCharFloat(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharFloat() {
+        test("doConvertCharFloat", maxObject);
+        test("doConvertCharFloat", (FieldObject) null);
+    }
+
+    public static float doConvertIntFloat(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntFloat() {
+        test("doConvertIntFloat", maxObject);
+        test("doConvertIntFloat", (FieldObject) null);
+    }
+
+    public static float doConvertLongFloat(FieldObject f) {
+        return f.longValue;
+    }
+
+    @Test
+    public void testConvertLongFloat() {
+        test("doConvertLongFloat", maxObject);
+        test("doConvertLongFloat", (FieldObject) null);
+    }
+
+    public static float doConvertDoubleFloat(FieldObject f) {
+        return (float) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleFloat() {
+        test("doConvertDoubleFloat", maxObject);
+        test("doConvertDoubleFloat", (FieldObject) null);
+    }
+
+    public static double doConvertByteDouble(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteDouble() {
+        test("doConvertByteDouble", maxObject);
+        test("doConvertByteDouble", (FieldObject) null);
+    }
+
+    public static double doConvertShortDouble(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortDouble() {
+        test("doConvertShortDouble", maxObject);
+        test("doConvertShortDouble", (FieldObject) null);
+    }
+
+    public static double doConvertCharDouble(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharDouble() {
+        test("doConvertCharDouble", maxObject);
+        test("doConvertCharDouble", (FieldObject) null);
+    }
+
+    public static double doConvertIntDouble(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntDouble() {
+        test("doConvertIntDouble", maxObject);
+        test("doConvertIntDouble", (FieldObject) null);
+    }
+
+    public static double doConvertLongDouble(FieldObject f) {
+        return f.longValue;
+    }
+
+    @Test
+    public void testConvertLongDouble() {
+        test("doConvertLongDouble", maxObject);
+        test("doConvertLongDouble", (FieldObject) null);
+    }
+
+    public static double doConvertFloatDouble(FieldObject f) {
+        return f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatDouble() {
+        test("doConvertFloatDouble", maxObject);
+        test("doConvertFloatDouble", (FieldObject) null);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java
new file mode 100644
index 0000000..398fc13
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks;
+import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+/**
+ * In these test the FrameStates are explicitly cleared out, so that the scheduling of
+ * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
+ * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
+ * right thing.
+ *
+ * The scheduling shouldn't depend on FrameStates, which is tested by this class.
+ */
+public class MemoryScheduleTest extends GraphScheduleTest {
+
+    private enum TestMode {
+        WITH_FRAMESTATES,
+        WITHOUT_FRAMESTATES,
+        INLINED_WITHOUT_FRAMESTATES
+    }
+
+    public static class Container {
+
+        public int a;
+        public int b;
+        public int c;
+
+        public Object obj;
+    }
+
+    private static final Container container = new Container();
+    private static final List<Container> containerList = new ArrayList<>();
+
+    /**
+     * In this test the read should be scheduled before the write.
+     */
+    public static int testSimpleSnippet() {
+        try {
+            return container.a;
+        } finally {
+            container.a = 15;
+        }
+    }
+
+    @Test
+    public void testSimple() {
+        for (TestMode mode : TestMode.values()) {
+            ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode);
+            StructuredGraph graph = schedule.getCFG().graph;
+            assertReadAndWriteInSameBlock(schedule, true);
+            assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first());
+        }
+    }
+
+    /**
+     * In this case the read should be scheduled in the first block.
+     */
+    public static int testSplit1Snippet(int a) {
+        try {
+            return container.a;
+        } finally {
+            if (a < 0) {
+                container.a = 15;
+            } else {
+                container.b = 15;
+            }
+        }
+    }
+
+    @Test
+    public void testSplit1() {
+        for (TestMode mode : TestMode.values()) {
+            ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode);
+            assertReadWithinStartBlock(schedule, true);
+            assertReadWithinAllReturnBlocks(schedule, false);
+        }
+    }
+
+    /**
+     * Here the read should float to the end.
+     */
+    public static int testSplit2Snippet(int a) {
+        try {
+            return container.a;
+        } finally {
+            if (a < 0) {
+                container.c = 15;
+            } else {
+                container.b = 15;
+            }
+            container.obj = null;
+        }
+    }
+
+    @Test
+    public void testSplit2() {
+        ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, true);
+    }
+
+    /**
+     * Here the read should not float to the end.
+     */
+    public static int testLoop1Snippet(int a, int b) {
+        try {
+            return container.a;
+        } finally {
+            for (int i = 0; i < a; i++) {
+                if (b < 0) {
+                    container.b = 10;
+                } else {
+                    container.a = 15;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testLoop1() {
+        ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should float to the end.
+     */
+    public static int testLoop2Snippet(int a, int b) {
+        try {
+            return container.a;
+        } finally {
+            for (int i = 0; i < a; i++) {
+                if (b < 0) {
+                    container.b = 10;
+                } else {
+                    container.c = 15;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testLoop2() {
+        ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, true);
+    }
+
+    /**
+     * Here the read should float out of the loop.
+     */
+    public static int testLoop3Snippet(int a) {
+        int j = 0;
+        for (int i = 0; i < a; i++) {
+            if (i - container.a == 0) {
+                break;
+            }
+            j++;
+        }
+        return j;
+    }
+
+    @Test
+    public void testLoop3() {
+        ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    public String testStringReplaceSnippet(String input) {
+        return input.replace('a', 'b');
+    }
+
+    @Test
+    public void testStringReplace() {
+        getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
+        test("testStringReplaceSnippet", "acbaaa");
+    }
+
+    /**
+     * Here the read should float out of the loop.
+     */
+    public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop5() {
+        ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(10, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should not float out of the loop.
+     */
+    public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+                for (int j = 0; j < b; ++j) {
+                    obj.hash = 3;
+                }
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop6() {
+        ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(13, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should not float out of the loop.
+     */
+    public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+                for (int k = 0; k < a; ++k) {
+                    if (k % 2 == 1) {
+                        for (int j = 0; j < b; ++j) {
+                            obj.hash = 3;
+                        }
+                    }
+                }
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop7() {
+        ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(18, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should not float to the end.
+     */
+    public static int testLoop8Snippet(int a, int b) {
+        int result = container.a;
+        for (int i = 0; i < a; i++) {
+            if (b < 0) {
+                container.b = 10;
+                break;
+            } else {
+                for (int j = 0; j < b; j++) {
+                    container.a = 0;
+                }
+            }
+        }
+        GraalDirectives.controlFlowAnchor();
+        return result;
+    }
+
+    @Test
+    public void testLoop8() {
+        ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(10, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should float after the loop.
+     */
+    public static int testLoop9Snippet(int a, int b) {
+        container.a = b;
+        for (int i = 0; i < a; i++) {
+            container.a = i;
+        }
+        GraalDirectives.controlFlowAnchor();
+        return container.a;
+    }
+
+    @Test
+    public void testLoop9() {
+        ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES);
+        StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
+        assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1));
+        ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
+        assertThat(ret.result(), instanceOf(FloatingReadNode.class));
+        Block readBlock = schedule.getNodeToBlockMap().get(ret.result());
+        Assert.assertEquals(0, readBlock.getLoopDepth());
+    }
+
+    /**
+     * Here the read should float to the end (into the same block as the return).
+     */
+    public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) {
+        System.arraycopy(a, 0, b, 0, len);
+        return intValue.intValue();
+    }
+
+    @Test
+    public void testArrayCopy() {
+        ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
+        StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
+        assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
+        assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
+        assertReadWithinAllReturnBlocks(schedule, true);
+    }
+
+    /**
+     * Here the read should not float to the end.
+     */
+    public static int testIfRead1Snippet(int a) {
+        int res = container.a;
+        if (a < 0) {
+            container.a = 10;
+        }
+        return res;
+    }
+
+    @Test
+    public void testIfRead1() {
+        ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, true);
+        assertReadAndWriteInSameBlock(schedule, false);
+    }
+
+    /**
+     * Here the read should float in the else block.
+     */
+    public static int testIfRead2Snippet(int a) {
+        int res = 0;
+        if (a < 0) {
+            container.a = 10;
+        } else {
+            res = container.a;
+        }
+        return res;
+    }
+
+    @Test
+    public void testIfRead2() {
+        ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+        assertReadAndWriteInSameBlock(schedule, false);
+    }
+
+    /**
+     * Here the read should float to the end, right before the write.
+     */
+    public static int testIfRead3Snippet(int a) {
+        if (a < 0) {
+            container.a = 10;
+        }
+        int res = container.a;
+        container.a = 20;
+        return res;
+    }
+
+    @Test
+    public void testIfRead3() {
+        ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, true);
+    }
+
+    /**
+     * Here the read should be just in the if branch (with the write).
+     */
+    public static int testIfRead4Snippet(int a) {
+        if (a > 0) {
+            int res = container.a;
+            container.a = 0x20;
+            return res;
+        } else {
+            return 0x10;
+        }
+    }
+
+    @Test
+    public void testIfRead4() {
+        ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+        assertReadAndWriteInSameBlock(schedule, true);
+    }
+
+    /**
+     * Here the read should float to the end.
+     */
+    public static int testIfRead5Snippet(int a) {
+        if (a < 0) {
+            container.a = 10;
+        }
+        return container.a;
+    }
+
+    @Test
+    public void testIfRead5() {
+        ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, true);
+        assertReadAndWriteInSameBlock(schedule, false);
+    }
+
+    public static int testAntiDependencySnippet(int a) {
+        /*
+         * This read must not be scheduled after the following write.
+         */
+        int res = container.a;
+        container.a = 10;
+
+        /*
+         * Add some more basic blocks.
+         */
+        if (a < 0) {
+            container.b = 20;
+        }
+        container.c = 30;
+        return res;
+    }
+
+    @Test
+    public void testAntiDependency() {
+        ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
+        assertReadBeforeAllWritesInStartBlock(schedule);
+    }
+
+    /**
+     * testing scheduling within a block.
+     */
+    public static int testBlockScheduleSnippet() {
+        int res = 0;
+        container.a = 0x00;
+        container.a = 0x10;
+        container.a = 0x20;
+        container.a = 0x30;
+        container.a = 0x40;
+        res = container.a;
+        container.a = 0x50;
+        container.a = 0x60;
+        container.a = 0x70;
+        return res;
+    }
+
+    @Test
+    public void testBlockSchedule() {
+        ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
+        StructuredGraph graph = schedule.getCFG().graph;
+        NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
+
+        assertDeepEquals(1, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(8, writeNodes.count());
+        assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
+
+        FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
+
+        WriteNode[] writes = new WriteNode[8];
+        int i = 0;
+        for (WriteNode n : writeNodes) {
+            writes[i] = n;
+            i++;
+        }
+        assertOrderedAfterSchedule(schedule, writes[4], read);
+        assertOrderedAfterSchedule(schedule, read, writes[5]);
+        for (int j = 0; j < 7; j++) {
+            assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]);
+        }
+    }
+
+    /**
+     * read should move inside the loop (out of loop is disabled).
+     */
+    public static int testBlockSchedule2Snippet(int value) {
+        int res = 0;
+
+        container.a = value;
+        for (int i = 0; i < 100; i++) {
+            if (i == 10) {
+                return container.a;
+            }
+            res += i;
+        }
+        return res;
+    }
+
+    @Test
+    public void testBlockSchedule2() {
+        ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+        assertReadAndWriteInSameBlock(schedule, false);
+    }
+
+    public static void testProxySnippet() {
+        while (container.a < container.b) {
+            List<Container> list = new ArrayList<>(containerList);
+            while (container.c < list.size()) {
+                if (container.obj != null) {
+                    return;
+                }
+                container.c++;
+            }
+            container.a = 0;
+            container.b--;
+        }
+        container.b++;
+    }
+
+    @Test
+    public void testProxy() {
+        ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    private int hash = 0;
+    private final char[] value = new char[3];
+
+    public int testStringHashCodeSnippet() {
+        int h = hash;
+        if (h == 0 && value.length > 0) {
+            char[] val = value;
+
+            for (int i = 0; i < value.length; i++) {
+                h = 31 * h + val[i];
+            }
+            hash = h;
+        }
+        return h;
+    }
+
+    @Test
+    public void testStringHashCode() {
+        ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
+        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinAllReturnBlocks(schedule, false);
+
+        hash = 0x1337;
+        value[0] = 'a';
+        value[1] = 'b';
+        value[2] = 'c';
+        test("testStringHashCodeSnippet");
+    }
+
+    public static int testLoop4Snippet(int count) {
+        int[] a = new int[count];
+
+        for (int i = 0; i < a.length; i++) {
+            a[i] = i;
+        }
+
+        int i = 0;
+        int iwrap = count - 1;
+        int sum = 0;
+
+        while (i < count) {
+            sum += (a[i] + a[iwrap]) / 2;
+            iwrap = i;
+            i++;
+        }
+        return sum;
+    }
+
+    @Test
+    public void testLoop4() {
+        ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) {
+        StructuredGraph graph = schedule.getCFG().graph;
+        assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty());
+
+        int withRead = 0;
+        int returnBlocks = 0;
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
+            Block block = schedule.getCFG().getNodeToBlock().get(returnNode);
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+                if (node instanceof FloatingReadNode) {
+                    withRead++;
+                    break;
+                }
+            }
+            returnBlocks++;
+        }
+        assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
+    }
+
+    private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) {
+        boolean readEncountered = false;
+        for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
+            if (node instanceof FloatingReadNode) {
+                readEncountered = true;
+            }
+        }
+        assertDeepEquals(withinStartBlock, readEncountered);
+    }
+
+    private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) {
+        StructuredGraph graph = schedule.getCFG().graph;
+        FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
+        WriteNode write = graph.getNodes().filter(WriteNode.class).first();
+        assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
+    }
+
+    private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) {
+        boolean writeNodeFound = false;
+        boolean readNodeFound = false;
+        for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
+            if (node instanceof FloatingReadNode) {
+                assertTrue(!writeNodeFound);
+                readNodeFound = true;
+            } else if (node instanceof WriteNode) {
+                writeNodeFound = true;
+            }
+        }
+        assertTrue(readNodeFound);
+    }
+
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) {
+        return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS);
+    }
+
+    @SuppressWarnings("try")
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        try (Scope d = Debug.scope("FloatingReadTest", graph)) {
+            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
+                HighTierContext context = getDefaultHighTierContext();
+                CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+                canonicalizer.apply(graph, context);
+                if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    new InliningPhase(canonicalizer).apply(graph, context);
+                }
+                new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+                if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    graph.clearAllStateAfter();
+                }
+                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates");
+
+                new FloatingReadPhase().apply(graph);
+                new RemoveValueProxyPhase().apply(graph);
+
+                MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+                new GuardLoweringPhase().apply(graph, midContext);
+                new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+                new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext);
+
+                SchedulePhase schedule = new SchedulePhase(schedulingStrategy);
+                schedule.apply(graph);
+                assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
+                return graph.getLastSchedule();
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java
new file mode 100644
index 0000000..15a682d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class MergeCanonicalizerTest extends GraalCompilerTest {
+
+    public static int staticField;
+
+    private int field;
+
+    @Test
+    public void testSplitReturn() {
+        test("testSplitReturnSnippet", 2);
+        testReturnCount("testSplitReturnSnippet", 2);
+    }
+
+    public int testSplitReturnSnippet(int b) {
+        int v;
+        if (b < 0) {
+            staticField = 1;
+            v = 10;
+        } else {
+            staticField = 2;
+            v = 20;
+        }
+        int i = field;
+        i = field + i;
+        return v;
+    }
+
+    private void testReturnCount(String snippet, int returnCount) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java
new file mode 100644
index 0000000..4582273
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+public final class MethodHandleEagerResolution extends GraalCompilerTest {
+    private static final MethodHandle FIELD_HANDLE;
+
+    static {
+        Field field;
+        try {
+            field = String.class.getDeclaredField("value");
+        } catch (NoSuchFieldException ex) {
+            throw new RuntimeException(ex.getMessage(), ex);
+        }
+        field.setAccessible(true);
+
+        try {
+            FIELD_HANDLE = MethodHandles.lookup().unreflectGetter(field);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException("unable to initialize field handle", e);
+        }
+    }
+
+    public static char[] getBackingCharArray(String str) {
+        try {
+            return (char[]) FIELD_HANDLE.invokeExact(str);
+        } catch (Throwable e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    @Test
+    public void testFieldInvokeExact() {
+        StructuredGraph graph = parseEager("getBackingCharArray", AllowAssumptions.NO);
+        assertTrue(graph.getNodes().filter(DeoptimizeNode.class).isEmpty());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java
new file mode 100644
index 0000000..11188b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+/**
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant
+ * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the
+ * graph of the method that just has a "return 1" statement in it.
+ */
+public class MonitorGraphTest extends GraalCompilerTest {
+
+    private static final String REFERENCE_SNIPPET = "referenceSnippet";
+
+    @SuppressWarnings("all")
+    public static synchronized int referenceSnippet(int a) {
+        return 1;
+    }
+
+    public static int const1() {
+        return 1;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("all")
+    public static synchronized int test1Snippet(int a) {
+        return const1();
+    }
+
+    @Test
+    public void test2() {
+        StructuredGraph graph = parseAndProcess("test2Snippet");
+        NodeIterable<MonitorExitNode> monitors = graph.getNodes(MonitorExitNode.TYPE);
+        Assert.assertEquals(1, monitors.count());
+        Assert.assertEquals(monitors.first().stateAfter().bci, 3);
+    }
+
+    @SuppressWarnings("all")
+    public static int test2Snippet(int a) {
+        return const2();
+    }
+
+    public static synchronized int const2() {
+        return 1;
+    }
+
+    private StructuredGraph parseAndProcess(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        ParameterNode param = graph.getNodes(ParameterNode.TYPE).first();
+        if (param != null) {
+            ConstantNode constant = ConstantNode.forInt(0, graph);
+            for (Node n : param.usages().snapshot()) {
+                if (!(n instanceof FrameState)) {
+                    n.replaceFirstInput(param, constant);
+                }
+            }
+        }
+        Map<Invoke, Double> hints = new HashMap<>();
+        for (Invoke invoke : graph.getInvokes()) {
+            hints.put(invoke, 1000d);
+        }
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, context);
+        new DeadCodeEliminationPhase().apply(graph);
+        return graph;
+    }
+
+    private void test(String snippet) {
+        StructuredGraph graph = parseAndProcess(snippet);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO);
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java
new file mode 100644
index 0000000..543bb44
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+
+public class NestedLoopTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet", 1, 2, 2);
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", 1, 2, 2);
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet", 1, 2, 2);
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", 1, 3, 2);
+    }
+
+    @SuppressWarnings("all")
+    public static void test1Snippet(int a) {
+        while (a()) { // a() exits root, while() exits root
+            m1: while (b()) { // b() exits nested & root, while() exits nested
+                while (c()) { // c() exits innermost & nested & root, while() exits innermost
+                    if (d()) { // d() exits innermost & nested & root
+                        break m1; // break exits innermost & nested
+                    }
+                }
+            }
+        }
+    }// total : root = 5 exits, nested = 5, innermost = 4
+
+    @SuppressWarnings("all")
+    public static void test2Snippet(int a) {
+        while (a()) { // a() exits root, while() exits root
+            try {
+                m1: while (b()) { // b() exits nested, while() exits nested
+                    while (c()) { // c() exits innermost & nested, while() exits innermost
+                        if (d()) { // d() exits innermost & nested
+                            break m1; // break exits innermost & nested
+                        }
+                    }
+                }
+            } catch (Throwable t) {
+            }
+        }
+    }// total : root = 2 exits, nested = 5, innermost = 4
+
+    @SuppressWarnings("all")
+    public static void test3Snippet(int a) {
+        while (a == 0) { // while() exits root
+            try {
+                m1: while (b()) { // b() exits nested, while() exits nested
+                    while (c()) { // c() exits innermost & nested, while() exits innermost
+                        if (d()) { // d() exits innermost & nested
+                            a(); // a() exits nothing (already outside innermost & nested)
+                            break m1; // break exits innermost & nested
+                        }
+                    }
+                }
+            } catch (Throwable t) {
+            }
+        }
+    }// total : root = 1 exit, nested = 5, innermost = 4
+
+    public static void test4Snippet(int a) {
+        while (a != 0) { // while() exits root
+            try {
+                m1: while (a != 0) { // while() exits nested
+                    b(); // b() exits nested
+                    while (c()) { // c() exits innermost & nested, while() exits innermost
+                        if (d()) { // d() exits innermost & nested
+                            break m1; // break exits innermost & nested
+                        }
+                    }
+                    if (a != 2) {
+                        a(); // a() exits nothing (already outside innermost & nested)
+                        throw new Exception(); // throw exits nested
+                    }
+                }
+            } catch (Throwable t) {
+            }
+        }
+    } // total : root = 1 exit, nested = 6, innermost = 4
+
+    private static native boolean a();
+
+    private static native boolean b();
+
+    private static native boolean c();
+
+    private static native boolean d();
+
+    private static Invoke getInvoke(String name, StructuredGraph graph) {
+        for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            if (callTarget.targetMethod().getName().equals(name)) {
+                return callTarget.invoke();
+            }
+        }
+        return null;
+    }
+
+    private void test(String snippet, int rootExits, int nestedExits, int innerExits) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+
+        Assert.assertEquals(3, cfg.getLoops().size());
+        Loop<Block> rootLoop = cfg.getLoops().get(0);
+        Loop<Block> nestedLoop = cfg.getLoops().get(1);
+        Loop<Block> innerMostLoop = cfg.getLoops().get(2);
+        Invoke a = getInvoke("a", graph);
+        Invoke b = getInvoke("b", graph);
+        Invoke c = getInvoke("c", graph);
+        Invoke d = getInvoke("d", graph);
+        Assert.assertTrue(containsDirect(rootLoop, a, cfg));
+        Assert.assertTrue(containsDirect(nestedLoop, b, cfg));
+        Assert.assertTrue(containsDirect(innerMostLoop, c, cfg));
+        Assert.assertTrue(containsDirect(innerMostLoop, d, cfg));
+        Assert.assertTrue(contains(rootLoop, d, cfg));
+        Assert.assertTrue(contains(nestedLoop, d, cfg));
+        Assert.assertEquals(rootExits, rootLoop.getExits().size());
+        Assert.assertEquals(nestedExits, nestedLoop.getExits().size());
+        Assert.assertEquals(innerExits, innerMostLoop.getExits().size());
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+    }
+
+    private static boolean contains(Loop<Block> loop, Invoke node, ControlFlowGraph cfg) {
+        Block block = cfg.blockFor((Node) node);
+        Assert.assertNotNull(block);
+        return loop.getBlocks().contains(block);
+    }
+
+    private static boolean containsDirect(Loop<Block> loop, Invoke node, ControlFlowGraph cfg) {
+        for (Loop<Block> child : loop.getChildren()) {
+            if (contains(child, node, cfg)) {
+                return false;
+            }
+        }
+        return contains(loop, node, cfg);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePosIteratorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePosIteratorTest.java
new file mode 100644
index 0000000..d4b74dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePosIteratorTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.Iterator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeSuccessorList;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+public class NodePosIteratorTest extends GraalCompilerTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+        @Successor Node s1;
+        @Successor Node s2;
+        @Successor NodeSuccessorList<Node> stail;
+
+        @Input NodeInputList<ValueNode> itail;
+        @Input ConstantNode i1;
+        @Input FloatingNode i2;
+
+        protected TestNode() {
+            super(TYPE);
+        }
+
+    }
+
+    @Test
+    public void testInputs() {
+        TestNode n = new TestNode();
+
+        ConstantNode i1 = ConstantNode.forInt(1);
+        ConstantNode i2 = ConstantNode.forDouble(1.0d);
+        ConstantNode i3 = ConstantNode.forInt(4);
+        ConstantNode i4 = ConstantNode.forInt(14);
+        n.itail = new NodeInputList<>(n, new ValueNode[]{i3, i4});
+        n.i1 = i1;
+        n.i2 = i2;
+
+        NodeIterable<Node> inputs = n.inputs();
+
+        Iterator<Node> iterator = inputs.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        Iterator<Position> positionIterator = n.inputPositions().iterator();
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals("ConstantNode:i1", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals("FloatingNode:i2", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals("NodeInputList:itail[0]", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals("NodeInputList:itail[1]", positionIterator.next().toString());
+        Assert.assertFalse(positionIterator.hasNext());
+        Assert.assertFalse(positionIterator.hasNext());
+
+        iterator = inputs.iterator();
+        n.i1 = i4;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        n.i2 = i1;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i3);
+        n.itail.initialize(1, i4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = inputs.iterator();
+        n.i1 = null;
+        n.i2 = i2;
+        n.itail.initialize(0, null);
+        n.itail.initialize(1, i4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testSuccessors() {
+        TestNode n = new TestNode();
+        EndNode s1 = new EndNode();
+        EndNode s2 = new EndNode();
+        EndNode s3 = new EndNode();
+        EndNode s4 = new EndNode();
+        n.s1 = s1;
+        n.s2 = s2;
+        n.stail = new NodeSuccessorList<>(n, new Node[]{s3, s4});
+
+        NodeIterable<Node> successors = n.successors();
+        Iterator<Node> iterator = successors.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        Iterator<Position> positionIterator = n.successorPositions().iterator();
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals(Node.class.getSimpleName() + ":s1", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals(Node.class.getSimpleName() + ":s2", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[0]", positionIterator.next().toString());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertTrue(positionIterator.hasNext());
+        Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[1]", positionIterator.next().toString());
+        Assert.assertFalse(positionIterator.hasNext());
+        Assert.assertFalse(positionIterator.hasNext());
+
+        iterator = successors.iterator();
+        n.s1 = s4;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        n.s2 = s1;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s3);
+        n.stail.initialize(1, s4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = successors.iterator();
+        n.s1 = null;
+        n.s2 = s2;
+        n.stail.initialize(0, null);
+        n.stail.initialize(1, s4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java
new file mode 100644
index 0000000..ee5ca66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomCanonicalizer;
+import org.graalvm.compiler.phases.contract.NodeCostUtil;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class NodePropertiesTest extends GraalCompilerTest {
+
+    public static Object sideEffect;
+
+    public static Object[] array = new Object[]{new Object(), new Object(), new Object()};
+
+    public static int test1Snippet(int a) {
+        int x = 0;
+        if (a > 0) {
+            x = 1;
+            sideEffect = null;
+        } else {
+            x = 2;
+            sideEffect = null;
+        }
+        sideEffect = null;
+        // can shift
+        return a * x * 4;
+    }
+
+    public static int test2Snippet(int a) {
+        int x = 0;
+        if (a > 0) {
+            x = 1;
+            sideEffect = null;
+        } else {
+            x = 2;
+            sideEffect = null;
+        }
+        sideEffect = null;
+        // cannot shift
+        return a * x * 3;
+    }
+
+    public static final int ITERATIONS_LOOP_1 = 128;
+    public static final int ITERATIONS_LOOP_2 = 256;
+
+    public static int testLoop01(int a) {
+        int res = 0;
+        for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) {
+            res += i;
+        }
+        return res;
+    }
+
+    public static int testLoop02(int a) {
+        int res = 0;
+        for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_2, i < a); i++) {
+            res += i;
+        }
+        return res;
+    }
+
+    public static int testLoop03(int a) {
+        int res = 0;
+        for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) {
+            res *= i;
+        }
+        return res;
+    }
+
+    public static int testLoop04(int a) {
+        int res = 0;
+        for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1 * ITERATIONS_LOOP_2, i < a); i++) {
+            res += i;
+        }
+        return res;
+    }
+
+    public static int testLoop05(int a) {
+        int res = 0;
+        for (int i = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_1, i < a); i++) {
+            res += i;
+            for (int j = 0; GraalDirectives.injectIterationCount(ITERATIONS_LOOP_2, j < ITERATIONS_LOOP_2); j++) {
+                res += i;
+            }
+        }
+        return res;
+    }
+
+    public static int dontInline(int a) {
+        int res = 1;
+        for (int i = 0; i < a; i++) {
+            for (int j = 0; j < i; j++) {
+                for (int k = 0; k < j; k++) {
+                    res += i + j + k;
+                }
+            }
+        }
+        sideEffect = res;
+        return (Integer) sideEffect;
+    }
+
+    public static int untrused01(int a) {
+        return dontInline(a);
+    }
+
+    public static int arrayLoadTest(int a) {
+        return array[a].hashCode();
+    }
+
+    public static int arrayStoreTest(int a) {
+        String s = String.valueOf(a);
+        array[2] = s;
+        return s.length();
+    }
+
+    public static int fieldLoad(int a) {
+        return sideEffect.hashCode() * a;
+    }
+
+    public static int fieldStore(int a) {
+        sideEffect = a;
+        return a;
+    }
+
+    @Test
+    public void testCanonicalizationExample() {
+        HighTierContext htc = getDefaultHighTierContext();
+        ImprovementSavingCanonicalizer c1 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider());
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet"));
+        new CanonicalizerPhase(c1).apply(g1, htc);
+        ImprovementSavingCanonicalizer c2 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider());
+        StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet"));
+        new CanonicalizerPhase(c2).apply(g2, htc);
+        Assert.assertTrue(c1.savedCycles > c2.savedCycles);
+    }
+
+    private static void prepareGraphForLoopFrequencies(StructuredGraph g, HighTierContext htc) {
+        // let canonicalizer work away branch probability nodes
+        new CanonicalizerPhase().apply(g, htc);
+        // recompute the loop frequencies
+        ComputeLoopFrequenciesClosure.compute(g);
+    }
+
+    private static void assertFrequency(StructuredGraph g, int iterations) {
+        NodeIterable<LoopBeginNode> loopBeginNodes = g.getNodes(LoopBeginNode.TYPE);
+        LoopBeginNode loopBeginNode = loopBeginNodes.first();
+        Assert.assertEquals("loop frequency of " + loopBeginNode, iterations, loopBeginNode.loopFrequency(), 0);
+    }
+
+    @Test
+    public void testDifferentLoopFaster() {
+        HighTierContext htc = getDefaultHighTierContext();
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop01"));
+        StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop03"));
+        prepareGraphForLoopFrequencies(g1, htc);
+        prepareGraphForLoopFrequencies(g2, htc);
+        assertFrequency(g1, ITERATIONS_LOOP_1);
+        assertFrequency(g2, ITERATIONS_LOOP_1);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        GraphCostPhase gc2 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        gc2.apply(g2, htc);
+        Debug.log("Test testDifferentLoopFaster --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize);
+        Assert.assertTrue(gc2.finalCycles > gc1.finalCycles);
+        Assert.assertTrue(gc2.finalSize == gc1.finalSize);
+    }
+
+    @Test
+    public void testSameLoopMoreIterationsCostlier() {
+        HighTierContext htc = getDefaultHighTierContext();
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop01"));
+        StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop02"));
+        prepareGraphForLoopFrequencies(g1, htc);
+        prepareGraphForLoopFrequencies(g2, htc);
+        assertFrequency(g1, ITERATIONS_LOOP_1);
+        assertFrequency(g2, ITERATIONS_LOOP_2);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        GraphCostPhase gc2 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        gc2.apply(g2, htc);
+        Debug.log("Test testSameLoopMoreIterationsCostlier --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize);
+        Assert.assertTrue(gc2.finalCycles > gc1.finalCycles);
+        Assert.assertTrue(gc2.finalSize == gc1.finalSize);
+    }
+
+    @Test
+    public void testDifferentLoopsInnerOuter() {
+        HighTierContext htc = getDefaultHighTierContext();
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("testLoop04"));
+        StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("testLoop05"));
+        prepareGraphForLoopFrequencies(g1, htc);
+        prepareGraphForLoopFrequencies(g2, htc);
+        assertFrequency(g1, ITERATIONS_LOOP_1 * ITERATIONS_LOOP_2);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        GraphCostPhase gc2 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        gc2.apply(g2, htc);
+        Debug.log("Test testDifferentLoopsInnerOuter --> 1.Graph cycles:%f size:%f vs. 2.Graph cycles:%f size:%f\n", gc1.finalCycles, gc1.finalSize, gc2.finalCycles, gc2.finalSize);
+        Assert.assertTrue(gc2.finalSize > gc1.finalSize);
+    }
+
+    @Test
+    public void testGraphCost() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet"));
+        StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        new CanonicalizerPhase().apply(g2, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        GraphCostPhase gc2 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        gc2.apply(g2, htc);
+        Debug.log("Test Graph Cost --> 1.Graph cost:%f vs. 2.Graph cost:%f\n", gc1.finalCycles, gc2.finalCycles);
+        Assert.assertTrue(gc2.finalCycles > gc1.finalCycles);
+        Assert.assertTrue(gc2.finalSize == gc1.finalSize + 1/* mul has 3 const input */);
+    }
+
+    @Test
+    public void testExpectUntrusted() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("untrused01"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+    }
+
+    @Test
+    public void testArrayLoad() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayLoadTest"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        Assert.assertEquals(35, gc1.finalCycles, 25);
+    }
+
+    @Test
+    public void testArrayStore() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayStoreTest"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        Assert.assertEquals(50, gc1.finalCycles, 25);
+    }
+
+    @Test
+    public void testFieldLoad() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldLoad"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        Assert.assertEquals(30, gc1.finalCycles, 25);
+    }
+
+    @Test
+    public void testFieldStore() {
+        StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldStore"));
+        HighTierContext htc = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(g1, htc);
+        GraphCostPhase gc1 = new GraphCostPhase();
+        gc1.apply(g1, htc);
+        Assert.assertEquals(120, gc1.finalCycles, 25);
+    }
+
+    static class ImprovementSavingCanonicalizer extends CustomCanonicalizer {
+        private int savedCycles;
+        private final NodeCostProvider nodeCostProvider;
+
+        ImprovementSavingCanonicalizer(NodeCostProvider nodeCostProvider) {
+            this.nodeCostProvider = nodeCostProvider;
+        }
+
+        @Override
+        public void simplify(Node node, SimplifierTool tool) {
+            if (node instanceof Canonicalizable.Binary<?>) {
+                @SuppressWarnings("unchecked")
+                Canonicalizable.Binary<ValueNode> bc = (Canonicalizable.Binary<ValueNode>) node;
+                Node canonicalized = bc.canonical(tool, bc.getX(), bc.getY());
+                if (canonicalized != node) {
+                    savedCycles += nodeCostProvider.getEstimatedCPUCycles(node) - nodeCostProvider.getEstimatedCPUCycles(canonicalized);
+                }
+            }
+        }
+    }
+
+    private static class GraphCostPhase extends BasePhase<PhaseContext> {
+        private double finalCycles;
+        private double finalSize;
+
+        @Override
+        protected void run(StructuredGraph graph, PhaseContext context) {
+            finalCycles = NodeCostUtil.computeGraphCycles(graph, context.getNodeCostProvider(), true);
+            finalSize = NodeCostUtil.computeGraphSize(graph, context.getNodeCostProvider());
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OnStackReplacementTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OnStackReplacementTest.java
new file mode 100644
index 0000000..52f6ce6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OnStackReplacementTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+public class OnStackReplacementTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    static int limit = 10000;
+
+    public static void test1Snippet() {
+        for (int i = 0; !Thread.currentThread().isInterrupted() && i < limit; i++) {
+            for (int j = 0; !Thread.currentThread().isInterrupted() && j < limit; j++) {
+            }
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java
new file mode 100644
index 0000000..ea1de66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static java.lang.String.format;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+
+/**
+ * Verifies a class declaring one or more {@linkplain OptionValue options} has a class initializer
+ * that only initializes the option(s). This sanity check mitigates the possibility of an option
+ * value being used before being set.
+ */
+public class OptionsVerifierTest {
+
+    @Test
+    public void verifyOptions() throws IOException {
+        try (Classpath cp = new Classpath()) {
+            HashSet<Class<?>> checked = new HashSet<>();
+            for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, getClass().getClassLoader())) {
+                for (OptionDescriptor desc : opts) {
+                    OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked, cp);
+                }
+            }
+        }
+    }
+
+    static class Classpath implements AutoCloseable {
+        private final Map<String, Object> entries = new LinkedHashMap<>();
+
+        Classpath() throws IOException {
+            List<String> names = new ArrayList<>(Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)));
+            if (GraalTest.Java8OrEarlier) {
+                names.addAll(Arrays.asList(System.getProperty("sun.boot.class.path").split(File.pathSeparator)));
+            } else {
+                names.addAll(Arrays.asList(System.getProperty("jdk.module.path").split(File.pathSeparator)));
+            }
+            for (String n : names) {
+                File path = new File(n);
+                if (path.exists()) {
+                    if (path.isDirectory()) {
+                        entries.put(n, path);
+                    } else if (n.endsWith(".jar") || n.endsWith(".zip")) {
+                        URL url = new URL("jar", "", "file:" + n + "!/");
+                        entries.put(n, new URLClassLoader(new URL[]{url}));
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            for (Object e : entries.values()) {
+                if (e instanceof URLClassLoader) {
+                    ((URLClassLoader) e).close();
+                }
+            }
+        }
+
+        public byte[] getInputStream(String classFilePath) throws IOException {
+            for (Object e : entries.values()) {
+                if (e instanceof File) {
+                    File path = new File((File) e, classFilePath.replace('/', File.separatorChar));
+                    if (path.exists()) {
+                        return Files.readAllBytes(path.toPath());
+                    }
+                } else {
+                    assert e instanceof URLClassLoader;
+                    URLClassLoader ucl = (URLClassLoader) e;
+                    try (InputStream in = ucl.getResourceAsStream(classFilePath)) {
+                        if (in != null) {
+                            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+                            int nRead;
+                            byte[] data = new byte[1024];
+                            while ((nRead = in.read(data, 0, data.length)) != -1) {
+                                buffer.write(data, 0, nRead);
+                            }
+                            return buffer.toByteArray();
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    static final class OptionsVerifier extends ClassVisitor {
+
+        public static void checkClass(Class<?> cls, OptionDescriptor option, Set<Class<?>> checked, Classpath cp) throws IOException {
+            if (!checked.contains(cls)) {
+                checked.add(cls);
+                Class<?> superclass = cls.getSuperclass();
+                if (superclass != null && !superclass.equals(Object.class)) {
+                    checkClass(superclass, option, checked, cp);
+                }
+
+                String classFilePath = cls.getName().replace('.', '/') + ".class";
+                ClassReader cr = new ClassReader(Objects.requireNonNull(cp.getInputStream(classFilePath), "Could not find class file for " + cls.getName()));
+
+                ClassVisitor cv = new OptionsVerifier(cls, option);
+                cr.accept(cv, 0);
+            }
+        }
+
+        /**
+         * The option field context of the verification.
+         */
+        private final OptionDescriptor option;
+
+        /**
+         * The class in which {@link #option} is declared or a super-class of that class. This is
+         * the class whose {@code <clinit>} method is being verified.
+         */
+        private final Class<?> cls;
+
+        /**
+         * Source file context for error reporting.
+         */
+        String sourceFile = null;
+
+        /**
+         * Line number for error reporting.
+         */
+        int lineNo = -1;
+
+        final Class<?>[] boxingTypes = {Boolean.class, Byte.class, Short.class, Character.class, Integer.class, Float.class, Long.class, Double.class};
+
+        private static Class<?> resolve(String name) {
+            try {
+                return Class.forName(name.replace('/', '.'));
+            } catch (ClassNotFoundException e) {
+                throw new InternalError(e);
+            }
+        }
+
+        OptionsVerifier(Class<?> cls, OptionDescriptor desc) {
+            super(Opcodes.ASM5);
+            this.cls = cls;
+            this.option = desc;
+        }
+
+        @Override
+        public void visitSource(String source, String debug) {
+            this.sourceFile = source;
+        }
+
+        void verify(boolean condition, String message) {
+            if (!condition) {
+                error(message);
+            }
+        }
+
+        void error(String message) {
+            String errorMessage = format(
+                            "%s:%d: Illegal code in %s.<clinit> which may be executed when %s.%s is initialized:%n%n    %s%n%n" + "The recommended solution is to move " + option.getName() +
+                                            " into a separate class (e.g., %s.Options).%n",
+                            sourceFile, lineNo, cls.getSimpleName(), option.getDeclaringClass().getSimpleName(), option.getName(),
+                            message, option.getDeclaringClass().getSimpleName());
+            throw new InternalError(errorMessage);
+
+        }
+
+        @Override
+        public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) {
+            if (name.equals("<clinit>")) {
+                return new MethodVisitor(Opcodes.ASM5) {
+
+                    @Override
+                    public void visitLineNumber(int line, Label start) {
+                        lineNo = line;
+                    }
+
+                    @Override
+                    public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDesc) {
+                        if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) {
+                            verify(resolve(owner).equals(option.getDeclaringClass()), format("store to field %s.%s", resolve(owner).getSimpleName(), fieldName));
+                            verify(opcode != Opcodes.PUTFIELD, format("store to non-static field %s.%s", resolve(owner).getSimpleName(), fieldName));
+                        }
+                    }
+
+                    private Executable resolveMethod(String owner, String methodName, String methodDesc) {
+                        Class<?> declaringClass = resolve(owner);
+                        if (methodName.equals("<init>")) {
+                            for (Constructor<?> c : declaringClass.getDeclaredConstructors()) {
+                                if (methodDesc.equals(Type.getConstructorDescriptor(c))) {
+                                    return c;
+                                }
+                            }
+                        } else {
+                            Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
+                            for (Method m : declaringClass.getDeclaredMethods()) {
+                                if (m.getName().equals(methodName)) {
+                                    if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) {
+                                        if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) {
+                                            return m;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        throw new NoSuchMethodError(declaringClass + "." + methodName + methodDesc);
+                    }
+
+                    /**
+                     * Checks whether a given method is allowed to be called.
+                     */
+                    private boolean checkInvokeTarget(Executable method) {
+                        Class<?> holder = method.getDeclaringClass();
+                        if (method instanceof Constructor) {
+                            if (OptionValue.class.isAssignableFrom(holder)) {
+                                return true;
+                            }
+                        } else if (Arrays.asList(boxingTypes).contains(holder)) {
+                            return method.getName().equals("valueOf");
+                        } else if (method.getDeclaringClass().equals(Class.class)) {
+                            return method.getName().equals("desiredAssertionStatus");
+                        }
+                        return false;
+                    }
+
+                    @Override
+                    public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) {
+                        Executable callee = resolveMethod(owner, methodName, methodDesc);
+                        verify(checkInvokeTarget(callee), "invocation of " + callee);
+                    }
+                };
+            } else {
+                return null;
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java
new file mode 100644
index 0000000..b5101a9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+
+/**
+ * In the following tests, the correct removal of redundant phis during graph building is tested.
+ */
+public class PhiCreationTests extends GraalCompilerTest {
+
+    /**
+     * Dummy method to avoid javac dead code elimination.
+     */
+    private static void test() {
+    }
+
+    @Test
+    public void test1() {
+        StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
+        Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
+    }
+
+    public static int test1Snippet(int a) {
+        if (a > 1) {
+            test();
+        }
+        return a;
+    }
+
+    @Test
+    public void test2() {
+        StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.YES);
+        Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
+    }
+
+    public static int test2Snippet(int a) {
+        while (a > 1) {
+            test();
+        }
+        return a;
+    }
+
+    @Test
+    public void test3() {
+        StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
+    }
+
+    public static int test3Snippet(int a) {
+        while (a > 1) {
+            while (a > 1) {
+                test();
+            }
+        }
+        return a;
+    }
+
+    @Test
+    public void test4() {
+        StructuredGraph graph = parseEager("test4Snippet", AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
+    }
+
+    public static int test4Snippet(int a) {
+        int b = 5;
+        while (a > 1) {
+            while (a > 1) {
+                while (a > 1) {
+                    try {
+                        test();
+                    } catch (Throwable t) {
+
+                    }
+                }
+            }
+            while (a > 1) {
+                while (a > 1) {
+                    try {
+                        test();
+                    } catch (Throwable t) {
+
+                    }
+                }
+            }
+        }
+        return a + b;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java
new file mode 100644
index 0000000..684d4a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.io.Serializable;
+
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.TriState;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests profiling information provided by the runtime.
+ * <p>
+ * NOTE: These tests are actually not very robust. The problem is that only partial profiling
+ * information may be gathered for any given method. For example, HotSpot's advanced compilation
+ * policy can decide to only gather partial profiles in a first level compilation (see
+ * AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this,
+ * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only set's
+ * the null_seen bit when doing full profiling.
+ */
+public class ProfilingInfoTest extends GraalCompilerTest {
+
+    private static final int N = 10;
+    private static final double DELTA = 1d / Integer.MAX_VALUE;
+
+    @Test
+    public void testBranchTakenProbability() {
+        ProfilingInfo info = profile("branchProbabilitySnippet", 0);
+        Assert.assertEquals(0.0, info.getBranchTakenProbability(1), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(1));
+        Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA);
+        Assert.assertEquals(0, info.getExecutionCount(8));
+
+        info = profile("branchProbabilitySnippet", 1);
+        Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(1));
+        Assert.assertEquals(0.0, info.getBranchTakenProbability(8), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(8));
+
+        info = profile("branchProbabilitySnippet", 2);
+        Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(1));
+        Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(8));
+
+        continueProfiling(3 * N, "branchProbabilitySnippet", 0);
+        Assert.assertEquals(0.25, info.getBranchTakenProbability(1), DELTA);
+        Assert.assertEquals(4 * N, info.getExecutionCount(1));
+        Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA);
+        Assert.assertEquals(N, info.getExecutionCount(8));
+
+        resetProfile("branchProbabilitySnippet");
+        Assert.assertEquals(-1.0, info.getBranchTakenProbability(1), DELTA);
+        Assert.assertEquals(0, info.getExecutionCount(1));
+        Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA);
+        Assert.assertEquals(0, info.getExecutionCount(8));
+    }
+
+    public static int branchProbabilitySnippet(int value) {
+        if (value == 0) {
+            return -1;
+        } else if (value == 1) {
+            return -2;
+        } else {
+            return -3;
+        }
+    }
+
+    @Test
+    public void testSwitchProbabilities() {
+        ProfilingInfo info = profile("switchProbabilitySnippet", 0);
+        Assert.assertArrayEquals(new double[]{1.0, 0.0, 0.0}, info.getSwitchProbabilities(1), DELTA);
+
+        info = profile("switchProbabilitySnippet", 1);
+        Assert.assertArrayEquals(new double[]{0.0, 1.0, 0.0}, info.getSwitchProbabilities(1), DELTA);
+
+        info = profile("switchProbabilitySnippet", 2);
+        Assert.assertArrayEquals(new double[]{0.0, 0.0, 1.0}, info.getSwitchProbabilities(1), DELTA);
+
+        resetProfile("switchProbabilitySnippet");
+        Assert.assertNull(info.getSwitchProbabilities(1));
+    }
+
+    public static int switchProbabilitySnippet(int value) {
+        switch (value) {
+            case 0:
+                return -1;
+            case 1:
+                return -2;
+            default:
+                return -3;
+        }
+    }
+
+    @Test
+    public void testProfileInvokeVirtual() {
+        testTypeProfile("invokeVirtualSnippet", 1);
+    }
+
+    public static int invokeVirtualSnippet(Object obj) {
+        return obj.hashCode();
+    }
+
+    @Test
+    public void testTypeProfileInvokeInterface() {
+        testTypeProfile("invokeInterfaceSnippet", 1);
+    }
+
+    public static int invokeInterfaceSnippet(CharSequence a) {
+        return a.length();
+    }
+
+    @Test
+    public void testTypeProfileCheckCast() {
+        testTypeProfile("checkCastSnippet", 1);
+    }
+
+    public static Serializable checkCastSnippet(Object obj) {
+        try {
+            return (Serializable) obj;
+        } catch (ClassCastException e) {
+            return null;
+        }
+    }
+
+    @Test
+    public void testTypeProfileInstanceOf() {
+        testTypeProfile("instanceOfSnippet", 1);
+    }
+
+    public static boolean instanceOfSnippet(Object obj) {
+        return obj instanceof Serializable;
+    }
+
+    private void testTypeProfile(String testSnippet, int bci) {
+        ResolvedJavaType stringType = getMetaAccess().lookupJavaType(String.class);
+        ResolvedJavaType stringBuilderType = getMetaAccess().lookupJavaType(StringBuilder.class);
+
+        ProfilingInfo info = profile(testSnippet, "ABC");
+        JavaTypeProfile typeProfile = info.getTypeProfile(bci);
+        Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA);
+        Assert.assertEquals(1, typeProfile.getTypes().length);
+        Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType());
+        Assert.assertEquals(1.0, typeProfile.getTypes()[0].getProbability(), DELTA);
+
+        continueProfiling(testSnippet, new StringBuilder());
+        typeProfile = info.getTypeProfile(bci);
+        Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA);
+        Assert.assertEquals(2, typeProfile.getTypes().length);
+        Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType());
+        Assert.assertEquals(stringBuilderType, typeProfile.getTypes()[1].getType());
+        Assert.assertEquals(0.5, typeProfile.getTypes()[0].getProbability(), DELTA);
+        Assert.assertEquals(0.5, typeProfile.getTypes()[1].getProbability(), DELTA);
+
+        resetProfile(testSnippet);
+        typeProfile = info.getTypeProfile(bci);
+        Assert.assertNull(typeProfile);
+    }
+
+    @Test
+    public void testExceptionSeen() {
+        // NullPointerException
+        ProfilingInfo info = profile("nullPointerExceptionSnippet", 5);
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+
+        info = profile("nullPointerExceptionSnippet", (Object) null);
+        Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1));
+
+        resetProfile("nullPointerExceptionSnippet");
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+
+        // ArrayOutOfBoundsException
+        info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[1]);
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2));
+
+        info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[0]);
+        Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(2));
+
+        resetProfile("arrayIndexOutOfBoundsExceptionSnippet");
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2));
+
+        // CheckCastException
+        info = profile("checkCastExceptionSnippet", "ABC");
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+
+        info = profile("checkCastExceptionSnippet", 5);
+        Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1));
+
+        resetProfile("checkCastExceptionSnippet");
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+
+        // Invoke with exception
+        info = profile("invokeWithExceptionSnippet", false);
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+
+        info = profile("invokeWithExceptionSnippet", true);
+        Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1));
+
+        resetProfile("invokeWithExceptionSnippet");
+        Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1));
+    }
+
+    public static int nullPointerExceptionSnippet(Object obj) {
+        try {
+            return obj.hashCode();
+        } catch (NullPointerException e) {
+            return 1;
+        }
+    }
+
+    public static int arrayIndexOutOfBoundsExceptionSnippet(int[] array) {
+        try {
+            return array[0];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            return 1;
+        }
+    }
+
+    public static int checkCastExceptionSnippet(Object obj) {
+        try {
+            return ((String) obj).length();
+        } catch (ClassCastException e) {
+            return 1;
+        }
+    }
+
+    public static int invokeWithExceptionSnippet(boolean doThrow) {
+        try {
+            return throwException(doThrow);
+        } catch (IllegalArgumentException e) {
+            return 1;
+        }
+    }
+
+    private static int throwException(boolean doThrow) {
+        if (doThrow) {
+            throw new IllegalArgumentException();
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testNullSeen() {
+        testNullSeen("instanceOfSnippet");
+        testNullSeen("checkCastSnippet");
+    }
+
+    private void testNullSeen(String snippet) {
+        ProfilingInfo info = profile(snippet, 1);
+        Assert.assertEquals(TriState.FALSE, info.getNullSeen(1));
+
+        continueProfiling(snippet, "ABC");
+        Assert.assertEquals(TriState.FALSE, info.getNullSeen(1));
+
+        continueProfiling(snippet, new Object());
+        Assert.assertEquals(TriState.FALSE, info.getNullSeen(1));
+
+        if (TriState.TRUE == info.getNullSeen(1)) {
+            // See the javadoc comment for ProfilingInfoTest.
+            continueProfiling(snippet, (Object) null);
+            Assert.assertEquals(TriState.TRUE, info.getNullSeen(1));
+
+            continueProfiling(snippet, 0.0);
+            Assert.assertEquals(TriState.TRUE, info.getNullSeen(1));
+
+            continueProfiling(snippet, new Object());
+            Assert.assertEquals(TriState.TRUE, info.getNullSeen(1));
+        }
+
+        resetProfile(snippet);
+        Assert.assertEquals(TriState.FALSE, info.getNullSeen(1));
+    }
+
+    private ProfilingInfo profile(String methodName, Object... args) {
+        return profile(true, N, methodName, args);
+    }
+
+    private void continueProfiling(String methodName, Object... args) {
+        profile(false, N, methodName, args);
+    }
+
+    private void continueProfiling(int executions, String methodName, Object... args) {
+        profile(false, executions, methodName, args);
+    }
+
+    private ProfilingInfo profile(boolean resetProfile, int executions, String methodName, Object... args) {
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName);
+        Assert.assertTrue(javaMethod.isStatic());
+        if (resetProfile) {
+            javaMethod.reprofile();
+        }
+
+        for (int i = 0; i < executions; ++i) {
+            try {
+                invoke(javaMethod, null, args);
+            } catch (Throwable e) {
+                Assert.fail("method should not throw an exception: " + e.toString());
+            }
+        }
+
+        ProfilingInfo info = javaMethod.getProfilingInfo();
+        // The execution counts are low so force maturity
+        info.setMature();
+        return info;
+    }
+
+    private void resetProfile(String methodName) {
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName);
+        javaMethod.reprofile();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java
new file mode 100644
index 0000000..9cfacab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.PushThroughPiPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class PushNodesThroughPiTest extends GraalCompilerTest {
+
+    public static class A {
+
+        public long x = 20;
+    }
+
+    public static class B extends A {
+
+        public long y = 10;
+    }
+
+    public static class C extends B {
+
+        public long z = 5;
+    }
+
+    public static long test1Snippet(A a) {
+        C c = (C) a;
+        long ret = c.x; // this can be pushed before the checkcast
+        ret += c.y; // not allowed to push
+        ret += c.z; // not allowed to push
+        // the null-check should be canonicalized with the null-check of the checkcast
+        ret += c != null ? 100 : 200;
+        return ret;
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test1() {
+        final String snippet = "test1Snippet";
+        try (Scope s = Debug.scope("PushThroughPi", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = compileTestSnippet(snippet);
+            for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) {
+                OffsetAddressNode address = (OffsetAddressNode) rn.getAddress();
+                long disp = address.getOffset().asJavaConstant().asLong();
+
+                ResolvedJavaType receiverType = StampTool.typeOrNull(address.getBase());
+                ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp, rn.getStackKind());
+
+                assert field != null : "Node " + rn + " tries to access a field which doesn't exists for this type";
+                if (field.getName().equals("x")) {
+                    Assert.assertTrue(address.getBase() instanceof ParameterNode);
+                } else {
+                    Assert.assertTrue(address.getBase().toString(), address.getBase() instanceof PiNode);
+                }
+            }
+
+            Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private StructuredGraph compileTestSnippet(final String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new PushThroughPiPhase().apply(graph);
+        canonicalizer.apply(graph, context);
+
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java
new file mode 100644
index 0000000..04cacfa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class PushThroughIfTest extends GraalCompilerTest {
+
+    public int field1;
+    public int field2;
+
+    public int testSnippet(boolean b) {
+        int i;
+        if (b) {
+            i = field1;
+        } else {
+            i = field1;
+        }
+        return i + field2;
+    }
+
+    @SuppressWarnings("unused")
+    public int referenceSnippet(boolean b) {
+        return field1 + field2;
+    }
+
+    @Test
+    public void test1() {
+        test("testSnippet", "referenceSnippet");
+    }
+
+    private void test(String snippet, String reference) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) {
+            fs.replaceAtUsages(null);
+            GraphUtil.killWithUnusedFloatingInputs(fs);
+        }
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+
+        StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
+        for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).snapshot()) {
+            fs.replaceAtUsages(null);
+            GraphUtil.killWithUnusedFloatingInputs(fs);
+        }
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java
new file mode 100644
index 0000000..57ca56a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.OptimizeGuardAnchorsPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/* consider
+ *     B b = (B) a;
+ *     return b.x10;
+ *
+ * With snippets a typecheck is performed and if it was successful, a PiNode is created.
+ * For the read node, however, there is only a dependency to the PiNode, but not to the
+ * typecheck itself. With special crafting, it's possible to get the scheduler moving the
+ * FloatingReadNode before the typecheck. Assuming the object is of the wrong type (here for
+ * example A), an invalid field read is done.
+ *
+ * In order to avoid this situation, an anchor node is introduced in CheckCastSnippts.
+ */
+
+public class ReadAfterCheckCastTest extends GraphScheduleTest {
+
+    public static long foo = 0;
+
+    public static class A {
+
+        public long x1;
+    }
+
+    public static class B extends A {
+
+        public long x10;
+    }
+
+    public static long test1Snippet(A a) {
+        if (foo > 4) {
+            B b = (B) a;
+            b.x10 += 1;
+            return b.x10;
+        } else {
+            B b = (B) a;
+            b.x10 += 1;
+            return b.x10;
+        }
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("try")
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("ReadAfterCheckCastTest", new DebugDumpScope(snippet))) {
+            // check shape of graph, with lots of assumptions. will probably fail if graph
+            // structure changes significantly
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            PhaseContext context = new PhaseContext(getProviders());
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
+            new OptimizeGuardAnchorsPhase().apply(graph);
+            canonicalizer.apply(graph, context);
+
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering");
+
+            for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) {
+                // Checking that the parameter a is not directly used for the access to field
+                // x10 (because x10 must be guarded by the checkcast).
+                Assert.assertTrue(node.getLocationIdentity().isImmutable());
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java
new file mode 100644
index 0000000..5d9d4f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class ReassociateAndCanonicalTest extends GraalCompilerTest {
+
+    public static int rnd = (int) (Math.random() * 100);
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "ref1Snippet");
+    }
+
+    public static int test1Snippet() {
+        return 1 + (rnd + 2);
+    }
+
+    public static int ref1Snippet() {
+        return rnd + 3;
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", "ref2Snippet");
+    }
+
+    public static int test2Snippet() {
+        return rnd + 3;
+    }
+
+    public static int ref2Snippet() {
+        return (rnd + 2) + 1;
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet", "ref3Snippet");
+    }
+
+    public static int test3Snippet() {
+        return rnd + 3;
+    }
+
+    public static int ref3Snippet() {
+        return 1 + (2 + rnd);
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", "ref4Snippet");
+    }
+
+    public static int test4Snippet() {
+        return rnd + 3;
+    }
+
+    public static int ref4Snippet() {
+        return (2 + rnd) + 1;
+    }
+
+    @Test
+    public void test5() {
+        test("test5Snippet", "ref5Snippet");
+    }
+
+    public static int test5Snippet() {
+        return -1 - rnd;
+    }
+
+    public static int ref5Snippet() {
+        return 1 - (rnd + 2);
+    }
+
+    @Test
+    public void test6() {
+        test("test6Snippet", "ref6Snippet");
+    }
+
+    public static int test6Snippet() {
+        return rnd + 1;
+    }
+
+    public static int ref6Snippet() {
+        return (rnd + 2) - 1;
+    }
+
+    @Test
+    public void test7() {
+        test("test7Snippet", "ref7Snippet");
+    }
+
+    public static int test7Snippet() {
+        return -1 - rnd;
+    }
+
+    public static int ref7Snippet() {
+        return 1 - (2 + rnd);
+    }
+
+    @Test
+    public void test8() {
+        test("test8Snippet", "ref8Snippet");
+    }
+
+    public static int test8Snippet() {
+        return rnd + 1;
+    }
+
+    public static int ref8Snippet() {
+        return (2 + rnd) - 1;
+    }
+
+    @Test
+    public void test9() {
+        test("test9Snippet", "ref9Snippet");
+    }
+
+    public static int test9Snippet() {
+        return rnd - 1;
+    }
+
+    public static int ref9Snippet() {
+        return 1 + (rnd - 2);
+    }
+
+    @Test
+    public void test10() {
+        test("test10Snippet", "ref10Snippet");
+    }
+
+    public static int test10Snippet() {
+        return rnd - 1;
+    }
+
+    public static int ref10Snippet() {
+        return (rnd - 2) + 1;
+    }
+
+    @Test
+    public void test11() {
+        test("test11Snippet", "ref11Snippet");
+    }
+
+    public static int test11Snippet() {
+        return -rnd + 3;
+    }
+
+    public static int ref11Snippet() {
+        return 1 + (2 - rnd);
+    }
+
+    @Test
+    public void test12() {
+        test("test12Snippet", "ref12Snippet");
+    }
+
+    public static int test12Snippet() {
+        return -rnd + 3;
+    }
+
+    public static int ref12Snippet() {
+        return (2 - rnd) + 1;
+    }
+
+    @Test
+    public void test13() {
+        test("test13Snippet", "ref13Snippet");
+    }
+
+    public static int test13Snippet() {
+        return -rnd + 3;
+    }
+
+    public static int ref13Snippet() {
+        return 1 - (rnd - 2);
+    }
+
+    @Test
+    public void test14() {
+        test("test14Snippet", "ref14Snippet");
+    }
+
+    public static int test14Snippet() {
+        return rnd - 3;
+    }
+
+    public static int ref14Snippet() {
+        return (rnd - 2) - 1;
+    }
+
+    @Test
+    public void test15() {
+        test("test15Snippet", "ref15Snippet");
+    }
+
+    public static int test15Snippet() {
+        return rnd + -1;
+    }
+
+    public static int ref15Snippet() {
+        return 1 - (2 - rnd);
+    }
+
+    @Test
+    public void test16() {
+        test("test16Snippet", "ref16Snippet");
+    }
+
+    public static int test16Snippet() {
+        return -rnd + 1;
+    }
+
+    public static int ref16Snippet() {
+        return (2 - rnd) - 1;
+    }
+
+    private <T extends Node & IterableNodeType> void test(String test, String ref) {
+        StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO);
+        new CanonicalizerPhase().apply(testGraph, new PhaseContext(getProviders()));
+        StructuredGraph refGraph = parseEager(ref, AllowAssumptions.NO);
+        new CanonicalizerPhase().apply(refGraph, new PhaseContext(getProviders()));
+        assertEquals(testGraph, refGraph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java
new file mode 100644
index 0000000..6596d4d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+public class ReentrantBlockIteratorTest extends GraalCompilerTest {
+
+    public static int IntSideEffect;
+
+    public static int oneBlock() {
+        return 0;
+    }
+
+    public static int fourBlock(int a) {
+        if (a > 0) {
+            IntSideEffect = a;
+        } else {
+            IntSideEffect = 0;
+        }
+        GraalDirectives.controlFlowAnchor();
+        return 0;
+    }
+
+    public static int loopBlocks(int a) {
+        int phi = 0;
+        for (int i = 0; i < a; i++) {
+            phi += i;
+        }
+        return phi;
+    }
+
+    public static int loopBlocks2(int a) {
+        int phi = 0;
+        for (int i = 0; i < a; i++) {
+            phi += i;
+        }
+        // first loop exit, second loop will not be visited at all AFTER_FSA
+        for (int i = 0; i < a; i++) {
+            phi += i;
+        }
+        return phi;
+    }
+
+    // from String.indexof
+    @SuppressWarnings("all")
+    public static int loopBlocks3(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount,
+                    int fromIndex) {
+
+        // Checkstyle: stop
+        if (fromIndex >= sourceCount) {
+            return (targetCount == 0 ? sourceCount : -1);
+        }
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        }
+        if (targetCount == 0) {
+            return fromIndex;
+        }
+
+        char first = target[targetOffset];
+        int max = sourceOffset + (sourceCount - targetCount);
+
+        for (int i = sourceOffset + fromIndex; i <= max; i++) {
+            /* Look for first character. */
+            if (source[i] != first) {
+                while (++i <= max && source[i] != first) {
+
+                }
+            }
+
+            /* Found first character, now look at the rest of v2 */
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + targetCount - 1;
+                for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++) {
+
+                }
+
+                if (j == end) {
+                    /* Found whole string. */
+                    return i - sourceOffset;
+                }
+            }
+        }
+        return -1;
+        // Checkstyle: resume
+    }
+
+    public static int loopBlocks4(int a, int c, int d) {
+        int phi = 0;
+        l1: for (int i = 0; i < a; i++) {
+            l3: for (int k = 0; k < c; k++) {
+                for (int l = 0; l < d; l++) {
+                    phi += i * k * l;
+                    if (phi == 5) {
+                        break l3;
+                    }
+                }
+            }
+            if (phi > 100) {
+                break l1;
+            }
+        }
+        return phi;
+    }
+
+    @Test
+
+    public void test01() {
+        List<Block> blocks = getVisitedBlocksInOrder("oneBlock");
+        assertOrder(blocks, 0);
+    }
+
+    @Test
+    public void test02() {
+        List<Block> blocks = getVisitedBlocksInOrder("fourBlock");
+        assertOrder(blocks, 0, 1, 2, 3);
+    }
+
+    @Test
+    public void test03() {
+        List<Block> blocks = getVisitedBlocksInOrder("loopBlocks");
+        assertOrder(blocks, 0, 1, 2, 3);
+    }
+
+    @Test
+    public void test04() {
+        List<Block> blocks = getVisitedBlocksInOrder("loopBlocks2");
+        assertOrder(blocks, 0, 1, 2, 3, 4, 5, 6);
+    }
+
+    @Test
+    public void test05() {
+        List<Block> blocks = getVisitedBlocksInOrder("loopBlocks3");
+        assertVisited(blocks, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
+    }
+
+    @Test
+    public void test06() {
+        getVisitedBlocksInOrder("loopBlocks4");
+    }
+
+    private static void assertOrder(List<Block> blocks, int... ids) {
+        if (blocks.size() != ids.length) {
+            Assert.fail("Different length of blocks " + Arrays.toString(blocks.toArray()) + " ids:" + Arrays.toString(ids));
+        }
+        for (int i = 0; i < blocks.size(); i++) {
+            if (blocks.get(i).getId() != ids[i]) {
+                Assert.fail("Different id for block " + blocks.get(i) + " and associated id " + ids[i]);
+            }
+        }
+    }
+
+    private static void assertVisited(List<Block> blocks, int... ids) {
+        if (blocks.size() != ids.length) {
+            Assert.fail("Different length of blocks " + Arrays.toString(blocks.toArray()) + " ids:" + Arrays.toString(ids));
+        }
+        outer: for (int i = 0; i < blocks.size(); i++) {
+            for (int j = 0; j < blocks.size(); j++) {
+                if (blocks.get(i).getId() == ids[j]) {
+                    continue outer;
+                }
+            }
+            Assert.fail("Id for block " + blocks.get(i) + " not found");
+        }
+    }
+
+    private List<Block> getVisitedBlocksInOrder(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        // after FSA to ensure HIR loop data structure does not contain loop exits
+        graph.setGuardsStage(GuardsStage.AFTER_FSA);
+        ArrayList<Block> blocks = new ArrayList<>();
+        class VoidState {
+        }
+        final VoidState voidState = new VoidState();
+        BlockIteratorClosure<VoidState> closure = new BlockIteratorClosure<VoidState>() {
+
+            @Override
+            protected VoidState getInitialState() {
+                return voidState;
+            }
+
+            @Override
+            protected VoidState processBlock(Block block, VoidState currentState) {
+                // remember the visit order
+                blocks.add(block);
+                return currentState;
+            }
+
+            @Override
+            protected VoidState merge(Block merge, List<VoidState> states) {
+                return voidState;
+            }
+
+            @Override
+            protected VoidState cloneState(VoidState oldState) {
+                return voidState;
+            }
+
+            @Override
+            protected List<VoidState> processLoop(Loop<Block> loop, VoidState initialState) {
+                return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+            }
+        };
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, false);
+        ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
+        // schedule for IGV
+        new SchedulePhase().apply(graph);
+        return blocks;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java
new file mode 100644
index 0000000..ff37a85
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.memory.Access;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+public class ReferenceGetLoopTest extends GraalCompilerTest {
+
+    @Override
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        final LoopsData loops = new LoopsData(graph);
+        boolean found = false;
+        for (LoopEx loop : loops.loops()) {
+            for (Node node : loop.inside().nodes()) {
+                if (node instanceof Access) {
+                    Access access = (Access) node;
+                    LocationIdentity location = access.getLocationIdentity();
+                    if (location instanceof FieldLocationIdentity) {
+                        ResolvedJavaField field = ((FieldLocationIdentity) location).getField();
+                        if (field.getName().equals("referent") && field.getDeclaringClass().equals(getMetaAccess().lookupJavaType(Reference.class))) {
+                            found = true;
+                        }
+                    }
+                }
+            }
+        }
+        if (!found) {
+            assertTrue(false, "Reference.referent not found in loop: " + getCanonicalGraphString(graph, true, false));
+        }
+        return true;
+    }
+
+    public volatile Object referent;
+    public final FinalWeakReference<Object> ref;
+    public final ReferenceQueue<Object> refQueue;
+
+    /*
+     * Ensure that the Reference.get invoke is statically bindable.
+     */
+    public static final class FinalWeakReference<T> extends WeakReference<T> {
+        public FinalWeakReference(T referent, ReferenceQueue<? super T> q) {
+            super(referent, q);
+        }
+    }
+
+    public ReferenceGetLoopTest() {
+        referent = new Object();
+        refQueue = new ReferenceQueue<>();
+        ref = new FinalWeakReference<>(referent, refQueue);
+    }
+
+    @Test
+    public void test() {
+        getCode(getMetaAccess().lookupJavaMethod(getMethod("testSnippet")));
+    }
+
+    public void testSnippet() {
+        while (ref.get() != null) {
+            // burn!
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java
new file mode 100644
index 0000000..da59e9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * In the following tests, the scalar type system of the compiler should be complete enough to see
+ * the relation between the different conditions.
+ */
+public class ScalarTypeSystemTest extends GraalCompilerTest {
+
+    public static int referenceSnippet1(int a) {
+        if (a > 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1() {
+        test("test1Snippet", "referenceSnippet1");
+    }
+
+    public static int test1Snippet(int a) {
+        if (a > 0) {
+            if (a > -1) {
+                return 1;
+            } else {
+                return 3;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2() {
+        test("test2Snippet", "referenceSnippet1");
+    }
+
+    public static int test2Snippet(int a) {
+        if (a > 0) {
+            if (a == -15) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test3() {
+        test("test3Snippet", "referenceSnippet2");
+    }
+
+    public static int referenceSnippet2(int a, int b) {
+        if (a > b) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int test3Snippet(int a, int b) {
+        if (a > b) {
+            if (a == b) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    public static int referenceSnippet3(int a, int b) {
+        if (a == b) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test6() {
+        test("test6Snippet", "referenceSnippet3");
+    }
+
+    public static int test6Snippet(int a, int b) {
+        if (a == b) {
+            if (a == b + 1) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    private void test(final String snippet, final String referenceSnippet) {
+        // No debug scope to reduce console noise for @Test(expected = ...) tests
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        PhaseContext context = new PhaseContext(getProviders());
+        new CanonicalizerPhase().apply(graph, context);
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java
new file mode 100644
index 0000000..c85f020
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+
+public class SchedulingTest extends GraphScheduleTest {
+
+    public static int testValueProxyInputsSnippet(int s) {
+        int i = 0;
+        while (true) {
+            i++;
+            int v = i - s * 2;
+            if (i == s) {
+                return v;
+            }
+        }
+    }
+
+    @Test
+    public void testValueProxyInputs() {
+        StructuredGraph graph = parseEager("testValueProxyInputsSnippet", AllowAssumptions.YES);
+        for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) {
+            fs.replaceAtUsages(null);
+            GraphUtil.killWithUnusedFloatingInputs(fs);
+        }
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
+        NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
+        assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
+        LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
+        List<Node> list = schedule.nodesFor(nodeToBlock.get(loopExit));
+        for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
+            if (!(node instanceof AddNode)) {
+                assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit));
+                assertTrue(list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java
new file mode 100644
index 0000000..22cbe45
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode.DeoptDuring;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class SchedulingTest2 extends GraphScheduleTest {
+
+    public static int testSnippet() {
+        return test() + 2;
+    }
+
+    public static int test() {
+        return 40;
+    }
+
+    @Test
+    public void testValueProxyInputs() {
+        StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
+        ReturnNode returnNode = graph.getNodes(ReturnNode.TYPE).first();
+        BeginNode beginNode = graph.add(new BeginNode());
+        returnNode.replaceAtPredecessor(beginNode);
+        beginNode.setNext(returnNode);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
+        BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+        assertDeepEquals(2, schedule.getCFG().getBlocks().length);
+        for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
+            if (node instanceof AddNode) {
+                assertTrue(node.toString() + " expected: " + nodeToBlock.get(beginNode) + " but was: " + nodeToBlock.get(node), nodeToBlock.get(node) != nodeToBlock.get(beginNode));
+            }
+        }
+
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if (usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+        MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+
+        new GuardLoweringPhase().apply(graph, midContext);
+        FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase();
+        phase.apply(graph);
+
+        schedulePhase.apply(graph);
+        schedule = graph.getLastSchedule();
+        blockToNodesMap = schedule.getBlockToNodesMap();
+        nodeToBlock = schedule.getNodeToBlockMap();
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if ((usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) || (usage instanceof DeoptDuring && ((DeoptDuring) usage).stateDuring() == fs)) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ShortCircuitNodeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ShortCircuitNodeTest.java
new file mode 100644
index 0000000..a57599f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ShortCircuitNodeTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.ea.EATestBase.TestClassInt;
+
+public class ShortCircuitNodeTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        // only executeActual, to avoid creating profiling information
+        executeActual(getResolvedJavaMethod("test1Snippet"), 1, 2);
+    }
+
+    public static final TestClassInt field = null;
+    public static TestClassInt field2 = null;
+
+    @SuppressWarnings("unused")
+    public static void test1Snippet(int a, int b) {
+        /*
+         * if a ShortCircuitOrNode is created for the check inside test2, then faulty handling of
+         * guards can create a cycle in the graph.
+         */
+        int v;
+        if (a == 1) {
+            if (b != 1) {
+                int i = field.x;
+            }
+            field2 = null;
+            v = 0;
+        } else {
+            v = 1;
+        }
+
+        if (test2(v, b)) {
+            int i = field.x;
+        }
+    }
+
+    public static boolean test2(int a, int b) {
+        return a != 0 || b != 1;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java
new file mode 100644
index 0000000..f750ecd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+
+public class SimpleCFGTest extends GraalCompilerTest {
+
+    private static void dumpGraph(final StructuredGraph graph) {
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+    }
+
+    @Test
+    public void testImplies() {
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID);
+
+        EndNode trueEnd = graph.add(new EndNode());
+        EndNode falseEnd = graph.add(new EndNode());
+
+        AbstractBeginNode trueBegin = graph.add(new BeginNode());
+        trueBegin.setNext(trueEnd);
+        AbstractBeginNode falseBegin = graph.add(new BeginNode());
+        falseBegin.setNext(falseEnd);
+
+        IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
+        graph.start().setNext(ifNode);
+
+        AbstractMergeNode merge = graph.add(new MergeNode());
+        merge.addForwardEnd(trueEnd);
+        merge.addForwardEnd(falseEnd);
+        ReturnNode returnNode = graph.add(new ReturnNode(null));
+        merge.setNext(returnNode);
+
+        dumpGraph(graph);
+
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+
+        Block[] blocks = cfg.getBlocks();
+        // check number of blocks
+        assertDeepEquals(4, blocks.length);
+
+        // check block - node assignment
+        assertDeepEquals(blocks[0], cfg.blockFor(graph.start()));
+        assertDeepEquals(blocks[0], cfg.blockFor(ifNode));
+        assertDeepEquals(blocks[1], cfg.blockFor(trueBegin));
+        assertDeepEquals(blocks[1], cfg.blockFor(trueEnd));
+        assertDeepEquals(blocks[2], cfg.blockFor(falseBegin));
+        assertDeepEquals(blocks[2], cfg.blockFor(falseEnd));
+        assertDeepEquals(blocks[3], cfg.blockFor(merge));
+        assertDeepEquals(blocks[3], cfg.blockFor(returnNode));
+
+        // check dominators
+        assertDominator(blocks[0], null);
+        assertDominator(blocks[1], blocks[0]);
+        assertDominator(blocks[2], blocks[0]);
+        assertDominator(blocks[3], blocks[0]);
+
+        // check dominated
+        assertDominatedSize(blocks[0], 3);
+        assertDominatedSize(blocks[1], 0);
+        assertDominatedSize(blocks[2], 0);
+        assertDominatedSize(blocks[3], 0);
+
+        // check postdominators
+        assertPostdominator(blocks[0], blocks[3]);
+        assertPostdominator(blocks[1], blocks[3]);
+        assertPostdominator(blocks[2], blocks[3]);
+        assertPostdominator(blocks[3], null);
+    }
+
+    public static void assertDominator(Block block, Block expectedDominator) {
+        Assert.assertEquals("dominator of " + block, expectedDominator, block.getDominator());
+    }
+
+    public static void assertDominatedSize(Block block, int size) {
+        Assert.assertEquals("number of dominated blocks of " + block, size, block.getDominated().size());
+    }
+
+    public static void assertPostdominator(Block block, Block expectedPostdominator) {
+        Assert.assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java
new file mode 100644
index 0000000..ed98724
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * This class tests some specific patterns the stamp system should be able to canonicalize away
+ * using {@link IntegerStamp#upMask()}.
+ */
+public class StampCanonicalizerTest extends GraalCompilerTest {
+
+    public static int andStamp(int a, int b) {
+        int v = (a & 0xffff00) & (b & 0xff0000f);
+        return v & 1;
+    }
+
+    @Test
+    public void testAnd() {
+        testZeroReturn("andStamp");
+    }
+
+    public static int shiftLeftStamp1(int a) {
+        int v = a << 1;
+        return v & 1;
+    }
+
+    public static int shiftLeftStamp2(int a) {
+        int v = a << 1;
+        if (a == 17) {
+            v = a * 4;
+        }
+        return v & 1;
+    }
+
+    @Test
+    public void testShift() {
+        testZeroReturn("shiftLeftStamp1");
+        testZeroReturn("shiftLeftStamp2");
+    }
+
+    public static int upperBoundShiftStamp1(int a) {
+        int v = a & 0xffff;
+        return (v << 4) & 0xff00000;
+    }
+
+    public static int upperBoundShiftStamp2(int a) {
+        int v = a & 0xffff;
+        return (v >> 4) & 0xf000;
+    }
+
+    @Test
+    public void testUpperBoundShift() {
+        testZeroReturn("upperBoundShiftStamp1");
+        testZeroReturn("upperBoundShiftStamp2");
+    }
+
+    public static int divStamp1(int[] a) {
+        int v = a.length / 4;
+        return v & 0x80000000;
+    }
+
+    public static int divStamp2(int[] a) {
+        int v = a.length / 5;
+        return v & 0x80000000;
+    }
+
+    @Test
+    public void testDiv() {
+        testZeroReturn("divStamp1");
+        testZeroReturn("divStamp2");
+    }
+
+    public static int distinctMask(int a, int b) {
+        int x = a & 0xaaaa;
+        int y = (b & 0x5555) | 0x1;
+        return x == y ? 1 : 0;
+    }
+
+    @Test
+    public void testDistinctMask() {
+        testZeroReturn("distinctMask");
+    }
+
+    private void testZeroReturn(String methodName) {
+        StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new DeadCodeEliminationPhase().apply(graph);
+        assertConstantReturn(graph, 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java
new file mode 100644
index 0000000..235f312
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT;
+
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DelegatingDebugConfig;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.test.GraalTest;
+
+/**
+ * Test that interfaces are correctly initialized by a static field resolution during eager graph
+ * building.
+ */
+public class StaticInterfaceFieldTest extends GraalTest {
+
+    private interface I {
+        Object CONST = new Object() {
+        };
+
+    }
+
+    private static final class C implements I {
+        @SuppressWarnings({"static-method", "unused"})
+        public Object test() {
+            return CONST;
+        }
+    }
+
+    @Test
+    public void test() {
+        eagerlyParseMethod(C.class, "test");
+
+    }
+
+    @SuppressWarnings("try")
+    private void eagerlyParseMethod(Class<C> clazz, String methodName) {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+
+        Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
+
+        final Method m = getMethod(clazz, methodName);
+        ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+        StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+        try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("GraphBuilding", graph, method)) {
+            graphBuilderSuite.apply(graph, context);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java
new file mode 100644
index 0000000..6c9dd26
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class StraighteningTest extends GraalCompilerTest {
+
+    private static final String REFERENCE_SNIPPET = "ref";
+
+    public static boolean ref(int a, int b) {
+        return a == b;
+    }
+
+    public static boolean test1Snippet(int a, int b) {
+        int c = a;
+        if (c == b) {
+            c = 0x55;
+        }
+        if (c != 0x55) {
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean test3Snippet(int a, int b) {
+        int val = (int) System.currentTimeMillis();
+        int c = val + 1;
+        if (a == b) {
+            c = val;
+        }
+        if (c != val) {
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean test2Snippet(int a, int b) {
+        int c;
+        if (a == b) {
+            c = 1;
+        } else {
+            c = 0;
+        }
+        return c == 1;
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    public void test2() {
+        test("test2Snippet");
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test3() {
+        test("test3Snippet");
+    }
+
+    private void test(final String snippet) {
+        // No debug scope to reduce console noise for @Test(expected = ...) tests
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
+        assertEquals(referenceGraph, graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java
new file mode 100644
index 0000000..2dc0a53f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * In the following tests, the scalar type system of the compiler should be complete enough to see
+ * the relation between the different conditions.
+ */
+public class TypeSystemTest extends GraalCompilerTest {
+
+    @Test
+    public void test3() {
+        test("test3Snippet", "referenceSnippet3");
+    }
+
+    public static int referenceSnippet3(Object o) {
+        if (o == null) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int test3Snippet(Object o) {
+        if (o == null) {
+            if (o != null) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", "referenceSnippet3");
+    }
+
+    @SuppressWarnings("unused")
+    public static int test4Snippet(Object o) {
+        if (o == null) {
+            Object o2 = Integer.class;
+            if (o == o2) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    @Test
+    @Ignore
+    public void test5() {
+        test("test5Snippet", "referenceSnippet5");
+    }
+
+    public static int referenceSnippet5(Object o, Object a) {
+        if (o == null) {
+            if (a == Integer.class) {
+                return 1;
+            }
+        } else {
+            if (a == Double.class) {
+                return 11;
+            }
+        }
+        if (a == Integer.class) {
+            return 3;
+        }
+        return 5;
+    }
+
+    @SuppressWarnings("unused")
+    public static int test5Snippet(Object o, Object a) {
+        if (o == null) {
+            if (a == Integer.class) {
+                if (a == null) {
+                    return 10;
+                }
+                return 1;
+            }
+        } else {
+            if (a == Double.class) {
+                if (a != null) {
+                    return 11;
+                }
+                return 2;
+            }
+        }
+        if (a == Integer.class) {
+            return 3;
+        }
+        return 5;
+    }
+
+    @Test
+    public void test6() {
+        testHelper("test6Snippet", InstanceOfNode.class);
+    }
+
+    public static int test6Snippet(int i) throws IOException {
+        Object o = null;
+
+        if (i == 5) {
+            o = new FileInputStream("asdf");
+        }
+        if (i < 10) {
+            o = new ByteArrayInputStream(new byte[]{1, 2, 3});
+        }
+        if (i > 0) {
+            o = new BufferedInputStream(null);
+        }
+
+        return ((InputStream) o).available();
+    }
+
+    @Test
+    public void test7() {
+        test("test7Snippet", "referenceSnippet7");
+    }
+
+    public static int test7Snippet(int x) {
+        return ((x & 0xff) << 10) == ((x & 0x1f) + 1) ? 0 : x;
+    }
+
+    public static int referenceSnippet7(int x) {
+        return x;
+    }
+
+    private void test(String snippet, String referenceSnippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        /*
+         * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
+         * tail-duplication gets activated thus resulting in a graph with more nodes than the
+         * reference graph.
+         */
+        new DominatorConditionalEliminationPhase(false).apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        // a second canonicalizer is needed to process nested MaterializeNodes
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+        new DominatorConditionalEliminationPhase(false).apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        assertEquals(referenceGraph, graph);
+    }
+
+    @Override
+    protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
+        if (getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "expected (node count)");
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "graph (node count)");
+            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
+        }
+    }
+
+    public static void outputGraph(StructuredGraph graph, String message) {
+        TTY.println("========================= " + message);
+        SchedulePhase schedulePhase = new SchedulePhase();
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
+        for (Block block : schedule.getCFG().getBlocks()) {
+            TTY.print("Block " + block + " ");
+            if (block == schedule.getCFG().getStartBlock()) {
+                TTY.print("* ");
+            }
+            TTY.print("-> ");
+            for (Block succ : block.getSuccessors()) {
+                TTY.print(succ + " ");
+            }
+            TTY.println();
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+                outputNode(node);
+            }
+        }
+    }
+
+    private static void outputNode(Node node) {
+        TTY.print("  " + node + "    (usage count: " + node.getUsageCount() + ") (inputs:");
+        for (Node input : node.inputs()) {
+            TTY.print(" " + input.toString(Verbosity.Id));
+        }
+        TTY.println(")");
+        if (node instanceof AbstractMergeNode) {
+            for (PhiNode phi : ((AbstractMergeNode) node).phis()) {
+                outputNode(phi);
+            }
+        }
+    }
+
+    private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph " + snippet);
+        Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeWriterTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeWriterTest.java
new file mode 100644
index 0000000..e6e6249
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeWriterTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.util.TypeConversion;
+import org.graalvm.compiler.core.common.util.TypeReader;
+import org.graalvm.compiler.core.common.util.TypeWriter;
+import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
+import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter;
+
+public class TypeWriterTest extends GraalCompilerTest {
+
+    private static void putValue(TypeWriter writer, long value) {
+        if (TypeConversion.isS1(value)) {
+            writer.putS1(value);
+        }
+        if (TypeConversion.isU1(value)) {
+            writer.putU1(value);
+        }
+        if (TypeConversion.isS2(value)) {
+            writer.putS2(value);
+        }
+        if (TypeConversion.isU2(value)) {
+            writer.putU2(value);
+        }
+        if (TypeConversion.isS4(value)) {
+            writer.putS4(value);
+        }
+        if (TypeConversion.isU4(value)) {
+            writer.putU4(value);
+        }
+        writer.putS8(value);
+        writer.putSV(value);
+        if (value >= 0) {
+            writer.putUV(value);
+        }
+    }
+
+    private static void checkValue(TypeReader reader, long value) {
+        if (TypeConversion.isS1(value)) {
+            Assert.assertEquals(value, reader.getS1());
+        }
+        if (TypeConversion.isU1(value)) {
+            Assert.assertEquals(value, reader.getU1());
+        }
+        if (TypeConversion.isS2(value)) {
+            Assert.assertEquals(value, reader.getS2());
+        }
+        if (TypeConversion.isU2(value)) {
+            Assert.assertEquals(value, reader.getU2());
+        }
+        if (TypeConversion.isS4(value)) {
+            Assert.assertEquals(value, reader.getS4());
+        }
+        if (TypeConversion.isU4(value)) {
+            Assert.assertEquals(value, reader.getU4());
+        }
+        Assert.assertEquals(value, reader.getS8());
+        Assert.assertEquals(value, reader.getSV());
+        if (value >= 0) {
+            Assert.assertEquals(value, reader.getUV());
+        }
+    }
+
+    private static void putValues(TypeWriter writer) {
+        for (int i = 0; i < 64; i++) {
+            long value = 1L << i;
+            putValue(writer, value - 2);
+            putValue(writer, value - 1);
+            putValue(writer, value);
+            putValue(writer, value + 1);
+            putValue(writer, value + 2);
+
+            putValue(writer, -value - 2);
+            putValue(writer, -value - 1);
+            putValue(writer, -value);
+            putValue(writer, -value + 1);
+            putValue(writer, -value + 2);
+        }
+    }
+
+    private static void checkValues(TypeReader reader) {
+        for (int i = 0; i < 64; i++) {
+            long value = 1L << i;
+            checkValue(reader, value - 2);
+            checkValue(reader, value - 1);
+            checkValue(reader, value);
+            checkValue(reader, value + 1);
+            checkValue(reader, value + 2);
+
+            checkValue(reader, -value - 2);
+            checkValue(reader, -value - 1);
+            checkValue(reader, -value);
+            checkValue(reader, -value + 1);
+            checkValue(reader, -value + 2);
+        }
+    }
+
+    private static void test01(boolean supportsUnalignedMemoryAccess) {
+        UnsafeArrayTypeWriter writer = UnsafeArrayTypeWriter.create(supportsUnalignedMemoryAccess);
+        putValues(writer);
+
+        byte[] array = new byte[(int) writer.getBytesWritten()];
+        writer.toArray(array);
+        UnsafeArrayTypeReader reader = UnsafeArrayTypeReader.create(array, 0, supportsUnalignedMemoryAccess);
+        checkValues(reader);
+    }
+
+    @Test
+    public void test01a() {
+        test01(getTarget().arch.supportsUnalignedMemoryAccess());
+    }
+
+    @Test
+    public void test01b() {
+        test01(false);
+    }
+
+    private static void checkSignedSize(TypeWriter writer, long value, int expectedSize) {
+        long sizeBefore = writer.getBytesWritten();
+        writer.putSV(value);
+        Assert.assertEquals(expectedSize, writer.getBytesWritten() - sizeBefore);
+    }
+
+    private static void checkUnsignedSize(TypeWriter writer, long value, int expectedSize) {
+        long sizeBefore = writer.getBytesWritten();
+        writer.putUV(value);
+        Assert.assertEquals(expectedSize, writer.getBytesWritten() - sizeBefore);
+    }
+
+    private static void checkSizes(TypeWriter writer) {
+        checkSignedSize(writer, 0, 1);
+        checkSignedSize(writer, 63, 1);
+        checkSignedSize(writer, -64, 1);
+        checkSignedSize(writer, 64, 2);
+        checkSignedSize(writer, -65, 2);
+        checkSignedSize(writer, 8191, 2);
+        checkSignedSize(writer, -8192, 2);
+        checkSignedSize(writer, 8192, 3);
+        checkSignedSize(writer, -8193, 3);
+        checkSignedSize(writer, Long.MAX_VALUE, 10);
+        checkSignedSize(writer, Long.MIN_VALUE, 10);
+
+        checkUnsignedSize(writer, 0, 1);
+        checkUnsignedSize(writer, 127, 1);
+        checkUnsignedSize(writer, 128, 2);
+        checkUnsignedSize(writer, 16383, 2);
+        checkUnsignedSize(writer, 16384, 3);
+        checkUnsignedSize(writer, Long.MAX_VALUE, 9);
+    }
+
+    @Test
+    public void test02a() {
+        checkSizes(UnsafeArrayTypeWriter.create(getTarget().arch.supportsUnalignedMemoryAccess()));
+    }
+
+    @Test
+    public void test02b() {
+        checkSizes(UnsafeArrayTypeWriter.create(false));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java
new file mode 100644
index 0000000..2c96072
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+
+/**
+ * Exercise handling of unbalanced monitor operations by the parser. Algorithmically Graal assumes
+ * that locks are statically block structured but that isn't something enforced by the bytecodes. In
+ * HotSpot a dataflow is performed to ensure they are properly structured and methods with
+ * unstructured locking aren't compiled and fall back to the interpreter. Having the Graal parser
+ * handle this directly is simplifying for targets of Graal since they don't have to provide a data
+ * flow that checks this property.
+ */
+public class UnbalancedMonitorsTest extends GraalCompilerTest implements Opcodes {
+    private static final String CLASS_NAME = UnbalancedMonitorsTest.class.getName();
+    private static final String INNER_CLASS_NAME = CLASS_NAME + "$UnbalancedMonitors";
+    private static final String CLASS_NAME_INTERNAL = CLASS_NAME.replace('.', '/');
+    private static final String INNER_CLASS_NAME_INTERNAL = INNER_CLASS_NAME.replace('.', '/');
+
+    private static AsmLoader LOADER = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader());
+
+    @Test
+    public void runWrongOrder() throws Exception {
+        checkForBailout("wrongOrder");
+    }
+
+    @Test
+    public void runTooFewExits() throws Exception {
+        checkForBailout("tooFewExits");
+    }
+
+    @Test
+    public void runTooManyExits() throws Exception {
+        checkForBailout("tooManyExits");
+    }
+
+    @Test
+    public void runTooFewExitsExceptional() throws Exception {
+        checkForBailout("tooFewExitsExceptional");
+    }
+
+    @Test
+    public void runTooManyExitsExceptional() throws Exception {
+        checkForBailout("tooManyExitsExceptional");
+    }
+
+    private void checkForBailout(String name) throws ClassNotFoundException {
+        ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name);
+        try {
+            StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+            Plugins plugins = new Plugins(new InvocationPlugins(getMetaAccess()));
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+            OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
+
+            GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null);
+            graphBuilder.apply(graph);
+        } catch (BailoutException e) {
+            if (e.getMessage().contains("unbalanced monitors")) {
+                return;
+            }
+            throw e;
+        }
+        assertTrue("should have bailed out", false);
+    }
+
+    // @formatter:off
+    // Template class used with Bytecode Outline to generate ASM code
+    //    public static class UnbalancedMonitors {
+    //
+    //        public UnbalancedMonitors() {
+    //        }
+    //
+    //        public Object wrongOrder(Object a, Object b) {
+    //            synchronized (a) {
+    //                synchronized (b) {
+    //                    return b;
+    //                }
+    //            }
+    //        }
+    //
+    //        public Object tooFewExits(Object a, Object b) {
+    //            synchronized (a) {
+    //                synchronized (b) {
+    //                    return b;
+    //                }
+    //            }
+    //        }
+    //
+    //        public boolean tooFewExitsExceptional(Object a, Object b) {
+    //            synchronized (a) {
+    //                synchronized (b) {
+    //                    return b.equals(a);
+    //                }
+    //            }
+    //        }
+    //    }
+    // @formatter:on
+
+    public static byte[] generateClass() {
+
+        ClassWriter cw = new ClassWriter(0);
+
+        cw.visit(52, ACC_SUPER | ACC_PUBLIC, INNER_CLASS_NAME_INTERNAL, null, "java/lang/Object", null);
+
+        cw.visitSource("UnbalancedMonitorsTest.java", null);
+
+        cw.visitInnerClass(INNER_CLASS_NAME_INTERNAL, CLASS_NAME_INTERNAL, "UnbalancedMonitors", ACC_STATIC);
+
+        visitConstructor(cw);
+        visitWrongOrder(cw);
+        visitBlockStructured(cw, true, false);
+        visitBlockStructured(cw, true, true);
+        visitBlockStructured(cw, false, false);
+        visitBlockStructured(cw, false, true);
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+
+    private static void visitBlockStructured(ClassWriter cw, boolean normalReturnError, boolean tooMany) {
+        String name = (tooMany ? "tooMany" : "tooFew") + "Exits" + (normalReturnError ? "" : "Exceptional");
+        // Generate too many or too few exits down the either the normal or exceptional return paths
+        int exceptionalExitCount = normalReturnError ? 1 : (tooMany ? 2 : 0);
+        int normalExitCount = normalReturnError ? (tooMany ? 2 : 0) : 1;
+        MethodVisitor mv;
+        mv = cw.visitMethod(ACC_PUBLIC, name, "(Ljava/lang/Object;Ljava/lang/Object;)Z", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        Label l1 = new Label();
+        Label l2 = new Label();
+        mv.visitTryCatchBlock(l0, l1, l2, null);
+        Label l3 = new Label();
+        mv.visitTryCatchBlock(l2, l3, l2, null);
+        Label l4 = new Label();
+        Label l5 = new Label();
+        Label l6 = new Label();
+        mv.visitTryCatchBlock(l4, l5, l6, null);
+        Label l7 = new Label();
+        mv.visitTryCatchBlock(l2, l7, l6, null);
+        Label l8 = new Label();
+        mv.visitLabel(l8);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ASTORE, 3);
+        mv.visitInsn(MONITORENTER);
+        mv.visitLabel(l4);
+        mv.visitVarInsn(ALOAD, 2);
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ASTORE, 4);
+        mv.visitInsn(MONITORENTER);
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 2);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
+        mv.visitVarInsn(ALOAD, 4);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l1);
+        for (int i = 0; i < normalExitCount; i++) {
+            mv.visitVarInsn(ALOAD, 3);
+            mv.visitInsn(MONITOREXIT);
+        }
+        mv.visitLabel(l5);
+        mv.visitInsn(IRETURN);
+        mv.visitLabel(l2);
+        mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object",
+                        "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"});
+        mv.visitVarInsn(ALOAD, 4);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l3);
+        mv.visitInsn(ATHROW);
+        mv.visitLabel(l6);
+        mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1,
+                        new Object[]{"java/lang/Throwable"});
+        for (int i = 0; i < exceptionalExitCount; i++) {
+            mv.visitVarInsn(ALOAD, 3);
+            mv.visitInsn(MONITOREXIT);
+        }
+        mv.visitLabel(l7);
+        mv.visitInsn(ATHROW);
+        Label l9 = new Label();
+        mv.visitLabel(l9);
+        mv.visitMaxs(2, 5);
+        mv.visitEnd();
+    }
+
+    private static void visitWrongOrder(ClassWriter cw) {
+        MethodVisitor mv;
+        mv = cw.visitMethod(ACC_PUBLIC, "wrongOrder", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        Label l1 = new Label();
+        Label l2 = new Label();
+        mv.visitTryCatchBlock(l0, l1, l2, null);
+        Label l3 = new Label();
+        mv.visitTryCatchBlock(l2, l3, l2, null);
+        Label l4 = new Label();
+        Label l5 = new Label();
+        Label l6 = new Label();
+        mv.visitTryCatchBlock(l4, l5, l6, null);
+        Label l7 = new Label();
+        mv.visitTryCatchBlock(l2, l7, l6, null);
+        Label l8 = new Label();
+        mv.visitLabel(l8);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ASTORE, 3);
+        mv.visitInsn(MONITORENTER);
+        mv.visitLabel(l4);
+        mv.visitVarInsn(ALOAD, 2);
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ASTORE, 4);
+        mv.visitInsn(MONITORENTER);
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 2);
+        mv.visitVarInsn(ALOAD, 3);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l1);
+        // Swapped exit order with exit above
+        mv.visitVarInsn(ALOAD, 4);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l5);
+        mv.visitInsn(ARETURN);
+        mv.visitLabel(l2);
+        mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object",
+                        "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"});
+        mv.visitVarInsn(ALOAD, 4);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l3);
+        mv.visitInsn(ATHROW);
+        mv.visitLabel(l6);
+        mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1,
+                        new Object[]{"java/lang/Throwable"});
+        mv.visitVarInsn(ALOAD, 3);
+        mv.visitInsn(MONITOREXIT);
+        mv.visitLabel(l7);
+        mv.visitInsn(ATHROW);
+        Label l9 = new Label();
+        mv.visitLabel(l9);
+        mv.visitMaxs(2, 5);
+        mv.visitEnd();
+    }
+
+    private static void visitConstructor(ClassWriter cw) {
+        MethodVisitor mv;
+        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitInsn(RETURN);
+        Label l2 = new Label();
+        mv.visitLabel(l2);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+    }
+
+    public static class AsmLoader extends ClassLoader {
+        Class<?> loaded;
+
+        public AsmLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(INNER_CLASS_NAME)) {
+                if (loaded != null) {
+                    return loaded;
+                }
+                byte[] bytes = generateClass();
+                return (loaded = defineClass(name, bytes, 0, bytes.length));
+            } else {
+                return super.findClass(name);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java
new file mode 100644
index 0000000..7e8914b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.lang.reflect.Field;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+import sun.misc.Unsafe;
+
+public class UnsafeReadEliminationTest extends GraalCompilerTest {
+
+    public static final Unsafe UNSAFE;
+    static {
+        try {
+            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafe.setAccessible(true);
+            UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("Exception while trying to get Unsafe", e);
+        }
+    }
+
+    public static long[] Memory = new long[]{1, 2};
+    public static double SideEffectD;
+    public static double SideEffectL;
+
+    public static long test1Snippet(double a) {
+        final Object m = Memory;
+        if (a > 0) {
+            UNSAFE.putDouble(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, a);
+        } else {
+            SideEffectL = UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
+        }
+        return UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
+    }
+
+    public static class A {
+        long[][] o;
+        long[][] p;
+    }
+
+    public static Object test2Snippet(A a, int c) {
+        Object phi = null;
+        if (c != 0) {
+            long[][] r = a.o;
+            phi = r;
+            UNSAFE.putDouble(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 12d);
+        } else {
+            long[][] r = a.p;
+            phi = r;
+            UNSAFE.putLong(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 123);
+        }
+        GraalDirectives.controlFlowAnchor();
+        SideEffectD = UNSAFE.getDouble(phi, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
+        return phi;
+    }
+
+    @Test
+    public void test01() {
+        StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO);
+        testEarlyReadElimination(graph, 3, 2);
+    }
+
+    @Test
+    public void test02() {
+        StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO);
+        testPartialEscapeReadElimination(graph, 3, 2);
+    }
+
+    @Test
+    public void test03() {
+        StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO);
+        testEarlyReadElimination(graph, 3, 3);
+    }
+
+    @Test
+    public void test04() {
+        StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO);
+        testEarlyReadElimination(graph, 3, 3);
+    }
+
+    public void testEarlyReadElimination(StructuredGraph graph, int reads, int writes) {
+        PhaseContext context = getDefaultHighTierContext();
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, context);
+        new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+        Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
+        // after lowering the same applies for reads and writes
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+        Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count());
+        Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count());
+    }
+
+    public void testPartialEscapeReadElimination(StructuredGraph graph, int reads, int writes) {
+        PhaseContext context = getDefaultHighTierContext();
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, context);
+        new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context);
+        Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
+        // after lowering the same applies for reads and writes
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context);
+        Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count());
+        Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java
new file mode 100644
index 0000000..0a50d91
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class VerifyBailoutUsageTest {
+
+    private static class InvalidBailoutUsagePhase1 extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            throw new BailoutException("Bailout in graph %s", graph);
+        }
+    }
+
+    private static class InvalidBailoutUsagePhase2 extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            throw new BailoutException(new GraalError("other cause"), "Bailout in graph %s", graph);
+        }
+    }
+
+    private static class InvalidBailoutUsagePhase3 extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            throw new BailoutException(true/* permanent */, "Bailout in graph %s", graph);
+        }
+    }
+
+    private static class ValidPermanentBailoutUsage extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            throw new PermanentBailoutException("Valid permanent bailout %s", graph);
+        }
+    }
+
+    private static class ValidRetryableBailoutUsage extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            throw new RetryableBailoutException("Valid retryable bailout %s", graph);
+        }
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidBailout01() {
+        testBailoutUsage(InvalidBailoutUsagePhase1.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidBailout02() {
+        testBailoutUsage(InvalidBailoutUsagePhase2.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidBailout03() {
+        testBailoutUsage(InvalidBailoutUsagePhase3.class);
+    }
+
+    @Test
+    public void testValidPermanentBailout() {
+        testBailoutUsage(ValidPermanentBailoutUsage.class);
+    }
+
+    @Test
+    public void testValidRetryableBailout() {
+        testBailoutUsage(ValidRetryableBailoutUsage.class);
+    }
+
+    @SuppressWarnings("try")
+    private static void testBailoutUsage(Class<?> c) {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+        for (Method m : c.getDeclaredMethods()) {
+            if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
+                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                graphBuilderSuite.apply(graph, context);
+                try (DebugConfigScope s = Debug.disableIntercept()) {
+                    new VerifyBailoutUsage().apply(graph, context);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java
new file mode 100644
index 0000000..00df743
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class VerifyDebugUsageTest {
+
+    private static class InvalidLogUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            for (Node n : graph.getNodes()) {
+                Debug.log("%s", n.toString());
+            }
+        }
+
+    }
+
+    private static class InvalidLogAndIndentUsagePhase extends Phase {
+
+        @Override
+        @SuppressWarnings("try")
+        protected void run(StructuredGraph graph) {
+            try (Indent i = Debug.logAndIndent("%s", graph.toString())) {
+                for (Node n : graph.getNodes()) {
+                    Debug.log("%s", n);
+                }
+            }
+        }
+
+    }
+
+    private static class InvalidDumpUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph.toString());
+        }
+
+    }
+
+    private static class InvalidVerifyUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.verify(graph, "%s", graph.toString());
+        }
+
+    }
+
+    private static class InvalidConcatLogUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            for (Node n : graph.getNodes()) {
+                Debug.log("error " + n);
+            }
+        }
+
+    }
+
+    private static class InvalidConcatLogAndIndentUsagePhase extends Phase {
+
+        @Override
+        @SuppressWarnings("try")
+        protected void run(StructuredGraph graph) {
+            try (Indent i = Debug.logAndIndent("error " + graph)) {
+                for (Node n : graph.getNodes()) {
+                    Debug.log("%s", n);
+                }
+            }
+        }
+
+    }
+
+    private static class InvalidConcatDumpUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "error " + graph);
+        }
+
+    }
+
+    private static class InvalidConcatVerifyUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.verify(graph, "error " + graph);
+        }
+
+    }
+
+    private static class ValidLogUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            for (Node n : graph.getNodes()) {
+                Debug.log("%s", n);
+            }
+        }
+
+    }
+
+    private static class ValidLogAndIndentUsagePhase extends Phase {
+
+        @Override
+        @SuppressWarnings("try")
+        protected void run(StructuredGraph graph) {
+            try (Indent i = Debug.logAndIndent("%s", graph)) {
+                for (Node n : graph.getNodes()) {
+                    Debug.log("%s", n);
+                }
+            }
+        }
+
+    }
+
+    private static class ValidDumpUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph);
+        }
+
+    }
+
+    private static class ValidVerifyUsagePhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.verify(graph, "%s", graph);
+        }
+
+    }
+
+    private static class InvalidGraalErrorGuaranteePhase extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s %s %s", graph, graph, graph, graph.toString());
+        }
+    }
+
+    private static class ValidGraalErrorGuaranteePhase extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s", graph);
+        }
+    }
+
+    public static Object sideEffect;
+
+    private static class InvalidGraalErrorCtorPhase extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            sideEffect = new GraalError("No Error %s", graph.toString());
+        }
+    }
+
+    private static class ValidGraalErrorCtorPhase extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            sideEffect = new GraalError("Error %s", graph);
+        }
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalid() {
+        testDebugUsageClass(InvalidLogUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogAndIndentInvalid() {
+        testDebugUsageClass(InvalidLogAndIndentUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testVerifyInvalid() {
+        testDebugUsageClass(InvalidVerifyUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testDumpInvalid() {
+        testDebugUsageClass(InvalidDumpUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidConcat() {
+        testDebugUsageClass(InvalidConcatLogUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogAndIndentInvalidConcat() {
+        testDebugUsageClass(InvalidConcatLogAndIndentUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testVerifyInvalidConcat() {
+        testDebugUsageClass(InvalidConcatVerifyUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testDumpInvalidConcat() {
+        testDebugUsageClass(InvalidConcatDumpUsagePhase.class);
+    }
+
+    @Test
+    public void testLogValid() {
+        testDebugUsageClass(ValidLogUsagePhase.class);
+    }
+
+    @Test()
+    public void testLogAndIndentValid() {
+        testDebugUsageClass(ValidLogAndIndentUsagePhase.class);
+    }
+
+    @Test
+    public void testVerifyValid() {
+        testDebugUsageClass(ValidVerifyUsagePhase.class);
+    }
+
+    @Test
+    public void testDumpValid() {
+        testDebugUsageClass(ValidDumpUsagePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testGraalGuaranteeInvalid() {
+        testDebugUsageClass(InvalidGraalErrorGuaranteePhase.class);
+    }
+
+    @Test
+    public void testGraalGuaranteeValid() {
+        testDebugUsageClass(ValidGraalErrorGuaranteePhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testGraalCtorInvalid() {
+        testDebugUsageClass(InvalidGraalErrorCtorPhase.class);
+    }
+
+    @Test
+    public void testGraalCtorValid() {
+        testDebugUsageClass(ValidGraalErrorCtorPhase.class);
+    }
+
+    @SuppressWarnings("try")
+    private static void testDebugUsageClass(Class<?> c) {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+        for (Method m : c.getDeclaredMethods()) {
+            if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
+                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                graphBuilderSuite.apply(graph, context);
+                try (DebugConfigScope s = Debug.disableIntercept()) {
+                    new VerifyDebugUsage().apply(graph, context);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java
new file mode 100644
index 0000000..855be89
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class VerifyVirtualizableTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class InvalidEffectNodeAdd extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<InvalidEffectNodeAdd> TYPE = NodeClass.create(InvalidEffectNodeAdd.class);
+
+        protected InvalidEffectNodeAdd() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().add(new ArrayLengthNode(null));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class InvalidEffectNodeAddWithoutUnique extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<InvalidEffectNodeAddWithoutUnique> TYPE = NodeClass.create(InvalidEffectNodeAddWithoutUnique.class);
+
+        protected InvalidEffectNodeAddWithoutUnique() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addWithoutUnique(new ArrayLengthNode(null));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class InvalidEffectNodeAddOrUnique extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<InvalidEffectNodeAddOrUnique> TYPE = NodeClass.create(InvalidEffectNodeAddOrUnique.class);
+
+        protected InvalidEffectNodeAddOrUnique() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(new ArrayLengthNode(null));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class InvalidEffectNodeAddWithoutUniqueWithInputs extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<InvalidEffectNodeAddWithoutUniqueWithInputs> TYPE = NodeClass.create(InvalidEffectNodeAddWithoutUniqueWithInputs.class);
+
+        protected InvalidEffectNodeAddWithoutUniqueWithInputs() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(new ArrayLengthNode(null));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class InvalidEffectNodeAddOrUniqueWithInputs extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<InvalidEffectNodeAddOrUniqueWithInputs> TYPE = NodeClass.create(InvalidEffectNodeAddOrUniqueWithInputs.class);
+
+        protected InvalidEffectNodeAddOrUniqueWithInputs() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(new ArrayLengthNode(null));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ValidEffectNodeAdd extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<ValidEffectNodeAdd> TYPE = NodeClass.create(ValidEffectNodeAdd.class);
+
+        protected ValidEffectNodeAdd() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().add(ConstantNode.forBoolean(false));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ValidEffectNodeAddWithoutUnique extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<ValidEffectNodeAddWithoutUnique> TYPE = NodeClass.create(ValidEffectNodeAddWithoutUnique.class);
+
+        protected ValidEffectNodeAddWithoutUnique() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addWithoutUnique(ConstantNode.forBoolean(false));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ValidEffectNodeAddOrUnique extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<ValidEffectNodeAddOrUnique> TYPE = NodeClass.create(ValidEffectNodeAddOrUnique.class);
+
+        protected ValidEffectNodeAddOrUnique() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(ConstantNode.forBoolean(false));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ValidEffectNodeAddWithoutUniqueWithInputs extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<ValidEffectNodeAddWithoutUniqueWithInputs> TYPE = NodeClass.create(ValidEffectNodeAddWithoutUniqueWithInputs.class);
+
+        protected ValidEffectNodeAddWithoutUniqueWithInputs() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(ConstantNode.forBoolean(false));
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ValidEffectNodeAddOrUniqueWithInputs extends ValueNode implements Virtualizable {
+
+        public static final NodeClass<ValidEffectNodeAddOrUniqueWithInputs> TYPE = NodeClass.create(ValidEffectNodeAddOrUniqueWithInputs.class);
+
+        protected ValidEffectNodeAddOrUniqueWithInputs() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @Override
+        public void virtualize(VirtualizerTool tool) {
+            graph().addOrUnique(ConstantNode.forBoolean(false));
+        }
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidAdd() {
+        testVirtualizableEffects(InvalidEffectNodeAdd.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidAddWithoutUnique() {
+        testVirtualizableEffects(InvalidEffectNodeAddWithoutUnique.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidAddOrUnique() {
+        testVirtualizableEffects(InvalidEffectNodeAddOrUnique.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidAddWithoutUniqueWithInputs() {
+        testVirtualizableEffects(InvalidEffectNodeAddWithoutUniqueWithInputs.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testInvalidAddOrUniqueWithInputs() {
+        testVirtualizableEffects(InvalidEffectNodeAddOrUniqueWithInputs.class);
+    }
+
+    @Test
+    public void testValidAdd() {
+        testVirtualizableEffects(ValidEffectNodeAdd.class);
+    }
+
+    @Test
+    public void testValidAddWithoutUnique() {
+        testVirtualizableEffects(ValidEffectNodeAddWithoutUnique.class);
+    }
+
+    @Test
+    public void testValidAddOrUnique() {
+        testVirtualizableEffects(ValidEffectNodeAddOrUnique.class);
+    }
+
+    @Test
+    public void testValidAddWithoutUniqueWithInputs() {
+        testVirtualizableEffects(ValidEffectNodeAddWithoutUniqueWithInputs.class);
+    }
+
+    @Test
+    public void testValidAddOrUniqueWithInputs() {
+        testVirtualizableEffects(ValidEffectNodeAddOrUniqueWithInputs.class);
+    }
+
+    @SuppressWarnings("try")
+    private static void testVirtualizableEffects(Class<?> c) {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+        for (Method m : c.getDeclaredMethods()) {
+            if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
+                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                graphBuilderSuite.apply(graph, context);
+                try (DebugConfigScope s = Debug.disableIntercept()) {
+                    new VerifyVirtualizableUsage().apply(graph, context);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java
new file mode 100644
index 0000000..daa6e06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.backend;
+
+import java.util.HashSet;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.Value;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+public class AllocatorTest extends BackendTest {
+
+    @SuppressWarnings("try")
+    protected void testAllocation(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) {
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        try (Scope s = Debug.scope("AllocatorTest", graph, graph.method(), getCodeCache())) {
+            final RegisterStats stats = new RegisterStats(getLIRGenerationResult(graph).getLIR());
+            try (Scope s2 = Debug.scope("Assertions", stats.lir)) {
+                Assert.assertEquals("register count", expectedRegisters, stats.registers.size());
+                Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves);
+                Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private class RegisterStats {
+
+        public final LIR lir;
+        public HashSet<Register> registers = new HashSet<>();
+        public int regRegMoves;
+        public int spillMoves;
+
+        RegisterStats(LIR lir) {
+            this.lir = lir;
+
+            for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+                if (block == null) {
+                    continue;
+                }
+                for (LIRInstruction instr : lir.getLIRforBlock(block)) {
+                    collectStats(instr);
+                }
+            }
+        }
+
+        private ValueProcedure collectStatsProc = (value, mode, flags) -> {
+            if (ValueUtil.isRegister(value)) {
+                final Register reg = ValueUtil.asRegister(value);
+                registers.add(reg);
+            }
+            return value;
+        };
+
+        private void collectStats(final LIRInstruction instr) {
+            instr.forEachOutput(collectStatsProc);
+
+            if (instr instanceof ValueMoveOp) {
+                ValueMoveOp move = (ValueMoveOp) instr;
+                Value def = move.getResult();
+                Value use = move.getInput();
+                if (ValueUtil.isRegister(def)) {
+                    if (ValueUtil.isRegister(use)) {
+                        regRegMoves++;
+                    }
+                } else if (LIRValueUtil.isStackSlotValue(def)) {
+                    spillMoves++;
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/BackendTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/BackendTest.java
new file mode 100644
index 0000000..5f68922
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/BackendTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.backend;
+
+import jdk.vm.ci.code.Architecture;
+
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+
+public abstract class BackendTest extends GraalCompilerTest {
+
+    public BackendTest() {
+        super();
+    }
+
+    public BackendTest(Class<? extends Architecture> arch) {
+        super(arch);
+    }
+
+    @SuppressWarnings("try")
+    protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
+        try (Scope s = Debug.scope("FrontEnd")) {
+            GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.getProfilingInfo(), getSuites());
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), graph, null, null, getLIRSuites());
+        return lirGen;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest.java
new file mode 100644
index 0000000..5704e05
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.DebugVerifyHandler;
+import org.graalvm.compiler.debug.DelegatingDebugConfig;
+import org.graalvm.compiler.debug.DelegatingDebugConfig.Feature;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl.CompilationData;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.ShiftNode;
+import org.graalvm.compiler.nodes.calc.SignedDivNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class MethodMetricsTest extends GraalCompilerTest {
+    static class TestApplication {
+        public static int m01(int x, int y) {
+            return x + y;
+        }
+
+        public static int m02(int x, int y) {
+            return x * y;
+        }
+
+        public static int m03(int x, int y) {
+            return x ^ y;
+        }
+
+        public static int m04(int x, int y) {
+            return x >> y;
+        }
+
+        public static int m05(int x, int y) {
+            return x >>> y;
+        }
+
+        public static int m06(int x, int y) {
+            return x << y;
+        }
+
+        public static int m07(int x, int y) {
+            return x > y ? 0 : 1;
+        }
+
+        public static int m08(int x, int y) {
+            return x % y;
+        }
+
+        public static int m09(int x, int y) {
+            return x / y;
+        }
+
+        public static int m10(int x, int y) {
+            return x - y;
+        }
+
+    }
+
+    public static final Class<?>[] testSignature = new Class<?>[]{int.class, int.class};
+    public static final Object[] testArgs = new Object[]{10, 10};
+
+    static class MethodMetricPhases {
+        static class CountingAddPhase extends Phase {
+
+            // typically those global metrics would be static final, but we need new timers every
+            // invocation if we override the debugvaluefactory
+            private final DebugCounter globalCounter = Debug.counter("GlobalMetric");
+            private final DebugTimer globalTimer = Debug.timer("GlobalTimer");
+
+            @Override
+            @SuppressWarnings("try")
+            protected void run(StructuredGraph graph) {
+                try (DebugCloseable d = globalTimer.start()) {
+                    ResolvedJavaMethod method = graph.method();
+                    DebugMethodMetrics mm = Debug.methodMetrics(method);
+                    mm.addToMetric(graph.getNodes().filter(InvokeNode.class).count(), "Invokes");
+                    mm.incrementMetric("PhaseRunsOnMethod");
+                    globalCounter.increment();
+                }
+            }
+        }
+
+        static class CountingShiftPhase extends Phase {
+            @Override
+            protected void run(StructuredGraph graph) {
+                Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(ShiftNode.class).count(), "Shifts");
+            }
+        }
+
+        static class CountingMulPhase extends Phase {
+            @Override
+            protected void run(StructuredGraph graph) {
+                Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(MulNode.class).count(), "Muls");
+            }
+        }
+
+        static class CountingSubPhase extends Phase {
+            @Override
+            protected void run(StructuredGraph graph) {
+                Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(SubNode.class).count(), "Subs");
+            }
+        }
+
+        static class CountingDivPhase extends Phase {
+            @Override
+            protected void run(StructuredGraph graph) {
+                Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(SignedDivNode.class).count(), "Divs");
+            }
+        }
+
+        static class CountingBinOpPhase extends Phase {
+            @Override
+            protected void run(StructuredGraph graph) {
+                Debug.methodMetrics(graph.method()).addToMetric(graph.getNodes().filter(x -> x instanceof BinaryNode || x instanceof FixedBinaryNode).count(), "BinOps");
+            }
+        }
+
+        static class ScopeTestPhase extends Phase {
+            // typically those global metrics would be static final, but we need new timers every
+            // invocation if we override the debugvaluefactory
+            private final DebugTimer timer = Debug.timer("GlobalTimer1");
+            private final DebugTimer scopedTimer = Debug.timer("GlobalTimer2");
+            private final DebugTimer scopedScopedTimer = Debug.timer("GlobalTimer3");
+            private final DebugTimer scopedScopedScopeTimer = Debug.timer("GlobalTimer4");
+
+            private final DebugTimer timer1 = Debug.timer("GlobalTimer1_WithoutInlineEnhancement");
+            private final DebugTimer scopedTimer1 = Debug.timer("GlobalTimer2_WithoutInlineEnhancement");
+            private final DebugTimer scopedScopedTimer1 = Debug.timer("GlobalTimer3_WithoutInlineEnhancement");
+            private final DebugTimer scopedScopedScopeTimer1 = Debug.timer("GlobalTimer4_WithoutInlineEnhancement");
+
+            @Override
+            @SuppressWarnings("try")
+            protected void run(StructuredGraph graph) {
+                // we are in an enhanced debug scope from graal compiler
+                // now we open multiple inlining scopes, record their time
+                try (DebugCloseable c1 = timer.start()) {
+                    try (DebugCloseable c2 = scopedTimer.start()) {
+                        try (DebugCloseable c3 = scopedScopedTimer.start()) {
+                            // do sth unnecessary long allocating many inlinee scopes
+                            for (int i = 0; i < 50; i++) {
+                                try (Debug.Scope s1 = Debug.methodMetricsScope("InlineEnhancement1", MethodMetricsInlineeScopeInfo.create(graph.method()), false)) {
+                                    try (DebugCloseable c4 = scopedScopedScopeTimer.start()) {
+                                        new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph);
+                                        // double scoped inlinee scopes should not make problems
+                                        // with the data
+                                        try (Debug.Scope s2 = Debug.methodMetricsScope("InlineEnhancement2", MethodMetricsInlineeScopeInfo.create(graph.method()),
+                                                        false)) {
+                                            new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // now lets try different counters without the inline enhancement
+                try (DebugCloseable c1 = timer1.start()) {
+                    try (DebugCloseable c2 = scopedTimer1.start()) {
+                        try (DebugCloseable c3 = scopedScopedTimer1.start()) {
+                            // do sth unnecessary long allocating many inlinee scopes
+                            for (int i = 0; i < 50; i++) {
+                                try (DebugCloseable c4 = scopedScopedScopeTimer1.start()) {
+                                    new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph);
+                                    new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS).apply(graph);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+
+    static DebugConfig overrideGraalDebugConfig(PrintStream log, String methodFilter, String methodMeter) {
+        List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
+        List<DebugVerifyHandler> verifyHandlers = new ArrayList<>();
+        GraalDebugConfig debugConfig = new GraalDebugConfig(
+                        GraalDebugConfig.Options.Log.getValue(),
+                        GraalDebugConfig.Options.Count.getValue(),
+                        GraalDebugConfig.Options.TrackMemUse.getValue(),
+                        GraalDebugConfig.Options.Time.getValue(),
+                        GraalDebugConfig.Options.Dump.getValue(),
+                        GraalDebugConfig.Options.Verify.getValue(),
+                        methodFilter,
+                        methodMeter,
+                        log, dumpHandlers, verifyHandlers);
+        return debugConfig;
+    }
+
+    private static OverrideScope overrideMetricPrinterConfig() {
+        Map<OptionValue<?>, Object> mapping = new HashMap<>();
+        mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true);
+        return OptionValue.override(mapping);
+    }
+
+    abstract Phase additionalPhase();
+
+    @Override
+    protected Suites createSuites() {
+        Suites ret = super.createSuites();
+        ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true);
+        PhaseSuite.findNextPhase(iter, CanonicalizerPhase.class);
+        iter.add(additionalPhase());
+        return ret;
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test() throws Throwable {
+        try (DebugConfigScope s = Debug.setConfig(getConfig()); OverrideScope o = getOScope();) {
+            executeMethod(TestApplication.class.getMethod("m01", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m02", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m03", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m04", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m05", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m06", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m07", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m08", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m09", testSignature), null, testArgs);
+            executeMethod(TestApplication.class.getMethod("m10", testSignature), null, testArgs);
+            assertValues();
+        }
+    }
+
+    @Before
+    public void rememberScopeId() {
+        scopeIdBeforeAccess = DebugScope.getCurrentGlobalScopeId();
+    }
+
+    @After
+    public void clearMMCache() {
+        MethodMetricsImpl.clearMM();
+    }
+
+    abstract DebugConfig getConfig();
+
+    OverrideScope getOScope() {
+        return overrideMetricPrinterConfig();
+    }
+
+    abstract void assertValues() throws Throwable;
+
+    @SuppressWarnings("unchecked")
+    private static Map<ResolvedJavaMethod, CompilationData> readMethodMetricsImplData() {
+        Map<ResolvedJavaMethod, CompilationData> threadLocalMap = null;
+        for (Field f : MethodMetricsImpl.class.getDeclaredFields()) {
+            if (f.getName().equals("threadEntries")) {
+                f.setAccessible(true);
+                Object map;
+                try {
+                    map = ((ThreadLocal<?>) f.get(null)).get();
+                } catch (Throwable t) {
+                    throw new RuntimeException(t);
+                }
+                threadLocalMap = (Map<ResolvedJavaMethod, CompilationData>) map;
+                break;
+            }
+        }
+        return threadLocalMap;
+    }
+
+    private long scopeIdBeforeAccess;
+    private long scopeIdAfterAccess;
+
+    protected long readValFromCurrThread(ResolvedJavaMethod method, String metricName) {
+
+        Map<ResolvedJavaMethod, CompilationData> threadLocalMap = readMethodMetricsImplData();
+        assert threadLocalMap != null;
+        CompilationData compilationData = threadLocalMap.get(method);
+        assert compilationData != null;
+        Map<Long, Map<String, Long>> compilations = compilationData.getCompilations();
+        List<Map<String, Long>> compilationEntries = new ArrayList<>();
+        compilations.forEach((x, y) -> {
+            if (x >= scopeIdBeforeAccess && x <= scopeIdAfterAccess) {
+                compilationEntries.add(y);
+            }
+        });
+        List<Map<String, Long>> listView = compilationEntries.stream().filter(x -> x.size() > 0).collect(Collectors.toList());
+        assert listView.size() <= 1 : "There must be at most one none empty compilation data point present:" + listView.size();
+        /*
+         * NOTE: Using the pre-generation of compilation entries for a method has the disadvantage
+         * that during testing we have different points in time when we request the metric. First,
+         * properly, when we use it and then when we want to know the result, but when we check the
+         * result the debug context no longer holds a correct scope with the unique id, so we return
+         * the first compilation entry that is not empty.
+         */
+        Map<String, Long> entries = listView.size() > 0 ? listView.get(0) : null;
+        Long res = entries != null ? entries.get(metricName) : null;
+        return res != null ? res : 0;
+    }
+
+    @SuppressWarnings("try")
+    void assertValues(String metricName, long[] vals) {
+        scopeIdAfterAccess = DebugScope.getCurrentGlobalScopeId();
+        try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().enable(Feature.METHOD_METRICS))) {
+            Assert.assertEquals(vals[0], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m01", testSignature)), metricName));
+            Assert.assertEquals(vals[1], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m02", testSignature)), metricName));
+            Assert.assertEquals(vals[2], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m03", testSignature)), metricName));
+            Assert.assertEquals(vals[3], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m04", testSignature)), metricName));
+            Assert.assertEquals(vals[4], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m05", testSignature)), metricName));
+            Assert.assertEquals(vals[5], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m06", testSignature)), metricName));
+            Assert.assertEquals(vals[6], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m07", testSignature)), metricName));
+            Assert.assertEquals(vals[7], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m08", testSignature)), metricName));
+            Assert.assertEquals(vals[8], readValFromCurrThread(asResolvedJavaMethod(TestApplication.class.getMethod("m09", testSignature)), metricName));
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    void executeMethod(Method m, Object receiver, Object... args) {
+        test(asResolvedJavaMethod(m), receiver, args);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest1.java
new file mode 100644
index 0000000..658945e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest1.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest1 extends MethodMetricsTest {
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingAddPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingAddPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("PhaseRunsOnMethod", new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
+    }
+
+    @Override
+    @Test
+    public void test() throws Throwable {
+        super.test();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest2.java
new file mode 100644
index 0000000..e7d01cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest2.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest2 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingShiftPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingShiftPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("Shifts", new long[]{0, 0, 0, 1, 1, 1, 0, 0, 0, 0});
+    }
+
+    @Test
+    @Override
+    public void test() throws Throwable {
+        super.test();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest3.java
new file mode 100644
index 0000000..fd575dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest3.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest3 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingMulPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingMulPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("Muls", new long[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0});
+    }
+
+    @Override
+    @Test
+    public void test() throws Throwable {
+        super.test();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest4.java
new file mode 100644
index 0000000..c1cffbd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest4.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest4 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingSubPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingSubPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("Subs", new long[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 1});
+    }
+
+    @Override
+    @Test
+    public void test() throws Throwable {
+        super.test();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest5.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest5.java
new file mode 100644
index 0000000..c294a40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest5.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest5 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingDivPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingDivPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("Divs", new long[]{0, 0, 0, 0, 0, 0, 0, 0, 1, 0});
+    }
+
+    @Override
+    @Test
+    public void test() throws Throwable {
+        super.test();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest6.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest6.java
new file mode 100644
index 0000000..068ef58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTest6.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.phases.Phase;
+
+public class MethodMetricsTest6 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingBinOpPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        return overrideGraalDebugConfig(System.out, "MethodMetricsTest$TestApplication.*", "CountingBinOpPhase");
+    }
+
+    @Override
+    void assertValues() throws Throwable {
+        assertValues("BinOps", new long[]{1, 1, 1, 1, 1, 1, 0, 1, 1, 1});
+    }
+
+    @Override
+    @Test
+    public void test() throws Throwable {
+        super.test();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception01.java
new file mode 100644
index 0000000..ba51364
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception01.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.DebugValueFactory;
+import org.graalvm.compiler.debug.DebugVerifyHandler;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.internal.CounterImpl;
+import org.graalvm.compiler.debug.internal.MemUseTrackerImpl;
+import org.graalvm.compiler.debug.internal.TimerImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.Phase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+// intercepting metrics
+public class MethodMetricsTestInterception01 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.CountingAddPhase();
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
+        List<DebugVerifyHandler> verifyHandlers = new ArrayList<>();
+        GraalDebugConfig debugConfig = new GraalDebugConfig(
+                        GraalDebugConfig.Options.Log.getValue(),
+                        "CountingAddPhase",
+                        GraalDebugConfig.Options.TrackMemUse.getValue(),
+                        "CountingAddPhase",
+                        GraalDebugConfig.Options.Dump.getValue(),
+                        GraalDebugConfig.Options.Verify.getValue(),
+                        "MethodMetricsTest$TestApplication.*",
+                        "CountingAddPhase",
+                        System.out, dumpHandlers, verifyHandlers);
+        return debugConfig;
+    }
+
+    @Override
+    protected OverrideScope getOScope() {
+        Map<OptionValue<?>, Object> mapping = new HashMap<>();
+        mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true);
+        return OptionValue.override(mapping);
+    }
+
+    private DebugValueFactory factory;
+
+    @Test
+    @Override
+    @SuppressWarnings("try")
+    public void test() throws Throwable {
+        factory = Debug.getDebugValueFactory();
+        Debug.setDebugValueFactory(new DebugValueFactory() {
+            @Override
+            public DebugTimer createTimer(String name, boolean conditional) {
+                return new TimerImpl(name, conditional, true);
+            }
+
+            @Override
+            public DebugCounter createCounter(String name, boolean conditional) {
+                return CounterImpl.create(name, conditional, true);
+            }
+
+            @Override
+            public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) {
+                return MethodMetricsImpl.getMethodMetrics(method);
+            }
+
+            @Override
+            public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) {
+                return new MemUseTrackerImpl(name, conditional, true);
+            }
+        });
+        super.test();
+
+    }
+
+    @Override
+    public void afterTest() {
+        super.afterTest();
+        Debug.setDebugValueFactory(factory);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    void assertValues() throws Throwable {
+        assertValues("GlobalMetric", new long[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception02.java
new file mode 100644
index 0000000..e00c2c8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/MethodMetricsTestInterception02.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.DebugValueFactory;
+import org.graalvm.compiler.debug.DebugVerifyHandler;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.Phase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+// intercepting metrics
+public class MethodMetricsTestInterception02 extends MethodMetricsTest {
+
+    @Override
+    protected Phase additionalPhase() {
+        return new MethodMetricPhases.ScopeTestPhase();
+    }
+
+    private DebugValueFactory factory;
+
+    public void setFactory() {
+        /*
+         * setting a custom debug value factory creating a constant timer for checking scope
+         * creation and inlining scopes with metric intercepting works
+         */
+        factory = Debug.getDebugValueFactory();
+        Debug.setDebugValueFactory(new DebugValueFactory() {
+            @Override
+            public DebugTimer createTimer(String name, boolean conditional) {
+                // can still use together with real timer
+                // TimerImpl realTimer = new TimerImpl(name, conditional, true);
+                return new DebugTimer() {
+                    int runs = 0;
+
+                    // private DebugCloseable t;
+
+                    @Override
+                    public DebugCloseable start() {
+                        // t = realTimer.start();
+                        return new DebugCloseable() {
+                            @Override
+                            public void close() {
+                                // t.close();
+                                runs++;
+                                MethodMetricsImpl.addToCurrentScopeMethodMetrics(name, 1);
+                            }
+                        };
+                    }
+
+                    @Override
+                    public void setConditional(boolean flag) {
+
+                    }
+
+                    @Override
+                    public boolean isConditional() {
+                        return false;
+                    }
+
+                    @Override
+                    public TimeUnit getTimeUnit() {
+                        return TimeUnit.MILLISECONDS;
+                    }
+
+                    @Override
+                    public long getCurrentValue() {
+                        return runs;
+                    }
+                };
+            }
+
+            @Override
+            public DebugCounter createCounter(String name, boolean conditional) {
+                return factory.createCounter(name, conditional);
+            }
+
+            @Override
+            public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) {
+                return factory.createMethodMetrics(method);
+            }
+
+            @Override
+            public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) {
+                return factory.createMemUseTracker(name, conditional);
+            }
+        });
+    }
+
+    @Override
+    protected OverrideScope getOScope() {
+        Map<OptionValue<?>, Object> mapping = new HashMap<>();
+        mapping.put(MethodMetricsPrinter.Options.MethodMeterPrintAscii, true);
+        return OptionValue.override(mapping);
+    }
+
+    @Test
+    @Override
+    public void test() throws Throwable {
+        setFactory();
+        super.test();
+    }
+
+    @Override
+    public void afterTest() {
+        super.afterTest();
+        Debug.setDebugValueFactory(factory);
+    }
+
+    @Override
+    DebugConfig getConfig() {
+        List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
+        List<DebugVerifyHandler> verifyHandlers = new ArrayList<>();
+        GraalDebugConfig debugConfig = new GraalDebugConfig(
+                        GraalDebugConfig.Options.Log.getValue(),
+                        ""/* unscoped meter */,
+                        GraalDebugConfig.Options.TrackMemUse.getValue(),
+                        ""/* unscoped time */,
+                        GraalDebugConfig.Options.Dump.getValue(),
+                        GraalDebugConfig.Options.Verify.getValue(),
+                        null /* no method filter */,
+                        "" /* unscoped method metering */,
+                        System.out, dumpHandlers, verifyHandlers);
+        return debugConfig;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    void assertValues() throws Throwable {
+        assertValues("GlobalTimer4_WithoutInlineEnhancement", new long[]{50, 50, 50, 50, 50, 50, 50, 50, 50, 50});
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java
new file mode 100644
index 0000000..ccfc04f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.debug;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ *
+ * Tests to verify that the usage of method metrics does not generate compile time overhead through
+ * eager evaluation of arguments.
+ */
+public class VerifyMethodMetricsTest {
+
+    private static class InvalidCCP_ToString01Inc extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.incrementMetric(n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_Concat01Inc extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.incrementMetric("a" + n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_ToString02Inc extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.incrementMetric("%s", n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_Concat02Inc extends Phase {
+        private final String s = this.getClass().toGenericString();
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.incrementMetric("%s%s", "a" + s, n);
+            }
+        }
+    }
+
+    private static class ValidCCP_ToStringInc extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "%s", n);
+            }
+        }
+    }
+
+    private static class ValidCCP_ConcatInc extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.incrementMetric("%s%s", "a", n);
+            }
+        }
+    }
+
+    private static class InvalidCCP_ToString01Add extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_Concat01Add extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "a" + n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_ToString02Add extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "%s", n.toString());
+            }
+        }
+    }
+
+    private static class InvalidCCP_Concat02Add extends Phase {
+        private final String s = this.getClass().toGenericString();
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "%s%s", "a" + s, n);
+            }
+        }
+    }
+
+    private static class ValidCCP_ToStringAdd extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "%s", n);
+            }
+        }
+    }
+
+    private static class ValidCCP_ConcatAdd extends Phase {
+        @Override
+        protected void run(StructuredGraph graph) {
+            DebugMethodMetrics m = Debug.methodMetrics(graph.method());
+            for (Node n : graph.getNodes()) {
+                m.addToMetric(1, "%s%s", "a", n);
+            }
+        }
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidToString01Add() {
+        testDebugUsageClass(InvalidCCP_ToString01Add.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidConcat01Add() {
+        testDebugUsageClass(InvalidCCP_Concat01Add.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidToString02Add() {
+        testDebugUsageClass(InvalidCCP_ToString02Add.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidConcat02Add() {
+        testDebugUsageClass(InvalidCCP_Concat02Add.class);
+    }
+
+    @Test
+    public void testLogValidToStringAdd() {
+        testDebugUsageClass(ValidCCP_ToStringAdd.class);
+    }
+
+    @Test
+    public void testLogValidConcatAdd() {
+        testDebugUsageClass(ValidCCP_ConcatAdd.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidToString01Inc() {
+        testDebugUsageClass(InvalidCCP_ToString01Inc.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidConcat01Inc() {
+        testDebugUsageClass(InvalidCCP_Concat01Inc.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidToString02Inc() {
+        testDebugUsageClass(InvalidCCP_ToString02Inc.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testLogInvalidConcat02Inc() {
+        testDebugUsageClass(InvalidCCP_Concat02Inc.class);
+    }
+
+    @Test
+    public void testLogValidToStringInc() {
+        testDebugUsageClass(ValidCCP_ToStringInc.class);
+    }
+
+    @Test
+    public void testLogValidConcatInc() {
+        testDebugUsageClass(ValidCCP_ConcatInc.class);
+    }
+
+    @SuppressWarnings("try")
+    private static void testDebugUsageClass(Class<?> c) {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
+        HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
+        for (Method m : c.getDeclaredMethods()) {
+            if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
+                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                graphBuilderSuite.apply(graph, context);
+                try (DebugConfigScope s = Debug.disableIntercept()) {
+                    new VerifyDebugUsage().apply(graph, context);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java
new file mode 100644
index 0000000..f7e0c92
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.deopt;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant
+ * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the
+ * graph of the method that just has a "return 1" statement in it.
+ */
+public class CompiledMethodTest extends GraalCompilerTest {
+
+    public static Object testMethod(Object arg1, Object arg2, Object arg3) {
+        return arg1 + " " + arg2 + " " + arg3;
+    }
+
+    Object f1;
+
+    public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) {
+        return f1 + " " + arg1 + " " + arg2 + " " + arg3;
+    }
+
+    @Test
+    public void test1() {
+        final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
+        final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new DeadCodeEliminationPhase().apply(graph);
+
+        for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
+            if (node.getStackKind() == JavaKind.Object && " ".equals(getSnippetReflection().asObject(String.class, node.asJavaConstant()))) {
+                node.replace(graph, ConstantNode.forConstant(getSnippetReflection().forObject("-"), getMetaAccess(), graph));
+            }
+        }
+
+        InstalledCode compiledMethod = getCode(javaMethod, graph);
+        try {
+            Object result = compiledMethod.executeVarargs("1", "2", "3");
+            Assert.assertEquals("1-2-3", result);
+        } catch (InvalidInstalledCodeException t) {
+            Assert.fail("method invalidated");
+        }
+    }
+
+    @Test
+    public void test3() {
+        final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
+        InstalledCode compiledMethod = getCode(javaMethod);
+        try {
+            Object result = compiledMethod.executeVarargs("1", "2", "3");
+            Assert.assertEquals("1 2 3", result);
+        } catch (InvalidInstalledCodeException t) {
+            Assert.fail("method invalidated");
+        }
+    }
+
+    @Test
+    public void test4() {
+        final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethodVirtual");
+        InstalledCode compiledMethod = getCode(javaMethod);
+        try {
+            f1 = "0";
+            Object result = compiledMethod.executeVarargs(this, "1", "2", "3");
+            Assert.assertEquals("0 1 2 3", result);
+        } catch (InvalidInstalledCodeException t) {
+            Assert.fail("method invalidated");
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/MonitorDeoptTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/MonitorDeoptTest.java
new file mode 100644
index 0000000..1075fbb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/MonitorDeoptTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.core.test.deopt;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+public final class MonitorDeoptTest extends GraalCompilerTest {
+
+    private enum State {
+        INITIAL,
+        ALLOWING_SAFEPOINT,
+        RUNNING_GRAAL,
+        INVALIDATED,
+        RUNNING_INTERPRETER,
+        TERMINATED
+    }
+
+    static final long TIMEOUT = 5000;
+
+    private static class Monitor {
+        private volatile State state = State.INITIAL;
+
+        public synchronized void setState(State newState) {
+            state = newState;
+            notifyAll();
+        }
+
+        public synchronized boolean tryUpdateState(State oldState, State newState) {
+            if (state == oldState) {
+                state = newState;
+                notifyAll();
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public synchronized void waitState(State targetState) throws InterruptedException {
+            long startTime = System.currentTimeMillis();
+            while (state != targetState && System.currentTimeMillis() - startTime < TIMEOUT) {
+                wait(100);
+            }
+            if (state != targetState) {
+                throw new IllegalStateException("Timed out waiting for " + targetState);
+            }
+        }
+
+        /**
+         * Change the current state to {@link State#ALLOWING_SAFEPOINT} and do a short wait to allow
+         * a safepoint to happen. Then restore the state to the original value.
+         *
+         * @param expectedState
+         * @throws InterruptedException
+         */
+        public synchronized void safepoint(State expectedState) throws InterruptedException {
+            if (state == expectedState) {
+                state = State.ALLOWING_SAFEPOINT;
+                wait(1);
+                if (state != State.ALLOWING_SAFEPOINT) {
+                    throw new InternalError("Other threads can not update the state from ALLOWING_SAFEPOINT: " + state);
+                }
+                state = expectedState;
+                notifyAll();
+            }
+        }
+
+        public synchronized State getState() {
+            return state;
+        }
+
+        public synchronized void invalidate(InstalledCode code) throws InterruptedException {
+            // wait for the main thread to start
+            waitState(State.RUNNING_GRAAL);
+
+            state = State.INVALIDATED;
+            code.invalidate();
+        }
+    }
+
+    public static boolean test(Monitor monitor) throws InterruptedException {
+        // initially, we're running as Graal compiled code
+        monitor.setState(State.RUNNING_GRAAL);
+
+        boolean timedOut = true;
+        long startTime = System.currentTimeMillis();
+        long safepointCheckTime = startTime;
+        while (System.currentTimeMillis() - startTime < TIMEOUT) {
+            // wait for the compiled code to be invalidated
+            if (monitor.tryUpdateState(State.INVALIDATED, State.RUNNING_INTERPRETER)) {
+                timedOut = false;
+                break;
+            }
+            if (System.currentTimeMillis() - safepointCheckTime > 200) {
+                /*
+                 * It's possible for a safepoint to be triggered by external code before
+                 * invalidation is ready. Allow a safepoint to occur if required but don't allow
+                 * invalidation to proceed.
+                 */
+                monitor.safepoint(State.RUNNING_GRAAL);
+                safepointCheckTime = System.currentTimeMillis();
+            }
+        }
+        if (timedOut) {
+            throw new InternalError("Timed out while waiting for code to be invalidated: " + monitor.getState());
+        }
+
+        for (int i = 0; i < 500; i++) {
+            // wait for the control thread to send the TERMINATED signal
+            if (monitor.getState() == State.TERMINATED) {
+                return true;
+            }
+
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException e) {
+            }
+        }
+
+        // we're running for more than 5 s in the interpreter
+        // probably the control thread is deadlocked
+        return false;
+    }
+
+    private static LoopBeginNode findFirstLoop(StructuredGraph graph) {
+        FixedNode node = graph.start();
+        for (;;) {
+            if (node instanceof LoopBeginNode) {
+                return (LoopBeginNode) node;
+            } else if (node instanceof FixedWithNextNode) {
+                node = ((FixedWithNextNode) node).next();
+            } else if (node instanceof AbstractEndNode) {
+                node = ((AbstractEndNode) node).merge();
+            } else {
+                Assert.fail(String.format("unexpected node %s in graph of test method", node));
+            }
+        }
+    }
+
+    /**
+     * Remove the safepoint from the first loop in the test method, so only the safepoints on
+     * MonitorEnter and MonitorExit remain in the loop. That way, we can make sure it deopts inside
+     * the MonitorEnter by invalidating the code while holding the lock.
+     */
+    private static void removeLoopSafepoint(StructuredGraph graph) {
+        LoopBeginNode loopBegin = findFirstLoop(graph);
+        loopBegin.disableSafepoint();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test");
+
+        StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES);
+        removeLoopSafepoint(graph);
+
+        CompilationResult compilationResult = compile(javaMethod, graph);
+        final InstalledCode installedCode = getBackend().createDefaultInstalledCode(javaMethod, compilationResult);
+
+        final Monitor monitor = new Monitor();
+
+        Thread controlThread = new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    // Wait for thread to reach RUNNING_GRAAL and then invalidate the code
+                    monitor.invalidate(installedCode);
+
+                    // wait for the main thread to continue running in the interpreter
+                    monitor.waitState(State.RUNNING_INTERPRETER);
+
+                    // terminate the main thread
+                    monitor.setState(State.TERMINATED);
+                } catch (InterruptedException e) {
+                }
+            }
+        });
+
+        controlThread.start();
+
+        boolean result = test(monitor);
+        Assert.assertTrue(result);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SafepointRethrowDeoptTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SafepointRethrowDeoptTest.java
new file mode 100644
index 0000000..6ac8dd3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SafepointRethrowDeoptTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.core.test.deopt;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+import jdk.vm.ci.code.InstalledCode;
+
+public final class SafepointRethrowDeoptTest extends GraalCompilerTest {
+
+    private static final Object RETURN_VALUE = "1 2 3";
+    private static final RuntimeException BREAK_EX = new RuntimeException();
+    private static final RuntimeException CONTINUE_EX = new RuntimeException();
+    private static volatile int terminate;
+    private static volatile int entered;
+
+    public static Object execute() {
+        entered = 1;
+        for (;;) {
+            try {
+                if (terminate != 0) {
+                    throw BREAK_EX;
+                } else {
+                    throw CONTINUE_EX;
+                }
+            } catch (RuntimeException e) {
+                if (e == BREAK_EX) {
+                    break;
+                } else if (e == CONTINUE_EX) {
+                    continue;
+                }
+                throw e;
+            }
+        }
+        return RETURN_VALUE;
+    }
+
+    @Test
+    public void test() {
+        Assume.assumeTrue(GraalOptions.GenLoopSafepoints.getValue());
+        synchronized (SafepointRethrowDeoptTest.class) {
+            // needs static fields
+            terminate = 1;
+
+            InstalledCode installed = getCode(getResolvedJavaMethod("execute"));
+
+            terminate = 0;
+            entered = 0;
+            CountDownLatch cdl = new CountDownLatch(1);
+            Thread t1 = new Thread(() -> {
+                try {
+                    cdl.await();
+                    while (entered == 0) {
+                        /* spin */
+                    }
+                    installed.invalidate();
+                } catch (InterruptedException e) {
+                    Assert.fail("interrupted");
+                } finally {
+                    terminate = 1;
+                }
+            });
+            Thread t2 = new Thread(() -> {
+                cdl.countDown();
+                Object result;
+                try {
+                    result = installed.executeVarargs();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    Assert.fail("exception");
+                    return;
+                }
+                Assert.assertEquals(RETURN_VALUE, result);
+            });
+
+            t1.start();
+            t2.start();
+            try {
+                t1.join();
+                t2.join();
+            } catch (InterruptedException e) {
+                Assert.fail("interrupted");
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java
new file mode 100644
index 0000000..50ade26
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.deopt;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.core.test.ea.EATestBase.TestClassObject;
+
+/**
+ * In the following tests, we try to deoptimize out of synchronized methods.
+ */
+public class SynchronizedMethodDeoptimizationTest extends GraalCompilerTest {
+
+    public static final TestClassObject testObject = null;
+
+    public static synchronized Object testMethodSynchronized(Object o) {
+        if (o == null) {
+            // this branch will always deoptimize
+            return testObject.x;
+        }
+        return o;
+    }
+
+    @Test
+    public void test1() {
+        test("testMethodSynchronized", "test");
+        test("testMethodSynchronized", (Object) null);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EAMergingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EAMergingTest.java
new file mode 100644
index 0000000..7ba18dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EAMergingTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+
+public class EAMergingTest extends EATestBase {
+
+    @Test
+    public void testSimpleMerge() {
+        testEscapeAnalysis("simpleMergeSnippet", null, false);
+        assertDeepEquals(1, returnNodes.size());
+        assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode);
+        PhiNode phi = (PhiNode) returnNodes.get(0).result();
+        assertTrue(phi.valueAt(0) instanceof ParameterNode);
+        assertTrue(phi.valueAt(1) instanceof ParameterNode);
+    }
+
+    public static int simpleMergeSnippet(boolean b, int u, int v) {
+        TestClassInt obj;
+        if (b) {
+            obj = new TestClassInt(u, 0);
+            notInlineable();
+        } else {
+            obj = new TestClassInt(v, 0);
+            notInlineable();
+        }
+        return obj.x;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java
new file mode 100644
index 0000000..735da74
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import java.util.List;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+//JaCoCo Exclude
+
+/**
+ * This base class for all Escape Analysis tests does not contain tests itself, therefore it is not
+ * automatically excluded from JaCoCo. Since it includes code that is used in the test snippets, it
+ * needs to be excluded manually.
+ */
+public class EATestBase extends GraalCompilerTest {
+
+    public static class TestClassInt {
+        public int x;
+        public int y;
+        public int z;
+
+        public TestClassInt() {
+            this(0, 0);
+        }
+
+        public TestClassInt(int x) {
+            this(x, 0);
+        }
+
+        public TestClassInt(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            TestClassInt other = (TestClassInt) obj;
+            return x == other.x && y == other.y && z == other.z;
+        }
+
+        @Override
+        public String toString() {
+            return "{" + x + "," + y + "}";
+        }
+
+        @Override
+        public int hashCode() {
+            return x + 13 * y;
+        }
+    }
+
+    public static class TestClassObject {
+        public Object x;
+        public Object y;
+
+        public TestClassObject() {
+            this(null, null);
+        }
+
+        public TestClassObject(Object x) {
+            this(x, null);
+        }
+
+        public TestClassObject(Object x, Object y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            TestClassObject other = (TestClassObject) obj;
+            return x == other.x && y == other.y;
+        }
+
+        @Override
+        public String toString() {
+            return "{" + x + "," + y + "}";
+        }
+
+        @Override
+        public int hashCode() {
+            return (x == null ? 0 : x.hashCode()) + 13 * (y == null ? 0 : y.hashCode());
+        }
+    }
+
+    protected static native void notInlineable();
+
+    protected StructuredGraph graph;
+    protected HighTierContext context;
+    protected List<ReturnNode> returnNodes;
+
+    /**
+     * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the
+     * graph.
+     *
+     * @param snippet the name of the method whose graph should be processed
+     * @param expectedConstantResult if this is non-null, the resulting graph needs to have the
+     *            given constant return value
+     * @param iterativeEscapeAnalysis true if escape analysis should be run for more than one
+     *            iteration
+     */
+    protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) {
+        prepareGraph(snippet, iterativeEscapeAnalysis);
+        if (expectedConstantResult != null) {
+            for (ReturnNode returnNode : returnNodes) {
+                Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
+                Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
+            }
+        }
+        int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() +
+                        graph.getNodes().filter(CommitAllocationNode.class).count();
+        Assert.assertEquals(0, newInstanceCount);
+    }
+
+    @SuppressWarnings("try")
+    protected void prepareGraph(String snippet, boolean iterativeEscapeAnalysis) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
+        try (Scope s = Debug.scope(getClass(), method, getCodeCache())) {
+            graph = parseEager(method, AllowAssumptions.YES);
+            context = getDefaultHighTierContext();
+            new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
+            new CanonicalizerPhase().apply(graph, context);
+            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null).apply(graph, context);
+            returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java
new file mode 100644
index 0000000..804f04f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+
+public class EarlyReadEliminationTest extends GraalCompilerTest {
+
+    public static Object staticField;
+
+    public static class TestObject {
+
+        public int x;
+        public int y;
+
+        public TestObject(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    public static class TestObject2 {
+
+        public Object x;
+        public Object y;
+
+        public TestObject2(Object x, Object y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    public static class TestObject3 extends TestObject {
+
+        public int z;
+
+        public TestObject3(int x, int y, int z) {
+            super(x, y);
+            this.z = z;
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleSnippet(TestObject a) {
+        a.x = 2;
+        staticField = a;
+        return a.x;
+    }
+
+    @Test
+    public void testSimple() {
+        // Test without lowering.
+        ValueNode result = getReturn("testSimpleSnippet", false).result();
+        assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
+        assertTrue(result.isConstant());
+        assertDeepEquals(2, result.asJavaConstant().asInt());
+
+        // Test with lowering.
+        result = getReturn("testSimpleSnippet", true).result();
+        assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty());
+        assertTrue(result.isConstant());
+        assertDeepEquals(2, result.asJavaConstant().asInt());
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleConflictSnippet(TestObject a, TestObject b) {
+        a.x = 2;
+        b.x = 3;
+        staticField = a;
+        return a.x;
+    }
+
+    @Test
+    public void testSimpleConflict() {
+        ValueNode result = getReturn("testSimpleConflictSnippet", false).result();
+        assertFalse(result.isConstant());
+        assertTrue(result instanceof LoadFieldNode);
+    }
+
+    @SuppressWarnings("all")
+    public static int testParamSnippet(TestObject a, int b) {
+        a.x = b;
+        return a.x;
+    }
+
+    @Test
+    public void testParam() {
+        ValueNode result = getReturn("testParamSnippet", false).result();
+        assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
+        assertDeepEquals(result.graph().getParameter(1), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testMaterializedSnippet(int a) {
+        TestObject obj = new TestObject(a, 0);
+        staticField = obj;
+        return obj.x;
+    }
+
+    @Test
+    public void testMaterialized() {
+        ValueNode result = getReturn("testMaterializedSnippet", false).result();
+        assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
+        assertDeepEquals(result.graph().getParameter(0), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testSimpleLoopSnippet(TestObject obj, int a, int b) {
+        obj.x = a;
+        for (int i = 0; i < 10; i++) {
+            staticField = obj;
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testSimpleLoop() {
+        // Test without lowering.
+        ValueNode result = getReturn("testSimpleLoopSnippet", false).result();
+        assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
+        assertDeepEquals(result.graph().getParameter(1), result);
+
+        // Now test with lowering.
+        result = getReturn("testSimpleLoopSnippet", true).result();
+        assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty());
+        assertDeepEquals(result.graph().getParameter(1), result);
+    }
+
+    @SuppressWarnings("all")
+    public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) {
+        obj.x = a;
+        for (int i = 0; i < 10; i++) {
+            staticField = obj;
+            obj2.x = 10;
+            obj.x = 0;
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testBadLoop() {
+        ValueNode result = getReturn("testBadLoopSnippet", false).result();
+        assertDeepEquals(0, result.graph().getNodes().filter(LoadFieldNode.class).count());
+        assertTrue(result instanceof ProxyNode);
+        assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode);
+    }
+
+    @SuppressWarnings("all")
+    public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) {
+        obj.x = a;
+        for (int i = 0; i < 10; i++) {
+            obj.x = 0;
+            obj2.x = 10;
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testBadLoop2() {
+        ValueNode result = getReturn("testBadLoop2Snippet", false).result();
+        assertDeepEquals(1, result.graph().getNodes().filter(LoadFieldNode.class).count());
+        assertTrue(result instanceof LoadFieldNode);
+    }
+
+    @SuppressWarnings("all")
+    public static int testPhiSnippet(TestObject a, int b) {
+        if (b < 0) {
+            a.x = 1;
+        } else {
+            a.x = 2;
+        }
+        return a.x;
+    }
+
+    @Test
+    public void testPhi() {
+        StructuredGraph graph = processMethod("testPhiSnippet", false);
+        assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
+        List<ReturnNode> returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
+        assertDeepEquals(2, returnNodes.size());
+        assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode);
+        assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode);
+        assertTrue(returnNodes.get(0).result().isConstant());
+        assertTrue(returnNodes.get(1).result().isConstant());
+    }
+
+    @SuppressWarnings("all")
+    public static void testSimpleStoreSnippet(TestObject a, int b) {
+        a.x = b;
+        a.x = b;
+    }
+
+    @Test
+    public void testSimpleStore() {
+        StructuredGraph graph = processMethod("testSimpleStoreSnippet", false);
+        assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
+    }
+
+    public static int testValueProxySnippet(boolean b, TestObject o) {
+        int sum = 0;
+        if (b) {
+            sum += o.x;
+        } else {
+            TestObject3 p = (TestObject3) o;
+            sum += p.x;
+        }
+        sum += o.x;
+        return sum;
+    }
+
+    @Test
+    public void testValueProxy() {
+        StructuredGraph graph = processMethod("testValueProxySnippet", false);
+        assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
+    }
+
+    ReturnNode getReturn(String snippet, boolean doLowering) {
+        StructuredGraph graph = processMethod(snippet, doLowering);
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        return graph.getNodes(ReturnNode.TYPE).first();
+    }
+
+    protected StructuredGraph processMethod(String snippet, boolean doLowering) {
+        StructuredGraph graph = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        if (doLowering) {
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        }
+        new EarlyReadEliminationPhase(new CanonicalizerPhase()).apply(graph, context);
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java
new file mode 100644
index 0000000..ebb431f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
+import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+/**
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
+ */
+public class EscapeAnalysisTest extends EATestBase {
+
+    @Test
+    public void test1() {
+        testEscapeAnalysis("test1Snippet", JavaConstant.forInt(101), false);
+    }
+
+    public static int test1Snippet() {
+        Integer x = new Integer(101);
+        return x.intValue();
+    }
+
+    @Test
+    public void test2() {
+        testEscapeAnalysis("test2Snippet", JavaConstant.forInt(0), false);
+    }
+
+    public static int test2Snippet() {
+        Integer[] x = new Integer[0];
+        return x.length;
+    }
+
+    @Test
+    public void test3() {
+        testEscapeAnalysis("test3Snippet", JavaConstant.NULL_POINTER, false);
+    }
+
+    public static Object test3Snippet() {
+        Integer[] x = new Integer[1];
+        return x[0];
+    }
+
+    @Test
+    public void testMonitor() {
+        testEscapeAnalysis("testMonitorSnippet", JavaConstant.forInt(0), false);
+    }
+
+    public static int testMonitorSnippet() {
+        Integer x = new Integer(0);
+        Double y = new Double(0);
+        Object z = new Object();
+        synchronized (x) {
+            synchronized (y) {
+                synchronized (z) {
+                    notInlineable();
+                }
+            }
+        }
+        return x.intValue();
+    }
+
+    @Test
+    public void testMonitor2() {
+        testEscapeAnalysis("testMonitor2Snippet", JavaConstant.forInt(0), false);
+    }
+
+    /**
+     * This test case differs from the last one in that it requires inlining within a synchronized
+     * region.
+     */
+    public static int testMonitor2Snippet() {
+        Integer x = new Integer(0);
+        Double y = new Double(0);
+        Object z = new Object();
+        synchronized (x) {
+            synchronized (y) {
+                synchronized (z) {
+                    notInlineable();
+                    return x.intValue();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testMerge() {
+        testEscapeAnalysis("testMerge1Snippet", JavaConstant.forInt(0), true);
+    }
+
+    public static int testMerge1Snippet(int a) {
+        TestClassInt obj = new TestClassInt(1, 0);
+        if (a < 0) {
+            obj.x = obj.x + 1;
+        } else {
+            obj.x = obj.x + 2;
+            obj.y = 0;
+        }
+        if (obj.x > 1000) {
+            return 1;
+        }
+        return obj.y;
+    }
+
+    @Test
+    public void testSimpleLoop() {
+        testEscapeAnalysis("testSimpleLoopSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testSimpleLoopSnippet(int a) {
+        TestClassInt obj = new TestClassInt(1, 2);
+        for (int i = 0; i < a; i++) {
+            notInlineable();
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testModifyingLoop() {
+        testEscapeAnalysis("testModifyingLoopSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testModifyingLoopSnippet(int a) {
+        TestClassInt obj = new TestClassInt(1, 2);
+        for (int i = 0; i < a; i++) {
+            obj.x = 3;
+            notInlineable();
+        }
+        return obj.x <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testMergeAllocationsInt() {
+        testEscapeAnalysis("testMergeAllocationsIntSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsIntSnippet(int a) {
+        TestClassInt obj;
+        if (a < 0) {
+            obj = new TestClassInt(1, 2);
+            notInlineable();
+        } else {
+            obj = new TestClassInt(1, 2);
+            notInlineable();
+        }
+        return obj.x <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testMergeAllocationsObj() {
+        testEscapeAnalysis("testMergeAllocationsObjSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsObjSnippet(int a) {
+        TestClassObject obj;
+        Integer one = 1;
+        Integer two = 2;
+        Integer three = 3;
+        if (a < 0) {
+            obj = new TestClassObject(one, two);
+            notInlineable();
+        } else {
+            obj = new TestClassObject(one, three);
+            notInlineable();
+        }
+        return ((Integer) obj.x).intValue() <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testMergeAllocationsObjCirc() {
+        testEscapeAnalysis("testMergeAllocationsObjCircSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsObjCircSnippet(int a) {
+        TestClassObject obj;
+        Integer one = 1;
+        Integer two = 2;
+        Integer three = 3;
+        if (a < 0) {
+            obj = new TestClassObject(one);
+            obj.y = obj;
+            obj.y = two;
+            notInlineable();
+        } else {
+            obj = new TestClassObject(one);
+            obj.y = obj;
+            obj.y = three;
+            notInlineable();
+        }
+        return ((Integer) obj.x).intValue() <= 3 ? 1 : 0;
+    }
+
+    static class MyException extends RuntimeException {
+
+        private static final long serialVersionUID = 0L;
+
+        protected Integer value;
+
+        MyException(Integer value) {
+            super((Throwable) null);
+            this.value = value;
+        }
+
+        @SuppressWarnings("sync-override")
+        @Override
+        public final Throwable fillInStackTrace() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testMergeAllocationsException() {
+        testEscapeAnalysis("testMergeAllocationsExceptionSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsExceptionSnippet(int a) {
+        MyException obj;
+        Integer one = 1;
+        if (a < 0) {
+            obj = new MyException(one);
+            notInlineable();
+        } else {
+            obj = new MyException(one);
+            notInlineable();
+        }
+        return obj.value <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testCheckCast() {
+        testEscapeAnalysis("testCheckCastSnippet", getSnippetReflection().forObject(TestClassObject.class), false);
+    }
+
+    public Object testCheckCastSnippet() {
+        TestClassObject obj = new TestClassObject(TestClassObject.class);
+        TestClassObject obj2 = new TestClassObject(obj);
+        return ((TestClassObject) obj2.x).x;
+    }
+
+    @Test
+    public void testInstanceOf() {
+        testEscapeAnalysis("testInstanceOfSnippet", JavaConstant.forInt(1), false);
+    }
+
+    public boolean testInstanceOfSnippet() {
+        TestClassObject obj = new TestClassObject(TestClassObject.class);
+        TestClassObject obj2 = new TestClassObject(obj);
+        return obj2.x instanceof TestClassObject;
+    }
+
+    @SuppressWarnings("unused")
+    public static void testNewNodeSnippet() {
+        new ValueAnchorNode(null);
+    }
+
+    /**
+     * This test makes sure that the allocation of a {@link Node} can be removed. It therefore also
+     * tests the intrinsification of {@link Object#getClass()}.
+     */
+    @Test
+    public void testNewNode() {
+        testEscapeAnalysis("testNewNodeSnippet", null, false);
+    }
+
+    private static final TestClassObject staticObj = new TestClassObject();
+
+    public static Object testFullyUnrolledLoopSnippet() {
+        /*
+         * This tests a case that can appear if PEA is performed both before and after loop
+         * unrolling/peeling: If the VirtualInstanceNode is not duplicated correctly with the loop,
+         * the resulting object will reference itself, and not a second (different) object.
+         */
+        TestClassObject obj = staticObj;
+        for (int i = 0; i < 2; i++) {
+            obj = new TestClassObject(obj);
+        }
+        return obj.x;
+    }
+
+    @Test
+    public void testFullyUnrolledLoop() {
+        prepareGraph("testFullyUnrolledLoopSnippet", false);
+        new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
+        new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
+        Assert.assertEquals(1, returnNodes.size());
+        Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode);
+        CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit();
+        Assert.assertEquals(2, commit.getValues().size());
+        Assert.assertEquals(1, commit.getVirtualObjects().size());
+        Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0));
+    }
+
+    @SuppressWarnings("unused") private static Object staticField;
+
+    private static TestClassObject inlinedPart(TestClassObject obj) {
+        TestClassObject ret = new TestClassObject(obj);
+        staticField = null;
+        return ret;
+    }
+
+    public static Object testPeeledLoopSnippet() {
+        TestClassObject obj = staticObj;
+        int i = 0;
+        do {
+            obj = inlinedPart(obj);
+        } while (i++ < 10);
+        staticField = obj;
+        return obj.x;
+    }
+
+    @Test
+    public void testPeeledLoop() {
+        prepareGraph("testPeeledLoopSnippet", false);
+        new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, getDefaultHighTierContext());
+        new SchedulePhase().apply(graph);
+    }
+
+    public static void testDeoptMonitorSnippetInner(Object o2, Object t, int i) {
+        staticField = null;
+        if (i == 0) {
+            staticField = o2;
+            Number n = (Number) t;
+            n.toString();
+        }
+    }
+
+    public static void testDeoptMonitorSnippet(Object t, int i) {
+        TestClassObject o = new TestClassObject();
+        TestClassObject o2 = new TestClassObject(o);
+
+        synchronized (o) {
+            testDeoptMonitorSnippetInner(o2, t, i);
+        }
+    }
+
+    @Test
+    public void testDeoptMonitor() {
+        test("testDeoptMonitorSnippet", new Object(), 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/NestedBoxingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/NestedBoxingTest.java
new file mode 100644
index 0000000..7ab8b89
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/NestedBoxingTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import org.junit.Test;
+
+public class NestedBoxingTest extends EATestBase {
+
+    @Test
+    public void testSimpleMerge() {
+        testEscapeAnalysis("testSnippet", null, false);
+    }
+
+    public static int testSnippet(int n) {
+        Integer cur = 1;
+        Integer prev = 1;
+
+        for (int i = 0; i < n; i++) {
+            Integer next = prev + cur;
+            prev = cur;
+            cur = next;
+        }
+        return cur;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java
new file mode 100644
index 0000000..8c3f702
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.code.SourceStackTraceBailoutException;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+public class PEAAssertionsTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    public static void snippet1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+    }
+
+    @Test
+    public void test1() {
+        test("snippet1", 1);
+    }
+
+    public static void snippet2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void test2() {
+        test("snippet2", 1);
+    }
+
+    public static void snippet3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void test3() {
+        test("snippet3", 1);
+    }
+
+    public static void snippetHere1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+    }
+
+    @Test
+    public void testHere1() {
+        test("snippetHere1", 1);
+    }
+
+    public static void snippetHere2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+        field = object;
+    }
+
+    @Test
+    public void testHere2() {
+        test("snippetHere2", 1);
+    }
+
+    public static void snippetHere3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testHere3() {
+        test("snippetHere3", 1);
+    }
+
+    public static void snippetBoxing1(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testBoxing1() {
+        test("snippetBoxing1", 1);
+    }
+
+    public static void snippetBoxing2(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualized(object); // assert here
+        field = object;
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testBoxing2() {
+        test("snippetBoxing2", 1);
+    }
+
+    public static void snippetControlFlow1(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        GraalDirectives.controlFlowAnchor();
+        field = object;
+    }
+
+    @Test
+    public void testControlFlow1() {
+        test("snippetControlFlow1", true, 1);
+    }
+
+    public static void snippetControlFlow2(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        } else {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        GraalDirectives.controlFlowAnchor();
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testControlFlow2() {
+        test("snippetControlFlow2", true, 1);
+    }
+
+    public static void snippetControlFlow3(boolean b, int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        if (b) {
+            field = 1;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.controlFlowAnchor();
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testControlFlow3() {
+        test("snippetControlFlow3", true, 1);
+    }
+
+    public static void snippetControlFlow4(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testControlFlow4() {
+        test("snippetControlFlow4", true, 1);
+    }
+
+    public static void snippetControlFlow5(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testControlFlow5() {
+        test("snippetControlFlow5", true, 1);
+    }
+
+    public static final class TestClass {
+        Object a;
+        Object b;
+    }
+
+    public static void snippetIndirect1(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(object);
+
+        if (b) {
+            field = t; // assert here
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test(expected = SourceStackTraceBailoutException.class)
+    public void testIndirect1() {
+        test("snippetIndirect1", true, 1);
+    }
+
+    public static void snippetIndirect2(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(t);
+
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test
+    public void testIndirect2() {
+        test("snippetIndirect2", true, 1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java
new file mode 100644
index 0000000..94ca538
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+public class PEAReadEliminationTest extends EarlyReadEliminationTest {
+
+    public static int testIndexed1Snippet(int[] array) {
+        array[1] = 1;
+        array[2] = 2;
+        array[3] = 3;
+        array[4] = 4;
+        array[5] = 5;
+        array[6] = 6;
+        return array[1] + array[2] + array[3] + array[4] + array[5] + array[6];
+    }
+
+    @Test
+    public void testIndexed1() {
+        StructuredGraph graph = processMethod("testIndexed1Snippet", false);
+        assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count());
+    }
+
+    public static int testIndexed2Snippet(int v, int[] array) {
+        array[1] = 1;
+        array[2] = 2;
+        array[3] = 3;
+        array[v] = 0;
+        array[4] = 4;
+        array[5] = 5;
+        array[6] = 6;
+        array[4] = 4;
+        array[5] = 5;
+        array[6] = 6;
+        return array[1] + array[2] + array[3] + array[4] + array[5] + array[6];
+    }
+
+    @Test
+    public void testIndexed2() {
+        StructuredGraph graph = processMethod("testIndexed2Snippet", false);
+        assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
+        assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count());
+    }
+
+    public static int testIndexed3Snippet(int v, int[] array, short[] array2) {
+        array[1] = 1;
+        array2[1] = 1;
+        array[2] = 2;
+        array2[2] = 2;
+        array[3] = 3;
+        array2[3] = 3;
+        array[v] = 0;
+        array[4] = 4;
+        array2[4] = 4;
+        array[5] = 5;
+        array2[5] = 5;
+        array[6] = 6;
+        array2[6] = 6;
+        return array[1] + array[2] + array[3] + array[4] + array[5] + array[6] + array2[1] + array2[2] + array2[3] + array2[4] + array2[5] + array2[6];
+    }
+
+    @Test
+    public void testIndexed3() {
+        StructuredGraph graph = processMethod("testIndexed3Snippet", false);
+        assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
+    }
+
+    private static native void nonInlineable();
+
+    public static int testIndexed4Snippet(int[] array) {
+        array[1] = 1;
+        array[2] = 2;
+        array[3] = 3;
+        nonInlineable();
+        array[4] = 4;
+        array[5] = 5;
+        array[6] = 6;
+        return array[1] + array[2] + array[3] + array[4] + array[5] + array[6];
+    }
+
+    @Test
+    public void testIndexed4() {
+        StructuredGraph graph = processMethod("testIndexed4Snippet", false);
+        assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
+    }
+
+    private static final long offsetInt1 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 1;
+    private static final long offsetInt2 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 2;
+
+    public static int testUnsafe1Snippet(int v, int[] array) {
+        int s = UNSAFE.getInt(array, offsetInt1);
+        UNSAFE.putInt(array, offsetInt1, v);
+        UNSAFE.putInt(array, offsetInt2, v);
+        return s + UNSAFE.getInt(array, offsetInt1) + UNSAFE.getInt(array, offsetInt2);
+    }
+
+    @Test
+    public void testUnsafe1() {
+        StructuredGraph graph = processMethod("testUnsafe1Snippet", false);
+        assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count());
+    }
+
+    public static int testUnsafe2Snippet(int v, Object array) {
+        int s = UNSAFE.getInt(array, offsetInt1);
+        UNSAFE.putInt(array, offsetInt1, v);
+        UNSAFE.putInt(array, offsetInt2, v);
+        return s + UNSAFE.getInt(array, offsetInt1) + UNSAFE.getInt(array, offsetInt2);
+    }
+
+    @Test
+    public void testUnsafe2() {
+        StructuredGraph graph = processMethod("testUnsafe2Snippet", false);
+        assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count());
+    }
+
+    private static final long offsetObject1 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 1;
+    private static final long offsetObject2 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 2;
+
+    public static int testUnsafe3Snippet(int v, Object[] array) {
+        int s = (Integer) UNSAFE.getObject(array, offsetObject1);
+        UNSAFE.putObject(array, offsetObject1, v);
+        UNSAFE.putObject(array, offsetObject2, v);
+        return s + (Integer) UNSAFE.getObject(array, offsetObject1) + (Integer) UNSAFE.getObject(array, offsetObject2);
+    }
+
+    @Test
+    public void testUnsafe3() {
+        StructuredGraph graph = processMethod("testUnsafe3Snippet", false);
+        assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count());
+    }
+
+    public static int testUnsafe4Snippet(int v, Object[] array) {
+        int s = (Integer) UNSAFE.getObject(array, offsetObject1);
+        UNSAFE.putObject(array, offsetObject1, v);
+        UNSAFE.putObject(array, offsetObject2, v);
+        array[v] = null;
+        return s + (Integer) UNSAFE.getObject(array, offsetObject1) + (Integer) UNSAFE.getObject(array, offsetObject2);
+    }
+
+    @Test
+    public void testUnsafe4() {
+        StructuredGraph graph = processMethod("testUnsafe4Snippet", false);
+        assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count());
+    }
+
+    private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
+    private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2;
+
+    public static int testUnsafe5Snippet(int v, long[] array) {
+        int s = UNSAFE.getInt(array, offsetLong1);
+        UNSAFE.putInt(array, offsetLong1, v);
+        UNSAFE.putInt(array, offsetLong2, v);
+        return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2);
+    }
+
+    @Test
+    public void testUnsafe5() {
+        StructuredGraph graph = processMethod("testUnsafe5Snippet", false);
+        assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count());
+    }
+
+    @Override
+    protected StructuredGraph processMethod(final String snippet, boolean doLowering) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new PartialEscapePhase(false, true, new CanonicalizerPhase(), null).apply(graph, context);
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java
new file mode 100644
index 0000000..206ee38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import java.lang.ref.SoftReference;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.TypeSystemTest;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+
+/**
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
+ */
+public class PartialEscapeAnalysisTest extends EATestBase {
+
+    public static class TestObject {
+
+        public int x;
+        public int y;
+
+        public TestObject(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    public static class TestObject2 {
+
+        public Object x;
+        public Object y;
+
+        public TestObject2(Object x, Object y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    @Test
+    public void test1() {
+        testPartialEscapeAnalysis("test1Snippet", 0.25, 1);
+    }
+
+    @SuppressWarnings("all")
+    public static Object test1Snippet(int a, int b, Object x, Object y) {
+        TestObject2 obj = new TestObject2(x, y);
+        if (a < 0) {
+            if (b < 0) {
+                return obj;
+            } else {
+                return obj.y;
+            }
+        } else {
+            return obj.x;
+        }
+    }
+
+    @Test
+    public void test2() {
+        testPartialEscapeAnalysis("test2Snippet", 1.5, 3, LoadIndexedNode.class);
+    }
+
+    public static Object test2Snippet(int a, Object x, Object y, Object z) {
+        TestObject2 obj = new TestObject2(x, y);
+        obj.x = new TestObject2(obj, z);
+        if (a < 0) {
+            ((TestObject2) obj.x).y = null;
+            obj.y = null;
+            return obj;
+        } else {
+            ((TestObject2) obj.x).y = Integer.class;
+            ((TestObject2) obj.x).x = null;
+            return obj.x;
+        }
+    }
+
+    @Test
+    public void test3() {
+        testPartialEscapeAnalysis("test3Snippet", 0.5, 1, StoreFieldNode.class, LoadFieldNode.class);
+    }
+
+    public static Object test3Snippet(int a) {
+        if (a < 0) {
+            TestObject obj = new TestObject(1, 2);
+            obj.x = 123;
+            obj.y = 234;
+            obj.x = 123111;
+            obj.y = new Integer(123).intValue();
+            return obj;
+        } else {
+            return null;
+        }
+    }
+
+    @Test
+    public void testArrayCopy() {
+        testPartialEscapeAnalysis("testArrayCopySnippet", 0, 0);
+    }
+
+    public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"};
+
+    public static Object testArrayCopySnippet(int a) {
+        Object[] tmp = new Object[]{a != 1 ? array[a] : null};
+        Object[] tmp2 = new Object[5];
+        System.arraycopy(tmp, 0, tmp2, 4, 1);
+        return tmp2[4];
+    }
+
+    @Test
+    @Ignore
+    public void testCache() {
+        testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1);
+    }
+
+    public static class CacheKey {
+
+        private final int idx;
+        private final Object ref;
+
+        public CacheKey(int idx, Object ref) {
+            this.idx = idx;
+            this.ref = ref;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * idx + ref.hashCode();
+        }
+
+        public synchronized boolean equals(CacheKey other) {
+            return idx == other.idx && ref == other.ref;
+        }
+    }
+
+    public static CacheKey cacheKey = null;
+    public static Object value = null;
+
+    private static native Object createValue(CacheKey key);
+
+    public static Object testCacheSnippet(int idx, Object ref) {
+        CacheKey key = new CacheKey(idx, ref);
+        if (!key.equals(cacheKey)) {
+            cacheKey = key;
+            value = createValue(key);
+        }
+        return value;
+    }
+
+    public static int testReference1Snippet(Object a) {
+        SoftReference<Object> softReference = new SoftReference<>(a);
+        if (softReference.get().hashCode() == 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @Test
+    public void testReference1() {
+        prepareGraph("testReference1Snippet", false);
+        assertDeepEquals(1, graph.getNodes().filter(NewInstanceNode.class).count());
+    }
+
+    public static int testCanonicalizeSnippet(int v) {
+        CacheKey key = new CacheKey(v, null);
+
+        CacheKey key2;
+        if (key.idx == v) {
+            key2 = new CacheKey(v, null);
+        } else {
+            key2 = null;
+        }
+        return key2.idx;
+    }
+
+    @Test
+    public void testCanonicalize() {
+        prepareGraph("testCanonicalizeSnippet", false);
+        assertTrue(graph.getNodes().filter(ReturnNode.class).count() == 1);
+        assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0));
+    }
+
+    public static int testBoxLoopSnippet(int n) {
+        Integer sum = 0;
+        for (Integer i = 0; i < n; i++) {
+            if (sum == null) {
+                sum = null;
+            } else {
+                sum += i;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void testBoxLoop() {
+        testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class);
+    }
+
+    static volatile int staticField;
+    static boolean executedDeoptimizeDirective;
+
+    static class A {
+        String field;
+    }
+
+    public static Object deoptWithVirtualObjectsSnippet() {
+        A a = new A();
+        a.field = "field";
+
+        staticField = 5;
+        if (staticField == 5) {
+            GraalDirectives.deoptimize();
+            executedDeoptimizeDirective = true;
+        }
+
+        return a.field;
+    }
+
+    /**
+     * Tests deoptimizing with virtual objects in debug info.
+     */
+    @Test
+    public void testDeoptWithVirtualObjects() {
+        assertFalse(executedDeoptimizeDirective);
+        test("deoptWithVirtualObjectsSnippet");
+        assertTrue(executedDeoptimizeDirective);
+    }
+
+    @SafeVarargs
+    protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
+        prepareGraph(snippet, false);
+        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
+            merge.setStateAfter(null);
+        }
+        new DeadCodeEliminationPhase().apply(graph);
+        new CanonicalizerPhase().apply(graph, context);
+        try {
+            Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty());
+            Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty());
+
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            double probabilitySum = 0;
+            int materializeCount = 0;
+            for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) {
+                probabilitySum += cfg.blockFor(materialize).probability() * materialize.getVirtualObjects().size();
+                materializeCount += materialize.getVirtualObjects().size();
+            }
+            Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
+            Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01);
+            for (Node node : graph.getNodes()) {
+                for (Class<? extends Node> clazz : invalidNodeClasses) {
+                    Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty());
+                }
+            }
+        } catch (AssertionError e) {
+            TypeSystemTest.outputGraph(graph, snippet + ": " + e.getMessage());
+            throw e;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java
new file mode 100644
index 0000000..128ee5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * Tests {@link AbstractNewObjectNode#simplify(org.graalvm.compiler.graph.spi.SimplifierTool)}.
+ *
+ */
+public class PoorMansEATest extends GraalCompilerTest {
+    public static class A {
+        public A obj;
+    }
+
+    public static A test1Snippet() {
+        A a = new A();
+        a.obj = a;
+        return null;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    @SuppressWarnings("try")
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+            HighTierContext highTierContext = getDefaultHighTierContext();
+            new InliningPhase(new CanonicalizerPhase()).apply(graph, highTierContext);
+            PhaseContext context = new PhaseContext(getProviders());
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+
+            // remove framestates in order to trigger the simplification.
+            cleanup: for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) {
+                for (Node input : fs.inputs()) {
+                    if (input instanceof NewInstanceNode) {
+                        fs.replaceAtUsages(null);
+                        fs.safeDelete();
+                        continue cleanup;
+                    }
+                }
+            }
+            new CanonicalizerPhase().apply(graph, context);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java
new file mode 100644
index 0000000..fbfbd64
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.ea;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+
+public class UnsafeEATest extends EATestBase {
+
+    public static int zero = 0;
+
+    private static final long fieldOffset1;
+    private static final long fieldOffset2;
+
+    static {
+        try {
+            long localFieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("x"));
+            // Make the fields 8 byte aligned (Required for testing setLong on Architectures which
+            // does not support unaligned memory access
+            if (localFieldOffset1 % 8 == 0) {
+                fieldOffset1 = localFieldOffset1;
+                fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("y"));
+            } else {
+                fieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("y"));
+                fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("z"));
+            }
+            assert fieldOffset2 == fieldOffset1 + 4;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void testSimpleInt() {
+        testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false);
+    }
+
+    public static int testSimpleIntSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putInt(x, fieldOffset1, 101);
+        return UNSAFE.getInt(x, fieldOffset1);
+    }
+
+    @Test
+    public void testMaterializedInt() {
+        test("testMaterializedIntSnippet");
+    }
+
+    public static TestClassInt testMaterializedIntSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putInt(x, fieldOffset1, 101);
+        return x;
+    }
+
+    @Test
+    public void testSimpleDouble() {
+        testEscapeAnalysis("testSimpleDoubleSnippet", JavaConstant.forDouble(10.1), false);
+    }
+
+    public static double testSimpleDoubleSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putDouble(x, fieldOffset1, 10.1);
+        return UNSAFE.getDouble(x, fieldOffset1);
+    }
+
+    @Test
+    public void testMergedDouble() {
+        testEscapeAnalysis("testMergedDoubleSnippet", null, false);
+        Assert.assertEquals(1, returnNodes.size());
+        Assert.assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode);
+        PhiNode phi = (PhiNode) returnNodes.get(0).result();
+        Assert.assertTrue(phi.valueAt(0) instanceof LoadFieldNode);
+        Assert.assertTrue(phi.valueAt(1) instanceof LoadFieldNode);
+    }
+
+    public static double testMergedDoubleSnippet(boolean a) {
+        TestClassInt x;
+        if (a) {
+            x = new TestClassInt(0, 0);
+            UNSAFE.putDouble(x, fieldOffset1, doubleField);
+        } else {
+            x = new TestClassInt();
+            UNSAFE.putDouble(x, fieldOffset1, doubleField2);
+        }
+        return UNSAFE.getDouble(x, fieldOffset1);
+    }
+
+    @Test
+    public void testMaterializedDouble() {
+        test("testMaterializedDoubleSnippet");
+    }
+
+    public static TestClassInt testMaterializedDoubleSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putDouble(x, fieldOffset1, 10.1);
+        return x;
+    }
+
+    @Test
+    public void testDeoptDoubleVar() {
+        test("testDeoptDoubleVarSnippet");
+    }
+
+    public static double doubleField = 10.1e99;
+    public static double doubleField2;
+
+    public static TestClassInt testDeoptDoubleVarSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putDouble(x, fieldOffset1, doubleField);
+        doubleField2 = 123;
+        try {
+            doubleField = ((int) UNSAFE.getDouble(x, fieldOffset1)) / zero;
+        } catch (RuntimeException e) {
+            return x;
+        }
+        return x;
+    }
+
+    @Test
+    public void testDeoptDoubleConstant() {
+        test("testDeoptDoubleConstantSnippet");
+    }
+
+    public static TestClassInt testDeoptDoubleConstantSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putDouble(x, fieldOffset1, 10.123);
+        doubleField2 = 123;
+        try {
+            doubleField = ((int) UNSAFE.getDouble(x, fieldOffset1)) / zero;
+        } catch (RuntimeException e) {
+            return x;
+        }
+        return x;
+    }
+
+    @Test
+    public void testDeoptLongVar() {
+        test("testDeoptLongVarSnippet");
+    }
+
+    public static long longField = 0x133443218aaaffffL;
+    public static long longField2;
+
+    public static TestClassInt testDeoptLongVarSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putLong(x, fieldOffset1, longField);
+        longField2 = 123;
+        try {
+            longField = UNSAFE.getLong(x, fieldOffset1) / zero;
+        } catch (RuntimeException e) {
+            return x;
+        }
+        return x;
+    }
+
+    @Test
+    public void testDeoptLongConstant() {
+        test("testDeoptLongConstantSnippet");
+    }
+
+    public static TestClassInt testDeoptLongConstantSnippet() {
+        TestClassInt x = new TestClassInt();
+        UNSAFE.putLong(x, fieldOffset1, 0x2222222210123L);
+        longField2 = 123;
+        try {
+            longField = UNSAFE.getLong(x, fieldOffset1) / zero;
+        } catch (RuntimeException e) {
+            return x;
+        }
+        return x;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java
new file mode 100644
index 0000000..2c558b1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.inlining;
+
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class InliningTest extends GraalCompilerTest {
+
+    @Test
+    public void testInvokeStaticInlining() {
+        assertInlined(getGraph("invokeStaticSnippet", false));
+        assertInlined(getGraph("invokeStaticOnInstanceSnippet", false));
+    }
+
+    @SuppressWarnings("all")
+    public static Boolean invokeStaticSnippet(boolean value) {
+        return Boolean.valueOf(value);
+    }
+
+    @SuppressWarnings({"all", "static"})
+    public static Boolean invokeStaticOnInstanceSnippet(Boolean obj, boolean value) {
+        return obj.valueOf(value);
+    }
+
+    @Test
+    public void testStaticBindableInlining() {
+        assertInlined(getGraph("invokeConstructorSnippet", false));
+        assertInlined(getGraph("invokeFinalMethodSnippet", false));
+        assertInlined(getGraph("invokeMethodOnFinalClassSnippet", false));
+        assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", false));
+    }
+
+    @Ignore("would need read elimination/EA before inlining")
+    @Test
+    public void testDependentStaticBindableInlining() {
+        assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", false));
+        assertInlined(getGraph("invokeMethodOnFieldSnippet", false));
+    }
+
+    @Test
+    public void testStaticBindableInliningIP() {
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalClassSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", true)));
+    }
+
+    @Ignore("would need read elimination/EA before inlining")
+    @Test
+    public void testDependentStaticBindableInliningIP() {
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true)));
+    }
+
+    @SuppressWarnings("all")
+    public static Object invokeConstructorSnippet(int value) {
+        return new SuperClass(value);
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeFinalMethodSnippet(SuperClass superClass, SubClassA subClassA, FinalSubClass finalSubClass) {
+        return superClass.publicFinalMethod() + subClassA.publicFinalMethod() + finalSubClass.publicFinalMethod() + superClass.protectedFinalMethod() + subClassA.protectedFinalMethod() +
+                        finalSubClass.protectedFinalMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeMethodOnFinalClassSnippet(FinalSubClass finalSubClass) {
+        return finalSubClass.publicFinalMethod() + finalSubClass.publicNotOverriddenMethod() + finalSubClass.publicOverriddenMethod() + finalSubClass.protectedFinalMethod() +
+                        finalSubClass.protectedNotOverriddenMethod() + finalSubClass.protectedOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeMethodOnStaticFinalFieldSnippet() {
+        return StaticFinalFields.NumberStaticFinalField.intValue() + StaticFinalFields.SuperClassStaticFinalField.publicOverriddenMethod() +
+                        StaticFinalFields.FinalSubClassStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SingleImplementorStaticFinalField.publicOverriddenMethod() +
+                        StaticFinalFields.MultipleImplementorsStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassAStaticFinalField.publicOverriddenMethod() +
+                        StaticFinalFields.SubClassBStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassCStaticFinalField.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeMethodOnFinalFieldSnippet() {
+        FinalFields fields = new FinalFields();
+        return fields.numberFinalField.intValue() + fields.superClassFinalField.publicOverriddenMethod() + fields.finalSubClassFinalField.publicOverriddenMethod() +
+                        fields.singleImplementorFinalField.publicOverriddenMethod() + fields.multipleImplementorsFinalField.publicOverriddenMethod() +
+                        fields.subClassAFinalField.publicOverriddenMethod() + fields.subClassBFinalField.publicOverriddenMethod() + fields.subClassCFinalField.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeMethodOnFieldSnippet() {
+        Fields fields = new Fields();
+        return fields.numberField.intValue() + fields.superClassField.publicOverriddenMethod() + fields.finalSubClassField.publicOverriddenMethod() +
+                        fields.singleImplementorField.publicOverriddenMethod() + fields.multipleImplementorsField.publicOverriddenMethod() + fields.subClassAField.publicOverriddenMethod() +
+                        fields.subClassBField.publicOverriddenMethod() + fields.subClassCField.publicOverriddenMethod();
+    }
+
+    public interface Attributes {
+
+        int getLength();
+    }
+
+    public class NullAttributes implements Attributes {
+
+        @Override
+        public int getLength() {
+            return 0;
+        }
+
+    }
+
+    public class TenAttributes implements Attributes {
+
+        @Override
+        public int getLength() {
+            return 10;
+        }
+
+    }
+
+    public int getAttributesLength(Attributes a) {
+        return a.getLength();
+    }
+
+    @Test
+    public void testGuardedInline() {
+        NullAttributes nullAttributes = new NullAttributes();
+        for (int i = 0; i < 10000; i++) {
+            getAttributesLength(nullAttributes);
+        }
+        getAttributesLength(new TenAttributes());
+
+        test("getAttributesLength", nullAttributes);
+        test("getAttributesLength", (Object) null);
+    }
+
+    @Test
+    public void testClassHierarchyAnalysis() {
+        assertInlined(getGraph("invokeLeafClassMethodSnippet", false));
+        assertInlined(getGraph("invokeConcreteMethodSnippet", false));
+        assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", false));
+        // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", false));
+
+        assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", false));
+        assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", false));
+        assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false));
+    }
+
+    @Test
+    public void testClassHierarchyAnalysisIP() {
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true)));
+        assertManyMethodInfopoints(assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", true)));
+        //@formatter:off
+        // assertInlineInfopoints(assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", true)));
+        //@formatter:on
+
+        assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", true)));
+        assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", true)));
+        assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", true)));
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeLeafClassMethodSnippet(SubClassA subClassA) {
+        return subClassA.publicFinalMethod() + subClassA.publicNotOverriddenMethod() + subClassA.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeConcreteMethodSnippet(SuperClass superClass) {
+        return superClass.publicNotOverriddenMethod() + superClass.protectedNotOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeSingleImplementorInterfaceSnippet(SingleImplementorInterface testInterface) {
+        return testInterface.publicNotOverriddenMethod() + testInterface.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeConcreteInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) {
+        return testInterface.publicNotOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeOverriddenInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) {
+        return testInterface.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeOverriddenPublicMethodSnippet(SuperClass superClass) {
+        return superClass.publicOverriddenMethod();
+    }
+
+    @SuppressWarnings("all")
+    public static int invokeOverriddenProtectedMethodSnippet(SuperClass superClass) {
+        return superClass.protectedOverriddenMethod();
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) {
+        try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet, true))) {
+            ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
+            StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES);
+            try (Scope s2 = Debug.scope("Inlining", graph)) {
+                PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode
+                                ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true))
+                                : getDefaultGraphBuilderSuite();
+                HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL);
+                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+                new CanonicalizerPhase().apply(graph, context);
+                new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+                new CanonicalizerPhase().apply(graph, context);
+                new DeadCodeEliminationPhase().apply(graph);
+                return graph;
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private static StructuredGraph assertInlined(StructuredGraph graph) {
+        return assertNotInGraph(graph, Invoke.class);
+    }
+
+    private static StructuredGraph assertNotInlined(StructuredGraph graph) {
+        return assertInGraph(graph, Invoke.class);
+    }
+
+    private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    private static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                return graph;
+            }
+        }
+        fail("Graph does not contain a node of class " + clazz.getName());
+        return graph;
+    }
+
+    private static int[] countMethodInfopoints(StructuredGraph graph) {
+        int start = 0;
+        int end = 0;
+        for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
+            if (ipn.getReason() == InfopointReason.METHOD_START) {
+                ++start;
+            } else if (ipn.getReason() == InfopointReason.METHOD_END) {
+                ++end;
+            }
+        }
+        return new int[]{start, end};
+    }
+
+    private static StructuredGraph assertManyMethodInfopoints(StructuredGraph graph) {
+        int[] counts = countMethodInfopoints(graph);
+        if (counts[0] <= 1 || counts[1] <= 1) {
+            fail(String.format("Graph contains too few required method boundary infopoints: %d starts, %d ends.", counts[0], counts[1]));
+        }
+        return graph;
+    }
+
+    private static StructuredGraph assertFewMethodInfopoints(StructuredGraph graph) {
+        int[] counts = countMethodInfopoints(graph);
+        if (counts[0] > 1 || counts[1] > 1) {
+            fail(String.format("Graph contains too many method boundary infopoints: %d starts, %d ends.", counts[0], counts[1]));
+        }
+        return graph;
+    }
+
+    // some interfaces and classes for testing
+    private interface MultipleImplementorsInterface {
+
+        int publicNotOverriddenMethod();
+
+        int publicOverriddenMethod();
+    }
+
+    private interface SingleImplementorInterface {
+
+        int publicNotOverriddenMethod();
+
+        int publicOverriddenMethod();
+    }
+
+    private static class SuperClass implements MultipleImplementorsInterface {
+
+        protected int value;
+
+        SuperClass(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public int publicNotOverriddenMethod() {
+            return value;
+        }
+
+        @Override
+        public int publicOverriddenMethod() {
+            return value;
+        }
+
+        protected int protectedNotOverriddenMethod() {
+            return value;
+        }
+
+        protected int protectedOverriddenMethod() {
+            return value;
+        }
+
+        public final int publicFinalMethod() {
+            return value + 255;
+        }
+
+        protected final int protectedFinalMethod() {
+            return value + 255;
+        }
+    }
+
+    private static class SubClassA extends SuperClass implements SingleImplementorInterface {
+
+        SubClassA(int value) {
+            super(value);
+        }
+
+        @Override
+        public int publicOverriddenMethod() {
+            return value + 2;
+        }
+
+        @Override
+        protected int protectedOverriddenMethod() {
+            return value * 2;
+        }
+    }
+
+    private static class SubClassB extends SuperClass {
+
+        SubClassB(int value) {
+            super(value);
+        }
+
+        @Override
+        public int publicOverriddenMethod() {
+            return value + 3;
+        }
+
+        @Override
+        protected int protectedOverriddenMethod() {
+            return value * 3;
+        }
+    }
+
+    private static class SubClassC extends SuperClass {
+
+        SubClassC(int value) {
+            super(value);
+        }
+
+        @Override
+        public int publicOverriddenMethod() {
+            return value + 4;
+        }
+
+        @Override
+        protected int protectedOverriddenMethod() {
+            return value * 4;
+        }
+    }
+
+    private static final class FinalSubClass extends SuperClass {
+
+        FinalSubClass(int value) {
+            super(value);
+        }
+
+        @Override
+        public int publicOverriddenMethod() {
+            return value + 5;
+        }
+
+        @Override
+        protected int protectedOverriddenMethod() {
+            return value * 5;
+        }
+    }
+
+    private static final class StaticFinalFields {
+
+        private static final Number NumberStaticFinalField = new Integer(1);
+        private static final SuperClass SuperClassStaticFinalField = new SubClassA(2);
+        private static final FinalSubClass FinalSubClassStaticFinalField = new FinalSubClass(3);
+        private static final SingleImplementorInterface SingleImplementorStaticFinalField = new SubClassA(4);
+        private static final MultipleImplementorsInterface MultipleImplementorsStaticFinalField = new SubClassC(5);
+        private static final SubClassA SubClassAStaticFinalField = new SubClassA(6);
+        private static final SubClassB SubClassBStaticFinalField = new SubClassB(7);
+        private static final SubClassC SubClassCStaticFinalField = new SubClassC(8);
+    }
+
+    private static final class FinalFields {
+
+        private final Number numberFinalField = new Integer(1);
+        private final SuperClass superClassFinalField = new SubClassA(2);
+        private final FinalSubClass finalSubClassFinalField = new FinalSubClass(3);
+        private final SingleImplementorInterface singleImplementorFinalField = new SubClassA(4);
+        private final MultipleImplementorsInterface multipleImplementorsFinalField = new SubClassC(5);
+        private final SubClassA subClassAFinalField = new SubClassA(6);
+        private final SubClassB subClassBFinalField = new SubClassB(7);
+        private final SubClassC subClassCFinalField = new SubClassC(8);
+    }
+
+    private static final class Fields {
+
+        private Number numberField = new Integer(1);
+        private SuperClass superClassField = new SubClassA(2);
+        private FinalSubClass finalSubClassField = new FinalSubClass(3);
+        private SingleImplementorInterface singleImplementorField = new SubClassA(4);
+        private MultipleImplementorsInterface multipleImplementorsField = new SubClassC(5);
+        private SubClassA subClassAField = new SubClassA(6);
+        private SubClassB subClassBField = new SubClassB(7);
+        private SubClassC subClassCField = new SubClassC(8);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/RecursiveInliningTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/RecursiveInliningTest.java
new file mode 100644
index 0000000..4e1d784
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/RecursiveInliningTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.inlining;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+public class RecursiveInliningTest extends GraalCompilerTest {
+
+    public static int SideEffectI;
+    public static int[] Memory = new int[]{1, 2};
+
+    public static final Unsafe UNSAFE;
+    static {
+        try {
+            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafe.setAccessible(true);
+            UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("Exception while trying to get Unsafe", e);
+        }
+    }
+
+    public static void recursiveLoopMethodUnsafeLoad(int a) {
+        if (UNSAFE.getInt(Memory, (long) Unsafe.ARRAY_LONG_BASE_OFFSET) == 0) {
+            return;
+        }
+        for (int i = 0; i < a; i++) {
+            recursiveLoopMethodUnsafeLoad(i);
+        }
+    }
+
+    public static void recursiveLoopMethodFieldLoad(int a) {
+        if (SideEffectI == 0) {
+            return;
+        }
+        for (int i = 0; i < a; i++) {
+            recursiveLoopMethodFieldLoad(i);
+        }
+    }
+
+    public static void recursiveLoopMethod(int a) {
+        if (a == 0) {
+            return;
+        }
+        for (int i = 0; i < a; i++) {
+            recursiveLoopMethod(i);
+        }
+    }
+
+    public static final boolean LOG = false;
+
+    public static int IterationsStart = 1;
+    public static int IterationsEnd = 128;
+
+    @Test(timeout = 120_000)
+    public void inlineDirectRecursiveLoopCallUnsafeLoad() {
+        testAndTime("recursiveLoopMethodUnsafeLoad");
+    }
+
+    @Test(timeout = 120_000)
+    public void inlineDirectRecursiveLoopCallFieldLoad() {
+        testAndTime("recursiveLoopMethodFieldLoad");
+    }
+
+    @Test(timeout = 120_000)
+    public void inlineDirectRecursiveLoopCallNoReads() {
+        testAndTime("recursiveLoopMethod");
+    }
+
+    private void testAndTime(String snippet) {
+        for (int i = IterationsStart; i < IterationsEnd; i++) {
+            StructuredGraph graph = getGraph(snippet, i);
+            long elapsed = runAndTimeEarlyReadEliminationPhase(graph);
+            if (LOG) {
+                System.out.printf("Needed %dms to run early read elimination on a graph with %d recursive inlined calls of method %s\n", elapsed, i, graph.method());
+            }
+        }
+        for (int i = IterationsStart; i < IterationsEnd; i++) {
+            StructuredGraph graph = getGraph(snippet, i);
+            long elapsed = runAndTimePartialEscapeAnalysis(graph);
+            if (LOG) {
+                System.out.printf("Needed %dms to run early partial escape analysis on a graph with %d recursive inlined calls of method %s\n", elapsed, i, graph.method());
+            }
+        }
+    }
+
+    private long runAndTimePartialEscapeAnalysis(StructuredGraph g) {
+        PartialEscapePhase p = new PartialEscapePhase(true, new CanonicalizerPhase());
+        HighTierContext context = getDefaultHighTierContext();
+        long start = System.currentTimeMillis();
+        p.apply(g, context);
+        long end = System.currentTimeMillis();
+        Debug.dump(Debug.BASIC_LOG_LEVEL, g, "After PEA");
+        return end - start;
+    }
+
+    private long runAndTimeEarlyReadEliminationPhase(StructuredGraph g) {
+        EarlyReadEliminationPhase er = new EarlyReadEliminationPhase(new CanonicalizerPhase());
+        HighTierContext context = getDefaultHighTierContext();
+        long start = System.currentTimeMillis();
+        er.apply(g, context);
+        long end = System.currentTimeMillis();
+        Debug.dump(Debug.BASIC_LOG_LEVEL, g, "After Early Read Elimination");
+        return end - start;
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph getGraph(final String snippet, int nrOfInlinings) {
+        try (Scope s = Debug.scope("RecursiveInliningTest", new DebugDumpScope(snippet, true))) {
+            ResolvedJavaMethod callerMethod = getResolvedJavaMethod(snippet);
+            StructuredGraph callerGraph = parseEager(callerMethod, AllowAssumptions.YES);
+            PhaseSuite<HighTierContext> graphBuilderSuite = getDefaultGraphBuilderSuite();
+            HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+
+            for (int i = 0; i < nrOfInlinings; i++) {
+                InvokeNode next = getNextInvoke(callerGraph);
+                ResolvedJavaMethod calleeMethod = next.callTarget().targetMethod();
+                StructuredGraph calleeGraph = getInlineeGraph(next, callerGraph, context, canonicalizer);
+                List<Node> canonicalizeNodes = new ArrayList<>();
+                InliningUtil.inline(next, calleeGraph, false, canonicalizeNodes, calleeMethod);
+                canonicalizer.applyIncremental(callerGraph, context, canonicalizeNodes);
+                Debug.dump(Debug.BASIC_LOG_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i);
+            }
+            new SchedulePhase().apply(callerGraph);
+            return callerGraph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private static StructuredGraph getInlineeGraph(InvokeNode invoke, StructuredGraph caller, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), invoke.callTarget().targetMethod(), invoke.bci());
+        if (result != null) {
+            return result;
+        }
+        return parseBytecodes(invoke.callTarget().targetMethod(), context, canonicalizer, caller);
+    }
+
+    @SuppressWarnings("try")
+    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
+        StructuredGraph newGraph = new StructuredGraph(method, AllowAssumptions.from(caller.getAssumptions() != null), INVALID_COMPILATION_ID);
+        if (!caller.isUnsafeAccessTrackingEnabled()) {
+            newGraph.disableUnsafeAccessTracking();
+        }
+        if (context.getGraphBuilderSuite() != null) {
+            context.getGraphBuilderSuite().apply(newGraph, context);
+        }
+        assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined();
+        new DeadCodeEliminationPhase(Optional).apply(newGraph);
+        canonicalizer.apply(newGraph, context);
+        return newGraph;
+    }
+
+    private static InvokeNode getNextInvoke(StructuredGraph graph) {
+        return graph.getNodes().filter(InvokeNode.class).first();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java
new file mode 100644
index 0000000..815bb88
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.tutorial;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
+ * the examples in IGV (the graph visualization tool), use the {@code -Dgraal.Dump} and
+ * {@code -Dgraal.MethodFilter} options. For example, run the first test case using
+ *
+ * <pre>
+ * mx unittest -Dgraal.Dump= -Dgraal.MethodFilter=String.hashCode GraalTutorial#testStringHashCode
+ * </pre>
+ */
+public class GraalTutorial extends InvokeGraal {
+
+    /*
+     * Example for the Graal API: access the Graal API metadata object for a method.
+     */
+
+    @Test
+    public void testPrintBytecodes() {
+        ResolvedJavaMethod method = findMethod(String.class, "hashCode");
+        Bytecode bytecode = new ResolvedJavaMethodBytecode(method);
+
+        byte[] bytecodes = bytecode.getCode();
+        Assert.assertNotNull(bytecodes);
+
+        System.out.println(new BytecodeDisassembler().disassemble(bytecode));
+    }
+
+    /*
+     * A simple Graal compilation example: Compile the method String.hashCode()
+     */
+
+    @Test
+    public void testStringHashCode() throws InvalidInstalledCodeException {
+        int expectedResult = "Hello World".hashCode();
+
+        InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
+
+        int result = (int) installedCode.executeVarargs("Hello World");
+        Assert.assertEquals(expectedResult, result);
+    }
+
+    /*
+     * Tutorial example for speculative optimizations.
+     */
+
+    int f1;
+    int f2;
+
+    public void speculativeOptimization(boolean flag) {
+        f1 = 41;
+        if (flag) {
+            f2 = 42;
+            return;
+        }
+        f2 = 43;
+    }
+
+    @Test
+    public void testSpeculativeOptimization() throws InvalidInstalledCodeException {
+        /*
+         * Collect profiling information by running the method in the interpreter.
+         */
+
+        for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
+            speculativeOptimization(false);
+        }
+
+        /*
+         * Warmup to collect profiling information is done, now we compile the method. Since the
+         * value of "flag" was always false during the warmup, the compiled code speculates that the
+         * value remains false.
+         */
+
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
+        f1 = 0;
+        f2 = 0;
+        compiledMethod.executeVarargs(this, true);
+        Assert.assertEquals(41, f1);
+        Assert.assertEquals(42, f2);
+
+        /*
+         * We executed the compiled method with a "flag" value that triggered deoptimization (since
+         * the warmup always used the different "flag" value). The interpreter updated the profiling
+         * information, so the second compilation does not perform the speculative optimization.
+         */
+
+        compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
+        f1 = 0;
+        f2 = 0;
+        compiledMethod.executeVarargs(this, false);
+        Assert.assertEquals(41, f1);
+        Assert.assertEquals(43, f2);
+    }
+
+    /*
+     * Tutorial example for snippets and lowering.
+     */
+
+    static class A {
+    }
+
+    static class B extends A {
+    }
+
+    public static int instanceOfUsage(Object obj) {
+        if (obj instanceof A) {
+            return 42;
+        } else {
+            return 0;
+        }
+    }
+
+    @Test
+    public void testInstanceOfUsage() throws InvalidInstalledCodeException {
+        /*
+         * Collect profiling information by running the method in the interpreter.
+         */
+
+        A a = new A();
+        /* Allocate an (unused) instance of B so that the class B gets loaded. */
+        @SuppressWarnings("unused")
+        B b = new B();
+        int expectedResult = instanceOfUsage(a);
+        for (int i = 0; i < 10000; i++) {
+            /* Execute several times so that enough profiling information gets collected. */
+            instanceOfUsage(a);
+        }
+
+        /* Warmup to collect profiling information is done, now compile the method. */
+
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
+
+        int result = (int) compiledMethod.executeVarargs(a);
+        Assert.assertEquals(expectedResult, result);
+    }
+
+    /*
+     * Tutorial example for intrinsic methods.
+     */
+
+    public static double intrinsicUsage(double val) {
+        return Math.sin(val);
+    }
+
+    @Test
+    public void testIntrinsicUsage() throws InvalidInstalledCodeException {
+        double expectedResult = intrinsicUsage(42d);
+
+        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage"));
+
+        double result = (double) compiledMethod.executeVarargs(42d);
+        Assert.assertEquals(expectedResult, result, 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java
new file mode 100644
index 0000000..c722047
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.tutorial;
+
+import static org.graalvm.compiler.core.common.CompilationRequestIdentifier.asCompilationRequest;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Sample code that shows how to invoke Graal from an application.
+ */
+public class InvokeGraal {
+
+    protected final Backend backend;
+    protected final Providers providers;
+    protected final MetaAccessProvider metaAccess;
+    protected final CodeCacheProvider codeCache;
+
+    public InvokeGraal() {
+        /* Ask the hosting Java VM for the entry point object to the Graal API. */
+        RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class);
+
+        /*
+         * The default backend (architecture, VM configuration) that the hosting VM is running on.
+         */
+        backend = runtimeProvider.getHostBackend();
+        /* Access to all of the Graal API providers, as implemented by the hosting VM. */
+        providers = backend.getProviders();
+        /* Some frequently used providers and configuration objects. */
+        metaAccess = providers.getMetaAccess();
+        codeCache = providers.getCodeCache();
+    }
+
+    /**
+     * The simplest way to compile a method, using the default behavior for everything.
+     */
+    @SuppressWarnings("try")
+    protected InstalledCode compileAndInstallMethod(ResolvedJavaMethod method) {
+        /* Create a unique compilation identifier, visible in IGV. */
+        CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
+        try (Scope s = Debug.scope("compileAndInstallMethod", new DebugDumpScope(String.valueOf(compilationId), true))) {
+
+            /*
+             * The graph that is compiled. We leave it empty (no nodes added yet). This means that
+             * it will be filled according to the graphBuilderSuite defined below. We also specify
+             * that we want the compilation to make optimistic assumptions about runtime state such
+             * as the loaded class hierarchy.
+             */
+            StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.YES, compilationId);
+
+            /*
+             * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If
+             * the graph already contains nodes, it is ignored.
+             */
+            PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite();
+
+            /*
+             * The optimization phases that are applied to the graph. This is the main configuration
+             * point for Graal. Add or remove phases to customize your compilation.
+             */
+            Suites suites = backend.getSuites().getDefaultSuites();
+
+            /*
+             * The low-level phases that are applied to the low-level representation.
+             */
+            LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites();
+
+            /*
+             * We want Graal to perform all speculative optimistic optimizations, using the
+             * profiling information that comes with the method (collected by the interpreter) for
+             * speculation.
+             */
+            OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
+            ProfilingInfo profilingInfo = graph.getProfilingInfo(method);
+
+            /* The default class and configuration for compilation results. */
+            CompilationResult compilationResult = new CompilationResult();
+            CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
+
+            /* Invoke the whole Graal compilation pipeline. */
+            GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory);
+
+            /*
+             * Install the compilation result into the VM, i.e., copy the byte[] array that contains
+             * the machine code into an actual executable memory location.
+             */
+            return backend.addInstalledCode(method, asCompilationRequest(compilationId), compilationResult);
+        } catch (Throwable ex) {
+            throw Debug.handle(ex);
+        }
+    }
+
+    /**
+     * Look up a method using Java reflection and convert it to the Graal API method object.
+     */
+    protected ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
+        Method reflectionMethod = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (m.getName().equals(name)) {
+                assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName();
+                reflectionMethod = m;
+            }
+        }
+        assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
+        return metaAccess.lookupJavaMethod(reflectionMethod);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java
new file mode 100644
index 0000000..92898ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.tutorial;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.graph.StatelessPostOrderNodeIterator;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A simple context-insensitive static analysis based on the Graal API. It is intended for
+ * educational purposes, not for use in production. Only a limited set of Java functionality is
+ * supported to keep the code minimal.
+ * <p>
+ * The analysis builds a directed graph of {@link TypeFlow type flows}. If a type is added to type
+ * flow, it is propagated to all {@link TypeFlow#uses uses} of the type flow. Types are propagated
+ * using a {@link #worklist} of changed type flows until a fixpoint is reached, i.e., until no more
+ * types need to be added to any type state.
+ * <p>
+ * The type flows are constructed from a high-level Graal graph by the {@link TypeFlowBuilder}. All
+ * nodes that operate on {@link JavaKind#Object object} values are converted to the appropriate type
+ * flows. The analysis is context insensitive: every Java field has {@link Results#lookupField one
+ * list} of types assigned to the field; every Java method has {@link Results#lookupMethod one
+ * state} for each {@link MethodState#formalParameters parameter} as well as the
+ * {@link MethodState#formalReturn return value}.
+ */
+public class StaticAnalysis {
+    /** Access to type, method, and fields using the Graal API. */
+    private final MetaAccessProvider metaAccess;
+    /** Access to platform dependent stamps. */
+    private final StampProvider stampProvider;
+    /** The results of the static analysis. */
+    private final Results results;
+    /** Worklist for fixpoint iteration. */
+    private final Deque<WorklistEntry> worklist;
+
+    public StaticAnalysis(MetaAccessProvider metaAccess, StampProvider stampProvider) {
+        this.metaAccess = metaAccess;
+        this.stampProvider = stampProvider;
+        this.results = new Results();
+        this.worklist = new ArrayDeque<>();
+    }
+
+    /**
+     * Adds a root method to the static analysis. The method must be static and must not have any
+     * parameters, because the possible types of the parameters would not be known.
+     */
+    public void addMethod(ResolvedJavaMethod method) {
+        if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) {
+            error("Entry point method is not static or has parameters: " + method.format("%H.%n(%p)"));
+        }
+        addToWorklist(results.lookupMethod(method));
+    }
+
+    /**
+     * Performs the fixed-point analysis that finds all methods transitively reachable from the
+     * {@link #addMethod root methods}.
+     */
+    public void finish() {
+        while (!worklist.isEmpty()) {
+            worklist.removeFirst().process();
+        }
+    }
+
+    /**
+     * Returns the static analysis results computed by {@link StaticAnalysis#finish}.
+     */
+    public Results getResults() {
+        return results;
+    }
+
+    protected void addToWorklist(WorklistEntry task) {
+        worklist.addLast(task);
+    }
+
+    protected static RuntimeException error(String msg) {
+        throw GraalError.shouldNotReachHere(msg);
+    }
+
+    /**
+     * Base class for all work items that can be {@link #addToWorklist added to the worklist}.
+     */
+    abstract class WorklistEntry {
+        protected abstract void process();
+    }
+
+    /**
+     * The results computed by the static analysis.
+     */
+    public class Results {
+        private final TypeFlow allInstantiatedTypes;
+        private final Map<ResolvedJavaField, TypeFlow> fields;
+        private final Map<ResolvedJavaMethod, MethodState> methods;
+
+        protected Results() {
+            allInstantiatedTypes = new TypeFlow();
+            fields = new HashMap<>();
+            methods = new HashMap<>();
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that are found to be instantiated, i.e., all types
+         * allocated by the reachable instance and array allocation bytecodes.
+         */
+        public TypeFlow getAllInstantiatedTypes() {
+            return allInstantiatedTypes;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the given field can have, i.e., all types
+         * assigned by the reachable field store bytecodes.
+         */
+        public TypeFlow lookupField(ResolvedJavaField field) {
+            TypeFlow result = fields.get(field);
+            if (result == null) {
+                result = new TypeFlow();
+                fields.put(field, result);
+            }
+            return result;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that {@link MethodState#formalParameters
+         * parameters} and {@link MethodState#formalReturn return value} of the given method can
+         * have.
+         */
+        public MethodState lookupMethod(ResolvedJavaMethod method) {
+            MethodState result = methods.get(method);
+            if (result == null) {
+                result = new MethodState(method);
+                methods.put(method, result);
+            }
+            return result;
+        }
+    }
+
+    /**
+     * The {@link TypeFlow#getTypes() types} of the parameters and return value of a method. Also
+     * serves as the worklist element to parse the bytecodes of the method.
+     */
+    public class MethodState extends WorklistEntry {
+        private final ResolvedJavaMethod method;
+        private final TypeFlow[] formalParameters;
+        private final TypeFlow formalReturn;
+        private boolean processed;
+
+        protected MethodState(ResolvedJavaMethod method) {
+            this.method = method;
+
+            formalParameters = new TypeFlow[method.getSignature().getParameterCount(!method.isStatic())];
+            for (int i = 0; i < formalParameters.length; i++) {
+                formalParameters[i] = new TypeFlow();
+            }
+            formalReturn = new TypeFlow();
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the parameters of this method can have.
+         */
+        public TypeFlow[] getFormalParameters() {
+            return formalParameters;
+        }
+
+        /**
+         * All {@link TypeFlow#getTypes() types} that the return value of this method can have.
+         */
+        public TypeFlow getFormalReturn() {
+            return formalReturn;
+        }
+
+        @Override
+        @SuppressWarnings("try")
+        protected void process() {
+            if (!processed) {
+                /* We want to process a method only once. */
+                processed = true;
+
+                /*
+                 * Build the Graal graph for the method using the bytecode parser provided by Graal.
+                 */
+
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
+                /*
+                 * Support for graph dumping, IGV uses this information to show the method name of a
+                 * graph.
+                 */
+                try (Scope scope = Debug.scope("graph building", graph)) {
+                    /*
+                     * We want all types to be resolved by the graph builder, i.e., we want classes
+                     * referenced by the bytecodes to be loaded and initialized. Since we do not run
+                     * the code before static analysis, the classes would otherwise be not loaded
+                     * yet and the bytecode parser would only create a graph.
+                     */
+                    Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+                    /*
+                     * For simplicity, we ignore all exception handling during the static analysis.
+                     * This is a constraint of this example code, a real static analysis needs to
+                     * handle the Graal nodes for throwing and handling exceptions.
+                     */
+                    graphBuilderConfig = graphBuilderConfig.withBytecodeExceptionMode(BytecodeExceptionMode.OmitAll);
+                    /*
+                     * We do not want Graal to perform any speculative optimistic optimizations,
+                     * i.e., we do not want to use profiling information. Since we do not run the
+                     * code before static analysis, the profiling information is empty and therefore
+                     * wrong.
+                     */
+                    OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
+
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, null, graphBuilderConfig, optimisticOpts, null);
+                    graphBuilder.apply(graph);
+                } catch (Throwable ex) {
+                    Debug.handle(ex);
+                }
+
+                /*
+                 * Build the type flow graph from the Graal graph, i.e., process all nodes that are
+                 * deal with objects.
+                 */
+
+                TypeFlowBuilder typeFlowBuilder = new TypeFlowBuilder(graph);
+                typeFlowBuilder.apply();
+            }
+        }
+    }
+
+    /**
+     * The active element during static analysis: types are added until a fixed point is reached.
+     * When a new type is added, it is propagated to all usages by putting this element on the
+     * {@link StaticAnalysis#addToWorklist worklist}.
+     */
+    public class TypeFlow extends WorklistEntry {
+        private final Set<ResolvedJavaType> types;
+        private final Set<TypeFlow> uses;
+
+        protected TypeFlow() {
+            types = new HashSet<>();
+            uses = new HashSet<>();
+        }
+
+        /** Returns the types of this element. */
+        public Set<ResolvedJavaType> getTypes() {
+            return types;
+        }
+
+        /**
+         * Adds new types to this element. If that changes the state of this element, it is added to
+         * the {@link StaticAnalysis#addToWorklist worklist} in order to propagate the added types
+         * to all usages.
+         */
+        protected void addTypes(Set<ResolvedJavaType> newTypes) {
+            if (types.addAll(newTypes)) {
+                addToWorklist(this);
+            }
+        }
+
+        /**
+         * Adds a new use to this element. All types of this element are propagated to the new
+         * usage.
+         */
+        protected void addUse(TypeFlow use) {
+            if (uses.add(use)) {
+                use.addTypes(types);
+            }
+        }
+
+        /**
+         * Processing of the worklist element: propagate the types to all usages. That in turn can
+         * add the usages to the worklist (if the types of the usage are changed).
+         */
+        @Override
+        protected void process() {
+            for (TypeFlow use : uses) {
+                use.addTypes(types);
+            }
+        }
+    }
+
+    /**
+     * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and
+     * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this
+     * node are the receiver types. When a new receiver type is added, a new callee might be added.
+     * Adding a new callee means linking the type flow of the actual parameters with the formal
+     * parameters of the callee, and linking the return value of the callee with the return value
+     * state of the invocation.
+     *
+     * Statically bindable methods calls ({@link InvokeKind#Static static} and
+     * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for
+     * simplicity.
+     */
+    class InvokeTypeFlow extends TypeFlow {
+        private final MethodCallTargetNode callTarget;
+        private final TypeFlow[] actualParameters;
+        private final TypeFlow actualReturn;
+        private final Set<ResolvedJavaMethod> callees;
+
+        protected InvokeTypeFlow(MethodCallTargetNode callTarget, TypeFlow[] actualParameterFlows, TypeFlow actualReturnFlow) {
+            this.callTarget = callTarget;
+            this.actualParameters = actualParameterFlows;
+            this.actualReturn = actualReturnFlow;
+            this.callees = new HashSet<>();
+        }
+
+        private void linkCallee(ResolvedJavaMethod callee) {
+            if (callees.add(callee)) {
+                /* We have added a new callee. */
+
+                /*
+                 * Connect the actual parameters of the invocation with the formal parameters of the
+                 * callee.
+                 */
+                MethodState calleeState = results.lookupMethod(callee);
+                for (int i = 0; i < actualParameters.length; i++) {
+                    if (actualParameters[i] != null) {
+                        actualParameters[i].addUse(calleeState.formalParameters[i]);
+                    }
+                }
+
+                /*
+                 * Connect the formal return value of the callee with the actual return value of the
+                 * invocation.
+                 */
+                if (actualReturn != null) {
+                    calleeState.formalReturn.addUse(actualReturn);
+                }
+                addToWorklist(calleeState);
+            }
+        }
+
+        @Override
+        protected void process() {
+            if (callTarget.invokeKind().isDirect()) {
+                /* Static and special calls: link the statically known callee method. */
+                linkCallee(callTarget.targetMethod());
+            } else {
+                /* Virtual and interface call: Iterate all receiver types. */
+                for (ResolvedJavaType type : getTypes()) {
+                    /*
+                     * Resolve the method call for one exact receiver type. The method linking
+                     * semantics of Java are complicated, but fortunatley we can use the linker of
+                     * the hosting Java VM. The Graal API exposes this functionality.
+                     */
+                    ResolvedJavaMethod method = type.resolveConcreteMethod(callTarget.targetMethod(), callTarget.invoke().getContextType());
+
+                    /*
+                     * Since the static analysis is conservative, the list of receiver types can
+                     * contain types that actually do not provide the method to be called. Ignore
+                     * these.
+                     */
+                    if (method != null && !method.isAbstract()) {
+                        linkCallee(method);
+                    }
+                }
+            }
+            super.process();
+        }
+    }
+
+    /**
+     * Converts the Graal nodes of a method to a type flow graph. The main part of the algorithm is
+     * a reverse-postorder iteration of the Graal nodes, which is provided by the base class
+     * {@link StatelessPostOrderNodeIterator}.
+     */
+    class TypeFlowBuilder extends StatelessPostOrderNodeIterator {
+        private final StructuredGraph graph;
+        private final MethodState methodState;
+        /**
+         * Mapping from Graal nodes to type flows. This uses an efficient Graal-provided
+         * {@link NodeMap collection class}.
+         */
+        private final NodeMap<TypeFlow> typeFlows;
+
+        protected TypeFlowBuilder(StructuredGraph graph) {
+            super(graph.start());
+
+            this.graph = graph;
+            this.methodState = results.lookupMethod(graph.method());
+            this.typeFlows = new NodeMap<>(graph);
+        }
+
+        /**
+         * Register the type flow node for a Graal node.
+         */
+        private void registerFlow(ValueNode node, TypeFlow flow) {
+            /*
+             * We ignore intermediate nodes used by Graal that, e.g., add more type information or
+             * encapsulate values flowing out of loops.
+             */
+            ValueNode unproxiedNode = GraphUtil.unproxify(node);
+
+            assert typeFlows.get(unproxiedNode) == null : "overwriting existing value";
+            typeFlows.set(unproxiedNode, flow);
+        }
+
+        /**
+         * Lookup the type flow node for a Graal node.
+         */
+        private TypeFlow lookupFlow(ValueNode node) {
+            ValueNode unproxiedNode = GraphUtil.unproxify(node);
+            TypeFlow result = typeFlows.get(unproxiedNode);
+            if (result == null) {
+                /*
+                 * This is only the prototype of a static analysis, the handling of many Graal nodes
+                 * (such as array accesses) is not implemented.
+                 */
+                throw error("Node is not supported yet by static analysis: " + node.getClass().getName());
+            }
+            return result;
+        }
+
+        private boolean isObject(ValueNode node) {
+            return node.getStackKind() == JavaKind.Object;
+        }
+
+        @Override
+        public void apply() {
+            /*
+             * Before the reverse-postorder iteration of fixed nodes, we handle some classes of
+             * floating nodes.
+             */
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ParameterNode) {
+                    /*
+                     * Incoming method parameter already have a type flow created by the
+                     * MethodState.
+                     */
+                    ParameterNode node = (ParameterNode) n;
+                    if (isObject(node)) {
+                        registerFlow(node, methodState.formalParameters[(node.index())]);
+                    }
+                } else if (n instanceof ValuePhiNode) {
+                    /*
+                     * Phi functions for loops are cyclic. We create the type flow here (before
+                     * processing any loop nodes), but link the phi values only later (after
+                     * processing of all loop nodes.
+                     */
+                    ValuePhiNode node = (ValuePhiNode) n;
+                    if (isObject(node)) {
+                        registerFlow(node, new TypeFlow());
+                    }
+                } else if (n instanceof ConstantNode) {
+                    /* Constants have a known type. */
+                    ConstantNode node = (ConstantNode) n;
+                    JavaConstant constant = node.asJavaConstant();
+                    if (constant.isNull()) {
+                        registerFlow(node, new TypeFlow());
+                    }
+                }
+            }
+
+            super.apply();
+
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ValuePhiNode) {
+                    /*
+                     * Post-processing of phi functions. Now the type flow for all input values has
+                     * been created, so we can link the type flows together.
+                     */
+                    ValuePhiNode node = (ValuePhiNode) n;
+                    if (isObject(node)) {
+                        TypeFlow phiFlow = lookupFlow(node);
+                        for (ValueNode value : node.values()) {
+                            lookupFlow(value).addUse(phiFlow);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void allocation(ValueNode node, ResolvedJavaType type) {
+            /*
+             * The type flow of allocation nodes is one exact type. This is the source of the
+             * fixpoint iteration, the types are propagated downwards from these sources.
+             */
+            TypeFlow flow = new TypeFlow();
+            flow.addTypes(Collections.singleton(type));
+            registerFlow(node, flow);
+            flow.addUse(results.getAllInstantiatedTypes());
+        }
+
+        @Override
+        protected void node(FixedNode n) {
+            if (n instanceof NewInstanceNode) {
+                NewInstanceNode node = (NewInstanceNode) n;
+                allocation(node, node.instanceClass());
+            } else if (n instanceof NewArrayNode) {
+                NewArrayNode node = (NewArrayNode) n;
+                allocation(node, node.elementType().getArrayClass());
+
+            } else if (n instanceof LoadFieldNode) {
+                /*
+                 * The type flow of a field load is the type flow of the field itself. It
+                 * accumulates all types ever stored to the field.
+                 */
+                LoadFieldNode node = (LoadFieldNode) n;
+                if (isObject(node)) {
+                    registerFlow(node, results.lookupField(node.field()));
+                }
+            } else if (n instanceof StoreFieldNode) {
+                /*
+                 * Connect the type flow of the stored value with the type flow of the field.
+                 */
+                StoreFieldNode node = (StoreFieldNode) n;
+                if (isObject(node.value())) {
+                    TypeFlow fieldFlow = results.lookupField(node.field());
+                    lookupFlow(node.value()).addUse(fieldFlow);
+                }
+
+            } else if (n instanceof ReturnNode) {
+                /*
+                 * Connect the type flow of the returned value with the formal return type flow of
+                 * the MethodState.
+                 */
+                ReturnNode node = (ReturnNode) n;
+                if (node.result() != null && isObject(node.result())) {
+                    lookupFlow(node.result()).addUse(methodState.formalReturn);
+                }
+
+            } else if (n instanceof Invoke) {
+                /*
+                 * Create the InvokeTypeFlow, which performs all the linking of actual and formal
+                 * parameter values with all identified callees.
+                 */
+                Invoke invoke = (Invoke) n;
+                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+
+                TypeFlow[] actualParameters = new TypeFlow[callTarget.arguments().size()];
+                for (int i = 0; i < actualParameters.length; i++) {
+                    ValueNode actualParam = callTarget.arguments().get(i);
+                    if (isObject(actualParam)) {
+                        actualParameters[i] = lookupFlow(actualParam);
+                    }
+                }
+                TypeFlow actualReturn = null;
+                if (isObject(invoke.asNode())) {
+                    actualReturn = new TypeFlow();
+                    registerFlow(invoke.asNode(), actualReturn);
+                }
+
+                InvokeTypeFlow invokeFlow = new InvokeTypeFlow(callTarget, actualParameters, actualReturn);
+
+                if (callTarget.invokeKind().isIndirect()) {
+                    /*
+                     * For virtual and interface calls, new receiver types can lead to new callees.
+                     * Connect the type flow of the receiver with the invocation flow.
+                     */
+                    lookupFlow(callTarget.arguments().get(0)).addUse(invokeFlow);
+                }
+                /*
+                 * Ensure the invocation is on the worklist at least once, even if it is a static
+                 * call with not parameters that does not involve any type flows.
+                 */
+                addToWorklist(invokeFlow);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java
new file mode 100644
index 0000000..9882534
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test.tutorial;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.MethodState;
+import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.TypeFlow;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+public class StaticAnalysisTests {
+
+    static class A {
+        Object foo(Object arg) {
+            return arg;
+        }
+    }
+
+    static class B extends A {
+        @Override
+        Object foo(Object arg) {
+            if (arg instanceof Data) {
+                return ((Data) arg).f;
+            } else {
+                return super.foo(arg);
+            }
+        }
+    }
+
+    static class Data {
+        Object f;
+    }
+
+    private final MetaAccessProvider metaAccess;
+    private final StampProvider stampProvider;
+
+    public StaticAnalysisTests() {
+        Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        Providers providers = backend.getProviders();
+        this.metaAccess = providers.getMetaAccess();
+        this.stampProvider = providers.getStampProvider();
+    }
+
+    static void test01Entry() {
+        A a = new A();
+        a.foo(null);
+    }
+
+    @Test
+    public void test01() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class));
+        assertEquals(f(sa, Data.class, "f"));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, A.class, "foo").getFormalReturn());
+    }
+
+    static void test02Entry() {
+        A a = new A();
+        a.foo(new Data());
+
+        B b = new B();
+        b.foo(null);
+    }
+
+    @Test
+    public void test02() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class));
+        assertEquals(f(sa, Data.class, "f"));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class));
+    }
+
+    static void test03Entry() {
+        Data data = new Data();
+        data.f = new Integer(42);
+
+        A a = new A();
+        a.foo(new Data());
+
+        B b = new B();
+        b.foo(null);
+    }
+
+    @Test
+    public void test03() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class), t(Integer.class));
+        assertEquals(f(sa, Data.class, "f"), t(Integer.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
+        assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
+        assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class));
+    }
+
+    static void test04Entry() {
+        Data data = null;
+        for (int i = 0; i < 2; i++) {
+            if (i == 0) {
+                data = new Data();
+            } else if (i == 1) {
+                data.f = new Integer(42);
+            }
+        }
+
+        A a = new A();
+        a.foo(data);
+    }
+
+    @Test
+    public void test04() {
+        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry"));
+        sa.finish();
+
+        assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(Data.class), t(Integer.class));
+        assertEquals(f(sa, Data.class, "f"), t(Integer.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
+        assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
+        assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
+    }
+
+    private MethodState m(StaticAnalysis sa, Class<?> declaringClass, String name) {
+        return sa.getResults().lookupMethod(findMethod(declaringClass, name));
+    }
+
+    private TypeFlow f(StaticAnalysis sa, Class<?> declaringClass, String name) {
+        return sa.getResults().lookupField(findField(declaringClass, name));
+    }
+
+    private static void assertEquals(TypeFlow actual, Object... expected) {
+        Collection<?> actualTypes = actual.getTypes();
+        if (actualTypes.size() != expected.length || !actualTypes.containsAll(Arrays.asList(expected))) {
+            Assert.fail(actualTypes + " != " + Arrays.asList(expected));
+        }
+    }
+
+    private ResolvedJavaType t(Class<?> clazz) {
+        return metaAccess.lookupJavaType(clazz);
+    }
+
+    private ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
+        Method reflectionMethod = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (m.getName().equals(name)) {
+                assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName();
+                reflectionMethod = m;
+            }
+        }
+        assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
+        return metaAccess.lookupJavaMethod(reflectionMethod);
+    }
+
+    private ResolvedJavaField findField(Class<?> declaringClass, String name) {
+        Field reflectionField;
+        try {
+            reflectionField = declaringClass.getDeclaredField(name);
+        } catch (NoSuchFieldException | SecurityException ex) {
+            throw new AssertionError(ex);
+        }
+        return metaAccess.lookupJavaField(reflectionField);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThread.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThread.java
new file mode 100644
index 0000000..00600db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThread.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+
+/**
+ * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in the
+ * context of a thread-local {@linkplain GraalDebugConfig debug configuration}.
+ */
+public class CompilerThread extends Thread {
+
+    private final DebugConfigAccess debugConfigAccess;
+
+    public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) {
+        super(r);
+        this.setName(namePrefix + "-" + this.getId());
+        this.setPriority(Thread.MAX_PRIORITY);
+        this.setDaemon(true);
+        this.debugConfigAccess = debugConfigAccess;
+    }
+
+    @Override
+    public void run() {
+        DebugConfig debugConfig = debugConfigAccess.getDebugConfig();
+        setContextClassLoader(getClass().getClassLoader());
+        try {
+            super.run();
+        } finally {
+            if (debugConfig != null) {
+                for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) {
+                    try {
+                        dumpHandler.close();
+                    } catch (Throwable t) {
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThreadFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThreadFactory.java
new file mode 100644
index 0000000..4701be8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilerThreadFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import java.util.concurrent.ThreadFactory;
+
+import org.graalvm.compiler.debug.DebugConfig;
+
+/**
+ * Facility for creating {@linkplain CompilerThread compiler threads}.
+ */
+public class CompilerThreadFactory implements ThreadFactory {
+
+    /**
+     * Capability to get a thread-local debug configuration for the current thread.
+     */
+    public interface DebugConfigAccess {
+        /**
+         * Get a thread-local debug configuration for the current thread. This will be null if
+         * debugging is disabled.
+         */
+        DebugConfig getDebugConfig();
+    }
+
+    protected final String threadNamePrefix;
+    protected final DebugConfigAccess debugConfigAccess;
+
+    public CompilerThreadFactory(String threadNamePrefix, DebugConfigAccess debugConfigAccess) {
+        this.threadNamePrefix = threadNamePrefix;
+        this.debugConfigAccess = debugConfigAccess;
+    }
+
+    @Override
+    public Thread newThread(Runnable r) {
+        return new CompilerThread(r, threadNamePrefix, debugConfigAccess);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java
new file mode 100644
index 0000000..26541c8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import static org.graalvm.compiler.core.GraalCompilerOptions.EmitLIRRepeatCount;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext;
+import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.CompilationAlarm;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo;
+import org.graalvm.compiler.lir.BailoutAndRestartBackendException;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.instrumentation.ExtractInstrumentationPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.TargetProvider;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.VMConstant;
+
+/**
+ * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
+ */
+public class GraalCompiler {
+
+    private static final DebugTimer CompilerTimer = Debug.timer("GraalCompiler");
+    private static final DebugTimer FrontEnd = Debug.timer("FrontEnd");
+    private static final DebugTimer BackEnd = Debug.timer("BackEnd");
+    private static final DebugTimer EmitLIR = Debug.timer("EmitLIR");
+    private static final DebugTimer EmitCode = Debug.timer("EmitCode");
+    private static final LIRGenerationPhase LIR_GENERATION_PHASE = new LIRGenerationPhase();
+
+    /**
+     * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}.
+     */
+    public static class Request<T extends CompilationResult> {
+        public final StructuredGraph graph;
+        public final ResolvedJavaMethod installedCodeOwner;
+        public final Providers providers;
+        public final Backend backend;
+        public final PhaseSuite<HighTierContext> graphBuilderSuite;
+        public final OptimisticOptimizations optimisticOpts;
+        public final ProfilingInfo profilingInfo;
+        public final Suites suites;
+        public final LIRSuites lirSuites;
+        public final T compilationResult;
+        public final CompilationResultBuilderFactory factory;
+
+        /**
+         * @param graph the graph to be compiled
+         * @param installedCodeOwner the method the compiled code will be associated with once
+         *            installed. This argument can be null.
+         * @param providers
+         * @param backend
+         * @param graphBuilderSuite
+         * @param optimisticOpts
+         * @param profilingInfo
+         * @param suites
+         * @param lirSuites
+         * @param compilationResult
+         * @param factory
+         */
+        public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
+                        OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+            this.graph = graph;
+            this.installedCodeOwner = installedCodeOwner;
+            this.providers = providers;
+            this.backend = backend;
+            this.graphBuilderSuite = graphBuilderSuite;
+            this.optimisticOpts = optimisticOpts;
+            this.profilingInfo = profilingInfo;
+            this.suites = suites;
+            this.lirSuites = lirSuites;
+            this.compilationResult = compilationResult;
+            this.factory = factory;
+        }
+
+        /**
+         * Executes this compilation request.
+         *
+         * @return the result of the compilation
+         */
+        public T execute() {
+            return GraalCompiler.compile(this);
+        }
+    }
+
+    /**
+     * Requests compilation of a given graph.
+     *
+     * @param graph the graph to be compiled
+     * @param installedCodeOwner the method the compiled code will be associated with once
+     *            installed. This argument can be null.
+     * @return the result of the compilation
+     */
+    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
+                    PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
+                    CompilationResultBuilderFactory factory) {
+        return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory));
+    }
+
+    /**
+     * Services a given compilation request.
+     *
+     * @return the result of the compilation
+     */
+    @SuppressWarnings("try")
+    public static <T extends CompilationResult> T compile(Request<T> r) {
+        try (Scope s = MethodMetricsRootScopeInfo.createRootScopeIfAbsent(r.installedCodeOwner);
+                        CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod()) {
+            assert !r.graph.isFrozen();
+            try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start()) {
+                emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
+                emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            return r.compilationResult;
+        }
+    }
+
+    /**
+     * Builds the graph, optimizes it.
+     */
+    @SuppressWarnings("try")
+    public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
+                    ProfilingInfo profilingInfo, Suites suites) {
+        try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) {
+            HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
+            if (graph.start().next() == null) {
+                graphBuilderSuite.apply(graph, highTierContext);
+                new DeadCodeEliminationPhase(Optional).apply(graph);
+            } else {
+                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "initial state");
+            }
+            if (UseGraalInstrumentation.getValue()) {
+                new ExtractInstrumentationPhase().apply(graph, highTierContext);
+            }
+
+            suites.getHighTier().apply(graph, highTierContext);
+            graph.maybeCompress();
+
+            MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
+            suites.getMidTier().apply(graph, midTierContext);
+            graph.maybeCompress();
+
+            LowTierContext lowTierContext = new LowTierContext(providers, target);
+            suites.getLowTier().apply(graph, lowTierContext);
+
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    @SuppressWarnings("try")
+    public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult,
+                    CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) {
+        try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) {
+            // Repeatedly run the LIR code generation pass to improve statistical profiling results.
+            for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
+                SchedulePhase dummySchedule = new SchedulePhase();
+                dummySchedule.apply(graph);
+                emitLIR(backend, graph, stub, registerConfig, lirSuites);
+            }
+
+            LIRGenerationResult lirGen = null;
+            lirGen = emitLIR(backend, graph, stub, registerConfig, lirSuites);
+            try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
+                int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
+                compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
+                emitCode(backend, graph.getAssumptions(), graph.method(), graph.getMethods(), graph.getFields(), bytecodeSize, lirGen, compilationResult, installedCodeOwner, factory);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    @SuppressWarnings("try")
+    public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) {
+        OverrideScope overrideScope = null;
+        LIRSuites lirSuites0 = lirSuites;
+        while (true) {
+            try (OverrideScope scope = overrideScope) {
+                return emitLIR0(backend, graph, stub, registerConfig, lirSuites0);
+            } catch (BailoutAndRestartBackendException e) {
+                if (BailoutAndRestartBackendException.Options.LIRUnlockBackendRestart.getValue() && e.shouldRestart()) {
+                    overrideScope = e.getOverrideScope();
+                    lirSuites0 = e.updateLIRSuites(lirSuites);
+                    if (lirSuites0 != null) {
+                        continue;
+                    }
+                }
+                /*
+                 * The BailoutAndRestartBackendException is permanent. If restart fails or is
+                 * disabled we throw the bailout.
+                 */
+                throw e;
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) {
+        try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) {
+            ScheduleResult schedule = graph.getLastSchedule();
+            Block[] blocks = schedule.getCFG().getBlocks();
+            Block startBlock = schedule.getCFG().getStartBlock();
+            assert startBlock != null;
+            assert startBlock.getPredecessorCount() == 0;
+
+            LIR lir = null;
+            AbstractBlockBase<?>[] codeEmittingOrder = null;
+            AbstractBlockBase<?>[] linearScanOrder = null;
+            try (Scope s = Debug.scope("ComputeLinearScanOrder", lir)) {
+                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
+                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
+
+                lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder);
+                Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After linear scan order");
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
+            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, graph, stub);
+            LIRGeneratorTool lirGen = backend.newLIRGenerator(lirGenRes);
+            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
+
+            // LIR generation
+            LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule);
+            LIR_GENERATION_PHASE.apply(backend.getTarget(), lirGenRes, context);
+
+            try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
+                Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "After LIR generation");
+                LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig));
+                Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "Before code generation");
+                return result;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) {
+        if (compilationResult != null && compilationResult.getName() != null) {
+            return compilationResult.getName();
+        }
+        ResolvedJavaMethod method = graph.method();
+        if (method == null) {
+            return "<unknown>";
+        }
+        return method.format("%H.%n(%p)");
+    }
+
+    public static LIRGenerationResult emitLowLevel(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen, LIRSuites lirSuites,
+                    RegisterAllocationConfig registerAllocationConfig) {
+        PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
+        lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext);
+
+        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
+        lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext);
+
+        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
+        lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext);
+
+        return lirGenRes;
+    }
+
+    @SuppressWarnings("try")
+    public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods, Collection<ResolvedJavaField> accessedFields,
+                    int bytecodeSize, LIRGenerationResult lirGenRes,
+                    CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) {
+        try (DebugCloseable a = EmitCode.start()) {
+            FrameMap frameMap = lirGenRes.getFrameMap();
+            CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
+            backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
+            if (assumptions != null && !assumptions.isEmpty()) {
+                compilationResult.setAssumptions(assumptions.toArray());
+            }
+            if (rootMethod != null) {
+                compilationResult.setMethods(rootMethod, inlinedMethods);
+                compilationResult.setFields(accessedFields);
+                compilationResult.setBytecodeSize(bytecodeSize);
+            }
+            crb.finish();
+            if (Debug.isCountEnabled()) {
+                List<DataPatch> ldp = compilationResult.getDataPatches();
+                JavaKind[] kindValues = JavaKind.values();
+                DebugCounter[] dms = new DebugCounter[kindValues.length];
+                for (int i = 0; i < dms.length; i++) {
+                    dms[i] = Debug.counter("DataPatches-%s", kindValues[i]);
+                }
+
+                for (DataPatch dp : ldp) {
+                    JavaKind kind = JavaKind.Illegal;
+                    if (dp.reference instanceof ConstantReference) {
+                        VMConstant constant = ((ConstantReference) dp.reference).getConstant();
+                        if (constant instanceof JavaConstant) {
+                            kind = ((JavaConstant) constant).getJavaKind();
+                        }
+                    }
+                    dms[kind.ordinal()].add(1);
+                }
+
+                Debug.counter("CompilationResults").increment();
+                Debug.counter("CodeBytesEmitted").add(compilationResult.getTargetCodeSize());
+                Debug.counter("InfopointsEmitted").add(compilationResult.getInfopoints().size());
+                Debug.counter("DataPatches").add(ldp.size());
+                Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
+            }
+
+            Debug.dump(Debug.BASIC_LOG_LEVEL, compilationResult, "After code generation");
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java
new file mode 100644
index 0000000..f8c8a0a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Options related to {@link GraalCompiler}.
+ */
+public class GraalCompilerOptions {
+
+    // @formatter:off
+    @Option(help = "Repeatedly run the LIR code generation pass to improve statistical profiling results.", type = OptionType.Debug)
+    public static final OptionValue<Integer> EmitLIRRepeatCount = new OptionValue<>(0);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintBailout = new OptionValue<>(false);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ExitVMOnBailout = new OptionValue<>(false);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ExitVMOnException = new OptionValue<>(false);
+    @Option(help = "", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintStackTraceOnException = new OptionValue<>(false);
+    // @formatter:on
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java
new file mode 100644
index 0000000..38cb71f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Params;
+import org.graalvm.compiler.debug.DebugInitializationParticipant;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+/**
+ * A service provider that may modify the initialization of {@link Debug} based on the values
+ * specified for various {@link GraalDebugConfig} options.
+ */
+@ServiceProvider(DebugInitializationParticipant.class)
+public class GraalDebugInitializationParticipant implements DebugInitializationParticipant {
+
+    @Override
+    public void apply(Params params) {
+        if (GraalDebugConfig.areDebugScopePatternsEnabled()) {
+            params.enable = true;
+        }
+        if ("".equals(GraalDebugConfig.Options.Count.getValue())) {
+            params.enableUnscopedCounters = true;
+        }
+        if ("".equals(GraalDebugConfig.Options.MethodMeter.getValue())) {
+            params.enableUnscopedMethodMetrics = true;
+            // mm requires full debugging support
+            params.enable = true;
+        }
+        if ("".equals(GraalDebugConfig.Options.Time.getValue())) {
+            params.enableUnscopedTimers = true;
+        }
+        if ("".equals(GraalDebugConfig.Options.TrackMemUse.getValue())) {
+            params.enableUnscopedMemUseTrackers = true;
+        }
+        // unscoped counters/timers/mem use trackers/method metrics should respect method filter
+        // semantics
+        if (!params.enable && (params.enableUnscopedMemUseTrackers || params.enableUnscopedMethodMetrics || params.enableUnscopedCounters || params.enableUnscopedTimers) &&
+                        GraalDebugConfig.isNotEmpty(GraalDebugConfig.Options.MethodFilter)) {
+            params.enable = true;
+            params.enableMethodFilter = true;
+        }
+
+        if (!params.enableUnscopedMethodMetrics && GraalDebugConfig.Options.MethodMeter.getValue() != null) {
+            // mm requires full debugging support
+            params.enable = true;
+        }
+
+        if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) {
+            if (!params.enable) {
+                TTY.println("WARNING: MethodMeter is disabled but GlobalMetricsInterceptedByMethodMetrics is enabled. Ignoring MethodMeter and GlobalMetricsInterceptedByMethodMetrics.");
+            } else {
+                parseMethodMetricsDebugValueInterception(params);
+            }
+        }
+        if (GraalDebugConfig.isNotEmpty(GraalDebugConfig.Options.MethodMeter) || params.enableUnscopedMethodMetrics) {
+            if (!MethodMetricsPrinter.methodMetricsDumpingEnabled()) {
+                TTY.println("WARNING: MethodMeter is enabled but MethodMeter dumping is disabled. Output will not contain MethodMetrics.");
+            }
+        }
+    }
+
+    private static void parseMethodMetricsDebugValueInterception(Params params) {
+        String interceptionGroup = GraalDebugConfig.Options.GlobalMetricsInterceptedByMethodMetrics.getValue();
+        boolean intercepted = false;
+        if (interceptionGroup.contains("Timers")) {
+            params.interceptTime = true;
+            intercepted = true;
+        }
+        if (interceptionGroup.contains("Counters")) {
+            params.interceptCount = true;
+            intercepted = true;
+        }
+        if (interceptionGroup.contains("MemUseTrackers")) {
+            params.interceptMem = true;
+            intercepted = true;
+        }
+
+        if (!intercepted) {
+            TTY.println("WARNING: Ignoring GlobalMetricsInterceptedByMethodMetrics as the supplied argument does not contain Timers/Counters/MemUseTrackers.");
+            GraalDebugConfig.Options.GlobalMetricsInterceptedByMethodMetrics.setValue(null);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java
new file mode 100644
index 0000000..51aa28e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class LIRGenerationPhase extends LIRPhase<LIRGenerationPhase.LIRGenerationContext> {
+
+    public static final class LIRGenerationContext {
+        private final NodeLIRBuilderTool nodeLirBuilder;
+        private final LIRGeneratorTool lirGen;
+        private final StructuredGraph graph;
+        private final ScheduleResult schedule;
+
+        public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, ScheduleResult schedule) {
+            this.nodeLirBuilder = nodeLirBuilder;
+            this.lirGen = lirGen;
+            this.graph = graph;
+            this.schedule = schedule;
+        }
+    }
+
+    private static final DebugCounter instructionCounter = Debug.counter("GeneratedLIRInstructions");
+
+    @Override
+    protected final void run(TargetDescription target, LIRGenerationResult lirGenRes, LIRGenerationPhase.LIRGenerationContext context) {
+        NodeLIRBuilderTool nodeLirBuilder = context.nodeLirBuilder;
+        StructuredGraph graph = context.graph;
+        ScheduleResult schedule = context.schedule;
+        for (AbstractBlockBase<?> b : lirGenRes.getLIR().getControlFlowGraph().getBlocks()) {
+            emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap());
+        }
+        context.lirGen.beforeRegisterAllocation();
+        assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
+    }
+
+    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
+        assert !isProcessed(lirGenRes, b) : "Block already processed " + b;
+        assert verifyPredecessors(lirGenRes, b);
+        nodeLirGen.doBlock(b, graph, blockMap);
+        if (instructionCounter.isEnabled()) {
+            instructionCounter.add(lirGenRes.getLIR().getLIRforBlock(b).size());
+        }
+    }
+
+    private static boolean verifyPredecessors(LIRGenerationResult lirGenRes, Block block) {
+        for (Block pred : block.getPredecessors()) {
+            if (!block.isLoopHeader() || !pred.isLoopEnd()) {
+                assert isProcessed(lirGenRes, pred) : "Predecessor not yet processed " + pred;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isProcessed(LIRGenerationResult lirGenRes, Block b) {
+        return lirGenRes.getLIR().getLIRforBlock(b) != null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/BytecodeParserTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/BytecodeParserTool.java
new file mode 100644
index 0000000..f3d7f9f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/BytecodeParserTool.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.gen;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * visible interface of bytecode parsers.
+ */
+public interface BytecodeParserTool {
+
+    void storeLocal(int i, Value x);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java
new file mode 100644
index 0000000..4449ecc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.gen;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Queue;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
+import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Builds {@link LIRFrameState}s from {@link FrameState}s.
+ */
+public class DebugInfoBuilder {
+
+    protected final NodeValueMap nodeValueMap;
+
+    public DebugInfoBuilder(NodeValueMap nodeValueMap) {
+        this.nodeValueMap = nodeValueMap;
+    }
+
+    private static final JavaValue[] NO_JAVA_VALUES = {};
+    private static final JavaKind[] NO_JAVA_KINDS = {};
+
+    protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = Node.newMap();
+    protected final Map<VirtualObjectNode, EscapeObjectState> objectStates = Node.newIdentityMap();
+
+    protected final Queue<VirtualObjectNode> pendingVirtualObjects = new ArrayDeque<>();
+
+    public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) {
+        assert virtualObjects.size() == 0;
+        assert objectStates.size() == 0;
+        assert pendingVirtualObjects.size() == 0;
+
+        // collect all VirtualObjectField instances:
+        FrameState current = topState;
+        do {
+            if (current.virtualObjectMappingCount() > 0) {
+                for (EscapeObjectState state : current.virtualObjectMappings()) {
+                    if (!objectStates.containsKey(state.object())) {
+                        if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) {
+                            objectStates.put(state.object(), state);
+                        }
+                    }
+                }
+            }
+            current = current.outerFrameState();
+        } while (current != null);
+
+        BytecodeFrame frame = computeFrameForState(topState);
+
+        VirtualObject[] virtualObjectsArray = null;
+        if (virtualObjects.size() != 0) {
+            // fill in the VirtualObject values
+            VirtualObjectNode vobjNode;
+            while ((vobjNode = pendingVirtualObjects.poll()) != null) {
+                VirtualObject vobjValue = virtualObjects.get(vobjNode);
+                assert vobjValue.getValues() == null;
+
+                JavaValue[] values;
+                JavaKind[] slotKinds;
+                int entryCount = vobjNode.entryCount();
+                if (entryCount == 0) {
+                    values = NO_JAVA_VALUES;
+                    slotKinds = NO_JAVA_KINDS;
+                } else {
+                    values = new JavaValue[entryCount];
+                    slotKinds = new JavaKind[entryCount];
+                }
+                if (values.length > 0) {
+                    VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobjNode);
+                    assert currentField != null;
+                    int pos = 0;
+                    for (int i = 0; i < entryCount; i++) {
+                        if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asJavaConstant().getJavaKind() != JavaKind.Illegal) {
+                            ValueNode value = currentField.values().get(i);
+                            values[pos] = toJavaValue(value);
+                            slotKinds[pos] = toSlotKind(value);
+                            pos++;
+                        } else {
+                            assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " +
+                                            currentField.values().get(i - 1);
+                        }
+                    }
+                    if (pos != entryCount) {
+                        values = Arrays.copyOf(values, pos);
+                        slotKinds = Arrays.copyOf(slotKinds, pos);
+                    }
+                }
+                assert checkValues(vobjValue.getType(), values, slotKinds);
+                vobjValue.setValues(values, slotKinds);
+            }
+
+            virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]);
+            virtualObjects.clear();
+        }
+        objectStates.clear();
+
+        return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
+    }
+
+    private boolean checkValues(ResolvedJavaType type, JavaValue[] values, JavaKind[] slotKinds) {
+        assert (values == null) == (slotKinds == null);
+        if (values != null) {
+            assert values.length == slotKinds.length;
+            if (!type.isArray()) {
+                ResolvedJavaField[] fields = type.getInstanceFields(true);
+                int fieldIndex = 0;
+                for (int i = 0; i < values.length; i++) {
+                    ResolvedJavaField field = fields[fieldIndex++];
+                    JavaKind valKind = slotKinds[i].getStackKind();
+                    JavaKind fieldKind = storageKind(field.getType());
+                    if (fieldKind == JavaKind.Object) {
+                        assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind;
+                    } else {
+                        if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
+                            assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int;
+                            fieldIndex++;
+                        } else {
+                            assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
+                        }
+                    }
+                }
+                assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
+            } else {
+                JavaKind componentKind = storageKind(type.getComponentType()).getStackKind();
+                if (componentKind == JavaKind.Object) {
+                    for (int i = 0; i < values.length; i++) {
+                        assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind;
+                    }
+                } else {
+                    for (int i = 0; i < values.length; i++) {
+                        assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() ||
+                                        (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Customization point for subclasses. For example, Word types have a kind Object, but are
+     * internally stored as a primitive value. We do not know about Word types here, but subclasses
+     * do know.
+     */
+    protected JavaKind storageKind(JavaType type) {
+        return type.getJavaKind();
+    }
+
+    protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
+        return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge);
+    }
+
+    protected BytecodeFrame computeFrameForState(FrameState state) {
+        try {
+            assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
+            assert state.bci != BytecodeFrame.UNKNOWN_BCI;
+            assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0;
+            assert !(state.getMethod().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) ||
+                            state.locksSize() > 0;
+            assert state.verify();
+
+            int numLocals = state.localsSize();
+            int numStack = state.stackSize();
+            int numLocks = state.locksSize();
+
+            int numValues = numLocals + numStack + numLocks;
+            int numKinds = numLocals + numStack;
+
+            JavaValue[] values = numValues == 0 ? NO_JAVA_VALUES : new JavaValue[numValues];
+            JavaKind[] slotKinds = numKinds == 0 ? NO_JAVA_KINDS : new JavaKind[numKinds];
+            computeLocals(state, numLocals, values, slotKinds);
+            computeStack(state, numLocals, numStack, values, slotKinds);
+            computeLocks(state, values);
+
+            BytecodeFrame caller = null;
+            if (state.outerFrameState() != null) {
+                caller = computeFrameForState(state.outerFrameState());
+            }
+
+            if (!state.canProduceBytecodeFrame()) {
+                // This typically means a snippet or intrinsic frame state made it to the backend
+                StackTraceElement ste = state.getCode().asStackTraceElement(state.bci);
+                throw new GraalError("Frame state for %s cannot be converted to a BytecodeFrame since the frame state's code is " +
+                                "not the same as the frame state method's code", ste);
+            }
+
+            return new BytecodeFrame(caller, state.getMethod(), state.bci, state.rethrowException(), state.duringCall(), values, slotKinds, numLocals, numStack, numLocks);
+        } catch (GraalError e) {
+            throw e.addContext("FrameState: ", state);
+        }
+    }
+
+    protected void computeLocals(FrameState state, int numLocals, JavaValue[] values, JavaKind[] slotKinds) {
+        for (int i = 0; i < numLocals; i++) {
+            ValueNode local = state.localAt(i);
+            values[i] = toJavaValue(local);
+            slotKinds[i] = toSlotKind(local);
+        }
+    }
+
+    protected void computeStack(FrameState state, int numLocals, int numStack, JavaValue[] values, JavaKind[] slotKinds) {
+        for (int i = 0; i < numStack; i++) {
+            ValueNode stack = state.stackAt(i);
+            values[numLocals + i] = toJavaValue(stack);
+            slotKinds[numLocals + i] = toSlotKind(stack);
+        }
+    }
+
+    protected void computeLocks(FrameState state, JavaValue[] values) {
+        for (int i = 0; i < state.locksSize(); i++) {
+            values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i);
+        }
+    }
+
+    protected JavaValue computeLockValue(FrameState state, int i) {
+        return toJavaValue(state.lockAt(i));
+    }
+
+    private static final DebugCounter STATE_VIRTUAL_OBJECTS = Debug.counter("StateVirtualObjects");
+    private static final DebugCounter STATE_ILLEGALS = Debug.counter("StateIllegals");
+    private static final DebugCounter STATE_VARIABLES = Debug.counter("StateVariables");
+    private static final DebugCounter STATE_CONSTANTS = Debug.counter("StateConstants");
+
+    private static JavaKind toSlotKind(ValueNode value) {
+        if (value == null) {
+            return JavaKind.Illegal;
+        } else {
+            return value.getStackKind();
+        }
+    }
+
+    protected JavaValue toJavaValue(ValueNode value) {
+        try {
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode obj = (VirtualObjectNode) value;
+                EscapeObjectState state = objectStates.get(obj);
+                if (state == null && obj.entryCount() > 0) {
+                    // null states occur for objects with 0 fields
+                    throw new GraalError("no mapping found for virtual object %s", obj);
+                }
+                if (state instanceof MaterializedObjectState) {
+                    return toJavaValue(((MaterializedObjectState) state).materializedValue());
+                } else {
+                    assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
+                    VirtualObject vobject = virtualObjects.get(obj);
+                    if (vobject == null) {
+                        vobject = VirtualObject.get(obj.type(), virtualObjects.size());
+                        virtualObjects.put(obj, vobject);
+                        pendingVirtualObjects.add(obj);
+                    }
+                    STATE_VIRTUAL_OBJECTS.increment();
+                    return vobject;
+                }
+            } else {
+                // Remove proxies from constants so the constant can be directly embedded.
+                ValueNode unproxied = GraphUtil.unproxify(value);
+                if (unproxied instanceof ConstantNode) {
+                    STATE_CONSTANTS.increment();
+                    return unproxied.asJavaConstant();
+
+                } else if (value != null) {
+                    STATE_VARIABLES.increment();
+                    Value operand = nodeValueMap.operand(value);
+                    if (operand instanceof ConstantValue && ((ConstantValue) operand).isJavaConstant()) {
+                        return ((ConstantValue) operand).getJavaConstant();
+                    } else {
+                        assert operand instanceof Variable : operand + " for " + value;
+                        return (JavaValue) operand;
+                    }
+
+                } else {
+                    // return a dummy value because real value not needed
+                    STATE_ILLEGALS.increment();
+                    return Value.ILLEGAL;
+                }
+            }
+        } catch (GraalError e) {
+            throw e.addContext("toValue: ", value);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/InstructionPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/InstructionPrinter.java
new file mode 100644
index 0000000..13057d4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/InstructionPrinter.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.gen;
+
+import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.BCI;
+import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.END;
+import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.INSTRUCTION;
+import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.USE;
+import static org.graalvm.compiler.core.gen.InstructionPrinter.InstructionLineColumn.VALUE;
+
+import org.graalvm.compiler.debug.LogStream;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+
+/**
+ * A utility for {@linkplain #printInstruction(ValueNode) printing} a node as an expression or
+ * statement.
+ */
+public class InstructionPrinter {
+
+    /**
+     * The columns printed in a tabulated instruction
+     * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}.
+     */
+    public enum InstructionLineColumn {
+        /**
+         * The instruction's bytecode index.
+         */
+        BCI(2, "bci"),
+
+        /**
+         * The instruction's use count.
+         */
+        USE(7, "use"),
+
+        /**
+         * The instruction as a value.
+         */
+        VALUE(12, "tid"),
+
+        /**
+         * The instruction formatted as an expression or statement.
+         */
+        INSTRUCTION(19, "instr"),
+
+        END(60, "");
+
+        final int position;
+        final String label;
+
+        InstructionLineColumn(int position, String label) {
+            this.position = position;
+            this.label = label;
+        }
+
+        /**
+         * Prints this column's label to a given stream after padding the stream with '_' characters
+         * until its {@linkplain LogStream#position() position} is equal to this column's position.
+         *
+         * @param out the print stream
+         */
+        public void printLabel(LogStream out) {
+            out.fillTo(position + out.indentationLevel(), '_');
+            out.print(label);
+        }
+
+        /**
+         * Prints space characters to a given stream until its {@linkplain LogStream#position()
+         * position} is equal to this column's position.
+         *
+         * @param out the print stream
+         */
+        public void advance(LogStream out) {
+            out.fillTo(position + out.indentationLevel(), ' ');
+        }
+    }
+
+    private final LogStream out;
+
+    public InstructionPrinter(LogStream out) {
+        this.out = out;
+    }
+
+    public LogStream out() {
+        return out;
+    }
+
+    /**
+     * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)}
+     * .
+     */
+    public void printInstructionListingHeader() {
+        BCI.printLabel(out);
+        USE.printLabel(out);
+        VALUE.printLabel(out);
+        INSTRUCTION.printLabel(out);
+        END.printLabel(out);
+        out.println();
+    }
+
+    /**
+     * Prints an instruction listing on one line. The instruction listing is composed of the columns
+     * specified by {@link InstructionLineColumn}.
+     *
+     * @param instruction the instruction to print
+     */
+    public void printInstructionListing(ValueNode instruction) {
+        int indentation = out.indentationLevel();
+        out.fillTo(BCI.position + indentation, ' ').print(0).fillTo(USE.position + indentation, ' ').print("0").fillTo(VALUE.position + indentation, ' ').print(
+                        ValueNodeUtil.valueString(instruction)).fillTo(
+                                        INSTRUCTION.position + indentation, ' ');
+        printInstruction(instruction);
+        if (instruction instanceof StateSplit) {
+            out.print("  [state: " + ((StateSplit) instruction).stateAfter() + "]");
+        }
+        out.println();
+    }
+
+    public void printInstruction(ValueNode node) {
+        out.print(node.toString());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java
new file mode 100644
index 0000000..2c70da1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.gen;
+
+import static org.graalvm.compiler.core.common.GraalOptions.MatchExpressions;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose;
+import static org.graalvm.compiler.lir.LIR.verifyBlock;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.match.ComplexMatchValue;
+import org.graalvm.compiler.core.match.MatchRuleRegistry;
+import org.graalvm.compiler.core.match.MatchStatement;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.GraalGraphError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.lir.FullInfopointOp;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.debug.LIRGenerationDebugContext;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.lir.gen.LIRGenerator.Options;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.BlockScope;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoweredCallTargetNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerTestNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGenerationDebugContext {
+
+    private final NodeMap<Value> nodeOperands;
+    private final DebugInfoBuilder debugInfoBuilder;
+
+    protected final LIRGenerator gen;
+
+    private ValueNode currentInstruction;
+    private ValueNode lastInstructionPrinted; // Debugging only
+
+    private final NodeMatchRules nodeMatchRules;
+    private Map<Class<? extends Node>, List<MatchStatement>> matchRules;
+
+    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, NodeMatchRules nodeMatchRules) {
+        this.gen = (LIRGenerator) gen;
+        this.nodeMatchRules = nodeMatchRules;
+        this.nodeOperands = graph.createNodeMap();
+        this.debugInfoBuilder = createDebugInfoBuilder(graph, this);
+        if (MatchExpressions.getValue()) {
+            matchRules = MatchRuleRegistry.lookup(nodeMatchRules.getClass());
+        }
+
+        assert nodeMatchRules.lirBuilder == null;
+        nodeMatchRules.lirBuilder = this;
+    }
+
+    public NodeMatchRules getNodeMatchRules() {
+        return nodeMatchRules;
+    }
+
+    @SuppressWarnings({"unused"})
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        return new DebugInfoBuilder(nodeValueMap);
+    }
+
+    /**
+     * Returns the operand that has been previously initialized by
+     * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code
+     * generation error to ask for the operand of ValueNode that doesn't have one yet.
+     *
+     * @param node A node that produces a result value.
+     */
+    @Override
+    public Value operand(Node node) {
+        Value operand = getOperand(node);
+        assert operand != null : String.format("missing operand for %1s", node);
+        return operand;
+    }
+
+    @Override
+    public boolean hasOperand(Node node) {
+        return getOperand(node) != null;
+    }
+
+    private Value getOperand(Node node) {
+        if (nodeOperands == null) {
+            return null;
+        }
+        return nodeOperands.get(node);
+    }
+
+    @Override
+    public ValueNode valueForOperand(Value value) {
+        assert nodeOperands != null;
+        for (Entry<Node, Value> entry : nodeOperands.entries()) {
+            if (entry.getValue().equals(value)) {
+                return (ValueNode) entry.getKey();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Object getSourceForOperand(Value value) {
+        return valueForOperand(value);
+    }
+
+    @Override
+    public Value setResult(ValueNode x, Value operand) {
+        assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable());
+        assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice";
+        assert operand != null && isLegal(operand) : "operand must be legal";
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+        return operand;
+    }
+
+    /**
+     * Used by the {@link MatchStatement} machinery to override the generation LIR for some
+     * ValueNodes.
+     */
+    public void setMatchResult(Node x, Value operand) {
+        assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
+        assert operand instanceof ComplexMatchValue || x.getUsageCount() == 1 : "interior matches must be single user";
+        assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+    }
+
+    public LabelRef getLIRBlock(FixedNode b) {
+        assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
+        Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b);
+        int suxIndex = 0;
+        for (AbstractBlockBase<?> succ : gen.getCurrentBlock().getSuccessors()) {
+            if (succ == result) {
+                assert gen.getCurrentBlock() instanceof Block;
+                return LabelRef.forSuccessor(gen.getResult().getLIR(), gen.getCurrentBlock(), suxIndex);
+            }
+            suxIndex++;
+        }
+        throw GraalError.shouldNotReachHere("Block not in successor list of current block");
+    }
+
+    public final void append(LIRInstruction op) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
+            if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
+                lastInstructionPrinted = currentInstruction;
+                InstructionPrinter ip = new InstructionPrinter(TTY.out());
+                ip.printInstructionListing(currentInstruction);
+            }
+        }
+        gen.append(op);
+    }
+
+    protected LIRKind getExactPhiKind(PhiNode phi) {
+        // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList.
+        ArrayList<LIRKind> values = new ArrayList<>(phi.valueCount());
+        for (int i = 0; i < phi.valueCount(); i++) {
+            ValueNode node = phi.valueAt(i);
+            Value value = getOperand(node);
+            if (value != null) {
+                values.add(value.getValueKind(LIRKind.class));
+            } else {
+                assert isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", node, phi);
+                // non-java constant -> get LIRKind from stamp.
+                LIRKind kind = gen.getLIRKind(node.stamp());
+                values.add(gen.toRegisterKind(kind));
+            }
+        }
+        LIRKind derivedKind = LIRKind.merge(values);
+        assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp()));
+        return derivedKind;
+    }
+
+    private boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) {
+        PlatformKind derivedPlatformKind = derivedKind.getPlatformKind();
+        PlatformKind phiPlatformKind = gen.toRegisterKind(phiKind).getPlatformKind();
+        assert derivedPlatformKind.equals(phiPlatformKind) : "kinds don't match: " + derivedPlatformKind + " vs " + phiPlatformKind;
+        return true;
+    }
+
+    private static boolean isPhiInputFromBackedge(PhiNode phi, int index) {
+        AbstractMergeNode merge = phi.merge();
+        AbstractEndNode end = merge.phiPredecessorAt(index);
+        return end instanceof LoopEndNode && ((LoopEndNode) end).loopBegin().equals(merge);
+    }
+
+    private Value[] createPhiIn(AbstractMergeNode merge) {
+        List<Value> values = new ArrayList<>();
+        for (ValuePhiNode phi : merge.valuePhis()) {
+            assert getOperand(phi) == null;
+            Variable value = gen.newVariable(getExactPhiKind(phi));
+            values.add(value);
+            setResult(phi, value);
+        }
+        return values.toArray(new Value[values.size()]);
+    }
+
+    /**
+     * @return {@code true} if object constant to stack moves are supported.
+     */
+    protected boolean allowObjectConstantToStackMove() {
+        return true;
+    }
+
+    private Value[] createPhiOut(AbstractMergeNode merge, AbstractEndNode pred) {
+        List<Value> values = new ArrayList<>();
+        for (PhiNode phi : merge.valuePhis()) {
+            ValueNode node = phi.valueAt(pred);
+            Value value = operand(node);
+            assert value != null;
+            if (isRegister(value)) {
+                /*
+                 * Fixed register intervals are not allowed at block boundaries so we introduce a
+                 * new Variable.
+                 */
+                value = gen.emitMove(value);
+            } else if (!allowObjectConstantToStackMove() && node instanceof ConstantNode && !LIRKind.isValue(value)) {
+                /*
+                 * Some constants are not allowed as inputs for PHIs in certain backends. Explicitly
+                 * create a copy of this value to force it into a register. The new variable is only
+                 * used in the PHI.
+                 */
+                Variable result = gen.newVariable(value.getValueKind());
+                gen.emitMove(result, value);
+                value = result;
+            }
+            values.add(value);
+        }
+        return values.toArray(new Value[values.size()]);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
+        try (BlockScope blockScope = gen.getBlockScope(block)) {
+            setSourcePosition(null);
+
+            if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) {
+                assert block.getPredecessorCount() == 0;
+                emitPrologue(graph);
+            } else {
+                assert block.getPredecessorCount() > 0;
+                // create phi-in value array
+                AbstractBeginNode begin = block.getBeginNode();
+                if (begin instanceof AbstractMergeNode) {
+                    AbstractMergeNode merge = (AbstractMergeNode) begin;
+                    LabelOp label = (LabelOp) gen.getResult().getLIR().getLIRforBlock(block).get(0);
+                    label.setPhiValues(createPhiIn(merge));
+                    if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
+                        TTY.println("Created PhiIn: " + label);
+
+                    }
+                }
+            }
+
+            List<Node> nodes = blockMap.get(block);
+
+            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+            // of instructions
+            matchComplexExpressions(nodes);
+
+            for (int i = 0; i < nodes.size(); i++) {
+                Node node = nodes.get(i);
+                if (node instanceof ValueNode) {
+                    ValueNode valueNode = (ValueNode) node;
+                    if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
+                        TTY.println("LIRGen for " + valueNode);
+                    }
+                    Value operand = getOperand(valueNode);
+                    if (operand == null) {
+                        if (!peephole(valueNode)) {
+                            try {
+                                doRoot(valueNode);
+                            } catch (GraalError e) {
+                                throw GraalGraphError.transformAndAddContext(e, valueNode);
+                            } catch (Throwable e) {
+                                throw new GraalGraphError(e).addContext(valueNode);
+                            }
+                        }
+                    } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
+                        // Doesn't need to be evaluated
+                        Debug.log("interior match for %s", valueNode);
+                    } else if (operand instanceof ComplexMatchValue) {
+                        Debug.log("complex match for %s", valueNode);
+                        ComplexMatchValue match = (ComplexMatchValue) operand;
+                        operand = match.evaluate(this);
+                        if (operand != null) {
+                            setResult(valueNode, operand);
+                        }
+                    } else {
+                        // There can be cases in which the result of an instruction is already set
+                        // before by other instructions.
+                    }
+                }
+            }
+
+            if (!gen.hasBlockEnd(block)) {
+                NodeIterable<Node> successors = block.getEndNode().successors();
+                assert successors.count() == block.getSuccessorCount();
+                if (block.getSuccessorCount() != 1) {
+                    /*
+                     * If we have more than one successor, we cannot just use the first one. Since
+                     * successors are unordered, this would be a random choice.
+                     */
+                    throw new GraalError("Block without BlockEndOp: " + block.getEndNode());
+                }
+                gen.emitJump(getLIRBlock((FixedNode) successors.first()));
+            }
+
+            assert verifyBlock(gen.getResult().getLIR(), block);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void matchComplexExpressions(List<Node> nodes) {
+        if (matchRules != null) {
+            try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                if (LogVerbose.getValue()) {
+                    int i = 0;
+                    for (Node node : nodes) {
+                        Debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node);
+                    }
+                }
+
+                // Match the nodes in backwards order to encourage longer matches.
+                for (int index = nodes.size() - 1; index >= 0; index--) {
+                    Node node = nodes.get(index);
+                    if (getOperand(node) != null) {
+                        continue;
+                    }
+                    // See if this node is the root of any MatchStatements
+                    List<MatchStatement> statements = matchRules.get(node.getClass());
+                    if (statements != null) {
+                        for (MatchStatement statement : statements) {
+                            if (statement.generate(this, index, node, nodes)) {
+                                // Found a match so skip to the next
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected abstract boolean peephole(ValueNode valueNode);
+
+    private void doRoot(ValueNode instr) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 2) {
+            TTY.println("Emitting LIR for instruction " + instr);
+        }
+        currentInstruction = instr;
+
+        Debug.log("Visiting %s", instr);
+        emitNode(instr);
+        Debug.log("Operand for %s = %s", instr, getOperand(instr));
+    }
+
+    protected void emitNode(ValueNode node) {
+        if (Debug.isLogEnabled() && node.stamp().isEmpty()) {
+            Debug.log("This node has an empty stamp, we are emitting dead code(?): %s", node);
+        }
+        setSourcePosition(node.getNodeSourcePosition());
+        if (node instanceof LIRLowerable) {
+            ((LIRLowerable) node).generate(this);
+        } else {
+            throw GraalError.shouldNotReachHere("node is not LIRLowerable: " + node);
+        }
+    }
+
+    protected void emitPrologue(StructuredGraph graph) {
+        CallingConvention incomingArguments = gen.getResult().getCallingConvention();
+
+        Value[] params = new Value[incomingArguments.getArgumentCount()];
+        for (int i = 0; i < params.length; i++) {
+            params[i] = incomingArguments.getArgument(i);
+            if (ValueUtil.isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) {
+                    gen.getResult().getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+
+        gen.emitIncomingValues(params);
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue + " " + getLIRGeneratorTool().getLIRKind(param.stamp());
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    @Override
+    public void visitMerge(AbstractMergeNode x) {
+    }
+
+    @Override
+    public void visitEndNode(AbstractEndNode end) {
+        AbstractMergeNode merge = end.merge();
+        JumpOp jump = newJumpOp(getLIRBlock(merge));
+        jump.setPhiValues(createPhiOut(merge, end));
+        append(jump);
+    }
+
+    /**
+     * Runtime specific classes can override this to insert a safepoint at the end of a loop.
+     */
+    @Override
+    public void visitLoopEnd(LoopEndNode x) {
+    }
+
+    protected JumpOp newJumpOp(LabelRef ref) {
+        return new JumpOp(ref);
+    }
+
+    protected LIRKind getPhiKind(PhiNode phi) {
+        return gen.getLIRKind(phi.stamp());
+    }
+
+    @Override
+    public void emitIf(IfNode x) {
+        emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
+    }
+
+    public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        if (node instanceof IsNullNode) {
+            emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof CompareNode) {
+            emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof LogicConstantNode) {
+            emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor);
+        } else if (node instanceof IntegerTestNode) {
+            emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else {
+            throw GraalError.unimplemented(node.toString());
+        }
+    }
+
+    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        LIRKind kind = gen.getLIRKind(node.getValue().stamp());
+        Value nullValue = gen.emitConstant(kind, JavaConstant.NULL_POINTER);
+        gen.emitCompareBranch(kind.getPlatformKind(), operand(node.getValue()), nullValue, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind();
+        gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        gen.emitIntegerTestBranch(operand(test.getX()), operand(test.getY()), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) {
+        LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
+        gen.emitJump(block);
+    }
+
+    @Override
+    public void emitConditional(ConditionalNode conditional) {
+        Value tVal = operand(conditional.trueValue());
+        Value fVal = operand(conditional.falseValue());
+        setResult(conditional, emitConditional(conditional.condition(), tVal, fVal));
+    }
+
+    public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) {
+        if (node instanceof IsNullNode) {
+            IsNullNode isNullNode = (IsNullNode) node;
+            LIRKind kind = gen.getLIRKind(isNullNode.getValue().stamp());
+            Value nullValue = gen.emitConstant(kind, JavaConstant.NULL_POINTER);
+            return gen.emitConditionalMove(kind.getPlatformKind(), operand(isNullNode.getValue()), nullValue, Condition.EQ, false, trueValue, falseValue);
+        } else if (node instanceof CompareNode) {
+            CompareNode compare = (CompareNode) node;
+            PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind();
+            return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
+        } else if (node instanceof LogicConstantNode) {
+            return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue);
+        } else if (node instanceof IntegerTestNode) {
+            IntegerTestNode test = (IntegerTestNode) node;
+            return gen.emitIntegerTestMove(operand(test.getX()), operand(test.getY()), trueValue, falseValue);
+        } else {
+            throw GraalError.unimplemented(node.toString());
+        }
+    }
+
+    @Override
+    public void emitInvoke(Invoke x) {
+        LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
+        CallingConvention invokeCc = gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()),
+                        callTarget.signature(), gen);
+        gen.getResult().getFrameMapBuilder().callsMethod(invokeCc);
+
+        Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());
+
+        LabelRef exceptionEdge = null;
+        if (x instanceof InvokeWithExceptionNode) {
+            exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge());
+        }
+        LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
+
+        Value result = invokeCc.getReturn();
+        if (callTarget instanceof DirectCallTargetNode) {
+            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
+        } else if (callTarget instanceof IndirectCallTargetNode) {
+            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+
+        if (isLegal(result)) {
+            setResult(x.asNode(), gen.emitMove(result));
+        }
+
+        if (x instanceof InvokeWithExceptionNode) {
+            gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next()));
+        }
+    }
+
+    protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
+
+    protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
+
+    @Override
+    public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) {
+        // for each argument, load it into the correct location
+        Value[] result = new Value[arguments.size()];
+        int j = 0;
+        for (ValueNode arg : arguments) {
+            if (arg != null) {
+                AllocatableValue operand = invokeCc.getArgument(j);
+                gen.emitMove(operand, operand(arg));
+                result[j] = operand;
+                j++;
+            } else {
+                throw GraalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types...");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * This method tries to create a switch implementation that is optimal for the given switch. It
+     * will either generate a sequential if/then/else cascade, a set of range tests or a table
+     * switch.
+     *
+     * If the given switch does not contain int keys, it will always create a sequential
+     * implementation.
+     */
+    @Override
+    public void emitSwitch(SwitchNode x) {
+        assert x.defaultSuccessor() != null;
+        LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor());
+        int keyCount = x.keyCount();
+        if (keyCount == 0) {
+            gen.emitJump(defaultTarget);
+        } else {
+            Variable value = gen.load(operand(x.value()));
+            if (keyCount == 1) {
+                assert defaultTarget != null;
+                double probability = x.probability(x.keySuccessor(0));
+                LIRKind kind = gen.getLIRKind(x.value().stamp());
+                Value key = gen.emitConstant(kind, x.keyAt(0));
+                gen.emitCompareBranch(kind.getPlatformKind(), gen.load(operand(x.value())), key, Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability);
+            } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
+                IntegerSwitchNode intSwitch = (IntegerSwitchNode) x;
+                LabelRef[] keyTargets = new LabelRef[keyCount];
+                JavaConstant[] keyConstants = new JavaConstant[keyCount];
+                double[] keyProbabilities = new double[keyCount];
+                JavaKind keyKind = intSwitch.keyAt(0).getJavaKind();
+                for (int i = 0; i < keyCount; i++) {
+                    keyTargets[i] = getLIRBlock(intSwitch.keySuccessor(i));
+                    keyConstants[i] = intSwitch.keyAt(i);
+                    keyProbabilities[i] = intSwitch.keyProbability(i);
+                    assert keyConstants[i].getJavaKind() == keyKind;
+                }
+                gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value);
+            } else {
+                // keyKind != JavaKind.Int || !x.isSorted()
+                LabelRef[] keyTargets = new LabelRef[keyCount];
+                Constant[] keyConstants = new Constant[keyCount];
+                double[] keyProbabilities = new double[keyCount];
+                for (int i = 0; i < keyCount; i++) {
+                    keyTargets[i] = getLIRBlock(x.keySuccessor(i));
+                    keyConstants[i] = x.keyAt(i);
+                    keyProbabilities[i] = x.keyProbability(i);
+                }
+
+                // hopefully only a few entries
+                gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
+            }
+        }
+    }
+
+    public DebugInfoBuilder getDebugInfoBuilder() {
+        assert debugInfoBuilder != null;
+        return debugInfoBuilder;
+    }
+
+    private static FrameState getFrameState(DeoptimizingNode deopt) {
+        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
+        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
+        } else {
+            assert deopt instanceof DeoptimizingNode.DeoptAfter;
+            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
+        }
+    }
+
+    @Override
+    public LIRFrameState state(DeoptimizingNode deopt) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateFor(getFrameState(deopt));
+    }
+
+    public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
+    }
+
+    public LIRFrameState stateFor(FrameState state) {
+        return stateForWithExceptionEdge(state, null);
+    }
+
+    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
+        if (gen.needOnlyOopMaps()) {
+            return new LIRFrameState(null, null, null);
+        }
+        assert state != null;
+        return getDebugInfoBuilder().build(state, exceptionEdge);
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp stamp, double probability) {
+        LIRKind cmpKind = getLIRGeneratorTool().getLIRKind(stamp);
+        gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), cmpKind, probability);
+    }
+
+    @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        append(new FullInfopointOp(stateFor(i.getState()), i.getReason()));
+    }
+
+    @Override
+    public void setSourcePosition(NodeSourcePosition position) {
+        gen.setSourcePosition(position);
+    }
+
+    @Override
+    public LIRGeneratorTool getLIRGeneratorTool() {
+        return gen;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java
new file mode 100644
index 0000000..280b670
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.gen;
+
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.core.match.MatchableNode;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
+import org.graalvm.compiler.nodes.calc.FloatLessThanNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.IntegerTestNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.calc.OrNode;
+import org.graalvm.compiler.nodes.calc.PointerEqualsNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
+import org.graalvm.compiler.nodes.calc.XorNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+
+@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
+@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
+@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = ReadNode.class, inputs = {"address"})
+@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = PointerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = PiNode.class, inputs = {"object"})
+public abstract class NodeMatchRules {
+
+    NodeLIRBuilder lirBuilder;
+    protected final LIRGeneratorTool gen;
+
+    protected NodeMatchRules(LIRGeneratorTool gen) {
+        this.gen = gen;
+    }
+
+    protected LIRGeneratorTool getLIRGeneratorTool() {
+        return gen;
+    }
+
+    /*
+     * For now we do not want to expose the full lirBuilder to subclasses, so we delegate the few
+     * methods that are actually needed. If the list grows too long, exposing lirBuilder might be
+     * the better approach.
+     */
+
+    protected final Value operand(Node node) {
+        return lirBuilder.operand(node);
+    }
+
+    protected final LIRFrameState state(DeoptimizingNode deopt) {
+        return lirBuilder.state(deopt);
+    }
+
+    protected final LabelRef getLIRBlock(FixedNode b) {
+        return lirBuilder.getLIRBlock(b);
+    }
+
+    protected final void append(LIRInstruction op) {
+        lirBuilder.append(op);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/package-info.java
new file mode 100644
index 0000000..f0f12aa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/**
+ * This package contains the port of the LIRGenerator which translates HIR instructions to LIR
+ * instructions for the backend.
+ */
+package org.graalvm.compiler.core.gen;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchResult.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchResult.java
new file mode 100644
index 0000000..e173a8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchResult.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+
+/**
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows
+ * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at
+ * the proper time.
+ */
+public interface ComplexMatchResult {
+    Value evaluate(NodeLIRBuilder gen);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchValue.java
new file mode 100644
index 0000000..c4349ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/ComplexMatchValue.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the
+ * closure because Value is serializable which is a hassle for the little inner classes which
+ * usually occur here.
+ */
+public class ComplexMatchValue extends Value {
+
+    /**
+     * This is the Value of a node which was matched as part of a complex match. The value isn't
+     * actually useable but this marks it as having been evaluated.
+     */
+    public static final Value INTERIOR_MATCH = new Value(LIRKind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "INTERIOR_MATCH";
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            // This class is a singleton
+            return other != null && getClass() == other.getClass();
+        }
+    };
+
+    final ComplexMatchResult result;
+
+    public ComplexMatchValue(ComplexMatchResult result) {
+        super(LIRKind.Illegal);
+        this.result = result;
+    }
+
+    public Value evaluate(NodeLIRBuilder builder) {
+        return result.evaluate(builder);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java
new file mode 100644
index 0000000..9abe43a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.core.match.MatchPattern.Result;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * Container for state captured during a match.
+ */
+public class MatchContext {
+
+    private final Node root;
+
+    private final List<Node> nodes;
+
+    private final MatchStatement rule;
+
+    private Map<String, NamedNode> namedNodes;
+
+    private ArrayList<Node> consumed;
+
+    private int startIndex;
+
+    private int endIndex;
+
+    private final NodeLIRBuilder builder;
+
+    private static class NamedNode {
+        final Class<? extends Node> type;
+        final Node value;
+
+        NamedNode(Class<? extends Node> type, Node value) {
+            this.type = type;
+            this.value = value;
+        }
+    }
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, List<Node> nodes) {
+        this.builder = builder;
+        this.rule = rule;
+        this.root = node;
+        this.nodes = nodes;
+        assert index == nodes.indexOf(node);
+        // The root should be the last index since all the inputs must be scheduled before it.
+        startIndex = endIndex = index;
+    }
+
+    public Node getRoot() {
+        return root;
+    }
+
+    public Result captureNamedValue(String name, Class<? extends Node> type, Node value) {
+        if (namedNodes == null) {
+            namedNodes = new HashMap<>(2);
+        }
+        NamedNode current = namedNodes.get(name);
+        if (current == null) {
+            current = new NamedNode(type, value);
+            namedNodes.put(name, current);
+            return Result.OK;
+        } else {
+            if (current.value != value || current.type != type) {
+                return Result.namedValueMismatch(value, rule.getPattern());
+            }
+            return Result.OK;
+        }
+    }
+
+    public Result validate() {
+        // Ensure that there's no unsafe work in between these operations.
+        for (int i = startIndex; i <= endIndex; i++) {
+            Node node = nodes.get(i);
+            if (node instanceof VirtualObjectNode || node instanceof FloatingNode) {
+                // The order of evaluation of these nodes controlled by data dependence so they
+                // don't interfere with this match.
+                continue;
+            } else if ((consumed == null || !consumed.contains(node)) && node != root) {
+                if (LogVerbose.getValue()) {
+                    Debug.log("unexpected node %s", node);
+                    for (int j = startIndex; j <= endIndex; j++) {
+                        Node theNode = nodes.get(j);
+                        Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.getUsageCount(), theNode);
+                    }
+                }
+                return Result.notSafe(node, rule.getPattern());
+            }
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
+     * During final LIR generation it will be evaluated to produce the actual LIR value.
+     *
+     * @param result
+     */
+    public void setResult(ComplexMatchResult result) {
+        ComplexMatchValue value = new ComplexMatchValue(result);
+        if (Debug.isLogEnabled()) {
+            Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+            Debug.log("with nodes %s", rule.formatMatch(root));
+        }
+        if (consumed != null) {
+            for (Node node : consumed) {
+                // All the interior nodes should be skipped during the normal doRoot calls in
+                // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+                // closure which will be evaluated to produce the final LIR.
+                builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH);
+            }
+        }
+        builder.setMatchResult(root, value);
+    }
+
+    /**
+     * Mark a node as consumed by the match. Consumed nodes will never be evaluated.
+     *
+     * @return Result.OK if the node can be safely consumed.
+     */
+    public Result consume(Node node) {
+        assert node.getUsageCount() <= 1 : "should have already been checked";
+
+        // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED
+        int index = nodes.indexOf(node);
+        if (index == -1) {
+            return Result.notInBlock(node, rule.getPattern());
+        }
+
+        if (builder.hasOperand(node)) {
+            return Result.alreadyUsed(node, rule.getPattern());
+        }
+
+        startIndex = Math.min(startIndex, index);
+        if (consumed == null) {
+            consumed = new ArrayList<>(2);
+        }
+        consumed.add(node);
+        return Result.OK;
+    }
+
+    /**
+     * Return the named node. It's an error if the
+     *
+     * @param name the name of a node in the match rule
+     * @return the matched node
+     * @throws GraalError is the named node doesn't exist.
+     */
+    public Node namedNode(String name) {
+        if (namedNodes != null) {
+            NamedNode value = namedNodes.get(name);
+            if (value != null) {
+                return value.value;
+            }
+        }
+        throw new GraalError("missing node %s", name);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : "");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchGenerator.java
new file mode 100644
index 0000000..31249c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchGenerator.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+
+/**
+ * Code generator for complex match patterns.
+ */
+public interface MatchGenerator {
+    /**
+     * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
+     *          evaluated during LIR generation to produce the final LIR value.
+     */
+    ComplexMatchResult match(NodeMatchRules matchRules, Object... args);
+
+    /**
+     * @return a descriptive name meaningful to the user.
+     */
+    String getName();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java
new file mode 100644
index 0000000..171c2dbf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+
+/**
+ * A simple recursive pattern matcher for a DAG of nodes.
+ */
+
+public class MatchPattern {
+
+    enum MatchResultCode {
+        OK,
+        WRONG_CLASS,
+        NAMED_VALUE_MISMATCH,
+        TOO_MANY_USERS,
+        NOT_IN_BLOCK,
+        NOT_SAFE,
+        ALREADY_USED,
+    }
+
+    /**
+     * A descriptive result for match failures. This can be helpful for debugging why a match
+     * doesn't work as expected.
+     */
+    static class Result {
+        final MatchResultCode code;
+
+        final Node node;
+
+        final MatchPattern matcher;
+
+        Result(MatchResultCode result, Node node, MatchPattern matcher) {
+            this.code = result;
+            this.node = node;
+            this.matcher = matcher;
+        }
+
+        private static final DebugCounter MatchResult_WRONG_CLASS = Debug.counter("MatchResult_WRONG_CLASS");
+        private static final DebugCounter MatchResult_NAMED_VALUE_MISMATCH = Debug.counter("MatchResult_NAMED_VALUE_MISMATCH");
+        private static final DebugCounter MatchResult_TOO_MANY_USERS = Debug.counter("MatchResult_TOO_MANY_USERS");
+        private static final DebugCounter MatchResult_NOT_IN_BLOCK = Debug.counter("MatchResult_NOT_IN_BLOCK");
+        private static final DebugCounter MatchResult_NOT_SAFE = Debug.counter("MatchResult_NOT_SAFE");
+        private static final DebugCounter MatchResult_ALREADY_USED = Debug.counter("MatchResult_ALREADY_USED");
+
+        static final Result OK = new Result(MatchResultCode.OK, null, null);
+        private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null);
+        private static final Result CACHED_NAMED_VALUE_MISMATCH = new Result(MatchResultCode.NAMED_VALUE_MISMATCH, null, null);
+        private static final Result CACHED_TOO_MANY_USERS = new Result(MatchResultCode.TOO_MANY_USERS, null, null);
+        private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null);
+        private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
+        private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);
+
+        static Result wrongClass(Node node, MatchPattern matcher) {
+            MatchResult_WRONG_CLASS.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS;
+        }
+
+        static Result namedValueMismatch(Node node, MatchPattern matcher) {
+            MatchResult_NAMED_VALUE_MISMATCH.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH;
+        }
+
+        static Result tooManyUsers(Node node, MatchPattern matcher) {
+            MatchResult_TOO_MANY_USERS.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS;
+        }
+
+        static Result notInBlock(Node node, MatchPattern matcher) {
+            MatchResult_NOT_IN_BLOCK.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK;
+        }
+
+        static Result notSafe(Node node, MatchPattern matcher) {
+            MatchResult_NOT_SAFE.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE;
+        }
+
+        static Result alreadyUsed(Node node, MatchPattern matcher) {
+            MatchResult_ALREADY_USED.increment();
+            return Debug.isLogEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
+        }
+
+        @Override
+        public String toString() {
+            if (code == MatchResultCode.OK) {
+                return "OK";
+            }
+            if (node == null) {
+                return code.toString();
+            } else {
+                return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+            }
+        }
+    }
+
+    /**
+     * The expected type of the node. It must match exactly.
+     */
+    private final Class<? extends Node> nodeClass;
+
+    /**
+     * An optional name for this node. A name can occur multiple times in a match and that name must
+     * always refer to the same node of the match will fail.
+     */
+    private final String name;
+
+    /**
+     * Patterns to match the inputs.
+     */
+    private final MatchPattern[] patterns;
+
+    /**
+     * The inputs to match the patterns against.
+     */
+    private final Position[] inputs;
+
+    /**
+     * Can there only be one user of the node. Constant nodes can be matched even if there are other
+     * users.
+     */
+    private final boolean singleUser;
+
+    private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
+
+    public MatchPattern(String name, boolean singleUser) {
+        this(null, name, singleUser);
+    }
+
+    public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser) {
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = EMPTY_PATTERNS;
+        this.inputs = null;
+    }
+
+    private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
+        assert inputs == null || inputs.length == patterns.length;
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = patterns;
+        this.inputs = inputs;
+    }
+
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
+    }
+
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
+    }
+
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
+    }
+
+    Class<? extends Node> nodeClass() {
+        return nodeClass;
+    }
+
+    private Result matchType(Node node) {
+        if (nodeClass != null && node.getClass() != nodeClass) {
+            return Result.wrongClass(node, this);
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Match any named nodes and ensure that the consumed nodes can be safely merged.
+     *
+     * @param node
+     * @param context
+     * @return Result.OK is the pattern can be safely matched.
+     */
+    Result matchUsage(Node node, MatchContext context) {
+        Result result = matchUsage(node, context, true);
+        if (result == Result.OK) {
+            result = context.validate();
+        }
+        return result;
+    }
+
+    private Result matchUsage(Node node, MatchContext context, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+        if (singleUser && !atRoot) {
+            result = context.consume(node);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        if (name != null) {
+            result = context.captureNamedValue(name, nodeClass, node);
+        }
+
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchUsage(getInput(input, node), context, false);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Recursively match the shape of the tree without worry about named values. Most matches fail
+     * at this point so it's performed first.
+     *
+     * @param node
+     * @param statement
+     * @return Result.OK if the shape of the pattern matches.
+     */
+    public Result matchShape(Node node, MatchStatement statement) {
+        return matchShape(node, statement, true);
+    }
+
+    private Result matchShape(Node node, MatchStatement statement, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+
+        if (singleUser && !atRoot) {
+            if (node.getUsageCount() > 1) {
+                return Result.tooManyUsers(node, statement.getPattern());
+            }
+        }
+
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchShape(getInput(input, node), statement, false);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * For a node starting at root, produce a String showing the inputs that matched against this
+     * rule. It's assumed that a match has already succeeded against this rule, otherwise the
+     * printing may produce exceptions.
+     */
+    public String formatMatch(Node root) {
+        String result = String.format("%s", root);
+        if (patterns.length == 0) {
+            return result;
+        } else {
+            StringBuilder sb = new StringBuilder();
+            sb.append("(");
+            sb.append(result);
+            for (int input = 0; input < patterns.length; input++) {
+                sb.append(" ");
+                sb.append(patterns[input].formatMatch(getInput(input, root)));
+            }
+            sb.append(")");
+            return sb.toString();
+        }
+    }
+
+    private Node getInput(int index, Node node) {
+        return inputs[index].get(node);
+    }
+
+    @Override
+    public String toString() {
+        if (nodeClass == null) {
+            return name;
+        } else {
+            String nodeName = nodeClass.getSimpleName();
+            if (nodeName.endsWith("Node")) {
+                nodeName = nodeName.substring(0, nodeName.length() - 4);
+            }
+            if (patterns.length == 0) {
+                return nodeName + (name != null ? "=" + name : "");
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append("(");
+                sb.append(nodeName);
+                for (int index = 0; index < patterns.length; index++) {
+                    sb.append(" ");
+                    sb.append(patterns[index].toString());
+                }
+                sb.append(")");
+                return sb.toString();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRule.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRule.java
new file mode 100644
index 0000000..32b205c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRule.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.graalvm.compiler.nodes.ConstantNode;
+
+/**
+ * This annotation declares a textual pattern for matching an HIR tree. The format is a LISP style
+ * s-expression with node types and/or names that are matched against the HIR. Node types are always
+ * uppercase and the names of nodes are always lowercase. Named nodes can be used to match trees
+ * where a node is used multiple times but only as an input to the full match.
+ *
+ * <pre>
+ *   &lt;node-name&gt;    := [a-z][a-zA-Z0-9]*
+ *   &lt;node-type&gt;    := [A-Z][a-zA-Z0-9]*
+ *   &lt;node-spec&gt;    := &lt;node-type&gt; { '=' &lt;node-name&gt; }
+ *   &lt;node-or-name&gt; := &lt;node-spec&gt; | &lt;node-name&gt;
+ *   &lt;argument&gt;     := &lt;node-or-name&gt; | &lt;match-rule&gt;
+ *   &lt;match-rule&gt;   := '(' &lt;node-spec&gt; &lt;argument&gt;+ ')'
+ * </pre>
+ *
+ * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
+ * All matched nodes must be in the same block.
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Repeatable(value = MatchRules.class)
+public @interface MatchRule {
+    String value();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java
new file mode 100644
index 0000000..bab5c59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+public class MatchRuleRegistry {
+
+    /**
+     * Convert a list of field names into {@link org.graalvm.compiler.graph.Position} objects that
+     * can be used to read them during a match. The names should already have been confirmed to
+     * exist in the type.
+     *
+     * @param nodeClass
+     * @param names
+     * @return an array of Position objects corresponding to the named fields.
+     */
+    public static Position[] findPositions(NodeClass<? extends Node> nodeClass, String[] names) {
+        Position[] result = new Position[names.length];
+        for (int i = 0; i < names.length; i++) {
+            Edges edges = nodeClass.getInputEdges();
+            for (int e = 0; e < edges.getDirectCount(); e++) {
+                if (names[i].equals(edges.getName(e))) {
+                    result[i] = new Position(edges, e, Node.NOT_ITERABLE);
+                }
+            }
+            if (result[i] == null) {
+                throw new GraalError("unknown field \"%s\" in class %s", names[i], nodeClass);
+            }
+        }
+        return result;
+    }
+
+    private static final HashMap<Class<? extends NodeMatchRules>, Map<Class<? extends Node>, List<MatchStatement>>> registry = new HashMap<>();
+
+    /**
+     * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
+     *
+     * @param theClass
+     * @return the set of {@link MatchStatement}s applicable to theClass.
+     */
+    @SuppressWarnings("try")
+    public static synchronized Map<Class<? extends Node>, List<MatchStatement>> lookup(Class<? extends NodeMatchRules> theClass) {
+        Map<Class<? extends Node>, List<MatchStatement>> result = registry.get(theClass);
+
+        if (result == null) {
+            Map<Class<? extends Node>, List<MatchStatement>> rules = createRules(theClass);
+            registry.put(theClass, rules);
+            assert registry.get(theClass) == rules;
+            result = rules;
+
+            if (LogVerbose.getValue()) {
+                try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                    Debug.log("Match rules for %s", theClass.getSimpleName());
+                    for (Entry<Class<? extends Node>, List<MatchStatement>> entry : result.entrySet()) {
+                        Debug.log("  For node class: %s", entry.getKey());
+                        for (MatchStatement statement : entry.getValue()) {
+                            Debug.log("    %s", statement.getPattern());
+                        }
+                    }
+                }
+            }
+        }
+
+        if (result.size() == 0) {
+            return null;
+        }
+        return result;
+    }
+
+    /*
+     * This is a separate, public method so that external clients can create rules with a custom
+     * lookup and without the default caching behavior.
+     */
+    public static Map<Class<? extends Node>, List<MatchStatement>> createRules(Class<? extends NodeMatchRules> theClass) {
+        HashMap<Class<? extends NodeMatchRules>, MatchStatementSet> matchSets = new HashMap<>();
+        Iterable<MatchStatementSet> sl = GraalServices.load(MatchStatementSet.class);
+        for (MatchStatementSet rules : sl) {
+            matchSets.put(rules.forClass(), rules);
+        }
+
+        // Walk the class hierarchy collecting lists and merge them together. The subclass
+        // rules are first which gives them preference over earlier rules.
+        Map<Class<? extends Node>, List<MatchStatement>> rules = new HashMap<>();
+        Class<?> currentClass = theClass;
+        do {
+            MatchStatementSet matchSet = matchSets.get(currentClass);
+            if (matchSet != null) {
+                List<MatchStatement> statements = matchSet.statements();
+                for (MatchStatement statement : statements) {
+                    Class<? extends Node> nodeClass = statement.getPattern().nodeClass();
+                    List<MatchStatement> current = rules.get(nodeClass);
+                    if (current == null) {
+                        current = new ArrayList<>();
+                        rules.put(nodeClass, current);
+                    }
+                    current.add(statement);
+                }
+            }
+            currentClass = currentClass.getSuperclass();
+        } while (currentClass != NodeMatchRules.class);
+        return rules;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRules.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRules.java
new file mode 100644
index 0000000..f300bcc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRules.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The repeatable representation of {@link MatchRule}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface MatchRules {
+    MatchRule[] value();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java
new file mode 100644
index 0000000..7d4fbb0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose;
+
+import java.util.List;
+
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.core.match.MatchPattern.MatchResultCode;
+import org.graalvm.compiler.core.match.MatchPattern.Result;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.GraalGraphError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+
+/**
+ * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
+ * one or more {@link Node}s with a single {@link Value}.
+ */
+
+public class MatchStatement {
+    private static final DebugCounter MatchStatementSuccess = Debug.counter("MatchStatementSuccess");
+
+    /**
+     * A printable name for this statement. Usually it's just the name of the method doing the
+     * emission.
+     */
+    private final String name;
+
+    /**
+     * The actual match pattern.
+     */
+    private final MatchPattern pattern;
+
+    /**
+     * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission.
+     */
+    private MatchGenerator generatorMethod;
+
+    /**
+     * The name of arguments in the order they are expected to be passed to the generator method.
+     */
+    private String[] arguments;
+
+    public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) {
+        this.name = name;
+        this.pattern = pattern;
+        this.generatorMethod = generator;
+        this.arguments = arguments;
+    }
+
+    /**
+     * Attempt to match the current statement against a Node.
+     *
+     * @param builder the current builder instance.
+     * @param node the node to be matched
+     * @param nodes the nodes in the current block
+     * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
+     *         evaluated by the NodeLIRBuilder.
+     */
+    public boolean generate(NodeLIRBuilder builder, int index, Node node, List<Node> nodes) {
+        assert index == nodes.indexOf(node);
+        // Check that the basic shape matches
+        Result result = pattern.matchShape(node, this);
+        if (result != Result.OK) {
+            return false;
+        }
+        // Now ensure that the other safety constraints are matched.
+        MatchContext context = new MatchContext(builder, this, index, node, nodes);
+        result = pattern.matchUsage(node, context);
+        if (result == Result.OK) {
+            // Invoke the generator method and set the result if it's non null.
+            ComplexMatchResult value = generatorMethod.match(builder.getNodeMatchRules(), buildArgList(context));
+            if (value != null) {
+                context.setResult(value);
+                MatchStatementSuccess.increment();
+                Debug.counter("MatchStatement[%s]", getName()).increment();
+                return true;
+            }
+            // The pattern matched but some other code generation constraint disallowed code
+            // generation for the pattern.
+            if (LogVerbose.getValue()) {
+                Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName());
+                Debug.log("with nodes %s", formatMatch(node));
+            }
+        } else {
+            if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) {
+                Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param context
+     * @return the Nodes captured by the match rule in the order expected by the generatorMethod
+     */
+    private Object[] buildArgList(MatchContext context) {
+        Object[] result = new Object[arguments.length];
+        for (int i = 0; i < arguments.length; i++) {
+            if ("root".equals(arguments[i])) {
+                result[i] = context.getRoot();
+            } else {
+                result[i] = context.namedNode(arguments[i]);
+                if (result[i] == null) {
+                    throw new GraalGraphError("Can't find named node %s", arguments[i]);
+                }
+            }
+        }
+        return result;
+    }
+
+    public String formatMatch(Node root) {
+        return pattern.formatMatch(root);
+    }
+
+    public MatchPattern getPattern() {
+        return pattern;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return pattern.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatementSet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatementSet.java
new file mode 100644
index 0000000..b4f95c0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatementSet.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.core.gen.NodeMatchRules;
+
+public interface MatchStatementSet {
+    /**
+     * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
+     *         instances.
+     */
+    Class<? extends NodeMatchRules> forClass();
+
+    /**
+     * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
+     */
+    List<MatchStatement> statements();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java
new file mode 100644
index 0000000..438b547
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * Describes the properties of a node for use when building a {@link MatchPattern}. These
+ * declarations are required when parsing a {@link MatchRule}. They are expected to be found on a
+ * super type of the holder of the method declaring the {@link MatchRule}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchableNodes.class)
+public @interface MatchableNode {
+
+    /**
+     * The {@link ValueNode} subclass this annotation describes. These annotations might work better
+     * if they were directly on the node being described but that may complicate the annotation
+     * processing.
+     */
+    Class<? extends ValueNode> nodeClass();
+
+    /**
+     * The names of the inputs in the order they should appear in the match.
+     */
+    String[] inputs() default {};
+
+    /**
+     * Can a pattern be matched with the operands swapped. This will cause swapped versions of
+     * patterns to be automatically generated.
+     */
+    boolean commutative() default false;
+
+    /**
+     * Can a node with multiple uses be safely matched by a rule.
+     */
+    boolean shareable() default false;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNodes.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNodes.java
new file mode 100644
index 0000000..d6bd274
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNodes.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.match;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The repeatable representation of {@link MatchableNode}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodes {
+    MatchableNode[] value() default {};
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/package-info.java
new file mode 100644
index 0000000..05d9a6d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * The top-level package in Graal containing the main compiler class
+ * {@link org.graalvm.compiler.core.GraalCompiler}.
+ */
+package org.graalvm.compiler.core;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java
new file mode 100644
index 0000000..c2ff09d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.AllocationStage;
+import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationStage;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationStage;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class CoreCompilerConfiguration implements CompilerConfiguration {
+
+    @Override
+    public PhaseSuite<HighTierContext> createHighTier() {
+        return new HighTier();
+    }
+
+    @Override
+    public PhaseSuite<MidTierContext> createMidTier() {
+        return new MidTier();
+    }
+
+    @Override
+    public PhaseSuite<LowTierContext> createLowTier() {
+        return new LowTier();
+    }
+
+    @Override
+    public LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage() {
+        return new PreAllocationOptimizationStage();
+    }
+
+    @Override
+    public LIRPhaseSuite<AllocationContext> createAllocationStage() {
+        return new AllocationStage();
+    }
+
+    @Override
+    public LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage() {
+        return new PostAllocationOptimizationStage();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java
new file mode 100644
index 0000000..307a59b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.EconomyAllocationStage;
+import org.graalvm.compiler.lir.phases.EconomyPostAllocationOptimizationStage;
+import org.graalvm.compiler.lir.phases.EconomyPreAllocationOptimizationStage;
+import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class EconomyCompilerConfiguration implements CompilerConfiguration {
+
+    @Override
+    public PhaseSuite<HighTierContext> createHighTier() {
+        return new EconomyHighTier();
+    }
+
+    @Override
+    public PhaseSuite<MidTierContext> createMidTier() {
+        return new EconomyMidTier();
+    }
+
+    @Override
+    public PhaseSuite<LowTierContext> createLowTier() {
+        return new EconomyLowTier();
+    }
+
+    @Override
+    public LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage() {
+        return new EconomyPreAllocationOptimizationStage();
+    }
+
+    @Override
+    public LIRPhaseSuite<AllocationContext> createAllocationStage() {
+        return new EconomyAllocationStage();
+    }
+
+    @Override
+    public LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage() {
+        return new EconomyPostAllocationOptimizationStage();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java
new file mode 100644
index 0000000..76efa54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class EconomyHighTier extends PhaseSuite<HighTierContext> {
+
+    public EconomyHighTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+
+        appendPhase(canonicalizer);
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java
new file mode 100644
index 0000000..db1b0f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ExpandLogicPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+
+public class EconomyLowTier extends PhaseSuite<LowTierContext> {
+
+    public EconomyLowTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
+
+        appendPhase(new ExpandLogicPhase());
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java
new file mode 100644
index 0000000..c6350bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class EconomyMidTier extends PhaseSuite<MidTierContext> {
+
+    public EconomyMidTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+        appendPhase(new RemoveValueProxyPhase());
+
+        appendPhase(new LoopSafepointInsertionPhase());
+
+        appendPhase(new GuardLoweringPhase());
+
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
+
+        appendPhase(new FrameStateAssignmentPhase());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java
new file mode 100644
index 0000000..bb7236d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * A utility phase for detecting when a phase would change the graph and reporting extra information
+ * about the effects. The phase is first run on a copy of the graph and if a change in that graph is
+ * detected then it's rerun on the original graph inside a new debug scope under
+ * GraphChangeMonitoringPhase. The message argument can be used to distinguish between the same
+ * phase run at different points.
+ *
+ * @param <C>
+ */
+public class GraphChangeMonitoringPhase<C extends PhaseContext> extends PhaseSuite<C> {
+
+    private final String message;
+
+    public GraphChangeMonitoringPhase(String message, BasePhase<C> phase) {
+        super();
+        this.message = message;
+        appendPhase(phase);
+    }
+
+    public GraphChangeMonitoringPhase(String message) {
+        super();
+        this.message = message;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, C context) {
+        /*
+         * Phase may add nodes but not end up using them so ignore additions. Nodes going dead and
+         * having their inputs change are the main interesting differences.
+         */
+        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED);
+        StructuredGraph graphCopy = (StructuredGraph) graph.copy();
+        try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) {
+            try (Scope s2 = Debug.sandbox("WithoutMonitoring", null)) {
+                super.run(graphCopy, context);
+            } catch (Throwable t) {
+                Debug.handle(t);
+            }
+        }
+        /*
+         * Ignore LogicConstantNode since those are sometimes created and deleted as part of running
+         * a phase.
+         */
+        if (listener.getNodes().stream().filter(e -> !(e instanceof LogicConstantNode)).findFirst().isPresent()) {
+            /* rerun it on the real graph in a new Debug scope so Dump and Log can find it. */
+            listener = new HashSetNodeEventListener();
+            try (NodeEventScope s = graph.trackNodeEvents(listener)) {
+                try (Scope s2 = Debug.scope("WithGraphChangeMonitoring")) {
+                    if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+                        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** Before phase %s", getName());
+                    }
+                    super.run(graph, context);
+                    Set<Node> collect = listener.getNodes().stream().filter(e -> !e.isAlive()).filter(e -> !(e instanceof LogicConstantNode)).collect(Collectors.toSet());
+                    if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+                        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** After phase %s %s", getName(), collect);
+                    }
+                    Debug.log("*** %s %s %s\n", message, graph, collect);
+                }
+            }
+        } else {
+            // Go ahead and run it normally even though it should have no effect
+            super.run(graph, context);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java
new file mode 100644
index 0000000..675c1dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
+import static org.graalvm.compiler.core.common.GraalOptions.FullUnroll;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.LoopPeeling;
+import static org.graalvm.compiler.core.common.GraalOptions.LoopUnswitch;
+import static org.graalvm.compiler.core.common.GraalOptions.OptConvertDeoptsToGuards;
+import static org.graalvm.compiler.core.common.GraalOptions.OptLoopTransform;
+import static org.graalvm.compiler.core.common.GraalOptions.PartialEscapeAnalysis;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
+
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
+import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
+import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.common.instrumentation.HighTierReconcileInstrumentationPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+public class HighTier extends PhaseSuite<HighTierContext> {
+
+    public static class Options {
+
+        // @formatter:off
+        @Option(help = "Enable inlining", type = OptionType.Expert)
+        public static final OptionValue<Boolean> Inline = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    public HighTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+
+        appendPhase(canonicalizer);
+
+        if (Options.Inline.getValue()) {
+            appendPhase(new InliningPhase(canonicalizer));
+            appendPhase(new DeadCodeEliminationPhase(Optional));
+
+            if (ConditionalElimination.getValue()) {
+                appendPhase(canonicalizer);
+                appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, false));
+            }
+        }
+
+        if (OptConvertDeoptsToGuards.getValue()) {
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new ConvertDeoptimizeToGuardPhase()));
+        }
+
+        LoopPolicies loopPolicies = createLoopPolicies();
+        if (FullUnroll.getValue()) {
+            appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies));
+        }
+
+        if (OptLoopTransform.getValue()) {
+            if (LoopPeeling.getValue()) {
+                appendPhase(new LoopPeelingPhase(loopPolicies));
+            }
+            if (LoopUnswitch.getValue()) {
+                appendPhase(new LoopUnswitchingPhase(loopPolicies));
+            }
+        }
+
+        appendPhase(canonicalizer);
+
+        if (PartialEscapeAnalysis.getValue()) {
+            appendPhase(new PartialEscapePhase(true, canonicalizer));
+        }
+        appendPhase(new RemoveValueProxyPhase());
+
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER));
+        if (UseGraalInstrumentation.getValue()) {
+            appendPhase(new HighTierReconcileInstrumentationPhase());
+        }
+    }
+
+    public LoopPolicies createLoopPolicies() {
+        return new DefaultLoopPolicies();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java
new file mode 100644
index 0000000..57c72bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.ExpandLogicPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ProfileCompiledMethodsPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.UseTrappingNullChecksPhase;
+import org.graalvm.compiler.phases.common.instrumentation.InlineInstrumentationPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+
+public class LowTier extends PhaseSuite<LowTierContext> {
+
+    static class Options {
+
+        // @formatter:off
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> ProfileCompiledMethods = new OptionValue<>(false);
+        // @formatter:on
+
+    }
+
+    public LowTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+
+        if (Options.ProfileCompiledMethods.getValue()) {
+            appendPhase(new ProfileCompiledMethodsPhase());
+        }
+
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
+        if (UseGraalInstrumentation.getValue()) {
+            appendPhase(new InlineInstrumentationPhase());
+        }
+
+        appendPhase(new RemoveValueProxyPhase());
+
+        appendPhase(new ExpandLogicPhase());
+
+        /* Cleanup IsNull checks resulting from MID_TIER/LOW_TIER lowering and ExpandLogic phase. */
+        if (ConditionalElimination.getValue()) {
+            appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, false));
+            /* Canonicalizer may create some new ShortCircuitOrNodes so clean them up. */
+            appendPhase(new ExpandLogicPhase());
+        }
+
+        appendPhase(new UseTrappingNullChecksPhase());
+
+        appendPhase(new DeadCodeEliminationPhase(Required));
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java
new file mode 100644
index 0000000..dc79e14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.OptDeoptimizationGrouping;
+import static org.graalvm.compiler.core.common.GraalOptions.OptEliminatePartiallyRedundantGuards;
+import static org.graalvm.compiler.core.common.GraalOptions.OptFloatingReads;
+import static org.graalvm.compiler.core.common.GraalOptions.OptPushThroughPi;
+import static org.graalvm.compiler.core.common.GraalOptions.OptReadElimination;
+import static org.graalvm.compiler.core.common.GraalOptions.ReassociateInvariants;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.core.common.GraalOptions.VerifyHeapAtReturn;
+
+import org.graalvm.compiler.loop.phases.LoopSafepointEliminationPhase;
+import org.graalvm.compiler.loop.phases.ReassociateInvariantPhase;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeoptimizationGroupingPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LockEliminationPhase;
+import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.OptimizeGuardAnchorsPhase;
+import org.graalvm.compiler.phases.common.PushThroughPiPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.ValueAnchorCleanupPhase;
+import org.graalvm.compiler.phases.common.VerifyHeapAtReturnPhase;
+import org.graalvm.compiler.phases.common.instrumentation.MidTierReconcileInstrumentationPhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+
+public class MidTier extends PhaseSuite<MidTierContext> {
+
+    public MidTier() {
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        if (ImmutableCode.getValue()) {
+            canonicalizer.disableReadCanonicalization();
+        }
+
+        if (OptPushThroughPi.getValue()) {
+            appendPhase(new PushThroughPiPhase());
+        }
+
+        appendPhase(canonicalizer);
+
+        appendPhase(new ValueAnchorCleanupPhase());
+        appendPhase(new LockEliminationPhase());
+
+        if (OptReadElimination.getValue()) {
+            appendPhase(new EarlyReadEliminationPhase(canonicalizer));
+        }
+
+        if (OptFloatingReads.getValue()) {
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()));
+        }
+        appendPhase(new RemoveValueProxyPhase());
+
+        appendPhase(canonicalizer);
+
+        if (OptEliminatePartiallyRedundantGuards.getValue()) {
+            appendPhase(new OptimizeGuardAnchorsPhase());
+        }
+
+        if (ConditionalElimination.getValue()) {
+            appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, true));
+        }
+
+        if (OptEliminatePartiallyRedundantGuards.getValue()) {
+            appendPhase(new OptimizeGuardAnchorsPhase());
+        }
+
+        appendPhase(canonicalizer);
+
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopSafepointEliminationPhase()));
+
+        appendPhase(new LoopSafepointInsertionPhase());
+
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new GuardLoweringPhase()));
+
+        if (VerifyHeapAtReturn.getValue()) {
+            appendPhase(new VerifyHeapAtReturnPhase());
+        }
+
+        appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
+        if (UseGraalInstrumentation.getValue()) {
+            appendPhase(new MidTierReconcileInstrumentationPhase());
+        }
+
+        appendPhase(new FrameStateAssignmentPhase());
+
+        if (ReassociateInvariants.getValue()) {
+            appendPhase(new ReassociateInvariantPhase());
+        }
+
+        if (OptDeoptimizationGrouping.getValue()) {
+            appendPhase(new DeoptimizationGroupingPhase());
+        }
+
+        appendPhase(canonicalizer);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java
new file mode 100644
index 0000000..53214af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.target;
+
+import java.util.Set;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.phases.tiers.SuitesProvider;
+import org.graalvm.compiler.phases.tiers.TargetProvider;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationRequest;
+import jdk.vm.ci.code.CompiledCode;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.ValueKindFactory;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.SpeculationLog;
+
+/**
+ * Represents a compiler backend for Graal.
+ */
+public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKind> {
+
+    private final Providers providers;
+
+    public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class);
+    public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class);
+
+    protected Backend(Providers providers) {
+        this.providers = providers;
+    }
+
+    public Providers getProviders() {
+        return providers;
+    }
+
+    public CodeCacheProvider getCodeCache() {
+        return providers.getCodeCache();
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    public ConstantReflectionProvider getConstantReflection() {
+        return providers.getConstantReflection();
+    }
+
+    public ForeignCallsProvider getForeignCalls() {
+        return providers.getForeignCalls();
+    }
+
+    public abstract SuitesProvider getSuites();
+
+    @Override
+    public TargetDescription getTarget() {
+        return providers.getCodeCache().getTarget();
+    }
+
+    @Override
+    public LIRKind getValueKind(JavaKind javaKind) {
+        return LIRKind.fromJavaKind(getTarget().arch, javaKind);
+    }
+
+    /**
+     * The given registerConfig is optional, in case null is passed the default RegisterConfig from
+     * the CodeCacheProvider will be used.
+     */
+    public abstract FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig);
+
+    public abstract RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig);
+
+    public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
+
+    public abstract LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes);
+
+    public abstract LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph,
+                    Object stub);
+
+    public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
+
+    /**
+     * Creates the assembler used to emit the machine code.
+     */
+    protected abstract Assembler createAssembler(FrameMap frameMap);
+
+    /**
+     * Creates the object used to fill in the details of a given compilation result.
+     */
+    public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult,
+                    CompilationResultBuilderFactory factory);
+
+    /**
+     * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed
+     * to the VM for code installation.
+     */
+    protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult);
+
+    /**
+     * @see #createInstalledCode(ResolvedJavaMethod, CompilationRequest, CompilationResult,
+     *      SpeculationLog, InstalledCode, boolean)
+     */
+    public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult,
+                    SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) {
+        return createInstalledCode(method, null, compilationResult, speculationLog, predefinedInstalledCode, isDefault);
+    }
+
+    /**
+     * Installs code based on a given compilation result.
+     *
+     * @param method the method compiled to produce {@code compiledCode} or {@code null} if the
+     *            input to {@code compResult} was not a {@link ResolvedJavaMethod}
+     * @param compilationRequest the compilation request or {@code null}
+     * @param compilationResult the code to be compiled
+     * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a
+     *            reference to the installed code. If {@code null}, a new {@link InstalledCode}
+     *            object will be created.
+     * @param speculationLog the speculation log to be used
+     * @param isDefault specifies if the installed code should be made the default implementation of
+     *            {@code compRequest.getMethod()}. The default implementation for a method is the
+     *            code executed for standard calls to the method. This argument is ignored if
+     *            {@code compRequest == null}.
+     * @return a reference to the compiled and ready-to-run installed code
+     * @throws BailoutException if the code installation failed
+     */
+    @SuppressWarnings("try")
+    public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult,
+                    SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) {
+        try (Scope s2 = Debug.scope("CodeInstall", getProviders().getCodeCache(), compilationResult)) {
+            CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
+            return getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     * Installs code based on a given compilation result.
+     *
+     * @param method the method compiled to produce {@code compiledCode} or {@code null} if the
+     *            input to {@code compResult} was not a {@link ResolvedJavaMethod}
+     * @param compilationRequest the request or {@code null}
+     * @param compilationResult the code to be compiled
+     * @return a reference to the compiled and ready-to-run installed code
+     * @throws BailoutException if the code installation failed
+     */
+    public InstalledCode addInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult) {
+        return createInstalledCode(method, compilationRequest, compilationResult, null, null, false);
+    }
+
+    /**
+     * Installs code based on a given compilation result and sets it as the default code to be used
+     * when {@code method} is invoked.
+     *
+     * @param method the method compiled to produce {@code compiledCode} or {@code null} if the
+     *            input to {@code compResult} was not a {@link ResolvedJavaMethod}
+     * @param compilationResult the code to be compiled
+     * @return a reference to the compiled and ready-to-run installed code
+     * @throws BailoutException if the code installation failed
+     */
+    public InstalledCode createDefaultInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult) {
+        return createInstalledCode(method, compilationResult, null, null, true);
+    }
+
+    /**
+     * Emits the code for a given graph.
+     *
+     * @param installedCodeOwner the method the compiled code will be associated with once
+     *            installed. This argument can be null.
+     */
+    public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner);
+
+    /**
+     * Translates a set of registers from the callee's perspective to the caller's perspective. This
+     * is needed for architectures where input/output registers are renamed during a call (e.g.
+     * register windows on SPARC). Registers which are not visible by the caller are removed.
+     */
+    public abstract Set<Register> translateToCallerRegisters(Set<Register> calleeRegisters);
+
+    /**
+     * Gets the compilation id for a given {@link ResolvedJavaMethod}. Returns
+     * {@code CompilationIdentifier#INVALID_COMPILATION_ID} in case there is no such id.
+     *
+     * @param resolvedJavaMethod
+     */
+    public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) {
+        return CompilationIdentifier.INVALID_COMPILATION_ID;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/CSVUtilTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/CSVUtilTest.java
new file mode 100644
index 0000000..35fdb40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/CSVUtilTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.debug.CSVUtil;
+
+@RunWith(Enclosed.class)
+public class CSVUtilTest {
+
+    @RunWith(Parameterized.class)
+    public static class FormatStringBuilder {
+        /** Some interesting values. */
+        private static final Object[][] values = {
+                        {"", ""},
+                        {"%s", "%s"},
+                        {"%s,%s", "%s;%s"},
+        };
+
+        @Parameters(name = " [{0}] to \"{1}\" ")
+        public static Collection<Object[]> data() {
+            return Arrays.asList(values);
+        }
+
+        @Parameter(value = 0) public String input;
+        @Parameter(value = 1) public String expected;
+
+        @Test
+        public void testBuildFormatString() {
+            assertEquals(expected, CSVUtil.buildFormatString(input.split(",")));
+        }
+    }
+
+    @RunWith(Parameterized.class)
+    public static class Escape {
+
+        /** Some interesting values. */
+        private static final Object[][] values = {
+                        {"XXX\"YYY", "\"XXX\\\"YYY\""},
+                        {"X\\XX\"YYY", "\"X\\\\XX\\\"YYY\""},
+        };
+
+        @Parameters(name = "''{0}'' to ''{1}''")
+        public static Collection<Object[]> data() {
+            return Arrays.asList(values);
+        }
+
+        @Parameter(value = 0) public String input;
+        @Parameter(value = 1) public String expected;
+
+        @Test
+        public void testEscape() {
+            assertEquals(expected, CSVUtil.Escape.escapeRaw(input));
+        }
+
+    }
+
+    @RunWith(Parameterized.class)
+    public static class Formatter {
+        /** Some interesting values. */
+        private static final Object[][] values = {
+                        {"%s;%s", "XXX,YYY", "XXX;YYY"},
+                        {"%s;%s", "XXX,Y\"YY", "XXX;Y\"YY"},
+                        {"%s;%s", "XXX,Y;YY", "XXX;\"Y;YY\""},
+                        {"%s;%s", "XXX,Y\"Y;Y", "XXX;\"Y\\\"Y;Y\""},
+        };
+
+        @Parameters(name = "format=''{0}'' args=''{1}'' output=''{2}''")
+        public static Collection<Object[]> data() {
+            return Arrays.asList(values);
+        }
+
+        @Parameter(value = 0) public String format;
+        @Parameter(value = 1) public String args;
+        @Parameter(value = 2) public String expected;
+
+        @Test
+        public void testFormatter() {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            // call the method under test
+            CSVUtil.Escape.println(new PrintStream(outputStream), format, toObjectArray(args));
+            // get the actual string
+            String printedStream = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
+            // remove newline
+            assertEquals(expected, printedStream.substring(0, printedStream.length() - 1));
+        }
+
+        private static Object[] toObjectArray(String args) {
+            String[] split = args.split(",");
+            Object[] obj = new Object[split.length];
+            for (int i = 0; i < split.length; i++) {
+                obj[i] = split[i];
+            }
+            return obj;
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugHistogramTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugHistogramTest.java
new file mode 100644
index 0000000..a6fe2fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugHistogramTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugHistogram;
+import org.graalvm.compiler.debug.internal.DebugHistogramAsciiPrinter;
+import org.graalvm.compiler.debug.internal.DebugHistogramRPrinter;
+
+public class DebugHistogramTest {
+
+    @Test
+    public void testEmptyHistogram() {
+        DebugHistogram histogram = Debug.createHistogram("TestHistogram");
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
+        String line = outputStream.toString().split("\r?\n")[0];
+        Assert.assertEquals("TestHistogram is empty.", line);
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        Assert.assertEquals("", outputStream.toString());
+    }
+
+    @Test
+    public void testSingleEntryHistogram() {
+        DebugHistogram histogram = Debug.createHistogram("TestHistogram");
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        histogram.add(new Integer(1));
+        histogram.add(new Integer(1));
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
+        String[] lines = outputStream.toString().split("\r?\n");
+        // @formatter:off
+        String[] expected = {
+            "TestHistogram has 1 unique elements and 2 total elements:",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
+            "| 1                                                  | 2          | ==================================================================================================== |",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        lines = outputStream.toString().split("\r?\n");
+        // @formatter:off
+        expected = new String[] {
+            "TestHistogram <- c(2);",
+            "names(TestHistogram) <- c(\"1\");"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+    }
+
+    @Test
+    public void testMultipleEntryHistogram() {
+        DebugHistogram histogram = Debug.createHistogram("TestHistogram");
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        histogram.add(new Integer(1));
+        histogram.add(new Integer(2));
+        histogram.add(new Integer(2));
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream)).print(histogram);
+        String[] lines = outputStream.toString().split("\r?\n");
+        // @formatter:off
+        String[] expected = new String[] {
+            "TestHistogram has 2 unique elements and 3 total elements:",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------",
+            "| 2                                                  | 2          | ==================================================================================================== |",
+            "| 1                                                  | 1          | ==================================================                                                   |",
+            "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+
+        outputStream.reset();
+        new DebugHistogramRPrinter(new PrintStream(outputStream)).print(histogram);
+        lines = outputStream.toString().split("\r?\n");
+        // @formatter:off
+        expected = new String[] {
+            "TestHistogram <- c(2, 1);",
+            "names(TestHistogram) <- c(\"2\", \"1\");"
+        };
+        // @formatter:on
+        Assert.assertArrayEquals(expected, lines);
+    }
+
+    @Test
+    public void testTooLongValueString() {
+        DebugHistogram histogram = Debug.createHistogram("TestHistogram");
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        histogram.add("MyCustomValue");
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10, 1).print(histogram);
+        String[] lines = outputStream.toString().split("\r?\n");
+        Assert.assertEquals(4, lines.length);
+        Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]);
+        Assert.assertEquals("----------------------------------------", lines[1]);
+        Assert.assertEquals("| MyCusto... | 1          | ========== |", lines[2]);
+        Assert.assertEquals("----------------------------------------", lines[3]);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugTimerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugTimerTest.java
new file mode 100644
index 0000000..42b4eee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugTimerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ThreadMXBean;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.Management;
+
+@SuppressWarnings("try")
+public class DebugTimerTest {
+
+    private static final ThreadMXBean threadMXBean = Management.getThreadMXBean();
+
+    @Before
+    public void checkCapabilities() {
+        Assume.assumeTrue("skipping management interface test", threadMXBean.isCurrentThreadCpuTimeSupported());
+    }
+
+    /**
+     * Actively spins the current thread for at least a given number of milliseconds in such a way
+     * that timers for the current thread keep ticking over.
+     *
+     * @return the number of milliseconds actually spent spinning which is guaranteed to be >=
+     *         {@code ms}
+     */
+    private static long spin(long ms) {
+        long start = threadMXBean.getCurrentThreadCpuTime();
+        do {
+            long durationMS = (threadMXBean.getCurrentThreadCpuTime() - start) / 1000;
+            if (durationMS >= ms) {
+                return durationMS;
+            }
+        } while (true);
+    }
+
+    @Test
+    public void test1() {
+        DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out);
+        try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) {
+
+            DebugTimer timerA = Debug.timer("TimerA");
+            DebugTimer timerB = Debug.timer("TimerB");
+
+            long spinA;
+            long spinB;
+
+            try (DebugCloseable a1 = timerA.start()) {
+                spinA = spin(50);
+                try (DebugCloseable b1 = timerB.start()) {
+                    spinB = spin(50);
+                }
+            }
+
+            Assert.assertTrue(timerB.getCurrentValue() < timerA.getCurrentValue());
+            if (timerA.getFlat() != null && timerB.getFlat() != null) {
+                assertTrue(spinB >= spinA || timerB.getFlat().getCurrentValue() < timerA.getFlat().getCurrentValue());
+                assertEquals(timerA.getFlat().getCurrentValue(), timerA.getCurrentValue() - timerB.getFlat().getCurrentValue(), 10D);
+            }
+        }
+    }
+
+    @Test
+    public void test2() {
+        DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out);
+        try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) {
+            DebugTimer timerC = Debug.timer("TimerC");
+            try (DebugCloseable c1 = timerC.start()) {
+                spin(50);
+                try (DebugCloseable c2 = timerC.start()) {
+                    spin(50);
+                    try (DebugCloseable c3 = timerC.start()) {
+                        spin(50);
+                        try (DebugCloseable c4 = timerC.start()) {
+                            spin(50);
+                            try (DebugCloseable c5 = timerC.start()) {
+                                spin(50);
+                            }
+                        }
+                    }
+                }
+            }
+            if (timerC.getFlat() != null) {
+                assertEquals(timerC.getFlat().getCurrentValue(), timerC.getCurrentValue());
+            }
+        }
+    }
+
+    @Test
+    public void test3() {
+        DebugConfig debugConfig = Debug.fixedConfig(0, 0, false, false, true, false, false, null, null, System.out);
+        try (DebugConfigScope dcs = new DebugConfigScope(debugConfig); Debug.Scope s = Debug.scope("DebugTimerTest")) {
+
+            DebugTimer timerD = Debug.timer("TimerD");
+            DebugTimer timerE = Debug.timer("TimerE");
+
+            long spinD1;
+            long spinE;
+
+            try (DebugCloseable d1 = timerD.start()) {
+                spinD1 = spin(50);
+                try (DebugCloseable e1 = timerE.start()) {
+                    spinE = spin(50);
+                    try (DebugCloseable d2 = timerD.start()) {
+                        spin(50);
+                        try (DebugCloseable d3 = timerD.start()) {
+                            spin(50);
+                        }
+                    }
+                }
+            }
+
+            Assert.assertTrue(timerE.getCurrentValue() < timerD.getCurrentValue());
+            if (timerD.getFlat() != null && timerE.getFlat() != null) {
+                assertTrue(spinE >= spinD1 || timerE.getFlat().getCurrentValue() < timerD.getFlat().getCurrentValue());
+                assertEquals(timerD.getFlat().getCurrentValue(), timerD.getCurrentValue() - timerE.getFlat().getCurrentValue(), 10D);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CSVUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CSVUtil.java
new file mode 100644
index 0000000..5c43ccc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CSVUtil.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+
+/**
+ * Utilities and global definitions for creating CSV output.
+ */
+public final class CSVUtil {
+    public static final char SEPARATOR = ';';
+    public static final String SEPARATOR_STR = String.valueOf(SEPARATOR);
+    public static final char QUOTE = '"';
+    public static final String QUOTE_STR = String.valueOf(QUOTE);
+    public static final char ESCAPE = '\\';
+    public static final String ESCAPE_STR = String.valueOf(ESCAPE);
+    public static final String ESCAPED_QUOTE_STR = ESCAPE_STR + QUOTE_STR;
+    public static final String ESCAPED_ESCAPE_STR = ESCAPE_STR + ESCAPE_STR;
+
+    public static String buildFormatString(String format, int num) {
+        return buildFormatString(format, SEPARATOR, num);
+    }
+
+    public static String buildFormatString(String... format) {
+        return String.join(SEPARATOR_STR, format);
+    }
+
+    public static String buildFormatString(String format, char separator, int num) {
+        StringBuilder sb = new StringBuilder(num * (format.length() + 1) - 1);
+        sb.append(format);
+        for (int i = 1; i < num; i++) {
+            sb.append(separator).append(format);
+        }
+        return sb.toString();
+    }
+
+    public static final class Escape {
+
+        public static PrintStream println(PrintStream out, String format, Object... args) {
+            return println(out, SEPARATOR, QUOTE, ESCAPE, format, args);
+        }
+
+        public static LogStream println(LogStream out, String format, Object... args) {
+            return println(out, SEPARATOR, QUOTE, ESCAPE, format, args);
+        }
+
+        public static String escape(String str) {
+            return escape(str, SEPARATOR, QUOTE, ESCAPE);
+        }
+
+        public static String escapeRaw(String str) {
+            return escapeRaw(str, QUOTE, ESCAPE);
+        }
+
+        public static PrintStream println(PrintStream out, char separator, char quote, char escape, String format, Object... args) {
+            out.printf(format, escapeArgs(separator, quote, escape, args));
+            out.println();
+            return out;
+        }
+
+        public static LogStream println(LogStream out, char separator, char quote, char escape, String format, Object... args) {
+            out.printf(format, escapeArgs(separator, quote, escape, args));
+            out.println();
+            return out;
+        }
+
+        private static Object[] escapeArgs(char separator, char quote, char escape, Object... args) {
+            String separatorStr = String.valueOf(separator);
+            for (int i = 0; i < args.length; i++) {
+                Object obj = args[i];
+                if (obj instanceof String) {
+                    String str = (String) obj;
+                    if (str.contains(separatorStr)) {
+                        args[i] = escapeRaw(str, quote, escape);
+                    }
+                }
+            }
+            return args;
+        }
+
+        public static String escape(String str, char separator, char quote, char escape) {
+            String separatorStr = String.valueOf(separator);
+            if (str.contains(separatorStr)) {
+                return escapeRaw(str, quote, escape);
+            }
+            return str;
+        }
+
+        public static String escapeRaw(String str, char quote, char escape) {
+            String quoteStr = String.valueOf(quote);
+            String escapeStr = String.valueOf(escape);
+            String escapedEscapeStr = escapeStr + escape;
+            String escapedQuoteStr = escapeStr + quote;
+            String str1 = str.replace(escapeStr, escapedEscapeStr);
+            String str2 = str1.replace(quoteStr, escapedQuoteStr);
+            String str3 = quoteStr + str2 + quote;
+            return str3;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
new file mode 100644
index 0000000..f5a3758
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
@@ -0,0 +1,1713 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.LOG_METHOD;
+import static java.util.FormattableFlags.LEFT_JUSTIFY;
+import static java.util.FormattableFlags.UPPERCASE;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.graalvm.compiler.debug.DelegatingDebugConfig.Level;
+import org.graalvm.compiler.debug.internal.CounterImpl;
+import org.graalvm.compiler.debug.internal.DebugHistogramImpl;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.MemUseTrackerImpl;
+import org.graalvm.compiler.debug.internal.TimerImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Scope based debugging facility.
+ *
+ * This facility is {@linkplain #isEnabled() enabled} if any of the following hold when the
+ * {@link Debug} class is initialized:
+ * <ul>
+ * <li>assertions are enabled for the {@link Debug} class</li>
+ * <li>{@link Debug#params}{@code .enable} is {@code true}</li>
+ * </ul>
+ */
+public class Debug {
+
+    private static final Params params = new Params();
+
+    static {
+        // Load the service providers that may want to modify any of the
+        // parameters encapsulated by the Initialization class below.
+        for (DebugInitializationParticipant p : GraalServices.load(DebugInitializationParticipant.class)) {
+            p.apply(params);
+        }
+    }
+
+    /**
+     * The parameters for configuring the initialization of {@link Debug} class.
+     */
+    public static class Params {
+        public boolean enable;
+        public boolean enableMethodFilter;
+        public boolean enableUnscopedTimers;
+        public boolean enableUnscopedCounters;
+        public boolean enableUnscopedMethodMetrics;
+        public boolean enableUnscopedMemUseTrackers;
+        public boolean interceptCount;
+        public boolean interceptTime;
+        public boolean interceptMem;
+    }
+
+    @SuppressWarnings("all")
+    private static boolean initialize() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled || params.enable || GraalDebugConfig.Options.ForceDebugEnable.getValue();
+    }
+
+    private static final boolean ENABLED = initialize();
+
+    public static boolean isEnabled() {
+        return ENABLED;
+    }
+
+    public static boolean isDumpEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isDumpEnabledForMethod();
+    }
+
+    public static final int BASIC_LOG_LEVEL = 1;
+    public static final int INFO_LOG_LEVEL = 2;
+    public static final int VERBOSE_LOG_LEVEL = 3;
+    public static final int DETAILED_LOG_LEVEL = 4;
+
+    public static boolean isDumpEnabled(int dumpLevel) {
+        return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
+    }
+
+    /**
+     * Determines if verification is enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     *
+     * @see Debug#verify(Object, String)
+     */
+    public static boolean isVerifyEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isVerifyEnabledForMethod();
+    }
+
+    /**
+     * Determines if verification is enabled in the {@linkplain Debug#currentScope() current debug
+     * scope}.
+     *
+     * @see Debug#verify(Object, String)
+     */
+    public static boolean isVerifyEnabled() {
+        return ENABLED && DebugScope.getInstance().isVerifyEnabled();
+    }
+
+    public static boolean isCountEnabled() {
+        return ENABLED && DebugScope.getInstance().isCountEnabled();
+    }
+
+    public static boolean isTimeEnabled() {
+        return ENABLED && DebugScope.getInstance().isTimeEnabled();
+    }
+
+    public static boolean isMemUseTrackingEnabled() {
+        return ENABLED && DebugScope.getInstance().isMemUseTrackingEnabled();
+    }
+
+    public static boolean isLogEnabledForMethod() {
+        if (!ENABLED) {
+            return false;
+        }
+        DebugConfig config = DebugScope.getConfig();
+        if (config == null) {
+            return false;
+        }
+        return config.isLogEnabledForMethod();
+    }
+
+    public static boolean isLogEnabled() {
+        return isLogEnabled(BASIC_LOG_LEVEL);
+    }
+
+    public static boolean isLogEnabled(int logLevel) {
+        return ENABLED && DebugScope.getInstance().isLogEnabled(logLevel);
+    }
+
+    public static boolean isMethodMeterEnabled() {
+        return ENABLED && DebugScope.getInstance().isMethodMeterEnabled();
+    }
+
+    @SuppressWarnings("unused")
+    public static Runnable decorateDebugRoot(Runnable runnable, String name, DebugConfig config) {
+        return runnable;
+    }
+
+    @SuppressWarnings("unused")
+    public static <T> Callable<T> decorateDebugRoot(Callable<T> callable, String name, DebugConfig config) {
+        return callable;
+    }
+
+    @SuppressWarnings("unused")
+    public static Runnable decorateScope(Runnable runnable, String name, Object... context) {
+        return runnable;
+    }
+
+    @SuppressWarnings("unused")
+    public static <T> Callable<T> decorateScope(Callable<T> callable, String name, Object... context) {
+        return callable;
+    }
+
+    /**
+     * Gets a string composed of the names in the current nesting of debug
+     * {@linkplain #scope(Object) scopes} separated by {@code '.'}.
+     */
+    public static String currentScope() {
+        if (ENABLED) {
+            return DebugScope.getInstance().getQualifiedName();
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Represents a debug scope entered by {@link Debug#scope(Object)} or
+     * {@link Debug#sandbox(CharSequence, DebugConfig, Object...)}. Leaving the scope is achieved
+     * via {@link #close()}.
+     */
+    public interface Scope extends AutoCloseable {
+        @Override
+        void close();
+    }
+
+    /**
+     * Creates and enters a new debug scope which will be a child of the current debug scope.
+     * <p>
+     * It is recommended to use the try-with-resource statement for managing entering and leaving
+     * debug scopes. For example:
+     *
+     * <pre>
+     * try (Scope s = Debug.scope(&quot;InliningGraph&quot;, inlineeGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * </pre>
+     *
+     * The {@code name} argument is subject to the following type based conversion before having
+     * {@link Object#toString()} called on it:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @param name the name of the new scope
+     * @param contextObjects an array of object to be appended to the {@linkplain #context()
+     *            current} debug context
+     * @throws Throwable used to enforce a catch block.
+     * @return the scope entered by this method which will be exited when its {@link Scope#close()}
+     *         method is called
+     */
+    public static Scope scope(Object name, Object[] contextObjects) throws Throwable {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, contextObjects);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Similar to {@link #scope(Object, Object[])} but without context objects. Therefore the catch
+     * block can be omitted.
+     *
+     * @see #scope(Object, Object[])
+     */
+    public static Scope scope(Object name) {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null);
+        } else {
+            return null;
+        }
+    }
+
+    public static Scope methodMetricsScope(Object name, DebugScope.ExtraInfo metaInfo, boolean newId, Object... context) {
+        if (ENABLED) {
+            return DebugScope.getInstance().enhanceWithExtraInfo(convertFormatArg(name).toString(), metaInfo, newId, context);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object, Object[])
+     * @param context an object to be appended to the {@linkplain #context() current} debug context
+     */
+    public static Scope scope(Object name, Object context) throws Throwable {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object, Object[])
+     * @param context1 first object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context2 second object to be appended to the {@linkplain #context() current} debug
+     *            context
+     */
+    public static Scope scope(Object name, Object context1, Object context2) throws Throwable {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object, Object[])
+     * @param context1 first object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context2 second object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context3 third object to be appended to the {@linkplain #context() current} debug
+     *            context
+     */
+    public static Scope scope(Object name, Object context1, Object context2, Object context3) throws Throwable {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates and enters a new debug scope which will be disjoint from the current debug scope.
+     * <p>
+     * It is recommended to use the try-with-resource statement for managing entering and leaving
+     * debug scopes. For example:
+     *
+     * <pre>
+     * try (Scope s = Debug.sandbox(&quot;CompilingStub&quot;, null, stubGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * </pre>
+     *
+     * @param name the name of the new scope
+     * @param config the debug configuration to use for the new scope
+     * @param context objects to be appended to the {@linkplain #context() current} debug context
+     * @return the scope entered by this method which will be exited when its {@link Scope#close()}
+     *         method is called
+     */
+    public static Scope sandbox(CharSequence name, DebugConfig config, Object... context) throws Throwable {
+        if (ENABLED) {
+            DebugConfig sandboxConfig = config == null ? silentConfig() : config;
+            return DebugScope.getInstance().scope(name, sandboxConfig, context);
+        } else {
+            return null;
+        }
+    }
+
+    public static Scope forceLog() throws Throwable {
+        ArrayList<Object> context = new ArrayList<>();
+        for (Object obj : context()) {
+            context.add(obj);
+        }
+        return Debug.sandbox("forceLog", new DelegatingDebugConfig().override(Level.LOG, Integer.MAX_VALUE).enable(LOG_METHOD), context.toArray());
+    }
+
+    /**
+     * Opens a scope in which exception {@linkplain DebugConfig#interceptException(Throwable)
+     * interception} is disabled. It is recommended to use the try-with-resource statement for
+     * managing entering and leaving such scopes:
+     *
+     * <pre>
+     * try (DebugConfigScope s = Debug.disableIntercept()) {
+     *     ...
+     * }
+     * </pre>
+     *
+     * This is particularly useful to suppress extraneous output in JUnit tests that are expected to
+     * throw an exception.
+     */
+    public static DebugConfigScope disableIntercept() {
+        return Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT));
+    }
+
+    /**
+     * Handles an exception in the context of the debug scope just exited. The just exited scope
+     * must have the current scope as its parent which will be the case if the try-with-resource
+     * pattern recommended by {@link #scope(Object)} and
+     * {@link #sandbox(CharSequence, DebugConfig, Object...)} is used
+     *
+     * @see #scope(Object, Object[])
+     * @see #sandbox(CharSequence, DebugConfig, Object...)
+     */
+    public static RuntimeException handle(Throwable exception) {
+        if (ENABLED) {
+            return DebugScope.getInstance().handle(exception);
+        } else {
+            if (exception instanceof Error) {
+                throw (Error) exception;
+            }
+            if (exception instanceof RuntimeException) {
+                throw (RuntimeException) exception;
+            }
+            throw new RuntimeException(exception);
+        }
+    }
+
+    public static void log(String msg) {
+        log(BASIC_LOG_LEVEL, msg);
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param msg the message to log
+     */
+    public static void log(int logLevel, String msg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, msg);
+        }
+    }
+
+    public static void log(String format, Object arg) {
+        log(BASIC_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     */
+    public static void log(int logLevel, String format, Object arg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg);
+        }
+    }
+
+    public static void log(String format, int arg) {
+        log(BASIC_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     */
+    public static void log(int logLevel, String format, int arg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, int arg1, Object arg2) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, Object arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, Object arg1, int arg2) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, int arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, int arg1, int arg2) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, int arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3);
+        }
+    }
+
+    public static void log(String format, int arg1, int arg2, int arg3) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, int arg2, int arg3) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        }
+    }
+
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+    }
+
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
+        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+    }
+
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+        }
+    }
+
+    public static void logv(String format, Object... args) {
+        logv(BASIC_LOG_LEVEL, format, args);
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream. This method must only be called
+     * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call
+     * site. If possible, call one of the other {@code log()} methods in this class that take a
+     * fixed number of parameters.
+     *
+     * @param format a format string
+     * @param args the arguments referenced by the format specifiers in {@code format}
+     */
+    public static void logv(int logLevel, String format, Object... args) {
+        if (!ENABLED) {
+            throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()");
+        }
+        DebugScope.getInstance().log(logLevel, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #log(String, Object)} is called with one
+     * argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void log(String format, Object[] args) {
+        assert false : "shouldn't use this";
+        log(BASIC_LOG_LEVEL, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #log(int, String, Object)} is called with one
+     * argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void log(int logLevel, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logv(logLevel, format, args);
+    }
+
+    public static void dump(int dumpLevel, Object object, String msg) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, msg);
+        }
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg);
+        }
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2);
+        }
+    }
+
+    public static void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, arg1, arg2, arg3);
+        }
+    }
+
+    /**
+     * This override exists to catch cases when {@link #dump(int, Object, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void dump(int dumpLevel, Object object, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
+            DebugScope.getInstance().dump(dumpLevel, object, format, args);
+        }
+    }
+
+    /**
+     * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig()
+     * config} to perform verification on a given object.
+     *
+     * @param object object to verify
+     * @param message description of verification context
+     *
+     * @see DebugVerifyHandler#verify(Object, String)
+     */
+    public static void verify(Object object, String message) {
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, message);
+        }
+    }
+
+    /**
+     * Calls all {@link DebugVerifyHandler}s in the current {@linkplain DebugScope#getConfig()
+     * config} to perform verification on a given object.
+     *
+     * @param object object to verify
+     * @param format a format string for the description of the verification context
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     *
+     * @see DebugVerifyHandler#verify(Object, String)
+     */
+    public static void verify(Object object, String format, Object arg) {
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, format, arg);
+        }
+    }
+
+    /**
+     * This override exists to catch cases when {@link #verify(Object, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void verify(Object object, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
+            DebugScope.getInstance().verify(object, format, args);
+        }
+    }
+
+    /**
+     * Opens a new indentation level (by adding some spaces) based on the current indentation level.
+     * This should be used in a {@linkplain Indent try-with-resources} pattern.
+     *
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     * @see #logAndIndent(int, String)
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent indent() {
+        if (ENABLED) {
+            DebugScope scope = DebugScope.getInstance();
+            return scope.pushIndentLogger();
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String msg) {
+        return logAndIndent(BASIC_LOG_LEVEL, msg);
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String)} and {@link #indent()}.
+     *
+     * @param msg the message to log
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(int logLevel, String msg) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, msg);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg1, Object arg2) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, Object arg2) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, int arg2) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg1, int arg2) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2, int arg3) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2, int arg3) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        if (ENABLED && Debug.isLogEnabled(logLevel)) {
+            return logvAndIndentInternal(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6);
+        }
+        return null;
+    }
+
+    /**
+     * A convenience function which combines {@link #logv(int, String, Object...)} and
+     * {@link #indent()}.
+     *
+     * @param format a format string
+     * @param args the arguments referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logvAndIndent(int logLevel, String format, Object... args) {
+        if (ENABLED) {
+            if (Debug.isLogEnabled(logLevel)) {
+                return logvAndIndentInternal(logLevel, format, args);
+            }
+            return null;
+        }
+        throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()");
+    }
+
+    private static Indent logvAndIndentInternal(int logLevel, String format, Object... args) {
+        assert ENABLED && Debug.isLogEnabled(logLevel) : "must have checked Debug.isLogEnabled()";
+        DebugScope scope = DebugScope.getInstance();
+        scope.log(logLevel, format, args);
+        return scope.pushIndentLogger();
+    }
+
+    /**
+     * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with
+     * one argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void logAndIndent(String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logAndIndent(BASIC_LOG_LEVEL, format, args);
+    }
+
+    /**
+     * This override exists to catch cases when {@link #logAndIndent(int, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void logAndIndent(int logLevel, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logvAndIndent(logLevel, format, args);
+    }
+
+    public static Iterable<Object> context() {
+        if (ENABLED) {
+            return DebugScope.getInstance().getCurrentContext();
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> contextSnapshot(Class<T> clazz) {
+        if (ENABLED) {
+            List<T> result = new ArrayList<>();
+            for (Object o : context()) {
+                if (clazz.isInstance(o)) {
+                    result.add((T) o);
+                }
+            }
+            return result;
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * Searches the current debug scope, bottom up, for a context object that is an instance of a
+     * given type. The first such object found is returned.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T contextLookup(Class<T> clazz) {
+        if (ENABLED) {
+            for (Object o : context()) {
+                if (clazz.isInstance(o)) {
+                    return ((T) o);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates a {@linkplain DebugMemUseTracker memory use tracker} that is enabled iff debugging is
+     * {@linkplain #isEnabled() enabled}.
+     * <p>
+     * A disabled tracker has virtually no overhead.
+     */
+    public static DebugMemUseTracker memUseTracker(CharSequence name) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker("%s", name, null);
+    }
+
+    /**
+     * Creates a debug memory use tracker. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.memUseTracker(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if mem tracking is enabled.
+     *
+     * @see #counter(String, Object, Object)
+     */
+    public static DebugMemUseTracker memUseTracker(String format, Object arg) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker(format, arg, null);
+    }
+
+    /**
+     * Creates a debug memory use tracker. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.memUseTracker(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if memory use tracking is enabled. In
+     * addition, each argument is subject to the following type based conversion before being passed
+     * as an argument to {@link String#format(String, Object...)}:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @see #memUseTracker(CharSequence)
+     */
+    public static DebugMemUseTracker memUseTracker(String format, Object arg1, Object arg2) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker(format, arg1, arg2);
+    }
+
+    private static DebugMemUseTracker createMemUseTracker(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        return DebugValueFactory.createMemUseTracker(name, !isUnconditionalMemUseTrackingEnabled);
+    }
+
+    /**
+     * Creates a {@linkplain DebugCounter counter} that is enabled iff debugging is
+     * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding
+     * {@value #ENABLE_COUNTER_PROPERTY_NAME_PREFIX} to {@code name} is
+     * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the
+     * returned counter is {@linkplain DebugCounter#isConditional() unconditional} otherwise it is
+     * conditional.
+     * <p>
+     * A disabled counter has virtually no overhead.
+     */
+    public static DebugCounter counter(CharSequence name) {
+        if (!areUnconditionalCountersEnabled() && !ENABLED) {
+            return VOID_COUNTER;
+        }
+        return createCounter("%s", name, null);
+    }
+
+    /**
+     * Creates a {@link DebugMethodMetrics metric} that is enabled iff debugging is
+     * {@link #isEnabled() enabled}.
+     */
+    public static DebugMethodMetrics methodMetrics(ResolvedJavaMethod method) {
+        if (isMethodMeterEnabled() && method != null) {
+            return MethodMetricsImpl.getMethodMetrics(method);
+        }
+        return VOID_MM;
+    }
+
+    public static String applyFormattingFlagsAndWidth(String s, int flags, int width) {
+        if (flags == 0 && width < 0) {
+            return s;
+        }
+        StringBuilder sb = new StringBuilder(s);
+
+        // apply width and justification
+        int len = sb.length();
+        if (len < width) {
+            for (int i = 0; i < width - len; i++) {
+                if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) {
+                    sb.append(' ');
+                } else {
+                    sb.insert(0, ' ');
+                }
+            }
+        }
+
+        String res = sb.toString();
+        if ((flags & UPPERCASE) == UPPERCASE) {
+            res = res.toUpperCase();
+        }
+        return res;
+    }
+
+    /**
+     * Creates a debug counter. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.counter(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if count is enabled.
+     *
+     * @see #counter(String, Object, Object)
+     */
+    public static DebugCounter counter(String format, Object arg) {
+        if (!areUnconditionalCountersEnabled() && !ENABLED) {
+            return VOID_COUNTER;
+        }
+        return createCounter(format, arg, null);
+    }
+
+    /**
+     * Creates a debug counter. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.counter(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if count is enabled. In addition, each
+     * argument is subject to the following type based conversion before being passed as an argument
+     * to {@link String#format(String, Object...)}:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @see #counter(CharSequence)
+     */
+    public static DebugCounter counter(String format, Object arg1, Object arg2) {
+        if (!areUnconditionalCountersEnabled() && !ENABLED) {
+            return VOID_COUNTER;
+        }
+        return createCounter(format, arg1, arg2);
+    }
+
+    private static DebugCounter createCounter(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        boolean conditional = enabledCounters == null || !findMatch(enabledCounters, enabledCountersSubstrings, name);
+        if (!ENABLED && conditional) {
+            return VOID_COUNTER;
+        }
+        return DebugValueFactory.createCounter(name, conditional);
+    }
+
+    /**
+     * Changes the debug configuration for the current thread.
+     *
+     * @param config new configuration to use for the current thread
+     * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the
+     *         debug configuration for the current thread to what it was before this method was
+     *         called
+     */
+    public static DebugConfigScope setConfig(DebugConfig config) {
+        if (ENABLED) {
+            return new DebugConfigScope(config);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates an object for counting value frequencies.
+     */
+    public static DebugHistogram createHistogram(String name) {
+        return new DebugHistogramImpl(name);
+    }
+
+    public static DebugConfig silentConfig() {
+        return fixedConfig(0, 0, false, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), Collections.<DebugVerifyHandler> emptyList(), null);
+    }
+
+    public static DebugConfig fixedConfig(final int logLevel, final int dumpLevel, final boolean isCountEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled,
+                    final boolean isVerifyEnabled, final boolean isMMEnabled, final Collection<DebugDumpHandler> dumpHandlers, final Collection<DebugVerifyHandler> verifyHandlers,
+                    final PrintStream output) {
+        return new DebugConfig() {
+
+            @Override
+            public int getLogLevel() {
+                return logLevel;
+            }
+
+            @Override
+            public boolean isLogEnabledForMethod() {
+                return logLevel > 0;
+            }
+
+            @Override
+            public boolean isCountEnabled() {
+                return isCountEnabled;
+            }
+
+            @Override
+            public boolean isMemUseTrackingEnabled() {
+                return isMemUseTrackingEnabled;
+            }
+
+            @Override
+            public int getDumpLevel() {
+                return dumpLevel;
+            }
+
+            @Override
+            public boolean isDumpEnabledForMethod() {
+                return dumpLevel > 0;
+            }
+
+            @Override
+            public boolean isVerifyEnabled() {
+                return isVerifyEnabled;
+            }
+
+            @Override
+            public boolean isVerifyEnabledForMethod() {
+                return isVerifyEnabled;
+            }
+
+            @Override
+            public boolean isMethodMeterEnabled() {
+                return isMMEnabled;
+            }
+
+            @Override
+            public boolean isTimeEnabled() {
+                return isTimerEnabled;
+            }
+
+            @Override
+            public RuntimeException interceptException(Throwable e) {
+                return null;
+            }
+
+            @Override
+            public Collection<DebugDumpHandler> dumpHandlers() {
+                return dumpHandlers;
+            }
+
+            @Override
+            public Collection<DebugVerifyHandler> verifyHandlers() {
+                return verifyHandlers;
+            }
+
+            @Override
+            public PrintStream output() {
+                return output;
+            }
+
+            @Override
+            public void addToContext(Object o) {
+            }
+
+            @Override
+            public void removeFromContext(Object o) {
+            }
+        };
+    }
+
+    private static final DebugCounter VOID_COUNTER = new DebugCounter() {
+
+        @Override
+        public void increment() {
+        }
+
+        @Override
+        public void add(long value) {
+        }
+
+        @Override
+        public void setConditional(boolean flag) {
+            throw new InternalError("Cannot make void counter conditional");
+        }
+
+        @Override
+        public boolean isConditional() {
+            return false;
+        }
+
+        @Override
+        public long getCurrentValue() {
+            return 0L;
+        }
+    };
+
+    private static final DebugMethodMetrics VOID_MM = new DebugMethodMetrics() {
+
+        @Override
+        public void addToMetric(long value, String metricName) {
+        }
+
+        @Override
+        public void addToMetric(long value, String format, Object arg1) {
+        }
+
+        @Override
+        public void addToMetric(long value, String format, Object arg1, Object arg2) {
+        }
+
+        @Override
+        public void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3) {
+        }
+
+        @Override
+        public void incrementMetric(String metricName) {
+        }
+
+        @Override
+        public void incrementMetric(String format, Object arg1) {
+        }
+
+        @Override
+        public void incrementMetric(String format, Object arg1, Object arg2) {
+        }
+
+        @Override
+        public void incrementMetric(String format, Object arg1, Object arg2, Object arg3) {
+        }
+
+        @Override
+        public long getCurrentMetricValue(String metricName) {
+            return 0;
+        }
+
+        @Override
+        public long getCurrentMetricValue(String format, Object arg1) {
+            return 0;
+        }
+
+        @Override
+        public long getCurrentMetricValue(String format, Object arg1, Object arg2) {
+            return 0;
+        }
+
+        @Override
+        public long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3) {
+            return 0;
+        }
+
+        @Override
+        public ResolvedJavaMethod getMethod() {
+            return null;
+        }
+
+    };
+
+    private static final DebugMemUseTracker VOID_MEM_USE_TRACKER = new DebugMemUseTracker() {
+
+        @Override
+        public DebugCloseable start() {
+            return DebugCloseable.VOID_CLOSEABLE;
+        }
+
+        @Override
+        public long getCurrentValue() {
+            return 0;
+        }
+    };
+
+    /**
+     * @see #timer(CharSequence)
+     */
+    public static final String ENABLE_TIMER_PROPERTY_NAME_PREFIX = "graaldebug.timer.";
+
+    /**
+     * @see #counter(CharSequence)
+     */
+    public static final String ENABLE_COUNTER_PROPERTY_NAME_PREFIX = "graaldebug.counter.";
+
+    /**
+     * Set of unconditionally enabled counters. Possible values and their meanings:
+     * <ul>
+     * <li>{@code null}: no unconditionally enabled counters</li>
+     * <li>{@code isEmpty()}: all counters are unconditionally enabled</li>
+     * <li>{@code !isEmpty()}: use {@link #findMatch(Set, Set, String)} on this set and
+     * {@link #enabledCountersSubstrings} to determine which counters are unconditionally enabled
+     * </li>
+     * </ul>
+     */
+    private static final Set<String> enabledCounters;
+
+    /**
+     * Set of unconditionally enabled timers. Same interpretation of values as for
+     * {@link #enabledCounters}.
+     */
+    private static final Set<String> enabledTimers;
+
+    private static final Set<String> enabledCountersSubstrings = new HashSet<>();
+    private static final Set<String> enabledTimersSubstrings = new HashSet<>();
+
+    /**
+     * Specifies if all mem use trackers are unconditionally enabled.
+     */
+    private static final boolean isUnconditionalMemUseTrackingEnabled;
+
+    static {
+        Set<String> counters = new HashSet<>();
+        Set<String> timers = new HashSet<>();
+        parseCounterAndTimerSystemProperties(counters, timers, enabledCountersSubstrings, enabledTimersSubstrings);
+        counters = counters.isEmpty() && enabledCountersSubstrings.isEmpty() ? null : counters;
+        timers = timers.isEmpty() && enabledTimersSubstrings.isEmpty() ? null : timers;
+        if (counters == null && params.enableUnscopedCounters && !params.enableMethodFilter) {
+            counters = Collections.emptySet();
+        }
+        if (timers == null && params.enableUnscopedTimers && !params.enableMethodFilter) {
+            timers = Collections.emptySet();
+        }
+        enabledCounters = counters;
+        enabledTimers = timers;
+        isUnconditionalMemUseTrackingEnabled = params.enableUnscopedMemUseTrackers;
+        DebugValueFactory = initDebugValueFactory();
+    }
+
+    private static DebugValueFactory initDebugValueFactory() {
+        return new DebugValueFactory() {
+
+            @Override
+            public DebugTimer createTimer(String name, boolean conditional) {
+                return new TimerImpl(name, conditional, params.interceptTime);
+            }
+
+            @Override
+            public DebugCounter createCounter(String name, boolean conditional) {
+                return CounterImpl.create(name, conditional, params.interceptCount);
+            }
+
+            @Override
+            public DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method) {
+                return MethodMetricsImpl.getMethodMetrics(method);
+            }
+
+            @Override
+            public DebugMemUseTracker createMemUseTracker(String name, boolean conditional) {
+                return new MemUseTrackerImpl(name, conditional, params.interceptMem);
+            }
+        };
+    }
+
+    private static DebugValueFactory DebugValueFactory;
+
+    public static void setDebugValueFactory(DebugValueFactory factory) {
+        Objects.requireNonNull(factory);
+        DebugValueFactory = factory;
+    }
+
+    public static DebugValueFactory getDebugValueFactory() {
+        return DebugValueFactory;
+    }
+
+    private static boolean findMatch(Set<String> haystack, Set<String> haystackSubstrings, String needle) {
+        if (haystack.isEmpty() && haystackSubstrings.isEmpty()) {
+            // Empty haystack means match all
+            return true;
+        }
+        if (haystack.contains(needle)) {
+            return true;
+        }
+        if (!haystackSubstrings.isEmpty()) {
+            for (String h : haystackSubstrings) {
+                if (needle.startsWith(h)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean areUnconditionalTimersEnabled() {
+        return enabledTimers != null;
+    }
+
+    public static boolean areUnconditionalCountersEnabled() {
+        return enabledCounters != null;
+    }
+
+    public static boolean isMethodFilteringEnabled() {
+        return params.enableMethodFilter;
+    }
+
+    public static boolean areUnconditionalMethodMetricsEnabled() {
+        // we do not collect mm substrings
+        return params.enableUnscopedMethodMetrics;
+    }
+
+    protected static void parseCounterAndTimerSystemProperties(Set<String> counters, Set<String> timers, Set<String> countersSubstrings, Set<String> timersSubstrings) {
+        do {
+            try {
+                for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
+                    String name = e.getKey().toString();
+                    if (name.startsWith(ENABLE_COUNTER_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) {
+                        if (name.endsWith("*")) {
+                            countersSubstrings.add(name.substring(ENABLE_COUNTER_PROPERTY_NAME_PREFIX.length(), name.length() - 1));
+                        } else {
+                            counters.add(name.substring(ENABLE_COUNTER_PROPERTY_NAME_PREFIX.length()));
+                        }
+                    }
+                    if (name.startsWith(ENABLE_TIMER_PROPERTY_NAME_PREFIX) && Boolean.parseBoolean(e.getValue().toString())) {
+                        if (name.endsWith("*")) {
+                            timersSubstrings.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length(), name.length() - 1));
+                        } else {
+                            timers.add(name.substring(ENABLE_TIMER_PROPERTY_NAME_PREFIX.length()));
+                        }
+                    }
+                }
+                return;
+            } catch (ConcurrentModificationException e) {
+                // Iterating over the system properties may race with another thread that is
+                // updating the system properties. Simply try again in this case.
+            }
+        } while (true);
+    }
+
+    /**
+     * Creates a {@linkplain DebugTimer timer} that is enabled iff debugging is
+     * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding
+     * {@value #ENABLE_TIMER_PROPERTY_NAME_PREFIX} to {@code name} is
+     * {@linkplain Boolean#getBoolean(String) true}. If the latter condition is true, then the
+     * returned timer is {@linkplain DebugCounter#isConditional() unconditional} otherwise it is
+     * conditional.
+     * <p>
+     * A disabled timer has virtually no overhead.
+     */
+    public static DebugTimer timer(CharSequence name) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
+            return VOID_TIMER;
+        }
+        return createTimer("%s", name, null);
+    }
+
+    /**
+     * Creates a debug timer. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.timer(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if timing is enabled.
+     *
+     * @see #timer(String, Object, Object)
+     */
+    public static DebugTimer timer(String format, Object arg) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
+            return VOID_TIMER;
+        }
+        return createTimer(format, arg, null);
+    }
+
+    /**
+     * Creates a debug timer. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.timer(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if timing is enabled. In addition, each
+     * argument is subject to the following type based conversion before being passed as an argument
+     * to {@link String#format(String, Object...)}:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @see #timer(CharSequence)
+     */
+    public static DebugTimer timer(String format, Object arg1, Object arg2) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
+            return VOID_TIMER;
+        }
+        return createTimer(format, arg1, arg2);
+    }
+
+    /**
+     * There are paths where construction of formatted class names are common and the code below is
+     * surprisingly expensive, so compute it once and cache it.
+     */
+    private static final ClassValue<String> formattedClassName = new ClassValue<String>() {
+        @Override
+        protected String computeValue(Class<?> c) {
+            final String simpleName = c.getSimpleName();
+            Class<?> enclosingClass = c.getEnclosingClass();
+            if (enclosingClass != null) {
+                String prefix = "";
+                while (enclosingClass != null) {
+                    prefix = enclosingClass.getSimpleName() + "_" + prefix;
+                    enclosingClass = enclosingClass.getEnclosingClass();
+                }
+                return prefix + simpleName;
+            } else {
+                return simpleName;
+            }
+        }
+    };
+
+    public static Object convertFormatArg(Object arg) {
+        if (arg instanceof Class) {
+            return formattedClassName.get((Class<?>) arg);
+        }
+        return arg;
+    }
+
+    private static String formatDebugName(String format, Object arg1, Object arg2) {
+        return String.format(format, convertFormatArg(arg1), convertFormatArg(arg2));
+    }
+
+    private static DebugTimer createTimer(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        boolean conditional = enabledTimers == null || !findMatch(enabledTimers, enabledTimersSubstrings, name);
+        if (!ENABLED && conditional) {
+            return VOID_TIMER;
+        }
+        return DebugValueFactory.createTimer(name, conditional);
+    }
+
+    private static final DebugTimer VOID_TIMER = new DebugTimer() {
+
+        @Override
+        public DebugCloseable start() {
+            return DebugCloseable.VOID_CLOSEABLE;
+        }
+
+        @Override
+        public void setConditional(boolean flag) {
+            throw new InternalError("Cannot make void timer conditional");
+        }
+
+        @Override
+        public boolean isConditional() {
+            return false;
+        }
+
+        @Override
+        public long getCurrentValue() {
+            return 0L;
+        }
+
+        @Override
+        public TimeUnit getTimeUnit() {
+            return null;
+        }
+    };
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCloseable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCloseable.java
new file mode 100644
index 0000000..50aad68
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCloseable.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+/**
+ * An {@link AutoCloseable} whose {@link #close()} does not throw a checked exception.
+ */
+public interface DebugCloseable extends AutoCloseable {
+
+    DebugCloseable VOID_CLOSEABLE = new DebugCloseable() {
+
+        @Override
+        public void close() {
+        }
+    };
+
+    @Override
+    void close();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfig.java
new file mode 100644
index 0000000..66b5c32
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfig.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+import java.util.Collection;
+
+public interface DebugConfig {
+
+    /**
+     * Determines the current log level in the {@linkplain Debug#currentScope() current debug scope}
+     * .
+     */
+    int getLogLevel();
+
+    /**
+     * Determines the current dump level in the {@linkplain Debug#currentScope() current debug
+     * scope}.
+     */
+    int getDumpLevel();
+
+    /**
+     * Determines if logging can be enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     */
+    boolean isLogEnabledForMethod();
+
+    /**
+     * Determines if counting is enabled in the {@linkplain Debug#currentScope() current debug
+     * scope}.
+     *
+     * @see Debug#counter(CharSequence)
+     */
+    boolean isCountEnabled();
+
+    /**
+     * Determines if memory use tracking is enabled in the {@linkplain Debug#currentScope() current
+     * debug scope}.
+     *
+     * @see Debug#memUseTracker(CharSequence)
+     */
+    boolean isMemUseTrackingEnabled();
+
+    /**
+     * Determines if dumping can be enabled in the current method, regardless of the
+     * {@linkplain Debug#currentScope() current debug scope}.
+     */
+    boolean isDumpEnabledForMethod();
+
+    /**
+     * @see Debug#isVerifyEnabled()
+     */
+    boolean isVerifyEnabled();
+
+    /**
+     * @see Debug#isVerifyEnabledForMethod()
+     */
+    boolean isVerifyEnabledForMethod();
+
+    /**
+     * @see Debug#isMethodMeterEnabled()
+     */
+    boolean isMethodMeterEnabled();
+
+    /**
+     * Adds an object the context used by this configuration to do filtering.
+     */
+    void addToContext(Object o);
+
+    /**
+     * Removes an object the context used by this configuration to do filtering.
+     *
+     * This should only removes extra context added by {@link #addToContext(Object)}.
+     */
+    void removeFromContext(Object o);
+
+    /**
+     * @see Debug#timer(CharSequence)
+     */
+    boolean isTimeEnabled();
+
+    /**
+     * Handles notification of an exception occurring within a debug scope.
+     *
+     * @return the exception object that is to be propagated to parent scope. A value of
+     *         {@code null} indicates that {@code e} is to be propagated.
+     */
+    RuntimeException interceptException(Throwable e);
+
+    /**
+     * Gets the modifiable collection of dump handlers registered with this configuration.
+     */
+    Collection<DebugDumpHandler> dumpHandlers();
+
+    PrintStream output();
+
+    /**
+     * Gets the modifiable collection of verify handlers registered with this configuration.
+     */
+    Collection<DebugVerifyHandler> verifyHandlers();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigCustomizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigCustomizer.java
new file mode 100644
index 0000000..5b0f851
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigCustomizer.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+public interface DebugConfigCustomizer {
+    void customize(DebugConfig config, Object... extraArgs);
+
+    static <T> T lookupArg(Class<T> c, Object... extraArgs) {
+        for (Object arg : extraArgs) {
+            if (c.isInstance(arg)) {
+                return c.cast(arg);
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigScope.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigScope.java
new file mode 100644
index 0000000..555fa6a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigScope.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import org.graalvm.compiler.debug.internal.DebugScope;
+
+/**
+ * A utility for scoping a change to the current debug {@linkplain DebugScope#setConfig(DebugConfig)
+ * configuration}. For example:
+ *
+ * <pre>
+ *     DebugConfig config = ...;
+ *     try (DebugConfigScope s = new DebugConfigScope(config)) {
+ *         // ...
+ *     }
+ * </pre>
+ */
+public class DebugConfigScope implements AutoCloseable {
+
+    private final DebugConfig current;
+
+    /**
+     * Sets the current debug {@linkplain DebugScope#setConfig(DebugConfig) configuration} to a
+     * given value and creates an object that when {@linkplain #close() closed} resets the
+     * configuration to the {@linkplain DebugScope#getConfig() current} configuration.
+     */
+    public DebugConfigScope(DebugConfig config) {
+        this.current = DebugScope.getConfig();
+        DebugScope.getInstance().setConfig(config);
+    }
+
+    @Override
+    public void close() {
+        DebugScope.getInstance().setConfig(current);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCounter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCounter.java
new file mode 100644
index 0000000..f0e3f6b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugCounter.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+/**
+ * A counter for some value of interest.
+ */
+public interface DebugCounter {
+
+    /**
+     * Adds 1 to this counter if counting is {@link Debug#isCountEnabled() enabled} or this is an
+     * {@linkplain #isConditional() unconditional} counter.
+     */
+    void increment();
+
+    /**
+     * Adds {@code value} to this counter if counting is {@link Debug#isCountEnabled() enabled} or
+     * this is an {@linkplain #isConditional() unconditional} counter.
+     */
+    void add(long value);
+
+    /**
+     * Sets a flag determining if this counter is only enabled if counting is
+     * {@link Debug#isCountEnabled() enabled}.
+     */
+    void setConditional(boolean flag);
+
+    /**
+     * Determines if this counter is only enabled if counting is {@link Debug#isCountEnabled()
+     * enabled}.
+     */
+    boolean isConditional();
+
+    /**
+     * Gets the current value of this counter.
+     */
+    long getCurrentValue();
+
+    /**
+     * Determines if this counter is enabled (either conditionally or unconditionally).
+     */
+    default boolean isEnabled() {
+        return !isConditional() || Debug.isCountEnabled();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java
new file mode 100644
index 0000000..3b52c31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.Closeable;
+
+public interface DebugDumpHandler extends Closeable {
+
+    void dump(Object object, String message);
+
+    /**
+     * Flushes and releases resources managed by this dump handler. A subsequent call to
+     * {@link #dump(Object, String)} will create and open new resources. That is, this method can be
+     * used to reset the handler.
+     */
+    @Override
+    void close();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpScope.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpScope.java
new file mode 100644
index 0000000..fb6b236
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpScope.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+public class DebugDumpScope {
+
+    public final String name;
+
+    /**
+     * Specifies if this scope decorates an inner scope. A hierarchical or tree representation of
+     * nested scopes may choose to represent a decorator scope at the same level as the scope it
+     * decorates.
+     */
+    public final boolean decorator;
+
+    public DebugDumpScope(String name) {
+        this(name, false);
+    }
+
+    public DebugDumpScope(String name, boolean decorator) {
+        this.name = name;
+        this.decorator = decorator;
+    }
+
+    @Override
+    public String toString() {
+        return "DebugDumpScope[" + name + "]";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java
new file mode 100644
index 0000000..9a15e24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Log;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Count;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Time;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.TrackMemUse;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodMeter;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+import jdk.vm.ci.runtime.JVMCI;
+
+public class DebugEnvironment {
+
+    public static GraalDebugConfig initialize(PrintStream log, Object... extraArgs) {
+        // Initialize JVMCI before loading class Debug
+        JVMCI.initialize();
+        if (!Debug.isEnabled()) {
+            log.println("WARNING: Scope debugging needs to be enabled with -esa");
+            return null;
+        }
+        List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
+        List<DebugVerifyHandler> verifyHandlers = new ArrayList<>();
+        GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Count.getValue(), TrackMemUse.getValue(), Time.getValue(), Dump.getValue(), Verify.getValue(), MethodFilter.getValue(),
+                        MethodMeter.getValue(),
+                        log, dumpHandlers, verifyHandlers);
+
+        for (DebugConfigCustomizer customizer : GraalServices.load(DebugConfigCustomizer.class)) {
+            customizer.customize(debugConfig, extraArgs);
+        }
+
+        Debug.setConfig(debugConfig);
+        return debugConfig;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java
new file mode 100644
index 0000000..0345a54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.debug.internal.DebugScope;
+
+/**
+ * Implements the filter specified by the {@link Options#Dump}, {@link Options#Log},
+ * {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options.
+ * <p>
+ * These options enable the associated debug facility if their filter matches the
+ * {@linkplain DebugScope#getQualifiedName() name} of the {@linkplain Debug#currentScope() current
+ * scope}. For the {@link Options#Dump} and {@link Options#Log} options, the log or dump level is
+ * set. The {@link Options#Count},{@link Options#MethodMeter} and {@link Options#Time} options don't
+ * have a level, for them {@code level = 0} means disabled and a {@code level > 0} means enabled.
+ * <p>
+ * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code
+ * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it
+ * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code :
+ * <level>} is omitted, it defaults to {@link Debug#BASIC_LOG_LEVEL}. The term {@code ~<pattern>} is
+ * a shorthand for {@code <pattern>:0} to disable a debug facility for a pattern.
+ * <p>
+ * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term
+ * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log
+ * level of {@link Debug#BASIC_LOG_LEVEL}.
+ *
+ * <h2>Examples of filters</h2>
+ *
+ * <ul>
+ * <li>(empty string)<br>
+ * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}.
+ *
+ * <li>{@code :1}<br>
+ * Matches any scope with log level 1.
+ *
+ * <li>{@code *}<br>
+ * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}.
+ *
+ * <li>{@code CodeGen,CodeInstall}<br>
+ * Matches scopes containing "CodeGen" or "CodeInstall", both with log level
+ * {@link Debug#BASIC_LOG_LEVEL}.
+ *
+ * <li>{@code CodeGen:2,CodeInstall:1}<br>
+ * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1.
+ *
+ * <li>{@code :1,Dead:2}<br>
+ * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1.
+ *
+ * <li>{@code :1,Dead:0}<br>
+ * Matches all scopes with log level 1, except those containing "Dead".
+ *
+ * <li>{@code Code*}<br>
+ * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LOG_LEVEL}.
+ *
+ * <li>{@code Code,~Dead}<br>
+ * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LOG_LEVEL}.
+ * </ul>
+ */
+final class DebugFilter {
+
+    public static DebugFilter parse(String spec) {
+        if (spec == null) {
+            return null;
+        }
+        return new DebugFilter(spec.split(","));
+    }
+
+    private final Term[] terms;
+
+    private DebugFilter(String[] terms) {
+        if (terms.length == 0) {
+            this.terms = null;
+        } else {
+            this.terms = new Term[terms.length];
+            for (int i = 0; i < terms.length; i++) {
+                String t = terms[i];
+                int idx = t.indexOf(':');
+
+                String pattern;
+                int level;
+                if (idx < 0) {
+                    if (t.startsWith("~")) {
+                        pattern = t.substring(1);
+                        level = 0;
+                    } else {
+                        pattern = t;
+                        level = Debug.BASIC_LOG_LEVEL;
+                    }
+                } else {
+                    pattern = t.substring(0, idx);
+                    if (idx + 1 < t.length()) {
+                        String levelString = t.substring(idx + 1);
+                        try {
+                            level = Integer.parseInt(levelString);
+                        } catch (NumberFormatException e) {
+                            switch (levelString) {
+                                case "basic":
+                                    level = Debug.BASIC_LOG_LEVEL;
+                                    break;
+                                case "info":
+                                    level = Debug.INFO_LOG_LEVEL;
+                                    break;
+                                case "verbose":
+                                    level = Debug.VERBOSE_LOG_LEVEL;
+                                    break;
+                                default:
+                                    throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer");
+                            }
+                        }
+
+                    } else {
+                        level = Debug.BASIC_LOG_LEVEL;
+                    }
+                }
+
+                this.terms[i] = new Term(pattern, level);
+            }
+        }
+    }
+
+    /**
+     * Check whether a given input is matched by this filter, and determine the log level.
+     */
+    public int matchLevel(String input) {
+        if (terms == null) {
+            return Debug.BASIC_LOG_LEVEL;
+        } else {
+            int level = 0;
+            for (Term t : terms) {
+                if (t.matches(input)) {
+                    level = t.level;
+                }
+            }
+            return level;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("DebugFilter");
+        if (terms != null) {
+            buf.append(Arrays.toString(terms));
+        } else {
+            buf.append("[]");
+        }
+        return buf.toString();
+    }
+
+    private static class Term {
+
+        private final Pattern pattern;
+        public final int level;
+
+        Term(String filter, int level) {
+            this.level = level;
+            if (filter.isEmpty()) {
+                this.pattern = null;
+            } else if (filter.contains("*") || filter.contains("?")) {
+                this.pattern = Pattern.compile(MethodFilter.createGlobString(filter));
+            } else {
+                this.pattern = Pattern.compile(".*" + MethodFilter.createGlobString(filter) + ".*");
+            }
+        }
+
+        /**
+         * Determines if a given input is matched by this filter.
+         */
+        public boolean matches(String input) {
+            return pattern == null || pattern.matcher(input).matches();
+        }
+
+        @Override
+        public String toString() {
+            return (pattern == null ? ".*" : pattern.toString()) + ":" + level;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHistogram.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHistogram.java
new file mode 100644
index 0000000..bd28c6f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHistogram.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.List;
+
+/**
+ * Facility for recording value frequencies.
+ */
+public interface DebugHistogram {
+
+    /**
+     * Gets the name specified when this objected was {@linkplain Debug#createHistogram(String)
+     * created}.
+     */
+    String getName();
+
+    /**
+     * Increments the count for a given value.
+     */
+    void add(Object value);
+
+    void add(Object value, long count);
+
+    /**
+     * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
+     * values with higher frequencies first.
+     */
+    class CountedValue implements Comparable<CountedValue> {
+
+        private long count;
+        private final Object value;
+
+        public CountedValue(long count, Object value) {
+            this.count = count;
+            this.value = value;
+        }
+
+        @Override
+        public int compareTo(CountedValue o) {
+            if (count < o.count) {
+                return 1;
+            } else if (count > o.count) {
+                return -1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return count + " -> " + value;
+        }
+
+        public void inc() {
+            count++;
+        }
+
+        public void add(long n) {
+            count += n;
+        }
+
+        public long getCount() {
+            return count;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * Gets a list of the counted values, sorted in descending order of frequency.
+     */
+    List<CountedValue> getValues();
+
+    /**
+     * Interface for a service that can render a visualization of a histogram.
+     */
+    public interface Printer {
+
+        void print(DebugHistogram histogram);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugInitializationParticipant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugInitializationParticipant.java
new file mode 100644
index 0000000..738c5b1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugInitializationParticipant.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import org.graalvm.compiler.debug.Debug.Params;
+
+/**
+ * Defines a service that can modify the {@linkplain Params parameters} for {@link Debug}.
+ */
+public interface DebugInitializationParticipant {
+
+    /**
+     * Modifies the given {@link Debug} initialization parameters as necessary.
+     */
+    void apply(Params params);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMemUseTracker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMemUseTracker.java
new file mode 100644
index 0000000..8ce52f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMemUseTracker.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import com.sun.management.ThreadMXBean;
+
+/**
+ * Tracks memory usage within a scope using {@link ThreadMXBean}. This facility should be employed
+ * using the try-with-resources pattern:
+ *
+ * <pre>
+ * try (DebugMemUseTracker.Closeable a = memUseTracker.start()) {
+ *     // the code to measure
+ * }
+ * </pre>
+ */
+public interface DebugMemUseTracker {
+
+    /**
+     * Creates a point from which memory usage will be recorded if memory use tracking is
+     * {@linkplain Debug#isMemUseTrackingEnabled() enabled}.
+     *
+     * @return an object that must be closed once the activity has completed to add the memory used
+     *         since this call to the total for this tracker
+     */
+    DebugCloseable start();
+
+    /**
+     * Gets the current value of this tracker.
+     */
+    long getCurrentValue();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMethodMetrics.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMethodMetrics.java
new file mode 100644
index 0000000..6877926
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugMethodMetrics.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A set of debug metrics for all compilations of a {@link ResolvedJavaMethod}. A method metrics
+ * object is a container for several metrics per compilation of a method {@code <Method,List
+ * <CompilationData>>}. Metrics are stored on a per-method per-compilation basis.
+ *
+ * <pre>
+ * DebugMethodMetrics m = Debug.methodMetrics(method);
+ * m.incrementMetric("MyPerCompilationmetric");
+ * </pre>
+ *
+ * In contrast to global metrics like {@link DebugCounter}, {@link DebugTimer} or
+ * {@linkplain DebugMemUseTracker}, method compilation metrics are always associated with a
+ * {@link ResolvedJavaMethod}.
+ */
+public interface DebugMethodMetrics {
+
+    /**
+     * Adds {@code value} to the metric for the current compilation associated with
+     * {@code metricName}. If the metric is yet undefined for the current compilation a new metric
+     * for the given name is defined and the value for it is set to {@code value}.
+     *
+     * @param metricName the name for the metric to be incremented
+     * @param value the value to add to the metric defined by name
+     */
+    void addToMetric(long value, String metricName);
+
+    /**
+     * @see #addToMetric(long, String)
+     */
+    void addToMetric(long value, String format, Object arg1);
+
+    /**
+     * @see #addToMetric(long, String)
+     */
+    void addToMetric(long value, String format, Object arg1, Object arg2);
+
+    /**
+     * @see #addToMetric(long, String)
+     */
+    void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3);
+
+    /**
+     * Adds {@code 1} to the metric for the current compilation associated with {@code metricName}.
+     * If the metric is yet undefined for the current compilation a new metric for the given name is
+     * defined and the value for it is set to {@code value}.
+     *
+     * @param metricName the name for the metric to be incremented
+     */
+    void incrementMetric(String metricName);
+
+    /**
+     * @see #incrementMetric(String)
+     */
+    void incrementMetric(String format, Object arg1);
+
+    /**
+     * @see #incrementMetric(String)
+     */
+    void incrementMetric(String format, Object arg1, Object arg2);
+
+    /**
+     * @see #incrementMetric(String)
+     */
+    void incrementMetric(String format, Object arg1, Object arg2, Object arg3);
+
+    /**
+     * Gets the value of the metric for the current compilation associated with the
+     * {@code metricName} . If the metric is yet undefined for the current compilation {@code 0} is
+     * returned instead.
+     *
+     * @param metricName the name of the metric for which the value will be returned
+     * @return the value of the metric for the given compilation or {@code 0} if it is not defined
+     */
+    long getCurrentMetricValue(String metricName);
+
+    /**
+     * @see #getCurrentMetricValue(String)
+     */
+    long getCurrentMetricValue(String format, Object arg1);
+
+    /**
+     * @see #getCurrentMetricValue(String)
+     */
+    long getCurrentMetricValue(String format, Object arg1, Object arg2);
+
+    /**
+     * @see #getCurrentMetricValue(String)
+     */
+    long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3);
+
+    /**
+     * Gets the {@link ResolvedJavaMethod} associated with this {@linkplain DebugMethodMetrics}.
+     *
+     * @return the {@link ResolvedJavaMethod} of the current method metric
+     */
+    ResolvedJavaMethod getMethod();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugTimer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugTimer.java
new file mode 100644
index 0000000..f05d251
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugTimer.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A timer for some activity of interest. A timer should be deployed using the try-with-resources
+ * pattern:
+ *
+ * <pre>
+ * try (TimerCloseable a = timer.start()) {
+ *     // the code to time
+ * }
+ * </pre>
+ */
+public interface DebugTimer {
+
+    /**
+     * Starts this timer if timing is {@linkplain Debug#isTimeEnabled() enabled} or this is an
+     * {@linkplain #isConditional() unconditional} timer.
+     *
+     * @return an object that must be closed once the activity has completed to add the elapsed time
+     *         since this call to the total for this timer
+     */
+    DebugCloseable start();
+
+    /**
+     * Sets a flag determining if this timer is only enabled if timing is
+     * {@link Debug#isTimeEnabled() enabled}.
+     */
+    void setConditional(boolean flag);
+
+    /**
+     * Determines if this timer is only enabled if timing is {@link Debug#isTimeEnabled() enabled}.
+     */
+    boolean isConditional();
+
+    /**
+     * Gets the current value of this timer.
+     */
+    long getCurrentValue();
+
+    /**
+     * Gets the time unit of this timer.
+     */
+    TimeUnit getTimeUnit();
+
+    /**
+     * Gets the timer recording the amount time spent within a timed scope minus the time spent in
+     * any nested timed scopes.
+     *
+     * @return null if this timer does not support flat timing
+     */
+    default DebugTimer getFlat() {
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueFactory.java
new file mode 100644
index 0000000..a97d90e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A factory for creating {@link DebugCounter}s, {@link DebugTimer}s, {@link DebugMemUseTracker}s
+ * and {@link DebugMethodMetrics}.
+ */
+public interface DebugValueFactory {
+
+    DebugCounter createCounter(String name, boolean conditional);
+
+    DebugTimer createTimer(String name, boolean conditional);
+
+    DebugMemUseTracker createMemUseTracker(String name, boolean conditional);
+
+    DebugMethodMetrics createMethodMetrics(ResolvedJavaMethod method);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java
new file mode 100644
index 0000000..d949f97
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+/**
+ * Performs some kind of verification on an object.
+ */
+public interface DebugVerifyHandler {
+
+    /**
+     * Verifies that a given object satisfies some invariants.
+     *
+     * @param object object to verify
+     * @param message description of verification context
+     */
+    void verify(Object object, String message);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DelegatingDebugConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DelegatingDebugConfig.java
new file mode 100644
index 0000000..ac336ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DelegatingDebugConfig.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.internal.DebugScope;
+
+public class DelegatingDebugConfig implements DebugConfig {
+
+    protected final DebugConfig delegate;
+
+    /**
+     * The features of a {@link DelegatingDebugConfig} that can be force
+     * {@linkplain DelegatingDebugConfig#enable(Feature) enabled}/
+     * {@linkplain DelegatingDebugConfig#disable(Feature) disabled} or
+     * {@linkplain DelegatingDebugConfig#delegate(Feature) delegated}.
+     */
+    public enum Feature {
+        /**
+         * @see Debug#isLogEnabledForMethod()
+         */
+        LOG_METHOD,
+        /**
+         * @see Debug#isDumpEnabledForMethod()
+         */
+        DUMP_METHOD,
+        /**
+         * @see Debug#isVerifyEnabled()
+         */
+        VERIFY,
+        /**
+         * @see Debug#isVerifyEnabledForMethod()
+         */
+        VERIFY_METHOD,
+        /**
+         * @see Debug#isCountEnabled()
+         */
+        COUNT,
+        /**
+         * @see Debug#isMethodMeterEnabled()
+         */
+        METHOD_METRICS,
+        /**
+         * @see Debug#isMemUseTrackingEnabled()
+         */
+        TRACK_MEM_USE,
+        /**
+         * @see Debug#isTimeEnabled()
+         */
+        TIME,
+        /**
+         * @see DebugConfig#interceptException(Throwable)
+         */
+        INTERCEPT
+    }
+
+    private final Map<Feature, Boolean> featureState = new EnumMap<>(Feature.class);
+
+    /**
+     * The debug levels of a {@link DelegatingDebugConfig} than can be
+     * {@linkplain DelegatingDebugConfig#override(Level, int) overridden} or
+     * {@linkplain DelegatingDebugConfig#delegate(Level) delegated}.
+     */
+    public enum Level {
+        LOG,
+        DUMP
+    }
+
+    private final Map<Level, Integer> levelState = new EnumMap<>(Level.class);
+
+    /**
+     * Creates a config that delegates to the {@link DebugScope#getConfig() current config}.
+     */
+    public DelegatingDebugConfig() {
+        this(DebugScope.getConfig());
+    }
+
+    /**
+     * Creates a config that delegates to a given config.
+     */
+    public DelegatingDebugConfig(DebugConfig delegate) {
+        this.delegate = delegate;
+    }
+
+    public DelegatingDebugConfig enable(Feature feature) {
+        featureState.put(feature, Boolean.TRUE);
+        return this;
+    }
+
+    public DelegatingDebugConfig disable(Feature feature) {
+        featureState.put(feature, Boolean.FALSE);
+        return this;
+    }
+
+    public DelegatingDebugConfig override(Level level, int newLevel) {
+        levelState.put(level, newLevel);
+        return this;
+    }
+
+    public DelegatingDebugConfig delegate(Feature feature) {
+        featureState.put(feature, null);
+        return this;
+    }
+
+    public DelegatingDebugConfig delegate(Level level) {
+        levelState.put(level, null);
+        return this;
+    }
+
+    @Override
+    public int getLogLevel() {
+        Integer ls = levelState.get(Level.LOG);
+        if (ls == null) {
+            return delegate.getLogLevel();
+        }
+        return ls.intValue();
+    }
+
+    @Override
+    public boolean isLogEnabledForMethod() {
+        Boolean fs = featureState.get(Feature.LOG_METHOD);
+        if (fs == null) {
+            return delegate.isLogEnabledForMethod();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isCountEnabled() {
+        Boolean fs = featureState.get(Feature.COUNT);
+        if (fs == null) {
+            return delegate.isCountEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isMemUseTrackingEnabled() {
+        Boolean fs = featureState.get(Feature.TRACK_MEM_USE);
+        if (fs == null) {
+            return delegate.isMemUseTrackingEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public int getDumpLevel() {
+        Integer ls = levelState.get(Level.DUMP);
+        if (ls == null) {
+            return delegate.getDumpLevel();
+        }
+        return ls.intValue();
+    }
+
+    @Override
+    public boolean isDumpEnabledForMethod() {
+        Boolean fs = featureState.get(Feature.DUMP_METHOD);
+        if (fs == null) {
+            return delegate.isDumpEnabledForMethod();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isVerifyEnabled() {
+        Boolean fs = featureState.get(Feature.VERIFY);
+        if (fs == null) {
+            return delegate.isVerifyEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isVerifyEnabledForMethod() {
+        Boolean fs = featureState.get(Feature.VERIFY_METHOD);
+        if (fs == null) {
+            return delegate.isVerifyEnabledForMethod();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isTimeEnabled() {
+        Boolean fs = featureState.get(Feature.TIME);
+        if (fs == null) {
+            return delegate.isTimeEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public boolean isMethodMeterEnabled() {
+        Boolean fs = featureState.get(Feature.METHOD_METRICS);
+        if (fs == null) {
+            return delegate.isMethodMeterEnabled();
+        }
+        return fs.booleanValue();
+    }
+
+    @Override
+    public RuntimeException interceptException(Throwable e) {
+        Boolean fs = featureState.get(Feature.INTERCEPT);
+        if (fs == null || fs) {
+            return delegate.interceptException(e);
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<DebugDumpHandler> dumpHandlers() {
+        return delegate.dumpHandlers();
+    }
+
+    @Override
+    public Collection<DebugVerifyHandler> verifyHandlers() {
+        return delegate.verifyHandlers();
+    }
+
+    @Override
+    public PrintStream output() {
+        return delegate.output();
+    }
+
+    @Override
+    public void addToContext(Object o) {
+        delegate.addToContext(o);
+    }
+
+    @Override
+    public void removeFromContext(Object o) {
+        delegate.removeFromContext(o);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Fingerprint.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Fingerprint.java
new file mode 100644
index 0000000..367d0dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Fingerprint.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Facility for fingerprinting execution.
+ */
+public class Fingerprint implements AutoCloseable {
+
+    public static class Options {
+        @Option(help = "Enables execution fingerprinting.")//
+        public static final OptionValue<Boolean> UseFingerprinting = new OptionValue<>(false);
+
+        @Option(help = "Limit number of events shown in fingerprinting error message.")//
+        public static final OptionValue<Integer> FingerprintErrorEventTailLength = new OptionValue<>(50);
+
+        @Option(help = "Fingerprinting event at which to execute breakpointable code.")//
+        public static final OptionValue<Integer> FingerprintingBreakpointEvent = new OptionValue<>(-1);
+    }
+
+    /**
+     * Determines whether fingerprinting is enabled.
+     */
+    public static final boolean ENABLED = Options.UseFingerprinting.getValue();
+
+    private static final ThreadLocal<Fingerprint> current = ENABLED ? new ThreadLocal<>() : null;
+
+    private final List<String> events;
+    private int index;
+
+    /**
+     * Creates an object to record a fingerprint.
+     */
+    public Fingerprint() {
+        events = new ArrayList<>();
+        index = -1;
+    }
+
+    /**
+     * Creates an object to verify execution matches a given fingerprint.
+     *
+     * @param toVerifyAgainst the fingerprint events to verify against
+     */
+    public Fingerprint(List<String> toVerifyAgainst) {
+        this.events = toVerifyAgainst;
+        index = 0;
+    }
+
+    /**
+     * Creates an object to verify execution matches a given fingerprint.
+     *
+     * @param toVerifyAgainst the fingerprint to verify against
+     */
+    public Fingerprint(Fingerprint toVerifyAgainst) {
+        this(toVerifyAgainst.events);
+    }
+
+    public Collection<String> getEvents() {
+        return Collections.unmodifiableCollection(events);
+    }
+
+    /**
+     * Starts fingerprint recording or verification for the current thread. At most one fingerprint
+     * object can be active for any thread.
+     */
+    public Fingerprint open() {
+        if (ENABLED) {
+            assert current.get() == null;
+            current.set(this);
+            return this;
+        }
+        return null;
+    }
+
+    /**
+     * Finishes fingerprint recording or verification for the current thread.
+     */
+    @Override
+    public void close() {
+        if (ENABLED) {
+            assert current.get() == this;
+            current.set(null);
+        }
+    }
+
+    private static final int BREAKPOINT_EVENT = Options.FingerprintingBreakpointEvent.getValue();
+
+    /**
+     * Submits an execution event for the purpose of recording or verifying a fingerprint. This must
+     * only be called if {@link #ENABLED} is {@code true}.
+     */
+    public static void submit(String format, Object... args) {
+        assert ENABLED : "fingerprinting must be enabled (-Dgraal." + Options.UseFingerprinting.getName() + "=true)";
+        Fingerprint fingerprint = current.get();
+        if (fingerprint != null) {
+            int eventId = fingerprint.nextEventId();
+            if (eventId == BREAKPOINT_EVENT) {
+                // Set IDE breakpoint on the following line and set the relevant
+                // system property to debug a fingerprint verification error.
+                System.console();
+            }
+            fingerprint.event(String.format(eventId + ": " + format, args));
+        }
+    }
+
+    private int nextEventId() {
+        return index == -1 ? events.size() : index;
+    }
+
+    private static final int MAX_EVENT_TAIL_IN_ERROR_MESSAGE = Options.FingerprintErrorEventTailLength.getValue();
+
+    private String tail() {
+        int start = Math.max(index - MAX_EVENT_TAIL_IN_ERROR_MESSAGE, 0);
+        return events.subList(start, index).stream().collect(Collectors.joining(String.format("%n")));
+    }
+
+    private void event(String entry) {
+        if (index == -1) {
+            events.add(entry);
+        } else {
+            if (index > events.size()) {
+                throw new InternalError(String.format("%s%nOriginal fingerprint limit reached", tail()));
+            }
+            String l = events.get(index);
+            if (!l.equals(entry)) {
+                throw new InternalError(String.format("%s%nFingerprint differs at event %d%nexpected: %s%n  actual: %s", tail(), index, l, entry));
+            }
+            index++;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java
new file mode 100644
index 0000000..69c6e46
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.JavaMethod;
+
+public class GraalDebugConfig implements DebugConfig {
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug)
+        public static final OptionValue<String> Dump = new OptionValue<>(null);
+        @Option(help = "Pattern for scope(s) in which counting is enabled (see DebugFilter and Debug.counter). " +
+                       "An empty value enables all counters unconditionally.", type = OptionType.Debug)
+        public static final OptionValue<String> Count = new OptionValue<>(null);
+        @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug)
+        public static final OptionValue<String> Verify = new OptionValue<String>() {
+            @Override
+            protected String defaultValue() {
+                return assertionsEnabled() ? "" : null;
+            }
+        };
+        @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.counter). " +
+                       "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug)
+        public static final OptionValue<String> TrackMemUse = new OptionValue<>(null);
+        @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer). " +
+                       "An empty value enables all timers unconditionally.", type = OptionType.Debug)
+        public static final OptionValue<String> Time = new OptionValue<>(null);
+        @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug)
+        public static final OptionValue<String> Log = new OptionValue<>(null);
+        @Option(help = "Pattern for filtering debug scope output based on method context (see MethodFilter)", type = OptionType.Debug)
+        public static final OptionValue<String> MethodFilter = new OptionValue<>(null);
+        @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug)
+        public static final OptionValue<Boolean> MethodFilterRootOnly = new OptionValue<>(false);
+
+        @Option(help = "How to print counters and timing values:%n" +
+                       "Name - aggregate by unqualified name%n" +
+                       "Partial - aggregate by partially qualified name (e.g., A.B.C.D.Counter and X.Y.Z.D.Counter will be merged to D.Counter)%n" +
+                       "Complete - aggregate by qualified name%n" +
+                       "Thread - aggregate by qualified name and thread", type = OptionType.Debug)
+        public static final OptionValue<String> DebugValueSummary = new OptionValue<>("Name");
+        @Option(help = "Print counters and timers in a human readable form.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> DebugValueHumanReadable = new OptionValue<>(true);
+        @Option(help = "Omit reporting 0-value counters", type = OptionType.Debug)
+        public static final OptionValue<Boolean> SuppressZeroDebugValues = new OptionValue<>(true);
+        @Option(help = "Only report debug values for maps which match the regular expression.", type = OptionType.Debug)
+        public static final OptionValue<String> DebugValueThreadFilter = new OptionValue<>(null);
+        @Option(help = "Write debug values into a file instead of the terminal. " +
+                       "If DebugValueSummary is Thread, the thread name will be prepended.", type = OptionType.Debug)
+        public static final OptionValue<String> DebugValueFile = new OptionValue<>(null);
+        @Option(help = "Send Graal compiler IR to dump handlers on error", type = OptionType.Debug)
+        public static final OptionValue<Boolean> DumpOnError = new OptionValue<>(false);
+        @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
+        public static final OptionValue<Boolean> InterceptBailout = new OptionValue<>(false);
+        @Option(help = "Enable more verbose log output when available", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
+
+        @Option(help = "The directory where various Graal dump files are written.")
+        public static final OptionValue<String> DumpPath = new OptionValue<>(".");
+
+        @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintCFG = new OptionValue<>(false);
+        @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintBackendCFG = new OptionValue<>(true);
+        @Option(help = "Base filename when dumping C1Visualizer output to files.", type = OptionType.Debug)
+        public static final OptionValue<String> PrintCFGFileName = new OptionValue<>("compilations");
+
+        @Option(help = "Output probabilities for fixed nodes during binary graph dumping", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintGraphProbabilities = new OptionValue<>(false);
+        @Option(help = "Enable dumping to the IdealGraphVisualizer.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintIdealGraph = new OptionValue<>(true);
+        @Option(help = "Dump IdealGraphVisualizer output in binary format", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintBinaryGraphs = new OptionValue<>(true);
+        @Option(help = "Print Ideal graphs as opposed to sending them over the network.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintIdealGraphFile = new OptionValue<>(false);
+        @Option(help = "Base filename when dumping Ideal graphs to files.", type = OptionType.Debug)
+        public static final OptionValue<String> PrintIdealGraphFileName = new OptionValue<>("runtime-graphs");
+
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<String> PrintIdealGraphAddress = new OptionValue<>("127.0.0.1");
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Integer> PrintIdealGraphPort = new OptionValue<>(4444);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Integer> PrintBinaryGraphPort = new OptionValue<>(4445);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintIdealGraphSchedule = new OptionValue<>(false);
+        @Option(help = "Enable dumping Truffle ASTs to the IdealGraphVisualizer.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintTruffleTrees = new OptionValue<>(true);
+
+        @Option(help = "Enable dumping canonical text from for graphs.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintCanonicalGraphStrings = new OptionValue<>(false);
+        @Option(help = "Base directory when dumping graphs strings to files.", type = OptionType.Debug)
+        public static final OptionValue<String> PrintCanonicalGraphStringsDirectory = new OptionValue<>("graph-strings");
+        @Option(help = "Choose format used when dumping canonical text for graphs: " +
+                "0 gives a scheduled graph (better for spotting changes involving the schedule)" +
+                "while 1 gives a CFG containing expressions rooted at fixed nodes (better for spotting small structure differences)", type = OptionType.Debug)
+        public static final OptionValue<Integer> PrintCanonicalGraphStringFlavor = new OptionValue<>(0);
+        @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> CanonicalGraphStringsExcludeVirtuals = new OptionValue<>(true);
+        @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> CanonicalGraphStringsCheckConstants = new OptionValue<>(false);
+        @Option(help = "Attempts to remove object identity hashes when dumping canonical text for graphs.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> CanonicalGraphStringsRemoveIdentities = new OptionValue<>(true);
+
+        @Option(help = "Enable per method metrics that are collected across all compilations of a method." +
+                       "Pattern for scope(s) in which method metering is enabled (see DebugFilter and Debug.metric).", type = OptionType.Debug)
+        public static final OptionValue<String> MethodMeter = new OptionValue<>(null);
+        @Option(help = "If a global metric (DebugTimer, DebugCounter or DebugMemUseTracker) is enabled in the same scope as a method metric, " +
+                       "use the global metric to update the method metric for the current compilation. " +
+                       "This option enables the re-use of global metrics on per-compilation basis. " +
+                       "Whenever a value is added to a global metric, the value is also added to a MethodMetric under the same name " +
+                       "as the global metric. " +
+                       "This option incurs a small but constant overhead due to the context method lookup at each metric update. " +
+                       "Format to specify GlobalMetric interception:(Timers|Counters|MemUseTrackers)(,Timers|,Counters|,MemUseTrackers)*", type = OptionType.Debug)
+        public static final OptionValue<String> GlobalMetricsInterceptedByMethodMetrics = new OptionValue<>(null);
+        @Option(help = "Force-enable debug code paths", type = OptionType.Debug)
+        public static final OptionValue<Boolean> ForceDebugEnable = new OptionValue<>(false);
+        @Option(help = "Clear the debug metrics after bootstrap.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> ClearMetricsAfterBootstrap = new OptionValue<>(false);
+        @Option(help = "Do not compile anything on bootstrap but just initialize the compiler.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> BootstrapInitializeOnly = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    public static boolean isNotEmpty(OptionValue<String> option) {
+        return option.getValue() != null && !option.getValue().isEmpty();
+    }
+
+    public static boolean areDebugScopePatternsEnabled() {
+        return Options.DumpOnError.getValue() || Options.Dump.getValue() != null || Options.Log.getValue() != null || areScopedGlobalMetricsEnabled();
+    }
+
+    public static boolean isGlobalMetricsInterceptedByMethodMetricsEnabled() {
+        return isNotEmpty(Options.GlobalMetricsInterceptedByMethodMetrics);
+    }
+
+    /**
+     * Determines if any of {@link Options#Count}, {@link Options#Time} or
+     * {@link Options#TrackMemUse} has a non-null, non-empty value.
+     */
+    public static boolean areScopedGlobalMetricsEnabled() {
+        return isNotEmpty(Options.Count) || isNotEmpty(Options.Time) || isNotEmpty(Options.TrackMemUse) || isNotEmpty(Options.MethodMeter);
+    }
+
+    private final DebugFilter countFilter;
+    private final DebugFilter logFilter;
+    private final DebugFilter methodMetricsFilter;
+    private final DebugFilter trackMemUseFilter;
+    private final DebugFilter timerFilter;
+    private final DebugFilter dumpFilter;
+    private final DebugFilter verifyFilter;
+    private final MethodFilter[] methodFilter;
+    private final List<DebugDumpHandler> dumpHandlers;
+    private final List<DebugVerifyHandler> verifyHandlers;
+    private final PrintStream output;
+
+    // Use an identity set to handle context objects that don't support hashCode().
+    private final Set<Object> extraFilters = Collections.newSetFromMap(new IdentityHashMap<>());
+
+    public GraalDebugConfig(String logFilter, String countFilter, String trackMemUseFilter, String timerFilter, String dumpFilter, String verifyFilter, String methodFilter,
+                    String methodMetricsFilter, PrintStream output, List<DebugDumpHandler> dumpHandlers, List<DebugVerifyHandler> verifyHandlers) {
+        this.logFilter = DebugFilter.parse(logFilter);
+        this.countFilter = DebugFilter.parse(countFilter);
+        this.trackMemUseFilter = DebugFilter.parse(trackMemUseFilter);
+        this.timerFilter = DebugFilter.parse(timerFilter);
+        this.dumpFilter = DebugFilter.parse(dumpFilter);
+        this.verifyFilter = DebugFilter.parse(verifyFilter);
+        this.methodMetricsFilter = DebugFilter.parse(methodMetricsFilter);
+        if (methodFilter == null || methodFilter.isEmpty()) {
+            this.methodFilter = null;
+        } else {
+            this.methodFilter = org.graalvm.compiler.debug.MethodFilter.parse(methodFilter);
+        }
+
+        // Report the filters that have been configured so the user can verify it's what they expect
+        if (logFilter != null || countFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) {
+            // TTY.println(Thread.currentThread().getName() + ": " + toString());
+        }
+        this.dumpHandlers = dumpHandlers;
+        this.verifyHandlers = verifyHandlers;
+        this.output = output;
+    }
+
+    @Override
+    public int getLogLevel() {
+        return getLevel(logFilter);
+    }
+
+    @Override
+    public boolean isLogEnabledForMethod() {
+        return isEnabledForMethod(logFilter);
+    }
+
+    @Override
+    public boolean isCountEnabled() {
+        return isEnabled(countFilter);
+    }
+
+    @Override
+    public boolean isMemUseTrackingEnabled() {
+        return isEnabled(trackMemUseFilter);
+    }
+
+    @Override
+    public int getDumpLevel() {
+        return getLevel(dumpFilter);
+    }
+
+    @Override
+    public boolean isDumpEnabledForMethod() {
+        return isEnabledForMethod(dumpFilter);
+    }
+
+    @Override
+    public boolean isVerifyEnabled() {
+        return isEnabled(verifyFilter);
+    }
+
+    @Override
+    public boolean isVerifyEnabledForMethod() {
+        return isEnabledForMethod(verifyFilter);
+    }
+
+    @Override
+    public boolean isMethodMeterEnabled() {
+        return isEnabled(methodMetricsFilter);
+    }
+
+    @Override
+    public boolean isTimeEnabled() {
+        return isEnabled(timerFilter);
+    }
+
+    @Override
+    public PrintStream output() {
+        return output;
+    }
+
+    private boolean isEnabled(DebugFilter filter) {
+        return getLevel(filter) > 0;
+    }
+
+    private int getLevel(DebugFilter filter) {
+        int level;
+        if (filter == null) {
+            level = 0;
+        } else {
+            level = filter.matchLevel(Debug.currentScope());
+        }
+        if (level > 0 && !checkMethodFilter()) {
+            level = 0;
+        }
+        return level;
+    }
+
+    private boolean isEnabledForMethod(DebugFilter filter) {
+        return filter != null && checkMethodFilter();
+    }
+
+    /**
+     * Extracts a {@link JavaMethod} from an opaque debug context.
+     *
+     * @return the {@link JavaMethod} represented by {@code context} or null
+     */
+    public static JavaMethod asJavaMethod(Object context) {
+        if (context instanceof JavaMethodContext) {
+            return ((JavaMethodContext) context).asJavaMethod();
+        }
+        if (context instanceof JavaMethod) {
+            return (JavaMethod) context;
+        }
+        return null;
+    }
+
+    private boolean checkMethodFilter() {
+        if (methodFilter == null && extraFilters.isEmpty()) {
+            return true;
+        } else {
+            JavaMethod lastMethod = null;
+            for (Object o : Debug.context()) {
+                if (extraFilters.contains(o)) {
+                    return true;
+                } else if (methodFilter != null) {
+                    JavaMethod method = asJavaMethod(o);
+                    if (method != null) {
+                        if (!Options.MethodFilterRootOnly.getValue()) {
+                            if (org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, method)) {
+                                return true;
+                            }
+                        } else {
+                            /*
+                             * The context values operate as a stack so if we want MethodFilter to
+                             * only apply to the root method we have to check only the last method
+                             * seen.
+                             */
+                            lastMethod = method;
+                        }
+                    }
+                }
+            }
+            if (lastMethod != null && org.graalvm.compiler.debug.MethodFilter.matches(methodFilter, lastMethod)) {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Debug config:");
+        add(sb, "Log", logFilter);
+        add(sb, "Count", countFilter);
+        add(sb, "MethodMeter", methodMetricsFilter);
+        add(sb, "Time", timerFilter);
+        add(sb, "Dump", dumpFilter);
+        add(sb, "MethodFilter", methodFilter);
+        return sb.toString();
+    }
+
+    private static void add(StringBuilder sb, String name, Object filter) {
+        if (filter != null) {
+            sb.append(' ');
+            sb.append(name);
+            sb.append('=');
+            if (filter instanceof Object[]) {
+                sb.append(Arrays.toString((Object[]) filter));
+            } else {
+                sb.append(String.valueOf(filter));
+            }
+        }
+    }
+
+    @Override
+    public RuntimeException interceptException(Throwable e) {
+        if (e instanceof BailoutException && !Options.InterceptBailout.getValue()) {
+            return null;
+        }
+        Debug.setConfig(Debug.fixedConfig(Debug.BASIC_LOG_LEVEL, Debug.BASIC_LOG_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output));
+        Debug.log("Exception occurred in scope: %s", Debug.currentScope());
+        Map<Object, Object> firstSeen = new IdentityHashMap<>();
+        for (Object o : Debug.context()) {
+            // Only dump a context object once.
+            if (!firstSeen.containsKey(o)) {
+                firstSeen.put(o, o);
+                if (Options.DumpOnError.getValue()) {
+                    Debug.dump(Debug.BASIC_LOG_LEVEL, o, "Exception: %s", e);
+                } else {
+                    Debug.log("Context obj %s", o);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<DebugDumpHandler> dumpHandlers() {
+        return dumpHandlers;
+    }
+
+    @Override
+    public Collection<DebugVerifyHandler> verifyHandlers() {
+        return verifyHandlers;
+    }
+
+    @Override
+    public void addToContext(Object o) {
+        extraFilters.add(o);
+    }
+
+    @Override
+    public void removeFromContext(Object o) {
+        extraFilters.remove(o);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java
new file mode 100644
index 0000000..4ff6cc5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * Indicates a condition that should never occur during normal operation.
+ */
+public class GraalError extends Error {
+
+    private static final long serialVersionUID = 531632331813456233L;
+    private final ArrayList<String> context = new ArrayList<>();
+
+    public static RuntimeException unimplemented() {
+        throw new GraalError("unimplemented");
+    }
+
+    public static RuntimeException unimplemented(String msg) {
+        throw new GraalError("unimplemented: %s", msg);
+    }
+
+    public static RuntimeException shouldNotReachHere() {
+        throw new GraalError("should not reach here");
+    }
+
+    public static RuntimeException shouldNotReachHere(String msg) {
+        throw new GraalError("should not reach here: %s", msg);
+    }
+
+    public static RuntimeException shouldNotReachHere(Throwable cause) {
+        throw new GraalError(cause);
+    }
+
+    /**
+     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
+     * stronger than assertions in that they are always checked. Error messages for guarantee
+     * violations should clearly indicate the nature of the problem as well as a suggested solution
+     * if possible.
+     *
+     * @param condition the condition to check
+     * @param msg the message that will be associated with the error, in
+     *            {@link String#format(String, Object...)} syntax
+     * @param args arguments to the format string
+     */
+    public static void guarantee(boolean condition, String msg, Object... args) {
+        if (!condition) {
+            throw new GraalError("failed guarantee: " + msg, args);
+        }
+    }
+
+    /**
+     * This constructor creates a {@link GraalError} with a given message.
+     *
+     * @param msg the message that will be associated with the error
+     */
+    public GraalError(String msg) {
+        super(msg);
+    }
+
+    /**
+     * This constructor creates a {@link GraalError} with a message assembled via
+     * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
+     * always generate the same output.
+     *
+     * @param msg the message that will be associated with the error, in String.format syntax
+     * @param args parameters to String.format - parameters that implement {@link Iterable} will be
+     *            expanded into a [x, x, ...] representation.
+     */
+    public GraalError(String msg, Object... args) {
+        super(format(msg, args));
+    }
+
+    /**
+     * This constructor creates a {@link GraalError} for a given causing Throwable instance.
+     *
+     * @param cause the original exception that contains additional information on this error
+     */
+    public GraalError(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * This constructor creates a {@link GraalError} and adds all the
+     * {@linkplain #addContext(String) context} of another {@link GraalError}.
+     *
+     * @param e the original {@link GraalError}
+     */
+    public GraalError(GraalError e) {
+        super(e);
+        context.addAll(e.context);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(super.toString());
+        for (String s : context) {
+            str.append("\n\tat ").append(s);
+        }
+        return str.toString();
+    }
+
+    private static String format(String msg, Object... args) {
+        if (args != null) {
+            // expand Iterable parameters into a list representation
+            for (int i = 0; i < args.length; i++) {
+                if (args[i] instanceof Iterable<?>) {
+                    ArrayList<Object> list = new ArrayList<>();
+                    for (Object o : (Iterable<?>) args[i]) {
+                        list.add(o);
+                    }
+                    args[i] = list.toString();
+                }
+            }
+        }
+        return String.format(Locale.ENGLISH, msg, args);
+    }
+
+    public GraalError addContext(String newContext) {
+        this.context.add(newContext);
+        return this;
+    }
+
+    public GraalError addContext(String name, Object obj) {
+        return addContext(format("%s: %s", name, obj));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Indent.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Indent.java
new file mode 100644
index 0000000..ecb6cb3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Indent.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+/**
+ * Object used to close a debug {@link Debug#indent() indentation} scope.
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ *
+ *      try (Indent i1 = Debug.logAndIndent("header message")) {
+ *          ...
+ *          Debug.log("message");
+ *          ...
+ *          try (Indent i2 = Debug.logAndIndent(sub-header message")) {
+ *              ...
+ *              Debug.log("inner message");
+ *              ...
+ *          }
+ *      }
+ *
+ * </pre>
+ */
+public interface Indent extends AutoCloseable {
+
+    /**
+     * Closes the current indentation scope.
+     */
+    @Override
+    void close();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/JavaMethodContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/JavaMethodContext.java
new file mode 100644
index 0000000..d400bf6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/JavaMethodContext.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import jdk.vm.ci.meta.JavaMethod;
+
+/**
+ * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a
+ * {@link JavaMethod}.
+ */
+public interface JavaMethodContext {
+    JavaMethod asJavaMethod();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java
new file mode 100644
index 0000000..f7b9420
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * A utility for printing compiler debug and informational output to an output stream.
+ *
+ * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying
+ * output stream every time one of the {@code println} methods is invoked, or a newline character (
+ * {@code '\n'}) is written.
+ *
+ * All of the {@code print} and {@code println} methods return the {code LogStream} instance on
+ * which they were invoked. This allows chaining of these calls to mitigate use of String
+ * concatenation by the caller.
+ *
+ * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. Each
+ * line of output written to this stream has {@code n} spaces prefixed to it where {@code n} is the
+ * value that would be returned by {@link #indentationLevel()} when the first character of a new
+ * line is written.
+ *
+ * A {@code LogStream} maintains a current {@linkplain #position() position} for the current line
+ * being written. This position can be advanced to a specified position by
+ * {@linkplain #fillTo(int, char) filling} this stream with a given character.
+ */
+public class LogStream {
+
+    /**
+     * Null output stream that simply swallows any output sent to it.
+     */
+    public static final LogStream SINK = new LogStream();
+
+    private static final PrintStream SINK_PS = new PrintStream(new OutputStream() {
+
+        @Override
+        public void write(int b) throws IOException {
+        }
+    });
+
+    private LogStream() {
+        this.ps = null;
+        this.lineBuffer = null;
+    }
+
+    /**
+     * The output stream to which this log stream writes.
+     */
+    private final PrintStream ps;
+
+    private final StringBuilder lineBuffer;
+    private int indentationLevel;
+    private char indentation = ' ';
+    private boolean indentationDisabled;
+
+    public final PrintStream out() {
+        if (ps == null) {
+            return SINK_PS;
+        }
+        return ps;
+    }
+
+    /**
+     * The system dependent line separator.
+     */
+    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /**
+     * Creates a new log stream.
+     *
+     * @param os the underlying output stream to which prints are sent
+     */
+    public LogStream(OutputStream os) {
+        ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os);
+        lineBuffer = new StringBuilder(100);
+    }
+
+    /**
+     * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given
+     * {@link LogStream}.
+     *
+     * @param log a LogStream whose output stream is shared with this one
+     */
+    public LogStream(LogStream log) {
+        ps = log.ps;
+        lineBuffer = new StringBuilder(100);
+    }
+
+    /**
+     * Prepends {@link #indentation} to the current output line until its write position is equal to
+     * the current {@linkplain #indentationLevel()} level.
+     */
+    private void indent() {
+        if (ps != null) {
+            if (!indentationDisabled && indentationLevel != 0) {
+                while (lineBuffer.length() < indentationLevel) {
+                    lineBuffer.append(indentation);
+                }
+            }
+        }
+    }
+
+    private LogStream flushLine(boolean withNewline) {
+        if (ps != null) {
+            if (withNewline) {
+                lineBuffer.append(LINE_SEPARATOR);
+            }
+            ps.print(lineBuffer.toString());
+            ps.flush();
+            lineBuffer.setLength(0);
+        }
+        return this;
+    }
+
+    /**
+     * Flushes the stream. This is done by terminating the current line if it is not at position 0
+     * and then flushing the underlying output stream.
+     */
+    public void flush() {
+        if (ps != null) {
+            if (lineBuffer.length() != 0) {
+                flushLine(false);
+            }
+            ps.flush();
+        }
+    }
+
+    /**
+     * Gets the current column position of this log stream.
+     *
+     * @return the current column position of this log stream
+     */
+    public int position() {
+        return lineBuffer == null ? 0 : lineBuffer.length();
+
+    }
+
+    /**
+     * Gets the current indentation level for this log stream.
+     *
+     * @return the current indentation level for this log stream.
+     */
+    public int indentationLevel() {
+        return indentationLevel;
+    }
+
+    /**
+     * Adjusts the current indentation level of this log stream.
+     *
+     * @param delta
+     */
+    public void adjustIndentation(int delta) {
+        if (delta < 0) {
+            indentationLevel = Math.max(0, indentationLevel + delta);
+        } else {
+            indentationLevel += delta;
+        }
+    }
+
+    /**
+     * Gets the current indentation character of this log stream.
+     */
+    public char indentation() {
+        return indentation;
+    }
+
+    public void disableIndentation() {
+        indentationDisabled = true;
+    }
+
+    public void enableIndentation() {
+        indentationDisabled = false;
+    }
+
+    /**
+     * Sets the character used for indentation.
+     */
+    public void setIndentation(char c) {
+        indentation = c;
+    }
+
+    /**
+     * Advances this stream's {@linkplain #position() position} to a given position by repeatedly
+     * appending a given character as necessary.
+     *
+     * @param position the position to which this stream's position will be advanced
+     * @param filler the character used to pad the stream
+     */
+    public LogStream fillTo(int position, char filler) {
+        if (ps != null) {
+            indent();
+            while (lineBuffer.length() < position) {
+                lineBuffer.append(filler);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a boolean value to this stream as {@code "true"} or {@code "false"}.
+     *
+     * @param b the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(boolean b) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(b);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param b the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(boolean b) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(b);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a character value to this stream.
+     *
+     * @param c the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(char c) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(c);
+            if (c == '\n') {
+                if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) {
+                    flushLine(false);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param c the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(char c) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(c);
+            flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Prints an int value.
+     *
+     * @param i the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(int i) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(i);
+        }
+        return this;
+    }
+
+    /**
+     * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
+     *
+     * @param i the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(int i) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(i);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a float value to this stream.
+     *
+     * @param f the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(float f) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(f);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}
+     * .
+     *
+     * @param f the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(float f) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(f);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a long value to this stream.
+     *
+     * @param l the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(long l) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(l);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
+     *
+     * @param l the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(long l) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(l);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a double value to this stream.
+     *
+     * @param d the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(double d) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(d);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param d the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(double d) {
+        if (ps != null) {
+            indent();
+            lineBuffer.append(d);
+            return flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@code String} value to this stream. This method ensures that the
+     * {@linkplain #position() position} of this stream is updated correctly with respect to any
+     * {@linkplain #LINE_SEPARATOR line separators} present in {@code s}.
+     *
+     * @param s the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream print(String s) {
+        if (ps != null) {
+            if (s == null) {
+                indent();
+                lineBuffer.append(s);
+                return this;
+            }
+
+            int index = 0;
+            int next = s.indexOf(LINE_SEPARATOR, index);
+            while (index < s.length()) {
+                indent();
+                if (next > index || next == 0) {
+                    lineBuffer.append(s.substring(index, next));
+                    flushLine(true);
+                    index = next + LINE_SEPARATOR.length();
+                    next = s.indexOf(LINE_SEPARATOR, index);
+                } else {
+                    lineBuffer.append(s.substring(index));
+                    break;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line
+     * separator}.
+     *
+     * @param s the value to be printed
+     * @return this {@link LogStream} instance
+     */
+    public LogStream println(String s) {
+        if (ps != null) {
+            print(s);
+            flushLine(true);
+        }
+        return this;
+    }
+
+    /**
+     * Writes a formatted string to this stream.
+     *
+     * @param format a format string as described in {@link String#format(String, Object...)}
+     * @param args the arguments to be formatted
+     * @return this {@link LogStream} instance
+     */
+    public LogStream printf(String format, Object... args) {
+        if (ps != null) {
+            print(String.format(format, args));
+        }
+        return this;
+    }
+
+    /**
+     * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream.
+     *
+     * @return this {@code LogStream} instance
+     */
+    public LogStream println() {
+        if (ps != null) {
+            indent();
+            flushLine(true);
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java
new file mode 100644
index 0000000..5f81841
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import static java.lang.Thread.currentThread;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+
+import javax.management.ObjectName;
+
+public class Management {
+
+    private static final com.sun.management.ThreadMXBean threadMXBean = Management.initThreadMXBean();
+
+    /**
+     * The amount of memory allocated by
+     * {@link com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)} itself.
+     */
+    private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes();
+
+    public static long getCurrentThreadAllocatedBytes() {
+        return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead;
+    }
+
+    private static com.sun.management.ThreadMXBean initThreadMXBean() {
+        try {
+            return (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
+        } catch (Error err) {
+            return new UnimplementedBean();
+        }
+    }
+
+    public static ThreadMXBean getThreadMXBean() {
+        return threadMXBean;
+    }
+
+    private static class UnimplementedBean implements ThreadMXBean, com.sun.management.ThreadMXBean {
+
+        @Override
+        public ObjectName getObjectName() {
+            return null;
+        }
+
+        @Override
+        public long getThreadAllocatedBytes(long arg0) {
+            return 0;
+        }
+
+        @Override
+        public long[] getThreadAllocatedBytes(long[] arg0) {
+            return null;
+        }
+
+        @Override
+        public long[] getThreadCpuTime(long[] arg0) {
+            return null;
+        }
+
+        @Override
+        public long[] getThreadUserTime(long[] arg0) {
+            return null;
+        }
+
+        @Override
+        public boolean isThreadAllocatedMemoryEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isThreadAllocatedMemorySupported() {
+            return false;
+        }
+
+        @Override
+        public void setThreadAllocatedMemoryEnabled(boolean arg0) {
+        }
+
+        @Override
+        public int getThreadCount() {
+            return 0;
+        }
+
+        @Override
+        public int getPeakThreadCount() {
+            return 0;
+        }
+
+        @Override
+        public long getTotalStartedThreadCount() {
+            return 0;
+        }
+
+        @Override
+        public int getDaemonThreadCount() {
+            return 0;
+        }
+
+        @Override
+        public long[] getAllThreadIds() {
+            return null;
+        }
+
+        @Override
+        public ThreadInfo getThreadInfo(long id) {
+            return null;
+        }
+
+        @Override
+        public ThreadInfo[] getThreadInfo(long[] ids) {
+            return null;
+        }
+
+        @Override
+        public ThreadInfo getThreadInfo(long id, int maxDepth) {
+            return null;
+        }
+
+        @Override
+        public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) {
+            return null;
+        }
+
+        @Override
+        public boolean isThreadContentionMonitoringSupported() {
+            return false;
+        }
+
+        @Override
+        public boolean isThreadContentionMonitoringEnabled() {
+            return false;
+        }
+
+        @Override
+        public void setThreadContentionMonitoringEnabled(boolean enable) {
+        }
+
+        @Override
+        public long getCurrentThreadCpuTime() {
+            return 0;
+        }
+
+        @Override
+        public long getCurrentThreadUserTime() {
+            return 0;
+        }
+
+        @Override
+        public long getThreadCpuTime(long id) {
+            return 0;
+        }
+
+        @Override
+        public long getThreadUserTime(long id) {
+            return 0;
+        }
+
+        @Override
+        public boolean isThreadCpuTimeSupported() {
+            return false;
+        }
+
+        @Override
+        public boolean isCurrentThreadCpuTimeSupported() {
+            return false;
+        }
+
+        @Override
+        public boolean isThreadCpuTimeEnabled() {
+            return false;
+        }
+
+        @Override
+        public void setThreadCpuTimeEnabled(boolean enable) {
+        }
+
+        @Override
+        public long[] findMonitorDeadlockedThreads() {
+            return null;
+        }
+
+        @Override
+        public void resetPeakThreadCount() {
+        }
+
+        @Override
+        public long[] findDeadlockedThreads() {
+            return null;
+        }
+
+        @Override
+        public boolean isObjectMonitorUsageSupported() {
+            return false;
+        }
+
+        @Override
+        public boolean isSynchronizerUsageSupported() {
+            return false;
+        }
+
+        @Override
+        public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) {
+            return null;
+        }
+
+        @Override
+        public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) {
+            return null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java
new file mode 100644
index 0000000..8ea958a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * This class implements a method filter that can filter based on class name, method name and
+ * parameters. The syntax for the source pattern that is passed to the constructor is as follows:
+ *
+ * <pre>
+ * SourcePatterns = SourcePattern ["," SourcePatterns] .
+ * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
+ * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
+ * Class = { package "." } class .
+ * </pre>
+ *
+ *
+ * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid
+ * filters are:
+ *
+ * <ul>
+ * <li>
+ *
+ * <pre>
+ * visit(Argument;BlockScope)
+ * </pre>
+ *
+ * Matches all methods named "visit", with the first parameter of type "Argument", and the second
+ * parameter of type "BlockScope". The packages of the parameter types are irrelevant.</li>
+ * <li>
+ *
+ * <pre>
+ * arraycopy(Object;;;;)
+ * </pre>
+ *
+ * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more
+ * parameters of any type. The packages of the parameter types are irrelevant.</li>
+ * <li>
+ *
+ * <pre>
+ * org.graalvm.compiler.core.graph.PostOrderNodeIterator.*
+ * </pre>
+ *
+ * Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator".</li>
+ * <li>
+ *
+ * <pre>
+ * *
+ * </pre>
+ *
+ * Matches all methods in all classes</li>
+ * <li>
+ *
+ * <pre>
+ * org.graalvm.compiler.core.graph.*.visit
+ * </pre>
+ *
+ * Matches all methods named "visit" in classes in the package "org.graalvm.compiler.core.graph".
+ * <li>
+ *
+ * <pre>
+ * arraycopy,toString
+ * </pre>
+ *
+ * Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an <i>or</i>
+ * operator.</li>
+ * </ul>
+ */
+public class MethodFilter {
+
+    private final Pattern clazz;
+    private final Pattern methodName;
+    private final Pattern[] signature;
+
+    /**
+     * Parses a string containing list of comma separated filter patterns into an array of
+     * {@link MethodFilter}s.
+     */
+    public static MethodFilter[] parse(String commaSeparatedPatterns) {
+        String[] filters = commaSeparatedPatterns.split(",");
+        MethodFilter[] methodFilters = new MethodFilter[filters.length];
+        for (int i = 0; i < filters.length; i++) {
+            methodFilters[i] = new MethodFilter(filters[i]);
+        }
+        return methodFilters;
+    }
+
+    /**
+     * Determines if a given method is matched by a given array of filters.
+     */
+    public static boolean matches(MethodFilter[] filters, JavaMethod method) {
+        for (MethodFilter filter : filters) {
+            if (filter.matches(method)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines if a given class name is matched by a given array of filters.
+     */
+    public static boolean matchesClassName(MethodFilter[] filters, String className) {
+        for (MethodFilter filter : filters) {
+            if (filter.matchesClassName(className)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public MethodFilter(String sourcePattern) {
+        String pattern = sourcePattern.trim();
+
+        // extract parameter part
+        int pos = pattern.indexOf('(');
+        if (pos != -1) {
+            if (pattern.charAt(pattern.length() - 1) != ')') {
+                throw new IllegalArgumentException("missing ')' at end of method filter pattern: " + pattern);
+            }
+            String[] signatureClasses = pattern.substring(pos + 1, pattern.length() - 1).split(";", -1);
+            signature = new Pattern[signatureClasses.length];
+            for (int i = 0; i < signatureClasses.length; i++) {
+                signature[i] = createClassGlobPattern(signatureClasses[i].trim());
+            }
+            pattern = pattern.substring(0, pos);
+        } else {
+            signature = null;
+        }
+
+        // If there is at least one "." then everything before the last "." is the class name.
+        // Otherwise, the pattern contains only the method name.
+        pos = pattern.lastIndexOf('.');
+        if (pos != -1) {
+            clazz = createClassGlobPattern(pattern.substring(0, pos));
+            methodName = Pattern.compile(createGlobString(pattern.substring(pos + 1)));
+        } else {
+            clazz = null;
+            methodName = Pattern.compile(createGlobString(pattern));
+        }
+    }
+
+    public static String createGlobString(String pattern) {
+        return Pattern.quote(pattern).replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q");
+    }
+
+    private static Pattern createClassGlobPattern(String pattern) {
+        if (pattern.length() == 0) {
+            return null;
+        } else if (pattern.contains(".")) {
+            return Pattern.compile(createGlobString(pattern));
+        } else {
+            return Pattern.compile("([^\\.\\$]*[\\.\\$])*" + createGlobString(pattern));
+        }
+    }
+
+    public boolean hasSignature() {
+        return signature != null;
+    }
+
+    /**
+     * Determines if the class part of this filter matches a given class name.
+     */
+    public boolean matchesClassName(String className) {
+        return clazz == null || clazz.matcher(className).matches();
+    }
+
+    public boolean matches(JavaMethod o) {
+        // check method name first, since MetaUtil.toJavaName is expensive
+        if (methodName != null && !methodName.matcher(o.getName()).matches()) {
+            return false;
+        }
+        if (clazz != null && !clazz.matcher(o.getDeclaringClass().toJavaName()).matches()) {
+            return false;
+        }
+        return matchesSignature(o.getSignature());
+    }
+
+    private boolean matchesSignature(Signature sig) {
+        if (signature == null) {
+            return true;
+        }
+        if (sig.getParameterCount(false) != signature.length) {
+            return false;
+        }
+        for (int i = 0; i < signature.length; i++) {
+            JavaType type = sig.getParameterType(i, null);
+            String javaName = type.toJavaName();
+            if (signature[i] != null && !signature[i].matcher(javaName).matches()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean matches(String javaClassName, String name, Signature sig) {
+        assert sig != null || signature == null;
+        // check method name first, since MetaUtil.toJavaName is expensive
+        if (methodName != null && !methodName.matcher(name).matches()) {
+            return false;
+        }
+        if (clazz != null && !clazz.matcher(javaClassName).matches()) {
+            return false;
+        }
+        return matchesSignature(sig);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("MethodFilter[");
+        String sep = "";
+        if (clazz != null) {
+            buf.append(sep).append("clazz=").append(clazz);
+            sep = ", ";
+        }
+        if (methodName != null) {
+            buf.append(sep).append("methodName=").append(methodName);
+            sep = ", ";
+        }
+        if (signature != null) {
+            buf.append(sep).append("signature=").append(Arrays.toString(signature));
+            sep = ", ";
+        }
+        return buf.append("]").toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java
new file mode 100644
index 0000000..f7bc3d7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+/**
+ * A collection of static methods for printing debug and informational output to a global
+ * {@link LogStream}. The output can be (temporarily) suppressed per thread through use of a
+ * {@linkplain Filter filter}.
+ */
+public class TTY {
+
+    /**
+     * Support for thread-local suppression of {@link TTY}.
+     */
+    public static class Filter {
+
+        private LogStream previous;
+        private final Thread thread = Thread.currentThread();
+
+        /**
+         * Creates an object that will suppress {@link TTY} for the current thread if the given
+         * filter does not match the given object. To revert the suppression state to how it was
+         * before this call, the {@link #remove()} method must be called on the suppression object.
+         *
+         * @param filter the pattern for matching. If {@code null}, then the match is successful. If
+         *            it starts with "~", then a regular expression
+         *            {@linkplain Pattern#matches(String, CharSequence) match} is performed where
+         *            the regular expression is specified by {@code filter} without the "~" prefix.
+         *            Otherwise, a simple {@linkplain String#contains(CharSequence) substring} match
+         *            is performed where {@code filter} is the substring used.
+         * @param object an object whose {@linkplain Object#toString() string} value is matched
+         *            against {@code filter}
+         */
+        public Filter(String filter, Object object) {
+            boolean suppressed = false;
+            if (filter != null) {
+                String input = object.toString();
+                if (filter.startsWith("~")) {
+                    suppressed = !Pattern.matches(filter.substring(1), input);
+                } else {
+                    suppressed = !input.contains(filter);
+                }
+                if (suppressed) {
+                    previous = out();
+                    log.set(LogStream.SINK);
+                }
+            }
+        }
+
+        /**
+         * Creates an object that will suppress {@link TTY} for the current thread. To revert the
+         * suppression state to how it was before this call, the {@link #remove()} method must be
+         * called on this filter object.
+         */
+        public Filter() {
+            previous = out();
+            log.set(LogStream.SINK);
+        }
+
+        /**
+         * Reverts the suppression state of {@link TTY} to how it was before this object was
+         * constructed.
+         */
+        public void remove() {
+            assert thread == Thread.currentThread();
+            if (previous != null) {
+                log.set(previous);
+            }
+        }
+    }
+
+    /**
+     * The {@link PrintStream} to which all non-suppressed output from {@link TTY} is written.
+     */
+    public static final PrintStream out;
+    static {
+        TTYStreamProvider p = GraalServices.loadSingle(TTYStreamProvider.class, false);
+        out = p == null ? System.out : p.getStream();
+    }
+
+    private static final ThreadLocal<LogStream> log = new ThreadLocal<LogStream>() {
+
+        @Override
+        protected LogStream initialValue() {
+            return new LogStream(out);
+        }
+    };
+
+    public static boolean isSuppressed() {
+        return log.get() == LogStream.SINK;
+    }
+
+    /**
+     * Gets the thread-local log stream to which the static methods of this class send their output.
+     * This will either be a global log stream or the global {@linkplain LogStream#SINK sink}
+     * depending on whether any suppression {@linkplain Filter filters} are in effect for the
+     * current thread.
+     */
+    public static LogStream out() {
+        return log.get();
+    }
+
+    /**
+     * @see LogStream#print(String)
+     */
+    public static void print(String s) {
+        out().print(s);
+    }
+
+    /**
+     * @see LogStream#print(int)
+     */
+    public static void print(int i) {
+        out().print(i);
+    }
+
+    /**
+     * @see LogStream#print(long)
+     */
+    public static void print(long i) {
+        out().print(i);
+    }
+
+    /**
+     * @see LogStream#print(char)
+     */
+    public static void print(char c) {
+        out().print(c);
+    }
+
+    /**
+     * @see LogStream#print(boolean)
+     */
+    public static void print(boolean b) {
+        out().print(b);
+    }
+
+    /**
+     * @see LogStream#print(double)
+     */
+    public static void print(double d) {
+        out().print(d);
+    }
+
+    /**
+     * @see LogStream#print(float)
+     */
+    public static void print(float f) {
+        out().print(f);
+    }
+
+    /**
+     * @see LogStream#println(String)
+     */
+    public static void println(String s) {
+        out().println(s);
+    }
+
+    /**
+     * @see LogStream#println()
+     */
+    public static void println() {
+        out().println();
+    }
+
+    /**
+     * @see LogStream#println(int)
+     */
+    public static void println(int i) {
+        out().println(i);
+    }
+
+    /**
+     * @see LogStream#println(long)
+     */
+    public static void println(long l) {
+        out().println(l);
+    }
+
+    /**
+     * @see LogStream#println(char)
+     */
+    public static void println(char c) {
+        out().println(c);
+    }
+
+    /**
+     * @see LogStream#println(boolean)
+     */
+    public static void println(boolean b) {
+        out().println(b);
+    }
+
+    /**
+     * @see LogStream#println(double)
+     */
+    public static void println(double d) {
+        out().println(d);
+    }
+
+    /**
+     * @see LogStream#println(float)
+     */
+    public static void println(float f) {
+        out().println(f);
+    }
+
+    public static void printf(String format, Object... args) {
+        out().printf(format, args);
+    }
+
+    public static void println(String format, Object... args) {
+        out().printf(format + "%n", args);
+    }
+
+    public static void fillTo(int i) {
+        out().fillTo(i, ' ');
+    }
+
+    public static void printFields(Class<?> javaClass) {
+        final String className = javaClass.getSimpleName();
+        TTY.println(className + " {");
+        for (final Field field : javaClass.getFields()) {
+            printField(field, false);
+        }
+        TTY.println("}");
+    }
+
+    public static void printField(final Field field, boolean tabbed) {
+        final String fieldName = String.format("%35s", field.getName());
+        try {
+            String prefix = tabbed ? "" : "    " + fieldName + " = ";
+            String postfix = tabbed ? "\t" : "\n";
+            if (field.getType() == int.class) {
+                TTY.print(prefix + field.getInt(null) + postfix);
+            } else if (field.getType() == boolean.class) {
+                TTY.print(prefix + field.getBoolean(null) + postfix);
+            } else if (field.getType() == float.class) {
+                TTY.print(prefix + field.getFloat(null) + postfix);
+            } else if (field.getType() == String.class) {
+                TTY.print(prefix + field.get(null) + postfix);
+            } else if (field.getType() == Map.class) {
+                Map<?, ?> m = (Map<?, ?>) field.get(null);
+                TTY.print(prefix + printMap(m) + postfix);
+            } else {
+                TTY.print(prefix + field.get(null) + postfix);
+            }
+        } catch (IllegalAccessException e) {
+            // do nothing.
+        }
+    }
+
+    private static String printMap(Map<?, ?> m) {
+        StringBuilder sb = new StringBuilder();
+
+        List<String> keys = new ArrayList<>();
+        for (Object key : m.keySet()) {
+            keys.add((String) key);
+        }
+        Collections.sort(keys);
+
+        for (String key : keys) {
+            sb.append(key);
+            sb.append("\t");
+            sb.append(m.get(key));
+            sb.append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    public static void flush() {
+        out().flush();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTYStreamProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTYStreamProvider.java
new file mode 100644
index 0000000..530b129
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTYStreamProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.io.PrintStream;
+
+/**
+ * Provides a {@link PrintStream} that writes to the underlying log stream of the VM.
+ */
+public interface TTYStreamProvider {
+    PrintStream getStream();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java
new file mode 100644
index 0000000..8933be0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+import java.lang.management.ThreadMXBean;
+
+/**
+ * A consistent source of timing data that should be used by all facilities in the debug package.
+ */
+public class TimeSource {
+    private static final boolean USING_BEAN;
+    private static final ThreadMXBean threadMXBean;
+
+    static {
+        threadMXBean = Management.getThreadMXBean();
+        if (threadMXBean.isThreadCpuTimeSupported()) {
+            USING_BEAN = true;
+        } else {
+            USING_BEAN = false;
+        }
+    }
+
+    /**
+     * Gets the current time of this thread in nanoseconds from the most accurate timer available on
+     * the system. The returned value will be the current time in nanoseconds precision but not
+     * necessarily nanoseconds accuracy.
+     * <p>
+     * The intended use case of this method is to measure the time a certain action takes by making
+     * successive calls to it. It should not be used to measure total times in the sense of a time
+     * stamp.
+     *
+     * @return the current thread's time in nanoseconds
+     */
+    public static long getTimeNS() {
+        return USING_BEAN ? threadMXBean.getCurrentThreadCpuTime() : System.nanoTime();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TopLevelDebugConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TopLevelDebugConfig.java
new file mode 100644
index 0000000..dc692f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TopLevelDebugConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+/**
+ * A marker class for a scoped debug configuration covering a compilation region. Useful for
+ * programmatically enabling debug config features.
+ *
+ */
+public class TopLevelDebugConfig extends DelegatingDebugConfig {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/AccumulatedDebugValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/AccumulatedDebugValue.java
new file mode 100644
index 0000000..e502753
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/AccumulatedDebugValue.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+public abstract class AccumulatedDebugValue extends DebugValue {
+    protected final DebugValue flat;
+
+    public AccumulatedDebugValue(String name, boolean conditional, DebugValue flat) {
+        super(name + "_Accm", conditional);
+        this.flat = flat;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CloseableCounterImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CloseableCounterImpl.java
new file mode 100644
index 0000000..b3ca4b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CloseableCounterImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import org.graalvm.compiler.debug.DebugCloseable;
+
+/**
+ * A helper class for DebugValues that can nest and need to split out accumulated and flat values
+ * for some kind of counter-like measurement.
+ */
+abstract class CloseableCounterImpl implements DebugCloseable {
+
+    protected final CloseableCounterImpl parent;
+    protected final AccumulatedDebugValue counter;
+    protected final long start;
+    protected long nestedAmountToSubtract;
+
+    CloseableCounterImpl(CloseableCounterImpl parent, AccumulatedDebugValue counter) {
+        this.parent = parent;
+        this.start = getCounterValue();
+        this.counter = counter;
+    }
+
+    /**
+     * A hook for subclasses. Lets them perform custom operations with the value since the last
+     * invocation of {@link CloseableCounterImpl#close()} of this accumulated
+     * {@link CloseableCounterImpl#counter}.
+     *
+     * @param difference since the last invocation of this counter flat
+     */
+    protected void interceptDifferenceAccm(long difference) {
+        // hook for subclasses
+    }
+
+    /**
+     * A hook for subclasses. Lets them perform custom operations with the value since the last
+     * invocation of {@link CloseableCounterImpl#close()} of this flat
+     * {@link CloseableCounterImpl#counter}.
+     *
+     * @param difference since the last invocation of this counter flat
+     */
+    protected void interceptDifferenceFlat(long difference) {
+        // hook for subclasses
+    }
+
+    @Override
+    public void close() {
+        long end = getCounterValue();
+        long difference = end - start;
+        if (parent != null) {
+            if (!counter.getName().equals(parent.counter.getName())) {
+                parent.nestedAmountToSubtract += difference;
+                // Look for our counter in an outer scope and fix up
+                // the adjustment to the flat count
+                CloseableCounterImpl ancestor = parent.parent;
+                while (ancestor != null) {
+                    if (ancestor.counter.getName().equals(counter.getName())) {
+                        ancestor.nestedAmountToSubtract -= difference;
+                        break;
+                    }
+                    ancestor = ancestor.parent;
+                }
+            }
+        }
+        long flatAmount = difference - nestedAmountToSubtract;
+        counter.addToCurrentValue(difference);
+        counter.flat.addToCurrentValue(flatAmount);
+        interceptDifferenceAccm(difference);
+        interceptDifferenceFlat(flatAmount);
+    }
+
+    abstract long getCounterValue();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CounterImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CounterImpl.java
new file mode 100644
index 0000000..5732cff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/CounterImpl.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+
+public abstract class CounterImpl extends DebugValue implements DebugCounter {
+
+    public CounterImpl(String name, boolean conditional) {
+        super(name, conditional);
+        if (isEnabled()) {
+            // Allows for zero counters to be shown
+            getCurrentValue();
+        }
+    }
+
+    @Override
+    public void increment() {
+        add(1);
+    }
+
+    @Override
+    public String rawUnit() {
+        return "";
+    }
+
+    @Override
+    public String toRawString(long value) {
+        return Long.toString(value);
+    }
+
+    @Override
+    public String toString(long value) {
+        return Long.toString(value);
+    }
+
+    private static final class InterceptingCounterImpl extends CounterImpl {
+
+        private InterceptingCounterImpl(String name, boolean conditional) {
+            super(name, conditional);
+        }
+
+        @Override
+        public void add(long value) {
+            if (isEnabled()) {
+                if (Debug.isMethodMeterEnabled()) {
+                    MethodMetricsImpl.addToCurrentScopeMethodMetrics(getName(), value);
+                }
+                super.addToCurrentValue(value);
+            }
+        }
+    }
+
+    private static final class PlainCounterImpl extends CounterImpl {
+
+        private PlainCounterImpl(String name, boolean conditional) {
+            super(name, conditional);
+        }
+
+        @Override
+        public void add(long value) {
+            if (isEnabled()) {
+                super.addToCurrentValue(value);
+            }
+        }
+    }
+
+    public static DebugCounter create(String name, boolean conditional, boolean intercepting) {
+        if (intercepting) {
+            return new InterceptingCounterImpl(name, conditional);
+        }
+        return new PlainCounterImpl(name, conditional);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramAsciiPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramAsciiPrinter.java
new file mode 100644
index 0000000..7c71515
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramAsciiPrinter.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.debug.DebugHistogram;
+import org.graalvm.compiler.debug.DebugHistogram.CountedValue;
+import org.graalvm.compiler.debug.DebugHistogram.Printer;
+
+/**
+ * Renders a textual representation of a histogram to a given print stream.
+ */
+public class DebugHistogramAsciiPrinter implements Printer {
+
+    public static final int NumberSize = 10;
+    public static final int DefaultNameSize = 50;
+    public static final int DefaultBarSize = 100;
+    public static final int DefaultScale = 1;
+
+    private final PrintStream os;
+    private final int limit;
+    private final int nameSize;
+    private final int barSize;
+    private final int scale;
+
+    public DebugHistogramAsciiPrinter(PrintStream os) {
+        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize, DefaultScale);
+    }
+
+    /**
+     * @param os where to print
+     * @param limit limits printing to the {@code limit} most frequent values
+     * @param nameSize the width of the value names column
+     * @param barSize the width of the value frequency column
+     * @param scale a factor by which every result is divided
+     */
+    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize, int scale) {
+        this.os = os;
+        this.limit = limit;
+        this.nameSize = nameSize;
+        this.barSize = barSize;
+        this.scale = scale;
+    }
+
+    @Override
+    public void print(DebugHistogram histogram) {
+        List<CountedValue> list = histogram.getValues();
+        if (list.isEmpty()) {
+            os.printf("%s is empty.%n", histogram.getName());
+            return;
+        }
+
+        // Sum up the total number of elements.
+        long total = list.stream().mapToLong(CountedValue::getCount).sum();
+
+        // Print header.
+        os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total / scale);
+
+        long max = list.get(0).getCount() / scale;
+        final int lineSize = nameSize + NumberSize + barSize + 10;
+        printLine(os, '-', lineSize);
+        String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            long value = cv.getCount() / scale;
+            char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
+            Arrays.fill(bar, '=');
+            String objectString = String.valueOf(cv.getValue());
+            if (objectString.length() > nameSize) {
+                objectString = objectString.substring(0, nameSize - 3) + "...";
+            }
+            os.printf(formatString, objectString, value, new String(bar));
+        }
+        printLine(os, '-', lineSize);
+    }
+
+    private static void printLine(PrintStream printStream, char c, int lineSize) {
+        char[] charArr = new char[lineSize];
+        Arrays.fill(charArr, c);
+        printStream.printf("%s%n", new String(charArr));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramImpl.java
new file mode 100644
index 0000000..1348cc3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramImpl.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import org.graalvm.compiler.debug.DebugHistogram;
+
+public class DebugHistogramImpl implements DebugHistogram {
+
+    private final String name;
+    private HashMap<Object, CountedValue> map = new HashMap<>();
+
+    public DebugHistogramImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void add(Object value) {
+        CountedValue cv = map.get(value);
+        if (cv == null) {
+            map.put(value, new CountedValue(1, value));
+        } else {
+            cv.inc();
+        }
+    }
+
+    @Override
+    public void add(Object value, long count) {
+        CountedValue cv = map.get(value);
+        if (cv == null) {
+            map.put(value, new CountedValue(count, value));
+        } else {
+            cv.add(count);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public List<CountedValue> getValues() {
+        ArrayList<CountedValue> res = new ArrayList<>(map.values());
+        Collections.sort(res);
+        return res;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramRPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramRPrinter.java
new file mode 100644
index 0000000..a2ee811
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugHistogramRPrinter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.io.PrintStream;
+import java.util.List;
+
+import org.graalvm.compiler.debug.DebugHistogram;
+import org.graalvm.compiler.debug.DebugHistogram.CountedValue;
+import org.graalvm.compiler.debug.DebugHistogram.Printer;
+
+/**
+ * Renders a histogram as an R script to a given print stream. The R script emitted for a histogram
+ * is a simple set of statements for defining a vector of named objects.
+ */
+public class DebugHistogramRPrinter implements Printer {
+
+    private PrintStream os;
+    private int limit;
+
+    public DebugHistogramRPrinter(PrintStream os) {
+        this(os, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @param os where to print
+     * @param limit limits printing to the {@code limit} most frequent values
+     */
+    public DebugHistogramRPrinter(PrintStream os, int limit) {
+        this.os = os;
+        this.limit = limit;
+    }
+
+    @Override
+    public void print(DebugHistogram histogram) {
+        List<CountedValue> list = histogram.getValues();
+        if (list.isEmpty()) {
+            return;
+        }
+
+        String var = histogram.getName().replace('-', '.').replace(' ', '_');
+        os.print(var + " <- c(");
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            if (i != 0) {
+                os.print(", ");
+            }
+            os.print(cv.getCount());
+        }
+        os.println(");");
+
+        os.print("names(" + var + ") <- c(");
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            if (i != 0) {
+                os.print(", ");
+            }
+            os.print("\"" + cv.getValue() + "\"");
+        }
+        os.println(");");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java
new file mode 100644
index 0000000..3526125
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugVerifyHandler;
+import org.graalvm.compiler.debug.DelegatingDebugConfig;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.debug.JavaMethodContext;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.TopLevelDebugConfig;
+
+import jdk.vm.ci.meta.JavaMethod;
+
+public final class DebugScope implements Debug.Scope {
+
+    private final class IndentImpl implements Indent {
+
+        private static final String INDENTATION_INCREMENT = "  ";
+
+        final String indent;
+        final IndentImpl parentIndent;
+
+        IndentImpl(IndentImpl parentIndent) {
+            this.parentIndent = parentIndent;
+            this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT);
+        }
+
+        private boolean logScopeName() {
+            return logScopeName;
+        }
+
+        private void printScopeName(StringBuilder str, boolean isCurrent) {
+            if (logScopeName) {
+                boolean parentPrinted = false;
+                if (parentIndent != null) {
+                    parentPrinted = parentIndent.logScopeName();
+                    parentIndent.printScopeName(str, false);
+                }
+                /*
+                 * Always print the current scope, scopes with context and the any scope whose
+                 * parent didn't print. This ensure the first new scope always shows up.
+                 */
+                if (isCurrent || printContext(null) != 0 || !parentPrinted) {
+                    str.append(indent).append("[thread:").append(Thread.currentThread().getId()).append("] scope: ").append(getQualifiedName()).append(System.lineSeparator());
+                }
+                printContext(str);
+                logScopeName = false;
+            }
+        }
+
+        /**
+         * Print or count the context objects for the current scope.
+         */
+        private int printContext(StringBuilder str) {
+            int count = 0;
+            if (context != null && context.length > 0) {
+                // Include some context in the scope output
+                for (Object contextObj : context) {
+                    if (contextObj instanceof JavaMethodContext || contextObj instanceof JavaMethod) {
+                        if (str != null) {
+                            str.append(indent).append("Context: ").append(contextObj).append(System.lineSeparator());
+                        }
+                        count++;
+                    }
+                }
+            }
+            return count;
+        }
+
+        public void log(int logLevel, String msg, Object... args) {
+            if (isLogEnabled(logLevel)) {
+                StringBuilder str = new StringBuilder();
+                printScopeName(str, true);
+                str.append(indent);
+                String result = args.length == 0 ? msg : String.format(msg, args);
+                String lineSep = System.lineSeparator();
+                str.append(result.replace(lineSep, lineSep.concat(indent)));
+                str.append(lineSep);
+                output.append(str);
+                lastUsedIndent = this;
+            }
+        }
+
+        IndentImpl indent() {
+            lastUsedIndent = new IndentImpl(this);
+            return lastUsedIndent;
+        }
+
+        @Override
+        public void close() {
+            if (parentIndent != null) {
+                lastUsedIndent = parentIndent;
+            }
+        }
+    }
+
+    /**
+     * Interface for an additional information object per scope. The information object will be
+     * given to child scopes, but can be explicitly set with
+     * {@link DebugScope#enhanceWithExtraInfo(CharSequence, ExtraInfo, boolean, Object...)}
+     */
+    public interface ExtraInfo {
+
+    }
+
+    private static final ThreadLocal<DebugScope> instanceTL = new ThreadLocal<>();
+    private static final ThreadLocal<DebugScope> lastClosedTL = new ThreadLocal<>();
+    private static final ThreadLocal<DebugConfig> configTL = new ThreadLocal<>();
+    private static final ThreadLocal<Throwable> lastExceptionThrownTL = new ThreadLocal<>();
+
+    private final DebugScope parent;
+    private final DebugConfig parentConfig;
+    private final boolean sandbox;
+    private IndentImpl lastUsedIndent;
+    private boolean logScopeName;
+
+    private final Object[] context;
+
+    private DebugValueMap valueMap;
+
+    private String qualifiedName;
+    private final String unqualifiedName;
+
+    private final ExtraInfo extraInfo;
+
+    private static final AtomicLong uniqueScopeId = new AtomicLong();
+    private final long scopeId;
+
+    private static final char SCOPE_SEP = '.';
+
+    private boolean countEnabled;
+    private boolean timeEnabled;
+    private boolean memUseTrackingEnabled;
+    private boolean verifyEnabled;
+    private boolean methodMetricsEnabled;
+
+    private int currentDumpLevel;
+    private int currentLogLevel;
+
+    private PrintStream output;
+
+    public static long getCurrentGlobalScopeId() {
+        return uniqueScopeId.get();
+    }
+
+    public static DebugScope getInstance() {
+        DebugScope result = instanceTL.get();
+        if (result == null) {
+            DebugScope topLevelDebugScope = new DebugScope(Thread.currentThread());
+            instanceTL.set(topLevelDebugScope);
+            return topLevelDebugScope;
+        } else {
+            return result;
+        }
+    }
+
+    public static DebugConfig getConfig() {
+        return configTL.get();
+    }
+
+    static final Object[] EMPTY_CONTEXT = new Object[0];
+
+    private DebugScope(Thread thread) {
+        this(thread.getName(), null, uniqueScopeId.incrementAndGet(), null, false);
+        computeValueMap(thread.getName());
+        DebugValueMap.registerTopLevel(getValueMap());
+    }
+
+    private DebugScope(String unqualifiedName, DebugScope parent, long scopeId, ExtraInfo metaInfo, boolean sandbox, Object... context) {
+        this.parent = parent;
+        this.sandbox = sandbox;
+        this.parentConfig = getConfig();
+        this.context = context;
+        this.scopeId = scopeId;
+        this.unqualifiedName = unqualifiedName;
+        this.extraInfo = metaInfo;
+        if (parent != null) {
+            logScopeName = !unqualifiedName.equals("");
+        } else {
+            logScopeName = true;
+        }
+
+        this.output = TTY.out;
+        assert context != null;
+    }
+
+    private void computeValueMap(String name) {
+        if (parent != null) {
+            for (DebugValueMap child : parent.getValueMap().getChildren()) {
+                if (child.getName().equals(name)) {
+                    this.valueMap = child;
+                    return;
+                }
+            }
+            this.valueMap = new DebugValueMap(name);
+            parent.getValueMap().addChild(this.valueMap);
+        } else {
+            this.valueMap = new DebugValueMap(name);
+        }
+    }
+
+    @Override
+    public void close() {
+        instanceTL.set(parent);
+        configTL.set(parentConfig);
+        lastClosedTL.set(this);
+    }
+
+    public boolean isDumpEnabled(int dumpLevel) {
+        assert dumpLevel > 0;
+        return currentDumpLevel >= dumpLevel;
+    }
+
+    /**
+     * Enable dumping at the new {@code dumpLevel} for the remainder of enclosing scopes. This only
+     * works if a {@link TopLevelDebugConfig} was installed at a higher scope.
+     *
+     * @param dumpLevel
+     */
+    public static void setDumpLevel(int dumpLevel) {
+        TopLevelDebugConfig config = fetchTopLevelDebugConfig("setDebugLevel");
+        if (config != null) {
+            config.override(DelegatingDebugConfig.Level.DUMP, dumpLevel);
+            recursiveUpdateFlags();
+        }
+    }
+
+    /**
+     * Enable logging at the new {@code logLevel} for the remainder of enclosing scopes. This only
+     * works if a {@link TopLevelDebugConfig} was installed at a higher scope.
+     *
+     * @param logLevel
+     */
+    public static void setLogLevel(int logLevel) {
+        TopLevelDebugConfig config = fetchTopLevelDebugConfig("setLogLevel");
+        if (config != null) {
+            config.override(DelegatingDebugConfig.Level.LOG, logLevel);
+            config.delegate(DelegatingDebugConfig.Feature.LOG_METHOD);
+            recursiveUpdateFlags();
+        }
+    }
+
+    private static void recursiveUpdateFlags() {
+        DebugScope c = DebugScope.getInstance();
+        while (c != null) {
+            c.updateFlags();
+            c = c.parent;
+        }
+    }
+
+    private static TopLevelDebugConfig fetchTopLevelDebugConfig(String msg) {
+        DebugConfig config = getConfig();
+        if (config instanceof TopLevelDebugConfig) {
+            return (TopLevelDebugConfig) config;
+        } else {
+            if (config == null) {
+                TTY.println("DebugScope.%s ignored because debugging is disabled", msg);
+            } else {
+                TTY.println("DebugScope.%s ignored because top level delegate config missing", msg);
+            }
+            return null;
+        }
+    }
+
+    public boolean isVerifyEnabled() {
+        return verifyEnabled;
+    }
+
+    public boolean isLogEnabled(int logLevel) {
+        assert logLevel > 0;
+        return currentLogLevel >= logLevel;
+    }
+
+    public boolean isCountEnabled() {
+        return countEnabled;
+    }
+
+    public boolean isTimeEnabled() {
+        return timeEnabled;
+    }
+
+    public boolean isMethodMeterEnabled() {
+        return methodMetricsEnabled;
+    }
+
+    public boolean isMemUseTrackingEnabled() {
+        return memUseTrackingEnabled;
+    }
+
+    public void log(int logLevel, String msg, Object... args) {
+        if (isLogEnabled(logLevel)) {
+            getLastUsedIndent().log(logLevel, msg, args);
+        }
+    }
+
+    public ExtraInfo getExtraInfo() {
+        return extraInfo;
+    }
+
+    public long scopeId() {
+        return scopeId;
+    }
+
+    public void dump(int dumpLevel, Object object, String formatString, Object... args) {
+        if (isDumpEnabled(dumpLevel)) {
+            DebugConfig config = getConfig();
+            if (config != null) {
+                String message = String.format(formatString, args);
+                for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
+                    dumpHandler.dump(object, message);
+                }
+            }
+        }
+    }
+
+    /**
+     * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph.
+     */
+    public static void forceDump(Object object, String format, Object... args) {
+        DebugConfig config = getConfig();
+        if (config != null) {
+            String message = String.format(format, args);
+            for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
+                dumpHandler.dump(object, message);
+            }
+        } else {
+            TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.Dump=xxx");
+        }
+    }
+
+    /**
+     * @see Debug#verify(Object, String)
+     */
+    public void verify(Object object, String formatString, Object... args) {
+        if (isVerifyEnabled()) {
+            DebugConfig config = getConfig();
+            if (config != null) {
+                String message = String.format(formatString, args);
+                for (DebugVerifyHandler handler : config.verifyHandlers()) {
+                    handler.verify(object, message);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates and enters a new debug scope which is either a child of the current scope or a
+     * disjoint top level scope.
+     *
+     * @param name the name of the new scope
+     * @param sandboxConfig the configuration to use for a new top level scope, or null if the new
+     *            scope should be a child scope
+     * @param newContextObjects objects to be appended to the debug context
+     * @return the new scope which will be exited when its {@link #close()} method is called
+     */
+    public DebugScope scope(CharSequence name, DebugConfig sandboxConfig, Object... newContextObjects) {
+        DebugScope newScope = null;
+        if (sandboxConfig != null) {
+            newScope = new DebugScope(name.toString(), this, uniqueScopeId.incrementAndGet(), null, true, newContextObjects);
+            configTL.set(sandboxConfig);
+        } else {
+            newScope = this.createChild(name.toString(), this.extraInfo, newContextObjects);
+        }
+        instanceTL.set(newScope);
+        newScope.updateFlags();
+        return newScope;
+    }
+
+    public DebugScope enhanceWithExtraInfo(CharSequence name, ExtraInfo newInfo, boolean newId, Object... newContext) {
+        DebugScope newScope = createChild(name.toString(), newInfo, newId ? uniqueScopeId.incrementAndGet() : this.scopeId, newContext);
+        instanceTL.set(newScope);
+        newScope.updateFlags();
+        return newScope;
+    }
+
+    public RuntimeException handle(Throwable e) {
+        DebugScope lastClosed = lastClosedTL.get();
+        assert lastClosed.parent == this : "Debug.handle() used with no matching Debug.scope(...) or Debug.sandbox(...)";
+        if (e != lastExceptionThrownTL.get()) {
+            RuntimeException newException = null;
+            instanceTL.set(lastClosed);
+            try (DebugScope s = lastClosed) {
+                newException = s.interceptException(e);
+            }
+            assert instanceTL.get() == this;
+            assert lastClosed == lastClosedTL.get();
+            if (newException == null) {
+                lastExceptionThrownTL.set(e);
+            } else {
+                lastExceptionThrownTL.set(newException);
+                throw newException;
+            }
+        }
+        if (e instanceof Error) {
+            throw (Error) e;
+        }
+        if (e instanceof RuntimeException) {
+            throw (RuntimeException) e;
+        }
+        throw new RuntimeException(e);
+    }
+
+    private void updateFlags() {
+        DebugConfig config = getConfig();
+        if (config == null) {
+            countEnabled = false;
+            memUseTrackingEnabled = false;
+            timeEnabled = false;
+            verifyEnabled = false;
+            currentDumpLevel = 0;
+            methodMetricsEnabled = false;
+            // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
+            // set while logging
+            output = TTY.out;
+        } else {
+            countEnabled = config.isCountEnabled();
+            memUseTrackingEnabled = config.isMemUseTrackingEnabled();
+            timeEnabled = config.isTimeEnabled();
+            verifyEnabled = config.isVerifyEnabled();
+            output = config.output();
+            currentDumpLevel = config.getDumpLevel();
+            currentLogLevel = config.getLogLevel();
+            methodMetricsEnabled = config.isMethodMeterEnabled();
+        }
+    }
+
+    @SuppressWarnings("try")
+    private RuntimeException interceptException(final Throwable e) {
+        final DebugConfig config = getConfig();
+        if (config != null) {
+            try (DebugScope s = scope("InterceptException", null, e)) {
+                return config.interceptException(e);
+            } catch (Throwable t) {
+                return new RuntimeException("Exception while intercepting exception", t);
+            }
+        }
+        return null;
+    }
+
+    private DebugValueMap getValueMap() {
+        if (valueMap == null) {
+            computeValueMap(unqualifiedName);
+        }
+        return valueMap;
+    }
+
+    long getCurrentValue(int index) {
+        return getValueMap().getCurrentValue(index);
+    }
+
+    void setCurrentValue(int index, long l) {
+        getValueMap().setCurrentValue(index, l);
+    }
+
+    private DebugScope createChild(String newName, ExtraInfo newInfo, Object[] newContext) {
+        return new DebugScope(newName, this, this.scopeId, newInfo, false, newContext);
+    }
+
+    private DebugScope createChild(String newName, ExtraInfo newInfo, long newId, Object[] newContext) {
+        return new DebugScope(newName, this, newId, newInfo, false, newContext);
+    }
+
+    public Iterable<Object> getCurrentContext() {
+        final DebugScope scope = this;
+        return new Iterable<Object>() {
+
+            @Override
+            public Iterator<Object> iterator() {
+                return new Iterator<Object>() {
+
+                    DebugScope currentScope = scope;
+                    int objectIndex;
+
+                    @Override
+                    public boolean hasNext() {
+                        selectScope();
+                        return currentScope != null;
+                    }
+
+                    private void selectScope() {
+                        while (currentScope != null && currentScope.context.length <= objectIndex) {
+                            currentScope = currentScope.sandbox ? null : currentScope.parent;
+                            objectIndex = 0;
+                        }
+                    }
+
+                    @Override
+                    public Object next() {
+                        selectScope();
+                        if (currentScope != null) {
+                            return currentScope.context[objectIndex++];
+                        }
+                        throw new IllegalStateException("May only be called if there is a next element.");
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException("This iterator is read only.");
+                    }
+                };
+            }
+        };
+    }
+
+    public static <T> T call(Callable<T> callable) {
+        try {
+            return callable.call();
+        } catch (Exception e) {
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            } else {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public void setConfig(DebugConfig newConfig) {
+        configTL.set(newConfig);
+        updateFlags();
+    }
+
+    public String getQualifiedName() {
+        if (qualifiedName == null) {
+            if (parent == null) {
+                qualifiedName = unqualifiedName;
+            } else {
+                qualifiedName = parent.getQualifiedName() + SCOPE_SEP + unqualifiedName;
+            }
+        }
+        return qualifiedName;
+    }
+
+    public Indent pushIndentLogger() {
+        lastUsedIndent = getLastUsedIndent().indent();
+        return lastUsedIndent;
+    }
+
+    public IndentImpl getLastUsedIndent() {
+        if (lastUsedIndent == null) {
+            if (parent != null) {
+                lastUsedIndent = new IndentImpl(parent.getLastUsedIndent());
+            } else {
+                lastUsedIndent = new IndentImpl(null);
+            }
+        }
+        return lastUsedIndent;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValue.java
new file mode 100644
index 0000000..c0bba23
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValue.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+/**
+ * A name and index for a value managed in a thread local value map. All access to the value is made
+ * via a {@link DebugValue} instance.
+ */
+public abstract class DebugValue implements Comparable<DebugValue> {
+
+    private final String name;
+    private int index;
+    private boolean conditional;
+
+    protected DebugValue(String name, boolean conditional) {
+        this.name = name;
+        this.index = -1;
+        this.conditional = conditional;
+    }
+
+    public long getCurrentValue() {
+        ensureInitialized();
+        return DebugScope.getInstance().getCurrentValue(index);
+    }
+
+    protected void setCurrentValue(long l) {
+        ensureInitialized();
+        DebugScope.getInstance().setCurrentValue(index, l);
+    }
+
+    public void setConditional(boolean flag) {
+        conditional = flag;
+    }
+
+    public boolean isConditional() {
+        return conditional;
+    }
+
+    private void ensureInitialized() {
+        if (index == -1) {
+            index = KeyRegistry.register(this);
+        }
+    }
+
+    protected void addToCurrentValue(long value) {
+        setCurrentValue(getCurrentValue() + value);
+    }
+
+    /**
+     * Gets the globally unique index for the value represented by this object.
+     */
+    public int getIndex() {
+        ensureInitialized();
+        return index;
+    }
+
+    /**
+     * Gets the globally unique name for the value represented by this object.
+     */
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public int compareTo(DebugValue o) {
+        return name.compareTo(o.name);
+    }
+
+    @Override
+    public String toString() {
+        return name + "@" + index;
+    }
+
+    public abstract String toString(long value);
+
+    /**
+     * The raw unit of the value (e.g. 'us', 'ms'). Use {@code ""} if there is no unit.
+     */
+    public abstract String rawUnit();
+
+    /**
+     * The raw value.
+     */
+    public abstract String toRawString(long value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValueMap.java
new file mode 100644
index 0000000..7b8753a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValueMap.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A node in a tree of {@link DebugValue}s.
+ */
+public class DebugValueMap {
+
+    private static final List<DebugValueMap> topLevelMaps = new ArrayList<>();
+
+    private long[] values;
+    private List<DebugValueMap> children;
+    private String name;
+
+    public DebugValueMap(String name) {
+        this.name = name;
+    }
+
+    public void setCurrentValue(int index, long l) {
+        ensureSize(index);
+        values[index] = l;
+    }
+
+    public long getCurrentValue(int index) {
+        ensureSize(index);
+        return values[index];
+    }
+
+    public void clearChildren() {
+        if (children != null) {
+            children.clear();
+        }
+    }
+
+    public void reset() {
+        if (values != null) {
+            Arrays.fill(values, 0L);
+        }
+        if (children != null) {
+            for (DebugValueMap child : children) {
+                child.reset();
+            }
+        }
+    }
+
+    private void ensureSize(int index) {
+        if (values == null) {
+            values = new long[index + 1];
+        }
+        if (values.length <= index) {
+            values = Arrays.copyOf(values, index + 1);
+        }
+    }
+
+    private int capacity() {
+        return (values == null) ? 0 : values.length;
+    }
+
+    public void addChild(DebugValueMap map) {
+        if (children == null) {
+            children = new ArrayList<>(4);
+        }
+        children.add(map);
+    }
+
+    public List<DebugValueMap> getChildren() {
+        if (children == null) {
+            return Collections.emptyList();
+        } else {
+            return Collections.unmodifiableList(children);
+        }
+    }
+
+    public boolean hasChildren() {
+        return children != null && !children.isEmpty();
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String toString() {
+        return "DebugValueMap<" + getName() + ">";
+    }
+
+    public static synchronized void registerTopLevel(DebugValueMap map) {
+        topLevelMaps.add(map);
+    }
+
+    public static synchronized List<DebugValueMap> getTopLevelMaps() {
+        return topLevelMaps;
+    }
+
+    public void normalize() {
+        if (hasChildren()) {
+            Map<String, DebugValueMap> occurred = new HashMap<>();
+            for (DebugValueMap map : children) {
+                String mapName = map.getName();
+                if (!occurred.containsKey(mapName)) {
+                    occurred.put(mapName, map);
+                    map.normalize();
+                } else {
+                    occurred.get(mapName).mergeWith(map);
+                    occurred.get(mapName).normalize();
+                }
+            }
+
+            if (occurred.values().size() < children.size()) {
+                // At least one duplicate was found.
+                children.clear();
+                for (DebugValueMap map : occurred.values()) {
+                    addChild(map);
+                    map.normalize();
+                }
+            }
+        }
+    }
+
+    private void mergeWith(DebugValueMap map) {
+        if (map.hasChildren()) {
+            if (hasChildren()) {
+                children.addAll(map.children);
+            } else {
+                children = map.children;
+            }
+            map.children = null;
+        }
+
+        int size = Math.max(this.capacity(), map.capacity());
+        ensureSize(size);
+        for (int i = 0; i < size; ++i) {
+            long curValue = getCurrentValue(i);
+            long otherValue = map.getCurrentValue(i);
+            setCurrentValue(i, curValue + otherValue);
+        }
+    }
+
+    public void group() {
+        if (this.hasChildren()) {
+            List<DebugValueMap> oldChildren = new ArrayList<>(this.children);
+            this.children.clear();
+            for (DebugValueMap map : oldChildren) {
+                mergeWith(map);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValuesPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValuesPrinter.java
new file mode 100644
index 0000000..90af22b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugValuesPrinter.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueFile;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueHumanReadable;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueThreadFilter;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.SuppressZeroDebugValues;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.LogStream;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+
+/**
+ * Facility for printing the {@linkplain KeyRegistry#getDebugValues() values} collected across all
+ * {@link DebugValueMap#getTopLevelMaps() threads}.
+ */
+public class DebugValuesPrinter {
+    private static final String COMPUTER_READABLE_FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s");
+    private static final char SCOPE_DELIMITER = '.';
+    private final MethodMetricsPrinter mmPrinter;
+
+    public DebugValuesPrinter() {
+        this(null);
+    }
+
+    public DebugValuesPrinter(MethodMetricsPrinter mmPrinter) {
+        this.mmPrinter = mmPrinter;
+    }
+
+    public void printDebugValues() throws GraalError {
+        TTY.println();
+        TTY.println("<DebugValues>");
+        List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
+        List<DebugValue> debugValues = KeyRegistry.getDebugValues();
+        if (debugValues.size() > 0) {
+            try {
+                ArrayList<DebugValue> sortedValues = new ArrayList<>(debugValues);
+                Collections.sort(sortedValues);
+
+                String summary = DebugValueSummary.getValue();
+                if (summary == null) {
+                    summary = "Complete";
+                }
+                if (DebugValueThreadFilter.getValue() != null && topLevelMaps.size() != 0) {
+                    topLevelMaps = topLevelMaps.stream().filter(map -> Pattern.compile(DebugValueThreadFilter.getValue()).matcher(map.getName()).find()).collect(Collectors.toList());
+                    if (topLevelMaps.size() == 0) {
+                        TTY.println("Warning: DebugValueThreadFilter=%s eliminated all maps so nothing will be printed", DebugValueThreadFilter.getValue());
+                    }
+                }
+                switch (summary) {
+                    case "Name": {
+                        LogStream log = getLogStream();
+                        printSummary(log, topLevelMaps, sortedValues);
+                        break;
+                    }
+                    case "Partial": {
+                        DebugValueMap globalMap = new DebugValueMap("Global");
+                        for (DebugValueMap map : topLevelMaps) {
+                            flattenChildren(map, globalMap);
+                        }
+                        globalMap.normalize();
+                        LogStream log = getLogStream();
+                        printMap(log, new DebugValueScope(null, globalMap), sortedValues);
+                        break;
+                    }
+                    case "Complete": {
+                        DebugValueMap globalMap = new DebugValueMap("Global");
+                        for (DebugValueMap map : topLevelMaps) {
+                            globalMap.addChild(map);
+                        }
+                        globalMap.group();
+                        globalMap.normalize();
+                        LogStream log = getLogStream();
+                        printMap(log, new DebugValueScope(null, globalMap), sortedValues);
+                        break;
+                    }
+                    case "Thread":
+                        for (DebugValueMap map : topLevelMaps) {
+                            TTY.println("Showing the results for thread: " + map.getName());
+                            map.group();
+                            map.normalize();
+                            LogStream log = getLogStream(map.getName().replace(' ', '_'));
+                            printMap(log, new DebugValueScope(null, map), sortedValues);
+                        }
+                        break;
+                    default:
+                        throw new GraalError("Unknown summary type: %s", summary);
+                }
+                for (DebugValueMap topLevelMap : topLevelMaps) {
+                    topLevelMap.reset();
+                }
+            } catch (Throwable e) {
+                // Don't want this to change the exit status of the VM
+                PrintStream err = System.err;
+                err.println("Error while printing debug values:");
+                e.printStackTrace();
+            }
+        }
+        if (mmPrinter != null) {
+            mmPrinter.printMethodMetrics(MethodMetricsImpl.collectedMetrics());
+        }
+        TTY.println("</DebugValues>");
+    }
+
+    private static LogStream getLogStream() {
+        return getLogStream(null);
+    }
+
+    private static LogStream getLogStream(String prefix) {
+        String debugValueFile = DebugValueFile.getValue();
+        if (debugValueFile != null) {
+            try {
+                final String fileName;
+                if (prefix != null) {
+                    fileName = prefix + '-' + debugValueFile;
+                } else {
+                    fileName = debugValueFile;
+                }
+                LogStream logStream = new LogStream(new FileOutputStream(fileName));
+                TTY.println("Writing debug values to '%s'", fileName);
+                return logStream;
+            } catch (FileNotFoundException e) {
+                TTY.println("Warning: Could not open debug value log file: %s (defaulting to TTY)", e.getMessage());
+            }
+        }
+        return TTY.out();
+    }
+
+    private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
+        globalMap.addChild(map);
+        for (DebugValueMap child : map.getChildren()) {
+            flattenChildren(child, globalMap);
+        }
+        map.clearChildren();
+    }
+
+    private void printSummary(LogStream log, List<DebugValueMap> topLevelMaps, List<DebugValue> debugValues) {
+        DebugValueMap result = new DebugValueMap("Summary");
+        for (int i = debugValues.size() - 1; i >= 0; i--) {
+            DebugValue debugValue = debugValues.get(i);
+            int index = debugValue.getIndex();
+            long total = collectTotal(topLevelMaps, index);
+            result.setCurrentValue(index, total);
+        }
+        printMap(log, new DebugValueScope(null, result), debugValues);
+    }
+
+    private long collectTotal(List<DebugValueMap> maps, int index) {
+        long total = 0;
+        for (int i = 0; i < maps.size(); i++) {
+            DebugValueMap map = maps.get(i);
+            total += map.getCurrentValue(index);
+            total += collectTotal(map.getChildren(), index);
+        }
+        return total;
+    }
+
+    /**
+     * Tracks the scope when printing a {@link DebugValueMap}, allowing "empty" scopes to be
+     * omitted. An empty scope is one in which there are no (nested) non-zero debug values.
+     */
+    static class DebugValueScope {
+
+        final DebugValueScope parent;
+        final int level;
+        final DebugValueMap map;
+        private boolean printed;
+
+        DebugValueScope(DebugValueScope parent, DebugValueMap map) {
+            this.parent = parent;
+            this.map = map;
+            this.level = parent == null ? 0 : parent.level + 1;
+        }
+
+        public void print(LogStream log) {
+            if (!printed) {
+                printed = true;
+                if (parent != null) {
+                    parent.print(log);
+                }
+                printIndent(log, level);
+                log.printf("%s%n", map.getName());
+            }
+        }
+
+        public String toRawString() {
+            return toRaw(new StringBuilder()).toString();
+        }
+
+        private StringBuilder toRaw(StringBuilder stringBuilder) {
+            final StringBuilder sb = (parent == null) ? stringBuilder : parent.toRaw(stringBuilder).append(SCOPE_DELIMITER);
+            return sb.append(map.getName());
+        }
+
+    }
+
+    private void printMap(LogStream log, DebugValueScope scope, List<DebugValue> debugValues) {
+        if (DebugValueHumanReadable.getValue()) {
+            printMapHumanReadable(log, scope, debugValues);
+        } else {
+            printMapComputerReadable(log, scope, debugValues);
+        }
+    }
+
+    private void printMapComputerReadable(LogStream log, DebugValueScope scope, List<DebugValue> debugValues) {
+
+        for (DebugValue value : debugValues) {
+            long l = scope.map.getCurrentValue(value.getIndex());
+            if (l != 0 || !SuppressZeroDebugValues.getValue()) {
+                CSVUtil.Escape.println(log, COMPUTER_READABLE_FMT, scope.toRawString(), value.getName(), value.toRawString(l), value.rawUnit());
+            }
+        }
+
+        List<DebugValueMap> children = scope.map.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            DebugValueMap child = children.get(i);
+            printMapComputerReadable(log, new DebugValueScope(scope, child), debugValues);
+        }
+    }
+
+    private void printMapHumanReadable(LogStream log, DebugValueScope scope, List<DebugValue> debugValues) {
+
+        for (DebugValue value : debugValues) {
+            long l = scope.map.getCurrentValue(value.getIndex());
+            if (l != 0 || !SuppressZeroDebugValues.getValue()) {
+                scope.print(log);
+                printIndent(log, scope.level + 1);
+                log.println(value.getName() + "=" + value.toString(l));
+            }
+        }
+
+        List<DebugValueMap> children = scope.map.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            DebugValueMap child = children.get(i);
+            printMapHumanReadable(log, new DebugValueScope(scope, child), debugValues);
+        }
+    }
+
+    private static void printIndent(LogStream log, int level) {
+        for (int i = 0; i < level; ++i) {
+            log.print("    ");
+        }
+        log.print("|-> ");
+    }
+
+    public void clearDebugValues() {
+        List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
+        List<DebugValue> debugValues = KeyRegistry.getDebugValues();
+        if (debugValues.size() > 0) {
+            for (DebugValueMap map : topLevelMaps) {
+                map.reset();
+            }
+        }
+        if (mmPrinter != null) {
+            MethodMetricsImpl.clearMM();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/KeyRegistry.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/KeyRegistry.java
new file mode 100644
index 0000000..19ab80e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/KeyRegistry.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Registry for allocating a globally unique integer id to each {@link DebugValue}.
+ */
+public class KeyRegistry {
+
+    private static final Map<String, Integer> keyMap = new HashMap<>();
+    private static final List<DebugValue> debugValues = new ArrayList<>();
+
+    /**
+     * Ensures a given debug value is registered.
+     *
+     * @return the globally unique id for {@code value}
+     */
+    public static synchronized int register(DebugValue value) {
+        String name = value.getName();
+        if (!keyMap.containsKey(name)) {
+            keyMap.put(name, debugValues.size());
+            debugValues.add(value);
+        }
+        return keyMap.get(name);
+    }
+
+    /**
+     * Gets a immutable view of the registered debug values.
+     *
+     * @return a list where {@code get(i).getIndex() == i}
+     */
+    public static synchronized List<DebugValue> getDebugValues() {
+        return Collections.unmodifiableList(debugValues);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/MemUseTrackerImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/MemUseTrackerImpl.java
new file mode 100644
index 0000000..789db1f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/MemUseTrackerImpl.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.Management;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+
+public class MemUseTrackerImpl extends AccumulatedDebugValue implements DebugMemUseTracker {
+    private final boolean intercepting;
+
+    public static long getCurrentThreadAllocatedBytes() {
+        return Management.getCurrentThreadAllocatedBytes();
+    }
+
+    /**
+     * Records the most recent active tracker.
+     */
+    private static final ThreadLocal<CloseableCounterImpl> currentTracker = new ThreadLocal<>();
+
+    public MemUseTrackerImpl(String name, boolean conditional, boolean intercepting) {
+        super(name, conditional, new DebugValue(name + "_Flat", conditional) {
+
+            @Override
+            public String toString(long value) {
+                return valueToString(value);
+            }
+
+            @Override
+            public String rawUnit() {
+                return "B";
+            }
+
+            @Override
+            public String toRawString(long value) {
+                return Long.toString(value);
+            }
+        });
+        this.intercepting = intercepting;
+    }
+
+    @Override
+    public DebugCloseable start() {
+        if (!isConditional() || Debug.isMemUseTrackingEnabled()) {
+            CloseableCounterImpl result = intercepting ? new MemUseInterceptingCloseableCounterImpl(this) : new MemUseCloseableCounterImpl(this);
+            currentTracker.set(result);
+            return result;
+        } else {
+            return VOID_CLOSEABLE;
+        }
+    }
+
+    public static String valueToString(long value) {
+        return String.format("%d bytes", value);
+    }
+
+    @Override
+    public String toString(long value) {
+        return valueToString(value);
+    }
+
+    private static final class MemUseCloseableCounterImpl extends CloseableCounterImpl implements DebugCloseable {
+
+        private MemUseCloseableCounterImpl(AccumulatedDebugValue counter) {
+            super(currentTracker.get(), counter);
+        }
+
+        @Override
+        long getCounterValue() {
+            return getCurrentThreadAllocatedBytes();
+        }
+
+        @Override
+        public void close() {
+            super.close();
+            currentTracker.set(parent);
+        }
+    }
+
+    private static final class MemUseInterceptingCloseableCounterImpl extends CloseableCounterImpl implements DebugCloseable {
+
+        private MemUseInterceptingCloseableCounterImpl(AccumulatedDebugValue counter) {
+            super(currentTracker.get(), counter);
+        }
+
+        @Override
+        long getCounterValue() {
+            return getCurrentThreadAllocatedBytes();
+        }
+
+        @Override
+        public void close() {
+            super.close();
+            currentTracker.set(parent);
+        }
+
+        @Override
+        protected void interceptDifferenceAccm(long difference) {
+            if (Debug.isMethodMeterEnabled()) {
+                MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.getName(), difference);
+            }
+        }
+
+        @Override
+        protected void interceptDifferenceFlat(long difference) {
+            if (Debug.isMethodMeterEnabled()) {
+                MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.flat.getName(), difference);
+            }
+        }
+    }
+
+    @Override
+    public String rawUnit() {
+        return "B";
+    }
+
+    @Override
+    public String toRawString(long value) {
+        return Long.toString(value);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/TimerImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/TimerImpl.java
new file mode 100644
index 0000000..6f0ae33
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/TimerImpl.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal;
+
+import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE;
+
+import java.util.concurrent.TimeUnit;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.TimeSource;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+
+public final class TimerImpl extends AccumulatedDebugValue implements DebugTimer {
+    private final boolean intercepting;
+
+    /**
+     * Records the most recent active timer.
+     */
+    private static final ThreadLocal<CloseableCounterImpl> currentTimer = new ThreadLocal<>();
+
+    static class FlatTimer extends DebugValue implements DebugTimer {
+        private TimerImpl accm;
+
+        FlatTimer(String name, boolean conditional) {
+            super(name + "_Flat", conditional);
+        }
+
+        @Override
+        public String toString(long value) {
+            return valueToString(value);
+        }
+
+        @Override
+        public TimeUnit getTimeUnit() {
+            return accm.getTimeUnit();
+        }
+
+        @Override
+        public DebugCloseable start() {
+            return accm.start();
+        }
+
+        @Override
+        public String rawUnit() {
+            return "us";
+        }
+
+        @Override
+        public String toRawString(long value) {
+            return valueToRawString(value);
+        }
+    }
+
+    public TimerImpl(String name, boolean conditional, boolean intercepting) {
+        super(name, conditional, new FlatTimer(name, conditional));
+        ((FlatTimer) flat).accm = this;
+        this.intercepting = intercepting;
+    }
+
+    @Override
+    public DebugCloseable start() {
+        if (!isConditional() || Debug.isTimeEnabled()) {
+            AbstractTimer result = intercepting ? new InterceptingTimer(this) : new Timer(this);
+            currentTimer.set(result);
+            return result;
+        } else {
+            return VOID_CLOSEABLE;
+        }
+    }
+
+    public static String valueToString(long value) {
+        return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10);
+    }
+
+    @Override
+    public DebugTimer getFlat() {
+        return (FlatTimer) flat;
+    }
+
+    @Override
+    public String toString(long value) {
+        return valueToString(value);
+    }
+
+    @Override
+    public TimeUnit getTimeUnit() {
+        return TimeUnit.NANOSECONDS;
+    }
+
+    private abstract class AbstractTimer extends CloseableCounterImpl implements DebugCloseable {
+
+        private AbstractTimer(AccumulatedDebugValue counter) {
+            super(currentTimer.get(), counter);
+        }
+
+        @Override
+        public void close() {
+            super.close();
+            currentTimer.set(parent);
+        }
+    }
+
+    private final class Timer extends AbstractTimer {
+
+        private Timer(TimerImpl timer) {
+            super(timer);
+        }
+
+        @Override
+        protected long getCounterValue() {
+            return TimeSource.getTimeNS();
+        }
+
+    }
+
+    private final class InterceptingTimer extends AbstractTimer {
+
+        private InterceptingTimer(TimerImpl timer) {
+            super(timer);
+        }
+
+        @Override
+        protected long getCounterValue() {
+            return TimeSource.getTimeNS();
+        }
+
+        @Override
+        protected void interceptDifferenceAccm(long difference) {
+            if (Debug.isMethodMeterEnabled()) {
+                MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.getName(), difference);
+            }
+        }
+
+        @Override
+        protected void interceptDifferenceFlat(long difference) {
+            if (Debug.isMethodMeterEnabled()) {
+                MethodMetricsImpl.addToCurrentScopeMethodMetrics(counter.flat.getName(), difference);
+            }
+        }
+    }
+
+    @Override
+    public String rawUnit() {
+        return "us";
+    }
+
+    @Override
+    public String toRawString(long value) {
+        return valueToRawString(value);
+    }
+
+    public static String valueToRawString(long value) {
+        return Long.toString(value / 1000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsImpl.java
new file mode 100644
index 0000000..de653ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsImpl.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal.method;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.internal.DebugScope;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodMetricsImpl implements DebugMethodMetrics {
+
+    /**
+     * A list capturing all method metrics data of all the compiler threads. Every thread registers
+     * a reference to its thread local map of compilation metrics in this list. During metrics
+     * dumping this list is globally locked and all method entries across all threads are merged to
+     * a result.
+     */
+    private static final List<Map<ResolvedJavaMethod, CompilationData>> threadMaps = new ArrayList<>();
+    /**
+     * Every compiler thread carries its own map of metric data for each method and compilation it
+     * compiles. This data is stored in {@link ThreadLocal} maps for each compiler thread that are
+     * merged before metrics are reported. Storing compilation data thread locally reduces the
+     * locking on access of a method metric object to one point for each thread, the first access
+     * where the thread local is initialized.
+     */
+    private static final ThreadLocal<Map<ResolvedJavaMethod, CompilationData>> threadEntries = new ThreadLocal<>();
+    /**
+     * The lowest debug scope id that should be used during metric dumping. When a bootstrap is run
+     * all compilations during bootstrap are also collected if the associated debug filters match.
+     * Data collected during bootstrap should normally not be included in metrics for application
+     * compilation, thus every compilation lower than this index is ignored during metric dumping.
+     */
+    private static long lowestCompilationDebugScopeId;
+
+    public static class CompilationData {
+        /**
+         * A mapping of graph ids (unique ids used for the caching) to compilations.
+         */
+        private final Map<Long, Map<String, Long>> compilations;
+        /**
+         * A pointer to a {@code MethodMetricsImpl} object. This reference is created once for every
+         * compilation of a method (and once for each thread, i.e. if method a is compiled by 8
+         * compiler threads there will be 8 metrics objects for the given method, one local to every
+         * thread, this avoids synchronizing on the metrics object on every access) accessing method
+         * metrics for a given method.
+         */
+        private final MethodMetricsImpl metrics;
+
+        CompilationData(ResolvedJavaMethod method) {
+            compilations = new HashMap<>(8);
+            metrics = new MethodMetricsImpl(method);
+        }
+
+        public Map<Long, Map<String, Long>> getCompilations() {
+            return compilations;
+        }
+    }
+
+    private static void addThreadCompilationData(Map<ResolvedJavaMethod, CompilationData> threadMap) {
+        synchronized (threadMaps) {
+            threadMaps.add(threadMap);
+        }
+    }
+
+    /**
+     * A reference to the {@link ResolvedJavaMethod} method object. This object's identity is used
+     * to store metrics for each compilation.
+     */
+    private final ResolvedJavaMethod method;
+    /**
+     * A list of all recorded compilations. This is generated during metric dumping when all thread
+     * local metrics are merged into one final method metrics object that is than reported
+     */
+    private List<Map<Long, Map<String, Long>>> collected;
+    /**
+     * A pointer to the current compilation data for the {@link MethodMetricsImpl#method} method
+     * which allows to avoid synchronizing over the compilation data. This reference changes for
+     * each compilation of the given method. It is set on the first access of this
+     * {@link MethodMetricsImpl} object during the call to
+     * {@link MethodMetricsImpl#getMethodMetrics(ResolvedJavaMethod)}.
+     */
+    private Map<String, Long> currentCompilation;
+
+    MethodMetricsImpl(ResolvedJavaMethod method) {
+        this.method = method;
+    }
+
+    private static void clearData() {
+        lowestCompilationDebugScopeId = DebugScope.getCurrentGlobalScopeId();
+    }
+
+    @Override
+    public void addToMetric(long value, String metricName) {
+        if (!Debug.isMethodMeterEnabled() || value == 0) {
+            return;
+        }
+        assert metricName != null;
+        Long valueStored = currentCompilation.get(metricName);
+        currentCompilation.put(metricName, valueStored == null ? value : value + valueStored);
+    }
+
+    @Override
+    public long getCurrentMetricValue(String metricName) {
+        assert metricName != null;
+        Long valueStored = currentCompilation.get(metricName);
+        return valueStored == null ? 0 : valueStored;
+    }
+
+    @Override
+    public void addToMetric(long value, String format, Object arg1) {
+        addToMetric(value, String.format(format, arg1));
+    }
+
+    @Override
+    public void addToMetric(long value, String format, Object arg1, Object arg2) {
+        addToMetric(value, String.format(format, arg1, arg2));
+    }
+
+    @Override
+    public void addToMetric(long value, String format, Object arg1, Object arg2, Object arg3) {
+        addToMetric(value, String.format(format, arg1, arg2, arg3));
+    }
+
+    @Override
+    public void incrementMetric(String metricName) {
+        addToMetric(1, metricName);
+    }
+
+    @Override
+    public void incrementMetric(String format, Object arg1) {
+        incrementMetric(String.format(format, arg1));
+    }
+
+    @Override
+    public void incrementMetric(String format, Object arg1, Object arg2) {
+        incrementMetric(String.format(format, arg1, arg2));
+    }
+
+    @Override
+    public void incrementMetric(String format, Object arg1, Object arg2, Object arg3) {
+        incrementMetric(String.format(format, arg1, arg2, arg3));
+    }
+
+    @Override
+    public long getCurrentMetricValue(String format, Object arg1) {
+        return getCurrentMetricValue(String.format(format, arg1));
+    }
+
+    @Override
+    public long getCurrentMetricValue(String format, Object arg1, Object arg2) {
+        return getCurrentMetricValue(String.format(format, arg1, arg2));
+    }
+
+    @Override
+    public long getCurrentMetricValue(String format, Object arg1, Object arg2, Object arg3) {
+        return getCurrentMetricValue(String.format(format, arg1, arg2, arg3));
+    }
+
+    @Override
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    public static DebugMethodMetrics getMethodMetrics(ResolvedJavaMethod method) {
+        assert method != null;
+        Map<ResolvedJavaMethod, CompilationData> threadCache = threadEntries.get();
+        if (threadCache == null) {
+            // this branch will only be executed once for each compiler thread on the first request
+            // of a method metric
+            threadCache = new HashMap<>(GraalDebugConfig.Options.MethodFilter.getValue() == null ? 128 : 16);
+            threadEntries.set(threadCache);
+            addThreadCompilationData(threadCache);
+        }
+
+        CompilationData recorded = threadCache.get(method);
+        if (recorded == null) {
+            recorded = new CompilationData(method);
+            threadCache.put(method, recorded);
+        }
+        // pre-generate the current compilation map to avoid doing it later every time we add to a
+        // metric or read a current metric's value
+        long compilationId = DebugScope.getInstance().scopeId();
+        Map<String, Long> currentCompilation = recorded.compilations.get(compilationId);
+        if (currentCompilation == null) {
+            // this map is generated for every distinct compilation of a unique method
+            currentCompilation = new HashMap<>(32);
+            recorded.compilations.put(compilationId, currentCompilation);
+            // we remember a reference to the current compilation to avoid the expensive lookup
+            recorded.metrics.currentCompilation = currentCompilation;
+        }
+
+        return recorded.metrics;
+    }
+
+    public void dumpASCII(PrintStream p) {
+        // we need to lock the threadmap as a concurrent call to #collectedMetrics can change the
+        // content of this#collected
+        synchronized (threadMaps) {
+            String methodName = method.toString();
+            int maxLen = methodName.length();
+            int entrySum = 0;
+            // get the longest entry
+            for (Map<Long, Map<String, Long>> compilationThreadTable : collected) {
+                for (Map.Entry<Long, Map<String, Long>> compilationEntry : compilationThreadTable.entrySet()) {
+                    Map<String, Long> table = compilationEntry.getValue();
+                    if (table != null) {
+                        for (Map.Entry<String, Long> entry : table.entrySet()) {
+                            maxLen = Math.max(maxLen, entry.getKey().length());
+                            entrySum += entry.getValue();
+                        }
+                    }
+                }
+            }
+            if (entrySum == 0) {
+                // nothing to report
+                return;
+            }
+            maxLen += 23;
+            for (int j = 0; j < maxLen; j++) {
+                p.print("#");
+            }
+            p.println();
+            p.println(methodName);
+            for (int j = 0; j < maxLen; j++) {
+                p.print("~");
+            }
+            p.println();
+            for (Map<Long, Map<String, Long>> compilationThreadTable : collected) {
+                for (Map.Entry<Long, Map<String, Long>> compilationEntry : compilationThreadTable.entrySet()) {
+                    Map<String, Long> table = compilationEntry.getValue();
+                    if (table != null) {
+                        if (table.values().stream().filter(x -> x > 0).count() == 0) {
+                            continue;
+                        }
+                        Set<Map.Entry<String, Long>> entries = table.entrySet();
+                        for (Map.Entry<String, Long> entry : entries.stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).collect(Collectors.toList())) {
+                            long value = entry.getValue();
+                            // report timers in ms and memory in mb
+                            if ((entry.getKey().endsWith("Accm") || entry.getKey().endsWith("Flat")) &&
+                                            !entry.getKey().toLowerCase().contains("mem")) {
+                                value = value / 1000000;
+                            }
+                            if (value == 0) {
+                                continue;
+                            }
+                            p.print(String.format("%-" + String.valueOf(maxLen - 23) + "s = %20d", entry.getKey(), value));
+                            p.println();
+                        }
+                        for (int j = 0; j < maxLen; j++) {
+                            p.print("~");
+                        }
+                        p.println();
+                    }
+                }
+            }
+            for (int j = 0; j < maxLen; j++) {
+                p.print("#");
+            }
+            p.println();
+        }
+    }
+
+    private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%d", "%d", "%s", "%d");
+
+    public void dumpCSV(PrintStream p) {
+        // we need to lock the threadmap as a concurrent call to #collectedMetrics can change
+        // the content of this#collected
+        synchronized (threadMaps) {
+            String methodName = method.format("%H.%n(%p)%R");
+            /*
+             * NOTE: the caching mechanism works by caching compilation data based on the identity
+             * of the resolved java method object. The identity is based on the metaspace address of
+             * the resolved java method object. If the class was loaded by different class loaders
+             * or e.g. loaded - unloaded - loaded the identity will be different. Therefore we also
+             * need to include the identity in the reporting of the data as it is an additional
+             * dimension to <method,compilationId>.
+             */
+            String methodIdentity = String.valueOf(System.identityHashCode(method));
+            int nrOfCompilations = 0;
+            for (Map<Long, Map<String, Long>> compilationThreadTable : collected) {
+                for (Map.Entry<Long, Map<String, Long>> compilationEntry : compilationThreadTable.entrySet()) {
+                    Map<String, Long> table = compilationEntry.getValue();
+                    if (table != null) {
+                        Set<Map.Entry<String, Long>> entries = table.entrySet();
+                        for (Map.Entry<String, Long> entry : entries.stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).collect(Collectors.toList())) {
+                            CSVUtil.Escape.println(p, FMT, methodName, methodIdentity, nrOfCompilations, compilationEntry.getKey(), entry.getKey(), entry.getValue());
+                        }
+                        nrOfCompilations++;
+                    }
+                }
+            }
+        }
+    }
+
+    public static Collection<DebugMethodMetrics> collectedMetrics() {
+        synchronized (threadMaps) {
+            // imprecise excluding all compilations that follow, we simply do not report them
+            final long lastId = DebugScope.getCurrentGlobalScopeId();
+            List<DebugMethodMetrics> finalMetrics = new ArrayList<>();
+            Set<ResolvedJavaMethod> methods = new HashSet<>();
+
+            // gather all methods we found
+            threadMaps.stream().forEach(x -> {
+                // snapshot the current compilations to only capture all methods compiled until now
+                HashMap<ResolvedJavaMethod, CompilationData> snapShot = new HashMap<>(x);
+                snapShot.keySet().forEach(y -> methods.add(y));
+            });
+
+            // for each method gather all metrics we want to report
+            for (ResolvedJavaMethod method : methods) {
+                MethodMetricsImpl impl = new MethodMetricsImpl(method);
+                impl.collected = new ArrayList<>();
+                for (Map<ResolvedJavaMethod, CompilationData> threadMap : threadMaps) {
+                    CompilationData threadMethodData = threadMap.get(method);
+
+                    // not every method is necessarily compiled by all threads
+                    if (threadMethodData != null) {
+                        Map<Long, Map<String, Long>> snapshot = new HashMap<>(threadMethodData.compilations);
+                        for (Map.Entry<Long, Map<String, Long>> entry : snapshot.entrySet()) {
+                            if (entry.getKey() < lowestCompilationDebugScopeId || entry.getKey() > lastId) {
+                                entry.setValue(null);
+                            }
+                        }
+                        impl.collected.add(snapshot);
+                    }
+                }
+                finalMetrics.add(impl);
+            }
+
+            return finalMetrics;
+        }
+    }
+
+    public static void clearMM() {
+        clearData();
+    }
+
+    private static final String INLINEE_PREFIX = "INLINING_SCOPE_";
+    private static final boolean TRACK_INLINED_SCOPES = false;
+
+    public static void recordInlinee(ResolvedJavaMethod root, ResolvedJavaMethod caller, ResolvedJavaMethod inlinee) {
+        if (TRACK_INLINED_SCOPES) {
+            Debug.methodMetrics(root).addToMetric(1, "INLINED_METHOD_root: caller:%s inlinee:%s", caller, inlinee);
+        }
+    }
+
+    private static final boolean COUNT_CACHE = false;
+    private static final String HIT_MSG = "InterceptionCache_Hit";
+    private static final String MISS_MSG = "InterceptionCache_Miss";
+    private static final DebugCounter cacheHit = Debug.counter(HIT_MSG);
+    private static final DebugCounter cacheMiss = Debug.counter(MISS_MSG);
+    /**
+     * To avoid the lookup of a method metrics through the
+     * {@link MethodMetricsImpl#getMethodMetrics(ResolvedJavaMethod)} method on every global metric
+     * interception we thread-locally cache the last (through metric interception)
+     * {@link MethodMetricsImpl} object. This avoids additional map lookups and replaces them with a
+     * {@link DebugScope#scopeId()} call and a numerical comparison in a cache hit case.
+     */
+    private static final ThreadLocal<Long> interceptionCache = new ThreadLocal<>();
+    private static final ThreadLocal<MethodMetricsImpl> interceptionMetrics = new ThreadLocal<>();
+
+    public static void addToCurrentScopeMethodMetrics(String metricName, long value) {
+        if (COUNT_CACHE) {
+            if (metricName.equals(HIT_MSG) || metricName.equals(MISS_MSG)) {
+                return;
+            }
+        }
+        final DebugScope currScope = DebugScope.getInstance();
+        final DebugScope.ExtraInfo metaInfo = currScope.getExtraInfo();
+        final long currScopeId = currScope.scopeId();
+        if (metaInfo instanceof MethodMetricsRootScopeInfo) {
+            ResolvedJavaMethod rootMethod = ((MethodMetricsRootScopeInfo) metaInfo).getRootMethod();
+            if (metaInfo instanceof MethodMetricsInlineeScopeInfo) {
+                /*
+                 * if we make use of a method filter(s) together with interception we get a problem
+                 * with inlined methods and their scopes. Inlining will put the inlinee(s) on the
+                 * debug scope context thus Debug.areMethodMetricsEnabled() will yield true if an
+                 * inlinee matches a method filter. Thus we must make sure the root is defined as
+                 * this means the root matched a method filter and therefore the inlinee can be
+                 * safely recorded.
+                 */
+                if (TRACK_INLINED_SCOPES) {
+                    if (threadEntries.get().get(rootMethod) != null) {
+                        Debug.methodMetrics(rootMethod).addToMetric(value, "%s%s", INLINEE_PREFIX, metricName);
+                    }
+                }
+            } else {
+                // when unboxing the thread local on access it must not be null
+                Long cachedId = interceptionCache.get();
+                if (cachedId != null && cachedId == currScopeId) {
+                    interceptionMetrics.get().addToMetric(value, metricName);
+                    if (COUNT_CACHE) {
+                        cacheHit.increment();
+                    }
+                } else {
+                    // avoid the lookup over Debug.methodMetrics
+                    final MethodMetricsImpl impl = (MethodMetricsImpl) getMethodMetrics(rootMethod);
+                    impl.addToMetric(value, metricName);
+                    // cache for next access
+                    interceptionCache.set(currScopeId);
+                    interceptionMetrics.set(impl);
+                    if (COUNT_CACHE) {
+                        cacheMiss.increment();
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsInlineeScopeInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsInlineeScopeInfo.java
new file mode 100644
index 0000000..11f82ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsInlineeScopeInfo.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal.method;
+
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodMetricsInlineeScopeInfo extends MethodMetricsRootScopeInfo {
+
+    MethodMetricsInlineeScopeInfo(ResolvedJavaMethod rootMethod) {
+        super(rootMethod);
+    }
+
+    public static MethodMetricsInlineeScopeInfo create(ResolvedJavaMethod rootMethod) {
+        if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) {
+            return new MethodMetricsInlineeScopeInfo(rootMethod);
+        }
+        return null;
+    }
+
+    public static MethodMetricsInlineeScopeInfo create() {
+        if (GraalDebugConfig.isGlobalMetricsInterceptedByMethodMetricsEnabled()) {
+            ExtraInfo rootInfo = DebugScope.getInstance().getExtraInfo();
+            if (rootInfo instanceof MethodMetricsRootScopeInfo) {
+                return new MethodMetricsInlineeScopeInfo(((MethodMetricsRootScopeInfo) rootInfo).getRootMethod());
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsPrinter.java
new file mode 100644
index 0000000..e74ed66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsPrinter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal.method;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Interface for printing a collection of method metrics (e.g. during shutdown).
+ */
+public interface MethodMetricsPrinter {
+
+    class Options {
+        // @formatter:off
+        @Option(help = "Dump method metrics to stdout on shutdown.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> MethodMeterPrintAscii = new OptionValue<>(false);
+        @Option(help = "Dump method metrics to the given file in CSV format on shutdown.", type = OptionType.Debug)
+        public static final OptionValue<String> MethodMeterFile = new OptionValue<>(null);
+        // @formatter:on
+    }
+
+    static boolean methodMetricsDumpingEnabled() {
+        return MethodMetricsPrinter.Options.MethodMeterPrintAscii.getValue() || MethodMetricsPrinter.Options.MethodMeterFile.getValue() != null;
+    }
+
+    /**
+     * Prints the metrics to a destination specified by the implementor of this interface.
+     *
+     * @param metrics the set of collected method metrics during execution as defined by
+     *            {@link DebugMethodMetrics}.
+     */
+    void printMethodMetrics(Collection<DebugMethodMetrics> metrics);
+
+    class MethodMetricsASCIIPrinter implements MethodMetricsPrinter {
+        private final OutputStream out;
+
+        public MethodMetricsASCIIPrinter(OutputStream out) {
+            this.out = out;
+        }
+
+        @Override
+        public void printMethodMetrics(Collection<DebugMethodMetrics> metrics) {
+            PrintStream p = new PrintStream(out);
+            for (DebugMethodMetrics m : metrics) {
+                ((MethodMetricsImpl) m).dumpASCII(p);
+                p.println();
+            }
+        }
+
+    }
+
+    class MethodMetricsCompositePrinter implements MethodMetricsPrinter {
+        private final List<MethodMetricsPrinter> printers;
+
+        public MethodMetricsCompositePrinter(MethodMetricsPrinter... p) {
+            printers = Arrays.asList(p);
+        }
+
+        public void registerPrinter(MethodMetricsPrinter printer) {
+            printers.add(printer);
+        }
+
+        public void unregisterPrinter(MethodMetricsPrinter printer) {
+            printers.remove(printer);
+        }
+
+        @Override
+        public void printMethodMetrics(Collection<DebugMethodMetrics> metrics) {
+            for (MethodMetricsPrinter p : printers) {
+                p.printMethodMetrics(metrics);
+            }
+        }
+
+    }
+
+    class MethodMetricsCSVFilePrinter implements MethodMetricsPrinter {
+        private FileOutputStream fw;
+
+        public MethodMetricsCSVFilePrinter() {
+            try {
+                fw = new FileOutputStream(new File(Options.MethodMeterFile.getValue()));
+            } catch (IOException e) {
+                TTY.println("Cannot create file %s for method metrics dumping:%s", Options.MethodMeterFile.getValue(), e);
+                throw new Error(e);
+            }
+        }
+
+        @Override
+        public void printMethodMetrics(Collection<DebugMethodMetrics> metrics) {
+            // mm printing creates simple (R-parsable) csv files in long data format
+            if (fw != null && metrics != null) {
+                try (PrintStream p = new PrintStream(fw)) {
+                    for (DebugMethodMetrics m : metrics) {
+                        if (m instanceof MethodMetricsImpl) {
+                            ((MethodMetricsImpl) m).dumpCSV(p);
+                            p.println();
+                        }
+                    }
+                }
+                try {
+                    fw.close();
+                } catch (IOException e) {
+                    throw new Error(e);
+                }
+            }
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsRootScopeInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsRootScopeInfo.java
new file mode 100644
index 0000000..fd8b18d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/method/MethodMetricsRootScopeInfo.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug.internal.method;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodMetricsRootScopeInfo implements ExtraInfo {
+    protected final ResolvedJavaMethod rootMethod;
+
+    MethodMetricsRootScopeInfo(ResolvedJavaMethod rootMethod) {
+        this.rootMethod = rootMethod;
+    }
+
+    public ResolvedJavaMethod getRootMethod() {
+        return rootMethod;
+    }
+
+    public static MethodMetricsRootScopeInfo create(ResolvedJavaMethod rootMethod) {
+        return new MethodMetricsRootScopeInfo(rootMethod);
+    }
+
+    /**
+     * Creates and returns a {@link org.graalvm.compiler.debug.Debug.Scope scope} iff there is no
+     * existing {@linkplain org.graalvm.compiler.debug.internal.DebugScope.ExtraInfo extraInfo}
+     * object of type {@link MethodMetricsRootScopeInfo} present in the current {@link DebugScope
+     * scope}.
+     *
+     * @param method
+     * @return a new {@link org.graalvm.compiler.debug.Debug.Scope scope} or {@code null} iff there
+     *         is already an existing one on the scope
+     */
+    public static Debug.Scope createRootScopeIfAbsent(ResolvedJavaMethod method) {
+        /*
+         * if the current compilation is not triggered from JVMCI we need a valid context root
+         * method for method metrics
+         */
+        return DebugScope.getInstance().getExtraInfo() instanceof MethodMetricsRootScopeInfo ? null : Debug.methodMetricsScope("GraalCompilerRoot", MethodMetricsRootScopeInfo.create(method), true);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java
new file mode 100644
index 0000000..8d23f55
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeMapTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+public class NodeMapTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+        protected TestNode() {
+            super(TYPE);
+        }
+    }
+
+    private Graph graph;
+    private TestNode[] nodes = new TestNode[100];
+    private NodeMap<Integer> map;
+
+    @Before
+    public void before() {
+        // Need to initialize HotSpotGraalRuntime before any Node class is initialized.
+        Graal.getRuntime();
+
+        graph = new Graph();
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = graph.add(new TestNode());
+        }
+        map = new NodeMap<>(graph);
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+    }
+
+    @Test
+    public void testEmpty() {
+        NodeMap<Integer> emptyMap = new NodeMap<>(graph);
+        for (TestNode node : nodes) {
+            assertEquals(null, emptyMap.get(node));
+        }
+    }
+
+    @Test
+    public void testSimple() {
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @Test
+    public void testSimpleChanged() {
+        for (TestNode node : nodes) {
+            map.set(node, 1);
+        }
+        for (TestNode node : nodes) {
+            map.set(node, null);
+        }
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
+
+    @Test
+    public void testNewGet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of get need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        try {
+            map.get(newNode);
+            fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName()));
+        } catch (AssertionError ae) {
+            // thrown when assertions are enabled
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // thrown when assertions are disabled
+        }
+    }
+
+    @Test
+    public void testNewSet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of set need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        try {
+            map.set(newNode, 1);
+            fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName()));
+        } catch (AssertionError ae) {
+            // thrown when assertions are enabled
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // thrown when assertions are disabled
+        }
+    }
+
+    @Test
+    public void testNewGetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        assertEquals(null, map.getAndGrow(newNode));
+    }
+
+    @Test
+    public void testNewSetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        map.setAndGrow(newNode, 1);
+        assertEquals((Integer) 1, map.get(newNode));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java
new file mode 100644
index 0000000..2f8f34f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableContains.contains;
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty;
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+public class NodeUsagesTests {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class Def extends Node {
+        public static final NodeClass<Def> TYPE = NodeClass.create(Def.class);
+
+        protected Def() {
+            super(TYPE);
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class Use extends Node {
+        public static final NodeClass<Use> TYPE = NodeClass.create(Use.class);
+        @Input Def in0;
+        @Input Def in1;
+        @Input Def in2;
+
+        protected Use(Def in0, Def in1, Def in2) {
+            super(TYPE);
+            this.in0 = in0;
+            this.in1 = in1;
+            this.in2 = in2;
+        }
+
+    }
+
+    @Test
+    public void testReplaceAtUsages() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtUsages(def1);
+
+        assertThat(def0.usages(), isEmpty());
+
+        assertEquals(3, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use1));
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicateAll() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> true);
+
+        assertThat(def0.usages(), isEmpty());
+
+        assertEquals(3, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use1));
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicateNone() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> false);
+
+        assertThat(def1.usages(), isEmpty());
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate1() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u == use1);
+
+        assertEquals(1, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use1));
+
+        assertThat(def1.usages(), isNotEmpty());
+
+        assertEquals(2, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate2() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u == use2);
+
+        assertEquals(1, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+
+        assertEquals(2, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+
+        assertThat(def0.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate0() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u == use0);
+
+        assertEquals(1, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+
+        assertThat(def1.usages(), isNotEmpty());
+
+        assertEquals(2, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate02() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u != use1);
+
+        assertEquals(1, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use1));
+
+        assertThat(def0.usages(), isNotEmpty());
+
+        assertEquals(2, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate023() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+        Use use3 = graph.add(new Use(null, null, def0));
+
+        assertEquals(4, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+        assertThat(def0.usages(), contains(use3));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u != use1);
+
+        assertEquals(1, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use1));
+
+        assertThat(def0.usages(), isNotEmpty());
+
+        assertEquals(3, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use2));
+        assertThat(def1.usages(), contains(use3));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate013() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+        Use use3 = graph.add(new Use(null, null, def0));
+
+        assertEquals(4, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+        assertThat(def0.usages(), contains(use3));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u != use2);
+
+        assertEquals(1, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+
+        assertEquals(3, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use1));
+        assertThat(def1.usages(), contains(use3));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate203() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+        Use use3 = graph.add(new Use(null, null, def0));
+
+        assertEquals(4, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+        assertThat(def0.usages(), contains(use3));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u == use2);
+
+        assertEquals(1, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use3));
+
+        assertThat(def0.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate01() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u != use2);
+
+        assertEquals(1, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+
+        assertEquals(2, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use0));
+        assertThat(def1.usages(), contains(use1));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+
+    @Test
+    public void testReplaceAtUsagesWithPredicate12() {
+        Graph graph = new Graph();
+        Def def0 = graph.add(new Def());
+        Def def1 = graph.add(new Def());
+        Use use0 = graph.add(new Use(def0, null, null));
+        Use use1 = graph.add(new Use(null, def0, null));
+        Use use2 = graph.add(new Use(null, null, def0));
+
+        assertEquals(3, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+        assertThat(def0.usages(), contains(use1));
+        assertThat(def0.usages(), contains(use2));
+
+        assertThat(def0.usages(), isNotEmpty());
+        assertThat(def1.usages(), isEmpty());
+
+        def0.replaceAtMatchingUsages(def1, u -> u != use0);
+
+        assertEquals(1, def0.getUsageCount());
+        assertThat(def0.usages(), contains(use0));
+
+        assertThat(def0.usages(), isNotEmpty());
+
+        assertEquals(2, def1.getUsageCount());
+        assertThat(def1.usages(), contains(use1));
+        assertThat(def1.usages(), contains(use2));
+
+        assertThat(def1.usages(), isNotEmpty());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeValidationChecksTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeValidationChecksTest.java
new file mode 100644
index 0000000..18d822d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeValidationChecksTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+public class NodeValidationChecksTest {
+
+    @NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+        @Input TestNode input;
+        @Successor TestNode successor;
+
+        protected TestNode(TestNode input, TestNode successor) {
+            super(TYPE);
+            this.input = input;
+            this.successor = successor;
+        }
+    }
+
+    @Test
+    public void testInputNotAlive() {
+        Graph graph = new Graph();
+        TestNode node = new TestNode(null, null);
+        try {
+            graph.add(new TestNode(node, null));
+            Assert.fail("Exception expected.");
+        } catch (AssertionError e) {
+            Assert.assertTrue(e.getMessage().contains("Input"));
+            Assert.assertTrue(e.getMessage().contains("not alive"));
+        }
+    }
+
+    @Test
+    public void testSuccessorNotAlive() {
+        Graph graph = new Graph();
+        TestNode node = new TestNode(null, null);
+        try {
+            graph.add(new TestNode(null, node));
+            Assert.fail("Exception expected.");
+        } catch (AssertionError e) {
+            Assert.assertTrue(e.getMessage().contains("Successor"));
+            Assert.assertTrue(e.getMessage().contains("not alive"));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TestNodeInterface.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TestNodeInterface.java
new file mode 100644
index 0000000..85f166f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TestNodeInterface.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+public interface TestNodeInterface {
+
+    String getName();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest.java
new file mode 100644
index 0000000..269143b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+public class TypedNodeIteratorTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class TestNode extends Node implements IterableNodeType, TestNodeInterface {
+
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+        protected final String name;
+
+        protected TestNode(String name) {
+            super(TYPE);
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    @Test
+    public void singleNodeTest() {
+        Graph graph = new Graph();
+        graph.add(new TestNode("a"));
+        assertTrue(graph.hasNode(TestNode.TYPE));
+        assertEquals("a", toString(graph.getNodes(TestNode.TYPE)));
+    }
+
+    @Test
+    public void deletingNodeTest() {
+        TestNode testNode = new TestNode("a");
+        Graph graph = new Graph();
+        graph.add(testNode);
+        testNode.safeDelete();
+        assertEquals("", toString(graph.getNodes(TestNode.TYPE)));
+    }
+
+    @Test
+    public void deleteAndAddTest() {
+        TestNode testNode = new TestNode("b");
+        Graph graph = new Graph();
+        graph.add(new TestNode("a"));
+        graph.add(testNode);
+        testNode.safeDelete();
+        assertEquals("a", toString(graph.getNodes(TestNode.TYPE)));
+        graph.add(new TestNode("c"));
+        assertEquals("ac", toString(graph.getNodes(TestNode.TYPE)));
+    }
+
+    @Test
+    public void iteratorBehaviorTest() {
+        Graph graph = new Graph();
+        graph.add(new TestNode("a"));
+        Iterator<TestNode> iterator = graph.getNodes(TestNode.TYPE).iterator();
+        assertTrue(iterator.hasNext());
+        assertEquals("a", iterator.next().getName());
+        assertFalse(iterator.hasNext());
+        graph.add(new TestNode("b"));
+        assertTrue(iterator.hasNext());
+        assertEquals("b", iterator.next().getName());
+        assertFalse(iterator.hasNext());
+        TestNode c = new TestNode("c");
+        graph.add(c);
+        assertTrue(iterator.hasNext());
+        c.safeDelete();
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void complicatedIterationTest() {
+        Graph graph = new Graph();
+        graph.add(new TestNode("a"));
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
+            String name = tn.getName();
+            for (int i = 0; i < name.length(); ++i) {
+                char c = name.charAt(i);
+                if (c == 'a') {
+                    tn.safeDelete();
+                    graph.add(new TestNode("b"));
+                    graph.add(new TestNode("c"));
+                } else if (c == 'b') {
+                    tn.safeDelete();
+                } else if (c == 'c') {
+                    graph.add(new TestNode("d"));
+                    graph.add(new TestNode("e"));
+                    graph.add(new TestNode("d"));
+                    graph.add(new TestNode("e"));
+                    graph.add(new TestNode("e"));
+                    graph.add(new TestNode("d"));
+                    graph.add(new TestNode("e"));
+                    graph.add(new TestNode("d"));
+                } else if (c == 'd') {
+                    for (TestNode tn2 : graph.getNodes(TestNode.TYPE)) {
+                        if (tn2.getName().equals("e")) {
+                            tn2.safeDelete();
+                        } else if (tn2.getName().equals("c")) {
+                            tn2.safeDelete();
+                        }
+                    }
+                } else if (c == 'e') {
+                    fail("All e nodes must have been deleted by visiting the d node");
+                }
+            }
+        }
+        assertEquals("dddd", toString(graph.getNodes(TestNode.TYPE)));
+    }
+
+    @Test
+    public void addingNodeDuringIterationTest() {
+        Graph graph = new Graph();
+        graph.add(new TestNode("a"));
+        StringBuilder sb = new StringBuilder();
+        int z = 0;
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
+            if (z == 0) {
+                graph.add(new TestNode("b"));
+            }
+            sb.append(tn.getName());
+            z++;
+        }
+        assertEquals(2, z);
+        assertEquals("ab", sb.toString());
+        z = 0;
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
+            if (z == 0) {
+                graph.add(new TestNode("c"));
+            }
+            assertNotNull(tn);
+            z++;
+        }
+        assertEquals(3, z);
+    }
+
+    public static String toString(Iterable<? extends TestNodeInterface> nodes) {
+        StringBuilder sb = new StringBuilder();
+        for (TestNodeInterface tn : nodes) {
+            sb.append(tn.getName());
+        }
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest2.java
new file mode 100644
index 0000000..c56b19c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/TypedNodeIteratorTest2.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+public class TypedNodeIteratorTest2 {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class NodeA extends Node implements TestNodeInterface {
+
+        public static final NodeClass<NodeA> TYPE = NodeClass.create(NodeA.class);
+        protected final String name;
+
+        protected NodeA(String name) {
+            this(TYPE, name);
+        }
+
+        protected NodeA(NodeClass<? extends NodeA> c, String name) {
+            super(c);
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class NodeB extends NodeA implements IterableNodeType {
+        public static final NodeClass<NodeB> TYPE = NodeClass.create(NodeB.class);
+
+        protected NodeB(String name) {
+            this(TYPE, name);
+        }
+
+        protected NodeB(NodeClass<? extends NodeB> c, String name) {
+            super(c, name);
+        }
+
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class NodeC extends NodeB {
+        public static final NodeClass<NodeC> TYPE = NodeClass.create(NodeC.class);
+
+        protected NodeC(String name) {
+            this(TYPE, name);
+        }
+
+        protected NodeC(NodeClass<? extends NodeC> c, String name) {
+            super(c, name);
+        }
+
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class NodeD extends NodeC {
+        public static final NodeClass<NodeD> TYPE = NodeClass.create(NodeD.class);
+
+        protected NodeD(String name) {
+            super(TYPE, name);
+        }
+
+    }
+
+    @Test
+    public void simpleSubclassTest() {
+        Graph graph = new Graph();
+        graph.add(new NodeB("b"));
+        graph.add(new NodeD("d"));
+
+        Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.TYPE)));
+        Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.TYPE)));
+    }
+
+    @Test
+    public void addingNodeDuringIterationTest() {
+        Graph graph = new Graph();
+        graph.add(new NodeB("b1"));
+        NodeD d1 = graph.add(new NodeD("d1"));
+        StringBuilder sb = new StringBuilder();
+        for (NodeB tn : graph.getNodes(NodeB.TYPE)) {
+            if (tn == d1) {
+                graph.add(new NodeB("b2"));
+            }
+            sb.append(tn.getName());
+        }
+        assertEquals("b1d1b2", sb.toString());
+        for (NodeB tn : graph.getNodes(NodeB.TYPE)) {
+            if (tn == d1) {
+                graph.add(new NodeB("b3"));
+            }
+            assertNotNull(tn);
+        }
+        assertEquals(4, graph.getNodes(NodeB.TYPE).count());
+        assertEquals(1, graph.getNodes(NodeD.TYPE).count());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableContains.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableContains.java
new file mode 100644
index 0000000..360f411
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableContains.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test.matchers;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+public class NodeIterableContains<T extends Node> extends TypeSafeDiagnosingMatcher<NodeIterable<T>> {
+    private T node;
+
+    public NodeIterableContains(T node) {
+        this.node = node;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("is a NodeIterable containing ").appendValue(node);
+    }
+
+    public static <T extends Node> NodeIterableContains<T> contains(T node) {
+        return new NodeIterableContains<>(node);
+    }
+
+    @Override
+    protected boolean matchesSafely(NodeIterable<T> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a NodeIterable that does not contain ").appendValue(node);
+        return iterable.contains(node);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableCount.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableCount.java
new file mode 100644
index 0000000..51d63ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableCount.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test.matchers;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+public class NodeIterableCount extends TypeSafeDiagnosingMatcher<NodeIterable<?>> {
+    private int count;
+
+    public NodeIterableCount(int count) {
+        this.count = count;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("is a NodeIterable containing ").appendValue(count).appendText(" elements");
+    }
+
+    public static NodeIterableCount hasCount(int count) {
+        return new NodeIterableCount(count);
+    }
+
+    @Override
+    protected boolean matchesSafely(NodeIterable<?> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a NodeIterable containing ").appendValue(iterable.count()).appendText(" elements");
+        return iterable.count() == count;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableIsEmpty.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableIsEmpty.java
new file mode 100644
index 0000000..1710099
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/matchers/NodeIterableIsEmpty.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test.matchers;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.hamcrest.core.IsNot;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+public class NodeIterableIsEmpty extends TypeSafeDiagnosingMatcher<NodeIterable<?>> {
+
+    private static final NodeIterableIsEmpty INSTANCE = new NodeIterableIsEmpty();
+
+    @Override
+    public boolean matchesSafely(NodeIterable<?> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a non-empty NodeIterable");
+        return iterable.isEmpty();
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("is an empty NodeIterable");
+    }
+
+    public static Matcher<NodeIterable<?>> isEmpty() {
+        return INSTANCE;
+    }
+
+    public static Matcher<NodeIterable<?>> isNotEmpty() {
+        return IsNot.not(INSTANCE);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml
new file mode 100644
index 0000000..f18b015
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+    This configuration file was written by the eclipse-cs plugin configuration editor
+-->
+<!--
+    Checkstyle-Configuration: Checks
+    Description: none
+-->
+<module name="Checker">
+  <property name="severity" value="error"/>
+  <module name="TreeWalker">
+    <module name="AvoidStarImport">
+      <property name="allowClassImports" value="false"/>
+      <property name="allowStaticMemberImports" value="false"/>
+    </module>
+    <property name="tabWidth" value="4"/>
+    <module name="FileContentsHolder"/>
+    <module name="JavadocStyle">
+      <property name="checkHtml" value="false"/>
+    </module>
+    <module name="LocalFinalVariableName"/>
+    <module name="LocalVariableName"/>
+    <module name="MemberName">
+      <property name="format" value="^(([a-z][a-zA-Z0-9]*$)|(_[A-Z][a-zA-Z0-9]*_[a-z][a-zA-Z0-9]*$))"/>
+    </module>
+    <module name="MethodName"/>
+    <module name="PackageName"/>
+    <module name="ParameterName"/>
+    <module name="TypeName">
+      <property name="format" value="^[A-Z][_a-zA-Z0-9]*$"/>
+    </module>
+    <module name="RedundantImport"/>
+    <module name="LineLength">
+      <property name="max" value="250"/>
+    </module>
+    <module name="MethodParamPad"/>
+    <module name="NoWhitespaceAfter">
+      <property name="tokens" value="ARRAY_INIT,BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
+    </module>
+    <module name="NoWhitespaceBefore">
+      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+    </module>
+    <module name="ParenPad"/>
+    <module name="TypecastParenPad">
+      <property name="tokens" value="RPAREN,TYPECAST"/>
+    </module>
+    <module name="WhitespaceAfter"/>
+    <module name="WhitespaceAround">
+      <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
+    </module>
+    <module name="RedundantModifier"/>
+    <module name="AvoidNestedBlocks">
+      <property name="allowInSwitchCase" value="true"/>
+    </module>
+    <module name="EmptyBlock">
+      <property name="option" value="text"/>
+      <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
+    </module>
+    <module name="LeftCurly"/>
+    <module name="NeedBraces"/>
+    <module name="RightCurly"/>
+    <module name="EmptyStatement"/>
+    <module name="HiddenField">
+      <property name="severity" value="ignore"/>
+      <property name="ignoreConstructorParameter" value="true"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="FinalClass"/>
+    <module name="HideUtilityClassConstructor">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ArrayTypeStyle"/>
+    <module name="UpperEll"/>
+    <module name="FallThrough"/>
+    <module name="FinalLocalVariable">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="MultipleVariableDeclarations"/>
+    <module name="StringLiteralEquality">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="SuperFinalize"/>
+    <module name="UnnecessaryParentheses">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="Indentation">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="StaticVariableName">
+      <property name="format" value="^[A-Za-z][a-zA-Z0-9]*$"/>
+    </module>
+    <module name="EmptyForInitializerPad"/>
+    <module name="EmptyForIteratorPad"/>
+    <module name="ModifierOrder"/>
+    <module name="DefaultComesLast"/>
+    <module name="InnerAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ModifiedControlVariable"/>
+    <module name="MutableException">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ParameterAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="format" value="\s$"/>
+      <property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="illegal space before a comma"/>
+      <property name="format" value=" ,"/>
+      <property name="message" value="illegal space before a comma"/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="[^\x00-\x7F]"/>
+      <property name="message" value="Only use ASCII characters."/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
+      <property name="message" value="Don't use old synchronized collection classes"/>
+    </module>
+  </module>
+  <module name="RegexpHeader">
+    <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
+    <property name="fileExtensions" value="java"/>
+  </module>
+  <module name="FileTabCharacter">
+    <property name="severity" value="error"/>
+    <property name="fileExtensions" value="java"/>
+  </module>
+  <module name="NewlineAtEndOfFile">
+    <property name="lineSeparator" value="lf"/>
+  </module>
+  <module name="Translation"/>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop constant name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume constant name check"/>
+    <property name="checkFormat" value="ConstantNameCheck"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Allow non-conforming constant names"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop method name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume method name check"/>
+    <property name="checkFormat" value="MethodName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable method name checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop parameter assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume parameter assignment check"/>
+    <property name="checkFormat" value="ParameterAssignment"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable Parameter Assignment"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop final variable check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume final variable check"/>
+    <property name="checkFormat" value="FinalLocalVariable"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable final variable checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop"/>
+    <property name="onCommentFormat" value="Checkstyle: resume"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop inner assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume inner assignment check"/>
+    <property name="checkFormat" value="InnerAssignment"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable inner assignment checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop field name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume field name check"/>
+    <property name="checkFormat" value="MemberName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable field name checks"/>
+  </module>
+  <module name="RegexpMultiline">
+    <metadata name="net.sf.eclipsecs.core.comment" value="illegal Windows line ending"/>
+    <property name="format" value="\r\n"/>
+    <property name="message" value="illegal Windows line ending"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop header check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume header check"/>
+    <property name="checkFormat" value=".*Header"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable header checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop line length check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume line length check"/>
+    <property name="checkFormat" value="LineLength"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: start generated"/>
+    <property name="onCommentFormat" value="CheckStyle: stop generated"/>
+    <property name="checkFormat" value=".*Name|.*LineLength|.*Header"/>
+  </module>
+</module>
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java
new file mode 100644
index 0000000..4212297
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+/**
+ * This class is a container of a graph that needs to be readonly and optionally a lazily created
+ * mutable copy of the graph.
+ */
+public final class CachedGraph<G extends Graph> {
+
+    private final G readonlyCopy;
+    private G mutableCopy;
+
+    private CachedGraph(G readonlyCopy, G mutableCopy) {
+        this.readonlyCopy = readonlyCopy;
+        this.mutableCopy = mutableCopy;
+    }
+
+    public static <G extends Graph> CachedGraph<G> fromReadonlyCopy(G graph) {
+        return new CachedGraph<>(graph, null);
+    }
+
+    public static <G extends Graph> CachedGraph<G> fromMutableCopy(G graph) {
+        return new CachedGraph<>(graph, graph);
+    }
+
+    public G getReadonlyCopy() {
+        if (hasMutableCopy()) {
+            return mutableCopy;
+        }
+        return readonlyCopy;
+    }
+
+    public boolean hasMutableCopy() {
+        return mutableCopy != null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public G getMutableCopy(Consumer<Map<Node, Node>> duplicationMapCallback) {
+        if (!hasMutableCopy()) {
+            mutableCopy = (G) readonlyCopy.copy(duplicationMapCallback);
+        }
+        return mutableCopy;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/DefaultNodeCollectionsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/DefaultNodeCollectionsProvider.java
new file mode 100644
index 0000000..70da681
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/DefaultNodeCollectionsProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.api.collections.DefaultCollectionsProvider;
+
+/**
+ * A default implementation of {@link NodeCollectionsProvider} that creates standard JDK collection
+ * class objects.
+ */
+public class DefaultNodeCollectionsProvider extends DefaultCollectionsProvider implements NodeCollectionsProvider {
+
+    @Override
+    public <E extends Node> Set<E> newNodeIdentitySet() {
+        return Collections.newSetFromMap(newNodeIdentityMap());
+    }
+
+    @Override
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap() {
+        return new IdentityHashMap<>();
+    }
+
+    @Override
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap(int expectedMaxSize) {
+        return new IdentityHashMap<>(expectedMaxSize);
+    }
+
+    @Override
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap(Map<K, V> initFrom) {
+        return new IdentityHashMap<>(initFrom);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java
new file mode 100644
index 0000000..4c36413
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
+import static org.graalvm.compiler.graph.Node.NOT_ITERABLE;
+import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.FieldsScanner;
+import org.graalvm.compiler.graph.NodeClass.EdgeInfo;
+
+/**
+ * Describes {@link Node} fields representing the set of inputs for the node or the set of the
+ * node's successors.
+ */
+public abstract class Edges extends Fields {
+
+    /**
+     * Constants denoting whether a set of edges are inputs or successors.
+     */
+    public enum Type {
+        Inputs,
+        Successors;
+    }
+
+    private final int directCount;
+    private final Type type;
+
+    public Edges(Type type, int directCount, ArrayList<? extends FieldsScanner.FieldInfo> edges) {
+        super(edges);
+        this.type = type;
+        this.directCount = directCount;
+    }
+
+    public static void translateInto(Edges edges, ArrayList<EdgeInfo> infos) {
+        for (int index = 0; index < edges.getCount(); index++) {
+            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index)));
+        }
+    }
+
+    public static Node getNodeUnsafe(Node node, long offset) {
+        return (Node) UNSAFE.getObject(node, offset);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static NodeList<Node> getNodeListUnsafe(Node node, long offset) {
+        return (NodeList<Node>) UNSAFE.getObject(node, offset);
+    }
+
+    private static void putNodeUnsafe(Node node, long offset, Node value) {
+        UNSAFE.putObject(node, offset, value);
+    }
+
+    private static void putNodeListUnsafe(Node node, long offset, NodeList<?> value) {
+        UNSAFE.putObject(node, offset, value);
+    }
+
+    /**
+     * Get the number of direct edges represented by this object. A direct edge goes directly to
+     * another {@link Node}. An indirect edge goes via a {@link NodeList}.
+     */
+    public int getDirectCount() {
+        return directCount;
+    }
+
+    /**
+     * Gets the {@link Node} at the end point of a {@linkplain #getDirectCount() direct} edge.
+     *
+     * @param node one end point of the edge
+     * @param index the index of a non-list the edge (must be less than {@link #getDirectCount()})
+     * @return the Node at the other edge of the requested edge
+     */
+    public static Node getNode(Node node, long[] offsets, int index) {
+        return getNodeUnsafe(node, offsets[index]);
+    }
+
+    /**
+     * Gets the {@link NodeList} at the end point of a {@linkplain #getDirectCount() direct} edge.
+     *
+     * @param node one end point of the edge
+     * @param index the index of a non-list the edge (must be equal to or greater than
+     *            {@link #getDirectCount()})
+     * @return the {@link NodeList} at the other edge of the requested edge
+     */
+    public static NodeList<Node> getNodeList(Node node, long[] offsets, int index) {
+        return getNodeListUnsafe(node, offsets[index]);
+    }
+
+    /**
+     * Clear edges in a given node. This is accomplished by setting {@linkplain #getDirectCount()
+     * direct} edges to null and replacing the lists containing indirect edges with new lists. The
+     * latter is important so that this method can be used to clear the edges of cloned nodes.
+     *
+     * @param node the node whose edges are to be cleared
+     */
+    public void clear(Node node) {
+        final long[] curOffsets = this.offsets;
+        final Type curType = this.type;
+        int index = 0;
+        int curDirectCount = getDirectCount();
+        while (index < curDirectCount) {
+            initializeNode(node, index++, null);
+        }
+        int curCount = getCount();
+        while (index < curCount) {
+            NodeList<Node> list = getNodeList(node, curOffsets, index);
+            if (list != null) {
+                int size = list.initialSize;
+                NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+
+                // replacing with a new list object is the expected behavior!
+                initializeList(node, index, newList);
+            }
+            index++;
+        }
+    }
+
+    /**
+     * Initializes the list edges in a given node based on the size of the list edges in a prototype
+     * node.
+     *
+     * @param node the node whose list edges are to be initialized
+     * @param prototype the node whose list edge sizes are used when creating new edge lists
+     */
+    public void initializeLists(Node node, Node prototype) {
+        int index = getDirectCount();
+        final long[] curOffsets = this.offsets;
+        final Edges.Type curType = this.type;
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(prototype, curOffsets, index);
+            if (list != null) {
+                int size = list.initialSize;
+                NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+                initializeList(node, index, newList);
+            }
+            index++;
+        }
+    }
+
+    /**
+     * Copies edges from {@code fromNode} to {@code toNode}. The nodes are expected to be of the
+     * exact same type.
+     *
+     * @param fromNode the node from which the edges should be copied.
+     * @param toNode the node to which the edges should be copied.
+     */
+    public void copy(Node fromNode, Node toNode) {
+        assert fromNode != toNode;
+        assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz();
+        int index = 0;
+        final long[] curOffsets = this.offsets;
+        final Type curType = this.type;
+        int curDirectCount = getDirectCount();
+        while (index < curDirectCount) {
+            initializeNode(toNode, index, getNode(fromNode, curOffsets, index));
+            index++;
+        }
+        int curCount = getCount();
+        while (index < curCount) {
+            NodeList<Node> list = getNodeList(toNode, curOffsets, index);
+            NodeList<Node> fromList = getNodeList(fromNode, curOffsets, index);
+            if (list == null || list == fromList) {
+                list = curType == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList);
+                initializeList(toNode, index, list);
+            } else {
+                list.copy(fromList);
+            }
+            index++;
+        }
+    }
+
+    @Override
+    public void set(Object node, int index, Object value) {
+        throw new IllegalArgumentException("Cannot call set on " + this);
+    }
+
+    /**
+     * Sets the value of a given edge without notifying the new and old nodes on the other end of
+     * the edge of the change.
+     *
+     * @param node the node whose edge is to be updated
+     * @param index the index of the edge (between 0 and {@link #getCount()})
+     * @param value the node to be written to the edge
+     */
+    public void initializeNode(Node node, int index, Node value) {
+        verifyUpdateValid(node, index, value);
+        putNodeUnsafe(node, offsets[index], value);
+    }
+
+    public void initializeList(Node node, int index, NodeList<Node> value) {
+        verifyUpdateValid(node, index, value);
+        putNodeListUnsafe(node, offsets[index], value);
+    }
+
+    private void verifyUpdateValid(Node node, int index, Object newValue) {
+        if (newValue != null && !getType(index).isAssignableFrom(newValue.getClass())) {
+            throw new IllegalArgumentException("Can not assign " + newValue.getClass() + " to " + getType(index) + " in " + node);
+        }
+    }
+
+    /**
+     * Sets the value of a given edge and notifies the new and old nodes on the other end of the
+     * edge of the change.
+     *
+     * @param node the node whose edge is to be updated
+     * @param index the index of the edge (between 0 and {@link #getCount()})
+     * @param value the node to be written to the edge
+     */
+    public void setNode(Node node, int index, Node value) {
+        assert index < directCount;
+        Node old = getNodeUnsafe(node, offsets[index]);
+        initializeNode(node, index, value);
+        update(node, old, value);
+    }
+
+    public abstract void update(Node node, Node oldValue, Node newValue);
+
+    public boolean contains(Node node, Node value) {
+        final long[] curOffsets = this.offsets;
+        for (int i = 0; i < directCount; i++) {
+            if (getNode(node, curOffsets, i) == value) {
+                return true;
+            }
+        }
+        for (int i = directCount; i < getCount(); i++) {
+            NodeList<?> curList = getNodeList(node, curOffsets, i);
+            if (curList != null && curList.contains(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * An iterator that will iterate over edges.
+     *
+     * An iterator of this type will not return null values, unless edges are modified concurrently.
+     * Concurrent modifications are detected by an assertion on a best-effort basis.
+     */
+    private static class EdgesIterator implements Iterator<Position> {
+        protected final Node node;
+        protected final Edges edges;
+        protected int index;
+        protected int subIndex;
+        protected boolean needsForward;
+        protected final int directCount;
+        protected final long[] offsets;
+
+        /**
+         * Creates an iterator that will iterate over some given edges in a given node.
+         */
+        EdgesIterator(Node node, Edges edges) {
+            this.node = node;
+            this.edges = edges;
+            index = NOT_ITERABLE;
+            subIndex = 0;
+            needsForward = true;
+            this.directCount = edges.getDirectCount();
+            this.offsets = edges.getOffsets();
+        }
+
+        void forward() {
+            needsForward = false;
+            if (index < directCount) {
+                index++;
+                if (index < directCount) {
+                    return;
+                }
+            } else {
+                subIndex++;
+            }
+            if (index < edges.getCount()) {
+                forwardNodeList();
+            }
+        }
+
+        private void forwardNodeList() {
+            do {
+                NodeList<?> list = Edges.getNodeList(node, offsets, index);
+                if (list != null) {
+                    if (subIndex < list.size()) {
+                        return;
+                    }
+                }
+                subIndex = 0;
+                index++;
+            } while (index < edges.getCount());
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (needsForward) {
+                forward();
+            }
+            return index < edges.getCount();
+        }
+
+        @Override
+        public Position next() {
+            if (needsForward) {
+                forward();
+            }
+            needsForward = true;
+            if (index < directCount) {
+                return new Position(edges, index, NOT_ITERABLE);
+            } else {
+                return new Position(edges, index, subIndex);
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static final class EdgesWithModCountIterator extends EdgesIterator {
+        private final int modCount;
+
+        private EdgesWithModCountIterator(Node node, Edges edges) {
+            super(node, edges);
+            assert isModificationCountsEnabled();
+            this.modCount = node.modCount();
+        }
+
+        @Override
+        public boolean hasNext() {
+            try {
+                return super.hasNext();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+
+        @Override
+        public Position next() {
+            try {
+                return super.next();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+    }
+
+    public Iterable<Position> getPositionsIterable(final Node node) {
+        return new Iterable<Position>() {
+
+            @Override
+            public Iterator<Position> iterator() {
+                if (isModificationCountsEnabled()) {
+                    return new EdgesWithModCountIterator(node, Edges.this);
+                } else {
+                    return new EdgesIterator(node, Edges.this);
+                }
+            }
+        };
+    }
+
+    public Type type() {
+        return type;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraalGraphError.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraalGraphError.java
new file mode 100644
index 0000000..48927ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraalGraphError.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import org.graalvm.compiler.debug.GraalError;
+
+/**
+ * This error is the graph/node aware extension of {@link GraalError}.
+ */
+public class GraalGraphError extends GraalError {
+
+    private static final long serialVersionUID = -989290015525497919L;
+    private Node node;
+    private Graph graph;
+
+    /**
+     * This constructor creates a {@link GraalGraphError} with a message assembled via
+     * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
+     * always generate the same output.
+     *
+     * @param msg the message that will be associated with the error, in String.format syntax
+     * @param args parameters to String.format - parameters that implement {@link Iterable} will be
+     *            expanded into a [x, x, ...] representation.
+     */
+    public GraalGraphError(String msg, Object... args) {
+        super(msg, args);
+    }
+
+    /**
+     * This constructor creates a {@link GraalGraphError} for a given causing Throwable instance.
+     *
+     * @param cause the original exception that contains additional information on this error
+     */
+    public GraalGraphError(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * This constructor creates a {@link GraalGraphError} from a given GraalError instance.
+     *
+     * @param e the original GraalError
+     */
+    protected GraalGraphError(GraalError e) {
+        super(e);
+        if (e instanceof GraalGraphError) {
+            node = ((GraalGraphError) e).node;
+            graph = ((GraalGraphError) e).graph;
+        }
+    }
+
+    /**
+     * Adds a graph to the context of this VerificationError. The first graph added via this method
+     * will be returned by {@link #graph()}.
+     *
+     * @param newGraph the graph which is in a incorrect state, if the verification error was not
+     *            caused by a specific node
+     */
+    GraalGraphError addContext(Graph newGraph) {
+        if (newGraph != this.graph) {
+            addContext("graph", newGraph);
+            if (this.graph == null) {
+                this.graph = newGraph;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Adds a node to the context of this VerificationError. The first node added via this method
+     * will be returned by {@link #node()}.
+     *
+     * @param newNode the node which is in a incorrect state, if the verification error was caused
+     *            by a node
+     */
+    public GraalGraphError addContext(Node newNode) {
+        if (newNode != this.node) {
+            addContext("node", newNode);
+            if (this.node == null) {
+                this.node = newNode;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Transform a GraalError into a GraalGraphInternalError and add a graph to the context.
+     *
+     * @param e the previous error
+     * @param newGraph the graph which is in a incorrect state, if the verification error was not
+     *            caused by a specific node
+     */
+    public static GraalGraphError transformAndAddContext(GraalError e, Graph newGraph) {
+        GraalGraphError graphError;
+        if (e instanceof GraalGraphError) {
+            graphError = (GraalGraphError) e;
+        } else {
+            graphError = new GraalGraphError(e);
+        }
+        return graphError.addContext(newGraph);
+    }
+
+    /**
+     * Transform a GraalError into a GraalGraphInternalError and add a node to the context.
+     *
+     * @param e the previous error
+     * @param newNode the node which is in a incorrect state, if the verification error was caused
+     *            by a node
+     */
+    public static GraalGraphError transformAndAddContext(GraalError e, Node newNode) {
+        GraalGraphError graphError;
+        if (e instanceof GraalGraphError) {
+            graphError = (GraalGraphError) e;
+        } else {
+            graphError = new GraalGraphError(e);
+        }
+        return graphError.addContext(newNode);
+    }
+
+    public Node node() {
+        return node;
+    }
+
+    public Graph graph() {
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java
new file mode 100644
index 0000000..8e99606
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java
@@ -0,0 +1,1113 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * This class is a graph container, it contains the set of nodes that belong to this graph.
+ */
+public class Graph {
+
+    public static class Options {
+        @Option(help = "Verify graphs often during compilation when assertions are turned on", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> VerifyGraalGraphs = new OptionValue<>(true);
+        @Option(help = "Perform expensive verification of graph inputs, usages, successors and predecessors", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> VerifyGraalGraphEdges = new OptionValue<>(false);
+        @Option(help = "Graal graph compression is performed when percent of live nodes falls below this value", type = OptionType.Debug)//
+        public static final OptionValue<Integer> GraphCompressionThreshold = new OptionValue<>(70);
+        @Option(help = "Use Unsafe to clone graph nodes thus avoiding copying fields that will be re-initialized anyway", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> CloneNodesWithUnsafe = new OptionValue<>(true);
+    }
+
+    public final String name;
+
+    /**
+     * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time.
+     */
+    Node[] nodes;
+
+    /**
+     * Source information to associate with newly created nodes.
+     */
+    NodeSourcePosition currentNodeSourcePosition;
+
+    /**
+     * Records if updating of node source information is required when performing inlining.
+     */
+    boolean seenNodeSourcePosition;
+
+    /**
+     * The number of valid entries in {@link #nodes}.
+     */
+    int nodesSize;
+
+    /**
+     * Records the modification count for nodes. This is only used in assertions.
+     */
+    private int[] nodeModCounts;
+
+    /**
+     * Records the modification count for nodes' usage lists. This is only used in assertions.
+     */
+    private int[] nodeUsageModCounts;
+
+    // these two arrays contain one entry for each NodeClass, indexed by NodeClass.iterableId.
+    // they contain the first and last pointer to a linked list of all nodes with this type.
+    private final ArrayList<Node> iterableNodesFirst;
+    private final ArrayList<Node> iterableNodesLast;
+
+    private int nodesDeletedSinceLastCompression;
+    private int nodesDeletedBeforeLastCompression;
+
+    /**
+     * The number of times this graph has been compressed.
+     */
+    int compressions;
+
+    NodeEventListener nodeEventListener;
+
+    /**
+     * Used to global value number {@link ValueNumberable} {@linkplain NodeClass#isLeafNode() leaf}
+     * nodes.
+     */
+    private final HashMap<CacheEntry, Node> cachedLeafNodes = CollectionsFactory.newMap();
+
+    /*
+     * Indicates that the graph should no longer be modified. Frozen graphs can be used my multiple
+     * threads so it's only safe to read them.
+     */
+    private boolean isFrozen = false;
+
+    /**
+     * Entry in {@link Graph#cachedLeafNodes}.
+     */
+    private static final class CacheEntry {
+
+        private final Node node;
+
+        CacheEntry(Node node) {
+            assert node.getNodeClass().valueNumberable();
+            assert node.getNodeClass().isLeafNode();
+            this.node = node;
+        }
+
+        @Override
+        public int hashCode() {
+            return node.getNodeClass().valueNumber(node);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof CacheEntry) {
+                CacheEntry other = (CacheEntry) obj;
+                if (other.node.getClass() == node.getClass()) {
+                    return node.valueEquals(other.node);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return node.toString();
+        }
+    }
+
+    private class NodeSourcePositionScope implements DebugCloseable {
+        private final NodeSourcePosition previous;
+
+        NodeSourcePositionScope(NodeSourcePosition sourcePosition) {
+            previous = currentNodeSourcePosition;
+            currentNodeSourcePosition = sourcePosition;
+        }
+
+        @Override
+        public void close() {
+            currentNodeSourcePosition = previous;
+        }
+    }
+
+    public NodeSourcePosition currentNodeSourcePosition() {
+        return currentNodeSourcePosition;
+    }
+
+    /**
+     * Opens a scope in which the source information from {@code node} is copied into nodes created
+     * within the scope. If {@code node} has no source information information, no scope is opened
+     * and {@code null} is returned.
+     *
+     * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope
+     *         was opened
+     */
+    public DebugCloseable withNodeSourcePosition(Node node) {
+        return withNodeSourcePosition(node.sourcePosition);
+    }
+
+    /**
+     * Opens a scope in which {@code sourcePosition} is copied into nodes created within the scope.
+     * If {@code sourcePosition == null}, no scope is opened and {@code null} is returned.
+     *
+     * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope
+     *         was opened
+     */
+    public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) {
+        return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
+    }
+
+    /**
+     * Opens a scope in which newly created nodes do not get any source information added.
+     *
+     * @return a {@link DebugCloseable} for managing the opened scope
+     */
+    public DebugCloseable withoutNodeSourcePosition() {
+        return new NodeSourcePositionScope(null);
+    }
+
+    /**
+     * Determines if this graph might contain nodes with source information. This is mainly useful
+     * to short circuit logic for updating those positions after inlining since that requires
+     * visiting every node in the graph.
+     */
+    public boolean mayHaveNodeSourcePosition() {
+        assert seenNodeSourcePosition || verifyHasNoSourcePosition();
+        return seenNodeSourcePosition;
+    }
+
+    private boolean verifyHasNoSourcePosition() {
+        for (Node node : getNodes()) {
+            assert node.getNodeSourcePosition() == null;
+        }
+        return true;
+    }
+
+    /**
+     * Creates an empty Graph with no name.
+     */
+    public Graph() {
+        this(null);
+    }
+
+    /**
+     * We only want the expensive modification count tracking when assertions are enabled for the
+     * {@link Graph} class.
+     */
+    @SuppressWarnings("all")
+    public static boolean isModificationCountsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled;
+    }
+
+    private static final int INITIAL_NODES_SIZE = 32;
+
+    /**
+     * Creates an empty Graph with a given name.
+     *
+     * @param name the name of the graph, used for debugging purposes
+     */
+    public Graph(String name) {
+        nodes = new Node[INITIAL_NODES_SIZE];
+        iterableNodesFirst = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
+        iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
+        this.name = name;
+        if (isModificationCountsEnabled()) {
+            nodeModCounts = new int[INITIAL_NODES_SIZE];
+            nodeUsageModCounts = new int[INITIAL_NODES_SIZE];
+        }
+    }
+
+    int extractOriginalNodeId(Node node) {
+        int id = node.id;
+        if (id <= Node.DELETED_ID_START) {
+            id = Node.DELETED_ID_START - id;
+        }
+        return id;
+    }
+
+    int modCount(Node node) {
+        int id = extractOriginalNodeId(node);
+        if (id >= 0 && id < nodeModCounts.length) {
+            return nodeModCounts[id];
+        }
+        return 0;
+    }
+
+    void incModCount(Node node) {
+        int id = extractOriginalNodeId(node);
+        if (id >= 0) {
+            if (id >= nodeModCounts.length) {
+                nodeModCounts = Arrays.copyOf(nodeModCounts, id * 2 + 30);
+            }
+            nodeModCounts[id]++;
+        } else {
+            assert false;
+        }
+    }
+
+    int usageModCount(Node node) {
+        int id = extractOriginalNodeId(node);
+        if (id >= 0 && id < nodeUsageModCounts.length) {
+            return nodeUsageModCounts[id];
+        }
+        return 0;
+    }
+
+    void incUsageModCount(Node node) {
+        int id = extractOriginalNodeId(node);
+        if (id >= 0) {
+            if (id >= nodeUsageModCounts.length) {
+                nodeUsageModCounts = Arrays.copyOf(nodeUsageModCounts, id * 2 + 30);
+            }
+            nodeUsageModCounts[id]++;
+        } else {
+            assert false;
+        }
+    }
+
+    /**
+     * Creates a copy of this graph.
+     */
+    public final Graph copy() {
+        return copy(name, null);
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
+    public final Graph copy(Consumer<Map<Node, Node>> duplicationMapCallback) {
+        return copy(name, duplicationMapCallback);
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param newName the name of the copy, used for debugging purposes (can be null)
+     */
+    public final Graph copy(String newName) {
+        return copy(newName, null);
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param newName the name of the copy, used for debugging purposes (can be null)
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
+    protected Graph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback) {
+        Graph copy = new Graph(newName);
+        Map<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map<Node, Node>) null);
+        if (duplicationMapCallback != null) {
+            duplicationMapCallback.accept(duplicates);
+        }
+        return copy;
+    }
+
+    @Override
+    public String toString() {
+        return name == null ? super.toString() : "Graph " + name;
+    }
+
+    /**
+     * Gets the number of live nodes in this graph. That is the number of nodes which have been
+     * added to the graph minus the number of deleted nodes.
+     *
+     * @return the number of live nodes in this graph
+     */
+    public int getNodeCount() {
+        return nodesSize - getNodesDeletedSinceLastCompression();
+    }
+
+    /**
+     * Gets the number of times this graph has been {@linkplain #maybeCompress() compressed}. Node
+     * identifiers are only stable between compressions. To ensure this constraint is observed, any
+     * entity relying upon stable node identifiers should use {@link NodeIdAccessor}.
+     */
+    public int getCompressions() {
+        return compressions;
+    }
+
+    /**
+     * Gets the number of nodes which have been deleted from this graph since it was last
+     * {@linkplain #maybeCompress() compressed}.
+     */
+    public int getNodesDeletedSinceLastCompression() {
+        return nodesDeletedSinceLastCompression;
+    }
+
+    /**
+     * Gets the total number of nodes which have been deleted from this graph.
+     */
+    public int getTotalNodesDeleted() {
+        return nodesDeletedSinceLastCompression + nodesDeletedBeforeLastCompression;
+    }
+
+    /**
+     * Adds a new node to the graph.
+     *
+     * @param node the node to be added
+     * @return the node which was added to the graph
+     */
+    public <T extends Node> T add(T node) {
+        if (node.getNodeClass().valueNumberable()) {
+            throw new IllegalStateException("Using add for value numberable node. Consider using either unique or addWithoutUnique.");
+        }
+        return addHelper(node);
+    }
+
+    public <T extends Node> T addWithoutUnique(T node) {
+        return addHelper(node);
+    }
+
+    public <T extends Node> T addOrUnique(T node) {
+        if (node.getNodeClass().valueNumberable()) {
+            return uniqueHelper(node, true);
+        }
+        return add(node);
+    }
+
+    public <T extends Node> T addWithoutUniqueWithInputs(T node) {
+        addInputs(node);
+        return addHelper(node);
+    }
+
+    public <T extends Node> T addOrUniqueWithInputs(T node) {
+        addInputs(node);
+        if (node.getNodeClass().valueNumberable()) {
+            return uniqueHelper(node, true);
+        }
+        return add(node);
+    }
+
+    private final class AddInputsFilter extends Node.EdgeVisitor {
+
+        @Override
+        public Node apply(Node self, Node input) {
+            if (!input.isAlive()) {
+                assert !input.isDeleted();
+                return addOrUniqueWithInputs(input);
+            } else {
+                return input;
+            }
+        }
+
+    }
+
+    private AddInputsFilter addInputsFilter = new AddInputsFilter();
+
+    private <T extends Node> void addInputs(T node) {
+        node.applyInputs(addInputsFilter);
+    }
+
+    private <T extends Node> T addHelper(T node) {
+        node.initialize(this);
+        return node;
+    }
+
+    /**
+     * The type of events sent to a {@link NodeEventListener}.
+     */
+    public enum NodeEvent {
+        /**
+         * A node's input is changed.
+         */
+        INPUT_CHANGED,
+
+        /**
+         * A node's {@linkplain Node#usages() usages} count dropped to zero.
+         */
+        ZERO_USAGES,
+
+        /**
+         * A node was added to a graph.
+         */
+        NODE_ADDED;
+    }
+
+    /**
+     * Client interested in one or more node related events.
+     */
+    public interface NodeEventListener {
+
+        /**
+         * Default handler for events.
+         *
+         * @param e an event
+         * @param node the node related to {@code e}
+         */
+        default void event(NodeEvent e, Node node) {
+        }
+
+        /**
+         * Notifies this listener of a change in a node's inputs.
+         *
+         * @param node a node who has had one of its inputs changed
+         */
+        default void inputChanged(Node node) {
+            event(NodeEvent.INPUT_CHANGED, node);
+        }
+
+        /**
+         * Notifies this listener of a node becoming unused.
+         *
+         * @param node a node whose {@link Node#usages()} just became empty
+         */
+        default void usagesDroppedToZero(Node node) {
+            event(NodeEvent.ZERO_USAGES, node);
+        }
+
+        /**
+         * Notifies this listener of an added node.
+         *
+         * @param node a node that was just added to the graph
+         */
+        default void nodeAdded(Node node) {
+            event(NodeEvent.NODE_ADDED, node);
+        }
+    }
+
+    /**
+     * Registers a given {@link NodeEventListener} with the enclosing graph until this object is
+     * {@linkplain #close() closed}.
+     */
+    public final class NodeEventScope implements AutoCloseable {
+        NodeEventScope(NodeEventListener listener) {
+            if (nodeEventListener == null) {
+                nodeEventListener = listener;
+            } else {
+                nodeEventListener = new ChainedNodeEventListener(listener, nodeEventListener);
+            }
+        }
+
+        @Override
+        public void close() {
+            assert nodeEventListener != null;
+            if (nodeEventListener instanceof ChainedNodeEventListener) {
+                nodeEventListener = ((ChainedNodeEventListener) nodeEventListener).next;
+            } else {
+                nodeEventListener = null;
+            }
+        }
+    }
+
+    private static class ChainedNodeEventListener implements NodeEventListener {
+
+        NodeEventListener head;
+        NodeEventListener next;
+
+        ChainedNodeEventListener(NodeEventListener head, NodeEventListener next) {
+            this.head = head;
+            this.next = next;
+        }
+
+        @Override
+        public void nodeAdded(Node node) {
+            head.nodeAdded(node);
+            next.nodeAdded(node);
+        }
+
+        @Override
+        public void inputChanged(Node node) {
+            head.inputChanged(node);
+            next.inputChanged(node);
+        }
+
+        @Override
+        public void usagesDroppedToZero(Node node) {
+            head.usagesDroppedToZero(node);
+            next.usagesDroppedToZero(node);
+        }
+    }
+
+    /**
+     * Registers a given {@link NodeEventListener} with this graph. This should be used in
+     * conjunction with try-with-resources statement as follows:
+     *
+     * <pre>
+     * try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+     *     // make changes to the graph
+     * }
+     * </pre>
+     */
+    public NodeEventScope trackNodeEvents(NodeEventListener listener) {
+        return new NodeEventScope(listener);
+    }
+
+    /**
+     * Looks for a node <i>similar</i> to {@code node} and returns it if found. Otherwise
+     * {@code node} is added to this graph and returned.
+     *
+     * @return a node similar to {@code node} if one exists, otherwise {@code node}
+     */
+    public <T extends Node & ValueNumberable> T unique(T node) {
+        return uniqueHelper(node, true);
+    }
+
+    <T extends Node> T uniqueHelper(T node, boolean addIfMissing) {
+        assert node.getNodeClass().valueNumberable();
+        T other = this.findDuplicate(node);
+        if (other != null) {
+            return other;
+        } else {
+            T result = addIfMissing ? addHelper(node) : node;
+            if (node.getNodeClass().isLeafNode()) {
+                putNodeIntoCache(result);
+            }
+            return result;
+        }
+    }
+
+    void putNodeIntoCache(Node node) {
+        assert node.graph() == this || node.graph() == null;
+        assert node.getNodeClass().valueNumberable();
+        assert node.getNodeClass().isLeafNode() : node.getClass();
+        CacheEntry entry = new CacheEntry(node);
+        cachedLeafNodes.put(entry, node);
+    }
+
+    Node findNodeInCache(Node node) {
+        CacheEntry key = new CacheEntry(node);
+        Node result = cachedLeafNodes.get(key);
+        if (result != null && result.isDeleted()) {
+            cachedLeafNodes.remove(key);
+            return null;
+        }
+        return result;
+    }
+
+    /**
+     * Returns a possible duplicate for the given node in the graph or {@code null} if no such
+     * duplicate exists.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Node> T findDuplicate(T node) {
+        NodeClass<?> nodeClass = node.getNodeClass();
+        assert nodeClass.valueNumberable();
+        if (nodeClass.isLeafNode()) {
+            // Leaf node: look up in cache
+            Node cachedNode = findNodeInCache(node);
+            if (cachedNode != null && cachedNode != node) {
+                return (T) cachedNode;
+            } else {
+                return null;
+            }
+        } else {
+            /*
+             * Non-leaf node: look for another usage of the node's inputs that has the same data,
+             * inputs and successors as the node. To reduce the cost of this computation, only the
+             * input with lowest usage count is considered. If this node is the only user of any
+             * input then the search can terminate early. The usage count is only incremented once
+             * the Node is in the Graph, so account for that in the test.
+             */
+            final int earlyExitUsageCount = node.graph() != null ? 1 : 0;
+            int minCount = Integer.MAX_VALUE;
+            Node minCountNode = null;
+            for (Node input : node.inputs()) {
+                int usageCount = input.getUsageCount();
+                if (usageCount == earlyExitUsageCount) {
+                    return null;
+                } else if (usageCount < minCount) {
+                    minCount = usageCount;
+                    minCountNode = input;
+                }
+            }
+            if (minCountNode != null) {
+                for (Node usage : minCountNode.usages()) {
+                    if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.equalInputs(node, usage) &&
+                                    nodeClass.equalSuccessors(node, usage)) {
+                        return (T) usage;
+                    }
+                }
+                return null;
+            }
+            return null;
+        }
+    }
+
+    public boolean isNew(Mark mark, Node node) {
+        return node.id >= mark.getValue();
+    }
+
+    /**
+     * A snapshot of the {@linkplain Graph#getNodeCount() live node count} in a graph.
+     */
+    public static class Mark extends NodeIdAccessor {
+        private final int value;
+
+        Mark(Graph graph) {
+            super(graph);
+            this.value = graph.nodeIdCount();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Mark) {
+                Mark other = (Mark) obj;
+                return other.getValue() == getValue() && other.getGraph() == getGraph();
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return value ^ (epoch + 11);
+        }
+
+        /**
+         * Determines if this mark is positioned at the first live node in the graph.
+         */
+        public boolean isStart() {
+            return value == 0;
+        }
+
+        /**
+         * Gets the {@linkplain Graph#getNodeCount() live node count} of the associated graph when
+         * this object was created.
+         */
+        int getValue() {
+            return value;
+        }
+
+        /**
+         * Determines if this mark still represents the {@linkplain Graph#getNodeCount() live node
+         * count} of the graph.
+         */
+        public boolean isCurrent() {
+            return value == graph.nodeIdCount();
+        }
+    }
+
+    /**
+     * Gets a mark that can be used with {@link #getNewNodes}.
+     */
+    public Mark getMark() {
+        return new Mark(this);
+    }
+
+    /**
+     * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark()
+     * mark}.
+     */
+    public NodeIterable<Node> getNewNodes(Mark mark) {
+        final int index = mark == null ? 0 : mark.getValue();
+        return new NodeIterable<Node>() {
+
+            @Override
+            public Iterator<Node> iterator() {
+                return new GraphNodeIterator(Graph.this, index);
+            }
+        };
+    }
+
+    /**
+     * Returns an {@link Iterable} providing all the live nodes.
+     *
+     * @return an {@link Iterable} providing all the live nodes.
+     */
+    public NodeIterable<Node> getNodes() {
+        return new NodeIterable<Node>() {
+
+            @Override
+            public Iterator<Node> iterator() {
+                return new GraphNodeIterator(Graph.this);
+            }
+
+            @Override
+            public int count() {
+                return getNodeCount();
+            }
+        };
+    }
+
+    // Fully qualified annotation name is required to satisfy javac
+    @org.graalvm.compiler.nodeinfo.NodeInfo
+    static final class PlaceHolderNode extends Node {
+
+        public static final NodeClass<PlaceHolderNode> TYPE = NodeClass.create(PlaceHolderNode.class);
+
+        protected PlaceHolderNode() {
+            super(TYPE);
+        }
+
+    }
+
+    static final Node PLACE_HOLDER = new PlaceHolderNode();
+
+    public static final int COMPRESSION_THRESHOLD = Options.GraphCompressionThreshold.getValue();
+
+    private static final DebugCounter GraphCompressions = Debug.counter("GraphCompressions");
+
+    /**
+     * If the {@linkplain #COMPRESSION_THRESHOLD compression threshold} is met, the list of nodes is
+     * compressed such that all non-null entries precede all null entries while preserving the
+     * ordering between the nodes within the list.
+     */
+    public boolean maybeCompress() {
+        if (Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()) {
+            return false;
+        }
+        int liveNodeCount = getNodeCount();
+        int liveNodePercent = liveNodeCount * 100 / nodesSize;
+        if (COMPRESSION_THRESHOLD == 0 || liveNodePercent >= COMPRESSION_THRESHOLD) {
+            return false;
+        }
+        GraphCompressions.increment();
+        int nextId = 0;
+        for (int i = 0; nextId < liveNodeCount; i++) {
+            Node n = nodes[i];
+            if (n != null) {
+                assert n.id == i;
+                if (i != nextId) {
+                    assert n.id > nextId;
+                    n.id = nextId;
+                    nodes[nextId] = n;
+                    nodes[i] = null;
+                }
+                nextId++;
+            }
+        }
+        if (isModificationCountsEnabled()) {
+            // This will cause any current iteration to fail with an assertion
+            Arrays.fill(nodeModCounts, 0);
+            Arrays.fill(nodeUsageModCounts, 0);
+        }
+        nodesSize = nextId;
+        compressions++;
+        nodesDeletedBeforeLastCompression += nodesDeletedSinceLastCompression;
+        nodesDeletedSinceLastCompression = 0;
+        return true;
+    }
+
+    /**
+     * Returns an {@link Iterable} providing all the live nodes whose type is compatible with
+     * {@code type}.
+     *
+     * @param nodeClass the type of node to return
+     * @return an {@link Iterable} providing all the matching nodes
+     */
+    public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final NodeClass<T> nodeClass) {
+        return new NodeIterable<T>() {
+
+            @Override
+            public Iterator<T> iterator() {
+                return new TypedGraphNodeIterator<>(nodeClass, Graph.this);
+            }
+        };
+    }
+
+    /**
+     * Returns whether the graph contains at least one node of the given type.
+     *
+     * @param type the type of node that is checked for occurrence
+     * @return whether there is at least one such node
+     */
+    public <T extends Node & IterableNodeType> boolean hasNode(final NodeClass<T> type) {
+        return getNodes(type).iterator().hasNext();
+    }
+
+    /**
+     * @param iterableId
+     * @return the first live Node with a matching iterableId
+     */
+    Node getIterableNodeStart(int iterableId) {
+        if (iterableNodesFirst.size() <= iterableId) {
+            return null;
+        }
+        Node start = iterableNodesFirst.get(iterableId);
+        if (start == null || !start.isDeleted()) {
+            return start;
+        }
+        return findFirstLiveIterable(iterableId, start);
+    }
+
+    private Node findFirstLiveIterable(int iterableId, Node node) {
+        Node start = node;
+        while (start != null && start.isDeleted()) {
+            start = start.typeCacheNext;
+        }
+        /*
+         * Multiple threads iterating nodes can update this cache simultaneously. This is a benign
+         * race, since all threads update it to the same value.
+         */
+        iterableNodesFirst.set(iterableId, start);
+        if (start == null) {
+            iterableNodesLast.set(iterableId, start);
+        }
+        return start;
+    }
+
+    /**
+     * @param node
+     * @return return the first live Node with a matching iterableId starting from {@code node}
+     */
+    Node getIterableNodeNext(Node node) {
+        if (node == null) {
+            return null;
+        }
+        Node n = node;
+        if (n == null || !n.isDeleted()) {
+            return n;
+        }
+
+        return findNextLiveiterable(node);
+    }
+
+    private Node findNextLiveiterable(Node start) {
+        Node n = start;
+        while (n != null && n.isDeleted()) {
+            n = n.typeCacheNext;
+        }
+        if (n == null) {
+            // Only dead nodes after this one
+            start.typeCacheNext = null;
+            int nodeClassId = start.getNodeClass().iterableId();
+            assert nodeClassId != Node.NOT_ITERABLE;
+            iterableNodesLast.set(nodeClassId, start);
+        } else {
+            // Everything in between is dead
+            start.typeCacheNext = n;
+        }
+        return n;
+    }
+
+    public NodeBitMap createNodeBitMap() {
+        return new NodeBitMap(this);
+    }
+
+    public <T> NodeMap<T> createNodeMap() {
+        return new NodeMap<>(this);
+    }
+
+    public NodeFlood createNodeFlood() {
+        return new NodeFlood(this);
+    }
+
+    public NodeWorkList createNodeWorkList() {
+        return new NodeWorkList.SingletonNodeWorkList(this);
+    }
+
+    public NodeWorkList createIterativeNodeWorkList(boolean fill, int iterationLimitPerNode) {
+        return new NodeWorkList.IterativeNodeWorkList(this, fill, iterationLimitPerNode);
+    }
+
+    void register(Node node) {
+        assert !isFrozen();
+        assert node.id() == Node.INITIAL_ID;
+        if (nodes.length == nodesSize) {
+            Node[] newNodes = new Node[(nodesSize * 2) + 1];
+            System.arraycopy(nodes, 0, newNodes, 0, nodesSize);
+            nodes = newNodes;
+        }
+        int id = nodesSize;
+        nodes[id] = node;
+        if (currentNodeSourcePosition != null) {
+            node.setNodeSourcePosition(currentNodeSourcePosition);
+        } else if (!seenNodeSourcePosition && node.getNodeSourcePosition() != null) {
+            seenNodeSourcePosition = true;
+        }
+        nodesSize++;
+
+        updateNodeCaches(node);
+
+        node.id = id;
+        if (nodeEventListener != null) {
+            nodeEventListener.nodeAdded(node);
+        }
+        if (!seenNodeSourcePosition && node.sourcePosition != null) {
+            seenNodeSourcePosition = true;
+        }
+        if (Fingerprint.ENABLED) {
+            Fingerprint.submit("%s: %s", NodeEvent.NODE_ADDED, node);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void postDeserialization() {
+        recomputeIterableNodeLists();
+    }
+
+    /**
+     * Rebuilds the lists used to support {@link #getNodes(NodeClass)}. This is useful for
+     * serialization where the underlying {@linkplain NodeClass#iterableId() iterable ids} may have
+     * changed.
+     */
+    private void recomputeIterableNodeLists() {
+        iterableNodesFirst.clear();
+        iterableNodesLast.clear();
+        for (Node node : nodes) {
+            if (node != null && node.isAlive()) {
+                updateNodeCaches(node);
+            }
+        }
+    }
+
+    private void updateNodeCaches(Node node) {
+        int nodeClassId = node.getNodeClass().iterableId();
+        if (nodeClassId != Node.NOT_ITERABLE) {
+            while (iterableNodesFirst.size() <= nodeClassId) {
+                iterableNodesFirst.add(null);
+                iterableNodesLast.add(null);
+            }
+            Node prev = iterableNodesLast.get(nodeClassId);
+            if (prev != null) {
+                prev.typeCacheNext = node;
+            } else {
+                iterableNodesFirst.set(nodeClassId, node);
+            }
+            iterableNodesLast.set(nodeClassId, node);
+        }
+    }
+
+    void unregister(Node node) {
+        assert !isFrozen();
+        assert !node.isDeleted() : "cannot delete a node twice! node=" + node;
+        nodes[node.id] = null;
+        nodesDeletedSinceLastCompression++;
+
+        // nodes aren't removed from the type cache here - they will be removed during iteration
+    }
+
+    public boolean verify() {
+        if (Options.VerifyGraalGraphs.getValue()) {
+            for (Node node : getNodes()) {
+                try {
+                    try {
+                        assert node.verify();
+                    } catch (AssertionError t) {
+                        throw new GraalError(t);
+                    } catch (RuntimeException t) {
+                        throw new GraalError(t);
+                    }
+                } catch (GraalError e) {
+                    throw GraalGraphError.transformAndAddContext(e, node).addContext(this);
+                }
+            }
+        }
+        return true;
+    }
+
+    public Node getNode(int id) {
+        return nodes[id];
+    }
+
+    /**
+     * Returns the number of node ids generated so far.
+     *
+     * @return the number of node ids generated so far
+     */
+    int nodeIdCount() {
+        return nodesSize;
+    }
+
+    /**
+     * Adds duplicates of the nodes in {@code nodes} to this graph. This will recreate any edges
+     * between the duplicate nodes. The {@code replacement} map can be used to replace a node from
+     * the source graph by a given node (which must already be in this graph). Edges between
+     * duplicate and replacement nodes will also be recreated so care should be taken regarding the
+     * matching of node types in the replacement map.
+     *
+     * @param newNodes the nodes to be duplicated
+     * @param replacementsMap the replacement map (can be null if no replacement is to be performed)
+     * @return a map which associates the original nodes from {@code nodes} to their duplicates
+     */
+    public Map<Node, Node> addDuplicates(Iterable<? extends Node> newNodes, final Graph oldGraph, int estimatedNodeCount, Map<Node, Node> replacementsMap) {
+        DuplicationReplacement replacements;
+        if (replacementsMap == null) {
+            replacements = null;
+        } else {
+            replacements = new MapReplacement(replacementsMap);
+        }
+        return addDuplicates(newNodes, oldGraph, estimatedNodeCount, replacements);
+    }
+
+    public interface DuplicationReplacement {
+
+        Node replacement(Node original);
+    }
+
+    private static final class MapReplacement implements DuplicationReplacement {
+
+        private final Map<Node, Node> map;
+
+        MapReplacement(Map<Node, Node> map) {
+            this.map = map;
+        }
+
+        @Override
+        public Node replacement(Node original) {
+            Node replacement = map.get(original);
+            return replacement != null ? replacement : original;
+        }
+
+    }
+
+    private static final DebugTimer DuplicateGraph = Debug.timer("DuplicateGraph");
+
+    @SuppressWarnings({"all", "try"})
+    public Map<Node, Node> addDuplicates(Iterable<? extends Node> newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements) {
+        try (DebugCloseable s = DuplicateGraph.start()) {
+            return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements);
+        }
+    }
+
+    /**
+     * Reverses the usage orders of all nodes. This is used for debugging to make sure an unorthodox
+     * usage order does not trigger bugs in the compiler.
+     */
+    public void reverseUsageOrder() {
+        for (Node n : getNodes()) {
+            n.reverseUsageOrder();
+        }
+    }
+
+    public boolean isFrozen() {
+        return isFrozen;
+    }
+
+    public void freeze() {
+        this.isFrozen = true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraphNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraphNodeIterator.java
new file mode 100644
index 0000000..df52414
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/GraphNodeIterator.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Iterator;
+
+/**
+ * Iterates over the nodes in a given graph.
+ */
+class GraphNodeIterator implements Iterator<Node> {
+
+    private final Graph graph;
+    private int index;
+
+    GraphNodeIterator(Graph graph) {
+        this(graph, 0);
+    }
+
+    GraphNodeIterator(Graph graph, int index) {
+        this.graph = graph;
+        this.index = index - 1;
+        forward();
+    }
+
+    private void forward() {
+        if (index < graph.nodesSize) {
+            do {
+                index++;
+            } while (index < graph.nodesSize && graph.nodes[index] == null);
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        checkForDeletedNode();
+        return index < graph.nodesSize;
+    }
+
+    private void checkForDeletedNode() {
+        while (index < graph.nodesSize && graph.nodes[index] == null) {
+            index++;
+        }
+    }
+
+    @Override
+    public Node next() {
+        try {
+            return graph.nodes[index];
+        } finally {
+            forward();
+        }
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InputEdges.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InputEdges.java
new file mode 100644
index 0000000..d484be4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InputEdges.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Edges.Type.Inputs;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.graph.NodeClass.InputInfo;
+import org.graalvm.compiler.nodeinfo.InputType;
+
+public final class InputEdges extends Edges {
+
+    private final InputType[] inputTypes;
+    private final boolean[] isOptional;
+
+    public InputEdges(int directCount, ArrayList<InputInfo> edges) {
+        super(Inputs, directCount, edges);
+
+        this.inputTypes = new InputType[edges.size()];
+        this.isOptional = new boolean[edges.size()];
+        for (int i = 0; i < edges.size(); i++) {
+            this.inputTypes[i] = edges.get(i).inputType;
+            this.isOptional[i] = edges.get(i).optional;
+        }
+    }
+
+    public static void translateInto(InputEdges inputs, ArrayList<InputInfo> infos) {
+        for (int index = 0; index < inputs.getCount(); index++) {
+            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index)));
+        }
+    }
+
+    public InputType getInputType(int index) {
+        return inputTypes[index];
+    }
+
+    public boolean isOptional(int index) {
+        return isOptional[index];
+    }
+
+    @Override
+    public void update(Node node, Node oldValue, Node newValue) {
+        node.updateUsages(oldValue, newValue);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/IterableNodeType.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/IterableNodeType.java
new file mode 100644
index 0000000..93d2044
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/IterableNodeType.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+/**
+ * A marker for a node type supporting {@linkplain Graph#getNodes(NodeClass) fast iteration} of its
+ * instances in a graph. The support for fast iteration comes with a memory cost (e.g., extra data
+ * structures {@link Graph}) so only node types for which fast iteration provides a compilation
+ * performance benefit should implement this interface.
+ */
+public interface IterableNodeType {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java
new file mode 100644
index 0000000..14ebbd8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java
@@ -0,0 +1,1190 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Edges.Type.Inputs;
+import static org.graalvm.compiler.graph.Edges.Type.Successors;
+import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
+import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Formattable;
+import java.util.FormattableFlags;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Graph.Options;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.iterators.NodePredicate;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+
+import sun.misc.Unsafe;
+
+/**
+ * This class is the base class for all nodes. It represents a node that can be inserted in a
+ * {@link Graph}.
+ * <p>
+ * Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the
+ * subclasses are represented with annotated fields. There are two kind of edges : {@link Input} and
+ * {@link Successor}. If a field, of a type compatible with {@link Node}, annotated with either
+ * {@link Input} and {@link Successor} is not null, then there is an edge from this node to the node
+ * this field points to.
+ * <p>
+ * Nodes which are be value numberable should implement the {@link ValueNumberable} interface.
+ *
+ * <h1>Replay Compilation</h1>
+ *
+ * To enable deterministic replay compilation, node sets and node maps should be instantiated with
+ * the following methods:
+ * <ul>
+ * <li>{@link #newSet()}</li>
+ * <li>{@link #newSet(Collection)}</li>
+ * <li>{@link #newMap()}</li>
+ * <li>{@link #newMap(int)}</li>
+ * <li>{@link #newMap(Map)}</li>
+ * <li>{@link #newIdentityMap()}</li>
+ * <li>{@link #newIdentityMap(int)}</li>
+ * <li>{@link #newIdentityMap(Map)}</li>
+ * </ul>
+ *
+ * <h1>Assertions and Verification</h1>
+ *
+ * The Node class supplies the {@link #assertTrue(boolean, String, Object...)} and
+ * {@link #assertFalse(boolean, String, Object...)} methods, which will check the supplied boolean
+ * and throw a VerificationError if it has the wrong value. Both methods will always either throw an
+ * exception or return true. They can thus be used within an assert statement, so that the check is
+ * only performed if assertions are enabled.
+ */
+@NodeInfo
+public abstract class Node implements Cloneable, Formattable, NodeInterface {
+
+    public static final NodeClass<?> TYPE = null;
+    public static final boolean USE_UNSAFE_TO_CLONE = Graph.Options.CloneNodesWithUnsafe.getValue();
+
+    static final int DELETED_ID_START = -1000000000;
+    static final int INITIAL_ID = -1;
+    static final int ALIVE_ID_START = 0;
+
+    // The use of fully qualified class names here and in the rest
+    // of this file works around a problem javac has resolving symbols
+
+    /**
+     * Denotes a non-optional (non-null) node input. This should be applied to exactly the fields of
+     * a node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of
+     * type {@link Node} outside of their constructor should call
+     * {@link Node#updateUsages(Node, Node)} just prior to doing the update of the input.
+     */
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.FIELD)
+    public static @interface Input {
+        InputType value() default InputType.Value;
+    }
+
+    /**
+     * Denotes an optional (nullable) node input. This should be applied to exactly the fields of a
+     * node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of type
+     * {@link Node} outside of their constructor should call {@link Node#updateUsages(Node, Node)}
+     * just prior to doing the update of the input.
+     */
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.FIELD)
+    public static @interface OptionalInput {
+        InputType value() default InputType.Value;
+    }
+
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.FIELD)
+    public static @interface Successor {
+    }
+
+    /**
+     * Denotes that a parameter of an {@linkplain NodeIntrinsic intrinsic} method must be a compile
+     * time constant at all call sites to the intrinsic method.
+     */
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.PARAMETER)
+    public static @interface ConstantNodeParameter {
+    }
+
+    /**
+     * Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If
+     * the constructor is called as part of node intrinsification, the node intrinsifier will inject
+     * an argument for the annotated parameter. Injected parameters must precede all non-injected
+     * parameters in a constructor.
+     */
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.PARAMETER)
+    public static @interface InjectedNodeParameter {
+    }
+
+    /**
+     * Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the
+     * annotated method can be replaced with an instance of the node class denoted by
+     * {@link #value()}. For this reason, the signature of the annotated method must match the
+     * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a
+     * constructor in the node class.
+     * <p>
+     * If the node class has a static method {@code intrinsify} with a matching signature plus a
+     * {@code GraphBuilderContext} as first argument, this method is called instead of creating the
+     * node.
+     */
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.METHOD)
+    public static @interface NodeIntrinsic {
+
+        /**
+         * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated
+         * method. If not specified, then the class in which the annotated method is declared is
+         * used (and is assumed to be a {@link Node} subclass).
+         */
+        Class<?> value() default NodeIntrinsic.class;
+
+        /**
+         * Determines if the stamp of the instantiated intrinsic node has its stamp set from the
+         * return type of the annotated method.
+         * <p>
+         * When it is set to true, the stamp that is passed in to the constructor of ValueNode is
+         * ignored and can therefore safely be {@code null}.
+         */
+        boolean setStampFromReturnType() default false;
+
+        /**
+         * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null.
+         * Generally used in conjunction with {@link #setStampFromReturnType()}.
+         */
+        boolean returnStampIsNonNull() default false;
+    }
+
+    /**
+     * Marker for a node that can be replaced by another node via global value numbering. A
+     * {@linkplain NodeClass#isLeafNode() leaf} node can be replaced by another node of the same
+     * type that has exactly the same {@linkplain NodeClass#getData() data} values. A non-leaf node
+     * can be replaced by another node of the same type that has exactly the same data values as
+     * well as the same {@linkplain Node#inputs() inputs} and {@linkplain Node#successors()
+     * successors}.
+     */
+    public interface ValueNumberable {
+    }
+
+    /**
+     * Marker interface for nodes that contains other nodes. When the inputs to this node changes,
+     * users of this node should also be placed on the work list for canonicalization.
+     */
+    public interface IndirectCanonicalization {
+    }
+
+    private Graph graph;
+    int id;
+
+    // this next pointer is used in Graph to implement fast iteration over NodeClass types, it
+    // therefore points to the next Node of the same type.
+    Node typeCacheNext;
+
+    static final int INLINE_USAGE_COUNT = 2;
+    private static final Node[] NO_NODES = {};
+
+    /**
+     * Head of usage list. The elements of the usage list in order are {@link #usage0},
+     * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list.
+     */
+    Node usage0;
+    Node usage1;
+    Node[] extraUsages;
+    int extraUsagesCount;
+
+    private Node predecessor;
+    private NodeClass<? extends Node> nodeClass;
+
+    public static final int NODE_LIST = -2;
+    public static final int NOT_ITERABLE = -1;
+
+    public Node(NodeClass<? extends Node> c) {
+        init(c);
+    }
+
+    final void init(NodeClass<? extends Node> c) {
+        assert c.getJavaClass() == this.getClass();
+        this.nodeClass = c;
+        id = INITIAL_ID;
+        extraUsages = NO_NODES;
+    }
+
+    final int id() {
+        return id;
+    }
+
+    @Override
+    public Node asNode() {
+        return this;
+    }
+
+    /**
+     * @see CollectionsFactory#newSet()
+     */
+    public static <E extends Node> Set<E> newSet() {
+        return CollectionsFactory.newSet();
+    }
+
+    /**
+     * @see #newSet()
+     */
+    public static <E extends Node> Set<E> newSet(Collection<? extends E> c) {
+        return CollectionsFactory.newSet(c);
+    }
+
+    public static <K extends Node, V> Map<K, V> newMap() {
+        // Node.equals() and Node.hashCode() are final and are implemented
+        // purely in terms of identity so HashMap and IdentityHashMap with
+        // Node's as keys will behave the same. We choose to use the latter
+        // due to its lighter memory footprint.
+        return newIdentityMap();
+    }
+
+    public static <K extends Node, V> Map<K, V> newMap(Map<K, V> m) {
+        // Node.equals() and Node.hashCode() are final and are implemented
+        // purely in terms of identity so HashMap and IdentityHashMap with
+        // Node's as keys will behave the same. We choose to use the latter
+        // due to its lighter memory footprint.
+        return newIdentityMap(m);
+    }
+
+    public static <K extends Node, V> Map<K, V> newMap(int expectedMaxSize) {
+        // Node.equals() and Node.hashCode() are final and are implemented
+        // purely in terms of identity so HashMap and IdentityHashMap with
+        // Node's as keys will behave the same. We choose to use the latter
+        // due to its lighter memory footprint.
+        return newIdentityMap(expectedMaxSize);
+    }
+
+    public static <K extends Node, V> Map<K, V> newIdentityMap() {
+        return CollectionsFactory.newIdentityMap();
+    }
+
+    public static <K extends Node, V> Map<K, V> newIdentityMap(Map<K, V> m) {
+        return CollectionsFactory.newIdentityMap(m);
+    }
+
+    public static <K extends Node, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
+        return CollectionsFactory.newIdentityMap(expectedMaxSize);
+    }
+
+    /**
+     * Gets the graph context of this node.
+     */
+    public Graph graph() {
+        return graph;
+    }
+
+    /**
+     * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null input
+     * edges of this node.
+     *
+     * @return an {@link NodeIterable iterable} for all non-null input edges.
+     */
+    public NodeIterable<Node> inputs() {
+        return nodeClass.getInputIterable(this);
+    }
+
+    /**
+     * Returns an {@link Iterable iterable} which can be used to traverse all non-null input edges
+     * of this node.
+     *
+     * @return an {@link Iterable iterable} for all non-null input edges.
+     */
+    public Iterable<Position> inputPositions() {
+        return nodeClass.getInputEdges().getPositionsIterable(this);
+    }
+
+    public abstract static class EdgeVisitor {
+
+        public abstract Node apply(Node source, Node target);
+
+    }
+
+    /**
+     * Applies the given visitor to all inputs of this node.
+     *
+     * @param visitor the visitor to be applied to the inputs
+     */
+    public void applyInputs(EdgeVisitor visitor) {
+        nodeClass.applyInputs(this, visitor);
+    }
+
+    /**
+     * Applies the given visitor to all successors of this node.
+     *
+     * @param visitor the visitor to be applied to the successors
+     */
+    public void applySuccessors(EdgeVisitor visitor) {
+        nodeClass.applySuccessors(this, visitor);
+    }
+
+    /**
+     * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null successor
+     * edges of this node.
+     *
+     * @return an {@link NodeIterable iterable} for all non-null successor edges.
+     */
+    public NodeIterable<Node> successors() {
+        assert !this.isDeleted();
+        return nodeClass.getSuccessorIterable(this);
+    }
+
+    /**
+     * Returns an {@link Iterable iterable} which can be used to traverse all successor edge
+     * positions of this node.
+     *
+     * @return an {@link Iterable iterable} for all successor edge positoins.
+     */
+    public Iterable<Position> successorPositions() {
+        return nodeClass.getSuccessorEdges().getPositionsIterable(this);
+    }
+
+    /**
+     * Gets the maximum number of usages this node has had at any point in time.
+     */
+    public int getUsageCount() {
+        if (usage0 == null) {
+            return 0;
+        }
+        if (usage1 == null) {
+            return 1;
+        }
+        return 2 + extraUsagesCount;
+    }
+
+    /**
+     * Gets the list of nodes that use this node (i.e., as an input).
+     */
+    public final NodeIterable<Node> usages() {
+        return new NodeUsageIterable(this);
+    }
+
+    /**
+     * Checks whether this node has no usages.
+     */
+    public final boolean hasNoUsages() {
+        return this.usage0 == null;
+    }
+
+    /**
+     * Checks whether this node has usages.
+     */
+    public final boolean hasUsages() {
+        return this.usage0 != null;
+    }
+
+    void reverseUsageOrder() {
+        List<Node> snapshot = this.usages().snapshot();
+        for (Node n : snapshot) {
+            this.removeUsage(n);
+        }
+        Collections.reverse(snapshot);
+        for (Node n : snapshot) {
+            this.addUsage(n);
+        }
+    }
+
+    /**
+     * Adds a given node to this node's {@linkplain #usages() usages}.
+     *
+     * @param node the node to add
+     */
+    void addUsage(Node node) {
+        incUsageModCount();
+        if (usage0 == null) {
+            usage0 = node;
+        } else if (usage1 == null) {
+            usage1 = node;
+        } else {
+            int length = extraUsages.length;
+            if (length == 0) {
+                extraUsages = new Node[4];
+            } else if (extraUsagesCount == length) {
+                Node[] newExtraUsages = new Node[length * 2 + 1];
+                System.arraycopy(extraUsages, 0, newExtraUsages, 0, length);
+                extraUsages = newExtraUsages;
+            }
+            extraUsages[extraUsagesCount++] = node;
+        }
+    }
+
+    private void movUsageFromEndTo(int destIndex) {
+        int lastIndex = this.getUsageCount() - 1;
+        if (destIndex == 0) {
+            if (lastIndex == 0) {
+                usage0 = null;
+                return;
+            } else if (lastIndex == 1) {
+                usage0 = usage1;
+                usage1 = null;
+                return;
+            } else {
+                usage0 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
+            }
+        } else if (destIndex == 1) {
+            if (lastIndex == 1) {
+                usage1 = null;
+                return;
+            }
+            usage1 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
+        } else {
+            Node n = extraUsages[lastIndex - INLINE_USAGE_COUNT];
+            extraUsages[destIndex - INLINE_USAGE_COUNT] = n;
+        }
+        extraUsages[lastIndex - INLINE_USAGE_COUNT] = null;
+        this.extraUsagesCount--;
+    }
+
+    /**
+     * Removes a given node from this node's {@linkplain #usages() usages}.
+     *
+     * @param node the node to remove
+     * @return whether or not {@code usage} was in the usage list
+     */
+    public boolean removeUsage(Node node) {
+        assert node != null;
+        // It is critical that this method maintains the invariant that
+        // the usage list has no null element preceding a non-null element
+        incUsageModCount();
+        if (usage0 == node) {
+            this.movUsageFromEndTo(0);
+            return true;
+        }
+        if (usage1 == node) {
+            this.movUsageFromEndTo(1);
+            return true;
+        }
+        for (int i = this.extraUsagesCount - 1; i >= 0; i--) {
+            if (extraUsages[i] == node) {
+                this.movUsageFromEndTo(i + INLINE_USAGE_COUNT);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public final Node predecessor() {
+        return predecessor;
+    }
+
+    public final int modCount() {
+        if (isModificationCountsEnabled() && graph != null) {
+            return graph.modCount(this);
+        }
+        return 0;
+    }
+
+    final void incModCount() {
+        if (isModificationCountsEnabled() && graph != null) {
+            graph.incModCount(this);
+        }
+    }
+
+    final int usageModCount() {
+        if (isModificationCountsEnabled() && graph != null) {
+            return graph.usageModCount(this);
+        }
+        return 0;
+    }
+
+    final void incUsageModCount() {
+        if (isModificationCountsEnabled() && graph != null) {
+            graph.incUsageModCount(this);
+        }
+    }
+
+    public boolean isDeleted() {
+        return id <= DELETED_ID_START;
+    }
+
+    public boolean isAlive() {
+        return id >= ALIVE_ID_START;
+    }
+
+    /**
+     * Updates the usages sets of the given nodes after an input slot is changed from
+     * {@code oldInput} to {@code newInput} by removing this node from {@code oldInput}'s usages and
+     * adds this node to {@code newInput}'s usages.
+     */
+    protected void updateUsages(Node oldInput, Node newInput) {
+        assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput;
+        if (oldInput != newInput) {
+            if (oldInput != null) {
+                boolean result = removeThisFromUsages(oldInput);
+                assert assertTrue(result, "not found in usages, old input: %s", oldInput);
+            }
+            maybeNotifyInputChanged(this);
+            if (newInput != null) {
+                newInput.addUsage(this);
+            }
+            if (oldInput != null && oldInput.hasNoUsages()) {
+                maybeNotifyZeroUsages(oldInput);
+            }
+        }
+    }
+
+    protected void updateUsagesInterface(NodeInterface oldInput, NodeInterface newInput) {
+        updateUsages(oldInput == null ? null : oldInput.asNode(), newInput == null ? null : newInput.asNode());
+    }
+
+    /**
+     * Updates the predecessor of the given nodes after a successor slot is changed from
+     * oldSuccessor to newSuccessor: removes this node from oldSuccessor's predecessors and adds
+     * this node to newSuccessor's predecessors.
+     */
+    protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) {
+        assert isAlive() && (newSuccessor == null || newSuccessor.isAlive()) || newSuccessor == null && !isAlive() : "adding " + newSuccessor + " to " + this + " instead of " + oldSuccessor;
+        assert graph == null || !graph.isFrozen();
+        if (oldSuccessor != newSuccessor) {
+            if (oldSuccessor != null) {
+                assert assertTrue(newSuccessor == null || oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s, should be %s", oldSuccessor, oldSuccessor.predecessor, this);
+                oldSuccessor.predecessor = null;
+            }
+            if (newSuccessor != null) {
+                assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this);
+                newSuccessor.predecessor = this;
+            }
+        }
+    }
+
+    void initialize(Graph newGraph) {
+        assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
+        this.graph = newGraph;
+        newGraph.register(this);
+        this.getNodeClass().registerAtInputsAsUsage(this);
+        this.getNodeClass().registerAtSuccessorsAsPredecessor(this);
+    }
+
+    /**
+     * The position of the bytecode that generated this node.
+     */
+    NodeSourcePosition sourcePosition;
+
+    /**
+     * Gets the source position information for this node or null if it doesn't exist.
+     */
+
+    public NodeSourcePosition getNodeSourcePosition() {
+        return sourcePosition;
+    }
+
+    /**
+     * Set the source position to {@code sourcePosition}.
+     */
+    public void setNodeSourcePosition(NodeSourcePosition sourcePosition) {
+        this.sourcePosition = sourcePosition;
+        if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) {
+            graph.seenNodeSourcePosition = true;
+        }
+    }
+
+    public DebugCloseable withNodeSourcePosition() {
+        return graph.withNodeSourcePosition(this);
+    }
+
+    public final NodeClass<? extends Node> getNodeClass() {
+        return nodeClass;
+    }
+
+    public boolean isAllowedUsageType(InputType type) {
+        if (type == InputType.Value) {
+            return false;
+        }
+        return getNodeClass().getAllowedUsageTypes().contains(type);
+    }
+
+    private boolean checkReplaceWith(Node other) {
+        assert assertTrue(graph == null || !graph.isFrozen(), "cannot modify frozen graph");
+        assert assertFalse(other == this, "cannot replace a node with itself");
+        assert assertFalse(isDeleted(), "cannot replace deleted node");
+        assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other);
+        return true;
+    }
+
+    public final void replaceAtUsages(Node other) {
+        replaceAtUsages(other, null, null);
+    }
+
+    public final void replaceAtUsages(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, null);
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other) {
+        replaceAtUsages(other, null, this);
+        safeDelete();
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, this);
+        safeDelete();
+    }
+
+    protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
+        assert checkReplaceWith(other);
+        int i = 0;
+        while (i < this.getUsageCount()) {
+            Node usage = this.getUsageAt(i);
+            if (filter == null || filter.test(usage)) {
+                boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+                assert assertTrue(result, "not found in inputs, usage: %s", usage);
+                /*
+                 * Don't notify for nodes which are about to be deleted.
+                 */
+                if (toBeDeleted == null || usage != toBeDeleted) {
+                    maybeNotifyInputChanged(usage);
+                }
+                if (other != null) {
+                    other.addUsage(usage);
+                }
+                this.movUsageFromEndTo(i);
+            } else {
+                ++i;
+            }
+        }
+    }
+
+    public Node getUsageAt(int index) {
+        if (index == 0) {
+            return this.usage0;
+        } else if (index == 1) {
+            return this.usage1;
+        } else {
+            return this.extraUsages[index - INLINE_USAGE_COUNT];
+        }
+    }
+
+    public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) {
+        assert checkReplaceWith(other);
+        int index = 0;
+        while (index < this.getUsageCount()) {
+            Node usage = getUsageAt(index);
+            if (usagePredicate.apply(usage)) {
+                boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+                assert assertTrue(result, "not found in inputs, usage: %s", usage);
+                if (other != null) {
+                    maybeNotifyInputChanged(usage);
+                    other.addUsage(usage);
+                }
+                this.movUsageFromEndTo(index);
+            } else {
+                index++;
+            }
+        }
+    }
+
+    public void replaceAtUsages(InputType type, Node other) {
+        assert checkReplaceWith(other);
+        for (Node usage : usages().snapshot()) {
+            for (Position pos : usage.inputPositions()) {
+                if (pos.getInputType() == type && pos.get(usage) == this) {
+                    pos.set(usage, other);
+                }
+            }
+        }
+    }
+
+    private void maybeNotifyInputChanged(Node node) {
+        if (graph != null) {
+            assert !graph.isFrozen();
+            NodeEventListener listener = graph.nodeEventListener;
+            if (listener != null) {
+                listener.inputChanged(node);
+            }
+            if (Fingerprint.ENABLED) {
+                Fingerprint.submit("%s: %s", NodeEvent.INPUT_CHANGED, node);
+            }
+        }
+    }
+
+    public void maybeNotifyZeroUsages(Node node) {
+        if (graph != null) {
+            assert !graph.isFrozen();
+            NodeEventListener listener = graph.nodeEventListener;
+            if (listener != null && node.isAlive()) {
+                listener.usagesDroppedToZero(node);
+            }
+            if (Fingerprint.ENABLED) {
+                Fingerprint.submit("%s: %s", NodeEvent.ZERO_USAGES, node);
+            }
+        }
+    }
+
+    public void replaceAtPredecessor(Node other) {
+        assert checkReplaceWith(other);
+        if (predecessor != null) {
+            boolean result = predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other);
+            assert assertTrue(result, "not found in successors, predecessor: %s", predecessor);
+            predecessor.updatePredecessor(this, other);
+        }
+    }
+
+    public void replaceAndDelete(Node other) {
+        assert checkReplaceWith(other);
+        assert other != null;
+        replaceAtUsages(other);
+        replaceAtPredecessor(other);
+        this.safeDelete();
+    }
+
+    public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) {
+        if (nodeClass.replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) {
+            updatePredecessor(oldSuccessor, newSuccessor);
+        }
+    }
+
+    public void replaceFirstInput(Node oldInput, Node newInput) {
+        if (nodeClass.replaceFirstInput(this, oldInput, newInput)) {
+            updateUsages(oldInput, newInput);
+        }
+    }
+
+    public void clearInputs() {
+        assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
+        getNodeClass().unregisterAtInputsAsUsage(this);
+    }
+
+    boolean removeThisFromUsages(Node n) {
+        return n.removeUsage(this);
+    }
+
+    public void clearSuccessors() {
+        assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
+        getNodeClass().unregisterAtSuccessorsAsPredecessor(this);
+    }
+
+    private boolean checkDeletion() {
+        assertTrue(isAlive(), "must be alive");
+        assertTrue(hasNoUsages(), "cannot delete node %s because of usages: %s", this, usages());
+        assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
+        return true;
+    }
+
+    /**
+     * Removes this node from its graph. This node must have no {@linkplain Node#usages() usages}
+     * and no {@linkplain #predecessor() predecessor}.
+     */
+    public void safeDelete() {
+        assert checkDeletion();
+        this.clearInputs();
+        this.clearSuccessors();
+        markDeleted();
+    }
+
+    public void markDeleted() {
+        graph.unregister(this);
+        id = DELETED_ID_START - id;
+        assert isDeleted();
+    }
+
+    public final Node copyWithInputs() {
+        return copyWithInputs(true);
+    }
+
+    public final Node copyWithInputs(boolean insertIntoGraph) {
+        Node newNode = clone(insertIntoGraph ? graph : null, WithOnlyInputEdges);
+        if (insertIntoGraph) {
+            for (Node input : inputs()) {
+                input.addUsage(newNode);
+            }
+        }
+        return newNode;
+    }
+
+    /**
+     * Must be overridden by subclasses that implement {@link Simplifiable}. The implementation in
+     * {@link Node} exists to obviate the need to cast a node before invoking
+     * {@link Simplifiable#simplify(SimplifierTool)}.
+     *
+     * @param tool
+     */
+    public void simplify(SimplifierTool tool) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @param newNode the result of cloning this node or {@link Unsafe#allocateInstance(Class) raw
+     *            allocating} a copy of this node
+     * @param type the type of edges to process
+     * @param edgesToCopy if {@code type} is in this set, the edges are copied otherwise they are
+     *            cleared
+     */
+    private void copyOrClearEdgesForClone(Node newNode, Edges.Type type, EnumSet<Edges.Type> edgesToCopy) {
+        if (edgesToCopy.contains(type)) {
+            getNodeClass().getEdges(type).copy(this, newNode);
+        } else {
+            if (USE_UNSAFE_TO_CLONE) {
+                // The direct edges are already null
+                getNodeClass().getEdges(type).initializeLists(newNode, this);
+            } else {
+                getNodeClass().getEdges(type).clear(newNode);
+            }
+        }
+    }
+
+    public static final EnumSet<Edges.Type> WithNoEdges = EnumSet.noneOf(Edges.Type.class);
+    public static final EnumSet<Edges.Type> WithAllEdges = EnumSet.allOf(Edges.Type.class);
+    public static final EnumSet<Edges.Type> WithOnlyInputEdges = EnumSet.of(Inputs);
+    public static final EnumSet<Edges.Type> WithOnlySucessorEdges = EnumSet.of(Successors);
+
+    /**
+     * Makes a copy of this node in(to) a given graph.
+     *
+     * @param into the graph in which the copy will be registered (which may be this node's graph)
+     *            or null if the copy should not be registered in a graph
+     * @param edgesToCopy specifies the edges to be copied. The edges not specified in this set are
+     *            initialized to their default value (i.e., {@code null} for a direct edge, an empty
+     *            list for an edge list)
+     * @return the copy of this node
+     */
+    final Node clone(Graph into, EnumSet<Edges.Type> edgesToCopy) {
+        final NodeClass<? extends Node> nodeClassTmp = getNodeClass();
+        boolean useIntoLeafNodeCache = false;
+        if (into != null) {
+            if (nodeClassTmp.valueNumberable() && nodeClassTmp.isLeafNode()) {
+                useIntoLeafNodeCache = true;
+                Node otherNode = into.findNodeInCache(this);
+                if (otherNode != null) {
+                    return otherNode;
+                }
+            }
+        }
+
+        Node newNode = null;
+        try {
+            if (USE_UNSAFE_TO_CLONE) {
+                newNode = (Node) UNSAFE.allocateInstance(getClass());
+                newNode.nodeClass = nodeClassTmp;
+                nodeClassTmp.getData().copy(this, newNode);
+                copyOrClearEdgesForClone(newNode, Inputs, edgesToCopy);
+                copyOrClearEdgesForClone(newNode, Successors, edgesToCopy);
+            } else {
+                newNode = (Node) this.clone();
+                newNode.typeCacheNext = null;
+                newNode.usage0 = null;
+                newNode.usage1 = null;
+                newNode.predecessor = null;
+                newNode.extraUsagesCount = 0;
+                copyOrClearEdgesForClone(newNode, Inputs, edgesToCopy);
+                copyOrClearEdgesForClone(newNode, Successors, edgesToCopy);
+            }
+        } catch (Exception e) {
+            throw new GraalGraphError(e).addContext(this);
+        }
+        newNode.graph = into;
+        newNode.id = INITIAL_ID;
+        if (into != null) {
+            into.register(newNode);
+        }
+        newNode.extraUsages = NO_NODES;
+
+        if (into != null && useIntoLeafNodeCache) {
+            into.putNodeIntoCache(newNode);
+        }
+        if (graph != null && into != null && sourcePosition != null) {
+            newNode.setNodeSourcePosition(sourcePosition);
+        }
+        newNode.afterClone(this);
+        return newNode;
+    }
+
+    protected void afterClone(@SuppressWarnings("unused") Node other) {
+    }
+
+    protected boolean verifyInputs() {
+        for (Position pos : inputPositions()) {
+            Node input = pos.get(this);
+            if (input == null) {
+                assertTrue(pos.isInputOptional(), "non-optional input %s cannot be null in %s (fix nullness or use @OptionalInput)", pos, this);
+            } else {
+                assertFalse(input.isDeleted(), "input was deleted");
+                assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph");
+                assertTrue(pos.getInputType() == InputType.Unchecked || input.isAllowedUsageType(pos.getInputType()), "invalid usage type %s %s", input, pos.getInputType());
+            }
+        }
+        return true;
+    }
+
+    public boolean verify() {
+        assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
+        assertTrue(graph() != null, "null graph");
+        verifyInputs();
+        if (Options.VerifyGraalGraphEdges.getValue()) {
+            verifyEdges();
+        }
+        return true;
+    }
+
+    /**
+     * Perform expensive verification of inputs, usages, predecessors and successors.
+     *
+     * @return true
+     */
+    public boolean verifyEdges() {
+        for (Node input : inputs()) {
+            assertTrue(input == null || input.usages().contains(this), "missing usage of %s in input %s", this, input);
+        }
+
+        for (Node successor : successors()) {
+            assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
+            assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor);
+        }
+        for (Node usage : usages()) {
+            assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage);
+            assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage);
+            boolean foundThis = false;
+            for (Position pos : usage.inputPositions()) {
+                if (pos.get(usage) == this) {
+                    foundThis = true;
+                    if (pos.getInputType() != InputType.Unchecked) {
+                        assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type %s from %s to %s (%s)", pos.getInputType(), usage, this, pos.getName());
+                    }
+                }
+            }
+            assertTrue(foundThis, "missing input in usage %s", usage);
+        }
+
+        if (predecessor != null) {
+            assertFalse(predecessor.isDeleted(), "predecessor %s must never be deleted", predecessor);
+            assertTrue(predecessor.successors().contains(this), "missing successor in predecessor %s", predecessor);
+        }
+        return true;
+    }
+
+    public boolean assertTrue(boolean condition, String message, Object... args) {
+        if (condition) {
+            return true;
+        } else {
+            throw fail(message, args);
+        }
+    }
+
+    public boolean assertFalse(boolean condition, String message, Object... args) {
+        if (condition) {
+            throw fail(message, args);
+        } else {
+            return true;
+        }
+    }
+
+    protected VerificationError fail(String message, Object... args) throws GraalGraphError {
+        throw new VerificationError(message, args).addContext(this);
+    }
+
+    public Iterable<? extends Node> cfgPredecessors() {
+        if (predecessor == null) {
+            return Collections.emptySet();
+        } else {
+            return Collections.singleton(predecessor);
+        }
+    }
+
+    /**
+     * Returns an iterator that will provide all control-flow successors of this node. Normally this
+     * will be the contents of all fields annotated with {@link Successor}, but some node classes
+     * (like EndNode) may return different nodes.
+     */
+    public Iterable<? extends Node> cfgSuccessors() {
+        return successors();
+    }
+
+    /**
+     * Nodes always use an {@linkplain System#identityHashCode(Object) identity} hash code.
+     */
+    @Override
+    public final int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    /**
+     * Equality tests must rely solely on identity.
+     */
+    @Override
+    public final boolean equals(Object obj) {
+        return super.equals(obj);
+    }
+
+    /**
+     * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the
+     * ideal graph visualizer).
+     */
+    public final Map<Object, Object> getDebugProperties() {
+        return getDebugProperties(new HashMap<>());
+    }
+
+    /**
+     * Fills a {@link Map} with properties of this node for use in debugging (e.g., to view in the
+     * ideal graph visualizer). Subclasses overriding this method should also fill the map using
+     * their superclass.
+     *
+     * @param map
+     */
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Fields properties = getNodeClass().getData();
+        for (int i = 0; i < properties.getCount(); i++) {
+            map.put(properties.getName(i), properties.get(this, i));
+        }
+        NodeSourcePosition pos = getNodeSourcePosition();
+        if (pos != null) {
+            map.put("nodeSourcePosition", pos);
+        }
+        return map;
+    }
+
+    /**
+     * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#Short}.
+     */
+    @Override
+    public final String toString() {
+        return toString(Verbosity.Short);
+    }
+
+    /**
+     * Creates a String representation for this node with a given {@link Verbosity}.
+     */
+    public String toString(Verbosity verbosity) {
+        switch (verbosity) {
+            case Id:
+                return Integer.toString(id);
+            case Name:
+                return getNodeClass().shortName();
+            case Short:
+                return toString(Verbosity.Id) + "|" + toString(Verbosity.Name);
+            case Long:
+                return toString(Verbosity.Short);
+            case Debugger:
+            case All: {
+                StringBuilder str = new StringBuilder();
+                str.append(toString(Verbosity.Short)).append(" { ");
+                for (Map.Entry<Object, Object> entry : getDebugProperties().entrySet()) {
+                    str.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
+                }
+                str.append(" }");
+                return str.toString();
+            }
+            default:
+                throw new RuntimeException("unknown verbosity: " + verbosity);
+        }
+    }
+
+    @Deprecated
+    public int getId() {
+        return id;
+    }
+
+    @Override
+    public void formatTo(Formatter formatter, int flags, int width, int precision) {
+        if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) {
+            formatter.format("%s", toString(Verbosity.Id));
+        } else if ((flags & FormattableFlags.UPPERCASE) == FormattableFlags.UPPERCASE) {
+            // Use All here since Long is only slightly longer than Short.
+            formatter.format("%s", toString(Verbosity.All));
+        } else {
+            formatter.format("%s", toString(Verbosity.Short));
+        }
+
+        boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY);
+        int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0);
+        if (width > 0) {
+            if (this.predecessor != null) {
+                formatter.format(" pred={");
+                this.predecessor.formatTo(formatter, neighborsFlags, width - 1, 0);
+                formatter.format("}");
+            }
+
+            for (Position position : this.inputPositions()) {
+                Node input = position.get(this);
+                if (input != null) {
+                    formatter.format(" ");
+                    formatter.format(position.getName());
+                    formatter.format("={");
+                    input.formatTo(formatter, neighborsFlags, width - 1, 0);
+                    formatter.format("}");
+                }
+            }
+        }
+
+        if (precision > 0) {
+            if (!hasNoUsages()) {
+                formatter.format(" usages={");
+                int z = 0;
+                for (Node usage : usages()) {
+                    if (z != 0) {
+                        formatter.format(", ");
+                    }
+                    usage.formatTo(formatter, neighborsFlags, 0, precision - 1);
+                    ++z;
+                }
+                formatter.format("}");
+            }
+
+            for (Position position : this.successorPositions()) {
+                Node successor = position.get(this);
+                if (successor != null) {
+                    formatter.format(" ");
+                    formatter.format(position.getName());
+                    formatter.format("={");
+                    successor.formatTo(formatter, neighborsFlags, 0, precision - 1);
+                    formatter.format("}");
+                }
+            }
+        }
+    }
+
+    /**
+     * Determines if this node's {@link NodeClass#getData() data} fields are equal to the data
+     * fields of another node of the same type. Primitive fields are compared by value and
+     * non-primitive fields are compared by {@link Objects#equals(Object, Object)}.
+     *
+     * The result of this method undefined if {@code other.getClass() != this.getClass()}.
+     *
+     * @param other a node of exactly the same type as this node
+     * @return true if the data fields of this object and {@code other} are equal
+     */
+    public boolean valueEquals(Node other) {
+        return getNodeClass().dataEquals(this, other);
+    }
+
+    public final void pushInputs(NodeStack stack) {
+        getNodeClass().pushInputs(this, stack);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java
new file mode 100644
index 0000000..b8333e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+public final class NodeBitMap implements NodeIterable<Node> {
+    private static final int SHIFT = 6;
+
+    private long[] bits;
+    private int nodeCount;
+    private int counter;
+    private final Graph graph;
+
+    public NodeBitMap(Graph graph) {
+        this.nodeCount = graph.nodeIdCount();
+        this.bits = new long[sizeForNodeCount(nodeCount)];
+        this.graph = graph;
+    }
+
+    private static int sizeForNodeCount(int nodeCount) {
+        return (nodeCount + Long.SIZE - 1) >> SHIFT;
+    }
+
+    public int getCounter() {
+        return counter;
+    }
+
+    private NodeBitMap(NodeBitMap other) {
+        this.bits = other.bits.clone();
+        this.nodeCount = other.nodeCount;
+        this.graph = other.graph;
+    }
+
+    public Graph graph() {
+        return graph;
+    }
+
+    public boolean isNew(Node node) {
+        return node.id() >= nodeCount;
+    }
+
+    public boolean isMarked(Node node) {
+        assert check(node, false);
+        return isMarked(node.id());
+    }
+
+    public boolean checkAndMarkInc(Node node) {
+        if (!isMarked(node)) {
+            this.counter++;
+            this.mark(node);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean isMarked(int id) {
+        return (bits[id >> SHIFT] & (1L << id)) != 0;
+    }
+
+    public boolean isMarkedAndGrow(Node node) {
+        assert check(node, true);
+        int id = node.id();
+        checkGrow(id);
+        return isMarked(id);
+    }
+
+    public void mark(Node node) {
+        assert check(node, false);
+        int id = node.id();
+        bits[id >> SHIFT] |= (1L << id);
+    }
+
+    public void markAndGrow(Node node) {
+        assert check(node, true);
+        int id = node.id();
+        checkGrow(id);
+        bits[id >> SHIFT] |= (1L << id);
+    }
+
+    public void clear(Node node) {
+        assert check(node, false);
+        int id = node.id();
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    public void clearAndGrow(Node node) {
+        assert check(node, true);
+        int id = node.id();
+        checkGrow(id);
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    private void checkGrow(int id) {
+        if (id >= nodeCount) {
+            if ((id >> SHIFT) >= bits.length) {
+                grow();
+            } else {
+                nodeCount = id + 1;
+            }
+        }
+    }
+
+    public void clearAll() {
+        Arrays.fill(bits, 0);
+    }
+
+    public void intersect(NodeBitMap other) {
+        assert graph() == other.graph();
+        int commonLength = Math.min(bits.length, other.bits.length);
+        for (int i = commonLength; i < bits.length; i++) {
+            bits[i] = 0;
+        }
+        for (int i = 0; i < commonLength; i++) {
+            bits[i] &= other.bits[i];
+        }
+    }
+
+    public void subtract(NodeBitMap other) {
+        assert graph() == other.graph();
+        int commonLength = Math.min(bits.length, other.bits.length);
+        for (int i = 0; i < commonLength; i++) {
+            bits[i] &= ~other.bits[i];
+        }
+    }
+
+    public void union(NodeBitMap other) {
+        assert graph() == other.graph();
+        grow();
+        if (bits.length < other.bits.length) {
+            bits = Arrays.copyOf(bits, other.bits.length);
+        }
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] |= other.bits[i];
+        }
+    }
+
+    public void grow() {
+        nodeCount = Math.max(nodeCount, graph().nodeIdCount());
+        int newLength = sizeForNodeCount(nodeCount);
+        if (newLength > bits.length) {
+            newLength = Math.max(newLength, (bits.length * 3 / 2) + 1);
+            bits = Arrays.copyOf(bits, newLength);
+        }
+    }
+
+    private boolean check(Node node, boolean grow) {
+        assert node.graph() == graph() : "this node is not part of the graph: " + node;
+        assert grow || !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
+        assert node.isAlive() : "node is deleted!" + node;
+        return true;
+    }
+
+    public <T extends Node> void markAll(Iterable<T> nodes) {
+        for (Node node : nodes) {
+            mark(node);
+        }
+    }
+
+    private static class MarkedNodeIterator implements Iterator<Node> {
+
+        private final NodeBitMap visited;
+        private Iterator<Node> nodes;
+        private Node nextNode;
+
+        MarkedNodeIterator(NodeBitMap visited, Iterator<Node> nodes) {
+            this.visited = visited;
+            this.nodes = nodes;
+            forward();
+        }
+
+        private void forward() {
+            do {
+                if (!nodes.hasNext()) {
+                    nextNode = null;
+                    return;
+                }
+                nextNode = nodes.next();
+                if (visited.isNew(nextNode)) {
+                    nextNode = null;
+                    return;
+                }
+            } while (!visited.isMarked(nextNode));
+        }
+
+        @Override
+        public boolean hasNext() {
+            return nextNode != null;
+        }
+
+        @Override
+        public Node next() {
+            try {
+                return nextNode;
+            } finally {
+                forward();
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    @Override
+    public Iterator<Node> iterator() {
+        return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator());
+    }
+
+    public NodeBitMap copy() {
+        return new NodeBitMap(this);
+    }
+
+    @Override
+    public int count() {
+        int count = 0;
+        for (long l : bits) {
+            count += Long.bitCount(l);
+        }
+        return count;
+    }
+
+    @Override
+    public boolean contains(Node node) {
+        return isMarked(node);
+    }
+
+    @Override
+    public String toString() {
+        return snapshot().toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java
new file mode 100644
index 0000000..b802b32
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java
@@ -0,0 +1,1360 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.core.common.Fields.translateInto;
+import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.graph.Edges.translateInto;
+import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
+import static org.graalvm.compiler.graph.InputEdges.translateInto;
+import static org.graalvm.compiler.graph.Node.WithAllEdges;
+import static org.graalvm.compiler.graph.Node.newIdentityMap;
+import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.core.common.FieldIntrospection;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.FieldsScanner;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Edges.Type;
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node.EdgeVisitor;
+import org.graalvm.compiler.graph.Node.Input;
+import org.graalvm.compiler.graph.Node.OptionalInput;
+import org.graalvm.compiler.graph.Node.Successor;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+
+/**
+ * Metadata for every {@link Node} type. The metadata includes:
+ * <ul>
+ * <li>The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods
+ * for iterating over such fields.</li>
+ * <li>The identifier for an {@link IterableNodeType} class.</li>
+ * </ul>
+ */
+public final class NodeClass<T> extends FieldIntrospection<T> {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Verifies that receivers of NodeInfo#size() and NodeInfo#cycles() do not have UNSET values.")
+        public static final OptionValue<Boolean> VerifyNodeCostOnAccess = new StableOptionValue<>(false);
+        // @formatter:on
+    }
+
+    // Timers for creation of a NodeClass instance
+    private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning");
+    private static final DebugTimer Init_FieldScanningInner = Debug.timer("NodeClass.Init.FieldScanning.Inner");
+    private static final DebugTimer Init_AnnotationParsing = Debug.timer("NodeClass.Init.AnnotationParsing");
+    private static final DebugTimer Init_Edges = Debug.timer("NodeClass.Init.Edges");
+    private static final DebugTimer Init_Data = Debug.timer("NodeClass.Init.Data");
+    private static final DebugTimer Init_AllowedUsages = Debug.timer("NodeClass.Init.AllowedUsages");
+    private static final DebugTimer Init_IterableIds = Debug.timer("NodeClass.Init.IterableIds");
+
+    public static final long MAX_EDGES = 8;
+    public static final long MAX_LIST_EDGES = 6;
+    public static final long OFFSET_MASK = 0xFC;
+    public static final long LIST_MASK = 0x01;
+    public static final long NEXT_EDGE = 0x08;
+
+    @SuppressWarnings("try")
+    private static <T extends Annotation> T getAnnotationTimed(AnnotatedElement e, Class<T> annotationClass) {
+        try (DebugCloseable s = Init_AnnotationParsing.start()) {
+            return e.getAnnotation(annotationClass);
+        }
+    }
+
+    /**
+     * Gets the {@link NodeClass} associated with a given {@link Class}.
+     */
+    public static <T> NodeClass<T> create(Class<T> c) {
+        assert get(c) == null;
+        Class<? super T> superclass = c.getSuperclass();
+        NodeClass<? super T> nodeSuperclass = null;
+        if (superclass != NODE_CLASS) {
+            nodeSuperclass = get(superclass);
+        }
+        return new NodeClass<>(c, nodeSuperclass);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> NodeClass<T> get(Class<T> superclass) {
+        try {
+            Field field = superclass.getDeclaredField("TYPE");
+            field.setAccessible(true);
+            return (NodeClass<T>) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static final Class<?> NODE_CLASS = Node.class;
+    private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
+    private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
+
+    private static AtomicInteger nextIterableId = new AtomicInteger();
+
+    private final InputEdges inputs;
+    private final SuccessorEdges successors;
+    private final NodeClass<? super T> superNodeClass;
+
+    private final boolean canGVN;
+    private final int startGVNNumber;
+    private final String nameTemplate;
+    private final int iterableId;
+    private final EnumSet<InputType> allowedUsageTypes;
+    private int[] iterableIds;
+    private final long inputsIteration;
+    private final long successorIteration;
+
+    private static final DebugCounter ITERABLE_NODE_TYPES = Debug.counter("IterableNodeTypes");
+    private final DebugCounter nodeIterableCount;
+
+    /**
+     * Determines if this node type implements {@link Canonicalizable}.
+     */
+    private final boolean isCanonicalizable;
+
+    /**
+     * Determines if this node type implements {@link BinaryCommutative}.
+     */
+    private final boolean isCommutative;
+
+    /**
+     * Determines if this node type implements {@link Simplifiable}.
+     */
+    private final boolean isSimplifiable;
+    private final boolean isLeafNode;
+
+    public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass) {
+        this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0);
+    }
+
+    @SuppressWarnings("try")
+    public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
+        super(clazz);
+        this.superNodeClass = superNodeClass;
+        assert NODE_CLASS.isAssignableFrom(clazz);
+
+        this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
+        this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz);
+        if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) {
+            assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both";
+        }
+
+        this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
+
+        NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass);
+        try (DebugCloseable t = Init_FieldScanning.start()) {
+            fs.scan(clazz, clazz.getSuperclass(), false);
+        }
+
+        try (DebugCloseable t1 = Init_Edges.start()) {
+            successors = new SuccessorEdges(fs.directSuccessors, fs.successors);
+            successorIteration = computeIterationMask(successors.type(), successors.getDirectCount(), successors.getOffsets());
+            inputs = new InputEdges(fs.directInputs, fs.inputs);
+            inputsIteration = computeIterationMask(inputs.type(), inputs.getDirectCount(), inputs.getOffsets());
+        }
+        try (DebugCloseable t1 = Init_Data.start()) {
+            data = new Fields(fs.data);
+        }
+
+        isLeafNode = inputs.getCount() + successors.getCount() == 0;
+
+        canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
+        startGVNNumber = clazz.getName().hashCode();
+
+        NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
+        assert info != null : "Missing NodeInfo annotation on " + clazz;
+        this.nameTemplate = info.nameTemplate();
+
+        try (DebugCloseable t1 = Init_AllowedUsages.start()) {
+            allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone();
+            allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes()));
+        }
+
+        if (presetIterableIds != null) {
+            this.iterableIds = presetIterableIds;
+            this.iterableId = presetIterableId;
+        } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
+            ITERABLE_NODE_TYPES.increment();
+            try (DebugCloseable t1 = Init_IterableIds.start()) {
+                this.iterableId = nextIterableId.getAndIncrement();
+
+                NodeClass<?> snc = superNodeClass;
+                while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
+                    snc.addIterableId(iterableId);
+                    snc = snc.superNodeClass;
+                }
+
+                this.iterableIds = new int[]{iterableId};
+            }
+        } else {
+            this.iterableId = Node.NOT_ITERABLE;
+            this.iterableIds = null;
+        }
+        nodeIterableCount = Debug.counter("NodeIterable_%s", clazz);
+        assert verifyIterableIds();
+
+        try (Debug.Scope scope = Debug.scope("NodeCosts")) {
+            /*
+             * Note: We do not check for the existence of the node cost annotations during
+             * construction as not every node needs to have them set. However if costs are queried,
+             * after the construction of the node class, they must be properly set. This is
+             * important as we can not trust our cost model if there are unspecified nodes. Nodes
+             * that do not need cost annotations are e.g. abstractions like FixedNode or
+             * FloatingNode or ValueNode. Sub classes where costs are not specified will ask the
+             * superclass for their costs during node class initialization. Therefore getters for
+             * cycles and size can omit verification during creation.
+             */
+            NodeCycles c = info.cycles();
+            if (c == NodeCycles.CYCLES_UNSET) {
+                cycles = superNodeClass != null ? superNodeClass.cycles : NodeCycles.CYCLES_UNSET;
+            } else {
+                cycles = c;
+            }
+            assert cycles != null;
+            NodeSize s = info.size();
+            if (s == NodeSize.SIZE_UNSET) {
+                size = superNodeClass != null ? superNodeClass.size : NodeSize.SIZE_UNSET;
+            } else {
+                size = s;
+            }
+            assert size != null;
+            Debug.log("Node cost for node of type __| %s |_, cycles:%s,size:%s", clazz, cycles, size);
+        }
+
+    }
+
+    private final NodeCycles cycles;
+    private final NodeSize size;
+
+    public NodeCycles cycles() {
+        if (Options.VerifyNodeCostOnAccess.getValue() && cycles == NodeCycles.CYCLES_UNSET) {
+            throw new GraalError("Missing NodeCycles specification in the @NodeInfo annotation of the node %s", this);
+        }
+        return cycles;
+    }
+
+    public NodeSize size() {
+        if (Options.VerifyNodeCostOnAccess.getValue() && size == NodeSize.SIZE_UNSET) {
+            throw new GraalError("Missing NodeSize specification in the @NodeInfo annotation of the node %s", this);
+        }
+        return size;
+    }
+
+    public static long computeIterationMask(Type type, int directCount, long[] offsets) {
+        long mask = 0;
+        if (offsets.length > NodeClass.MAX_EDGES) {
+            throw new GraalError("Exceeded maximum of %d edges (%s)", NodeClass.MAX_EDGES, type);
+        }
+        if (offsets.length - directCount > NodeClass.MAX_LIST_EDGES) {
+            throw new GraalError("Exceeded maximum of %d list edges (%s)", NodeClass.MAX_LIST_EDGES, type);
+        }
+
+        for (int i = offsets.length - 1; i >= 0; i--) {
+            long offset = offsets[i];
+            assert ((offset & 0xFF) == offset) : "field offset too large!";
+            mask <<= NodeClass.NEXT_EDGE;
+            mask |= offset;
+            if (i >= directCount) {
+                mask |= 0x3;
+            }
+        }
+        return mask;
+    }
+
+    private synchronized void addIterableId(int newIterableId) {
+        assert !containsId(newIterableId, iterableIds);
+        int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1);
+        copy[iterableIds.length] = newIterableId;
+        iterableIds = copy;
+    }
+
+    private boolean verifyIterableIds() {
+        NodeClass<?> snc = superNodeClass;
+        while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
+            assert containsId(iterableId, snc.iterableIds);
+            snc = snc.superNodeClass;
+        }
+        return true;
+    }
+
+    private static boolean containsId(int iterableId, int[] iterableIds) {
+        for (int i : iterableIds) {
+            if (i == iterableId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String shortName;
+
+    public String shortName() {
+        if (shortName == null) {
+            NodeInfo info = getClazz().getAnnotation(NodeInfo.class);
+            if (!info.shortName().isEmpty()) {
+                shortName = info.shortName();
+            } else {
+                String localShortName = getClazz().getSimpleName();
+                if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals("EndNode")) {
+                    shortName = localShortName.substring(0, localShortName.length() - 4);
+                } else {
+                    shortName = localShortName;
+                }
+            }
+        }
+        return shortName;
+    }
+
+    @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, inputs, successors};
+    }
+
+    public int[] iterableIds() {
+        nodeIterableCount.increment();
+        return iterableIds;
+    }
+
+    public int iterableId() {
+        return iterableId;
+    }
+
+    public boolean valueNumberable() {
+        return canGVN;
+    }
+
+    /**
+     * Determines if this node type implements {@link Canonicalizable}.
+     */
+    public boolean isCanonicalizable() {
+        return isCanonicalizable;
+    }
+
+    /**
+     * Determines if this node type implements {@link BinaryCommutative}.
+     */
+    public boolean isCommutative() {
+        return isCommutative;
+    }
+
+    /**
+     * Determines if this node type implements {@link Simplifiable}.
+     */
+    public boolean isSimplifiable() {
+        return isSimplifiable;
+    }
+
+    static int allocatedNodeIterabledIds() {
+        return nextIterableId.get();
+    }
+
+    public EnumSet<InputType> getAllowedUsageTypes() {
+        return allowedUsageTypes;
+    }
+
+    /**
+     * Describes a field representing an input or successor edge in a node.
+     */
+    protected static class EdgeInfo extends FieldsScanner.FieldInfo {
+
+        public EdgeInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
+            super(offset, name, type, declaringClass);
+        }
+
+        /**
+         * Sorts non-list edges before list edges.
+         */
+        @Override
+        public int compareTo(FieldsScanner.FieldInfo o) {
+            if (NodeList.class.isAssignableFrom(o.type)) {
+                if (!NodeList.class.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (NodeList.class.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+    }
+
+    /**
+     * Describes a field representing an {@linkplain Type#Inputs input} edge in a node.
+     */
+    protected static class InputInfo extends EdgeInfo {
+        final InputType inputType;
+        final boolean optional;
+
+        public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) {
+            super(offset, name, type, declaringClass);
+            this.inputType = inputType;
+            this.optional = optional;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}";
+        }
+    }
+
+    protected static class NodeFieldsScanner extends FieldsScanner {
+
+        public final ArrayList<InputInfo> inputs = new ArrayList<>();
+        public final ArrayList<EdgeInfo> successors = new ArrayList<>();
+        int directInputs;
+        int directSuccessors;
+
+        protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass<?> superNodeClass) {
+            super(calc);
+            if (superNodeClass != null) {
+                translateInto(superNodeClass.inputs, inputs);
+                translateInto(superNodeClass.successors, successors);
+                translateInto(superNodeClass.data, data);
+                directInputs = superNodeClass.inputs.getDirectCount();
+                directSuccessors = superNodeClass.successors.getDirectCount();
+            }
+        }
+
+        @SuppressWarnings("try")
+        @Override
+        protected void scanField(Field field, long offset) {
+            Input inputAnnotation = getAnnotationTimed(field, Node.Input.class);
+            OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class);
+            Successor successorAnnotation = getAnnotationTimed(field, Successor.class);
+            try (DebugCloseable s = Init_FieldScanningInner.start()) {
+                Class<?> type = field.getType();
+                int modifiers = field.getModifiers();
+
+                if (inputAnnotation != null || optionalInputAnnotation != null) {
+                    assert successorAnnotation == null : "field cannot be both input and successor";
+                    if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
+                        // NodeInputList fields should not be final since they are
+                        // written (via Unsafe) in clearInputs()
+                        GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field);
+                        GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field);
+                    } else {
+                        GraalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
+                        GraalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field);
+                        directInputs++;
+                    }
+                    InputType inputType;
+                    if (inputAnnotation != null) {
+                        assert optionalInputAnnotation == null : "inputs can either be optional or non-optional";
+                        inputType = inputAnnotation.value();
+                    } else {
+                        inputType = optionalInputAnnotation.value();
+                    }
+                    inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
+                } else if (successorAnnotation != null) {
+                    if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
+                        // NodeSuccessorList fields should not be final since they are
+                        // written (via Unsafe) in clearSuccessors()
+                        GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeSuccessorList successor field % should not be final", field);
+                        GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeSuccessorList successor field %s should not be public", field);
+                    } else {
+                        GraalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type);
+                        GraalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field);
+                        directSuccessors++;
+                    }
+                    successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass()));
+                } else {
+                    GraalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
+                    GraalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
+                    GraalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field);
+                    super.scanField(field, offset);
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append("NodeClass ").append(getClazz().getSimpleName()).append(" [");
+        inputs.appendFields(str);
+        str.append("] [");
+        successors.appendFields(str);
+        str.append("] [");
+        data.appendFields(str);
+        str.append("]");
+        return str.toString();
+    }
+
+    private static int deepHashCode0(Object o) {
+        if (o instanceof Object[]) {
+            return Arrays.deepHashCode((Object[]) o);
+        } else if (o instanceof byte[]) {
+            return Arrays.hashCode((byte[]) o);
+        } else if (o instanceof short[]) {
+            return Arrays.hashCode((short[]) o);
+        } else if (o instanceof int[]) {
+            return Arrays.hashCode((int[]) o);
+        } else if (o instanceof long[]) {
+            return Arrays.hashCode((long[]) o);
+        } else if (o instanceof char[]) {
+            return Arrays.hashCode((char[]) o);
+        } else if (o instanceof float[]) {
+            return Arrays.hashCode((float[]) o);
+        } else if (o instanceof double[]) {
+            return Arrays.hashCode((double[]) o);
+        } else if (o instanceof boolean[]) {
+            return Arrays.hashCode((boolean[]) o);
+        } else if (o != null) {
+            return o.hashCode();
+        } else {
+            return 0;
+        }
+    }
+
+    public int valueNumber(Node n) {
+        int number = 0;
+        if (canGVN) {
+            number = startGVNNumber;
+            for (int i = 0; i < data.getCount(); ++i) {
+                Class<?> type = data.getType(i);
+                if (type.isPrimitive()) {
+                    if (type == Integer.TYPE) {
+                        int intValue = data.getInt(n, i);
+                        number += intValue;
+                    } else if (type == Long.TYPE) {
+                        long longValue = data.getLong(n, i);
+                        number += longValue ^ (longValue >>> 32);
+                    } else if (type == Boolean.TYPE) {
+                        boolean booleanValue = data.getBoolean(n, i);
+                        if (booleanValue) {
+                            number += 7;
+                        }
+                    } else if (type == Float.TYPE) {
+                        float floatValue = data.getFloat(n, i);
+                        number += Float.floatToRawIntBits(floatValue);
+                    } else if (type == Double.TYPE) {
+                        double doubleValue = data.getDouble(n, i);
+                        long longValue = Double.doubleToRawLongBits(doubleValue);
+                        number += longValue ^ (longValue >>> 32);
+                    } else if (type == Short.TYPE) {
+                        short shortValue = data.getShort(n, i);
+                        number += shortValue;
+                    } else if (type == Character.TYPE) {
+                        char charValue = data.getChar(n, i);
+                        number += charValue;
+                    } else if (type == Byte.TYPE) {
+                        byte byteValue = data.getByte(n, i);
+                        number += byteValue;
+                    } else {
+                        assert false : "unhandled property type: " + type;
+                    }
+                } else {
+                    Object o = data.getObject(n, i);
+                    number += deepHashCode0(o);
+                }
+                number *= 13;
+            }
+        }
+        return number;
+    }
+
+    private static boolean deepEquals0(Object e1, Object e2) {
+        assert e1 != null;
+        boolean eq;
+        if (e1 instanceof Object[] && e2 instanceof Object[]) {
+            eq = Arrays.deepEquals((Object[]) e1, (Object[]) e2);
+        } else if (e1 instanceof byte[] && e2 instanceof byte[]) {
+            eq = Arrays.equals((byte[]) e1, (byte[]) e2);
+        } else if (e1 instanceof short[] && e2 instanceof short[]) {
+            eq = Arrays.equals((short[]) e1, (short[]) e2);
+        } else if (e1 instanceof int[] && e2 instanceof int[]) {
+            eq = Arrays.equals((int[]) e1, (int[]) e2);
+        } else if (e1 instanceof long[] && e2 instanceof long[]) {
+            eq = Arrays.equals((long[]) e1, (long[]) e2);
+        } else if (e1 instanceof char[] && e2 instanceof char[]) {
+            eq = Arrays.equals((char[]) e1, (char[]) e2);
+        } else if (e1 instanceof float[] && e2 instanceof float[]) {
+            eq = Arrays.equals((float[]) e1, (float[]) e2);
+        } else if (e1 instanceof double[] && e2 instanceof double[]) {
+            eq = Arrays.equals((double[]) e1, (double[]) e2);
+        } else if (e1 instanceof boolean[] && e2 instanceof boolean[]) {
+            eq = Arrays.equals((boolean[]) e1, (boolean[]) e2);
+        } else {
+            eq = e1.equals(e2);
+        }
+        return eq;
+    }
+
+    public boolean dataEquals(Node a, Node b) {
+        assert a.getClass() == b.getClass();
+        for (int i = 0; i < data.getCount(); ++i) {
+            Class<?> type = data.getType(i);
+            if (type.isPrimitive()) {
+                if (type == Integer.TYPE) {
+                    int aInt = data.getInt(a, i);
+                    int bInt = data.getInt(b, i);
+                    if (aInt != bInt) {
+                        return false;
+                    }
+                } else if (type == Boolean.TYPE) {
+                    boolean aBoolean = data.getBoolean(a, i);
+                    boolean bBoolean = data.getBoolean(b, i);
+                    if (aBoolean != bBoolean) {
+                        return false;
+                    }
+                } else if (type == Long.TYPE) {
+                    long aLong = data.getLong(a, i);
+                    long bLong = data.getLong(b, i);
+                    if (aLong != bLong) {
+                        return false;
+                    }
+                } else if (type == Float.TYPE) {
+                    float aFloat = data.getFloat(a, i);
+                    float bFloat = data.getFloat(b, i);
+                    if (aFloat != bFloat) {
+                        return false;
+                    }
+                } else if (type == Double.TYPE) {
+                    double aDouble = data.getDouble(a, i);
+                    double bDouble = data.getDouble(b, i);
+                    if (aDouble != bDouble) {
+                        return false;
+                    }
+                } else if (type == Short.TYPE) {
+                    short aShort = data.getShort(a, i);
+                    short bShort = data.getShort(b, i);
+                    if (aShort != bShort) {
+                        return false;
+                    }
+                } else if (type == Character.TYPE) {
+                    char aChar = data.getChar(a, i);
+                    char bChar = data.getChar(b, i);
+                    if (aChar != bChar) {
+                        return false;
+                    }
+                } else if (type == Byte.TYPE) {
+                    byte aByte = data.getByte(a, i);
+                    byte bByte = data.getByte(b, i);
+                    if (aByte != bByte) {
+                        return false;
+                    }
+                } else {
+                    assert false : "unhandled type: " + type;
+                }
+            } else {
+                Object objectA = data.getObject(a, i);
+                Object objectB = data.getObject(b, i);
+                if (objectA != objectB) {
+                    if (objectA != null && objectB != null) {
+                        if (!deepEquals0(objectA, objectB)) {
+                            return false;
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    public boolean isValid(Position pos, NodeClass<?> from, Edges fromEdges) {
+        if (this == from) {
+            return true;
+        }
+        Edges toEdges = getEdges(fromEdges.type());
+        if (pos.getIndex() >= toEdges.getCount()) {
+            return false;
+        }
+        if (pos.getIndex() >= fromEdges.getCount()) {
+            return false;
+        }
+        return toEdges.isSame(fromEdges, pos.getIndex());
+    }
+
+    static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
+        int index = 0;
+        Type curType = edges.type();
+        int directCount = edges.getDirectCount();
+        final long[] curOffsets = edges.getOffsets();
+        while (index < directCount) {
+            Node edge = Edges.getNode(node, curOffsets, index);
+            if (edge != null) {
+                Node newEdge = duplicationReplacement.replacement(edge, curType);
+                if (curType == Edges.Type.Inputs) {
+                    node.updateUsages(null, newEdge);
+                } else {
+                    node.updatePredecessor(null, newEdge);
+                }
+                edges.initializeNode(node, index, newEdge);
+            }
+            index++;
+        }
+
+        while (index < edges.getCount()) {
+            NodeList<Node> list = Edges.getNodeList(node, curOffsets, index);
+            if (list != null) {
+                edges.initializeList(node, index, updateEdgeListCopy(node, list, duplicationReplacement, curType));
+            }
+            index++;
+        }
+    }
+
+    void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
+        updateEdgesInPlace(node, duplicationReplacement, inputs);
+        updateEdgesInPlace(node, duplicationReplacement, successors);
+    }
+
+    private static NodeList<Node> updateEdgeListCopy(Node node, NodeList<Node> list, InplaceUpdateClosure duplicationReplacement, Edges.Type type) {
+        NodeList<Node> result = type == Edges.Type.Inputs ? new NodeInputList<>(node, list.size()) : new NodeSuccessorList<>(node, list.size());
+
+        for (int i = 0; i < list.count(); ++i) {
+            Node oldNode = list.get(i);
+            if (oldNode != null) {
+                Node newNode = duplicationReplacement.replacement(oldNode, type);
+                result.set(i, newNode);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Gets the input or successor edges defined by this node class.
+     */
+    public Edges getEdges(Edges.Type type) {
+        return type == Edges.Type.Inputs ? inputs : successors;
+    }
+
+    public Edges getInputEdges() {
+        return inputs;
+    }
+
+    public Edges getSuccessorEdges() {
+        return successors;
+    }
+
+    /**
+     * Returns a newly allocated node for which no subclass-specific constructor has been called.
+     */
+    @SuppressWarnings("unchecked")
+    public Node allocateInstance() {
+        try {
+            Node node = (Node) UNSAFE.allocateInstance(getJavaClass());
+            node.init((NodeClass<? extends Node>) this);
+            return node;
+        } catch (InstantiationException ex) {
+            throw shouldNotReachHere(ex);
+        }
+    }
+
+    public Class<T> getJavaClass() {
+        return getClazz();
+    }
+
+    /**
+     * The template used to build the {@link Verbosity#Name} version. Variable parts are specified
+     * using &#123;i#inputName&#125; or &#123;p#propertyName&#125;.
+     */
+    public String getNameTemplate() {
+        return nameTemplate.isEmpty() ? shortName() : nameTemplate;
+    }
+
+    interface InplaceUpdateClosure {
+
+        Node replacement(Node node, Edges.Type type);
+    }
+
+    static Map<Node, Node> addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable<? extends Node> nodes, final DuplicationReplacement replacements) {
+        final Map<Node, Node> newNodes;
+        int denseThreshold = oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4;
+        if (estimatedNodeCount > denseThreshold) {
+            // Use dense map
+            newNodes = new NodeNodeMap(oldGraph);
+        } else {
+            // Use sparse map
+            newNodes = newIdentityMap();
+        }
+        createNodeDuplicates(graph, nodes, replacements, newNodes);
+
+        InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() {
+
+            @Override
+            public Node replacement(Node node, Edges.Type type) {
+                Node target = newNodes.get(node);
+                if (target == null) {
+                    Node replacement = node;
+                    if (replacements != null) {
+                        replacement = replacements.replacement(node);
+                    }
+                    if (replacement != node) {
+                        target = replacement;
+                    } else if (node.graph() == graph && type == Edges.Type.Inputs) {
+                        // patch to the outer world
+                        target = node;
+                    }
+
+                }
+                return target;
+            }
+
+        };
+
+        // re-wire inputs
+        for (Node oldNode : nodes) {
+            Node node = newNodes.get(oldNode);
+            NodeClass<?> nodeClass = node.getNodeClass();
+            if (replacements == null || replacements.replacement(oldNode) == oldNode) {
+                nodeClass.updateInputSuccInPlace(node, replacementClosure);
+            } else {
+                transferEdgesDifferentNodeClass(graph, replacements, newNodes, oldNode, node);
+            }
+        }
+
+        return newNodes;
+    }
+
+    private static void createNodeDuplicates(final Graph graph, Iterable<? extends Node> nodes, final DuplicationReplacement replacements, final Map<Node, Node> newNodes) {
+        for (Node node : nodes) {
+            if (node != null) {
+                assert !node.isDeleted() : "trying to duplicate deleted node: " + node;
+                Node replacement = node;
+                if (replacements != null) {
+                    replacement = replacements.replacement(node);
+                }
+                if (replacement != node) {
+                    if (Fingerprint.ENABLED) {
+                        Fingerprint.submit("replacing %s with %s", node, replacement);
+                    }
+                    assert replacement != null;
+                    newNodes.put(node, replacement);
+                } else {
+                    if (Fingerprint.ENABLED) {
+                        Fingerprint.submit("duplicating %s", node);
+                    }
+                    Node newNode = node.clone(graph, WithAllEdges);
+                    assert newNode.getNodeClass().isLeafNode() || newNode.hasNoUsages();
+                    assert newNode.getClass() == node.getClass();
+                    newNodes.put(node, newNode);
+                }
+            }
+        }
+    }
+
+    private static void transferEdgesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node) {
+        transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Inputs);
+        transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Successors);
+    }
+
+    private static void transferEdges(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node, Edges.Type type) {
+        NodeClass<?> nodeClass = node.getNodeClass();
+        NodeClass<?> oldNodeClass = oldNode.getNodeClass();
+        Edges oldEdges = oldNodeClass.getEdges(type);
+        for (Position pos : oldEdges.getPositionsIterable(oldNode)) {
+            if (!nodeClass.isValid(pos, oldNodeClass, oldEdges)) {
+                continue;
+            }
+            Node oldEdge = pos.get(oldNode);
+            if (oldEdge != null) {
+                Node target = newNodes.get(oldEdge);
+                if (target == null) {
+                    Node replacement = oldEdge;
+                    if (replacements != null) {
+                        replacement = replacements.replacement(oldEdge);
+                    }
+                    if (replacement != oldEdge) {
+                        target = replacement;
+                    } else if (type == Edges.Type.Inputs && oldEdge.graph() == graph) {
+                        // patch to the outer world
+                        target = oldEdge;
+                    }
+                }
+                pos.set(node, target);
+            }
+        }
+    }
+
+    /**
+     * @returns true if the node has no inputs and no successors
+     */
+    public boolean isLeafNode() {
+        return isLeafNode;
+    }
+
+    public long inputsIteration() {
+        return inputsIteration;
+    }
+
+    /**
+     * An iterator that will iterate over edges.
+     *
+     * An iterator of this type will not return null values, unless edges are modified concurrently.
+     * Concurrent modifications are detected by an assertion on a best-effort basis.
+     */
+    private static class RawEdgesIterator implements Iterator<Node> {
+        protected final Node node;
+        protected long mask;
+        protected Node nextValue;
+
+        RawEdgesIterator(Node node, long mask) {
+            this.node = node;
+            this.mask = mask;
+        }
+
+        @Override
+        public boolean hasNext() {
+            Node next = nextValue;
+            if (next != null) {
+                return true;
+            } else {
+                nextValue = forward();
+                return nextValue != null;
+            }
+        }
+
+        private Node forward() {
+            while (mask != 0) {
+                Node next = getInput();
+                mask = advanceInput();
+                if (next != null) {
+                    return next;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public Node next() {
+            Node next = nextValue;
+            if (next == null) {
+                next = forward();
+                if (next == null) {
+                    throw new NoSuchElementException();
+                } else {
+                    return next;
+                }
+            } else {
+                nextValue = null;
+                return next;
+            }
+        }
+
+        public final long advanceInput() {
+            int state = (int) mask & 0x03;
+            if (state == 0) {
+                // Skip normal field.
+                return mask >>> NEXT_EDGE;
+            } else if (state == 1) {
+                // We are iterating a node list.
+                if ((mask & 0xFFFF00) != 0) {
+                    // Node list count is non-zero, decrease by 1.
+                    return mask - 0x100;
+                } else {
+                    // Node list is finished => go to next input.
+                    return mask >>> 24;
+                }
+            } else {
+                // Need to expand node list.
+                NodeList<?> nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC);
+                if (nodeList != null) {
+                    int size = nodeList.size();
+                    if (size != 0) {
+                        // Set pointer to upper most index of node list.
+                        return ((mask >>> NEXT_EDGE) << 24) | (mask & 0xFD) | ((size - 1) << NEXT_EDGE);
+                    }
+                }
+                // Node list is empty or null => skip.
+                return mask >>> NEXT_EDGE;
+            }
+        }
+
+        public Node getInput() {
+            int state = (int) mask & 0x03;
+            if (state == 0) {
+                return Edges.getNodeUnsafe(node, mask & 0xFC);
+            } else if (state == 1) {
+                // We are iterating a node list.
+                NodeList<?> nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC);
+                return nodeList.nodes[nodeList.size() - 1 - (int) ((mask >>> NEXT_EDGE) & 0xFFFF)];
+            } else {
+                // Node list needs to expand first.
+                return null;
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Position nextPosition() {
+            return null;
+        }
+    }
+
+    private static final class RawEdgesWithModCountIterator extends RawEdgesIterator {
+        private final int modCount;
+
+        private RawEdgesWithModCountIterator(Node node, long mask) {
+            super(node, mask);
+            assert isModificationCountsEnabled();
+            this.modCount = node.modCount();
+        }
+
+        @Override
+        public boolean hasNext() {
+            try {
+                return super.hasNext();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+
+        @Override
+        public Node next() {
+            try {
+                return super.next();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+
+        @Override
+        public Position nextPosition() {
+            try {
+                return super.nextPosition();
+            } finally {
+                assert modCount == node.modCount();
+            }
+        }
+    }
+
+    public NodeIterable<Node> getSuccessorIterable(final Node node) {
+        long mask = this.successorIteration;
+        return new NodeIterable<Node>() {
+
+            @Override
+            public Iterator<Node> iterator() {
+                if (isModificationCountsEnabled()) {
+                    return new RawEdgesWithModCountIterator(node, mask);
+                } else {
+                    return new RawEdgesIterator(node, mask);
+                }
+            }
+        };
+    }
+
+    public NodeIterable<Node> getInputIterable(final Node node) {
+        long mask = this.inputsIteration;
+        return new NodeIterable<Node>() {
+
+            @Override
+            public Iterator<Node> iterator() {
+                if (isModificationCountsEnabled()) {
+                    return new RawEdgesWithModCountIterator(node, mask);
+                } else {
+                    return new RawEdgesIterator(node, mask);
+                }
+            }
+        };
+    }
+
+    public boolean equalSuccessors(Node node, Node other) {
+        return equalEdges(node, other, successorIteration);
+    }
+
+    public boolean equalInputs(Node node, Node other) {
+        return equalEdges(node, other, inputsIteration);
+    }
+
+    private boolean equalEdges(Node node, Node other, long mask) {
+        long myMask = mask;
+        assert other.getNodeClass() == this;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            Object v1 = UNSAFE.getObject(node, offset);
+            Object v2 = UNSAFE.getObject(other, offset);
+            if ((myMask & LIST_MASK) == 0) {
+                if (v1 != v2) {
+                    return false;
+                }
+            } else {
+                if (!Objects.equals(v1, v2)) {
+                    return false;
+                }
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+        return true;
+    }
+
+    public void pushInputs(Node node, NodeStack stack) {
+        long myMask = this.inputsIteration;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    stack.push(curNode);
+                }
+            } else {
+                pushAllHelper(stack, node, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void pushAllHelper(NodeStack stack, Node node, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    stack.push(curNode);
+                }
+            }
+        }
+    }
+
+    public void applySuccessors(Node node, EdgeVisitor consumer) {
+        applyEdges(node, consumer, this.successorIteration);
+    }
+
+    public void applyInputs(Node node, EdgeVisitor consumer) {
+        applyEdges(node, consumer, this.inputsIteration);
+    }
+
+    private static void applyEdges(Node node, EdgeVisitor consumer, long mask) {
+        long myMask = mask;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    Node newNode = consumer.apply(node, curNode);
+                    if (newNode != curNode) {
+                        UNSAFE.putObject(node, offset, newNode);
+                    }
+                }
+            } else {
+                applyHelper(node, consumer, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void applyHelper(Node node, EdgeVisitor consumer, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    Node newNode = consumer.apply(node, curNode);
+                    if (newNode != curNode) {
+                        list.initialize(i, newNode);
+                    }
+                }
+            }
+        }
+    }
+
+    public void unregisterAtSuccessorsAsPredecessor(Node node) {
+        long myMask = this.successorIteration;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    node.updatePredecessor(curNode, null);
+                    UNSAFE.putObject(node, offset, null);
+                }
+            } else {
+                unregisterAtSuccessorsAsPredecessorHelper(node, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void unregisterAtSuccessorsAsPredecessorHelper(Node node, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    node.updatePredecessor(curNode, null);
+                }
+            }
+            list.clearWithoutUpdate();
+        }
+    }
+
+    public void registerAtSuccessorsAsPredecessor(Node node) {
+        long myMask = this.successorIteration;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    assert curNode.isAlive() : "Successor not alive";
+                    node.updatePredecessor(null, curNode);
+                }
+            } else {
+                registerAtSuccessorsAsPredecessorHelper(node, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void registerAtSuccessorsAsPredecessorHelper(Node node, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    assert curNode.isAlive() : "Successor not alive";
+                    node.updatePredecessor(null, curNode);
+                }
+            }
+        }
+    }
+
+    public boolean replaceFirstInput(Node node, Node key, Node replacement) {
+        return replaceFirstEdge(node, key, replacement, this.inputsIteration);
+    }
+
+    public boolean replaceFirstSuccessor(Node node, Node key, Node replacement) {
+        return replaceFirstEdge(node, key, replacement, this.successorIteration);
+    }
+
+    public static boolean replaceFirstEdge(Node node, Node key, Node replacement, long mask) {
+        long myMask = mask;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Object curNode = UNSAFE.getObject(node, offset);
+                if (curNode == key) {
+                    UNSAFE.putObject(node, offset, replacement);
+                    return true;
+                }
+            } else {
+                NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+                if (list != null && list.replaceFirst(key, replacement)) {
+                    return true;
+                }
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+        return false;
+    }
+
+    public void registerAtInputsAsUsage(Node node) {
+        long myMask = this.inputsIteration;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    assert curNode.isAlive() : "Input not alive " + curNode;
+                    curNode.addUsage(node);
+                }
+            } else {
+                registerAtInputsAsUsageHelper(node, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void registerAtInputsAsUsageHelper(Node node, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    assert curNode.isAlive() : "Input not alive";
+                    curNode.addUsage(node);
+                }
+            }
+        }
+    }
+
+    public void unregisterAtInputsAsUsage(Node node) {
+        long myMask = this.inputsIteration;
+        while (myMask != 0) {
+            long offset = (myMask & OFFSET_MASK);
+            if ((myMask & LIST_MASK) == 0) {
+                Node curNode = Edges.getNodeUnsafe(node, offset);
+                if (curNode != null) {
+                    node.removeThisFromUsages(curNode);
+                    if (curNode.hasNoUsages()) {
+                        node.maybeNotifyZeroUsages(curNode);
+                    }
+                    UNSAFE.putObject(node, offset, null);
+                }
+            } else {
+                unregisterAtInputsAsUsageHelper(node, offset);
+            }
+            myMask >>>= NEXT_EDGE;
+        }
+    }
+
+    private static void unregisterAtInputsAsUsageHelper(Node node, long offset) {
+        NodeList<Node> list = Edges.getNodeListUnsafe(node, offset);
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    node.removeThisFromUsages(curNode);
+                    if (curNode.hasNoUsages()) {
+                        node.maybeNotifyZeroUsages(curNode);
+                    }
+                }
+            }
+            list.clearWithoutUpdate();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeCollectionsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeCollectionsProvider.java
new file mode 100644
index 0000000..848c9ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeCollectionsProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.api.collections.CollectionsProvider;
+
+/**
+ * Extends {@link CollectionsProvider} with support for creating {@link Node} based collections.
+ */
+public interface NodeCollectionsProvider extends CollectionsProvider {
+
+    /**
+     * Creates a set of {@link Node}s that uses reference-equality in place of object-equality when
+     * comparing entries.
+     */
+    <E extends Node> Set<E> newNodeIdentitySet();
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap();
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap(int expectedMaxSize);
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     *
+     * @param initFrom the returned map is populated with the entries in this map
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap(Map<K, V> initFrom);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeFlood.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeFlood.java
new file mode 100644
index 0000000..c69ce24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeFlood.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.ArrayDeque;
+import java.util.Iterator;
+import java.util.Queue;
+
+public final class NodeFlood implements Iterable<Node> {
+
+    private final NodeBitMap visited;
+    private final Queue<Node> worklist;
+    private int totalMarkedCount;
+
+    public NodeFlood(Graph graph) {
+        visited = graph.createNodeBitMap();
+        worklist = new ArrayDeque<>();
+    }
+
+    public void add(Node node) {
+        if (node != null && !visited.isMarked(node)) {
+            visited.mark(node);
+            worklist.add(node);
+            totalMarkedCount++;
+        }
+    }
+
+    public int getTotalMarkedCount() {
+        return totalMarkedCount;
+    }
+
+    public void addAll(Iterable<? extends Node> nodes) {
+        for (Node node : nodes) {
+            this.add(node);
+        }
+    }
+
+    public NodeBitMap getVisited() {
+        return visited;
+    }
+
+    public boolean isMarked(Node node) {
+        return visited.isMarked(node);
+    }
+
+    public boolean isNew(Node node) {
+        return visited.isNew(node);
+    }
+
+    private static class QueueConsumingIterator implements Iterator<Node> {
+
+        private final Queue<Node> queue;
+
+        QueueConsumingIterator(Queue<Node> queue) {
+            this.queue = queue;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return !queue.isEmpty();
+        }
+
+        @Override
+        public Node next() {
+            return queue.remove();
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public Iterator<Node> iterator() {
+        return new QueueConsumingIterator(worklist);
+    }
+
+    private static class UnmarkedNodeIterator implements Iterator<Node> {
+
+        private final NodeBitMap visited;
+        private Iterator<Node> nodes;
+        private Node nextNode;
+
+        UnmarkedNodeIterator(NodeBitMap visited, Iterator<Node> nodes) {
+            this.visited = visited;
+            this.nodes = nodes;
+            forward();
+        }
+
+        private void forward() {
+            do {
+                if (!nodes.hasNext()) {
+                    nextNode = null;
+                    return;
+                }
+                nextNode = nodes.next();
+            } while (visited.isMarked(nextNode));
+        }
+
+        @Override
+        public boolean hasNext() {
+            return nextNode != null;
+        }
+
+        @Override
+        public Node next() {
+            try {
+                return nextNode;
+            } finally {
+                forward();
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public Iterable<Node> unmarkedNodes() {
+        return new Iterable<Node>() {
+
+            @Override
+            public Iterator<Node> iterator() {
+                return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator());
+            }
+        };
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java
new file mode 100644
index 0000000..67a1cc7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+/**
+ * An entity that depends upon {@linkplain Graph#maybeCompress() stable} node identifiers.
+ */
+class NodeIdAccessor {
+    final Graph graph;
+    final int epoch;
+
+    NodeIdAccessor(Graph graph) {
+        this.graph = graph;
+        this.epoch = graph.compressions;
+    }
+
+    Graph getGraph() {
+        return graph;
+    }
+
+    /**
+     * Verifies that node identifiers have not changed since this object was created.
+     *
+     * @return true if the check succeeds
+     * @throws VerificationError if the check fails
+     */
+    boolean verifyIdsAreStable() {
+        int compressions = graph.compressions - epoch;
+        if (compressions != 0) {
+            throw new VerificationError("accessing node id in %s across %d graph compression%s", graph, compressions, compressions == 1 ? "" : "s");
+        }
+        return true;
+    }
+
+    /**
+     * Gets the identifier for a node. If assertions are enabled, this method asserts that the
+     * identifier is stable.
+     */
+    int getNodeId(Node node) {
+        assert verifyIdsAreStable();
+        return node.id();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java
new file mode 100644
index 0000000..4df1e7d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Edges.Type.Inputs;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.graalvm.compiler.graph.Edges.Type;
+
+public final class NodeInputList<T extends Node> extends NodeList<T> {
+
+    public NodeInputList(Node self, int initialSize) {
+        super(self, initialSize);
+    }
+
+    public NodeInputList(Node self) {
+        super(self);
+    }
+
+    public NodeInputList(Node self, T[] elements) {
+        super(self, elements);
+        assert self.hasNoUsages();
+    }
+
+    public NodeInputList(Node self, List<? extends T> elements) {
+        super(self, elements);
+        assert self.hasNoUsages();
+    }
+
+    public NodeInputList(Node self, Collection<? extends NodeInterface> elements) {
+        super(self, elements);
+        assert self.hasNoUsages();
+    }
+
+    @Override
+    protected void update(T oldNode, T newNode) {
+        self.updateUsages(oldNode, newNode);
+    }
+
+    @Override
+    public Type getEdgesType() {
+        return Inputs;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java
new file mode 100644
index 0000000..5c2c622
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+public interface NodeInterface {
+    Node asNode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java
new file mode 100644
index 0000000..caa0eea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.RandomAccess;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess {
+
+    protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
+
+    protected final Node self;
+    protected Node[] nodes;
+    private int size;
+    protected final int initialSize;
+
+    protected NodeList(Node self) {
+        this.self = self;
+        this.nodes = EMPTY_NODE_ARRAY;
+        this.initialSize = 0;
+    }
+
+    protected NodeList(Node self, int initialSize) {
+        this.self = self;
+        this.size = initialSize;
+        this.initialSize = initialSize;
+        this.nodes = new Node[initialSize];
+    }
+
+    protected NodeList(Node self, T[] elements) {
+        this.self = self;
+        if (elements == null || elements.length == 0) {
+            this.size = 0;
+            this.nodes = EMPTY_NODE_ARRAY;
+            this.initialSize = 0;
+        } else {
+            this.size = elements.length;
+            this.initialSize = elements.length;
+            this.nodes = new Node[elements.length];
+            for (int i = 0; i < elements.length; i++) {
+                this.nodes[i] = elements[i];
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i];
+            }
+        }
+    }
+
+    protected NodeList(Node self, List<? extends T> elements) {
+        this.self = self;
+        if (elements == null || elements.isEmpty()) {
+            this.size = 0;
+            this.nodes = EMPTY_NODE_ARRAY;
+            this.initialSize = 0;
+        } else {
+            this.size = elements.size();
+            this.initialSize = elements.size();
+            this.nodes = new Node[elements.size()];
+            for (int i = 0; i < elements.size(); i++) {
+                this.nodes[i] = elements.get(i);
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
+            }
+        }
+    }
+
+    protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
+        this.self = self;
+        if (elements == null || elements.isEmpty()) {
+            this.size = 0;
+            this.nodes = EMPTY_NODE_ARRAY;
+            this.initialSize = 0;
+        } else {
+            this.size = elements.size();
+            this.initialSize = elements.size();
+            this.nodes = new Node[elements.size()];
+            int i = 0;
+            for (NodeInterface n : elements) {
+                this.nodes[i] = n.asNode();
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
+                i++;
+            }
+        }
+    }
+
+    public boolean isList() {
+        return true;
+    }
+
+    protected abstract void update(T oldNode, T newNode);
+
+    public abstract Edges.Type getEdgesType();
+
+    @Override
+    public final int size() {
+        return size;
+    }
+
+    @Override
+    public final boolean isEmpty() {
+        return size == 0;
+    }
+
+    @Override
+    public boolean isNotEmpty() {
+        return size > 0;
+    }
+
+    @Override
+    public int count() {
+        return size;
+    }
+
+    protected final void incModCount() {
+        modCount++;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean add(Node node) {
+        assert node == null || !node.isDeleted();
+        self.incModCount();
+        incModCount();
+        int length = nodes.length;
+        if (length == 0) {
+            nodes = new Node[2];
+        } else if (size == length) {
+            Node[] newNodes = new Node[nodes.length * 2 + 1];
+            System.arraycopy(nodes, 0, newNodes, 0, length);
+            nodes = newNodes;
+        }
+        nodes[size++] = node;
+        update(null, (T) node);
+        return true;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T get(int index) {
+        assert assertInRange(index);
+        return (T) nodes[index];
+    }
+
+    private boolean assertInRange(int index) {
+        assert index >= 0 && index < size() : index + " < " + size();
+        return true;
+    }
+
+    public T last() {
+        return get(size() - 1);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T set(int index, Node node) {
+        incModCount();
+        T oldValue = (T) nodes[index];
+        assert assertInRange(index);
+        update((T) nodes[index], (T) node);
+        nodes[index] = node;
+        return oldValue;
+    }
+
+    public void initialize(int index, Node node) {
+        incModCount();
+        assert index < size();
+        nodes[index] = node;
+    }
+
+    void copy(NodeList<? extends Node> other) {
+        self.incModCount();
+        incModCount();
+        Node[] newNodes = new Node[other.size];
+        System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length);
+        nodes = newNodes;
+        size = other.size;
+    }
+
+    public boolean equals(NodeList<T> other) {
+        if (size != other.size) {
+            return false;
+        }
+        for (int i = 0; i < size; i++) {
+            if (nodes[i] != other.nodes[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void clear() {
+        self.incModCount();
+        incModCount();
+        for (int i = 0; i < size; i++) {
+            update((T) nodes[i], null);
+        }
+        clearWithoutUpdate();
+    }
+
+    void clearWithoutUpdate() {
+        nodes = EMPTY_NODE_ARRAY;
+        size = 0;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean remove(Object node) {
+        self.incModCount();
+        int i = 0;
+        incModCount();
+        while (i < size && nodes[i] != node) {
+            i++;
+        }
+        if (i < size) {
+            T oldValue = (T) nodes[i];
+            i++;
+            while (i < size) {
+                nodes[i - 1] = nodes[i];
+                i++;
+            }
+            nodes[--size] = null;
+            update(oldValue, null);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T remove(int index) {
+        self.incModCount();
+        T oldValue = (T) nodes[index];
+        int i = index + 1;
+        incModCount();
+        while (i < size) {
+            nodes[i - 1] = nodes[i];
+            i++;
+        }
+        nodes[--size] = null;
+        update(oldValue, null);
+        return oldValue;
+    }
+
+    boolean replaceFirst(Node node, Node other) {
+        for (int i = 0; i < size; i++) {
+            if (nodes[i] == node) {
+                nodes[i] = other;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return new NodeListIterator<>(this, 0);
+    }
+
+    @Override
+    public boolean contains(T other) {
+        for (int i = 0; i < size; i++) {
+            if (nodes[i] == other) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<T> snapshot() {
+        return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size));
+    }
+
+    @Override
+    public void snapshotTo(Collection<? super T> to) {
+        for (int i = 0; i < size; i++) {
+            to.add(get(i));
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void setAll(NodeList<T> values) {
+        self.incModCount();
+        incModCount();
+        for (int i = 0; i < size(); i++) {
+            update((T) nodes[i], null);
+        }
+        nodes = Arrays.copyOf(values.nodes, values.size());
+        size = values.size();
+
+        for (int i = 0; i < size(); i++) {
+            update(null, (T) nodes[i]);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <A> A[] toArray(A[] a) {
+        if (a.length >= size) {
+            System.arraycopy(nodes, 0, a, 0, size);
+            return a;
+        }
+        return (A[]) Arrays.copyOf(nodes, size, a.getClass());
+    }
+
+    @Override
+    public Object[] toArray() {
+        return Arrays.copyOf(nodes, size);
+    }
+
+    protected void replace(T node, T other) {
+        incModCount();
+        for (int i = 0; i < size(); i++) {
+            if (nodes[i] == node) {
+                nodes[i] = other;
+                update(node, other);
+            }
+        }
+    }
+
+    @Override
+    public int indexOf(Object node) {
+        for (int i = 0; i < size; i++) {
+            if (nodes[i] == node) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return indexOf(o) != -1;
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> c) {
+        for (T e : c) {
+            add(e);
+        }
+        return true;
+    }
+
+    public boolean addAll(T[] c) {
+        for (T e : c) {
+            add(e);
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(nodes[i]);
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+    @Override
+    public T first() {
+        if (size() > 0) {
+            return get(0);
+        }
+        return null;
+    }
+
+    public SubList<T> subList(int startIndex) {
+        assert assertInRange(startIndex);
+        return new SubList<>(this, startIndex);
+    }
+
+    public static final class SubList<R extends Node> extends AbstractList<R> implements NodeIterable<R>, RandomAccess {
+        private final NodeList<R> list;
+        private final int offset;
+
+        private SubList(NodeList<R> list, int offset) {
+            this.list = list;
+            this.offset = offset;
+        }
+
+        @Override
+        public R get(int index) {
+            assert index >= 0 : index;
+            return list.get(offset + index);
+        }
+
+        @Override
+        public int size() {
+            return list.size() - offset;
+        }
+
+        public SubList<R> subList(int startIndex) {
+            assert startIndex >= 0 && startIndex < size() : startIndex;
+            return new SubList<>(this.list, startIndex + offset);
+        }
+
+        @Override
+        public Iterator<R> iterator() {
+            return new NodeListIterator<>(list, offset);
+        }
+    }
+
+    private static final class NodeListIterator<R extends Node> implements Iterator<R> {
+        private final NodeList<R> list;
+        private final int expectedModCount;
+        private int index;
+
+        private NodeListIterator(NodeList<R> list, int startIndex) {
+            this.list = list;
+            this.expectedModCount = list.modCount;
+            this.index = startIndex;
+        }
+
+        @Override
+        public boolean hasNext() {
+            assert expectedModCount == list.modCount;
+            return index < list.size;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public R next() {
+            assert expectedModCount == list.modCount;
+            return (R) list.nodes[index++];
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java
new file mode 100644
index 0000000..32ab50d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+public class NodeMap<T> extends NodeIdAccessor {
+
+    private static final int MIN_REALLOC_SIZE = 16;
+
+    protected Object[] values;
+
+    public NodeMap(Graph graph) {
+        super(graph);
+        this.values = new Object[graph.nodeIdCount()];
+    }
+
+    public NodeMap(NodeMap<T> copyFrom) {
+        super(copyFrom.graph);
+        this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length);
+    }
+
+    @SuppressWarnings("unchecked")
+    public T get(Node node) {
+        assert check(node);
+        return (T) values[getNodeId(node)];
+    }
+
+    @SuppressWarnings("unchecked")
+    public T getAndGrow(Node node) {
+        checkAndGrow(node);
+        return (T) values[getNodeId(node)];
+    }
+
+    private void checkAndGrow(Node node) {
+        if (isNew(node)) {
+            this.values = Arrays.copyOf(values, Math.max(MIN_REALLOC_SIZE, graph.nodeIdCount() * 3 / 2));
+        }
+        assert check(node);
+    }
+
+    public boolean isEmpty() {
+        return !entries().iterator().hasNext();
+    }
+
+    public boolean containsKey(Object key) {
+        if (key instanceof Node) {
+            Node node = (Node) key;
+            if (node.graph() == graph()) {
+                return get(node) != null;
+            }
+        }
+        return false;
+    }
+
+    public boolean containsValue(Object value) {
+        for (Object o : values) {
+            if (o == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Graph graph() {
+        return graph;
+    }
+
+    public void set(Node node, T value) {
+        assert check(node);
+        values[getNodeId(node)] = value;
+    }
+
+    public void setAndGrow(Node node, T value) {
+        checkAndGrow(node);
+        values[getNodeId(node)] = value;
+    }
+
+    /**
+     * @param i
+     * @return Return the key for the entry at index {@code i}
+     */
+    protected Node getKey(int i) {
+        return graph.getNode(i);
+    }
+
+    public int size() {
+        return values.length;
+    }
+
+    public boolean isNew(Node node) {
+        return getNodeId(node) >= size();
+    }
+
+    private boolean check(Node node) {
+        assert node.graph() == graph : String.format("%s is not part of the graph", node);
+        assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
+        return true;
+    }
+
+    public void clear() {
+        Arrays.fill(values, null);
+    }
+
+    public Iterable<Entry<Node, T>> entries() {
+        return new Iterable<Entry<Node, T>>() {
+
+            @Override
+            public Iterator<Entry<Node, T>> iterator() {
+                return new Iterator<Entry<Node, T>>() {
+
+                    int i = 0;
+
+                    @Override
+                    public boolean hasNext() {
+                        forward();
+                        return i < NodeMap.this.values.length;
+                    }
+
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public Entry<Node, T> next() {
+                        final int pos = i;
+                        Node key = NodeMap.this.getKey(pos);
+                        T value = (T) NodeMap.this.values[pos];
+                        i++;
+                        forward();
+                        return new SimpleEntry<Node, T>(key, value) {
+
+                            private static final long serialVersionUID = 7813842391085737738L;
+
+                            @Override
+                            public T setValue(T v) {
+                                T oldv = super.setValue(v);
+                                NodeMap.this.values[pos] = v;
+                                return oldv;
+                            }
+                        };
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+
+                    private void forward() {
+                        while (i < NodeMap.this.values.length && (NodeMap.this.getKey(i) == null || NodeMap.this.values[i] == null)) {
+                            i++;
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public String toString() {
+        Iterator<Entry<Node, T>> i = entries().iterator();
+        if (!i.hasNext()) {
+            return "{}";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        while (true) {
+            Entry<Node, T> e = i.next();
+            Node key = e.getKey();
+            T value = e.getValue();
+            sb.append(key);
+            sb.append('=');
+            sb.append(value);
+            if (!i.hasNext()) {
+                return sb.append('}').toString();
+            }
+            sb.append(',').append(' ');
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeNodeMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeNodeMap.java
new file mode 100644
index 0000000..31e4071
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeNodeMap.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public final class NodeNodeMap extends NodeMap<Node> implements Map<Node, Node> {
+
+    public NodeNodeMap(Graph graph) {
+        super(graph);
+    }
+
+    public NodeNodeMap(NodeNodeMap copyFrom) {
+        super(copyFrom);
+    }
+
+    @Override
+    public Node get(Object key) {
+        return super.get((Node) key);
+    }
+
+    @Override
+    public Node put(Node key, Node value) {
+        Node oldValue = super.get(key);
+        super.set(key, value);
+        return oldValue;
+    }
+
+    @Override
+    public Node remove(Object key) {
+        throw new UnsupportedOperationException("Cannot remove keys from this map");
+    }
+
+    @Override
+    public void putAll(Map<? extends Node, ? extends Node> m) {
+        for (Entry<? extends Node, ? extends Node> entry : m.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public Set<Node> keySet() {
+        HashSet<Node> entries = new HashSet<>();
+        for (int i = 0; i < values.length; ++i) {
+            Object v = values[i];
+            if (v != null) {
+                Node key = getKey(i);
+                if (key != null) {
+                    entries.add(key);
+                }
+            }
+        }
+        /*
+         * The normal contract for entrySet is that modifications of the set are reflected in the
+         * underlying data structure. For simplicity don't allow that but complain if someone tries
+         * to use it that way.
+         */
+        return Collections.unmodifiableSet(entries);
+    }
+
+    @Override
+    public Collection<Node> values() {
+        ArrayList<Node> result = new ArrayList<>(this.size());
+        for (int i = 0; i < values.length; ++i) {
+            Object v = values[i];
+            if (v != null) {
+                result.add((Node) v);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Set<Map.Entry<Node, Node>> entrySet() {
+        HashSet<Map.Entry<Node, Node>> entries = new HashSet<>();
+        for (Map.Entry<Node, Node> entry : entries()) {
+            entries.add(entry);
+        }
+        /*
+         * The normal contract for entrySet is that modifications of the set are reflected in the
+         * underlying data structure. For simplicity don't allow that but complain if someone tries
+         * to use it that way.
+         */
+        return Collections.unmodifiableSet(entries);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java
new file mode 100644
index 0000000..f747d79
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Objects;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaUtil;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class NodeSourcePosition extends BytecodePosition {
+
+    /**
+     * The receiver of the method this frame refers to.
+     */
+    private final JavaConstant receiver;
+
+    public NodeSourcePosition(JavaConstant receiver, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
+        super(caller, method, bci);
+        this.receiver = receiver;
+        assert receiver == null || method.getDeclaringClass().isInstance(receiver);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj != null && getClass() == obj.getClass()) {
+            NodeSourcePosition that = (NodeSourcePosition) obj;
+            if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) &&
+                            Objects.equals(this.receiver, that.receiver)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public JavaConstant getReceiver() {
+        return receiver;
+    }
+
+    @Override
+    public NodeSourcePosition getCaller() {
+        return (NodeSourcePosition) super.getCaller();
+    }
+
+    public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) {
+        if (getCaller() == null) {
+            assert newCallerReceiver == null || receiver == null : "replacing receiver";
+            return new NodeSourcePosition(newCallerReceiver, link, getMethod(), getBCI());
+        } else {
+            return new NodeSourcePosition(receiver, getCaller().addCaller(newCallerReceiver, link), getMethod(), getBCI());
+        }
+    }
+
+    public NodeSourcePosition addCaller(NodeSourcePosition link) {
+        return addCaller(null, link);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(100);
+        NodeSourcePosition pos = this;
+        while (pos != null) {
+            MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
+            if (pos.receiver != null) {
+                sb.append("receiver=" + pos.receiver + " ");
+            }
+            pos = pos.getCaller();
+            if (pos != null) {
+                sb.append(CodeUtil.NEW_LINE);
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java
new file mode 100644
index 0000000..5e82577
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+public final class NodeStack {
+
+    private static final int INITIAL_SIZE = 8;
+
+    protected Node[] values;
+    public int tos;
+
+    public NodeStack() {
+        values = new Node[INITIAL_SIZE];
+    }
+
+    public void push(Node n) {
+        int newIndex = tos++;
+        int valuesLength = values.length;
+        if (newIndex >= valuesLength) {
+            grow();
+        }
+        values[newIndex] = n;
+    }
+
+    private void grow() {
+        int valuesLength = values.length;
+        Node[] newValues = new Node[valuesLength << 1];
+        System.arraycopy(values, 0, newValues, 0, valuesLength);
+        values = newValues;
+    }
+
+    public Node pop() {
+        assert tos > 0 : "stack must be non-empty";
+        return values[--tos];
+    }
+
+    public Node peek() {
+        assert tos > 0 : "stack must be non-empty";
+        return values[tos - 1];
+    }
+
+    public boolean isEmpty() {
+        return tos == 0;
+    }
+
+    @Override
+    public String toString() {
+        if (tos == 0) {
+            return "NodeStack: []";
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < tos; i++) {
+            sb.append(", ");
+            sb.append(values[i]);
+        }
+        return "NodeStack: [" + sb.substring(2) + "]";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSuccessorList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSuccessorList.java
new file mode 100644
index 0000000..2d87d53
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSuccessorList.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Edges.Type.Successors;
+
+import java.util.List;
+
+import org.graalvm.compiler.graph.Edges.Type;
+
+public final class NodeSuccessorList<T extends Node> extends NodeList<T> {
+
+    public NodeSuccessorList(Node self, int initialSize) {
+        super(self, initialSize);
+    }
+
+    protected NodeSuccessorList(Node self) {
+        super(self);
+    }
+
+    public NodeSuccessorList(Node self, T[] elements) {
+        super(self, elements);
+        assert self.hasNoUsages();
+    }
+
+    public NodeSuccessorList(Node self, List<? extends T> elements) {
+        super(self, elements);
+        assert self.hasNoUsages();
+    }
+
+    @Override
+    protected void update(T oldNode, T newNode) {
+        self.updatePredecessor(oldNode, newNode);
+    }
+
+    @Override
+    public Type getEdgesType() {
+        return Successors;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUnionFind.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUnionFind.java
new file mode 100644
index 0000000..c997bf2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUnionFind.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+/**
+ * Union-find data structure for {@link Node Nodes}.
+ *
+ * All operations have an accumulated worst-case complexity of O(a(n)), where a(n) is the inverse of
+ * the Ackermann function A(n,n).
+ */
+public class NodeUnionFind extends NodeIdAccessor {
+
+    private int[] rank;
+    private int[] parent;
+
+    /**
+     * Create a new union-find data structure for a {@link Graph}. Initially, all nodes are in their
+     * own equivalence set.
+     */
+    public NodeUnionFind(Graph graph) {
+        super(graph);
+        rank = new int[graph.nodeIdCount()];
+        parent = new int[graph.nodeIdCount()];
+        for (int i = 0; i < parent.length; i++) {
+            parent[i] = i;
+        }
+    }
+
+    /**
+     * Merge the equivalence sets of two nodes.
+     *
+     * After calling this function, find(a) == find(b).
+     */
+    public void union(Node a, Node b) {
+        union(getNodeId(a), getNodeId(b));
+    }
+
+    /**
+     * Get a representative element of the equivalence set of a node.
+     *
+     * This function returns the same representative element for all members of the same equivalence
+     * set, i.e., find(a) == find(b) if and only if a and b are in the same set.
+     */
+    public Node find(Node a) {
+        int id = find(getNodeId(a));
+        return graph.getNode(id);
+    }
+
+    public boolean equiv(Node a, Node b) {
+        return find(getNodeId(a)) == find(getNodeId(b));
+    }
+
+    private void union(int a, int b) {
+        int aRoot = find(a);
+        int bRoot = find(b);
+        if (aRoot != bRoot) {
+            if (rank[aRoot] < rank[bRoot]) {
+                parent[aRoot] = bRoot;
+            } else {
+                parent[bRoot] = aRoot;
+                if (rank[aRoot] == rank[bRoot]) {
+                    rank[aRoot]++;
+                }
+            }
+        }
+    }
+
+    private int find(int a) {
+        int ret = a;
+        while (ret != parent[ret]) {
+            parent[ret] = parent[parent[ret]];
+            ret = parent[ret];
+        }
+        return ret;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterable.java
new file mode 100644
index 0000000..b84fada
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterable.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+
+class NodeUsageIterable implements NodeIterable<Node> {
+
+    private final Node node;
+
+    NodeUsageIterable(Node node) {
+        this.node = node;
+    }
+
+    @Override
+    public NodeUsageIterator iterator() {
+        if (isModificationCountsEnabled()) {
+            return new NodeUsageWithModCountIterator(node);
+        } else {
+            return new NodeUsageIterator(node);
+        }
+    }
+
+    @Override
+    public Node first() {
+        return node.usage0;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return node.usage0 == null;
+    }
+
+    @Override
+    public boolean isNotEmpty() {
+        return node.usage0 != null;
+    }
+
+    @Override
+    public int count() {
+        return node.getUsageCount();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterator.java
new file mode 100644
index 0000000..272225e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageIterator.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class NodeUsageIterator implements Iterator<Node> {
+
+    final Node node;
+    int index = -1;
+    Node current;
+
+    void advance() {
+        current = null;
+        index++;
+        if (index == 0) {
+            current = node.usage0;
+        } else if (index == 1) {
+            current = node.usage1;
+        } else {
+            int relativeIndex = index - Node.INLINE_USAGE_COUNT;
+            if (relativeIndex < node.extraUsagesCount) {
+                current = node.extraUsages[relativeIndex];
+            }
+        }
+    }
+
+    NodeUsageIterator(Node node) {
+        this.node = node;
+        advance();
+    }
+
+    @Override
+    public boolean hasNext() {
+        return current != null;
+    }
+
+    @Override
+    public Node next() {
+        Node result = current;
+        if (result == null) {
+            throw new NoSuchElementException();
+        }
+        advance();
+        return result;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageWithModCountIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageWithModCountIterator.java
new file mode 100644
index 0000000..287bab0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeUsageWithModCountIterator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.ConcurrentModificationException;
+
+class NodeUsageWithModCountIterator extends NodeUsageIterator {
+
+    NodeUsageWithModCountIterator(Node n) {
+        super(n);
+    }
+
+    private final int expectedModCount = node.usageModCount();
+
+    @Override
+    public boolean hasNext() {
+        if (expectedModCount != node.usageModCount()) {
+            throw new ConcurrentModificationException();
+        }
+        return super.hasNext();
+    }
+
+    @Override
+    public Node next() {
+        if (expectedModCount != node.usageModCount()) {
+            throw new ConcurrentModificationException();
+        }
+        return super.next();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java
new file mode 100644
index 0000000..335826d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.ArrayDeque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+
+public abstract class NodeWorkList implements Iterable<Node> {
+
+    protected final Queue<Node> worklist;
+
+    private NodeWorkList(Graph graph, boolean fill) {
+        if (fill) {
+            ArrayDeque<Node> deque = new ArrayDeque<>(graph.getNodeCount());
+            for (Node node : graph.getNodes()) {
+                deque.add(node);
+            }
+            worklist = deque;
+        } else {
+            worklist = new ArrayDeque<>();
+        }
+    }
+
+    public void addAll(Iterable<? extends Node> nodes) {
+        for (Node node : nodes) {
+            if (node.isAlive()) {
+                this.add(node);
+            }
+        }
+    }
+
+    public abstract void add(Node node);
+
+    public abstract boolean contains(Node node);
+
+    private abstract class QueueConsumingIterator implements Iterator<Node> {
+
+        protected void dropDeleted() {
+            while (!worklist.isEmpty() && worklist.peek().isDeleted()) {
+                worklist.remove();
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public static final class IterativeNodeWorkList extends NodeWorkList {
+
+        private static final int EXPLICIT_BITMAP_THRESHOLD = 10;
+        protected NodeBitMap inQueue;
+
+        private int iterationLimit = Integer.MAX_VALUE;
+        private Node firstNoChange;
+        private Node lastPull;
+        private Node lastChain;
+
+        public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
+            super(graph, fill);
+            if (iterationLimitPerNode > 0) {
+                iterationLimit = iterationLimitPerNode * graph.getNodeCount();
+            }
+        }
+
+        @Override
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return iterationLimit > 0 && !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    if (iterationLimit-- <= 0) {
+                        throw new NoSuchElementException();
+                    }
+                    dropDeleted();
+                    Node node = worklist.remove();
+                    assert updateInfiniteWork(node);
+                    if (inQueue != null) {
+                        inQueue.clearAndGrow(node);
+                    }
+                    return node;
+                }
+
+                private boolean updateInfiniteWork(Node node) {
+                    if (lastPull != lastChain) {
+                        firstNoChange = null;
+                    }
+                    lastPull = node;
+                    return true;
+                }
+            };
+        }
+
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (inQueue == null && worklist.size() > EXPLICIT_BITMAP_THRESHOLD) {
+                    inflateToBitMap(node.graph());
+                }
+
+                if (inQueue != null) {
+                    if (inQueue.isMarkedAndGrow(node)) {
+                        return;
+                    }
+                } else {
+                    for (Node queuedNode : worklist) {
+                        if (queuedNode == node) {
+                            return;
+                        }
+                    }
+                }
+                assert checkInfiniteWork(node) : "Readded " + node;
+                if (inQueue != null) {
+                    inQueue.markAndGrow(node);
+                }
+                worklist.add(node);
+            }
+        }
+
+        @Override
+        public boolean contains(Node node) {
+            if (inQueue != null) {
+                return inQueue.isMarked(node);
+            } else {
+                for (Node queuedNode : worklist) {
+                    if (queuedNode == node) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
+        private boolean checkInfiniteWork(Node node) {
+            if (lastPull == node && !node.hasNoUsages()) {
+                if (firstNoChange == null) {
+                    firstNoChange = node;
+                    lastChain = node;
+                } else if (node == firstNoChange) {
+                    return false;
+                } else {
+                    lastChain = node;
+                }
+            } else {
+                firstNoChange = null;
+            }
+            return true;
+        }
+
+        private void inflateToBitMap(Graph graph) {
+            assert inQueue == null;
+            inQueue = graph.createNodeBitMap();
+            for (Node queuedNode : worklist) {
+                if (queuedNode.isAlive()) {
+                    inQueue.mark(queuedNode);
+                }
+            }
+        }
+    }
+
+    public static final class SingletonNodeWorkList extends NodeWorkList {
+        protected final NodeBitMap visited;
+
+        public SingletonNodeWorkList(Graph graph) {
+            super(graph, false);
+            visited = graph.createNodeBitMap();
+        }
+
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (!visited.isMarkedAndGrow(node)) {
+                    visited.mark(node);
+                    worklist.add(node);
+                }
+            }
+        }
+
+        @Override
+        public boolean contains(Node node) {
+            return visited.isMarked(node);
+        }
+
+        @Override
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    dropDeleted();
+                    return worklist.remove();
+                }
+            };
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Position.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Position.java
new file mode 100644
index 0000000..f7b87e8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Position.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import org.graalvm.compiler.nodeinfo.InputType;
+
+/**
+ * Describes an edge slot for a {@link NodeClass}.
+ */
+public final class Position {
+
+    /**
+     * The edges in which this position lies.
+     */
+    private final Edges edges;
+
+    /**
+     * Index of the {@link Node} or {@link NodeList} field denoted by this position.
+     */
+    private final int index;
+
+    /**
+     * Index within a {@link NodeList} if {@link #index} denotes a {@link NodeList} field otherwise
+     * {@link Node#NOT_ITERABLE}.
+     */
+    private final int subIndex;
+
+    public Position(Edges edges, int index, int subIndex) {
+        this.edges = edges;
+        this.index = index;
+        this.subIndex = subIndex;
+    }
+
+    public Node get(Node node) {
+        if (index < edges.getDirectCount()) {
+            return Edges.getNode(node, edges.getOffsets(), index);
+        } else {
+            return Edges.getNodeList(node, edges.getOffsets(), index).get(subIndex);
+        }
+    }
+
+    public InputType getInputType() {
+        return ((InputEdges) edges).getInputType(index);
+    }
+
+    public String getName() {
+        return edges.getName(index);
+    }
+
+    public boolean isInputOptional() {
+        return ((InputEdges) edges).isOptional(index);
+    }
+
+    public void set(Node node, Node value) {
+        if (index < edges.getDirectCount()) {
+            edges.setNode(node, index, value);
+        } else {
+            Edges.getNodeList(node, edges.getOffsets(), index).set(subIndex, value);
+        }
+    }
+
+    public void initialize(Node node, Node value) {
+        if (index < edges.getDirectCount()) {
+            edges.initializeNode(node, index, value);
+        } else {
+            Edges.getNodeList(node, edges.getOffsets(), index).initialize(subIndex, value);
+        }
+    }
+
+    @Override
+    public String toString() {
+        String res = edges.getType(index).getSimpleName() + ":" + edges.getName(index);
+        if (subIndex != Node.NOT_ITERABLE) {
+            res += "[" + subIndex + "]";
+        }
+        return res;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + index;
+        result = prime * result + edges.hashCode();
+        result = prime * result + subIndex;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Position other = (Position) obj;
+        if (index != other.index) {
+            return false;
+        }
+        if (edges != other.edges) {
+            return false;
+        }
+        if (subIndex != other.subIndex) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Gets the index within a {@link NodeList} if {@link #getIndex()} denotes a {@link NodeList}
+     * field otherwise {@link Node#NOT_ITERABLE}.
+     */
+    public int getSubIndex() {
+        return subIndex;
+    }
+
+    /**
+     * Gets the index of the {@link Node} or {@link NodeList} field denoted by this position.
+     */
+    public int getIndex() {
+        return index;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SuccessorEdges.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SuccessorEdges.java
new file mode 100644
index 0000000..7c34d8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SuccessorEdges.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import static org.graalvm.compiler.graph.Edges.Type.Successors;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.graph.NodeClass.EdgeInfo;
+
+public final class SuccessorEdges extends Edges {
+
+    public SuccessorEdges(int directCount, ArrayList<EdgeInfo> edges) {
+        super(Successors, directCount, edges);
+    }
+
+    @Override
+    public void update(Node node, Node oldValue, Node newValue) {
+        node.updatePredecessor(oldValue, newValue);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/TypedGraphNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/TypedGraphNodeIterator.java
new file mode 100644
index 0000000..e018065
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/TypedGraphNodeIterator.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class TypedGraphNodeIterator<T extends IterableNodeType> implements Iterator<T> {
+
+    private final Graph graph;
+    private final int[] ids;
+    private final Node[] current;
+
+    private int currentIdIndex;
+    private boolean needsForward;
+
+    TypedGraphNodeIterator(NodeClass<?> clazz, Graph graph) {
+        this.graph = graph;
+        ids = clazz.iterableIds();
+        currentIdIndex = 0;
+        current = new Node[ids.length];
+        Arrays.fill(current, Graph.PLACE_HOLDER);
+        needsForward = true;
+    }
+
+    private Node findNext() {
+        if (needsForward) {
+            forward();
+        } else {
+            Node c = current();
+            Node afterDeleted = graph.getIterableNodeNext(c);
+            if (afterDeleted == null) {
+                needsForward = true;
+            } else if (c != afterDeleted) {
+                setCurrent(afterDeleted);
+            }
+        }
+        if (needsForward) {
+            return null;
+        }
+        return current();
+    }
+
+    private void forward() {
+        needsForward = false;
+        int startIdx = currentIdIndex;
+        while (true) {
+            Node next;
+            if (current() == Graph.PLACE_HOLDER) {
+                next = graph.getIterableNodeStart(ids[currentIdIndex]);
+            } else {
+                next = graph.getIterableNodeNext(current().typeCacheNext);
+            }
+            if (next == null) {
+                currentIdIndex++;
+                if (currentIdIndex >= ids.length) {
+                    currentIdIndex = 0;
+                }
+                if (currentIdIndex == startIdx) {
+                    needsForward = true;
+                    return;
+                }
+            } else {
+                setCurrent(next);
+                break;
+            }
+        }
+    }
+
+    private Node current() {
+        return current[currentIdIndex];
+    }
+
+    private void setCurrent(Node n) {
+        current[currentIdIndex] = n;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return findNext() != null;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T next() {
+        Node result = findNext();
+        if (result == null) {
+            throw new NoSuchElementException();
+        }
+        needsForward = true;
+        return (T) result;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.java
new file mode 100644
index 0000000..d47b906
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java
new file mode 100644
index 0000000..4bfda31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph;
+
+/**
+ * This error represents a failed verification of a node . It must only be used for conditions that
+ * should never occur during normal operation.
+ */
+public class VerificationError extends GraalGraphError {
+
+    private static final long serialVersionUID = 8459607567446819822L;
+
+    /**
+     * This constructor creates a {@link VerificationError} with a message assembled via
+     * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
+     * always generate the same output.
+     *
+     * @param msg the message that will be associated with the error, in String.format syntax
+     * @param args parameters to String.format - parameters that implement {@link Iterable} will be
+     *            expanded into a [x, x, ...] representation.
+     */
+    public VerificationError(String msg, Object... args) {
+        super(msg, args);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/FilteredNodeIterable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/FilteredNodeIterable.java
new file mode 100644
index 0000000..70f5960
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/FilteredNodeIterable.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.graph.Node;
+
+public class FilteredNodeIterable<T extends Node> implements NodeIterable<T> {
+
+    protected final NodeIterable<T> nodeIterable;
+    protected NodePredicate predicate = NodePredicates.alwaysTrue();
+
+    public FilteredNodeIterable(NodeIterable<T> nodeIterable) {
+        this.nodeIterable = nodeIterable;
+    }
+
+    public FilteredNodeIterable<T> and(NodePredicate nodePredicate) {
+        this.predicate = this.predicate.and(nodePredicate);
+        return this;
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return new PredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <F extends T> FilteredNodeIterable<F> filter(Class<F> clazz) {
+        return (FilteredNodeIterable<F>) this.and(NodePredicates.isA(clazz));
+    }
+
+    @Override
+    public FilteredNodeIterable<T> filter(NodePredicate p) {
+        return this.and(p);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterable.java
new file mode 100644
index 0000000..3041eb2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterable.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.graalvm.compiler.graph.Node;
+
+public interface NodeIterable<T extends Node> extends Iterable<T> {
+
+    @SuppressWarnings("unchecked")
+    default <F extends T> NodeIterable<F> filter(Class<F> clazz) {
+        return (NodeIterable<F>) new FilteredNodeIterable<>(this).and(NodePredicates.isA(clazz));
+    }
+
+    default FilteredNodeIterable<T> filter(NodePredicate predicate) {
+        return new FilteredNodeIterable<>(this).and(predicate);
+    }
+
+    default List<T> snapshot() {
+        ArrayList<T> list = new ArrayList<>();
+        snapshotTo(list);
+        return list;
+    }
+
+    default void snapshotTo(Collection<? super T> to) {
+        for (T n : this) {
+            to.add(n);
+        }
+    }
+
+    default T first() {
+        Iterator<T> iterator = iterator();
+        if (iterator.hasNext()) {
+            return iterator.next();
+        }
+        return null;
+    }
+
+    default int count() {
+        int count = 0;
+        Iterator<T> iterator = iterator();
+        while (iterator.hasNext()) {
+            iterator.next();
+            count++;
+        }
+        return count;
+    }
+
+    default boolean isEmpty() {
+        return !iterator().hasNext();
+    }
+
+    default boolean isNotEmpty() {
+        return iterator().hasNext();
+    }
+
+    default boolean contains(T node) {
+        for (T next : this) {
+            if (next == node) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterator.java
new file mode 100644
index 0000000..ef4ba70
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodeIterator.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.graalvm.compiler.graph.Node;
+
+public abstract class NodeIterator<T extends Node> implements Iterator<T> {
+
+    protected T current;
+
+    protected abstract void forward();
+
+    @Override
+    public boolean hasNext() {
+        forward();
+        return current != null;
+    }
+
+    @Override
+    public T next() {
+        forward();
+        T ret = current;
+        if (current == null) {
+            throw new NoSuchElementException();
+        }
+        current = null;
+        return ret;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java
new file mode 100644
index 0000000..84ace70
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodePredicates.AndPredicate;
+
+public interface NodePredicate {
+
+    boolean apply(Node n);
+
+    default NodePredicate and(NodePredicate np) {
+        return new AndPredicate(this, np);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java
new file mode 100644
index 0000000..f52306d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import org.graalvm.compiler.graph.Node;
+
+public abstract class NodePredicates {
+
+    private static final TautologyPredicate TAUTOLOGY = new TautologyPredicate();
+    private static final ContradictionPredicate CONTRADICTION = new ContradictionPredicate();
+    private static final IsNullPredicate IS_NULL = new IsNullPredicate();
+
+    public static NodePredicate alwaysTrue() {
+        return TAUTOLOGY;
+    }
+
+    public static NodePredicate alwaysFalse() {
+        return CONTRADICTION;
+    }
+
+    public static NodePredicate isNull() {
+        return IS_NULL;
+    }
+
+    public static NegativeTypePredicate isNotA(Class<? extends Node> clazz) {
+        return new NegativeTypePredicate(clazz);
+    }
+
+    public static PositiveTypePredicate isA(Class<? extends Node> clazz) {
+        return new PositiveTypePredicate(clazz);
+    }
+
+    static final class TautologyPredicate implements NodePredicate {
+
+        @Override
+        public boolean apply(Node n) {
+            return true;
+        }
+
+        @Override
+        public NodePredicate and(NodePredicate np) {
+            return np;
+        }
+    }
+
+    static final class ContradictionPredicate implements NodePredicate {
+
+        @Override
+        public boolean apply(Node n) {
+            return false;
+        }
+
+        @Override
+        public NodePredicate and(NodePredicate np) {
+            return this;
+        }
+    }
+
+    static final class AndPredicate implements NodePredicate {
+
+        private final NodePredicate a;
+        private final NodePredicate b;
+
+        AndPredicate(NodePredicate a, NodePredicate b) {
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public boolean apply(Node n) {
+            return a.apply(n) && b.apply(n);
+        }
+    }
+
+    static final class NotPredicate implements NodePredicate {
+
+        private final NodePredicate a;
+
+        NotPredicate(NodePredicate n) {
+            this.a = n;
+        }
+
+        @Override
+        public boolean apply(Node n) {
+            return !a.apply(n);
+        }
+
+        public NodePredicate negate() {
+            return a;
+        }
+    }
+
+    static final class IsNullPredicate implements NodePredicate {
+
+        @Override
+        public boolean apply(Node n) {
+            return n == null;
+        }
+    }
+
+    public static final class PositiveTypePredicate implements NodePredicate {
+
+        private final Class<?> type;
+        private PositiveTypePredicate or;
+
+        PositiveTypePredicate(Class<?> type) {
+            this.type = type;
+        }
+
+        public PositiveTypePredicate(NegativeTypePredicate a) {
+            type = a.type;
+            if (a.nor != null) {
+                or = new PositiveTypePredicate(a.nor);
+            }
+        }
+
+        @Override
+        public boolean apply(Node n) {
+            return type.isInstance(n) || (or != null && or.apply(n));
+        }
+
+        public PositiveTypePredicate or(Class<? extends Node> clazz) {
+            if (or == null) {
+                or = new PositiveTypePredicate(clazz);
+            } else {
+                or.or(clazz);
+            }
+            return this;
+        }
+
+        public NodePredicate negate() {
+            return new NegativeTypePredicate(this);
+        }
+    }
+
+    public static final class NegativeTypePredicate implements NodePredicate {
+
+        private final Class<?> type;
+        private NegativeTypePredicate nor;
+
+        NegativeTypePredicate(Class<?> type) {
+            this.type = type;
+        }
+
+        public NegativeTypePredicate(PositiveTypePredicate a) {
+            type = a.type;
+            if (a.or != null) {
+                nor = new NegativeTypePredicate(a.or);
+            }
+        }
+
+        @Override
+        public boolean apply(Node n) {
+            return !type.isInstance(n) && (nor == null || nor.apply(n));
+        }
+
+        public NegativeTypePredicate nor(Class<? extends Node> clazz) {
+            if (nor == null) {
+                nor = new NegativeTypePredicate(clazz);
+            } else {
+                nor.nor(clazz);
+            }
+            return this;
+        }
+
+        public NodePredicate negate() {
+            return new PositiveTypePredicate(this);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/PredicatedProxyNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/PredicatedProxyNodeIterator.java
new file mode 100644
index 0000000..bfcee67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/PredicatedProxyNodeIterator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.iterators;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.graph.Node;
+
+public class PredicatedProxyNodeIterator<T extends Node> extends NodeIterator<T> {
+
+    private final Iterator<T> iterator;
+    private final NodePredicate predicate;
+
+    public PredicatedProxyNodeIterator(Iterator<T> iterator, NodePredicate predicate) {
+        this.iterator = iterator;
+        this.predicate = predicate;
+    }
+
+    @Override
+    protected void forward() {
+        while ((current == null || !current.isAlive() || !predicate.apply(current)) && iterator.hasNext()) {
+            current = iterator.next();
+        }
+        if (current != null && (!current.isAlive() || !predicate.apply(current))) {
+            current = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/package-info.java
new file mode 100644
index 0000000..648aea3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/**
+ * This package contains the Node base class and the Graph container class of the Graal IR.
+ */
+package org.graalvm.compiler.graph;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java
new file mode 100644
index 0000000..bf86864
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.spi;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Nodes can implement {@link Canonicalizable} or one of the two sub-interfaces {@link Unary} and
+ * {@link Binary} to provide local optimizations like constant folding and strength reduction.
+ * Implementations should return a replacement that is always semantically correct for the given
+ * inputs, or "this" if they do not see an opportunity for improvement.<br/>
+ * <br/>
+ * <b>Implementations of {@link Canonicalizable#canonical(CanonicalizerTool)} or the equivalent
+ * methods of the two sub-interfaces must not have any side effects.</b><br/>
+ * They are not allowed to change inputs, successors or properties of any node (including the
+ * current one) and they also cannot add new nodes to the graph.<br/>
+ * <br/>
+ * In addition to pre-existing nodes they can return newly created nodes, which will be added to the
+ * graph automatically if (and only if) the effects of the canonicalization are committed.
+ * Non-cyclic graphs (DAGs) of newly created nodes (i.e., one newly created node with an input to
+ * another newly created node) will be handled correctly.
+ */
+public interface Canonicalizable {
+
+    /**
+     * Implementations of this method can provide local optimizations like constant folding and
+     * strength reduction. Implementations should look at the properties and inputs of the current
+     * node and determine if there is a more optimal and always semantically correct replacement.
+     * <br/>
+     * The return value determines the effect that the canonicalization will have:
+     * <ul>
+     * <li>Returning an pre-existing node will replace the current node with the given one.</li>
+     * <li>Returning a newly created node (that was not yet added to the graph) will replace the
+     * current node with the given one, after adding it to the graph. If both the replacement and
+     * the replacee are anchored in control flow (fixed nodes), the replacement will be added to the
+     * control flow. It is invalid to replace a non-fixed node with a newly created fixed node
+     * (because its placement in the control flow cannot be determined without scheduling).</li>
+     * <li>Returning {@code null} will delete the current node and replace it with {@code null} at
+     * all usages. Note that it is not necessary to delete floating nodes that have no more usages
+     * this way - they will be deleted automatically.</li>
+     * </ul>
+     *
+     * @param tool provides access to runtime interfaces like {@link MetaAccessProvider}
+     */
+    Node canonical(CanonicalizerTool tool);
+
+    /**
+     * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly one
+     * input. It has an additional {@link #canonical(CanonicalizerTool, Node)} method that looks at
+     * the given input instead of the current input of the node - which can be used to ask "what if
+     * this input is changed to this node" - questions.
+     *
+     * @param <T> the common supertype of all inputs of this node
+     */
+    public interface Unary<T extends Node> extends Canonicalizable {
+
+        /**
+         * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that
+         * implementations should act as if the current input of the node was the given one, i.e.,
+         * they should never look at the inputs via the this pointer.
+         */
+        Node canonical(CanonicalizerTool tool, T forValue);
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node)} with the value returned from this method
+         * should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getValue();
+
+        @SuppressWarnings("unchecked")
+        @Override
+        default T canonical(CanonicalizerTool tool) {
+            return (T) canonical(tool, getValue());
+        }
+    }
+
+    /**
+     * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly two
+     * inputs. It has an additional {@link #canonical(CanonicalizerTool, Node, Node)} method that
+     * looks at the given inputs instead of the current inputs of the node - which can be used to
+     * ask "what if this input is changed to this node" - questions.
+     *
+     * @param <T> the common supertype of all inputs of this node
+     */
+    public interface Binary<T extends Node> extends Canonicalizable {
+
+        /**
+         * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that
+         * implementations should act as if the current input of the node was the given one, i.e.,
+         * they should never look at the inputs via the this pointer.
+         */
+        Node canonical(CanonicalizerTool tool, T forX, T forY);
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this
+         * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getX();
+
+        /**
+         * Gets the current value of the input, so that calling
+         * {@link #canonical(CanonicalizerTool, Node, Node)} with the value returned from this
+         * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}.
+         */
+        T getY();
+
+        @SuppressWarnings("unchecked")
+        @Override
+        default T canonical(CanonicalizerTool tool) {
+            return (T) canonical(tool, getX(), getY());
+        }
+    }
+
+    /**
+     * This sub-interface of {@link Canonicalizable.Binary} is for nodes with two inputs where the
+     * operation is commutative. It is used to improve GVN by trying to merge nodes with the same
+     * inputs in different order.
+     */
+    public interface BinaryCommutative<T extends Node> extends Binary<T> {
+
+        /**
+         * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order
+         * the inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on
+         * the node if it's currently in a graph. It's assumed that if there was a constant on the
+         * left it's been moved to the right by other code and that ordering is left alone.
+         *
+         * @return the original node or another node with the same input ordering
+         */
+        Node maybeCommuteInputs();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java
new file mode 100644
index 0000000..e7fc59fe6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.spi;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.graph.Node;
+
+public interface CanonicalizerTool {
+
+    Assumptions getAssumptions();
+
+    MetaAccessProvider getMetaAccess();
+
+    ConstantReflectionProvider getConstantReflection();
+
+    ConstantFieldProvider getConstantFieldProvider();
+
+    boolean canonicalizeReads();
+
+    /**
+     * If this method returns false, not all {@link Node#usages() usages of a node} are yet
+     * available. So a node must not be canonicalized base on, e.g., information returned from
+     * {@link Node#hasNoUsages()}.
+     */
+    boolean allUsagesAvailable();
+
+    /**
+     * Indicates whether the target platform supports comparison of integers of a particular bit
+     * width. This check is used by canonicalizations that might introduce subword compares.
+     */
+    boolean supportSubwordCompare(int bits);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Simplifiable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Simplifiable.java
new file mode 100644
index 0000000..ccea8c3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Simplifiable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.spi;
+
+/**
+ * This interface allows nodes to perform more complicated simplifications, in contrast to
+ * {@link Canonicalizable}, which supports only replacing the current node.
+ *
+ * Implementors of this interface need to be aware that they need to call
+ * {@link SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node)} for each node that might be
+ * influenced (in terms of simplification and canonicalization) by the actions performed in
+ * simplify.
+ */
+public interface Simplifiable {
+
+    void simplify(SimplifierTool tool);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/SimplifierTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/SimplifierTool.java
new file mode 100644
index 0000000..abdc6ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/SimplifierTool.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.spi;
+
+import org.graalvm.compiler.graph.Node;
+
+/**
+ * @see Simplifiable
+ */
+public interface SimplifierTool extends CanonicalizerTool {
+
+    void deleteBranch(Node branch);
+
+    /**
+     * Adds a node to the worklist independent of whether it has already been on the worklist.
+     */
+    void addToWorkList(Node node);
+
+    void addToWorkList(Iterable<? extends Node> nodes);
+
+    void removeIfUnused(Node node);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java
new file mode 100644
index 0000000..8d3b056
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
+import static java.lang.reflect.Modifier.isStatic;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.aarch64.AArch64.r10;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import java.util.Set;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.aarch64.AArch64FrameMap;
+import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.asm.DataBuilder;
+import org.graalvm.compiler.lir.asm.FrameContext;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * HotSpot AArch64 specific backend.
+ */
+public class AArch64HotSpotBackend extends HotSpotHostBackend {
+
+    public AArch64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(config, runtime, providers);
+    }
+
+    @Override
+    public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+    }
+
+    @Override
+    public FrameMap newFrameMap(RegisterConfig registerConfig) {
+        return new AArch64FrameMap(getCodeCache(), registerConfig, this);
+    }
+
+    @Override
+    public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
+        return new AArch64HotSpotLIRGenerator(getProviders(), config, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) {
+        return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+        return new AArch64HotSpotNodeLIRBuilder(graph, lirGen, new AArch64NodeMatchRules(lirGen));
+    }
+
+    @Override
+    protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
+        AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            AArch64Address address = masm.makeAddress(sp, -bangOffset, scratch, 8, /* allowOverwrite */false);
+            masm.str(64, zr, address);
+        }
+    }
+
+    private class HotSpotFrameContext implements FrameContext {
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
+        @Override
+        public void enter(CompilationResultBuilder crb) {
+            FrameMap frameMap = crb.frameMap;
+            final int frameSize = frameMap.frameSize();
+            final int totalFrameSize = frameMap.totalFrameSize();
+            assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words";
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            if (!isStub) {
+                emitStackOverflowCheck(crb);
+            }
+            crb.blockComment("[method prologue]");
+
+            if (ZapStackOnMethodEntry.getValue()) {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    int intSize = 4;
+                    AArch64Address address = AArch64Address.createPreIndexedImmediateAddress(scratch, -intSize);
+                    try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                        Register value = sc2.getRegister();
+                        masm.mov(value, 0xC1C1C1C1);
+                        for (int i = 0; i < frameSize; i += intSize) {
+                            masm.str(32, value, address);
+                        }
+                    }
+                    masm.mov(64, sp, scratch);
+                }
+            } else {
+                if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) {
+                    masm.sub(64, sp, sp, totalFrameSize);
+                } else {
+                    try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                        Register scratch2 = sc2.getRegister();
+                        masm.mov(scratch2, totalFrameSize);
+                        masm.sub(64, sp, sp, scratch2);
+                    }
+                }
+            }
+
+            AArch64Address address2 = AArch64Address.createPairUnscaledImmediateAddress(sp, frameSize / 8); // XXX
+            masm.stp(64, fp, lr, address2);
+
+            crb.blockComment("[code body]");
+        }
+
+        @Override
+        public void leave(CompilationResultBuilder crb) {
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            FrameMap frameMap = crb.frameMap;
+            final int frameSize = frameMap.frameSize();
+            final int totalFrameSize = frameMap.totalFrameSize();
+
+            crb.blockComment("[method epilogue]");
+
+            AArch64Address address2 = AArch64Address.createPairUnscaledImmediateAddress(sp, frameSize / 8); // XXX
+            masm.ldp(64, fp, lr, address2);
+
+            if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) {
+                masm.add(64, sp, sp, totalFrameSize);
+            } else {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    masm.mov(scratch, totalFrameSize);
+                    masm.add(64, sp, sp, scratch);
+                }
+            }
+        }
+
+        @Override
+        public boolean hasFrame() {
+            return true;
+        }
+
+    }
+
+    @Override
+    protected Assembler createAssembler(FrameMap frameMap) {
+        return new AArch64MacroAssembler(getTarget());
+    }
+
+    @Override
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen;
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+
+        Stub stub = gen.getStub();
+        Assembler masm = createAssembler(frameMap);
+        HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
+
+        DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
+        CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult);
+        crb.setTotalFrameSize(frameMap.totalFrameSize());
+        crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+        if (deoptimizationRescueSlot != null && stub == null) {
+            crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
+        }
+
+        if (stub != null) {
+            Set<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
+            updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap);
+        }
+        return crb;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+        AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig regConfig = frameMap.getRegisterConfig();
+        Label verifiedStub = new Label();
+
+        emitCodePrefix(crb, installedCodeOwner, masm, regConfig, verifiedStub);
+        emitCodeBody(crb, lir, masm);
+        emitCodeSuffix(crb, masm, frameMap);
+    }
+
+    private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, Label verifiedStub) {
+        HotSpotProviders providers = getProviders();
+        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
+            crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+            CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this);
+            // See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp
+            // equal to scratch(1) careful!
+            Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister;
+            Register receiver = asRegister(cc.getArgument(0));
+            int transferSize = config.useCompressedClassPointers ? 4 : 8;
+            AArch64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize);
+
+            // Are r10 and r11 available scratch registers here? One would hope so.
+            Register klass = r10;
+            if (config.useCompressedClassPointers) {
+                masm.ldr(32, klass, klassAddress);
+                AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding());
+            } else {
+                masm.ldr(64, klass, klassAddress);
+            }
+            masm.cmp(64, inlineCacheKlass, klass);
+            /*
+             * Conditional jumps have a much lower range than unconditional ones, which can be a
+             * problem because the miss handler could be out of range.
+             */
+            masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub);
+            AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER));
+        }
+        masm.align(config.codeEntryAlignment);
+        crb.recordMark(config.MARKID_OSR_ENTRY);
+        masm.bind(verifiedStub);
+        crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+    }
+
+    private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
+        /*
+         * Insert a nop at the start of the prolog so we can patch in a branch if we need to
+         * invalidate the method later.
+         */
+        crb.blockComment("[nop for method invalidation]");
+        masm.nop();
+
+        crb.emit(lir);
+    }
+
+    private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
+        HotSpotProviders providers = getProviders();
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+        if (!frameContext.isStub) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+                ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
+                Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+
+                crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+                linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
+                helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+            }
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+            assert !frameMap.accessesCallerFrame();
+        }
+    }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64HotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
+    @Override
+    public Set<Register> translateToCallerRegisters(Set<Register> calleeRegisters) {
+        return calleeRegisters;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
new file mode 100644
index 0000000..64d47cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.common.InitTimer.timer;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.aarch64.AArch64AddressLowering;
+import org.graalvm.compiler.core.aarch64.AArch64SuitesProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegisters;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.aarch64.AArch64GraphBuilderPlugins;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.InitTimer;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+@ServiceProvider(HotSpotBackendFactory.class)
+public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
+
+    @Override
+    public String getName() {
+        return "core";
+    }
+
+    @Override
+    public Class<? extends Architecture> getArchitecture() {
+        return AArch64.class;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) {
+        assert host == null;
+
+        JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
+        GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
+        HotSpotProviders providers;
+        HotSpotRegistersProvider registers;
+        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache();
+        TargetDescription target = codeCache.getTarget();
+        HotSpotHostForeignCallsProvider foreignCalls;
+        Value[] nativeABICallerSaveRegisters;
+        HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess();
+        HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
+        HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
+        HotSpotLoweringProvider lowerer;
+        HotSpotSnippetReflectionProvider snippetReflection;
+        HotSpotReplacementsImpl replacements;
+        HotSpotSuitesProvider suites;
+        HotSpotWordTypes wordTypes;
+        Plugins plugins;
+        NodeCostProvider nodeCostProvider;
+        BytecodeProvider bytecodeProvider;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = createRegisters();
+            }
+            try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) {
+                nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
+            }
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
+            }
+            try (InitTimer rt = timer("create NodeCost provider")) {
+                nodeCostProvider = createNodeCostProvider();
+            }
+            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+
+            try (InitTimer rt = timer("create SnippetReflection provider")) {
+                snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
+            }
+            try (InitTimer rt = timer("create Bytecode provider")) {
+                bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = createReplacements(p, snippetReflection, bytecodeProvider);
+            }
+            try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
+                plugins = createGraphBuilderPlugins(config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                replacements.setGraphBuilderPlugins(plugins);
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = createSuites(config, graalRuntime, compilerConfiguration, plugins);
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+                            snippetReflection, wordTypes,
+                            plugins);
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return createBackend(config, graalRuntime, providers);
+        }
+    }
+
+    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls,
+                    HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes,
+                    HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        AArch64GraphBuilderPlugins.register(plugins, foreignCalls, replacements.getReplacementBytecodeProvider());
+        return plugins;
+    }
+
+    protected AArch64HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        return new AArch64HotSpotBackend(config, runtime, providers);
+    }
+
+    protected HotSpotRegistersProvider createRegisters() {
+        return new HotSpotRegisters(AArch64HotSpotRegisterConfig.threadRegister, AArch64HotSpotRegisterConfig.heapBaseRegister, sp);
+    }
+
+    protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
+        return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget());
+    }
+
+    protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
+        return new AArch64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
+    }
+
+    protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        return new HotSpotSuitesProvider(new AArch64SuitesProvider(compilerConfiguration, plugins), config, runtime, new AArch64AddressLowering());
+    }
+
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
+    }
+
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
+                    HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    protected HotSpotNodeCostProvider createNodeCostProvider() {
+        return new AArchHotSpotNodeCostProvider();
+    }
+
+    protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) {
+        AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig;
+        RegisterArray callerSavedRegisters = conf.getCallerSaveRegisters();
+        int size = callerSavedRegisters.size();
+        Value[] nativeABICallerSaveRegisters = new Value[size];
+        for (int i = 0; i < size; i++) {
+            nativeABICallerSaveRegisters[i] = callerSavedRegisters.get(i).asValue();
+        }
+        return nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public String toString() {
+        return "AArch64";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java
new file mode 100644
index 0000000..ee841e6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+public class AArch64HotSpotCRuntimeCallEpilogueOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallEpilogueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaFpOffset;
+    private final Register thread;
+
+    public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // Reset last Java frame:
+        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
+        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java
new file mode 100644
index 0000000..c28be7f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+@Opcode("CRUNTIME_CALL_PROLOGUE")
+public class AArch64HotSpotCRuntimeCallPrologueOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallPrologueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadLastJavaFpOffset;
+    private final Register thread;
+    @Temp({REG}) protected AllocatableValue scratch;
+    private final Label label;
+
+    public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, Register thread, AllocatableValue scratch, Label label) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.thread = thread;
+        this.scratch = scratch;
+        this.label = label;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // Save last Java frame.
+        // We cannot save the SP directly so use a temporary register.
+        Register scratchRegister = asRegister(scratch);
+        masm.movx(scratchRegister, sp);
+        masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
+
+        // Get the current PC. Use a label to patch the return address.
+        masm.adr(scratchRegister, label);
+        masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaPcOffset, 8));
+
+        masm.str(64, fp, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java
new file mode 100644
index 0000000..025b16d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+public class AArch64HotSpotDeoptimizeCallerOp extends AArch64HotSpotEpilogueOp {
+    public static final LIRInstructionClass<AArch64HotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeCallerOp.class);
+
+    public AArch64HotSpotDeoptimizeCallerOp(GraalHotSpotVMConfig config) {
+        super(TYPE, config);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+        AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java
new file mode 100644
index 0000000..f9d43ce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.aarch64.AArch64BlockEndOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+@Opcode("DEOPT")
+public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements BlockEndOp {
+    public static final LIRInstructionClass<AArch64HotSpotDeoptimizeOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeOp.class);
+
+    @State private LIRFrameState info;
+
+    public AArch64HotSpotDeoptimizeOp(LIRFrameState info) {
+        super(TYPE);
+        this.info = info;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java
new file mode 100644
index 0000000..c1593d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64Call.DirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class AArch64HotSpotDirectStaticCallOp extends DirectCallOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDirectStaticCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    AArch64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isDirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        // For the first invocation this is set to a bitpattern that is guaranteed to never be a
+        // valid object which causes the called function to call a handler that installs the
+        // correct inline cache value here.
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
+        masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
+        super.emitCode(crb, masm);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java
new file mode 100644
index 0000000..6d13e61
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64Call.DirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class AArch64HotSpotDirectVirtualCallOp extends DirectCallOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDirectVirtualCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    AArch64HotSpotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isIndirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        // For the first invocation this is set to a bitpattern that is guaranteed to never be a
+        // valid object which causes the called function to call a handler that installs the
+        // correct inline cache value here.
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
+        masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
+        super.emitCode(crb, masm);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java
new file mode 100644
index 0000000..79be3d6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64BlockEndOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Superclass for operations that leave a method's frame.
+ */
+abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp {
+
+    private final GraalHotSpotVMConfig config;
+
+    protected AArch64HotSpotEpilogueOp(LIRInstructionClass<? extends AArch64HotSpotEpilogueOp> c, GraalHotSpotVMConfig config) {
+        super(c);
+        this.config = config;
+    }
+
+    protected void leaveFrame(CompilationResultBuilder crb, AArch64MacroAssembler masm, boolean emitSafepoint) {
+        assert crb.frameContext != null : "We never elide frames in aarch64";
+        crb.frameContext.leave(crb);
+        if (emitSafepoint) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                AArch64HotSpotSafepointOp.emitCode(crb, masm, config, true, scratch, null);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java
new file mode 100644
index 0000000..d7aefd8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
+import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32;
+import static jdk.vm.ci.aarch64.AArch64.r0;
+import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+import static jdk.vm.ci.meta.Value.ILLEGAL;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider {
+
+    private final Value[] nativeABICallerSaveRegisters;
+
+    public AArch64HotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
+        super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes);
+        this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers) {
+        GraalHotSpotVMConfig config = runtime.getVMConfig();
+        TargetDescription target = providers.getCodeCache().getTarget();
+        PlatformKind word = target.arch.getWordKind();
+
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        RegisterValue exception = r0.asValue(LIRKind.reference(word));
+        RegisterValue exceptionPc = r3.asValue(LIRKind.value(word));
+        CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
+        register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any()));
+
+        if (PreferGraalStubs.getValue()) {
+            throw GraalError.unimplemented("PreferGraalStubs");
+        }
+
+        // These stubs do callee saving
+        if (config.useCRC32Intrinsics) {
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, any());
+        }
+
+        super.initialize(providers);
+    }
+
+    @Override
+    public Value[] getNativeABICallerSaveRegisters() {
+        return nativeABICallerSaveRegisters;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java
new file mode 100644
index 0000000..52fbb28
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+public class AArch64HotSpotJumpToExceptionHandlerInCallerOp extends AArch64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(AArch64HotSpotJumpToExceptionHandlerInCallerOp.class);
+
+    @Use(REG) private AllocatableValue handlerInCallerPc;
+    @Use(REG) private AllocatableValue exception;
+    @Use(REG) private AllocatableValue exceptionPc;
+    private final Register thread;
+    private final int isMethodHandleReturnOffset;
+
+    public AArch64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset,
+                    Register thread, GraalHotSpotVMConfig config) {
+        super(TYPE, config);
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+        this.isMethodHandleReturnOffset = isMethodHandleReturnOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+
+        // Restore sp from fp if the exception PC is a method handle call site.
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            AArch64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, /* allowOverwrite */false);
+            masm.ldr(32, scratch, address);
+            Label noRestore = new Label();
+            masm.cbz(32, scratch, noRestore);
+            masm.mov(64, sp, fp);
+            masm.bind(noRestore);
+        }
+        masm.jmp(asRegister(handlerInCallerPc));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java
new file mode 100644
index 0000000..d8b03b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+
+import java.util.function.Function;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
+import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator;
+import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
+import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * LIR generator specialized for AArch64 HotSpot.
+ */
+public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator {
+
+    final GraalHotSpotVMConfig config;
+    private HotSpotDebugInfoBuilder debugInfoBuilder;
+
+    protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
+        this(new AArch64HotSpotLIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
+    }
+
+    protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
+                    LIRGenerationResult lirGenRes) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
+        this.config = config;
+    }
+
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    @Override
+    public boolean needOnlyOopMaps() {
+        // Stubs only need oop maps
+        return getResult().getStub() != null;
+    }
+
+    @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo;
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        currentRuntimeCallInfo = info;
+        if (AArch64Call.isNearCall(linkage)) {
+            append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label));
+        } else {
+            append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label));
+        }
+    }
+
+    @Override
+    public void emitTailcall(Value[] args, Value address) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public SaveRegistersOp emitSaveAllRegisters() {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public VirtualStackSlot getLockSlot(int lockDepth) {
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
+        return debugInfoBuilder.lockStack();
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        Value localX = x;
+        Value localY = y;
+        if (localX instanceof HotSpotObjectConstant) {
+            localX = load(localX);
+        }
+        if (localY instanceof HotSpotObjectConstant) {
+            localY = load(localY);
+        }
+        super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
+    }
+
+    @Override
+    protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) {
+        Value localA = a;
+        Value localB = b;
+        if (isConstantValue(a)) {
+            Constant c = asConstant(a);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
+            } else if (c instanceof HotSpotObjectConstant) {
+                localA = load(localA);
+            }
+        }
+        if (isConstantValue(b)) {
+            Constant c = asConstant(b);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
+            } else if (c instanceof HotSpotObjectConstant) {
+                localB = load(localB);
+            }
+        }
+        return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue);
+    }
+
+    @Override
+    public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(AArch64Kind.DWORD));
+            append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base));
+            }
+            append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    @Override
+    public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == AArch64Kind.DWORD;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD));
+            append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base));
+            }
+            append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    @Override
+    public void emitPrefetchAllocate(Value address) {
+        append(new AArch64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr));
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        super.beforeRegisterAllocation();
+        boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
+        if (hasDebugInfo) {
+            getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
+        }
+
+        getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
+    }
+
+    private Label label;
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
+        HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
+        Variable result;
+        LIRFrameState debugInfo = null;
+        if (hotspotLinkage.needsDebugInfo()) {
+            debugInfo = state;
+            assert debugInfo != null || getStub() != null;
+        }
+
+        if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
+            HotSpotRegistersProvider registers = getProviders().getRegisters();
+            Register thread = registers.getThreadRegister();
+            Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
+
+            // We need a label for the return address.
+            label = new Label();
+
+            append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label));
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+            append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+
+            // Clear it out so it's not being reused later.
+            label = null;
+        } else {
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
+        Value nullValue = emitConstant(LIRKind.reference(AArch64Kind.QWORD), JavaConstant.NULL_POINTER);
+        moveDeoptValuesToThread(actionAndReason, nullValue);
+        append(new AArch64HotSpotDeoptimizeCallerOp(config));
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
+        moveDeoptValuesToThread(actionAndReason, failedSpeculation);
+        append(new AArch64HotSpotDeoptimizeOp(state));
+    }
+
+    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
+        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
+        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
+    }
+
+    private void moveValueToThread(Value value, int offset) {
+        LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
+        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
+        final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes();
+        final int scaledDisplacement = offset >> NumUtil.log2Ceil(transferSize);
+        AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, scaledDisplacement, true, AddressingMode.IMMEDIATE_SCALED);
+        append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null));
+    }
+
+    @Override
+    public void emitUnwind(Value exception) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
+        emitMove(exceptionParameter, exception);
+        append(new AArch64HotSpotUnwindOp(config, exceptionParameter));
+    }
+
+    @Override
+    public void emitReturn(JavaKind kind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(kind, input.getValueKind());
+            emitMove(operand, input);
+        }
+        append(new AArch64HotSpotReturnOp(operand, getStub() != null, config));
+    }
+
+    /**
+     * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
+     * being generated.
+     */
+    public Stub getStub() {
+        return getResult().getStub();
+    }
+
+    @Override
+    public HotSpotLIRGenerationResult getResult() {
+        return ((HotSpotLIRGenerationResult) super.getResult());
+    }
+
+    @Override
+    protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
+                    Function<Condition, ConditionFlag> converter) {
+        return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
+    }
+
+    public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
+        this.debugInfoBuilder = debugInfoBuilder;
+    }
+
+    @Override
+    public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
+        throw GraalError.unimplemented();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java
new file mode 100644
index 0000000..5f159de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+
+public class AArch64HotSpotLIRKindTool extends AArch64LIRKindTool implements HotSpotLIRKindTool {
+
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(AArch64Kind.DWORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(AArch64Kind.DWORD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java
new file mode 100644
index 0000000..8aa3a04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.aarch64;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.RemNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.aarch64.AArch64FloatArithmeticSnippets;
+import org.graalvm.compiler.replacements.aarch64.AArch64IntegerArithmeticSnippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class AArch64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
+
+    private AArch64IntegerArithmeticSnippets integerArithmeticSnippets;
+    private AArch64FloatArithmeticSnippets floatArithmeticSnippets;
+
+    public AArch64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) {
+        integerArithmeticSnippets = new AArch64IntegerArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
+        floatArithmeticSnippets = new AArch64FloatArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
+        super.initialize(providers, config);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof FixedBinaryNode) {
+            integerArithmeticSnippets.lower((FixedBinaryNode) n, tool);
+        } else if (n instanceof RemNode) {
+            floatArithmeticSnippets.lower((RemNode) n, tool);
+        } else if (n instanceof FloatConvertNode) {
+            // AMD64 has custom lowerings for ConvertNodes, HotSpotLoweringProvider does not expect
+            // to see a ConvertNode and throws an error, just do nothing here.
+        } else {
+            super.lower(n, tool);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java
new file mode 100644
index 0000000..89dc03d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+public class AArch64HotSpotMove {
+
+    public static class LoadHotSpotObjectConstantInline extends AArch64LIRInstruction implements LoadConstantOp {
+        public static final LIRInstructionClass<LoadHotSpotObjectConstantInline> TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class);
+
+        private HotSpotConstant constant;
+        @Def({REG, STACK}) AllocatableValue result;
+
+        public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) {
+            super(TYPE);
+            this.constant = constant;
+            this.result = result;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            crb.recordInlineDataInCode(constant);
+            if (constant.isCompressed()) {
+                // masm.forceMov(asRegister(result), 0);
+                throw GraalError.unimplemented();
+            } else {
+                masm.movNativeAddress(asRegister(result), 0);
+            }
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        @Override
+        public Constant getConstant() {
+            return constant;
+        }
+    }
+
+    /**
+     * Compresses a 8-byte pointer as a 4-byte int.
+     */
+    public static class CompressPointer extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register resultRegister = asRegister(result);
+            Register ptr = asRegister(input);
+            Register base = asRegister(baseRegister);
+            // result = (ptr - base) >> shift
+            if (encoding.base == 0) {
+                if (encoding.shift == 0) {
+                    masm.movx(resultRegister, ptr);
+                } else {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.lshr(64, resultRegister, ptr, encoding.shift);
+                }
+            } else if (nonNull) {
+                masm.sub(64, resultRegister, ptr, base);
+                if (encoding.shift != 0) {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.shl(64, resultRegister, resultRegister, encoding.shift);
+                }
+            } else {
+                // if ptr is null it still has to be null after compression
+                masm.cmp(64, ptr, 0);
+                masm.cmov(64, resultRegister, ptr, base, AArch64Assembler.ConditionFlag.NE);
+                masm.sub(64, resultRegister, resultRegister, base);
+                if (encoding.shift != 0) {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.lshr(64, resultRegister, resultRegister, encoding.shift);
+                }
+            }
+        }
+    }
+
+    /**
+     * Decompresses a 4-byte offset into an actual pointer.
+     */
+    public static class UncompressPointer extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register ptr = asRegister(input);
+            Register resultRegister = asRegister(result);
+            Register base = asRegister(baseRegister);
+            // result = base + (ptr << shift)
+            if (nonNull) {
+                assert encoding.shift == encoding.alignment;
+                masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.ASR, encoding.shift);
+            } else {
+                // if ptr is null it has to be null after decompression
+                // masm.cmp(64, );
+                throw GraalError.unimplemented();
+            }
+
+        }
+    }
+
+    //
+    // private static void decompressPointer(CompilationResultBuilder crb, ARMv8MacroAssembler masm,
+    // Register result,
+    // Register ptr, long base, int shift, int alignment) {
+    // assert base != 0 || shift == 0 || alignment == shift;
+    // // result = heapBase + ptr << alignment
+    // Register heapBase = ARMv8.heapBaseRegister;
+    // // if result == 0, we make sure that it will still be 0 at the end, so that it traps when
+    // // loading storing a value.
+    // masm.cmp(32, ptr, 0);
+    // masm.add(64, result, heapBase, ptr, ARMv8Assembler.ExtendType.UXTX, alignment);
+    // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE);
+    // }
+
+    public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, Register klassBase, CompressEncoding encoding) {
+        // result = klassBase + ptr << shift
+        if (encoding.shift != 0 || encoding.base != 0) {
+            // (shift != 0 -> shift == alignment)
+            assert (encoding.shift == 0 || encoding.shift == encoding.alignment) : "Decode algorithm is wrong: " + encoding;
+            masm.add(64, result, klassBase, ptr, AArch64Assembler.ExtendType.UXTX, encoding.shift);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java
new file mode 100644
index 0000000..641cf5d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL;
+import static jdk.vm.ci.meta.JavaConstant.INT_0;
+import static jdk.vm.ci.meta.JavaConstant.LONG_0;
+
+import org.graalvm.compiler.core.aarch64.AArch64MoveFactory;
+import org.graalvm.compiler.lir.LIRInstruction;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class AArch64HotSpotMoveFactory extends AArch64MoveFactory {
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return false;
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        Constant usedSource;
+        if (COMPRESSED_NULL.equals(src)) {
+            usedSource = INT_0;
+        } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) {
+            usedSource = LONG_0;
+        } else {
+            usedSource = src;
+        }
+        if (usedSource instanceof HotSpotConstant) {
+            HotSpotConstant constant = (HotSpotConstant) usedSource;
+            if (constant.isCompressed()) {
+                return new AArch64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst);
+            } else {
+                // XXX Do we need the constant table?
+                // return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst,
+                // constantTableBaseProvider.getConstantTableBase());
+                return new AArch64HotSpotMove.LoadHotSpotObjectConstantInline(constant, dst);
+            }
+        } else {
+            return super.createLoad(dst, usedSource);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java
new file mode 100644
index 0000000..1352a91
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.metaspaceMethodRegister;
+
+import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
+import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.gen.DebugInfoBuilder;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.aarch64.AArch64BreakpointOp;
+import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * LIR generator specialized for AArch64 HotSpot.
+ */
+public class AArch64HotSpotNodeLIRBuilder extends AArch64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
+
+    public AArch64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AArch64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
+        assert gen instanceof AArch64HotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((AArch64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()));
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AArch64Kind.QWORD));
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen);
+    }
+
+    private AArch64HotSpotLIRGenerator getGen() {
+        return (AArch64HotSpotLIRGenerator) gen;
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        CallingConvention incomingArguments = gen.getResult().getCallingConvention();
+        Value[] params = new Value[incomingArguments.getArgumentCount() + 2];
+        for (int i = 0; i < incomingArguments.getArgumentCount(); i++) {
+            params[i] = incomingArguments.getArgument(i);
+            if (isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) {
+                    gen.getResult().getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+        params[params.length - 2] = fp.asValue(LIRKind.value(AArch64Kind.QWORD));
+        params[params.length - 1] = lr.asValue(LIRKind.value(AArch64Kind.QWORD));
+
+        gen.emitIncomingValues(params);
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue.getValueKind() + " != " + param.stamp();
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = state(i);
+        Variable scratch = gen.newVariable(LIRKind.value(getGen().target().arch.getWordKind()));
+        append(new AArch64HotSpotSafepointOp(info, getGen().config, scratch));
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind.isIndirect()) {
+            append(new AArch64HotSpotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        } else {
+            assert invokeKind.isDirect();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+            assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
+            append(new AArch64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod());
+        Value targetAddressSrc = operand(callTarget.computedAddress());
+        AllocatableValue metaspaceMethodDst = metaspaceMethodRegister.asValue(metaspaceMethodSrc.getValueKind());
+        AllocatableValue targetAddressDst = inlineCacheRegister.asValue(targetAddressSrc.getValueKind());
+        gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc);
+        gen.emitMove(targetAddressDst, targetAddressSrc);
+        append(new AArch64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config));
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new AArch64HotSpotPatchReturnAddressOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        AArch64HotSpotJumpToExceptionHandlerInCallerOp op = new AArch64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed,
+                        getGen().config.threadIsMethodHandleReturnOffset, thread, getGen().config);
+        append(op);
+    }
+
+    @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitFullInfopointNode(i);
+        }
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        AllocatableValue address = gen.asAllocatable(operand(x.getAddress()));
+        AllocatableValue cmpValue = gen.asAllocatable(operand(x.expectedValue()));
+        AllocatableValue newValue = gen.asAllocatable(operand(x.newValue()));
+        ValueKind<?> kind = cmpValue.getValueKind();
+        assert kind.equals(newValue.getValueKind());
+
+        Variable result = gen.newVariable(newValue.getValueKind());
+        Variable scratch = gen.newVariable(LIRKind.value(AArch64Kind.DWORD));
+        append(new CompareAndSwapOp(result, cmpValue, newValue, address, scratch));
+        setResult(x, result);
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
+                        node.arguments());
+        append(new AArch64BreakpointOp(parameters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotPatchReturnAddressOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotPatchReturnAddressOp.java
new file mode 100644
index 0000000..5848b3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotPatchReturnAddressOp.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AArch64ExceptionCode;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class AArch64HotSpotPatchReturnAddressOp extends AArch64LIRInstruction {
+
+    public static final LIRInstructionClass<AArch64HotSpotPatchReturnAddressOp> TYPE = LIRInstructionClass.create(AArch64HotSpotPatchReturnAddressOp.class);
+
+    @Use(REG) AllocatableValue address;
+
+    AArch64HotSpotPatchReturnAddressOp(AllocatableValue address) {
+        super(TYPE);
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        final int frameSize = crb.frameMap.frameSize();
+        // XXX where is lr exactly?
+        AArch64Address lrAddress = AArch64Address.createUnscaledImmediateAddress(sp, frameSize);
+        masm.brk(AArch64ExceptionCode.BREAKPOINT); // XXX
+        masm.str(64, asRegister(address), lrAddress);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java
new file mode 100644
index 0000000..ac9b096
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.r0;
+import static jdk.vm.ci.aarch64.AArch64.r1;
+import static jdk.vm.ci.aarch64.AArch64.r10;
+import static jdk.vm.ci.aarch64.AArch64.r11;
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.aarch64.AArch64.r13;
+import static jdk.vm.ci.aarch64.AArch64.r14;
+import static jdk.vm.ci.aarch64.AArch64.r15;
+import static jdk.vm.ci.aarch64.AArch64.r16;
+import static jdk.vm.ci.aarch64.AArch64.r17;
+import static jdk.vm.ci.aarch64.AArch64.r18;
+import static jdk.vm.ci.aarch64.AArch64.r19;
+import static jdk.vm.ci.aarch64.AArch64.r2;
+import static jdk.vm.ci.aarch64.AArch64.r20;
+import static jdk.vm.ci.aarch64.AArch64.r21;
+import static jdk.vm.ci.aarch64.AArch64.r22;
+import static jdk.vm.ci.aarch64.AArch64.r23;
+import static jdk.vm.ci.aarch64.AArch64.r24;
+import static jdk.vm.ci.aarch64.AArch64.r25;
+import static jdk.vm.ci.aarch64.AArch64.r26;
+import static jdk.vm.ci.aarch64.AArch64.r27;
+import static jdk.vm.ci.aarch64.AArch64.r28;
+import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.aarch64.AArch64.r4;
+import static jdk.vm.ci.aarch64.AArch64.r5;
+import static jdk.vm.ci.aarch64.AArch64.r6;
+import static jdk.vm.ci.aarch64.AArch64.r7;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.v0;
+import static jdk.vm.ci.aarch64.AArch64.v1;
+import static jdk.vm.ci.aarch64.AArch64.v10;
+import static jdk.vm.ci.aarch64.AArch64.v11;
+import static jdk.vm.ci.aarch64.AArch64.v12;
+import static jdk.vm.ci.aarch64.AArch64.v13;
+import static jdk.vm.ci.aarch64.AArch64.v14;
+import static jdk.vm.ci.aarch64.AArch64.v15;
+import static jdk.vm.ci.aarch64.AArch64.v16;
+import static jdk.vm.ci.aarch64.AArch64.v17;
+import static jdk.vm.ci.aarch64.AArch64.v18;
+import static jdk.vm.ci.aarch64.AArch64.v19;
+import static jdk.vm.ci.aarch64.AArch64.v2;
+import static jdk.vm.ci.aarch64.AArch64.v20;
+import static jdk.vm.ci.aarch64.AArch64.v21;
+import static jdk.vm.ci.aarch64.AArch64.v22;
+import static jdk.vm.ci.aarch64.AArch64.v23;
+import static jdk.vm.ci.aarch64.AArch64.v24;
+import static jdk.vm.ci.aarch64.AArch64.v25;
+import static jdk.vm.ci.aarch64.AArch64.v26;
+import static jdk.vm.ci.aarch64.AArch64.v27;
+import static jdk.vm.ci.aarch64.AArch64.v28;
+import static jdk.vm.ci.aarch64.AArch64.v29;
+import static jdk.vm.ci.aarch64.AArch64.v3;
+import static jdk.vm.ci.aarch64.AArch64.v30;
+import static jdk.vm.ci.aarch64.AArch64.v31;
+import static jdk.vm.ci.aarch64.AArch64.v4;
+import static jdk.vm.ci.aarch64.AArch64.v5;
+import static jdk.vm.ci.aarch64.AArch64.v6;
+import static jdk.vm.ci.aarch64.AArch64.v7;
+import static jdk.vm.ci.aarch64.AArch64.v8;
+import static jdk.vm.ci.aarch64.AArch64.v9;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+
+public class AArch64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig {
+
+    // @formatter:off
+    static final Register[] registerAllocationOrder = {
+        r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
+        r8,  r9,  r10, r11, r12, r13, r14, r15,
+        r16, r17, r18, r19, r20, r21, r22, r23,
+        r24, r25, r26, r27, r28, /* r29, r30, r31 */
+
+        v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,
+        v8,  v9,  v10, v11, v12, v13, v14, v15,
+        v16, v17, v18, v19, v20, v21, v22, v23,
+        v24, v25, v26, v27, v28, v29, v30, v31
+    };
+    // @formatter:on
+
+    public AArch64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) {
+        super(registerConfig);
+    }
+
+    @Override
+    protected RegisterArray initAllocatable(RegisterArray registers) {
+        BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size());
+        for (Register reg : registers) {
+            regMap.set(reg.number);
+        }
+
+        ArrayList<Register> allocatableRegisters = new ArrayList<>(registers.size());
+        for (Register reg : registerAllocationOrder) {
+            if (regMap.get(reg.number)) {
+                allocatableRegisters.add(reg);
+            }
+        }
+
+        return super.initAllocatable(new RegisterArray(allocatableRegisters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java
new file mode 100644
index 0000000..283e3fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Returns from a function.
+ */
+@Opcode("RETURN")
+public final class AArch64HotSpotReturnOp extends AArch64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotReturnOp> TYPE = LIRInstructionClass.create(AArch64HotSpotReturnOp.class);
+
+    @Use({REG, ILLEGAL}) private Value result;
+    private final boolean isStub;
+
+    public AArch64HotSpotReturnOp(Value result, boolean isStub, GraalHotSpotVMConfig config) {
+        super(TYPE, config);
+        assert validReturnValue(result);
+        this.result = result;
+        this.isStub = isStub;
+    }
+
+    private static boolean validReturnValue(Value result) {
+        if (result.equals(Value.ILLEGAL)) {
+            return true;
+        }
+        return asRegister(result).encoding == 0;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        final boolean emitSafepoint = !isStub;
+        leaveFrame(crb, masm, emitSafepoint);
+        masm.ret(lr);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java
new file mode 100644
index 0000000..02b2146
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public class AArch64HotSpotSafepointOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotSafepointOp> TYPE = LIRInstructionClass.create(AArch64HotSpotSafepointOp.class);
+
+    @State protected LIRFrameState state;
+    @Temp protected AllocatableValue scratchValue;
+
+    private final GraalHotSpotVMConfig config;
+
+    public AArch64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, AllocatableValue scratch) {
+        super(TYPE);
+        this.state = state;
+        this.config = config;
+        this.scratchValue = scratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register scratch = asRegister(scratchValue);
+        emitCode(crb, masm, config, false, scratch, state);
+    }
+
+    /**
+     * Conservatively checks whether we can load the safepoint polling address with a single ldr
+     * instruction or not.
+     *
+     * @return true if it is guaranteed that polling page offset will always fit into a 21-bit
+     *         signed integer, false otherwise.
+     */
+    private static boolean isPollingPageFar(GraalHotSpotVMConfig config) {
+        final long pollingPageAddress = config.safepointPollingAddress;
+        return !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheLowBound) || !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheHighBound);
+    }
+
+    public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) {
+        int pos = masm.position();
+        if (isPollingPageFar(config)) {
+            crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+            masm.movNativeAddress(scratch, config.safepointPollingAddress);
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            masm.ldr(32, zr, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+        } else {
+            crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR);
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            masm.ldr(32, zr, AArch64Address.createPcLiteralAddress(0));
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotStrategySwitchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotStrategySwitchOp.java
new file mode 100644
index 0000000..d8856bca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotStrategySwitchOp.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.function.Function;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+final class AArch64HotSpotStrategySwitchOp extends AArch64ControlFlow.StrategySwitchOp {
+    public static final LIRInstructionClass<AArch64HotSpotStrategySwitchOp> TYPE = LIRInstructionClass.create(AArch64HotSpotStrategySwitchOp.class);
+
+    AArch64HotSpotStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, Function<Condition, AArch64Assembler.ConditionFlag> converter) {
+        super(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter);
+    }
+
+    @Override
+    public void emitCode(final CompilationResultBuilder crb, final AArch64MacroAssembler masm) {
+        strategy.run(new HotSpotSwitchClosure(asRegister(key), crb, masm));
+    }
+
+    public class HotSpotSwitchClosure extends SwitchClosure {
+
+        protected HotSpotSwitchClosure(Register keyRegister, CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            super(keyRegister, crb, masm);
+        }
+
+        @Override
+        protected void emitComparison(Constant c) {
+            if (c instanceof HotSpotMetaspaceConstant) {
+                HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c;
+                if (meta.isCompressed()) {
+                    crb.recordInlineDataInCode(meta);
+                    // masm.cmpl(keyRegister, 0xDEADDEAD);
+                    throw GraalError.unimplemented();
+                } else {
+                    crb.recordInlineDataInCode(meta);
+                    masm.movNativeAddress(asRegister(scratch), 0x0000_DEAD_DEAD_DEADL);
+                    masm.cmp(64, keyRegister, asRegister(scratch));
+                }
+            } else {
+                super.emitComparison(c);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java
new file mode 100644
index 0000000..72c71d7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+
+/**
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
+ */
+@Opcode("UNWIND")
+public final class AArch64HotSpotUnwindOp extends AArch64HotSpotEpilogueOp {
+    public static final LIRInstructionClass<AArch64HotSpotUnwindOp> TYPE = LIRInstructionClass.create(AArch64HotSpotUnwindOp.class);
+
+    @Use protected RegisterValue exception;
+
+    public AArch64HotSpotUnwindOp(GraalHotSpotVMConfig config, RegisterValue exception) {
+        super(TYPE, config);
+        this.exception = exception;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+
+        ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getOutgoingCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is in lr after frame leave)
+        Register returnAddress = asRegister(cc.getArgument(1));
+        masm.movx(returnAddress, lr);
+
+        AArch64Call.directJmp(crb, masm, linkage);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java
new file mode 100644
index 0000000..cbeae9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.aarch64.AArch64Call;
+import org.graalvm.compiler.lir.aarch64.AArch64Call.IndirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A register indirect call that complies with the extra conventions for such calls in HotSpot. In
+ * particular, the metaspace Method of the callee must be in r12 for the case where a vtable entry's
+ * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to
+ * be in r12.
+ */
+@Opcode("CALL_INDIRECT")
+final class AArch64IndirectCallOp extends IndirectCallOp {
+
+    public static final LIRInstructionClass<AArch64IndirectCallOp> TYPE = LIRInstructionClass.create(AArch64IndirectCallOp.class);
+
+    /**
+     * Vtable stubs expect the metaspace Method in r12.
+     */
+    public static final Register METHOD = r12;
+
+    @Use({REG}) private Value metaspaceMethod;
+
+    private final GraalHotSpotVMConfig config;
+
+    AArch64IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state,
+                    GraalHotSpotVMConfig config) {
+        super(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
+        Register callReg = asRegister(targetAddress);
+        assert !callReg.equals(METHOD);
+        AArch64Call.indirectCall(crb, masm, callReg, callTarget, state);
+    }
+
+    @Override
+    public void verify() {
+        super.verify();
+        assert asRegister(metaspaceMethod).equals(METHOD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java
new file mode 100644
index 0000000..b69ae1b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+
+public class AArchHotSpotNodeCostProvider extends HotSpotNodeCostProvider {
+
+    @Override
+    public NodeCycles cycles(Node n) {
+        return super.cycles(n);
+    }
+
+    @Override
+    public NodeSize size(Node n) {
+        return super.size(n);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java
new file mode 100644
index 0000000..ddc1446
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64.test;
+
+import static jdk.vm.ci.amd64.AMD64.rax;
+
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Ensures that frame omission works in cases where it is expected to.
+ */
+public class AMD64HotSpotFrameOmissionTest extends GraalCompilerTest {
+
+    interface CodeGenerator {
+
+        void generateCode(AMD64Assembler asm);
+    }
+
+    public static void test1snippet() {
+        return;
+    }
+
+    @Ignore
+    @Test
+    public void test1() {
+        testHelper("test1snippet", new CodeGenerator() {
+
+            @Override
+            public void generateCode(AMD64Assembler asm) {
+                asm.nop(5); // padding for mt-safe patching
+                asm.ret(0);
+            }
+        });
+    }
+
+    public static int test2snippet(int x) {
+        return x + 5;
+    }
+
+    @Ignore
+    @Test
+    public void test2() {
+        testHelper("test2snippet", new CodeGenerator() {
+
+            @Override
+            public void generateCode(AMD64Assembler asm) {
+                Register arg = getArgumentRegister(0, JavaKind.Int);
+                asm.nop(5); // padding for mt-safe patching
+                asm.addl(arg, 5);
+                asm.movl(rax, arg);
+                asm.ret(0);
+            }
+        });
+    }
+
+    public static long test3snippet(long x) {
+        return 1 + x;
+    }
+
+    @Ignore
+    @Test
+    public void test3() {
+        testHelper("test3snippet", new CodeGenerator() {
+
+            @Override
+            public void generateCode(AMD64Assembler asm) {
+                Register arg = getArgumentRegister(0, JavaKind.Long);
+                asm.nop(5); // padding for mt-safe patching
+                asm.addq(arg, 1);
+                asm.movq(rax, arg);
+                asm.ret(0);
+            }
+        });
+    }
+
+    private void testHelper(String name, CodeGenerator gen) {
+        ResolvedJavaMethod javaMethod = getResolvedJavaMethod(name);
+        InstalledCode installedCode = getCode(javaMethod);
+
+        TargetDescription target = getCodeCache().getTarget();
+        AMD64Assembler asm = new AMD64Assembler(target);
+
+        gen.generateCode(asm);
+        byte[] expectedCode = asm.close(true);
+
+        // Only compare up to expectedCode.length bytes to ignore
+        // padding instructions adding during code installation
+        byte[] actualCode = Arrays.copyOf(installedCode.getCode(), expectedCode.length);
+
+        Assert.assertArrayEquals(expectedCode, actualCode);
+    }
+
+    private Register getArgumentRegister(int index, JavaKind kind) {
+        RegisterArray regs = getCodeCache().getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, kind);
+        return regs.get(index);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/CompressedNullCheckTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/CompressedNullCheckTest.java
new file mode 100644
index 0000000..31b6798
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/CompressedNullCheckTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64.test;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.test.HotSpotGraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Ensures that frame omission works in cases where it is expected to.
+ */
+public class CompressedNullCheckTest extends HotSpotGraalCompilerTest {
+
+    private static final class Container {
+        Integer i;
+    }
+
+    public static void testSnippet(Container c) {
+        c.i.intValue();
+    }
+
+    @SuppressWarnings("try")
+    private void testImplicit(Integer i) {
+        Assume.assumeTrue(runtime().getVMConfig().useCompressedOops);
+
+        Container c = new Container();
+        c.i = i;
+
+        try (OverrideScope s = OptionValue.override(GraalOptions.OptImplicitNullChecks, true)) {
+            ResolvedJavaMethod method = getResolvedJavaMethod("testSnippet");
+            Result expect = executeExpected(method, null, c);
+
+            // make sure we don't get a profile that removes the implicit null check
+            method.reprofile();
+
+            Result actual = executeActual(method, null, c);
+            assertEquals(expect, actual);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void testExplicit(Integer i) {
+        Assume.assumeTrue(runtime().getVMConfig().useCompressedOops);
+
+        Container c = new Container();
+        c.i = i;
+
+        try (OverrideScope s = OptionValue.override(GraalOptions.OptImplicitNullChecks, false)) {
+            test("testSnippet", c);
+        }
+    }
+
+    @Test
+    public void implicit() {
+        testImplicit(new Integer(1));
+    }
+
+    @Test
+    public void implicitNull() {
+        testImplicit(null);
+    }
+
+    @Test
+    public void explicit() {
+        testExplicit(new Integer(1));
+    }
+
+    @Test
+    public void explicitNull() {
+        testExplicit(null);
+    }
+
+    @Override
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        int count = 0;
+        for (IsNullNode isNull : graph.getNodes().filter(IsNullNode.class).snapshot()) {
+            ValueNode value = isNull.getValue();
+            if (value instanceof CompressionNode) {
+                count++;
+                isNull.replaceFirstInput(value, ((CompressionNode) value).getValue());
+            }
+        }
+        Assert.assertEquals("graph should contain exactly one IsNullNode", 1, count);
+        return super.checkMidTierGraph(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java
new file mode 100644
index 0000000..3c83cc4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.amd64.test;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.hotspot.test.HotSpotGraalCompilerTest;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class DataPatchInConstantsTest extends HotSpotGraalCompilerTest {
+
+    @Before
+    public void checkAMD64() {
+        Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+    }
+
+    private static final Object object = new Object() {
+
+        @Override
+        public String toString() {
+            return "testObject";
+        }
+    };
+
+    private static Object loadThroughPatch(Object obj) {
+        return obj;
+    }
+
+    public static Object oopSnippet() {
+        Object patch = loadThroughPatch(object);
+        if (object != patch) {
+            return "invalid patch";
+        }
+        System.gc();
+        patch = loadThroughPatch(object);
+        if (object != patch) {
+            return "failed after gc";
+        }
+        return patch;
+    }
+
+    @Test
+    public void oopTest() {
+        test("oopSnippet");
+    }
+
+    private static Object loadThroughCompressedPatch(Object obj) {
+        return obj;
+    }
+
+    public static Object narrowOopSnippet() {
+        Object patch = loadThroughCompressedPatch(object);
+        if (object != patch) {
+            return "invalid patch";
+        }
+        System.gc();
+        patch = loadThroughCompressedPatch(object);
+        if (object != patch) {
+            return "failed after gc";
+        }
+        return patch;
+    }
+
+    @Test
+    public void narrowOopTest() {
+        Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops);
+        test("narrowOopSnippet");
+    }
+
+    public static Object compareSnippet() {
+        Object uncompressed = loadThroughPatch(object);
+        Object compressed = loadThroughCompressedPatch(object);
+        if (object != uncompressed) {
+            return "uncompressed failed";
+        }
+        if (object != compressed) {
+            return "compressed failed";
+        }
+        if (uncompressed != compressed) {
+            return "uncompressed != compressed";
+        }
+        return object;
+    }
+
+    @Test
+    public void compareTest() {
+        Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops);
+        test("compareSnippet");
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), DataPatchInConstantsTest.class);
+
+        r.register1("loadThroughPatch", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                b.addPush(JavaKind.Object, new LoadThroughPatchNode(arg));
+                return true;
+            }
+        });
+
+        r.register1("loadThroughCompressedPatch", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ValueNode compressed = b.add(CompressionNode.compress(arg, runtime().getVMConfig().getOopEncoding()));
+                ValueNode patch = b.add(new LoadThroughPatchNode(compressed));
+                b.addPush(JavaKind.Object, CompressionNode.uncompress(patch, runtime().getVMConfig().getOopEncoding()));
+                return true;
+            }
+        });
+
+        return plugins;
+    }
+
+    @NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+    private static final class LoadThroughPatchNode extends FixedWithNextNode implements LIRLowerable {
+        public static final NodeClass<LoadThroughPatchNode> TYPE = NodeClass.create(LoadThroughPatchNode.class);
+
+        @Input protected ValueNode input;
+
+        protected LoadThroughPatchNode(ValueNode input) {
+            super(TYPE, input.stamp());
+            this.input = input;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool generator) {
+            assert input.isConstant();
+
+            LIRGeneratorTool gen = generator.getLIRGeneratorTool();
+            Variable ret = gen.newVariable(gen.getLIRKind(stamp()));
+
+            gen.append(new LoadThroughPatchOp(input.asConstant(), stamp() instanceof NarrowOopStamp, ret));
+            generator.setResult(this, ret);
+        }
+    }
+
+    private static final class LoadThroughPatchOp extends LIRInstruction {
+        public static final LIRInstructionClass<LoadThroughPatchOp> TYPE = LIRInstructionClass.create(LoadThroughPatchOp.class);
+
+        final Constant c;
+        final boolean compressed;
+        @Def({REG}) AllocatableValue result;
+
+        LoadThroughPatchOp(Constant c, boolean compressed, AllocatableValue result) {
+            super(TYPE);
+            this.c = c;
+            this.compressed = compressed;
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(c, compressed ? 4 : 8);
+            AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
+            if (compressed) {
+                asm.movl(asRegister(result), address);
+            } else {
+                asm.movq(asRegister(result), address);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java
new file mode 100644
index 0000000..b7b473b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.amd64.test;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.SnippetStub;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+public class StubAVXTest extends LIRTest {
+
+    @Before
+    public void checkAMD64() {
+        Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+        Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX));
+    }
+
+    private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32);
+
+    private static class LoadAVXConstant extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<LoadAVXConstant> TYPE = LIRInstructionClass.create(LoadAVXConstant.class);
+
+        @Def({REG}) AllocatableValue result;
+
+        LoadAVXConstant(AllocatableValue result) {
+            super(TYPE);
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.vmovdqu(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(avxConstant));
+        }
+    }
+
+    private static final LIRTestSpecification loadAVXConstant = new LIRTestSpecification() {
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            Variable ret = gen.newVariable(LIRKind.value(AMD64Kind.V256_SINGLE));
+            gen.append(new LoadAVXConstant(ret));
+            setResult(ret);
+        }
+    };
+
+    @LIRIntrinsic
+    public static Object loadAVXConstant(@SuppressWarnings("unused") LIRTestSpecification spec) {
+        return null;
+    }
+
+    private static class CompareAVXRegister extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompareAVXRegister> TYPE = LIRInstructionClass.create(CompareAVXRegister.class);
+
+        @Def({REG}) AllocatableValue result;
+        @Use({REG}) AllocatableValue left;
+        @Use({REG}) AllocatableValue right;
+        @Temp({REG}) AllocatableValue temp;
+
+        CompareAVXRegister(AllocatableValue result, AllocatableValue left, AllocatableValue right, AllocatableValue temp) {
+            super(TYPE);
+            this.result = result;
+            this.left = left;
+            this.right = right;
+            this.temp = temp;
+        }
+
+        private static int getRXB(Register reg, Register rm) {
+            int rxb = (reg.encoding & 0x08) >> 1;
+            rxb |= (rm.encoding & 0x08) >> 3;
+            return rxb;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            Register res = ValueUtil.asRegister(result);
+            Register x = ValueUtil.asRegister(left);
+            Register y = ValueUtil.asRegister(right);
+            Register tmp = ValueUtil.asRegister(temp);
+
+            // VEX.NDS.256.0F.WIG C2 /r ib(0)
+            // VCMPPS tmp, x, y, EQ
+            masm.emitByte(0xC4);                                   // VEX 3-byte
+            masm.emitByte((~getRXB(tmp, y) & 0x7) << 5 | 0x01);    // RXB m-mmmmm (0F)
+            masm.emitByte(((~x.encoding & 0x0f) << 3) | 0b1_00);   // W(0) vvvv L(1) pp(0)
+            masm.emitByte(0xC2);
+            masm.emitByte(0xC0 | ((tmp.encoding & 0x07) << 3) | (y.encoding & 0x07));
+            masm.emitByte(0);
+
+            // VEX.256.0F.WIG 50 /r
+            // VMOVMSKPS res, tmp
+            masm.emitByte(0xC4);                                   // VEX 3-byte
+            masm.emitByte((~getRXB(res, tmp) & 0x7) << 5 | 0x01);  // RXB m-mmmmm (0F)
+            masm.emitByte(0b0_1111_1_00);                          // W(0) vvvv L(1) pp(0)
+            masm.emitByte(0x50);
+            masm.emitByte(0xC0 | ((res.encoding & 0x07) << 3) | (tmp.encoding & 0x07));
+        }
+    }
+
+    private static final LIRTestSpecification compareAVXRegister = new LIRTestSpecification() {
+
+        @Override
+        public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) {
+            Variable ret = gen.newVariable(LIRKind.value(AMD64Kind.DWORD));
+            gen.append(new CompareAVXRegister(ret, gen.asAllocatable(arg0), gen.asAllocatable(arg1), gen.newVariable(LIRKind.value(AMD64Kind.V256_QWORD))));
+            setResult(ret);
+        }
+    };
+
+    private static class TestStub extends SnippetStub {
+
+        TestStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+            super("testStub", providers, linkage);
+        }
+
+        @Snippet
+        static void testStub() {
+        }
+    }
+
+    public static final ForeignCallDescriptor TEST_STUB = new ForeignCallDescriptor("test_stub", void.class);
+
+    @LIRIntrinsic
+    public static int compareAVXRegister(@SuppressWarnings("unused") LIRTestSpecification spec, Object left, Object right) {
+        return left == right ? 0xff : 0;
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestStub.class);
+        r.register0("testStub", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) {
+                b.add(new ForeignCallNode(getProviders().getForeignCalls(), TEST_STUB));
+                return true;
+            }
+        });
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    public static int testStub() {
+        Object preStub = loadAVXConstant(loadAVXConstant);
+
+        // do something to potentially destroy the value
+        TestStub.testStub();
+
+        Object postStub = loadAVXConstant(loadAVXConstant);
+        return compareAVXRegister(compareAVXRegister, preStub, postStub);
+    }
+
+    @Test
+    public void test() {
+        HotSpotProviders providers = (HotSpotProviders) getProviders();
+        HotSpotForeignCallsProviderImpl foreignCalls = (HotSpotForeignCallsProviderImpl) providers.getForeignCalls();
+        HotSpotForeignCallLinkage linkage = foreignCalls.registerStubCall(TEST_STUB, true, HotSpotForeignCallLinkage.Transition.LEAF_NOFP);
+        linkage.setCompiledStub(new TestStub(providers, linkage));
+        runTest("testStub");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizationStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizationStub.java
new file mode 100644
index 0000000..d0d77ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizationStub.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.r10;
+import static jdk.vm.ci.amd64.AMD64.r11;
+import static jdk.vm.ci.amd64.AMD64.r13;
+import static jdk.vm.ci.amd64.AMD64.r14;
+import static jdk.vm.ci.amd64.AMD64.r8;
+import static jdk.vm.ci.amd64.AMD64.r9;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.amd64.AMD64.rcx;
+import static jdk.vm.ci.amd64.AMD64.rdi;
+import static jdk.vm.ci.amd64.AMD64.rdx;
+import static jdk.vm.ci.amd64.AMD64.rsi;
+
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub;
+
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.amd64.AMD64HotSpotRegisterConfig;
+
+final class AMD64DeoptimizationStub extends DeoptimizationStub {
+
+    private RegisterConfig registerConfig;
+
+    AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        registerConfig = new AMD64HotSpotRegisterConfig(target, new RegisterArray(rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14), config.windowsOs);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java
new file mode 100644
index 0000000..bce1d81
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64DeoptimizeOp.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.amd64.AMD64BlockEndOp;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+@Opcode("DEOPT")
+final class AMD64DeoptimizeOp extends AMD64BlockEndOp implements BlockEndOp {
+    public static final LIRInstructionClass<AMD64DeoptimizeOp> TYPE = LIRInstructionClass.create(AMD64DeoptimizeOp.class);
+
+    @State private LIRFrameState info;
+
+    AMD64DeoptimizeOp(LIRFrameState info) {
+        super(TYPE);
+        this.info = info;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
new file mode 100644
index 0000000..d8c5cd6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.core.amd64.AMD64AddressLowering;
+import org.graalvm.compiler.core.amd64.AMD64AddressNode;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.JavaKind;
+
+public class AMD64HotSpotAddressLowering extends AMD64AddressLowering {
+
+    private final long heapBase;
+    private final Register heapBaseRegister;
+    private final GraalHotSpotVMConfig config;
+
+    @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+    public static class HeapBaseNode extends FloatingNode implements LIRLowerable {
+
+        public static final NodeClass<HeapBaseNode> TYPE = NodeClass.create(HeapBaseNode.class);
+
+        private final Register heapBaseRegister;
+
+        public HeapBaseNode(Register heapBaseRegister) {
+            super(TYPE, StampFactory.pointer());
+            this.heapBaseRegister = heapBaseRegister;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool generator) {
+            LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+            generator.setResult(this, heapBaseRegister.asValue(kind));
+        }
+    }
+
+    public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister) {
+        this.heapBase = config.getOopEncoding().base;
+        this.config = config;
+        if (heapBase == 0 && !GeneratePIC.getValue()) {
+            this.heapBaseRegister = null;
+        } else {
+            this.heapBaseRegister = heapBaseRegister;
+        }
+    }
+
+    @Override
+    protected boolean improve(AMD64AddressNode addr) {
+        if (addr.getScale() == Scale.Times1) {
+            if (addr.getBase() == null && addr.getIndex() instanceof CompressionNode) {
+                if (improveUncompression(addr, (CompressionNode) addr.getIndex())) {
+                    return true;
+                }
+            }
+
+            if (addr.getIndex() == null && addr.getBase() instanceof CompressionNode) {
+                if (improveUncompression(addr, (CompressionNode) addr.getBase())) {
+                    return true;
+                }
+            }
+        }
+
+        return super.improve(addr);
+    }
+
+    private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression) {
+        if (compression.getOp() == CompressionOp.Uncompress) {
+            CompressEncoding encoding = compression.getEncoding();
+            Scale scale = Scale.fromShift(encoding.shift);
+            if (scale == null) {
+                return false;
+            }
+
+            if (heapBaseRegister != null && encoding.base == heapBase) {
+                if (!GeneratePIC.getValue() || compression.stamp() instanceof ObjectStamp) {
+                    // With PIC it is only legal to do for oops since the base value may be
+                    // different at runtime.
+                    ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister));
+                    addr.setBase(base);
+                } else {
+                    return false;
+                }
+            } else if (encoding.base != 0 || (GeneratePIC.getValue() && compression.stamp() instanceof KlassPointerStamp)) {
+                if (GeneratePIC.getValue()) {
+                    ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long));
+                    addr.setBase(base);
+                } else {
+                    long disp = addr.getDisplacement() + encoding.base;
+                    if (NumUtil.isInt(disp)) {
+                        addr.setDisplacement((int) disp);
+                        addr.setBase(null);
+                    } else {
+                        return false;
+                    }
+                }
+            } else {
+                addr.setBase(null);
+            }
+
+            addr.setScale(scale);
+            addr.setIndex(compression.getValue());
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java
new file mode 100644
index 0000000..b14f177
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.COS;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG10;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.SIN;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.TAN;
+
+import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.Variable;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
+
+import jdk.vm.ci.meta.Value;
+
+public class AMD64HotSpotArithmeticLIRGenerator extends AMD64ArithmeticLIRGenerator {
+
+    @Override
+    public Value emitMathLog(Value input, boolean base10) {
+        if (GraalArithmeticStubs.getValue()) {
+            return super.emitMathLog(input, base10);
+        }
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Value emitMathCos(Value input) {
+        if (GraalArithmeticStubs.getValue()) {
+            return super.emitMathCos(input);
+        }
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Value emitMathSin(Value input) {
+        if (GraalArithmeticStubs.getValue()) {
+            return super.emitMathSin(input);
+        }
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Value emitMathTan(Value input) {
+        if (GraalArithmeticStubs.getValue()) {
+            return super.emitMathTan(input);
+        }
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input)));
+        return result;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java
new file mode 100644
index 0000000..4ccc1bb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.CanOmitFrame;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
+import static jdk.vm.ci.amd64.AMD64.r10;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.Set;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.amd64.AMD64FrameMap;
+import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.asm.DataBuilder;
+import org.graalvm.compiler.lir.asm.FrameContext;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * HotSpot AMD64 specific backend.
+ */
+public class AMD64HotSpotBackend extends HotSpotHostBackend {
+
+    public AMD64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(config, runtime, providers);
+    }
+
+    @Override
+    public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AMD64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+    }
+
+    @Override
+    public FrameMap newFrameMap(RegisterConfig registerConfig) {
+        return new AMD64FrameMap(getCodeCache(), registerConfig, this);
+    }
+
+    @Override
+    public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
+        return new AMD64HotSpotLIRGenerator(getProviders(), config, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) {
+        return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+        return new AMD64HotSpotNodeLIRBuilder(graph, lirGen, new AMD64NodeMatchRules(lirGen));
+    }
+
+    @Override
+    protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
+        AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
+        int pos = asm.position();
+        asm.movl(new AMD64Address(rsp, -bangOffset), AMD64.rax);
+        assert asm.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+    }
+
+    /**
+     * The size of the instruction used to patch the verified entry point of an nmethod when the
+     * nmethod is made non-entrant or a zombie (e.g. during deopt or class unloading). The first
+     * instruction emitted at an nmethod's verified entry point must be at least this length to
+     * ensure mt-safe patching.
+     */
+    public static final int PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE = 5;
+
+    /**
+     * Emits code at the verified entry point and return point(s) of a method.
+     */
+    class HotSpotFrameContext implements FrameContext {
+
+        final boolean isStub;
+        final boolean omitFrame;
+
+        HotSpotFrameContext(boolean isStub, boolean omitFrame) {
+            this.isStub = isStub;
+            this.omitFrame = omitFrame;
+        }
+
+        @Override
+        public boolean hasFrame() {
+            return !omitFrame;
+        }
+
+        @Override
+        public void enter(CompilationResultBuilder crb) {
+            FrameMap frameMap = crb.frameMap;
+            int frameSize = frameMap.frameSize();
+            AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
+            if (omitFrame) {
+                if (!isStub) {
+                    asm.nop(PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE);
+                }
+            } else {
+                int verifiedEntryPointOffset = asm.position();
+                if (!isStub) {
+                    emitStackOverflowCheck(crb);
+                    // assert asm.position() - verifiedEntryPointOffset >=
+                    // PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+                }
+                if (!isStub && asm.position() == verifiedEntryPointOffset) {
+                    asm.subqWide(rsp, frameSize);
+                    assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE;
+                } else {
+                    asm.decrementq(rsp, frameSize);
+                }
+                if (ZapStackOnMethodEntry.getValue()) {
+                    final int intSize = 4;
+                    for (int i = 0; i < frameSize / intSize; ++i) {
+                        asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1);
+                    }
+                }
+                assert frameMap.getRegisterConfig().getCalleeSaveRegisters() == null;
+            }
+        }
+
+        @Override
+        public void leave(CompilationResultBuilder crb) {
+            if (!omitFrame) {
+                AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
+                assert crb.frameMap.getRegisterConfig().getCalleeSaveRegisters() == null;
+
+                int frameSize = crb.frameMap.frameSize();
+                asm.incrementq(rsp, frameSize);
+            }
+        }
+    }
+
+    @Override
+    protected Assembler createAssembler(FrameMap frameMap) {
+        return new AMD64MacroAssembler(getTarget());
+    }
+
+    @Override
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        // Omit the frame if the method:
+        // - has no spill slots or other slots allocated during register allocation
+        // - has no callee-saved registers
+        // - has no incoming arguments passed on the stack
+        // - has no deoptimization points
+        // - makes no foreign calls (which require an aligned stack)
+        HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen;
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+        boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall();
+
+        Stub stub = gen.getStub();
+        Assembler masm = createAssembler(frameMap);
+        HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame);
+        DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
+        CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult);
+        crb.setTotalFrameSize(frameMap.totalFrameSize());
+        crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+        if (deoptimizationRescueSlot != null && stub == null) {
+            crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
+        }
+
+        if (stub != null) {
+            Set<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
+            updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap);
+        }
+
+        return crb;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+        AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig regConfig = frameMap.getRegisterConfig();
+        Label verifiedEntry = new Label();
+
+        // Emit the prefix
+        emitCodePrefix(installedCodeOwner, crb, asm, regConfig, verifiedEntry);
+
+        // Emit code for the LIR
+        emitCodeBody(installedCodeOwner, crb, lir);
+
+        // Emit the suffix
+        emitCodeSuffix(installedCodeOwner, crb, asm, frameMap);
+
+        // Profile assembler instructions
+        profileInstructions(lir, crb);
+    }
+
+    /**
+     * Emits the code prior to the verified entry point.
+     *
+     * @param installedCodeOwner see {@link Backend#emitCode}
+     */
+    public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, Label verifiedEntry) {
+        HotSpotProviders providers = getProviders();
+        if (installedCodeOwner != null && !installedCodeOwner.isStatic()) {
+            crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+            CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this);
+            Register inlineCacheKlass = rax; // see definition of IC_Klass in
+                                             // c1_LIRAssembler_x86.cpp
+            Register receiver = asRegister(cc.getArgument(0));
+            AMD64Address src = new AMD64Address(receiver, config.hubOffset);
+
+            if (config.useCompressedClassPointers) {
+                Register register = r10;
+                AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding());
+                if (config.narrowKlassBase != 0) {
+                    // The heap base register was destroyed above, so restore it
+                    asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
+                }
+                asm.cmpq(inlineCacheKlass, register);
+            } else {
+                asm.cmpq(inlineCacheKlass, src);
+            }
+            AMD64Call.directConditionalJmp(crb, asm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER), ConditionFlag.NotEqual);
+        }
+
+        asm.align(config.codeEntryAlignment);
+        crb.recordMark(config.MARKID_OSR_ENTRY);
+        asm.bind(verifiedEntry);
+        crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+
+        if (GeneratePIC.getValue()) {
+            // Check for method state
+            HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+            if (!frameContext.isStub) {
+                crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AMD64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT);
+                asm.movq(AMD64.rax, asm.getPlaceholder(-1));
+                asm.testq(AMD64.rax, AMD64.rax);
+                AMD64Call.directConditionalJmp(crb, asm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER), ConditionFlag.NotZero);
+            }
+        }
+    }
+
+    /**
+     * Emits the code which starts at the verified entry point.
+     *
+     * @param installedCodeOwner see {@link Backend#emitCode}
+     */
+    public void emitCodeBody(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIR lir) {
+        crb.emit(lir);
+    }
+
+    /**
+     * @param installedCodeOwner see {@link Backend#emitCode}
+     */
+    public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) {
+        HotSpotProviders providers = getProviders();
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+        if (!frameContext.isStub) {
+            HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
+            crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
+            crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+
+            if (frameContext.omitFrame) {
+                // Cannot access slots in caller's frame if my frame is omitted
+                assert !frameMap.accessesCallerFrame();
+            }
+        }
+    }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AMD64HotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
+    @Override
+    public Set<Register> translateToCallerRegisters(Set<Register> calleeRegisters) {
+        return calleeRegisters;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
new file mode 100644
index 0000000..96f90d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
+import static jdk.vm.ci.common.InitTimer.timer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegisters;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.amd64.AMD64GraphBuilderPlugins;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.InitTimer;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+@ServiceProvider(HotSpotBackendFactory.class)
+public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
+
+    @Override
+    public String getName() {
+        return "core";
+    }
+
+    @Override
+    public Class<? extends Architecture> getArchitecture() {
+        return AMD64.class;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) {
+        assert host == null;
+
+        JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
+        GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
+        HotSpotProviders providers;
+        HotSpotRegistersProvider registers;
+        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache();
+        TargetDescription target = codeCache.getTarget();
+        HotSpotHostForeignCallsProvider foreignCalls;
+        Value[] nativeABICallerSaveRegisters;
+        HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess();
+        HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
+        ConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
+        HotSpotLoweringProvider lowerer;
+        HotSpotSnippetReflectionProvider snippetReflection;
+        HotSpotReplacementsImpl replacements;
+        HotSpotSuitesProvider suites;
+        HotSpotWordTypes wordTypes;
+        Plugins plugins;
+        NodeCostProvider nodeCostProvider;
+        BytecodeProvider bytecodeProvider;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = createRegisters();
+            }
+            try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) {
+                nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
+            }
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
+            }
+            try (InitTimer rt = timer("create NodeCost provider")) {
+                nodeCostProvider = createNodeCostProvider(target);
+            }
+            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+
+            try (InitTimer rt = timer("create SnippetReflection provider")) {
+                snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
+            }
+            try (InitTimer rt = timer("create Bytecode provider")) {
+                bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = createReplacements(p, snippetReflection, bytecodeProvider);
+            }
+            try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
+                plugins = createGraphBuilderPlugins(config, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                replacements.setGraphBuilderPlugins(plugins);
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, registers, replacements);
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+                            snippetReflection, wordTypes,
+                            plugins);
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return createBackend(config, graalRuntime, providers);
+        }
+    }
+
+    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, TargetDescription target, HotSpotConstantReflectionProvider constantReflection,
+                    HotSpotHostForeignCallsProvider foreignCalls,
+                    HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes,
+                    HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        AMD64GraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue());
+        return plugins;
+    }
+
+    protected AMD64HotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        return new AMD64HotSpotBackend(config, runtime, providers);
+    }
+
+    protected HotSpotRegistersProvider createRegisters() {
+        return new HotSpotRegisters(AMD64.r15, AMD64.r12, AMD64.rsp);
+    }
+
+    protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
+        return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget());
+    }
+
+    protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
+        return new AMD64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
+    }
+
+    /**
+     * @param replacements
+     */
+    protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins,
+                    HotSpotRegistersProvider registers, Replacements replacements) {
+        return new HotSpotSuitesProvider(new AMD64HotSpotSuitesProvider(compilerConfiguration, plugins), config, runtime, new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister()));
+    }
+
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
+    }
+
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
+                    HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    protected HotSpotNodeCostProvider createNodeCostProvider(TargetDescription target) {
+        return new AMD64HotSpotNodeCostProvider(target);
+    }
+
+    protected Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) {
+        List<Register> callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList());
+        if (config.windowsOs) {
+            // http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
+            callerSave.remove(AMD64.rdi);
+            callerSave.remove(AMD64.rsi);
+            callerSave.remove(AMD64.rbx);
+            callerSave.remove(AMD64.rbp);
+            callerSave.remove(AMD64.rsp);
+            callerSave.remove(AMD64.r12);
+            callerSave.remove(AMD64.r13);
+            callerSave.remove(AMD64.r14);
+            callerSave.remove(AMD64.r15);
+            callerSave.remove(AMD64.xmm6);
+            callerSave.remove(AMD64.xmm7);
+            callerSave.remove(AMD64.xmm8);
+            callerSave.remove(AMD64.xmm9);
+            callerSave.remove(AMD64.xmm10);
+            callerSave.remove(AMD64.xmm11);
+            callerSave.remove(AMD64.xmm12);
+            callerSave.remove(AMD64.xmm13);
+            callerSave.remove(AMD64.xmm14);
+            callerSave.remove(AMD64.xmm15);
+        } else {
+            /*
+             * System V Application Binary Interface, AMD64 Architecture Processor Supplement
+             *
+             * Draft Version 0.96
+             *
+             * http://www.uclibc.org/docs/psABI-x86_64.pdf
+             *
+             * 3.2.1
+             *
+             * ...
+             *
+             * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
+             * through %r15 "belong" to the calling function and the called function is required to
+             * preserve their values. In other words, a called function must preserve these
+             * registers' values for its caller. Remaining registers "belong" to the called
+             * function. If a calling function wants to preserve such a register value across a
+             * function call, it must save the value in its local stack frame.
+             */
+            callerSave.remove(AMD64.rbp);
+            callerSave.remove(AMD64.rbx);
+            callerSave.remove(AMD64.r12);
+            callerSave.remove(AMD64.r13);
+            callerSave.remove(AMD64.r14);
+            callerSave.remove(AMD64.r15);
+        }
+        Value[] nativeABICallerSaveRegisters = new Value[callerSave.size()];
+        for (int i = 0; i < callerSave.size(); i++) {
+            nativeABICallerSaveRegisters[i] = callerSave.get(i).asValue();
+        }
+        return nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public String toString() {
+        return "AMD64";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java
new file mode 100644
index 0000000..3e1f699
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallEpilogueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaFpOffset;
+    private final int threadLastJavaPcOffset;
+    private final Register thread;
+
+    AMD64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, int threadLastJavaPcOffset, Register thread) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // reset last Java frame:
+        masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0);
+        masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java
new file mode 100644
index 0000000..42cd620
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.rsp;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+
+@Opcode
+final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallPrologueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final Register thread;
+
+    AMD64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // save last Java frame
+        masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotConstantRetrievalOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotConstantRetrievalOp.java
new file mode 100644
index 0000000..5ee0a5f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotConstantRetrievalOp.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AMD64HotSpotConstantRetrievalOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotConstantRetrievalOp> TYPE = LIRInstructionClass.create(AMD64HotSpotConstantRetrievalOp.class);
+
+    @Def protected AllocatableValue result;
+    protected final Constant[] constants;
+    @Alive protected AllocatableValue[] constantDescriptions;
+    @Temp protected AllocatableValue[] gotSlotOffsetParameters;
+    @Temp protected AllocatableValue[] descriptionParameters;
+    @Temp protected Value[] callTemps;
+    @State protected LIRFrameState frameState;
+    private final ForeignCallLinkage callLinkage;
+    private final Object[] notes;
+
+    private class CollectTemporaries implements ValueProcedure {
+        ArrayList<Value> values = new ArrayList<>();
+
+        CollectTemporaries() {
+            forEachTemp(this);
+        }
+
+        public Value[] asArray() {
+            Value[] copy = new Value[values.size()];
+            return values.toArray(copy);
+        }
+
+        @Override
+        public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            values.add(value);
+            return value;
+        }
+    }
+
+    public AMD64HotSpotConstantRetrievalOp(Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState, ForeignCallLinkage callLinkage, Object[] notes) {
+        super(TYPE);
+        this.constantDescriptions = constantDescriptions;
+        this.constants = constants;
+        this.frameState = frameState;
+        this.notes = notes;
+        assert constants.length == notes.length;
+
+        // call arguments
+        CallingConvention callingConvention = callLinkage.getOutgoingCallingConvention();
+        this.gotSlotOffsetParameters = new AllocatableValue[constants.length];
+        int argIndex = 0;
+        for (int i = 0; i < constants.length; i++, argIndex++) {
+            this.gotSlotOffsetParameters[i] = callingConvention.getArgument(argIndex);
+        }
+        this.descriptionParameters = new AllocatableValue[constantDescriptions.length];
+        for (int i = 0; i < constantDescriptions.length; i++, argIndex++) {
+            this.descriptionParameters[i] = callingConvention.getArgument(argIndex);
+        }
+        this.result = callingConvention.getReturn();
+
+        this.callLinkage = callLinkage;
+
+        // compute registers that are killed by the stub, but are not used as other temps.
+        this.callTemps = new Value[0];
+        this.callTemps = LIRValueUtil.subtractRegisters(callLinkage.getTemporaries(), new CollectTemporaries().asArray());
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // metadata_adr
+        for (int i = 0; i < constants.length; i++) {
+            crb.recordInlineDataInCodeWithNote(constants[i], notes[i]);
+            masm.leaq(asRegister(gotSlotOffsetParameters[i]), masm.getPlaceholder(-1));
+        }
+
+        for (int i = 0; i < constantDescriptions.length; i++) {
+            masm.movq(asRegister(descriptionParameters[i]), asRegister(constantDescriptions[i]));
+        }
+
+        final int before = masm.position();
+        masm.call();
+        final int after = masm.position();
+        crb.recordDirectCall(before, after, callLinkage, frameState);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java
new file mode 100644
index 0000000..f1d4e3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotCounterOp;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+@Opcode("BenchMarkCounter")
+public class AMD64HotSpotCounterOp extends HotSpotCounterOp {
+    public static final LIRInstructionClass<AMD64HotSpotCounterOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCounterOp.class);
+
+    @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot;
+
+    public AMD64HotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config, AllocatableValue backupSlot) {
+        super(TYPE, name, group, increment, registers, config);
+        this.backupSlot = backupSlot;
+    }
+
+    public AMD64HotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config, AllocatableValue backupSlot) {
+        super(TYPE, names, groups, increments, registers, config);
+        this.backupSlot = backupSlot;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        AMD64MacroAssembler masm = (AMD64MacroAssembler) crb.asm;
+        TargetDescription target = crb.target;
+
+        Register scratch;
+        // It can happen that the rax register is the increment register, in this case we do not
+        // want to spill it to the stack.
+        if (!contains(increments, rax)) {
+            scratch = rax;
+        } else if (!contains(increments, rbx)) {
+            scratch = rbx;
+        } else {
+            // In this case rax and rbx are used as increment. Either we implement a third register
+            // or we implement a spillover the value from rax to rbx or vice versa during
+            // emitIncrement().
+            throw GraalError.unimplemented("RAX and RBX are increment registers at the same time, spilling over the scratch register is not supported right now");
+        }
+
+        // address for counters array
+        AMD64Address countersArrayAddr = new AMD64Address(thread, config.jvmciCountersThreadOffset);
+        Register countersArrayReg = scratch;
+
+        // backup scratch register
+        masm.movq((AMD64Address) crb.asAddress(backupSlot), scratch);
+
+        // load counters array
+        masm.movptr(countersArrayReg, countersArrayAddr);
+        CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement);
+        forEachCounter(emitProcedure, target);
+
+        // restore scratch register
+        masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot));
+    }
+
+    /**
+     * Tests if the array contains the register.
+     */
+    private static boolean contains(Value[] increments, Register register) {
+        for (Value increment : increments) {
+            if (isRegister(increment) && asRegister(increment).equals(register)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value incrementValue, int displacement) {
+        // address for counter value
+        AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement);
+        // increment counter (in memory)
+        if (isJavaConstant(incrementValue)) {
+            int increment = asInt(asJavaConstant(incrementValue));
+            masm.incrementq(counterAddr, increment);
+        } else {
+            masm.addq(counterAddr, asRegister(incrementValue));
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java
new file mode 100644
index 0000000..b056626
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueBlockEndOp {
+
+    public static final LIRInstructionClass<AMD64HotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDeoptimizeCallerOp.class);
+
+    protected AMD64HotSpotDeoptimizeCallerOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(crb, masm);
+        AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java
new file mode 100644
index 0000000..1230d66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64Call.DirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
+ * inline cache so it's just a patchable call site.
+ */
+@Opcode("CALL_DIRECT")
+final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<AMD64HotSpotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDirectStaticCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isDirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
+        super.emitCode(crb, masm);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java
new file mode 100644
index 0000000..30c8a7f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.amd64.AMD64.rip;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotEnterUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotEnterUnpackFramesStackFrameOp.class);
+
+    private final Register threadRegister;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadLastJavaFpOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue senderFp;
+
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc,
+                    AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
+        this.threadRegister = threadRegister;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.senderFp = senderFp;
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.getRegisterConfig();
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+        final int totalFrameSize = frameMap.totalFrameSize();
+
+        // Push return address.
+        masm.push(asRegister(framePc));
+
+        // Push base pointer.
+        masm.push(asRegister(senderFp));
+        masm.movq(rbp, stackPointerRegister);
+
+        /*
+         * Allocate a full sized frame. Since return address and base pointer are already in place
+         * (see above) we allocate two words less.
+         */
+        masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize);
+
+        // Save return registers after moving the frame.
+        final int stackSlotSize = frameMap.getTarget().wordSize;
+        Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long);
+        masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister);
+
+        Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double);
+        masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister);
+
+        // Set up last Java values.
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister);
+
+        /*
+         * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned
+         * SP. Don't need the precise return PC here, just precise enough to point into this code
+         * blob.
+         */
+        masm.leaq(rax, new AMD64Address(rip, 0));
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax);
+
+        // Use BP because the frames look interpreted now.
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp);
+
+        // Align the stack for the following unpackFrames call.
+        masm.andq(stackPointerRegister, -(crb.target.stackAlignment));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java
new file mode 100644
index 0000000..237dcce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.amd64.AMD64BlockEndOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * @see AMD64HotSpotEpilogueOp
+ */
+abstract class AMD64HotSpotEpilogueBlockEndOp extends AMD64BlockEndOp implements AMD64HotSpotRestoreRbpOp {
+
+    protected AMD64HotSpotEpilogueBlockEndOp(LIRInstructionClass<? extends AMD64HotSpotEpilogueBlockEndOp> c) {
+        super(c);
+    }
+
+    @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER;
+
+    protected void leaveFrameAndRestoreRbp(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64HotSpotEpilogueOp.leaveFrameAndRestoreRbp(savedRbp, crb, masm);
+    }
+
+    @Override
+    public void setSavedRbp(AllocatableValue value) {
+        savedRbp = value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueOp.java
new file mode 100644
index 0000000..0650ac6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueOp.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Superclass for operations that use the value of RBP saved in a method's prologue.
+ */
+abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction implements AMD64HotSpotRestoreRbpOp {
+
+    protected AMD64HotSpotEpilogueOp(LIRInstructionClass<? extends AMD64HotSpotEpilogueOp> c) {
+        super(c);
+    }
+
+    @Use({REG, STACK}) private AllocatableValue savedRbp = PLACEHOLDER;
+
+    protected void leaveFrameAndRestoreRbp(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(savedRbp, crb, masm);
+    }
+
+    static void leaveFrameAndRestoreRbp(AllocatableValue savedRbp, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (isStackSlot(savedRbp)) {
+            // Restoring RBP from the stack must be done before the frame is removed
+            masm.movq(rbp, (AMD64Address) crb.asAddress(savedRbp));
+        } else {
+            Register framePointer = asRegister(savedRbp);
+            if (!framePointer.equals(rbp)) {
+                masm.movq(rbp, framePointer);
+            }
+        }
+        crb.frameContext.leave(crb);
+    }
+
+    @Override
+    public void setSavedRbp(AllocatableValue value) {
+        savedRbp = value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java
new file mode 100644
index 0000000..3f9f2cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rdx;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+import static jdk.vm.ci.meta.Value.ILLEGAL;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider {
+
+    public static final ForeignCallDescriptor ARITHMETIC_SIN_STUB = new ForeignCallDescriptor("arithmeticSinStub", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_COS_STUB = new ForeignCallDescriptor("arithmeticCosStub", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_TAN_STUB = new ForeignCallDescriptor("arithmeticTanStub", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_EXP_STUB = new ForeignCallDescriptor("arithmeticExpStub", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_POW_STUB = new ForeignCallDescriptor("arithmeticPowStub", double.class, double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_LOG_STUB = new ForeignCallDescriptor("arithmeticLogStub", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_LOG10_STUB = new ForeignCallDescriptor("arithmeticLog10Stub", double.class, double.class);
+
+    private final Value[] nativeABICallerSaveRegisters;
+
+    public AMD64HotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
+        super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes);
+        this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers) {
+        GraalHotSpotVMConfig config = runtime.getVMConfig();
+        TargetDescription target = providers.getCodeCache().getTarget();
+        PlatformKind word = target.arch.getWordKind();
+
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        // in templateInterpreter_x86_64.cpp around line 1923
+        RegisterValue exception = rax.asValue(LIRKind.reference(word));
+        RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word));
+        CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any()));
+
+        if (PreferGraalStubs.getValue()) {
+            link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+            link(new AMD64UncommonTrapStub(providers, target, config, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        }
+        link(new AMD64MathStub(ARITHMETIC_LOG_STUB, providers, registerStubCall(ARITHMETIC_LOG_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_LOG10_STUB, providers, registerStubCall(ARITHMETIC_LOG10_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_SIN_STUB, providers, registerStubCall(ARITHMETIC_SIN_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_COS_STUB, providers, registerStubCall(ARITHMETIC_COS_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_TAN_STUB, providers, registerStubCall(ARITHMETIC_TAN_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_EXP_STUB, providers, registerStubCall(ARITHMETIC_EXP_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64MathStub(ARITHMETIC_POW_STUB, providers, registerStubCall(ARITHMETIC_POW_STUB, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+
+        if (config.useCRC32Intrinsics) {
+            // This stub does callee saving
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
+        }
+
+        super.initialize(providers);
+    }
+
+    @Override
+    public Value[] getNativeABICallerSaveRegisters() {
+        return nativeABICallerSaveRegisters;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java
new file mode 100644
index 0000000..03b9b85
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueBlockEndOp {
+
+    public static final LIRInstructionClass<AMD64HotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(AMD64HotSpotJumpToExceptionHandlerInCallerOp.class);
+
+    @Use(REG) AllocatableValue handlerInCallerPc;
+    @Use(REG) AllocatableValue exception;
+    @Use(REG) AllocatableValue exceptionPc;
+    private final Register thread;
+    private final int isMethodHandleReturnOffset;
+
+    AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) {
+        super(TYPE);
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+        this.isMethodHandleReturnOffset = isMethodHandleReturnOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(crb, masm);
+
+        // Discard the return address, thus completing restoration of caller frame
+        masm.incrementq(rsp, 8);
+
+        if (System.getProperty("java.specification.version").compareTo("1.8") < 0) {
+            // Restore rsp from rbp if the exception PC is a method handle call site.
+            AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset);
+            masm.cmpl(dst, 0);
+            masm.cmovq(ConditionFlag.NotEqual, rsp, rbp);
+        }
+
+        masm.jmp(asRegister(handlerInCallerPc));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java
new file mode 100644
index 0000000..850faa1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
+import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
+import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.NoOp;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
+import org.graalvm.compiler.lir.amd64.AMD64CCall;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder;
+import org.graalvm.compiler.lir.amd64.AMD64Move;
+import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp;
+import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp;
+import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounter;
+import org.graalvm.compiler.lir.amd64.AMD64RestoreRegistersOp;
+import org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp;
+import org.graalvm.compiler.lir.amd64.AMD64VZeroUpper;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * LIR generator specialized for AMD64 HotSpot.
+ */
+public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
+
+    final GraalHotSpotVMConfig config;
+    private HotSpotDebugInfoBuilder debugInfoBuilder;
+
+    protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
+        this(providers, config, lirGenRes, new BackupSlotProvider(lirGenRes.getFrameMapBuilder()));
+    }
+
+    private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
+        this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
+    }
+
+    protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
+                    LIRGenerationResult lirGenRes) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
+        assert config.basicLockSize == 8;
+        this.config = config;
+    }
+
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    /**
+     * Utility for emitting the instruction to save RBP.
+     */
+    class SaveRbp {
+
+        final NoOp placeholder;
+
+        /**
+         * The slot reserved for saving RBP.
+         */
+        final StackSlot reservedSlot;
+
+        SaveRbp(NoOp placeholder) {
+            this.placeholder = placeholder;
+            AMD64FrameMapBuilder frameMapBuilder = (AMD64FrameMapBuilder) getResult().getFrameMapBuilder();
+            this.reservedSlot = frameMapBuilder.allocateRBPSpillSlot();
+        }
+
+        /**
+         * Replaces this operation with the appropriate move for saving rbp.
+         *
+         * @param useStack specifies if rbp must be saved to the stack
+         */
+        public AllocatableValue finalize(boolean useStack) {
+            AllocatableValue dst;
+            if (useStack) {
+                dst = reservedSlot;
+            } else {
+                ((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).freeRBPSpillSlot();
+                dst = newVariable(LIRKind.value(AMD64Kind.QWORD));
+            }
+
+            placeholder.replace(getResult().getLIR(), new MoveFromRegOp(AMD64Kind.QWORD, dst, rbp.asValue(LIRKind.value(AMD64Kind.QWORD))));
+            return dst;
+        }
+    }
+
+    private SaveRbp saveRbp;
+
+    protected void emitSaveRbp() {
+        NoOp placeholder = new NoOp(getCurrentBlock(), getResult().getLIR().getLIRforBlock(getCurrentBlock()).size());
+        append(placeholder);
+        saveRbp = new SaveRbp(placeholder);
+    }
+
+    protected SaveRbp getSaveRbp() {
+        return saveRbp;
+    }
+
+    /**
+     * Helper instruction to reserve a stack slot for the whole method. Note that the actual users
+     * of the stack slot might be inserted after stack slot allocation. This dummy instruction
+     * ensures that the stack slot is alive and gets a real stack slot assigned.
+     */
+    private static final class RescueSlotDummyOp extends LIRInstruction {
+        public static final LIRInstructionClass<RescueSlotDummyOp> TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class);
+
+        @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue slot;
+
+        RescueSlotDummyOp(FrameMapBuilder frameMapBuilder, LIRKind kind) {
+            super(TYPE);
+            slot = frameMapBuilder.allocateSpillSlot(kind);
+        }
+
+        public AllocatableValue getSlot() {
+            return slot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+        }
+    }
+
+    private RescueSlotDummyOp rescueSlotOp;
+
+    private AllocatableValue getOrInitRescueSlot() {
+        RescueSlotDummyOp op = getOrInitRescueSlotOp();
+        return op.getSlot();
+    }
+
+    private RescueSlotDummyOp getOrInitRescueSlotOp() {
+        if (rescueSlotOp == null) {
+            // create dummy instruction to keep the rescue slot alive
+            rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind());
+        }
+        return rescueSlotOp;
+    }
+
+    /**
+     * List of epilogue operations that need to restore RBP.
+     */
+    List<AMD64HotSpotRestoreRbpOp> epilogueOps = new ArrayList<>(2);
+
+    @Override
+    public <I extends LIRInstruction> I append(I op) {
+        I ret = super.append(op);
+        if (op instanceof AMD64HotSpotRestoreRbpOp) {
+            epilogueOps.add((AMD64HotSpotRestoreRbpOp) op);
+        }
+        return ret;
+    }
+
+    @Override
+    public VirtualStackSlot getLockSlot(int lockDepth) {
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
+        return debugInfoBuilder.lockStack();
+    }
+
+    private Register findPollOnReturnScratchRegister() {
+        RegisterConfig regConfig = getProviders().getCodeCache().getRegisterConfig();
+        for (Register r : regConfig.getAllocatableRegisters()) {
+            if (!r.equals(regConfig.getReturnRegister(JavaKind.Long)) && !r.equals(AMD64.rbp)) {
+                return r;
+            }
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    private Register pollOnReturnScratchRegister;
+
+    @Override
+    public void emitReturn(JavaKind kind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(kind, input.getValueKind());
+            emitMove(operand, input);
+        }
+        if (pollOnReturnScratchRegister == null) {
+            pollOnReturnScratchRegister = findPollOnReturnScratchRegister();
+        }
+        append(new AMD64HotSpotReturnOp(operand, getStub() != null, pollOnReturnScratchRegister, config));
+    }
+
+    @Override
+    public boolean needOnlyOopMaps() {
+        // Stubs only need oop maps
+        return getResult().getStub() != null;
+    }
+
+    private LIRFrameState currentRuntimeCallInfo;
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        currentRuntimeCallInfo = info;
+        HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage;
+        AMD64 arch = (AMD64) target().arch;
+        if (arch.getFeatures().contains(AMD64.CPUFeature.AVX) && hsLinkage.mayContainFP() && !hsLinkage.isCompiledStub()) {
+            /*
+             * If the target may contain FP ops, and it is not compiled by us, we may have an
+             * AVX-SSE transition.
+             *
+             * We exclude the argument registers from the zeroing LIR instruction since it violates
+             * the LIR semantics of @Temp that values must not be live. Note that the emitted
+             * machine instruction actually zeros _all_ XMM registers which is fine since we know
+             * that their upper half is not used.
+             */
+            append(new AMD64VZeroUpper(arguments));
+        }
+        super.emitForeignCallOp(linkage, result, arguments, temps, info);
+    }
+
+    @Override
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp));
+    }
+
+    @Override
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        Variable frameSizeVariable = load(frameSize);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable));
+    }
+
+    @Override
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable senderFpVariable = load(senderFp);
+        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
+                        senderSpVariable, senderFpVariable, saveRegisterOp));
+    }
+
+    @Override
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp));
+    }
+
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
+    }
+
+    /**
+     * Allocate a stack slot for saving a register.
+     */
+    protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
+        PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
+        if (kind.getVectorLength() > 1) {
+            // we don't use vector registers, so there is no need to save them
+            kind = AMD64Kind.DOUBLE;
+        }
+        return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
+    }
+
+    /**
+     * Adds a node to the graph that saves all allocatable registers to the stack.
+     *
+     * @param supportsRemove determines if registers can be pruned
+     * @return the register save node
+     */
+    private AMD64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
+        AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
+    }
+
+    @Override
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // We are saving all registers.
+        // TODO Save upper half of YMM registers.
+        return emitSaveAllRegisters(target().arch.getAvailableValueRegisters().toArray(), false);
+    }
+
+    protected void emitRestoreRegisters(AMD64SaveRegistersOp save) {
+        append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
+    }
+
+    /**
+     * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
+     * being generated.
+     */
+    public Stub getStub() {
+        return getResult().getStub();
+    }
+
+    @Override
+    public HotSpotLIRGenerationResult getResult() {
+        return ((HotSpotLIRGenerationResult) super.getResult());
+    }
+
+    public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
+        this.debugInfoBuilder = debugInfoBuilder;
+    }
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
+        HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
+        boolean destroysRegisters = hotspotLinkage.destroysRegisters();
+
+        AMD64SaveRegistersOp save = null;
+        Stub stub = getStub();
+        if (destroysRegisters) {
+            if (stub != null && stub.preservesRegisters()) {
+                Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray();
+                save = emitSaveAllRegisters(savedRegisters, true);
+            }
+        }
+
+        Variable result;
+        LIRFrameState debugInfo = null;
+        if (hotspotLinkage.needsDebugInfo()) {
+            debugInfo = state;
+            assert debugInfo != null || stub != null;
+        }
+
+        if (hotspotLinkage.needsJavaFrameAnchor()) {
+            Register thread = getProviders().getRegisters().getThreadRegister();
+            append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+            append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread));
+        } else {
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+        }
+
+        if (destroysRegisters) {
+            if (stub != null) {
+                if (stub.preservesRegisters()) {
+                    HotSpotLIRGenerationResult generationResult = getResult();
+                    assert !generationResult.getCalleeSaveInfo().containsKey(currentRuntimeCallInfo);
+                    generationResult.getCalleeSaveInfo().put(currentRuntimeCallInfo, save);
+                    emitRestoreRegisters(save);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public Value emitLoadObjectAddress(Constant constant) {
+        HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
+        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
+        LIRKind kind = objectConstant.isCompressed() ? kindTool.getNarrowOopKind() : kindTool.getObjectKind();
+        Variable result = newVariable(kind);
+        append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
+        return result;
+    }
+
+    @Override
+    public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
+        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
+        LIRKind kind = metaspaceConstant.isCompressed() ? kindTool.getNarrowPointerKind() : kindTool.getWordKind();
+        Variable result = newVariable(kind);
+        append(new AMD64HotSpotLoadAddressOp(result, constant, action));
+        return result;
+    }
+
+    @Override
+    public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL);
+        Constant[] constants = new Constant[]{constant};
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
+        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+        return emitMove(result);
+    }
+
+    @Override
+    public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL);
+        Constant[] constants = new Constant[]{constant};
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
+        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+        return emitMove(result);
+    }
+
+    @Override
+    public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS);
+        Constant[] constants = new Constant[]{method};
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
+        Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS};
+        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+        return emitMove(result);
+
+    }
+
+    @Override
+    public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL);
+        Constant[] constants = new Constant[]{constant};
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+        Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE};
+        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+        return emitMove(result);
+    }
+
+    @Override
+    public Value emitLoadConfigValue(int markId) {
+        // Globals are always full-pointer width.
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new AMD64HotSpotLoadConfigValueOp(markId, result));
+        return result;
+    }
+
+    @Override
+    public Value emitRandomSeed() {
+        AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter();
+        append(timestamp);
+        return emitMove(timestamp.getLowResult());
+    }
+
+    @Override
+    public Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), trapRequest, mode);
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
+    @Override
+    public Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), mode);
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
+    @Override
+    public void emitTailcall(Value[] args, Value address) {
+        append(new AMD64TailcallOp(args, address));
+    }
+
+    @Override
+    public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) {
+        Value[] argLocations = new Value[args.length];
+        getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention);
+        // TODO(mg): in case a native function uses floating point varargs, the ABI requires that
+        // RAX contains the length of the varargs
+        PrimitiveConstant intConst = JavaConstant.forInt(numberOfFloatingPointArguments);
+        AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD));
+        emitMoveConstant(numberOfFloatingPointArgumentsRegister, intConst);
+        for (int i = 0; i < args.length; i++) {
+            Value arg = args[i];
+            AllocatableValue loc = nativeCallingConvention.getArgument(i);
+            emitMove(loc, arg);
+            argLocations[i] = loc;
+        }
+        Value ptr = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(address));
+        append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations));
+    }
+
+    @Override
+    public void emitUnwind(Value exception) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
+        emitMove(exceptionParameter, exception);
+        append(new AMD64HotSpotUnwindOp(exceptionParameter));
+    }
+
+    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
+        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
+        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
+    }
+
+    private void moveValueToThread(Value v, int offset) {
+        LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
+        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
+        AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset);
+        arithmeticLIRGen.emitStore(v.getValueKind(), address, v, null);
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
+        moveDeoptValuesToThread(actionAndReason, speculation);
+        append(new AMD64DeoptimizeOp(state));
+    }
+
+    @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
+        Value nullValue = emitConstant(LIRKind.reference(AMD64Kind.QWORD), JavaConstant.NULL_POINTER);
+        moveDeoptValuesToThread(actionAndReason, nullValue);
+        append(new AMD64HotSpotDeoptimizeCallerOp());
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        super.beforeRegisterAllocation();
+        boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
+        AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
+        if (hasDebugInfo) {
+            getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
+        }
+
+        getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
+
+        for (AMD64HotSpotRestoreRbpOp op : epilogueOps) {
+            op.setSavedRbp(savedRbp);
+        }
+        if (BenchmarkCounters.enabled) {
+            // ensure that the rescue slot is available
+            LIRInstruction op = getOrInitRescueSlotOp();
+            // insert dummy instruction into the start block
+            LIR lir = getResult().getLIR();
+            List<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
+            instructions.add(1, op);
+            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op");
+        }
+    }
+
+    @Override
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new AMD64HotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable, config));
+    }
+
+    @Override
+    public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == AMD64Kind.QWORD;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD));
+            append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0 || GeneratePIC.getValue()) {
+                if (GeneratePIC.getValue()) {
+                    Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
+                    AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
+                    append(move);
+                    base = baseAddress;
+                } else {
+                    base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base));
+                }
+            }
+            append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    @Override
+    public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == AMD64Kind.DWORD;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD));
+            append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0 || GeneratePIC.getValue()) {
+                if (GeneratePIC.getValue()) {
+                    Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
+                    AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
+                    append(move);
+                    base = baseAddress;
+                } else {
+                    base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base));
+                }
+            }
+            append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) {
+            CompressEncoding encoding = config.getOopEncoding();
+            Value uncompressed;
+            if (encoding.shift <= 3) {
+                LIRKind wordKind = LIRKind.unknownReference(target().arch.getWordKind());
+                uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.shift), 0);
+            } else {
+                uncompressed = emitUncompress(address, encoding, false);
+            }
+            append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
+        } else {
+            super.emitNullCheck(address, state);
+        }
+    }
+
+    @Override
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        if (BenchmarkCounters.enabled) {
+            return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot());
+        }
+        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
+    }
+
+    @Override
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        if (BenchmarkCounters.enabled) {
+            return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot());
+        }
+        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
+    }
+
+    @Override
+    public void emitPrefetchAllocate(Value address) {
+        append(new AMD64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr));
+    }
+
+    @Override
+    protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
+        return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java
new file mode 100644
index 0000000..12bda76
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+
+public class AMD64HotSpotLIRKindTool extends AMD64LIRKindTool implements HotSpotLIRKindTool {
+
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(AMD64Kind.DWORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(AMD64Kind.DWORD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java
new file mode 100644
index 0000000..43dd5b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.rdx;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Pops the current frame off the stack including the return address and restores the return
+ * registers stored on the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AMD64HotSpotLeaveCurrentStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveCurrentStackFrameOp.class);
+
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.getRegisterConfig();
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointer = registerConfig.getFrameRegister();
+
+        // Restore integer result register.
+        final int stackSlotSize = frameMap.getTarget().wordSize;
+        Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+        masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize));
+
+        // Restore float result register.
+        Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
+
+        /*
+         * All of the register save area will be popped of the stack. Only the return address
+         * remains.
+         */
+        leaveFrameAndRestoreRbp(crb, masm);
+
+        // Remove return address.
+        masm.addq(stackPointer, crb.target.arch.getReturnAddressSize());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java
new file mode 100644
index 0000000..d86979c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Pops a deoptimized stack frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AMD64HotSpotLeaveDeoptimizedStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveDeoptimizedStackFrameOp.class);
+    @Use(REG) AllocatableValue frameSize;
+    @Use(REG) AllocatableValue framePointer;
+
+    AMD64HotSpotLeaveDeoptimizedStackFrameOp(AllocatableValue frameSize, AllocatableValue initialInfo) {
+        super(TYPE);
+        this.frameSize = frameSize;
+        this.framePointer = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        Register stackPointer = crb.frameMap.getRegisterConfig().getFrameRegister();
+        masm.addq(stackPointer, asRegister(frameSize));
+
+        /*
+         * Restore the frame pointer before stack bang because if a stack overflow is thrown it
+         * needs to be pushed (and preserved).
+         */
+        masm.movq(rbp, asRegister(framePointer));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java
new file mode 100644
index 0000000..40155af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotLeaveUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveUnpackFramesStackFrameOp.class);
+
+    private final Register threadRegister;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadLastJavaFpOffset;
+
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
+        this.threadRegister = threadRegister;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.getRegisterConfig();
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+
+        // Restore stack pointer.
+        masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset));
+
+        // Clear last Java frame values.
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0);
+
+        // Restore return values.
+        final int stackSlotSize = frameMap.getTarget().wordSize;
+        Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+
+        Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadAddressOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadAddressOp.java
new file mode 100644
index 0000000..a4bd197
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadAddressOp.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AMD64HotSpotLoadAddressOp extends AMD64LIRInstruction {
+
+    public static final LIRInstructionClass<AMD64HotSpotLoadAddressOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLoadAddressOp.class);
+
+    @Def({OperandFlag.REG}) protected AllocatableValue result;
+    private final Constant constant;
+    private final Object note;
+
+    public AMD64HotSpotLoadAddressOp(AllocatableValue result, Constant constant, Object note) {
+        super(TYPE);
+        this.result = result;
+        this.constant = constant;
+        this.note = note;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        crb.recordInlineDataInCodeWithNote(constant, note);
+        AMD64Kind kind = (AMD64Kind) result.getPlatformKind();
+        switch (kind) {
+            case DWORD:
+                masm.movl(asRegister(result), masm.getPlaceholder(-1));
+                break;
+            case QWORD:
+                masm.movq(asRegister(result), masm.getPlaceholder(-1));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("unexpected kind: " + kind);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java
new file mode 100644
index 0000000..28e2c0d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AMD64HotSpotLoadConfigValueOp extends AMD64LIRInstruction {
+
+    public static final LIRInstructionClass<AMD64HotSpotLoadConfigValueOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLoadConfigValueOp.class);
+
+    @Def({OperandFlag.REG}) protected AllocatableValue result;
+    private final int markId;
+
+    public AMD64HotSpotLoadConfigValueOp(int markId, AllocatableValue result) {
+        super(TYPE);
+        this.result = result;
+        this.markId = markId;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (GeneratePIC.getValue()) {
+            masm.movq(asRegister(result), masm.getPlaceholder(-1));
+        } else {
+            throw GraalError.unimplemented();
+        }
+        crb.recordMark(markId);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java
new file mode 100644
index 0000000..36292b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_COS_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_EXP_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG10_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_SIN_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_POW_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_TAN_STUB;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.replacements.profiling.ProbabilisticProfileSnippets;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.amd64.AMD64ConvertSnippets;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
+
+    private AMD64ConvertSnippets.Templates convertSnippets;
+    private ProbabilisticProfileSnippets.Templates profileSnippets;
+
+    public AMD64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) {
+        convertSnippets = new AMD64ConvertSnippets.Templates(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
+        profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue() ? new ProbabilisticProfileSnippets.Templates(providers, providers.getCodeCache().getTarget()) : null;
+        super.initialize(providers, config);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof FloatConvertNode) {
+            convertSnippets.lower((FloatConvertNode) n, tool);
+        } else if (profileSnippets != null && n instanceof ProfileNode) {
+            profileSnippets.lower((ProfileNode) n, tool);
+        } else {
+            super.lower(n, tool);
+        }
+    }
+
+    @Override
+    protected ForeignCallDescriptor toForeignCall(UnaryOperation operation) {
+        if (GraalArithmeticStubs.getValue()) {
+            switch (operation) {
+                case LOG:
+                    return ARITHMETIC_LOG_STUB;
+                case LOG10:
+                    return ARITHMETIC_LOG10_STUB;
+                case SIN:
+                    return ARITHMETIC_SIN_STUB;
+                case COS:
+                    return ARITHMETIC_COS_STUB;
+                case TAN:
+                    return ARITHMETIC_TAN_STUB;
+                case EXP:
+                    return ARITHMETIC_EXP_STUB;
+            }
+        } else if (operation == UnaryOperation.EXP) {
+            return operation.foreignCallDescriptor;
+        }
+        // Lower only using LIRGenerator
+        return null;
+    }
+
+    @Override
+    protected ForeignCallDescriptor toForeignCall(BinaryOperation operation) {
+        if (GraalArithmeticStubs.getValue()) {
+            switch (operation) {
+                case POW:
+                    return ARITHMETIC_POW_STUB;
+            }
+        } else if (operation == BinaryOperation.POW) {
+            return operation.foreignCallDescriptor;
+        }
+        // Lower only using LIRGenerator
+        return null;
+    }
+
+    @Override
+    public boolean supportSubwordCompare(int bits) {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMathIntrinsicOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMathIntrinsicOp.java
new file mode 100644
index 0000000..67d81c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMathIntrinsicOp.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This provides the default implementation expected by some HotSpot based lowerings of Math
+ * intrinsics. Depending on the release different patterns might be used.
+ */
+public final class AMD64HotSpotMathIntrinsicOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotMathIntrinsicOp> TYPE = LIRInstructionClass.create(AMD64HotSpotMathIntrinsicOp.class);
+
+    public enum IntrinsicOpcode {
+        SIN,
+        COS,
+        TAN,
+        LOG,
+        LOG10
+    }
+
+    @Opcode private final IntrinsicOpcode opcode;
+    @Def protected Value result;
+    @Use protected Value input;
+
+    public AMD64HotSpotMathIntrinsicOp(IntrinsicOpcode opcode, Value result, Value input) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        switch (opcode) {
+            case LOG:
+                masm.flog(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), false);
+                break;
+            case LOG10:
+                masm.flog(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), true);
+                break;
+            case SIN:
+                masm.fsin(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE));
+                break;
+            case COS:
+                masm.fcos(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE));
+                break;
+            case TAN:
+                masm.ftan(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java
new file mode 100644
index 0000000..f7a5f20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.amd64.AMD64Move;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+public class AMD64HotSpotMove {
+
+    public static final class HotSpotLoadObjectConstantOp extends AMD64LIRInstruction implements LoadConstantOp {
+        public static final LIRInstructionClass<HotSpotLoadObjectConstantOp> TYPE = LIRInstructionClass.create(HotSpotLoadObjectConstantOp.class);
+
+        @Def({REG, STACK}) private AllocatableValue result;
+        private final HotSpotObjectConstant input;
+
+        public HotSpotLoadObjectConstantOp(AllocatableValue result, HotSpotObjectConstant input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (GeneratePIC.getValue()) {
+                throw GraalError.shouldNotReachHere("Object constant load should not be happening directly");
+            }
+            boolean compressed = input.isCompressed();
+            if (crb.target.inlineObjects) {
+                crb.recordInlineDataInCode(input);
+                if (isRegister(result)) {
+                    if (compressed) {
+                        masm.movl(asRegister(result), 0xDEADDEAD);
+                    } else {
+                        masm.movq(asRegister(result), 0xDEADDEADDEADDEADL);
+                    }
+                } else {
+                    assert isStackSlot(result);
+                    if (compressed) {
+                        masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD);
+                    } else {
+                        throw GraalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                    }
+                }
+            } else {
+                if (isRegister(result)) {
+                    AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(input, compressed ? 4 : 8);
+                    if (compressed) {
+                        masm.movl(asRegister(result), address);
+                    } else {
+                        masm.movq(asRegister(result), address);
+                    }
+                } else {
+                    throw GraalError.shouldNotReachHere("Cannot directly store data patch to memory");
+                }
+            }
+        }
+
+        @Override
+        public Constant getConstant() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static final class BaseMove extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BaseMove> TYPE = LIRInstructionClass.create(BaseMove.class);
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        private final GraalHotSpotVMConfig config;
+
+        public BaseMove(AllocatableValue result, GraalHotSpotVMConfig config) {
+            super(TYPE);
+            this.result = result;
+            this.config = config;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.movq(asRegister(result), masm.getPlaceholder(-1));
+            crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+        }
+
+    }
+
+    public static final class HotSpotLoadMetaspaceConstantOp extends AMD64LIRInstruction implements LoadConstantOp {
+        public static final LIRInstructionClass<HotSpotLoadMetaspaceConstantOp> TYPE = LIRInstructionClass.create(HotSpotLoadMetaspaceConstantOp.class);
+
+        @Def({REG, STACK}) private AllocatableValue result;
+        private final HotSpotMetaspaceConstant input;
+
+        public HotSpotLoadMetaspaceConstantOp(AllocatableValue result, HotSpotMetaspaceConstant input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (GeneratePIC.getValue()) {
+                throw GraalError.shouldNotReachHere("Metaspace constant load should not be happening directly");
+            }
+            boolean compressed = input.isCompressed();
+            if (isRegister(result)) {
+                if (compressed) {
+                    crb.recordInlineDataInCode(input);
+                    masm.movl(asRegister(result), 0xDEADDEAD);
+                } else {
+                    crb.recordInlineDataInCode(input);
+                    masm.movq(asRegister(result), 0xDEADDEADDEADDEADL);
+                }
+            } else {
+                assert isStackSlot(result);
+                if (compressed) {
+                    crb.recordInlineDataInCode(input);
+                    masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD);
+                } else {
+                    throw GraalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                }
+            }
+        }
+
+        @Override
+        public Constant getConstant() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static final class CompressPointer extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(AMD64Kind.QWORD, crb, masm, result, input);
+
+            Register resReg = asRegister(result);
+            if (encoding.base != 0 || GeneratePIC.getValue()) {
+                Register baseReg = asRegister(baseRegister);
+                if (!nonNull) {
+                    masm.testq(resReg, resReg);
+                    masm.cmovq(ConditionFlag.Equal, resReg, baseReg);
+                }
+                masm.subq(resReg, baseReg);
+            }
+
+            if (encoding.shift != 0) {
+                masm.shrq(resReg, encoding.shift);
+            }
+        }
+    }
+
+    public static final class UncompressPointer extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(AMD64Kind.DWORD, crb, masm, result, input);
+
+            Register resReg = asRegister(result);
+            if (encoding.shift != 0) {
+                masm.shlq(resReg, encoding.shift);
+            }
+
+            if (encoding.base != 0 || GeneratePIC.getValue()) {
+                if (nonNull) {
+                    masm.addq(resReg, asRegister(baseRegister));
+                } else {
+                    if (encoding.shift == 0) {
+                        // if encoding.shift != 0, the flags are already set by the shlq
+                        masm.testq(resReg, resReg);
+                    }
+
+                    Label done = new Label();
+                    masm.jccb(ConditionFlag.Equal, done);
+                    masm.addq(resReg, asRegister(baseRegister));
+                    masm.bind(done);
+                }
+            }
+        }
+    }
+
+    public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) {
+        masm.movl(register, address);
+        if (encoding.shift != 0) {
+            assert encoding.alignment == encoding.shift : "Decode algorithm is wrong";
+            masm.shlq(register, encoding.alignment);
+        }
+        if (encoding.base != 0) {
+            masm.movq(scratch, encoding.base);
+            masm.addq(register, scratch);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMoveFactory.java
new file mode 100644
index 0000000..893a352
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMoveFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.core.amd64.AMD64MoveFactory;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class AMD64HotSpotMoveFactory extends AMD64MoveFactory {
+
+    public AMD64HotSpotMoveFactory(BackupSlotProvider backupSlotProvider) {
+        super(backupSlotProvider);
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).isCompressed();
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        if (value instanceof HotSpotConstant) {
+            return ((HotSpotConstant) value).isCompressed();
+        }
+        return true;
+    }
+
+    @Override
+    public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
+            return super.createLoad(dst, JavaConstant.INT_0);
+        } else if (src instanceof HotSpotObjectConstant) {
+            return new AMD64HotSpotMove.HotSpotLoadObjectConstantOp(dst, (HotSpotObjectConstant) src);
+        } else if (src instanceof HotSpotMetaspaceConstant) {
+            return new AMD64HotSpotMove.HotSpotLoadMetaspaceConstantOp(dst, (HotSpotMetaspaceConstant) src);
+        } else {
+            return super.createLoad(dst, src);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java
new file mode 100644
index 0000000..24e7d67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_6;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.TargetDescription;
+
+public class AMD64HotSpotNodeCostProvider extends HotSpotNodeCostProvider {
+    private final boolean avx2;
+    private final boolean sse41;
+
+    public AMD64HotSpotNodeCostProvider(TargetDescription target) {
+        this.avx2 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX2);
+        this.sse41 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.SSE4_1);
+    }
+
+    @Override
+    public NodeCycles cycles(Node n) {
+        if (n instanceof UnaryMathIntrinsicNode) {
+            UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n;
+            switch (u.getOperation()) {
+                case LOG:
+                case LOG10:
+                    return CYCLES_15;
+                default:
+                    break;
+            }
+        } else if (n instanceof ReturnNode) {
+            return CYCLES_6;
+        } else if (n instanceof ArrayEqualsNode) {
+            if (avx2) {
+                return CYCLES_50;
+            } else if (sse41) {
+                return CYCLES_80;
+            }
+        }
+        return super.cycles(n);
+    }
+
+    @Override
+    public NodeSize size(Node n) {
+        if (n instanceof UnaryMathIntrinsicNode) {
+            UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n;
+            switch (u.getOperation()) {
+                case LOG:
+                case LOG10:
+                    return SIZE_30;
+                default:
+                    break;
+            }
+        } else if (n instanceof ReturnNode) {
+            return SIZE_4;
+        }
+        return super.size(n);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java
new file mode 100644
index 0000000..09a6d98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
+import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.gen.DebugInfoBuilder;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.amd64.AMD64BreakpointOp;
+import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * LIR generator specialized for AMD64 HotSpot.
+ */
+public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
+
+    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
+        assert gen instanceof AMD64HotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((AMD64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()));
+    }
+
+    private AMD64HotSpotLIRGenerator getGen() {
+        return (AMD64HotSpotLIRGenerator) gen;
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AMD64Kind.QWORD));
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen);
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+
+        CallingConvention incomingArguments = gen.getResult().getCallingConvention();
+
+        Value[] params = new Value[incomingArguments.getArgumentCount() + 1];
+        for (int i = 0; i < params.length - 1; i++) {
+            params[i] = incomingArguments.getArgument(i);
+            if (isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) {
+                    gen.getResult().getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+        params[params.length - 1] = rbp.asValue(LIRKind.value(AMD64Kind.QWORD));
+
+        gen.emitIncomingValues(params);
+
+        getGen().emitSaveRbp();
+
+        getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue.getValueKind() + " != " + param.stamp();
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = state(i);
+        append(new AMD64HotSpotSafepointOp(info, getGen().config, this));
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind.isIndirect()) {
+            append(new AMD64HotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        } else {
+            assert invokeKind.isDirect();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+            assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
+            append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        if (callTarget instanceof HotSpotIndirectCallTargetNode) {
+            Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod());
+            Value targetAddressSrc = operand(callTarget.computedAddress());
+            AllocatableValue metaspaceMethodDst = AMD64.rbx.asValue(metaspaceMethodSrc.getValueKind());
+            AllocatableValue targetAddressDst = AMD64.rax.asValue(targetAddressSrc.getValueKind());
+            gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc);
+            gen.emitMove(targetAddressDst, targetAddressSrc);
+            append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config));
+        } else {
+            super.emitIndirectCall(callTarget, result, parameters, temps, callState);
+        }
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new AMD64HotSpotPatchReturnAddressOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset,
+                        thread);
+        append(op);
+    }
+
+    @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitFullInfopointNode(i);
+        }
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        Value expected = gen.loadNonConst(operand(x.expectedValue()));
+        Variable newVal = gen.load(operand(x.newValue()));
+        assert expected.getValueKind().equals(newVal.getValueKind());
+
+        RegisterValue raxLocal = AMD64.rax.asValue(expected.getValueKind());
+        gen.emitMove(raxLocal, expected);
+        append(new CompareAndSwapOp((AMD64Kind) expected.getPlatformKind(), raxLocal, getGen().asAddressValue(operand(x.getAddress())), raxLocal, newVal));
+
+        setResult(x, gen.emitMove(raxLocal));
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
+                        node.arguments());
+        append(new AMD64BreakpointOp(parameters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java
new file mode 100644
index 0000000..0c04238
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotPatchReturnAddressOp> TYPE = LIRInstructionClass.create(AMD64HotSpotPatchReturnAddressOp.class);
+
+    @Use(REG) AllocatableValue address;
+
+    AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) {
+        super(TYPE);
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        int frameSize = crb.frameMap.frameSize();
+        masm.movq(new AMD64Address(rsp, frameSize), asRegister(address));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java
new file mode 100644
index 0000000..a272293
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class AMD64HotSpotPushInterpreterFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotPushInterpreterFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotPushInterpreterFrameOp.class);
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+    private final GraalHotSpotVMConfig config;
+
+    AMD64HotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo, GraalHotSpotVMConfig config) {
+        super(TYPE);
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+        final Register initialInfoRegister = asRegister(initialInfo);
+        final int wordSize = 8;
+
+        // We'll push PC and BP by hand.
+        masm.subq(frameSizeRegister, 2 * wordSize);
+
+        // Push return address.
+        masm.push(framePcRegister);
+
+        // Prolog
+        masm.push(initialInfoRegister);
+        masm.movq(initialInfoRegister, rsp);
+        masm.subq(rsp, frameSizeRegister);
+
+        // This value is corrected by layout_activation_impl.
+        masm.movptr(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameLastSpOffset * wordSize), 0);
+
+        // Make the frame walkable.
+        masm.movq(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameSenderSpOffset * wordSize), senderSpRegister);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java
new file mode 100644
index 0000000..fd08e39
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.r10;
+import static jdk.vm.ci.amd64.AMD64.r11;
+import static jdk.vm.ci.amd64.AMD64.r12;
+import static jdk.vm.ci.amd64.AMD64.r13;
+import static jdk.vm.ci.amd64.AMD64.r14;
+import static jdk.vm.ci.amd64.AMD64.r8;
+import static jdk.vm.ci.amd64.AMD64.r9;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.amd64.AMD64.rcx;
+import static jdk.vm.ci.amd64.AMD64.rdi;
+import static jdk.vm.ci.amd64.AMD64.rdx;
+import static jdk.vm.ci.amd64.AMD64.rsi;
+import static jdk.vm.ci.amd64.AMD64.xmm0;
+import static jdk.vm.ci.amd64.AMD64.xmm1;
+import static jdk.vm.ci.amd64.AMD64.xmm10;
+import static jdk.vm.ci.amd64.AMD64.xmm11;
+import static jdk.vm.ci.amd64.AMD64.xmm12;
+import static jdk.vm.ci.amd64.AMD64.xmm13;
+import static jdk.vm.ci.amd64.AMD64.xmm14;
+import static jdk.vm.ci.amd64.AMD64.xmm15;
+import static jdk.vm.ci.amd64.AMD64.xmm2;
+import static jdk.vm.ci.amd64.AMD64.xmm3;
+import static jdk.vm.ci.amd64.AMD64.xmm4;
+import static jdk.vm.ci.amd64.AMD64.xmm5;
+import static jdk.vm.ci.amd64.AMD64.xmm6;
+import static jdk.vm.ci.amd64.AMD64.xmm7;
+import static jdk.vm.ci.amd64.AMD64.xmm8;
+import static jdk.vm.ci.amd64.AMD64.xmm9;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+
+class AMD64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig {
+    /**
+     * Specify priority of register selection within phases of register allocation. Highest priority
+     * is first. A useful heuristic is to give registers a low priority when they are required by
+     * machine instructions, like EAX and EDX on I486, and choose no-save registers before
+     * save-on-call, & save-on-call before save-on-entry. Registers which participate in fixed
+     * calling sequences should come last. Registers which are used as pairs must fall on an even
+     * boundary.
+     *
+     * Adopted from x86_64.ad.
+     */
+    // @formatter:off
+    static final Register[] registerAllocationOrder = {
+        r10, r11, r8, r9, r12, rcx, rbx, rdi, rdx, rsi, rax, rbp, r13, r14, /*r15,*/ /*rsp,*/
+        xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
+        xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
+    };
+    // @formatter:on
+
+    AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) {
+        super(registerConfig);
+    }
+
+    @Override
+    protected RegisterArray initAllocatable(RegisterArray registers) {
+        BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size());
+        for (Register reg : registers) {
+            regMap.set(reg.number);
+        }
+
+        ArrayList<Register> allocatableRegisters = new ArrayList<>(registers.size());
+        for (Register reg : registerAllocationOrder) {
+            if (regMap.get(reg.number)) {
+                allocatableRegisters.add(reg);
+            }
+        }
+
+        return super.initAllocatable(new RegisterArray(allocatableRegisters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRestoreRbpOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRestoreRbpOp.java
new file mode 100644
index 0000000..7452af5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRestoreRbpOp.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public interface AMD64HotSpotRestoreRbpOp {
+
+    /**
+     * The type of location (i.e., stack or register) in which RBP is saved is not known until
+     * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR
+     * verification is successful.
+     */
+    Variable PLACEHOLDER = new Variable(LIRKind.value(AMD64Kind.QWORD), Integer.MAX_VALUE);
+
+    void setSavedRbp(AllocatableValue value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java
new file mode 100644
index 0000000..ffcdc62
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapStackArgumentSpaceBeforeInstruction;
+
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Returns from a function.
+ */
+@Opcode("RETURN")
+final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueBlockEndOp implements ZapStackArgumentSpaceBeforeInstruction {
+
+    public static final LIRInstructionClass<AMD64HotSpotReturnOp> TYPE = LIRInstructionClass.create(AMD64HotSpotReturnOp.class);
+    @Use({REG, ILLEGAL}) protected Value value;
+    private final boolean isStub;
+    private final Register scratchForSafepointOnReturn;
+    private final GraalHotSpotVMConfig config;
+
+    AMD64HotSpotReturnOp(Value value, boolean isStub, Register scratchForSafepointOnReturn, GraalHotSpotVMConfig config) {
+        super(TYPE);
+        this.value = value;
+        this.isStub = isStub;
+        this.scratchForSafepointOnReturn = scratchForSafepointOnReturn;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(crb, masm);
+        if (!isStub) {
+            // Every non-stub compile method must have a poll before the return.
+            AMD64HotSpotSafepointOp.emitCode(crb, masm, config, true, null, scratchForSafepointOnReturn);
+
+            /*
+             * We potentially return to the interpreter, and that's an AVX-SSE transition. The only
+             * live value at this point should be the return value in either rax, or in xmm0 with
+             * the upper half of the register unused, so we don't destroy any value here.
+             */
+            if (masm.supports(CPUFeature.AVX)) {
+                masm.vzeroupper();
+            }
+        }
+        masm.ret(0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java
new file mode 100644
index 0000000..1032118
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.asm.NumUtil.isInt;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rip;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public final class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotSafepointOp> TYPE = LIRInstructionClass.create(AMD64HotSpotSafepointOp.class);
+
+    @State protected LIRFrameState state;
+    @Temp({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue temp;
+
+    private final GraalHotSpotVMConfig config;
+
+    public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, NodeLIRBuilderTool tool) {
+        super(TYPE);
+        this.state = state;
+        this.config = config;
+        if (isPollingPageFar(config) || ImmutableCode.getValue()) {
+            temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind()));
+        } else {
+            // Don't waste a register if it's unneeded
+            temp = Value.ILLEGAL;
+        }
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        emitCode(crb, asm, config, false, state, temp instanceof RegisterValue ? ((RegisterValue) temp).getRegister() : null);
+    }
+
+    /**
+     * Tests if the polling page address can be reached from the code cache with 32-bit
+     * displacements.
+     */
+    private static boolean isPollingPageFar(GraalHotSpotVMConfig config) {
+        final long pollingPageAddress = config.safepointPollingAddress;
+        return config.forceUnreachable || !isInt(pollingPageAddress - config.codeCacheLowBound) || !isInt(pollingPageAddress - config.codeCacheHighBound);
+    }
+
+    public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
+        assert !atReturn || state == null : "state is unneeded at return";
+        if (ImmutableCode.getValue()) {
+            JavaKind hostWordKind = JavaKind.Long;
+            int alignment = hostWordKind.getBitCount() / Byte.SIZE;
+            JavaConstant pollingPageAddress = JavaConstant.forIntegerKind(hostWordKind, config.safepointPollingAddress);
+            // This move will be patched to load the safepoint page from a data segment
+            // co-located with the immutable code.
+            if (GeneratePIC.getValue()) {
+                asm.movq(scratch, asm.getPlaceholder(-1));
+            } else {
+                asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment));
+            }
+            final int pos = asm.position();
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            asm.testl(rax, new AMD64Address(scratch));
+        } else if (isPollingPageFar(config)) {
+            asm.movq(scratch, config.safepointPollingAddress);
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+            final int pos = asm.position();
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            asm.testl(rax, new AMD64Address(scratch));
+        } else {
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR);
+            final int pos = asm.position();
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            // The C++ code transforms the polling page offset into an RIP displacement
+            // to the real address at that offset in the polling page.
+            asm.testl(rax, new AMD64Address(rip, 0));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotStrategySwitchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotStrategySwitchOp.java
new file mode 100644
index 0000000..08f441f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotStrategySwitchOp.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+final class AMD64HotSpotStrategySwitchOp extends AMD64ControlFlow.StrategySwitchOp {
+    public static final LIRInstructionClass<AMD64HotSpotStrategySwitchOp> TYPE = LIRInstructionClass.create(AMD64HotSpotStrategySwitchOp.class);
+
+    AMD64HotSpotStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+        super(TYPE, strategy, keyTargets, defaultTarget, key, scratch);
+    }
+
+    @Override
+    public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) {
+        strategy.run(new HotSpotSwitchClosure(ValueUtil.asRegister(key), crb, masm));
+    }
+
+    public class HotSpotSwitchClosure extends SwitchClosure {
+
+        protected HotSpotSwitchClosure(Register keyRegister, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            super(keyRegister, crb, masm);
+        }
+
+        @Override
+        protected void emitComparison(Constant c) {
+            if (c instanceof HotSpotMetaspaceConstant) {
+                HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c;
+                if (meta.isCompressed()) {
+                    crb.recordInlineDataInCode(meta);
+                    masm.cmpl(keyRegister, 0xDEADDEAD);
+                } else {
+                    AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(meta, 8);
+                    masm.cmpq(keyRegister, addr);
+                }
+            } else {
+                super.emitComparison(c);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesProvider.java
new file mode 100644
index 0000000..431d90c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSuitesProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.core.amd64.AMD64SuitesProvider;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.hotspot.lir.HotSpotZapRegistersPhase;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+
+public class AMD64HotSpotSuitesProvider extends AMD64SuitesProvider {
+
+    public AMD64HotSpotSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+    @Override
+    public LIRSuites createLIRSuites() {
+        LIRSuites lirSuites = super.createLIRSuites();
+        if (GraalOptions.DetailedAsserts.getValue()) {
+            lirSuites.getPostAllocationOptimizationStage().appendPhase(new HotSpotZapRegistersPhase());
+        }
+        return lirSuites;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java
new file mode 100644
index 0000000..eb52694
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+
+/**
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
+ */
+@Opcode("UNWIND")
+final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueBlockEndOp {
+    public static final LIRInstructionClass<AMD64HotSpotUnwindOp> TYPE = LIRInstructionClass.create(AMD64HotSpotUnwindOp.class);
+
+    @Use({REG}) protected RegisterValue exception;
+
+    AMD64HotSpotUnwindOp(RegisterValue exception) {
+        super(TYPE);
+        this.exception = exception;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(crb, masm);
+
+        ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getOutgoingCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is on top of stack after leave).
+        Register returnAddress = asRegister(cc.getArgument(1));
+        masm.movq(returnAddress, new AMD64Address(rsp, 0));
+
+        AMD64Call.directJmp(crb, masm, linkage);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java
new file mode 100644
index 0000000..c29de93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64Call.DirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class AMD64HotspotDirectVirtualCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<AMD64HotspotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(AMD64HotspotDirectVirtualCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    AMD64HotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        this.invokeKind = invokeKind;
+        this.config = config;
+        assert invokeKind.isIndirect();
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
+        // This must be emitted exactly like this to ensure it's patchable
+        masm.movq(AMD64.rax, config.nonOopBits);
+        super.emitCode(crb, masm);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java
new file mode 100644
index 0000000..f0f1813
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.amd64.AMD64Call.IndirectCallOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A register indirect call that complies with the extra conventions for such calls in HotSpot. In
+ * particular, the metaspace Method of the callee must be in RBX for the case where a vtable entry's
+ * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to
+ * be in RBX.
+ */
+@Opcode("CALL_INDIRECT")
+final class AMD64IndirectCallOp extends IndirectCallOp {
+    public static final LIRInstructionClass<AMD64IndirectCallOp> TYPE = LIRInstructionClass.create(AMD64IndirectCallOp.class);
+
+    /**
+     * Vtable stubs expect the metaspace Method in RBX.
+     */
+    public static final Register METHOD = AMD64.rbx;
+
+    @Use({REG}) protected Value metaspaceMethod;
+
+    private final GraalHotSpotVMConfig config;
+
+    AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state,
+                    GraalHotSpotVMConfig config) {
+        super(TYPE, targetMethod, result, parameters, temps, targetAddress, state);
+        this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
+        Register callReg = asRegister(targetAddress);
+        assert !callReg.equals(METHOD);
+        AMD64Call.indirectCall(crb, masm, callReg, callTarget, state);
+    }
+
+    @Override
+    public void verify() {
+        super.verify();
+        assert asRegister(metaspaceMethod).equals(METHOD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64MathStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64MathStub.java
new file mode 100644
index 0000000..15956d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64MathStub.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_COS_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_EXP_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG10_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_LOG_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_POW_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_SIN_STUB;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotForeignCallsProvider.ARITHMETIC_TAN_STUB;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.SnippetStub;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+/**
+ * Stub called to support {@link Math}.
+ */
+public class AMD64MathStub extends SnippetStub {
+
+    public AMD64MathStub(ForeignCallDescriptor descriptor, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super(snippetName(descriptor), providers, linkage);
+    }
+
+    private static String snippetName(ForeignCallDescriptor descriptor) {
+        if (descriptor == ARITHMETIC_LOG_STUB) {
+            return "log";
+        }
+        if (descriptor == ARITHMETIC_LOG10_STUB) {
+            return "log10";
+        }
+        if (descriptor == ARITHMETIC_SIN_STUB) {
+            return "sin";
+        }
+        if (descriptor == ARITHMETIC_COS_STUB) {
+            return "cos";
+        }
+        if (descriptor == ARITHMETIC_TAN_STUB) {
+            return "tan";
+        }
+        if (descriptor == ARITHMETIC_EXP_STUB) {
+            return "exp";
+        }
+        if (descriptor == ARITHMETIC_POW_STUB) {
+            return "pow";
+        }
+        throw new InternalError("Unknown operation " + descriptor);
+    }
+
+    @Snippet
+    private static double log(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.LOG);
+    }
+
+    @Snippet
+    private static double log10(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.LOG10);
+    }
+
+    @Snippet
+    private static double sin(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.SIN);
+    }
+
+    @Snippet
+    private static double cos(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.COS);
+    }
+
+    @Snippet
+    private static double tan(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.TAN);
+    }
+
+    @Snippet
+    private static double exp(double value) {
+        return UnaryMathIntrinsicNode.compute(value, UnaryOperation.EXP);
+    }
+
+    @Snippet
+    private static double pow(double value1, double value2) {
+        return BinaryMathIntrinsicNode.compute(value1, value2, BinaryOperation.POW);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java
new file mode 100644
index 0000000..2391ec6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
+import org.graalvm.compiler.core.common.type.RawPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_20)
+public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
+
+    protected final JavaConstant functionPointer;
+    @Input NodeInputList<ValueNode> args;
+
+    public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
+        super(TYPE, StampFactory.forKind(returnType));
+        this.functionPointer = functionPointer;
+        this.args = new NodeInputList<>(this, args);
+    }
+
+    private static class PointerType implements JavaType {
+
+        @Override
+        public String getName() {
+            return "void*";
+        }
+
+        @Override
+        public JavaType getComponentType() {
+            return null;
+        }
+
+        @Override
+        public JavaType getArrayClass() {
+            return null;
+        }
+
+        @Override
+        public JavaKind getJavaKind() {
+            // native pointers and java objects use the same registers in the calling convention
+            return JavaKind.Object;
+        }
+
+        @Override
+        public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
+            return null;
+        }
+    }
+
+    private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
+        if (stamp instanceof RawPointerStamp) {
+            return new PointerType();
+        } else {
+            return stamp.javaType(metaAccess);
+        }
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
+        Value[] parameter = new Value[args.count()];
+        JavaType[] parameterTypes = new JavaType[args.count()];
+        for (int i = 0; i < args.count(); i++) {
+            parameter[i] = generator.operand(args.get(i));
+            parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
+        }
+        JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
+        CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
+                        generator.getLIRGeneratorTool());
+        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+        if (this.getStackKind() != JavaKind.Void) {
+            generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
+        }
+    }
+
+    private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
+        int count = 0;
+        for (ValueNode n : args) {
+            if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) {
+                count++;
+            }
+        }
+        if (count > 8) {
+            return 8;
+        }
+        return count;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64TailcallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64TailcallOp.java
new file mode 100644
index 0000000..9e859da
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64TailcallOp.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Performs a hard-coded tail call to the specified target, which normally should be an
+ * {@link InstalledCode} instance.
+ */
+@Opcode("TAILCALL")
+public final class AMD64TailcallOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64TailcallOp> TYPE = LIRInstructionClass.create(AMD64TailcallOp.class);
+
+    @Use protected Value target;
+    @Alive protected Value[] parameters;
+
+    public AMD64TailcallOp(Value[] parameters, Value target) {
+        super(TYPE);
+        this.target = target;
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // destroy the current frame (now the return address is the top of stack)
+        masm.leave();
+
+        // jump to the target method
+        masm.jmp(asRegister(target));
+        masm.ensureUniquePC();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64UncommonTrapStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64UncommonTrapStub.java
new file mode 100644
index 0000000..a4ca9d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64UncommonTrapStub.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.r10;
+import static jdk.vm.ci.amd64.AMD64.r11;
+import static jdk.vm.ci.amd64.AMD64.r13;
+import static jdk.vm.ci.amd64.AMD64.r14;
+import static jdk.vm.ci.amd64.AMD64.r8;
+import static jdk.vm.ci.amd64.AMD64.r9;
+import static jdk.vm.ci.amd64.AMD64.rbx;
+import static jdk.vm.ci.amd64.AMD64.rcx;
+import static jdk.vm.ci.amd64.AMD64.rdi;
+import static jdk.vm.ci.amd64.AMD64.rdx;
+import static jdk.vm.ci.amd64.AMD64.rsi;
+
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub;
+
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.amd64.AMD64HotSpotRegisterConfig;
+
+final class AMD64UncommonTrapStub extends UncommonTrapStub {
+
+    private RegisterConfig registerConfig;
+
+    AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        RegisterArray allocatable = new RegisterArray(rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14);
+        registerConfig = new AMD64HotSpotRegisterConfig(target, allocatable, config.windowsOs);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/ExceedMaxOopMapStackOffset.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/ExceedMaxOopMapStackOffset.java
new file mode 100644
index 0000000..2a93a64
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/ExceedMaxOopMapStackOffset.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.lir.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ExceedMaxOopMapStackOffset extends LIRTest {
+
+    /**
+     * Allocate lots of stacks slots and initialize them with a constant.
+     */
+    private static class WriteStackSlotsSpec extends LIRTestSpecification {
+        private final JavaConstant constant;
+
+        WriteStackSlotsSpec(JavaConstant constant) {
+            this.constant = constant;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            LIRKind lirKind = LIRKind.reference(gen.target().arch.getPlatformKind(constant.getJavaKind()));
+            // create slots
+            for (int i = 0; i < slots.length; i++) {
+                AllocatableValue src = gen.emitLoadConstant(lirKind, constant);
+                slots[i] = frameMapBuilder.allocateSpillSlot(lirKind);
+                gen.emitMove(slots[i], src);
+            }
+        }
+    }
+
+    /**
+     * Read stacks slots and move their content into a blackhole.
+     */
+    private static class ReadStackSlotsSpec extends LIRTestSpecification {
+
+        ReadStackSlotsSpec() {
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            for (int i = 0; i < slots.length; i++) {
+                gen.emitBlackhole(gen.emitMove(slots[i]));
+            }
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugin safepointPlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new SafepointNode());
+                return true;
+            }
+        };
+        conf.getPlugins().getInvocationPlugins().register(safepointPlugin, getClass(), "safepoint");
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    /*
+     * Safepoint Snippet
+     */
+    private static void safepoint() {
+    }
+
+    private static AllocatableValue[] slots;
+
+    private static final LIRTestSpecification readStackObjects = new ReadStackSlotsSpec();
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static void instrinsic(LIRTestSpecification spec) {
+    }
+
+    private static final LIRTestSpecification writeStackObjects = new WriteStackSlotsSpec(JavaConstant.NULL_POINTER);
+
+    public void testStackObjects() {
+        instrinsic(writeStackObjects);
+        safepoint();
+        instrinsic(readStackObjects);
+    }
+
+    @Test
+    public void runStackObjects() throws Throwable {
+        int max = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().maxOopMapStackOffset;
+        if (max == Integer.MAX_VALUE) {
+            max = 16 * 1024 - 64;
+        }
+        try {
+            int numSlots = (max / 8) + 1;
+            slots = new AllocatableValue[numSlots];
+            runTest("testStackObjects");
+        } catch (BailoutException e) {
+            return;
+        }
+        fail("Expected exception BailoutException wasn't thrown");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizationStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizationStub.java
new file mode 100644
index 0000000..eb8e69b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizationStub.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.g1;
+import static jdk.vm.ci.sparc.SPARC.g3;
+import static jdk.vm.ci.sparc.SPARC.g4;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub;
+
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.sparc.SPARCHotSpotRegisterConfig;
+
+final class SPARCDeoptimizationStub extends DeoptimizationStub {
+
+    private RegisterConfig registerConfig;
+
+    SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        // This is basically the maximum we can spare. All other G and O register are used.
+        RegisterArray allocatable = new RegisterArray(g1, g3, g4, g5, o0, o1, o2, o3, o4);
+        registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java
new file mode 100644
index 0000000..135fbbd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.sparc.SPARC;
+
+@Opcode("DEOPT")
+final class SPARCDeoptimizeOp extends SPARCBlockEndOp {
+    public static final LIRInstructionClass<SPARCDeoptimizeOp> TYPE = LIRInstructionClass.create(SPARCDeoptimizeOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+    @Temp AllocatableValue pcRegister;
+    @State private LIRFrameState info;
+
+    SPARCDeoptimizeOp(LIRFrameState info, PlatformKind wordKind) {
+        super(TYPE, SIZE);
+        this.info = info;
+        pcRegister = SPARC.o7.asValue(LIRKind.value(wordKind));
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // TODO the patched call address looks odd (and is invalid) compared to other runtime calls:
+        // 0xffffffff749bb5fc: call 0xffffffff415a720c ; {runtime_call}
+        // [Exception Handler]
+        // 0xffffffff749bb604: call 0xffffffff749bb220 ; {runtime_call}
+        // 0xffffffff749bb608: nop
+        // [Deopt Handler Code]
+        // 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call}
+        // 0xffffffff749bb610: nop
+        SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java
new file mode 100644
index 0000000..abe2d0b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
+import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i7;
+import static jdk.vm.ci.sparc.SPARC.l0;
+import static jdk.vm.ci.sparc.SPARC.l7;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o7;
+import static jdk.vm.ci.sparc.SPARC.sp;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DataSection;
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.asm.DataBuilder;
+import org.graalvm.compiler.lir.asm.FrameContext;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
+import org.graalvm.compiler.lir.sparc.SPARCFrameMap;
+import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate;
+import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * HotSpot SPARC specific backend.
+ */
+public class SPARCHotSpotBackend extends HotSpotHostBackend {
+
+    private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE");
+    private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL");
+
+    public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(config, runtime, providers);
+    }
+
+    private static class SizeEstimateStatistics {
+        private static final ConcurrentHashMap<String, DebugCounter> counters = new ConcurrentHashMap<>();
+        private final String suffix;
+
+        SizeEstimateStatistics(String suffix) {
+            super();
+            this.suffix = suffix;
+        }
+
+        public void add(Class<?> c, int count) {
+            String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix;
+            DebugCounter m = counters.computeIfAbsent(name, (n) -> Debug.counter(n));
+            m.add(count);
+        }
+    }
+
+    @Override
+    public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+    }
+
+    @Override
+    public FrameMap newFrameMap(RegisterConfig registerConfig) {
+        return new SPARCFrameMap(getCodeCache(), registerConfig, this);
+    }
+
+    @Override
+    public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
+        return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) {
+        return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+        return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen));
+    }
+
+    @Override
+    protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
+        // Use SPARCAddress to get the final displacement including the stack bias.
+        SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+        SPARCAddress address = new SPARCAddress(sp, -bangOffset);
+        if (SPARCAssembler.isSimm13(address.getDisplacement())) {
+            masm.stx(g0, address);
+        } else {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch;
+                masm.setx(address.getDisplacement(), scratch, false);
+                masm.stx(g0, new SPARCAddress(sp, scratch));
+            }
+        }
+    }
+
+    public class HotSpotFrameContext implements FrameContext {
+
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
+        @Override
+        public boolean hasFrame() {
+            return true;
+        }
+
+        @Override
+        public void enter(CompilationResultBuilder crb) {
+            final int frameSize = crb.frameMap.totalFrameSize();
+            final int stackpoinerChange = -frameSize;
+            SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+            emitStackOverflowCheck(crb);
+
+            if (SPARCAssembler.isSimm13(stackpoinerChange)) {
+                masm.save(sp, stackpoinerChange, sp);
+            } else {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch;
+                    masm.setx(stackpoinerChange, scratch, false);
+                    masm.save(sp, scratch, sp);
+                }
+            }
+
+            if (ZapStackOnMethodEntry.getValue()) {
+                final int slotSize = 8;
+                for (int i = 0; i < frameSize / slotSize; ++i) {
+                    // 0xC1C1C1C1
+                    masm.stx(g0, new SPARCAddress(sp, i * slotSize));
+                }
+            }
+        }
+
+        @Override
+        public void leave(CompilationResultBuilder crb) {
+            SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+            masm.restoreWindow();
+        }
+    }
+
+    @Override
+    protected Assembler createAssembler(FrameMap frameMap) {
+        return new SPARCMacroAssembler(getTarget());
+    }
+
+    @Override
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes;
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+
+        Stub stub = gen.getStub();
+        Assembler masm = createAssembler(frameMap);
+        // On SPARC we always use stack frames.
+        HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
+        DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
+        CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult);
+        crb.setTotalFrameSize(frameMap.totalFrameSize());
+        crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+        if (deoptimizationRescueSlot != null && stub == null) {
+            crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
+        }
+
+        if (stub != null) {
+            // Even on sparc we need to save floating point registers
+            Set<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
+            Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo();
+            updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap);
+        }
+        assert registerSizePredictionValidator(crb);
+        return crb;
+    }
+
+    /**
+     * Registers a verifier which checks if the LIRInstructions estimate of constants size is
+     * greater or equal to the actual one.
+     */
+    private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb) {
+        /**
+         * Used to hold state between beforeOp and afterOp
+         */
+        class ValidationState {
+            LIRInstruction op;
+            int constantSizeBefore;
+
+            public void before(LIRInstruction before) {
+                assert op == null : "LIRInstruction " + op + " no after call received";
+                op = before;
+                constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection());
+            }
+
+            public void after(LIRInstruction after) {
+                assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after;
+                int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection());
+                int actual = constantSizeAfter - constantSizeBefore;
+                if (op instanceof SPARCLIRInstructionMixin) {
+                    org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize();
+                    assert size != null : "No size prediction available for op: " + op;
+                    Class<?> c = op.getClass();
+                    CONSTANT_ESTIMATED_STATS.add(c, size.constantSize);
+                    CONSTANT_ACTUAL_STATS.add(c, actual);
+                    assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual;
+                } else {
+                    assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate.";
+                }
+                op = null;
+                constantSizeBefore = 0;
+            }
+        }
+        final ValidationState state = new ValidationState();
+        crb.setOpCallback(op -> state.before(op), op -> state.after(op));
+        return true;
+    }
+
+    private static int calculateDataSectionSize(DataSection ds) {
+        int sum = 0;
+        for (Data d : ds) {
+            sum += d.getSize();
+        }
+        return sum;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+        SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+        // TODO: (sa) Fold the two traversals into one
+        stuffDelayedControlTransfers(lir);
+        int constantSize = calculateConstantSize(lir);
+        boolean canUseImmediateConstantLoad = constantSize < (1 << 13);
+        masm.setImmediateConstantLoad(canUseImmediateConstantLoad);
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig regConfig = frameMap.getRegisterConfig();
+        Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
+        for (int i = 0; i < 2; i++) {
+            if (i > 0) {
+                crb.resetForEmittingCode();
+                lir.resetLabels();
+                resetDelayedControlTransfers(lir);
+            }
+
+            // Emit the prefix
+            if (unverifiedStub != null) {
+                crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+                // We need to use JavaCall here because we haven't entered the frame yet.
+                CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this);
+                Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
+
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    Register receiver = asRegister(cc.getArgument(0));
+                    SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
+
+                    masm.ldx(src, scratch);
+                    masm.cmp(scratch, inlineCacheKlass);
+                }
+                BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub);
+                masm.nop();  // delay slot
+            }
+
+            masm.align(config.codeEntryAlignment);
+            crb.recordMark(config.MARKID_OSR_ENTRY);
+            crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+
+            // Emit code for the LIR
+            crb.emit(lir);
+        }
+        profileInstructions(lir, crb);
+
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+        HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
+        if (!frameContext.isStub) {
+            crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
+            crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+        }
+
+        if (unverifiedStub != null) {
+            masm.bind(unverifiedStub);
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
+            }
+        }
+        masm.peephole();
+    }
+
+    private static int calculateConstantSize(LIR lir) {
+        int size = 0;
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                if (inst instanceof SPARCLIRInstructionMixin) {
+                    SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize();
+                    if (pred != null) {
+                        size += pred.constantSize;
+                    }
+                }
+            }
+        }
+        return size;
+    }
+
+    private static void resetDelayedControlTransfers(LIR lir) {
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                if (inst instanceof SPARCDelayedControlTransfer) {
+                    ((SPARCDelayedControlTransfer) inst).resetState();
+                }
+            }
+        }
+    }
+
+    /**
+     * Fix-up over whole LIR.
+     *
+     * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase)
+     * @param l
+     */
+    private static void stuffDelayedControlTransfers(LIR l) {
+        for (AbstractBlockBase<?> b : l.codeEmittingOrder()) {
+            if (b != null) {
+                stuffDelayedControlTransfers(l, b);
+            }
+        }
+    }
+
+    /**
+     * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also
+     * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if
+     * possible.
+     */
+    private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = l.getLIRforBlock(block);
+        if (instructions.size() >= 2) {
+            LIRDependencyAccumulator acc = new LIRDependencyAccumulator();
+            SPARCDelayedControlTransfer delayedTransfer = null;
+            int delayTransferPosition = -1;
+            for (int i = instructions.size() - 1; i >= 0; i--) {
+                LIRInstruction inst = instructions.get(i);
+                boolean adjacent = delayTransferPosition - i == 1;
+                if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) {
+                    delayedTransfer = null;
+                }
+                if (inst instanceof SPARCDelayedControlTransfer) {
+                    delayedTransfer = (SPARCDelayedControlTransfer) inst;
+                    acc.start(inst);
+                    delayTransferPosition = i;
+                } else if (delayedTransfer != null) {
+                    boolean overlap = acc.add(inst);
+                    if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) {
+                        // We have found a non overlapping LIR instruction which can be delayed
+                        ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer);
+                        delayedTransfer = null;
+                    }
+                }
+            }
+        }
+    }
+
+    private static boolean leavesRegisterWindow(LIRInstruction inst) {
+        return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow();
+    }
+
+    /**
+     * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and
+     * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be
+     * moved nearer to the DelayedControlTransfer instruction.
+     */
+    private static class LIRDependencyAccumulator {
+        private final Set<Object> inputs = new HashSet<>(10);
+        private boolean overlap = false;
+
+        private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> {
+            Object valueObject = value;
+            if (isRegister(value)) { // Canonicalize registers
+                valueObject = asRegister(value);
+            }
+            if (!inputs.add(valueObject)) {
+                overlap = true;
+            }
+        };
+
+        public void start(LIRInstruction initial) {
+            inputs.clear();
+            overlap = false;
+            initial.visitEachInput(valueConsumer);
+            initial.visitEachTemp(valueConsumer);
+            initial.visitEachAlive(valueConsumer);
+        }
+
+        /**
+         * Adds the inputs of lir instruction to the accumulator and returns, true if there was any
+         * overlap of parameters.
+         *
+         * @param inst
+         * @return true if an overlap was found
+         */
+        public boolean add(LIRInstruction inst) {
+            overlap = false;
+            inst.visitEachOutput(valueConsumer);
+            inst.visitEachTemp(valueConsumer);
+            inst.visitEachInput(valueConsumer);
+            inst.visitEachAlive(valueConsumer);
+            return overlap;
+        }
+    }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
+    @Override
+    public Set<Register> translateToCallerRegisters(Set<Register> calleeRegisters) {
+        HashSet<Register> callerRegisters = new HashSet<>(calleeRegisters.size());
+        for (Register register : calleeRegisters) {
+            if (l0.number <= register.number && register.number <= l7.number) {
+                // do nothing
+            } else if (o0.number <= register.number && register.number <= o7.number) {
+                // do nothing
+            } else if (i0.number <= register.number && register.number <= i7.number) {
+                // translate input to output registers
+                callerRegisters.add(translateInputToOutputRegister(register));
+            } else {
+                callerRegisters.add(register);
+            }
+        }
+        return callerRegisters;
+    }
+
+    private Register translateInputToOutputRegister(Register register) {
+        assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register;
+        return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
new file mode 100644
index 0000000..821348a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.sparc.SPARCAddressLowering;
+import org.graalvm.compiler.core.sparc.SPARCSuitesProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
+import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegisters;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.replacements.sparc.SPARCGraphBuilderPlugins;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCIBackend;
+import jdk.vm.ci.sparc.SPARC;
+
+@ServiceProvider(HotSpotBackendFactory.class)
+public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
+
+    @Override
+    public String getName() {
+        return "core";
+    }
+
+    @Override
+    public Class<? extends Architecture> getArchitecture() {
+        return SPARC.class;
+    }
+
+    @Override
+    public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) {
+        assert host == null;
+
+        GraalHotSpotVMConfig config = runtime.getVMConfig();
+        JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
+        HotSpotRegistersProvider registers = createRegisters();
+        HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess();
+        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache();
+        TargetDescription target = codeCache.getTarget();
+        HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
+        HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
+        Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
+        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+        HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
+        LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+        HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+        NodeCostProvider nodeCostProvider = new SPARCHotSpotNodeCostProvider();
+        Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
+        BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, target);
+        Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
+        replacements.setGraphBuilderPlugins(plugins);
+        HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+                        snippetReflection,
+                        wordTypes, plugins);
+
+        return createBackend(config, runtime, providers);
+    }
+
+    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess, HotSpotConstantReflectionProvider constantReflection,
+                    HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements,
+                    HotSpotWordTypes wordTypes) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        SPARCGraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider());
+        return plugins;
+    }
+
+    /**
+     * @param replacements
+     */
+    protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins,
+                    Replacements replacements) {
+        return new HotSpotSuitesProvider(new SPARCSuitesProvider(compilerConfiguration, plugins), config, runtime, new SPARCAddressLowering());
+    }
+
+    protected SPARCHotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        return new SPARCHotSpotBackend(config, runtime, providers);
+    }
+
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
+                    HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        return new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    protected HotSpotRegistersProvider createRegisters() {
+        return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp);
+    }
+
+    protected HotSpotNodeCostProvider createNodeCostProvider() {
+        return new SPARCHotSpotNodeCostProvider();
+    }
+
+    @SuppressWarnings("unused")
+    private static Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) {
+        Set<Register> callerSavedRegisters = new HashSet<>();
+        SPARC.fpusRegisters.addTo(callerSavedRegisters);
+        SPARC.fpudRegisters.addTo(callerSavedRegisters);
+        callerSavedRegisters.add(SPARC.g1);
+        callerSavedRegisters.add(SPARC.g4);
+        callerSavedRegisters.add(SPARC.g5);
+        Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.size()];
+        int i = 0;
+        for (Register reg : callerSavedRegisters) {
+            nativeABICallerSaveRegisters[i] = reg.asValue();
+            i++;
+        }
+        return nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public String toString() {
+        return "SPARC";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java
new file mode 100644
index 0000000..1852f8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+import org.graalvm.compiler.lir.sparc.SPARCMove;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+final class SPARCHotSpotCRuntimeCallEpilogueOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallEpilogueOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(11);
+
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadJavaFrameAnchorFlagsOffset;
+    private final Register thread;
+    @Use({REG, STACK}) protected Value threadTemp;
+
+    SPARCHotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset, Register thread, Value threadTemp) {
+        super(TYPE, SIZE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+        this.thread = thread;
+        this.threadTemp = threadTemp;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+
+        // Restore the thread register when coming back from the runtime.
+        SPARCMove.move(crb, masm, thread.asValue(LIRKind.value(XWORD)), threadTemp, SPARCDelayedControlTransfer.DUMMY);
+
+        // Reset last Java frame, last Java PC and flags.
+        masm.stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset));
+        masm.stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset));
+        masm.stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java
new file mode 100644
index 0000000..cbf03bb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.STACK_BIAS;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+import org.graalvm.compiler.lir.sparc.SPARCMove;
+import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+@Opcode("CRUNTIME_CALL_PROLOGUE")
+final class SPARCHotSpotCRuntimeCallPrologueOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallPrologueOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(10);
+
+    private final int threadLastJavaSpOffset;
+    private final Register thread;
+    private final Register stackPointer;
+    @Def({REG, STACK}) protected Value threadTemp;
+    @Temp({REG}) protected AllocatableValue spScratch;
+
+    SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp, AllocatableValue spScratch) {
+        super(TYPE, SIZE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.thread = thread;
+        this.stackPointer = stackPointer;
+        this.threadTemp = threadTemp;
+        this.spScratch = spScratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save last Java frame.
+        Register scratchRegister = asRegister(spScratch);
+        masm.add(stackPointer, STACK_BIAS, scratchRegister);
+        masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset));
+
+        // Save the thread register when calling out to the runtime.
+        SPARCMove.move(crb, masm, threadTemp, thread.asValue(LIRKind.value(XWORD)), getDelayedControlTransfer());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java
new file mode 100644
index 0000000..47200fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.hotspot.HotSpotCounterOp;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+@Opcode("BenchMarkCounter")
+public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
+    public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
+
+    private int[] counterPatchOffsets;
+
+    public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) {
+        super(TYPE, name, group, increment, registers, config);
+        this.counterPatchOffsets = new int[1];
+    }
+
+    public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) {
+        super(TYPE, names, groups, increments, registers, config);
+        this.counterPatchOffsets = new int[names.length];
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+        TargetDescription target = crb.target;
+
+        // address for counters array
+        SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.jvmciCountersThreadOffset);
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            Register countersArrayReg = scratch.getRegister();
+
+            // load counters array
+            masm.ldx(countersArrayAddr, countersArrayReg);
+            IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm);
+            forEachCounter(emitter, target);
+        }
+    }
+
+    private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) {
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            Register counterReg = scratch.getRegister();
+            // load counter value
+            masm.ldx(counterAddr, counterReg);
+            counterPatchOffsets[counterIndex] = masm.position();
+            // increment counter
+            if (isJavaConstant(increment)) {
+                masm.add(counterReg, asInt(asJavaConstant(increment)), counterReg);
+            } else {
+                masm.add(counterReg, asRegister(increment), counterReg);
+            }
+            // store counter value
+            masm.stx(counterReg, counterAddr);
+        }
+    }
+
+    /**
+     * Patches the increment value in the instruction emitted by the
+     * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is
+     * used if patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    @Override
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        for (int i = 0; i < increment.length; i++) {
+            int inst = counterPatchOffsets[i];
+            ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]);
+        }
+    }
+
+    public int[] getCounterPatchOffsets() {
+        return counterPatchOffsets;
+    }
+
+    private class IncrementEmitter implements CounterProcedure {
+        private int lastDisplacement = 0;
+        private final Register countersArrayReg;
+        private final SPARCMacroAssembler masm;
+
+        IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) {
+            super();
+            this.countersArrayReg = countersArrayReg;
+            this.masm = masm;
+        }
+
+        @Override
+        public void apply(int counterIndex, Value increment, int displacement) {
+            SPARCAddress counterAddr;
+            int relativeDisplacement = displacement - lastDisplacement;
+            if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction
+                counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement);
+            } else {
+                try (ScratchRegister scratch = masm.getScratchRegister()) {
+                    Register tempOffsetRegister = scratch.getRegister();
+                    masm.setx(relativeDisplacement, tempOffsetRegister, false);
+                    masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg);
+                }
+                lastDisplacement = displacement;
+                counterAddr = new SPARCAddress(countersArrayReg, 0);
+            }
+            emitIncrement(counterIndex, masm, counterAddr, increment);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java
new file mode 100644
index 0000000..d138278
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeCallerOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(32);
+
+    protected SPARCHotSpotDeoptimizeCallerOp() {
+        super(TYPE, SIZE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        leaveFrame(crb);
+
+        // SPARCHotSpotBackend backend = (SPARCHotSpotBackend)
+        // HotSpotGraalRuntime.runtime().getBackend();
+        // final boolean isStub = true;
+        // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub);
+        // frameContext.enter(crb);
+
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
+        }
+
+        // frameContext.leave(crb);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java
new file mode 100644
index 0000000..418ea88
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.STACK_BIAS;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.i2;
+import static jdk.vm.ci.sparc.SPARC.i3;
+import static jdk.vm.ci.sparc.SPARC.i4;
+import static jdk.vm.ci.sparc.SPARC.l7;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+import static jdk.vm.ci.sparc.SPARC.o5;
+import static jdk.vm.ci.sparc.SPARC.o7;
+import static jdk.vm.ci.sparc.SPARC.sp;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotEnterUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotEnterUnpackFramesStackFrameOp.class);
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Temp(REG) AllocatableValue scratch;
+    @Temp(REG) AllocatableValue callerReturnPc;
+
+    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch,
+                    PlatformKind wordKind) {
+        super(TYPE);
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.scratch = scratch;
+        callerReturnPc = o7.asValue(LIRKind.value(wordKind));
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        Register framePcRegister = asRegister(framePc);
+        Register senderSpRegister = asRegister(senderSp);
+        Register scratchRegister = asRegister(scratch);
+
+        // Save final sender SP to O5_savedSP.
+        masm.mov(senderSpRegister, o5);
+
+        // Load final frame PC.
+        masm.mov(framePcRegister, asRegister(callerReturnPc));
+
+        // Allocate a full sized frame.
+        masm.save(sp, -totalFrameSize, sp);
+
+        masm.mov(i0, o0);
+        masm.mov(i1, o1);
+        masm.mov(i2, o2);
+        masm.mov(i3, o3);
+        masm.mov(i4, o4);
+
+        // Set up last Java values.
+        masm.add(sp, STACK_BIAS, scratchRegister);
+        masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset));
+
+        // Clear last Java PC.
+        masm.stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset));
+
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        masm.mov(thread, l7);
+    }
+
+    @Override
+    public boolean leavesRegisterWindow() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java
new file mode 100644
index 0000000..6ff0c88
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp;
+
+/**
+ * Superclass for operations that leave a method's frame.
+ */
+abstract class SPARCHotSpotEpilogueOp extends SPARCBlockEndOp {
+    public static final LIRInstructionClass<SPARCHotSpotEpilogueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotEpilogueOp.class);
+
+    protected SPARCHotSpotEpilogueOp(LIRInstructionClass<? extends SPARCHotSpotEpilogueOp> c, SizeEstimate size) {
+        super(c, size);
+    }
+
+    protected void leaveFrame(CompilationResultBuilder crb) {
+        crb.frameContext.leave(crb);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java
new file mode 100644
index 0000000..58a9bbe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+import static jdk.vm.ci.meta.Value.ILLEGAL;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class SPARCHotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider {
+
+    private final Value[] nativeABICallerSaveRegisters;
+
+    public SPARCHotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
+        super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes);
+        this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers) {
+        GraalHotSpotVMConfig config = runtime.getVMConfig();
+        TargetDescription target = providers.getCodeCache().getTarget();
+        PlatformKind word = target.arch.getWordKind();
+
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        // in templateInterpreter_sparc.cpp around line 1925
+        RegisterValue outgoingException = o0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object));
+        RegisterValue outgoingExceptionPc = o1.asValue(LIRKind.value(word));
+        RegisterValue incomingException = i0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object));
+        RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word));
+        CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc);
+        CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc);
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any()));
+
+        if (PreferGraalStubs.getValue()) {
+            link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+            link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        }
+
+        if (config.useCRC32Intrinsics) {
+            // This stub does callee saving
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
+        }
+
+        super.initialize(providers);
+    }
+
+    @Override
+    public Value[] getNativeABICallerSaveRegisters() {
+        return nativeABICallerSaveRegisters;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java
new file mode 100644
index 0000000..bd14e51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.l7;
+import static jdk.vm.ci.sparc.SPARC.sp;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<SPARCHotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerInCallerOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(5);
+
+    @Use(REG) AllocatableValue handlerInCallerPc;
+    @Use(REG) AllocatableValue exception;
+    @Use(REG) AllocatableValue exceptionPc;
+    private final Register thread;
+    private final int isMethodHandleReturnOffset;
+
+    SPARCHotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) {
+        super(TYPE, SIZE);
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+        this.isMethodHandleReturnOffset = isMethodHandleReturnOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Restore SP from L7 if the exception PC is a method handle call site.
+        SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset);
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            Register scratchReg = scratch.getRegister();
+            masm.lduw(dst, scratchReg);
+            masm.cmp(scratchReg, scratchReg);
+            masm.movcc(ConditionFlag.NotZero, CC.Icc, l7, sp);
+        }
+        masm.jmpl(asRegister(handlerInCallerPc), 0, g0);
+        leaveFrame(crb); // Delay slot
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java
new file mode 100644
index 0000000..2a457ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * Jumps to the exception handler specified by {@link #address} and leaves the current window. It
+ * does not modify the i7 register, as the exception handler stub expects the throwing pc in it.
+ * <p>
+ * See also:
+ * <li>Runtime1::generate_handle_exception c1_Runtime1_sparc.cpp
+ * <li>SharedRuntime::generate_deopt_blob at exception_in_tls_offset (sharedRuntime_sparc.cpp)
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER")
+final class SPARCHotSpotJumpToExceptionHandlerOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotJumpToExceptionHandlerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+    @Use(REG) AllocatableValue address;
+
+    SPARCHotSpotJumpToExceptionHandlerOp(AllocatableValue address) {
+        super(TYPE, SIZE);
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register addrRegister = asRegister(address, SPARCKind.XWORD);
+        masm.jmp(addrRegister);
+        masm.restoreWindow();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java
new file mode 100644
index 0000000..b6a2b52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static jdk.vm.ci.sparc.SPARC.d32;
+import static jdk.vm.ci.sparc.SPARC.d34;
+import static jdk.vm.ci.sparc.SPARC.d36;
+import static jdk.vm.ci.sparc.SPARC.d38;
+import static jdk.vm.ci.sparc.SPARC.d40;
+import static jdk.vm.ci.sparc.SPARC.d42;
+import static jdk.vm.ci.sparc.SPARC.d44;
+import static jdk.vm.ci.sparc.SPARC.d46;
+import static jdk.vm.ci.sparc.SPARC.d48;
+import static jdk.vm.ci.sparc.SPARC.d50;
+import static jdk.vm.ci.sparc.SPARC.d52;
+import static jdk.vm.ci.sparc.SPARC.d54;
+import static jdk.vm.ci.sparc.SPARC.d56;
+import static jdk.vm.ci.sparc.SPARC.d58;
+import static jdk.vm.ci.sparc.SPARC.d60;
+import static jdk.vm.ci.sparc.SPARC.d62;
+import static jdk.vm.ci.sparc.SPARC.f0;
+import static jdk.vm.ci.sparc.SPARC.f10;
+import static jdk.vm.ci.sparc.SPARC.f12;
+import static jdk.vm.ci.sparc.SPARC.f14;
+import static jdk.vm.ci.sparc.SPARC.f16;
+import static jdk.vm.ci.sparc.SPARC.f18;
+import static jdk.vm.ci.sparc.SPARC.f2;
+import static jdk.vm.ci.sparc.SPARC.f20;
+import static jdk.vm.ci.sparc.SPARC.f22;
+import static jdk.vm.ci.sparc.SPARC.f24;
+import static jdk.vm.ci.sparc.SPARC.f26;
+import static jdk.vm.ci.sparc.SPARC.f28;
+import static jdk.vm.ci.sparc.SPARC.f30;
+import static jdk.vm.ci.sparc.SPARC.f4;
+import static jdk.vm.ci.sparc.SPARC.f6;
+import static jdk.vm.ci.sparc.SPARC.f8;
+import static jdk.vm.ci.sparc.SPARC.g1;
+import static jdk.vm.ci.sparc.SPARC.g3;
+import static jdk.vm.ci.sparc.SPARC.g4;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator;
+import org.graalvm.compiler.core.sparc.SPARCLIRGenerator;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp;
+import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
+import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
+import org.graalvm.compiler.lir.sparc.SPARCPrefetchOp;
+import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
+
+    final GraalHotSpotVMConfig config;
+    private HotSpotDebugInfoBuilder debugInfoBuilder;
+    private LIRFrameState currentRuntimeCallInfo;
+
+    public SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
+        this(providers, config, lirGenRes, new ConstantTableBaseProvider());
+    }
+
+    private SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        this(new SPARCHotSpotLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider);
+    }
+
+    public SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
+                    LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes, constantTableBaseProvider);
+        assert config.basicLockSize == 8;
+        this.config = config;
+    }
+
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+
+    /**
+     * Value where the address for safepoint poll is kept.
+     */
+    private AllocatableValue safepointAddressValue;
+
+    @Override
+    public VirtualStackSlot getLockSlot(int lockDepth) {
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
+        return debugInfoBuilder.lockStack();
+    }
+
+    @Override
+    public boolean needOnlyOopMaps() {
+        // Stubs only need oop maps
+        return getStub() != null;
+    }
+
+    public Stub getStub() {
+        return getResult().getStub();
+    }
+
+    @Override
+    public HotSpotLIRGenerationResult getResult() {
+        return ((HotSpotLIRGenerationResult) super.getResult());
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        super.beforeRegisterAllocation();
+        boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
+        if (hasDebugInfo) {
+            getResult().setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
+        }
+
+        getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
+    }
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        currentRuntimeCallInfo = info;
+        super.emitForeignCallOp(linkage, result, arguments, temps, info);
+    }
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
+        HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
+        Variable result;
+        LIRFrameState debugInfo = null;
+        if (hotspotLinkage.needsDebugInfo()) {
+            debugInfo = state;
+            assert debugInfo != null || getStub() != null;
+        }
+
+        if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
+            HotSpotRegistersProvider registers = getProviders().getRegisters();
+            Register thread = registers.getThreadRegister();
+            Value threadTemp = newVariable(LIRKind.value(SPARCKind.XWORD));
+            Register stackPointer = registers.getStackPointerRegister();
+            Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
+            append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch));
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+            append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp));
+        } else {
+            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void emitReturn(JavaKind javaKind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(javaKind, input.getValueKind());
+            emitMove(operand, input);
+        }
+        append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, getSafepointAddressValue()));
+    }
+
+    @Override
+    public void emitTailcall(Value[] args, Value address) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public void emitUnwind(Value exception) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
+        emitMove(exceptionParameter, exception);
+        append(new SPARCHotSpotUnwindOp(exceptionParameter));
+    }
+
+    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
+        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
+        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
+    }
+
+    private void moveValueToThread(Value v, int offset) {
+        LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
+        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
+        SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset);
+        append(new StoreOp(v.getPlatformKind(), pendingDeoptAddress, load(v), null));
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
+        moveDeoptValuesToThread(actionAndReason, speculation);
+        append(new SPARCDeoptimizeOp(state, target().arch.getWordKind()));
+    }
+
+    @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
+        Value nullValue = emitJavaConstant(JavaConstant.NULL_POINTER);
+        moveDeoptValuesToThread(actionAndReason, nullValue);
+        append(new SPARCHotSpotDeoptimizeCallerOp());
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        ValueKind<?> kind = newValue.getValueKind();
+        assert kind.equals(expectedValue.getValueKind());
+        SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
+        Variable result = newVariable(newValue.getValueKind());
+        append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
+        return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue);
+    }
+
+    @Override
+    public void emitPrefetchAllocate(Value address) {
+        SPARCAddressValue addr = asAddressValue(address);
+        append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
+    }
+
+    public StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        Value localX = x;
+        Value localY = y;
+        if (localX instanceof HotSpotObjectConstant) {
+            localX = load(localX);
+        }
+        if (localY instanceof HotSpotObjectConstant) {
+            localY = load(localY);
+        }
+        super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
+    }
+
+    @Override
+    protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
+        Value localA = a;
+        Value localB = b;
+        if (isConstantValue(a)) {
+            Constant c = asConstant(a);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                localA = SPARC.g0.asValue(LIRKind.value(WORD));
+            } else if (c instanceof HotSpotObjectConstant) {
+                localA = load(localA);
+            }
+        }
+        if (isConstantValue(b)) {
+            Constant c = asConstant(b);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                localB = SPARC.g0.asValue(LIRKind.value(WORD));
+            } else if (c instanceof HotSpotObjectConstant) {
+                localB = load(localB);
+            }
+        }
+        return super.emitCompare(cmpKind, localA, localB);
+    }
+
+    @Override
+    public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == XWORD : inputKind;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(WORD));
+            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(WORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.base));
+            }
+            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    @Override
+    public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        assert inputKind.getPlatformKind() == WORD;
+        if (inputKind.isReference(0)) {
+            // oop
+            Variable result = newVariable(LIRKind.reference(XWORD));
+            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+            return result;
+        } else {
+            // metaspace pointer
+            Variable result = newVariable(LIRKind.value(XWORD));
+            AllocatableValue base = Value.ILLEGAL;
+            if (encoding.base != 0) {
+                base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.base));
+            }
+            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+            return result;
+        }
+    }
+
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
+    }
+
+    @Override
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // We save all registers that were not saved by the save instruction.
+        // @formatter:off
+        Register[] savedRegisters = {
+                        // CPU
+                        g1, g3, g4, g5,
+                        // FPU, use only every second register as doubles are stored anyways
+                        f0,  /*f1, */ f2,  /*f3, */ f4,  /*f5, */ f6,  /*f7, */
+                        f8,  /*f9, */ f10, /*f11,*/ f12, /*f13,*/ f14, /*f15,*/
+                        f16, /*f17,*/ f18, /*f19,*/ f20, /*f21,*/ f22, /*f23,*/
+                        f24, /*f25,*/ f26, /*f27,*/ f28, /*f29,*/ f30, /*f31 */
+                        d32,          d34,          d36,          d38,
+                        d40,          d42,          d44,          d46,
+                        d48,          d50,          d52,          d54,
+                        d56,          d58,          d60,          d62
+        };
+        // @formatter:on
+        AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+            VirtualStackSlot spillSlot = getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
+            savedRegisterLocations[i] = spillSlot;
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
+    }
+
+    @Override
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new SPARCHotSpotLeaveCurrentStackFrameOp());
+    }
+
+    @Override
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
+    }
+
+    @Override
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable scratchVariable = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable,
+                        target().arch.getWordKind()));
+    }
+
+    @Override
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
+    }
+
+    @Override
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
+    }
+
+    @Override
+    public Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Value threadTemp = newVariable(LIRKind.value(target().arch.getWordKind()));
+        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+        Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().arch.getWordKind())), trapRequest, mode);
+        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo();
+        assert currentRuntimeCallInfo != null;
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
+    @Override
+    public Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO);
+
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Value threadTemp = newVariable(LIRKind.value(target().arch.getWordKind()));
+        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+        Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().arch.getWordKind())), mode);
+        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo();
+        assert currentRuntimeCallInfo != null;
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        PlatformKind kind = address.getPlatformKind();
+        if (kind == WORD) {
+            CompressEncoding encoding = config.getOopEncoding();
+            Value uncompressed = emitUncompress(address, encoding, false);
+            append(new NullCheckOp(asAddressValue(uncompressed), state));
+        } else {
+            super.emitNullCheck(address, state);
+        }
+    }
+
+    @Override
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        if (BenchmarkCounters.enabled) {
+            return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
+        }
+        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
+    }
+
+    @Override
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        if (BenchmarkCounters.enabled) {
+            return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
+        }
+        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
+    }
+
+    public AllocatableValue getSafepointAddressValue() {
+        if (this.safepointAddressValue == null) {
+            this.safepointAddressValue = newVariable(LIRKind.value(target().arch.getWordKind()));
+        }
+        return this.safepointAddressValue;
+    }
+
+    @Override
+    protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) {
+        return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
+    }
+
+    public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
+        this.debugInfoBuilder = debugInfoBuilder;
+    }
+
+    @Override
+    public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
+        throw GraalError.unimplemented();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java
new file mode 100644
index 0000000..c7f5851
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.sparc.SPARCLIRKindTool;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
+
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCHotSpotLIRKindTool extends SPARCLIRKindTool implements HotSpotLIRKindTool {
+
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(SPARCKind.WORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(SPARCKind.WORD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java
new file mode 100644
index 0000000..a41f682
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.i2;
+import static jdk.vm.ci.sparc.SPARC.i3;
+import static jdk.vm.ci.sparc.SPARC.i4;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+/**
+ * Pops the current frame off the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotLeaveCurrentStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveCurrentStackFrameOp.class);
+
+    SPARCHotSpotLeaveCurrentStackFrameOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        masm.mov(o0, i0);
+        masm.mov(o1, i1);
+        masm.mov(o2, i2);
+        masm.mov(o3, i3);
+        masm.mov(o4, i4);
+
+        crb.frameContext.leave(crb);
+    }
+
+    @Override
+    public boolean leavesRegisterWindow() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java
new file mode 100644
index 0000000..3d828ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.i2;
+import static jdk.vm.ci.sparc.SPARC.i3;
+import static jdk.vm.ci.sparc.SPARC.i4;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCLIRInstruction {
+
+    public static final LIRInstructionClass<SPARCHotSpotLeaveDeoptimizedStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveDeoptimizedStackFrameOp.class);
+
+    protected SPARCHotSpotLeaveDeoptimizedStackFrameOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        masm.mov(o0, i0);
+        masm.mov(o1, i1);
+        masm.mov(o2, i2);
+        masm.mov(o3, i3);
+        masm.mov(o4, i4);
+
+        masm.restoreWindow();
+    }
+
+    @Override
+    public boolean leavesRegisterWindow() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java
new file mode 100644
index 0000000..99f3826
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.l7;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotLeaveUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveUnpackFramesStackFrameOp.class);
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadJavaFrameAnchorFlagsOffset;
+
+    SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+        super(TYPE);
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        masm.mov(l7, thread);
+
+        SPARCAddress lastJavaPc = new SPARCAddress(thread, threadLastJavaPcOffset);
+
+        // We borrow the threads lastJavaPC to transfer the value from float to i0
+        masm.stdf(SPARCSaveRegistersOp.RETURN_REGISTER_STORAGE, lastJavaPc);
+        masm.ldx(lastJavaPc, i0);
+
+        // Clear last Java frame values.
+        masm.stx(g0, lastJavaPc);
+        masm.stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset));
+        masm.stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java
new file mode 100644
index 0000000..7c9b33e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
+
+    public SPARCHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof FloatConvertNode) {
+            // FloatConvertNodes are handled in SPARCLIRGenerator.emitConvert
+        } else {
+            super.lower(n, tool);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java
new file mode 100644
index 0000000..7b869c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+public class SPARCHotSpotMove {
+
+    public static class LoadHotSpotObjectConstantInline extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, LoadConstantOp {
+        public static final LIRInstructionClass<LoadHotSpotObjectConstantInline> TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class);
+
+        public static final SizeEstimate SIZE = SizeEstimate.create(8);
+        private HotSpotConstant constant;
+        @Def({REG, STACK}) AllocatableValue result;
+
+        public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) {
+            super(TYPE, SIZE);
+            this.constant = constant;
+            this.result = result;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            crb.recordInlineDataInCode(constant);
+            if (constant.isCompressed()) {
+                masm.setw(0, asRegister(result), true);
+            } else {
+                masm.setx(0, asRegister(result), true);
+            }
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        @Override
+        public Constant getConstant() {
+            return constant;
+        }
+    }
+
+    public static class LoadHotSpotObjectConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadHotSpotObjectConstantFromTable> TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantFromTable.class);
+
+        public static final SizeEstimate SIZE = SizeEstimate.create(2, 8);
+        private final HotSpotConstant constant;
+        @Use({REG}) private AllocatableValue constantTableBase;
+        @Def({REG, STACK}) AllocatableValue result;
+
+        public LoadHotSpotObjectConstantFromTable(HotSpotConstant constant, AllocatableValue result, AllocatableValue constantTableBase) {
+            super(TYPE, SIZE);
+            this.constant = constant;
+            this.result = result;
+            this.constantTableBase = constantTableBase;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            try (ScratchRegister scratch = masm.getScratchRegister()) {
+                boolean isStack = ValueUtil.isStackSlot(result);
+                Register register;
+                if (isStack) {
+                    register = scratch.getRegister();
+                } else {
+                    register = asRegister(result);
+                }
+                int bytes = result.getPlatformKind().getSizeInBytes();
+                loadFromConstantTable(crb, masm, bytes, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY);
+                if (isStack) {
+                    masm.st(register, (SPARCAddress) crb.asAddress(result), bytes);
+                }
+            }
+        }
+    }
+
+    public static final class CompressPointer extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(5);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            Register inputRegister = asRegister(input);
+            Register resReg = asRegister(result);
+            if (encoding.base != 0) {
+                Register baseReg = asRegister(baseRegister);
+                if (!nonNull) {
+                    masm.cmp(inputRegister, baseReg);
+                    masm.movcc(ConditionFlag.Equal, CC.Xcc, baseReg, resReg);
+                    masm.sub(resReg, baseReg, resReg);
+                } else {
+                    masm.sub(inputRegister, baseReg, resReg);
+                }
+                if (encoding.shift != 0) {
+                    masm.srlx(resReg, encoding.shift, resReg);
+                }
+            } else {
+                masm.srlx(inputRegister, encoding.shift, resReg);
+            }
+        }
+    }
+
+    public static final class UncompressPointer extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(4);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            Register inputRegister = asRegister(input);
+            Register resReg = asRegister(result);
+            Register secondaryInput;
+            if (encoding.shift != 0) {
+                masm.sll(inputRegister, encoding.shift, resReg);
+                secondaryInput = resReg;
+            } else {
+                secondaryInput = inputRegister;
+            }
+
+            if (encoding.base != 0) {
+                if (nonNull) {
+                    masm.add(secondaryInput, asRegister(baseRegister), resReg);
+                } else {
+                    Label done = new Label();
+                    BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done);
+                    masm.add(asRegister(baseRegister), secondaryInput, resReg);
+                    masm.bind(done);
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java
new file mode 100644
index 0000000..80545e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL;
+import static jdk.vm.ci.meta.JavaConstant.INT_0;
+import static jdk.vm.ci.meta.JavaConstant.LONG_0;
+
+import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider;
+import org.graalvm.compiler.core.sparc.SPARCMoveFactory;
+import org.graalvm.compiler.lir.LIRInstruction;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class SPARCHotSpotMoveFactory extends SPARCMoveFactory {
+
+    public SPARCHotSpotMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) {
+        super(constantTableBaseProvider);
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return false;
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        Constant usedSource;
+        if (COMPRESSED_NULL.equals(src)) {
+            usedSource = INT_0;
+        } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) {
+            usedSource = LONG_0;
+        } else {
+            usedSource = src;
+        }
+        if (usedSource instanceof HotSpotConstant) {
+            HotSpotConstant constant = (HotSpotConstant) usedSource;
+            if (constant.isCompressed()) {
+                return new SPARCHotSpotMove.LoadHotSpotObjectConstantInline(constant, dst);
+            } else {
+                return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst, constantTableBaseProvider.getConstantTableBase());
+            }
+        } else {
+            return super.createLoad(dst, usedSource);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java
new file mode 100644
index 0000000..d2c3eca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
+import org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerNode;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.ReturnNode;
+
+public class SPARCHotSpotNodeCostProvider extends HotSpotNodeCostProvider {
+
+    @Override
+    public NodeCycles cycles(Node n) {
+        if (n instanceof ReturnNode) {
+            return NodeCycles.CYCLES_6;
+        } else if (n instanceof JumpToExceptionHandlerNode) {
+            // restore caller window
+            return NodeCycles.CYCLES_3;
+        }
+        return super.cycles(n);
+    }
+
+    @Override
+    public NodeSize size(Node n) {
+        if (n instanceof ReturnNode) {
+            return NodeSize.SIZE_4;
+        } else if (n instanceof JumpToExceptionHandlerNode) {
+            // restore caller window
+            return NodeSize.SIZE_3;
+        }
+        return super.size(n);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java
new file mode 100644
index 0000000..e16abf5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.gen.DebugInfoBuilder;
+import org.graalvm.compiler.core.sparc.SPARCNodeLIRBuilder;
+import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.sparc.SPARCBreakpointOp;
+import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
+
+    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
+        assert gen instanceof SPARCHotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((SPARCHotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()));
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(SPARCKind.XWORD));
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen);
+    }
+
+    private SPARCHotSpotLIRGenerator getGen() {
+        return (SPARCHotSpotLIRGenerator) gen;
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = state(i);
+        append(new SPARCHotSpotSafepointOp(info, getGen().config, gen));
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        AllocatableValue address = gen.asAllocatable(operand(x.getAddress()));
+        AllocatableValue cmpValue = gen.asAllocatable(operand(x.expectedValue()));
+        AllocatableValue newValue = gen.asAllocatable(operand(x.newValue()));
+        assert cmpValue.getValueKind().equals(newValue.getValueKind());
+
+        Variable result = gen.newVariable(newValue.getValueKind());
+        append(new CompareAndSwapOp(result, address, cmpValue, newValue));
+        setResult(x, result);
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind.isIndirect()) {
+            append(new SPARCHotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        } else {
+            assert invokeKind.isDirect();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+            assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
+            append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod());
+        AllocatableValue metaspaceMethod = g5.asValue(metaspaceMethodSrc.getValueKind());
+        gen.emitMove(metaspaceMethod, metaspaceMethodSrc);
+
+        Value targetAddressSrc = operand(callTarget.computedAddress());
+        AllocatableValue targetAddress = o7.asValue(targetAddressSrc.getValueKind());
+        gen.emitMove(targetAddress, targetAddressSrc);
+        append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState, getGen().config));
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandler(ValueNode address) {
+        append(new SPARCHotSpotJumpToExceptionHandlerOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset,
+                        thread);
+        append(op);
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        super.emitPrologue(graph);
+        AllocatableValue var = getGen().getSafepointAddressValue();
+        append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, getGen().config));
+        getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
+    }
+
+    @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitFullInfopointNode(i);
+        }
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
+                        node.arguments());
+        append(new SPARCBreakpointOp(parameters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java
new file mode 100644
index 0000000..1ac1340
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.i7;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class SPARCHotSpotPatchReturnAddressOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotPatchReturnAddressOp> TYPE = LIRInstructionClass.create(SPARCHotSpotPatchReturnAddressOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    @Use(REG) AllocatableValue address;
+
+    SPARCHotSpotPatchReturnAddressOp(AllocatableValue address) {
+        super(TYPE, SIZE);
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register addrRegister = asRegister(address, XWORD);
+        masm.sub(addrRegister, SPARCAssembler.PC_RETURN_OFFSET, i7);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java
new file mode 100644
index 0000000..8692c0c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.i2;
+import static jdk.vm.ci.sparc.SPARC.i3;
+import static jdk.vm.ci.sparc.SPARC.i4;
+import static jdk.vm.ci.sparc.SPARC.i7;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+import static jdk.vm.ci.sparc.SPARC.o5;
+import static jdk.vm.ci.sparc.SPARC.sp;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotPushInterpreterFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotPushInterpreterFrameOp.class);
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+
+    SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        super(TYPE);
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+
+        // Save sender SP to O5_savedSP.
+        masm.mov(senderSpRegister, o5);
+
+        masm.neg(frameSizeRegister);
+        masm.save(sp, frameSizeRegister, sp);
+
+        masm.mov(i0, o0);
+        masm.mov(i1, o1);
+        masm.mov(i2, o2);
+        masm.mov(i3, o3);
+        masm.mov(i4, o4);
+
+        // NOTE: Don't touch I5 as it contains valuable saved SP!
+
+        // Move frame's new PC into i7
+        masm.mov(framePcRegister, i7);
+    }
+
+    @Override
+    public boolean leavesRegisterWindow() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java
new file mode 100644
index 0000000..85fd975
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.d32;
+import static jdk.vm.ci.sparc.SPARC.d34;
+import static jdk.vm.ci.sparc.SPARC.d36;
+import static jdk.vm.ci.sparc.SPARC.d38;
+import static jdk.vm.ci.sparc.SPARC.d40;
+import static jdk.vm.ci.sparc.SPARC.d42;
+import static jdk.vm.ci.sparc.SPARC.d44;
+import static jdk.vm.ci.sparc.SPARC.d46;
+import static jdk.vm.ci.sparc.SPARC.d48;
+import static jdk.vm.ci.sparc.SPARC.d50;
+import static jdk.vm.ci.sparc.SPARC.d52;
+import static jdk.vm.ci.sparc.SPARC.d54;
+import static jdk.vm.ci.sparc.SPARC.d56;
+import static jdk.vm.ci.sparc.SPARC.d58;
+import static jdk.vm.ci.sparc.SPARC.d60;
+import static jdk.vm.ci.sparc.SPARC.d62;
+import static jdk.vm.ci.sparc.SPARC.f10;
+import static jdk.vm.ci.sparc.SPARC.f11;
+import static jdk.vm.ci.sparc.SPARC.f12;
+import static jdk.vm.ci.sparc.SPARC.f13;
+import static jdk.vm.ci.sparc.SPARC.f14;
+import static jdk.vm.ci.sparc.SPARC.f15;
+import static jdk.vm.ci.sparc.SPARC.f16;
+import static jdk.vm.ci.sparc.SPARC.f17;
+import static jdk.vm.ci.sparc.SPARC.f18;
+import static jdk.vm.ci.sparc.SPARC.f19;
+import static jdk.vm.ci.sparc.SPARC.f20;
+import static jdk.vm.ci.sparc.SPARC.f21;
+import static jdk.vm.ci.sparc.SPARC.f22;
+import static jdk.vm.ci.sparc.SPARC.f23;
+import static jdk.vm.ci.sparc.SPARC.f24;
+import static jdk.vm.ci.sparc.SPARC.f25;
+import static jdk.vm.ci.sparc.SPARC.f26;
+import static jdk.vm.ci.sparc.SPARC.f27;
+import static jdk.vm.ci.sparc.SPARC.f28;
+import static jdk.vm.ci.sparc.SPARC.f29;
+import static jdk.vm.ci.sparc.SPARC.f30;
+import static jdk.vm.ci.sparc.SPARC.f31;
+import static jdk.vm.ci.sparc.SPARC.f8;
+import static jdk.vm.ci.sparc.SPARC.f9;
+import static jdk.vm.ci.sparc.SPARC.g1;
+import static jdk.vm.ci.sparc.SPARC.g4;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i1;
+import static jdk.vm.ci.sparc.SPARC.i2;
+import static jdk.vm.ci.sparc.SPARC.i3;
+import static jdk.vm.ci.sparc.SPARC.i4;
+import static jdk.vm.ci.sparc.SPARC.i5;
+import static jdk.vm.ci.sparc.SPARC.l0;
+import static jdk.vm.ci.sparc.SPARC.l1;
+import static jdk.vm.ci.sparc.SPARC.l2;
+import static jdk.vm.ci.sparc.SPARC.l3;
+import static jdk.vm.ci.sparc.SPARC.l4;
+import static jdk.vm.ci.sparc.SPARC.l5;
+import static jdk.vm.ci.sparc.SPARC.l6;
+import static jdk.vm.ci.sparc.SPARC.l7;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+import static jdk.vm.ci.sparc.SPARC.o5;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+
+public class SPARCHotSpotRegisterAllocationConfig extends RegisterAllocationConfig {
+
+    // @formatter:off
+    static final Register[] registerAllocationOrder = {
+      l0, l1, l2, l3, l4, l5, l6, l7,
+      i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
+      o0, o1, o2, o3, o4, o5, /*o6, o7,*/
+      g1, g4, g5,
+      // f0, f1, f2, f3, f4, f5, f6, f7
+      f8,  f9,  f10, f11, f12, f13, f14, f15,
+      f16, f17, f18, f19, f20, f21, f22, f23,
+      f24, f25, f26, f27, f28, f29, f30, f31,
+      d32, d34, d36, d38, d40, d42, d44, d46,
+      d48, d50, d52, d54, d56, d58, d60, d62
+    };
+    // @formatter:on
+
+    public SPARCHotSpotRegisterAllocationConfig(RegisterConfig registerConfig) {
+        super(registerConfig);
+    }
+
+    @Override
+    protected RegisterArray initAllocatable(RegisterArray registers) {
+        BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size());
+        for (Register reg : registers) {
+            regMap.set(reg.number);
+        }
+
+        ArrayList<Register> allocatableRegisters = new ArrayList<>(registers.size());
+        for (Register reg : registerAllocationOrder) {
+            if (regMap.get(reg.number)) {
+                allocatableRegisters.add(reg);
+            }
+        }
+
+        return super.initAllocatable(new RegisterArray(allocatableRegisters));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java
new file mode 100644
index 0000000..134da90
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Returns from a function.
+ */
+@Opcode("RETURN")
+final class SPARCHotSpotReturnOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotReturnOp> TYPE = LIRInstructionClass.create(SPARCHotSpotReturnOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+    @Use({REG, ILLEGAL}) protected Value value;
+    @Use({REG}) protected Value safepointPollAddress;
+    private final boolean isStub;
+    private final GraalHotSpotVMConfig config;
+
+    SPARCHotSpotReturnOp(Value value, boolean isStub, GraalHotSpotVMConfig config, Value safepointPoll) {
+        super(TYPE, SIZE);
+        this.value = value;
+        this.isStub = isStub;
+        this.config = config;
+        this.safepointPollAddress = safepointPoll;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        if (!isStub) {
+            // Every non-stub compile method must have a poll before the return.
+            SPARCHotSpotSafepointOp.emitCode(crb, masm, config, true, null, asRegister(safepointPollAddress));
+        }
+        ReturnOp.emitCodeHelper(crb, masm);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java
new file mode 100644
index 0000000..4b0bf19
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotSafepointOp> TYPE = LIRInstructionClass.create(SPARCHotSpotSafepointOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(9);
+
+    @State protected LIRFrameState state;
+    @Use({OperandFlag.REG}) AllocatableValue safepointPollAddress;
+    private final GraalHotSpotVMConfig config;
+
+    public SPARCHotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, LIRGeneratorTool tool) {
+        super(TYPE, SIZE);
+        this.state = state;
+        this.config = config;
+        SPARCHotSpotLIRGenerator lirGen = (SPARCHotSpotLIRGenerator) tool;
+        safepointPollAddress = lirGen.getSafepointAddressValue();
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        emitCode(crb, masm, config, false, state, asRegister(safepointPollAddress));
+    }
+
+    public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register safepointPollAddress) {
+        crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+        if (state != null) {
+            final int pos = masm.position();
+            crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+        }
+        masm.ldx(new SPARCAddress(safepointPollAddress, 0), g0);
+    }
+
+    public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<SPARCLoadSafepointPollAddress> TYPE = LIRInstructionClass.create(SPARCLoadSafepointPollAddress.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        @Def({OperandFlag.REG}) protected AllocatableValue result;
+        private final GraalHotSpotVMConfig config;
+
+        public SPARCLoadSafepointPollAddress(AllocatableValue result, GraalHotSpotVMConfig config) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.config = config;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            masm.setx(config.safepointPollingAddress, ValueUtil.asRegister(result), false);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java
new file mode 100644
index 0000000..fedd4a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+
+import org.graalvm.compiler.asm.Assembler.LabelHint;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCControlFlow;
+import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+
+final class SPARCHotSpotStrategySwitchOp extends SPARCControlFlow.StrategySwitchOp {
+    public static final LIRInstructionClass<SPARCHotSpotStrategySwitchOp> TYPE = LIRInstructionClass.create(SPARCHotSpotStrategySwitchOp.class);
+
+    SPARCHotSpotStrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+        super(TYPE, constantTableBase, strategy, keyTargets, defaultTarget, key, scratch);
+    }
+
+    public class HotSpotSwitchClosure extends SwitchClosure {
+        protected HotSpotSwitchClosure(Register keyRegister, Register constantBaseRegister, CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            super(keyRegister, constantBaseRegister, crb, masm);
+        }
+
+        @Override
+        protected void conditionalJump(int index, Condition condition, Label target) {
+            if (keyConstants[index] instanceof HotSpotMetaspaceConstant) {
+                HotSpotMetaspaceConstant constant = (HotSpotMetaspaceConstant) keyConstants[index];
+                CC conditionCode = constant.isCompressed() ? CC.Icc : CC.Xcc;
+                ConditionFlag conditionFlag = SPARCControlFlow.fromCondition(true, condition, false);
+                LabelHint hint = requestHint(masm, target);
+
+                // Load constant takes one instruction
+                int cbCondPosition = masm.position() + INSTRUCTION_SIZE;
+                boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && SPARCControlFlow.isShortBranch(masm, cbCondPosition, hint, target);
+
+                Register scratchRegister = asRegister(scratch);
+                final int byteCount = constant.isCompressed() ? 4 : 8;
+                loadFromConstantTable(crb, masm, byteCount, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY);
+
+                if (canUseShortBranch) {
+                    CBCOND.emit(masm, conditionFlag, conditionCode == CC.Xcc, keyRegister, scratchRegister, target);
+                } else {
+                    masm.cmp(keyRegister, scratchRegister);
+                    BPCC.emit(masm, conditionCode, conditionFlag, ANNUL, PREDICT_TAKEN, target);
+                    masm.nop();  // delay slot
+                }
+            } else {
+                super.conditionalJump(index, condition, target);
+            }
+        }
+    }
+
+    @Override
+    protected int estimateEmbeddedSize(Constant c) {
+        if (c instanceof HotSpotMetaspaceConstant) {
+            return ((HotSpotMetaspaceConstant) c).isCompressed() ? 4 : 8;
+        } else {
+            return super.estimateEmbeddedSize(c);
+        }
+    }
+
+    @Override
+    public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) {
+        final Register keyRegister = asRegister(key);
+        final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase);
+        strategy.run(new HotSpotSwitchClosure(keyRegister, constantBaseRegister, crb, masm));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java
new file mode 100644
index 0000000..d48f6db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+
+/**
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
+ */
+@Opcode("UNWIND")
+final class SPARCHotSpotUnwindOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotUnwindOp> TYPE = LIRInstructionClass.create(SPARCHotSpotUnwindOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(32);
+
+    @Use({REG}) protected RegisterValue exception;
+
+    SPARCHotSpotUnwindOp(RegisterValue exception) {
+        super(TYPE, SIZE);
+        this.exception = exception;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // This Frame is left but the called unwind (which is sibling) method needs the exception as
+        // input in i0
+        masm.mov(o0, i0);
+        leaveFrame(crb);
+
+        ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getOutgoingCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is in o7 after leave).
+        Register returnAddress = asRegister(cc.getArgument(1));
+        masm.add(o7, SPARCAssembler.PC_RETURN_OFFSET, returnAddress);
+        Register scratch = g5;
+        SPARCCall.indirectJmp(crb, masm, scratch, linkage);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java
new file mode 100644
index 0000000..578cefe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
+ * inline cache so it's just a patchable call site.
+ */
+@Opcode("CALL_DIRECT")
+final class SPARCHotspotDirectStaticCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<SPARCHotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(8);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, SIZE, target, result, parameters, temps, state);
+        assert invokeKind.isDirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java
new file mode 100644
index 0000000..6ac8b37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.g5;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class SPARCHotspotDirectVirtualCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<SPARCHotspotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(SPARCHotspotDirectVirtualCallOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(8);
+
+    private final InvokeKind invokeKind;
+    private final GraalHotSpotVMConfig config;
+
+    SPARCHotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
+        super(TYPE, SIZE, target, result, parameters, temps, state);
+        this.invokeKind = invokeKind;
+        this.config = config;
+        assert invokeKind.isIndirect();
+    }
+
+    @Override
+    public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
+        Register scratchRegister = g5;
+        masm.setx(config.nonOopBits, scratchRegister, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java
new file mode 100644
index 0000000..79f5db2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g5;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+import org.graalvm.compiler.lir.sparc.SPARCCall.IndirectCallOp;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A register indirect call that complies with the extra conventions for such calls in HotSpot. In
+ * particular, the metaspace Method of the callee must be in g5 for the case where a vtable entry's
+ * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to
+ * be in g5.
+ */
+@Opcode("CALL_INDIRECT")
+final class SPARCIndirectCallOp extends IndirectCallOp {
+    public static final LIRInstructionClass<SPARCIndirectCallOp> TYPE = LIRInstructionClass.create(SPARCIndirectCallOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+    /**
+     * Vtable stubs expect the metaspace Method in g5.
+     */
+    public static final Register METHOD = g5;
+
+    @Use({REG}) protected Value metaspaceMethod;
+
+    private final GraalHotSpotVMConfig config;
+
+    SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state,
+                    GraalHotSpotVMConfig config) {
+        super(TYPE, SIZE, targetMethod, result, parameters, temps, targetAddress, state);
+        this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
+        Register callReg = asRegister(targetAddress);
+        assert !callReg.equals(METHOD);
+        SPARCCall.indirectCall(crb, masm, callReg, callTarget, state);
+    }
+
+    @Override
+    public void verify() {
+        super.verify();
+        assert asRegister(metaspaceMethod).equals(METHOD);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCUncommonTrapStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCUncommonTrapStub.java
new file mode 100644
index 0000000..3ef2751
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCUncommonTrapStub.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static jdk.vm.ci.sparc.SPARC.g1;
+import static jdk.vm.ci.sparc.SPARC.g3;
+import static jdk.vm.ci.sparc.SPARC.g4;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o1;
+import static jdk.vm.ci.sparc.SPARC.o2;
+import static jdk.vm.ci.sparc.SPARC.o3;
+import static jdk.vm.ci.sparc.SPARC.o4;
+
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub;
+
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.sparc.SPARCHotSpotRegisterConfig;
+
+final class SPARCUncommonTrapStub extends UncommonTrapStub {
+
+    private RegisterConfig registerConfig;
+
+    SPARCUncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        // This is basically the maximum we can spare. All other G and O register are used.
+        RegisterArray allocatable = new RegisterArray(g1, g3, g4, g5, o0, o1, o2, o3, o4);
+        registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java
new file mode 100644
index 0000000..ec528b1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.core.GraalCompiler.compileGraph;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.SuitesProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * use
+ *
+ * <pre>
+ * mx unittest AheadOfTimeCompilationTest @-XX:CompileCommand='print,*AheadOfTimeCompilationTest.*'
+ * </pre>
+ *
+ * to print disassembly.
+ */
+public class AheadOfTimeCompilationTest extends GraalCompilerTest {
+
+    public static final Object STATICFINALOBJECT = new Object();
+    public static final String STATICFINALSTRING = "test string";
+
+    public static Object getStaticFinalObject() {
+        return AheadOfTimeCompilationTest.STATICFINALOBJECT;
+    }
+
+    @Test
+    public void testStaticFinalObjectAOT() {
+        StructuredGraph result = compile("getStaticFinalObject", true);
+        assertDeepEquals(1, getConstantNodes(result).count());
+        Stamp constantStamp = getConstantNodes(result).first().stamp();
+        Assert.assertTrue(constantStamp.toString(), constantStamp instanceof KlassPointerStamp);
+        assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    @Test
+    public void testStaticFinalObject() {
+        StructuredGraph result = compile("getStaticFinalObject", false);
+        assertDeepEquals(1, getConstantNodes(result).count());
+        assertDeepEquals(JavaKind.Object, getConstantNodes(result).first().getStackKind());
+        assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    public static Class<AheadOfTimeCompilationTest> getClassObject() {
+        return AheadOfTimeCompilationTest.class;
+    }
+
+    @Test
+    public void testClassObjectAOT() {
+        StructuredGraph result = compile("getClassObject", true);
+
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
+        assertDeepEquals(1, filter.count());
+        HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class);
+        assertDeepEquals(type.klass(), filter.first().asConstant());
+
+        assertDeepEquals(1, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    @Test
+    public void testClassObject() {
+        StructuredGraph result = compile("getClassObject", false);
+
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
+        assertDeepEquals(1, filter.count());
+        JavaConstant c = filter.first().asJavaConstant();
+        Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), AheadOfTimeCompilationTest.class);
+
+        assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    public static Class<Integer> getPrimitiveClassObject() {
+        return int.class;
+    }
+
+    @Test
+    public void testPrimitiveClassObjectAOT() {
+        StructuredGraph result = compile("getPrimitiveClassObject", true);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
+        assertDeepEquals(1, filter.count());
+        Stamp constantStamp = filter.first().stamp();
+        Assert.assertTrue(constantStamp instanceof KlassPointerStamp);
+
+        assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    @Test
+    public void testPrimitiveClassObject() {
+        StructuredGraph result = compile("getPrimitiveClassObject", false);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
+        assertDeepEquals(1, filter.count());
+        JavaConstant c = filter.first().asJavaConstant();
+        Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), Integer.TYPE);
+
+        assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    public static String getStringObject() {
+        return AheadOfTimeCompilationTest.STATICFINALSTRING;
+    }
+
+    @Test
+    public void testStringObjectAOT() {
+        // embedded strings are fine
+        testStringObjectCommon(true);
+    }
+
+    @Test
+    public void testStringObject() {
+        testStringObjectCommon(false);
+    }
+
+    private void testStringObjectCommon(boolean compileAOT) {
+        StructuredGraph result = compile("getStringObject", compileAOT);
+
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
+        assertDeepEquals(1, filter.count());
+        JavaConstant c = filter.first().asJavaConstant();
+        Assert.assertEquals(getSnippetReflection().asObject(String.class, c), "test string");
+
+        assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
+    }
+
+    public static Boolean getBoxedBoolean() {
+        return Boolean.valueOf(true);
+    }
+
+    @Ignore("ImmutableCode override may not work reliably in non-hosted mode")
+    @Test
+    public void testBoxedBooleanAOT() {
+        StructuredGraph result = compile("getBoxedBoolean", true);
+
+        assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(1, result.getNodes(PiNode.TYPE).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
+        ConstantNode constant = getConstantNodes(result).first();
+        assertDeepEquals(JavaKind.Long, constant.getStackKind());
+        assertDeepEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
+    }
+
+    @Test
+    public void testBoxedBoolean() {
+        StructuredGraph result = compile("getBoxedBoolean", false);
+        assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes(PiNode.TYPE).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
+        ConstantNode constant = getConstantNodes(result).first();
+        assertDeepEquals(JavaKind.Object, constant.getStackKind());
+
+        JavaConstant c = constant.asJavaConstant();
+        Assert.assertEquals(getSnippetReflection().asObject(Boolean.class, c), Boolean.TRUE);
+    }
+
+    @SuppressWarnings("try")
+    private StructuredGraph compile(String test, boolean compileAOT) {
+        try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) {
+            StructuredGraph graph = parseEager(test, AllowAssumptions.YES);
+            ResolvedJavaMethod method = graph.method();
+            // create suites everytime, as we modify options for the compiler
+            SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
+            final Suites suitesLocal = suitesProvider.getDefaultSuites();
+            final LIRSuites lirSuitesLocal = suitesProvider.getDefaultLIRSuites();
+            final CompilationResult compResult = compileGraph(graph, method, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
+                            suitesLocal, lirSuitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default);
+            addMethod(method, compResult);
+            return graph;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java
new file mode 100644
index 0000000..e3ea0bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoweredCallTargetNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}.
+ */
+public class ArrayCopyIntrinsificationTest extends GraalCompilerTest {
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph g) {
+        StructuredGraph graph = g == null ? parseForCompile(method) : g;
+        int nodeCount = graph.getNodeCount();
+        InstalledCode result = super.getCode(method, graph);
+        boolean graphWasProcessed = nodeCount != graph.getNodeCount();
+        if (graphWasProcessed) {
+            if (mustIntrinsify) {
+                for (Node node : graph.getNodes()) {
+                    if (node instanceof Invoke) {
+                        Invoke invoke = (Invoke) node;
+                        Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode);
+                        LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
+                        JavaMethod callee = directCall.targetMethod();
+                        if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
+                            // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may
+                            // call the original arraycopy method
+                        } else {
+                            Assert.assertTrue(callee.toString(), callee.getName().equals("<init>"));
+                            Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) ||
+                                            getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
+                        }
+                    }
+                }
+            } else {
+                boolean found = false;
+                for (Node node : graph.getNodes()) {
+                    if (node instanceof Invoke) {
+                        Invoke invoke = (Invoke) node;
+                        LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
+                        JavaMethod callee = directCall.targetMethod();
+                        if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
+                            found = true;
+                        } else {
+                            fail("found invoke to some method other than arraycopy: " + callee);
+                        }
+                    }
+                }
+                Assert.assertTrue("did not find invoke to arraycopy", found);
+            }
+        }
+        return result;
+    }
+
+    boolean mustIntrinsify = true;
+
+    @Test
+    public void test0() {
+        // Array store checks
+        test("genericArraycopy", new Object(), 0, new Object[0], 0, 0);
+        test("genericArraycopy", new Object[0], 0, new Object(), 0, 0);
+    }
+
+    @Test
+    public void test1() {
+        String name = "intArraycopy";
+        int[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        // Null checks
+        test(name, null, 0, src, 0, 0);
+        test(name, src, 0, null, 0, 0);
+        // Bounds checks
+        test(name, src, 0, src, 0, -1);
+        test(name, src, 0, src, 0, src.length + 1);
+    }
+
+    @Test
+    public void testByte() {
+        byte[] src = {-1, 0, 1, 2, 3, 4};
+        testHelper("byteArraycopy", src);
+    }
+
+    @Test
+    public void testChar() {
+        char[] src = "some string of chars".toCharArray();
+        testHelper("charArraycopy", src);
+    }
+
+    @Test
+    public void testShort() {
+        short[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("shortArraycopy", src);
+    }
+
+    @Test
+    public void testInt() {
+        int[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("intArraycopy", src);
+    }
+
+    @Test
+    public void testFloat() {
+        float[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("floatArraycopy", src);
+    }
+
+    @Test
+    public void testLong() {
+        long[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("longArraycopy", src);
+    }
+
+    @Test
+    public void testDouble() {
+        double[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("doubleArraycopy", src);
+    }
+
+    @Test
+    public void testObject() {
+        Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()};
+        testHelper("objectArraycopy", src);
+    }
+
+    /**
+     * Tests {@link ArrayCopySnippets#checkcastArraycopyWork(Object, int, Object, int, int)}.
+     */
+    @Test
+    public void testArrayStoreException() {
+        Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()};
+        Object[] dst = new CharSequence[src.length];
+        // Will throw ArrayStoreException for 4th element
+        test("objectArraycopy", src, 0, dst, 0, src.length);
+    }
+
+    @Test
+    public void testDisjointObject() {
+        Integer[] src1 = {1, 2, 3, 4};
+        test("objectArraycopy", src1, 0, src1, 1, src1.length - 1);
+
+        Integer[] src2 = {1, 2, 3, 4};
+        test("objectArraycopy", src2, 1, src2, 0, src2.length - 1);
+    }
+
+    @Test
+    public void testObjectExact() {
+        Integer[] src = {1, 2, 3, 4};
+        testHelper("objectArraycopyExact", src);
+    }
+
+    private static Object newArray(Object proto, int length) {
+        assert proto != null;
+        assert proto.getClass().isArray();
+        return Array.newInstance(proto.getClass().getComponentType(), length);
+    }
+
+    private void testHelper(String name, Object src) {
+        int srcLength = Array.getLength(src);
+
+        // Complete array copy
+        test(name, src, 0, newArray(src, srcLength), 0, srcLength);
+
+        for (int length : new int[]{0, 1, srcLength - 1, srcLength}) {
+            // Partial array copying
+            test(name, src, 0, newArray(src, length), 0, length);
+            test(name, src, srcLength - length, newArray(src, length), 0, length);
+            test(name, src, 0, newArray(src, srcLength), 0, length);
+        }
+
+        if (srcLength > 1) {
+            test(name, src, 0, src, 1, srcLength - 1);
+        }
+    }
+
+    public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    /**
+     * Test case derived from assertion while compiling <a href=
+     * "https://code.google.com/r/baggiogamp-guava/source/browse/guava/src/com/google/common/collect/ArrayTable.java?r=d2e06112416223cb5437d43c12a989c0adc7345b#181"
+     * > com.google.common.collect.ArrayTable(ArrayTable other)</a>.
+     */
+    @Test
+    public void testCopyRows() {
+        Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}};
+        test("copyRows", rows, 4, new Integer(rows.length));
+    }
+
+    public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) {
+        Object[][] copy = new Object[rows.length][rowSize];
+        for (int i = 0; i < rowCount.intValue(); i++) {
+            System.arraycopy(rows[i], 0, copy[i], 0, rows[i].length);
+        }
+        return copy;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32SubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32SubstitutionsTest.java
new file mode 100644
index 0000000..655414e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32SubstitutionsTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.zip.CRC32;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests compiled call to {@link CRC32#update(int, int)}.
+ */
+@SuppressWarnings("javadoc")
+public class CRC32SubstitutionsTest extends GraalCompilerTest {
+
+    public static long update(byte[] input) {
+        CRC32 crc = new CRC32();
+        for (byte b : input) {
+            crc.update(b);
+        }
+        return crc.getValue();
+    }
+
+    @Test
+    public void test1() {
+        test("update", "some string".getBytes());
+    }
+
+    public static long updateBytes(byte[] input, int offset, int length) {
+        CRC32 crc = new CRC32();
+        crc.update(input, offset, length);
+        return crc.getValue();
+    }
+
+    @Test
+    public void test2() {
+        byte[] buf = "some string".getBytes();
+        int off = 0;
+        int len = buf.length;
+        test("updateBytes", buf, off, len);
+    }
+
+    @Test
+    public void test3() throws Throwable {
+        String classfileName = CRC32SubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class";
+        InputStream s = CRC32SubstitutionsTest.class.getResourceAsStream(classfileName);
+        byte[] buf = new byte[s.available()];
+        new DataInputStream(s).readFully(buf);
+        test("updateBytes", buf, 0, buf.length);
+        for (int offset = 1; offset < buf.length; offset++) {
+            test("updateBytes", buf, offset, buf.length - offset);
+        }
+    }
+
+    public static long updateByteBuffer(ByteBuffer buffer) {
+        CRC32 crc = new CRC32();
+        buffer.rewind();
+        crc.update(buffer);
+        return crc.getValue();
+    }
+
+    @Test
+    public void test4() throws Throwable {
+        String classfileName = CRC32SubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class";
+        InputStream s = CRC32SubstitutionsTest.class.getResourceAsStream(classfileName);
+        byte[] buf = new byte[s.available()];
+        new DataInputStream(s).readFully(buf);
+
+        ByteBuffer directBuf = ByteBuffer.allocateDirect(buf.length);
+        directBuf.put(buf);
+        ByteBuffer heapBuf = ByteBuffer.wrap(buf);
+
+        test("updateByteBuffer", directBuf);
+        test("updateByteBuffer", heapBuf);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
new file mode 100644
index 0000000..42d4dd4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.test.GraalTest;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+import jdk.vm.ci.hotspot.VMIntrinsicMethod;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Checks the set of intrinsics implemented by Graal against the set of intrinsics declared by
+ * HotSpot. The purpose of this test is to detect when new intrinsics are added to HotSpot and
+ * process them appropriately in Graal. This will be achieved by working through
+ * {@link #TO_BE_INVESTIGATED} and either implementing the intrinsic or moving it to {@link #IGNORE}
+ * .
+ */
+public class CheckGraalIntrinsics extends GraalTest {
+
+    public static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) {
+        if (intrinsic.name.equals(method.getName())) {
+            if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) {
+                String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/');
+                if (declaringClass.equals(intrinsic.declaringClass)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ResolvedJavaMethod findMethod(Set<ResolvedJavaMethod> methods, VMIntrinsicMethod intrinsic) {
+        for (ResolvedJavaMethod method : methods) {
+            if (match(method, intrinsic)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    private static ResolvedJavaMethod resolveIntrinsic(MetaAccessProvider metaAccess, VMIntrinsicMethod intrinsic) throws ClassNotFoundException {
+        Class<?> c = Class.forName(intrinsic.declaringClass.replace('/', '.'), false, CheckGraalIntrinsics.class.getClassLoader());
+        for (Method javaMethod : c.getDeclaredMethods()) {
+            if (javaMethod.getName().equals(intrinsic.name)) {
+                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(javaMethod);
+                if (intrinsic.descriptor.equals("*")) {
+                    // Signature polymorphic method - name match is enough
+                    return method;
+                } else {
+                    if (method.getSignature().toMethodDescriptor().equals(intrinsic.descriptor)) {
+                        return method;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The HotSpot intrinsics implemented without {@link InvocationPlugin}s or whose
+     * {@link InvocationPlugin} registration is guarded by a condition that is false in the current
+     * VM context.
+     */
+    private static final Set<String> IGNORE = new TreeSet<>();
+
+    /**
+     * The HotSpot intrinsics yet to be implemented or moved to {@link #IGNORE}.
+     */
+    private static final Set<String> TO_BE_INVESTIGATED = new TreeSet<>();
+
+    private static Collection<String> add(Collection<String> c, String... elements) {
+        String[] sorted = elements.clone();
+        Arrays.sort(sorted);
+        for (int i = 0; i < elements.length; i++) {
+            if (!elements[i].equals(sorted[i])) {
+                // Let's keep the list sorted for easier visual inspection
+                fail("Element %d is out of order, \"%s\"", i, elements[i]);
+            }
+        }
+        c.addAll(Arrays.asList(elements));
+        return c;
+    }
+
+    static {
+        add(IGNORE,
+                        // dead
+                        "java/lang/Math.atan2(DD)D",
+                        // Used during stack walking
+                        "java/lang/Throwable.fillInStackTrace()Ljava/lang/Throwable;",
+                        // Marker intrinsic id
+                        "java/lang/invoke/MethodHandle.<compiledLambdaForm>*",
+                        // Marker intrinsic id
+                        "java/lang/invoke/MethodHandle.invoke*",
+                        // Implemented through lowering
+                        "java/lang/ref/Reference.get()Ljava/lang/Object;",
+                        // Used during stack walk
+                        "java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
+                        // Only used by C1
+                        "java/nio/Buffer.checkIndex(I)I",
+                        // dead
+                        "sun/misc/Unsafe.park(ZJ)V",
+                        // dead
+                        "sun/misc/Unsafe.prefetchRead(Ljava/lang/Object;J)V",
+                        // dead
+                        "sun/misc/Unsafe.prefetchReadStatic(Ljava/lang/Object;J)V",
+                        // dead
+                        "sun/misc/Unsafe.prefetchWrite(Ljava/lang/Object;J)V",
+                        // dead
+                        "sun/misc/Unsafe.prefetchWriteStatic(Ljava/lang/Object;J)V",
+                        // dead
+                        "sun/misc/Unsafe.unpark(Ljava/lang/Object;)V");
+
+        add(TO_BE_INVESTIGATED,
+                        // JDK 8
+                        "java/lang/Double.doubleToLongBits(D)J",
+                        "java/lang/Float.floatToIntBits(F)I",
+                        "java/lang/Integer.toString(I)Ljava/lang/String;",
+                        "java/lang/Math.decrementExact(I)I",
+                        "java/lang/Math.decrementExact(J)J",
+                        "java/lang/Math.incrementExact(I)I",
+                        "java/lang/Math.incrementExact(J)J",
+                        "java/lang/Math.max(II)I",
+                        "java/lang/Math.min(II)I",
+                        "java/lang/Math.negateExact(I)I",
+                        "java/lang/Math.negateExact(J)J",
+                        "java/lang/String.<init>(Ljava/lang/String;)V",
+                        "java/lang/String.compareTo(Ljava/lang/String;)I",
+                        "java/lang/String.indexOf(Ljava/lang/String;)I",
+                        "java/lang/StringBuffer.<init>()V",
+                        "java/lang/StringBuffer.<init>(I)V",
+                        "java/lang/StringBuffer.<init>(Ljava/lang/String;)V",
+                        "java/lang/StringBuffer.append(C)Ljava/lang/StringBuffer;",
+                        "java/lang/StringBuffer.append(I)Ljava/lang/StringBuffer;",
+                        "java/lang/StringBuffer.append(Ljava/lang/String;)Ljava/lang/StringBuffer;",
+                        "java/lang/StringBuffer.toString()Ljava/lang/String;",
+                        "java/lang/StringBuilder.<init>()V",
+                        "java/lang/StringBuilder.<init>(I)V",
+                        "java/lang/StringBuilder.<init>(Ljava/lang/String;)V",
+                        "java/lang/StringBuilder.append(C)Ljava/lang/StringBuilder;",
+                        "java/lang/StringBuilder.append(I)Ljava/lang/StringBuilder;",
+                        "java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+                        "java/lang/StringBuilder.toString()Ljava/lang/String;",
+                        "java/lang/reflect/Array.newArray(Ljava/lang/Class;I)Ljava/lang/Object;",
+                        "java/util/Arrays.copyOf([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object;",
+                        "java/util/Arrays.copyOfRange([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;",
+                        "oracle/jrockit/jfr/Timing.counterTime()J",
+                        "oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J",
+                        "oracle/jrockit/jfr/VMJFR.threadID()I",
+                        "sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
+                        "sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I",
+                        "sun/security/provider/DigestBase.implCompressMultiBlock([BII)I",
+                        "sun/security/provider/SHA.implCompress([BI)V",
+                        "sun/security/provider/SHA2.implCompress([BI)V",
+                        "sun/security/provider/SHA5.implCompress([BI)V");
+
+        add(TO_BE_INVESTIGATED,
+                        // JDK 9
+                        "com/sun/crypto/provider/CounterMode.implCrypt([BII[BI)I",
+                        "com/sun/crypto/provider/GHASH.processBlocks([BII[J[J)V",
+                        "java/lang/Math.fma(DDD)D",
+                        "java/lang/Math.fma(FFF)F",
+                        "java/lang/Object.notify()V",
+                        "java/lang/Object.notifyAll()V",
+                        "java/lang/StringCoding.hasNegatives([BII)Z",
+                        "java/lang/StringCoding.implEncodeISOArray([BI[BII)I",
+                        "java/lang/StringLatin1.compareTo([B[B)I",
+                        "java/lang/StringLatin1.compareToUTF16([B[B)I",
+                        "java/lang/StringLatin1.equals([B[B)Z",
+                        "java/lang/StringLatin1.indexOf([BI[BII)I",
+                        "java/lang/StringLatin1.indexOf([B[B)I",
+                        "java/lang/StringLatin1.inflate([BI[BII)V",
+                        "java/lang/StringLatin1.inflate([BI[CII)V",
+                        "java/lang/StringUTF16.compareTo([B[B)I",
+                        "java/lang/StringUTF16.compareToLatin1([B[B)I",
+                        "java/lang/StringUTF16.compress([BI[BII)I",
+                        "java/lang/StringUTF16.compress([CI[BII)I",
+                        "java/lang/StringUTF16.equals([B[B)Z",
+                        "java/lang/StringUTF16.getChar([BI)C",
+                        "java/lang/StringUTF16.getChars([BII[CI)V",
+                        "java/lang/StringUTF16.indexOf([BI[BII)I",
+                        "java/lang/StringUTF16.indexOf([B[B)I",
+                        "java/lang/StringUTF16.indexOfChar([BIII)I",
+                        "java/lang/StringUTF16.indexOfLatin1([BI[BII)I",
+                        "java/lang/StringUTF16.indexOfLatin1([B[B)I",
+                        "java/lang/StringUTF16.putChar([BII)V",
+                        "java/lang/StringUTF16.toBytes([CII)[B",
+                        "java/lang/Thread.onSpinWait()V",
+                        "java/lang/invoke/MethodHandleImpl.isCompileConstant(Ljava/lang/Object;)Z",
+                        "java/math/BigInteger.implMontgomeryMultiply([I[I[IIJ[I)[I",
+                        "java/math/BigInteger.implMontgomerySquare([I[IIJ[I)[I",
+                        "java/math/BigInteger.implMulAdd([I[IIII)I",
+                        "java/math/BigInteger.implSquareToLen([II[II)[I",
+                        "java/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I",
+                        "java/util/stream/Streams$RangeIntSpliterator.forEachRemaining(Ljava/util/function/IntConsumer;)V",
+                        "java/util/zip/Adler32.updateByteBuffer(IJII)I",
+                        "java/util/zip/Adler32.updateBytes(I[BII)I",
+                        "jdk/internal/misc/Unsafe.allocateUninitializedArray0(Ljava/lang/Class;I)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeByteAcquire(Ljava/lang/Object;JBB)B",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeByteRelease(Ljava/lang/Object;JBB)B",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeByteVolatile(Ljava/lang/Object;JBB)B",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeIntAcquire(Ljava/lang/Object;JII)I",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeIntRelease(Ljava/lang/Object;JII)I",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeIntVolatile(Ljava/lang/Object;JII)I",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeLongAcquire(Ljava/lang/Object;JJJ)J",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeLongRelease(Ljava/lang/Object;JJJ)J",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeLongVolatile(Ljava/lang/Object;JJJ)J",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeObjectAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeObjectRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeShortAcquire(Ljava/lang/Object;JSS)S",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S",
+                        "jdk/internal/misc/Unsafe.compareAndExchangeShortVolatile(Ljava/lang/Object;JSS)S",
+                        "jdk/internal/misc/Unsafe.compareAndSwapByte(Ljava/lang/Object;JBB)Z",
+                        "jdk/internal/misc/Unsafe.compareAndSwapShort(Ljava/lang/Object;JSS)Z",
+                        "jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
+                        "jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B",
+                        "jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S",
+                        "jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B",
+                        "jdk/internal/misc/Unsafe.getAndSetShort(Ljava/lang/Object;JS)S",
+                        "jdk/internal/misc/Unsafe.getBooleanAcquire(Ljava/lang/Object;J)Z",
+                        "jdk/internal/misc/Unsafe.getBooleanOpaque(Ljava/lang/Object;J)Z",
+                        "jdk/internal/misc/Unsafe.getByteAcquire(Ljava/lang/Object;J)B",
+                        "jdk/internal/misc/Unsafe.getByteOpaque(Ljava/lang/Object;J)B",
+                        "jdk/internal/misc/Unsafe.getCharAcquire(Ljava/lang/Object;J)C",
+                        "jdk/internal/misc/Unsafe.getCharOpaque(Ljava/lang/Object;J)C",
+                        "jdk/internal/misc/Unsafe.getDoubleAcquire(Ljava/lang/Object;J)D",
+                        "jdk/internal/misc/Unsafe.getDoubleOpaque(Ljava/lang/Object;J)D",
+                        "jdk/internal/misc/Unsafe.getFloatAcquire(Ljava/lang/Object;J)F",
+                        "jdk/internal/misc/Unsafe.getFloatOpaque(Ljava/lang/Object;J)F",
+                        "jdk/internal/misc/Unsafe.getIntAcquire(Ljava/lang/Object;J)I",
+                        "jdk/internal/misc/Unsafe.getIntOpaque(Ljava/lang/Object;J)I",
+                        "jdk/internal/misc/Unsafe.getLongAcquire(Ljava/lang/Object;J)J",
+                        "jdk/internal/misc/Unsafe.getLongOpaque(Ljava/lang/Object;J)J",
+                        "jdk/internal/misc/Unsafe.getObjectAcquire(Ljava/lang/Object;J)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.getObjectOpaque(Ljava/lang/Object;J)Ljava/lang/Object;",
+                        "jdk/internal/misc/Unsafe.getShortAcquire(Ljava/lang/Object;J)S",
+                        "jdk/internal/misc/Unsafe.getShortOpaque(Ljava/lang/Object;J)S",
+                        "jdk/internal/misc/Unsafe.park(ZJ)V",
+                        "jdk/internal/misc/Unsafe.putBooleanOpaque(Ljava/lang/Object;JZ)V",
+                        "jdk/internal/misc/Unsafe.putByteOpaque(Ljava/lang/Object;JB)V",
+                        "jdk/internal/misc/Unsafe.putCharOpaque(Ljava/lang/Object;JC)V",
+                        "jdk/internal/misc/Unsafe.putDoubleOpaque(Ljava/lang/Object;JD)V",
+                        "jdk/internal/misc/Unsafe.putFloatOpaque(Ljava/lang/Object;JF)V",
+                        "jdk/internal/misc/Unsafe.putIntOpaque(Ljava/lang/Object;JI)V",
+                        "jdk/internal/misc/Unsafe.putLongOpaque(Ljava/lang/Object;JJ)V",
+                        "jdk/internal/misc/Unsafe.putObjectOpaque(Ljava/lang/Object;JLjava/lang/Object;)V",
+                        "jdk/internal/misc/Unsafe.putShortOpaque(Ljava/lang/Object;JS)V",
+                        "jdk/internal/misc/Unsafe.unpark(Ljava/lang/Object;)V",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapByte(Ljava/lang/Object;JBB)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapByteAcquire(Ljava/lang/Object;JBB)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapByteRelease(Ljava/lang/Object;JBB)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapByteVolatile(Ljava/lang/Object;JBB)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapInt(Ljava/lang/Object;JII)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapIntAcquire(Ljava/lang/Object;JII)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapIntRelease(Ljava/lang/Object;JII)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapIntVolatile(Ljava/lang/Object;JII)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapLong(Ljava/lang/Object;JJJ)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapLongAcquire(Ljava/lang/Object;JJJ)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapLongRelease(Ljava/lang/Object;JJJ)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapLongVolatile(Ljava/lang/Object;JJJ)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapShort(Ljava/lang/Object;JSS)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapShortAcquire(Ljava/lang/Object;JSS)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapShortRelease(Ljava/lang/Object;JSS)Z",
+                        "jdk/internal/misc/Unsafe.weakCompareAndSwapShortVolatile(Ljava/lang/Object;JSS)Z",
+                        "jdk/internal/util/Preconditions.checkIndex(IILjava/util/function/BiFunction;)I",
+                        "jdk/jfr/internal/JVM.counterTime()J",
+                        "jdk/jfr/internal/JVM.getBufferWriter()Ljava/lang/Object;",
+                        "jdk/jfr/internal/JVM.getClassId(Ljava/lang/Class;)J",
+                        "sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray([CI[BII)I",
+                        "sun/security/provider/DigestBase.implCompressMultiBlock0([BII)I",
+                        "sun/security/provider/SHA.implCompress0([BI)V",
+                        "sun/security/provider/SHA2.implCompress0([BI)V",
+                        "sun/security/provider/SHA5.implCompress0([BI)V");
+
+        if (!getHostArchitectureName().equals("amd64")) {
+            add(TO_BE_INVESTIGATED,
+                            // Can we implement these on non-AMD64 platforms? C2 seems to.
+                            "sun/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I",
+                            "sun/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J",
+                            "sun/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I",
+                            "sun/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J",
+                            "sun/misc/Unsafe.getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;");
+            // JDK 9
+            add(TO_BE_INVESTIGATED,
+                            "jdk/internal/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I",
+                            "jdk/internal/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J",
+                            "jdk/internal/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I",
+                            "jdk/internal/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J",
+                            "jdk/internal/misc/Unsafe.getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;",
+                            "jdk/internal/misc/Unsafe.getCharUnaligned(Ljava/lang/Object;J)C",
+                            "jdk/internal/misc/Unsafe.getIntUnaligned(Ljava/lang/Object;J)I",
+                            "jdk/internal/misc/Unsafe.getLongUnaligned(Ljava/lang/Object;J)J",
+                            "jdk/internal/misc/Unsafe.getShortUnaligned(Ljava/lang/Object;J)S",
+                            "jdk/internal/misc/Unsafe.putCharUnaligned(Ljava/lang/Object;JC)V",
+                            "jdk/internal/misc/Unsafe.putIntUnaligned(Ljava/lang/Object;JI)V",
+                            "jdk/internal/misc/Unsafe.putLongUnaligned(Ljava/lang/Object;JJ)V",
+                            "jdk/internal/misc/Unsafe.putShortUnaligned(Ljava/lang/Object;JS)V");
+        }
+
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        GraalHotSpotVMConfig config = rt.getVMConfig();
+
+        /*
+         * These are known to be implemented but the platform dependent conditions for when they are
+         * enabled are complex so just ignore them all the time.
+         */
+        add(IGNORE,
+                        "java/lang/Integer.bitCount(I)I",
+                        "java/lang/Integer.numberOfLeadingZeros(I)I",
+                        "java/lang/Integer.numberOfTrailingZeros(I)I",
+                        "java/lang/Long.bitCount(J)I",
+                        "java/lang/Long.numberOfLeadingZeros(J)I",
+                        "java/lang/Long.numberOfTrailingZeros(J)I");
+
+        if (!config.useCRC32Intrinsics) {
+            // Registration of the CRC32 plugins is guarded by UseCRC32Intrinsics
+            add(IGNORE, "java/util/zip/CRC32.update(II)I");
+            if (JAVA_SPECIFICATION_VERSION < 9) {
+                add(IGNORE,
+                                "java/util/zip/CRC32.updateByteBuffer(IJII)I",
+                                "java/util/zip/CRC32.updateBytes(I[BII)I");
+            } else {
+                add(IGNORE,
+                                "java/util/zip/CRC32.updateByteBuffer0(IJII)I",
+                                "java/util/zip/CRC32.updateBytes0(I[BII)I",
+                                "java/util/zip/CRC32C.updateBytes(I[BII)I",
+                                "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
+            }
+        } else {
+            if (JAVA_SPECIFICATION_VERSION >= 9) {
+                add(TO_BE_INVESTIGATED,
+                                "java/util/zip/CRC32C.updateBytes(I[BII)I",
+                                "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
+            }
+        }
+
+        if (!config.useAESIntrinsics) {
+            // Registration of the AES plugins is guarded by UseAESIntrinsics
+            if (JAVA_SPECIFICATION_VERSION < 9) {
+                add(IGNORE,
+                                "com/sun/crypto/provider/AESCrypt.decryptBlock([BI[BI)V",
+                                "com/sun/crypto/provider/AESCrypt.encryptBlock([BI[BI)V",
+                                "com/sun/crypto/provider/CipherBlockChaining.decrypt([BII[BI)I",
+                                "com/sun/crypto/provider/CipherBlockChaining.encrypt([BII[BI)I");
+            } else {
+                add(IGNORE,
+                                "com/sun/crypto/provider/AESCrypt.implDecryptBlock([BI[BI)V",
+                                "com/sun/crypto/provider/AESCrypt.implEncryptBlock([BI[BI)V",
+                                "com/sun/crypto/provider/CipherBlockChaining.implDecrypt([BII[BI)I",
+                                "com/sun/crypto/provider/CipherBlockChaining.implEncrypt([BII[BI)I");
+            }
+        }
+        if (!config.useMultiplyToLenIntrinsic()) {
+            // Registration of the AES plugins is guarded by UseAESIntrinsics
+            if (JAVA_SPECIFICATION_VERSION < 9) {
+                add(IGNORE, "java/math/BigInteger.multiplyToLen([II[II[I)[I");
+            } else {
+                add(IGNORE, "java/math/BigInteger.implMultiplyToLen([II[II[I)[I");
+            }
+        }
+    }
+
+    private static String getHostArchitectureName() {
+        String arch = System.getProperty("os.arch");
+        if (arch.equals("x86_64")) {
+            arch = "amd64";
+        } else if (arch.equals("sparcv9")) {
+            arch = "sparc";
+        }
+        return arch;
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test() throws ClassNotFoundException {
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        HotSpotProviders providers = rt.getHostBackend().getProviders();
+        Map<ResolvedJavaMethod, Object> impl = new HashMap<>();
+        Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins();
+        InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins();
+        for (ResolvedJavaMethod method : invocationPlugins.getMethods()) {
+            InvocationPlugin plugin = invocationPlugins.lookupInvocation(method);
+            assert plugin != null;
+            impl.put(method, plugin);
+        }
+
+        Set<ResolvedJavaMethod> methods = invocationPlugins.getMethods();
+        HotSpotVMConfigStore store = rt.getVMConfig().getStore();
+        List<VMIntrinsicMethod> intrinsics = store.getIntrinsics();
+
+        List<String> missing = new ArrayList<>();
+        for (VMIntrinsicMethod intrinsic : intrinsics) {
+            ResolvedJavaMethod method = findMethod(methods, intrinsic);
+            if (method == null) {
+                method = resolveIntrinsic(providers.getMetaAccess(), intrinsic);
+
+                IntrinsicMethod intrinsicMethod = null;
+                if (method != null) {
+                    intrinsicMethod = providers.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(method);
+                    if (intrinsicMethod != null) {
+                        continue;
+                    }
+                }
+                String m = String.format("%s.%s%s", intrinsic.declaringClass, intrinsic.name, intrinsic.descriptor);
+                if (!TO_BE_INVESTIGATED.contains(m) && !IGNORE.contains(m)) {
+                    missing.add(m);
+                }
+            }
+        }
+
+        if (!missing.isEmpty()) {
+            Collections.sort(missing);
+            String missingString = missing.stream().collect(Collectors.joining(String.format("%n    ")));
+            fail("missing Graal intrinsics for:%n    %s", missingString);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java
new file mode 100644
index 0000000..7b22ece
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+public class ClassSubstitutionsTests extends GraalCompilerTest {
+
+    public Number instanceField;
+
+    public Object[] arrayField;
+
+    public String[] stringArrayField;
+
+    @SuppressWarnings("try")
+    protected StructuredGraph test(final String snippet) {
+        try (Scope s = Debug.scope("ClassSubstitutionsTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            assertNotInGraph(graph, Invoke.class);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    public boolean constantIsArray() {
+        return "".getClass().isArray();
+    }
+
+    public boolean constantIsInterface() {
+        return "".getClass().isInterface();
+    }
+
+    public boolean constantIsPrimitive() {
+        return "".getClass().isPrimitive();
+    }
+
+    @Test
+    public void testIsArray() {
+        testConstantReturn("constantIsArray", 0);
+    }
+
+    @Test
+    public void testIsInterface() {
+        testConstantReturn("constantIsInterface", 0);
+    }
+
+    @Test
+    public void testIsPrimitive() {
+        testConstantReturn("constantIsPrimitive", 0);
+    }
+
+    public boolean fieldIsNotArray() {
+        if (instanceField != null) {
+            // The base type of instanceField is not Object or an Interface, so it's provably an
+            // instance type, so isArray will always return false.
+            return instanceField.getClass().isArray();
+        }
+        return false;
+    }
+
+    @Test
+    public void testFieldIsNotArray() {
+        testConstantReturn("fieldIsNotArray", 0);
+    }
+
+    public boolean foldComponentType() {
+        return stringArrayField.getClass().getComponentType() == String.class;
+    }
+
+    @Test
+    public void testFoldComponentType() {
+        testConstantReturn("foldComponentType", 1);
+    }
+
+    @Test
+    public void testFieldIsArray() {
+        testConstantReturn("fieldIsArray", 1);
+    }
+
+    public boolean fieldIsArray() {
+        if (arrayField != null) {
+            // The base type of arrayField is an array of some sort so isArray will always return
+            // true.
+            return arrayField.getClass().isArray();
+        }
+        return true;
+    }
+
+    private static class A {
+    }
+
+    private static class B extends A {
+    }
+
+    private static class C {
+    }
+
+    private static final A a = new A();
+    private static final B b = new B();
+    private static final C c = new C();
+
+    public boolean classIsAssignable1() {
+        return a.getClass().isAssignableFrom(a.getClass());
+    }
+
+    public boolean classIsAssignable2() {
+        return a.getClass().isAssignableFrom(b.getClass());
+    }
+
+    public boolean classIsAssignable3() {
+        return a.getClass().isAssignableFrom(c.getClass());
+    }
+
+    public boolean classIsAssignable4() {
+        return b.getClass().isAssignableFrom(a.getClass());
+    }
+
+    public boolean classIsAssignable5() {
+        return c.getClass().isAssignableFrom(b.getClass());
+    }
+
+    public boolean classIsAssignable6() {
+        return int.class.isAssignableFrom(b.getClass());
+    }
+
+    public boolean classIsAssignable7() {
+        return int.class.isAssignableFrom(int.class);
+    }
+
+    @Test
+    public void testClassIsAssignable() {
+        testConstantReturn("classIsAssignable1", 1);
+        testConstantReturn("classIsAssignable2", 1);
+        testConstantReturn("classIsAssignable3", 0);
+        testConstantReturn("classIsAssignable4", 0);
+        testConstantReturn("classIsAssignable5", 0);
+        testConstantReturn("classIsAssignable6", 0);
+        testConstantReturn("classIsAssignable7", 1);
+    }
+
+    private void testConstantReturn(String name, Object value) {
+        StructuredGraph result = test(name);
+        ReturnNode ret = result.getNodes(ReturnNode.TYPE).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count());
+
+        assertDeepEquals(true, ret.result().isConstant());
+        assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java
new file mode 100644
index 0000000..481a338
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.CompileTheWorld;
+import org.graalvm.compiler.hotspot.CompileTheWorld.Config;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+
+/**
+ * Tests {@link CompileTheWorld} functionality.
+ */
+public class CompileTheWorldTest extends GraalCompilerTest {
+
+    @Test
+    public void testJDK() throws Throwable {
+        boolean originalSetting = ExitVMOnException.getValue();
+        // Compile a couple classes in rt.jar
+        HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
+        System.setProperty(CompileTheWorld.LIMITMODS_PROPERTY_NAME, "java.base");
+        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, new Config("Inline=false"), 1, 5, null, null, true).compile();
+        assert ExitVMOnException.getValue() == originalSetting;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompressedOopTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompressedOopTest.java
new file mode 100644
index 0000000..281ecb1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompressedOopTest.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.test;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * The following tests perform object/array equality and assignments in various ways. The selected
+ * cases have been the problematic ones while implementing the Compressed Oops support.
+ */
+public class CompressedOopTest extends GraalCompilerTest {
+
+    private HotSpotInstalledCode getInstalledCode(String name, Class<?>... parameterTypes) throws Exception {
+        final ResolvedJavaMethod javaMethod = getResolvedJavaMethod(getClass(), name, parameterTypes);
+        final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(javaMethod);
+        return installedBenchmarkCode;
+    }
+
+    @Test
+    public void test() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("fieldTest", Object.class);
+        Container c1 = new Container();
+        Assert.assertEquals(c1.b, installedBenchmarkCode.executeVarargs(c1));
+    }
+
+    public static Object fieldTest(Object c1) {
+        ((Container) c1).a = ((Container) c1).b;
+        return ((Container) c1).a;
+    }
+
+    @Test
+    public void test1() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("arrayTest", Object.class, Object.class, Object.class);
+        ArrayContainer ac = new ArrayContainer();
+        Assert.assertEquals(ac.a[9], installedBenchmarkCode.executeVarargs(ac.a, 0, 9));
+        Assert.assertEquals(ac.a[8], installedBenchmarkCode.executeVarargs(ac.a, 1, 8));
+        Assert.assertEquals(ac.a[7], installedBenchmarkCode.executeVarargs(ac.a, 2, 7));
+        Assert.assertEquals(ac.a[6], installedBenchmarkCode.executeVarargs(ac.a, 3, 6));
+        Assert.assertEquals(ac.a[5], installedBenchmarkCode.executeVarargs(ac.a, 4, 5));
+        Assert.assertEquals(ac.a[4], installedBenchmarkCode.executeVarargs(ac.a, 5, 4));
+        Assert.assertEquals(ac.a[3], installedBenchmarkCode.executeVarargs(ac.a, 6, 3));
+        Assert.assertEquals(ac.a[2], installedBenchmarkCode.executeVarargs(ac.a, 7, 2));
+        Assert.assertEquals(ac.a[1], installedBenchmarkCode.executeVarargs(ac.a, 8, 1));
+        Assert.assertEquals(ac.a[0], installedBenchmarkCode.executeVarargs(ac.a, 9, 0));
+    }
+
+    public static Object arrayTest(Object c1, Object c2, Object c3) {
+        Object[] array = (Object[]) c1;
+        int initialIndex = ((Integer) c2).intValue();
+        int replacingIndex = ((Integer) c3).intValue();
+        array[initialIndex] = array[replacingIndex];
+        return array[initialIndex];
+    }
+
+    @Test
+    public void test2() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("arrayCopyTest", Object.class, Object.class);
+        ArrayContainer source = new ArrayContainer();
+        ArrayContainer destination = new ArrayContainer();
+        Assert.assertEquals(source.a.length, destination.a.length);
+        Assert.assertFalse(Arrays.equals(source.a, destination.a));
+        installedBenchmarkCode.executeVarargs(source.a, destination.a);
+        Assert.assertArrayEquals(source.a, destination.a);
+    }
+
+    public static void arrayCopyTest(Object c1, Object c2) {
+        Object[] source = (Object[]) c1;
+        Object[] destination = (Object[]) c2;
+        System.arraycopy(source, 0, destination, 0, source.length);
+    }
+
+    @Test
+    public void test3() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("compareAndSwapTest", Object.class, Object.class, Object.class);
+        Object initial = new Object();
+        Object replacement = new Object();
+        AtomicReference<Object> cas = new AtomicReference<>();
+        Assert.assertEquals(cas.get(), null);
+        installedBenchmarkCode.executeVarargs(cas, null, initial);
+        Assert.assertEquals(cas.get(), initial);
+        installedBenchmarkCode.executeVarargs(cas, initial, replacement);
+        Assert.assertEquals(cas.get(), replacement);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void compareAndSwapTest(Object c1, Object c2, Object c3) throws ClassCastException {
+        AtomicReference<Object> cas = (AtomicReference<Object>) c1;
+        cas.compareAndSet(c2, c3);
+    }
+
+    @Test
+    public void test4() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("charArrayCopyTest", Object.class, Object.class, Object.class);
+        StringContainer1 source1 = new StringContainer1();
+        StringContainer2 source2 = new StringContainer2();
+        char[] result = new char[source1.value.length + source2.value.length];
+        installedBenchmarkCode.executeVarargs(source1.value, source2.value, result);
+        Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result);
+    }
+
+    public static char[] charArrayCopyTest(Object c1, Object c2, Object c3) {
+        char[] source1 = (char[]) c1;
+        char[] source2 = (char[]) c2;
+        char[] result = (char[]) c3;
+        for (int i = 0; i < source1.length; i++) {
+            result[i] = source1[i];
+        }
+
+        for (int i = 0; i < source2.length; i++) {
+            result[source1.length + i] = source2[i];
+        }
+        return result;
+    }
+
+    @Test
+    public void test5() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("charContainerArrayCopyTest", Object.class, Object.class, Object.class);
+        StringContainer1 source1 = new StringContainer1();
+        StringContainer2 source2 = new StringContainer2();
+        char[] result = new char[source1.value.length + source2.value.length];
+        installedBenchmarkCode.executeVarargs(source1, source2, result);
+        Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result);
+    }
+
+    public static char[] charContainerArrayCopyTest(Object c1, Object c2, Object c3) {
+        char[] source1 = ((StringContainer1) c1).value;
+        char[] source2 = ((StringContainer2) c2).value;
+        char[] result = (char[]) c3;
+        for (int i = 0; i < source1.length; i++) {
+            result[i] = source1[i];
+        }
+        for (int i = 0; i < source2.length; i++) {
+            result[source1.length + i] = source2[i];
+        }
+        return result;
+    }
+
+    @Test
+    public void test6() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringCopyTest", Object.class, Object.class);
+        String a = new String("Test ");
+        String b = new String("String");
+        String c = (String) installedBenchmarkCode.executeVarargs(a, b);
+        Assert.assertTrue(c.equals("Test String"));
+    }
+
+    public static String stringCopyTest(Object c1, Object c2) {
+        String source = (String) c1;
+        String destination = (String) c2;
+        return source + destination;
+    }
+
+    @Test
+    public void test7() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("queueTest", Object.class, Object.class);
+        ArrayDeque<Object> q = new ArrayDeque<>();
+        Object[] objects = new Object[512];
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = new Object();
+        }
+        int j = 0;
+        while (j < objects.length) {
+            if (!installedBenchmarkCode.isValid()) {
+                // This can get invalidated due to lack of MDO update
+                installedBenchmarkCode = getInstalledCode("queueTest", Object.class, Object.class);
+            }
+            installedBenchmarkCode.executeVarargs(q, objects[j]);
+            j++;
+        }
+
+        System.gc();
+        Assert.assertTrue(q.size() == objects.length);
+        Assert.assertTrue(!q.isEmpty());
+        j = 0;
+        while (j < objects.length) {
+            Assert.assertTrue(objects[j] == q.remove());
+            j++;
+        }
+
+        Assert.assertTrue(q.size() == 0);
+        Assert.assertTrue(q.isEmpty());
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void queueTest(Object c1, Object c2) {
+        ArrayDeque<Object> queue = (ArrayDeque<Object>) c1;
+        queue.add(c2);
+    }
+
+    @Test
+    public void test8() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTest", Object.class);
+        List<Object> list = new ArrayList<>();
+        for (int i = 0; i < 512; i++) {
+            list.add(new Object());
+        }
+        Object[] array = (Object[]) installedBenchmarkCode.executeVarargs(list);
+        Assert.assertTrue(list.size() == array.length);
+        int i = 0;
+        for (Object obj : list) {
+            Assert.assertTrue(obj == array[i]);
+            i++;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object[] unmodListTest(Object c1) {
+        List<Object> queue = (ArrayList<Object>) c1;
+        Object[] result = Collections.unmodifiableCollection(queue).toArray(new Object[queue.size()]);
+        return result;
+    }
+
+    @Test
+    public void test9() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTest", Object.class);
+        List<Object> list = new ArrayList<>();
+        Object[] array = (Object[]) installedBenchmarkCode.executeVarargs(list);
+        Assert.assertTrue(list.size() == array.length);
+    }
+
+    public void test10() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("constantTest", Object.class);
+        Container c = new Container();
+        Assert.assertFalse((boolean) installedBenchmarkCode.executeVarargs(c));
+    }
+
+    public static Boolean constantTest(Object c1) {
+        ConstantContainer container = (ConstantContainer) c1;
+        return container.a.equals(container.b);
+    }
+
+    @Test
+    public void test11() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringEqualsTest", Object.class, Object.class);
+        String s1 = new String("Test");
+        String s2 = new String("Test");
+        boolean result = ((Boolean) (installedBenchmarkCode.executeVarargs(s1, s2))).booleanValue();
+        Assert.assertTrue(result);
+    }
+
+    public static Boolean stringEqualsTest(Object c1, Object c2) {
+        return ((String) c1).equals(c2);
+    }
+
+    @Test
+    public void test12() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringConstantEqualsTest", Object.class);
+        String s1 = new String("Test");
+        boolean result = ((Boolean) (installedBenchmarkCode.executeVarargs(s1))).booleanValue();
+        Assert.assertTrue(result);
+    }
+
+    public static Boolean stringConstantEqualsTest(Object c1) {
+        return "Test".equals(c1);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object[] unmodListTestByte(Object c1) {
+        List<Byte> queue = (ArrayList<Byte>) c1;
+        Byte[] result = Collections.unmodifiableCollection(queue).toArray(new Byte[queue.size()]);
+        return result;
+    }
+
+    @Test
+    public void test13() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTestByte", Object.class);
+        List<Byte> list = new ArrayList<>();
+        Byte[] array = (Byte[]) installedBenchmarkCode.executeVarargs(list);
+        Assert.assertTrue(list.size() == array.length);
+    }
+
+    @Test
+    public void test14() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTest", Object.class, Object.class);
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
+        Assert.assertTrue(buffer.length() == 28);
+        String a = new String("TestTestTestTestTestTestTest");
+        installedBenchmarkCode.executeVarargs(buffer, a.toCharArray());
+        Assert.assertTrue(buffer.length() == 56);
+        Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
+    }
+
+    public static void stringBuilderTest(Object c1, Object c2) {
+        StringBuilder source = (StringBuilder) c1;
+        char[] add = (char[]) c2;
+        for (int i = 0; i < add.length; i++) {
+            source.append(add[i]);
+        }
+    }
+
+    @Test
+    public void test15() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTestIn");
+        installedBenchmarkCode.executeVarargs();
+    }
+
+    public static void stringBuilderTestIn() {
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
+        Assert.assertTrue(buffer.length() == 28);
+        String a = new String("TestTestTestTestTestTestTest");
+        char[] add = a.toCharArray();
+        for (int i = 0; i < add.length; i++) {
+            buffer.append(add[i]);
+        }
+        Assert.assertTrue(buffer.length() == 56);
+        Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
+    }
+
+    @Test
+    public void test16() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderArrayCopy");
+        installedBenchmarkCode.executeVarargs();
+    }
+
+    public static void stringBuilderArrayCopy() {
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
+        Assert.assertTrue(buffer.length() == 28);
+        String a = new String("TestTestTestTestTestTestTest");
+        char[] dst = new char[buffer.length() * 2];
+        System.arraycopy(buffer.toString().toCharArray(), 0, dst, 0, buffer.length());
+        System.arraycopy(a.toCharArray(), 0, dst, buffer.length(), buffer.length());
+        Assert.assertTrue(dst.length == 56);
+        Assert.assertTrue(new String(dst).equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
+    }
+
+    @Test
+    public void test17() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringFormat");
+        installedBenchmarkCode.executeVarargs();
+    }
+
+    public static void stringFormat() {
+        String.format("Hello %d", 0);
+        String.format("Hello %d", -11);
+        String.format("Hello %d", -2147483648);
+    }
+
+    @Test
+    public void test18() throws Exception {
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilder");
+        StringBuilder b = (StringBuilder) installedBenchmarkCode.executeVarargs();
+        Assert.assertTrue(b.capacity() == 16);
+        Assert.assertTrue(b.length() == 0);
+    }
+
+    public static Object stringBuilder() {
+        return new StringBuilder();
+    }
+
+    static class Container {
+
+        public Object a = new Object();
+        public Object b = new Object();
+    }
+
+    static class ArrayContainer {
+
+        public Object[] a = new Object[10];
+
+        ArrayContainer() {
+            for (int i = 0; i < 10; i++) {
+                a[i] = new Object();
+            }
+        }
+    }
+
+    static class HashMapContainer {
+
+        public HashMap<Object, Object> a = new HashMap<>();
+
+        HashMapContainer() {
+            for (int i = 0; i < 10; i++) {
+                a.put(new Object(), new Object());
+            }
+        }
+    }
+
+    static class StringContainer1 {
+
+        public char[] value = new char[5];
+
+        StringContainer1() {
+            value[0] = 'T';
+            value[1] = 'e';
+            value[2] = 's';
+            value[3] = 't';
+            value[4] = ' ';
+
+        }
+    }
+
+    static class StringContainer2 {
+
+        public char[] value = new char[6];
+
+        StringContainer2() {
+            value[0] = 'S';
+            value[1] = 't';
+            value[2] = 'r';
+            value[3] = 'i';
+            value[4] = 'n';
+            value[5] = 'g';
+        }
+    }
+
+    static class ConstantContainer {
+
+        public final Object a = new Object();
+        public final Object b = new Object();
+
+        ConstantContainer() {
+
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java
new file mode 100644
index 0000000..2585d36
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports;
+import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ConstantPoolSubstitutionsTests extends GraalCompilerTest implements Opcodes {
+
+    @SuppressWarnings("try")
+    protected StructuredGraph test(final String snippet) {
+        ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet));
+        try (Scope s = Debug.scope("ConstantPoolSubstitutionsTests", method)) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            assertNotInGraph(graph, Invoke.class);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    private static Object getConstantPoolForObject() {
+        String miscPackage = Java8OrEarlier ? "sun.misc" : "jdk.internal.misc";
+        try {
+            Class<?> sharedSecretsClass = Class.forName(miscPackage + ".SharedSecrets");
+            Class<?> javaLangAccessClass = Class.forName(miscPackage + ".JavaLangAccess");
+            Object jla = sharedSecretsClass.getDeclaredMethod("getJavaLangAccess").invoke(null);
+            return javaLangAccessClass.getDeclaredMethod("getConstantPool", Class.class).invoke(jla, Object.class);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Get the test methods from the generated class.
+     */
+    @Override
+    protected Method getMethod(String methodName) {
+        Class<?> cl;
+        try {
+            cl = LOADER.findClass(AsmLoader.NAME);
+            addExports(cl);
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError(e);
+        }
+        return getMethod(cl, methodName);
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        addExports(AsmLoader.class);
+    }
+
+    /**
+     * This test uses some API hidden by the JDK9 module system.
+     */
+    private static void addExports(Class<?> c) {
+        if (!Util.Java8OrEarlier) {
+            Object javaBaseModule = getModule.invoke(String.class);
+            Object cModule = getModule.invoke(c);
+            addExports.invokeStatic(javaBaseModule, "jdk.internal.reflect", cModule);
+            addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", cModule);
+        }
+    }
+
+    /**
+     * Disables these tests until we know how to dynamically export the {@code jdk.internal.reflect}
+     * package from the {@code java.base} module to the unnamed module associated with
+     * {@link AsmLoader}. Without such an export, the test fails as follows:
+     *
+     * <pre>
+     * Caused by: java.lang.IllegalAccessError: class org.graalvm.compiler.hotspot.test.ConstantPoolTest
+     * (in unnamed module @0x57599b23) cannot access class jdk.internal.reflect.ConstantPool (in
+     * module java.base) because module java.base does not export jdk.internal.reflect to unnamed
+     * module @0x57599b23
+     * </pre>
+     */
+    private static void assumeJDK8() {
+        // Assume.assumeTrue(Java8OrEarlier);
+    }
+
+    @Test
+    public void testGetSize() {
+        assumeJDK8();
+        Object cp = getConstantPoolForObject();
+        test("getSize", cp);
+    }
+
+    @Test
+    public void testGetIntAt() {
+        assumeJDK8();
+        test("getIntAt");
+    }
+
+    @Test
+    public void testGetLongAt() {
+        assumeJDK8();
+        test("getLongAt");
+    }
+
+    @Test
+    public void testGetFloatAt() {
+        assumeJDK8();
+        test("getFloatAt");
+    }
+
+    @Test
+    public void testGetDoubleAt() {
+        assumeJDK8();
+        test("getDoubleAt");
+    }
+
+    // @Test
+    public void testGetUTF8At() {
+        assumeJDK8();
+        test("getUTF8At");
+    }
+
+    private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName();
+    private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/');
+
+    private static AsmLoader LOADER = new AsmLoader(ConstantPoolSubstitutionsTests.class.getClassLoader());
+
+    public static class AsmLoader extends ClassLoader {
+        Class<?> loaded;
+
+        static final String NAME = PACKAGE_NAME + ".ConstantPoolTest";
+
+        public AsmLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(NAME)) {
+                if (loaded != null) {
+                    return loaded;
+                }
+                byte[] bytes = generateClass();
+                return (loaded = defineClass(name, bytes, 0, bytes.length));
+            } else {
+                return super.findClass(name);
+            }
+        }
+    }
+
+    // @formatter:off
+    /*
+    static class ConstantPoolTest {
+        public static int getSize(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getSize();
+        }
+
+        public static int getIntAt(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getIntAt(0);
+        }
+
+        public static long getLongAt(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getLongAt(0);
+        }
+
+        public static float getFloatAt(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getFloatAt(0);
+        }
+
+        public static double getDoubleAt(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getDoubleAt(0);
+        }
+
+        public static String getUTF8At(Object o) {
+            ConstantPool cp = (ConstantPool) o;
+            return cp.getUTF8At(0);
+        }
+    }
+    */
+    // @formatter:on
+    private static byte[] generateClass() {
+
+        ClassWriter cw = new ClassWriter(0);
+        MethodVisitor mv;
+
+        cw.visit(52, ACC_SUPER, PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", null, "java/lang/Object", null);
+        cw.visitInnerClass(PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", PACKAGE_NAME_INTERNAL + "/ConstantPoolSubstitutionsTests", "ConstantPoolTest",
+                        ACC_STATIC);
+        String constantPool = Java8OrEarlier ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool";
+
+        mv = cw.visitMethod(0, "<init>", "()V", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getSize", "(Ljava/lang/Object;)I", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getSize", "()I", false);
+        mv.visitInsn(IRETURN);
+        mv.visitMaxs(1, 3);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getIntAt", "(Ljava/lang/Object;)I", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(ICONST_0);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getIntAt", "(I)I", false);
+        mv.visitInsn(IRETURN);
+        mv.visitMaxs(2, 3);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getLongAt", "(Ljava/lang/Object;)J", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(ICONST_0);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getLongAt", "(I)J", false);
+        mv.visitInsn(LRETURN);
+        mv.visitMaxs(2, 3);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getFloatAt", "(Ljava/lang/Object;)F", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(ICONST_0);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getFloatAt", "(I)F", false);
+        mv.visitInsn(FRETURN);
+        mv.visitMaxs(2, 3);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getDoubleAt", "(Ljava/lang/Object;)D", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(ICONST_0);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getDoubleAt", "(I)D", false);
+        mv.visitInsn(DRETURN);
+        mv.visitMaxs(2, 3);
+        mv.visitEnd();
+
+        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "getUTF8At", "(Ljava/lang/Object;)Ljava/lang/String;", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitTypeInsn(CHECKCAST, constantPool);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitInsn(ICONST_0);
+        mv.visitMethodInsn(INVOKEVIRTUAL, constantPool, "getUTF8At", "(I)Ljava/lang/String;", false);
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(2, 3);
+        mv.visitEnd();
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java
new file mode 100644
index 0000000..445c48e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.OpaqueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class DataPatchTest extends HotSpotGraalCompilerTest {
+
+    public static double doubleSnippet() {
+        return 84.72;
+    }
+
+    @Test
+    public void doubleTest() {
+        test("doubleSnippet");
+    }
+
+    public static Object oopSnippet() {
+        return "asdf";
+    }
+
+    @Test
+    public void oopTest() {
+        test("oopSnippet");
+    }
+
+    private static Object compressUncompress(Object obj) {
+        return obj;
+    }
+
+    public static Object narrowOopSnippet() {
+        return compressUncompress("narrowAsdf");
+    }
+
+    @Test
+    public void narrowOopTest() {
+        Assume.assumeTrue("skipping narrow oop data patch test", runtime().getVMConfig().useCompressedOops);
+        test("narrowOopSnippet");
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        Registration r = new Registration(invocationPlugins, DataPatchTest.class);
+        r.register1("compressUncompress", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                CompressEncoding encoding = runtime().getVMConfig().getOopEncoding();
+                ValueNode compressed = b.add(CompressionNode.compress(arg, encoding));
+                ValueNode proxy = b.add(new OpaqueNode(compressed));
+                b.addPush(JavaKind.Object, CompressionNode.uncompress(proxy, encoding));
+                return true;
+            }
+        });
+        return super.editGraphBuilderConfiguration(conf);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java
new file mode 100644
index 0000000..b1099a4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ExplicitExceptionTest extends GraalCompilerTest {
+
+    private int expectedForeignCallCount;
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method) {
+        InstalledCode installedCode = super.getCode(method);
+        assertDeepEquals(expectedForeignCallCount, lastCompiledGraph.getNodes().filter(ForeignCallNode.class).count());
+        return installedCode;
+    }
+
+    public static int testAIOOBESnippet(int[] array) {
+        return array[10];
+    }
+
+    @Test
+    public void testAIOOBE() {
+        int[] array = new int[4];
+        for (int i = 0; i < 10000; i++) {
+            try {
+                testAIOOBESnippet(array);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // nothing to do
+            }
+        }
+        expectedForeignCallCount = 2;
+        test("testAIOOBESnippet", array);
+    }
+
+    public static int testNPEArraySnippet(int[] array) {
+        return array[10];
+    }
+
+    @Test
+    public void testNPEArray() {
+        int[] array = null;
+        for (int i = 0; i < 10000; i++) {
+            try {
+                testNPEArraySnippet(array);
+            } catch (NullPointerException e) {
+                // nothing to do
+            }
+        }
+        expectedForeignCallCount = 2;
+        test("testNPEArraySnippet", array);
+    }
+
+    private static class TestClass {
+        int field;
+    }
+
+    public static int testNPESnippet(TestClass obj) {
+        return obj.field;
+    }
+
+    @SuppressWarnings("unused")
+    @Test
+    public void testNPE() {
+        new TestClass();
+        TestClass obj = null;
+        for (int i = 0; i < 10000; i++) {
+            try {
+                testNPESnippet(obj);
+            } catch (NullPointerException e) {
+                // nothing to do
+            }
+        }
+        expectedForeignCallCount = 1;
+        test("testNPESnippet", obj);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java
new file mode 100644
index 0000000..12c411f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests that deoptimization upon exception handling works.
+ */
+public class ForeignCallDeoptimizeTest extends GraalCompilerTest {
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        ForeignCallsProvider foreignCalls = ((HotSpotProviders) getProviders()).getForeignCalls();
+
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        ret.getInvocationPlugins().register(new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ForeignCallNode node = new ForeignCallNode(foreignCalls, HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALL_INT, arg);
+                b.addPush(JavaKind.Int, node);
+                return true;
+            }
+        }, ForeignCallDeoptimizeTest.class, "testCallInt", int.class);
+        return ret;
+    }
+
+    public static int testCallInt(int value) {
+        return value;
+    }
+
+    public static int testForeignCall(int value) {
+        if (testCallInt(value) != value) {
+            throw new InternalError();
+        }
+        return value;
+    }
+
+    @Test
+    public void test1() {
+        test("testForeignCall", 0);
+    }
+
+    @Test
+    public void test2() {
+        test("testForeignCall", -1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java
new file mode 100644
index 0000000..5466a63
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Test on-stack-replacement with locks.
+ */
+public class GraalOSRLockTest extends GraalOSRTestBase {
+
+    @Ignore("OSR with locks not supported")
+    @Test
+    public void testOSR() {
+        testOSR("test");
+    }
+
+    static int limit = 10000;
+
+    private static Object lock = new Object();
+
+    public static ReturnValue test() {
+        synchronized (lock) {
+            for (int i = 0; i < limit * limit; i++) {
+                GraalDirectives.blackhole(i);
+                if (GraalDirectives.inCompiledCode()) {
+                    return ReturnValue.SUCCESS;
+                }
+            }
+            return ReturnValue.FAILURE;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java
new file mode 100644
index 0000000..3ae9608
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+
+/**
+ * Test on-stack-replacement with Graal. The test manually triggers a Graal OSR-compilation which is
+ * later invoked when hitting the backedge counter overflow.
+ */
+public class GraalOSRTest extends GraalOSRTestBase {
+
+    @Test
+    public void testOSR() {
+        testOSR("test");
+    }
+
+    static int limit = 10000;
+
+    public static ReturnValue test() {
+        for (int i = 0; i < limit * limit; i++) {
+            GraalDirectives.blackhole(i);
+            if (GraalDirectives.inCompiledCode()) {
+                return ReturnValue.SUCCESS;
+            }
+        }
+        return ReturnValue.FAILURE;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java
new file mode 100644
index 0000000..9742ebd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeStream;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompilationTask;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.java.BciBlockMapping;
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class GraalOSRTestBase extends GraalCompilerTest {
+
+    protected void testOSR(String methodName) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(methodName);
+        testOSR(method);
+    }
+
+    protected void testOSR(ResolvedJavaMethod method) {
+        // invalidate any existing compiled code
+        method.reprofile();
+        compileOSR(method);
+        Result result = executeExpected(method, null);
+        checkResult(result);
+    }
+
+    private static void compile(ResolvedJavaMethod method, int bci) {
+        HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
+        long jvmciEnv = 0L;
+        HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) method, bci, jvmciEnv);
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler();
+        CompilationTask task = new CompilationTask(runtime, compiler, request, true, true);
+        HotSpotCompilationRequestResult result = task.runCompilation();
+        if (result.getFailure() != null) {
+            throw new GraalError(result.getFailureMessage());
+        }
+    }
+
+    /**
+     * Returns the target BCI of the first bytecode backedge. This is where HotSpot triggers
+     * on-stack-replacement in case the backedge counter overflows.
+     */
+    private static int getBackedgeBCI(ResolvedJavaMethod method) {
+        Bytecode code = new ResolvedJavaMethodBytecode(method);
+        BytecodeStream stream = new BytecodeStream(code.getCode());
+        BciBlockMapping bciBlockMapping = BciBlockMapping.create(stream, code);
+        assert bciBlockMapping.getLoopCount() == 1 : "Expected exactly one loop " + method;
+
+        for (BciBlock block : bciBlockMapping.getBlocks()) {
+            int bci = block.startBci;
+            for (BciBlock succ : block.getSuccessors()) {
+                int succBci = succ.startBci;
+                if (succBci < bci) {
+                    // back edge
+                    return succBci;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private static void checkResult(Result result) {
+        Assert.assertNull("Unexpected exception", result.exception);
+        Assert.assertNotNull(result.returnValue);
+        Assert.assertTrue(result.returnValue instanceof ReturnValue);
+        Assert.assertEquals(ReturnValue.SUCCESS, result.returnValue);
+    }
+
+    private void compileOSR(ResolvedJavaMethod method) {
+        int bci = getBackedgeBCI(method);
+        assert bci != -1;
+        // ensure eager resolving
+        parseEager(method, AllowAssumptions.YES);
+        compile(method, bci);
+    }
+
+    protected enum ReturnValue {
+        SUCCESS,
+        FAILURE
+    }
+
+    public GraalOSRTestBase() {
+        super();
+    }
+
+    public GraalOSRTestBase(Class<? extends Architecture> arch) {
+        super(arch);
+    }
+
+    public GraalOSRTestBase(Backend backend) {
+        super(backend);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java
new file mode 100644
index 0000000..0d2e63f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AlgorithmParameters;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests the intrinsification of certain crypto methods.
+ */
+public class HotSpotCryptoSubstitutionTest extends HotSpotGraalCompilerTest {
+
+    @Override
+    protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
+        return getBackend().createDefaultInstalledCode(method, compResult);
+    }
+
+    SecretKey aesKey;
+    SecretKey desKey;
+    byte[] input;
+    ByteArrayOutputStream aesExpected = new ByteArrayOutputStream();
+    ByteArrayOutputStream desExpected = new ByteArrayOutputStream();
+
+    public HotSpotCryptoSubstitutionTest() throws Exception {
+        byte[] seed = {0x4, 0x7, 0x1, 0x1};
+        SecureRandom random = new SecureRandom(seed);
+        KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
+        KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede");
+        aesKeyGen.init(128, random);
+        desKeyGen.init(168, random);
+        aesKey = aesKeyGen.generateKey();
+        desKey = desKeyGen.generateKey();
+        input = readClassfile16(getClass());
+
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
+
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding"));
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding"));
+    }
+
+    @Test
+    public void testAESCryptIntrinsics() throws Exception {
+        if (compileAndInstall("com.sun.crypto.provider.AESCrypt", HotSpotGraphBuilderPlugins.aesEncryptName, HotSpotGraphBuilderPlugins.aesDecryptName)) {
+            ByteArrayOutputStream actual = new ByteArrayOutputStream();
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
+        }
+    }
+
+    @Test
+    public void testCipherBlockChainingIntrinsics() throws Exception {
+        if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", HotSpotGraphBuilderPlugins.cbcEncryptName, HotSpotGraphBuilderPlugins.cbcDecryptName)) {
+            ByteArrayOutputStream actual = new ByteArrayOutputStream();
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
+
+            actual.reset();
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding"));
+            Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray());
+        }
+    }
+
+    /**
+     * Compiles and installs the substitution for some specified methods. Once installed, the next
+     * execution of the methods will use the newly installed code.
+     *
+     * @param className the name of the class for which substitutions are available
+     * @param methodNames the names of the substituted methods
+     * @return true if at least one substitution was compiled and installed
+     */
+    private boolean compileAndInstall(String className, String... methodNames) {
+        if (!runtime().getVMConfig().useAESIntrinsics) {
+            return false;
+        }
+        Class<?> c;
+        try {
+            c = Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            // It's ok to not find the class - a different security provider
+            // may have been installed
+            return false;
+        }
+        boolean atLeastOneCompiled = false;
+        for (String methodName : methodNames) {
+            if (compileAndInstallSubstitution(c, methodName) != null) {
+                atLeastOneCompiled = true;
+            }
+        }
+        return atLeastOneCompiled;
+    }
+
+    AlgorithmParameters algorithmParameters;
+
+    private byte[] encrypt(byte[] indata, SecretKey key, String algorithm) throws Exception {
+
+        byte[] result = indata;
+
+        Cipher c = Cipher.getInstance(algorithm);
+        c.init(Cipher.ENCRYPT_MODE, key);
+        algorithmParameters = c.getParameters();
+
+        byte[] r1 = c.update(result);
+        byte[] r2 = c.doFinal();
+
+        result = new byte[r1.length + r2.length];
+        System.arraycopy(r1, 0, result, 0, r1.length);
+        System.arraycopy(r2, 0, result, r1.length, r2.length);
+
+        return result;
+    }
+
+    private byte[] decrypt(byte[] indata, SecretKey key, String algorithm) throws Exception {
+
+        byte[] result = indata;
+
+        Cipher c = Cipher.getInstance(algorithm);
+        c.init(Cipher.DECRYPT_MODE, key, algorithmParameters);
+
+        byte[] r1 = c.update(result);
+        byte[] r2 = c.doFinal();
+
+        result = new byte[r1.length + r2.length];
+        System.arraycopy(r1, 0, result, 0, r1.length);
+        System.arraycopy(r2, 0, result, r1.length, r2.length);
+        return result;
+    }
+
+    private static byte[] readClassfile16(Class<? extends HotSpotCryptoSubstitutionTest> c) throws IOException {
+        String classFilePath = "/" + c.getName().replace('.', '/') + ".class";
+        InputStream stream = c.getResourceAsStream(classFilePath);
+        int bytesToRead = stream.available();
+        bytesToRead -= bytesToRead % 16;
+        byte[] classFile = new byte[bytesToRead];
+        new DataInputStream(stream).readFully(classFile);
+        return classFile;
+    }
+
+    public byte[] runEncryptDecrypt(SecretKey key, String algorithm) throws Exception {
+        byte[] indata = input.clone();
+        byte[] cipher = encrypt(indata, key, algorithm);
+        byte[] plain = decrypt(cipher, key, algorithm);
+        Assert.assertArrayEquals(indata, plain);
+        return plain;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java
new file mode 100644
index 0000000..1851b26
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+
+/**
+ * A Graal compiler test that needs access to the {@link HotSpotGraalRuntimeProvider}.
+ */
+public abstract class HotSpotGraalCompilerTest extends GraalCompilerTest {
+
+    /**
+     * Gets the {@link HotSpotGraalRuntimeProvider}.
+     */
+    protected HotSpotGraalRuntimeProvider runtime() {
+        return ((HotSpotBackend) getBackend()).getRuntime();
+    }
+
+    protected InstalledCode compileAndInstallSubstitution(Class<?> c, String methodName) {
+        ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(c, methodName));
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler();
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        HotSpotProviders providers = rt.getHostBackend().getProviders();
+        CompilationIdentifier compilationId = runtime().getHostBackend().getCompilationIdentifier(method);
+        StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, compilationId);
+        if (graph != null) {
+            return getCode(method, graph, true, true);
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java
new file mode 100644
index 0000000..a93e0d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+
+/**
+ * Tests HotSpot specific {@link MethodSubstitution}s.
+ */
+public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest {
+
+    @Test
+    public void testObjectSubstitutions() {
+        TestClassA obj = new TestClassA();
+
+        testGraph("getClass0");
+        testGraph("objectHashCode");
+
+        test("getClass0", "a string");
+        test("objectHashCode", obj);
+    }
+
+    @SuppressWarnings("all")
+    public static Class<?> getClass0(Object obj) {
+        return obj.getClass();
+    }
+
+    @SuppressWarnings("all")
+    public static int objectHashCode(TestClassA obj) {
+        return obj.hashCode();
+    }
+
+    @Test
+    public void testClassSubstitutions() {
+        testGraph("getModifiers");
+        testGraph("isInterface");
+        testGraph("isArray");
+        testGraph("isPrimitive");
+        testGraph("getSuperClass");
+        testGraph("getComponentType");
+
+        for (Class<?> c : new Class<?>[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
+            test("getModifiers", c);
+            test("isInterface", c);
+            test("isArray", c);
+            test("isPrimitive", c);
+            test("getSuperClass", c);
+            test("getComponentType", c);
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static int getModifiers(Class<?> clazz) {
+        return clazz.getModifiers();
+    }
+
+    @SuppressWarnings("all")
+    public static boolean isInterface(Class<?> clazz) {
+        return clazz.isInterface();
+    }
+
+    @SuppressWarnings("all")
+    public static boolean isArray(Class<?> clazz) {
+        return clazz.isArray();
+    }
+
+    @SuppressWarnings("all")
+    public static boolean isPrimitive(Class<?> clazz) {
+        return clazz.isPrimitive();
+    }
+
+    @SuppressWarnings("all")
+    public static Class<?> getSuperClass(Class<?> clazz) {
+        return clazz.getSuperclass();
+    }
+
+    @SuppressWarnings("all")
+    public static Class<?> getComponentType(Class<?> clazz) {
+        return clazz.getComponentType();
+    }
+
+    @Test
+    public void testThreadSubstitutions() {
+        testGraph("currentThread");
+        testGraph("threadIsInterrupted");
+        testGraph("threadInterrupted");
+
+        Thread currentThread = Thread.currentThread();
+        test("currentThread", currentThread);
+        test("threadIsInterrupted", currentThread);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean currentThread(Thread other) {
+        return Thread.currentThread() == other;
+    }
+
+    @SuppressWarnings("all")
+    public static boolean threadIsInterrupted(Thread thread) {
+        return thread.isInterrupted();
+    }
+
+    @SuppressWarnings("all")
+    public static boolean threadInterrupted() {
+        return Thread.interrupted();
+    }
+
+    @Test
+    public void testSystemSubstitutions() {
+        testGraph("systemTime");
+        testGraph("systemIdentityHashCode");
+
+        for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
+            test("systemIdentityHashCode", o);
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static long systemTime() {
+        return System.currentTimeMillis() + System.nanoTime();
+    }
+
+    @SuppressWarnings("all")
+    public static int systemIdentityHashCode(Object obj) {
+        return System.identityHashCode(obj);
+    }
+
+    private static class TestClassA {
+    }
+
+    public static String testCallSiteGetTargetSnippet(int i) throws Exception {
+        ConstantCallSite site;
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+        switch (i) {
+            case 1:
+                site = GraalDirectives.opaque(new ConstantCallSite(lookup.findVirtual(String.class, "replace", MethodType.methodType(String.class, char.class, char.class))));
+                break;
+            default:
+                site = GraalDirectives.opaque(new ConstantCallSite(lookup.findStatic(java.util.Arrays.class, "asList", MethodType.methodType(java.util.List.class, Object[].class))));
+        }
+        return site.getTarget().toString();
+    }
+
+    public static String testCastSnippet(int i, Object obj) throws Exception {
+        Class<?> c;
+        switch (i) {
+            case 1:
+                c = GraalDirectives.opaque(Number.class);
+                break;
+            default:
+                c = GraalDirectives.opaque(Integer.class);
+                break;
+        }
+        return c.cast(obj).toString();
+    }
+
+    public static String testGetClassSnippet(int i) {
+        Object c;
+        switch (i) {
+            case 1:
+                c = GraalDirectives.opaque(new Object());
+                break;
+            default:
+                c = GraalDirectives.opaque("TEST");
+                break;
+        }
+        return c.getClass().toString();
+    }
+
+    /**
+     * Tests ambiguous receiver of CallSite.getTarget.
+     */
+    @Test
+    public void testCallSiteGetTarget() {
+        test("testCallSiteGetTargetSnippet", 1);
+    }
+
+    /**
+     * Tests ambiguous receiver of Class.cast.
+     */
+    @Test
+    public void testCast() {
+        test("testCastSnippet", 1, new Integer(1));
+    }
+
+    /**
+     * Tests ambiguous receiver of Object.getClass.
+     */
+    @Test
+    public void testGetClass() {
+        test("testGetClassSnippet", 1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMonitorValueTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMonitorValueTest.java
new file mode 100644
index 0000000..2546b78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMonitorValueTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.StackLockValue;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class HotSpotMonitorValueTest extends GraalCompilerTest {
+
+    @Override
+    protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
+        for (Infopoint i : compResult.getInfopoints()) {
+            if (i instanceof Call) {
+                Call call = (Call) i;
+                if (call.target instanceof ResolvedJavaMethod) {
+                    ResolvedJavaMethod target = (ResolvedJavaMethod) call.target;
+                    if (target.equals(lookupObjectWait())) {
+                        BytecodeFrame frame = call.debugInfo.frame();
+                        BytecodeFrame caller = frame.caller();
+                        assertNotNull(caller);
+                        assertNull(caller.caller());
+                        assertDeepEquals(2, frame.numLocks);
+                        assertDeepEquals(2, caller.numLocks);
+                        StackLockValue lock1 = (StackLockValue) frame.getLockValue(0);
+                        StackLockValue lock2 = (StackLockValue) frame.getLockValue(1);
+                        StackLockValue lock3 = (StackLockValue) caller.getLockValue(0);
+                        StackLockValue lock4 = (StackLockValue) caller.getLockValue(1);
+
+                        List<StackLockValue> locks = Arrays.asList(lock1, lock2, lock3, lock4);
+                        for (StackLockValue lock : locks) {
+                            for (StackLockValue other : locks) {
+                                if (other != lock) {
+                                    // Every lock must have a different stack slot
+                                    assertThat(lock.getSlot(), not(other.getSlot()));
+                                }
+                            }
+                        }
+                        assertDeepEquals(lock3.getOwner(), lock4.getOwner());
+                        assertThat(lock1.getOwner(), not(lock2.getOwner()));
+                        return super.addMethod(method, compResult);
+                    }
+                }
+            }
+        }
+        throw new AssertionError("Could not find debug info for call to Object.wait(long)");
+    }
+
+    private ResolvedJavaMethod lookupObjectWait() {
+        try {
+            return getMetaAccess().lookupJavaMethod(Object.class.getDeclaredMethod("wait", long.class));
+        } catch (Exception e) {
+            throw new GraalError("Could not find Object.wait(long): %s", e);
+        }
+    }
+
+    @Test
+    public void test() {
+        test("testSnippet", "a", "b");
+    }
+
+    private static void locks2(Object a, Object b) throws InterruptedException {
+        synchronized (a) {
+            synchronized (b) {
+                a.wait(5);
+            }
+        }
+    }
+
+    public static void testSnippet(Object a, Object b) throws InterruptedException {
+        synchronized (a) {
+            synchronized (a) {
+                locks2(a, b);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNmethodTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNmethodTest.java
new file mode 100644
index 0000000..962e238
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNmethodTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.hotspot.HotSpotNmethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class HotSpotNmethodTest extends GraalCompilerTest {
+
+    private static final int ITERATION_COUNT = 100000;
+
+    @Test
+    public void testInstallCodeInvalidation() {
+        final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
+        Assert.assertTrue(nmethod.isValid());
+        Object result;
+        try {
+            result = nmethod.executeVarargs(null, "b", "c");
+            assertDeepEquals(43, result);
+        } catch (InvalidInstalledCodeException e) {
+            Assert.fail("Code was invalidated");
+        }
+        Assert.assertTrue(nmethod.isValid());
+        nmethod.invalidate();
+        Assert.assertFalse(nmethod.isValid());
+        try {
+            result = nmethod.executeVarargs(null, null, null);
+            Assert.fail("Code was not invalidated");
+        } catch (InvalidInstalledCodeException e) {
+        }
+        Assert.assertFalse(nmethod.isValid());
+    }
+
+    @Test
+    public void testInstallCodeInvalidationWhileRunning() {
+        final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
+        Object result;
+        try {
+            result = nmethod.executeVarargs(nmethod, null, null);
+            assertDeepEquals(43, result);
+        } catch (InvalidInstalledCodeException e) {
+            Assert.fail("Code was invalidated");
+        }
+        Assert.assertFalse(nmethod.isValid());
+    }
+
+    @Test
+    public void testInstalledCodeCalledFromCompiledCode() {
+        final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
+        Assert.assertTrue(nmethod.isValid());
+        try {
+            for (int i = 0; i < ITERATION_COUNT; ++i) {
+                nmethod.executeVarargs(null, "b", "c");
+            }
+        } catch (InvalidInstalledCodeException e) {
+            Assert.fail("Code was invalidated");
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static Object foo(HotSpotNmethod method, Object a2, Object a3) {
+        return 42;
+    }
+
+    @SuppressWarnings("unused")
+    public static Object otherFoo(HotSpotNmethod method, Object a2, Object a3) {
+        if (method != null) {
+            method.invalidate();
+        }
+        return 43;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNodeSubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNodeSubstitutionsTest.java
new file mode 100644
index 0000000..fe00028
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotNodeSubstitutionsTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+
+/**
+ * Tests HotSpot specific substitutions for {@link Node}.
+ */
+public class HotSpotNodeSubstitutionsTest extends MethodSubstitutionTest {
+
+    @Test
+    public void test() {
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID);
+        test("getNodeClass", ConstantNode.forInt(42, graph));
+    }
+
+    public static NodeClass<?> getNodeClass(Node n) {
+        return n.getNodeClass();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedJavaFieldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedJavaFieldTest.java
new file mode 100644
index 0000000..549a69b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedJavaFieldTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static java.lang.reflect.Modifier.FINAL;
+import static java.lang.reflect.Modifier.PRIVATE;
+import static java.lang.reflect.Modifier.PROTECTED;
+import static java.lang.reflect.Modifier.PUBLIC;
+import static java.lang.reflect.Modifier.STATIC;
+import static java.lang.reflect.Modifier.TRANSIENT;
+import static java.lang.reflect.Modifier.VOLATILE;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * Tests {@link HotSpotResolvedJavaField} functionality.
+ */
+public class HotSpotResolvedJavaFieldTest extends HotSpotGraalCompilerTest {
+
+    private static final Class<?>[] classesWithInternalFields = {Class.class, ClassLoader.class};
+
+    private static final Method createFieldMethod;
+
+    static {
+        Method ret = null;
+        try {
+            Class<?> typeImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl");
+            ret = typeImpl.getDeclaredMethod("createField", String.class, JavaType.class, long.class, int.class);
+            ret.setAccessible(true);
+        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
+            e.printStackTrace();
+        }
+
+        createFieldMethod = ret;
+    }
+
+    /**
+     * Same as {@code HotSpotModifiers.jvmFieldModifiers()} but works when using a JVMCI version
+     * prior to the introduction of that method.
+     */
+    private int jvmFieldModifiers() {
+        GraalHotSpotVMConfig config = runtime().getVMConfig();
+        int accEnum = config.getConstant("JVM_ACC_ENUM", Integer.class, 0x4000);
+        int accSynthetic = config.getConstant("JVM_ACC_SYNTHETIC", Integer.class, 0x1000);
+        return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | accEnum | accSynthetic;
+    }
+
+    /**
+     * Tests that {@link HotSpotResolvedJavaField#getModifiers()} only includes the modifiers
+     * returned by {@link Field#getModifiers()}. Namely, it must not include
+     * {@code HotSpotResolvedJavaField#FIELD_INTERNAL_FLAG}.
+     */
+    @Test
+    public void testModifiersForInternal() {
+        for (Class<?> c : classesWithInternalFields) {
+            HotSpotResolvedObjectType type = HotSpotResolvedObjectType.fromObjectClass(c);
+            for (ResolvedJavaField field : type.getInstanceFields(false)) {
+                if (field.isInternal()) {
+                    Assert.assertEquals(0, ~jvmFieldModifiers() & field.getModifiers());
+                }
+            }
+        }
+    }
+
+    /**
+     * Tests that {@code HotSpotResolvedObjectType#createField(String, JavaType, long, int)} always
+     * returns the same object for an internal field.
+     *
+     * @throws InvocationTargetException
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     */
+    @Test
+    public void testCachingForInternalFields() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        Assert.assertTrue("HotSpotResolvedObjectTypeImpl.createField method not found", createFieldMethod != null);
+        for (Class<?> c : classesWithInternalFields) {
+            HotSpotResolvedObjectType type = HotSpotResolvedObjectType.fromObjectClass(c);
+            for (ResolvedJavaField field : type.getInstanceFields(false)) {
+                if (field.isInternal()) {
+                    HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field;
+                    ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getName(), expected.getType(), expected.offset(), expected.getModifiers());
+                    Assert.assertEquals(expected, actual);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testIsInObject() {
+        for (Field f : String.class.getDeclaredFields()) {
+            HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) getMetaAccess().lookupJavaField(f);
+            Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !rf.isStatic());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedObjectTypeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedObjectTypeTest.java
new file mode 100644
index 0000000..5c084c6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotResolvedObjectTypeTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+/**
+ * Tests {@link HotSpotResolvedJavaMethod} functionality.
+ */
+public class HotSpotResolvedObjectTypeTest extends HotSpotGraalCompilerTest {
+
+    @Test
+    public void testGetSourceFileName() throws Throwable {
+        Assert.assertEquals("Object.java", HotSpotResolvedObjectType.fromObjectClass(Object.class).getSourceFileName());
+        Assert.assertEquals("HotSpotResolvedObjectTypeTest.java", HotSpotResolvedObjectType.fromObjectClass(this.getClass()).getSourceFileName());
+    }
+
+    @Test
+    public void testKlassLayoutHelper() {
+        Constant klass = HotSpotResolvedObjectType.fromObjectClass(this.getClass()).klass();
+        MemoryAccessProvider memoryAccess = getProviders().getConstantReflection().getMemoryAccessProvider();
+        GraalHotSpotVMConfig config = runtime().getVMConfig();
+        Constant c = StampFactory.forKind(JavaKind.Int).readConstant(memoryAccess, klass, config.klassLayoutHelperOffset);
+        assertTrue(c.toString(), c.getClass() == PrimitiveConstant.class);
+        PrimitiveConstant pc = (PrimitiveConstant) c;
+        assertTrue(pc.toString(), pc.getJavaKind() == JavaKind.Int);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/InstalledCodeExecuteHelperTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/InstalledCodeExecuteHelperTest.java
new file mode 100644
index 0000000..9d9e159
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/InstalledCodeExecuteHelperTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static java.lang.reflect.Modifier.isStatic;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class InstalledCodeExecuteHelperTest extends GraalCompilerTest {
+
+    private static final int ITERATIONS = 100000;
+    Object[] argsToBind;
+
+    @Test
+    public void test1() throws InvalidInstalledCodeException {
+        final ResolvedJavaMethod fooMethod = getResolvedJavaMethod("foo");
+        final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooMethod);
+
+        argsToBind = new Object[]{fooCode};
+
+        final ResolvedJavaMethod benchmarkMethod = getResolvedJavaMethod("benchmark");
+        final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(benchmarkMethod);
+
+        Assert.assertEquals(Integer.valueOf(42), benchmark(fooCode));
+
+        Assert.assertEquals(Integer.valueOf(42), installedBenchmarkCode.executeVarargs(argsToBind[0]));
+
+    }
+
+    public static Integer benchmark(HotSpotInstalledCode code) throws InvalidInstalledCodeException {
+        int val = 0;
+        for (int j = 0; j < 100; j++) {
+            for (int i = 0; i < ITERATIONS; i++) {
+                val = (Integer) code.executeVarargs();
+            }
+        }
+        return val;
+    }
+
+    public static Integer foo() {
+        return 42;
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId);
+        if (argsToBind != null) {
+            Object receiver = isStatic(m.getModifiers()) ? null : this;
+            Object[] args = argsWithReceiver(receiver, argsToBind);
+            JavaType[] parameterTypes = m.toParameterTypes();
+            assert parameterTypes.length == args.length;
+            for (int i = 0; i < argsToBind.length; i++) {
+                ParameterNode param = graph.getParameter(i);
+                JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[i].getJavaKind(), argsToBind[i]);
+                ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
+                param.replaceAtUsages(replacement);
+            }
+        }
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java
new file mode 100644
index 0000000..65676ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.function.Consumer;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.lir.FullInfopointOp;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+public class JVMCIInfopointErrorTest extends GraalCompilerTest {
+
+    private static class ValueDef extends LIRInstruction {
+        private static final LIRInstructionClass<ValueDef> TYPE = LIRInstructionClass.create(ValueDef.class);
+
+        @Def({REG, STACK}) AllocatableValue value;
+
+        ValueDef(AllocatableValue value) {
+            super(TYPE);
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+        }
+    }
+
+    private static class ValueUse extends LIRInstruction {
+        private static final LIRInstructionClass<ValueUse> TYPE = LIRInstructionClass.create(ValueUse.class);
+
+        @Use({REG, STACK}) AllocatableValue value;
+
+        ValueUse(AllocatableValue value) {
+            super(TYPE);
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    private static class TestNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+        private static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+        private final TestSpec spec;
+
+        protected TestNode(TestSpec spec) {
+            super(TYPE, StampFactory.forVoid());
+            this.spec = spec;
+        }
+
+        @Override
+        public boolean canDeoptimize() {
+            return true;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool gen) {
+            LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+            LIRFrameState state = gen.state(this);
+            spec.spec(tool, state, st -> {
+                tool.append(new FullInfopointOp(st, InfopointReason.SAFEPOINT));
+            });
+        }
+    }
+
+    @FunctionalInterface
+    private interface TestSpec {
+        void spec(LIRGeneratorTool tool, LIRFrameState state, Consumer<LIRFrameState> safepoint);
+    }
+
+    public static void testMethod() {
+    }
+
+    private void test(TestSpec spec) {
+        ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
+
+        StructuredGraph graph = parseForCompile(method);
+        TestNode test = graph.add(new TestNode(spec));
+        graph.addAfterFixed(graph.start(), test);
+
+        CompilationResult compResult = compile(method, graph);
+        HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(method, null, compResult);
+        getCodeCache().addCode(method, compiledCode, null, null);
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testInvalidShortOop() {
+        test((tool, state, safepoint) -> {
+            PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short);
+            LIRKind lirKind = LIRKind.reference(kind);
+
+            Variable var = tool.newVariable(lirKind);
+            tool.append(new ValueDef(var));
+            safepoint.accept(state);
+            tool.append(new ValueUse(var));
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testInvalidShortDerivedOop() {
+        test((tool, state, safepoint) -> {
+            Variable baseOop = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Object));
+            tool.append(new ValueDef(baseOop));
+
+            PlatformKind kind = tool.target().arch.getPlatformKind(JavaKind.Short);
+            LIRKind lirKind = LIRKind.derivedReference(kind, baseOop);
+
+            Variable var = tool.newVariable(lirKind);
+            tool.append(new ValueDef(var));
+            safepoint.accept(state);
+            tool.append(new ValueUse(var));
+        });
+    }
+
+    private static LIRFrameState modifyTopFrame(LIRFrameState state, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) {
+        return modifyTopFrame(state, null, values, slotKinds, locals, stack, locks);
+    }
+
+    private static LIRFrameState modifyTopFrame(LIRFrameState state, VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) {
+        BytecodeFrame top = state.topFrame;
+        top = new BytecodeFrame(top.caller(), top.getMethod(), top.getBCI(), top.rethrowException, top.duringCall, values, slotKinds, locals, stack, locks);
+        return new LIRFrameState(top, vobj, state.exceptionEdge);
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedScopeValuesLength() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.FALSE}, new JavaKind[0], 0, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedScopeSlotKindsLength() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[0], new JavaKind[]{JavaKind.Boolean}, 0, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testWrongMonitorType() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{}, 0, 0, 1);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedIllegalValue() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{Value.ILLEGAL}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedTypeInRegister() {
+        test((tool, state, safepoint) -> {
+            Variable var = tool.newVariable(LIRKind.fromJavaKind(tool.target().arch, JavaKind.Int));
+            tool.append(new ValueDef(var));
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{var}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testWrongConstantType() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{JavaKind.Object}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnsupportedConstantType() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.forShort((short) 0)}, new JavaKind[]{JavaKind.Short}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedNull() {
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.NULL_POINTER}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedObject() {
+        JavaValue wrapped = getSnippetReflection().forObject(this);
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{wrapped}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    private static class UnknownJavaValue implements JavaValue {
+    }
+
+    @SuppressWarnings("try")
+    @Test(expected = Error.class)
+    public void testUnknownJavaValue() {
+        try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) {
+            /*
+             * Expected: either AssertionError or GraalError, depending on whether the unit test run
+             * is with assertions enabled or disabled.
+             */
+            test((tool, state, safepoint) -> {
+                LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{new UnknownJavaValue()}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
+                safepoint.accept(newState);
+            });
+        }
+    }
+
+    @Test(expected = Error.class)
+    public void testMissingIllegalAfterDouble() {
+        /*
+         * Expected: either AssertionError or GraalError, depending on whether the unit test run is
+         * with assertions enabled or disabled.
+         */
+        test((tool, state, safepoint) -> {
+            LIRFrameState newState = modifyTopFrame(state, new JavaValue[]{JavaConstant.DOUBLE_0, JavaConstant.INT_0}, new JavaKind[]{JavaKind.Double, JavaKind.Int}, 2, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testInvalidVirtualObjectId() {
+        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
+        test((tool, state, safepoint) -> {
+            VirtualObject o = VirtualObject.get(obj, 5);
+            o.setValues(new JavaValue[0], new JavaKind[0]);
+
+            safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o}, state.exceptionEdge));
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testDuplicateVirtualObject() {
+        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
+        test((tool, state, safepoint) -> {
+            VirtualObject o1 = VirtualObject.get(obj, 0);
+            o1.setValues(new JavaValue[0], new JavaKind[0]);
+
+            VirtualObject o2 = VirtualObject.get(obj, 0);
+            o2.setValues(new JavaValue[0], new JavaKind[0]);
+
+            safepoint.accept(new LIRFrameState(state.topFrame, new VirtualObject[]{o1, o2}, state.exceptionEdge));
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUnexpectedVirtualObject() {
+        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
+        test((tool, state, safepoint) -> {
+            VirtualObject o = VirtualObject.get(obj, 0);
+            o.setValues(new JavaValue[0], new JavaKind[0]);
+
+            LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o}, new JavaValue[]{o}, new JavaKind[]{JavaKind.Int}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+
+    @Test(expected = JVMCIError.class)
+    public void testUndefinedVirtualObject() {
+        ResolvedJavaType obj = getMetaAccess().lookupJavaType(Object.class);
+        test((tool, state, safepoint) -> {
+            VirtualObject o0 = VirtualObject.get(obj, 0);
+            o0.setValues(new JavaValue[0], new JavaKind[0]);
+
+            VirtualObject o1 = VirtualObject.get(obj, 1);
+            o1.setValues(new JavaValue[0], new JavaKind[0]);
+
+            LIRFrameState newState = modifyTopFrame(state, new VirtualObject[]{o0}, new JavaValue[]{o1}, new JavaKind[]{JavaKind.Object}, 1, 0, 0);
+            safepoint.accept(newState);
+        });
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java
new file mode 100644
index 0000000..57c9776
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class LoadJavaMirrorWithKlassTest extends GraalCompilerTest {
+
+    private static class Wrapper {
+        private Class<?> clazz;
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Wrapper) {
+                return Objects.equals(this.clazz, ((Wrapper) obj).clazz);
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return clazz.hashCode();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected Suites createSuites() {
+        try (OverrideScope s = OptionValue.override(GraalOptions.ImmutableCode, true)) {
+            return super.createSuites();
+        }
+    }
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class)) {
+            assert constantNode.asJavaConstant() == null || constantNode.asJavaConstant().getJavaKind() != JavaKind.Object ||
+                            constantNode.asJavaConstant().isDefaultForKind() : "Found unexpected object constant " +
+                                            constantNode + ", this should have been removed by the LoadJavaMirrorWithKlassPhase.";
+        }
+        return true;
+    }
+
+    public static Class<?> classConstant() {
+        return Wrapper.class;
+    }
+
+    @Test
+    public void testClassConstant() {
+        test("classConstant");
+    }
+
+    public static Class<?> primitiveClassConstant() {
+        return int.class;
+    }
+
+    @Test
+    public void testPrimitiveClassConstant() {
+        test("primitiveClassConstant");
+    }
+
+    public static Wrapper compressedClassConstant(Wrapper w) {
+        w.clazz = Wrapper.class;
+        return w;
+    }
+
+    @Test
+    public void testCompressedClassConstant() {
+        ArgSupplier arg = () -> new Wrapper();
+        test("compressedClassConstant", arg);
+    }
+
+    public static Wrapper compressedPrimitiveClassConstant(Wrapper w) {
+        w.clazz = int.class;
+        return w;
+    }
+
+    @Test
+    public void testCompressedPrimitiveClassConstant() {
+        ArgSupplier arg = () -> new Wrapper();
+        test("compressedPrimitiveClassConstant", arg);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java
new file mode 100644
index 0000000..f12b0ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.debug.internal.MemUseTrackerImpl.getCurrentThreadAllocatedBytes;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.test.AllocSpy;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.hotspot.CompilationTask;
+import org.graalvm.compiler.hotspot.CompileTheWorld;
+import org.graalvm.compiler.hotspot.CompileTheWorldOptions;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * Used to benchmark memory usage during Graal compilation.
+ *
+ * To benchmark:
+ *
+ * <pre>
+ *     mx vm -XX:-UseJVMCIClassLoader -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
+ * </pre>
+ *
+ * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example:
+ *
+ * <pre>
+ *     mx --vm server vm -XX:-UseJVMCIClassLoader -Dgraal.CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
+ * </pre>
+ */
+public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest {
+
+    public static int simple(int a, int b) {
+        return a + b;
+    }
+
+    public static synchronized int complex(CharSequence cs) {
+        if (cs instanceof String) {
+            return cs.hashCode();
+        }
+
+        if (cs instanceof StringBuilder) {
+            int[] hash = {0};
+            cs.chars().forEach(c -> hash[0] += c);
+            return hash[0];
+        }
+
+        int res = 0;
+
+        // Exercise lock elimination
+        synchronized (cs) {
+            res = cs.length();
+        }
+        synchronized (cs) {
+            res = cs.hashCode() ^ 31;
+        }
+
+        for (int i = 0; i < cs.length(); i++) {
+            res *= cs.charAt(i);
+        }
+
+        // A fixed length loop with some canonicalizable arithmetics will
+        // activate loop unrolling and more canonicalization
+        int sum = 0;
+        for (int i = 0; i < 5; i++) {
+            sum += i * 2;
+        }
+        res += sum;
+
+        // Activates escape-analysis
+        res += new String("asdf").length();
+
+        return res;
+    }
+
+    static class MemoryUsageCloseable implements AutoCloseable {
+
+        private final long start;
+        private final String name;
+
+        MemoryUsageCloseable(String name) {
+            this.name = name;
+            this.start = getCurrentThreadAllocatedBytes();
+        }
+
+        @Override
+        public void close() {
+            long end = getCurrentThreadAllocatedBytes();
+            long allocated = end - start;
+            System.out.println(name + ": " + allocated);
+        }
+    }
+
+    public static void main(String[] args) {
+        // Ensure a Graal runtime is initialized prior to Debug being initialized as the former
+        // may include processing command line options used by the latter.
+        Graal.getRuntime();
+
+        // Ensure a debug configuration for this thread is initialized
+        if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+            DebugEnvironment.initialize(System.out);
+        }
+        new MemoryUsageBenchmark().run();
+    }
+
+    @SuppressWarnings("try")
+    private void doCompilation(String methodName, String label) {
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
+
+        // invalidate any existing compiled code
+        method.reprofile();
+
+        long jvmciEnv = 0L;
+
+        try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) {
+            HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
+            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
+            HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, jvmciEnv);
+            CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false);
+            task.runCompilation();
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void allocSpyCompilation(String methodName) {
+        if (AllocSpy.isEnabled()) {
+            HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
+
+            // invalidate any existing compiled code
+            method.reprofile();
+
+            long jvmciEnv = 0L;
+            try (AllocSpy as = AllocSpy.open(methodName)) {
+                HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
+                HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, JVMCICompiler.INVOCATION_ENTRY_BCI, jvmciEnv);
+                CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false);
+                task.runCompilation();
+            }
+        }
+    }
+
+    private static final boolean verbose = Boolean.getBoolean("verbose");
+
+    private void compileAndTime(String methodName) {
+
+        // Parse in eager mode to resolve methods/fields/classes
+        parseEager(methodName, AllowAssumptions.YES);
+
+        // Warm up and initialize compiler phases used by this compilation
+        for (int i = 0; i < 10; i++) {
+            doCompilation(methodName, verbose ? methodName + "[warmup-" + i + "]" : null);
+        }
+
+        doCompilation(methodName, methodName);
+    }
+
+    public void run() {
+        compileAndTime("simple");
+        compileAndTime("complex");
+        if (CompileTheWorldOptions.CompileTheWorldClasspath.getValue() != CompileTheWorld.SUN_BOOT_CLASS_PATH) {
+            HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
+            CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler());
+            try {
+                ctw.compile();
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+        allocSpyCompilation("simple");
+        allocSpyCompilation("complex");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java
new file mode 100644
index 0000000..3185b44
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+import jdk.vm.ci.hotspot.VMIntrinsicMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+
+/**
+ * Exercise the compilation of intrinsic method substitutions.
+ */
+public class TestIntrinsicCompiles extends GraalCompilerTest {
+
+    private static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) {
+        if (intrinsic.name.equals(method.getName())) {
+            if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) {
+                String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/');
+                if (declaringClass.equals(intrinsic.declaringClass)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ResolvedJavaMethod findMethod(Set<ResolvedJavaMethod> methods, VMIntrinsicMethod intrinsic) {
+        for (ResolvedJavaMethod method : methods) {
+            if (match(method, intrinsic)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test() {
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler();
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        HotSpotProviders providers = rt.getHostBackend().getProviders();
+        Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins();
+        InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins();
+
+        Set<ResolvedJavaMethod> pluginMethods = invocationPlugins.getMethods();
+        HotSpotVMConfigStore store = rt.getVMConfig().getStore();
+        List<VMIntrinsicMethod> intrinsics = store.getIntrinsics();
+        for (VMIntrinsicMethod intrinsic : intrinsics) {
+            ResolvedJavaMethod method = findMethod(pluginMethods, intrinsic);
+            if (method != null) {
+                InvocationPlugin plugin = invocationPlugins.lookupInvocation(method);
+                if (plugin instanceof MethodSubstitutionPlugin && !method.isNative()) {
+                    StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, CompilationIdentifier.INVALID_COMPILATION_ID);
+                    getCode(method, graph);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java
new file mode 100644
index 0000000..b7ad77f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Exercise the execution of the SHA digest substitutions.
+ */
+public class TestSHASubstitutions extends HotSpotGraalCompilerTest {
+
+    public byte[] testDigest(String name, byte[] data) throws NoSuchAlgorithmException {
+        MessageDigest digest;
+        try {
+            digest = MessageDigest.getInstance(name, "SUN");
+            digest.update(data);
+            return digest.digest();
+        } catch (NoSuchProviderException e) {
+            return null;
+        }
+    }
+
+    byte[] getData() {
+        byte[] data = new byte[1024 * 16];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte) i;
+        }
+        return data;
+    }
+
+    GraalHotSpotVMConfig getConfig() {
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        return rt.getVMConfig();
+    }
+
+    @Test
+    public void testSha1() {
+        if (getConfig().useSHA1Intrinsics()) {
+            testWithInstalledIntrinsic("sun.security.provider.SHA", SHASubstitutions.implCompressName, "testDigest", "SHA-1", getData());
+        }
+    }
+
+    void testWithInstalledIntrinsic(String className, String methodName, String testSnippetName, Object... args) {
+        Class<?> c;
+        try {
+            c = Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            // It's ok to not find the class - a different security provider
+            // may have been installed
+            return;
+        }
+        InstalledCode code = null;
+        try {
+            ResolvedJavaMethod method = getResolvedJavaMethod(testSnippetName);
+            Object receiver = method.isStatic() ? null : this;
+            Result expect = executeExpected(method, receiver, args);
+            code = compileAndInstallSubstitution(c, methodName);
+            assertTrue("Failed to install " + methodName, code != null);
+            testAgainstExpected(method, expect, receiver, args);
+        } catch (AssumptionViolatedException e) {
+            // Suppress so that subsequent calls to this method within the
+            // same Junit @Test annotated method can proceed.
+        }
+        if (code != null) {
+            code.invalidate();
+        }
+    }
+
+    @Test
+    public void testSha256() {
+        if (getConfig().useSHA256Intrinsics()) {
+            testWithInstalledIntrinsic("sun.security.provider.SHA2", SHA2Substitutions.implCompressName, "testDigest", "SHA-256", getData());
+        }
+    }
+
+    @Test
+    public void testSha512() {
+        if (getConfig().useSHA512Intrinsics()) {
+            testWithInstalledIntrinsic("sun.security.provider.SHA5", SHA5Substitutions.implCompressName, "testDigest", "SHA-512", getData());
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
new file mode 100644
index 0000000..14ab256
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset;
+
+import java.lang.ref.WeakReference;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * The following unit tests assert the presence of write barriers for both Serial and G1 GCs.
+ * Normally, the tests check for compile time inserted barriers. However, there are the cases of
+ * unsafe loads of the java.lang.ref.Reference.referent field where runtime checks have to be
+ * performed also. For those cases, the unit tests check the presence of the compile-time inserted
+ * barriers. Concerning the runtime checks, the results of variable inputs (object types and
+ * offsets) passed as input parameters can be checked against printed output from the G1 write
+ * barrier snippets. The runtime checks have been validated offline.
+ */
+public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
+
+    private final GraalHotSpotVMConfig config = runtime().getVMConfig();
+    private static final long referentOffset = referentOffset();
+
+    public static class Container {
+
+        public Container a;
+        public Container b;
+    }
+
+    /**
+     * Expected 2 barriers for the Serial GC and 4 for G1 (2 pre + 2 post).
+     */
+    @Test
+    public void test1() throws Exception {
+        testHelper("test1Snippet", (config.useG1GC) ? 4 : 2);
+    }
+
+    public static void test1Snippet() {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        main.a = temp1;
+        main.b = temp2;
+    }
+
+    /**
+     * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post).
+     */
+    @Test
+    public void test2() throws Exception {
+        testHelper("test2Snippet", config.useG1GC ? 8 : 4);
+    }
+
+    public static void test2Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                main.a = temp1;
+                main.b = temp2;
+            } else {
+                main.a = temp2;
+                main.b = temp1;
+            }
+        }
+    }
+
+    /**
+     * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post).
+     */
+    @Test
+    public void test3() throws Exception {
+        testHelper("test3Snippet", config.useG1GC ? 8 : 4);
+    }
+
+    public static void test3Snippet() {
+        Container[] main = new Container[10];
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        for (int i = 0; i < 10; i++) {
+            main[i].a = main[i].b = temp1;
+        }
+
+        for (int i = 0; i < 10; i++) {
+            main[i].a = main[i].b = temp2;
+        }
+    }
+
+    /**
+     * Expected 2 barriers for the Serial GC and 5 for G1 (3 pre + 2 post) The (2 or 4) barriers are
+     * emitted while initializing the fields of the WeakReference instance. The extra pre barrier of
+     * G1 concerns the read of the referent field.
+     */
+    @Test
+    public void test4() throws Exception {
+        testHelper("test4Snippet", config.useG1GC ? 5 : 2);
+    }
+
+    public static Object test4Snippet() {
+        WeakReference<Object> weakRef = new WeakReference<>(new Object());
+        return weakRef.get();
+    }
+
+    static WeakReference<Object> wr = new WeakReference<>(new Object());
+    static Container con = new Container();
+
+    /**
+     * Expected 4 barriers for the Serial GC and 9 for G1 (1 ref + 4 pre + 4 post). In this test, we
+     * load the correct offset of the WeakReference object so naturally we assert the presence of
+     * the pre barrier.
+     */
+    @Test
+    public void test5() throws Exception {
+        testHelper("test5Snippet", config.useG1GC ? 1 : 0);
+    }
+
+    public static Object test5Snippet() throws Exception {
+        return UNSAFE.getObject(wr, config(null).useCompressedOops ? 12L : 16L);
+    }
+
+    /**
+     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
+     * load the java.lang.ref.Reference.referent field so the pre barier has to be executed.
+     */
+    @Test
+    public void test6() throws Exception {
+        test2("testUnsafeLoad", UNSAFE, wr, new Long(referentOffset), null);
+    }
+
+    /**
+     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
+     * load a matching offset of a wrong object so the pre barier must not be executed.
+     */
+    @Test
+    public void test7() throws Exception {
+        test2("testUnsafeLoad", UNSAFE, con, new Long(referentOffset), null);
+    }
+
+    /**
+     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
+     * load a non-matching offset field of the java.lang.ref.Reference object so the pre barier must
+     * not be executed.
+     */
+    @Test
+    public void test8() throws Exception {
+        test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 20 : 32), null);
+    }
+
+    /**
+     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
+     * load a matching offset+disp field of the java.lang.ref.Reference object so the pre barier
+     * must be executed.
+     */
+    @Test
+    public void test10() throws Exception {
+        test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 6 : 8), new Integer(config.useCompressedOops ? 6 : 8));
+    }
+
+    /**
+     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
+     * load a non-matching offset+disp field of the java.lang.ref.Reference object so the pre barier
+     * must not be executed.
+     */
+    @Test
+    public void test9() throws Exception {
+        test2("testUnsafeLoad", UNSAFE, wr, new Long(config.useCompressedOops ? 10 : 16), new Integer(config.useCompressedOops ? 10 : 16));
+    }
+
+    static Object[] src = new Object[1];
+    static Object[] dst = new Object[1];
+
+    static {
+        for (int i = 0; i < src.length; i++) {
+            src[i] = new Object();
+        }
+        for (int i = 0; i < dst.length; i++) {
+            dst[i] = new Object();
+        }
+    }
+
+    public static void testArrayCopy(Object a, Object b, Object c) throws Exception {
+        System.arraycopy(a, 0, b, 0, (int) c);
+    }
+
+    @Test
+    public void test11() throws Exception {
+        test2("testArrayCopy", src, dst, dst.length);
+    }
+
+    public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception {
+        final int offset = (c == null ? 0 : ((Integer) c).intValue());
+        final long displacement = (b == null ? 0 : ((Long) b).longValue());
+        return theUnsafe.getObject(a, offset + displacement);
+    }
+
+    private HotSpotInstalledCode getInstalledCode(String name, boolean withUnsafePrefix) throws Exception {
+        final ResolvedJavaMethod javaMethod = withUnsafePrefix ? getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Unsafe.class, Object.class, Object.class, Object.class)
+                        : getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Object.class, Object.class, Object.class);
+        final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(javaMethod);
+        return installedCode;
+    }
+
+    @SuppressWarnings("try")
+    private void testHelper(final String snippetName, final int expectedBarriers) throws Exception, SecurityException {
+        ResolvedJavaMethod snippet = getResolvedJavaMethod(snippetName);
+        try (Scope s = Debug.scope("WriteBarrierAdditionTest", snippet)) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+            HighTierContext highContext = getDefaultHighTierContext();
+            MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+            new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
+            new CanonicalizerPhase().apply(graph, highContext);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
+            new GuardLoweringPhase().apply(graph, midContext);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+            new WriteBarrierAdditionPhase(config).apply(graph);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After Write Barrier Addition");
+
+            int barriers = 0;
+            if (config.useG1GC) {
+                barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
+                                graph.getNodes().filter(G1PostWriteBarrier.class).count();
+            } else {
+                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
+            }
+            if (expectedBarriers != barriers) {
+                Assert.assertEquals(getScheduledGraphString(graph), expectedBarriers, barriers);
+            }
+            for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
+                if (config.useG1GC) {
+                    if (write.getBarrierType() != BarrierType.NONE) {
+                        Assert.assertEquals(1, write.successors().count());
+                        Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
+                        Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
+                    }
+                } else {
+                    if (write.getBarrierType() != BarrierType.NONE) {
+                        Assert.assertEquals(1, write.successors().count());
+                        Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
+                    }
+                }
+            }
+
+            for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
+                if (read.getBarrierType() != BarrierType.NONE) {
+                    Assert.assertTrue(read.getAddress() instanceof OffsetAddressNode);
+                    JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant();
+                    Assert.assertNotNull(constDisp);
+                    Assert.assertEquals(referentOffset, constDisp.asLong());
+                    Assert.assertTrue(config.useG1GC);
+                    Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
+                    Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private void test2(final String snippet, Object... args) throws Exception {
+        HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe);
+        code.executeVarargs(args);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java
new file mode 100644
index 0000000..ce367b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopyNode;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * The following tests validate the write barrier verification phase. For every tested snippet, an
+ * array of write barrier indices and the total write barrier number are passed as parameters. The
+ * indices denote the barriers that will be manually removed. The write barrier verification phase
+ * runs after the write barrier removal and depending on the result an assertion might be generated.
+ * The tests anticipate the presence or not of an assertion generated by the verification phase.
+ */
+public class WriteBarrierVerificationTest extends HotSpotGraalCompilerTest {
+
+    public static int barrierIndex;
+
+    private final GraalHotSpotVMConfig config = runtime().getVMConfig();
+
+    public static class Container {
+
+        public Container a;
+        public Container b;
+    }
+
+    private static native void safepoint();
+
+    public static void test1Snippet(Container main) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        safepoint();
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1() {
+        test("test1Snippet", 2, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2() {
+        test("test1Snippet", 2, new int[]{2});
+    }
+
+    public static void test2Snippet(Container main) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test3() {
+        test("test2Snippet", 2, new int[]{1});
+    }
+
+    @Test
+    public void test4() {
+        test("test2Snippet", 2, new int[]{2});
+    }
+
+    public static void test3Snippet(Container main, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 1;
+                main.a = temp1;
+                barrierIndex = 2;
+                main.b = temp2;
+            } else {
+                barrierIndex = 3;
+                main.a = temp1;
+                barrierIndex = 4;
+                main.b = temp2;
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test5() {
+        test("test3Snippet", 4, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test6() {
+        test("test3Snippet", 4, new int[]{3, 4});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test7() {
+        test("test3Snippet", 4, new int[]{1});
+    }
+
+    @Test
+    public void test8() {
+        test("test3Snippet", 4, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test9() {
+        test("test3Snippet", 4, new int[]{3});
+    }
+
+    @Test
+    public void test10() {
+        test("test3Snippet", 4, new int[]{4});
+    }
+
+    public static void test4Snippet(Container main, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 2;
+                main.a = temp1;
+                barrierIndex = 3;
+                main.b = temp2;
+            } else {
+                barrierIndex = 4;
+                main.a = temp2;
+                barrierIndex = 5;
+                main.b = temp1;
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test11() {
+        test("test4Snippet", 5, new int[]{2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test12() {
+        test("test4Snippet", 5, new int[]{4, 5});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test13() {
+        test("test4Snippet", 5, new int[]{1});
+    }
+
+    public static void test5Snippet(Container main) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (main.a == main.b) {
+            barrierIndex = 2;
+            main.a = temp1;
+            barrierIndex = 3;
+            main.b = temp2;
+        } else {
+            barrierIndex = 4;
+            main.a = temp2;
+            barrierIndex = 5;
+            main.b = temp1;
+        }
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test14() {
+        test("test5Snippet", 5, new int[]{1});
+    }
+
+    @Test
+    public void test15() {
+        test("test5Snippet", 5, new int[]{2});
+    }
+
+    @Test
+    public void test16() {
+        test("test5Snippet", 5, new int[]{4});
+    }
+
+    @Test
+    public void test17() {
+        test("test5Snippet", 5, new int[]{3});
+    }
+
+    @Test
+    public void test18() {
+        test("test5Snippet", 5, new int[]{5});
+    }
+
+    @Test
+    public void test19() {
+        test("test5Snippet", 5, new int[]{2, 3});
+    }
+
+    @Test
+    public void test20() {
+        test("test5Snippet", 5, new int[]{4, 5});
+    }
+
+    public static void test6Snippet(Container main, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (test) {
+            barrierIndex = 2;
+            main.a = temp1;
+            barrierIndex = 3;
+            main.b = temp1.a.a;
+        } else {
+            barrierIndex = 4;
+            main.a = temp2;
+            barrierIndex = 5;
+            main.b = temp2.a.a;
+        }
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test21() {
+        test("test6Snippet", 5, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test22() {
+        test("test6Snippet", 5, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test23() {
+        test("test6Snippet", 5, new int[]{3});
+    }
+
+    @Test
+    public void test24() {
+        test("test6Snippet", 5, new int[]{4});
+    }
+
+    public static void test7Snippet(Container main, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (test) {
+            barrierIndex = 2;
+            main.a = temp1;
+        }
+        barrierIndex = 3;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test
+    public void test25() {
+        test("test7Snippet", 3, new int[]{2});
+    }
+
+    @Test
+    public void test26() {
+        test("test7Snippet", 3, new int[]{3});
+    }
+
+    @Test
+    public void test27() {
+        test("test7Snippet", 3, new int[]{2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test28() {
+        test("test7Snippet", 3, new int[]{1});
+    }
+
+    public static void test8Snippet(Container main, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main.a = temp1;
+        }
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test29() {
+        test("test8Snippet", 2, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test30() {
+        test("test8Snippet", 2, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test31() {
+        test("test8Snippet", 2, new int[]{1, 2});
+    }
+
+    public static void test9Snippet(Container main1, Container main2, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+        } else {
+            barrierIndex = 2;
+            main2.a = temp1;
+        }
+        barrierIndex = 3;
+        main1.b = temp2;
+        barrierIndex = 4;
+        main2.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test32() {
+        test("test9Snippet", 4, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test33() {
+        test("test9Snippet", 4, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test34() {
+        test("test9Snippet", 4, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test35() {
+        test("test9Snippet", 4, new int[]{4});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test36() {
+        test("test9Snippet", 4, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test37() {
+        test("test9Snippet", 4, new int[]{3, 4});
+    }
+
+    public static void test10Snippet(Container main1, Container main2, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+            barrierIndex = 2;
+            main2.a = temp2;
+        } else {
+            barrierIndex = 3;
+            main2.a = temp1;
+        }
+        barrierIndex = 4;
+        main1.b = temp2;
+        barrierIndex = 5;
+        main2.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test38() {
+        test("test10Snippet", 5, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test39() {
+        test("test10Snippet", 5, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test40() {
+        test("test10Snippet", 5, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test41() {
+        test("test10Snippet", 5, new int[]{4});
+    }
+
+    @Test
+    public void test42() {
+        test("test10Snippet", 5, new int[]{5});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test43() {
+        test("test10Snippet", 5, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test44() {
+        test("test10Snippet", 5, new int[]{1, 2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test45() {
+        test("test10Snippet", 5, new int[]{3, 4});
+    }
+
+    public static void test11Snippet(Container main1, Container main2, Container main3, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+            barrierIndex = 2;
+            main3.a = temp1;
+            if (!test) {
+                barrierIndex = 3;
+                main2.a = temp2;
+            } else {
+                barrierIndex = 4;
+                main1.a = temp2;
+                barrierIndex = 5;
+                main3.a = temp2;
+            }
+        } else {
+            barrierIndex = 6;
+            main1.b = temp2;
+            for (int i = 0; i < 10; i++) {
+                barrierIndex = 7;
+                main3.a = temp1;
+            }
+            barrierIndex = 8;
+            main3.b = temp2;
+        }
+        barrierIndex = 9;
+        main1.b = temp2;
+        barrierIndex = 10;
+        main2.b = temp2;
+        barrierIndex = 11;
+        main3.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test46() {
+        test("test11Snippet", 11, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test47() {
+        test("test11Snippet", 11, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test48() {
+        test("test11Snippet", 11, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test49() {
+        test("test11Snippet", 11, new int[]{6});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test50() {
+        test("test11Snippet", 11, new int[]{7});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test51() {
+        test("test11Snippet", 11, new int[]{8});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test52() {
+        test("test11Snippet", 11, new int[]{9});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test53() {
+        test("test11Snippet", 11, new int[]{10});
+    }
+
+    @Test
+    public void test54() {
+        test("test11Snippet", 11, new int[]{4});
+    }
+
+    @Test
+    public void test55() {
+        test("test11Snippet", 11, new int[]{5});
+    }
+
+    @Test
+    public void test56() {
+        test("test11Snippet", 11, new int[]{11});
+    }
+
+    public static void test12Snippet(Container main, Container main1, boolean test) {
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 7;
+        main1.a = temp1;
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 1;
+                main.a = temp1;
+                barrierIndex = 2;
+                main.b = temp2;
+            } else {
+                barrierIndex = 3;
+                main.a = temp1;
+                barrierIndex = 4;
+                main.b = temp2;
+            }
+        }
+        barrierIndex = 5;
+        main.a = temp1;
+        barrierIndex = 6;
+        main.b = temp1;
+        barrierIndex = 8;
+        main1.b = temp1;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test57() {
+        test("test12Snippet", 8, new int[]{5});
+    }
+
+    @Test
+    public void test58() {
+        test("test12Snippet", 8, new int[]{6});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test59() {
+        test("test12Snippet", 8, new int[]{7});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test60() {
+        test("test12Snippet", 8, new int[]{8});
+    }
+
+    public static void test13Snippet(Object[] a, Object[] b) {
+        System.arraycopy(a, 0, b, 0, a.length);
+    }
+
+    @Test
+    public void test61() {
+        GraphPredicate checkForUnsafeArrayCopy = graph -> graph.getNodes().filter(UnsafeArrayCopyNode.class).count() > 0 ? 1 : 0;
+        testPredicate("test13Snippet", checkForUnsafeArrayCopy, new int[]{});
+    }
+
+    private interface GraphPredicate {
+        int apply(StructuredGraph graph);
+    }
+
+    private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) {
+        GraphPredicate noCheck = noArg -> expectedBarriers;
+        testPredicate(snippet, noCheck, removedBarrierIndices);
+    }
+
+    @SuppressWarnings("try")
+    private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) {
+        try (Scope d = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) {
+            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            HighTierContext highTierContext = getDefaultHighTierContext();
+            new InliningPhase(new CanonicalizerPhase()).apply(graph, highTierContext);
+
+            MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
+            new GuardLoweringPhase().apply(graph, midTierContext);
+            new LoopSafepointInsertionPhase().apply(graph);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, highTierContext);
+
+            new WriteBarrierAdditionPhase(config).apply(graph);
+
+            int barriers = 0;
+            // First, the total number of expected barriers is checked.
+            if (config.useG1GC) {
+                barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() +
+                                graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count();
+                Assert.assertTrue(expectedBarriers.apply(graph) * 2 == barriers);
+            } else {
+                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count();
+                Assert.assertTrue(expectedBarriers.apply(graph) == barriers);
+            }
+            ResolvedJavaField barrierIndexField = getMetaAccess().lookupJavaField(WriteBarrierVerificationTest.class.getDeclaredField("barrierIndex"));
+            LocationIdentity barrierIdentity = new FieldLocationIdentity(barrierIndexField);
+            // Iterate over all write nodes and remove barriers according to input indices.
+            NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
+
+                @Override
+                protected Boolean processNode(FixedNode node, Boolean currentState) {
+                    if (node instanceof WriteNode) {
+                        WriteNode write = (WriteNode) node;
+                        LocationIdentity obj = write.getLocationIdentity();
+                        if (obj.equals(barrierIdentity)) {
+                            /*
+                             * A "barrierIndex" variable was found and is checked against the input
+                             * barrier array.
+                             */
+                            if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) {
+                                return true;
+                            }
+                        }
+                    } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
+                        // Remove flagged write barriers.
+                        if (currentState) {
+                            graph.removeFixed(((FixedWithNextNode) node));
+                            return false;
+                        }
+                    }
+                    return currentState;
+                }
+
+                private boolean eliminateBarrier(int index, int[] map) {
+                    for (int i = 0; i < map.length; i++) {
+                        if (map[i] == index) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+                @Override
+                protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
+                    return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
+                }
+
+                @Override
+                protected Boolean merge(AbstractMergeNode merge, List<Boolean> states) {
+                    return false;
+                }
+
+                @Override
+                protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+                    return false;
+                }
+            };
+
+            DebugConfig debugConfig = DebugScope.getConfig();
+            DebugConfig fixedConfig = debugConfig == null ? null
+                            : Debug.fixedConfig(0, 0, false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
+            try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+                ReentrantNodeIterator.apply(closure, graph.start(), false);
+                new WriteBarrierVerificationPhase(config).apply(graph);
+            } catch (AssertionError error) {
+                /*
+                 * Catch assertion, test for expected one and re-throw in order to validate unit
+                 * test.
+                 */
+                Assert.assertTrue(error.getMessage().contains("Write barrier must be present"));
+                throw error;
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java
new file mode 100644
index 0000000..7e4ac5f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt;
+import static org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory.GRAAL_OPTION_PROPERTY_PREFIX;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.CompilationRequest;
+
+/**
+ * A watch dog that monitors the duration and compilation rate during a
+ * {@linkplain HotSpotGraalRuntimeProvider#isBootstrapping() bootstrap}. If time spent bootstrapping
+ * exceeds a specified timeout or the compilation rate falls below a given ratio of the maximum
+ * observed compilation rate (i.e., compilation slows down too much), the compiler will ignore all
+ * subsequent compilation requests, effectively draining the bootstrap completion queue and
+ * expediting completion of bootstrap. Note that the compilation rate is computed over the whole
+ * execution, not just the most recent measurement period. This means a sudden but temporary drop in
+ * any given measurement period won't cause bootstrapping to terminate early.
+ *
+ * This mechanism is based on past observations that a significantly falling bootstrap compilation
+ * rate implies a configuration where bootstrapping will take an unreasonably long time and it's
+ * better to drain the bootstrap compilation queue at some point that risk triggering timeouts in
+ * external harnesses such as integration tests.
+ */
+final class BootstrapWatchDog extends Thread {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Ratio of the maximum compilation rate below which the bootstrap compilation rate must not fall " +
+                       "(0 or less disables monitoring).", type = OptionType.Debug)
+        public static final OptionValue<Double> BootstrapWatchDogCriticalRateRatio = new OptionValue<>(0.25D);
+        @Option(help = "Maximum time in minutes to spend bootstrapping (0 to disable this limit).", type = OptionType.Debug)
+        public static final OptionValue<Double> BootstrapTimeout = new OptionValue<>(15D);
+        // @formatter:on
+    }
+
+    /**
+     * Count of completed compilations. This is updated by the compiler threads and read by the
+     * watch dog thread.
+     */
+    private final AtomicInteger compilations = new AtomicInteger();
+
+    /**
+     * Set to true once the compilation rate drops too low or bootstrapping times out.
+     */
+    private boolean hitCriticalRateOrTimeout;
+
+    /**
+     * The maximum compilation rate seen during execution.
+     */
+    private double maxRate;
+
+    private final HotSpotGraalRuntimeProvider graalRuntime;
+
+    /**
+     * Creates and returns a {@link BootstrapWatchDog} if
+     * {@link Options#BootstrapWatchDogCriticalRateRatio} is not set to 0 otherwise returns
+     * {@code null}.
+     */
+    static BootstrapWatchDog maybeCreate(HotSpotGraalRuntimeProvider graalRuntime) {
+        return MAX_RATE_DECREASE <= 0.0D && TIMEOUT == 0 ? null : new BootstrapWatchDog(graalRuntime);
+    }
+
+    private BootstrapWatchDog(HotSpotGraalRuntimeProvider graalRuntime) {
+        this.setName(getClass().getSimpleName());
+        this.start();
+        this.graalRuntime = graalRuntime;
+    }
+
+    /**
+     * Set to true to debug the watch dog.
+     */
+    private static final boolean DEBUG = Boolean.getBoolean("debug.graal.BootstrapWatchDog");
+
+    /**
+     * Seconds to delay before starting to measure the compilation rate.
+     */
+    private static final int INITIAL_DELAY = 10;
+
+    /**
+     * Seconds between each compilation rate measurement.
+     */
+    private static final long EPOCH = 5;
+
+    /**
+     * Time in seconds before stopping a bootstrap.
+     */
+    private static final int TIMEOUT = (int) (Options.BootstrapTimeout.getValue() * 60);
+
+    /**
+     * The watch dog {@link #hitCriticalCompilationRateOrTimeout() hits} a critical compilation rate
+     * if the current compilation rate falls below this ratio of the maximum compilation rate.
+     */
+    private static final double MAX_RATE_DECREASE = Options.BootstrapWatchDogCriticalRateRatio.getValue();
+
+    @Override
+    public void run() {
+        if (DEBUG) {
+            TTY.printf("%nStarted %s%n", this);
+        }
+        long start = System.currentTimeMillis();
+        Map<Thread, Watch> requestsAtTimeout = null;
+        Map<Thread, StackTraceElement[]> stacksAtTimeout = null;
+        try {
+            Thread.sleep(INITIAL_DELAY * 1000);
+            while (true) {
+                int currentCompilations = compilations.get();
+                long elapsed = System.currentTimeMillis() - start;
+                double rate = currentCompilations / seconds(elapsed);
+                if (DEBUG) {
+                    TTY.printf("%.2f: compilation rate is %.2f/sec%n", seconds(elapsed), rate);
+                }
+                if (rate > maxRate) {
+                    maxRate = rate;
+                } else if (rate < (maxRate * MAX_RATE_DECREASE)) {
+                    TTY.printf("%nAfter %.2f seconds bootstrapping, compilation rate is %.2f compilations per second " +
+                                    "which is below %.2f times the max compilation rate of %.2f%n", seconds(elapsed), rate, MAX_RATE_DECREASE, maxRate);
+                    TTY.printf("To enable monitoring of long running individual compilations, re-run with -D%s%s=%.2f%n",
+                                    GRAAL_OPTION_PROPERTY_PREFIX, CompilationWatchDog.Options.CompilationWatchDogStartDelay.getName(),
+                                    seconds(elapsed) - 5);
+                    hitCriticalRateOrTimeout = true;
+                    return;
+                }
+                if (elapsed > TIMEOUT * 1000) {
+                    if (requestsAtTimeout == null) {
+                        requestsAtTimeout = snapshotRequests();
+                        stacksAtTimeout = new HashMap<>();
+                        for (Thread t : requestsAtTimeout.keySet()) {
+                            stacksAtTimeout.put(t, t.getStackTrace());
+                        }
+                    } else {
+                        TTY.printf("%nHit bootstrapping timeout after %.2f seconds%n", seconds(elapsed));
+                        Map<Thread, Watch> requestsNow = snapshotRequests();
+                        for (Map.Entry<Thread, Watch> e : requestsAtTimeout.entrySet()) {
+                            Thread t = e.getKey();
+                            CompilationRequest request1 = requestsAtTimeout.get(t).request;
+                            CompilationRequest request2 = requestsNow.get(t).request;
+                            if (request1 != null && request1 == request2) {
+                                StackTraceElement[] stackTraceNow = t.getStackTrace();
+                                TTY.printf("Printing stack trace for current compilation of %s lasting more than %d seconds:%n%s",
+                                                fmt(request1.getMethod()), EPOCH, fmt(stackTraceNow));
+                                if (Arrays.equals(stacksAtTimeout.get(t), stackTraceNow)) {
+                                    TTY.printf("\t** Identical stack trace %d seconds ago, implying a hung compilation **%n",
+                                                    EPOCH);
+                                }
+                            } else {
+                                if (DEBUG) {
+                                    TTY.printf("%s was compiling %s%n", t, fmt(request1.getMethod()));
+                                }
+                            }
+                        }
+                        hitCriticalRateOrTimeout = true;
+                        return;
+                    }
+                }
+                if (!graalRuntime.isBootstrapping()) {
+                    return;
+                }
+
+                Thread.sleep(EPOCH * 1000);
+            }
+        } catch (InterruptedException e) {
+            e.printStackTrace(TTY.out);
+        }
+    }
+
+    private Map<Thread, Watch> snapshotRequests() {
+        synchronized (requests) {
+            return new HashMap<>(requests);
+        }
+    }
+
+    private static double seconds(long ms) {
+        return (double) ms / 1000;
+    }
+
+    /**
+     * Queries whether a critically low compilation rate or {@link #TIMEOUT} occurred.
+     */
+    boolean hitCriticalCompilationRateOrTimeout() {
+        return hitCriticalRateOrTimeout;
+    }
+
+    private final Map<Thread, Watch> requests = new HashMap<>();
+    private final ThreadLocal<Watch> requestForThread = new ThreadLocal<>();
+
+    /**
+     * Opens a scope for watching the compilation of a given method.
+     *
+     * @param request a compilation request about to be processed
+     * @return {@code null} if the compilation watch dog is disabled otherwise this object. The
+     *         returned value should be used in a {@code try}-with-resources statement whose scope
+     *         is the whole compilation so that leaving the scope will cause {@link Watch#close()}
+     *         to be called.
+     */
+    Watch watch(CompilationRequest request) {
+        Watch watch = requestForThread.get();
+        if (watch == null) {
+            watch = new Watch();
+            synchronized (requests) {
+                requests.put(Thread.currentThread(), watch);
+            }
+        }
+        watch.open(request);
+        return watch;
+    }
+
+    /**
+     * Object for watching the compilations requests of a single compiler thread.
+     */
+    class Watch implements AutoCloseable {
+        CompilationRequest request;
+
+        void open(CompilationRequest r) {
+            assert this.request == null;
+            this.request = r;
+        }
+
+        @Override
+        public void close() {
+            compilations.incrementAndGet();
+            request = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationCounters.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationCounters.java
new file mode 100644
index 0000000..e5f0f4e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationCounters.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt;
+import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.str;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+
+import jdk.vm.ci.code.CompilationRequest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+class CompilationCounters {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "The number of compilations allowed for any method before " +
+                       "the VM exits (a value of 0 means there is no limit).", type = OptionType.Debug)
+        public static final OptionValue<Integer> CompilationCountLimit = new StableOptionValue<>(0);
+        // @formatter:on
+    }
+
+    CompilationCounters() {
+        TTY.println("Warning: Compilation counters enabled, excessive recompilation of a method will cause a failure!");
+    }
+
+    private final Map<ResolvedJavaMethod, Integer> counters = new HashMap<>();
+
+    /**
+     * Counts the number of compilations for the {@link ResolvedJavaMethod} of the
+     * {@link CompilationRequest}. If the number of compilations exceeds
+     * {@link Options#CompilationCountLimit} this method prints an error message and exits the VM.
+     *
+     * @param method the method about to be compiled
+     */
+    synchronized void countCompilation(ResolvedJavaMethod method) {
+        Integer val = counters.get(method);
+        val = val != null ? val + 1 : 1;
+        counters.put(method, val);
+        if (val > Options.CompilationCountLimit.getValue()) {
+            TTY.printf("Error. Method %s was compiled too many times. Number of compilations: %d\n", fmt(method),
+                            CompilationCounters.Options.CompilationCountLimit.getValue());
+            TTY.println("==================================== High compilation counters ====================================");
+            SortedSet<Map.Entry<ResolvedJavaMethod, Integer>> sortedCounters = new TreeSet<>(new CounterComparator());
+            for (Map.Entry<ResolvedJavaMethod, Integer> e : counters.entrySet()) {
+                sortedCounters.add(e);
+            }
+            for (Map.Entry<ResolvedJavaMethod, Integer> entry : sortedCounters) {
+                if (entry.getValue() >= Options.CompilationCountLimit.getValue() / 2) {
+                    TTY.out.printf("%d\t%s%n", entry.getValue(), str(entry.getKey()));
+                }
+            }
+            TTY.flush();
+            System.exit(-1);
+        }
+    }
+
+    static final class CounterComparator implements Comparator<Map.Entry<ResolvedJavaMethod, Integer>> {
+        @Override
+        public int compare(Entry<ResolvedJavaMethod, Integer> o1, Entry<ResolvedJavaMethod, Integer> o2) {
+            if (o1.getValue() < o2.getValue()) {
+                return -1;
+            }
+            if (o1.getValue() > o2.getValue()) {
+                return 1;
+            }
+            return str(o1.getKey()).compareTo(str(o2.getKey()));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java
new file mode 100644
index 0000000..a40d071
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static java.lang.Thread.currentThread;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Deque;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.Management;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionValue;
+import com.sun.management.ThreadMXBean;
+
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+
+@SuppressWarnings("unused")
+public final class CompilationStatistics {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enables CompilationStatistics.")
+        public static final OptionValue<Boolean> UseCompilationStatistics = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    private static final long RESOLUTION = 100000000;
+    private static final boolean ENABLED = Options.UseCompilationStatistics.getValue();
+
+    private static final CompilationStatistics DUMMY = new CompilationStatistics(null, false);
+
+    private static ConcurrentLinkedDeque<CompilationStatistics> list = new ConcurrentLinkedDeque<>();
+
+    private static final ThreadLocal<Deque<CompilationStatistics>> current = new ThreadLocal<Deque<CompilationStatistics>>() {
+
+        @Override
+        protected Deque<CompilationStatistics> initialValue() {
+            return new ArrayDeque<>();
+        }
+    };
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    private static @interface NotReported {
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    private static @interface TimeValue {
+    }
+
+    private static long zeroTime = System.nanoTime();
+
+    private static long getThreadAllocatedBytes() {
+        ThreadMXBean thread = (ThreadMXBean) Management.getThreadMXBean();
+        return thread.getThreadAllocatedBytes(currentThread().getId());
+    }
+
+    @NotReported private final long startTime;
+    @NotReported private long threadAllocatedBytesStart;
+
+    private int bytecodeCount;
+    private int codeSize;
+    @TimeValue private long duration;
+    private long memoryUsed;
+    private final boolean osr;
+    private final String holder;
+    private final String name;
+    private final String signature;
+
+    private CompilationStatistics(HotSpotResolvedJavaMethod method, boolean osr) {
+        this.osr = osr;
+        if (method != null) {
+            holder = method.getDeclaringClass().getName();
+            name = method.getName();
+            signature = method.getSignature().toMethodDescriptor();
+            startTime = System.nanoTime();
+            bytecodeCount = method.getCodeSize();
+            threadAllocatedBytesStart = getThreadAllocatedBytes();
+        } else {
+            holder = "";
+            name = "";
+            signature = "";
+            startTime = 0;
+        }
+    }
+
+    public void finish(HotSpotResolvedJavaMethod method, HotSpotInstalledCode code) {
+        if (ENABLED) {
+            duration = System.nanoTime() - startTime;
+            codeSize = (int) code.getCodeSize();
+            memoryUsed = getThreadAllocatedBytes() - threadAllocatedBytesStart;
+            if (current.get().getLast() != this) {
+                throw new RuntimeException("mismatch in finish()");
+            }
+            current.get().removeLast();
+        }
+    }
+
+    public static CompilationStatistics current() {
+        return current.get().isEmpty() ? null : current.get().getLast();
+    }
+
+    public static CompilationStatistics create(HotSpotResolvedJavaMethod method, boolean isOSR) {
+        if (ENABLED) {
+            CompilationStatistics stats = new CompilationStatistics(method, isOSR);
+            list.add(stats);
+            current.get().addLast(stats);
+            return stats;
+        } else {
+            return DUMMY;
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    public static void clear(String dumpName) {
+        if (!ENABLED) {
+            return;
+        }
+        try {
+            ConcurrentLinkedDeque<CompilationStatistics> snapshot = list;
+            long snapshotZeroTime = zeroTime;
+
+            list = new ConcurrentLinkedDeque<>();
+            zeroTime = System.nanoTime();
+
+            Date now = new Date();
+            String dateString = (now.getYear() + 1900) + "-" + (now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getHours() + "" + now.getMinutes();
+
+            dumpCompilations(snapshot, dumpName, dateString);
+
+            try (FileOutputStream fos = new FileOutputStream("timeline_" + dateString + "_" + dumpName + ".csv", true); PrintStream out = new PrintStream(fos)) {
+
+                long[] timeSpent = new long[10000];
+                int maxTick = 0;
+                for (CompilationStatistics stats : snapshot) {
+                    long start = stats.startTime - snapshotZeroTime;
+                    long duration = stats.duration;
+                    if (start < 0) {
+                        duration -= -start;
+                        start = 0;
+                    }
+
+                    int tick = (int) (start / RESOLUTION);
+                    long timeLeft = RESOLUTION - (start % RESOLUTION);
+
+                    while (tick < timeSpent.length && duration > 0) {
+                        if (tick > maxTick) {
+                            maxTick = tick;
+                        }
+                        timeSpent[tick] += Math.min(timeLeft, duration);
+                        duration -= timeLeft;
+                        tick++;
+                        timeLeft = RESOLUTION;
+                    }
+                }
+                String timelineName = System.getProperty("stats.timeline.name");
+                if (timelineName != null && !timelineName.isEmpty()) {
+                    out.printf("%s%c", CSVUtil.Escape.escape(timelineName), CSVUtil.SEPARATOR);
+                }
+                for (int i = 0; i < maxTick; i++) {
+                    out.printf("%d%c", normalize(timeSpent[i]), CSVUtil.SEPARATOR);
+                }
+                // print last column
+                out.printf("%d", normalize(timeSpent[maxTick]));
+                out.println();
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static long normalize(long time) {
+        return time * 100 / RESOLUTION;
+    }
+
+    protected static void dumpCompilations(ConcurrentLinkedDeque<CompilationStatistics> snapshot, String dumpName, String dateString) throws IllegalAccessException, FileNotFoundException {
+        String fileName = "compilations_" + dateString + "_" + dumpName + ".csv";
+        char separator = '\t';
+        try (PrintStream out = new PrintStream(fileName)) {
+            // output the list of all compilations
+
+            Field[] declaredFields = CompilationStatistics.class.getDeclaredFields();
+            ArrayList<Field> fields = new ArrayList<>();
+            for (Field field : declaredFields) {
+                if (!Modifier.isStatic(field.getModifiers()) && !field.isAnnotationPresent(NotReported.class)) {
+                    fields.add(field);
+                }
+            }
+            String format = CSVUtil.buildFormatString("%s", separator, fields.size());
+            CSVUtil.Escape.println(out, separator, CSVUtil.QUOTE, CSVUtil.ESCAPE, format, fields.toArray());
+            for (CompilationStatistics stats : snapshot) {
+                Object[] values = new Object[fields.size()];
+                for (int i = 0; i < fields.size(); i++) {
+                    Field field = fields.get(i);
+                    if (field.isAnnotationPresent(TimeValue.class)) {
+                        double value = field.getLong(stats) / 1000000d;
+                        values[i] = String.format(Locale.ENGLISH, "%.3f", value);
+                    } else {
+                        values[i] = field.get(stats);
+                    }
+                }
+                CSVUtil.Escape.println(out, separator, CSVUtil.QUOTE, CSVUtil.ESCAPE, format, values);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java
new file mode 100644
index 0000000..e86a1bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnBailout;
+import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintAfterCompilation;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintFilter;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
+import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
+
+import java.util.List;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Management;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.TimeSource;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.hotspot.EventProvider;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotNmethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCICompiler;
+import jdk.vm.ci.services.JVMCIServiceLocator;
+
+//JaCoCo Exclude
+
+public class CompilationTask {
+
+    private static final DebugCounter BAILOUTS = Debug.counter("Bailouts");
+
+    private static final EventProvider eventProvider;
+
+    static {
+        List<EventProvider> providers = JVMCIServiceLocator.getProviders(EventProvider.class);
+        if (providers.size() > 1) {
+            throw new GraalError("Multiple %s providers found: %s", EventProvider.class.getName(), providers);
+        } else if (providers.isEmpty()) {
+            eventProvider = EventProvider.createEmptyEventProvider();
+        } else {
+            eventProvider = providers.get(0);
+        }
+    }
+
+    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+
+    private final HotSpotGraalCompiler compiler;
+    private final HotSpotCompilationIdentifier compilationId;
+
+    private HotSpotInstalledCode installedCode;
+
+    /**
+     * Specifies whether the compilation result is installed as the
+     * {@linkplain HotSpotNmethod#isDefault() default} nmethod for the compiled method.
+     */
+    private final boolean installAsDefault;
+
+    private final boolean useProfilingInfo;
+
+    static class Lazy {
+        /**
+         * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the
+         * current compiler thread, e.g. total allocated bytes.
+         */
+        static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean();
+    }
+
+    public CompilationTask(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault) {
+        this.jvmciRuntime = jvmciRuntime;
+        this.compiler = compiler;
+        this.compilationId = new HotSpotCompilationIdentifier(request);
+        this.useProfilingInfo = useProfilingInfo;
+        this.installAsDefault = installAsDefault;
+    }
+
+    public HotSpotResolvedJavaMethod getMethod() {
+        return getRequest().getMethod();
+    }
+
+    /**
+     * Returns the compilation id of this task.
+     *
+     * @return compile id
+     */
+    public int getId() {
+        return getRequest().getId();
+    }
+
+    public int getEntryBCI() {
+        return getRequest().getEntryBCI();
+    }
+
+    /**
+     * @return the compilation id plus a trailing '%' is the compilation is an OSR to match
+     *         PrintCompilation style output
+     */
+    public String getIdString() {
+        if (getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) {
+            return getId() + "%";
+        } else {
+            return Integer.toString(getId());
+        }
+    }
+
+    public HotSpotInstalledCode getInstalledCode() {
+        return installedCode;
+    }
+
+    /**
+     * Time spent in compilation.
+     */
+    private static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+
+    /**
+     * Counts the number of compiled {@linkplain CompilationResult#getBytecodeSize() bytecodes}.
+     */
+    private static final DebugCounter CompiledBytecodes = Debug.counter("CompiledBytecodes");
+
+    /**
+     * Counts the number of compiled {@linkplain CompilationResult#getBytecodeSize() bytecodes} for
+     * which {@linkplain CompilationResult#getTargetCode()} code was installed.
+     */
+    private static final DebugCounter CompiledAndInstalledBytecodes = Debug.counter("CompiledAndInstalledBytecodes");
+
+    /**
+     * Counts the number of installed {@linkplain CompilationResult#getTargetCodeSize()} bytes.
+     */
+    private static final DebugCounter InstalledCodeSize = Debug.counter("InstalledCodeSize");
+
+    /**
+     * Time spent in code installation.
+     */
+    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
+
+    @SuppressWarnings("try")
+    public HotSpotCompilationRequestResult runCompilation() {
+        HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
+        GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
+        final long threadId = Thread.currentThread().getId();
+        int entryBCI = getEntryBCI();
+        final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
+        HotSpotResolvedJavaMethod method = getMethod();
+
+        // register the compilation id in the method metrics
+        if (Debug.isMethodMeterEnabled()) {
+            if (getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) {
+                Debug.methodMetrics(method).addToMetric(getId(), "CompilationIdOSR");
+            } else {
+                Debug.methodMetrics(method).addToMetric(getId(), "CompilationId");
+            }
+        }
+
+        // Log a compilation event.
+        EventProvider.CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
+
+        // If there is already compiled code for this method on our level we simply return.
+        // JVMCI compiles are always at the highest compile level, even in non-tiered mode so we
+        // only need to check for that value.
+        if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
+            return null;
+        }
+
+        CompilationResult result = null;
+        try (DebugCloseable a = CompilationTime.start()) {
+            CompilationStatistics stats = CompilationStatistics.create(method, isOSR);
+            final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
+            final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
+            if (printCompilation) {
+                TTY.println(getMethodDescription() + "...");
+            }
+
+            TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
+            final long start;
+            final long allocatedBytesBefore;
+            if (printAfterCompilation || printCompilation) {
+                start = TimeSource.getTimeNS();
+                allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
+            } else {
+                start = 0L;
+                allocatedBytesBefore = 0L;
+            }
+
+            try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) {
+                // Begin the compilation event.
+                compilationEvent.begin();
+                /*
+                 * Disable inlining if HotSpot has it disabled unless it's been explicitly set in
+                 * Graal.
+                 */
+                boolean disableInlining = !config.inline && !Inline.hasBeenSet();
+                try (OverrideScope s1 = disableInlining ? OptionValue.override(Inline, false) : null) {
+                    result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId);
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            } finally {
+                // End the compilation event.
+                compilationEvent.end();
+
+                filter.remove();
+
+                if (printAfterCompilation || printCompilation) {
+                    final long stop = TimeSource.getTimeNS();
+                    final long duration = (stop - start) / 1000000;
+                    final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1;
+                    final int bytecodeSize = result != null ? result.getBytecodeSize() : 0;
+                    final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId);
+                    final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
+
+                    if (printAfterCompilation) {
+                        TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
+                    } else if (printCompilation) {
+                        TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
+                    }
+                }
+            }
+
+            if (result != null) {
+                try (DebugCloseable b = CodeInstallationTime.start()) {
+                    installMethod(result);
+                }
+            }
+            stats.finish(method, installedCode);
+            if (result != null) {
+                return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize());
+            }
+            return null;
+        } catch (BailoutException bailout) {
+            BAILOUTS.increment();
+            if (ExitVMOnBailout.getValue()) {
+                TTY.out.println(method.format("Bailout in %H.%n(%p)"));
+                bailout.printStackTrace(TTY.out);
+                System.exit(-1);
+            } else if (PrintBailout.getValue()) {
+                TTY.out.println(method.format("Bailout in %H.%n(%p)"));
+                bailout.printStackTrace(TTY.out);
+            }
+            /*
+             * Handling of permanent bailouts: Permanent bailouts that can happen for example due to
+             * unsupported unstructured control flow in the bytecodes of a method must not be
+             * retried. Hotspot compile broker will ensure that no recompilation at the given tier
+             * will happen if retry is false.
+             */
+            final boolean permanentBailout = bailout.isPermanent();
+            if (permanentBailout && PrintBailout.getValue()) {
+                TTY.println("Permanent bailout %s compiling method %s %s.", bailout.getMessage(), HotSpotGraalCompiler.str(method), (isOSR ? "OSR" : ""));
+            }
+            return HotSpotCompilationRequestResult.failure(bailout.getMessage(), !permanentBailout);
+        } catch (Throwable t) {
+            // Log a failure event.
+            EventProvider.CompilerFailureEvent event = eventProvider.newCompilerFailureEvent();
+            if (event.shouldWrite()) {
+                event.setCompileId(getId());
+                event.setMessage(t.getMessage());
+                event.commit();
+            }
+
+            handleException(t);
+            /*
+             * Treat random exceptions from the compiler as indicating a problem compiling this
+             * method. Report the result of toString instead of getMessage to ensure that the
+             * exception type is included in the output in case there's no detail mesage.
+             */
+            return HotSpotCompilationRequestResult.failure(t.toString(), false);
+        } finally {
+            try {
+                int compiledBytecodes = 0;
+                int codeSize = 0;
+                if (result != null) {
+                    compiledBytecodes = result.getBytecodeSize();
+                    CompiledBytecodes.add(compiledBytecodes);
+                    if (installedCode != null) {
+                        codeSize = installedCode.getSize();
+                        CompiledAndInstalledBytecodes.add(compiledBytecodes);
+                        InstalledCodeSize.add(codeSize);
+                    }
+                }
+
+                // Log a compilation event.
+                if (compilationEvent.shouldWrite()) {
+                    compilationEvent.setMethod(method.format("%H.%n(%p)"));
+                    compilationEvent.setCompileId(getId());
+                    compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
+                    compilationEvent.setSucceeded(result != null && installedCode != null);
+                    compilationEvent.setIsOsr(isOSR);
+                    compilationEvent.setCodeSize(codeSize);
+                    compilationEvent.setInlinedBytes(compiledBytecodes);
+                    compilationEvent.commit();
+                }
+            } catch (Throwable t) {
+                handleException(t);
+            }
+        }
+    }
+
+    protected void handleException(Throwable t) {
+        /*
+         * Automatically enable ExitVMOnException during bootstrap or when asserts are enabled but
+         * respect ExitVMOnException if it's been explicitly set.
+         */
+        boolean exitVMOnException = ExitVMOnException.getValue();
+        if (!ExitVMOnException.hasBeenSet()) {
+            assert (exitVMOnException = true) == true;
+            if (!exitVMOnException) {
+                HotSpotGraalRuntimeProvider runtime = compiler.getGraalRuntime();
+                if (runtime.isBootstrapping()) {
+                    exitVMOnException = true;
+                }
+            }
+        }
+
+        if (PrintStackTraceOnException.getValue() || exitVMOnException) {
+            try {
+                t.printStackTrace(TTY.out);
+            } catch (Throwable throwable) {
+                // Don't let an exception here change the other control flow
+            }
+        }
+
+        if (exitVMOnException) {
+            System.exit(-1);
+        }
+    }
+
+    private String getMethodDescription() {
+        HotSpotResolvedJavaMethod method = getMethod();
+        return String.format("%-6d JVMCI %-70s %-45s %-50s %s", getId(), method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
+                        getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
+    }
+
+    @SuppressWarnings("try")
+    private void installMethod(final CompilationResult compResult) {
+        final CodeCacheProvider codeCache = jvmciRuntime.getHostJVMCIBackend().getCodeCache();
+        installedCode = null;
+        Object[] context = {new DebugDumpScope(getIdString(), true), codeCache, getMethod(), compResult};
+        try (Scope s = Debug.scope("CodeInstall", context)) {
+            HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(getRequest().getMethod(), getRequest(), compResult);
+            installedCode = (HotSpotInstalledCode) codeCache.installCode(getRequest().getMethod(), compiledCode, null, getRequest().getMethod().getSpeculationLog(), installAsDefault);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Compilation[id=" + getId() + ", " + getMethod().format("%H.%n(%p)") + (getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "@" + getEntryBCI()) + "]";
+    }
+
+    private HotSpotCompilationRequest getRequest() {
+        return compilationId.getRequest();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java
new file mode 100644
index 0000000..eb9532c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A watch dog for reporting long running compilations. This is designed to be an always on
+ * mechanism for the purpose of getting better reports from customer sites. As such, it only exits
+ * the VM when it is very sure about a stuck compilation as opposed to only observing a long running
+ * compilation. In both cases, it logs messages to {@link TTY}.
+ *
+ * A watch dog thread is associated with each compiler thread. It wakes up every
+ * {@value #SPIN_TIMEOUT_MS} milliseconds to observe the state of the compiler thread. After the
+ * first {@link Options#CompilationWatchDogStartDelay} seconds of a specific compilation, the watch
+ * dog reports a long running compilation. Every
+ * {@link Options#CompilationWatchDogStackTraceInterval} seconds after that point in time where the
+ * same compilation is still executing, the watch dog takes a stack trace of the compiler thread. If
+ * more than {@value Options#NonFatalIdenticalCompilationSnapshots} contiguous identical stack
+ * traces are seen, the watch dog reports a stuck compilation and exits the VM.
+ */
+class CompilationWatchDog extends Thread implements AutoCloseable {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Delay in seconds before watch dog monitoring a compilation (0 disables monitoring).", type = OptionType.Debug)
+        public static final OptionValue<Double> CompilationWatchDogStartDelay = new OptionValue<>(30.0D);
+        @Option(help = "Interval in seconds between a watch dog reporting stack traces for long running compilations.", type = OptionType.Debug)
+        public static final OptionValue<Double> CompilationWatchDogStackTraceInterval = new OptionValue<>(30.0D);
+        @Option(help = "Number of contiguous identical compiler thread stack traces allowed before the VM exits " +
+                       "on the basis of a stuck compilation.", type = OptionType.Debug)
+         public static final OptionValue<Integer> NonFatalIdenticalCompilationSnapshots = new OptionValue<>(10);
+        // @formatter:on
+    }
+
+    private enum WatchDogState {
+        /**
+         * The watch dog thread sleeps currently, either no method is currently compiled, or no
+         * method is compiled long enough to be monitored.
+         */
+        SLEEPING,
+        /**
+         * The watch dog thread identified a compilation that already takes long enough to be
+         * interesting. It will sleep and wake up periodically and check if the current compilation
+         * takes too long. If it takes too long it will start collecting stack traces from the
+         * compiler thread.
+         */
+        WATCHING_WITHOUT_STACK_INSPECTION,
+        /**
+         * The watch dog thread is fully monitoring the compiler thread. It takes stack traces
+         * periodically and sleeps again until the next period. If the number of stack traces
+         * reaches a certain upper bound and those stack traces are equal it will shut down the
+         * entire VM with an error.
+         */
+        WATCHING_WITH_STACK_INSPECTION
+    }
+
+    /**
+     * The number of milliseconds a watch dog thread sleeps between observing the state of the
+     * compilation thread it is associated with. Most compilations are expected to complete within
+     * this time period and thus not be actively monitored by the watch dog.
+     */
+    private static final int SPIN_TIMEOUT_MS = 1000;
+    private static final long START_DELAY_MS = ms(Options.CompilationWatchDogStartDelay.getValue());
+    private static final long STACK_TRACE_INTERVAL_MS = ms(Options.CompilationWatchDogStackTraceInterval.getValue());
+    private static final boolean ENABLED = START_DELAY_MS > 0.0D;
+
+    private WatchDogState state = WatchDogState.SLEEPING;
+    private final Thread compilerThread;
+    private volatile ResolvedJavaMethod currentMethod;
+    private volatile int currentId;
+    private ResolvedJavaMethod lastWatched;
+
+    // The 4 fields below are for a single compilation being watched
+    private long elapsed;
+    private int traceIntervals;
+    private int numberOfIdenticalStackTraces;
+    private StackTraceElement[] lastStackTrace;
+
+    CompilationWatchDog(Thread compilerThread) {
+        this.compilerThread = compilerThread;
+        this.setName("WatchDog" + getId() + "[" + compilerThread.getName() + "]");
+        this.setPriority(Thread.MAX_PRIORITY);
+        this.setDaemon(true);
+    }
+
+    public void startCompilation(ResolvedJavaMethod method, int id) {
+        trace("start %s", fmt(method));
+        this.currentMethod = method;
+        this.currentId = id;
+    }
+
+    public void stopCompilation() {
+        trace(" stop %s", fmt(currentMethod));
+        this.currentMethod = null;
+    }
+
+    private void reset() {
+        elapsed = 0;
+        traceIntervals = 0;
+        numberOfIdenticalStackTraces = 0;
+        lastWatched = null;
+        lastStackTrace = null;
+        state = WatchDogState.SLEEPING;
+    }
+
+    private void tick(WatchDogState newState) {
+        state = newState;
+    }
+
+    /**
+     * Saves the current stack trace {@link StackTraceElement} of the monitored compiler thread
+     * {@link CompilationWatchDog#compilerThread}.
+     *
+     * @param newStackTrace the current stack trace of the monitored compiler thread
+     * @return {@code true} if the stack trace is equal to the last stack trace (or if it is the
+     *         first one) and {@code false} if it is not equal to the last one.
+     */
+    private boolean recordStackTrace(StackTraceElement[] newStackTrace) {
+        if (lastStackTrace == null) {
+            lastStackTrace = newStackTrace;
+            return true;
+        }
+        if (!Arrays.equals(lastStackTrace, newStackTrace)) {
+            lastStackTrace = newStackTrace;
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set to true to debug the watch dog.
+     */
+    private static final boolean DEBUG = Boolean.getBoolean("debug.graal.CompilationWatchDog");
+
+    private void trace(String format, Object... args) {
+        if (DEBUG) {
+            TTY.println(this + ": " + String.format(format, args));
+        }
+    }
+
+    private static long ms(double seconds) {
+        return (long) seconds * 1000;
+    }
+
+    private static double secs(long ms) {
+        return (double) ms / 1000;
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    @Override
+    public void run() {
+        trace("Started%n", this);
+        try {
+            while (true) {
+                // get a copy of the last set method
+                final ResolvedJavaMethod currentlyCompiling = currentMethod;
+                if (currentlyCompiling == null) {
+                    // continue sleeping, compilation is either over before starting
+                    // to watch the compiler thread or no compilation at all started
+                    reset();
+                } else {
+                    switch (state) {
+                        case SLEEPING:
+                            lastWatched = currentlyCompiling;
+                            elapsed = 0;
+                            tick(WatchDogState.WATCHING_WITHOUT_STACK_INSPECTION);
+                            break;
+                        case WATCHING_WITHOUT_STACK_INSPECTION:
+                            if (currentlyCompiling == lastWatched) {
+                                if (elapsed >= START_DELAY_MS) {
+                                    // we looked at the same compilation for a certain time
+                                    // so now we start to collect stack traces
+                                    tick(WatchDogState.WATCHING_WITH_STACK_INSPECTION);
+                                    trace("changes mode to watching with stack traces");
+                                } else {
+                                    // we still compile the same method but won't collect traces yet
+                                    trace("watching without stack traces [%.2f seconds]", secs(elapsed));
+                                }
+                                elapsed += SPIN_TIMEOUT_MS;
+                            } else {
+                                // compilation finished before we exceeded initial watching period
+                                reset();
+                            }
+                            break;
+                        case WATCHING_WITH_STACK_INSPECTION:
+                            if (currentlyCompiling == lastWatched) {
+                                if (elapsed >= START_DELAY_MS + (traceIntervals * STACK_TRACE_INTERVAL_MS)) {
+                                    trace("took a stack trace");
+                                    boolean newStackTrace = recordStackTrace(compilerThread.getStackTrace());
+                                    if (!newStackTrace) {
+                                        trace("%d identical stack traces in a row", numberOfIdenticalStackTraces);
+                                        numberOfIdenticalStackTraces = 0;
+                                    }
+                                    numberOfIdenticalStackTraces++;
+                                    if (numberOfIdenticalStackTraces > Options.NonFatalIdenticalCompilationSnapshots.getValue()) {
+                                        synchronized (CompilationWatchDog.class) {
+                                            TTY.printf("======================= WATCH DOG THREAD =======================%n" +
+                                                            "%s took %d identical stack traces, which indicates a stuck compilation (id=%d) of %s%n%sExiting VM%n", this,
+                                                            numberOfIdenticalStackTraces, currentId, fmt(currentMethod), fmt(lastStackTrace));
+                                            System.exit(-1);
+                                        }
+                                    } else if (newStackTrace) {
+                                        synchronized (CompilationWatchDog.class) {
+                                            TTY.printf("======================= WATCH DOG THREAD =======================%n" +
+                                                            "%s detected long running compilation (id=%d) of %s [%.2f seconds]%n%s", this, currentId, fmt(currentMethod),
+                                                            secs(elapsed), fmt(lastStackTrace));
+                                        }
+                                    }
+                                    traceIntervals++;
+                                } else {
+                                    // we still watch the compilation in the same trace interval
+                                    trace("watching with stack traces [%.2f seconds]", secs(elapsed));
+                                }
+                                elapsed += SPIN_TIMEOUT_MS;
+                            } else {
+                                // compilation finished before we are able to collect stack traces
+                                reset();
+                            }
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                Thread.sleep(SPIN_TIMEOUT_MS);
+            }
+        } catch (Throwable t) {
+            synchronized (CompilationWatchDog.class) {
+                TTY.printf("%s encountered an exception%n%s%n", this, fmt(t));
+            }
+        }
+    }
+
+    private static final ThreadLocal<CompilationWatchDog> WATCH_DOGS = ENABLED ? new ThreadLocal<>() : null;
+
+    /**
+     * Opens a scope for watching the compilation of a given method.
+     *
+     * @param method a method about to be compiled
+     * @param id compilation request identifier
+     * @return {@code null} if the compilation watch dog is disabled otherwise this object. The
+     *         returned value should be used in a {@code try}-with-resources statement whose scope
+     *         is the whole compilation so that leaving the scope will cause {@link #close()} to be
+     *         called.
+     */
+    static CompilationWatchDog watch(ResolvedJavaMethod method, int id) {
+        if (ENABLED) {
+            // Lazily get a watch dog thread for the current compiler thread
+            CompilationWatchDog watchDog = WATCH_DOGS.get();
+            if (watchDog == null) {
+                Thread currentThread = currentThread();
+                watchDog = new CompilationWatchDog(currentThread);
+                WATCH_DOGS.set(watchDog);
+                watchDog.start();
+            }
+            watchDog.startCompilation(method, id);
+            return watchDog;
+        }
+        return null;
+    }
+
+    @Override
+    public void close() {
+        stopCompilation();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java
new file mode 100644
index 0000000..fae52a2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldClasspath;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldConfig;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldExcludeMethodFilter;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldMethodFilter;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStartAt;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStopAt;
+import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldVerbose;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.core.CompilerThreadFactory;
+import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.MethodFilter;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.MemUseTrackerImpl;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.options.OptionsParser;
+import org.graalvm.compiler.options.OptionsParser.OptionConsumer;
+
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.runtime.JVMCICompiler;
+import jdk.vm.ci.services.Services;
+
+/**
+ * This class implements compile-the-world functionality with JVMCI.
+ */
+public final class CompileTheWorld {
+
+    /**
+     * Magic token to denote that JDK classes are to be compiled. If {@link Util#Java8OrEarlier},
+     * then the classes in {@code rt.jar} are compiled. Otherwise the classes in {@code
+     * <java.home>/lib/modules} are compiled.
+     */
+    public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
+
+    /**
+     * A mechanism for overriding JVMCI options that affect compilation. A {@link Config} object
+     * should be used in a try-with-resources statement to ensure overriding of options is scoped
+     * properly. For example:
+     *
+     * <pre>
+     *     Config config = ...;
+     *     try (AutoCloseable s = config == null ? null : config.apply()) {
+     *         // perform a JVMCI compilation
+     *     }
+     * </pre>
+     */
+    @SuppressWarnings("serial")
+    public static class Config extends HashMap<OptionValue<?>, Object> implements OptionConsumer {
+        /**
+         * Creates a {@link Config} object by parsing a set of space separated override options.
+         *
+         * @param options a space separated set of option value settings with each option setting in
+         *            a {@code -Dgraal.<name>=<value>} format but without the leading
+         *            {@code -Dgraal.}. Ignored if null.
+         */
+        public Config(String options) {
+            if (options != null) {
+                Map<String, String> optionSettings = new HashMap<>();
+                for (String optionSetting : options.split("\\s+|#")) {
+                    OptionsParser.parseOptionSettingTo(optionSetting, optionSettings);
+                }
+                OptionsParser.parseOptions(optionSettings, this, ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader()));
+            }
+        }
+
+        /**
+         * Applies the overrides represented by this object. The overrides are in effect until
+         * {@link OverrideScope#close()} is called on the returned object.
+         */
+        OverrideScope apply() {
+            return OptionValue.override(this);
+        }
+
+        @Override
+        public void set(OptionDescriptor desc, Object value) {
+            put(desc.getOptionValue(), value);
+        }
+    }
+
+    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+
+    private final HotSpotGraalCompiler compiler;
+
+    /**
+     * Class path denoting classes to compile.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldClasspath
+     */
+    private final String inputClassPath;
+
+    /**
+     * Class index to start compilation at.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldStartAt
+     */
+    private final int startAt;
+
+    /**
+     * Class index to stop compilation at.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldStopAt
+     */
+    private final int stopAt;
+
+    /** Only compile methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] methodFilters;
+
+    /** Exclude methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] excludeMethodFilters;
+
+    // Counters
+    private int classFileCounter = 0;
+    private AtomicLong compiledMethodsCounter = new AtomicLong();
+    private AtomicLong compileTime = new AtomicLong();
+    private AtomicLong memoryUsed = new AtomicLong();
+
+    private boolean verbose;
+    private final Config config;
+
+    /**
+     * Signal that the threads should start compiling in multithreaded mode.
+     */
+    private boolean running;
+
+    private ThreadPoolExecutor threadPool;
+
+    /**
+     * Creates a compile-the-world instance.
+     *
+     * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile
+     * @param startAt index of the class file to start compilation at
+     * @param stopAt index of the class file to stop compilation at
+     * @param methodFilters
+     * @param excludeMethodFilters
+     */
+    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, String files, Config config, int startAt, int stopAt, String methodFilters,
+                    String excludeMethodFilters, boolean verbose) {
+        this.jvmciRuntime = jvmciRuntime;
+        this.compiler = compiler;
+        this.inputClassPath = files;
+        this.startAt = startAt;
+        this.stopAt = stopAt;
+        this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
+        this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters);
+        this.verbose = verbose;
+        this.config = config;
+
+        // We don't want the VM to exit when a method fails to compile...
+        config.putIfAbsent(ExitVMOnException, false);
+
+        // ...but we want to see exceptions.
+        config.putIfAbsent(PrintBailout, true);
+        config.putIfAbsent(PrintStackTraceOnException, true);
+    }
+
+    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler) {
+        this(jvmciRuntime, compiler, CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue(),
+                        CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
+    }
+
+    /**
+     * Compiles all methods in all classes in {@link #inputClassPath}. If {@link #inputClassPath}
+     * equals {@link #SUN_BOOT_CLASS_PATH} the boot class path is used.
+     */
+    public void compile() throws Throwable {
+        // By default only report statistics for the CTW threads themselves
+        if (!GraalDebugConfig.Options.DebugValueThreadFilter.hasBeenSet()) {
+            GraalDebugConfig.Options.DebugValueThreadFilter.setValue("^CompileTheWorld");
+        }
+        if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) {
+            String bcpEntry = null;
+            if (Java8OrEarlier) {
+                final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
+                for (int i = 0; i < entries.length && bcpEntry == null; i++) {
+                    String entry = entries[i];
+                    File entryFile = new File(entry);
+                    // We stop at rt.jar, unless it is the first boot class path entry.
+                    if (entryFile.getName().endsWith("rt.jar") && entryFile.isFile()) {
+                        bcpEntry = entry;
+                    }
+                }
+            } else {
+                bcpEntry = System.getProperty("java.home") + "/lib/modules".replace('/', File.separatorChar);
+            }
+            compile(bcpEntry);
+        } else {
+            compile(inputClassPath);
+        }
+    }
+
+    public void println() {
+        println("");
+    }
+
+    public void println(String format, Object... args) {
+        println(String.format(format, args));
+    }
+
+    public void println(String s) {
+        println(verbose, s);
+    }
+
+    public static void println(boolean cond, String s) {
+        if (cond) {
+            TTY.println(s);
+        }
+    }
+
+    public void printStackTrace(Throwable t) {
+        if (verbose) {
+            t.printStackTrace(TTY.out);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void dummy() {
+    }
+
+    /**
+     * Abstraction over different types of class path entries.
+     */
+    abstract static class ClassPathEntry implements Closeable {
+        final String name;
+
+        ClassPathEntry(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Creates a {@link ClassLoader} for loading classes from this entry.
+         */
+        public abstract ClassLoader createClassLoader() throws IOException;
+
+        /**
+         * Gets the list of classes available under this entry.
+         */
+        public abstract List<String> getClassNames() throws IOException;
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public void close() throws IOException {
+        }
+    }
+
+    /**
+     * A class path entry that is a normal file system directory.
+     */
+    static class DirClassPathEntry extends ClassPathEntry {
+
+        private final File dir;
+
+        DirClassPathEntry(String name) {
+            super(name);
+            dir = new File(name);
+            assert dir.isDirectory();
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = dir.toURI().toURL();
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            List<String> classNames = new ArrayList<>();
+            String root = dir.getPath();
+            SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    if (attrs.isRegularFile()) {
+                        File path = file.toFile();
+                        if (path.getName().endsWith(".class")) {
+                            String pathString = path.getPath();
+                            assert pathString.startsWith(root);
+                            String classFile = pathString.substring(root.length() + 1);
+                            String className = classFile.replace(File.separatorChar, '.');
+                            classNames.add(className.replace('/', '.').substring(0, className.length() - ".class".length()));
+                        }
+                    }
+                    return super.visitFile(file, attrs);
+                }
+            };
+            Files.walkFileTree(dir.toPath(), visitor);
+            return classNames;
+        }
+    }
+
+    /**
+     * A class path entry that is a jar or zip file.
+     */
+    static class JarClassPathEntry extends ClassPathEntry {
+
+        private final JarFile jarFile;
+
+        JarClassPathEntry(String name) throws IOException {
+            super(name);
+            jarFile = new JarFile(name);
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = new URL("jar", "", "file:" + name + "!/");
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            Enumeration<JarEntry> e = jarFile.entries();
+            List<String> classNames = new ArrayList<>(jarFile.size());
+            while (e.hasMoreElements()) {
+                JarEntry je = e.nextElement();
+                if (je.isDirectory() || !je.getName().endsWith(".class")) {
+                    continue;
+                }
+                String className = je.getName().substring(0, je.getName().length() - ".class".length());
+                classNames.add(className.replace('/', '.'));
+            }
+            return classNames;
+        }
+
+        @Override
+        public void close() throws IOException {
+            jarFile.close();
+        }
+    }
+
+    /**
+     * Name of the property that limits the set of modules processed by CompileTheWorld.
+     */
+    public static final String LIMITMODS_PROPERTY_NAME = "CompileTheWorld.limitmods";
+
+    /**
+     * A class path entry that is a jimage file.
+     */
+    static class ImageClassPathEntry extends ClassPathEntry {
+
+        private final File jimage;
+
+        ImageClassPathEntry(String name) {
+            super(name);
+            jimage = new File(name);
+            assert jimage.isFile();
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = jimage.toURI().toURL();
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            String prop = System.getProperty(LIMITMODS_PROPERTY_NAME);
+            Set<String> limitmods = prop == null ? null : new HashSet<>(Arrays.asList(prop.split(",")));
+            List<String> classNames = new ArrayList<>();
+            String[] entries = readJimageEntries();
+            for (String e : entries) {
+                if (e.endsWith(".class") && !e.endsWith("module-info.class")) {
+                    assert e.charAt(0) == '/' : e;
+                    int endModule = e.indexOf('/', 1);
+                    assert endModule != -1 : e;
+                    if (limitmods != null) {
+                        String module = e.substring(1, endModule);
+                        if (!limitmods.contains(module)) {
+                            continue;
+                        }
+                    }
+                    // Strip the module prefix and convert to dotted form
+                    String className = e.substring(endModule + 1).replace('/', '.');
+                    // Strip ".class" suffix
+                    className = className.replace('/', '.').substring(0, className.length() - ".class".length());
+                    classNames.add(className);
+                }
+            }
+            return classNames;
+        }
+
+        private String[] readJimageEntries() {
+            try {
+                // Use reflection so this can be compiled on JDK8
+                Path path = FileSystems.getDefault().getPath(name);
+                Method open = Class.forName("jdk.internal.jimage.BasicImageReader").getDeclaredMethod("open", Path.class);
+                Object reader = open.invoke(null, path);
+                Method getEntryNames = reader.getClass().getDeclaredMethod("getEntryNames");
+                getEntryNames.setAccessible(true);
+                String[] entries = (String[]) getEntryNames.invoke(reader);
+                return entries;
+            } catch (Exception e) {
+                TTY.println("Error reading entries from " + name + ": " + e);
+                return new String[0];
+            }
+        }
+    }
+
+    /**
+     * Determines if a given path denotes a jimage file.
+     *
+     * @param path file path
+     * @return {@code true} if the 4 byte integer (in native endianness) at the start of
+     *         {@code path}'s contents is {@code 0xCAFEDADA}
+     */
+    static boolean isJImage(String path) {
+        try {
+            FileChannel channel = FileChannel.open(Paths.get(path), StandardOpenOption.READ);
+            ByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
+            map.order(ByteOrder.nativeOrder()).asIntBuffer().get(0);
+            int magic = map.asIntBuffer().get(0);
+            if (magic == 0xCAFEDADA) {
+                return true;
+            }
+        } catch (IOException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Compiles all methods in all classes in a given class path.
+     *
+     * @param classPath class path denoting classes to compile
+     * @throws IOException
+     */
+    @SuppressWarnings("try")
+    private void compile(String classPath) throws IOException {
+        final String[] entries = classPath.split(File.pathSeparator);
+        long start = System.currentTimeMillis();
+
+        CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
+            @Override
+            public GraalDebugConfig getDebugConfig() {
+                if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+                    return DebugEnvironment.initialize(System.out, compiler.getGraalRuntime().getHostProviders().getSnippetReflection());
+                }
+                return null;
+            }
+        });
+
+        try {
+            // compile dummy method to get compiler initialized outside of the
+            // config debug override.
+            HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
+                            CompileTheWorld.class.getDeclaredMethod("dummy"));
+            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), useProfilingInfo, installAsDefault);
+            task.runCompilation();
+        } catch (NoSuchMethodException | SecurityException e1) {
+            printStackTrace(e1);
+        }
+
+        /*
+         * Always use a thread pool, even for single threaded mode since it simplifies the use of
+         * DebugValueThreadFilter to filter on the thread names.
+         */
+        int threadCount = 1;
+        if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue()) {
+            threadCount = CompileTheWorldOptions.CompileTheWorldThreads.getValue();
+            if (threadCount == 0) {
+                threadCount = Runtime.getRuntime().availableProcessors();
+            }
+        } else {
+            running = true;
+        }
+        threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+
+        try (OverrideScope s = config.apply()) {
+            for (int i = 0; i < entries.length; i++) {
+                final String entry = entries[i];
+
+                ClassPathEntry cpe;
+                if (entry.endsWith(".zip") || entry.endsWith(".jar")) {
+                    cpe = new JarClassPathEntry(entry);
+                } else if (isJImage(entry)) {
+                    assert !Java8OrEarlier;
+                    cpe = new ImageClassPathEntry(entry);
+                } else {
+                    if (!new File(entry).isDirectory()) {
+                        println("CompileTheWorld : Skipped classes in " + entry);
+                        println();
+                        continue;
+                    }
+                    cpe = new DirClassPathEntry(entry);
+                }
+
+                if (methodFilters == null || methodFilters.length == 0) {
+                    println("CompileTheWorld : Compiling all classes in " + entry);
+                } else {
+                    String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include);
+                }
+                if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
+                    String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude);
+                }
+                println();
+
+                ClassLoader loader = cpe.createClassLoader();
+
+                for (String className : cpe.getClassNames()) {
+
+                    // Are we done?
+                    if (classFileCounter >= stopAt) {
+                        break;
+                    }
+
+                    classFileCounter++;
+
+                    if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
+                        continue;
+                    }
+
+                    try {
+                        // Load and initialize class
+                        Class<?> javaClass = Class.forName(className, true, loader);
+
+                        // Pre-load all classes in the constant pool.
+                        try {
+                            HotSpotResolvedObjectType objectType = HotSpotResolvedObjectType.fromObjectClass(javaClass);
+                            ConstantPool constantPool = objectType.getConstantPool();
+                            for (int cpi = 1; cpi < constantPool.length(); cpi++) {
+                                constantPool.loadReferencedType(cpi, Bytecodes.LDC);
+                            }
+                        } catch (Throwable t) {
+                            // If something went wrong during pre-loading we just ignore it.
+                            println("Preloading failed for (%d) %s: %s", classFileCounter, className, t);
+                        }
+
+                        /*
+                         * Only check filters after class loading and resolution to mitigate impact
+                         * on reproducibility.
+                         */
+                        if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, className)) {
+                            continue;
+                        }
+                        if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, className)) {
+                            continue;
+                        }
+
+                        // Are we compiling this class?
+                        MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
+                        if (classFileCounter >= startAt) {
+                            println("CompileTheWorld (%d) : %s", classFileCounter, className);
+
+                            // Compile each constructor/method in the class.
+                            for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
+                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(constructor);
+                                if (canBeCompiled(javaMethod, constructor.getModifiers())) {
+                                    compileMethod(javaMethod);
+                                }
+                            }
+                            for (Method method : javaClass.getDeclaredMethods()) {
+                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method);
+                                if (canBeCompiled(javaMethod, method.getModifiers())) {
+                                    compileMethod(javaMethod);
+                                }
+                            }
+
+                            // Also compile the class initializer if it exists
+                            HotSpotResolvedJavaMethod clinit = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaType(javaClass).getClassInitializer();
+                            if (clinit != null && canBeCompiled(clinit, clinit.getModifiers())) {
+                                compileMethod(clinit);
+                            }
+                        }
+                    } catch (Throwable t) {
+                        println("CompileTheWorld (%d) : Skipping %s %s", classFileCounter, className, t.toString());
+                        printStackTrace(t);
+                    }
+                }
+                cpe.close();
+            }
+        }
+
+        if (!running) {
+            startThreads();
+        }
+        int wakeups = 0;
+        while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
+            if (wakeups % 15 == 0) {
+                TTY.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
+            }
+            try {
+                threadPool.awaitTermination(1, TimeUnit.SECONDS);
+                wakeups++;
+            } catch (InterruptedException e) {
+            }
+        }
+        threadPool = null;
+
+        long elapsedTime = System.currentTimeMillis() - start;
+
+        println();
+        if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue()) {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
+                            compileTime.get(), memoryUsed.get());
+        } else {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
+        }
+    }
+
+    private synchronized void startThreads() {
+        running = true;
+        // Wake up any waiting threads
+        notifyAll();
+    }
+
+    private synchronized void waitToRun() {
+        while (!running) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void compileMethod(HotSpotResolvedJavaMethod method) throws InterruptedException, ExecutionException {
+        if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) {
+            return;
+        }
+        if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) {
+            return;
+        }
+        Future<?> task = threadPool.submit(new Runnable() {
+            @Override
+            public void run() {
+                waitToRun();
+                try (OverrideScope s = config.apply()) {
+                    compileMethod(method, classFileCounter);
+                }
+            }
+        });
+        if (threadPool.getCorePoolSize() == 1) {
+            task.get();
+        }
+    }
+
+    /**
+     * Compiles a method and gathers some statistics.
+     */
+    private void compileMethod(HotSpotResolvedJavaMethod method, int counter) {
+        try {
+            long start = System.currentTimeMillis();
+            long allocatedAtStart = MemUseTrackerImpl.getCurrentThreadAllocatedBytes();
+            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
+            HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
+            // For more stable CTW execution, disable use of profiling information
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, useProfilingInfo, installAsDefault);
+            task.runCompilation();
+
+            // Invalidate the generated code so the code cache doesn't fill up
+            HotSpotInstalledCode installedCode = task.getInstalledCode();
+            if (installedCode != null) {
+                installedCode.invalidate();
+            }
+
+            memoryUsed.getAndAdd(MemUseTrackerImpl.getCurrentThreadAllocatedBytes() - allocatedAtStart);
+            compileTime.getAndAdd(System.currentTimeMillis() - start);
+            compiledMethodsCounter.incrementAndGet();
+        } catch (Throwable t) {
+            // Catch everything and print a message
+            println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
+            printStackTrace(t);
+        }
+    }
+
+    /**
+     * Determines if a method should be compiled (Cf. CompilationPolicy::can_be_compiled).
+     *
+     * @return true if it can be compiled, false otherwise
+     */
+    private boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) {
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return false;
+        }
+        GraalHotSpotVMConfig c = compiler.getGraalRuntime().getVMConfig();
+        if (c.dontCompileHugeMethods && javaMethod.getCodeSize() > c.hugeMethodLimit) {
+            println(verbose || methodFilters != null,
+                            String.format("CompileTheWorld (%d) : Skipping huge method %s (use -XX:-DontCompileHugeMethods or -XX:HugeMethodLimit=%d to include it)", classFileCounter,
+                                            javaMethod.format("%H.%n(%p):%r"),
+                                            javaMethod.getCodeSize()));
+            return false;
+        }
+        // Allow use of -XX:CompileCommand=dontinline to exclude problematic methods
+        if (!javaMethod.canBeInlined()) {
+            return false;
+        }
+        // Skip @Snippets for now
+        for (Annotation annotation : javaMethod.getAnnotations()) {
+            if (annotation.annotationType().equals(Snippet.class)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Services.exportJVMCITo(CompileTheWorld.class);
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) HotSpotJVMCIRuntime.runtime().getCompiler();
+        compiler.compileTheWorld();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java
new file mode 100644
index 0000000..4f3032d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Options related to {@link CompileTheWorld}.
+ *
+ * Note: This must be a top level class to work around for
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=477597">Eclipse bug 477597</a>.
+ */
+public class CompileTheWorldOptions {
+    // @formatter:off
+    @Option(help = "Class path denoting methods to compile", type = OptionType.Debug)
+    public static final OptionValue<String> CompileTheWorldClasspath = new OptionValue<>(CompileTheWorld.SUN_BOOT_CLASS_PATH);
+    @Option(help = "Verbose CompileTheWorld operation", type = OptionType.Debug)
+    public static final OptionValue<Boolean> CompileTheWorldVerbose = new OptionValue<>(true);
+    @Option(help = "The number of CompileTheWorld iterations to perform", type = OptionType.Debug)
+    public static final OptionValue<Integer> CompileTheWorldIterations = new OptionValue<>(1);
+    @Option(help = "Only compile methods matching this filter", type = OptionType.Debug)
+    public static final OptionValue<String> CompileTheWorldMethodFilter = new OptionValue<>(null);
+    @Option(help = "Exclude methods matching this filter from compilation", type = OptionType.Debug)
+    public static final OptionValue<String> CompileTheWorldExcludeMethodFilter = new OptionValue<>(null);
+    @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
+    public static final OptionValue<Integer> CompileTheWorldStartAt = new OptionValue<>(1);
+    @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
+    public static final OptionValue<Integer> CompileTheWorldStopAt = new OptionValue<>(Integer.MAX_VALUE);
+    @Option(help = "Option value overrides to use during compile the world. For example, " +
+                   "to disable inlining and partial escape analysis specify 'PartialEscapeAnalysis=false Inline=false'. " +
+                   "The format for each option is the same as on the command line just without the '-Dgraal.' prefix.", type = OptionType.Debug)
+    public static final OptionValue<String> CompileTheWorldConfig = new OptionValue<>(null);
+
+    @Option(help = "Run CTW using as many threads as there are processors on the system", type = OptionType.Debug)
+    public static final OptionValue<Boolean> CompileTheWorldMultiThreaded = new OptionValue<>(false);
+    @Option(help = "Number of threads to use for multithreaded CTW.  Defaults to Runtime.getRuntime().availableProcessors()", type = OptionType.Debug)
+    public static final OptionValue<Integer> CompileTheWorldThreads = new OptionValue<>(0);
+    // @formatter:on
+
+    /**
+     * Overrides {@link #CompileTheWorldStartAt} and {@link #CompileTheWorldStopAt} from {@code -XX}
+     * HotSpot options of the same name if the latter have non-default values.
+     */
+    public static void overrideWithNativeOptions(GraalHotSpotVMConfig c) {
+        if (c.compileTheWorldStartAt != 1) {
+            CompileTheWorldStartAt.setValue(c.compileTheWorldStartAt);
+        }
+        if (c.compileTheWorldStopAt != Integer.MAX_VALUE) {
+            CompileTheWorldStopAt.setValue(c.compileTheWorldStopAt);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java
new file mode 100644
index 0000000..3940a9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static jdk.vm.ci.common.InitTimer.timer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.common.InitTimer;
+
+/**
+ * A factory that creates the {@link CompilerConfiguration} the Graal compiler will use. Each
+ * factory must have a unique {@link #name} and {@link #autoSelectionPriority}. The latter imposes a
+ * total ordering between factories for the purpose of auto-selecting the factory to use.
+ */
+public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> {
+
+    static class Options {
+        // @formatter:off
+        @Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " +
+                       "with the highest auto-selection priority is used. To see the set of available configurations, " +
+                       "supply the value 'help' to this option.", type = OptionType.Expert)
+        public static final OptionValue<String> CompilerConfiguration = new OptionValue<>(null);
+        // @formatter:on
+    }
+
+    /**
+     * The name of this factory. This must be unique across all factory instances and is used when
+     * selecting a factory based on the value of {@link Options#CompilerConfiguration}.
+     */
+    private final String name;
+
+    /**
+     * The priority of this factory. This must be unique across all factory instances and is used
+     * when selecting a factory when {@link Options#CompilerConfiguration} is omitted
+     */
+    private final int autoSelectionPriority;
+
+    protected CompilerConfigurationFactory(String name, int autoSelectionPriority) {
+        this.name = name;
+        this.autoSelectionPriority = autoSelectionPriority;
+        assert checkAndAddNewFactory(this);
+    }
+
+    public abstract CompilerConfiguration createCompilerConfiguration();
+
+    /**
+     * Collect the set of available {@linkplain HotSpotBackendFactory backends} for this compiler
+     * configuration.
+     */
+    public BackendMap createBackendMap() {
+        // default to backend with the same name as the compiler configuration
+        return new DefaultBackendMap(name);
+    }
+
+    public interface BackendMap {
+        HotSpotBackendFactory getBackendFactory(Architecture arch);
+    }
+
+    public static class DefaultBackendMap implements BackendMap {
+
+        private final IdentityHashMap<Class<? extends Architecture>, HotSpotBackendFactory> backends = new IdentityHashMap<>();
+
+        @SuppressWarnings("try")
+        public DefaultBackendMap(String backendName) {
+            try (InitTimer t = timer("HotSpotBackendFactory.register")) {
+                for (HotSpotBackendFactory backend : GraalServices.load(HotSpotBackendFactory.class)) {
+                    if (backend.getName().equals(backendName)) {
+                        Class<? extends Architecture> arch = backend.getArchitecture();
+                        HotSpotBackendFactory oldEntry = backends.put(arch, backend);
+                        assert oldEntry == null || oldEntry == backend : "duplicate Graal backend";
+                    }
+                }
+            }
+        }
+
+        @Override
+        public final HotSpotBackendFactory getBackendFactory(Architecture arch) {
+            return backends.get(arch.getClass());
+        }
+    }
+
+    @Override
+    public int compareTo(CompilerConfigurationFactory o) {
+        if (autoSelectionPriority > o.autoSelectionPriority) {
+            return -1;
+        }
+        if (autoSelectionPriority < o.autoSelectionPriority) {
+            return 1;
+        }
+        assert this == o : "distinct compiler configurations cannot have the same auto selection priority";
+        return 0;
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
+
+    /**
+     * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all
+     * {@link CompilerConfigurationFactory} instances.
+     */
+    private static final List<CompilerConfigurationFactory> factories = assertionsEnabled() ? new ArrayList<>() : null;
+
+    private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) {
+        for (CompilerConfigurationFactory other : factories) {
+            assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name;
+            assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() +
+                            ": " + factory.autoSelectionPriority;
+        }
+        factories.add(factory);
+        return true;
+    }
+
+    /**
+     * @return sorted list of {@link CompilerConfigurationFactory}s
+     */
+    private static List<CompilerConfigurationFactory> getAllCandidates() {
+        List<CompilerConfigurationFactory> candidates = new ArrayList<>();
+        for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) {
+            candidates.add(candidate);
+        }
+        Collections.sort(candidates);
+        return candidates;
+    }
+
+    /**
+     * Selects and instantiates a {@link CompilerConfigurationFactory}. The selection algorithm is
+     * as follows: if {@code name} is non-null, then select the factory with the same name else if
+     * {@link Options#CompilerConfiguration}{@code .getValue()} is non-null then select the factory
+     * whose name matches the value else select the factory with the highest
+     * {@link #autoSelectionPriority} value.
+     *
+     * @param name the name of the compiler configuration to select (optional)
+     */
+    @SuppressWarnings("try")
+    public static CompilerConfigurationFactory selectFactory(String name) {
+        CompilerConfigurationFactory factory = null;
+        try (InitTimer t = timer("CompilerConfigurationFactory.selectFactory")) {
+            String value = name == null ? Options.CompilerConfiguration.getValue() : name;
+            if ("help".equals(value)) {
+                System.out.println("The available Graal compiler configurations are:");
+                for (CompilerConfigurationFactory candidate : getAllCandidates()) {
+                    System.out.println("    " + candidate.name);
+                }
+                System.exit(0);
+            } else if (value != null) {
+                for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) {
+                    if (candidate.name.equals(value)) {
+                        factory = candidate;
+                        break;
+                    }
+                }
+                if (factory == null) {
+                    throw new GraalError("Graal compiler configuration '%s' not found. Available configurations are: %s", value,
+                                    getAllCandidates().stream().map(c -> c.name).collect(Collectors.joining(", ")));
+                }
+            } else {
+                List<CompilerConfigurationFactory> candidates = getAllCandidates();
+                if (candidates.isEmpty()) {
+                    throw new GraalError("No %s providers found", CompilerConfigurationFactory.class.getName());
+                }
+                factory = candidates.get(0);
+            }
+        }
+        return factory;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java
new file mode 100644
index 0000000..9b8b62b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+
+/**
+ * Used to access native configuration details for static compilation support.
+ */
+public class CompilerRuntimeHotSpotVMConfig extends HotSpotVMConfigAccess {
+
+    public CompilerRuntimeHotSpotVMConfig(HotSpotVMConfigStore store) {
+        super(store);
+    }
+
+    public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol");
+    public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol");
+    public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters");
+    public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol");
+    public final long invocationEvent = getAddress("CompilerRuntime::invocation_event");
+    public final long backedgeEvent = getAddress("CompilerRuntime::backedge_event");
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompressEncoding.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompressEncoding.java
new file mode 100644
index 0000000..9a0a8d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompressEncoding.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+/**
+ * A compact representation of the different encoding strategies for Objects and metadata.
+ */
+public class CompressEncoding {
+    public final long base;
+    public final int shift;
+    public final int alignment;
+
+    CompressEncoding(long base, int shift, int alignment) {
+        this.base = base;
+        this.shift = shift;
+        this.alignment = alignment;
+    }
+
+    public int compress(long ptr) {
+        if (ptr == 0L) {
+            return 0;
+        } else {
+            return (int) ((ptr - base) >>> shift);
+        }
+    }
+
+    public long uncompress(int ptr) {
+        if (ptr == 0) {
+            return 0L;
+        } else {
+            return ((ptr & 0xFFFFFFFFL) << shift) + base;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "base: " + base + " shift: " + shift + " alignment: " + alignment;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + alignment;
+        result = prime * result + (int) (base ^ (base >>> 32));
+        result = prime * result + shift;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof CompressEncoding) {
+            CompressEncoding other = (CompressEncoding) obj;
+            return alignment == other.alignment && base == other.base && shift == other.shift;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java
new file mode 100644
index 0000000..2dec945
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.core.phases.CoreCompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+@ServiceProvider(CompilerConfigurationFactory.class)
+public class CoreCompilerConfigurationFactory extends CompilerConfigurationFactory {
+
+    public static final String NAME = "core";
+
+    public static final int AUTO_SELECTION_PRIORITY = 2;
+
+    public CoreCompilerConfigurationFactory() {
+        super(NAME, AUTO_SELECTION_PRIORITY);
+    }
+
+    @Override
+    public CompilerConfiguration createCompilerConfiguration() {
+        return new CoreCompilerConfiguration();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java
new file mode 100644
index 0000000..c9e4c08
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.core.phases.EconomyCompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+@ServiceProvider(CompilerConfigurationFactory.class)
+public class EconomyCompilerConfigurationFactory extends CompilerConfigurationFactory {
+
+    public static final String NAME = "economy";
+
+    public static final int AUTO_SELECTION_PRIORITY = 1;
+
+    public EconomyCompilerConfigurationFactory() {
+        super(NAME, AUTO_SELECTION_PRIORITY);
+    }
+
+    @Override
+    public CompilerConfiguration createCompilerConfiguration() {
+        return new EconomyCompilerConfiguration();
+    }
+
+    @Override
+    public BackendMap createBackendMap() {
+        // the economy configuration only differs in the frontend, it reuses the "core" backend
+        return new DefaultBackendMap(CoreCompilerConfigurationFactory.NAME);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/FingerprintUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/FingerprintUtil.java
new file mode 100644
index 0000000..f035e01
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/FingerprintUtil.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot;
+
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+
+/**
+ * Reflective wrapper around the fingerprint generation functionality in JDK9.
+ */
+public class FingerprintUtil {
+    private static Method getFingerprint;
+    static {
+        try {
+            getFingerprint = HotSpotResolvedObjectType.class.getMethod("getFingerprint");
+        } catch (Exception e) {
+        }
+    }
+
+    public static long getFingerprint(HotSpotResolvedObjectType type) {
+        if (getFingerprint != null) {
+            try {
+                return ((Long) getFingerprint.invoke(type)).longValue();
+            } catch (Exception e) {
+            }
+        }
+        return 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
new file mode 100644
index 0000000..e7ce8f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+
+/**
+ * Used to access native configuration details.
+ */
+public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
+
+    /**
+     * Sentinel value to use for an {@linkplain InjectedParameter injected}
+     * {@link GraalHotSpotVMConfig} parameter to a {@linkplain Fold foldable} method.
+     */
+    public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null;
+
+    private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+    public final String osName = getHostOSName();
+    public final String osArch = getHostArchitectureName();
+    public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
+    public final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux");
+
+    GraalHotSpotVMConfig(HotSpotVMConfigStore store) {
+        super(store);
+
+        oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment());
+        klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment);
+
+        assert check();
+    }
+
+    /**
+     * Gets the value of a static C++ field under two possible names. {@code name} is the preferred
+     * name and will be checked first.
+     *
+     * @param name fully qualified name of the field
+     * @param alternateName fully qualified alternate name of the field
+     * @param type the boxed type to which the constant value will be converted
+     * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"})
+     * @return the value of the requested field
+     * @throws JVMCIError if the field is not static or not present
+     */
+    public <T> T getFieldValueWithAlternate(String name, String alternateName, Class<T> type, String cppType) {
+        try {
+            return getFieldValue(name, type, cppType);
+        } catch (JVMCIError e) {
+            try {
+                return getFieldValue(alternateName, type, cppType);
+            } catch (JVMCIError e2) {
+                throw new JVMCIError("expected VM field not found: " + name + " or " + alternateName);
+            }
+        }
+    }
+
+    private final CompressEncoding oopEncoding;
+    private final CompressEncoding klassEncoding;
+
+    public CompressEncoding getOopEncoding() {
+        return oopEncoding;
+    }
+
+    public CompressEncoding getKlassEncoding() {
+        return klassEncoding;
+    }
+
+    /**
+     * Gets the host operating system name.
+     */
+    private static String getHostOSName() {
+        String osName = System.getProperty("os.name");
+        switch (osName) {
+            case "Linux":
+                osName = "linux";
+                break;
+            case "SunOS":
+                osName = "solaris";
+                break;
+            case "Mac OS X":
+                osName = "bsd";
+                break;
+            default:
+                // Of course Windows is different...
+                if (osName.startsWith("Windows")) {
+                    osName = "windows";
+                } else {
+                    throw new JVMCIError("Unexpected OS name: " + osName);
+                }
+        }
+        return osName;
+    }
+
+    private static String getHostArchitectureName() {
+        String arch = System.getProperty("os.arch");
+        switch (arch) {
+            case "x86_64":
+                arch = "amd64";
+                break;
+            case "sparcv9":
+                arch = "sparc";
+                break;
+        }
+        return arch;
+    }
+
+    private final Integer intRequiredOnAMD64 = osArch.equals("amd64") ? null : 0;
+    private final Integer intNotPresentInJDK8 = isJDK8 ? 0 : null;
+    private final Long longNotPresentInJDK8 = isJDK8 ? 0L : null;
+
+    public final boolean cAssertions = getConstant("ASSERT", Boolean.class);
+
+    public final int codeEntryAlignment = getFlag("CodeEntryAlignment", Integer.class);
+    public final boolean enableContended = getFlag("EnableContended", Boolean.class);
+    public final boolean restrictContended = getFlag("RestrictContended", Boolean.class);
+    public final int contendedPaddingWidth = getFlag("ContendedPaddingWidth", Integer.class);
+    public final int fieldsAllocationStyle = getFlag("FieldsAllocationStyle", Integer.class);
+    public final boolean compactFields = getFlag("CompactFields", Boolean.class);
+    public final boolean verifyOops = getFlag("VerifyOops", Boolean.class);
+    public final boolean ciTime = getFlag("CITime", Boolean.class);
+    public final boolean ciTimeEach = getFlag("CITimeEach", Boolean.class);
+    public final int compileTheWorldStartAt = getFlag("CompileTheWorldStartAt", Integer.class, 1);
+    public final int compileTheWorldStopAt = getFlag("CompileTheWorldStopAt", Integer.class, Integer.MAX_VALUE);
+    public final boolean dontCompileHugeMethods = getFlag("DontCompileHugeMethods", Boolean.class);
+    public final int hugeMethodLimit = getFlag("HugeMethodLimit", Integer.class);
+    public final boolean printInlining = getFlag("PrintInlining", Boolean.class);
+    public final boolean inline = getFlag("Inline", Boolean.class);
+    public final boolean useFastLocking = getFlag("JVMCIUseFastLocking", Boolean.class);
+    public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class);
+    public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class);
+    public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class);
+
+    public final boolean useTLAB = getFlag("UseTLAB", Boolean.class);
+    public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class);
+    public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class);
+    public final boolean useAESIntrinsics = getFlag("UseAESIntrinsics", Boolean.class);
+    public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class);
+
+    private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class);
+    private final boolean useSHA1Intrinsics = getFlag("UseSHA1Intrinsics", Boolean.class);
+    private final boolean useSHA256Intrinsics = getFlag("UseSHA256Intrinsics", Boolean.class);
+    private final boolean useSHA512Intrinsics = getFlag("UseSHA512Intrinsics", Boolean.class);
+    private final boolean useMontgomeryMultiplyIntrinsic = getFlag("UseMontgomeryMultiplyIntrinsic", Boolean.class, false);
+    private final boolean useMontgomerySquareIntrinsic = getFlag("UseMontgomerySquareIntrinsic", Boolean.class, false);
+    private final boolean useMulAddIntrinsic = getFlag("UseMulAddIntrinsic", Boolean.class, false);
+    private final boolean useSquareToLenIntrinsic = getFlag("UseSquareToLenIntrinsic", Boolean.class, false);
+
+    /*
+     * These are methods because in some JDKs the flags are visible but the stubs themselves haven't
+     * been exported so we have to check both if the flag is on and if we have the stub.
+     */
+    public boolean useMultiplyToLenIntrinsic() {
+        return useMultiplyToLenIntrinsic && multiplyToLen != 0;
+    }
+
+    public boolean useSHA1Intrinsics() {
+        return useSHA1Intrinsics && sha1ImplCompress != 0;
+    }
+
+    public boolean useSHA256Intrinsics() {
+        return useSHA256Intrinsics && sha256ImplCompress != 0;
+    }
+
+    public boolean useSHA512Intrinsics() {
+        return useSHA512Intrinsics && sha512ImplCompress != 0;
+    }
+
+    public boolean useMontgomeryMultiplyIntrinsic() {
+        return useMontgomeryMultiplyIntrinsic && montgomeryMultiply != 0;
+    }
+
+    public boolean useMontgomerySquareIntrinsic() {
+        return useMontgomerySquareIntrinsic && montgomerySquare != 0;
+    }
+
+    public boolean useMulAddIntrinsic() {
+        return useMulAddIntrinsic && mulAdd != 0;
+    }
+
+    public boolean useSquareToLenIntrinsic() {
+        return useSquareToLenIntrinsic && squareToLen != 0;
+    }
+
+    public final boolean useG1GC = getFlag("UseG1GC", Boolean.class);
+    public final boolean useCMSGC = getFlag("UseConcMarkSweepGC", Boolean.class);
+
+    public final int allocatePrefetchStyle = getFlag("AllocatePrefetchStyle", Integer.class);
+    public final int allocatePrefetchInstr = getFlag("AllocatePrefetchInstr", Integer.class);
+    public final int allocatePrefetchLines = getFlag("AllocatePrefetchLines", Integer.class);
+    public final int allocateInstancePrefetchLines = getFlag("AllocateInstancePrefetchLines", Integer.class);
+    public final int allocatePrefetchStepSize = getFlag("AllocatePrefetchStepSize", Integer.class);
+    public final int allocatePrefetchDistance = getFlag("AllocatePrefetchDistance", Integer.class);
+
+    private final long universeCollectedHeap = getFieldValue("CompilerToVM::Data::Universe_collectedHeap", Long.class, "CollectedHeap*");
+    private final int collectedHeapTotalCollectionsOffset = getFieldOffset("CollectedHeap::_total_collections", Integer.class, "unsigned int");
+
+    public long gcTotalCollectionsAddress() {
+        return universeCollectedHeap + collectedHeapTotalCollectionsOffset;
+    }
+
+    public final boolean useDeferredInitBarriers = getFlag("ReduceInitialCardMarks", Boolean.class);
+
+    // Compressed Oops related values.
+    public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class);
+    public final boolean useCompressedClassPointers = getFlag("UseCompressedClassPointers", Boolean.class);
+
+    public final long narrowOopBase = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_base", Long.class, "address");
+    public final int narrowOopShift = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_shift", Integer.class, "int");
+    public final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class);
+
+    public final int minObjAlignment() {
+        return objectAlignment / heapWordSize;
+    }
+
+    public final int logMinObjAlignment() {
+        return (int) (Math.log(objectAlignment) / Math.log(2));
+    }
+
+    public final int narrowKlassSize = getTypeSize("narrowKlass");
+    public final long narrowKlassBase = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_base", Long.class, "address");
+    public final int narrowKlassShift = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_shift", Integer.class, "int");
+    public final int logKlassAlignment = getConstant("LogKlassAlignmentInBytes", Integer.class);
+
+    public final int stackShadowPages = getFlag("StackShadowPages", Integer.class);
+    public final int stackReservedPages = getFlag("StackReservedPages", Integer.class, 0);
+    public final boolean useStackBanging = getFlag("UseStackBanging", Boolean.class);
+    public final int stackBias = getConstant("STACK_BIAS", Integer.class);
+    public final int vmPageSize = getFieldValue("CompilerToVM::Data::vm_page_size", Integer.class, "int");
+
+    public final int markOffset = getFieldOffset("oopDesc::_mark", Integer.class, "markOop");
+    public final int hubOffset = getFieldOffset("oopDesc::_metadata._klass", Integer.class, "Klass*");
+
+    public final int prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, "markOop");
+    public final int subklassOffset = getFieldOffset("Klass::_subklass", Integer.class, "Klass*");
+    public final int nextSiblingOffset = getFieldOffset("Klass::_next_sibling", Integer.class, "Klass*");
+    public final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint");
+    public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*");
+    public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array<Klass*>*");
+
+    public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop");
+
+    public final int klassSuperKlassOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*");
+    public final int klassModifierFlagsOffset = getFieldOffset("Klass::_modifier_flags", Integer.class, "jint");
+    public final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags");
+    public final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint");
+
+    public final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class);
+    public final int layoutHelperLog2ElementSizeShift = getConstant("Klass::_lh_log2_element_size_shift", Integer.class);
+    public final int layoutHelperLog2ElementSizeMask = getConstant("Klass::_lh_log2_element_size_mask", Integer.class);
+    public final int layoutHelperElementTypeShift = getConstant("Klass::_lh_element_type_shift", Integer.class);
+    public final int layoutHelperElementTypeMask = getConstant("Klass::_lh_element_type_mask", Integer.class);
+    public final int layoutHelperHeaderSizeShift = getConstant("Klass::_lh_header_size_shift", Integer.class);
+    public final int layoutHelperHeaderSizeMask = getConstant("Klass::_lh_header_size_mask", Integer.class);
+    public final int layoutHelperArrayTagShift = getConstant("Klass::_lh_array_tag_shift", Integer.class);
+    public final int layoutHelperArrayTagTypeValue = getConstant("Klass::_lh_array_tag_type_value", Integer.class);
+    public final int layoutHelperArrayTagObjectValue = getConstant("Klass::_lh_array_tag_obj_value", Integer.class);
+
+    /**
+     * This filters out the bit that differentiates a type array from an object array.
+     */
+    public int layoutHelperElementTypePrimitiveInPlace() {
+        return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift;
+    }
+
+    public final int vtableEntrySize = getTypeSize("vtableEntry");
+    public final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*");
+
+    public final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1");
+    public final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*");
+    public final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array<u2>*");
+    public final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int");
+    public final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int");
+
+    public final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class);
+    public final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class);
+
+    public final int arrayOopDescSize = getTypeSize("arrayOopDesc");
+
+    /**
+     * The offset of the array length word in an array object's header.
+     *
+     * See {@code arrayOopDesc::length_offset_in_bytes()}.
+     */
+    public final int arrayOopDescLengthOffset() {
+        return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize;
+    }
+
+    public final int arrayU1LengthOffset = getFieldOffset("Array<int>::_length", Integer.class, "int");
+    public final int arrayU1DataOffset = getFieldOffset("Array<u1>::_data", Integer.class);
+    public final int arrayU2DataOffset = getFieldOffset("Array<u2>::_data", Integer.class);
+    public final int metaspaceArrayLengthOffset = getFieldOffset("Array<Klass*>::_length", Integer.class, "int");
+    public final int metaspaceArrayBaseOffset = getFieldOffset("Array<Klass*>::_data[0]", Integer.class, "Klass*");
+
+    public final int arrayClassElementOffset = getFieldOffset("ObjArrayKlass::_element_klass", Integer.class, "Klass*");
+
+    public final int fieldInfoAccessFlagsOffset = getConstant("FieldInfo::access_flags_offset", Integer.class);
+    public final int fieldInfoNameIndexOffset = getConstant("FieldInfo::name_index_offset", Integer.class);
+    public final int fieldInfoSignatureIndexOffset = getConstant("FieldInfo::signature_index_offset", Integer.class);
+    public final int fieldInfoInitvalIndexOffset = getConstant("FieldInfo::initval_index_offset", Integer.class);
+    public final int fieldInfoLowPackedOffset = getConstant("FieldInfo::low_packed_offset", Integer.class);
+    public final int fieldInfoHighPackedOffset = getConstant("FieldInfo::high_packed_offset", Integer.class);
+    public final int fieldInfoFieldSlots = getConstant("FieldInfo::field_slots", Integer.class);
+
+    public final int fieldInfoTagSize = getConstant("FIELDINFO_TAG_SIZE", Integer.class);
+
+    public final int jvmAccMonitorMatch = getConstant("JVM_ACC_MONITOR_MATCH", Integer.class);
+    public final int jvmAccHasMonitorBytecodes = getConstant("JVM_ACC_HAS_MONITOR_BYTECODES", Integer.class);
+    public final int jvmAccHasFinalizer = getConstant("JVM_ACC_HAS_FINALIZER", Integer.class);
+    public final int jvmAccFieldInternal = getConstant("JVM_ACC_FIELD_INTERNAL", Integer.class);
+    public final int jvmAccFieldStable = getConstant("JVM_ACC_FIELD_STABLE", Integer.class);
+    public final int jvmAccFieldHasGenericSignature = getConstant("JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE", Integer.class);
+    public final int jvmAccWrittenFlags = getConstant("JVM_ACC_WRITTEN_FLAGS", Integer.class);
+    public final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class);
+
+    public final int threadTlabOffset = getFieldOffset("Thread::_tlab", Integer.class, "ThreadLocalAllocBuffer");
+    public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor");
+    public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop");
+    public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*");
+    public final int javaThreadDirtyCardQueueOffset = getFieldOffset("JavaThread::_dirty_card_queue", Integer.class, "DirtyCardQueue");
+    public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int");
+    public final int javaThreadSatbMarkQueueOffset = getFieldOffset("JavaThread::_satb_mark_queue", Integer.class);
+    public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop");
+    public final int jvmciCountersThreadOffset = getFieldOffset("JavaThread::_jvmci_counters", Integer.class, "jlong*");
+    public final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address", intNotPresentInJDK8);
+
+    /**
+     * An invalid value for {@link #rtldDefault}.
+     */
+    public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE;
+
+    /**
+     * Address of the library lookup routine. The C signature of this routine is:
+     *
+     * <pre>
+     *     void* (const char *filename, char *ebuf, int ebuflen)
+     * </pre>
+     */
+    public final long dllLoad = getAddress("os::dll_load");
+
+    /**
+     * Address of the library lookup routine. The C signature of this routine is:
+     *
+     * <pre>
+     *     void* (void* handle, const char* name)
+     * </pre>
+     */
+    public final long dllLookup = getAddress("os::dll_lookup");
+
+    /**
+     * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will
+     * return the first occurrence of the desired symbol using the default library search order. If
+     * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on
+     * the current platform.
+     */
+    public final long rtldDefault = getAddress("RTLD_DEFAULT", osName.equals("bsd") || osName.equals("linux") ? null : INVALID_RTLD_DEFAULT_HANDLE);
+
+    /**
+     * This field is used to pass exception objects into and out of the runtime system during
+     * exception handling for compiled code.
+     */
+    public final int threadExceptionOopOffset = getFieldOffset("JavaThread::_exception_oop", Integer.class, "oop");
+    public final int threadExceptionPcOffset = getFieldOffset("JavaThread::_exception_pc", Integer.class, "address");
+    public final int pendingExceptionOffset = getFieldOffset("ThreadShadow::_pending_exception", Integer.class, "oop");
+
+    public final int pendingDeoptimizationOffset = getFieldOffset("JavaThread::_pending_deoptimization", Integer.class, "int");
+    public final int pendingFailedSpeculationOffset = getFieldOffset("JavaThread::_pending_failed_speculation", Integer.class, "oop");
+    public final int pendingTransferToInterpreterOffset = getFieldOffset("JavaThread::_pending_transfer_to_interpreter", Integer.class, "bool");
+
+    private final int javaFrameAnchorLastJavaSpOffset = getFieldOffset("JavaFrameAnchor::_last_Java_sp", Integer.class, "intptr_t*");
+    private final int javaFrameAnchorLastJavaPcOffset = getFieldOffset("JavaFrameAnchor::_last_Java_pc", Integer.class, "address");
+
+    public int threadLastJavaSpOffset() {
+        return javaThreadAnchorOffset + javaFrameAnchorLastJavaSpOffset;
+    }
+
+    public int threadLastJavaPcOffset() {
+        return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset;
+    }
+
+    public int threadLastJavaFpOffset() {
+        assert osArch.equals("aarch64") || osArch.equals("amd64");
+        return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_last_Java_fp", Integer.class, "intptr_t*");
+    }
+
+    public int threadJavaFrameAnchorFlagsOffset() {
+        assert osArch.equals("sparc");
+        return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_flags", Integer.class, "int");
+    }
+
+    public final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, intRequiredOnAMD64);
+    public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, intRequiredOnAMD64);
+    public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, intRequiredOnAMD64);
+
+    private final int dirtyCardQueueBufferOffset = isJDK8 ? getFieldOffset("PtrQueue::_buf", Integer.class, "void**") : getConstant("dirtyCardQueueBufferOffset", Integer.class);
+    private final int dirtyCardQueueIndexOffset = isJDK8 ? getFieldOffset("PtrQueue::_index", Integer.class, "size_t") : getConstant("dirtyCardQueueIndexOffset", Integer.class);
+
+    private final int satbMarkQueueBufferOffset = getConstant("satbMarkQueueBufferOffset", Integer.class, intNotPresentInJDK8);
+    private final int satbMarkQueueIndexOffset = getConstant("satbMarkQueueIndexOffset", Integer.class, intNotPresentInJDK8);
+    private final int satbMarkQueueActiveOffset = isJDK8 ? getFieldOffset("PtrQueue::_active", Integer.class, "bool") : getConstant("satbMarkQueueActiveOffset", Integer.class, intNotPresentInJDK8);
+
+    public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint");
+
+    public final long markOopDescHashShift = getConstant("markOopDesc::hash_shift", Long.class);
+
+    public final int biasedLockMaskInPlace = getConstant("markOopDesc::biased_lock_mask_in_place", Integer.class);
+    public final int ageMaskInPlace = getConstant("markOopDesc::age_mask_in_place", Integer.class);
+    public final int epochMaskInPlace = getConstant("markOopDesc::epoch_mask_in_place", Integer.class);
+    public final long markOopDescHashMask = getConstant("markOopDesc::hash_mask", Long.class);
+    public final long markOopDescHashMaskInPlace = getConstant("markOopDesc::hash_mask_in_place", Long.class);
+
+    public final int unlockedMask = getConstant("markOopDesc::unlocked_value", Integer.class);
+    public final int biasedLockPattern = getConstant("markOopDesc::biased_lock_pattern", Integer.class);
+
+    public final int markWordNoHashInPlace = getConstant("markOopDesc::no_hash_in_place", Integer.class);
+    public final int markWordNoLockInPlace = getConstant("markOopDesc::no_lock_in_place", Integer.class);
+
+    /**
+     * See {@code markOopDesc::prototype()}.
+     */
+    public long arrayPrototypeMarkWord() {
+        return markWordNoHashInPlace | markWordNoLockInPlace;
+    }
+
+    /**
+     * See {@code markOopDesc::copy_set_hash()}.
+     */
+    public long tlabIntArrayMarkWord() {
+        long tmp = arrayPrototypeMarkWord() & (~markOopDescHashMaskInPlace);
+        tmp |= ((0x2 & markOopDescHashMask) << markOopDescHashShift);
+        return tmp;
+    }
+
+    /**
+     * Mark word right shift to get identity hash code.
+     */
+    public final int identityHashCodeShift = getConstant("markOopDesc::hash_shift", Integer.class);
+
+    /**
+     * Identity hash code value when uninitialized.
+     */
+    public final int uninitializedIdentityHashCodeValue = getConstant("markOopDesc::no_hash", Integer.class);
+
+    public final int methodAccessFlagsOffset = getFieldOffset("Method::_access_flags", Integer.class, "AccessFlags");
+    public final int methodConstMethodOffset = getFieldOffset("Method::_constMethod", Integer.class, "ConstMethod*");
+    public final int methodIntrinsicIdOffset = getFieldOffset("Method::_intrinsic_id", Integer.class, isJDK8 ? "u1" : "u2");
+    public final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, isJDK8 ? "u1" : "u2");
+    public final int methodVtableIndexOffset = getFieldOffset("Method::_vtable_index", Integer.class, "int");
+
+    public final int methodCountersOffset = getFieldOffset("Method::_method_counters", Integer.class, "MethodCounters*");
+    public final int methodDataOffset = getFieldOffset("Method::_method_data", Integer.class, "MethodData*");
+    public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address");
+    public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*");
+
+    public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class);
+    public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class);
+    public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class);
+    public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class);
+    public final int methodFlagsHidden = getConstant("Method::_hidden", Integer.class);
+    public final int nonvirtualVtableIndex = getConstant("Method::nonvirtual_vtable_index", Integer.class);
+    public final int invalidVtableIndex = getConstant("Method::invalid_vtable_index", Integer.class);
+
+    public final int invocationCounterOffset = getFieldOffset("MethodCounters::_invocation_counter", Integer.class, "InvocationCounter");
+    public final int backedgeCounterOffset = getFieldOffset("MethodCounters::_backedge_counter", Integer.class, "InvocationCounter");
+    public final int invocationCounterIncrement = getConstant("InvocationCounter::count_increment", Integer.class, intNotPresentInJDK8);
+    public final int invocationCounterShift = getConstant("InvocationCounter::count_shift", Integer.class, intNotPresentInJDK8);
+
+    public final int nmethodEntryOffset = getFieldOffset("nmethod::_verified_entry_point",
+                    Integer.class, "address");
+    public final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization",
+                    Integer.class);
+
+    public final int constantPoolSize = getTypeSize("ConstantPool");
+    public final int constantPoolLengthOffset = getFieldOffset("ConstantPool::_length",
+                    Integer.class, "int");
+
+    public final int heapWordSize = getConstant("HeapWordSize", Integer.class);
+
+    /**
+     * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value
+     * are allowed to look like (respectively) the high or low bits of a real oop.
+     */
+    public final long nonOopBits = getFieldValue("CompilerToVM::Data::Universe_non_oop_bits", Long.class, "void*");
+
+    public final long verifyOopCounterAddress = getFieldAddress("StubRoutines::_verify_oop_count", "jint");
+    public final long verifyOopMask = getFieldValue("CompilerToVM::Data::Universe_verify_oop_mask", Long.class, "uintptr_t");
+    public final long verifyOopBits = getFieldValue("CompilerToVM::Data::Universe_verify_oop_bits", Long.class, "uintptr_t");
+
+    public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int");
+
+    public final byte dirtyCardValue = isJDK8 ? getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int") : getConstant("CardTableModRefBS::dirty_card", Byte.class);
+    public final byte g1YoungCardValue = isJDK8 ? getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int") : getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class);
+
+    public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*");
+    public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int");
+
+    /**
+     * This is the largest stack offset encodeable in an OopMapValue. Offsets larger than this will
+     * throw an exception during code installation.
+     */
+    public final int maxOopMapStackOffset = getFieldValueWithAlternate("CompilerToVM::Data::_max_oop_map_stack_offset", "JVMCIRuntime::max_oop_map_stack_offset", Integer.class, "int");
+
+    public final long safepointPollingAddress = getFieldValue("os::_polling_page", Long.class, "address");
+
+    // G1 Collector Related Values.
+
+    public int g1CardQueueIndexOffset() {
+        return javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset;
+    }
+
+    public int g1CardQueueBufferOffset() {
+        return javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset;
+    }
+
+    public int g1SATBQueueMarkingOffset() {
+        return javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset;
+    }
+
+    public int g1SATBQueueIndexOffset() {
+        return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueIndexOffset : satbMarkQueueIndexOffset);
+    }
+
+    public int g1SATBQueueBufferOffset() {
+        return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueBufferOffset : satbMarkQueueBufferOffset);
+    }
+
+    public final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int");
+    public final int arrayKlassOffset = getFieldValue("java_lang_Class::_array_klass_offset", Integer.class, "int");
+
+    public final int basicLockSize = getTypeSize("BasicLock");
+    public final int basicLockDisplacedHeaderOffset = getFieldOffset("BasicLock::_displaced_header", Integer.class, "markOop");
+
+    public final int threadAllocatedBytesOffset = getFieldOffset("Thread::_allocated_bytes", Integer.class, "jlong");
+
+    public final int tlabRefillWasteIncrement = getFlag("TLABWasteIncrement", Integer.class);
+
+    private final int threadLocalAllocBufferStartOffset = getFieldOffset("ThreadLocalAllocBuffer::_start", Integer.class, "HeapWord*");
+    private final int threadLocalAllocBufferEndOffset = getFieldOffset("ThreadLocalAllocBuffer::_end", Integer.class, "HeapWord*");
+    private final int threadLocalAllocBufferTopOffset = getFieldOffset("ThreadLocalAllocBuffer::_top", Integer.class, "HeapWord*");
+    private final int threadLocalAllocBufferPfTopOffset = getFieldOffset("ThreadLocalAllocBuffer::_pf_top", Integer.class, "HeapWord*");
+    private final int threadLocalAllocBufferSlowAllocationsOffset = getFieldOffset("ThreadLocalAllocBuffer::_slow_allocations", Integer.class, "unsigned");
+    private final int threadLocalAllocBufferFastRefillWasteOffset = getFieldOffset("ThreadLocalAllocBuffer::_fast_refill_waste", Integer.class, "unsigned");
+    private final int threadLocalAllocBufferNumberOfRefillsOffset = getFieldOffset("ThreadLocalAllocBuffer::_number_of_refills", Integer.class, "unsigned");
+    private final int threadLocalAllocBufferRefillWasteLimitOffset = getFieldOffset("ThreadLocalAllocBuffer::_refill_waste_limit", Integer.class, "size_t");
+    private final int threadLocalAllocBufferDesiredSizeOffset = getFieldOffset("ThreadLocalAllocBuffer::_desired_size", Integer.class, "size_t");
+
+    public int tlabSlowAllocationsOffset() {
+        return threadTlabOffset + threadLocalAllocBufferSlowAllocationsOffset;
+    }
+
+    public int tlabFastRefillWasteOffset() {
+        return threadTlabOffset + threadLocalAllocBufferFastRefillWasteOffset;
+    }
+
+    public int tlabNumberOfRefillsOffset() {
+        return threadTlabOffset + threadLocalAllocBufferNumberOfRefillsOffset;
+    }
+
+    public int tlabRefillWasteLimitOffset() {
+        return threadTlabOffset + threadLocalAllocBufferRefillWasteLimitOffset;
+    }
+
+    public int threadTlabSizeOffset() {
+        return threadTlabOffset + threadLocalAllocBufferDesiredSizeOffset;
+    }
+
+    public int threadTlabStartOffset() {
+        return threadTlabOffset + threadLocalAllocBufferStartOffset;
+    }
+
+    public int threadTlabEndOffset() {
+        return threadTlabOffset + threadLocalAllocBufferEndOffset;
+    }
+
+    public int threadTlabTopOffset() {
+        return threadTlabOffset + threadLocalAllocBufferTopOffset;
+    }
+
+    public int threadTlabPfTopOffset() {
+        return threadTlabOffset + threadLocalAllocBufferPfTopOffset;
+    }
+
+    public final int tlabAlignmentReserve = getFieldValue("CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve", Integer.class, "size_t");
+
+    public final boolean tlabStats = getFlag("TLABStats", Boolean.class);
+
+    // FIXME This is only temporary until the GC code is changed.
+    public final boolean inlineContiguousAllocationSupported = getFieldValue("CompilerToVM::Data::_supports_inline_contig_alloc", Boolean.class);
+    public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**");
+    public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, isJDK8 ? "HeapWord**" : "HeapWord* volatile*");
+
+    public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address");
+    public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address");
+
+    public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address");
+    public final long uncommonTrapStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", Long.class, "address");
+
+    public final long codeCacheLowBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_low_bound" : "CodeCache::_low_bound", Long.class, "address");
+    public final long codeCacheHighBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_high_bound" : "CodeCache::_high_bound", Long.class, "address");
+
+    public final long aescryptEncryptBlockStub = getFieldValue("StubRoutines::_aescrypt_encryptBlock", Long.class, "address");
+    public final long aescryptDecryptBlockStub = getFieldValue("StubRoutines::_aescrypt_decryptBlock", Long.class, "address");
+    public final long cipherBlockChainingEncryptAESCryptStub = getFieldValue("StubRoutines::_cipherBlockChaining_encryptAESCrypt", Long.class, "address");
+    public final long cipherBlockChainingDecryptAESCryptStub = getFieldValue("StubRoutines::_cipherBlockChaining_decryptAESCrypt", Long.class, "address");
+    public final long updateBytesCRC32Stub = getFieldValue("StubRoutines::_updateBytesCRC32", Long.class, "address");
+    public final long crcTableAddress = getFieldValue("StubRoutines::_crc_table_adr", Long.class, "address");
+
+    public final long sha1ImplCompress = getFieldValue("StubRoutines::_sha1_implCompress", Long.class, "address", 0L);
+    public final long sha1ImplCompressMB = getFieldValue("StubRoutines::_sha1_implCompressMB", Long.class, "address", 0L);
+    public final long sha256ImplCompress = getFieldValue("StubRoutines::_sha256_implCompress", Long.class, "address", 0L);
+    public final long sha256ImplCompressMB = getFieldValue("StubRoutines::_sha256_implCompressMB", Long.class, "address", 0L);
+    public final long sha512ImplCompress = getFieldValue("StubRoutines::_sha512_implCompress", Long.class, "address", 0L);
+    public final long sha512ImplCompressMB = getFieldValue("StubRoutines::_sha512_implCompressMB", Long.class, "address", 0L);
+    public final long multiplyToLen = getFieldValue("StubRoutines::_multiplyToLen", Long.class, "address", 0L);
+
+    public final long counterModeAESCrypt = getFieldValue("StubRoutines::_counterMode_AESCrypt", Long.class, "address", 0L);
+    public final long ghashProcessBlocks = getFieldValue("StubRoutines::_ghash_processBlocks", Long.class, "address", 0L);
+    public final long crc32cTableTddr = getFieldValue("StubRoutines::_crc32c_table_addr", Long.class, "address", 0L);
+    public final long updateBytesCRC32C = getFieldValue("StubRoutines::_updateBytesCRC32C", Long.class, "address", 0L);
+    public final long updateBytesAdler32 = getFieldValue("StubRoutines::_updateBytesAdler32", Long.class, "address", 0L);
+    public final long squareToLen = getFieldValue("StubRoutines::_squareToLen", Long.class, "address", 0L);
+    public final long mulAdd = getFieldValue("StubRoutines::_mulAdd", Long.class, "address", 0L);
+    public final long montgomeryMultiply = getFieldValue("StubRoutines::_montgomeryMultiply", Long.class, "address", 0L);
+    public final long montgomerySquare = getFieldValue("StubRoutines::_montgomerySquare", Long.class, "address", 0L);
+    public final long vectorizedMismatch = getFieldValue("StubRoutines::_vectorizedMismatch", Long.class, "address", 0L);
+
+    public final long throwDelayedStackOverflowErrorEntry = getFieldValue("StubRoutines::_throw_delayed_StackOverflowError_entry", Long.class, "address", longNotPresentInJDK8);
+
+    public final long jbyteArraycopy = getFieldValue("StubRoutines::_jbyte_arraycopy", Long.class, "address");
+    public final long jshortArraycopy = getFieldValue("StubRoutines::_jshort_arraycopy", Long.class, "address");
+    public final long jintArraycopy = getFieldValue("StubRoutines::_jint_arraycopy", Long.class, "address");
+    public final long jlongArraycopy = getFieldValue("StubRoutines::_jlong_arraycopy", Long.class, "address");
+    public final long oopArraycopy = getFieldValue("StubRoutines::_oop_arraycopy", Long.class, "address");
+    public final long oopArraycopyUninit = getFieldValue("StubRoutines::_oop_arraycopy_uninit", Long.class, "address");
+    public final long jbyteDisjointArraycopy = getFieldValue("StubRoutines::_jbyte_disjoint_arraycopy", Long.class, "address");
+    public final long jshortDisjointArraycopy = getFieldValue("StubRoutines::_jshort_disjoint_arraycopy", Long.class, "address");
+    public final long jintDisjointArraycopy = getFieldValue("StubRoutines::_jint_disjoint_arraycopy", Long.class, "address");
+    public final long jlongDisjointArraycopy = getFieldValue("StubRoutines::_jlong_disjoint_arraycopy", Long.class, "address");
+    public final long oopDisjointArraycopy = getFieldValue("StubRoutines::_oop_disjoint_arraycopy", Long.class, "address");
+    public final long oopDisjointArraycopyUninit = getFieldValue("StubRoutines::_oop_disjoint_arraycopy_uninit", Long.class, "address");
+    public final long jbyteAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jbyte_arraycopy", Long.class, "address");
+    public final long jshortAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jshort_arraycopy", Long.class, "address");
+    public final long jintAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jint_arraycopy", Long.class, "address");
+    public final long jlongAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_jlong_arraycopy", Long.class, "address");
+    public final long oopAlignedArraycopy = getFieldValue("StubRoutines::_arrayof_oop_arraycopy", Long.class, "address");
+    public final long oopAlignedArraycopyUninit = getFieldValue("StubRoutines::_arrayof_oop_arraycopy_uninit", Long.class, "address");
+    public final long jbyteAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jbyte_disjoint_arraycopy", Long.class, "address");
+    public final long jshortAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jshort_disjoint_arraycopy", Long.class, "address");
+    public final long jintAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jint_disjoint_arraycopy", Long.class, "address");
+    public final long jlongAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_jlong_disjoint_arraycopy", Long.class, "address");
+    public final long oopAlignedDisjointArraycopy = getFieldValue("StubRoutines::_arrayof_oop_disjoint_arraycopy", Long.class, "address");
+    public final long oopAlignedDisjointArraycopyUninit = getFieldValue("StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", Long.class, "address");
+    public final long checkcastArraycopy = getFieldValue("StubRoutines::_checkcast_arraycopy", Long.class, "address");
+    public final long checkcastArraycopyUninit = getFieldValue("StubRoutines::_checkcast_arraycopy_uninit", Long.class, "address");
+    public final long unsafeArraycopy = getFieldValue("StubRoutines::_unsafe_arraycopy", Long.class, "address");
+    public final long genericArraycopy = getFieldValue("StubRoutines::_generic_arraycopy", Long.class, "address");
+
+    public final long newInstanceAddress = getAddress("JVMCIRuntime::new_instance");
+    public final long newArrayAddress = getAddress("JVMCIRuntime::new_array");
+    public final long newMultiArrayAddress = getAddress("JVMCIRuntime::new_multi_array");
+    public final long dynamicNewArrayAddress = getAddress("JVMCIRuntime::dynamic_new_array");
+    public final long dynamicNewInstanceAddress = getAddress("JVMCIRuntime::dynamic_new_instance");
+
+    public final long threadIsInterruptedAddress = getAddress("JVMCIRuntime::thread_is_interrupted");
+    public final long vmMessageAddress = getAddress("JVMCIRuntime::vm_message");
+    public final long identityHashCodeAddress = getAddress("JVMCIRuntime::identity_hash_code");
+    public final long exceptionHandlerForPcAddress = getAddress("JVMCIRuntime::exception_handler_for_pc");
+    public final long monitorenterAddress = getAddress("JVMCIRuntime::monitorenter");
+    public final long monitorexitAddress = getAddress("JVMCIRuntime::monitorexit");
+    public final long throwAndPostJvmtiExceptionAddress = getAddress("JVMCIRuntime::throw_and_post_jvmti_exception");
+    public final long throwKlassExternalNameExceptionAddress = getAddress("JVMCIRuntime::throw_klass_external_name_exception");
+    public final long throwClassCastExceptionAddress = getAddress("JVMCIRuntime::throw_class_cast_exception");
+    public final long logPrimitiveAddress = getAddress("JVMCIRuntime::log_primitive");
+    public final long logObjectAddress = getAddress("JVMCIRuntime::log_object");
+    public final long logPrintfAddress = getAddress("JVMCIRuntime::log_printf");
+    public final long vmErrorAddress = getAddress("JVMCIRuntime::vm_error");
+    public final long loadAndClearExceptionAddress = getAddress("JVMCIRuntime::load_and_clear_exception");
+    public final long writeBarrierPreAddress = getAddress("JVMCIRuntime::write_barrier_pre");
+    public final long writeBarrierPostAddress = getAddress("JVMCIRuntime::write_barrier_post");
+    public final long validateObject = getAddress("JVMCIRuntime::validate_object");
+
+    public final long testDeoptimizeCallInt = getAddress("JVMCIRuntime::test_deoptimize_call_int");
+
+    public final long registerFinalizerAddress = getAddress("SharedRuntime::register_finalizer");
+    public final long exceptionHandlerForReturnAddressAddress = getAddress("SharedRuntime::exception_handler_for_return_address");
+    public final long osrMigrationEndAddress = getAddress("SharedRuntime::OSR_migration_end");
+    public final long enableStackReservedZoneAddress = getAddress("SharedRuntime::enable_stack_reserved_zone", longNotPresentInJDK8);
+
+    public final long javaTimeMillisAddress = getAddress("os::javaTimeMillis");
+    public final long javaTimeNanosAddress = getAddress("os::javaTimeNanos");
+    public final long arithmeticSinAddress = getFieldValue("CompilerToVM::Data::dsin", Long.class, "address");
+    public final long arithmeticCosAddress = getFieldValue("CompilerToVM::Data::dcos", Long.class, "address");
+    public final long arithmeticTanAddress = getFieldValue("CompilerToVM::Data::dtan", Long.class, "address");
+    public final long arithmeticExpAddress = getFieldValue("CompilerToVM::Data::dexp", Long.class, "address");
+    public final long arithmeticLogAddress = getFieldValue("CompilerToVM::Data::dlog", Long.class, "address");
+    public final long arithmeticLog10Address = getFieldValue("CompilerToVM::Data::dlog10", Long.class, "address");
+    public final long arithmeticPowAddress = getFieldValue("CompilerToVM::Data::dpow", Long.class, "address");
+
+    public final long fremAddress = getAddress("SharedRuntime::frem");
+    public final long dremAddress = getAddress("SharedRuntime::drem");
+
+    public final int jvmciCountersSize = getFlag("JVMCICounterSize", Integer.class);
+
+    public final long deoptimizationFetchUnrollInfo = getAddress("Deoptimization::fetch_unroll_info");
+    public final long deoptimizationUncommonTrap = getAddress("Deoptimization::uncommon_trap");
+    public final long deoptimizationUnpackFrames = getAddress("Deoptimization::unpack_frames");
+
+    public final int deoptimizationUnpackDeopt = getConstant("Deoptimization::Unpack_deopt", Integer.class);
+    public final int deoptimizationUnpackException = getConstant("Deoptimization::Unpack_exception", Integer.class);
+    public final int deoptimizationUnpackUncommonTrap = getConstant("Deoptimization::Unpack_uncommon_trap", Integer.class);
+    public final int deoptimizationUnpackReexecute = getConstant("Deoptimization::Unpack_reexecute", Integer.class);
+
+    public final int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset = getFieldOffset("Deoptimization::UnrollBlock::_size_of_deoptimized_frame", Integer.class, "int");
+    public final int deoptimizationUnrollBlockCallerAdjustmentOffset = getFieldOffset("Deoptimization::UnrollBlock::_caller_adjustment", Integer.class, "int");
+    public final int deoptimizationUnrollBlockNumberOfFramesOffset = getFieldOffset("Deoptimization::UnrollBlock::_number_of_frames", Integer.class, "int");
+    public final int deoptimizationUnrollBlockTotalFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_total_frame_sizes", Integer.class, "int");
+    public final int deoptimizationUnrollBlockUnpackKindOffset = getFieldOffset("Deoptimization::UnrollBlock::_unpack_kind", Integer.class, "int");
+    public final int deoptimizationUnrollBlockFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_sizes", Integer.class, "intptr_t*");
+    public final int deoptimizationUnrollBlockFramePcsOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_pcs", Integer.class, "address*");
+    public final int deoptimizationUnrollBlockInitialInfoOffset = getFieldOffset("Deoptimization::UnrollBlock::_initial_info", Integer.class, "intptr_t");
+
+    // Checkstyle: stop
+    public final int MARKID_VERIFIED_ENTRY = getConstant("CodeInstaller::VERIFIED_ENTRY", Integer.class);
+    public final int MARKID_UNVERIFIED_ENTRY = getConstant("CodeInstaller::UNVERIFIED_ENTRY", Integer.class);
+    public final int MARKID_OSR_ENTRY = getConstant("CodeInstaller::OSR_ENTRY", Integer.class);
+    public final int MARKID_EXCEPTION_HANDLER_ENTRY = getConstant("CodeInstaller::EXCEPTION_HANDLER_ENTRY", Integer.class);
+    public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class);
+    public final int MARKID_INVOKEINTERFACE = getConstant("CodeInstaller::INVOKEINTERFACE", Integer.class);
+    public final int MARKID_INVOKEVIRTUAL = getConstant("CodeInstaller::INVOKEVIRTUAL", Integer.class);
+    public final int MARKID_INVOKESTATIC = getConstant("CodeInstaller::INVOKESTATIC", Integer.class);
+    public final int MARKID_INVOKESPECIAL = getConstant("CodeInstaller::INVOKESPECIAL", Integer.class);
+    public final int MARKID_INLINE_INVOKE = getConstant("CodeInstaller::INLINE_INVOKE", Integer.class);
+    public final int MARKID_POLL_NEAR = getConstant("CodeInstaller::POLL_NEAR", Integer.class);
+    public final int MARKID_POLL_RETURN_NEAR = getConstant("CodeInstaller::POLL_RETURN_NEAR", Integer.class);
+    public final int MARKID_POLL_FAR = getConstant("CodeInstaller::POLL_FAR", Integer.class);
+    public final int MARKID_POLL_RETURN_FAR = getConstant("CodeInstaller::POLL_RETURN_FAR", Integer.class);
+    public final int MARKID_CARD_TABLE_SHIFT = getConstant("CodeInstaller::CARD_TABLE_SHIFT", Integer.class);
+    public final int MARKID_CARD_TABLE_ADDRESS = getConstant("CodeInstaller::CARD_TABLE_ADDRESS", Integer.class);
+    public final int MARKID_INVOKE_INVALID = getConstant("CodeInstaller::INVOKE_INVALID", Integer.class);
+
+    /**
+     * The following constants are given default values here since they are missing in the native
+     * JVMCI-8 code but are still required for {@link GraalHotSpotVMConfigNode#canonical} to work in
+     * a JDK8 environment.
+     */
+    public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17);
+    public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18);
+    public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19);
+    public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20);
+    public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21);
+    public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22);
+
+    // Checkstyle: resume
+
+    private boolean check() {
+        for (Field f : getClass().getDeclaredFields()) {
+            int modifiers = f.getModifiers();
+            if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
+                assert Modifier.isFinal(modifiers) : "field should be final: " + f;
+            }
+        }
+
+        assert codeEntryAlignment > 0 : codeEntryAlignment;
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java
new file mode 100644
index 0000000..cd21784
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode;
+import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode;
+import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
+import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
+import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub;
+import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.tiers.SuitesProvider;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.CompilationRequest;
+import jdk.vm.ci.code.CompiledCode;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * HotSpot specific backend.
+ */
+public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use Graal stubs instead of HotSpot stubs where possible")
+        public static final OptionValue<Boolean> PreferGraalStubs = new OptionValue<>(false);
+        @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible")
+        public static final OptionValue<Boolean> GraalArithmeticStubs = new OptionValue<>(true);
+        @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
+                        " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
+        public static final OptionValue<String> ASMInstructionProfiling = new OptionValue<>(null);
+        // @formatter:on
+    }
+
+    /**
+     * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
+     * {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a
+     * compiled method.
+     */
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
+
+    /**
+     * Descriptor for SharedRuntime::get_ic_miss_stub().
+     */
+    public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class);
+
+    /**
+     * Descriptor for SharedRuntime::get_handle_wrong_method_stub().
+     */
+    public static final ForeignCallDescriptor WRONG_METHOD_HANDLER = new ForeignCallDescriptor("wrongMethodHandler", void.class);
+
+    /**
+     * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated
+     * from {@link UnwindNode}.
+     */
+    public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class);
+
+    /**
+     * Descriptor for the arguments when unwinding to an exception handler in a caller.
+     */
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class);
+
+    private final HotSpotGraalRuntimeProvider runtime;
+
+    /**
+     * @see DeoptimizationFetchUnrollInfoCallNode
+     */
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, long.class, int.class);
+
+    /**
+     * @see DeoptimizationStub#unpackFrames(ForeignCallDescriptor, Word, int)
+     */
+    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(DeoptimizationStub.class, "unpackFrames", int.class, Word.class, int.class);
+
+    /**
+     * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer)
+     */
+    public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Pointer.class);
+
+    /**
+     * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer)
+     */
+    public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class);
+
+    /**
+     * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer)
+     */
+    public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class,
+                    Pointer.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class,
+                    int.class, Pointer.class);
+
+    /**
+     * @see BigIntegerSubstitutions#multiplyToLen
+     */
+    public static final ForeignCallDescriptor MULTIPLY_TO_LEN = new ForeignCallDescriptor("multiplyToLen", void.class, Word.class, int.class, Word.class, int.class, Word.class, int.class);
+
+    public static void multiplyToLenStub(Word xAddr, int xlen, Word yAddr, int ylen, Word zAddr, int zLen) {
+        multiplyToLenStub(HotSpotBackend.MULTIPLY_TO_LEN, xAddr, xlen, yAddr, ylen, zAddr, zLen);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void multiplyToLenStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xIn, int xLen, Word yIn, int yLen, Word zIn, int zLen);
+
+    /**
+     * @see BigIntegerSubstitutions#mulAdd
+     */
+    public static final ForeignCallDescriptor MUL_ADD = new ForeignCallDescriptor("mulAdd", int.class, Word.class, Word.class, int.class, int.class, int.class);
+
+    public static int mulAddStub(Word inAddr, Word outAddr, int newOffset, int len, int k) {
+        return mulAddStub(HotSpotBackend.MUL_ADD, inAddr, outAddr, newOffset, len, k);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native int mulAddStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word inAddr, Word outAddr, int newOffset, int len, int k);
+
+    /**
+     * @see BigIntegerSubstitutions#implMontgomeryMultiply
+     */
+    public static final ForeignCallDescriptor MONTGOMERY_MULTIPLY = new ForeignCallDescriptor("implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class,
+                    Word.class);
+
+    public static void implMontgomeryMultiply(Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr) {
+        implMontgomeryMultiply(HotSpotBackend.MONTGOMERY_MULTIPLY, aAddr, bAddr, nAddr, len, inv, productAddr);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void implMontgomeryMultiply(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr);
+
+    /**
+     * @see BigIntegerSubstitutions#implMontgomerySquare
+     */
+    public static final ForeignCallDescriptor MONTGOMERY_SQUARE = new ForeignCallDescriptor("implMontgomerySquare", void.class, Word.class, Word.class, int.class, long.class, Word.class);
+
+    public static void implMontgomerySquare(Word aAddr, Word nAddr, int len, long inv, Word productAddr) {
+        implMontgomerySquare(HotSpotBackend.MONTGOMERY_SQUARE, aAddr, nAddr, len, inv, productAddr);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void implMontgomerySquare(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word nAddr, int len, long inv, Word productAddr);
+
+    /**
+     * @see BigIntegerSubstitutions#implSquareToLen
+     */
+    public static final ForeignCallDescriptor SQUARE_TO_LEN = new ForeignCallDescriptor("implSquareToLen", void.class, Word.class, int.class, Word.class, int.class);
+
+    public static void implSquareToLen(Word xAddr, int len, Word zAddr, int zLen) {
+        implSquareToLen(SQUARE_TO_LEN, xAddr, len, zAddr, zLen);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void implSquareToLen(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xAddr, int len, Word zAddr, int zLen);
+
+    /**
+     * @see SHASubstitutions#implCompress0
+     */
+    public static final ForeignCallDescriptor SHA_IMPL_COMPRESS = new ForeignCallDescriptor("shaImplCompress", void.class, Word.class, Object.class);
+
+    public static void shaImplCompressStub(Word bufAddr, Object state) {
+        shaImplCompressStub(HotSpotBackend.SHA_IMPL_COMPRESS, bufAddr, state);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void shaImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
+
+    /**
+     * @see SHA2Substitutions#implCompress0
+     */
+    public static final ForeignCallDescriptor SHA2_IMPL_COMPRESS = new ForeignCallDescriptor("sha2ImplCompress", void.class, Word.class, Object.class);
+
+    public static void sha2ImplCompressStub(Word bufAddr, Object state) {
+        sha2ImplCompressStub(HotSpotBackend.SHA2_IMPL_COMPRESS, bufAddr, state);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void sha2ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
+
+    /**
+     * @see SHA5Substitutions#implCompress0
+     */
+    public static final ForeignCallDescriptor SHA5_IMPL_COMPRESS = new ForeignCallDescriptor("sha5ImplCompress", void.class, Word.class, Object.class);
+
+    public static void sha5ImplCompressStub(Word bufAddr, Object state) {
+        sha5ImplCompressStub(HotSpotBackend.SHA5_IMPL_COMPRESS, bufAddr, state);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
+
+    /**
+     * @see VMErrorNode
+     */
+    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
+
+    /**
+     * New multi array stub call.
+     */
+    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, KlassPointer.class, int.class, Word.class);
+
+    /**
+     * New array stub.
+     */
+    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, KlassPointer.class, int.class, boolean.class);
+
+    /**
+     * New instance stub.
+     */
+    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, KlassPointer.class);
+
+    /**
+     * @see ResolveConstantStubCall
+     */
+    public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class);
+
+    /**
+     * @see ResolveConstantStubCall
+     */
+    public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class);
+
+    /**
+     * @see ResolveConstantStubCall
+     */
+    public static final ForeignCallDescriptor INITIALIZE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("initialize_klass_by_symbol", Word.class, Word.class, Word.class);
+
+    /**
+     * @see ResolveConstantStubCall
+     */
+    public static final ForeignCallDescriptor RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS = new ForeignCallDescriptor("resolve_method_by_symbol_and_load_counters", Word.class, Word.class, Word.class,
+                    Word.class);
+
+    /**
+     * Tiered support.
+     */
+    public static final ForeignCallDescriptor INVOCATION_EVENT = new ForeignCallDescriptor("invocation_event", void.class, Word.class);
+    public static final ForeignCallDescriptor BACKEDGE_EVENT = new ForeignCallDescriptor("backedge_event", void.class, Word.class, int.class, int.class);
+
+    /**
+     * @see UncommonTrapCallNode
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class, int.class);
+
+    public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(providers);
+        this.runtime = runtime;
+    }
+
+    public HotSpotGraalRuntimeProvider getRuntime() {
+        return runtime;
+    }
+
+    /**
+     * Performs any remaining initialization that was deferred until the {@linkplain #getRuntime()
+     * runtime} object was initialized and this backend was registered with it.
+     *
+     * @param jvmciRuntime
+     */
+    public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime) {
+    }
+
+    /**
+     * Finds all the registers that are defined by some given LIR.
+     *
+     * @param lir the LIR to examine
+     * @return the registers that are defined by or used as temps for any instruction in {@code lir}
+     */
+    protected final Set<Register> gatherDestroyedCallerRegisters(LIR lir) {
+        final Set<Register> destroyedRegisters = new HashSet<>();
+        ValueConsumer defConsumer = new ValueConsumer() {
+
+            @Override
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (ValueUtil.isRegister(value)) {
+                    final Register reg = ValueUtil.asRegister(value);
+                    destroyedRegisters.add(reg);
+                }
+            }
+        };
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            for (LIRInstruction op : lir.getLIRforBlock(block)) {
+                if (op instanceof LabelOp) {
+                    // Don't consider this as a definition
+                } else {
+                    op.visitEachTemp(defConsumer);
+                    op.visitEachOutput(defConsumer);
+                }
+            }
+        }
+        return translateToCallerRegisters(destroyedRegisters);
+    }
+
+    /**
+     * Updates a given stub with respect to the registers it destroys.
+     * <p>
+     * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove()
+     * supports} pruning will have {@code destroyedRegisters}
+     * {@linkplain SaveRegistersOp#remove(Set) removed} as these registers are declared as
+     * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by
+     * the stub's caller).
+     *
+     * @param stub the stub to update
+     * @param destroyedRegisters the registers destroyed by the stub
+     * @param calleeSaveInfo a map from debug infos to the operations that provide their
+     *            {@linkplain RegisterSaveLayout callee-save information}
+     * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual
+     *            slot to a frame slot index
+     */
+    protected void updateStub(Stub stub, Set<Register> destroyedRegisters, Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo, FrameMap frameMap) {
+        stub.initDestroyedCallerRegisters(destroyedRegisters);
+
+        for (Map.Entry<LIRFrameState, SaveRegistersOp> e : calleeSaveInfo.entrySet()) {
+            SaveRegistersOp save = e.getValue();
+            if (save.supportsRemove()) {
+                save.remove(destroyedRegisters);
+            }
+            DebugInfo info = e.getKey() == null ? null : e.getKey().debugInfo();
+            if (info != null) {
+                info.setCalleeSaveInfo(save.getMap(frameMap));
+            }
+        }
+    }
+
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    @Override
+    public SuitesProvider getSuites() {
+        return getProviders().getSuites();
+    }
+
+    protected void profileInstructions(LIR lir, CompilationResultBuilder crb) {
+        if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) {
+            HotSpotInstructionProfiling.countInstructions(lir, crb.asm);
+        }
+    }
+
+    @Override
+    public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) {
+        HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null;
+        return HotSpotCompiledCodeBuilder.createCompiledCode(method, compRequest, compResult);
+    }
+
+    @Override
+    public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) {
+        if (resolvedJavaMethod instanceof HotSpotResolvedJavaMethod) {
+            HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) resolvedJavaMethod, JVMCICompiler.INVOCATION_ENTRY_BCI, 0L);
+            return new HotSpotCompilationIdentifier(request);
+        }
+        return super.getCompilationIdentifier(resolvedJavaMethod);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java
new file mode 100644
index 0000000..94effaf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+
+public interface HotSpotBackendFactory {
+
+    /**
+     * Gets the name of this backend factory. This should not include the {@link #getArchitecture()
+     * architecture}. The {@link CompilerConfigurationFactory} can select alternative backends based
+     * on this name.
+     */
+    String getName();
+
+    /**
+     * Gets the class describing the architecture the backend created by this factory is associated
+     * with.
+     */
+    Class<? extends Architecture> getArchitecture();
+
+    HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompilationIdentifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompilationIdentifier.java
new file mode 100644
index 0000000..d232580
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompilationIdentifier.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.CompilationRequestIdentifier;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * {@link CompilationIdentifier} for a {@linkplain HotSpotCompilationRequest hotspot compilation
+ * request}.
+ */
+public class HotSpotCompilationIdentifier implements CompilationRequestIdentifier {
+    private final HotSpotCompilationRequest request;
+
+    public HotSpotCompilationIdentifier(HotSpotCompilationRequest request) {
+        this.request = request;
+    }
+
+    public boolean isOsrCompilation() {
+        return request.getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI;
+    }
+
+    @Override
+    public final String toString() {
+        return toString(Verbosity.DETAILED);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        return buildString(new StringBuilder(), verbosity).toString();
+    }
+
+    protected StringBuilder buildString(StringBuilder sb, Verbosity verbosity) {
+        switch (verbosity) {
+            case ID:
+                buildID(sb);
+                break;
+            case NAME:
+                buildName(sb);
+                break;
+            case DETAILED:
+                buildID(sb);
+                sb.append('[');
+                buildName(sb);
+                if (isOsrCompilation()) {
+                    sb.append("@");
+                    sb.append(request.getEntryBCI());
+                }
+                sb.append(']');
+                break;
+            default:
+                throw new GraalError("unknown verbosity: " + verbosity);
+        }
+        return sb;
+    }
+
+    protected StringBuilder buildName(StringBuilder sb) {
+        return sb.append(request.getMethod().format("%H.%n(%p)"));
+    }
+
+    protected StringBuilder buildID(StringBuilder sb) {
+        if (isOsrCompilation()) {
+            sb.append("HotSpotOSRCompilation-");
+        } else {
+            sb.append("HotSpotCompilation-");
+        }
+        return sb.append(request.getId());
+    }
+
+    @Override
+    public HotSpotCompilationRequest getRequest() {
+        return request;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java
new file mode 100644
index 0000000..79c8379
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import java.util.stream.Stream.Builder;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
+import org.graalvm.compiler.code.CompilationResult.CodeComment;
+import org.graalvm.compiler.code.CompilationResult.JumpTable;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.code.DataSection;
+import org.graalvm.compiler.code.SourceMapping;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.code.site.Site;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
+import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class HotSpotCompiledCodeBuilder {
+
+    public static HotSpotCompiledCode createCompiledCode(ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) {
+        String name = compResult.getName();
+
+        byte[] targetCode = compResult.getTargetCode();
+        int targetCodeSize = compResult.getTargetCodeSize();
+
+        Site[] sites = getSortedSites(compResult);
+
+        Assumption[] assumptions = compResult.getAssumptions();
+
+        ResolvedJavaMethod[] methods = compResult.getMethods();
+
+        List<CodeAnnotation> annotations = compResult.getAnnotations();
+        Comment[] comments = new Comment[annotations.size()];
+        if (!annotations.isEmpty()) {
+            for (int i = 0; i < comments.length; i++) {
+                CodeAnnotation annotation = annotations.get(i);
+                String text;
+                if (annotation instanceof CodeComment) {
+                    CodeComment codeComment = (CodeComment) annotation;
+                    text = codeComment.value;
+                } else if (annotation instanceof JumpTable) {
+                    JumpTable jumpTable = (JumpTable) annotation;
+                    text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]";
+                } else {
+                    text = annotation.toString();
+                }
+                comments[i] = new Comment(annotation.position, text);
+            }
+        }
+
+        DataSection data = compResult.getDataSection();
+        byte[] dataSection = new byte[data.getSectionSize()];
+
+        ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder());
+        Builder<DataPatch> patchBuilder = Stream.builder();
+        data.buildDataSection(buffer, vmConstant -> {
+            patchBuilder.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
+        });
+
+        int dataSectionAlignment = data.getSectionAlignment();
+        DataPatch[] dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]);
+
+        int totalFrameSize = compResult.getTotalFrameSize();
+        StackSlot customStackArea = compResult.getCustomStackArea();
+        boolean isImmutablePIC = compResult.isImmutablePIC();
+
+        if (method instanceof HotSpotResolvedJavaMethod) {
+            HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+            int entryBCI = compResult.getEntryBCI();
+            boolean hasUnsafeAccess = compResult.hasUnsafeAccess();
+
+            int id;
+            long jvmciEnv;
+            if (compRequest != null) {
+                id = compRequest.getId();
+                jvmciEnv = compRequest.getJvmciEnv();
+            } else {
+                id = hsMethod.allocateCompileId(entryBCI);
+                jvmciEnv = 0L;
+            }
+            return new HotSpotCompiledNmethod(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC,
+                            totalFrameSize, customStackArea, hsMethod, entryBCI, id, jvmciEnv, hasUnsafeAccess);
+        } else {
+            return new HotSpotCompiledCode(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC,
+                            totalFrameSize, customStackArea);
+        }
+    }
+
+    static class SiteComparator implements Comparator<Site> {
+
+        /**
+         * Defines an order for sorting {@link Infopoint}s based on their
+         * {@linkplain Infopoint#reason reasons}. This is used to choose which infopoint to preserve
+         * when multiple infopoints collide on the same PC offset. A negative order value implies a
+         * non-optional infopoint (i.e., must be preserved).
+         */
+        static final Map<InfopointReason, Integer> HOTSPOT_INFOPOINT_SORT_ORDER = new EnumMap<>(InfopointReason.class);
+
+        static {
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.SAFEPOINT, -4);
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.CALL, -3);
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.IMPLICIT_EXCEPTION, -2);
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.METHOD_START, 2);
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.METHOD_END, 3);
+            HOTSPOT_INFOPOINT_SORT_ORDER.put(InfopointReason.BYTECODE_POSITION, 4);
+        }
+
+        static int ord(Infopoint info) {
+            return HOTSPOT_INFOPOINT_SORT_ORDER.get(info.reason);
+        }
+
+        static int checkCollision(Infopoint i1, Infopoint i2) {
+            int o1 = ord(i1);
+            int o2 = ord(i2);
+            if (o1 < 0 && o2 < 0) {
+                throw new GraalError("Non optional infopoints cannot collide: %s and %s", i1, i2);
+            }
+            return o1 - o2;
+        }
+
+        /**
+         * Records whether any two {@link Infopoint}s had the same {@link Infopoint#pcOffset}.
+         */
+        boolean sawCollidingInfopoints;
+
+        @Override
+        public int compare(Site s1, Site s2) {
+            if (s1.pcOffset == s2.pcOffset) {
+                // Marks must come first since patching a call site
+                // may need to know the mark denoting the call type
+                // (see uses of CodeInstaller::_next_call_type).
+                boolean s1IsMark = s1 instanceof Mark;
+                boolean s2IsMark = s2 instanceof Mark;
+                if (s1IsMark != s2IsMark) {
+                    return s1IsMark ? -1 : 1;
+                }
+
+                // Infopoints must group together so put them after
+                // other Site types.
+                boolean s1IsInfopoint = s1 instanceof Infopoint;
+                boolean s2IsInfopoint = s2 instanceof Infopoint;
+                if (s1IsInfopoint != s2IsInfopoint) {
+                    return s1IsInfopoint ? 1 : -1;
+                }
+
+                if (s1IsInfopoint) {
+                    sawCollidingInfopoints = true;
+                    return checkCollision((Infopoint) s1, (Infopoint) s2);
+                }
+            }
+            return s1.pcOffset - s2.pcOffset;
+        }
+    }
+
+    /**
+     * HotSpot expects sites to be presented in ascending order of PC (see
+     * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects
+     * {@link Infopoint} PCs to be unique.
+     */
+    private static Site[] getSortedSites(CompilationResult target) {
+        List<Site> sites = new ArrayList<>(
+                        target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size());
+        sites.addAll(target.getExceptionHandlers());
+        sites.addAll(target.getInfopoints());
+        sites.addAll(target.getDataPatches());
+        sites.addAll(target.getMarks());
+
+        /*
+         * Translate the source mapping into appropriate info points. In HotSpot only one position
+         * can really be represented and recording the end PC seems to give the best results and
+         * corresponds with what C1 and C2 do.
+         */
+        for (SourceMapping source : target.getSourceMappings()) {
+            sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION));
+            assert verifySourcePositionReceivers(source.getSourcePosition());
+        }
+
+        SiteComparator c = new SiteComparator();
+        Collections.sort(sites, c);
+        if (c.sawCollidingInfopoints) {
+            Infopoint lastInfopoint = null;
+            List<Site> copy = new ArrayList<>(sites.size());
+            for (Site site : sites) {
+                if (site instanceof Infopoint) {
+                    Infopoint info = (Infopoint) site;
+                    if (lastInfopoint == null || lastInfopoint.pcOffset != info.pcOffset) {
+                        lastInfopoint = info;
+                        copy.add(info);
+                    } else {
+                        // Omit this colliding infopoint
+                        assert lastInfopoint.reason.compareTo(info.reason) <= 0;
+                    }
+                } else {
+                    copy.add(site);
+                }
+            }
+            sites = copy;
+        }
+        return sites.toArray(new Site[sites.size()]);
+    }
+
+    /**
+     * Verifies that the captured receiver type agrees with the declared type of the method.
+     */
+    private static boolean verifySourcePositionReceivers(NodeSourcePosition start) {
+        NodeSourcePosition pos = start;
+        while (pos != null) {
+            if (pos.getReceiver() != null) {
+                assert ((HotSpotObjectConstant) pos.getReceiver()).asObject(pos.getMethod().getDeclaringClass()) != null;
+            }
+            pos = pos.getCaller();
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java
new file mode 100644
index 0000000..794f767
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+public abstract class HotSpotCounterOp extends LIRInstruction {
+    public static final LIRInstructionClass<HotSpotCounterOp> TYPE = LIRInstructionClass.create(HotSpotCounterOp.class);
+
+    private final String[] names;
+    private final String[] groups;
+    protected final Register thread;
+    protected final GraalHotSpotVMConfig config;
+    @Alive({OperandFlag.CONST, OperandFlag.REG}) protected Value[] increments;
+
+    public HotSpotCounterOp(LIRInstructionClass<? extends HotSpotCounterOp> c, String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) {
+        this(c, new String[]{name}, new String[]{group}, new Value[]{increment}, registers, config);
+    }
+
+    public HotSpotCounterOp(LIRInstructionClass<? extends HotSpotCounterOp> c, String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) {
+        super(c);
+
+        assert names.length == groups.length;
+        assert groups.length == increments.length;
+
+        this.names = names;
+        this.groups = groups;
+        this.increments = increments;
+        this.thread = registers.getThreadRegister();
+        this.config = config;
+    }
+
+    protected static int getDisplacementForLongIndex(TargetDescription target, long index) {
+        long finalDisp = index * target.arch.getPlatformKind(JavaKind.Long).getSizeInBytes();
+        if (!NumUtil.isInt(finalDisp)) {
+            throw GraalError.unimplemented("cannot deal with indices that big: " + index);
+        }
+        return (int) finalDisp;
+    }
+
+    protected interface CounterProcedure {
+        /**
+         * Lambda interface for iterating over counters declared in this op.
+         *
+         * @param counterIndex Index in this CounterOp object.
+         * @param increment Value for increment
+         * @param displacement Displacement in bytes in the counter array
+         */
+        void apply(int counterIndex, Value increment, int displacement);
+    }
+
+    /**
+     * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement
+     * in the counter array.
+     *
+     * @param proc The procedure to be called
+     * @param target Target architecture (used to calculate the array displacements)
+     */
+    protected void forEachCounter(CounterProcedure proc, TargetDescription target) {
+        if (names.length == 1) { // fast path
+            int arrayIndex = getIndex(names[0], groups[0], increments[0]);
+            int displacement = getDisplacementForLongIndex(target, arrayIndex);
+            proc.apply(0, increments[0], displacement);
+        } else { // Slow path with sort by displacements ascending
+            int[] displacements = new int[names.length];
+            HashMap<Integer, Integer> offsetMap = new HashMap<>(names.length);
+            for (int i = 0; i < names.length; i++) {
+                int arrayIndex = getIndex(names[i], groups[i], increments[i]);
+                displacements[i] = getDisplacementForLongIndex(target, arrayIndex);
+                offsetMap.put(displacements[i], i);
+            }
+            Arrays.sort(displacements);
+            // Now apply in order
+            for (int offset : displacements) {
+                int idx = offsetMap.get(offset);
+                proc.apply(idx, increments[idx], displacements[idx]);
+            }
+        }
+    }
+
+    protected int getIndex(String name, String group, Value increment) {
+        if (isJavaConstant(increment)) {
+            // get index for the counter
+            return BenchmarkCounters.getIndexConstantIncrement(name, group, config, asLong(asJavaConstant(increment)));
+        }
+        assert isRegister(increment) : "Unexpected Value: " + increment;
+        // get index for the counter
+        return BenchmarkCounters.getIndex(name, group, config);
+    }
+
+    /**
+     * Patches the increment value in the instruction emitted by this instruction. Use only, if
+     * patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        throw GraalError.unimplemented();
+    }
+
+    private static long asLong(JavaConstant value) {
+        JavaKind kind = value.getJavaKind();
+        switch (kind) {
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+                return value.asInt();
+            case Long:
+                return value.asLong();
+            default:
+                throw new IllegalArgumentException("not an integer kind: " + kind);
+        }
+    }
+
+    protected static int asInt(JavaConstant value) {
+        long l = asLong(value);
+        if (!NumUtil.isInt(l)) {
+            throw GraalError.shouldNotReachHere("value does not fit into int: " + l);
+        }
+        return (int) l;
+    }
+
+    public String[] getNames() {
+        return names;
+    }
+
+    public String[] getGroups() {
+        return groups;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java
new file mode 100644
index 0000000..78f0280
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL;
+
+import java.nio.ByteBuffer;
+
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.code.DataSection.Patches;
+import org.graalvm.compiler.code.DataSection.SerializableData;
+import org.graalvm.compiler.code.DataSection.ZeroData;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.asm.DataBuilder;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.SerializableConstant;
+import jdk.vm.ci.meta.VMConstant;
+
+public class HotSpotDataBuilder extends DataBuilder {
+
+    private final TargetDescription target;
+
+    public HotSpotDataBuilder(TargetDescription target) {
+        this.target = target;
+    }
+
+    @Override
+    public boolean needDetailedPatchingInformation() {
+        /* The HotSpot VM finds operands that need patching by decoding the instruction. */
+        return false;
+    }
+
+    @Override
+    public Data createDataItem(Constant constant) {
+        int size;
+        if (constant instanceof VMConstant) {
+            VMConstant vmConstant = (VMConstant) constant;
+            boolean compressed;
+            if (constant instanceof HotSpotConstant) {
+                HotSpotConstant c = (HotSpotConstant) vmConstant;
+                compressed = c.isCompressed();
+            } else {
+                throw new GraalError(String.valueOf(constant));
+            }
+
+            size = compressed ? 4 : target.wordSize;
+            if (size == 4) {
+                return new Data(size, size) {
+
+                    @Override
+                    protected void emit(ByteBuffer buffer, Patches patches) {
+                        patches.registerPatch(vmConstant);
+                        buffer.putInt(0xDEADDEAD);
+                    }
+                };
+            } else {
+                return new Data(size, size) {
+
+                    @Override
+                    protected void emit(ByteBuffer buffer, Patches patches) {
+                        patches.registerPatch(vmConstant);
+                        buffer.putLong(0xDEADDEADDEADDEADL);
+                    }
+                };
+            }
+        } else if (JavaConstant.isNull(constant)) {
+            boolean compressed = COMPRESSED_NULL.equals(constant);
+            size = compressed ? 4 : target.wordSize;
+            return ZeroData.create(size, size);
+        } else if (constant instanceof SerializableConstant) {
+            SerializableConstant s = (SerializableConstant) constant;
+            return new SerializableData(s);
+        } else {
+            throw new GraalError(String.valueOf(constant));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java
new file mode 100644
index 0000000..babe75e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
+
+import org.graalvm.compiler.core.gen.DebugInfoBuilder;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.StackLockValue;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.meta.JavaValue;
+
+/**
+ * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks.
+ */
+public class HotSpotDebugInfoBuilder extends DebugInfoBuilder {
+
+    private final HotSpotLockStack lockStack;
+
+    private int maxInterpreterFrameSize;
+
+    private HotSpotCodeCacheProvider codeCacheProvider;
+
+    public HotSpotDebugInfoBuilder(NodeValueMap nodeValueMap, HotSpotLockStack lockStack, HotSpotLIRGenerator gen) {
+        super(nodeValueMap);
+        this.lockStack = lockStack;
+        this.codeCacheProvider = gen.getProviders().getCodeCache();
+    }
+
+    public HotSpotLockStack lockStack() {
+        return lockStack;
+    }
+
+    public int maxInterpreterFrameSize() {
+        return maxInterpreterFrameSize;
+    }
+
+    @Override
+    protected JavaValue computeLockValue(FrameState state, int lockIndex) {
+        int lockDepth = lockIndex;
+        if (state.outerFrameState() != null) {
+            lockDepth += state.outerFrameState().nestedLockDepth();
+        }
+        VirtualStackSlot slot = lockStack.makeLockSlot(lockDepth);
+        ValueNode lock = state.lockAt(lockIndex);
+        JavaValue object = toJavaValue(lock);
+        boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex) == null;
+        assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth;
+        return new StackLockValue(object, slot, eliminated);
+    }
+
+    @Override
+    protected BytecodeFrame computeFrameForState(FrameState state) {
+        if (isPlaceholderBci(state.bci) && state.bci != BytecodeFrame.BEFORE_BCI) {
+            // This is really a hard error since an incorrect state could crash hotspot
+            throw GraalError.shouldNotReachHere("Invalid state " + BytecodeFrame.getPlaceholderBciName(state.bci) + " " + state);
+        }
+        BytecodeFrame result = super.computeFrameForState(state);
+        maxInterpreterFrameSize = Math.max(maxInterpreterFrameSize, codeCacheProvider.interpreterFrameSize(result));
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java
new file mode 100644
index 0000000..82d665b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import jdk.vm.ci.meta.InvokeTarget;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+
+/**
+ * The details required to link a HotSpot runtime or stub call.
+ */
+public interface HotSpotForeignCallLinkage extends ForeignCallLinkage, InvokeTarget {
+
+    /**
+     * Constants for specifying whether a foreign call destroys or preserves registers. A foreign
+     * call will always destroy {@link HotSpotForeignCallLinkage#getOutgoingCallingConvention() its}
+     * {@linkplain ForeignCallLinkage#getTemporaries() temporary} registers.
+     */
+    enum RegisterEffect {
+        DESTROYS_REGISTERS,
+        PRESERVES_REGISTERS
+    }
+
+    /**
+     * Constants for specifying whether a call is a leaf or not and whether a
+     * {@code JavaFrameAnchor} prologue and epilogue is required around the call. A leaf function
+     * does not lock, GC or throw exceptions.
+     */
+    enum Transition {
+        /**
+         * A call to a leaf function that is guaranteed to not use floating point registers and will
+         * never have its caller stack inspected by the VM. That is, {@code JavaFrameAnchor}
+         * management around the call can be omitted.
+         */
+        LEAF_NOFP,
+
+        /**
+         * A call to a leaf function that might use floating point registers but will never have its
+         * caller stack inspected. That is, {@code JavaFrameAnchor} management around the call can
+         * be omitted.
+         */
+        LEAF,
+
+        /**
+         * A call to a leaf function that might use floating point registers and may have its caller
+         * stack inspected. That is, {@code JavaFrameAnchor} management code around the call is
+         * required.
+         */
+        STACK_INSPECTABLE_LEAF,
+
+        /**
+         * A function that may lock, GC or raise an exception and thus requires debug info to be
+         * associated with a call site to the function. The execution stack may be inspected while
+         * in the called function. That is, {@code JavaFrameAnchor} management code around the call
+         * is required.
+         */
+        SAFEPOINT,
+    }
+
+    /**
+     * Sentinel marker for a computed jump address.
+     */
+    long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL;
+
+    boolean isReexecutable();
+
+    LocationIdentity[] getKilledLocations();
+
+    void setCompiledStub(Stub stub);
+
+    /**
+     * Determines if this is a call to a compiled {@linkplain Stub stub}.
+     */
+    boolean isCompiledStub();
+
+    void finalizeAddress(Backend backend);
+
+    long getAddress();
+
+    /**
+     * Determines if the runtime function or stub might use floating point registers. If the answer
+     * is no, then no FPU state management prologue or epilogue needs to be emitted around the call.
+     */
+    boolean mayContainFP();
+
+    /**
+     * Determines if a {@code JavaFrameAnchor} needs to be set up and torn down around this call.
+     */
+    boolean needsJavaFrameAnchor();
+
+    /**
+     * Gets the VM symbol associated with the target {@linkplain #getAddress() address} of the call.
+     */
+    String getSymbol();
+
+    /**
+     * Identifies foreign calls which are guaranteed to include a safepoint check.
+     */
+    boolean isGuaranteedSafepoint();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java
new file mode 100644
index 0000000..c4e0d8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
+
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CallingConvention.Type;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.ValueKindFactory;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * The details required to link a HotSpot runtime or stub call.
+ */
+public class HotSpotForeignCallLinkageImpl extends HotSpotForeignCallTarget implements HotSpotForeignCallLinkage {
+
+    /**
+     * The descriptor of the call.
+     */
+    protected final ForeignCallDescriptor descriptor;
+
+    /**
+     * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}.
+     */
+    private Stub stub;
+
+    /**
+     * The calling convention for this call.
+     */
+    private final CallingConvention outgoingCallingConvention;
+
+    /**
+     * The calling convention for incoming arguments to the stub, iff this call uses a compiled
+     * {@linkplain Stub stub}.
+     */
+    private final CallingConvention incomingCallingConvention;
+
+    private final RegisterEffect effect;
+
+    private final Transition transition;
+
+    /**
+     * The registers and stack slots defined/killed by the call.
+     */
+    private Value[] temporaries = AllocatableValue.NONE;
+
+    /**
+     * The memory locations killed by the call.
+     */
+    private final LocationIdentity[] killedLocations;
+
+    private final boolean reexecutable;
+
+    /**
+     * Creates a {@link HotSpotForeignCallLinkage}.
+     *
+     * @param descriptor the descriptor of the call
+     * @param address the address of the code to call
+     * @param effect specifies if the call destroys or preserves all registers (apart from
+     *            temporaries which are always destroyed)
+     * @param outgoingCcType outgoing (caller) calling convention type
+     * @param incomingCcType incoming (callee) calling convention type (can be null)
+     * @param transition specifies if this is a {@linkplain #needsDebugInfo() leaf} call
+     * @param reexecutable specifies if the call can be re-executed without (meaningful) side
+     *            effects. Deoptimization will not return to a point before a call that cannot be
+     *            re-executed.
+     * @param killedLocations the memory locations killed by the call
+     */
+    public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, HotSpotForeignCallsProvider foreignCalls,
+                    ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, boolean reexecutable,
+                    LocationIdentity... killedLocations) {
+        CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, outgoingCcType);
+        CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, incomingCcType);
+        HotSpotForeignCallLinkageImpl linkage = new HotSpotForeignCallLinkageImpl(descriptor, address, effect, transition, outgoingCc, incomingCc, reexecutable, killedLocations);
+        if (outgoingCcType == HotSpotCallingConventionType.NativeCall) {
+            linkage.temporaries = foreignCalls.getNativeABICallerSaveRegisters();
+        }
+        return linkage;
+    }
+
+    /**
+     * Gets a calling convention for a given descriptor and call type.
+     */
+    public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, ValueKindFactory<?> valueKindFactory,
+                    ForeignCallDescriptor descriptor, Type ccType) {
+        assert ccType != null;
+        Class<?>[] argumentTypes = descriptor.getArgumentTypes();
+        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
+        for (int i = 0; i < parameterTypes.length; ++i) {
+            parameterTypes[i] = asJavaType(argumentTypes[i], metaAccess, wordTypes);
+        }
+        JavaType returnType = asJavaType(descriptor.getResultType(), metaAccess, wordTypes);
+        RegisterConfig regConfig = codeCache.getRegisterConfig();
+        return regConfig.getCallingConvention(ccType, returnType, parameterTypes, valueKindFactory);
+    }
+
+    private static JavaType asJavaType(Class<?> type, MetaAccessProvider metaAccess, WordTypes wordTypes) {
+        ResolvedJavaType javaType = metaAccess.lookupJavaType(type);
+        if (wordTypes.isWord(javaType)) {
+            javaType = metaAccess.lookupJavaType(wordTypes.getWordKind().toJavaClass());
+        }
+        return javaType;
+    }
+
+    public HotSpotForeignCallLinkageImpl(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention outgoingCallingConvention,
+                    CallingConvention incomingCallingConvention, boolean reexecutable, LocationIdentity... killedLocations) {
+        super(address);
+        this.descriptor = descriptor;
+        this.address = address;
+        this.effect = effect;
+        this.transition = transition;
+        assert outgoingCallingConvention != null : "only incomingCallingConvention can be null";
+        this.outgoingCallingConvention = outgoingCallingConvention;
+        this.incomingCallingConvention = incomingCallingConvention != null ? incomingCallingConvention : outgoingCallingConvention;
+        this.reexecutable = reexecutable;
+        this.killedLocations = killedLocations;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString());
+        sb.append("@0x").append(Long.toHexString(address)).append(':').append(outgoingCallingConvention).append(":").append(incomingCallingConvention);
+        if (temporaries != null && temporaries.length != 0) {
+            sb.append("; temps=");
+            String sep = "";
+            for (Value op : temporaries) {
+                sb.append(sep).append(op);
+                sep = ",";
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public boolean isReexecutable() {
+        return reexecutable;
+    }
+
+    @Override
+    public boolean isGuaranteedSafepoint() {
+        return transition == Transition.SAFEPOINT;
+    }
+
+    @Override
+    public LocationIdentity[] getKilledLocations() {
+        return killedLocations;
+    }
+
+    @Override
+    public CallingConvention getOutgoingCallingConvention() {
+        return outgoingCallingConvention;
+    }
+
+    @Override
+    public CallingConvention getIncomingCallingConvention() {
+        return incomingCallingConvention;
+    }
+
+    @Override
+    public Value[] getTemporaries() {
+        if (temporaries.length == 0) {
+            return temporaries;
+        }
+        return temporaries.clone();
+    }
+
+    @Override
+    public long getMaxCallTargetOffset() {
+        return runtime().getHostJVMCIBackend().getCodeCache().getMaxCallTargetOffset(address);
+    }
+
+    @Override
+    public ForeignCallDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public void setCompiledStub(Stub stub) {
+        assert address == 0L : "cannot set stub for linkage that already has an address: " + this;
+        this.stub = stub;
+    }
+
+    /**
+     * Determines if this is a call to a compiled {@linkplain Stub stub}.
+     */
+    @Override
+    public boolean isCompiledStub() {
+        return address == 0L || stub != null;
+    }
+
+    @Override
+    public void finalizeAddress(Backend backend) {
+        if (address == 0) {
+            assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?";
+            InstalledCode code = stub.getCode(backend);
+
+            Set<Register> destroyedRegisters = stub.getDestroyedCallerRegisters();
+            if (!destroyedRegisters.isEmpty()) {
+                AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
+                int i = 0;
+                for (Register reg : destroyedRegisters) {
+                    temporaryLocations[i++] = reg.asValue();
+                }
+                temporaries = temporaryLocations;
+            }
+            address = code.getStart();
+        }
+    }
+
+    @Override
+    public long getAddress() {
+        assert address != 0L : "address not yet finalized: " + this;
+        return address;
+    }
+
+    @Override
+    public boolean destroysRegisters() {
+        return effect == DESTROYS_REGISTERS;
+    }
+
+    @Override
+    public boolean needsDebugInfo() {
+        return transition == Transition.SAFEPOINT;
+    }
+
+    @Override
+    public boolean mayContainFP() {
+        return transition != Transition.LEAF_NOFP;
+    }
+
+    @Override
+    public boolean needsJavaFrameAnchor() {
+        if (transition == Transition.SAFEPOINT || transition == Transition.STACK_INSPECTABLE_LEAF) {
+            if (stub != null) {
+                // The stub will do the JavaFrameAnchor management
+                // around the runtime call(s) it makes
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String getSymbol() {
+        return stub == null ? null : stub.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java
new file mode 100644
index 0000000..f495102
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions;
+import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Formattable;
+import java.util.Formatter;
+
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.util.CompilationAlarm;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.TopLevelDebugConfig;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo;
+import org.graalvm.compiler.hotspot.CompilationCounters.Options;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.code.CompilationRequest;
+import jdk.vm.ci.code.CompilationRequestResult;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.SpeculationLog;
+import jdk.vm.ci.meta.TriState;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+public class HotSpotGraalCompiler implements GraalJVMCICompiler {
+
+    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+    private final HotSpotGraalRuntimeProvider graalRuntime;
+    private final CompilationCounters compilationCounters;
+    private final BootstrapWatchDog bootstrapWatchDog;
+
+    HotSpotGraalCompiler(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime) {
+        this.jvmciRuntime = jvmciRuntime;
+        this.graalRuntime = graalRuntime;
+        // It is sufficient to have one compilation counter object per Graal compiler object.
+        this.compilationCounters = Options.CompilationCountLimit.getValue() > 0 ? new CompilationCounters() : null;
+        this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !GraalDebugConfig.Options.BootstrapInitializeOnly.getValue() ? BootstrapWatchDog.maybeCreate(graalRuntime) : null;
+    }
+
+    @Override
+    public HotSpotGraalRuntimeProvider getGraalRuntime() {
+        return graalRuntime;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public CompilationRequestResult compileMethod(CompilationRequest request) {
+        if (graalRuntime.isBootstrapping() && GraalDebugConfig.Options.BootstrapInitializeOnly.getValue()) {
+            return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", GraalDebugConfig.Options.BootstrapInitializeOnly.getName()), true);
+        }
+        if (bootstrapWatchDog != null && graalRuntime.isBootstrapping()) {
+            if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) {
+                // Drain the compilation queue to expedite completion of the bootstrap
+                return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true);
+            }
+        }
+        ResolvedJavaMethod method = request.getMethod();
+        HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request;
+        try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId());
+                        BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request);
+                        CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod();) {
+            if (compilationCounters != null) {
+                compilationCounters.countCompilation(method);
+            }
+            // Ensure a debug configuration for this thread is initialized
+            if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+                DebugEnvironment.initialize(TTY.out, graalRuntime.getHostProviders().getSnippetReflection());
+            }
+            CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, true);
+            CompilationRequestResult r = null;
+            try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig());
+                            Debug.Scope s = Debug.methodMetricsScope("HotSpotGraalCompiler", MethodMetricsRootScopeInfo.create(method), true, method)) {
+                r = task.runCompilation();
+            }
+            assert r != null;
+            return r;
+        }
+    }
+
+    public void compileTheWorld() throws Throwable {
+        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmciRuntime.getHostJVMCIBackend().getCodeCache();
+        int iterations = CompileTheWorldOptions.CompileTheWorldIterations.getValue();
+        for (int i = 0; i < iterations; i++) {
+            codeCache.resetCompilationStatistics();
+            TTY.println("CompileTheWorld : iteration " + i);
+            CompileTheWorld ctw = new CompileTheWorld(jvmciRuntime, this);
+            ctw.compile();
+        }
+        System.exit(0);
+    }
+
+    public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId) {
+        HotSpotBackend backend = graalRuntime.getHostBackend();
+        HotSpotProviders providers = backend.getProviders();
+        final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
+        StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers, compilationId);
+
+        if (graph == null) {
+            SpeculationLog speculationLog = method.getSpeculationLog();
+            if (speculationLog != null) {
+                speculationLog.collectFailedSpeculations();
+            }
+            graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()), speculationLog, useProfilingInfo, compilationId);
+        }
+
+        Suites suites = getSuites(providers);
+        LIRSuites lirSuites = getLIRSuites(providers);
+        ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE);
+        OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
+        if (isOSR) {
+            // In OSR compiles, we cannot rely on never executed code profiles, because
+            // all code after the OSR loop is never executed.
+            optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
+        }
+        CompilationResult result = new CompilationResult();
+        result.setEntryBCI(entryBCI);
+        boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
+        PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR);
+        GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, CompilationResultBuilderFactory.Default);
+
+        if (!isOSR && useProfilingInfo) {
+            ProfilingInfo profile = profilingInfo;
+            profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount());
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets a graph produced from the intrinsic for a given method that can be compiled and
+     * installed for the method.
+     *
+     * @param method
+     * @param compilationId
+     * @return an intrinsic graph that can be compiled and installed for {@code method} or null
+     */
+    @SuppressWarnings("try")
+    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId) {
+        Replacements replacements = providers.getReplacements();
+        ResolvedJavaMethod substMethod = replacements.getSubstitutionMethod(method);
+        if (substMethod != null) {
+            assert !substMethod.equals(method);
+            StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES, NO_PROFILING_INFO, compilationId);
+            try (Debug.Scope scope = Debug.scope("GetIntrinsicGraph", graph)) {
+                Plugins plugins = new Plugins(providers.getGraphBuilderPlugins());
+                GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+                IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, replacements.getReplacementBytecodeProvider(), ROOT_COMPILATION);
+                new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
+                                OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
+                assert !graph.isFrozen();
+                return graph;
+            } catch (Throwable e) {
+                Debug.handle(e);
+            }
+        }
+        return null;
+    }
+
+    protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo) {
+        return new OptimisticOptimizations(profilingInfo);
+    }
+
+    protected Suites getSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultSuites();
+    }
+
+    protected LIRSuites getLIRSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultLIRSuites();
+    }
+
+    /**
+     * Reconfigures a given graph builder suite (GBS) if one of the given GBS parameter values is
+     * not the default.
+     *
+     * @param suite the graph builder suite
+     * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is
+     *            false)
+     * @param isOSR specifies if extra OSR-specific post-processing is required (default is false)
+     * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a
+     *         default value otherwise {@code suite}
+     */
+    protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR) {
+        if (shouldDebugNonSafepoints || isOSR) {
+            PhaseSuite<HighTierContext> newGbs = suite.copy();
+
+            if (shouldDebugNonSafepoints) {
+                GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
+                GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
+                graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true);
+                GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
+                newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
+            }
+            if (isOSR) {
+                newGbs.appendPhase(new OnStackReplacementPhase());
+            }
+            return newGbs;
+        }
+        return suite;
+    }
+
+    /**
+     * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format
+     * string {@code "%H.%n(%p)"}.
+     */
+    static String str(JavaMethod method) {
+        return method.format("%H.%n(%p)");
+    }
+
+    /**
+     * Wraps {@code obj} in a {@link Formatter} that standardizes formatting for certain objects.
+     */
+    static Formattable fmt(Object obj) {
+        return new Formattable() {
+            @Override
+            public void formatTo(Formatter buf, int flags, int width, int precision) {
+                if (obj instanceof Throwable) {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    ((Throwable) obj).printStackTrace(new PrintStream(baos));
+                    buf.format("%s", baos.toString());
+                } else if (obj instanceof StackTraceElement[]) {
+                    for (StackTraceElement e : (StackTraceElement[]) obj) {
+                        buf.format("\t%s%n", e);
+                    }
+                } else if (obj instanceof JavaMethod) {
+                    buf.format("%s", str((JavaMethod) obj));
+                } else {
+                    buf.format("%s", obj);
+                }
+            }
+        };
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java
new file mode 100644
index 0000000..e7ca226
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.options.OptionValue.PROFILE_OPTIONVALUE_PROPERTY_NAME;
+import static jdk.vm.ci.common.InitTimer.timer;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.MethodFilter;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionsParser;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+
+import jdk.vm.ci.common.InitTimer;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotSignature;
+import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
+import jdk.vm.ci.runtime.JVMCIRuntime;
+
+public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
+
+    /**
+     * The name of the system property specifying a file containing extra Graal option settings.
+     */
+    private static final String GRAAL_OPTIONS_FILE_PROPERTY_NAME = "graal.options.file";
+
+    /**
+     * The name of the system property specifying the Graal version.
+     */
+    private static final String GRAAL_VERSION_PROPERTY_NAME = "graal.version";
+
+    /**
+     * The prefix for system properties that correspond to {@link Option} annotated fields. A field
+     * named {@code MyOption} will have its value set from a system property with the name
+     * {@code GRAAL_OPTION_PROPERTY_PREFIX + "MyOption"}.
+     */
+    public static final String GRAAL_OPTION_PROPERTY_PREFIX = "graal.";
+
+    private static MethodFilter[] graalCompileOnlyFilter;
+
+    /**
+     * Gets the system property assignment that would set the current value for a given option.
+     */
+    public static String asSystemPropertySetting(OptionValue<?> value) {
+        return GRAAL_OPTION_PROPERTY_PREFIX + value.getName() + "=" + value.getValue();
+    }
+
+    private final HotSpotGraalJVMCIServiceLocator locator;
+
+    HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) {
+        this.locator = locator;
+    }
+
+    @Override
+    public String getCompilerName() {
+        return "graal";
+    }
+
+    @Override
+    public void onSelection() {
+        initializeOptions();
+        JVMCIVersionCheck.check(false);
+    }
+
+    @Override
+    public void printProperties(PrintStream out) {
+        ServiceLoader<OptionDescriptors> loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader());
+        out.println("[Graal properties]");
+        OptionsParser.printFlags(loader, out, allOptionsSettings.keySet(), GRAAL_OPTION_PROPERTY_PREFIX);
+    }
+
+    static class Options {
+
+        // @formatter:off
+        @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
+        public static final OptionValue<Boolean> CompileGraalWithC1Only = new OptionValue<>(true);
+
+        @Option(help = "Hook into VM-level mechanism for denoting compilations to be performed in first tier.", type = OptionType.Expert)
+        public static final OptionValue<Boolean> UseTrivialPrefixes = new OptionValue<>(false);
+
+        @Option(help = "A method filter selecting what should be compiled by Graal.  All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
+        public static final OptionValue<String> GraalCompileOnly = new OptionValue<>(null);
+        // @formatter:on
+
+    }
+
+    private static Map<String, String> allOptionsSettings;
+
+    /**
+     * Initializes options if they haven't already been initialized.
+     *
+     * Initialization means first parsing the options in the file denoted by the
+     * {@code VM.getSavedProperty(String) saved} system property named
+     * {@value HotSpotGraalCompilerFactory#GRAAL_OPTIONS_FILE_PROPERTY_NAME} if the file exists
+     * followed by parsing the options encoded in saved system properties whose names start with
+     * {@value #GRAAL_OPTION_PROPERTY_PREFIX}. Key/value pairs are parsed from the aforementioned
+     * file with {@link Properties#load(java.io.Reader)}.
+     */
+    @SuppressWarnings("try")
+    private static synchronized void initializeOptions() {
+        if (allOptionsSettings == null) {
+            try (InitTimer t = timer("InitializeOptions")) {
+                ServiceLoader<OptionDescriptors> loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader());
+                Properties savedProps = getSavedProperties(Java8OrEarlier);
+                String optionsFile = savedProps.getProperty(GRAAL_OPTIONS_FILE_PROPERTY_NAME);
+
+                if (optionsFile != null) {
+                    File graalOptions = new File(optionsFile);
+                    if (graalOptions.exists()) {
+                        try (FileReader fr = new FileReader(graalOptions)) {
+                            Properties props = new Properties();
+                            props.load(fr);
+                            Map<String, String> optionSettings = new HashMap<>();
+                            for (Map.Entry<Object, Object> e : props.entrySet()) {
+                                optionSettings.put((String) e.getKey(), (String) e.getValue());
+                            }
+                            try {
+                                OptionsParser.parseOptions(optionSettings, null, loader);
+                                if (allOptionsSettings == null) {
+                                    allOptionsSettings = new HashMap<>(optionSettings);
+                                } else {
+                                    allOptionsSettings.putAll(optionSettings);
+                                }
+                            } catch (Throwable e) {
+                                throw new InternalError("Error parsing an option from " + graalOptions, e);
+                            }
+                        } catch (IOException e) {
+                            throw new InternalError("Error reading " + graalOptions, e);
+                        }
+                    }
+                }
+
+                Map<String, String> optionSettings = new HashMap<>();
+                for (Map.Entry<Object, Object> e : savedProps.entrySet()) {
+                    String name = (String) e.getKey();
+                    if (name.startsWith(GRAAL_OPTION_PROPERTY_PREFIX)) {
+                        if (name.equals("graal.PrintFlags") || name.equals("graal.ShowFlags")) {
+                            System.err.println("The " + name + " option has been removed and will be ignored. Use -XX:+JVMCIPrintProperties instead.");
+                        } else if (name.equals(GRAAL_OPTIONS_FILE_PROPERTY_NAME) || name.equals(GRAAL_VERSION_PROPERTY_NAME) || name.equals(PROFILE_OPTIONVALUE_PROPERTY_NAME)) {
+                            // Ignore well known properties that do not denote an option
+                        } else {
+                            String value = (String) e.getValue();
+                            optionSettings.put(name.substring(GRAAL_OPTION_PROPERTY_PREFIX.length()), value);
+                        }
+                    }
+                }
+
+                OptionsParser.parseOptions(optionSettings, null, loader);
+
+                if (allOptionsSettings == null) {
+                    allOptionsSettings = optionSettings;
+                } else {
+                    allOptionsSettings.putAll(optionSettings);
+                }
+
+                if (Options.GraalCompileOnly.getValue() != null) {
+                    graalCompileOnlyFilter = MethodFilter.parse(Options.GraalCompileOnly.getValue());
+                    if (graalCompileOnlyFilter.length == 0) {
+                        graalCompileOnlyFilter = null;
+                    }
+                }
+                if (graalCompileOnlyFilter != null || !Options.UseTrivialPrefixes.getValue()) {
+                    /*
+                     * Exercise this code path early to encourage loading now. This doesn't solve
+                     * problem of deadlock during class loading but seems to eliminate it in
+                     * practice.
+                     */
+                    adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
+                    adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
+                }
+            }
+        }
+    }
+
+    private static Properties getSavedProperties(boolean jdk8OrEarlier) {
+        try {
+            String vmClassName = jdk8OrEarlier ? "sun.misc.VM" : "jdk.internal.misc.VM";
+            Class<?> vmClass = Class.forName(vmClassName);
+            Field savedPropsField = vmClass.getDeclaredField("savedProps");
+            savedPropsField.setAccessible(true);
+            return (Properties) savedPropsField.get(null);
+        } catch (Exception e) {
+            throw new GraalError(e);
+        }
+    }
+
+    @Override
+    public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
+        HotSpotGraalCompiler compiler = createCompiler(runtime, CompilerConfigurationFactory.selectFactory(null));
+        // Only the HotSpotGraalRuntime associated with the compiler created via
+        // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
+        // VM events.
+        locator.onCompilerCreation(compiler);
+        return compiler;
+    }
+
+    /**
+     * Creates a new {@link HotSpotGraalRuntime} object and a new {@link HotSpotGraalCompiler} and
+     * returns the latter.
+     *
+     * @param runtime the JVMCI runtime on which the {@link HotSpotGraalRuntime} is built
+     * @param compilerConfigurationFactory factory for the {@link CompilerConfiguration}
+     */
+    @SuppressWarnings("try")
+    public static HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime, CompilerConfigurationFactory compilerConfigurationFactory) {
+        HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime;
+        try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
+            HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory);
+            return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime);
+        }
+    }
+
+    @Override
+    public String[] getTrivialPrefixes() {
+        if (Options.UseTrivialPrefixes.getValue()) {
+            if (Options.CompileGraalWithC1Only.getValue()) {
+                return new String[]{"jdk/vm/ci", "org/graalvm/compiler", "com/oracle/graal"};
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public CompilationLevelAdjustment getCompilationLevelAdjustment() {
+        if (graalCompileOnlyFilter != null) {
+            return CompilationLevelAdjustment.ByFullSignature;
+        }
+        if (!Options.UseTrivialPrefixes.getValue()) {
+            if (Options.CompileGraalWithC1Only.getValue()) {
+                // We only decide using the class declaring the method
+                // so no need to have the method name and signature
+                // symbols converted to a String.
+                return CompilationLevelAdjustment.ByHolder;
+            }
+        }
+        return CompilationLevelAdjustment.None;
+    }
+
+    @Override
+    public CompilationLevel adjustCompilationLevel(Class<?> declaringClass, String name, String signature, boolean isOsr, CompilationLevel level) {
+        return adjustCompilationLevelInternal(declaringClass, name, signature, level);
+    }
+
+    /*
+     * This method is static so it can be exercised during initialization.
+     */
+    private static CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
+        if (graalCompileOnlyFilter != null) {
+            if (level == CompilationLevel.FullOptimization) {
+                String declaringClassName = declaringClass.getName();
+                HotSpotSignature sig = null;
+                for (MethodFilter filter : graalCompileOnlyFilter) {
+                    if (filter.hasSignature() && sig == null) {
+                        sig = new HotSpotSignature(HotSpotJVMCIRuntime.runtime(), signature);
+                    }
+                    if (filter.matches(declaringClassName, name, sig)) {
+                        return level;
+                    }
+                }
+                return CompilationLevel.Simple;
+            }
+        }
+        if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
+            String declaringClassName = declaringClass.getName();
+            if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm.compiler") || declaringClassName.startsWith("com.oracle.graal")) {
+                return CompilationLevel.Simple;
+            }
+        }
+        return level;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java
new file mode 100644
index 0000000..b33b0cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports;
+import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
+import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+import jdk.vm.ci.hotspot.HotSpotVMEventListener;
+import jdk.vm.ci.runtime.JVMCICompilerFactory;
+import jdk.vm.ci.services.JVMCIServiceLocator;
+
+@ServiceProvider(JVMCIServiceLocator.class)
+public final class HotSpotGraalJVMCIServiceLocator extends JVMCIServiceLocator {
+
+    private boolean exportsAdded;
+
+    /**
+     * Dynamically exports various internal JDK packages to the Graal module. This requires only
+     * {@code --add-exports=java.base/jdk.internal.module=org.graalvm.compiler.graal_core} on the VM
+     * command line instead of a {@code --add-exports} instance for each JDK internal package used
+     * by Graal.
+     */
+    private void addExports() {
+        if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) {
+            Object javaBaseModule = getModule.invoke(String.class);
+            Object graalModule = getModule.invoke(getClass());
+            addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
+            addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
+            addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
+            exportsAdded = true;
+        }
+    }
+
+    private HotSpotGraalRuntime graalRuntime;
+
+    @Override
+    public <T> T getProvider(Class<T> service) {
+        if (service == JVMCICompilerFactory.class) {
+            addExports();
+            return service.cast(new HotSpotGraalCompilerFactory(this));
+        } else if (service == HotSpotVMEventListener.class) {
+            if (graalRuntime != null) {
+                addExports();
+                return service.cast(new HotSpotGraalVMEventListener(graalRuntime));
+            }
+        }
+        return null;
+    }
+
+    public void onCompilerCreation(HotSpotGraalCompiler compiler) {
+        assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created";
+        this.graalRuntime = (HotSpotGraalRuntime) compiler.getGraalRuntime();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
new file mode 100644
index 0000000..01401ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Log;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify;
+import static jdk.vm.ci.common.InitTimer.timer;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.api.collections.CollectionsProvider;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.runtime.GraalRuntime;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.DebugValuesPrinter;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsPrinter;
+import org.graalvm.compiler.graph.DefaultNodeCollectionsProvider;
+import org.graalvm.compiler.graph.NodeCollectionsProvider;
+import org.graalvm.compiler.hotspot.CompilerConfigurationFactory.BackendMap;
+import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.stack.StackIntrospection;
+import jdk.vm.ci.common.InitTimer;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+//JaCoCo Exclude
+
+/**
+ * Singleton class holding the instance of the {@link GraalRuntime}.
+ */
+public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
+
+    private static boolean checkArrayIndexScaleInvariants() {
+        assert getArrayIndexScale(JavaKind.Byte) == 1;
+        assert getArrayIndexScale(JavaKind.Boolean) == 1;
+        assert getArrayIndexScale(JavaKind.Char) == 2;
+        assert getArrayIndexScale(JavaKind.Short) == 2;
+        assert getArrayIndexScale(JavaKind.Int) == 4;
+        assert getArrayIndexScale(JavaKind.Long) == 8;
+        assert getArrayIndexScale(JavaKind.Float) == 4;
+        assert getArrayIndexScale(JavaKind.Double) == 8;
+        return true;
+    }
+
+    private final HotSpotBackend hostBackend;
+    private DebugValuesPrinter debugValuesPrinter;
+
+    private final Map<Class<? extends Architecture>, HotSpotBackend> backends = new HashMap<>();
+
+    private final GraalHotSpotVMConfig config;
+
+    /**
+     * @param compilerConfigurationFactory factory for the compiler configuration
+     *            {@link CompilerConfigurationFactory#selectFactory(String)}
+     */
+    @SuppressWarnings("try")
+    HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) {
+
+        HotSpotVMConfigStore store = jvmciRuntime.getConfigStore();
+        config = new GraalHotSpotVMConfig(store);
+        CompileTheWorldOptions.overrideWithNativeOptions(config);
+
+        // Only set HotSpotPrintInlining if it still has its default value (false).
+        if (GraalOptions.HotSpotPrintInlining.getValue() == false) {
+            GraalOptions.HotSpotPrintInlining.setValue(config.printInlining);
+        }
+
+        CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
+        BackendMap backendMap = compilerConfigurationFactory.createBackendMap();
+
+        JVMCIBackend hostJvmciBackend = jvmciRuntime.getHostJVMCIBackend();
+        Architecture hostArchitecture = hostJvmciBackend.getTarget().arch;
+        try (InitTimer t = timer("create backend:", hostArchitecture)) {
+            HotSpotBackendFactory factory = backendMap.getBackendFactory(hostArchitecture);
+            if (factory == null) {
+                throw new GraalError("No backend available for host architecture \"%s\"", hostArchitecture);
+            }
+            hostBackend = registerBackend(factory.createBackend(this, compilerConfiguration, jvmciRuntime, null));
+        }
+
+        for (JVMCIBackend jvmciBackend : jvmciRuntime.getJVMCIBackends().values()) {
+            if (jvmciBackend == hostJvmciBackend) {
+                continue;
+            }
+
+            Architecture gpuArchitecture = jvmciBackend.getTarget().arch;
+            HotSpotBackendFactory factory = backendMap.getBackendFactory(gpuArchitecture);
+            if (factory == null) {
+                throw new GraalError("No backend available for specified GPU architecture \"%s\"", gpuArchitecture);
+            }
+            try (InitTimer t = timer("create backend:", gpuArchitecture)) {
+                registerBackend(factory.createBackend(this, compilerConfiguration, null, hostBackend));
+            }
+        }
+
+        if (Log.getValue() == null && !areScopedGlobalMetricsEnabled() && Dump.getValue() == null && Verify.getValue() == null) {
+            if (MethodFilter.getValue() != null && !Debug.isEnabled()) {
+                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, TrackMemUse, Dump and Verify options are all null");
+            }
+        }
+
+        if (Debug.isEnabled()) {
+            DebugEnvironment.initialize(TTY.out, hostBackend.getProviders().getSnippetReflection());
+
+            String summary = DebugValueSummary.getValue();
+            if (summary != null) {
+                switch (summary) {
+                    case "Name":
+                    case "Partial":
+                    case "Complete":
+                    case "Thread":
+                        break;
+                    default:
+                        throw new GraalError("Unsupported value for DebugSummaryValue: %s", summary);
+                }
+            }
+        }
+
+        if (Debug.areUnconditionalCountersEnabled() || Debug.areUnconditionalTimersEnabled() || Debug.areUnconditionalMethodMetricsEnabled() ||
+                        (Debug.isEnabled() && areScopedGlobalMetricsEnabled()) || (Debug.isEnabled() && Debug.isMethodFilteringEnabled())) {
+            // This must be created here to avoid loading the DebugValuesPrinter class
+            // during shutdown() which in turn can cause a deadlock
+            int mmPrinterType = 0;
+            mmPrinterType |= MethodMetricsPrinter.Options.MethodMeterPrintAscii.getValue() ? 1 : 0;
+            mmPrinterType |= MethodMetricsPrinter.Options.MethodMeterFile.getValue() != null ? 2 : 0;
+            switch (mmPrinterType) {
+                case 0:
+                    debugValuesPrinter = new DebugValuesPrinter();
+                    break;
+                case 1:
+                    debugValuesPrinter = new DebugValuesPrinter(new MethodMetricsPrinter.MethodMetricsASCIIPrinter(TTY.out));
+                    break;
+                case 2:
+                    debugValuesPrinter = new DebugValuesPrinter(new MethodMetricsPrinter.MethodMetricsCSVFilePrinter());
+                    break;
+                case 3:
+                    debugValuesPrinter = new DebugValuesPrinter(
+                                    new MethodMetricsPrinter.MethodMetricsCompositePrinter(new MethodMetricsPrinter.MethodMetricsCSVFilePrinter(),
+                                                    new MethodMetricsPrinter.MethodMetricsASCIIPrinter(TTY.out)));
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Complete initialization of backends
+        try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
+            hostBackend.completeInitialization(jvmciRuntime);
+        }
+        for (HotSpotBackend backend : backends.values()) {
+            if (backend != hostBackend) {
+                try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) {
+                    backend.completeInitialization(jvmciRuntime);
+                }
+            }
+        }
+
+        BenchmarkCounters.initialize(jvmciRuntime);
+
+        assert checkArrayIndexScaleInvariants();
+
+        runtimeStartTime = System.nanoTime();
+        bootstrapJVMCI = config.getFlag("BootstrapJVMCI", Boolean.class);
+    }
+
+    private HotSpotBackend registerBackend(HotSpotBackend backend) {
+        Class<? extends Architecture> arch = backend.getTarget().arch.getClass();
+        HotSpotBackend oldValue = backends.put(arch, backend);
+        assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName();
+        return backend;
+    }
+
+    @Override
+    public HotSpotProviders getHostProviders() {
+        return getHostBackend().getProviders();
+    }
+
+    @Override
+    public GraalHotSpotVMConfig getVMConfig() {
+        return config;
+    }
+
+    @Override
+    public String getName() {
+        return getClass().getSimpleName();
+    }
+
+    private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T getCapability(Class<T> clazz) {
+        if (clazz == RuntimeProvider.class) {
+            return (T) this;
+        } else if (clazz == CollectionsProvider.class || clazz == NodeCollectionsProvider.class) {
+            return (T) nodeCollectionsProvider;
+        } else if (clazz == StackIntrospection.class) {
+            return (T) this;
+        } else if (clazz == SnippetReflectionProvider.class) {
+            return (T) getHostProviders().getSnippetReflection();
+        } else if (clazz == StampProvider.class) {
+            return (T) getHostProviders().getStampProvider();
+        }
+        return null;
+    }
+
+    @Override
+    public HotSpotBackend getHostBackend() {
+        return hostBackend;
+    }
+
+    @Override
+    public <T extends Architecture> Backend getBackend(Class<T> arch) {
+        assert arch != Architecture.class;
+        return backends.get(arch);
+    }
+
+    public Map<Class<? extends Architecture>, HotSpotBackend> getBackends() {
+        return Collections.unmodifiableMap(backends);
+    }
+
+    private long runtimeStartTime;
+
+    /**
+     * Take action related to entering a new execution phase.
+     *
+     * @param phase the execution phase being entered
+     */
+    static void phaseTransition(String phase) {
+        CompilationStatistics.clear(phase);
+    }
+
+    void shutdown() {
+        if (debugValuesPrinter != null) {
+            debugValuesPrinter.printDebugValues();
+        }
+        phaseTransition("final");
+
+        SnippetCounter.printGroups(TTY.out().out());
+        BenchmarkCounters.shutdown(runtime(), runtimeStartTime);
+    }
+
+    void clearMeters() {
+        if (debugValuesPrinter != null) {
+            debugValuesPrinter.clearDebugValues();
+        }
+    }
+
+    private final boolean bootstrapJVMCI;
+    private boolean bootstrapFinished;
+
+    public void notifyBootstrapFinished() {
+        bootstrapFinished = true;
+    }
+
+    @Override
+    public boolean isBootstrapping() {
+        return bootstrapJVMCI && !bootstrapFinished;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
new file mode 100644
index 0000000..f662ab8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.api.runtime.GraalRuntime;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.TargetDescription;
+
+//JaCoCo Exclude
+
+/**
+ * Configuration information for the HotSpot Graal runtime.
+ */
+public interface HotSpotGraalRuntimeProvider extends GraalRuntime, RuntimeProvider {
+
+    default TargetDescription getTarget() {
+        return getHostBackend().getTarget();
+    }
+
+    HotSpotProviders getHostProviders();
+
+    @Override
+    default String getName() {
+        return getClass().getSimpleName();
+    }
+
+    @Override
+    HotSpotBackend getHostBackend();
+
+    GraalHotSpotVMConfig getVMConfig();
+
+    /**
+     * Determines if the VM is currently bootstrapping the JVMCI compiler.
+     */
+    boolean isBootstrapping();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java
new file mode 100644
index 0000000..64d1073
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+
+import jdk.vm.ci.code.CompiledCode;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotVMEventListener;
+
+public class HotSpotGraalVMEventListener implements HotSpotVMEventListener {
+
+    private final HotSpotGraalRuntime runtime;
+
+    HotSpotGraalVMEventListener(HotSpotGraalRuntime runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    public void notifyShutdown() {
+        runtime.shutdown();
+    }
+
+    @Override
+    public void notifyInstall(HotSpotCodeCacheProvider codeCache, InstalledCode installedCode, CompiledCode compiledCode) {
+        if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+            CompilationResult compResult = Debug.contextLookup(CompilationResult.class);
+            assert compResult != null : "can't dump installed code properly without CompilationResult";
+            Debug.dump(Debug.BASIC_LOG_LEVEL, installedCode, "After code installation");
+        }
+        if (Debug.isLogEnabled()) {
+            Debug.log("%s", codeCache.disassemble(installedCode));
+        }
+    }
+
+    @Override
+    public void notifyBootstrapFinished() {
+        runtime.notifyBootstrapFinished();
+        if (GraalDebugConfig.Options.ClearMetricsAfterBootstrap.getValue()) {
+            runtime.clearMeters();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java
new file mode 100644
index 0000000..8df8a9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static jdk.vm.ci.code.CodeUtil.getCallingConvention;
+import static jdk.vm.ci.common.InitTimer.timer;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.hotspot.stubs.UncommonTrapStub;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.common.InitTimer;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * Common functionality of HotSpot host backends.
+ */
+public abstract class HotSpotHostBackend extends HotSpotBackend {
+
+    /**
+     * Descriptor for {@code SharedRuntime::deopt_blob()->unpack()} or
+     * {@link DeoptimizationStub#deoptimizationHandler} depending on
+     * {@link HotSpotBackend.Options#PreferGraalStubs}.
+     */
+    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
+
+    /**
+     * Descriptor for {@code SharedRuntime::deopt_blob()->uncommon_trap()} or
+     * {@link UncommonTrapStub#uncommonTrapHandler} depending on
+     * {@link HotSpotBackend.Options#PreferGraalStubs}.
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
+
+    protected final GraalHotSpotVMConfig config;
+
+    public HotSpotHostBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(runtime, providers);
+        this.config = config;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime) {
+        final HotSpotProviders providers = getProviders();
+        HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
+        final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
+
+        try (InitTimer st = timer("foreignCalls.initialize")) {
+            foreignCalls.initialize(providers);
+        }
+        try (InitTimer st = timer("lowerer.initialize")) {
+            lowerer.initialize(providers, config);
+        }
+    }
+
+    protected CallingConvention makeCallingConvention(StructuredGraph graph, Stub stub) {
+        if (stub != null) {
+            return stub.getLinkage().getIncomingCallingConvention();
+        }
+
+        CallingConvention cc = getCallingConvention(getCodeCache(), HotSpotCallingConventionType.JavaCallee, graph.method(), this);
+        if (graph.getEntryBCI() != JVMCICompiler.INVOCATION_ENTRY_BCI) {
+            // for OSR, only a pointer is passed to the method.
+            JavaType[] parameterTypes = new JavaType[]{getMetaAccess().lookupJavaType(long.class)};
+            CallingConvention tmp = getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCallee, getMetaAccess().lookupJavaType(void.class), parameterTypes, this);
+            cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
+        }
+        return cc;
+    }
+
+    public void emitStackOverflowCheck(CompilationResultBuilder crb) {
+        if (config.useStackBanging) {
+            // Each code entry causes one stack bang n pages down the stack where n
+            // is configurable by StackShadowPages. The setting depends on the maximum
+            // depth of VM call stack or native before going back into java code,
+            // since only java code can raise a stack overflow exception using the
+            // stack banging mechanism. The VM and native code does not detect stack
+            // overflow.
+            // The code in JavaCalls::call() checks that there is at least n pages
+            // available, so all entry code needs to do is bang once for the end of
+            // this shadow zone.
+            // The entry code may need to bang additional pages if the framesize
+            // is greater than a page.
+
+            int pageSize = config.vmPageSize;
+            int bangEnd = config.stackShadowPages * pageSize;
+
+            // This is how far the previous frame's stack banging extended.
+            int bangEndSafe = bangEnd;
+
+            int frameSize = Math.max(crb.frameMap.frameSize(), crb.compilationResult.getMaxInterpreterFrameSize());
+            if (frameSize > pageSize) {
+                bangEnd += frameSize;
+            }
+
+            int bangOffset = bangEndSafe;
+            if (bangOffset <= bangEnd) {
+                crb.blockComment("[stack overflow check]");
+            }
+            while (bangOffset <= bangEnd) {
+                // Need at least one stack bang at end of shadow zone.
+                bangStackWithOffset(crb, bangOffset);
+                bangOffset += pageSize;
+            }
+        }
+    }
+
+    protected abstract void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset);
+
+    @Override
+    public ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize) {
+        return new HotSpotReferenceMapBuilder(totalFrameSize, config.maxOopMapStackOffset);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotInstructionProfiling.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotInstructionProfiling.java
new file mode 100644
index 0000000..8b91390
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotInstructionProfiling.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.util.List;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Assembler.InstructionCounter;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase {
+    public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER";
+    private final String[] instructionsToProfile;
+
+    public HotSpotInstructionProfiling(String instructionsToProfile) {
+        this.instructionsToProfile = instructionsToProfile.split(",");
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), context.diagnosticLirGenTool).run();
+    }
+
+    private class Analyzer {
+        private final TargetDescription target;
+        private final LIR lir;
+        private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
+        private final LIRInsertionBuffer buffer;
+        private final String compilationUnitName;
+
+        Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
+            this.target = target;
+            this.lir = lir;
+            this.compilationUnitName = compilationUnitName;
+            this.diagnosticLirGenTool = diagnosticLirGenTool;
+            this.buffer = new LIRInsertionBuffer();
+        }
+
+        public void run() {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+            String[] names = new String[instructionsToProfile.length];
+            String[] groups = new String[instructionsToProfile.length];
+            Value[] increments = new Value[instructionsToProfile.length];
+            for (int i = 0; i < instructionsToProfile.length; i++) {
+                names[i] = compilationUnitName;
+                groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i];
+                // Default is zero; this value is patched to the real instruction count after
+                // assembly in method HotSpotInstructionProfiling.countInstructions
+                increments[i] = new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.INT_0);
+            }
+            HotSpotCounterOp op = (HotSpotCounterOp) diagnosticLirGenTool.createMultiBenchmarkCounter(names, groups, increments);
+            LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile);
+            assert inst != null;
+            buffer.init(instructions);
+            buffer.append(1, inst);
+            buffer.finish();
+        }
+    }
+
+    /**
+     * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)}
+     * calls this method for patching the instruction counts into the counter increment code.
+     */
+    public static void countInstructions(LIR lir, Assembler asm) {
+        InstructionCounterOp lastOp = null;
+        InstructionCounter counter = asm.getInstructionCounter();
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                if (inst instanceof InstructionCounterOp) {
+                    InstructionCounterOp currentOp = (InstructionCounterOp) inst;
+
+                    if (lastOp != null) {
+                        int beginPc = lastOp.countOffsetEnd;
+                        int endPc = currentOp.countOffsetBegin;
+                        int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+                        lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+                    }
+                    lastOp = ((InstructionCounterOp) inst);
+                }
+            }
+        }
+        if (lastOp != null) {
+            assert lastOp.countOffsetBegin < asm.position();
+            int beginPc = lastOp.countOffsetBegin;
+            int endPc = asm.position();
+            int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+            lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+        }
+    }
+
+    public static class InstructionCounterOp extends LIRInstruction {
+        public static final LIRInstructionClass<InstructionCounterOp> TYPE = LIRInstructionClass.create(InstructionCounterOp.class);
+        private final HotSpotCounterOp delegate;
+        private final String[] instructionsToProfile;
+        private int countOffsetBegin;
+        private int countOffsetEnd;
+
+        public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) {
+            super(TYPE);
+            this.delegate = delegate;
+            this.instructionsToProfile = instructionsToProfile;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            countOffsetBegin = crb.asm.position();
+            this.delegate.emitCode(crb);
+            countOffsetEnd = crb.asm.position();
+        }
+
+        public String[] getInstructionsToProfile() {
+            return instructionsToProfile;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java
new file mode 100644
index 0000000..11383b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.StackSlot;
+
+public class HotSpotLIRGenerationResult extends LIRGenerationResult {
+
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+    protected final Object stub;
+
+    private int maxInterpreterFrameSize;
+
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = CollectionsFactory.newMap();
+
+    public HotSpotLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, CallingConvention callingConvention, Object stub) {
+        super(compilationId, lir, frameMapBuilder, callingConvention);
+        this.stub = stub;
+    }
+
+    public Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
+
+    public Stub getStub() {
+        return (Stub) stub;
+    }
+
+    public StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
+
+    public final void setDeoptimizationRescueSlot(StackSlot stackSlot) {
+        this.deoptimizationRescueSlot = stackSlot;
+    }
+
+    public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) {
+        this.maxInterpreterFrameSize = maxInterpreterFrameSize;
+    }
+
+    public int getMaxInterpreterFrameSize() {
+        return maxInterpreterFrameSize;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java
new file mode 100644
index 0000000..d2c61d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode;
+import org.graalvm.compiler.hotspot.nodes.EnterUnpackFramesStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveCurrentStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveDeoptimizedStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveUnpackFramesStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.PushInterpreterFrameNode;
+import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode;
+import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode;
+import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
+ * to abstract methods from {@link LIRGenerator} and {@link LIRGeneratorTool}.
+ */
+public interface HotSpotLIRGenerator extends LIRGeneratorTool {
+
+    /**
+     * Emits an operation to make a tail call.
+     *
+     * @param args the arguments of the call
+     * @param address the target address of the call
+     */
+    void emitTailcall(Value[] args, Value address);
+
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+
+    /**
+     * Emits code for a {@link SaveAllRegistersNode}.
+     *
+     * @return a {@link SaveRegistersOp} operation
+     */
+    SaveRegistersOp emitSaveAllRegisters();
+
+    /**
+     * Emits code for a {@link LeaveCurrentStackFrameNode}.
+     *
+     * @param saveRegisterOp saved registers
+     */
+    default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LeaveDeoptimizedStackFrameNode}.
+     *
+     * @param frameSize
+     * @param initialInfo
+     */
+    default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link EnterUnpackFramesStackFrameNode}.
+     *
+     * @param framePc
+     * @param senderSp
+     * @param senderFp
+     * @param saveRegisterOp
+     */
+    default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LeaveUnpackFramesStackFrameNode}.
+     *
+     * @param saveRegisterOp
+     */
+    default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link PushInterpreterFrameNode}.
+     *
+     * @param frameSize
+     * @param framePc
+     * @param senderSp
+     * @param initialInfo
+     */
+    default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LoadConstantIndirectlyNode}.
+     *
+     * @param constant
+     * @return value of loaded address in register
+     */
+    default Value emitLoadObjectAddress(Constant constant) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LoadConstantIndirectlyNode}.
+     *
+     * @param constant
+     * @return Value of loaded address in register
+     */
+    @SuppressWarnings("unused")
+    default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link GraalHotSpotVMConfigNode}.
+     *
+     * @param markId type of address to load
+     * @return value of loaded global in register
+     */
+    default Value emitLoadConfigValue(int markId) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotObjectConstant}.
+     *
+     * @param constantDescription a description of the string that need to be materialized (and
+     *            interned) as java.lang.String, generated with {@link EncodedSymbolConstant}
+     * @return Returns the address of the requested constant.
+     */
+    @SuppressWarnings("unused")
+    default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotMetaspaceConstant}.
+     *
+     * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
+     *            generated by {@link EncodedSymbolConstant}
+     * @return Returns the address of the requested constant.
+     */
+    @SuppressWarnings("unused")
+    default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link ResolveMethodAndLoadCountersNode} to resolve a
+     * {@link HotSpotMetaspaceConstant} that represents a {@link ResolvedJavaMethod} and return the
+     * corresponding MethodCounters object.
+     *
+     * @param klassHint a klass in which the method is declared
+     * @param methodDescription is symbolic description of the constant generated by
+     *            {@link EncodedSymbolConstant}
+     * @return Returns the address of the requested constant.
+     */
+    @SuppressWarnings("unused")
+    default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link ResolveConstantNode} to resolve a klass
+     * {@link HotSpotMetaspaceConstant} and run static initializer.
+     *
+     * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
+     *            generated by {@link EncodedSymbolConstant}
+     * @return Returns the address of the requested constant.
+     */
+    @SuppressWarnings("unused")
+    default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link RandomSeedNode}.
+     *
+     * @return value of the counter
+     */
+    default Value emitRandomSeed() {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link UncommonTrapCallNode}.
+     *
+     * @param trapRequest
+     * @param mode
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}.
+     *
+     * @param mode
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth.
+     */
+    VirtualStackSlot getLockSlot(int lockDepth);
+
+    @Override
+    HotSpotProviders getProviders();
+
+    Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull);
+
+    Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLockStack.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLockStack.java
new file mode 100644
index 0000000..6e1dd62
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLockStack.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Manages allocation and re-use of lock slots in a scoped manner. The slots are used in HotSpot's
+ * lightweight locking mechanism to store the mark word of an object being locked.
+ */
+public class HotSpotLockStack extends LIRInstruction {
+    public static final LIRInstructionClass<HotSpotLockStack> TYPE = LIRInstructionClass.create(HotSpotLockStack.class);
+    private static final AllocatableValue[] EMPTY = new AllocatableValue[0];
+
+    @Def({STACK}) private AllocatableValue[] locks;
+    private final FrameMapBuilder frameMapBuilder;
+    private final LIRKind slotKind;
+
+    public HotSpotLockStack(FrameMapBuilder frameMapBuilder, LIRKind slotKind) {
+        super(TYPE);
+        this.frameMapBuilder = frameMapBuilder;
+        this.slotKind = slotKind;
+        this.locks = EMPTY;
+    }
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth, allocating it first if necessary.
+     */
+    public VirtualStackSlot makeLockSlot(int lockDepth) {
+        if (locks == EMPTY) {
+            locks = new AllocatableValue[lockDepth + 1];
+        } else if (locks.length < lockDepth + 1) {
+            locks = Arrays.copyOf(locks, lockDepth + 1);
+        }
+        if (locks[lockDepth] == null) {
+            locks[lockDepth] = frameMapBuilder.allocateSpillSlot(slotKind);
+        }
+        return (VirtualStackSlot) locks[lockDepth];
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        // do nothing
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java
new file mode 100644
index 0000000..7dc534a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.core.match.MatchableNode;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
+ * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}.
+ */
+@MatchableNode(nodeClass = CompressionNode.class, inputs = {"value"})
+public interface HotSpotNodeLIRBuilder {
+
+    void emitPatchReturnAddress(ValueNode address);
+
+    default void emitJumpToExceptionHandler(ValueNode address) {
+        emitPatchReturnAddress(address);
+    }
+
+    void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc);
+
+    void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java
new file mode 100644
index 0000000..a8b7982
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
+
+import jdk.vm.ci.code.Location;
+import jdk.vm.ci.code.ReferenceMap;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotReferenceMap;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public final class HotSpotReferenceMapBuilder extends ReferenceMapBuilder {
+
+    private int maxRegisterSize;
+
+    private final ArrayList<Value> objectValues;
+    private int objectCount;
+
+    private final int totalFrameSize;
+    private final int maxOopMapStackOffset;
+
+    public HotSpotReferenceMapBuilder(int totalFrameSize, int maxOopMapStackOffset) {
+        this.objectValues = new ArrayList<>();
+        this.objectCount = 0;
+        this.maxOopMapStackOffset = maxOopMapStackOffset;
+        this.totalFrameSize = totalFrameSize;
+    }
+
+    @Override
+    public void addLiveValue(Value v) {
+        if (isJavaConstant(v)) {
+            return;
+        }
+        LIRKind lirKind = (LIRKind) v.getValueKind();
+        if (!lirKind.isValue()) {
+            objectValues.add(v);
+            if (lirKind.isUnknownReference()) {
+                objectCount++;
+            } else {
+                objectCount += lirKind.getReferenceCount();
+            }
+        }
+        if (isRegister(v)) {
+            int size = lirKind.getPlatformKind().getSizeInBytes();
+            if (size > maxRegisterSize) {
+                maxRegisterSize = size;
+            }
+        }
+    }
+
+    private static final Location[] NO_LOCATIONS = {};
+    private static final int[] NO_SIZES = {};
+
+    @Override
+    public ReferenceMap finish(LIRFrameState state) {
+        Location[] objects;
+        Location[] derivedBase;
+        int[] sizeInBytes;
+        if (objectCount == 0) {
+            objects = NO_LOCATIONS;
+            derivedBase = NO_LOCATIONS;
+            sizeInBytes = NO_SIZES;
+        } else {
+            objects = new Location[objectCount];
+            derivedBase = new Location[objectCount];
+            sizeInBytes = new int[objectCount];
+        }
+        int idx = 0;
+        for (Value obj : objectValues) {
+            LIRKind kind = (LIRKind) obj.getValueKind();
+            int bytes = bytesPerElement(kind);
+            if (kind.isUnknownReference()) {
+                throw GraalError.shouldNotReachHere("unknown reference alive across safepoint");
+            } else {
+                Location base = null;
+                if (kind.isDerivedReference()) {
+                    Variable baseVariable = (Variable) kind.getDerivedReferenceBase();
+                    Value baseValue = state.getLiveBasePointers().get(baseVariable.index);
+                    assert baseValue.getPlatformKind().getVectorLength() == 1 && ((LIRKind) baseValue.getValueKind()).isReference(0) && !((LIRKind) baseValue.getValueKind()).isDerivedReference();
+                    base = toLocation(baseValue, 0);
+                }
+
+                for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) {
+                    if (kind.isReference(i)) {
+                        objects[idx] = toLocation(obj, i * bytes);
+                        derivedBase[idx] = base;
+                        sizeInBytes[idx] = bytes;
+                        idx++;
+                    }
+                }
+            }
+        }
+
+        return new HotSpotReferenceMap(objects, derivedBase, sizeInBytes, maxRegisterSize);
+    }
+
+    private static int bytesPerElement(LIRKind kind) {
+        PlatformKind platformKind = kind.getPlatformKind();
+        return platformKind.getSizeInBytes() / platformKind.getVectorLength();
+    }
+
+    private Location toLocation(Value v, int offset) {
+        if (isRegister(v)) {
+            return Location.subregister(asRegister(v), offset);
+        } else {
+            StackSlot s = asStackSlot(v);
+            int totalOffset = s.getOffset(totalFrameSize) + offset;
+            if (totalOffset > maxOopMapStackOffset) {
+                throw new PermanentBailoutException("stack offset %d for oopmap is greater than encoding limit %d", totalOffset, maxOopMapStackOffset);
+            }
+            return Location.stack(totalOffset);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
new file mode 100644
index 0000000..dc52af6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotOperation;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Filters certain method substitutions based on whether there is underlying hardware support for
+ * them.
+ */
+public class HotSpotReplacementsImpl extends ReplacementsImpl {
+
+    public HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) {
+        super(providers, snippetReflection, bytecodeProvider, target);
+    }
+
+    @Override
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java
new file mode 100644
index 0000000..8bd1710
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.io.PrintStream;
+
+import org.graalvm.compiler.debug.TTYStreamProvider;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+@ServiceProvider(TTYStreamProvider.class)
+public class HotSpotTTYStreamProvider implements TTYStreamProvider {
+
+    public static class Options {
+
+        // @formatter:off
+        @Option(help = "File to which logging is sent.  A %p in the name will be replaced with a string identifying " +
+        "the process, usually the process id and %t will be replaced by System.currentTimeMillis().", type = OptionType.Expert)
+        public static final PrintStreamOption LogFile = new PrintStreamOption();
+        // @formatter:on
+    }
+
+    @Override
+    public PrintStream getStream() {
+        return Options.LogFile.getStream();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java
new file mode 100644
index 0000000..abae7a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.util.Formatter;
+
+/**
+ * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API
+ * required by Graal. The {@code JVMCI_VERSION_CHECK} environment variable can be used to ignore a
+ * failed check ({@code JVMCI_VERSION_CHECK=ignore}) or print a warning (
+ * {@code JVMCI_VERSION_CHECK=warn}) and continue. Otherwise, a failed check results in an
+ * {@link InternalError} being raised or, if called from {@link #main(String[])}, the VM exiting
+ * with a result code of {@code -1}
+ *
+ * This class only depends on the JDK so that it can be used without building Graal.
+ */
+class JVMCIVersionCheck {
+
+    private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
+    private static final int JVMCI8_MIN_MINOR_VERSION = 23;
+
+    // Will be updated once an ea build with the required JVMCI API is available.
+    private static final int JVMCI9_MIN_EA_BUILD = 143;
+
+    private static void failVersionCheck(boolean exit, String reason, Object... args) {
+        Formatter errorMessage = new Formatter().format(reason, args);
+        String javaHome = System.getProperty("java.home");
+        String vmName = System.getProperty("java.vm.name");
+        errorMessage.format("Set the JVMCI_VERSION_CHECK environment variable to \"ignore\" to suppress ");
+        errorMessage.format("this error or to \"warn\" to emit a warning and continue execution.%n");
+        errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
+        errorMessage.format("Currently used VM configuration is: %s%n", vmName);
+        if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
+            errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html");
+        } else {
+            errorMessage.format("Download the latest JDK 9 EA from https://jdk9.java.net/download/");
+        }
+        String value = System.getenv("JVMCI_VERSION_CHECK");
+        if ("warn".equals(value)) {
+            System.err.println(errorMessage.toString());
+        } else if ("ignore".equals(value)) {
+            return;
+        } else if (exit) {
+            System.err.println(errorMessage.toString());
+            System.exit(-1);
+        } else {
+            throw new InternalError(errorMessage.toString());
+        }
+    }
+
+    static void check(boolean exitOnFailure) {
+        // Don't use regular expressions to minimize Graal startup time
+        String vmVersion = System.getProperty("java.vm.version");
+        if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
+            int start = vmVersion.indexOf("-jvmci-");
+            if (start >= 0) {
+                start += "-jvmci-".length();
+                int end = vmVersion.indexOf('.', start);
+                if (end > 0) {
+                    int major = Integer.parseInt(vmVersion.substring(start, end));
+                    start = end + 1;
+                    end = start;
+                    while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
+                        end++;
+                    }
+                    int minor = Integer.parseInt(vmVersion.substring(start, end));
+                    if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) {
+                        return;
+                    }
+                    failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
+                                    major, minor, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
+                    return;
+                }
+            }
+            failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                            "Cannot read JVMCI version from java.vm.version property: %s.%n", vmVersion);
+        } else {
+            if (vmVersion.contains("SNAPSHOT")) {
+                // The snapshot of http://hg.openjdk.java.net/jdk9/hs tip is expected to work
+                return;
+            }
+            if (vmVersion.contains("internal")) {
+                // Allow local builds
+                return;
+            }
+            // http://openjdk.java.net/jeps/223
+            // Only support EA builds until GA is available
+            if (vmVersion.startsWith("9-ea+")) {
+                int start = "9-ea+".length();
+                int end = start;
+                end = start;
+                while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
+                    end++;
+                }
+                int build = Integer.parseInt(vmVersion.substring(start, end));
+                if (build >= JVMCI9_MIN_EA_BUILD) {
+                    return;
+                }
+                failVersionCheck(exitOnFailure, "The VM is an insufficiently recent EA JDK9 build for Graal: %d < %d.%n", build, JVMCI9_MIN_EA_BUILD);
+                return;
+            }
+            failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                            "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion);
+        }
+    }
+
+    /**
+     * Command line interface for performing the check.
+     */
+    public static void main(String[] args) {
+        check(true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOption.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOption.java
new file mode 100644
index 0000000..e2b389f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOption.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.UniquePathUtilities;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+
+/**
+ * An option that encapsulates and configures a print stream.
+ */
+public class PrintStreamOption extends OptionValue<String> {
+
+    public PrintStreamOption() {
+        super(null);
+    }
+
+    /**
+     * The print stream to which output will be written.
+     *
+     * Declared {@code volatile} to enable safe use of double-checked locking in
+     * {@link #getStream()} and {@link #setValue(Object)}.
+     */
+    private volatile PrintStream ps;
+
+    /**
+     * Replaces any instance of %p with an identifying name such as a process ID extracted from
+     * {@link RuntimeMXBean#getName()} and any instance of %t with the value of
+     * {@link System#currentTimeMillis()}.
+     *
+     * @return the name of the file to log to
+     */
+    private String getFilename() {
+        String name = getValue();
+        if (name.contains("%t")) {
+            name = name.replaceAll("%t", String.valueOf(UniquePathUtilities.getGlobalTimeStamp()));
+        }
+        if (name.contains("%p")) {
+            String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
+            try {
+                int index = runtimeName.indexOf('@');
+                if (index != -1) {
+                    long pid = Long.parseLong(runtimeName.substring(0, index));
+                    runtimeName = Long.toString(pid);
+                }
+                name = name.replaceAll("%p", runtimeName);
+            } catch (NumberFormatException e) {
+
+            }
+        }
+        return name;
+    }
+
+    /**
+     * An output stream that redirects to {@link HotSpotJVMCIRuntimeProvider#getLogStream()}. The
+     * {@link HotSpotJVMCIRuntimeProvider#getLogStream()} value is only accessed the first time an
+     * IO operation is performed on the stream. This is required to break a deadlock in early JVMCI
+     * initialization.
+     */
+    static class DelayedOutputStream extends OutputStream {
+        private volatile OutputStream lazy;
+
+        private OutputStream lazy() {
+            if (lazy == null) {
+                synchronized (this) {
+                    if (lazy == null) {
+                        lazy = HotSpotJVMCIRuntime.runtime().getLogStream();
+                    }
+                }
+            }
+            return lazy;
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            lazy().write(b, off, len);
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            lazy().write(b);
+        }
+
+        @Override
+        public void flush() throws IOException {
+            lazy().flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            lazy().close();
+        }
+    }
+
+    /**
+     * Gets the print stream configured by this option. If no file is configured, the print stream
+     * will output to HotSpot's {@link HotSpotJVMCIRuntimeProvider#getLogStream() log} stream.
+     */
+    public PrintStream getStream() {
+        if (ps == null) {
+            if (getValue() != null) {
+                synchronized (this) {
+                    if (ps == null) {
+                        try {
+                            final boolean enableAutoflush = true;
+                            ps = new PrintStream(new FileOutputStream(getFilename()), enableAutoflush);
+                            /*
+                             * Add the JVM and Java arguments to the log file to help identity it.
+                             */
+                            String inputArguments = String.join(" ", ManagementFactory.getRuntimeMXBean().getInputArguments());
+                            ps.println("VM Arguments: " + inputArguments);
+                            String cmd = System.getProperty("sun.java.command");
+                            if (cmd != null) {
+                                ps.println("sun.java.command=" + cmd);
+                            }
+                        } catch (FileNotFoundException e) {
+                            throw new RuntimeException("couldn't open file: " + getValue(), e);
+                        }
+                    }
+                }
+            } else {
+                ps = new PrintStream(new DelayedOutputStream());
+            }
+        }
+        return ps;
+    }
+
+    @Override
+    public void setValue(Object v) {
+        if (ps != null) {
+            synchronized (this) {
+                if (ps != null) {
+                    ps.close();
+                    ps = null;
+                }
+            }
+        }
+        super.setValue(v);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java
new file mode 100644
index 0000000..700fa99
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.debug;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions;
+import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+import org.graalvm.compiler.options.UniquePathUtilities;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+
+//JaCoCo Exclude
+
+/**
+ * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The
+ * infrastructure is enabled by specifying either the GenericDynamicCounters or
+ * BenchmarkDynamicCounters option.
+ * <p>
+ *
+ * The counters are kept in a special area allocated for each native JavaThread object, and the
+ * number of counters is configured using {@code -XX:JVMCICounterSize=value}.
+ * {@code -XX:+/-JVMCICountersExcludeCompiler} configures whether to exclude compiler threads
+ * (defaults to true).
+ *
+ * The subsystems that use the logging need to have their own options to turn on the counters, and
+ * insert DynamicCounterNodes when they're enabled.
+ *
+ * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise
+ * they will be displayed as a total number.
+ *
+ * <h1>Example</h1> In order to create statistics about allocations within the DaCapo pmd benchmark
+ * the following steps are necessary:
+ * <ul>
+ * <li>Set {@code -XX:JVMCICounterSize=value}. The actual required value depends on the granularity
+ * of the profiling, 10000 should be enough for most cases.</li>
+ * <li>Also: {@code -XX:+/-JVMCICountersExcludeCompiler} specifies whether the numbers generated by
+ * compiler threads should be excluded (default: true).</li>
+ * <li>Start the DaCapo pmd benchmark with
+ * {@code "-Dgraal.BenchmarkDynamicCounters=err, starting ====, PASSED in "} and
+ * {@code -Dgraal.ProfileAllocations=true}.</li>
+ * <li>The numbers will only include allocation from compiled code!</li>
+ * <li>The counters can be further configured by modifying the
+ * {@link HotspotSnippetsOptions#ProfileAllocationsContext} flag..</li>
+ * </ul>
+ */
+public class BenchmarkCounters {
+
+    static class Options {
+
+        //@formatter:off
+        @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown", type = OptionType.Debug)
+        public static final OptionValue<Boolean> GenericDynamicCounters = new OptionValue<>(false);
+        @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds", type = OptionType.Debug)
+        public static final OptionValue<Integer> TimedDynamicCounters = new OptionValue<>(-1);
+
+        @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" +
+                       "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" +
+                       "Examples:%n" +
+                       "  dacapo = 'err, starting =====, PASSED in'%n" +
+                       "  specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug)
+        public static final OptionValue<String> BenchmarkDynamicCounters = new OptionValue<>(null);
+        @Option(help = "Use grouping separators for number printing", type = OptionType.Debug)
+        public static final OptionValue<Boolean> DynamicCountersPrintGroupSeparator = new OptionValue<>(true);
+        @Option(help = "Print in human readable format", type = OptionType.Debug)
+        public static final OptionValue<Boolean> DynamicCountersHumanReadable = new OptionValue<>(true);
+        @Option(help = "Benchmark counters log file (default is stdout)", type = OptionType.Debug)
+        public static final OptionValue<String> BenchmarkCountersFile = new OptionValue<>(null);
+        @Option(help = "Dump dynamic counters", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> BenchmarkCountersDumpDynamic = new StableOptionValue<>(true);
+        @Option(help = "Dump static counters", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> BenchmarkCountersDumpStatic = new StableOptionValue<>(false);
+        //@formatter:on
+    }
+
+    public static boolean enabled = false;
+
+    private static class Counter {
+        public final int index;
+        public final String group;
+        public final AtomicLong staticCounters;
+
+        Counter(int index, String group, AtomicLong staticCounters) {
+            this.index = index;
+            this.group = group;
+            this.staticCounters = staticCounters;
+        }
+    }
+
+    public static final ConcurrentHashMap<String, Counter> counterMap = new ConcurrentHashMap<>();
+    public static long[] delta;
+
+    public static int getIndexConstantIncrement(String name, String group, GraalHotSpotVMConfig config, long increment) {
+        Counter counter = getCounter(name, group, config);
+        counter.staticCounters.addAndGet(increment);
+        return counter.index;
+    }
+
+    public static int getIndex(String name, String group, GraalHotSpotVMConfig config) {
+        Counter counter = getCounter(name, group, config);
+        return counter.index;
+    }
+
+    @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
+    private static Counter getCounter(String name, String group, GraalHotSpotVMConfig config) throws GraalError {
+        if (!enabled) {
+            throw new GraalError("cannot access count index when counters are not enabled: " + group + ", " + name);
+        }
+        String nameGroup = name + "#" + group;
+        Counter counter = counterMap.get(nameGroup);
+        if (counter == null) {
+            synchronized (BenchmarkCounters.class) {
+                counter = counterMap.get(nameGroup);
+                if (counter == null) {
+                    counter = new Counter(counterMap.size(), group, new AtomicLong());
+                    counterMap.put(nameGroup, counter);
+                }
+            }
+        }
+        assert counter.group.equals(group) : "mismatching groups: " + counter.group + " vs. " + group;
+        int countersSize = config.jvmciCountersSize;
+        if (counter.index >= countersSize) {
+            throw new GraalError("too many counters, reduce number of counters or increase -XX:JVMCICounterSize=... (current value: " + countersSize + ")");
+        }
+        return counter;
+    }
+
+    private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
+        if (!counterMap.isEmpty()) {
+            if (Options.DynamicCountersHumanReadable.getValue()) {
+                out.println("====== dynamic counters (" + counterMap.size() + " in total) ======");
+            }
+            TreeSet<String> set = new TreeSet<>();
+            counterMap.forEach((nameGroup, counter) -> set.add(counter.group));
+            for (String group : set) {
+                if (group != null) {
+                    if (Options.BenchmarkCountersDumpStatic.getValue()) {
+                        dumpCounters(out, seconds, counters, true, group, maxRows);
+                    }
+                    if (Options.BenchmarkCountersDumpDynamic.getValue()) {
+                        dumpCounters(out, seconds, counters, false, group, maxRows);
+                    }
+                }
+            }
+            if (Options.DynamicCountersHumanReadable.getValue()) {
+                out.println("============================");
+            }
+
+            clear(counters);
+        }
+    }
+
+    private static synchronized void clear(long[] counters) {
+        delta = counters;
+    }
+
+    private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group, int maxRows) {
+
+        // collect the numbers
+        long[] array;
+        if (staticCounter) {
+            array = new long[counterMap.size()];
+            for (Counter counter : counterMap.values()) {
+                array[counter.index] = counter.staticCounters.get();
+            }
+        } else {
+            array = counters.clone();
+            for (int i = 0; i < array.length; i++) {
+                array[i] -= delta[i];
+            }
+        }
+        Set<Entry<String, Counter>> counterEntrySet = counterMap.entrySet();
+        if (Options.DynamicCountersHumanReadable.getValue()) {
+            dumpHumanReadable(out, seconds, staticCounter, group, maxRows, array, counterEntrySet);
+        } else {
+            dumpComputerReadable(out, staticCounter, group, array, counterEntrySet);
+        }
+    }
+
+    private static String getName(String nameGroup, String group) {
+        return nameGroup.substring(0, nameGroup.length() - group.length() - 1);
+    }
+
+    private static void dumpHumanReadable(PrintStream out, double seconds, boolean staticCounter, String group, int maxRows, long[] array, Set<Entry<String, Counter>> counterEntrySet) {
+        // sort the counters by putting them into a sorted map
+        TreeMap<Long, String> sorted = new TreeMap<>();
+        long sum = 0;
+        for (Map.Entry<String, Counter> entry : counterEntrySet) {
+            Counter counter = entry.getValue();
+            int index = counter.index;
+            if (counter.group.equals(group)) {
+                sum += array[index];
+                sorted.put(array[index] * array.length + index, getName(entry.getKey(), group));
+            }
+        }
+
+        if (sum > 0) {
+            long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100);
+            int cnt = sorted.size();
+
+            // remove everything below cutoff and keep at most maxRows
+            Iterator<Map.Entry<Long, String>> iter = sorted.entrySet().iterator();
+            while (iter.hasNext()) {
+                Map.Entry<Long, String> entry = iter.next();
+                long counter = entry.getKey() / array.length;
+                if (counter < cutoff || cnt > maxRows) {
+                    iter.remove();
+                }
+                cnt--;
+            }
+
+            String numFmt = Options.DynamicCountersPrintGroupSeparator.getValue() ? "%,19d" : "%19d";
+            if (staticCounter) {
+                out.println("=========== " + group + " (static counters):");
+                for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                    long counter = entry.getKey() / array.length;
+                    out.format(Locale.US, numFmt + " %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
+                }
+                out.format(Locale.US, numFmt + " total\n", sum);
+            } else {
+                if (group.startsWith("~")) {
+                    out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:");
+                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                        long counter = entry.getKey() / array.length;
+                        out.format(Locale.US, numFmt + "/s %3d%%  %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue());
+                    }
+                    out.format(Locale.US, numFmt + "/s total\n", (long) (sum / seconds));
+                } else {
+                    out.println("=========== " + group + " (dynamic counters):");
+                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                        long counter = entry.getKey() / array.length;
+                        out.format(Locale.US, numFmt + " %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
+                    }
+                    out.format(Locale.US, numFmt + " total\n", sum);
+                }
+            }
+        }
+    }
+
+    private static final String CSV_FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%d");
+
+    private static void dumpComputerReadable(PrintStream out, boolean staticCounter, String group, long[] array, Set<Entry<String, Counter>> counterEntrySet) {
+        String category = staticCounter ? "static counters" : "dynamic counters";
+        for (Map.Entry<String, Counter> entry : counterEntrySet) {
+            Counter counter = entry.getValue();
+            if (counter.group.equals(group)) {
+                String name = getName(entry.getKey(), group);
+                int index = counter.index;
+                long value = array[index];
+                CSVUtil.Escape.println(out, CSV_FMT, category, group, name, value);
+            }
+        }
+    }
+
+    private static long percentage(long counter, long sum) {
+        return (counter * 200 + 1) / sum / 2;
+    }
+
+    private abstract static class CallbackOutputStream extends OutputStream {
+
+        protected final PrintStream delegate;
+        private final byte[][] patterns;
+        private final int[] positions;
+
+        CallbackOutputStream(PrintStream delegate, String... patterns) {
+            this.delegate = delegate;
+            this.positions = new int[patterns.length];
+            this.patterns = new byte[patterns.length][];
+            for (int i = 0; i < patterns.length; i++) {
+                this.patterns[i] = patterns[i].getBytes();
+            }
+        }
+
+        protected abstract void patternFound(int index);
+
+        @Override
+        public void write(int b) throws IOException {
+            try {
+                delegate.write(b);
+                for (int i = 0; i < patterns.length; i++) {
+                    int j = positions[i];
+                    byte[] cs = patterns[i];
+                    byte patternChar = cs[j];
+                    if (patternChar == '~' && Character.isDigit(b)) {
+                        // nothing to do...
+                    } else {
+                        if (patternChar == '~') {
+                            patternChar = cs[++positions[i]];
+                        }
+                        if (b == patternChar) {
+                            positions[i]++;
+                        } else {
+                            positions[i] = 0;
+                        }
+                    }
+                    if (positions[i] == patterns[i].length) {
+                        positions[i] = 0;
+                        patternFound(i);
+                    }
+                }
+            } catch (RuntimeException e) {
+                e.printStackTrace(delegate);
+                throw e;
+            }
+        }
+    }
+
+    public static void initialize(final HotSpotJVMCIRuntime jvmciRuntime) {
+        final class BenchmarkCountersOutputStream extends CallbackOutputStream {
+
+            private long startTime;
+            private boolean running;
+            private boolean waitingForEnd;
+
+            private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
+                super(delegate, new String[]{"\n", end, start});
+            }
+
+            @Override
+            protected void patternFound(int index) {
+                switch (index) {
+                    case 2:
+                        startTime = System.nanoTime();
+                        BenchmarkCounters.clear(jvmciRuntime.collectCounters());
+                        running = true;
+                        break;
+                    case 1:
+                        if (running) {
+                            waitingForEnd = true;
+                        }
+                        break;
+                    case 0:
+                        if (waitingForEnd) {
+                            waitingForEnd = false;
+                            running = false;
+                            BenchmarkCounters.dump(getPrintStream(), (System.nanoTime() - startTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+                        }
+                        break;
+                }
+            }
+        }
+
+        if (Options.BenchmarkDynamicCounters.getValue() != null) {
+            String[] arguments = Options.BenchmarkDynamicCounters.getValue().split(",");
+            if (arguments.length == 0 || (arguments.length % 3) != 0) {
+                throw new GraalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)");
+            }
+            for (int i = 0; i < arguments.length; i += 3) {
+                if (arguments[i].equals("err")) {
+                    System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2])));
+                } else if (arguments[i].equals("out")) {
+                    System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2])));
+                } else {
+                    throw new GraalError("invalid arguments to BenchmarkDynamicCounters: err|out");
+                }
+            }
+            enabled = true;
+        }
+        if (Options.GenericDynamicCounters.getValue()) {
+            enabled = true;
+        }
+        if (Options.TimedDynamicCounters.getValue() > 0) {
+            Thread thread = new Thread() {
+                long lastTime = System.nanoTime();
+                PrintStream out = getPrintStream();
+
+                @Override
+                public void run() {
+                    while (true) {
+                        try {
+                            Thread.sleep(Options.TimedDynamicCounters.getValue());
+                        } catch (InterruptedException e) {
+                        }
+                        long time = System.nanoTime();
+                        dump(out, (time - lastTime) / 1000000000d, jvmciRuntime.collectCounters(), 10);
+                        lastTime = time;
+                    }
+                }
+            };
+            thread.setDaemon(true);
+            thread.setPriority(Thread.MAX_PRIORITY);
+            thread.start();
+            enabled = true;
+        }
+        if (enabled) {
+            clear(jvmciRuntime.collectCounters());
+        }
+    }
+
+    public static void shutdown(HotSpotJVMCIRuntime jvmciRuntime, long compilerStartTime) {
+        if (Options.GenericDynamicCounters.getValue()) {
+            dump(getPrintStream(), (System.nanoTime() - compilerStartTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+        }
+    }
+
+    private static PrintStream getPrintStream() {
+        if (Options.BenchmarkCountersFile.getValue() != null) {
+            try {
+                Path path = UniquePathUtilities.getPathGlobal(Options.BenchmarkCountersFile, GraalDebugConfig.Options.DumpPath, "csv");
+                TTY.println("Writing benchmark counters to '%s'", path);
+                return new PrintStream(path.toFile());
+            } catch (FileNotFoundException e) {
+                TTY.out().println(e.getMessage());
+                TTY.out().println("Fallback to default");
+            }
+        }
+        return TTY.out;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/HotSpotZapRegistersPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/HotSpotZapRegistersPhase.java
new file mode 100644
index 0000000..3909545
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/HotSpotZapRegistersPhase.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.lir;
+
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapRegistersAfterInstruction;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapStackArgumentSpaceBeforeInstruction;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Inserts a {@link DiagnosticLIRGeneratorTool#createZapRegisters ZapRegistersOp} after
+ * {@link ZapRegistersAfterInstruction} for stubs and
+ * {@link DiagnosticLIRGeneratorTool#zapArgumentSpace ZapArgumentSpaceOp} after
+ * {@link ZapStackArgumentSpaceBeforeInstruction} for all compiles.
+ */
+public final class HotSpotZapRegistersPhase extends PostAllocationOptimizationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        Stub stub = ((HotSpotLIRGenerationResult) lirGenRes).getStub();
+        boolean zapRegisters = stub != null && !stub.preservesRegisters();
+        boolean zapStack = false;
+        for (AllocatableValue arg : lirGenRes.getCallingConvention().getArguments()) {
+            if (isStackSlot(arg)) {
+                zapStack = true;
+                break;
+            }
+        }
+        if (zapRegisters || zapStack) {
+            LIR lir = lirGenRes.getLIR();
+            processLIR(context.diagnosticLirGenTool, (HotSpotLIRGenerationResult) lirGenRes, lir, zapRegisters, zapStack);
+        }
+    }
+
+    private static void processLIR(DiagnosticLIRGeneratorTool diagnosticLirGenTool, HotSpotLIRGenerationResult res, LIR lir, boolean zapRegisters, boolean zapStack) {
+        LIRInsertionBuffer buffer = new LIRInsertionBuffer();
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block != null) {
+                processBlock(diagnosticLirGenTool, res, lir, buffer, block, zapRegisters, zapStack);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private static void processBlock(DiagnosticLIRGeneratorTool diagnosticLirGenTool, HotSpotLIRGenerationResult res, LIR lir, LIRInsertionBuffer buffer, AbstractBlockBase<?> block,
+                    boolean zapRegisters, boolean zapStack) {
+        try (Indent indent = Debug.logAndIndent("Process block %s", block)) {
+            ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            buffer.init(instructions);
+            for (int index = 0; index < instructions.size(); index++) {
+                LIRInstruction inst = instructions.get(index);
+                if (zapStack && inst instanceof ZapStackArgumentSpaceBeforeInstruction) {
+                    LIRInstruction zap = diagnosticLirGenTool.zapArgumentSpace();
+                    if (zap != null) {
+                        buffer.append(index, zap);
+                    }
+                }
+                if (zapRegisters && inst instanceof ZapRegistersAfterInstruction) {
+                    LIRFrameState state = getLIRState(inst);
+                    if (state != null) {
+                        SaveRegistersOp zap = diagnosticLirGenTool.createZapRegisters();
+                        SaveRegistersOp old = res.getCalleeSaveInfo().put(state, zap);
+                        assert old == null : "Already another SaveRegisterOp registered! " + old;
+                        buffer.append(index + 1, (LIRInstruction) zap);
+                        Debug.log("Insert ZapRegister after %s", inst);
+                    }
+                }
+            }
+            buffer.finish();
+        }
+    }
+
+    /**
+     * Returns the {@link LIRFrameState} of an instruction.
+     */
+    private static LIRFrameState getLIRState(LIRInstruction inst) {
+        final LIRFrameState[] lirState = {null};
+        inst.forEachState(state -> {
+            assert lirState[0] == null : "Multiple states: " + inst;
+            lirState[0] = state;
+        });
+        assert lirState[0] != null : "No state: " + inst;
+        return lirState[0];
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
new file mode 100644
index 0000000..47ed91d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
+import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.INIT_LOCATION;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import java.lang.ref.Reference;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode;
+import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.hotspot.replacements.AssertionSnippets;
+import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
+import org.graalvm.compiler.hotspot.replacements.HashCodeSnippets;
+import org.graalvm.compiler.hotspot.replacements.HubGetClassNode;
+import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
+import org.graalvm.compiler.hotspot.replacements.InstanceOfSnippets;
+import org.graalvm.compiler.hotspot.replacements.KlassLayoutHelperNode;
+import org.graalvm.compiler.hotspot.replacements.LoadExceptionObjectSnippets;
+import org.graalvm.compiler.hotspot.replacements.MonitorSnippets;
+import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets;
+import org.graalvm.compiler.hotspot.replacements.StringToBytesSnippets;
+import org.graalvm.compiler.hotspot.replacements.UnsafeLoadSnippets;
+import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
+import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySlowPathNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyUnrollNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopySnippets;
+import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoweredCallTargetNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.calc.RemNode;
+import org.graalvm.compiler.nodes.debug.StringToBytesNode;
+import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GetClassNode;
+import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.LoadMethodNode;
+import org.graalvm.compiler.nodes.extended.OSRLocalNode;
+import org.graalvm.compiler.nodes.extended.OSRStartNode;
+import org.graalvm.compiler.nodes.extended.StoreHubNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
+import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
+import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.replacements.DefaultJavaLoweringProvider;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider {
+
+    protected final HotSpotGraalRuntimeProvider runtime;
+    protected final HotSpotRegistersProvider registers;
+    protected final HotSpotConstantReflectionProvider constantReflection;
+
+    protected InstanceOfSnippets.Templates instanceofSnippets;
+    protected NewObjectSnippets.Templates newObjectSnippets;
+    protected MonitorSnippets.Templates monitorSnippets;
+    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
+    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+    protected AssertionSnippets.Templates assertionSnippets;
+    protected ArrayCopySnippets.Templates arraycopySnippets;
+    protected StringToBytesSnippets.Templates stringToBytesSnippets;
+    protected HashCodeSnippets.Templates hashCodeSnippets;
+    protected ResolveConstantSnippets.Templates resolveConstantSnippets;
+    protected ProfileSnippets.Templates profileSnippets;
+
+    public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        super(metaAccess, foreignCalls, target);
+        this.runtime = runtime;
+        this.registers = registers;
+        this.constantReflection = constantReflection;
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config) {
+        super.initialize(providers, providers.getSnippetReflection());
+
+        assert target == providers.getCodeCache().getTarget();
+        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(providers, target, config);
+        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
+        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        assertionSnippets = new AssertionSnippets.Templates(providers, target);
+        arraycopySnippets = new ArrayCopySnippets.Templates(providers, target);
+        stringToBytesSnippets = new StringToBytesSnippets.Templates(providers, target);
+        hashCodeSnippets = new HashCodeSnippets.Templates(providers, target);
+        if (GeneratePIC.getValue()) {
+            resolveConstantSnippets = new ResolveConstantSnippets.Templates(providers, target);
+            profileSnippets = new ProfileSnippets.Templates(providers, target);
+        }
+        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) n.graph();
+        if (n instanceof Invoke) {
+            lowerInvoke((Invoke) n, tool, graph);
+        } else if (n instanceof LoadMethodNode) {
+            lowerLoadMethodNode((LoadMethodNode) n);
+        } else if (n instanceof GetClassNode) {
+            lowerGetClassNode((GetClassNode) n, tool, graph);
+        } else if (n instanceof StoreHubNode) {
+            lowerStoreHubNode((StoreHubNode) n, graph);
+        } else if (n instanceof OSRStartNode) {
+            lowerOSRStartNode((OSRStartNode) n);
+        } else if (n instanceof BytecodeExceptionNode) {
+            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
+        } else if (n instanceof InstanceOfNode) {
+            InstanceOfNode instanceOfNode = (InstanceOfNode) n;
+            if (graph.getGuardsStage().areDeoptsFixed()) {
+                instanceofSnippets.lower(instanceOfNode, tool);
+            } else {
+                if (instanceOfNode.allowsNull()) {
+                    ValueNode object = instanceOfNode.getValue();
+                    LogicNode newTypeCheck = graph.addOrUniqueWithInputs(InstanceOfNode.create(instanceOfNode.type(), object, instanceOfNode.profile(), instanceOfNode.getAnchor()));
+                    LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
+                    instanceOfNode.replaceAndDelete(newNode);
+                }
+            }
+        } else if (n instanceof InstanceOfDynamicNode) {
+            InstanceOfDynamicNode instanceOfDynamicNode = (InstanceOfDynamicNode) n;
+            if (graph.getGuardsStage().areDeoptsFixed()) {
+                instanceofSnippets.lower(instanceOfDynamicNode, tool);
+            } else {
+                ValueNode mirror = instanceOfDynamicNode.getMirrorOrHub();
+                if (mirror.stamp().getStackKind() == JavaKind.Object) {
+                    ClassGetHubNode classGetHub = graph.unique(new ClassGetHubNode(mirror));
+                    instanceOfDynamicNode.setMirror(classGetHub);
+                }
+
+                if (instanceOfDynamicNode.allowsNull()) {
+                    ValueNode object = instanceOfDynamicNode.getObject();
+                    LogicNode newTypeCheck = graph.addOrUniqueWithInputs(
+                                    InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), instanceOfDynamicNode.getMirrorOrHub(), object, false));
+                    LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
+                    instanceOfDynamicNode.replaceAndDelete(newNode);
+                }
+            }
+        } else if (n instanceof ClassIsAssignableFromNode) {
+            if (graph.getGuardsStage().areDeoptsFixed()) {
+                instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewInstanceNode) {
+            DynamicNewInstanceNode newInstanceNode = (DynamicNewInstanceNode) n;
+            if (newInstanceNode.getClassClass() == null) {
+                JavaConstant classClassMirror = constantReflection.forObject(Class.class);
+                ConstantNode classClass = ConstantNode.forConstant(classClassMirror, tool.getMetaAccess(), graph);
+                newInstanceNode.setClassClass(classClass);
+            }
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower(newInstanceNode, registers, tool);
+            }
+        } else if (n instanceof NewArrayNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewArrayNode) {
+            DynamicNewArrayNode dynamicNewArrayNode = (DynamicNewArrayNode) n;
+            if (dynamicNewArrayNode.getVoidClass() == null) {
+                JavaConstant voidClassMirror = constantReflection.forObject(void.class);
+                ConstantNode voidClass = ConstantNode.forConstant(voidClassMirror, tool.getMetaAccess(), graph);
+                dynamicNewArrayNode.setVoidClass(voidClass);
+            }
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower(dynamicNewArrayNode, registers, tool);
+            }
+        } else if (n instanceof VerifyHeapNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower((VerifyHeapNode) n, registers, tool);
+            }
+        } else if (n instanceof RawMonitorEnterNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                monitorSnippets.lower((RawMonitorEnterNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
+        } else if (n instanceof ArrayCopyNode) {
+            arraycopySnippets.lower((ArrayCopyNode) n, tool);
+        } else if (n instanceof ArrayCopySlowPathNode) {
+            arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool);
+        } else if (n instanceof ArrayCopyUnrollNode) {
+            arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool);
+        } else if (n instanceof G1PreWriteBarrier) {
+            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1PostWriteBarrier) {
+            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ReferentFieldReadBarrier) {
+            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+        } else if (n instanceof SerialWriteBarrier) {
+            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+        } else if (n instanceof SerialArrayRangeWriteBarrier) {
+            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            }
+        } else if (n instanceof LoadExceptionObjectNode) {
+            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+        } else if (n instanceof AssertionNode) {
+            assertionSnippets.lower((AssertionNode) n, tool);
+        } else if (n instanceof StringToBytesNode) {
+            if (graph.getGuardsStage().areDeoptsFixed()) {
+                stringToBytesSnippets.lower((StringToBytesNode) n, tool);
+            }
+        } else if (n instanceof IntegerDivRemNode) {
+            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
+            // zero and the MIN_VALUE / -1 cases.
+        } else if (n instanceof AbstractDeoptimizeNode || n instanceof UnwindNode || n instanceof RemNode || n instanceof SafepointNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
+        } else if (n instanceof ClassGetHubNode) {
+            lowerClassGetHubNode((ClassGetHubNode) n, tool);
+        } else if (n instanceof HubGetClassNode) {
+            lowerHubGetClassNode((HubGetClassNode) n, tool);
+        } else if (n instanceof KlassLayoutHelperNode) {
+            lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool);
+        } else if (n instanceof ComputeObjectAddressNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                lowerComputeObjectAddressNode((ComputeObjectAddressNode) n);
+            }
+        } else if (n instanceof IdentityHashCodeNode) {
+            hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
+        } else if (n instanceof ResolveConstantNode) {
+            resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
+        } else if (n instanceof ResolveMethodAndLoadCountersNode) {
+            resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool);
+        } else if (n instanceof InitializeKlassNode) {
+            resolveConstantSnippets.lower((InitializeKlassNode) n, tool);
+        } else if (n instanceof ProfileNode) {
+            profileSnippets.lower((ProfileNode) n, tool);
+        } else {
+            super.lower(n, tool);
+        }
+    }
+
+    private static void lowerComputeObjectAddressNode(ComputeObjectAddressNode n) {
+        /*
+         * Lower the node into a ComputeObjectAddress node and an Add but ensure that it's below any
+         * potential safepoints and above it's uses.
+         */
+        for (Node use : n.usages().snapshot()) {
+            if (use instanceof FixedNode) {
+                FixedNode fixed = (FixedNode) use;
+                StructuredGraph graph = n.graph();
+                GetObjectAddressNode address = graph.add(new GetObjectAddressNode(n.getObject()));
+                graph.addBeforeFixed(fixed, address);
+                AddNode add = graph.addOrUnique(new AddNode(address, n.getOffset()));
+                use.replaceFirstInput(n, add);
+            } else {
+                throw GraalError.shouldNotReachHere("Unexpected floating use of ComputeObjectAddressNode " + n);
+            }
+        }
+        GraphUtil.unlinkFixedNode(n);
+        n.safeDelete();
+    }
+
+    private void lowerKlassLayoutHelperNode(KlassLayoutHelperNode n, LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+        StructuredGraph graph = n.graph();
+        assert !n.getHub().isConstant();
+        AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().klassLayoutHelperOffset);
+        n.replaceAtUsagesAndDelete(graph.unique(new FloatingReadNode(address, KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)));
+    }
+
+    private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+
+        StructuredGraph graph = n.graph();
+        assert !n.getHub().isConstant();
+        AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().classMirrorOffset);
+        FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
+        n.replaceAtUsagesAndDelete(read);
+    }
+
+    private void lowerClassGetHubNode(ClassGetHubNode n, LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+
+        StructuredGraph graph = n.graph();
+        assert !n.getValue().isConstant();
+        AddressNode address = createOffsetAddress(graph, n.getValue(), runtime.getVMConfig().klassOffset);
+        FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_KLASS_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
+        n.replaceAtUsagesAndDelete(read);
+    }
+
+    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+            NodeInputList<ValueNode> parameters = callTarget.arguments();
+            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) {
+                GuardingNode receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                PiNode nonNullReceiver = graph.unique(new PiNode(receiver, ((ObjectStamp) receiver.stamp()).join(StampFactory.objectNonNull()), (ValueNode) receiverNullCheck));
+                parameters.set(0, nonNullReceiver);
+                receiver = nonNullReceiver;
+            }
+            JavaType[] signature = callTarget.targetMethod().getSignature().toParameterTypes(callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+            LoweredCallTargetNode loweredCallTarget = null;
+            if (InlineVTableStubs.getValue() && callTarget.invokeKind().isIndirect() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                ResolvedJavaType receiverType = invoke.getReceiverType();
+                if (hsMethod.isInVirtualMethodTable(receiverType)) {
+                    JavaKind wordKind = runtime.getTarget().wordJavaKind;
+                    ValueNode hub = createReadHub(graph, receiver, tool);
+
+                    ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType);
+                    // We use LocationNode.ANY_LOCATION for the reads that access the
+                    // compiled code entry as HotSpot does not guarantee they are final
+                    // values.
+                    int methodCompiledEntryOffset = runtime.getVMConfig().methodCompiledEntryOffset;
+                    AddressNode address = createOffsetAddress(graph, metaspaceMethod, methodCompiledEntryOffset);
+                    ReadNode compiledEntry = graph.add(new ReadNode(address, any(), StampFactory.forKind(wordKind), BarrierType.NONE));
+
+                    loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(),
+                                    signature, callTarget.targetMethod(),
+                                    HotSpotCallingConventionType.JavaCall, callTarget.invokeKind()));
+
+                    graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                    graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                }
+            }
+
+            if (loweredCallTarget == null) {
+                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(),
+                                signature, callTarget.targetMethod(),
+                                HotSpotCallingConventionType.JavaCall,
+                                callTarget.invokeKind()));
+            }
+            callTarget.replaceAndDelete(loweredCallTarget);
+        }
+    }
+
+    @Override
+    protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
+        if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
+            return NarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding());
+        }
+        return super.loadStamp(stamp, kind, compressible);
+    }
+
+    @Override
+    protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
+        if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
+            return new CompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding());
+        }
+        return super.implicitLoadConvert(kind, value, compressible);
+    }
+
+    @Override
+    public ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) {
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
+        JavaConstant base = constantReflection.asJavaClass(field.getDeclaringClass());
+        return ConstantNode.forConstant(base, metaAccess, graph);
+    }
+
+    @Override
+    protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
+        if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
+            return new CompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding());
+        }
+        return super.implicitStoreConvert(kind, value, compressible);
+    }
+
+    @Override
+    protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) {
+        /*
+         * Anchor the read of the element klass to the cfg, because it is only valid when arrayClass
+         * is an object class, which might not be the case in other parts of the compiled method.
+         */
+        AddressNode address = createOffsetAddress(graph, arrayHub, runtime.getVMConfig().arrayClassElementOffset);
+        return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), AbstractBeginNode.prevBegin(anchor)));
+    }
+
+    @Override
+    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (!(load instanceof GuardedUnsafeLoadNode) && !graph.getGuardsStage().allowsFloatingGuards() && addReadBarrier(load)) {
+            unsafeLoadSnippets.lower(load, tool);
+        } else {
+            super.lowerUnsafeLoadNode(load, tool);
+        }
+    }
+
+    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
+        StructuredGraph graph = loadMethodNode.graph();
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType());
+        graph.replaceFixed(loadMethodNode, metaspaceMethod);
+    }
+
+    private static void lowerGetClassNode(GetClassNode getClass, LoweringTool tool, StructuredGraph graph) {
+        StampProvider stampProvider = tool.getStampProvider();
+        LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, getClass.getObject()));
+        HubGetClassNode hubGetClass = graph.unique(new HubGetClassNode(tool.getMetaAccess(), hub));
+        getClass.replaceAtUsagesAndDelete(hubGetClass);
+        hub.lower(tool);
+        hubGetClass.lower(tool);
+    }
+
+    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
+        WriteNode hub = createWriteHub(graph, storeHub.getObject(), storeHub.getValue());
+        graph.replaceFixed(storeHub, hub);
+    }
+
+    @Override
+    public BarrierType fieldInitializationBarrier(JavaKind entryKind) {
+        return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.IMPRECISE : BarrierType.NONE;
+    }
+
+    @Override
+    public BarrierType arrayInitializationBarrier(JavaKind entryKind) {
+        return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.PRECISE : BarrierType.NONE;
+    }
+
+    private void lowerOSRStartNode(OSRStartNode osrStart) {
+        StructuredGraph graph = osrStart.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            StartNode newStart = graph.add(new StartNode());
+            ParameterNode buffer = graph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(StampFactory.forKind(runtime.getTarget().wordJavaKind))));
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) {
+                int size = osrLocal.getStackKind().getSlotCount();
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                AddressNode address = createOffsetAddress(graph, buffer, offset);
+                ReadNode load = graph.add(new ReadNode(address, any(), osrLocal.stamp(), BarrierType.NONE));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsagesAndDelete(newStart);
+        }
+    }
+
+    static final class Exceptions {
+        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
+        protected static final NullPointerException cachedNullPointerException;
+
+        static {
+            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
+            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
+            cachedNullPointerException = new NullPointerException();
+            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
+        }
+    }
+
+    public static final class RuntimeCalls {
+        public static final ForeignCallDescriptor CREATE_ARRAY_STORE_EXCEPTION = new ForeignCallDescriptor("createArrayStoreException", ArrayStoreException.class, Object.class);
+        public static final ForeignCallDescriptor CREATE_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("createClassCastException", ClassCastException.class, Object.class, KlassPointer.class);
+        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
+        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
+    }
+
+    private boolean throwCachedException(BytecodeExceptionNode node) {
+        Throwable exception;
+        if (node.getExceptionClass() == NullPointerException.class) {
+            exception = Exceptions.cachedNullPointerException;
+        } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+            exception = Exceptions.cachedArrayIndexOutOfBoundsException;
+        } else {
+            return false;
+        }
+
+        StructuredGraph graph = node.graph();
+        FloatingNode exceptionNode = ConstantNode.forConstant(constantReflection.forObject(exception), metaAccess, graph);
+        graph.replaceFixedWithFloating(node, exceptionNode);
+        return true;
+    }
+
+    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
+        if (OmitHotExceptionStacktrace.getValue()) {
+            if (throwCachedException(node)) {
+                return;
+            }
+        }
+
+        ForeignCallDescriptor descriptor;
+        if (node.getExceptionClass() == NullPointerException.class) {
+            descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
+        } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+            descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
+        } else if (node.getExceptionClass() == ArrayStoreException.class) {
+            descriptor = RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION;
+        } else if (node.getExceptionClass() == ClassCastException.class) {
+            descriptor = RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION;
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+
+        StructuredGraph graph = node.graph();
+        ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
+        graph.replaceFixedWithFixed(node, foreignCallNode);
+    }
+
+    private boolean addReadBarrier(UnsafeLoadNode load) {
+        if (runtime.getVMConfig().useG1GC && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getStackKind() == JavaKind.Object &&
+                        load.accessKind() == JavaKind.Object && !StampTool.isPointerAlwaysNull(load.object())) {
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && !type.isArray()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
+        return createReadVirtualMethod(graph, hub, method.vtableEntryOffset(receiverType));
+    }
+
+    private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, int vtableEntryOffset) {
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        Stamp methodStamp = MethodPointerStamp.method();
+        AddressNode address = createOffsetAddress(graph, hub, vtableEntryOffset);
+        ReadNode metaspaceMethod = graph.add(new ReadNode(address, any(), methodStamp, BarrierType.NONE));
+        return metaspaceMethod;
+    }
+
+    @Override
+    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool) {
+        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
+            return graph.unique(new LoadHubNode(tool.getStampProvider(), object));
+        }
+        assert !object.isConstant() || object.isNullConstant();
+
+        KlassPointerStamp hubStamp = KlassPointerStamp.klassNonNull();
+        if (runtime.getVMConfig().useCompressedClassPointers) {
+            hubStamp = hubStamp.compressed(runtime.getVMConfig().getKlassEncoding());
+        }
+
+        AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset);
+        LocationIdentity hubLocation = runtime.getVMConfig().useCompressedClassPointers ? COMPRESSED_HUB_LOCATION : HUB_LOCATION;
+        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE));
+        if (runtime.getVMConfig().useCompressedClassPointers) {
+            return CompressionNode.uncompress(memoryRead, runtime.getVMConfig().getKlassEncoding());
+        } else {
+            return memoryRead;
+        }
+    }
+
+    private WriteNode createWriteHub(StructuredGraph graph, ValueNode object, ValueNode value) {
+        assert !object.isConstant() || object.asConstant().isDefaultForKind();
+
+        ValueNode writeValue = value;
+        if (runtime.getVMConfig().useCompressedClassPointers) {
+            writeValue = CompressionNode.compress(value, runtime.getVMConfig().getKlassEncoding());
+        }
+
+        AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset);
+        return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE));
+    }
+
+    @Override
+    protected BarrierType fieldLoadBarrierType(ResolvedJavaField f) {
+        HotSpotResolvedJavaField loadField = (HotSpotResolvedJavaField) f;
+        BarrierType barrierType = BarrierType.NONE;
+        if (runtime.getVMConfig().useG1GC && loadField.getJavaKind() == JavaKind.Object && metaAccess.lookupJavaType(Reference.class).equals(loadField.getDeclaringClass()) &&
+                        loadField.getName().equals("referent")) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    @Override
+    public int fieldOffset(ResolvedJavaField f) {
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
+        return field.offset();
+    }
+
+    @Override
+    public int arrayScalingFactor(JavaKind kind) {
+        if (runtime.getVMConfig().useCompressedOops && kind == JavaKind.Object) {
+            return super.arrayScalingFactor(JavaKind.Int);
+        } else {
+            return super.arrayScalingFactor(kind);
+        }
+    }
+
+    @Override
+    public int arrayBaseOffset(JavaKind kind) {
+        return getArrayBaseOffset(kind);
+    }
+
+    @Override
+    public int arrayLengthOffset() {
+        return runtime.getVMConfig().arrayOopDescLengthOffset();
+    }
+
+    @Override
+    public LocationIdentity initLocationIdentity() {
+        return INIT_LOCATION;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java
new file mode 100644
index 0000000..ec7de3f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.hotspot.FingerprintUtil;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class HotSpotAOTProfilingPlugin extends HotSpotProfilingPlugin {
+    public static class Options {
+        @Option(help = "Do profiling and callbacks to tiered runtime", type = OptionType.User)//
+        public static final OptionValue<Boolean> TieredAOT = new OptionValue<>(false);
+        @Option(help = "Invocation notification frequency", type = OptionType.Expert)//
+        public static final OptionValue<Integer> TierAInvokeNotifyFreqLog = new OptionValue<>(13);
+        @Option(help = "Inlinee invocation notification frequency (-1 means count, but do not notify)", type = OptionType.Expert)//
+        public static final OptionValue<Integer> TierAInvokeInlineeNotifyFreqLog = new OptionValue<>(-1);
+        @Option(help = "Invocation profile probability", type = OptionType.Expert)//
+        public static final OptionValue<Integer> TierAInvokeProfileProbabilityLog = new OptionValue<>(8);
+        @Option(help = "Backedge notification frequency", type = OptionType.Expert)//
+        public static final OptionValue<Integer> TierABackedgeNotifyFreqLog = new OptionValue<>(16);
+        @Option(help = "Backedge profile probability", type = OptionType.Expert)//
+        public static final OptionValue<Integer> TierABackedgeProfileProbabilityLog = new OptionValue<>(12);
+    }
+
+    @Override
+    public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) {
+        return super.shouldProfile(builder, method) && FingerprintUtil.getFingerprint(((HotSpotResolvedObjectType) method.getDeclaringClass())) != 0;
+    }
+
+    @Override
+    public int invokeNotifyFreqLog() {
+        return Options.TierAInvokeNotifyFreqLog.getValue();
+    }
+
+    @Override
+    public int invokeInlineeNotifyFreqLog() {
+        return Options.TierAInvokeInlineeNotifyFreqLog.getValue();
+    }
+
+    @Override
+    public int invokeProfilePobabilityLog() {
+        return Options.TierAInvokeProfileProbabilityLog.getValue();
+    }
+
+    @Override
+    public int backedgeNotifyFreqLog() {
+        return Options.TierABackedgeNotifyFreqLog.getValue();
+    }
+
+    @Override
+    public int backedgeProfilePobabilityLog() {
+        return Options.TierABackedgeProfileProbabilityLog.getValue();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java
new file mode 100644
index 0000000..fa71a6a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin {
+    @Override
+    public boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type) {
+        if (!builder.parsingIntrinsic()) {
+            ResolvedJavaMethod method = builder.getGraph().method();
+            ResolvedJavaType methodHolder = method.getDeclaringClass();
+            // We can elide initialization nodes if type >=: methodHolder.
+            // The type is already initialized by either "new" or "invokestatic".
+
+            // Emit initialization node if type is an interface since:
+            // JLS 12.4: Before a class is initialized, its direct superclass must be initialized,
+            // but interfaces implemented by the class are not initialized.
+            // and a class or interface type T will be initialized immediately
+            // before the first occurrence of accesses listed in JLS 12.4.1.
+
+            return !type.isAssignableFrom(methodHolder) || type.isInterface();
+        }
+        return false;
+    }
+
+    @Override
+    public ValueNode apply(GraphBuilderContext builder, ResolvedJavaType type, FrameState frameState) {
+        assert shouldApply(builder, type);
+        Stamp hubStamp = builder.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
+        ConstantNode hub = builder.append(ConstantNode.forConstant(hubStamp, ((HotSpotResolvedObjectType) type).klass(), builder.getMetaAccess(), builder.getGraph()));
+        InitializeKlassNode initialize = builder.append(new InitializeKlassNode(hub));
+        initialize.setStateBefore(frameState);
+        return initialize;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantFieldProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantFieldProvider.java
new file mode 100644
index 0000000..f7f99c6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantFieldProvider.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.core.common.spi.JavaConstantFieldProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Implements the default constant folding semantics for Java fields in the HotSpot VM.
+ */
+public class HotSpotConstantFieldProvider extends JavaConstantFieldProvider {
+
+    private final GraalHotSpotVMConfig config;
+
+    public HotSpotConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        super(metaAccess);
+        this.config = config;
+    }
+
+    @Override
+    protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool<?> tool) {
+        if (!config.foldStableValues) {
+            return false;
+        }
+        if (field.isStatic() && !isStaticFieldConstant(field)) {
+            return false;
+        }
+
+        if (((HotSpotResolvedJavaField) field).isStable()) {
+            return true;
+        }
+        return super.isStableField(field, tool);
+    }
+
+    @Override
+    protected boolean isFinalField(ResolvedJavaField field, ConstantFieldTool<?> tool) {
+        if (field.isStatic() && !isStaticFieldConstant(field)) {
+            return false;
+        }
+
+        return super.isFinalField(field, tool);
+    }
+
+    private static final String SystemClassName = "Ljava/lang/System;";
+
+    protected boolean isStaticFieldConstant(ResolvedJavaField field) {
+        ResolvedJavaType declaringClass = field.getDeclaringClass();
+        return declaringClass.isInitialized() && !declaringClass.getName().equals(SystemClassName);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantLoadAction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantLoadAction.java
new file mode 100644
index 0000000..f2c608b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotConstantLoadAction.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+public enum HotSpotConstantLoadAction {
+    RESOLVE(0),
+    INITIALIZE(1),
+    MAKE_NOT_ENTRANT(2),
+    LOAD_COUNTERS(3);
+
+    private int value;
+
+    HotSpotConstantLoadAction(int value) {
+        this.value = value;
+    }
+
+    public int value() {
+        return value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotDisassemblerProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotDisassemblerProvider.java
new file mode 100644
index 0000000..6a9c03a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotDisassemblerProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+
+/**
+ * HotSpot implementation of {@link DisassemblerProvider}.
+ */
+@ServiceProvider(DisassemblerProvider.class)
+public class HotSpotDisassemblerProvider implements DisassemblerProvider {
+
+    @Override
+    public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) {
+        return null;
+    }
+
+    @Override
+    public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode code) {
+        return ((HotSpotCodeCacheProvider) codeCache).disassemble(code);
+    }
+
+    @Override
+    public String getName() {
+        return "hsdis";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProvider.java
new file mode 100644
index 0000000..76b663c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * HotSpot extension of {@link ForeignCallsProvider}.
+ */
+public interface HotSpotForeignCallsProvider extends ForeignCallsProvider {
+
+    /**
+     * Gets the registers that must be saved across a foreign call into the runtime.
+     */
+    Value[] getNativeABICallerSaveRegisters();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
new file mode 100644
index 0000000..f2ddb96
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.stubs.ForeignCallStub;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * HotSpot implementation of {@link HotSpotForeignCallsProvider}.
+ */
+public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignCallsProvider {
+
+    public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class);
+    public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class);
+    public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class);
+    public static final ForeignCallDescriptor LOAD_AND_CLEAR_EXCEPTION = new ForeignCallDescriptor("load_and_clear_exception", Object.class, Word.class);
+
+    public static final ForeignCallDescriptor TEST_DEOPTIMIZE_CALL_INT = new ForeignCallDescriptor("test_deoptimize_call_int", int.class, int.class);
+
+    protected final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+    protected final HotSpotGraalRuntimeProvider runtime;
+
+    protected final Map<ForeignCallDescriptor, HotSpotForeignCallLinkage> foreignCalls = new HashMap<>();
+    protected final MetaAccessProvider metaAccess;
+    protected final CodeCacheProvider codeCache;
+    protected final WordTypes wordTypes;
+
+    public HotSpotForeignCallsProviderImpl(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    WordTypes wordTypes) {
+        this.jvmciRuntime = jvmciRuntime;
+        this.runtime = runtime;
+        this.metaAccess = metaAccess;
+        this.codeCache = codeCache;
+        this.wordTypes = wordTypes;
+    }
+
+    /**
+     * Registers the linkage for a foreign call.
+     */
+    public HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) {
+        assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor();
+        foreignCalls.put(linkage.getDescriptor(), linkage);
+        return linkage;
+    }
+
+    /**
+     * Return true if the descriptor has already been registered.
+     */
+    public boolean isRegistered(ForeignCallDescriptor descriptor) {
+        return foreignCalls.containsKey(descriptor);
+    }
+
+    /**
+     * Creates and registers the details for linking a foreign call to a {@link Stub}.
+     *
+     * @param descriptor the signature of the call to the stub
+     * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side
+     *            effects. Deoptimization will not return to a point before a stub call that cannot
+     *            be re-executed.
+     * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call
+     * @param killedLocations the memory locations killed by the stub call
+     */
+    public HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor, boolean reexecutable, Transition transition, LocationIdentity... killedLocations) {
+        return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable,
+                        killedLocations));
+    }
+
+    /**
+     * Creates and registers the linkage for a foreign call.
+     *
+     * @param descriptor the signature of the foreign call
+     * @param address the address of the code to call
+     * @param outgoingCcType outgoing (caller) calling convention type
+     * @param effect specifies if the call destroys or preserves all registers (apart from
+     *            temporaries which are always destroyed)
+     * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call
+     * @param reexecutable specifies if the foreign call can be re-executed without (meaningful)
+     *            side effects. Deoptimization will not return to a point before a foreign call that
+     *            cannot be re-executed.
+     * @param killedLocations the memory locations killed by the foreign call
+     */
+    public HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type outgoingCcType, RegisterEffect effect, Transition transition,
+                    boolean reexecutable, LocationIdentity... killedLocations) {
+        Class<?> resultType = descriptor.getResultType();
+        assert address != 0;
+        assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor;
+        return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutable, killedLocations));
+    }
+
+    /**
+     * Creates a {@linkplain ForeignCallStub stub} for a foreign call.
+     *
+     * @param descriptor the signature of the call to the stub
+     * @param address the address of the foreign code to call
+     * @param prependThread true if the JavaThread value for the current thread is to be prepended
+     *            to the arguments for the call to {@code address}
+     * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call
+     * @param reexecutable specifies if the foreign call can be re-executed without (meaningful)
+     *            side effects. Deoptimization will not return to a point before a foreign call that
+     *            cannot be re-executed.
+     * @param killedLocations the memory locations killed by the foreign call
+     */
+    public void linkForeignCall(HotSpotProviders providers, ForeignCallDescriptor descriptor, long address, boolean prependThread, Transition transition, boolean reexecutable,
+                    LocationIdentity... killedLocations) {
+        ForeignCallStub stub = new ForeignCallStub(jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutable, killedLocations);
+        HotSpotForeignCallLinkage linkage = stub.getLinkage();
+        HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage();
+        linkage.setCompiledStub(stub);
+        register(linkage);
+        register(targetLinkage);
+    }
+
+    public static final boolean PREPEND_THREAD = true;
+    public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD;
+
+    public static final boolean REEXECUTABLE = true;
+    public static final boolean NOT_REEXECUTABLE = !REEXECUTABLE;
+
+    public static final LocationIdentity[] NO_LOCATIONS = {};
+
+    @Override
+    public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+        assert foreignCalls != null : descriptor;
+        HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor);
+        callTarget.finalizeAddress(runtime.getHostBackend());
+        return callTarget;
+    }
+
+    @Override
+    public boolean isReexecutable(ForeignCallDescriptor descriptor) {
+        assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
+        return foreignCalls.get(descriptor).isReexecutable();
+    }
+
+    @Override
+    public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
+        assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
+        return foreignCalls.get(descriptor).needsDebugInfo();
+    }
+
+    @Override
+    public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) {
+        assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
+        return foreignCalls.get(descriptor).isGuaranteedSafepoint();
+    }
+
+    @Override
+    public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
+        assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
+        return foreignCalls.get(descriptor).getKilledLocations();
+    }
+
+    @Override
+    public LIRKind getValueKind(JavaKind javaKind) {
+        return LIRKind.fromJavaKind(codeCache.getTarget().arch, javaKind);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java
new file mode 100644
index 0000000..659a79e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.ImmutableCodeLazy.isCalledForSnippets;
+import static org.graalvm.compiler.hotspot.stubs.SnippetStub.SnippetGraphUnderConstruction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.options.StableOptionValue;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.runtime.JVMCI;
+
+/**
+ * Extends {@link HotSpotConstantFieldProvider} to override the implementation of
+ * {@link #readConstantField} with Graal specific semantics.
+ */
+public class HotSpotGraalConstantFieldProvider extends HotSpotConstantFieldProvider {
+
+    public HotSpotGraalConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        super(config, metaAccess);
+        this.metaAccess = metaAccess;
+    }
+
+    @Override
+    public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) {
+        assert !ImmutableCode.getValue() || isCalledForSnippets(metaAccess) || SnippetGraphUnderConstruction.get() != null ||
+                        FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : tool.getReceiver();
+        if (!field.isStatic() && field.getName().equals("value")) {
+            if (getStableOptionValueType().isInstance(tool.getReceiver())) {
+                JavaConstant ret = tool.readValue();
+                return tool.foldConstant(ret);
+            }
+        }
+
+        return super.readConstantField(field, tool);
+    }
+
+    /**
+     * In AOT mode, some fields should never be embedded even for snippets/replacements.
+     */
+    @Override
+    protected boolean isStaticFieldConstant(ResolvedJavaField field) {
+        return super.isStaticFieldConstant(field) && (!ImmutableCode.getValue() || ImmutableCodeLazy.isEmbeddable(field));
+    }
+
+    @Override
+    protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
+        if (super.isFinalFieldValueConstant(field, value, tool)) {
+            return true;
+        }
+
+        if (!field.isStatic()) {
+            JavaConstant receiver = tool.getReceiver();
+            if (getSnippetCounterType().isInstance(receiver) || getNodeClassType().isInstance(receiver)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
+        if (super.isStableFieldValueConstant(field, value, tool)) {
+            return true;
+        }
+
+        if (!field.isStatic()) {
+            JavaConstant receiver = tool.getReceiver();
+            if (getHotSpotVMConfigType().isInstance(receiver)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private final MetaAccessProvider metaAccess;
+
+    private ResolvedJavaType cachedStableOptionValueType;
+    private ResolvedJavaType cachedHotSpotVMConfigType;
+    private ResolvedJavaType cachedSnippetCounterType;
+    private ResolvedJavaType cachedNodeClassType;
+
+    private ResolvedJavaType getStableOptionValueType() {
+        if (cachedStableOptionValueType == null) {
+            cachedStableOptionValueType = metaAccess.lookupJavaType(StableOptionValue.class);
+        }
+        return cachedStableOptionValueType;
+    }
+
+    private ResolvedJavaType getHotSpotVMConfigType() {
+        if (cachedHotSpotVMConfigType == null) {
+            cachedHotSpotVMConfigType = metaAccess.lookupJavaType(GraalHotSpotVMConfig.class);
+        }
+        return cachedHotSpotVMConfigType;
+    }
+
+    private ResolvedJavaType getSnippetCounterType() {
+        if (cachedSnippetCounterType == null) {
+            cachedSnippetCounterType = metaAccess.lookupJavaType(SnippetCounter.class);
+        }
+        return cachedSnippetCounterType;
+    }
+
+    private ResolvedJavaType getNodeClassType() {
+        if (cachedNodeClassType == null) {
+            cachedNodeClassType = metaAccess.lookupJavaType(NodeClass.class);
+        }
+        return cachedNodeClassType;
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled;
+    }
+
+    public static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = assertionsEnabled() ? new ThreadLocal<>() : null;
+
+    /**
+     * Compares two {@link StackTraceElement}s for equality, ignoring differences in
+     * {@linkplain StackTraceElement#getLineNumber() line number}.
+     */
+    private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) {
+        return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName());
+    }
+
+    /**
+     * Separate out the static initialization of {@linkplain #isEmbeddable(ResolvedJavaField)
+     * embeddable fields} to eliminate cycles between clinit and other locks that could lead to
+     * deadlock. Static code that doesn't call back into type or field machinery is probably ok but
+     * anything else should be made lazy.
+     */
+    static class ImmutableCodeLazy {
+
+        /**
+         * If the compiler is configured for AOT mode, {@link #readConstantField} should be only
+         * called for snippets or replacements.
+         */
+        static boolean isCalledForSnippets(MetaAccessProvider metaAccess) {
+            assert ImmutableCode.getValue();
+            ResolvedJavaMethod makeGraphMethod = null;
+            ResolvedJavaMethod initMethod = null;
+            try {
+                Class<?> rjm = ResolvedJavaMethod.class;
+                makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm));
+                initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalError(e);
+            }
+            StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0);
+            StackTraceElement initSTE = initMethod.asStackTraceElement(0);
+
+            StackTraceElement[] stackTrace = new Exception().getStackTrace();
+            for (StackTraceElement element : stackTrace) {
+                // Ignoring line numbers should not weaken this check too much while at
+                // the same time making it more robust against source code changes
+                if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Determine if it's ok to embed the value of {@code field}.
+         */
+        static boolean isEmbeddable(ResolvedJavaField field) {
+            assert ImmutableCode.getValue();
+            return !embeddableFields.contains(field);
+        }
+
+        private static final List<ResolvedJavaField> embeddableFields = new ArrayList<>();
+        static {
+            try {
+                MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
+                embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE")));
+                embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE")));
+
+                Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
+                assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName());
+                embeddableFields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache")));
+
+                Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
+                assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName());
+                embeddableFields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache")));
+
+                Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0];
+                assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName());
+                embeddableFields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache")));
+
+                Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0];
+                assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName());
+                embeddableFields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache")));
+
+                Class<?> longCacheClass = Long.class.getDeclaredClasses()[0];
+                assert "java.lang.Long$LongCache".equals(longCacheClass.getName());
+                embeddableFields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache")));
+
+                embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK")));
+                embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL")));
+            } catch (SecurityException | NoSuchFieldException e) {
+                throw new GraalError(e);
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
new file mode 100644
index 0000000..0fc8323
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
+
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
+import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
+
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MutableCallSite;
+import java.lang.invoke.VolatileCallSite;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.math.BigInteger;
+import java.util.zip.CRC32;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.FingerprintUtil;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
+import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
+import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
+import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
+import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
+import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
+import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
+import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
+import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
+import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.DynamicPiNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.StableOptionValue;
+import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
+import org.graalvm.compiler.replacements.InlineGraalDirectivesPlugin;
+import org.graalvm.compiler.replacements.MethodHandlePlugin;
+import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
+import org.graalvm.compiler.replacements.WordOperationPlugin;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Defines the {@link Plugins} used when running on HotSpot.
+ */
+public class HotSpotGraphBuilderPlugins {
+
+    /**
+     * Creates a {@link Plugins} object that should be used when running on HotSpot.
+     *
+     * @param constantReflection
+     * @param snippetReflection
+     * @param foreignCalls
+     * @param stampProvider
+     */
+    public static Plugins create(GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
+                    SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) {
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
+
+        Plugins plugins = new Plugins(invocationPlugins);
+        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
+        HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
+        HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin);
+
+        plugins.appendTypePlugin(nodePlugin);
+        plugins.appendNodePlugin(nodePlugin);
+        if (GeneratePIC.getValue()) {
+            // AOT needs to filter out bad invokes
+            plugins.prependNodePlugin(new NodePlugin() {
+                @Override
+                public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+                    if (b.parsingIntrinsic()) {
+                        return false;
+                    }
+                    // check if the holder has a valid fingerprint
+                    if (FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) method.getDeclaringClass()) == 0) {
+                        // Deopt otherwise
+                        b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+                        return true;
+                    }
+                    // the last argument that may come from appendix, check if it is a supported
+                    // constant type
+                    if (args.length > 0) {
+                        JavaConstant constant = args[args.length - 1].asJavaConstant();
+                        if (constant != null && constant instanceof HotSpotObjectConstant) {
+                            HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType();
+                            Class<?> clazz = type.mirror();
+                            if (clazz.equals(String.class)) {
+                                return false;
+                            }
+                            if (Class.class.isAssignableFrom(clazz) && FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) != 0) {
+                                return false;
+                            }
+                            b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            });
+        }
+        plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
+        plugins.appendInlineInvokePlugin(replacements);
+        if (InlineDuringParsing.getValue()) {
+            plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
+        }
+        plugins.appendInlineInvokePlugin(new InlineGraalDirectivesPlugin());
+
+        if (GeneratePIC.getValue()) {
+            plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
+            if (TieredAOT.getValue()) {
+                plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
+            }
+        }
+
+        invocationPlugins.defer(new Runnable() {
+
+            @Override
+            public void run() {
+                BytecodeProvider replacementBytecodeProvider = replacements.getReplacementBytecodeProvider();
+                registerObjectPlugins(invocationPlugins, replacementBytecodeProvider);
+                registerClassPlugins(plugins, config, replacementBytecodeProvider);
+                registerSystemPlugins(invocationPlugins, foreignCalls);
+                registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
+                registerCallSitePlugins(invocationPlugins);
+                registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
+                registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
+                registerStableOptionPlugins(invocationPlugins, snippetReflection);
+                registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
+
+                for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
+                    factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
+                }
+            }
+        });
+        return plugins;
+    }
+
+    private static void registerObjectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Object.class, bytecodeProvider);
+        if (!GeneratePIC.getValue()) {
+            // FIXME: clone() requires speculation and requires a fix in here (to check that
+            // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
+            // an instantiation of IntrinsicGraphBuilder using a constructor that sets
+            // AllowAssumptions to YES automatically. The former has to inherit the assumptions
+            // settings from the root compile instead. So, for now, I'm disabling it for
+            // GeneratePIC.
+            r.register1("clone", Receiver.class, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    ValueNode object = receiver.get();
+                    b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
+                    return true;
+                }
+
+                @Override
+                public boolean inlineOnly() {
+                    return true;
+                }
+            });
+        }
+        r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
+    }
+
+    private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
+
+        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
+        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
+        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
+        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
+        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
+
+        if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
+            r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
+        }
+
+        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                ValueNode javaClass = receiver.get();
+                LogicNode condition = b.recursiveAppend(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), javaClass, object, true));
+                if (condition.isTautology()) {
+                    b.addPush(JavaKind.Object, object);
+                } else {
+                    FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
+                    b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass));
+                }
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
+    }
+
+    private static void registerCallSitePlugins(InvocationPlugins plugins) {
+        InvocationPlugin plugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode callSite = receiver.get();
+                ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
+                if (folded != null) {
+                    b.addPush(JavaKind.Object, folded);
+                } else {
+                    b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
+                }
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        };
+        plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
+    }
+
+    private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
+        r.register0("getCallerClass", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
+        r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
+    }
+
+    private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
+    private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
+
+    /**
+     * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
+     * {@code constantPoolOop} field in a ConstantPool value.
+     *
+     * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
+     * @return a node representing the metaspace {@code ConstantPool} pointer associated with
+     *         {@code constantPoolOop}
+     */
+    private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
+        // ConstantPool.constantPoolOop is in fact the holder class.
+        ClassGetHubNode klass = b.add(new ClassGetHubNode(constantPoolOop));
+
+        boolean notCompressible = false;
+        AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
+        return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
+    }
+
+    /**
+     * Emits a node representing an element in a metaspace {@code ConstantPool}.
+     *
+     * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
+     */
+    private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
+        ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
+        int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
+        ValueNode scaledIndex = b.add(new LeftShiftNode(index, b.add(ConstantNode.forInt(shift))));
+        ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forInt(config.constantPoolSize))));
+        AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
+        boolean notCompressible = false;
+        ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
+        b.addPush(elementKind, elementValue);
+        return true;
+    }
+
+    private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
+
+        r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
+                boolean notCompressible = false;
+                ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
+                AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
+                ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
+                b.addPush(JavaKind.Int, length);
+                return true;
+            }
+        });
+
+        r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
+                return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
+            }
+        });
+        r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
+                return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
+            }
+        });
+        r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
+                return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
+            }
+        });
+        r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
+                return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
+            }
+        });
+    }
+
+    private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
+        Registration r = new Registration(plugins, System.class);
+        r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
+        r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
+        r.register1("identityHashCode", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
+        r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+                b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
+    }
+
+    private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
+        r.register0("currentThread", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
+                boolean compressible = false;
+                ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
+                AddressNode address = b.add(new OffsetAddressNode(thread, offset));
+                ValueNode javaThread = WordOperationPlugin.readOp(b, JavaKind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible);
+                boolean exactType = false;
+                boolean nonNull = true;
+                b.addPush(JavaKind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull));
+                return true;
+            }
+        });
+
+        r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
+    }
+
+    private static void registerStableOptionPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection) {
+        Registration r = new Registration(plugins, StableOptionValue.class);
+        r.register1("getValue", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                if (receiver.isConstant()) {
+                    StableOptionValue<?> option = snippetReflection.asObject(StableOptionValue.class, (JavaConstant) receiver.get().asConstant());
+                    b.addPush(JavaKind.Object, ConstantNode.forConstant(snippetReflection.forObject(option.getValue()), b.getMetaAccess()));
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public static final String cbcEncryptName;
+    public static final String cbcDecryptName;
+    public static final String aesEncryptName;
+    public static final String aesDecryptName;
+
+    public static final String reflectionClass;
+    public static final String constantPoolClass;
+
+    static {
+        if (Java8OrEarlier) {
+            cbcEncryptName = "encrypt";
+            cbcDecryptName = "decrypt";
+            aesEncryptName = "encryptBlock";
+            aesDecryptName = "decryptBlock";
+            reflectionClass = "sun.reflect.Reflection";
+            constantPoolClass = "sun.reflect.ConstantPool";
+        } else {
+            cbcEncryptName = "implEncrypt";
+            cbcDecryptName = "implDecrypt";
+            aesEncryptName = "implEncryptBlock";
+            aesDecryptName = "implDecryptBlock";
+            reflectionClass = "jdk.internal.reflect.Reflection";
+            constantPoolClass = "jdk.internal.reflect.ConstantPool";
+        }
+    }
+
+    private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        if (config.useAESIntrinsics) {
+            assert config.aescryptEncryptBlockStub != 0L;
+            assert config.aescryptDecryptBlockStub != 0L;
+            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
+            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
+            String arch = config.osArch;
+            String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
+            Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
+            r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
+            r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
+                            int.class);
+            r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
+            r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
+            r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
+        }
+    }
+
+    private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
+        if (config.useMultiplyToLenIntrinsic()) {
+            assert config.multiplyToLen != 0L;
+            if (Java8OrEarlier) {
+                try {
+                    Method m = BigInteger.class.getDeclaredMethod("multiplyToLen", int[].class, int.class, int[].class, int.class, int[].class);
+                    if (Modifier.isStatic(m.getModifiers())) {
+                        r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
+                                        int[].class);
+                    } else {
+                        r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", Receiver.class, int[].class, int.class, int[].class, int.class,
+                                        int[].class);
+                    }
+                } catch (NoSuchMethodException | SecurityException e) {
+                    throw new GraalError(e);
+                }
+            } else {
+                r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
+                                int[].class);
+            }
+        }
+        if (config.useMulAddIntrinsic()) {
+            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
+        }
+        if (config.useMontgomeryMultiplyIntrinsic()) {
+            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class);
+        }
+        if (config.useMontgomerySquareIntrinsic()) {
+            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class);
+        }
+        if (config.useSquareToLenIntrinsic()) {
+            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
+        }
+    }
+
+    private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        if (config.useSHA1Intrinsics()) {
+            assert config.sha1ImplCompress != 0L;
+            Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider);
+            r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+        }
+        if (config.useSHA256Intrinsics()) {
+            assert config.sha256ImplCompress != 0L;
+            Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider);
+            r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+        }
+        if (config.useSHA512Intrinsics()) {
+            assert config.sha512ImplCompress != 0L;
+            Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider);
+            r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+        }
+    }
+
+    private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+        if (config.useCRC32Intrinsics) {
+            Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
+            if (Java8OrEarlier) {
+                r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
+                r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
+            } else {
+                r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
+                r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
new file mode 100644
index 0000000..7260878
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM;
+import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.BACKEDGE_EVENT;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.INVOCATION_EVENT;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.IC_MISS_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_MULTIPLY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_SQUARE;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.MULTIPLY_TO_LEN;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.MUL_ADD;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNPACK_FRAMES;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.STACK_INSPECTABLE_LEAF;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION;
+import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION;
+import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
+import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
+import static org.graalvm.compiler.hotspot.replacements.AssertionSnippets.ASSERTION_VM_MESSAGE_C;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITORENTER;
+import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITOREXIT;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_ARRAY;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.INIT_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions.THREAD_IS_INTERRUPTED;
+import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPOSTCALL;
+import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPRECALL;
+import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.VALIDATE_OBJECT;
+import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.EXCEPTION_HANDLER_FOR_PC;
+import static org.graalvm.compiler.hotspot.stubs.NewArrayStub.NEW_ARRAY_C;
+import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.NEW_INSTANCE_C;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.VM_MESSAGE_C;
+import static org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub.EXCEPTION_HANDLER_FOR_RETURN_ADDRESS;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.any;
+import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
+import static org.graalvm.compiler.replacements.Log.LOG_OBJECT;
+import static org.graalvm.compiler.replacements.Log.LOG_PRIMITIVE;
+import static org.graalvm.compiler.replacements.Log.LOG_PRINTF;
+import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.CompilerRuntimeHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.stubs.ArrayStoreExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.ClassCastExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.CreateExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub;
+import org.graalvm.compiler.hotspot.stubs.NewArrayStub;
+import org.graalvm.compiler.hotspot.stubs.NewInstanceStub;
+import org.graalvm.compiler.hotspot.stubs.NullPointerExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.OutOfBoundsExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
+import org.graalvm.compiler.hotspot.stubs.VerifyOopStub;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * HotSpot implementation of {@link ForeignCallsProvider}.
+ */
+public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCallsProviderImpl {
+
+    public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class);
+    public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class);
+
+    public HotSpotHostForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    WordTypes wordTypes) {
+        super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes);
+    }
+
+    protected static void link(Stub stub) {
+        stub.getLinkage().setCompiledStub(stub);
+    }
+
+    public static ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit) {
+        return checkcastArraycopyDescriptors[uninit ? 1 : 0];
+    }
+
+    public static ForeignCallDescriptor lookupArraycopyDescriptor(JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny) {
+        if (uninit) {
+            assert kind == JavaKind.Object;
+            assert !killAny : "unsupported";
+            return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0];
+        }
+        if (killAny) {
+            assert kind == JavaKind.Object;
+            return objectArraycopyDescriptorsKillAny[aligned ? 1 : 0][disjoint ? 1 : 0];
+        }
+        return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
+    }
+
+    @SuppressWarnings({"unchecked"}) private static final EnumMap<JavaKind, ForeignCallDescriptor>[][] arraycopyDescriptors = (EnumMap<JavaKind, ForeignCallDescriptor>[][]) new EnumMap<?, ?>[2][2];
+
+    private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2];
+    private static final ForeignCallDescriptor[] checkcastArraycopyDescriptors = new ForeignCallDescriptor[2];
+    private static ForeignCallDescriptor[][] objectArraycopyDescriptorsKillAny = new ForeignCallDescriptor[2][2];
+
+    static {
+        // Populate the EnumMap instances
+        for (int i = 0; i < arraycopyDescriptors.length; i++) {
+            for (int j = 0; j < arraycopyDescriptors[i].length; j++) {
+                arraycopyDescriptors[i][j] = new EnumMap<>(JavaKind.class);
+            }
+        }
+    }
+
+    private void registerArraycopyDescriptor(Map<Long, ForeignCallDescriptor> descMap, JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
+        ForeignCallDescriptor desc = descMap.get(routine);
+        if (desc == null) {
+            desc = buildDescriptor(kind, aligned, disjoint, uninit, killAny, routine);
+            descMap.put(routine, desc);
+        }
+        if (uninit) {
+            assert kind == JavaKind.Object;
+            uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0] = desc;
+        } else {
+            arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc);
+        }
+    }
+
+    private ForeignCallDescriptor buildDescriptor(JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
+        assert !killAny || kind == JavaKind.Object;
+        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy" + (killAny ? "KillAny" : "");
+        ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class);
+        LocationIdentity killed = killAny ? LocationIdentity.any() : NamedLocationIdentity.getArrayLocation(kind);
+        registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        return desc;
+    }
+
+    private void registerCheckcastArraycopyDescriptor(boolean uninit, long routine) {
+        String name = "Object" + (uninit ? "Uninit" : "") + "Checkcast";
+        // Input:
+        // c_rarg0 - source array address
+        // c_rarg1 - destination array address
+        // c_rarg2 - element count, treated as ssize_t, can be zero
+        // c_rarg3 - size_t ckoff (super_check_offset)
+        // c_rarg4 - oop ckval (super_klass)
+        // return: 0 = success, n = number of copied elements xor'd with -1.
+        ForeignCallDescriptor desc = new ForeignCallDescriptor(name, int.class, Word.class, Word.class, Word.class, Word.class, Word.class);
+        LocationIdentity killed = NamedLocationIdentity.getArrayLocation(JavaKind.Object);
+        registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
+        checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc;
+    }
+
+    private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
+        registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false);
+    }
+
+    private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) {
+        /*
+         * Sometimes the same function is used for multiple cases so share them when that's the case
+         * but only within the same Kind. For instance short and char are the same copy routines but
+         * they kill different memory so they still have to be distinct.
+         */
+        Map<Long, ForeignCallDescriptor> descMap = new HashMap<>();
+        registerArraycopyDescriptor(descMap, kind, false, false, uninit, false, routine);
+        registerArraycopyDescriptor(descMap, kind, true, false, uninit, false, alignedRoutine);
+        registerArraycopyDescriptor(descMap, kind, false, true, uninit, false, disjointRoutine);
+        registerArraycopyDescriptor(descMap, kind, true, true, uninit, false, alignedDisjointRoutine);
+
+        if (kind == JavaKind.Object && !uninit) {
+            objectArraycopyDescriptorsKillAny[0][0] = buildDescriptor(kind, false, false, uninit, true, routine);
+            objectArraycopyDescriptorsKillAny[1][0] = buildDescriptor(kind, true, false, uninit, true, alignedRoutine);
+            objectArraycopyDescriptorsKillAny[0][1] = buildDescriptor(kind, false, true, uninit, true, disjointRoutine);
+            objectArraycopyDescriptorsKillAny[1][1] = buildDescriptor(kind, true, true, uninit, true, alignedDisjointRoutine);
+        }
+    }
+
+    public void initialize(HotSpotProviders providers) {
+        GraalHotSpotVMConfig c = runtime.getVMConfig();
+        if (!PreferGraalStubs.getValue()) {
+            registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+            registerForeignCall(UNCOMMON_TRAP_HANDLER, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        }
+        registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+
+        registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(SIN.foreignCallDescriptor, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(COS.foreignCallDescriptor, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(TAN.foreignCallDescriptor, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(EXP.foreignCallDescriptor, c.arithmeticExpAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(LOG.foreignCallDescriptor, c.arithmeticLogAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(LOG10.foreignCallDescriptor, c.arithmeticLog10Address, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(POW.foreignCallDescriptor, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ARITHMETIC_FREM, c.fremAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ARITHMETIC_DREM, c.dremAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+
+        registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
+
+        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, NOT_REEXECUTABLE, any());
+
+        /*
+         * We cannot use LEAF_SP here because on some architectures we have to align the stack
+         * manually before calling into the VM. See {@link
+         * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
+         */
+        registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, any());
+
+        CreateExceptionStub.registerForeignCalls(c, this);
+
+        /*
+         * This message call is registered twice, where the second one must only be used for calls
+         * that do not return, i.e., that exit the VM.
+         */
+        registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+
+        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
+        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
+        link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER)));
+        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, SAFEPOINT, any())));
+        link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
+        link(new ArrayStoreExceptionStub(providers, registerStubCall(CREATE_ARRAY_STORE_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
+        link(new ClassCastExceptionStub(providers, registerStubCall(CREATE_CLASS_CAST_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
+        link(new NullPointerExceptionStub(providers, registerStubCall(CREATE_NULL_POINTER_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
+        link(new OutOfBoundsExceptionStub(providers, registerStubCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
+
+        linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
+        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+
+        if (GeneratePIC.getValue()) {
+            registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+            CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore());
+            linkForeignCall(providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+            linkForeignCall(providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
+            linkForeignCall(providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
+            linkForeignCall(providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
+            linkForeignCall(providers, INVOCATION_EVENT, cr.invocationEvent, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
+            linkForeignCall(providers, BACKEDGE_EVENT, cr.backedgeEvent, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
+        }
+
+        // Cannot be a leaf as VM acquires Thread_lock which requires thread_in_vm state
+        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
+
+        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
+
+        registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
+        registerArrayCopy(JavaKind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
+
+        registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
+        registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
+
+        if (c.useMultiplyToLenIntrinsic()) {
+            registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
+        }
+        if (c.useSHA1Intrinsics()) {
+            registerForeignCall(SHA_IMPL_COMPRESS, c.sha1ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
+        }
+        if (c.useSHA256Intrinsics()) {
+            registerForeignCall(SHA2_IMPL_COMPRESS, c.sha256ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
+        }
+        if (c.useSHA512Intrinsics()) {
+            registerForeignCall(SHA5_IMPL_COMPRESS, c.sha512ImplCompress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
+        }
+        if (c.useMulAddIntrinsic()) {
+            registerForeignCall(MUL_ADD, c.mulAdd, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
+        }
+        if (c.useMontgomeryMultiplyIntrinsic()) {
+            registerForeignCall(MONTGOMERY_MULTIPLY, c.montgomeryMultiply, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
+        }
+        if (c.useMontgomerySquareIntrinsic()) {
+            registerForeignCall(MONTGOMERY_SQUARE, c.montgomerySquare, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
+        }
+        if (c.useSquareToLenIntrinsic()) {
+            registerForeignCall(SQUARE_TO_LEN, c.squareToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
+        }
+
+        if (c.useAESIntrinsics) {
+            /*
+             * When the java.ext.dirs property is modified then the crypto classes might not be
+             * found. If that's the case we ignore the ClassNotFoundException and continue since we
+             * cannot replace a non-existing method anyway.
+             */
+            try {
+                // These stubs do callee saving
+                registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+            } catch (GraalError e) {
+                if (!(e.getCause() instanceof ClassNotFoundException)) {
+                    throw e;
+                }
+            }
+            try {
+                // These stubs do callee saving
+                registerForeignCall(ENCRYPT, c.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT_WITH_ORIGINAL_KEY, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+            } catch (GraalError e) {
+                if (!(e.getCause() instanceof ClassNotFoundException)) {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    public HotSpotForeignCallLinkage getForeignCall(ForeignCallDescriptor descriptor) {
+        assert foreignCalls != null : descriptor;
+        return foreignCalls.get(descriptor);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java
new file mode 100644
index 0000000..6c7f008
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import java.lang.reflect.Type;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.nodes.MacroNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration.
+ */
+final class HotSpotInvocationPlugins extends InvocationPlugins {
+    final GraalHotSpotVMConfig config;
+
+    HotSpotInvocationPlugins(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        super(metaAccess);
+        this.config = config;
+    }
+
+    @Override
+    public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
+        if (!config.usePopCountInstruction) {
+            if (name.equals("bitCount")) {
+                assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class);
+                return;
+            }
+        }
+        super.register(plugin, declaringClass, name, argumentTypes);
+    }
+
+    @Override
+    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        for (Node node : newNodes) {
+            if (node instanceof MacroNode) {
+                // MacroNode based plugins can only be used for inlining since they
+                // require a valid bci should they need to replace themselves with
+                // an InvokeNode during lowering.
+                assert plugin.inlineOnly() : String.format("plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroNode.class.getSimpleName(), node, plugin);
+            }
+        }
+        if (GraalOptions.ImmutableCode.getValue()) {
+            for (Node node : newNodes) {
+                if (node.hasUsages() && node instanceof ConstantNode) {
+                    ConstantNode c = (ConstantNode) node;
+                    if (c.getStackKind() == JavaKind.Object && AheadOfTimeVerificationPhase.isIllegalObjectConstant(c)) {
+                        if (isClass(c)) {
+                            // This will be handled later by LoadJavaMirrorWithKlassPhase
+                        } else {
+                            // Tolerate uses in unused FrameStates
+                            if (node.usages().filter((n) -> !(n instanceof FrameState) || n.hasUsages()).isNotEmpty()) {
+                                throw new AssertionError("illegal constant node in AOT: " + node);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        super.checkNewNodes(b, plugin, newNodes);
+    }
+
+    private static boolean isClass(ConstantNode node) {
+        ResolvedJavaType type = StampTool.typeOrNull(node);
+        return type != null && "Ljava/lang/Class;".equals(type.getName());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotLoweringProvider.java
new file mode 100644
index 0000000..95b21a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotLoweringProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public interface HotSpotLoweringProvider extends LoweringProvider {
+
+    void initialize(HotSpotProviders providers, GraalHotSpotVMConfig config);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
new file mode 100644
index 0000000..89729e7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
+import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
+import org.graalvm.compiler.replacements.WordOperationPlugin;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * This plugin handles the HotSpot-specific customizations of bytecode parsing:
+ * <p>
+ * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions
+ * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that
+ * we forward the {@link NodePlugin} and {@link TypePlugin} methods, but not the
+ * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not
+ * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined,
+ * i.e., there are never non-inlined invokes that involve the {@link Word} type.
+ * <p>
+ * Constant folding of field loads.
+ */
+public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
+    protected final WordOperationPlugin wordOperationPlugin;
+
+    public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin) {
+        this.wordOperationPlugin = wordOperationPlugin;
+    }
+
+    @Override
+    public boolean canChangeStackKind(GraphBuilderContext b) {
+        if (b.parsingIntrinsic()) {
+            return wordOperationPlugin.canChangeStackKind(b);
+        }
+        return false;
+    }
+
+    @Override
+    public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
+        if (b.parsingIntrinsic()) {
+            return wordOperationPlugin.interceptType(b, declaredType, nonNull);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleInvoke(b, method, args)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
+        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
+            if (object.isConstant()) {
+                JavaConstant asJavaConstant = object.asJavaConstant();
+                if (tryReadField(b, field, asJavaConstant)) {
+                    return true;
+                }
+            }
+        }
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
+        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
+            if (tryReadField(b, field, null)) {
+                return true;
+            }
+        }
+        if (GeneratePIC.getValue()) {
+            if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) {
+                return tryReadField(b, field, null);
+            }
+        }
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
+        // FieldReadEnabledInImmutableCode is non null only if assertions are enabled
+        if (FieldReadEnabledInImmutableCode != null && ImmutableCode.getValue()) {
+            FieldReadEnabledInImmutableCode.set(Boolean.TRUE);
+            try {
+                return tryConstantFold(b, field, object);
+            } finally {
+                FieldReadEnabledInImmutableCode.set(null);
+            }
+        } else {
+            return tryConstantFold(b, field, object);
+        }
+    }
+
+    private static boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
+        ConstantNode result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, object);
+        if (result != null) {
+            result = b.getGraph().unique(result);
+            b.push(field.getJavaKind(), result);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreField(b, object, field, value)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreStaticField(b, field, value)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, elementKind)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, elementKind, value)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleCheckCast(b, object, type, profile)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java
new file mode 100644
index 0000000..d0dad67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class HotSpotProfilingPlugin implements ProfilingPlugin {
+    public static class Options {
+        @Option(help = "Emit profiling of invokes", type = OptionType.Expert)//
+        public static final OptionValue<Boolean> ProfileInvokes = new OptionValue<>(true);
+        @Option(help = "Emit profiling of backedges", type = OptionType.Expert)//
+        public static final OptionValue<Boolean> ProfileBackedges = new OptionValue<>(true);
+    }
+
+    public abstract int invokeNotifyFreqLog();
+
+    public abstract int invokeInlineeNotifyFreqLog();
+
+    public abstract int invokeProfilePobabilityLog();
+
+    public abstract int backedgeNotifyFreqLog();
+
+    public abstract int backedgeProfilePobabilityLog();
+
+    @Override
+    public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) {
+        return !builder.parsingIntrinsic();
+    }
+
+    @Override
+    public void profileInvoke(GraphBuilderContext builder, ResolvedJavaMethod method, FrameState frameState) {
+        assert shouldProfile(builder, method);
+        if (Options.ProfileInvokes.getValue() && !method.isClassInitializer()) {
+            ProfileNode p = builder.append(new ProfileInvokeNode(method, invokeNotifyFreqLog(), invokeProfilePobabilityLog()));
+            p.setStateBefore(frameState);
+        }
+    }
+
+    @Override
+    public void profileGoto(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, int targetBci, FrameState frameState) {
+        assert shouldProfile(builder, method);
+        if (Options.ProfileBackedges.getValue() && targetBci <= bci) {
+            ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(), backedgeProfilePobabilityLog(), bci, targetBci));
+            p.setStateBefore(frameState);
+        }
+    }
+
+    @Override
+    public void profileIf(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, LogicNode condition, int trueBranchBci, int falseBranchBci, FrameState frameState) {
+        assert shouldProfile(builder, method);
+        if (Options.ProfileBackedges.getValue() && (falseBranchBci <= bci || trueBranchBci <= bci)) {
+            boolean negate = false;
+            int targetBci = trueBranchBci;
+            if (falseBranchBci <= bci) {
+                assert trueBranchBci > bci;
+                negate = true;
+                targetBci = falseBranchBci;
+            } else {
+                assert trueBranchBci <= bci && falseBranchBci > bci;
+            }
+            ValueNode trueValue = builder.append(ConstantNode.forBoolean(!negate));
+            ValueNode falseValue = builder.append(ConstantNode.forBoolean(negate));
+            ConditionalNode branchCondition = builder.append(new ConditionalNode(condition, trueValue, falseValue));
+            ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(), backedgeProfilePobabilityLog(), branchCondition, bci, targetBci));
+            p.setStateBefore(frameState);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java
new file mode 100644
index 0000000..2b65a88
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.tiers.SuitesProvider;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Extends {@link Providers} to include a number of extra capabilities used by the HotSpot parts of
+ * the compiler.
+ */
+public class HotSpotProviders extends Providers {
+
+    private final SuitesProvider suites;
+    private final HotSpotRegistersProvider registers;
+    private final SnippetReflectionProvider snippetReflection;
+    private final HotSpotWordTypes wordTypes;
+    private final Plugins graphBuilderPlugins;
+
+    public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantField,
+                    HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, NodeCostProvider nodeCostProvider, SuitesProvider suites,
+                    HotSpotRegistersProvider registers,
+                    SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) {
+        super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider(), nodeCostProvider);
+        this.suites = suites;
+        this.registers = registers;
+        this.snippetReflection = snippetReflection;
+        this.wordTypes = wordTypes;
+        this.graphBuilderPlugins = graphBuilderPlugins;
+    }
+
+    @Override
+    public HotSpotCodeCacheProvider getCodeCache() {
+        return (HotSpotCodeCacheProvider) super.getCodeCache();
+    }
+
+    @Override
+    public HotSpotForeignCallsProvider getForeignCalls() {
+        return (HotSpotForeignCallsProvider) super.getForeignCalls();
+    }
+
+    public SuitesProvider getSuites() {
+        return suites;
+    }
+
+    public HotSpotRegistersProvider getRegisters() {
+        return registers;
+    }
+
+    public SnippetReflectionProvider getSnippetReflection() {
+        return snippetReflection;
+    }
+
+    public Plugins getGraphBuilderPlugins() {
+        return graphBuilderPlugins;
+    }
+
+    public HotSpotWordTypes getWordTypes() {
+        return wordTypes;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegisters.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegisters.java
new file mode 100644
index 0000000..17fad8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegisters.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import jdk.vm.ci.code.Register;
+
+public class HotSpotRegisters implements HotSpotRegistersProvider {
+
+    private final Register threadRegister;
+    private final Register heapBaseRegister;
+    private final Register stackPointerRegister;
+
+    public HotSpotRegisters(Register threadRegister, Register heapBaseRegister, Register stackPointerRegister) {
+        this.threadRegister = threadRegister;
+        this.heapBaseRegister = heapBaseRegister;
+        this.stackPointerRegister = stackPointerRegister;
+    }
+
+    @Override
+    public Register getThreadRegister() {
+        assert !threadRegister.equals(Register.None) : "thread register is not defined";
+        return threadRegister;
+    }
+
+    @Override
+    public Register getHeapBaseRegister() {
+        assert !heapBaseRegister.equals(Register.None) : "heap base register is not defined";
+        return heapBaseRegister;
+    }
+
+    @Override
+    public Register getStackPointerRegister() {
+        assert !stackPointerRegister.equals(Register.None) : "stack pointer register is not defined";
+        return stackPointerRegister;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegistersProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegistersProvider.java
new file mode 100644
index 0000000..b53ab37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotRegistersProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Special registers reserved by HotSpot for frequently used values.
+ */
+public interface HotSpotRegistersProvider {
+
+    /**
+     * Gets the register holding the current thread.
+     */
+    Register getThreadRegister();
+
+    /**
+     * Gets the register holding the heap base address for compressed pointers.
+     */
+    Register getHeapBaseRegister();
+
+    /**
+     * Gets the stack pointer register.
+     */
+    Register getStackPointerRegister();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java
new file mode 100644
index 0000000..f1c7359
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvider {
+
+    private final HotSpotGraalRuntimeProvider runtime;
+    private final HotSpotConstantReflectionProvider constantReflection;
+    private final WordTypes wordTypes;
+
+    public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        this.runtime = runtime;
+        this.constantReflection = constantReflection;
+        this.wordTypes = wordTypes;
+    }
+
+    @Override
+    public JavaConstant forObject(Object object) {
+        return constantReflection.forObject(object);
+    }
+
+    @Override
+    public Object asObject(ResolvedJavaType type, JavaConstant constant) {
+        if (constant.isNull()) {
+            return null;
+        }
+        HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant;
+        return hsConstant.asObject(type);
+    }
+
+    @Override
+    public <T> T asObject(Class<T> type, JavaConstant constant) {
+        if (constant.isNull()) {
+            return null;
+        }
+        HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant;
+        return hsConstant.asObject(type);
+    }
+
+    @Override
+    public JavaConstant forBoxed(JavaKind kind, Object value) {
+        if (kind == JavaKind.Object) {
+            return forObject(value);
+        } else {
+            return JavaConstant.forBoxedPrimitive(value);
+        }
+    }
+
+    // Lazily initialized
+    private Class<?> wordTypesType;
+    private Class<?> runtimeType;
+    private Class<?> configType;
+
+    @Override
+    public <T> T getInjectedNodeIntrinsicParameter(Class<T> type) {
+        // Need to test all fields since there no guarantee under the JMM
+        // about the order in which these fields are written.
+        GraalHotSpotVMConfig config = runtime.getVMConfig();
+        if (configType == null || wordTypesType == null || configType == null) {
+            wordTypesType = wordTypes.getClass();
+            runtimeType = runtime.getClass();
+            configType = config.getClass();
+        }
+
+        if (type.isAssignableFrom(wordTypesType)) {
+            return type.cast(wordTypes);
+        }
+        if (type.isAssignableFrom(runtimeType)) {
+            return type.cast(runtime);
+        }
+        if (type.isAssignableFrom(configType)) {
+            return type.cast(config);
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotStampProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotStampProvider.java
new file mode 100644
index 0000000..613361e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotStampProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+
+public class HotSpotStampProvider implements StampProvider {
+
+    @Override
+    public Stamp createHubStamp(ObjectStamp object) {
+        return KlassPointerStamp.klassNonNull();
+    }
+
+    @Override
+    public Stamp createMethodStamp() {
+        return MethodPointerStamp.methodNonNull();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java
new file mode 100644
index 0000000..32d7281
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases;
+
+import java.util.ListIterator;
+
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
+import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
+import org.graalvm.compiler.hotspot.phases.aot.AOTInliningPolicy;
+import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase;
+import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase;
+import org.graalvm.compiler.hotspot.phases.profiling.FinalizeProfileNodesPhase;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.java.SuitesProviderBase;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.EncodedGraph;
+import org.graalvm.compiler.nodes.GraphEncoder;
+import org.graalvm.compiler.nodes.SimplifyingGraphDecoder;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.AddressLoweringPhase;
+import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ExpandLogicPhase;
+import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.SuitesCreator;
+
+/**
+ * HotSpot implementation of {@link SuitesCreator}.
+ */
+public class HotSpotSuitesProvider extends SuitesProviderBase {
+
+    protected final GraalHotSpotVMConfig config;
+    protected final HotSpotGraalRuntimeProvider runtime;
+
+    private final AddressLowering addressLowering;
+    private final SuitesCreator defaultSuitesCreator;
+
+    public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, AddressLowering addressLowering) {
+        this.defaultSuitesCreator = defaultSuitesCreator;
+        this.config = config;
+        this.runtime = runtime;
+        this.addressLowering = addressLowering;
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
+    }
+
+    @Override
+    public Suites createSuites() {
+        Suites ret = defaultSuitesCreator.createSuites();
+
+        if (ImmutableCode.getValue()) {
+            // lowering introduces class constants, therefore it must be after lowering
+            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config.classMirrorOffset, config.useCompressedOops ? config.getOopEncoding() : null));
+            if (VerifyPhases.getValue()) {
+                ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
+            }
+            if (GeneratePIC.getValue()) {
+                // EliminateRedundantInitializationPhase must happen before the first lowering.
+                ListIterator<BasePhase<? super HighTierContext>> highTierLowering = ret.getHighTier().findPhase(LoweringPhase.class);
+                highTierLowering.previous();
+                highTierLowering.add(new EliminateRedundantInitializationPhase());
+                if (HotSpotAOTProfilingPlugin.Options.TieredAOT.getValue()) {
+                    highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue()));
+                }
+                ret.getMidTier().findPhase(LoopSafepointInsertionPhase.class).add(new ReplaceConstantNodesPhase());
+
+                // Replace inlining policy
+                ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(InliningPhase.class);
+                InliningPhase inlining = (InliningPhase) iter.previous();
+                CanonicalizerPhase canonicalizer = inlining.getCanonicalizer();
+                iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer));
+            }
+        }
+
+        ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase(config));
+        if (VerifyPhases.getValue()) {
+            ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config));
+        }
+
+        ret.getLowTier().findPhase(ExpandLogicPhase.class).add(new AddressLoweringPhase(addressLowering));
+
+        return ret;
+    }
+
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+        PhaseSuite<HighTierContext> suite = defaultSuitesCreator.getDefaultGraphBuilderSuite().copy();
+        assert appendGraphEncoderTest(suite);
+        return suite;
+    }
+
+    /**
+     * When assertions are enabled, we encode and decode every parsed graph, to ensure that the
+     * encoding and decoding process work correctly. The decoding performs canonicalization during
+     * decoding, so the decoded graph can be different than the encoded graph - we cannot check them
+     * for equality here. However, the encoder {@link GraphEncoder#verifyEncoding verifies the
+     * encoding itself}, i.e., performs a decoding without canoncialization and checks the graphs
+     * for equality.
+     */
+    private boolean appendGraphEncoderTest(PhaseSuite<HighTierContext> suite) {
+        suite.appendPhase(new BasePhase<HighTierContext>() {
+            @Override
+            protected void run(StructuredGraph graph, HighTierContext context) {
+                EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch);
+
+                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(),
+                                context.getStampProvider(), !ImmutableCode.getValue(), runtime.getTarget().arch);
+                StructuredGraph targetGraph = new StructuredGraph(graph.method(), AllowAssumptions.YES, INVALID_COMPILATION_ID);
+                graphDecoder.decode(targetGraph, encodedGraph);
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "VerifyEncodingDecoding";
+            }
+        });
+        return true;
+    }
+
+    /**
+     * Modifies a given {@link GraphBuilderConfiguration} to record per node source information.
+     *
+     * @param gbs the current graph builder suite to modify
+     */
+    public static PhaseSuite<HighTierContext> withNodeSourcePosition(PhaseSuite<HighTierContext> gbs) {
+        PhaseSuite<HighTierContext> newGbs = gbs.copy();
+        GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
+        GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
+        GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig.withNodeSourcePosition(true));
+        newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
+        return newGbs;
+    }
+
+    @Override
+    public LIRSuites createLIRSuites() {
+        LIRSuites suites = defaultSuitesCreator.createLIRSuites();
+        String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue();
+        if (profileInstructions != null) {
+            suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
+        }
+        return suites;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java
new file mode 100644
index 0000000..cb47a5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
+import static org.graalvm.compiler.nodes.ConstantNode.forBoolean;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.nodes.LoadIndexedPointerNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MetaspacePointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
+import org.graalvm.compiler.hotspot.word.HotSpotOperation;
+import org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode;
+import org.graalvm.compiler.hotspot.word.PointerCastNode;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.calc.PointerEqualsNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.WordOperationPlugin;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Extends {@link WordOperationPlugin} to handle {@linkplain HotSpotOperation HotSpot word
+ * operations}.
+ */
+class HotSpotWordOperationPlugin extends WordOperationPlugin {
+    HotSpotWordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+        super(snippetReflection, wordTypes);
+    }
+
+    @Override
+    protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
+        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+        Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType());
+        if (componentStamp instanceof MetaspacePointerStamp) {
+            return new LoadIndexedPointerNode(componentStamp, array, index);
+        } else {
+            return super.createLoadIndexedNode(array, index);
+        }
+    }
+
+    @Override
+    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (!wordTypes.isWordOperation(method)) {
+            return false;
+        }
+
+        HotSpotOperation operation = BridgeMethodUtils.getAnnotation(HotSpotOperation.class, method);
+        if (operation == null) {
+            processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
+            return true;
+        }
+        processHotSpotWordOperation(b, method, args, operation);
+        return true;
+    }
+
+    protected void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) {
+        JavaKind returnKind = method.getSignature().getReturnKind();
+        switch (operation.opcode()) {
+            case POINTER_EQ:
+            case POINTER_NE:
+                assert args.length == 2;
+                HotspotOpcode opcode = operation.opcode();
+                ValueNode left = args[0];
+                ValueNode right = args[1];
+                assert left.stamp() instanceof MetaspacePointerStamp : left + " " + left.stamp();
+                assert right.stamp() instanceof MetaspacePointerStamp : right + " " + right.stamp();
+                assert opcode == POINTER_EQ || opcode == POINTER_NE;
+
+                PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right));
+                ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ));
+                ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE));
+                b.addPush(returnKind, new ConditionalNode(comparison, eqValue, neValue));
+                break;
+
+            case IS_NULL:
+                assert args.length == 1;
+                ValueNode pointer = args[0];
+                assert pointer.stamp() instanceof MetaspacePointerStamp;
+
+                LogicNode isNull = b.add(IsNullNode.create(pointer));
+                b.addPush(returnKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
+                break;
+
+            case FROM_POINTER:
+                assert args.length == 1;
+                b.addPush(returnKind, new PointerCastNode(StampFactory.forKind(wordKind), args[0]));
+                break;
+
+            case TO_KLASS_POINTER:
+                assert args.length == 1;
+                b.addPush(returnKind, new PointerCastNode(KlassPointerStamp.klass(), args[0]));
+                break;
+
+            case TO_METHOD_POINTER:
+                assert args.length == 1;
+                b.addPush(returnKind, new PointerCastNode(MethodPointerStamp.method(), args[0]));
+                break;
+
+            case READ_KLASS_POINTER:
+                assert args.length == 2 || args.length == 3;
+                Stamp readStamp = KlassPointerStamp.klass();
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                LocationIdentity location;
+                if (args.length == 2) {
+                    location = any();
+                } else {
+                    assert args[2].isConstant();
+                    location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant());
+                }
+                ReadNode read = b.add(new ReadNode(address, location, readStamp, BarrierType.NONE));
+                /*
+                 * The read must not float outside its block otherwise it may float above an
+                 * explicit zero check on its base address.
+                 */
+                read.setGuard(AbstractBeginNode.prevBegin(read));
+                b.push(returnKind, read);
+                break;
+
+            default:
+                throw GraalError.shouldNotReachHere("unknown operation: " + operation.opcode());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AcquiredCASLockNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AcquiredCASLockNode.java
new file mode 100644
index 0000000..d681a55
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AcquiredCASLockNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Marks the control flow path where an object acquired a lightweight lock based on an atomic
+ * compare-and-swap (CAS) of the mark word in the object's header.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class AcquiredCASLockNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<AcquiredCASLockNode> TYPE = NodeClass.create(AcquiredCASLockNode.class);
+
+    @Input ValueNode object;
+
+    public AcquiredCASLockNode(ValueNode object) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // This is just a marker node so it generates nothing
+    }
+
+    @NodeIntrinsic
+    public static native void mark(Object object);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java
new file mode 100644
index 0000000..4c5dcd8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for
+ * the entire execution of the associated method.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<AllocaNode> TYPE = NodeClass.create(AllocaNode.class);
+    /**
+     * The number of slots in block.
+     */
+    protected final int slots;
+
+    /**
+     * The indexes of the object pointer slots in the block. Each such object pointer slot must be
+     * initialized before any safepoint in the method otherwise the garbage collector will see
+     * garbage values when processing these slots.
+     */
+    protected final BitSet objects;
+
+    public AllocaNode(@InjectedNodeParameter WordTypes wordTypes, int slots) {
+        this(slots, wordTypes.getWordKind(), new BitSet());
+    }
+
+    public AllocaNode(int slots, JavaKind wordKind, BitSet objects) {
+        super(TYPE, StampFactory.forKind(wordKind));
+        this.slots = slots;
+        this.objects = objects;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        VirtualStackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(slots, objects, null);
+        Value result = gen.getLIRGeneratorTool().emitAddress(array);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word alloca(@ConstantNodeParameter int slots);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java
new file mode 100644
index 0000000..f5c0f8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+
+@NodeInfo
+public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable {
+
+    public static final NodeClass<ArrayRangeWriteBarrier> TYPE = NodeClass.create(ArrayRangeWriteBarrier.class);
+    @Input ValueNode object;
+    @Input ValueNode startIndex;
+    @Input ValueNode length;
+
+    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(c);
+        this.object = object;
+        this.startIndex = startIndex;
+        this.length = length;
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public ValueNode getStartIndex() {
+        return startIndex;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java
new file mode 100644
index 0000000..d3c5b86
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.MonitorEnter;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Intrinsic for opening a scope binding a stack-based lock with an object. A lock scope must be
+ * closed with an {@link EndLockScopeNode}. The frame state after this node denotes that the object
+ * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer
+ * check on the object.
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_2, size = SIZE_1)
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
+
+    public static final NodeClass<BeginLockScopeNode> TYPE = NodeClass.create(BeginLockScopeNode.class);
+    protected int lockDepth;
+
+    public BeginLockScopeNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
+        this.lockDepth = lockDepth;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
+        VirtualStackSlot slot = hsGen.getLockSlot(lockDepth);
+        Value result = gen.getLIRGeneratorTool().emitAddress(slot);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java
new file mode 100644
index 0000000..104859a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConvertNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Compress or uncompress an oop or metaspace pointer.
+ */
+@NodeInfo(nameTemplate = "{p#op/s}", cycles = CYCLES_2, size = SIZE_2)
+public final class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable {
+
+    public static final NodeClass<CompressionNode> TYPE = NodeClass.create(CompressionNode.class);
+
+    public enum CompressionOp {
+        Compress,
+        Uncompress
+    }
+
+    protected final CompressionOp op;
+    protected final CompressEncoding encoding;
+
+    public CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
+        super(TYPE, mkStamp(op, input.stamp(), encoding), input);
+        this.op = op;
+        this.encoding = encoding;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        return mkStamp(op, newStamp, encoding);
+    }
+
+    public static CompressionNode compress(ValueNode input, CompressEncoding encoding) {
+        return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding));
+    }
+
+    public static CompressionNode compressNoUnique(ValueNode input, CompressEncoding encoding) {
+        return new CompressionNode(CompressionOp.Compress, input, encoding);
+    }
+
+    public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) {
+        return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding));
+    }
+
+    private static Constant compress(Constant c) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else if (c instanceof HotSpotConstant) {
+            return ((HotSpotConstant) c).compress();
+        } else {
+            throw GraalError.shouldNotReachHere("invalid constant input for compress op: " + c);
+        }
+    }
+
+    private static Constant uncompress(Constant c) {
+        if (c instanceof HotSpotConstant) {
+            return ((HotSpotConstant) c).uncompress();
+        } else {
+            throw GraalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
+        }
+    }
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        switch (op) {
+            case Compress:
+                return compress(c);
+            case Uncompress:
+                return uncompress(c);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        switch (op) {
+            case Compress:
+                return uncompress(c);
+            case Uncompress:
+                return compress(c);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
+    private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) {
+        switch (op) {
+            case Compress:
+                if (input instanceof ObjectStamp) {
+                    // compressed oop
+                    return NarrowOopStamp.compressed((ObjectStamp) input, encoding);
+                } else if (input instanceof KlassPointerStamp) {
+                    // compressed klass pointer
+                    return ((KlassPointerStamp) input).compressed(encoding);
+                }
+                break;
+            case Uncompress:
+                if (input instanceof NarrowOopStamp) {
+                    // oop
+                    assert encoding.equals(((NarrowOopStamp) input).getEncoding());
+                    return ((NarrowOopStamp) input).uncompressed();
+                } else if (input instanceof KlassPointerStamp) {
+                    // metaspace pointer
+                    assert encoding.equals(((KlassPointerStamp) input).getEncoding());
+                    return ((KlassPointerStamp) input).uncompressed();
+                }
+                break;
+        }
+        throw GraalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
+    }
+
+    public CompressionOp getOp() {
+        return op;
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            if (GeneratePIC.getValue()) {
+                // We always want uncompressed constants
+                return this;
+            }
+            int stableDimension = ((ConstantNode) forValue).getStableDimension();
+            boolean isDefaultStable = ((ConstantNode) forValue).isDefaultStable();
+            return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), stableDimension, isDefaultStable, tool.getMetaAccess());
+        } else if (forValue instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) forValue;
+            if (op != other.op && encoding.equals(other.encoding)) {
+                return other.getValue();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
+        boolean nonNull;
+        if (getValue().stamp() instanceof AbstractObjectStamp) {
+            nonNull = StampTool.isPointerNonNull(getValue().stamp());
+        } else {
+            // metaspace pointers are never null
+            nonNull = true;
+        }
+
+        Value result;
+        switch (op) {
+            case Compress:
+                result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
+                break;
+            case Uncompress:
+                result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Object compression(@ConstantNodeParameter CompressionOp op, Object object, @ConstantNodeParameter CompressEncoding encoding);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java
new file mode 100644
index 0000000..bff064c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.ControlFlowAnchored;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * A high-level intrinsic for getting an address inside of an object. During lowering it will be
+ * moved next to any uses to avoid creating a derived pointer that is live across a safepoint.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_2)
+public final class ComputeObjectAddressNode extends FixedWithNextNode implements Lowerable, ControlFlowAnchored {
+    public static final NodeClass<ComputeObjectAddressNode> TYPE = NodeClass.create(ComputeObjectAddressNode.class);
+
+    @Input ValueNode object;
+    @Input ValueNode offset;
+
+    public ComputeObjectAddressNode(ValueNode obj, ValueNode offset) {
+        super(TYPE, StampFactory.forKind(JavaKind.Long));
+        this.object = obj;
+        this.offset = offset;
+    }
+
+    @NodeIntrinsic
+    public static native long get(Object array, long offset);
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public ValueNode getOffset() {
+        return offset;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentJavaThreadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentJavaThreadNode.java
new file mode 100644
index 0000000..7154b1e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentJavaThreadNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+
+/**
+ * Gets the address of the C++ JavaThread object for the current thread.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<CurrentJavaThreadNode> TYPE = NodeClass.create(CurrentJavaThreadNode.class);
+
+    public CurrentJavaThreadNode(@InjectedNodeParameter WordTypes wordTypes) {
+        this(wordTypes.getWordKind());
+    }
+
+    public CurrentJavaThreadNode(JavaKind wordKind) {
+        super(TYPE, StampFactory.forKind(wordKind));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Register rawThread = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).getProviders().getRegisters().getThreadRegister();
+        PlatformKind wordKind = gen.getLIRGeneratorTool().target().arch.getWordKind();
+        gen.setResult(this, rawThread.asValue(LIRKind.value(wordKind)));
+    }
+
+    @NodeIntrinsic
+    public static native Word get();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentLockNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentLockNode.java
new file mode 100644
index 0000000..e3658c6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CurrentLockNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class CurrentLockNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<CurrentLockNode> TYPE = NodeClass.create(CurrentLockNode.class);
+
+    protected int lockDepth;
+
+    public CurrentLockNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
+        this.lockDepth = lockDepth;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
+        VirtualStackSlot slot = hsGen.getLockSlot(lockDepth);
+        // The register allocator cannot handle stack -> register moves so we use an LEA here
+        Value result = gen.getLIRGeneratorTool().emitAddress(slot);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word currentLock(@ConstantNodeParameter int lockDepth);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java
new file mode 100644
index 0000000..06a26f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.FETCH_UNROLL_INFO;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the runtime code {@code Deoptimization::fetch_unroll_info}.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<DeoptimizationFetchUnrollInfoCallNode> TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class);
+    @Input SaveAllRegistersNode registerSaver;
+    @Input ValueNode mode;
+    protected final ForeignCallsProvider foreignCalls;
+
+    public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode mode) {
+        super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.mode = mode;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    /**
+     * Returns the node representing the exec_mode/unpack_kind used during this fetch_unroll_info
+     * call.
+     */
+    public ValueNode getMode() {
+        return mode;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(gen.operand(getMode()), getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word fetchUnrollInfo(long registerSaver, int mode);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java
new file mode 100644
index 0000000..09aa3e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}", cycles = CYCLES_1, size = SIZE_3)
+public final class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
+
+    public static final NodeClass<DeoptimizeCallerNode> TYPE = NodeClass.create(DeoptimizeCallerNode.class);
+    protected final DeoptimizationAction action;
+    protected final DeoptimizationReason reason;
+
+    public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) {
+        super(TYPE, StampFactory.forVoid());
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizeCaller(action, reason);
+    }
+
+    @NodeIntrinsic
+    public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizingStubCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizingStubCall.java
new file mode 100644
index 0000000..7f273ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizingStubCall.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public abstract class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode {
+
+    public static final NodeClass<DeoptimizingStubCall> TYPE = NodeClass.create(DeoptimizingStubCall.class);
+
+    public DeoptimizingStubCall(NodeClass<? extends DeoptimizingStubCall> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java
new file mode 100644
index 0000000..db08803
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.asm.NumUtil.roundUp;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
+ * instruction.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<DimensionsNode> TYPE = NodeClass.create(DimensionsNode.class);
+    protected final int rank;
+
+    public DimensionsNode(@InjectedNodeParameter WordTypes wordTypes, int rank) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
+        this.rank = rank;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
+        int size = rank * 4;
+        int wordSize = lirGen.target().wordSize;
+        int slots = roundUp(size, wordSize) / wordSize;
+        VirtualStackSlot array = lirGen.getResult().getFrameMapBuilder().allocateStackSlots(slots, new BitSet(0), null);
+        Value result = lirGen.emitAddress(array);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word allocaDimsArray(@ConstantNodeParameter int rank);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DirectCompareAndSwapNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DirectCompareAndSwapNode.java
new file mode 100644
index 0000000..74eac1e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DirectCompareAndSwapNode.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.CompareAndSwapNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+/**
+ * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a
+ * {@link StateSplit} and it {@linkplain #compareAndSwap(Address, Word, Word, LocationIdentity)}
+ * returns either the expected value or the compared against value instead of a boolean.
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_30, size = SIZE_8)
+public final class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<DirectCompareAndSwapNode> TYPE = NodeClass.create(DirectCompareAndSwapNode.class);
+    @Input(Association) AddressNode address;
+    @Input ValueNode expectedValue;
+    @Input ValueNode newValue;
+
+    protected final LocationIdentity locationIdentity;
+
+    public DirectCompareAndSwapNode(ValueNode address, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) {
+        super(TYPE, expected.stamp());
+        this.address = (AddressNode) address;
+        this.expectedValue = expected;
+        this.newValue = newValue;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public AddressNode getAddress() {
+        return address;
+    }
+
+    public ValueNode expectedValue() {
+        return expectedValue;
+    }
+
+    public ValueNode newValue() {
+        return newValue;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this);
+    }
+
+    /**
+     * Compares an expected value with the actual value in a location denoted by an address. Iff
+     * they are same, {@code newValue} is placed into the location and the {@code expectedValue} is
+     * returned. Otherwise, the actual value is returned. All of the above is performed in one
+     * atomic hardware transaction.
+     *
+     * @param address the address to be atomically tested and updated
+     * @param expectedValue if this value is currently in the field, perform the swap
+     * @param newValue the new value to put into the field
+     * @return either {@code expectedValue} or the actual value
+     */
+    @NodeIntrinsic
+    public static native Word compareAndSwap(Address address, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java
new file mode 100644
index 0000000..53db7d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.MonitorExit;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an
+ * object.
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_0, size = SIZE_0)
+public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single {
+    public static final NodeClass<EndLockScopeNode> TYPE = NodeClass.create(EndLockScopeNode.class);
+
+    public EndLockScopeNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+
+    @NodeIntrinsic
+    public static native void endLockScope();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EnterUnpackFramesStackFrameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EnterUnpackFramesStackFrameNode.java
new file mode 100644
index 0000000..2685973
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EnterUnpackFramesStackFrameNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Emits code to enter a low-level stack frame specifically to call out to the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@NodeInfo(cycles = CYCLES_20, size = SIZE_10)
+public final class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<EnterUnpackFramesStackFrameNode> TYPE = NodeClass.create(EnterUnpackFramesStackFrameNode.class);
+
+    @Input ValueNode framePc;
+    @Input ValueNode senderSp;
+    @Input ValueNode senderFp;
+    @Input SaveAllRegistersNode registerSaver;
+
+    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) {
+        super(TYPE, StampFactory.forVoid());
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.senderFp = senderFp;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value operandValue = gen.operand(framePc);
+        Value senderSpValue = gen.operand(senderSp);
+        Value senderFpValue = gen.operand(senderFp);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp());
+    }
+
+    @NodeIntrinsic
+    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/FastAcquireBiasedLockNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/FastAcquireBiasedLockNode.java
new file mode 100644
index 0000000..8491b9f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/FastAcquireBiasedLockNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Marks the control flow path where an object acquired a biased lock because the lock was already
+ * biased to the object on the current thread.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class FastAcquireBiasedLockNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<FastAcquireBiasedLockNode> TYPE = NodeClass.create(FastAcquireBiasedLockNode.class);
+
+    @Input ValueNode object;
+
+    public FastAcquireBiasedLockNode(ValueNode object) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // This is just a marker node so it generates nothing
+    }
+
+    @NodeIntrinsic
+    public static native void mark(Object object);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java
new file mode 100644
index 0000000..3254f6b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
+
+    public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(TYPE, object, startIndex, length);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java
new file mode 100644
index 0000000..e290a14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
+
+    public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(TYPE, object, startIndex, length);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java
new file mode 100644
index 0000000..d4a994c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+public class G1PostWriteBarrier extends ObjectWriteBarrier {
+
+    public static final NodeClass<G1PostWriteBarrier> TYPE = NodeClass.create(G1PostWriteBarrier.class);
+    protected final boolean alwaysNull;
+
+    public G1PostWriteBarrier(AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
+        this(TYPE, address, value, precise, alwaysNull);
+    }
+
+    protected G1PostWriteBarrier(NodeClass<? extends G1PostWriteBarrier> c, AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
+        super(c, address, value, precise);
+        this.alwaysNull = alwaysNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java
new file mode 100644
index 0000000..4e21beb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+public final class G1PreWriteBarrier extends ObjectWriteBarrier implements DeoptimizingNode.DeoptBefore {
+
+    public static final NodeClass<G1PreWriteBarrier> TYPE = NodeClass.create(G1PreWriteBarrier.class);
+
+    @OptionalInput(InputType.State) FrameState stateBefore;
+    protected final boolean nullCheck;
+    protected final boolean doLoad;
+
+    public G1PreWriteBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad, boolean nullCheck) {
+        super(TYPE, address, expectedObject, true);
+        this.doLoad = doLoad;
+        this.nullCheck = nullCheck;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState state) {
+        updateUsages(stateBefore, state);
+        stateBefore = state;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java
new file mode 100644
index 0000000..bc59c04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+/**
+ * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent
+ * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an
+ * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
+ * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
+ */
+@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier {
+    public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
+
+    protected final boolean doLoad;
+
+    public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad) {
+        super(TYPE, address, expectedObject, true);
+        this.doLoad = doLoad;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GetObjectAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GetObjectAddressNode.java
new file mode 100644
index 0000000..17ae883
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GetObjectAddressNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Intrinsification for getting the address of an object. The code path(s) between a call to
+ * {@link #get(Object)} and all uses of the returned value must not contain safepoints. This can
+ * only be guaranteed if used in a snippet that is instantiated after frame state assignment.
+ * {@link ComputeObjectAddressNode} should generally be used in preference to this node.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<GetObjectAddressNode> TYPE = NodeClass.create(GetObjectAddressNode.class);
+
+    @Input ValueNode object;
+
+    public GetObjectAddressNode(ValueNode obj) {
+        super(TYPE, StampFactory.forKind(JavaKind.Long));
+        this.object = obj;
+    }
+
+    @NodeIntrinsic
+    public static native long get(Object array);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(LIRKind.unknownReference(gen.getLIRGeneratorTool().target().arch.getWordKind()));
+        gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object));
+        gen.setResult(this, obj);
+    }
+
+    @Override
+    public boolean verify() {
+        assert graph().getGuardsStage().areFrameStatesAtDeopts() || graph().method().getAnnotation(Snippet.class) != null : "GetObjectAddressNode can't be used directly until frame states are fixed";
+        return super.verify();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java
new file mode 100644
index 0000000..cdb8160
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents {@link GraalHotSpotVMConfig} values that may change after compilation.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public class GraalHotSpotVMConfigNode extends FloatingNode implements LIRLowerable, Canonicalizable {
+    public static final NodeClass<GraalHotSpotVMConfigNode> TYPE = NodeClass.create(GraalHotSpotVMConfigNode.class);
+
+    private final GraalHotSpotVMConfig config;
+    protected final int markId;
+
+    public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId, JavaKind kind) {
+        super(TYPE, StampFactory.forKind(kind));
+        this.config = config;
+        this.markId = markId;
+    }
+
+    /**
+     * Constructor selected by {@link #loadConfigValue(int, JavaKind)}.
+     *
+     * @param config
+     * @param markId
+     */
+    public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId) {
+        super(TYPE, StampFactory.forKind(JavaKind.Boolean));
+        this.config = config;
+        this.markId = 0;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        Value res = ((HotSpotLIRGenerator) generator.getLIRGeneratorTool()).emitLoadConfigValue(markId);
+        generator.setResult(this, res);
+    }
+
+    @NodeIntrinsic
+    private static native boolean isConfigValueConstant(@ConstantNodeParameter int markId);
+
+    @NodeIntrinsic
+    private static native long loadConfigValue(@ConstantNodeParameter int markId, @ConstantNodeParameter JavaKind kind);
+
+    public static long cardTableAddress() {
+        return loadConfigValue(cardTableAddressMark(INJECTED_VMCONFIG), JavaKind.Long);
+    }
+
+    public static boolean isCardTableAddressConstant() {
+        return isConfigValueConstant(cardTableAddressMark(INJECTED_VMCONFIG));
+    }
+
+    public static long heapTopAddress() {
+        return loadConfigValue(heapTopAddressMark(INJECTED_VMCONFIG), JavaKind.Long);
+    }
+
+    public static long heapEndAddress() {
+        return loadConfigValue(heapEndAddressMark(INJECTED_VMCONFIG), JavaKind.Long);
+    }
+
+    public static long crcTableAddress() {
+        return loadConfigValue(crcTableAddressMark(INJECTED_VMCONFIG), JavaKind.Long);
+    }
+
+    public static int logOfHeapRegionGrainBytes() {
+        return (int) loadConfigValue(logOfHeapRegionGrainBytesMark(INJECTED_VMCONFIG), JavaKind.Byte);
+    }
+
+    public static boolean inlineContiguousAllocationSupported() {
+        return loadConfigValue(inlineContiguousAllocationSupportedMark(INJECTED_VMCONFIG), JavaKind.Byte) > 0;
+    }
+
+    @Fold
+    public static int cardTableAddressMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_CARD_TABLE_ADDRESS;
+    }
+
+    @Fold
+    public static int heapTopAddressMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_HEAP_TOP_ADDRESS;
+    }
+
+    @Fold
+    public static int heapEndAddressMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_HEAP_END_ADDRESS;
+    }
+
+    @Fold
+    public static int crcTableAddressMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_CRC_TABLE_ADDRESS;
+    }
+
+    @Fold
+    public static int logOfHeapRegionGrainBytesMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES;
+    }
+
+    @Fold
+    public static int inlineContiguousAllocationSupportedMark(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (markId == 0) {
+            return ConstantNode.forBoolean(!GeneratePIC.getValue());
+        }
+        if (!GeneratePIC.getValue()) {
+            if (markId == cardTableAddressMark(config)) {
+                return ConstantNode.forLong(config.cardtableStartAddress);
+            } else if (markId == heapTopAddressMark(config)) {
+                return ConstantNode.forLong(config.heapTopAddress);
+            } else if (markId == heapEndAddressMark(config)) {
+                return ConstantNode.forLong(config.heapEndAddress);
+            } else if (markId == crcTableAddressMark(config)) {
+                return ConstantNode.forLong(config.crcTableAddress);
+            } else if (markId == logOfHeapRegionGrainBytesMark(config)) {
+                return ConstantNode.forInt(config.logOfHRGrainBytes);
+            } else if (markId == inlineContiguousAllocationSupportedMark(config)) {
+                return ConstantNode.forBoolean(config.inlineContiguousAllocationSupported);
+            } else {
+                assert false;
+            }
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotDirectCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotDirectCallTargetNode.java
new file mode 100644
index 0000000..f4ec60a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotDirectCallTargetNode.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DirectCallTargetNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.code.CallingConvention.Type;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public final class HotSpotDirectCallTargetNode extends DirectCallTargetNode {
+    public static final NodeClass<HotSpotDirectCallTargetNode> TYPE = NodeClass.create(HotSpotDirectCallTargetNode.class);
+
+    public HotSpotDirectCallTargetNode(ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target, Type callType, InvokeKind invokeKind) {
+        super(TYPE, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotIndirectCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotIndirectCallTargetNode.java
new file mode 100644
index 0000000..3e12033
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotIndirectCallTargetNode.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.IndirectCallTargetNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.code.CallingConvention.Type;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public final class HotSpotIndirectCallTargetNode extends IndirectCallTargetNode {
+    public static final NodeClass<HotSpotIndirectCallTargetNode> TYPE = NodeClass.create(HotSpotIndirectCallTargetNode.class);
+
+    @Input ValueNode metaspaceMethod;
+
+    public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature,
+                    ResolvedJavaMethod target,
+                    Type callType, InvokeKind invokeKind) {
+        super(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
+        this.metaspaceMethod = metaspaceMethod;
+    }
+
+    public ValueNode metaspaceMethod() {
+        return metaspaceMethod;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java
new file mode 100644
index 0000000..86785dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.spi.DefaultNodeCostProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public abstract class HotSpotNodeCostProvider extends DefaultNodeCostProvider {
+
+    @Override
+    public NodeSize size(Node n) {
+        if (n instanceof ObjectCloneNode) {
+            ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject());
+            if (type != null) {
+                if (type.isArray()) {
+                    return SIZE_30;
+                } else {
+                    return SIZE_20;
+                }
+            }
+        }
+        return super.size(n);
+    }
+
+    @Override
+    public NodeCycles cycles(Node n) {
+        if (n instanceof ObjectCloneNode) {
+            ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject());
+            if (type != null) {
+                if (type.isArray()) {
+                    return CYCLES_30;
+                } else {
+                    return CYCLES_20;
+                }
+            }
+        }
+        return super.cycles(n);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java
new file mode 100644
index 0000000..de069c2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+/**
+ * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an
+ * exception handler in the caller's frame, removes the current frame and jumps to said handler.
+ */
+@NodeInfo(cycles = CYCLES_15, size = SIZE_8)
+public final class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable {
+
+    public static final NodeClass<JumpToExceptionHandlerInCallerNode> TYPE = NodeClass.create(JumpToExceptionHandlerInCallerNode.class);
+    @Input ValueNode handlerInCallerPc;
+    @Input ValueNode exception;
+    @Input ValueNode exceptionPc;
+
+    public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        super(TYPE, StampFactory.forVoid());
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc);
+    }
+
+    @NodeIntrinsic
+    public static native void jumpToExceptionHandlerInCaller(Word handlerInCallerPc, Object exception, Word exceptionPc);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java
new file mode 100644
index 0000000..f7ca42f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+/**
+ * Jumps to the exception handler specified by {@link #address}. This node is specific for the
+ * {@link ExceptionHandlerStub} and should not be used elswhere.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class JumpToExceptionHandlerNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<JumpToExceptionHandlerNode> TYPE = NodeClass.create(JumpToExceptionHandlerNode.class);
+    @Input ValueNode address;
+
+    public JumpToExceptionHandlerNode(ValueNode address) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandler(address);
+    }
+
+    @NodeIntrinsic
+    public static native void jumpToExceptionHandler(Word address);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveCurrentStackFrameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveCurrentStackFrameNode.java
new file mode 100644
index 0000000..45e076f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveCurrentStackFrameNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Emits code to leave (pop) the current low-level stack frame. This operation also removes the
+ * return address if its location is on the stack.
+ */
+@NodeInfo(cycles = CYCLES_10, size = SIZE_6)
+public final class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<LeaveCurrentStackFrameNode> TYPE = NodeClass.create(LeaveCurrentStackFrameNode.class);
+    @Input SaveAllRegistersNode registerSaver;
+
+    public LeaveCurrentStackFrameNode(ValueNode registerSaver) {
+        super(TYPE, StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp());
+    }
+
+    @NodeIntrinsic
+    public static native void leaveCurrentStackFrame(long registerSaver);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java
new file mode 100644
index 0000000..843dbc6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.stubs.DeoptimizationStub;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Emits code to leave (pop) the current low-level stack frame which is being deoptimized. This node
+ * is only used in {@link DeoptimizationStub}.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_2)
+public final class LeaveDeoptimizedStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<LeaveDeoptimizedStackFrameNode> TYPE = NodeClass.create(LeaveDeoptimizedStackFrameNode.class);
+    @Input ValueNode frameSize;
+    @Input ValueNode initialInfo;
+
+    public LeaveDeoptimizedStackFrameNode(ValueNode frameSize, ValueNode initialInfo) {
+        super(TYPE, StampFactory.forVoid());
+        this.frameSize = frameSize;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value frameSizeValue = gen.operand(frameSize);
+        Value initialInfoValue = gen.operand(initialInfo);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveDeoptimizedStackFrame(frameSizeValue, initialInfoValue);
+    }
+
+    @NodeIntrinsic
+    public static native void leaveDeoptimizedStackFrame(int frameSize, Word initialInfo);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java
new file mode 100644
index 0000000..2c54a4a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Emits code to leave a low-level stack frame specifically to call out to the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@NodeInfo(cycles = CYCLES_10, size = SIZE_6)
+public final class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<LeaveUnpackFramesStackFrameNode> TYPE = NodeClass.create(LeaveUnpackFramesStackFrameNode.class);
+    @Input SaveAllRegistersNode registerSaver;
+
+    public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) {
+        super(TYPE, StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp());
+    }
+
+    @NodeIntrinsic
+    public static native void leaveUnpackFramesStackFrame(long registerSaver);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java
new file mode 100644
index 0000000..b2771d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo
+public final class LoadIndexedPointerNode extends LoadIndexedNode {
+
+    public static final NodeClass<LoadIndexedPointerNode> TYPE = NodeClass.create(LoadIndexedPointerNode.class);
+
+    public LoadIndexedPointerNode(Stamp stamp, ValueNode array, ValueNode index) {
+        super(TYPE, stamp, array, index, JavaKind.Illegal);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java
new file mode 100644
index 0000000..39ddbaf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Node that is used to maintain a stack based counter of how many locks are currently held.
+ */
+@NodeInfo(cycles = NodeCycles.CYCLES_2, size = SIZE_1)
+public final class MonitorCounterNode extends FloatingNode implements LIRLowerable, Node.ValueNumberable {
+    public static final NodeClass<MonitorCounterNode> TYPE = NodeClass.create(MonitorCounterNode.class);
+
+    public MonitorCounterNode(@InjectedNodeParameter WordTypes wordTypes) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
+        VirtualStackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(1, new BitSet(0), null);
+        Value result = gen.getLIRGeneratorTool().emitAddress(counter);
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word counter();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ObjectWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ObjectWriteBarrier.java
new file mode 100644
index 0000000..2d14e9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ObjectWriteBarrier.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo
+public abstract class ObjectWriteBarrier extends WriteBarrier {
+
+    public static final NodeClass<ObjectWriteBarrier> TYPE = NodeClass.create(ObjectWriteBarrier.class);
+    @Input(InputType.Association) protected AddressNode address;
+    @OptionalInput protected ValueNode value;
+    protected final boolean precise;
+
+    protected ObjectWriteBarrier(NodeClass<? extends ObjectWriteBarrier> c, AddressNode address, ValueNode value, boolean precise) {
+        super(c);
+        this.address = address;
+        this.value = value;
+        this.precise = precise;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public AddressNode getAddress() {
+        return address;
+    }
+
+    public boolean usePrecise() {
+        return precise;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PatchReturnAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PatchReturnAddressNode.java
new file mode 100644
index 0000000..f2b9b5d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PatchReturnAddressNode.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+/**
+ * Modifies the return address of the current frame.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<PatchReturnAddressNode> TYPE = NodeClass.create(PatchReturnAddressNode.class);
+    @Input ValueNode address;
+
+    public PatchReturnAddressNode(ValueNode address) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotNodeLIRBuilder) gen).emitPatchReturnAddress(address);
+    }
+
+    @NodeIntrinsic
+    public static native void patchReturnAddress(Word address);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PushInterpreterFrameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PushInterpreterFrameNode.java
new file mode 100644
index 0000000..e779da5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/PushInterpreterFrameNode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the runtime code implementing the uncommon trap logic.
+ */
+@NodeInfo(cycles = CYCLES_8, size = SIZE_6)
+public final class PushInterpreterFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<PushInterpreterFrameNode> TYPE = NodeClass.create(PushInterpreterFrameNode.class);
+    @Input ValueNode framePc;
+    @Input ValueNode frameSize;
+    @Input ValueNode senderSp;
+    @Input ValueNode initialInfo;
+
+    public PushInterpreterFrameNode(ValueNode frameSize, ValueNode framePc, ValueNode senderSp, ValueNode initialInfo) {
+        super(TYPE, StampFactory.forVoid());
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value frameSizeValue = gen.operand(frameSize);
+        Value framePcValue = gen.operand(framePc);
+        Value senderSpValue = gen.operand(senderSp);
+        Value initialInfoValue = gen.operand(initialInfo);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitPushInterpreterFrame(frameSizeValue, framePcValue, senderSpValue, initialInfoValue);
+    }
+
+    @NodeIntrinsic
+    public static native void pushInterpreterFrame(Word frameSize, Word framePc, Word senderSp, Word initialInfo);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SaveAllRegistersNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SaveAllRegistersNode.java
new file mode 100644
index 0000000..e0a2503
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SaveAllRegistersNode.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Saves all allocatable registers.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public final class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<SaveAllRegistersNode> TYPE = NodeClass.create(SaveAllRegistersNode.class);
+    protected SaveRegistersOp saveRegistersOp;
+
+    public SaveAllRegistersNode() {
+        super(TYPE, StampFactory.forKind(JavaKind.Long));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        saveRegistersOp = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitSaveAllRegisters();
+    }
+
+    /**
+     * @return the map from registers to the stack locations in they are saved
+     */
+    public SaveRegistersOp getSaveRegistersOp() {
+        assert saveRegistersOp != null : "saved registers op has not yet been created";
+        return saveRegistersOp;
+    }
+
+    /**
+     * @return a token that couples this node to an {@link UncommonTrapCallNode} so that the latter
+     *         has access to the {@linkplain SaveRegistersOp#getMap register save map}
+     */
+    @NodeIntrinsic
+    public static native long saveAllRegisters();
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java
new file mode 100644
index 0000000..ba95b81
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+@NodeInfo(cycles = CYCLES_15, size = SIZE_20)
+public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
+
+    public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
+
+    public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(TYPE, object, startIndex, length);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java
new file mode 100644
index 0000000..cf03b16
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_8, size = SIZE_3)
+public class SerialWriteBarrier extends ObjectWriteBarrier {
+
+    public static final NodeClass<SerialWriteBarrier> TYPE = NodeClass.create(SerialWriteBarrier.class);
+
+    public SerialWriteBarrier(AddressNode address, boolean precise) {
+        this(TYPE, address, precise);
+    }
+
+    protected SerialWriteBarrier(NodeClass<? extends SerialWriteBarrier> c, AddressNode address, boolean precise) {
+        super(c, address, null, precise);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetAnchorNode.java
new file mode 100644
index 0000000..3fca8fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetAnchorNode.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Anchor;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.InputType.Value;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+@NodeInfo(allowedUsageTypes = {Value, Anchor, Guard}, cycles = CYCLES_0, size = SIZE_0)
+public final class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode {
+    public static final NodeClass<SnippetAnchorNode> TYPE = NodeClass.create(SnippetAnchorNode.class);
+
+    public SnippetAnchorNode() {
+        super(TYPE, StampFactory.object());
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(this);
+        replaceAtUsages(Anchor, prevBegin);
+        replaceAtUsages(Guard, prevBegin);
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            graph().removeFixed(this);
+        }
+    }
+
+    @NodeIntrinsic
+    public static native GuardingNode anchor();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetLocationProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetLocationProxyNode.java
new file mode 100644
index 0000000..061dc11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SnippetLocationProxyNode.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+@NodeInfo(allowedUsageTypes = {InputType.Association, InputType.Value}, cycles = CYCLES_0, size = SIZE_0)
+public final class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable, Node.ValueNumberable {
+
+    public static final NodeClass<SnippetLocationProxyNode> TYPE = NodeClass.create(SnippetLocationProxyNode.class);
+    @Input(InputType.Unchecked) ValueNode location;
+
+    public SnippetLocationProxyNode(ValueNode location) {
+        super(TYPE, StampFactory.object());
+        this.location = location;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return location.isAllowedUsageType(InputType.Association) ? location : this;
+    }
+
+    @NodeIntrinsic
+    public static native GuardingNode location(Object location);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java
new file mode 100644
index 0000000..3d285fc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Node for a {@linkplain ForeignCallDescriptor foreign} call from within a stub.
+ */
+@NodeInfo(nameTemplate = "StubForeignCall#{p#descriptor/s}", allowedUsageTypes = Memory, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+
+    public static final NodeClass<StubForeignCallNode> TYPE = NodeClass.create(StubForeignCallNode.class);
+    @Input NodeInputList<ValueNode> arguments;
+    protected final ForeignCallsProvider foreignCalls;
+
+    protected final ForeignCallDescriptor descriptor;
+
+    public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+        this.foreignCalls = foreignCalls;
+    }
+
+    public ForeignCallDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        LocationIdentity[] killedLocations = foreignCalls.getKilledLocations(descriptor);
+        killedLocations = Arrays.copyOf(killedLocations, killedLocations.length + 1);
+        killedLocations[killedLocations.length - 1] = HotSpotReplacementsUtil.PENDING_EXCEPTION_LOCATION;
+        return killedLocations;
+    }
+
+    protected Value[] operands(NodeLIRBuilderTool gen) {
+        Value[] operands = new Value[arguments.size()];
+        for (int i = 0; i < operands.length; i++) {
+            operands[i] = gen.operand(arguments.get(i));
+        }
+        return operands;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert graph().start() instanceof StubStartNode;
+        ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(descriptor);
+        Value[] operands = operands(gen);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, operands);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + descriptor;
+        }
+        return super.toString(verbosity);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubStartNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubStartNode.java
new file mode 100644
index 0000000..3d63dc5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubStartNode.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StartNode;
+
+/**
+ * Start node for a {@link Stub}'s graph.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class StubStartNode extends StartNode {
+
+    public static final NodeClass<StubStartNode> TYPE = NodeClass.create(StubStartNode.class);
+    protected final Stub stub;
+
+    public StubStartNode(Stub stub) {
+        super(TYPE);
+        this.stub = stub;
+    }
+
+    public Stub getStub() {
+        return stub;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/UncommonTrapCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/UncommonTrapCallNode.java
new file mode 100644
index 0000000..2cee5fc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/UncommonTrapCallNode.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNCOMMON_TRAP;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the runtime code implementing the uncommon trap logic.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<UncommonTrapCallNode> TYPE = NodeClass.create(UncommonTrapCallNode.class);
+    @Input ValueNode trapRequest;
+    @Input ValueNode mode;
+    @Input SaveAllRegistersNode registerSaver;
+    protected final ForeignCallsProvider foreignCalls;
+
+    public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest, ValueNode mode) {
+        super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
+        this.trapRequest = trapRequest;
+        this.mode = mode;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    /**
+     * Returns the node representing the exec_mode/unpack_kind used during this fetch_unroll_info
+     * call.
+     */
+    public ValueNode getMode() {
+        return mode;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value trapRequestValue = gen.operand(trapRequest);
+        Value modeValue = gen.operand(getMode());
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitUncommonTrapCall(trapRequestValue, modeValue, getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word uncommonTrap(long registerSaver, int trapRequest, int mode);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java
new file mode 100644
index 0000000..f88797f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.replacements.nodes.CStringConstant;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Causes the VM to exit with a description of the current Java location and an optional
+ * {@linkplain Log#printf(String, long) formatted} error message specified.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
+
+    public static final NodeClass<VMErrorNode> TYPE = NodeClass.create(VMErrorNode.class);
+    protected final String format;
+    @Input ValueNode value;
+
+    public VMErrorNode(String format, ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.format = format;
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        String whereString;
+        if (stateBefore() != null) {
+            String nl = CodeUtil.NEW_LINE;
+            StringBuilder sb = new StringBuilder("in compiled code associated with frame state:");
+            FrameState fs = stateBefore();
+            while (fs != null) {
+                Bytecode.appendLocation(sb.append(nl).append("\t"), fs.getCode(), fs.bci);
+                fs = fs.outerFrameState();
+            }
+            whereString = sb.toString();
+        } else {
+            ResolvedJavaMethod method = graph().method();
+            whereString = "in compiled code for " + (method == null ? graph().toString() : method.format("%H.%n(%p)"));
+        }
+
+        LIRKind wordKind = gen.getLIRGeneratorTool().getLIRKind(StampFactory.pointer());
+        Value whereArg = gen.getLIRGeneratorTool().emitConstant(wordKind, new CStringConstant(whereString));
+        Value formatArg = gen.getLIRGeneratorTool().emitConstant(wordKind, new CStringConstant(format));
+
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VM_ERROR);
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
+    }
+
+    @NodeIntrinsic
+    public static native void vmError(@ConstantNodeParameter String format, long value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java
new file mode 100644
index 0000000..0d6d459
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo
+public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<WriteBarrier> TYPE = NodeClass.create(WriteBarrier.class);
+
+    protected WriteBarrier(NodeClass<? extends WriteBarrier> c) {
+        super(c, StampFactory.forVoid());
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        assert graph().getGuardsStage().areFrameStatesAtDeopts();
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java
new file mode 100644
index 0000000..31cbf05
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.Constant;
+
+@NodeInfo
+public final class EncodedSymbolNode extends FloatingNode implements Canonicalizable {
+
+    public static final NodeClass<EncodedSymbolNode> TYPE = NodeClass.create(EncodedSymbolNode.class);
+
+    @OptionalInput protected ValueNode value;
+
+    public EncodedSymbolNode(ValueNode value) {
+        super(TYPE, null);
+        assert value != null;
+        this.value = value;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            Constant constant = GraphUtil.foldIfConstantAndRemove(this, value);
+            if (constant != null) {
+                return new ConstantNode(new EncodedSymbolConstant(constant), StampFactory.pointer());
+            }
+        }
+        return this;
+    }
+
+    @NodeIntrinsic(setStampFromReturnType = true)
+    public static native Word encode(Object constant);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java
new file mode 100644
index 0000000..48acc4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable {
+    public static final NodeClass<InitializeKlassNode> TYPE = NodeClass.create(InitializeKlassNode.class);
+
+    @Input ValueNode value;
+
+    public InitializeKlassNode(ValueNode value) {
+        super(TYPE, value.stamp());
+        this.value = value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java
new file mode 100644
index 0000000..03d11fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the VM via a regular stub.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_20)
+public class InitializeKlassStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single {
+    public static final NodeClass<InitializeKlassStubCall> TYPE = NodeClass.create(InitializeKlassStubCall.class);
+
+    @OptionalInput protected ValueNode value;
+    @Input protected ValueNode string;
+    @OptionalInput(InputType.State) protected FrameState stateBefore;
+    protected Constant constant;
+
+    protected InitializeKlassStubCall(ValueNode value, ValueNode string) {
+        super(TYPE, value.stamp());
+        this.value = value;
+        this.string = string;
+    }
+
+    @NodeIntrinsic
+    public static native KlassPointer initializeKlass(KlassPointer value, Object string);
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value stringValue = gen.operand(string);
+        LIRFrameState fs = gen.state(this);
+        assert fs != null : "Frame state should be set";
+        assert constant instanceof HotSpotMetaspaceConstant;
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs);
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java
new file mode 100644
index 0000000..257fc5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.hotspot.word.MethodPointer;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+public class LoadConstantIndirectlyFixedNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable {
+
+    public static final NodeClass<LoadConstantIndirectlyFixedNode> TYPE = NodeClass.create(LoadConstantIndirectlyFixedNode.class);
+
+    @OptionalInput protected ValueNode value;
+    protected Constant constant;
+    protected HotSpotConstantLoadAction action;
+
+    public LoadConstantIndirectlyFixedNode(ValueNode value) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+        this.constant = null;
+        this.action = HotSpotConstantLoadAction.RESOLVE;
+    }
+
+    public LoadConstantIndirectlyFixedNode(ValueNode value, HotSpotConstantLoadAction action) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+        this.constant = null;
+        this.action = action;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value result;
+        if (constant instanceof HotSpotObjectConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant);
+        } else if (constant instanceof HotSpotMetaspaceConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action);
+        } else {
+            throw new PermanentBailoutException("Unsupported constant type: " + constant);
+        }
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action);
+
+    @NodeIntrinsic
+    public static native KlassPointer loadKlass(KlassPointer klassPointer);
+
+    @NodeIntrinsic
+    public static native MethodPointer loadMethod(MethodPointer klassPointer);
+
+    @NodeIntrinsic
+    public static native Object loadObject(Object object);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java
new file mode 100644
index 0000000..10c3c93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+public class LoadConstantIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable {
+
+    public static final NodeClass<LoadConstantIndirectlyNode> TYPE = NodeClass.create(LoadConstantIndirectlyNode.class);
+
+    @OptionalInput protected ValueNode value;
+    protected Constant constant;
+    protected HotSpotConstantLoadAction action;
+
+    public LoadConstantIndirectlyNode(ValueNode value) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+        this.constant = null;
+        this.action = HotSpotConstantLoadAction.RESOLVE;
+    }
+
+    public LoadConstantIndirectlyNode(ValueNode value, HotSpotConstantLoadAction action) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+        this.constant = null;
+        this.action = action;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value result;
+        if (constant instanceof HotSpotObjectConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant);
+        } else if (constant instanceof HotSpotMetaspaceConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action);
+        } else {
+            throw new PermanentBailoutException("Unsupported constant type: " + constant);
+        }
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action);
+
+    @NodeIntrinsic
+    public static native KlassPointer loadKlass(KlassPointer klassPointer);
+
+    @NodeIntrinsic
+    public static native Object loadObject(Object object);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java
new file mode 100644
index 0000000..1b8180b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
+import org.graalvm.compiler.hotspot.word.MethodCountersPointer;
+import org.graalvm.compiler.hotspot.word.MethodPointer;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+public class LoadMethodCountersIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable {
+
+    public static final NodeClass<LoadMethodCountersIndirectlyNode> TYPE = NodeClass.create(LoadMethodCountersIndirectlyNode.class);
+
+    @OptionalInput protected ValueNode value;
+    protected Constant constant;
+
+    public LoadMethodCountersIndirectlyNode(ValueNode value) {
+        super(TYPE, MethodCountersPointerStamp.methodCounters());
+        this.value = value;
+        this.constant = null;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value result;
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, HotSpotConstantLoadAction.LOAD_COUNTERS);
+        } else {
+            throw new PermanentBailoutException("Unsupported constant type: " + constant);
+        }
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native MethodCountersPointer loadMethodCounters(MethodPointer methodPointer);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java
new file mode 100644
index 0000000..290de38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+public class LoadMethodCountersNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<LoadMethodCountersNode> TYPE = NodeClass.create(LoadMethodCountersNode.class);
+
+    ResolvedJavaMethod method;
+
+    public LoadMethodCountersNode(ResolvedJavaMethod method) {
+        super(TYPE, MethodCountersPointerStamp.methodCountersNonNull());
+        this.method = method;
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    public static NodeIterable<LoadMethodCountersNode> getLoadMethodCountersNodes(StructuredGraph graph) {
+        return graph.getNodes().filter(LoadMethodCountersNode.class);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // TODO: With AOT we don't need this, as this node will be replaced.
+        // Implement later when profiling is needed in the JIT mode.
+        throw GraalError.unimplemented();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java
new file mode 100644
index 0000000..17a3e0e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+public class ResolveConstantNode extends FloatingNode implements Lowerable {
+    public static final NodeClass<ResolveConstantNode> TYPE = NodeClass.create(ResolveConstantNode.class);
+
+    @Input ValueNode value;
+    protected HotSpotConstantLoadAction action;
+
+    public ResolveConstantNode(ValueNode value, HotSpotConstantLoadAction action) {
+        super(TYPE, value.stamp());
+        this.value = value;
+        this.action = action;
+    }
+
+    public ResolveConstantNode(ValueNode value) {
+        super(TYPE, value.stamp());
+        this.value = value;
+        this.action = HotSpotConstantLoadAction.RESOLVE;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public HotSpotConstantLoadAction action() {
+        return action;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java
new file mode 100644
index 0000000..017feac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the VM via a regular stub.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20)
+public class ResolveConstantStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable {
+    public static final NodeClass<ResolveConstantStubCall> TYPE = NodeClass.create(ResolveConstantStubCall.class);
+
+    @OptionalInput protected ValueNode value;
+    @Input protected ValueNode string;
+    protected Constant constant;
+    protected HotSpotConstantLoadAction action;
+
+    public ResolveConstantStubCall(ValueNode value, ValueNode string) {
+        super(TYPE, value.stamp());
+        this.value = value;
+        this.string = string;
+        this.action = HotSpotConstantLoadAction.RESOLVE;
+    }
+
+    public ResolveConstantStubCall(ValueNode value, ValueNode string, HotSpotConstantLoadAction action) {
+        super(TYPE, value.stamp());
+        this.value = value;
+        this.string = string;
+        this.action = action;
+    }
+
+    @NodeIntrinsic
+    public static native Object resolveObject(Object value, Object symbol);
+
+    @NodeIntrinsic
+    public static native KlassPointer resolveKlass(KlassPointer value, Object symbol);
+
+    @NodeIntrinsic
+    public static native KlassPointer resolveKlass(KlassPointer value, Object symbol, @ConstantNodeParameter HotSpotConstantLoadAction action);
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value stringValue = gen.operand(string);
+        Value result;
+        LIRFrameState fs = gen.state(this);
+        assert fs != null : "The stateAfter is null";
+        if (constant instanceof HotSpotObjectConstant) {
+            result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs);
+        } else if (constant instanceof HotSpotMetaspaceConstant) {
+            if (action == HotSpotConstantLoadAction.RESOLVE) {
+                result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitMetaspaceConstantRetrieval(constant, stringValue, fs);
+            } else {
+                assert action == HotSpotConstantLoadAction.INITIALIZE;
+                result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs);
+            }
+        } else {
+            throw new PermanentBailoutException("Unsupported constant type: " + constant);
+        }
+        gen.setResult(this, result);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java
new file mode 100644
index 0000000..6561da2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+public class ResolveMethodAndLoadCountersNode extends FloatingNode implements Lowerable {
+    public static final NodeClass<ResolveMethodAndLoadCountersNode> TYPE = NodeClass.create(ResolveMethodAndLoadCountersNode.class);
+
+    ResolvedJavaMethod method;
+    @Input ValueNode hub;
+
+    public ResolveMethodAndLoadCountersNode(ResolvedJavaMethod method, ValueNode hub) {
+        super(TYPE, MethodCountersPointerStamp.methodCountersNonNull());
+        this.method = method;
+        this.hub = hub;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    public ValueNode getHub() {
+        return hub;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java
new file mode 100644
index 0000000..faa0bd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.aot;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall;
+import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.hotspot.word.MethodCountersPointer;
+import org.graalvm.compiler.hotspot.word.MethodPointer;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+/**
+ * A call to the VM via a regular stub.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20)
+public class ResolveMethodAndLoadCountersStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable {
+    public static final NodeClass<ResolveMethodAndLoadCountersStubCall> TYPE = NodeClass.create(ResolveMethodAndLoadCountersStubCall.class);
+
+    @OptionalInput protected ValueNode method;
+    @Input protected ValueNode klassHint;
+    @Input protected ValueNode methodDescription;
+    protected Constant methodConstant;
+
+    public ResolveMethodAndLoadCountersStubCall(ValueNode method, ValueNode klassHint, ValueNode methodDescription) {
+        super(TYPE, MethodCountersPointerStamp.methodCountersNonNull());
+        this.klassHint = klassHint;
+        this.method = method;
+        this.methodDescription = methodDescription;
+    }
+
+    @NodeIntrinsic
+    public static native MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint, Object methodDescription);
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (method != null) {
+            methodConstant = GraphUtil.foldIfConstantAndRemove(this, method);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert methodConstant != null : "Expected method to fold: " + method;
+
+        Value methodDescriptionValue = gen.operand(methodDescription);
+        Value klassHintValue = gen.operand(klassHint);
+        LIRFrameState fs = gen.state(this);
+        assert fs != null : "The stateAfter is null";
+
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveMethodAndLoadCounters(methodConstant, klassHintValue, methodDescriptionValue, fs);
+
+        gen.setResult(this, result);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java
new file mode 100644
index 0000000..d7f4754
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.profiling;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public class ProfileBranchNode extends ProfileWithNotificationNode {
+    public static final NodeClass<ProfileBranchNode> TYPE = NodeClass.create(ProfileBranchNode.class);
+
+    @OptionalInput ValueNode branchCondition;
+    protected int bci;
+    protected int targetBci;
+
+    public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, ConditionalNode branchCondition, int bci, int targetBci) {
+        super(TYPE, method, freqLog, probabilityLog);
+        assert targetBci <= bci;
+        this.branchCondition = branchCondition;
+        this.bci = bci;
+        this.targetBci = targetBci;
+    }
+
+    public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, int bci, int targetBci) {
+        super(TYPE, method, freqLog, probabilityLog);
+        assert targetBci <= bci;
+        this.branchCondition = null;
+        this.bci = bci;
+        this.targetBci = targetBci;
+    }
+
+    public int bci() {
+        return bci;
+    }
+
+    public int targetBci() {
+        return targetBci;
+    }
+
+    public ValueNode branchCondition() {
+        return branchCondition;
+    }
+
+    public boolean hasCondition() {
+        return branchCondition != null;
+    }
+
+    /**
+     * Gathers all the {@link ProfileBranchNode}s that are inputs to the
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
+     */
+    public static NodeIterable<ProfileBranchNode> getProfileBranchNodes(StructuredGraph graph) {
+        return graph.getNodes().filter(ProfileBranchNode.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java
new file mode 100644
index 0000000..03f12cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.profiling;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public class ProfileInvokeNode extends ProfileWithNotificationNode {
+    public static final NodeClass<ProfileInvokeNode> TYPE = NodeClass.create(ProfileInvokeNode.class);
+
+    public ProfileInvokeNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) {
+        super(TYPE, method, freqLog, probabilityLog);
+    }
+
+    /**
+     * Gathers all the {@link ProfileInvokeNode}s that are inputs to the
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
+     */
+    public static NodeIterable<ProfileInvokeNode> getProfileInvokeNodes(StructuredGraph graph) {
+        return graph.getNodes().filter(ProfileInvokeNode.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java
new file mode 100644
index 0000000..9d5e015
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.profiling;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+@NodeInfo
+public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowerable {
+    public static class Options {
+        @Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)//
+        public static final OptionValue<Boolean> ProbabilisticProfiling = new OptionValue<>(true);
+    }
+
+    public static final NodeClass<ProfileNode> TYPE = NodeClass.create(ProfileNode.class);
+
+    protected ResolvedJavaMethod method;
+
+    // Only used if ProbabilisticProfiling == true and may be ignored by lowerer.
+    @OptionalInput protected ValueNode random;
+
+    // logarithm base 2 of the profile probability
+    protected int probabilityLog;
+
+    protected ProfileNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, ResolvedJavaMethod method, int probabilityLog) {
+        super(c, StampFactory.forVoid());
+        this.method = method;
+        this.probabilityLog = probabilityLog;
+    }
+
+    public ProfileNode(ResolvedJavaMethod method, int probabilityLog) {
+        super(TYPE, StampFactory.forVoid());
+        this.method = method;
+        this.probabilityLog = probabilityLog;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ResolvedJavaMethod getProfiledMethod() {
+        return method;
+    }
+
+    public ValueNode getRandom() {
+        return random;
+    }
+
+    public void setRandom(ValueNode r) {
+        updateUsages(random, r);
+        this.random = r;
+    }
+
+    /**
+     * Get the logarithm base 2 of the profile probability.
+     */
+    public int getProbabilityLog() {
+        return probabilityLog;
+    }
+
+    /**
+     * Gathers all the {@link ProfileNode}s that are inputs to the
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
+     */
+    public static NodeIterable<ProfileNode> getProfileNodes(StructuredGraph graph) {
+        return graph.getNodes().filter(ProfileNode.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java
new file mode 100644
index 0000000..4d63dea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.profiling;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo(cycles = CYCLES_10, size = SIZE_50)
+public class ProfileWithNotificationNode extends ProfileNode {
+    public static final NodeClass<ProfileWithNotificationNode> TYPE = NodeClass.create(ProfileWithNotificationNode.class);
+
+    protected int freqLog;
+
+    protected ProfileWithNotificationNode(NodeClass<? extends ProfileNode> c, ResolvedJavaMethod method, int freqLog, int probabilityLog) {
+        super(c, method, probabilityLog);
+        this.freqLog = freqLog;
+    }
+
+    public ProfileWithNotificationNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) {
+        super(TYPE, method, probabilityLog);
+        this.freqLog = freqLog;
+    }
+
+    /**
+     * Get the logarithm base 2 of the notification frequency.
+     */
+    public int getNotificationFreqLog() {
+        return freqLog;
+    }
+
+    /**
+     * Set the logarithm base 2 of the notification frequency.
+     */
+    public void setNotificationFreqLog(int freqLog) {
+        assert freqLog < 32;
+        this.freqLog = freqLog;
+    }
+
+    public void setNotificationOff() {
+        setNotificationFreqLog(-1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java
new file mode 100644
index 0000000..3f048ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.nodes.profiling;
+
+import jdk.vm.ci.meta.Value;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public class RandomSeedNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<RandomSeedNode> TYPE = NodeClass.create(RandomSeedNode.class);
+
+    public RandomSeedNode() {
+        super(TYPE, StampFactory.intValue());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitRandomSeed();
+        gen.setResult(this, result);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java
new file mode 100644
index 0000000..7c8c4fb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+
+/**
+ * Extension of {@link LIRKindTool} that includes support for compressed pointer kinds.
+ */
+public interface HotSpotLIRKindTool extends LIRKindTool {
+
+    /**
+     * Get the platform specific kind used to represent compressed oops.
+     */
+    LIRKind getNarrowOopKind();
+
+    /**
+     * Gets the platform specific kind used to represent compressed metaspace pointers.
+     */
+    LIRKind getNarrowPointerKind();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java
new file mode 100644
index 0000000..51ef44e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import java.util.Objects;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public final class KlassPointerStamp extends MetaspacePointerStamp {
+
+    private static final KlassPointerStamp KLASS = new KlassPointerStamp(false, false);
+
+    private static final KlassPointerStamp KLASS_NON_NULL = new KlassPointerStamp(true, false);
+
+    private static final KlassPointerStamp KLASS_ALWAYS_NULL = new KlassPointerStamp(false, true);
+
+    private final CompressEncoding encoding;
+
+    public static KlassPointerStamp klass() {
+        return KLASS;
+    }
+
+    public static KlassPointerStamp klassNonNull() {
+        return KLASS_NON_NULL;
+    }
+
+    public static KlassPointerStamp klassAlwaysNull() {
+        return KLASS_ALWAYS_NULL;
+    }
+
+    private KlassPointerStamp(boolean nonNull, boolean alwaysNull) {
+        this(nonNull, alwaysNull, null);
+    }
+
+    private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
+        super(nonNull, alwaysNull);
+        this.encoding = encoding;
+    }
+
+    @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding);
+    }
+
+    @Override
+    public boolean isCompatible(Stamp otherStamp) {
+        if (this == otherStamp) {
+            return true;
+        }
+        if (otherStamp instanceof KlassPointerStamp) {
+            KlassPointerStamp other = (KlassPointerStamp) otherStamp;
+            return Objects.equals(this.encoding, other.encoding);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            return ((HotSpotMetaspaceConstant) constant).asResolvedJavaType() != null;
+        } else {
+            return super.isCompatible(constant);
+        }
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        if (isCompressed()) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                return new KlassPointerStamp(false, true, encoding);
+            }
+        } else {
+            if (JavaConstant.NULL_POINTER.equals(c)) {
+                return KLASS_ALWAYS_NULL;
+            }
+        }
+
+        assert c instanceof HotSpotMetaspaceConstant;
+        assert ((HotSpotMetaspaceConstant) c).isCompressed() == isCompressed();
+        if (nonNull()) {
+            return this;
+        }
+        if (isCompressed()) {
+            return new KlassPointerStamp(true, false, encoding);
+        } else {
+            return KLASS_NON_NULL;
+        }
+    }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull() && isCompressed()) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else {
+            return super.asConstant();
+        }
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        if (isCompressed()) {
+            return ((HotSpotLIRKindTool) tool).getNarrowPointerKind();
+        } else {
+            return super.getLIRKind(tool);
+        }
+    }
+
+    public boolean isCompressed() {
+        return encoding != null;
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
+    public KlassPointerStamp compressed(CompressEncoding newEncoding) {
+        assert !isCompressed();
+        return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding);
+    }
+
+    public KlassPointerStamp uncompressed() {
+        assert isCompressed();
+        return new KlassPointerStamp(nonNull(), alwaysNull());
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
+        if (isCompressed()) {
+            return hsProvider.readNarrowKlassPointerConstant(base, displacement);
+        } else {
+            return hsProvider.readKlassPointerConstant(base, displacement);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((encoding == null) ? 0 : encoding.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof KlassPointerStamp)) {
+            return false;
+        }
+        KlassPointerStamp other = (KlassPointerStamp) obj;
+        return Objects.equals(this.encoding, other.encoding);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder ret = new StringBuilder("Klass*");
+        appendString(ret);
+        if (isCompressed()) {
+            ret.append("(compressed ").append(encoding).append(")");
+        }
+        return ret.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MetaspacePointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MetaspacePointerStamp.java
new file mode 100644
index 0000000..4db514d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MetaspacePointerStamp.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public abstract class MetaspacePointerStamp extends AbstractPointerStamp {
+
+    protected MetaspacePointerStamp(boolean nonNull, boolean alwaysNull) {
+        super(nonNull, alwaysNull);
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getWordKind();
+    }
+
+    @Override
+    public Stamp empty() {
+        // there is no empty pointer stamp
+        return this;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        return constant.isDefaultForKind();
+    }
+
+    @Override
+    public boolean hasValues() {
+        return true;
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        throw GraalError.shouldNotReachHere("metaspace pointer has no Java type");
+    }
+
+    protected void appendString(StringBuilder str) {
+        str.append(nonNull() ? "!" : "").append(alwaysNull() ? " NULL" : "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodCountersPointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodCountersPointerStamp.java
new file mode 100644
index 0000000..67271fe3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodCountersPointerStamp.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+
+public final class MethodCountersPointerStamp extends MetaspacePointerStamp {
+
+    private static final MethodCountersPointerStamp METHOD_COUNTERS = new MethodCountersPointerStamp(false, false);
+
+    private static final MethodCountersPointerStamp METHOD_COUNTERS_NON_NULL = new MethodCountersPointerStamp(true, false);
+
+    private static final MethodCountersPointerStamp METHOD_COUNTERS_ALWAYS_NULL = new MethodCountersPointerStamp(false, true);
+
+    public static MethodCountersPointerStamp methodCounters() {
+        return METHOD_COUNTERS;
+    }
+
+    public static MethodCountersPointerStamp methodCountersNonNull() {
+        return METHOD_COUNTERS_NON_NULL;
+    }
+
+    private MethodCountersPointerStamp(boolean nonNull, boolean alwaysNull) {
+        super(nonNull, alwaysNull);
+    }
+
+    @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        if (newNonNull) {
+            assert !newAlwaysNull;
+            return METHOD_COUNTERS_NON_NULL;
+        } else if (newAlwaysNull) {
+            return METHOD_COUNTERS_ALWAYS_NULL;
+        } else {
+            return METHOD_COUNTERS;
+        }
+    }
+
+    @Override
+    public boolean isCompatible(Stamp otherStamp) {
+        if (this == otherStamp) {
+            return true;
+        }
+        return otherStamp instanceof MethodCountersPointerStamp;
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return METHOD_COUNTERS_ALWAYS_NULL;
+        } else {
+            assert c instanceof HotSpotMetaspaceConstant;
+            return METHOD_COUNTERS_NON_NULL;
+        }
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder ret = new StringBuilder("MethodCounters*");
+        appendString(ret);
+        return ret.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodPointerStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodPointerStamp.java
new file mode 100644
index 0000000..4c6cf8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/MethodPointerStamp.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+
+import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public final class MethodPointerStamp extends MetaspacePointerStamp {
+
+    private static final MethodPointerStamp METHOD = new MethodPointerStamp(false, false);
+
+    private static final MethodPointerStamp METHOD_NON_NULL = new MethodPointerStamp(true, false);
+
+    private static final MethodPointerStamp METHOD_ALWAYS_NULL = new MethodPointerStamp(false, true);
+
+    public static MethodPointerStamp method() {
+        return METHOD;
+    }
+
+    public static MethodPointerStamp methodNonNull() {
+        return METHOD_NON_NULL;
+    }
+
+    private MethodPointerStamp(boolean nonNull, boolean alwaysNull) {
+        super(nonNull, alwaysNull);
+    }
+
+    @Override
+    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
+        if (newNonNull) {
+            assert !newAlwaysNull;
+            return METHOD_NON_NULL;
+        } else if (newAlwaysNull) {
+            return METHOD_ALWAYS_NULL;
+        } else {
+            return METHOD;
+        }
+    }
+
+    @Override
+    public boolean isCompatible(Stamp otherStamp) {
+        if (this == otherStamp) {
+            return true;
+        }
+        return otherStamp instanceof MethodPointerStamp;
+    }
+
+    @Override
+    public boolean isCompatible(Constant constant) {
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            return ((HotSpotMetaspaceConstant) constant).asResolvedJavaMethod() != null;
+        } else {
+            return super.isCompatible(constant);
+        }
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return METHOD_ALWAYS_NULL;
+        } else {
+            assert c instanceof HotSpotMetaspaceConstant;
+            return METHOD_NON_NULL;
+        }
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
+        return hsProvider.readMethodPointerConstant(base, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder ret = new StringBuilder("Method*");
+        appendString(ret);
+        return ret.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java
new file mode 100644
index 0000000..5f96876
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.nodes.type;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class NarrowOopStamp extends AbstractObjectStamp {
+
+    private final CompressEncoding encoding;
+
+    public NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
+        super(type, exactType, nonNull, alwaysNull);
+        this.encoding = encoding;
+    }
+
+    @Override
+    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        return new NarrowOopStamp(type, exactType, nonNull, alwaysNull, encoding);
+    }
+
+    public static Stamp compressed(AbstractObjectStamp stamp, CompressEncoding encoding) {
+        return new NarrowOopStamp(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding);
+    }
+
+    public Stamp uncompressed() {
+        return new ObjectStamp(type(), isExactType(), nonNull(), alwaysNull());
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return ((HotSpotLIRKindTool) tool).getNarrowOopKind();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('n');
+        appendString(str);
+        return str.toString();
+    }
+
+    @Override
+    public boolean isCompatible(Stamp other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof NarrowOopStamp) {
+            NarrowOopStamp narrow = (NarrowOopStamp) other;
+            return encoding.equals(narrow.encoding);
+        }
+        return false;
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
+        return hsProvider.readNarrowOopConstant(base, displacement);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + encoding.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        NarrowOopStamp other = (NarrowOopStamp) obj;
+        if (!encoding.equals(other.encoding)) {
+            return false;
+        }
+        return super.equals(other);
+    }
+
+    @Override
+    public JavaConstant asConstant() {
+        if (alwaysNull()) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean isCompatible(Constant other) {
+        if (other instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) other).isCompressed();
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/package-info.java
new file mode 100644
index 0000000..2faa973
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java
new file mode 100644
index 0000000..69e6675
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases;
+
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Checks for {@link #isIllegalObjectConstant(ConstantNode) illegal} object constants in a graph
+ * processed for AOT compilation.
+ *
+ * @see LoadJavaMirrorWithKlassPhase
+ */
+public class AheadOfTimeVerificationPhase extends VerifyPhase<PhaseContext> {
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        for (ConstantNode node : getConstantNodes(graph)) {
+            if (isIllegalObjectConstant(node)) {
+                throw new VerificationError("illegal object constant: " + node);
+            }
+        }
+        return true;
+    }
+
+    public static boolean isIllegalObjectConstant(ConstantNode node) {
+        return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node);
+    }
+
+    private static boolean isObject(ConstantNode node) {
+        return node.getStackKind() == JavaKind.Object;
+    }
+
+    private static boolean isNullReference(ConstantNode node) {
+        return isObject(node) && node.isNullConstant();
+    }
+
+    private static boolean isDirectMethodHandle(ConstantNode node) {
+        if (!isObject(node)) {
+            return false;
+        }
+        return "Ljava/lang/invoke/DirectMethodHandle;".equals(StampTool.typeOrNull(node).getName());
+    }
+
+    private static boolean isBoundMethodHandle(ConstantNode node) {
+        if (!isObject(node)) {
+            return false;
+        }
+        return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle");
+    }
+
+    private static boolean isInternedString(ConstantNode node) {
+        if (!isObject(node)) {
+            return false;
+        }
+
+        HotSpotObjectConstant c = (HotSpotObjectConstant) node.asConstant();
+        return c.isInternedString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java
new file mode 100644
index 0000000..bb5d0f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases;
+
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.FINAL_LOCATION;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.hotspot.HotSpotResolvedPrimitiveType;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * For AOT compilation we aren't allowed to use a {@link Class} reference ({@code javaMirror})
+ * directly. Instead the {@link Class} reference should be obtained from the {@code Klass} object.
+ * The reason for this is, that in Class Data Sharing (CDS) a {@code Klass} object is mapped to a
+ * fixed address in memory, but the {@code javaMirror} is not (which lives in the Java heap).
+ *
+ * Lowering can introduce new {@link ConstantNode}s containing a {@link Class} reference, thus this
+ * phase must be applied after {@link LoweringPhase}.
+ *
+ * @see AheadOfTimeVerificationPhase
+ */
+public class LoadJavaMirrorWithKlassPhase extends BasePhase<PhaseContext> {
+
+    private final int classMirrorOffset;
+    private final CompressEncoding oopEncoding;
+
+    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) {
+        this.classMirrorOffset = classMirrorOffset;
+        this.oopEncoding = oopEncoding;
+    }
+
+    private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, JavaConstant constant) {
+        if (constant instanceof HotSpotObjectConstant) {
+            ConstantReflectionProvider constantReflection = context.getConstantReflection();
+            ResolvedJavaType type = constantReflection.asJavaType(constant);
+            if (type != null) {
+                MetaAccessProvider metaAccess = context.getMetaAccess();
+                Stamp stamp = StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(Class.class)));
+
+                if (type instanceof HotSpotResolvedObjectType) {
+                    ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph);
+                    AddressNode address = graph.unique(new OffsetAddressNode(klass, ConstantNode.forLong(classMirrorOffset, graph)));
+                    ValueNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, stamp));
+
+                    if (((HotSpotObjectConstant) constant).isCompressed()) {
+                        return CompressionNode.compress(read, oopEncoding);
+                    } else {
+                        return read;
+                    }
+                } else {
+                    /*
+                     * Primitive classes are more difficult since they don't have a corresponding
+                     * Klass* so get them from Class.TYPE for the java box type.
+                     */
+                    HotSpotResolvedPrimitiveType primitive = (HotSpotResolvedPrimitiveType) type;
+                    ResolvedJavaType boxingClass = metaAccess.lookupJavaType(primitive.getJavaKind().toBoxedJavaClass());
+                    ConstantNode clazz = ConstantNode.forConstant(context.getConstantReflection().asJavaClass(boxingClass), metaAccess, graph);
+                    HotSpotResolvedJavaField[] a = (HotSpotResolvedJavaField[]) boxingClass.getStaticFields();
+                    HotSpotResolvedJavaField typeField = null;
+                    for (HotSpotResolvedJavaField f : a) {
+                        if (f.getName().equals("TYPE")) {
+                            typeField = f;
+                            break;
+                        }
+                    }
+                    if (typeField == null) {
+                        throw new GraalError("Can't find TYPE field in class");
+                    }
+
+                    if (oopEncoding != null) {
+                        stamp = NarrowOopStamp.compressed((AbstractObjectStamp) stamp, oopEncoding);
+                    }
+                    AddressNode address = graph.unique(new OffsetAddressNode(clazz, ConstantNode.forLong(typeField.offset(), graph)));
+                    ValueNode read = graph.unique(new FloatingReadNode(address, FINAL_LOCATION, null, stamp));
+
+                    if (oopEncoding == null || ((HotSpotObjectConstant) constant).isCompressed()) {
+                        return read;
+                    } else {
+                        return CompressionNode.uncompress(read, oopEncoding);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        for (ConstantNode node : getConstantNodes(graph)) {
+            JavaConstant constant = node.asJavaConstant();
+            ValueNode freadNode = getClassConstantReplacement(graph, context, constant);
+            if (freadNode != null) {
+                node.replace(graph, freadNode);
+            }
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 2.5f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java
new file mode 100644
index 0000000..84f0f33
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases;
+
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.loop.phases.LoopTransformations;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.EntryMarkerNode;
+import org.graalvm.compiler.nodes.EntryProxyNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.extended.OSRLocalNode;
+import org.graalvm.compiler.nodes.extended.OSRStartNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+public class OnStackReplacementPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) {
+            // This happens during inlining in a OSR method, because the same phase plan will be
+            // used.
+            assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty();
+            return;
+        }
+        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement initial");
+        EntryMarkerNode osr;
+        int maxIterations = -1;
+        int iterations = 0;
+        do {
+            osr = getEntryMarker(graph);
+            LoopsData loops = new LoopsData(graph);
+            // Find the loop that contains the EntryMarker
+            Loop<Block> l = loops.getCFG().getNodeToBlock().get(osr).getLoop();
+            if (l == null) {
+                break;
+            }
+            iterations++;
+            if (maxIterations == -1) {
+                maxIterations = l.getDepth();
+            } else if (iterations > maxIterations) {
+                throw GraalError.shouldNotReachHere();
+            }
+            // Peel the outermost loop first
+            while (l.getParent() != null) {
+                l = l.getParent();
+            }
+
+            LoopTransformations.peel(loops.loop(l));
+            osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor()));
+            for (Node usage : osr.usages().snapshot()) {
+                EntryProxyNode proxy = (EntryProxyNode) usage;
+                proxy.replaceAndDelete(proxy.value());
+            }
+            GraphUtil.removeFixedWithUnusedInputs(osr);
+            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement loop peeling result");
+        } while (true);
+
+        FrameState osrState = osr.stateAfter();
+        osr.setStateAfter(null);
+        OSRStartNode osrStart = graph.add(new OSRStartNode());
+        StartNode start = graph.start();
+        FixedNode next = osr.next();
+        osr.setNext(null);
+        osrStart.setNext(next);
+        graph.setStart(osrStart);
+        osrStart.setStateAfter(osrState);
+
+        for (int i = 0; i < osrState.localsSize(); i++) {
+            ValueNode value = osrState.localAt(i);
+            if (value instanceof EntryProxyNode) {
+                EntryProxyNode proxy = (EntryProxyNode) value;
+                /*
+                 * we need to drop the stamp since the types we see during OSR may be too precise
+                 * (if a branch was not parsed for example).
+                 */
+                proxy.replaceAndDelete(graph.addOrUnique(new OSRLocalNode(i, proxy.stamp().unrestricted())));
+            } else {
+                assert value == null || value instanceof OSRLocalNode;
+            }
+        }
+        osr.replaceAtUsages(InputType.Guard, osrStart);
+        assert osr.usages().isEmpty();
+
+        GraphUtil.killCFG(start);
+
+        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result");
+        new DeadCodeEliminationPhase(Required).apply(graph);
+    }
+
+    private static EntryMarkerNode getEntryMarker(StructuredGraph graph) {
+        NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.TYPE);
+        EntryMarkerNode osr = osrNodes.first();
+        if (osr == null) {
+            throw new PermanentBailoutException("No OnStackReplacementNode generated");
+        }
+        if (osrNodes.count() > 1) {
+            throw new GraalError("Multiple OnStackReplacementNodes generated");
+        }
+        if (osr.stateAfter().locksSize() != 0) {
+            throw new PermanentBailoutException("OSR with locks not supported");
+        }
+        if (osr.stateAfter().stackSize() != 0) {
+            throw new PermanentBailoutException("OSR with stack entries not supported: %s", osr.stateAfter().toString(Verbosity.Debugger));
+        }
+        return osr;
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 5.0f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java
new file mode 100644
index 0000000..a252994
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.java.LoweredCompareAndSwapNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.Phase;
+
+public class WriteBarrierAdditionPhase extends Phase {
+
+    private GraalHotSpotVMConfig config;
+
+    public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) {
+        this.config = config;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ReadNode) {
+                addReadNodeBarriers((ReadNode) n, graph);
+            } else if (n instanceof WriteNode) {
+                addWriteNodeBarriers((WriteNode) n, graph);
+            } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+                LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n;
+                addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
+            } else if (n instanceof LoweredCompareAndSwapNode) {
+                addCASBarriers((LoweredCompareAndSwapNode) n, graph);
+            } else if (n instanceof ArrayRangeWriteNode) {
+                ArrayRangeWriteNode node = (ArrayRangeWriteNode) n;
+                if (node.isObjectArray()) {
+                    addArrayRangeBarriers(node, graph);
+                }
+            }
+        }
+    }
+
+    private void addReadNodeBarriers(ReadNode node, StructuredGraph graph) {
+        if (node.getBarrierType() == BarrierType.PRECISE) {
+            assert config.useG1GC;
+            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
+            graph.addAfterFixed(node, barrier);
+        } else {
+            assert node.getBarrierType() == BarrierType.NONE : "Non precise read barrier has been attached to read node.";
+        }
+    }
+
+    protected static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
+        G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck));
+        preBarrier.setStateBefore(node.stateBefore());
+        node.setNullCheck(false);
+        node.setStateBefore(null);
+        graph.addBeforeFixed(node, preBarrier);
+    }
+
+    protected void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
+        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
+        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull)));
+    }
+
+    protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
+        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
+        if (alwaysNull) {
+            // Serial barrier isn't needed for null value
+            return;
+        }
+        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise)));
+    }
+
+    private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
+        BarrierType barrierType = node.getBarrierType();
+        switch (barrierType) {
+            case NONE:
+                // nothing to do
+                break;
+            case IMPRECISE:
+            case PRECISE:
+                boolean precise = barrierType == BarrierType.PRECISE;
+                if (config.useG1GC) {
+                    if (!node.isInitialization()) {
+                        addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
+                    }
+                    addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
+                } else {
+                    addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
+                }
+                break;
+            default:
+                throw new GraalError("unexpected barrier type: " + barrierType);
+        }
+    }
+
+    private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) {
+        BarrierType barrierType = node.getBarrierType();
+        switch (barrierType) {
+            case NONE:
+                // nothing to do
+                break;
+            case IMPRECISE:
+            case PRECISE:
+                boolean precise = barrierType == BarrierType.PRECISE;
+                if (config.useG1GC) {
+                    addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
+                    addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
+                } else {
+                    addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
+                }
+                break;
+            default:
+                throw new GraalError("unexpected barrier type: " + barrierType);
+        }
+    }
+
+    private void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) {
+        BarrierType barrierType = node.getBarrierType();
+        switch (barrierType) {
+            case NONE:
+                // nothing to do
+                break;
+            case IMPRECISE:
+            case PRECISE:
+                boolean precise = barrierType == BarrierType.PRECISE;
+                if (config.useG1GC) {
+                    addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph);
+                    addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
+                } else {
+                    addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
+                }
+                break;
+            default:
+                throw new GraalError("unexpected barrier type: " + barrierType);
+        }
+    }
+
+    private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) {
+        if (config.useG1GC) {
+            if (!node.isInitialization()) {
+                G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
+                graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier);
+            }
+            G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
+            graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier);
+        } else {
+            SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
+            graph.addAfterFixed(node, serialArrayRangeWriteBarrier);
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java
new file mode 100644
index 0000000..1cd9421
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.hotspot.phases;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeFlood;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.ArrayRangeWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.ObjectWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.java.LoweredCompareAndSwapNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.Phase;
+
+/**
+ * Verification phase that checks if, for every write, at least one write barrier is present at all
+ * paths leading to the previous safepoint. For every write, necessitating a write barrier, a
+ * bottom-up traversal of the graph is performed up to the previous safepoints via all possible
+ * paths. If, for a certain path, no write barrier satisfying the processed write is found, an
+ * assertion is generated.
+ */
+public class WriteBarrierVerificationPhase extends Phase {
+
+    private final GraalHotSpotVMConfig config;
+
+    public WriteBarrierVerificationPhase(GraalHotSpotVMConfig config) {
+        this.config = config;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        processWrites(graph);
+    }
+
+    private void processWrites(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            if (isObjectWrite(node) || isObjectArrayRangeWrite(node)) {
+                validateWrite(node);
+            }
+        }
+    }
+
+    private void validateWrite(Node write) {
+        /*
+         * The currently validated write is checked in order to discover if it has an appropriate
+         * attached write barrier.
+         */
+        if (hasAttachedBarrier((FixedWithNextNode) write)) {
+            return;
+        }
+        NodeFlood frontier = write.graph().createNodeFlood();
+        expandFrontier(frontier, write);
+        Iterator<Node> iterator = frontier.iterator();
+        while (iterator.hasNext()) {
+            Node currentNode = iterator.next();
+            if (isSafepoint(currentNode)) {
+                throw new AssertionError("Write barrier must be present " + write);
+            }
+            if (useG1GC()) {
+                if (!(currentNode instanceof G1PostWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
+                    expandFrontier(frontier, currentNode);
+                }
+            } else {
+                if (!(currentNode instanceof SerialWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode)) ||
+                                ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
+                    expandFrontier(frontier, currentNode);
+                }
+            }
+        }
+    }
+
+    private boolean useG1GC() {
+        return config.useG1GC;
+    }
+
+    private boolean hasAttachedBarrier(FixedWithNextNode node) {
+        final Node next = node.next();
+        final Node previous = node.predecessor();
+        final boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization());
+        if (isObjectWrite(node)) {
+            return (isObjectBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isObjectBarrier(node, previous));
+        } else if (isObjectArrayRangeWrite(node)) {
+            return (isArrayBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isArrayBarrier(node, previous));
+        } else {
+            return true;
+        }
+    }
+
+    private static boolean isObjectBarrier(FixedWithNextNode node, final Node next) {
+        return next instanceof ObjectWriteBarrier && validateBarrier((FixedAccessNode) node, (ObjectWriteBarrier) next);
+    }
+
+    private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) {
+        return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject();
+    }
+
+    private static boolean isObjectWrite(Node node) {
+        // Read nodes with barrier attached (G1 Ref field) are not validated yet.
+        return node instanceof FixedAccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode);
+    }
+
+    private static boolean isObjectArrayRangeWrite(Node node) {
+        return node instanceof ArrayRangeWriteNode && ((ArrayRangeWriteNode) node).isObjectArray();
+    }
+
+    private static void expandFrontier(NodeFlood frontier, Node node) {
+        for (Node previousNode : node.cfgPredecessors()) {
+            if (previousNode != null) {
+                frontier.add(previousNode);
+            }
+        }
+    }
+
+    private static boolean isSafepoint(Node node) {
+        /*
+         * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed
+         * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write
+         * barriers inside loops, derived from writes outside loops, can not be permitted.
+         */
+        return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
+    }
+
+    private static ValueNode getValueWritten(FixedWithNextNode write) {
+        if (write instanceof WriteNode) {
+            return ((WriteNode) write).value();
+        } else if (write instanceof LoweredCompareAndSwapNode) {
+            return ((LoweredCompareAndSwapNode) write).getNewValue();
+        } else if (write instanceof LoweredAtomicReadAndWriteNode) {
+            return ((LoweredAtomicReadAndWriteNode) write).getNewValue();
+        } else {
+            throw GraalError.shouldNotReachHere(String.format("unexpected write node %s", write));
+        }
+    }
+
+    private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) {
+        assert write instanceof WriteNode || write instanceof LoweredCompareAndSwapNode || write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write;
+        if (!barrier.usePrecise()) {
+            if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) {
+                return ((OffsetAddressNode) barrier.getAddress()).getBase() == ((OffsetAddressNode) write.getAddress()).getBase();
+            }
+        }
+        return barrier.getAddress() == write.getAddress();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java
new file mode 100644
index 0000000..8f1efa3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases.aot;
+
+import static org.graalvm.compiler.core.common.GraalOptions.InlineEverything;
+import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize;
+
+import java.util.Map;
+
+import org.graalvm.compiler.hotspot.FingerprintUtil;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
+import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+
+public class AOTInliningPolicy extends GreedyInliningPolicy {
+    public static class Options {
+        // @formatter:off
+        @Option(help = "", type = OptionType.Expert)
+        public static final OptionValue<Double> AOTInliningDepthToSizeRate = new OptionValue<>(2.5);
+        @Option(help = "", type = OptionType.Expert)
+        public static final OptionValue<Integer> AOTInliningSizeMaximum = new OptionValue<>(300);
+        @Option(help = "", type = OptionType.Expert)
+        public static final OptionValue<Integer> AOTInliningSizeMinimum = new OptionValue<>(50);
+        // @formatter:on
+    }
+
+    public AOTInliningPolicy(Map<Invoke, Double> hints) {
+        super(hints);
+    }
+
+    protected double maxInliningSize(int inliningDepth) {
+        return Math.max(Options.AOTInliningSizeMaximum.getValue() / (inliningDepth * Options.AOTInliningDepthToSizeRate.getValue()), Options.AOTInliningSizeMinimum.getValue());
+    }
+
+    @Override
+    public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+        final InlineInfo info = invocation.callee();
+
+        for (int i = 0; i < info.numberOfMethods(); ++i) {
+            HotSpotResolvedObjectType t = (HotSpotResolvedObjectType) info.methodAt(i).getDeclaringClass();
+            if (FingerprintUtil.getFingerprint(t) == 0) {
+                return false;
+            }
+        }
+
+        final double probability = invocation.probability();
+        final double relevance = invocation.relevance();
+
+        if (InlineEverything.getValue()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+            return true;
+        }
+
+        if (isIntrinsic(replacements, info)) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+            return true;
+        }
+
+        if (info.shouldInline()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+            return true;
+        }
+
+        double inliningBonus = getInliningBonus(info);
+        int nodes = info.determineNodeCount();
+
+        if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+            return true;
+        }
+
+        double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth) * inliningBonus));
+        if (nodes <= maximumNodes) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+                            nodes, maximumNodes);
+            return true;
+        }
+
+        InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java
new file mode 100644
index 0000000..46d8be1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases.aot;
+
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class EliminateRedundantInitializationPhase extends BasePhase<PhaseContext> {
+    /**
+     * Find blocks with class initializing nodes for the class identified the by the constant node.
+     * Return the map of a block to a list of initializing nodes in that block.
+     *
+     * @param cfg an instance of the {@link ControlFlowGraph}.
+     * @param constant common input to the instances of {@link InitializeKlassNode}.
+     * @return map of blocks to lists of initializing nodes.
+     */
+    private static HashMap<Block, ArrayList<Node>> findBlocksWithInitializers(ControlFlowGraph cfg, ConstantNode constant) {
+        // node is ConstantNode representing a metaspace constant (a klass reference).
+        // InitializeKlassNodes for the same class would share the same ConstantNode input.
+        NodeIterable<?> initializers = constant.usages().filter(InitializeKlassNode.class);
+        // Map the found nodes to blocks
+        HashMap<Block, ArrayList<Node>> blockToInits = new HashMap<>();
+        for (Node i : initializers) {
+            Block b = cfg.blockFor(i);
+            ArrayList<Node> initsInBlock = blockToInits.get(b);
+            if (initsInBlock == null) {
+                initsInBlock = new ArrayList<>();
+            }
+            initsInBlock.add(i);
+            blockToInits.put(b, initsInBlock);
+        }
+        return blockToInits;
+    }
+
+    /**
+     * Process the block-to-initializers map and produce a list of blocks that contain more than one
+     * instance of {@link InitializeKlassNode}.
+     *
+     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
+     * @return list of blocks that contain multiple instances of {@link InitializeKlassNode}.
+     */
+    private static ArrayList<Block> findBlocksWithMultipleInitializers(HashMap<Block, ArrayList<Node>> blockToInits) {
+        ArrayList<Block> result = new ArrayList<>();
+        // Select the blocks from the blocksToInits map that have more than one InitializeKlassNode
+        for (Entry<Block, ArrayList<Node>> e : blockToInits.entrySet()) {
+            if (e.getValue().size() > 1) {
+                result.add(e.getKey());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Iterate through blocks with multiple instances of {@link InitializeKlassNode} and identify
+     * redundant instances. Remove redundant instances from the block-to-list-of-initializer map.
+     *
+     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
+     * @param blocksWithMultipleInits a list of blocks that contain multiple instances of
+     *            {@link InitializeKlassNode}.
+     * @param constant common input to the instances of {@link InitializeKlassNode}.
+     * @return list of {@link InitializeKlassNode} instances that can be removed.
+     */
+    private static ArrayList<Node> findRedundantLocalInitializers(HashMap<Block, ArrayList<Node>> blockToInits, ArrayList<Block> blocksWithMultipleInits, ConstantNode constant) {
+        ArrayList<Node> result = new ArrayList<>();
+        for (Block b : blocksWithMultipleInits) {
+            // First initializer for our constant in the block
+            InitializeKlassNode first = null;
+            for (Node n : b.getNodes()) {
+                if (n instanceof InitializeKlassNode) {
+                    InitializeKlassNode i = (InitializeKlassNode) n;
+                    if (i.value() == constant) {
+                        if (first == null) {
+                            // First instance of {@link InitializeKlassNode} stays.
+                            first = i;
+                        } else {
+                            // All the following instances of {@link InitializeKlassNode} can be
+                            // removed.
+                            result.add(i);
+                        }
+                    }
+                }
+            }
+            assert first != null;
+
+            // Replace the entry in the initsInBlock map to contain just a single initializer
+            ArrayList<Node> initsInBlock = new ArrayList<>();
+            initsInBlock.add(first);
+            blockToInits.put(b, initsInBlock);
+        }
+        return result;
+    }
+
+    /**
+     * Find cases when one {@link InitializeKlassNode} instance dominates another. The dominated
+     * instance can be removed.
+     *
+     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
+     * @return list of {@link InitializeKlassNode} instances that can be removed.
+     */
+    private static ArrayList<Node> findRedundantGlobalInitializers(HashMap<Block, ArrayList<Node>> blockToInits) {
+        ArrayList<Node> result = new ArrayList<>();
+        for (Entry<Block, ArrayList<Node>> e : blockToInits.entrySet()) {
+            Block currentBlock = e.getKey();
+            ArrayList<Node> nodesInCurrent = e.getValue();
+            if (nodesInCurrent != null) { // if the list is null, the initializer has already been
+                                          // eliminated.
+                for (Block d : currentBlock.getDominated()) {
+                    ArrayList<Node> nodesInDominated = blockToInits.get(d);
+                    if (nodesInDominated != null) { // if the list is null, the initializer has
+                                                    // already been eliminated.
+                        assert nodesInDominated.size() == 1;
+                        Node n = nodesInDominated.iterator().next();
+                        result.add(n);
+                        blockToInits.put(d, null);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Compute the list of redundant {@link InitializeKlassNode} instances that have the common
+     * {@link ConstantNode}.
+     *
+     * @param cfg an instance of the {@link ControlFlowGraph}.
+     * @param constant common input to the instances of {@link InitializeKlassNode}.
+     * @return list of {@link InitializeKlassNode} instances that can be removed.
+     */
+    private static ArrayList<Node> processConstantNode(ControlFlowGraph cfg, ConstantNode constant) {
+        HashMap<Block, ArrayList<Node>> blockToInits = findBlocksWithInitializers(cfg, constant);
+        ArrayList<Block> blocksWithMultipleInits = findBlocksWithMultipleInitializers(blockToInits);
+        ArrayList<Node> redundantInits = findRedundantLocalInitializers(blockToInits, blocksWithMultipleInits, constant);
+        // At this point each block has at most one initializer for this constant
+        if (blockToInits.size() > 1) {
+            redundantInits.addAll(findRedundantGlobalInitializers(blockToInits));
+        }
+        return redundantInits;
+    }
+
+    /**
+     * Find each {@link Invoke} that has a corresponding {@link InitializeKlassNode}. These
+     * {@link InitializeKlassNode} are redundant and are removed.
+     *
+     */
+    private static void removeInitsAtStaticCalls(StructuredGraph graph) {
+        for (Invoke invoke : graph.getInvokes()) {
+            if (invoke.classInit() != null) {
+                Node classInit = invoke.classInit();
+                classInit.replaceAtUsages(null);
+                graph.removeFixed((FixedWithNextNode) classInit);
+            }
+        }
+    }
+
+    /**
+     * Find {@link InitializeKlassNode} instances that can be removed because there is an existing
+     * dominating initialization.
+     *
+     * @param graph the program graph.
+     */
+    private static void removeRedundantInits(StructuredGraph graph) {
+        // Create cfg, we need blocks and dominators.
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, false);
+        ArrayList<Node> redundantInits = new ArrayList<>();
+        for (ConstantNode node : getConstantNodes(graph)) {
+            JavaConstant constant = node.asJavaConstant();
+            if (constant instanceof HotSpotMetaspaceConstant) {
+                redundantInits.addAll(processConstantNode(cfg, node));
+            }
+        }
+        // Remove redundant instances of {@link InitializeKlassNode} from the graph.
+        for (Node n : redundantInits) {
+            graph.removeFixed((FixedWithNextNode) n);
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        removeInitsAtStaticCalls(graph);
+        removeRedundantInits(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java
new file mode 100644
index 0000000..2766877
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases.aot;
+
+import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes;
+import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+
+import java.util.HashSet;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.FingerprintUtil;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
+
+    private static final HashSet<Class<?>> builtIns = new HashSet<>();
+
+    static {
+        builtIns.add(Boolean.class);
+
+        Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
+        assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName());
+        builtIns.add(characterCacheClass);
+
+        Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
+        assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName());
+        builtIns.add(byteCacheClass);
+
+        Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0];
+        assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName());
+        builtIns.add(shortCacheClass);
+
+        Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0];
+        assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName());
+        builtIns.add(integerCacheClass);
+
+        Class<?> longCacheClass = Long.class.getDeclaredClasses()[0];
+        assert "java.lang.Long$LongCache".equals(longCacheClass.getName());
+        builtIns.add(longCacheClass);
+    }
+
+    private static boolean isReplacementNode(Node n) {
+        // @formatter:off
+        return n instanceof LoadConstantIndirectlyNode      ||
+               n instanceof LoadConstantIndirectlyFixedNode ||
+               n instanceof ResolveConstantNode             ||
+               n instanceof InitializeKlassNode;
+        // @formatter:on
+    }
+
+    private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) {
+        if (type.isArray()) {
+            if (type.getElementalType().isPrimitive()) {
+                return false;
+            }
+            return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0;
+        }
+        return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0;
+    }
+
+    private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
+        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
+
+        if (type != null) {
+            if (checkForBadFingerprint(type)) {
+                throw new GraalError("Type with bad fingerprint: " + type);
+            }
+
+            assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
+            ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
+            ValueNode replacement;
+
+            if (type.isArray() && type.getComponentType().isPrimitive()) {
+                // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
+                // omit the resolution call.
+                replacement = new LoadConstantIndirectlyNode(node);
+            } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
+                // If it's a supertype of or the same class that declares the top method, we are
+                // guaranteed to have it resolved already. If it's an interface, we just test for
+                // equality.
+                replacement = new LoadConstantIndirectlyNode(node);
+            } else if (builtIns.contains(type.mirror())) {
+                // Special case of klass constants that come from {@link BoxingSnippets}.
+                replacement = new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE);
+            } else {
+                replacement = new ResolveConstantNode(node);
+            }
+
+            node.replaceAtUsages(graph.addOrUnique(replacement), n -> !isReplacementNode(n));
+        } else {
+            throw new GraalError("Unsupported metaspace constant type: " + type);
+        }
+    }
+
+    private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) {
+        HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant();
+        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
+        if (type.mirror().equals(String.class)) {
+            assert !constant.isCompressed() : "No support for replacing compressed oop constants";
+            ValueNode replacement = graph.unique(new ResolveConstantNode(node));
+            node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode));
+        } else {
+            throw new GraalError("Unsupported object constant type: " + type);
+        }
+    }
+
+    private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) {
+        ResolvedJavaType type = node.getMethod().getDeclaringClass();
+        Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
+        ConstantReflectionProvider constantReflection = context.getConstantReflection();
+        ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph);
+        ValueNode replacement = graph.unique(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint));
+        node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode));
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
+        // constants.
+        for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
+            handleLoadMethodCounters(graph, node, context);
+        }
+
+        // Replace object and klass constants (including the ones added in the previous pass) with
+        // resolution nodes.
+        for (ConstantNode node : getConstantNodes(graph)) {
+            Constant constant = node.asConstant();
+            if (constant instanceof HotSpotMetaspaceConstant) {
+                handleHotSpotMetaspaceConstant(graph, node);
+            } else if (constant instanceof HotSpotObjectConstant) {
+                handleHotSpotObjectConstant(graph, node);
+            }
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java
new file mode 100644
index 0000000..e0fe3c7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.phases.profiling;
+
+import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode.getProfileInvokeNodes;
+import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode.getProfileNodes;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class FinalizeProfileNodesPhase extends BasePhase<PhaseContext> {
+    private int inlineeInvokeNotificationFreqLog;
+
+    public static class Options {
+        @Option(help = "Profile simple methods", type = OptionType.Expert)//
+        public static final OptionValue<Boolean> ProfileSimpleMethods = new OptionValue<>(true);
+        @Option(help = "Maximum number of nodes in a graph for a simple method", type = OptionType.Expert)//
+        public static final OptionValue<Integer> SimpleMethodGraphSize = new OptionValue<>(256);
+        @Option(help = "Maximum number of calls in a simple method", type = OptionType.Expert)//
+        public static final OptionValue<Integer> SimpleMethodCalls = new OptionValue<>(1);
+        @Option(help = "Maximum number of indirect calls in a simple moethod", type = OptionType.Expert)//
+        public static final OptionValue<Integer> SimpleMethodIndirectCalls = new OptionValue<>(0);
+
+    }
+
+    public FinalizeProfileNodesPhase(int inlineeInvokeNotificationFreqLog) {
+        this.inlineeInvokeNotificationFreqLog = inlineeInvokeNotificationFreqLog;
+    }
+
+    private static void removeAllProfilingNodes(StructuredGraph graph) {
+        getProfileNodes(graph).forEach((n) -> GraphUtil.removeFixedWithUnusedInputs(n));
+    }
+
+    private void assignInlineeInvokeFrequencies(StructuredGraph graph) {
+        for (ProfileInvokeNode node : getProfileInvokeNodes(graph)) {
+            ResolvedJavaMethod profiledMethod = node.getProfiledMethod();
+            if (!profiledMethod.equals(graph.method())) {
+                // Some inlinee, reassign the inlinee frequency
+                node.setNotificationFreqLog(inlineeInvokeNotificationFreqLog);
+            }
+        }
+    }
+
+    // Hacky heuristic to determine whether we want any profiling in this method.
+    // The heuristic is applied after the graph is fully formed and before the first lowering.
+    private static boolean simpleMethodHeuristic(StructuredGraph graph) {
+        if (Options.ProfileSimpleMethods.getValue()) {
+            return false;
+        }
+
+        // Check if the graph is smallish..
+        if (graph.getNodeCount() > Options.SimpleMethodGraphSize.getValue()) {
+            return false;
+        }
+
+        // Check if method has loops
+        if (graph.hasLoops()) {
+            return false;
+        }
+
+        // Check if method has calls
+        if (graph.getNodes().filter(InvokeNode.class).count() > Options.SimpleMethodCalls.getValue()) {
+            return false;
+        }
+
+        // Check if method has calls that need profiling
+        if (graph.getNodes().filter(InvokeNode.class).filter((n) -> ((InvokeNode) n).getInvokeKind().isIndirect()).count() > Options.SimpleMethodIndirectCalls.getDefaultValue()) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private static void assignRandomSources(StructuredGraph graph) {
+        ValueNode seed = graph.unique(new RandomSeedNode());
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false);
+        Map<LoopBeginNode, ValueNode> loopRandomValueCache = new HashMap<>();
+
+        for (ProfileNode node : getProfileNodes(graph)) {
+            ValueNode random;
+            Block block = cfg.blockFor(node);
+            Loop<Block> loop = block.getLoop();
+            // Inject <a href=https://en.wikipedia.org/wiki/Linear_congruential_generator>LCG</a>
+            // pseudo-random number generator into the loop
+            if (loop != null) {
+                LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
+                random = loopRandomValueCache.get(loopBegin);
+                if (random == null) {
+                    PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(), loopBegin));
+                    phi.addInput(seed);
+                    // X_{n+1} = a*X_n + c, using glibc-like constants
+                    ValueNode a = ConstantNode.forInt(1103515245, graph);
+                    ValueNode c = ConstantNode.forInt(12345, graph);
+                    ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a)));
+                    for (int i = 0; i < loopBegin.getLoopEndCount(); i++) {
+                        phi.addInput(next);
+                    }
+                    random = phi;
+                    loopRandomValueCache.put(loopBegin, random);
+                }
+            } else {
+                // Graal doesn't compile methods with irreducible loops. So all profile nodes that
+                // are not in a loop are guaranteed to be executed at most once. We feed the seed
+                // value to such nodes directly.
+                random = seed;
+            }
+            node.setRandom(random);
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (simpleMethodHeuristic(graph)) {
+            removeAllProfilingNodes(graph);
+            return;
+        }
+
+        assignInlineeInvokeFrequencies(graph);
+        if (ProfileNode.Options.ProbabilisticProfiling.getValue()) {
+            assignRandomSources(graph);
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java
new file mode 100644
index 0000000..3dfb421
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods.
+ */
+@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true)
+public class AESCryptSubstitutions {
+
+    static final long kOffset;
+    static final long lastKeyOffset;
+    static final Class<?> AESCryptClass;
+    static final int AES_BLOCK_SIZE;
+
+    static {
+        try {
+            // Need to use the system class loader as com.sun.crypto.provider.AESCrypt
+            // is normally loaded by the extension class loader which is not delegated
+            // to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+            AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl);
+            kOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("K"));
+            lastKeyOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("lastKey"));
+            Field aesBlockSizeField = Class.forName("com.sun.crypto.provider.AESConstants", true, cl).getDeclaredField("AES_BLOCK_SIZE");
+            aesBlockSizeField.setAccessible(true);
+            AES_BLOCK_SIZE = aesBlockSizeField.getInt(null);
+        } catch (Exception ex) {
+            throw new GraalError(ex);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, true, false);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void implEncryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, true, false);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, false);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void implDecryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, false);
+    }
+
+    /**
+     * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility
+     * issues between Java key expansion and hardware crypto instructions.
+     */
+    @MethodSubstitution(value = "decryptBlock", isStatic = false)
+    static void decryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, true);
+    }
+
+    /**
+     * @see #decryptBlockWithOriginalKey(Object, byte[], int, byte[], int)
+     */
+    @MethodSubstitution(value = "implDecryptBlock", isStatic = false)
+    static void implDecryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, true);
+    }
+
+    private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt, boolean withOriginalKey) {
+        checkArgs(in, inOffset, out, outOffset);
+        Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass);
+        Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, JavaKind.Object, LocationIdentity.any());
+        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
+        Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
+        Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
+        if (encrypt) {
+            encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr);
+        } else {
+            if (withOriginalKey) {
+                Object lastKeyObject = UnsafeLoadNode.load(realReceiver, lastKeyOffset, JavaKind.Object, LocationIdentity.any());
+                Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte));
+                decryptBlockWithOriginalKeyStub(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, lastKeyAddr);
+            } else {
+                decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr);
+            }
+        }
+    }
+
+    /**
+     * Perform null and array bounds checks for arguments to a cipher operation.
+     */
+    static void checkArgs(byte[] in, int inOffset, byte[] out, int outOffset) {
+        if (probability(VERY_SLOW_PATH_PROBABILITY, inOffset < 0 || in.length - AES_BLOCK_SIZE < inOffset || outOffset < 0 || out.length - AES_BLOCK_SIZE < outOffset)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptBlockWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer originalKey);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java
new file mode 100644
index 0000000..a99dbd4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubStartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class AssertionSnippets implements Snippets {
+
+    /**
+     * This call can only be used with true for the "vmError" parameter, so that it can be
+     * configured to be a leaf method.
+     */
+    public static final ForeignCallDescriptor ASSERTION_VM_MESSAGE_C = new ForeignCallDescriptor("assertionVmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    @Snippet
+    public static void assertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @Snippet
+    public static void stubAssertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo assertion = snippet(AssertionSnippets.class, "assertion");
+        private final SnippetInfo stubAssertion = snippet(AssertionSnippets.class, "stubAssertion");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(AssertionNode assertionNode, LoweringTool tool) {
+            StructuredGraph graph = assertionNode.graph();
+            Arguments args = new Arguments(graph.start() instanceof StubStartNode ? stubAssertion : assertion, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("value", assertionNode.value());
+            args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")");
+
+            template(args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/BigIntegerSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/BigIntegerSubstitutions.java
new file mode 100644
index 0000000..7fb1e52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/BigIntegerSubstitutions.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayStart;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+
+@ClassSubstitution(className = "java.math.BigInteger", optional = true)
+public class BigIntegerSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    static int[] multiplyToLen(@SuppressWarnings("unused") Object receiver, int[] x, int xlen, int[] y, int ylen, int[] zIn) {
+        return multiplyToLenStatic(x, xlen, y, ylen, zIn);
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int[] multiplyToLenStatic(int[] x, int xlen, int[] y, int ylen, int[] zIn) {
+        int[] zResult = zIn;
+        int zLen;
+        if (zResult == null || zResult.length < (xlen + ylen)) {
+            zLen = xlen + ylen;
+            zResult = new int[xlen + ylen];
+        } else {
+            zLen = zIn.length;
+        }
+        HotSpotBackend.multiplyToLenStub(arrayStart(x), xlen, arrayStart(y), ylen, arrayStart(zResult), zLen);
+        return zResult;
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
+        int[] outNonNull = GraalDirectives.guardingNonNull(out);
+        int newOffset = outNonNull.length - offset;
+        return HotSpotBackend.mulAddStub(arrayStart(outNonNull), arrayStart(in), newOffset, len, k);
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
+        int[] outNonNull = GraalDirectives.guardingNonNull(out);
+        int newOffset = outNonNull.length - offset;
+        return HotSpotBackend.mulAddStub(arrayStart(outNonNull), arrayStart(in), newOffset, len, k);
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv, int[] product) {
+        HotSpotBackend.implMontgomeryMultiply(arrayStart(a), arrayStart(b), arrayStart(n), len, inv, arrayStart(product));
+        return product;
+
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int[] implMontgomerySquare(int[] a, int[] n, int len, long inv, int[] product) {
+        HotSpotBackend.implMontgomerySquare(arrayStart(a), arrayStart(n), len, inv, arrayStart(product));
+        return product;
+    }
+
+    @MethodSubstitution(isStatic = true)
+    static int[] implSquareToLen(int[] x, int len, int[] z, int zLen) {
+        HotSpotBackend.implSquareToLen(arrayStart(x), len, arrayStart(z), zLen);
+        return z;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java
new file mode 100644
index 0000000..218b4f0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
+
+import java.util.zip.CRC32;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link CRC32}.
+ */
+@ClassSubstitution(CRC32.class)
+public class CRC32Substitutions {
+
+    /**
+     * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}.
+     */
+    @Fold
+    static long crcTableAddress(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.crcTableAddress;
+    }
+
+    @MethodSubstitution
+    static int update(int crc, int b) {
+        final long crcTableRawAddress = GraalHotSpotVMConfigNode.crcTableAddress();
+
+        int c = ~crc;
+        int index = (b ^ c) & 0xFF;
+        int offset = index << 2;
+        int result = Word.unsigned(crcTableRawAddress).readInt(offset);
+        result = result ^ (c >>> 8);
+        return ~result;
+    }
+
+    @MethodSubstitution
+    static int updateBytes(int crc, byte[] buf, int off, int len) {
+        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
+        return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
+    }
+
+    /**
+     * @since 9
+     */
+    @MethodSubstitution(optional = true)
+    static int updateBytes0(int crc, byte[] buf, int off, int len) {
+        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
+        return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
+    }
+
+    @MethodSubstitution
+    static int updateByteBuffer(int crc, long addr, int off, int len) {
+        Word bufAddr = Word.unsigned(addr).add(off);
+        return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
+    }
+
+    /**
+     * @since 9
+     */
+    @MethodSubstitution(optional = true)
+    static int updateByteBuffer0(int crc, long addr, int off, int len) {
+        Word bufAddr = Word.unsigned(addr).add(off);
+        return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
+    }
+
+    public static final ForeignCallDescriptor UPDATE_BYTES_CRC32 = new ForeignCallDescriptor("updateBytesCRC32", int.class, int.class, Word.class, int.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native int updateBytesCRC32(@ConstantNodeParameter ForeignCallDescriptor descriptor, int crc, Word buf, int length);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java
new file mode 100644
index 0000000..c3d7547
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode;
+
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public final class CallSiteTargetNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
+
+    public static final NodeClass<CallSiteTargetNode> TYPE = NodeClass.create(CallSiteTargetNode.class);
+
+    public CallSiteTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnStamp, receiver);
+    }
+
+    private ValueNode getCallSite() {
+        return arguments.get(0);
+    }
+
+    public static ConstantNode tryFold(ValueNode callSite, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        if (callSite != null && callSite.isConstant() && !callSite.isNullConstant()) {
+            HotSpotObjectConstant c = (HotSpotObjectConstant) callSite.asConstant();
+            JavaConstant target = c.getCallSiteTarget(assumptions);
+            if (target != null) {
+                return ConstantNode.forConstant(target, metaAccess);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
+        if (target != null) {
+            return target;
+        }
+
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
+
+        if (target != null) {
+            graph().replaceFixedWithFloating(this, target);
+        } else {
+            InvokeNode invoke = createInvoke();
+            graph().replaceFixedWithFixed(this, invoke);
+            invoke.lower(tool);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java
new file mode 100644
index 0000000..ab52ce2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT;
+import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods.
+ */
+@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining", optional = true)
+public class CipherBlockChainingSubstitutions {
+
+    private static final long embeddedCipherOffset;
+    private static final long rOffset;
+    private static final Class<?> cipherBlockChainingClass;
+    private static final Class<?> feedbackCipherClass;
+    static {
+        try {
+            // Need to use the system class loader as com.sun.crypto.provider.FeedbackCipher
+            // is normally loaded by the extension class loader which is not delegated
+            // to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+
+            feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl);
+            embeddedCipherOffset = UNSAFE.objectFieldOffset(feedbackCipherClass.getDeclaredField("embeddedCipher"));
+
+            cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl);
+            rOffset = UNSAFE.objectFieldOffset(cipherBlockChainingClass.getDeclaredField("r"));
+        } catch (Exception ex) {
+            throw new GraalError(ex);
+        }
+    }
+
+    @Fold
+    static Class<?> getAESCryptClass() {
+        return AESCryptSubstitutions.AESCryptClass;
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
+            return inLength;
+        } else {
+            return encrypt(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false, value = "implEncrypt")
+    static int implEncrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
+            return inLength;
+        } else {
+            return implEncrypt(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
+            return inLength;
+        } else {
+            return decrypt(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static int implDecrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
+            return inLength;
+        } else {
+            return implDecrypt(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    /**
+     * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility
+     * issues between Java key expansion and hardware crypto instructions.
+     */
+    @MethodSubstitution(isStatic = false, value = "decrypt")
+    static int decryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
+            return inLength;
+        } else {
+            return decryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    /**
+     * @see #decryptWithOriginalKey(Object, byte[], int, int, byte[], int)
+     */
+    @MethodSubstitution(isStatic = false, value = "implDecrypt")
+    static int implDecryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
+            return inLength;
+        } else {
+            return implDecryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) {
+        AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset);
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object aesCipher = getAESCryptClass().cast(embeddedCipher);
+        Object kObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any());
+        Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any());
+        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
+        Pointer rAddr = Word.objectToTrackedPointer(rObject).add(getArrayBaseOffset(JavaKind.Byte));
+        Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
+        Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
+        if (encrypt) {
+            encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
+        } else {
+            if (withOriginalKey) {
+                Object lastKeyObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.lastKeyOffset, JavaKind.Object, LocationIdentity.any());
+                Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte));
+                decryptAESCryptWithOriginalKeyStub(DECRYPT_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, rAddr, inLength, lastKeyAddr);
+            } else {
+                decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
+            }
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptAESCryptWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength, Pointer originalKey);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java
new file mode 100644
index 0000000..ea6af4d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FloatingGuardedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConvertNode;
+import org.graalvm.compiler.nodes.extended.GetClassNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Read {@code Class::_klass} to get the hub for a {@link java.lang.Class}. This node mostly exists
+ * to replace {@code _klass._java_mirror._klass} with {@code _klass}. The constant folding could be
+ * handled by
+ * {@link ReadNode#canonicalizeRead(ValueNode, AddressNode, LocationIdentity, CanonicalizerTool)}.
+ */
+@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+public final class ClassGetHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
+    public static final NodeClass<ClassGetHubNode> TYPE = NodeClass.create(ClassGetHubNode.class);
+    @Input protected ValueNode clazz;
+
+    public ClassGetHubNode(ValueNode clazz) {
+        this(clazz, null);
+    }
+
+    public ClassGetHubNode(ValueNode clazz, ValueNode guard) {
+        super(TYPE, KlassPointerStamp.klass(), (GuardingNode) guard);
+        this.clazz = clazz;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        } else {
+            if (clazz.isConstant()) {
+                MetaAccessProvider metaAccess = tool.getMetaAccess();
+                if (metaAccess != null) {
+                    ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(clazz.asJavaConstant());
+                    if (exactType.isPrimitive()) {
+                        return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, metaAccess);
+                    } else {
+                        return ConstantNode.forConstant(stamp(), tool.getConstantReflection().asObjectHub(exactType), metaAccess);
+                    }
+                }
+            }
+            if (clazz instanceof GetClassNode) {
+                GetClassNode getClass = (GetClassNode) clazz;
+                return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject());
+            }
+            if (clazz instanceof HubGetClassNode) {
+                // replace _klass._java_mirror._klass -> _klass
+                return ((HubGetClassNode) clazz).getHub();
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static native KlassPointer readClass(Class<?> clazz);
+
+    @NodeIntrinsic
+    public static native KlassPointer readClass(Class<?> clazz, GuardingNode guard);
+
+    @Override
+    public ValueNode getValue() {
+        return clazz;
+    }
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        ResolvedJavaType exactType = constantReflection.asJavaType(c);
+        if (exactType.isPrimitive()) {
+            return JavaConstant.NULL_POINTER;
+        } else {
+            return constantReflection.asObjectHub(exactType);
+        }
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        assert !c.equals(JavaConstant.NULL_POINTER);
+        ResolvedJavaType objectType = constantReflection.asJavaType(c);
+        return constantReflection.asJavaClass(objectType);
+    }
+
+    @Override
+    public boolean isLossless() {
+        return false;
+    }
+
+    @Override
+    public boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) {
+        assert op == Condition.EQ || op == Condition.NE;
+        ResolvedJavaType exactType = constantReflection.asJavaType(value);
+        return !exactType.isPrimitive();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/EncodedSymbolConstant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/EncodedSymbolConstant.java
new file mode 100644
index 0000000..301b03d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/EncodedSymbolConstant.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.nio.ByteBuffer;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Constant;
+
+/**
+ * Represents an encoded representation of a constant.
+ */
+public final class EncodedSymbolConstant extends DataPointerConstant {
+    private final Constant constant;
+    private byte[] bytes;
+
+    public EncodedSymbolConstant(Constant constant) {
+        super(1);
+        this.constant = constant;
+    }
+
+    @Override
+    public int getSerializedSize() {
+        return getEncodedConstant().length;
+    }
+
+    @Override
+    public void serialize(ByteBuffer buffer) {
+        buffer.put(getEncodedConstant());
+    }
+
+    /**
+     * Converts a string to a byte array with modified UTF-8 encoding. The first two bytes of the
+     * byte array store the length of the string in bytes.
+     *
+     * @param s a java.lang.String in UTF-16
+     */
+    private static byte[] toUTF8String(String s) {
+        try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) {
+            DataOutputStream stream = new DataOutputStream(bytes);
+            stream.writeUTF(s);
+            return bytes.toByteArray();
+        } catch (Exception e) {
+            throw new PermanentBailoutException(e, "String conversion failed: %s", s);
+        }
+    }
+
+    private static byte[] encodeConstant(Constant constant) {
+        assert constant != null;
+        if (constant instanceof HotSpotObjectConstant) {
+            return toUTF8String(((HotSpotObjectConstant) constant).asObject(String.class));
+        } else if (constant instanceof HotSpotMetaspaceConstant) {
+            HotSpotMetaspaceConstant metaspaceConstant = ((HotSpotMetaspaceConstant) constant);
+            HotSpotResolvedObjectType klass = metaspaceConstant.asResolvedJavaType();
+            if (klass != null) {
+                return toUTF8String(klass.getName());
+            }
+            HotSpotResolvedJavaMethod method = metaspaceConstant.asResolvedJavaMethod();
+            if (method != null) {
+                byte[] methodName = toUTF8String(method.getName());
+                byte[] signature = toUTF8String(method.getSignature().toMethodDescriptor());
+                byte[] result = new byte[methodName.length + signature.length];
+                int resultPos = 0;
+                System.arraycopy(methodName, 0, result, resultPos, methodName.length);
+                resultPos += methodName.length;
+                System.arraycopy(signature, 0, result, resultPos, signature.length);
+                resultPos += signature.length;
+                assert resultPos == result.length;
+                return result;
+            }
+
+        }
+        throw new PermanentBailoutException("Encoding of constant %s failed", constant);
+    }
+
+    public byte[] getEncodedConstant() {
+        if (bytes == null) {
+            bytes = encodeConstant(constant);
+        }
+        return bytes;
+    }
+
+    @Override
+    public String toValueString() {
+        return "encoded symbol\"" + constant.toValueString() + "\"";
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java
new file mode 100644
index 0000000..f0608fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.IDENTITY_HASHCODE;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCode;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCodeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.uninitializedIdentityHashCodeValue;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class HashCodeSnippets implements Snippets {
+
+    @Snippet
+    public static int identityHashCodeSnippet(final Object thisObj) {
+        if (probability(NOT_FREQUENT_PROBABILITY, thisObj == null)) {
+            return 0;
+        }
+        return computeHashCode(thisObj);
+    }
+
+    static int computeHashCode(final Object x) {
+        Word mark = loadWordFromObject(x, markOffset(INJECTED_VMCONFIG));
+
+        // this code is independent from biased locking (although it does not look that way)
+        final Word biasedLock = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
+        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask(INJECTED_VMCONFIG))))) {
+            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue();
+            if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) {
+                return hash;
+            }
+        }
+        return identityHashCode(IDENTITY_HASHCODE, x);
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo identityHashCodeSnippet = snippet(HashCodeSnippets.class, "identityHashCodeSnippet", HotSpotReplacementsUtil.MARK_WORD_LOCATION);
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(IdentityHashCodeNode node, LoweringTool tool) {
+            StructuredGraph graph = node.graph();
+            Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("thisObj", node.object);
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java
new file mode 100644
index 0000000..8113802
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ARRAY_KLASS_COMPONENT_MIRROR;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_MODIFIER_FLAGS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassComponentMirrorOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassIsArray;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassModifierFlagsOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassSuperKlassOffset;
+
+import java.lang.reflect.Modifier;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.PiNode;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link java.lang.Class} methods.
+ */
+@ClassSubstitution(Class.class)
+public class HotSpotClassSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static int getModifiers(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            // Class for primitive type
+            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
+        } else {
+            return klass.readInt(klassModifierFlagsOffset(INJECTED_VMCONFIG), KLASS_MODIFIER_FLAGS_LOCATION);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInterface(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            // Class for primitive type
+            return false;
+        } else {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION);
+            return (accessFlags & Modifier.INTERFACE) != 0;
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isArray(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            // Class for primitive type
+            return false;
+        } else {
+            return klassIsArray(klass);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isPrimitive(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        return klass.isNull();
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getSuperclass(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (!klass.isNull()) {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION);
+            if ((accessFlags & Modifier.INTERFACE) == 0) {
+                if (klassIsArray(klass)) {
+                    return Object.class;
+                } else {
+                    KlassPointer superKlass = klass.readKlassPointer(klassSuperKlassOffset(INJECTED_VMCONFIG), KLASS_SUPER_KLASS_LOCATION);
+                    if (superKlass.isNull()) {
+                        return null;
+                    } else {
+                        return readJavaMirror(superKlass);
+                    }
+                }
+            }
+        } else {
+            // Class for primitive type
+        }
+        return null;
+    }
+
+    public static Class<?> readJavaMirror(KlassPointer klass) {
+        return PiNode.asNonNullClass(HubGetClassNode.readClass(klass));
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getComponentType(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (!klass.isNull()) {
+            if (klassIsArray(klass)) {
+                return PiNode.asNonNullClass(klass.readObject(arrayKlassComponentMirrorOffset(INJECTED_VMCONFIG), ARRAY_KLASS_COMPONENT_MIRROR));
+            }
+        } else {
+            // Class for primitive type
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
new file mode 100644
index 0000000..90c3483
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
@@ -0,0 +1,954 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.VERIFY_OOP;
+import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.CanonicalizableLocation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.StoreHubNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.memory.Access;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.replacements.nodes.ReadRegisterNode;
+import org.graalvm.compiler.replacements.nodes.WriteRegisterNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+//JaCoCo Exclude
+
+/**
+ * A collection of methods used in HotSpot snippets, substitutions and stubs.
+ */
+public class HotSpotReplacementsUtil {
+
+    abstract static class HotSpotOptimizingLocationIdentity extends NamedLocationIdentity implements CanonicalizableLocation {
+
+        HotSpotOptimizingLocationIdentity(String name) {
+            super(name, true);
+        }
+
+        @Override
+        public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool);
+
+        protected ValueNode findReadHub(ValueNode object) {
+            ValueNode base = object;
+            if (base instanceof CompressionNode) {
+                base = ((CompressionNode) base).getValue();
+            }
+            if (base instanceof Access) {
+                Access access = (Access) base;
+                if (access.getLocationIdentity().equals(HUB_LOCATION) || access.getLocationIdentity().equals(COMPRESSED_HUB_LOCATION)) {
+                    AddressNode address = access.getAddress();
+                    if (address instanceof OffsetAddressNode) {
+                        OffsetAddressNode offset = (OffsetAddressNode) address;
+                        return offset.getBase();
+                    }
+                }
+            } else if (base instanceof LoadHubNode) {
+                LoadHubNode loadhub = (LoadHubNode) base;
+                return loadhub.getValue();
+            }
+            return null;
+        }
+
+        /**
+         * Fold reads that convert from Class -> Hub -> Class or vice versa.
+         *
+         * @param read
+         * @param object
+         * @param otherLocation
+         * @return an earlier read or the original {@code read}
+         */
+        protected static ValueNode foldIndirection(ValueNode read, ValueNode object, LocationIdentity otherLocation) {
+            if (object instanceof Access) {
+                Access access = (Access) object;
+                if (access.getLocationIdentity().equals(otherLocation)) {
+                    AddressNode address = access.getAddress();
+                    if (address instanceof OffsetAddressNode) {
+                        OffsetAddressNode offset = (OffsetAddressNode) address;
+                        assert offset.getBase().stamp().isCompatible(read.stamp());
+                        return offset.getBase();
+                    }
+                }
+            }
+            return read;
+        }
+    }
+
+    public static HotSpotJVMCIRuntimeProvider runtime() {
+        return HotSpotJVMCIRuntime.runtime();
+    }
+
+    @Fold
+    public static GraalHotSpotVMConfig config(@InjectedParameter GraalHotSpotVMConfig config) {
+        assert config != null;
+        return config;
+    }
+
+    @Fold
+    public static boolean useTLAB(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useTLAB;
+    }
+
+    @Fold
+    public static boolean verifyOops(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.verifyOops;
+    }
+
+    public static final LocationIdentity EXCEPTION_OOP_LOCATION = NamedLocationIdentity.mutable("ExceptionOop");
+
+    /**
+     * @see GraalHotSpotVMConfig#threadExceptionOopOffset
+     */
+    @Fold
+    public static int threadExceptionOopOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadExceptionOopOffset;
+    }
+
+    public static final LocationIdentity EXCEPTION_PC_LOCATION = NamedLocationIdentity.mutable("ExceptionPc");
+
+    @Fold
+    public static int threadExceptionPcOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadExceptionPcOffset;
+    }
+
+    public static final LocationIdentity TLAB_TOP_LOCATION = NamedLocationIdentity.mutable("TlabTop");
+
+    @Fold
+    public static int threadTlabTopOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadTlabTopOffset();
+    }
+
+    public static final LocationIdentity TLAB_END_LOCATION = NamedLocationIdentity.mutable("TlabEnd");
+
+    @Fold
+    static int threadTlabEndOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadTlabEndOffset();
+    }
+
+    public static final LocationIdentity TLAB_START_LOCATION = NamedLocationIdentity.mutable("TlabStart");
+
+    @Fold
+    static int threadTlabStartOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadTlabStartOffset();
+    }
+
+    public static final LocationIdentity PENDING_EXCEPTION_LOCATION = NamedLocationIdentity.mutable("PendingException");
+
+    /**
+     * @see GraalHotSpotVMConfig#pendingExceptionOffset
+     */
+    @Fold
+    static int threadPendingExceptionOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.pendingExceptionOffset;
+    }
+
+    public static final LocationIdentity PENDING_DEOPTIMIZATION_LOCATION = NamedLocationIdentity.mutable("PendingDeoptimization");
+
+    /**
+     * @see GraalHotSpotVMConfig#pendingDeoptimizationOffset
+     */
+    @Fold
+    static int threadPendingDeoptimizationOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.pendingDeoptimizationOffset;
+    }
+
+    public static final LocationIdentity OBJECT_RESULT_LOCATION = NamedLocationIdentity.mutable("ObjectResult");
+
+    @Fold
+    static int objectResultOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadObjectResultOffset;
+    }
+
+    /**
+     * @see GraalHotSpotVMConfig#threadExceptionOopOffset
+     */
+    public static Object readExceptionOop(Word thread) {
+        return thread.readObject(threadExceptionOopOffset(INJECTED_VMCONFIG), EXCEPTION_OOP_LOCATION);
+    }
+
+    public static Word readExceptionPc(Word thread) {
+        return thread.readWord(threadExceptionPcOffset(INJECTED_VMCONFIG), EXCEPTION_PC_LOCATION);
+    }
+
+    /**
+     * @see GraalHotSpotVMConfig#threadExceptionOopOffset
+     */
+    public static void writeExceptionOop(Word thread, Object value) {
+        thread.writeObject(threadExceptionOopOffset(INJECTED_VMCONFIG), value, EXCEPTION_OOP_LOCATION);
+    }
+
+    public static void writeExceptionPc(Word thread, Word value) {
+        thread.writeWord(threadExceptionPcOffset(INJECTED_VMCONFIG), value, EXCEPTION_PC_LOCATION);
+    }
+
+    public static Word readTlabTop(Word thread) {
+        return thread.readWord(threadTlabTopOffset(INJECTED_VMCONFIG), TLAB_TOP_LOCATION);
+    }
+
+    public static Word readTlabEnd(Word thread) {
+        return thread.readWord(threadTlabEndOffset(INJECTED_VMCONFIG), TLAB_END_LOCATION);
+    }
+
+    public static Word readTlabStart(Word thread) {
+        return thread.readWord(threadTlabStartOffset(INJECTED_VMCONFIG), TLAB_START_LOCATION);
+    }
+
+    public static void writeTlabTop(Word thread, Word top) {
+        thread.writeWord(threadTlabTopOffset(INJECTED_VMCONFIG), top, TLAB_TOP_LOCATION);
+    }
+
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static void initializeTlab(Word thread, Word start, Word end) {
+        thread.writeWord(threadTlabStartOffset(INJECTED_VMCONFIG), start, TLAB_START_LOCATION);
+        thread.writeWord(threadTlabTopOffset(INJECTED_VMCONFIG), start, TLAB_TOP_LOCATION);
+        thread.writeWord(threadTlabEndOffset(INJECTED_VMCONFIG), end, TLAB_END_LOCATION);
+    }
+
+    /**
+     * Clears the pending exception for the given thread.
+     *
+     * @return the pending exception, or null if there was none
+     */
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static Object clearPendingException(Word thread) {
+        Object result = thread.readObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), PENDING_EXCEPTION_LOCATION);
+        thread.writeObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), null, PENDING_EXCEPTION_LOCATION);
+        return result;
+    }
+
+    /**
+     * Reads the pending deoptimization value for the given thread.
+     *
+     * @return {@code true} if there was a pending deoptimization
+     */
+    public static int readPendingDeoptimization(Word thread) {
+        return thread.readInt(threadPendingDeoptimizationOffset(INJECTED_VMCONFIG), PENDING_DEOPTIMIZATION_LOCATION);
+    }
+
+    /**
+     * Writes the pending deoptimization value for the given thread.
+     */
+    public static void writePendingDeoptimization(Word thread, int value) {
+        thread.writeInt(threadPendingDeoptimizationOffset(INJECTED_VMCONFIG), value, PENDING_DEOPTIMIZATION_LOCATION);
+    }
+
+    /**
+     * Gets and clears the object result from a runtime call stored in a thread local.
+     *
+     * @return the object that was in the thread local
+     */
+    public static Object getAndClearObjectResult(Word thread) {
+        Object result = thread.readObject(objectResultOffset(INJECTED_VMCONFIG), OBJECT_RESULT_LOCATION);
+        thread.writeObject(objectResultOffset(INJECTED_VMCONFIG), null, OBJECT_RESULT_LOCATION);
+        return result;
+    }
+
+    public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj");
+
+    @Fold
+    public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadObjectOffset;
+    }
+
+    public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread");
+
+    @Fold
+    public static int osThreadOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.osThreadOffset;
+    }
+
+    @Fold
+    public static int osThreadInterruptedOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.osThreadInterruptedOffset;
+    }
+
+    @Fold
+    public static JavaKind getWordKind() {
+        return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind;
+    }
+
+    @Fold
+    public static int wordSize() {
+        return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize;
+    }
+
+    @Fold
+    public static int pageSize() {
+        return UNSAFE.pageSize();
+    }
+
+    @Fold
+    public static int heapWordSize(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.heapWordSize;
+    }
+
+    public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("PrototypeMarkWord");
+
+    @Fold
+    public static int prototypeMarkWordOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.prototypeMarkWordOffset;
+    }
+
+    @Fold
+    public static long arrayPrototypeMarkWord(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.arrayPrototypeMarkWord();
+    }
+
+    public static final LocationIdentity KLASS_ACCESS_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_access_flags");
+
+    @Fold
+    public static int klassAccessFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.klassAccessFlagsOffset;
+    }
+
+    @Fold
+    public static int jvmAccWrittenFlags(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.jvmAccWrittenFlags;
+    }
+
+    public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = new HotSpotOptimizingLocationIdentity("Klass::_layout_helper") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            ValueNode javaObject = findReadHub(object);
+            if (javaObject != null) {
+                if (javaObject.stamp() instanceof ObjectStamp) {
+                    ObjectStamp stamp = (ObjectStamp) javaObject.stamp();
+                    HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) stamp.javaType(tool.getMetaAccess());
+                    if (type.isArray() && !type.getComponentType().isPrimitive()) {
+                        int layout = type.layoutHelper();
+                        return ConstantNode.forInt(layout);
+                    }
+                }
+            }
+            return read;
+        }
+    };
+
+    @Fold
+    public static int klassLayoutHelperOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.klassLayoutHelperOffset;
+    }
+
+    public static int readLayoutHelper(KlassPointer hub) {
+        // return hub.readInt(klassLayoutHelperOffset(), KLASS_LAYOUT_HELPER_LOCATION);
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        return loadKlassLayoutHelperIntrinsic(hub, anchorNode);
+    }
+
+    @NodeIntrinsic(value = KlassLayoutHelperNode.class)
+    public static native int loadKlassLayoutHelperIntrinsic(KlassPointer object, GuardingNode anchor);
+
+    @NodeIntrinsic(value = KlassLayoutHelperNode.class)
+    public static native int loadKlassLayoutHelperIntrinsic(KlassPointer object);
+
+    /**
+     * Checks if class {@code klass} is an array.
+     *
+     * See: Klass::layout_helper_is_array
+     *
+     * @param klass the class to be checked
+     * @return true if klass is an array, false otherwise
+     */
+    public static boolean klassIsArray(KlassPointer klass) {
+        /*
+         * The less-than check only works if both values are ints. We use local variables to make
+         * sure these are still ints and haven't changed.
+         */
+        final int layoutHelper = readLayoutHelper(klass);
+        final int layoutHelperNeutralValue = config(INJECTED_VMCONFIG).klassLayoutHelperNeutralValue;
+        return (layoutHelper < layoutHelperNeutralValue);
+    }
+
+    public static final LocationIdentity ARRAY_KLASS_COMPONENT_MIRROR = NamedLocationIdentity.immutable("ArrayKlass::_component_mirror");
+
+    @Fold
+    public static int arrayKlassComponentMirrorOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop");
+    }
+
+    public static final LocationIdentity KLASS_SUPER_KLASS_LOCATION = NamedLocationIdentity.immutable("Klass::_super");
+
+    @Fold
+    public static int klassSuperKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.klassSuperKlassOffset;
+    }
+
+    public static final LocationIdentity MARK_WORD_LOCATION = NamedLocationIdentity.mutable("MarkWord");
+
+    @Fold
+    public static int markOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.markOffset;
+    }
+
+    public static final LocationIdentity HUB_WRITE_LOCATION = NamedLocationIdentity.mutable("Hub:write");
+
+    public static final LocationIdentity HUB_LOCATION = new HotSpotOptimizingLocationIdentity("Hub") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            TypeReference constantType = StampTool.typeReferenceOrNull(object);
+            if (constantType != null && constantType.isExact()) {
+                return ConstantNode.forConstant(read.stamp(), tool.getConstantReflection().asObjectHub(constantType.getType()), tool.getMetaAccess());
+            }
+            return read;
+        }
+    };
+
+    public static final LocationIdentity COMPRESSED_HUB_LOCATION = new HotSpotOptimizingLocationIdentity("CompressedHub") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            TypeReference constantType = StampTool.typeReferenceOrNull(object);
+            if (constantType != null && constantType.isExact()) {
+                return ConstantNode.forConstant(read.stamp(), ((HotSpotMetaspaceConstant) tool.getConstantReflection().asObjectHub(constantType.getType())).compress(), tool.getMetaAccess());
+            }
+            return read;
+        }
+    };
+
+    @Fold
+    static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.hubOffset;
+    }
+
+    public static void initializeObjectHeader(Word memory, Word markWord, KlassPointer hub) {
+        memory.writeWord(markOffset(INJECTED_VMCONFIG), markWord, MARK_WORD_LOCATION);
+        StoreHubNode.write(memory, hub);
+    }
+
+    @Fold
+    public static int unlockedMask(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.unlockedMask;
+    }
+
+    /**
+     * Mask for a biasable, locked or unlocked mark word.
+     *
+     * <pre>
+     * +----------------------------------+-+-+
+     * |                                 1|1|1|
+     * +----------------------------------+-+-+
+     * </pre>
+     *
+     */
+    @Fold
+    public static int biasedLockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.biasedLockMaskInPlace;
+    }
+
+    @Fold
+    public static int epochMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.epochMaskInPlace;
+    }
+
+    /**
+     * Pattern for a biasable, unlocked mark word.
+     *
+     * <pre>
+     * +----------------------------------+-+-+
+     * |                                 1|0|1|
+     * +----------------------------------+-+-+
+     * </pre>
+     *
+     */
+    @Fold
+    public static int biasedLockPattern(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.biasedLockPattern;
+    }
+
+    @Fold
+    public static int ageMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.ageMaskInPlace;
+    }
+
+    @Fold
+    public static int metaspaceArrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.metaspaceArrayLengthOffset;
+    }
+
+    @Fold
+    public static int metaspaceArrayBaseOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.metaspaceArrayBaseOffset;
+    }
+
+    @Fold
+    public static int arrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.arrayOopDescLengthOffset();
+    }
+
+    @Fold
+    public static int arrayBaseOffset(JavaKind elementKind) {
+        return getArrayBaseOffset(elementKind);
+    }
+
+    @Fold
+    public static int arrayIndexScale(JavaKind elementKind) {
+        return getArrayIndexScale(elementKind);
+    }
+
+    public static Word arrayStart(int[] a) {
+        return Word.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int)));
+    }
+
+    @Fold
+    public static int instanceHeaderSize(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useCompressedClassPointers ? (2 * wordSize()) - 4 : 2 * wordSize();
+    }
+
+    @Fold
+    public static byte dirtyCardValue(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.dirtyCardValue;
+    }
+
+    @Fold
+    public static byte g1YoungCardValue(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1YoungCardValue;
+    }
+
+    @Fold
+    public static int cardTableShift(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.cardtableShift;
+    }
+
+    @Fold
+    public static long cardTableStart(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.cardtableStartAddress;
+    }
+
+    @Fold
+    public static int g1CardQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1CardQueueIndexOffset();
+    }
+
+    @Fold
+    public static int g1CardQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1CardQueueBufferOffset();
+    }
+
+    @Fold
+    public static int logOfHeapRegionGrainBytes(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.logOfHRGrainBytes;
+    }
+
+    @Fold
+    public static int g1SATBQueueMarkingOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1SATBQueueMarkingOffset();
+    }
+
+    @Fold
+    public static int g1SATBQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1SATBQueueIndexOffset();
+    }
+
+    @Fold
+    public static int g1SATBQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.g1SATBQueueBufferOffset();
+    }
+
+    public static final LocationIdentity KLASS_SUPER_CHECK_OFFSET_LOCATION = NamedLocationIdentity.immutable("Klass::_super_check_offset");
+
+    @Fold
+    public static int superCheckOffsetOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.superCheckOffsetOffset;
+    }
+
+    public static final LocationIdentity SECONDARY_SUPER_CACHE_LOCATION = NamedLocationIdentity.mutable("SecondarySuperCache");
+
+    @Fold
+    public static int secondarySuperCacheOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.secondarySuperCacheOffset;
+    }
+
+    public static final LocationIdentity SECONDARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("SecondarySupers");
+
+    @Fold
+    public static int secondarySupersOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.secondarySupersOffset;
+    }
+
+    public static final LocationIdentity DISPLACED_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("DisplacedMarkWord");
+
+    @Fold
+    public static int lockDisplacedMarkOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.basicLockDisplacedHeaderOffset;
+    }
+
+    @Fold
+    public static boolean useBiasedLocking(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useBiasedLocking;
+    }
+
+    @Fold
+    public static boolean useDeferredInitBarriers(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useDeferredInitBarriers;
+    }
+
+    @Fold
+    public static boolean useG1GC(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useG1GC;
+    }
+
+    @Fold
+    public static boolean useCompressedOops(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useCompressedOops;
+    }
+
+    @Fold
+    static int uninitializedIdentityHashCodeValue(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.uninitializedIdentityHashCodeValue;
+    }
+
+    @Fold
+    static int identityHashCodeShift(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.identityHashCodeShift;
+    }
+
+    /**
+     * Loads the hub of an object (without null checking it first).
+     */
+    public static KlassPointer loadHub(Object object) {
+        return loadHubIntrinsic(object);
+    }
+
+    public static Object verifyOop(Object object) {
+        if (verifyOops(INJECTED_VMCONFIG)) {
+            verifyOopStub(VERIFY_OOP, object);
+        }
+        return object;
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
+
+    public static Word loadWordFromObject(Object object, int offset) {
+        ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
+        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any());
+    }
+
+    public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) {
+        ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
+        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), identity);
+    }
+
+    public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) {
+        ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
+        return loadKlassFromObjectIntrinsic(object, offset, getWordKind(), identity);
+    }
+
+    /**
+     * Reads the value of a given register.
+     *
+     * @param register a register which must not be available to the register allocator
+     * @return the value of {@code register} as a word
+     */
+    public static Word registerAsWord(@ConstantNodeParameter Register register) {
+        return registerAsWord(register, true, false);
+    }
+
+    @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
+    public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
+
+    @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true)
+    public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value);
+
+    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
+    private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
+
+    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
+    private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
+
+    @NodeIntrinsic(value = LoadHubNode.class)
+    public static native KlassPointer loadHubIntrinsic(Object object);
+
+    @Fold
+    public static int log2WordSize() {
+        return CodeUtil.log2(wordSize());
+    }
+
+    public static final LocationIdentity CLASS_STATE_LOCATION = NamedLocationIdentity.mutable("ClassState");
+
+    @Fold
+    public static int instanceKlassInitStateOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.instanceKlassInitStateOffset;
+    }
+
+    @Fold
+    public static int instanceKlassStateFullyInitialized(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.instanceKlassStateFullyInitialized;
+    }
+
+    /**
+     *
+     * @param hub the hub of an InstanceKlass
+     * @return true is the InstanceKlass represented by hub is fully initialized
+     */
+    public static boolean isInstanceKlassFullyInitialized(KlassPointer hub) {
+        return readInstanceKlassState(hub) == instanceKlassStateFullyInitialized(INJECTED_VMCONFIG);
+    }
+
+    private static byte readInstanceKlassState(KlassPointer hub) {
+        return hub.readByte(instanceKlassInitStateOffset(INJECTED_VMCONFIG), CLASS_STATE_LOCATION);
+    }
+
+    public static final LocationIdentity KLASS_MODIFIER_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_modifier_flags");
+
+    @Fold
+    public static int klassModifierFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.klassModifierFlagsOffset;
+    }
+
+    public static final LocationIdentity CLASS_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            return foldIndirection(read, object, CLASS_MIRROR_LOCATION);
+        }
+    };
+
+    @Fold
+    public static int klassOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.klassOffset;
+    }
+
+    public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._array_klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            return foldIndirection(read, object, ARRAY_KLASS_COMPONENT_MIRROR);
+        }
+    };
+
+    @Fold
+    public static int arrayKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.arrayKlassOffset;
+    }
+
+    public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror");
+
+    public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop");
+
+    @Fold
+    public static long heapTopAddress(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.heapTopAddress;
+    }
+
+    public static final LocationIdentity HEAP_END_LOCATION = NamedLocationIdentity.mutable("HeapEnd");
+
+    @Fold
+    public static long heapEndAddress(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.heapEndAddress;
+    }
+
+    @Fold
+    public static long tlabIntArrayMarkWord(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabIntArrayMarkWord();
+    }
+
+    @Fold
+    public static boolean inlineContiguousAllocationSupported(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.inlineContiguousAllocationSupported;
+    }
+
+    @Fold
+    public static int tlabAlignmentReserveInHeapWords(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabAlignmentReserve;
+    }
+
+    public static final LocationIdentity TLAB_SIZE_LOCATION = NamedLocationIdentity.mutable("TlabSize");
+
+    @Fold
+    public static int threadTlabSizeOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadTlabSizeOffset();
+    }
+
+    public static final LocationIdentity TLAB_THREAD_ALLOCATED_BYTES_LOCATION = NamedLocationIdentity.mutable("TlabThreadAllocatedBytes");
+
+    @Fold
+    public static int threadAllocatedBytesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.threadAllocatedBytesOffset;
+    }
+
+    public static final LocationIdentity TLAB_REFILL_WASTE_LIMIT_LOCATION = NamedLocationIdentity.mutable("RefillWasteLimit");
+
+    @Fold
+    public static int tlabRefillWasteLimitOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabRefillWasteLimitOffset();
+    }
+
+    public static final LocationIdentity TLAB_NOF_REFILLS_LOCATION = NamedLocationIdentity.mutable("TlabNOfRefills");
+
+    @Fold
+    public static int tlabNumberOfRefillsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabNumberOfRefillsOffset();
+    }
+
+    public static final LocationIdentity TLAB_FAST_REFILL_WASTE_LOCATION = NamedLocationIdentity.mutable("TlabFastRefillWaste");
+
+    @Fold
+    public static int tlabFastRefillWasteOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabFastRefillWasteOffset();
+    }
+
+    public static final LocationIdentity TLAB_SLOW_ALLOCATIONS_LOCATION = NamedLocationIdentity.mutable("TlabSlowAllocations");
+
+    @Fold
+    public static int tlabSlowAllocationsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabSlowAllocationsOffset();
+    }
+
+    @Fold
+    public static int tlabRefillWasteIncrement(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabRefillWasteIncrement;
+    }
+
+    @Fold
+    public static boolean tlabStats(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.tlabStats;
+    }
+
+    @Fold
+    public static int layoutHelperHeaderSizeShift(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperHeaderSizeShift;
+    }
+
+    @Fold
+    public static int layoutHelperHeaderSizeMask(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperHeaderSizeMask;
+    }
+
+    @Fold
+    public static int layoutHelperLog2ElementSizeShift(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperLog2ElementSizeShift;
+    }
+
+    @Fold
+    public static int layoutHelperLog2ElementSizeMask(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperLog2ElementSizeMask;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypeShift(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperElementTypeShift;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypeMask(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperElementTypeMask;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypePrimitiveInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.layoutHelperElementTypePrimitiveInPlace();
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native int identityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
+
+    @Fold
+    public static int verifiedEntryPointOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.nmethodEntryOffset;
+    }
+
+    @Fold
+    public static long gcTotalCollectionsAddress(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.gcTotalCollectionsAddress();
+    }
+
+    @Fold
+    public static long referentOffset() {
+        try {
+            return UNSAFE.objectFieldOffset(java.lang.ref.Reference.class.getDeclaredField("referent"));
+        } catch (Exception e) {
+            throw new GraalError(e);
+        }
+    }
+
+    public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") {
+        @Override
+        public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
+            ValueNode javaObject = findReadHub(object);
+            if (javaObject != null) {
+                ResolvedJavaType type = StampTool.typeOrNull(javaObject);
+                if (type != null && type.isArray()) {
+                    ResolvedJavaType element = type.getComponentType();
+                    if (element != null && !element.isPrimitive() && !element.getElementalType().isInterface()) {
+                        Assumptions assumptions = object.graph().getAssumptions();
+                        AssumptionResult<ResolvedJavaType> leafType = element.findLeafConcreteSubtype();
+                        if (leafType != null && leafType.canRecordTo(assumptions)) {
+                            leafType.recordTo(assumptions);
+                            return ConstantNode.forConstant(read.stamp(), tool.getConstantReflection().asObjectHub(leafType.getResult()), tool.getMetaAccess());
+                        }
+                    }
+                }
+            }
+            return read;
+        }
+    };
+
+    @Fold
+    public static int arrayClassElementOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.arrayClassElementOffset;
+    }
+
+    public static final LocationIdentity PRIMARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("PrimarySupers");
+
+    public static final LocationIdentity METASPACE_ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("MetaspaceArrayLength");
+
+    public static final LocationIdentity SECONDARY_SUPERS_ELEMENT_LOCATION = NamedLocationIdentity.immutable("SecondarySupersElement");
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java
new file mode 100644
index 0000000..9472450
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.ProfileContext;
+import org.graalvm.compiler.options.EnumOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Options related to HotSpot snippets in this package.
+ *
+ * Note: This must be a top level class to work around for
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=477597">Eclipse bug 477597</a>.
+ */
+public class HotspotSnippetsOptions {
+
+    // @formatter:off
+    @Option(help = "If the probability that a type check will hit one the profiled types (up to " +
+                   "TypeCheckMaxHints) is below this value, the type check will be compiled without profiling info", type = OptionType.Expert)
+    public static final OptionValue<Double> TypeCheckMinProfileHitProbability = new OptionValue<>(0.5);
+
+    @Option(help = "The maximum number of profiled types that will be used when compiling a profiled type check. " +
+                    "Note that TypeCheckMinProfileHitProbability also influences whether profiling info is used in compiled type checks.", type = OptionType.Expert)
+    public static final OptionValue<Integer> TypeCheckMaxHints = new OptionValue<>(2);
+
+    @Option(help = "Use a VM runtime call to load and clear the exception object from the thread at the start of a compiled exception handler.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> LoadExceptionObjectInVM = new OptionValue<>(false);
+
+    @Option(help = "Enable profiling of allocation sites.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ProfileAllocations = new OptionValue<>(false);
+
+    @Option(help = "Control the naming of the counters when using ProfileAllocations.", type = OptionType.Debug)
+    public static final EnumOptionValue<ProfileContext> ProfileAllocationsContext = new EnumOptionValue<>(ProfileContext.AllocatingMethod);
+
+    @Option(help = "Enable profiling of monitor operations.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> ProfileMonitors = new OptionValue<>(false);
+
+    @Option(help = "Trace monitor operations on objects whose type contains this substring.", type = OptionType.Debug)
+    public static final OptionValue<String> TraceMonitorsTypeFilter = new OptionValue<>(null);
+
+    @Option(help = "Trace monitor operations in methods whose fully qualified name contains this substring.", type = OptionType.Debug)
+    public static final OptionValue<String> TraceMonitorsMethodFilter = new OptionValue<>(null);
+
+    @Option(help = "Emit extra code to dynamically check monitor operations are balanced.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> VerifyBalancedMonitors = new OptionValue<>(false);
+    //@formatter:on
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java
new file mode 100644
index 0000000..647b8d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FloatingGuardedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConvertNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Read {@code Klass::_java_mirror} and incorporate non-null type information into stamp. This is
+ * also used by {@link ClassGetHubNode} to eliminate chains of {@code klass._java_mirror._klass}.
+ */
+@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+public final class HubGetClassNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
+    public static final NodeClass<HubGetClassNode> TYPE = NodeClass.create(HubGetClassNode.class);
+    @Input protected ValueNode hub;
+
+    public HubGetClassNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode hub) {
+        super(TYPE, StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(metaAccess.lookupJavaType(Class.class))), null);
+        this.hub = hub;
+    }
+
+    public ValueNode getHub() {
+        return hub;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        } else {
+            MetaAccessProvider metaAccess = tool.getMetaAccess();
+            if (metaAccess != null && hub.isConstant()) {
+                ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant());
+                if (exactType != null) {
+                    return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess);
+                }
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static native Class<?> readClass(KlassPointer hub);
+
+    @Override
+    public ValueNode getValue() {
+        return hub;
+    }
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return c;
+        }
+        return constantReflection.asJavaClass(constantReflection.asJavaType(c));
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return c;
+        }
+        ResolvedJavaType type = constantReflection.asJavaType(c);
+        if (type.isPrimitive()) {
+            return JavaConstant.NULL_POINTER;
+        } else {
+            return constantReflection.asObjectHub(type);
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        /*
+         * Any concrete Klass* has a corresponding java.lang.Class
+         */
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java
new file mode 100644
index 0000000..9c1da83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.JavaConstant;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public class IdentityHashCodeNode extends FixedWithNextNode implements Canonicalizable, Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<IdentityHashCodeNode> TYPE = NodeClass.create(IdentityHashCodeNode.class);
+
+    @Input ValueNode object;
+
+    public IdentityHashCodeNode(ValueNode object) {
+        super(TYPE, StampFactory.forInteger(32));
+        this.object = object;
+
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return HotSpotReplacementsUtil.MARK_WORD_LOCATION;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (object.isConstant()) {
+            assert object.stamp() instanceof AbstractObjectStamp;
+            JavaConstant c = (JavaConstant) object.asConstant();
+            if (ImmutableCode.getValue()) {
+                return this;
+            }
+            JavaConstant identityHashCode = null;
+            if (c.isNull()) {
+                identityHashCode = JavaConstant.forInt(0);
+            } else {
+                identityHashCode = JavaConstant.forInt(((HotSpotObjectConstant) c).getIdentityHashCode());
+            }
+
+            return new ConstantNode(identityHashCode, StampFactory.forConstant(identityHashCode));
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static native int identityHashCode(Object object);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java
new file mode 100644
index 0000000..177b159
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PRIMARY_SUPERS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPER_CACHE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TypeCheckMaxHints;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TypeCheckMinProfileHitProbability;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.checkSecondarySubType;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.checkUnknownSubType;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.createHints;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.displayHit;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.displayMiss;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.exactHit;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.exactMiss;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.hintsHit;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.hintsMiss;
+import static org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.isNull;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.OptimizedTypeCheckViolated;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.replacements.TypeCheckSnippetUtils.Hints;
+import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.TypeCheckHints;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.InstanceOfSnippetsTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * Snippets used for implementing the type test of an instanceof instruction. Since instanceof is a
+ * floating node, it is lowered separately for each of its usages.
+ *
+ * The type tests implemented are described in the paper
+ * <a href="http://dl.acm.org/citation.cfm?id=583821"> Fast subtype checking in the HotSpot JVM</a>
+ * by Cliff Click and John Rose.
+ */
+public class InstanceOfSnippets implements Snippets {
+
+    /**
+     * A test against a set of hints derived from a profile with 100% precise coverage of seen
+     * types. This snippet deoptimizes on hint miss paths.
+     */
+    @Snippet
+    public static Object instanceofWithProfile(Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue,
+                    @ConstantParameter boolean nullSeen) {
+        if (probability(NOT_FREQUENT_PROBABILITY, object == null)) {
+            isNull.inc();
+            if (!nullSeen) {
+                // See comment below for other deoptimization path; the
+                // same reasoning applies here.
+                DeoptimizeNode.deopt(InvalidateReprofile, OptimizedTypeCheckViolated);
+            }
+            return falseValue;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+        // if we get an exact match: succeed immediately
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < hints.length; i++) {
+            KlassPointer hintHub = hints[i];
+            boolean positive = hintIsPositive[i];
+            if (probability(LIKELY_PROBABILITY, hintHub.equal(objectHub))) {
+                hintsHit.inc();
+                return positive ? trueValue : falseValue;
+            }
+            hintsMiss.inc();
+        }
+        // This maybe just be a rare event but it might also indicate a phase change
+        // in the application. Ideally we want to use DeoptimizationAction.None for
+        // the former but the cost is too high if indeed it is the latter. As such,
+        // we defensively opt for InvalidateReprofile.
+        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, OptimizedTypeCheckViolated);
+        return falseValue;
+    }
+
+    /**
+     * A test against a final type.
+     */
+    @Snippet
+    public static Object instanceofExact(Object object, KlassPointer exactHub, Object trueValue, Object falseValue) {
+        if (probability(NOT_FREQUENT_PROBABILITY, object == null)) {
+            isNull.inc();
+            return falseValue;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+        if (probability(LIKELY_PROBABILITY, objectHub.notEqual(exactHub))) {
+            exactMiss.inc();
+            return falseValue;
+        }
+        exactHit.inc();
+        return trueValue;
+    }
+
+    @Snippet
+    public static Object instanceofExactPIC(Object object, KlassPointer exactHub, Object trueValue, Object falseValue) {
+        KlassPointer exactHubPIC = ResolveConstantSnippets.resolveKlassConstant(exactHub);
+        return instanceofExact(object, exactHubPIC, trueValue, falseValue);
+    }
+
+    /**
+     * A test against a primary type.
+     */
+    @Snippet
+    public static Object instanceofPrimary(KlassPointer hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue) {
+        if (probability(NOT_FREQUENT_PROBABILITY, object == null)) {
+            isNull.inc();
+            return falseValue;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+        if (probability(NOT_LIKELY_PROBABILITY, objectHub.readKlassPointer(superCheckOffset, PRIMARY_SUPERS_LOCATION).notEqual(hub))) {
+            displayMiss.inc();
+            return falseValue;
+        }
+        displayHit.inc();
+        return trueValue;
+    }
+
+    @Snippet
+    public static Object instanceofPrimaryPIC(KlassPointer hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue) {
+        KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub);
+        return instanceofPrimary(resolvedHub, object, superCheckOffset, trueValue, falseValue);
+    }
+
+    /**
+     * A test against a restricted secondary type type.
+     */
+    @Snippet
+    public static Object instanceofSecondary(KlassPointer hub, Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue) {
+        if (probability(NOT_FREQUENT_PROBABILITY, object == null)) {
+            isNull.inc();
+            return falseValue;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+        // if we get an exact match: succeed immediately
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < hints.length; i++) {
+            KlassPointer hintHub = hints[i];
+            boolean positive = hintIsPositive[i];
+            if (probability(NOT_FREQUENT_PROBABILITY, hintHub.equal(objectHub))) {
+                hintsHit.inc();
+                return positive ? trueValue : falseValue;
+            }
+        }
+        hintsMiss.inc();
+        if (!checkSecondarySubType(hub, objectHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
+    @Snippet
+    public static Object instanceofSecondaryPIC(KlassPointer hub, Object object, @VarargsParameter KlassPointer[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue,
+                    Object falseValue) {
+        KlassPointer resolvedHub = ResolveConstantSnippets.resolveKlassConstant(hub);
+        return instanceofSecondary(resolvedHub, object, hints, hintIsPositive, trueValue, falseValue);
+    }
+
+    /**
+     * Type test used when the type being tested against is not known at compile time.
+     */
+    @Snippet
+    public static Object instanceofDynamic(KlassPointer hub, Object object, Object trueValue, Object falseValue, @ConstantParameter boolean allowNull) {
+        if (probability(NOT_FREQUENT_PROBABILITY, object == null)) {
+            isNull.inc();
+            if (allowNull) {
+                return trueValue;
+            } else {
+                return falseValue;
+            }
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+        // The hub of a primitive type can be null => always return false in this case.
+        if (hub.isNull() || !checkUnknownSubType(hub, objectHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
+    @Snippet
+    public static Object isAssignableFrom(Class<?> thisClass, Class<?> otherClass, Object trueValue, Object falseValue) {
+        if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, otherClass == null)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
+            return false;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer thisHub = ClassGetHubNode.readClass(thisClass, anchorNode);
+        KlassPointer otherHub = ClassGetHubNode.readClass(otherClass, anchorNode);
+        if (thisHub.isNull() || otherHub.isNull()) {
+            // primitive types, only true if equal.
+            return thisClass == otherClass ? trueValue : falseValue;
+        }
+        if (!TypeCheckSnippetUtils.checkUnknownSubType(thisHub, otherHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
+    public static class Templates extends InstanceOfSnippetsTemplates {
+
+        private final SnippetInfo instanceofWithProfile = snippet(InstanceOfSnippets.class, "instanceofWithProfile");
+        private final SnippetInfo instanceofExact = snippet(InstanceOfSnippets.class, "instanceofExact");
+        private final SnippetInfo instanceofExactPIC = snippet(InstanceOfSnippets.class, "instanceofExactPIC");
+        private final SnippetInfo instanceofPrimary = snippet(InstanceOfSnippets.class, "instanceofPrimary");
+        private final SnippetInfo instanceofPrimaryPIC = snippet(InstanceOfSnippets.class, "instanceofPrimaryPIC");
+        private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary", SECONDARY_SUPER_CACHE_LOCATION);
+        private final SnippetInfo instanceofSecondaryPIC = snippet(InstanceOfSnippets.class, "instanceofSecondaryPIC", SECONDARY_SUPER_CACHE_LOCATION);
+        private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic", SECONDARY_SUPER_CACHE_LOCATION);
+        private final SnippetInfo isAssignableFrom = snippet(InstanceOfSnippets.class, "isAssignableFrom", SECONDARY_SUPER_CACHE_LOCATION);
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        @Override
+        protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) {
+            if (replacer.instanceOf instanceof InstanceOfNode) {
+                InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
+                ValueNode object = instanceOf.getValue();
+                Assumptions assumptions = instanceOf.graph().getAssumptions();
+
+                JavaTypeProfile profile = instanceOf.profile();
+                if (GeneratePIC.getValue()) {
+                    // FIXME: We can't embed constants in hints. We can't really load them from GOT
+                    // either. Hard problem.
+                    profile = null;
+                }
+                TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), profile, assumptions, TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue());
+                final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type().getType();
+                ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), instanceOf.graph());
+
+                Arguments args;
+
+                StructuredGraph graph = instanceOf.graph();
+                if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) {
+                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
+                    args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage());
+                    args.add("object", object);
+                    args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);
+                    args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(JavaKind.Boolean), hints.isPositive);
+                } else if (hintInfo.exact != null) {
+                    SnippetInfo snippet = GeneratePIC.getValue() ? instanceofExactPIC : instanceofExact;
+                    args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+                    args.add("object", object);
+                    args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hintInfo.exact).klass(), providers.getMetaAccess(), graph));
+                } else if (type.isPrimaryType()) {
+                    SnippetInfo snippet = GeneratePIC.getValue() ? instanceofPrimaryPIC : instanceofPrimary;
+                    args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+                    args.add("hub", hub);
+                    args.add("object", object);
+                    args.addConst("superCheckOffset", type.superCheckOffset());
+                } else {
+                    Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
+                    SnippetInfo snippet = GeneratePIC.getValue() ? instanceofSecondaryPIC : instanceofSecondary;
+                    args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+                    args.add("hub", hub);
+                    args.add("object", object);
+                    args.addVarargs("hints", KlassPointer.class, KlassPointerStamp.klassNonNull(), hints.hubs);
+                    args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(JavaKind.Boolean), hints.isPositive);
+                }
+                args.add("trueValue", replacer.trueValue);
+                args.add("falseValue", replacer.falseValue);
+                if (hintInfo.hintHitProbability >= 1.0 && hintInfo.exact == null) {
+                    args.addConst("nullSeen", hintInfo.profile.getNullSeen() != TriState.FALSE);
+                }
+                return args;
+            } else if (replacer.instanceOf instanceof InstanceOfDynamicNode) {
+                InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf;
+                ValueNode object = instanceOf.getObject();
+
+                Arguments args = new Arguments(instanceofDynamic, instanceOf.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("hub", instanceOf.getMirrorOrHub());
+                args.add("object", object);
+                args.add("trueValue", replacer.trueValue);
+                args.add("falseValue", replacer.falseValue);
+                args.addConst("allowNull", instanceOf.allowsNull());
+                return args;
+            } else if (replacer.instanceOf instanceof ClassIsAssignableFromNode) {
+                ClassIsAssignableFromNode isAssignable = (ClassIsAssignableFromNode) replacer.instanceOf;
+                Arguments args = new Arguments(isAssignableFrom, isAssignable.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("thisClass", isAssignable.getThisClass());
+                args.add("otherClass", isAssignable.getOtherClass());
+                args.add("trueValue", replacer.trueValue);
+                args.add("falseValue", replacer.falseValue);
+                return args;
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java
new file mode 100644
index 0000000..346c94f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FloatingGuardedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Read {@code Klass::_layout_helper} and incorporate any useful stamp information based on any type
+ * information in {@code klass}.
+ */
+@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+public final class KlassLayoutHelperNode extends FloatingGuardedNode implements Canonicalizable, Lowerable {
+
+    public static final NodeClass<KlassLayoutHelperNode> TYPE = NodeClass.create(KlassLayoutHelperNode.class);
+    @Input protected ValueNode klass;
+    protected final GraalHotSpotVMConfig config;
+
+    public KlassLayoutHelperNode(@InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass) {
+        this(config, klass, null);
+    }
+
+    public KlassLayoutHelperNode(@InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass, ValueNode guard) {
+        super(TYPE, StampFactory.forKind(JavaKind.Int), (GuardingNode) guard);
+        this.klass = klass;
+        this.config = config;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        if (klass instanceof LoadHubNode) {
+            LoadHubNode hub = (LoadHubNode) klass;
+            Stamp hubStamp = hub.getValue().stamp();
+            if (hubStamp instanceof ObjectStamp) {
+                ObjectStamp objectStamp = (ObjectStamp) hubStamp;
+                ResolvedJavaType type = objectStamp.type();
+                if (type != null && !type.isJavaLangObject()) {
+                    if (!type.isArray() && !type.isInterface()) {
+                        /*
+                         * Definitely some form of instance type.
+                         */
+                        return updateStamp(StampFactory.forInteger(JavaKind.Int, config.klassLayoutHelperNeutralValue, Integer.MAX_VALUE));
+                    }
+                    if (type.isArray()) {
+                        return updateStamp(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, config.klassLayoutHelperNeutralValue - 1));
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        } else {
+            if (klass.isConstant()) {
+                if (!klass.asConstant().isDefaultForKind()) {
+                    Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset);
+                    return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
+                }
+            }
+            if (klass instanceof LoadHubNode) {
+                LoadHubNode hub = (LoadHubNode) klass;
+                Stamp hubStamp = hub.getValue().stamp();
+                if (hubStamp instanceof ObjectStamp) {
+                    ObjectStamp ostamp = (ObjectStamp) hubStamp;
+                    HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type();
+                    if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) {
+                        // The layout for all object arrays is the same.
+                        Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset);
+                        return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
+                    }
+                }
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ValueNode getHub() {
+        return klass;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java
new file mode 100644
index 0000000..02eaf65
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.LOAD_AND_CLEAR_EXCEPTION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.EXCEPTION_OOP_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.EXCEPTION_PC_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionPc;
+import static org.graalvm.compiler.nodes.PiNode.piCast;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.ReadRegisterNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Snippet for loading the exception object at the start of an exception dispatcher.
+ * <p>
+ * The frame state upon entry to an exception handler is such that it is a
+ * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
+ * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
+ * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
+ * find the exception object to be rethrown.
+ */
+public class LoadExceptionObjectSnippets implements Snippets {
+
+    /**
+     * Alternative way to implement exception object loading.
+     */
+    private static final boolean USE_C_RUNTIME = HotspotSnippetsOptions.LoadExceptionObjectInVM.getValue();
+
+    @Snippet
+    public static Object loadException(@ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
+        Object exception = readExceptionOop(thread);
+        writeExceptionOop(thread, null);
+        writeExceptionPc(thread, Word.zero());
+        return piCast(exception, StampFactory.forNodeIntrinsic());
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo loadException = snippet(LoadExceptionObjectSnippets.class, "loadException", EXCEPTION_OOP_LOCATION, EXCEPTION_PC_LOCATION);
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers, LoweringTool tool) {
+            if (USE_C_RUNTIME) {
+                StructuredGraph graph = loadExceptionObject.graph();
+                ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false));
+                graph.addBeforeFixed(loadExceptionObject, thread);
+                ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread));
+                loadExceptionC.setStateAfter(loadExceptionObject.stateAfter());
+                graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC);
+            } else {
+                Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage());
+                args.addConst("threadRegister", registers.getThreadRegister());
+                template(args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java
new file mode 100644
index 0000000..9174791
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode.beginLockScope;
+import static org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode.compareAndSwap;
+import static org.graalvm.compiler.hotspot.nodes.EndLockScopeNode.endLockScope;
+import static org.graalvm.compiler.hotspot.nodes.VMErrorNode.vmError;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockPattern;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.epochMaskInPlace;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockDisplacedMarkOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileMonitors;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsMethodFilter;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsTypeFilter;
+import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.VerifyBalancedMonitors;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.nodes.AcquiredCASLockNode;
+import org.graalvm.compiler.hotspot.nodes.CurrentLockNode;
+import org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode;
+import org.graalvm.compiler.hotspot.nodes.FastAcquireBiasedLockNode;
+import org.graalvm.compiler.hotspot.nodes.MonitorCounterNode;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
+import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordBase;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Snippets used for implementing the monitorenter and monitorexit instructions.
+ *
+ * The locking algorithm used is described in the paper
+ * <a href="http://dl.acm.org/citation.cfm?id=1167515.1167496"> Eliminating synchronization-related
+ * atomic operations with biased locking and bulk rebiasing</a> by Kenneth Russell and David
+ * Detlefs.
+ *
+ * Comment below is reproduced from {@code markOop.hpp} for convenience:
+ *
+ * <pre>
+ *  Bit-format of an object header (most significant first, big endian layout below):
+ *  32 bits:
+ *  --------
+ *             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
+ *             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
+ *             size:32 ------------------------------------------>| (CMS free block)
+ *             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
+ *
+ *  64 bits:
+ *  --------
+ *  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
+ *  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
+ *  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
+ *  size:64 ----------------------------------------------------->| (CMS free block)
+ *
+ *  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
+ *  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
+ *  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
+ *  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
+ *
+ *  - hash contains the identity hash value: largest value is
+ *    31 bits, see os::random().  Also, 64-bit vm's require
+ *    a hash value no bigger than 32 bits because they will not
+ *    properly generate a mask larger than that: see library_call.cpp
+ *    and c1_CodePatterns_sparc.cpp.
+ *
+ *  - the biased lock pattern is used to bias a lock toward a given
+ *    thread. When this pattern is set in the low three bits, the lock
+ *    is either biased toward a given thread or "anonymously" biased,
+ *    indicating that it is possible for it to be biased. When the
+ *    lock is biased toward a given thread, locking and unlocking can
+ *    be performed by that thread without using atomic operations.
+ *    When a lock's bias is revoked, it reverts back to the normal
+ *    locking scheme described below.
+ *
+ *    Note that we are overloading the meaning of the "unlocked" state
+ *    of the header. Because we steal a bit from the age we can
+ *    guarantee that the bias pattern will never be seen for a truly
+ *    unlocked object.
+ *
+ *    Note also that the biased state contains the age bits normally
+ *    contained in the object header. Large increases in scavenge
+ *    times were seen when these bits were absent and an arbitrary age
+ *    assigned to all biased objects, because they tended to consume a
+ *    significant fraction of the eden semispaces and were not
+ *    promoted promptly, causing an increase in the amount of copying
+ *    performed. The runtime system aligns all JavaThread* pointers to
+ *    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
+ *    to make room for the age bits & the epoch bits (used in support of
+ *    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
+ *
+ *    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
+ *    [0           | epoch | age | 1 | 01]       lock is anonymously biased
+ *
+ *  - the two lock bits are used to describe three states: locked/unlocked and monitor.
+ *
+ *    [ptr             | 00]  locked             ptr points to real header on stack
+ *    [header      | 0 | 01]  unlocked           regular object header
+ *    [ptr             | 10]  monitor            inflated lock (header is wapped out)
+ *    [ptr             | 11]  marked             used by markSweep to mark an object
+ *                                               not valid at any other time
+ *
+ *    We assume that stack/thread pointers have the lowest two bits cleared.
+ * </pre>
+ *
+ * Note that {@code Thread::allocate} enforces {@code JavaThread} objects to be aligned
+ * appropriately to comply with the layouts above.
+ */
+public class MonitorSnippets implements Snippets {
+
+    private static final boolean PROFILE_CONTEXT = false;
+
+    @Fold
+    static boolean doProfile() {
+        return ProfileMonitors.getValue();
+    }
+
+    @Snippet
+    public static void monitorenter(Object object, KlassPointer hub, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister,
+                    @ConstantParameter boolean trace) {
+        verifyOop(object);
+
+        // Load the mark word - this includes a null-check on object
+        final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
+
+        final Word lock = beginLockScope(lockDepth);
+
+        trace(trace, "           object: 0x%016lx\n", Word.objectToTrackedPointer(object));
+        trace(trace, "             lock: 0x%016lx\n", lock);
+        trace(trace, "             mark: 0x%016lx\n", mark);
+
+        incCounter();
+
+        if (useBiasedLocking(INJECTED_VMCONFIG)) {
+            // See whether the lock is currently biased toward our thread and
+            // whether the epoch is still valid.
+            // Note that the runtime guarantees sufficient alignment of JavaThread
+            // pointers to allow age to be placed into low bits.
+            final Word biasableLockBits = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
+
+            // Check whether the bias pattern is present in the object's mark word
+            // and the bias owner and the epoch are both still current.
+            final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
+            final Word thread = registerAsWord(threadRegister);
+            final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace(INJECTED_VMCONFIG));
+            trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
+            trace(trace, "           thread: 0x%016lx\n", thread);
+            trace(trace, "              tmp: 0x%016lx\n", tmp);
+            if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, tmp.equal(0))) {
+                // Object is already biased to current thread -> done
+                traceObject(trace, "+lock{bias:existing}", object, true);
+                lockBiasExisting.inc();
+                FastAcquireBiasedLockNode.mark(object);
+                return;
+            }
+
+            // Now check to see whether biasing is enabled for this object
+            if (probability(BranchProbabilityNode.FAST_PATH_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
+                // Biasing not enabled -> fall through to lightweight locking
+                unbiasable.inc();
+            } else {
+                // At this point we know that the mark word has the bias pattern and
+                // that we are not the bias owner in the current epoch. We need to
+                // figure out more details about the state of the mark word in order to
+                // know what operations can be legally performed on the object's
+                // mark word.
+
+                // If the low three bits in the xor result aren't clear, that means
+                // the prototype header is no longer biasable and we have to revoke
+                // the bias on this object.
+                if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
+                    // Biasing is still enabled for object's type. See whether the
+                    // epoch of the current bias is still valid, meaning that the epoch
+                    // bits of the mark word are equal to the epoch bits of the
+                    // prototype mark word. (Note that the prototype mark word's epoch bits
+                    // only change at a safepoint.) If not, attempt to rebias the object
+                    // toward the current thread. Note that we must be absolutely sure
+                    // that the current epoch is invalid in order to do this because
+                    // otherwise the manipulations it performs on the mark word are
+                    // illegal.
+                    if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
+                        // The epoch of the current bias is still valid but we know nothing
+                        // about the owner; it might be set or it might be clear. Try to
+                        // acquire the bias of the object using an atomic operation. If this
+                        // fails we will go in to the runtime to revoke the object's bias.
+                        // Note that we first construct the presumed unbiased header so we
+                        // don't accidentally blow away another thread's valid bias.
+                        Word unbiasedMark = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG));
+                        Word biasedMark = unbiasedMark.or(thread);
+                        trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
+                        trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
+                        if (probability(VERY_FAST_PATH_PROBABILITY,
+                                        compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
+                            // Object is now biased to current thread -> done
+                            traceObject(trace, "+lock{bias:acquired}", object, true);
+                            lockBiasAcquired.inc();
+                            return;
+                        }
+                        // If the biasing toward our thread failed, this means that another thread
+                        // owns the bias and we need to revoke that bias. The revocation will occur
+                        // in the interpreter runtime.
+                        traceObject(trace, "+lock{stub:revoke}", object, true);
+                        lockStubRevoke.inc();
+                    } else {
+                        // At this point we know the epoch has expired, meaning that the
+                        // current bias owner, if any, is actually invalid. Under these
+                        // circumstances _only_, are we allowed to use the current mark word
+                        // value as the comparison value when doing the CAS to acquire the
+                        // bias in the current epoch. In other words, we allow transfer of
+                        // the bias from one thread to another directly in this situation.
+                        Word biasedMark = prototypeMarkWord.or(thread);
+                        trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
+                        if (probability(VERY_FAST_PATH_PROBABILITY,
+                                        compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
+                            // Object is now biased to current thread -> done
+                            traceObject(trace, "+lock{bias:transfer}", object, true);
+                            lockBiasTransfer.inc();
+                            return;
+                        }
+                        // If the biasing toward our thread failed, then another thread
+                        // succeeded in biasing it toward itself and we need to revoke that
+                        // bias. The revocation will occur in the runtime in the slow case.
+                        traceObject(trace, "+lock{stub:epoch-expired}", object, true);
+                        lockStubEpochExpired.inc();
+                    }
+                    monitorenterStubC(MONITORENTER, object, lock);
+                    return;
+                } else {
+                    // The prototype mark word doesn't have the bias bit set any
+                    // more, indicating that objects of this data type are not supposed
+                    // to be biased any more. We are going to try to reset the mark of
+                    // this object to the prototype value and fall through to the
+                    // CAS-based locking scheme. Note that if our CAS fails, it means
+                    // that another thread raced us for the privilege of revoking the
+                    // bias of this particular object, so it's okay to continue in the
+                    // normal locking code.
+                    Word result = compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), mark, prototypeMarkWord, MARK_WORD_LOCATION);
+
+                    // Fall through to the normal CAS-based lock, because no matter what
+                    // the result of the above CAS, some thread must have succeeded in
+                    // removing the bias bit from the object's header.
+
+                    if (ENABLE_BREAKPOINT) {
+                        bkpt(object, mark, tmp, result);
+                    }
+                    revokeBias.inc();
+                }
+            }
+        }
+
+        // Create the unlocked mark word pattern
+        Word unlockedMark = mark.or(unlockedMask(INJECTED_VMCONFIG));
+        trace(trace, "     unlockedMark: 0x%016lx\n", unlockedMark);
+
+        // Copy this unlocked mark word into the lock slot on the stack
+        lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), unlockedMark, DISPLACED_MARK_WORD_LOCATION);
+
+        // Test if the object's mark word is unlocked, and if so, store the
+        // (address of) the lock slot into the object's mark word.
+        Word currentMark = compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), unlockedMark, lock, MARK_WORD_LOCATION);
+        if (probability(BranchProbabilityNode.SLOW_PATH_PROBABILITY, currentMark.notEqual(unlockedMark))) {
+            trace(trace, "      currentMark: 0x%016lx\n", currentMark);
+            // The mark word in the object header was not the same.
+            // Either the object is locked by another thread or is already locked
+            // by the current thread. The latter is true if the mark word
+            // is a stack pointer into the current thread's stack, i.e.:
+            //
+            // 1) (currentMark & aligned_mask) == 0
+            // 2) rsp <= currentMark
+            // 3) currentMark <= rsp + page_size
+            //
+            // These 3 tests can be done by evaluating the following expression:
+            //
+            // (currentMark - rsp) & (aligned_mask - page_size)
+            //
+            // assuming both the stack pointer and page_size have their least
+            // significant 2 bits cleared and page_size is a power of 2
+            final Word alignedMask = Word.unsigned(wordSize() - 1);
+            final Word stackPointer = registerAsWord(stackPointerRegister).add(config(INJECTED_VMCONFIG).stackBias);
+            if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
+                // Most likely not a recursive lock, go into a slow runtime call
+                traceObject(trace, "+lock{stub:failed-cas}", object, true);
+                lockStubFailedCas.inc();
+                monitorenterStubC(MONITORENTER, object, lock);
+                return;
+            } else {
+                // Recursively locked => write 0 to the lock slot
+                lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), Word.zero(), DISPLACED_MARK_WORD_LOCATION);
+                traceObject(trace, "+lock{cas:recursive}", object, true);
+                lockCasRecursive.inc();
+            }
+        } else {
+            traceObject(trace, "+lock{cas}", object, true);
+            lockCas.inc();
+            AcquiredCASLockNode.mark(object);
+        }
+    }
+
+    /**
+     * Calls straight out to the monitorenter stub.
+     */
+    @Snippet
+    public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
+        verifyOop(object);
+        incCounter();
+        if (object == null) {
+            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
+        }
+        // BeginLockScope nodes do not read from object so a use of object
+        // cannot float about the null check above
+        final Word lock = beginLockScope(lockDepth);
+        traceObject(trace, "+lock{stub}", object, true);
+        monitorenterStubC(MONITORENTER, object, lock);
+    }
+
+    @Snippet
+    public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
+        trace(trace, "           object: 0x%016lx\n", Word.objectToTrackedPointer(object));
+        if (useBiasedLocking(INJECTED_VMCONFIG)) {
+            // Check for biased locking unlock case, which is a no-op
+            // Note: we do not have to check the thread ID for two reasons.
+            // First, the interpreter checks for IllegalMonitorStateException at
+            // a higher level. Second, if the bias was revoked while we held the
+            // lock, the object could not be rebiased toward another thread, so
+            // the bias bit would be clear.
+            final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
+            trace(trace, "             mark: 0x%016lx\n", mark);
+            if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
+                endLockScope();
+                decCounter();
+                traceObject(trace, "-lock{bias}", object, false);
+                unlockBias.inc();
+                return;
+            }
+        }
+
+        final Word lock = CurrentLockNode.currentLock(lockDepth);
+
+        // Load displaced mark
+        final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), DISPLACED_MARK_WORD_LOCATION);
+        trace(trace, "    displacedMark: 0x%016lx\n", displacedMark);
+
+        if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, displacedMark.equal(0))) {
+            // Recursive locking => done
+            traceObject(trace, "-lock{recursive}", object, false);
+            unlockCasRecursive.inc();
+        } else {
+            verifyOop(object);
+            // Test if object's mark word is pointing to the displaced mark word, and if so, restore
+            // the displaced mark in the object - if the object's mark word is not pointing to
+            // the displaced mark word, do unlocking via runtime call.
+            if (probability(VERY_SLOW_PATH_PROBABILITY,
+                            DirectCompareAndSwapNode.compareAndSwap(OffsetAddressNode.address(object, markOffset(INJECTED_VMCONFIG)), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) {
+                // The object's mark word was not pointing to the displaced header,
+                // we do unlocking via runtime call.
+                traceObject(trace, "-lock{stub}", object, false);
+                unlockStub.inc();
+                monitorexitStubC(MONITOREXIT, object, lock);
+            } else {
+                traceObject(trace, "-lock{cas}", object, false);
+                unlockCas.inc();
+            }
+        }
+        endLockScope();
+        decCounter();
+    }
+
+    /**
+     * Calls straight out to the monitorexit stub.
+     */
+    @Snippet
+    public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
+        verifyOop(object);
+        traceObject(trace, "-lock{stub}", object, false);
+        final Word lock = CurrentLockNode.currentLock(lockDepth);
+        monitorexitStubC(MONITOREXIT, object, lock);
+        endLockScope();
+        decCounter();
+    }
+
+    public static void traceObject(boolean enabled, String action, Object object, boolean enter) {
+        if (doProfile()) {
+            DynamicCounterNode.counter(action, enter ? "number of monitor enters" : "number of monitor exits", 1, PROFILE_CONTEXT);
+        }
+        if (enabled) {
+            Log.print(action);
+            Log.print(' ');
+            Log.printlnObject(object);
+        }
+    }
+
+    public static void trace(boolean enabled, String format, WordBase value) {
+        if (enabled) {
+            Log.printf(format, value.rawValue());
+        }
+    }
+
+    /**
+     * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode}
+     * intrinsic.
+     */
+    private static final boolean ENABLE_BREAKPOINT = false;
+
+    private static final LocationIdentity MONITOR_COUNTER_LOCATION = NamedLocationIdentity.mutable("MonitorCounter");
+
+    @NodeIntrinsic(BreakpointNode.class)
+    static native void bkpt(Object object, Word mark, Word tmp, Word value);
+
+    private static final boolean VERIFY_BALANCED_MONITORS = VerifyBalancedMonitors.getValue();
+
+    public static void incCounter() {
+        if (VERIFY_BALANCED_MONITORS) {
+            final Word counter = MonitorCounterNode.counter();
+            final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
+            counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION);
+        }
+    }
+
+    public static void decCounter() {
+        if (VERIFY_BALANCED_MONITORS) {
+            final Word counter = MonitorCounterNode.counter();
+            final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
+            counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION);
+        }
+    }
+
+    @Snippet
+    private static void initCounter() {
+        final Word counter = MonitorCounterNode.counter();
+        counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION);
+    }
+
+    @Snippet
+    private static void checkCounter(@ConstantParameter String errMsg) {
+        final Word counter = MonitorCounterNode.counter();
+        final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
+        if (count != 0) {
+            vmError(errMsg, count);
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo monitorenter = snippet(MonitorSnippets.class, "monitorenter");
+        private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit");
+        private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub");
+        private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub");
+        private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter");
+        private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter");
+
+        private final boolean useFastLocking;
+
+        public Templates(HotSpotProviders providers, TargetDescription target, boolean useFastLocking) {
+            super(providers, providers.getSnippetReflection(), target);
+            this.useFastLocking = useFastLocking;
+        }
+
+        public void lower(RawMonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = monitorenterNode.graph();
+            checkBalancedMonitors(graph, tool);
+
+            assert ((ObjectStamp) monitorenterNode.object().stamp()).nonNull();
+
+            Arguments args;
+            if (useFastLocking) {
+                args = new Arguments(monitorenter, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("object", monitorenterNode.object());
+                args.add("hub", monitorenterNode.getHub());
+                args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
+                args.addConst("threadRegister", registers.getThreadRegister());
+                args.addConst("stackPointerRegister", registers.getStackPointerRegister());
+                args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method()));
+            } else {
+                args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("object", monitorenterNode.object());
+                args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
+                args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method()));
+            }
+
+            template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(MonitorExitNode monitorexitNode, LoweringTool tool) {
+            StructuredGraph graph = monitorexitNode.graph();
+
+            Arguments args;
+            if (useFastLocking) {
+                args = new Arguments(monitorexit, graph.getGuardsStage(), tool.getLoweringStage());
+            } else {
+                args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage());
+            }
+            args.add("object", monitorexitNode.object());
+            args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth());
+            args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph.method()));
+
+            template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
+        }
+
+        public static boolean isTracingEnabledForType(ValueNode object) {
+            ResolvedJavaType type = StampTool.typeOrNull(object.stamp());
+            String filter = TraceMonitorsTypeFilter.getValue();
+            if (filter == null) {
+                return false;
+            } else {
+                if (filter.length() == 0) {
+                    return true;
+                }
+                if (type == null) {
+                    return false;
+                }
+                return (type.getName().contains(filter));
+            }
+        }
+
+        public static boolean isTracingEnabledForMethod(ResolvedJavaMethod method) {
+            String filter = TraceMonitorsMethodFilter.getValue();
+            if (filter == null) {
+                return false;
+            } else {
+                if (filter.length() == 0) {
+                    return true;
+                }
+                if (method == null) {
+                    return false;
+                }
+                return (method.format("%H.%n").contains(filter));
+            }
+        }
+
+        /**
+         * If balanced monitor checking is enabled then nodes are inserted at the start and all
+         * return points of the graph to initialize and check the monitor counter respectively.
+         */
+        private void checkBalancedMonitors(StructuredGraph graph, LoweringTool tool) {
+            if (VERIFY_BALANCED_MONITORS) {
+                NodeIterable<MonitorCounterNode> nodes = graph.getNodes().filter(MonitorCounterNode.class);
+                if (nodes.isEmpty()) {
+                    // Only insert the nodes if this is the first monitorenter being lowered.
+                    JavaType returnType = initCounter.getMethod().getSignature().getReturnType(initCounter.getMethod().getDeclaringClass());
+                    StampPair returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+                    MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter.getMethod(), new ValueNode[0], returnStamp, null));
+                    InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0));
+                    invoke.setStateAfter(graph.start().stateAfter());
+                    graph.addAfterFixed(graph.start(), invoke);
+
+                    StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null);
+                    InliningUtil.inline(invoke, inlineeGraph, false, null, null);
+
+                    List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot();
+                    for (ReturnNode ret : rets) {
+                        returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass());
+                        String msg = "unbalanced monitors in " + graph.method().format("%H.%n(%p)") + ", count = %d";
+                        ConstantNode errMsg = ConstantNode.forConstant(tool.getConstantReflection().forString(msg), providers.getMetaAccess(), graph);
+                        returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+                        callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnStamp, null));
+                        invoke = graph.add(new InvokeNode(callTarget, 0));
+                        Bytecode code = new ResolvedJavaMethodBytecode(graph.method());
+                        FrameState stateAfter = new FrameState(null, code, BytecodeFrame.AFTER_BCI, new ValueNode[0], new ValueNode[0], 0, new ValueNode[0], null, false, false);
+                        invoke.setStateAfter(graph.add(stateAfter));
+                        graph.addBeforeFixed(ret, invoke);
+
+                        Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage());
+                        args.addConst("errMsg", msg);
+                        inlineeGraph = template(args).copySpecializedGraph();
+                        InliningUtil.inline(invoke, inlineeGraph, false, null, null);
+                    }
+                }
+            }
+        }
+    }
+
+    public static final ForeignCallDescriptor MONITORENTER = new ForeignCallDescriptor("monitorenter", void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void monitorenterStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+
+    /**
+     * Counters for the various paths for acquiring a lock. The counters whose names start with
+     * {@code "lock"} are mutually exclusive. The other counters are for paths that may be shared.
+     */
+    public static final SnippetCounter.Group lockCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("MonitorEnters") : null;
+    public static final SnippetCounter lockBiasExisting = new SnippetCounter(lockCounters, "lock{bias:existing}", "bias-locked previously biased object");
+    public static final SnippetCounter lockBiasAcquired = new SnippetCounter(lockCounters, "lock{bias:acquired}", "bias-locked newly biased object");
+    public static final SnippetCounter lockBiasTransfer = new SnippetCounter(lockCounters, "lock{bias:transfer}", "bias-locked, biased transferred");
+    public static final SnippetCounter lockCas = new SnippetCounter(lockCounters, "lock{cas}", "cas-locked an object");
+    public static final SnippetCounter lockCasRecursive = new SnippetCounter(lockCounters, "lock{cas:recursive}", "cas-locked, recursive");
+    public static final SnippetCounter lockStubEpochExpired = new SnippetCounter(lockCounters, "lock{stub:epoch-expired}", "stub-locked, epoch expired");
+    public static final SnippetCounter lockStubRevoke = new SnippetCounter(lockCounters, "lock{stub:revoke}", "stub-locked, biased revoked");
+    public static final SnippetCounter lockStubFailedCas = new SnippetCounter(lockCounters, "lock{stub:failed-cas}", "stub-locked, failed cas");
+
+    public static final SnippetCounter unbiasable = new SnippetCounter(lockCounters, "unbiasable", "object with unbiasable type");
+    public static final SnippetCounter revokeBias = new SnippetCounter(lockCounters, "revokeBias", "object had bias revoked");
+
+    /**
+     * Counters for the various paths for releasing a lock. The counters whose names start with
+     * {@code "unlock"} are mutually exclusive. The other counters are for paths that may be shared.
+     */
+    public static final SnippetCounter.Group unlockCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("MonitorExits") : null;
+    public static final SnippetCounter unlockBias = new SnippetCounter(unlockCounters, "unlock{bias}", "bias-unlocked an object");
+    public static final SnippetCounter unlockCas = new SnippetCounter(unlockCounters, "unlock{cas}", "cas-unlocked an object");
+    public static final SnippetCounter unlockCasRecursive = new SnippetCounter(unlockCounters, "unlock{cas:recursive}", "cas-unlocked an object, recursive");
+    public static final SnippetCounter unlockStub = new SnippetCounter(unlockCounters, "unlock{stub}", "stub-unlocked an object");
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java
new file mode 100644
index 0000000..564e89a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.core.common.calc.UnsignedMath.belowThan;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayLengthOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.initializeObjectHeader;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.instanceHeaderSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.isInstanceKlassFullyInitialized;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabEnd;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabTop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop;
+import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCast;
+import static org.graalvm.compiler.nodes.PiNode.piCast;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED;
+import static org.graalvm.compiler.replacements.ReplacementsUtil.staticAssert;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
+import static org.graalvm.compiler.replacements.nodes.ExplodeLoopNode.explodeLoop;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotMetaAccessProvider.computeArrayAllocationSize;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.nodes.DimensionsNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PrefetchAllocateNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
+import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
+import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
+import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.MemoryBarriers;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY.
+ */
+public class NewObjectSnippets implements Snippets {
+
+    public static final LocationIdentity INIT_LOCATION = NamedLocationIdentity.mutable("Initialization");
+
+    enum ProfileContext {
+        AllocatingMethod,
+        InstanceOrArray,
+        AllocatedType,
+        AllocatedTypesInMethod,
+        Total
+    }
+
+    @Fold
+    static String createName(String path, String typeContext) {
+        switch (HotspotSnippetsOptions.ProfileAllocationsContext.getValue()) {
+            case AllocatingMethod:
+                return "";
+            case InstanceOrArray:
+                return path;
+            case AllocatedType:
+            case AllocatedTypesInMethod:
+                return typeContext;
+            case Total:
+                return "bytes";
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Fold
+    static boolean doProfile() {
+        return HotspotSnippetsOptions.ProfileAllocations.getValue();
+    }
+
+    @Fold
+    static boolean withContext() {
+        ProfileContext context = HotspotSnippetsOptions.ProfileAllocationsContext.getValue();
+        return context == ProfileContext.AllocatingMethod || context == ProfileContext.AllocatedTypesInMethod;
+    }
+
+    protected static void profileAllocation(String path, long size, String typeContext) {
+        if (doProfile()) {
+            String name = createName(path, typeContext);
+
+            boolean context = withContext();
+            DynamicCounterNode.counter(name, "number of bytes allocated", size, context);
+            DynamicCounterNode.counter(name, "number of allocations", 1, context);
+        }
+    }
+
+    public static void emitPrefetchAllocate(Word address, boolean isArray) {
+        GraalHotSpotVMConfig config = config(INJECTED_VMCONFIG);
+        if (config.allocatePrefetchStyle > 0) {
+            // Insert a prefetch for each allocation only on the fast-path
+            // Generate several prefetch instructions.
+            int lines = isArray ? config.allocatePrefetchLines : config.allocateInstancePrefetchLines;
+            int stepSize = config.allocatePrefetchStepSize;
+            int distance = config.allocatePrefetchDistance;
+            ExplodeLoopNode.explodeLoop();
+            for (int i = 0; i < lines; i++) {
+                PrefetchAllocateNode.prefetch(OffsetAddressNode.address(address, distance));
+                distance += stepSize;
+            }
+        }
+    }
+
+    @Snippet
+    public static Object allocateInstance(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) {
+        Object result;
+        Word thread = registerAsWord(threadRegister);
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+        Word newTop = top.add(size);
+        if (useTLAB(INJECTED_VMCONFIG) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+            writeTlabTop(thread, newTop);
+            emitPrefetchAllocate(newTop, false);
+            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true);
+        } else {
+            new_stub.inc();
+            result = newInstance(HotSpotBackend.NEW_INSTANCE, hub);
+        }
+        profileAllocation("instance", size, typeContext);
+        return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
+
+    @Snippet
+    public static Object allocateInstancePIC(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
+                    @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) {
+        // Klass must be initialized by the time the first instance is allocated, therefore we can
+        // just load it from the corresponding cell and avoid the resolution check. We have to use a
+        // fixed load though, to prevent it from floating above the initialization.
+        KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
+        return allocateInstance(size, picHub, prototypeMarkWord, fillContents, threadRegister, constantSize, typeContext);
+    }
+
+    @Snippet
+    public static Object allocateInstanceDynamic(Class<?> type, Class<?> classClass, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
+        if (probability(SLOW_PATH_PROBABILITY, type == null || DynamicNewInstanceNode.throwsInstantiationException(type, classClass))) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+
+        KlassPointer hub = ClassGetHubNode.readClass(type);
+        if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
+            if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
+                int layoutHelper = readLayoutHelper(hub);
+                /*
+                 * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number,
+                 * the instance size. This size is already passed through align_object_size and
+                 * scaled to bytes. The low order bit is set if instances of this class cannot be
+                 * allocated using the fastpath.
+                 */
+                if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) {
+                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
+                    /*
+                     * FIXME(je,ds): we should actually pass typeContext instead of "" but late
+                     * binding of parameters is not yet supported by the GraphBuilderPlugin system.
+                     */
+                    return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, "");
+                }
+            }
+        }
+        return dynamicNewInstanceStub(type);
+    }
+
+    /**
+     * Maximum array length for which fast path allocation is used.
+     */
+    public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
+
+    @Snippet
+    public static Object allocatePrimitiveArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
+        KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub);
+        return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
+    }
+
+    @Snippet
+    public static Object allocateArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
+        KlassPointer picHub = ResolveConstantSnippets.resolveKlassConstant(hub);
+        return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
+    }
+
+    @Snippet
+    public static Object allocateArray(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
+        Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
+    }
+
+    private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents,
+                    @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean maybeUnroll, String typeContext, boolean skipNegativeCheck) {
+        Object result;
+        int alignment = wordSize();
+        int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
+        Word thread = registerAsWord(threadRegister);
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+        Word newTop = top.add(allocationSize);
+        if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB(INJECTED_VMCONFIG) &&
+                        probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+            writeTlabTop(thread, newTop);
+            emitPrefetchAllocate(newTop, true);
+            newarray_loopInit.inc();
+            result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
+        } else {
+            result = newArray(HotSpotBackend.NEW_ARRAY, hub, length, fillContents);
+        }
+        profileAllocation("array", allocationSize, typeContext);
+        return result;
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length, boolean fillContents);
+
+    public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
+    public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
+
+    public static Object dynamicNewInstanceStub(Class<?> elementType) {
+        return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType);
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
+
+    @Snippet
+    public static Object allocateArrayDynamic(Class<?> elementType, Class<?> voidClass, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
+                    @ConstantParameter JavaKind knownElementKind, @ConstantParameter int knownLayoutHelper, Word prototypeMarkWord) {
+        Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, threadRegister, knownElementKind, knownLayoutHelper, prototypeMarkWord);
+        return result;
+    }
+
+    private static Object allocateArrayDynamicImpl(Class<?> elementType, Class<?> voidClass, int length, boolean fillContents, Register threadRegister, JavaKind knownElementKind,
+                    int knownLayoutHelper, Word prototypeMarkWord) {
+        /*
+         * We only need the dynamic check for void when we have no static information from
+         * knownElementKind.
+         */
+        staticAssert(knownElementKind != JavaKind.Void, "unsupported knownElementKind");
+        if (knownElementKind == JavaKind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType, voidClass))) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+
+        KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION);
+        if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, klass.isNull() || length < 0)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        int layoutHelper = knownElementKind != JavaKind.Illegal ? knownLayoutHelper : readLayoutHelper(klass);
+        //@formatter:off
+        // from src/share/vm/oops/klass.hpp:
+        //
+        // For arrays, layout helper is a negative number, containing four
+        // distinct bytes, as follows:
+        //    MSB:[tag, hsz, ebt, log2(esz)]:LSB
+        // where:
+        //    tag is 0x80 if the elements are oops, 0xC0 if non-oops
+        //    hsz is array header size in bytes (i.e., offset of first element)
+        //    ebt is the BasicType of the elements
+        //    esz is the element size in bytes
+        //@formatter:on
+
+        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
+        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
+
+        Object result = allocateArrayImpl(klass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
+    }
+
+    /**
+     * Calls the runtime stub for implementing MULTIANEWARRAY.
+     */
+    @Snippet
+    public static Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
+        Word dims = DimensionsNode.allocaDimsArray(rank);
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < rank; i++) {
+            dims.writeInt(i * 4, dimensions[i], INIT_LOCATION);
+        }
+        return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims);
+    }
+
+    @Snippet
+    public static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
+        KlassPointer hubPIC = ResolveConstantSnippets.resolveKlassConstant(hub);
+        return newmultiarray(hubPIC, rank, dimensions);
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
+
+    /**
+     * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
+     * objects have their bodies initialized in a loop.
+     */
+    private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8;
+
+    /**
+     * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring
+     * that stores are aligned.
+     *
+     * @param size number of bytes to zero
+     * @param memory beginning of object which is being zeroed
+     * @param constantSize is {@code size} known to be constant in the snippet
+     * @param startOffset offset to begin zeroing. May not be word aligned.
+     * @param manualUnroll maximally unroll zeroing
+     */
+    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
+    }
+
+    private static void fillMemory(long value, int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
+        int offset = startOffset;
+        if ((offset & 0x7) != 0) {
+            memory.writeInt(offset, (int) value, INIT_LOCATION);
+            offset += 4;
+        }
+        ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
+        if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
+            ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time");
+            // This case handles arrays of constant length. Instead of having a snippet variant for
+            // each length, generate a chain of stores of maximum length. Once it's inlined the
+            // break statement will trim excess stores.
+            if (useSnippetCounters) {
+                new_seqInit.inc();
+            }
+            explodeLoop();
+            for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) {
+                if (offset == size) {
+                    break;
+                }
+                memory.initializeLong(offset, value, INIT_LOCATION);
+            }
+        } else {
+            // Use Word instead of int to avoid extension to long in generated code
+            Word off = Word.signed(offset);
+            if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
+                if (useSnippetCounters) {
+                    new_seqInit.inc();
+                }
+                explodeLoop();
+            } else {
+                if (useSnippetCounters) {
+                    new_loopInit.inc();
+                }
+            }
+            for (; off.rawValue() < size; off = off.add(8)) {
+                memory.initializeLong(off, value, INIT_LOCATION);
+            }
+        }
+    }
+
+    /**
+     * Fill uninitialized memory with garbage value in a newly allocated object, unrolling as
+     * necessary and ensuring that stores are aligned.
+     *
+     * @param size number of bytes to zero
+     * @param memory beginning of object which is being zeroed
+     * @param constantSize is {@code  size} known to be constant in the snippet
+     * @param startOffset offset to begin zeroing. May not be word aligned.
+     * @param manualUnroll maximally unroll zeroing
+     */
+    private static void fillWithGarbage(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
+    }
+
+    /**
+     * Formats some allocated memory with an object header and zeroes out the rest. Disables asserts
+     * since they can't be compiled in stubs.
+     */
+    public static Object formatObjectForStub(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
+        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, false);
+    }
+
+    /**
+     * Formats some allocated memory with an object header and zeroes out the rest.
+     */
+    protected static Object formatObject(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean useSnippetCounters) {
+        Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
+        initializeObjectHeader(memory, prototypeMarkWord, hub);
+        if (fillContents) {
+            zeroMemory(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, useSnippetCounters);
+        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            fillWithGarbage(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, useSnippetCounters);
+        }
+        MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, INIT_LOCATION);
+        return memory.toObject();
+    }
+
+    @Snippet
+    protected static void verifyHeap(@ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
+        Word topValue = readTlabTop(thread);
+        if (!topValue.equal(Word.zero())) {
+            Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION);
+            if (topValueContents.equal(Word.zero())) {
+                AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L);
+            }
+        }
+    }
+
+    /**
+     * Formats some allocated memory with an object header and zeroes out the rest.
+     */
+    public static Object formatArray(KlassPointer hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
+                    boolean useSnippetCounters) {
+        memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, INIT_LOCATION);
+        /*
+         * store hub last as the concurrent garbage collectors assume length is valid if hub field
+         * is not null
+         */
+        initializeObjectHeader(memory, prototypeMarkWord, hub);
+        if (fillContents) {
+            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
+        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
+        }
+        MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, INIT_LOCATION);
+        return memory.toObject();
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo allocateInstancePIC = snippet(NewObjectSnippets.class, "allocateInstancePIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
+                        TLAB_END_LOCATION);
+        private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo allocateArrayPIC = snippet(NewObjectSnippets.class, "allocateArrayPIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo allocatePrimitiveArrayPIC = snippet(NewObjectSnippets.class, "allocatePrimitiveArrayPIC", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
+                        TLAB_END_LOCATION);
+        private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
+                        TLAB_END_LOCATION);
+        private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
+                        TLAB_END_LOCATION);
+        private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray", INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo newmultiarrayPIC = snippet(NewObjectSnippets.class, "newmultiarrayPIC", INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap");
+        private final GraalHotSpotVMConfig config;
+
+        public Templates(HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config) {
+            super(providers, providers.getSnippetReflection(), target);
+            this.config = config;
+        }
+
+        /**
+         * Lowers a {@link NewInstanceNode}.
+         */
+        public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = newInstanceNode.graph();
+            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
+            assert !type.isArray();
+            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
+            int size = instanceSize(type);
+
+            SnippetInfo snippet = GeneratePIC.getValue() ? allocateInstancePIC : allocateInstance;
+            Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.addConst("size", size);
+            args.add("hub", hub);
+            args.add("prototypeMarkWord", type.prototypeMarkWord());
+            args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("constantSize", true);
+            args.addConst("typeContext", HotspotSnippetsOptions.ProfileAllocations.getValue() ? type.toJavaName(false) : "");
+
+            SnippetTemplate template = template(args);
+            Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
+            template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
+        }
+
+        /**
+         * Lowers a {@link NewArrayNode}.
+         */
+        public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = newArrayNode.graph();
+            ResolvedJavaType elementType = newArrayNode.elementType();
+            HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
+            JavaKind elementKind = elementType.getJavaKind();
+            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayType.klass(), providers.getMetaAccess(), graph);
+            final int headerSize = getArrayBaseOffset(elementKind);
+            int log2ElementSize = CodeUtil.log2(HotSpotJVMCIRuntimeProvider.getArrayIndexScale(elementKind));
+
+            SnippetInfo snippet;
+            if (GeneratePIC.getValue()) {
+                if (elementType.isPrimitive()) {
+                    snippet = allocatePrimitiveArrayPIC;
+                } else {
+                    snippet = allocateArrayPIC;
+                }
+            } else {
+                snippet = allocateArray;
+            }
+
+            Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("hub", hub);
+            ValueNode length = newArrayNode.length();
+            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
+            assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord";
+            args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
+            args.addConst("headerSize", headerSize);
+            args.addConst("log2ElementSize", log2ElementSize);
+            args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("maybeUnroll", length.isConstant());
+            args.addConst("typeContext", HotspotSnippetsOptions.ProfileAllocations.getValue() ? arrayType.toJavaName(false) : "");
+            SnippetTemplate template = template(args);
+            Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
+            template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(DynamicNewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            Arguments args = new Arguments(allocateInstanceDynamic, newInstanceNode.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("type", newInstanceNode.getInstanceType());
+            ValueNode classClass = newInstanceNode.getClassClass();
+            assert classClass != null;
+            args.add("classClass", classClass);
+            args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
+
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = newArrayNode.graph();
+            Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("elementType", newArrayNode.getElementType());
+            ValueNode voidClass = newArrayNode.getVoidClass();
+            assert voidClass != null;
+            args.add("voidClass", voidClass);
+            ValueNode length = newArrayNode.length();
+            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
+            args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            /*
+             * We use Kind.Illegal as a marker value instead of null because constant snippet
+             * parameters cannot be null.
+             */
+            args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? JavaKind.Illegal : newArrayNode.getKnownElementKind());
+            if (newArrayNode.getKnownElementKind() != null) {
+                args.addConst("knownLayoutHelper", lookupArrayClass(tool, newArrayNode.getKnownElementKind()).layoutHelper());
+            } else {
+                args.addConst("knownLayoutHelper", 0);
+            }
+            args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
+        }
+
+        private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, JavaKind kind) {
+            return (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(kind == JavaKind.Object ? Object.class : kind.toJavaClass()).getArrayClass();
+        }
+
+        public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
+            StructuredGraph graph = newmultiarrayNode.graph();
+            int rank = newmultiarrayNode.dimensionCount();
+            ValueNode[] dims = new ValueNode[rank];
+            for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) {
+                dims[i] = newmultiarrayNode.dimension(i);
+            }
+            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type();
+            ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
+
+            SnippetInfo snippet = GeneratePIC.getValue() ? newmultiarrayPIC : newmultiarray;
+            Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("hub", hub);
+            args.addConst("rank", rank);
+            args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims);
+            template(args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
+        }
+
+        private static int instanceSize(HotSpotResolvedObjectType type) {
+            int size = type.instanceSize();
+            assert size >= 0;
+            return size;
+        }
+
+        public void lower(VerifyHeapNode verifyHeapNode, HotSpotRegistersProvider registers, LoweringTool tool) {
+            if (config.cAssertions) {
+                Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
+                args.addConst("threadRegister", registers.getThreadRegister());
+
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
+            } else {
+                GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);
+            }
+        }
+    }
+
+    private static final SnippetCounter.Group countersNew = SnippetCounters.getValue() ? new SnippetCounter.Group("NewInstance") : null;
+    private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing");
+    private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
+    private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub");
+
+    private static final SnippetCounter.Group countersNewArray = SnippetCounters.getValue() ? new SnippetCounter.Group("NewArray") : null;
+    private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
+    private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub");
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java
new file mode 100644
index 0000000..7e6252d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.nodes.BasicObjectCloneNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo
+public final class ObjectCloneNode extends BasicObjectCloneNode implements VirtualizableAllocation, ArrayLengthProvider {
+
+    public static final NodeClass<ObjectCloneNode> TYPE = NodeClass.create(ObjectCloneNode.class);
+
+    public ObjectCloneNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnStamp, receiver);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) {
+        ResolvedJavaType type = StampTool.typeOrNull(getObject());
+        if (type != null) {
+            if (type.isArray()) {
+                Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getJavaKind());
+                if (method != null) {
+                    final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(method);
+                    final Replacements replacements = tool.getReplacements();
+                    StructuredGraph snippetGraph = null;
+                    try (Scope s = Debug.scope("ArrayCloneSnippet", snippetMethod)) {
+                        snippetGraph = replacements.getSnippet(snippetMethod, null);
+                    } catch (Throwable e) {
+                        throw Debug.handle(e);
+                    }
+
+                    assert snippetGraph != null : "ObjectCloneSnippets should be installed";
+                    return lowerReplacement((StructuredGraph) snippetGraph.copy(), tool);
+                }
+                assert false : "unhandled array type " + type.getComponentType().getJavaKind();
+            } else {
+                Assumptions assumptions = graph().getAssumptions();
+                type = getConcreteType(getObject().stamp());
+                if (type != null) {
+                    StructuredGraph newGraph = new StructuredGraph(AllowAssumptions.from(assumptions != null), INVALID_COMPILATION_ID);
+                    ParameterNode param = newGraph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(getObject().stamp())));
+                    NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true));
+                    newGraph.addAfterFixed(newGraph.start(), newInstance);
+                    ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance));
+                    newGraph.addAfterFixed(newInstance, returnNode);
+
+                    for (ResolvedJavaField field : type.getInstanceFields(true)) {
+                        LoadFieldNode load = newGraph.add(LoadFieldNode.create(newGraph.getAssumptions(), param, field));
+                        newGraph.addBeforeFixed(returnNode, load);
+                        newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load)));
+                    }
+                    return lowerReplacement(newGraph, tool);
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneSnippets.java
new file mode 100644
index 0000000..7c1aec1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneSnippets.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import java.lang.reflect.Method;
+import java.util.EnumMap;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyCallNode;
+import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class ObjectCloneSnippets implements Snippets {
+
+    public static final EnumMap<JavaKind, Method> arrayCloneMethods = new EnumMap<>(JavaKind.class);
+
+    static {
+        arrayCloneMethods.put(JavaKind.Boolean, getCloneMethod("booleanArrayClone", boolean[].class));
+        arrayCloneMethods.put(JavaKind.Byte, getCloneMethod("byteArrayClone", byte[].class));
+        arrayCloneMethods.put(JavaKind.Char, getCloneMethod("charArrayClone", char[].class));
+        arrayCloneMethods.put(JavaKind.Short, getCloneMethod("shortArrayClone", short[].class));
+        arrayCloneMethods.put(JavaKind.Int, getCloneMethod("intArrayClone", int[].class));
+        arrayCloneMethods.put(JavaKind.Float, getCloneMethod("floatArrayClone", float[].class));
+        arrayCloneMethods.put(JavaKind.Long, getCloneMethod("longArrayClone", long[].class));
+        arrayCloneMethods.put(JavaKind.Double, getCloneMethod("doubleArrayClone", double[].class));
+        arrayCloneMethods.put(JavaKind.Object, getCloneMethod("objectArrayClone", Object[].class));
+    }
+
+    private static Method getCloneMethod(String name, Class<?> param) {
+        try {
+            return ObjectCloneSnippets.class.getDeclaredMethod(name, param);
+        } catch (SecurityException | NoSuchMethodException e) {
+            throw new GraalError(e);
+        }
+    }
+
+    @Snippet
+    public static boolean[] booleanArrayClone(boolean[] src) {
+        boolean[] result = (boolean[]) NewArrayNode.newUninitializedArray(Boolean.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Boolean);
+        return result;
+    }
+
+    @Snippet
+    public static byte[] byteArrayClone(byte[] src) {
+        byte[] result = (byte[]) NewArrayNode.newUninitializedArray(Byte.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Byte);
+        return result;
+    }
+
+    @Snippet
+    public static short[] shortArrayClone(short[] src) {
+        short[] result = (short[]) NewArrayNode.newUninitializedArray(Short.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Short);
+        return result;
+    }
+
+    @Snippet
+    public static char[] charArrayClone(char[] src) {
+        char[] result = (char[]) NewArrayNode.newUninitializedArray(Character.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Char);
+        return result;
+    }
+
+    @Snippet
+    public static int[] intArrayClone(int[] src) {
+        int[] result = (int[]) NewArrayNode.newUninitializedArray(Integer.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Int);
+        return result;
+    }
+
+    @Snippet
+    public static float[] floatArrayClone(float[] src) {
+        float[] result = (float[]) NewArrayNode.newUninitializedArray(Float.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Float);
+        return result;
+    }
+
+    @Snippet
+    public static long[] longArrayClone(long[] src) {
+        long[] result = (long[]) NewArrayNode.newUninitializedArray(Long.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Long);
+        return result;
+    }
+
+    @Snippet
+    public static double[] doubleArrayClone(double[] src) {
+        double[] result = (double[]) NewArrayNode.newUninitializedArray(Double.TYPE, src.length);
+        ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, JavaKind.Double);
+        return result;
+    }
+
+    @Snippet
+    public static Object[] objectArrayClone(Object[] src) {
+        /* Since this snippet is lowered early the array must be initialized */
+        Object[] result = (Object[]) DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(src.getClass().getComponentType()), src.length, JavaKind.Object);
+        ArrayCopyCallNode.disjointUninitializedArraycopy(src, 0, result, 0, src.length, JavaKind.Object);
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java
new file mode 100644
index 0000000..1ca911e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link java.lang.Object} methods.
+ */
+@ClassSubstitution(Object.class)
+public class ObjectSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static int hashCode(final Object thisObj) {
+        return IdentityHashCodeNode.identityHashCode(thisObj);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java
new file mode 100644
index 0000000..6556bd9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "This node can be lowered to a call", size = SIZE_20)
+public final class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
+
+    public static final NodeClass<ReflectionGetCallerClassNode> TYPE = NodeClass.create(ReflectionGetCallerClassNode.class);
+
+    public ReflectionGetCallerClassNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection());
+        if (callerClassNode != null) {
+            return callerClassNode;
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection());
+
+        if (callerClassNode != null) {
+            graph().replaceFixedWithFloating(this, graph().addOrUniqueWithInputs(callerClassNode));
+        } else {
+            InvokeNode invoke = createInvoke();
+            graph().replaceFixedWithFixed(this, invoke);
+            invoke.lower(tool);
+        }
+    }
+
+    /**
+     * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by
+     * walking the the stack.
+     *
+     * @param metaAccess
+     * @return ConstantNode of the caller class, or null
+     */
+    private ConstantNode getCallerClassNode(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        // Walk back up the frame states to find the caller at the required depth.
+        FrameState state = stateAfter();
+
+        // Cf. JVM_GetCallerClass
+        // NOTE: Start the loop at depth 1 because the current frame state does
+        // not include the Reflection.getCallerClass() frame.
+        for (int n = 1; state != null; state = state.outerFrameState(), n++) {
+            HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.getMethod();
+            switch (n) {
+                case 0:
+                    throw GraalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame");
+                case 1:
+                    // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass).
+                    if (!method.isCallerSensitive()) {
+                        return null;  // bail-out; let JVM_GetCallerClass do the work
+                    }
+                    break;
+                default:
+                    if (!method.ignoredBySecurityStackWalk()) {
+                        // We have reached the desired frame; return the holder class.
+                        HotSpotResolvedObjectType callerClass = method.getDeclaringClass();
+                        return ConstantNode.forConstant(constantReflection.asJavaClass(callerClass), metaAccess);
+                    }
+                    break;
+            }
+        }
+        return null;  // bail-out; let JVM_GetCallerClass do the work
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java
new file mode 100644
index 0000000..4df4cdd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.jvmAccWrittenFlags;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset;
+
+import java.lang.reflect.Modifier;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+
+/**
+ * Substitutions for {@link sun.reflect.Reflection} methods.
+ */
+@ClassSubstitution(className = {"jdk.internal.reflect.Reflection", "sun.reflect.Reflection"}, optional = true)
+public class ReflectionSubstitutions {
+
+    @MethodSubstitution
+    public static int getClassAccessFlags(Class<?> aClass) {
+        KlassPointer klass = ClassGetHubNode.readClass(GraalDirectives.guardingNonNull(aClass));
+        if (klass.isNull()) {
+            // Class for primitive type
+            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
+        } else {
+            return klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION) & jvmAccWrittenFlags(INJECTED_VMCONFIG);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java
new file mode 100644
index 0000000..b72577f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@ClassSubstitution(className = "sun.security.provider.SHA2", optional = true)
+public class SHA2Substitutions {
+
+    static final long stateOffset;
+
+    static final Class<?> shaClass;
+
+    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+
+    static {
+        try {
+            // Need to use the system class loader as com.sun.crypto.provider.AESCrypt
+            // is normally loaded by the extension class loader which is not delegated
+            // to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+            shaClass = Class.forName("sun.security.provider.SHA2", true, cl);
+            stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state"));
+        } catch (Exception ex) {
+            throw new GraalError(ex);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void implCompress0(Object receiver, byte[] buf, int ofs) {
+        Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
+        Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
+        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        HotSpotBackend.sha2ImplCompressStub(bufAddr, stateAddr);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java
new file mode 100644
index 0000000..0abda01
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@ClassSubstitution(className = "sun.security.provider.SHA5", optional = true)
+public class SHA5Substitutions {
+
+    static final long stateOffset;
+
+    static final Class<?> shaClass;
+
+    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+
+    static {
+        try {
+            // Need to use the system class loader as com.sun.crypto.provider.AESCrypt
+            // is normally loaded by the extension class loader which is not delegated
+            // to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+            shaClass = Class.forName("sun.security.provider.SHA5", true, cl);
+            stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state"));
+        } catch (Exception ex) {
+            throw new GraalError(ex);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void implCompress0(Object receiver, byte[] buf, int ofs) {
+        Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
+        Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
+        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        HotSpotBackend.sha5ImplCompressStub(bufAddr, stateAddr);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java
new file mode 100644
index 0000000..7d389f0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@ClassSubstitution(className = "sun.security.provider.SHA", optional = true)
+public class SHASubstitutions {
+
+    static final long stateOffset;
+
+    static final Class<?> shaClass;
+
+    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+
+    static {
+        try {
+            // Need to use the system class loader as com.sun.crypto.provider.AESCrypt
+            // is normally loaded by the extension class loader which is not delegated
+            // to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+            shaClass = Class.forName("sun.security.provider.SHA", true, cl);
+            stateOffset = UnsafeAccess.UNSAFE.objectFieldOffset(shaClass.getDeclaredField("state"));
+        } catch (Exception ex) {
+            throw new GraalError(ex);
+        }
+    }
+
+    @MethodSubstitution(isStatic = false)
+    static void implCompress0(Object receiver, byte[] buf, int ofs) {
+        Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
+        Object state = UnsafeLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
+        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        HotSpotBackend.shaImplCompressStub(bufAddr, stateAddr);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java
new file mode 100644
index 0000000..434ae81
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.debug.StringToBytesNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.CStringConstant;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code StringToBytesSnippets} contains a snippet for lowering {@link StringToBytesNode}.
+ */
+public class StringToBytesSnippets implements Snippets {
+
+    public static final LocationIdentity CSTRING_LOCATION = NamedLocationIdentity.immutable("CString location");
+
+    @Fold
+    static long arrayBaseOffset() {
+        return UNSAFE.arrayBaseOffset(char[].class);
+    }
+
+    @Snippet
+    public static byte[] transform(@ConstantParameter String compilationTimeString) {
+        int i = compilationTimeString.length();
+        byte[] array = (byte[]) NewArrayNode.newUninitializedArray(byte.class, i);
+        Word cArray = CStringConstant.cstring(compilationTimeString);
+        while (i-- > 0) {
+            // array[i] = cArray.readByte(i);
+            UNSAFE.putByte(array, arrayBaseOffset() + i, cArray.readByte(i, CSTRING_LOCATION));
+        }
+        return array;
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo create;
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+            create = snippet(StringToBytesSnippets.class, "transform", NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+        }
+
+        public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) {
+            Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage());
+            args.addConst("compilationTimeString", stringToBytesNode.getValue());
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args);
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java
new file mode 100644
index 0000000..99fb04d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OSTHREAD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadInterruptedOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadObjectOffset;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.word.Word;
+
+/**
+ * Substitutions for {@link java.lang.Thread} methods.
+ */
+@ClassSubstitution(Thread.class)
+public class ThreadSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
+        Word javaThread = CurrentJavaThreadNode.get();
+        Object thread = javaThread.readObject(threadObjectOffset(INJECTED_VMCONFIG), JAVA_THREAD_THREAD_OBJECT_LOCATION);
+        if (thisObject == thread) {
+            Word osThread = javaThread.readWord(osThreadOffset(INJECTED_VMCONFIG), JAVA_THREAD_OSTHREAD_LOCATION);
+            boolean interrupted = osThread.readInt(osThreadInterruptedOffset(INJECTED_VMCONFIG), any()) != 0;
+            if (!interrupted || !clearInterrupted) {
+                return interrupted;
+            }
+        }
+
+        return threadIsInterruptedStub(THREAD_IS_INTERRUPTED, thisObject, clearInterrupted);
+    }
+
+    public static final ForeignCallDescriptor THREAD_IS_INTERRUPTED = new ForeignCallDescriptor("thread_is_interrupted", boolean.class, Thread.class, boolean.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native boolean threadIsInterruptedStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Thread thread, boolean clearIsInterrupted);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/TypeCheckSnippetUtils.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/TypeCheckSnippetUtils.java
new file mode 100644
index 0000000..b112d1a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/TypeCheckSnippetUtils.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_CHECK_OFFSET_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.METASPACE_ARRAY_LENGTH_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PRIMARY_SUPERS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPERS_ELEMENT_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPERS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPER_CACHE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.metaspaceArrayBaseOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.metaspaceArrayLengthOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.secondarySuperCacheOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.secondarySupersOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.TypeCheckHints;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+//JaCoCo Exclude
+
+/**
+ * Utilities and common code paths used by the type check snippets.
+ */
+public class TypeCheckSnippetUtils {
+
+    static boolean checkSecondarySubType(KlassPointer t, KlassPointer s) {
+        // if (S.cache == T) return true
+        if (s.readKlassPointer(secondarySuperCacheOffset(INJECTED_VMCONFIG), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) {
+            cacheHit.inc();
+            return true;
+        }
+
+        return checkSelfAndSupers(t, s);
+    }
+
+    static boolean checkUnknownSubType(KlassPointer t, KlassPointer s) {
+        // int off = T.offset
+        int superCheckOffset = t.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION);
+        boolean primary = superCheckOffset != secondarySuperCacheOffset(INJECTED_VMCONFIG);
+
+        // if (T = S[off]) return true
+        if (s.readKlassPointer(superCheckOffset, PRIMARY_SUPERS_LOCATION).equal(t)) {
+            if (primary) {
+                cacheHit.inc();
+            } else {
+                displayHit.inc();
+            }
+            return true;
+        }
+
+        // if (off != &cache) return false
+        if (primary) {
+            displayMiss.inc();
+            return false;
+        }
+
+        return checkSelfAndSupers(t, s);
+    }
+
+    private static boolean checkSelfAndSupers(KlassPointer t, KlassPointer s) {
+        // if (T == S) return true
+        if (s.equal(t)) {
+            T_equals_S.inc();
+            return true;
+        }
+
+        // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
+        Word secondarySupers = s.readWord(secondarySupersOffset(INJECTED_VMCONFIG), SECONDARY_SUPERS_LOCATION);
+        int length = secondarySupers.readInt(metaspaceArrayLengthOffset(INJECTED_VMCONFIG), METASPACE_ARRAY_LENGTH_LOCATION);
+        for (int i = 0; i < length; i++) {
+            if (probability(NOT_LIKELY_PROBABILITY, t.equal(loadSecondarySupersElement(secondarySupers, i)))) {
+                s.writeKlassPointer(secondarySuperCacheOffset(INJECTED_VMCONFIG), t, SECONDARY_SUPER_CACHE_LOCATION);
+                secondariesHit.inc();
+                return true;
+            }
+        }
+        secondariesMiss.inc();
+        return false;
+    }
+
+    /**
+     * A set of type check hints ordered by decreasing probabilities.
+     */
+    public static class Hints {
+
+        /**
+         * The hubs of the hint types.
+         */
+        public final ConstantNode[] hubs;
+
+        /**
+         * A predicate over {@link #hubs} specifying whether the corresponding hint type is a
+         * sub-type of the checked type.
+         */
+        public final boolean[] isPositive;
+
+        Hints(ConstantNode[] hints, boolean[] hintIsPositive) {
+            this.hubs = hints;
+            this.isPositive = hintIsPositive;
+        }
+    }
+
+    static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, StructuredGraph graph) {
+        ConstantNode[] hubs = new ConstantNode[hints.hints.length];
+        boolean[] isPositive = new boolean[hints.hints.length];
+        int index = 0;
+        for (int i = 0; i < hubs.length; i++) {
+            if (!positiveOnly || hints.hints[i].positive) {
+                hubs[index] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) hints.hints[i].type).klass(), metaAccess, graph);
+                isPositive[index] = hints.hints[i].positive;
+                index++;
+            }
+        }
+        if (positiveOnly && index != hubs.length) {
+            assert index < hubs.length;
+            hubs = Arrays.copyOf(hubs, index);
+            isPositive = Arrays.copyOf(isPositive, index);
+        }
+        return new Hints(hubs, isPositive);
+    }
+
+    static KlassPointer loadSecondarySupersElement(Word metaspaceArray, int index) {
+        return KlassPointer.fromWord(metaspaceArray.readWord(metaspaceArrayBaseOffset(INJECTED_VMCONFIG) + index * wordSize(), SECONDARY_SUPERS_ELEMENT_LOCATION));
+    }
+
+    private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("TypeCheck") : null;
+    static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type");
+    static final SnippetCounter hintsMiss = new SnippetCounter(counters, "hintsMiss", "missed a hint type");
+    static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded");
+    static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed");
+    static final SnippetCounter isNull = new SnippetCounter(counters, "isNull", "object tested was null");
+    static final SnippetCounter cacheHit = new SnippetCounter(counters, "cacheHit", "secondary type cache hit");
+    static final SnippetCounter secondariesHit = new SnippetCounter(counters, "secondariesHit", "secondaries scan succeeded");
+    static final SnippetCounter secondariesMiss = new SnippetCounter(counters, "secondariesMiss", "secondaries scan failed");
+    static final SnippetCounter displayHit = new SnippetCounter(counters, "displayHit", "primary type test succeeded");
+    static final SnippetCounter displayMiss = new SnippetCounter(counters, "displayMiss", "primary type test failed");
+    static final SnippetCounter T_equals_S = new SnippetCounter(counters, "T_equals_S", "object type was equal to secondary type");
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeAccess.java
new file mode 100644
index 0000000..2d8464e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeAccess.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java
new file mode 100644
index 0000000..0eef687
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class UnsafeLoadSnippets implements Snippets {
+
+    @Snippet
+    public static Object lowerUnsafeLoad(Object object, long offset) {
+        Object fixedObject = FixedValueAnchorNode.getObject(object);
+        if (object instanceof java.lang.ref.Reference && referentOffset() == offset) {
+            return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.PRECISE);
+        } else {
+            return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.NONE);
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo unsafeLoad = snippet(UnsafeLoadSnippets.class, "lowerUnsafeLoad");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(UnsafeLoadNode load, LoweringTool tool) {
+            Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("object", load.object());
+            args.add("offset", load.offset());
+            template(args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java
new file mode 100644
index 0000000..526e9a5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueBufferOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueIndexOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueBufferOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueIndexOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueMarkingOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1YoungCardValue;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.CompressEncoding;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
+import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.extended.NullCheckNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode;
+import org.graalvm.compiler.replacements.nodes.DirectStoreNode;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Unsigned;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+public class WriteBarrierSnippets implements Snippets {
+
+    private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null;
+    private static final SnippetCounter serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
+    private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of attempted G1 Pre Write Barriers");
+    private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of effective G1 Pre Write Barriers");
+    private static final SnippetCounter g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of executed G1 Pre Write Barriers");
+    private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
+    private static final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the XOR test)");
+    private static final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the NULL test)");
+    private static final SnippetCounter g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
+
+    public static final LocationIdentity GC_CARD_LOCATION = NamedLocationIdentity.mutable("GC-Card");
+    public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log");
+    public static final LocationIdentity GC_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Index");
+
+    private static void serialWriteBarrier(Pointer ptr) {
+        serialWriteBarrierCounter.inc();
+        final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
+        Word base = (Word) ptr.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
+        if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
+            base.writeByte((int) startAddress, (byte) 0, GC_CARD_LOCATION);
+        } else {
+            base.writeByte(Word.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION);
+        }
+    }
+
+    @Snippet
+    public static void serialImpreciseWriteBarrier(Object object) {
+        serialWriteBarrier(Word.objectToTrackedPointer(object));
+    }
+
+    @Snippet
+    public static void serialPreciseWriteBarrier(Address address) {
+        serialWriteBarrier(Word.fromAddress(address));
+    }
+
+    @Snippet
+    public static void serialArrayRangeWriteBarrier(Object object, int startIndex, int length) {
+        if (length == 0) {
+            return;
+        }
+        Object dest = FixedValueAnchorNode.getObject(object);
+        int cardShift = cardTableShift(INJECTED_VMCONFIG);
+        final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
+        final int scale = arrayIndexScale(JavaKind.Object);
+        int header = arrayBaseOffset(JavaKind.Object);
+        long dstAddr = GetObjectAddressNode.get(dest);
+        long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift;
+        long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift;
+        long count = end - start + 1;
+        while (count-- > 0) {
+            DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean);
+        }
+    }
+
+    @Snippet
+    public static void g1PreWriteBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
+                    @ConstantParameter Register threadRegister, @ConstantParameter boolean trace) {
+        if (nullCheck) {
+            NullCheckNode.nullCheck(address);
+        }
+        Word thread = registerAsWord(threadRegister);
+        verifyOop(object);
+        Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
+        Pointer field = Word.fromAddress(address);
+        Pointer previousOop = Word.objectToTrackedPointer(fixedExpectedObject);
+        byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
+        int gcCycle = 0;
+        if (trace) {
+            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0);
+            log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(fixedExpectedObject).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
+            log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
+        }
+        g1AttemptedPreWriteBarrierCounter.inc();
+        // If the concurrent marker is enabled, the barrier is issued.
+        if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
+            // If the previous value has to be loaded (before the write), the load is issued.
+            // The load is always issued except the cases of CAS and referent field.
+            if (probability(LIKELY_PROBABILITY, doLoad)) {
+                previousOop = Word.objectToTrackedPointer(field.readObject(0, BarrierType.NONE));
+                if (trace) {
+                    log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
+                    verifyOop(previousOop.toObject());
+                }
+            }
+            g1EffectivePreWriteBarrierCounter.inc();
+            // If the previous value is null the barrier should not be issued.
+            if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
+                g1ExecutedPreWriteBarrierCounter.inc();
+                // If the thread-local SATB buffer is full issue a native call which will
+                // initialize a new one and add the entry.
+                Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
+                Word indexValue = indexAddress.readWord(0);
+                if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
+                    Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
+                    Word nextIndex = indexValue.subtract(wordSize());
+                    Word logAddress = bufferAddress.add(nextIndex);
+                    // Log the object to be marked as well as update the SATB's buffer next index.
+                    logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
+                } else {
+                    g1PreBarrierStub(G1WBPRECALL, previousOop.toObject());
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean trace) {
+        Word thread = registerAsWord(threadRegister);
+        Object fixedValue = FixedValueAnchorNode.getObject(value);
+        verifyOop(object);
+        verifyOop(fixedValue);
+        validateObject(object, fixedValue);
+        Pointer oop;
+        if (usePrecise) {
+            oop = Word.fromAddress(address);
+        } else {
+            oop = Word.objectToTrackedPointer(object);
+        }
+        int gcCycle = 0;
+        if (trace) {
+            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0);
+            log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
+            log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
+        }
+        Pointer writtenValue = Word.objectToTrackedPointer(fixedValue);
+        // The result of the xor reveals whether the installed pointer crosses heap regions.
+        // In case it does the write barrier has to be issued.
+        final int logOfHeapRegionGrainBytes = GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes();
+        Unsigned xorResult = (oop.xor(writtenValue)).unsignedShiftRight(logOfHeapRegionGrainBytes);
+
+        // Calculate the address of the card to be enqueued to the
+        // thread local card queue.
+        Unsigned cardBase = oop.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
+        final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
+        int displacement = 0;
+        if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
+            displacement = (int) startAddress;
+        } else {
+            cardBase = cardBase.add(Word.unsigned(startAddress));
+        }
+        Word cardAddress = (Word) cardBase.add(displacement);
+
+        g1AttemptedPostWriteBarrierCounter.inc();
+        if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
+            g1EffectiveAfterXORPostWriteBarrierCounter.inc();
+
+            // If the written value is not null continue with the barrier addition.
+            if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
+                byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
+                g1EffectiveAfterNullPostWriteBarrierCounter.inc();
+
+                // If the card is already dirty, (hence already enqueued) skip the insertion.
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
+                    MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
+                    byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
+                    if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
+                        log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue());
+                        cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
+                        g1ExecutedPostWriteBarrierCounter.inc();
+
+                        // If the thread local card queue is full, issue a native call which will
+                        // initialize a new one and add the card entry.
+                        Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
+                        Word indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
+                        if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
+                            Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
+                            Word nextIndex = indexValue.subtract(wordSize());
+                            Word logAddress = bufferAddress.add(nextIndex);
+                            // Log the object to be scanned as well as update
+                            // the card queue's next index.
+                            logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
+                            indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
+                        } else {
+                            g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
+        byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
+        // If the concurrent marker is not enabled or the vector length is zero, return.
+        if (markingValue == (byte) 0 || length == 0) {
+            return;
+        }
+        Object dest = FixedValueAnchorNode.getObject(object);
+        Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
+        Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
+        long dstAddr = GetObjectAddressNode.get(dest);
+        long indexValue = indexAddress.readWord(0).rawValue();
+        final int scale = arrayIndexScale(JavaKind.Object);
+        int header = arrayBaseOffset(JavaKind.Object);
+
+        for (int i = startIndex; i < length; i++) {
+            long address = dstAddr + header + (i * scale);
+            Pointer oop = Word.objectToTrackedPointer(Word.unsigned(address).readObject(0, BarrierType.NONE));
+            verifyOop(oop.toObject());
+            if (oop.notEqual(0)) {
+                if (indexValue != 0) {
+                    indexValue = indexValue - wordSize();
+                    Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
+                    // Log the object to be marked as well as update the SATB's buffer next index.
+                    logAddress.writeWord(0, oop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
+                } else {
+                    g1PreBarrierStub(G1WBPRECALL, oop.toObject());
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
+        if (length == 0) {
+            return;
+        }
+        Object dest = FixedValueAnchorNode.getObject(object);
+        Word thread = registerAsWord(threadRegister);
+        Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
+        Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
+        long indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG)).rawValue();
+
+        int cardShift = cardTableShift(INJECTED_VMCONFIG);
+        final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
+        final int scale = arrayIndexScale(JavaKind.Object);
+        int header = arrayBaseOffset(JavaKind.Object);
+        long dstAddr = GetObjectAddressNode.get(dest);
+        long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift;
+        long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift;
+        long count = end - start + 1;
+
+        while (count-- > 0) {
+            Word cardAddress = Word.unsigned((start + cardStart) + count);
+            byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
+            // If the card is already dirty, (hence already enqueued) skip the insertion.
+            if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
+                MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
+                byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
+                    cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
+                    // If the thread local card queue is full, issue a native call which will
+                    // initialize a new one and add the card entry.
+                    if (indexValue != 0) {
+                        indexValue = indexValue - wordSize();
+                        Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
+                        // Log the object to be scanned as well as update
+                        // the card queue's next index.
+                        logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
+                        indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
+                    } else {
+                        g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
+                    }
+                }
+            }
+        }
+    }
+
+    public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void g1PreBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
+
+    public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void g1PostBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word card);
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo serialImpreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialImpreciseWriteBarrier", GC_CARD_LOCATION);
+        private final SnippetInfo serialPreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialPreciseWriteBarrier", GC_CARD_LOCATION);
+        private final SnippetInfo serialArrayRangeWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayRangeWriteBarrier");
+        private final SnippetInfo g1PreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
+        private final SnippetInfo g1ReferentReadBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
+        private final SnippetInfo g1PostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
+        private final SnippetInfo g1ArrayRangePreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
+        private final SnippetInfo g1ArrayRangePostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
+
+        private final CompressEncoding oopEncoding;
+
+        public Templates(HotSpotProviders providers, TargetDescription target, CompressEncoding oopEncoding) {
+            super(providers, providers.getSnippetReflection(), target);
+            this.oopEncoding = oopEncoding;
+        }
+
+        public void lower(SerialWriteBarrier writeBarrier, LoweringTool tool) {
+            Arguments args;
+            if (writeBarrier.usePrecise()) {
+                args = new Arguments(serialPreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("address", writeBarrier.getAddress());
+            } else {
+                args = new Arguments(serialImpreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+                OffsetAddressNode address = (OffsetAddressNode) writeBarrier.getAddress();
+                args.add("object", address.getBase());
+            }
+            template(args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
+            Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("object", arrayRangeWriteBarrier.getObject());
+            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("length", arrayRangeWriteBarrier.getLength());
+            template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) {
+            Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = writeBarrierPre.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                args.add("object", null);
+            }
+
+            ValueNode expected = writeBarrierPre.getExpectedObject();
+            if (expected != null && expected.stamp() instanceof NarrowOopStamp) {
+                assert oopEncoding != null;
+                expected = CompressionNode.uncompress(expected, oopEncoding);
+            }
+            args.add("expectedObject", expected);
+
+            args.addConst("doLoad", writeBarrierPre.doLoad());
+            args.addConst("nullCheck", writeBarrierPre.getNullCheck());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("trace", traceBarrier());
+            template(args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
+            Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = readBarrier.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                args.add("object", null);
+            }
+
+            ValueNode expected = readBarrier.getExpectedObject();
+            if (expected != null && expected.stamp() instanceof NarrowOopStamp) {
+                assert oopEncoding != null;
+                expected = CompressionNode.uncompress(expected, oopEncoding);
+            }
+
+            args.add("expectedObject", expected);
+            args.addConst("doLoad", readBarrier.doLoad());
+            args.addConst("nullCheck", false);
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("trace", traceBarrier());
+            template(args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) {
+            StructuredGraph graph = writeBarrierPost.graph();
+            if (writeBarrierPost.alwaysNull()) {
+                graph.removeFixed(writeBarrierPost);
+                return;
+            }
+            Arguments args = new Arguments(g1PostWriteBarrier, graph.getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = writeBarrierPost.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                assert writeBarrierPost.usePrecise() : "found imprecise barrier that's not an object access " + writeBarrierPost;
+                args.add("object", null);
+            }
+
+            ValueNode value = writeBarrierPost.getValue();
+            if (value.stamp() instanceof NarrowOopStamp) {
+                assert oopEncoding != null;
+                value = CompressionNode.uncompress(value, oopEncoding);
+            }
+            args.add("value", value);
+
+            args.addConst("usePrecise", writeBarrierPost.usePrecise());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("trace", traceBarrier());
+            template(args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
+            Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("object", arrayRangeWriteBarrier.getObject());
+            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
+            Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("object", arrayRangeWriteBarrier.getObject());
+            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("threadRegister", registers.getThreadRegister());
+            template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+        }
+    }
+
+    /**
+     * Log method of debugging purposes.
+     */
+    public static void log(boolean enabled, String format, long value) {
+        if (enabled) {
+            Log.printf(format, value);
+        }
+    }
+
+    public static void log(boolean enabled, String format, long value1, long value2) {
+        if (enabled) {
+            Log.printf(format, value1, value2);
+        }
+    }
+
+    public static void log(boolean enabled, String format, long value1, long value2, long value3) {
+        if (enabled) {
+            Log.printf(format, value1, value2, value3);
+        }
+    }
+
+    public static boolean traceBarrier() {
+        return GraalOptions.GCDebugStartCycle.getValue() > 0 &&
+                        ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0) > GraalOptions.GCDebugStartCycle.getValue());
+    }
+
+    /**
+     * Validation helper method which performs sanity checks on write operations. The addresses of
+     * both the object and the value being written are checked in order to determine if they reside
+     * in a valid heap region. If an object is stale, an invalid access is performed in order to
+     * prematurely crash the VM and debug the stack trace of the faulty method.
+     */
+    public static void validateObject(Object parent, Object child) {
+        if (verifyOops(INJECTED_VMCONFIG) && child != null && !validateOop(VALIDATE_OBJECT, parent, child)) {
+            log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.objectToTrackedPointer(parent).rawValue(), Word.objectToTrackedPointer(child).rawValue());
+            DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.any(), JavaKind.Object);
+        }
+    }
+
+    public static final ForeignCallDescriptor VALIDATE_OBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object parent, Object object);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java
new file mode 100644
index 0000000..7b0f000
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.aot;
+
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.aot.EncodedSymbolNode;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
+import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.hotspot.word.MethodCountersPointer;
+import org.graalvm.compiler.hotspot.word.MethodPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+
+public class ResolveConstantSnippets implements Snippets {
+
+    @Snippet
+    public static Object resolveObjectConstant(Object constant) {
+        Object result = LoadConstantIndirectlyNode.loadObject(constant);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) {
+            result = ResolveConstantStubCall.resolveObject(constant, EncodedSymbolNode.encode(constant));
+        }
+        return result;
+    }
+
+    @Snippet
+    public static KlassPointer resolveKlassConstant(KlassPointer constant) {
+        KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
+            result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant));
+        }
+        return result;
+    }
+
+    @Snippet
+    public static MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint) {
+        MethodCountersPointer result = LoadMethodCountersIndirectlyNode.loadMethodCounters(method);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
+            result = ResolveMethodAndLoadCountersStubCall.resolveMethodAndLoadCounters(method, klassHint, EncodedSymbolNode.encode(method));
+        }
+        return result;
+    }
+
+    @Snippet
+    public static KlassPointer initializeKlass(KlassPointer constant) {
+        KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
+            result = InitializeKlassStubCall.initializeKlass(constant, EncodedSymbolNode.encode(constant));
+        }
+        return result;
+    }
+
+    @Snippet
+    public static KlassPointer pureInitializeKlass(KlassPointer constant) {
+        KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
+            result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant), HotSpotConstantLoadAction.INITIALIZE);
+        }
+        return result;
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant");
+        private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant");
+        private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters");
+        private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass");
+        private final SnippetInfo pureInitializeKlass = snippet(ResolveConstantSnippets.class, "pureInitializeKlass");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) {
+            StructuredGraph graph = resolveConstantNode.graph();
+
+            ValueNode value = resolveConstantNode.value();
+            assert value.isConstant() : "Expected a constant: " + value;
+            Constant constant = value.asConstant();
+            SnippetInfo snippet = null;
+
+            if (constant instanceof HotSpotMetaspaceConstant) {
+                HotSpotMetaspaceConstant hotspotMetaspaceConstant = (HotSpotMetaspaceConstant) constant;
+                if (hotspotMetaspaceConstant.asResolvedJavaType() != null) {
+                    if (resolveConstantNode.action() == HotSpotConstantLoadAction.RESOLVE) {
+                        snippet = resolveKlassConstant;
+                    } else {
+                        assert resolveConstantNode.action() == HotSpotConstantLoadAction.INITIALIZE;
+                        snippet = pureInitializeKlass;
+                    }
+                }
+            } else if (constant instanceof HotSpotObjectConstant) {
+                snippet = resolveObjectConstant;
+                HotSpotObjectConstant hotspotObjectConstant = (HotSpotObjectConstant) constant;
+                assert hotspotObjectConstant.isInternedString();
+            }
+            if (snippet == null) {
+                throw new GraalError("Unsupported constant type: " + constant);
+            }
+
+            Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("constant", value);
+
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, tool, args);
+
+            assert resolveConstantNode.hasNoUsages();
+            if (!resolveConstantNode.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode);
+            }
+        }
+
+        public void lower(InitializeKlassNode initializeKlassNode, LoweringTool tool) {
+            StructuredGraph graph = initializeKlassNode.graph();
+
+            ValueNode value = initializeKlassNode.value();
+            assert value.isConstant() : "Expected a constant: " + value;
+            Constant constant = value.asConstant();
+
+            if (constant instanceof HotSpotMetaspaceConstant) {
+                Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("constant", value);
+
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args);
+                assert initializeKlassNode.hasNoUsages();
+                if (!initializeKlassNode.isDeleted()) {
+                    GraphUtil.killWithUnusedFloatingInputs(initializeKlassNode);
+                }
+
+            } else {
+                throw new GraalError("Unsupported constant type: " + constant);
+            }
+        }
+
+        public void lower(ResolveMethodAndLoadCountersNode resolveMethodAndLoadCountersNode, LoweringTool tool) {
+            StructuredGraph graph = resolveMethodAndLoadCountersNode.graph();
+            ConstantNode method = ConstantNode.forConstant(MethodPointerStamp.methodNonNull(), resolveMethodAndLoadCountersNode.getMethod().getEncoding(), tool.getMetaAccess(), graph);
+            Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("method", method);
+            args.add("klassHint", resolveMethodAndLoadCountersNode.getHub());
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, tool, args);
+
+            assert resolveMethodAndLoadCountersNode.hasNoUsages();
+            if (!resolveMethodAndLoadCountersNode.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(resolveMethodAndLoadCountersNode);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java
new file mode 100644
index 0000000..50618b2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+//JaCoCo Exclude
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable {
+
+    public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class);
+    @Input protected ValueNode src;
+    @Input protected ValueNode srcPos;
+    @Input protected ValueNode dest;
+    @Input protected ValueNode destPos;
+    @Input protected ValueNode length;
+
+    @OptionalInput(Memory) MemoryNode lastLocationAccess;
+
+    protected final JavaKind elementKind;
+    protected final LocationIdentity locationIdentity;
+
+    /**
+     * Aligned means that the offset of the copy is heap word aligned.
+     */
+    protected boolean aligned;
+    protected boolean disjoint;
+    protected boolean uninitialized;
+
+    protected final HotSpotGraalRuntimeProvider runtime;
+
+    public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind,
+                    boolean aligned, boolean disjoint, boolean uninitialized) {
+        this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized);
+    }
+
+    public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind,
+                    boolean disjoint) {
+        this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false);
+    }
+
+    protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind,
+                    LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) {
+        super(TYPE, StampFactory.forVoid());
+        assert elementKind != null;
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.elementKind = elementKind;
+        this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind));
+        this.aligned = aligned;
+        this.disjoint = disjoint;
+        this.uninitialized = uninitialized;
+        this.runtime = runtime;
+    }
+
+    public ValueNode getSource() {
+        return src;
+    }
+
+    public ValueNode getSourcePosition() {
+        return srcPos;
+    }
+
+    public ValueNode getDestination() {
+        return dest;
+    }
+
+    public ValueNode getDestinationPosition() {
+        return destPos;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
+    public JavaKind getElementKind() {
+        return elementKind;
+    }
+
+    private ValueNode computeBase(ValueNode base, ValueNode pos) {
+        FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base));
+        graph().addBeforeFixed(this, basePtr);
+        Stamp wordStamp = StampFactory.forKind(runtime.getTarget().wordJavaKind);
+        ValueNode wordPos = IntegerConvertNode.convert(pos, wordStamp, graph());
+        int shift = CodeUtil.log2(getArrayIndexScale(elementKind));
+        ValueNode scaledIndex = graph().unique(new LeftShiftNode(wordPos, ConstantNode.forInt(shift, graph())));
+        ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerStamp(wordStamp, getArrayBaseOffset(elementKind), graph())));
+        return graph().unique(new OffsetAddressNode(basePtr, offset));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
+            updateAlignedDisjoint();
+            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(),
+                            locationIdentity.equals(LocationIdentity.any()));
+            StructuredGraph graph = graph();
+            ValueNode srcAddr = computeBase(getSource(), getSourcePosition());
+            ValueNode destAddr = computeBase(getDestination(), getDestinationPosition());
+            ValueNode len = getLength();
+            if (len.stamp().getStackKind() != JavaKind.Long) {
+                len = IntegerConvertNode.convert(len, StampFactory.forKind(JavaKind.Long), graph());
+            }
+            ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len));
+            call.setStateAfter(stateAfter());
+            graph.replaceFixedWithFixed(this, call);
+        }
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @NodeIntrinsic
+    private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned,
+                    @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized);
+
+    @NodeIntrinsic
+    private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind,
+                    @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint,
+                    @ConstantNodeParameter boolean uninitialized);
+
+    public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) {
+        arraycopy(src, srcPos, dest, destPos, length, JavaKind.Object, LocationIdentity.any(), false, false, false);
+    }
+
+    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false);
+    }
+
+    public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, false);
+    }
+
+    public static void disjointUninitializedArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind) {
+        arraycopy(src, srcPos, dest, destPos, length, elementKind, false, true, true);
+    }
+
+    public boolean isAligned() {
+        return aligned;
+    }
+
+    public boolean isDisjoint() {
+        return disjoint;
+    }
+
+    public boolean isUninitialized() {
+        return uninitialized;
+    }
+
+    boolean isHeapWordAligned(JavaConstant value, JavaKind kind) {
+        return (getArrayBaseOffset(kind) + (long) value.asInt() * getArrayIndexScale(kind)) % runtime.getVMConfig().heapWordSize == 0;
+    }
+
+    public void updateAlignedDisjoint() {
+        JavaKind componentKind = elementKind;
+        if (srcPos == destPos) {
+            // Can treat as disjoint
+            disjoint = true;
+        }
+        PrimitiveConstant constantSrc = (PrimitiveConstant) srcPos.stamp().asConstant();
+        PrimitiveConstant constantDst = (PrimitiveConstant) destPos.stamp().asConstant();
+        if (constantSrc != null && constantDst != null) {
+            if (!aligned) {
+                aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind);
+            }
+            if (constantSrc.asInt() >= constantDst.asInt()) {
+                // low to high copy so treat as disjoint
+                disjoint = true;
+            }
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) {
+            if (lastLocationAccess != null) {
+                replaceAtUsages(InputType.Memory, lastLocationAccess.asNode());
+            }
+            return null;
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java
new file mode 100644
index 0000000..803ee73
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
+
+@NodeInfo
+public final class ArrayCopyNode extends BasicArrayCopyNode implements Virtualizable, Lowerable {
+
+    public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
+
+    private JavaKind elementKind;
+
+    public ArrayCopyNode(int bci, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+        super(TYPE, src, srcPos, dst, dstPos, length, null, bci);
+        elementKind = ArrayCopySnippets.Templates.selectComponentKind(this);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind == null) {
+            elementKind = ArrayCopySnippets.Templates.selectComponentKind(this);
+        }
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java
new file mode 100644
index 0000000..4111f70
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.JavaKind;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
+
+@NodeInfo(allowedUsageTypes = InputType.Memory)
+public final class ArrayCopySlowPathNode extends BasicArrayCopyNode {
+
+    public static final NodeClass<ArrayCopySlowPathNode> TYPE = NodeClass.create(ArrayCopySlowPathNode.class);
+
+    private final SnippetTemplate.SnippetInfo snippet;
+
+    /**
+     * Extra context for the slow path snippet.
+     */
+    private final Object argument;
+
+    /**
+     * AOT compilation requires klass constants to be exposed after the first lowering to be handled
+     * automatically. Lowering for {@link ArrayCopySlowPathNode}, with snippet ==
+     * {@link ArrayCopySnippets#arraycopyPredictedObjectWork}, requires a klass of Object[]. For
+     * other snippets {@link #predictedKlass} is a null constant.
+     */
+    @Input protected ValueNode predictedKlass;
+
+    public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode predictedKlass, JavaKind elementKind,
+                    SnippetTemplate.SnippetInfo snippet, Object argument) {
+        super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
+        assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
+        this.snippet = snippet;
+        this.argument = argument;
+        this.predictedKlass = predictedKlass;
+    }
+
+    @NodeIntrinsic
+    public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer predictedKlass,
+                    @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet, @ConstantNodeParameter Object argument);
+
+    public SnippetTemplate.SnippetInfo getSnippet() {
+        return snippet;
+    }
+
+    public Object getArgument() {
+        return argument;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    public void setBci(int bci) {
+        this.bci = bci;
+    }
+
+    public ValueNode getPredictedKlass() {
+        return predictedKlass;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java
new file mode 100644
index 0000000..08eab36
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_CHECK_OFFSET_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayClassElementOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypePrimitiveInPlace;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHub;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import java.lang.reflect.Method;
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
+import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode;
+import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class ArrayCopySnippets implements Snippets {
+
+    private static int checkArrayType(KlassPointer hub) {
+        int layoutHelper = readLayoutHelper(hub);
+        if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        return layoutHelper;
+    }
+
+    private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) {
+        if (probability(SLOW_PATH_PROBABILITY, srcPos < 0)) {
+            checkAIOOBECounter.inc();
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        if (probability(SLOW_PATH_PROBABILITY, destPos < 0)) {
+            checkAIOOBECounter.inc();
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        if (probability(SLOW_PATH_PROBABILITY, length < 0)) {
+            checkAIOOBECounter.inc();
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        if (probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length)) {
+            checkAIOOBECounter.inc();
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        if (probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) {
+            checkAIOOBECounter.inc();
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        checkSuccessCounter.inc();
+    }
+
+    @Snippet
+    public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        checkArrayType(srcHub);
+        checkArrayType(destHub);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        zeroLengthStaticCounter.inc();
+    }
+
+    @Snippet
+    public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter counter,
+                    @ConstantParameter SnippetCounter copiedCounter) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        counter.inc();
+        copiedCounter.add(length);
+        ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+            nonZeroLengthDynamicCopiedCounter.add(length);
+        }
+    }
+
+    /**
+     * This intrinsic is useful for the case where we know something statically about one of the
+     * inputs but not the other.
+     */
+    @Snippet
+    public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind,
+                    @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        counter.inc();
+        copiedCounter.add(length);
+        ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+            nonZeroLengthDynamicCopiedCounter.add(length);
+        }
+    }
+
+    @Snippet
+    public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass,
+                    @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter) {
+        if (length > 0) {
+            KlassPointer srcHub = loadHub(PiNode.asNonNullObject(nonNullSrc));
+            KlassPointer destHub = loadHub(PiNode.asNonNullObject(nonNullDest));
+            if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) {
+                counter.inc();
+                copiedCounter.add(length);
+                predictedObjectArrayCopyFastPathCounter.inc();
+                predictedObjectArrayCopyFastPathCopiedCounter.add(length);
+                ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            } else {
+                predictedObjectArrayCopySlowPathCounter.inc();
+                predictedObjectArrayCopySlowPathCopiedCounter.add(length);
+                System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            }
+        }
+    }
+
+    /**
+     * This is the basic template for the full arraycopy checks, including a check that the
+     * underlying type is really an array type.
+     */
+    @Snippet
+    public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, KlassPointer predictedKlass, @ConstantParameter JavaKind elementKind,
+                    @ConstantParameter SnippetInfo slowPath, @ConstantParameter Object slowPathArgument) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        checkArrayType(srcHub);
+        checkArrayType(destHub);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+            nonZeroLengthDynamicCopiedCounter.add(length);
+        }
+        ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, predictedKlass, elementKind, slowPath, slowPathArgument);
+    }
+
+    /**
+     * Snippet for unrolled arraycopy.
+     */
+    @Snippet
+    public static void arraycopyUnrolledIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter int unrolledLength, @ConstantParameter JavaKind elementKind) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        if (length == 0) {
+            zeroLengthDynamicCounter.inc();
+        } else {
+            nonZeroLengthDynamicCounter.inc();
+            nonZeroLengthDynamicCopiedCounter.add(length);
+        }
+        ArrayCopyUnrollNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, unrolledLength, elementKind);
+    }
+
+    @Snippet
+    public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length) {
+        if (length > 0) {
+            KlassPointer destKlass = loadHub(nonNullDest);
+            KlassPointer srcKlass = loadHub(nonNullSrc);
+            if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) {
+                // no storecheck required.
+                objectCheckcastSameTypeCounter.inc();
+                objectCheckcastSameTypeCopiedCounter.add(length);
+                ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            } else {
+                KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
+                Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
+                objectCheckcastCounter.inc();
+                objectCheckcastCopiedCounter.add(length);
+                int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
+                if (copiedElements != 0) {
+                    /*
+                     * the checkcast stub doesn't throw the ArrayStoreException, but returns the
+                     * number of copied elements (xor'd with -1).
+                     */
+                    copiedElements ^= -1;
+                    System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length) {
+        Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+        Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+        KlassPointer srcHub = loadHub(nonNullSrc);
+        KlassPointer destHub = loadHub(nonNullDest);
+        if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) {
+            int layoutHelper = checkArrayType(srcHub);
+            final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace(INJECTED_VMCONFIG)) == 0);
+            checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            if (probability(FAST_PATH_PROBABILITY, isObjectArray)) {
+                genericObjectExactCallCounter.inc();
+                genericObjectExactCallCopiedCounter.add(length);
+                ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, JavaKind.Object);
+            } else {
+                genericPrimitiveCallCounter.inc();
+                genericPrimitiveCallCopiedCounter.add(length);
+                UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper);
+            }
+        } else {
+            SystemArraycopyCounter.inc();
+            SystemArraycopyCopiedCounter.add(length);
+            System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
+        }
+    }
+
+    @Fold
+    static LocationIdentity getArrayLocation(JavaKind kind) {
+        return NamedLocationIdentity.getArrayLocation(kind);
+    }
+
+    @Snippet
+    public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter JavaKind elementKind) {
+        final int scale = arrayIndexScale(elementKind);
+        int arrayBaseOffset = arrayBaseOffset(elementKind);
+        LocationIdentity arrayLocation = getArrayLocation(elementKind);
+        if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case
+            long start = (long) (length - 1) * scale;
+            long i = start;
+            ExplodeLoopNode.explodeLoop();
+            for (int iteration = 0; iteration < length; iteration++) {
+                if (i >= 0) {
+                    Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
+                    DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind);
+                    i -= scale;
+                }
+            }
+        } else {
+            long end = (long) length * scale;
+            long i = 0;
+            ExplodeLoopNode.explodeLoop();
+            for (int iteration = 0; iteration < length; iteration++) {
+                if (i < end) {
+                    Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
+                    DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind);
+                    i += scale;
+                }
+            }
+        }
+    }
+
+    private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null;
+    private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess");
+    private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE");
+
+    private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy") : null;
+
+    private static final SnippetCounter objectCheckcastCounter = new SnippetCounter(counters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
+    private static final SnippetCounter objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]{slow-path}", "used System.arraycopy slow path for predicted Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
+
+    private static final EnumMap<JavaKind, SnippetCounter> arraycopyCallCounters = new EnumMap<>(JavaKind.class);
+    private static final EnumMap<JavaKind, SnippetCounter> arraycopyCounters = new EnumMap<>(JavaKind.class);
+
+    private static final EnumMap<JavaKind, SnippetCounter> arraycopyCallCopiedCounters = new EnumMap<>(JavaKind.class);
+    private static final EnumMap<JavaKind, SnippetCounter> arraycopyCopiedCounters = new EnumMap<>(JavaKind.class);
+
+    static void createArraycopyCounter(JavaKind kind) {
+        arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
+        arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
+
+        arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
+        arraycopyCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
+    }
+
+    static {
+        createArraycopyCounter(JavaKind.Byte);
+        createArraycopyCounter(JavaKind.Boolean);
+        createArraycopyCounter(JavaKind.Char);
+        createArraycopyCounter(JavaKind.Short);
+        createArraycopyCounter(JavaKind.Int);
+        createArraycopyCounter(JavaKind.Long);
+        createArraycopyCounter(JavaKind.Float);
+        createArraycopyCounter(JavaKind.Double);
+        createArraycopyCounter(JavaKind.Object);
+    }
+
+    private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
+    private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
+    private static final SnippetCounter SystemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy");
+
+    private static final SnippetCounter.Group lengthCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy 0-length checks") : null;
+
+    private static final SnippetCounter zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0");
+    private static final SnippetCounter zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0");
+    private static final SnippetCounter nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
+
+    private static final SnippetCounter.Group copiedCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy copied elements") : null;
+
+    private static final SnippetCounter nonZeroLengthDynamicCopiedCounter = new SnippetCounter(copiedCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
+    private static final SnippetCounter genericPrimitiveCallCopiedCounter = new SnippetCounter(copiedCounters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
+    private static final SnippetCounter genericObjectExactCallCopiedCounter = new SnippetCounter(copiedCounters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
+    private static final SnippetCounter SystemArraycopyCopiedCounter = new SnippetCounter(copiedCounters, "genericObject", "call to System.arraycopy");
+
+    private static final SnippetCounter objectCheckcastCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
+    private static final SnippetCounter objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopySlowPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{slow-path}",
+                    "used System.arraycopy slow path for predicted Object[] arrays");
+    private static final SnippetCounter predictedObjectArrayCopyFastPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
+
+    public static class Templates extends SnippetTemplate.AbstractTemplates {
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        private ResolvedJavaMethod originalArraycopy() throws GraalError {
+            if (originalArraycopy == null) {
+                Method method;
+                try {
+                    method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
+                } catch (NoSuchMethodException | SecurityException e) {
+                    throw new GraalError(e);
+                }
+                originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
+            }
+            return originalArraycopy;
+        }
+
+        private ResolvedJavaMethod originalArraycopy;
+
+        private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork");
+        private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric");
+
+        private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic");
+        private final SnippetInfo arraycopyUnrolledIntrinsicSnippet = snippet("arraycopyUnrolledIntrinsic");
+        private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic");
+        private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic");
+        private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic");
+        private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork");
+
+        private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork");
+
+        protected SnippetInfo snippet(String methodName) {
+            SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any());
+            info.setOriginalMethod(originalArraycopy());
+            return info;
+        }
+
+        public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) {
+            return selectComponentKind(arraycopy, true);
+        }
+
+        public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) {
+            ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
+            ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+
+            if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+                if (!exact) {
+                    JavaKind component = getComponentKind(srcType);
+                    if (component != null) {
+                        return component;
+                    }
+                    return getComponentKind(destType);
+                }
+                return null;
+            }
+            if (exact) {
+                if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
+                    return null;
+                }
+                if (!arraycopy.isExact()) {
+                    return null;
+                }
+            }
+            return srcType.getComponentType().getJavaKind();
+        }
+
+        private static JavaKind getComponentKind(ResolvedJavaType type) {
+            if (type != null && type.isArray()) {
+                return type.getComponentType().getJavaKind();
+            }
+            return null;
+        }
+
+        private static boolean shouldUnroll(ValueNode length) {
+            return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
+        }
+
+        public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
+            JavaKind componentKind = selectComponentKind(arraycopy);
+            SnippetInfo snippetInfo = null;
+            SnippetInfo slowPathSnippetInfo = null;
+            Object slowPathArgument = null;
+
+            if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
+                snippetInfo = arraycopyZeroLengthIntrinsicSnippet;
+            } else if (arraycopy.isExact()) {
+                snippetInfo = arraycopyExactIntrinsicSnippet;
+                if (shouldUnroll(arraycopy.getLength())) {
+                    snippetInfo = arraycopyUnrolledIntrinsicSnippet;
+                }
+            } else {
+                if (componentKind == JavaKind.Object) {
+                    ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
+                    ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+                    ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
+                    ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
+                    if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
+                        snippetInfo = arraycopySlowPathIntrinsicSnippet;
+                        slowPathSnippetInfo = checkcastArraycopyWorkSnippet;
+                        slowPathArgument = LocationIdentity.any();
+                        /*
+                         * Because this snippet has to use Sysytem.arraycopy as a slow path, we must
+                         * pretend to kill any() so clear the componentKind.
+                         */
+                        componentKind = null;
+                    }
+                }
+                if (componentKind == null && snippetInfo == null) {
+                    JavaKind predictedKind = selectComponentKind(arraycopy, false);
+                    if (predictedKind != null) {
+                        /*
+                         * At least one array is of a known type requiring no store checks, so
+                         * assume the other is of the same type. Generally this is working around
+                         * deficiencies in our propagation of type information.
+                         */
+                        componentKind = predictedKind;
+                        if (predictedKind == JavaKind.Object) {
+                            snippetInfo = arraycopySlowPathIntrinsicSnippet;
+                            slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet;
+                            slowPathArgument = predictedKind;
+                            componentKind = null;
+                        } else {
+                            snippetInfo = arraycopyPredictedExactIntrinsicSnippet;
+                        }
+                    }
+                }
+                if (snippetInfo == null) {
+                    snippetInfo = arraycopyGenericSnippet;
+                }
+            }
+            Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("src", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("dest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            args.add("length", arraycopy.getLength());
+            if (snippetInfo == arraycopyUnrolledIntrinsicSnippet) {
+                args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt());
+                args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
+            } else if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
+                ValueNode predictedKlass = null;
+                if (slowPathArgument == arraycopyPredictedObjectWorkSnippet) {
+                    HotSpotResolvedObjectType arrayClass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class);
+                    predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayClass.klass(), tool.getMetaAccess(), arraycopy.graph());
+                } else {
+                    predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassAlwaysNull(), JavaConstant.NULL_POINTER, tool.getMetaAccess(), arraycopy.graph());
+                }
+                args.add("predictedKlass", predictedKlass);
+                args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
+                args.addConst("slowPath", slowPathSnippetInfo);
+                assert slowPathArgument != null;
+                args.addConst("slowPathArgument", slowPathArgument);
+            } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) {
+                assert componentKind != null;
+                args.addConst("elementKind", componentKind);
+                args.addConst("counter", arraycopyCallCounters.get(componentKind));
+                args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(componentKind));
+            }
+            instantiate(args, arraycopy);
+        }
+
+        public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) {
+            StructuredGraph graph = arraycopy.graph();
+            if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                // Can't be lowered yet
+                return;
+            }
+            SnippetInfo snippetInfo = arraycopy.getSnippet();
+            Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("nonNullSrc", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("nonNullDest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            if (snippetInfo == arraycopyUnrolledWorkSnippet) {
+                args.addConst("length", ((Integer) arraycopy.getArgument()).intValue());
+                args.addConst("elementKind", arraycopy.getElementKind());
+            } else {
+                args.add("length", arraycopy.getLength());
+            }
+            if (snippetInfo == arraycopyPredictedObjectWorkSnippet) {
+                args.add("objectArrayKlass", arraycopy.getPredictedKlass());
+                args.addConst("counter", arraycopyCallCounters.get(JavaKind.Object));
+                args.addConst("copiedCounter", arraycopyCallCopiedCounters.get(JavaKind.Object));
+            }
+            instantiate(args, arraycopy);
+        }
+
+        public void lower(ArrayCopyUnrollNode arraycopy, LoweringTool tool) {
+            StructuredGraph graph = arraycopy.graph();
+            if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                // Can't be lowered yet
+                return;
+            }
+            SnippetInfo snippetInfo = arraycopyUnrolledWorkSnippet;
+            Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("nonNullSrc", arraycopy.getSource());
+            args.add("srcPos", arraycopy.getSourcePosition());
+            args.add("nonNullDest", arraycopy.getDestination());
+            args.add("destPos", arraycopy.getDestinationPosition());
+            args.addConst("length", arraycopy.getUnrollLength());
+            args.addConst("elementKind", arraycopy.getElementKind());
+            template(args).instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        /**
+         * Instantiate the snippet template and fix up the FrameState of any Invokes of
+         * System.arraycopy and propagate the captured bci in the ArrayCopySlowPathNode.
+         *
+         * @param args
+         * @param arraycopy
+         */
+        private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
+            StructuredGraph graph = arraycopy.graph();
+            SnippetTemplate template = template(args);
+            Map<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+            for (Node originalNode : replacements.keySet()) {
+                if (originalNode instanceof Invoke) {
+                    Invoke invoke = (Invoke) replacements.get(originalNode);
+                    assert invoke.asNode().graph() == graph;
+                    CallTargetNode call = invoke.callTarget();
+
+                    if (!call.targetMethod().equals(originalArraycopy)) {
+                        throw new GraalError("unexpected invoke %s in snippet", call.targetMethod());
+                    }
+                    // Here we need to fix the bci of the invoke
+                    InvokeNode newInvoke = graph.add(new InvokeNode(invoke.callTarget(), arraycopy.getBci()));
+                    if (arraycopy.stateDuring() != null) {
+                        newInvoke.setStateDuring(arraycopy.stateDuring());
+                    } else {
+                        assert arraycopy.stateAfter() != null;
+                        newInvoke.setStateAfter(arraycopy.stateAfter());
+                    }
+                    graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
+                } else if (originalNode instanceof ArrayCopySlowPathNode) {
+                    ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode);
+                    assert arraycopy.stateAfter() != null;
+                    slowPath.setStateAfter(arraycopy.stateAfter());
+                    slowPath.setBci(arraycopy.getBci());
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java
new file mode 100644
index 0000000..f0729b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(allowedUsageTypes = InputType.Memory)
+public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess {
+
+    public static final NodeClass<ArrayCopyUnrollNode> TYPE = NodeClass.create(ArrayCopyUnrollNode.class);
+
+    @Input protected ValueNode src;
+    @Input protected ValueNode srcPos;
+    @Input protected ValueNode dest;
+    @Input protected ValueNode destPos;
+    @Input protected ValueNode length;
+
+    private JavaKind elementKind;
+
+    private int unrolledLength;
+
+    @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
+
+    public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, JavaKind elementKind) {
+        super(TYPE, StampFactory.forKind(JavaKind.Void));
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.unrolledLength = unrolledLength;
+        assert elementKind != null && elementKind != JavaKind.Illegal;
+        this.elementKind = elementKind;
+    }
+
+    public ValueNode getSource() {
+        return src;
+    }
+
+    public ValueNode getSourcePosition() {
+        return srcPos;
+    }
+
+    public ValueNode getDestination() {
+        return dest;
+    }
+
+    public ValueNode getDestinationPosition() {
+        return destPos;
+    }
+
+    @Override
+    public ValueNode getLength() {
+        return length;
+    }
+
+    @Override
+    public ValueNode getArray() {
+        return dest;
+    }
+
+    @Override
+    public ValueNode getIndex() {
+        return destPos;
+    }
+
+    @Override
+    public boolean isObjectArray() {
+        return elementKind == JavaKind.Object;
+    }
+
+    @Override
+    public boolean isInitialization() {
+        return false;
+    }
+
+    @NodeIntrinsic
+    public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength,
+                    @ConstantNodeParameter JavaKind elementKind);
+
+    public int getUnrollLength() {
+        return unrolledLength;
+    }
+
+    public JavaKind getElementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java
new file mode 100644
index 0000000..4f98f07
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+//JaCoCo Exclude
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<CheckcastArrayCopyCallNode> TYPE = NodeClass.create(CheckcastArrayCopyCallNode.class);
+    @Input ValueNode src;
+    @Input ValueNode srcPos;
+    @Input ValueNode dest;
+    @Input ValueNode destPos;
+    @Input ValueNode length;
+    @Input ValueNode destElemKlass;
+    @Input ValueNode superCheckOffset;
+
+    protected final boolean uninit;
+
+    protected final HotSpotGraalRuntimeProvider runtime;
+
+    protected CheckcastArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length,
+                    ValueNode superCheckOffset, ValueNode destElemKlass, boolean uninit) {
+        super(TYPE, StampFactory.forKind(JavaKind.Int));
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.superCheckOffset = superCheckOffset;
+        this.destElemKlass = destElemKlass;
+        this.uninit = uninit;
+        this.runtime = runtime;
+    }
+
+    public ValueNode getSource() {
+        return src;
+    }
+
+    public ValueNode getSourcePosition() {
+        return srcPos;
+    }
+
+    public ValueNode getDestination() {
+        return dest;
+    }
+
+    public ValueNode getDestinationPosition() {
+        return destPos;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
+    public boolean isUninit() {
+        return uninit;
+    }
+
+    private ValueNode computeBase(ValueNode base, ValueNode pos) {
+        FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base));
+        graph().addBeforeFixed(this, basePtr);
+
+        int shift = CodeUtil.log2(getArrayIndexScale(JavaKind.Object));
+        ValueNode scaledIndex = graph().unique(new LeftShiftNode(pos, ConstantNode.forInt(shift, graph())));
+        ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forInt(getArrayBaseOffset(JavaKind.Object), graph())));
+        return graph().unique(new OffsetAddressNode(basePtr, offset));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
+            ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupCheckcastArraycopyDescriptor(isUninit());
+            StructuredGraph graph = graph();
+            ValueNode srcAddr = computeBase(getSource(), getSourcePosition());
+            ValueNode destAddr = computeBase(getDestination(), getDestinationPosition());
+            ValueNode len = getLength();
+            if (len.stamp().getStackKind() != runtime.getTarget().wordJavaKind) {
+                len = IntegerConvertNode.convert(len, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph());
+            }
+            ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, destElemKlass));
+            call.setStateAfter(stateAfter());
+            graph.replaceFixedWithFixed(this, call);
+        }
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        /*
+         * Because of restrictions that the memory graph of snippets matches the original node,
+         * pretend that we kill any.
+         */
+        return LocationIdentity.any();
+    }
+
+    @NodeIntrinsic
+    public static native int checkcastArraycopy(Object src, int srcPos, Object dest, int destPos, int length, Word superCheckOffset, Object destElemKlass, @ConstantNodeParameter boolean uninit);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java
new file mode 100644
index 0000000..d904f2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_200;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_200, size = SIZE_200)
+public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single, MemoryAccess {
+
+    public static final NodeClass<UnsafeArrayCopyNode> TYPE = NodeClass.create(UnsafeArrayCopyNode.class);
+    @Input ValueNode src;
+    @Input ValueNode srcPos;
+    @Input ValueNode dest;
+    @Input ValueNode destPos;
+    @Input ValueNode length;
+    @OptionalInput ValueNode layoutHelper;
+
+    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
+
+    protected JavaKind elementKind;
+
+    public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, JavaKind elementKind) {
+        super(TYPE, StampFactory.forVoid());
+        assert layoutHelper == null || elementKind == null;
+        this.src = src;
+        this.srcPos = srcPos;
+        this.dest = dest;
+        this.destPos = destPos;
+        this.length = length;
+        this.layoutHelper = layoutHelper;
+        this.elementKind = elementKind;
+    }
+
+    public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
+        this(src, srcPos, dest, destPos, length, null, elementKind);
+    }
+
+    public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) {
+        this(src, srcPos, dest, destPos, length, layoutHelper, null);
+    }
+
+    @Override
+    public ValueNode getArray() {
+        return dest;
+    }
+
+    @Override
+    public ValueNode getIndex() {
+        return destPos;
+    }
+
+    @Override
+    public ValueNode getLength() {
+        return length;
+    }
+
+    @Override
+    public boolean isObjectArray() {
+        return elementKind == JavaKind.Object;
+    }
+
+    @Override
+    public boolean isInitialization() {
+        return false;
+    }
+
+    public JavaKind getElementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
+            UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class);
+            templates.lower(this, tool);
+        }
+    }
+
+    public void addSnippetArguments(Arguments args) {
+        args.add("src", src);
+        args.add("srcPos", srcPos);
+        args.add("dest", dest);
+        args.add("destPos", destPos);
+        args.add("length", length);
+        if (layoutHelper != null) {
+            args.add("layoutHelper", layoutHelper);
+        }
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+
+    @NodeIntrinsic
+    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind);
+
+    @NodeIntrinsic
+    public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java
new file mode 100644
index 0000000..69cb573
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.runtime;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.any;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.extended.UnsafeCopyNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.DirectObjectStoreNode;
+import org.graalvm.compiler.word.ObjectAccess;
+import org.graalvm.compiler.word.Unsigned;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * As opposed to {@link ArrayCopySnippets}, these Snippets do <b>not</b> perform store checks.
+ */
+public class UnsafeArrayCopySnippets implements Snippets {
+
+    private static final boolean supportsUnalignedMemoryAccess = runtime().getHostJVMCIBackend().getTarget().arch.supportsUnalignedMemoryAccess();
+
+    private static final JavaKind VECTOR_KIND = JavaKind.Long;
+    private static final long VECTOR_SIZE = getArrayIndexScale(VECTOR_KIND);
+
+    private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, JavaKind baseKind, LocationIdentity locationIdentity) {
+        int arrayBaseOffset = arrayBaseOffset(baseKind);
+        int elementSize = arrayIndexScale(baseKind);
+        long byteLength = (long) length * elementSize;
+        long srcOffset = (long) srcPos * elementSize;
+        long destOffset = (long) destPos * elementSize;
+
+        long preLoopBytes;
+        long mainLoopBytes;
+        long postLoopBytes;
+
+        // We can easily vectorize the loop if both offsets have the same alignment.
+        if (byteLength >= VECTOR_SIZE && (srcOffset % VECTOR_SIZE) == (destOffset % VECTOR_SIZE)) {
+            preLoopBytes = NumUtil.roundUp(arrayBaseOffset + srcOffset, VECTOR_SIZE) - (arrayBaseOffset + srcOffset);
+            postLoopBytes = (byteLength - preLoopBytes) % VECTOR_SIZE;
+            mainLoopBytes = byteLength - preLoopBytes - postLoopBytes;
+        } else {
+            // Does the architecture support unaligned memory accesses?
+            if (supportsUnalignedMemoryAccess) {
+                preLoopBytes = byteLength % VECTOR_SIZE;
+                mainLoopBytes = byteLength - preLoopBytes;
+                postLoopBytes = 0;
+            } else {
+                // No. Let's do element-wise copying.
+                preLoopBytes = byteLength;
+                mainLoopBytes = 0;
+                postLoopBytes = 0;
+            }
+        }
+
+        if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) {
+            // bad aliased case
+            srcOffset += byteLength;
+            destOffset += byteLength;
+
+            // Post-loop
+            for (long i = 0; i < postLoopBytes; i += elementSize) {
+                srcOffset -= elementSize;
+                destOffset -= elementSize;
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
+            }
+            // Main-loop
+            for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
+                srcOffset -= VECTOR_SIZE;
+                destOffset -= VECTOR_SIZE;
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
+            }
+            // Pre-loop
+            for (long i = 0; i < preLoopBytes; i += elementSize) {
+                srcOffset -= elementSize;
+                destOffset -= elementSize;
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
+            }
+        } else {
+            // Pre-loop
+            for (long i = 0; i < preLoopBytes; i += elementSize) {
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
+                srcOffset += elementSize;
+                destOffset += elementSize;
+            }
+            // Main-loop
+            for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
+                srcOffset += VECTOR_SIZE;
+                destOffset += VECTOR_SIZE;
+            }
+            // Post-loop
+            for (long i = 0; i < postLoopBytes; i += elementSize) {
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
+                srcOffset += elementSize;
+                destOffset += elementSize;
+            }
+        }
+    }
+
+    @Fold
+    static LocationIdentity getArrayLocation(JavaKind kind) {
+        return NamedLocationIdentity.getArrayLocation(kind);
+    }
+
+    @Snippet
+    public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Byte;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Boolean;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Char;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Short;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Int;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Float;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Long;
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    @Snippet
+    public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Double;
+        /*
+         * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values to be
+         * copied atomically, but not long values. For example, on Intel 32-bit this code is not
+         * atomic as long as the vector kind remains Kind.Long.
+         */
+        vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
+    }
+
+    /**
+     * For this kind, Object, we want to avoid write barriers between writes, but instead have them
+     * at the end of the snippet. This is done by using {@link DirectObjectStoreNode}, and rely on
+     * {@link WriteBarrierAdditionPhase} to put write barriers after the {@link UnsafeArrayCopyNode}
+     * with kind Object.
+     */
+    @Snippet
+    public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
+        JavaKind kind = JavaKind.Object;
+        final int scale = arrayIndexScale(kind);
+        int arrayBaseOffset = arrayBaseOffset(kind);
+        LocationIdentity arrayLocation = getArrayLocation(kind);
+        if (src == dest && srcPos < destPos) { // bad aliased case
+            long start = (long) (length - 1) * scale;
+            for (long i = start; i >= 0; i -= scale) {
+                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
+                DirectObjectStoreNode.storeObject(dest, arrayBaseOffset, i + (long) destPos * scale, a, getArrayLocation(kind), kind);
+            }
+        } else {
+            long end = (long) length * scale;
+            for (long i = 0; i < end; i += scale) {
+                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
+                DirectObjectStoreNode.storeObject(dest, arrayBaseOffset, i + (long) destPos * scale, a, getArrayLocation(kind), kind);
+            }
+        }
+    }
+
+    @Snippet
+    public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) {
+        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
+        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
+
+        Unsigned vectorSize = Word.unsigned(VECTOR_SIZE);
+        Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destStart = destOffset;
+        Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
+
+        Unsigned destVectorEnd = null;
+        Unsigned nonVectorBytes = null;
+        Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize);
+        if (supportsUnalignedMemoryAccess) {
+            nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize);
+            destVectorEnd = destEnd;
+        } else {
+            boolean inPhase = srcOffset.and((int) VECTOR_SIZE - 1).equal(destOffset.and((int) VECTOR_SIZE - 1));
+            boolean hasAtLeastOneVector = sizeInBytes.aboveOrEqual(vectorSize);
+            // We must have at least one full vector, otherwise we must copy each byte separately
+            if (hasAtLeastOneVector && inPhase) { // If in phase, we can vectorize
+                nonVectorBytes = vectorSize.subtract(destStart.unsignedRemainder(vectorSize));
+            } else { // fallback is byte-wise
+                nonVectorBytes = sizeInBytes;
+            }
+            destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(vectorSize));
+        }
+
+        Unsigned destNonVectorEnd = destStart.add(nonVectorBytes);
+        while (destOffset.belowThan(destNonVectorEnd)) {
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
+            destOffset = destOffset.add(1);
+            srcOffset = srcOffset.add(1);
+        }
+        // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8));
+        while (destOffset.belowThan(destVectorEnd)) {
+            ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any());
+            destOffset = destOffset.add(wordSize());
+            srcOffset = srcOffset.add(wordSize());
+        }
+        // Do the last bytes each when it is required to have absolute alignment.
+        while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) {
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
+            destOffset = destOffset.add(1);
+            srcOffset = srcOffset.add(1);
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo[] arraycopySnippets;
+        private final SnippetInfo genericPrimitiveSnippet;
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+
+            arraycopySnippets = new SnippetInfo[JavaKind.values().length];
+            arraycopySnippets[JavaKind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean");
+            arraycopySnippets[JavaKind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte");
+            arraycopySnippets[JavaKind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort");
+            arraycopySnippets[JavaKind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar");
+            arraycopySnippets[JavaKind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt");
+            arraycopySnippets[JavaKind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong");
+            arraycopySnippets[JavaKind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat");
+            arraycopySnippets[JavaKind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble");
+            arraycopySnippets[JavaKind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject");
+
+            genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive");
+        }
+
+        public void lower(UnsafeArrayCopyNode node, LoweringTool tool) {
+            JavaKind elementKind = node.getElementKind();
+            SnippetInfo snippet;
+            if (elementKind == null) {
+                // primitive array of unknown kind
+                snippet = genericPrimitiveSnippet;
+            } else {
+                snippet = arraycopySnippets[elementKind.ordinal()];
+                assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found";
+            }
+
+            Arguments args = new Arguments(snippet, node.graph().getGuardsStage(), tool.getLoweringStage());
+            node.addSnippetArguments(args);
+
+            SnippetTemplate template = template(args);
+            template.instantiate(providers.getMetaAccess(), node, DEFAULT_REPLACER, args);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java
new file mode 100644
index 0000000..87ce20a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.profiling;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.word.MethodCountersPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class ProbabilisticProfileSnippets implements Snippets {
+    @Snippet
+    public static boolean shouldProfile(@ConstantParameter int probLog, int random) {
+        int probabilityMask = (1 << probLog) - 1;
+        return (random & probabilityMask) == 0;
+    }
+
+    @Snippet
+    public static int notificationMask(int freqLog, int probLog) {
+        int probabilityMask = (1 << probLog) - 1;
+        int frequencyMask = (1 << freqLog) - 1;
+        return frequencyMask & ~probabilityMask;
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
+
+    @Snippet
+    public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog) {
+        if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
+            int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
+            counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
+            if (freqLog >= 0) {
+                int mask = notificationMask(freqLog, probLog);
+                if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+                    methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
+                }
+            }
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
+
+    @Snippet
+    public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci, int targetBci) {
+        if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
+            int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
+            counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
+            int mask = notificationMask(freqLog, probLog);
+            if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+                methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
+            }
+        }
+    }
+
+    @Snippet
+    public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, boolean branchCondition,
+                    int bci, int targetBci) {
+        if (branchCondition) {
+            profileBackedgeWithProbability(counters, random, freqLog, probLog, bci, targetBci);
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo profileMethodEntryWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileMethodEntryWithProbability");
+        private final SnippetInfo profileBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileBackedgeWithProbability");
+        private final SnippetInfo profileConditionalBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileConditionalBackedgeWithProbability");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(ProfileNode profileNode, LoweringTool tool) {
+            assert profileNode.getRandom() != null;
+
+            StructuredGraph graph = profileNode.graph();
+            LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
+
+            if (profileNode instanceof ProfileBranchNode) {
+                // Backedge event
+                ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode;
+                SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedgeWithProbability : profileBackedgeWithProbability;
+                Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+                ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
+                ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
+                args.add("counters", counters);
+                args.add("random", profileBranchNode.getRandom());
+                args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
+                args.addConst("probLog", profileBranchNode.getProbabilityLog());
+                if (profileBranchNode.hasCondition()) {
+                    args.add("branchCondition", profileBranchNode.branchCondition());
+                }
+                args.add("bci", bci);
+                args.add("targetBci", targetBci);
+
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
+            } else if (profileNode instanceof ProfileInvokeNode) {
+                ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
+                // Method invocation event
+                Arguments args = new Arguments(profileMethodEntryWithProbability, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("counters", counters);
+                args.add("random", profileInvokeNode.getRandom());
+                args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
+                args.addConst("probLog", profileInvokeNode.getProbabilityLog());
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
+            } else {
+                throw new GraalError("Unsupported profile node type: " + profileNode);
+            }
+
+            assert profileNode.hasNoUsages();
+            if (!profileNode.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(profileNode);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java
new file mode 100644
index 0000000..98c5588
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements.profiling;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode;
+import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.word.MethodCountersPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class ProfileSnippets implements Snippets {
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
+
+    @Snippet
+    public static void profileMethodEntry(MethodCountersPointer counters, @ConstantParameter int freqLog) {
+        int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
+        counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
+        if (freqLog >= 0) {
+            final int frequencyMask = (1 << freqLog) - 1;
+            if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+                methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
+            }
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
+
+    @Snippet
+    public static void profileBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, int bci, int targetBci) {
+        int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
+        counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
+        final int frequencyMask = (1 << freqLog) - 1;
+        if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+            methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
+        }
+    }
+
+    @Snippet
+    public static void profileConditionalBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) {
+        if (branchCondition) {
+            profileBackedge(counters, freqLog, bci, targetBci);
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo profileMethodEntry = snippet(ProfileSnippets.class, "profileMethodEntry");
+        private final SnippetInfo profileBackedge = snippet(ProfileSnippets.class, "profileBackedge");
+        private final SnippetInfo profileConditionalBackedge = snippet(ProfileSnippets.class, "profileConditionalBackedge");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(ProfileNode profileNode, LoweringTool tool) {
+            StructuredGraph graph = profileNode.graph();
+            LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
+
+            if (profileNode instanceof ProfileBranchNode) {
+                // Backedge event
+                ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode;
+                SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedge : profileBackedge;
+                Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+                ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
+                ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
+                args.add("counters", counters);
+                args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
+                if (profileBranchNode.hasCondition()) {
+                    args.add("branchCondition", profileBranchNode.branchCondition());
+                }
+                args.add("bci", bci);
+                args.add("targetBci", targetBci);
+
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
+            } else if (profileNode instanceof ProfileInvokeNode) {
+                ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
+                // Method invocation event
+                Arguments args = new Arguments(profileMethodEntry, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("counters", counters);
+                args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
+                SnippetTemplate template = template(args);
+                template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
+            } else {
+                throw new GraalError("Unsupported profile node type: " + profileNode);
+            }
+
+            assert profileNode.hasNoUsages();
+            if (!profileNode.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(profileNode);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ArrayStoreExceptionStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ArrayStoreExceptionStub.java
new file mode 100644
index 0000000..9877dc7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ArrayStoreExceptionStub.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ */
+public class ArrayStoreExceptionStub extends CreateExceptionStub {
+
+    public ArrayStoreExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("createArrayStoreException", providers, linkage);
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        GraalError.guarantee(index == 1, "unknown parameter %s at index %d", name, index);
+        return providers.getRegisters().getThreadRegister();
+    }
+
+    @Snippet
+    private static Object createArrayStoreException(Object object, @ConstantParameter Register threadRegister) {
+        KlassPointer klass = HotSpotReplacementsUtil.loadHub(object);
+        return createException(threadRegister, ArrayStoreException.class, klass);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ClassCastExceptionStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ClassCastExceptionStub.java
new file mode 100644
index 0000000..d9a7aa1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ClassCastExceptionStub.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ */
+public class ClassCastExceptionStub extends CreateExceptionStub {
+
+    public ClassCastExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("createClassCastException", providers, linkage);
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        GraalError.guarantee(index == 2, "unknown parameter %s at index %d", name, index);
+        return providers.getRegisters().getThreadRegister();
+    }
+
+    @Snippet
+    private static Object createClassCastException(Object object, KlassPointer targetKlass, @ConstantParameter Register threadRegister) {
+        KlassPointer objKlass = HotSpotReplacementsUtil.loadHub(object);
+        return createException(threadRegister, ClassCastException.class, objKlass, targetKlass);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java
new file mode 100644
index 0000000..6436013
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
+import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.REEXECUTABLE;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.replacements.nodes.CStringConstant;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Base class for stubs that create a runtime exception.
+ */
+public class CreateExceptionStub extends SnippetStub {
+
+    protected CreateExceptionStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super(snippetMethodName, providers, linkage);
+    }
+
+    @Fold
+    static String getInternalClassName(Class<?> cls) {
+        return cls.getName().replace('.', '/');
+    }
+
+    private static Word classAsCString(Class<?> cls) {
+        return CStringConstant.cstring(getInternalClassName(cls));
+    }
+
+    protected static Object createException(Register threadRegister, Class<? extends Throwable> exception) {
+        Word message = null;
+        return createException(threadRegister, exception, message);
+    }
+
+    protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, Word message) {
+        Word thread = registerAsWord(threadRegister);
+        throwAndPostJvmtiException(THROW_AND_POST_JVMTI_EXCEPTION, thread, classAsCString(exception), message);
+        return clearPendingException(thread);
+    }
+
+    protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer klass) {
+        Word thread = registerAsWord(threadRegister);
+        throwKlassExternalNameException(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, thread, classAsCString(exception), klass);
+        return clearPendingException(thread);
+    }
+
+    protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer objKlass, KlassPointer targetKlass) {
+        Word thread = registerAsWord(threadRegister);
+        throwClassCastException(THROW_CLASS_CAST_EXCEPTION, thread, classAsCString(exception), objKlass, targetKlass);
+        return clearPendingException(thread);
+    }
+
+    private static final ForeignCallDescriptor THROW_AND_POST_JVMTI_EXCEPTION = new ForeignCallDescriptor("throw_and_post_jvmti_exception", void.class, Word.class, Word.class, Word.class);
+    private static final ForeignCallDescriptor THROW_KLASS_EXTERNAL_NAME_EXCEPTION = new ForeignCallDescriptor("throw_klass_external_name_exception", void.class, Word.class, Word.class,
+                    KlassPointer.class);
+    private static final ForeignCallDescriptor THROW_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("throw_class_cast_exception", void.class, Word.class, Word.class, KlassPointer.class,
+                    KlassPointer.class);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void throwAndPostJvmtiException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, Word message);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void throwKlassExternalNameException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer klass);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void throwClassCastException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer objKlass, KlassPointer targetKlass);
+
+    public static void registerForeignCalls(GraalHotSpotVMConfig c, HotSpotForeignCallsProviderImpl foreignCalls) {
+        foreignCalls.registerForeignCall(THROW_AND_POST_JVMTI_EXCEPTION, c.throwAndPostJvmtiExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        foreignCalls.registerForeignCall(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, c.throwKlassExternalNameExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        foreignCalls.registerForeignCall(THROW_CLASS_CAST_EXCEPTION, c.throwClassCastExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/DeoptimizationStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/DeoptimizationStub.java
new file mode 100644
index 0000000..acfb4e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/DeoptimizationStub.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNPACK_FRAMES;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode.fetchUnrollInfo;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeRegisterAsWord;
+import static org.graalvm.compiler.hotspot.stubs.UncommonTrapStub.STACK_BANG_LOCATION;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.EnterUnpackFramesStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveCurrentStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveDeoptimizedStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.LeaveUnpackFramesStackFrameNode;
+import org.graalvm.compiler.hotspot.nodes.PushInterpreterFrameNode;
+import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Deoptimization stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
+ *
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * <li>deallocate the deoptimization frame
+ *
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
+ *
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ *
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
+ */
+public class DeoptimizationStub extends SnippetStub {
+
+    private final TargetDescription target;
+
+    public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(DeoptimizationStub.class, "deoptimizationHandler", providers, linkage);
+        this.target = target;
+        assert PreferGraalStubs.getValue();
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Deoptimization handler for normal deoptimization
+     * {@link GraalHotSpotVMConfig#deoptimizationUnpackDeopt}.
+     */
+    @Snippet
+    private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final Word unrollBlock = fetchUnrollInfo(registerSaver, deoptimizationUnpackDeopt(INJECTED_VMCONFIG));
+
+        deoptimizationCommon(stackPointerRegister, thread, registerSaver, unrollBlock);
+    }
+
+    static void deoptimizationCommon(Register stackPointerRegister, final Word thread, final long registerSaver, final Word unrollBlock) {
+        // Pop all the frames we must move/replace.
+        //
+        // Frame picture (youngest to oldest)
+        // 1: self-frame
+        // 2: deoptimizing frame
+        // 3: caller of deoptimizing frame (could be compiled/interpreted).
+
+        // Pop self-frame.
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
+
+        // Load the initial info we should save (e.g. frame pointer).
+        final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset(INJECTED_VMCONFIG));
+
+        // Pop deoptimized frame.
+        final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(INJECTED_VMCONFIG));
+        LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
+
+        /*
+         * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
+         * total size of the interpreter frames plus shadow page size. Bang one page at a time
+         * because large sizes can bang beyond yellow and red zones.
+         *
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
+         */
+        final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset(INJECTED_VMCONFIG));
+        final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages(INJECTED_VMCONFIG);
+        Word stackPointer = readRegister(stackPointerRegister);
+
+        for (int i = 1; i < bangPages; i++) {
+            stackPointer.writeInt((-i * pageSize()) + stackBias(INJECTED_VMCONFIG), 0, STACK_BANG_LOCATION);
+        }
+
+        // Load number of interpreter frames.
+        final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset(INJECTED_VMCONFIG));
+
+        // Load address of array of frame sizes.
+        final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset(INJECTED_VMCONFIG));
+
+        // Load address of array of frame PCs.
+        final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset(INJECTED_VMCONFIG));
+
+        /*
+         * Get the current stack pointer (sender's original SP) before adjustment so that we can
+         * save it in the skeletal interpreter frame.
+         */
+        Word senderSp = readRegister(stackPointerRegister);
+
+        // Adjust old interpreter frame to make space for new frame's extra Java locals.
+        final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset(INJECTED_VMCONFIG));
+        writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment));
+
+        for (int i = 0; i < numberOfFrames; i++) {
+            final Word frameSize = frameSizes.readWord(i * wordSize());
+            final Word framePc = framePcs.readWord(i * wordSize());
+
+            // Push an interpreter frame onto the stack.
+            PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo);
+
+            // Get the current stack pointer (sender SP) and pass it to next frame.
+            senderSp = readRegister(stackPointerRegister);
+        }
+
+        // Get final return address.
+        final Word framePc = framePcs.readWord(numberOfFrames * wordSize());
+
+        /*
+         * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an
+         * unknown alignment we need to align it here before calling C++ code.
+         */
+        final Word senderFp = initialInfo;
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
+
+        final int mode = unrollBlock.readInt(deoptimizationUnrollBlockUnpackKindOffset(INJECTED_VMCONFIG));
+        unpackFrames(UNPACK_FRAMES, thread, mode);
+
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    static int stackShadowPages(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useStackBanging ? config.stackShadowPages : 0;
+    }
+
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    static int stackBias(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.stackBias;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockNumberOfFramesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockUnpackKindOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockUnpackKindOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockFramePcsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockInitialInfoOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnpackDeopt(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    static int deoptimizationUnpackUncommonTrap(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnpackUncommonTrap;
+    }
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java
new file mode 100644
index 0000000..bd435f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerNode.jumpToExceptionHandler;
+import static org.graalvm.compiler.hotspot.nodes.PatchReturnAddressNode.patchReturnAddress;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readExceptionPc;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionOop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeExceptionPc;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.cAssertionsEnabled;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.decipher;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.fatal;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Stub called by the {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception
+ * handler entry point} in a compiled method. This entry point is used when returning to a method to
+ * handle an exception thrown by a callee. It is not used for routing implicit exceptions.
+ * Therefore, it does not need to save any registers as HotSpot uses a caller save convention.
+ * <p>
+ * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}.
+ */
+public class ExceptionHandlerStub extends SnippetStub {
+
+    public ExceptionHandlerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("exceptionHandler", providers, linkage);
+    }
+
+    /**
+     * This stub is called when returning to a method to handle an exception thrown by a callee. It
+     * is not used for routing implicit exceptions. Therefore, it does not need to save any
+     * registers as HotSpot uses a caller save convention.
+     */
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        assert index == 2;
+        return providers.getRegisters().getThreadRegister();
+    }
+
+    @Snippet
+    private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
+        checkNoExceptionInThread(thread, assertionsEnabled(INJECTED_VMCONFIG));
+        checkExceptionNotNull(assertionsEnabled(INJECTED_VMCONFIG), exception);
+        writeExceptionOop(thread, exception);
+        writeExceptionPc(thread, exceptionPc);
+        if (logging()) {
+            printf("handling exception %p (", Word.objectToTrackedPointer(exception).rawValue());
+            decipher(Word.objectToTrackedPointer(exception).rawValue());
+            printf(") at %p (", exceptionPc.rawValue());
+            decipher(exceptionPc.rawValue());
+            printf(")\n");
+        }
+
+        // patch throwing pc into return address so that deoptimization finds the right debug info
+        patchReturnAddress(exceptionPc);
+
+        Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread);
+
+        if (logging()) {
+            printf("handler for exception %p at %p is at %p (", Word.objectToTrackedPointer(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue());
+            decipher(handlerPc.rawValue());
+            printf(")\n");
+        }
+
+        // patch the return address so that this stub returns to the exception handler
+        jumpToExceptionHandler(handlerPc);
+    }
+
+    static void checkNoExceptionInThread(Word thread, boolean enabled) {
+        if (enabled) {
+            Object currentException = readExceptionOop(thread);
+            if (currentException != null) {
+                fatal("exception object in thread must be null, not %p", Word.objectToTrackedPointer(currentException).rawValue());
+            }
+            if (cAssertionsEnabled(INJECTED_VMCONFIG)) {
+                // This thread-local is only cleared in DEBUG builds of the VM
+                // (see OptoRuntime::generate_exception_blob)
+                Word currentExceptionPc = readExceptionPc(thread);
+                if (currentExceptionPc.notEqual(Word.zero())) {
+                    fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue());
+                }
+            }
+        }
+    }
+
+    static void checkExceptionNotNull(boolean enabled, Object exception) {
+        if (enabled && exception == null) {
+            fatal("exception must not be null");
+        }
+    }
+
+    @Fold
+    static boolean logging() {
+        return StubOptions.TraceExceptionHandlerStub.getValue();
+    }
+
+    /**
+     * Determines if either Java assertions are enabled for {@link ExceptionHandlerStub} or if this
+     * is a HotSpot build where the ASSERT mechanism is enabled.
+     * <p>
+     * This first check relies on the per-class assertion status which is why this method must be in
+     * this class.
+     */
+    @Fold
+    @SuppressWarnings("all")
+    static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled || cAssertionsEnabled(config);
+    }
+
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class);
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java
new file mode 100644
index 0000000..ef51bbd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
+import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee;
+import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.JavaMethodContext;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.replacements.GraphKit;
+import org.graalvm.compiler.replacements.nodes.ReadRegisterNode;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotSignature;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * A {@linkplain #getGraph generated} stub for a {@link Transition non-leaf} foreign call from
+ * compiled code. A stub is required for such calls as the caller may be scheduled for
+ * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow
+ * paths, we don't want to force the register allocator to spill around the call. As such, this stub
+ * saves and restores all allocatable registers. It also
+ * {@linkplain StubUtil#handlePendingException(Word, boolean) handles} any exceptions raised during
+ * the foreign call.
+ */
+public class ForeignCallStub extends Stub {
+
+    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+
+    /**
+     * The target of the call.
+     */
+    private final HotSpotForeignCallLinkage target;
+
+    /**
+     * Specifies if the JavaThread value for the current thread is to be prepended to the arguments
+     * for the call to {@link #target}.
+     */
+    protected final boolean prependThread;
+
+    /**
+     * Creates a stub for a call to code at a given address.
+     *
+     * @param address the address of the code to call
+     * @param descriptor the signature of the call to this stub
+     * @param prependThread true if the JavaThread value for the current thread is to be prepended
+     *            to the arguments for the call to {@code address}
+     * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side
+     *            effects. Deoptimization will not return to a point before a stub call that cannot
+     *            be re-executed.
+     * @param killedLocations the memory locations killed by the stub call
+     */
+    public ForeignCallStub(HotSpotJVMCIRuntimeProvider runtime, HotSpotProviders providers, long address, ForeignCallDescriptor descriptor, boolean prependThread, Transition transition,
+                    boolean reexecutable, LocationIdentity... killedLocations) {
+        super(providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), descriptor, 0L,
+                        PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, killedLocations));
+        this.jvmciRuntime = runtime;
+        this.prependThread = prependThread;
+        Class<?>[] targetParameterTypes = createTargetParameters(descriptor);
+        ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes);
+        target = HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), targetSig, address,
+                        DESTROYS_REGISTERS, NativeCall, NativeCall, transition, reexecutable, killedLocations);
+    }
+
+    /**
+     * Gets the linkage information for the call from this stub.
+     */
+    public HotSpotForeignCallLinkage getTargetLinkage() {
+        return target;
+    }
+
+    private Class<?>[] createTargetParameters(ForeignCallDescriptor descriptor) {
+        Class<?>[] parameters = descriptor.getArgumentTypes();
+        if (prependThread) {
+            Class<?>[] newParameters = new Class<?>[parameters.length + 1];
+            System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
+            newParameters[0] = Word.class;
+            return newParameters;
+        }
+        return parameters;
+    }
+
+    @Override
+    protected ResolvedJavaMethod getInstalledCodeOwner() {
+        return null;
+    }
+
+    private class DebugScopeContext implements JavaMethod, JavaMethodContext {
+        @Override
+        public JavaMethod asJavaMethod() {
+            return this;
+        }
+
+        @Override
+        public Signature getSignature() {
+            ForeignCallDescriptor d = linkage.getDescriptor();
+            MetaAccessProvider metaAccess = providers.getMetaAccess();
+            Class<?>[] arguments = d.getArgumentTypes();
+            ResolvedJavaType[] parameters = new ResolvedJavaType[arguments.length];
+            for (int i = 0; i < arguments.length; i++) {
+                parameters[i] = metaAccess.lookupJavaType(arguments[i]);
+            }
+            return new HotSpotSignature(jvmciRuntime, metaAccess.lookupJavaType(d.getResultType()), parameters);
+        }
+
+        @Override
+        public String getName() {
+            return linkage.getDescriptor().getName();
+        }
+
+        @Override
+        public JavaType getDeclaringClass() {
+            return providers.getMetaAccess().lookupJavaType(ForeignCallStub.class);
+        }
+
+        @Override
+        public String toString() {
+            return format("ForeignCallStub<%n(%p)>");
+        }
+    }
+
+    @Override
+    protected Object debugScopeContext() {
+        return new DebugScopeContext() {
+
+        };
+    }
+
+    /**
+     * Creates a graph for this stub.
+     * <p>
+     * If the stub returns an object, the graph created corresponds to this pseudo code:
+     *
+     * <pre>
+     *     Object foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             getAndClearObjectResult(thread());
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return verifyObject(getAndClearObjectResult(thread()));
+     *     }
+     * </pre>
+     *
+     * If the stub returns a primitive or word, the graph created corresponds to this pseudo code
+     * (using {@code int} as the primitive return type):
+     *
+     * <pre>
+     *     int foreignFunctionStub(args...) {
+     *         int result = foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return result;
+     *     }
+     * </pre>
+     *
+     * If the stub is void, the graph created corresponds to this pseudo code:
+     *
+     * <pre>
+     *     void foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *     }
+     * </pre>
+     *
+     * In each example above, the {@code currentThread} argument is the C++ JavaThread value (i.e.,
+     * %r15 on AMD64) and is only prepended if {@link #prependThread} is true.
+     */
+    @Override
+    protected StructuredGraph getGraph(CompilationIdentifier compilationId) {
+        WordTypes wordTypes = providers.getWordTypes();
+        Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
+        boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn());
+
+        StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO, compilationId);
+        graph.disableUnsafeAccessTracking();
+
+        GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
+        ParameterNode[] params = createParameters(kit, args);
+
+        ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
+        ValueNode result = createTargetCall(kit, params, thread);
+        kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
+        if (isObjectResult) {
+            InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
+            result = kit.createInvoke(StubUtil.class, "verifyObject", object);
+        }
+        kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
+
+        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Initial stub graph");
+        }
+
+        kit.inlineInvokes();
+
+        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Stub graph before compilation");
+        }
+
+        return graph;
+    }
+
+    private ParameterNode[] createParameters(GraphKit kit, Class<?>[] args) {
+        ParameterNode[] params = new ParameterNode[args.length];
+        ResolvedJavaType accessingClass = providers.getMetaAccess().lookupJavaType(getClass());
+        for (int i = 0; i < args.length; i++) {
+            ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(args[i]).resolve(accessingClass);
+            StampPair stamp = StampFactory.forDeclaredType(kit.getGraph().getAssumptions(), type, false);
+            ParameterNode param = kit.unique(new ParameterNode(i, stamp));
+            params[i] = param;
+        }
+        return params;
+    }
+
+    private StubForeignCallNode createTargetCall(GraphKit kit, ParameterNode[] params, ReadRegisterNode thread) {
+        if (prependThread) {
+            ValueNode[] targetArguments = new ValueNode[1 + params.length];
+            targetArguments[0] = thread;
+            System.arraycopy(params, 0, targetArguments, 1, params.length);
+            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), targetArguments));
+        } else {
+            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), params));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java
new file mode 100644
index 0000000..c30dda9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayPrototypeMarkWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassLayoutHelperIntrinsic;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH;
+import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.formatArray;
+import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.refillAllocate;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.handlePendingException;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject;
+import static jdk.vm.ci.hotspot.HotSpotMetaAccessProvider.computeArrayAllocationSize;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+
+/**
+ * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
+ * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
+ * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
+ * runtime to complete the allocation.
+ */
+public class NewArrayStub extends SnippetStub {
+
+    public NewArrayStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("newArray", providers, linkage);
+    }
+
+    @Override
+    protected Object[] makeConstArgs() {
+        HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        assert checkConstArg(3, "intArrayHub");
+        assert checkConstArg(4, "threadRegister");
+        args[3] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[4] = providers.getRegisters().getThreadRegister();
+        return args;
+    }
+
+    @Fold
+    static boolean logging() {
+        return StubOptions.TraceNewArrayStub.getValue();
+    }
+
+    /**
+     * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
+     * -XX:-UseTLAB).
+     *
+     * @param hub the hub of the object to be allocated
+     * @param length the length of the array
+     * @param fillContents Should the array be filled with zeroes?
+     * @param intArrayHub the hub for {@code int[].class}
+     */
+    @Snippet
+    private static Object newArray(KlassPointer hub, int length, boolean fillContents, @ConstantParameter KlassPointer intArrayHub, @ConstantParameter Register threadRegister) {
+        int layoutHelper = loadKlassLayoutHelperIntrinsic(hub);
+        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
+        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
+        int elementKind = (layoutHelper >> layoutHelperElementTypeShift(INJECTED_VMCONFIG)) & layoutHelperElementTypeMask(INJECTED_VMCONFIG);
+        int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize);
+        if (logging()) {
+            printf("newArray: element kind %d\n", elementKind);
+            printf("newArray: array length %d\n", length);
+            printf("newArray: array size %d\n", sizeInBytes);
+            printf("newArray: hub=%p\n", hub.asWord().rawValue());
+        }
+
+        // check that array length is small enough for fast path.
+        Word thread = registerAsWord(threadRegister);
+        boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
+        if (inlineContiguousAllocationSupported && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
+            Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
+            if (memory.notEqual(0)) {
+                if (logging()) {
+                    printf("newArray: allocated new array at %p\n", memory.rawValue());
+                }
+                return verifyObject(
+                                formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord(INJECTED_VMCONFIG)), fillContents, false, false));
+            }
+        }
+        if (logging()) {
+            printf("newArray: calling new_array_c\n");
+        }
+
+        newArrayC(NEW_ARRAY_C, thread, hub, length);
+        handlePendingException(thread, true);
+        return verifyObject(getAndClearObjectResult(thread));
+    }
+
+    public static final ForeignCallDescriptor NEW_ARRAY_C = newDescriptor(NewArrayStub.class, "newArrayC", void.class, Word.class, KlassPointer.class, int.class);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, KlassPointer hub, int length);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java
new file mode 100644
index 0000000..b6a64dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.nodes.DirectCompareAndSwapNode.compareAndSwap;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HEAP_END_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HEAP_TOP_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_FAST_REFILL_WASTE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_NOF_REFILLS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_REFILL_WASTE_LIMIT_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_SIZE_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_SLOW_ALLOCATIONS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_THREAD_ALLOCATED_BYTES_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.initializeTlab;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.isInstanceKlassFullyInitialized;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassLayoutHelperIntrinsic;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.log2WordSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabEnd;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabStart;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabTop;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadAllocatedBytesOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadTlabSizeOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabAlignmentReserveInHeapWords;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabFastRefillWasteOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabIntArrayMarkWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabNumberOfRefillsOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteIncrement;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteLimitOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabSlowAllocationsOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabStats;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useG1GC;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.handlePendingException;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
+ * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
+ * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
+ * runtime for to complete the allocation.
+ */
+public class NewInstanceStub extends SnippetStub {
+
+    public NewInstanceStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("newInstance", providers, linkage);
+    }
+
+    @Override
+    protected Object[] makeConstArgs() {
+        HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        assert checkConstArg(1, "intArrayHub");
+        assert checkConstArg(2, "threadRegister");
+        args[1] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[2] = providers.getRegisters().getThreadRegister();
+        return args;
+    }
+
+    private static Word allocate(Word thread, int size) {
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+        Word newTop = top.add(size);
+        /*
+         * this check might lead to problems if the TLAB is within 16GB of the address space end
+         * (checked in c++ code)
+         */
+        if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+            writeTlabTop(thread, newTop);
+            return top;
+        }
+        return Word.zero();
+    }
+
+    @Fold
+    static boolean logging() {
+        return StubOptions.TraceNewInstanceStub.getValue();
+    }
+
+    /**
+     * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
+     * -XX:-UseTLAB).
+     *
+     * @param hub the hub of the object to be allocated
+     * @param intArrayHub the hub for {@code int[].class}
+     */
+    @Snippet
+    private static Object newInstance(KlassPointer hub, @ConstantParameter KlassPointer intArrayHub, @ConstantParameter Register threadRegister) {
+        /*
+         * The type is known to be an instance so Klass::_layout_helper is the instance size as a
+         * raw number
+         */
+        int sizeInBytes = loadKlassLayoutHelperIntrinsic(hub);
+        Word thread = registerAsWord(threadRegister);
+        boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
+        if (!forceSlowPath() && inlineContiguousAllocationSupported) {
+            if (isInstanceKlassFullyInitialized(hub)) {
+                Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
+                if (memory.notEqual(0)) {
+                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
+                    NewObjectSnippets.formatObjectForStub(hub, sizeInBytes, memory, prototypeMarkWord);
+                    return verifyObject(memory.toObject());
+                }
+            }
+        }
+
+        if (logging()) {
+            printf("newInstance: calling new_instance_c\n");
+        }
+
+        newInstanceC(NEW_INSTANCE_C, thread, hub);
+        handlePendingException(thread, true);
+        return verifyObject(getAndClearObjectResult(thread));
+    }
+
+    /**
+     * Attempts to refill the current thread's TLAB and retries the allocation.
+     *
+     * @param intArrayHub the hub for {@code int[].class}
+     * @param sizeInBytes the size of the allocation
+     * @param log specifies if logging is enabled
+     *
+     * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the
+     *         operation was unsuccessful
+     */
+    static Word refillAllocate(Word thread, KlassPointer intArrayHub, int sizeInBytes, boolean log) {
+        // If G1 is enabled, the "eden" allocation space is not the same always
+        // and therefore we have to go to slowpath to allocate a new TLAB.
+        if (useG1GC(INJECTED_VMCONFIG)) {
+            return Word.zero();
+        }
+        if (!useTLAB(INJECTED_VMCONFIG)) {
+            return edenAllocate(Word.unsigned(sizeInBytes), log);
+        }
+        Word intArrayMarkWord = Word.unsigned(tlabIntArrayMarkWord(INJECTED_VMCONFIG));
+        int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords(INJECTED_VMCONFIG) * wordSize();
+
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+
+        // calculate amount of free space
+        long tlabFreeSpaceInBytes = end.subtract(top).rawValue();
+
+        if (log) {
+            printf("refillTLAB: thread=%p\n", thread.rawValue());
+            printf("refillTLAB: top=%p\n", top.rawValue());
+            printf("refillTLAB: end=%p\n", end.rawValue());
+            printf("refillTLAB: tlabFreeSpaceInBytes=%ld\n", tlabFreeSpaceInBytes);
+        }
+
+        long tlabFreeSpaceInWords = tlabFreeSpaceInBytes >>> log2WordSize();
+
+        // Retain TLAB and allocate object in shared space if
+        // the amount free in the TLAB is too large to discard.
+        Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset(INJECTED_VMCONFIG), TLAB_REFILL_WASTE_LIMIT_LOCATION);
+        if (tlabFreeSpaceInWords <= refillWasteLimit.rawValue()) {
+            if (tlabStats(INJECTED_VMCONFIG)) {
+                // increment number of refills
+                thread.writeInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), thread.readInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION);
+                if (log) {
+                    printf("thread: %p -- number_of_refills %d\n", thread.rawValue(), thread.readInt(tlabNumberOfRefillsOffset(INJECTED_VMCONFIG), TLAB_NOF_REFILLS_LOCATION));
+                }
+                // accumulate wastage
+                int wastage = thread.readInt(tlabFastRefillWasteOffset(INJECTED_VMCONFIG), TLAB_FAST_REFILL_WASTE_LOCATION) + (int) tlabFreeSpaceInWords;
+                if (log) {
+                    printf("thread: %p -- accumulated wastage %d\n", thread.rawValue(), wastage);
+                }
+                thread.writeInt(tlabFastRefillWasteOffset(INJECTED_VMCONFIG), wastage, TLAB_FAST_REFILL_WASTE_LOCATION);
+            }
+
+            // if TLAB is currently allocated (top or end != null) then
+            // fill [top, end + alignment_reserve) with array object
+            if (top.notEqual(0)) {
+                int headerSize = arrayBaseOffset(JavaKind.Int);
+                // just like the HotSpot assembler stubs, assumes that tlabFreeSpaceInInts fits in
+                // an int
+                int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes >>> 2;
+                int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts;
+                NewObjectSnippets.formatArray(intArrayHub, 0, length, headerSize, top, intArrayMarkWord, false, false, false);
+
+                long allocated = thread.readLong(threadAllocatedBytesOffset(INJECTED_VMCONFIG), TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
+                allocated = allocated + top.subtract(readTlabStart(thread)).rawValue();
+                thread.writeLong(threadAllocatedBytesOffset(INJECTED_VMCONFIG), allocated, TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
+            }
+
+            // refill the TLAB with an eden allocation
+            Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset(INJECTED_VMCONFIG), TLAB_SIZE_LOCATION);
+            Word tlabRefillSizeInBytes = tlabRefillSizeInWords.multiply(wordSize());
+            // allocate new TLAB, address returned in top
+            top = edenAllocate(tlabRefillSizeInBytes, log);
+            if (top.notEqual(0)) {
+                end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes));
+                initializeTlab(thread, top, end);
+
+                return NewInstanceStub.allocate(thread, sizeInBytes);
+            } else {
+                return Word.zero();
+            }
+        } else {
+            // Retain TLAB
+            Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement(INJECTED_VMCONFIG));
+            thread.writeWord(tlabRefillWasteLimitOffset(INJECTED_VMCONFIG), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION);
+            if (log) {
+                printf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.rawValue());
+            }
+
+            if (tlabStats(INJECTED_VMCONFIG)) {
+                thread.writeInt(tlabSlowAllocationsOffset(INJECTED_VMCONFIG), thread.readInt(tlabSlowAllocationsOffset(INJECTED_VMCONFIG), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1,
+                                TLAB_SLOW_ALLOCATIONS_LOCATION);
+            }
+
+            return edenAllocate(Word.unsigned(sizeInBytes), log);
+        }
+    }
+
+    /**
+     * Attempts to allocate a chunk of memory from Eden space.
+     *
+     * @param sizeInBytes the size of the chunk to allocate
+     * @param log specifies if logging is enabled
+     * @return the allocated chunk or {@link Word#zero()} if allocation fails
+     */
+    public static Word edenAllocate(Word sizeInBytes, boolean log) {
+        final long heapTopRawAddress = GraalHotSpotVMConfigNode.heapTopAddress();
+        final long heapEndRawAddress = GraalHotSpotVMConfigNode.heapEndAddress();
+
+        Word heapTopAddress = Word.unsigned(heapTopRawAddress);
+        Word heapEndAddress = Word.unsigned(heapEndRawAddress);
+
+        while (true) {
+            Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION);
+            Word newHeapTop = heapTop.add(sizeInBytes);
+            if (newHeapTop.belowOrEqual(heapTop)) {
+                return Word.zero();
+            }
+
+            Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION);
+            if (newHeapTop.aboveThan(heapEnd)) {
+                return Word.zero();
+            }
+
+            if (compareAndSwap(RawAddressNode.address(heapTopAddress), heapTop, newHeapTop, HEAP_TOP_LOCATION).equal(heapTop)) {
+                return heapTop;
+            }
+        }
+    }
+
+    @Fold
+    static boolean forceSlowPath() {
+        return StubOptions.ForceUseOfNewInstanceStub.getValue();
+    }
+
+    public static final ForeignCallDescriptor NEW_INSTANCE_C = newDescriptor(NewInstanceStub.class, "newInstanceC", void.class, Word.class, KlassPointer.class);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, KlassPointer hub);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NullPointerExceptionStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NullPointerExceptionStub.java
new file mode 100644
index 0000000..b5ba143
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NullPointerExceptionStub.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Stub to allocate a {@link NullPointerException} thrown by a bytecode.
+ */
+public class NullPointerExceptionStub extends CreateExceptionStub {
+
+    public NullPointerExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("createNullPointerException", providers, linkage);
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        GraalError.guarantee(index == 0, "unknown parameter %s at index %d", name, index);
+        return providers.getRegisters().getThreadRegister();
+    }
+
+    @Snippet
+    private static Object createNullPointerException(@ConstantParameter Register threadRegister) {
+        return createException(threadRegister, NullPointerException.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java
new file mode 100644
index 0000000..0956800
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.AllocaNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Stub to allocate an {@link ArrayIndexOutOfBoundsException} thrown by a bytecode.
+ */
+public class OutOfBoundsExceptionStub extends CreateExceptionStub {
+
+    public OutOfBoundsExceptionStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("createOutOfBoundsException", providers, linkage);
+    }
+
+    private static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length();
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 1:
+                return providers.getRegisters().getThreadRegister();
+            case 2:
+                int wordSize = providers.getWordTypes().getWordKind().getByteCount();
+                // (MAX_INT_STRING_SIZE + 1) / wordSize, rounded up
+                return MAX_INT_STRING_SIZE / wordSize + 1;
+            default:
+                throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    @Snippet
+    private static Object createOutOfBoundsException(int idx, @ConstantParameter Register threadRegister, @ConstantParameter int bufferSizeInWords) {
+        Word buffer = AllocaNode.alloca(bufferSizeInWords);
+
+        long number = idx;
+        if (number < 0) {
+            number = -number;
+        }
+
+        Word ptr = buffer.add(MAX_INT_STRING_SIZE);
+        ptr.writeByte(0, (byte) 0);
+        do {
+            long digit = number % 10;
+            number /= 10;
+
+            ptr = ptr.subtract(1);
+            ptr.writeByte(0, (byte) ('0' + digit));
+        } while (number > 0);
+
+        if (idx < 0) {
+            ptr = ptr.subtract(1);
+            ptr.writeByte(0, (byte) '-');
+        }
+
+        return createException(threadRegister, ArrayIndexOutOfBoundsException.class, ptr);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java
new file mode 100644
index 0000000..b645d89
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.replacements.ConstantBindingParameterPlugin;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.meta.Local;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Base class for a stub defined by a snippet.
+ */
+public abstract class SnippetStub extends Stub implements Snippets {
+
+    protected final ResolvedJavaMethod method;
+
+    /**
+     * Creates a new snippet stub.
+     *
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in the class of
+     *            this object
+     * @param linkage linkage details for a call to the stub
+     */
+    public SnippetStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        this(null, snippetMethodName, providers, linkage);
+    }
+
+    /**
+     * Creates a new snippet stub.
+     *
+     * @param snippetDeclaringClass this class in which the {@link Snippet} annotated method is
+     *            declared. If {@code null}, this the class of this object is used.
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in
+     *            {@code snippetDeclaringClass}
+     * @param linkage linkage details for a call to the stub
+     */
+    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super(providers, linkage);
+        Method javaMethod = SnippetTemplate.AbstractTemplates.findMethod(snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName, null);
+        this.method = providers.getMetaAccess().lookupJavaMethod(javaMethod);
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled;
+    }
+
+    public static final ThreadLocal<StructuredGraph> SnippetGraphUnderConstruction = assertionsEnabled() ? new ThreadLocal<>() : null;
+
+    @Override
+    @SuppressWarnings("try")
+    protected StructuredGraph getGraph(CompilationIdentifier compilationId) {
+        Plugins defaultPlugins = providers.getGraphBuilderPlugins();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
+
+        Plugins plugins = new Plugins(defaultPlugins);
+        plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), metaAccess, snippetReflection));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+
+        // Stubs cannot have optimistic assumptions since they have
+        // to be valid for the entire run of the VM.
+        final StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, NO_PROFILING_INFO, compilationId);
+        try (Scope outer = Debug.scope("SnippetStub", graph)) {
+            graph.disableUnsafeAccessTracking();
+
+            if (SnippetGraphUnderConstruction != null) {
+                assert SnippetGraphUnderConstruction.get() == null : SnippetGraphUnderConstruction.get().toString() + " " + graph;
+                SnippetGraphUnderConstruction.set(graph);
+            }
+
+            try {
+                IntrinsicContext initialIntrinsicContext = new IntrinsicContext(method, method, providers.getReplacements().getReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
+                GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(),
+                                providers.getConstantReflection(), providers.getConstantFieldProvider(),
+                                config, OptimisticOptimizations.NONE,
+                                initialIntrinsicContext);
+                instance.apply(graph);
+
+            } finally {
+                if (SnippetGraphUnderConstruction != null) {
+                    SnippetGraphUnderConstruction.set(null);
+                }
+            }
+
+            graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            PhaseContext context = new PhaseContext(providers);
+            canonicalizer.apply(graph, context);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        return graph;
+    }
+
+    protected boolean checkConstArg(int index, String expectedName) {
+        assert method.getParameterAnnotation(ConstantParameter.class, index) != null : String.format("parameter %d of %s is expected to be constant", index, method.format("%H.%n(%p)"));
+        LocalVariableTable lvt = method.getLocalVariableTable();
+        if (lvt != null) {
+            Local local = lvt.getLocal(index, 0);
+            assert local != null;
+            String actualName = local.getName();
+            assert actualName.equals(expectedName) : String.format("parameter %d of %s is expected to be named %s, not %s", index, method.format("%H.%n(%p)"), expectedName, actualName);
+        }
+        return true;
+    }
+
+    protected Object[] makeConstArgs() {
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        for (int i = 0; i < args.length; i++) {
+            if (method.getParameterAnnotation(ConstantParameter.class, i) != null) {
+                args[i] = getConstantParameterValue(i, null);
+            }
+        }
+        return args;
+    }
+
+    protected Object getConstantParameterValue(int index, String name) {
+        throw new GraalError("%s must override getConstantParameterValue() to provide a value for parameter %d%s", getClass().getName(), index, name == null ? "" : " (" + name + ")");
+    }
+
+    @Override
+    protected Object debugScopeContext() {
+        return getInstalledCodeOwner();
+    }
+
+    @Override
+    public ResolvedJavaMethod getInstalledCodeOwner() {
+        return method;
+    }
+
+    @Override
+    public String toString() {
+        return "Stub<" + getInstalledCodeOwner().format("%h.%n") + ">";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java
new file mode 100644
index 0000000..5d2eb3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.core.GraalCompiler.emitBackEnd;
+import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubStartNode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.profiling.MoveProfilingPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+//JaCoCo Exclude
+
+/**
+ * Base class for implementing some low level code providing the out-of-line slow path for a snippet
+ * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java
+ * method.
+ */
+public abstract class Stub {
+
+    private static final List<Stub> stubs = new ArrayList<>();
+
+    /**
+     * The linkage information for a call to this stub from compiled code.
+     */
+    protected final HotSpotForeignCallLinkage linkage;
+
+    /**
+     * The code installed for the stub.
+     */
+    protected InstalledCode code;
+
+    /**
+     * Compilation result from which {@link #code} was created.
+     */
+    protected CompilationResult compResult;
+
+    /**
+     * The registers destroyed by this stub (from the caller's perspective).
+     */
+    private Set<Register> destroyedCallerRegisters;
+
+    private HotSpotCompiledCode compiledCode;
+
+    public void initDestroyedCallerRegisters(Set<Register> registers) {
+        assert registers != null;
+        assert destroyedCallerRegisters == null || registers.equals(destroyedCallerRegisters) : "cannot redefine";
+        destroyedCallerRegisters = registers;
+    }
+
+    /**
+     * Gets the registers destroyed by this stub from a caller's perspective. These are the
+     * temporaries of this stub and must thus be caller saved by a callers of this stub.
+     */
+    public Set<Register> getDestroyedCallerRegisters() {
+        assert destroyedCallerRegisters != null : "not yet initialized";
+        return destroyedCallerRegisters;
+    }
+
+    /**
+     * Determines if this stub preserves all registers apart from those it
+     * {@linkplain #getDestroyedCallerRegisters() destroys}.
+     */
+    public boolean preservesRegisters() {
+        return true;
+    }
+
+    protected final HotSpotProviders providers;
+
+    /**
+     * Creates a new stub.
+     *
+     * @param linkage linkage details for a call to the stub
+     */
+    public Stub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        this.linkage = linkage;
+        this.providers = providers;
+        stubs.add(this);
+    }
+
+    /**
+     * Gets an immutable view of all stubs that have been created.
+     */
+    public static Collection<Stub> getStubs() {
+        return Collections.unmodifiableList(stubs);
+    }
+
+    /**
+     * Gets the linkage for a call to this stub from compiled code.
+     */
+    public HotSpotForeignCallLinkage getLinkage() {
+        return linkage;
+    }
+
+    public RegisterConfig getRegisterConfig() {
+        return null;
+    }
+
+    /**
+     * Gets the graph that from which the code for this stub will be compiled.
+     *
+     * @param compilationId unique compilation id for the stub
+     */
+    protected abstract StructuredGraph getGraph(CompilationIdentifier compilationId);
+
+    @Override
+    public String toString() {
+        return "Stub<" + linkage.getDescriptor() + ">";
+    }
+
+    /**
+     * Gets the method the stub's code will be associated with once installed. This may be null.
+     */
+    protected abstract ResolvedJavaMethod getInstalledCodeOwner();
+
+    /**
+     * Gets a context object for the debug scope created when producing the code for this stub.
+     */
+    protected abstract Object debugScopeContext();
+
+    /**
+     * Gets the code for this stub, compiling it first if necessary.
+     */
+    @SuppressWarnings("try")
+    public synchronized InstalledCode getCode(final Backend backend) {
+        if (code == null) {
+            try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
+                final StructuredGraph graph = getGraph(getStubCompilationId());
+
+                // Stubs cannot be recompiled so they cannot be compiled with assumptions
+                assert graph.getAssumptions() == null;
+
+                if (!(graph.start() instanceof StubStartNode)) {
+                    StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
+                    newStart.setStateAfter(graph.start().stateAfter());
+                    graph.replaceFixed(graph.start(), newStart);
+                }
+
+                CodeCacheProvider codeCache = providers.getCodeCache();
+
+                compResult = new CompilationResult(toString(), GeneratePIC.getValue());
+                try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
+                    Suites suites = createSuites();
+                    emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites);
+                    LIRSuites lirSuites = createLIRSuites();
+                    emitBackEnd(graph, Stub.this, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites);
+                    assert checkStubInvariants();
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+
+                assert destroyedCallerRegisters != null;
+                try (Scope s = Debug.scope("CodeInstall", compResult)) {
+                    // Add a GeneratePIC check here later, we don't want to install
+                    // code if we don't have a corresponding VM global symbol.
+                    compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult);
+                    code = codeCache.installCode(null, compiledCode, null, null, false);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            assert code != null : "error installing stub " + this;
+        }
+
+        return code;
+    }
+
+    public CompilationIdentifier getStubCompilationId() {
+        return new StubCompilationIdentifier(this);
+    }
+
+    /**
+     * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub.
+     */
+    private boolean checkStubInvariants() {
+        assert compResult.getExceptionHandlers().isEmpty() : this;
+
+        // Stubs cannot be recompiled so they cannot be compiled with
+        // assumptions and there is no point in recording evol_method dependencies
+        assert compResult.getAssumptions() == null : "stubs should not use assumptions: " + this;
+
+        for (DataPatch data : compResult.getDataPatches()) {
+            if (data.reference instanceof ConstantReference) {
+                ConstantReference ref = (ConstantReference) data.reference;
+                if (ref.getConstant() instanceof HotSpotMetaspaceConstant) {
+                    HotSpotMetaspaceConstant c = (HotSpotMetaspaceConstant) ref.getConstant();
+                    if (c.asResolvedJavaType() != null && c.asResolvedJavaType().getName().equals("[I")) {
+                        // special handling for NewArrayStub
+                        // embedding the type '[I' is safe, since it is never unloaded
+                        continue;
+                    }
+                }
+            }
+
+            assert !(data.reference instanceof ConstantReference) : this + " cannot have embedded object or metadata constant: " + data.reference;
+        }
+        for (Infopoint infopoint : compResult.getInfopoints()) {
+            assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint;
+            Call call = (Call) infopoint;
+            assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target;
+            HotSpotForeignCallLinkage callLinkage = (HotSpotForeignCallLinkage) call.target;
+            assert !callLinkage.isCompiledStub() || callLinkage.getDescriptor().equals(UNCOMMON_TRAP_HANDLER) : this + " cannot call compiled stub " + callLinkage;
+        }
+        return true;
+    }
+
+    protected Suites createSuites() {
+        Suites defaultSuites = providers.getSuites().getDefaultSuites();
+        return new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier());
+    }
+
+    protected LIRSuites createLIRSuites() {
+        LIRSuites lirSuites = new LIRSuites(providers.getSuites().getDefaultLIRSuites());
+        ListIterator<LIRPhase<PostAllocationOptimizationContext>> moveProfiling = lirSuites.getPostAllocationOptimizationStage().findPhase(MoveProfilingPhase.class);
+        if (moveProfiling != null) {
+            moveProfiling.remove();
+        }
+        return lirSuites;
+    }
+
+    /**
+     * Gets the HotSpotCompiledCode that was created during installation.
+     */
+    public synchronized HotSpotCompiledCode getCompiledCode(final Backend backend) {
+        getCompilationResult(backend);
+        assert compiledCode != null;
+        return compiledCode;
+    }
+
+    /**
+     * Gets the compilation result for this stub, compiling it first if necessary, and installing it
+     * in code.
+     */
+    public synchronized CompilationResult getCompilationResult(final Backend backend) {
+        if (code == null) {
+            getCode(backend);
+        }
+        return compResult;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubCompilationIdentifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubCompilationIdentifier.java
new file mode 100644
index 0000000..514282e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubCompilationIdentifier.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.debug.GraalError;
+
+/**
+ * {@link CompilationIdentifier} for {@linkplain Stub stub compilations}.
+ */
+public class StubCompilationIdentifier implements CompilationIdentifier {
+
+    private static final AtomicLong uniqueStubIds = new AtomicLong();
+    private final long id;
+    private final Stub stub;
+
+    public StubCompilationIdentifier(Stub stub) {
+        this.id = uniqueStubIds.getAndIncrement();
+        this.stub = stub;
+    }
+
+    @Override
+    public final String toString() {
+        return toString(Verbosity.DETAILED);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        switch (verbosity) {
+            case ID:
+                return buildID();
+            case NAME:
+                return buildName();
+            case DETAILED:
+                return buildID() + '[' + buildName() + ']';
+        }
+        throw new GraalError("unknown verbosity: " + verbosity);
+    }
+
+    private String buildName() {
+        return stub.toString();
+    }
+
+    private String buildID() {
+        return "StubCompilation-" + id;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubOptions.java
new file mode 100644
index 0000000..87425f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubOptions.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+//JaCoCo Exclude
+
+/**
+ * Options related to HotSpot Graal-generated stubs.
+ *
+ * Note: This must be a top level class to work around for
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=477597">Eclipse bug 477597</a>.
+ */
+public class StubOptions {
+    // @formatter:off
+    @Option(help = "Trace execution of stub used to handle an exception thrown by a callee.", type = OptionType.Debug)
+    static final OptionValue<Boolean> TraceExceptionHandlerStub = new OptionValue<>(false);
+
+    @Option(help = "Trace execution of the stub that routes an exception to a handler in the calling frame.", type = OptionType.Debug)
+    static final OptionValue<Boolean> TraceUnwindStub = new OptionValue<>(false);
+
+    @Option(help = "Trace execution of slow path stub for array allocation.", type = OptionType.Debug)
+    static final OptionValue<Boolean> TraceNewArrayStub = new OptionValue<>(false);
+
+    @Option(help = "Trace execution of slow path stub for non-array object allocation.", type = OptionType.Debug)
+    static final OptionValue<Boolean> TraceNewInstanceStub = new OptionValue<>(false);
+
+    @Option(help = "Force non-array object allocation to always use the slow path.", type = OptionType.Debug)
+    static final OptionValue<Boolean> ForceUseOfNewInstanceStub = new OptionValue<>(false);
+    //@formatter:on
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java
new file mode 100644
index 0000000..169a03e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops;
+import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
+import static org.graalvm.compiler.word.Word.unsigned;
+import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.nodes.DeoptimizeCallerNode;
+import org.graalvm.compiler.hotspot.nodes.SnippetAnchorNode;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
+import org.graalvm.compiler.hotspot.word.KlassPointer;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+
+//JaCoCo Exclude
+
+/**
+ * A collection of methods used in {@link Stub}s.
+ */
+public class StubUtil {
+
+    public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) {
+        ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes);
+        assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d;
+        return d;
+    }
+
+    /**
+     * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in
+     * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the
+     * value of {@code hasSideEffect}.
+     */
+    private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
+        Method found = null;
+        for (Method method : stubClass.getDeclaredMethods()) {
+            if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) {
+                if (method.getAnnotation(NodeIntrinsic.class).value().equals(StubForeignCallNode.class)) {
+                    assert found == null : "found more than one foreign call named " + name + " in " + stubClass;
+                    assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass +
+                                    " must be of type " + ForeignCallDescriptor.class.getSimpleName();
+                    found = method;
+                }
+            }
+        }
+        assert found != null : "could not find foreign call named " + name + " in " + stubClass;
+        List<Class<?>> paramList = Arrays.asList(found.getParameterTypes());
+        Class<?>[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class<?>[paramList.size() - 1]);
+        return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes);
+    }
+
+    public static void handlePendingException(Word thread, boolean isObjectResult) {
+        if (clearPendingException(thread) != null) {
+            if (isObjectResult) {
+                getAndClearObjectResult(thread);
+            }
+            DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint);
+        }
+    }
+
+    /**
+     * Determines if this is a HotSpot build where the ASSERT mechanism is enabled.
+     */
+    @Fold
+    public static boolean cAssertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.cAssertions;
+    }
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     *
+     * @param message a message string
+     */
+    public static void printf(String message) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param value the value associated with the first conversion specifier in {@code format}
+     */
+    public static void printf(String format, long value) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     */
+    public static void printf(String format, long v1, long v2) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @param v3 the value associated with the third conversion specifier in {@code format}
+     */
+    public static void printf(String format, long v1, long v2, long v3) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3);
+    }
+
+    /**
+     * Analyzes a given value and prints information about it to the log stream.
+     */
+    public static void decipher(long value) {
+        vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     *
+     * @param message an error message
+     */
+    public static void fatal(String message) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param value the value associated with the first conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long value) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long v1, long v2) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     *
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @param v3 the value associated with the third conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long v1, long v2, long v3) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3);
+    }
+
+    /**
+     * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled.
+     */
+    public static Object verifyObject(Object object) {
+        if (verifyOops(INJECTED_VMCONFIG)) {
+            Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress(INJECTED_VMCONFIG));
+            verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1);
+
+            Pointer oop = Word.objectToTrackedPointer(object);
+            if (object != null) {
+                GuardingNode anchorNode = SnippetAnchorNode.anchor();
+                // make sure object is 'reasonable'
+                if (!oop.and(unsigned(verifyOopMask(INJECTED_VMCONFIG))).equal(unsigned(verifyOopBits(INJECTED_VMCONFIG)))) {
+                    fatal("oop not in heap: %p", oop.rawValue());
+                }
+
+                KlassPointer klass = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
+                if (klass.isNull()) {
+                    fatal("klass for oop %p is null", oop.rawValue());
+                }
+            }
+        }
+        return object;
+    }
+
+    @Fold
+    static long verifyOopCounterAddress(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.verifyOopCounterAddress;
+    }
+
+    @Fold
+    static long verifyOopMask(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.verifyOopMask;
+    }
+
+    @Fold
+    static long verifyOopBits(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.verifyOopBits;
+    }
+
+    @Fold
+    static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.hubOffset;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UncommonTrapStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UncommonTrapStub.java
new file mode 100644
index 0000000..2c981ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UncommonTrapStub.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readPendingDeoptimization;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writePendingDeoptimization;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeRegisterAsWord;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Uncommon trap stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
+ *
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * <li>deallocate the deoptimization frame
+ *
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
+ *
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ *
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
+ */
+public class UncommonTrapStub extends SnippetStub {
+
+    public static final LocationIdentity STACK_BANG_LOCATION = NamedLocationIdentity.mutable("stack bang");
+
+    private final TargetDescription target;
+
+    public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(UncommonTrapStub.class, "uncommonTrapHandler", providers, linkage);
+        this.target = target;
+        assert PreferGraalStubs.getValue();
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Uncommon trap handler.
+     *
+     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
+     * routine captures the return values and returns a structure which describes the current frame
+     * size and the sizes of all replacement frames. The current frame is compiled code and may
+     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
+     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
+     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
+     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
+     * was patched.
+     */
+    @Snippet
+    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final int actionAndReason = readPendingDeoptimization(thread);
+        writePendingDeoptimization(thread, -1);
+
+        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason, deoptimizationUnpackUncommonTrap(INJECTED_VMCONFIG));
+
+        DeoptimizationStub.deoptimizationCommon(stackPointerRegister, thread, registerSaver, unrollBlock);
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    static int stackShadowPages(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.useStackBanging ? config.stackShadowPages : 0;
+    }
+
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    static int stackBias(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.stackBias;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockNumberOfFramesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockFramePcsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnrollBlockInitialInfoOffset(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    static int deoptimizationUnpackDeopt(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    static int deoptimizationUnpackUncommonTrap(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config.deoptimizationUnpackUncommonTrap;
+    }
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java
new file mode 100644
index 0000000..5c8e086
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerInCallerNode.jumpToExceptionHandlerInCaller;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkExceptionNotNull;
+import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkNoExceptionInThread;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.cAssertionsEnabled;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.decipher;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an
+ * exception and completes by jumping to the exception handler in the calling frame.
+ */
+public class UnwindExceptionToCallerStub extends SnippetStub {
+
+    public UnwindExceptionToCallerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("unwindExceptionToCaller", providers, linkage);
+    }
+
+    /**
+     * The current frame is unwound by this stub. Therefore, it does not need to save any registers
+     * as HotSpot uses a caller save convention.
+     */
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        assert index == 2;
+        return providers.getRegisters().getThreadRegister();
+    }
+
+    @Snippet
+    private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) {
+        Pointer exceptionOop = Word.objectToTrackedPointer(exception);
+        if (logging()) {
+            printf("unwinding exception %p (", exceptionOop.rawValue());
+            decipher(exceptionOop.rawValue());
+            printf(") at %p (", returnAddress.rawValue());
+            decipher(returnAddress.rawValue());
+            printf(")\n");
+        }
+        Word thread = registerAsWord(threadRegister);
+        checkNoExceptionInThread(thread, assertionsEnabled(null));
+        checkExceptionNotNull(assertionsEnabled(null), exception);
+
+        Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress);
+
+        if (logging()) {
+            printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue());
+            decipher(handlerInCallerPc.rawValue());
+            printf(")\n");
+        }
+
+        jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress);
+    }
+
+    @Fold
+    static boolean logging() {
+        return StubOptions.TraceUnwindStub.getValue();
+    }
+
+    /**
+     * Determines if either Java assertions are enabled for {@link UnwindExceptionToCallerStub} or
+     * if this is a HotSpot build where the ASSERT mechanism is enabled.
+     * <p>
+     * This first check relies on the per-class assertion status which is why this method must be in
+     * this class.
+     */
+    @Fold
+    @SuppressWarnings("all")
+    static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled || cAssertionsEnabled(config);
+    }
+
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
+                    Word.class);
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/VerifyOopStub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/VerifyOopStub.java
new file mode 100644
index 0000000..ea11ef5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/VerifyOopStub.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.stubs;
+
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+
+/**
+ * Stub called via {@link HotSpotHostForeignCallsProvider#VERIFY_OOP}.
+ */
+public class VerifyOopStub extends SnippetStub {
+
+    public VerifyOopStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("verifyOop", providers, linkage);
+    }
+
+    @Snippet
+    private static Object verifyOop(Object object) {
+        return verifyObject(object);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotOperation.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotOperation.java
new file mode 100644
index 0000000..a627d51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotOperation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface HotSpotOperation {
+
+    enum HotspotOpcode {
+        FROM_POINTER,
+        TO_KLASS_POINTER,
+        TO_METHOD_POINTER,
+        POINTER_EQ,
+        POINTER_NE,
+        IS_NULL,
+        READ_KLASS_POINTER
+    }
+
+    HotspotOpcode opcode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotWordTypes.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotWordTypes.java
new file mode 100644
index 0000000..8a5deee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/HotSpotWordTypes.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
+import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Extends {@link WordTypes} with information about HotSpot metaspace pointer types.
+ */
+public class HotSpotWordTypes extends WordTypes {
+
+    /**
+     * Resolved type for {@link MetaspacePointer}.
+     */
+    private final ResolvedJavaType metaspacePointerType;
+
+    /**
+     * Resolved type for {@link KlassPointer}.
+     */
+    private final ResolvedJavaType klassPointerType;
+
+    /**
+     * Resolved type for {@link MethodPointer}.
+     */
+    private final ResolvedJavaType methodPointerType;
+
+    /**
+     * Resolved type for {@link MethodCountersPointer}.
+     */
+    private final ResolvedJavaType methodCountersPointerType;
+
+    public HotSpotWordTypes(MetaAccessProvider metaAccess, JavaKind wordKind) {
+        super(metaAccess, wordKind);
+        this.metaspacePointerType = metaAccess.lookupJavaType(MetaspacePointer.class);
+        this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class);
+        this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class);
+        this.methodCountersPointerType = metaAccess.lookupJavaType(MethodCountersPointer.class);
+    }
+
+    @Override
+    public boolean isWord(JavaType type) {
+        if (type instanceof ResolvedJavaType && metaspacePointerType.isAssignableFrom((ResolvedJavaType) type)) {
+            return true;
+        }
+        return super.isWord(type);
+    }
+
+    @Override
+    public JavaKind asKind(JavaType type) {
+        if (klassPointerType.equals(type) || methodPointerType.equals(type)) {
+            return getWordKind();
+        }
+        return super.asKind(type);
+    }
+
+    @Override
+    public Stamp getWordStamp(ResolvedJavaType type) {
+        if (type.equals(klassPointerType)) {
+            return KlassPointerStamp.klass();
+        } else if (type.equals(methodPointerType)) {
+            return MethodPointerStamp.method();
+        } else if (type.equals(methodCountersPointerType)) {
+            return MethodCountersPointerStamp.methodCounters();
+        }
+        return super.getWordStamp(type);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java
new file mode 100644
index 0000000..0cad4f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.READ_KLASS_POINTER;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_KLASS_POINTER;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+
+/**
+ * Marker type for a metaspace pointer to a type.
+ */
+public abstract class KlassPointer extends MetaspacePointer {
+
+    @HotSpotOperation(opcode = POINTER_EQ)
+    public abstract boolean equal(KlassPointer other);
+
+    @HotSpotOperation(opcode = POINTER_NE)
+    public abstract boolean notEqual(KlassPointer other);
+
+    @HotSpotOperation(opcode = TO_KLASS_POINTER)
+    public static native KlassPointer fromWord(Pointer pointer);
+
+    @HotSpotOperation(opcode = READ_KLASS_POINTER)
+    public native KlassPointer readKlassPointer(int offset, LocationIdentity locationIdentity);
+
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public native void writeKlassPointer(int offset, KlassPointer t, LocationIdentity locationIdentity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java
new file mode 100644
index 0000000..434471c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_POINTER;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.IS_NULL;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Signed;
+import org.graalvm.compiler.word.Unsigned;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+import org.graalvm.compiler.word.WordBase;
+
+/**
+ * Marker type for a metaspace pointer.
+ */
+public abstract class MetaspacePointer {
+
+    @HotSpotOperation(opcode = IS_NULL)
+    public abstract boolean isNull();
+
+    @HotSpotOperation(opcode = FROM_POINTER)
+    public abstract Pointer asWord();
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract byte readByte(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract char readChar(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract short readShort(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract int readInt(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract long readLong(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract float readFloat(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract double readDouble(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Word readWord(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract byte readByte(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract char readChar(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract short readShort(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract int readInt(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract long readLong(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract float readFloat(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract double readDouble(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Word readWord(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.INITIALIZE)
+    public abstract void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeByte(int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeChar(int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeShort(int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeInt(int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeFloat(int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeDouble(int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.INITIALIZE)
+    public abstract void initializeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeObject(int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract byte readByte(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract char readChar(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract short readShort(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract int readInt(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract long readLong(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract float readFloat(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract double readDouble(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Word readWord(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
+     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
+     * field).
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param barrierType the type of the read barrier to be added
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(WordBase offset, BarrierType barrierType);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract byte readByte(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract char readChar(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract short readShort(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract int readInt(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract long readLong(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract float readFloat(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract double readDouble(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Word readWord(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
+     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
+     * field).
+     *
+     * @param offset the signed offset for the memory access
+     * @param barrierType the type of the read barrier to be added
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_POINTER)
+    public abstract Object readObject(int offset, BarrierType barrierType);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeByte(WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeChar(WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeShort(WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeInt(WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeLong(WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeFloat(WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeDouble(WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeWord(WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeObject(WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeByte(int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeChar(int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeShort(int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeInt(int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeLong(int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeFloat(int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeDouble(int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeWord(int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public abstract void writeObject(int offset, Object val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodCountersPointer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodCountersPointer.java
new file mode 100644
index 0000000..f1bf1e7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodCountersPointer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
+
+/**
+ * Marker type for a metaspace pointer to a method counters.
+ */
+public abstract class MethodCountersPointer extends MetaspacePointer {
+
+    @HotSpotOperation(opcode = POINTER_EQ)
+    public abstract boolean equal(MethodCountersPointer other);
+
+    @HotSpotOperation(opcode = POINTER_NE)
+    public abstract boolean notEqual(MethodCountersPointer other);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java
new file mode 100644
index 0000000..f00d0da
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
+import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_METHOD_POINTER;
+
+import org.graalvm.compiler.word.Pointer;
+
+/**
+ * Marker type for a metaspace pointer to a method.
+ */
+public abstract class MethodPointer extends MetaspacePointer {
+
+    @HotSpotOperation(opcode = POINTER_EQ)
+    public abstract boolean equal(KlassPointer other);
+
+    @HotSpotOperation(opcode = POINTER_NE)
+    public abstract boolean notEqual(KlassPointer other);
+
+    @HotSpotOperation(opcode = TO_METHOD_POINTER)
+    public static native MethodPointer fromWord(Pointer pointer);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/PointerCastNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/PointerCastNode.java
new file mode 100644
index 0000000..866ba59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/PointerCastNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.word;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Cast between Word and metaspace pointers exposed by the {@link HotspotOpcode#FROM_POINTER} and
+ * {@link HotspotOpcode#TO_KLASS_POINTER} operations.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class PointerCastNode extends FloatingNode implements LIRLowerable, Node.ValueNumberable {
+
+    public static final NodeClass<PointerCastNode> TYPE = NodeClass.create(PointerCastNode.class);
+    @Input ValueNode input;
+
+    public PointerCastNode(Stamp stamp, ValueNode input) {
+        super(TYPE, stamp);
+        this.input = input;
+    }
+
+    public ValueNode getInput() {
+        return input;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        Value value = generator.operand(input);
+        assert value.getValueKind().equals(generator.getLIRGeneratorTool().getLIRKind(stamp())) : "PointerCastNode shouldn't change the LIRKind";
+
+        generator.setResult(this, value);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java
new file mode 100644
index 0000000..725e649
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java
@@ -0,0 +1,1076 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH;
+import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW;
+import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.RET;
+import static org.graalvm.compiler.bytecode.Bytecodes.RETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
+import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
+import org.graalvm.compiler.bytecode.BytecodeStream;
+import org.graalvm.compiler.bytecode.BytecodeSwitch;
+import org.graalvm.compiler.bytecode.BytecodeTableSwitch;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.debug.Debug;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.ExceptionHandler;
+
+/**
+ * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph
+ * (CFG). It makes one linear passes over the bytecodes to build the CFG where it detects block
+ * headers and connects them.
+ * <p>
+ * It also creates exception dispatch blocks for exception handling. These blocks are between a
+ * bytecode that might throw an exception, and the actual exception handler entries, and are later
+ * used to create the type checks with the exception handler catch types. If a bytecode is covered
+ * by an exception handler, this bytecode ends the basic block. This guarantees that a) control flow
+ * cannot be transferred to an exception dispatch block in the middle of a block, and b) that every
+ * block has at most one exception dispatch block (which is always the last entry in the successor
+ * list).
+ * <p>
+ * If a bytecode is covered by multiple exception handlers, a chain of exception dispatch blocks is
+ * created so that multiple exception handler types can be checked. The chains are re-used if
+ * multiple bytecodes are covered by the same exception handlers.
+ * <p>
+ * Note that exception unwinds, i.e., bytecodes that can throw an exception but the exception is not
+ * handled in this method, do not end a basic block. Not modeling the exception unwind block reduces
+ * the complexity of the CFG, and there is no algorithm yet where the exception unwind block would
+ * matter.
+ * <p>
+ * The class also handles subroutines (jsr and ret bytecodes): subroutines are inlined by
+ * duplicating the subroutine blocks. This is limited to simple, structured subroutines with a
+ * maximum subroutine nesting of 4. Otherwise, a bailout is thrown.
+ * <p>
+ * Loops in the methods are detected. If a method contains an irreducible loop (a loop with more
+ * than one entry), a bailout is thrown. This simplifies the compiler later on since only structured
+ * loops need to be supported.
+ * <p>
+ * A data flow analysis computes the live local variables from the point of view of the interpreter.
+ * The result is used later to prune frame states, i.e., remove local variable entries that are
+ * guaranteed to be never used again (even in the case of deoptimization).
+ * <p>
+ * The algorithms and analysis in this class are conservative and do not use any assumptions or
+ * profiling information.
+ */
+public final class BciBlockMapping {
+
+    public static class BciBlock implements Cloneable {
+
+        protected int id;
+        public int startBci;
+        public int endBci;
+        public boolean isExceptionEntry;
+        public boolean isLoopHeader;
+        public int loopId;
+        public int loopEnd;
+        protected List<BciBlock> successors;
+        private int predecessorCount;
+
+        private boolean visited;
+        private boolean active;
+        public long loops;
+        public JSRData jsrData;
+
+        public static class JSRData implements Cloneable {
+            public HashMap<JsrScope, BciBlock> jsrAlternatives;
+            public JsrScope jsrScope = JsrScope.EMPTY_SCOPE;
+            public BciBlock jsrSuccessor;
+            public int jsrReturnBci;
+            public BciBlock retSuccessor;
+            public boolean endsWithRet = false;
+
+            public JSRData copy() {
+                try {
+                    return (JSRData) this.clone();
+                } catch (CloneNotSupportedException e) {
+                    return null;
+                }
+            }
+        }
+
+        public BciBlock() {
+            this.successors = new ArrayList<>(4);
+        }
+
+        public BciBlock exceptionDispatchBlock() {
+            if (successors.size() > 0 && successors.get(successors.size() - 1) instanceof ExceptionDispatchBlock) {
+                return successors.get(successors.size() - 1);
+            }
+            return null;
+        }
+
+        public int getId() {
+            return id;
+        }
+
+        public int getPredecessorCount() {
+            return this.predecessorCount;
+        }
+
+        public int numNormalSuccessors() {
+            if (exceptionDispatchBlock() != null) {
+                return successors.size() - 1;
+            }
+            return successors.size();
+        }
+
+        public BciBlock copy() {
+            try {
+                BciBlock block = (BciBlock) super.clone();
+                if (block.jsrData != null) {
+                    block.jsrData = block.jsrData.copy();
+                }
+                block.successors = new ArrayList<>(successors);
+                return block;
+            } catch (CloneNotSupportedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("B").append(getId());
+            sb.append('[').append(startBci).append("->").append(endBci);
+            if (isLoopHeader || isExceptionEntry) {
+                sb.append(' ');
+                if (isLoopHeader) {
+                    sb.append('L');
+                }
+                if (isExceptionEntry) {
+                    sb.append('!');
+                }
+            }
+            sb.append(']');
+            return sb.toString();
+        }
+
+        public int getLoopDepth() {
+            return Long.bitCount(loops);
+        }
+
+        public boolean isLoopHeader() {
+            return isLoopHeader;
+        }
+
+        public boolean isExceptionEntry() {
+            return isExceptionEntry;
+        }
+
+        public BciBlock getSuccessor(int index) {
+            return successors.get(index);
+        }
+
+        /**
+         * Get the loop id of the inner most loop.
+         *
+         * @return the loop id of the most inner loop or -1 if not part of any loop
+         */
+        public int getLoopId() {
+            long l = loops;
+            if (l == 0) {
+                return -1;
+            }
+            int pos = 0;
+            for (int lMask = 1; (l & lMask) == 0; lMask = lMask << 1) {
+                pos++;
+            }
+            return pos;
+        }
+
+        /**
+         * Iterate over loop ids.
+         */
+        public Iterable<Integer> loopIdIterable() {
+            return new Iterable<Integer>() {
+                @Override
+                public Iterator<Integer> iterator() {
+                    return idIterator(loops);
+                }
+            };
+        }
+
+        private static Iterator<Integer> idIterator(long field) {
+            return new Iterator<Integer>() {
+
+                long l = field;
+                int pos = 0;
+                int lMask = 1;
+
+                @Override
+                public Integer next() {
+                    for (; (l & lMask) == 0; lMask = lMask << 1) {
+                        pos++;
+                    }
+                    l &= ~lMask;
+                    return pos;
+                }
+
+                @Override
+                public boolean hasNext() {
+                    return l != 0;
+                }
+            };
+
+        }
+
+        public double probability() {
+            return 1D;
+        }
+
+        public BciBlock getPostdominator() {
+            return null;
+        }
+
+        private JSRData getOrCreateJSRData() {
+            if (jsrData == null) {
+                jsrData = new JSRData();
+            }
+            return jsrData;
+        }
+
+        void setEndsWithRet() {
+            getOrCreateJSRData().endsWithRet = true;
+        }
+
+        public JsrScope getJsrScope() {
+            if (this.jsrData == null) {
+                return JsrScope.EMPTY_SCOPE;
+            } else {
+                return jsrData.jsrScope;
+            }
+        }
+
+        public boolean endsWithRet() {
+            if (this.jsrData == null) {
+                return false;
+            } else {
+                return jsrData.endsWithRet;
+            }
+        }
+
+        void setRetSuccessor(BciBlock bciBlock) {
+            this.getOrCreateJSRData().retSuccessor = bciBlock;
+        }
+
+        public BciBlock getRetSuccessor() {
+            if (this.jsrData == null) {
+                return null;
+            } else {
+                return jsrData.retSuccessor;
+            }
+        }
+
+        public BciBlock getJsrSuccessor() {
+            if (this.jsrData == null) {
+                return null;
+            } else {
+                return jsrData.jsrSuccessor;
+            }
+        }
+
+        public int getJsrReturnBci() {
+            if (this.jsrData == null) {
+                return -1;
+            } else {
+                return jsrData.jsrReturnBci;
+            }
+        }
+
+        public HashMap<JsrScope, BciBlock> getJsrAlternatives() {
+            if (this.jsrData == null) {
+                return null;
+            } else {
+                return jsrData.jsrAlternatives;
+            }
+        }
+
+        public void initJsrAlternatives() {
+            JSRData data = this.getOrCreateJSRData();
+            if (data.jsrAlternatives == null) {
+                data.jsrAlternatives = new HashMap<>();
+            }
+        }
+
+        void setJsrScope(JsrScope nextScope) {
+            this.getOrCreateJSRData().jsrScope = nextScope;
+        }
+
+        void setJsrSuccessor(BciBlock clone) {
+            this.getOrCreateJSRData().jsrSuccessor = clone;
+        }
+
+        void setJsrReturnBci(int bci) {
+            this.getOrCreateJSRData().jsrReturnBci = bci;
+        }
+
+        public int getSuccessorCount() {
+            return successors.size();
+        }
+
+        public List<BciBlock> getSuccessors() {
+            return successors;
+        }
+
+        void setId(int i) {
+            this.id = i;
+        }
+
+        public void addSuccessor(BciBlock sux) {
+            successors.add(sux);
+            sux.predecessorCount++;
+        }
+
+        public void clearSucccessors() {
+            for (BciBlock sux : successors) {
+                sux.predecessorCount--;
+            }
+            successors.clear();
+        }
+    }
+
+    public static class ExceptionDispatchBlock extends BciBlock {
+
+        private HashMap<ExceptionHandler, ExceptionDispatchBlock> exceptionDispatch = new HashMap<>();
+
+        public ExceptionHandler handler;
+        public int deoptBci;
+    }
+
+    /**
+     * The blocks found in this method, in reverse postorder.
+     */
+    private BciBlock[] blocks;
+    public final Bytecode code;
+    public boolean hasJsrBytecodes;
+
+    private final ExceptionHandler[] exceptionHandlers;
+    private BciBlock startBlock;
+    private BciBlock[] loopHeaders;
+
+    private static final int LOOP_HEADER_MAX_CAPACITY = Long.SIZE;
+    private static final int LOOP_HEADER_INITIAL_CAPACITY = 4;
+
+    private int blocksNotYetAssignedId;
+    public int returnCount;
+    private int returnBci;
+
+    /**
+     * Creates a new BlockMap instance from {@code code}.
+     */
+    private BciBlockMapping(Bytecode code) {
+        this.code = code;
+        this.exceptionHandlers = code.getExceptionHandlers();
+    }
+
+    public BciBlock[] getBlocks() {
+        return this.blocks;
+    }
+
+    public int getReturnCount() {
+        return this.returnCount;
+    }
+
+    /**
+     * Builds the block map and conservative CFG and numbers blocks.
+     */
+    public void build(BytecodeStream stream) {
+        int codeSize = code.getCodeSize();
+        BciBlock[] blockMap = new BciBlock[codeSize];
+        makeExceptionEntries(blockMap);
+        iterateOverBytecodes(blockMap, stream);
+        if (hasJsrBytecodes) {
+            if (!SupportJsrBytecodes.getValue()) {
+                throw new JsrNotSupportedBailout("jsr/ret parsing disabled");
+            }
+            createJsrAlternatives(blockMap, blockMap[0]);
+        }
+        if (Debug.isLogEnabled()) {
+            this.log(blockMap, "Before BlockOrder");
+        }
+        computeBlockOrder(blockMap);
+        fixLoopBits(blockMap);
+
+        assert verify();
+
+        startBlock = blockMap[0];
+        if (Debug.isLogEnabled()) {
+            this.log(blockMap, "Before LivenessAnalysis");
+        }
+    }
+
+    private boolean verify() {
+        for (BciBlock block : blocks) {
+            assert blocks[block.getId()] == block;
+
+            for (int i = 0; i < block.getSuccessorCount(); i++) {
+                BciBlock sux = block.getSuccessor(i);
+                if (sux instanceof ExceptionDispatchBlock) {
+                    assert i == block.getSuccessorCount() - 1 : "Only one exception handler allowed, and it must be last in successors list";
+                }
+            }
+        }
+
+        return true;
+    }
+
+    private void makeExceptionEntries(BciBlock[] blockMap) {
+        // start basic blocks at all exception handler blocks and mark them as exception entries
+        for (ExceptionHandler h : this.exceptionHandlers) {
+            BciBlock xhandler = makeBlock(blockMap, h.getHandlerBCI());
+            xhandler.isExceptionEntry = true;
+        }
+    }
+
+    private void iterateOverBytecodes(BciBlock[] blockMap, BytecodeStream stream) {
+        // iterate over the bytecodes top to bottom.
+        // mark the entrypoints of basic blocks and build lists of successors for
+        // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
+        BciBlock current = null;
+        stream.setBCI(0);
+        while (stream.currentBC() != Bytecodes.END) {
+            int bci = stream.currentBCI();
+
+            if (current == null || blockMap[bci] != null) {
+                BciBlock b = makeBlock(blockMap, bci);
+                if (current != null) {
+                    addSuccessor(blockMap, current.endBci, b);
+                }
+                current = b;
+            }
+            blockMap[bci] = current;
+            current.endBci = bci;
+
+            switch (stream.currentBC()) {
+                case IRETURN: // fall through
+                case LRETURN: // fall through
+                case FRETURN: // fall through
+                case DRETURN: // fall through
+                case ARETURN: // fall through
+                case RETURN: {
+                    returnCount++;
+                    current = null;
+                    returnBci = bci;
+                    break;
+                }
+                case ATHROW: {
+                    current = null;
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
+                    if (handler != null) {
+                        addSuccessor(blockMap, bci, handler);
+                    }
+                    break;
+                }
+                case IFEQ:      // fall through
+                case IFNE:      // fall through
+                case IFLT:      // fall through
+                case IFGE:      // fall through
+                case IFGT:      // fall through
+                case IFLE:      // fall through
+                case IF_ICMPEQ: // fall through
+                case IF_ICMPNE: // fall through
+                case IF_ICMPLT: // fall through
+                case IF_ICMPGE: // fall through
+                case IF_ICMPGT: // fall through
+                case IF_ICMPLE: // fall through
+                case IF_ACMPEQ: // fall through
+                case IF_ACMPNE: // fall through
+                case IFNULL:    // fall through
+                case IFNONNULL: {
+                    current = null;
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest()));
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
+                    break;
+                }
+                case GOTO:
+                case GOTO_W: {
+                    current = null;
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest()));
+                    break;
+                }
+                case TABLESWITCH: {
+                    current = null;
+                    addSwitchSuccessors(blockMap, bci, new BytecodeTableSwitch(stream, bci));
+                    break;
+                }
+                case LOOKUPSWITCH: {
+                    current = null;
+                    addSwitchSuccessors(blockMap, bci, new BytecodeLookupSwitch(stream, bci));
+                    break;
+                }
+                case JSR:
+                case JSR_W: {
+                    hasJsrBytecodes = true;
+                    int target = stream.readBranchDest();
+                    if (target == 0) {
+                        throw new JsrNotSupportedBailout("jsr target bci 0 not allowed");
+                    }
+                    BciBlock b1 = makeBlock(blockMap, target);
+                    current.setJsrSuccessor(b1);
+                    current.setJsrReturnBci(stream.nextBCI());
+                    current = null;
+                    addSuccessor(blockMap, bci, b1);
+                    break;
+                }
+                case RET: {
+                    current.setEndsWithRet();
+                    current = null;
+                    break;
+                }
+                case INVOKEINTERFACE:
+                case INVOKESPECIAL:
+                case INVOKESTATIC:
+                case INVOKEVIRTUAL:
+                case INVOKEDYNAMIC: {
+                    current = null;
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
+                    if (handler != null) {
+                        addSuccessor(blockMap, bci, handler);
+                    }
+                    break;
+                }
+                case IASTORE:
+                case LASTORE:
+                case FASTORE:
+                case DASTORE:
+                case AASTORE:
+                case BASTORE:
+                case CASTORE:
+                case SASTORE:
+                case IALOAD:
+                case LALOAD:
+                case FALOAD:
+                case DALOAD:
+                case AALOAD:
+                case BALOAD:
+                case CALOAD:
+                case SALOAD:
+                case ARRAYLENGTH:
+                case PUTFIELD:
+                case GETFIELD: {
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
+                    if (handler != null) {
+                        current = null;
+                        addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
+                        addSuccessor(blockMap, bci, handler);
+                    }
+                }
+            }
+            stream.next();
+        }
+    }
+
+    private BciBlock makeBlock(BciBlock[] blockMap, int startBci) {
+        BciBlock oldBlock = blockMap[startBci];
+        if (oldBlock == null) {
+            BciBlock newBlock = new BciBlock();
+            blocksNotYetAssignedId++;
+            newBlock.startBci = startBci;
+            blockMap[startBci] = newBlock;
+            return newBlock;
+
+        } else if (oldBlock.startBci != startBci) {
+            // Backward branch into the middle of an already processed block.
+            // Add the correct fall-through successor.
+            BciBlock newBlock = new BciBlock();
+            blocksNotYetAssignedId++;
+            newBlock.startBci = startBci;
+            newBlock.endBci = oldBlock.endBci;
+            for (BciBlock oldSuccessor : oldBlock.getSuccessors()) {
+                newBlock.addSuccessor(oldSuccessor);
+            }
+
+            oldBlock.endBci = startBci - 1;
+            oldBlock.clearSucccessors();
+            oldBlock.addSuccessor(newBlock);
+
+            for (int i = startBci; i <= newBlock.endBci; i++) {
+                blockMap[i] = newBlock;
+            }
+            return newBlock;
+
+        } else {
+            return oldBlock;
+        }
+    }
+
+    private void addSwitchSuccessors(BciBlock[] blockMap, int predBci, BytecodeSwitch bswitch) {
+        // adds distinct targets to the successor list
+        Collection<Integer> targets = new TreeSet<>();
+        for (int i = 0; i < bswitch.numberOfCases(); i++) {
+            targets.add(bswitch.targetAt(i));
+        }
+        targets.add(bswitch.defaultTarget());
+        for (int targetBci : targets) {
+            addSuccessor(blockMap, predBci, makeBlock(blockMap, targetBci));
+        }
+    }
+
+    private static void addSuccessor(BciBlock[] blockMap, int predBci, BciBlock sux) {
+        BciBlock predecessor = blockMap[predBci];
+        if (sux.isExceptionEntry) {
+            throw new PermanentBailoutException("Exception handler can be reached by both normal and exceptional control flow");
+        }
+        predecessor.addSuccessor(sux);
+    }
+
+    private final ArrayList<BciBlock> jsrVisited = new ArrayList<>();
+
+    private void createJsrAlternatives(BciBlock[] blockMap, BciBlock block) {
+        jsrVisited.add(block);
+        JsrScope scope = block.getJsrScope();
+
+        if (block.endsWithRet()) {
+            block.setRetSuccessor(blockMap[scope.nextReturnAddress()]);
+            block.addSuccessor(block.getRetSuccessor());
+            assert block.getRetSuccessor() != block.getJsrSuccessor();
+        }
+        Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.getSuccessors(), block.getJsrSuccessor(), block.getRetSuccessor(), block.getJsrScope());
+
+        if (block.getJsrSuccessor() != null || !scope.isEmpty()) {
+            for (int i = 0; i < block.getSuccessorCount(); i++) {
+                BciBlock successor = block.getSuccessor(i);
+                JsrScope nextScope = scope;
+                if (successor == block.getJsrSuccessor()) {
+                    nextScope = scope.push(block.getJsrReturnBci());
+                }
+                if (successor == block.getRetSuccessor()) {
+                    nextScope = scope.pop();
+                }
+                if (!successor.getJsrScope().isPrefixOf(nextScope)) {
+                    throw new JsrNotSupportedBailout("unstructured control flow  (" + successor.getJsrScope() + " " + nextScope + ")");
+                }
+                if (!nextScope.isEmpty()) {
+                    BciBlock clone;
+                    if (successor.getJsrAlternatives() != null && successor.getJsrAlternatives().containsKey(nextScope)) {
+                        clone = successor.getJsrAlternatives().get(nextScope);
+                    } else {
+                        successor.initJsrAlternatives();
+                        clone = successor.copy();
+                        blocksNotYetAssignedId++;
+                        clone.setJsrScope(nextScope);
+                        successor.getJsrAlternatives().put(nextScope, clone);
+                    }
+                    block.getSuccessors().set(i, clone);
+                    if (successor == block.getJsrSuccessor()) {
+                        block.setJsrSuccessor(clone);
+                    }
+                    if (successor == block.getRetSuccessor()) {
+                        block.setRetSuccessor(clone);
+                    }
+                }
+            }
+        }
+        for (BciBlock successor : block.getSuccessors()) {
+            if (!jsrVisited.contains(successor)) {
+                createJsrAlternatives(blockMap, successor);
+            }
+        }
+    }
+
+    private HashMap<ExceptionHandler, ExceptionDispatchBlock> initialExceptionDispatch = CollectionsFactory.newMap();
+
+    private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) {
+        ExceptionDispatchBlock lastHandler = null;
+
+        for (int i = exceptionHandlers.length - 1; i >= 0; i--) {
+            ExceptionHandler h = exceptionHandlers[i];
+            if (h.getStartBCI() <= bci && bci < h.getEndBCI()) {
+                if (h.isCatchAll()) {
+                    // Discard all information about succeeding exception handlers, since they can
+                    // never be reached.
+                    lastHandler = null;
+                }
+
+                HashMap<ExceptionHandler, ExceptionDispatchBlock> exceptionDispatch = lastHandler != null ? lastHandler.exceptionDispatch : initialExceptionDispatch;
+                ExceptionDispatchBlock curHandler = exceptionDispatch.get(h);
+                if (curHandler == null) {
+                    curHandler = new ExceptionDispatchBlock();
+                    blocksNotYetAssignedId++;
+                    curHandler.startBci = -1;
+                    curHandler.endBci = -1;
+                    curHandler.deoptBci = bci;
+                    curHandler.handler = h;
+                    curHandler.addSuccessor(blockMap[h.getHandlerBCI()]);
+                    if (lastHandler != null) {
+                        curHandler.addSuccessor(lastHandler);
+                    }
+                    exceptionDispatch.put(h, curHandler);
+                }
+                lastHandler = curHandler;
+            }
+        }
+        return lastHandler;
+    }
+
+    private boolean loopChanges;
+
+    private void fixLoopBits(BciBlock[] blockMap) {
+        do {
+            loopChanges = false;
+            for (BciBlock b : blocks) {
+                b.visited = false;
+            }
+
+            long loop = fixLoopBits(blockMap, blockMap[0]);
+
+            if (loop != 0) {
+                // There is a path from a loop end to the method entry that does not pass the loop
+                // header.
+                // Therefore, the loop is non reducible (has more than one entry).
+                // We don't want to compile such methods because the IR only supports structured
+                // loops.
+                throw new PermanentBailoutException("Non-reducible loop: %016x", loop);
+            }
+        } while (loopChanges);
+    }
+
+    private void computeBlockOrder(BciBlock[] blockMap) {
+        int maxBlocks = blocksNotYetAssignedId;
+        this.blocks = new BciBlock[blocksNotYetAssignedId];
+        long loop = computeBlockOrder(blockMap[0]);
+
+        if (loop != 0) {
+            // There is a path from a loop end to the method entry that does not pass the loop
+            // header. Therefore, the loop is non reducible (has more than one entry).
+            // We don't want to compile such methods because the IR only supports structured loops.
+            throw new PermanentBailoutException("Non-reducible loop");
+        }
+
+        // Purge null entries for unreached blocks and sort blocks such that loop bodies are always
+        // consecutively in the array.
+        int blockCount = maxBlocks - blocksNotYetAssignedId + 2;
+        BciBlock[] newBlocks = new BciBlock[blockCount];
+        int next = 0;
+        for (int i = 0; i < blocks.length; ++i) {
+            BciBlock b = blocks[i];
+            if (b != null) {
+                b.setId(next);
+                newBlocks[next++] = b;
+                if (b.isLoopHeader) {
+                    next = handleLoopHeader(newBlocks, next, i, b);
+                }
+            }
+        }
+
+        // Add return block.
+        BciBlock returnBlock = new BciBlock();
+        returnBlock.startBci = returnBci;
+        returnBlock.endBci = returnBci;
+        returnBlock.setId(newBlocks.length - 2);
+        newBlocks[newBlocks.length - 2] = returnBlock;
+
+        // Add unwind block.
+        ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock();
+        unwindBlock.startBci = -1;
+        unwindBlock.endBci = -1;
+        unwindBlock.deoptBci = code.getMethod().isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI;
+        unwindBlock.setId(newBlocks.length - 1);
+        newBlocks[newBlocks.length - 1] = unwindBlock;
+
+        blocks = newBlocks;
+    }
+
+    private int handleLoopHeader(BciBlock[] newBlocks, int nextStart, int i, BciBlock loopHeader) {
+        int next = nextStart;
+        int endOfLoop = nextStart - 1;
+        for (int j = i + 1; j < blocks.length; ++j) {
+            BciBlock other = blocks[j];
+            if (other != null && (other.loops & (1L << loopHeader.loopId)) != 0) {
+                other.setId(next);
+                endOfLoop = next;
+                newBlocks[next++] = other;
+                blocks[j] = null;
+                if (other.isLoopHeader) {
+                    next = handleLoopHeader(newBlocks, next, j, other);
+                }
+            }
+        }
+        loopHeader.loopEnd = endOfLoop;
+        return next;
+    }
+
+    public void log(BciBlock[] blockMap, String name) {
+        if (Debug.isLogEnabled()) {
+            String n = System.lineSeparator();
+            StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :");
+            sb.append(n);
+            Iterable<BciBlock> it;
+            if (blocks == null) {
+                it = new HashSet<>(Arrays.asList(blockMap));
+            } else {
+                it = Arrays.asList(blocks);
+            }
+            for (BciBlock b : it) {
+                if (b == null) {
+                    continue;
+                }
+                sb.append("B").append(b.getId()).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")");
+                if (b.isLoopHeader) {
+                    sb.append(" LoopHeader");
+                }
+                if (b.isExceptionEntry) {
+                    sb.append(" ExceptionEntry");
+                }
+                sb.append(n).append("  Sux : ");
+                for (BciBlock s : b.getSuccessors()) {
+                    sb.append("B").append(s.getId()).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")");
+                    if (s.isExceptionEntry) {
+                        sb.append("!");
+                    }
+                    sb.append(" ");
+                }
+                sb.append(n).append("  Loop : ");
+                for (int pos : b.loopIdIterable()) {
+                    sb.append("B").append(loopHeaders[pos].getId()).append(" ");
+                }
+                sb.append(n);
+            }
+            Debug.log("%s", sb);
+        }
+    }
+
+    /**
+     * Get the header block for a loop index.
+     */
+    public BciBlock getLoopHeader(int index) {
+        return loopHeaders[index];
+    }
+
+    /**
+     * The next available loop number.
+     */
+    private int nextLoop;
+
+    /**
+     * Mark the block as a loop header, using the next available loop number. Also checks for corner
+     * cases that we don't want to compile.
+     */
+    private void makeLoopHeader(BciBlock block) {
+        if (!block.isLoopHeader) {
+            block.isLoopHeader = true;
+
+            if (block.isExceptionEntry) {
+                // Loops that are implicitly formed by an exception handler lead to all sorts of
+                // corner cases.
+                // Don't compile such methods for now, until we see a concrete case that allows
+                // checking for correctness.
+                throw new PermanentBailoutException("Loop formed by an exception handler");
+            }
+            if (nextLoop >= LOOP_HEADER_MAX_CAPACITY) {
+                // This restriction can be removed by using a fall-back to a BitSet in case we have
+                // more than 64 loops
+                // Don't compile such methods for now, until we see a concrete case that allows
+                // checking for correctness.
+                throw new PermanentBailoutException("Too many loops in method");
+            }
+
+            assert block.loops == 0;
+            block.loops = 1L << nextLoop;
+            Debug.log("makeLoopHeader(%s) -> %x", block, block.loops);
+            if (loopHeaders == null) {
+                loopHeaders = new BciBlock[LOOP_HEADER_INITIAL_CAPACITY];
+            } else if (nextLoop >= loopHeaders.length) {
+                loopHeaders = Arrays.copyOf(loopHeaders, LOOP_HEADER_MAX_CAPACITY);
+            }
+            loopHeaders[nextLoop] = block;
+            block.loopId = nextLoop;
+            nextLoop++;
+        }
+        assert Long.bitCount(block.loops) == 1;
+    }
+
+    /**
+     * Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is
+     * used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect
+     * cycles (backward edges).
+     */
+    private long computeBlockOrder(BciBlock block) {
+        if (block.visited) {
+            if (block.active) {
+                // Reached block via backward branch.
+                makeLoopHeader(block);
+                // Return cached loop information for this block.
+                return block.loops;
+            } else if (block.isLoopHeader) {
+                return block.loops & ~(1L << block.loopId);
+            } else {
+                return block.loops;
+            }
+        }
+
+        block.visited = true;
+        block.active = true;
+
+        long loops = 0;
+        for (BciBlock successor : block.getSuccessors()) {
+            // Recursively process successors.
+            loops |= computeBlockOrder(successor);
+            if (successor.active) {
+                // Reached block via backward branch.
+                loops |= (1L << successor.loopId);
+            }
+        }
+
+        block.loops = loops;
+        Debug.log("computeBlockOrder(%s) -> %x", block, block.loops);
+
+        if (block.isLoopHeader) {
+            loops &= ~(1L << block.loopId);
+        }
+
+        block.active = false;
+        blocksNotYetAssignedId--;
+        blocks[blocksNotYetAssignedId] = block;
+
+        return loops;
+    }
+
+    private long fixLoopBits(BciBlock[] blockMap, BciBlock block) {
+        if (block.visited) {
+            // Return cached loop information for this block.
+            if (block.isLoopHeader) {
+                return block.loops & ~(1L << block.loopId);
+            } else {
+                return block.loops;
+            }
+        }
+
+        block.visited = true;
+        long loops = block.loops;
+        for (BciBlock successor : block.getSuccessors()) {
+            // Recursively process successors.
+            loops |= fixLoopBits(blockMap, successor);
+        }
+        if (block.loops != loops) {
+            loopChanges = true;
+            block.loops = loops;
+            Debug.log("fixLoopBits0(%s) -> %x", block, block.loops);
+        }
+
+        if (block.isLoopHeader) {
+            loops &= ~(1L << block.loopId);
+        }
+
+        return loops;
+    }
+
+    public static BciBlockMapping create(BytecodeStream stream, Bytecode code) {
+        BciBlockMapping map = new BciBlockMapping(code);
+        map.build(stream);
+        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            Debug.dump(Debug.INFO_LOG_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)"));
+        }
+
+        return map;
+    }
+
+    public BciBlock[] getLoopHeaders() {
+        return loopHeaders;
+    }
+
+    public BciBlock getStartBlock() {
+        return startBlock;
+    }
+
+    public BciBlock getReturnBlock() {
+        return blocks[blocks.length - 2];
+    }
+
+    public ExceptionDispatchBlock getUnwindBlock() {
+        return (ExceptionDispatchBlock) blocks[blocks.length - 1];
+    }
+
+    public int getLoopCount() {
+        return nextLoop;
+    }
+
+    public int getBlockCount() {
+        return blocks.length;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
new file mode 100644
index 0000000..bba5c70
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
@@ -0,0 +1,4118 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ACONST_NULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW;
+import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.BREAKPOINT;
+import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST;
+import static org.graalvm.compiler.bytecode.Bytecodes.D2F;
+import static org.graalvm.compiler.bytecode.Bytecodes.D2I;
+import static org.graalvm.compiler.bytecode.Bytecodes.D2L;
+import static org.graalvm.compiler.bytecode.Bytecodes.DADD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.DCMPG;
+import static org.graalvm.compiler.bytecode.Bytecodes.DCMPL;
+import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DDIV;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.DMUL;
+import static org.graalvm.compiler.bytecode.Bytecodes.DNEG;
+import static org.graalvm.compiler.bytecode.Bytecodes.DREM;
+import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSUB;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2;
+import static org.graalvm.compiler.bytecode.Bytecodes.F2D;
+import static org.graalvm.compiler.bytecode.Bytecodes.F2I;
+import static org.graalvm.compiler.bytecode.Bytecodes.F2L;
+import static org.graalvm.compiler.bytecode.Bytecodes.FADD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FCMPG;
+import static org.graalvm.compiler.bytecode.Bytecodes.FCMPL;
+import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.FDIV;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.FMUL;
+import static org.graalvm.compiler.bytecode.Bytecodes.FNEG;
+import static org.graalvm.compiler.bytecode.Bytecodes.FREM;
+import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSUB;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2B;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2C;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2D;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2F;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2L;
+import static org.graalvm.compiler.bytecode.Bytecodes.I2S;
+import static org.graalvm.compiler.bytecode.Bytecodes.IADD;
+import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.IAND;
+import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_4;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_5;
+import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_M1;
+import static org.graalvm.compiler.bytecode.Bytecodes.IDIV;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IINC;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.IMUL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INEG;
+import static org.graalvm.compiler.bytecode.Bytecodes.INSTANCEOF;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IOR;
+import static org.graalvm.compiler.bytecode.Bytecodes.IREM;
+import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISHL;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISHR;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISUB;
+import static org.graalvm.compiler.bytecode.Bytecodes.IUSHR;
+import static org.graalvm.compiler.bytecode.Bytecodes.IXOR;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.L2D;
+import static org.graalvm.compiler.bytecode.Bytecodes.L2F;
+import static org.graalvm.compiler.bytecode.Bytecodes.L2I;
+import static org.graalvm.compiler.bytecode.Bytecodes.LADD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LAND;
+import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.LCMP;
+import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDIV;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.LMUL;
+import static org.graalvm.compiler.bytecode.Bytecodes.LNEG;
+import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.LOR;
+import static org.graalvm.compiler.bytecode.Bytecodes.LREM;
+import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSHL;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSHR;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSUB;
+import static org.graalvm.compiler.bytecode.Bytecodes.LUSHR;
+import static org.graalvm.compiler.bytecode.Bytecodes.LXOR;
+import static org.graalvm.compiler.bytecode.Bytecodes.MONITORENTER;
+import static org.graalvm.compiler.bytecode.Bytecodes.MONITOREXIT;
+import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEW;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.NOP;
+import static org.graalvm.compiler.bytecode.Bytecodes.POP;
+import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.RET;
+import static org.graalvm.compiler.bytecode.Bytecodes.RETURN;
+import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
+import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.nameOf;
+import static org.graalvm.compiler.core.common.GraalOptions.DeoptALot;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.PrintProfilingInformation;
+import static org.graalvm.compiler.core.common.GraalOptions.ResolveClassBeforeStaticInvoke;
+import static org.graalvm.compiler.core.common.GraalOptions.StressInvokeWithExceptionNode;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
+import static org.graalvm.compiler.debug.GraalError.guarantee;
+import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding;
+import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
+import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
+import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING;
+import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull;
+import static java.lang.String.format;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
+import static jdk.vm.ci.meta.DeoptimizationReason.TypeCheckedInliningViolated;
+import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode;
+import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
+import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
+
+import java.lang.ref.Reference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.bytecode.BytecodeStream;
+import org.graalvm.compiler.bytecode.BytecodeSwitch;
+import org.graalvm.compiler.bytecode.BytecodeTableSwitch;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+import org.graalvm.compiler.java.BciBlockMapping.ExceptionDispatchBlock;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.BeginStateSplitNode;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.EntryMarkerNode;
+import org.graalvm.compiler.nodes.EntryProxyNode;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.KillingBeginNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.calc.OrNode;
+import org.graalvm.compiler.nodes.calc.RemNode;
+import org.graalvm.compiler.nodes.calc.RightShiftNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.SignedDivNode;
+import org.graalvm.compiler.nodes.calc.SignedRemNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
+import org.graalvm.compiler.nodes.calc.XorNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationBeginNode;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.LoadMethodNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
+import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.MonitorEnterNode;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
+import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
+import jdk.vm.ci.meta.LineNumberTable;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.RawConstant;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
+ */
+public class BytecodeParser implements GraphBuilderContext {
+
+    /**
+     * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set
+     * to trace the bytecode instructions as they are parsed.
+     */
+    public static final int TRACELEVEL_INSTRUCTIONS = 1;
+
+    /**
+     * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set
+     * to trace the frame state before each bytecode instruction as it is parsed.
+     */
+    public static final int TRACELEVEL_STATE = 2;
+
+    /**
+     * Meters the number of actual bytecodes parsed.
+     */
+    public static final DebugCounter BytecodesParsed = Debug.counter("BytecodesParsed");
+
+    protected static final DebugCounter EXPLICIT_EXCEPTIONS = Debug.counter("ExplicitExceptions");
+
+    /**
+     * A scoped object for tasks to be performed after parsing an intrinsic such as processing
+     * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states.
+     */
+    static class IntrinsicScope implements AutoCloseable {
+        FrameState stateBefore;
+        final Mark mark;
+        final BytecodeParser parser;
+
+        /**
+         * Creates a scope for root parsing an intrinsic.
+         *
+         * @param parser the parsing context of the intrinsic
+         */
+        IntrinsicScope(BytecodeParser parser) {
+            this.parser = parser;
+            assert parser.parent == null;
+            assert parser.bci() == 0;
+            mark = null;
+        }
+
+        /**
+         * Creates a scope for parsing an intrinsic during graph builder inlining.
+         *
+         * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic
+         * @param args the arguments to the call
+         */
+        IntrinsicScope(BytecodeParser parser, JavaKind[] argSlotKinds, ValueNode[] args) {
+            assert !parser.parsingIntrinsic();
+            this.parser = parser;
+            mark = parser.getGraph().getMark();
+            stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, argSlotKinds, args);
+        }
+
+        @Override
+        public void close() {
+            IntrinsicContext intrinsic = parser.intrinsicContext;
+            if (intrinsic != null && intrinsic.isPostParseInlined()) {
+                return;
+            }
+
+            processPlaceholderFrameStates(intrinsic);
+        }
+
+        /**
+         * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states
+         * added to the graph while parsing/inlining the intrinsic for which this object exists.
+         */
+        private void processPlaceholderFrameStates(IntrinsicContext intrinsic) {
+            FrameState stateAfterReturn = null;
+            StructuredGraph graph = parser.getGraph();
+            for (Node node : graph.getNewNodes(mark)) {
+                if (node instanceof FrameState) {
+                    FrameState frameState = (FrameState) node;
+                    if (BytecodeFrame.isPlaceholderBci(frameState.bci)) {
+                        if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                            FrameStateBuilder frameStateBuilder = parser.frameState;
+                            if (frameState.stackSize() != 0) {
+                                assert frameState.usages().count() == 1;
+                                ValueNode returnVal = frameState.stackAt(0);
+                                assert returnVal == frameState.usages().first();
+
+                                if (parser.currentInvokeReturnType == null) {
+                                    assert intrinsic.isCompilationRoot();
+                                    FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                    frameState.replaceAndDelete(newFrameState);
+                                } else {
+                                    /*
+                                     * Swap the top-of-stack value with the side-effect return value
+                                     * using the frame state.
+                                     */
+                                    JavaKind returnKind = parser.currentInvokeReturnType.getJavaKind();
+                                    ValueNode tos = frameStateBuilder.pop(returnKind);
+                                    assert tos.getStackKind() == returnVal.getStackKind();
+                                    FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, new JavaKind[]{returnKind},
+                                                    new ValueNode[]{returnVal});
+                                    frameState.replaceAndDelete(newFrameState);
+                                    frameStateBuilder.push(returnKind, tos);
+                                }
+                            } else {
+                                if (stateAfterReturn == null) {
+                                    if (intrinsic != null) {
+                                        assert intrinsic.isCompilationRoot();
+                                        stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                    } else {
+                                        stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null);
+                                    }
+                                }
+                                frameState.replaceAndDelete(stateAfterReturn);
+                            }
+                        } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
+                            if (stateBefore == null) {
+                                stateBefore = graph.start().stateAfter();
+                            }
+                            if (stateBefore != frameState) {
+                                frameState.replaceAndDelete(stateBefore);
+                            }
+                        } else {
+                            assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static class Target {
+        FixedNode fixed;
+        FrameStateBuilder state;
+
+        Target(FixedNode fixed, FrameStateBuilder state) {
+            this.fixed = fixed;
+            this.state = state;
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class BytecodeParserError extends GraalError {
+
+        public BytecodeParserError(Throwable cause) {
+            super(cause);
+        }
+
+        public BytecodeParserError(String msg, Object... args) {
+            super(msg, args);
+        }
+    }
+
+    private final GraphBuilderPhase.Instance graphBuilderInstance;
+    protected final StructuredGraph graph;
+
+    private BciBlockMapping blockMap;
+    private LocalLiveness liveness;
+    protected final int entryBCI;
+    private final BytecodeParser parent;
+
+    private LineNumberTable lnt;
+    private int previousLineNumber;
+    private int currentLineNumber;
+
+    private ValueNode methodSynchronizedObject;
+
+    private ValueNode returnValue;
+    private FixedWithNextNode beforeReturnNode;
+    private ValueNode unwindValue;
+    private FixedWithNextNode beforeUnwindNode;
+
+    protected FixedWithNextNode lastInstr;                 // the last instruction added
+    private boolean controlFlowSplit;
+    private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this);
+
+    private FixedWithNextNode[] firstInstructionArray;
+    private FrameStateBuilder[] entryStateArray;
+
+    private int lastBCI; // BCI of lastInstr. This field is for resolving instrumentation target.
+
+    private boolean finalBarrierRequired;
+    private ValueNode originalReceiver;
+
+    protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method,
+                    int entryBCI, IntrinsicContext intrinsicContext) {
+        this.bytecodeProvider = intrinsicContext == null ? new ResolvedJavaMethodBytecodeProvider() : intrinsicContext.getBytecodeProvider();
+        this.code = bytecodeProvider.getBytecode(method);
+        this.method = code.getMethod();
+        this.graphBuilderInstance = graphBuilderInstance;
+        this.graph = graph;
+        this.graphBuilderConfig = graphBuilderInstance.graphBuilderConfig;
+        this.optimisticOpts = graphBuilderInstance.optimisticOpts;
+        this.metaAccess = graphBuilderInstance.metaAccess;
+        this.stampProvider = graphBuilderInstance.stampProvider;
+        this.constantReflection = graphBuilderInstance.constantReflection;
+        this.constantFieldProvider = graphBuilderInstance.constantFieldProvider;
+        this.stream = new BytecodeStream(code.getCode());
+        this.profilingInfo = graph.useProfilingInfo() ? code.getProfilingInfo() : null;
+        this.constantPool = code.getConstantPool();
+        this.intrinsicContext = intrinsicContext;
+        this.entryBCI = entryBCI;
+        this.parent = parent;
+        this.lastBCI = -1;
+
+        assert code.getCode() != null : "method must contain bytecodes: " + method;
+
+        if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
+            lnt = code.getLineNumberTable();
+            previousLineNumber = -1;
+        }
+    }
+
+    protected GraphBuilderPhase.Instance getGraphBuilderInstance() {
+        return graphBuilderInstance;
+    }
+
+    public ValueNode getReturnValue() {
+        return returnValue;
+    }
+
+    public FixedWithNextNode getBeforeReturnNode() {
+        return this.beforeReturnNode;
+    }
+
+    public ValueNode getUnwindValue() {
+        return unwindValue;
+    }
+
+    public FixedWithNextNode getBeforeUnwindNode() {
+        return this.beforeUnwindNode;
+    }
+
+    @SuppressWarnings("try")
+    protected void buildRootMethod() {
+        FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph);
+        startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins());
+
+        try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(this) : null) {
+            build(graph.start(), startFrameState);
+        }
+
+        cleanupFinalGraph();
+        ComputeLoopFrequenciesClosure.compute(graph);
+    }
+
+    @SuppressWarnings("try")
+    protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) {
+        if (PrintProfilingInformation.getValue() && profilingInfo != null) {
+            TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
+            TTY.println(Util.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
+        }
+
+        try (Indent indent = Debug.logAndIndent("build graph for %s", method)) {
+            if (bytecodeProvider.shouldRecordMethodDependencies()) {
+                assert getParent() != null || method.equals(graph.method());
+                // Record method dependency in the graph
+                graph.recordMethod(method);
+            }
+
+            // compute the block map, setup exception handlers and get the entrypoint(s)
+            BciBlockMapping newMapping = BciBlockMapping.create(stream, code);
+            this.blockMap = newMapping;
+            this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()];
+            this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()];
+            if (!method.isStatic()) {
+                originalReceiver = startFrameState.loadLocal(0, JavaKind.Object);
+            }
+
+            /*
+             * Configure the assertion checking behavior of the FrameStateBuilder. This needs to be
+             * done only when assertions are enabled, so it is wrapped in an assertion itself.
+             */
+            assert computeKindVerification(startFrameState);
+
+            try (Scope s = Debug.scope("LivenessAnalysis")) {
+                int maxLocals = method.getMaxLocals();
+                liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
+            lastInstr = startInstruction;
+            this.setCurrentFrameState(startFrameState);
+            stream.setBCI(0);
+
+            BciBlock startBlock = blockMap.getStartBlock();
+            if (this.parent == null) {
+                StartNode startNode = graph.start();
+                if (method.isSynchronized()) {
+                    assert !parsingIntrinsic();
+                    startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode));
+                } else {
+                    if (!parsingIntrinsic()) {
+                        if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
+                            /*
+                             * Don't clear the receiver when Object.<init> is the compilation root.
+                             * The receiver is needed as input to RegisterFinalizerNode.
+                             */
+                        } else {
+                            frameState.clearNonLiveLocals(startBlock, liveness, true);
+                        }
+                        assert bci() == 0;
+                        startNode.setStateAfter(createFrameState(bci(), startNode));
+                    } else {
+                        if (startNode.stateAfter() == null) {
+                            FrameState stateAfterStart = createStateAfterStartOfReplacementGraph();
+                            startNode.setStateAfter(stateAfterStart);
+                        }
+                    }
+                }
+            }
+
+            if (method.isSynchronized()) {
+                // add a monitor enter to the start block
+                methodSynchronizedObject = synchronizedObject(frameState, method);
+                frameState.clearNonLiveLocals(startBlock, liveness, true);
+                assert bci() == 0;
+                genMonitorEnter(methodSynchronizedObject, bci());
+            }
+
+            ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
+            if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                profilingPlugin.profileInvoke(this, method, stateBefore);
+            }
+
+            finishPrepare(lastInstr);
+
+            genInfoPointNode(InfopointReason.METHOD_START, null);
+
+            currentBlock = blockMap.getStartBlock();
+            setEntryState(startBlock, frameState);
+            if (startBlock.isLoopHeader) {
+                appendGoto(startBlock);
+            } else {
+                setFirstInstruction(startBlock, lastInstr);
+            }
+
+            BciBlock[] blocks = blockMap.getBlocks();
+            for (BciBlock block : blocks) {
+                processBlock(block);
+            }
+
+            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue() && this.beforeReturnNode != startInstruction) {
+                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Bytecodes parsed: %s.%s", method.getDeclaringClass().getUnqualifiedName(), method.getName());
+            }
+        }
+    }
+
+    private boolean computeKindVerification(FrameStateBuilder startFrameState) {
+        if (blockMap.hasJsrBytecodes) {
+            /*
+             * The JSR return address is an int value, but stored using the astore bytecode. Instead
+             * of weakening the kind assertion checking for all methods, we disable it completely
+             * for methods that contain a JSR bytecode.
+             */
+            startFrameState.disableKindVerification();
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.canChangeStackKind(this)) {
+                /*
+                 * We have a plugin that can change the kind of values, so no kind assertion
+                 * checking is possible.
+                 */
+                startFrameState.disableKindVerification();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Hook for subclasses to modify the graph start instruction or append new instructions to it.
+     *
+     * @param startInstr the start instruction of the graph
+     */
+    protected void finishPrepare(FixedWithNextNode startInstr) {
+    }
+
+    protected void cleanupFinalGraph() {
+        GraphUtil.normalizeLoops(graph);
+
+        // Remove dead parameters.
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            if (param.hasNoUsages()) {
+                assert param.inputs().isEmpty();
+                param.safeDelete();
+            }
+        }
+
+        // Remove redundant begin nodes.
+        for (BeginNode beginNode : graph.getNodes(BeginNode.TYPE)) {
+            Node predecessor = beginNode.predecessor();
+            if (predecessor instanceof ControlSplitNode) {
+                // The begin node is necessary.
+            } else {
+                if (beginNode.hasUsages()) {
+                    reanchorGuardedNodes(beginNode);
+                }
+                GraphUtil.unlinkFixedNode(beginNode);
+                beginNode.safeDelete();
+            }
+        }
+    }
+
+    /**
+     * Removes {@link GuardedNode}s from {@code beginNode}'s usages and re-attaches them to an
+     * appropriate preceeding {@link GuardingNode}.
+     */
+    protected void reanchorGuardedNodes(BeginNode beginNode) {
+        // Find the new guarding node
+        GuardingNode guarding = null;
+        Node pred = beginNode.predecessor();
+        while (pred != null) {
+            if (pred instanceof BeginNode) {
+                if (pred.predecessor() instanceof ControlSplitNode) {
+                    guarding = (GuardingNode) pred;
+                    break;
+                }
+            } else if (pred.getNodeClass().getAllowedUsageTypes().contains(InputType.Guard)) {
+                guarding = (GuardingNode) pred;
+                break;
+            }
+            pred = pred.predecessor();
+        }
+
+        // Reset the guard for all of beginNode's usages
+        for (Node usage : beginNode.usages().snapshot()) {
+            GuardedNode guarded = (GuardedNode) usage;
+            assert guarded.getGuard() == beginNode;
+            guarded.setGuard(guarding);
+        }
+        assert beginNode.hasNoUsages() : beginNode;
+    }
+
+    /**
+     * Creates the frame state after the start node of a graph for an {@link IntrinsicContext
+     * intrinsic} that is the parse root (either for root compiling or for post-parse inlining).
+     */
+    private FrameState createStateAfterStartOfReplacementGraph() {
+        assert parent == null;
+        assert frameState.getMethod().equals(intrinsicContext.getIntrinsicMethod());
+        assert bci() == 0;
+        assert frameState.stackSize() == 0;
+        FrameState stateAfterStart;
+        if (intrinsicContext.isPostParseInlined()) {
+            stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
+        } else {
+            ResolvedJavaMethod original = intrinsicContext.getOriginalMethod();
+            ValueNode[] locals;
+            if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) {
+                locals = new ValueNode[original.getMaxLocals()];
+                for (int i = 0; i < locals.length; i++) {
+                    ValueNode node = frameState.locals[i];
+                    if (node == FrameState.TWO_SLOT_MARKER) {
+                        node = null;
+                    }
+                    locals[i] = node;
+                }
+            } else {
+                locals = new ValueNode[original.getMaxLocals()];
+                int parameterCount = original.getSignature().getParameterCount(!original.isStatic());
+                for (int i = 0; i < parameterCount; i++) {
+                    ValueNode param = frameState.locals[i];
+                    if (param == FrameState.TWO_SLOT_MARKER) {
+                        param = null;
+                    }
+                    locals[i] = param;
+                    assert param == null || param instanceof ParameterNode || param.isConstant();
+                }
+            }
+            ValueNode[] stack = {};
+            int stackSize = 0;
+            ValueNode[] locks = {};
+            List<MonitorIdNode> monitorIds = Collections.emptyList();
+            stateAfterStart = graph.add(new FrameState(null, new ResolvedJavaMethodBytecode(original), 0, locals, stack, stackSize, locks, monitorIds, false, false));
+        }
+        return stateAfterStart;
+    }
+
+    /**
+     * @param type the unresolved type of the constant
+     */
+    protected void handleUnresolvedLoadConstant(JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param type the unresolved type of the type check
+     * @param object the object value whose type is being checked against {@code type}
+     */
+    protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new FixedGuardNode(graph.unique(IsNullNode.create(object)), Unresolved, InvalidateRecompile));
+        frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER));
+    }
+
+    /**
+     * @param type the unresolved type of the type check
+     * @param object the object value whose type is being checked against {@code type}
+     */
+    protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
+        assert !graphBuilderConfig.eagerResolving();
+        AbstractBeginNode successor = graph.add(new BeginNode());
+        DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        append(new IfNode(graph.unique(IsNullNode.create(object)), successor, deopt, 1));
+        lastInstr = successor;
+        frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0));
+    }
+
+    /**
+     * @param type the type being instantiated
+     */
+    protected void handleUnresolvedNewInstance(JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param type the type of the array being instantiated
+     * @param length the length of the array
+     */
+    protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param type the type being instantiated
+     * @param dims the dimensions for the multi-array
+     */
+    protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param field the unresolved field
+     * @param receiver the object containing the field or {@code null} if {@code field} is static
+     */
+    protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param field the unresolved field
+     * @param value the value being stored to the field
+     * @param receiver the object containing the field or {@code null} if {@code field} is static
+     */
+    protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param type
+     */
+    protected void handleUnresolvedExceptionType(JavaType type) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    /**
+     * @param javaMethod
+     * @param invokeKind
+     */
+    protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
+        assert !graphBuilderConfig.eagerResolving();
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+    }
+
+    private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) {
+        assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
+        Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));
+
+        FrameStateBuilder dispatchState = frameState.copy();
+        dispatchState.clearStack();
+
+        AbstractBeginNode dispatchBegin;
+        if (exceptionObject == null) {
+            ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(metaAccess));
+            dispatchBegin = newExceptionObject;
+            dispatchState.push(JavaKind.Object, dispatchBegin);
+            dispatchState.setRethrowException(true);
+            newExceptionObject.setStateAfter(dispatchState.create(bci, newExceptionObject));
+        } else {
+            dispatchBegin = graph.add(new BeginNode());
+            dispatchState.push(JavaKind.Object, exceptionObject);
+            dispatchState.setRethrowException(true);
+        }
+        this.controlFlowSplit = true;
+        FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
+
+        createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
+
+        return dispatchBegin;
+    }
+
+    protected void createHandleExceptionTarget(FixedWithNextNode finishedDispatch, int bci, FrameStateBuilder dispatchState) {
+        BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
+        /*
+         * The exception dispatch block is always for the last bytecode of a block, so if we are not
+         * at the endBci yet, there is no exception handler for this bci and we can unwind
+         * immediately.
+         */
+        if (bci != currentBlock.endBci || dispatchBlock == null) {
+            dispatchBlock = blockMap.getUnwindBlock();
+        }
+
+        FixedNode target = createTarget(dispatchBlock, dispatchState);
+        finishedDispatch.setNext(target);
+    }
+
+    protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, JavaKind kind) {
+        return LoadIndexedNode.create(graph.getAssumptions(), array, index, kind, metaAccess, constantReflection);
+    }
+
+    protected void genStoreIndexed(ValueNode array, ValueNode index, JavaKind kind, ValueNode value) {
+        add(new StoreIndexedNode(array, index, kind, value));
+    }
+
+    protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) {
+        return AddNode.create(x, y);
+    }
+
+    protected ValueNode genIntegerSub(ValueNode x, ValueNode y) {
+        return SubNode.create(x, y);
+    }
+
+    protected ValueNode genIntegerMul(ValueNode x, ValueNode y) {
+        return MulNode.create(x, y);
+    }
+
+    protected ValueNode genFloatAdd(ValueNode x, ValueNode y) {
+        return AddNode.create(x, y);
+    }
+
+    protected ValueNode genFloatSub(ValueNode x, ValueNode y) {
+        return SubNode.create(x, y);
+    }
+
+    protected ValueNode genFloatMul(ValueNode x, ValueNode y) {
+        return MulNode.create(x, y);
+    }
+
+    protected ValueNode genFloatDiv(ValueNode x, ValueNode y) {
+        return DivNode.create(x, y);
+    }
+
+    protected ValueNode genFloatRem(ValueNode x, ValueNode y) {
+        return new RemNode(x, y);
+    }
+
+    protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) {
+        return new SignedDivNode(x, y);
+    }
+
+    protected ValueNode genIntegerRem(ValueNode x, ValueNode y) {
+        return new SignedRemNode(x, y);
+    }
+
+    protected ValueNode genNegateOp(ValueNode x) {
+        return (new NegateNode(x));
+    }
+
+    protected ValueNode genLeftShift(ValueNode x, ValueNode y) {
+        return new LeftShiftNode(x, y);
+    }
+
+    protected ValueNode genRightShift(ValueNode x, ValueNode y) {
+        return new RightShiftNode(x, y);
+    }
+
+    protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) {
+        return new UnsignedRightShiftNode(x, y);
+    }
+
+    protected ValueNode genAnd(ValueNode x, ValueNode y) {
+        return AndNode.create(x, y);
+    }
+
+    protected ValueNode genOr(ValueNode x, ValueNode y) {
+        return OrNode.create(x, y);
+    }
+
+    protected ValueNode genXor(ValueNode x, ValueNode y) {
+        return XorNode.create(x, y);
+    }
+
+    protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
+        return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
+    }
+
+    protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
+        return FloatConvertNode.create(op, input);
+    }
+
+    protected ValueNode genNarrow(ValueNode input, int bitCount) {
+        return NarrowNode.create(input, bitCount);
+    }
+
+    protected ValueNode genSignExtend(ValueNode input, int bitCount) {
+        return SignExtendNode.create(input, bitCount);
+    }
+
+    protected ValueNode genZeroExtend(ValueNode input, int bitCount) {
+        return ZeroExtendNode.create(input, bitCount);
+    }
+
+    protected void genGoto() {
+        ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
+        if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            int targetBci = currentBlock.getSuccessor(0).startBci;
+            profilingPlugin.profileGoto(this, method, bci(), targetBci, stateBefore);
+        }
+        appendGoto(currentBlock.getSuccessor(0));
+        assert currentBlock.numNormalSuccessors() == 1;
+    }
+
+    protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
+        return ObjectEqualsNode.create(x, y, constantReflection);
+    }
+
+    protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
+        return IntegerEqualsNode.create(x, y, constantReflection);
+    }
+
+    protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
+        return IntegerLessThanNode.create(x, y, constantReflection);
+    }
+
+    protected ValueNode genUnique(ValueNode x) {
+        return graph.addOrUniqueWithInputs(x);
+    }
+
+    protected LogicNode genUnique(LogicNode x) {
+        return graph.addOrUniqueWithInputs(x);
+    }
+
+    protected ValueNode genIfNode(LogicNode condition, FixedNode falseSuccessor, FixedNode trueSuccessor, double d) {
+        return new IfNode(condition, falseSuccessor, trueSuccessor, d);
+    }
+
+    protected void genThrow() {
+        genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
+
+        ValueNode exception = frameState.pop(JavaKind.Object);
+        FixedGuardNode nullCheck = append(new FixedGuardNode(graph.unique(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
+        PiNode nonNullException = graph.unique(new PiNode(exception, exception.stamp().join(objectNonNull()), nullCheck));
+        lastInstr.setNext(handleException(nonNullException, bci()));
+    }
+
+    protected LogicNode createInstanceOf(TypeReference type, ValueNode object) {
+        return InstanceOfNode.create(type, object);
+    }
+
+    protected AnchoringNode createAnchor(JavaTypeProfile profile) {
+        if (profile == null || profile.getNotRecordedProbability() > 0.0) {
+            return null;
+        } else {
+            return append(new ValueAnchorNode(null));
+        }
+    }
+
+    protected LogicNode createInstanceOf(TypeReference type, ValueNode object, JavaTypeProfile profile) {
+        return InstanceOfNode.create(type, object, profile, createAnchor(profile));
+    }
+
+    protected LogicNode createInstanceOfAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile) {
+        return InstanceOfNode.createAllowNull(type, object, profile, createAnchor(profile));
+    }
+
+    protected ValueNode genConditional(ValueNode x) {
+        return new ConditionalNode((LogicNode) x);
+    }
+
+    protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
+        return new NewInstanceNode(type, fillContents);
+    }
+
+    protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+        return new NewArrayNode(elementType, length, fillContents);
+    }
+
+    protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, ValueNode[] dimensions) {
+        return new NewMultiArrayNode(type, dimensions);
+    }
+
+    protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) {
+        StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false);
+        if (stamp == null) {
+            return LoadFieldNode.create(this.graph.getAssumptions(), receiver, field);
+        } else {
+            return LoadFieldNode.createOverrideStamp(stamp, receiver, field);
+        }
+    }
+
+    protected ValueNode emitExplicitNullCheck(ValueNode receiver) {
+        if (StampTool.isPointerNonNull(receiver.stamp())) {
+            return receiver;
+        }
+        BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
+        AbstractBeginNode falseSucc = graph.add(new BeginNode());
+        PiNode nonNullReceiver = graph.unique(new PiNode(receiver, receiver.stamp().join(objectNonNull()), falseSucc));
+        append(new IfNode(graph.unique(IsNullNode.create(receiver)), exception, falseSucc, 0.01));
+        lastInstr = falseSucc;
+
+        exception.setStateAfter(createFrameState(bci(), exception));
+        exception.setNext(handleException(exception, bci()));
+        return nonNullReceiver;
+    }
+
+    protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
+        AbstractBeginNode trueSucc = graph.add(new BeginNode());
+        BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
+        append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
+        lastInstr = trueSucc;
+
+        exception.setStateAfter(createFrameState(bci(), exception));
+        exception.setNext(handleException(exception, bci()));
+    }
+
+    protected ValueNode genArrayLength(ValueNode x) {
+        return ArrayLengthNode.create(x, constantReflection);
+    }
+
+    protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
+        StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value);
+        append(storeFieldNode);
+        storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode));
+    }
+
+    /**
+     * Ensure that concrete classes are at least linked before generating an invoke. Interfaces may
+     * never be linked so simply return true for them.
+     *
+     * @param target
+     * @return true if the declared holder is an interface or is linked
+     */
+    private static boolean callTargetIsResolved(JavaMethod target) {
+        if (target instanceof ResolvedJavaMethod) {
+            ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
+            ResolvedJavaType resolvedType = resolvedTarget.getDeclaringClass();
+            return resolvedType.isInterface() || resolvedType.isLinked();
+        }
+        return false;
+    }
+
+    protected void genInvokeStatic(JavaMethod target) {
+        if (callTargetIsResolved(target)) {
+            ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
+            ResolvedJavaType holder = resolvedTarget.getDeclaringClass();
+            if (!holder.isInitialized() && ResolveClassBeforeStaticInvoke.getValue()) {
+                handleUnresolvedInvoke(target, InvokeKind.Static);
+            } else {
+                ValueNode classInit = null;
+                ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+                if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedTarget.getDeclaringClass())) {
+                    FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                    classInit = classInitializationPlugin.apply(this, resolvedTarget.getDeclaringClass(), stateBefore);
+                }
+
+                ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(false));
+                Invoke invoke = appendInvoke(InvokeKind.Static, resolvedTarget, args);
+                if (invoke != null) {
+                    invoke.setClassInit(classInit);
+                }
+            }
+        } else {
+            handleUnresolvedInvoke(target, InvokeKind.Static);
+        }
+    }
+
+    protected void genInvokeInterface(JavaMethod target) {
+        if (callTargetIsResolved(target)) {
+            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
+            appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args);
+        } else {
+            handleUnresolvedInvoke(target, InvokeKind.Interface);
+        }
+    }
+
+    protected void genInvokeDynamic(JavaMethod target) {
+        if (target instanceof ResolvedJavaMethod) {
+            JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
+            if (appendix != null) {
+                frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
+            }
+            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false));
+            appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
+        } else {
+            handleUnresolvedInvoke(target, InvokeKind.Static);
+        }
+    }
+
+    protected void genInvokeVirtual(JavaMethod target) {
+        if (callTargetIsResolved(target)) {
+            /*
+             * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...)
+             * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see
+             * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic
+             */
+            boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
+            JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
+            if (appendix != null) {
+                frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
+            }
+            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
+            if (hasReceiver) {
+                appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
+            } else {
+                appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
+            }
+        } else {
+            handleUnresolvedInvoke(target, InvokeKind.Virtual);
+        }
+
+    }
+
+    protected void genInvokeSpecial(JavaMethod target) {
+        if (callTargetIsResolved(target)) {
+            assert target != null;
+            assert target.getSignature() != null;
+            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
+            appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args);
+        } else {
+            handleUnresolvedInvoke(target, InvokeKind.Special);
+        }
+    }
+
+    private InvokeKind currentInvokeKind;
+    private JavaType currentInvokeReturnType;
+    protected FrameStateBuilder frameState;
+    protected BciBlock currentBlock;
+    protected final BytecodeStream stream;
+    protected final GraphBuilderConfiguration graphBuilderConfig;
+    protected final ResolvedJavaMethod method;
+    protected final Bytecode code;
+    protected final BytecodeProvider bytecodeProvider;
+    protected final ProfilingInfo profilingInfo;
+    protected final OptimisticOptimizations optimisticOpts;
+    protected final ConstantPool constantPool;
+    protected final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+    private final ConstantFieldProvider constantFieldProvider;
+    private final StampProvider stampProvider;
+    protected final IntrinsicContext intrinsicContext;
+
+    @Override
+    public InvokeKind getInvokeKind() {
+        return currentInvokeKind;
+    }
+
+    @Override
+    public JavaType getInvokeReturnType() {
+        return currentInvokeReturnType;
+    }
+
+    private boolean forceInliningEverything;
+
+    @Override
+    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) {
+        boolean previous = forceInliningEverything;
+        forceInliningEverything = previous || inlineEverything;
+        try {
+            appendInvoke(invokeKind, targetMethod, args);
+        } finally {
+            forceInliningEverything = previous;
+        }
+    }
+
+    private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
+        ResolvedJavaMethod targetMethod = initialTargetMethod;
+        InvokeKind invokeKind = initialInvokeKind;
+        if (initialInvokeKind.isIndirect()) {
+            ResolvedJavaType contextType = this.frameState.getMethod().getDeclaringClass();
+            ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, contextType);
+            if (specialCallTarget != null) {
+                invokeKind = InvokeKind.Special;
+                targetMethod = specialCallTarget;
+            }
+        }
+
+        JavaKind resultType = targetMethod.getSignature().getReturnKind();
+        if (DeoptALot.getValue()) {
+            append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
+            frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph));
+            return null;
+        }
+
+        JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass());
+        if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) {
+            returnType = returnType.resolve(targetMethod.getDeclaringClass());
+        }
+        if (invokeKind.hasReceiver()) {
+            args[0] = emitExplicitExceptions(args[0], null);
+
+            if (args[0].isNullConstant()) {
+                append(new DeoptimizeNode(InvalidateRecompile, NullCheckException));
+                return null;
+            }
+        }
+
+        InlineInfo inlineInfo = null;
+        try {
+            currentInvokeReturnType = returnType;
+            currentInvokeKind = invokeKind;
+            if (tryNodePluginForInvocation(args, targetMethod)) {
+                if (TraceParserPlugins.getValue()) {
+                    traceWithContext("used node plugin for %s", targetMethod.format("%h.%n(%p)"));
+                }
+                return null;
+            }
+
+            if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue() && !GeneratePIC.getValue())) {
+                if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                    }
+                    return null;
+                }
+            }
+            if (invokeKind.isDirect()) {
+
+                inlineInfo = tryInline(args, targetMethod);
+                if (inlineInfo == SUCCESSFULLY_INLINED) {
+                    return null;
+                }
+            }
+        } finally {
+            currentInvokeReturnType = null;
+            currentInvokeKind = null;
+        }
+
+        JavaTypeProfile profile = null;
+        if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) {
+            profile = profilingInfo.getTypeProfile(bci());
+        }
+        return createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+    }
+
+    protected Invoke createNonInlinedInvoke(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind,
+                    JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
+
+        StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
+        if (returnStamp == null) {
+            returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+        }
+
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile));
+
+        Invoke invoke;
+        if (omitInvokeExceptionEdge(callTarget, inlineInfo)) {
+            invoke = createInvoke(callTarget, resultType);
+        } else {
+            invoke = createInvokeWithException(callTarget, resultType);
+            AbstractBeginNode beginNode = graph.add(new KillingBeginNode(LocationIdentity.any()));
+            invoke.setNext(beginNode);
+            lastInstr = beginNode;
+        }
+
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            plugin.notifyNotInlined(this, targetMethod, invoke);
+        }
+
+        return invoke;
+    }
+
+    /**
+     * If the method returns true, the invocation of the given {@link MethodCallTargetNode call
+     * target} does not need an exception edge.
+     *
+     * @param callTarget The call target.
+     */
+    protected boolean omitInvokeExceptionEdge(MethodCallTargetNode callTarget, InlineInfo lastInlineInfo) {
+        if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) {
+            return false;
+        } else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) {
+            return true;
+        } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.CheckAll) {
+            return false;
+        } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) {
+            return true;
+        } else {
+            assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile;
+            // be conservative if information was not recorded (could result in endless
+            // recompiles otherwise)
+            return (!StressInvokeWithExceptionNode.getValue() && optimisticOpts.useExceptionProbability() && profilingInfo != null && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE);
+        }
+    }
+
+    /**
+     * Contains all the assertion checking logic around the application of an
+     * {@link InvocationPlugin}. This class is only loaded when assertions are enabled.
+     */
+    class InvocationPluginAssertions {
+        final InvocationPlugin plugin;
+        final ValueNode[] args;
+        final ResolvedJavaMethod targetMethod;
+        final JavaKind resultType;
+        final int beforeStackSize;
+        final boolean needsNullCheck;
+        final int nodeCount;
+        final Mark mark;
+
+        InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) {
+            guarantee(assertionsEnabled(), "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName());
+            this.plugin = plugin;
+            this.targetMethod = targetMethod;
+            this.args = args;
+            this.resultType = resultType;
+            this.beforeStackSize = frameState.stackSize();
+            this.needsNullCheck = !targetMethod.isStatic() && args[0].getStackKind() == JavaKind.Object && !StampTool.isPointerNonNull(args[0].stamp());
+            this.nodeCount = graph.getNodeCount();
+            this.mark = graph.getMark();
+        }
+
+        String error(String format, Object... a) {
+            return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess));
+        }
+
+        boolean check(boolean pluginResult) {
+            if (pluginResult == true) {
+                int expectedStackSize = beforeStackSize + resultType.getSlotCount();
+                assert expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize());
+                NodeIterable<Node> newNodes = graph.getNewNodes(mark);
+                assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]);
+                for (Node n : newNodes) {
+                    if (n instanceof StateSplit) {
+                        StateSplit stateSplit = (StateSplit) n;
+                        assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s",
+                                        StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit);
+                    }
+                }
+                try {
+                    graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes);
+                } catch (Throwable t) {
+                    throw new AssertionError(error("Error in plugin"), t);
+                }
+            } else {
+                assert nodeCount == graph.getNodeCount() : error("plugin that returns false must not create new nodes");
+                assert beforeStackSize == frameState.stackSize() : error("plugin that returns false must not modify the stack");
+            }
+            return true;
+        }
+    }
+
+    protected static class IntrinsicGuard {
+        final FixedWithNextNode lastInstr;
+        final Mark mark;
+        final AbstractBeginNode nonIntrinsicBranch;
+        final ValueNode receiver;
+        final JavaTypeProfile profile;
+
+        public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark, AbstractBeginNode nonIntrinsicBranch, JavaTypeProfile profile) {
+            this.lastInstr = lastInstr;
+            this.receiver = receiver;
+            this.mark = mark;
+            this.nonIntrinsicBranch = nonIntrinsicBranch;
+            this.profile = profile;
+        }
+    }
+
+    /**
+     * Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod}
+     * and not another method that overrides it. This should only be called if there is an intrinsic
+     * (i.e., an {@link InvocationPlugin}) for {@code targetMethod} and the invocation is indirect.
+     *
+     * The control flow woven around the intrinsic is as follows:
+     *
+     * <pre>
+     *  if (LoadMethod(LoadHub(receiver)) == targetMethod) {
+     *       <intrinsic for targetMethod>
+     *  } else {
+     *       <virtual call to targetMethod>
+     *  }
+     * </pre>
+     *
+     * The {@code else} branch is woven by {@link #afterInvocationPluginExecution}.
+     *
+     * @return {@code null} if the intrinsic cannot be used otherwise an object to be used by
+     *         {@link #afterInvocationPluginExecution} to weave code for the non-intrinsic branch
+     */
+    protected IntrinsicGuard guardIntrinsic(ValueNode[] args, ResolvedJavaMethod targetMethod, InvocationPluginReceiver pluginReceiver) {
+        ValueNode intrinsicReceiver = args[0];
+        ResolvedJavaType receiverType = StampTool.typeOrNull(intrinsicReceiver);
+        if (receiverType == null) {
+            // The verifier guarantees it to be at least type declaring targetMethod
+            receiverType = targetMethod.getDeclaringClass();
+        }
+        ResolvedJavaMethod resolvedMethod = receiverType.resolveMethod(targetMethod, method.getDeclaringClass());
+        if (resolvedMethod == null || resolvedMethod == targetMethod) {
+            assert resolvedMethod == null || targetMethod.getDeclaringClass().isAssignableFrom(resolvedMethod.getDeclaringClass());
+            Mark mark = graph.getMark();
+            FixedWithNextNode currentLastInstr = lastInstr;
+            ValueNode nonNullReceiver = pluginReceiver.get();
+            Stamp methodStamp = stampProvider.createMethodStamp();
+            LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
+            LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
+            ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
+            LogicNode compare = graph.unique(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection));
+
+            JavaTypeProfile profile = null;
+            if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) {
+                profile = profilingInfo.getTypeProfile(bci());
+                if (profile != null) {
+                    JavaTypeProfile newProfile = adjustProfileForInvocationPlugin(profile, targetMethod);
+                    if (newProfile != profile) {
+                        if (newProfile.getTypes().length == 0) {
+                            // All profiled types select the intrinsic so
+                            // emit a fixed guard instead of a if-then-else.
+                            lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false));
+                            return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null);
+                        }
+                    } else {
+                        // No profiled types select the intrinsic so emit a virtual call
+                        return null;
+                    }
+                    profile = newProfile;
+                }
+            }
+
+            AbstractBeginNode intrinsicBranch = graph.add(new BeginNode());
+            AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode());
+            append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, 0.01));
+            lastInstr = intrinsicBranch;
+            return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile);
+        } else {
+            // Receiver selects an overriding method so emit a virtual call
+            return null;
+        }
+    }
+
+    /**
+     * Adjusts the profile for an indirect invocation of a virtual method for which there is an
+     * intrinsic. The adjustment made by this method is to remove all types from the profile that do
+     * not override {@code targetMethod}.
+     *
+     * @param profile the profile to adjust
+     * @param targetMethod the virtual method for which there is an intrinsic
+     * @return the adjusted profile or the original {@code profile} object if no adjustment was made
+     */
+    protected JavaTypeProfile adjustProfileForInvocationPlugin(JavaTypeProfile profile, ResolvedJavaMethod targetMethod) {
+        if (profile.getTypes().length > 0) {
+            List<ProfiledType> retained = new ArrayList<>();
+            double notRecordedProbability = profile.getNotRecordedProbability();
+            for (ProfiledType ptype : profile.getTypes()) {
+                if (!ptype.getType().resolveMethod(targetMethod, method.getDeclaringClass()).equals(targetMethod)) {
+                    retained.add(ptype);
+                } else {
+                    notRecordedProbability += ptype.getProbability();
+                }
+            }
+            if (!retained.isEmpty()) {
+                if (retained.size() != profile.getTypes().length) {
+                    return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, retained.toArray(new ProfiledType[retained.size()]));
+                }
+            } else {
+                return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, new ProfiledType[0]);
+            }
+        }
+        return profile;
+    }
+
+    /**
+     * Performs any action required after execution of an invocation plugin. This includes
+     * {@linkplain InvocationPluginAssertions#check(boolean) checking} invocation plugin invariants
+     * as well as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
+     * {@code guard != null}.
+     */
+    protected void afterInvocationPluginExecution(boolean pluginResult, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
+                    InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
+        assert assertions.check(pluginResult);
+        if (intrinsicGuard != null) {
+            if (pluginResult) {
+                if (intrinsicGuard.nonIntrinsicBranch != null) {
+                    // Intrinsic emitted: emit a virtual call to the target method and
+                    // merge it with the intrinsic branch
+                    EndNode intrinsicEnd = append(new EndNode());
+
+                    FrameStateBuilder intrinsicState = null;
+                    FrameStateBuilder nonIntrinisicState = null;
+                    if (resultType != JavaKind.Void) {
+                        intrinsicState = frameState.copy();
+                        frameState.pop(resultType);
+                        nonIntrinisicState = frameState;
+                    }
+
+                    lastInstr = intrinsicGuard.nonIntrinsicBranch;
+                    createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
+
+                    EndNode nonIntrinsicEnd = append(new EndNode());
+                    AbstractMergeNode mergeNode = graph.add(new MergeNode());
+
+                    mergeNode.addForwardEnd(intrinsicEnd);
+                    if (intrinsicState != null) {
+                        intrinsicState.merge(mergeNode, nonIntrinisicState);
+                        frameState = intrinsicState;
+                    }
+                    mergeNode.addForwardEnd(nonIntrinsicEnd);
+                    mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode));
+
+                    lastInstr = mergeNode;
+                }
+            } else {
+                // Intrinsic was not applied: remove intrinsic guard
+                // and restore the original receiver node in the arguments array
+                for (Node node : graph.getNewNodes(intrinsicGuard.mark)) {
+                    GraphUtil.killCFG(node);
+                }
+                lastInstr = intrinsicGuard.lastInstr;
+                args[0] = intrinsicGuard.receiver;
+            }
+        }
+    }
+
+    protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
+        InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
+        if (plugin != null) {
+
+            if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
+                // Self recursive intrinsic means the original
+                // method should be called.
+                assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
+                return false;
+            }
+
+            InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args);
+
+            IntrinsicGuard intrinsicGuard = null;
+            if (invokeKind.isIndirect()) {
+                intrinsicGuard = guardIntrinsic(args, targetMethod, pluginReceiver);
+                if (intrinsicGuard == null) {
+                    return false;
+                } else if (intrinsicGuard.nonIntrinsicBranch == null) {
+                    assert lastInstr instanceof FixedGuardNode;
+                }
+            }
+
+            InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
+            if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
+                afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+                return true;
+            } else {
+                afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+            }
+        }
+        return false;
+    }
+
+    private boolean tryNodePluginForInvocation(ValueNode[] args, ResolvedJavaMethod targetMethod) {
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleInvoke(this, targetMethod, args)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static final InlineInfo SUCCESSFULLY_INLINED = InlineInfo.createStandardInlineInfo(null);
+
+    /**
+     * Try to inline a method. If the method was inlined, returns {@link #SUCCESSFULLY_INLINED}.
+     * Otherwise, it returns the {@link InlineInfo} that lead to the decision to not inline it, or
+     * {@code null} if there is no {@link InlineInfo} for this method.
+     */
+    private InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) {
+        boolean canBeInlined = forceInliningEverything || parsingIntrinsic() || targetMethod.canBeInlined();
+        if (!canBeInlined) {
+            return null;
+        }
+
+        if (forceInliningEverything) {
+            if (inline(targetMethod, targetMethod, null, args)) {
+                return SUCCESSFULLY_INLINED;
+            } else {
+                return null;
+            }
+        }
+
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            InlineInfo inlineInfo = plugin.shouldInlineInvoke(this, targetMethod, args);
+            if (inlineInfo != null) {
+                if (inlineInfo.getMethodToInline() != null) {
+                    if (inline(targetMethod, inlineInfo.getMethodToInline(), inlineInfo.getIntrinsicBytecodeProvider(), args)) {
+                        return SUCCESSFULLY_INLINED;
+                    }
+                }
+                /* Do not inline, and do not ask the remaining plugins. */
+                return inlineInfo;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean intrinsify(BytecodeProvider intrinsicBytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
+        if (receiver != null) {
+            receiver.get();
+        }
+        boolean res = inline(targetMethod, substitute, intrinsicBytecodeProvider, args);
+        assert res : "failed to inline " + substitute;
+        return res;
+    }
+
+    private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) {
+        if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) {
+            if (targetMethod.equals(inlinedMethod)) {
+                traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
+            } else {
+                traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
+            }
+        }
+        IntrinsicContext intrinsic = this.intrinsicContext;
+        if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) {
+            if (intrinsic.isCompilationRoot()) {
+                // A root compiled intrinsic needs to deoptimize
+                // if the slow path is taken. During frame state
+                // assignment, the deopt node will get its stateBefore
+                // from the start node of the intrinsic
+                append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
+                printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)");
+                return true;
+            } else {
+                // Otherwise inline the original method. Any frame state created
+                // during the inlining will exclude frame(s) in the
+                // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                if (intrinsic.getOriginalMethod().isNative()) {
+                    printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)");
+                    return false;
+                }
+                printInlining(targetMethod, inlinedMethod, true, "inline intrinsic (bytecode parsing)");
+                parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
+                return true;
+            }
+        } else {
+            boolean isIntrinsic = intrinsicBytecodeProvider != null;
+            if (intrinsic == null && isIntrinsic) {
+                assert !inlinedMethod.equals(targetMethod);
+                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING);
+            }
+            if (inlinedMethod.hasBytecodes()) {
+                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+                    plugin.notifyBeforeInline(inlinedMethod);
+                }
+                printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)");
+                parseAndInlineCallee(inlinedMethod, args, intrinsic);
+                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+                    plugin.notifyAfterInline(inlinedMethod);
+                }
+            } else {
+                printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) {
+        if (GraalOptions.HotSpotPrintInlining.getValue()) {
+            if (targetMethod.equals(inlinedMethod)) {
+                Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s", msg);
+            } else {
+                Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s intrinsic for %s", msg, targetMethod.format("%h.%n(%p)"));
+            }
+        }
+    }
+
+    /**
+     * Prints a line to {@link TTY} with a prefix indicating the current parse context. The prefix
+     * is of the form:
+     *
+     * <pre>
+     * {SPACE * n} {name of method being parsed} "(" {file name} ":" {line number} ")"
+     * </pre>
+     *
+     * where {@code n} is the current inlining depth.
+     *
+     * @param format a format string
+     * @param args arguments to the format string
+     */
+
+    protected void traceWithContext(String format, Object... args) {
+        StackTraceElement where = code.asStackTraceElement(bci());
+        TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
+                        format(format, args)));
+    }
+
+    protected BytecodeParserError asParserError(Throwable e) {
+        if (e instanceof BytecodeParserError) {
+            return (BytecodeParserError) e;
+        }
+        BytecodeParser bp = this;
+        BytecodeParserError res = new BytecodeParserError(e);
+        while (bp != null) {
+            res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci()));
+            bp = bp.parent;
+        }
+        return res;
+    }
+
+    @SuppressWarnings("try")
+    protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
+        try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) {
+
+            BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
+            FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph);
+            if (!targetMethod.isStatic()) {
+                args[0] = nullCheckedValue(args[0]);
+            }
+            startFrameState.initializeFromArgumentsArray(args);
+            parser.build(this.lastInstr, startFrameState);
+
+            FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
+            this.lastInstr = calleeBeforeReturnNode;
+            JavaKind calleeReturnKind = targetMethod.getSignature().getReturnKind();
+            if (calleeBeforeReturnNode != null) {
+                ValueNode calleeReturnValue = parser.getReturnValue();
+                if (calleeReturnValue != null) {
+                    frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue);
+                }
+            }
+
+            FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
+            if (calleeBeforeUnwindNode != null) {
+                ValueNode calleeUnwindValue = parser.getUnwindValue();
+                assert calleeUnwindValue != null;
+                calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+            }
+        }
+    }
+
+    public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile);
+    }
+
+    protected InvokeNode createInvoke(CallTargetNode callTarget, JavaKind resultType) {
+        InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
+        frameState.pushReturn(resultType, invoke);
+        invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
+        return invoke;
+    }
+
+    protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, JavaKind resultType) {
+        if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
+            /*
+             * Clear non-live locals early so that the exception handler entry gets the cleared
+             * state.
+             */
+            frameState.clearNonLiveLocals(currentBlock, liveness, false);
+        }
+
+        AbstractBeginNode exceptionEdge = handleException(null, bci());
+        InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
+        frameState.pushReturn(resultType, invoke);
+        invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
+        return invoke;
+    }
+
+    protected void genReturn(ValueNode returnVal, JavaKind returnKind) {
+        if (parsingIntrinsic() && returnVal != null) {
+            if (returnVal instanceof StateSplit) {
+                StateSplit stateSplit = (StateSplit) returnVal;
+                FrameState stateAfter = stateSplit.stateAfter();
+                if (stateSplit.hasSideEffect()) {
+                    assert stateSplit != null;
+                    if (stateAfter.bci == BytecodeFrame.AFTER_BCI) {
+                        assert stateAfter.usages().count() == 1;
+                        assert stateAfter.usages().first() == stateSplit;
+                        stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal)));
+                        GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                    } else {
+                        /*
+                         * This must be the return value from within a partial intrinsification.
+                         */
+                        assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci);
+                    }
+                } else {
+                    assert stateAfter == null;
+                }
+            }
+        }
+        if (parent == null) {
+            frameState.setRethrowException(false);
+            frameState.clearStack();
+            beforeReturn(returnVal, returnKind);
+            append(new ReturnNode(returnVal));
+        } else {
+            if (blockMap.getReturnCount() == 1 || !controlFlowSplit) {
+                // There is only a single return.
+                beforeReturn(returnVal, returnKind);
+                this.returnValue = returnVal;
+                this.beforeReturnNode = this.lastInstr;
+                this.lastInstr = null;
+            } else {
+                frameState.setRethrowException(false);
+                frameState.clearStack();
+                if (returnVal != null) {
+                    frameState.push(returnKind, returnVal);
+                }
+                assert blockMap.getReturnCount() > 1;
+                appendGoto(blockMap.getReturnBlock());
+            }
+        }
+    }
+
+    private void beforeReturn(ValueNode x, JavaKind kind) {
+        if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
+            /*
+             * Get the receiver from the initial state since bytecode rewriting could do arbitrary
+             * things to the state of the locals.
+             */
+            ValueNode receiver = graph.start().stateAfter().localAt(0);
+            assert receiver != null && receiver.getStackKind() == JavaKind.Object;
+            if (RegisterFinalizerNode.mayHaveFinalizer(receiver, graph.getAssumptions())) {
+                append(new RegisterFinalizerNode(receiver));
+            }
+        }
+        genInfoPointNode(InfopointReason.METHOD_END, x);
+        if (finalBarrierRequired) {
+            assert originalReceiver != null;
+            append(new FinalFieldBarrierNode(originalReceiver));
+        }
+        synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x, kind);
+    }
+
+    protected MonitorEnterNode createMonitorEnterNode(ValueNode x, MonitorIdNode monitorId) {
+        return new MonitorEnterNode(x, monitorId);
+    }
+
+    protected void genMonitorEnter(ValueNode x, int bci) {
+        MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth(true)));
+        MonitorEnterNode monitorEnter = append(createMonitorEnterNode(x, monitorId));
+        frameState.pushLock(x, monitorId);
+        monitorEnter.setStateAfter(createFrameState(bci, monitorEnter));
+    }
+
+    protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) {
+        if (frameState.lockDepth(false) == 0) {
+            throw bailout("unbalanced monitors: too many exits");
+        }
+        MonitorIdNode monitorId = frameState.peekMonitorId();
+        ValueNode lockedObject = frameState.popLock();
+        if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
+            throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)));
+        }
+        MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue));
+        monitorExit.setStateAfter(createFrameState(bci, monitorExit));
+    }
+
+    protected void genJsr(int dest) {
+        BciBlock successor = currentBlock.getJsrSuccessor();
+        assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci();
+        JsrScope scope = currentBlock.getJsrScope();
+        int nextBci = getStream().nextBCI();
+        if (!successor.getJsrScope().pop().equals(scope)) {
+            throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)");
+        }
+        if (successor.getJsrScope().nextReturnAddress() != nextBci) {
+            throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)");
+        }
+        ConstantNode nextBciNode = getJsrConstant(nextBci);
+        frameState.push(JavaKind.Object, nextBciNode);
+        appendGoto(successor);
+    }
+
+    protected void genRet(int localIndex) {
+        BciBlock successor = currentBlock.getRetSuccessor();
+        ValueNode local = frameState.loadLocal(localIndex, JavaKind.Object);
+        JsrScope scope = currentBlock.getJsrScope();
+        int retAddress = scope.nextReturnAddress();
+        ConstantNode returnBciNode = getJsrConstant(retAddress);
+        LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflection);
+        guard = graph.unique(guard);
+        append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile));
+        if (!successor.getJsrScope().equals(scope.pop())) {
+            throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
+        }
+        appendGoto(successor);
+    }
+
+    private ConstantNode getJsrConstant(long bci) {
+        JavaConstant nextBciConstant = new RawConstant(bci);
+        Stamp nextBciStamp = StampFactory.forConstant(nextBciConstant);
+        ConstantNode nextBciNode = new ConstantNode(nextBciConstant, nextBciStamp);
+        return graph.unique(nextBciNode);
+    }
+
+    protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+        if (value.isConstant()) {
+            JavaConstant constant = (JavaConstant) value.asConstant();
+            int constantValue = constant.asInt();
+            for (int i = 0; i < keys.length; ++i) {
+                if (keys[i] == constantValue) {
+                    appendGoto(actualSuccessors.get(keySuccessors[i]));
+                    return;
+                }
+            }
+            appendGoto(actualSuccessors.get(keySuccessors[keys.length]));
+        } else {
+            this.controlFlowSplit = true;
+            double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities);
+            IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
+            for (int i = 0; i < actualSuccessors.size(); i++) {
+                switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState));
+            }
+        }
+    }
+
+    /**
+     * Helper function that sums up the probabilities of all keys that lead to a specific successor.
+     *
+     * @return an array of size successorCount with the accumulated probability for each successor.
+     */
+    private static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
+        double[] probability = new double[successorCount];
+        for (int i = 0; i < keySuccessors.length; i++) {
+            probability[keySuccessors[i]] += keyProbabilities[i];
+        }
+        return probability;
+    }
+
+    protected ConstantNode appendConstant(JavaConstant constant) {
+        assert constant != null;
+        return ConstantNode.forConstant(constant, metaAccess, graph);
+    }
+
+    @Override
+    public <T extends ValueNode> T append(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUnique(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    @Override
+    public <T extends ValueNode> T recursiveAppend(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUniqueWithInputs(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    private <T extends ValueNode> void updateLastInstruction(T v) {
+        if (UseGraalInstrumentation.getValue()) {
+            // resolve instrumentation target
+            if (v instanceof InstrumentationBeginNode) {
+                InstrumentationBeginNode begin = (InstrumentationBeginNode) v;
+                if (!begin.isAnchored() && lastBCI != -1) {
+                    int currentBCI = stream.currentBCI();
+                    // temporarily set the bytecode stream to lastBCI
+                    stream.setBCI(lastBCI);
+                    // The instrumentation should be associated with the predecessor. In case of the
+                    // predecessor being optimized away, e.g., inlining, we should not set the
+                    // target.
+                    if (stream.nextBCI() == currentBCI) {
+                        begin.setTarget(lastInstr);
+                    }
+                    // restore the current BCI
+                    stream.setBCI(currentBCI);
+                }
+            }
+        }
+        if (v instanceof FixedNode) {
+            FixedNode fixedNode = (FixedNode) v;
+            lastInstr.setNext(fixedNode);
+            if (fixedNode instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                lastInstr = fixedWithNextNode;
+                lastBCI = stream.currentBCI();
+            } else {
+                lastInstr = null;
+                lastBCI = -1;
+            }
+        }
+    }
+
+    private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) {
+        if (currentBlock != null) {
+            long exits = currentBlock.loops & ~targetBlock.loops;
+            if (exits != 0) {
+                LoopExitNode firstLoopExit = null;
+                LoopExitNode lastLoopExit = null;
+
+                int pos = 0;
+                ArrayList<BciBlock> exitLoops = new ArrayList<>(Long.bitCount(exits));
+                do {
+                    long lMask = 1L << pos;
+                    if ((exits & lMask) != 0) {
+                        exitLoops.add(blockMap.getLoopHeader(pos));
+                        exits &= ~lMask;
+                    }
+                    pos++;
+                } while (exits != 0);
+
+                Collections.sort(exitLoops, new Comparator<BciBlock>() {
+
+                    @Override
+                    public int compare(BciBlock o1, BciBlock o2) {
+                        return Long.bitCount(o2.loops) - Long.bitCount(o1.loops);
+                    }
+                });
+
+                int bci = targetBlock.startBci;
+                if (targetBlock instanceof ExceptionDispatchBlock) {
+                    bci = ((ExceptionDispatchBlock) targetBlock).deoptBci;
+                }
+                FrameStateBuilder newState = state.copy();
+                for (BciBlock loop : exitLoops) {
+                    LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop);
+                    LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin));
+                    if (lastLoopExit != null) {
+                        lastLoopExit.setNext(loopExit);
+                    }
+                    if (firstLoopExit == null) {
+                        firstLoopExit = loopExit;
+                    }
+                    lastLoopExit = loopExit;
+                    Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop);
+                    newState.clearNonLiveLocals(targetBlock, liveness, true);
+                    newState.insertLoopProxies(loopExit, getEntryState(loop));
+                    loopExit.setStateAfter(newState.create(bci, loopExit));
+                }
+
+                lastLoopExit.setNext(target);
+                return new Target(firstLoopExit, newState);
+            }
+        }
+        return new Target(target, state);
+    }
+
+    private FrameStateBuilder getEntryState(BciBlock block) {
+        return entryStateArray[block.id];
+    }
+
+    private void setEntryState(BciBlock block, FrameStateBuilder entryState) {
+        this.entryStateArray[block.id] = entryState;
+    }
+
+    private void setFirstInstruction(BciBlock block, FixedWithNextNode firstInstruction) {
+        this.firstInstructionArray[block.id] = firstInstruction;
+    }
+
+    private FixedWithNextNode getFirstInstruction(BciBlock block) {
+        return firstInstructionArray[block.id];
+    }
+
+    private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
+        assert probability >= 0 && probability <= 1.01 : probability;
+        if (isNeverExecutedCode(probability)) {
+            return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
+        } else {
+            assert block != null;
+            return createTarget(block, stateAfter);
+        }
+    }
+
+    private FixedNode createTarget(BciBlock block, FrameStateBuilder state) {
+        return createTarget(block, state, false, false);
+    }
+
+    private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
+        assert block != null && state != null;
+        assert !block.isExceptionEntry || state.stackSize() == 1;
+
+        if (getFirstInstruction(block) == null) {
+            /*
+             * This is the first time we see this block as a branch target. Create and return a
+             * placeholder that later can be replaced with a MergeNode when we see this block again.
+             */
+            FixedNode targetNode;
+            if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
+                setFirstInstruction(block, lastInstr);
+                lastInstr = null;
+            } else {
+                setFirstInstruction(block, graph.add(new BeginNode()));
+            }
+            targetNode = getFirstInstruction(block);
+            Target target = checkLoopExit(targetNode, block, state);
+            FixedNode result = target.fixed;
+            FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
+            setEntryState(block, currentEntryState);
+            currentEntryState.clearNonLiveLocals(block, liveness, true);
+
+            Debug.log("createTarget %s: first visit, result: %s", block, targetNode);
+            return result;
+        }
+
+        // We already saw this block before, so we have to merge states.
+        if (!getEntryState(block).isCompatibleWith(state)) {
+            throw bailout("stacks do not match; bytecodes would not verify");
+        }
+
+        if (getFirstInstruction(block) instanceof LoopBeginNode) {
+            assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
+            /*
+             * Backward loop edge. We need to create a special LoopEndNode and merge with the loop
+             * begin node created before.
+             */
+            LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
+            LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
+            Target target = checkLoopExit(loopEnd, block, state);
+            FixedNode result = target.fixed;
+            getEntryState(block).merge(loopBegin, target.state);
+
+            Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
+            return result;
+        }
+        assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
+        assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
+
+        if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
+            /*
+             * This is the second time we see this block. Create the actual MergeNode and the End
+             * Node for the already existing edge.
+             */
+            AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
+
+            // The EndNode for the already existing edge.
+            EndNode end = graph.add(new EndNode());
+            // The MergeNode that replaces the placeholder.
+            AbstractMergeNode mergeNode = graph.add(new MergeNode());
+            FixedNode next = beginNode.next();
+
+            if (beginNode.predecessor() instanceof ControlSplitNode) {
+                beginNode.setNext(end);
+            } else {
+                beginNode.replaceAtPredecessor(end);
+                beginNode.safeDelete();
+            }
+
+            mergeNode.addForwardEnd(end);
+            mergeNode.setNext(next);
+
+            setFirstInstruction(block, mergeNode);
+        }
+
+        AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
+
+        // The EndNode for the newly merged edge.
+        EndNode newEnd = graph.add(new EndNode());
+        Target target = checkLoopExit(newEnd, block, state);
+        FixedNode result = target.fixed;
+        getEntryState(block).merge(mergeNode, target.state);
+        mergeNode.addForwardEnd(newEnd);
+
+        Debug.log("createTarget %s: merging state, result: %s", block, result);
+        return result;
+    }
+
+    /**
+     * Returns a block begin node with the specified state. If the specified probability is 0, the
+     * block deoptimizes immediately.
+     */
+    private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
+        FixedNode target = createTarget(probability, block, stateAfter);
+        AbstractBeginNode begin = BeginNode.begin(target);
+
+        assert !(target instanceof DeoptimizeNode && begin instanceof BeginStateSplitNode &&
+                        ((BeginStateSplitNode) begin).stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node," +
+                                        " because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information.";
+        return begin;
+    }
+
+    private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) {
+        if (target.isStatic()) {
+            return appendConstant(getConstantReflection().asJavaClass(target.getDeclaringClass()));
+        } else {
+            return state.loadLocal(0, JavaKind.Object);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void processBlock(BciBlock block) {
+        // Ignore blocks that have no predecessors by the time their bytecodes are parsed
+        FixedWithNextNode firstInstruction = getFirstInstruction(block);
+        if (firstInstruction == null) {
+            Debug.log("Ignoring block %s", block);
+            return;
+        }
+        try (Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, firstInstruction, block.isLoopHeader)) {
+
+            lastInstr = firstInstruction;
+            frameState = getEntryState(block);
+            setCurrentFrameState(frameState);
+            currentBlock = block;
+
+            if (firstInstruction instanceof AbstractMergeNode) {
+                setMergeStateAfter(block, firstInstruction);
+            }
+
+            if (block == blockMap.getReturnBlock()) {
+                handleReturnBlock();
+            } else if (block == blockMap.getUnwindBlock()) {
+                handleUnwindBlock();
+            } else if (block instanceof ExceptionDispatchBlock) {
+                createExceptionDispatch((ExceptionDispatchBlock) block);
+            } else {
+                frameState.setRethrowException(false);
+                iterateBytecodesForBlock(block);
+            }
+        }
+    }
+
+    private void handleUnwindBlock() {
+        if (parent == null) {
+            frameState.setRethrowException(false);
+            createUnwind();
+        } else {
+            ValueNode exception = frameState.pop(JavaKind.Object);
+            this.unwindValue = exception;
+            this.beforeUnwindNode = this.lastInstr;
+        }
+    }
+
+    private void handleReturnBlock() {
+        JavaKind returnKind = method.getSignature().getReturnKind().getStackKind();
+        ValueNode x = returnKind == JavaKind.Void ? null : frameState.pop(returnKind);
+        assert frameState.stackSize() == 0;
+        beforeReturn(x, returnKind);
+        this.returnValue = x;
+        this.beforeReturnNode = this.lastInstr;
+    }
+
+    private void setMergeStateAfter(BciBlock block, FixedWithNextNode firstInstruction) {
+        AbstractMergeNode abstractMergeNode = (AbstractMergeNode) firstInstruction;
+        if (abstractMergeNode.stateAfter() == null) {
+            int bci = block.startBci;
+            if (block instanceof ExceptionDispatchBlock) {
+                bci = ((ExceptionDispatchBlock) block).deoptBci;
+            }
+            abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode));
+        }
+    }
+
+    private void createUnwind() {
+        assert frameState.stackSize() == 1 : frameState;
+        ValueNode exception = frameState.pop(JavaKind.Object);
+        synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null);
+        append(new UnwindNode(exception));
+    }
+
+    private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, JavaKind currentReturnValueKind) {
+        if (method.isSynchronized()) {
+            if (currentReturnValue != null) {
+                frameState.push(currentReturnValueKind, currentReturnValue);
+            }
+            genMonitorExit(methodSynchronizedObject, currentReturnValue, bci);
+            assert !frameState.rethrowException();
+        }
+        if (frameState.lockDepth(false) != 0) {
+            throw bailout("unbalanced monitors: too few exits exiting frame");
+        }
+    }
+
+    private void createExceptionDispatch(ExceptionDispatchBlock block) {
+        assert frameState.stackSize() == 1 : frameState;
+        if (block.handler.isCatchAll()) {
+            assert block.getSuccessorCount() == 1;
+            appendGoto(block.getSuccessor(0));
+            return;
+        }
+
+        JavaType catchType = block.handler.getCatchType();
+        if (graphBuilderConfig.eagerResolving()) {
+            catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF);
+        }
+        if (catchType instanceof ResolvedJavaType) {
+            TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType);
+
+            if (graphBuilderConfig.getSkippedExceptionTypes() != null) {
+                for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
+                    if (skippedType.isAssignableFrom(checkedCatchType.getType())) {
+                        BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
+                        ValueNode exception = frameState.stack[0];
+                        FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
+                        FixedNode nextDispatch = createTarget(nextBlock, frameState);
+                        append(new IfNode(graph.addOrUniqueWithInputs(createInstanceOf(checkedCatchType, exception)), trueSuccessor, nextDispatch, 0));
+                        return;
+                    }
+                }
+            }
+
+            BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
+            ValueNode exception = frameState.stack[0];
+            /* Anchor for the piNode, which must be before any LoopExit inserted by createTarget. */
+            BeginNode piNodeAnchor = graph.add(new BeginNode());
+            ObjectStamp checkedStamp = StampFactory.objectNonNull(checkedCatchType);
+            PiNode piNode = graph.addWithoutUnique(new PiNode(exception, checkedStamp));
+            frameState.pop(JavaKind.Object);
+            frameState.push(JavaKind.Object, piNode);
+            FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState);
+            frameState.pop(JavaKind.Object);
+            frameState.push(JavaKind.Object, exception);
+            FixedNode nextDispatch = createTarget(nextBlock, frameState);
+            piNodeAnchor.setNext(catchSuccessor);
+            IfNode ifNode = append(new IfNode(graph.unique(createInstanceOf(checkedCatchType, exception)), piNodeAnchor, nextDispatch, 0.5));
+            assert ifNode.trueSuccessor() == piNodeAnchor;
+            piNode.setGuard(ifNode.trueSuccessor());
+        } else {
+            handleUnresolvedExceptionType(catchType);
+        }
+    }
+
+    private void appendGoto(BciBlock successor) {
+        FixedNode targetInstr = createTarget(successor, frameState, true, true);
+        if (lastInstr != null && lastInstr != targetInstr) {
+            lastInstr.setNext(targetInstr);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void iterateBytecodesForBlock(BciBlock block) {
+        if (block.isLoopHeader) {
+            // Create the loop header block, which later will merge the backward branches of
+            // the loop.
+            controlFlowSplit = true;
+            LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr);
+            lastInstr = loopBegin;
+
+            // Create phi functions for all local variables and operand stack slots.
+            frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis(), stampFromValueForForcedPhis());
+            loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
+
+            /*
+             * We have seen all forward branches. All subsequent backward branches will merge to the
+             * loop header. This ensures that the loop header has exactly one non-loop predecessor.
+             */
+            setFirstInstruction(block, loopBegin);
+            /*
+             * We need to preserve the frame state builder of the loop header so that we can merge
+             * values for phi functions, so make a copy of it.
+             */
+            setEntryState(block, frameState.copy());
+
+            Debug.log("  created loop header %s", loopBegin);
+        } else if (lastInstr instanceof MergeNode) {
+            /*
+             * All inputs of non-loop phi nodes are known by now. We can infer the stamp for the
+             * phi, so that parsing continues with more precise type information.
+             */
+            frameState.inferPhiStamps((AbstractMergeNode) lastInstr);
+        }
+        assert lastInstr.next() == null : "instructions already appended at block " + block;
+        Debug.log("  frameState: %s", frameState);
+
+        lastInstr = finishInstruction(lastInstr, frameState);
+
+        int endBCI = stream.endBCI();
+
+        stream.setBCI(block.startBci);
+        int bci = block.startBci;
+        BytecodesParsed.add(block.endBci - bci);
+
+        /* Reset line number for new block */
+        if (graphBuilderConfig.insertFullInfopoints()) {
+            previousLineNumber = -1;
+        }
+
+        while (bci < endBCI) {
+            if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
+                currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
+                if (currentLineNumber != previousLineNumber) {
+                    genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
+                    previousLineNumber = currentLineNumber;
+                }
+            }
+
+            // read the opcode
+            int opcode = stream.currentBC();
+            assert traceState();
+            assert traceInstruction(bci, opcode, bci == block.startBci);
+            if (parent == null && bci == entryBCI) {
+                if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
+                    throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
+                }
+                EntryMarkerNode x = append(new EntryMarkerNode());
+                frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
+                x.setStateAfter(createFrameState(bci, x));
+            }
+
+            try (DebugCloseable context = openNodeContext()) {
+                processBytecode(bci, opcode);
+            } catch (BailoutException e) {
+                // Don't wrap bailouts as parser errors
+                throw e;
+            } catch (Throwable e) {
+                throw asParserError(e);
+            }
+
+            if (lastInstr == null || lastInstr.next() != null) {
+                break;
+            }
+
+            stream.next();
+            bci = stream.currentBCI();
+
+            assert block == currentBlock;
+            assert checkLastInstruction();
+            lastInstr = finishInstruction(lastInstr, frameState);
+            if (bci < endBCI) {
+                if (bci > block.endBci) {
+                    assert !block.getSuccessor(0).isExceptionEntry;
+                    assert block.numNormalSuccessors() == 1;
+                    // we fell through to the next block, add a goto and break
+                    appendGoto(block.getSuccessor(0));
+                    break;
+                }
+            }
+        }
+    }
+
+    private DebugCloseable openNodeContext() {
+        if (graphBuilderConfig.trackNodeSourcePosition() && !parsingIntrinsic()) {
+            return graph.withNodeSourcePosition(createBytecodePosition());
+        }
+        return null;
+    }
+
+    /* Also a hook for subclasses. */
+    protected boolean forceLoopPhis() {
+        return graph.isOSR();
+    }
+
+    /* Hook for subclasses. */
+    protected boolean stampFromValueForForcedPhis() {
+        return false;
+    }
+
+    protected boolean checkLastInstruction() {
+        if (lastInstr instanceof BeginNode) {
+            // ignore
+        } else if (lastInstr instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) lastInstr;
+            if (stateSplit.hasSideEffect()) {
+                assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter";
+            }
+        }
+        return true;
+    }
+
+    /* Also a hook for subclasses. */
+    protected boolean disableLoopSafepoint() {
+        return parsingIntrinsic();
+    }
+
+    private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) {
+        EndNode preLoopEnd = graph.add(new EndNode());
+        LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
+        if (disableLoopSafepoint()) {
+            loopBegin.disableSafepoint();
+        }
+        fixedWithNext.setNext(preLoopEnd);
+        // Add the single non-loop predecessor of the loop header.
+        loopBegin.addForwardEnd(preLoopEnd);
+        return loopBegin;
+    }
+
+    /**
+     * Hook for subclasses to modify the last instruction or add other instructions.
+     *
+     * @param instr The last instruction (= fixed node) which was added.
+     * @param state The current frame state.
+     * @return Returns the (new) last instruction.
+     */
+    protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) {
+        return instr;
+    }
+
+    private void genInfoPointNode(InfopointReason reason, ValueNode escapedReturnValue) {
+        if (!parsingIntrinsic() && graphBuilderConfig.insertFullInfopoints()) {
+            append(new FullInfopointNode(reason, createFrameState(bci(), null), escapedReturnValue));
+        }
+    }
+
+    private boolean traceState() {
+        if (Debug.isEnabled() && BytecodeParserOptions.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) {
+            frameState.traceState();
+        }
+        return true;
+    }
+
+    protected void genIf(ValueNode x, Condition cond, ValueNode y) {
+        assert x.getStackKind() == y.getStackKind();
+        assert currentBlock.getSuccessorCount() == 2;
+        BciBlock trueBlock = currentBlock.getSuccessor(0);
+        BciBlock falseBlock = currentBlock.getSuccessor(1);
+
+        FrameState stateBefore = null;
+        ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
+        if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+            stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+        }
+
+        if (trueBlock == falseBlock) {
+            // The target block is the same independent of the condition.
+            appendGoto(trueBlock);
+            return;
+        }
+
+        ValueNode a = x;
+        ValueNode b = y;
+
+        // Check whether the condition needs to mirror the operands.
+        if (cond.canonicalMirror()) {
+            a = y;
+            b = x;
+        }
+
+        // Create the logic node for the condition.
+        LogicNode condition = createLogicNode(cond, a, b);
+
+        // Check whether the condition needs to negate the result.
+        boolean negate = cond.canonicalNegate();
+
+        // Remove a logic negation node and fold it into the negate boolean.
+        if (condition instanceof LogicNegationNode) {
+            LogicNegationNode logicNegationNode = (LogicNegationNode) condition;
+            negate = !negate;
+            condition = logicNegationNode.getValue();
+        }
+
+        if (condition instanceof LogicConstantNode) {
+            genConstantTargetIf(trueBlock, falseBlock, negate, condition);
+        } else {
+            if (condition.graph() == null) {
+                condition = graph.unique(condition);
+            }
+
+            // Need to get probability based on current bci.
+            double probability = branchProbability();
+
+            if (negate) {
+                BciBlock tmpBlock = trueBlock;
+                trueBlock = falseBlock;
+                falseBlock = tmpBlock;
+                probability = 1 - probability;
+            }
+
+            if (isNeverExecutedCode(probability)) {
+                append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true));
+                if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                    profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore);
+                }
+                appendGoto(falseBlock);
+                return;
+            } else if (isNeverExecutedCode(1 - probability)) {
+                append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false));
+                if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                    profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore);
+                }
+                appendGoto(trueBlock);
+                return;
+            }
+
+            if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                profilingPlugin.profileIf(this, method, bci(), condition, trueBlock.startBci, falseBlock.startBci, stateBefore);
+            }
+
+            int oldBci = stream.currentBCI();
+            int trueBlockInt = checkPositiveIntConstantPushed(trueBlock);
+            if (trueBlockInt != -1) {
+                int falseBlockInt = checkPositiveIntConstantPushed(falseBlock);
+                if (falseBlockInt != -1) {
+                    if (tryGenConditionalForIf(trueBlock, falseBlock, condition, oldBci, trueBlockInt, falseBlockInt)) {
+                        return;
+                    }
+                }
+            }
+
+            this.controlFlowSplit = true;
+            FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, false);
+            FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true);
+            ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability);
+            postProcessIfNode(ifNode);
+            append(ifNode);
+            if (parsingIntrinsic()) {
+                if (x instanceof BranchProbabilityNode) {
+                    ((BranchProbabilityNode) x).simplify(null);
+                } else if (y instanceof BranchProbabilityNode) {
+                    ((BranchProbabilityNode) y).simplify(null);
+                }
+            }
+        }
+    }
+
+    /**
+     * Hook for subclasses to generate custom nodes before an IfNode.
+     */
+    @SuppressWarnings("unused")
+    protected void postProcessIfNode(ValueNode node) {
+    }
+
+    private boolean tryGenConditionalForIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt) {
+        if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) {
+            genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, false);
+            return true;
+        } else if (this.parent != null && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
+            genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, true);
+            return true;
+        }
+        return false;
+    }
+
+    private void genConditionalForIf(BciBlock trueBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt, boolean genReturn) {
+        ConstantNode trueValue = graph.unique(ConstantNode.forInt(trueBlockInt));
+        ConstantNode falseValue = graph.unique(ConstantNode.forInt(falseBlockInt));
+        ValueNode conditionalNode = ConditionalNode.create(condition, trueValue, falseValue);
+        if (conditionalNode.graph() == null) {
+            conditionalNode = graph.addOrUnique(conditionalNode);
+        }
+        if (genReturn) {
+            JavaKind returnKind = method.getSignature().getReturnKind().getStackKind();
+            this.genReturn(conditionalNode, returnKind);
+        } else {
+            frameState.push(JavaKind.Int, conditionalNode);
+            appendGoto(trueBlock.getSuccessor(0));
+            stream.setBCI(oldBci);
+        }
+    }
+
+    private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) {
+        LogicNode condition;
+        assert !a.getStackKind().isNumericFloat();
+        if (cond == Condition.EQ || cond == Condition.NE) {
+            if (a.getStackKind() == JavaKind.Object) {
+                condition = genObjectEquals(a, b);
+            } else {
+                condition = genIntegerEquals(a, b);
+            }
+        } else {
+            assert a.getStackKind() != JavaKind.Object && !cond.isUnsigned();
+            condition = genIntegerLessThan(a, b);
+        }
+        return condition;
+    }
+
+    private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) {
+        LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
+        boolean value = constantLogicNode.getValue();
+        if (negate) {
+            value = !value;
+        }
+        BciBlock nextBlock = falseBlock;
+        if (value) {
+            nextBlock = trueBlock;
+        }
+        int startBci = nextBlock.startBci;
+        int targetAtStart = stream.readUByte(startBci);
+        if (targetAtStart == Bytecodes.GOTO && nextBlock.getPredecessorCount() == 1) {
+            // This is an empty block. Skip it.
+            BciBlock successorBlock = nextBlock.successors.get(0);
+            ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin();
+            if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                profilingPlugin.profileGoto(this, method, bci(), successorBlock.startBci, stateBefore);
+            }
+            appendGoto(successorBlock);
+            assert nextBlock.numNormalSuccessors() == 1;
+        } else {
+            ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin();
+            if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                profilingPlugin.profileGoto(this, method, bci(), nextBlock.startBci, stateBefore);
+            }
+            appendGoto(nextBlock);
+        }
+    }
+
+    private int checkPositiveIntConstantPushed(BciBlock block) {
+        stream.setBCI(block.startBci);
+        int currentBC = stream.currentBC();
+        if (currentBC >= Bytecodes.ICONST_0 && currentBC <= Bytecodes.ICONST_5) {
+            int constValue = currentBC - Bytecodes.ICONST_0;
+            return constValue;
+        }
+        return -1;
+    }
+
+    private boolean gotoOrFallThroughAfterConstant(BciBlock block) {
+        stream.setBCI(block.startBci);
+        int currentBCI = stream.nextBCI();
+        stream.setBCI(currentBCI);
+        int currentBC = stream.currentBC();
+        return stream.currentBCI() > block.endBci || currentBC == Bytecodes.GOTO || currentBC == Bytecodes.GOTO_W;
+    }
+
+    private boolean returnAfterConstant(BciBlock block) {
+        stream.setBCI(block.startBci);
+        int currentBCI = stream.nextBCI();
+        stream.setBCI(currentBCI);
+        int currentBC = stream.currentBC();
+        return currentBC == Bytecodes.IRETURN;
+    }
+
+    @Override
+    public StampProvider getStampProvider() {
+        return stampProvider;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @Override
+    public void push(JavaKind slotKind, ValueNode value) {
+        assert value.isAlive();
+        frameState.push(slotKind, value);
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    /**
+     * Gets the graph being processed by this builder.
+     */
+    @Override
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+
+    @Override
+    public BytecodeParser getParent() {
+        return parent;
+    }
+
+    @Override
+    public IntrinsicContext getIntrinsic() {
+        return intrinsicContext;
+    }
+
+    @Override
+    public String toString() {
+        Formatter fmt = new Formatter();
+        BytecodeParser bp = this;
+        String indent = "";
+        while (bp != null) {
+            if (bp != this) {
+                fmt.format("%n%s", indent);
+            }
+            fmt.format("%s [bci: %d, intrinsic: %s]", bp.code.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingIntrinsic());
+            fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.code, bp.bci(), bp.bci() + 10));
+            bp = bp.parent;
+            indent += " ";
+        }
+        return fmt.toString();
+    }
+
+    @Override
+    public BailoutException bailout(String string) {
+        FrameState currentFrameState = createFrameState(bci(), null);
+        StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState);
+        BailoutException bailout = new PermanentBailoutException(string);
+        throw GraphUtil.createBailoutException(string, bailout, elements);
+    }
+
+    private FrameState createFrameState(int bci, StateSplit forStateSplit) {
+        if (currentBlock != null && bci > currentBlock.endBci) {
+            frameState.clearNonLiveLocals(currentBlock, liveness, false);
+        }
+        return frameState.create(bci, forStateSplit);
+    }
+
+    @Override
+    public void setStateAfter(StateSplit sideEffect) {
+        assert sideEffect.hasSideEffect();
+        FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect);
+        sideEffect.setStateAfter(stateAfter);
+    }
+
+    protected NodeSourcePosition createBytecodePosition() {
+        return frameState.createBytecodePosition(bci());
+    }
+
+    public void setCurrentFrameState(FrameStateBuilder frameState) {
+        this.frameState = frameState;
+    }
+
+    protected final BytecodeStream getStream() {
+        return stream;
+    }
+
+    @Override
+    public int bci() {
+        return stream.currentBCI();
+    }
+
+    public void loadLocal(int index, JavaKind kind) {
+        ValueNode value = frameState.loadLocal(index, kind);
+        frameState.push(kind, value);
+    }
+
+    public void storeLocal(JavaKind kind, int index) {
+        ValueNode value = frameState.pop(kind);
+        frameState.storeLocal(index, kind, value);
+    }
+
+    private void genLoadConstant(int cpi, int opcode) {
+        Object con = lookupConstant(cpi, opcode);
+
+        if (con instanceof JavaType) {
+            // this is a load of class constant which might be unresolved
+            JavaType type = (JavaType) con;
+            if (type instanceof ResolvedJavaType) {
+                frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type)));
+            } else {
+                handleUnresolvedLoadConstant(type);
+            }
+        } else if (con instanceof JavaConstant) {
+            JavaConstant constant = (JavaConstant) con;
+            frameState.push(constant.getJavaKind(), appendConstant(constant));
+        } else {
+            throw new Error("lookupConstant returned an object of incorrect type");
+        }
+    }
+
+    private void genLoadIndexed(JavaKind kind) {
+        ValueNode index = frameState.pop(JavaKind.Int);
+        ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index);
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleLoadIndexed(this, array, index, kind)) {
+                return;
+            }
+        }
+
+        frameState.push(kind, append(genLoadIndexed(array, index, kind)));
+    }
+
+    private void genStoreIndexed(JavaKind kind) {
+        ValueNode value = frameState.pop(kind);
+        ValueNode index = frameState.pop(JavaKind.Int);
+        ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index);
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleStoreIndexed(this, array, index, kind, value)) {
+                return;
+            }
+        }
+
+        genStoreIndexed(array, index, kind, value);
+    }
+
+    private void genArithmeticOp(JavaKind kind, int opcode) {
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
+        switch (opcode) {
+            case IADD:
+            case LADD:
+                v = genIntegerAdd(x, y);
+                break;
+            case FADD:
+            case DADD:
+                v = genFloatAdd(x, y);
+                break;
+            case ISUB:
+            case LSUB:
+                v = genIntegerSub(x, y);
+                break;
+            case FSUB:
+            case DSUB:
+                v = genFloatSub(x, y);
+                break;
+            case IMUL:
+            case LMUL:
+                v = genIntegerMul(x, y);
+                break;
+            case FMUL:
+            case DMUL:
+                v = genFloatMul(x, y);
+                break;
+            case FDIV:
+            case DDIV:
+                v = genFloatDiv(x, y);
+                break;
+            case FREM:
+            case DREM:
+                v = genFloatRem(x, y);
+                break;
+            default:
+                throw shouldNotReachHere();
+        }
+        frameState.push(kind, append(v));
+    }
+
+    private void genIntegerDivOp(JavaKind kind, int opcode) {
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
+        switch (opcode) {
+            case IDIV:
+            case LDIV:
+                v = genIntegerDiv(x, y);
+                break;
+            case IREM:
+            case LREM:
+                v = genIntegerRem(x, y);
+                break;
+            default:
+                throw shouldNotReachHere();
+        }
+        frameState.push(kind, append(v));
+    }
+
+    private void genNegateOp(JavaKind kind) {
+        ValueNode x = frameState.pop(kind);
+        frameState.push(kind, append(genNegateOp(x)));
+    }
+
+    private void genShiftOp(JavaKind kind, int opcode) {
+        ValueNode s = frameState.pop(JavaKind.Int);
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
+        switch (opcode) {
+            case ISHL:
+            case LSHL:
+                v = genLeftShift(x, s);
+                break;
+            case ISHR:
+            case LSHR:
+                v = genRightShift(x, s);
+                break;
+            case IUSHR:
+            case LUSHR:
+                v = genUnsignedRightShift(x, s);
+                break;
+            default:
+                throw shouldNotReachHere();
+        }
+        frameState.push(kind, append(v));
+    }
+
+    private void genLogicOp(JavaKind kind, int opcode) {
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
+        switch (opcode) {
+            case IAND:
+            case LAND:
+                v = genAnd(x, y);
+                break;
+            case IOR:
+            case LOR:
+                v = genOr(x, y);
+                break;
+            case IXOR:
+            case LXOR:
+                v = genXor(x, y);
+                break;
+            default:
+                throw shouldNotReachHere();
+        }
+        frameState.push(kind, append(v));
+    }
+
+    private void genCompareOp(JavaKind kind, boolean isUnorderedLess) {
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        frameState.push(JavaKind.Int, append(genNormalizeCompare(x, y, isUnorderedLess)));
+    }
+
+    private void genFloatConvert(FloatConvert op, JavaKind from, JavaKind to) {
+        ValueNode input = frameState.pop(from);
+        frameState.push(to, append(genFloatConvert(op, input)));
+    }
+
+    private void genSignExtend(JavaKind from, JavaKind to) {
+        ValueNode input = frameState.pop(from);
+        if (from != from.getStackKind()) {
+            input = append(genNarrow(input, from.getBitCount()));
+        }
+        frameState.push(to, append(genSignExtend(input, to.getBitCount())));
+    }
+
+    private void genZeroExtend(JavaKind from, JavaKind to) {
+        ValueNode input = frameState.pop(from);
+        if (from != from.getStackKind()) {
+            input = append(genNarrow(input, from.getBitCount()));
+        }
+        frameState.push(to, append(genZeroExtend(input, to.getBitCount())));
+    }
+
+    private void genNarrow(JavaKind from, JavaKind to) {
+        ValueNode input = frameState.pop(from);
+        frameState.push(to, append(genNarrow(input, to.getBitCount())));
+    }
+
+    private void genIncrement() {
+        int index = getStream().readLocalIndex();
+        int delta = getStream().readIncrement();
+        ValueNode x = frameState.loadLocal(index, JavaKind.Int);
+        ValueNode y = appendConstant(JavaConstant.forInt(delta));
+        frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y)));
+    }
+
+    private void genIfZero(Condition cond) {
+        ValueNode y = appendConstant(JavaConstant.INT_0);
+        ValueNode x = frameState.pop(JavaKind.Int);
+        genIf(x, cond, y);
+    }
+
+    private void genIfNull(Condition cond) {
+        ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
+        ValueNode x = frameState.pop(JavaKind.Object);
+        genIf(x, cond, y);
+    }
+
+    private void genIfSame(JavaKind kind, Condition cond) {
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        genIf(x, cond, y);
+    }
+
+    protected JavaType lookupType(int cpi, int bytecode) {
+        maybeEagerlyResolve(cpi, bytecode);
+        JavaType result = constantPool.lookupType(cpi, bytecode);
+        assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
+        return result;
+    }
+
+    private JavaMethod lookupMethod(int cpi, int opcode) {
+        maybeEagerlyResolve(cpi, opcode);
+        JavaMethod result = constantPool.lookupMethod(cpi, opcode);
+        /*
+         * In general, one cannot assume that the declaring class being initialized is useful, since
+         * the actual concrete receiver may be a different class (except for static calls). Also,
+         * interfaces are initialized only under special circumstances, so that this assertion would
+         * often fail for interface calls.
+         */
+        assert !graphBuilderConfig.unresolvedIsError() ||
+                        (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
+        return result;
+    }
+
+    private JavaField lookupField(int cpi, int opcode) {
+        maybeEagerlyResolve(cpi, opcode);
+        JavaField result = constantPool.lookupField(cpi, method, opcode);
+        if (graphBuilderConfig.eagerResolving()) {
+            assert result instanceof ResolvedJavaField : "Not resolved: " + result;
+            ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
+            if (!declaringClass.isInitialized()) {
+                assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
+                declaringClass.initialize();
+            }
+        }
+        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
+        return result;
+    }
+
+    private Object lookupConstant(int cpi, int opcode) {
+        maybeEagerlyResolve(cpi, opcode);
+        Object result = constantPool.lookupConstant(cpi);
+        assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
+        return result;
+    }
+
+    private void maybeEagerlyResolve(int cpi, int bytecode) {
+        if (intrinsicContext != null) {
+            constantPool.loadReferencedType(cpi, bytecode);
+        } else if (graphBuilderConfig.eagerResolving()) {
+            /*
+             * Since we're potentially triggering class initialization here, we need synchronization
+             * to mitigate the potential for class initialization related deadlock being caused by
+             * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
+             */
+            synchronized (BytecodeParser.class) {
+                constantPool.loadReferencedType(cpi, bytecode);
+            }
+        }
+    }
+
+    private JavaTypeProfile getProfileForTypeCheck(TypeReference type) {
+        if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || type.isExact()) {
+            return null;
+        } else {
+            return profilingInfo.getTypeProfile(bci());
+        }
+    }
+
+    private void genCheckCast() {
+        int cpi = getStream().readCPI();
+        JavaType type = lookupType(cpi, CHECKCAST);
+        ValueNode object = frameState.pop(JavaKind.Object);
+
+        if (!(type instanceof ResolvedJavaType)) {
+            handleUnresolvedCheckCast(type, object);
+            return;
+        }
+        TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type);
+        JavaTypeProfile profile = getProfileForTypeCheck(checkedType);
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleCheckCast(this, object, checkedType.getType(), profile)) {
+                return;
+            }
+        }
+
+        ValueNode castNode = null;
+        if (profile != null) {
+            if (profile.getNullSeen().isFalse()) {
+                object = appendNullCheck(object);
+                ResolvedJavaType singleType = profile.asSingleType();
+                if (singleType != null && checkedType.getType().isAssignableFrom(singleType)) {
+                    LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile));
+                    if (typeCheck.isTautology()) {
+                        castNode = object;
+                    } else {
+                        FixedGuardNode fixedGuard = append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, false));
+                        castNode = append(new PiNode(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard));
+                    }
+                }
+            }
+        }
+        if (castNode == null) {
+            LogicNode condition = genUnique(createInstanceOfAllowNull(checkedType, object, null));
+            if (condition.isTautology()) {
+                castNode = object;
+            } else {
+                FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
+                castNode = append(new PiNode(object, StampFactory.object(checkedType), fixedGuard));
+            }
+        }
+        frameState.push(JavaKind.Object, castNode);
+    }
+
+    private ValueNode appendNullCheck(ValueNode object) {
+        if (object.stamp() instanceof AbstractPointerStamp) {
+            AbstractPointerStamp stamp = (AbstractPointerStamp) object.stamp();
+            if (stamp.nonNull()) {
+                return object;
+            }
+        }
+
+        LogicNode isNull = append(IsNullNode.create(object));
+        FixedGuardNode fixedGuard = append(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true));
+        return append(new PiNode(object, object.stamp().join(StampFactory.objectNonNull()), fixedGuard));
+    }
+
+    private void genInstanceOf() {
+        int cpi = getStream().readCPI();
+        JavaType type = lookupType(cpi, INSTANCEOF);
+        ValueNode object = frameState.pop(JavaKind.Object);
+
+        if (!(type instanceof ResolvedJavaType)) {
+            handleUnresolvedInstanceOf(type, object);
+            return;
+        }
+        TypeReference resolvedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type);
+        JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleInstanceOf(this, object, resolvedType.getType(), profile)) {
+                return;
+            }
+        }
+
+        LogicNode instanceOfNode = null;
+        if (profile != null) {
+            if (profile.getNullSeen().isFalse()) {
+                object = appendNullCheck(object);
+                ResolvedJavaType singleType = profile.asSingleType();
+                if (singleType != null) {
+                    LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile));
+                    if (!typeCheck.isTautology()) {
+                        append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+                    }
+                    instanceOfNode = LogicConstantNode.forBoolean(resolvedType.getType().isAssignableFrom(singleType));
+                }
+            }
+        }
+        if (instanceOfNode == null) {
+            instanceOfNode = createInstanceOf(resolvedType, object, null);
+        }
+        frameState.push(JavaKind.Int, append(genConditional(genUnique(instanceOfNode))));
+    }
+
+    void genNewInstance(int cpi) {
+        JavaType type = lookupType(cpi, NEW);
+
+        if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) {
+            handleUnresolvedNewInstance(type);
+            return;
+        }
+        ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+
+        ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
+        if (skippedExceptionTypes != null) {
+            for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
+                if (exceptionType.isAssignableFrom(resolvedType)) {
+                    append(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, RuntimeConstraint));
+                    return;
+                }
+            }
+        }
+
+        ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            classInitializationPlugin.apply(this, resolvedType, stateBefore);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleNewInstance(this, resolvedType)) {
+                return;
+            }
+        }
+
+        frameState.push(JavaKind.Object, append(createNewInstance(resolvedType, true)));
+    }
+
+    /**
+     * Gets the kind of array elements for the array type code that appears in a
+     * {@link Bytecodes#NEWARRAY} bytecode.
+     *
+     * @param code the array type code
+     * @return the kind from the array type code
+     */
+    private static Class<?> arrayTypeCodeToClass(int code) {
+        switch (code) {
+            case 4:
+                return boolean.class;
+            case 5:
+                return char.class;
+            case 6:
+                return float.class;
+            case 7:
+                return double.class;
+            case 8:
+                return byte.class;
+            case 9:
+                return short.class;
+            case 10:
+                return int.class;
+            case 11:
+                return long.class;
+            default:
+                throw new IllegalArgumentException("unknown array type code: " + code);
+        }
+    }
+
+    private void genNewPrimitiveArray(int typeCode) {
+        ResolvedJavaType elementType = metaAccess.lookupJavaType(arrayTypeCodeToClass(typeCode));
+        ValueNode length = frameState.pop(JavaKind.Int);
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleNewArray(this, elementType, length)) {
+                return;
+            }
+        }
+
+        frameState.push(JavaKind.Object, append(createNewArray(elementType, length, true)));
+    }
+
+    private void genNewObjectArray(int cpi) {
+        JavaType type = lookupType(cpi, ANEWARRAY);
+
+        if (!(type instanceof ResolvedJavaType)) {
+            ValueNode length = frameState.pop(JavaKind.Int);
+            handleUnresolvedNewObjectArray(type, length);
+            return;
+        }
+
+        ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+
+        ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore);
+        }
+
+        ValueNode length = frameState.pop(JavaKind.Int);
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleNewArray(this, resolvedType, length)) {
+                return;
+            }
+        }
+
+        frameState.push(JavaKind.Object, append(createNewArray(resolvedType, length, true)));
+    }
+
+    private void genNewMultiArray(int cpi) {
+        JavaType type = lookupType(cpi, MULTIANEWARRAY);
+        int rank = getStream().readUByte(bci() + 3);
+        ValueNode[] dims = new ValueNode[rank];
+
+        if (!(type instanceof ResolvedJavaType)) {
+            for (int i = rank - 1; i >= 0; i--) {
+                dims[i] = frameState.pop(JavaKind.Int);
+            }
+            handleUnresolvedNewMultiArray(type, dims);
+            return;
+        }
+        ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+
+        ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore);
+        }
+
+        for (int i = rank - 1; i >= 0; i--) {
+            dims[i] = frameState.pop(JavaKind.Int);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleNewMultiArray(this, resolvedType, dims)) {
+                return;
+            }
+        }
+
+        frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims)));
+    }
+
+    private void genGetField(JavaField field) {
+        ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object), null);
+
+        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+            handleUnresolvedLoadField(field, receiver);
+            return;
+        }
+        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
+        if (!parsingIntrinsic() && GeneratePIC.getValue()) {
+            graph.recordField(resolvedField);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleLoadField(this, receiver, resolvedField)) {
+                return;
+            }
+        }
+
+        frameState.push(field.getJavaKind(), append(genLoadField(receiver, resolvedField)));
+        if (resolvedField.getName().equals("referent") && resolvedField.getDeclaringClass().equals(metaAccess.lookupJavaType(Reference.class))) {
+            LocationIdentity referentIdentity = new FieldLocationIdentity(resolvedField);
+            append(new MembarNode(0, referentIdentity));
+        }
+    }
+
+    /**
+     * @param receiver the receiver of an object based operation
+     * @param index the index of an array based operation that is to be tested for out of bounds.
+     *            This is null for a non-array operation.
+     * @return the receiver value possibly modified to have a tighter stamp
+     */
+    protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
+        assert receiver != null;
+        if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) {
+            return receiver;
+        }
+        if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile && (profilingInfo == null ||
+                        (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue()))) {
+            return receiver;
+        }
+
+        ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
+        if (index != null) {
+            ValueNode length = append(genArrayLength(nonNullReceiver));
+            emitExplicitBoundsCheck(index, length);
+        }
+        EXPLICIT_EXCEPTIONS.increment();
+        return nonNullReceiver;
+    }
+
+    private void genPutField(JavaField field) {
+        ValueNode value = frameState.pop(field.getJavaKind());
+        ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object), null);
+
+        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+            handleUnresolvedStoreField(field, value, receiver);
+            return;
+        }
+        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
+        if (!parsingIntrinsic() && GeneratePIC.getValue()) {
+            graph.recordField(resolvedField);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleStoreField(this, receiver, resolvedField, value)) {
+                return;
+            }
+        }
+
+        if (resolvedField.isFinal() && method.isConstructor()) {
+            finalBarrierRequired = true;
+        }
+        genStoreField(receiver, resolvedField, value);
+    }
+
+    private void genGetStatic(JavaField field) {
+        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+            handleUnresolvedLoadField(field, null);
+            return;
+        }
+        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
+        if (!parsingIntrinsic() && GeneratePIC.getValue()) {
+            graph.recordField(resolvedField);
+        }
+
+        /*
+         * Javac does not allow use of "$assertionsDisabled" for a field name but Eclipse does, in
+         * which case a suffix is added to the generated field.
+         */
+        if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) {
+            frameState.push(field.getJavaKind(), ConstantNode.forBoolean(true, graph));
+            return;
+        }
+
+        ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleLoadStaticField(this, resolvedField)) {
+                return;
+            }
+        }
+
+        frameState.push(field.getJavaKind(), append(genLoadField(null, resolvedField)));
+    }
+
+    private void genPutStatic(JavaField field) {
+        ValueNode value = frameState.pop(field.getJavaKind());
+        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+            handleUnresolvedStoreField(field, value, null);
+            return;
+        }
+        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
+        if (!parsingIntrinsic() && GeneratePIC.getValue()) {
+            graph.recordField(resolvedField);
+        }
+
+        ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) {
+            FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+            classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore);
+        }
+
+        for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+            if (plugin.handleStoreStaticField(this, resolvedField, value)) {
+                return;
+            }
+        }
+
+        genStoreField(null, resolvedField, value);
+    }
+
+    private double[] switchProbability(int numberOfCases, int bci) {
+        double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
+        if (prob != null) {
+            assert prob.length == numberOfCases;
+        } else {
+            Debug.log("Missing probability (switch) in %s at bci %d", method, bci);
+            prob = new double[numberOfCases];
+            for (int i = 0; i < numberOfCases; i++) {
+                prob[i] = 1.0d / numberOfCases;
+            }
+        }
+        assert allPositive(prob);
+        return prob;
+    }
+
+    private static boolean allPositive(double[] a) {
+        for (double d : a) {
+            if (d < 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    static class SuccessorInfo {
+        final int blockIndex;
+        int actualIndex;
+
+        SuccessorInfo(int blockSuccessorIndex) {
+            this.blockIndex = blockSuccessorIndex;
+            actualIndex = -1;
+        }
+    }
+
+    private void genSwitch(BytecodeSwitch bs) {
+        int bci = bci();
+        ValueNode value = frameState.pop(JavaKind.Int);
+
+        int nofCases = bs.numberOfCases();
+        double[] keyProbabilities = switchProbability(nofCases + 1, bci);
+
+        Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
+        for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
+            assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
+            if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
+                bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
+            }
+        }
+
+        ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
+        int[] keys = new int[nofCases];
+        int[] keySuccessors = new int[nofCases + 1];
+        int deoptSuccessorIndex = -1;
+        int nextSuccessorIndex = 0;
+        boolean constantValue = value.isConstant();
+        for (int i = 0; i < nofCases + 1; i++) {
+            if (i < nofCases) {
+                keys[i] = bs.keyAt(i);
+            }
+
+            if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
+                if (deoptSuccessorIndex < 0) {
+                    deoptSuccessorIndex = nextSuccessorIndex++;
+                    actualSuccessors.add(null);
+                }
+                keySuccessors[i] = deoptSuccessorIndex;
+            } else {
+                int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i);
+                SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
+                if (info.actualIndex < 0) {
+                    info.actualIndex = nextSuccessorIndex++;
+                    actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
+                }
+                keySuccessors[i] = info.actualIndex;
+            }
+        }
+
+        genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors);
+
+    }
+
+    protected boolean isNeverExecutedCode(double probability) {
+        return probability == 0 && optimisticOpts.removeNeverExecutedCode();
+    }
+
+    protected double branchProbability() {
+        if (profilingInfo == null) {
+            return 0.5;
+        }
+        assert assertAtIfBytecode();
+        double probability = profilingInfo.getBranchTakenProbability(bci());
+        if (probability < 0) {
+            assert probability == -1 : "invalid probability";
+            Debug.log("missing probability in %s at bci %d", code, bci());
+            probability = 0.5;
+        }
+
+        if (!optimisticOpts.removeNeverExecutedCode()) {
+            if (probability == 0) {
+                probability = 0.0000001;
+            } else if (probability == 1) {
+                probability = 0.999999;
+            }
+        }
+        return probability;
+    }
+
+    private boolean assertAtIfBytecode() {
+        int bytecode = stream.currentBC();
+        switch (bytecode) {
+            case IFEQ:
+            case IFNE:
+            case IFLT:
+            case IFGE:
+            case IFGT:
+            case IFLE:
+            case IF_ICMPEQ:
+            case IF_ICMPNE:
+            case IF_ICMPLT:
+            case IF_ICMPGE:
+            case IF_ICMPGT:
+            case IF_ICMPLE:
+            case IF_ACMPEQ:
+            case IF_ACMPNE:
+            case IFNULL:
+            case IFNONNULL:
+                return true;
+        }
+        assert false : String.format("%x is not an if bytecode", bytecode);
+        return true;
+    }
+
+    public final void processBytecode(int bci, int opcode) {
+        int cpi;
+
+        // @formatter:off
+        // Checkstyle: stop
+        switch (opcode) {
+            case NOP            : /* nothing to do */ break;
+            case ACONST_NULL    : frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); break;
+            case ICONST_M1      : // fall through
+            case ICONST_0       : // fall through
+            case ICONST_1       : // fall through
+            case ICONST_2       : // fall through
+            case ICONST_3       : // fall through
+            case ICONST_4       : // fall through
+            case ICONST_5       : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
+            case LCONST_0       : // fall through
+            case LCONST_1       : frameState.push(JavaKind.Long, appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
+            case FCONST_0       : // fall through
+            case FCONST_1       : // fall through
+            case FCONST_2       : frameState.push(JavaKind.Float, appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
+            case DCONST_0       : // fall through
+            case DCONST_1       : frameState.push(JavaKind.Double, appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
+            case BIPUSH         : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readByte()))); break;
+            case SIPUSH         : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readShort()))); break;
+            case LDC            : // fall through
+            case LDC_W          : // fall through
+            case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
+            case ILOAD          : loadLocal(stream.readLocalIndex(), JavaKind.Int); break;
+            case LLOAD          : loadLocal(stream.readLocalIndex(), JavaKind.Long); break;
+            case FLOAD          : loadLocal(stream.readLocalIndex(), JavaKind.Float); break;
+            case DLOAD          : loadLocal(stream.readLocalIndex(), JavaKind.Double); break;
+            case ALOAD          : loadLocal(stream.readLocalIndex(), JavaKind.Object); break;
+            case ILOAD_0        : // fall through
+            case ILOAD_1        : // fall through
+            case ILOAD_2        : // fall through
+            case ILOAD_3        : loadLocal(opcode - ILOAD_0, JavaKind.Int); break;
+            case LLOAD_0        : // fall through
+            case LLOAD_1        : // fall through
+            case LLOAD_2        : // fall through
+            case LLOAD_3        : loadLocal(opcode - LLOAD_0, JavaKind.Long); break;
+            case FLOAD_0        : // fall through
+            case FLOAD_1        : // fall through
+            case FLOAD_2        : // fall through
+            case FLOAD_3        : loadLocal(opcode - FLOAD_0, JavaKind.Float); break;
+            case DLOAD_0        : // fall through
+            case DLOAD_1        : // fall through
+            case DLOAD_2        : // fall through
+            case DLOAD_3        : loadLocal(opcode - DLOAD_0, JavaKind.Double); break;
+            case ALOAD_0        : // fall through
+            case ALOAD_1        : // fall through
+            case ALOAD_2        : // fall through
+            case ALOAD_3        : loadLocal(opcode - ALOAD_0, JavaKind.Object); break;
+            case IALOAD         : genLoadIndexed(JavaKind.Int   ); break;
+            case LALOAD         : genLoadIndexed(JavaKind.Long  ); break;
+            case FALOAD         : genLoadIndexed(JavaKind.Float ); break;
+            case DALOAD         : genLoadIndexed(JavaKind.Double); break;
+            case AALOAD         : genLoadIndexed(JavaKind.Object); break;
+            case BALOAD         : genLoadIndexed(JavaKind.Byte  ); break;
+            case CALOAD         : genLoadIndexed(JavaKind.Char  ); break;
+            case SALOAD         : genLoadIndexed(JavaKind.Short ); break;
+            case ISTORE         : storeLocal(JavaKind.Int, stream.readLocalIndex()); break;
+            case LSTORE         : storeLocal(JavaKind.Long, stream.readLocalIndex()); break;
+            case FSTORE         : storeLocal(JavaKind.Float, stream.readLocalIndex()); break;
+            case DSTORE         : storeLocal(JavaKind.Double, stream.readLocalIndex()); break;
+            case ASTORE         : storeLocal(JavaKind.Object, stream.readLocalIndex()); break;
+            case ISTORE_0       : // fall through
+            case ISTORE_1       : // fall through
+            case ISTORE_2       : // fall through
+            case ISTORE_3       : storeLocal(JavaKind.Int, opcode - ISTORE_0); break;
+            case LSTORE_0       : // fall through
+            case LSTORE_1       : // fall through
+            case LSTORE_2       : // fall through
+            case LSTORE_3       : storeLocal(JavaKind.Long, opcode - LSTORE_0); break;
+            case FSTORE_0       : // fall through
+            case FSTORE_1       : // fall through
+            case FSTORE_2       : // fall through
+            case FSTORE_3       : storeLocal(JavaKind.Float, opcode - FSTORE_0); break;
+            case DSTORE_0       : // fall through
+            case DSTORE_1       : // fall through
+            case DSTORE_2       : // fall through
+            case DSTORE_3       : storeLocal(JavaKind.Double, opcode - DSTORE_0); break;
+            case ASTORE_0       : // fall through
+            case ASTORE_1       : // fall through
+            case ASTORE_2       : // fall through
+            case ASTORE_3       : storeLocal(JavaKind.Object, opcode - ASTORE_0); break;
+            case IASTORE        : genStoreIndexed(JavaKind.Int   ); break;
+            case LASTORE        : genStoreIndexed(JavaKind.Long  ); break;
+            case FASTORE        : genStoreIndexed(JavaKind.Float ); break;
+            case DASTORE        : genStoreIndexed(JavaKind.Double); break;
+            case AASTORE        : genStoreIndexed(JavaKind.Object); break;
+            case BASTORE        : genStoreIndexed(JavaKind.Byte  ); break;
+            case CASTORE        : genStoreIndexed(JavaKind.Char  ); break;
+            case SASTORE        : genStoreIndexed(JavaKind.Short ); break;
+            case POP            : // fall through
+            case POP2           : // fall through
+            case DUP            : // fall through
+            case DUP_X1         : // fall through
+            case DUP_X2         : // fall through
+            case DUP2           : // fall through
+            case DUP2_X1        : // fall through
+            case DUP2_X2        : // fall through
+            case SWAP           : frameState.stackOp(opcode); break;
+            case IADD           : // fall through
+            case ISUB           : // fall through
+            case IMUL           : genArithmeticOp(JavaKind.Int, opcode); break;
+            case IDIV           : // fall through
+            case IREM           : genIntegerDivOp(JavaKind.Int, opcode); break;
+            case LADD           : // fall through
+            case LSUB           : // fall through
+            case LMUL           : genArithmeticOp(JavaKind.Long, opcode); break;
+            case LDIV           : // fall through
+            case LREM           : genIntegerDivOp(JavaKind.Long, opcode); break;
+            case FADD           : // fall through
+            case FSUB           : // fall through
+            case FMUL           : // fall through
+            case FDIV           : // fall through
+            case FREM           : genArithmeticOp(JavaKind.Float, opcode); break;
+            case DADD           : // fall through
+            case DSUB           : // fall through
+            case DMUL           : // fall through
+            case DDIV           : // fall through
+            case DREM           : genArithmeticOp(JavaKind.Double, opcode); break;
+            case INEG           : genNegateOp(JavaKind.Int); break;
+            case LNEG           : genNegateOp(JavaKind.Long); break;
+            case FNEG           : genNegateOp(JavaKind.Float); break;
+            case DNEG           : genNegateOp(JavaKind.Double); break;
+            case ISHL           : // fall through
+            case ISHR           : // fall through
+            case IUSHR          : genShiftOp(JavaKind.Int, opcode); break;
+            case IAND           : // fall through
+            case IOR            : // fall through
+            case IXOR           : genLogicOp(JavaKind.Int, opcode); break;
+            case LSHL           : // fall through
+            case LSHR           : // fall through
+            case LUSHR          : genShiftOp(JavaKind.Long, opcode); break;
+            case LAND           : // fall through
+            case LOR            : // fall through
+            case LXOR           : genLogicOp(JavaKind.Long, opcode); break;
+            case IINC           : genIncrement(); break;
+            case I2F            : genFloatConvert(FloatConvert.I2F, JavaKind.Int, JavaKind.Float); break;
+            case I2D            : genFloatConvert(FloatConvert.I2D, JavaKind.Int, JavaKind.Double); break;
+            case L2F            : genFloatConvert(FloatConvert.L2F, JavaKind.Long, JavaKind.Float); break;
+            case L2D            : genFloatConvert(FloatConvert.L2D, JavaKind.Long, JavaKind.Double); break;
+            case F2I            : genFloatConvert(FloatConvert.F2I, JavaKind.Float, JavaKind.Int); break;
+            case F2L            : genFloatConvert(FloatConvert.F2L, JavaKind.Float, JavaKind.Long); break;
+            case F2D            : genFloatConvert(FloatConvert.F2D, JavaKind.Float, JavaKind.Double); break;
+            case D2I            : genFloatConvert(FloatConvert.D2I, JavaKind.Double, JavaKind.Int); break;
+            case D2L            : genFloatConvert(FloatConvert.D2L, JavaKind.Double, JavaKind.Long); break;
+            case D2F            : genFloatConvert(FloatConvert.D2F, JavaKind.Double, JavaKind.Float); break;
+            case L2I            : genNarrow(JavaKind.Long, JavaKind.Int); break;
+            case I2L            : genSignExtend(JavaKind.Int, JavaKind.Long); break;
+            case I2B            : genSignExtend(JavaKind.Byte, JavaKind.Int); break;
+            case I2S            : genSignExtend(JavaKind.Short, JavaKind.Int); break;
+            case I2C            : genZeroExtend(JavaKind.Char, JavaKind.Int); break;
+            case LCMP           : genCompareOp(JavaKind.Long, false); break;
+            case FCMPL          : genCompareOp(JavaKind.Float, true); break;
+            case FCMPG          : genCompareOp(JavaKind.Float, false); break;
+            case DCMPL          : genCompareOp(JavaKind.Double, true); break;
+            case DCMPG          : genCompareOp(JavaKind.Double, false); break;
+            case IFEQ           : genIfZero(Condition.EQ); break;
+            case IFNE           : genIfZero(Condition.NE); break;
+            case IFLT           : genIfZero(Condition.LT); break;
+            case IFGE           : genIfZero(Condition.GE); break;
+            case IFGT           : genIfZero(Condition.GT); break;
+            case IFLE           : genIfZero(Condition.LE); break;
+            case IF_ICMPEQ      : genIfSame(JavaKind.Int, Condition.EQ); break;
+            case IF_ICMPNE      : genIfSame(JavaKind.Int, Condition.NE); break;
+            case IF_ICMPLT      : genIfSame(JavaKind.Int, Condition.LT); break;
+            case IF_ICMPGE      : genIfSame(JavaKind.Int, Condition.GE); break;
+            case IF_ICMPGT      : genIfSame(JavaKind.Int, Condition.GT); break;
+            case IF_ICMPLE      : genIfSame(JavaKind.Int, Condition.LE); break;
+            case IF_ACMPEQ      : genIfSame(JavaKind.Object, Condition.EQ); break;
+            case IF_ACMPNE      : genIfSame(JavaKind.Object, Condition.NE); break;
+            case GOTO           : genGoto(); break;
+            case JSR            : genJsr(stream.readBranchDest()); break;
+            case RET            : genRet(stream.readLocalIndex()); break;
+            case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
+            case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
+            case IRETURN        : genReturn(frameState.pop(JavaKind.Int), JavaKind.Int); break;
+            case LRETURN        : genReturn(frameState.pop(JavaKind.Long), JavaKind.Long); break;
+            case FRETURN        : genReturn(frameState.pop(JavaKind.Float), JavaKind.Float); break;
+            case DRETURN        : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break;
+            case ARETURN        : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break;
+            case RETURN         : genReturn(null, JavaKind.Void); break;
+            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
+            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
+            case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
+            case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
+            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
+            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
+            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
+            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
+            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+            case NEW            : genNewInstance(stream.readCPI()); break;
+            case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
+            case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
+            case ARRAYLENGTH    : genArrayLength(); break;
+            case ATHROW         : genThrow(); break;
+            case CHECKCAST      : genCheckCast(); break;
+            case INSTANCEOF     : genInstanceOf(); break;
+            case MONITORENTER   : genMonitorEnter(frameState.pop(JavaKind.Object), stream.nextBCI()); break;
+            case MONITOREXIT    : genMonitorExit(frameState.pop(JavaKind.Object), null, stream.nextBCI()); break;
+            case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
+            case IFNULL         : genIfNull(Condition.EQ); break;
+            case IFNONNULL      : genIfNull(Condition.NE); break;
+            case GOTO_W         : genGoto(); break;
+            case JSR_W          : genJsr(stream.readBranchDest()); break;
+            case BREAKPOINT     : throw new PermanentBailoutException("concurrent setting of breakpoint");
+            default             : throw new PermanentBailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
+        }
+        // @formatter:on
+        // Checkstyle: resume
+    }
+
+    private void genArrayLength() {
+        ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), null);
+        frameState.push(JavaKind.Int, append(genArrayLength(array)));
+    }
+
+    @Override
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    @Override
+    public Bytecode getCode() {
+        return code;
+    }
+
+    public FrameStateBuilder getFrameStateBuilder() {
+        return frameState;
+    }
+
+    protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
+        if (Debug.isEnabled() && BytecodeParserOptions.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
+            traceInstructionHelper(bci, opcode, blockStart);
+        }
+        return true;
+    }
+
+    private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
+        StringBuilder sb = new StringBuilder(40);
+        sb.append(blockStart ? '+' : '|');
+        if (bci < 10) {
+            sb.append("  ");
+        } else if (bci < 100) {
+            sb.append(' ');
+        }
+        sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode));
+        for (int i = bci + 1; i < stream.nextBCI(); ++i) {
+            sb.append(' ').append(stream.readUByte(i));
+        }
+        if (!currentBlock.getJsrScope().isEmpty()) {
+            sb.append(' ').append(currentBlock.getJsrScope());
+        }
+        Debug.log("%s", sb);
+    }
+
+    @Override
+    public boolean parsingIntrinsic() {
+        return intrinsicContext != null;
+    }
+
+    @Override
+    public BytecodeParser getNonIntrinsicAncestor() {
+        BytecodeParser ancestor = parent;
+        while (ancestor != null && ancestor.parsingIntrinsic()) {
+            ancestor = ancestor.parent;
+        }
+        return ancestor;
+    }
+
+    static String nSpaces(int n) {
+        return n == 0 ? "" : format("%" + n + "s", "");
+    }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java
new file mode 100644
index 0000000..9328c76
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+
+/**
+ * Options related to {@link BytecodeParser}.
+ *
+ * Note: This must be a top level class to work around for
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=477597">Eclipse bug 477597</a>.
+ */
+public class BytecodeParserOptions {
+    // @formatter:off
+    @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
+    public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
+
+    @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
+    public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(true);
+
+    @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
+    public static final StableOptionValue<Boolean> InlineIntrinsicsDuringParsing = new StableOptionValue<>(true);
+
+    @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
+
+    @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
+
+    @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
+    public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
+
+    @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
+    @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> HideSubstitutionStates = new OptionValue<>(false);
+
+    @Option(help = "Use intrinsics guarded by a virtual dispatch test at indirect call sites.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> UseGuardedIntrinsics = new OptionValue<>(true);
+    // @formatter:on
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java
new file mode 100644
index 0000000..c2cc0ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
+
+public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure<Double> {
+
+    private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure();
+
+    private ComputeLoopFrequenciesClosure() {
+        // nothing to do
+    }
+
+    @Override
+    protected Double processNode(FixedNode node, Double currentState) {
+        // normal nodes never change the probability of a path
+        return currentState;
+    }
+
+    @Override
+    protected Double merge(AbstractMergeNode merge, List<Double> states) {
+        // a merge has the sum of all predecessor probabilities
+        return states.stream().collect(Collectors.summingDouble(d -> d));
+    }
+
+    @Override
+    protected Double afterSplit(AbstractBeginNode node, Double oldState) {
+        // a control split splits up the probability
+        ControlSplitNode split = (ControlSplitNode) node.predecessor();
+        return oldState * split.probability(node);
+    }
+
+    @Override
+    protected Map<LoopExitNode, Double> processLoop(LoopBeginNode loop, Double initialState) {
+        Map<LoopExitNode, Double> exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates;
+
+        double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum();
+        exitProbability = Math.min(1D, exitProbability);
+        if (exitProbability < ControlFlowGraph.MIN_PROBABILITY) {
+            exitProbability = ControlFlowGraph.MIN_PROBABILITY;
+        }
+        assert exitProbability <= 1D && exitProbability >= 0D;
+        double loopFrequency = 1D / exitProbability;
+        loop.setLoopFrequency(loopFrequency);
+
+        double adjustmentFactor = initialState * loopFrequency;
+        exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor));
+
+        return exitStates;
+    }
+
+    /**
+     * Multiplies a and b and saturates the result to {@link ControlFlowGraph#MAX_PROBABILITY}.
+     */
+    public static double multiplySaturate(double a, double b) {
+        double r = a * b;
+        if (r > ControlFlowGraph.MAX_PROBABILITY) {
+            return ControlFlowGraph.MAX_PROBABILITY;
+        }
+        return r;
+    }
+
+    /**
+     * Computes the frequencies of all loops in the given graph. This is done by performing a
+     * reverse postorder iteration and computing the probability of all fixed nodes. The combined
+     * probability of all exits of a loop can be used to compute the loop's expected frequency.
+     */
+    public static void compute(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            ReentrantNodeIterator.apply(INSTANCE, graph.start(), 1D);
+        }
+    }
+
+    public static class ComputeLoopFrequencyPhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            compute(graph);
+        }
+    }
+
+    public static final ComputeLoopFrequencyPhase PHASE_INSTANCE = new ComputeLoopFrequencyPhase();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/DefaultSuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/DefaultSuitesProvider.java
new file mode 100644
index 0000000..8be604a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/DefaultSuitesProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+public class DefaultSuitesProvider extends SuitesProviderBase {
+
+    private final CompilerConfiguration compilerConfiguration;
+
+    public DefaultSuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super();
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite(plugins);
+        this.compilerConfiguration = compilerConfiguration;
+    }
+
+    @Override
+    public Suites createSuites() {
+        return Suites.createSuites(compilerConfiguration);
+    }
+
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite(Plugins plugins) {
+        PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
+        suite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(plugins)));
+        return suite;
+    }
+
+    @Override
+    public LIRSuites createLIRSuites() {
+        return Suites.createLIRSuites(compilerConfiguration);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java
new file mode 100644
index 0000000..092d213d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java
@@ -0,0 +1,1000 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2;
+import static org.graalvm.compiler.bytecode.Bytecodes.POP;
+import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
+import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
+import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates;
+import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState;
+import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+public final class FrameStateBuilder implements SideEffectsState {
+
+    private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+
+    private final BytecodeParser parser;
+    private final GraphBuilderTool tool;
+    private final Bytecode code;
+    private int stackSize;
+    protected final ValueNode[] locals;
+    protected final ValueNode[] stack;
+    private ValueNode[] lockedObjects;
+    private boolean canVerifyKind;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    private boolean rethrowException;
+
+    private MonitorIdNode[] monitorIds;
+    private final StructuredGraph graph;
+    private FrameState outerFrameState;
+
+    /**
+     * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
+     * than one when the current block contains no side-effects but merging predecessor blocks do.
+     */
+    private List<StateSplit> sideEffects;
+
+    private JavaConstant constantReceiver;
+
+    /**
+     * Creates a new frame state builder for the given method and the given target graph.
+     *
+     * @param method the method whose frame is simulated
+     * @param graph the target graph of Graal nodes created by the builder
+     */
+    public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) {
+        this(tool, new ResolvedJavaMethodBytecode(method), graph);
+    }
+
+    /**
+     * Creates a new frame state builder for the given code attribute, method and the given target
+     * graph.
+     *
+     * @param code the bytecode in which the frame exists
+     * @param graph the target graph of Graal nodes created by the builder
+     */
+    public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph) {
+        this.tool = tool;
+        if (tool instanceof BytecodeParser) {
+            this.parser = (BytecodeParser) tool;
+        } else {
+            this.parser = null;
+        }
+        this.code = code;
+        this.locals = allocateArray(code.getMaxLocals());
+        this.stack = allocateArray(Math.max(1, code.getMaxStackSize()));
+        this.lockedObjects = allocateArray(0);
+
+        assert graph != null;
+
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
+        this.graph = graph;
+        this.canVerifyKind = true;
+    }
+
+    public void disableKindVerification() {
+        canVerifyKind = false;
+    }
+
+    public void initializeFromArgumentsArray(ValueNode[] arguments) {
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!getMethod().isStatic()) {
+            // set the receiver
+            locals[javaIndex] = arguments[index];
+            javaIndex = 1;
+            index = 1;
+            constantReceiver = locals[0].asJavaConstant();
+        }
+        Signature sig = getMethod().getSignature();
+        int max = sig.getParameterCount(false);
+        for (int i = 0; i < max; i++) {
+            JavaKind kind = sig.getParameterKind(i);
+            locals[javaIndex] = arguments[index];
+            javaIndex++;
+            if (kind.needsTwoSlots()) {
+                locals[javaIndex] = TWO_SLOT_MARKER;
+                javaIndex++;
+            }
+            index++;
+        }
+    }
+
+    public void initializeForMethodStart(Assumptions assumptions, boolean eagerResolve, Plugins plugins) {
+
+        int javaIndex = 0;
+        int index = 0;
+        ResolvedJavaMethod method = getMethod();
+        ResolvedJavaType originalType = method.getDeclaringClass();
+        if (!method.isStatic()) {
+            // add the receiver
+            FloatingNode receiver = null;
+            StampPair receiverStamp = null;
+            if (plugins != null) {
+                receiverStamp = plugins.getOverridingStamp(tool, originalType, true);
+            }
+            if (receiverStamp == null) {
+                receiverStamp = StampFactory.forDeclaredType(assumptions, originalType, true);
+            }
+
+            if (plugins != null) {
+                for (ParameterPlugin plugin : plugins.getParameterPlugins()) {
+                    receiver = plugin.interceptParameter(tool, index, receiverStamp);
+                    if (receiver != null) {
+                        break;
+                    }
+                }
+            }
+            if (receiver == null) {
+                receiver = new ParameterNode(javaIndex, receiverStamp);
+            }
+
+            locals[javaIndex] = graph.addOrUnique(receiver);
+            javaIndex = 1;
+            index = 1;
+        }
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        ResolvedJavaType accessingClass = originalType;
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass);
+            if (eagerResolve) {
+                type = type.resolve(accessingClass);
+            }
+            JavaKind kind = type.getJavaKind();
+            StampPair stamp = null;
+            if (plugins != null) {
+                stamp = plugins.getOverridingStamp(tool, type, false);
+            }
+            if (stamp == null) {
+                stamp = StampFactory.forDeclaredType(assumptions, type, false);
+            }
+
+            FloatingNode param = null;
+            if (plugins != null) {
+                for (ParameterPlugin plugin : plugins.getParameterPlugins()) {
+                    param = plugin.interceptParameter(tool, index, stamp);
+                    if (param != null) {
+                        break;
+                    }
+                }
+            }
+            if (param == null) {
+                param = new ParameterNode(index, stamp);
+            }
+
+            locals[javaIndex] = graph.addOrUnique(param);
+            javaIndex++;
+            if (kind.needsTwoSlots()) {
+                locals[javaIndex] = TWO_SLOT_MARKER;
+                javaIndex++;
+            }
+            index++;
+        }
+    }
+
+    private FrameStateBuilder(FrameStateBuilder other) {
+        this.parser = other.parser;
+        this.tool = other.tool;
+        this.code = other.code;
+        this.stackSize = other.stackSize;
+        this.locals = other.locals.clone();
+        this.stack = other.stack.clone();
+        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
+        this.rethrowException = other.rethrowException;
+        this.canVerifyKind = other.canVerifyKind;
+
+        assert locals.length == code.getMaxLocals();
+        assert stack.length == Math.max(1, code.getMaxStackSize());
+
+        assert other.graph != null;
+        graph = other.graph;
+        monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
+
+        assert locals.length == code.getMaxLocals();
+        assert stack.length == Math.max(1, code.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    private static ValueNode[] allocateArray(int length) {
+        return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return code.getMethod();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[locals: [");
+        for (int i = 0; i < locals.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i] == TWO_SLOT_MARKER ? "#" : locals[i].toString(Verbosity.Id));
+        }
+        sb.append("] stack: [");
+        for (int i = 0; i < stackSize; i++) {
+            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i] == TWO_SLOT_MARKER ? "#" : stack[i].toString(Verbosity.Id));
+        }
+        sb.append("] locks: [");
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
+        }
+        sb.append("]");
+        if (rethrowException) {
+            sb.append(" rethrowException");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public FrameState create(int bci, StateSplit forStateSplit) {
+        if (parser != null && parser.parsingIntrinsic()) {
+            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit);
+        }
+
+        // Skip intrinsic frames
+        return create(bci, parser != null ? parser.getNonIntrinsicAncestor() : null, false, null, null);
+    }
+
+    /**
+     * @param pushedValues if non-null, values to {@link #push(JavaKind, ValueNode)} to the stack
+     *            before creating the {@link FrameState}
+     */
+    public FrameState create(int bci, BytecodeParser parent, boolean duringCall, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        if (outerFrameState == null && parent != null) {
+            assert !parent.parsingIntrinsic() : "must already have the next non-intrinsic ancestor";
+            outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), parent.getNonIntrinsicAncestor(), true, null, null);
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, false, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{stack[0]});
+            return newFrameState;
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw shouldNotReachHere();
+        }
+
+        if (pushedValues != null) {
+            assert pushedSlotKinds.length == pushedValues.length;
+            int stackSizeToRestore = stackSize;
+            for (int i = 0; i < pushedValues.length; i++) {
+                push(pushedSlotKinds[i], pushedValues[i]);
+            }
+            FrameState res = graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+            stackSize = stackSizeToRestore;
+            return res;
+        } else {
+            if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                assert outerFrameState == null;
+                clearLocals();
+            }
+            return graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+        }
+    }
+
+    public NodeSourcePosition createBytecodePosition(int bci) {
+        BytecodeParser parent = parser.getParent();
+        if (HideSubstitutionStates.getValue()) {
+            if (parser.parsingIntrinsic()) {
+                // Attribute to the method being replaced
+                return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
+            }
+            // Skip intrinsic frames
+            parent = parser.getNonIntrinsicAncestor();
+        }
+        return create(null, constantReceiver, bci, parent);
+    }
+
+    private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent) {
+        NodeSourcePosition outer = o;
+        if (outer == null && parent != null) {
+            outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            return FrameState.toSourcePosition(outerFrameState);
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw shouldNotReachHere();
+        }
+        return new NodeSourcePosition(receiver, outer, code.getMethod(), bci);
+    }
+
+    public FrameStateBuilder copy() {
+        return new FrameStateBuilder(this);
+    }
+
+    public boolean isCompatibleWith(FrameStateBuilder other) {
+        assert code.equals(other.code) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
+
+        if (stackSize() != other.stackSize()) {
+            return false;
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode x = stack[i];
+            ValueNode y = other.stack[i];
+            assert x != null && y != null;
+            if (x != y && (x == TWO_SLOT_MARKER || x.isDeleted() || y == TWO_SLOT_MARKER || y.isDeleted() || x.getStackKind() != y.getStackKind())) {
+                return false;
+            }
+        }
+        if (lockedObjects.length != other.lockedObjects.length) {
+            return false;
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
+                throw new PermanentBailoutException("unbalanced monitors");
+            }
+        }
+        return true;
+    }
+
+    public void merge(AbstractMergeNode block, FrameStateBuilder other) {
+        assert isCompatibleWith(other);
+
+        for (int i = 0; i < localsSize(); i++) {
+            locals[i] = merge(locals[i], other.locals[i], block);
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            stack[i] = merge(stack[i], other.stack[i], block);
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
+            assert monitorIds[i] == other.monitorIds[i];
+        }
+
+        if (sideEffects == null) {
+            sideEffects = other.sideEffects;
+        } else {
+            if (other.sideEffects != null) {
+                sideEffects.addAll(other.sideEffects);
+            }
+        }
+    }
+
+    private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        if (currentValue == null || currentValue.isDeleted()) {
+            return null;
+        } else if (block.isPhiAtMerge(currentValue)) {
+            if (otherValue == null || otherValue == TWO_SLOT_MARKER || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) {
+                // This phi must be dead anyway, add input of correct stack kind to keep the graph
+                // invariants.
+                ((PhiNode) currentValue).addInput(ConstantNode.defaultForKind(currentValue.getStackKind(), graph));
+            } else {
+                ((PhiNode) currentValue).addInput(otherValue);
+            }
+            return currentValue;
+        } else if (currentValue != otherValue) {
+            if (currentValue == TWO_SLOT_MARKER || otherValue == TWO_SLOT_MARKER) {
+                return null;
+            } else if (otherValue == null || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) {
+                return null;
+            }
+            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
+            return createValuePhi(currentValue, otherValue, block);
+        } else {
+            return currentValue;
+        }
+    }
+
+    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
+        for (int i = 0; i < block.phiPredecessorCount(); i++) {
+            phi.addInput(currentValue);
+        }
+        phi.addInput(otherValue);
+        assert phi.valueCount() == block.phiPredecessorCount() + 1;
+        return phi;
+    }
+
+    public void inferPhiStamps(AbstractMergeNode block) {
+        for (int i = 0; i < localsSize(); i++) {
+            inferPhiStamp(block, locals[i]);
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            inferPhiStamp(block, stack[i]);
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            inferPhiStamp(block, lockedObjects[i]);
+        }
+    }
+
+    private static void inferPhiStamp(AbstractMergeNode block, ValueNode node) {
+        if (block.isPhiAtMerge(node)) {
+            node.inferStamp();
+        }
+    }
+
+    public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis, boolean stampFromValueForForcedPhis) {
+        for (int i = 0; i < localsSize(); i++) {
+            boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i);
+            if (forcePhis || changedInLoop) {
+                locals[i] = createLoopPhi(loopBegin, locals[i], stampFromValueForForcedPhis && !changedInLoop);
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            stack[i] = createLoopPhi(loopBegin, stack[i], false);
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false);
+        }
+    }
+
+    public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = locals[i];
+            if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                locals[i] = ProxyNode.forValue(value, loopExit, graph);
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stack[i];
+            if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                stack[i] = ProxyNode.forValue(value, loopExit, graph);
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
+            }
+        }
+    }
+
+    public void insertProxies(Function<ValueNode, ValueNode> proxyFunction) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = locals[i];
+            if (value != null && value != TWO_SLOT_MARKER) {
+                Debug.log(" inserting proxy for %s", value);
+                locals[i] = proxyFunction.apply(value);
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stack[i];
+            if (value != null && value != TWO_SLOT_MARKER) {
+                Debug.log(" inserting proxy for %s", value);
+                stack[i] = proxyFunction.apply(value);
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = proxyFunction.apply(value);
+            }
+        }
+    }
+
+    private ValueNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) {
+        if (value == null || value == TWO_SLOT_MARKER) {
+            return value;
+        }
+        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
+
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block));
+        phi.addInput(value);
+        return phi;
+    }
+
+    /**
+     * Adds a locked monitor to this frame state.
+     *
+     * @param object the object whose monitor will be locked.
+     */
+    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
+        assert object.isAlive() && object.getStackKind() == JavaKind.Object : "unexpected value: " + object;
+        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
+        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
+        lockedObjects[lockedObjects.length - 1] = object;
+        monitorIds[monitorIds.length - 1] = monitorId;
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    /**
+     * Removes a locked monitor from this frame state.
+     *
+     * @return the object whose monitor was removed from the locks list.
+     */
+    public ValueNode popLock() {
+        try {
+            return lockedObjects[lockedObjects.length - 1];
+        } finally {
+            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
+            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
+        }
+    }
+
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
+    /**
+     * @return the current lock depth
+     */
+    public int lockDepth(boolean includeParents) {
+        int depth = lockedObjects.length;
+        assert depth == monitorIds.length;
+        if (includeParents && parser.getParent() != null) {
+            depth += parser.getParent().frameState.lockDepth(true);
+        }
+        return depth;
+    }
+
+    public boolean contains(ValueNode value) {
+        for (int i = 0; i < localsSize(); i++) {
+            if (locals[i] == value) {
+                return true;
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (stack[i] == value) {
+                return true;
+            }
+        }
+        assert lockedObjects.length == monitorIds.length;
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (lockedObjects[i] == value || monitorIds[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
+        if (!parser.graphBuilderConfig.clearNonLiveLocals()) {
+            return;
+        }
+        if (liveIn) {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveIn(block, i)) {
+                    assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
+                    locals[i] = null;
+                }
+            }
+        } else {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveOut(block, i)) {
+                    assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
+                    locals[i] = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Clears all local variables.
+     */
+    public void clearLocals() {
+        for (int i = 0; i < locals.length; i++) {
+            locals[i] = null;
+        }
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public boolean rethrowException() {
+        return rethrowException;
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public void setRethrowException(boolean b) {
+        rethrowException = b;
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public int localsSize() {
+        return locals.length;
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackSize;
+    }
+
+    private boolean verifyKind(JavaKind slotKind, ValueNode x) {
+        assert x != null;
+        assert x != TWO_SLOT_MARKER;
+        assert slotKind.getSlotCount() > 0;
+
+        if (canVerifyKind) {
+            assert x.getStackKind() == slotKind.getStackKind();
+        }
+        return true;
+    }
+
+    /**
+     * Loads the local variable at the specified index, checking that the returned value is non-null
+     * and that two-stack values are properly handled.
+     *
+     * @param i the index of the local variable to load
+     * @param slotKind the kind of the local variable from the point of view of the bytecodes
+     * @return the instruction that produced the specified local
+     */
+    public ValueNode loadLocal(int i, JavaKind slotKind) {
+        ValueNode x = locals[i];
+        assert verifyKind(slotKind, x);
+        assert slotKind.needsTwoSlots() ? locals[i + 1] == TWO_SLOT_MARKER : (i == locals.length - 1 || locals[i + 1] != TWO_SLOT_MARKER);
+        return x;
+    }
+
+    /**
+     * Stores a given local variable at the specified index. If the value occupies two slots, then
+     * the next local variable index is also overwritten.
+     *
+     * @param i the index at which to store
+     * @param slotKind the kind of the local variable from the point of view of the bytecodes
+     * @param x the instruction which produces the value for the local
+     */
+    public void storeLocal(int i, JavaKind slotKind, ValueNode x) {
+        assert verifyKind(slotKind, x);
+
+        if (locals[i] == TWO_SLOT_MARKER) {
+            /* Writing the second slot of a two-slot value invalidates the first slot. */
+            locals[i - 1] = null;
+        }
+        locals[i] = x;
+        if (slotKind.needsTwoSlots()) {
+            /* Writing a two-slot value: mark the second slot. */
+            locals[i + 1] = TWO_SLOT_MARKER;
+        } else if (i < locals.length - 1 && locals[i + 1] == TWO_SLOT_MARKER) {
+            /*
+             * Writing a one-slot value to an index previously occupied by a two-slot value: clear
+             * the old marker of the second slot.
+             */
+            locals[i + 1] = null;
+        }
+    }
+
+    /**
+     * Pushes an instruction onto the stack with the expected type.
+     *
+     * @param slotKind the kind of the stack element from the point of view of the bytecodes
+     * @param x the instruction to push onto the stack
+     */
+    public void push(JavaKind slotKind, ValueNode x) {
+        assert verifyKind(slotKind, x);
+
+        xpush(x);
+        if (slotKind.needsTwoSlots()) {
+            xpush(TWO_SLOT_MARKER);
+        }
+    }
+
+    public void pushReturn(JavaKind slotKind, ValueNode x) {
+        if (slotKind != JavaKind.Void) {
+            push(slotKind, x);
+        }
+    }
+
+    /**
+     * Pops an instruction off the stack with the expected type.
+     *
+     * @param slotKind the kind of the stack element from the point of view of the bytecodes
+     * @return the instruction on the top of the stack
+     */
+    public ValueNode pop(JavaKind slotKind) {
+        if (slotKind.needsTwoSlots()) {
+            ValueNode s = xpop();
+            assert s == TWO_SLOT_MARKER;
+        }
+        ValueNode x = xpop();
+        assert verifyKind(slotKind, x);
+        return x;
+    }
+
+    private void xpush(ValueNode x) {
+        assert x != null;
+        stack[stackSize++] = x;
+    }
+
+    private ValueNode xpop() {
+        ValueNode result = stack[--stackSize];
+        assert result != null;
+        return result;
+    }
+
+    private ValueNode xpeek() {
+        ValueNode result = stack[stackSize - 1];
+        assert result != null;
+        return result;
+    }
+
+    /**
+     * Pop the specified number of slots off of this stack and return them as an array of
+     * instructions.
+     *
+     * @return an array containing the arguments off of the stack
+     */
+    public ValueNode[] popArguments(int argSize) {
+        ValueNode[] result = allocateArray(argSize);
+        for (int i = argSize - 1; i >= 0; i--) {
+            ValueNode x = xpop();
+            if (x == TWO_SLOT_MARKER) {
+                /* Ignore second slot of two-slot value. */
+                x = xpop();
+            }
+            assert x != null && x != TWO_SLOT_MARKER;
+            result[i] = x;
+        }
+        return result;
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackSize = 0;
+    }
+
+    /**
+     * Performs a raw stack operation as defined in the Java bytecode specification.
+     *
+     * @param opcode The Java bytecode.
+     */
+    public void stackOp(int opcode) {
+        switch (opcode) {
+            case POP: {
+                ValueNode w1 = xpop();
+                assert w1 != TWO_SLOT_MARKER;
+                break;
+            }
+            case POP2: {
+                xpop();
+                ValueNode w2 = xpop();
+                assert w2 != TWO_SLOT_MARKER;
+                break;
+            }
+            case DUP: {
+                ValueNode w1 = xpeek();
+                assert w1 != TWO_SLOT_MARKER;
+                xpush(w1);
+                break;
+            }
+            case DUP_X1: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                assert w1 != TWO_SLOT_MARKER;
+                xpush(w1);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP_X2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                assert w1 != TWO_SLOT_MARKER;
+                xpush(w1);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2_X1: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2_X2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                ValueNode w4 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w4);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case SWAP: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                assert w1 != TWO_SLOT_MARKER;
+                assert w2 != TWO_SLOT_MARKER;
+                xpush(w1);
+                xpush(w2);
+                break;
+            }
+            default:
+                throw shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        int result = hashCode(locals, locals.length);
+        result *= 13;
+        result += hashCode(stack, this.stackSize);
+        return result;
+    }
+
+    private static int hashCode(Object[] a, int length) {
+        int result = 1;
+        for (int i = 0; i < length; ++i) {
+            Object element = a[i];
+            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
+        }
+        return result;
+    }
+
+    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
+        for (int i = 0; i < length; ++i) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object otherObject) {
+        if (otherObject instanceof FrameStateBuilder) {
+            FrameStateBuilder other = (FrameStateBuilder) otherObject;
+            if (!other.code.equals(code)) {
+                return false;
+            }
+            if (other.stackSize != stackSize) {
+                return false;
+            }
+            if (other.parser != parser) {
+                return false;
+            }
+            if (other.tool != tool) {
+                return false;
+            }
+            if (other.rethrowException != rethrowException) {
+                return false;
+            }
+            if (other.graph != graph) {
+                return false;
+            }
+            if (other.locals.length != locals.length) {
+                return false;
+            }
+            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
+                            equals(other.monitorIds, monitorIds, monitorIds.length);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isAfterSideEffect() {
+        return sideEffects != null;
+    }
+
+    @Override
+    public Iterable<StateSplit> sideEffects() {
+        return sideEffects;
+    }
+
+    @Override
+    public void addSideEffect(StateSplit sideEffect) {
+        assert sideEffect != null;
+        assert sideEffect.hasSideEffect();
+        if (sideEffects == null) {
+            sideEffects = new ArrayList<>(4);
+        }
+        sideEffects.add(sideEffect);
+    }
+
+    public void traceState() {
+        Debug.log("|   state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod());
+        for (int i = 0; i < localsSize(); ++i) {
+            ValueNode value = locals[i];
+            Debug.log("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
+        }
+        for (int i = 0; i < stackSize(); ++i) {
+            ValueNode value = stack[i];
+            Debug.log("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java
new file mode 100644
index 0000000..78cf010
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Parses the bytecodes of a method and builds the IR graph.
+ */
+public class GraphBuilderPhase extends BasePhase<HighTierContext> {
+
+    private final GraphBuilderConfiguration graphBuilderConfig;
+
+    public GraphBuilderPhase(GraphBuilderConfiguration config) {
+        this.graphBuilderConfig = config;
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, HighTierContext context) {
+        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getConstantReflection(), context.getConstantFieldProvider(), graphBuilderConfig, context.getOptimisticOptimizations(),
+                        null).run(graph);
+    }
+
+    public GraphBuilderConfiguration getGraphBuilderConfig() {
+        return graphBuilderConfig;
+    }
+
+    // Fully qualified name is a workaround for JDK-8056066
+    public static class Instance extends org.graalvm.compiler.phases.Phase {
+
+        protected final MetaAccessProvider metaAccess;
+        protected final StampProvider stampProvider;
+        protected final ConstantReflectionProvider constantReflection;
+        protected final ConstantFieldProvider constantFieldProvider;
+        protected final GraphBuilderConfiguration graphBuilderConfig;
+        protected final OptimisticOptimizations optimisticOpts;
+        private final IntrinsicContext initialIntrinsicContext;
+
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+            this.graphBuilderConfig = graphBuilderConfig;
+            this.optimisticOpts = optimisticOpts;
+            this.metaAccess = metaAccess;
+            this.stampProvider = stampProvider;
+            this.constantReflection = constantReflection;
+            this.constantFieldProvider = constantFieldProvider;
+            this.initialIntrinsicContext = initialIntrinsicContext;
+        }
+
+        @Override
+        public boolean checkContract() {
+            return false;
+        }
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            createBytecodeParser(graph, null, graph.method(), graph.getEntryBCI(), initialIntrinsicContext).buildRootMethod();
+        }
+
+        /* Hook for subclasses of Instance to provide a subclass of BytecodeParser. */
+        protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) {
+            return new BytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrNotSupportedBailout.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrNotSupportedBailout.java
new file mode 100644
index 0000000..8baadb6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrNotSupportedBailout.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+
+public class JsrNotSupportedBailout extends PermanentBailoutException {
+
+    private static final long serialVersionUID = -7476925652727154272L;
+
+    public JsrNotSupportedBailout(String reason) {
+        super(reason);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java
new file mode 100644
index 0000000..1a526f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+public class JsrScope {
+
+    public static final JsrScope EMPTY_SCOPE = new JsrScope();
+
+    private final long scope;
+
+    private JsrScope(long scope) {
+        this.scope = scope;
+    }
+
+    public JsrScope() {
+        this.scope = 0;
+    }
+
+    public int nextReturnAddress() {
+        return (int) (scope & 0xffff);
+    }
+
+    public JsrScope push(int jsrReturnBci) {
+        if ((scope & 0xffff000000000000L) != 0) {
+            throw new JsrNotSupportedBailout("only four jsr nesting levels are supported");
+        }
+        return new JsrScope((scope << 16) | jsrReturnBci);
+    }
+
+    public boolean isEmpty() {
+        return scope == 0;
+    }
+
+    public boolean isPrefixOf(JsrScope other) {
+        return (scope & other.scope) == scope;
+    }
+
+    public JsrScope pop() {
+        return new JsrScope(scope >>> 16);
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (scope ^ (scope >>> 32));
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        return obj != null && getClass() == obj.getClass() && scope == ((JsrScope) obj).scope;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        long tmp = scope;
+        sb.append(" [");
+        while (tmp != 0) {
+            sb.append(", ").append(tmp & 0xffff);
+            tmp = tmp >>> 16;
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LargeLocalLiveness.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LargeLocalLiveness.java
new file mode 100644
index 0000000..6b7438d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LargeLocalLiveness.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+
+public final class LargeLocalLiveness extends LocalLiveness {
+    private BitSet[] localsLiveIn;
+    private BitSet[] localsLiveOut;
+    private BitSet[] localsLiveGen;
+    private BitSet[] localsLiveKill;
+    private BitSet[] localsChangedInLoop;
+
+    public LargeLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) {
+        super(blocks);
+        int blocksSize = blocks.length;
+        localsLiveIn = new BitSet[blocksSize];
+        localsLiveOut = new BitSet[blocksSize];
+        localsLiveGen = new BitSet[blocksSize];
+        localsLiveKill = new BitSet[blocksSize];
+        for (int i = 0; i < blocksSize; i++) {
+            localsLiveIn[i] = new BitSet(maxLocals);
+            localsLiveOut[i] = new BitSet(maxLocals);
+            localsLiveGen[i] = new BitSet(maxLocals);
+            localsLiveKill[i] = new BitSet(maxLocals);
+        }
+        localsChangedInLoop = new BitSet[loopCount];
+        for (int i = 0; i < loopCount; ++i) {
+            localsChangedInLoop[i] = new BitSet(maxLocals);
+        }
+    }
+
+    @Override
+    protected String debugLiveIn(int blockID) {
+        return localsLiveIn[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveOut(int blockID) {
+        return localsLiveOut[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveGen(int blockID) {
+        return localsLiveGen[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveKill(int blockID) {
+        return localsLiveKill[blockID].toString();
+    }
+
+    @Override
+    protected int liveOutCardinality(int blockID) {
+        return localsLiveOut[blockID].cardinality();
+    }
+
+    @Override
+    protected void propagateLiveness(int blockID, int successorID) {
+        localsLiveOut[blockID].or(localsLiveIn[successorID]);
+    }
+
+    @Override
+    protected void updateLiveness(int blockID) {
+        BitSet liveIn = localsLiveIn[blockID];
+        liveIn.clear();
+        liveIn.or(localsLiveOut[blockID]);
+        liveIn.andNot(localsLiveKill[blockID]);
+        liveIn.or(localsLiveGen[blockID]);
+    }
+
+    @Override
+    protected void loadOne(int blockID, int local) {
+        if (!localsLiveKill[blockID].get(local)) {
+            localsLiveGen[blockID].set(local);
+        }
+    }
+
+    @Override
+    protected void storeOne(int blockID, int local) {
+        if (!localsLiveGen[blockID].get(local)) {
+            localsLiveKill[blockID].set(local);
+        }
+
+        BciBlock block = blocks[blockID];
+        long tmp = block.loops;
+        int pos = 0;
+        while (tmp != 0) {
+            if ((tmp & 1L) == 1L) {
+                this.localsChangedInLoop[pos].set(local);
+            }
+            tmp >>>= 1;
+            ++pos;
+        }
+    }
+
+    @Override
+    public boolean localIsLiveIn(BciBlock block, int local) {
+        return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local);
+    }
+
+    @Override
+    public boolean localIsLiveOut(BciBlock block, int local) {
+        return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local);
+    }
+
+    @Override
+    public boolean localIsChangedInLoop(int loopId, int local) {
+        return localsChangedInLoop[loopId].get(local);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java
new file mode 100644
index 0000000..73b9f1d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.IINC;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3;
+import static org.graalvm.compiler.bytecode.Bytecodes.RET;
+
+import org.graalvm.compiler.bytecode.BytecodeStream;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+
+/**
+ * Encapsulates the liveness calculation, so that subclasses for locals &le; 64 and locals &gt; 64
+ * can be implemented.
+ */
+public abstract class LocalLiveness {
+    protected final BciBlock[] blocks;
+
+    public static LocalLiveness compute(BytecodeStream stream, BciBlock[] blocks, int maxLocals, int loopCount) {
+        LocalLiveness liveness = maxLocals <= 64 ? new SmallLocalLiveness(blocks, maxLocals, loopCount) : new LargeLocalLiveness(blocks, maxLocals, loopCount);
+        liveness.computeLiveness(stream);
+        return liveness;
+    }
+
+    protected LocalLiveness(BciBlock[] blocks) {
+        this.blocks = blocks;
+    }
+
+    void computeLiveness(BytecodeStream stream) {
+        for (BciBlock block : blocks) {
+            computeLocalLiveness(stream, block);
+        }
+
+        boolean changed;
+        int iteration = 0;
+        do {
+            assert traceIteration(iteration);
+            changed = false;
+            for (int i = blocks.length - 1; i >= 0; i--) {
+                BciBlock block = blocks[i];
+                int blockID = block.getId();
+                assert traceStart(block, blockID);
+
+                boolean blockChanged = (iteration == 0);
+                if (block.getSuccessorCount() > 0) {
+                    int oldCardinality = liveOutCardinality(blockID);
+                    for (BciBlock sux : block.getSuccessors()) {
+                        assert traceSuccessor(sux);
+                        propagateLiveness(blockID, sux.getId());
+                    }
+                    blockChanged |= (oldCardinality != liveOutCardinality(blockID));
+                }
+
+                if (blockChanged) {
+                    updateLiveness(blockID);
+                    assert traceEnd(block, blockID);
+                }
+                changed |= blockChanged;
+            }
+            iteration++;
+        } while (changed);
+    }
+
+    private static boolean traceIteration(int iteration) {
+        Debug.log("Iteration %d", iteration);
+        return true;
+    }
+
+    private boolean traceEnd(BciBlock block, int blockID) {
+        if (Debug.isLogEnabled()) {
+            Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID),
+                            debugLiveKill(blockID));
+        }
+        return true;
+    }
+
+    private boolean traceSuccessor(BciBlock sux) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
+        }
+        return true;
+    }
+
+    private boolean traceStart(BciBlock block, int blockID) {
+        if (Debug.isLogEnabled()) {
+            Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID),
+                            debugLiveKill(blockID));
+        }
+        return true;
+    }
+
+    /**
+     * Returns whether the local is live at the beginning of the given block.
+     */
+    public abstract boolean localIsLiveIn(BciBlock block, int local);
+
+    /**
+     * Returns whether the local is set in the given loop.
+     */
+    public abstract boolean localIsChangedInLoop(int loopId, int local);
+
+    /**
+     * Returns whether the local is live at the end of the given block.
+     */
+    public abstract boolean localIsLiveOut(BciBlock block, int local);
+
+    /**
+     * Returns a string representation of the liveIn values of the given block.
+     */
+    protected abstract String debugLiveIn(int blockID);
+
+    /**
+     * Returns a string representation of the liveOut values of the given block.
+     */
+    protected abstract String debugLiveOut(int blockID);
+
+    /**
+     * Returns a string representation of the liveGen values of the given block.
+     */
+    protected abstract String debugLiveGen(int blockID);
+
+    /**
+     * Returns a string representation of the liveKill values of the given block.
+     */
+    protected abstract String debugLiveKill(int blockID);
+
+    /**
+     * Returns the number of live locals at the end of the given block.
+     */
+    protected abstract int liveOutCardinality(int blockID);
+
+    /**
+     * Adds all locals the are in the liveIn of the successor to the liveOut of the block.
+     */
+    protected abstract void propagateLiveness(int blockID, int successorID);
+
+    /**
+     * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen.
+     */
+    protected abstract void updateLiveness(int blockID);
+
+    /**
+     * Adds the local to liveGen if it wasn't already killed in this block.
+     */
+    protected abstract void loadOne(int blockID, int local);
+
+    /**
+     * Add this local to liveKill if it wasn't already generated in this block.
+     */
+    protected abstract void storeOne(int blockID, int local);
+
+    private void computeLocalLiveness(BytecodeStream stream, BciBlock block) {
+        if (block.startBci < 0 || block.endBci < 0) {
+            return;
+        }
+        int blockID = block.getId();
+        int localIndex;
+        stream.setBCI(block.startBci);
+        while (stream.currentBCI() <= block.endBci) {
+            switch (stream.currentBC()) {
+                case LLOAD:
+                case DLOAD:
+                    loadTwo(blockID, stream.readLocalIndex());
+                    break;
+                case LLOAD_0:
+                case DLOAD_0:
+                    loadTwo(blockID, 0);
+                    break;
+                case LLOAD_1:
+                case DLOAD_1:
+                    loadTwo(blockID, 1);
+                    break;
+                case LLOAD_2:
+                case DLOAD_2:
+                    loadTwo(blockID, 2);
+                    break;
+                case LLOAD_3:
+                case DLOAD_3:
+                    loadTwo(blockID, 3);
+                    break;
+                case IINC:
+                    localIndex = stream.readLocalIndex();
+                    loadOne(blockID, localIndex);
+                    storeOne(blockID, localIndex);
+                    break;
+                case ILOAD:
+                case FLOAD:
+                case ALOAD:
+                case RET:
+                    loadOne(blockID, stream.readLocalIndex());
+                    break;
+                case ILOAD_0:
+                case FLOAD_0:
+                case ALOAD_0:
+                    loadOne(blockID, 0);
+                    break;
+                case ILOAD_1:
+                case FLOAD_1:
+                case ALOAD_1:
+                    loadOne(blockID, 1);
+                    break;
+                case ILOAD_2:
+                case FLOAD_2:
+                case ALOAD_2:
+                    loadOne(blockID, 2);
+                    break;
+                case ILOAD_3:
+                case FLOAD_3:
+                case ALOAD_3:
+                    loadOne(blockID, 3);
+                    break;
+
+                case LSTORE:
+                case DSTORE:
+                    storeTwo(blockID, stream.readLocalIndex());
+                    break;
+                case LSTORE_0:
+                case DSTORE_0:
+                    storeTwo(blockID, 0);
+                    break;
+                case LSTORE_1:
+                case DSTORE_1:
+                    storeTwo(blockID, 1);
+                    break;
+                case LSTORE_2:
+                case DSTORE_2:
+                    storeTwo(blockID, 2);
+                    break;
+                case LSTORE_3:
+                case DSTORE_3:
+                    storeTwo(blockID, 3);
+                    break;
+                case ISTORE:
+                case FSTORE:
+                case ASTORE:
+                    storeOne(blockID, stream.readLocalIndex());
+                    break;
+                case ISTORE_0:
+                case FSTORE_0:
+                case ASTORE_0:
+                    storeOne(blockID, 0);
+                    break;
+                case ISTORE_1:
+                case FSTORE_1:
+                case ASTORE_1:
+                    storeOne(blockID, 1);
+                    break;
+                case ISTORE_2:
+                case FSTORE_2:
+                case ASTORE_2:
+                    storeOne(blockID, 2);
+                    break;
+                case ISTORE_3:
+                case FSTORE_3:
+                case ASTORE_3:
+                    storeOne(blockID, 3);
+                    break;
+            }
+            stream.next();
+        }
+    }
+
+    private void loadTwo(int blockID, int local) {
+        loadOne(blockID, local);
+        loadOne(blockID, local + 1);
+    }
+
+    private void storeTwo(int blockID, int local) {
+        storeOne(blockID, local);
+        storeOne(blockID, local + 1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SmallLocalLiveness.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SmallLocalLiveness.java
new file mode 100644
index 0000000..a7f8b4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SmallLocalLiveness.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
+
+public final class SmallLocalLiveness extends LocalLiveness {
+    /*
+     * local n is represented by the bit accessible as (1 << n)
+     */
+
+    private final long[] localsLiveIn;
+    private final long[] localsLiveOut;
+    private final long[] localsLiveGen;
+    private final long[] localsLiveKill;
+    private final long[] localsChangedInLoop;
+    private final int maxLocals;
+
+    public SmallLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) {
+        super(blocks);
+        this.maxLocals = maxLocals;
+        int blockSize = blocks.length;
+        localsLiveIn = new long[blockSize];
+        localsLiveOut = new long[blockSize];
+        localsLiveGen = new long[blockSize];
+        localsLiveKill = new long[blockSize];
+        localsChangedInLoop = new long[loopCount];
+    }
+
+    private String debugString(long value) {
+        StringBuilder str = new StringBuilder("{");
+        long current = value;
+        for (int i = 0; i < maxLocals; i++) {
+            if ((current & 1L) == 1L) {
+                if (str.length() > 1) {
+                    str.append(", ");
+                }
+                str.append(i);
+            }
+            current >>= 1;
+        }
+        return str.append('}').toString();
+    }
+
+    @Override
+    protected String debugLiveIn(int blockID) {
+        return debugString(localsLiveIn[blockID]);
+    }
+
+    @Override
+    protected String debugLiveOut(int blockID) {
+        return debugString(localsLiveOut[blockID]);
+    }
+
+    @Override
+    protected String debugLiveGen(int blockID) {
+        return debugString(localsLiveGen[blockID]);
+    }
+
+    @Override
+    protected String debugLiveKill(int blockID) {
+        return debugString(localsLiveKill[blockID]);
+    }
+
+    @Override
+    protected int liveOutCardinality(int blockID) {
+        return Long.bitCount(localsLiveOut[blockID]);
+    }
+
+    @Override
+    protected void propagateLiveness(int blockID, int successorID) {
+        localsLiveOut[blockID] |= localsLiveIn[successorID];
+    }
+
+    @Override
+    protected void updateLiveness(int blockID) {
+        localsLiveIn[blockID] = (localsLiveOut[blockID] & ~localsLiveKill[blockID]) | localsLiveGen[blockID];
+    }
+
+    @Override
+    protected void loadOne(int blockID, int local) {
+        long bit = 1L << local;
+        if ((localsLiveKill[blockID] & bit) == 0L) {
+            localsLiveGen[blockID] |= bit;
+        }
+    }
+
+    @Override
+    protected void storeOne(int blockID, int local) {
+        long bit = 1L << local;
+        if ((localsLiveGen[blockID] & bit) == 0L) {
+            localsLiveKill[blockID] |= bit;
+        }
+
+        BciBlock block = blocks[blockID];
+        long tmp = block.loops;
+        int pos = 0;
+        while (tmp != 0) {
+            if ((tmp & 1L) == 1L) {
+                this.localsChangedInLoop[pos] |= bit;
+            }
+            tmp >>>= 1;
+            ++pos;
+        }
+    }
+
+    @Override
+    public boolean localIsLiveIn(BciBlock block, int local) {
+        int blockID = block.getId();
+        return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L;
+    }
+
+    @Override
+    public boolean localIsLiveOut(BciBlock block, int local) {
+        int blockID = block.getId();
+        return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L;
+    }
+
+    @Override
+    public boolean localIsChangedInLoop(int loopId, int local) {
+        return (localsChangedInLoop[loopId] & (1L << local)) != 0L;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SuitesProviderBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SuitesProviderBase.java
new file mode 100644
index 0000000..025fe1f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/SuitesProviderBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.java;
+
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.options.DerivedOptionValue;
+import org.graalvm.compiler.options.DerivedOptionValue.OptionSupplier;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.SuitesCreator;
+
+public abstract class SuitesProviderBase implements SuitesCreator {
+
+    protected final DerivedOptionValue<Suites> defaultSuites;
+    protected PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
+    protected final DerivedOptionValue<LIRSuites> defaultLIRSuites;
+
+    private class SuitesSupplier implements OptionSupplier<Suites> {
+
+        private static final long serialVersionUID = 2677805381215454728L;
+
+        @Override
+        public Suites get() {
+            Suites suites = createSuites();
+            suites.setImmutable();
+            return suites;
+        }
+
+    }
+
+    private class LIRSuitesSupplier implements OptionSupplier<LIRSuites> {
+
+        private static final long serialVersionUID = 312070237227476252L;
+
+        @Override
+        public LIRSuites get() {
+            LIRSuites lirSuites = createLIRSuites();
+            lirSuites.setImmutable();
+            return lirSuites;
+        }
+
+    }
+
+    public SuitesProviderBase() {
+        this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
+        this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
+    }
+
+    @Override
+    public final Suites getDefaultSuites() {
+        return defaultSuites.getValue();
+    }
+
+    @Override
+    public PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
+        return defaultGraphBuilderSuite;
+    }
+
+    @Override
+    public final LIRSuites getDefaultLIRSuites() {
+        return defaultLIRSuites.getValue();
+    }
+
+    @Override
+    public abstract LIRSuites createLIRSuites();
+
+    @Override
+    public abstract Suites createSuites();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java
new file mode 100644
index 0000000..d240fee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt;
+
+import static java.lang.reflect.Modifier.isStatic;
+
+import java.util.Collections;
+import java.util.Set;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+/**
+ * Base class for the JTT tests.
+ * <p>
+ * These tests are executed twice: once with arguments passed to the execution and once with the
+ * arguments bound to the test's parameters during compilation. The latter is a good test of
+ * canonicalization.
+ */
+public class JTTTest extends GraalCompilerTest {
+
+    public static final class DummyTestClass {
+    }
+
+    protected static final Set<DeoptimizationReason> EMPTY = Collections.<DeoptimizationReason> emptySet();
+    /**
+     * The arguments which, if non-null, will replace the Locals in the test method's graph.
+     */
+    Object[] argsToBind;
+
+    public JTTTest() {
+        Assert.assertNotNull(getCodeCache());
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId);
+        if (argsToBind != null) {
+            Object receiver = isStatic(m.getModifiers()) ? null : this;
+            Object[] args = argsWithReceiver(receiver, argsToBind);
+            JavaType[] parameterTypes = m.toParameterTypes();
+            assert parameterTypes.length == args.length;
+            for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+                JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
+                ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
+                param.replaceAtUsages(replacement);
+            }
+        }
+        return graph;
+    }
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
+        return super.getCode(method, graph, argsToBind != null);
+    }
+
+    Double delta;
+
+    @Override
+    protected void assertDeepEquals(Object expected, Object actual) {
+        if (delta != null) {
+            Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta);
+        } else {
+            super.assertDeepEquals(expected, actual);
+        }
+    }
+
+    @SuppressWarnings("hiding")
+    protected void runTestWithDelta(double delta, String name, Object... args) {
+        this.delta = Double.valueOf(delta);
+        runTest(name, args);
+    }
+
+    protected void runTest(String name, Object... args) {
+        runTest(EMPTY, name, args);
+    }
+
+    protected void runTest(Set<DeoptimizationReason> shouldNotDeopt, String name, Object... args) {
+        runTest(shouldNotDeopt, true, false, name, args);
+    }
+
+    protected void runTest(Set<DeoptimizationReason> shouldNotDeopt, boolean bind, boolean noProfile, String name, Object... args) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(name);
+        Object receiver = method.isStatic() ? null : this;
+
+        Result expect = executeExpected(method, receiver, args);
+
+        if (noProfile) {
+            method.reprofile();
+        }
+
+        testAgainstExpected(method, expect, shouldNotDeopt, receiver, args);
+        if (args.length > 0 && bind) {
+            if (noProfile) {
+                method.reprofile();
+            }
+
+            this.argsToBind = args;
+            testAgainstExpected(method, expect, shouldNotDeopt, receiver, args);
+            this.argsToBind = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/ConstantPhiTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/ConstantPhiTest.java
new file mode 100644
index 0000000..f358e10
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/ConstantPhiTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.backend;
+
+import static org.graalvm.compiler.api.directives.GraalDirectives.LIKELY_PROBABILITY;
+import static org.graalvm.compiler.api.directives.GraalDirectives.injectBranchProbability;
+
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+public class ConstantPhiTest extends JTTTest {
+
+    public static int test(int i, int x) throws Throwable {
+        int r;
+        if (injectBranchProbability(LIKELY_PROBABILITY, i < 0)) {
+            r = 42;
+        } else {
+            r = x;
+        }
+        destroyCallerSavedValues();
+        return r;
+    }
+
+    protected static void destroyCallerSavedValues() throws Throwable {
+        Class<ConstantPhiTest> c = ConstantPhiTest.class;
+        Method m = c.getMethod("destroyCallerSavedValues0");
+        m.invoke(null);
+    }
+
+    public static void destroyCallerSavedValues0() {
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void run0() {
+        try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) {
+            runTest("test", 0, 0xDEADDEAD);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void run1() {
+        try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) {
+            runTest("test", -1, 0xDEADDEAD);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void run2() {
+        try (OverrideScope os = OptionValue.override(GraalOptions.MaximumInliningSize, -1)) {
+            runTest("test", 1, 0xDEADDEAD);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/EmptyMethodTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/EmptyMethodTest.java
new file mode 100644
index 0000000..7ef53c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/EmptyMethodTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.backend;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class EmptyMethodTest extends JTTTest {
+
+    public static void test() {
+        GraalDirectives.spillRegisters();
+    }
+
+    @Test
+    public void run() {
+        runTest("test");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java
new file mode 100644
index 0000000..a48e6cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.backend;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.IFNE;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.LADD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LCMP;
+import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.test.ExportingClassLoader;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+
+public class LargeConstantSectionTest extends JTTTest {
+    private static final String NAME = "LargeConstantSection";
+    private static final long LARGE_CONSTANT = 0xF0F0F0F0F0L;
+    private static LargeConstantClassLoader LOADER;
+
+    @BeforeClass
+    public static void before() {
+        LOADER = new LargeConstantClassLoader(LargeConstantSectionTest.class.getClassLoader());
+    }
+
+    public abstract static class LargeConstantAbstract {
+        public abstract long run(long i);
+    }
+
+    public static long test(LargeConstantAbstract a, long i) throws Exception {
+        return a.run(GraalDirectives.opaque(i));
+    }
+
+    public static class LargeConstantClassLoader extends ExportingClassLoader {
+        public LargeConstantClassLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(NAME)) {
+                String graalDirectivesClassName = GraalDirectives.class.getName().replace('.', '/');
+                int numberIfBlocks = 1100; // Each if block contains three constants
+                ClassWriter cw = new ClassWriter(0);
+                MethodVisitor mv;
+                String abstractClassName = Type.getInternalName(LargeConstantAbstract.class);
+                cw.visit(52, ACC_PUBLIC + ACC_SUPER, NAME, null, abstractClassName, null);
+
+                mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+                mv.visitCode();
+                Label l0 = new Label();
+                mv.visitLabel(l0);
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitMethodInsn(INVOKESPECIAL, abstractClassName, "<init>", "()V", false);
+                mv.visitInsn(RETURN);
+                Label l1 = new Label();
+                mv.visitLabel(l1);
+                mv.visitMaxs(1, 1);
+                mv.visitEnd();
+
+                mv = cw.visitMethod(ACC_PUBLIC, "run", "(J)J", null, null);
+                mv.visitCode();
+                Label nextIf = new Label();
+                for (int i = 0; i < numberIfBlocks; i++) {
+                    mv.visitLabel(nextIf);
+                    mv.visitFrame(Opcodes.F_NEW, 2, new Object[]{abstractClassName, Opcodes.LONG}, 0, new Object[]{});
+                    mv.visitVarInsn(LLOAD, 1);
+                    mv.visitLdcInsn(new Long(LARGE_CONSTANT + i));
+                    mv.visitInsn(LCMP);
+                    nextIf = new Label();
+                    mv.visitJumpInsn(IFNE, nextIf);
+                    mv.visitLdcInsn(new Long(LARGE_CONSTANT + i + numberIfBlocks));
+                    mv.visitMethodInsn(INVOKESTATIC, graalDirectivesClassName, "opaque", "(J)J", false);
+                    mv.visitLdcInsn(new Long(LARGE_CONSTANT + i + numberIfBlocks * 2));
+                    mv.visitMethodInsn(INVOKESTATIC, graalDirectivesClassName, "opaque", "(J)J", false);
+                    mv.visitInsn(LADD);
+                    mv.visitInsn(LRETURN);
+                }
+                mv.visitLabel(nextIf);
+                mv.visitFrame(Opcodes.F_NEW, 2, new Object[]{abstractClassName, Opcodes.LONG}, 0, new Object[]{});
+                mv.visitInsn(LCONST_0);
+                mv.visitInsn(LRETURN);
+                Label l9 = new Label();
+                mv.visitLabel(l9);
+                mv.visitMaxs(4, 6);
+                mv.visitEnd();
+
+                cw.visitEnd();
+
+                byte[] bytes = cw.toByteArray();
+                return defineClass(name, bytes, 0, bytes.length);
+            } else {
+                return super.findClass(name);
+            }
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void run0() throws Exception {
+        try (OverrideScope os = OptionValue.override(GraalOptions.InlineEverything, true)) {
+            runTest("test", LOADER.findClass(NAME).newInstance(), 0L);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload.java
new file mode 100644
index 0000000..dd16760
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aaload extends JTTTest {
+
+    static Object[] array = {null, null, ""};
+
+    public static Object test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload_1.java
new file mode 100644
index 0000000..9780c54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aaload_1.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aaload_1 extends JTTTest {
+
+    static Object[][] array = {{null}, {null}, {""}};
+
+    public static Object test(int arg) {
+        return array[arg][0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aastore.java
new file mode 100644
index 0000000..694c2f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aastore.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aastore extends JTTTest {
+
+    static Object[] param = {new Object(), null, "h"};
+    static Object[] array1 = {null, null, null};
+    static String[] array2 = {null, null, null};
+
+    public static int test(boolean a, int indx) {
+        Object[] array = a ? array1 : array2;
+        Object val;
+        val = param[indx];
+        array[indx] = val;
+        return indx;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", true, 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", true, 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", false, 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", false, 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_0.java
new file mode 100644
index 0000000..5e3b60a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_0.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aload_0 extends JTTTest {
+
+    public static Object test(Object arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "x");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_1.java
new file mode 100644
index 0000000..8c67cc2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_1.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aload_1 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static Object test(int i, Object arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, "x");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_2.java
new file mode 100644
index 0000000..90929bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_2.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aload_2 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static Object test(int i, int j, Object arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, "x");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_3.java
new file mode 100644
index 0000000..eccd83a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_aload_3.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aload_3 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static Object test(int i, int j, int k, Object arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, 1, "x");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, 1, null);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_anewarray.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_anewarray.java
new file mode 100644
index 0000000..b21e7bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_anewarray.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_anewarray extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a) {
+        final BC_anewarray[] v = new BC_anewarray[3];
+        if (v != null) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_areturn.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_areturn.java
new file mode 100644
index 0000000..4bed9ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_areturn.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_areturn extends JTTTest {
+
+    public static Object test(Object a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "this");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_arraylength.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_arraylength.java
new file mode 100644
index 0000000..ef38422
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_arraylength.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_arraylength extends JTTTest {
+
+    static byte[] array0 = {1, 2};
+    static char[] array1 = {'a', 'b', 'c', 'd'};
+    static short[] array2 = {1, 2, 3, 4, 5, 6};
+    static int[] array3 = {1, 2, 3};
+    static long[] array4 = {1L, 2L, 3L, 4L};
+    static float[] array5 = {0.1f, 0.2f};
+    static double[] array6 = {0.1, 0.2, 0.3, 0.4};
+    static Object[] array7 = new Object[5];
+    static boolean[] array8 = {false, true, false};
+
+    public static int testByte(byte[] arg) {
+        return arg.length;
+    }
+
+    public static int testChar(char[] arg) {
+        return arg.length;
+    }
+
+    public static int testShort(short[] arg) {
+        return arg.length;
+    }
+
+    public static int testInt(int[] arg) {
+        return arg.length;
+    }
+
+    public static int testLong(long[] arg) {
+        return arg.length;
+    }
+
+    public static int testFloat(float[] arg) {
+        return arg.length;
+    }
+
+    public static int testDouble(double[] arg) {
+        return arg.length;
+    }
+
+    public static int testObject(Object[] arg) {
+        return arg.length;
+    }
+
+    public static int testBoolean(boolean[] arg) {
+        return arg.length;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("testByte", array0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("testChar", array1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("testShort", array2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("testInt", array3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("testLong", array4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("testFloat", array5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("testDouble", array6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("testObject", new Object[]{array7});
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("testBoolean", array8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_athrow.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_athrow.java
new file mode 100644
index 0000000..cce9019
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_athrow.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_athrow extends JTTTest {
+
+    static Throwable throwable = new Throwable();
+
+    public static int test(int arg) throws Throwable {
+        if (arg == 2) {
+            throw throwable;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_baload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_baload.java
new file mode 100644
index 0000000..8c3752c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_baload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_baload extends JTTTest {
+
+    static boolean[] array = {true, false, true, false};
+
+    public static boolean test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_bastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_bastore.java
new file mode 100644
index 0000000..595abcc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_bastore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_bastore extends JTTTest {
+
+    static boolean[] array = {false, false, false, false};
+
+    public static boolean test(int arg, boolean val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, true);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, false);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_caload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_caload.java
new file mode 100644
index 0000000..9739113
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_caload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_caload extends JTTTest {
+
+    static char[] array = {'\000', 'a', ' ', 10000};
+
+    public static char test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_castore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_castore.java
new file mode 100644
index 0000000..3029c31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_castore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_castore extends JTTTest {
+
+    static char[] array = {0, 0, 0, 0};
+
+    public static char test(int arg, char val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((char) 97));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((char) 65));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, ((char) 42));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((char) 120));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast01.java
new file mode 100644
index 0000000..90bc7d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast01.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast01 extends JTTTest {
+
+    private static class TestClass {
+    }
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new TestClass();
+
+    public static int test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        final TestClass bc = (TestClass) obj;
+        if (bc != null) {
+            return arg;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast02.java
new file mode 100644
index 0000000..fd8ec93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast02.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast02 extends JTTTest {
+
+    private static class TestClass {
+    }
+
+    static Object[] o1 = {new Object()};
+    static String[] o2 = {""};
+    static TestClass[] o3 = {new TestClass()};
+
+    public static int test(int arg) {
+        Object obj = null;
+        if (arg == 0) {
+            obj = o1;
+        }
+        if (arg == 1) {
+            obj = o2;
+        }
+        if (arg == 2) {
+            obj = o3;
+        }
+        Object[] r = (Object[]) obj;
+        return r == null ? -1 : -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast03.java
new file mode 100644
index 0000000..31680a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_checkcast03.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * Tests the checkcast works, when casting an array of interface.
+ */
+public class BC_checkcast03 extends JTTTest {
+
+    public interface IObject {
+
+    }
+
+    private static class BaseClass {
+
+    }
+
+    private static class TestClass extends BaseClass implements IObject {
+    }
+
+    static TestClass[] a1 = {new TestClass()};
+
+    public static BaseClass[] getBaseClassArray() {
+        return a1;
+    }
+
+    public static IObject[] test() {
+        return (IObject[]) getBaseClassArray();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2f.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2f.java
new file mode 100644
index 0000000..00914f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2f.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2f extends JTTTest {
+
+    public static float test(double d) {
+        return (float) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.06d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i01.java
new file mode 100644
index 0000000..8729461
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2i01 extends JTTTest {
+
+    public static int test(double d) {
+        return (int) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.06d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -156.82743d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i02.java
new file mode 100644
index 0000000..5095840
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2i02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2i02 extends JTTTest {
+
+    private static double[] inputs = {-1.3e44d, Double.NEGATIVE_INFINITY, Double.NaN, Double.POSITIVE_INFINITY, 1.3e44d};
+
+    public static int test(int i) {
+        return (int) inputs[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l01.java
new file mode 100644
index 0000000..c0c4733
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2l01 extends JTTTest {
+
+    public static long test(double d) {
+        return (long) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.06d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -156.82743d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l02.java
new file mode 100644
index 0000000..32e6b59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2l02 extends JTTTest {
+
+    private static double[] inputs = {-1.3e44d, Double.NEGATIVE_INFINITY, Double.NaN, Double.POSITIVE_INFINITY, 1.3e44d};
+
+    public static long test(int i) {
+        return (long) inputs[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l03.java
new file mode 100644
index 0000000..94dbbed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_d2l03.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_d2l03 extends JTTTest {
+
+    public static long test(double divider) {
+        return (long) (((long) divider) * divider);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 34.5D);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dadd.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dadd.java
new file mode 100644
index 0000000..8936302
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dadd.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dadd extends JTTTest {
+
+    public static double test(double a, double b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d, 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d, 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 253.11d, 54.43d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_daload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_daload.java
new file mode 100644
index 0000000..e6d5007
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_daload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_daload extends JTTTest {
+
+    static double[] array = {0.0, -1.1, 4.32, 6.06};
+
+    public static double test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dastore.java
new file mode 100644
index 0000000..09c8e0c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dastore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dastore extends JTTTest {
+
+    static double[] array = {0, 0, 0, 0};
+
+    public static double test(int arg, double val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0.01d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1.4d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 0.01d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -1.4d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp01.java
new file mode 100644
index 0000000..21036a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp01.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp01 extends JTTTest {
+
+    public static boolean test(double a, double b) {
+        return a < b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0d, -0.1d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 78.00d, 78.001d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp02.java
new file mode 100644
index 0000000..960cc14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp02.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp02 extends JTTTest {
+
+    public static boolean test(double a) {
+        return (a / a) < 0.0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp03.java
new file mode 100644
index 0000000..ece27ad
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp03.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp03 extends JTTTest {
+
+    public static boolean test(double a) {
+        return (a / a) > 0.0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp04.java
new file mode 100644
index 0000000..1385bf8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp04.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp04 extends JTTTest {
+
+    public static boolean test(double a) {
+        return (a / a) <= 0.0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp05.java
new file mode 100644
index 0000000..d05df10
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp05.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp05 extends JTTTest {
+
+    public static boolean test(double a) {
+        return (a / a) >= 0.0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp06.java
new file mode 100644
index 0000000..a7b4c06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp06.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp06 extends JTTTest {
+
+    public static boolean test(double a) {
+        return 0.0 < (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp07.java
new file mode 100644
index 0000000..4ebef7b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp07.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp07 extends JTTTest {
+
+    public static boolean test(double a) {
+        return 0.0 > (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp08.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp08.java
new file mode 100644
index 0000000..a37cf2c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp08.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp08 extends JTTTest {
+
+    public static boolean test(double a) {
+        return 0.0 <= (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp09.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp09.java
new file mode 100644
index 0000000..b949639
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp09.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp09 extends JTTTest {
+
+    public static boolean test(double a) {
+        return 0.0 >= (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp10.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp10.java
new file mode 100644
index 0000000..f4f61ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dcmp10.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dcmp10 extends JTTTest {
+
+    public static boolean test(int x) {
+        double a = 0;
+        double b = 0;
+        switch (x) {
+            case 0:
+                a = Double.POSITIVE_INFINITY;
+                b = 1;
+                break;
+            case 1:
+                a = 1;
+                b = Double.POSITIVE_INFINITY;
+                break;
+            case 2:
+                a = Double.NEGATIVE_INFINITY;
+                b = 1;
+                break;
+            case 3:
+                a = 1;
+                b = Double.NEGATIVE_INFINITY;
+                break;
+            case 4:
+                a = Double.NEGATIVE_INFINITY;
+                b = Double.NEGATIVE_INFINITY;
+                break;
+            case 5:
+                a = Double.NEGATIVE_INFINITY;
+                b = Double.POSITIVE_INFINITY;
+                break;
+            case 6:
+                a = Double.NaN;
+                b = Double.POSITIVE_INFINITY;
+                break;
+            case 7:
+                a = 1;
+                b = Double.NaN;
+                break;
+            case 8:
+                a = 1;
+                b = -0.0d / 0.0d;
+                break;
+        }
+        return a <= b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ddiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ddiv.java
new file mode 100644
index 0000000..e1e7e16
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ddiv.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+public class BC_ddiv extends BC_double_base {
+
+    public static double test(double a, double b) {
+        return a / b;
+    }
+
+    @Test
+    public void ddiv() {
+        runTest("test", x, y);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dmul.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dmul.java
new file mode 100644
index 0000000..62e9a40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dmul.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dmul extends JTTTest {
+
+    public static double test(double a, double b) {
+        return a * b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 311.0D, 10D);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11.2D, 2.0D);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg.java
new file mode 100644
index 0000000..25bd620
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dneg extends JTTTest {
+
+    public static double test(double a, double b, int which) {
+        double result1 = -a;
+        double result2 = -b;
+        double result = 0.0;
+        if (which == 0) {
+            result = result1;
+        } else {
+            result = result2;
+        }
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d, 1.0d, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1.01d, -2.01d, 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 7263.8734d, 8263.8734d, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0.0d, 1.0d, 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1.01d, -2.01d, 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 7263.8734d, 8263.8734d, 1);
+    }
+
+    public static double test2(double a, double b) {
+        return -(a - b);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test2", -1.0d, -1.0d);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg2.java
new file mode 100644
index 0000000..7948f9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dneg2.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dneg2 extends JTTTest {
+
+    public static double test(double a) {
+        return 1 / (-a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_double_base.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_double_base.java
new file mode 100644
index 0000000..93b2f31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_double_base.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+@RunWith(Parameterized.class)
+public abstract class BC_double_base extends JTTTest {
+
+    /** Some interesting values. */
+    private static final double[] values = {
+                    0.0d,
+                    -0.0d,
+                    1.0d,
+                    -1.0d,
+                    Double.POSITIVE_INFINITY,
+                    Double.NEGATIVE_INFINITY,
+                    Double.NaN,
+                    10.0d,
+                    -10.0d,
+                    311.0d,
+                    -311.0d,
+    };
+
+    @Parameters(name = "{0}, {1}")
+    public static Collection<Object[]> data() {
+        List<Object[]> d = new ArrayList<>();
+        for (int i = 0; i < values.length; i++) {
+            double x = values[i];
+            for (int j = 0; j < values.length; j++) {
+                double y = values[j];
+                d.add(new Object[]{x, y});
+            }
+        }
+        return d;
+    }
+
+    @Parameter(value = 0) public double x;
+    @Parameter(value = 1) public double y;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_drem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_drem.java
new file mode 100644
index 0000000..c97dc3a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_drem.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+public class BC_drem extends BC_double_base {
+
+    public static double test(double a, double b) {
+        return a % b;
+    }
+
+    @Test
+    public void drem() {
+        runTest("test", x, y);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dreturn.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dreturn.java
new file mode 100644
index 0000000..137aaf2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dreturn.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dreturn extends JTTTest {
+
+    public static double test(double a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.4d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 256.33d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1000.001d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub.java
new file mode 100644
index 0000000..640d13d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dsub extends JTTTest {
+
+    public static double test(double a, double b) {
+        return a - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d, 0.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0d, 1.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 253.11d, 54.43d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub2.java
new file mode 100644
index 0000000..7fc251c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_dsub2.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_dsub2 extends JTTTest {
+
+    public static double test(double a) {
+        return 1.0 / (0.0 - a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    public static double test2(double a) {
+        return a - a;
+    }
+
+    @Test
+    public void run1() {
+        runTest("test2", 17.3);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test2", Double.NaN);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2d.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2d.java
new file mode 100644
index 0000000..4911d7a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2d.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_f2d extends JTTTest {
+
+    public static double test(float d) {
+        return d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2.00f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i01.java
new file mode 100644
index 0000000..a8b7510
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_f2i01 extends JTTTest {
+
+    public static int test(float d) {
+        return (int) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.06f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -156.82743f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i02.java
new file mode 100644
index 0000000..f843914
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2i02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_f2i02 extends JTTTest {
+
+    private static float[] inputs = {-1.3e22f, Float.NEGATIVE_INFINITY, Float.NaN, Float.POSITIVE_INFINITY, 1.3e22f};
+
+    public static int test(int i) {
+        return (int) inputs[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l01.java
new file mode 100644
index 0000000..78adf31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_f2l01 extends JTTTest {
+
+    public static long test(float d) {
+        return (long) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.06f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -156.82743f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l02.java
new file mode 100644
index 0000000..36b37be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_f2l02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_f2l02 extends JTTTest {
+
+    private static float[] inputs = {-1.3e22f, Float.NEGATIVE_INFINITY, Float.NaN, Float.POSITIVE_INFINITY, 1.3e22f};
+
+    public static long test(int i) {
+        return (long) inputs[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fadd.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fadd.java
new file mode 100644
index 0000000..a257a67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fadd.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fadd extends JTTTest {
+
+    public static float test(float a, float b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f, 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f, 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 253.11f, 54.43f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", Float.MAX_VALUE, Float.MIN_VALUE);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", Float.MAX_VALUE / 2, Float.MAX_VALUE / 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_faload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_faload.java
new file mode 100644
index 0000000..058c0d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_faload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_faload extends JTTTest {
+
+    static float[] array = {0.0f, -1.1f, 4.32f, 6.06f};
+
+    public static float test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fastore.java
new file mode 100644
index 0000000..d9dc9fb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fastore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fastore extends JTTTest {
+
+    static float[] array = {0, 0, 0, 0};
+
+    public static float test(int arg, float val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0.01f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1.4f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 0.01f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -1.4f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp01.java
new file mode 100644
index 0000000..61b80f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp01.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp01 extends JTTTest {
+
+    public static boolean test(float a, float b) {
+        return a < b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f, -0.1f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 78.00f, 78.001f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp02.java
new file mode 100644
index 0000000..82efbe1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp02.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp02 extends JTTTest {
+
+    public static boolean test(float a) {
+        return (a / a) < 0.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp03.java
new file mode 100644
index 0000000..1974ae9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp03.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp03 extends JTTTest {
+
+    public static boolean test(float a) {
+        return (a / a) > 0.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp04.java
new file mode 100644
index 0000000..de4fb71
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp04.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp04 extends JTTTest {
+
+    public static boolean test(float a) {
+        return (a / a) <= 0.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp05.java
new file mode 100644
index 0000000..d902503
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp05.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp05 extends JTTTest {
+
+    public static boolean test(float a) {
+        return (a / a) >= 0.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp06.java
new file mode 100644
index 0000000..1325c8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp06.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp06 extends JTTTest {
+
+    public static boolean test(float a) {
+        return 0.0f < (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp07.java
new file mode 100644
index 0000000..26f0a1c0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp07.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp07 extends JTTTest {
+
+    public static boolean test(float a) {
+        return 0.0f > (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp08.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp08.java
new file mode 100644
index 0000000..8fd9ab8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp08.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp08 extends JTTTest {
+
+    public static boolean test(float a) {
+        return 0.0f <= (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp09.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp09.java
new file mode 100644
index 0000000..63229fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp09.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp09 extends JTTTest {
+
+    public static boolean test(float a) {
+        return 0.0f >= (a / a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp10.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp10.java
new file mode 100644
index 0000000..93d7399
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fcmp10.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fcmp10 extends JTTTest {
+
+    public static boolean test(int x) {
+        float a = 0;
+        float b = 0;
+        switch (x) {
+            case 0:
+                a = Float.POSITIVE_INFINITY;
+                b = 1;
+                break;
+            case 1:
+                a = 1;
+                b = Float.POSITIVE_INFINITY;
+                break;
+            case 2:
+                a = Float.NEGATIVE_INFINITY;
+                b = 1;
+                break;
+            case 3:
+                a = 1;
+                b = Float.NEGATIVE_INFINITY;
+                break;
+            case 4:
+                a = Float.NEGATIVE_INFINITY;
+                b = Float.NEGATIVE_INFINITY;
+                break;
+            case 5:
+                a = Float.NEGATIVE_INFINITY;
+                b = Float.POSITIVE_INFINITY;
+                break;
+            case 6:
+                a = Float.NaN;
+                b = Float.POSITIVE_INFINITY;
+                break;
+            case 7:
+                a = 1;
+                b = Float.NaN;
+                break;
+            case 8:
+                a = 1;
+                b = -0.0f / 0.0f;
+                break;
+        }
+        return a <= b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fdiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fdiv.java
new file mode 100644
index 0000000..d858cb1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fdiv.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+public class BC_fdiv extends BC_float_base {
+
+    public static float test(float a, float b) {
+        return a / b;
+    }
+
+    @Test
+    public void fdiv() {
+        runTest("test", x, y);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload.java
new file mode 100644
index 0000000..915ad8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fload extends JTTTest {
+
+    public static float test(float arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1.01f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload_2.java
new file mode 100644
index 0000000..9db6508
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fload_2.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fload_2 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static float test(float i, float arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f, -1f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0f, -1.01f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_float_base.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_float_base.java
new file mode 100644
index 0000000..b2ebb9e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_float_base.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+@RunWith(Parameterized.class)
+public abstract class BC_float_base extends JTTTest {
+
+    /** Some interesting values. */
+    private static final float[] values = {
+                    0.0f,
+                    -0.0f,
+                    1.0f,
+                    -1.0f,
+                    Float.POSITIVE_INFINITY,
+                    Float.NEGATIVE_INFINITY,
+                    Float.NaN,
+                    10.0f,
+                    -10.0f,
+                    311.0f,
+                    -311.0f,
+    };
+
+    @Parameters(name = "{0}, {1}")
+    public static Collection<Object[]> data() {
+        List<Object[]> d = new ArrayList<>();
+        for (int i = 0; i < values.length; i++) {
+            float x = values[i];
+            for (int j = 0; j < values.length; j++) {
+                float y = values[j];
+                d.add(new Object[]{x, y});
+            }
+        }
+        return d;
+    }
+
+    @Parameter(value = 0) public float x;
+    @Parameter(value = 1) public float y;
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fmul.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fmul.java
new file mode 100644
index 0000000..3617edb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fmul.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fmul extends JTTTest {
+
+    public static float test(float a, float b) {
+        return a * b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 311.0f, 10f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11.2f, 2.0f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fneg.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fneg.java
new file mode 100644
index 0000000..e03e5ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fneg.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fneg extends JTTTest {
+
+    public static float test(float a) {
+        return -a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1.01f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 7263.8734f);
+    }
+
+    public static float test2(float a, float b) {
+        return -(a - b);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test2", -1.0f, -1.0f);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_frem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_frem.java
new file mode 100644
index 0000000..17d4f2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_frem.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+public class BC_frem extends BC_float_base {
+
+    public static float test(float a, float b) {
+        return a % b;
+    }
+
+    @Test
+    public void frem() {
+        runTest("test", x, y);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_freturn.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_freturn.java
new file mode 100644
index 0000000..78d7145
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_freturn.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_freturn extends JTTTest {
+
+    public static float test(float a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.4f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 256.33f);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1000.001f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fsub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fsub.java
new file mode 100644
index 0000000..4259d95
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_fsub.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_fsub extends JTTTest {
+
+    public static float test(float a, float b) {
+        return a - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0f, 0.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0f, 1.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 253.11f, 54.43f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield.java
new file mode 100644
index 0000000..82aba32
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getfield extends JTTTest {
+
+    private static BC_getfield object = new BC_getfield();
+
+    private int field = 13;
+
+    public static int test() {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_b.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_b.java
new file mode 100644
index 0000000..7911d11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_b.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_b extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(byte field) {
+            this.field = field;
+        }
+
+        private byte field;
+    }
+
+    public static byte test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder((byte) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Byte.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Byte.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_c.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_c.java
new file mode 100644
index 0000000..4779425
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_c.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_c extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(char field) {
+            this.field = field;
+        }
+
+        private char field;
+    }
+
+    public static char test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder('A'));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Character.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Character.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_d.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_d.java
new file mode 100644
index 0000000..52f9a15
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_d.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_d extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(double field) {
+            this.field = field;
+        }
+
+        private double field;
+    }
+
+    public static double test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(0.0D));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Double.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Double.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_f.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_f.java
new file mode 100644
index 0000000..c09fca1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_f.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_f extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(float field) {
+            this.field = field;
+        }
+
+        private float field;
+    }
+
+    public static float test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(0.0F));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Float.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Float.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_i.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_i.java
new file mode 100644
index 0000000..1a49f8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_i.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_i extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(int field) {
+            this.field = field;
+        }
+
+        private int field;
+    }
+
+    public static int test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Integer.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Integer.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_l.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_l.java
new file mode 100644
index 0000000..af8872b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_l.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_l extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(long field) {
+            this.field = field;
+        }
+
+        private long field;
+    }
+
+    public static long test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Long.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Long.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_o.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_o.java
new file mode 100644
index 0000000..6c59ebd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_o.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_o extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(Object field) {
+            this.field = field;
+        }
+
+        private Object field;
+    }
+
+    public static Object test(FieldHolder object) {
+        return object.field == null ? null : object.field.getClass();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(null));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder("field"));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_s.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_s.java
new file mode 100644
index 0000000..655ec53
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_s.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_s extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(short field) {
+            this.field = field;
+        }
+
+        private short field;
+    }
+
+    public static short test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(Short.MAX_VALUE));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new FieldHolder(Short.MIN_VALUE));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_z.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_z.java
new file mode 100644
index 0000000..a82bab0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getfield_z.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield_z extends JTTTest {
+
+    static class FieldHolder {
+        FieldHolder(boolean field) {
+            this.field = field;
+        }
+
+        private boolean field;
+    }
+
+    public static boolean test(FieldHolder object) {
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new FieldHolder(true));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new FieldHolder(false));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_b.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_b.java
new file mode 100644
index 0000000..d5ec027
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_b.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_b extends JTTTest {
+
+    private static byte field = 11;
+
+    public static byte test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_c.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_c.java
new file mode 100644
index 0000000..e7ac64c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_c.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_c extends JTTTest {
+
+    private static char field = 11;
+
+    public static char test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_d.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_d.java
new file mode 100644
index 0000000..cd3f54d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_d.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_d extends JTTTest {
+
+    private static double field = 11;
+
+    public static double test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_f.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_f.java
new file mode 100644
index 0000000..b2abf9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_f.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_f extends JTTTest {
+
+    private static float field = 11;
+
+    public static float test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_i.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_i.java
new file mode 100644
index 0000000..cc62f56
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_i.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_i extends JTTTest {
+
+    private static int field = 11;
+
+    public static int test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_l.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_l.java
new file mode 100644
index 0000000..64ad2de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_l.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_l extends JTTTest {
+
+    private static long field = 11;
+
+    public static long test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_s.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_s.java
new file mode 100644
index 0000000..8f56536
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_s.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_s extends JTTTest {
+
+    private static short field = 11;
+
+    public static short test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_z.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_z.java
new file mode 100644
index 0000000..f537d45
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_getstatic_z.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_getstatic_z extends JTTTest {
+
+    private static boolean field = true;
+
+    public static boolean test() {
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2b.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2b.java
new file mode 100644
index 0000000..914be2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2b.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2b extends JTTTest {
+
+    public static byte test(int a) {
+        return (byte) a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 255);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 128);
+    }
+
+    public static int testInt(int a) {
+        return (byte) a;
+    }
+
+    @Test
+    public void runI0() throws Throwable {
+        runTest("testInt", -1);
+    }
+
+    @Test
+    public void runI1() throws Throwable {
+        runTest("testInt", 2);
+    }
+
+    @Test
+    public void runI2() throws Throwable {
+        runTest("testInt", 255);
+    }
+
+    @Test
+    public void runI3() throws Throwable {
+        runTest("testInt", 128);
+    }
+
+    public static long testLong(int a) {
+        return (byte) a;
+    }
+
+    @Test
+    public void runL0() throws Throwable {
+        runTest("testLong", -1);
+    }
+
+    @Test
+    public void runL1() throws Throwable {
+        runTest("testLong", 2);
+    }
+
+    @Test
+    public void runL2() throws Throwable {
+        runTest("testLong", 255);
+    }
+
+    @Test
+    public void runL3() throws Throwable {
+        runTest("testLong", 128);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2c.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2c.java
new file mode 100644
index 0000000..fda56fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2c.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2c extends JTTTest {
+
+    public static char test(int a) {
+        return (char) a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 645);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 65535);
+    }
+
+    public static int testInt(int a) {
+        return (char) a;
+    }
+
+    @Test
+    public void runI0() throws Throwable {
+        runTest("testInt", -1);
+    }
+
+    @Test
+    public void runI1() throws Throwable {
+        runTest("testInt", 645);
+    }
+
+    @Test
+    public void runI2() throws Throwable {
+        runTest("testInt", 65535);
+    }
+
+    public static long testLong(int a) {
+        return (char) a;
+    }
+
+    @Test
+    public void runL0() throws Throwable {
+        runTest("testLong", -1);
+    }
+
+    @Test
+    public void runL1() throws Throwable {
+        runTest("testLong", 645);
+    }
+
+    @Test
+    public void runL2() throws Throwable {
+        runTest("testLong", 65535);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2d.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2d.java
new file mode 100644
index 0000000..a63ac9e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2d.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2d extends JTTTest {
+
+    public static double test(int a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -34);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", Integer.MIN_VALUE);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 34);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", new Integer(Short.MAX_VALUE));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2f.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2f.java
new file mode 100644
index 0000000..1f86bed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2f.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2f extends JTTTest {
+
+    public static float test(int a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -34);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2l.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2l.java
new file mode 100644
index 0000000..4d12155
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2l.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2l extends JTTTest {
+
+    public static long test(int a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483647);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2s.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2s.java
new file mode 100644
index 0000000..2ef9f9b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_i2s.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_i2s extends JTTTest {
+
+    public static short test(int a) {
+        return (short) a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 34);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 65535);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 32768);
+    }
+
+    public static int testInt(int a) {
+        return (short) a;
+    }
+
+    @Test
+    public void runI0() throws Throwable {
+        runTest("testInt", -1);
+    }
+
+    @Test
+    public void runI1() throws Throwable {
+        runTest("testInt", 34);
+    }
+
+    @Test
+    public void runI2() throws Throwable {
+        runTest("testInt", 65535);
+    }
+
+    @Test
+    public void runI3() throws Throwable {
+        runTest("testInt", 32768);
+    }
+
+    public static long testLong(int a) {
+        return (short) a;
+    }
+
+    @Test
+    public void runL0() throws Throwable {
+        runTest("testLong", -1);
+    }
+
+    @Test
+    public void runL1() throws Throwable {
+        runTest("testLong", 34);
+    }
+
+    @Test
+    public void runL2() throws Throwable {
+        runTest("testLong", 65535);
+    }
+
+    @Test
+    public void runL3() throws Throwable {
+        runTest("testLong", 32768);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd.java
new file mode 100644
index 0000000..0f597c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33, 67);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647, 1);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483647, -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd2.java
new file mode 100644
index 0000000..7e91a8f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd2.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd2 extends JTTTest {
+
+    public static int test(byte a, byte b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((byte) 1), ((byte) 2));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((byte) 0), ((byte) -1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((byte) 33), ((byte) 67));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((byte) 1), ((byte) -1));
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", ((byte) -128), ((byte) 1));
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", ((byte) 127), ((byte) 1));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd3.java
new file mode 100644
index 0000000..1337175
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd3.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd3 extends JTTTest {
+
+    public static int test(short a, short b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((short) 1), ((short) 2));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((short) 0), ((short) -1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((short) 33), ((short) 67));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((short) 1), ((short) -1));
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", ((short) -128), ((short) 1));
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", ((short) 127), ((short) 1));
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", ((short) -32768), ((short) 1));
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", ((short) 32767), ((short) 1));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const0.java
new file mode 100644
index 0000000..b675e9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const0.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd_const0 extends JTTTest {
+
+    public static int test(int a, int b, boolean neg) {
+        int x = GraalDirectives.opaque(a);
+        if (!neg) {
+            return x + b;
+        }
+        return x - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 42, 1, false);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 42, -1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 42, 1, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 42, -1, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const1.java
new file mode 100644
index 0000000..caa44ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const1.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd_const1 extends JTTTest {
+
+    public static int test(byte a, byte b, boolean neg) {
+        byte x = GraalDirectives.opaque(a);
+        if (!neg) {
+            return x + b;
+        }
+        return x - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (byte) 42, (byte) 1, false);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (byte) 42, (byte) -1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", (byte) 42, (byte) 1, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", (byte) 42, (byte) -1, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const2.java
new file mode 100644
index 0000000..ae7f9ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const2.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd_const2 extends JTTTest {
+
+    public static int test(short a, short b, boolean neg) {
+        short x = GraalDirectives.opaque(a);
+        if (!neg) {
+            return x + b;
+        }
+        return x - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (short) 42, (short) 1, false);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (short) 42, (short) -1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", (short) 42, (short) 1, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", (short) 42, (short) -1, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const3.java
new file mode 100644
index 0000000..a7a786e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iadd_const3.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iadd_const3 extends JTTTest {
+
+    public static long test(long a, long b, boolean neg) {
+        long x = GraalDirectives.opaque(a);
+        if (!neg) {
+            return x + b;
+        }
+        return x - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (long) 42, (long) 1, false);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (long) 42, (long) -1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", (long) 42, (long) 1, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", (long) 42, (long) -1, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iaload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iaload.java
new file mode 100644
index 0000000..d26f515
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iaload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iaload extends JTTTest {
+
+    static int[] array = {0, -1, 4, 1000000000};
+
+    public static int test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iand.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iand.java
new file mode 100644
index 0000000..58f4a45
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iand.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iand extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a & b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 63);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iastore.java
new file mode 100644
index 0000000..5d00a4d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iastore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iastore extends JTTTest {
+
+    static int[] array = {0, 0, 0, 0};
+
+    public static int test(int arg, int val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 11);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -14);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iconst.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iconst.java
new file mode 100644
index 0000000..e0200fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iconst.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iconst extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return 0;
+        }
+        if (arg == 1) {
+            return 1;
+        }
+        if (arg == 2) {
+            return 2;
+        }
+        if (arg == 3) {
+            return 3;
+        }
+        if (arg == 4) {
+            return 4;
+        }
+        if (arg == 5) {
+            return 5;
+        }
+        return 375;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv.java
new file mode 100644
index 0000000..467875f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_idiv extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 256, 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 135, 7);
+    }
+
+    public static int testStrictlyPositive(int b) {
+        return 64 / ((b & 7) + 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("testStrictlyPositive", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv2.java
new file mode 100644
index 0000000..59f627b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_idiv2.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_idiv2 extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648, -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq.java
new file mode 100644
index 0000000..764f9a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifeq extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a == 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a != 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() {
+        runTest("testb", 0xff);
+    }
+
+    /**
+     * Tests if the if does work properly on byte stamp.
+     */
+    public static int testb(int b) {
+        byte x = (byte) b;
+        int y = x & 0xff;
+        if (y == 0xff) {
+            // Just do anything else to force jump instead of conditional move
+            y = (int) (System.currentTimeMillis() >> 32);
+        }
+        return y;
+    }
+
+    @Test
+    public void run4() {
+        runTest("tests", 0xffff);
+    }
+
+    /**
+     * Tests if the if does work properly on short stamp.
+     */
+    public static int tests(int b) {
+        short x = (short) b;
+        int y = x & 0xffff;
+        if (y == 0xffff) {
+            // Just do anything else to force jump instead of conditional move
+            y = (int) (System.currentTimeMillis() >> 32);
+        }
+        return y;
+    }
+
+    @Test
+    public void run5() {
+        runTest("testc", 0xffff);
+    }
+
+    /**
+     * Tests if the if does work properly on char stamp (boils down to short, just to cover all the
+     * java types).
+     */
+    public static int testc(int b) {
+        char x = (char) b;
+        int y = x & 0xffff;
+        if (y == 0xffff) {
+            // Just do anything else to force jump instead of conditional move
+            y = (int) (System.currentTimeMillis() >> 32);
+        }
+        return y;
+    }
+
+    // the same with conditional move
+    @Test
+    public void run6() {
+        runTest("testCondb", 0xff);
+    }
+
+    /**
+     * Tests if the if does work properly on byte stamp.
+     */
+    public static boolean testCondb(int b) {
+        byte x = (byte) b;
+        int y = x & 0xff;
+        return y == 0xff;
+    }
+
+    @Test
+    public void run7() {
+        runTest("testConds", 0xffff);
+    }
+
+    /**
+     * Tests if the if does work properly on short stamp.
+     */
+    public static boolean testConds(int b) {
+        short x = (short) b;
+        int y = x & 0xffff;
+        return y == 0xffff;
+    }
+
+    @Test
+    public void run8() {
+        runTest("testCondc", 0xffff);
+    }
+
+    /**
+     * Tests if the if does work properly on char type.
+     */
+    public static boolean testCondc(int b) {
+        char x = (char) b;
+        int y = x & 0xffff;
+        return y == 0xffff;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_2.java
new file mode 100644
index 0000000..b462d9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_2.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifeq_2 extends JTTTest {
+
+    public static boolean test(int a) {
+        return a == 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_3.java
new file mode 100644
index 0000000..ce0158a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifeq_3.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifeq_3 extends JTTTest {
+
+    public static boolean test(int a) {
+        return a != 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge.java
new file mode 100644
index 0000000..373bca5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifge extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a >= 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a < 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_2.java
new file mode 100644
index 0000000..392c4c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_2.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifge_2 extends JTTTest {
+
+    public static boolean test(int a, int b) {
+        return a >= b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -100);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1, 0);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -12, -12);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_3.java
new file mode 100644
index 0000000..e956901
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifge_3.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifge_3 extends JTTTest {
+
+    public static boolean test(int a, int b) {
+        return a < b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -100);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1, 0);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -12, -12);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifgt.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifgt.java
new file mode 100644
index 0000000..e5d0d79
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifgt.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifgt extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a > 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a <= 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt1.java
new file mode 100644
index 0000000..8812f77
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt1.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ificmplt1 extends JTTTest {
+
+    public static int test(int a) {
+        return a < 1 ? 12 : 13;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt2.java
new file mode 100644
index 0000000..c2d4f9e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmplt2.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ificmplt2 extends JTTTest {
+
+    public static int test(int a) {
+        return a > 1 ? 13 : 12;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne1.java
new file mode 100644
index 0000000..68d3de4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne1.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ificmpne1 extends JTTTest {
+
+    public static int test(int a) {
+        return a == 1 ? 12 : 13;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne2.java
new file mode 100644
index 0000000..9697ba7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ificmpne2.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ificmpne2 extends JTTTest {
+
+    public static int test(int a) {
+        return a != 1 ? 13 : 12;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifle.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifle.java
new file mode 100644
index 0000000..0d642c0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifle.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifle extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a <= 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a > 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iflt.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iflt.java
new file mode 100644
index 0000000..40586ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iflt.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iflt extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a < 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a >= 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifne.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifne.java
new file mode 100644
index 0000000..aef4909
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifne.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifne extends JTTTest {
+
+    public static int test(int a) {
+        int n = 0;
+        if (a != 0) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a == 0) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull.java
new file mode 100644
index 0000000..b8c497f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnonnull extends JTTTest {
+
+    public static int test(Object a) {
+        int n = 0;
+        if (a == null) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a != null) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_2.java
new file mode 100644
index 0000000..32a2fa4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_2.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnonnull_2 extends JTTTest {
+
+    public static boolean test(Object a) {
+        return a != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_3.java
new file mode 100644
index 0000000..4be540f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnonnull_3.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnonnull_3 extends JTTTest {
+
+    public static int test(Object a) {
+        if (a != null) {
+            return 1;
+        }
+        return 2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull.java
new file mode 100644
index 0000000..5b55fc6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnull extends JTTTest {
+
+    public static int test(Object a) {
+        int n = 0;
+        if (a != null) {
+            n += 1;
+        } else {
+            n -= 1;
+        }
+        if (a == null) {
+            n -= 1;
+        } else {
+            n += 1;
+        }
+        return n;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_2.java
new file mode 100644
index 0000000..aba43ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_2.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnull_2 extends JTTTest {
+
+    public static boolean test(Object a) {
+        return a == null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_3.java
new file mode 100644
index 0000000..7f0cc96
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ifnull_3.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ifnull_3 extends JTTTest {
+
+    public static int test(Object a) {
+        if (a == null) {
+            return 1;
+        }
+        return 2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_1.java
new file mode 100644
index 0000000..e15710e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_1.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iinc_1 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        arg += 1;
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_2.java
new file mode 100644
index 0000000..6d14da1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_2.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iinc_2 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        arg += 2;
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_3.java
new file mode 100644
index 0000000..3d750bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_3.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iinc_3 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        arg += 51;
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_4.java
new file mode 100644
index 0000000..d93899e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iinc_4.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iinc_4 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        arg += 512;
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0.java
new file mode 100644
index 0000000..b182c28
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_0 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_1.java
new file mode 100644
index 0000000..1b6bc51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_1.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_0_1 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg + 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_2.java
new file mode 100644
index 0000000..ef5aa27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_0_2.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_0_2 extends JTTTest {
+
+    public static int test(int arg) {
+        int i = arg;
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1.java
new file mode 100644
index 0000000..947dd51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_1 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int i, int arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1_1.java
new file mode 100644
index 0000000..f47f916
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_1_1.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_1_1 extends JTTTest {
+
+    public static int test(int i) {
+        int arg = 0;
+        return i + arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_2.java
new file mode 100644
index 0000000..755584a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_2.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_2 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int i, int j, int arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, 1, 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_3.java
new file mode 100644
index 0000000..dbcd576
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iload_3.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iload_3 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int i, int j, int k, int arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, 1, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, 1, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1, 1, 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, 1, 1, 1000345);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_imul.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_imul.java
new file mode 100644
index 0000000..c558bcd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_imul.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_imul extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a * b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33, 67);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647, -1);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483648, -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ineg.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ineg.java
new file mode 100644
index 0000000..9bdfd53
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ineg.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ineg extends JTTTest {
+
+    public static int test(int a) {
+        return -a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 7263);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof.java
new file mode 100644
index 0000000..4545fdb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_instanceof extends JTTTest {
+
+    private static class TestClass {
+    }
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new TestClass();
+
+    public static boolean test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        return obj instanceof TestClass;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof01.java
new file mode 100644
index 0000000..791ee24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_instanceof01.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+/**
+ * Tests the instanceof works, when casting an array of interface.
+ */
+public class BC_instanceof01 extends JTTTest {
+
+    public interface IObject {
+
+    }
+
+    public interface IDerivedObject extends IObject {
+
+    }
+
+    private static class BaseClass {
+
+    }
+
+    private static class TestClass extends BaseClass implements IObject {
+    }
+
+    private static class DerivedTestClass extends BaseClass implements IDerivedObject {
+
+    }
+
+    static TestClass[] a1 = {new TestClass()};
+    static DerivedTestClass[] a2 = {new DerivedTestClass()};
+
+    public static BaseClass[] getBaseClassArray() {
+        return a1;
+    }
+
+    public static BaseClass[] getDerivedBaseClassArray() {
+        return a2;
+    }
+
+    public static boolean test() {
+        return getBaseClassArray() instanceof IObject[];
+    }
+
+    public static int testConditionalElimination() {
+        BaseClass[] result = getDerivedBaseClassArray();
+        if (result instanceof IDerivedObject[]) {
+            if (result instanceof IObject[]) {
+                return 1;
+            } else {
+                return 2;
+            }
+        } else {
+            return 3;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected Suites getSuites() {
+        try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) {
+            return super.getSuites();
+        }
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("testConditionalElimination");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokeinterface.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokeinterface.java
new file mode 100644
index 0000000..515e6b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokeinterface.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokeinterface extends JTTTest {
+
+    public interface ITest {
+
+        int id(int a);
+    }
+
+    static class IClass implements ITest {
+
+        @Override
+        public int id(int a) {
+            return a;
+        }
+    }
+
+    static ITest object = new IClass();
+
+    public static int test(int a) {
+        return object.id(a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial.java
new file mode 100644
index 0000000..4c12b63
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokespecial extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private int id(int i) {
+            return i;
+        }
+    }
+
+    static TestClass object = new TestClass();
+
+    public static int test(int a) {
+        return object.id(a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial2.java
new file mode 100644
index 0000000..865a657
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokespecial2.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokespecial2 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private int id(int i) {
+            return 4 + i;
+        }
+    }
+
+    static TestClass object = new TestClass();
+
+    public static int test(int a) {
+        return 3 + object.id(a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokestatic.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokestatic.java
new file mode 100644
index 0000000..c20775f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokestatic.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokestatic extends JTTTest {
+
+    public static int test(int a) {
+        return id(a);
+    }
+
+    public static int id(int i) {
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokevirtual.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokevirtual.java
new file mode 100644
index 0000000..07a5406
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_invokevirtual.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokevirtual extends JTTTest {
+
+    private static class TestClass {
+        public int id(int i) {
+            return i;
+        }
+    }
+
+    static TestClass object = new TestClass();
+
+    public static int test(int a) {
+        return object.id(a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ior.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ior.java
new file mode 100644
index 0000000..b0bb635
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ior.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ior extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a | b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 63);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem.java
new file mode 100644
index 0000000..bb0c16b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_irem extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a % b;
+    }
+
+    // Left as constant
+    public static int test2(int b) {
+        return 13 % b;
+    }
+
+    // Right as constant
+    public static int test3(int a) {
+        return a % 13;
+    }
+
+    // Tests if the zero extension works fine with 64 bit registers behind
+    public static long test4(int a, int b) {
+        int ra = Math.abs(a % b);
+        int rb = Math.abs(a) % b;
+        return ra << 32 | rb;
+    }
+
+    // Test if sign extension works on architectures with 64 bit registers only
+    public static int test5(int a, int b) {
+        return (a + 0xFF) % (b + 0xFF);
+    }
+
+    // Test if sign extension works on architectures with 64 bit registers only
+    public static int test6(int a, int b) {
+        return (a - 0xFF) % (b - 0xFF);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 256, 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 135, 7);
+    }
+
+    @Test
+    public void run20() throws Throwable {
+        runTest("test2", 2);
+    }
+
+    @Test
+    public void run21() throws Throwable {
+        runTest("test2", 20000000);
+    }
+
+    @Test
+    public void run22() throws Throwable {
+        runTest("test2", -20000000);
+    }
+
+    @Test
+    public void run30() throws Throwable {
+        runTest("test3", 2);
+    }
+
+    @Test
+    public void run31() throws Throwable {
+        runTest("test3", 200000000);
+    }
+
+    @Test
+    public void run32() throws Throwable {
+        runTest("test3", -200000000);
+    }
+
+    @Test
+    public void run41() throws Throwable {
+        runTest("test4", -100000, 3000000);
+    }
+
+    @Test
+    public void run42() throws Throwable {
+        runTest("test4", -100000, 30);
+    }
+
+    @Test
+    public void run43() throws Throwable {
+        runTest("test4", -1000000, -30);
+    }
+
+    @Test
+    public void run51() {
+        runTest("test5", Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void run61() {
+        runTest("test6", Integer.MIN_VALUE, Integer.MIN_VALUE);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem2.java
new file mode 100644
index 0000000..d76faaa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem2.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_irem2 extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a % b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648, -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem3.java
new file mode 100644
index 0000000..144bc34
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem3.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_irem3 extends JTTTest {
+
+    public static int test(int a) {
+        return a % 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1000);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ireturn.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ireturn.java
new file mode 100644
index 0000000..aa2f8be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ireturn.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ireturn extends JTTTest {
+
+    public static int test(int a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 256);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishl.java
new file mode 100644
index 0000000..f06e26a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ishl extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a << b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishr.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishr.java
new file mode 100644
index 0000000..1b445ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ishr.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ishr extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a >> b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 67, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 16);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_isub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_isub.java
new file mode 100644
index 0000000..57aafea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_isub.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_isub extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33, -67);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, -1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647, -1);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483647, 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iushr.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iushr.java
new file mode 100644
index 0000000..f6f219e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_iushr.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_iushr extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a >>> b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 67, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 16);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ixor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ixor.java
new file mode 100644
index 0000000..9d2e299
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ixor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ixor extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a ^ b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31, 63);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2d.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2d.java
new file mode 100644
index 0000000..16b026e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2d.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_l2d extends JTTTest {
+
+    public static double test(long a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -74652389L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2f.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2f.java
new file mode 100644
index 0000000..b9913ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2f.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_l2f extends JTTTest {
+
+    public static float test(long a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -74652389L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", Long.MAX_VALUE);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", Long.MIN_VALUE);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i.java
new file mode 100644
index 0000000..a0072fb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_l2i extends JTTTest {
+
+    public static int test(long a) {
+        return (int) a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483647L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -2147483648L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i_2.java
new file mode 100644
index 0000000..fe06dc5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_l2i_2.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_l2i_2 extends JTTTest {
+
+    static Object[] array = {null};
+
+    public static Object test(long a) {
+        long arg = a;
+        arg = arg << 32;
+        return array[(int) arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 123456789L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd.java
new file mode 100644
index 0000000..58c3ac9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ladd extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33L, 67L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1L, -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647L, 1L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483647L, -2L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd2.java
new file mode 100644
index 0000000..2b572b6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ladd2.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ladd2 extends JTTTest {
+
+    public static long test(int a, int b) {
+        return a + (long) b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33, 67);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648, 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647, 1);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483647, -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_laload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_laload.java
new file mode 100644
index 0000000..2c58e20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_laload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_laload extends JTTTest {
+
+    static long[] array = {0L, -1L, 4L, 1000000000000L};
+
+    public static long test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_land.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_land.java
new file mode 100644
index 0000000..dc32552
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_land.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_land extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a & b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 63L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lastore.java
new file mode 100644
index 0000000..6c1d5c2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lastore extends JTTTest {
+
+    static long[] array = {0, 0, 0, 0};
+
+    public static long test(int arg, long val) {
+        final long[] array2 = arg == -2 ? null : BC_lastore.array;
+        array2[arg] = val;
+        return array2[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 11L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -14L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lcmp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lcmp.java
new file mode 100644
index 0000000..f1407ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lcmp.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lcmp extends JTTTest {
+
+    public static boolean test(long a, long b) {
+        return a < b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 77L, 78L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L, 0L);
+    }
+
+    /**
+     * Test with ugly numbers (which probably does not fit into one instruction.
+     *
+     * @throws Throwable
+     */
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 293521900824L, 97726785831L);
+    }
+
+    /**
+     * Test with big numbers where it makes difference if the value is handled with 64 bits.
+     *
+     * @throws Throwable
+     */
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1L, Long.MIN_VALUE);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_01.java
new file mode 100644
index 0000000..898003f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_01.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_01 extends JTTTest {
+
+    public static int test() {
+        return -123;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_02.java
new file mode 100644
index 0000000..c262f16
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_02.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_02 extends JTTTest {
+
+    public static float test() {
+        return -2.4f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_03.java
new file mode 100644
index 0000000..bb2fb82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_03.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_03 extends JTTTest {
+
+    public static long test() {
+        return -123L;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_04.java
new file mode 100644
index 0000000..87401d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_04.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_04 extends JTTTest {
+
+    public static String test() {
+        return "xyz";
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_05.java
new file mode 100644
index 0000000..f8f5e3f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_05.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_05 extends JTTTest {
+
+    public static double test() {
+        return -2.33d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_06.java
new file mode 100644
index 0000000..9067222
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldc_06.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldc_06 extends JTTTest {
+
+    public static String test() {
+        return test2().getName();
+    }
+
+    static Class<BC_ldc_06> test2() {
+        return BC_ldc_06.class;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv.java
new file mode 100644
index 0000000..a0c771b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldiv extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 256L, 4L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 135L, 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv2.java
new file mode 100644
index 0000000..eba1696
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv2.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldiv2 extends JTTTest {
+
+    public static long MIN = Long.MIN_VALUE;
+    public static long MAX = Long.MAX_VALUE;
+
+    public static long test(long a, long b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", MIN, -1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", MIN, 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", MIN, MAX);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv3.java
new file mode 100644
index 0000000..c34f2fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_ldiv3.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldiv3 extends JTTTest {
+
+    public static long PLUS7 = 7;
+    public static long PLUS3 = 3;
+    public static long MIN7 = -7;
+    public static long MIN3 = -3;
+
+    public static long test(long a, long b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", PLUS7, 2L);
+        runTest("test", PLUS3, 2L);
+        runTest("test", MIN7, 2L);
+        runTest("test", MIN3, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", PLUS7, -4L);
+        runTest("test", PLUS3, -4L);
+        runTest("test", MIN7, -4L);
+        runTest("test", MIN3, -4L);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_0.java
new file mode 100644
index 0000000..50565df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_0.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lload_0 extends JTTTest {
+
+    public static long test(long arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -3L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 10000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_01.java
new file mode 100644
index 0000000..373af8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_01.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+@SuppressWarnings("unused")
+public class BC_lload_01 extends JTTTest {
+
+    public static long test(int i) {
+        return test1(null);
+    }
+
+    public static int test1(Object o0) {
+        long x = 1;
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -3);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_1.java
new file mode 100644
index 0000000..eaa8cd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_1.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lload_1 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static long test(int i, long arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -3L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 10000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_2.java
new file mode 100644
index 0000000..fd6b3fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_2.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lload_2 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static long test(int i, int j, long arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, -3L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1, 10000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_3.java
new file mode 100644
index 0000000..38f4b5d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lload_3.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lload_3 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static long test(int i, int j, int k, long arg) {
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 1, 1, 1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, 1, -3L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 1, 1, 10000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lmul.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lmul.java
new file mode 100644
index 0000000..dd07f0f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lmul.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lmul extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a * b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33L, 67L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1L, -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647L, -1L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483648L, -1L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1000000L, 1000000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lneg.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lneg.java
new file mode 100644
index 0000000..4ac6e37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lneg.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lneg extends JTTTest {
+
+    public static long test(long a) {
+        return -a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 7263L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -2147483648L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch01.java
new file mode 100644
index 0000000..e12eb9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch01.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lookupswitch01 extends JTTTest {
+
+    public static int test(int a) {
+        switch (a) {
+            case 67:
+                return 0;
+            case 97:
+                return 1;
+            case 107:
+                return 2;
+            case 133:
+                return 3;
+            case 212:
+                return 4;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 66);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 67);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 68);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 96);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 97);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 98);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 106);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 107);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 108);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 132);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 133);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 134);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 211);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 212);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 213);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch02.java
new file mode 100644
index 0000000..8476597
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch02.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lookupswitch02 extends JTTTest {
+
+    public static int test(int a) {
+        final int b = a;
+        switch (b) {
+            case 67:
+                return 0;
+            case 97:
+                return 1;
+            case 107:
+                return 2;
+            case 133:
+                return 3;
+            case 212:
+                return 4;
+            case -122:
+                return 5;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 66);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 67);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 68);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 96);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 97);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 98);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 106);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 107);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 108);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 132);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 133);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 134);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 211);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 212);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 213);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", -121);
+    }
+
+    @Test
+    public void run18() throws Throwable {
+        runTest("test", -122);
+    }
+
+    @Test
+    public void run19() throws Throwable {
+        runTest("test", -123);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch03.java
new file mode 100644
index 0000000..8d99af6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch03.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lookupswitch03 extends JTTTest {
+
+    public static int test(int a) {
+        final int b = a + 10;
+        switch (b) {
+            case 77:
+                return 0;
+            case 107:
+                return 1;
+            case 117:
+                return 2;
+            case 143:
+                return 3;
+            case 222:
+                return 4;
+            case -112:
+                return 5;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 66);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 67);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 68);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 96);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 97);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 98);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 106);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 107);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 108);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 132);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 133);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 134);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 211);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 212);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 213);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", -121);
+    }
+
+    @Test
+    public void run18() throws Throwable {
+        runTest("test", -122);
+    }
+
+    @Test
+    public void run19() throws Throwable {
+        runTest("test", -123);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch04.java
new file mode 100644
index 0000000..580b746
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch04.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lookupswitch04 extends JTTTest {
+
+    public static int test(int a) {
+        final int b = a + 8;
+        final int c = b + 2;
+        switch (c) {
+            case 77:
+                return 0;
+            case 107:
+                return 1;
+            case 117:
+                return 2;
+            case 143:
+                return 3;
+            case 222:
+                return 4;
+            case -112:
+                return 5;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 66);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 67);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 68);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 96);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 97);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 98);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 106);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 107);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 108);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 132);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 133);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 134);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 211);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 212);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 213);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", -121);
+    }
+
+    @Test
+    public void run18() throws Throwable {
+        runTest("test", -122);
+    }
+
+    @Test
+    public void run19() throws Throwable {
+        runTest("test", -123);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch05.java
new file mode 100644
index 0000000..11965c7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lookupswitch05.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lookupswitch05 extends JTTTest {
+
+    public static Object test(int a) {
+        switch (a) {
+            default:
+                return new String();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lor.java
new file mode 100644
index 0000000..b52b24b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lor extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a | b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 63L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem.java
new file mode 100644
index 0000000..20608a4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lrem extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a % b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 256L, 4L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 135L, 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem2.java
new file mode 100644
index 0000000..47fed9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lrem2.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lrem2 extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a % b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L, -1L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -9223372036854775808L, 1L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lreturn.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lreturn.java
new file mode 100644
index 0000000..fd7cc95
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lreturn.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lreturn extends JTTTest {
+
+    public static long test(long a) {
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 256L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1000000000000L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshl.java
new file mode 100644
index 0000000..230227a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshl extends JTTTest {
+
+    public static long test(long a, int b) {
+        return a << b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr.java
new file mode 100644
index 0000000..a458a2d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshr extends JTTTest {
+
+    public static long test(long a, int b) {
+        return a >> b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 67L, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 16);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr02.java
new file mode 100644
index 0000000..f7fa964
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lshr02.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshr02 extends JTTTest {
+
+    public static long test0(long arg) {
+        long a = arg >> 32;
+        return a >> 32;
+    }
+
+    @Test
+    public void run0a() throws Throwable {
+        runTest("test0", 1L);
+    }
+
+    @Test
+    public void run0b() throws Throwable {
+        runTest("test0", 0L);
+    }
+
+    @Test
+    public void run0c() throws Throwable {
+        runTest("test0", -1L);
+    }
+
+    @Test
+    public void run0d() throws Throwable {
+        runTest("test0", Long.MAX_VALUE);
+    }
+
+    @Test
+    public void run0e() throws Throwable {
+        runTest("test0", Long.MIN_VALUE);
+    }
+
+    /* testcase for a postive stamp */
+    public static int test1(long[] arg) {
+        int a = arg.length >> 16;
+        return a >> 16;
+    }
+
+    @Test
+    public void run1a() throws Throwable {
+        long[] arg = new long[0x100];
+        runTest("test1", arg);
+    }
+
+    /* testcase for a strictly negative stamp */
+    public static int test2(long[] arg) {
+        int a = (-arg.length - 1) >> 16;
+        return a >> 16;
+    }
+
+    @Test
+    public void run2a() throws Throwable {
+        long[] arg = new long[0x100];
+        runTest("test2", arg);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lsub.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lsub.java
new file mode 100644
index 0000000..190d64c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lsub.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lsub extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a - b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, -2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33L, -67L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1L, 1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, -1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2147483647L, -1L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -2147483647L, 2L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lushr.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lushr.java
new file mode 100644
index 0000000..5aaeb3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lushr.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lushr extends JTTTest {
+
+    public static long test(long a, int b) {
+        return a >>> b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 67L, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 16);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lxor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lxor.java
new file mode 100644
index 0000000..18fa124
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_lxor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lxor extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a ^ b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0L, -1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 31L, 63L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6L, 4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -2147483648L, 1L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter.java
new file mode 100644
index 0000000..d2390f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_monitorenter extends JTTTest {
+
+    static DummyTestClass object = new DummyTestClass();
+
+    public static int test(int arg) {
+        synchronized (object) {
+            return arg;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter02.java
new file mode 100644
index 0000000..918c2aa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_monitorenter02.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_monitorenter02 extends JTTTest {
+
+    static DummyTestClass object = new DummyTestClass();
+
+    public static int test(int arg, int arg2) {
+        int result = arg;
+        synchronized (object) {
+            result = arg / arg2;
+        }
+        synchronized (object) {
+            result = arg / arg2;
+        }
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2, 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray01.java
new file mode 100644
index 0000000..bd2b109
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray01.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_multianewarray01 extends JTTTest {
+
+    public static int test(int a) {
+        final DummyTestClass[][] v = new DummyTestClass[3][3];
+        return v != null ? a : -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray02.java
new file mode 100644
index 0000000..5516cb4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray02.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_multianewarray02 extends JTTTest {
+
+    public static int test(int a) {
+        final DummyTestClass[][][][] v = new DummyTestClass[3][3][3][3];
+        return v != null ? a : -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray03.java
new file mode 100644
index 0000000..d64868b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray03.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_multianewarray03 extends JTTTest {
+
+    public static int test(int a) {
+        final BC_multianewarray03[][][][] v = new BC_multianewarray03[a][a][a][a];
+        return v.length + v[0].length + v[0][0].length + v[0][0][0].length;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray04.java
new file mode 100644
index 0000000..c66986a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_multianewarray04.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_multianewarray04 extends JTTTest {
+
+    public static int test(int a) {
+        int i = 1;
+
+        i += testByte(a);
+        i += testBoolean(a);
+        i += testChar(a);
+        i += testShort(a);
+        i += testInt(a);
+        i += testFloat(a);
+        i += testLong(a);
+        i += testDouble(a);
+
+        return i;
+    }
+
+    private static int testDouble(int a) {
+        double[][] b2 = new double[a][a];
+        double[][][] b3 = new double[a][a][a];
+        double[][][][] b4 = new double[a][a][a][a];
+        double[][][][][] b5 = new double[a][a][a][a][a];
+        double[][][][][][] b6 = new double[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testLong(int a) {
+        long[][] b2 = new long[a][a];
+        long[][][] b3 = new long[a][a][a];
+        long[][][][] b4 = new long[a][a][a][a];
+        long[][][][][] b5 = new long[a][a][a][a][a];
+        long[][][][][][] b6 = new long[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testFloat(int a) {
+        float[][] b2 = new float[a][a];
+        float[][][] b3 = new float[a][a][a];
+        float[][][][] b4 = new float[a][a][a][a];
+        float[][][][][] b5 = new float[a][a][a][a][a];
+        float[][][][][][] b6 = new float[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testInt(int a) {
+        int[][] b2 = new int[a][a];
+        int[][][] b3 = new int[a][a][a];
+        int[][][][] b4 = new int[a][a][a][a];
+        int[][][][][] b5 = new int[a][a][a][a][a];
+        int[][][][][][] b6 = new int[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testShort(int a) {
+        short[][] b2 = new short[a][a];
+        short[][][] b3 = new short[a][a][a];
+        short[][][][] b4 = new short[a][a][a][a];
+        short[][][][][] b5 = new short[a][a][a][a][a];
+        short[][][][][][] b6 = new short[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testChar(int a) {
+        char[][] b2 = new char[a][a];
+        char[][][] b3 = new char[a][a][a];
+        char[][][][] b4 = new char[a][a][a][a];
+        char[][][][][] b5 = new char[a][a][a][a][a];
+        char[][][][][][] b6 = new char[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testBoolean(int a) {
+        boolean[][] b2 = new boolean[a][a];
+        boolean[][][] b3 = new boolean[a][a][a];
+        boolean[][][][] b4 = new boolean[a][a][a][a];
+        boolean[][][][][] b5 = new boolean[a][a][a][a][a];
+        boolean[][][][][][] b6 = new boolean[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    private static int testByte(int a) {
+        byte[][] b2 = new byte[a][a];
+        byte[][][] b3 = new byte[a][a][a];
+        byte[][][][] b4 = new byte[a][a][a][a];
+        byte[][][][][] b5 = new byte[a][a][a][a][a];
+        byte[][][][][][] b6 = new byte[a][a][a][a][a][a];
+        return b2.length + b3.length + b4.length + b5.length + b6.length;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_new.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_new.java
new file mode 100644
index 0000000..c7ff20f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_new.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_new extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a) {
+        new DummyTestClass();
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray.java
new file mode 100644
index 0000000..c2e936f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_newarray extends JTTTest {
+
+    @SuppressWarnings("all")
+    public static int test(int a) {
+        if (new boolean[3] == null) {
+            return -1;
+        }
+        if (new char[3] == null) {
+            return -1;
+        }
+        if (new float[3] == null) {
+            return -1;
+        }
+        if (new double[3] == null) {
+            return -1;
+        }
+        if (new byte[3] == null) {
+            return -1;
+        }
+        if (new short[3] == null) {
+            return -1;
+        }
+        if (new int[3] == null) {
+            return -1;
+        }
+        if (new long[3] == null) {
+            return -1;
+        }
+
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_01.java
new file mode 100644
index 0000000..0889861
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_01.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_putfield_01 extends JTTTest {
+
+    private static class TestClass {
+        private int field;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        object.field = arg;
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_02.java
new file mode 100644
index 0000000..0a231eb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_02.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_putfield_02 extends JTTTest {
+
+    private static class TestClass {
+        private Object field;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static Object test(Object arg) {
+        object.field = arg;
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "0");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "string");
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", "-4");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_03.java
new file mode 100644
index 0000000..05f55f8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_03.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_putfield_03 extends JTTTest {
+
+    private static class TestClass {
+        private volatile int field;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        object.field = arg;
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_04.java
new file mode 100644
index 0000000..5369d92
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putfield_04.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_putfield_04 extends JTTTest {
+
+    private static class TestClass {
+        private volatile Object field;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static Object test(Object arg) {
+        object.field = arg;
+        return object.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "0");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "string");
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", "-4");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putstatic.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putstatic.java
new file mode 100644
index 0000000..25f63bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_putstatic.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_putstatic extends JTTTest {
+
+    private static int field;
+
+    public static int test(int a) {
+        field = a;
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_saload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_saload.java
new file mode 100644
index 0000000..93c20f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_saload.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_saload extends JTTTest {
+
+    static short[] array = {0, -1, 4, 10000};
+
+    public static short test(int arg) {
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_sastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_sastore.java
new file mode 100644
index 0000000..34e6bc7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_sastore.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_sastore extends JTTTest {
+
+    static short[] array = {0, 0, 0, 0};
+
+    public static short test(int arg, short val) {
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((short) -1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, ((short) 11));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((short) -14));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch.java
new file mode 100644
index 0000000..df72d27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_tableswitch extends JTTTest {
+
+    public static int test(int a) {
+        switch (a) {
+            case 0:
+                return 10;
+            case 1:
+                return 20;
+            case 2:
+                return 30;
+            case 4:
+                return 40;
+            case 5:
+                return 50;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch2.java
new file mode 100644
index 0000000..81d6cca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch2.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_tableswitch2 extends JTTTest {
+
+    public static int test(int a) {
+        switch (a) {
+            case 5:
+                return 55;
+            case 6:
+                return 66;
+            case 7:
+                return 77;
+        }
+        return 11;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch3.java
new file mode 100644
index 0000000..49b4caa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch3.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_tableswitch3 extends JTTTest {
+
+    public static int test(int a) {
+        switch (a) {
+            case -2:
+                return 22;
+            case -1:
+                return 11;
+            case 0:
+                return 33;
+            case 1:
+                return 77;
+        }
+        return 99;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch4.java
new file mode 100644
index 0000000..585fd03
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_tableswitch4.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_tableswitch4 extends JTTTest {
+
+    public static int test(int a) {
+        switch (a) {
+            case -5:
+                return 55;
+            case -4:
+                return 44;
+            case -3:
+                return 33;
+        }
+        return 11;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -3);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide01.java
new file mode 100644
index 0000000..297ec5d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide01.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_wide01 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int arg) {
+
+        // Checkstyle: stop
+        long i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15;
+        long j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+        long k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15;
+        long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15;
+        long m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15;
+        long n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15;
+        long o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15;
+        long p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15;
+        long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15;
+        long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
+        // Checkstyle: resume
+
+        int i255 = 10;
+        return arg + i255 + 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide02.java
new file mode 100644
index 0000000..f46da85
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_wide02.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_wide02 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int arg) {
+
+        // Checkstyle: stop
+        long i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15;
+        long j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+        long k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15;
+        long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15;
+        long m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15;
+        long n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15;
+        long o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15;
+        long p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15;
+        long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15;
+        long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
+        // Checkstyle: resume
+
+        int i255 = 9;
+        i255++;
+        return arg + i255 + 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload0.java
new file mode 100644
index 0000000..65d3d77
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload0.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_aaload0 extends JTTTest {
+
+    static Object[] array = {null, null, ""};
+
+    public static Object test(int arg) {
+        final Object[] obj = arg == -2 ? null : array;
+        return obj[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload1.java
new file mode 100644
index 0000000..fd21103
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aaload1.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aaload1 extends JTTTest {
+
+    static Object[] array = {null, null, ""};
+
+    public static Object test(int arg) {
+        final Object[] obj = arg == -2 ? null : array;
+        try {
+            return obj[arg];
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore0.java
new file mode 100644
index 0000000..50cd9cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore0.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_aastore0 extends JTTTest {
+
+    static Object[] param = {new Object(), null, "h"};
+    static Object[] arr = {null, null, null};
+    static String[] arr2 = {null, null, null};
+
+    public static int test(boolean a, int indx) {
+        Object[] array = a ? arr : arr2;
+        Object val;
+        if (indx == -2) {
+            array = null;
+            val = null;
+        } else {
+            val = param[indx];
+        }
+        array[indx] = val;
+        return indx;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true, -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", true, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", true, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", true, 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", true, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", true, 3);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", false, 0);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", false, 1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", false, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", false, 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore1.java
new file mode 100644
index 0000000..c0b0632
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_aastore1.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_aastore1 extends JTTTest {
+
+    static Object[] param = {new Object(), null, "h"};
+    static Object[] arr = {null, null, null};
+    static String[] arr2 = {null, null, null};
+
+    public static int test(boolean a, int indx) {
+        try {
+            Object[] array = a ? arr : arr2;
+            Object val;
+            if (indx == -2) {
+                array = null;
+                val = null;
+            } else {
+                val = param[indx];
+            }
+            array[indx] = val;
+            return indx;
+        } catch (NullPointerException e) {
+            return 5;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true, -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", true, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", true, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", true, 1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", true, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", true, 3);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", false, 0);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", false, 1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", false, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", false, 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_anewarray.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_anewarray.java
new file mode 100644
index 0000000..31e7c34
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_anewarray.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_anewarray extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a) {
+        final DummyTestClass[] v = new DummyTestClass[a];
+        if (v != null) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_arraylength.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_arraylength.java
new file mode 100644
index 0000000..5bc66ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_arraylength.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_arraylength extends JTTTest {
+
+    static int[] arr = {1, 2, 3};
+    static char[] arr2 = {'a', 'b', 'c', 'd'};
+    static Object[] arr3 = new Object[5];
+
+    @SuppressWarnings("all")
+    public static int test(int arg) {
+        if (arg == 0) {
+            int[] array = null;
+            return array.length;
+        }
+        if (arg == 1) {
+            return arr.length;
+        }
+        if (arg == 2) {
+            return arr2.length;
+        }
+        if (arg == 3) {
+            return arr3.length;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow0.java
new file mode 100644
index 0000000..681154f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow0.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_athrow0 extends JTTTest {
+
+    static Throwable throwable = new Throwable();
+
+    public static int test(int arg) throws Throwable {
+        if (arg == 2) {
+            throw throwable;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow1.java
new file mode 100644
index 0000000..11844aa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow1.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_athrow1 extends JTTTest {
+
+    static Throwable throwable = new Throwable();
+
+    public static int test(int arg) throws Throwable {
+        if (arg == 2) {
+            throw throwable;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow2.java
new file mode 100644
index 0000000..015c022
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow2.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_athrow2 extends JTTTest {
+
+    static Throwable throwable = new Throwable();
+
+    public static int test(int arg) throws Throwable {
+        if (arg == 2) {
+            throw throwable;
+        } else if (arg == 3) {
+            throw null;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow3.java
new file mode 100644
index 0000000..0e30580
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_athrow3.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_athrow3 extends JTTTest {
+
+    static Throwable throwable = new Throwable();
+
+    public static int test(int arg) throws Throwable {
+        if (arg == 2) {
+            throw2();
+        } else if (arg == 3) {
+            throw1();
+        }
+        return arg;
+    }
+
+    private static void throw2() throws Throwable {
+        throw throwable;
+    }
+
+    private static void throw1() throws Throwable {
+        throw null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_baload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_baload.java
new file mode 100644
index 0000000..1f714df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_baload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_baload extends JTTTest {
+
+    static boolean[] arr = {true, false, true, false};
+
+    public static boolean test(int arg) {
+        final boolean[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_bastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_bastore.java
new file mode 100644
index 0000000..98d7256
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_bastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_bastore extends JTTTest {
+
+    static boolean[] arr = {false, false, false, false};
+
+    public static boolean test(int arg, boolean val) {
+        final boolean[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, true);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, true);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_caload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_caload.java
new file mode 100644
index 0000000..ad8318a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_caload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_caload extends JTTTest {
+
+    static char[] arr = {'\000', 'a', ' ', 10000};
+
+    public static char test(int arg) {
+        final char[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_castore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_castore.java
new file mode 100644
index 0000000..e7bfb11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_castore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_castore extends JTTTest {
+
+    static char[] arr = {0, 0, 0, 0};
+
+    public static char test(int arg, char val) {
+        final char[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, ((char) 97));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, ((char) 99));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((char) 97));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, ((char) 97));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast.java
new file mode 100644
index 0000000..23fc5cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj = null;
+        if (arg == 2) {
+            obj = object2;
+        }
+        if (arg == 3) {
+            obj = object3;
+        }
+        if (arg == 4) {
+            obj = object4;
+        }
+        final DummyTestClass bc = (DummyTestClass) obj;
+        if (bc == null) {
+            return arg;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast1.java
new file mode 100644
index 0000000..dca178a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast1.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast1 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj = null;
+        if (arg == 2) {
+            obj = object2;
+        }
+        if (arg == 3) {
+            obj = object3;
+        }
+        if (arg == 4) {
+            obj = object4;
+        }
+        final DummyTestClass bc = (DummyTestClass) obj;
+        if (bc == null) {
+            return arg;
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast2.java
new file mode 100644
index 0000000..e31134c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast2.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast2 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        final DummyTestClass bc = (DummyTestClass) obj;
+        if (bc != null) {
+            return arg;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast3.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast3.java
new file mode 100644
index 0000000..e4c85e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast3.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast3 extends JTTTest {
+
+    static Object[] o1 = {new Object()};
+    static String[] o2 = {""};
+    static DummyTestClass[] o3 = {new DummyTestClass()};
+
+    public static int test(int arg) {
+        Object obj = null;
+        if (arg == 0) {
+            obj = o1;
+        }
+        if (arg == 1) {
+            obj = o2;
+        }
+        if (arg == 2) {
+            obj = o3;
+        }
+        Object[] r = (DummyTestClass[]) obj;
+        return r == null ? -1 : -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast4.java
new file mode 100644
index 0000000..711b20e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast4.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class BC_checkcast4 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        final DummyTestClass bc = (DummyTestClass) obj;
+        if (bc != null) {
+            return arg;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast5.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast5.java
new file mode 100644
index 0000000..f2d2b50
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast5.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_checkcast5 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        try {
+            final DummyTestClass bc = (DummyTestClass) obj;
+            if (bc != null) {
+                return arg;
+            }
+        } catch (ClassCastException e) {
+            return -5;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast6.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast6.java
new file mode 100644
index 0000000..a695ade
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_checkcast6.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class BC_checkcast6 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj;
+        if (arg == 2) {
+            obj = object2;
+        } else if (arg == 3) {
+            obj = object3;
+        } else if (arg == 4) {
+            obj = object4;
+        } else {
+            obj = null;
+        }
+        try {
+            final DummyTestClass bc = (DummyTestClass) obj;
+            if (bc != null) {
+                return arg;
+            }
+        } catch (ClassCastException e) {
+            return -5;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_daload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_daload.java
new file mode 100644
index 0000000..d5e426a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_daload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_daload extends JTTTest {
+
+    static double[] arr = {0.0, -1.1, 4.32, 6.06};
+
+    public static double test(int arg) {
+        final double[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_dastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_dastore.java
new file mode 100644
index 0000000..5114365
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_dastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_dastore extends JTTTest {
+
+    static double[] arr = {0, 0, 0, 0};
+
+    public static double test(int arg, double val) {
+        final double[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, 0.01d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, -1.4d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 0.01d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, 0.01d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_faload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_faload.java
new file mode 100644
index 0000000..01305f2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_faload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_faload extends JTTTest {
+
+    static float[] arr = {0.0f, -1.1f, 4.32f, 6.06f};
+
+    public static float test(int arg) {
+        final float[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_fastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_fastore.java
new file mode 100644
index 0000000..dbb4556
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_fastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_fastore extends JTTTest {
+
+    static float[] arr = {0, 0, 0, 0};
+
+    public static float test(int arg, float val) {
+        final float[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, 0.01f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, -1.4f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 0.01f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, 0.01f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield.java
new file mode 100644
index 0000000..33dd83d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield extends JTTTest {
+
+    private static class TestClass {
+        private int field = 13;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        final TestClass obj = (arg == 3) ? null : object;
+        return obj.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield1.java
new file mode 100644
index 0000000..1753afa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_getfield1.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_getfield1 extends JTTTest {
+
+    private static class TestClass {
+        private int field = 13;
+    }
+
+    public static void test(TestClass arg) {
+        @SuppressWarnings("unused")
+        int i = arg.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        // tests that the null check isn't removed along with the read
+        runTest(EMPTY, true, true, "test", (Object) null);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new TestClass());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iaload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iaload.java
new file mode 100644
index 0000000..7185bfa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iaload.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_iaload extends JTTTest {
+
+    static int[] arr = {0, -1, 4, 1000000000};
+
+    public static int test(int arg) {
+        final int[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", Integer.MIN_VALUE);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iastore.java
new file mode 100644
index 0000000..9105e31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_iastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_iastore extends JTTTest {
+
+    static int[] arr = {0, 0, 0, 0};
+
+    public static int test(int arg, int val) {
+        final int[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, 3);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv.java
new file mode 100644
index 0000000..48a2849
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_idiv extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv2.java
new file mode 100644
index 0000000..14c519b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_idiv2.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_idiv2 extends JTTTest {
+
+    public static int test(int a, int b) {
+        try {
+            return a / b;
+        } catch (Exception e) {
+            return -11;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokespecial01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokespecial01.java
new file mode 100644
index 0000000..5c54495
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokespecial01.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokespecial01 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        private boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
+
+    public static boolean test(int arg) {
+        TestClass object = null;
+        if (arg == 0) {
+            object = obj;
+        }
+        return object.method();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual01.java
new file mode 100644
index 0000000..9238c89
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual01.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokevirtual01 extends JTTTest {
+
+    private static class TestClass {
+        public boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
+
+    public static boolean test(int arg) {
+        TestClass object = null;
+        if (arg == 0) {
+            object = obj;
+        }
+        return object.method();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual02.java
new file mode 100644
index 0000000..ac00d98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_invokevirtual02.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokevirtual02 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("static-method")
+        public final boolean method() {
+            return true;
+        }
+    }
+
+    private static final TestClass obj = new TestClass();
+
+    public static boolean test(int arg) {
+        TestClass object = null;
+        if (arg == 0) {
+            object = obj;
+        }
+        return object.method();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_irem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_irem.java
new file mode 100644
index 0000000..15b8b6ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_irem.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_irem extends JTTTest {
+
+    public static int test(int a, int b) {
+        return a % b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_laload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_laload.java
new file mode 100644
index 0000000..d50c9a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_laload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_laload extends JTTTest {
+
+    static long[] arr = {0L, -1L, 4L, 1000000000000L};
+
+    public static long test(int arg) {
+        final long[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lastore.java
new file mode 100644
index 0000000..de676ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_lastore extends JTTTest {
+
+    static long[] arr = {0, 0, 0, 0};
+
+    public static long test(int arg, long val) {
+        final long[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, 3L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 0L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, 0L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv.java
new file mode 100644
index 0000000..6974311
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_ldiv extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a / b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11L, 0L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv2.java
new file mode 100644
index 0000000..dfd90ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_ldiv2.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_ldiv2 extends JTTTest {
+
+    public static long test(long a, long b) {
+        try {
+            return a / b;
+        } catch (Exception e) {
+            return -11;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11L, 0L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 11L, 1000000000000L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1000000000000L, 11L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1000000000000L, 0L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lrem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lrem.java
new file mode 100644
index 0000000..02bfb27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_lrem.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_lrem extends JTTTest {
+
+    public static long test(long a, long b) {
+        return a % b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1L, 2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 11L, 0L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_monitorenter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_monitorenter.java
new file mode 100644
index 0000000..6b3b9fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_monitorenter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_monitorenter extends JTTTest {
+
+    static DummyTestClass object = new DummyTestClass();
+
+    public static boolean test(boolean arg) {
+        final Object o = arg ? object : null;
+        synchronized (o) {
+            return arg;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", false);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_multianewarray.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_multianewarray.java
new file mode 100644
index 0000000..d4cc41e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_multianewarray.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_multianewarray extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a, int b) {
+        final DummyTestClass[][] v = new DummyTestClass[a][b];
+        if (v != null) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_newarray.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_newarray.java
new file mode 100644
index 0000000..e3f6415
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_newarray.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_newarray extends JTTTest {
+
+    @SuppressWarnings("all")
+    public static int test(int a) {
+        if (new boolean[a] == null) {
+            return -1;
+        }
+        if (new char[a] == null) {
+            return -1;
+        }
+        if (new float[a] == null) {
+            return -1;
+        }
+        if (new double[a] == null) {
+            return -1;
+        }
+        if (new byte[a] == null) {
+            return -1;
+        }
+        if (new short[a] == null) {
+            return -1;
+        }
+        if (new int[a] == null) {
+            return -1;
+        }
+        if (new long[a] == null) {
+            return -1;
+        }
+
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_putfield.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_putfield.java
new file mode 100644
index 0000000..88b9088
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_putfield.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_putfield extends JTTTest {
+
+    private static class TestClass {
+        private int field;
+    }
+
+    private static TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        final TestClass obj = arg == 3 ? null : object;
+        obj.field = arg;
+        return obj.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_saload.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_saload.java
new file mode 100644
index 0000000..fd988d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_saload.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_saload extends JTTTest {
+
+    static short[] arr = {0, -1, 4, 10000};
+
+    public static short test(int arg) {
+        final short[] array = arg == -2 ? null : arr;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_sastore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_sastore.java
new file mode 100644
index 0000000..e96c509
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/BC_sastore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_sastore extends JTTTest {
+
+    static short[] arr = {0, 0, 0, 0};
+
+    public static short test(int arg, short val) {
+        final short[] array = arg == -2 ? null : arr;
+        array[arg] = val;
+        return array[arg];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2, ((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1, ((short) 3));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((short) 0));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4, ((short) 0));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop01.java
new file mode 100644
index 0000000..2aabe7c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop01.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Loop01 extends JTTTest {
+
+    public static int test(int arg) {
+        int accum = 0;
+        for (int i = 0; i < arg; i++) {
+            try {
+                accum += div(20, i);
+            } catch (ArithmeticException e) {
+                accum -= 100;
+            }
+        }
+        return accum;
+    }
+
+    static int div(int a, int b) {
+        return a / (b % 3);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 30);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop02.java
new file mode 100644
index 0000000..984bee3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop02.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Loop02 extends JTTTest {
+
+    public static int test(int arg) {
+        int accum = 0;
+        for (int i = 0; i < arg; i++) {
+            try {
+                accum += div(20, i);
+            } catch (IllegalArgumentException e) {
+                accum -= 100;
+            }
+        }
+        return accum;
+    }
+
+    static int div(int a, int b) {
+        if (b % 3 == 0) {
+            throw new IllegalArgumentException();
+        }
+        return a / (b % 3);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 30);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop03.java
new file mode 100644
index 0000000..1b93d4d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Loop03.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Loop03 extends JTTTest {
+
+    public static int test(int arg) {
+        int accum = 0;
+        for (int i = 0; i < arg; i++) {
+            try {
+                accum += div(20, i);
+            } catch (Catch_Loop03_Exception1 e) {
+                accum -= 100;
+            }
+        }
+        return accum;
+    }
+
+    static int div(int a, int b) {
+        if (b % 3 == 0) {
+            throw new Catch_Loop03_Exception1();
+        }
+        return a / (b % 3);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 30);
+    }
+
+}
+
+@SuppressWarnings("serial")
+class Catch_Loop03_Exception1 extends RuntimeException {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_1.java
new file mode 100644
index 0000000..f8cb55b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_1.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NASE_1 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a) {
+        try {
+            int[] v = new int[a];
+            if (v != null) {
+                return v.length;
+            }
+            return -1;
+        } catch (NegativeArraySizeException e) {
+            return 100;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -34);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_2.java
new file mode 100644
index 0000000..ca32df4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NASE_2.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NASE_2 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static int test(int a) {
+        try {
+            DummyTestClass[] v = new DummyTestClass[a];
+            if (v != null) {
+                return v.length;
+            }
+            return -1;
+        } catch (NegativeArraySizeException e) {
+            return 100;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -34);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_00.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_00.java
new file mode 100644
index 0000000..f3963a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_00.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_00 extends JTTTest {
+
+    public static int test(int a) {
+        int[] array = a > 0 ? new int[3] : null;
+        try {
+            return array.length;
+        } catch (NullPointerException npe) {
+            return -1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -3);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_01.java
new file mode 100644
index 0000000..a81315e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_01.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_01 extends JTTTest {
+
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                throw new NullPointerException();
+            }
+        } catch (NullPointerException npe) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_02.java
new file mode 100644
index 0000000..831ea82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_02.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_02 extends JTTTest {
+
+    public static int test(int a) {
+        try {
+            throwNPE(a);
+        } catch (NullPointerException npe) {
+            return a;
+        }
+        return -1;
+    }
+
+    private static void throwNPE(int a) {
+        if (a >= 0) {
+            throw new NullPointerException();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_03.java
new file mode 100644
index 0000000..8ed01ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_03.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_03 extends JTTTest {
+
+    @SuppressWarnings("all")
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                final Object o = null;
+                return o.hashCode();
+            }
+        } catch (NullPointerException npe) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_04.java
new file mode 100644
index 0000000..103c45e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_04.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_04 extends JTTTest {
+
+    private int field = 45;
+
+    @SuppressWarnings("all")
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                final Catch_NPE_04 obj = null;
+                return obj.field;
+            }
+        } catch (NullPointerException npe) {
+            return a;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_05.java
new file mode 100644
index 0000000..90f8575
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_05.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_05 extends JTTTest {
+
+    private int field = 45;
+
+    public static int test(int a) {
+        try {
+            return throwNPE(a);
+        } catch (NullPointerException npe) {
+            return a;
+        }
+    }
+
+    @SuppressWarnings("all")
+    private static int throwNPE(int a) {
+        if (a >= 0) {
+            final Catch_NPE_05 obj = null;
+            return obj.field;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_06.java
new file mode 100644
index 0000000..29780d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_06.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_06 extends JTTTest {
+
+    public static int test(String string) {
+        try {
+            return string.hashCode();
+        } catch (NullPointerException npe) {
+            return -1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_07.java
new file mode 100644
index 0000000..2ba2182
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_07.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_07 extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class MyThrowable extends Throwable {
+    }
+
+    @SuppressWarnings("unused")
+    public static int foo(Throwable t) {
+        try {
+            throw t;
+        } catch (Throwable t1) {
+            if (t1 == null) {
+                return -1;
+            }
+            if (t1 instanceof NullPointerException) {
+                return 0;
+            }
+            if (t1 instanceof MyThrowable) {
+                return 1;
+            }
+            return -2;
+        }
+    }
+
+    public static int test(int i) {
+        Throwable t = (i == 0) ? null : new MyThrowable();
+        try {
+            return foo(t);
+        } catch (Throwable t1) {
+            return -3;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_08.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_08.java
new file mode 100644
index 0000000..4a05db7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_08.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_08 extends JTTTest {
+
+    public static int test(int a) {
+        try {
+            throwNPE(a);
+        } catch (NullPointerException npe) {
+            return a;
+        }
+        return -1;
+    }
+
+    @SuppressWarnings("unused")
+    private static void throwNPE(int a) {
+        throw null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_09.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_09.java
new file mode 100644
index 0000000..5434dbc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_09.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_09 extends JTTTest {
+
+    public static int test(int a) {
+        int r = 0;
+        try {
+            r = 0;
+            throwNPE(a);
+            r = 1;
+            throwNPE(a - 1);
+        } catch (NullPointerException e) {
+            return r + 10;
+        }
+        return r;
+    }
+
+    private static void throwNPE(int a) {
+        if (a == 0) {
+            throw null;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_10.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_10.java
new file mode 100644
index 0000000..79ea511
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_10.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_10 extends JTTTest {
+
+    public static int test(int a) {
+        int r = 0;
+        try {
+            r = 0;
+            if (a == 0) {
+                throw null;
+            }
+            r = 1;
+            if (a - 1 == 0) {
+                throw null;
+            }
+        } catch (NullPointerException e) {
+            return r + 10;
+        }
+        return r;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_11.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_11.java
new file mode 100644
index 0000000..8207c83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_NPE_11.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_NPE_11 extends JTTTest {
+
+    public static int test(int a) {
+        int r = 0;
+        try {
+            r = 0;
+            throwE(a);
+            r = 1;
+            throwE(a - 1);
+        } catch (ArithmeticException e) {
+            return r + 10;
+        }
+        return r;
+    }
+
+    private static int throwE(int a) {
+        return 1 / a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_01.java
new file mode 100644
index 0000000..9f25b2e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_01.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_StackOverflowError_01 extends JTTTest {
+
+    private static void recurse() {
+        recurse();
+    }
+
+    public static int test() throws StackOverflowError {
+        recurse();
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_02.java
new file mode 100644
index 0000000..02189ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_02.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_StackOverflowError_02 extends JTTTest {
+
+    private static void recurse() {
+        recurse();
+    }
+
+    public static int test() {
+        try {
+            recurse();
+        } catch (StackOverflowError stackOverflowError) {
+            // tests that the guard page was reset and a second SOE can be handled
+            recurse();
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_03.java
new file mode 100644
index 0000000..b55487b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_StackOverflowError_03.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * Some basic checking of the stack trace produced after a StackOverflowError.
+ */
+public class Catch_StackOverflowError_03 extends JTTTest {
+
+    private static final int PASS = 0;
+    private static final int FAIL = 1;
+
+    private static void recurseA() {
+        recurseB();
+    }
+
+    private static void recurseB() {
+        recurseA();
+    }
+
+    public static int test() {
+        try {
+            recurseA();
+        } catch (StackOverflowError stackOverflowError) {
+            // Check that a method does not appear to be calling itself in the stack trace
+            // and check that recurse* is only called by either recurse* or test
+            StackTraceElement[] elements = null;
+            elements = stackOverflowError.getStackTrace();
+            if (elements.length == 0) {
+                // Not much we can do about this perfectly legal situation
+                return PASS;
+            }
+            String lastMethodName = elements[0].getMethodName();
+            for (int i = 1; i < elements.length; ++i) {
+                String methodName = elements[i].getMethodName();
+
+                // Skip top-of-stack until we find a method with name "recurse*".
+                if (!methodName.startsWith("recurse")) {
+                    continue;
+                }
+
+                // We reached the test method => done.
+                if (methodName.equals("test")) {
+                    break;
+                }
+
+                // Stack elements must alternate between recurseA and recurseB
+                if (lastMethodName.equals(methodName) || (!methodName.equals("recurseA") && !methodName.equals("recurseB"))) {
+                    return FAIL;
+                }
+
+                lastMethodName = methodName;
+            }
+
+            return PASS;
+        }
+
+        return FAIL;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two01.java
new file mode 100644
index 0000000..ef85037
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two01.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Two01 extends JTTTest {
+
+    public static String test(int arg) {
+        try {
+            throwSomething(arg);
+        } catch (NullPointerException e) {
+            return e.getClass().getName();
+        } catch (ArithmeticException e) {
+            return e.getClass().getName();
+        }
+        return "none";
+    }
+
+    private static void throwSomething(int arg) {
+        if (arg == 0) {
+            throw new NullPointerException();
+        }
+        if (arg == 1) {
+            throw new ArithmeticException();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two02.java
new file mode 100644
index 0000000..386d3bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two02.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Two02 extends JTTTest {
+
+    public static String test(int arg) {
+        try {
+            throwSomething(arg + 10);
+        } catch (NullPointerException e) {
+            return e.getClass().getName();
+        } catch (ArithmeticException e) {
+            return e.getClass().getName();
+        }
+        return "none" + (arg + 10);
+    }
+
+    private static void throwSomething(int arg) {
+        if (arg == 10) {
+            throw new NullPointerException();
+        }
+        if (arg == 11) {
+            throw new ArithmeticException();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two03.java
new file mode 100644
index 0000000..283bb32
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Two03.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Two03 extends JTTTest {
+
+    public static String test(int arg) {
+        int r = 0;
+        try {
+            r = 1;
+            throwSomething(r + arg);
+            r = 2;
+            throwSomething(r + arg);
+            r = 3;
+            throwSomething(r + arg);
+            r = 4;
+        } catch (NullPointerException e) {
+            return e.getClass().getName() + r;
+        } catch (ArithmeticException e) {
+            return e.getClass().getName() + r;
+        }
+        return "none" + r;
+    }
+
+    private static void throwSomething(int arg) {
+        if (arg == 5) {
+            throw new NullPointerException();
+        }
+        if (arg == 6) {
+            throw new ArithmeticException();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved.java
new file mode 100644
index 0000000..f886ae2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Unresolved extends JTTTest {
+
+    public static boolean executed;
+
+    public static int test(int arg) {
+        executed = false;
+        try {
+            helper1(arg);
+            helper2(arg);
+        } catch (Catch_Unresolved_Exception1 e) {
+            return 1;
+        } catch (Catch_Unresolved_Exception2 e) {
+            return 2;
+        }
+        return 0;
+    }
+
+    private static void helper1(int arg) {
+        if (executed) {
+            throw new IllegalStateException("helper1 may only be called once");
+        }
+        executed = true;
+        if (arg == 1) {
+            throw new Catch_Unresolved_Exception1();
+        } else if (arg == 2) {
+            throw new Catch_Unresolved_Exception2();
+        }
+    }
+
+    private static void helper2(int arg) {
+        if (arg != 0) {
+            throw new IllegalStateException("helper2 can only be called if arg==0");
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved_Exception1 extends RuntimeException {
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved_Exception2 extends RuntimeException {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved01.java
new file mode 100644
index 0000000..6d2c27d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved01.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Unresolved01 extends JTTTest {
+
+    public static boolean executed;
+
+    public static int test(int arg) {
+        executed = false;
+        try {
+            helper1(arg);
+        } catch (Catch_Unresolved_Exception3 e) {
+            return 1;
+        } catch (Catch_Unresolved_Exception4 e) {
+            return 2;
+        }
+        return 0;
+    }
+
+    private static void helper1(int arg) {
+        if (executed) {
+            throw new IllegalStateException("helper1 may only be called once");
+        }
+        executed = true;
+        if (arg == 1) {
+            throw new Catch_Unresolved_Exception3();
+        } else if (arg == 2) {
+            throw new Catch_Unresolved_Exception4();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved_Exception3 extends RuntimeException {
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved_Exception4 extends RuntimeException {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved02.java
new file mode 100644
index 0000000..5156d22
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved02.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Unresolved02 extends JTTTest {
+
+    public static boolean executed;
+    public static int value;
+
+    public static int test(int arg) {
+        executed = false;
+        int result = 0;
+        try {
+            result = value + helper1(arg) + helper2(arg);
+        } catch (Catch_Unresolved02_Exception1 e) {
+            return 1 + result;
+        } catch (Catch_Unresolved02_Exception2 e) {
+            return 2 + result;
+        }
+        return result;
+    }
+
+    private static int helper1(int arg) {
+        if (executed) {
+            throw new IllegalStateException("helper1 may only be called once");
+        }
+        executed = true;
+        if (arg == 1) {
+            throw new Catch_Unresolved02_Exception1();
+        } else if (arg == 2) {
+            throw new Catch_Unresolved02_Exception2();
+        }
+        return 0;
+    }
+
+    private static int helper2(int arg) {
+        if (arg != 0) {
+            throw new IllegalStateException("helper2 can only be called if arg==0");
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved02_Exception1 extends RuntimeException {
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved02_Exception2 extends RuntimeException {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved03.java
new file mode 100644
index 0000000..25902d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Catch_Unresolved03.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Catch_Unresolved03 extends JTTTest {
+
+    public static boolean executed;
+    public static int value;
+
+    public static int test(int arg) {
+        executed = false;
+        int result = 0;
+        try {
+            result = value + helper1(arg) + helper2(arg);
+        } catch (Catch_Unresolved03_Exception1 e) {
+            if (arg == 1) {
+                return 1;
+            }
+            return new Catch_Unresolved03_UnresolvedClass().value();
+        }
+        return result;
+    }
+
+    private static int helper1(int arg) {
+        if (executed) {
+            throw new IllegalStateException("helper1 may only be called once");
+        }
+        executed = true;
+        if (arg == 1 || arg == 2) {
+            throw new Catch_Unresolved03_Exception1();
+        }
+        return 0;
+    }
+
+    private static int helper2(int arg) {
+        if (arg != 0) {
+            throw new IllegalStateException("helper2 can only be called if arg==0");
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
+
+@SuppressWarnings("serial")
+class Catch_Unresolved03_Exception1 extends RuntimeException {
+}
+
+class Catch_Unresolved03_UnresolvedClass {
+
+    public int value() {
+        return 2;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Locals.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Locals.java
new file mode 100644
index 0000000..235082f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Locals.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Except_Locals extends JTTTest {
+
+    public static int test(String a, String b) {
+        int x = 0;
+        try {
+            x = 1;
+            a.toString();
+            x = 2;
+            b.toString();
+        } catch (NullPointerException e) {
+            return x;
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", null, null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "", null);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "", "");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized01.java
new file mode 100644
index 0000000..001766b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized01.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Except_Synchronized01 extends JTTTest {
+
+    private static class TestClass {
+        final int x = 1;
+
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            try {
+                TestClass object = null;
+                return object.x;
+            } catch (NullPointerException e) {
+                return 2;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static int test(int i) throws Exception {
+        if (i == 0) {
+            return 0;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized02.java
new file mode 100644
index 0000000..ce6e838
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized02.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Except_Synchronized02 extends JTTTest {
+
+    private static class TestClass {
+
+        final int x = 1;
+
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            while (true) {
+                try {
+                    TestClass object = null;
+                    return object.x;
+                } catch (NullPointerException e) {
+                    return 2;
+                }
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static int test(int i) throws Exception {
+        if (i == 0) {
+            return 0;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized03.java
new file mode 100644
index 0000000..771a9d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized03.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Except_Synchronized03 extends JTTTest {
+
+    private static class TestClass {
+        int x = 1;
+
+        @SuppressWarnings("all")
+        public synchronized int test2(int i) throws Exception {
+            while (true) {
+                try {
+                    synchronized (this) {
+                        TestClass object = null;
+                        return object.x;
+                    }
+                } catch (NullPointerException e) {
+                    return 2;
+                }
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static int test(int i) throws Exception {
+        if (i == 0) {
+            return 0;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized04.java
new file mode 100644
index 0000000..a8c760e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized04.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Except_Synchronized04 extends JTTTest {
+
+    private static class TestClass {
+
+        final int x = 1;
+
+        @SuppressWarnings("all")
+        public int test2(int i) throws Exception {
+            try {
+                synchronized (Except_Synchronized04.class) {
+                    TestClass object = null;
+                    return object.x;
+                }
+            } catch (NullPointerException e) {
+                return 2;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static int test(int i) throws Exception {
+        if (i == 0) {
+            return 0;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized05.java
new file mode 100644
index 0000000..05ca598
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Except_Synchronized05.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Except_Synchronized05 extends JTTTest {
+
+    static class Foo {
+
+        Object field;
+
+        public synchronized Object bar(int arg) {
+            try {
+                String f = foo1(arg);
+                if (f == null) {
+                    field = new Object();
+                }
+            } catch (NullPointerException e) {
+                // do nothing
+            }
+            return field;
+        }
+
+        public Object baz(int arg) {
+            synchronized (this) {
+                try {
+                    String f = foo1(arg);
+                    if (f == null) {
+                        field = new Object();
+                    }
+                } catch (NullPointerException e) {
+                    // do nothing
+                }
+                return field;
+            }
+        }
+
+        @SuppressWarnings("static-method")
+        private String foo1(int arg) {
+            if (arg == 0) {
+                throw null;
+            }
+            return null;
+        }
+
+    }
+
+    public static int test(int arg) {
+        Foo obj = new Foo();
+        int a = obj.bar(arg) != null ? 1 : 0;
+        int b = obj.baz(arg) != null ? 1 : 0;
+        return a + b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally01.java
new file mode 100644
index 0000000..151ab3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally01.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Finally01 extends JTTTest {
+
+    /**
+     * @param arg
+     */
+    @SuppressWarnings("finally")
+    public static int test(int arg) {
+        try {
+            return 0;
+        } finally {
+            return -1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally02.java
new file mode 100644
index 0000000..2e1336b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Finally02.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Finally02 extends JTTTest {
+
+    public static int test() {
+        try {
+            a();
+        } finally {
+            b();
+        }
+
+        return c();
+    }
+
+    static int a() {
+        return 0;
+    }
+
+    static int b() {
+        return -3;
+    }
+
+    static int c() {
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_AIOOBE_00.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_AIOOBE_00.java
new file mode 100644
index 0000000..03cf2a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_AIOOBE_00.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_AIOOBE_00 extends JTTTest {
+
+    private static int[] array = new int[3];
+
+    public static int test(int a) {
+        try {
+            return array[a];
+        } catch (ArrayIndexOutOfBoundsException npe) {
+            for (StackTraceElement e : npe.getStackTrace()) {
+                if (e.getClassName().equals(StackTrace_AIOOBE_00.class.getName()) && e.getMethodName().equals("test")) {
+                    return -1;
+                }
+            }
+        }
+        return -2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_CCE_00.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_CCE_00.java
new file mode 100644
index 0000000..9dc6565
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_CCE_00.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_CCE_00 extends JTTTest {
+
+    static Object object2 = new Object();
+    static Object object3 = "";
+    static Object object4 = new DummyTestClass();
+
+    public static int test(int arg) {
+        Object obj = null;
+        if (arg == 2) {
+            obj = object2;
+        }
+        if (arg == 3) {
+            obj = object3;
+        }
+        if (arg == 4) {
+            obj = object4;
+        }
+        try {
+            final DummyTestClass bc = (DummyTestClass) obj;
+            if (bc == null) {
+                return arg;
+            }
+            return arg;
+        } catch (ClassCastException npe) {
+            for (StackTraceElement e : npe.getStackTrace()) {
+                if (e.getClassName().equals(StackTrace_CCE_00.class.getName()) && e.getMethodName().equals("test")) {
+                    return -100;
+                }
+            }
+            return -200;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_00.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_00.java
new file mode 100644
index 0000000..a75cffe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_00.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_NPE_00 extends JTTTest {
+
+    public static int test(int a) {
+        int[] array = a > 0 ? new int[3] : null;
+        try {
+            return array.length;
+        } catch (NullPointerException npe) {
+            for (StackTraceElement e : npe.getStackTrace()) {
+                if (e.getClassName().equals(StackTrace_NPE_00.class.getName())) {
+                    return -1;
+                }
+            }
+            return -2;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -3);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_01.java
new file mode 100644
index 0000000..730f4ad
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_01.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_NPE_01 extends JTTTest {
+
+    @SuppressWarnings("all")
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                final Object o = null;
+                return o.hashCode();
+            }
+        } catch (NullPointerException npe) {
+            for (StackTraceElement e : npe.getStackTrace()) {
+                if (e.getClassName().equals(StackTrace_NPE_01.class.getName()) && e.getMethodName().equals("test")) {
+                    return a;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_02.java
new file mode 100644
index 0000000..2e6a00f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_02.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_NPE_02 extends JTTTest {
+
+    private static String[] trace = {"test1", "test"};
+
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                return test1();
+            }
+        } catch (NullPointerException npe) {
+            String thisClass = StackTrace_NPE_02.class.getName();
+            StackTraceElement[] stackTrace = npe.getStackTrace();
+            for (int i = 0; i < stackTrace.length; i++) {
+                StackTraceElement e = stackTrace[i];
+                if (e.getClassName().equals(thisClass)) {
+                    for (int j = 0; j < trace.length; j++) {
+                        StackTraceElement f = stackTrace[i + j];
+                        if (!f.getClassName().equals(thisClass)) {
+                            return -2;
+                        }
+                        if (!f.getMethodName().equals(trace[j])) {
+                            return -3;
+                        }
+                    }
+                    return 0;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @SuppressWarnings("all")
+    private static int test1() {
+        final Object o = null;
+        return o.hashCode();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_03.java
new file mode 100644
index 0000000..88d84db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/StackTrace_NPE_03.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class StackTrace_NPE_03 extends JTTTest {
+
+    private static String[] trace = {"test2", "test1", "test"};
+
+    public static int test(int a) {
+        try {
+            if (a >= 0) {
+                return test1();
+            }
+        } catch (NullPointerException npe) {
+            String thisClass = StackTrace_NPE_03.class.getName();
+            StackTraceElement[] stackTrace = npe.getStackTrace();
+            for (int i = 0; i < stackTrace.length; i++) {
+                StackTraceElement e = stackTrace[i];
+                if (e.getClassName().equals(thisClass)) {
+                    for (int j = 0; j < trace.length; j++) {
+                        StackTraceElement f = stackTrace[i + j];
+                        if (!f.getClassName().equals(thisClass)) {
+                            return -2;
+                        }
+                        if (!f.getMethodName().equals(trace[j])) {
+                            return -3;
+                        }
+                    }
+                    return 0;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private static int test1() {
+        return test2();
+    }
+
+    private static int test2() {
+        throw new NullPointerException();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch01.java
new file mode 100644
index 0000000..4b24c9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch01.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_InCatch01 extends JTTTest {
+
+    public static boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        try {
+            throw new Exception();
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch02.java
new file mode 100644
index 0000000..17a0657
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch02.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_InCatch02 extends JTTTest {
+
+    public static boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        try {
+            throwE();
+        } catch (Exception e) {
+            throwE(e);
+        }
+        return false;
+    }
+
+    private static void throwE(Exception e) throws Exception {
+        throw e;
+    }
+
+    private static void throwE() throws Exception {
+        throw new Exception();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch03.java
new file mode 100644
index 0000000..818c6fb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InCatch03.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_InCatch03 extends JTTTest {
+
+    public static boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        try {
+            throwE();
+        } catch (Exception e) {
+            throw e;
+        }
+        return false;
+    }
+
+    private static void throwE() throws Exception {
+        throw new Exception();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InNested.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InNested.java
new file mode 100644
index 0000000..f3abf3d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_InNested.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_InNested extends JTTTest {
+
+    public static int test(int i) throws Exception {
+        return 42 + test2(i);
+    }
+
+    public static int test2(int i) throws Exception {
+        try {
+            return test3(i);
+        } catch (Exception e) {
+            return 5;
+        }
+    }
+
+    private static int test3(int i) {
+        if (i == 0) {
+            throw new RuntimeException();
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_NPE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_NPE_01.java
new file mode 100644
index 0000000..9242532
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_NPE_01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_NPE_01 extends JTTTest {
+
+    public static int test(int i) throws Exception {
+        int a = test2(i);
+        a = a + 1;
+        return a;
+    }
+
+    public static int test2(int i) {
+        if (i < 0) {
+            throw null;
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized01.java
new file mode 100644
index 0000000..9f11c37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized01.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_Synchronized01 extends JTTTest {
+
+    public static synchronized boolean test(int i) throws Exception {
+        return i == 0 || test2(i);
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean test2(int i) throws Exception {
+        throw new Exception();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized02.java
new file mode 100644
index 0000000..ea3c592
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized02.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_Synchronized02 extends JTTTest {
+
+    public static synchronized boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        throw new Exception();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized03.java
new file mode 100644
index 0000000..87c1483
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized03.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_Synchronized03 extends JTTTest {
+
+    public static synchronized boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        return test2(i);
+    }
+
+    @SuppressWarnings("unused")
+    public static synchronized boolean test2(int i) throws Exception {
+        throw new Exception();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized04.java
new file mode 100644
index 0000000..02222c5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized04.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_Synchronized04 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        public synchronized boolean test2(int i) throws Exception {
+            throw new Exception();
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized05.java
new file mode 100644
index 0000000..1ec341e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/Throw_Synchronized05.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Throw_Synchronized05 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        public synchronized boolean test2(int i) throws Exception {
+            try {
+                throw new Exception();
+            } catch (Exception e) {
+                // do nothing and then rethrow
+                throw e;
+            }
+        }
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static boolean test(int i) throws Exception {
+        if (i == 0) {
+            return true;
+        }
+        return object.test2(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java
new file mode 100644
index 0000000..ac93957
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.except;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.test.ExportingClassLoader;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+
+public class UntrustedInterfaces extends JTTTest {
+
+    public interface CallBack {
+        int callBack(TestInterface ti);
+    }
+
+    private interface TestInterface {
+        int method();
+    }
+
+    /**
+     * What a GoodPill would look like.
+     *
+     * <pre>
+     * private static final class GoodPill extends Pill {
+     *     public void setField() {
+     *         field = new TestConstant();
+     *     }
+     *
+     *     public void setStaticField() {
+     *         staticField = new TestConstant();
+     *     }
+     *
+     *     public int callMe(CallBack callback) {
+     *         return callback.callBack(new TestConstant());
+     *     }
+     *
+     *     public TestInterface get() {
+     *         return new TestConstant();
+     *     }
+     * }
+     *
+     * private static final class TestConstant implements TestInterface {
+     *     public int method() {
+     *         return 42;
+     *     }
+     * }
+     * </pre>
+     */
+    public abstract static class Pill {
+        public static TestInterface staticField;
+        public TestInterface field;
+
+        public abstract void setField();
+
+        public abstract void setStaticField();
+
+        public abstract int callMe(CallBack callback);
+
+        public abstract TestInterface get();
+    }
+
+    public int callBack(TestInterface list) {
+        return list.method();
+    }
+
+    public int staticFieldInvoke(Pill pill) {
+        pill.setStaticField();
+        return Pill.staticField.method();
+    }
+
+    public int fieldInvoke(Pill pill) {
+        pill.setField();
+        return pill.field.method();
+    }
+
+    public int argumentInvoke(Pill pill) {
+        return pill.callMe(ti -> ti.method());
+    }
+
+    public int returnInvoke(Pill pill) {
+        return pill.get().method();
+    }
+
+    @SuppressWarnings("cast")
+    public boolean staticFieldInstanceof(Pill pill) {
+        pill.setStaticField();
+        return Pill.staticField instanceof TestInterface;
+    }
+
+    @SuppressWarnings("cast")
+    public boolean fieldInstanceof(Pill pill) {
+        pill.setField();
+        return pill.field instanceof TestInterface;
+    }
+
+    @SuppressWarnings("cast")
+    public int argumentInstanceof(Pill pill) {
+        return pill.callMe(ti -> ti instanceof TestInterface ? 42 : 24);
+    }
+
+    @SuppressWarnings("cast")
+    public boolean returnInstanceof(Pill pill) {
+        return pill.get() instanceof TestInterface;
+    }
+
+    public TestInterface staticFieldCheckcast(Pill pill) {
+        pill.setStaticField();
+        return TestInterface.class.cast(Pill.staticField);
+    }
+
+    public TestInterface fieldCheckcast(Pill pill) {
+        pill.setField();
+        return TestInterface.class.cast(pill.field);
+    }
+
+    public int argumentCheckcast(Pill pill) {
+        return pill.callMe(ti -> TestInterface.class.cast(ti).method());
+    }
+
+    public TestInterface returnCheckcast(Pill pill) {
+        return TestInterface.class.cast(pill.get());
+    }
+
+    private static Pill poisonPill;
+
+    // Checkstyle: stop
+    @BeforeClass
+    public static void setUp() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        poisonPill = (Pill) new PoisonLoader().findClass(PoisonLoader.POISON_IMPL_NAME).newInstance();
+    }
+
+    // Checkstyle: resume
+
+    @Test
+    public void testStaticField0() {
+        runTest("staticFieldInvoke", poisonPill);
+    }
+
+    @Test
+    public void testStaticField1() {
+        runTest("staticFieldInstanceof", poisonPill);
+    }
+
+    @Test
+    public void testStaticField2() {
+        runTest("staticFieldCheckcast", poisonPill);
+    }
+
+    @Test
+    public void testField0() {
+        runTest("fieldInvoke", poisonPill);
+    }
+
+    @Test
+    public void testField1() {
+        runTest("fieldInstanceof", poisonPill);
+    }
+
+    @Test
+    public void testField2() {
+        runTest("fieldCheckcast", poisonPill);
+    }
+
+    @Test
+    public void testArgument0() {
+        runTest("argumentInvoke", poisonPill);
+    }
+
+    @Test
+    public void testArgument1() {
+        runTest("argumentInstanceof", poisonPill);
+    }
+
+    @Test
+    public void testArgument2() {
+        runTest("argumentCheckcast", poisonPill);
+    }
+
+    @Test
+    public void testReturn0() {
+        runTest("returnInvoke", poisonPill);
+    }
+
+    @Test
+    public void testReturn1() {
+        runTest("returnInstanceof", poisonPill);
+    }
+
+    @Test
+    public void testReturn2() {
+        runTest("returnCheckcast", poisonPill);
+    }
+
+    private static class PoisonLoader extends ExportingClassLoader {
+        public static final String POISON_IMPL_NAME = "org.graalvm.compiler.jtt.except.PoisonPill";
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(POISON_IMPL_NAME)) {
+                ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+
+                cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, POISON_IMPL_NAME.replace('.', '/'), null, Type.getInternalName(Pill.class), null);
+                // constructor
+                MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
+                constructor.visitCode();
+                constructor.visitVarInsn(Opcodes.ALOAD, 0);
+                constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Pill.class), "<init>", "()V", false);
+                constructor.visitInsn(Opcodes.RETURN);
+                constructor.visitMaxs(0, 0);
+                constructor.visitEnd();
+
+                MethodVisitor setList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setField", "()V", null, null);
+                setList.visitCode();
+                setList.visitVarInsn(Opcodes.ALOAD, 0);
+                setList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class));
+                setList.visitInsn(Opcodes.DUP);
+                setList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false);
+                setList.visitFieldInsn(Opcodes.PUTFIELD, Type.getInternalName(Pill.class), "field", Type.getDescriptor(TestInterface.class));
+                setList.visitInsn(Opcodes.RETURN);
+                setList.visitMaxs(0, 0);
+                setList.visitEnd();
+
+                MethodVisitor setStaticList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setStaticField", "()V", null, null);
+                setStaticList.visitCode();
+                setStaticList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class));
+                setStaticList.visitInsn(Opcodes.DUP);
+                setStaticList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false);
+                setStaticList.visitFieldInsn(Opcodes.PUTSTATIC, Type.getInternalName(Pill.class), "staticField", Type.getDescriptor(TestInterface.class));
+                setStaticList.visitInsn(Opcodes.RETURN);
+                setStaticList.visitMaxs(0, 0);
+                setStaticList.visitEnd();
+
+                MethodVisitor callMe = cw.visitMethod(Opcodes.ACC_PUBLIC, "callMe", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(CallBack.class)), null, null);
+                callMe.visitCode();
+                callMe.visitVarInsn(Opcodes.ALOAD, 1);
+                callMe.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class));
+                callMe.visitInsn(Opcodes.DUP);
+                callMe.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false);
+                callMe.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(CallBack.class), "callBack", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(TestInterface.class)), true);
+                callMe.visitInsn(Opcodes.IRETURN);
+                callMe.visitMaxs(0, 0);
+                callMe.visitEnd();
+
+                MethodVisitor getList = cw.visitMethod(Opcodes.ACC_PUBLIC, "get", Type.getMethodDescriptor(Type.getType(TestInterface.class)), null, null);
+                getList.visitCode();
+                getList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class));
+                getList.visitInsn(Opcodes.DUP);
+                getList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false);
+                getList.visitInsn(Opcodes.ARETURN);
+                getList.visitMaxs(0, 0);
+                getList.visitEnd();
+
+                cw.visitEnd();
+
+                byte[] bytes = cw.toByteArray();
+                return defineClass(name, bytes, 0, bytes.length);
+            }
+            return super.findClass(name);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate01.java
new file mode 100644
index 0000000..319df72
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate01.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_allocate01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += i;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java
new file mode 100644
index 0000000..da16974
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_allocate02 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            final Integer j = new Integer(i);
+            sum += j;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate03.java
new file mode 100644
index 0000000..1591abd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate03.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_allocate03 extends JTTTest {
+
+    public static int test(int count) {
+        @SuppressWarnings("unused")
+        final int sum = 0;
+        String text = "";
+        for (int i = 0; i < count; i++) {
+            text += '.';
+        }
+        return text.length();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate04.java
new file mode 100644
index 0000000..936e747
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate04.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_allocate04 extends JTTTest {
+
+    public static int test(int count) {
+        int[] a = new int[count];
+
+        for (int i = 0; i < a.length; i++) {
+            a[i] = i;
+        }
+
+        int i = 0;
+        int iwrap = count - 1;
+        int sum = 0;
+
+        while (i < count) {
+            sum += (a[i] + a[iwrap]) / 2;
+            iwrap = i;
+            i++;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array01.java
new file mode 100644
index 0000000..83db2f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array01.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_array01 extends JTTTest {
+
+    public static int[] array = new int[40];
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            array[i] = i;
+            sum += array[i];
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array02.java
new file mode 100644
index 0000000..ac7c073
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array02.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_array02 extends JTTTest {
+
+    public static byte[] b = new byte[40];
+    public static char[] c = new char[40];
+    public static short[] s = new short[40];
+    public static int[] iArray = new int[40];
+    public static long[] l = new long[40];
+    public static float[] f = new float[40];
+    public static double[] d = new double[40];
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int x = 0; x < count; x++) {
+            b[x] = (byte) x;
+            c[x] = (char) x;
+            s[x] = (short) x;
+            iArray[x] = x;
+            l[x] = x;
+            f[x] = x;
+            d[x] = x;
+            sum += b[x] + c[x] + s[x] + iArray[x] + l[x] + f[x] + d[x];
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array03.java
new file mode 100644
index 0000000..397c48a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array03.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_array03 extends JTTTest {
+
+    public static byte[] b = new byte[40];
+    public static char[] c = new char[40];
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += b.length + c.length;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array04.java
new file mode 100644
index 0000000..5c6888c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_array04.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_array04 extends JTTTest {
+
+    public static byte[] b = new byte[40];
+    public static char[] c = new char[40];
+
+    public static int test(int count) {
+        int sum = 0;
+
+        for (int i = 0; i < b.length; i++) {
+            b[i] = (byte) i;
+            c[i] = (char) i;
+        }
+
+        for (int j = 0; j < 10; j++) {
+            try {
+                for (int i = 0; i < count; i++) {
+                    sum += b[i] + c[i];
+                }
+            } catch (IndexOutOfBoundsException e) {
+                sum += j;
+            }
+        }
+
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control01.java
new file mode 100644
index 0000000..60c9af3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control01.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_control01 extends JTTTest {
+
+    public static int test(int count) {
+        int i1 = 1;
+        int i2 = 2;
+        int i3 = 3;
+        int i4 = 4;
+
+        for (int i = 0; i < count; i++) {
+            i1 = i2;
+            i2 = i3;
+            i3 = i4;
+            i4 = i1;
+
+            i1 = i2;
+            i2 = i3;
+            i3 = i4;
+            i4 = i1;
+
+            i1 = i2;
+            i2 = i3;
+            i3 = i4;
+            i4 = i1;
+
+            i1 = i2;
+            i2 = i3;
+            i3 = i4;
+            i4 = i1;
+        }
+
+        return i1 + i2 * 10 + i3 * 100 + i4 * 1000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control02.java
new file mode 100644
index 0000000..545cfec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_control02.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_control02 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            switch (i) {
+                case 30:
+                    sum += 30;
+                    break;
+                case 31:
+                    sum += 31;
+                    break;
+                case 32:
+                    sum += 32;
+                    break;
+                case 33:
+                    sum += 33;
+                    break;
+                case 34:
+                    sum += 34;
+                    break;
+                case 35:
+                    sum += 35;
+                    break;
+                case 36:
+                    sum += 36;
+                    break;
+                case 37:
+                    sum += 37;
+                    break;
+                case 38:
+                    sum += 38;
+                    break;
+                case 39:
+                    sum += 39;
+                    break;
+                case 40:
+                    sum += 40;
+                    break;
+                case 41:
+                    sum += 41;
+                    break;
+                case 42:
+                    sum += 42;
+                    break;
+                default:
+                    sum += 1;
+                    break;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 60);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_convert01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_convert01.java
new file mode 100644
index 0000000..5b4c548
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_convert01.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_convert01 extends JTTTest {
+
+    public static int test(int count) {
+        double sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum = (int) sum + i;
+        }
+        return (int) sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_count.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_count.java
new file mode 100644
index 0000000..6a601bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_count.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Runs: 10 = 55; 20 = 210; 30 = 465; 40 = 820;
+ */
+@SuppressWarnings("unused")
+public class HP_count extends JTTTest {
+
+    public static int test(int count) {
+        float unusedFloat = 0;
+        double dub = 0;
+        int sum = 0;
+        double unusedDouble = 0;
+        for (int i = 0; i <= count; i++) {
+            if (i > 20) {
+                sum += i;
+            } else {
+                sum += i;
+            }
+            dub += sum;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_dead01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_dead01.java
new file mode 100644
index 0000000..95007fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_dead01.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_dead01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i <= count; i++) {
+            int a = i + i;
+            int b = i / 2 * i - 10;
+            @SuppressWarnings("unused")
+            int c = a + b;
+            int d = a;
+            sum += d;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 20);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 30);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_demo01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_demo01.java
new file mode 100644
index 0000000..936de3a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_demo01.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_demo01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+
+        for (int i = 0; i < count; i++) {
+            int[] ia = new int[count];
+            long[] la = new long[count];
+            float[] fa = new float[count];
+            double[] da = new double[count];
+            sum += ia[i] = (int) (la[i] = (long) (fa[i] = (float) (da[i] = i)));
+        }
+
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field01.java
new file mode 100644
index 0000000..5fabb06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field01.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_field01 extends JTTTest {
+
+    public static int a;
+    public static int b;
+    public static int c;
+
+    public static int test(int count) {
+        for (int i = 0; i <= count; i++) {
+            if (i > 5) {
+                a += i;
+            } else if (i > 7) {
+                b += i;
+            } else {
+                c += i;
+            }
+        }
+        return a + b + c;
+    }
+
+    @Override
+    public void before(ResolvedJavaMethod m) {
+        a = 0;
+        b = 0;
+        c = 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field02.java
new file mode 100644
index 0000000..381cd0d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field02.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Runs: 10 = 55; 20 = 210; 30 = 465; 40 = 820;
+ */
+public class HP_field02 extends JTTTest {
+
+    private static class TestClass {
+        public int a;
+        public int b;
+        public int c;
+
+        public int run(int count) {
+            for (int i = 0; i <= count; i++) {
+                if (i > 5) {
+                    a += i;
+                } else if (i > 7) {
+                    b += i;
+                } else {
+                    c += i;
+                }
+            }
+            return a + b + c;
+        }
+    }
+
+    public static int test(int count) {
+        return new TestClass().run(count);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field03.java
new file mode 100644
index 0000000..31cc990
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field03.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_field03 extends JTTTest {
+
+    public static byte b;
+    public static char c;
+    public static short s;
+    public static int i;
+    public static long l;
+    public static float f;
+    public static double d;
+
+    public static int test(int count) {
+        for (int x = 0; x <= count; x++) {
+            b += x;
+            c += x;
+            s += x;
+            i += x;
+            l += x;
+            f += x;
+            d += x;
+        }
+        return (int) (b + c + s + i + l + f + d);
+    }
+
+    @Override
+    public void before(ResolvedJavaMethod m) {
+        b = 0;
+        c = 0;
+        s = 0;
+        i = 0;
+        l = 0L;
+        f = 0.0F;
+        d = 0.0D;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field04.java
new file mode 100644
index 0000000..8cafb80
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_field04.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_field04 extends JTTTest {
+
+    private static class TestClass {
+        public byte b;
+        public char c;
+        public short s;
+        public int i;
+        public long l;
+        public float f;
+        public double d;
+
+        public int run(int count) {
+            for (int x = 0; x <= count; x++) {
+                b += x;
+                c += x;
+                s += x;
+                i += x;
+                l += x;
+                f += x;
+                d += x;
+            }
+            return (int) (b + c + s + i + l + f + d);
+        }
+    }
+
+    public static int test(int count) {
+        return new TestClass().run(count);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_idea.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_idea.java
new file mode 100644
index 0000000..dc81abf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_idea.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+
+package org.graalvm.compiler.jtt.hotpath;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class HP_idea extends JTTTest {
+
+    public boolean test() {
+        buildTestData();
+        Do();
+        return verify();
+    }
+
+    // Declare class data. Byte buffer plain1 holds the original
+    // data for encryption, crypt1 holds the encrypted data, and
+    // plain2 holds the decrypted data, which should match plain1
+    // byte for byte.
+
+    int array_rows;
+
+    byte[] plain1; // Buffer for plaintext data.
+    byte[] crypt1; // Buffer for encrypted data.
+    byte[] plain2; // Buffer for decrypted data.
+
+    short[] userkey; // Key for encryption/decryption.
+    int[] Z; // Encryption subkey (userkey derived).
+    int[] DK; // Decryption subkey (userkey derived).
+
+    void Do() {
+        cipher_idea(plain1, crypt1, Z); // Encrypt plain1.
+        cipher_idea(crypt1, plain2, DK); // Decrypt.
+    }
+
+    /*
+     * buildTestData
+     *
+     * Builds the data used for the test -- each time the test is run.
+     */
+
+    void buildTestData() {
+        // Create three byte arrays that will be used (and reused) for
+        // encryption/decryption operations.
+
+        plain1 = new byte[array_rows];
+        crypt1 = new byte[array_rows];
+        plain2 = new byte[array_rows];
+
+        Random rndnum = new Random(136506717L); // Create random number generator.
+
+        // Allocate three arrays to hold keys: userkey is the 128-bit key.
+        // Z is the set of 16-bit encryption subkeys derived from userkey,
+        // while DK is the set of 16-bit decryption subkeys also derived
+        // from userkey. NOTE: The 16-bit values are stored here in
+        // 32-bit int arrays so that the values may be used in calculations
+        // as if they are unsigned. Each 64-bit block of plaintext goes
+        // through eight processing rounds involving six of the subkeys
+        // then a final output transform with four of the keys; (8 * 6)
+        // + 4 = 52 subkeys.
+
+        userkey = new short[8]; // User key has 8 16-bit shorts.
+        Z = new int[52]; // Encryption subkey (user key derived).
+        DK = new int[52]; // Decryption subkey (user key derived).
+
+        // Generate user key randomly; eight 16-bit values in an array.
+
+        for (int i = 0; i < 8; i++) {
+            // Again, the random number function returns int. Converting
+            // to a short type preserves the bit pattern in the lower 16
+            // bits of the int and discards the rest.
+
+            userkey[i] = (short) rndnum.nextInt();
+        }
+
+        // Compute encryption and decryption subkeys.
+
+        calcEncryptKey();
+        calcDecryptKey();
+
+        // Fill plain1 with "text."
+        for (int i = 0; i < array_rows; i++) {
+            plain1[i] = (byte) i;
+
+            // Converting to a byte
+            // type preserves the bit pattern in the lower 8 bits of the
+            // int and discards the rest.
+        }
+    }
+
+    /*
+     * calcEncryptKey
+     *
+     * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array.
+     * The routing corrects an error in the source code in the Schnier book. Basically, the sense of
+     * the 7- and 9-bit shifts are reversed. It still works reversed, but would encrypted code would
+     * not decrypt with someone else's IDEA code.
+     */
+
+    private void calcEncryptKey() {
+        int j; // Utility variable.
+
+        for (int i = 0; i < 52; i++) {
+            // Zero out the 52-int Z array.
+            Z[i] = 0;
+        }
+
+        for (int i = 0; i < 8; i++) // First 8 subkeys are userkey itself.
+        {
+            Z[i] = userkey[i] & 0xffff; // Convert "unsigned"
+            // short to int.
+        }
+
+        // Each set of 8 subkeys thereafter is derived from left rotating
+        // the whole 128-bit key 25 bits to left (once between each set of
+        // eight keys and then before the last four). Instead of actually
+        // rotating the whole key, this routine just grabs the 16 bits
+        // that are 25 bits to the right of the corresponding subkey
+        // eight positions below the current subkey. That 16-bit extent
+        // straddles two array members, so bits are shifted left in one
+        // member and right (with zero fill) in the other. For the last
+        // two subkeys in any group of eight, those 16 bits start to
+        // wrap around to the first two members of the previous eight.
+
+        for (int i = 8; i < 52; i++) {
+            j = i % 8;
+            if (j < 6) {
+                Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 6] << 7)) // Shift and combine.
+                                & 0xFFFF; // Just 16 bits.
+                continue; // Next iteration.
+            }
+
+            if (j == 6) // Wrap to beginning for second chunk.
+            {
+                Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF;
+                continue;
+            }
+
+            // j == 7 so wrap to beginning for both chunks.
+
+            Z[i] = ((Z[i - 15] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF;
+        }
+    }
+
+    /*
+     * calcDecryptKey
+     *
+     * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a
+     * 32-bit int array holding 16-bit values as unsigned.
+     */
+
+    private void calcDecryptKey() {
+        int j, k; // Index counters.
+        int t1, t2, t3; // Temps to hold decrypt subkeys.
+
+        t1 = inv(Z[0]); // Multiplicative inverse (mod x10001).
+        t2 = -Z[1] & 0xffff; // Additive inverse, 2nd encrypt subkey.
+        t3 = -Z[2] & 0xffff; // Additive inverse, 3rd encrypt subkey.
+
+        DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001).
+        DK[50] = t3;
+        DK[49] = t2;
+        DK[48] = t1;
+
+        j = 47; // Indices into temp and encrypt arrays.
+        k = 4;
+        for (int i = 0; i < 7; i++) {
+            t1 = Z[k++];
+            DK[j--] = Z[k++];
+            DK[j--] = t1;
+            t1 = inv(Z[k++]);
+            t2 = -Z[k++] & 0xffff;
+            t3 = -Z[k++] & 0xffff;
+            DK[j--] = inv(Z[k++]);
+            DK[j--] = t2;
+            DK[j--] = t3;
+            DK[j--] = t1;
+        }
+
+        t1 = Z[k++];
+        DK[j--] = Z[k++];
+        DK[j--] = t1;
+        t1 = inv(Z[k++]);
+        t2 = -Z[k++] & 0xffff;
+        t3 = -Z[k++] & 0xffff;
+        DK[j--] = inv(Z[k++]);
+        DK[j--] = t3;
+        DK[j--] = t2;
+        DK[j--] = t1;
+    }
+
+    /*
+     * cipher_idea
+     *
+     * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time,
+     * breaking the block into four 16-bit unsigned subblocks. It goes through eight rounds of
+     * processing using 6 new subkeys each time, plus four for last step. The source text is in
+     * array text1, the destination text goes into array text2 The routine represents 16-bit
+     * subblocks and subkeys as type int so that they can be treated more easily as unsigned.
+     * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16
+     * bits.
+     */
+
+    @SuppressWarnings("static-method")
+    private void cipher_idea(byte[] text1, byte[] text2, int[] key) {
+
+        int i1 = 0; // Index into first text array.
+        int i2 = 0; // Index into second text array.
+        int ik; // Index into key array.
+        int x1, x2, x3, x4, t1, t2; // Four "16-bit" blocks, two temps.
+        int r; // Eight rounds of processing.
+
+        for (int i = 0; i < text1.length; i += 8) {
+
+            ik = 0; // Restart key index.
+            r = 8; // Eight rounds of processing.
+
+            // Load eight plain1 bytes as four 16-bit "unsigned" integers.
+            // Masking with 0xff prevents sign extension with cast to int.
+
+            x1 = text1[i1++] & 0xff; // Build 16-bit x1 from 2 bytes,
+            x1 |= (text1[i1++] & 0xff) << 8; // assuming low-order byte first.
+            x2 = text1[i1++] & 0xff;
+            x2 |= (text1[i1++] & 0xff) << 8;
+            x3 = text1[i1++] & 0xff;
+            x3 |= (text1[i1++] & 0xff) << 8;
+            x4 = text1[i1++] & 0xff;
+            x4 |= (text1[i1++] & 0xff) << 8;
+
+            do {
+                // 1) Multiply (modulo 0x10001), 1st text sub-block
+                // with 1st key sub-block.
+
+                x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
+
+                // 2) Add (modulo 0x10000), 2nd text sub-block
+                // with 2nd key sub-block.
+
+                x2 = x2 + key[ik++] & 0xffff;
+
+                // 3) Add (modulo 0x10000), 3rd text sub-block
+                // with 3rd key sub-block.
+
+                x3 = x3 + key[ik++] & 0xffff;
+
+                // 4) Multiply (modulo 0x10001), 4th text sub-block
+                // with 4th key sub-block.
+
+                x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
+
+                // 5) XOR results from steps 1 and 3.
+
+                t2 = x1 ^ x3;
+
+                // 6) XOR results from steps 2 and 4.
+                // Included in step 8.
+
+                // 7) Multiply (modulo 0x10001), result of step 5
+                // with 5th key sub-block.
+
+                t2 = (int) ((long) t2 * key[ik++] % 0x10001L & 0xffff);
+
+                // 8) Add (modulo 0x10000), results of steps 6 and 7.
+
+                t1 = t2 + (x2 ^ x4) & 0xffff;
+
+                // 9) Multiply (modulo 0x10001), result of step 8
+                // with 6th key sub-block.
+
+                t1 = (int) ((long) t1 * key[ik++] % 0x10001L & 0xffff);
+
+                // 10) Add (modulo 0x10000), results of steps 7 and 9.
+
+                t2 = t1 + t2 & 0xffff;
+
+                // 11) XOR results from steps 1 and 9.
+
+                x1 ^= t1;
+
+                // 14) XOR results from steps 4 and 10. (Out of order).
+
+                x4 ^= t2;
+
+                // 13) XOR results from steps 2 and 10. (Out of order).
+
+                t2 ^= x2;
+
+                // 12) XOR results from steps 3 and 9. (Out of order).
+
+                x2 = x3 ^ t1;
+
+                x3 = t2; // Results of x2 and x3 now swapped.
+
+            } while (--r != 0); // Repeats seven more rounds.
+
+            // Final output transform (4 steps).
+
+            // 1) Multiply (modulo 0x10001), 1st text-block
+            // with 1st key sub-block.
+
+            x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
+
+            // 2) Add (modulo 0x10000), 2nd text sub-block
+            // with 2nd key sub-block. It says x3, but that is to undo swap
+            // of subblocks 2 and 3 in 8th processing round.
+
+            x3 = x3 + key[ik++] & 0xffff;
+
+            // 3) Add (modulo 0x10000), 3rd text sub-block
+            // with 3rd key sub-block. It says x2, but that is to undo swap
+            // of subblocks 2 and 3 in 8th processing round.
+
+            x2 = x2 + key[ik++] & 0xffff;
+
+            // 4) Multiply (modulo 0x10001), 4th text-block
+            // with 4th key sub-block.
+
+            x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
+
+            // Repackage from 16-bit sub-blocks to 8-bit byte array text2.
+
+            text2[i2++] = (byte) x1;
+            text2[i2++] = (byte) (x1 >>> 8);
+            text2[i2++] = (byte) x3; // x3 and x2 are switched
+            text2[i2++] = (byte) (x3 >>> 8); // only in name.
+            text2[i2++] = (byte) x2;
+            text2[i2++] = (byte) (x2 >>> 8);
+            text2[i2++] = (byte) x4;
+            text2[i2++] = (byte) (x4 >>> 8);
+
+        } // End for loop.
+
+    } // End routine.
+
+    /*
+     * mul
+     *
+     * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that
+     * untaken branches are cheaper than taken branches, and that the compiler doesn't schedule
+     * branches. Java: Must work with 32-bit int and one 64-bit long to keep 16-bit values and their
+     * products "unsigned." The routine assumes that both a and b could fit in 16 bits even though
+     * they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit. Also,
+     * because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to
+     * zero whenever the result would zero, be 2**16. And if one of the multiplicands is 0, the
+     * result is not zero, but (2**16) + 1 minus the other multiplicand (sort of an additive inverse
+     * mod 0x10001).
+     *
+     * NOTE: The java conversion of this routine works correctly, but is half the speed of using
+     * Java's modulus division function (%) on the multiplication with a 16-bit masking of the
+     * result--running in the Symantec Caje IDE. So it's not called for now; the test uses Java %
+     * instead.
+     */
+
+    /*
+     * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch
+     * 16-bit multiply // without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b
+     * = (int) p & 0xFFFF; // Lower 16 bits. a = (int) p >>> 16; // Upper 16 bits.
+     *
+     * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0,
+     * then same as // 0x10001 - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); //
+     * same as 0x10001 - b. }
+     */
+
+    /*
+     * inv
+     *
+     * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest
+     * common divisor) algorithm. It is unrolled twice to avoid swapping the meaning of the
+     * registers. And some subtracts are changed to adds. Java: Though it uses signed 32-bit ints,
+     * the interpretation of the bits within is strictly unsigned 16-bit.
+     */
+
+    public int inv(int x) {
+        int x2 = x;
+        int t0, t1;
+        int q, y;
+
+        if (x2 <= 1) {
+            return (x2); // 0 and 1 are self-inverse.
+        }
+
+        t1 = 0x10001 / x2; // (2**16+1)/x; x is >= 2, so fits 16 bits.
+        y = 0x10001 % x2;
+        if (y == 1) {
+            return ((1 - t1) & 0xFFFF);
+        }
+
+        t0 = 1;
+        do {
+            q = x2 / y;
+            x2 = x2 % y;
+            t0 += q * t1;
+            if (x2 == 1) {
+                return (t0);
+            }
+            q = y / x2;
+            y = y % x2;
+            t1 += q * t0;
+        } while (y != 1);
+
+        return ((1 - t1) & 0xFFFF);
+    }
+
+    boolean verify() {
+        boolean error;
+        for (int i = 0; i < array_rows; i++) {
+            error = (plain1[i] != plain2[i]);
+            if (error) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * freeTestData
+     *
+     * Nulls arrays and forces garbage collection to free up memory.
+     */
+
+    void freeTestData() {
+        plain1 = null;
+        crypt1 = null;
+        plain2 = null;
+        userkey = null;
+        Z = null;
+        DK = null;
+    }
+
+    public HP_idea() {
+        array_rows = 3000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+    @Test
+    public void runInv() {
+        runTest("inv", 724);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline01.java
new file mode 100644
index 0000000..a18d464
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline01.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_inline01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += foo(i);
+        }
+        return sum;
+    }
+
+    public static int foo(int x) {
+        if (x < 15) {
+            return bar(x);
+        }
+        return bar(x + 1);
+    }
+
+    public static int bar(int x) {
+        return x + 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline02.java
new file mode 100644
index 0000000..a358d21
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_inline02.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_inline02 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += foo(i, sum);
+        }
+        return sum;
+    }
+
+    public static int foo(int x, int y) {
+        if (x < 18) {
+            return bar(x, x - y);
+        }
+        return bar(x, x + y);
+    }
+
+    public static int bar(int x, int y) {
+        if (x < 15) {
+            return car(x, x + y);
+        }
+        return x - 1;
+    }
+
+    @SuppressWarnings("unused")
+    public static int car(int x, int y) {
+        if (x < 13) {
+            return x + 1;
+        }
+        return x - 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_invoke01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_invoke01.java
new file mode 100644
index 0000000..6b4d193
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_invoke01.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_invoke01 extends JTTTest {
+
+    private static int sum;
+
+    public static int test(int count) {
+        sum = 0;
+        final Instruction[] instructions = new Instruction[]{new Instruction.Add(), new Instruction.Sub(), new Instruction.Mul(), new Instruction.Div()};
+        final Visitor v = new Visitor();
+        for (int i = 0; i < count; i++) {
+            instructions[i % 4].accept(v);
+        }
+        return sum;
+    }
+
+    public static abstract class Instruction {
+
+        public abstract void accept(Visitor v);
+
+        public static abstract class Binary extends Instruction {
+
+        }
+
+        public static class Add extends Binary {
+
+            @Override
+            public void accept(Visitor v) {
+                v.visit(this);
+            }
+        }
+
+        public static class Sub extends Binary {
+
+            @Override
+            public void accept(Visitor v) {
+                v.visit(this);
+            }
+        }
+
+        public static class Mul extends Binary {
+
+            @Override
+            public void accept(Visitor v) {
+                v.visit(this);
+            }
+        }
+
+        public static class Div extends Binary {
+
+            @Override
+            public void accept(Visitor v) {
+                v.visit(this);
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static class Visitor {
+
+        public void visit(Instruction.Add i) {
+            sum += 7;
+        }
+
+        public void visit(Instruction.Sub i) {
+            sum += 194127;
+        }
+
+        public void visit(Instruction.Mul i) {
+            sum += 18991;
+        }
+
+        public void visit(Instruction.Div i) {
+            sum += 91823;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 80);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_life.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_life.java
new file mode 100644
index 0000000..d3df439
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_life.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_life extends JTTTest {
+
+    public static int test(int generations) {
+        reset();
+        for (int i = 0; i < generations; ++i) {
+            step();
+        }
+        int sum = 0;
+        for (int row = 0; row < rows; ++row) {
+            for (int col = 0; col < cols; ++col) {
+                boolean value = cell(row, col);
+                sum += (row * 15223242 + col * 21623234) ^ ((value ? 1 : 0) * 15323142);
+            }
+        }
+        return sum;
+    }
+
+    private static final int rows = 20;
+    private static final int cols = 20;
+    private static boolean cells[] = new boolean[rows * cols];
+
+    private static boolean cell(int row, int col) {
+        return ((row >= 0) && (row < rows) && (col >= 0) && (col < cols) && cells[row * cols + col]);
+    }
+
+    private static boolean step() {
+        boolean next[] = new boolean[rows * cols];
+        boolean changed = false;
+        for (int row = rows - 1; row >= 0; --row) {
+            int row_offset = row * cols;
+            for (int col = cols - 1; col >= 0; --col) {
+                int count = 0;
+                if (cell(row - 1, col - 1)) {
+                    count++;
+                }
+                if (cell(row - 1, col)) {
+                    count++;
+                }
+                if (cell(row - 1, col + 1)) {
+                    count++;
+                }
+                if (cell(row, col - 1)) {
+                    count++;
+                }
+                if (cell(row, col + 1)) {
+                    count++;
+                }
+                if (cell(row + 1, col - 1)) {
+                    count++;
+                }
+                if (cell(row + 1, col)) {
+                    count++;
+                }
+                if (cell(row + 1, col + 1)) {
+                    count++;
+                }
+                boolean old_state = cells[row_offset + col];
+                boolean new_state = (!old_state && count == 3) || (old_state && (count == 2 || count == 3));
+                if (!changed && new_state != old_state) {
+                    changed = true;
+                }
+                next[row_offset + col] = new_state;
+            }
+        }
+        cells = next;
+        return changed;
+    }
+
+    private static void reset() {
+        Random random = new Random(0);
+        boolean cells2[] = HP_life.cells;
+        for (int offset = 0; offset < cells2.length; ++offset) {
+            cells2[offset] = random.nextDouble() > 0.5;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest01.java
new file mode 100644
index 0000000..0db5b3f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest01.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_nest01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += i;
+            for (int j = 0; j < count; j++) {
+                sum += j;
+            }
+            for (int j = 0; j < count; j++) {
+                sum += j;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 15);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest02.java
new file mode 100644
index 0000000..ef94236
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_nest02.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_nest02 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            sum += i;
+            sum = foo(count, sum);
+            sum = foo(count, sum);
+        }
+        return sum;
+    }
+
+    private static int foo(int count, int s) {
+        int sum = s;
+        for (int j = 0; j < count; j++) {
+            sum += j;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 15);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope01.java
new file mode 100644
index 0000000..4aeddda
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope01.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_scope01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+
+        for (int k = 0; k < count; k++) {
+            {
+                int i = 1;
+                sum += i;
+            }
+            {
+                float f = 3;
+                sum += f;
+            }
+            {
+                long l = 7;
+                sum += l;
+            }
+            {
+                double d = 11;
+                sum += d;
+            }
+        }
+
+        for (int k = 0; k < count; k++) {
+            if (k < 20) {
+                int i = 1;
+                sum += i;
+            } else {
+                float f = 3;
+                sum += f;
+            }
+        }
+
+        for (int k = 0; k < count; k++) {
+            int i = 3;
+            for (int j = 0; j < count; j++) {
+                float f = 7;
+                sum += i + f;
+            }
+        }
+
+        for (int k = 0; k < count; k++) {
+            for (int j = 0; j < count; j++) {
+                float f = 7;
+                sum += j + f;
+            }
+            int i = 3;
+            sum += i;
+        }
+
+        return sum;
+    }
+
+    @Ignore
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope02.java
new file mode 100644
index 0000000..456fa29
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_scope02.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_scope02 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        // Although sum is not explicitly read in the tree below it is implicitly read
+        // by the guard bail-out.
+        for (int i = 0; i < count; i++) {
+            if (i > 20) {
+                break; // We need to write back either the original value of sum, or the previous
+                       // iteration's value.
+            }
+            sum = i;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 22);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java
new file mode 100644
index 0000000..b3d341d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_series extends JTTTest {
+
+    public static double test(int count) {
+        final int arrayRows = count;
+        final double[][] testArray = new double[2][arrayRows];
+        double omega; // Fundamental frequency.
+        testArray[0][0] = TrapezoidIntegrate(0.0, // Lower bound.
+                        2.0, // Upper bound.
+                        1000, // # of steps.
+                        0.0, // No omega*n needed.
+                        0) / 2.0; // 0 = term A[0].
+        omega = 3.1415926535897932;
+        for (int i = 1; i < arrayRows; i++) {
+            testArray[0][i] = TrapezoidIntegrate(0.0, 2.0, 1000, omega * i, 1); // 1 = cosine
+            // term.
+            testArray[1][i] = TrapezoidIntegrate(0.0, 2.0, 1000, omega * i, 2); // 2 = sine
+            // term.
+        }
+        final double ref[][] = {{2.8729524964837996, 0.0}, {1.1161046676147888, -1.8819691893398025}, {0.34429060398168704, -1.1645642623320958}, {0.15238898702519288, -0.8143461113044298}};
+        double error = 0.0;
+        double sum = 0.0;
+        for (int i = 0; i < 4; i++) {
+            for (int j = 0; j < 2; j++) {
+                error += Math.abs(testArray[j][i] - ref[i][j]);
+                sum += testArray[j][i];
+            }
+        }
+        return sum + error;
+    }
+
+    private static double TrapezoidIntegrate(double x0, // Lower bound.
+                    double x1, // Upper bound.
+                    int ns, // # of steps.
+                    double omegan, // omega * n.
+                    int select) // Term type.
+    {
+        int nsteps = ns;
+        double x; // Independent variable.
+        double dx; // Step size.
+        double rvalue; // Return value.
+
+        x = x0;
+        dx = (x1 - x0) / nsteps;
+        rvalue = thefunction(x0, omegan, select) / 2.0;
+        if (nsteps != 1) {
+            --nsteps; // Already done 1 step.
+            while (--nsteps > 0) {
+                x += dx;
+                rvalue += thefunction(x, omegan, select);
+            }
+        }
+        rvalue = (rvalue + thefunction(x1, omegan, select) / 2.0) * dx;
+        return (rvalue);
+    }
+
+    private static double thefunction(double x, // Independent variable.
+                    double omegan, // Omega * term.
+                    int select) // Choose type.
+    {
+        switch (select) {
+            case 0:
+                return (Math.pow(x + 1.0, x));
+            case 1:
+                return (Math.pow(x + 1.0, x) * Math.cos(omegan * x));
+            case 2:
+                return (Math.pow(x + 1.0, x) * Math.sin(omegan * x));
+        }
+        return (0.0);
+    }
+
+    /*
+     * This test is sensible to the implementation of Math.pow, cos and sin. Since for these
+     * functions, the specs says "The computed result must be within 1 ulp of the exact result",
+     * different implementation may return different results. The 11 ulp delta allowed for test(100)
+     * tries to account for that but is not guaranteed to work forever.
+     */
+    @Ignore("failure-prone because of the variabiliy of pow/cos/sin")
+    @Test
+    public void run0() throws Throwable {
+        double expected = 0.6248571921291398d;
+        runTestWithDelta(11 * Math.ulp(expected), "test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_trees01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_trees01.java
new file mode 100644
index 0000000..e94b7e9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_trees01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.hotpath;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class HP_trees01 extends JTTTest {
+
+    public static int test(int count) {
+        int sum = 0;
+        for (int i = 0; i < count; i++) {
+            if (i < 100) {
+                sum += 1;
+            } else if (i < 200) {
+                sum += 3;
+            } else if (i < 300) {
+                sum += 5;
+            } else if (i < 400) {
+                sum += 7;
+            } else if (i < 500) {
+                sum += 11;
+            }
+
+            if (i % 5 == 0) {
+                sum += 1;
+            } else if (i % 5 == 1) {
+                sum += 3;
+            } else if (i % 5 == 2) {
+                sum += 5;
+            } else if (i % 5 == 3) {
+                sum += 7;
+            } else if (i % 5 == 4) {
+                sum += 11;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6186134.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6186134.java
new file mode 100644
index 0000000..df29668
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6186134.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.util.ArraySet;
+import org.graalvm.compiler.jtt.JTTTest;
+
+// @formatter:off
+public class Test6186134 extends JTTTest {
+
+    public static class TestClass {
+
+        int num = 0;
+
+        public TestClass(int n) {
+            num = n;
+        }
+
+        public boolean more() {
+            return num-- > 0;
+        }
+
+        public ArrayList<?> test1() {
+            ArrayList<Object> res = new ArrayList<>();
+            int maxResults = Integer.MAX_VALUE;
+            int n = 0;
+            boolean more = more();
+            while ((n++ < maxResults) && more) {
+                res.add(new Object());
+                more = more();
+            }
+            return res;
+        }
+
+    }
+
+    public static int test(int n) {
+        for (int i = 0; i < n; i++) {
+            TestClass t = new TestClass(10);
+            int size = t.test1().size();
+            if (size != 10) {
+                return 97;
+            }
+        }
+        return 0;
+    }
+
+    @Before
+    public void setUp() {
+        /* Ensure that ArrayList is _not_ a leaf class (otherwise code installation may fail due to a failed leaf type dependency). */
+        UNSAFE.ensureClassInitialized(ArraySet.class);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6196102.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6196102.java
new file mode 100644
index 0000000..27de633
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6196102.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * @bug 6196102
+ * @summary Integer seems to be greater than {@link Integer#MAX_VALUE}.
+ *
+ * @run main Test6196102
+ */
+public class Test6196102 extends JTTTest {
+
+    public static String test() {
+        int i1 = 0;
+        int i2 = Integer.MAX_VALUE;
+
+        while (i1 >= 0) {
+            i1++;
+            if (i1 > i2) {
+                return "E R R O R: " + i1;
+            }
+        }
+        return "ok";
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6753639.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6753639.java
new file mode 100644
index 0000000..59f59b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6753639.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * @test
+ * @bug 6753639
+ * @summary Strange optimisation in for loop with cyclic integer condition
+ *
+ * @run main/othervm -Xbatch Test6753639
+ */
+// @formatter:off
+public class Test6753639 extends JTTTest {
+
+    public static int test() {
+        int end = Integer.MAX_VALUE;
+        int count = 0;
+        for (int i = Integer.MAX_VALUE - 5; i <= end; i++) {
+            count++;
+            if (count > 100000) {
+                return 95;
+            }
+        }
+        return 97;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java
new file mode 100644
index 0000000..d24c26f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+//@formatter:off
+
+/**
+ * @test
+ * @bug 6823354
+ * @summary These methods can be instrinsified by using bit scan, bit test, and population count instructions.
+ *
+ * @run main/othervm -Xcomp -XX:CompileOnly=Test6823354.lzcomp,Test6823354.tzcomp,.dolzcomp,.dotzcomp Test6823354
+ */
+
+import java.net.URLClassLoader;
+
+// Checkstyle: stop
+public class Test6823354 {
+    // Arrays of corner case values.
+    static final int[]  ia = new int[]  { 0,  1,  -1,  Integer.MIN_VALUE, Integer.MAX_VALUE };
+    static final long[] la = new long[] { 0L, 1L, -1L, Long.MIN_VALUE,    Long.MAX_VALUE    };
+
+    public static void main(String[] args) throws Exception {
+        // Load the classes and the methods.
+        Integer.numberOfLeadingZeros(0);
+        Integer.numberOfTrailingZeros(0);
+        Long.numberOfLeadingZeros(0);
+        Long.numberOfTrailingZeros(0);
+
+        lz();
+        tz();
+    }
+
+    static void lz() throws Exception {
+        // int
+
+        // Test corner cases.
+        for (int i = 0; i < ia.length; i++) {
+            int x = ia[i];
+            check(x, lzcomp(x), lzint(x));
+        }
+
+        // Test all possible return values.
+        for (int i = 0; i < Integer.SIZE; i++) {
+            int x = 1 << i;
+            check(x, lzcomp(x), lzint(x));
+        }
+
+        String classname = Test6823354.class.getName() + "$lzconI";
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < ia.length; i++) {
+            testclass(classname, ia[i]);
+        }
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < Integer.SIZE; i++) {
+            int x = 1 << i;
+            testclass(classname, x);
+        }
+
+
+        // long
+
+        // Test corner cases.
+        for (int i = 0; i < ia.length; i++) {
+            long x = la[i];
+            check(x, lzcomp(x), lzint(x));
+        }
+
+        // Test all possible return values.
+        for (int i = 0; i < Long.SIZE; i++) {
+            long x = 1L << i;
+            check(x, lzcomp(x), lzint(x));
+        }
+
+        classname = Test6823354.class.getName() + "$lzconL";
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < la.length; i++) {
+            testclass(classname, la[i]);
+        }
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < Long.SIZE; i++) {
+            long x = 1L << i;
+            testclass(classname, x);
+        }
+    }
+
+    static void tz() throws Exception {
+        // int
+
+        // Test corner cases.
+        for (int i = 0; i < ia.length; i++) {
+            int x = ia[i];
+            check(x, tzcomp(x), tzint(x));
+        }
+
+        // Test all possible return values.
+        for (int i = 0; i < Integer.SIZE; i++) {
+            int x = 1 << i;
+            check(x, tzcomp(x), tzint(x));
+        }
+
+        String classname = Test6823354.class.getName() + "$tzconI";
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < ia.length; i++) {
+            testclass(classname, ia[i]);
+        }
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < Integer.SIZE; i++) {
+            int x = 1 << i;
+            testclass(classname, x);
+        }
+
+
+        // long
+
+        // Test corner cases.
+        for (int i = 0; i < la.length; i++) {
+            long x = la[i];
+            check(x, tzcomp(x), tzint(x));
+        }
+
+        // Test all possible return values.
+        for (int i = 0; i < Long.SIZE; i++) {
+            long x = 1L << i;
+            check(x, tzcomp(x), tzint(x));
+        }
+
+        classname = Test6823354.class.getName() + "$tzconL";
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < la.length; i++) {
+            testclass(classname, la[i]);
+        }
+
+        // Test Ideal optimizations (constant values).
+        for (int i = 0; i < Long.SIZE; i++) {
+            long x = 1L << i;
+            testclass(classname, x);
+        }
+    }
+
+    static void check(int value, int result, int expected) {
+        if (result != expected)
+            throw new InternalError(value + " failed: " + result + " != " + expected);
+    }
+
+    static void check(long value, long result, long expected) {
+        if (result != expected)
+            throw new InternalError(value + " failed: " + result + " != " + expected);
+    }
+
+    static int lzint( int i)  { return Integer.numberOfLeadingZeros(i); }
+    static int lzcomp(int i)  { return Integer.numberOfLeadingZeros(i); }
+
+    static int lzint( long l) { return Long.numberOfLeadingZeros(l); }
+    static int lzcomp(long l) { return Long.numberOfLeadingZeros(l); }
+
+    static int tzint( int i)  { return Integer.numberOfTrailingZeros(i); }
+    static int tzcomp(int i)  { return Integer.numberOfTrailingZeros(i); }
+
+    static int tzint( long l) { return Long.numberOfTrailingZeros(l); }
+    static int tzcomp(long l) { return Long.numberOfTrailingZeros(l); }
+
+    static void testclass(String classname, int x) throws Exception {
+        System.setProperty("value", "" + x);
+        loadandrunclass(classname);
+    }
+
+    static void testclass(String classname, long x) throws Exception {
+        System.setProperty("value", "" + x);
+        loadandrunclass(classname);
+    }
+
+    static void loadandrunclass(String classname) throws Exception {
+        Class<?> cl = Class.forName(classname);
+        URLClassLoader apploader = (URLClassLoader) cl.getClassLoader();
+        ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent());
+        Class<?> c = loader.loadClass(classname);
+        Runnable r = (Runnable) c.newInstance();
+        r.run();
+    }
+
+    public static class lzconI implements Runnable {
+        static final int VALUE;
+
+        static {
+            int value = 0;
+            try {
+                value = Integer.decode(System.getProperty("value"));
+            } catch (Throwable e) {}
+            VALUE = value;
+        }
+
+        @Override
+        public void run() { check(VALUE, lzint(VALUE), dolzcomp()); }
+        static int dolzcomp() { return lzcomp(VALUE); }
+    }
+
+    public static class lzconL implements Runnable {
+        static final long VALUE;
+
+        static {
+            long value = 0;
+            try {
+                value = Long.decode(System.getProperty("value"));
+            } catch (Throwable e) {}
+            VALUE = value;
+        }
+
+        @Override
+        public void run() { check(VALUE, lzint(VALUE), dolzcomp()); }
+        static int dolzcomp() { return lzcomp(VALUE); }
+    }
+
+    public static class tzconI implements Runnable {
+        static final int VALUE;
+
+        static {
+            int value = 0;
+            try {
+                value = Integer.decode(System.getProperty("value"));
+            } catch (Throwable e) {}
+            VALUE = value;
+        }
+
+        @Override
+        public void run() { check(VALUE, tzint(VALUE), dotzcomp()); }
+        static int dotzcomp() { return tzcomp(VALUE); }
+    }
+
+    public static class tzconL implements Runnable {
+        static final long VALUE;
+
+        static {
+            long value = 0;
+            try {
+                value = Long.decode(System.getProperty("value"));
+            } catch (Throwable e) {}
+            VALUE = value;
+        }
+
+        @Override
+        public void run() { check(VALUE, tzint(VALUE), dotzcomp()); }
+        static int dotzcomp() { return tzcomp(VALUE); }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6850611.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6850611.java
new file mode 100644
index 0000000..a5a6c75
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6850611.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+//@formatter:off
+
+/**
+ * @test
+ * @bug 6850611
+ * @summary int / long arithmetic seems to be broken in 1.6.0_14 HotSpot Server VM (Win XP)
+ *
+ * @run main Test6850611
+ */
+
+public class Test6850611 extends JTTTest {
+
+    public static int test() {
+        // for (int j = 0; j < 5; ++j) {
+        long x = 0;
+        for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; ++i) {
+            x += i;
+        }
+        if (x != -4294967295L) {
+            return 97;
+        }
+        // }
+        return 95;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java
new file mode 100644
index 0000000..2467c77
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Test6959129 extends JTTTest {
+
+    public static long test() {
+        int min = Integer.MAX_VALUE - 30000;
+        int max = Integer.MAX_VALUE;
+        return maxMoves(min, max);
+    }
+
+    /**
+     * Imperative implementation that returns the length hailstone moves for a given number.
+     */
+    public static long hailstoneLengthImp(long n2) {
+        long n = n2;
+        long moves = 0;
+        while (n != 1) {
+            if (n <= 1) {
+                throw new IllegalStateException();
+            }
+            if (isEven(n)) {
+                n = n / 2;
+            } else {
+                n = 3 * n + 1;
+            }
+            ++moves;
+        }
+        return moves;
+    }
+
+    private static boolean isEven(long n) {
+        return n % 2 == 0;
+    }
+
+    /**
+     * Returns the maximum length of the hailstone sequence for numbers between min to max.
+     *
+     * For rec1 - Assume that min is bigger than max.
+     */
+    public static long maxMoves(int min, int max) {
+        long maxmoves = 0;
+        for (int n = min; n <= max; n++) {
+            long moves = hailstoneLengthImp(n);
+            if (moves > maxmoves) {
+                maxmoves = moves;
+            }
+        }
+        return maxmoves;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test7005594.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test7005594.java
new file mode 100644
index 0000000..1c1a05e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test7005594.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.hotspot;
+
+//@formatter:off
+
+/**
+ * @test
+ * @bug 7005594
+ * @summary Array overflow not handled correctly with loop optimzations
+ *
+ * @run shell Test7005594.sh
+ */
+public class Test7005594 {
+
+    private static int test0(byte[] a) {
+        int result = 0;
+        for (int i = 0; i < a.length; i += ((0x7fffffff >> 1) + 1)) {
+            result += a[i];
+        }
+        return result;
+    }
+
+    public static int test() {
+        byte[] a = new byte[(0x7fffffff >> 1) + 2];
+        try {
+            test0(a);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            return 95;
+        }
+        return 97;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/CharacterBits.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/CharacterBits.java
new file mode 100644
index 0000000..087ca63
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/CharacterBits.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class CharacterBits extends JTTTest {
+    @SuppressWarnings("unused") private static char init = Character.reverseBytes((char) 42);
+    private static char original = 0x1708;
+
+    public static char test(char o) {
+        return Character.reverseBytes(o);
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", original);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test", (char) 0x1708L);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test", (char) 0);
+        runTest("test", (char) 1);
+        runTest("test", (char) -1);
+        runTest("test", (char) 0x00ff);
+        runTest("test", (char) 0xff00);
+        runTest("test", (char) 0xffff);
+        runTest("test", (char) 0x3fff);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Class_getName.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Class_getName.java
new file mode 100644
index 0000000..91d7fab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Class_getName.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getName extends JTTTest {
+
+    public static String test(int a) {
+        if (a == 0) {
+            return String.class.getName();
+        }
+        return "";
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/DivideUnsigned.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/DivideUnsigned.java
new file mode 100644
index 0000000..33b6567
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/DivideUnsigned.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class DivideUnsigned extends JTTTest {
+
+    public static int divUInt(int a, int b) {
+        return Integer.divideUnsigned(a, b);
+    }
+
+    public static int remUInt(int a, int b) {
+        return Integer.remainderUnsigned(a, b);
+    }
+
+    public static long divULong(long a, long b) {
+        return Long.divideUnsigned(a, b);
+    }
+
+    public static long remULong(long a, long b) {
+        return Long.remainderUnsigned(a, b);
+    }
+
+    public void testInt(int a, int b) {
+        runTest("divUInt", a, b);
+        runTest("remUInt", a, b);
+    }
+
+    public void testLong(long a, long b) {
+        runTest("divULong", a, b);
+        runTest("remULong", a, b);
+    }
+
+    @Test
+    public void testIntPP() {
+        testInt(5, 2);
+    }
+
+    @Test
+    public void testIntNP() {
+        testInt(-5, 2);
+    }
+
+    @Test
+    public void testIntPN() {
+        testInt(5, -2);
+    }
+
+    @Test
+    public void testIntNN() {
+        testInt(-5, -2);
+    }
+
+    @Test
+    public void testLongPP() {
+        testLong(5, 2);
+    }
+
+    @Test
+    public void testLongNP() {
+        testLong(-5, 2);
+    }
+
+    @Test
+    public void testLongPN() {
+        testLong(5, -2);
+    }
+
+    @Test
+    public void testLongNN() {
+        testLong(-5, -2);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap01.java
new file mode 100644
index 0000000..ec653f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap01.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import java.util.EnumMap;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class EnumMap01 extends JTTTest {
+
+    private static final EnumMap<Enum, String> map = new EnumMap<>(Enum.class);
+
+    static {
+        map.put(Enum.A, "A");
+        map.put(Enum.B, "B");
+        map.put(Enum.C, "C");
+    }
+
+    public static String test(int i) {
+        return map.get(Enum.values()[i]);
+    }
+
+    private enum Enum {
+        A,
+        B,
+        C
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap02.java
new file mode 100644
index 0000000..0ad7564
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/EnumMap02.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import java.util.EnumMap;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class EnumMap02 extends JTTTest {
+
+    public static String test(int i) {
+        EnumMap<Enum, String> map = new EnumMap<>(Enum.class);
+        map.put(Enum.A, "A");
+        map.put(Enum.B, "B");
+        map.put(Enum.C, "C");
+        return map.get(Enum.values()[i]);
+    }
+
+    private enum Enum {
+        A,
+        B,
+        C
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/IntegerBits.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/IntegerBits.java
new file mode 100644
index 0000000..29ff22e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/IntegerBits.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class IntegerBits extends JTTTest {
+
+    @SuppressWarnings("unused") private static int init = Integer.reverseBytes(42);
+    private static int original = 0x01020304;
+    private static int v = 0b1000;
+    private static int zero = 0;
+
+    public static int test(int o) {
+        return Integer.reverseBytes(o);
+    }
+
+    public static int test2(int o) {
+        return Integer.numberOfLeadingZeros(o);
+    }
+
+    public static int test3(int o) {
+        return Integer.numberOfTrailingZeros(o);
+    }
+
+    public static int test4(int o) {
+        return Integer.bitCount(o);
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", original);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test3", v);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test2", v);
+    }
+
+    @Test
+    public void run3() {
+        runTest("test3", zero);
+    }
+
+    @Test
+    public void run4() {
+        runTest("test2", zero);
+    }
+
+    @Test
+    public void run5() {
+        runTest("test", 0x01020304);
+    }
+
+    @Test
+    public void run6() {
+        runTest("test3", 0b1000);
+    }
+
+    @Test
+    public void run7() {
+        runTest("test2", 0b1000);
+    }
+
+    @Test
+    public void run8() {
+        runTest("test3", 0);
+    }
+
+    @Test
+    public void run9() {
+        runTest("test2", 0);
+    }
+
+    @Test
+    public void run10() {
+        runTest("test4", 0xffffffff);
+    }
+
+    @Test
+    public void run11() {
+        runTest("test2", 0xFFFFFFFF);
+    }
+
+    @Test
+    public void run12() {
+        runTest("test2", 0x7FFFFFFF);
+    }
+
+    @Test
+    public void run17() {
+        runTest("test2", 0x80000000);
+    }
+
+    @Test
+    public void run18() {
+        runTest("test2", 0x40000000);
+    }
+
+    @Test
+    public void run13() {
+        runTest("test3", 0x7FFFFFFF);
+    }
+
+    @Test
+    public void run14() {
+        runTest("test3", 0xFFFFFFFF);
+    }
+
+    @Test
+    public void run15() {
+        runTest("test3", 0x80000000);
+    }
+
+    @Test
+    public void run16() {
+        runTest("test3", 0x40000000);
+    }
+
+    @Test
+    public void run19() {
+        runTest("test4", 0x80000000);
+    }
+
+    @Test
+    public void run20() {
+        runTest("test4", 0x40000000);
+    }
+
+    @Test
+    public void run21() {
+        runTest("test4", 0x00000001);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/LongBits.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/LongBits.java
new file mode 100644
index 0000000..7c7b95c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/LongBits.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class LongBits extends JTTTest {
+
+    @SuppressWarnings("unused") private static long init = Long.reverseBytes(42);
+    private static long original = 0x0102030405060708L;
+    private static long v = 0b1000L;
+    private static long v2 = 0x0100000000L;
+    private static long zero = 0L;
+
+    public static long test(long o) {
+        return Long.reverseBytes(o);
+    }
+
+    public static int test2(long o) {
+        return Long.numberOfLeadingZeros(o);
+    }
+
+    public static int test3(long o) {
+        return Long.numberOfTrailingZeros(o);
+    }
+
+    public static int test4(long o) {
+        return Long.bitCount(o);
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", original);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test3", v);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test2", v);
+    }
+
+    @Test
+    public void run3() {
+        runTest("test3", zero);
+    }
+
+    @Test
+    public void run4() {
+        runTest("test2", zero);
+    }
+
+    @Test
+    public void run5() {
+        runTest("test", 0x0102030405060708L);
+    }
+
+    @Test
+    public void run6() {
+        runTest("test3", 0b1000L);
+    }
+
+    @Test
+    public void run7() {
+        runTest("test2", 0b1000L);
+    }
+
+    @Test
+    public void run8() {
+        runTest("test3", 0L);
+    }
+
+    @Test
+    public void run9() {
+        runTest("test2", 0L);
+    }
+
+    @Test
+    public void run10() {
+        runTest("test2", v2);
+    }
+
+    @Test
+    public void run11() {
+        runTest("test3", v2);
+    }
+
+    @Test
+    public void run12() {
+        runTest("test2", 0x0100000000L);
+    }
+
+    @Test
+    public void run13() {
+        runTest("test3", 0x0100000000L);
+    }
+
+    @Test
+    public void run14() {
+        runTest("test4", 0L);
+        runTest("test4", 1L);
+        runTest("test4", 0xffff00ffL);
+        runTest("test4", 0xffffffffL);
+        runTest("test4", 0x3ffffffffL);
+        runTest("test4", 0xffffffff3L);
+        runTest("test4", 0xffffffffffffffffL);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/ShortBits.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/ShortBits.java
new file mode 100644
index 0000000..8648d2b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/ShortBits.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class ShortBits extends JTTTest {
+    @SuppressWarnings("unused") private static short init = Short.reverseBytes((short) 42);
+    private static short original = 0x1708;
+
+    public static short test(short o) {
+        return Short.reverseBytes(o);
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", original);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test", (short) 0x1708L);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test", (short) 0);
+        runTest("test", (short) 1);
+        runTest("test", (short) -1);
+        runTest("test", (short) 0x00ff);
+        runTest("test", (short) 0xff00);
+        runTest("test", (short) 0xffff);
+        runTest("test", (short) 0x3fff);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis01.java
new file mode 100644
index 0000000..3f1ecf8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis01.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_currentTimeMillis01 extends JTTTest {
+
+    public static int test() {
+        long start = System.currentTimeMillis();
+        for (int i = 0; i < 10000000; i++) {
+            if (System.currentTimeMillis() - start > 0) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis02.java
new file mode 100644
index 0000000..54564e6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_currentTimeMillis02.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_currentTimeMillis02 extends JTTTest {
+
+    static void m(long[] times) {
+        times[1] = System.currentTimeMillis() - times[0];
+    }
+
+    public static boolean test() {
+        long[] times = new long[2];  // { start, delta }
+        times[0] = System.currentTimeMillis();
+        times[1] = 0;
+        // force compilation:
+        for (int i = 0; i < 5000; i++) {
+            m(times);
+        }
+        times[0] = System.currentTimeMillis();
+        times[1] = 0;
+        for (int i = 0; times[1] == 0 && i < 5000000; i++) {
+            m(times);
+            // do nothing.
+        }
+        // better get at least 100 millisecond resolution.
+        return times[1] >= 1 && times[1] < 100;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime01.java
new file mode 100644
index 0000000..e950a27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime01.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_nanoTime01 extends JTTTest {
+
+    public static int test() {
+        long start = System.nanoTime();
+        for (int i = 0; i < 10000000; i++) {
+            if (System.nanoTime() - start > 0) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime02.java
new file mode 100644
index 0000000..d913a7d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_nanoTime02.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_nanoTime02 extends JTTTest {
+
+    public static boolean test() {
+        long minDelta = Long.MAX_VALUE;
+
+        // the first call to System.nanoTime might take a long time due to call resolution
+        for (int c = 0; c < 10; c++) {
+            long start = System.nanoTime();
+            long delta = 0;
+            int i;
+            for (i = 0; delta == 0 && i < 50000; i++) {
+                delta = System.nanoTime() - start;
+                // do nothing.
+            }
+            if (delta < minDelta) {
+                minDelta = delta;
+            }
+        }
+
+        // better get at least 30 microsecond resolution.
+        return minDelta > 1 && minDelta < 30000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_setOut.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_setOut.java
new file mode 100644
index 0000000..6a843a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/System_setOut.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_setOut extends JTTTest {
+
+    public static int test(int n) throws Exception {
+        PrintStream oldOut = System.out;
+        int sum = 0;
+        for (int i = 0; i < 10; i++) {
+            ByteArrayOutputStream ba = new ByteArrayOutputStream(n * 10);
+            PrintStream newOut = new PrintStream(ba);
+            System.setOut(newOut);
+            doPrint(n);
+            sum += ba.size();
+        }
+
+        System.setOut(oldOut);
+        return sum;
+    }
+
+    private static void doPrint(int n) {
+        PrintStream out = System.out;
+        for (int i = 0; i < n; i++) {
+            out.print('x');
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        PrintStream out = System.out;
+        out.println(test(10000));
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 10000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Thread_setName.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Thread_setName.java
new file mode 100644
index 0000000..b1bb7e9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Thread_setName.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Thread_setName extends JTTTest {
+
+    public static String test(String name) {
+        String oldName = Thread.currentThread().getName();
+        Thread.currentThread().setName(name);
+        String name2 = Thread.currentThread().getName();
+        Thread.currentThread().setName(oldName);
+        return name2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "abc");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAccess01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAccess01.java
new file mode 100644
index 0000000..815110f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAccess01.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import java.lang.reflect.Field;
+
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class UnsafeAccess01 extends JTTTest {
+
+    private static int randomValue = 100;
+    private static final Unsafe unsafe;
+    private static final long offset;
+    private static Object staticObject = new TestClass();
+
+    static {
+        unsafe = getUnsafe();
+        Field field = null;
+        try {
+            field = TestClass.class.getDeclaredField("field");
+        } catch (NoSuchFieldException e) {
+        } catch (SecurityException e) {
+        }
+        offset = unsafe.objectFieldOffset(field);
+    }
+
+    private static class TestClass {
+        private int field = 42;
+    }
+
+    public static int test() {
+        final TestClass object = new TestClass();
+        final int value = unsafe.getInt(object, offset);
+        return value;
+    }
+
+    static Unsafe getUnsafe() {
+        try {
+            final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+            unsafeField.setAccessible(true);
+            return (Unsafe) unsafeField.get(null);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+    @Test
+    public void runDiamond() throws Throwable {
+        runTest("testDiamond");
+    }
+
+    public static int testDiamond() {
+
+        final Object object = staticObject;
+        final int oldValue = ((TestClass) object).field;
+
+        if (randomValue == 100) {
+            unsafe.putInt(object, offset, 41);
+        } else {
+            unsafe.putInt(object, offset, 40);
+        }
+        unsafe.putInt(object, offset, 42);
+        return oldValue;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java
new file mode 100644
index 0000000..6df268c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import java.util.AbstractList;
+import java.util.List;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/*
+ */
+public class UnsafeAllocateInstance01 extends JTTTest {
+
+    int field01 = 42;
+
+    public static int testInstance() throws SecurityException, InstantiationException {
+        UnsafeAllocateInstance01 newObject = (UnsafeAllocateInstance01) UNSAFE.allocateInstance(UnsafeAllocateInstance01.class);
+        return newObject.field01;
+    }
+
+    public static void testClassForException(Class<?> clazz) throws SecurityException, InstantiationException {
+        UNSAFE.allocateInstance(clazz);
+    }
+
+    @Override
+    protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) {
+        if (args.length == 1) {
+            /*
+             * HotSpot will crash if the C2 intrinsic for this is used with array classes, so just
+             * handle it explicitly so that we can still exercise Graal.
+             */
+            Class<?> cl = (Class<?>) args[0];
+            if (cl.isArray()) {
+                return new Result(null, new InstantiationException(cl.getName()));
+            }
+        }
+        return super.executeExpected(method, receiver, args);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("testInstance");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("testClassForException", UnsafeAllocateInstance01[].class);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("testClassForException", UnsafeAllocateInstance01.class);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("testClassForException", AbstractList.class);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("testClassForException", List.class);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("testClassForException", Class.class);
+    }
+
+    @Ignore("Currently crashes hotspot because primitive classes aren't handled")
+    @Test
+    public void run5() throws Throwable {
+        runTest("testClassForException", void.class);
+    }
+
+    @Ignore("Currently crashes hotspot because primitive classes aren't handled")
+    @Test
+    public void run6() throws Throwable {
+        runTest("testClassForException", int.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwap.java
new file mode 100644
index 0000000..98f0f27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwap.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Unsafe_compareAndSwap extends JTTTest {
+
+    static final Unsafe unsafe = UnsafeAccess01.getUnsafe();
+    static final long valueOffset;
+    static {
+        try {
+            valueOffset = unsafe.objectFieldOffset(Unsafe_compareAndSwap.class.getDeclaredField("value"));
+        } catch (Exception ex) {
+            throw new Error(ex);
+        }
+    }
+
+    public static String test(Unsafe_compareAndSwap u, Object o, String expected, String newValue) {
+        // First arg is not an array - can use a field write barrier
+        unsafe.compareAndSwapObject(u, valueOffset, expected, newValue);
+        // Not known if first arg is an array - different write barrier may be used
+        unsafe.compareAndSwapObject(o, valueOffset, expected, newValue);
+
+        return instance.value;
+    }
+
+    private String value;
+
+    private static final Unsafe_compareAndSwap instance = new Unsafe_compareAndSwap();
+
+    @Override
+    protected void before(ResolvedJavaMethod m) {
+        instance.value = "a";
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", instance, instance, "a", "b");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwapNullCheck.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwapNullCheck.java
new file mode 100644
index 0000000..5d109a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/Unsafe_compareAndSwapNullCheck.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.jdk;
+
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Unsafe_compareAndSwapNullCheck extends JTTTest {
+
+    static final Unsafe unsafe = UnsafeAccess01.getUnsafe();
+    static final long valueOffset;
+    static {
+        try {
+            valueOffset = unsafe.objectFieldOffset(Unsafe_compareAndSwap.class.getDeclaredField("value"));
+        } catch (Exception ex) {
+            throw new Error(ex);
+        }
+    }
+
+    long value;
+    long lng;
+
+    public static void test(Unsafe_compareAndSwapNullCheck u, long expected, long newValue) {
+        @SuppressWarnings("unused")
+        long l = u.lng;
+        unsafe.compareAndSwapLong(u, valueOffset, expected, newValue);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest(EMPTY, false, true, "test", null, 1L, 2L);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Boxed_TYPE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Boxed_TYPE_01.java
new file mode 100644
index 0000000..66b827f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Boxed_TYPE_01.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Boxed_TYPE_01 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return Boolean.TYPE.getName();
+        }
+        if (i == 1) {
+            return Byte.TYPE.getName();
+        }
+        if (i == 2) {
+            return Character.TYPE.getName();
+        }
+        if (i == 3) {
+            return Double.TYPE.getName();
+        }
+        if (i == 4) {
+            return Float.TYPE.getName();
+        }
+        if (i == 5) {
+            return Integer.TYPE.getName();
+        }
+        if (i == 6) {
+            return Long.TYPE.getName();
+        }
+        if (i == 7) {
+            return Short.TYPE.getName();
+        }
+        if (i == 8) {
+            return Void.TYPE.getName();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Bridge_method01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Bridge_method01.java
new file mode 100644
index 0000000..b425d01
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Bridge_method01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Bridge_method01 extends JTTTest {
+
+    private abstract static class Wrap<T> {
+
+        abstract T get();
+    }
+
+    private static class IWrap extends Wrap<Integer> {
+
+        @Override
+        Integer get() {
+            return 1;
+        }
+    }
+
+    private static Wrap<Integer> wrapped = new IWrap();
+
+    public static int test() {
+        return wrapped.get();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ClassLoader_loadClass01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ClassLoader_loadClass01.java
new file mode 100644
index 0000000..1472c29
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ClassLoader_loadClass01.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class ClassLoader_loadClass01 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        final URLClassLoader classLoader = new URLClassLoader(new URL[0], String.class.getClassLoader());
+        if (i == 0) {
+            return classLoader.loadClass("java.lang.String").toString();
+        } else if (i == 1) {
+            return classLoader.loadClass("[Ljava.lang.String;").toString();
+        } else if (i == 2) {
+            return classLoader.loadClass("java.lang.String[]").toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_Literal01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_Literal01.java
new file mode 100644
index 0000000..e9681ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_Literal01.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_Literal01 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return Object.class.toString();
+        }
+        if (i == 1) {
+            return String.class.toString();
+        }
+        if (i == 2) {
+            return Class.class.toString();
+        }
+        if (i == 3) {
+            return Class_Literal01.class.toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_asSubclass01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_asSubclass01.java
new file mode 100644
index 0000000..11053e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_asSubclass01.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_asSubclass01 extends JTTTest {
+
+    public static int test(int i) {
+        if (i == 0) {
+            if (Object.class.asSubclass(String.class) == null) {
+                return -1;
+            }
+        }
+        if (i == 1) {
+            if (String.class.asSubclass(Object.class) == null) {
+                return -1;
+            }
+        }
+        if (i == 2) {
+            if (Object.class.asSubclass(Class_asSubclass01.class) == null) {
+                return -1;
+            }
+        }
+        if (i == 3) {
+            if (Class_asSubclass01.class.asSubclass(Object.class) == null) {
+                return -1;
+            }
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast01.java
new file mode 100644
index 0000000..cdf62cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_cast01 extends JTTTest {
+
+    static final String string = "";
+    static final Object object = new Object();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static int test(int i) {
+        if (i == 0) {
+            if (Object.class.cast(string) == null) {
+                return -1;
+            }
+        }
+        if (i == 1) {
+            if (String.class.cast(object) == null) {
+                return -1;
+            }
+        }
+        if (i == 2) {
+            if (Object.class.cast(thisObject) == null) {
+                return -1;
+            }
+        }
+        if (i == 3) {
+            if (DummyTestClass.class.cast(object) == null) {
+                return -1;
+            }
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast02.java
new file mode 100644
index 0000000..4657298
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_cast02.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_cast02 extends JTTTest {
+
+    static final String string = "";
+    static final Object object = new Object();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static int test(int i) {
+        if (i == 0) {
+            if (Object.class.cast(null) == null) {
+                return -1;
+            }
+        }
+        if (i == 1) {
+            if (String.class.cast(null) == null) {
+                return -1;
+            }
+        }
+        if (i == 2) {
+            if (Object.class.cast(null) == null) {
+                return -1;
+            }
+        }
+        if (i == 3) {
+            if (DummyTestClass.class.cast(null) == null) {
+                return -1;
+            }
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName01.java
new file mode 100644
index 0000000..443e961
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName01.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_forName01 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        if (i == 0) {
+            return Class.forName("java.lang.Object").toString();
+        }
+        if (i == 1) {
+            return Class.forName("java.lang.String").toString();
+        }
+        if (i == 2) {
+            return Class.forName("org.graalvm.compiler.jtt.lang.Class_forName01").toString();
+        }
+        if (i == 3) {
+            return Class.forName("xyxzz.xyzyzyz.XXYYY").toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName02.java
new file mode 100644
index 0000000..9ac0300
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName02.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_forName02 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        String clname = null;
+        Class<?> cl = null;
+        if (i == 0) {
+            clname = "java.lang.Object";
+            cl = Object.class;
+        } else if (i == 1) {
+            clname = "java.lang.String";
+            cl = String.class;
+        } else if (i == 2) {
+            clname = "org.graalvm.compiler.jtt.lang.Class_forName02";
+            cl = Class_forName02.class;
+        } else if (i == 3) {
+            clname = "xyzz.zyxy.XYXY";
+            cl = Class_forName02.class;
+        }
+        if (clname != null) {
+            return Class.forName(clname, false, cl.getClassLoader()).toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName03.java
new file mode 100644
index 0000000..715f7d7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName03.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Class_forName03 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        String clname = null;
+        Class<?> cl = null;
+        if (i == 0) {
+            clname = "java.lang.Object[]";
+            cl = Object.class;
+        } else if (i == 1) {
+            clname = "[Ljava.lang.String;";
+            cl = String.class;
+        } else if (i == 2) {
+            clname = "[Ljava/lang/String;";
+            cl = String.class;
+        } else if (i == 3) {
+            clname = "[I";
+            cl = Class_forName03.class;
+        } else if (i == 4) {
+            clname = "[java.lang.Object;";
+            cl = Class_forName03.class;
+        }
+        if (clname != null) {
+            return Class.forName(clname, false, new URLClassLoader(new URL[0], cl.getClassLoader())).toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName04.java
new file mode 100644
index 0000000..25276ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName04.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Class_forName04 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        String clname = null;
+        if (i == 0) {
+            clname = "java.lang.Object[]";
+        } else if (i == 1) {
+            clname = "[Ljava.lang.String;";
+        } else if (i == 2) {
+            clname = "[Ljava/lang/String;";
+        } else if (i == 3) {
+            clname = "[I";
+        } else if (i == 4) {
+            clname = "[java.lang.Object;";
+        }
+        if (clname != null) {
+            return Class.forName(clname).toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName05.java
new file mode 100644
index 0000000..d5eede5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_forName05.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Class_forName05 extends JTTTest {
+
+    public static String test(int i) throws ClassNotFoundException {
+        final URLClassLoader classLoader = new URLClassLoader(new URL[0], String.class.getClassLoader());
+        if (i == 0) {
+            return Class.forName("java.lang.String", false, classLoader).toString();
+        } else if (i == 1) {
+            return Class.forName("[Ljava.lang.String;", false, classLoader).toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getComponentType01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getComponentType01.java
new file mode 100644
index 0000000..8134c97
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getComponentType01.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getComponentType01 extends JTTTest {
+
+    public static String test(int i) {
+        Class<?> cl = Object.class;
+        if (i == 0) {
+            cl = int.class;
+        } else if (i == 1) {
+            cl = int[].class;
+        } else if (i == 2) {
+            cl = Object.class;
+        } else if (i == 3) {
+            cl = Object[].class;
+        } else if (i == 4) {
+            cl = Class_getComponentType01.class;
+        } else if (i == 5) {
+            cl = Cloneable.class;
+        } else if (i == 6) {
+            cl = Object[][].class;
+        } else if (i == 7) {
+            cl = void.class;
+        }
+        cl = cl.getComponentType();
+        if (cl == null) {
+            return null;
+        }
+        return cl.getName();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getInterfaces01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getInterfaces01.java
new file mode 100644
index 0000000..fc77af6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getInterfaces01.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Class_getInterfaces01 extends JTTTest {
+
+    public static Class<?>[] test(Class<?> clazz) {
+        return clazz.getInterfaces();
+    }
+
+    interface I1 {
+
+    }
+
+    interface I2 extends I1 {
+
+    }
+
+    static class C1 implements I1 {
+
+    }
+
+    static class C2 implements I2 {
+
+    }
+
+    static class C12 implements I1, I2 {
+
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", I1.class);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", I2.class);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", C1.class);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", C2.class);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", C12.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers01.java
new file mode 100644
index 0000000..51a807e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.io.Serializable;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getModifiers01 extends JTTTest {
+
+    private static class PrivateStatic {
+    }
+
+    private static final class PrivateStaticFinal {
+    }
+
+    private static class Private {
+    }
+
+    public static int test(Class<?> c) {
+        return c.getModifiers();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", Object.class);
+        runTest("test", Object[].class);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", Serializable.class);
+        runTest("test", Serializable[].class);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", void.class);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", int.class);
+        runTest("test", int[].class);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", Private.class);
+        runTest("test", Private[].class);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", PrivateStatic.class);
+        runTest("test", PrivateStatic[].class);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", PrivateStaticFinal.class);
+        runTest("test", PrivateStaticFinal[].class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers02.java
new file mode 100644
index 0000000..e6afe5f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getModifiers02.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getModifiers02 extends JTTTest {
+
+    public static int test(int i) {
+        if (i == 0) {
+            return int.class.getModifiers();
+        }
+        if (i == 1) {
+            return int[].class.getModifiers();
+        }
+        if (i == 2) {
+            return Object[][].class.getModifiers();
+        }
+        return Class_getModifiers02.class.getModifiers();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName01.java
new file mode 100644
index 0000000..11c3a9f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName01.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getName01 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return Object.class.getName();
+        } else if (i == 1) {
+            return Class.class.getName();
+        } else if (i == 2) {
+            return Class_getName01.class.getName();
+        } else if (i == 3) {
+            return "a string".getClass() == String.class ? "true" : "false";
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName02.java
new file mode 100644
index 0000000..6bdec6e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getName02.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getName02 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return int.class.getName();
+        }
+        if (i == 1) {
+            return int[].class.getName();
+        }
+        if (i == 2) {
+            return Object[][].class.getName();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName01.java
new file mode 100644
index 0000000..e8442ad
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getSimpleName01 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return Object.class.getSimpleName();
+        }
+        if (i == 1) {
+            return Class.class.getSimpleName();
+        }
+        if (i == 2) {
+            return Class_getSimpleName01.class.getSimpleName();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName02.java
new file mode 100644
index 0000000..aca900b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSimpleName02.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getSimpleName02 extends JTTTest {
+
+    public static String test(int i) {
+        if (i == 0) {
+            return int.class.getSimpleName();
+        }
+        if (i == 1) {
+            return int[].class.getSimpleName();
+        }
+        if (i == 2) {
+            return Object[][].class.getSimpleName();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSuperClass01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSuperClass01.java
new file mode 100644
index 0000000..112c010
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_getSuperClass01.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_getSuperClass01 extends JTTTest {
+
+    public static String test(int i) {
+        Class<?> cl = Object.class;
+        if (i == 0) {
+            cl = int.class;
+        } else if (i == 1) {
+            cl = Object.class;
+        } else if (i == 2) {
+            cl = int[].class;
+        } else if (i == 3) {
+            cl = Cloneable.class;
+        } else if (i == 4) {
+            cl = Integer.class;
+        } else if (i == 5) {
+            cl = Class.class;
+        } else if (i == 6) {
+            cl = Class_getSuperClass01.class;
+        }
+        cl = cl.getSuperclass();
+        if (cl == null) {
+            return null;
+        }
+        return cl.getName();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isArray01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isArray01.java
new file mode 100644
index 0000000..ae6442a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isArray01.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isArray01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return int.class.isArray();
+        }
+        if (i == 1) {
+            return int[].class.isArray();
+        }
+        if (i == 2) {
+            return Object.class.isArray();
+        }
+        if (i == 3) {
+            return Object[].class.isArray();
+        }
+        if (i == 4) {
+            return Class_isArray01.class.isArray();
+        }
+        if (i == 5) {
+            return Cloneable.class.isArray();
+        }
+        if (i == 6) {
+            return Runnable.class.isArray();
+        }
+        if (i == 7) {
+            return void.class.isArray();
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom01.java
new file mode 100644
index 0000000..31d520a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom01.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isAssignableFrom01 extends JTTTest {
+
+    public static boolean test(int i) {
+        Class<?> source = Object.class;
+        if (i == 0) {
+            source = int.class;
+        }
+        if (i == 1) {
+            source = int[].class;
+        }
+        if (i == 2) {
+            source = float.class;
+        }
+        if (i == 3) {
+            source = byte.class;
+        }
+        if (i == 4) {
+            source = Runnable.class;
+        }
+        if (i == 5) {
+            source = Class_isAssignableFrom01.class;
+        }
+        if (i == 6) {
+            source = Object[].class;
+        }
+        return int.class.isAssignableFrom(source);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom02.java
new file mode 100644
index 0000000..06803df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom02.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isAssignableFrom02 extends JTTTest {
+
+    public static boolean test(int i) {
+        Class<?> source = Object.class;
+        if (i == 0) {
+            source = int.class;
+        }
+        if (i == 1) {
+            source = int[].class;
+        }
+        if (i == 2) {
+            source = float.class;
+        }
+        if (i == 3) {
+            source = byte.class;
+        }
+        if (i == 4) {
+            source = Runnable.class;
+        }
+        if (i == 5) {
+            source = Class_isAssignableFrom02.class;
+        }
+        if (i == 6) {
+            source = Object[].class;
+        }
+        return Object.class.isAssignableFrom(source);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom03.java
new file mode 100644
index 0000000..361f092
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isAssignableFrom03.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isAssignableFrom03 extends JTTTest implements Cloneable {
+
+    public static boolean test(int i) {
+        Class<?> source = Object.class;
+        if (i == 0) {
+            source = int.class;
+        }
+        if (i == 1) {
+            source = int[].class;
+        }
+        if (i == 2) {
+            source = float.class;
+        }
+        if (i == 3) {
+            source = Cloneable.class;
+        }
+        if (i == 4) {
+            source = Runnable.class;
+        }
+        if (i == 5) {
+            source = Class_isAssignableFrom03.class;
+        }
+        if (i == 6) {
+            source = Object[].class;
+        }
+        return Cloneable.class.isAssignableFrom(source);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance01.java
new file mode 100644
index 0000000..82cccfe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance01.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance01 extends JTTTest {
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = thisObject;
+        }
+        return Object.class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance02.java
new file mode 100644
index 0000000..a8454f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance02.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance02 extends JTTTest {
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = thisObject;
+        }
+        return String.class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance03.java
new file mode 100644
index 0000000..f5dffd4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance03.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance03 extends JTTTest {
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = thisObject;
+        }
+        return DummyTestClass.class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance04.java
new file mode 100644
index 0000000..ae00fa9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance04.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance04 extends JTTTest {
+
+    static final String string = "";
+    static final Object[] oarray = {};
+    static final String[] sarray = {};
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = oarray;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = sarray;
+        }
+        return String[].class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance05.java
new file mode 100644
index 0000000..e6289a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance05.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance05 extends JTTTest {
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final int[] array = {};
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = array;
+        }
+        return int[].class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance06.java
new file mode 100644
index 0000000..a4507b5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance06.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance06 extends JTTTest {
+
+    private static class TestClass implements Cloneable {
+    }
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final String[] sarray = {};
+    static final Object thisObject = new TestClass();
+
+    public static boolean test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = sarray;
+        }
+        if (i == 3) {
+            object = thisObject;
+        }
+        return Cloneable.class.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance07.java
new file mode 100644
index 0000000..77a5e0e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInstance07.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInstance07 extends JTTTest {
+
+    static final String string = "";
+    static final Object obj = new Object();
+    static final String[] sarray = {};
+    static final Object thisObject = new DummyTestClass();
+
+    public static boolean test(int i, Class<?> c) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        }
+        if (i == 1) {
+            object = string;
+        }
+        if (i == 2) {
+            object = thisObject;
+        }
+        return c.isInstance(object);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, String.class);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, String.class);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, String.class);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, String.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInterface01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInterface01.java
new file mode 100644
index 0000000..f60f3e8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isInterface01.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isInterface01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return int.class.isInterface();
+        }
+        if (i == 1) {
+            return int[].class.isInterface();
+        }
+        if (i == 2) {
+            return Object.class.isInterface();
+        }
+        if (i == 3) {
+            return Object[].class.isInterface();
+        }
+        if (i == 4) {
+            return Class_isInterface01.class.isInterface();
+        }
+        if (i == 5) {
+            return Cloneable.class.isInterface();
+        }
+        if (i == 6) {
+            return Runnable.class.isInterface();
+        }
+        if (i == 7) {
+            return void.class.isInterface();
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isPrimitive01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isPrimitive01.java
new file mode 100644
index 0000000..e7efda5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Class_isPrimitive01.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_isPrimitive01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return int.class.isPrimitive();
+        }
+        if (i == 1) {
+            return int[].class.isPrimitive();
+        }
+        if (i == 2) {
+            return Object.class.isPrimitive();
+        }
+        if (i == 3) {
+            return Object[].class.isPrimitive();
+        }
+        if (i == 4) {
+            return Class_isPrimitive01.class.isPrimitive();
+        }
+        if (i == 5) {
+            return Cloneable.class.isPrimitive();
+        }
+        if (i == 6) {
+            return Runnable.class.isPrimitive();
+        }
+        if (i == 7) {
+            return void.class.isPrimitive();
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_01.java
new file mode 100644
index 0000000..745bdd9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_01.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Double_01 extends JTTTest {
+
+    public static boolean test() {
+        return Double.doubleToLongBits(Double.longBitsToDouble(0x7ff8000000000088L)) == 0x7ff8000000000000L;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_conditional.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_conditional.java
new file mode 100644
index 0000000..3e70d58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_conditional.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.bytecode.BC_double_base;
+
+public final class Double_conditional extends BC_double_base {
+
+    public static double test(double x, double y) {
+        if (x == y) {
+            return y;
+        }
+        return x;
+    }
+
+    public static double conditional(double x, double y) {
+        return x == y ? x : y;
+    }
+
+    @Test
+    public void runEquals() throws Throwable {
+        runTest("test", x, y);
+    }
+
+    @Test
+    public void runConditional() throws Throwable {
+        runTest("conditional", x, y);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_toString.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_toString.java
new file mode 100644
index 0000000..4c8a184
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Double_toString.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Double_toString extends JTTTest {
+
+    public static String test() {
+        double z1 = 0.4363485526704198;
+        double z2 = -0.43536514763046896;
+        double z3 = z1 + z2;
+        return Double.toString(z3);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_01.java
new file mode 100644
index 0000000..96907a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_01.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Float_01 extends JTTTest {
+
+    public static boolean test(float f) {
+        return /* Float.isNaN(f); */f != f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.5f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", java.lang.Float.NaN);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_02.java
new file mode 100644
index 0000000..1c97b35
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_02.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Float_02 extends JTTTest {
+
+    public static boolean test(float f) {
+        return f != 1.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1.0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2.0f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.5f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", java.lang.Float.NaN);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_03.java
new file mode 100644
index 0000000..d201995
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_03.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Float_03 extends JTTTest {
+
+    public static boolean test() {
+        return Float.floatToIntBits(Float.intBitsToFloat(0x7fc00088)) == 0x7fc00000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_conditional.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_conditional.java
new file mode 100644
index 0000000..622374b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Float_conditional.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.bytecode.BC_float_base;
+
+public final class Float_conditional extends BC_float_base {
+
+    public static float test(float x, float y) {
+        if (x == y) {
+            return y;
+        }
+        return x;
+    }
+
+    public static float conditional(float x, float y) {
+        return x == y ? x : y;
+    }
+
+    @Test
+    public void runEquals() throws Throwable {
+        runTest("test", x, y);
+    }
+
+    @Test
+    public void runConditional() throws Throwable {
+        runTest("conditional", x, y);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater01.java
new file mode 100644
index 0000000..99c0987
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greater01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i > 0) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater02.java
new file mode 100644
index 0000000..c04fe65
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater02.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greater02 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i > 5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater03.java
new file mode 100644
index 0000000..9fec7e6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greater03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greater03 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i > -5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual01.java
new file mode 100644
index 0000000..b477194
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greaterEqual01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i >= 0) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual02.java
new file mode 100644
index 0000000..982a78c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual02.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greaterEqual02 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i >= 5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual03.java
new file mode 100644
index 0000000..ee253f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_greaterEqual03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_greaterEqual03 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i >= -5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less01.java
new file mode 100644
index 0000000..dc8471d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_less01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i < 0) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less02.java
new file mode 100644
index 0000000..4fc03c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less02.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_less02 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i < 5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less03.java
new file mode 100644
index 0000000..9f49539
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_less03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_less03 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i < -5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual01.java
new file mode 100644
index 0000000..61340e2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_lessEqual01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i <= 0) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual02.java
new file mode 100644
index 0000000..1a73117
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual02.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_lessEqual02 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i <= 5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual03.java
new file mode 100644
index 0000000..6350a60
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Int_lessEqual03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Int_lessEqual03 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i <= -5) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders01.java
new file mode 100644
index 0000000..fe37e20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders01.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class JDK_ClassLoaders01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return Object.class.getClassLoader() == null;
+        }
+        if (i == 1) {
+            return Class.class.getClassLoader() == null;
+        }
+        if (i == 2) {
+            return String.class.getClassLoader() == null;
+        }
+        if (i == 3) {
+            return Thread.class.getClassLoader() == null;
+        }
+        if (i == 4) {
+            return System.class.getClassLoader() == null;
+        }
+        if (i == 5) {
+            return ClassLoader.class.getClassLoader() == null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders02.java
new file mode 100644
index 0000000..c36e97c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/JDK_ClassLoaders02.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.net.URLClassLoader;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class JDK_ClassLoaders02 extends JTTTest {
+
+    public static boolean test() {
+        ClassLoader classLoader = JDK_ClassLoaders02.class.getClassLoader();
+        return classLoader == null || classLoader instanceof URLClassLoader;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/LambdaEagerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/LambdaEagerTest.java
new file mode 100644
index 0000000..cefbae2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/LambdaEagerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.util.EnumSet;
+import java.util.function.IntBinaryOperator;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+public class LambdaEagerTest extends GraalCompilerTest {
+
+    private static final EnumSet<DeoptimizationReason> UNRESOLVED_UNREACHED = EnumSet.of(DeoptimizationReason.Unresolved, DeoptimizationReason.UnreachedCode);
+
+    private static int doBinary(IntBinaryOperator op, int x, int y) {
+        return op.applyAsInt(x, y);
+    }
+
+    private static int add(int x, int y) {
+        return x + y;
+    }
+
+    public static int nonCapturing(int x, int y) {
+        return doBinary((a, b) -> a + b, x, y);
+    }
+
+    public static int nonCapturing2(int x, int y) {
+        return doBinary(LambdaEagerTest::add, x, y);
+    }
+
+    public static int capturing(int x, int y, int z) {
+        return doBinary((a, b) -> a + b - z, x, y);
+    }
+
+    @Test
+    public void testEagerResolveNonCapturing01() {
+        Result expected = new Result(3, null);
+        testAgainstExpected(getResolvedJavaMethod("nonCapturing"), expected, UNRESOLVED_UNREACHED, 1, 2);
+    }
+
+    @Test
+    public void testEagerResolveNonCapturing02() {
+        Result expected = new Result(3, null);
+        testAgainstExpected(getResolvedJavaMethod("nonCapturing2"), expected, UNRESOLVED_UNREACHED, 1, 2);
+    }
+
+    @Test
+    public void testEagerResolveCapturing() {
+        Result expected = new Result(0, null);
+        testAgainstExpected(getResolvedJavaMethod("capturing"), expected, UNRESOLVED_UNREACHED, 1, 2, 3);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile) {
+        try (OverrideScope scope = OptionValue.override(GraalOptions.InlineEverything, true)) {
+            return super.getCode(installedCodeOwner, graph, forceCompile);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater01.java
new file mode 100644
index 0000000..a00d3fe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public final class Long_greater01 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i > 0L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater02.java
new file mode 100644
index 0000000..d9871bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater02.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_greater02 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i > 5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater03.java
new file mode 100644
index 0000000..c1ee30a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greater03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_greater03 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i > -5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual01.java
new file mode 100644
index 0000000..28ccc37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_greaterEqual01 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i >= 0L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual02.java
new file mode 100644
index 0000000..d6876fe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual02.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_greaterEqual02 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i >= 5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual03.java
new file mode 100644
index 0000000..c57cf8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_greaterEqual03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_greaterEqual03 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i >= -5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less01.java
new file mode 100644
index 0000000..9c55fcb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_less01 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i < 0L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less02.java
new file mode 100644
index 0000000..3aa0d90
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less02.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_less02 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i < 5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less03.java
new file mode 100644
index 0000000..ad1ef48
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_less03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_less03 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i < -5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual01.java
new file mode 100644
index 0000000..22cf6ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual01.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_lessEqual01 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i <= 0L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual02.java
new file mode 100644
index 0000000..8386107
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual02.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_lessEqual02 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i <= 5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual03.java
new file mode 100644
index 0000000..4ea9813
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_lessEqual03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Long_lessEqual03 extends JTTTest {
+
+    public static boolean test(long i) {
+        if (i <= -5L) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -9223372036854775808L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -6L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 9223372036854775807L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes01.java
new file mode 100644
index 0000000..d929a34
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes01.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Long_reverseBytes01 extends JTTTest {
+
+    public static long test(long val) {
+        return Long.reverseBytes(val);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0x1122334455667708L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes02.java
new file mode 100644
index 0000000..e69a029
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Long_reverseBytes02.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Long_reverseBytes02 extends JTTTest {
+
+    public static long test(long val) {
+        return (((val >> 56) & 0xff) << 0) | (((val >> 48) & 0xff) << 8) | (((val >> 40) & 0xff) << 16) | (((val >> 32) & 0xff) << 24) | (((val >> 24) & 0xff) << 32) | (((val >> 16) & 0xff) << 40) |
+                        (((val >> 8) & 0xff) << 48) | (((val >> 0) & 0xff) << 56);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0x1122334455667708L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java
new file mode 100644
index 0000000..8e20462
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_abs extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.abs(arg);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 5.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -5.0d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java
new file mode 100644
index 0000000..7ec9f38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_cos extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.cos(arg);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exact.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exact.java
new file mode 100644
index 0000000..dd180e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exact.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_exact extends JTTTest {
+
+    public static int testIntAddExact(int a, int b) {
+        return Math.addExact(a, b);
+    }
+
+    @Test
+    public void runTestIntAddExact() throws Throwable {
+        runTest("testIntAddExact", 1, 2);
+        runTest("testIntAddExact", 1, Integer.MAX_VALUE);
+        runTest("testIntAddExact", -1, Integer.MIN_VALUE);
+    }
+
+    public static long testLongAddExact(long a, long b) {
+        return Math.addExact(a, b);
+    }
+
+    @Test
+    public void runTestLongAddExact() throws Throwable {
+        runTest("testLongAddExact", 1L, 2L);
+        runTest("testLongAddExact", 1L, Long.MAX_VALUE);
+        runTest("testLongAddExact", -1L, Long.MIN_VALUE);
+    }
+
+    public static int testIntSubExact(int a, int b) {
+        return Math.subtractExact(a, b);
+    }
+
+    @Test
+    public void runTestIntSubExact() throws Throwable {
+        runTest("testIntSubExact", 1, 2);
+        runTest("testIntSubExact", -2, Integer.MAX_VALUE);
+        runTest("testIntSubExact", 2, Integer.MIN_VALUE);
+    }
+
+    public static long testLongSubExact(long a, long b) {
+        return Math.subtractExact(a, b);
+    }
+
+    @Test
+    public void runTestLongSubExact() throws Throwable {
+        runTest("testLongSubExact", 1L, 2L);
+        runTest("testLongSubExact", -2L, Long.MAX_VALUE);
+        runTest("testLongSubExact", 2L, Long.MIN_VALUE);
+    }
+
+    public static int testIntMulExact(int a, int b) {
+        return Math.multiplyExact(a, b);
+    }
+
+    @Test
+    public void runTestIntMulExact() throws Throwable {
+        runTest("testIntMulExact", 1, 2);
+        runTest("testIntMulExact", -2, Integer.MAX_VALUE);
+        runTest("testIntMulExact", 2, Integer.MIN_VALUE);
+    }
+
+    public static long testLongMulExact(long a, long b) {
+        return Math.multiplyExact(a, b);
+    }
+
+    @Test
+    public void runTestLongMulExact() throws Throwable {
+        runTest("testLongMulExact", 1L, 2L);
+        runTest("testLongMulExact", 2L, Long.MAX_VALUE);
+        runTest("testLongMulExact", -2L, Long.MIN_VALUE);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java
new file mode 100644
index 0000000..7824eee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_exp extends JTTTest {
+
+    public static double test(double arg) {
+        return Math.exp(arg);
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run3() {
+        runTest("test", -1D);
+    }
+
+    @Test
+    public void run4() {
+        runTest("test", -0.0D);
+    }
+
+    @Test
+    public void run5() {
+        runTest("test", 0.0D);
+    }
+
+    @Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>")
+    @Test
+    public void run6() {
+        runTest("test", 1.0D);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java
new file mode 100644
index 0000000..02a126c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_log extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.log(arg);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", java.lang.Math.E);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log10.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log10.java
new file mode 100644
index 0000000..0f77ca9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log10.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * This has been converted to JUnit from the jtreg test test/java/lang/Math/Log10Tests.java in JDK8.
+ */
+@RunWith(Parameterized.class)
+public final class Math_log10 extends JTTTest {
+
+    static final double LN_10 = StrictMath.log(10.0);
+
+    @Parameter(value = 0) public double input;
+    @Parameter(value = 1) public Number input2;
+    @Parameter(value = 2) public Number result;
+    @Parameter(value = 3) public Condition condition;
+    public Double computedResult;
+
+    enum Condition {
+        EQUALS,
+        THREE_ULPS,
+        MONOTONICITY
+    }
+
+    public static double log10(double v) {
+        return Math.log10(v);
+    }
+
+    public static boolean log10Monotonicity(double v, double v2) {
+        return Math.log10(v) < Math.log(v2);
+    }
+
+    @Test
+    public void testLog10() {
+        if (condition == Condition.MONOTONICITY) {
+            runTest("log10Monotonicity", input, input2.doubleValue());
+        } else {
+            runTest("log10", input);
+        }
+    }
+
+    public static double strictLog10(double v) {
+        return StrictMath.log10(v);
+    }
+
+    public static boolean strictLog10Monotonicity(double v, double v2) {
+        return StrictMath.log10(v) < StrictMath.log(v2);
+    }
+
+    @Test
+    public void testStrictLog10() {
+        if (condition == Condition.MONOTONICITY) {
+            runTest("strictLog10Monotonicity", input, input2.doubleValue());
+        } else {
+            runTest("strictLog10", input);
+        }
+    }
+
+    @Before
+    public void before() {
+        computedResult = null;
+    }
+
+    private static boolean checkFor3ulps(double expected, double result) {
+        return Math.abs(result - expected) / Math.ulp(expected) <= 3;
+    }
+
+    @Override
+    protected void assertDeepEquals(Object expected, Object actual) {
+        if (this.condition == Condition.THREE_ULPS) {
+            double actualValue = ((Number) actual).doubleValue();
+            assertTrue("differs by more than 3 ulps: " + result.doubleValue() + "," + actualValue, checkFor3ulps(result.doubleValue(), actualValue));
+            if (computedResult != null && actualValue != computedResult) {
+                /*
+                 * This test detects difference in the actual result between the built in
+                 * implementation and what Graal does. If it reaches this test then the value was
+                 * within 3 ulps but differs in the exact amount.
+                 *
+                 * System.err.println("value for " + input + " is within 3 ulps but differs from
+                 * computed value: " + computedResult + " " + actualValue);
+                 */
+            }
+        } else {
+            super.assertDeepEquals(expected, actual);
+        }
+    }
+
+    @Override
+    protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) {
+        Result actual = super.executeExpected(method, receiver, args);
+        if (actual.returnValue instanceof Number) {
+            computedResult = ((Number) actual.returnValue).doubleValue();
+            assertDeepEquals(computedResult, actual.returnValue);
+        }
+        return actual;
+    }
+
+    static void addEqualityTest(List<Object[]> tests, double input, double expected) {
+        tests.add(new Object[]{input, null, expected, Condition.EQUALS});
+    }
+
+    static void add3UlpTest(List<Object[]> tests, double input, double expected) {
+        tests.add(new Object[]{input, null, expected, Condition.THREE_ULPS});
+    }
+
+    static void addMonotonicityTest(List<Object[]> tests, double input, double input2) {
+        tests.add(new Object[]{input, input2, null, Condition.MONOTONICITY});
+    }
+
+    @Parameters(name = "{index}")
+    public static Collection<Object[]> data() {
+        List<Object[]> tests = new ArrayList<>();
+
+        addEqualityTest(tests, Double.NaN, Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0x7FF0000000000001L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0xFFF0000000000001L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0x7FF8555555555555L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0xFFF8555555555555L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0x7FFDeadBeef00000L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0xFFFDeadBeef00000L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0x7FFCafeBabe00000L), Double.NaN);
+        addEqualityTest(tests, Double.longBitsToDouble(0xFFFCafeBabe00000L), Double.NaN);
+        addEqualityTest(tests, Double.NEGATIVE_INFINITY, Double.NaN);
+        addEqualityTest(tests, -8.0, Double.NaN);
+        addEqualityTest(tests, -1.0, Double.NaN);
+        addEqualityTest(tests, -Double.MIN_NORMAL, Double.NaN);
+        addEqualityTest(tests, -Double.MIN_VALUE, Double.NaN);
+        addEqualityTest(tests, -0.0, -Double.POSITIVE_INFINITY);
+        addEqualityTest(tests, +0.0, -Double.POSITIVE_INFINITY);
+        addEqualityTest(tests, +1.0, 0.0);
+        addEqualityTest(tests, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+
+        // Test log10(10^n) == n for integer n; 10^n, n < 0 is not
+        // exactly representable as a floating-point value -- up to
+        // 10^22 can be represented exactly
+        double testCase = 1.0;
+        for (int i = 0; i < 23; i++) {
+            addEqualityTest(tests, testCase, i);
+            testCase *= 10.0;
+        }
+
+        // Test for gross inaccuracy by comparing to log; should be
+        // within a few ulps of log(x)/log(10)
+        Random rand = new java.util.Random(0L);
+        for (int i = 0; i < 10000; i++) {
+            double input = Double.longBitsToDouble(rand.nextLong());
+            if (!Double.isFinite(input)) {
+                continue; // avoid testing NaN and infinite values
+            } else {
+                input = Math.abs(input);
+
+                double expected = StrictMath.log(input) / LN_10;
+                if (!Double.isFinite(expected)) {
+                    continue; // if log(input) overflowed, try again
+                } else {
+                    add3UlpTest(tests, input, expected);
+                }
+            }
+        }
+
+        double z = Double.NaN;
+        // Test inputs greater than 1.0.
+        double[] input = new double[40];
+        int half = input.length / 2;
+        // Initialize input to the 40 consecutive double values
+        // "centered" at 1.0.
+        double up = Double.NaN;
+        double down = Double.NaN;
+        for (int i = 0; i < half; i++) {
+            if (i == 0) {
+                input[half] = 1.0;
+                up = Math.nextUp(1.0);
+                down = Math.nextDown(1.0);
+            } else {
+                input[half + i] = up;
+                input[half - i] = down;
+                up = Math.nextUp(up);
+                down = Math.nextDown(down);
+            }
+        }
+        input[0] = Math.nextDown(input[1]);
+        for (int i = 0; i < input.length; i++) {
+            // Test accuracy.
+            z = input[i] - 1.0;
+            double expected = (z - (z * z) * 0.5) / LN_10;
+            add3UlpTest(tests, input[i], expected);
+
+            // Test monotonicity
+            if (i > 0) {
+                addMonotonicityTest(tests, input[i - 1], input[i]);
+            }
+        }
+
+        return tests;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java
new file mode 100644
index 0000000..0ad21ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_pow extends JTTTest {
+
+    public static double test(double x, double y) {
+        return Math.pow(x, y);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 2d, 0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2d, 0.5d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2d, 0.5d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2d, 1d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 2d, -1d);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 2d, 2d);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 2d, 3.1d);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 2d, Double.NaN);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", Double.NaN, 0d);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", Double.NaN, 23d);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 0.999998, 1500000.0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_round.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_round.java
new file mode 100644
index 0000000..888e4a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_round.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+@RunWith(Parameterized.class)
+public class Math_round extends JTTTest {
+
+    @Parameter(value = 0) public double input;
+
+    public static double rint(double arg) {
+        return Math.rint(arg);
+    }
+
+    @Test
+    public void runRint() throws Throwable {
+        runTest("rint", input);
+    }
+
+    public static double floor(double arg) {
+        return Math.floor(arg);
+    }
+
+    @Test
+    public void runFloor() throws Throwable {
+        runTest("floor", input);
+    }
+
+    public static double ceil(double arg) {
+        return Math.ceil(arg);
+    }
+
+    @Test
+    public void runCeil() throws Throwable {
+        runTest("ceil", input);
+    }
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        ArrayList<Object[]> tests = new ArrayList<>();
+        for (int i = -3; i < 3; i++) {
+            addTest(tests, i);
+            addTest(tests, i + 0.2);
+            addTest(tests, i + 0.5);
+            addTest(tests, i + 0.7);
+        }
+        addTest(tests, -0.0);
+        addTest(tests, Double.NaN);
+        addTest(tests, Double.NEGATIVE_INFINITY);
+        addTest(tests, Double.POSITIVE_INFINITY);
+        return tests;
+    }
+
+    private static void addTest(ArrayList<Object[]> tests, double input) {
+        tests.add(new Object[]{input});
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java
new file mode 100644
index 0000000..07a1b2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_sin extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.sin(arg) * Math.sin(arg * 5);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void runFirst() throws Throwable {
+        /*
+         * Execute Double.isNaN enough times to create a profile indicating that the path returning
+         * false is never taken. Then compile and execute the test with a NaN value to test that
+         * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of
+         * course, this relies on Double.isNaN never having yet been called with NaN. if it has,
+         * this test is equivalent to run0.
+         */
+        for (int i = 0; i < 10000; i++) {
+            Double.isNaN(1D);
+        }
+        executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java
new file mode 100644
index 0000000..d8d4016
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_sqrt extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.sqrt(arg);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 4.0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1.0d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java
new file mode 100644
index 0000000..e49aeb7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Math_tan extends JTTTest {
+
+    @SuppressWarnings("serial")
+    public static class NaN extends Throwable {
+    }
+
+    public static double test(double arg) throws NaN {
+        double v = Math.tan(arg);
+        if (Double.isNaN(v)) {
+            // NaN can't be tested against itself
+            throw new NaN();
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", java.lang.Double.NaN);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", java.lang.Double.NEGATIVE_INFINITY);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", java.lang.Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -0.0d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0.0d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone01.java
new file mode 100644
index 0000000..209f6f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone01.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_clone01 extends JTTTest {
+
+    private static class TestClass {
+        @SuppressWarnings("unused")
+        private boolean tryClone(int i) throws CloneNotSupportedException {
+            return this == this.clone();
+        }
+    }
+
+    static final TestClass field = new TestClass();
+
+    public static boolean test(int i) throws CloneNotSupportedException {
+        return field.tryClone(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone02.java
new file mode 100644
index 0000000..36b63f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_clone02.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_clone02 extends JTTTest {
+
+    private static class TestClass implements Cloneable {
+        @SuppressWarnings("unused")
+        private boolean tryClone(int i) throws CloneNotSupportedException {
+            return this == this.clone();
+        }
+    }
+
+    static final TestClass field = new TestClass();
+
+    public static boolean test(int i) throws CloneNotSupportedException {
+        return field.tryClone(i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_equals01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_equals01.java
new file mode 100644
index 0000000..6c85964
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_equals01.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_equals01 extends JTTTest {
+
+    public static DummyTestClass field = new DummyTestClass();
+
+    public static boolean test(int i) {
+        final Object obj1 = new Object();
+        final Object obj2 = new Object();
+        switch (i) {
+            case 0:
+                return obj1.equals(field);
+            case 1:
+                return obj1.equals(obj2);
+            case 2:
+                return obj1.equals(null);
+            case 3:
+                return obj1.equals(obj1);
+            case 4:
+                return field.equals(field);
+            case 5:
+                return obj2.equals(field);
+            case 6:
+                return obj2.equals(obj2);
+            case 7:
+                return obj2.equals(null);
+            case 8:
+                return obj2.equals(obj1);
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_getClass01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_getClass01.java
new file mode 100644
index 0000000..a445d04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_getClass01.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_getClass01 extends JTTTest {
+
+    static final Object object = new Object();
+    static final Object string = new String();
+    static final DummyTestClass thisObject = new DummyTestClass();
+
+    public static String test(int i) {
+        if (i == 0) {
+            return object.getClass().toString();
+        }
+        if (i == 1) {
+            return string.getClass().toString();
+        }
+        if (i == 2) {
+            return thisObject.getClass().toString();
+        }
+        if (i == 3) {
+            return thisObject.getClass().getClass().toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode01.java
new file mode 100644
index 0000000..f7d4680
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode01.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_hashCode01 extends JTTTest {
+
+    public static boolean test() {
+        final Object o1 = new Object();
+        final Object o2 = new Object();
+        return o1.hashCode() != 0 || o2.hashCode() != 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode02.java
new file mode 100644
index 0000000..1829992
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_hashCode02.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.time.DayOfWeek;
+import java.util.HashMap;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_hashCode02 extends JTTTest {
+
+    public static final Object obj1 = new Object();
+    public static final Object obj2 = DayOfWeek.FRIDAY;
+    public static final Object obj3 = new HashMap<>();
+
+    public static int test(int a) {
+        if (a == 1) {
+            return obj1.hashCode();
+        }
+        if (a == 2) {
+            return obj2.hashCode();
+        }
+        return obj3.hashCode();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify01.java
new file mode 100644
index 0000000..c4ad13e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify01.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_notify01 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() {
+        object.notify();
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify02.java
new file mode 100644
index 0000000..3678034
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notify02.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_notify02 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() {
+        synchronized (object) {
+            object.notify();
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll01.java
new file mode 100644
index 0000000..28e6de8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll01.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_notifyAll01 extends JTTTest {
+
+    static final Object obj = new Object();
+
+    public static boolean test() {
+        obj.notifyAll();
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll02.java
new file mode 100644
index 0000000..3718ccc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_notifyAll02.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_notifyAll02 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() {
+        synchronized (object) {
+            object.notifyAll();
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString01.java
new file mode 100644
index 0000000..0e373c8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString01.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_toString01 extends JTTTest {
+
+    private static class TestClass {
+        @Override
+        public String toString() {
+            return string;
+        }
+    }
+
+    static final String string = "Object_toString01";
+    static final Object object = new Object();
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return object.toString() != null;
+        }
+        if (i == 1) {
+            return new TestClass().toString() == string;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString02.java
new file mode 100644
index 0000000..4dc9f46
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_toString02.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_toString02 extends JTTTest {
+
+    private static class TestClass {
+        @Override
+        public String toString() {
+            return "XYZ";
+        }
+    }
+
+    static final Object obj = new TestClass();
+
+    public static String test(int i) {
+        Object object = null;
+        if (i == 0) {
+            object = obj;
+        } else if (i == 1) {
+            object = "string";
+        } else if (i == 2) {
+            object = "string".getClass();
+        }
+        return object.toString();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait01.java
new file mode 100644
index 0000000..e8bc44c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait01.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_wait01 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() throws InterruptedException {
+        object.wait();
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait02.java
new file mode 100644
index 0000000..932e2ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait02.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_wait02 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() throws InterruptedException {
+        synchronized (object) {
+            object.wait(1);
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait03.java
new file mode 100644
index 0000000..b78da31
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Object_wait03.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Object_wait03 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() throws InterruptedException {
+        synchronized (object) {
+            object.wait(1, 1);
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ProcessEnvironment_init.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ProcessEnvironment_init.java
new file mode 100644
index 0000000..615ab6e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/ProcessEnvironment_init.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class ProcessEnvironment_init extends JTTTest {
+
+    private static HashMap<Object, Object> theEnvironment;
+    public static Map<Object, Object> theUnmodifiableEnvironment;
+
+    public static int test(int v) {
+
+        byte[][] environ = environ();
+        theEnvironment = new HashMap<>(environ.length / 2 + 3);
+
+        for (int i = environ.length - 1; i > 0; i -= 2) {
+            theEnvironment.put(Variable.valueOf(environ[i - 1]), Value.valueOf(environ[i]));
+        }
+
+        theUnmodifiableEnvironment = Collections.unmodifiableMap(new StringEnvironment(theEnvironment));
+
+        return v;
+    }
+
+    @SuppressWarnings("serial")
+    private static final class StringEnvironment extends HashMap<Object, Object> {
+
+        @SuppressWarnings("unused")
+        StringEnvironment(HashMap<Object, Object> theenvironment) {
+        }
+    }
+
+    private static final class Variable {
+
+        @SuppressWarnings("unused")
+        public static Object valueOf(byte[] bs) {
+            return new Object();
+        }
+    }
+
+    private static final class Value {
+
+        @SuppressWarnings("unused")
+        public static Object valueOf(byte[] bs) {
+            return new Object();
+        }
+    }
+
+    private static byte[][] environ() {
+        return new byte[3][3];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/StringCoding_Scale.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/StringCoding_Scale.java
new file mode 100644
index 0000000..65a87ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/StringCoding_Scale.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class StringCoding_Scale extends JTTTest {
+
+    public static float maxCharPerByte = 1.0f;
+
+    public static int test(int i) {
+        return scale(i, maxCharPerByte);
+    }
+
+    // Copy of java.lang.StringCode.scale
+    private static int scale(int len, float expansionFactor) {
+        // We need to perform double, not float, arithmetic; otherwise
+        // we lose low order bits when len is larger than 2**24.
+        return (int) (len * (double) expansionFactor);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern01.java
new file mode 100644
index 0000000..26264fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern01.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_intern01 extends JTTTest {
+
+    public static boolean test() {
+        // Checkstyle: stop
+        return "id".intern() == "id";
+        // Checkstyle: resume
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern02.java
new file mode 100644
index 0000000..d30ae27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern02.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_intern02 extends JTTTest {
+
+    public static boolean test(int i) {
+        return ("id" + i).intern() == ("id" + i).intern();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern03.java
new file mode 100644
index 0000000..53632cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_intern03.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_intern03 extends JTTTest {
+
+    public static boolean test(int i) {
+        return ("id" + i).intern().equals("id" + i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_valueOf01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_valueOf01.java
new file mode 100644
index 0000000..5fa88a7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/String_valueOf01.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_valueOf01 extends JTTTest {
+
+    public static String test(int i) {
+        Object result = null;
+        if (i == 1) {
+            result = "string";
+        }
+        return String.valueOf(result);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/System_identityHashCode01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/System_identityHashCode01.java
new file mode 100644
index 0000000..a4a1bf1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/System_identityHashCode01.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.lang;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class System_identityHashCode01 extends JTTTest {
+
+    private static final Object object0 = new Object();
+    private static final Object object1 = new Object();
+    private static final Object object2 = new Object();
+
+    private static final int hash0 = System.identityHashCode(object0);
+    private static final int hash1 = System.identityHashCode(object1);
+    private static final int hash2 = System.identityHashCode(object2);
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return hash0 == System.identityHashCode(object0);
+        }
+        if (i == 1) {
+            return hash1 == System.identityHashCode(object1);
+        }
+        if (i == 2) {
+            return hash2 == System.identityHashCode(object2);
+        }
+        if (i == 3) {
+            return 0 == System.identityHashCode(null);
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/DegeneratedLoop.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/DegeneratedLoop.java
new file mode 100644
index 0000000..79fc085
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/DegeneratedLoop.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class DegeneratedLoop extends JTTTest {
+
+    public static String test(int a) {
+        int arg = a;
+        for (;;) {
+            try {
+                arg++;
+                break;
+            } catch (Unresolved iioe) {
+            }
+        }
+        return "ok-" + arg;
+    }
+
+    @SuppressWarnings("serial")
+    public static class Unresolved extends RuntimeException {
+
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop01.java
new file mode 100644
index 0000000..51d77d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop01.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop01 extends JTTTest {
+
+    public static boolean test() {
+        int x = 1;
+
+        for (int i = 0; i < 10; i++) {
+            int y = m();
+            if (x == 1) {
+                return true;
+            }
+            x = y;
+        }
+        return false;
+    }
+
+    private static int m() {
+        return 2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop02.java
new file mode 100644
index 0000000..a15116c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop02.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop02 extends JTTTest {
+
+    public static boolean test(int arg) {
+        int x = arg;
+
+        for (int i = 0; i < 10; i++) {
+            int y = m();
+            if (x == 1) {
+                return true;
+            }
+            x = y;
+        }
+        return false;
+    }
+
+    private static int m() {
+        return 2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop03.java
new file mode 100644
index 0000000..16c2a53
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop03.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop03 extends JTTTest {
+
+    public static int test(int count) {
+        int i1 = 1;
+        int i2 = 2;
+        int i4 = 4;
+
+        for (int i = 0; i < count; i++) {
+            i1 = i2;
+            i2 = 7;
+            i4 = i1;
+        }
+        return i1 + i2 * 10 + i4 * 1000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop04.java
new file mode 100644
index 0000000..0694c8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop04.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop04 extends JTTTest {
+
+    public static int test(int count) {
+        int i1 = 1;
+        int i2 = 2;
+        int i3 = 3;
+        int i4 = 4;
+
+        for (int i = 0; i < count; i++) {
+            i1 = i2;
+            i2 = i3;
+            i3 = i4;
+            i4 = i1;
+        }
+        return i1 + i2 * 10 + i3 * 100 + i4 * 1000;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop05.java
new file mode 100644
index 0000000..5c1602b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop05.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop05 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static String test(int a) {
+        int arg = a;
+        int count = 0;
+        while (--arg > 0) {
+            count++;
+            new Object();
+        }
+        return "ok" + count;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop06.java
new file mode 100644
index 0000000..7bd5774
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop06.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop06 extends JTTTest {
+
+    public static String test(int a) {
+        int arg = a;
+        int count = 0;
+        while (--arg > 0) {
+            count++;
+            foo();
+        }
+        return "ok" + count;
+    }
+
+    static void foo() {
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07.java
new file mode 100644
index 0000000..16ed55e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Loop07 extends JTTTest {
+
+    public static String test(int arg) {
+        int count = arg;
+        for (int i = 0; i < arg; i++) {
+            count++;
+        }
+        return "ok" + count;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07_2.java
new file mode 100644
index 0000000..cb06469
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop07_2.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Loop07_2 extends JTTTest {
+
+    public static int test(int arg) {
+        int count = arg;
+        for (int i = 0; i < arg; i++) {
+            count++;
+        }
+        return count;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop08.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop08.java
new file mode 100644
index 0000000..32728ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop08.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop08 extends JTTTest {
+
+    public static int test(int arg) {
+        int a = 0;
+        for (int i = 0; i < arg; i++) {
+            a += i;
+        }
+        return a;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09.java
new file mode 100644
index 0000000..ebefb25
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop09 extends JTTTest {
+
+    private static int cnt;
+
+    public static String test(int arg) {
+        cnt = 0;
+        int count = arg;
+        for (int i = 0; i < arg; i++) {
+            count++;
+            foo();
+        }
+        return "ok" + count + "-" + cnt;
+    }
+
+    static void foo() {
+        cnt++;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09_2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09_2.java
new file mode 100644
index 0000000..11d2fa6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop09_2.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop09_2 extends JTTTest {
+
+    private static int cnt;
+
+    public static int test(int arg) {
+        cnt = 0;
+        int count = arg;
+        for (int i = 0; i < arg; i++) {
+            count++;
+            foo();
+        }
+        return count - cnt;
+    }
+
+    static void foo() {
+        cnt++;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop11.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop11.java
new file mode 100644
index 0000000..53ee8ec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop11.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop11 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        int v = 0;
+        while (arg-- > 0) {
+            v = 1;
+        }
+        return v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop12.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop12.java
new file mode 100644
index 0000000..1a09002
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop12.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop12 extends JTTTest {
+
+    private static int[] source = new int[]{10, 15, 20, 25, 30};
+
+    public static int test(int arg) {
+        int i = 0;
+        if (source[i] != arg) {
+            while (++i <= 5 && source[i] != arg) {
+                // nothing
+            }
+        }
+        return i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 15);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 30);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop13.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop13.java
new file mode 100644
index 0000000..1dbd09b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop13.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop13 extends JTTTest {
+
+    public static class Loop {
+
+        private int index;
+        private Object[] nodes = new Object[]{null, null, new Object(), null, null, new Object(), null};
+        private int size = nodes.length;
+
+        public Loop(int start) {
+            index = start;
+        }
+
+        public void test0() {
+            if (index < size) {
+                do {
+                    index++;
+                } while (index < size && nodes[index] == null);
+            }
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+    }
+
+    public static int test(int arg) {
+        Loop loop = new Loop(arg);
+        loop.test0();
+        return loop.getIndex();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop14.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop14.java
new file mode 100644
index 0000000..53c996a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop14.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Loop14 extends JTTTest {
+
+    private static int value;
+
+    public static int test(int arg) {
+        return calc(arg);
+    }
+
+    public static int calc(int arg) {
+        int result = 0;
+        for (int k = 0; k < arg; ++k) {
+            value = 5;
+            for (int i = 0; i < arg; ++i) {
+                for (int j = 0; j < arg; ++j) {
+                }
+                result += value;
+            }
+        }
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop15.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop15.java
new file mode 100644
index 0000000..f384cd5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop15.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Loop15 extends JTTTest {
+
+    public static int test(int arg) {
+        Object o = null;
+        int result = 10;
+        for (int k = 0; k < arg; ++k) {
+            if (o == null) {
+                o = new Object();
+            }
+            if (k >= 5) {
+                break;
+            }
+            result++;
+        }
+        return result + (o == null ? 0 : 1);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop16.java
new file mode 100644
index 0000000..6b25abe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop16.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests exiting 2 loops at the same time with escape-analysed values flowing out of loops
+ */
+public class Loop16 extends JTTTest {
+
+    private static class TestClass {
+        public int a;
+        public int b;
+        public int c;
+
+        public int run(int count) {
+            l1: for (int i = 0; i <= count; i++) {
+                if (i > 5) {
+                    for (int j = 0; j < i; j++) {
+                        a += i;
+                        if (a > 500) {
+                            break l1;
+                        }
+                    }
+                } else if (i > 7) {
+                    b += i;
+                } else {
+                    c += i;
+                }
+            }
+            return a + b + c;
+        }
+    }
+
+    public static int test(int count) {
+        return new TestClass().run(count);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 40);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop17.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop17.java
new file mode 100644
index 0000000..c61df7e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/Loop17.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test around an object that escapes directly from inside a loop (no virtual phi on the loop)
+ */
+public class Loop17 extends JTTTest {
+
+    private static class L {
+
+        public int a;
+        public int b;
+        public int c;
+
+        public L(int a, int b, int c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+    }
+
+    public static int test(int count) {
+        int i = 0;
+        L l;
+        do {
+            l = new L(i, i + 1, i + 2);
+        } while (++i < count);
+
+        return l.a + l.b * 10 + l.c * 100;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new L(4, 4, 4).a);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopEscape.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopEscape.java
new file mode 100644
index 0000000..9a1d679
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopEscape.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test around an object that escapes directly from inside a loop (no virtual phi on the loop)
+ */
+public class LoopEscape extends JTTTest {
+
+    public static L ll = new L(0, 1, 2);
+
+    private static class L {
+
+        public int a;
+        public int b;
+        public int c;
+
+        public L(int a, int b, int c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+    }
+
+    public static int test0(int count) {
+        L l = new L(5, 5, 5);
+        for (int i = 0; i < count; i++) {
+            l.a++;
+            l.b--;
+            l.c = 4;
+        }
+
+        return l.a + l.b * 10 + l.c * 100;
+    }
+
+    public static int test1(int count) {
+        L l = new L(5, 5, 5);
+        for (int i = 0; i < count; i++) {
+            if (l.a % 2 == 0) {
+                l.a++;
+                l.b--;
+                l.c = 4;
+            } else {
+                l.a++;
+            }
+        }
+
+        return l.a + l.b * 10 + l.c * 100;
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test1", 0);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test1", 1);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test1", 2);
+    }
+
+    @Test
+    public void run00() throws Throwable {
+        runTest("test0", 0);
+    }
+
+    @Test
+    public void run01() throws Throwable {
+        runTest("test0", 1);
+    }
+
+    @Test
+    public void run02() throws Throwable {
+        runTest("test0", 2);
+    }
+
+    @Test
+    public void run05() throws Throwable {
+        runTest("test0", 5);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopInline.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopInline.java
new file mode 100644
index 0000000..fa793bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopInline.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class LoopInline extends JTTTest {
+
+    public static int test(int arg) {
+        int count = 0;
+        for (int i = 0; i < arg; i++) {
+            count += foo(i);
+            if (count > 15) {
+                count -= foo(3);
+                break;
+            }
+        }
+        return count;
+    }
+
+    public static int foo(int t) {
+        int sum = 0;
+        for (int i = 0; i < t; i++) {
+            sum += i;
+            if (i == 4) {
+                sum += foo2(sum);
+                break;
+            }
+        }
+        return sum;
+    }
+
+    public static int foo2(int i) {
+        int j = i;
+        int sum = 0;
+        while (j > 0) {
+            sum += j * j;
+            j--;
+        }
+        return sum;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopLastIndexOf.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopLastIndexOf.java
new file mode 100644
index 0000000..3816ffa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopLastIndexOf.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * see java.lang.String.lastIndexOf(char[], int, int, char[], int ,int, int)
+ */
+public class LoopLastIndexOf extends JTTTest {
+
+    private static final char[] v1 = new char[]{'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'};
+    private static final char[] v2 = new char[]{'d', 'a'};
+    private static final char[] v3 = new char[]{'d', 'b', 'c'};
+    private static final char[] v4 = new char[]{'z', 'a', 'b', 'c'};
+
+    public static int test(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndexParam) {
+        int rightIndex = sourceCount - targetCount;
+        int fromIndex = fromIndexParam;
+        if (fromIndex < 0) {
+            return -1;
+        }
+        if (fromIndex > rightIndex) {
+            fromIndex = rightIndex;
+        }
+        /* Empty string always matches. */
+        if (targetCount == 0) {
+            return fromIndex;
+        }
+
+        int strLastIndex = targetOffset + targetCount - 1;
+        char strLastChar = target[strLastIndex];
+        int min = sourceOffset + targetCount - 1;
+        int i = min + fromIndex;
+
+        startSearchForLastChar: while (true) {
+            while (i >= min && source[i] != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - (targetCount - 1);
+            int k = strLastIndex - 1;
+
+            while (j > start) {
+                if (source[j--] != target[k--]) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start - sourceOffset + 1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", v1, 0, v1.length, v2, 0, v2.length, 10);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", v1, 0, v1.length, v3, 0, v3.length, 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", v1, 0, v1.length, v4, 0, v4.length, 10);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", v1, 1, v1.length - 1, v3, 0, v3.length, 10);
+    }
+
+    @Test
+    // (expected = ArrayIndexOutOfBoundsException.class)
+    public void run4() throws Throwable {
+        runTest("test", v1, 1, v1.length, v3, 0, v3.length, 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopNewInstance.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopNewInstance.java
new file mode 100644
index 0000000..4a73589
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopNewInstance.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class LoopNewInstance extends JTTTest {
+
+    public static Blop initBlop = new Blop();
+
+    @SuppressWarnings("unused")
+    public static int test(int arg) {
+        for (int i = 0; i < arg; i++) {
+            new Blop();
+        }
+        return count;
+    }
+
+    private static int count;
+
+    private static class Blop {
+
+        private boolean exists;
+
+        Blop() {
+            if (!exists) {
+                count++;
+            }
+            exists = true;
+        }
+    }
+
+    @Override
+    protected void before(ResolvedJavaMethod m) {
+        count = 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        count = 0;
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        count = 0;
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopParseLong.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopParseLong.java
new file mode 100644
index 0000000..53abadb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopParseLong.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class LoopParseLong extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static long testShortened(String s, int radix) throws NumberFormatException {
+        long result = 0;
+        boolean negative = false;
+        int len = s.length();
+        char firstChar = s.charAt(0);
+        if (firstChar < '0') {
+            if (firstChar == '-') {
+                negative = true;
+            } else if (firstChar != '+') {
+                throw new NumberFormatException();
+            }
+            if (len == 1) {
+                throw new NumberFormatException();
+            }
+        }
+        return result;
+    }
+
+    public static long test(String s, int radix) throws NumberFormatException {
+        if (s == null) {
+            throw new NumberFormatException("null");
+        }
+        if (radix < Character.MIN_RADIX) {
+            throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
+        }
+        if (radix > Character.MAX_RADIX) {
+            throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
+        }
+        long result = 0;
+        boolean negative = false;
+        int i = 0;
+        int len = s.length();
+        long limit = -Long.MAX_VALUE;
+        long multmin;
+        int digit;
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar < '0') {
+                if (firstChar == '-') {
+                    negative = true;
+                    limit = Long.MIN_VALUE;
+                } else if (firstChar != '+') {
+                    throw new NumberFormatException();
+                }
+                if (len == 1) {
+                    throw new NumberFormatException();
+                }
+                i++;
+            }
+            multmin = limit / radix;
+            while (i < len) {
+                digit = Character.digit(s.charAt(i++), radix);
+                if (digit < 0) {
+                    throw new NumberFormatException();
+                }
+                if (result < multmin) {
+                    throw new NumberFormatException();
+                }
+                result *= radix;
+                if (result < limit + digit) {
+                    throw new NumberFormatException();
+                }
+                result -= digit;
+            }
+        } else {
+            throw new NumberFormatException();
+        }
+        return negative ? result : -result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("testShortened", "7", 10);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("testShortened", "-100", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "7", 10);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", "-100", 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhi.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhi.java
new file mode 100644
index 0000000..697029b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhi.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+
+public class LoopPhi extends JTTTest {
+
+    public static int test(int arg) {
+        for (int i = 0; i < arg; i++) {
+            testHelper(1, 1, 1, 1, 1, 1);
+        }
+        return testHelper(1, 1, 1, 1, 1, 1);
+    }
+
+    public static int testHelper(int j1, int j2, int j3, int j4, int j5, int j6) {
+        int i1 = j1;
+        int i2 = j2;
+        int i3 = j3;
+        int i4 = j4;
+        int i5 = j5;
+        int i6 = j6;
+
+        if (i1 == 0) {
+            i1 = 2;
+        } else {
+            i2 = 2;
+        }
+        for (int i = 0; i < 10; i++) {
+            if (i == 0) {
+                i3 = 2;
+            } else {
+                i4 = 2;
+            }
+
+            for (int j = 0; j < 10; j++) {
+                if (j == 0) {
+                    i5 = 2;
+                } else {
+                    i6 = 2;
+                }
+            }
+        }
+
+        return i1 + i2 + i3 + i4 + i5 + i6;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 50000);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhiResolutionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhiResolutionTest.java
new file mode 100644
index 0000000..7fb9c28
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopPhiResolutionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class LoopPhiResolutionTest extends JTTTest {
+
+    public static int test(int count) {
+        int i1 = 1;
+        int i2 = 2;
+        int i3 = 3;
+        int i4 = 4;
+
+        for (int i = 0; i < count; i++) {
+            i1 = wormhole(i1);
+            i2 = wormhole(i2);
+            i3 = wormhole(i2);
+            i4 = wormhole(i4);
+        }
+        return i1 + i2 * 10 + i3 * 100 + i4 * 1000;
+    }
+
+    private static int wormhole(int x) {
+        return (int) GraalDirectives.opaque((long) x);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSpilling.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSpilling.java
new file mode 100644
index 0000000..4e41d0e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSpilling.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class LoopSpilling extends JTTTest {
+
+    private static final int ITERATION = 64;
+
+    /**
+     * Modification of sun.security.provider.SHA2.implCompress().
+     */
+    void test(int[] state) {
+
+        int a1 = state[0];
+        int b1 = state[1];
+        int c1 = state[2];
+        int d1 = state[3];
+        int e1 = state[4];
+        int f1 = state[5];
+        int g1 = state[6];
+        int h1 = state[7];
+
+        // 2nd
+        int a2 = state[8];
+        int b2 = state[9];
+        int c2 = state[10];
+        int d2 = state[11];
+        int e2 = state[12];
+        int f2 = state[13];
+        int g2 = state[14];
+        int h2 = state[15];
+
+        for (int i = 0; i < ITERATION; i++) {
+            h1 = g1;
+            g1 = f1;
+            f1 = e1;
+            e1 = d1;
+            d1 = c1;
+            c1 = b1;
+            b1 = a1;
+            a1 = h1;
+            // 2nd
+            h2 = g2;
+            g2 = f2;
+            f2 = e2;
+            e2 = d2;
+            d2 = c2;
+            c2 = b2;
+            b2 = a2;
+            a2 = h2;
+        }
+        state[0] += a1;
+        state[1] += b1;
+        state[2] += c1;
+        state[3] += d1;
+        state[4] += e1;
+        state[5] += f1;
+        state[6] += g1;
+        state[7] += h1;
+        // 2nd
+        state[8] += a2;
+        state[9] += b2;
+        state[10] += c2;
+        state[11] += d2;
+        state[12] += e2;
+        state[13] += f2;
+        state[14] += g2;
+        state[15] += h2;
+    }
+
+    private static final int[] INITIAL_HASHES = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+                    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", supply(() -> INITIAL_HASHES.clone()));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSwitch01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSwitch01.java
new file mode 100644
index 0000000..7da761c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopSwitch01.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class LoopSwitch01 extends JTTTest {
+
+    static int count = 0;
+
+    @SuppressWarnings("unused")
+    public static String test() {
+        String line;
+        while ((line = string()) != null) {
+            switch (line.charAt(0)) {
+                case 'a':
+                    new Object();
+                    break;
+                case 'b':
+                    new Object();
+                    break;
+                default:
+                    new Object();
+                    break;
+            }
+        }
+        return "ok" + count;
+    }
+
+    private static String string() {
+        if (count == 0) {
+            return null;
+        }
+        count--;
+        return "" + ('a' + count);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopUnroll.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopUnroll.java
new file mode 100644
index 0000000..4f781f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/LoopUnroll.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class LoopUnroll extends JTTTest {
+
+    public static int test(int input) {
+        int ret = 2;
+        int current = input;
+        for (int i = 0; i < 7; i++) {
+            ret *= 2 + current;
+            current /= 50;
+        }
+        return ret;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 42);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/SpillLoopPhiVariableAtDefinition.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/SpillLoopPhiVariableAtDefinition.java
new file mode 100644
index 0000000..453b47e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/loop/SpillLoopPhiVariableAtDefinition.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.loop;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class SpillLoopPhiVariableAtDefinition extends JTTTest {
+
+    public static int test(int arg) {
+        int count = arg;
+        for (int i = 0; i < arg; i++) {
+            GraalDirectives.bindToRegister(count);
+            GraalDirectives.spillRegisters();
+            GraalDirectives.bindToRegister(count);
+            if (i == 0) {
+                GraalDirectives.spillRegisters();
+                continue;
+            }
+            GraalDirectives.spillRegisters();
+            count++;
+        }
+        return count;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare01.java
new file mode 100644
index 0000000..36d8b1b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ArrayCompare01 extends JTTTest {
+
+    static final long[] a1 = {1, 2, 3, -5};
+    static final long[] a2 = {1, 2, 3, -5};
+    static final long[] a3 = {1, 2, 4, -5};
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return compare(a1, a2);
+        }
+        if (arg == 1) {
+            return compare(a1, a3);
+        }
+        return false;
+    }
+
+    static boolean compare(long[] a, long[] b) {
+        if (a.length == b.length) {
+            for (int i = 0; i < a.length; i++) {
+                if (a[i] != b[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare02.java
new file mode 100644
index 0000000..6495503
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ArrayCompare02.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ArrayCompare02 extends JTTTest {
+
+    static final long[] a1 = {1, 1, 1, 1, 1, 1};
+    static final long[] a2 = {1, 1, 1, 2, 1, 1};
+    static final long[] a3 = {1, 1, 2, 2, 3, 3};
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return compare(a1);
+        }
+        if (arg == 1) {
+            return compare(a2);
+        }
+        if (arg == 2) {
+            return compare(a3);
+        }
+        return false;
+    }
+
+    static boolean compare(long[] a) {
+        return a[0] == a[1] & a[2] == a[3] & a[4] == a[5];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BC_invokevirtual2.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BC_invokevirtual2.java
new file mode 100644
index 0000000..39c9448
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BC_invokevirtual2.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_invokevirtual2 extends JTTTest {
+
+    static Unresolved object;
+
+    public static class Unresolved {
+
+        public int id(int i) {
+            return i;
+        }
+    }
+
+    private static Unresolved object() {
+        if (object == null) {
+            object = new Unresolved();
+        }
+        return object;
+    }
+
+    public static int test(int a) {
+        return object().id(a);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigByteParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigByteParams01.java
new file mode 100644
index 0000000..88dce54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigByteParams01.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigByteParams01 extends JTTTest {
+
+    public static int test(int num) {
+        int sum = 0;
+        if (num == 0) {
+            sum += testA((byte) 0, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 1, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 2, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 3, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 4, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 5, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 6, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 7, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testA((byte) 8, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+        } else if (num == 1) {
+            sum += testB(0, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(1, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(2, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(3, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(4, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(5, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(6, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(7, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            sum += testB(8, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 9; i++) {
+                sum += testB(i, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 9);
+            }
+        }
+        return sum;
+    }
+
+    private static int testA(int choice, byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, byte p6, byte p7, byte p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigDoubleParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigDoubleParams02.java
new file mode 100644
index 0000000..a3b7117
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigDoubleParams02.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigDoubleParams02 extends JTTTest {
+
+    public static double test(int choice, double p0, double p1, double p2, double p3, double p4, double p5, double p6, double p7, double p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams01.java
new file mode 100644
index 0000000..b74f8b1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams01.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigFloatParams01 extends JTTTest {
+
+    public static double test(int num) {
+        double sum = 0;
+        if (num == 0) {
+            sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        } else if (num == 1) {
+            sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 9; i++) {
+                sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            }
+        }
+        return sum;
+    }
+
+    private static float testA(int choice, float p0, float p1, float p2, float p3, float p4, float p5, float p6, float p7, float p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    private static double testB(int choice, double p0, double p1, double p2, double p3, double p4, double p5, double p6, double p7, double p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams02.java
new file mode 100644
index 0000000..fb74304
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigFloatParams02.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigFloatParams02 extends JTTTest {
+
+    public static float test(int choice, float p0, float p1, float p2, float p3, float p4, float p5, float p6, float p7, float p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams01.java
new file mode 100644
index 0000000..2ea3991
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams01.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigIntParams01 extends JTTTest {
+
+    public static int test(int num) {
+        int sum = 0;
+        if (num == 0) {
+            sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        } else if (num == 1) {
+            sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 9; i++) {
+                sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            }
+        }
+        return sum;
+    }
+
+    private static int testA(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams02.java
new file mode 100644
index 0000000..d23396ec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigIntParams02.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigIntParams02 extends JTTTest {
+
+    public static int test(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, 1, 2, 3, 4, 5, 6, 7, -8, -9);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigInterfaceParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigInterfaceParams01.java
new file mode 100644
index 0000000..900134a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigInterfaceParams01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigInterfaceParams01 extends JTTTest {
+
+    public static String test(boolean b, String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+        I i = b ? new A() : new B();
+        return i.test(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+    }
+
+    interface I {
+
+        String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9);
+    }
+
+    static class A implements I {
+
+        @Override
+        public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+            return "A" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+        }
+    }
+
+    static class B implements I {
+
+        @Override
+        public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+            return "B" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", false, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigLongParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigLongParams02.java
new file mode 100644
index 0000000..c9829f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigLongParams02.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigLongParams02 extends JTTTest {
+
+    public static long test(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, 1L, 2L, 3L, 4L, 5L, 6L, 7L, -8L, -9L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams01.java
new file mode 100644
index 0000000..af64562
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams01.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigMixedParams01 extends JTTTest {
+
+    public static double test(int num) {
+        double sum = 0;
+        if (num == 0) {
+            sum += testA(0, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(1, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(2, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(3, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(4, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(5, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(6, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(7, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            sum += testA(8, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+        } else if (num == 1) {
+            sum += testB(0, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(2, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(3, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(4, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(5, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(6, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(7, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            sum += testB(8, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 9; i++) {
+                sum += testB(i, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+            }
+        }
+        return sum;
+    }
+
+    @SuppressWarnings("unused")
+    private static float testA(int choice, int i0, int i1, int i2, int i3, float p0, float p1, float p2, float p3, int i4, int i5, float p4, float p5, float p6, float p7, float p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @SuppressWarnings("unused")
+    private static double testB(int choice, int i0, int i1, int i2, double p0, double p1, double p2, double p3, int i3, int i4, double p4, double p5, double p6, double p7, double p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams02.java
new file mode 100644
index 0000000..7237e98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams02.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigMixedParams02 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static float test(int choice, int i0, int i1, int i2, int i3, float p0, float p1, float p2, float p3, int i4, int i5, float p4, float p5, float p6, float p7, float p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, -1, -1, -1, -1, 1f, 2f, 3f, 4f, -1, -1, 5f, 6f, 7f, 8f, 9f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams03.java
new file mode 100644
index 0000000..7ea6f82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams03.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigMixedParams03 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static double test(int choice, int i0, int i1, int i2, int i3, double p0, double p1, double p2, double p3, int i4, int i5, double p4, double p5, double p6, double p7, double p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8, -1, -1, -1, -1, 1d, 2d, 3d, 4d, -1, -1, 5d, 6d, 7d, 8d, 9d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams04.java
new file mode 100644
index 0000000..6d8236b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigMixedParams04.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * Tests different alignment on the stack with extended parameters (index > 5).
+ */
+public class BigMixedParams04 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static long test(int choice, int i0, int i1, int i2, int i3, double d1, double d2, boolean bo1, boolean bo2, byte by, short sh, char ch, int in) {
+        switch (choice) {
+            case 0:
+                return bo1 ? 1L : 2L;
+            case 1:
+                return bo2 ? 1L : 2L;
+            case 2:
+                return by;
+            case 3:
+                return sh;
+            case 4:
+                return ch;
+            case 5:
+                return in;
+        }
+        return 42;
+    }
+
+    /**
+     * Test SPARC mixed params with double/single float register overlapping.
+     *
+     * @param f1
+     * @param d2
+     * @param f3
+     * @return Must always return the argument d2
+     */
+    @SuppressWarnings("all")
+    public static double test2(int i1, float f1, double d2, float f3,
+// @formatter:off
+                    double ad1,
+                    double ad2,
+                    double ad3,
+                    double ad4,
+                    double ad5,
+                    double ad6,
+                    double ad7,
+                    double ad8,
+                    double ad9,
+                    double ad10,
+                    double ad11,
+                    double ad12,
+                    double ad13,
+                    double ad14,
+                    double ad15,
+                    double ad16,
+                    float  af1,
+                    float  af2,
+                    float  af3,
+                    float  af4,
+                    float  af5,
+                    float  af6,
+                    float  af7,
+                    float  af8,
+                    float  af9,
+                    float  af10,
+                    float  af11,
+                    float  af12,
+                    float  af13,
+                    float  af14,
+                    float  af15,
+                    float  af16
+    // @formatter:on
+    ) {
+
+        // now do something with the locals to make sure the locals don't get optimized away.
+        for (int i = 0; i < i1; i++) {
+            af1 += f1;
+            af2 += f1;
+            af3 += f1;
+            af4 += f1;
+            af5 += f1;
+            af6 += f1;
+            af7 += f1;
+            af8 += f1;
+            af9 += f1;
+            af10 += f1;
+            af11 += f1;
+            af12 += f1;
+            af13 += f1;
+            af14 += f1;
+            af15 += f1;
+            af16 += f1;
+            ad1 += f1;
+            ad2 += f1;
+            ad3 += f1;
+            ad4 += f1;
+            ad5 += f1;
+            ad6 += f1;
+            ad7 += f1;
+            ad8 += f1;
+            ad9 += f1;
+            ad10 += f1;
+            ad11 += f1;
+            ad12 += f1;
+            ad13 += f1;
+            ad14 += f1;
+            ad15 += f1;
+            ad16 += f1;
+        }
+        // @formatter:off
+        boolean orderFloat =
+                        af1  < af2  &&
+                        af2  < af3  &&
+                        af3  < af4  &&
+                        af4  < af5  &&
+                        af5  < af6  &&
+                        af6  < af7  &&
+                        af7  < af8  &&
+                        af8  < af9  &&
+                        af9  < af10 &&
+                        af10 < af11 &&
+                        af11 < af12 &&
+                        af12 < af13 &&
+                        af13 < af14 &&
+                        af14 < af15 &&
+                        af15 < af16;
+        boolean orderDouble =
+                        ad1  < ad2  &&
+                        ad2  < ad3  &&
+                        ad3  < ad4  &&
+                        ad4  < ad5  &&
+                        ad5  < ad6  &&
+                        ad6  < ad7  &&
+                        ad7  < ad8  &&
+                        ad8  < ad9  &&
+                        ad9  < ad10 &&
+                        ad10 < ad11 &&
+                        ad11 < ad12 &&
+                        ad12 < ad13 &&
+                        ad13 < ad14 &&
+                        ad14 < ad15 &&
+                        ad15 < ad16;
+        // @formatter:on
+        if (orderDouble && orderFloat) {
+            return f1 + d2 + f3; // this should not be destroyed
+        }
+        Assert.fail();
+        return 0.0;
+    }
+
+    /**
+     * Test SPARC mixed params with double/single float register overlapping.
+     *
+     * @param f1
+     * @param d2
+     * @param f3
+     * @return Must always return the argument d2
+     */
+    @SuppressWarnings("all")
+    public static double test3(boolean f, int idx,
+// @formatter:off
+                    double ad1,
+                    double ad2,
+                    double ad3,
+                    double ad4,
+                    double ad5,
+                    double ad6,
+                    double ad7,
+                    double ad8,
+                    double ad9,
+                    double ad10,
+                    double ad11,
+                    double ad12,
+                    double ad13,
+                    double ad14,
+                    double ad15,
+                    double ad16,
+                    float  af1,
+                    float  af2,
+                    float  af3,
+                    float  af4,
+                    float  af5,
+                    float  af6,
+                    float  af7,
+                    float  af8,
+                    float  af9,
+                    float  af10,
+                    float  af11,
+                    float  af12,
+                    float  af13,
+                    float  af14,
+                    float  af15,
+                    float  af16
+    ) {
+        switch(f ? idx + 16 : idx) {
+            case 1 : return ad1;
+            case 2 : return ad2;
+            case 3 : return ad3;
+            case 4 : return ad4;
+            case 5 : return ad5;
+            case 6 : return ad6;
+            case 7 : return ad7;
+            case 8 : return ad8;
+            case 9 : return ad9;
+            case 10: return ad10;
+            case 11: return ad11;
+            case 12: return ad12;
+            case 13: return ad13;
+            case 14: return ad14;
+            case 15: return ad15;
+            case 16: return ad16;
+            case 1  + 16: return af1;
+            case 2  + 16: return af2;
+            case 3  + 16: return af3;
+            case 4  + 16: return af4;
+            case 5  + 16: return af5;
+            case 6  + 16: return af6;
+            case 7  + 16: return af7;
+            case 8  + 16: return af8;
+            case 9  + 16: return af9;
+            case 10 + 16: return af10;
+            case 11 + 16: return af11;
+            case 12 + 16: return af12;
+            case 13 + 16: return af13;
+            case 14 + 16: return af14;
+            case 15 + 16: return af15;
+            case 16 + 16: return af16;
+        }
+        Assert.fail(); // should not reach here
+        return 0;
+
+    }
+    // @formatter:on
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        // @formatter:off
+        runTest("test2", 20, 1.0f, -3.2912948246387967943231233d, 3.0f,
+                        1d,
+                        2d,
+                        3d,
+                        4d,
+                        5d,
+                        6d,
+                        7d,
+                        8d,
+                        9d,
+                        10d,
+                        11d,
+                        12d,
+                        13d,
+                        14d,
+                        15d,
+                        16d,
+                        1f,
+                        2f,
+                        3f,
+                        4f,
+                        5f,
+                        6f,
+                        7f,
+                        8f,
+                        9f,
+                        10f,
+                        11f,
+                        12f,
+                        13f,
+                        14f,
+                        15f,
+                        16f
+                        );
+        // @formatter:on
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        // @formatter:off
+        for (int i = 0; i < 32 * 2; i++) {
+        runTest("test3", i % 2 == 0, i / 2,
+                        1d,
+                        2d,
+                        3d,
+                        4d,
+                        5d,
+                        6d,
+                        7d,
+                        8d,
+                        9d,
+                        10d,
+                        11d,
+                        12d,
+                        13d,
+                        14d,
+                        15d,
+                        16d,
+                        1f,
+                        2f,
+                        3f,
+                        4f,
+                        5f,
+                        6f,
+                        7f,
+                        8f,
+                        9f,
+                        10f,
+                        11f,
+                        12f,
+                        13f,
+                        14f,
+                        15f,
+                        16f
+                        );
+        }
+        // @formatter:on
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams01.java
new file mode 100644
index 0000000..05611a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams01.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigObjectParams01 extends JTTTest {
+
+    @SuppressWarnings("unused")
+    public static String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+        return p0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "a", null, null, null, null, null, null, null, null, null);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams02.java
new file mode 100644
index 0000000..f6fbdf1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigObjectParams02.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigObjectParams02 extends JTTTest {
+
+    public static String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+        return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigParamsAlignment.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigParamsAlignment.java
new file mode 100644
index 0000000..5903c02
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigParamsAlignment.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BigParamsAlignment extends JTTTest {
+
+    public static int test(int num) {
+        int sum = 0;
+        if (num == 0) {
+            sum += testA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(4, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(5, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(6, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(7, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            sum += testA(8, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        } else if (num == 1) {
+            sum += testB(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(7, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            sum += testB(9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 10; i++) {
+                sum += testB(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+            }
+        } else if (num == 4) {
+            for (int i = 0; i < 11; i++) {
+                sum += testC(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+            }
+        } else if (num == 5) {
+            for (int i = 0; i < 12; i++) {
+                sum += testD(i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+            }
+        }
+        return sum;
+    }
+
+    private static int testA(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    private static int testB(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+            case 9:
+                return p9;
+        }
+        return 42;
+    }
+
+    private static int testC(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+            case 9:
+                return p9;
+            case 10:
+                return p10;
+        }
+        return 42;
+    }
+
+    private static int testD(int choice, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+            case 9:
+                return p9;
+            case 10:
+                return p10;
+            case 11:
+                return p11;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigShortParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigShortParams01.java
new file mode 100644
index 0000000..02c0241
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigShortParams01.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigShortParams01 extends JTTTest {
+
+    public static int test(int num) {
+        int sum = 0;
+        if (num == 0) {
+            sum += testA((short) 0, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 1, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 2, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 3, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 4, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 5, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 6, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 7, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testA((short) 8, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+        } else if (num == 1) {
+            sum += testB(0, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(1, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(2, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(3, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(4, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(5, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(6, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(7, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            sum += testB(8, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+        } else if (num == 2) {
+            for (int i = 0; i < 9; i++) {
+                sum += testA(i, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            }
+        } else if (num == 3) {
+            for (int i = 0; i < 9; i++) {
+                sum += testB(i, (short) 1, (short) 2, (short) 3, (short) 4, (short) 5, (short) 6, (short) 7, (short) 8, (short) 9);
+            }
+        }
+        return sum;
+    }
+
+    private static int testA(int choice, short p0, short p1, short p2, short p3, short p4, short p5, short p6, short p7, short p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    private static long testB(int choice, long p0, long p1, long p2, long p3, long p4, long p5, long p6, long p7, long p8) {
+        switch (choice) {
+            case 0:
+                return p0;
+            case 1:
+                return p1;
+            case 2:
+                return p2;
+            case 3:
+                return p3;
+            case 4:
+                return p4;
+            case 5:
+                return p5;
+            case 6:
+                return p6;
+            case 7:
+                return p7;
+            case 8:
+                return p8;
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigVirtualParams01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigVirtualParams01.java
new file mode 100644
index 0000000..c9e1ecf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/BigVirtualParams01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BigVirtualParams01 extends JTTTest {
+
+    public static String test(boolean b, String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+        I i = b ? new A() : new B();
+        return i.test(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+    }
+
+    abstract static class I {
+
+        abstract String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9);
+    }
+
+    static class A extends I {
+
+        @Override
+        public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+            return "A" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+        }
+    }
+
+    static class B extends I {
+
+        @Override
+        public String test(String p0, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) {
+            return "B" + p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", true, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", false, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Bubblesort.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Bubblesort.java
new file mode 100644
index 0000000..f8228d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Bubblesort.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Bubblesort extends JTTTest {
+
+    public static int test(int num) {
+        final int[] array = {23, 8, -9, 5, 882, 0, 0, 1};
+
+        for (int i = 0; i < array.length; i++) {
+            for (int j = i + 1; j < array.length; j++) {
+                if (array[j] < array[i]) {
+                    final int tmp = array[i];
+                    array[i] = array[j];
+                    array[j] = tmp;
+                }
+            }
+        }
+        return array[num];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ConstantLoadTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ConstantLoadTest.java
new file mode 100644
index 0000000..d9bcc11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ConstantLoadTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class ConstantLoadTest extends JTTTest {
+
+    private static final class MyClass {
+        public long a;
+        public long b;
+
+        MyClass(long a, long b) {
+            this.a = a;
+            this.b = b;
+        }
+    }
+
+    private static final MyClass myClass = new MyClass(Long.MIN_VALUE, Long.MAX_VALUE);
+    private static final long myLong = Long.MAX_VALUE;
+
+    public static long test(int arg) {
+        if (arg == 0) {
+            return myClass.a / arg + myLong;
+        }
+        if (arg == 1) {
+            return myClass.b - arg + myLong;
+        }
+        long r = 1;
+        for (int i = 0; i < arg; i++) {
+            r *= i;
+        }
+        return r;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Fibonacci.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Fibonacci.java
new file mode 100644
index 0000000..036e366
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Fibonacci.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Fibonacci extends JTTTest {
+
+    public static int test(int num) {
+        if (num <= 0) {
+            return 0;
+        }
+        int n1 = 0;
+        int n2 = 1;
+        for (int i = 1; i < num; i++) {
+            final int next = n2 + n1;
+            n1 = n2;
+            n2 = next;
+        }
+        return n2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/FloatingReads.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/FloatingReads.java
new file mode 100644
index 0000000..31bb6f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/FloatingReads.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class FloatingReads extends JTTTest {
+
+    public static long init = Runtime.getRuntime().totalMemory();
+    private final int f = 10;
+    private int a;
+    private int b;
+    private int c;
+
+    public int test(int d) {
+        a = 3;
+        b = 5;
+        c = 7;
+        for (int i = 0; i < d; i++) {
+            if (i % 2 == 0) {
+                a += b;
+            }
+            if (i % 4 == 0) {
+                b += c;
+            } else if (i % 3 == 0) {
+                b -= a;
+            }
+            if (i % 5 == 0) {
+                for (int j = 0; j < i; j++) {
+                    c += a;
+                }
+                a -= f;
+            }
+            b = a ^ c;
+            if (i % 6 == 0) {
+                c--;
+            } else if (i % 7 == 0) {
+                Runtime.getRuntime().totalMemory();
+            }
+        }
+        return a + b + c;
+    }
+
+    @Test
+    public void run0() {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test", 1000);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run3() {
+        runTest("test", 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_01.java
new file mode 100644
index 0000000..d9264bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_01.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class InvokeInterface_01 extends JTTTest {
+
+    interface I {
+
+        int plus(int a);
+    }
+
+    abstract static class A implements I {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C1 extends A {
+    }
+
+    static class C2 extends A {
+    }
+
+    static class C3 extends A {
+    }
+
+    static class C4 extends A {
+    }
+
+    static class C5 extends A {
+    }
+
+    static class C6 extends A {
+    }
+
+    static class C7 extends A {
+    }
+
+    static class C8 extends A {
+    }
+
+    static class C9 extends A {
+    }
+
+    static class C10 extends A {
+    }
+
+    static class C11 extends A {
+    }
+
+    static class C12 extends A {
+    }
+
+    static class C13 extends A {
+    }
+
+    static class C14 extends A {
+    }
+
+    static class C15 extends A {
+    }
+
+    public static int test(I i, int a) {
+        return i.plus(a);
+    }
+
+    @Before
+    public void setUp() {
+        I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()};
+        int a = 0;
+        for (I i : x) {
+            i.plus(a++);
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new C1(), 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new C2(), 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_02.java
new file mode 100644
index 0000000..b3f9ce1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_02.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class InvokeInterface_02 extends JTTTest {
+
+    interface I {
+
+        int plus(int a);
+    }
+
+    static class A implements I {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C1 extends A {
+    }
+
+    static class C2 extends A {
+    }
+
+    static class C3 extends A {
+    }
+
+    static class C4 extends A {
+    }
+
+    static class C5 extends A {
+    }
+
+    static class C6 extends A {
+    }
+
+    static class C7 extends A {
+    }
+
+    static class C8 extends A {
+    }
+
+    static class C9 extends A {
+    }
+
+    static class C10 extends A {
+    }
+
+    static class C11 extends A {
+    }
+
+    static class C12 extends A {
+    }
+
+    static class C13 extends A {
+    }
+
+    static class C14 extends A {
+    }
+
+    static class C15 extends A {
+    }
+
+    public static int test(I i, int a) {
+        return i.plus(a);
+    }
+
+    @Before
+    public void setUp() {
+        I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()};
+        int a = 0;
+        for (I i : x) {
+            i.plus(a++);
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new C1(), 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new C2(), 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_03.java
new file mode 100644
index 0000000..4878399
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_03.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class InvokeInterface_03 extends JTTTest {
+
+    interface I {
+
+        int plus(int a);
+    }
+
+    abstract static class A implements I {
+    }
+
+    static class C1 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C2 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C3 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C4 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C5 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C6 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C7 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C8 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C9 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C10 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C11 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C12 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C13 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C14 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C15 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    public static int test(I i, int a) {
+        return i.plus(a);
+    }
+
+    @Before
+    public void setUp() {
+        I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()};
+        int a = 0;
+        for (I i : x) {
+            i.plus(a++);
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new C1(), 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new C2(), 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_04.java
new file mode 100644
index 0000000..e165a71
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeInterface_04.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class InvokeInterface_04 extends JTTTest {
+
+    interface I {
+
+        int plus(int a);
+    }
+
+    abstract static class A implements I {
+        @Override
+        public abstract int plus(int a);
+    }
+
+    static class C1 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C2 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C3 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C4 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C5 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C6 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C7 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C8 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C9 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C10 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C11 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C12 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C13 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C14 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    static class C15 extends A {
+
+        @Override
+        public int plus(int a) {
+            return a;
+        }
+    }
+
+    public static int test(I i, int a) {
+        return i.plus(a);
+    }
+
+    @Before
+    public void setUp() {
+        I[] x = new I[]{new C1(), new C2(), new C3(), new C4(), new C5(), new C6(), new C7(), new C8(), new C9(), new C10(), new C11(), new C12(), new C13(), new C14(), new C15()};
+        int a = 0;
+        for (I i : x) {
+            i.plus(a++);
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new C1(), 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new C2(), 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_01.java
new file mode 100644
index 0000000..42b675f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_01.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class InvokeVirtual_01 extends JTTTest {
+
+    static class A {
+
+        int plus(int a) {
+            return a;
+        }
+    }
+
+    static class B extends A {
+
+        @Override
+        int plus(int a) {
+            return a + 10;
+        }
+    }
+
+    static class C extends A {
+
+        @Override
+        int plus(int a) {
+            return a + 20;
+        }
+    }
+
+    static A aObject = new A();
+    static A bObject = new B();
+    static A cObject = new C();
+
+    public static int test(int a) {
+        if (a == 0) {
+            return aObject.plus(a);
+        }
+        if (a == 1) {
+            return bObject.plus(a);
+        }
+        if (a == 2) {
+            return cObject.plus(a);
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_02.java
new file mode 100644
index 0000000..51e69ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/InvokeVirtual_02.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class InvokeVirtual_02 extends JTTTest {
+
+    static class A {
+
+        long plus(long a) {
+            return a;
+        }
+    }
+
+    static class B extends A {
+
+        @Override
+        long plus(long a) {
+            return a + 10;
+        }
+    }
+
+    static class C extends A {
+
+        @Override
+        long plus(long a) {
+            return a + 20;
+        }
+    }
+
+    static A objectA = new A();
+    static A objectB = new B();
+    static A objectC = new C();
+
+    public static long test(long a) {
+        if (a == 0) {
+            return objectA.plus(a);
+        }
+        if (a == 1) {
+            return objectB.plus(a);
+        }
+        if (a == 2) {
+            return objectC.plus(a);
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Matrix01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Matrix01.java
new file mode 100644
index 0000000..e098649
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/Matrix01.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Matrix01 extends JTTTest {
+
+    public static class Matrix {
+
+        final int id;
+
+        Matrix(int id) {
+            this.id = id;
+        }
+    }
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return matrix1(3) + matrix1(5);
+        }
+        if (arg == 1) {
+            return matrix2(3) + matrix2(5);
+        }
+        if (arg == 2) {
+            return matrix3(3) + matrix3(5);
+        }
+        if (arg == 3) {
+            return matrix4(3) + matrix4(5);
+        }
+        if (arg == 4) {
+            return matrix5(3) + matrix5(5);
+        }
+        return 42;
+    }
+
+    static int matrix1(int size) {
+        Matrix[] matrix = new Matrix[size];
+        fillMatrix(matrix, size);
+        int count = 0;
+        for (Matrix m : matrix) {
+            if (m != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    static int matrix2(int size) {
+        Matrix[][] matrix = new Matrix[size][size];
+        fillMatrix(matrix, size * size);
+        int count = 0;
+        for (Matrix[] n : matrix) {
+            for (Matrix m : n) {
+                if (m != null) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+
+    static int matrix3(int size) {
+        Matrix[][][] matrix = new Matrix[size][5][size];
+        fillMatrix(matrix, size * size * size);
+        int count = 0;
+        for (Matrix[][] o : matrix) {
+            for (Matrix[] n : o) {
+                for (Matrix m : n) {
+                    if (m != null) {
+                        count++;
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    static int matrix4(int size) {
+        Matrix[][][][] matrix = new Matrix[size][2][size][3];
+        fillMatrix(matrix, size * size * size * size);
+        int count = 0;
+        for (Matrix[][][] p : matrix) {
+            for (Matrix[][] o : p) {
+                for (Matrix[] n : o) {
+                    for (Matrix m : n) {
+                        if (m != null) {
+                            count++;
+                        }
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    static int matrix5(int size) {
+        Matrix[][][][][] matrix = new Matrix[size][size][3][4][size];
+        fillMatrix(matrix, size * size * size * size * size);
+        int count = 0;
+        for (Matrix[][][][] q : matrix) {
+            for (Matrix[][][] p : q) {
+                for (Matrix[][] o : p) {
+                    for (Matrix[] n : o) {
+                        for (Matrix m : n) {
+                            if (m != null) {
+                                count++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    static void fillMatrix(Object[] matrix, int total) {
+        for (int i = 0; i < 10000; i += 7) {
+            int number = i % total;
+            set(matrix, number);
+        }
+    }
+
+    static void set(Object[] matrix, int number) {
+        int val = number;
+        Object[] array = matrix;
+        while (!(array instanceof Matrix[])) {
+            int index = val % array.length;
+            val = val / array.length;
+            array = (Object[]) array[index];
+        }
+        ((Matrix[]) array)[val % array.length] = new Matrix(number);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ReferenceMap01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ReferenceMap01.java
new file mode 100644
index 0000000..ec7e591
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/ReferenceMap01.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ReferenceMap01 extends JTTTest {
+
+    public static Integer val1 = new Integer(3);
+    public static Integer val2 = new Integer(4);
+
+    @SuppressWarnings("unused")
+    private static String foo(String[] a) {
+        String[] args = new String[]{"78"};
+        Integer i1 = new Integer(1);
+        Integer i2 = new Integer(2);
+        Integer i3 = val1;
+        Integer i4 = val2;
+        Integer i5 = new Integer(5);
+        Integer i6 = new Integer(6);
+        Integer i7 = new Integer(7);
+        Integer i8 = new Integer(8);
+        Integer i9 = new Integer(9);
+        Integer i10 = new Integer(10);
+        Integer i11 = new Integer(11);
+        Integer i12 = new Integer(12);
+
+        System.gc();
+        int sum = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12;
+        return args[0] + sum;
+    }
+
+    public static int test() {
+        return Integer.valueOf(foo(new String[]{"asdf"}));
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/StrangeFrames.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/StrangeFrames.java
new file mode 100644
index 0000000..fa5432e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/StrangeFrames.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+@SuppressWarnings("unused")
+public class StrangeFrames extends JTTTest {
+
+    public static boolean test(int arg) {
+        empty();
+        oneOperandStackSlot();
+        twoOperandStackSlots();
+        oneLocalSlot();
+        return true;
+    }
+
+    static void empty() {
+        // do nothing.
+    }
+
+    static void oneOperandStackSlot() {
+        new DummyTestClass();
+    }
+
+    static void twoOperandStackSlots() {
+        two(new DummyTestClass(), new DummyTestClass());
+    }
+
+    static void oneLocalSlot() {
+        int a;
+    }
+
+    static void two(Object a, Object b) {
+        Object c = b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format01.java
new file mode 100644
index 0000000..057e44b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format01.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_format01 extends JTTTest {
+
+    public static String test(String s) {
+        return String.format("Hello %s", s);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "World");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "New World Order");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format02.java
new file mode 100644
index 0000000..f66de66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/String_format02.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class String_format02 extends JTTTest {
+
+    public static String test(int val) {
+        return String.format("Hello %d", val);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -11);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -2147483648);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 2147483647);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_String01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_String01.java
new file mode 100644
index 0000000..1ad5ba2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_String01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_String01 extends JTTTest {
+
+    public static String test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, "a", null, "test");
+    }
+
+    private static String get(int index, String... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_Unroll.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_Unroll.java
new file mode 100644
index 0000000..6cccfde
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_Unroll.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_Unroll extends JTTTest {
+
+    public static boolean test(String a, String b) {
+        return check(a, b);
+    }
+
+    private static boolean check(String... args) {
+        if (args.length == 0) {
+            return true;
+        }
+        String s = args[0];
+        for (String t : args) {
+            if (!t.equals(s)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "ab", "ab");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "ab", "abc");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_boolean01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_boolean01.java
new file mode 100644
index 0000000..92c2d4d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_boolean01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_boolean01 extends JTTTest {
+
+    public static boolean test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, true, false, true);
+    }
+
+    private static boolean get(int index, boolean... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_byte01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_byte01.java
new file mode 100644
index 0000000..ff2f809
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_byte01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_byte01 extends JTTTest {
+
+    public static byte test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, (byte) 1, (byte) 2, (byte) 3);
+    }
+
+    private static byte get(int index, byte... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_char01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_char01.java
new file mode 100644
index 0000000..d615a95
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_char01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_char01 extends JTTTest {
+
+    public static char test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, 'a', 'b', 'c');
+    }
+
+    private static char get(int index, char... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_double01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_double01.java
new file mode 100644
index 0000000..0b08a0a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_double01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_double01 extends JTTTest {
+
+    public static double test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, 0.0d, 1.0d, 2.0d);
+    }
+
+    private static double get(int index, double... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_float01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_float01.java
new file mode 100644
index 0000000..b8ea82b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_float01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_float01 extends JTTTest {
+
+    public static float test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, 0.0f, 1.0f, 2.0f);
+    }
+
+    private static float get(int index, float... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_int01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_int01.java
new file mode 100644
index 0000000..c3a69b6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_int01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_int01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, 0, 1, 2);
+    }
+
+    private static int get(int index, int... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_long01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_long01.java
new file mode 100644
index 0000000..fde4fdd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_long01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_long01 extends JTTTest {
+
+    public static long test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, 0L, 1L, 2L);
+    }
+
+    private static long get(int index, long... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_short01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_short01.java
new file mode 100644
index 0000000..326744c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/micro/VarArgs_short01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.micro;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class VarArgs_short01 extends JTTTest {
+
+    public static short test(int arg) {
+        if (arg == 4) {
+            return get(0);
+        }
+        return get(arg, (short) 0, (short) 1, (short) 2);
+    }
+
+    private static short get(int index, short... args) {
+        return args[index];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_01.java
new file mode 100644
index 0000000..eae896c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_01.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ABCE_01 extends JTTTest {
+
+    public static int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+    public static int test(int a) {
+        int arg = a;
+        for (int i = 0; i < array.length; i++) {
+            arg += array[i];
+        }
+        return arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_02.java
new file mode 100644
index 0000000..56390cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_02.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ABCE_02 extends JTTTest {
+
+    public static int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+    public static int test(int arg) {
+        int r = 0;
+        for (int i = 0; i < arg; i++) {
+            r += array[i];
+        }
+        return r;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_03.java
new file mode 100644
index 0000000..6c42871
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ABCE_03.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ABCE_03 extends JTTTest {
+
+    private static final int[] ARRAY1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    private static final int[] ARRAY2 = new int[]{1};
+
+    public static int test(int arg) {
+        int[] array = arg == 0 ? ARRAY2 : ARRAY1;
+        int r = 0;
+        for (int i = 0; i < arg; i++) {
+            r += array[i];
+        }
+        return r;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 20);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy01.java
new file mode 100644
index 0000000..9e39d05
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy01 extends JTTTest {
+
+    public static Object[] src = new Object[]{null, null};
+    public static Object[] dest = new Object[]{null, null};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(src, 0, src, 0, src.length);
+    }
+
+    public static int test(int srcPos, int destPos, int length) {
+        System.arraycopy(src, srcPos, dest, destPos, length);
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy02.java
new file mode 100644
index 0000000..ec87472
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy02.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy02 extends JTTTest {
+
+    public static int[] src = new int[]{0, 1, 2, 3, 4, 5};
+    public static int[] dest0 = new int[]{5, 4, 3, 2, 1, 0};
+    public static int[] dest = new int[]{5, 4, 3, 2, 1, 0};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(src, 0, src, 0, src.length);
+    }
+
+    @Before
+    public void setUp() {
+        System.currentTimeMillis();
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = dest0[i];
+        }
+    }
+
+    public static int[] test(int srcPos, int destPos, int length) {
+        System.arraycopy(src, srcPos, dest, destPos, length);
+        return dest;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 6);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 0, 0, 6);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 0, 1, 5);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, 0, 5);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 1, 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy03.java
new file mode 100644
index 0000000..1ee1f9d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy03.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy03 extends JTTTest {
+
+    public static byte[] src = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    public static byte[] dest0 = new byte[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+    public static byte[] dest = new byte[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(src, 0, src, 0, src.length);
+    }
+
+    @Before
+    public void setUp() {
+        System.currentTimeMillis();
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = dest0[i];
+        }
+    }
+
+    public static byte[] test(int srcPos, int destPos, int length) {
+        System.arraycopy(src, srcPos, dest, destPos, length);
+        return dest;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 11);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 11);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 0, 0, 6);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 0, 1, 5);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, 0, 5);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 1, 5);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 0, 0, 11);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy04.java
new file mode 100644
index 0000000..d3582be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy04.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy04 extends JTTTest {
+
+    public static byte[] array = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    public static byte[] array0 = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(array, 0, array, 0, array.length);
+    }
+
+    @Before
+    public void setUp() {
+        System.currentTimeMillis();
+        for (int i = 0; i < array.length; i++) {
+            array[i] = array0[i];
+        }
+    }
+
+    public static byte[] test(int srcPos, int destPos, int length) {
+        System.arraycopy(array, srcPos, array, destPos, length);
+        return array;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 11);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 11);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 0, 0, 6);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 0, 1, 5);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, 0, 5);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 1, 5);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 0, 0, 11);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 0, 1, 10);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", 1, 0, 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy05.java
new file mode 100644
index 0000000..a9794e5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy05.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy05 extends JTTTest {
+
+    public static char[] array = new char[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    public static char[] array0 = new char[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(array, 0, array, 0, array.length);
+    }
+
+    @Before
+    public void setUp() {
+        System.currentTimeMillis();
+        for (int i = 0; i < array.length; i++) {
+            array[i] = array0[i];
+        }
+    }
+
+    public static char[] test(int srcPos, int destPos, int length) {
+        System.arraycopy(array, srcPos, array, destPos, length);
+        return array;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 11);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 11);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 0, 0, 6);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 0, 1, 5);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, 0, 5);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 1, 5);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 0, 0, 11);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 0, 1, 10);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", 1, 0, 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy06.java
new file mode 100644
index 0000000..058d5af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopy06.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopy06 extends JTTTest {
+
+    public static short[] array = new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    public static short[] array0 = new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    static {
+        // Ensure System is resolved
+        System.arraycopy(array, 0, array, 0, array.length);
+    }
+
+    @Before
+    public void setUp() {
+        System.currentTimeMillis();
+        for (int i = 0; i < array.length; i++) {
+            array[i] = array0[i];
+        }
+    }
+
+    public static short[] test(int srcPos, int destPos, int length) {
+        System.arraycopy(array, srcPos, array, destPos, length);
+        return array;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 0, -1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -1, 0, 0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1, 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, 0, 2);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 1, 11);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 1, 0, 11);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 1, -1);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 0, 1, 2);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 0, 2);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 1, 2);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 0, 0, 6);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 0, 1, 5);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, 0, 5);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 1, 5);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 0, 0, 11);
+    }
+
+    @Test
+    public void run16() throws Throwable {
+        runTest("test", 0, 1, 10);
+    }
+
+    @Test
+    public void run17() throws Throwable {
+        runTest("test", 1, 0, 10);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopyGeneric.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopyGeneric.java
new file mode 100644
index 0000000..ae31c8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayCopyGeneric.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopyGeneric extends JTTTest {
+
+    public Object[] arraysFrom;
+    public Object[] arraysTo;
+
+    public void init() {
+        arraysFrom = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+        arraysTo = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+    }
+
+    public Object test() {
+        init();
+
+        for (int i = 0; i < arraysFrom.length; i++) {
+            Object from = arraysFrom[i];
+            Object to = arraysTo[i];
+            System.arraycopy(from, 1, to, 2, 2);
+            System.arraycopy(from, 8, to, 7, 2);
+        }
+        return arraysTo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayLength01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayLength01.java
new file mode 100644
index 0000000..ad9b278
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ArrayLength01.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of array length operations.
+ */
+public class ArrayLength01 extends JTTTest {
+
+    public static final int SIZE = 8;
+    public static final byte[] arr = new byte[5];
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return arr.length;
+        }
+        if (arg == 1) {
+            return new byte[6].length;
+        }
+        if (arg == 2) {
+            return new Object[7].length;
+        }
+        if (arg == 3) {
+            return new Class<?>[SIZE][].length;
+        }
+        if (arg == 4) {
+            return new int[arg].length;
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_16.java
new file mode 100644
index 0000000..e16bc00
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_16.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_idiv_16 extends JTTTest {
+
+    public static int test(int i, int arg) {
+        if (i == 0) {
+            final int constant = 16;
+            return arg / constant;
+        }
+        return arg / 16;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 16);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 17);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, -16);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, -17);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 0, -1024);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 1, 16);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 17);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 1, -16);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 1, -17);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, -1024);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_4.java
new file mode 100644
index 0000000..216a28d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_idiv_4.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_idiv_4 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg / 4;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -256);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_16.java
new file mode 100644
index 0000000..092e883
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_16.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_imul_16 extends JTTTest {
+
+    public static int test(int i, int arg) {
+        if (i == 0) {
+            final int mult = 16;
+            return arg * mult;
+        }
+        return arg * 16;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 16);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 17);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 0, -16);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, -17);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 0, 2147483647);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 0, -2147483648);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 1, 16);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 1, 17);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 1, -16);
+    }
+
+    @Test
+    public void run13() throws Throwable {
+        runTest("test", 1, -17);
+    }
+
+    @Test
+    public void run14() throws Throwable {
+        runTest("test", 1, 2147483647);
+    }
+
+    @Test
+    public void run15() throws Throwable {
+        runTest("test", 1, -2147483648);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_4.java
new file mode 100644
index 0000000..33b0dda
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_imul_4.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_imul_4 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg * 4;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -256);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_16.java
new file mode 100644
index 0000000..db69027
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_16.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldiv_16 extends JTTTest {
+
+    public static long test(long arg) {
+        return arg / 16;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 16L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 17L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -16L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -17L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -1024L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_4.java
new file mode 100644
index 0000000..3ad7199
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_ldiv_4.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_ldiv_4 extends JTTTest {
+
+    public static long test(long arg) {
+        return arg / 4;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -256L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_16.java
new file mode 100644
index 0000000..e5d680b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_16.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lmul_16 extends JTTTest {
+
+    public static long test(long arg) {
+        return arg * 16;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 16L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 17L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -16L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -17L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -1024L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_4.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_4.java
new file mode 100644
index 0000000..cf31ea0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lmul_4.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lmul_4 extends JTTTest {
+
+    public static long test(long arg) {
+        return arg * 4;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", -256L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C16.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C16.java
new file mode 100644
index 0000000..817d6b9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C16.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshr_C16 extends JTTTest {
+
+    public static long test(long a) {
+        return a >> 16;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 87224824140L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C24.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C24.java
new file mode 100644
index 0000000..45823b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C24.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshr_C24 extends JTTTest {
+
+    public static long test(long a) {
+        return a >> 24;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 87224824140L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C32.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C32.java
new file mode 100644
index 0000000..35b6303
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BC_lshr_C32.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BC_lshr_C32 extends JTTTest {
+
+    public static long test(long a) {
+        return a >> 32;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 87224824140L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BlockSkip01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BlockSkip01.java
new file mode 100644
index 0000000..9c60cf4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BlockSkip01.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class BlockSkip01 extends JTTTest {
+
+    public static boolean test(int arg) {
+        int x = 1;
+
+        if (arg > 2) {
+            x = 2;
+        } else {
+            x = 1;
+        }
+        return m(x) == 2;
+    }
+
+    private static int m(int x) {
+        return x + 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BoxingIdentity.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BoxingIdentity.java
new file mode 100644
index 0000000..ee4dc40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/BoxingIdentity.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BoxingIdentity extends JTTTest {
+    interface ArrayMirror {
+        Object get(int i);
+    }
+
+    static class IntArray implements ArrayMirror {
+        final int[] array;
+
+        IntArray() {
+            this.array = new int[8];
+        }
+
+        @Override
+        public Object get(int i) {
+            return array[i];
+        }
+    }
+
+    public int testIntArray(Object m) {
+        ArrayMirror a = new IntArray();
+        if (a.get(0) != m) {
+            return 42;
+        }
+        return 41;
+    }
+
+    @Test
+    public void runIntArray() {
+        runTest("testIntArray", 0);
+        runTest("testIntArray", 1);
+    }
+
+    public boolean isTrue(Object obj) {
+        return obj == Boolean.valueOf(true);
+    }
+
+    @Test
+    public void runIsTrue() {
+        runTest("isTrue", true);
+        runTest("isTrue", false);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov01.java
new file mode 100644
index 0000000..872ed4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov01.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Cmov01 extends JTTTest {
+
+    public static boolean test(int a, int b) {
+        boolean result = a < b || a == b;
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1, -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov02.java
new file mode 100644
index 0000000..5898e6e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Cmov02.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Cmov02 extends JTTTest {
+
+    public static int test(double a, double b, int v1, int v2) {
+        return a < b ? v1 : v2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1.0, 1.1, 1, 2);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0, -1.1, 1, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 1.0, java.lang.Double.NaN, 1, 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Conditional01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Conditional01.java
new file mode 100644
index 0000000..0eac5cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Conditional01.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+@SuppressWarnings("unused")
+public class Conditional01 extends JTTTest {
+
+    private static class TestClass {
+        private int nextPC;
+        private int pc;
+        private boolean aC;
+        private boolean aH;
+        private boolean aN;
+        private boolean aZ;
+        private boolean aV;
+        private boolean aS;
+        private int cyclesConsumed;
+        private int[] sram = new int[RAM_SIZE];
+
+        public void visit(CPC i) {
+            nextPC = pc + 2;
+            int tmp0 = getRegisterByte(i.r1);
+            int tmp1 = getRegisterByte(i.r2);
+            int tmp2 = bit(aC);
+            int tmp3 = tmp0 - tmp1 - tmp2;
+            boolean tmp4 = ((tmp0 & 128) != 0);
+            boolean tmp5 = ((tmp1 & 128) != 0);
+            boolean tmp6 = ((tmp3 & 128) != 0);
+            boolean tmp7 = ((tmp0 & 8) != 0);
+            boolean tmp8 = ((tmp1 & 8) != 0);
+            boolean tmp9 = ((tmp3 & 8) != 0);
+            aH = !tmp7 && tmp8 || tmp8 && tmp9 || tmp9 && !tmp7;
+            aC = !tmp4 && tmp5 || tmp5 && tmp6 || tmp6 && !tmp4;
+            aN = tmp6;
+            aZ = low(tmp3) == 0 && aZ;
+            aV = tmp4 && !tmp5 && !tmp6 || !tmp4 && tmp5 && tmp6;
+            aS = (aN != aV);
+            cyclesConsumed++;
+        }
+
+        public int getRegisterByte(Register r1) {
+            if ((r1.val % 10) == 0) {
+                return sram[r1.num];
+            }
+            return r1.val;
+        }
+
+        public int low(int tmp3) {
+            return tmp3 & 0x01;
+        }
+
+        public int bit(boolean c2) {
+            return c2 ? 1 : 0;
+        }
+    }
+
+    private static final int RAM_SIZE = 0x100;
+    private static final int init = new Random().nextInt();
+    private static final int init1 = new Register().val;
+    private static final Register init2 = new CPC().r1;
+
+    public static int test(int arg) {
+        TestClass c = new TestClass();
+        Random rnd = new Random();
+        for (int i = 0; i < arg; i++) {
+            CPC i2 = new CPC();
+            i2.r1 = new Register();
+            i2.r1.val = i;
+            i2.r1.num = i + RAM_SIZE - 20;
+            i2.r2 = new Register();
+            i2.r2.val = rnd.nextInt();
+            i2.r2.num = rnd.nextInt(RAM_SIZE);
+            try {
+                c.visit(i2);
+            } catch (RuntimeException re) {
+
+            }
+        }
+        return c.cyclesConsumed;
+    }
+
+    private static class Register {
+
+        int val;
+        int num;
+    }
+
+    private static class CPC {
+
+        public Register r1;
+        public Register r2;
+
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 20);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 40);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination01.java
new file mode 100644
index 0000000..970ac3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class ConditionalElimination01 extends JTTTest {
+
+    private static int x;
+    private static Object o = new Object();
+
+    private static class A {
+
+        A(int y) {
+            this.y = y;
+        }
+
+        int y;
+    }
+
+    @Override
+    protected void before(ResolvedJavaMethod method) {
+        super.before(method);
+        x = 0;
+    }
+
+    public int test(A a) {
+        if (o == null) {
+            return -1;
+        }
+        if (a == null) {
+            return -2;
+        }
+        if (o == null) {
+            return -3;
+        }
+        x = 3;
+        return a.y + x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new A(5));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new Object[]{null});
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java
new file mode 100644
index 0000000..e975bd8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.util.EnumSet;
+
+import jdk.vm.ci.meta.DeoptimizationReason;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class ConditionalElimination02 extends JTTTest {
+
+    private static Object o = null;
+
+    private static class A {
+
+        A(int y) {
+            this.y = y;
+        }
+
+        int y;
+    }
+
+    public int test(A a, boolean isNull, boolean isVeryNull) {
+        if (o == null) {
+            if (!isNull) {
+                if (o == null) {
+                    return a.y;
+                }
+            }
+            if (!isVeryNull) {
+                if (o == null) {
+                    return a.y;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new A(5), false, false);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new Object[]{null, true, true});
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConvertCompare.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConvertCompare.java
new file mode 100644
index 0000000..a5510b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConvertCompare.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class ConvertCompare extends JTTTest {
+    public static boolean test(int a, float d) {
+        return a == (double) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 2.87f);
+    }
+
+    public static boolean testChar42(int x) {
+        return ((char) x) == 42;
+    }
+
+    @Test
+    public void run1() {
+        runTest("testChar42", 42);
+    }
+
+    @Test
+    public void run2() {
+        runTest("testChar42", (int) Character.MAX_VALUE);
+    }
+
+    public static boolean testCharMax(int x) {
+        return ((char) x) == Character.MAX_VALUE;
+    }
+
+    @Test
+    public void run3() {
+        runTest("testCharMax", 42);
+    }
+
+    @Test
+    public void run4() {
+        runTest("testCharMax", (int) Character.MAX_VALUE);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode01.java
new file mode 100644
index 0000000..68c7d9b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode01.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class DeadCode01 extends JTTTest {
+
+    public static int test(int a) {
+        int arg = a;
+        int p = arg;
+        if (p > 2) {
+            p += 1;
+            arg += 10;
+        } else {
+            p += 2;
+            arg += 20;
+            if (p > 3) {
+                p += 1;
+                arg += 10;
+                if (p > 4) {
+                    p += 1;
+                    arg += 10;
+                } else {
+                    p += 2;
+                    arg += 20;
+                }
+            } else {
+                p += 2;
+                arg += 20;
+            }
+        }
+        return p;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode02.java
new file mode 100644
index 0000000..e34d45d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/DeadCode02.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class DeadCode02 extends JTTTest {
+
+    public static int test() {
+        int i = 0;
+        while (true) {
+            i++;
+            if (test2()) {
+                break;
+            }
+        }
+        return i;
+    }
+
+    public static boolean test2() {
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Cast01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Cast01.java
new file mode 100644
index 0000000..cb88cde
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Cast01.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_Cast01 extends JTTTest {
+
+    private static class TestClass {
+        int field = 9;
+    }
+
+    static final Object object = new TestClass();
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return ((TestClass) object).field;
+        }
+        if (arg == 1) {
+            Object obj = new TestClass();
+            return ((TestClass) obj).field;
+        }
+        if (arg == 2) {
+            return ((TestClass) null).field;
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert01.java
new file mode 100644
index 0000000..f7dd3d7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert01.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_Convert01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return i2b();
+        }
+        if (arg == 1) {
+            return i2s();
+        }
+        if (arg == 2) {
+            return i2c();
+        }
+        return 0;
+    }
+
+    public static int i2b() {
+        int x = 0x00000080;
+        return (byte) x;
+    }
+
+    public static int i2s() {
+        int x = 0x00008000;
+        return (short) x;
+    }
+
+    public static int i2c() {
+        int x = 0xffffffff;
+        return (char) x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert02.java
new file mode 100644
index 0000000..22f4f92
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert02.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_Convert02 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return i2l();
+        }
+        if (arg == 1) {
+            return f2l();
+        }
+        if (arg == 2) {
+            return d2l();
+        }
+        return 0;
+    }
+
+    public static long i2l() {
+        int x = 0x80000000;
+        return x;
+    }
+
+    public static long f2l() {
+        float x = -33.1f;
+        return (long) x;
+    }
+
+    public static long d2l() {
+        double x = -78.1d;
+        return (long) x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert03.java
new file mode 100644
index 0000000..7afc87b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert03.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of float conversions
+ */
+public class Fold_Convert03 extends JTTTest {
+
+    public static float test(float arg) {
+        if (arg == 0) {
+            return i2f();
+        }
+        if (arg == 1) {
+            return l2f();
+        }
+        if (arg == 2) {
+            return d2f();
+        }
+        return 0;
+    }
+
+    public static float i2f() {
+        int x = 1024;
+        return x;
+    }
+
+    public static float l2f() {
+        long x = -33;
+        return x;
+    }
+
+    public static float d2f() {
+        double x = -78.1d;
+        return (float) x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0F);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0F);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2.0F);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert04.java
new file mode 100644
index 0000000..a1fba82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Convert04.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of float conversions
+ */
+public class Fold_Convert04 extends JTTTest {
+
+    public static double test(double arg) {
+        if (arg == 0) {
+            return l2d();
+        }
+        if (arg == 1) {
+            return f2d();
+        }
+        return 0;
+    }
+
+    public static double l2d() {
+        long x = 1024;
+        return x;
+    }
+
+    public static double f2d() {
+        float x = -1.25f;
+        return x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0.0D);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1.0D);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double01.java
new file mode 100644
index 0000000..1688034
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double01.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of float operations.
+ */
+public class Fold_Double01 extends JTTTest {
+
+    public static double test(double arg) {
+        if (arg == 0) {
+            return add();
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul();
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        return 0;
+    }
+
+    public static double add() {
+        double x = 3;
+        return x + 7;
+    }
+
+    public static double sub() {
+        double x = 15;
+        return x - 4;
+    }
+
+    public static double mul() {
+        double x = 6;
+        return x * 2;
+    }
+
+    public static double div() {
+        double x = 26;
+        return x / 2;
+    }
+
+    public static double mod() {
+        double x = 29;
+        return x % 15;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3d);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double02.java
new file mode 100644
index 0000000..f75cb64
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double02.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer comparisons.
+ */
+public class Fold_Double02 extends JTTTest {
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return equ();
+        }
+        if (arg == 1) {
+            return neq();
+        }
+        if (arg == 2) {
+            return geq();
+        }
+        if (arg == 3) {
+            return ge();
+        }
+        if (arg == 4) {
+            return ltq();
+        }
+        if (arg == 5) {
+            return lt();
+        }
+        return false;
+    }
+
+    static boolean equ() {
+        double x = 34;
+        return x == 34;
+    }
+
+    static boolean neq() {
+        double x = 34;
+        return x != 33;
+    }
+
+    static boolean geq() {
+        double x = 34;
+        return x >= 33;
+    }
+
+    static boolean ge() {
+        double x = 34;
+        return x > 35;
+    }
+
+    static boolean ltq() {
+        double x = 34;
+        return x <= 32;
+    }
+
+    static boolean lt() {
+        double x = 34;
+        return x < 31;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double03.java
new file mode 100644
index 0000000..96fdde0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double03.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Fold_Double03 extends JTTTest {
+
+    private static final double MINUS_ZERO = 1 / Double.NEGATIVE_INFINITY;
+
+    public static double test(int t, double a) {
+        double v;
+        if (t == 0) {
+            v = a * 0.0;
+        } else {
+            v = a * MINUS_ZERO;
+        }
+        return 1 / v;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 5.0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 5.0);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, -5.0);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, -5.0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float01.java
new file mode 100644
index 0000000..44d6306
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float01.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of float operations.
+ */
+public class Fold_Float01 extends JTTTest {
+
+    public static float test(float arg) {
+        if (arg == 0) {
+            return add();
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul();
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        return 0;
+    }
+
+    public static float add() {
+        float x = 3;
+        return x + 7;
+    }
+
+    public static float sub() {
+        float x = 15;
+        return x - 4;
+    }
+
+    public static float mul() {
+        float x = 6;
+        return x * 2;
+    }
+
+    public static float div() {
+        float x = 26;
+        return x / 2;
+    }
+
+    public static float mod() {
+        float x = 29;
+        return x % 15;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3f);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float02.java
new file mode 100644
index 0000000..a0bc99f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float02.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer comparisons.
+ */
+public class Fold_Float02 extends JTTTest {
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return equ();
+        }
+        if (arg == 1) {
+            return neq();
+        }
+        if (arg == 2) {
+            return geq();
+        }
+        if (arg == 3) {
+            return ge();
+        }
+        if (arg == 4) {
+            return ltq();
+        }
+        if (arg == 5) {
+            return lt();
+        }
+        return false;
+    }
+
+    static boolean equ() {
+        float x = 34;
+        return x == 34;
+    }
+
+    static boolean neq() {
+        float x = 34;
+        return x != 33;
+    }
+
+    static boolean geq() {
+        float x = 34;
+        return x >= 33;
+    }
+
+    static boolean ge() {
+        float x = 34;
+        return x > 35;
+    }
+
+    static boolean ltq() {
+        float x = 34;
+        return x <= 32;
+    }
+
+    static boolean lt() {
+        float x = 34;
+        return x < 31;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_InstanceOf01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_InstanceOf01.java
new file mode 100644
index 0000000..92d93c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_InstanceOf01.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_InstanceOf01 extends JTTTest {
+
+    static final Object object = new DummyTestClass();
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return object instanceof DummyTestClass;
+        }
+        if (arg == 1) {
+            Object obj = new DummyTestClass();
+            return obj instanceof DummyTestClass;
+        }
+        if (arg == 2) {
+            return null instanceof DummyTestClass;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int01.java
new file mode 100644
index 0000000..32f5b8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int01.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_Int01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add();
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul();
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and();
+        }
+        if (arg == 6) {
+            return or();
+        }
+        if (arg == 7) {
+            return xor();
+        }
+        return 0;
+    }
+
+    public static int add() {
+        int x = 3;
+        return x + 7;
+    }
+
+    public static int sub() {
+        int x = 15;
+        return x - 4;
+    }
+
+    public static int mul() {
+        int x = 6;
+        return x * 2;
+    }
+
+    public static int div() {
+        int x = 26;
+        return x / 2;
+    }
+
+    public static int mod() {
+        int x = 29;
+        return x % 15;
+    }
+
+    public static int and() {
+        int x = 31;
+        return x & 15;
+    }
+
+    public static int or() {
+        int x = 16;
+        return x | 16;
+    }
+
+    public static int xor() {
+        int x = 0;
+        return x ^ 17;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int02.java
new file mode 100644
index 0000000..bdb84f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Int02.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer comparisons.
+ */
+public class Fold_Int02 extends JTTTest {
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return equ();
+        }
+        if (arg == 1) {
+            return neq();
+        }
+        if (arg == 2) {
+            return geq();
+        }
+        if (arg == 3) {
+            return ge();
+        }
+        if (arg == 4) {
+            return ltq();
+        }
+        if (arg == 5) {
+            return lt();
+        }
+        return false;
+    }
+
+    static boolean equ() {
+        int x = 34;
+        return x == 34;
+    }
+
+    static boolean neq() {
+        int x = 34;
+        return x != 33;
+    }
+
+    static boolean geq() {
+        int x = 34;
+        return x >= 33;
+    }
+
+    static boolean ge() {
+        int x = 34;
+        return x > 35;
+    }
+
+    static boolean ltq() {
+        int x = 34;
+        return x <= 32;
+    }
+
+    static boolean lt() {
+        int x = 34;
+        return x < 31;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long01.java
new file mode 100644
index 0000000..8b2c265
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long01.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Fold_Long01 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return add();
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul();
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and();
+        }
+        if (arg == 6) {
+            return or();
+        }
+        if (arg == 7) {
+            return xor();
+        }
+        return 0;
+    }
+
+    public static long add() {
+        long x = 3;
+        return x + 7;
+    }
+
+    public static long sub() {
+        long x = 15;
+        return x - 4;
+    }
+
+    public static long mul() {
+        long x = 6;
+        return x * 2;
+    }
+
+    public static long div() {
+        long x = 26;
+        return x / 2;
+    }
+
+    public static long mod() {
+        long x = 29;
+        return x % 15;
+    }
+
+    public static long and() {
+        long x = 31;
+        return x & 15;
+    }
+
+    public static long or() {
+        long x = 16;
+        return x | 16;
+    }
+
+    public static long xor() {
+        long x = 0;
+        return x ^ 17;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long02.java
new file mode 100644
index 0000000..cd0f188
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Long02.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer comparisons.
+ */
+public class Fold_Long02 extends JTTTest {
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return equ();
+        }
+        if (arg == 1) {
+            return neq();
+        }
+        if (arg == 2) {
+            return geq();
+        }
+        if (arg == 3) {
+            return ge();
+        }
+        if (arg == 4) {
+            return ltq();
+        }
+        if (arg == 5) {
+            return lt();
+        }
+        return false;
+    }
+
+    static boolean equ() {
+        long x = 34;
+        return x == 34;
+    }
+
+    static boolean neq() {
+        long x = 34;
+        return x != 33;
+    }
+
+    static boolean geq() {
+        long x = 34;
+        return x >= 33;
+    }
+
+    static boolean ge() {
+        long x = 34;
+        return x > 35;
+    }
+
+    static boolean ltq() {
+        long x = 34;
+        return x <= 32;
+    }
+
+    static boolean lt() {
+        long x = 34;
+        return x < 31;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Math01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Math01.java
new file mode 100644
index 0000000..a2cb098
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Math01.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Fold_Math01 extends JTTTest {
+
+    public static double test(int arg) {
+        switch (arg) {
+            case 0:
+                return abs();
+            case 1:
+                return sin();
+            case 2:
+                return cos();
+            case 3:
+                return tan();
+            case 4:
+                return atan2();
+            case 5:
+                return sqrt();
+            case 6:
+                return log();
+            case 7:
+                return log10();
+            case 8:
+                return pow();
+            case 9:
+                return exp();
+            case 10:
+                return min();
+            case 11:
+                return max();
+        }
+        return 42;
+    }
+
+    private static double abs() {
+        return Math.abs(-10.0d);
+    }
+
+    private static double sin() {
+        return Math.sin(0.15d);
+    }
+
+    private static double cos() {
+        return Math.cos(0.15d);
+    }
+
+    private static double tan() {
+        return Math.tan(0.15d);
+    }
+
+    private static double atan2() {
+        return Math.atan2(0.15d, 3.1d);
+    }
+
+    private static double sqrt() {
+        return Math.sqrt(144d);
+    }
+
+    private static double log() {
+        return Math.log(3.15d);
+    }
+
+    private static double log10() {
+        return Math.log10(0.15d);
+    }
+
+    private static double pow() {
+        return Math.pow(2.15d, 6.1d);
+    }
+
+    private static double exp() {
+        return Math.log(3.15d);
+    }
+
+    private static int min() {
+        return Math.min(2, -1);
+    }
+
+    private static int max() {
+        return Math.max(2, -1);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+    @Test
+    public void run9() throws Throwable {
+        runTest("test", 9);
+    }
+
+    @Test
+    public void run10() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run11() throws Throwable {
+        runTest("test", 11);
+    }
+
+    @Test
+    public void run12() throws Throwable {
+        runTest("test", 12);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/InferStamp01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/InferStamp01.java
new file mode 100644
index 0000000..3e4ac54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/InferStamp01.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * test some stamps in combination with full loop unrolling and shifts.
+ */
+public class InferStamp01 extends JTTTest {
+
+    public static int testi0(int arg) {
+        int a = arg;
+        for (int i = 0; i < 2; i++) {
+            a = a >> 16;
+        }
+        return a;
+    }
+
+    @Test
+    public void runi0() throws Throwable {
+        runTest("testi0", 0x7788_99aa);
+    }
+
+    @Test
+    public void runi0neg() throws Throwable {
+        runTest("testi0", 0xf788_99aa);
+    }
+
+    public static int testi1(int arg) {
+        int a = arg;
+        for (int i = 0; i < 2; i++) {
+            a = a >>> 16;
+        }
+        return a;
+    }
+
+    @Test
+    public void runi1() throws Throwable {
+        runTest("testi1", 0x7788_99aa);
+    }
+
+    @Test
+    public void runi1neg() throws Throwable {
+        runTest("testi1", 0xf788_99aa);
+    }
+
+    public static int testi2(int arg) {
+        int a = arg;
+        for (int i = 0; i < 2; i++) {
+            a = a << 16;
+        }
+        return a;
+    }
+
+    @Test
+    public void runi2() throws Throwable {
+        runTest("testi2", 0x7788_99aa);
+    }
+
+    @Test
+    public void runi2neg() throws Throwable {
+        runTest("testi2", 0xf788_99aa);
+    }
+
+    public static long testl0(long arg) {
+        long a = arg;
+        for (long i = 0; i < 2; i++) {
+            a = a >> 32;
+        }
+        return a;
+    }
+
+    @Test
+    public void runl0() throws Throwable {
+        runTest("testl0", 0x3344_5566_7788_99aaL);
+    }
+
+    @Test
+    public void runl0neg() throws Throwable {
+        runTest("testl0", 0xf344_5566_7788_99aaL);
+    }
+
+    public static long testl1(long arg) {
+        long a = arg;
+        for (long i = 0; i < 2; i++) {
+            a = a >>> 32;
+        }
+        return a;
+    }
+
+    @Test
+    public void runl1() throws Throwable {
+        runTest("testl1", 0x3344_5566_7788_99aaL);
+    }
+
+    @Test
+    public void runl1neg() throws Throwable {
+        runTest("testl1", 0xf344_5566_7788_99aaL);
+    }
+
+    public static long testl2(long arg) {
+        long a = arg;
+        for (long i = 0; i < 2; i++) {
+            a = a << 32;
+        }
+        return a;
+    }
+
+    @Test
+    public void runl2() throws Throwable {
+        runTest("testl2", 0x3344_5566_7788_99aaL);
+    }
+
+    @Test
+    public void runl2neg() throws Throwable {
+        runTest("testl2", 0xf344_5566_7788_99aaL);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline01.java
new file mode 100644
index 0000000..558b83f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline01.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Inline01 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg + nobranch(true) + nobranch(false) + nobranch(true) + nobranch(false);
+    }
+
+    static int nobranch(boolean f) {
+        if (f) {
+            return 0;
+        }
+        return 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline02.java
new file mode 100644
index 0000000..26a91dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Inline02.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Inline02 extends JTTTest {
+
+    public static int test(int arg) {
+        return arg + nobranch(true, arg) + nobranch(false, arg) + nobranch(true, arg) + nobranch(false, arg);
+    }
+
+    static int nobranch(boolean f, int v) {
+        if (f) {
+            return v;
+        }
+        return 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LLE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LLE_01.java
new file mode 100644
index 0000000..099655d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LLE_01.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test case for local load elimination. It makes sure that the second field store is not eliminated, because
+ * it is recognized that the first store changes the field "field1", so it is no longer guaranteed that it
+ * has its default value 0.
+ */
+public class LLE_01 extends JTTTest {
+
+    private static class TestClass {
+        int field1;
+    }
+
+    public static int test() {
+        TestClass o = new TestClass();
+        o.field1 = 1;
+        o.field1 = 0;
+        return o.field1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/List_reorder_bug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/List_reorder_bug.java
new file mode 100644
index 0000000..7a0e2f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/List_reorder_bug.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+@SuppressWarnings("unused")
+public class List_reorder_bug extends JTTTest {
+
+    private static class TestClass {
+        String s;
+
+        private void print(String s2) {
+            this.s = s2;
+        }
+
+        private void match(Object a, int src, int id, int seq) {
+            print("match: " + src + ", " + id);
+            List item = list;
+            List itemPrev = null;
+            while (item != null) {
+                if (item.id == id) {
+                    if (item.bool) {
+                        outcall(item.id);
+                    }
+                    if (itemPrev != null) {
+                        itemPrev.next = item.next;
+                    } else {
+                        list = item.next;
+                    }
+
+                    item.next = null;
+                    return;
+                }
+
+                itemPrev = item;
+                item = item.next;
+            }
+        }
+    }
+
+    static class List {
+
+        List(int id) {
+            this.id = id;
+        }
+
+        List next;
+        int id;
+        boolean bool = true;
+    }
+
+    private static List list;
+
+    public static boolean test(int i) {
+        list = new List(5);
+        list.next = new List(6);
+        new TestClass().match(new Object(), 27, 6, 0);
+        return list.next == null;
+    }
+
+    static int globalId;
+
+    private static void outcall(int id) {
+        globalId = id;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Logic0.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Logic0.java
new file mode 100644
index 0000000..b3fbd04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Logic0.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Logic0 extends JTTTest {
+
+    public static int test(int a, int b) {
+        if (((a != 0 ? 1 : 0) & (a != b ? 1 : 0)) != 0) {
+            return 42;
+        }
+        return 11;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 0, 33);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 33, 66);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 33, 67);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 33, 33);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 0, 32);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 32, 66);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 32, 67);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 32, 32);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LongToSomethingArray01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LongToSomethingArray01.java
new file mode 100644
index 0000000..af1446b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/LongToSomethingArray01.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * inspired by java.security.SecureRandom.longToByteArray(long).
+ *
+ */
+public class LongToSomethingArray01 extends JTTTest {
+
+    public static byte[] longToByteArray(long arg) {
+        long l = arg;
+        byte[] ret = new byte[8];
+        for (int i = 0; i < 8; i++) {
+            ret[i] = (byte) (l & 0xff);
+            l = l >> 8;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runB0() throws Throwable {
+        runTest("longToByteArray", 0x1122_3344_5566_7788L);
+    }
+
+    public static short[] longToShortArray(long arg) {
+        long l = arg;
+        short[] ret = new short[4];
+        for (int i = 0; i < 4; i++) {
+            ret[i] = (short) (l & 0xffff);
+            l = l >> 16;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runS0() throws Throwable {
+        runTest("longToShortArray", 0x1122_3344_5566_7788L);
+    }
+
+    public static int[] longToIntArray(long arg) {
+        long l = arg;
+        int[] ret = new int[2];
+        for (int i = 0; i < 2; i++) {
+            ret[i] = (int) (l & 0xffff_ffff);
+            l = l >> 32;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runI0() throws Throwable {
+        runTest("longToIntArray", 0x1122_3344_5566_7788L);
+    }
+
+    public static long[] longToLongArray(long arg) {
+        long l = arg;
+        long[] ret = new long[1];
+        for (int i = 0; i < 1; i++) {
+            ret[i] = l & 0xffff_ffff_ffff_ffffL;
+            l = l >> 64;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runL0() throws Throwable {
+        runTest("longToLongArray", 0x1122_3344_5566_7788L);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_01.java
new file mode 100644
index 0000000..49d47d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_01.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test case for null check elimination.
+ */
+public class NCE_01 extends JTTTest {
+
+    private static class TestClass {
+        int field1 = 22;
+        int field2 = 23;
+    }
+
+    public static TestClass object = new TestClass();
+
+    public static int test() {
+        TestClass o = object;
+        int i = o.field1;
+        // expected null check elimination here
+        return o.field2 + i;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_02.java
new file mode 100644
index 0000000..12ad334
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_02.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test case for null check elimination.
+ */
+public class NCE_02 extends JTTTest {
+
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
+
+    public static TestClass object = new TestClass();
+
+    public static int test() {
+        TestClass o = object;
+        o.field1 = 11;
+        // expect non-null
+        o.field1 = 22;
+        // expect non-null
+        return o.field2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_03.java
new file mode 100644
index 0000000..646756e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_03.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test case for null check elimination.
+ */
+public class NCE_03 extends JTTTest {
+
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
+
+    private static boolean cond = true;
+    public static TestClass object = new TestClass();
+
+    public static int test() {
+        TestClass o = object;
+        o.field1 = 11;
+        if (cond) {
+            // expect non-null
+            o.field1 = 22;
+        }
+        // expect non-null
+        return o.field2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_04.java
new file mode 100644
index 0000000..d441d12
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_04.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Test case for null check elimination.
+ */
+public class NCE_04 extends JTTTest {
+
+    public static class TestClass {
+        int field1;
+        int field2 = 23;
+    }
+
+    private static boolean cond = true;
+    public static TestClass object = new TestClass();
+
+    public static int test() {
+        TestClass o = object;
+        if (cond) {
+            o.field1 = 22;
+        } else {
+            o.field1 = 11;
+        }
+        // expect non-null
+        return o.field2;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive01.java
new file mode 100644
index 0000000..3d06569
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive01.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class NCE_FlowSensitive01 extends JTTTest {
+
+    public static String test(String arg) {
+        if (arg != null) {
+            return arg.toString();
+        }
+        return null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "x");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "yay");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive02.java
new file mode 100644
index 0000000..0f36b33
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive02.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class NCE_FlowSensitive02 extends JTTTest {
+
+    @SuppressWarnings("all")
+    public static String test(String arg) {
+        if (arg != null) {
+            return arg.toString();
+        }
+        return arg.toString();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "x");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "yay");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive03.java
new file mode 100644
index 0000000..6b79dc0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive03.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class NCE_FlowSensitive03 extends JTTTest {
+
+    public static String test(String arg) {
+        if ("x".equals(arg)) {
+            if (arg == null) {
+                return "null";
+            }
+        } else {
+            if (arg == null) {
+                return "null";
+            }
+        }
+        // arg cannot be null here
+        return arg.toString();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "x");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "yay");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive04.java
new file mode 100644
index 0000000..64ef7d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive04.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class NCE_FlowSensitive04 extends JTTTest {
+
+    public static String test(String arg2) {
+        String arg = arg2;
+        if (arg == null) {
+            arg = "null";
+        }
+        // arg cannot be null here
+        return arg.toString();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "x");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "yay");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive05.java
new file mode 100644
index 0000000..55944b1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NCE_FlowSensitive05.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class NCE_FlowSensitive05 extends JTTTest {
+
+    private static PrintStream ps = new PrintStream(new ByteArrayOutputStream());
+
+    public static String test(Object arg) {
+
+        // An artificial loop to trigger iterative NCE.
+        while (arg != null) {
+            ps.println(arg);
+        }
+
+        // The upcast must still include the null check.
+        return (String) arg;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte01.java
new file mode 100644
index 0000000..d0c45a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte01.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_byte01 extends JTTTest {
+
+    public static byte val;
+
+    public static byte test(byte b) {
+        val = b;
+        return val;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((byte) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((byte) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((byte) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((byte) 110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte02.java
new file mode 100644
index 0000000..811c6a9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_byte02 extends JTTTest {
+
+    static class Byte {
+
+        byte foo;
+    }
+
+    static Byte val = new Byte();
+
+    public static byte test(byte b) {
+        val.foo = b;
+        return val.foo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((byte) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((byte) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((byte) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((byte) 110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte03.java
new file mode 100644
index 0000000..9936509
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_byte03.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_byte03 extends JTTTest {
+
+    static byte[] val = new byte[4];
+
+    public static byte test(byte b) {
+        val[0] = b;
+        return val[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((byte) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((byte) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((byte) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((byte) 110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char01.java
new file mode 100644
index 0000000..ce937de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char01.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_char01 extends JTTTest {
+
+    public static char val;
+
+    public static char test(char b) {
+        val = b;
+        return val;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((char) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((char) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((char) 255));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((char) 65000));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char02.java
new file mode 100644
index 0000000..8d9b6ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_char02 extends JTTTest {
+
+    static class Char {
+
+        char foo;
+    }
+
+    static Char val = new Char();
+
+    public static char test(char b) {
+        val.foo = b;
+        return val.foo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((char) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((char) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((char) 255));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((char) 65000));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char03.java
new file mode 100644
index 0000000..bbe2dbb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_char03.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_char03 extends JTTTest {
+
+    static char[] val = new char[4];
+
+    public static char test(char b) {
+        val[0] = b;
+        return val[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((char) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((char) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((char) 255));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((char) 65000));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short01.java
new file mode 100644
index 0000000..3257afe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short01.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_short01 extends JTTTest {
+
+    public static short val;
+
+    public static short test(short b) {
+        val = b;
+        return val;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((short) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((short) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((short) 23110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short02.java
new file mode 100644
index 0000000..d9d9418
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short02.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_short02 extends JTTTest {
+
+    static class Short {
+
+        short foo;
+    }
+
+    static Short val = new Short();
+
+    public static short test(short b) {
+        val.foo = b;
+        return val.foo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((short) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((short) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((short) 23110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short03.java
new file mode 100644
index 0000000..efc3ac6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Narrow_short03.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Narrow_short03 extends JTTTest {
+
+    static short[] val = new short[4];
+
+    public static short test(short b) {
+        val[0] = b;
+        return val[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", ((short) 0));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", ((short) 1));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", ((short) -1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", ((short) 23110));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java
new file mode 100644
index 0000000..b479d7e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.util.ListIterator;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+public class NestedLoop_EA extends JTTTest {
+
+    @Override
+    protected Suites createSuites() {
+        Suites suites = super.createSuites();
+        ListIterator<BasePhase<? super HighTierContext>> position = suites.getHighTier().findPhase(PartialEscapePhase.class);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        // incremental canonicalizer of PEA is missing some important canonicalization (TODO?)
+        position.add(canonicalizer);
+        position.add(new PartialEscapePhase(true, canonicalizer));
+        return suites;
+    }
+
+    static class Frame {
+        Object[] objects = new Object[10];
+    }
+
+    static final int RESULT_SLOT = 0;
+    static final int K_SLOT = 1;
+    static final int I_SLOT = 2;
+    static final int ARG_SLOT = 3;
+    static final int STACK_BASE = 4;
+
+    static class Pointer {
+        public int sp = STACK_BASE;
+    }
+
+    public static int simpleLoop(int arg) {
+        Frame f = new Frame();
+        Pointer p = new Pointer();
+        f.objects[ARG_SLOT] = arg;
+        f.objects[RESULT_SLOT] = 0;
+        f.objects[K_SLOT] = 0;
+        for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) {
+
+            f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5;
+
+            f.objects[++p.sp] = f.objects[K_SLOT];
+            f.objects[++p.sp] = 1;
+            int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+            p.sp--;
+            f.objects[p.sp] = result;
+            f.objects[K_SLOT] = (int) f.objects[p.sp];
+            p.sp--;
+        }
+        return (int) f.objects[RESULT_SLOT];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("simpleLoop", 5);
+    }
+
+    public static int nestedLoop(int arg) {
+        Frame f = new Frame();
+        Pointer p = new Pointer();
+        f.objects[ARG_SLOT] = arg;
+        f.objects[RESULT_SLOT] = 0;
+        f.objects[K_SLOT] = 0;
+        for (; (int) f.objects[K_SLOT] < (int) f.objects[ARG_SLOT];) {
+
+            f.objects[I_SLOT] = 0;
+            for (; (int) f.objects[I_SLOT] < (int) f.objects[ARG_SLOT];) {
+                f.objects[RESULT_SLOT] = (int) f.objects[RESULT_SLOT] + 5;
+
+                f.objects[++p.sp] = f.objects[I_SLOT];
+                f.objects[++p.sp] = 1;
+                int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+                p.sp--;
+                f.objects[p.sp] = result;
+                f.objects[I_SLOT] = (int) f.objects[p.sp];
+                p.sp--;
+            }
+
+            f.objects[++p.sp] = f.objects[K_SLOT];
+            f.objects[++p.sp] = 1;
+            int result = (int) f.objects[p.sp] + (int) f.objects[p.sp - 1];
+            p.sp--;
+            f.objects[p.sp] = result;
+            f.objects[K_SLOT] = (int) f.objects[p.sp];
+            p.sp--;
+        }
+        return (int) f.objects[RESULT_SLOT];
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("nestedLoop", 5);
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        assert graph.getNodes().filter(CommitAllocationNode.class).count() == 0 : "all allocations should be virtualized";
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi01.java
new file mode 100644
index 0000000..bd8f81d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi01.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Phi01 extends JTTTest {
+
+    public static class Phi {
+
+        int f;
+
+        Phi(int f) {
+            this.f = f;
+        }
+    }
+
+    public static int test(int arg) {
+        return test2(new Phi(arg), arg);
+    }
+
+    private static int test2(Phi p, int a) {
+        int arg = a;
+        if (arg > 2) {
+            p.f += 1;
+            arg += 1;
+        } else {
+            p.f += 2;
+            arg += 2;
+            if (arg > 3) {
+                p.f += 1;
+                arg += 1;
+                if (arg > 4) {
+                    p.f += 1;
+                    arg += 1;
+                } else {
+                    p.f += 2;
+                    arg += 2;
+                }
+            } else {
+                p.f += 2;
+                arg += 2;
+            }
+        }
+        return arg + p.f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi02.java
new file mode 100644
index 0000000..7092d84
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi02.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Phi02 extends JTTTest {
+
+    public static class Phi {
+
+        int f;
+
+        Phi(int f) {
+            this.f = f;
+        }
+    }
+
+    public static int test(int arg) {
+        return test2(new Phi(arg), arg);
+    }
+
+    private static int test2(Phi p, int a) {
+        int arg = a;
+        if (arg > 2) {
+            inc(p, 1);
+            arg += 1;
+        } else {
+            inc(p, 2);
+            arg += 2;
+            if (arg > 3) {
+                inc(p, 1);
+                arg += 1;
+                if (arg > 4) {
+                    inc(p, 1);
+                    arg += 1;
+                } else {
+                    inc(p, 2);
+                    arg += 2;
+                }
+            } else {
+                inc(p, 2);
+                arg += 2;
+            }
+        }
+        return arg + p.f;
+    }
+
+    private static void inc(Phi p, int inc) {
+        p.f += inc;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi03.java
new file mode 100644
index 0000000..e110ed5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Phi03.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Phi03 extends JTTTest {
+
+    public static class Phi {
+
+        int f;
+
+        Phi(int f) {
+            this.f = f;
+        }
+    }
+
+    public static int test(int arg) {
+        return test2(new Phi(arg), arg);
+    }
+
+    private static int test2(Phi p, int a) {
+        int arg = a;
+        if (arg > 2) {
+            inc(p, 1);
+            arg += 1;
+        } else {
+            inc(p, 2);
+            arg += 2;
+            if (arg > 3) {
+                inc(p, 1);
+                arg += 1;
+                if (arg > 4) {
+                    inc(p, 1);
+                    arg += 1;
+                } else {
+                    inc(p, 2);
+                    arg += 2;
+                }
+            } else {
+                inc(p, 2);
+                arg += 2;
+            }
+        }
+        return p.f;
+    }
+
+    private static void inc(Phi p, int inc) {
+        p.f += inc;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ReassociateConstants.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ReassociateConstants.java
new file mode 100644
index 0000000..fdb9edd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ReassociateConstants.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ReassociateConstants {
+
+    public static int rnd = (int) (Math.random() * 100);
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(rnd + 3, 1 + (rnd + 2));
+        Assert.assertEquals(rnd + 3, (rnd + 2) + 1);
+        Assert.assertEquals(rnd + 3, 1 + (2 + rnd));
+        Assert.assertEquals(rnd + 3, (2 + rnd) + 1);
+
+        Assert.assertEquals(-1 - rnd, 1 - (rnd + 2));
+        Assert.assertEquals(rnd + 1, (rnd + 2) - 1);
+        Assert.assertEquals(-1 - rnd, 1 - (2 + rnd));
+        Assert.assertEquals(rnd + 1, (2 + rnd) - 1);
+
+        Assert.assertEquals(rnd - 1, 1 + (rnd - 2));
+        Assert.assertEquals(rnd - 1, (rnd - 2) + 1);
+        Assert.assertEquals(-rnd + 3, 1 + (2 - rnd));
+        Assert.assertEquals(-rnd + 3, (2 - rnd) + 1);
+
+        Assert.assertEquals(-rnd + 3, 1 - (rnd - 2));
+        Assert.assertEquals(rnd - 3, (rnd - 2) - 1);
+        Assert.assertEquals(rnd + -1, 1 - (2 - rnd));
+        Assert.assertEquals(-rnd + 1, (2 - rnd) - 1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Convert01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Convert01.java
new file mode 100644
index 0000000..ef2d425
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Convert01.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization integer conversions.
+ */
+public class Reduce_Convert01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return i2b(arg + 10);
+        }
+        if (arg == 1) {
+            return i2s(arg + 10);
+        }
+        if (arg == 2) {
+            return i2c(arg + 10);
+        }
+        return 0;
+    }
+
+    public static int i2b(int arg) {
+        int x = (byte) arg;
+        return (byte) x;
+    }
+
+    public static int i2s(int arg) {
+        int x = (short) arg;
+        return (short) x;
+    }
+
+    public static int i2c(int arg) {
+        int x = (char) arg;
+        return (char) x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Double01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Double01.java
new file mode 100644
index 0000000..b33e8fe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Double01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of double operations.
+ */
+public class Reduce_Double01 extends JTTTest {
+
+    public static double test(double arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub(11);
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div(13);
+        }
+        return 0;
+    }
+
+    public static double add(double x) {
+        return x + 0;
+    }
+
+    public static double sub(double x) {
+        return x - 0;
+    }
+
+    public static double mul(double x) {
+        return x * 1;
+    }
+
+    public static double div(double x) {
+        return x / 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Float01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Float01.java
new file mode 100644
index 0000000..230d9cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Float01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of float operations.
+ */
+public class Reduce_Float01 extends JTTTest {
+
+    public static float test(float arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub(11);
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div(13);
+        }
+        return 0;
+    }
+
+    public static float add(float x) {
+        return x + 0;
+    }
+
+    public static float sub(float x) {
+        return x - 0;
+    }
+
+    public static float mul(float x) {
+        return x * 1;
+    }
+
+    public static float div(float x) {
+        return x / 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int01.java
new file mode 100644
index 0000000..3e5560c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int01.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Int01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub(11);
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div(13);
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static int add(int x) {
+        return x + 0;
+    }
+
+    public static int sub(int x) {
+        return x - 0;
+    }
+
+    public static int mul(int x) {
+        return x * 1;
+    }
+
+    public static int div(int x) {
+        return x / 1;
+    }
+
+    public static int mod() {
+        return 14;
+    }
+
+    public static int and(int x) {
+        return x & -1;
+    }
+
+    public static int or(int x) {
+        return x | 0;
+    }
+
+    public static int xor(int x) {
+        return x ^ 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int02.java
new file mode 100644
index 0000000..11bec67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int02.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Int02 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static int add(int x) {
+        return 0 + x;
+    }
+
+    public static int sub() {
+        return 11;
+    }
+
+    public static int mul(int x) {
+        return 1 * x;
+    }
+
+    public static int div() {
+        return 13;
+    }
+
+    public static int mod() {
+        return 14;
+    }
+
+    public static int and(int x) {
+        return -1 & x;
+    }
+
+    public static int or(int x) {
+        return 0 | x;
+    }
+
+    public static int xor(int x) {
+        return 0 ^ x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int03.java
new file mode 100644
index 0000000..5888d03
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int03.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Int03 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add(5);
+        }
+        if (arg == 1) {
+            return sub(10);
+        }
+        if (arg == 2) {
+            return mul(5);
+        }
+        if (arg == 3) {
+            return div(5);
+        }
+        if (arg == 4) {
+            return mod(5);
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static int add(int x) {
+        return x + x;
+    }
+
+    public static int sub(int x) {
+        return x - x;
+    }
+
+    public static int mul(int x) {
+        return x * x;
+    }
+
+    public static int div(int x) {
+        return x / x;
+    }
+
+    public static int mod(int x) {
+        return x % x;
+    }
+
+    public static int and(int x) {
+        return x & x;
+    }
+
+    public static int or(int x) {
+        return x | x;
+    }
+
+    public static int xor(int x) {
+        return x ^ x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int04.java
new file mode 100644
index 0000000..14ba419
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Int04.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Int04 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return mul0(arg + 10);
+        }
+        if (arg == 1) {
+            return mul1(arg + 9);
+        }
+        return 0;
+    }
+
+    public static int mul0(int x) {
+        return x * 4;
+    }
+
+    public static int mul1(int x) {
+        return x * 65536;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift01.java
new file mode 100644
index 0000000..1fa3fae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift01.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class Reduce_IntShift01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return shift0(arg + 10);
+        }
+        if (arg == 1) {
+            return shift1(arg + 10);
+        }
+        if (arg == 2) {
+            return shift2(arg + 10);
+        }
+        if (arg == 3) {
+            return shift3(arg + 10);
+        }
+        if (arg == 4) {
+            return shift4(arg + 10);
+        }
+        if (arg == 5) {
+            return shift5(arg + 10);
+        }
+        return 0;
+    }
+
+    public static int shift0(int x) {
+        return x >> 0;
+    }
+
+    public static int shift1(int x) {
+        return x >>> 0;
+    }
+
+    public static int shift2(int x) {
+        return x << 0;
+    }
+
+    public static int shift3(int x) {
+        return x >> 64;
+    }
+
+    public static int shift4(int x) {
+        return x >>> 64;
+    }
+
+    public static int shift5(int x) {
+        return x << 64;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift02.java
new file mode 100644
index 0000000..efe55fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_IntShift02.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class Reduce_IntShift02 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return shift0(arg + 80);
+        }
+        if (arg == 1) {
+            return shift1(arg + 0x8000000a);
+        }
+        if (arg == 2) {
+            return shift2(arg + 192);
+        }
+        if (arg == 3) {
+            return shift3(arg + 208);
+        }
+        if (arg == 4) {
+            return shift4(arg);
+        }
+        if (arg == 5) {
+            return shift5(arg);
+        }
+        return 0;
+    }
+
+    public static int shift0(int x) {
+        return x >>> 3 << 3;
+    }
+
+    public static int shift1(int x) {
+        return x << 3 >>> 3;
+    }
+
+    public static int shift2(int x) {
+        return x >> 3 >> 1;
+    }
+
+    public static int shift3(int x) {
+        return x >>> 3 >>> 1;
+    }
+
+    public static int shift4(int x) {
+        return x << 3 << 1;
+    }
+
+    public static int shift5(int x) {
+        return x << 16 << 17;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long01.java
new file mode 100644
index 0000000..da1df3d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long01.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Long01 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub(11);
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div(13);
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static long add(long x) {
+        return x + 0;
+    }
+
+    public static long sub(long x) {
+        return x - 0;
+    }
+
+    public static long mul(long x) {
+        return x * 1;
+    }
+
+    public static long div(long x) {
+        return x / 1;
+    }
+
+    public static long mod() {
+        return 14;
+    }
+
+    public static long and(long x) {
+        return x & -1;
+    }
+
+    public static long or(long x) {
+        return x | 0;
+    }
+
+    public static long xor(long x) {
+        return x ^ 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long02.java
new file mode 100644
index 0000000..cb0da43
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long02.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Long02 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return add(10);
+        }
+        if (arg == 1) {
+            return sub();
+        }
+        if (arg == 2) {
+            return mul(12);
+        }
+        if (arg == 3) {
+            return div();
+        }
+        if (arg == 4) {
+            return mod();
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static long add(long x) {
+        return 0 + x;
+    }
+
+    public static long sub() {
+        return 11;
+    }
+
+    public static long mul(long x) {
+        return 1 * x;
+    }
+
+    public static long div() {
+        return 13;
+    }
+
+    public static long mod() {
+        return 14;
+    }
+
+    public static long and(long x) {
+        return -1 & x;
+    }
+
+    public static long or(long x) {
+        return 0 | x;
+    }
+
+    public static long xor(long x) {
+        return 0 ^ x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long03.java
new file mode 100644
index 0000000..7c1fab1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long03.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Long03 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return add(5);
+        }
+        if (arg == 1) {
+            return sub(10);
+        }
+        if (arg == 2) {
+            return mul(5);
+        }
+        if (arg == 3) {
+            return div(5);
+        }
+        if (arg == 4) {
+            return mod(5);
+        }
+        if (arg == 5) {
+            return and(15);
+        }
+        if (arg == 6) {
+            return or(16);
+        }
+        if (arg == 7) {
+            return xor(17);
+        }
+        return 0;
+    }
+
+    public static long add(long x) {
+        return x + x;
+    }
+
+    public static long sub(long x) {
+        return x - x;
+    }
+
+    public static long mul(long x) {
+        return x * x;
+    }
+
+    public static long div(long x) {
+        return x / x;
+    }
+
+    public static long mod(long x) {
+        return x % x;
+    }
+
+    public static long and(long x) {
+        return x & x;
+    }
+
+    public static long or(long x) {
+        return x | x;
+    }
+
+    public static long xor(long x) {
+        return x ^ x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6L);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long04.java
new file mode 100644
index 0000000..9c7dca9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_Long04.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class Reduce_Long04 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return mul0(arg + 10);
+        }
+        if (arg == 1) {
+            return mul1(arg + 9);
+        }
+        return 0;
+    }
+
+    public static long mul0(long x) {
+        return x * 4;
+    }
+
+    public static long mul1(long x) {
+        return x * 8589934592L;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift01.java
new file mode 100644
index 0000000..fcee83a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift01.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class Reduce_LongShift01 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return shift0(arg + 10);
+        }
+        if (arg == 1) {
+            return shift1(arg + 10);
+        }
+        if (arg == 2) {
+            return shift2(arg + 10);
+        }
+        if (arg == 3) {
+            return shift3(arg + 10);
+        }
+        if (arg == 4) {
+            return shift4(arg + 10);
+        }
+        if (arg == 5) {
+            return shift5(arg + 10);
+        }
+        return 0;
+    }
+
+    public static long shift0(long x) {
+        return x >> 0;
+    }
+
+    public static long shift1(long x) {
+        return x >>> 0;
+    }
+
+    public static long shift2(long x) {
+        return x << 0;
+    }
+
+    public static long shift3(long x) {
+        return x >> 64;
+    }
+
+    public static long shift4(long x) {
+        return x >>> 64;
+    }
+
+    public static long shift5(long x) {
+        return x << 64;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift02.java
new file mode 100644
index 0000000..89763ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Reduce_LongShift02.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class Reduce_LongShift02 extends JTTTest {
+
+    public static long test(long arg) {
+        if (arg == 0) {
+            return shift0(arg + 80);
+        }
+        if (arg == 1) {
+            return shift1(arg + 0x800000000000000aL);
+        }
+        if (arg == 2) {
+            return shift2(arg + 192);
+        }
+        if (arg == 3) {
+            return shift3(arg + 208);
+        }
+        if (arg == 4) {
+            return shift4(arg);
+        }
+        return 0;
+    }
+
+    public static long shift0(long x) {
+        return x >>> 3 << 3;
+    }
+
+    public static long shift1(long x) {
+        return x << 3 >>> 3;
+    }
+
+    public static long shift2(long x) {
+        return x >> 3 >> 1;
+    }
+
+    public static long shift3(long x) {
+        return x >>> 3 >>> 1;
+    }
+
+    public static long shift4(long x) {
+        return x << 3 << 1;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3L);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SchedulingBug_01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SchedulingBug_01.java
new file mode 100644
index 0000000..73beb0b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SchedulingBug_01.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class SchedulingBug_01 extends JTTTest {
+
+    private static class VolatileBoxHolder {
+        volatile Integer box;
+    }
+
+    public static int test(VolatileBoxHolder a, VolatileBoxHolder b) {
+        int value = a.box;
+        int result = 0;
+        if (b.box != null) {
+            result += value;
+        }
+        return result + value;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new VolatileBoxHolder(), new VolatileBoxHolder());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SignExtendShort.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SignExtendShort.java
new file mode 100644
index 0000000..31eb2ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/SignExtendShort.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class SignExtendShort extends JTTTest {
+
+    public static int val;
+
+    public static boolean test(short[] b) {
+        val = b[2];
+        int x = 0;
+        return val >= x;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", new short[]{0, 0, 0});
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", new short[]{0, 0, 1});
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new short[]{0, 0, -1});
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", new short[]{0, 0, Short.MAX_VALUE});
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", new short[]{0, 0, Short.MIN_VALUE});
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch01.java
new file mode 100644
index 0000000..c4d7ffb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch01.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of switches.
+ */
+public class Switch01 extends JTTTest {
+
+    public static int test(int arg) {
+        switch (arg) {
+            default:
+                return 1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch02.java
new file mode 100644
index 0000000..76f3151
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Switch02.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of switches.
+ */
+public class Switch02 extends JTTTest {
+    private static char staticCharVal = 0;
+    private static short staticShortVal = 0;
+    private static byte staticByteVal = 0;
+
+    public static int test(int arg) {
+        switch (arg) {
+            case 1:
+                return 2;
+            default:
+                return 1;
+        }
+    }
+
+    public static int test2char(char arg) {
+        int result = 392123;
+        Object x = null;
+        char val = staticCharVal != 0 ? staticCharVal : arg;
+        switch (val) {
+            case (char) 0xFFFF:
+                result = 23212 / val;
+                break;
+            case (char) 0xFFFF - 3:
+                result = 932991439 / val;
+                break;
+            case (char) 0xFFFF - 6:
+                result = 47329561 / val;
+                break;
+            case (char) 0xFFFF - 9:
+                result = 1950976984 / val;
+                break;
+            case (char) 0xFFFF - 10:
+                result = 97105581 / val;
+                switch (result) {
+                    case 1:
+                        result = 321;
+                        break;
+                    default:
+                        result = 2391;
+                        break;
+                }
+                break;
+            case (char) 0xFFFF - 12:
+                result = 99757362 / val;
+                break;
+            case (char) 0xFFFF - 15:
+                result = 912573 / val;
+                x = new LinkedList<>();
+                break;
+            case (char) 0xFFFF - 18:
+                x = new HashSet<>();
+                result = 876765 / val;
+                break;
+            case (char) 0xFFFF - 19:
+                result = 75442917 / val;
+                break;
+            case (char) 0xFFFF - 21:
+                result = 858112498 / val;
+                x = new HashMap<>();
+                break;
+            default:
+                result = 34324341 / val;
+        }
+        result = result + (x == null ? 0 : x.hashCode());
+        return result;
+    }
+
+    public static int test2short(short arg) {
+        int result = 392123;
+        Object x = null;
+        short val = staticShortVal != 0 ? staticShortVal : arg;
+        switch (val) {
+            case (short) -0x7FFF:
+                result = 23212 / val;
+                break;
+            case (short) -0x7FFF + 3:
+                result = 932991439 / val;
+                break;
+            case (short) -0x7FFF + 6:
+                result = 47329561 / val;
+                break;
+            case (short) -0x7FFF + 9:
+                result = 1950976984 / val;
+                break;
+            case (short) -0x7FFF + 10:
+                result = 97105581 / val;
+                switch (result) {
+                    case 1:
+                        result = 321;
+                        break;
+                    default:
+                        result = 2391;
+                        break;
+                }
+                break;
+            case (short) -0x7FFF + 12:
+                result = 99757362 / val;
+                break;
+            case (short) -0x7FFF + 15:
+                result = 912573 / val;
+                x = new LinkedList<>();
+                break;
+            case (short) -0x7FFF + 18:
+                x = new HashSet<>();
+                result = 876765 / val;
+                break;
+            case (short) -0x7FFF + 19:
+                result = 75442917 / val;
+                break;
+            case (short) -0x7FFF + 21:
+                result = 858112498 / val;
+                x = new HashMap<>();
+                break;
+            default:
+                result = 34324341 / val;
+        }
+        result = result + (x == null ? 0 : x.hashCode());
+        return result;
+    }
+
+    public static int test2byte(byte arg) {
+        int result = 392123;
+        Object x = null;
+        byte val = staticByteVal != 0 ? staticByteVal : arg;
+        switch (val) {
+            case (byte) -0x7F:
+                result = 23212 / val;
+                break;
+            case (byte) -0x7F + 3:
+                result = 932991439 / val;
+                break;
+            case (byte) -0x7F + 6:
+                result = 47329561 / val;
+                break;
+            case (byte) -0x7F + 9:
+                result = 1950976984 / val;
+                break;
+            case (byte) -0x7F + 10:
+                result = 97105581 / val;
+                switch (result) {
+                    case 1:
+                        result = 321;
+                        break;
+                    default:
+                        result = 2391;
+                        break;
+                }
+                break;
+            case (byte) -0x7F + 12:
+                result = 99757362 / val;
+                break;
+            case (byte) -0x7F + 15:
+                result = 912573 / val;
+                x = new LinkedList<>();
+                break;
+            case (byte) -0x7F + 18:
+                x = new HashSet<>();
+                result = 876765 / val;
+                break;
+            case (byte) -0x7F + 19:
+                result = 75442917 / val;
+                break;
+            case (byte) -0x7F + 20:
+                result = 856261268 / val;
+                break;
+            case (byte) -0x7F + 21:
+                result = 858112498 / val;
+                x = new HashMap<>();
+                break;
+            default:
+                result = 34324341 / val;
+        }
+        result = result + (x == null ? 0 : x.hashCode());
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test2char", (char) (0x0));
+        runTest("test2char", (char) (0xFFFF));
+        runTest("test2char", (char) (0xFFFF - 21)); // miss
+        runTest("test2char", (char) (0xFFFF - 22)); // hit
+        runTest("test2char", (char) (0xFFFF - 23)); // miss (out of bound)
+
+        staticCharVal = (char) 0xFFFF;
+        runTest("test2char", (char) 0);
+        staticCharVal = (char) (0xFFFF - 21);
+        runTest("test2char", (char) 0xFFFF);
+        staticCharVal = (char) (0xFFFF - 22);
+        runTest("test2char", (char) 0xFFFF);
+        staticCharVal = (char) (0xFFFF - 23);
+        runTest("test2char", (char) 0xFFFF);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test2short", (short) 0x0);
+        runTest("test2short", (short) -0x7FFF);
+        runTest("test2short", (short) (-0x7FFF + 21)); // Miss
+        runTest("test2short", (short) (-0x7FFF + 22)); // hit
+        runTest("test2short", (short) (-0x7FFF + 23)); // miss (out of bound)
+        runTest("test2short", (short) 0x7FFF);         // miss (out of bound)
+
+        staticShortVal = (short) -0x7FFF;
+        runTest("test2short", (short) 0);
+        staticShortVal = (short) (-0x7FFF + 21);
+        runTest("test2short", (short) 0);
+        staticShortVal = (short) (-0x7FFF + 22);
+        runTest("test2short", (short) 0);
+        staticShortVal = (short) (-0x7FFF + 23);
+        runTest("test2short", (short) 0);
+        staticShortVal = (short) 0x7FFF;
+        runTest("test2short", (short) 0);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test2byte", (byte) 0);
+        runTest("test2byte", (byte) -0x7F);
+        runTest("test2byte", (byte) (-0x7F + 21)); // Miss
+        runTest("test2byte", (byte) (-0x7F + 22)); // hit
+        runTest("test2byte", (byte) (-0x7F + 23)); // miss (out of bound)
+        runTest("test2byte", (byte) 0x7F);         // miss (out of bound)
+
+        staticByteVal = (byte) -0x7F;
+        runTest("test2short", (short) 0);
+        staticByteVal = (byte) (-0x7F + 21);
+        runTest("test2short", (short) 0);
+        staticByteVal = (byte) (-0x7F + 22);
+        runTest("test2short", (short) 0);
+        staticByteVal = (byte) (-0x7F + 23);
+        runTest("test2short", (short) 0);
+        staticByteVal = (byte) 0x7F;
+        runTest("test2short", (short) 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TypeCastElem.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TypeCastElem.java
new file mode 100644
index 0000000..dd3ac91
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TypeCastElem.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class TypeCastElem extends JTTTest {
+
+    interface Int1 {
+
+        int do1();
+    }
+
+    interface Int2 {
+
+        int do2();
+    }
+
+    interface Int3 extends Int1 {
+
+        int do3();
+    }
+
+    public static class ClassA implements Int1 {
+
+        private int a;
+
+        public ClassA(int a) {
+            this.a = a;
+        }
+
+        @Override
+        public int do1() {
+            return a;
+        }
+    }
+
+    public static class ClassB extends ClassA implements Int2 {
+
+        int b;
+
+        public ClassB(int a, int b) {
+            super(a);
+            this.b = b;
+        }
+
+        @Override
+        public int do2() {
+            return b;
+        }
+    }
+
+    public static class ClassC implements Int3 {
+
+        private int a;
+        private int b;
+
+        public ClassC(int a, int b) {
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public int do3() {
+            return b;
+        }
+
+        @Override
+        public int do1() {
+            return a;
+        }
+
+    }
+
+    public static int test1(Object o) {
+        if (o instanceof ClassB) {
+            ClassB b = (ClassB) o;
+            if (o instanceof Int1) {
+                return b.b - b.b + 1;
+            }
+            return 7;
+        }
+        return 3;
+    }
+
+    public static int test2(Object o) {
+        Object b = o;
+        if (o instanceof ClassB) {
+            ClassA a = (ClassA) o;
+            if (b instanceof Int1) {
+                return ((Int1) a).do1();
+            }
+            return 7;
+        }
+        return 3;
+    }
+
+    public static int test3(Object o) {
+        Object b = o;
+        boolean t = o instanceof Int3;
+        if (t) {
+            Int1 a = (Int1) b;
+            return a.do1();
+        }
+        return 3;
+    }
+
+    public static int test(int a, int b, int c) {
+        ClassA ca = new ClassA(a);
+        ClassB cb = new ClassB(a, b);
+        ClassC cc = new ClassC(c, c);
+        int sum1 = test1(ca) + test1(cb) * 10 + test1(cc) * 100;
+        int sum2 = test2(ca) + test2(cb) * 10 + test2(cc) * 100;
+        int sum3 = test3(ca) + test3(cb) * 10 + test3(cc) * 100;
+        int result = sum1 * 5 + sum2 * 7 + sum3 * 9;
+        return result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 10, 13, 25);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/UnsafeDeopt.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/UnsafeDeopt.java
new file mode 100644
index 0000000..929bb24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/UnsafeDeopt.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+
+import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.jtt.JTTTest;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+public class UnsafeDeopt extends JTTTest {
+    private static final Unsafe unsafe;
+
+    static {
+        try {
+            final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+            unsafeField.setAccessible(true);
+            unsafe = (Unsafe) unsafeField.get(null);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
+    public static int readWriteReadUnsafe(long addr, int m) {
+        int original = unsafe.getInt(addr);
+        if (original != 0) {
+            return -m;
+        }
+        unsafe.putInt(addr, m);
+        if (m > 10) {
+            if (m > 20) {
+                GraalDirectives.deoptimize();
+            }
+            unsafe.putInt(addr + 4, m);
+        }
+        return unsafe.getInt(addr);
+    }
+
+    public static int readWriteReadByteBuffer(ByteBuffer buffer, int m) {
+        int original = buffer.getInt(0);
+        if (original != 0) {
+            return -m;
+        }
+        buffer.putInt(0, m);
+        if (m > 10) {
+            if (m > 20) {
+                GraalDirectives.deoptimize();
+                buffer.putInt(4, m);
+            }
+        }
+        return buffer.getInt(0);
+    }
+
+    public long createBuffer() {
+        long addr = unsafe.allocateMemory(32);
+        unsafe.setMemory(addr, 32, (byte) 0);
+        return addr;
+    }
+
+    public void disposeBuffer(long addr) {
+        unsafe.freeMemory(addr);
+    }
+
+    @Test
+    public void testUnsafe() {
+        int m = 42;
+        long addr1 = createBuffer();
+        long addr2 = createBuffer();
+        try {
+            ResolvedJavaMethod method = getResolvedJavaMethod("readWriteReadUnsafe");
+            Object receiver = method.isStatic() ? null : this;
+            Result expect = executeExpected(method, receiver, addr1, m);
+            if (getCodeCache() == null) {
+                return;
+            }
+            testAgainstExpected(method, expect, receiver, addr2, m);
+        } catch (AssumptionViolatedException e) {
+            // Suppress so that subsequent calls to this method within the
+            // same Junit @Test annotated method can proceed.
+        } finally {
+            disposeBuffer(addr1);
+            disposeBuffer(addr2);
+        }
+    }
+
+    @Test
+    public void testByteBuffer() {
+        int m = 42;
+        try {
+            ResolvedJavaMethod method = getResolvedJavaMethod("readWriteReadByteBuffer");
+            Object receiver = method.isStatic() ? null : this;
+            Result expect = executeExpected(method, receiver, ByteBuffer.allocateDirect(32), m);
+            if (getCodeCache() == null) {
+                return;
+            }
+            ByteBuffer warmupBuffer = ByteBuffer.allocateDirect(32);
+            for (int i = 0; i < 10000; ++i) {
+                readWriteReadByteBuffer(warmupBuffer, (i % 50) + 1);
+                warmupBuffer.putInt(0, 0);
+            }
+            testAgainstExpected(method, expect, receiver, ByteBuffer.allocateDirect(32), m);
+        } catch (AssumptionViolatedException e) {
+            // Suppress so that subsequent calls to this method within the
+            // same Junit @Test annotated method can proceed.
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast01.java
new file mode 100644
index 0000000..dd81fbc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast01.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class VN_Cast01 extends JTTTest {
+
+    private static class TestClass {
+        int field = 9;
+    }
+
+    static final Object object = new TestClass();
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return test1();
+        }
+        if (arg == 1) {
+            return test2();
+        }
+        if (arg == 2) {
+            return test3();
+        }
+        return 0;
+    }
+
+    private static int test1() {
+        Object o = object;
+        TestClass a = (TestClass) o;
+        TestClass b = (TestClass) o;
+        return a.field + b.field;
+    }
+
+    private static int test2() {
+        Object obj = new TestClass();
+        TestClass a = (TestClass) obj;
+        TestClass b = (TestClass) obj;
+        return a.field + b.field;
+    }
+
+    @SuppressWarnings("all")
+    private static int test3() {
+        Object o = null;
+        TestClass a = (TestClass) o;
+        TestClass b = (TestClass) o;
+        return a.field + b.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast02.java
new file mode 100644
index 0000000..57ba97a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Cast02.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class VN_Cast02 extends JTTTest {
+
+    private static class TestClass {
+        int field = 9;
+    }
+
+    private static boolean cond = true;
+    static final Object object = new TestClass();
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return test1();
+        }
+        if (arg == 1) {
+            return test2();
+        }
+        if (arg == 2) {
+            return test3();
+        }
+        return 0;
+    }
+
+    private static int test1() {
+        Object o = object;
+        TestClass a = (TestClass) o;
+        if (cond) {
+            TestClass b = (TestClass) o;
+            return a.field + b.field;
+        }
+        return 0;
+    }
+
+    private static int test2() {
+        Object obj = new TestClass();
+        TestClass a = (TestClass) obj;
+        if (cond) {
+            TestClass b = (TestClass) obj;
+            return a.field + b.field;
+        }
+        return 0;
+    }
+
+    @SuppressWarnings("all")
+    private static int test3() {
+        Object o = null;
+        TestClass a = (TestClass) o;
+        if (cond) {
+            TestClass b = (TestClass) o;
+            return a.field + b.field;
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert01.java
new file mode 100644
index 0000000..5ed8da5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert01.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization integer conversions.
+ */
+public class VN_Convert01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return i2b(arg + 10);
+        }
+        if (arg == 1) {
+            return i2s(arg + 10);
+        }
+        if (arg == 2) {
+            return i2c(arg + 10);
+        }
+        return 0;
+    }
+
+    public static int i2b(int arg) {
+        int x = (byte) arg;
+        int y = (byte) arg;
+        return x + y;
+    }
+
+    public static int i2s(int arg) {
+        int x = (short) arg;
+        int y = (short) arg;
+        return x + y;
+    }
+
+    public static int i2c(int arg) {
+        int x = (char) arg;
+        int y = (char) arg;
+        return x + y;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert02.java
new file mode 100644
index 0000000..2b8e59b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Convert02.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization integer conversions.
+ */
+public class VN_Convert02 extends JTTTest {
+
+    private static boolean cond = true;
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return i2b(arg + 10);
+        }
+        if (arg == 1) {
+            return i2s(arg + 10);
+        }
+        if (arg == 2) {
+            return i2c(arg + 10);
+        }
+        return 0;
+    }
+
+    public static int i2b(int arg) {
+        int x = (byte) arg;
+        if (cond) {
+            int y = (byte) arg;
+            return x + y;
+        }
+        return 0;
+    }
+
+    public static int i2s(int arg) {
+        int x = (short) arg;
+        if (cond) {
+            int y = (short) arg;
+            return x + y;
+        }
+        return 0;
+    }
+
+    public static int i2c(int arg) {
+        int x = (char) arg;
+        if (cond) {
+            int y = (char) arg;
+            return x + y;
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double01.java
new file mode 100644
index 0000000..47d0ca1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double01.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of float operations.
+ */
+public class VN_Double01 extends JTTTest {
+
+    public static double test(double arg) {
+        if (arg == 0) {
+            return add(arg + 10);
+        }
+        if (arg == 1) {
+            return sub(arg + 10);
+        }
+        if (arg == 2) {
+            return mul(arg + 10);
+        }
+        if (arg == 3) {
+            return div(arg + 10);
+        }
+        return 0;
+    }
+
+    public static double add(double x) {
+        double c = 1;
+        double t = x + c;
+        double u = x + c;
+        return t + u;
+    }
+
+    public static double sub(double x) {
+        double c = 1;
+        double t = x - c;
+        double u = x - c;
+        return t - u;
+    }
+
+    public static double mul(double x) {
+        double c = 1;
+        double t = x * c;
+        double u = x * c;
+        return t * u;
+    }
+
+    public static double div(double x) {
+        double c = 1;
+        double t = x / c;
+        double u = x / c;
+        return t / u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double02.java
new file mode 100644
index 0000000..55ea328
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Double02.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of float operations.
+ */
+public class VN_Double02 extends JTTTest {
+
+    private static boolean cond = true;
+
+    public static double test(double arg) {
+        if (arg == 0) {
+            return add(arg + 10);
+        }
+        if (arg == 1) {
+            return sub(arg + 10);
+        }
+        if (arg == 2) {
+            return mul(arg + 10);
+        }
+        if (arg == 3) {
+            return div(arg + 10);
+        }
+        return 0;
+    }
+
+    public static double add(double x) {
+        double c = 1.0d;
+        double t = x + c;
+        if (cond) {
+            double u = x + c;
+            return t + u;
+        }
+        return 1;
+    }
+
+    public static double sub(double x) {
+        double c = 1.0d;
+        double t = x - c;
+        if (cond) {
+            double u = x - c;
+            return t - u;
+        }
+        return 1;
+    }
+
+    public static double mul(double x) {
+        double c = 1.0d;
+        double t = x * c;
+        if (cond) {
+            double u = x * c;
+            return t * u;
+        }
+        return 1.0d;
+    }
+
+    public static double div(double x) {
+        double c = 1.0d;
+        double t = x / c;
+        if (cond) {
+            double u = x / c;
+            return t / u;
+        }
+        return 1.0d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field01.java
new file mode 100644
index 0000000..01d1d95
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field01.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class VN_Field01 extends JTTTest {
+
+    private static class TestClass {
+        int field = 9;
+    }
+
+    static final TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return test1();
+        }
+        if (arg == 1) {
+            return test2();
+        }
+        if (arg == 2) {
+            return test3();
+        }
+        return 0;
+    }
+
+    private static int test1() {
+        TestClass a = object;
+        return a.field + a.field;
+    }
+
+    private static int test2() {
+        TestClass a = object;
+        TestClass b = object;
+        return a.field + b.field;
+    }
+
+    @SuppressWarnings("all")
+    private static int test3() {
+        TestClass a = null;
+        TestClass b = null;
+        return a.field + b.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field02.java
new file mode 100644
index 0000000..639d406
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Field02.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of integer operations.
+ */
+public class VN_Field02 extends JTTTest {
+
+    private static class TestClass {
+        int field = 9;
+    }
+
+    private static boolean cond = true;
+    static final TestClass object = new TestClass();
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return test1();
+        }
+        if (arg == 1) {
+            return test2();
+        }
+        if (arg == 2) {
+            return test3();
+        }
+        return 0;
+    }
+
+    private static int test1() {
+        TestClass a = object;
+        int c = a.field;
+        if (cond) {
+            return c + a.field;
+        }
+        return 0;
+    }
+
+    private static int test2() {
+        TestClass a = object;
+        if (cond) {
+            TestClass b = object;
+            return a.field + b.field;
+        }
+        return 0;
+    }
+
+    @SuppressWarnings("all")
+    private static int test3() {
+        TestClass a = null;
+        if (cond) {
+            TestClass b = null;
+            return a.field + b.field;
+        }
+        return 0;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float01.java
new file mode 100644
index 0000000..9898c0a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float01.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of float operations.
+ */
+public class VN_Float01 extends JTTTest {
+
+    public static float test(float arg) {
+        if (arg == 0) {
+            return add(arg + 10);
+        }
+        if (arg == 1) {
+            return sub(arg + 10);
+        }
+        if (arg == 2) {
+            return mul(arg + 10);
+        }
+        if (arg == 3) {
+            return div(arg + 10);
+        }
+        return 0;
+    }
+
+    public static float add(float x) {
+        float c = 1;
+        float t = x + c;
+        float u = x + c;
+        return t + u;
+    }
+
+    public static float sub(float x) {
+        float c = 1;
+        float t = x - c;
+        float u = x - c;
+        return t - u;
+    }
+
+    public static float mul(float x) {
+        float c = 1;
+        float t = x * c;
+        float u = x * c;
+        return t * u;
+    }
+
+    public static float div(float x) {
+        float c = 1;
+        float t = x / c;
+        float u = x / c;
+        return t / u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float02.java
new file mode 100644
index 0000000..7c7f5f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Float02.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of float operations.
+ */
+public class VN_Float02 extends JTTTest {
+
+    private static boolean cond = true;
+
+    public static float test(float arg) {
+        if (arg == 0) {
+            return add(arg + 10);
+        }
+        if (arg == 1) {
+            return sub(arg + 10);
+        }
+        if (arg == 2) {
+            return mul(arg + 10);
+        }
+        if (arg == 3) {
+            return div(arg + 10);
+        }
+        return 0;
+    }
+
+    public static float add(float x) {
+        float c = 1.0f;
+        float t = x + c;
+        if (cond) {
+            float u = x + c;
+            return t + u;
+        }
+        return 1.0f;
+    }
+
+    public static float sub(float x) {
+        float c = 1.0f;
+        float t = x - c;
+        if (cond) {
+            float u = x - c;
+            return t - u;
+        }
+        return 1.0f;
+    }
+
+    public static float mul(float x) {
+        float c = 1.0f;
+        float t = x * c;
+        if (cond) {
+            float u = x * c;
+            return t * u;
+        }
+        return 1.0f;
+    }
+
+    public static float div(float x) {
+        float c = 1.0f;
+        float t = x / c;
+        if (cond) {
+            float u = x / c;
+            return t / u;
+        }
+        return 1.0f;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf01.java
new file mode 100644
index 0000000..6b5d9ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf01.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of instanceof operations.
+ */
+public class VN_InstanceOf01 extends JTTTest {
+
+    static final Object object = new DummyTestClass();
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return foo1();
+        }
+        if (arg == 1) {
+            return foo2();
+        }
+        if (arg == 2) {
+            return foo3();
+        }
+        // do nothing
+        return false;
+    }
+
+    private static boolean foo1() {
+        boolean a = object instanceof DummyTestClass;
+        boolean b = object instanceof DummyTestClass;
+        return a | b;
+    }
+
+    private static boolean foo2() {
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
+        boolean b = obj instanceof DummyTestClass;
+        return a | b;
+    }
+
+    private static boolean foo3() {
+        boolean a = null instanceof DummyTestClass;
+        boolean b = null instanceof DummyTestClass;
+        return a | b;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf02.java
new file mode 100644
index 0000000..3b66a0a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf02.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of instanceof operations.
+ */
+public class VN_InstanceOf02 extends JTTTest {
+
+    private static boolean cond = true;
+
+    static final Object object = new DummyTestClass();
+
+    public static boolean test(int arg) {
+        if (arg == 0) {
+            return foo1();
+        }
+        if (arg == 1) {
+            return foo2();
+        }
+        if (arg == 2) {
+            return foo3();
+        }
+        // do nothing
+        return false;
+    }
+
+    private static boolean foo1() {
+        boolean a = object instanceof DummyTestClass;
+        if (cond) {
+            boolean b = object instanceof DummyTestClass;
+            return a | b;
+        }
+        return false;
+    }
+
+    private static boolean foo2() {
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
+        if (cond) {
+            boolean b = obj instanceof DummyTestClass;
+            return a | b;
+        }
+        return false;
+    }
+
+    private static boolean foo3() {
+        boolean a = null instanceof DummyTestClass;
+        if (cond) {
+            boolean b = null instanceof DummyTestClass;
+            return a | b;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf03.java
new file mode 100644
index 0000000..30cb4ad
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_InstanceOf03.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of instanceof operations.
+ */
+public class VN_InstanceOf03 extends JTTTest {
+
+    private static boolean cond = true;
+
+    static final Object object = new DummyTestClass();
+
+    public static boolean test() {
+        return foo();
+    }
+
+    private static boolean foo() {
+        Object obj = new DummyTestClass();
+        boolean a = obj instanceof DummyTestClass;
+        if (cond) {
+            boolean b = obj instanceof DummyTestClass;
+            return a | b;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int01.java
new file mode 100644
index 0000000..5be3c59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int01.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of integer operations.
+ */
+public class VN_Int01 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add(arg);
+        }
+        if (arg == 1) {
+            return sub(arg);
+        }
+        if (arg == 2) {
+            return mul(arg);
+        }
+        if (arg == 3) {
+            return div(arg);
+        }
+        if (arg == 4) {
+            return mod(arg);
+        }
+        if (arg == 5) {
+            return and(arg);
+        }
+        if (arg == 6) {
+            return or(arg);
+        }
+        if (arg == 7) {
+            return xor(arg);
+        }
+        return 0;
+    }
+
+    public static int add(int x) {
+        int c = 3;
+        int t = x + c;
+        int u = x + c;
+        return t + u;
+    }
+
+    public static int sub(int x) {
+        int c = 3;
+        int t = x - c;
+        int u = x - c;
+        return t - u;
+    }
+
+    public static int mul(int x) {
+        int i = 3;
+        int t = x * i;
+        int u = x * i;
+        return t * u;
+    }
+
+    public static int div(int x) {
+        int i = 9;
+        int t = i / x;
+        int u = i / x;
+        return t / u;
+    }
+
+    public static int mod(int x) {
+        int i = 7;
+        int t = i % x;
+        int u = i % x;
+        return t % u;
+    }
+
+    public static int and(int x) {
+        int i = 7;
+        int t = i & x;
+        int u = i & x;
+        return t & u;
+    }
+
+    public static int or(int x) {
+        int i = 7;
+        int t = i | x;
+        int u = i | x;
+        return t | u;
+    }
+
+    public static int xor(int x) {
+        int i = 7;
+        int t = i ^ x;
+        int u = i ^ x;
+        return t ^ u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int02.java
new file mode 100644
index 0000000..bbb920b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int02.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class VN_Int02 extends JTTTest {
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return shift0(arg + 10);
+        }
+        if (arg == 1) {
+            return shift1(arg + 10);
+        }
+        if (arg == 2) {
+            return shift2(arg + 10);
+        }
+        return 0;
+    }
+
+    public static int shift0(int x) {
+        int c = 1;
+        int t = x >> c;
+        int u = x >> c;
+        return t + u;
+    }
+
+    public static int shift1(int x) {
+        int c = 1;
+        int t = x >>> c;
+        int u = x >>> c;
+        return t + u;
+    }
+
+    public static int shift2(int x) {
+        int c = 1;
+        int t = x << c;
+        int u = x << c;
+        return t + u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int03.java
new file mode 100644
index 0000000..c56ecfc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Int03.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of integer operations.
+ */
+public class VN_Int03 extends JTTTest {
+
+    private static boolean cond = true;
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return add(arg);
+        }
+        if (arg == 1) {
+            return sub(arg);
+        }
+        if (arg == 2) {
+            return mul(arg);
+        }
+        if (arg == 3) {
+            return div(arg);
+        }
+        if (arg == 4) {
+            return mod(arg);
+        }
+        if (arg == 5) {
+            return and(arg);
+        }
+        if (arg == 6) {
+            return or(arg);
+        }
+        if (arg == 7) {
+            return xor(arg);
+        }
+        return 0;
+    }
+
+    public static int add(int x) {
+        int c = 3;
+        int t = x + c;
+        if (cond) {
+            int u = x + c;
+            return t + u;
+        }
+        return 0;
+    }
+
+    public static int sub(int x) {
+        int c = 3;
+        int t = x - c;
+        if (cond) {
+            int u = x - c;
+            return t - u;
+        }
+        return 3;
+    }
+
+    public static int mul(int x) {
+        int i = 3;
+        int t = x * i;
+        if (cond) {
+            int u = x * i;
+            return t * u;
+        }
+        return 3;
+    }
+
+    public static int div(int x) {
+        int i = 9;
+        int t = i / x;
+        if (cond) {
+            int u = i / x;
+            return t / u;
+        }
+        return 9;
+    }
+
+    public static int mod(int x) {
+        int i = 7;
+        int t = i % x;
+        if (cond) {
+            int u = i % x;
+            return t % u;
+        }
+        return 7;
+    }
+
+    public static int and(int x) {
+        int i = 7;
+        int t = i & x;
+        if (cond) {
+            int u = i & x;
+            return t & u;
+        }
+        return 7;
+    }
+
+    public static int or(int x) {
+        int i = 7;
+        int t = i | x;
+        if (cond) {
+            int u = i | x;
+            return t | u;
+        }
+        return 7;
+    }
+
+    public static int xor(int x) {
+        int i = 7;
+        int t = i ^ x;
+        if (cond) {
+            int u = i ^ x;
+            return t ^ u;
+        }
+        return 7;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long01.java
new file mode 100644
index 0000000..c28b941
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long01.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of long operations.
+ */
+public class VN_Long01 extends JTTTest {
+
+    public static long test(int arg) {
+        if (arg == 0) {
+            return add(arg);
+        }
+        if (arg == 1) {
+            return sub(arg);
+        }
+        if (arg == 2) {
+            return mul(arg);
+        }
+        if (arg == 3) {
+            return div(arg);
+        }
+        if (arg == 4) {
+            return mod(arg);
+        }
+        if (arg == 5) {
+            return and(arg);
+        }
+        if (arg == 6) {
+            return or(arg);
+        }
+        if (arg == 7) {
+            return xor(arg);
+        }
+        return 0;
+    }
+
+    public static long add(long x) {
+        long t = x + 3;
+        long u = x + 3;
+        return t + u;
+    }
+
+    public static long sub(long x) {
+        long t = x - 3;
+        long u = x - 3;
+        return t - u;
+    }
+
+    public static long mul(long x) {
+        long t = x * 3;
+        long u = x * 3;
+        return t * u;
+    }
+
+    public static long div(long x) {
+        long t = 9 / x;
+        long u = 9 / x;
+        return t / u;
+    }
+
+    public static long mod(long x) {
+        long t = 7 % x;
+        long u = 7 % x;
+        return t % u;
+    }
+
+    public static long and(long x) {
+        long t = 7 & x;
+        long u = 7 & x;
+        return t & u;
+    }
+
+    public static long or(long x) {
+        long t = 7 | x;
+        long u = 7 | x;
+        return t | u;
+    }
+
+    public static long xor(long x) {
+        long t = 7 ^ x;
+        long u = 7 ^ x;
+        return t ^ u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long02.java
new file mode 100644
index 0000000..f2c48e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long02.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests optimization of integer operations.
+ */
+public class VN_Long02 extends JTTTest {
+
+    public static long test(int arg) {
+        if (arg == 0) {
+            return shift0(arg + 10);
+        }
+        if (arg == 1) {
+            return shift1(arg + 10);
+        }
+        if (arg == 2) {
+            return shift2(arg + 10);
+        }
+        return 0;
+    }
+
+    public static long shift0(long x) {
+        long c = 1;
+        long t = x >> c;
+        long u = x >> c;
+        return t + u;
+    }
+
+    public static long shift1(long x) {
+        long c = 1;
+        long t = x >>> c;
+        long u = x >>> c;
+        return t + u;
+    }
+
+    public static long shift2(long x) {
+        long c = 1;
+        long t = x << c;
+        long u = x << c;
+        return t + u;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long03.java
new file mode 100644
index 0000000..122d4ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Long03.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of long operations.
+ */
+public class VN_Long03 extends JTTTest {
+
+    private static boolean cond = true;
+
+    public static long test(int arg) {
+        if (arg == 0) {
+            return add(arg);
+        }
+        if (arg == 1) {
+            return sub(arg);
+        }
+        if (arg == 2) {
+            return mul(arg);
+        }
+        if (arg == 3) {
+            return div(arg);
+        }
+        if (arg == 4) {
+            return mod(arg);
+        }
+        if (arg == 5) {
+            return and(arg);
+        }
+        if (arg == 6) {
+            return or(arg);
+        }
+        if (arg == 7) {
+            return xor(arg);
+        }
+        return 0;
+    }
+
+    public static long add(long x) {
+        long t = x + 3;
+        if (cond) {
+            long u = x + 3;
+            return t + u;
+        }
+        return 3;
+    }
+
+    public static long sub(long x) {
+        long t = x - 3;
+        if (cond) {
+            long u = x - 3;
+            return t - u;
+        }
+        return 3;
+    }
+
+    public static long mul(long x) {
+        long t = x * 3;
+        if (cond) {
+            long u = x * 3;
+            return t * u;
+        }
+        return 3;
+    }
+
+    public static long div(long x) {
+        long t = 9 / x;
+        if (cond) {
+            long u = 9 / x;
+            return t / u;
+        }
+        return 9;
+    }
+
+    public static long mod(long x) {
+        long t = 7 % x;
+        if (cond) {
+            long u = 7 % x;
+            return t % u;
+        }
+        return 7;
+    }
+
+    public static long and(long x) {
+        long t = 7 & x;
+        if (cond) {
+            long u = 7 & x;
+            return t & u;
+        }
+        return 7;
+    }
+
+    public static long or(long x) {
+        long t = 7 | x;
+        if (cond) {
+            long u = 7 | x;
+            return t | u;
+        }
+        return 7;
+    }
+
+    public static long xor(long x) {
+        long t = 7 ^ x;
+        if (cond) {
+            long u = 7 ^ x;
+            return t ^ u;
+        }
+        return 7;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Loop01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Loop01.java
new file mode 100644
index 0000000..940a5b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/VN_Loop01.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests value numbering of integer operations.
+ */
+public class VN_Loop01 extends JTTTest {
+
+    private static boolean cond1 = true;
+    private static boolean cond2 = true;
+
+    public static int test(int arg) {
+        if (arg == 0) {
+            return test1(arg);
+        }
+        if (arg == 1) {
+            return test2(arg);
+        }
+        if (arg == 2) {
+            return test3(arg);
+        }
+        if (arg == 3) {
+            return test4(arg);
+        }
+        return 0;
+    }
+
+    public static int test1(int x) {
+        int c = 3;
+        int t = x + c;
+        while (cond1) {
+            if (cond2) {
+                int u = x + c; // GVN should recognize u == t
+                return t + u;
+            }
+        }
+        return 3; // GVN should recognize 3 == 3
+    }
+
+    public static int test2(int x) {
+        int c = 3;
+        while (cond1) {
+            int t = x + c;
+            if (cond2) {
+                int u = x + c; // GVN should recognize u == t
+                return t + u;
+            }
+        }
+        return 3;
+    }
+
+    public static int test3(int x) {
+        int c = 3;
+        int t = x + c;
+        while (cond1) {
+            if (cond2) {
+                int u = x + c; // GVN should recognize u == t
+                return t + u;
+            }
+            int u = x + c; // GVN should recognize u == t
+            return t + u;
+        }
+        return 3; // GVN should recognize 3 == 3
+    }
+
+    public static int test4(int x) {
+        int c = 3;
+        int t = x + c;
+        while (cond1) {
+            if (!cond2) {
+                int u = x + c;
+                return t + u;
+            }
+            int u = x + c;
+            return t + u;
+        }
+        return 3;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get01.java
new file mode 100644
index 0000000..e46512b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_get01 extends JTTTest {
+
+    private static final String[] array = {"0", "1", "2"};
+
+    public static String test(int i) {
+        return (String) Array.get(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get02.java
new file mode 100644
index 0000000..fdc5053
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get02.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_get02 extends JTTTest {
+
+    private static final int[] array = {11, 21, 42};
+
+    public static int test(int i) {
+        return (Integer) Array.get(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get03.java
new file mode 100644
index 0000000..3aa3688
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_get03.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_get03 extends JTTTest {
+
+    private static final byte[] array = {11, 21, 42};
+
+    public static byte test(int i) {
+        return (Byte) Array.get(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getBoolean01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getBoolean01.java
new file mode 100644
index 0000000..9a3d196
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getBoolean01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getBoolean01 extends JTTTest {
+
+    private static final boolean[] array = {true, false, true};
+
+    public static boolean test(int i) {
+        return Array.getBoolean(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getByte01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getByte01.java
new file mode 100644
index 0000000..35ed92f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getByte01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getByte01 extends JTTTest {
+
+    private static final byte[] array = {11, 21, 42};
+
+    public static byte test(int i) {
+        return Array.getByte(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getChar01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getChar01.java
new file mode 100644
index 0000000..7cbe238
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getChar01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getChar01 extends JTTTest {
+
+    private static final char[] array = {11, 21, 42};
+
+    public static char test(int i) {
+        return Array.getChar(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getDouble01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getDouble01.java
new file mode 100644
index 0000000..20e2fec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getDouble01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getDouble01 extends JTTTest {
+
+    private static final double[] array = {11.1d, 21.1d, 42.1d};
+
+    public static double test(int i) {
+        return Array.getDouble(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getFloat01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getFloat01.java
new file mode 100644
index 0000000..b7cf07f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getFloat01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getFloat01 extends JTTTest {
+
+    private static final float[] array = {11.1f, 21.1f, 42.1f};
+
+    public static float test(int i) {
+        return Array.getFloat(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getInt01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getInt01.java
new file mode 100644
index 0000000..1d49d48
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getInt01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getInt01 extends JTTTest {
+
+    private static final int[] array = {11, 21, 42};
+
+    public static int test(int i) {
+        return Array.getInt(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLength01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLength01.java
new file mode 100644
index 0000000..9758cab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLength01.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getLength01 extends JTTTest {
+
+    private static final int[] array0 = {11, 21, 42};
+    private static final boolean[] array1 = {true, true, false, false};
+    private static final String[] array2 = {"String"};
+
+    public static int test(int i) {
+        Object array = null;
+        if (i == 0) {
+            array = array0;
+        } else if (i == 1) {
+            array = array1;
+        } else if (i == 2) {
+            array = array2;
+        }
+        return Array.getLength(array);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLong01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLong01.java
new file mode 100644
index 0000000..0b81319
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getLong01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getLong01 extends JTTTest {
+
+    private static final long[] array = {11, 21, 42};
+
+    public static long test(int i) {
+        return Array.getLong(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getShort01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getShort01.java
new file mode 100644
index 0000000..0b63586
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_getShort01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_getShort01 extends JTTTest {
+
+    private static final short[] array = {11, 21, 42};
+
+    public static short test(int i) {
+        return Array.getShort(array, i);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance01.java
new file mode 100644
index 0000000..8e7ea40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance01.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance01 extends JTTTest {
+
+    public static boolean test(int i) {
+        return Array.newInstance(Array_newInstance01.class, i) != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance02.java
new file mode 100644
index 0000000..aa2e62e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance02.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance02 extends JTTTest {
+
+    public static boolean test(int i) {
+        Class<?> javaClass;
+        if (i == 2) {
+            javaClass = void.class;
+        } else if (i == 3) {
+            javaClass = null;
+        } else {
+            javaClass = int.class;
+        }
+        return Array.newInstance(javaClass, 0) != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance03.java
new file mode 100644
index 0000000..d551c23
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance03.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance03 extends JTTTest {
+
+    public static boolean test(int i) {
+        Class<?> javaClass;
+        if (i == 2) {
+            javaClass = int.class;
+        } else if (i == 3) {
+            javaClass = Object.class;
+        } else {
+            javaClass = Array_newInstance03.class;
+        }
+        return Array.newInstance(javaClass, 0).getClass().getComponentType() == javaClass;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance04.java
new file mode 100644
index 0000000..898c936
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance04.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance04 extends JTTTest {
+
+    public static boolean test(int i, int j) {
+        final int[] dims = {i, j};
+        return Array.newInstance(Array_newInstance04.class, dims) != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2, 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3, 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 0, -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance05.java
new file mode 100644
index 0000000..fdf411d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance05.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance05 extends JTTTest {
+
+    public static boolean test(int i, int j) {
+        final int[] dims = {i, j};
+        Class<?> javaClass;
+        if (i == 2) {
+            javaClass = void.class;
+        } else if (i == 3) {
+            javaClass = null;
+        } else {
+            javaClass = int.class;
+        }
+        return Array.newInstance(javaClass, dims) != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1, 3);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2, 3);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3, 4);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 1, -1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance06.java
new file mode 100644
index 0000000..7424f8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_newInstance06.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_newInstance06 extends JTTTest {
+
+    public static boolean test(int i) {
+        final int[] dims = {i, 3};
+        Class<?> javaClass;
+        if (i == 2) {
+            javaClass = int.class;
+        } else if (i == 3) {
+            javaClass = Object.class;
+        } else {
+            javaClass = Array_newInstance06.class;
+        }
+        return Array.newInstance(javaClass, dims).getClass().getComponentType().getComponentType() == javaClass;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set01.java
new file mode 100644
index 0000000..f6d5e17
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_set01 extends JTTTest {
+
+    private static final String[] array = {"x", "x", "x"};
+
+    public static String test(int i, String value) {
+        Array.set(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, "1");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, "2");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, "XXd");
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, "--");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set02.java
new file mode 100644
index 0000000..efde54e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set02.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_set02 extends JTTTest {
+
+    private static final int[] array = {-1, -1, -1};
+
+    public static int test(int i, int value) {
+        Array.set(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 11);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 21);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 42);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set03.java
new file mode 100644
index 0000000..1e323dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_set03.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_set03 extends JTTTest {
+
+    private static final byte[] array = {-1, -1, -1};
+
+    public static byte test(int i, byte value) {
+        Array.set(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((byte) 11));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((byte) 21));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((byte) 42));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((byte) 0));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setBoolean01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setBoolean01.java
new file mode 100644
index 0000000..448d33b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setBoolean01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setBoolean01 extends JTTTest {
+
+    private static final boolean[] array = {false, false, false};
+
+    public static boolean test(int i, boolean value) {
+        Array.setBoolean(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, true);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, false);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2, true);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, false);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setByte01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setByte01.java
new file mode 100644
index 0000000..3fef03b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setByte01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setByte01 extends JTTTest {
+
+    private static final byte[] array = {-1, -1, -1};
+
+    public static byte test(int i, byte value) {
+        Array.setByte(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((byte) 11));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((byte) 21));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((byte) 42));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((byte) 0));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setChar01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setChar01.java
new file mode 100644
index 0000000..b0701dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setChar01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setChar01 extends JTTTest {
+
+    private static final char[] array = {0, 0, 0};
+
+    public static char test(int i, char value) {
+        Array.setChar(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((char) 11));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((char) 21));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((char) 42));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((char) 0));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setDouble01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setDouble01.java
new file mode 100644
index 0000000..835832a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setDouble01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setDouble01 extends JTTTest {
+
+    private static final double[] array = {-1, -1, -1};
+
+    public static double test(int i, double value) {
+        Array.setDouble(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 11.1d);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 21.1d);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 42.1d);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 0.1d);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setFloat01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setFloat01.java
new file mode 100644
index 0000000..56125bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setFloat01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setFloat01 extends JTTTest {
+
+    private static final float[] array = {-1, -1, -1};
+
+    public static float test(int i, float value) {
+        Array.setFloat(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 11.1f);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 21.1f);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 42.1f);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 0.1f);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setInt01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setInt01.java
new file mode 100644
index 0000000..f671a8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setInt01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setInt01 extends JTTTest {
+
+    private static final int[] array = {-1, -1, -1};
+
+    public static int test(int i, int value) {
+        Array.setInt(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 11);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 21);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 42);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setLong01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setLong01.java
new file mode 100644
index 0000000..e4bc223
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setLong01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setLong01 extends JTTTest {
+
+    private static final long[] array = {-1, -1, -1};
+
+    public static long test(int i, long value) {
+        Array.setLong(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 11L);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, 21L);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, 42L);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, 0L);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setShort01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setShort01.java
new file mode 100644
index 0000000..fae3abd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Array_setShort01.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Array_setShort01 extends JTTTest {
+
+    private static final short[] array = {-1, -1, -1};
+
+    public static short test(int i, short value) {
+        Array.setShort(array, i, value);
+        return array[i];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, ((short) 11));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1, ((short) 21));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 0, ((short) 42));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3, ((short) 0));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredField01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredField01.java
new file mode 100644
index 0000000..9666d5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredField01.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getDeclaredField01 extends JTTTest {
+
+    static String field;
+    static int f2;
+
+    public static String test(String input) throws NoSuchFieldException {
+        return Class_getDeclaredField01.class.getDeclaredField(input).getName();
+    }
+
+    public static void main(String[] args) {
+        field = args[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "field");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "f2");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredMethod01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredMethod01.java
new file mode 100644
index 0000000..3cf9039
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getDeclaredMethod01.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getDeclaredMethod01 extends JTTTest {
+
+    static String field;
+
+    public static String test(String input) throws NoSuchMethodException {
+        return Class_getDeclaredMethod01.class.getDeclaredMethod(input, String[].class).getName();
+    }
+
+    public static void main(String[] args) {
+        field = args[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "main");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "xx");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField01.java
new file mode 100644
index 0000000..cb756cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getField01 extends JTTTest {
+
+    public static String field;
+    public String field2;
+    String field3;
+
+    public static String test(String input) throws NoSuchFieldException {
+        return Class_getField01.class.getField(input).getName();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "field");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "field2");
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", "field3");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField02.java
new file mode 100644
index 0000000..1cf1270
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getField02.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getField02 extends JTTTest {
+
+    public static String field;
+    public String field2;
+    String field3;
+
+    public static String test(String input) throws NoSuchFieldException {
+        return Class_getField02b.class.getField(input).getName();
+    }
+
+    static class Class_getField02b extends Class_getField02 {
+
+        public String field4;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "field");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "field2");
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", "field3");
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", "field4");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod01.java
new file mode 100644
index 0000000..32a4232
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod01.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getMethod01 extends JTTTest {
+
+    static String field;
+
+    public static String test(String input) throws NoSuchMethodException {
+        return Class_getMethod01.class.getMethod(input, String[].class).getName();
+    }
+
+    public static void main(String[] args) {
+        field = args[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "main");
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", "xx");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod02.java
new file mode 100644
index 0000000..b40292d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_getMethod02.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Class_getMethod02 extends JTTTest {
+
+    static String field;
+
+    public static String test(int arg) throws NoSuchMethodException {
+        if (arg == 0) {
+            return Class_getMethod02.class.getMethod("test").getName();
+        } else if (arg == 1) {
+            return Class_getMethod02.class.getMethod("test", int.class).getName();
+        } else if (arg == 2) {
+            return Class_getMethod02.class.getMethod("main").getName();
+        } else if (arg == 3) {
+            return Class_getMethod02.class.getMethod("main", String[].class).getName();
+        } else if (arg == 4) {
+            return Class_getMethod02.class.getMethod("<init>").getName();
+        } else if (arg == 5) {
+            return Class_getMethod02.class.getMethod("<clinit>").getName();
+        }
+        return null;
+    }
+
+    public static void main(String[] args) {
+        field = args[0];
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java
new file mode 100644
index 0000000..3cea0d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_newInstance01 extends JTTTest {
+
+    public static boolean test(int i) throws IllegalAccessException, InstantiationException {
+        if (i == 0) {
+            return Class_newInstance01.class.newInstance() != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java
new file mode 100644
index 0000000..72d59a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_newInstance02 extends JTTTest {
+
+    public static boolean test(int i) throws IllegalAccessException, InstantiationException {
+        if (i == 0) {
+            // note: we rely on the other class here.
+            return Class_newInstance07.Class_newInstance.class.newInstance() != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java
new file mode 100644
index 0000000..179a900
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Class_newInstance03 extends JTTTest {
+
+    public abstract static class AbstractClass {
+    }
+
+    public static boolean test(int i) throws IllegalAccessException, InstantiationException {
+        if (i == 0) {
+            return AbstractClass.class.newInstance() != null;
+        } else if (i == 1) {
+            return Cloneable.class.newInstance() != null;
+        } else if (i == 2) {
+            return int[].class.newInstance() != null;
+        } else if (i == 3) {
+            return int.class.newInstance() != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java
new file mode 100644
index 0000000..4d02cb6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_newInstance06 extends JTTTest {
+
+    public static final class Class_newInstance {
+
+        @SuppressWarnings("unused")
+        private Class_newInstance(int i) {
+            // do nothing. xx
+        }
+    }
+
+    public static boolean test(int i) throws IllegalAccessException, InstantiationException {
+        if (i == 0) {
+            return Class_newInstance.class.newInstance() != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java
new file mode 100644
index 0000000..53be8ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Class_newInstance07 extends JTTTest {
+
+    public static final class Class_newInstance {
+
+        private Class_newInstance() throws Exception {
+            throw new Exception();
+        }
+    }
+
+    public static boolean test(int i) throws IllegalAccessException, InstantiationException {
+        if (i == 0) {
+            return Class_newInstance.class.newInstance() != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get01.java
new file mode 100644
index 0000000..a372731
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get01.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_get01 extends JTTTest {
+
+    public static final byte byteField = 11;
+    public static final short shortField = 12;
+    public static final char charField = 13;
+    public static final int intField = 14;
+    public static final long longField = 15;
+    public static final float floatField = 16;
+    public static final double doubleField = 17;
+    public static final boolean booleanField = true;
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            return Field_get01.class.getField("byteField").get(null).equals(byteField);
+        } else if (arg == 1) {
+            return Field_get01.class.getField("shortField").get(null).equals(shortField);
+        } else if (arg == 2) {
+            return Field_get01.class.getField("charField").get(null).equals(charField);
+        } else if (arg == 3) {
+            return Field_get01.class.getField("intField").get(null).equals(intField);
+        } else if (arg == 4) {
+            return Field_get01.class.getField("longField").get(null).equals(longField);
+        } else if (arg == 5) {
+            return Field_get01.class.getField("floatField").get(null).equals(floatField);
+        } else if (arg == 6) {
+            return Field_get01.class.getField("doubleField").get(null).equals(doubleField);
+        } else if (arg == 7) {
+            return Field_get01.class.getField("booleanField").get(null).equals(booleanField);
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get02.java
new file mode 100644
index 0000000..424d930
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get02.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_get02 extends JTTTest {
+
+    public static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
+
+    private static final TestClass object = new TestClass();
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            return TestClass.class.getField("byteField").get(object).equals(object.byteField);
+        } else if (arg == 1) {
+            return TestClass.class.getField("shortField").get(object).equals(object.shortField);
+        } else if (arg == 2) {
+            return TestClass.class.getField("charField").get(object).equals(object.charField);
+        } else if (arg == 3) {
+            return TestClass.class.getField("intField").get(object).equals(object.intField);
+        } else if (arg == 4) {
+            return TestClass.class.getField("longField").get(object).equals(object.longField);
+        } else if (arg == 5) {
+            return TestClass.class.getField("floatField").get(object).equals(object.floatField);
+        } else if (arg == 6) {
+            return TestClass.class.getField("doubleField").get(object).equals(object.doubleField);
+        } else if (arg == 7) {
+            return TestClass.class.getField("booleanField").get(object).equals(object.booleanField);
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get03.java
new file mode 100644
index 0000000..d813497
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get03.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.Field;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_get03 extends JTTTest {
+
+    private static Field ByteField;
+    private static Field ShortField;
+    private static Field CharField;
+    private static Field IntField;
+    private static Field LongField;
+    private static Field FloatField;
+    private static Field DoubleField;
+    private static Field BooleanField;
+
+    static {
+        try {
+            ByteField = TestClass.class.getField("byteField");
+            ShortField = TestClass.class.getField("shortField");
+            CharField = TestClass.class.getField("charField");
+            IntField = TestClass.class.getField("intField");
+            LongField = TestClass.class.getField("longField");
+            FloatField = TestClass.class.getField("floatField");
+            DoubleField = TestClass.class.getField("doubleField");
+            BooleanField = TestClass.class.getField("booleanField");
+        } catch (SecurityException | NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
+
+    private static final TestClass object = new TestClass();
+
+    public static boolean test(int arg) throws IllegalAccessException {
+        if (arg == 0) {
+            return ByteField.get(object).equals(object.byteField);
+        } else if (arg == 1) {
+            return ShortField.get(object).equals(object.shortField);
+        } else if (arg == 2) {
+            return CharField.get(object).equals(object.charField);
+        } else if (arg == 3) {
+            return IntField.get(object).equals(object.intField);
+        } else if (arg == 4) {
+            return LongField.get(object).equals(object.longField);
+        } else if (arg == 5) {
+            return FloatField.get(object).equals(object.floatField);
+        } else if (arg == 6) {
+            return DoubleField.get(object).equals(object.doubleField);
+        } else if (arg == 7) {
+            return BooleanField.get(object).equals(object.booleanField);
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get04.java
new file mode 100644
index 0000000..e4409ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_get04.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_get04 extends JTTTest {
+
+    private static class TestClass {
+        public final byte byteField = 11;
+        public final short shortField = 12;
+        public final char charField = 13;
+        public final int intField = 14;
+        public final long longField = 15;
+        public final float floatField = 16;
+        public final double doubleField = 17;
+        public final boolean booleanField = true;
+    }
+
+    private static final TestClass object = new TestClass();
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            return TestClass.class.getField("byteField").getByte(object) == object.byteField;
+        } else if (arg == 1) {
+            return TestClass.class.getField("shortField").getShort(object) == object.shortField;
+        } else if (arg == 2) {
+            return TestClass.class.getField("charField").getChar(object) == object.charField;
+        } else if (arg == 3) {
+            return TestClass.class.getField("intField").getInt(object) == object.intField;
+        } else if (arg == 4) {
+            return TestClass.class.getField("longField").getLong(object) == object.longField;
+        } else if (arg == 5) {
+            return TestClass.class.getField("floatField").getFloat(object) == object.floatField;
+        } else if (arg == 6) {
+            return TestClass.class.getField("doubleField").getDouble(object) == object.doubleField;
+        } else if (arg == 7) {
+            return TestClass.class.getField("booleanField").getBoolean(object) == object.booleanField;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_getType01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_getType01.java
new file mode 100644
index 0000000..ea9ed39
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_getType01.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_getType01 extends JTTTest {
+
+    public static final byte byteField = 11;
+    public static final short shortField = 12;
+    public static final char charField = 13;
+    public static final int intField = 14;
+    public static final long longField = 15;
+    public static final float floatField = 16;
+    public static final double doubleField = 17;
+    public static final boolean booleanField = true;
+
+    public static boolean test(int arg) throws NoSuchFieldException {
+        if (arg == 0) {
+            return Field_getType01.class.getField("byteField").getType() == byte.class;
+        } else if (arg == 1) {
+            return Field_getType01.class.getField("shortField").getType() == short.class;
+        } else if (arg == 2) {
+            return Field_getType01.class.getField("charField").getType() == char.class;
+        } else if (arg == 3) {
+            return Field_getType01.class.getField("intField").getType() == int.class;
+        } else if (arg == 4) {
+            return Field_getType01.class.getField("longField").getType() == long.class;
+        } else if (arg == 5) {
+            return Field_getType01.class.getField("floatField").getType() == float.class;
+        } else if (arg == 6) {
+            return Field_getType01.class.getField("doubleField").getType() == double.class;
+        } else if (arg == 7) {
+            return Field_getType01.class.getField("booleanField").getType() == boolean.class;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set01.java
new file mode 100644
index 0000000..645b53c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set01.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_set01 extends JTTTest {
+
+    public static byte byteField;
+    public static short shortField;
+    public static char charField;
+    public static int intField;
+    public static long longField;
+    public static float floatField;
+    public static double doubleField;
+    public static boolean booleanField;
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            Field_set01.class.getField("byteField").set(null, Byte.valueOf((byte) 11));
+            return byteField == 11;
+        } else if (arg == 1) {
+            Field_set01.class.getField("shortField").set(null, Short.valueOf((short) 12));
+            return shortField == 12;
+        } else if (arg == 2) {
+            Field_set01.class.getField("charField").set(null, Character.valueOf((char) 13));
+            return charField == 13;
+        } else if (arg == 3) {
+            Field_set01.class.getField("intField").set(null, Integer.valueOf(14));
+            return intField == 14;
+        } else if (arg == 4) {
+            Field_set01.class.getField("longField").set(null, Long.valueOf(15L));
+            return longField == 15;
+        } else if (arg == 5) {
+            Field_set01.class.getField("floatField").set(null, Float.valueOf(16));
+            return floatField == 16;
+        } else if (arg == 6) {
+            Field_set01.class.getField("doubleField").set(null, Double.valueOf(17));
+            return doubleField == 17;
+        } else if (arg == 7) {
+            Field_set01.class.getField("booleanField").set(null, true);
+            return booleanField == true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set02.java
new file mode 100644
index 0000000..c334985
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set02.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_set02 extends JTTTest {
+
+    private static class TestClass {
+        public byte byteField;
+        public short shortField;
+        public char charField;
+        public int intField;
+        public long longField;
+        public float floatField;
+        public double doubleField;
+        public boolean booleanField;
+    }
+
+    private static final TestClass object = new TestClass();
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            TestClass.class.getField("byteField").set(object, Byte.valueOf((byte) 11));
+            return object.byteField == 11;
+        } else if (arg == 1) {
+            TestClass.class.getField("shortField").set(object, Short.valueOf((short) 12));
+            return object.shortField == 12;
+        } else if (arg == 2) {
+            TestClass.class.getField("charField").set(object, Character.valueOf((char) 13));
+            return object.charField == 13;
+        } else if (arg == 3) {
+            TestClass.class.getField("intField").set(object, Integer.valueOf(14));
+            return object.intField == 14;
+        } else if (arg == 4) {
+            TestClass.class.getField("longField").set(object, Long.valueOf(15L));
+            return object.longField == 15;
+        } else if (arg == 5) {
+            TestClass.class.getField("floatField").set(object, Float.valueOf(16));
+            return object.floatField == 16;
+        } else if (arg == 6) {
+            TestClass.class.getField("doubleField").set(object, Double.valueOf(17));
+            return object.doubleField == 17;
+        } else if (arg == 7) {
+            TestClass.class.getField("booleanField").set(object, true);
+            return object.booleanField == true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set03.java
new file mode 100644
index 0000000..2a6e891
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Field_set03.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Field_set03 extends JTTTest {
+
+    private static class TestClass {
+        public byte byteField;
+        public short shortField;
+        public char charField;
+        public int intField;
+        public long longField;
+        public float floatField;
+        public double doubleField;
+        public boolean booleanField;
+    }
+
+    private static final TestClass object = new TestClass();
+
+    public static boolean test(int arg) throws NoSuchFieldException, IllegalAccessException {
+        if (arg == 0) {
+            TestClass.class.getField("byteField").setByte(object, (byte) 11);
+            return object.byteField == 11;
+        } else if (arg == 1) {
+            TestClass.class.getField("shortField").setShort(object, (short) 12);
+            return object.shortField == 12;
+        } else if (arg == 2) {
+            TestClass.class.getField("charField").setChar(object, (char) 13);
+            return object.charField == 13;
+        } else if (arg == 3) {
+            TestClass.class.getField("intField").setInt(object, 14);
+            return object.intField == 14;
+        } else if (arg == 4) {
+            TestClass.class.getField("longField").setLong(object, 15L);
+            return object.longField == 15;
+        } else if (arg == 5) {
+            TestClass.class.getField("floatField").setFloat(object, 16);
+            return object.floatField == 16;
+        } else if (arg == 6) {
+            TestClass.class.getField("doubleField").setDouble(object, 17);
+            return object.doubleField == 17;
+        } else if (arg == 7) {
+            TestClass.class.getField("booleanField").setBoolean(object, true);
+            return object.booleanField == true;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("test", 7);
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("test", 8);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_except01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_except01.java
new file mode 100644
index 0000000..7d51da1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_except01.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Invoke_except01 extends JTTTest {
+
+    public static class TestClass {
+        public static int method(int[] arg) {
+            return arg.length;
+        }
+    }
+
+    public static int test(int arg) throws IllegalAccessException, InvocationTargetException {
+        Object[] args;
+        if (arg == 0) {
+            args = new Object[]{new int[0]};
+        } else if (arg == 1) {
+            args = new Object[]{new int[3]};
+        } else if (arg == 2) {
+            args = new Object[]{null};
+        } else if (arg == 3) {
+            args = new Object[]{new char[3]};
+        } else {
+            args = null;
+        }
+        for (Method m : TestClass.class.getDeclaredMethods()) {
+            if ("method".equals(m.getName())) {
+                return (Integer) m.invoke(null, args);
+            }
+        }
+        return 42;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main01.java
new file mode 100644
index 0000000..0894666
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main01.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Invoke_main01 extends JTTTest {
+
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
+    static String field;
+
+    public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        field = null;
+        final String[] args = {input};
+        TestClass.class.getMethod("main", String[].class).invoke(null, new Object[]{args});
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test1");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "test2");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main02.java
new file mode 100644
index 0000000..4b4db39
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main02.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Invoke_main02 extends JTTTest {
+
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
+    static String field;
+
+    public static String test(String input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        field = null;
+        final String[] args = {input};
+        TestClass.class.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{args});
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test1");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "test2");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main03.java
new file mode 100644
index 0000000..69e18d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_main03.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Invoke_main03 extends JTTTest {
+
+    public static class TestClass {
+        public static void main(String[] args) {
+            field = args[0];
+        }
+    }
+
+    static String field;
+
+    public static String test(String input) throws IllegalAccessException, InvocationTargetException {
+        field = null;
+        final String[] args = {input};
+        for (Method m : TestClass.class.getDeclaredMethods()) {
+            if ("main".equals(m.getName())) {
+                m.invoke(null, new Object[]{args});
+            }
+        }
+        return field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", "test1");
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", "test2");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_virtual01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_virtual01.java
new file mode 100644
index 0000000..05d9adb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Invoke_virtual01.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Invoke_virtual01 extends JTTTest {
+
+    static final HelperTest helper = new HelperTest(55);
+
+    public static int test(int input) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        if (input == 1) {
+            final Method m = HelperTest.class.getDeclaredMethod("getInt");
+            Object o = m.invoke(helper);
+            return ((Integer) o).intValue();
+        }
+        return 0;
+    }
+
+    public static class HelperTest {
+
+        private int intField;
+
+        public int getInt() {
+            return intField;
+        }
+
+        public HelperTest(int i) {
+            intField = i;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 1);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getParameterTypes01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getParameterTypes01.java
new file mode 100644
index 0000000..bc3dcd6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getParameterTypes01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+@SuppressWarnings("unused")
+public class Method_getParameterTypes01 extends JTTTest {
+
+    public static int test(int arg) throws NoSuchMethodException {
+        if (arg == 0) {
+            return Method_getParameterTypes01.class.getMethod("method1").getParameterTypes().length;
+        } else if (arg == 1) {
+            return Method_getParameterTypes01.class.getMethod("method2", int.class).getParameterTypes().length;
+        } else if (arg == 2) {
+            return Method_getParameterTypes01.class.getMethod("method3", int.class, Object.class).getParameterTypes().length;
+        }
+        return -1;
+    }
+
+    public int method1() {
+        return 0;
+    }
+
+    public void method2(int arg1) {
+    }
+
+    public void method3(int arg1, Object arg2) {
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getReturnType01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getReturnType01.java
new file mode 100644
index 0000000..d1a026f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Method_getReturnType01.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.reflect;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class Method_getReturnType01 extends JTTTest {
+
+    public static String test(int arg) throws NoSuchMethodException {
+        if (arg == 0) {
+            return Method_getReturnType01.class.getMethod("method1").getReturnType().getName();
+        } else if (arg == 1) {
+            return Method_getReturnType01.class.getMethod("method2").getReturnType().getName();
+        } else if (arg == 2) {
+            return Method_getReturnType01.class.getMethod("method3").getReturnType().getName();
+        }
+        return null;
+    }
+
+    public int method1() {
+        return 0;
+    }
+
+    public String method2() {
+        return null;
+    }
+
+    public void method3() {
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java
new file mode 100644
index 0000000..d42b57e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Monitor_contended01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        boolean started = false;
+        boolean acquired = false;
+
+        @Override
+        public void run() {
+            // signal that we have started up so first thread will release lock
+            synchronized (cond) {
+                started = true;
+                cond.notifyAll();
+            }
+            synchronized (obj) {
+
+            }
+            // signal that we have successfully acquired and released the monitor
+            synchronized (cond) {
+                acquired = true;
+                cond.notifyAll();
+            }
+        }
+    }
+
+    static final Object cond = new Object();
+    static final Object obj = new Object();
+
+    public static boolean test() throws InterruptedException {
+        // test contention for monitor
+        final TestClass object = new TestClass();
+        synchronized (obj) {
+            new Thread(object).start();
+            // wait for other thread to startup and contend
+            synchronized (cond) {
+                cond.wait(1000);
+                if (!object.started) {
+                    return false;
+                }
+            }
+        }
+        // wait for other thread to acquire monitor and then exit
+        synchronized (cond) {
+            cond.wait(1000);
+        }
+        return object.acquired;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java
new file mode 100644
index 0000000..8c89780
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Monitor_notowner01 extends JTTTest {
+
+    static Object monitor = new Object();
+    static Object finished = new Object();
+
+    public static boolean test() throws InterruptedException {
+        final BadRunnable badRunnable = new BadRunnable();
+        synchronized (monitor) {
+            new Thread(badRunnable).start();
+            synchronized (finished) {
+                finished.wait(1000);
+            }
+        }
+        return badRunnable.caught;
+    }
+
+    static class BadRunnable implements Runnable {
+
+        protected boolean caught = false;
+
+        @Override
+        public void run() {
+            try {
+                // we don't own this!
+                monitor.wait();
+            } catch (InterruptedException ex) {
+
+            } catch (IllegalMonitorStateException ex) {
+                caught = true;
+                synchronized (finished) {
+                    finished.notifyAll();
+                }
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java
new file mode 100644
index 0000000..af35abe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Monitorenter01 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() {
+        // test nested locking.
+        synchronized (object) {
+            synchronized (object) {
+                return true;
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java
new file mode 100644
index 0000000..f688227
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Monitorenter02 extends JTTTest {
+
+    static final Object object = new Object();
+
+    public static boolean test() {
+        // test nested locking.
+        synchronized (object) {
+            return test2();
+        }
+    }
+
+    private static boolean test2() {
+        synchronized (object) {
+            return true;
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java
new file mode 100644
index 0000000..dc6eae1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_wait01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            int i = 0;
+            while (i++ < 1000000 && !done) {
+                synchronized (object) {
+                    count++;
+                    object.notifyAll();
+                }
+            }
+        }
+    }
+
+    static volatile int count = 0;
+    static volatile boolean done;
+    static final Object object = new Object();
+
+    public static boolean test(int i) throws InterruptedException {
+        count = 0;
+        done = false;
+        new Thread(new TestClass()).start();
+        synchronized (object) {
+            while (count < i) {
+                object.wait();
+            }
+            done = true;
+            return count >= i;
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test(timeout = 20000)
+    public void run2() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test(timeout = 20000)
+    public void run3() throws Throwable {
+        runTest("test", 15);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java
new file mode 100644
index 0000000..ccd61b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_wait02 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
+
+    static volatile boolean done;
+    static final Object object = new Object();
+    static int sleep;
+
+    public static boolean test(int i) throws InterruptedException {
+        done = false;
+        sleep = i * 200;
+        new Thread(new TestClass()).start();
+        synchronized (object) {
+            while (!done) {
+                object.wait(200);
+            }
+        }
+        return done;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test(timeout = 20000)
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java
new file mode 100644
index 0000000..d837662
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_wait03 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
+
+    static volatile boolean done;
+    static final Object object = new Object();
+    static int sleep;
+
+    public static boolean test(int i) throws InterruptedException {
+        done = false;
+        sleep = i * 200;
+        synchronized (object) {
+            new Thread(new TestClass()).start();
+            dowait();
+        }
+        return done;
+    }
+
+    private static void dowait() throws InterruptedException {
+        synchronized (object) {
+            while (!done) {
+                object.wait(200);
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test(timeout = 20000)
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java
new file mode 100644
index 0000000..925dada
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Object_wait04 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException ex) {
+
+            }
+            synchronized (object) {
+                done = true;
+                object.notifyAll();
+            }
+        }
+    }
+
+    static volatile boolean done;
+    static final Object object = new Object();
+    static int sleep;
+
+    public static boolean test(int i) throws InterruptedException {
+        done = false;
+        sleep = i * 50;
+        synchronized (object) {
+            new Thread(new TestClass()).start();
+            dowait(i);
+        }
+        return done;
+    }
+
+    private static void dowait(int i) throws InterruptedException {
+        if (i == 0) {
+            while (!done) {
+                object.wait(100);
+            }
+        } else {
+            synchronized (object) {
+                dowait(i - 1);
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test(timeout = 20000)
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test(timeout = 20000)
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test(timeout = 20000)
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+    @Test(timeout = 20000)
+    public void run5() throws Throwable {
+        runTest("test", 5);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java
new file mode 100644
index 0000000..fdb58db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/**
+ * Inspired by {@code com.sun.media.sound.DirectAudioDevice$DirectDL.drain()}.
+ *
+ * Two loop exits hold a monitor while merging.
+ *
+ */
+public final class SynchronizedLoopExit01 extends JTTTest {
+
+    protected Object object = new Object();
+    protected volatile boolean drained = false;
+    protected volatile boolean someBoolean = true;
+
+    public boolean test() {
+        boolean b = true;
+        while (!drained) {
+            synchronized (object) {
+                boolean c = b = someBoolean;
+                if (c || drained) {
+                    break;
+                }
+            }
+        }
+        return b;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal01.java
new file mode 100644
index 0000000..f98f28d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal01.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ThreadLocal01 extends JTTTest {
+
+    private static final ThreadLocal<Integer> local = new ThreadLocal<>();
+
+    public static int test(int i) {
+        local.set(i + 5);
+        return local.get();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal02.java
new file mode 100644
index 0000000..6cf2ecb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal02.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ThreadLocal02 extends JTTTest {
+
+    public static int test(int i) {
+        ThreadLocal<Integer> local = new ThreadLocal<>();
+        local.set(i + 5);
+        return local.get();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal03.java
new file mode 100644
index 0000000..17e3665
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/ThreadLocal03.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+public class ThreadLocal03 extends JTTTest {
+
+    static final ThreadLocal<Integer> local = new ThreadLocal<>();
+
+    public static int test(int i) {
+        int sum = 0;
+        for (int j = 0; j < i; j++) {
+            TThread t = new TThread();
+            t.input = 10 + j;
+            t.run();
+            try {
+                t.join();
+            } catch (InterruptedException e) {
+                return -1;
+            }
+            sum += t.output;
+        }
+        return sum;
+    }
+
+    private static class TThread extends Thread {
+
+        int input;
+        int output;
+
+        @Override
+        public void run() {
+            local.set(input + 5);
+            output = local.get();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_currentThread01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_currentThread01.java
new file mode 100644
index 0000000..0d63d78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_currentThread01.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_currentThread01 extends JTTTest {
+
+    public static boolean test() {
+        return Thread.currentThread() != null;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState01.java
new file mode 100644
index 0000000..7eccabd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState01.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_getState01 extends JTTTest {
+
+    public static boolean test() {
+        return Thread.currentThread().getState() == Thread.State.RUNNABLE;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState02.java
new file mode 100644
index 0000000..440a436
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_getState02.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_getState02 extends JTTTest {
+
+    public static boolean test() {
+        return new Thread().getState() == Thread.State.NEW;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_holdsLock01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_holdsLock01.java
new file mode 100644
index 0000000..0b45f56
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_holdsLock01.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_holdsLock01 extends JTTTest {
+
+    static final Object monitor = new Object();
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            synchronized (monitor) {
+                return Thread.holdsLock(monitor);
+            }
+        } else if (i == 1) {
+            synchronized (monitor) {
+                // do nothing.
+            }
+            return Thread.holdsLock(monitor);
+        } else if (i == 2) {
+            return Thread.holdsLock(null);
+        }
+        return Thread.holdsLock(monitor);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isAlive01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isAlive01.java
new file mode 100644
index 0000000..ff373ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isAlive01.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_isAlive01 extends JTTTest {
+
+    public static boolean test() {
+        return Thread.currentThread().isAlive();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted01.java
new file mode 100644
index 0000000..d529352
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted01.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_isInterrupted01 extends JTTTest {
+
+    public static boolean test() {
+        return Thread.currentThread().isInterrupted();
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java
new file mode 100644
index 0000000..41edeed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+//Test all, mainly monitors
+public class Thread_isInterrupted02 extends JTTTest {
+
+    private static final Object start = new Object();
+    private static final Object end = new Object();
+    private static int waitTime;
+
+    @SuppressWarnings("unused")
+    public static boolean test(int i, int time) throws InterruptedException {
+        waitTime = time;
+        final Thread thread = new Thread();
+        synchronized (thread) {
+            // start the thread and wait for it
+            thread.setDaemon(true); // in case the thread gets stuck
+            thread.start();
+            while (!thread.wait1Condition) {
+                thread.wait(10000);
+            }
+        }
+        synchronized (start) {
+            thread.interrupt();
+            thread.sentInterrupt = true;
+        }
+        synchronized (end) {
+            while (!thread.wait2Condition) {
+                end.wait(10000);
+            }
+        }
+        return thread.interrupted;
+    }
+
+    private static class Thread extends java.lang.Thread {
+
+        private boolean interrupted;
+        private boolean sentInterrupt;
+        private boolean wait1Condition;
+        private boolean wait2Condition;
+
+        @Override
+        public void run() {
+            try {
+                synchronized (start) {
+                    synchronized (this) {
+                        // signal test thread that we are running
+                        wait1Condition = true;
+                        notify();
+                    }
+                    // wait for the condition, which should be interrupted
+                    while (!sentInterrupt) {
+                        if (waitTime == 0) {
+                            start.wait();
+                        } else {
+                            start.wait(waitTime);
+                        }
+                        if (Thread.interrupted()) {
+                            throw new InterruptedException();
+                        }
+                    }
+                    Assert.fail("should not reach here - was not interrupted");
+                }
+            } catch (InterruptedException e) {
+                // interrupted successfully.
+                interrupted = true;
+                synchronized (end) {
+                    // notify the other thread we are done
+                    wait2Condition = true;
+                    end.notify();
+                }
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 0, 0);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 1, 500);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java
new file mode 100644
index 0000000..6e2b3c2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+
+// Interrupted while sleeping, throws an interrupted exception
+public class Thread_isInterrupted03 extends JTTTest {
+
+    public static boolean test() throws InterruptedException {
+        final Thread1 thread = new Thread1();
+        thread.start();
+        Thread.sleep(1000);
+        thread.interrupt();
+        Thread.sleep(1000);
+        // Did thread get interrupted?
+        final boolean result = thread.getInterrupted();
+        // This stops the thread even if the interrupt didn't!
+        thread.setInterrupted(true);
+        return result;
+    }
+
+    private static class Thread1 extends java.lang.Thread {
+
+        private boolean interrupted = false;
+
+        @Override
+        public void run() {
+            while (!interrupted) {
+                try {
+                    sleep(10000);
+                } catch (InterruptedException e) {
+                    interrupted = true;
+                }
+            }
+        }
+
+        public void setInterrupted(boolean val) {
+            interrupted = val;
+        }
+
+        public boolean getInterrupted() {
+            return interrupted;
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted04.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted04.java
new file mode 100644
index 0000000..a587501
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted04.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+
+// Interrupted while running, do nothing, just set the flag and continue
+// (thomaswue) This test will exercise deoptimization on HotSpot, because a volatile unloaded field is accessed.
+// (thomaswue) The temporary result variable is needed, because in order to query the isInterrupted flag, the thread must be alive.
+public class Thread_isInterrupted04 extends JTTTest {
+
+    public static boolean test() throws InterruptedException {
+        final Thread1 thread = new Thread1();
+        thread.start();
+        while (!thread.running) {
+            Thread.sleep(10);
+        }
+        Thread.sleep(100);
+        thread.interrupt();
+        boolean result = thread.isInterrupted();
+        thread.setStop(true);
+        return result;
+    }
+
+    public static class Thread1 extends java.lang.Thread {
+
+        private volatile boolean stop = false;
+        public volatile boolean running = false;
+        public long i = 0;
+
+        @Override
+        public void run() {
+            running = true;
+            while (!stop) {
+                i++;
+            }
+        }
+
+        public void setStop(boolean value) {
+            stop = value;
+        }
+
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java
new file mode 100644
index 0000000..9e70ded
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ */
+
+// Interrupted during wait, with interrupter joining
+public class Thread_isInterrupted05 extends JTTTest {
+
+    public static boolean test() throws InterruptedException {
+        final WaitInterruptee waitInterruptee = new WaitInterruptee();
+        waitInterruptee.start();
+        waitInterruptee.interrupt();
+        waitInterruptee.join();
+
+        if (waitInterruptee.throwable != null) {
+            throw new RuntimeException(waitInterruptee.throwable);
+        }
+        return true;
+    }
+
+    static class WaitInterruptee extends Thread {
+
+        Throwable throwable;
+
+        WaitInterruptee() {
+            super("WaitInterruptee");
+        }
+
+        @Override
+        public void run() {
+            try {
+                synchronized (this) {
+                    try {
+                        wait();
+                    } catch (InterruptedException ex) {
+                    }
+                }
+            } catch (Throwable t) {
+                throwable = t;
+            }
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java
new file mode 100644
index 0000000..1937618
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Thread_join01 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            cont = false;
+        }
+    }
+
+    static volatile boolean cont;
+
+    public static boolean test() throws InterruptedException {
+        cont = true;
+        final Thread thread = new Thread(new TestClass());
+        thread.start();
+        thread.join();
+        return cont;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java
new file mode 100644
index 0000000..824ecf7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ *
+ * This test sleeps the thread that is joined to, which should ensure that the joining thread
+ * actually does wait for completeion.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Thread_join02 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException ex) {
+            }
+            cont = false;
+        }
+    }
+
+    static volatile boolean cont;
+
+    public static boolean test() throws InterruptedException {
+        cont = true;
+        final Thread thread = new Thread(new TestClass());
+        thread.start();
+        thread.join();
+        return cont;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java
new file mode 100644
index 0000000..1e815b6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ *
+ * This test sleeps the joining thread, which should enure that the joinee is
+ * terminated by the time the join occurs.
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Thread_join03 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            cont = false;
+        }
+    }
+
+    static volatile boolean cont;
+
+    public static boolean test() throws InterruptedException {
+        cont = true;
+        final Thread thread = new Thread(new TestClass());
+        thread.start();
+        Thread.sleep(200);
+        thread.join();
+        return cont;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new01.java
new file mode 100644
index 0000000..392b4f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new01.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_new01 extends JTTTest {
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return new Thread() != null;
+        }
+        if (i == 1) {
+            return new Thread("Thread_new01") != null;
+        }
+        if (i == 2) {
+            return new Thread(new Thread()) != null;
+        }
+        if (i == 3) {
+            return new Thread(new Thread(), "Thread_new01") != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new02.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new02.java
new file mode 100644
index 0000000..329f16e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_new02.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class Thread_new02 extends JTTTest {
+
+    private static class TestClass implements Runnable {
+        @Override
+        public void run() {
+            // do nothing.
+        }
+    }
+
+    static final TestClass thisObject = new TestClass();
+
+    public static boolean test(int i) {
+        if (i == 0) {
+            return new Thread() != null;
+        }
+        if (i == 1) {
+            return new Thread("Thread_new01") != null;
+        }
+        if (i == 2) {
+            return new Thread(thisObject) != null;
+        }
+        if (i == 3) {
+            return new Thread(thisObject, "Thread_new01") != null;
+        }
+        return false;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 2);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 3);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 4);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_setPriority01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_setPriority01.java
new file mode 100644
index 0000000..40a462c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_setPriority01.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_setPriority01 extends JTTTest {
+
+    public static boolean test(int i) {
+        final Thread currentThread = Thread.currentThread();
+        final int prev = currentThread.getPriority();
+        currentThread.setPriority(i);
+        currentThread.setPriority(prev);
+        return true;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", 5);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", 11);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java
new file mode 100644
index 0000000..e224548
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_sleep01 extends JTTTest {
+
+    public static boolean test(int i) throws InterruptedException {
+        final long before = System.currentTimeMillis();
+        Thread.sleep(i);
+        return System.currentTimeMillis() - before >= i;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test", 10);
+    }
+
+    @Test(timeout = 20000)
+    public void run1() throws Throwable {
+        runTest("test", 20);
+    }
+
+    @Test(timeout = 20000)
+    public void run2() throws Throwable {
+        runTest("test", 100);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java
new file mode 100644
index 0000000..0c63801
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package org.graalvm.compiler.jtt.threads;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public final class Thread_yield01 extends JTTTest {
+
+    public static boolean test() {
+        Thread.yield();
+        return true;
+    }
+
+    @Test(timeout = 20000)
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AddressValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AddressValue.java
new file mode 100644
index 0000000..a6c6ffa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AddressValue.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType;
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class AArch64AddressValue extends CompositeValue {
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
+    @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
+    @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue offset;
+    private final int immediate;
+
+    /**
+     * Whether register offset should be scaled or not.
+     */
+    private final boolean scaled;
+    private final AddressingMode addressingMode;
+
+    public AArch64AddressValue(ValueKind<?> kind, AllocatableValue base, AllocatableValue offset, int immediate, boolean scaled, AddressingMode addressingMode) {
+        super(kind);
+        this.base = base;
+        this.offset = offset;
+        this.immediate = immediate;
+        this.scaled = scaled;
+        this.addressingMode = addressingMode;
+    }
+
+    private static Register toRegister(AllocatableValue value) {
+        if (value.equals(Value.ILLEGAL)) {
+            return AArch64.zr;
+        } else {
+            return ((RegisterValue) value).getRegister();
+        }
+    }
+
+    public AllocatableValue getBase() {
+        return base;
+    }
+
+    public AllocatableValue getOffset() {
+        return offset;
+    }
+
+    public int getImmediate() {
+        return immediate;
+    }
+
+    public boolean isScaled() {
+        return scaled;
+    }
+
+    public AddressingMode getAddressingMode() {
+        return addressingMode;
+    }
+
+    public AArch64Address toAddress() {
+        Register baseReg = toRegister(base);
+        Register offsetReg = toRegister(offset);
+        AArch64Assembler.ExtendType extendType = addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET ? ExtendType.SXTW : null;
+        return AArch64Address.createAddress(addressingMode, baseReg, offsetReg, immediate, scaled, extendType);
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newOffset = (AllocatableValue) proc.doValue(inst, offset, mode, flags);
+        if (!base.identityEquals(newBase) || !offset.identityEquals(newOffset)) {
+            return new AArch64AddressValue(getValueKind(), newBase, newOffset, immediate, scaled, addressingMode);
+        }
+        return this;
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, offset, mode, flags);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java
new file mode 100644
index 0000000..8c84dbc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This interface can be used to generate AArch64 LIR for arithmetic operations.
+ */
+public interface AArch64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool {
+
+    Value emitCountLeadingZeros(Value value);
+
+    Value emitCountTrailingZeros(Value value);
+
+    void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java
new file mode 100644
index 0000000..caf734f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.ARITHMETIC;
+import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.LOGICAL;
+import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.NONE;
+import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.SHIFT;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+
+public enum AArch64ArithmeticOp {
+    // TODO At least add and sub *can* be used with SP, so this should be supported
+    NEG,
+    NOT,
+    ADD(ARITHMETIC),
+    ADDS(ARITHMETIC),
+    SUB(ARITHMETIC),
+    SUBS(ARITHMETIC),
+    MUL,
+    DIV,
+    SMULH,
+    UMULH,
+    REM,
+    UDIV,
+    UREM,
+    AND(LOGICAL),
+    ANDS(LOGICAL),
+    OR(LOGICAL),
+    XOR(LOGICAL),
+    SHL(SHIFT),
+    LSHR(SHIFT),
+    ASHR(SHIFT),
+    ABS,
+
+    FADD,
+    FSUB,
+    FMUL,
+    FDIV,
+    FREM,
+    FNEG,
+    FABS,
+    SQRT;
+
+    /**
+     * Specifies what constants can be used directly without having to be loaded into a register
+     * with the given instruction.
+     */
+    public enum ARMv8ConstantCategory {
+        NONE,
+        LOGICAL,
+        ARITHMETIC,
+        SHIFT
+    }
+
+    public final ARMv8ConstantCategory category;
+
+    AArch64ArithmeticOp(ARMv8ConstantCategory category) {
+        this.category = category;
+    }
+
+    AArch64ArithmeticOp() {
+        this(NONE);
+    }
+
+    public static class UnaryOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<UnaryOp> TYPE = LIRInstructionClass.create(UnaryOp.class);
+
+        @Opcode private final AArch64ArithmeticOp opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+
+        public UnaryOp(AArch64ArithmeticOp opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src = asRegister(x);
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (opcode) {
+                case NEG:
+                    masm.sub(size, dst, zr, src);
+                    break;
+                case FNEG:
+                    masm.fneg(size, dst, src);
+                    break;
+                case NOT:
+                    masm.not(size, dst, src);
+                    break;
+                case ABS:
+                    masm.cmp(size, src, 0);
+                    masm.csneg(size, dst, src, ConditionFlag.LT);
+                    break;
+                case FABS:
+                    masm.fabs(size, dst, src);
+                    break;
+                case SQRT:
+                    masm.fsqrt(size, dst, src);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("op=" + opcode.name());
+            }
+        }
+    }
+
+    public static class BinaryConstOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryConstOp> TYPE = LIRInstructionClass.create(BinaryConstOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue a;
+        private final JavaConstant b;
+
+        public BinaryConstOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, JavaConstant b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            assert op.category != NONE;
+            Register dst = asRegister(result);
+            Register src = asRegister(a);
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    // Don't use asInt() here, since we can't use asInt on a long variable, even
+                    // if the constant easily fits as an int.
+                    assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong());
+                    masm.add(size, dst, src, (int) b.asLong());
+                    break;
+                case SUB:
+                    // Don't use asInt() here, since we can't use asInt on a long variable, even
+                    // if the constant easily fits as an int.
+                    assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong());
+                    masm.sub(size, dst, src, (int) b.asLong());
+                    break;
+                case AND:
+                    // XXX Should this be handled somewhere else?
+                    if (size == 32 && b.asLong() == 0xFFFF_FFFFL) {
+                        masm.mov(size, dst, src);
+                    } else {
+                        masm.and(size, dst, src, b.asLong());
+                    }
+                    break;
+                case ANDS:
+                    masm.ands(size, dst, src, b.asLong());
+                    break;
+                case OR:
+                    masm.or(size, dst, src, b.asLong());
+                    break;
+                case XOR:
+                    masm.eor(size, dst, src, b.asLong());
+                    break;
+                case SHL:
+                    masm.shl(size, dst, src, b.asLong());
+                    break;
+                case LSHR:
+                    masm.lshr(size, dst, src, b.asLong());
+                    break;
+                case ASHR:
+                    masm.ashr(size, dst, src, b.asLong());
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("op=" + op.name());
+            }
+        }
+    }
+
+    public static class BinaryOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryOp> TYPE = LIRInstructionClass.create(BinaryOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue a;
+        @Use({REG}) protected AllocatableValue b;
+
+        public BinaryOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src1 = asRegister(a);
+            Register src2 = asRegister(b);
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    masm.add(size, dst, src1, src2);
+                    break;
+                case ADDS:
+                    masm.adds(size, dst, src1, src2);
+                    break;
+                case SUB:
+                    masm.sub(size, dst, src1, src2);
+                    break;
+                case SUBS:
+                    masm.subs(size, dst, src1, src2);
+                    break;
+                case MUL:
+                    masm.mul(size, dst, src1, src2);
+                    break;
+                case UMULH:
+                    masm.umulh(size, dst, src1, src2);
+                    break;
+                case SMULH:
+                    masm.smulh(size, dst, src1, src2);
+                    break;
+                case DIV:
+                    masm.sdiv(size, dst, src1, src2);
+                    break;
+                case UDIV:
+                    masm.udiv(size, dst, src1, src2);
+                    break;
+                case AND:
+                    masm.and(size, dst, src1, src2);
+                    break;
+                case ANDS:
+                    masm.ands(size, dst, src1, src2);
+                    break;
+                case OR:
+                    masm.or(size, dst, src1, src2);
+                    break;
+                case XOR:
+                    masm.eor(size, dst, src1, src2);
+                    break;
+                case SHL:
+                    masm.shl(size, dst, src1, src2);
+                    break;
+                case LSHR:
+                    masm.lshr(size, dst, src1, src2);
+                    break;
+                case ASHR:
+                    masm.ashr(size, dst, src1, src2);
+                    break;
+                case FADD:
+                    masm.fadd(size, dst, src1, src2);
+                    break;
+                case FSUB:
+                    masm.fsub(size, dst, src1, src2);
+                    break;
+                case FMUL:
+                    masm.fmul(size, dst, src1, src2);
+                    break;
+                case FDIV:
+                    masm.fdiv(size, dst, src1, src2);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("op=" + op.name());
+            }
+        }
+    }
+
+    /**
+     * Class used for instructions that have to reuse one of their arguments. This only applies to
+     * the remainder instructions at the moment, since we have to compute n % d using rem = n -
+     * TruncatingDivision(n, d) * d
+     *
+     * TODO (das) Replace the remainder nodes in the LIR.
+     */
+    public static class BinaryCompositeOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryCompositeOp> TYPE = LIRInstructionClass.create(BinaryCompositeOp.class);
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Alive({REG}) protected AllocatableValue a;
+        @Alive({REG}) protected AllocatableValue b;
+
+        public BinaryCompositeOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src1 = asRegister(a);
+            Register src2 = asRegister(b);
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case REM:
+                    masm.rem(size, dst, src1, src2);
+                    break;
+                case UREM:
+                    masm.urem(size, dst, src1, src2);
+                    break;
+                case FREM:
+                    masm.frem(size, dst, src1, src2);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static class AddSubShiftOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<AddSubShiftOp> TYPE = LIRInstructionClass.create(AddSubShiftOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def(REG) protected AllocatableValue result;
+        @Use(REG) protected AllocatableValue src1;
+        @Use(REG) protected AllocatableValue src2;
+        private final AArch64MacroAssembler.ShiftType shiftType;
+        private final int shiftAmt;
+
+        /**
+         * Computes <code>result = src1 <op> src2 <shiftType> <shiftAmt></code>.
+         */
+        public AddSubShiftOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64MacroAssembler.ShiftType shiftType, int shiftAmt) {
+            super(TYPE);
+            assert op == ADD || op == SUB;
+            this.op = op;
+            this.result = result;
+            this.src1 = src1;
+            this.src2 = src2;
+            this.shiftType = shiftType;
+            this.shiftAmt = shiftAmt;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt);
+                    break;
+                case SUB:
+                    masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static class ExtendedAddShiftOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<ExtendedAddShiftOp> TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class);
+        @Def(REG) protected AllocatableValue result;
+        @Use(REG) protected AllocatableValue src1;
+        @Use(REG) protected AllocatableValue src2;
+        private final AArch64Assembler.ExtendType extendType;
+        private final int shiftAmt;
+
+        /**
+         * Computes <code>result = src1 + extendType(src2) << shiftAmt</code>.
+         *
+         * @param extendType defines how src2 is extended to the same size as src1.
+         * @param shiftAmt must be in range 0 to 4.
+         */
+        public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) {
+            super(TYPE);
+            this.result = result;
+            this.src1 = src1;
+            this.src2 = src2;
+            this.extendType = extendType;
+            this.shiftAmt = shiftAmt;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BitManipulationOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BitManipulationOp.java
new file mode 100644
index 0000000..31b6f4e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BitManipulationOp.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Bit manipulation ops for ARMv8 ISA.
+ */
+public class AArch64BitManipulationOp extends AArch64LIRInstruction {
+    public enum BitManipulationOpCode {
+        BSF,
+        BSR,
+        BSWP,
+        CLZ,
+    }
+
+    private static final LIRInstructionClass<AArch64BitManipulationOp> TYPE = LIRInstructionClass.create(AArch64BitManipulationOp.class);
+
+    @Opcode private final BitManipulationOpCode opcode;
+    @Def protected AllocatableValue result;
+    @Use({REG}) protected AllocatableValue input;
+
+    public AArch64BitManipulationOp(BitManipulationOpCode opcode, AllocatableValue result, AllocatableValue input) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register dst = asRegister(result);
+        Register src = asRegister(input);
+        final int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        switch (opcode) {
+            case CLZ:
+                masm.clz(size, dst, src);
+                break;
+            case BSR:
+                // BSR == <type width> - 1 - CLZ(input)
+                masm.clz(size, dst, src);
+                masm.neg(size, dst, dst);
+                masm.add(size, dst, dst, size - 1);
+                break;
+            case BSF:
+                // BSF == CLZ(rev(input))
+                masm.rev(size, dst, src);
+                masm.clz(size, dst, dst);
+                break;
+            case BSWP:
+                masm.rev(size, dst, src);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BlockEndOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BlockEndOp.java
new file mode 100644
index 0000000..115e578
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BlockEndOp.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public abstract class AArch64BlockEndOp extends AbstractBlockEndOp {
+
+    public static final LIRInstructionClass<AArch64BlockEndOp> TYPE = LIRInstructionClass.create(AArch64BlockEndOp.class);
+
+    protected AArch64BlockEndOp(LIRInstructionClass<? extends AArch64BlockEndOp> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AArch64MacroAssembler) crb.asm);
+    }
+
+    protected abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BreakpointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BreakpointOp.java
new file mode 100644
index 0000000..870da3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BreakpointOp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AArch64ExceptionCode;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+@Opcode("BREAKPOINT")
+public class AArch64BreakpointOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64BreakpointOp> TYPE = LIRInstructionClass.create(AArch64BreakpointOp.class);
+
+    /**
+     * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger).
+     */
+    @Use({REG, STACK}) private Value[] parameters;
+
+    public AArch64BreakpointOp(Value[] parameters) {
+        super(TYPE);
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        masm.brk(AArch64ExceptionCode.BREAKPOINT);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java
new file mode 100644
index 0000000..a8d3cbe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64Call {
+
+    public abstract static class CallOp extends AArch64LIRInstruction {
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @Temp({REG, STACK}) protected Value[] temps;
+        @State protected LIRFrameState state;
+
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c);
+            this.result = result;
+            this.parameters = parameters;
+            this.state = state;
+            this.temps = addStackSlotsToTemporaries(parameters, temps);
+            assert temps != null;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return true;
+        }
+    }
+
+    public abstract static class MethodCallOp extends CallOp {
+        protected final ResolvedJavaMethod callTarget;
+
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+    }
+
+    @Opcode("CALL_INDIRECT")
+    public static class IndirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
+
+        @Use({REG}) protected Value targetAddress;
+
+        public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        }
+
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
+                        LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
+            this.targetAddress = targetAddress;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register target = asRegister(targetAddress);
+            indirectCall(crb, masm, target, callTarget, state);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, " + "it must be in a fixed register for now";
+        }
+    }
+
+    @Opcode("CALL_DIRECT")
+    public abstract static class DirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
+
+        public DirectCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, target, result, parameters, temps, state);
+        }
+
+        protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, state);
+        }
+    }
+
+    public abstract static class ForeignCallOp extends CallOp {
+        protected final ForeignCallLinkage callTarget;
+        protected final Label label;
+
+        protected ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+            this.label = label;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitCall(crb, masm);
+        }
+
+        protected abstract void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+    }
+
+    @Opcode("NEAR_FOREIGN_CALL")
+    public static class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
+
+        public DirectNearForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) {
+            super(TYPE, callTarget, result, parameters, temps, state, label);
+        }
+
+        @Override
+        protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, state, label);
+        }
+    }
+
+    @Opcode("FAR_FOREIGN_CALL")
+    public static class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
+
+        public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state, Label label) {
+            super(TYPE, callTarget, result, parameters, temps, state, label);
+        }
+
+        @Override
+        protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // We can use any scratch register we want, since we know that they have been saved
+            // before calling.
+            directCall(crb, masm, callTarget, r8, state, label);
+        }
+    }
+
+    /**
+     * Tests whether linkage can be called directly under all circumstances without the need for a
+     * scratch register.
+     *
+     * Note this is a pessimistic assumption: This may return false despite a near call/jump being
+     * adequate.
+     *
+     * @param linkage Foreign call description
+     * @return true if foreign call can be called directly and does not need a scratch register to
+     *         load the address into.
+     */
+    public static boolean isNearCall(ForeignCallLinkage linkage) {
+        long maxOffset = linkage.getMaxCallTargetOffset();
+        return maxOffset != -1 && AArch64MacroAssembler.isBranchImmediateOffset(maxOffset);
+    }
+
+    public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) {
+        directCall(crb, masm, callTarget, scratch, info, null);
+    }
+
+    public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info, Label label) {
+        int before = masm.position();
+        if (scratch != null) {
+            /*
+             * Offset might not fit into a 28-bit immediate, generate an indirect call with a 64-bit
+             * immediate address which is fixed up by HotSpot.
+             */
+            masm.movNativeAddress(scratch, 0L);
+            masm.blr(scratch);
+        } else {
+            // Address is fixed up by HotSpot.
+            masm.bl(0);
+        }
+        if (label != null) {
+            // We need this label to be the return address.
+            masm.bind(label);
+        }
+        int after = masm.position();
+        crb.recordDirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
+        int before = masm.position();
+        masm.blr(dst);
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) {
+        int before = masm.position();
+        // Address is fixed up later by c++ code.
+        masm.jmp();
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) {
+        int before = masm.position();
+        masm.jmp(dst);
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void directConditionalJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target, AArch64Assembler.ConditionFlag cond) {
+        int before = masm.position();
+        masm.branchConditionally(cond);
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java
new file mode 100644
index 0000000..60a6fc9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64Compare {
+
+    public static class CompareOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompareOp> TYPE = LIRInstructionClass.create(CompareOp.class);
+
+        @Use protected Value x;
+        @Use({REG, CONST}) protected Value y;
+
+        public CompareOp(Value x, Value y) {
+            super(TYPE);
+            assert ((AArch64Kind) x.getPlatformKind()).isInteger() && ((AArch64Kind) y.getPlatformKind()).isInteger();
+            assert x.getPlatformKind() == y.getPlatformKind();
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            gpCompare(masm, x, y);
+        }
+    }
+
+    /**
+     * Compares integer values x and y.
+     *
+     * @param x integer value to compare. May not be null.
+     * @param y integer value to compare. May not be null.
+     */
+    public static void gpCompare(AArch64MacroAssembler masm, Value x, Value y) {
+        final int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        if (isRegister(y)) {
+            masm.cmp(size, asRegister(x), asRegister(y));
+        } else {
+            JavaConstant constant = asJavaConstant(y);
+            if (constant.isDefaultForKind()) {
+                masm.cmp(size, asRegister(x), 0);
+            } else {
+                final long longValue = constant.asLong();
+                assert NumUtil.isInt(longValue);
+                int maskedValue;
+                switch (constant.getJavaKind()) {
+                    case Boolean:
+                    case Byte:
+                        maskedValue = (int) (longValue & 0xFF);
+                        break;
+                    case Char:
+                    case Short:
+                        maskedValue = (int) (longValue & 0xFFFF);
+                        break;
+                    case Int:
+                    case Long:
+                        maskedValue = (int) longValue;
+                        break;
+                    default:
+                        throw GraalError.shouldNotReachHere();
+                }
+                masm.cmp(size, asRegister(x), maskedValue);
+            }
+        }
+    }
+
+    public static class FloatCompareOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<FloatCompareOp> TYPE = LIRInstructionClass.create(FloatCompareOp.class);
+
+        @Use protected Value x;
+        @Use({REG, CONST}) protected Value y;
+        private final Condition condition;
+        private final boolean unorderedIsTrue;
+
+        public FloatCompareOp(Value x, Value y, Condition condition, boolean unorderedIsTrue) {
+            super(TYPE);
+            assert !isJavaConstant(y) || isFloatCmpConstant(y, condition, unorderedIsTrue);
+            this.x = x;
+            this.y = y;
+            this.condition = condition;
+            this.unorderedIsTrue = unorderedIsTrue;
+        }
+
+        /**
+         * Checks if val can be used as a constant for the gpCompare operation or not.
+         */
+        public static boolean isFloatCmpConstant(Value val, Condition condition, boolean unorderedIsTrue) {
+            // If the condition is "EQ || unordered" or "NE && unordered" we have to use 2 registers
+            // in any case.
+            if (!(condition == Condition.EQ && unorderedIsTrue || condition == Condition.NE && !unorderedIsTrue)) {
+                return false;
+            }
+            return isJavaConstant(val) && asJavaConstant(val).isDefaultForKind();
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            assert isRegister(x);
+            int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            if (isRegister(y)) {
+                masm.fcmp(size, asRegister(x), asRegister(y));
+                // There is no condition code for "EQ || unordered" nor one for "NE && unordered",
+                // so we have to fix them up ourselves.
+                // In both cases we combine the asked for condition into the EQ, respectively NE
+                // condition, i.e.
+                // if EQ && unoreredIsTrue, then the EQ flag will be set if the two values gpCompare
+                // unequal but are
+                // unordered.
+                if (condition == Condition.EQ && unorderedIsTrue) {
+                    // if f1 ordered f2:
+                    // result = f1 == f2
+                    // else:
+                    // result = EQUAL
+                    int nzcv = 0b0100;   // EQUAL -> Z = 1
+                    masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC);
+                } else if (condition == Condition.NE && !unorderedIsTrue) {
+                    // if f1 ordered f2:
+                    // result = f1 != f2
+                    // else:
+                    // result = !NE == EQUAL
+                    int nzcv = 0b0100;   // EQUAL -> Z = 1
+                    masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC);
+                }
+            } else {
+                // cmp against +0.0
+                masm.fcmpZero(size, asRegister(x));
+            }
+        }
+
+        @Override
+        public void verify() {
+            assert x.getPlatformKind().equals(y.getPlatformKind()) : "a: " + x + " b: " + y;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java
new file mode 100644
index 0000000..9604854
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.function.Function;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.PatchLabelKind;
+import org.graalvm.compiler.code.CompilationResult.JumpTable;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64ControlFlow {
+
+    /**
+     * Compares integer register to 0 and branches if condition is true. Condition may only be equal
+     * or non-equal.
+     */
+    // TODO (das) where do we need this?
+    // public static class CompareAndBranchOp extends AArch64LIRInstruction implements
+    // StandardOp.BranchOp {
+    // private final ConditionFlag condition;
+    // private final LabelRef destination;
+    // @Use({REG}) private Value x;
+    //
+    // public CompareAndBranchOp(Condition condition, LabelRef destination, Value x) {
+    // assert condition == Condition.EQ || condition == Condition.NE;
+    // assert ARMv8.isGpKind(x.getKind());
+    // this.condition = condition == Condition.EQ ? ConditionFlag.EQ : ConditionFlag.NE;
+    // this.destination = destination;
+    // this.x = x;
+    // }
+    //
+    // @Override
+    // public void emitCode(CompilationResultBuilder crb, ARMv8MacroAssembler masm) {
+    // int size = ARMv8.bitsize(x.getKind());
+    // if (condition == ConditionFlag.EQ) {
+    // masm.cbz(size, asRegister(x), destination.label());
+    // } else {
+    // masm.cbnz(size, asRegister(x), destination.label());
+    // }
+    // }
+    // }
+
+    public static class BranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
+
+        private final AArch64Assembler.ConditionFlag condition;
+        private final LabelRef trueDestination;
+        private final LabelRef falseDestination;
+
+        private final double trueDestinationProbability;
+
+        public BranchOp(AArch64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            super(TYPE);
+            this.condition = condition;
+            this.trueDestination = trueDestination;
+            this.falseDestination = falseDestination;
+            this.trueDestinationProbability = trueDestinationProbability;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            /*
+             * Explanation: Depending on what the successor edge is, we can use the fall-through to
+             * optimize the generated code. If neither is a successor edge, use the branch
+             * probability to try to take the conditional jump as often as possible to avoid
+             * executing two instructions instead of one.
+             */
+            if (crb.isSuccessorEdge(trueDestination)) {
+                masm.branchConditionally(condition.negate(), falseDestination.label());
+            } else if (crb.isSuccessorEdge(falseDestination)) {
+                masm.branchConditionally(condition, trueDestination.label());
+            } else if (trueDestinationProbability < 0.5) {
+                masm.branchConditionally(condition.negate(), falseDestination.label());
+                masm.jmp(trueDestination.label());
+            } else {
+                masm.branchConditionally(condition, trueDestination.label());
+                masm.jmp(falseDestination.label());
+            }
+        }
+
+    }
+
+    @Opcode("CMOVE")
+    public static class CondMoveOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
+
+        @Def protected Value result;
+        @Use protected Value trueValue;
+        @Use protected Value falseValue;
+        private final AArch64Assembler.ConditionFlag condition;
+
+        public CondMoveOp(Variable result, AArch64Assembler.ConditionFlag condition, Value trueValue, Value falseValue) {
+            super(TYPE);
+            assert trueValue.getPlatformKind() == falseValue.getPlatformKind() && trueValue.getPlatformKind() == result.getPlatformKind();
+            this.result = result;
+            this.condition = condition;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Kind kind = (AArch64Kind) trueValue.getPlatformKind();
+            int size = kind.getSizeInBytes() * Byte.SIZE;
+            if (kind.isInteger()) {
+                masm.cmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition);
+            } else {
+                masm.fcmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition);
+            }
+        }
+    }
+
+    public static class StrategySwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
+
+        private final Constant[] keyConstants;
+        protected final SwitchStrategy strategy;
+        private final Function<Condition, ConditionFlag> converter;
+        private final LabelRef[] keyTargets;
+        private final LabelRef defaultTarget;
+        @Alive protected Value key;
+        // TODO (das) This could be optimized: We only need the scratch register in case of a
+        // datapatch, or too large immediates.
+        @Temp protected Value scratch;
+
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch,
+                        Function<Condition, ConditionFlag> converter) {
+            this(TYPE, strategy, keyTargets, defaultTarget, key, scratch, converter);
+        }
+
+        protected StrategySwitchOp(LIRInstructionClass<? extends StrategySwitchOp> c, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch,
+                        Function<Condition, ConditionFlag> converter) {
+            super(c);
+            this.strategy = strategy;
+            this.converter = converter;
+            this.keyConstants = strategy.getKeyConstants();
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+            this.key = key;
+            this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            strategy.run(new SwitchClosure(asRegister(key), crb, masm));
+        }
+
+        public class SwitchClosure extends BaseSwitchClosure {
+
+            protected final Register keyRegister;
+            protected final CompilationResultBuilder crb;
+            protected final AArch64MacroAssembler masm;
+
+            protected SwitchClosure(Register keyRegister, CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+                super(crb, masm, keyTargets, defaultTarget);
+                this.keyRegister = keyRegister;
+                this.crb = crb;
+                this.masm = masm;
+            }
+
+            protected void emitComparison(Constant c) {
+                JavaConstant jc = (JavaConstant) c;
+                ConstantValue constVal = new ConstantValue(LIRKind.value(key.getPlatformKind()), c);
+                switch (jc.getJavaKind()) {
+                    case Int:
+                        long lc = jc.asLong();
+                        assert NumUtil.isInt(lc);
+                        emitCompare(crb, masm, key, scratch, constVal);
+                        break;
+                    case Long:
+                        emitCompare(crb, masm, key, scratch, constVal);
+                        break;
+                    case Object:
+                        emitCompare(crb, masm, key, scratch, constVal);
+                        break;
+                    default:
+                        throw new GraalError("switch only supported for int, long and object");
+                }
+            }
+
+            @Override
+            protected void conditionalJump(int index, Condition condition, Label target) {
+                emitComparison(keyConstants[index]);
+                masm.branchConditionally(converter.apply(condition), target);
+            }
+        }
+    }
+
+    public static class TableSwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
+
+        private final int lowKey;
+        private final LabelRef defaultTarget;
+        private final LabelRef[] targets;
+        @Alive protected Variable keyValue;
+        @Temp protected Variable scratchValue;
+
+        public TableSwitchOp(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Variable key, Variable scratch) {
+            super(TYPE);
+            this.lowKey = lowKey;
+            this.defaultTarget = defaultTarget;
+            this.targets = targets;
+            this.keyValue = key;
+            this.scratchValue = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register key = asRegister(keyValue);
+            Register scratch = asRegister(scratchValue);
+            if (lowKey != 0) {
+                if (AArch64MacroAssembler.isArithmeticImmediate(lowKey)) {
+                    masm.sub(32, key, key, lowKey);
+                } else {
+                    ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(lowKey));
+                    AArch64Move.move(crb, masm, scratchValue, constVal);
+                    masm.sub(32, key, key, scratch);
+                }
+            }
+            if (defaultTarget != null) {
+                // if key is not in table range, jump to default target if it exists.
+                ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(targets.length));
+                emitCompare(crb, masm, keyValue, scratchValue, constVal);
+                masm.branchConditionally(AArch64Assembler.ConditionFlag.HS, defaultTarget.label());
+            }
+
+            // Load the start address of the jump table - which starts 3 instructions after the adr
+            // - into scratch.
+            masm.adr(scratch, 4 * 3);
+            masm.ldr(32, scratch, AArch64Address.createRegisterOffsetAddress(scratch, key, /* scaled */true));
+            masm.jmp(scratch);
+            int jumpTablePos = masm.position();
+            // emit jump table entries
+            for (LabelRef target : targets) {
+                Label label = target.label();
+                if (label.isBound()) {
+                    masm.emitInt(target.label().position());
+                } else {
+                    label.addPatchAt(masm.position());
+                    masm.emitInt(PatchLabelKind.JUMP_ADDRESS.encoding);
+                }
+            }
+            JumpTable jt = new JumpTable(jumpTablePos, lowKey, lowKey + targets.length - 1, 4);
+            crb.compilationResult.addAnnotation(jt);
+        }
+    }
+
+    private static void emitCompare(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value key, Value scratchValue, ConstantValue c) {
+        long imm = c.getJavaConstant().asLong();
+        final int size = key.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        if (AArch64MacroAssembler.isComparisonImmediate(imm)) {
+            masm.cmp(size, asRegister(key), (int) imm);
+        } else {
+            AArch64Move.move(crb, masm, asAllocatableValue(scratchValue), c);
+            masm.cmp(size, asRegister(key), asRegister(scratchValue));
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMap.java
new file mode 100644
index 0000000..e2988a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMap.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+/**
+ * AArch64 specific frame map.
+ * <p/>
+ * This is the format of an AArch64 stack frame:
+ * <p/>
+ *
+ * <pre>
+ *   Base       Contents
+ *
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *   ---------+--------------------------------+-------------------------
+ *            | return address                 |    |            ^
+ *            | prev. frame pointer            |    |            |
+ *            +--------------------------------+    |            |
+ *            | spill slot 0                   |    | negative   |      ^
+ *    callee  :     ...                        :    v offsets    |      |
+ *    frame   | spill slot n                   |  -----        total  frame
+ *            +--------------------------------+               frame  size
+ *            | alignment padding              |               size     |
+ *            +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |      |
+ *            :     ...                        :    | positive   |      |
+ *            | outgoing overflow argument 0   |    | offsets    v      v
+ *    %sp-->  +--------------------------------+---------------------------
+ *
+ * </pre>
+ *
+ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such
+ * a block may be greater than the size of a normal spill slot or the word size.
+ * <p/>
+ * A runtime can reserve space at the beginning of the overflow argument area. The calling
+ * convention can specify that the first overflow stack argument is not at offset 0, but at a
+ * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that
+ * call-free methods also have this space reserved. Then the VM can use the memory at offset 0
+ * relative to the stack pointer.
+ * <p/>
+ */
+public class AArch64FrameMap extends FrameMap {
+    // Note: Spill size includes callee save area
+
+    /**
+     * Creates a new frame map for the specified method.
+     */
+    public AArch64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
+        initialSpillSize = frameSetupSize();
+        spillSize = initialSpillSize;
+    }
+
+    @Override
+    public int totalFrameSize() {
+        // frameSize + return address + frame pointer
+        return frameSize() + frameSetupSize();
+    }
+
+    private int frameSetupSize() {
+        // Size of return address and frame pointer that are saved in function prologue
+        return getTarget().arch.getWordSize() * 2;
+    }
+
+    @Override
+    public int currentFrameSize() {
+        return alignFrameSize(outgoingSize + spillSize);
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        assert spillSize == initialSpillSize : "Deoptimization rescue slot must be the first stack slot";
+        return allocateSpillSlot(LIRKind.value(AArch64Kind.QWORD));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMapBuilder.java
new file mode 100644
index 0000000..4be0f92
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64FrameMapBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+public class AArch64FrameMapBuilder extends FrameMapBuilderImpl {
+
+    public AArch64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+        super(frameMap, codeCache, registerConfig);
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        return ((AArch64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64LIRInstruction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64LIRInstruction.java
new file mode 100644
index 0000000..d596583
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64LIRInstruction.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public abstract class AArch64LIRInstruction extends LIRInstruction {
+    protected AArch64LIRInstruction(LIRInstructionClass<? extends AArch64LIRInstruction> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AArch64MacroAssembler) crb.asm);
+    }
+
+    protected abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java
new file mode 100644
index 0000000..0fb4e83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.NullCheck;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64Move {
+
+    public static class LoadInlineConstant extends AArch64LIRInstruction implements LoadConstantOp {
+        public static final LIRInstructionClass<LoadInlineConstant> TYPE = LIRInstructionClass.create(LoadInlineConstant.class);
+
+        private JavaConstant constant;
+        @Def({REG, STACK}) AllocatableValue result;
+
+        public LoadInlineConstant(JavaConstant constant, AllocatableValue result) {
+            super(TYPE);
+            this.constant = constant;
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, result, constant);
+            } else if (isStackSlot(result)) {
+                StackSlot slot = asStackSlot(result);
+                const2stack(crb, masm, slot, constant);
+            }
+        }
+
+        @Override
+        public Constant getConstant() {
+            return constant;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    @Opcode("MOVE")
+    public static class Move extends AArch64LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<Move> TYPE = LIRInstructionClass.create(Move.class);
+
+        @Def({REG, STACK, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue input;
+
+        public Move(AllocatableValue result, AllocatableValue input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            move(crb, masm, getResult(), getInput());
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static class LoadAddressOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class);
+
+        @Def protected AllocatableValue result;
+        @Use(COMPOSITE) protected AArch64AddressValue address;
+
+        public LoadAddressOp(AllocatableValue result, AArch64AddressValue address) {
+            super(TYPE);
+            this.result = result;
+            this.address = address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            AArch64Address adr = address.toAddress();
+            masm.loadAddress(dst, adr, address.getPlatformKind().getSizeInBytes());
+        }
+    }
+
+    public static class LoadDataOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<LoadDataOp> TYPE = LIRInstructionClass.create(LoadDataOp.class);
+
+        @Def protected AllocatableValue result;
+        private final DataPointerConstant data;
+
+        public LoadDataOp(AllocatableValue result, DataPointerConstant data) {
+            super(TYPE);
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            masm.loadAddress(dst, (AArch64Address) crb.recordDataReferenceInCode(data), data.getAlignment());
+        }
+    }
+
+    public static class StackLoadAddressOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class);
+
+        @Def protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot;
+
+        public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) {
+            super(TYPE);
+            assert slot instanceof VirtualStackSlot || slot instanceof StackSlot;
+            this.result = result;
+            this.slot = slot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Address address = (AArch64Address) crb.asAddress(slot);
+            PlatformKind kind = AArch64Kind.QWORD;
+            masm.loadAddress(asRegister(result, kind), address, kind.getSizeInBytes());
+        }
+    }
+
+    public static class MembarOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
+
+        @SuppressWarnings("unused") private final int barriers;
+
+        public MembarOp(int barriers) {
+            super(TYPE);
+            this.barriers = barriers;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // As I understand it load acquire/store release have the same semantics as on IA64
+            // and allow us to handle LoadStore, LoadLoad and StoreStore without an explicit
+            // barrier.
+            // But Graal support to figure out if a load/store is volatile is non-existant so for
+            // now
+            // just use
+            // memory barriers everywhere.
+            // if ((barrier & MemoryBarriers.STORE_LOAD) != 0) {
+            masm.dmb(AArch64MacroAssembler.BarrierKind.ANY_ANY);
+            // }
+        }
+    }
+
+    abstract static class MemOp extends AArch64LIRInstruction implements StandardOp.ImplicitNullCheck {
+
+        protected final AArch64Kind kind;
+        @Use({COMPOSITE}) protected AArch64AddressValue addressValue;
+        @State protected LIRFrameState state;
+
+        MemOp(LIRInstructionClass<? extends MemOp> c, AArch64Kind kind, AArch64AddressValue address, LIRFrameState state) {
+            super(c);
+            this.kind = kind;
+            this.addressValue = address;
+            this.state = state;
+        }
+
+        protected abstract void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emitMemAccess(crb, masm);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            int immediate = addressValue.getImmediate();
+            if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && immediate >= 0 && immediate < implicitNullCheckLimit) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    public static final class LoadOp extends MemOp {
+        public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
+
+        @Def protected AllocatableValue result;
+
+        public LoadOp(AArch64Kind kind, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.result = result;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Address address = addressValue.toAddress();
+            Register dst = asRegister(result);
+
+            int destSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            int srcSize = kind.getSizeInBytes() * Byte.SIZE;
+            if (kind.isInteger()) {
+                // TODO How to load unsigned chars without the necessary information?
+                masm.ldrs(destSize, srcSize, dst, address);
+            } else {
+                assert srcSize == destSize;
+                masm.fldr(srcSize, dst, address);
+            }
+        }
+    }
+
+    public static class StoreOp extends MemOp {
+        public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class);
+        @Use protected AllocatableValue input;
+
+        public StoreOp(AArch64Kind kind, AArch64AddressValue address, AllocatableValue input, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.input = input;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitStore(crb, masm, kind, addressValue.toAddress(), input);
+        }
+    }
+
+    public static final class StoreConstantOp extends MemOp {
+        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
+
+        protected final JavaConstant input;
+
+        public StoreConstantOp(AArch64Kind kind, AArch64AddressValue address, JavaConstant input, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.input = input;
+            if (!input.isDefaultForKind()) {
+                throw GraalError.shouldNotReachHere("Can only store null constants to memory");
+            }
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitStore(crb, masm, kind, addressValue.toAddress(), zr.asValue(LIRKind.combine(addressValue)));
+        }
+    }
+
+    public static final class NullCheckOp extends AArch64LIRInstruction implements NullCheck {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
+
+        @Use(COMPOSITE) protected AArch64AddressValue address;
+        @State protected LIRFrameState state;
+
+        public NullCheckOp(AArch64AddressValue address, LIRFrameState state) {
+            super(TYPE);
+            this.address = address;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            crb.recordImplicitException(masm.position(), state);
+            masm.ldr(64, zr, address.toAddress());
+        }
+
+        @Override
+        public Value getCheckedValue() {
+            return address.base;
+        }
+
+        @Override
+        public LIRFrameState getState() {
+            return state;
+        }
+    }
+
+    /**
+     * Compare and swap instruction. Does the following atomically: <code>
+     *  CAS(newVal, expected, address):
+     *    oldVal = *address
+     *    if oldVal == expected:
+     *        *address = newVal
+     *    return oldVal
+     * </code>
+     */
+    @Opcode("CAS")
+    public static class CompareAndSwapOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class);
+
+        @Def protected AllocatableValue resultValue;
+        @Alive protected Value expectedValue;
+        @Alive protected AllocatableValue newValue;
+        @Alive protected AllocatableValue addressValue;
+        @Temp protected AllocatableValue scratchValue;
+
+        public CompareAndSwapOp(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AllocatableValue addressValue, AllocatableValue scratch) {
+            super(TYPE);
+            this.resultValue = result;
+            this.expectedValue = expectedValue;
+            this.newValue = newValue;
+            this.addressValue = addressValue;
+            this.scratchValue = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Kind kind = (AArch64Kind) expectedValue.getPlatformKind();
+            assert kind.isInteger();
+            final int size = kind.getSizeInBytes() * Byte.SIZE;
+
+            Register address = asRegister(addressValue);
+            Register result = asRegister(resultValue);
+            Register newVal = asRegister(newValue);
+            Register scratch = asRegister(scratchValue);
+            // We could avoid using a scratch register here, by reusing resultValue for the stlxr
+            // success flag and issue a mov resultValue, expectedValue in case of success before
+            // returning.
+            Label retry = new Label();
+            Label fail = new Label();
+            masm.bind(retry);
+            masm.ldaxr(size, result, address);
+            AArch64Compare.gpCompare(masm, resultValue, expectedValue);
+            masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, fail);
+            masm.stlxr(size, scratch, newVal, address);
+            // if scratch == 0 then write successful, else retry.
+            masm.cbnz(32, scratch, retry);
+            masm.bind(fail);
+        }
+    }
+
+    private static void emitStore(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AArch64Kind kind, AArch64Address dst, Value src) {
+        int destSize = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.str(destSize, asRegister(src), dst);
+        } else {
+            masm.fstr(destSize, asRegister(src), dst);
+        }
+    }
+
+    public static void move(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) {
+        if (isRegister(input)) {
+            if (isRegister(result)) {
+                reg2reg(crb, masm, result, asAllocatableValue(input));
+            } else if (isStackSlot(result)) {
+                reg2stack(crb, masm, result, asAllocatableValue(input));
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else if (isStackSlot(input)) {
+            if (isRegister(result)) {
+                stack2reg(crb, masm, result, asAllocatableValue(input));
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else if (isJavaConstant(input)) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, result, asJavaConstant(input));
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static void reg2reg(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        Register dst = asRegister(result);
+        Register src = asRegister(input);
+        if (src.equals(dst)) {
+            return;
+        }
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.mov(size, dst, src);
+        } else {
+            masm.fmov(size, dst, src);
+        }
+    }
+
+    private static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        AArch64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL);
+        Register src = asRegister(input);
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.str(size, src, dest);
+        } else {
+            masm.fstr(size, src, dest);
+        }
+    }
+
+    private static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        final int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), result);
+            masm.ldr(size, asRegister(result), src);
+        } else {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                AllocatableValue scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input));
+                AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), scratchRegisterValue);
+                masm.fldr(size, asRegister(result), src);
+            }
+        }
+    }
+
+    private static void const2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value result, JavaConstant input) {
+        Register dst = asRegister(result);
+        switch (input.getJavaKind().getStackKind()) {
+            case Int:
+                final int value = input.asInt();
+                int maskedValue;
+                switch (input.getJavaKind()) {
+                    case Boolean:
+                    case Byte:
+                        maskedValue = value & 0xFF;
+                        break;
+                    case Char:
+                    case Short:
+                        maskedValue = value & 0xFFFF;
+                        break;
+                    case Int:
+                        maskedValue = value;
+                        break;
+                    default:
+                        throw GraalError.shouldNotReachHere();
+                }
+                masm.mov(dst, maskedValue);
+                break;
+            case Long:
+                masm.mov(dst, input.asLong());
+                break;
+            case Float:
+                if (AArch64MacroAssembler.isFloatImmediate(input.asFloat())) {
+                    masm.fmov(32, dst, input.asFloat());
+                } else {
+                    masm.fldr(32, dst, (AArch64Address) crb.asFloatConstRef(input));
+                }
+                break;
+            case Double:
+                if (AArch64MacroAssembler.isDoubleImmediate(input.asDouble())) {
+                    masm.fmov(64, dst, input.asDouble());
+                } else {
+                    masm.fldr(64, dst, (AArch64Address) crb.asDoubleConstRef(input));
+                }
+                break;
+            case Object:
+                if (input.isNull()) {
+                    masm.mov(dst, 0);
+                } else if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(input);
+                    masm.movNativeAddress(dst, 0xDEADDEADDEADDEADL);
+                } else {
+                    masm.ldr(64, dst, (AArch64Address) crb.recordDataReferenceInCode(input, 8));
+                }
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("kind=" + input.getJavaKind().getStackKind());
+        }
+    }
+
+    private static void const2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value result, JavaConstant constant) {
+        if (constant.isDefaultForKind() || constant.isNull()) {
+            AArch64Address resultAddress = (AArch64Address) crb.asAddress(result);
+            emitStore(crb, masm, (AArch64Kind) result.getPlatformKind(), resultAddress, zr.asValue(LIRKind.combine(result)));
+        } else {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(result));
+                const2reg(crb, masm, scratchRegisterValue, constant);
+                AArch64Address resultAddress = (AArch64Address) crb.asAddress(result);
+                emitStore(crb, masm, (AArch64Kind) result.getPlatformKind(), resultAddress, scratchRegisterValue);
+            }
+        }
+    }
+
+    /**
+     * Returns AArch64Address of given StackSlot. We cannot use CompilationResultBuilder.asAddress
+     * since this calls AArch64MacroAssembler.makeAddress with displacements that may be larger than
+     * 9-bit signed, which cannot be handled by that method.
+     *
+     * Instead we create an address ourselves. We use scaled unsigned addressing since we know the
+     * transfersize, which gives us a 15-bit address range (for longs/doubles) respectively a 14-bit
+     * range (for everything else).
+     *
+     * @param scratch Scratch register that can be used to load address. If Value.ILLEGAL this
+     *            instruction fails if we try to access a StackSlot that is too large to be loaded
+     *            directly.
+     * @return AArch64Address of given StackSlot. Uses scratch register if necessary to do so.
+     */
+    private static AArch64Address loadStackSlotAddress(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, AllocatableValue scratch) {
+        int displacement = crb.frameMap.offsetForStackSlot(slot);
+        int transferSize = slot.getPlatformKind().getSizeInBytes();
+        Register scratchReg = Value.ILLEGAL.equals(scratch) ? zr : asRegister(scratch);
+        return masm.makeAddress(sp, displacement, scratchReg, transferSize, /* allowOverwrite */false);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PauseOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PauseOp.java
new file mode 100644
index 0000000..41ad26a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PauseOp.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Emits a pause.
+ */
+@Opcode("PAUSE")
+public final class AArch64PauseOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64PauseOp> TYPE = LIRInstructionClass.create(AArch64PauseOp.class);
+
+    public AArch64PauseOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        masm.pause();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PrefetchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PrefetchOp.java
new file mode 100644
index 0000000..814c32c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64PrefetchOp.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64PrefetchOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64PrefetchOp> TYPE = LIRInstructionClass.create(AArch64PrefetchOp.class);
+
+    @SuppressWarnings("unused") private final int instr;  // AllocatePrefetchInstr
+    @Alive({COMPOSITE}) protected AArch64AddressValue address;
+
+    public AArch64PrefetchOp(AArch64AddressValue address, int instr) {
+        super(TYPE);
+        this.address = address;
+        this.instr = instr;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // TODO implement prefetch
+        masm.nop();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ReinterpretOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ReinterpretOp.java
new file mode 100644
index 0000000..77dd2bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ReinterpretOp.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Instruction that reinterprets some bit pattern as a different type. It is possible to reinterpret
+ * the following: - int <-> float - long <-> double
+ */
+public class AArch64ReinterpretOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64ReinterpretOp> TYPE = LIRInstructionClass.create(AArch64ReinterpretOp.class);
+
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    public AArch64ReinterpretOp(AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        AArch64Kind from = (AArch64Kind) inputValue.getPlatformKind();
+        AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind();
+        assert from.getSizeInBytes() == to.getSizeInBytes() && from.isInteger() ^ to.isInteger();
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind();
+        final int size = to.getSizeInBytes() * Byte.SIZE;
+        masm.fmov(size, result, input);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SignExtendOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SignExtendOp.java
new file mode 100644
index 0000000..47f4d99
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SignExtendOp.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+@Opcode("SIGNEXTEND")
+public class AArch64SignExtendOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64SignExtendOp> TYPE = LIRInstructionClass.create(AArch64SignExtendOp.class);
+
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+    private final int fromBits;
+    private final int toBits;
+
+    public AArch64SignExtendOp(AllocatableValue resultValue, AllocatableValue inputValue, int fromBits, int toBits) {
+        super(TYPE);
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+        this.fromBits = fromBits;
+        this.toBits = toBits;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        masm.sxt(toBits, fromBits, result, input);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64AddressValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64AddressValue.java
new file mode 100644
index 0000000..d67920f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64AddressValue.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class AMD64AddressValue extends CompositeValue {
+
+    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
+    @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
+    protected final Scale scale;
+    protected final int displacement;
+
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
+    public AMD64AddressValue(ValueKind<?> kind, AllocatableValue base, int displacement) {
+        this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
+    }
+
+    public AMD64AddressValue(ValueKind<?> kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
+        super(kind);
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+
+        assert scale != null;
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags);
+        if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) {
+            return new AMD64AddressValue(getValueKind(), newBase, newIndex, scale, displacement);
+        }
+        return this;
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, index, mode, flags);
+    }
+
+    private static Register toRegister(AllocatableValue value) {
+        if (value.equals(Value.ILLEGAL)) {
+            return Register.None;
+        } else {
+            RegisterValue reg = (RegisterValue) value;
+            return reg.getRegister();
+        }
+    }
+
+    public AMD64Address toAddress() {
+        return new AMD64Address(toRegister(base), toRegister(index), scale, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (isLegal(index)) {
+            s.append(sep).append(index).append(" * ").append(scale.value);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) {
+        return value.equals(base) && index.equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof AMD64AddressValue) {
+            AMD64AddressValue addr = (AMD64AddressValue) obj;
+            return getValueKind().equals(addr.getValueKind()) && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getValueKind().hashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Arithmetic.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Arithmetic.java
new file mode 100644
index 0000000..cd1a24c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Arithmetic.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public enum AMD64Arithmetic {
+    FREM,
+    DREM;
+
+    public static class FPDivRemOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<FPDivRemOp> TYPE = LIRInstructionClass.create(FPDivRemOp.class);
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def protected AllocatableValue result;
+        @Use protected AllocatableValue x;
+        @Use protected AllocatableValue y;
+        @Temp protected AllocatableValue raxTemp;
+
+        public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.result = result;
+            this.raxTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD));
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Address tmp = new AMD64Address(AMD64.rsp);
+            masm.subq(AMD64.rsp, 8);
+            if (opcode == FREM) {
+                masm.movflt(tmp, asRegister(y));
+                masm.flds(tmp);
+                masm.movflt(tmp, asRegister(x));
+                masm.flds(tmp);
+            } else {
+                assert opcode == DREM;
+                masm.movdbl(tmp, asRegister(y));
+                masm.fldd(tmp);
+                masm.movdbl(tmp, asRegister(x));
+                masm.fldd(tmp);
+            }
+
+            Label label = new Label();
+            masm.bind(label);
+            masm.fprem();
+            masm.fwait();
+            masm.fnstswAX();
+            masm.testl(AMD64.rax, 0x400);
+            masm.jcc(ConditionFlag.NotZero, label);
+            masm.fxch(1);
+            masm.fpop();
+
+            if (opcode == FREM) {
+                masm.fstps(tmp);
+                masm.movflt(asRegister(result), tmp);
+            } else {
+                masm.fstpd(tmp);
+                masm.movdbl(asRegister(result), tmp);
+            }
+            masm.addq(AMD64.rsp, 8);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert (opcode.name().startsWith("F") && result.getPlatformKind() == AMD64Kind.SINGLE && x.getPlatformKind() == AMD64Kind.SINGLE && y.getPlatformKind() == AMD64Kind.SINGLE) ||
+                            (opcode.name().startsWith("D") && result.getPlatformKind() == AMD64Kind.DOUBLE && x.getPlatformKind() == AMD64Kind.DOUBLE && y.getPlatformKind() == AMD64Kind.DOUBLE);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java
new file mode 100644
index 0000000..55b8655
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This interface can be used to generate AMD64 LIR for arithmetic operations.
+ */
+public interface AMD64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool {
+
+    Value emitCountLeadingZeros(Value value);
+
+    Value emitCountTrailingZeros(Value value);
+
+    enum RoundingMode {
+        NEAREST(0),
+        DOWN(1),
+        UP(2),
+        TRUNCATE(3);
+
+        public final int encoding;
+
+        RoundingMode(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    Value emitRound(Value value, RoundingMode mode);
+
+    void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java
new file mode 100644
index 0000000..84462dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import sun.misc.Unsafe;
+
+/**
+ * Emits code which compares two arrays of the same length. If the CPU supports any vector
+ * instructions specialized code is emitted to leverage these instructions.
+ */
+@Opcode("ARRAY_EQUALS")
+public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ArrayEqualsOp> TYPE = LIRInstructionClass.create(AMD64ArrayEqualsOp.class);
+
+    private final JavaKind kind;
+    private final int arrayBaseOffset;
+    private final int arrayIndexScale;
+
+    @Def({REG}) protected Value resultValue;
+    @Alive({REG}) protected Value array1Value;
+    @Alive({REG}) protected Value array2Value;
+    @Alive({REG}) protected Value lengthValue;
+    @Temp({REG}) protected Value temp1;
+    @Temp({REG}) protected Value temp2;
+    @Temp({REG}) protected Value temp3;
+    @Temp({REG}) protected Value temp4;
+    @Temp({REG, ILLEGAL}) protected Value vectorTemp1;
+    @Temp({REG, ILLEGAL}) protected Value vectorTemp2;
+
+    public AMD64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) {
+        super(TYPE);
+        this.kind = kind;
+
+        Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
+        this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass);
+        this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass);
+
+        this.resultValue = result;
+        this.array1Value = array1;
+        this.array2Value = array2;
+        this.lengthValue = length;
+
+        // Allocate some temporaries.
+        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+        this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+
+        // We only need the vector temporaries if we generate SSE code.
+        if (supportsSSE41(tool.target())) {
+            this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.vectorTemp2 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+        } else {
+            this.vectorTemp1 = Value.ILLEGAL;
+            this.vectorTemp2 = Value.ILLEGAL;
+        }
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register array1 = asRegister(temp1);
+        Register array2 = asRegister(temp2);
+        Register length = asRegister(temp3);
+
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label done = new Label();
+
+        // Load array base addresses.
+        masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset));
+        masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset));
+
+        // Get array length in bytes.
+        masm.imull(length, asRegister(lengthValue), arrayIndexScale);
+        masm.movl(result, length); // copy
+
+        if (supportsAVX2(crb.target)) {
+            emitAVXCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
+        } else if (supportsSSE41(crb.target)) {
+            emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
+        }
+
+        emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
+        emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel);
+
+        // Return true
+        masm.bind(trueLabel);
+        masm.movl(result, 1);
+        masm.jmpb(done);
+
+        // Return false
+        masm.bind(falseLabel);
+        masm.xorl(result, result);
+
+        // That's it
+        masm.bind(done);
+    }
+
+    /**
+     * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions.
+     *
+     * @param target target description of the underlying architecture
+     * @return true if the underlying architecture supports SSE 4.1
+     */
+    private static boolean supportsSSE41(TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(CPUFeature.SSE4_1);
+    }
+
+    /**
+     * Vector size used in {@link #emitSSE41Compare}.
+     */
+    private static final int SSE4_1_VECTOR_SIZE = 16;
+
+    /**
+     * Emits code that uses SSE4.1 128-bit (16-byte) vector compares.
+     */
+    private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        assert supportsSSE41(crb.target);
+
+        Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
+        Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE);
+
+        Label loop = new Label();
+        Label compareTail = new Label();
+
+        // Compare 16-byte vectors
+        masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes)
+        masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes)
+        masm.jccb(ConditionFlag.Zero, compareTail);
+
+        masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.negq(length);
+
+        // Align the main loop
+        masm.align(crb.target.wordSize * 2);
+        masm.bind(loop);
+        masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.pxor(vector1, vector2);
+        masm.ptest(vector1, vector1);
+        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.addq(length, SSE4_1_VECTOR_SIZE);
+        masm.jcc(ConditionFlag.NotZero, loop);
+
+        masm.testl(result, result);
+        masm.jcc(ConditionFlag.Zero, trueLabel);
+
+        /*
+         * Compare the remaining bytes with an unaligned memory load aligned to the end of the
+         * array.
+         */
+        masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE));
+        masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE));
+        masm.pxor(vector1, vector2);
+        masm.ptest(vector1, vector1);
+        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.jmp(trueLabel);
+
+        masm.bind(compareTail);
+        masm.movl(length, result);
+    }
+
+    /**
+     * Returns if the underlying AMD64 architecture supports AVX instructions.
+     *
+     * @param target target description of the underlying architecture
+     * @return true if the underlying architecture supports AVX
+     */
+    private static boolean supportsAVX2(TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(CPUFeature.AVX2);
+    }
+
+    /**
+     * Vector size used in {@link #emitAVXCompare}.
+     */
+    private static final int AVX_VECTOR_SIZE = 32;
+
+    private void emitAVXCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        assert supportsAVX2(crb.target);
+
+        Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
+        Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE);
+
+        Label loop = new Label();
+        Label compareTail = new Label();
+
+        // Compare 16-byte vectors
+        masm.andl(result, AVX_VECTOR_SIZE - 1); // tail count (in bytes)
+        masm.andl(length, ~(AVX_VECTOR_SIZE - 1)); // vector count (in bytes)
+        masm.jccb(ConditionFlag.Zero, compareTail);
+
+        masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.negq(length);
+
+        // Align the main loop
+        masm.align(crb.target.wordSize * 2);
+        masm.bind(loop);
+        masm.vmovdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.vmovdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.vpxor(vector1, vector1, vector2);
+        masm.vptest(vector1, vector1);
+        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.addq(length, AVX_VECTOR_SIZE);
+        masm.jcc(ConditionFlag.NotZero, loop);
+
+        masm.testl(result, result);
+        masm.jcc(ConditionFlag.Zero, trueLabel);
+
+        /*
+         * Compare the remaining bytes with an unaligned memory load aligned to the end of the
+         * array.
+         */
+        masm.vmovdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -AVX_VECTOR_SIZE));
+        masm.vmovdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -AVX_VECTOR_SIZE));
+        masm.vpxor(vector1, vector1, vector2);
+        masm.vptest(vector1, vector1);
+        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.jmp(trueLabel);
+
+        masm.bind(compareTail);
+        masm.movl(length, result);
+    }
+
+    /**
+     * Vector size used in {@link #emit8ByteCompare}.
+     */
+    private static final int VECTOR_SIZE = 8;
+
+    /**
+     * Emits code that uses 8-byte vector compares.
+     */
+    private void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        Label loop = new Label();
+        Label compareTail = new Label();
+
+        Register temp = asRegister(temp4);
+
+        masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes)
+        masm.andl(length, ~(VECTOR_SIZE - 1));  // vector count (in bytes)
+        masm.jccb(ConditionFlag.Zero, compareTail);
+
+        masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.negq(length);
+
+        // Align the main loop
+        masm.align(crb.target.wordSize * 2);
+        masm.bind(loop);
+        masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0));
+        masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0));
+        masm.jccb(ConditionFlag.NotEqual, falseLabel);
+        masm.addq(length, VECTOR_SIZE);
+        masm.jccb(ConditionFlag.NotZero, loop);
+
+        masm.testl(result, result);
+        masm.jccb(ConditionFlag.Zero, trueLabel);
+
+        /*
+         * Compare the remaining bytes with an unaligned memory load aligned to the end of the
+         * array.
+         */
+        masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE));
+        masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE));
+        masm.jccb(ConditionFlag.NotEqual, falseLabel);
+        masm.jmpb(trueLabel);
+
+        masm.bind(compareTail);
+        masm.movl(length, result);
+    }
+
+    /**
+     * Emits code to compare the remaining 1 to 4 bytes.
+     */
+    private void emitTailCompares(AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        Label compare2Bytes = new Label();
+        Label compare1Byte = new Label();
+
+        Register temp = asRegister(temp4);
+
+        if (kind.getByteCount() <= 4) {
+            // Compare trailing 4 bytes, if any.
+            masm.testl(result, 4);
+            masm.jccb(ConditionFlag.Zero, compare2Bytes);
+            masm.movl(temp, new AMD64Address(array1, 0));
+            masm.cmpl(temp, new AMD64Address(array2, 0));
+            masm.jccb(ConditionFlag.NotEqual, falseLabel);
+
+            if (kind.getByteCount() <= 2) {
+                // Move array pointers forward.
+                masm.leaq(array1, new AMD64Address(array1, 4));
+                masm.leaq(array2, new AMD64Address(array2, 4));
+
+                // Compare trailing 2 bytes, if any.
+                masm.bind(compare2Bytes);
+                masm.testl(result, 2);
+                masm.jccb(ConditionFlag.Zero, compare1Byte);
+                masm.movzwl(temp, new AMD64Address(array1, 0));
+                masm.movzwl(length, new AMD64Address(array2, 0));
+                masm.cmpl(temp, length);
+                masm.jccb(ConditionFlag.NotEqual, falseLabel);
+
+                // The one-byte tail compare is only required for boolean and byte arrays.
+                if (kind.getByteCount() <= 1) {
+                    // Move array pointers forward before we compare the last trailing byte.
+                    masm.leaq(array1, new AMD64Address(array1, 2));
+                    masm.leaq(array2, new AMD64Address(array2, 2));
+
+                    // Compare trailing byte, if any.
+                    masm.bind(compare1Byte);
+                    masm.testl(result, 1);
+                    masm.jccb(ConditionFlag.Zero, trueLabel);
+                    masm.movzbl(temp, new AMD64Address(array1, 0));
+                    masm.movzbl(length, new AMD64Address(array2, 0));
+                    masm.cmpl(temp, length);
+                    masm.jccb(ConditionFlag.NotEqual, falseLabel);
+                } else {
+                    masm.bind(compare1Byte);
+                }
+            } else {
+                masm.bind(compare2Bytes);
+            }
+        }
+    }
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java
new file mode 100644
index 0000000..cff91a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters;
+import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * AMD64 LIR instructions that have two inputs and one output.
+ */
+public class AMD64Binary {
+
+    /**
+     * Instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class TwoOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<TwoOp> TYPE = LIRInstructionClass.create(TwoOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        /**
+         * This argument must be Alive to ensure that result and y are not assigned to the same
+         * register, which would break the code generation by destroying y too early.
+         */
+        @Alive({REG, STACK}) protected AllocatableValue y;
+
+        public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Instruction that has three {@link AllocatableValue} operands.
+     */
+    public static class ThreeOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<ThreeOp> TYPE = LIRInstructionClass.create(ThreeOp.class);
+
+        @Opcode private final AMD64RRMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public ThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Commutative instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class CommutativeTwoOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CommutativeTwoOp> TYPE = LIRInstructionClass.create(CommutativeTwoOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AllocatableValue input;
+            if (sameRegister(result, y)) {
+                input = x;
+            } else {
+                AMD64Move.move(crb, masm, result, x);
+                input = y;
+            }
+
+            if (isRegister(input)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(input));
+            } else {
+                assert isStackSlot(input);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
+            }
+        }
+    }
+
+    /**
+     * Commutative instruction that has three {@link AllocatableValue} operands.
+     */
+    public static class CommutativeThreeOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CommutativeThreeOp> TYPE = LIRInstructionClass.create(CommutativeThreeOp.class);
+
+        @Opcode private final AMD64RRMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public CommutativeThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
+     */
+    public static class ConstOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        private final int y;
+
+        public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y);
+        }
+
+        public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            opcode.emit(masm, size, asRegister(result), y);
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one
+     * {@link DataSectionReference} operand.
+     */
+    public static class DataTwoOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DataTwoOp> TYPE = LIRInstructionClass.create(DataTwoOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        private final JavaConstant y;
+
+        private final int alignment;
+
+        public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+            this(opcode, size, result, x, y, y.getJavaKind().getByteCount());
+        }
+
+        public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.alignment = alignment;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+        }
+    }
+
+    /**
+     * Instruction that has two {@link AllocatableValue} operands and one
+     * {@link DataSectionReference} operand.
+     */
+    public static class DataThreeOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DataThreeOp> TYPE = LIRInstructionClass.create(DataThreeOp.class);
+
+        @Opcode private final AMD64RRMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        private final JavaConstant y;
+
+        private final int alignment;
+
+        public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+            this(opcode, size, result, x, y, y.getJavaKind().getByteCount());
+        }
+
+        public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.alignment = alignment;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue
+     * memory} operand.
+     */
+    public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryTwoOp> TYPE = LIRInstructionClass.create(MemoryTwoOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        @Alive({COMPOSITE}) protected AMD64AddressValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(result), y.toAddress());
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, y) || sameRegister(x, y);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue
+     * memory} operand.
+     */
+    public static class MemoryThreeOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryThreeOp> TYPE = LIRInstructionClass.create(MemoryThreeOp.class);
+
+        @Opcode private final AMD64RRMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        @Use({COMPOSITE}) protected AMD64AddressValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(result), asRegister(x), y.toAddress());
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, y) || sameRegister(x, y);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit
+     * immediate input.
+     */
+    public static class RMIOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class);
+
+        @Opcode private final AMD64RMIOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final int y;
+
+        public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(x)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(x), y);
+            } else {
+                assert isStackSlot(x);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java
new file mode 100644
index 0000000..8669c52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.VMConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * AMD64 LIR instructions that have two input operands, but no output operand.
+ */
+public class AMD64BinaryConsumer {
+
+    /**
+     * Instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class Op extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<Op> TYPE = LIRInstructionClass.create(Op.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
+     */
+    public static class ConstOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final int y;
+
+        public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y);
+        }
+
+        public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
+            this(TYPE, opcode, size, x, y);
+        }
+
+        protected ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
+            super(c);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(x)) {
+                opcode.emit(masm, size, asRegister(x), y);
+            } else {
+                assert isStackSlot(x);
+                opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y);
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand
+     * that needs to be patched at runtime.
+     */
+    public static class VMConstOp extends ConstOp {
+        public static final LIRInstructionClass<VMConstOp> TYPE = LIRInstructionClass.create(VMConstOp.class);
+
+        protected final VMConstant c;
+
+        public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) {
+            super(TYPE, opcode, DWORD, x, 0xDEADDEAD);
+            this.c = c;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            crb.recordInlineDataInCode(c);
+            super.emitCode(crb, masm);
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one
+     * {@link DataSectionReference} operand.
+     */
+    public static class DataOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        private final Constant y;
+
+        private final int alignment;
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) {
+            this(opcode, size, x, y, size.getBytes());
+        }
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.alignment = alignment;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+        }
+    }
+
+    /**
+     * Instruction that has an {@link AllocatableValue} as first input and a
+     * {@link AMD64AddressValue memory} operand as second input.
+     */
+    public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({COMPOSITE}) protected AMD64AddressValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(x), y.toAddress());
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an
+     * {@link AllocatableValue} as second input.
+     */
+    public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class);
+
+        @Opcode private final AMD64MROp opcode;
+        private final OperandSize size;
+
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({REG}) protected AllocatableValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, x.toAddress(), asRegister(y));
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
+     * operand.
+     */
+    public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        private final int y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state);
+        }
+
+        public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            this(TYPE, opcode, size, x, y, state);
+        }
+
+        protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            super(c);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, x.toAddress(), y);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+
+        public AMD64MIOp getOpcode() {
+            return opcode;
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
+     * operand that needs to be patched at runtime.
+     */
+    public static class MemoryVMConstOp extends MemoryConstOp {
+        public static final LIRInstructionClass<MemoryVMConstOp> TYPE = LIRInstructionClass.create(MemoryVMConstOp.class);
+
+        protected final VMConstant c;
+
+        public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) {
+            super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state);
+            this.c = c;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            crb.recordInlineDataInCode(c);
+            super.emitCode(crb, masm);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BlockEndOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BlockEndOp.java
new file mode 100644
index 0000000..4f09ee0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BlockEndOp.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public abstract class AMD64BlockEndOp extends AbstractBlockEndOp {
+
+    public static final LIRInstructionClass<AMD64BlockEndOp> TYPE = LIRInstructionClass.create(AMD64BlockEndOp.class);
+
+    protected AMD64BlockEndOp(LIRInstructionClass<? extends AMD64BlockEndOp> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AMD64MacroAssembler) crb.asm);
+    }
+
+    public abstract void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BreakpointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BreakpointOp.java
new file mode 100644
index 0000000..4f7a25e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BreakpointOp.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Emits a breakpoint.
+ */
+@Opcode("BREAKPOINT")
+public final class AMD64BreakpointOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BreakpointOp> TYPE = LIRInstructionClass.create(AMD64BreakpointOp.class);
+
+    /**
+     * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger).
+     */
+    @Use({REG, STACK}) protected Value[] parameters;
+
+    public AMD64BreakpointOp(Value[] parameters) {
+        super(TYPE);
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        asm.int3();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ByteSwapOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ByteSwapOp.java
new file mode 100644
index 0000000..80c55b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ByteSwapOp.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.Value;
+
+@Opcode("BSWAP")
+public final class AMD64ByteSwapOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ByteSwapOp> TYPE = LIRInstructionClass.create(AMD64ByteSwapOp.class);
+
+    @Def({OperandFlag.REG, OperandFlag.HINT}) protected Value result;
+    @Use protected Value input;
+
+    public AMD64ByteSwapOp(Value result, Value input) {
+        super(TYPE);
+        this.result = result;
+        this.input = input;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, input);
+        switch ((AMD64Kind) input.getPlatformKind()) {
+            case DWORD:
+                masm.bswapl(ValueUtil.asRegister(result));
+                break;
+            case QWORD:
+                masm.bswapq(ValueUtil.asRegister(result));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64CCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64CCall.java
new file mode 100644
index 0000000..eae37b9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64CCall.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.Value;
+
+public final class AMD64CCall extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64CCall> TYPE = LIRInstructionClass.create(AMD64CCall.class);
+
+    @Def({REG, ILLEGAL}) protected Value result;
+    @Use({REG, STACK}) protected Value[] parameters;
+    @Use({REG}) protected Value functionPtr;
+    @Use({REG}) protected Value numberOfFloatingPointArguments;
+
+    public AMD64CCall(Value result, Value functionPtr, Value numberOfFloatingPointArguments, Value[] parameters) {
+        super(TYPE);
+        this.result = result;
+        this.functionPtr = functionPtr;
+        this.parameters = parameters;
+        this.numberOfFloatingPointArguments = numberOfFloatingPointArguments;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        directCall(masm);
+    }
+
+    private void directCall(AMD64MacroAssembler masm) {
+        Register reg = ValueUtil.asRegister(functionPtr);
+        masm.call(reg);
+        masm.ensureUniquePC();
+    }
+
+    @Override
+    public boolean destroysCallerSavedRegisters() {
+        return true;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java
new file mode 100644
index 0000000..8b1cfeb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapRegistersAfterInstruction;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64Call {
+
+    public abstract static class CallOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
+
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @Temp({REG, STACK}) protected Value[] temps;
+        @State protected LIRFrameState state;
+
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c);
+            this.result = result;
+            this.parameters = parameters;
+            this.state = state;
+            this.temps = addStackSlotsToTemporaries(parameters, temps);
+            assert temps != null;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return true;
+        }
+    }
+
+    public abstract static class MethodCallOp extends CallOp {
+        public static final LIRInstructionClass<MethodCallOp> TYPE = LIRInstructionClass.create(MethodCallOp.class);
+
+        protected final ResolvedJavaMethod callTarget;
+
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+
+    }
+
+    @Opcode("CALL_DIRECT")
+    public static class DirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
+
+        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, state);
+        }
+
+        protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, true, state);
+        }
+    }
+
+    @Opcode("CALL_INDIRECT")
+    public static class IndirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
+
+        @Use({REG}) protected Value targetAddress;
+
+        public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        }
+
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
+                        LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
+            this.targetAddress = targetAddress;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now";
+        }
+    }
+
+    public abstract static class ForeignCallOp extends CallOp implements ZapRegistersAfterInstruction {
+        public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
+
+        protected final ForeignCallLinkage callTarget;
+
+        public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
+        }
+    }
+
+    @Opcode("NEAR_FOREIGN_CALL")
+    public static final class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
+
+        public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, linkage, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, false, state);
+        }
+    }
+
+    @Opcode("FAR_FOREIGN_CALL")
+    public static final class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
+
+        @Temp({REG}) protected AllocatableValue callTemp;
+
+        public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, callTarget, result, parameters, temps, state);
+            /*
+             * The register allocator does not support virtual registers that are used at the call
+             * site, so use a fixed register.
+             */
+            callTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.QWORD));
+            assert differentRegisters(parameters, callTemp);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state);
+        }
+    }
+
+    public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) {
+        if (align) {
+            emitAlignmentForDirectCall(crb, masm);
+        }
+        int before = masm.position();
+        if (scratch != null) {
+            // offset might not fit a 32-bit immediate, generate an
+            // indirect call with a 64-bit immediate
+            masm.movq(scratch, 0L);
+            masm.call(scratch);
+        } else {
+            masm.call();
+        }
+        int after = masm.position();
+        crb.recordDirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // make sure that the displacement word of the call ends up word aligned
+        int offset = masm.position();
+        offset += crb.target.arch.getMachineCodeCallDisplacementOffset();
+        int modulus = crb.target.wordSize;
+        if (offset % modulus != 0) {
+            masm.nop(modulus - offset % modulus);
+        }
+    }
+
+    public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) {
+        int before = masm.position();
+        masm.jmp(0, true);
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) {
+        int before = masm.position();
+        masm.jcc(cond, 0, true);
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
+        int before = masm.position();
+        masm.call(dst);
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ClearRegisterOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ClearRegisterOp.java
new file mode 100644
index 0000000..70770f2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ClearRegisterOp.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+public class AMD64ClearRegisterOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ClearRegisterOp> TYPE = LIRInstructionClass.create(AMD64ClearRegisterOp.class);
+
+    @Opcode private final AMD64RMOp op;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+
+    public AMD64ClearRegisterOp(OperandSize size, AllocatableValue result) {
+        super(TYPE);
+        this.op = XOR.getRMOpcode(size);
+        this.size = size;
+        this.result = result;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        op.emit(masm, size, asRegister(result), asRegister(result));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java
new file mode 100644
index 0000000..dbddbcb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.code.CompilationResult.JumpTable;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64ControlFlow {
+
+    public static final class ReturnOp extends AMD64BlockEndOp implements BlockEndOp {
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
+        @Use({REG, ILLEGAL}) protected Value x;
+
+        public ReturnOp(Value x) {
+            super(TYPE);
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            crb.frameContext.leave(crb);
+            /*
+             * We potentially return to the interpreter, and that's an AVX-SSE transition. The only
+             * live value at this point should be the return value in either rax, or in xmm0 with
+             * the upper half of the register unused, so we don't destroy any value here.
+             */
+            if (masm.supports(CPUFeature.AVX)) {
+                masm.vzeroupper();
+            }
+            masm.ret(0);
+        }
+    }
+
+    public static class BranchOp extends AMD64BlockEndOp implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
+        protected final ConditionFlag condition;
+        protected final LabelRef trueDestination;
+        protected final LabelRef falseDestination;
+
+        private final double trueDestinationProbability;
+
+        public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            this(intCond(condition), trueDestination, falseDestination, trueDestinationProbability);
+        }
+
+        public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            this(TYPE, condition, trueDestination, falseDestination, trueDestinationProbability);
+        }
+
+        protected BranchOp(LIRInstructionClass<? extends BranchOp> c, ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            super(c);
+            this.condition = condition;
+            this.trueDestination = trueDestination;
+            this.falseDestination = falseDestination;
+            this.trueDestinationProbability = trueDestinationProbability;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            /*
+             * The strategy for emitting jumps is: If either trueDestination or falseDestination is
+             * the successor block, assume the block scheduler did the correct thing and jcc to the
+             * other. Otherwise, we need a jcc followed by a jmp. Use the branch probability to make
+             * sure it is more likely to branch on the jcc (= less likely to execute both the jcc
+             * and the jmp instead of just the jcc). In the case of loops, that means the jcc is the
+             * back-edge.
+             */
+            if (crb.isSuccessorEdge(trueDestination)) {
+                jcc(masm, true, falseDestination);
+            } else if (crb.isSuccessorEdge(falseDestination)) {
+                jcc(masm, false, trueDestination);
+            } else if (trueDestinationProbability < 0.5) {
+                jcc(masm, true, falseDestination);
+                masm.jmp(trueDestination.label());
+            } else {
+                jcc(masm, false, trueDestination);
+                masm.jmp(falseDestination.label());
+            }
+        }
+
+        protected void jcc(AMD64MacroAssembler masm, boolean negate, LabelRef target) {
+            masm.jcc(negate ? condition.negate() : condition, target.label());
+        }
+    }
+
+    public static final class FloatBranchOp extends BranchOp {
+        public static final LIRInstructionClass<FloatBranchOp> TYPE = LIRInstructionClass.create(FloatBranchOp.class);
+        protected boolean unorderedIsTrue;
+
+        public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            super(TYPE, floatCond(condition), trueDestination, falseDestination, trueDestinationProbability);
+            this.unorderedIsTrue = unorderedIsTrue;
+        }
+
+        @Override
+        protected void jcc(AMD64MacroAssembler masm, boolean negate, LabelRef target) {
+            floatJcc(masm, negate ? condition.negate() : condition, negate ? !unorderedIsTrue : unorderedIsTrue, target.label());
+        }
+    }
+
+    public static class StrategySwitchOp extends AMD64BlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
+        protected final Constant[] keyConstants;
+        private final LabelRef[] keyTargets;
+        private LabelRef defaultTarget;
+        @Alive({REG}) protected Value key;
+        @Temp({REG, ILLEGAL}) protected Value scratch;
+        protected final SwitchStrategy strategy;
+
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            this(TYPE, strategy, keyTargets, defaultTarget, key, scratch);
+        }
+
+        protected StrategySwitchOp(LIRInstructionClass<? extends StrategySwitchOp> c, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            super(c);
+            this.strategy = strategy;
+            this.keyConstants = strategy.getKeyConstants();
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+            this.key = key;
+            this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+        }
+
+        @Override
+        public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) {
+            strategy.run(new SwitchClosure(asRegister(key), crb, masm));
+        }
+
+        public class SwitchClosure extends BaseSwitchClosure {
+
+            protected final Register keyRegister;
+            protected final CompilationResultBuilder crb;
+            protected final AMD64MacroAssembler masm;
+
+            protected SwitchClosure(Register keyRegister, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+                super(crb, masm, keyTargets, defaultTarget);
+                this.keyRegister = keyRegister;
+                this.crb = crb;
+                this.masm = masm;
+            }
+
+            protected void emitComparison(Constant c) {
+                JavaConstant jc = (JavaConstant) c;
+                switch (jc.getJavaKind()) {
+                    case Int:
+                        long lc = jc.asLong();
+                        assert NumUtil.isInt(lc);
+                        masm.cmpl(keyRegister, (int) lc);
+                        break;
+                    case Long:
+                        masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(jc));
+                        break;
+                    case Object:
+                        AMD64Move.const2reg(crb, masm, asRegister(scratch), jc);
+                        masm.cmpptr(keyRegister, asRegister(scratch));
+                        break;
+                    default:
+                        throw new GraalError("switch only supported for int, long and object");
+                }
+            }
+
+            @Override
+            protected void conditionalJump(int index, Condition condition, Label target) {
+                emitComparison(keyConstants[index]);
+                masm.jcc(intCond(condition), target);
+            }
+        }
+    }
+
+    public static final class TableSwitchOp extends AMD64BlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
+        private final int lowKey;
+        private final LabelRef defaultTarget;
+        private final LabelRef[] targets;
+        @Use protected Value index;
+        @Temp({REG, HINT}) protected Value idxScratch;
+        @Temp protected Value scratch;
+
+        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Value index, Variable scratch, Variable idxScratch) {
+            super(TYPE);
+            this.lowKey = lowKey;
+            this.defaultTarget = defaultTarget;
+            this.targets = targets;
+            this.index = index;
+            this.scratch = scratch;
+            this.idxScratch = idxScratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            Register indexReg = asRegister(index, AMD64Kind.DWORD);
+            Register idxScratchReg = asRegister(idxScratch, AMD64Kind.DWORD);
+            Register scratchReg = asRegister(scratch, AMD64Kind.QWORD);
+
+            if (!indexReg.equals(idxScratchReg)) {
+                masm.movl(idxScratchReg, indexReg);
+            }
+
+            // Compare index against jump table bounds
+            int highKey = lowKey + targets.length - 1;
+            if (lowKey != 0) {
+                // subtract the low value from the switch value
+                masm.subl(idxScratchReg, lowKey);
+                masm.cmpl(idxScratchReg, highKey - lowKey);
+            } else {
+                masm.cmpl(idxScratchReg, highKey);
+            }
+
+            // Jump to default target if index is not within the jump table
+            if (defaultTarget != null) {
+                masm.jcc(ConditionFlag.Above, defaultTarget.label());
+            }
+
+            // Set scratch to address of jump table
+            masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0));
+            final int afterLea = masm.position();
+
+            // Load jump table entry into scratch and jump to it
+            masm.movslq(idxScratchReg, new AMD64Address(scratchReg, idxScratchReg, Scale.Times4, 0));
+            masm.addq(scratchReg, idxScratchReg);
+            masm.jmp(scratchReg);
+
+            // Inserting padding so that jump table address is 4-byte aligned
+            if ((masm.position() & 0x3) != 0) {
+                masm.nop(4 - (masm.position() & 0x3));
+            }
+
+            // Patch LEA instruction above now that we know the position of the jump table
+            // TODO this is ugly and should be done differently
+            final int jumpTablePos = masm.position();
+            final int leaDisplacementPosition = afterLea - 4;
+            masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
+
+            // Emit jump table entries
+            for (LabelRef target : targets) {
+                Label label = target.label();
+                int offsetToJumpTableBase = masm.position() - jumpTablePos;
+                if (label.isBound()) {
+                    int imm32 = label.position() - jumpTablePos;
+                    masm.emitInt(imm32);
+                } else {
+                    label.addPatchAt(masm.position());
+
+                    masm.emitByte(0); // pseudo-opcode for jump table entry
+                    masm.emitShort(offsetToJumpTableBase);
+                    masm.emitByte(0); // padding to make jump table entry 4 bytes wide
+                }
+            }
+
+            JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4);
+            crb.compilationResult.addAnnotation(jt);
+        }
+    }
+
+    @Opcode("CMOVE")
+    public static final class CondMoveOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
+        @Def({REG, HINT}) protected Value result;
+        @Alive({REG}) protected Value trueValue;
+        @Use({REG, STACK, CONST}) protected Value falseValue;
+        private final ConditionFlag condition;
+
+        public CondMoveOp(Variable result, Condition condition, AllocatableValue trueValue, Value falseValue) {
+            super(TYPE);
+            this.result = result;
+            this.condition = intCond(condition);
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            cmove(crb, masm, result, false, condition, false, trueValue, falseValue);
+        }
+    }
+
+    @Opcode("CMOVE")
+    public static final class FloatCondMoveOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<FloatCondMoveOp> TYPE = LIRInstructionClass.create(FloatCondMoveOp.class);
+        @Def({REG}) protected Value result;
+        @Alive({REG}) protected Value trueValue;
+        @Alive({REG}) protected Value falseValue;
+        private final ConditionFlag condition;
+        private final boolean unorderedIsTrue;
+
+        public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+            super(TYPE);
+            this.result = result;
+            this.condition = floatCond(condition);
+            this.unorderedIsTrue = unorderedIsTrue;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            cmove(crb, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue);
+        }
+    }
+
+    private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) {
+        Label endLabel = new Label();
+        if (unorderedIsTrue && !trueOnUnordered(condition)) {
+            masm.jcc(ConditionFlag.Parity, label);
+        } else if (!unorderedIsTrue && trueOnUnordered(condition)) {
+            masm.jccb(ConditionFlag.Parity, endLabel);
+        }
+        masm.jcc(condition, label);
+        masm.bind(endLabel);
+    }
+
+    private static void cmove(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, Value trueValue,
+                    Value falseValue) {
+        // check that we don't overwrite an input operand before it is used.
+        assert !result.equals(trueValue);
+
+        AMD64Move.move(crb, masm, result, falseValue);
+        cmove(crb, masm, result, condition, trueValue);
+
+        if (isFloat) {
+            if (unorderedIsTrue && !trueOnUnordered(condition)) {
+                cmove(crb, masm, result, ConditionFlag.Parity, trueValue);
+            } else if (!unorderedIsTrue && trueOnUnordered(condition)) {
+                cmove(crb, masm, result, ConditionFlag.Parity, falseValue);
+            }
+        }
+    }
+
+    private static void cmove(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, ConditionFlag cond, Value other) {
+        if (isRegister(other)) {
+            assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move";
+            switch ((AMD64Kind) other.getPlatformKind()) {
+                case BYTE:
+                case WORD:
+                case DWORD:
+                    masm.cmovl(cond, asRegister(result), asRegister(other));
+                    break;
+                case QWORD:
+                    masm.cmovq(cond, asRegister(result), asRegister(other));
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        } else {
+            AMD64Address addr = (AMD64Address) crb.asAddress(other);
+            switch ((AMD64Kind) other.getPlatformKind()) {
+                case BYTE:
+                case WORD:
+                case DWORD:
+                    masm.cmovl(cond, asRegister(result), addr);
+                    break;
+                case QWORD:
+                    masm.cmovq(cond, asRegister(result), addr);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    private static ConditionFlag intCond(Condition cond) {
+        switch (cond) {
+            case EQ:
+                return ConditionFlag.Equal;
+            case NE:
+                return ConditionFlag.NotEqual;
+            case LT:
+                return ConditionFlag.Less;
+            case LE:
+                return ConditionFlag.LessEqual;
+            case GE:
+                return ConditionFlag.GreaterEqual;
+            case GT:
+                return ConditionFlag.Greater;
+            case BE:
+                return ConditionFlag.BelowEqual;
+            case AE:
+                return ConditionFlag.AboveEqual;
+            case AT:
+                return ConditionFlag.Above;
+            case BT:
+                return ConditionFlag.Below;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static ConditionFlag floatCond(Condition cond) {
+        switch (cond) {
+            case EQ:
+                return ConditionFlag.Equal;
+            case NE:
+                return ConditionFlag.NotEqual;
+            case LT:
+                return ConditionFlag.Below;
+            case LE:
+                return ConditionFlag.BelowEqual;
+            case GE:
+                return ConditionFlag.AboveEqual;
+            case GT:
+                return ConditionFlag.Above;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static boolean trueOnUnordered(ConditionFlag condition) {
+        switch (condition) {
+            case AboveEqual:
+            case NotEqual:
+            case Above:
+            case Less:
+            case Overflow:
+                return false;
+            case Equal:
+            case BelowEqual:
+            case Below:
+            case GreaterEqual:
+            case NoOverflow:
+                return true;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java
new file mode 100644
index 0000000..67bcfe6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+/**
+ * AMD64 specific frame map.
+ *
+ * This is the format of an AMD64 stack frame:
+ *
+ * <pre>
+ *   Base       Contents
+ *
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *   ---------+--------------------------------+---------------------
+ *            | return address                 |    |            ^
+ *   current  +--------------------------------+    |            |    -----
+ *   frame    |                                |    |            |      ^
+ *            : callee save area               :    |            |      |
+ *            |                                |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            | spill slot 0                   |    | negative   |      |
+ *            :     ...                        :    v offsets    |      |
+ *            | spill slot n                   |  -----        total  frame
+ *            +--------------------------------+               frame  size
+ *            | alignment padding              |               size     |
+ *            +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |      |
+ *            :     ...                        :    | positive   |      |
+ *            | outgoing overflow argument 0   |    | offsets    v      v
+ *    %sp--&gt;  +--------------------------------+---------------------------
+ *
+ * </pre>
+ *
+ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such
+ * a block may be greater than the size of a normal spill slot or the word size.
+ * <p>
+ * A runtime can reserve space at the beginning of the overflow argument area. The calling
+ * convention can specify that the first overflow stack argument is not at offset 0, but at a
+ * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that
+ * call-free methods also have this space reserved. Then the VM can use the memory at offset 0
+ * relative to the stack pointer.
+ */
+public class AMD64FrameMap extends FrameMap {
+
+    private StackSlot rbpSpillSlot;
+
+    public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
+        // (negative) offset relative to sp + total frame size
+        initialSpillSize = returnAddressSize();
+        spillSize = initialSpillSize;
+    }
+
+    @Override
+    public int totalFrameSize() {
+        return frameSize() + returnAddressSize();
+    }
+
+    @Override
+    public int currentFrameSize() {
+        return alignFrameSize(outgoingSize + spillSize - returnAddressSize());
+    }
+
+    @Override
+    protected int alignFrameSize(int size) {
+        return NumUtil.roundUp(size + returnAddressSize(), getTarget().stackAlignment) - returnAddressSize();
+    }
+
+    @Override
+    public int offsetForStackSlot(StackSlot slot) {
+        // @formatter:off
+        assert (!slot.getRawAddFrameSize() && slot.getRawOffset() <  outgoingSize) ||
+               (slot.getRawAddFrameSize() && slot.getRawOffset()  <  0 && -slot.getRawOffset() <= spillSize) ||
+               (slot.getRawAddFrameSize() && slot.getRawOffset()  >= 0) :
+                   String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize);
+        // @formatter:on
+        return super.offsetForStackSlot(slot);
+    }
+
+    /**
+     * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot
+     * runtime for walking/inspecting frames of such methods.
+     */
+    StackSlot allocateRBPSpillSlot() {
+        assert spillSize == initialSpillSize : "RBP spill slot must be the first allocated stack slots";
+        rbpSpillSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+        assert asStackSlot(rbpSpillSlot).getRawOffset() == -16 : asStackSlot(rbpSpillSlot).getRawOffset();
+        return rbpSpillSlot;
+    }
+
+    void freeRBPSpillSlot() {
+        int size = spillSlotSize(LIRKind.value(AMD64Kind.QWORD));
+        assert spillSize == NumUtil.roundUp(initialSpillSize + size, size) : "RBP spill slot can not be freed after allocation other stack slots";
+        spillSize = initialSpillSize;
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        assert spillSize == initialSpillSize || spillSize == initialSpillSize +
+                        spillSlotSize(LIRKind.value(AMD64Kind.QWORD)) : "Deoptimization rescue slot must be the first or second (if there is an RBP spill slot) stack slot";
+        return allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java
new file mode 100644
index 0000000..d14e4d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+public class AMD64FrameMapBuilder extends FrameMapBuilderImpl {
+
+    public AMD64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+        super(frameMap, codeCache, registerConfig);
+    }
+
+    /**
+     * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot
+     * runtime for walking/inspecting frames of such methods.
+     */
+    public StackSlot allocateRBPSpillSlot() {
+        return ((AMD64FrameMap) getFrameMap()).allocateRBPSpillSlot();
+    }
+
+    public void freeRBPSpillSlot() {
+        ((AMD64FrameMap) getFrameMap()).freeRBPSpillSlot();
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        return ((AMD64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LIRInstruction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LIRInstruction.java
new file mode 100644
index 0000000..20429d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LIRInstruction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method.
+ */
+public abstract class AMD64LIRInstruction extends LIRInstruction {
+    public static final LIRInstructionClass<AMD64LIRInstruction> TYPE = LIRInstructionClass.create(AMD64LIRInstruction.class);
+
+    protected AMD64LIRInstruction(LIRInstructionClass<? extends AMD64LIRInstruction> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AMD64MacroAssembler) crb.asm);
+    }
+
+    public abstract void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicBinaryOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicBinaryOp.java
new file mode 100644
index 0000000..af2b3f0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicBinaryOp.java
@@ -0,0 +1,2064 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public final class AMD64MathIntrinsicBinaryOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MathIntrinsicBinaryOp> TYPE = LIRInstructionClass.create(AMD64MathIntrinsicBinaryOp.class);
+
+    public enum BinaryIntrinsicOpcode {
+        POW
+    }
+
+    @Opcode private final BinaryIntrinsicOpcode opcode;
+    @Def protected Value result;
+    @Use protected Value input;
+    @Use protected Value secondInput;
+    @Temp({REG, ILLEGAL}) protected Value xmm1Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm2Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm3Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm4Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm5Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm6Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm7Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm8Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm9Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm10Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr1Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr2Temp = Value.ILLEGAL;
+    @Temp protected AllocatableValue rcxTemp;
+    @Temp({REG, ILLEGAL}) protected Value gpr4Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr5Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr6Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr7Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr8Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr9Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr10Temp = Value.ILLEGAL;
+
+    CompilationResultBuilder internalCrb;
+
+    public AMD64MathIntrinsicBinaryOp(LIRGeneratorTool tool, BinaryIntrinsicOpcode opcode, Value result, Value input, Value alternateInput) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+        this.secondInput = alternateInput;
+        if (opcode == BinaryIntrinsicOpcode.POW) {
+            this.gpr1Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr2Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.rcxTemp = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr4Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+
+            this.xmm1Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm2Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm3Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm4Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm5Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm6Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm7Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm10Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+        }
+    }
+
+    private void setCrb(CompilationResultBuilder crb) {
+        internalCrb = crb;
+    }
+
+    private AMD64Address externalAddress(ArrayDataPointerConstant curPtr) {
+        return (AMD64Address) internalCrb.recordDataReferenceInCode(curPtr);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        switch (opcode) {
+            case POW:
+                powIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), asRegister(secondInput, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - POW() ---------------------
+     *
+     * Let x=2^k * mx, mx in [1,2)
+     *
+     * log2(x) calculation:
+     *
+     * Get B~1/mx based on the output of rcpps instruction (B0) B = int((B0*LH*2^9+0.5))/2^9 LH is a
+     * short approximation for log2(e)
+     *
+     * Reduced argument, scaled by LH: r=B*mx-LH (computed accurately in high and low parts)
+     *
+     * log2(x) result: k - log2(B) + p(r) p(r) is a degree 8 polynomial -log2(B) read from data
+     * table (high, low parts) log2(x) is formed from high and low parts For |x| in [1-1/32,
+     * 1+1/16), a slower but more accurate computation based om the same table design is performed.
+     *
+     * Main path is taken if | floor(log2(|log2(|x|)|) + floor(log2|y|) | < 8, to filter out all
+     * potential OF/UF cases. exp2(y*log2(x)) is computed using an 8-bit index table and a degree 5
+     * polynomial
+     *
+     * Special cases: pow(-0,y) = -INF and raises the divide-by-zero exception for y an odd integer
+     * < 0. pow(-0,y) = +INF and raises the divide-by-zero exception for y < 0 and not an odd
+     * integer. pow(-0,y) = -0 for y an odd integer > 0. pow(-0,y) = +0 for y > 0 and not an odd
+     * integer. pow(-1,-INF) = NaN. pow(+1,y) = NaN for any y, even a NaN. pow(x,-0) = 1 for any x,
+     * even a NaN. pow(x,y) = a NaN and raises the invalid exception for finite x < 0 and finite
+     * non-integer y. pow(x,-INF) = +INF for |x|<1. pow(x,-INF) = +0 for |x|>1. pow(x,+INF) = +0 for
+     * |x|<1. pow(x,+INF) = +INF for |x|>1. pow(-INF,y) = -0 for y an odd integer < 0. pow(-INF,y) =
+     * +0 for y < 0 and not an odd integer. pow(-INF,y) = -INF for y an odd integer > 0. pow(-INF,y)
+     * = +INF for y > 0 and not an odd integer. pow(+INF,y) = +0 for y <0. pow(+INF,y) = +INF for y
+     * >0.
+     *
+     */
+
+    private static int[] highSigMask = {
+                    0x00000000, 0xfffff800, 0x00000000, 0xfffff800
+    };
+
+    private static int[] logTwoE = {
+                    0x00000000, 0x3ff72000, 0x161bb241, 0xbf5dabe1
+    };
+
+    private static int[] highmaskY = {
+                    0x00000000, 0xfffffff8, 0x00000000, 0xffffffff
+    };
+
+    private static int[] tExp = {
+                    0x00000000, 0x3ff00000, 0x00000000, 0x3b700000, 0xfa5abcbf,
+                    0x3ff00b1a, 0xa7609f71, 0xbc84f6b2, 0xa9fb3335, 0x3ff0163d,
+                    0x9ab8cdb7, 0x3c9b6129, 0x143b0281, 0x3ff02168, 0x0fc54eb6,
+                    0xbc82bf31, 0x3e778061, 0x3ff02c9a, 0x535b085d, 0xbc719083,
+                    0x2e11bbcc, 0x3ff037d4, 0xeeade11a, 0x3c656811, 0xe86e7f85,
+                    0x3ff04315, 0x1977c96e, 0xbc90a31c, 0x72f654b1, 0x3ff04e5f,
+                    0x3aa0d08c, 0x3c84c379, 0xd3158574, 0x3ff059b0, 0xa475b465,
+                    0x3c8d73e2, 0x0e3c1f89, 0x3ff0650a, 0x5799c397, 0xbc95cb7b,
+                    0x29ddf6de, 0x3ff0706b, 0xe2b13c27, 0xbc8c91df, 0x2b72a836,
+                    0x3ff07bd4, 0x54458700, 0x3c832334, 0x18759bc8, 0x3ff08745,
+                    0x4bb284ff, 0x3c6186be, 0xf66607e0, 0x3ff092bd, 0x800a3fd1,
+                    0xbc968063, 0xcac6f383, 0x3ff09e3e, 0x18316136, 0x3c914878,
+                    0x9b1f3919, 0x3ff0a9c7, 0x873d1d38, 0x3c85d16c, 0x6cf9890f,
+                    0x3ff0b558, 0x4adc610b, 0x3c98a62e, 0x45e46c85, 0x3ff0c0f1,
+                    0x06d21cef, 0x3c94f989, 0x2b7247f7, 0x3ff0cc92, 0x16e24f71,
+                    0x3c901edc, 0x23395dec, 0x3ff0d83b, 0xe43f316a, 0xbc9bc14d,
+                    0x32d3d1a2, 0x3ff0e3ec, 0x27c57b52, 0x3c403a17, 0x5fdfa9c5,
+                    0x3ff0efa5, 0xbc54021b, 0xbc949db9, 0xaffed31b, 0x3ff0fb66,
+                    0xc44ebd7b, 0xbc6b9bed, 0x28d7233e, 0x3ff10730, 0x1692fdd5,
+                    0x3c8d46eb, 0xd0125b51, 0x3ff11301, 0x39449b3a, 0xbc96c510,
+                    0xab5e2ab6, 0x3ff11edb, 0xf703fb72, 0xbc9ca454, 0xc06c31cc,
+                    0x3ff12abd, 0xb36ca5c7, 0xbc51b514, 0x14f204ab, 0x3ff136a8,
+                    0xba48dcf0, 0xbc67108f, 0xaea92de0, 0x3ff1429a, 0x9af1369e,
+                    0xbc932fbf, 0x934f312e, 0x3ff14e95, 0x39bf44ab, 0xbc8b91e8,
+                    0xc8a58e51, 0x3ff15a98, 0xb9eeab0a, 0x3c82406a, 0x5471c3c2,
+                    0x3ff166a4, 0x82ea1a32, 0x3c58f23b, 0x3c7d517b, 0x3ff172b8,
+                    0xb9d78a76, 0xbc819041, 0x8695bbc0, 0x3ff17ed4, 0xe2ac5a64,
+                    0x3c709e3f, 0x388c8dea, 0x3ff18af9, 0xd1970f6c, 0xbc911023,
+                    0x58375d2f, 0x3ff19726, 0x85f17e08, 0x3c94aadd, 0xeb6fcb75,
+                    0x3ff1a35b, 0x7b4968e4, 0x3c8e5b4c, 0xf8138a1c, 0x3ff1af99,
+                    0xa4b69280, 0x3c97bf85, 0x84045cd4, 0x3ff1bbe0, 0x352ef607,
+                    0xbc995386, 0x95281c6b, 0x3ff1c82f, 0x8010f8c9, 0x3c900977,
+                    0x3168b9aa, 0x3ff1d487, 0x00a2643c, 0x3c9e016e, 0x5eb44027,
+                    0x3ff1e0e7, 0x088cb6de, 0xbc96fdd8, 0x22fcd91d, 0x3ff1ed50,
+                    0x027bb78c, 0xbc91df98, 0x8438ce4d, 0x3ff1f9c1, 0xa097af5c,
+                    0xbc9bf524, 0x88628cd6, 0x3ff2063b, 0x814a8495, 0x3c8dc775,
+                    0x3578a819, 0x3ff212be, 0x2cfcaac9, 0x3c93592d, 0x917ddc96,
+                    0x3ff21f49, 0x9494a5ee, 0x3c82a97e, 0xa27912d1, 0x3ff22bdd,
+                    0x5577d69f, 0x3c8d34fb, 0x6e756238, 0x3ff2387a, 0xb6c70573,
+                    0x3c99b07e, 0xfb82140a, 0x3ff2451f, 0x911ca996, 0x3c8acfcc,
+                    0x4fb2a63f, 0x3ff251ce, 0xbef4f4a4, 0x3c8ac155, 0x711ece75,
+                    0x3ff25e85, 0x4ac31b2c, 0x3c93e1a2, 0x65e27cdd, 0x3ff26b45,
+                    0x9940e9d9, 0x3c82bd33, 0x341ddf29, 0x3ff2780e, 0x05f9e76c,
+                    0x3c9e067c, 0xe1f56381, 0x3ff284df, 0x8c3f0d7e, 0xbc9a4c3a,
+                    0x7591bb70, 0x3ff291ba, 0x28401cbd, 0xbc82cc72, 0xf51fdee1,
+                    0x3ff29e9d, 0xafad1255, 0x3c8612e8, 0x66d10f13, 0x3ff2ab8a,
+                    0x191690a7, 0xbc995743, 0xd0dad990, 0x3ff2b87f, 0xd6381aa4,
+                    0xbc410adc, 0x39771b2f, 0x3ff2c57e, 0xa6eb5124, 0xbc950145,
+                    0xa6e4030b, 0x3ff2d285, 0x54db41d5, 0x3c900247, 0x1f641589,
+                    0x3ff2df96, 0xfbbce198, 0x3c9d16cf, 0xa93e2f56, 0x3ff2ecaf,
+                    0x45d52383, 0x3c71ca0f, 0x4abd886b, 0x3ff2f9d2, 0x532bda93,
+                    0xbc653c55, 0x0a31b715, 0x3ff306fe, 0xd23182e4, 0x3c86f46a,
+                    0xedeeb2fd, 0x3ff31432, 0xf3f3fcd1, 0x3c8959a3, 0xfc4cd831,
+                    0x3ff32170, 0x8e18047c, 0x3c8a9ce7, 0x3ba8ea32, 0x3ff32eb8,
+                    0x3cb4f318, 0xbc9c45e8, 0xb26416ff, 0x3ff33c08, 0x843659a6,
+                    0x3c932721, 0x66e3fa2d, 0x3ff34962, 0x930881a4, 0xbc835a75,
+                    0x5f929ff1, 0x3ff356c5, 0x5c4e4628, 0xbc8b5cee, 0xa2de883b,
+                    0x3ff36431, 0xa06cb85e, 0xbc8c3144, 0x373aa9cb, 0x3ff371a7,
+                    0xbf42eae2, 0xbc963aea, 0x231e754a, 0x3ff37f26, 0x9eceb23c,
+                    0xbc99f5ca, 0x6d05d866, 0x3ff38cae, 0x3c9904bd, 0xbc9e958d,
+                    0x1b7140ef, 0x3ff39a40, 0xfc8e2934, 0xbc99a9a5, 0x34e59ff7,
+                    0x3ff3a7db, 0xd661f5e3, 0xbc75e436, 0xbfec6cf4, 0x3ff3b57f,
+                    0xe26fff18, 0x3c954c66, 0xc313a8e5, 0x3ff3c32d, 0x375d29c3,
+                    0xbc9efff8, 0x44ede173, 0x3ff3d0e5, 0x8c284c71, 0x3c7fe8d0,
+                    0x4c123422, 0x3ff3dea6, 0x11f09ebc, 0x3c8ada09, 0xdf1c5175,
+                    0x3ff3ec70, 0x7b8c9bca, 0xbc8af663, 0x04ac801c, 0x3ff3fa45,
+                    0xf956f9f3, 0xbc97d023, 0xc367a024, 0x3ff40822, 0xb6f4d048,
+                    0x3c8bddf8, 0x21f72e2a, 0x3ff4160a, 0x1c309278, 0xbc5ef369,
+                    0x2709468a, 0x3ff423fb, 0xc0b314dd, 0xbc98462d, 0xd950a897,
+                    0x3ff431f5, 0xe35f7999, 0xbc81c7dd, 0x3f84b9d4, 0x3ff43ffa,
+                    0x9704c003, 0x3c8880be, 0x6061892d, 0x3ff44e08, 0x04ef80d0,
+                    0x3c489b7a, 0x42a7d232, 0x3ff45c20, 0x82fb1f8e, 0xbc686419,
+                    0xed1d0057, 0x3ff46a41, 0xd1648a76, 0x3c9c944b, 0x668b3237,
+                    0x3ff4786d, 0xed445733, 0xbc9c20f0, 0xb5c13cd0, 0x3ff486a2,
+                    0xb69062f0, 0x3c73c1a3, 0xe192aed2, 0x3ff494e1, 0x5e499ea0,
+                    0xbc83b289, 0xf0d7d3de, 0x3ff4a32a, 0xf3d1be56, 0x3c99cb62,
+                    0xea6db7d7, 0x3ff4b17d, 0x7f2897f0, 0xbc8125b8, 0xd5362a27,
+                    0x3ff4bfda, 0xafec42e2, 0x3c7d4397, 0xb817c114, 0x3ff4ce41,
+                    0x690abd5d, 0x3c905e29, 0x99fddd0d, 0x3ff4dcb2, 0xbc6a7833,
+                    0x3c98ecdb, 0x81d8abff, 0x3ff4eb2d, 0x2e5d7a52, 0xbc95257d,
+                    0x769d2ca7, 0x3ff4f9b2, 0xd25957e3, 0xbc94b309, 0x7f4531ee,
+                    0x3ff50841, 0x49b7465f, 0x3c7a249b, 0xa2cf6642, 0x3ff516da,
+                    0x69bd93ef, 0xbc8f7685, 0xe83f4eef, 0x3ff5257d, 0x43efef71,
+                    0xbc7c998d, 0x569d4f82, 0x3ff5342b, 0x1db13cad, 0xbc807abe,
+                    0xf4f6ad27, 0x3ff542e2, 0x192d5f7e, 0x3c87926d, 0xca5d920f,
+                    0x3ff551a4, 0xefede59b, 0xbc8d689c, 0xdde910d2, 0x3ff56070,
+                    0x168eebf0, 0xbc90fb6e, 0x36b527da, 0x3ff56f47, 0x011d93ad,
+                    0x3c99bb2c, 0xdbe2c4cf, 0x3ff57e27, 0x8a57b9c4, 0xbc90b98c,
+                    0xd497c7fd, 0x3ff58d12, 0x5b9a1de8, 0x3c8295e1, 0x27ff07cc,
+                    0x3ff59c08, 0xe467e60f, 0xbc97e2ce, 0xdd485429, 0x3ff5ab07,
+                    0x054647ad, 0x3c96324c, 0xfba87a03, 0x3ff5ba11, 0x4c233e1a,
+                    0xbc9b77a1, 0x8a5946b7, 0x3ff5c926, 0x816986a2, 0x3c3c4b1b,
+                    0x90998b93, 0x3ff5d845, 0xa8b45643, 0xbc9cd6a7, 0x15ad2148,
+                    0x3ff5e76f, 0x3080e65e, 0x3c9ba6f9, 0x20dceb71, 0x3ff5f6a3,
+                    0xe3cdcf92, 0xbc89eadd, 0xb976dc09, 0x3ff605e1, 0x9b56de47,
+                    0xbc93e242, 0xe6cdf6f4, 0x3ff6152a, 0x4ab84c27, 0x3c9e4b3e,
+                    0xb03a5585, 0x3ff6247e, 0x7e40b497, 0xbc9383c1, 0x1d1929fd,
+                    0x3ff633dd, 0xbeb964e5, 0x3c984710, 0x34ccc320, 0x3ff64346,
+                    0x759d8933, 0xbc8c483c, 0xfebc8fb7, 0x3ff652b9, 0xc9a73e09,
+                    0xbc9ae3d5, 0x82552225, 0x3ff66238, 0x87591c34, 0xbc9bb609,
+                    0xc70833f6, 0x3ff671c1, 0x586c6134, 0xbc8e8732, 0xd44ca973,
+                    0x3ff68155, 0x44f73e65, 0x3c6038ae, 0xb19e9538, 0x3ff690f4,
+                    0x9aeb445d, 0x3c8804bd, 0x667f3bcd, 0x3ff6a09e, 0x13b26456,
+                    0xbc9bdd34, 0xfa75173e, 0x3ff6b052, 0x2c9a9d0e, 0x3c7a38f5,
+                    0x750bdabf, 0x3ff6c012, 0x67ff0b0d, 0xbc728956, 0xddd47645,
+                    0x3ff6cfdc, 0xb6f17309, 0x3c9c7aa9, 0x3c651a2f, 0x3ff6dfb2,
+                    0x683c88ab, 0xbc6bbe3a, 0x98593ae5, 0x3ff6ef92, 0x9e1ac8b2,
+                    0xbc90b974, 0xf9519484, 0x3ff6ff7d, 0x25860ef6, 0xbc883c0f,
+                    0x66f42e87, 0x3ff70f74, 0xd45aa65f, 0x3c59d644, 0xe8ec5f74,
+                    0x3ff71f75, 0x86887a99, 0xbc816e47, 0x86ead08a, 0x3ff72f82,
+                    0x2cd62c72, 0xbc920aa0, 0x48a58174, 0x3ff73f9a, 0x6c65d53c,
+                    0xbc90a8d9, 0x35d7cbfd, 0x3ff74fbd, 0x618a6e1c, 0x3c9047fd,
+                    0x564267c9, 0x3ff75feb, 0x57316dd3, 0xbc902459, 0xb1ab6e09,
+                    0x3ff77024, 0x169147f8, 0x3c9b7877, 0x4fde5d3f, 0x3ff78069,
+                    0x0a02162d, 0x3c9866b8, 0x38ac1cf6, 0x3ff790b9, 0x62aadd3e,
+                    0x3c9349a8, 0x73eb0187, 0x3ff7a114, 0xee04992f, 0xbc841577,
+                    0x0976cfdb, 0x3ff7b17b, 0x8468dc88, 0xbc9bebb5, 0x0130c132,
+                    0x3ff7c1ed, 0xd1164dd6, 0x3c9f124c, 0x62ff86f0, 0x3ff7d26a,
+                    0xfb72b8b4, 0x3c91bddb, 0x36cf4e62, 0x3ff7e2f3, 0xba15797e,
+                    0x3c705d02, 0x8491c491, 0x3ff7f387, 0xcf9311ae, 0xbc807f11,
+                    0x543e1a12, 0x3ff80427, 0x626d972b, 0xbc927c86, 0xadd106d9,
+                    0x3ff814d2, 0x0d151d4d, 0x3c946437, 0x994cce13, 0x3ff82589,
+                    0xd41532d8, 0xbc9d4c1d, 0x1eb941f7, 0x3ff8364c, 0x31df2bd5,
+                    0x3c999b9a, 0x4623c7ad, 0x3ff8471a, 0xa341cdfb, 0xbc88d684,
+                    0x179f5b21, 0x3ff857f4, 0xf8b216d0, 0xbc5ba748, 0x9b4492ed,
+                    0x3ff868d9, 0x9bd4f6ba, 0xbc9fc6f8, 0xd931a436, 0x3ff879ca,
+                    0xd2db47bd, 0x3c85d2d7, 0xd98a6699, 0x3ff88ac7, 0xf37cb53a,
+                    0x3c9994c2, 0xa478580f, 0x3ff89bd0, 0x4475202a, 0x3c9d5395,
+                    0x422aa0db, 0x3ff8ace5, 0x56864b27, 0x3c96e9f1, 0xbad61778,
+                    0x3ff8be05, 0xfc43446e, 0x3c9ecb5e, 0x16b5448c, 0x3ff8cf32,
+                    0x32e9e3aa, 0xbc70d55e, 0x5e0866d9, 0x3ff8e06a, 0x6fc9b2e6,
+                    0xbc97114a, 0x99157736, 0x3ff8f1ae, 0xa2e3976c, 0x3c85cc13,
+                    0xd0282c8a, 0x3ff902fe, 0x85fe3fd2, 0x3c9592ca, 0x0b91ffc6,
+                    0x3ff9145b, 0x2e582524, 0xbc9dd679, 0x53aa2fe2, 0x3ff925c3,
+                    0xa639db7f, 0xbc83455f, 0xb0cdc5e5, 0x3ff93737, 0x81b57ebc,
+                    0xbc675fc7, 0x2b5f98e5, 0x3ff948b8, 0x797d2d99, 0xbc8dc3d6,
+                    0xcbc8520f, 0x3ff95a44, 0x96a5f039, 0xbc764b7c, 0x9a7670b3,
+                    0x3ff96bdd, 0x7f19c896, 0xbc5ba596, 0x9fde4e50, 0x3ff97d82,
+                    0x7c1b85d1, 0xbc9d185b, 0xe47a22a2, 0x3ff98f33, 0xa24c78ec,
+                    0x3c7cabda, 0x70ca07ba, 0x3ff9a0f1, 0x91cee632, 0xbc9173bd,
+                    0x4d53fe0d, 0x3ff9b2bb, 0x4df6d518, 0xbc9dd84e, 0x82a3f090,
+                    0x3ff9c491, 0xb071f2be, 0x3c7c7c46, 0x194bb8d5, 0x3ff9d674,
+                    0xa3dd8233, 0xbc9516be, 0x19e32323, 0x3ff9e863, 0x78e64c6e,
+                    0x3c7824ca, 0x8d07f29e, 0x3ff9fa5e, 0xaaf1face, 0xbc84a9ce,
+                    0x7b5de565, 0x3ffa0c66, 0x5d1cd533, 0xbc935949, 0xed8eb8bb,
+                    0x3ffa1e7a, 0xee8be70e, 0x3c9c6618, 0xec4a2d33, 0x3ffa309b,
+                    0x7ddc36ab, 0x3c96305c, 0x80460ad8, 0x3ffa42c9, 0x589fb120,
+                    0xbc9aa780, 0xb23e255d, 0x3ffa5503, 0xdb8d41e1, 0xbc9d2f6e,
+                    0x8af46052, 0x3ffa674a, 0x30670366, 0x3c650f56, 0x1330b358,
+                    0x3ffa799e, 0xcac563c7, 0x3c9bcb7e, 0x53c12e59, 0x3ffa8bfe,
+                    0xb2ba15a9, 0xbc94f867, 0x5579fdbf, 0x3ffa9e6b, 0x0ef7fd31,
+                    0x3c90fac9, 0x21356eba, 0x3ffab0e5, 0xdae94545, 0x3c889c31,
+                    0xbfd3f37a, 0x3ffac36b, 0xcae76cd0, 0xbc8f9234, 0x3a3c2774,
+                    0x3ffad5ff, 0xb6b1b8e5, 0x3c97ef3b, 0x995ad3ad, 0x3ffae89f,
+                    0x345dcc81, 0x3c97a1cd, 0xe622f2ff, 0x3ffafb4c, 0x0f315ecd,
+                    0xbc94b2fc, 0x298db666, 0x3ffb0e07, 0x4c80e425, 0xbc9bdef5,
+                    0x6c9a8952, 0x3ffb20ce, 0x4a0756cc, 0x3c94dd02, 0xb84f15fb,
+                    0x3ffb33a2, 0x3084d708, 0xbc62805e, 0x15b749b1, 0x3ffb4684,
+                    0xe9df7c90, 0xbc7f763d, 0x8de5593a, 0x3ffb5972, 0xbbba6de3,
+                    0xbc9c71df, 0x29f1c52a, 0x3ffb6c6e, 0x52883f6e, 0x3c92a8f3,
+                    0xf2fb5e47, 0x3ffb7f76, 0x7e54ac3b, 0xbc75584f, 0xf22749e4,
+                    0x3ffb928c, 0x54cb65c6, 0xbc9b7216, 0x30a1064a, 0x3ffba5b0,
+                    0x0e54292e, 0xbc9efcd3, 0xb79a6f1f, 0x3ffbb8e0, 0xc9696205,
+                    0xbc3f52d1, 0x904bc1d2, 0x3ffbcc1e, 0x7a2d9e84, 0x3c823dd0,
+                    0xc3f3a207, 0x3ffbdf69, 0x60ea5b53, 0xbc3c2623, 0x5bd71e09,
+                    0x3ffbf2c2, 0x3f6b9c73, 0xbc9efdca, 0x6141b33d, 0x3ffc0628,
+                    0xa1fbca34, 0xbc8d8a5a, 0xdd85529c, 0x3ffc199b, 0x895048dd,
+                    0x3c811065, 0xd9fa652c, 0x3ffc2d1c, 0x17c8a5d7, 0xbc96e516,
+                    0x5fffd07a, 0x3ffc40ab, 0xe083c60a, 0x3c9b4537, 0x78fafb22,
+                    0x3ffc5447, 0x2493b5af, 0x3c912f07, 0x2e57d14b, 0x3ffc67f1,
+                    0xff483cad, 0x3c92884d, 0x8988c933, 0x3ffc7ba8, 0xbe255559,
+                    0xbc8e76bb, 0x9406e7b5, 0x3ffc8f6d, 0x48805c44, 0x3c71acbc,
+                    0x5751c4db, 0x3ffca340, 0xd10d08f5, 0xbc87f2be, 0xdcef9069,
+                    0x3ffcb720, 0xd1e949db, 0x3c7503cb, 0x2e6d1675, 0x3ffccb0f,
+                    0x86009092, 0xbc7d220f, 0x555dc3fa, 0x3ffcdf0b, 0x53829d72,
+                    0xbc8dd83b, 0x5b5bab74, 0x3ffcf315, 0xb86dff57, 0xbc9a08e9,
+                    0x4a07897c, 0x3ffd072d, 0x43797a9c, 0xbc9cbc37, 0x2b08c968,
+                    0x3ffd1b53, 0x219a36ee, 0x3c955636, 0x080d89f2, 0x3ffd2f87,
+                    0x719d8578, 0xbc9d487b, 0xeacaa1d6, 0x3ffd43c8, 0xbf5a1614,
+                    0x3c93db53, 0xdcfba487, 0x3ffd5818, 0xd75b3707, 0x3c82ed02,
+                    0xe862e6d3, 0x3ffd6c76, 0x4a8165a0, 0x3c5fe87a, 0x16c98398,
+                    0x3ffd80e3, 0x8beddfe8, 0xbc911ec1, 0x71ff6075, 0x3ffd955d,
+                    0xbb9af6be, 0x3c9a052d, 0x03db3285, 0x3ffda9e6, 0x696db532,
+                    0x3c9c2300, 0xd63a8315, 0x3ffdbe7c, 0x926b8be4, 0xbc9b76f1,
+                    0xf301b460, 0x3ffdd321, 0x78f018c3, 0x3c92da57, 0x641c0658,
+                    0x3ffde7d5, 0x8e79ba8f, 0xbc9ca552, 0x337b9b5f, 0x3ffdfc97,
+                    0x4f184b5c, 0xbc91a5cd, 0x6b197d17, 0x3ffe1167, 0xbd5c7f44,
+                    0xbc72b529, 0x14f5a129, 0x3ffe2646, 0x817a1496, 0xbc97b627,
+                    0x3b16ee12, 0x3ffe3b33, 0x31fdc68b, 0xbc99f4a4, 0xe78b3ff6,
+                    0x3ffe502e, 0x80a9cc8f, 0x3c839e89, 0x24676d76, 0x3ffe6539,
+                    0x7522b735, 0xbc863ff8, 0xfbc74c83, 0x3ffe7a51, 0xca0c8de2,
+                    0x3c92d522, 0x77cdb740, 0x3ffe8f79, 0x80b054b1, 0xbc910894,
+                    0xa2a490da, 0x3ffea4af, 0x179c2893, 0xbc9e9c23, 0x867cca6e,
+                    0x3ffeb9f4, 0x2293e4f2, 0x3c94832f, 0x2d8e67f1, 0x3ffecf48,
+                    0xb411ad8c, 0xbc9c93f3, 0xa2188510, 0x3ffee4aa, 0xa487568d,
+                    0x3c91c68d, 0xee615a27, 0x3ffefa1b, 0x86a4b6b0, 0x3c9dc7f4,
+                    0x1cb6412a, 0x3fff0f9c, 0x65181d45, 0xbc932200, 0x376bba97,
+                    0x3fff252b, 0xbf0d8e43, 0x3c93a1a5, 0x48dd7274, 0x3fff3ac9,
+                    0x3ed837de, 0xbc795a5a, 0x5b6e4540, 0x3fff5076, 0x2dd8a18b,
+                    0x3c99d3e1, 0x798844f8, 0x3fff6632, 0x3539343e, 0x3c9fa37b,
+                    0xad9cbe14, 0x3fff7bfd, 0xd006350a, 0xbc9dbb12, 0x02243c89,
+                    0x3fff91d8, 0xa779f689, 0xbc612ea8, 0x819e90d8, 0x3fffa7c1,
+                    0xf3a5931e, 0x3c874853, 0x3692d514, 0x3fffbdba, 0x15098eb6,
+                    0xbc796773, 0x2b8f71f1, 0x3fffd3c2, 0x966579e7, 0x3c62eb74,
+                    0x6b2a23d9, 0x3fffe9d9, 0x7442fde3, 0x3c74a603
+    };
+
+    private static int[] eCoeff = {
+                    0xe78a6731, 0x3f55d87f, 0xd704a0c0, 0x3fac6b08, 0x6fba4e77,
+                    0x3f83b2ab, 0xff82c58f, 0x3fcebfbd, 0xfefa39ef, 0x3fe62e42,
+                    0x00000000, 0x00000000
+    };
+
+    private static int[] coeffH = {
+                    0x00000000, 0xbfd61a00, 0x00000000, 0xbf5dabe1
+    };
+
+    private static int[] highmaskLogX = {
+                    0xf8000000, 0xffffffff, 0x00000000, 0xfffff800
+    };
+
+    private static int[] halfmask = {
+                    0xf8000000, 0xffffffff, 0xf8000000, 0xffffffff
+    };
+
+    private static int[] coeffPow = {
+                    0x6dc96112, 0xbf836578, 0xee241472, 0xbf9b0301, 0x9f95985a,
+                    0xbfb528db, 0xb3841d2a, 0xbfd619b6, 0x518775e3, 0x3f9004f2,
+                    0xac8349bb, 0x3fa76c9b, 0x486ececc, 0x3fc4635e, 0x161bb241,
+                    0xbf5dabe1, 0x9f95985a, 0xbfb528db, 0xf8b5787d, 0x3ef2531e,
+                    0x486ececb, 0x3fc4635e, 0x412055cc, 0xbdd61bb2
+    };
+
+    private static int[] lTblPow = {
+                    0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x20000000,
+                    0x3feff00a, 0x96621f95, 0x3e5b1856, 0xe0000000, 0x3fefe019,
+                    0xe5916f9e, 0xbe325278, 0x00000000, 0x3fefd02f, 0x859a1062,
+                    0x3e595fb7, 0xc0000000, 0x3fefc049, 0xb245f18f, 0xbe529c38,
+                    0xe0000000, 0x3fefb069, 0xad2880a7, 0xbe501230, 0x60000000,
+                    0x3fefa08f, 0xc8e72420, 0x3e597bd1, 0x80000000, 0x3fef90ba,
+                    0xc30c4500, 0xbe5d6c75, 0xe0000000, 0x3fef80ea, 0x02c63f43,
+                    0x3e2e1318, 0xc0000000, 0x3fef7120, 0xb3d4cccc, 0xbe44c52a,
+                    0x00000000, 0x3fef615c, 0xdbd91397, 0xbe4e7d6c, 0xa0000000,
+                    0x3fef519c, 0x65c5cd68, 0xbe522dc8, 0xa0000000, 0x3fef41e2,
+                    0x46d1306c, 0xbe5a840e, 0xe0000000, 0x3fef322d, 0xd2980e94,
+                    0x3e5071af, 0xa0000000, 0x3fef227e, 0x773abade, 0xbe5891e5,
+                    0xa0000000, 0x3fef12d4, 0xdc6bf46b, 0xbe5cccbe, 0xe0000000,
+                    0x3fef032f, 0xbc7247fa, 0xbe2bab83, 0x80000000, 0x3feef390,
+                    0xbcaa1e46, 0xbe53bb3b, 0x60000000, 0x3feee3f6, 0x5f6c682d,
+                    0xbe54c619, 0x80000000, 0x3feed461, 0x5141e368, 0xbe4b6d86,
+                    0xe0000000, 0x3feec4d1, 0xec678f76, 0xbe369af6, 0x80000000,
+                    0x3feeb547, 0x41301f55, 0xbe2d4312, 0x60000000, 0x3feea5c2,
+                    0x676da6bd, 0xbe4d8dd0, 0x60000000, 0x3fee9642, 0x57a891c4,
+                    0x3e51f991, 0xa0000000, 0x3fee86c7, 0xe4eb491e, 0x3e579bf9,
+                    0x20000000, 0x3fee7752, 0xfddc4a2c, 0xbe3356e6, 0xc0000000,
+                    0x3fee67e1, 0xd75b5bf1, 0xbe449531, 0x80000000, 0x3fee5876,
+                    0xbd423b8e, 0x3df54fe4, 0x60000000, 0x3fee4910, 0x330e51b9,
+                    0x3e54289c, 0x80000000, 0x3fee39af, 0x8651a95f, 0xbe55aad6,
+                    0xa0000000, 0x3fee2a53, 0x5e98c708, 0xbe2fc4a9, 0xe0000000,
+                    0x3fee1afc, 0x0989328d, 0x3e23958c, 0x40000000, 0x3fee0bab,
+                    0xee642abd, 0xbe425dd8, 0xa0000000, 0x3fedfc5e, 0xc394d236,
+                    0x3e526362, 0x20000000, 0x3feded17, 0xe104aa8e, 0x3e4ce247,
+                    0xc0000000, 0x3fedddd4, 0x265a9be4, 0xbe5bb77a, 0x40000000,
+                    0x3fedce97, 0x0ecac52f, 0x3e4a7cb1, 0xe0000000, 0x3fedbf5e,
+                    0x124cb3b8, 0x3e257024, 0x80000000, 0x3fedb02b, 0xe6d4febe,
+                    0xbe2033ee, 0x20000000, 0x3feda0fd, 0x39cca00e, 0xbe3ddabc,
+                    0xc0000000, 0x3fed91d3, 0xef8a552a, 0xbe543390, 0x40000000,
+                    0x3fed82af, 0xb8e85204, 0x3e513850, 0xe0000000, 0x3fed738f,
+                    0x3d59fe08, 0xbe5db728, 0x40000000, 0x3fed6475, 0x3aa7ead1,
+                    0x3e58804b, 0xc0000000, 0x3fed555f, 0xf8a35ba9, 0xbe5298b0,
+                    0x00000000, 0x3fed464f, 0x9a88dd15, 0x3e5a8cdb, 0x40000000,
+                    0x3fed3743, 0xb0b0a190, 0x3e598635, 0x80000000, 0x3fed283c,
+                    0xe2113295, 0xbe5c1119, 0x80000000, 0x3fed193a, 0xafbf1728,
+                    0xbe492e9c, 0x60000000, 0x3fed0a3d, 0xe4a4ccf3, 0x3e19b90e,
+                    0x20000000, 0x3fecfb45, 0xba3cbeb8, 0x3e406b50, 0xc0000000,
+                    0x3fecec51, 0x110f7ddd, 0x3e0d6806, 0x40000000, 0x3fecdd63,
+                    0x7dd7d508, 0xbe5a8943, 0x80000000, 0x3fecce79, 0x9b60f271,
+                    0xbe50676a, 0x80000000, 0x3fecbf94, 0x0b9ad660, 0x3e59174f,
+                    0x60000000, 0x3fecb0b4, 0x00823d9c, 0x3e5bbf72, 0x20000000,
+                    0x3feca1d9, 0x38a6ec89, 0xbe4d38f9, 0x80000000, 0x3fec9302,
+                    0x3a0b7d8e, 0x3e53dbfd, 0xc0000000, 0x3fec8430, 0xc6826b34,
+                    0xbe27c5c9, 0xc0000000, 0x3fec7563, 0x0c706381, 0xbe593653,
+                    0x60000000, 0x3fec669b, 0x7df34ec7, 0x3e461ab5, 0xe0000000,
+                    0x3fec57d7, 0x40e5e7e8, 0xbe5c3dae, 0x00000000, 0x3fec4919,
+                    0x5602770f, 0xbe55219d, 0xc0000000, 0x3fec3a5e, 0xec7911eb,
+                    0x3e5a5d25, 0x60000000, 0x3fec2ba9, 0xb39ea225, 0xbe53c00b,
+                    0x80000000, 0x3fec1cf8, 0x967a212e, 0x3e5a8ddf, 0x60000000,
+                    0x3fec0e4c, 0x580798bd, 0x3e5f53ab, 0x00000000, 0x3febffa5,
+                    0xb8282df6, 0xbe46b874, 0x20000000, 0x3febf102, 0xe33a6729,
+                    0x3e54963f, 0x00000000, 0x3febe264, 0x3b53e88a, 0xbe3adce1,
+                    0x60000000, 0x3febd3ca, 0xc2585084, 0x3e5cde9f, 0x80000000,
+                    0x3febc535, 0xa335c5ee, 0xbe39fd9c, 0x20000000, 0x3febb6a5,
+                    0x7325b04d, 0x3e42ba15, 0x60000000, 0x3feba819, 0x1564540f,
+                    0x3e3a9f35, 0x40000000, 0x3feb9992, 0x83fff592, 0xbe5465ce,
+                    0xa0000000, 0x3feb8b0f, 0xb9da63d3, 0xbe4b1a0a, 0x80000000,
+                    0x3feb7c91, 0x6d6f1ea4, 0x3e557657, 0x00000000, 0x3feb6e18,
+                    0x5e80a1bf, 0x3e4ddbb6, 0x00000000, 0x3feb5fa3, 0x1c9eacb5,
+                    0x3e592877, 0xa0000000, 0x3feb5132, 0x6d40beb3, 0xbe51858c,
+                    0xa0000000, 0x3feb42c6, 0xd740c67b, 0x3e427ad2, 0x40000000,
+                    0x3feb345f, 0xa3e0ccee, 0xbe5c2fc4, 0x40000000, 0x3feb25fc,
+                    0x8e752b50, 0xbe3da3c2, 0xc0000000, 0x3feb179d, 0xa892e7de,
+                    0x3e1fb481, 0xc0000000, 0x3feb0943, 0x21ed71e9, 0xbe365206,
+                    0x20000000, 0x3feafaee, 0x0e1380a3, 0x3e5c5b7b, 0x20000000,
+                    0x3feaec9d, 0x3c3d640e, 0xbe5dbbd0, 0x60000000, 0x3feade50,
+                    0x8f97a715, 0x3e3a8ec5, 0x20000000, 0x3fead008, 0x23ab2839,
+                    0x3e2fe98a, 0x40000000, 0x3feac1c4, 0xf4bbd50f, 0x3e54d8f6,
+                    0xe0000000, 0x3feab384, 0x14757c4d, 0xbe48774c, 0xc0000000,
+                    0x3feaa549, 0x7c7b0eea, 0x3e5b51bb, 0x20000000, 0x3fea9713,
+                    0xf56f7013, 0x3e386200, 0xe0000000, 0x3fea88e0, 0xbe428ebe,
+                    0xbe514af5, 0xe0000000, 0x3fea7ab2, 0x8d0e4496, 0x3e4f9165,
+                    0x60000000, 0x3fea6c89, 0xdbacc5d5, 0xbe5c063b, 0x20000000,
+                    0x3fea5e64, 0x3f19d970, 0xbe5a0c8c, 0x20000000, 0x3fea5043,
+                    0x09ea3e6b, 0x3e5065dc, 0x80000000, 0x3fea4226, 0x78df246c,
+                    0x3e5e05f6, 0x40000000, 0x3fea340e, 0x4057d4a0, 0x3e431b2b,
+                    0x40000000, 0x3fea25fa, 0x82867bb5, 0x3e4b76be, 0xa0000000,
+                    0x3fea17ea, 0x9436f40a, 0xbe5aad39, 0x20000000, 0x3fea09df,
+                    0x4b5253b3, 0x3e46380b, 0x00000000, 0x3fe9fbd8, 0x8fc52466,
+                    0xbe386f9b, 0x20000000, 0x3fe9edd5, 0x22d3f344, 0xbe538347,
+                    0x60000000, 0x3fe9dfd6, 0x1ac33522, 0x3e5dbc53, 0x00000000,
+                    0x3fe9d1dc, 0xeabdff1d, 0x3e40fc0c, 0xe0000000, 0x3fe9c3e5,
+                    0xafd30e73, 0xbe585e63, 0xe0000000, 0x3fe9b5f3, 0xa52f226a,
+                    0xbe43e8f9, 0x20000000, 0x3fe9a806, 0xecb8698d, 0xbe515b36,
+                    0x80000000, 0x3fe99a1c, 0xf2b4e89d, 0x3e48b62b, 0x20000000,
+                    0x3fe98c37, 0x7c9a88fb, 0x3e44414c, 0x00000000, 0x3fe97e56,
+                    0xda015741, 0xbe5d13ba, 0xe0000000, 0x3fe97078, 0x5fdace06,
+                    0x3e51b947, 0x00000000, 0x3fe962a0, 0x956ca094, 0x3e518785,
+                    0x40000000, 0x3fe954cb, 0x01164c1d, 0x3e5d5b57, 0xc0000000,
+                    0x3fe946fa, 0xe63b3767, 0xbe4f84e7, 0x40000000, 0x3fe9392e,
+                    0xe57cc2a9, 0x3e34eda3, 0xe0000000, 0x3fe92b65, 0x8c75b544,
+                    0x3e5766a0, 0xc0000000, 0x3fe91da1, 0x37d1d087, 0xbe5e2ab1,
+                    0x80000000, 0x3fe90fe1, 0xa953dc20, 0x3e5fa1f3, 0x80000000,
+                    0x3fe90225, 0xdbd3f369, 0x3e47d6db, 0xa0000000, 0x3fe8f46d,
+                    0x1c9be989, 0xbe5e2b0a, 0xa0000000, 0x3fe8e6b9, 0x3c93d76a,
+                    0x3e5c8618, 0xe0000000, 0x3fe8d909, 0x2182fc9a, 0xbe41aa9e,
+                    0x20000000, 0x3fe8cb5e, 0xe6b3539d, 0xbe530d19, 0x60000000,
+                    0x3fe8bdb6, 0x49e58cc3, 0xbe3bb374, 0xa0000000, 0x3fe8b012,
+                    0xa7cfeb8f, 0x3e56c412, 0x00000000, 0x3fe8a273, 0x8d52bc19,
+                    0x3e1429b8, 0x60000000, 0x3fe894d7, 0x4dc32c6c, 0xbe48604c,
+                    0xc0000000, 0x3fe8873f, 0x0c868e56, 0xbe564ee5, 0x00000000,
+                    0x3fe879ac, 0x56aee828, 0x3e5e2fd8, 0x60000000, 0x3fe86c1c,
+                    0x7ceab8ec, 0x3e493365, 0xc0000000, 0x3fe85e90, 0x78d4dadc,
+                    0xbe4f7f25, 0x00000000, 0x3fe85109, 0x0ccd8280, 0x3e31e7a2,
+                    0x40000000, 0x3fe84385, 0x34ba4e15, 0x3e328077, 0x80000000,
+                    0x3fe83605, 0xa670975a, 0xbe53eee5, 0xa0000000, 0x3fe82889,
+                    0xf61b77b2, 0xbe43a20a, 0xa0000000, 0x3fe81b11, 0x13e6643b,
+                    0x3e5e5fe5, 0xc0000000, 0x3fe80d9d, 0x82cc94e8, 0xbe5ff1f9,
+                    0xa0000000, 0x3fe8002d, 0x8a0c9c5d, 0xbe42b0e7, 0x60000000,
+                    0x3fe7f2c1, 0x22a16f01, 0x3e5d9ea0, 0x20000000, 0x3fe7e559,
+                    0xc38cd451, 0x3e506963, 0xc0000000, 0x3fe7d7f4, 0x9902bc71,
+                    0x3e4503d7, 0x40000000, 0x3fe7ca94, 0xdef2a3c0, 0x3e3d98ed,
+                    0xa0000000, 0x3fe7bd37, 0xed49abb0, 0x3e24c1ff, 0xe0000000,
+                    0x3fe7afde, 0xe3b0be70, 0xbe40c467, 0x00000000, 0x3fe7a28a,
+                    0xaf9f193c, 0xbe5dff6c, 0xe0000000, 0x3fe79538, 0xb74cf6b6,
+                    0xbe258ed0, 0xa0000000, 0x3fe787eb, 0x1d9127c7, 0x3e345fb0,
+                    0x40000000, 0x3fe77aa2, 0x1028c21d, 0xbe4619bd, 0xa0000000,
+                    0x3fe76d5c, 0x7cb0b5e4, 0x3e40f1a2, 0xe0000000, 0x3fe7601a,
+                    0x2b1bc4ad, 0xbe32e8bb, 0xe0000000, 0x3fe752dc, 0x6839f64e,
+                    0x3e41f57b, 0xc0000000, 0x3fe745a2, 0xc4121f7e, 0xbe52c40a,
+                    0x60000000, 0x3fe7386c, 0xd6852d72, 0xbe5c4e6b, 0xc0000000,
+                    0x3fe72b39, 0x91d690f7, 0xbe57f88f, 0xe0000000, 0x3fe71e0a,
+                    0x627a2159, 0xbe4425d5, 0xc0000000, 0x3fe710df, 0x50a54033,
+                    0x3e422b7e, 0x60000000, 0x3fe703b8, 0x3b0b5f91, 0x3e5d3857,
+                    0xe0000000, 0x3fe6f694, 0x84d628a2, 0xbe51f090, 0x00000000,
+                    0x3fe6e975, 0x306d8894, 0xbe414d83, 0xe0000000, 0x3fe6dc58,
+                    0x30bf24aa, 0xbe4650ca, 0x80000000, 0x3fe6cf40, 0xd4628d69,
+                    0xbe5db007, 0xc0000000, 0x3fe6c22b, 0xa2aae57b, 0xbe31d279,
+                    0xc0000000, 0x3fe6b51a, 0x860edf7e, 0xbe2d4c4a, 0x80000000,
+                    0x3fe6a80d, 0xf3559341, 0xbe5f7e98, 0xe0000000, 0x3fe69b03,
+                    0xa885899e, 0xbe5c2011, 0xe0000000, 0x3fe68dfd, 0x2bdc6d37,
+                    0x3e224a82, 0xa0000000, 0x3fe680fb, 0xc12ad1b9, 0xbe40cf56,
+                    0x00000000, 0x3fe673fd, 0x1bcdf659, 0xbdf52f2d, 0x00000000,
+                    0x3fe66702, 0x5df10408, 0x3e5663e0, 0xc0000000, 0x3fe65a0a,
+                    0xa4070568, 0xbe40b12f, 0x00000000, 0x3fe64d17, 0x71c54c47,
+                    0x3e5f5e8b, 0x00000000, 0x3fe64027, 0xbd4b7e83, 0x3e42ead6,
+                    0xa0000000, 0x3fe6333a, 0x61598bd2, 0xbe4c48d4, 0xc0000000,
+                    0x3fe62651, 0x6f538d61, 0x3e548401, 0xa0000000, 0x3fe6196c,
+                    0x14344120, 0xbe529af6, 0x00000000, 0x3fe60c8b, 0x5982c587,
+                    0xbe3e1e4f, 0x00000000, 0x3fe5ffad, 0xfe51d4ea, 0xbe4c897a,
+                    0x80000000, 0x3fe5f2d2, 0xfd46ebe1, 0x3e552e00, 0xa0000000,
+                    0x3fe5e5fb, 0xa4695699, 0x3e5ed471, 0x60000000, 0x3fe5d928,
+                    0x80d118ae, 0x3e456b61, 0xa0000000, 0x3fe5cc58, 0x304c330b,
+                    0x3e54dc29, 0x80000000, 0x3fe5bf8c, 0x0af2dedf, 0xbe3aa9bd,
+                    0xe0000000, 0x3fe5b2c3, 0x15fc9258, 0xbe479a37, 0xc0000000,
+                    0x3fe5a5fe, 0x9292c7ea, 0x3e188650, 0x20000000, 0x3fe5993d,
+                    0x33b4d380, 0x3e5d6d93, 0x20000000, 0x3fe58c7f, 0x02fd16c7,
+                    0x3e2fe961, 0xa0000000, 0x3fe57fc4, 0x4a05edb6, 0xbe4d55b4,
+                    0xa0000000, 0x3fe5730d, 0x3d443abb, 0xbe5e6954, 0x00000000,
+                    0x3fe5665a, 0x024acfea, 0x3e50e61b, 0x00000000, 0x3fe559aa,
+                    0xcc9edd09, 0xbe325403, 0x60000000, 0x3fe54cfd, 0x1fe26950,
+                    0x3e5d500e, 0x60000000, 0x3fe54054, 0x6c5ae164, 0xbe4a79b4,
+                    0xc0000000, 0x3fe533ae, 0x154b0287, 0xbe401571, 0xa0000000,
+                    0x3fe5270c, 0x0673f401, 0xbe56e56b, 0xe0000000, 0x3fe51a6d,
+                    0x751b639c, 0x3e235269, 0xa0000000, 0x3fe50dd2, 0x7c7b2bed,
+                    0x3ddec887, 0xc0000000, 0x3fe5013a, 0xafab4e17, 0x3e5e7575,
+                    0x60000000, 0x3fe4f4a6, 0x2e308668, 0x3e59aed6, 0x80000000,
+                    0x3fe4e815, 0xf33e2a76, 0xbe51f184, 0xe0000000, 0x3fe4db87,
+                    0x839f3e3e, 0x3e57db01, 0xc0000000, 0x3fe4cefd, 0xa9eda7bb,
+                    0x3e535e0f, 0x00000000, 0x3fe4c277, 0x2a8f66a5, 0x3e5ce451,
+                    0xc0000000, 0x3fe4b5f3, 0x05192456, 0xbe4e8518, 0xc0000000,
+                    0x3fe4a973, 0x4aa7cd1d, 0x3e46784a, 0x40000000, 0x3fe49cf7,
+                    0x8e23025e, 0xbe5749f2, 0x00000000, 0x3fe4907e, 0x18d30215,
+                    0x3e360f39, 0x20000000, 0x3fe48408, 0x63dcf2f3, 0x3e5e00fe,
+                    0xc0000000, 0x3fe47795, 0x46182d09, 0xbe5173d9, 0xa0000000,
+                    0x3fe46b26, 0x8f0e62aa, 0xbe48f281, 0xe0000000, 0x3fe45eba,
+                    0x5775c40c, 0xbe56aad4, 0x60000000, 0x3fe45252, 0x0fe25f69,
+                    0x3e48bd71, 0x40000000, 0x3fe445ed, 0xe9989ec5, 0x3e590d97,
+                    0x80000000, 0x3fe4398b, 0xb3d9ffe3, 0x3e479dbc, 0x20000000,
+                    0x3fe42d2d, 0x388e4d2e, 0xbe5eed80, 0xe0000000, 0x3fe420d1,
+                    0x6f797c18, 0x3e554b4c, 0x20000000, 0x3fe4147a, 0x31048bb4,
+                    0xbe5b1112, 0x80000000, 0x3fe40825, 0x2efba4f9, 0x3e48ebc7,
+                    0x40000000, 0x3fe3fbd4, 0x50201119, 0x3e40b701, 0x40000000,
+                    0x3fe3ef86, 0x0a4db32c, 0x3e551de8, 0xa0000000, 0x3fe3e33b,
+                    0x0c9c148b, 0xbe50c1f6, 0x20000000, 0x3fe3d6f4, 0xc9129447,
+                    0x3e533fa0, 0x00000000, 0x3fe3cab0, 0xaae5b5a0, 0xbe22b68e,
+                    0x20000000, 0x3fe3be6f, 0x02305e8a, 0xbe54fc08, 0x60000000,
+                    0x3fe3b231, 0x7f908258, 0x3e57dc05, 0x00000000, 0x3fe3a5f7,
+                    0x1a09af78, 0x3e08038b, 0xe0000000, 0x3fe399bf, 0x490643c1,
+                    0xbe5dbe42, 0xe0000000, 0x3fe38d8b, 0x5e8ad724, 0xbe3c2b72,
+                    0x20000000, 0x3fe3815b, 0xc67196b6, 0x3e1713cf, 0xa0000000,
+                    0x3fe3752d, 0x6182e429, 0xbe3ec14c, 0x40000000, 0x3fe36903,
+                    0xab6eb1ae, 0x3e5a2cc5, 0x40000000, 0x3fe35cdc, 0xfe5dc064,
+                    0xbe5c5878, 0x40000000, 0x3fe350b8, 0x0ba6b9e4, 0x3e51619b,
+                    0x80000000, 0x3fe34497, 0x857761aa, 0x3e5fff53, 0x00000000,
+                    0x3fe3387a, 0xf872d68c, 0x3e484f4d, 0xa0000000, 0x3fe32c5f,
+                    0x087e97c2, 0x3e52842e, 0x80000000, 0x3fe32048, 0x73d6d0c0,
+                    0xbe503edf, 0x80000000, 0x3fe31434, 0x0c1456a1, 0xbe5f72ad,
+                    0xa0000000, 0x3fe30823, 0x83a1a4d5, 0xbe5e65cc, 0xe0000000,
+                    0x3fe2fc15, 0x855a7390, 0xbe506438, 0x40000000, 0x3fe2f00b,
+                    0xa2898287, 0x3e3d22a2, 0xe0000000, 0x3fe2e403, 0x8b56f66f,
+                    0xbe5aa5fd, 0x80000000, 0x3fe2d7ff, 0x52db119a, 0x3e3a2e3d,
+                    0x60000000, 0x3fe2cbfe, 0xe2ddd4c0, 0xbe586469, 0x40000000,
+                    0x3fe2c000, 0x6b01bf10, 0x3e352b9d, 0x40000000, 0x3fe2b405,
+                    0xb07a1cdf, 0x3e5c5cda, 0x80000000, 0x3fe2a80d, 0xc7b5f868,
+                    0xbe5668b3, 0xc0000000, 0x3fe29c18, 0x185edf62, 0xbe563d66,
+                    0x00000000, 0x3fe29027, 0xf729e1cc, 0x3e59a9a0, 0x80000000,
+                    0x3fe28438, 0x6433c727, 0xbe43cc89, 0x00000000, 0x3fe2784d,
+                    0x41782631, 0xbe30750c, 0xa0000000, 0x3fe26c64, 0x914911b7,
+                    0xbe58290e, 0x40000000, 0x3fe2607f, 0x3dcc73e1, 0xbe4269cd,
+                    0x00000000, 0x3fe2549d, 0x2751bf70, 0xbe5a6998, 0xc0000000,
+                    0x3fe248bd, 0x4248b9fb, 0xbe4ddb00, 0x80000000, 0x3fe23ce1,
+                    0xf35cf82f, 0x3e561b71, 0x60000000, 0x3fe23108, 0x8e481a2d,
+                    0x3e518fb9, 0x60000000, 0x3fe22532, 0x5ab96edc, 0xbe5fafc5,
+                    0x40000000, 0x3fe2195f, 0x80943911, 0xbe07f819, 0x40000000,
+                    0x3fe20d8f, 0x386f2d6c, 0xbe54ba8b, 0x40000000, 0x3fe201c2,
+                    0xf29664ac, 0xbe5eb815, 0x20000000, 0x3fe1f5f8, 0x64f03390,
+                    0x3e5e320c, 0x20000000, 0x3fe1ea31, 0x747ff696, 0x3e5ef0a5,
+                    0x40000000, 0x3fe1de6d, 0x3e9ceb51, 0xbe5f8d27, 0x20000000,
+                    0x3fe1d2ac, 0x4ae0b55e, 0x3e5faa21, 0x20000000, 0x3fe1c6ee,
+                    0x28569a5e, 0x3e598a4f, 0x20000000, 0x3fe1bb33, 0x54b33e07,
+                    0x3e46130a, 0x20000000, 0x3fe1af7b, 0x024f1078, 0xbe4dbf93,
+                    0x00000000, 0x3fe1a3c6, 0xb0783bfa, 0x3e419248, 0xe0000000,
+                    0x3fe19813, 0x2f02b836, 0x3e4e02b7, 0xc0000000, 0x3fe18c64,
+                    0x28dec9d4, 0x3e09064f, 0x80000000, 0x3fe180b8, 0x45cbf406,
+                    0x3e5b1f46, 0x40000000, 0x3fe1750f, 0x03d9964c, 0x3e5b0a79,
+                    0x00000000, 0x3fe16969, 0x8b5b882b, 0xbe238086, 0xa0000000,
+                    0x3fe15dc5, 0x73bad6f8, 0xbdf1fca4, 0x20000000, 0x3fe15225,
+                    0x5385769c, 0x3e5e8d76, 0xa0000000, 0x3fe14687, 0x1676dc6b,
+                    0x3e571d08, 0x20000000, 0x3fe13aed, 0xa8c41c7f, 0xbe598a25,
+                    0x60000000, 0x3fe12f55, 0xc4e1aaf0, 0x3e435277, 0xa0000000,
+                    0x3fe123c0, 0x403638e1, 0xbe21aa7c, 0xc0000000, 0x3fe1182e,
+                    0x557a092b, 0xbdd0116b, 0xc0000000, 0x3fe10c9f, 0x7d779f66,
+                    0x3e4a61ba, 0xc0000000, 0x3fe10113, 0x2b09c645, 0xbe5d586e,
+                    0x20000000, 0x3fe0ea04, 0xea2cad46, 0x3e5aa97c, 0x20000000,
+                    0x3fe0d300, 0x23190e54, 0x3e50f1a7, 0xa0000000, 0x3fe0bc07,
+                    0x1379a5a6, 0xbe51619d, 0x60000000, 0x3fe0a51a, 0x926a3d4a,
+                    0x3e5cf019, 0xa0000000, 0x3fe08e38, 0xa8c24358, 0x3e35241e,
+                    0x20000000, 0x3fe07762, 0x24317e7a, 0x3e512cfa, 0x00000000,
+                    0x3fe06097, 0xfd9cf274, 0xbe55bef3, 0x00000000, 0x3fe049d7,
+                    0x3689b49d, 0xbe36d26d, 0x40000000, 0x3fe03322, 0xf72ef6c4,
+                    0xbe54cd08, 0xa0000000, 0x3fe01c78, 0x23702d2d, 0xbe5900bf,
+                    0x00000000, 0x3fe005da, 0x3f59c14c, 0x3e57d80b, 0x40000000,
+                    0x3fdfde8d, 0xad67766d, 0xbe57fad4, 0x40000000, 0x3fdfb17c,
+                    0x644f4ae7, 0x3e1ee43b, 0x40000000, 0x3fdf8481, 0x903234d2,
+                    0x3e501a86, 0x40000000, 0x3fdf579c, 0xafe9e509, 0xbe267c3e,
+                    0x00000000, 0x3fdf2acd, 0xb7dfda0b, 0xbe48149b, 0x40000000,
+                    0x3fdefe13, 0x3b94305e, 0x3e5f4ea7, 0x80000000, 0x3fded16f,
+                    0x5d95da61, 0xbe55c198, 0x00000000, 0x3fdea4e1, 0x406960c9,
+                    0xbdd99a19, 0x00000000, 0x3fde7868, 0xd22f3539, 0x3e470c78,
+                    0x80000000, 0x3fde4c04, 0x83eec535, 0xbe3e1232, 0x40000000,
+                    0x3fde1fb6, 0x3dfbffcb, 0xbe4b7d71, 0x40000000, 0x3fddf37d,
+                    0x7e1be4e0, 0xbe5b8f8f, 0x40000000, 0x3fddc759, 0x46dae887,
+                    0xbe350458, 0x80000000, 0x3fdd9b4a, 0xed6ecc49, 0xbe5f0045,
+                    0x80000000, 0x3fdd6f50, 0x2e9e883c, 0x3e2915da, 0x80000000,
+                    0x3fdd436b, 0xf0bccb32, 0x3e4a68c9, 0x80000000, 0x3fdd179b,
+                    0x9bbfc779, 0xbe54a26a, 0x00000000, 0x3fdcebe0, 0x7cea33ab,
+                    0x3e43c6b7, 0x40000000, 0x3fdcc039, 0xe740fd06, 0x3e5526c2,
+                    0x40000000, 0x3fdc94a7, 0x9eadeb1a, 0xbe396d8d, 0xc0000000,
+                    0x3fdc6929, 0xf0a8f95a, 0xbe5c0ab2, 0x80000000, 0x3fdc3dc0,
+                    0x6ee2693b, 0x3e0992e6, 0xc0000000, 0x3fdc126b, 0x5ac6b581,
+                    0xbe2834b6, 0x40000000, 0x3fdbe72b, 0x8cc226ff, 0x3e3596a6,
+                    0x00000000, 0x3fdbbbff, 0xf92a74bb, 0x3e3c5813, 0x00000000,
+                    0x3fdb90e7, 0x479664c0, 0xbe50d644, 0x00000000, 0x3fdb65e3,
+                    0x5004975b, 0xbe55258f, 0x00000000, 0x3fdb3af3, 0xe4b23194,
+                    0xbe588407, 0xc0000000, 0x3fdb1016, 0xe65d4d0a, 0x3e527c26,
+                    0x80000000, 0x3fdae54e, 0x814fddd6, 0x3e5962a2, 0x40000000,
+                    0x3fdaba9a, 0xe19d0913, 0xbe562f4e, 0x80000000, 0x3fda8ff9,
+                    0x43cfd006, 0xbe4cfdeb, 0x40000000, 0x3fda656c, 0x686f0a4e,
+                    0x3e5e47a8, 0xc0000000, 0x3fda3af2, 0x7200d410, 0x3e5e1199,
+                    0xc0000000, 0x3fda108c, 0xabd2266e, 0x3e5ee4d1, 0x40000000,
+                    0x3fd9e63a, 0x396f8f2c, 0x3e4dbffb, 0x00000000, 0x3fd9bbfb,
+                    0xe32b25dd, 0x3e5c3a54, 0x40000000, 0x3fd991cf, 0x431e4035,
+                    0xbe457925, 0x80000000, 0x3fd967b6, 0x7bed3dd3, 0x3e40c61d,
+                    0x00000000, 0x3fd93db1, 0xd7449365, 0x3e306419, 0x80000000,
+                    0x3fd913be, 0x1746e791, 0x3e56fcfc, 0x40000000, 0x3fd8e9df,
+                    0xf3a9028b, 0xbe5041b9, 0xc0000000, 0x3fd8c012, 0x56840c50,
+                    0xbe26e20a, 0x40000000, 0x3fd89659, 0x19763102, 0xbe51f466,
+                    0x80000000, 0x3fd86cb2, 0x7032de7c, 0xbe4d298a, 0x80000000,
+                    0x3fd8431e, 0xdeb39fab, 0xbe4361eb, 0x40000000, 0x3fd8199d,
+                    0x5d01cbe0, 0xbe5425b3, 0x80000000, 0x3fd7f02e, 0x3ce99aa9,
+                    0x3e146fa8, 0x80000000, 0x3fd7c6d2, 0xd1a262b9, 0xbe5a1a69,
+                    0xc0000000, 0x3fd79d88, 0x8606c236, 0x3e423a08, 0x80000000,
+                    0x3fd77451, 0x8fd1e1b7, 0x3e5a6a63, 0xc0000000, 0x3fd74b2c,
+                    0xe491456a, 0x3e42c1ca, 0x40000000, 0x3fd7221a, 0x4499a6d7,
+                    0x3e36a69a, 0x00000000, 0x3fd6f91a, 0x5237df94, 0xbe0f8f02,
+                    0x00000000, 0x3fd6d02c, 0xb6482c6e, 0xbe5abcf7, 0x00000000,
+                    0x3fd6a750, 0x1919fd61, 0xbe57ade2, 0x00000000, 0x3fd67e86,
+                    0xaa7a994d, 0xbe3f3fbd, 0x00000000, 0x3fd655ce, 0x67db014c,
+                    0x3e33c550, 0x00000000, 0x3fd62d28, 0xa82856b7, 0xbe1409d1,
+                    0xc0000000, 0x3fd60493, 0x1e6a300d, 0x3e55d899, 0x80000000,
+                    0x3fd5dc11, 0x1222bd5c, 0xbe35bfc0, 0xc0000000, 0x3fd5b3a0,
+                    0x6e8dc2d3, 0x3e5d4d79, 0x00000000, 0x3fd58b42, 0xe0e4ace6,
+                    0xbe517303, 0x80000000, 0x3fd562f4, 0xb306e0a8, 0x3e5edf0f,
+                    0xc0000000, 0x3fd53ab8, 0x6574bc54, 0x3e5ee859, 0x80000000,
+                    0x3fd5128e, 0xea902207, 0x3e5f6188, 0xc0000000, 0x3fd4ea75,
+                    0x9f911d79, 0x3e511735, 0x80000000, 0x3fd4c26e, 0xf9c77397,
+                    0xbe5b1643, 0x40000000, 0x3fd49a78, 0x15fc9258, 0x3e479a37,
+                    0x80000000, 0x3fd47293, 0xd5a04dd9, 0xbe426e56, 0xc0000000,
+                    0x3fd44abf, 0xe04042f5, 0x3e56f7c6, 0x40000000, 0x3fd422fd,
+                    0x1d8bf2c8, 0x3e5d8810, 0x00000000, 0x3fd3fb4c, 0x88a8ddee,
+                    0xbe311454, 0xc0000000, 0x3fd3d3ab, 0x3e3b5e47, 0xbe5d1b72,
+                    0x40000000, 0x3fd3ac1c, 0xc2ab5d59, 0x3e31b02b, 0xc0000000,
+                    0x3fd3849d, 0xd4e34b9e, 0x3e51cb2f, 0x40000000, 0x3fd35d30,
+                    0x177204fb, 0xbe2b8cd7, 0x80000000, 0x3fd335d3, 0xfcd38c82,
+                    0xbe4356e1, 0x80000000, 0x3fd30e87, 0x64f54acc, 0xbe4e6224,
+                    0x00000000, 0x3fd2e74c, 0xaa7975d9, 0x3e5dc0fe, 0x80000000,
+                    0x3fd2c021, 0x516dab3f, 0xbe50ffa3, 0x40000000, 0x3fd29907,
+                    0x2bfb7313, 0x3e5674a2, 0xc0000000, 0x3fd271fd, 0x0549fc99,
+                    0x3e385d29, 0xc0000000, 0x3fd24b04, 0x55b63073, 0xbe500c6d,
+                    0x00000000, 0x3fd2241c, 0x3f91953a, 0x3e389977, 0xc0000000,
+                    0x3fd1fd43, 0xa1543f71, 0xbe3487ab, 0xc0000000, 0x3fd1d67b,
+                    0x4ec8867c, 0x3df6a2dc, 0x00000000, 0x3fd1afc4, 0x4328e3bb,
+                    0x3e41d9c0, 0x80000000, 0x3fd1891c, 0x2e1cda84, 0x3e3bdd87,
+                    0x40000000, 0x3fd16285, 0x4b5331ae, 0xbe53128e, 0x00000000,
+                    0x3fd13bfe, 0xb9aec164, 0xbe52ac98, 0xc0000000, 0x3fd11586,
+                    0xd91e1316, 0xbe350630, 0x80000000, 0x3fd0ef1f, 0x7cacc12c,
+                    0x3e3f5219, 0x40000000, 0x3fd0c8c8, 0xbce277b7, 0x3e3d30c0,
+                    0x00000000, 0x3fd0a281, 0x2a63447d, 0xbe541377, 0x80000000,
+                    0x3fd07c49, 0xfac483b5, 0xbe5772ec, 0xc0000000, 0x3fd05621,
+                    0x36b8a570, 0xbe4fd4bd, 0xc0000000, 0x3fd03009, 0xbae505f7,
+                    0xbe450388, 0x80000000, 0x3fd00a01, 0x3e35aead, 0xbe5430fc,
+                    0x80000000, 0x3fcfc811, 0x707475ac, 0x3e38806e, 0x80000000,
+                    0x3fcf7c3f, 0xc91817fc, 0xbe40ccea, 0x80000000, 0x3fcf308c,
+                    0xae05d5e9, 0xbe4919b8, 0x80000000, 0x3fcee4f8, 0xae6cc9e6,
+                    0xbe530b94, 0x00000000, 0x3fce9983, 0x1efe3e8e, 0x3e57747e,
+                    0x00000000, 0x3fce4e2d, 0xda78d9bf, 0xbe59a608, 0x00000000,
+                    0x3fce02f5, 0x8abe2c2e, 0x3e4a35ad, 0x00000000, 0x3fcdb7dc,
+                    0x1495450d, 0xbe0872cc, 0x80000000, 0x3fcd6ce1, 0x86ee0ba0,
+                    0xbe4f59a0, 0x00000000, 0x3fcd2205, 0xe81ca888, 0x3e5402c3,
+                    0x00000000, 0x3fccd747, 0x3b4424b9, 0x3e5dfdc3, 0x80000000,
+                    0x3fcc8ca7, 0xd305b56c, 0x3e202da6, 0x00000000, 0x3fcc4226,
+                    0x399a6910, 0xbe482a1c, 0x80000000, 0x3fcbf7c2, 0x747f7938,
+                    0xbe587372, 0x80000000, 0x3fcbad7c, 0x6fc246a0, 0x3e50d83d,
+                    0x00000000, 0x3fcb6355, 0xee9e9be5, 0xbe5c35bd, 0x80000000,
+                    0x3fcb194a, 0x8416c0bc, 0x3e546d4f, 0x00000000, 0x3fcacf5e,
+                    0x49f7f08f, 0x3e56da76, 0x00000000, 0x3fca858f, 0x5dc30de2,
+                    0x3e5f390c, 0x00000000, 0x3fca3bde, 0x950583b6, 0xbe5e4169,
+                    0x80000000, 0x3fc9f249, 0x33631553, 0x3e52aeb1, 0x00000000,
+                    0x3fc9a8d3, 0xde8795a6, 0xbe59a504, 0x00000000, 0x3fc95f79,
+                    0x076bf41e, 0x3e5122fe, 0x80000000, 0x3fc9163c, 0x2914c8e7,
+                    0x3e3dd064, 0x00000000, 0x3fc8cd1d, 0x3a30eca3, 0xbe21b4aa,
+                    0x80000000, 0x3fc8841a, 0xb2a96650, 0xbe575444, 0x80000000,
+                    0x3fc83b34, 0x2376c0cb, 0xbe2a74c7, 0x80000000, 0x3fc7f26b,
+                    0xd8a0b653, 0xbe5181b6, 0x00000000, 0x3fc7a9bf, 0x32257882,
+                    0xbe4a78b4, 0x00000000, 0x3fc7612f, 0x1eee8bd9, 0xbe1bfe9d,
+                    0x80000000, 0x3fc718bb, 0x0c603cc4, 0x3e36fdc9, 0x80000000,
+                    0x3fc6d064, 0x3728b8cf, 0xbe1e542e, 0x80000000, 0x3fc68829,
+                    0xc79a4067, 0x3e5c380f, 0x00000000, 0x3fc6400b, 0xf69eac69,
+                    0x3e550a84, 0x80000000, 0x3fc5f808, 0xb7a780a4, 0x3e5d9224,
+                    0x80000000, 0x3fc5b022, 0xad9dfb1e, 0xbe55242f, 0x00000000,
+                    0x3fc56858, 0x659b18be, 0xbe4bfda3, 0x80000000, 0x3fc520a9,
+                    0x66ee3631, 0xbe57d769, 0x80000000, 0x3fc4d916, 0x1ec62819,
+                    0x3e2427f7, 0x80000000, 0x3fc4919f, 0xdec25369, 0xbe435431,
+                    0x00000000, 0x3fc44a44, 0xa8acfc4b, 0xbe3c62e8, 0x00000000,
+                    0x3fc40304, 0xcf1d3eab, 0xbdfba29f, 0x80000000, 0x3fc3bbdf,
+                    0x79aba3ea, 0xbdf1b7c8, 0x80000000, 0x3fc374d6, 0xb8d186da,
+                    0xbe5130cf, 0x80000000, 0x3fc32de8, 0x9d74f152, 0x3e2285b6,
+                    0x00000000, 0x3fc2e716, 0x50ae7ca9, 0xbe503920, 0x80000000,
+                    0x3fc2a05e, 0x6caed92e, 0xbe533924, 0x00000000, 0x3fc259c2,
+                    0x9cb5034e, 0xbe510e31, 0x80000000, 0x3fc21340, 0x12c4d378,
+                    0xbe540b43, 0x80000000, 0x3fc1ccd9, 0xcc418706, 0x3e59887a,
+                    0x00000000, 0x3fc1868e, 0x921f4106, 0xbe528e67, 0x80000000,
+                    0x3fc1405c, 0x3969441e, 0x3e5d8051, 0x00000000, 0x3fc0fa46,
+                    0xd941ef5b, 0x3e5f9079, 0x80000000, 0x3fc0b44a, 0x5a3e81b2,
+                    0xbe567691, 0x00000000, 0x3fc06e69, 0x9d66afe7, 0xbe4d43fb,
+                    0x00000000, 0x3fc028a2, 0x0a92a162, 0xbe52f394, 0x00000000,
+                    0x3fbfc5ea, 0x209897e5, 0x3e529e37, 0x00000000, 0x3fbf3ac5,
+                    0x8458bd7b, 0x3e582831, 0x00000000, 0x3fbeafd5, 0xb8d8b4b8,
+                    0xbe486b4a, 0x00000000, 0x3fbe2518, 0xe0a3b7b6, 0x3e5bafd2,
+                    0x00000000, 0x3fbd9a90, 0x2bf2710e, 0x3e383b2b, 0x00000000,
+                    0x3fbd103c, 0x73eb6ab7, 0xbe56d78d, 0x00000000, 0x3fbc861b,
+                    0x32ceaff5, 0xbe32dc5a, 0x00000000, 0x3fbbfc2e, 0xbee04cb7,
+                    0xbe4a71a4, 0x00000000, 0x3fbb7274, 0x35ae9577, 0x3e38142f,
+                    0x00000000, 0x3fbae8ee, 0xcbaddab4, 0xbe5490f0, 0x00000000,
+                    0x3fba5f9a, 0x95ce1114, 0x3e597c71, 0x00000000, 0x3fb9d67a,
+                    0x6d7c0f78, 0x3e3abc2d, 0x00000000, 0x3fb94d8d, 0x2841a782,
+                    0xbe566cbc, 0x00000000, 0x3fb8c4d2, 0x6ed429c6, 0xbe3cfff9,
+                    0x00000000, 0x3fb83c4a, 0xe4a49fbb, 0xbe552964, 0x00000000,
+                    0x3fb7b3f4, 0x2193d81e, 0xbe42fa72, 0x00000000, 0x3fb72bd0,
+                    0xdd70c122, 0x3e527a8c, 0x00000000, 0x3fb6a3df, 0x03108a54,
+                    0xbe450393, 0x00000000, 0x3fb61c1f, 0x30ff7954, 0x3e565840,
+                    0x00000000, 0x3fb59492, 0xdedd460c, 0xbe5422b5, 0x00000000,
+                    0x3fb50d36, 0x950f9f45, 0xbe5313f6, 0x00000000, 0x3fb4860b,
+                    0x582cdcb1, 0x3e506d39, 0x00000000, 0x3fb3ff12, 0x7216d3a6,
+                    0x3e4aa719, 0x00000000, 0x3fb3784a, 0x57a423fd, 0x3e5a9b9f,
+                    0x00000000, 0x3fb2f1b4, 0x7a138b41, 0xbe50b418, 0x00000000,
+                    0x3fb26b4e, 0x2fbfd7ea, 0x3e23a53e, 0x00000000, 0x3fb1e519,
+                    0x18913ccb, 0x3e465fc1, 0x00000000, 0x3fb15f15, 0x7ea24e21,
+                    0x3e042843, 0x00000000, 0x3fb0d941, 0x7c6d9c77, 0x3e59f61e,
+                    0x00000000, 0x3fb0539e, 0x114efd44, 0x3e4ccab7, 0x00000000,
+                    0x3faf9c56, 0x1777f657, 0x3e552f65, 0x00000000, 0x3fae91d2,
+                    0xc317b86a, 0xbe5a61e0, 0x00000000, 0x3fad87ac, 0xb7664efb,
+                    0xbe41f64e, 0x00000000, 0x3fac7de6, 0x5d3d03a9, 0x3e0807a0,
+                    0x00000000, 0x3fab7480, 0x743c38eb, 0xbe3726e1, 0x00000000,
+                    0x3faa6b78, 0x06a253f1, 0x3e5ad636, 0x00000000, 0x3fa962d0,
+                    0xa35f541b, 0x3e5a187a, 0x00000000, 0x3fa85a88, 0x4b86e446,
+                    0xbe508150, 0x00000000, 0x3fa7529c, 0x2589cacf, 0x3e52938a,
+                    0x00000000, 0x3fa64b10, 0xaf6b11f2, 0xbe3454cd, 0x00000000,
+                    0x3fa543e2, 0x97506fef, 0xbe5fdec5, 0x00000000, 0x3fa43d10,
+                    0xe75f7dd9, 0xbe388dd3, 0x00000000, 0x3fa3369c, 0xa4139632,
+                    0xbdea5177, 0x00000000, 0x3fa23086, 0x352d6f1e, 0xbe565ad6,
+                    0x00000000, 0x3fa12acc, 0x77449eb7, 0xbe50d5c7, 0x00000000,
+                    0x3fa0256e, 0x7478da78, 0x3e404724, 0x00000000, 0x3f9e40dc,
+                    0xf59cef7f, 0xbe539d0a, 0x00000000, 0x3f9c3790, 0x1511d43c,
+                    0x3e53c2c8, 0x00000000, 0x3f9a2f00, 0x9b8bff3c, 0xbe43b3e1,
+                    0x00000000, 0x3f982724, 0xad1e22a5, 0x3e46f0bd, 0x00000000,
+                    0x3f962000, 0x130d9356, 0x3e475ba0, 0x00000000, 0x3f941994,
+                    0x8f86f883, 0xbe513d0b, 0x00000000, 0x3f9213dc, 0x914d0dc8,
+                    0xbe534335, 0x00000000, 0x3f900ed8, 0x2d73e5e7, 0xbe22ba75,
+                    0x00000000, 0x3f8c1510, 0xc5b7d70e, 0x3e599c5d, 0x00000000,
+                    0x3f880de0, 0x8a27857e, 0xbe3d28c8, 0x00000000, 0x3f840810,
+                    0xda767328, 0x3e531b3d, 0x00000000, 0x3f8003b0, 0x77bacaf3,
+                    0xbe5f04e3, 0x00000000, 0x3f780150, 0xdf4b0720, 0x3e5a8bff,
+                    0x00000000, 0x3f6ffc40, 0x34c48e71, 0xbe3fcd99, 0x00000000,
+                    0x3f5ff6c0, 0x1ad218af, 0xbe4c78a7, 0x00000000, 0x00000000,
+                    0x00000000, 0x80000000
+    };
+
+    private static int[] logTwoPow = {
+                    0xfefa39ef, 0x3fe62e42, 0xfefa39ef, 0xbfe62e42
+    };
+
+    public void powIntrinsic(Register dest, Register value1, Register value2, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant highSigMaskPtr = new ArrayDataPointerConstant(highSigMask, 16);
+        ArrayDataPointerConstant logTwoEPtr = new ArrayDataPointerConstant(logTwoE, 16);
+        ArrayDataPointerConstant highmaskYPtr = new ArrayDataPointerConstant(highmaskY, 16);
+        ArrayDataPointerConstant tExpPtr = new ArrayDataPointerConstant(tExp, 16);
+        ArrayDataPointerConstant eCoeffPtr = new ArrayDataPointerConstant(eCoeff, 16);
+        ArrayDataPointerConstant coeffHPtr = new ArrayDataPointerConstant(coeffH, 16);
+        ArrayDataPointerConstant highmaskLogXPtr = new ArrayDataPointerConstant(highmaskLogX, 16);
+        ArrayDataPointerConstant halfmaskPtr = new ArrayDataPointerConstant(halfmask, 8);
+        ArrayDataPointerConstant coeffPowPtr = new ArrayDataPointerConstant(coeffPow, 16);
+        ArrayDataPointerConstant lTblPowPtr = new ArrayDataPointerConstant(lTblPow, 16);
+        ArrayDataPointerConstant logTwoPowPtr = new ArrayDataPointerConstant(logTwoPow, 8);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb3 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb7 = new Label();
+        Label bb8 = new Label();
+        Label bb9 = new Label();
+        Label bb10 = new Label();
+        Label bb11 = new Label();
+        Label bb12 = new Label();
+        Label bb13 = new Label();
+        Label bb14 = new Label();
+        Label bb15 = new Label();
+        Label bb16 = new Label();
+        Label bb18 = new Label();
+        Label bb19 = new Label();
+        Label bb20 = new Label();
+        Label bb21 = new Label();
+        Label bb22 = new Label();
+        Label bb23 = new Label();
+        Label bb24 = new Label();
+        Label bb25 = new Label();
+        Label bb26 = new Label();
+        Label bb27 = new Label();
+        Label bb28 = new Label();
+        Label bb29 = new Label();
+        Label bb30 = new Label();
+        Label bb31 = new Label();
+        Label bb32 = new Label();
+        Label bb33 = new Label();
+        Label bb34 = new Label();
+        Label bb35 = new Label();
+        Label bb36 = new Label();
+        Label bb37 = new Label();
+        Label bb38 = new Label();
+        Label bb39 = new Label();
+        Label bb40 = new Label();
+        Label bb41 = new Label();
+        Label bb42 = new Label();
+        Label bb43 = new Label();
+        Label bb44 = new Label();
+        Label bb45 = new Label();
+        Label bb46 = new Label();
+        Label bb47 = new Label();
+        Label bb48 = new Label();
+        Label bb49 = new Label();
+        Label bb50 = new Label();
+        Label bb51 = new Label();
+        Label bb53 = new Label();
+        Label bb54 = new Label();
+        Label bb55 = new Label();
+        Label bb56 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+        Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD);
+        Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD);
+        Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD);
+        Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+        Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE);
+        Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE);
+        Register temp10 = asRegister(xmm10Temp, AMD64Kind.DOUBLE);
+
+        setCrb(crb);
+        masm.movdqu(temp10, value1);
+        masm.movsd(temp8, value2);
+        if (dest.encoding != value1.encoding) {
+            masm.movdqu(dest, value1);
+        }
+
+        masm.movq(temp9, externalAddress(logTwoEPtr));       // 0x00000000,
+                                                             // 0x3ff72000
+        masm.pextrw(gpr1, dest, 3);
+        masm.xorpd(temp2, temp2);
+        masm.movq(gpr2, 0x3ff0000000000000L);
+        masm.movdq(temp2, gpr2);
+        masm.movl(gpr5, 1069088768);
+        masm.movdq(temp7, gpr5);
+        masm.xorpd(temp1, temp1);
+        masm.movq(gpr6, 0x77f0000000000000L);
+        masm.movdq(temp1, gpr6);
+        masm.movdqu(temp3, dest);
+        masm.movl(gpr4, 32752);
+        masm.andl(gpr4, gpr1);
+        masm.subl(gpr4, 16368);
+        masm.movl(gpr3, gpr4);
+        masm.sarl(gpr4, 31);
+        masm.addl(gpr3, gpr4);
+        masm.xorl(gpr3, gpr4);
+        masm.por(dest, temp2);
+        masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000,
+                                                             // 0xfffff800,
+                                                             // 0x00000000,
+                                                             // 0xfffff800
+        masm.psrlq(dest, 27);
+        masm.psrld(dest, 2);
+        masm.addl(gpr3, 16);
+        masm.bsrl(gpr3, gpr3);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp3, 12);
+        masm.movl(gpr7, 8192);
+        masm.movdq(temp4, gpr7);
+        masm.psrlq(temp3, 12);
+        masm.subl(gpr1, 16);
+        masm.cmpl(gpr1, 32736);
+        masm.jcc(ConditionFlag.AboveEqual, bb0);
+
+        masm.movl(gpr5, 0);
+
+        masm.bind(bb1);
+        masm.mulss(dest, temp7);
+        masm.movl(gpr4, -1);
+        masm.subl(gpr3, 4);
+        masm.shll(gpr4);
+        masm.shlq(gpr4, 32);
+        masm.movdq(temp5, gpr4);
+        masm.por(temp3, temp1);
+        masm.subl(gpr1, 16351);
+        masm.cmpl(gpr1, 1);
+        masm.jcc(ConditionFlag.BelowEqual, bb2);
+
+        masm.paddd(dest, temp4);
+        masm.pand(temp5, temp3);
+        masm.movdl(gpr4, dest);
+        masm.psllq(dest, 29);
+
+        masm.bind(bb3);
+        masm.subsd(temp3, temp5);
+        masm.pand(dest, temp6);
+        masm.subl(gpr1, 1);
+        masm.sarl(gpr1, 4);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulpd(temp5, dest);
+
+        masm.bind(bb4);
+        masm.mulsd(temp3, dest);
+        masm.leaq(gpr8, externalAddress(coeffPowPtr));
+        masm.movdqu(temp1, new AMD64Address(gpr8, 0));       // 0x6dc96112,
+                                                             // 0xbf836578,
+                                                             // 0xee241472,
+                                                             // 0xbf9b0301
+        masm.movdqu(temp4, new AMD64Address(gpr8, 16));      // 0x9f95985a,
+                                                             // 0xbfb528db,
+                                                             // 0xb3841d2a,
+                                                             // 0xbfd619b6
+        masm.movdqu(temp6, new AMD64Address(gpr8, 32));      // 0x518775e3,
+                                                             // 0x3f9004f2,
+                                                             // 0xac8349bb,
+                                                             // 0x3fa76c9b
+        masm.movdqu(dest, new AMD64Address(gpr8, 48));       // 0x486ececc,
+                                                             // 0x3fc4635e,
+                                                             // 0x161bb241,
+                                                             // 0xbf5dabe1
+        masm.subsd(temp5, temp9);
+        masm.movl(gpr3, gpr1);
+        masm.sarl(gpr1, 31);
+        masm.addl(gpr3, gpr1);
+        masm.xorl(gpr1, gpr3);
+        masm.addl(gpr1, 1);
+        masm.bsrl(gpr1, gpr1);
+        masm.unpcklpd(temp5, temp3);
+        masm.addsd(temp3, temp5);
+        masm.leaq(gpr7, externalAddress(lTblPowPtr));
+        masm.andl(gpr4, 16760832);
+        masm.shrl(gpr4, 10);
+        masm.addpd(temp5, new AMD64Address(gpr7, gpr4, Scale.Times1, -3648));
+        masm.pshufd(temp2, temp3, 0x44);
+        masm.mulsd(temp3, temp3);
+        masm.mulpd(temp1, temp2);
+        masm.mulpd(temp4, temp2);
+        masm.addsd(temp5, temp7);
+        masm.mulsd(temp2, temp3);
+        masm.addpd(temp6, temp1);
+        masm.mulsd(temp3, temp3);
+        masm.addpd(dest, temp4);
+        masm.movdqu(temp1, temp8);
+        masm.pextrw(gpr3, temp8, 3);
+        masm.pshufd(temp7, temp5, 0xEE);
+        masm.movq(temp4, externalAddress(highmaskYPtr));     // 0x00000000,
+                                                             // 0xfffffff8
+        masm.mulpd(temp6, temp2);
+        masm.pshufd(temp3, temp3, 0x44);
+        masm.mulpd(dest, temp2);
+        masm.shll(gpr1, 4);
+        masm.subl(gpr1, 15872);
+        masm.andl(gpr3, 32752);
+        masm.addl(gpr1, gpr3);
+        masm.mulpd(temp3, temp6);
+        masm.cmpl(gpr1, 624);
+        masm.jcc(ConditionFlag.AboveEqual, bb5);
+
+        masm.xorpd(temp6, temp6);
+        masm.movl(gpr4, 17080);
+        masm.pinsrw(temp6, gpr4, 3);
+        masm.movdqu(temp2, temp1);
+        masm.pand(temp4, temp1);
+        masm.subsd(temp1, temp4);
+        masm.mulsd(temp4, temp5);
+        masm.addsd(dest, temp7);
+        masm.mulsd(temp1, temp5);
+        masm.movdqu(temp7, temp6);
+        masm.addsd(temp6, temp4);
+        masm.leaq(gpr7, externalAddress(tExpPtr));
+        masm.addpd(temp3, dest);
+        masm.movdl(gpr4, temp6);
+        masm.movl(gpr3, gpr4);
+        masm.andl(gpr4, 255);
+        masm.addl(gpr4, gpr4);
+        masm.movdqu(temp5, new AMD64Address(gpr7, gpr4, Scale.Times8, 0));
+        masm.subsd(temp6, temp7);
+        masm.pshufd(dest, temp3, 0xEE);
+        masm.subsd(temp4, temp6);
+        masm.addsd(dest, temp3);
+        masm.addsd(temp4, temp1);
+        masm.mulsd(temp2, dest);
+        masm.leaq(gpr8, externalAddress(eCoeffPtr));
+        masm.movdqu(temp7, new AMD64Address(gpr8, 0));       // 0xe78a6731,
+                                                             // 0x3f55d87f,
+                                                             // 0xd704a0c0,
+                                                             // 0x3fac6b08
+        masm.movdqu(temp3, new AMD64Address(gpr8, 16));      // 0x6fba4e77,
+                                                             // 0x3f83b2ab,
+                                                             // 0xff82c58f,
+                                                             // 0x3fcebfbd
+        masm.shll(gpr3, 12);
+        masm.xorl(gpr3, gpr5);
+        masm.andl(gpr3, -1048576);
+        masm.movdq(temp6, gpr3);
+        masm.addsd(temp2, temp4);
+        masm.movq(gpr2, 0x3fe62e42fefa39efL);
+        masm.movdq(temp1, gpr2);
+        masm.pshufd(dest, temp2, 0x44);
+        masm.pshufd(temp4, temp2, 0x44);
+        masm.mulsd(temp1, temp2);
+        masm.pshufd(temp6, temp6, 0x11);
+        masm.mulpd(dest, dest);
+        masm.mulpd(temp7, temp4);
+        masm.paddd(temp5, temp6);
+        masm.mulsd(temp1, temp5);
+        masm.pshufd(temp6, temp5, 0xEE);
+        masm.mulsd(dest, dest);
+        masm.addpd(temp3, temp7);
+        masm.addsd(temp1, temp6);
+        masm.mulpd(dest, temp3);
+        masm.pshufd(temp3, dest, 0xEE);
+        masm.mulsd(dest, temp5);
+        masm.mulsd(temp3, temp5);
+        masm.addsd(dest, temp1);
+        masm.addsd(dest, temp3);
+        masm.addsd(dest, temp5);
+        masm.jmp(bb56);
+
+        masm.bind(bb0);
+        masm.addl(gpr1, 16);
+        masm.movl(gpr4, 32752);
+        masm.andl(gpr4, gpr1);
+        masm.cmpl(gpr4, 32752);
+        masm.jcc(ConditionFlag.Equal, bb6);
+
+        masm.testl(gpr1, 32768);
+        masm.jcc(ConditionFlag.NotEqual, bb7);
+
+        masm.bind(bb8);
+        masm.movdqu(dest, temp10);
+        masm.movdqu(temp3, temp10);
+        masm.movdl(gpr4, temp3);
+        masm.psrlq(temp3, 32);
+        masm.movdl(gpr3, temp3);
+        masm.orl(gpr4, gpr3);
+        masm.cmpl(gpr4, 0);
+        masm.jcc(ConditionFlag.Equal, bb9);
+
+        masm.xorpd(temp3, temp3);
+        masm.movl(gpr1, 18416);
+        masm.pinsrw(temp3, gpr1, 3);
+        masm.mulsd(dest, temp3);
+        masm.xorpd(temp2, temp2);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.movdqu(temp3, dest);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.movl(gpr3, 18416);
+        masm.psrlq(dest, 27);
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp3, 12);
+        masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000,
+                                                             // 0xfffff800,
+                                                             // 0x00000000,
+                                                             // 0xfffff800
+        masm.psrlq(temp3, 12);
+        masm.mulss(dest, temp7);
+        masm.movl(gpr4, -1024);
+        masm.movdl(temp5, gpr4);
+        masm.por(temp3, temp1);
+        masm.paddd(dest, temp4);
+        masm.psllq(temp5, 32);
+        masm.movdl(gpr4, dest);
+        masm.psllq(dest, 29);
+        masm.pand(temp5, temp3);
+        masm.movl(gpr5, 0);
+        masm.pand(dest, temp6);
+        masm.subsd(temp3, temp5);
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, 18416);
+        masm.sarl(gpr1, 4);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulpd(temp5, dest);
+        masm.jmp(bb4);
+
+        masm.bind(bb10);
+        masm.movdqu(dest, temp10);
+        masm.movdqu(temp3, temp10);
+        masm.movdl(gpr4, temp3);
+        masm.psrlq(temp3, 32);
+        masm.movdl(gpr3, temp3);
+        masm.orl(gpr4, gpr3);
+        masm.cmpl(gpr4, 0);
+        masm.jcc(ConditionFlag.Equal, bb9);
+
+        masm.xorpd(temp3, temp3);
+        masm.movl(gpr1, 18416);
+        masm.pinsrw(temp3, gpr1, 3);
+        masm.mulsd(dest, temp3);
+        masm.xorpd(temp2, temp2);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.movdqu(temp3, dest);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.movl(gpr3, 18416);
+        masm.psrlq(dest, 27);
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp3, 12);
+        masm.movdqu(temp6, externalAddress(highSigMaskPtr)); // 0x00000000,
+                                                             // 0xfffff800,
+                                                             // 0x00000000,
+                                                             // 0xfffff800
+        masm.psrlq(temp3, 12);
+        masm.mulss(dest, temp7);
+        masm.movl(gpr4, -1024);
+        masm.movdl(temp5, gpr4);
+        masm.por(temp3, temp1);
+        masm.paddd(dest, temp4);
+        masm.psllq(temp5, 32);
+        masm.movdl(gpr4, dest);
+        masm.psllq(dest, 29);
+        masm.pand(temp5, temp3);
+        masm.movl(gpr5, Integer.MIN_VALUE);
+        masm.pand(dest, temp6);
+        masm.subsd(temp3, temp5);
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, 18416);
+        masm.sarl(gpr1, 4);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulpd(temp5, dest);
+        masm.jmp(bb4);
+
+        masm.bind(bb5);
+        masm.cmpl(gpr1, 0);
+        masm.jcc(ConditionFlag.Less, bb11);
+
+        masm.cmpl(gpr1, 752);
+        masm.jcc(ConditionFlag.AboveEqual, bb12);
+
+        masm.addsd(dest, temp7);
+        masm.movq(temp4, externalAddress(halfmaskPtr));      // 0xf8000000,
+                                                             // 0xffffffff
+        masm.addpd(temp3, dest);
+        masm.xorpd(temp6, temp6);
+        masm.movl(gpr1, 17080);
+        masm.pinsrw(temp6, gpr1, 3);
+        masm.pshufd(dest, temp3, 0xEE);
+        masm.addsd(dest, temp3);
+        masm.movdqu(temp3, temp5);
+        masm.addsd(temp5, dest);
+        masm.subsd(temp3, temp5);
+        masm.movdqu(temp7, temp5);
+        masm.pand(temp5, temp4);
+        masm.movdqu(temp2, temp1);
+        masm.pand(temp4, temp1);
+        masm.subsd(temp7, temp5);
+        masm.addsd(dest, temp3);
+        masm.subsd(temp1, temp4);
+        masm.mulsd(temp4, temp5);
+        masm.addsd(dest, temp7);
+        masm.mulsd(temp2, dest);
+        masm.movdqu(temp7, temp6);
+        masm.mulsd(temp1, temp5);
+        masm.addsd(temp6, temp4);
+        masm.movdl(gpr1, temp6);
+        masm.subsd(temp6, temp7);
+        masm.leaq(gpr7, externalAddress(tExpPtr));
+        masm.movl(gpr3, gpr1);
+        masm.andl(gpr1, 255);
+        masm.addl(gpr1, gpr1);
+        masm.movdqu(temp5, new AMD64Address(gpr7, gpr1, Scale.Times8, 0));
+        masm.addsd(temp2, temp1);
+        masm.leaq(gpr8, externalAddress(eCoeffPtr));
+        masm.movdqu(temp7, new AMD64Address(gpr8, 0));       // 0xe78a6731,
+                                                             // 0x3f55d87f,
+                                                             // 0xd704a0c0,
+                                                             // 0x3fac6b08
+        masm.movdqu(temp3, new AMD64Address(gpr8, 16));      // 0x6fba4e77,
+                                                             // 0x3f83b2ab,
+                                                             // 0xff82c58f,
+                                                             // 0x3fcebfbd
+        masm.subsd(temp4, temp6);
+        masm.pextrw(gpr4, temp6, 3);
+        masm.addsd(temp2, temp4);
+        masm.sarl(gpr3, 8);
+        masm.movl(gpr1, gpr3);
+        masm.sarl(gpr3, 1);
+        masm.subl(gpr1, gpr3);
+        masm.shll(gpr3, 20);
+        masm.xorl(gpr3, gpr5);
+        masm.movdl(temp6, gpr3);
+        masm.movq(temp1, new AMD64Address(gpr8, 32));        // 0xfefa39ef,
+                                                             // 0x3fe62e42
+        masm.andl(gpr4, 32767);
+        masm.cmpl(gpr4, 16529);
+        masm.jcc(ConditionFlag.Above, bb12);
+
+        masm.pshufd(dest, temp2, 0x44);
+        masm.pshufd(temp4, temp2, 0x44);
+        masm.mulpd(dest, dest);
+        masm.mulpd(temp7, temp4);
+        masm.pshufd(temp6, temp6, 0x11);
+        masm.mulsd(temp1, temp2);
+        masm.mulsd(dest, dest);
+        masm.paddd(temp5, temp6);
+        masm.addpd(temp3, temp7);
+        masm.mulsd(temp1, temp5);
+        masm.pshufd(temp6, temp5, 0xEE);
+        masm.mulpd(dest, temp3);
+        masm.addsd(temp1, temp6);
+        masm.pshufd(temp3, dest, 0xEE);
+        masm.mulsd(dest, temp5);
+        masm.mulsd(temp3, temp5);
+        masm.shll(gpr1, 4);
+        masm.xorpd(temp4, temp4);
+        masm.addl(gpr1, 16368);
+        masm.pinsrw(temp4, gpr1, 3);
+        masm.addsd(dest, temp1);
+        masm.addsd(dest, temp3);
+        masm.movdqu(temp1, dest);
+        masm.addsd(dest, temp5);
+        masm.mulsd(dest, temp4);
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32752);
+        masm.jcc(ConditionFlag.Equal, bb13);
+
+        masm.cmpl(gpr1, 32752);
+        masm.jcc(ConditionFlag.Equal, bb14);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb6);
+        masm.movdqu(temp1, temp8);
+        masm.movdqu(dest, temp10);
+        masm.movdqu(temp2, dest);
+        masm.movdl(gpr1, temp2);
+        masm.psrlq(temp2, 20);
+        masm.movdl(gpr4, temp2);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb15);
+
+        masm.movdl(gpr1, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr4, temp1);
+        masm.movl(gpr3, gpr4);
+        masm.addl(gpr4, gpr4);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb16);
+
+        masm.addsd(dest, dest);
+        masm.jmp(bb56);
+
+        masm.bind(bb16);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb18);
+        masm.addpd(dest, temp8);
+        masm.jmp(bb56);
+
+        masm.bind(bb15);
+        masm.movdl(gpr1, temp1);
+        masm.movdqu(temp2, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr4, temp1);
+        masm.movl(gpr3, gpr4);
+        masm.addl(gpr4, gpr4);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb19);
+
+        masm.pextrw(gpr1, temp2, 3);
+        masm.andl(gpr1, 32752);
+        masm.cmpl(gpr1, 32752);
+        masm.jcc(ConditionFlag.NotEqual, bb20);
+
+        masm.movdl(gpr1, temp2);
+        masm.psrlq(temp2, 20);
+        masm.movdl(gpr4, temp2);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.NotEqual, bb18);
+
+        masm.bind(bb20);
+        masm.pextrw(gpr1, dest, 3);
+        masm.testl(gpr1, 32768);
+        masm.jcc(ConditionFlag.NotEqual, bb21);
+
+        masm.testl(gpr3, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.NotZero, bb22);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb23);
+        masm.movdl(gpr1, temp8);
+        masm.testl(gpr1, 1);
+        masm.jcc(ConditionFlag.NotEqual, bb24);
+
+        masm.testl(gpr1, 2);
+        masm.jcc(ConditionFlag.NotEqual, bb25);
+
+        masm.jmp(bb24);
+
+        masm.bind(bb21);
+        masm.shrl(gpr3, 20);
+        masm.andl(gpr3, 2047);
+        masm.cmpl(gpr3, 1075);
+        masm.jcc(ConditionFlag.Above, bb24);
+
+        masm.jcc(ConditionFlag.Equal, bb26);
+
+        masm.cmpl(gpr3, 1074);
+        masm.jcc(ConditionFlag.Above, bb23);
+
+        masm.cmpl(gpr3, 1023);
+        masm.jcc(ConditionFlag.Below, bb24);
+
+        masm.movdqu(temp1, temp8);
+        masm.movl(gpr1, 17208);
+        masm.xorpd(temp3, temp3);
+        masm.pinsrw(temp3, gpr1, 3);
+        masm.movdqu(temp4, temp3);
+        masm.addsd(temp3, temp1);
+        masm.subsd(temp4, temp3);
+        masm.addsd(temp1, temp4);
+        masm.pextrw(gpr1, temp1, 3);
+        masm.andl(gpr1, 32752);
+        masm.jcc(ConditionFlag.NotEqual, bb24);
+
+        masm.movdl(gpr1, temp3);
+        masm.andl(gpr1, 1);
+        masm.jcc(ConditionFlag.Equal, bb24);
+
+        masm.bind(bb25);
+        masm.pextrw(gpr1, temp8, 3);
+        masm.andl(gpr1, 32768);
+        masm.jcc(ConditionFlag.NotEqual, bb27);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb27);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32768);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb24);
+        masm.pextrw(gpr1, temp8, 3);
+        masm.andl(gpr1, 32768);
+        masm.jcc(ConditionFlag.NotEqual, bb22);
+
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32752);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb26);
+        masm.movdl(gpr1, temp8);
+        masm.andl(gpr1, 1);
+        masm.jcc(ConditionFlag.Equal, bb24);
+
+        masm.jmp(bb25);
+
+        masm.bind(bb28);
+        masm.movdl(gpr1, temp1);
+        masm.psrlq(temp1, 20);
+        masm.movdl(gpr4, temp1);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb29);
+
+        masm.addsd(dest, temp8);
+        masm.jmp(bb56);
+
+        masm.bind(bb29);
+        masm.movdqu(dest, temp10);
+        masm.pextrw(gpr1, dest, 3);
+        masm.cmpl(gpr1, 49136);
+        masm.jcc(ConditionFlag.NotEqual, bb30);
+
+        masm.movdl(gpr3, dest);
+        masm.psrlq(dest, 20);
+        masm.movdl(gpr4, dest);
+        masm.orl(gpr3, gpr4);
+        masm.jcc(ConditionFlag.NotEqual, bb30);
+
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32760);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb30);
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, 16368);
+        masm.pextrw(gpr4, temp8, 3);
+        masm.xorpd(dest, dest);
+        masm.xorl(gpr1, gpr4);
+        masm.andl(gpr1, 32768);
+        masm.jcc(ConditionFlag.Equal, bb31);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb31);
+        masm.movl(gpr3, 32752);
+        masm.pinsrw(dest, gpr3, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb32);
+        masm.movdl(gpr1, temp1);
+        masm.cmpl(gpr4, 17184);
+        masm.jcc(ConditionFlag.Above, bb33);
+
+        masm.testl(gpr1, 1);
+        masm.jcc(ConditionFlag.NotEqual, bb34);
+
+        masm.testl(gpr1, 2);
+        masm.jcc(ConditionFlag.Equal, bb35);
+
+        masm.jmp(bb36);
+
+        masm.bind(bb33);
+        masm.testl(gpr1, 1);
+        masm.jcc(ConditionFlag.Equal, bb35);
+
+        masm.jmp(bb36);
+
+        masm.bind(bb7);
+        masm.movdqu(temp2, temp10);
+        masm.movdl(gpr1, temp2);
+        masm.psrlq(temp2, 31);
+        masm.movdl(gpr3, temp2);
+        masm.orl(gpr1, gpr3);
+        masm.jcc(ConditionFlag.Equal, bb9);
+
+        masm.pextrw(gpr4, temp8, 3);
+        masm.movdl(gpr1, temp8);
+        masm.movdqu(temp2, temp8);
+        masm.psrlq(temp2, 32);
+        masm.movdl(gpr3, temp2);
+        masm.addl(gpr3, gpr3);
+        masm.orl(gpr3, gpr1);
+        masm.jcc(ConditionFlag.Equal, bb37);
+
+        masm.andl(gpr4, 32752);
+        masm.cmpl(gpr4, 32752);
+        masm.jcc(ConditionFlag.Equal, bb28);
+
+        masm.cmpl(gpr4, 17200);
+        masm.jcc(ConditionFlag.Above, bb35);
+
+        masm.cmpl(gpr4, 17184);
+        masm.jcc(ConditionFlag.AboveEqual, bb32);
+
+        masm.cmpl(gpr4, 16368);
+        masm.jcc(ConditionFlag.Below, bb34);
+
+        masm.movl(gpr1, 17208);
+        masm.xorpd(temp2, temp2);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.movdqu(temp4, temp2);
+        masm.addsd(temp2, temp1);
+        masm.subsd(temp4, temp2);
+        masm.addsd(temp1, temp4);
+        masm.pextrw(gpr1, temp1, 3);
+        masm.andl(gpr1, 32767);
+        masm.jcc(ConditionFlag.NotEqual, bb34);
+
+        masm.movdl(gpr1, temp2);
+        masm.andl(gpr1, 1);
+        masm.jcc(ConditionFlag.Equal, bb35);
+
+        masm.bind(bb36);
+        masm.xorpd(temp1, temp1);
+        masm.movl(gpr4, 30704);
+        masm.pinsrw(temp1, gpr4, 3);
+        masm.pextrw(gpr1, temp10, 3);
+        masm.movl(gpr4, 8192);
+        masm.movdl(temp4, gpr4);
+        masm.andl(gpr1, 32767);
+        masm.subl(gpr1, 16);
+        masm.jcc(ConditionFlag.Less, bb10);
+
+        masm.movl(gpr4, gpr1);
+        masm.andl(gpr4, 32752);
+        masm.subl(gpr4, 16368);
+        masm.movl(gpr3, gpr4);
+        masm.sarl(gpr4, 31);
+        masm.addl(gpr3, gpr4);
+        masm.xorl(gpr3, gpr4);
+        masm.addl(gpr3, 16);
+        masm.bsrl(gpr3, gpr3);
+        masm.movl(gpr5, Integer.MIN_VALUE);
+        masm.jmp(bb1);
+
+        masm.bind(bb34);
+        masm.xorpd(temp1, temp1);
+        masm.movl(gpr1, 32752);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.xorpd(dest, dest);
+        masm.mulsd(dest, temp1);
+        masm.jmp(bb56);
+
+        masm.bind(bb35);
+        masm.xorpd(temp1, temp1);
+        masm.movl(gpr4, 30704);
+        masm.pinsrw(temp1, gpr4, 3);
+        masm.pextrw(gpr1, temp10, 3);
+        masm.movl(gpr4, 8192);
+        masm.movdl(temp4, gpr4);
+        masm.andl(gpr1, 32767);
+        masm.subl(gpr1, 16);
+        masm.jcc(ConditionFlag.Less, bb8);
+
+        masm.movl(gpr4, gpr1);
+        masm.andl(gpr4, 32752);
+        masm.subl(gpr4, 16368);
+        masm.movl(gpr3, gpr4);
+        masm.sarl(gpr4, 31);
+        masm.addl(gpr3, gpr4);
+        masm.xorl(gpr3, gpr4);
+        masm.addl(gpr3, 16);
+        masm.bsrl(gpr3, gpr3);
+        masm.movl(gpr5, 0);
+        masm.jmp(bb1);
+
+        masm.bind(bb19);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb22);
+        masm.xorpd(dest, dest);
+        masm.jmp(bb56);
+
+        masm.bind(bb11);
+        masm.addl(gpr1, 384);
+        masm.cmpl(gpr1, 0);
+        masm.jcc(ConditionFlag.Less, bb38);
+
+        masm.mulsd(temp5, temp1);
+        masm.addsd(dest, temp7);
+        masm.shrl(gpr5, 31);
+        masm.addpd(temp3, dest);
+        masm.pshufd(dest, temp3, 0xEE);
+        masm.addsd(temp3, dest);
+        masm.leaq(gpr7, externalAddress(logTwoPowPtr));      // 0xfefa39ef,
+                                                             // 0x3fe62e42,
+                                                             // 0xfefa39ef,
+                                                             // 0xbfe62e42
+        masm.movq(temp4, new AMD64Address(gpr7, gpr5, Scale.Times8, 0));
+        masm.mulsd(temp1, temp3);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 16368);
+        masm.shll(gpr5, 15);
+        masm.orl(gpr1, gpr5);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.addsd(temp5, temp1);
+        masm.mulsd(temp5, temp4);
+        masm.addsd(dest, temp5);
+        masm.jmp(bb56);
+
+        masm.bind(bb38);
+
+        masm.bind(bb37);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb39);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb9);
+        masm.movdqu(temp2, temp8);
+        masm.pextrw(gpr1, temp8, 3);
+        masm.andl(gpr1, 32752);
+        masm.cmpl(gpr1, 32752);
+        masm.jcc(ConditionFlag.NotEqual, bb40);
+
+        masm.movdl(gpr1, temp2);
+        masm.psrlq(temp2, 20);
+        masm.movdl(gpr4, temp2);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.NotEqual, bb18);
+
+        masm.bind(bb40);
+        masm.movdl(gpr1, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr4, temp1);
+        masm.movl(gpr3, gpr4);
+        masm.addl(gpr4, gpr4);
+        masm.orl(gpr1, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb39);
+
+        masm.shrl(gpr4, 21);
+        masm.cmpl(gpr4, 1075);
+        masm.jcc(ConditionFlag.Above, bb41);
+
+        masm.jcc(ConditionFlag.Equal, bb42);
+
+        masm.cmpl(gpr4, 1023);
+        masm.jcc(ConditionFlag.Below, bb41);
+
+        masm.movdqu(temp1, temp8);
+        masm.movl(gpr1, 17208);
+        masm.xorpd(temp3, temp3);
+        masm.pinsrw(temp3, gpr1, 3);
+        masm.movdqu(temp4, temp3);
+        masm.addsd(temp3, temp1);
+        masm.subsd(temp4, temp3);
+        masm.addsd(temp1, temp4);
+        masm.pextrw(gpr1, temp1, 3);
+        masm.andl(gpr1, 32752);
+        masm.jcc(ConditionFlag.NotEqual, bb41);
+
+        masm.movdl(gpr1, temp3);
+        masm.andl(gpr1, 1);
+        masm.jcc(ConditionFlag.Equal, bb41);
+
+        masm.bind(bb43);
+        masm.movdqu(dest, temp10);
+        masm.testl(gpr3, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.NotEqual, bb44);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb42);
+        masm.movdl(gpr1, temp8);
+        masm.testl(gpr1, 1);
+        masm.jcc(ConditionFlag.NotEqual, bb43);
+
+        masm.bind(bb41);
+        masm.testl(gpr3, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.Equal, bb22);
+
+        masm.xorpd(dest, dest);
+
+        masm.bind(bb44);
+        masm.movl(gpr1, 16368);
+        masm.xorpd(temp1, temp1);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.divsd(temp1, dest);
+        masm.movdqu(dest, temp1);
+        masm.jmp(bb56);
+
+        masm.bind(bb12);
+        masm.pextrw(gpr1, temp10, 3);
+        masm.pextrw(gpr4, temp8, 3);
+        masm.movl(gpr3, 32752);
+        masm.andl(gpr3, gpr4);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.Equal, bb45);
+
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, 16368);
+        masm.xorl(gpr4, gpr1);
+        masm.testl(gpr4, 32768);
+        masm.jcc(ConditionFlag.NotEqual, bb46);
+
+        masm.bind(bb47);
+        masm.movl(gpr1, 32736);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.shrl(gpr5, 16);
+        masm.orl(gpr1, gpr5);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.mulsd(dest, temp1);
+
+        masm.bind(bb14);
+        masm.jmp(bb56);
+
+        masm.bind(bb46);
+        masm.movl(gpr1, 16);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.mulsd(dest, dest);
+        masm.testl(gpr3, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.Equal, bb48);
+
+        masm.movq(gpr2, 0x8000000000000000L);
+        masm.movdq(temp2, gpr2);
+        masm.xorpd(dest, temp2);
+
+        masm.bind(bb48);
+        masm.jmp(bb56);
+
+        masm.bind(bb13);
+        masm.pextrw(gpr3, temp5, 3);
+        masm.pextrw(gpr4, temp4, 3);
+        masm.movl(gpr1, -1);
+        masm.andl(gpr3, 32752);
+        masm.subl(gpr3, 16368);
+        masm.andl(gpr4, 32752);
+        masm.addl(gpr4, gpr3);
+        masm.movl(gpr3, -31);
+        masm.sarl(gpr4, 4);
+        masm.subl(gpr3, gpr4);
+        masm.jcc(ConditionFlag.LessEqual, bb49);
+
+        masm.cmpl(gpr3, 20);
+        masm.jcc(ConditionFlag.Above, bb50);
+
+        masm.shll(gpr1);
+
+        masm.bind(bb49);
+        masm.movdl(dest, gpr1);
+        masm.psllq(dest, 32);
+        masm.pand(dest, temp5);
+        masm.subsd(temp5, dest);
+        masm.addsd(temp5, temp1);
+        masm.mulsd(dest, temp4);
+        masm.mulsd(temp5, temp4);
+        masm.addsd(dest, temp5);
+
+        masm.bind(bb50);
+        masm.jmp(bb48);
+
+        masm.bind(bb2);
+        masm.pextrw(gpr3, temp8, 3);
+        masm.movl(gpr4, Integer.MIN_VALUE);
+        masm.movdl(temp1, gpr4);
+        masm.xorpd(temp7, temp7);
+        masm.paddd(dest, temp4);
+        masm.movdl(gpr4, dest);
+        masm.psllq(dest, 29);
+        masm.paddq(temp1, temp3);
+        masm.pand(temp5, temp1);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 16560);
+        masm.jcc(ConditionFlag.Less, bb3);
+
+        masm.leaq(gpr7, externalAddress(lTblPowPtr));
+        masm.leaq(gpr8, externalAddress(coeffHPtr));
+        masm.movdqu(temp4, new AMD64Address(gpr8, 0));         // 0x00000000,
+                                                               // 0xbfd61a00,
+                                                               // 0x00000000,
+                                                               // 0xbf5dabe1
+        masm.pand(dest, temp6);
+        masm.subsd(temp3, temp5);
+        masm.addl(gpr1, 16351);
+        masm.shrl(gpr1, 4);
+        masm.subl(gpr1, 1022);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulpd(temp5, dest);
+        masm.mulsd(temp3, dest);
+        masm.subsd(temp5, temp9);
+        masm.pshufd(temp1, temp4, 0xE);
+        masm.pshufd(temp2, temp3, 0x44);
+        masm.unpcklpd(temp5, temp3);
+        masm.addsd(temp3, temp5);
+        masm.andl(gpr4, 16760832);
+        masm.shrl(gpr4, 10);
+        masm.addpd(temp7, new AMD64Address(gpr7, gpr4, Scale.Times1, -3648));
+        masm.movdqu(temp6, temp4);
+        masm.mulsd(temp4, temp5);
+        masm.movdqu(dest, temp1);
+        masm.mulsd(dest, temp5);
+        masm.mulsd(temp6, temp2);
+        masm.mulsd(temp1, temp2);
+        masm.movdqu(temp2, temp5);
+        masm.mulsd(temp4, temp5);
+        masm.addsd(temp5, dest);
+        masm.movdqu(dest, temp7);
+        masm.addsd(temp2, temp3);
+        masm.addsd(temp7, temp5);
+        masm.mulsd(temp6, temp2);
+        masm.subsd(dest, temp7);
+        masm.movdqu(temp2, temp7);
+        masm.addsd(temp7, temp4);
+        masm.addsd(dest, temp5);
+        masm.subsd(temp2, temp7);
+        masm.addsd(temp4, temp2);
+        masm.pshufd(temp2, temp5, 0xEE);
+        masm.movdqu(temp5, temp7);
+        masm.addsd(temp7, temp2);
+        masm.addsd(temp4, dest);
+        masm.leaq(gpr8, externalAddress(coeffPowPtr));
+        masm.movdqu(dest, new AMD64Address(gpr8, 0));        // 0x6dc96112,
+                                                             // 0xbf836578,
+                                                             // 0xee241472,
+                                                             // 0xbf9b0301
+        masm.subsd(temp5, temp7);
+        masm.addsd(temp6, temp4);
+        masm.movdqu(temp4, temp7);
+        masm.addsd(temp5, temp2);
+        masm.addsd(temp7, temp1);
+        masm.movdqu(temp2, new AMD64Address(gpr8, 64));      // 0x486ececc,
+                                                             // 0x3fc4635e,
+                                                             // 0x161bb241,
+                                                             // 0xbf5dabe1
+        masm.subsd(temp4, temp7);
+        masm.addsd(temp6, temp5);
+        masm.addsd(temp4, temp1);
+        masm.pshufd(temp5, temp7, 0xEE);
+        masm.movapd(temp1, temp7);
+        masm.addsd(temp7, temp5);
+        masm.subsd(temp1, temp7);
+        masm.addsd(temp1, temp5);
+        masm.movdqu(temp5, new AMD64Address(gpr8, 80));      // 0x9f95985a,
+                                                             // 0xbfb528db,
+                                                             // 0xf8b5787d,
+                                                             // 0x3ef2531e
+        masm.pshufd(temp3, temp3, 0x44);
+        masm.addsd(temp6, temp4);
+        masm.addsd(temp6, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr8, 32));      // 0x9f95985a,
+                                                             // 0xbfb528db,
+                                                             // 0xb3841d2a,
+                                                             // 0xbfd619b6
+        masm.mulpd(dest, temp3);
+        masm.mulpd(temp2, temp3);
+        masm.pshufd(temp4, temp3, 0x44);
+        masm.mulpd(temp3, temp3);
+        masm.addpd(dest, temp1);
+        masm.addpd(temp5, temp2);
+        masm.mulsd(temp4, temp3);
+        masm.movq(temp2, externalAddress(highmaskLogXPtr));  // 0xf8000000,
+                                                             // 0xffffffff
+        masm.mulpd(temp3, temp3);
+        masm.movdqu(temp1, temp8);
+        masm.pextrw(gpr3, temp8, 3);
+        masm.mulpd(dest, temp4);
+        masm.pextrw(gpr1, temp7, 3);
+        masm.mulpd(temp5, temp4);
+        masm.mulpd(dest, temp3);
+        masm.leaq(gpr8, externalAddress(highmaskYPtr));
+        masm.movq(temp4, new AMD64Address(gpr8, 8));         // 0x00000000,
+                                                             // 0xffffffff
+        masm.pand(temp2, temp7);
+        masm.addsd(temp5, temp6);
+        masm.subsd(temp7, temp2);
+        masm.addpd(temp5, dest);
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, 16368);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.Equal, bb45);
+
+        masm.addl(gpr3, gpr1);
+        masm.cmpl(gpr3, 16576);
+        masm.jcc(ConditionFlag.AboveEqual, bb51);
+
+        masm.pshufd(dest, temp5, 0xEE);
+        masm.pand(temp4, temp1);
+        masm.movdqu(temp3, temp1);
+        masm.addsd(temp5, dest);
+        masm.subsd(temp1, temp4);
+        masm.xorpd(temp6, temp6);
+        masm.movl(gpr4, 17080);
+        masm.pinsrw(temp6, gpr4, 3);
+        masm.addsd(temp7, temp5);
+        masm.mulsd(temp4, temp2);
+        masm.mulsd(temp1, temp2);
+        masm.movdqu(temp5, temp6);
+        masm.mulsd(temp3, temp7);
+        masm.addsd(temp6, temp4);
+        masm.addsd(temp1, temp3);
+        masm.leaq(gpr8, externalAddress(eCoeffPtr));
+        masm.movdqu(temp7, new AMD64Address(gpr8, 0));       // 0xe78a6731,
+                                                             // 0x3f55d87f,
+                                                             // 0xd704a0c0,
+                                                             // 0x3fac6b08
+        masm.movdl(gpr4, temp6);
+        masm.subsd(temp6, temp5);
+        masm.leaq(gpr7, externalAddress(tExpPtr));
+        masm.movl(gpr3, gpr4);
+        masm.andl(gpr4, 255);
+        masm.addl(gpr4, gpr4);
+        masm.movdqu(temp5, new AMD64Address(gpr7, gpr4, Scale.Times8, 0));
+        masm.movdqu(temp3, new AMD64Address(gpr8, 16));      // 0x6fba4e77,
+                                                             // 0x3f83b2ab,
+                                                             // 0xff82c58f,
+                                                             // 0x3fcebfbd
+        masm.movq(temp2, new AMD64Address(gpr8, 32));        // 0xfefa39ef,
+                                                             // 0x3fe62e42
+        masm.subsd(temp4, temp6);
+        masm.addsd(temp4, temp1);
+        masm.pextrw(gpr4, temp6, 3);
+        masm.shrl(gpr3, 8);
+        masm.movl(gpr1, gpr3);
+        masm.shrl(gpr3, 1);
+        masm.subl(gpr1, gpr3);
+        masm.shll(gpr3, 20);
+        masm.movdl(temp6, gpr3);
+        masm.pshufd(dest, temp4, 0x44);
+        masm.pshufd(temp1, temp4, 0x44);
+        masm.mulpd(dest, dest);
+        masm.mulpd(temp7, temp1);
+        masm.pshufd(temp6, temp6, 0x11);
+        masm.mulsd(temp2, temp4);
+        masm.andl(gpr4, 32767);
+        masm.cmpl(gpr4, 16529);
+        masm.jcc(ConditionFlag.Above, bb12);
+
+        masm.mulsd(dest, dest);
+        masm.paddd(temp5, temp6);
+        masm.addpd(temp3, temp7);
+        masm.mulsd(temp2, temp5);
+        masm.pshufd(temp6, temp5, 0xEE);
+        masm.mulpd(dest, temp3);
+        masm.addsd(temp2, temp6);
+        masm.pshufd(temp3, dest, 0xEE);
+        masm.addl(gpr1, 1023);
+        masm.shll(gpr1, 20);
+        masm.orl(gpr1, gpr5);
+        masm.movdl(temp4, gpr1);
+        masm.mulsd(dest, temp5);
+        masm.mulsd(temp3, temp5);
+        masm.addsd(dest, temp2);
+        masm.psllq(temp4, 32);
+        masm.addsd(dest, temp3);
+        masm.movdqu(temp1, dest);
+        masm.addsd(dest, temp5);
+        masm.mulsd(dest, temp4);
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32752);
+        masm.jcc(ConditionFlag.Equal, bb13);
+
+        masm.cmpl(gpr1, 32752);
+        masm.jcc(ConditionFlag.Equal, bb14);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb45);
+        masm.movdqu(dest, temp10);
+        masm.xorpd(temp2, temp2);
+        masm.movl(gpr1, 49136);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.addsd(temp2, dest);
+        masm.pextrw(gpr1, temp2, 3);
+        masm.cmpl(gpr1, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb53);
+
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32760);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb53);
+        masm.movdqu(temp1, temp8);
+        masm.movdl(gpr4, temp1);
+        masm.movdqu(temp3, temp1);
+        masm.psrlq(temp3, 20);
+        masm.movdl(gpr3, temp3);
+        masm.orl(gpr3, gpr4);
+        masm.jcc(ConditionFlag.Equal, bb54);
+
+        masm.addsd(temp1, temp1);
+        masm.movdqu(dest, temp1);
+        masm.jmp(bb56);
+
+        masm.bind(bb51);
+        masm.pextrw(gpr1, temp1, 3);
+        masm.pextrw(gpr3, temp2, 3);
+        masm.xorl(gpr1, gpr3);
+        masm.testl(gpr1, 32768);
+        masm.jcc(ConditionFlag.Equal, bb47);
+
+        masm.jmp(bb46);
+
+        masm.bind(bb54);
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32752);
+        masm.pextrw(gpr4, temp1, 3);
+        masm.xorpd(dest, dest);
+        masm.subl(gpr1, 16368);
+        masm.xorl(gpr1, gpr4);
+        masm.testl(gpr1, 32768);
+        masm.jcc(ConditionFlag.Equal, bb55);
+
+        masm.jmp(bb56);
+
+        masm.bind(bb55);
+        masm.movl(gpr4, 32752);
+        masm.pinsrw(dest, gpr4, 3);
+        masm.jmp(bb56);
+
+        masm.bind(bb56);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicUnaryOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicUnaryOp.java
new file mode 100644
index 0000000..51a6277
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathIntrinsicUnaryOp.java
@@ -0,0 +1,3843 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.ArrayDataPointerConstant;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public final class AMD64MathIntrinsicUnaryOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MathIntrinsicUnaryOp> TYPE = LIRInstructionClass.create(AMD64MathIntrinsicUnaryOp.class);
+
+    public enum UnaryIntrinsicOpcode {
+        LOG,
+        LOG10,
+        SIN,
+        COS,
+        TAN,
+        EXP
+    }
+
+    @Opcode private final UnaryIntrinsicOpcode opcode;
+    @Def protected Value result;
+    @Use protected Value input;
+    @Temp({REG, ILLEGAL}) protected Value xmm1Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm2Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm3Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm4Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm5Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm6Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm7Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm8Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm9Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value xmm10Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr1Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr2Temp = Value.ILLEGAL;
+    @Temp protected AllocatableValue rcxTemp;
+    @Temp({REG, ILLEGAL}) protected Value gpr4Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr5Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr6Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr7Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr8Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr9Temp = Value.ILLEGAL;
+    @Temp({REG, ILLEGAL}) protected Value gpr10Temp = Value.ILLEGAL;
+    @Temp({STACK, ILLEGAL}) protected Value stackTemp = Value.ILLEGAL;
+
+    CompilationResultBuilder internalCrb;
+
+    public AMD64MathIntrinsicUnaryOp(LIRGeneratorTool tool, UnaryIntrinsicOpcode opcode, Value result, Value input, Value stackTemp) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+        if (opcode == UnaryIntrinsicOpcode.LOG || opcode == UnaryIntrinsicOpcode.LOG10 ||
+                        opcode == UnaryIntrinsicOpcode.SIN || opcode == UnaryIntrinsicOpcode.COS ||
+                        opcode == UnaryIntrinsicOpcode.TAN || opcode == UnaryIntrinsicOpcode.EXP) {
+            this.gpr1Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr2Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.rcxTemp = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.QWORD));
+            this.gpr4Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            this.xmm1Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm2Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm3Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm4Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm5Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm6Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            this.xmm7Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+
+            if (opcode == UnaryIntrinsicOpcode.EXP) {
+                this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+                this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+                this.xmm10Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            }
+
+            if (opcode == UnaryIntrinsicOpcode.TAN) {
+                this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr9Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr10Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+            }
+
+            if (opcode == UnaryIntrinsicOpcode.SIN || opcode == UnaryIntrinsicOpcode.COS) {
+                this.gpr5Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr6Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr7Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr8Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr9Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.gpr10Temp = tool.newVariable(LIRKind.value(AMD64Kind.QWORD));
+                this.xmm8Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+                this.xmm9Temp = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+            }
+
+            this.stackTemp = stackTemp;
+        }
+    }
+
+    public AMD64MathIntrinsicUnaryOp(LIRGeneratorTool tool, UnaryIntrinsicOpcode opcode, Value result, Value input) {
+        this(tool, opcode, result, input, Value.ILLEGAL);
+    }
+
+    private void setCrb(CompilationResultBuilder crb) {
+        internalCrb = crb;
+    }
+
+    private AMD64Address externalAddress(ArrayDataPointerConstant curPtr) {
+        return (AMD64Address) internalCrb.recordDataReferenceInCode(curPtr);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        switch (opcode) {
+            case LOG:
+                logIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            case LOG10:
+                log10Intrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            case SIN:
+                sinIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            case COS:
+                cosIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            case TAN:
+                tanIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            case EXP:
+                expIntrinsic(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE), crb, masm);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static int[] logTwoTable = {
+                    0xfefa3800, 0x3fe62e42, 0x93c76730, 0x3d2ef357, 0xaa241800,
+                    0x3fe5ee82, 0x0cda46be, 0x3d220238, 0x5c364800, 0x3fe5af40,
+                    0xac10c9fb, 0x3d2dfa63, 0x26bb8c00, 0x3fe5707a, 0xff3303dd,
+                    0x3d09980b, 0x26867800, 0x3fe5322e, 0x5d257531, 0x3d05ccc4,
+                    0x835a5000, 0x3fe4f45a, 0x6d93b8fb, 0xbd2e6c51, 0x6f970c00,
+                    0x3fe4b6fd, 0xed4c541c, 0x3cef7115, 0x27e8a400, 0x3fe47a15,
+                    0xf94d60aa, 0xbd22cb6a, 0xf2f92400, 0x3fe43d9f, 0x481051f7,
+                    0xbcfd984f, 0x2125cc00, 0x3fe4019c, 0x30f0c74c, 0xbd26ce79,
+                    0x0c36c000, 0x3fe3c608, 0x7cfe13c2, 0xbd02b736, 0x17197800,
+                    0x3fe38ae2, 0xbb5569a4, 0xbd218b7a, 0xad9d8c00, 0x3fe35028,
+                    0x9527e6ac, 0x3d10b83f, 0x44340800, 0x3fe315da, 0xc5a0ed9c,
+                    0xbd274e93, 0x57b0e000, 0x3fe2dbf5, 0x07b9dc11, 0xbd17a6e5,
+                    0x6d0ec000, 0x3fe2a278, 0xe797882d, 0x3d206d2b, 0x1134dc00,
+                    0x3fe26962, 0x05226250, 0xbd0b61f1, 0xd8bebc00, 0x3fe230b0,
+                    0x6e48667b, 0x3d12fc06, 0x5fc61800, 0x3fe1f863, 0xc9fe81d3,
+                    0xbd2a7242, 0x49ae6000, 0x3fe1c078, 0xed70e667, 0x3cccacde,
+                    0x40f23c00, 0x3fe188ee, 0xf8ab4650, 0x3d14cc4e, 0xf6f29800,
+                    0x3fe151c3, 0xa293ae49, 0xbd2edd97, 0x23c75c00, 0x3fe11af8,
+                    0xbb9ddcb2, 0xbd258647, 0x8611cc00, 0x3fe0e489, 0x07801742,
+                    0x3d1c2998, 0xe2d05400, 0x3fe0ae76, 0x887e7e27, 0x3d1f486b,
+                    0x0533c400, 0x3fe078bf, 0x41edf5fd, 0x3d268122, 0xbe760400,
+                    0x3fe04360, 0xe79539e0, 0xbd04c45f, 0xe5b20800, 0x3fe00e5a,
+                    0xb1727b1c, 0xbd053ba3, 0xaf7a4800, 0x3fdfb358, 0x3c164935,
+                    0x3d0085fa, 0xee031800, 0x3fdf4aa7, 0x6f014a8b, 0x3d12cde5,
+                    0x56b41000, 0x3fdee2a1, 0x5a470251, 0x3d2f27f4, 0xc3ddb000,
+                    0x3fde7b42, 0x5372bd08, 0xbd246550, 0x1a272800, 0x3fde148a,
+                    0x07322938, 0xbd1326b2, 0x484c9800, 0x3fddae75, 0x60dc616a,
+                    0xbd1ea42d, 0x46def800, 0x3fdd4902, 0xe9a767a8, 0x3d235baf,
+                    0x18064800, 0x3fdce42f, 0x3ec7a6b0, 0xbd0797c3, 0xc7455800,
+                    0x3fdc7ff9, 0xc15249ae, 0xbd29b6dd, 0x693fa000, 0x3fdc1c60,
+                    0x7fe8e180, 0x3d2cec80, 0x1b80e000, 0x3fdbb961, 0xf40a666d,
+                    0x3d27d85b, 0x04462800, 0x3fdb56fa, 0x2d841995, 0x3d109525,
+                    0x5248d000, 0x3fdaf529, 0x52774458, 0xbd217cc5, 0x3c8ad800,
+                    0x3fda93ed, 0xbea77a5d, 0x3d1e36f2, 0x0224f800, 0x3fda3344,
+                    0x7f9d79f5, 0x3d23c645, 0xea15f000, 0x3fd9d32b, 0x10d0c0b0,
+                    0xbd26279e, 0x43135800, 0x3fd973a3, 0xa502d9f0, 0xbd152313,
+                    0x635bf800, 0x3fd914a8, 0x2ee6307d, 0xbd1766b5, 0xa88b3000,
+                    0x3fd8b639, 0xe5e70470, 0xbd205ae1, 0x776dc800, 0x3fd85855,
+                    0x3333778a, 0x3d2fd56f, 0x3bd81800, 0x3fd7fafa, 0xc812566a,
+                    0xbd272090, 0x687cf800, 0x3fd79e26, 0x2efd1778, 0x3d29ec7d,
+                    0x76c67800, 0x3fd741d8, 0x49dc60b3, 0x3d2d8b09, 0xe6af1800,
+                    0x3fd6e60e, 0x7c222d87, 0x3d172165, 0x3e9c6800, 0x3fd68ac8,
+                    0x2756eba0, 0x3d20a0d3, 0x0b3ab000, 0x3fd63003, 0xe731ae00,
+                    0xbd2db623, 0xdf596000, 0x3fd5d5bd, 0x08a465dc, 0xbd0a0b2a,
+                    0x53c8d000, 0x3fd57bf7, 0xee5d40ef, 0x3d1faded, 0x0738a000,
+                    0x3fd522ae, 0x8164c759, 0x3d2ebe70, 0x9e173000, 0x3fd4c9e0,
+                    0x1b0ad8a4, 0xbd2e2089, 0xc271c800, 0x3fd4718d, 0x0967d675,
+                    0xbd2f27ce, 0x23d5e800, 0x3fd419b4, 0xec90e09d, 0x3d08e436,
+                    0x77333000, 0x3fd3c252, 0xb606bd5c, 0x3d183b54, 0x76be1000,
+                    0x3fd36b67, 0xb0f177c8, 0x3d116ecd, 0xe1d36000, 0x3fd314f1,
+                    0xd3213cb8, 0xbd28e27a, 0x7cdc9000, 0x3fd2bef0, 0x4a5004f4,
+                    0x3d2a9cfa, 0x1134d800, 0x3fd26962, 0xdf5bb3b6, 0x3d2c93c1,
+                    0x6d0eb800, 0x3fd21445, 0xba46baea, 0x3d0a87de, 0x635a6800,
+                    0x3fd1bf99, 0x5147bdb7, 0x3d2ca6ed, 0xcbacf800, 0x3fd16b5c,
+                    0xf7a51681, 0x3d2b9acd, 0x8227e800, 0x3fd1178e, 0x63a5f01c,
+                    0xbd2c210e, 0x67616000, 0x3fd0c42d, 0x163ceae9, 0x3d27188b,
+                    0x604d5800, 0x3fd07138, 0x16ed4e91, 0x3cf89cdb, 0x5626c800,
+                    0x3fd01eae, 0x1485e94a, 0xbd16f08c, 0x6cb3b000, 0x3fcf991c,
+                    0xca0cdf30, 0x3d1bcbec, 0xe4dd0000, 0x3fcef5ad, 0x65bb8e11,
+                    0xbcca2115, 0xffe71000, 0x3fce530e, 0x6041f430, 0x3cc21227,
+                    0xb0d49000, 0x3fcdb13d, 0xf715b035, 0xbd2aff2a, 0xf2656000,
+                    0x3fcd1037, 0x75b6f6e4, 0xbd084a7e, 0xc6f01000, 0x3fcc6ffb,
+                    0xc5962bd2, 0xbcf1ec72, 0x383be000, 0x3fcbd087, 0x595412b6,
+                    0xbd2d4bc4, 0x575bd000, 0x3fcb31d8, 0x4eace1aa, 0xbd0c358d,
+                    0x3c8ae000, 0x3fca93ed, 0x50562169, 0xbd287243, 0x07089000,
+                    0x3fc9f6c4, 0x6865817a, 0x3d29904d, 0xdcf70000, 0x3fc95a5a,
+                    0x58a0ff6f, 0x3d07f228, 0xeb390000, 0x3fc8beaf, 0xaae92cd1,
+                    0xbd073d54, 0x6551a000, 0x3fc823c1, 0x9a631e83, 0x3d1e0ddb,
+                    0x85445000, 0x3fc7898d, 0x70914305, 0xbd1c6610, 0x8b757000,
+                    0x3fc6f012, 0xe59c21e1, 0xbd25118d, 0xbe8c1000, 0x3fc6574e,
+                    0x2c3c2e78, 0x3d19cf8b, 0x6b544000, 0x3fc5bf40, 0xeb68981c,
+                    0xbd127023, 0xe4a1b000, 0x3fc527e5, 0xe5697dc7, 0x3d2633e8,
+                    0x8333b000, 0x3fc4913d, 0x54fdb678, 0x3d258379, 0xa5993000,
+                    0x3fc3fb45, 0x7e6a354d, 0xbd2cd1d8, 0xb0159000, 0x3fc365fc,
+                    0x234b7289, 0x3cc62fa8, 0x0c868000, 0x3fc2d161, 0xcb81b4a1,
+                    0x3d039d6c, 0x2a49c000, 0x3fc23d71, 0x8fd3df5c, 0x3d100d23,
+                    0x7e23f000, 0x3fc1aa2b, 0x44389934, 0x3d2ca78e, 0x8227e000,
+                    0x3fc1178e, 0xce2d07f2, 0x3d21ef78, 0xb59e4000, 0x3fc08598,
+                    0x7009902c, 0xbd27e5dd, 0x39dbe000, 0x3fbfe891, 0x4fa10afd,
+                    0xbd2534d6, 0x830a2000, 0x3fbec739, 0xafe645e0, 0xbd2dc068,
+                    0x63844000, 0x3fbda727, 0x1fa71733, 0x3d1a8940, 0x01bc4000,
+                    0x3fbc8858, 0xc65aacd3, 0x3d2646d1, 0x8dad6000, 0x3fbb6ac8,
+                    0x2bf768e5, 0xbd139080, 0x40b1c000, 0x3fba4e76, 0xb94407c8,
+                    0xbd0e42b6, 0x5d594000, 0x3fb9335e, 0x3abd47da, 0x3d23115c,
+                    0x2f40e000, 0x3fb8197e, 0xf96ffdf7, 0x3d0f80dc, 0x0aeac000,
+                    0x3fb700d3, 0xa99ded32, 0x3cec1e8d, 0x4d97a000, 0x3fb5e95a,
+                    0x3c5d1d1e, 0xbd2c6906, 0x5d208000, 0x3fb4d311, 0x82f4e1ef,
+                    0xbcf53a25, 0xa7d1e000, 0x3fb3bdf5, 0xa5db4ed7, 0x3d2cc85e,
+                    0xa4472000, 0x3fb2aa04, 0xae9c697d, 0xbd20b6e8, 0xd1466000,
+                    0x3fb1973b, 0x560d9e9b, 0xbd25325d, 0xb59e4000, 0x3fb08598,
+                    0x7009902c, 0xbd17e5dd, 0xc006c000, 0x3faeea31, 0x4fc93b7b,
+                    0xbd0e113e, 0xcdddc000, 0x3faccb73, 0x47d82807, 0xbd1a68f2,
+                    0xd0fb0000, 0x3faaaef2, 0x353bb42e, 0x3d20fc1a, 0x149fc000,
+                    0x3fa894aa, 0xd05a267d, 0xbd197995, 0xf2d4c000, 0x3fa67c94,
+                    0xec19afa2, 0xbd029efb, 0xd42e0000, 0x3fa466ae, 0x75bdfd28,
+                    0xbd2c1673, 0x2f8d0000, 0x3fa252f3, 0xe021b67b, 0x3d283e9a,
+                    0x89e74000, 0x3fa0415d, 0x5cf1d753, 0x3d0111c0, 0xec148000,
+                    0x3f9c63d2, 0x3f9eb2f3, 0x3d2578c6, 0x28c90000, 0x3f984925,
+                    0x325a0c34, 0xbd2aa0ba, 0x25980000, 0x3f9432a9, 0x928637fe,
+                    0x3d098139, 0x58938000, 0x3f902056, 0x06e2f7d2, 0xbd23dc5b,
+                    0xa3890000, 0x3f882448, 0xda74f640, 0xbd275577, 0x75890000,
+                    0x3f801015, 0x999d2be8, 0xbd10c76b, 0x59580000, 0x3f700805,
+                    0xcb31c67b, 0x3d2166af, 0x00000000, 0x00000000, 0x00000000,
+                    0x80000000
+    };
+
+    private static int[] logTwoData = {
+                    0xfefa3800, 0x3fa62e42, 0x93c76730, 0x3ceef357
+    };
+
+    private static int[] coeffLogTwoData = {
+                    0x92492492, 0x3fc24924, 0x00000000, 0xbfd00000, 0x3d6fb175,
+                    0xbfc5555e, 0x55555555, 0x3fd55555, 0x9999999a, 0x3fc99999,
+                    0x00000000, 0xbfe00000
+    };
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - LOG() ---------------------
+     *
+     * x=2^k * mx, mx in [1,2)
+     *
+     * Get B~1/mx based on the output of rcpps instruction (B0) B = int((B0*2^7+0.5))/2^7
+     *
+     * Reduced argument: r=B*mx-1.0 (computed accurately in high and low parts)
+     *
+     * Result: k*log(2) - log(B) + p(r) if |x-1| >= small value (2^-6) and p(r) is a degree 7
+     * polynomial -log(B) read from data table (high, low parts) Result is formed from high and low
+     * parts.
+     *
+     * Special cases: log(NaN) = quiet NaN, and raise invalid exception log(+INF) = that INF log(0)
+     * = -INF with divide-by-zero exception raised log(1) = +0 log(x) = NaN with invalid exception
+     * raised if x < -0, including -INF
+     *
+     */
+
+    public void logIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant logTwoTablePtr = new ArrayDataPointerConstant(logTwoTable, 16);
+        ArrayDataPointerConstant logTwoDataPtr = new ArrayDataPointerConstant(logTwoData, 16);
+        ArrayDataPointerConstant coeffLogTwoDataPtr = new ArrayDataPointerConstant(coeffLogTwoData, 16);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb3 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb7 = new Label();
+        Label bb8 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+
+        AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp);
+
+        setCrb(crb);
+        masm.movdq(stackSlot, value);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+        masm.movq(gpr1, 0x3ff0000000000000L);
+        masm.movdq(temp2, gpr1);
+        masm.movq(gpr3, 0x77f0000000000000L);
+        masm.movdq(temp3, gpr3);
+        masm.movl(gpr2, 32768);
+        masm.movdl(temp4, gpr2);
+        masm.movq(gpr2, 0xffffe00000000000L);
+        masm.movdq(temp5, gpr2);
+        masm.movdqu(temp1, value);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.movl(gpr2, 16352);
+        masm.psrlq(dest, 27);
+        masm.leaq(gpr4, externalAddress(logTwoTablePtr));
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp1, 12);
+        masm.pshufd(temp6, temp5, 0xE4);
+        masm.psrlq(temp1, 12);
+        masm.subl(gpr1, 16);
+        masm.cmpl(gpr1, 32736);
+        masm.jcc(ConditionFlag.AboveEqual, bb0);
+
+        masm.bind(bb1);
+        masm.paddd(dest, temp4);
+        masm.por(temp1, temp3);
+        masm.movdl(gpr3, dest);
+        masm.psllq(dest, 29);
+        masm.pand(temp5, temp1);
+        masm.pand(dest, temp6);
+        masm.subsd(temp1, temp5);
+        masm.mulpd(temp5, dest);
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, gpr2);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulsd(temp1, dest);
+        masm.movdq(temp6, externalAddress(logTwoDataPtr));                                    // 0xfefa3800,
+                                                                                              // 0x3fa62e42
+        masm.movdqu(temp3, externalAddress(coeffLogTwoDataPtr));                              // 0x92492492,
+                                                                                              // 0x3fc24924,
+                                                                                              // 0x00000000,
+                                                                                              // 0xbfd00000
+        masm.subsd(temp5, temp2);
+        masm.andl(gpr3, 16711680);
+        masm.shrl(gpr3, 12);
+        masm.movdqu(dest, new AMD64Address(gpr4, gpr3, Scale.Times1, 0));
+        masm.leaq(gpr4, externalAddress(coeffLogTwoDataPtr));
+        masm.movdqu(temp4, new AMD64Address(gpr4, 16));                                       // 0x3d6fb175,
+                                                                                              // 0xbfc5555e,
+                                                                                              // 0x55555555,
+                                                                                              // 0x3fd55555
+        masm.addsd(temp1, temp5);
+        masm.movdqu(temp2, new AMD64Address(gpr4, 32));                                       // 0x9999999a,
+                                                                                              // 0x3fc99999,
+                                                                                              // 0x00000000,
+                                                                                              // 0xbfe00000
+        masm.mulsd(temp6, temp7);
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(temp5, temp1);
+        } else {
+            masm.movdqu(temp5, temp1);
+            masm.movlhps(temp5, temp5);
+        }
+        masm.leaq(gpr4, externalAddress(logTwoDataPtr));
+        masm.mulsd(temp7, new AMD64Address(gpr4, 8));                                         // 0x93c76730,
+                                                                                              // 0x3ceef357
+        masm.mulsd(temp3, temp1);
+        masm.addsd(dest, temp6);
+        masm.mulpd(temp4, temp5);
+        masm.mulpd(temp5, temp5);
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(temp6, dest);
+        } else {
+            masm.movdqu(temp6, dest);
+            masm.movlhps(temp6, temp6);
+        }
+        masm.addsd(dest, temp1);
+        masm.addpd(temp4, temp2);
+        masm.mulpd(temp3, temp5);
+        masm.subsd(temp6, dest);
+        masm.mulsd(temp4, temp1);
+        masm.pshufd(temp2, dest, 0xEE);
+        masm.addsd(temp1, temp6);
+        masm.mulsd(temp5, temp5);
+        masm.addsd(temp7, temp2);
+        masm.addpd(temp4, temp3);
+        masm.addsd(temp1, temp7);
+        masm.mulpd(temp4, temp5);
+        masm.addsd(temp1, temp4);
+        masm.pshufd(temp5, temp4, 0xEE);
+        masm.addsd(temp1, temp5);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb8);
+
+        masm.bind(bb0);
+        masm.movdq(dest, stackSlot);
+        masm.movdq(temp1, stackSlot);
+        masm.addl(gpr1, 16);
+        masm.cmpl(gpr1, 32768);
+        masm.jcc(ConditionFlag.AboveEqual, bb2);
+
+        masm.cmpl(gpr1, 16);
+        masm.jcc(ConditionFlag.Below, bb3);
+
+        masm.bind(bb4);
+        masm.addsd(dest, dest);
+        masm.jmp(bb8);
+
+        masm.bind(bb5);
+        masm.jcc(ConditionFlag.Above, bb4);
+
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Above, bb4);
+
+        masm.jmp(bb6);
+
+        masm.bind(bb3);
+        masm.xorpd(temp1, temp1);
+        masm.addsd(temp1, dest);
+        masm.movdl(gpr3, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr2, temp1);
+        masm.orl(gpr3, gpr2);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Equal, bb7);
+
+        masm.xorpd(temp1, temp1);
+        masm.movl(gpr1, 18416);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.mulsd(dest, temp1);
+        masm.movdqu(temp1, dest);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.psrlq(dest, 27);
+        masm.movl(gpr2, 18416);
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp1, 12);
+        masm.pshufd(temp6, temp5, 0xE4);
+        masm.psrlq(temp1, 12);
+        masm.jmp(bb1);
+
+        masm.bind(bb2);
+        masm.movdl(gpr3, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr2, temp1);
+        masm.addl(gpr2, gpr2);
+        masm.cmpl(gpr2, -2097152);
+        masm.jcc(ConditionFlag.AboveEqual, bb5);
+
+        masm.orl(gpr3, gpr2);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Equal, bb7);
+
+        masm.bind(bb6);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32752);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.mulsd(dest, temp1);
+        masm.jmp(bb8);
+
+        masm.bind(bb7);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 49136);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.divsd(dest, temp1);
+
+        masm.bind(bb8);
+    }
+
+    private static int[] highmaskLogTen = {
+                    0xf8000000, 0xffffffff, 0x00000000, 0xffffe000
+    };
+
+    private static int[] logTenE = {
+                    0x00000000, 0x3fdbc000, 0xbf2e4108, 0x3f5a7a6c
+    };
+
+    private static int[] logTenTable = {
+                    0x509f7800, 0x3fd34413, 0x1f12b358, 0x3d1fef31, 0x80333400,
+                    0x3fd32418, 0xc671d9d0, 0xbcf542bf, 0x51195000, 0x3fd30442,
+                    0x78a4b0c3, 0x3d18216a, 0x6fc79400, 0x3fd2e490, 0x80fa389d,
+                    0xbc902869, 0x89d04000, 0x3fd2c502, 0x75c2f564, 0x3d040754,
+                    0x4ddd1c00, 0x3fd2a598, 0xd219b2c3, 0xbcfa1d84, 0x6baa7c00,
+                    0x3fd28651, 0xfd9abec1, 0x3d1be6d3, 0x94028800, 0x3fd2672d,
+                    0xe289a455, 0xbd1ede5e, 0x78b86400, 0x3fd2482c, 0x6734d179,
+                    0x3d1fe79b, 0xcca3c800, 0x3fd2294d, 0x981a40b8, 0xbced34ea,
+                    0x439c5000, 0x3fd20a91, 0xcc392737, 0xbd1a9cc3, 0x92752c00,
+                    0x3fd1ebf6, 0x03c9afe7, 0x3d1e98f8, 0x6ef8dc00, 0x3fd1cd7d,
+                    0x71dae7f4, 0x3d08a86c, 0x8fe4dc00, 0x3fd1af25, 0xee9185a1,
+                    0xbcff3412, 0xace59400, 0x3fd190ee, 0xc2cab353, 0x3cf17ed9,
+                    0x7e925000, 0x3fd172d8, 0x6952c1b2, 0x3cf1521c, 0xbe694400,
+                    0x3fd154e2, 0xcacb79ca, 0xbd0bdc78, 0x26cbac00, 0x3fd1370d,
+                    0xf71f4de1, 0xbd01f8be, 0x72fa0800, 0x3fd11957, 0x55bf910b,
+                    0x3c946e2b, 0x5f106000, 0x3fd0fbc1, 0x39e639c1, 0x3d14a84b,
+                    0xa802a800, 0x3fd0de4a, 0xd3f31d5d, 0xbd178385, 0x0b992000,
+                    0x3fd0c0f3, 0x3843106f, 0xbd1f602f, 0x486ce800, 0x3fd0a3ba,
+                    0x8819497c, 0x3cef987a, 0x1de49400, 0x3fd086a0, 0x1caa0467,
+                    0x3d0faec7, 0x4c30cc00, 0x3fd069a4, 0xa4424372, 0xbd1618fc,
+                    0x94490000, 0x3fd04cc6, 0x946517d2, 0xbd18384b, 0xb7e84000,
+                    0x3fd03006, 0xe0109c37, 0xbd19a6ac, 0x798a0c00, 0x3fd01364,
+                    0x5121e864, 0xbd164cf7, 0x38ce8000, 0x3fcfedbf, 0x46214d1a,
+                    0xbcbbc402, 0xc8e62000, 0x3fcfb4ef, 0xdab93203, 0x3d1e0176,
+                    0x2cb02800, 0x3fcf7c5a, 0x2a2ea8e4, 0xbcfec86a, 0xeeeaa000,
+                    0x3fcf43fd, 0xc18e49a4, 0x3cf110a8, 0x9bb6e800, 0x3fcf0bda,
+                    0x923cc9c0, 0xbd15ce99, 0xc093f000, 0x3fced3ef, 0x4d4b51e9,
+                    0x3d1a04c7, 0xec58f800, 0x3fce9c3c, 0x163cad59, 0x3cac8260,
+                    0x9a907000, 0x3fce2d7d, 0x3fa93646, 0x3ce4a1c0, 0x37311000,
+                    0x3fcdbf99, 0x32abd1fd, 0x3d07ea9d, 0x6744b800, 0x3fcd528c,
+                    0x4dcbdfd4, 0xbd1b08e2, 0xe36de800, 0x3fcce653, 0x0b7b7f7f,
+                    0xbd1b8f03, 0x77506800, 0x3fcc7aec, 0xa821c9fb, 0x3d13c163,
+                    0x00ff8800, 0x3fcc1053, 0x536bca76, 0xbd074ee5, 0x70719800,
+                    0x3fcba684, 0xd7da9b6b, 0xbd1fbf16, 0xc6f8d800, 0x3fcb3d7d,
+                    0xe2220bb3, 0x3d1a295d, 0x16c15800, 0x3fcad53c, 0xe724911e,
+                    0xbcf55822, 0x82533800, 0x3fca6dbc, 0x6d982371, 0x3cac567c,
+                    0x3c19e800, 0x3fca06fc, 0x84d17d80, 0x3d1da204, 0x85ef8000,
+                    0x3fc9a0f8, 0x54466a6a, 0xbd002204, 0xb0ac2000, 0x3fc93bae,
+                    0xd601fd65, 0x3d18840c, 0x1bb9b000, 0x3fc8d71c, 0x7bf58766,
+                    0xbd14f897, 0x34aae800, 0x3fc8733e, 0x3af6ac24, 0xbd0f5c45,
+                    0x76d68000, 0x3fc81012, 0x4303e1a1, 0xbd1f9a80, 0x6af57800,
+                    0x3fc7ad96, 0x43fbcb46, 0x3cf4c33e, 0xa6c51000, 0x3fc74bc7,
+                    0x70f0eac5, 0xbd192e3b, 0xccab9800, 0x3fc6eaa3, 0xc0093dfe,
+                    0xbd0faf15, 0x8b60b800, 0x3fc68a28, 0xde78d5fd, 0xbc9ea4ee,
+                    0x9d987000, 0x3fc62a53, 0x962bea6e, 0xbd194084, 0xc9b0e800,
+                    0x3fc5cb22, 0x888dd999, 0x3d1fe201, 0xe1634800, 0x3fc56c93,
+                    0x16ada7ad, 0x3d1b1188, 0xc176c000, 0x3fc50ea4, 0x4159b5b5,
+                    0xbcf09c08, 0x51766000, 0x3fc4b153, 0x84393d23, 0xbcf6a89c,
+                    0x83695000, 0x3fc4549d, 0x9f0b8bbb, 0x3d1c4b8c, 0x538d5800,
+                    0x3fc3f881, 0xf49df747, 0x3cf89b99, 0xc8138000, 0x3fc39cfc,
+                    0xd503b834, 0xbd13b99f, 0xf0df0800, 0x3fc3420d, 0xf011b386,
+                    0xbd05d8be, 0xe7466800, 0x3fc2e7b2, 0xf39c7bc2, 0xbd1bb94e,
+                    0xcdd62800, 0x3fc28de9, 0x05e6d69b, 0xbd10ed05, 0xd015d800,
+                    0x3fc234b0, 0xe29b6c9d, 0xbd1ff967, 0x224ea800, 0x3fc1dc06,
+                    0x727711fc, 0xbcffb30d, 0x01540000, 0x3fc183e8, 0x39786c5a,
+                    0x3cc23f57, 0xb24d9800, 0x3fc12c54, 0xc905a342, 0x3d003a1d,
+                    0x82835800, 0x3fc0d54a, 0x9b9920c0, 0x3d03b25a, 0xc72ac000,
+                    0x3fc07ec7, 0x46f26a24, 0x3cf0fa41, 0xdd35d800, 0x3fc028ca,
+                    0x41d9d6dc, 0x3d034a65, 0x52474000, 0x3fbfa6a4, 0x44f66449,
+                    0x3d19cad3, 0x2da3d000, 0x3fbefcb8, 0x67832999, 0x3d18400f,
+                    0x32a10000, 0x3fbe53ce, 0x9c0e3b1a, 0xbcff62fd, 0x556b7000,
+                    0x3fbdabe3, 0x02976913, 0xbcf8243b, 0x97e88000, 0x3fbd04f4,
+                    0xec793797, 0x3d1c0578, 0x09647000, 0x3fbc5eff, 0x05fc0565,
+                    0xbd1d799e, 0xc6426000, 0x3fbbb9ff, 0x4625f5ed, 0x3d1f5723,
+                    0xf7afd000, 0x3fbb15f3, 0xdd5aae61, 0xbd1a7e1e, 0xd358b000,
+                    0x3fba72d8, 0x3314e4d3, 0x3d17bc91, 0x9b1f5000, 0x3fb9d0ab,
+                    0x9a4d514b, 0x3cf18c9b, 0x9cd4e000, 0x3fb92f69, 0x7e4496ab,
+                    0x3cf1f96d, 0x31f4f000, 0x3fb88f10, 0xf56479e7, 0x3d165818,
+                    0xbf628000, 0x3fb7ef9c, 0x26bf486d, 0xbd1113a6, 0xb526b000,
+                    0x3fb7510c, 0x1a1c3384, 0x3ca9898d, 0x8e31e000, 0x3fb6b35d,
+                    0xb3875361, 0xbd0661ac, 0xd01de000, 0x3fb6168c, 0x2a7cacfa,
+                    0xbd1bdf10, 0x0af23000, 0x3fb57a98, 0xff868816, 0x3cf046d0,
+                    0xd8ea0000, 0x3fb4df7c, 0x1515fbe7, 0xbd1fd529, 0xde3b2000,
+                    0x3fb44538, 0x6e59a132, 0x3d1faeee, 0xc8df9000, 0x3fb3abc9,
+                    0xf1322361, 0xbd198807, 0x505f1000, 0x3fb3132d, 0x0888e6ab,
+                    0x3d1e5380, 0x359bd000, 0x3fb27b61, 0xdfbcbb22, 0xbcfe2724,
+                    0x429ee000, 0x3fb1e463, 0x6eb4c58c, 0xbcfe4dd6, 0x4a673000,
+                    0x3fb14e31, 0x4ce1ac9b, 0x3d1ba691, 0x28b96000, 0x3fb0b8c9,
+                    0x8c7813b8, 0xbd0b3872, 0xc1f08000, 0x3fb02428, 0xc2bc8c2c,
+                    0x3cb5ea6b, 0x05a1a000, 0x3faf209c, 0x72e8f18e, 0xbce8df84,
+                    0xc0b5e000, 0x3fadfa6d, 0x9fdef436, 0x3d087364, 0xaf416000,
+                    0x3facd5c2, 0x1068c3a9, 0x3d0827e7, 0xdb356000, 0x3fabb296,
+                    0x120a34d3, 0x3d101a9f, 0x5dfea000, 0x3faa90e6, 0xdaded264,
+                    0xbd14c392, 0x6034c000, 0x3fa970ad, 0x1c9d06a9, 0xbd1b705e,
+                    0x194c6000, 0x3fa851e8, 0x83996ad9, 0xbd0117bc, 0xcf4ac000,
+                    0x3fa73492, 0xb1a94a62, 0xbca5ea42, 0xd67b4000, 0x3fa618a9,
+                    0x75aed8ca, 0xbd07119b, 0x9126c000, 0x3fa4fe29, 0x5291d533,
+                    0x3d12658f, 0x6f4d4000, 0x3fa3e50e, 0xcd2c5cd9, 0x3d1d5c70,
+                    0xee608000, 0x3fa2cd54, 0xd1008489, 0x3d1a4802, 0x9900e000,
+                    0x3fa1b6f9, 0x54fb5598, 0xbd16593f, 0x06bb6000, 0x3fa0a1f9,
+                    0x64ef57b4, 0xbd17636b, 0xb7940000, 0x3f9f1c9f, 0xee6a4737,
+                    0x3cb5d479, 0x91aa0000, 0x3f9cf7f5, 0x3a16373c, 0x3d087114,
+                    0x156b8000, 0x3f9ad5ed, 0x836c554a, 0x3c6900b0, 0xd4764000,
+                    0x3f98b67f, 0xed12f17b, 0xbcffc974, 0x77dec000, 0x3f9699a7,
+                    0x232ce7ea, 0x3d1e35bb, 0xbfbf4000, 0x3f947f5d, 0xd84ffa6e,
+                    0x3d0e0a49, 0x82c7c000, 0x3f92679c, 0x8d170e90, 0xbd14d9f2,
+                    0xadd20000, 0x3f90525d, 0x86d9f88e, 0x3cdeb986, 0x86f10000,
+                    0x3f8c7f36, 0xb9e0a517, 0x3ce29faa, 0xb75c8000, 0x3f885e9e,
+                    0x542568cb, 0xbd1f7bdb, 0x46b30000, 0x3f8442e8, 0xb954e7d9,
+                    0x3d1e5287, 0xb7e60000, 0x3f802c07, 0x22da0b17, 0xbd19fb27,
+                    0x6c8b0000, 0x3f7833e3, 0x821271ef, 0xbd190f96, 0x29910000,
+                    0x3f701936, 0xbc3491a5, 0xbd1bcf45, 0x354a0000, 0x3f600fe3,
+                    0xc0ff520a, 0xbd19d71c, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000
+    };
+
+    private static int[] logTwoLogTenData = {
+                    0x509f7800, 0x3f934413, 0x1f12b358, 0x3cdfef31
+    };
+
+    private static int[] coeffLogTenData = {
+                    0xc1a5f12e, 0x40358874, 0x64d4ef0d, 0xc0089309, 0x385593b1,
+                    0xc025c917, 0xdc963467, 0x3ffc6a02, 0x7f9d3aa1, 0x4016ab9f,
+                    0xdc77b115, 0xbff27af2
+    };
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - LOG10() ---------------------
+     *
+     * Let x=2^k * mx, mx in [1,2)
+     *
+     * Get B~1/mx based on the output of rcpss instruction (B0) B = int((B0*LH*2^7+0.5))/2^7 LH is a
+     * short approximation for log10(e)
+     *
+     * Reduced argument: r=B*mx-LH (computed accurately in high and low parts)
+     *
+     * Result: k*log10(2) - log(B) + p(r) p(r) is a degree 7 polynomial -log(B) read from data table
+     * (high, low parts) Result is formed from high and low parts
+     *
+     * Special cases: log10(0) = -INF with divide-by-zero exception raised log10(1) = +0 log10(x) =
+     * NaN with invalid exception raised if x < -0, including -INF log10(+INF) = +INF
+     *
+     */
+
+    public void log10Intrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant highmaskLogTenPtr = new ArrayDataPointerConstant(highmaskLogTen, 16);
+        ArrayDataPointerConstant logTenEPtr = new ArrayDataPointerConstant(logTenE, 16);
+        ArrayDataPointerConstant logTenTablePtr = new ArrayDataPointerConstant(logTenTable, 16);
+        ArrayDataPointerConstant logTwoLogTenDataPtr = new ArrayDataPointerConstant(logTwoLogTenData, 16);
+        ArrayDataPointerConstant coeffLogTenDataPtr = new ArrayDataPointerConstant(coeffLogTenData, 16);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb3 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb7 = new Label();
+        Label bb8 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+
+        AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp);
+
+        setCrb(crb);
+        masm.movdq(stackSlot, value);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+        masm.movdqu(temp5, externalAddress(highmaskLogTenPtr));                               // 0xf8000000,
+                                                                                              // 0xffffffff,
+                                                                                              // 0x00000000,
+                                                                                              // 0xffffe000
+        masm.xorpd(temp2, temp2);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.movl(gpr2, 1054736384);
+        masm.movdl(temp7, gpr2);
+        masm.xorpd(temp3, temp3);
+        masm.movl(gpr3, 30704);
+        masm.pinsrw(temp3, gpr3, 3);
+        masm.movl(gpr3, 32768);
+        masm.movdl(temp4, gpr3);
+        masm.movdqu(temp1, value);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.movl(gpr2, 16352);
+        masm.psrlq(dest, 27);
+        masm.movdqu(temp2, externalAddress(logTenEPtr));                                      // 0x00000000,
+                                                                                              // 0x3fdbc000,
+                                                                                              // 0xbf2e4108,
+                                                                                              // 0x3f5a7a6c
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp1, 12);
+        masm.pshufd(temp6, temp5, 0x4E);
+        masm.psrlq(temp1, 12);
+        masm.subl(gpr1, 16);
+        masm.cmpl(gpr1, 32736);
+        masm.jcc(ConditionFlag.AboveEqual, bb0);
+
+        masm.bind(bb1);
+        masm.mulss(dest, temp7);
+        masm.por(temp1, temp3);
+        masm.andpd(temp5, temp1);
+        masm.paddd(dest, temp4);
+        masm.movdqu(temp3, externalAddress(coeffLogTenDataPtr));                              // 0xc1a5f12e,
+                                                                                              // 0x40358874,
+                                                                                              // 0x64d4ef0d,
+                                                                                              // 0xc0089309
+        masm.leaq(gpr4, externalAddress(coeffLogTenDataPtr));
+        masm.movdqu(temp4, new AMD64Address(gpr4, 16));                                       // 0x385593b1,
+                                                                                              // 0xc025c917,
+                                                                                              // 0xdc963467,
+                                                                                              // 0x3ffc6a02
+        masm.subsd(temp1, temp5);
+        masm.movdl(gpr3, dest);
+        masm.psllq(dest, 29);
+        masm.andpd(dest, temp6);
+        masm.movdq(temp6, externalAddress(logTwoLogTenDataPtr));                              // 0x509f7800,
+                                                                                              // 0x3f934413
+        masm.andl(gpr1, 32752);
+        masm.subl(gpr1, gpr2);
+        masm.cvtsi2sdl(temp7, gpr1);
+        masm.mulpd(temp5, dest);
+        masm.mulsd(temp1, dest);
+        masm.subsd(temp5, temp2);
+        masm.movdqu(temp2, new AMD64Address(gpr4, 32));                                       // 0x7f9d3aa1,
+                                                                                              // 0x4016ab9f,
+                                                                                              // 0xdc77b115,
+                                                                                              // 0xbff27af2
+        masm.leaq(gpr4, externalAddress(logTenTablePtr));
+        masm.andl(gpr3, 16711680);
+        masm.shrl(gpr3, 12);
+        masm.movdqu(dest, new AMD64Address(gpr4, gpr3, Scale.Times1, -1504));
+        masm.addsd(temp1, temp5);
+        masm.mulsd(temp6, temp7);
+        masm.pshufd(temp5, temp1, 0x44);
+        masm.leaq(gpr4, externalAddress(logTwoLogTenDataPtr));
+        masm.mulsd(temp7, new AMD64Address(gpr4, 8));                                         // 0x1f12b358,
+                                                                                              // 0x3cdfef31
+        masm.mulsd(temp3, temp1);
+        masm.addsd(dest, temp6);
+        masm.mulpd(temp4, temp5);
+        masm.leaq(gpr4, externalAddress(logTenEPtr));
+        masm.movdq(temp6, new AMD64Address(gpr4, 8));                                         // 0xbf2e4108,
+                                                                                              // 0x3f5a7a6c
+        masm.mulpd(temp5, temp5);
+        masm.addpd(temp4, temp2);
+        masm.mulpd(temp3, temp5);
+        masm.pshufd(temp2, dest, 0xE4);
+        masm.addsd(dest, temp1);
+        masm.mulsd(temp4, temp1);
+        masm.subsd(temp2, dest);
+        masm.mulsd(temp6, temp1);
+        masm.addsd(temp1, temp2);
+        masm.pshufd(temp2, dest, 0xEE);
+        masm.mulsd(temp5, temp5);
+        masm.addsd(temp7, temp2);
+        masm.addsd(temp1, temp6);
+        masm.addpd(temp4, temp3);
+        masm.addsd(temp1, temp7);
+        masm.mulpd(temp4, temp5);
+        masm.addsd(temp1, temp4);
+        masm.pshufd(temp5, temp4, 0xEE);
+        masm.addsd(temp1, temp5);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb8);
+
+        masm.bind(bb0);
+        masm.movdq(dest, stackSlot);
+        masm.movdq(temp1, stackSlot);
+        masm.addl(gpr1, 16);
+        masm.cmpl(gpr1, 32768);
+        masm.jcc(ConditionFlag.AboveEqual, bb2);
+
+        masm.cmpl(gpr1, 16);
+        masm.jcc(ConditionFlag.Below, bb3);
+
+        masm.bind(bb4);
+        masm.addsd(dest, dest);
+        masm.jmp(bb8);
+
+        masm.bind(bb5);
+        masm.jcc(ConditionFlag.Above, bb4);
+
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Above, bb4);
+
+        masm.jmp(bb6);
+
+        masm.bind(bb3);
+        masm.xorpd(temp1, temp1);
+        masm.addsd(temp1, dest);
+        masm.movdl(gpr3, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr2, temp1);
+        masm.orl(gpr3, gpr2);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Equal, bb7);
+
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(temp2, temp2);
+        masm.movl(gpr1, 18416);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.mulsd(dest, temp1);
+        masm.movl(gpr1, 16368);
+        masm.pinsrw(temp2, gpr1, 3);
+        masm.movdqu(temp1, dest);
+        masm.pextrw(gpr1, dest, 3);
+        masm.por(dest, temp2);
+        masm.movl(gpr2, 18416);
+        masm.psrlq(dest, 27);
+        masm.movdqu(temp2, externalAddress(logTenEPtr));                                      // 0x00000000,
+                                                                                              // 0x3fdbc000,
+                                                                                              // 0xbf2e4108,
+                                                                                              // 0x3f5a7a6c
+        masm.psrld(dest, 2);
+        masm.rcpps(dest, dest);
+        masm.psllq(temp1, 12);
+        masm.pshufd(temp6, temp5, 0x4E);
+        masm.psrlq(temp1, 12);
+        masm.jmp(bb1);
+
+        masm.bind(bb2);
+        masm.movdl(gpr3, temp1);
+        masm.psrlq(temp1, 32);
+        masm.movdl(gpr2, temp1);
+        masm.addl(gpr2, gpr2);
+        masm.cmpl(gpr2, -2097152);
+        masm.jcc(ConditionFlag.AboveEqual, bb5);
+
+        masm.orl(gpr3, gpr2);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Equal, bb7);
+
+        masm.bind(bb6);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 32752);
+        masm.pinsrw(temp1, gpr1, 3);
+        masm.mulsd(dest, temp1);
+        masm.jmp(bb8);
+
+        masm.bind(bb7);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.movl(gpr1, 49136);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.divsd(dest, temp1);
+
+        masm.bind(bb8);
+    }
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - SIN() ---------------------
+     *
+     * 1. RANGE REDUCTION
+     *
+     * We perform an initial range reduction from X to r with
+     *
+     * X =~= N * pi/32 + r
+     *
+     * so that |r| <= pi/64 + epsilon. We restrict inputs to those where |N| <= 932560. Beyond this,
+     * the range reduction is insufficiently accurate. For extremely small inputs, denormalization
+     * can occur internally, impacting performance. This means that the main path is actually only
+     * taken for 2^-252 <= |X| < 90112.
+     *
+     * To avoid branches, we perform the range reduction to full accuracy each time.
+     *
+     * X - N * (P_1 + P_2 + P_3)
+     *
+     * where P_1 and P_2 are 32-bit numbers (so multiplication by N is exact) and P_3 is a 53-bit
+     * number. Together, these approximate pi well enough for all cases in the restricted range.
+     *
+     * The main reduction sequence is:
+     *
+     * y = 32/pi * x N = integer(y) (computed by adding and subtracting off SHIFTER)
+     *
+     * m_1 = N * P_1 m_2 = N * P_2 r_1 = x - m_1 r = r_1 - m_2 (this r can be used for most of the
+     * calculation)
+     *
+     * c_1 = r_1 - r m_3 = N * P_3 c_2 = c_1 - m_2 c = c_2 - m_3
+     *
+     * 2. MAIN ALGORITHM
+     *
+     * The algorithm uses a table lookup based on B = M * pi / 32 where M = N mod 64. The stored
+     * values are: sigma closest power of 2 to cos(B) C_hl 53-bit cos(B) - sigma S_hi + S_lo 2 *
+     * 53-bit sin(B)
+     *
+     * The computation is organized as follows:
+     *
+     * sin(B + r + c) = [sin(B) + sigma * r] + r * (cos(B) - sigma) + sin(B) * [cos(r + c) - 1] +
+     * cos(B) * [sin(r + c) - r]
+     *
+     * which is approximately:
+     *
+     * [S_hi + sigma * r] + C_hl * r + S_lo + S_hi * [(cos(r) - 1) - r * c] + (C_hl + sigma) *
+     * [(sin(r) - r) + c]
+     *
+     * and this is what is actually computed. We separate this sum into four parts:
+     *
+     * hi + med + pols + corr
+     *
+     * where
+     *
+     * hi = S_hi + sigma r med = C_hl * r pols = S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r)
+     * corr = S_lo + c * ((C_hl + sigma) - S_hi * r)
+     *
+     * 3. POLYNOMIAL
+     *
+     * The polynomial S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) can be rearranged freely,
+     * since it is quite small, so we exploit parallelism to the fullest.
+     *
+     * psc4 = SC_4 * r_1 msc4 = psc4 * r r2 = r * r msc2 = SC_2 * r2 r4 = r2 * r2 psc3 = SC_3 + msc4
+     * psc1 = SC_1 + msc2 msc3 = r4 * psc3 sincospols = psc1 + msc3 pols = sincospols * <S_hi * r^2
+     * | (C_hl + sigma) * r^3>
+     *
+     * 4. CORRECTION TERM
+     *
+     * This is where the "c" component of the range reduction is taken into account; recall that
+     * just "r" is used for most of the calculation.
+     *
+     * -c = m_3 - c_2 -d = S_hi * r - (C_hl + sigma) corr = -c * -d + S_lo
+     *
+     * 5. COMPENSATED SUMMATIONS
+     *
+     * The two successive compensated summations add up the high and medium parts, leaving just the
+     * low parts to add up at the end.
+     *
+     * rs = sigma * r res_int = S_hi + rs k_0 = S_hi - res_int k_2 = k_0 + rs med = C_hl * r res_hi
+     * = res_int + med k_1 = res_int - res_hi k_3 = k_1 + med
+     *
+     * 6. FINAL SUMMATION
+     *
+     * We now add up all the small parts:
+     *
+     * res_lo = pols(hi) + pols(lo) + corr + k_1 + k_3
+     *
+     * Now the overall result is just:
+     *
+     * res_hi + res_lo
+     *
+     * 7. SMALL ARGUMENTS
+     *
+     * If |x| < SNN (SNN meaning the smallest normal number), we simply perform 0.1111111 cdots 1111
+     * * x. For SNN <= |x|, we do 2^-55 * (2^55 * x - x).
+     *
+     * Special cases: sin(NaN) = quiet NaN, and raise invalid exception sin(INF) = NaN and raise
+     * invalid exception sin(+/-0) = +/-0
+     *
+     */
+
+    public int[] oneHalf = {
+                    0x00000000, 0x3fe00000, 0x00000000, 0x3fe00000
+    };
+
+    public int[] pTwo = {
+                    0x1a600000, 0x3d90b461, 0x1a600000, 0x3d90b461
+    };
+
+    public int[] scFour = {
+                    0xa556c734, 0x3ec71de3, 0x1a01a01a, 0x3efa01a0
+    };
+
+    public int[] cTable = {
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x3ff00000, 0x176d6d31, 0xbf73b92e,
+                    0xbc29b42c, 0x3fb917a6, 0xe0000000, 0xbc3e2718, 0x00000000,
+                    0x3ff00000, 0x011469fb, 0xbf93ad06, 0x3c69a60b, 0x3fc8f8b8,
+                    0xc0000000, 0xbc626d19, 0x00000000, 0x3ff00000, 0x939d225a,
+                    0xbfa60bea, 0x2ed59f06, 0x3fd29406, 0xa0000000, 0xbc75d28d,
+                    0x00000000, 0x3ff00000, 0x866b95cf, 0xbfb37ca1, 0xa6aea963,
+                    0x3fd87de2, 0xe0000000, 0xbc672ced, 0x00000000, 0x3ff00000,
+                    0x73fa1279, 0xbfbe3a68, 0x3806f63b, 0x3fde2b5d, 0x20000000,
+                    0x3c5e0d89, 0x00000000, 0x3ff00000, 0x5bc57974, 0xbfc59267,
+                    0x39ae68c8, 0x3fe1c73b, 0x20000000, 0x3c8b25dd, 0x00000000,
+                    0x3ff00000, 0x53aba2fd, 0xbfcd0dfe, 0x25091dd6, 0x3fe44cf3,
+                    0x20000000, 0x3c68076a, 0x00000000, 0x3ff00000, 0x99fcef32,
+                    0x3fca8279, 0x667f3bcd, 0x3fe6a09e, 0x20000000, 0xbc8bdd34,
+                    0x00000000, 0x3fe00000, 0x94247758, 0x3fc133cc, 0x6b151741,
+                    0x3fe8bc80, 0x20000000, 0xbc82c5e1, 0x00000000, 0x3fe00000,
+                    0x9ae68c87, 0x3fac73b3, 0x290ea1a3, 0x3fea9b66, 0xe0000000,
+                    0x3c39f630, 0x00000000, 0x3fe00000, 0x7f909c4e, 0xbf9d4a2c,
+                    0xf180bdb1, 0x3fec38b2, 0x80000000, 0xbc76e0b1, 0x00000000,
+                    0x3fe00000, 0x65455a75, 0xbfbe0875, 0xcf328d46, 0x3fed906b,
+                    0x20000000, 0x3c7457e6, 0x00000000, 0x3fe00000, 0x76acf82d,
+                    0x3fa4a031, 0x56c62dda, 0x3fee9f41, 0xe0000000, 0x3c8760b1,
+                    0x00000000, 0x3fd00000, 0x0e5967d5, 0xbfac1d1f, 0xcff75cb0,
+                    0x3fef6297, 0x20000000, 0x3c756217, 0x00000000, 0x3fd00000,
+                    0x0f592f50, 0xbf9ba165, 0xa3d12526, 0x3fefd88d, 0x40000000,
+                    0xbc887df6, 0x00000000, 0x3fc00000, 0x00000000, 0x00000000,
+                    0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x0f592f50, 0x3f9ba165, 0xa3d12526, 0x3fefd88d,
+                    0x40000000, 0xbc887df6, 0x00000000, 0xbfc00000, 0x0e5967d5,
+                    0x3fac1d1f, 0xcff75cb0, 0x3fef6297, 0x20000000, 0x3c756217,
+                    0x00000000, 0xbfd00000, 0x76acf82d, 0xbfa4a031, 0x56c62dda,
+                    0x3fee9f41, 0xe0000000, 0x3c8760b1, 0x00000000, 0xbfd00000,
+                    0x65455a75, 0x3fbe0875, 0xcf328d46, 0x3fed906b, 0x20000000,
+                    0x3c7457e6, 0x00000000, 0xbfe00000, 0x7f909c4e, 0x3f9d4a2c,
+                    0xf180bdb1, 0x3fec38b2, 0x80000000, 0xbc76e0b1, 0x00000000,
+                    0xbfe00000, 0x9ae68c87, 0xbfac73b3, 0x290ea1a3, 0x3fea9b66,
+                    0xe0000000, 0x3c39f630, 0x00000000, 0xbfe00000, 0x94247758,
+                    0xbfc133cc, 0x6b151741, 0x3fe8bc80, 0x20000000, 0xbc82c5e1,
+                    0x00000000, 0xbfe00000, 0x99fcef32, 0xbfca8279, 0x667f3bcd,
+                    0x3fe6a09e, 0x20000000, 0xbc8bdd34, 0x00000000, 0xbfe00000,
+                    0x53aba2fd, 0x3fcd0dfe, 0x25091dd6, 0x3fe44cf3, 0x20000000,
+                    0x3c68076a, 0x00000000, 0xbff00000, 0x5bc57974, 0x3fc59267,
+                    0x39ae68c8, 0x3fe1c73b, 0x20000000, 0x3c8b25dd, 0x00000000,
+                    0xbff00000, 0x73fa1279, 0x3fbe3a68, 0x3806f63b, 0x3fde2b5d,
+                    0x20000000, 0x3c5e0d89, 0x00000000, 0xbff00000, 0x866b95cf,
+                    0x3fb37ca1, 0xa6aea963, 0x3fd87de2, 0xe0000000, 0xbc672ced,
+                    0x00000000, 0xbff00000, 0x939d225a, 0x3fa60bea, 0x2ed59f06,
+                    0x3fd29406, 0xa0000000, 0xbc75d28d, 0x00000000, 0xbff00000,
+                    0x011469fb, 0x3f93ad06, 0x3c69a60b, 0x3fc8f8b8, 0xc0000000,
+                    0xbc626d19, 0x00000000, 0xbff00000, 0x176d6d31, 0x3f73b92e,
+                    0xbc29b42c, 0x3fb917a6, 0xe0000000, 0xbc3e2718, 0x00000000,
+                    0xbff00000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0xbff00000, 0x176d6d31,
+                    0x3f73b92e, 0xbc29b42c, 0xbfb917a6, 0xe0000000, 0x3c3e2718,
+                    0x00000000, 0xbff00000, 0x011469fb, 0x3f93ad06, 0x3c69a60b,
+                    0xbfc8f8b8, 0xc0000000, 0x3c626d19, 0x00000000, 0xbff00000,
+                    0x939d225a, 0x3fa60bea, 0x2ed59f06, 0xbfd29406, 0xa0000000,
+                    0x3c75d28d, 0x00000000, 0xbff00000, 0x866b95cf, 0x3fb37ca1,
+                    0xa6aea963, 0xbfd87de2, 0xe0000000, 0x3c672ced, 0x00000000,
+                    0xbff00000, 0x73fa1279, 0x3fbe3a68, 0x3806f63b, 0xbfde2b5d,
+                    0x20000000, 0xbc5e0d89, 0x00000000, 0xbff00000, 0x5bc57974,
+                    0x3fc59267, 0x39ae68c8, 0xbfe1c73b, 0x20000000, 0xbc8b25dd,
+                    0x00000000, 0xbff00000, 0x53aba2fd, 0x3fcd0dfe, 0x25091dd6,
+                    0xbfe44cf3, 0x20000000, 0xbc68076a, 0x00000000, 0xbff00000,
+                    0x99fcef32, 0xbfca8279, 0x667f3bcd, 0xbfe6a09e, 0x20000000,
+                    0x3c8bdd34, 0x00000000, 0xbfe00000, 0x94247758, 0xbfc133cc,
+                    0x6b151741, 0xbfe8bc80, 0x20000000, 0x3c82c5e1, 0x00000000,
+                    0xbfe00000, 0x9ae68c87, 0xbfac73b3, 0x290ea1a3, 0xbfea9b66,
+                    0xe0000000, 0xbc39f630, 0x00000000, 0xbfe00000, 0x7f909c4e,
+                    0x3f9d4a2c, 0xf180bdb1, 0xbfec38b2, 0x80000000, 0x3c76e0b1,
+                    0x00000000, 0xbfe00000, 0x65455a75, 0x3fbe0875, 0xcf328d46,
+                    0xbfed906b, 0x20000000, 0xbc7457e6, 0x00000000, 0xbfe00000,
+                    0x76acf82d, 0xbfa4a031, 0x56c62dda, 0xbfee9f41, 0xe0000000,
+                    0xbc8760b1, 0x00000000, 0xbfd00000, 0x0e5967d5, 0x3fac1d1f,
+                    0xcff75cb0, 0xbfef6297, 0x20000000, 0xbc756217, 0x00000000,
+                    0xbfd00000, 0x0f592f50, 0x3f9ba165, 0xa3d12526, 0xbfefd88d,
+                    0x40000000, 0x3c887df6, 0x00000000, 0xbfc00000, 0x00000000,
+                    0x00000000, 0x00000000, 0xbff00000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x0f592f50, 0xbf9ba165, 0xa3d12526,
+                    0xbfefd88d, 0x40000000, 0x3c887df6, 0x00000000, 0x3fc00000,
+                    0x0e5967d5, 0xbfac1d1f, 0xcff75cb0, 0xbfef6297, 0x20000000,
+                    0xbc756217, 0x00000000, 0x3fd00000, 0x76acf82d, 0x3fa4a031,
+                    0x56c62dda, 0xbfee9f41, 0xe0000000, 0xbc8760b1, 0x00000000,
+                    0x3fd00000, 0x65455a75, 0xbfbe0875, 0xcf328d46, 0xbfed906b,
+                    0x20000000, 0xbc7457e6, 0x00000000, 0x3fe00000, 0x7f909c4e,
+                    0xbf9d4a2c, 0xf180bdb1, 0xbfec38b2, 0x80000000, 0x3c76e0b1,
+                    0x00000000, 0x3fe00000, 0x9ae68c87, 0x3fac73b3, 0x290ea1a3,
+                    0xbfea9b66, 0xe0000000, 0xbc39f630, 0x00000000, 0x3fe00000,
+                    0x94247758, 0x3fc133cc, 0x6b151741, 0xbfe8bc80, 0x20000000,
+                    0x3c82c5e1, 0x00000000, 0x3fe00000, 0x99fcef32, 0x3fca8279,
+                    0x667f3bcd, 0xbfe6a09e, 0x20000000, 0x3c8bdd34, 0x00000000,
+                    0x3fe00000, 0x53aba2fd, 0xbfcd0dfe, 0x25091dd6, 0xbfe44cf3,
+                    0x20000000, 0xbc68076a, 0x00000000, 0x3ff00000, 0x5bc57974,
+                    0xbfc59267, 0x39ae68c8, 0xbfe1c73b, 0x20000000, 0xbc8b25dd,
+                    0x00000000, 0x3ff00000, 0x73fa1279, 0xbfbe3a68, 0x3806f63b,
+                    0xbfde2b5d, 0x20000000, 0xbc5e0d89, 0x00000000, 0x3ff00000,
+                    0x866b95cf, 0xbfb37ca1, 0xa6aea963, 0xbfd87de2, 0xe0000000,
+                    0x3c672ced, 0x00000000, 0x3ff00000, 0x939d225a, 0xbfa60bea,
+                    0x2ed59f06, 0xbfd29406, 0xa0000000, 0x3c75d28d, 0x00000000,
+                    0x3ff00000, 0x011469fb, 0xbf93ad06, 0x3c69a60b, 0xbfc8f8b8,
+                    0xc0000000, 0x3c626d19, 0x00000000, 0x3ff00000, 0x176d6d31,
+                    0xbf73b92e, 0xbc29b42c, 0xbfb917a6, 0xe0000000, 0x3c3e2718,
+                    0x00000000, 0x3ff00000
+    };
+
+    public int[] scTwo = {
+                    0x11111111, 0x3f811111, 0x55555555, 0x3fa55555
+    };
+
+    public int[] scThree = {
+                    0x1a01a01a, 0xbf2a01a0, 0x16c16c17, 0xbf56c16c
+    };
+
+    public int[] scOne = {
+                    0x55555555, 0xbfc55555, 0x00000000, 0xbfe00000
+    };
+
+    public int[] piInvTable = {
+                    0x00000000, 0x00000000, 0xa2f9836e, 0x4e441529, 0xfc2757d1,
+                    0xf534ddc0, 0xdb629599, 0x3c439041, 0xfe5163ab, 0xdebbc561,
+                    0xb7246e3a, 0x424dd2e0, 0x06492eea, 0x09d1921c, 0xfe1deb1c,
+                    0xb129a73e, 0xe88235f5, 0x2ebb4484, 0xe99c7026, 0xb45f7e41,
+                    0x3991d639, 0x835339f4, 0x9c845f8b, 0xbdf9283b, 0x1ff897ff,
+                    0xde05980f, 0xef2f118b, 0x5a0a6d1f, 0x6d367ecf, 0x27cb09b7,
+                    0x4f463f66, 0x9e5fea2d, 0x7527bac7, 0xebe5f17b, 0x3d0739f7,
+                    0x8a5292ea, 0x6bfb5fb1, 0x1f8d5d08, 0x56033046, 0xfc7b6bab,
+                    0xf0cfbc21
+    };
+
+    public int[] piFour = {
+                    0x40000000, 0x3fe921fb, 0x18469899, 0x3e64442d
+    };
+
+    public int[] piThirtyTwoInv = {
+                    0x6dc9c883, 0x40245f30
+    };
+
+    public int[] shifter = {
+                    0x00000000, 0x43380000
+    };
+
+    public int[] signMask = {
+                    0x00000000, 0x80000000
+    };
+
+    public int[] pThree = {
+                    0x2e037073, 0x3b63198a
+    };
+
+    public int[] allOnes = {
+                    0xffffffff, 0x3fefffff
+    };
+
+    public int[] twoPowFiftyFive = {
+                    0x00000000, 0x43600000
+    };
+
+    public int[] twoPowFiftyFiveM = {
+                    0x00000000, 0x3c800000
+    };
+
+    public int[] pOne = {
+                    0x54400000, 0x3fb921fb
+    };
+
+    public void sinIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant oneHalfPtr = new ArrayDataPointerConstant(oneHalf, 16);
+        ArrayDataPointerConstant pTwoPtr = new ArrayDataPointerConstant(pTwo, 16);
+        ArrayDataPointerConstant scFourPtr = new ArrayDataPointerConstant(scFour, 16);
+        ArrayDataPointerConstant cTablePtr = new ArrayDataPointerConstant(cTable, 16);
+        ArrayDataPointerConstant scTwoPtr = new ArrayDataPointerConstant(scTwo, 16);
+        ArrayDataPointerConstant scThreePtr = new ArrayDataPointerConstant(scThree, 16);
+        ArrayDataPointerConstant scOnePtr = new ArrayDataPointerConstant(scOne, 16);
+        ArrayDataPointerConstant piInvTablePtr = new ArrayDataPointerConstant(piInvTable, 16);
+        ArrayDataPointerConstant piFourPtr = new ArrayDataPointerConstant(piFour, 16);
+        ArrayDataPointerConstant piThirtyTwoInvPtr = new ArrayDataPointerConstant(piThirtyTwoInv, 8);
+        ArrayDataPointerConstant shifterPtr = new ArrayDataPointerConstant(shifter, 8);
+        ArrayDataPointerConstant signMaskPtr = new ArrayDataPointerConstant(signMask, 8);
+        ArrayDataPointerConstant pThreePtr = new ArrayDataPointerConstant(pThree, 8);
+        ArrayDataPointerConstant allOnesPtr = new ArrayDataPointerConstant(allOnes, 8);
+        ArrayDataPointerConstant twoPowFiftyFivePtr = new ArrayDataPointerConstant(twoPowFiftyFive, 8);
+        ArrayDataPointerConstant twoPowFiftyFiveMPtr = new ArrayDataPointerConstant(twoPowFiftyFiveM, 8);
+        ArrayDataPointerConstant pOnePtr = new ArrayDataPointerConstant(pOne, 8);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb8 = new Label();
+        Label bb9 = new Label();
+        Label bb10 = new Label();
+        Label bb11 = new Label();
+        Label bb12 = new Label();
+        Label bb13 = new Label();
+        Label bb14 = new Label();
+        Label bb15 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+        Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD);
+        Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD);
+        Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD);
+        Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD);
+        Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD);
+        Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+        Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE);
+        Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE);
+
+        AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp);
+
+        setCrb(crb);
+        masm.movsd(stackSlot, value);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+
+        masm.leaq(gpr1, stackSlot);
+        masm.movl(gpr1, new AMD64Address(gpr1, 4));
+        masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr));                                // 0x6dc9c883,
+                                                                                              // 0x40245f30
+        masm.movdq(temp2, externalAddress(shifterPtr));                                       // 0x00000000,
+                                                                                              // 0x43380000
+
+        masm.andl(gpr1, 2147418112);
+        masm.subl(gpr1, 808452096);
+        masm.cmpl(gpr1, 281346048);
+        masm.jcc(ConditionFlag.Above, bb0);
+
+        masm.mulsd(temp1, dest);
+        masm.movdqu(temp5, externalAddress(oneHalfPtr));                                      // 0x00000000,
+                                                                                              // 0x3fe00000,
+                                                                                              // 0x00000000,
+                                                                                              // 0x3fe00000
+        masm.movdq(temp4, externalAddress(signMaskPtr));                                      // 0x00000000,
+                                                                                              // 0x80000000
+        masm.pand(temp4, dest);
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.cvttsd2sil(gpr4, temp1);
+        masm.cvtsi2sdl(temp1, gpr4);
+        masm.movdqu(temp6, externalAddress(pTwoPtr));                                         // 0x1a600000,
+                                                                                              // 0x3d90b461,
+                                                                                              // 0x1a600000,
+                                                                                              // 0x3d90b461
+        masm.movq(gpr7, 0x3fb921fb54400000L);
+        masm.movdq(temp3, gpr7);
+        masm.movdqu(temp5, externalAddress(scFourPtr));                                       // 0xa556c734,
+                                                                                              // 0x3ec71de3,
+                                                                                              // 0x1a01a01a,
+                                                                                              // 0x3efa01a0
+        masm.pshufd(temp4, dest, 0x44);
+        masm.mulsd(temp3, temp1);
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(temp1, temp1);
+        } else {
+            masm.movlhps(temp1, temp1);
+        }
+        masm.andl(gpr4, 63);
+        masm.shll(gpr4, 5);
+        masm.leaq(gpr1, externalAddress(cTablePtr));
+        masm.addq(gpr1, gpr4);
+        masm.movdqu(temp8, new AMD64Address(gpr1, 0));
+        masm.mulpd(temp6, temp1);
+        masm.mulsd(temp1, externalAddress(pThreePtr));                                        // 0x2e037073,
+                                                                                              // 0x3b63198a
+        masm.subsd(temp4, temp3);
+        masm.subsd(dest, temp3);
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(temp3, temp4);
+        } else {
+            masm.movdqu(temp3, temp4);
+            masm.movlhps(temp3, temp3);
+        }
+        masm.subsd(temp4, temp6);
+        masm.pshufd(dest, dest, 0x44);
+        masm.pshufd(temp7, temp8, 0xE);
+        masm.movdqu(temp2, temp8);
+        masm.movdqu(temp9, temp7);
+        masm.mulpd(temp5, dest);
+        masm.subpd(dest, temp6);
+        masm.mulsd(temp7, temp4);
+        masm.subsd(temp3, temp4);
+        masm.mulpd(temp5, dest);
+        masm.mulpd(dest, dest);
+        masm.subsd(temp3, temp6);
+        masm.movdqu(temp6, externalAddress(scTwoPtr));                                        // 0x11111111,
+                                                                                              // 0x3f811111,
+                                                                                              // 0x55555555,
+                                                                                              // 0x3fa55555
+        masm.subsd(temp1, temp3);
+        masm.movdq(temp3, new AMD64Address(gpr1, 24));
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp7, temp2);
+        masm.mulsd(temp2, temp4);
+        masm.mulpd(temp6, dest);
+        masm.mulsd(temp3, temp4);
+        masm.mulpd(temp2, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp5, externalAddress(scThreePtr));                                       // 0x1a01a01a,
+                                                                                              // 0xbf2a01a0,
+                                                                                              // 0x16c16c17,
+                                                                                              // 0xbf56c16c
+        masm.mulsd(temp4, temp8);
+        masm.addpd(temp6, externalAddress(scOnePtr));                                         // 0x55555555,
+                                                                                              // 0xbfc55555,
+                                                                                              // 0x00000000,
+                                                                                              // 0xbfe00000
+        masm.mulpd(temp5, dest);
+        masm.movdqu(dest, temp3);
+        masm.addsd(temp3, temp9);
+        masm.mulpd(temp1, temp7);
+        masm.movdqu(temp7, temp4);
+        masm.addsd(temp4, temp3);
+        masm.addpd(temp6, temp5);
+        masm.subsd(temp9, temp3);
+        masm.subsd(temp3, temp4);
+        masm.addsd(temp1, new AMD64Address(gpr1, 16));
+        masm.mulpd(temp6, temp2);
+        masm.addsd(temp9, dest);
+        masm.addsd(temp3, temp7);
+        masm.addsd(temp1, temp9);
+        masm.addsd(temp1, temp3);
+        masm.addsd(temp1, temp6);
+        masm.unpckhpd(temp6, temp6);
+        masm.movdqu(dest, temp4);
+        masm.addsd(temp1, temp6);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb14);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.divsd(dest, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb0);
+        masm.jcc(ConditionFlag.Greater, bb1);
+
+        masm.shrl(gpr1, 20);
+        masm.cmpl(gpr1, 3325);
+        masm.jcc(ConditionFlag.NotEqual, bb2);
+
+        masm.mulsd(dest, externalAddress(allOnesPtr));                                        // 0xffffffff,
+                                                                                              // 0x3fefffff
+        masm.jmp(bb15);
+
+        masm.bind(bb2);
+        masm.movdq(temp3, externalAddress(twoPowFiftyFivePtr));                               // 0x00000000,
+                                                                                              // 0x43600000
+        masm.mulsd(temp3, dest);
+        masm.subsd(temp3, dest);
+        masm.mulsd(temp3, externalAddress(twoPowFiftyFiveMPtr));                              // 0x00000000,
+                                                                                              // 0x3c800000
+        masm.jmp(bb15);
+
+        masm.bind(bb1);
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.Equal, bb14);
+
+        masm.subl(gpr3, 16224);
+        masm.shrl(gpr3, 7);
+        masm.andl(gpr3, 65532);
+        masm.leaq(gpr10, externalAddress(piInvTablePtr));
+        masm.addq(gpr3, gpr10);
+        masm.movdq(gpr1, dest);
+        masm.movl(gpr9, new AMD64Address(gpr3, 20));
+        masm.movl(gpr7, new AMD64Address(gpr3, 24));
+        masm.movl(gpr4, gpr1);
+        masm.shrq(gpr1, 21);
+        masm.orl(gpr1, Integer.MIN_VALUE);
+        masm.shrl(gpr1, 11);
+        masm.movl(gpr8, gpr9);
+        masm.imulq(gpr9, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.imulq(gpr7, gpr1);
+        masm.movl(gpr5, new AMD64Address(gpr3, 16));
+        masm.movl(gpr6, new AMD64Address(gpr3, 12));
+        masm.movl(gpr10, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr8, gpr9);
+        masm.addq(gpr10, gpr7);
+        masm.movl(gpr7, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr8, gpr10);
+        masm.movl(gpr9, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr9, gpr1);
+        masm.movl(gpr10, gpr6);
+        masm.imulq(gpr6, gpr4);
+        masm.movl(gpr2, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr8, gpr2);
+        masm.movl(gpr2, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr9, gpr5);
+        masm.addq(gpr9, gpr8);
+        masm.shlq(gpr2, 32);
+        masm.orq(gpr7, gpr2);
+        masm.imulq(gpr10, gpr1);
+        masm.movl(gpr8, new AMD64Address(gpr3, 8));
+        masm.movl(gpr5, new AMD64Address(gpr3, 4));
+        masm.movl(gpr2, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr9, gpr2);
+        masm.movl(gpr2, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr10, gpr6);
+        masm.addq(gpr10, gpr9);
+        masm.movq(gpr6, gpr8);
+        masm.imulq(gpr8, gpr4);
+        masm.imulq(gpr6, gpr1);
+        masm.movl(gpr9, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr10, gpr9);
+        masm.movl(gpr9, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr6, gpr8);
+        masm.addq(gpr6, gpr10);
+        masm.movq(gpr8, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.shlq(gpr9, 32);
+        masm.orq(gpr9, gpr2);
+        masm.movl(gpr1, new AMD64Address(gpr3, 0));
+        masm.movl(gpr10, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr6, gpr10);
+        masm.movl(gpr10, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr8, gpr5);
+        masm.addq(gpr8, gpr6);
+        masm.imulq(gpr4, gpr1);
+        masm.pextrw(gpr2, dest, 3);
+        masm.leaq(gpr6, externalAddress(piInvTablePtr));
+        masm.subq(gpr3, gpr6);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, 19);
+        masm.movl(gpr5, 32768);
+        masm.andl(gpr5, gpr2);
+        masm.shrl(gpr2, 4);
+        masm.andl(gpr2, 2047);
+        masm.subl(gpr2, 1023);
+        masm.subl(gpr3, gpr2);
+        masm.addq(gpr8, gpr4);
+        masm.movl(gpr4, gpr3);
+        masm.addl(gpr4, 32);
+        masm.cmpl(gpr3, 1);
+        masm.jcc(ConditionFlag.Less, bb4);
+
+        masm.negl(gpr3);
+        masm.addl(gpr3, 29);
+        masm.shll(gpr8);
+        masm.movl(gpr6, gpr8);
+        masm.andl(gpr8, 536870911);
+        masm.testl(gpr8, 268435456);
+        masm.jcc(ConditionFlag.NotEqual, bb5);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+
+        masm.bind(bb6);
+
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.Equal, bb8);
+
+        masm.bind(bb9);
+        masm.bsrq(gpr10, gpr8);
+        masm.movl(gpr3, 29);
+        masm.subl(gpr3, gpr10);
+        masm.jcc(ConditionFlag.LessEqual, bb10);
+
+        masm.shlq(gpr8);
+        masm.movq(gpr1, gpr9);
+        masm.shlq(gpr9);
+        masm.addl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shrq(gpr1);
+        masm.shrq(gpr7);
+        masm.orq(gpr8, gpr1);
+        masm.orq(gpr9, gpr7);
+
+        masm.bind(bb11);
+        masm.cvtsi2sdq(dest, gpr8);
+        masm.shrq(gpr9, 1);
+        masm.cvtsi2sdq(temp3, gpr9);
+        masm.xorpd(temp4, temp4);
+        masm.shll(gpr4, 4);
+        masm.negl(gpr4);
+        masm.addl(gpr4, 16368);
+        masm.orl(gpr4, gpr5);
+        masm.xorl(gpr4, gpr2);
+        masm.pinsrw(temp4, gpr4, 3);
+        masm.leaq(gpr1, externalAddress(piFourPtr));
+        masm.movdqu(temp2, new AMD64Address(gpr1, 0));                                        // 0x40000000,
+                                                                                              // 0x3fe921fb,
+                                                                                              // 0x18469899,
+                                                                                              // 0x3e64442d
+        masm.xorpd(temp5, temp5);
+        masm.subl(gpr4, 1008);
+        masm.pinsrw(temp5, gpr4, 3);
+        masm.mulsd(dest, temp4);
+        masm.shll(gpr5, 16);
+        masm.sarl(gpr5, 31);
+        masm.mulsd(temp3, temp5);
+        masm.movdqu(temp1, dest);
+        masm.pshufd(temp6, temp2, 0xE);
+        masm.mulsd(dest, temp2);
+        masm.shrl(gpr6, 29);
+        masm.addsd(temp1, temp3);
+        masm.mulsd(temp3, temp2);
+        masm.addl(gpr6, gpr5);
+        masm.xorl(gpr6, gpr5);
+        masm.mulsd(temp6, temp1);
+        masm.movl(gpr1, gpr6);
+        masm.addsd(temp6, temp3);
+        masm.movdqu(temp2, dest);
+        masm.addsd(dest, temp6);
+        masm.subsd(temp2, dest);
+        masm.addsd(temp6, temp2);
+
+        masm.bind(bb12);
+        masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr));                                // 0x6dc9c883,
+                                                                                              // 0x40245f30
+        masm.mulsd(temp1, dest);
+        masm.movdq(temp5, externalAddress(oneHalfPtr));                                       // 0x00000000,
+                                                                                              // 0x3fe00000,
+                                                                                              // 0x00000000,
+                                                                                              // 0x3fe00000
+        masm.movdq(temp4, externalAddress(signMaskPtr));                                      // 0x00000000,
+                                                                                              // 0x80000000
+        masm.pand(temp4, dest);
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.cvttsd2sil(gpr4, temp1);
+        masm.cvtsi2sdl(temp1, gpr4);
+        masm.movdq(temp3, externalAddress(pOnePtr));                                          // 0x54400000,
+                                                                                              // 0x3fb921fb
+        masm.movdqu(temp2, externalAddress(pTwoPtr));                                         // 0x1a600000,
+                                                                                              // 0x3d90b461,
+                                                                                              // 0x1a600000,
+                                                                                              // 0x3d90b461
+        masm.mulsd(temp3, temp1);
+        masm.unpcklpd(temp1, temp1);
+        masm.shll(gpr1, 3);
+        masm.addl(gpr4, 1865216);
+        masm.movdqu(temp4, dest);
+        masm.addl(gpr4, gpr1);
+        masm.andl(gpr4, 63);
+        masm.movdqu(temp5, externalAddress(scFourPtr));                                       // 0x54400000,
+                                                                                              // 0x3fb921fb
+        masm.leaq(gpr1, externalAddress(cTablePtr));
+        masm.shll(gpr4, 5);
+        masm.addq(gpr1, gpr4);
+        masm.movdqu(temp8, new AMD64Address(gpr1, 0));
+        masm.mulpd(temp2, temp1);
+        masm.subsd(dest, temp3);
+        masm.mulsd(temp1, externalAddress(pThreePtr));                                        // 0x2e037073,
+                                                                                              // 0x3b63198a
+        masm.subsd(temp4, temp3);
+        masm.unpcklpd(dest, dest);
+        masm.movdqu(temp3, temp4);
+        masm.subsd(temp4, temp2);
+        masm.mulpd(temp5, dest);
+        masm.subpd(dest, temp2);
+        masm.pshufd(temp7, temp8, 0xE);
+        masm.movdqu(temp9, temp7);
+        masm.mulsd(temp7, temp4);
+        masm.subsd(temp3, temp4);
+        masm.mulpd(temp5, dest);
+        masm.mulpd(dest, dest);
+        masm.subsd(temp3, temp2);
+        masm.movdqu(temp2, temp8);
+        masm.subsd(temp1, temp3);
+        masm.movdq(temp3, new AMD64Address(gpr1, 24));
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp7, temp2);
+        masm.subsd(temp1, temp6);
+        masm.movdqu(temp6, externalAddress(scTwoPtr));                                        // 0x11111111,
+                                                                                              // 0x3f811111,
+                                                                                              // 0x55555555,
+                                                                                              // 0x3fa55555
+        masm.mulsd(temp2, temp4);
+        masm.mulpd(temp6, dest);
+        masm.mulsd(temp3, temp4);
+        masm.mulpd(temp2, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp5, externalAddress(scThreePtr));                                       // 0x1a01a01a,
+                                                                                              // 0xbf2a01a0,
+                                                                                              // 0x16c16c17,
+                                                                                              // 0xbf56c16c
+        masm.mulsd(temp4, temp8);
+        masm.addpd(temp6, externalAddress(scOnePtr));                                         // 0x55555555,
+                                                                                              // 0xbfc55555,
+                                                                                              // 0x00000000,
+                                                                                              // 0xbfe00000
+        masm.mulpd(temp5, dest);
+        masm.movdqu(dest, temp3);
+        masm.addsd(temp3, temp9);
+        masm.mulpd(temp1, temp7);
+        masm.movdqu(temp7, temp4);
+        masm.addsd(temp4, temp3);
+        masm.addpd(temp6, temp5);
+        masm.subsd(temp9, temp3);
+        masm.subsd(temp3, temp4);
+        masm.addsd(temp1, new AMD64Address(gpr1, 16));
+        masm.mulpd(temp6, temp2);
+        masm.addsd(temp9, dest);
+        masm.addsd(temp3, temp7);
+        masm.addsd(temp1, temp9);
+        masm.addsd(temp1, temp3);
+        masm.addsd(temp1, temp6);
+        masm.unpckhpd(temp6, temp6);
+        masm.movdqu(dest, temp4);
+        masm.addsd(temp1, temp6);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb8);
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.movl(gpr7, 0);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb9);
+
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb9);
+
+        masm.xorpd(dest, dest);
+        masm.xorpd(temp6, temp6);
+        masm.jmp(bb12);
+
+        masm.bind(bb10);
+        masm.jcc(ConditionFlag.Equal, bb11);
+
+        masm.negl(gpr3);
+        masm.shrq(gpr9);
+        masm.movq(gpr1, gpr8);
+        masm.shrq(gpr8);
+        masm.subl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shlq(gpr1);
+        masm.orq(gpr9, gpr1);
+        masm.jmp(bb11);
+
+        masm.bind(bb4);
+        masm.negl(gpr3);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr8);
+        masm.movq(gpr6, gpr8);
+        masm.testl(gpr8, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.NotEqual, bb13);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shrq(gpr6, 3);
+        masm.jmp(bb6);
+
+        masm.bind(bb5);
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 536870912);
+        masm.shrl(gpr2);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr2, 32);
+        masm.addl(gpr6, 536870912);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.jmp(bb6);
+
+        masm.bind(bb13);
+        masm.shrl(gpr8);
+        masm.movq(gpr2, 0x100000000L);
+        masm.shrq(gpr2);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.shrq(gpr6, 3);
+        masm.addl(gpr6, 536870912);
+        masm.jmp(bb6);
+
+        masm.bind(bb15);
+    }
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - COS() ---------------------
+     *
+     * 1. RANGE REDUCTION
+     *
+     * We perform an initial range reduction from X to r with
+     *
+     * X =~= N * pi/32 + r
+     *
+     * so that |r| <= pi/64 + epsilon. We restrict inputs to those where |N| <= 932560. Beyond this,
+     * the range reduction is insufficiently accurate. For extremely small inputs, denormalization
+     * can occur internally, impacting performance. This means that the main path is actually only
+     * taken for 2^-252 <= |X| < 90112.
+     *
+     * To avoid branches, we perform the range reduction to full accuracy each time.
+     *
+     * X - N * (P_1 + P_2 + P_3)
+     *
+     * where P_1 and P_2 are 32-bit numbers (so multiplication by N is exact) and P_3 is a 53-bit
+     * number. Together, these approximate pi well enough for all cases in the restricted range.
+     *
+     * The main reduction sequence is:
+     *
+     * y = 32/pi * x N = integer(y) (computed by adding and subtracting off SHIFTER)
+     *
+     * m_1 = N * P_1 m_2 = N * P_2 r_1 = x - m_1 r = r_1 - m_2 (this r can be used for most of the
+     * calculation)
+     *
+     * c_1 = r_1 - r m_3 = N * P_3 c_2 = c_1 - m_2 c = c_2 - m_3
+     *
+     * 2. MAIN ALGORITHM
+     *
+     * The algorithm uses a table lookup based on B = M * pi / 32 where M = N mod 64. The stored
+     * values are: sigma closest power of 2 to cos(B) C_hl 53-bit cos(B) - sigma S_hi + S_lo 2 *
+     * 53-bit sin(B)
+     *
+     * The computation is organized as follows:
+     *
+     * sin(B + r + c) = [sin(B) + sigma * r] + r * (cos(B) - sigma) + sin(B) * [cos(r + c) - 1] +
+     * cos(B) * [sin(r + c) - r]
+     *
+     * which is approximately:
+     *
+     * [S_hi + sigma * r] + C_hl * r + S_lo + S_hi * [(cos(r) - 1) - r * c] + (C_hl + sigma) *
+     * [(sin(r) - r) + c]
+     *
+     * and this is what is actually computed. We separate this sum into four parts:
+     *
+     * hi + med + pols + corr
+     *
+     * where
+     *
+     * hi = S_hi + sigma r med = C_hl * r pols = S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r)
+     * corr = S_lo + c * ((C_hl + sigma) - S_hi * r)
+     *
+     * 3. POLYNOMIAL
+     *
+     * The polynomial S_hi * (cos(r) - 1) + (C_hl + sigma) * (sin(r) - r) can be rearranged freely,
+     * since it is quite small, so we exploit parallelism to the fullest.
+     *
+     * psc4 = SC_4 * r_1 msc4 = psc4 * r r2 = r * r msc2 = SC_2 * r2 r4 = r2 * r2 psc3 = SC_3 + msc4
+     * psc1 = SC_1 + msc2 msc3 = r4 * psc3 sincospols = psc1 + msc3 pols = sincospols * <S_hi * r^2
+     * | (C_hl + sigma) * r^3>
+     *
+     * 4. CORRECTION TERM
+     *
+     * This is where the "c" component of the range reduction is taken into account; recall that
+     * just "r" is used for most of the calculation.
+     *
+     * -c = m_3 - c_2 -d = S_hi * r - (C_hl + sigma) corr = -c * -d + S_lo
+     *
+     * 5. COMPENSATED SUMMATIONS
+     *
+     * The two successive compensated summations add up the high and medium parts, leaving just the
+     * low parts to add up at the end.
+     *
+     * rs = sigma * r res_int = S_hi + rs k_0 = S_hi - res_int k_2 = k_0 + rs med = C_hl * r res_hi
+     * = res_int + med k_1 = res_int - res_hi k_3 = k_1 + med
+     *
+     * 6. FINAL SUMMATION
+     *
+     * We now add up all the small parts:
+     *
+     * res_lo = pols(hi) + pols(lo) + corr + k_1 + k_3
+     *
+     * Now the overall result is just:
+     *
+     * res_hi + res_lo
+     *
+     * 7. SMALL ARGUMENTS
+     *
+     * Inputs with |X| < 2^-252 are treated specially as 1 - |x|.
+     *
+     * Special cases: cos(NaN) = quiet NaN, and raise invalid exception cos(INF) = NaN and raise
+     * invalid exception cos(0) = 1
+     *
+     */
+
+    public int[] one = {
+                    0x00000000, 0x3ff00000
+    };
+
+    public void cosIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant oneHalfPtr = new ArrayDataPointerConstant(oneHalf, 16);
+        ArrayDataPointerConstant pTwoPtr = new ArrayDataPointerConstant(pTwo, 16);
+        ArrayDataPointerConstant scFourPtr = new ArrayDataPointerConstant(scFour, 16);
+        ArrayDataPointerConstant cTablePtr = new ArrayDataPointerConstant(cTable, 16);
+        ArrayDataPointerConstant scTwoPtr = new ArrayDataPointerConstant(scTwo, 16);
+        ArrayDataPointerConstant scThreePtr = new ArrayDataPointerConstant(scThree, 16);
+        ArrayDataPointerConstant scOnePtr = new ArrayDataPointerConstant(scOne, 16);
+        ArrayDataPointerConstant piInvTablePtr = new ArrayDataPointerConstant(piInvTable, 16);
+        ArrayDataPointerConstant piFourPtr = new ArrayDataPointerConstant(piFour, 16);
+        ArrayDataPointerConstant piThirtyTwoInvPtr = new ArrayDataPointerConstant(piThirtyTwoInv, 8);
+        ArrayDataPointerConstant signMaskPtr = new ArrayDataPointerConstant(signMask, 8);
+        ArrayDataPointerConstant pThreePtr = new ArrayDataPointerConstant(pThree, 8);
+        ArrayDataPointerConstant pOnePtr = new ArrayDataPointerConstant(pOne, 8);
+        ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 8);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb3 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb7 = new Label();
+        Label bb8 = new Label();
+        Label bb9 = new Label();
+        Label bb10 = new Label();
+        Label bb11 = new Label();
+        Label bb12 = new Label();
+        Label bb13 = new Label();
+        Label bb14 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+        Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD);
+        Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD);
+        Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD);
+        Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD);
+        Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD);
+        Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+        Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE);
+        Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE);
+
+        AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp);
+
+        setCrb(crb);
+        masm.movdq(stackSlot, value);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+
+        masm.leaq(gpr1, stackSlot);
+        masm.movl(gpr1, new AMD64Address(gpr1, 4));
+        masm.movdq(temp1, externalAddress(piThirtyTwoInvPtr));                              // 0x6dc9c883,
+                                                                                            // 0x40245f30
+
+        masm.andl(gpr1, 2147418112);
+        masm.subl(gpr1, 808452096);
+        masm.cmpl(gpr1, 281346048);
+        masm.jcc(ConditionFlag.Above, bb0);
+
+        masm.mulsd(temp1, dest);
+        masm.movdqu(temp5, externalAddress(oneHalfPtr));                                    // 0x00000000,
+                                                                                            // 0x3fe00000,
+                                                                                            // 0x00000000,
+                                                                                            // 0x3fe00000
+        masm.movdq(temp4, externalAddress(signMaskPtr));                                    // 0x00000000,
+                                                                                            // 0x80000000
+        masm.pand(temp4, dest);
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.cvttsd2sil(gpr4, temp1);
+        masm.cvtsi2sdl(temp1, gpr4);
+        masm.movdqu(temp2, externalAddress(pTwoPtr));                                       // 0x1a600000,
+                                                                                            // 0x3d90b461,
+                                                                                            // 0x1a600000,
+                                                                                            // 0x3d90b461
+        masm.movdq(temp3, externalAddress(pOnePtr));                                        // 0x54400000,
+                                                                                            // 0x3fb921fb
+        masm.mulsd(temp3, temp1);
+        masm.unpcklpd(temp1, temp1);
+        masm.addq(gpr4, 1865232);
+        masm.movdqu(temp4, dest);
+        masm.andq(gpr4, 63);
+        masm.movdqu(temp5, externalAddress(scFourPtr));                                     // 0xa556c734,
+                                                                                            // 0x3ec71de3,
+                                                                                            // 0x1a01a01a,
+                                                                                            // 0x3efa01a0
+        masm.leaq(gpr1, externalAddress(cTablePtr));
+        masm.shlq(gpr4, 5);
+        masm.addq(gpr1, gpr4);
+        masm.movdqu(temp8, new AMD64Address(gpr1, 0));
+        masm.mulpd(temp2, temp1);
+        masm.subsd(dest, temp3);
+        masm.mulsd(temp1, externalAddress(pThreePtr));                                      // 0x2e037073,
+                                                                                            // 0x3b63198a
+        masm.subsd(temp4, temp3);
+        masm.unpcklpd(dest, dest);
+        masm.movdqu(temp3, temp4);
+        masm.subsd(temp4, temp2);
+        masm.mulpd(temp5, dest);
+        masm.subpd(dest, temp2);
+        masm.pshufd(temp7, temp8, 0xE);
+        masm.movdqu(temp6, externalAddress(scTwoPtr));                                      // 0x11111111,
+                                                                                            // 0x3f811111,
+                                                                                            // 0x55555555,
+                                                                                            // 0x3fa55555
+        masm.mulsd(temp7, temp4);
+        masm.subsd(temp3, temp4);
+        masm.mulpd(temp5, dest);
+        masm.mulpd(dest, dest);
+        masm.subsd(temp3, temp2);
+        masm.movdqu(temp2, temp8);
+        masm.subsd(temp1, temp3);
+        masm.movdq(temp3, new AMD64Address(gpr1, 24));
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp7, temp2);
+        masm.mulsd(temp2, temp4);
+        masm.mulpd(temp6, dest);
+        masm.mulsd(temp3, temp4);
+        masm.mulpd(temp2, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp5, externalAddress(scThreePtr));                                     // 0x1a01a01a,
+                                                                                            // 0xbf2a01a0,
+                                                                                            // 0x16c16c17,
+                                                                                            // 0xbf56c16c
+        masm.mulsd(temp4, temp8);
+        masm.pshufd(temp9, temp8, 0xE);
+        masm.addpd(temp6, externalAddress(scOnePtr));                                       // 0x55555555,
+                                                                                            // 0xbfc55555,
+                                                                                            // 0x00000000,
+                                                                                            // 0xbfe00000
+        masm.mulpd(temp5, dest);
+        masm.movdqu(dest, temp3);
+        masm.addsd(temp3, temp9);
+        masm.mulpd(temp1, temp7);
+        masm.movdqu(temp7, temp4);
+        masm.addsd(temp4, temp3);
+        masm.addpd(temp6, temp5);
+        masm.subsd(temp9, temp3);
+        masm.subsd(temp3, temp4);
+        masm.addsd(temp1, new AMD64Address(gpr1, 16));
+        masm.mulpd(temp6, temp2);
+        masm.addsd(dest, temp9);
+        masm.addsd(temp3, temp7);
+        masm.addsd(dest, temp1);
+        masm.addsd(dest, temp3);
+        masm.addsd(dest, temp6);
+        masm.unpckhpd(temp6, temp6);
+        masm.addsd(dest, temp6);
+        masm.addsd(dest, temp4);
+        masm.jmp(bb13);
+
+        masm.bind(bb14);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.divsd(dest, temp1);
+        masm.jmp(bb13);
+
+        masm.bind(bb0);
+        masm.jcc(ConditionFlag.Greater, bb1);
+
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32767);
+        masm.pinsrw(dest, gpr1, 3);
+        masm.movdq(temp1, externalAddress(onePtr));                                         // 0x00000000,
+                                                                                            // 0x3ff00000
+        masm.subsd(temp1, dest);
+        masm.movdqu(dest, temp1);
+        masm.jmp(bb13);
+
+        masm.bind(bb1);
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.Equal, bb14);
+
+        masm.subl(gpr3, 16224);
+        masm.shrl(gpr3, 7);
+        masm.andl(gpr3, 65532);
+        masm.leaq(gpr10, externalAddress(piInvTablePtr));
+        masm.addq(gpr3, gpr10);
+        masm.movdq(gpr1, dest);
+        masm.movl(gpr9, new AMD64Address(gpr3, 20));
+        masm.movl(gpr7, new AMD64Address(gpr3, 24));
+        masm.movl(gpr4, gpr1);
+        masm.shrq(gpr1, 21);
+        masm.orl(gpr1, Integer.MIN_VALUE);
+        masm.shrl(gpr1, 11);
+        masm.movl(gpr8, gpr9);
+        masm.imulq(gpr9, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.imulq(gpr7, gpr1);
+        masm.movl(gpr5, new AMD64Address(gpr3, 16));
+        masm.movl(gpr6, new AMD64Address(gpr3, 12));
+        masm.movl(gpr10, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr8, gpr9);
+        masm.addq(gpr10, gpr7);
+        masm.movl(gpr7, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr8, gpr10);
+        masm.movl(gpr9, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr9, gpr1);
+        masm.movl(gpr10, gpr6);
+        masm.imulq(gpr6, gpr4);
+        masm.movl(gpr2, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr8, gpr2);
+        masm.movl(gpr2, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr9, gpr5);
+        masm.addq(gpr9, gpr8);
+        masm.shlq(gpr2, 32);
+        masm.orq(gpr7, gpr2);
+        masm.imulq(gpr10, gpr1);
+        masm.movl(gpr8, new AMD64Address(gpr3, 8));
+        masm.movl(gpr5, new AMD64Address(gpr3, 4));
+        masm.movl(gpr2, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr9, gpr2);
+        masm.movl(gpr2, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr10, gpr6);
+        masm.addq(gpr10, gpr9);
+        masm.movq(gpr6, gpr8);
+        masm.imulq(gpr8, gpr4);
+        masm.imulq(gpr6, gpr1);
+        masm.movl(gpr9, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr10, gpr9);
+        masm.movl(gpr9, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr6, gpr8);
+        masm.addq(gpr6, gpr10);
+        masm.movq(gpr8, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.shlq(gpr9, 32);
+        masm.orq(gpr9, gpr2);
+        masm.movl(gpr1, new AMD64Address(gpr3, 0));
+        masm.movl(gpr10, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr6, gpr10);
+        masm.movl(gpr10, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr8, gpr5);
+        masm.addq(gpr8, gpr6);
+        masm.imulq(gpr4, gpr1);
+        masm.pextrw(gpr2, dest, 3);
+        masm.leaq(gpr6, externalAddress(piInvTablePtr));
+        masm.subq(gpr3, gpr6);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, 19);
+        masm.movl(gpr5, 32768);
+        masm.andl(gpr5, gpr2);
+        masm.shrl(gpr2, 4);
+        masm.andl(gpr2, 2047);
+        masm.subl(gpr2, 1023);
+        masm.subl(gpr3, gpr2);
+        masm.addq(gpr8, gpr4);
+        masm.movl(gpr4, gpr3);
+        masm.addl(gpr4, 32);
+        masm.cmpl(gpr3, 1);
+        masm.jcc(ConditionFlag.Less, bb3);
+
+        masm.negl(gpr3);
+        masm.addl(gpr3, 29);
+        masm.shll(gpr8);
+        masm.movl(gpr6, gpr8);
+        masm.andl(gpr8, 536870911);
+        masm.testl(gpr8, 268435456);
+        masm.jcc(ConditionFlag.NotEqual, bb4);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+
+        masm.bind(bb5);
+
+        masm.bind(bb6);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.Equal, bb7);
+
+        masm.bind(bb8);
+        masm.bsrq(gpr10, gpr8);
+        masm.movl(gpr3, 29);
+        masm.subl(gpr3, gpr10);
+        masm.jcc(ConditionFlag.LessEqual, bb9);
+
+        masm.shlq(gpr8);
+        masm.movq(gpr1, gpr9);
+        masm.shlq(gpr9);
+        masm.addl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shrq(gpr1);
+        masm.shrq(gpr7);
+        masm.orq(gpr8, gpr1);
+        masm.orq(gpr9, gpr7);
+
+        masm.bind(bb10);
+        masm.cvtsi2sdq(dest, gpr8);
+        masm.shrq(gpr9, 1);
+        masm.cvtsi2sdq(temp3, gpr9);
+        masm.xorpd(temp4, temp4);
+        masm.shll(gpr4, 4);
+        masm.negl(gpr4);
+        masm.addl(gpr4, 16368);
+        masm.orl(gpr4, gpr5);
+        masm.xorl(gpr4, gpr2);
+        masm.pinsrw(temp4, gpr4, 3);
+        masm.leaq(gpr2, externalAddress(piFourPtr));
+        masm.movdqu(temp2, new AMD64Address(gpr2, 0));                                      // 0x40000000,
+                                                                                            // 0x3fe921fb,
+                                                                                            // 0x18469899,
+                                                                                            // 0x3e64442d
+        masm.xorpd(temp5, temp5);
+        masm.subl(gpr4, 1008);
+        masm.pinsrw(temp5, gpr4, 3);
+        masm.mulsd(dest, temp4);
+        masm.shll(gpr5, 16);
+        masm.sarl(gpr5, 31);
+        masm.mulsd(temp3, temp5);
+        masm.movdqu(temp1, dest);
+        masm.mulsd(dest, temp2);
+        masm.pshufd(temp6, temp2, 0xE);
+        masm.shrl(gpr6, 29);
+        masm.addsd(temp1, temp3);
+        masm.mulsd(temp3, temp2);
+        masm.addl(gpr6, gpr5);
+        masm.xorl(gpr6, gpr5);
+        masm.mulsd(temp6, temp1);
+        masm.movl(gpr1, gpr6);
+        masm.addsd(temp6, temp3);
+        masm.movdqu(temp2, dest);
+        masm.addsd(dest, temp6);
+        masm.subsd(temp2, dest);
+        masm.addsd(temp6, temp2);
+
+        masm.bind(bb11);
+        masm.movq(temp1, externalAddress(piThirtyTwoInvPtr));                               // 0x6dc9c883,
+                                                                                            // 0x40245f30
+        masm.mulsd(temp1, dest);
+        masm.movdq(temp5, externalAddress(oneHalfPtr));                                     // 0x00000000,
+                                                                                            // 0x3fe00000,
+                                                                                            // 0x00000000,
+                                                                                            // 0x3fe00000
+        masm.movdq(temp4, externalAddress(signMaskPtr));                                    // 0x00000000,
+                                                                                            // 0x80000000
+        masm.pand(temp4, dest);
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.cvttsd2siq(gpr4, temp1);
+        masm.cvtsi2sdq(temp1, gpr4);
+        masm.movdq(temp3, externalAddress(pOnePtr));                                        // 0x54400000,
+                                                                                            // 0x3fb921fb
+        masm.movdqu(temp2, externalAddress(pTwoPtr));                                       // 0x1a600000,
+                                                                                            // 0x3d90b461,
+                                                                                            // 0x1a600000,
+                                                                                            // 0x3d90b461
+        masm.mulsd(temp3, temp1);
+        masm.unpcklpd(temp1, temp1);
+        masm.shll(gpr1, 3);
+        masm.addl(gpr4, 1865232);
+        masm.movdqu(temp4, dest);
+        masm.addl(gpr4, gpr1);
+        masm.andl(gpr4, 63);
+        masm.movdqu(temp5, externalAddress(scFourPtr));                                     // 0xa556c734,
+                                                                                            // 0x3ec71de3,
+                                                                                            // 0x1a01a01a,
+                                                                                            // 0x3efa01a0
+        masm.leaq(gpr1, externalAddress(cTablePtr));
+        masm.shll(gpr4, 5);
+        masm.addq(gpr1, gpr4);
+        masm.movdqu(temp8, new AMD64Address(gpr1, 0));
+        masm.mulpd(temp2, temp1);
+        masm.subsd(dest, temp3);
+        masm.mulsd(temp1, externalAddress(pThreePtr));                                      // 0x2e037073,
+                                                                                            // 0x3b63198a
+        masm.subsd(temp4, temp3);
+        masm.unpcklpd(dest, dest);
+        masm.movdqu(temp3, temp4);
+        masm.subsd(temp4, temp2);
+        masm.mulpd(temp5, dest);
+        masm.pshufd(temp7, temp8, 0xE);
+        masm.movdqu(temp9, temp7);
+        masm.subpd(dest, temp2);
+        masm.mulsd(temp7, temp4);
+        masm.subsd(temp3, temp4);
+        masm.mulpd(temp5, dest);
+        masm.mulpd(dest, dest);
+        masm.subsd(temp3, temp2);
+        masm.movdqu(temp2, temp8);
+        masm.subsd(temp1, temp3);
+        masm.movdq(temp3, new AMD64Address(gpr1, 24));
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp7, temp2);
+        masm.subsd(temp1, temp6);
+        masm.movdqu(temp6, externalAddress(scTwoPtr));                                      // 0x11111111,
+                                                                                            // 0x3f811111,
+                                                                                            // 0x55555555,
+                                                                                            // 0x3fa55555
+        masm.mulsd(temp2, temp4);
+        masm.mulpd(temp6, dest);
+        masm.mulsd(temp3, temp4);
+        masm.mulpd(temp2, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp5, externalAddress(scThreePtr));                                     // 0x1a01a01a,
+                                                                                            // 0xbf2a01a0,
+                                                                                            // 0x16c16c17,
+                                                                                            // 0xbf56c16c
+        masm.mulsd(temp4, temp8);
+        masm.addpd(temp6, externalAddress(scOnePtr));                                       // 0x55555555,
+                                                                                            // 0xbfc55555,
+                                                                                            // 0x00000000,
+                                                                                            // 0xbfe00000
+        masm.mulpd(temp5, dest);
+        masm.movdqu(dest, temp3);
+        masm.addsd(temp3, temp9);
+        masm.mulpd(temp1, temp7);
+        masm.movdqu(temp7, temp4);
+        masm.addsd(temp4, temp3);
+        masm.addpd(temp6, temp5);
+        masm.subsd(temp9, temp3);
+        masm.subsd(temp3, temp4);
+        masm.addsd(temp1, new AMD64Address(gpr1, 16));
+        masm.mulpd(temp6, temp2);
+        masm.addsd(temp9, dest);
+        masm.addsd(temp3, temp7);
+        masm.addsd(temp1, temp9);
+        masm.addsd(temp1, temp3);
+        masm.addsd(temp1, temp6);
+        masm.unpckhpd(temp6, temp6);
+        masm.movdqu(dest, temp4);
+        masm.addsd(temp1, temp6);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb13);
+
+        masm.bind(bb7);
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.movl(gpr7, 0);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb8);
+
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb8);
+
+        masm.xorpd(dest, dest);
+        masm.xorpd(temp6, temp6);
+        masm.jmp(bb11);
+
+        masm.bind(bb9);
+        masm.jcc(ConditionFlag.Equal, bb10);
+
+        masm.negl(gpr3);
+        masm.shrq(gpr9);
+        masm.movq(gpr1, gpr8);
+        masm.shrq(gpr8);
+        masm.subl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shlq(gpr1);
+        masm.orq(gpr9, gpr1);
+        masm.jmp(bb10);
+
+        masm.bind(bb3);
+        masm.negl(gpr3);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr8);
+        masm.movq(gpr6, gpr8);
+        masm.testl(gpr8, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.NotEqual, bb12);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shrq(gpr6, 3);
+        masm.jmp(bb6);
+
+        masm.bind(bb4);
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 536870912);
+        masm.shrl(gpr2);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr2, 32);
+        masm.addl(gpr6, 536870912);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.jmp(bb5);
+
+        masm.bind(bb12);
+        masm.shrl(gpr8);
+        masm.movq(gpr2, 0x100000000L);
+        masm.shrq(gpr2);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.shrq(gpr6, 3);
+        masm.addl(gpr6, 536870912);
+        masm.jmp(bb6);
+
+        masm.bind(bb13);
+    }
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - TAN() ---------------------
+     *
+     * Polynomials coefficients and other constants.
+     *
+     * Note that in this algorithm, there is a different polynomial for each breakpoint, so there
+     * are 32 sets of polynomial coefficients as well as 32 instances of the other constants.
+     *
+     * The polynomial coefficients and constants are offset from the start of the main block as
+     * follows:
+     *
+     * 0: c8 | c0 16: c9 | c1 32: c10 | c2 48: c11 | c3 64: c12 | c4 80: c13 | c5 96: c14 | c6 112:
+     * c15 | c7 128: T_hi 136: T_lo 144: Sigma 152: T_hl 160: Tau 168: Mask 176: (end of block)
+     *
+     * The total table size is therefore 5632 bytes.
+     *
+     * Note that c0 and c1 are always zero. We could try storing other constants here, and just
+     * loading the low part of the SIMD register in these cases, after ensuring the high part is
+     * zero.
+     *
+     * The higher terms of the polynomial are computed in the *low* part of the SIMD register. This
+     * is so we can overlap the multiplication by r^8 and the unpacking of the other part.
+     *
+     * The constants are: T_hi + T_lo = accurate constant term in power series Sigma + T_hl =
+     * accurate coefficient of r in power series (Sigma=1 bit) Tau = multiplier for the reciprocal,
+     * always -1 or 0
+     *
+     * The basic reconstruction formula using these constants is:
+     *
+     * High = tau * recip_hi + t_hi Med = (sgn * r + t_hl * r)_hi Low = (sgn * r + t_hl * r)_lo +
+     * tau * recip_lo + T_lo + (T_hl + sigma) * c + pol
+     *
+     * where pol = c0 + c1 * r + c2 * r^2 + ... + c15 * r^15
+     *
+     * (c0 = c1 = 0, but using them keeps SIMD regularity)
+     *
+     * We then do a compensated sum High + Med, add the low parts together and then do the final
+     * sum.
+     *
+     * Here recip_hi + recip_lo is an accurate reciprocal of the remainder modulo pi/2
+     *
+     * Special cases: tan(NaN) = quiet NaN, and raise invalid exception tan(INF) = NaN and raise
+     * invalid exception tan(+/-0) = +/-0
+     *
+     */
+
+    private static int[] oneHalfTan = {
+                    0x00000000, 0x3fe00000, 0x00000000, 0x3fe00000
+    };
+
+    private static int[] mulSixteen = {
+                    0x00000000, 0x40300000, 0x00000000, 0x3ff00000
+    };
+
+    private static int[] signMaskTan = {
+                    0x00000000, 0x80000000, 0x00000000, 0x80000000
+    };
+
+    private static int[] piThirtyTwoInvTan = {
+                    0x6dc9c883, 0x3fe45f30, 0x6dc9c883, 0x40245f30
+    };
+
+    private static int[] pOneTan = {
+                    0x54444000, 0x3fb921fb, 0x54440000, 0x3fb921fb
+    };
+
+    private static int[] pTwoTan = {
+                    0x67674000, 0xbd32e7b9, 0x4c4c0000, 0x3d468c23
+    };
+
+    private static int[] pThreeTan = {
+                    0x3707344a, 0x3aa8a2e0, 0x03707345, 0x3ae98a2e
+    };
+
+    private static int[] cTableTan = {
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x882c10fa,
+                    0x3f9664f4, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x55e6c23d, 0x3f8226e3, 0x55555555,
+                    0x3fd55555, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x0e157de0, 0x3f6d6d3d, 0x11111111, 0x3fc11111, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x452b75e3, 0x3f57da36,
+                    0x1ba1ba1c, 0x3faba1ba, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x3ff00000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4e435f9b,
+                    0x3f953f83, 0x00000000, 0x00000000, 0x3c6e8e46, 0x3f9b74ea,
+                    0x00000000, 0x00000000, 0xda5b7511, 0x3f85ad63, 0xdc230b9b,
+                    0x3fb97558, 0x26cb3788, 0x3f881308, 0x76fc4985, 0x3fd62ac9,
+                    0x77bb08ba, 0x3f757c85, 0xb6247521, 0x3fb1381e, 0x5922170c,
+                    0x3f754e95, 0x8746482d, 0x3fc27f83, 0x11055b30, 0x3f64e391,
+                    0x3e666320, 0x3fa3e609, 0x0de9dae3, 0x3f6301df, 0x1f1dca06,
+                    0x3fafa8ae, 0x8c5b2da2, 0x3fb936bb, 0x4e88f7a5, 0x3c587d05,
+                    0x00000000, 0x3ff00000, 0xa8935dd9, 0x3f83dde2, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x5a279ea3, 0x3faa3407,
+                    0x00000000, 0x00000000, 0x432d65fa, 0x3fa70153, 0x00000000,
+                    0x00000000, 0x891a4602, 0x3f9d03ef, 0xd62ca5f8, 0x3fca77d9,
+                    0xb35f4628, 0x3f97a265, 0x433258fa, 0x3fd8cf51, 0xb58fd909,
+                    0x3f8f88e3, 0x01771cea, 0x3fc2b154, 0xf3562f8e, 0x3f888f57,
+                    0xc028a723, 0x3fc7370f, 0x20b7f9f0, 0x3f80f44c, 0x214368e9,
+                    0x3fb6dfaa, 0x28891863, 0x3f79b4b6, 0x172dbbf0, 0x3fb6cb8e,
+                    0xe0553158, 0x3fc975f5, 0x593fe814, 0x3c2ef5d3, 0x00000000,
+                    0x3ff00000, 0x03dec550, 0x3fa44203, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x9314533e, 0x3fbb8ec5, 0x00000000,
+                    0x00000000, 0x09aa36d0, 0x3fb6d3f4, 0x00000000, 0x00000000,
+                    0xdcb427fd, 0x3fb13950, 0xd87ab0bb, 0x3fd5335e, 0xce0ae8a5,
+                    0x3fabb382, 0x79143126, 0x3fddba41, 0x5f2b28d4, 0x3fa552f1,
+                    0x59f21a6d, 0x3fd015ab, 0x22c27d95, 0x3fa0e984, 0xe19fc6aa,
+                    0x3fd0576c, 0x8f2c2950, 0x3f9a4898, 0xc0b3f22c, 0x3fc59462,
+                    0x1883a4b8, 0x3f94b61c, 0x3f838640, 0x3fc30eb8, 0x355c63dc,
+                    0x3fd36a08, 0x1dce993d, 0xbc6d704d, 0x00000000, 0x3ff00000,
+                    0x2b82ab63, 0x3fb78e92, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x56f37042, 0x3fccfc56, 0x00000000, 0x00000000,
+                    0xaa563951, 0x3fc90125, 0x00000000, 0x00000000, 0x3d0e7c5d,
+                    0x3fc50533, 0x9bed9b2e, 0x3fdf0ed9, 0x5fe7c47c, 0x3fc1f250,
+                    0x96c125e5, 0x3fe2edd9, 0x5a02bbd8, 0x3fbe5c71, 0x86362c20,
+                    0x3fda08b7, 0x4b4435ed, 0x3fb9d342, 0x4b494091, 0x3fd911bd,
+                    0xb56658be, 0x3fb5e4c7, 0x93a2fd76, 0x3fd3c092, 0xda271794,
+                    0x3fb29910, 0x3303df2b, 0x3fd189be, 0x99fcef32, 0x3fda8279,
+                    0xb68c1467, 0x3c708b2f, 0x00000000, 0x3ff00000, 0x980c4337,
+                    0x3fc5f619, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0xcc03e501, 0x3fdff10f, 0x00000000, 0x00000000, 0x44a4e845,
+                    0x3fddb63b, 0x00000000, 0x00000000, 0x3768ad9f, 0x3fdb72a4,
+                    0x3dd01cca, 0x3fe5fdb9, 0xa61d2811, 0x3fd972b2, 0x5645ad0b,
+                    0x3fe977f9, 0xd013b3ab, 0x3fd78ca3, 0xbf0bf914, 0x3fe4f192,
+                    0x4d53e730, 0x3fd5d060, 0x3f8b9000, 0x3fe49933, 0xe2b82f08,
+                    0x3fd4322a, 0x5936a835, 0x3fe27ae1, 0xb1c61c9b, 0x3fd2b3fb,
+                    0xef478605, 0x3fe1659e, 0x190834ec, 0x3fe11ab7, 0xcdb625ea,
+                    0xbc8e564b, 0x00000000, 0x3ff00000, 0xb07217e3, 0x3fd248f1,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b2c49d0,
+                    0x3ff2de9c, 0x00000000, 0x00000000, 0x2655bc98, 0x3ff33e58,
+                    0x00000000, 0x00000000, 0xff691fa2, 0x3ff3972e, 0xe93463bd,
+                    0x3feeed87, 0x070e10a0, 0x3ff3f5b2, 0xf4d790a4, 0x3ff20c10,
+                    0xa04e8ea3, 0x3ff4541a, 0x386accd3, 0x3ff1369e, 0x222a66dd,
+                    0x3ff4b521, 0x22a9777e, 0x3ff20817, 0x52a04a6e, 0x3ff5178f,
+                    0xddaa0031, 0x3ff22137, 0x4447d47c, 0x3ff57c01, 0x1e9c7f1d,
+                    0x3ff29311, 0x2ab7f990, 0x3fe561b8, 0x209c7df1, 0x3c87a8c5,
+                    0x00000000, 0x3ff00000, 0x4170bcc6, 0x3fdc92d8, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0xc7ab4d5a, 0x40085e24,
+                    0x00000000, 0x00000000, 0xe93ea75d, 0x400b963d, 0x00000000,
+                    0x00000000, 0x94a7f25a, 0x400f37e2, 0x4b6261cb, 0x3ff5f984,
+                    0x5a9dd812, 0x4011aab0, 0x74c30018, 0x3ffaf5a5, 0x7f2ce8e3,
+                    0x4013fe8b, 0xfe8e54fa, 0x3ffd7334, 0x670d618d, 0x4016a10c,
+                    0x4db97058, 0x4000e012, 0x24df44dd, 0x40199c5f, 0x697d6ece,
+                    0x4003006e, 0x83298b82, 0x401cfc4d, 0x19d490d6, 0x40058c19,
+                    0x2ae42850, 0x3fea4300, 0x118e20e6, 0xbc7a6db8, 0x00000000,
+                    0x40000000, 0xe33345b8, 0xbfd4e526, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x65965966, 0x40219659, 0x00000000,
+                    0x00000000, 0x882c10fa, 0x402664f4, 0x00000000, 0x00000000,
+                    0x83cd3723, 0x402c8342, 0x00000000, 0x40000000, 0x55e6c23d,
+                    0x403226e3, 0x55555555, 0x40055555, 0x34451939, 0x40371c96,
+                    0xaaaaaaab, 0x400aaaaa, 0x0e157de0, 0x403d6d3d, 0x11111111,
+                    0x40111111, 0xa738201f, 0x4042bbce, 0x05b05b06, 0x4015b05b,
+                    0x452b75e3, 0x4047da36, 0x1ba1ba1c, 0x401ba1ba, 0x00000000,
+                    0x3ff00000, 0x00000000, 0x00000000, 0x00000000, 0x40000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x4f48b8d3, 0xbf33eaf9, 0x00000000, 0x00000000,
+                    0x0cf7586f, 0x3f20b8ea, 0x00000000, 0x00000000, 0xd0258911,
+                    0xbf0abaf3, 0x23e49fe9, 0xbfab5a8c, 0x2d53222e, 0x3ef60d15,
+                    0x21169451, 0x3fa172b2, 0xbb254dbc, 0xbee1d3b5, 0xdbf93b8e,
+                    0xbf84c7db, 0x05b4630b, 0x3ecd3364, 0xee9aada7, 0x3f743924,
+                    0x794a8297, 0xbeb7b7b9, 0xe015f797, 0xbf5d41f5, 0xe41a4a56,
+                    0x3ea35dfb, 0xe4c2a251, 0x3f49a2ab, 0x5af9e000, 0xbfce49ce,
+                    0x8c743719, 0x3d1eb860, 0x00000000, 0x00000000, 0x1b4863cf,
+                    0x3fd78294, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8,
+                    0x535ad890, 0xbf2b9320, 0x00000000, 0x00000000, 0x018fdf1f,
+                    0x3f16d61d, 0x00000000, 0x00000000, 0x0359f1be, 0xbf0139e4,
+                    0xa4317c6d, 0xbfa67e17, 0x82672d0f, 0x3eebb405, 0x2f1b621e,
+                    0x3f9f455b, 0x51ccf238, 0xbed55317, 0xf437b9ac, 0xbf804bee,
+                    0xc791a2b5, 0x3ec0e993, 0x919a1db2, 0x3f7080c2, 0x336a5b0e,
+                    0xbeaa48a2, 0x0a268358, 0xbf55a443, 0xdfd978e4, 0x3e94b61f,
+                    0xd7767a58, 0x3f431806, 0x2aea0000, 0xbfc9bbe8, 0x7723ea61,
+                    0xbd3a2369, 0x00000000, 0x00000000, 0xdf7796ff, 0x3fd6e642,
+                    0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0xb9ff07ce,
+                    0xbf231c78, 0x00000000, 0x00000000, 0xa5517182, 0x3f0ff0e0,
+                    0x00000000, 0x00000000, 0x790b4cbc, 0xbef66191, 0x848a46c6,
+                    0xbfa21ac0, 0xb16435fa, 0x3ee1d3ec, 0x2a1aa832, 0x3f9c71ea,
+                    0xfdd299ef, 0xbec9dd1a, 0x3f8dbaaf, 0xbf793363, 0x309fc6ea,
+                    0x3eb415d6, 0xbee60471, 0x3f6b83ba, 0x94a0a697, 0xbe9dae11,
+                    0x3e5c67b3, 0xbf4fd07b, 0x9a8f3e3e, 0x3e86bd75, 0xa4beb7a4,
+                    0x3f3d1eb1, 0x29cfc000, 0xbfc549ce, 0xbf159358, 0xbd397b33,
+                    0x00000000, 0x00000000, 0x871fee6c, 0x3fd666f0, 0x00000000,
+                    0x3ff00000, 0x00000000, 0xfffffff8, 0x7d98a556, 0xbf1a3958,
+                    0x00000000, 0x00000000, 0x9d88dc01, 0x3f0704c2, 0x00000000,
+                    0x00000000, 0x73742a2b, 0xbeed054a, 0x58844587, 0xbf9c2a13,
+                    0x55688a79, 0x3ed7a326, 0xee33f1d6, 0x3f9a48f4, 0xa8dc9888,
+                    0xbebf8939, 0xaad4b5b8, 0xbf72f746, 0x9102efa1, 0x3ea88f82,
+                    0xdabc29cf, 0x3f678228, 0x9289afb8, 0xbe90f456, 0x741fb4ed,
+                    0xbf46f3a3, 0xa97f6663, 0x3e79b4bf, 0xca89ff3f, 0x3f36db70,
+                    0xa8a2a000, 0xbfc0ee13, 0x3da24be1, 0xbd338b9f, 0x00000000,
+                    0x00000000, 0x11cd6c69, 0x3fd601fd, 0x00000000, 0x3ff00000,
+                    0x00000000, 0xfffffff8, 0x1a154b97, 0xbf116b01, 0x00000000,
+                    0x00000000, 0x2d427630, 0x3f0147bf, 0x00000000, 0x00000000,
+                    0xb93820c8, 0xbee264d4, 0xbb6cbb18, 0xbf94ab8c, 0x888d4d92,
+                    0x3ed0568b, 0x60730f7c, 0x3f98b19b, 0xe4b1fb11, 0xbeb2f950,
+                    0x22cf9f74, 0xbf6b21cd, 0x4a3ff0a6, 0x3e9f499e, 0xfd2b83ce,
+                    0x3f64aad7, 0x637b73af, 0xbe83487c, 0xe522591a, 0xbf3fc092,
+                    0xa158e8bc, 0x3e6e3aae, 0xe5e82ffa, 0x3f329d2f, 0xd636a000,
+                    0xbfb9477f, 0xc2c2d2bc, 0xbd135ef9, 0x00000000, 0x00000000,
+                    0xf2fdb123, 0x3fd5b566, 0x00000000, 0x3ff00000, 0x00000000,
+                    0xfffffff8, 0xc41acb64, 0xbf05448d, 0x00000000, 0x00000000,
+                    0xdbb03d6f, 0x3efb7ad2, 0x00000000, 0x00000000, 0x9e42962d,
+                    0xbed5aea5, 0x2579f8ef, 0xbf8b2398, 0x288a1ed9, 0x3ec81441,
+                    0xb0198dc5, 0x3f979a3a, 0x2fdfe253, 0xbea57cd3, 0x5766336f,
+                    0xbf617caa, 0x600944c3, 0x3e954ed6, 0xa4e0aaf8, 0x3f62c646,
+                    0x6b8fb29c, 0xbe74e3a3, 0xdc4c0409, 0xbf33f952, 0x9bffe365,
+                    0x3e6301ec, 0xb8869e44, 0x3f2fc566, 0xe1e04000, 0xbfb0cc62,
+                    0x016b907f, 0xbd119cbc, 0x00000000, 0x00000000, 0xe6b9d8fa,
+                    0x3fd57fb3, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8,
+                    0x5daf22a6, 0xbef429d7, 0x00000000, 0x00000000, 0x06bca545,
+                    0x3ef7a27d, 0x00000000, 0x00000000, 0x7211c19a, 0xbec41c3e,
+                    0x956ed53e, 0xbf7ae3f4, 0xee750e72, 0x3ec3901b, 0x91d443f5,
+                    0x3f96f713, 0x36661e6c, 0xbe936e09, 0x506f9381, 0xbf5122e8,
+                    0xcb6dd43f, 0x3e9041b9, 0x6698b2ff, 0x3f61b0c7, 0x576bf12b,
+                    0xbe625a8a, 0xe5a0e9dc, 0xbf23499d, 0x110384dd, 0x3e5b1c2c,
+                    0x68d43db6, 0x3f2cb899, 0x6ecac000, 0xbfa0c414, 0xcd7dd58c,
+                    0x3d13500f, 0x00000000, 0x00000000, 0x85a2c8fb, 0x3fd55fe0,
+                    0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x2bf70ebe, 0x3ef66a8f,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0xd644267f, 0x3ec22805, 0x16c16c17, 0x3f96c16c,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc4e09162,
+                    0x3e8d6db2, 0xbc011567, 0x3f61566a, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x1f79955c, 0x3e57da4e, 0x9334ef0b,
+                    0x3f2bbd77, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x55555555, 0x3fd55555, 0x00000000,
+                    0x3ff00000, 0x00000000, 0xfffffff8, 0x5daf22a6, 0x3ef429d7,
+                    0x00000000, 0x00000000, 0x06bca545, 0x3ef7a27d, 0x00000000,
+                    0x00000000, 0x7211c19a, 0x3ec41c3e, 0x956ed53e, 0x3f7ae3f4,
+                    0xee750e72, 0x3ec3901b, 0x91d443f5, 0x3f96f713, 0x36661e6c,
+                    0x3e936e09, 0x506f9381, 0x3f5122e8, 0xcb6dd43f, 0x3e9041b9,
+                    0x6698b2ff, 0x3f61b0c7, 0x576bf12b, 0x3e625a8a, 0xe5a0e9dc,
+                    0x3f23499d, 0x110384dd, 0x3e5b1c2c, 0x68d43db6, 0x3f2cb899,
+                    0x6ecac000, 0x3fa0c414, 0xcd7dd58c, 0xbd13500f, 0x00000000,
+                    0x00000000, 0x85a2c8fb, 0x3fd55fe0, 0x00000000, 0x3ff00000,
+                    0x00000000, 0xfffffff8, 0xc41acb64, 0x3f05448d, 0x00000000,
+                    0x00000000, 0xdbb03d6f, 0x3efb7ad2, 0x00000000, 0x00000000,
+                    0x9e42962d, 0x3ed5aea5, 0x2579f8ef, 0x3f8b2398, 0x288a1ed9,
+                    0x3ec81441, 0xb0198dc5, 0x3f979a3a, 0x2fdfe253, 0x3ea57cd3,
+                    0x5766336f, 0x3f617caa, 0x600944c3, 0x3e954ed6, 0xa4e0aaf8,
+                    0x3f62c646, 0x6b8fb29c, 0x3e74e3a3, 0xdc4c0409, 0x3f33f952,
+                    0x9bffe365, 0x3e6301ec, 0xb8869e44, 0x3f2fc566, 0xe1e04000,
+                    0x3fb0cc62, 0x016b907f, 0x3d119cbc, 0x00000000, 0x00000000,
+                    0xe6b9d8fa, 0x3fd57fb3, 0x00000000, 0x3ff00000, 0x00000000,
+                    0xfffffff8, 0x1a154b97, 0x3f116b01, 0x00000000, 0x00000000,
+                    0x2d427630, 0x3f0147bf, 0x00000000, 0x00000000, 0xb93820c8,
+                    0x3ee264d4, 0xbb6cbb18, 0x3f94ab8c, 0x888d4d92, 0x3ed0568b,
+                    0x60730f7c, 0x3f98b19b, 0xe4b1fb11, 0x3eb2f950, 0x22cf9f74,
+                    0x3f6b21cd, 0x4a3ff0a6, 0x3e9f499e, 0xfd2b83ce, 0x3f64aad7,
+                    0x637b73af, 0x3e83487c, 0xe522591a, 0x3f3fc092, 0xa158e8bc,
+                    0x3e6e3aae, 0xe5e82ffa, 0x3f329d2f, 0xd636a000, 0x3fb9477f,
+                    0xc2c2d2bc, 0x3d135ef9, 0x00000000, 0x00000000, 0xf2fdb123,
+                    0x3fd5b566, 0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8,
+                    0x7d98a556, 0x3f1a3958, 0x00000000, 0x00000000, 0x9d88dc01,
+                    0x3f0704c2, 0x00000000, 0x00000000, 0x73742a2b, 0x3eed054a,
+                    0x58844587, 0x3f9c2a13, 0x55688a79, 0x3ed7a326, 0xee33f1d6,
+                    0x3f9a48f4, 0xa8dc9888, 0x3ebf8939, 0xaad4b5b8, 0x3f72f746,
+                    0x9102efa1, 0x3ea88f82, 0xdabc29cf, 0x3f678228, 0x9289afb8,
+                    0x3e90f456, 0x741fb4ed, 0x3f46f3a3, 0xa97f6663, 0x3e79b4bf,
+                    0xca89ff3f, 0x3f36db70, 0xa8a2a000, 0x3fc0ee13, 0x3da24be1,
+                    0x3d338b9f, 0x00000000, 0x00000000, 0x11cd6c69, 0x3fd601fd,
+                    0x00000000, 0x3ff00000, 0x00000000, 0xfffffff8, 0xb9ff07ce,
+                    0x3f231c78, 0x00000000, 0x00000000, 0xa5517182, 0x3f0ff0e0,
+                    0x00000000, 0x00000000, 0x790b4cbc, 0x3ef66191, 0x848a46c6,
+                    0x3fa21ac0, 0xb16435fa, 0x3ee1d3ec, 0x2a1aa832, 0x3f9c71ea,
+                    0xfdd299ef, 0x3ec9dd1a, 0x3f8dbaaf, 0x3f793363, 0x309fc6ea,
+                    0x3eb415d6, 0xbee60471, 0x3f6b83ba, 0x94a0a697, 0x3e9dae11,
+                    0x3e5c67b3, 0x3f4fd07b, 0x9a8f3e3e, 0x3e86bd75, 0xa4beb7a4,
+                    0x3f3d1eb1, 0x29cfc000, 0x3fc549ce, 0xbf159358, 0x3d397b33,
+                    0x00000000, 0x00000000, 0x871fee6c, 0x3fd666f0, 0x00000000,
+                    0x3ff00000, 0x00000000, 0xfffffff8, 0x535ad890, 0x3f2b9320,
+                    0x00000000, 0x00000000, 0x018fdf1f, 0x3f16d61d, 0x00000000,
+                    0x00000000, 0x0359f1be, 0x3f0139e4, 0xa4317c6d, 0x3fa67e17,
+                    0x82672d0f, 0x3eebb405, 0x2f1b621e, 0x3f9f455b, 0x51ccf238,
+                    0x3ed55317, 0xf437b9ac, 0x3f804bee, 0xc791a2b5, 0x3ec0e993,
+                    0x919a1db2, 0x3f7080c2, 0x336a5b0e, 0x3eaa48a2, 0x0a268358,
+                    0x3f55a443, 0xdfd978e4, 0x3e94b61f, 0xd7767a58, 0x3f431806,
+                    0x2aea0000, 0x3fc9bbe8, 0x7723ea61, 0x3d3a2369, 0x00000000,
+                    0x00000000, 0xdf7796ff, 0x3fd6e642, 0x00000000, 0x3ff00000,
+                    0x00000000, 0xfffffff8, 0x4f48b8d3, 0x3f33eaf9, 0x00000000,
+                    0x00000000, 0x0cf7586f, 0x3f20b8ea, 0x00000000, 0x00000000,
+                    0xd0258911, 0x3f0abaf3, 0x23e49fe9, 0x3fab5a8c, 0x2d53222e,
+                    0x3ef60d15, 0x21169451, 0x3fa172b2, 0xbb254dbc, 0x3ee1d3b5,
+                    0xdbf93b8e, 0x3f84c7db, 0x05b4630b, 0x3ecd3364, 0xee9aada7,
+                    0x3f743924, 0x794a8297, 0x3eb7b7b9, 0xe015f797, 0x3f5d41f5,
+                    0xe41a4a56, 0x3ea35dfb, 0xe4c2a251, 0x3f49a2ab, 0x5af9e000,
+                    0x3fce49ce, 0x8c743719, 0xbd1eb860, 0x00000000, 0x00000000,
+                    0x1b4863cf, 0x3fd78294, 0x00000000, 0x3ff00000, 0x00000000,
+                    0xfffffff8, 0x65965966, 0xc0219659, 0x00000000, 0x00000000,
+                    0x882c10fa, 0x402664f4, 0x00000000, 0x00000000, 0x83cd3723,
+                    0xc02c8342, 0x00000000, 0xc0000000, 0x55e6c23d, 0x403226e3,
+                    0x55555555, 0x40055555, 0x34451939, 0xc0371c96, 0xaaaaaaab,
+                    0xc00aaaaa, 0x0e157de0, 0x403d6d3d, 0x11111111, 0x40111111,
+                    0xa738201f, 0xc042bbce, 0x05b05b06, 0xc015b05b, 0x452b75e3,
+                    0x4047da36, 0x1ba1ba1c, 0x401ba1ba, 0x00000000, 0xbff00000,
+                    0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0xc7ab4d5a, 0xc0085e24, 0x00000000, 0x00000000, 0xe93ea75d,
+                    0x400b963d, 0x00000000, 0x00000000, 0x94a7f25a, 0xc00f37e2,
+                    0x4b6261cb, 0xbff5f984, 0x5a9dd812, 0x4011aab0, 0x74c30018,
+                    0x3ffaf5a5, 0x7f2ce8e3, 0xc013fe8b, 0xfe8e54fa, 0xbffd7334,
+                    0x670d618d, 0x4016a10c, 0x4db97058, 0x4000e012, 0x24df44dd,
+                    0xc0199c5f, 0x697d6ece, 0xc003006e, 0x83298b82, 0x401cfc4d,
+                    0x19d490d6, 0x40058c19, 0x2ae42850, 0xbfea4300, 0x118e20e6,
+                    0x3c7a6db8, 0x00000000, 0x40000000, 0xe33345b8, 0xbfd4e526,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b2c49d0,
+                    0xbff2de9c, 0x00000000, 0x00000000, 0x2655bc98, 0x3ff33e58,
+                    0x00000000, 0x00000000, 0xff691fa2, 0xbff3972e, 0xe93463bd,
+                    0xbfeeed87, 0x070e10a0, 0x3ff3f5b2, 0xf4d790a4, 0x3ff20c10,
+                    0xa04e8ea3, 0xbff4541a, 0x386accd3, 0xbff1369e, 0x222a66dd,
+                    0x3ff4b521, 0x22a9777e, 0x3ff20817, 0x52a04a6e, 0xbff5178f,
+                    0xddaa0031, 0xbff22137, 0x4447d47c, 0x3ff57c01, 0x1e9c7f1d,
+                    0x3ff29311, 0x2ab7f990, 0xbfe561b8, 0x209c7df1, 0xbc87a8c5,
+                    0x00000000, 0x3ff00000, 0x4170bcc6, 0x3fdc92d8, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0xcc03e501, 0xbfdff10f,
+                    0x00000000, 0x00000000, 0x44a4e845, 0x3fddb63b, 0x00000000,
+                    0x00000000, 0x3768ad9f, 0xbfdb72a4, 0x3dd01cca, 0xbfe5fdb9,
+                    0xa61d2811, 0x3fd972b2, 0x5645ad0b, 0x3fe977f9, 0xd013b3ab,
+                    0xbfd78ca3, 0xbf0bf914, 0xbfe4f192, 0x4d53e730, 0x3fd5d060,
+                    0x3f8b9000, 0x3fe49933, 0xe2b82f08, 0xbfd4322a, 0x5936a835,
+                    0xbfe27ae1, 0xb1c61c9b, 0x3fd2b3fb, 0xef478605, 0x3fe1659e,
+                    0x190834ec, 0xbfe11ab7, 0xcdb625ea, 0x3c8e564b, 0x00000000,
+                    0x3ff00000, 0xb07217e3, 0x3fd248f1, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x56f37042, 0xbfccfc56, 0x00000000,
+                    0x00000000, 0xaa563951, 0x3fc90125, 0x00000000, 0x00000000,
+                    0x3d0e7c5d, 0xbfc50533, 0x9bed9b2e, 0xbfdf0ed9, 0x5fe7c47c,
+                    0x3fc1f250, 0x96c125e5, 0x3fe2edd9, 0x5a02bbd8, 0xbfbe5c71,
+                    0x86362c20, 0xbfda08b7, 0x4b4435ed, 0x3fb9d342, 0x4b494091,
+                    0x3fd911bd, 0xb56658be, 0xbfb5e4c7, 0x93a2fd76, 0xbfd3c092,
+                    0xda271794, 0x3fb29910, 0x3303df2b, 0x3fd189be, 0x99fcef32,
+                    0xbfda8279, 0xb68c1467, 0xbc708b2f, 0x00000000, 0x3ff00000,
+                    0x980c4337, 0x3fc5f619, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x9314533e, 0xbfbb8ec5, 0x00000000, 0x00000000,
+                    0x09aa36d0, 0x3fb6d3f4, 0x00000000, 0x00000000, 0xdcb427fd,
+                    0xbfb13950, 0xd87ab0bb, 0xbfd5335e, 0xce0ae8a5, 0x3fabb382,
+                    0x79143126, 0x3fddba41, 0x5f2b28d4, 0xbfa552f1, 0x59f21a6d,
+                    0xbfd015ab, 0x22c27d95, 0x3fa0e984, 0xe19fc6aa, 0x3fd0576c,
+                    0x8f2c2950, 0xbf9a4898, 0xc0b3f22c, 0xbfc59462, 0x1883a4b8,
+                    0x3f94b61c, 0x3f838640, 0x3fc30eb8, 0x355c63dc, 0xbfd36a08,
+                    0x1dce993d, 0x3c6d704d, 0x00000000, 0x3ff00000, 0x2b82ab63,
+                    0x3fb78e92, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x5a279ea3, 0xbfaa3407, 0x00000000, 0x00000000, 0x432d65fa,
+                    0x3fa70153, 0x00000000, 0x00000000, 0x891a4602, 0xbf9d03ef,
+                    0xd62ca5f8, 0xbfca77d9, 0xb35f4628, 0x3f97a265, 0x433258fa,
+                    0x3fd8cf51, 0xb58fd909, 0xbf8f88e3, 0x01771cea, 0xbfc2b154,
+                    0xf3562f8e, 0x3f888f57, 0xc028a723, 0x3fc7370f, 0x20b7f9f0,
+                    0xbf80f44c, 0x214368e9, 0xbfb6dfaa, 0x28891863, 0x3f79b4b6,
+                    0x172dbbf0, 0x3fb6cb8e, 0xe0553158, 0xbfc975f5, 0x593fe814,
+                    0xbc2ef5d3, 0x00000000, 0x3ff00000, 0x03dec550, 0x3fa44203,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4e435f9b,
+                    0xbf953f83, 0x00000000, 0x00000000, 0x3c6e8e46, 0x3f9b74ea,
+                    0x00000000, 0x00000000, 0xda5b7511, 0xbf85ad63, 0xdc230b9b,
+                    0xbfb97558, 0x26cb3788, 0x3f881308, 0x76fc4985, 0x3fd62ac9,
+                    0x77bb08ba, 0xbf757c85, 0xb6247521, 0xbfb1381e, 0x5922170c,
+                    0x3f754e95, 0x8746482d, 0x3fc27f83, 0x11055b30, 0xbf64e391,
+                    0x3e666320, 0xbfa3e609, 0x0de9dae3, 0x3f6301df, 0x1f1dca06,
+                    0x3fafa8ae, 0x8c5b2da2, 0xbfb936bb, 0x4e88f7a5, 0xbc587d05,
+                    0x00000000, 0x3ff00000, 0xa8935dd9, 0x3f83dde2, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000
+    };
+
+    private static int[] maskThirtyFiveTan = {
+                    0xfffc0000, 0xffffffff, 0x00000000, 0x00000000
+    };
+
+    private static int[] qElevenTan = {
+                    0xb8fe4d77, 0x3f82609a
+    };
+
+    private static int[] qNineTan = {
+                    0xbf847a43, 0x3f9664a0
+    };
+
+    private static int[] qSevenTan = {
+                    0x52c4c8ab, 0x3faba1ba
+    };
+
+    private static int[] qFiveTan = {
+                    0x11092746, 0x3fc11111
+    };
+
+    private static int[] qThreeTan = {
+                    0x55555612, 0x3fd55555
+    };
+
+    private static int[] piInvTableTan = {
+                    0x00000000, 0x00000000, 0xa2f9836e, 0x4e441529, 0xfc2757d1,
+                    0xf534ddc0, 0xdb629599, 0x3c439041, 0xfe5163ab, 0xdebbc561,
+                    0xb7246e3a, 0x424dd2e0, 0x06492eea, 0x09d1921c, 0xfe1deb1c,
+                    0xb129a73e, 0xe88235f5, 0x2ebb4484, 0xe99c7026, 0xb45f7e41,
+                    0x3991d639, 0x835339f4, 0x9c845f8b, 0xbdf9283b, 0x1ff897ff,
+                    0xde05980f, 0xef2f118b, 0x5a0a6d1f, 0x6d367ecf, 0x27cb09b7,
+                    0x4f463f66, 0x9e5fea2d, 0x7527bac7, 0xebe5f17b, 0x3d0739f7,
+                    0x8a5292ea, 0x6bfb5fb1, 0x1f8d5d08, 0x56033046, 0xfc7b6bab,
+                    0xf0cfbc21
+    };
+
+    private static int[] piFourTan = {
+                    0x00000000, 0x3fe921fb, 0x4611a626, 0x3e85110b
+    };
+
+    private static int[] qqTwoTan = {
+                    0x676733af, 0x3d32e7b9
+    };
+
+    private static int[] twoPowFiftyFiveTan = {
+                    0x00000000, 0x43600000
+    };
+
+    private static int[] twoPowMFiftyFiveTan = {
+                    0x00000000, 0x3c800000
+    };
+
+    public void tanIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant oneHalfTanPtr = new ArrayDataPointerConstant(oneHalfTan, 16);
+        ArrayDataPointerConstant mulSixteenPtr = new ArrayDataPointerConstant(mulSixteen, 16);
+        ArrayDataPointerConstant signMaskTanPtr = new ArrayDataPointerConstant(signMaskTan, 16);
+        ArrayDataPointerConstant piThirtyTwoInvTanPtr = new ArrayDataPointerConstant(piThirtyTwoInvTan, 16);
+        ArrayDataPointerConstant pOneTanPtr = new ArrayDataPointerConstant(pOneTan, 16);
+        ArrayDataPointerConstant pTwoTanPtr = new ArrayDataPointerConstant(pTwoTan, 16);
+        ArrayDataPointerConstant pThreeTanPtr = new ArrayDataPointerConstant(pThreeTan, 16);
+        ArrayDataPointerConstant cTableTanPtr = new ArrayDataPointerConstant(cTableTan, 16);
+        ArrayDataPointerConstant maskThirtyFiveTanPtr = new ArrayDataPointerConstant(maskThirtyFiveTan, 16);
+        ArrayDataPointerConstant qElevenTanPtr = new ArrayDataPointerConstant(qElevenTan, 16);
+        ArrayDataPointerConstant qNineTanPtr = new ArrayDataPointerConstant(qNineTan, 16);
+        ArrayDataPointerConstant qSevenTanPtr = new ArrayDataPointerConstant(qSevenTan, 8);
+        ArrayDataPointerConstant qFiveTanPtr = new ArrayDataPointerConstant(qFiveTan, 16);
+        ArrayDataPointerConstant qThreeTanPtr = new ArrayDataPointerConstant(qThreeTan, 16);
+        ArrayDataPointerConstant piInvTableTanPtr = new ArrayDataPointerConstant(piInvTableTan, 16);
+        ArrayDataPointerConstant piFourTanPtr = new ArrayDataPointerConstant(piFourTan, 8);
+        ArrayDataPointerConstant qqTwoTanPtr = new ArrayDataPointerConstant(qqTwoTan, 8);
+        ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 8);
+        ArrayDataPointerConstant twoPowFiftyFiveTanPtr = new ArrayDataPointerConstant(twoPowFiftyFiveTan, 8);
+        ArrayDataPointerConstant twoPowMFiftyFiveTanPtr = new ArrayDataPointerConstant(twoPowMFiftyFiveTan, 8);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb3 = new Label();
+        Label bb5 = new Label();
+        Label bb6 = new Label();
+        Label bb8 = new Label();
+        Label bb9 = new Label();
+        Label bb10 = new Label();
+        Label bb11 = new Label();
+        Label bb12 = new Label();
+        Label bb13 = new Label();
+        Label bb14 = new Label();
+        Label bb15 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+        Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD);
+        Register gpr6 = asRegister(gpr6Temp, AMD64Kind.QWORD);
+        Register gpr7 = asRegister(gpr7Temp, AMD64Kind.QWORD);
+        Register gpr8 = asRegister(gpr8Temp, AMD64Kind.QWORD);
+        Register gpr9 = asRegister(gpr9Temp, AMD64Kind.QWORD);
+        Register gpr10 = asRegister(gpr10Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+
+        setCrb(crb);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32767);
+        masm.subl(gpr1, 16314);
+        masm.cmpl(gpr1, 270);
+        masm.jcc(ConditionFlag.Above, bb0);
+
+        masm.movdqu(temp5, externalAddress(oneHalfTanPtr));                                     // 0x00000000,
+                                                                                                // 0x3fe00000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x3fe00000
+        masm.movdqu(temp6, externalAddress(mulSixteenPtr));                                     // 0x00000000,
+                                                                                                // 0x40300000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.unpcklpd(dest, dest);
+        masm.movdqu(temp4, externalAddress(signMaskTanPtr));                                    // 0x00000000,
+                                                                                                // 0x80000000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x80000000
+        masm.andpd(temp4, dest);
+        masm.movdqu(temp1, externalAddress(piThirtyTwoInvTanPtr));                              // 0x6dc9c883,
+                                                                                                // 0x3fe45f30,
+                                                                                                // 0x6dc9c883,
+                                                                                                // 0x40245f30
+        masm.mulpd(temp1, dest);
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.movdqu(temp7, temp1);
+        masm.unpckhpd(temp7, temp7);
+        masm.cvttsd2sil(gpr4, temp7);
+        masm.cvttpd2dq(temp1, temp1);
+        masm.cvtdq2pd(temp1, temp1);
+        masm.mulpd(temp1, temp6);
+        masm.movdqu(temp3, externalAddress(pOneTanPtr));                                        // 0x54444000,
+                                                                                                // 0x3fb921fb,
+                                                                                                // 0x54440000,
+                                                                                                // 0x3fb921fb
+        masm.movdq(temp5, externalAddress(qqTwoTanPtr));                                        // 0x676733af,
+                                                                                                // 0x3d32e7b9
+        masm.addq(gpr4, 469248);
+        masm.movdqu(temp4, externalAddress(pTwoTanPtr));                                        // 0x67674000,
+                                                                                                // 0xbd32e7b9,
+                                                                                                // 0x4c4c0000,
+                                                                                                // 0x3d468c23
+        masm.mulpd(temp3, temp1);
+        masm.andq(gpr4, 31);
+        masm.mulsd(temp5, temp1);
+        masm.movq(gpr3, gpr4);
+        masm.mulpd(temp4, temp1);
+        masm.shlq(gpr3, 1);
+        masm.subpd(dest, temp3);
+        masm.mulpd(temp1, externalAddress(pThreeTanPtr));                                       // 0x3707344a,
+                                                                                                // 0x3aa8a2e0,
+                                                                                                // 0x03707345,
+                                                                                                // 0x3ae98a2e
+        masm.addq(gpr4, gpr3);
+        masm.shlq(gpr3, 2);
+        masm.addq(gpr4, gpr3);
+        masm.addsd(temp5, dest);
+        masm.movdqu(temp2, dest);
+        masm.subpd(dest, temp4);
+        masm.movdq(temp6, externalAddress(onePtr));                                             // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.shlq(gpr4, 4);
+        masm.leaq(gpr1, externalAddress(cTableTanPtr));
+        masm.andpd(temp5, externalAddress(maskThirtyFiveTanPtr));                               // 0xfffc0000,
+                                                                                                // 0xffffffff,
+                                                                                                // 0x00000000,
+                                                                                                // 0x00000000
+        masm.movdqu(temp3, dest);
+        masm.addq(gpr1, gpr4);
+        masm.subpd(temp2, dest);
+        masm.unpckhpd(dest, dest);
+        masm.divsd(temp6, temp5);
+        masm.subpd(temp2, temp4);
+        masm.movdqu(temp7, new AMD64Address(gpr1, 16));
+        masm.subsd(temp3, temp5);
+        masm.mulpd(temp7, dest);
+        masm.subpd(temp2, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 48));
+        masm.mulpd(temp1, dest);
+        masm.movdqu(temp4, new AMD64Address(gpr1, 96));
+        masm.mulpd(temp4, dest);
+        masm.addsd(temp2, temp3);
+        masm.movdqu(temp3, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp7, new AMD64Address(gpr1, 0));
+        masm.addpd(temp1, new AMD64Address(gpr1, 32));
+        masm.mulpd(temp1, dest);
+        masm.addpd(temp4, new AMD64Address(gpr1, 80));
+        masm.addpd(temp7, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 112));
+        masm.mulpd(temp1, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp4, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 64));
+        masm.mulpd(temp1, dest);
+        masm.addpd(temp7, temp1);
+        masm.movdqu(temp1, temp3);
+        masm.mulpd(temp3, dest);
+        masm.mulsd(dest, dest);
+        masm.mulpd(temp1, new AMD64Address(gpr1, 144));
+        masm.mulpd(temp4, temp3);
+        masm.movdqu(temp3, temp1);
+        masm.addpd(temp7, temp4);
+        masm.movdqu(temp4, temp1);
+        masm.mulsd(dest, temp7);
+        masm.unpckhpd(temp7, temp7);
+        masm.addsd(dest, temp7);
+        masm.unpckhpd(temp1, temp1);
+        masm.addsd(temp3, temp1);
+        masm.subsd(temp4, temp3);
+        masm.addsd(temp1, temp4);
+        masm.movdqu(temp4, temp2);
+        masm.movdq(temp7, new AMD64Address(gpr1, 144));
+        masm.unpckhpd(temp2, temp2);
+        masm.addsd(temp7, new AMD64Address(gpr1, 152));
+        masm.mulsd(temp7, temp2);
+        masm.addsd(temp7, new AMD64Address(gpr1, 136));
+        masm.addsd(temp7, temp1);
+        masm.addsd(dest, temp7);
+        masm.movdq(temp7, externalAddress(onePtr));                                             // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.mulsd(temp4, temp6);
+        masm.movdq(temp2, new AMD64Address(gpr1, 168));
+        masm.andpd(temp2, temp6);
+        masm.mulsd(temp5, temp2);
+        masm.mulsd(temp6, new AMD64Address(gpr1, 160));
+        masm.subsd(temp7, temp5);
+        masm.subsd(temp2, new AMD64Address(gpr1, 128));
+        masm.subsd(temp7, temp4);
+        masm.mulsd(temp7, temp6);
+        masm.movdqu(temp4, temp3);
+        masm.subsd(temp3, temp2);
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp4, temp2);
+        masm.addsd(dest, temp4);
+        masm.subsd(dest, temp7);
+        masm.addsd(dest, temp3);
+        masm.jmp(bb15);
+
+        masm.bind(bb0);
+        masm.jcc(ConditionFlag.Greater, bb1);
+
+        masm.pextrw(gpr1, dest, 3);
+        masm.movl(gpr4, gpr1);
+        masm.andl(gpr1, 32752);
+        masm.jcc(ConditionFlag.Equal, bb2);
+
+        masm.andl(gpr4, 32767);
+        masm.cmpl(gpr4, 15904);
+        masm.jcc(ConditionFlag.Below, bb3);
+
+        masm.movdqu(temp2, dest);
+        masm.movdqu(temp3, dest);
+        masm.movdq(temp1, externalAddress(qElevenTanPtr));                                      // 0xb8fe4d77,
+                                                                                                // 0x3f82609a
+        masm.mulsd(temp2, dest);
+        masm.mulsd(temp3, temp2);
+        masm.mulsd(temp1, temp2);
+        masm.addsd(temp1, externalAddress(qNineTanPtr));                                        // 0xbf847a43,
+                                                                                                // 0x3f9664a0
+        masm.mulsd(temp1, temp2);
+        masm.addsd(temp1, externalAddress(qSevenTanPtr));                                       // 0x52c4c8ab,
+                                                                                                // 0x3faba1ba
+        masm.mulsd(temp1, temp2);
+        masm.addsd(temp1, externalAddress(qFiveTanPtr));                                        // 0x11092746,
+                                                                                                // 0x3fc11111
+        masm.mulsd(temp1, temp2);
+        masm.addsd(temp1, externalAddress(qThreeTanPtr));                                       // 0x55555612,
+                                                                                                // 0x3fd55555
+        masm.mulsd(temp1, temp3);
+        masm.addsd(dest, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb3);
+        masm.movdq(temp3, externalAddress(twoPowFiftyFiveTanPtr));                              // 0x00000000,
+                                                                                                // 0x43600000
+        masm.mulsd(temp3, dest);
+        masm.addsd(dest, temp3);
+        masm.mulsd(dest, externalAddress(twoPowMFiftyFiveTanPtr));                              // 0x00000000,
+                                                                                                // 0x3c800000
+        masm.jmp(bb15);
+
+        masm.bind(bb14);
+        masm.xorpd(temp1, temp1);
+        masm.xorpd(dest, dest);
+        masm.divsd(dest, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb2);
+        masm.movdqu(temp1, dest);
+        masm.mulsd(temp1, temp1);
+        masm.jmp(bb15);
+
+        masm.bind(bb1);
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.Equal, bb14);
+
+        masm.subl(gpr3, 16224);
+        masm.shrl(gpr3, 7);
+        masm.andl(gpr3, 65532);
+        masm.leaq(gpr10, externalAddress(piInvTableTanPtr));
+        masm.addq(gpr3, gpr10);
+        masm.movdq(gpr1, dest);
+        masm.movl(gpr9, new AMD64Address(gpr3, 20));
+        masm.movl(gpr7, new AMD64Address(gpr3, 24));
+        masm.movl(gpr4, gpr1);
+        masm.shrq(gpr1, 21);
+        masm.orl(gpr1, Integer.MIN_VALUE);
+        masm.shrl(gpr1, 11);
+        masm.movl(gpr8, gpr9);
+        masm.imulq(gpr9, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.imulq(gpr7, gpr1);
+        masm.movl(gpr5, new AMD64Address(gpr3, 16));
+        masm.movl(gpr6, new AMD64Address(gpr3, 12));
+        masm.movl(gpr10, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr8, gpr9);
+        masm.addq(gpr10, gpr7);
+        masm.movl(gpr7, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr8, gpr10);
+        masm.movl(gpr9, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr9, gpr1);
+        masm.movl(gpr10, gpr6);
+        masm.imulq(gpr6, gpr4);
+        masm.movl(gpr2, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr8, gpr2);
+        masm.movl(gpr2, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr9, gpr5);
+        masm.addq(gpr9, gpr8);
+        masm.shlq(gpr2, 32);
+        masm.orq(gpr7, gpr2);
+        masm.imulq(gpr10, gpr1);
+        masm.movl(gpr8, new AMD64Address(gpr3, 8));
+        masm.movl(gpr5, new AMD64Address(gpr3, 4));
+        masm.movl(gpr2, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr9, gpr2);
+        masm.movl(gpr2, gpr9);
+        masm.shrq(gpr9, 32);
+        masm.addq(gpr10, gpr6);
+        masm.addq(gpr10, gpr9);
+        masm.movq(gpr6, gpr8);
+        masm.imulq(gpr8, gpr4);
+        masm.imulq(gpr6, gpr1);
+        masm.movl(gpr9, gpr8);
+        masm.shrq(gpr8, 32);
+        masm.addq(gpr10, gpr9);
+        masm.movl(gpr9, gpr10);
+        masm.shrq(gpr10, 32);
+        masm.addq(gpr6, gpr8);
+        masm.addq(gpr6, gpr10);
+        masm.movq(gpr8, gpr5);
+        masm.imulq(gpr5, gpr4);
+        masm.imulq(gpr8, gpr1);
+        masm.shlq(gpr9, 32);
+        masm.orq(gpr9, gpr2);
+        masm.movl(gpr1, new AMD64Address(gpr3, 0));
+        masm.movl(gpr10, gpr5);
+        masm.shrq(gpr5, 32);
+        masm.addq(gpr6, gpr10);
+        masm.movl(gpr10, gpr6);
+        masm.shrq(gpr6, 32);
+        masm.addq(gpr8, gpr5);
+        masm.addq(gpr8, gpr6);
+        masm.imulq(gpr4, gpr1);
+        masm.pextrw(gpr2, dest, 3);
+        masm.leaq(gpr6, externalAddress(piInvTableTanPtr));
+        masm.subq(gpr3, gpr6);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, gpr3);
+        masm.addl(gpr3, 19);
+        masm.movl(gpr5, 32768);
+        masm.andl(gpr5, gpr2);
+        masm.shrl(gpr2, 4);
+        masm.andl(gpr2, 2047);
+        masm.subl(gpr2, 1023);
+        masm.subl(gpr3, gpr2);
+        masm.addq(gpr8, gpr4);
+        masm.movl(gpr4, gpr3);
+        masm.addl(gpr4, 32);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Less, bb5);
+
+        masm.negl(gpr3);
+        masm.addl(gpr3, 29);
+        masm.shll(gpr8);
+        masm.movl(gpr6, gpr8);
+        masm.andl(gpr8, 1073741823);
+        masm.testl(gpr8, 536870912);
+        masm.jcc(ConditionFlag.NotEqual, bb6);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+
+        masm.bind(bb8);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.Equal, bb9);
+
+        masm.bind(bb10);
+        masm.bsrq(gpr10, gpr8);
+        masm.movl(gpr3, 29);
+        masm.subl(gpr3, gpr10);
+        masm.jcc(ConditionFlag.LessEqual, bb11);
+
+        masm.shlq(gpr8);
+        masm.movq(gpr1, gpr9);
+        masm.shlq(gpr9);
+        masm.addl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shrq(gpr1);
+        masm.shrq(gpr7);
+        masm.orq(gpr8, gpr1);
+        masm.orq(gpr9, gpr7);
+
+        masm.bind(bb12);
+        masm.cvtsi2sdq(dest, gpr8);
+        masm.shrq(gpr9, 1);
+        masm.cvtsi2sdq(temp3, gpr9);
+        masm.xorpd(temp4, temp4);
+        masm.shll(gpr4, 4);
+        masm.negl(gpr4);
+        masm.addl(gpr4, 16368);
+        masm.orl(gpr4, gpr5);
+        masm.xorl(gpr4, gpr2);
+        masm.pinsrw(temp4, gpr4, 3);
+        masm.leaq(gpr1, externalAddress(piFourTanPtr));
+        masm.movdq(temp2, new AMD64Address(gpr1, 0));                                           // 0x00000000,
+                                                                                                // 0x3fe921fb,
+        masm.movdq(temp7, new AMD64Address(gpr1, 8));                                           // 0x4611a626,
+                                                                                                // 0x3e85110b
+        masm.xorpd(temp5, temp5);
+        masm.subl(gpr4, 1008);
+        masm.pinsrw(temp5, gpr4, 3);
+        masm.mulsd(dest, temp4);
+        masm.shll(gpr5, 16);
+        masm.sarl(gpr5, 31);
+        masm.mulsd(temp3, temp5);
+        masm.movdqu(temp1, dest);
+        masm.mulsd(dest, temp2);
+        masm.shrl(gpr6, 30);
+        masm.addsd(temp1, temp3);
+        masm.mulsd(temp3, temp2);
+        masm.addl(gpr6, gpr5);
+        masm.xorl(gpr6, gpr5);
+        masm.mulsd(temp7, temp1);
+        masm.movl(gpr1, gpr6);
+        masm.addsd(temp7, temp3);
+        masm.movdqu(temp2, dest);
+        masm.addsd(dest, temp7);
+        masm.subsd(temp2, dest);
+        masm.addsd(temp7, temp2);
+        masm.movdqu(temp1, externalAddress(piThirtyTwoInvTanPtr));                              // 0x6dc9c883,
+                                                                                                // 0x3fe45f30,
+                                                                                                // 0x6dc9c883,
+                                                                                                // 0x40245f30
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(dest, dest);
+        } else {
+            masm.movlhps(dest, dest);
+        }
+        masm.movdqu(temp4, externalAddress(signMaskTanPtr));                                    // 0x00000000,
+                                                                                                // 0x80000000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x80000000
+        masm.andpd(temp4, dest);
+        masm.mulpd(temp1, dest);
+        if (masm.supports(CPUFeature.SSE3)) {
+            masm.movddup(temp7, temp7);
+        } else {
+            masm.movlhps(temp7, temp7);
+        }
+        masm.movdqu(temp5, externalAddress(oneHalfTanPtr));                                     // 0x00000000,
+                                                                                                // 0x3fe00000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x3fe00000
+        masm.movdqu(temp6, externalAddress(mulSixteenPtr));                                     // 0x00000000,
+                                                                                                // 0x40300000,
+                                                                                                // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.por(temp5, temp4);
+        masm.addpd(temp1, temp5);
+        masm.movdqu(temp5, temp1);
+        masm.unpckhpd(temp5, temp5);
+        masm.cvttsd2sil(gpr4, temp5);
+        masm.cvttpd2dq(temp1, temp1);
+        masm.cvtdq2pd(temp1, temp1);
+        masm.mulpd(temp1, temp6);
+        masm.movdqu(temp3, externalAddress(pOneTanPtr));                                        // 0x54444000,
+                                                                                                // 0x3fb921fb,
+                                                                                                // 0x54440000,
+                                                                                                // 0x3fb921fb
+        masm.movdq(temp5, externalAddress(qqTwoTanPtr));                                        // 0x676733af,
+                                                                                                // 0x3d32e7b9
+        masm.shll(gpr1, 4);
+        masm.addl(gpr4, 469248);
+        masm.movdqu(temp4, externalAddress(pTwoTanPtr));                                        // 0x67674000,
+                                                                                                // 0xbd32e7b9,
+                                                                                                // 0x4c4c0000,
+                                                                                                // 0x3d468c23
+        masm.mulpd(temp3, temp1);
+        masm.addl(gpr4, gpr1);
+        masm.andl(gpr4, 31);
+        masm.mulsd(temp5, temp1);
+        masm.movl(gpr3, gpr4);
+        masm.mulpd(temp4, temp1);
+        masm.shll(gpr3, 1);
+        masm.subpd(dest, temp3);
+        masm.mulpd(temp1, externalAddress(pThreeTanPtr));                                       // 0x3707344a,
+                                                                                                // 0x3aa8a2e0,
+                                                                                                // 0x03707345,
+                                                                                                // 0x3ae98a2e
+        masm.addl(gpr4, gpr3);
+        masm.shll(gpr3, 2);
+        masm.addl(gpr4, gpr3);
+        masm.addsd(temp5, dest);
+        masm.movdqu(temp2, dest);
+        masm.subpd(dest, temp4);
+        masm.movdq(temp6, externalAddress(onePtr));                                             // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.shll(gpr4, 4);
+        masm.leaq(gpr1, externalAddress(cTableTanPtr));
+        masm.andpd(temp5, externalAddress(maskThirtyFiveTanPtr));                               // 0xfffc0000,
+                                                                                                // 0xffffffff,
+                                                                                                // 0x00000000,
+                                                                                                // 0x00000000
+        masm.movdqu(temp3, dest);
+        masm.addq(gpr1, gpr4);
+        masm.subpd(temp2, dest);
+        masm.unpckhpd(dest, dest);
+        masm.divsd(temp6, temp5);
+        masm.subpd(temp2, temp4);
+        masm.subsd(temp3, temp5);
+        masm.subpd(temp2, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 48));
+        masm.addpd(temp2, temp7);
+        masm.movdqu(temp7, new AMD64Address(gpr1, 16));
+        masm.mulpd(temp7, dest);
+        masm.movdqu(temp4, new AMD64Address(gpr1, 96));
+        masm.mulpd(temp1, dest);
+        masm.mulpd(temp4, dest);
+        masm.addsd(temp2, temp3);
+        masm.movdqu(temp3, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp7, new AMD64Address(gpr1, 0));
+        masm.addpd(temp1, new AMD64Address(gpr1, 32));
+        masm.mulpd(temp1, dest);
+        masm.addpd(temp4, new AMD64Address(gpr1, 80));
+        masm.addpd(temp7, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 112));
+        masm.mulpd(temp1, dest);
+        masm.mulpd(dest, dest);
+        masm.addpd(temp4, temp1);
+        masm.movdqu(temp1, new AMD64Address(gpr1, 64));
+        masm.mulpd(temp1, dest);
+        masm.addpd(temp7, temp1);
+        masm.movdqu(temp1, temp3);
+        masm.mulpd(temp3, dest);
+        masm.mulsd(dest, dest);
+        masm.mulpd(temp1, new AMD64Address(gpr1, 144));
+        masm.mulpd(temp4, temp3);
+        masm.movdqu(temp3, temp1);
+        masm.addpd(temp7, temp4);
+        masm.movdqu(temp4, temp1);
+        masm.mulsd(dest, temp7);
+        masm.unpckhpd(temp7, temp7);
+        masm.addsd(dest, temp7);
+        masm.unpckhpd(temp1, temp1);
+        masm.addsd(temp3, temp1);
+        masm.subsd(temp4, temp3);
+        masm.addsd(temp1, temp4);
+        masm.movdqu(temp4, temp2);
+        masm.movdq(temp7, new AMD64Address(gpr1, 144));
+        masm.unpckhpd(temp2, temp2);
+        masm.addsd(temp7, new AMD64Address(gpr1, 152));
+        masm.mulsd(temp7, temp2);
+        masm.addsd(temp7, new AMD64Address(gpr1, 136));
+        masm.addsd(temp7, temp1);
+        masm.addsd(dest, temp7);
+        masm.movdq(temp7, externalAddress(onePtr));                                             // 0x00000000,
+                                                                                                // 0x3ff00000
+        masm.mulsd(temp4, temp6);
+        masm.movdq(temp2, new AMD64Address(gpr1, 168));
+        masm.andpd(temp2, temp6);
+        masm.mulsd(temp5, temp2);
+        masm.mulsd(temp6, new AMD64Address(gpr1, 160));
+        masm.subsd(temp7, temp5);
+        masm.subsd(temp2, new AMD64Address(gpr1, 128));
+        masm.subsd(temp7, temp4);
+        masm.mulsd(temp7, temp6);
+        masm.movdqu(temp4, temp3);
+        masm.subsd(temp3, temp2);
+        masm.addsd(temp2, temp3);
+        masm.subsd(temp4, temp2);
+        masm.addsd(dest, temp4);
+        masm.subsd(dest, temp7);
+        masm.addsd(dest, temp3);
+        masm.jmp(bb15);
+
+        masm.bind(bb9);
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.movl(gpr7, 0);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb10);
+
+        masm.addl(gpr4, 64);
+        masm.movq(gpr8, gpr9);
+        masm.movq(gpr9, gpr7);
+        masm.cmpq(gpr8, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb10);
+
+        masm.jmp(bb12);
+
+        masm.bind(bb11);
+        masm.jcc(ConditionFlag.Equal, bb12);
+
+        masm.negl(gpr3);
+        masm.shrq(gpr9);
+        masm.movq(gpr1, gpr8);
+        masm.shrq(gpr8);
+        masm.subl(gpr4, gpr3);
+        masm.negl(gpr3);
+        masm.addl(gpr3, 64);
+        masm.shlq(gpr1);
+        masm.orq(gpr9, gpr1);
+        masm.jmp(bb12);
+
+        masm.bind(bb5);
+        masm.notl(gpr3);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr8);
+        masm.movq(gpr6, gpr8);
+        masm.testl(gpr8, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.NotEqual, bb13);
+
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 0);
+        masm.shrq(gpr6, 2);
+        masm.jmp(bb8);
+
+        masm.bind(bb6);
+        masm.shrl(gpr8);
+        masm.movl(gpr2, 1073741824);
+        masm.shrl(gpr2);
+        masm.shlq(gpr8, 32);
+        masm.orq(gpr8, gpr10);
+        masm.shlq(gpr2, 32);
+        masm.addl(gpr6, 1073741824);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.jmp(bb8);
+
+        masm.bind(bb13);
+        masm.shrl(gpr8);
+        masm.movq(gpr2, 0x100000000L);
+        masm.shrq(gpr2);
+        masm.movl(gpr3, 0);
+        masm.movl(gpr10, 0);
+        masm.subq(gpr3, gpr7);
+        masm.sbbq(gpr10, gpr9);
+        masm.sbbq(gpr2, gpr8);
+        masm.movq(gpr7, gpr3);
+        masm.movq(gpr9, gpr10);
+        masm.movq(gpr8, gpr2);
+        masm.movl(gpr2, 32768);
+        masm.shrq(gpr6, 2);
+        masm.addl(gpr6, 1073741824);
+        masm.jmp(bb8);
+
+        masm.bind(bb15);
+    }
+
+    /*
+     * Copyright (c) 2014, 2016, Intel Corporation. All rights reserved. Intel Math Library (LIBM)
+     * Source Code
+     *
+     * ALGORITHM DESCRIPTION - EXP() ---------------------
+     *
+     * Description: Let K = 64 (table size). x x/log(2) n e = 2 = 2 * T[j] * (1 + P(y)) where x =
+     * m*log(2)/K + y, y in [-log(2)/K..log(2)/K] m = n*K + j, m,n,j - signed integer, j in
+     * [-K/2..K/2] j/K values of 2 are tabulated as T[j] = T_hi[j] ( 1 + T_lo[j]).
+     *
+     * P(y) is a minimax polynomial approximation of exp(x)-1 on small interval
+     * [-log(2)/K..log(2)/K] (were calculated by Maple V).
+     *
+     * To avoid problems with arithmetic overflow and underflow, n n1 n2 value of 2 is safely
+     * computed as 2 * 2 where n1 in [-BIAS/2..BIAS/2] where BIAS is a value of exponent bias.
+     *
+     * Special cases: exp(NaN) = NaN exp(+INF) = +INF exp(-INF) = 0 exp(x) = 1 for subnormals for
+     * finite argument, only exp(0)=1 is exact For IEEE double if x > 709.782712893383973096 then
+     * exp(x) overflow if x < -745.133219101941108420 then exp(x) underflow
+     *
+     */
+
+    private static int[] cvExp = {
+                    0x652b82fe, 0x40571547, 0x652b82fe, 0x40571547, 0xfefa0000,
+                    0x3f862e42, 0xfefa0000, 0x3f862e42, 0xbc9e3b3a, 0x3d1cf79a,
+                    0xbc9e3b3a, 0x3d1cf79a, 0xfffffffe, 0x3fdfffff, 0xfffffffe,
+                    0x3fdfffff, 0xe3289860, 0x3f56c15c, 0x555b9e25, 0x3fa55555,
+                    0xc090cf0f, 0x3f811115, 0x55548ba1, 0x3fc55555
+    };
+
+    private static int[] shifterExp = {
+                    0x00000000, 0x43380000, 0x00000000, 0x43380000
+    };
+
+    private static int[] mMaskExp = {
+                    0xffffffc0, 0x00000000, 0xffffffc0, 0x00000000
+    };
+
+    private static int[] biasExp = {
+                    0x0000ffc0, 0x00000000, 0x0000ffc0, 0x00000000
+    };
+
+    private static int[] tblAddrExp = {
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0e03754d,
+                    0x3cad7bbf, 0x3e778060, 0x00002c9a, 0x3567f613, 0x3c8cd252,
+                    0xd3158574, 0x000059b0, 0x61e6c861, 0x3c60f74e, 0x18759bc8,
+                    0x00008745, 0x5d837b6c, 0x3c979aa6, 0x6cf9890f, 0x0000b558,
+                    0x702f9cd1, 0x3c3ebe3d, 0x32d3d1a2, 0x0000e3ec, 0x1e63bcd8,
+                    0x3ca3516e, 0xd0125b50, 0x00011301, 0x26f0387b, 0x3ca4c554,
+                    0xaea92ddf, 0x0001429a, 0x62523fb6, 0x3ca95153, 0x3c7d517a,
+                    0x000172b8, 0x3f1353bf, 0x3c8b898c, 0xeb6fcb75, 0x0001a35b,
+                    0x3e3a2f5f, 0x3c9aecf7, 0x3168b9aa, 0x0001d487, 0x44a6c38d,
+                    0x3c8a6f41, 0x88628cd6, 0x0002063b, 0xe3a8a894, 0x3c968efd,
+                    0x6e756238, 0x0002387a, 0x981fe7f2, 0x3c80472b, 0x65e27cdd,
+                    0x00026b45, 0x6d09ab31, 0x3c82f7e1, 0xf51fdee1, 0x00029e9d,
+                    0x720c0ab3, 0x3c8b3782, 0xa6e4030b, 0x0002d285, 0x4db0abb6,
+                    0x3c834d75, 0x0a31b715, 0x000306fe, 0x5dd3f84a, 0x3c8fdd39,
+                    0xb26416ff, 0x00033c08, 0xcc187d29, 0x3ca12f8c, 0x373aa9ca,
+                    0x000371a7, 0x738b5e8b, 0x3ca7d229, 0x34e59ff6, 0x0003a7db,
+                    0xa72a4c6d, 0x3c859f48, 0x4c123422, 0x0003dea6, 0x259d9205,
+                    0x3ca8b846, 0x21f72e29, 0x0004160a, 0x60c2ac12, 0x3c4363ed,
+                    0x6061892d, 0x00044e08, 0xdaa10379, 0x3c6ecce1, 0xb5c13cd0,
+                    0x000486a2, 0xbb7aafb0, 0x3c7690ce, 0xd5362a27, 0x0004bfda,
+                    0x9b282a09, 0x3ca083cc, 0x769d2ca6, 0x0004f9b2, 0xc1aae707,
+                    0x3ca509b0, 0x569d4f81, 0x0005342b, 0x18fdd78e, 0x3c933505,
+                    0x36b527da, 0x00056f47, 0xe21c5409, 0x3c9063e1, 0xdd485429,
+                    0x0005ab07, 0x2b64c035, 0x3c9432e6, 0x15ad2148, 0x0005e76f,
+                    0x99f08c0a, 0x3ca01284, 0xb03a5584, 0x0006247e, 0x0073dc06,
+                    0x3c99f087, 0x82552224, 0x00066238, 0x0da05571, 0x3c998d4d,
+                    0x667f3bcc, 0x0006a09e, 0x86ce4786, 0x3ca52bb9, 0x3c651a2e,
+                    0x0006dfb2, 0x206f0dab, 0x3ca32092, 0xe8ec5f73, 0x00071f75,
+                    0x8e17a7a6, 0x3ca06122, 0x564267c8, 0x00075feb, 0x461e9f86,
+                    0x3ca244ac, 0x73eb0186, 0x0007a114, 0xabd66c55, 0x3c65ebe1,
+                    0x36cf4e62, 0x0007e2f3, 0xbbff67d0, 0x3c96fe9f, 0x994cce12,
+                    0x00082589, 0x14c801df, 0x3c951f14, 0x9b4492ec, 0x000868d9,
+                    0xc1f0eab4, 0x3c8db72f, 0x422aa0db, 0x0008ace5, 0x59f35f44,
+                    0x3c7bf683, 0x99157736, 0x0008f1ae, 0x9c06283c, 0x3ca360ba,
+                    0xb0cdc5e4, 0x00093737, 0x20f962aa, 0x3c95e8d1, 0x9fde4e4f,
+                    0x00097d82, 0x2b91ce27, 0x3c71affc, 0x82a3f090, 0x0009c491,
+                    0x589a2ebd, 0x3c9b6d34, 0x7b5de564, 0x000a0c66, 0x9ab89880,
+                    0x3c95277c, 0xb23e255c, 0x000a5503, 0x6e735ab3, 0x3c846984,
+                    0x5579fdbf, 0x000a9e6b, 0x92cb3387, 0x3c8c1a77, 0x995ad3ad,
+                    0x000ae89f, 0xdc2d1d96, 0x3ca22466, 0xb84f15fa, 0x000b33a2,
+                    0xb19505ae, 0x3ca1112e, 0xf2fb5e46, 0x000b7f76, 0x0a5fddcd,
+                    0x3c74ffd7, 0x904bc1d2, 0x000bcc1e, 0x30af0cb3, 0x3c736eae,
+                    0xdd85529c, 0x000c199b, 0xd10959ac, 0x3c84e08f, 0x2e57d14b,
+                    0x000c67f1, 0x6c921968, 0x3c676b2c, 0xdcef9069, 0x000cb720,
+                    0x36df99b3, 0x3c937009, 0x4a07897b, 0x000d072d, 0xa63d07a7,
+                    0x3c74a385, 0xdcfba487, 0x000d5818, 0xd5c192ac, 0x3c8e5a50,
+                    0x03db3285, 0x000da9e6, 0x1c4a9792, 0x3c98bb73, 0x337b9b5e,
+                    0x000dfc97, 0x603a88d3, 0x3c74b604, 0xe78b3ff6, 0x000e502e,
+                    0x92094926, 0x3c916f27, 0xa2a490d9, 0x000ea4af, 0x41aa2008,
+                    0x3c8ec3bc, 0xee615a27, 0x000efa1b, 0x31d185ee, 0x3c8a64a9,
+                    0x5b6e4540, 0x000f5076, 0x4d91cd9d, 0x3c77893b, 0x819e90d8,
+                    0x000fa7c1
+    };
+
+    private static int[] allOnesExp = {
+                    0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+    };
+
+    private static int[] expBias = {
+                    0x00000000, 0x3ff00000, 0x00000000, 0x3ff00000
+    };
+
+    private static int[] xMaxExp = {
+                    0xffffffff, 0x7fefffff
+    };
+
+    private static int[] xMinExp = {
+                    0x00000000, 0x00100000
+    };
+
+    private static int[] infExp = {
+                    0x00000000, 0x7ff00000
+    };
+
+    private static int[] zeroExp = {
+                    0x00000000, 0x00000000
+    };
+
+    public void expIntrinsic(Register dest, Register value, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        ArrayDataPointerConstant onePtr = new ArrayDataPointerConstant(one, 16);
+        ArrayDataPointerConstant cvExpPtr = new ArrayDataPointerConstant(cvExp, 16);
+        ArrayDataPointerConstant shifterExpPtr = new ArrayDataPointerConstant(shifterExp, 8);
+        ArrayDataPointerConstant mMaskExpPtr = new ArrayDataPointerConstant(mMaskExp, 16);
+        ArrayDataPointerConstant biasExpPtr = new ArrayDataPointerConstant(biasExp, 16);
+        ArrayDataPointerConstant tblAddrExpPtr = new ArrayDataPointerConstant(tblAddrExp, 16);
+        ArrayDataPointerConstant expBiasPtr = new ArrayDataPointerConstant(expBias, 8);
+        ArrayDataPointerConstant xMaxExpPtr = new ArrayDataPointerConstant(xMaxExp, 8);
+        ArrayDataPointerConstant xMinExpPtr = new ArrayDataPointerConstant(xMinExp, 8);
+        ArrayDataPointerConstant infExpPtr = new ArrayDataPointerConstant(infExp, 8);
+        ArrayDataPointerConstant zeroExpPtr = new ArrayDataPointerConstant(zeroExp, 8);
+        ArrayDataPointerConstant allOnesExpPtr = new ArrayDataPointerConstant(allOnesExp, 8);
+
+        Label bb0 = new Label();
+        Label bb1 = new Label();
+        Label bb2 = new Label();
+        Label bb3 = new Label();
+        Label bb4 = new Label();
+        Label bb5 = new Label();
+        Label bb7 = new Label();
+        Label bb8 = new Label();
+        Label bb9 = new Label();
+        Label bb10 = new Label();
+        Label bb11 = new Label();
+        Label bb12 = new Label();
+        Label bb14 = new Label();
+
+        Register gpr1 = asRegister(gpr1Temp, AMD64Kind.QWORD);
+        Register gpr2 = asRegister(gpr2Temp, AMD64Kind.QWORD);
+        Register gpr3 = asRegister(rcxTemp, AMD64Kind.QWORD);
+        Register gpr4 = asRegister(gpr4Temp, AMD64Kind.QWORD);
+        Register gpr5 = asRegister(gpr5Temp, AMD64Kind.QWORD);
+
+        Register temp1 = asRegister(xmm1Temp, AMD64Kind.DOUBLE);
+        Register temp2 = asRegister(xmm2Temp, AMD64Kind.DOUBLE);
+        Register temp3 = asRegister(xmm3Temp, AMD64Kind.DOUBLE);
+        Register temp4 = asRegister(xmm4Temp, AMD64Kind.DOUBLE);
+        Register temp5 = asRegister(xmm5Temp, AMD64Kind.DOUBLE);
+        Register temp6 = asRegister(xmm6Temp, AMD64Kind.DOUBLE);
+        Register temp7 = asRegister(xmm7Temp, AMD64Kind.DOUBLE);
+        Register temp8 = asRegister(xmm8Temp, AMD64Kind.DOUBLE);
+        Register temp9 = asRegister(xmm9Temp, AMD64Kind.DOUBLE);
+        Register temp10 = asRegister(xmm10Temp, AMD64Kind.DOUBLE);
+
+        AMD64Address stackSlot = (AMD64Address) crb.asAddress(stackTemp);
+
+        setCrb(crb);
+        masm.movsd(stackSlot, value);
+        if (dest.encoding != value.encoding) {
+            masm.movdqu(dest, value);
+        }
+
+        masm.movdqu(temp9, externalAddress(mMaskExpPtr));                                // 0xffffffc0,
+                                                                                         // 0x00000000,
+                                                                                         // 0xffffffc0,
+                                                                                         // 0x00000000
+        masm.movdqu(temp10, externalAddress(biasExpPtr));                                // 0x0000ffc0,
+                                                                                         // 0x00000000,
+                                                                                         // 0x0000ffc0,
+                                                                                         // 0x00000000
+        masm.unpcklpd(dest, dest);
+        masm.leaq(gpr5, stackSlot);
+        masm.leaq(gpr2, externalAddress(cvExpPtr));
+        masm.movdqu(temp1, new AMD64Address(gpr2, 0));                                   // 0x652b82fe,
+                                                                                         // 0x40571547,
+                                                                                         // 0x652b82fe,
+                                                                                         // 0x40571547
+        masm.movdqu(temp6, externalAddress(shifterExpPtr));                              // 0x00000000,
+                                                                                         // 0x43380000,
+                                                                                         // 0x00000000,
+                                                                                         // 0x43380000
+        masm.movdqu(temp2, new AMD64Address(gpr2, 16));                                  // 0xfefa0000,
+                                                                                         // 0x3f862e42,
+                                                                                         // 0xfefa0000,
+                                                                                         // 0x3f862e42
+        masm.movdqu(temp3, new AMD64Address(gpr2, 32));                                  // 0xbc9e3b3a,
+                                                                                         // 0x3d1cf79a,
+                                                                                         // 0xbc9e3b3a,
+                                                                                         // 0x3d1cf79a
+        masm.pextrw(gpr1, dest, 3);
+        masm.andl(gpr1, 32767);
+        masm.movl(gpr4, 16527);
+        masm.subl(gpr4, gpr1);
+        masm.subl(gpr1, 15504);
+        masm.orl(gpr4, gpr1);
+        masm.cmpl(gpr4, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.AboveEqual, bb0);
+
+        masm.leaq(gpr4, externalAddress(tblAddrExpPtr));
+        masm.movdqu(temp8, new AMD64Address(gpr2, 48));                                  // 0xfffffffe,
+                                                                                         // 0x3fdfffff,
+                                                                                         // 0xfffffffe,
+                                                                                         // 0x3fdfffff
+        masm.movdqu(temp4, new AMD64Address(gpr2, 64));                                  // 0xe3289860,
+                                                                                         // 0x3f56c15c,
+                                                                                         // 0x555b9e25,
+                                                                                         // 0x3fa55555
+        masm.movdqu(temp5, new AMD64Address(gpr2, 80));                                  // 0xc090cf0f,
+                                                                                         // 0x3f811115,
+                                                                                         // 0x55548ba1,
+                                                                                         // 0x3fc55555
+        masm.mulpd(temp1, dest);
+        masm.addpd(temp1, temp6);
+        masm.movapd(temp7, temp1);
+        masm.movdl(gpr1, temp1);
+        masm.pand(temp7, temp9);
+        masm.subpd(temp1, temp6);
+        masm.mulpd(temp2, temp1);
+        masm.mulpd(temp3, temp1);
+        masm.paddq(temp7, temp10);
+        masm.subpd(dest, temp2);
+        masm.movl(gpr3, gpr1);
+        masm.andl(gpr3, 63);
+        masm.shll(gpr3, 4);
+        masm.movdqu(temp2, new AMD64Address(gpr3, gpr4, Scale.Times1, 0));
+        masm.sarl(gpr1, 6);
+        masm.psllq(temp7, 46);
+        masm.subpd(dest, temp3);
+        masm.mulpd(temp4, dest);
+        masm.movl(gpr4, gpr1);
+        masm.movapd(temp6, dest);
+        masm.movapd(temp1, dest);
+        masm.mulpd(temp6, temp6);
+        masm.mulpd(dest, temp6);
+        masm.addpd(temp5, temp4);
+        masm.mulsd(dest, temp6);
+        masm.mulpd(temp6, temp8);
+        masm.addsd(temp1, temp2);
+        masm.unpckhpd(temp2, temp2);
+        masm.mulpd(dest, temp5);
+        masm.addsd(temp1, dest);
+        masm.por(temp2, temp7);
+        masm.unpckhpd(dest, dest);
+        masm.addsd(dest, temp1);
+        masm.addsd(dest, temp6);
+        masm.addl(gpr4, 894);
+        masm.cmpl(gpr4, 1916);
+        masm.jcc(ConditionFlag.Above, bb1);
+
+        masm.mulsd(dest, temp2);
+        masm.addsd(dest, temp2);
+        masm.jmp(bb14);
+
+        masm.bind(bb1);
+        masm.movdqu(temp6, externalAddress(expBiasPtr));                                 // 0x00000000,
+                                                                                         // 0x3ff00000,
+                                                                                         // 0x00000000,
+                                                                                         // 0x3ff00000
+        masm.xorpd(temp3, temp3);
+        masm.movdqu(temp4, externalAddress(allOnesExpPtr));                              // 0xffffffff,
+                                                                                         // 0xffffffff,
+                                                                                         // 0xffffffff,
+                                                                                         // 0xffffffff
+        masm.movl(gpr4, -1022);
+        masm.subl(gpr4, gpr1);
+        masm.movdl(temp5, gpr4);
+        masm.psllq(temp4, temp5);
+        masm.movl(gpr3, gpr1);
+        masm.sarl(gpr1, 1);
+        masm.pinsrw(temp3, gpr1, 3);
+        masm.psllq(temp3, 4);
+        masm.psubd(temp2, temp3);
+        masm.mulsd(dest, temp2);
+        masm.cmpl(gpr4, 52);
+        masm.jcc(ConditionFlag.Greater, bb2);
+
+        masm.pand(temp4, temp2);
+        masm.paddd(temp3, temp6);
+        masm.subsd(temp2, temp4);
+        masm.addsd(dest, temp2);
+        masm.cmpl(gpr3, 1023);
+        masm.jcc(ConditionFlag.GreaterEqual, bb3);
+
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32768);
+        masm.orl(gpr4, gpr3);
+        masm.cmpl(gpr4, 0);
+        masm.jcc(ConditionFlag.Equal, bb4);
+
+        masm.movapd(temp6, dest);
+        masm.addsd(dest, temp4);
+        masm.mulsd(dest, temp3);
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 0);
+        masm.jcc(ConditionFlag.Equal, bb5);
+
+        masm.jmp(bb14);
+
+        masm.bind(bb5);
+        masm.mulsd(temp6, temp3);
+        masm.mulsd(temp4, temp3);
+        masm.movdqu(dest, temp6);
+        masm.pxor(temp6, temp4);
+        masm.psrad(temp6, 31);
+        masm.pshufd(temp6, temp6, 85);
+        masm.psllq(dest, 1);
+        masm.psrlq(dest, 1);
+        masm.pxor(dest, temp6);
+        masm.psrlq(temp6, 63);
+        masm.paddq(dest, temp6);
+        masm.paddq(dest, temp4);
+        masm.jmp(bb14);
+
+        masm.bind(bb4);
+        masm.addsd(dest, temp4);
+        masm.mulsd(dest, temp3);
+        masm.jmp(bb14);
+
+        masm.bind(bb3);
+        masm.addsd(dest, temp4);
+        masm.mulsd(dest, temp3);
+        masm.pextrw(gpr3, dest, 3);
+        masm.andl(gpr3, 32752);
+        masm.cmpl(gpr3, 32752);
+        masm.jcc(ConditionFlag.AboveEqual, bb7);
+
+        masm.jmp(bb14);
+
+        masm.bind(bb2);
+        masm.paddd(temp3, temp6);
+        masm.addpd(dest, temp2);
+        masm.mulsd(dest, temp3);
+        masm.jmp(bb14);
+
+        masm.bind(bb8);
+        masm.movsd(dest, externalAddress(xMaxExpPtr));                                   // 0xffffffff,
+                                                                                         // 0x7fefffff
+        masm.movsd(temp8, externalAddress(xMinExpPtr));                                  // 0x00000000,
+                                                                                         // 0x00100000
+        masm.cmpl(gpr1, 2146435072);
+        masm.jcc(ConditionFlag.AboveEqual, bb9);
+
+        masm.movl(gpr1, new AMD64Address(gpr5, 4));
+        masm.cmpl(gpr1, Integer.MIN_VALUE);
+        masm.jcc(ConditionFlag.AboveEqual, bb10);
+
+        masm.mulsd(dest, dest);
+
+        masm.bind(bb7);
+        masm.jmp(bb14);
+
+        masm.bind(bb10);
+        masm.mulsd(dest, temp8);
+        masm.jmp(bb14);
+
+        masm.bind(bb9);
+        masm.movl(gpr4, stackSlot);
+        masm.cmpl(gpr1, 2146435072);
+        masm.jcc(ConditionFlag.Above, bb11);
+
+        masm.cmpl(gpr4, 0);
+        masm.jcc(ConditionFlag.NotEqual, bb11);
+
+        masm.movl(gpr1, new AMD64Address(gpr5, 4));
+        masm.cmpl(gpr1, 2146435072);
+        masm.jcc(ConditionFlag.NotEqual, bb12);
+
+        masm.movsd(dest, externalAddress(infExpPtr));                                    // 0x00000000,
+                                                                                         // 0x7ff00000
+        masm.jmp(bb14);
+
+        masm.bind(bb12);
+        masm.movsd(dest, externalAddress(zeroExpPtr));                                   // 0x00000000,
+                                                                                         // 0x00000000
+        masm.jmp(bb14);
+
+        masm.bind(bb11);
+        masm.movsd(dest, stackSlot);
+        masm.addsd(dest, dest);
+        masm.jmp(bb14);
+
+        masm.bind(bb0);
+        masm.movl(gpr1, new AMD64Address(gpr5, 4));
+        masm.andl(gpr1, 2147483647);
+        masm.cmpl(gpr1, 1083179008);
+        masm.jcc(ConditionFlag.AboveEqual, bb8);
+
+        masm.addsd(dest, externalAddress(onePtr));                                       // 0x00000000,
+                                                                                         // 0x3ff00000
+        masm.bind(bb14);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java
new file mode 100644
index 0000000..e2bdfd3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java
@@ -0,0 +1,721 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static java.lang.Double.doubleToRawLongBits;
+import static java.lang.Float.floatToRawIntBits;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.NullCheck;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64Move {
+
+    private abstract static class AbstractMoveOp extends AMD64LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<AbstractMoveOp> TYPE = LIRInstructionClass.create(AbstractMoveOp.class);
+
+        private AMD64Kind moveKind;
+
+        protected AbstractMoveOp(LIRInstructionClass<? extends AbstractMoveOp> c, AMD64Kind moveKind) {
+            super(c);
+            this.moveKind = moveKind;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            move(moveKind, crb, masm, getResult(), getInput());
+        }
+    }
+
+    @Opcode("MOVE")
+    public static final class MoveToRegOp extends AbstractMoveOp {
+        public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue input;
+
+        public MoveToRegOp(AMD64Kind moveKind, AllocatableValue result, AllocatableValue input) {
+            super(TYPE, moveKind);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    @Opcode("MOVE")
+    public static final class MoveFromRegOp extends AbstractMoveOp {
+        public static final LIRInstructionClass<MoveFromRegOp> TYPE = LIRInstructionClass.create(MoveFromRegOp.class);
+
+        @Def({REG, STACK}) protected AllocatableValue result;
+        @Use({REG, HINT}) protected AllocatableValue input;
+
+        public MoveFromRegOp(AMD64Kind moveKind, AllocatableValue result, AllocatableValue input) {
+            super(TYPE, moveKind);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    @Opcode("MOVE")
+    public static class MoveFromConstOp extends AMD64LIRInstruction implements LoadConstantOp {
+        public static final LIRInstructionClass<MoveFromConstOp> TYPE = LIRInstructionClass.create(MoveFromConstOp.class);
+
+        @Def({REG, STACK}) protected AllocatableValue result;
+        private final JavaConstant input;
+
+        public MoveFromConstOp(AllocatableValue result, JavaConstant input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, asRegister(result), input);
+            } else {
+                assert isStackSlot(result);
+                const2stack(crb, masm, result, input);
+            }
+        }
+
+        @Override
+        public Constant getConstant() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    @Opcode("STACKMOVE")
+    public static final class AMD64StackMove extends AMD64LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<AMD64StackMove> TYPE = LIRInstructionClass.create(AMD64StackMove.class);
+
+        @Def({STACK}) protected AllocatableValue result;
+        @Use({STACK, HINT}) protected AllocatableValue input;
+        @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot;
+
+        private Register scratch;
+
+        public AMD64StackMove(AllocatableValue result, AllocatableValue input, Register scratch, AllocatableValue backupSlot) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.backupSlot = backupSlot;
+            this.scratch = scratch;
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        public Register getScratchRegister() {
+            return scratch;
+        }
+
+        public AllocatableValue getBackupSlot() {
+            return backupSlot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Kind backupKind = (AMD64Kind) backupSlot.getPlatformKind();
+            if (backupKind.isXMM()) {
+                // graal doesn't use vector values, so it's safe to backup using DOUBLE
+                backupKind = AMD64Kind.DOUBLE;
+            }
+
+            // backup scratch register
+            reg2stack(backupKind, crb, masm, backupSlot, scratch);
+            // move stack slot
+            stack2reg((AMD64Kind) getInput().getPlatformKind(), crb, masm, scratch, getInput());
+            reg2stack((AMD64Kind) getResult().getPlatformKind(), crb, masm, getResult(), scratch);
+            // restore scratch register
+            stack2reg(backupKind, crb, masm, scratch, backupSlot);
+        }
+    }
+
+    @Opcode("MULTISTACKMOVE")
+    public static final class AMD64MultiStackMove extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<AMD64MultiStackMove> TYPE = LIRInstructionClass.create(AMD64MultiStackMove.class);
+
+        @Def({STACK}) protected AllocatableValue[] results;
+        @Use({STACK}) protected Value[] inputs;
+        @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue backupSlot;
+
+        private Register scratch;
+
+        public AMD64MultiStackMove(AllocatableValue[] results, Value[] inputs, Register scratch, AllocatableValue backupSlot) {
+            super(TYPE);
+            this.results = results;
+            this.inputs = inputs;
+            this.backupSlot = backupSlot;
+            this.scratch = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Kind backupKind = (AMD64Kind) backupSlot.getPlatformKind();
+            if (backupKind.isXMM()) {
+                // graal doesn't use vector values, so it's safe to backup using DOUBLE
+                backupKind = AMD64Kind.DOUBLE;
+            }
+
+            // backup scratch register
+            move(backupKind, crb, masm, backupSlot, scratch.asValue(backupSlot.getValueKind()));
+            for (int i = 0; i < results.length; i++) {
+                Value input = inputs[i];
+                AllocatableValue result = results[i];
+                // move stack slot
+                move((AMD64Kind) input.getPlatformKind(), crb, masm, scratch.asValue(input.getValueKind()), input);
+                move((AMD64Kind) result.getPlatformKind(), crb, masm, result, scratch.asValue(result.getValueKind()));
+            }
+            // restore scratch register
+            move(backupKind, crb, masm, scratch.asValue(backupSlot.getValueKind()), backupSlot);
+        }
+    }
+
+    @Opcode("STACKMOVE")
+    public static final class AMD64PushPopStackMove extends AMD64LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<AMD64PushPopStackMove> TYPE = LIRInstructionClass.create(AMD64PushPopStackMove.class);
+
+        @Def({STACK}) protected AllocatableValue result;
+        @Use({STACK, HINT}) protected AllocatableValue input;
+        private final OperandSize size;
+
+        public AMD64PushPopStackMove(OperandSize size, AllocatableValue result, AllocatableValue input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.size = size;
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64MOp.PUSH.emit(masm, size, (AMD64Address) crb.asAddress(input));
+            AMD64MOp.POP.emit(masm, size, (AMD64Address) crb.asAddress(result));
+        }
+    }
+
+    public static final class LeaOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<LeaOp> TYPE = LIRInstructionClass.create(LeaOp.class);
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address;
+
+        public LeaOp(AllocatableValue result, AMD64AddressValue address) {
+            super(TYPE);
+            this.result = result;
+            this.address = address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.leaq(asRegister(result, AMD64Kind.QWORD), address.toAddress());
+        }
+    }
+
+    public static final class LeaDataOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<LeaDataOp> TYPE = LIRInstructionClass.create(LeaDataOp.class);
+
+        @Def({REG}) protected AllocatableValue result;
+        private final DataPointerConstant data;
+
+        public LeaDataOp(AllocatableValue result, DataPointerConstant data) {
+            super(TYPE);
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.leaq(asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(data));
+        }
+    }
+
+    public static final class StackLeaOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<StackLeaOp> TYPE = LIRInstructionClass.create(StackLeaOp.class);
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot;
+
+        public StackLeaOp(AllocatableValue result, AllocatableValue slot) {
+            super(TYPE);
+            this.result = result;
+            this.slot = slot;
+            assert slot instanceof VirtualStackSlot || slot instanceof StackSlot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.leaq(asRegister(result, AMD64Kind.QWORD), (AMD64Address) crb.asAddress(slot));
+        }
+    }
+
+    public static final class MembarOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
+
+        private final int barriers;
+
+        public MembarOp(final int barriers) {
+            super(TYPE);
+            this.barriers = barriers;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            masm.membar(barriers);
+        }
+    }
+
+    public static final class NullCheckOp extends AMD64LIRInstruction implements NullCheck {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
+
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
+        @State protected LIRFrameState state;
+
+        public NullCheckOp(AMD64AddressValue address, LIRFrameState state) {
+            super(TYPE);
+            this.address = address;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            crb.recordImplicitException(masm.position(), state);
+            masm.nullCheck(address.toAddress());
+        }
+
+        @Override
+        public Value getCheckedValue() {
+            return address.base;
+        }
+
+        @Override
+        public LIRFrameState getState() {
+            return state;
+        }
+    }
+
+    @Opcode("CAS")
+    public static final class CompareAndSwapOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class);
+
+        private final AMD64Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
+        @Use protected AllocatableValue cmpValue;
+        @Use protected AllocatableValue newValue;
+
+        public CompareAndSwapOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
+            super(TYPE);
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.cmpValue = cmpValue;
+            this.newValue = newValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            assert asRegister(cmpValue).equals(AMD64.rax) && asRegister(result).equals(AMD64.rax);
+
+            if (crb.target.isMP) {
+                masm.lock();
+            }
+            switch (accessKind) {
+                case DWORD:
+                    masm.cmpxchgl(asRegister(newValue), address.toAddress());
+                    break;
+                case QWORD:
+                    masm.cmpxchgq(asRegister(newValue), address.toAddress());
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("ATOMIC_READ_AND_ADD")
+    public static final class AtomicReadAndAddOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<AtomicReadAndAddOp> TYPE = LIRInstructionClass.create(AtomicReadAndAddOp.class);
+
+        private final AMD64Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Alive({COMPOSITE}) protected AMD64AddressValue address;
+        @Use protected AllocatableValue delta;
+
+        public AtomicReadAndAddOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue delta) {
+            super(TYPE);
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.delta = delta;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            move(accessKind, crb, masm, result, delta);
+            if (crb.target.isMP) {
+                masm.lock();
+            }
+            switch (accessKind) {
+                case DWORD:
+                    masm.xaddl(address.toAddress(), asRegister(result));
+                    break;
+                case QWORD:
+                    masm.xaddq(address.toAddress(), asRegister(result));
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("ATOMIC_READ_AND_WRITE")
+    public static final class AtomicReadAndWriteOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<AtomicReadAndWriteOp> TYPE = LIRInstructionClass.create(AtomicReadAndWriteOp.class);
+
+        private final AMD64Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Alive({COMPOSITE}) protected AMD64AddressValue address;
+        @Use protected AllocatableValue newValue;
+
+        public AtomicReadAndWriteOp(AMD64Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue newValue) {
+            super(TYPE);
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.newValue = newValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            move(accessKind, crb, masm, result, newValue);
+            switch (accessKind) {
+                case DWORD:
+                    masm.xchgl(asRegister(result), address.toAddress());
+                    break;
+                case QWORD:
+                    masm.xchgq(asRegister(result), address.toAddress());
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static void move(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Value input) {
+        move((AMD64Kind) result.getPlatformKind(), crb, masm, result, input);
+    }
+
+    public static void move(AMD64Kind moveKind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Value input) {
+        if (isRegister(input)) {
+            if (isRegister(result)) {
+                reg2reg(moveKind, masm, result, input);
+            } else if (isStackSlot(result)) {
+                reg2stack(moveKind, crb, masm, result, asRegister(input));
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else if (isStackSlot(input)) {
+            if (isRegister(result)) {
+                stack2reg(moveKind, crb, masm, asRegister(result), input);
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else if (isJavaConstant(input)) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, asRegister(result), asJavaConstant(input));
+            } else if (isStackSlot(result)) {
+                const2stack(crb, masm, result, asJavaConstant(input));
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static void reg2reg(AMD64Kind kind, AMD64MacroAssembler masm, Value result, Value input) {
+        if (asRegister(input).equals(asRegister(result))) {
+            return;
+        }
+        switch (kind) {
+            case BYTE:
+            case WORD:
+            case DWORD:
+                masm.movl(asRegister(result), asRegister(input));
+                break;
+            case QWORD:
+                masm.movq(asRegister(result), asRegister(input));
+                break;
+            case SINGLE:
+                masm.movflt(asRegister(result, AMD64Kind.SINGLE), asRegister(input, AMD64Kind.SINGLE));
+                break;
+            case DOUBLE:
+                masm.movdbl(asRegister(result, AMD64Kind.DOUBLE), asRegister(input, AMD64Kind.DOUBLE));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("kind=" + kind);
+        }
+    }
+
+    public static void reg2stack(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Register input) {
+        AMD64Address dest = (AMD64Address) crb.asAddress(result);
+        switch (kind) {
+            case BYTE:
+                masm.movb(dest, input);
+                break;
+            case WORD:
+                masm.movw(dest, input);
+                break;
+            case DWORD:
+                masm.movl(dest, input);
+                break;
+            case QWORD:
+                masm.movq(dest, input);
+                break;
+            case SINGLE:
+                masm.movflt(dest, input);
+                break;
+            case DOUBLE:
+                masm.movsd(dest, input);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public static void stack2reg(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Value input) {
+        AMD64Address src = (AMD64Address) crb.asAddress(input);
+        switch (kind) {
+            case BYTE:
+                masm.movsbl(result, src);
+                break;
+            case WORD:
+                masm.movswl(result, src);
+                break;
+            case DWORD:
+                masm.movl(result, src);
+                break;
+            case QWORD:
+                masm.movq(result, src);
+                break;
+            case SINGLE:
+                masm.movflt(result, src);
+                break;
+            case DOUBLE:
+                masm.movdbl(result, src);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, JavaConstant input) {
+        /*
+         * Note: we use the kind of the input operand (and not the kind of the result operand)
+         * because they don't match in all cases. For example, an object constant can be loaded to a
+         * long register when unsafe casts occurred (e.g., for a write barrier where arithmetic
+         * operations are then performed on the pointer).
+         */
+        switch (input.getJavaKind().getStackKind()) {
+            case Int:
+                // Do not optimize with an XOR as this instruction may be between
+                // a CMP and a Jcc in which case the XOR will modify the condition
+                // flags and interfere with the Jcc.
+                masm.movl(result, input.asInt());
+
+                break;
+            case Long:
+                // Do not optimize with an XOR as this instruction may be between
+                // a CMP and a Jcc in which case the XOR will modify the condition
+                // flags and interfere with the Jcc.
+                if (input.asLong() == (int) input.asLong()) {
+                    // Sign extended to long
+                    masm.movslq(result, (int) input.asLong());
+                } else if ((input.asLong() & 0xFFFFFFFFL) == input.asLong()) {
+                    // Zero extended to long
+                    masm.movl(result, (int) input.asLong());
+                } else {
+                    masm.movq(result, input.asLong());
+                }
+                break;
+            case Float:
+                // This is *not* the same as 'constant == 0.0f' in the case where constant is -0.0f
+                if (Float.floatToRawIntBits(input.asFloat()) == Float.floatToRawIntBits(0.0f)) {
+                    masm.xorps(result, result);
+                } else {
+                    masm.movflt(result, (AMD64Address) crb.asFloatConstRef(input));
+                }
+                break;
+            case Double:
+                // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d
+                if (Double.doubleToRawLongBits(input.asDouble()) == Double.doubleToRawLongBits(0.0d)) {
+                    masm.xorpd(result, result);
+                } else {
+                    masm.movdbl(result, (AMD64Address) crb.asDoubleConstRef(input));
+                }
+                break;
+            case Object:
+                // Do not optimize with an XOR as this instruction may be between
+                // a CMP and a Jcc in which case the XOR will modify the condition
+                // flags and interfere with the Jcc.
+                if (input.isNull()) {
+                    masm.movq(result, 0x0L);
+                } else if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(input);
+                    masm.movq(result, 0xDEADDEADDEADDEADL);
+                } else {
+                    masm.movq(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0));
+                }
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public static void const2stack(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, JavaConstant input) {
+        AMD64Address dest = (AMD64Address) crb.asAddress(result);
+        final long imm;
+        switch (input.getJavaKind().getStackKind()) {
+            case Int:
+                imm = input.asInt();
+                break;
+            case Long:
+                imm = input.asLong();
+                break;
+            case Float:
+                imm = floatToRawIntBits(input.asFloat());
+                break;
+            case Double:
+                imm = doubleToRawLongBits(input.asDouble());
+                break;
+            case Object:
+                if (input.isNull()) {
+                    imm = 0;
+                } else {
+                    throw GraalError.shouldNotReachHere("Non-null object constants must be in register");
+                }
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+
+        switch ((AMD64Kind) result.getPlatformKind()) {
+            case BYTE:
+                assert NumUtil.isByte(imm) : "Is not in byte range: " + imm;
+                AMD64MIOp.MOVB.emit(masm, OperandSize.BYTE, dest, (int) imm);
+                break;
+            case WORD:
+                assert NumUtil.isShort(imm) : "Is not in short range: " + imm;
+                AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm);
+                break;
+            case DWORD:
+            case SINGLE:
+                assert NumUtil.isInt(imm) : "Is not in int range: " + imm;
+                masm.movl(dest, (int) imm);
+                break;
+            case QWORD:
+            case DOUBLE:
+                masm.movlong(dest, imm);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("Unknown result Kind: " + result.getPlatformKind());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MulDivOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MulDivOp.java
new file mode 100644
index 0000000..697e686
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MulDivOp.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.DIV;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.IDIV;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.IMUL;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.MUL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * AMD64 mul/div operation. This operation has a single operand for the second input. The first
+ * input must be in RAX for mul and in RDX:RAX for div. The result is in RDX:RAX.
+ */
+public class AMD64MulDivOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MulDivOp> TYPE = LIRInstructionClass.create(AMD64MulDivOp.class);
+
+    @Opcode private final AMD64MOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue highResult;
+    @Def({REG}) protected AllocatableValue lowResult;
+
+    @Use({REG, ILLEGAL}) protected AllocatableValue highX;
+    @Use({REG}) protected AllocatableValue lowX;
+
+    @Use({REG, STACK}) protected AllocatableValue y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue x, AllocatableValue y) {
+        this(opcode, size, resultKind, Value.ILLEGAL, x, y, null);
+    }
+
+    public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue highX, AllocatableValue lowX, AllocatableValue y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.highResult = AMD64.rdx.asValue(resultKind);
+        this.lowResult = AMD64.rax.asValue(resultKind);
+
+        this.highX = highX;
+        this.lowX = lowX;
+
+        this.y = y;
+
+        this.state = state;
+    }
+
+    public AllocatableValue getHighResult() {
+        return highResult;
+    }
+
+    public AllocatableValue getLowResult() {
+        return lowResult;
+    }
+
+    public AllocatableValue getQuotient() {
+        return lowResult;
+    }
+
+    public AllocatableValue getRemainder() {
+        return highResult;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        if (isRegister(y)) {
+            opcode.emit(masm, size, asRegister(y));
+        } else {
+            assert isStackSlot(y);
+            opcode.emit(masm, size, (AMD64Address) crb.asAddress(y));
+        }
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(highResult).equals(AMD64.rdx);
+        assert asRegister(lowResult).equals(AMD64.rax);
+
+        assert asRegister(lowX).equals(AMD64.rax);
+        if (opcode == DIV || opcode == IDIV) {
+            assert asRegister(highX).equals(AMD64.rdx);
+        } else if (opcode == MUL || opcode == IMUL) {
+            assert isIllegal(highX);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PauseOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PauseOp.java
new file mode 100644
index 0000000..4c08b97
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PauseOp.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Emits a pause.
+ */
+@Opcode("PAUSE")
+public final class AMD64PauseOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64PauseOp> TYPE = LIRInstructionClass.create(AMD64PauseOp.class);
+
+    public AMD64PauseOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        asm.pause();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PrefetchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PrefetchOp.java
new file mode 100644
index 0000000..d3f1a12
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64PrefetchOp.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AMD64PrefetchOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64PrefetchOp> TYPE = LIRInstructionClass.create(AMD64PrefetchOp.class);
+
+    private final int instr;  // AllocatePrefetchInstr
+    @Alive({COMPOSITE}) protected AMD64AddressValue address;
+
+    public AMD64PrefetchOp(AMD64AddressValue address, int instr) {
+        super(TYPE);
+        this.address = address;
+        this.instr = instr;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        switch (instr) {
+            case 0:
+                masm.prefetchnta(address.toAddress());
+                break;
+            case 1:
+                masm.prefetcht0(address.toAddress());
+                break;
+            case 2:
+                masm.prefetcht2(address.toAddress());
+                break;
+            case 3:
+                masm.prefetchw(address.toAddress());
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("unspported prefetch op " + instr);
+
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ReadTimestampCounter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ReadTimestampCounter.java
new file mode 100644
index 0000000..ccd6a14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ReadTimestampCounter.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * AMD64 rdtsc operation. The result is in EDX:EAX.
+ */
+@Opcode("RDTSC")
+public class AMD64ReadTimestampCounter extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ReadTimestampCounter> TYPE = LIRInstructionClass.create(AMD64ReadTimestampCounter.class);
+
+    @Def({REG}) protected AllocatableValue highResult;
+    @Def({REG}) protected AllocatableValue lowResult;
+
+    public AMD64ReadTimestampCounter() {
+        super(TYPE);
+
+        this.highResult = AMD64.rdx.asValue(LIRKind.value(AMD64Kind.DWORD));
+        this.lowResult = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD));
+    }
+
+    public AllocatableValue getHighResult() {
+        return highResult;
+    }
+
+    public AllocatableValue getLowResult() {
+        return lowResult;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        masm.rdtsc();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64RestoreRegistersOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64RestoreRegistersOp.java
new file mode 100644
index 0000000..bbfd440
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64RestoreRegistersOp.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Restores registers from stack slots.
+ */
+@Opcode("RESTORE_REGISTER")
+public class AMD64RestoreRegistersOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64RestoreRegistersOp> TYPE = LIRInstructionClass.create(AMD64RestoreRegistersOp.class);
+
+    /**
+     * The slots from which the registers are restored.
+     */
+    @Use(STACK) protected final AllocatableValue[] slots;
+
+    /**
+     * The operation that saved the registers restored by this operation.
+     */
+    private final AMD64SaveRegistersOp save;
+
+    public AMD64RestoreRegistersOp(AllocatableValue[] values, AMD64SaveRegistersOp save) {
+        this(TYPE, values, save);
+    }
+
+    protected AMD64RestoreRegistersOp(LIRInstructionClass<? extends AMD64RestoreRegistersOp> c, AllocatableValue[] values, AMD64SaveRegistersOp save) {
+        super(c);
+        assert Arrays.asList(values).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
+        this.slots = values;
+        this.save = save;
+    }
+
+    protected Register[] getSavedRegisters() {
+        return save.savedRegisters;
+    }
+
+    protected void restoreRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, StackSlot input) {
+        AMD64Move.stack2reg((AMD64Kind) input.getPlatformKind(), crb, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        Register[] savedRegisters = getSavedRegisters();
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+                restoreRegister(crb, masm, savedRegisters[i], asStackSlot(slots[i]));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java
new file mode 100644
index 0000000..f4758ce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class AMD64SaveRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<AMD64SaveRegistersOp> TYPE = LIRInstructionClass.create(AMD64SaveRegistersOp.class);
+
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final AllocatableValue[] slots;
+
+    /**
+     * Specifies if {@link #remove(Set)} should have an effect.
+     */
+    protected final boolean supportsRemove;
+
+    /**
+     *
+     * @param savedRegisters the registers saved by this operation which may be subject to
+     *            {@linkplain #remove(Set) pruning}
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+     */
+    public AMD64SaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        this(TYPE, savedRegisters, savedRegisterLocations, supportsRemove);
+    }
+
+    public AMD64SaveRegistersOp(LIRInstructionClass<? extends AMD64SaveRegistersOp> c, Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        super(c);
+        assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
+        this.savedRegisters = savedRegisters;
+        this.slots = savedRegisterLocations;
+        this.supportsRemove = supportsRemove;
+    }
+
+    protected void saveRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, StackSlot result, Register input) {
+        AMD64Move.reg2stack((AMD64Kind) result.getPlatformKind(), crb, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+                saveRegister(crb, masm, asStackSlot(slots[i]), savedRegisters[i]);
+            }
+        }
+    }
+
+    public AllocatableValue[] getSlots() {
+        return slots;
+    }
+
+    @Override
+    public boolean supportsRemove() {
+        return supportsRemove;
+    }
+
+    @Override
+    public int remove(Set<Register> doNotSave) {
+        if (!supportsRemove) {
+            throw new UnsupportedOperationException();
+        }
+        return prune(doNotSave, savedRegisters);
+    }
+
+    static int prune(Set<Register> toRemove, Register[] registers) {
+        int pruned = 0;
+        for (int i = 0; i < registers.length; i++) {
+            if (registers[i] != null) {
+                if (toRemove.contains(registers[i])) {
+                    registers[i] = null;
+                    pruned++;
+                }
+            }
+        }
+        return pruned;
+    }
+
+    @Override
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        int total = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                total++;
+            }
+        }
+        Register[] keys = new Register[total];
+        int[] values = new int[total];
+        if (total != 0) {
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+                    StackSlot slot = asStackSlot(slots[i]);
+                    values[mapIndex] = indexForStackSlot(frameMap, slot);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == total;
+        }
+        return new RegisterSaveLayout(keys, values);
+    }
+
+    /**
+     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
+     * slots in the reference map.
+     *
+     * @param slot a stack slot
+     * @return the index of the stack slot
+     */
+    private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) {
+        assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0;
+        int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize;
+        return value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ShiftOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ShiftOp.java
new file mode 100644
index 0000000..c30aa24
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ShiftOp.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * AMD64 shift/rotate operation. This operation has a single operand for the first input and output.
+ * The second input must be in the RCX register.
+ */
+public class AMD64ShiftOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ShiftOp> TYPE = LIRInstructionClass.create(AMD64ShiftOp.class);
+
+    @Opcode private final AMD64MOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    @Alive({REG}) protected AllocatableValue y;
+
+    public AMD64ShiftOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        opcode.emit(masm, size, asRegister(result));
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(y).equals(AMD64.rcx);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SignExtendOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SignExtendOp.java
new file mode 100644
index 0000000..c920652
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SignExtendOp.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.AllocatableValue;
+
+@Opcode("CDQ")
+public class AMD64SignExtendOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64SignExtendOp> TYPE = LIRInstructionClass.create(AMD64SignExtendOp.class);
+
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue highResult;
+    @Def({REG}) protected AllocatableValue lowResult;
+
+    @Use({REG}) protected AllocatableValue input;
+
+    public AMD64SignExtendOp(OperandSize size, LIRKind resultKind, AllocatableValue input) {
+        super(TYPE);
+        this.size = size;
+
+        this.highResult = AMD64.rdx.asValue(resultKind);
+        this.lowResult = AMD64.rax.asValue(resultKind);
+        this.input = input;
+    }
+
+    public AllocatableValue getHighResult() {
+        return highResult;
+    }
+
+    public AllocatableValue getLowResult() {
+        return lowResult;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (size == DWORD) {
+            masm.cdql();
+        } else {
+            assert size == QWORD;
+            masm.cdqq();
+        }
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(highResult).equals(AMD64.rdx);
+        assert asRegister(lowResult).equals(AMD64.rax);
+        assert asRegister(input).equals(AMD64.rax);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Unary.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Unary.java
new file mode 100644
index 0000000..84f2a17
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Unary.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * AMD64 LIR instructions that have one input and one output.
+ */
+public class AMD64Unary {
+
+    /**
+     * Instruction with a single operand that is both input and output.
+     */
+    public static class MOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MOp> TYPE = LIRInstructionClass.create(MOp.class);
+
+        @Opcode private final AMD64MOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue value;
+
+        public MOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, value);
+            opcode.emit(masm, size, asRegister(result));
+        }
+    }
+
+    /**
+     * Instruction with separate input and output operands, and an operand encoding of RM.
+     */
+    public static class RMOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<RMOp> TYPE = LIRInstructionClass.create(RMOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue value;
+
+        public RMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(value)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(value));
+            } else {
+                assert isStackSlot(value);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value));
+            }
+        }
+    }
+
+    /**
+     * Instruction with separate input and output operands, and an operand encoding of MR.
+     */
+    public static class MROp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MROp> TYPE = LIRInstructionClass.create(MROp.class);
+
+        @Opcode private final AMD64MROp opcode;
+        private final OperandSize size;
+
+        @Def({REG, STACK}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue value;
+
+        public MROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(result)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(value));
+            } else {
+                assert isStackSlot(result);
+                opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value));
+            }
+        }
+    }
+
+    /**
+     * Instruction with a {@link AMD64AddressValue memory} operand.
+     */
+    public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryOp> TYPE = LIRInstructionClass.create(MemoryOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE}) protected AMD64AddressValue input;
+
+        @State protected LIRFrameState state;
+
+        public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.input = input;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(result), input.toAddress());
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64VZeroUpper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64VZeroUpper.java
new file mode 100644
index 0000000..6f7f095
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64VZeroUpper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.Value;
+
+public class AMD64VZeroUpper extends AMD64LIRInstruction {
+
+    public static final LIRInstructionClass<AMD64VZeroUpper> TYPE = LIRInstructionClass.create(AMD64VZeroUpper.class);
+
+    @Temp protected final RegisterValue[] xmmRegisters;
+
+    public AMD64VZeroUpper(Value[] exclude) {
+        super(TYPE);
+        xmmRegisters = initRegisterValues(exclude);
+    }
+
+    private static RegisterValue[] initRegisterValues(Value[] exclude) {
+        BitSet skippedRegs = new BitSet();
+        int numSkipped = 0;
+        if (exclude != null) {
+            for (Value value : exclude) {
+                if (isRegister(value) && asRegister(value).getRegisterCategory().equals(AMD64.XMM)) {
+                    skippedRegs.set(asRegister(value).number);
+                    numSkipped++;
+                }
+            }
+        }
+        RegisterValue[] regs = new RegisterValue[AMD64.xmmRegistersAVX512.length - numSkipped];
+        for (int i = 0, j = 0; i < AMD64.xmmRegistersAVX512.length; i++) {
+            Register reg = AMD64.xmmRegistersAVX512[i];
+            if (!skippedRegs.get(reg.number)) {
+                regs[j++] = reg.asValue();
+            }
+        }
+        return regs;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        asm.vzeroupper();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java
new file mode 100644
index 0000000..1345b49
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp.prune;
+
+import java.util.Set;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * Writes well known garbage values to registers.
+ */
+@Opcode("ZAP_REGISTER")
+public final class AMD64ZapRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<AMD64ZapRegistersOp> TYPE = LIRInstructionClass.create(AMD64ZapRegistersOp.class);
+
+    /**
+     * The registers that are zapped.
+     */
+    protected final Register[] zappedRegisters;
+
+    /**
+     * The garbage values that are written to the registers.
+     */
+    protected final JavaConstant[] zapValues;
+
+    public AMD64ZapRegistersOp(Register[] zappedRegisters, JavaConstant[] zapValues) {
+        super(TYPE);
+        this.zappedRegisters = zappedRegisters;
+        this.zapValues = zapValues;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        for (int i = 0; i < zappedRegisters.length; i++) {
+            Register reg = zappedRegisters[i];
+            if (reg != null) {
+                AMD64Move.const2reg(crb, masm, reg, zapValues[i]);
+            }
+        }
+    }
+
+    @Override
+    public boolean supportsRemove() {
+        return true;
+    }
+
+    @Override
+    public int remove(Set<Register> doNotSave) {
+        return prune(doNotSave, zappedRegisters);
+    }
+
+    @Override
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        return new RegisterSaveLayout(new Register[0], new int[0]);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapStackOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapStackOp.java
new file mode 100644
index 0000000..420ab78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapStackOp.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * Writes well known garbage values to stack slots.
+ */
+@Opcode("ZAP_STACK")
+public final class AMD64ZapStackOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ZapStackOp> TYPE = LIRInstructionClass.create(AMD64ZapStackOp.class);
+
+    /**
+     * The stack slots that are zapped.
+     */
+    @Def(OperandFlag.STACK) protected final StackSlot[] zappedStack;
+
+    /**
+     * The garbage values that are written to the stack.
+     */
+    protected final JavaConstant[] zapValues;
+
+    public AMD64ZapStackOp(StackSlot[] zappedStack, JavaConstant[] zapValues) {
+        super(TYPE);
+        this.zappedStack = zappedStack;
+        this.zapValues = zapValues;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        for (int i = 0; i < zappedStack.length; i++) {
+            StackSlot slot = zappedStack[i];
+            if (slot != null) {
+                AMD64Move.const2stack(crb, masm, slot, zapValues[i]);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/phases/StackMoveOptimizationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/phases/StackMoveOptimizationPhase.java
new file mode 100644
index 0000000..3eee2c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/phases/StackMoveOptimizationPhase.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64.phases;
+
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.RedundantMoveElimination;
+import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64MultiStackMove;
+import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64StackMove;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Replaces sequential {@link AMD64StackMove}s of the same type with a single
+ * {@link AMD64MultiStackMove} to avoid storing/restoring the scratch register multiple times.
+ *
+ * Note: this phase must be inserted <b>after</b> {@link RedundantMoveElimination} phase because
+ * {@link AMD64MultiStackMove} are not probably detected.
+ */
+public class StackMoveOptimizationPhase extends PostAllocationOptimizationPhase {
+    public static class Options {
+        // @formatter:off
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptStackMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        // @formatter:on
+    }
+
+    private static final DebugCounter eliminatedBackup = Debug.counter("StackMoveOptimizer[EliminatedScratchBackupRestore]");
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        LIR lir = lirGenRes.getLIR();
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            new Closure().process(instructions);
+        }
+    }
+
+    private static class Closure {
+        private static final int NONE = -1;
+
+        private int begin = NONE;
+        private Register reg = null;
+        private List<AllocatableValue> dst;
+        private List<Value> src;
+        private AllocatableValue slot;
+        private boolean removed = false;
+
+        public void process(List<LIRInstruction> instructions) {
+            for (int i = 0; i < instructions.size(); i++) {
+                LIRInstruction inst = instructions.get(i);
+
+                if (isStackMove(inst)) {
+                    AMD64StackMove move = asStackMove(inst);
+
+                    if (reg != null && !reg.equals(move.getScratchRegister())) {
+                        // end of trace & start of new
+                        replaceStackMoves(instructions);
+                    }
+
+                    // lazy initialize
+                    if (dst == null) {
+                        assert src == null;
+                        dst = new ArrayList<>();
+                        src = new ArrayList<>();
+                    }
+
+                    dst.add(move.getResult());
+                    src.add(move.getInput());
+
+                    if (begin == NONE) {
+                        // trace begin
+                        begin = i;
+                        reg = move.getScratchRegister();
+                        slot = move.getBackupSlot();
+                    }
+
+                } else if (begin != NONE) {
+                    // end of trace
+                    replaceStackMoves(instructions);
+                }
+            }
+            // remove instructions
+            if (removed) {
+                instructions.removeAll(Collections.singleton(null));
+            }
+
+        }
+
+        private void replaceStackMoves(List<LIRInstruction> instructions) {
+            int size = dst.size();
+            if (size > 1) {
+                AMD64MultiStackMove multiMove = new AMD64MultiStackMove(dst.toArray(new AllocatableValue[size]), src.toArray(new AllocatableValue[size]), reg, slot);
+                // replace first instruction
+                instructions.set(begin, multiMove);
+                // and null out others
+                Collections.fill(instructions.subList(begin + 1, begin + size), null);
+                // removed
+                removed = true;
+                eliminatedBackup.add(size - 1);
+            }
+            // reset
+            dst.clear();
+            src.clear();
+            begin = NONE;
+            reg = null;
+            slot = null;
+        }
+    }
+
+    private static AMD64StackMove asStackMove(LIRInstruction inst) {
+        assert isStackMove(inst);
+        return (AMD64StackMove) inst;
+    }
+
+    private static boolean isStackMove(LIRInstruction inst) {
+        return inst instanceof AMD64StackMove;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/ConstantStackCastTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/ConstantStackCastTest.java
new file mode 100644
index 0000000..52aebb9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/ConstantStackCastTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Tests move from a constant to a wider stack slot (e.g. byte constant to integer stack slot).
+ */
+public class ConstantStackCastTest extends LIRTest {
+    private static PlatformKind byteKind;
+    private static final LoadConstantStackSpec stackCopyByte = new LoadConstantStackSpec();
+
+    @Before
+    public void setup() {
+        // Necessary to get the PlatformKind on which we're currently running on
+        byteKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Byte);
+        stackCopyByte.dstKind = LIRKind.fromJavaKind(getBackend().getTarget().arch, JavaKind.Int);
+        stackCopyByte.srcKind = LIRKind.fromJavaKind(getBackend().getTarget().arch, JavaKind.Byte);
+    }
+
+    private static class LoadConstantStackSpec extends LIRTestSpecification {
+        LIRKind dstKind;
+        LIRKind srcKind;
+
+        @Override
+        public void generate(LIRGeneratorTool gen, Value value) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            // create slots
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(dstKind);
+            // move stuff around
+            Value srcValue;
+            if (isJavaConstant(value)) {
+                srcValue = getConstant(srcKind, asJavaConstant(value));
+            } else {
+                srcValue = value;
+            }
+            gen.emitMove(s1, srcValue);
+            gen.emitBlackhole(s1);
+            setResult(gen.emitMove(s1));
+        }
+
+        private static ConstantValue getConstant(LIRKind srcKind, JavaConstant c) {
+            if (srcKind.getPlatformKind() == byteKind) {
+                JavaConstant byteConst = JavaConstant.forByte((byte) c.asInt());
+                return new ConstantValue(srcKind, byteConst);
+            } else {
+                throw GraalError.shouldNotReachHere("Kind not supported: " + srcKind);
+            }
+        }
+
+    }
+
+    @LIRIntrinsic
+    public static byte testCopyByte(@SuppressWarnings("unused") LoadConstantStackSpec spec, byte value) {
+        return value;
+    }
+
+    public byte testByte(byte value) {
+        return testCopyByte(stackCopyByte, value);
+    }
+
+    @Test
+    public void runByte() throws Throwable {
+        runTest("testByte", (byte) 0);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java
new file mode 100644
index 0000000..39e4c7f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.stream.Stream;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Base class for LIR tests.
+ * <p>
+ * It provides facilities to replace methods with {@link LIRTestSpecification arbitrary LIR
+ * instructions}.
+ */
+public abstract class LIRTest extends JTTTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    private static final class LIRTestNode extends FixedWithNextNode implements LIRLowerable {
+
+        public static final NodeClass<LIRTestNode> TYPE = NodeClass.create(LIRTestNode.class);
+        @Input protected ValueNode opsNode;
+        @Input protected NodeInputList<ValueNode> values;
+        public final SnippetReflectionProvider snippetReflection;
+
+        protected LIRTestNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode[] values) {
+            super(TYPE, StampFactory.forKind(kind));
+            this.opsNode = opsNode;
+            this.values = new NodeInputList<>(this, values);
+            this.snippetReflection = snippetReflection;
+        }
+
+        public NodeInputList<ValueNode> values() {
+            return values;
+        }
+
+        public ValueNode getLIROpsNode() {
+            return opsNode;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool gen) {
+            LIRTestSpecification ops = getLIROperations();
+            Stream<Value> v = values().stream().map(node -> gen.operand(node));
+
+            ops.generate(gen.getLIRGeneratorTool(), v.toArray(size -> new Value[size]));
+            Value result = ops.getResult();
+            if (result != null) {
+                gen.setResult(this, result);
+            }
+        }
+
+        public LIRTestSpecification getLIROperations() {
+            assert getLIROpsNode().isConstant();
+            LIRTestSpecification spec = snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
+            return spec;
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    private static final class LIRValueNode extends FixedWithNextNode implements LIRLowerable {
+
+        public static final NodeClass<LIRValueNode> TYPE = NodeClass.create(LIRValueNode.class);
+        @Input protected ValueNode opsNode;
+        @Input protected ValueNode name;
+        public final SnippetReflectionProvider snippetReflection;
+
+        protected LIRValueNode(SnippetReflectionProvider snippetReflection, JavaKind kind, ValueNode opsNode, ValueNode name) {
+            super(TYPE, StampFactory.forKind(kind));
+            this.opsNode = opsNode;
+            this.name = name;
+            this.snippetReflection = snippetReflection;
+        }
+
+        public ValueNode getLIROpsNode() {
+            return opsNode;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool gen) {
+            LIRTestSpecification spec = getLIROperations();
+            Value output = spec.getOutput(getName());
+            gen.setResult(this, isVariable(output) ? output : gen.getLIRGeneratorTool().emitMove(output));
+        }
+
+        private String getName() {
+            assert name.isConstant();
+            return snippetReflection.asObject(String.class, name.asJavaConstant());
+        }
+
+        private LIRTestSpecification getLIROperations() {
+            assert getLIROpsNode().isConstant();
+            return snippetReflection.asObject(LIRTestSpecification.class, getLIROpsNode().asJavaConstant());
+        }
+
+    }
+
+    private InvocationPlugin lirTestPlugin = new InvocationPlugin() {
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec) {
+            JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+            LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{});
+            addNode(b, returnKind, node);
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0) {
+            JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+            LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0});
+            addNode(b, returnKind, node);
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1) {
+            JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+            LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1});
+            addNode(b, returnKind, node);
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2) {
+            JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+            LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2});
+            addNode(b, returnKind, node);
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+            LIRTestNode node = new LIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2, arg3});
+            addNode(b, returnKind, node);
+            return true;
+        }
+
+        private void addNode(GraphBuilderContext b, JavaKind returnKind, LIRTestNode node) {
+            if (returnKind.equals(JavaKind.Void)) {
+                b.add(node);
+            } else {
+                b.addPush(returnKind, node);
+            }
+        }
+
+    };
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+
+        Class<? extends LIRTest> c = getClass();
+        for (Method m : c.getMethods()) {
+            if (m.getAnnotation(LIRIntrinsic.class) != null) {
+                assert Modifier.isStatic(m.getModifiers());
+                Class<?>[] p = m.getParameterTypes();
+                assert p.length > 0;
+                assert LIRTestSpecification.class.isAssignableFrom(p[0]);
+
+                invocationPlugins.register(lirTestPlugin, c, m.getName(), p);
+            }
+        }
+        InvocationPlugin outputPlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode name, ValueNode expected) {
+                JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+                b.addPush(returnKind, new LIRValueNode(getSnippetReflection(), returnKind, spec, name));
+                return true;
+            }
+        };
+        invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, Object.class});
+        invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, int.class});
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    @SuppressWarnings("unused")
+    public static byte getOutput(LIRTestSpecification spec, String name, byte expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static short getOutput(LIRTestSpecification spec, String name, short expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static int getOutput(LIRTestSpecification spec, String name, int expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static long getOutput(LIRTestSpecification spec, String name, long expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static float getOutput(LIRTestSpecification spec, String name, float expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static double getOutput(LIRTestSpecification spec, String name, double expected) {
+        return expected;
+    }
+
+    @SuppressWarnings("unused")
+    public static Object getOutput(LIRTestSpecification spec, String name, Object expected) {
+        return expected;
+    }
+
+    @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target(ElementType.METHOD)
+    public static @interface LIRIntrinsic {
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestSpecification.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestSpecification.java
new file mode 100644
index 0000000..215aa80
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestSpecification.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import java.util.HashMap;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.meta.Value;
+
+public abstract class LIRTestSpecification {
+    private Value result;
+    private final HashMap<String, Value> output = new HashMap<>();
+
+    public void generate(LIRGeneratorTool gen) {
+        defaultHandler(gen);
+    }
+
+    public void generate(LIRGeneratorTool gen, Value arg0) {
+        defaultHandler(gen, arg0);
+    }
+
+    public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) {
+        defaultHandler(gen, arg0, arg1);
+    }
+
+    public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) {
+        defaultHandler(gen, arg0, arg1, arg2);
+    }
+
+    public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) {
+        defaultHandler(gen, arg0, arg1, arg2, arg3);
+    }
+
+    public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) {
+        defaultHandler(gen, arg0, arg1, arg2, arg3, arg4);
+    }
+
+    private static void defaultHandler(@SuppressWarnings("unused") LIRGeneratorTool gen, Value... args) {
+        throw new GraalError("LIRTestSpecification cannot handle generate() with %d arguments", args.length);
+    }
+
+    void generate(LIRGeneratorTool gen, Value[] values) {
+        if (values.length == 0) {
+            generate(gen);
+        } else if (values.length == 1) {
+            generate(gen, values[0]);
+        } else if (values.length == 2) {
+            generate(gen, values[0], values[1]);
+        } else if (values.length == 3) {
+            generate(gen, values[0], values[1], values[2]);
+        } else if (values.length == 4) {
+            generate(gen, values[0], values[1], values[2], values[3]);
+        } else if (values.length == 5) {
+            generate(gen, values[0], values[1], values[2], values[3], values[4]);
+        } else {
+            GraalError.unimplemented();
+        }
+
+    }
+
+    public void setOutput(String name, Value value) {
+        output.put(name, value);
+    }
+
+    public Value getOutput(String name) {
+        return output.get(name);
+    }
+
+    public void setResult(Value value) {
+        result = value;
+    }
+
+    public Value getResult() {
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestTest.java
new file mode 100644
index 0000000..6b6d3e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTestTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.meta.Value;
+
+public class LIRTestTest extends LIRTest {
+    private static final LIRTestSpecification stackCopy = new LIRTestSpecification() {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a, Value b) {
+            setOutput("a", a);
+            setOutput("b", b);
+            setResult(a);
+        }
+    };
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static int copyInt(LIRTestSpecification spec, int a, int b) {
+        return a;
+    }
+
+    public static int[] testGetOutput(int a, int b, int[] out) {
+        out[0] = copyInt(stackCopy, a, b);
+        out[1] = getOutput(stackCopy, "a", a);
+        out[2] = getOutput(stackCopy, "b", b);
+        return out;
+    }
+
+    @Test
+    public void runInt() throws Throwable {
+        runTest("testGetOutput", Integer.MIN_VALUE, 0, supply(() -> new int[3]));
+        runTest("testGetOutput", -1, Integer.MAX_VALUE, supply(() -> new int[3]));
+        runTest("testGetOutput", 0, 42, supply(() -> new int[3]));
+        runTest("testGetOutput", 1, -0xFFAA44, supply(() -> new int[3]));
+        runTest("testGetOutput", Integer.MAX_VALUE, -42, supply(() -> new int[3]));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java
new file mode 100644
index 0000000..2f6cc40
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC;
+
+/**
+ * Tests the {@link BailoutException} thrown, when trying to compile huge methods, which have branch
+ * displacements which does not fit into 19 bit signed.
+ */
+public class SPARCBranchBailoutTest extends LIRTest {
+    private static class BranchSpec extends LIRTestSpecification {
+        private final int n;
+
+        BranchSpec(int n) {
+            super();
+            this.n = n;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            gen.append(new LargeOp(n));
+            setResult(a);
+        }
+    }
+
+    private static final BranchSpec spec = new BranchSpec(1 << 20);
+
+    @LIRIntrinsic
+    public static int branch(@SuppressWarnings("unused") BranchSpec s, int a) {
+        return a;
+    }
+
+    public static int testBranch(int length) {
+        int res = 1;
+        if (length > 0) {
+            res = branch(spec, 1);
+        } else {
+            res = branch(spec, 2);
+        }
+        return GraalDirectives.opaque(res);
+    }
+
+    @Test
+    public void testBailoutOnBranchOverflow() throws Throwable {
+        Assume.assumeTrue(getBackend().getTarget().arch instanceof SPARC);
+        ResolvedJavaMethod m = getResolvedJavaMethod("testBranch");
+        try {
+            compile(m, null);
+        } catch (GraalError e) {
+            Assert.assertEquals(PermanentBailoutException.class, e.getCause().getClass());
+        }
+    }
+
+    public static class LargeOp extends LIRInstruction {
+        private static final LIRInstructionClass<LargeOp> TYPE = LIRInstructionClass.create(LargeOp.class);
+        private final int n;
+
+        public LargeOp(int n) {
+            super(TYPE);
+            this.n = n;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            for (int i = 0; i < n; i++) {
+                crb.asm.emitInt(0);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/StackMoveTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/StackMoveTest.java
new file mode 100644
index 0000000..d2c09fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/StackMoveTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.jtt;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public class StackMoveTest extends LIRTest {
+    private static PlatformKind byteKind;
+    private static PlatformKind shortKind;
+
+    @Before
+    public void setUp() {
+        byteKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Byte);
+        shortKind = getBackend().getTarget().arch.getPlatformKind(JavaKind.Short);
+    }
+
+    private static class StackCopySpec extends LIRTestSpecification {
+        @Override
+        public void generate(LIRGeneratorTool gen, Value a) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            ValueKind<?> valueKind = getValueKind(a);
+
+            // create slots
+            VirtualStackSlot s1 = frameMapBuilder.allocateSpillSlot(valueKind);
+            VirtualStackSlot s2 = frameMapBuilder.allocateSpillSlot(valueKind);
+
+            // start emit
+            gen.emitMove(s1, a);
+            Value copy1 = gen.emitMove(s1);
+            gen.append(gen.getSpillMoveFactory().createStackMove(s2, s1));
+            Variable result = gen.emitMove(s2);
+            // end emit
+
+            // set output and result
+            setResult(result);
+            setOutput("slotcopy", copy1);
+            setOutput("slot1", s1);
+            setOutput("slot2", s2);
+        }
+
+        protected ValueKind<?> getValueKind(Value value) {
+            return value.getValueKind();
+        }
+    }
+
+    private static final LIRTestSpecification stackCopy = new StackCopySpec();
+
+    /*
+     * int
+     */
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static int copyInt(LIRTestSpecification spec, int a) {
+        return a;
+    }
+
+    public int[] testInt(int a, int[] out) {
+        out[0] = copyInt(stackCopy, a);
+        out[1] = getOutput(stackCopy, "slotcopy", a);
+        out[2] = getOutput(stackCopy, "slot1", a);
+        out[3] = getOutput(stackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runInt() throws Throwable {
+        runTest("testInt", Integer.MIN_VALUE, supply(() -> new int[4]));
+        runTest("testInt", -1, supply(() -> new int[4]));
+        runTest("testInt", 0, supply(() -> new int[4]));
+        runTest("testInt", 1, supply(() -> new int[4]));
+        runTest("testInt", Integer.MAX_VALUE, supply(() -> new int[4]));
+    }
+
+    /*
+     * long
+     */
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static long copyLong(LIRTestSpecification spec, long a) {
+        return a;
+    }
+
+    public long[] testLong(long a, long[] out) {
+        out[0] = copyLong(stackCopy, a);
+        out[1] = getOutput(stackCopy, "slotcopy", a);
+        out[2] = getOutput(stackCopy, "slot1", a);
+        out[3] = getOutput(stackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runLong() throws Throwable {
+        runTest("testLong", Long.MIN_VALUE, supply(() -> new long[3]));
+        runTest("testLong", -1L, supply(() -> new long[3]));
+        runTest("testLong", 0L, supply(() -> new long[3]));
+        runTest("testLong", 1L, supply(() -> new long[3]));
+        runTest("testLong", Long.MAX_VALUE, supply(() -> new long[3]));
+    }
+
+    /*
+     * float
+     */
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static float copyFloat(LIRTestSpecification spec, float a) {
+        return a;
+    }
+
+    public float[] testFloat(float a, float[] out) {
+        out[0] = copyFloat(stackCopy, a);
+        out[1] = getOutput(stackCopy, "slotcopy", a);
+        out[2] = getOutput(stackCopy, "slot1", a);
+        out[3] = getOutput(stackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runFloat() throws Throwable {
+        runTest("testFloat", Float.MIN_VALUE, supply(() -> new float[3]));
+        runTest("testFloat", -1f, supply(() -> new float[3]));
+        runTest("testFloat", -0.1f, supply(() -> new float[3]));
+        runTest("testFloat", 0f, supply(() -> new float[3]));
+        runTest("testFloat", 0.1f, supply(() -> new float[3]));
+        runTest("testFloat", 1f, supply(() -> new float[3]));
+        runTest("testFloat", Float.MAX_VALUE, supply(() -> new float[3]));
+    }
+
+    /*
+     * double
+     */
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static double copyDouble(LIRTestSpecification spec, double a) {
+        return a;
+    }
+
+    public double[] testDouble(double a, double[] out) {
+        out[0] = copyDouble(stackCopy, a);
+        out[1] = getOutput(stackCopy, "slotcopy", a);
+        out[2] = getOutput(stackCopy, "slot1", a);
+        out[3] = getOutput(stackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runDouble() throws Throwable {
+        runTest("testDouble", Double.MIN_VALUE, supply(() -> new double[3]));
+        runTest("testDouble", -1., supply(() -> new double[3]));
+        runTest("testDouble", -0.1, supply(() -> new double[3]));
+        runTest("testDouble", 0., supply(() -> new double[3]));
+        runTest("testDouble", 0.1, supply(() -> new double[3]));
+        runTest("testDouble", 1., supply(() -> new double[3]));
+        runTest("testDouble", Double.MAX_VALUE, supply(() -> new double[3]));
+    }
+
+    /*
+     * short
+     */
+
+    private static final LIRTestSpecification shortStackCopy = new StackCopySpec() {
+        @Override
+        protected ValueKind<?> getValueKind(Value value) {
+            return LIRKind.value(shortKind);
+        }
+    };
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static short copyShort(LIRTestSpecification spec, short a) {
+        return a;
+    }
+
+    public short[] testShort(short a, short[] out) {
+        out[0] = copyShort(shortStackCopy, a);
+        out[1] = getOutput(shortStackCopy, "slotcopy", a);
+        out[2] = getOutput(shortStackCopy, "slot1", a);
+        out[3] = getOutput(shortStackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runShort() throws Throwable {
+        runTest("testShort", Short.MIN_VALUE, supply(() -> new short[3]));
+        runTest("testShort", (short) -1, supply(() -> new short[3]));
+        runTest("testShort", (short) 0, supply(() -> new short[3]));
+        runTest("testShort", (short) 1, supply(() -> new short[3]));
+        runTest("testShort", Short.MAX_VALUE, supply(() -> new short[3]));
+    }
+
+    /*
+     * byte
+     */
+
+    private static final LIRTestSpecification byteStackCopy = new StackCopySpec() {
+        @Override
+        protected ValueKind<?> getValueKind(Value value) {
+            return LIRKind.value(byteKind);
+        }
+    };
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static byte copyByte(LIRTestSpecification spec, byte a) {
+        return a;
+    }
+
+    public byte[] testByte(byte a, byte[] out) {
+        out[0] = copyByte(byteStackCopy, a);
+        out[1] = getOutput(byteStackCopy, "slotcopy", a);
+        out[2] = getOutput(byteStackCopy, "slot1", a);
+        out[3] = getOutput(byteStackCopy, "slot2", a);
+        return out;
+    }
+
+    @Test
+    public void runByte() throws Throwable {
+        runTest("testByte", Byte.MIN_VALUE, supply(() -> new byte[3]));
+        runTest("testByte", (byte) -1, supply(() -> new byte[3]));
+        runTest("testByte", (byte) 0, supply(() -> new byte[3]));
+        runTest("testByte", (byte) 1, supply(() -> new byte[3]));
+        runTest("testByte", Byte.MAX_VALUE, supply(() -> new byte[3]));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java
new file mode 100644
index 0000000..6bf9a9f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.lir.CompositeValue;
+
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public abstract class SPARCAddressValue extends CompositeValue {
+
+    public SPARCAddressValue(ValueKind<?> kind) {
+        super(kind);
+    }
+
+    public abstract SPARCAddress toAddress();
+
+    public abstract boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java
new file mode 100644
index 0000000..44edf5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
+import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC;
+
+public class SPARCArithmetic {
+    public static final class FloatConvertOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<FloatConvertOp> TYPE = LIRInstructionClass.create(FloatConvertOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(5);
+
+        @Opcode private final FloatConvert opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG}) protected Value x;
+
+        public enum FloatConvert {
+            F2I,
+            D2I,
+            F2L,
+            D2L
+        }
+
+        public FloatConvertOp(FloatConvert opcode, Value x, Value result) {
+            super(TYPE, SIZE);
+            this.opcode = opcode;
+            this.x = x;
+            this.result = result;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            Label notOrdered = new Label();
+            switch (opcode) {
+                case F2L:
+                    masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE));
+                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
+                    masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE));
+                    masm.fxtod(asRegister(result), asRegister(result));
+                    masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE));
+                    masm.bind(notOrdered);
+                    break;
+                case F2I:
+                    masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE));
+                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
+                    masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE));
+                    masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE));
+                    masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE));
+                    masm.bind(notOrdered);
+                    break;
+                case D2L:
+                    masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE));
+                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
+                    masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE));
+                    masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE));
+                    masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE));
+                    masm.bind(notOrdered);
+                    break;
+                case D2I:
+                    masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE));
+                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
+                    masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE));
+                    masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE));
+                    masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE));
+                    masm.bind(notOrdered);
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("missing: " + opcode);
+            }
+        }
+    }
+
+    /**
+     * Special LIR instruction as it requires a bunch of scratch registers.
+     */
+    public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<RemOp> TYPE = LIRInstructionClass.create(RemOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(4);
+
+        @Opcode private final Rem opcode;
+        @Def({REG}) protected Value result;
+        @Alive({REG, CONST}) protected Value x;
+        @Alive({REG, CONST}) protected Value y;
+        @Temp({REG}) protected Value scratch1;
+        @Temp({REG}) protected Value scratch2;
+        @State protected LIRFrameState state;
+
+        public enum Rem {
+            IUREM,
+            LUREM
+        }
+
+        public RemOp(Rem opcode, Value result, Value x, Value y, Value scratch1, Value scratch2, LIRFrameState state) {
+            super(TYPE, SIZE);
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+            this.scratch1 = scratch1;
+            this.scratch2 = scratch2;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (!isJavaConstant(x) && isJavaConstant(y)) {
+                assert isSimm13(crb.asIntConst(y));
+                assert !x.equals(scratch1);
+                assert !x.equals(scratch2);
+                assert !y.equals(scratch1);
+                switch (opcode) {
+                    case LUREM:
+                        crb.recordImplicitException(masm.position(), state);
+                        masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD));
+                        masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD));
+                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+                        masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD));
+                        break;
+                    case IUREM:
+                        GraalError.unimplemented();
+                        break;
+                    default:
+                        throw GraalError.shouldNotReachHere();
+                }
+            } else if (isRegister(x) && isRegister(y)) {
+                Value xLeft = x;
+                switch (opcode) {
+                    case LUREM:
+                        if (isJavaConstant(x)) {
+                            masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false);
+                            xLeft = scratch2;
+                        }
+                        assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD));
+                        assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD));
+                        crb.recordImplicitException(masm.position(), state);
+                        masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
+                        masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
+                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+                        masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD));
+                        break;
+                    case IUREM:
+                        assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD));
+                        assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD));
+                        masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD));
+                        masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD));
+                        crb.recordImplicitException(masm.position(), state);
+                        masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD));
+                        masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD));
+                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+                        masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD));
+                        break;
+                    default:
+                        throw GraalError.shouldNotReachHere();
+                }
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static final class SPARCIMulccOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<SPARCIMulccOp> TYPE = LIRInstructionClass.create(SPARCIMulccOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(10);
+        @Def({REG}) protected Value result;
+        @Alive({REG}) protected Value x;
+        @Alive({REG}) protected Value y;
+
+        public SPARCIMulccOp(Value result, Value x, Value y) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            try (ScratchRegister tmpScratch = masm.getScratchRegister()) {
+                Register tmp = tmpScratch.getRegister();
+                Register resultRegister = asRegister(result, WORD);
+                Register xRegister = asRegister(x, WORD);
+                Register yRegister = asRegister(y, WORD);
+                masm.sra(xRegister, 0, xRegister);
+                masm.sra(yRegister, 0, yRegister);
+                masm.mulx(xRegister, yRegister, resultRegister);
+                Label noOverflow = new Label();
+                masm.sra(resultRegister, 0, tmp);
+                masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null);
+                masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT));
+                masm.bind(noOverflow);
+            }
+        }
+    }
+
+    /**
+     * Calculates the product and condition code for long multiplication of long values.
+     */
+    public static final class SPARCLMulccOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<SPARCLMulccOp> TYPE = LIRInstructionClass.create(SPARCLMulccOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(13);
+
+        @Def({REG}) protected Value result;
+        @Alive({REG}) protected Value x;
+        @Alive({REG}) protected Value y;
+        @Temp({REG}) protected Value scratch1;
+        @Temp({REG}) protected Value scratch2;
+
+        public SPARCLMulccOp(Value result, Value x, Value y, LIRGeneratorTool gen) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.x = x;
+            this.y = y;
+            this.scratch1 = gen.newVariable(LIRKind.combine(x, y));
+            this.scratch2 = gen.newVariable(LIRKind.combine(x, y));
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            Label noOverflow = new Label();
+            masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD));
+
+            // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x))
+            masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
+            masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD));
+            masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD));
+            masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD));
+
+            masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD));
+            masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD));
+            masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD));
+
+            // Now construct the lower half and compare
+            masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD));
+            masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD));
+            BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow);
+            masm.nop();
+            masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT));
+            masm.bind(noOverflow);
+        }
+    }
+
+    public static final class MulHighOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(4);
+
+        @Opcode private final MulHigh opcode;
+        @Def({REG}) public AllocatableValue result;
+        @Alive({REG}) public AllocatableValue x;
+        @Alive({REG}) public AllocatableValue y;
+        @Temp({REG}) public AllocatableValue scratch;
+
+        public enum MulHigh {
+            IMUL,
+            LMUL
+        }
+
+        public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) {
+            super(TYPE, SIZE);
+            this.opcode = opcode;
+            this.x = x;
+            this.y = y;
+            this.scratch = scratch;
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch);
+            switch (opcode) {
+                case IMUL:
+                    masm.sra(asRegister(x), 0, asRegister(x));
+                    masm.sra(asRegister(y), 0, asRegister(y));
+                    masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD));
+                    masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD));
+                    break;
+                case LMUL:
+                    assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD));
+                    masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD));
+
+                    masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD));
+                    masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD));
+                    masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD));
+
+                    masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD));
+                    masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD));
+                    masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD));
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java
new file mode 100644
index 0000000..1a0be88
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARCKind;
+import sun.misc.Unsafe;
+
+/**
+ * Emits code which compares two arrays of the same length.
+ */
+@Opcode("ARRAY_EQUALS")
+public final class SPARCArrayEqualsOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCArrayEqualsOp> TYPE = LIRInstructionClass.create(SPARCArrayEqualsOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(32);
+
+    private final JavaKind kind;
+    private final int arrayBaseOffset;
+    private final int arrayIndexScale;
+
+    @Def({REG}) protected Value resultValue;
+    @Alive({REG}) protected Value array1Value;
+    @Alive({REG}) protected Value array2Value;
+    @Alive({REG}) protected Value lengthValue;
+    @Temp({REG}) protected Value temp1;
+    @Temp({REG}) protected Value temp2;
+    @Temp({REG}) protected Value temp3;
+    @Temp({REG}) protected Value temp4;
+    @Temp({REG}) protected Value temp5;
+
+    public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) {
+        super(TYPE, SIZE);
+        this.kind = kind;
+
+        Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
+        this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass);
+        this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass);
+
+        this.resultValue = result;
+        this.array1Value = array1;
+        this.array2Value = array2;
+        this.lengthValue = length;
+
+        // Allocate some temporaries.
+        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+        this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+        this.temp5 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register array1 = asRegister(temp1);
+        Register array2 = asRegister(temp2);
+        Register length = asRegister(temp3);
+
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label done = new Label();
+
+        // Load array base addresses.
+        masm.add(asRegister(array1Value), arrayBaseOffset, array1);
+        masm.add(asRegister(array2Value), arrayBaseOffset, array2);
+
+        // Get array length in bytes.
+        masm.mulx(asRegister(lengthValue, WORD), arrayIndexScale, length);
+        masm.mov(length, result); // copy
+
+        emit8ByteCompare(masm, result, array1, array2, length, trueLabel, falseLabel);
+        emitTailCompares(masm, result, array1, array2, trueLabel, falseLabel);
+
+        // Return true
+        masm.bind(trueLabel);
+        masm.mov(1, result);
+        masm.jmp(done);
+
+        // Return false
+        masm.bind(falseLabel);
+        masm.mov(g0, result);
+
+        // That's it
+        masm.bind(done);
+    }
+
+    /**
+     * Vector size used in {@link #emit8ByteCompare}.
+     */
+    private static final int VECTOR_SIZE = 8;
+
+    /**
+     * Emits code that uses 8-byte vector compares.
+     */
+    private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
+        assert lengthValue.getPlatformKind().equals(SPARCKind.WORD);
+        Label loop = new Label();
+        Label compareTail = new Label();
+        Label compareTailCorrectVectorEnd = new Label();
+
+        Register tempReg1 = asRegister(temp4);
+        Register tempReg2 = asRegister(temp5);
+
+        masm.sra(length, 0, length);
+        masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes)
+        masm.andcc(length, ~(VECTOR_SIZE - 1), length);  // vector count (in bytes)
+        BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_NOT_TAKEN, compareTail);
+
+        masm.sub(length, VECTOR_SIZE, length); // Delay slot
+        masm.add(array1, length, array1);
+        masm.add(array2, length, array2);
+        masm.sub(g0, length, length);
+
+        // Compare the last element first
+        masm.ldx(new SPARCAddress(array1, 0), tempReg1);
+        masm.ldx(new SPARCAddress(array2, 0), tempReg2);
+        masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null);
+        masm.compareBranch(length, 0, Equal, Xcc, compareTailCorrectVectorEnd, PREDICT_NOT_TAKEN, null);
+
+        // Load the first value from array 1 (Later done in back branch delay-slot)
+        masm.ldx(new SPARCAddress(array1, length), tempReg1);
+        masm.bind(loop);
+        masm.ldx(new SPARCAddress(array2, length), tempReg2);
+        masm.cmp(tempReg1, tempReg2);
+
+        BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, falseLabel);
+        // Delay slot, not annul, add for next iteration
+        masm.addcc(length, VECTOR_SIZE, length);
+        // Annul, to prevent access past the array
+        BPCC.emit(masm, Xcc, NotEqual, ANNUL, PREDICT_TAKEN, loop);
+        masm.ldx(new SPARCAddress(array1, length), tempReg1); // Load in delay slot
+
+        // Tail count zero, therefore we can go to the end
+        masm.compareBranch(result, 0, Equal, Xcc, trueLabel, PREDICT_TAKEN, null);
+
+        masm.bind(compareTailCorrectVectorEnd);
+        // Correct the array pointers
+        masm.add(array1, VECTOR_SIZE, array1);
+        masm.add(array2, VECTOR_SIZE, array2);
+
+        masm.bind(compareTail);
+    }
+
+    /**
+     * Emits code to compare the remaining 1 to 4 bytes.
+     */
+    private void emitTailCompares(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Label trueLabel, Label falseLabel) {
+        Label compare2Bytes = new Label();
+        Label compare1Byte = new Label();
+
+        Register tempReg1 = asRegister(temp3);
+        Register tempReg2 = asRegister(temp4);
+
+        if (kind.getByteCount() <= 4) {
+            // Compare trailing 4 bytes, if any.
+            masm.compareBranch(result, 4, Less, Xcc, compare2Bytes, PREDICT_NOT_TAKEN, null);
+
+            masm.lduw(new SPARCAddress(array1, 0), tempReg1);
+            masm.lduw(new SPARCAddress(array2, 0), tempReg2);
+            masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null);
+
+            if (kind.getByteCount() <= 2) {
+                // Move array pointers forward.
+                masm.add(array1, 4, array1);
+                masm.add(array2, 4, array2);
+                masm.sub(result, 4, result);
+
+                // Compare trailing 2 bytes, if any.
+                masm.bind(compare2Bytes);
+
+                masm.compareBranch(result, 2, Less, Xcc, compare1Byte, PREDICT_TAKEN, null);
+
+                masm.lduh(new SPARCAddress(array1, 0), tempReg1);
+                masm.lduh(new SPARCAddress(array2, 0), tempReg2);
+
+                masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null);
+
+                // The one-byte tail compare is only required for boolean and byte arrays.
+                if (kind.getByteCount() <= 1) {
+                    // Move array pointers forward before we compare the last trailing byte.
+                    masm.add(array1, 2, array1);
+                    masm.add(array2, 2, array2);
+                    masm.sub(result, 2, result);
+
+                    // Compare trailing byte, if any.
+                    masm.bind(compare1Byte);
+                    masm.compareBranch(result, 1, NotEqual, Xcc, trueLabel, PREDICT_TAKEN, null);
+
+                    masm.ldub(new SPARCAddress(array1, 0), tempReg1);
+                    masm.ldub(new SPARCAddress(array2, 0), tempReg2);
+                    masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null);
+                } else {
+                    masm.bind(compare1Byte);
+                }
+            } else {
+                masm.bind(compare2Bytes);
+            }
+        }
+    }
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java
new file mode 100644
index 0000000..1221ceb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public final class SPARCBitManipulationOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCBitManipulationOp> TYPE = LIRInstructionClass.create(SPARCBitManipulationOp.class);
+
+    public enum IntrinsicOpcode {
+        IBSR(SizeEstimate.create(13)),
+        LBSR(SizeEstimate.create(14)),
+        BSF(SizeEstimate.create(4));
+
+        final SizeEstimate size;
+
+        IntrinsicOpcode(SizeEstimate size) {
+            this.size = size;
+        }
+    }
+
+    @Opcode private final IntrinsicOpcode opcode;
+    @Def protected AllocatableValue result;
+    @Alive({REG}) protected AllocatableValue input;
+    @Temp({REG}) protected Value scratch;
+
+    public SPARCBitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input, LIRGeneratorTool gen) {
+        super(TYPE, opcode.size);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+        scratch = gen.newVariable(LIRKind.combine(input));
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register dst = asRegister(result, WORD);
+        if (isRegister(input)) {
+            Register src = asRegister(input);
+            switch (opcode) {
+                case BSF:
+                    PlatformKind tkind = input.getPlatformKind();
+                    if (tkind == WORD) {
+                        masm.sub(src, 1, dst);
+                        masm.andn(dst, src, dst);
+                        masm.srl(dst, g0, dst);
+                        masm.popc(dst, dst);
+                    } else if (tkind == XWORD) {
+                        masm.sub(src, 1, dst);
+                        masm.andn(dst, src, dst);
+                        masm.popc(dst, dst);
+                    } else {
+                        throw GraalError.shouldNotReachHere("missing: " + tkind);
+                    }
+                    break;
+                case IBSR: {
+                    PlatformKind ikind = input.getPlatformKind();
+                    assert ikind == WORD;
+                    Register tmp = asRegister(scratch);
+                    assert !tmp.equals(dst);
+                    masm.srl(src, 1, tmp);
+                    masm.srl(src, 0, dst);
+                    masm.or(dst, tmp, dst);
+                    masm.srl(dst, 2, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srl(dst, 4, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srl(dst, 8, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srl(dst, 16, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.popc(dst, dst);
+                    masm.sub(dst, 1, dst);
+                    break;
+                }
+                case LBSR: {
+                    PlatformKind lkind = input.getPlatformKind();
+                    assert lkind == XWORD;
+                    Register tmp = asRegister(scratch);
+                    assert !tmp.equals(dst);
+                    masm.srlx(src, 1, tmp);
+                    masm.or(src, tmp, dst);
+                    masm.srlx(dst, 2, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srlx(dst, 4, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srlx(dst, 8, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srlx(dst, 16, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.srlx(dst, 32, tmp);
+                    masm.or(dst, tmp, dst);
+                    masm.popc(dst, dst);
+                    masm.sub(dst, 1, dst); // This is required to fit the given structure.
+                    break;
+                }
+                default:
+                    throw GraalError.shouldNotReachHere();
+
+            }
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java
new file mode 100644
index 0000000..ed551fc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.AbstractBlockEndOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public abstract class SPARCBlockEndOp extends AbstractBlockEndOp implements SPARCLIRInstructionMixin {
+    public static final LIRInstructionClass<SPARCBlockEndOp> TYPE = LIRInstructionClass.create(SPARCBlockEndOp.class);
+    private final SPARCLIRInstructionMixinStore store;
+
+    protected SPARCBlockEndOp(LIRInstructionClass<? extends SPARCBlockEndOp> c) {
+        this(c, null);
+    }
+
+    protected SPARCBlockEndOp(LIRInstructionClass<? extends SPARCBlockEndOp> c, SizeEstimate sizeEstimate) {
+        super(c);
+        store = new SPARCLIRInstructionMixinStore(sizeEstimate);
+    }
+
+    @Override
+    public SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore() {
+        return store;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (SPARCMacroAssembler) crb.asm);
+    }
+
+    protected abstract void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java
new file mode 100644
index 0000000..e1d97eb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Emits a breakpoint.
+ */
+@Opcode("BREAKPOINT")
+public final class SPARCBreakpointOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCBreakpointOp> TYPE = LIRInstructionClass.create(SPARCBreakpointOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    // historical - from hotspot src/cpu/sparc/vm
+    // <sys/trap.h> promises that the system will not use traps 16-31
+    // We want to use ST_BREAKPOINT here, but the debugger is confused by it.
+    public static final int ST_RESERVED_FOR_USER_0 = 0x10;
+
+    /**
+     * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger).
+     */
+    @Use({REG, STACK}) protected Value[] parameters;
+
+    public SPARCBreakpointOp(Value[] parameters) {
+        super(TYPE, SIZE);
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        masm.ta(ST_RESERVED_FOR_USER_0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java
new file mode 100644
index 0000000..4679dacc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Asi;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARCKind;
+
+@Opcode("BSWAP")
+public final class SPARCByteSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCByteSwapOp> TYPE = LIRInstructionClass.create(SPARCByteSwapOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(3);
+    @Def({REG, HINT}) protected Value result;
+    @Use({REG}) protected Value input;
+    @Temp({REG}) protected Value tempIndex;
+    @Use({STACK, UNINITIALIZED}) protected AllocatableValue tmpSlot;
+
+    public SPARCByteSwapOp(LIRGeneratorTool tool, Value result, Value input) {
+        super(TYPE, SIZE);
+        this.result = result;
+        this.input = input;
+        this.tmpSlot = tool.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(XWORD));
+        this.tempIndex = tool.newVariable(LIRKind.value(XWORD));
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        SPARCAddress addr = (SPARCAddress) crb.asAddress(tmpSlot);
+        SPARCMove.emitStore(input, addr, result.getPlatformKind(), SPARCDelayedControlTransfer.DUMMY, null, crb, masm);
+        if (addr.getIndex().equals(Register.None)) {
+            Register tempReg = ValueUtil.asRegister(tempIndex, XWORD);
+            masm.setx(addr.getDisplacement(), tempReg, false);
+            addr = new SPARCAddress(addr.getBase(), tempReg);
+        }
+        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+        switch ((SPARCKind) input.getPlatformKind()) {
+            case WORD:
+                masm.lduwa(addr.getBase(), addr.getIndex(), asRegister(result, WORD), Asi.ASI_PRIMARY_LITTLE);
+                break;
+            case XWORD:
+                masm.ldxa(addr.getBase(), addr.getIndex(), asRegister(result, XWORD), Asi.ASI_PRIMARY_LITTLE);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java
new file mode 100644
index 0000000..0500842
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+public class SPARCCall {
+
+    public abstract static class CallOp extends SPARCLIRInstruction {
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @Temp({REG, STACK}) protected Value[] temps;
+        @State protected LIRFrameState state;
+
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, size);
+            this.result = result;
+            this.parameters = parameters;
+            this.state = state;
+            this.temps = addStackSlotsToTemporaries(parameters, temps);
+            assert temps != null;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return true;
+        }
+    }
+
+    public abstract static class MethodCallOp extends CallOp {
+
+        protected final ResolvedJavaMethod callTarget;
+
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, size, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+
+    }
+
+    @Opcode("CALL_DIRECT")
+    public abstract static class DirectCallOp extends MethodCallOp {
+        private boolean emitted = false;
+        private int before = -1;
+
+        public DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, size, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (!emitted) {
+                emitCallPrefixCode(crb, masm);
+                directCall(crb, masm, callTarget, null, state);
+            } else {
+                int after = masm.position();
+                if (after - before == 4) {
+                    masm.nop();
+                } else if (after - before == 8) {
+                    // everything is fine;
+                } else {
+                    GraalError.shouldNotReachHere("" + (after - before));
+                }
+                after = masm.position();
+                crb.recordDirectCall(before, after, callTarget, state);
+                crb.recordExceptionHandlers(after, state);
+                masm.ensureUniquePC();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            //
+        }
+
+        public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            assert !emitted;
+            emitCallPrefixCode(crb, masm);
+            before = masm.call(0);
+            emitted = true;
+        }
+
+        public void resetState() {
+            emitted = false;
+            before = -1;
+        }
+    }
+
+    @Opcode("CALL_INDIRECT")
+    public abstract static class IndirectCallOp extends MethodCallOp {
+        @Use({REG}) protected Value targetAddress;
+
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps,
+                        Value targetAddress, LIRFrameState state) {
+            super(c, size, callTarget, result, parameters, temps, state);
+            this.targetAddress = targetAddress;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now";
+        }
+    }
+
+    public abstract static class ForeignCallOp extends CallOp {
+        public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
+
+        protected final ForeignCallLinkage callTarget;
+
+        public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, size, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
+        }
+    }
+
+    @Opcode("NEAR_FOREIGN_CALL")
+    public static final class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, SIZE, linkage, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, state);
+        }
+    }
+
+    @Opcode("FAR_FOREIGN_CALL")
+    public static final class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, SIZE, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            try (ScratchRegister scratch = masm.getScratchRegister()) {
+                directCall(crb, masm, callTarget, scratch.getRegister(), state);
+            }
+        }
+    }
+
+    public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) {
+        int before;
+        if (scratch != null) {
+            // offset might not fit a 30-bit displacement, generate an
+            // indirect call with a 64-bit immediate
+            before = masm.position();
+            masm.sethix(0L, scratch, true);
+            masm.jmpl(scratch, 0, o7);
+        } else {
+            before = masm.call(0);
+        }
+        masm.nop();  // delay slot
+        int after = masm.position();
+        crb.recordDirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) {
+        int before = masm.position();
+        masm.sethix(0L, dst, true);
+        masm.jmp(new SPARCAddress(dst, 0));
+        masm.nop();  // delay slot
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
+        int before = masm.jmpl(dst, 0, o7);
+        masm.nop();  // delay slot
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java
new file mode 100644
index 0000000..a7823bb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm10;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm11;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm5;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Equal;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Greater;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_GreaterOrEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Less;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_LessOrEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedGreaterOrEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrGreater;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLess;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLessOrEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Greater;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqualUnsigned;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterUnsigned;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqualUnsigned;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessUnsigned;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.sparc.SPARCMove.const2reg;
+import static org.graalvm.compiler.lir.sparc.SPARCOP3Op.emitOp3;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.CPU;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Assembler.LabelHint;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCControlFlow {
+    // This describes the maximum offset between the first emitted (load constant in to scratch,
+    // if does not fit into simm5 of cbcond) instruction and the final branch instruction
+    private static final int maximumSelfOffsetInstructions = 2;
+
+    public static final class ReturnOp extends SPARCBlockEndOp {
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        @Use({REG, ILLEGAL}) protected Value x;
+
+        public ReturnOp(Value x) {
+            super(TYPE, SIZE);
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            emitCodeHelper(crb, masm);
+        }
+
+        public static void emitCodeHelper(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            masm.ret();
+            // On SPARC we always leave the frame (in the delay slot).
+            crb.frameContext.leave(crb);
+        }
+    }
+
+    public static final class CompareBranchOp extends SPARCBlockEndOp implements SPARCDelayedControlTransfer {
+        public static final LIRInstructionClass<CompareBranchOp> TYPE = LIRInstructionClass.create(CompareBranchOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(3);
+        static final EnumSet<SPARCKind> SUPPORTED_KINDS = EnumSet.of(XWORD, WORD);
+
+        @Use({REG}) protected Value x;
+        @Use({REG, CONST}) protected Value y;
+        private ConditionFlag conditionFlag;
+        protected final LabelRef trueDestination;
+        protected LabelHint trueDestinationHint;
+        protected final LabelRef falseDestination;
+        protected LabelHint falseDestinationHint;
+        protected final SPARCKind kind;
+        protected final boolean unorderedIsTrue;
+        private boolean emitted = false;
+        private int delaySlotPosition = -1;
+        private double trueDestinationProbability;
+
+        public CompareBranchOp(Value x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, boolean unorderedIsTrue, double trueDestinationProbability) {
+            super(TYPE, SIZE);
+            this.x = x;
+            this.y = y;
+            this.trueDestination = trueDestination;
+            this.falseDestination = falseDestination;
+            this.kind = kind;
+            this.unorderedIsTrue = unorderedIsTrue;
+            this.trueDestinationProbability = trueDestinationProbability;
+            conditionFlag = fromCondition(kind.isInteger(), condition, unorderedIsTrue);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (emitted) { // Only if delayed control transfer is used we must check this
+                assert masm.position() - delaySlotPosition == 4 : "Only one instruction can be stuffed into the delay slot";
+            }
+            if (!emitted) {
+                requestHints(masm);
+                int targetPosition = getTargetPosition(masm);
+                if (canUseShortBranch(crb, masm, targetPosition)) {
+                    emitted = emitShortCompareBranch(crb, masm);
+                }
+                if (!emitted) { // No short compare/branch was used, so we go into fallback
+                    emitted = emitLongCompareBranch(crb, masm, true);
+                    emitted = true;
+                }
+            }
+            assert emitted;
+        }
+
+        private boolean emitLongCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, boolean withDelayedNop) {
+            emitOp3(masm, Subcc, x, y);
+            return emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, withDelayedNop, trueDestinationProbability);
+        }
+
+        private static int getTargetPosition(Assembler asm) {
+            return asm.position() + maximumSelfOffsetInstructions * asm.target.wordSize;
+        }
+
+        @Override
+        public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            requestHints(masm);
+            // When we use short branches, no delay slot is available
+            int targetPosition = getTargetPosition(masm);
+            if (!canUseShortBranch(crb, masm, targetPosition)) {
+                emitted = emitLongCompareBranch(crb, masm, false);
+                if (emitted) {
+                    delaySlotPosition = masm.position();
+                }
+            }
+        }
+
+        private void requestHints(SPARCMacroAssembler masm) {
+            if (trueDestinationHint == null) {
+                this.trueDestinationHint = masm.requestLabelHint(trueDestination.label());
+            }
+            if (falseDestinationHint == null) {
+                this.falseDestinationHint = masm.requestLabelHint(falseDestination.label());
+            }
+        }
+
+        /**
+         * Tries to use the emit the compare/branch instruction.
+         * <p>
+         * CBcond has follwing limitations
+         * <ul>
+         * <li>Immediate field is only 5 bit and is on the right
+         * <li>Jump offset is maximum of -+512 instruction
+         *
+         * <p>
+         * We get from outside
+         * <ul>
+         * <li>at least one of trueDestination falseDestination is within reach of +-512
+         * instructions
+         * <li>two registers OR one register and a constant which fits simm13
+         *
+         * <p>
+         * We do:
+         * <ul>
+         * <li>find out which target needs to be branched conditionally
+         * <li>find out if fall-through is possible, if not, a unconditional branch is needed after
+         * cbcond (needJump=true)
+         * <li>if no fall through: we need to put the closer jump into the cbcond branch and the
+         * farther into the jmp (unconditional branch)
+         * <li>if constant on the left side, mirror to be on the right
+         * <li>if constant on right does not fit into simm5, put it into a scratch register
+         *
+         * @param crb
+         * @param masm
+         * @return true if the branch could be emitted
+         */
+        private boolean emitShortCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            ConditionFlag actualConditionFlag = conditionFlag;
+            Label actualTrueTarget = trueDestination.label();
+            Label actualFalseTarget = falseDestination.label();
+            Label tmpTarget;
+            boolean needJump;
+            if (crb.isSuccessorEdge(trueDestination)) {
+                actualConditionFlag = conditionFlag.negate();
+                tmpTarget = actualTrueTarget;
+                actualTrueTarget = actualFalseTarget;
+                actualFalseTarget = tmpTarget;
+                needJump = false;
+            } else {
+                needJump = !crb.isSuccessorEdge(falseDestination);
+                int targetPosition = getTargetPosition(masm);
+                if (needJump && !isShortBranch(masm, targetPosition, trueDestinationHint, actualTrueTarget)) {
+                    // we have to jump in either way, so we must put the shorter
+                    // branch into the actualTarget as only one of the two jump targets
+                    // is guaranteed to be simm10
+                    actualConditionFlag = actualConditionFlag.negate();
+                    tmpTarget = actualTrueTarget;
+                    actualTrueTarget = actualFalseTarget;
+                    actualFalseTarget = tmpTarget;
+                }
+            }
+            emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag);
+            if (needJump) {
+                masm.jmp(actualFalseTarget);
+                masm.nop();
+            }
+            return true;
+        }
+
+        private void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag) {
+            PlatformKind xKind = actualX.getPlatformKind();
+            boolean isLong = kind == SPARCKind.XWORD;
+            if (isJavaConstant(actualY)) {
+                JavaConstant c = asJavaConstant(actualY);
+                long constantY = c.isNull() ? 0 : c.asLong();
+                assert NumUtil.isInt(constantY);
+                CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), (int) constantY, actualTrueTarget);
+            } else {
+                CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), asRegister(actualY, xKind), actualTrueTarget);
+            }
+        }
+
+        private boolean canUseShortBranch(CompilationResultBuilder crb, SPARCAssembler asm, int position) {
+            if (!asm.hasFeature(CPUFeature.CBCOND)) {
+                return false;
+            }
+            if (!((SPARCKind) x.getPlatformKind()).isInteger()) {
+                return false;
+            }
+            // Do not use short branch, if the y value is a constant and does not fit into simm5 but
+            // fits into simm13; this means the code with CBcond would be longer as the code without
+            // CBcond.
+            if (isJavaConstant(y) && !isSimm5(asJavaConstant(y)) && isSimm13(asJavaConstant(y))) {
+                return false;
+            }
+            boolean hasShortJumpTarget = false;
+            if (!crb.isSuccessorEdge(trueDestination)) {
+                hasShortJumpTarget |= isShortBranch(asm, position, trueDestinationHint, trueDestination.label());
+            }
+            if (!crb.isSuccessorEdge(falseDestination)) {
+                hasShortJumpTarget |= isShortBranch(asm, position, falseDestinationHint, falseDestination.label());
+            }
+            return hasShortJumpTarget;
+        }
+
+        @Override
+        public void resetState() {
+            emitted = false;
+            delaySlotPosition = -1;
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert SUPPORTED_KINDS.contains(kind) : kind;
+            assert !isConstantValue(x);
+            assert x.getPlatformKind().equals(kind) && (isConstantValue(y) || y.getPlatformKind().equals(kind)) : x + " " + y;
+        }
+    }
+
+    public static boolean isShortBranch(SPARCAssembler asm, int position, LabelHint hint, Label label) {
+        int disp = 0;
+        boolean dispValid = true;
+        if (label.isBound()) {
+            disp = label.position() - position;
+        } else if (hint != null && hint.isValid()) {
+            disp = hint.getTarget() - hint.getPosition();
+        } else {
+            dispValid = false;
+        }
+        if (dispValid) {
+            if (disp < 0) {
+                disp -= maximumSelfOffsetInstructions * asm.target.wordSize;
+            } else {
+                disp += maximumSelfOffsetInstructions * asm.target.wordSize;
+            }
+            return isSimm10(disp >> 2);
+        } else if (hint == null) {
+            asm.requestLabelHint(label);
+        }
+        return false;
+    }
+
+    public static final class BranchOp extends SPARCBlockEndOp implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+        protected final ConditionFlag conditionFlag;
+        protected final LabelRef trueDestination;
+        protected final LabelRef falseDestination;
+        protected final SPARCKind kind;
+        protected final double trueDestinationProbability;
+
+        public BranchOp(ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, double trueDestinationProbability) {
+            super(TYPE, SIZE);
+            this.trueDestination = trueDestination;
+            this.falseDestination = falseDestination;
+            this.kind = kind;
+            this.conditionFlag = conditionFlag;
+            this.trueDestinationProbability = trueDestinationProbability;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, true, trueDestinationProbability);
+        }
+    }
+
+    private static boolean emitBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind kind, ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination,
+                    boolean withDelayedNop, double trueDestinationProbability) {
+        Label actualTarget;
+        ConditionFlag actualConditionFlag;
+        boolean needJump;
+        BranchPredict predictTaken;
+        if (falseDestination != null && crb.isSuccessorEdge(trueDestination)) {
+            actualConditionFlag = conditionFlag != null ? conditionFlag.negate() : null;
+            actualTarget = falseDestination.label();
+            needJump = false;
+            predictTaken = trueDestinationProbability < .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN;
+        } else {
+            actualConditionFlag = conditionFlag;
+            actualTarget = trueDestination.label();
+            needJump = falseDestination != null && !crb.isSuccessorEdge(falseDestination);
+            predictTaken = trueDestinationProbability > .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN;
+        }
+        if (!withDelayedNop && needJump) {
+            // We cannot make use of the delay slot when we jump in true-case and false-case
+            return false;
+        }
+        if (kind.isFloat()) {
+            FBPCC.emit(masm, Fcc0, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget);
+        } else {
+            assert kind.isInteger();
+            CC cc = kind.equals(WORD) ? Icc : Xcc;
+            BPCC.emit(masm, cc, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget);
+        }
+        if (withDelayedNop) {
+            masm.nop();  // delay slot
+        }
+        if (needJump) {
+            masm.jmp(falseDestination.label());
+        }
+        return true;
+    }
+
+    public static class StrategySwitchOp extends SPARCBlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
+        protected Constant[] keyConstants;
+        private final LabelRef[] keyTargets;
+        private LabelRef defaultTarget;
+        @Alive({REG}) protected Value key;
+        @Alive({REG, ILLEGAL}) protected Value constantTableBase;
+        @Temp({REG}) protected Value scratch;
+        protected final SwitchStrategy strategy;
+        private final Map<Label, LabelHint> labelHints;
+        private final List<Label> conditionalLabels = new ArrayList<>();
+
+        public StrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            this(TYPE, constantTableBase, strategy, keyTargets, defaultTarget, key, scratch);
+        }
+
+        protected StrategySwitchOp(LIRInstructionClass<? extends StrategySwitchOp> c, Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key,
+                        Value scratch) {
+            super(c);
+            this.strategy = strategy;
+            this.keyConstants = strategy.getKeyConstants();
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+            this.constantTableBase = constantTableBase;
+            this.key = key;
+            this.scratch = scratch;
+            this.labelHints = new HashMap<>();
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+        }
+
+        @Override
+        public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) {
+            final Register keyRegister = asRegister(key);
+            final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase);
+            strategy.run(new SwitchClosure(keyRegister, constantBaseRegister, crb, masm));
+        }
+
+        public class SwitchClosure extends BaseSwitchClosure {
+            private int conditionalLabelPointer = 0;
+
+            protected final Register keyRegister;
+            protected final Register constantBaseRegister;
+            protected final CompilationResultBuilder crb;
+            protected final SPARCMacroAssembler masm;
+
+            protected SwitchClosure(Register keyRegister, Register constantBaseRegister, CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+                super(crb, masm, keyTargets, defaultTarget);
+                this.keyRegister = keyRegister;
+                this.constantBaseRegister = constantBaseRegister;
+                this.crb = crb;
+                this.masm = masm;
+            }
+
+            /**
+             * This method caches the generated labels over two assembly passes to get information
+             * about branch lengths.
+             */
+            @Override
+            public Label conditionalJump(int index, Condition condition) {
+                Label label;
+                if (conditionalLabelPointer <= conditionalLabels.size()) {
+                    label = new Label();
+                    conditionalLabels.add(label);
+                    conditionalLabelPointer = conditionalLabels.size();
+                } else {
+                    // TODO: (sa) We rely here on the order how the labels are generated during
+                    // code generation; if the order is not stable ower two assembly passes, the
+                    // result can be wrong
+                    label = conditionalLabels.get(conditionalLabelPointer++);
+                }
+                conditionalJump(index, condition, label);
+                return label;
+            }
+
+            @Override
+            protected void conditionalJump(int index, Condition condition, Label target) {
+                JavaConstant constant = (JavaConstant) keyConstants[index];
+                CC conditionCode;
+                Long bits = constant.asLong();
+                switch (constant.getJavaKind()) {
+                    case Char:
+                    case Byte:
+                    case Short:
+                    case Int:
+                        conditionCode = CC.Icc;
+                        break;
+                    case Long:
+                        conditionCode = CC.Xcc;
+                        break;
+                    default:
+                        throw new GraalError("switch only supported for int, long and object");
+                }
+                ConditionFlag conditionFlag = fromCondition(keyRegister.getRegisterCategory().equals(CPU), condition, false);
+                LabelHint hint = requestHint(masm, target);
+                boolean isShortConstant = isSimm5(constant);
+                int cbCondPosition = masm.position();
+                if (!isShortConstant) { // Load constant takes one instruction
+                    cbCondPosition += INSTRUCTION_SIZE;
+                }
+                boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && isShortBranch(masm, cbCondPosition, hint, target);
+                if (bits != null && canUseShortBranch) {
+                    if (isShortConstant) {
+                        CBCOND.emit(masm, conditionFlag, conditionCode == Xcc, keyRegister, (int) (long) bits, target);
+                    } else {
+                        Register scratchRegister = asRegister(scratch);
+                        const2reg(crb, masm, scratch, constantBaseRegister, (JavaConstant) keyConstants[index], SPARCDelayedControlTransfer.DUMMY);
+                        CBCOND.emit(masm, conditionFlag, conditionCode == Xcc, keyRegister, scratchRegister, target);
+                    }
+                } else {
+                    if (bits != null && isSimm13(constant)) {
+                        masm.cmp(keyRegister, (int) (long) bits); // Cast is safe
+                    } else {
+                        Register scratchRegister = asRegister(scratch);
+                        const2reg(crb, masm, scratch, constantBaseRegister, (JavaConstant) keyConstants[index], SPARCDelayedControlTransfer.DUMMY);
+                        masm.cmp(keyRegister, scratchRegister);
+                    }
+                    BPCC.emit(masm, conditionCode, conditionFlag, ANNUL, PREDICT_TAKEN, target);
+                    masm.nop();  // delay slot
+                }
+            }
+        }
+
+        protected LabelHint requestHint(SPARCMacroAssembler masm, Label label) {
+            LabelHint hint = labelHints.get(label);
+            if (hint == null) {
+                hint = masm.requestLabelHint(label);
+                labelHints.put(label, hint);
+            }
+            return hint;
+        }
+
+        protected int estimateEmbeddedSize(Constant c) {
+            JavaConstant v = (JavaConstant) c;
+            if (!SPARCAssembler.isSimm13(v)) {
+                return v.getJavaKind().getByteCount();
+            } else {
+                return 0;
+            }
+        }
+
+        @Override
+        public SizeEstimate estimateSize() {
+            int constantBytes = 0;
+            for (Constant c : keyConstants) {
+                constantBytes += estimateEmbeddedSize(c);
+            }
+            return new SizeEstimate(4 * keyTargets.length, constantBytes);
+        }
+    }
+
+    public static final class TableSwitchOp extends SPARCBlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
+
+        private final int lowKey;
+        private final LabelRef defaultTarget;
+        private final LabelRef[] targets;
+        @Alive protected Value index;
+        @Temp protected Value scratch;
+
+        public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) {
+            super(TYPE);
+            this.lowKey = lowKey;
+            this.defaultTarget = defaultTarget;
+            this.targets = targets;
+            this.index = index;
+            this.scratch = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            Register value = asRegister(index, SPARCKind.WORD);
+            Register scratchReg = asRegister(scratch, SPARCKind.XWORD);
+
+            // Compare index against jump table bounds
+            int highKey = lowKey + targets.length - 1;
+
+            // subtract the low value from the switch value
+            if (isSimm13(lowKey)) {
+                masm.sub(value, lowKey, scratchReg);
+            } else {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch2 = sc.getRegister();
+                    masm.setx(lowKey, scratch2, false);
+                    masm.sub(value, scratch2, scratchReg);
+                }
+            }
+            int upperLimit = highKey - lowKey;
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch2 = sc.getRegister();
+                if (isSimm13(upperLimit)) {
+                    masm.cmp(scratchReg, upperLimit);
+                } else {
+                    masm.setx(upperLimit, scratch2, false);
+                    masm.cmp(scratchReg, upperLimit);
+                }
+
+                // Jump to default target if index is not within the jump table
+                if (defaultTarget != null) {
+                    BPCC.emit(masm, Icc, GreaterUnsigned, NOT_ANNUL, PREDICT_TAKEN, defaultTarget.label());
+                    masm.nop();  // delay slot
+                }
+
+                // Load jump table entry into scratch and jump to it
+                masm.sll(scratchReg, 3, scratchReg); // Multiply by 8
+                // Zero the left bits sll with shcnt>0 does not mask upper 32 bits
+                masm.srl(scratchReg, 0, scratchReg);
+                masm.rdpc(scratch2);
+
+                // The jump table follows four instructions after rdpc
+                masm.add(scratchReg, 4 * 4, scratchReg);
+                masm.jmpl(scratch2, scratchReg, g0);
+            }
+            masm.nop();
+
+            // Emit jump table entries
+            for (LabelRef target : targets) {
+                BPCC.emit(masm, Xcc, Always, NOT_ANNUL, PREDICT_TAKEN, target.label());
+                masm.nop(); // delay slot
+            }
+        }
+
+        @Override
+        public SizeEstimate estimateSize() {
+            return SizeEstimate.create(17 + targets.length * 2);
+        }
+    }
+
+    @Opcode("CMOVE")
+    public static final class CondMoveOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
+
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, CONST}) protected Value trueValue;
+        @Use({REG, CONST}) protected Value falseValue;
+
+        private final ConditionFlag condition;
+        private final CC cc;
+        private final CMOV cmove;
+
+        public CondMoveOp(CMOV cmove, CC cc, ConditionFlag condition, Value trueValue, Value falseValue, Value result) {
+            super(TYPE);
+            this.result = result;
+            this.condition = condition;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+            this.cc = cc;
+            this.cmove = cmove;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (result.equals(trueValue)) { // We have the true value in place, do he opposite
+                cmove(masm, condition.negate(), falseValue);
+            } else if (result.equals(falseValue)) {
+                cmove(masm, condition, trueValue);
+            } else { // We have to move one of the input values to the result
+                ConditionFlag actualCondition = condition;
+                Value actualTrueValue = trueValue;
+                Value actualFalseValue = falseValue;
+                if (isJavaConstant(falseValue) && isSimm11(asJavaConstant(falseValue))) {
+                    actualCondition = condition.negate();
+                    actualTrueValue = falseValue;
+                    actualFalseValue = trueValue;
+                }
+                SPARCMove.move(crb, masm, result, actualFalseValue, SPARCDelayedControlTransfer.DUMMY);
+                cmove(masm, actualCondition, actualTrueValue);
+            }
+        }
+
+        private void cmove(SPARCMacroAssembler masm, ConditionFlag localCondition, Value value) {
+            if (isConstantValue(value)) {
+                cmove.emit(masm, localCondition, cc, asImmediate(asJavaConstant(value)), asRegister(result));
+            } else {
+                cmove.emit(masm, localCondition, cc, asRegister(value), asRegister(result));
+            }
+        }
+
+        @Override
+        public SizeEstimate estimateSize() {
+            int constantSize = 0;
+            if (isJavaConstant(trueValue) && !SPARCAssembler.isSimm13(asJavaConstant(trueValue))) {
+                constantSize += trueValue.getPlatformKind().getSizeInBytes();
+            }
+            if (isJavaConstant(falseValue) && !SPARCAssembler.isSimm13(asJavaConstant(falseValue))) {
+                constantSize += trueValue.getPlatformKind().getSizeInBytes();
+            }
+            return SizeEstimate.create(3, constantSize);
+        }
+    }
+
+    public static ConditionFlag fromCondition(boolean integer, Condition cond, boolean unorderedIsTrue) {
+        if (integer) {
+            switch (cond) {
+                case EQ:
+                    return Equal;
+                case NE:
+                    return NotEqual;
+                case BT:
+                    return LessUnsigned;
+                case LT:
+                    return Less;
+                case BE:
+                    return LessEqualUnsigned;
+                case LE:
+                    return LessEqual;
+                case AE:
+                    return GreaterEqualUnsigned;
+                case GE:
+                    return GreaterEqual;
+                case AT:
+                    return GreaterUnsigned;
+                case GT:
+                    return Greater;
+            }
+            throw GraalError.shouldNotReachHere("Unimplemented for: " + cond);
+        } else {
+            switch (cond) {
+                case EQ:
+                    return unorderedIsTrue ? F_UnorderedOrEqual : F_Equal;
+                case NE:
+                    return ConditionFlag.F_NotEqual;
+                case LT:
+                    return unorderedIsTrue ? F_UnorderedOrLess : F_Less;
+                case LE:
+                    return unorderedIsTrue ? F_UnorderedOrLessOrEqual : F_LessOrEqual;
+                case GE:
+                    return unorderedIsTrue ? F_UnorderedGreaterOrEqual : F_GreaterOrEqual;
+                case GT:
+                    return unorderedIsTrue ? F_UnorderedOrGreater : F_Greater;
+            }
+            throw GraalError.shouldNotReachHere("Unkown condition: " + cond);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCDelayedControlTransfer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCDelayedControlTransfer.java
new file mode 100644
index 0000000..d403145
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCDelayedControlTransfer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * This interface is used for {@link LIRInstruction}s which provide a delay slot for one instruction
+ * from another {@link LIRInstruction}.
+ *
+ * @see SPARCTailDelayedLIRInstruction
+ */
+public interface SPARCDelayedControlTransfer {
+
+    SPARCDelayedControlTransfer DUMMY = new SPARCDelayedControlTransfer() {
+        @Override
+        public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            // do nothing
+        }
+
+        @Override
+        public String toString() {
+            return "null";
+        }
+
+        @Override
+        public void resetState() {
+        }
+    };
+
+    /**
+     * This method must be called, to generate the control transfer, but without any Nop in the
+     * delay slot.
+     *
+     * @param crb
+     * @param masm
+     */
+    void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm);
+
+    void resetState();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFloatCompareOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFloatCompareOp.java
new file mode 100644
index 0000000..0d256d4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFloatCompareOp.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+public class SPARCFloatCompareOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCFloatCompareOp> TYPE = LIRInstructionClass.create(SPARCFloatCompareOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    private final CC cc;
+    @Opcode protected final Opfs opf;
+    @Use({REG}) protected Value a;
+    @Use({REG}) protected Value b;
+
+    public SPARCFloatCompareOp(Opfs opf, CC cc, Value a, Value b) {
+        super(TYPE, SIZE);
+        this.cc = cc;
+        this.opf = opf;
+        this.a = a;
+        this.b = b;
+    }
+
+    @Override
+    protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+        SPARCAssembler.OpfOp.emitFcmp(masm, opf, cc, asRegister(a), asRegister(b));
+    }
+
+    @Override
+    public void verify() {
+        assert a.getPlatformKind().equals(b.getPlatformKind()) : "a: " + a + " b: " + b;
+        assert opf.equals(Opfs.Fcmpd) || opf.equals(Opfs.Fcmps) : opf;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMap.java
new file mode 100644
index 0000000..0c600a2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMap.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.ValueKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * SPARC specific frame map.
+ *
+ * This is the format of a SPARC stack frame:
+ *
+ * <pre>
+ *   Base       Contents
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *            +--------------------------------+    |
+ *            |                                |    |
+ *            : register save area             :    |
+ *            |                                |    |
+ *   ---------+--------------------------------+---------------------------
+ *            | spill slot 0                   |    | negative   ^      ^
+ *            :     ...                        :    v offsets    |      |
+ *            | spill slot n                   |  -----        total    |
+ *            +--------------------------------+               frame    |
+ *   current  | alignment padding              |               size     |
+ *   frame    +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |    frame
+ *            :     ...                        :    | positive   |    size
+ *            | outgoing overflow argument 0   |    | offsets    |      |
+ *            +--------------------------------+    |            |      |
+ *            | return address                 |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            |                                |    |            |      |
+ *            : callee save area               :    |            |      |
+ *            |                                |    |            v      v
+ *    %sp--&gt;  +--------------------------------+---------------------------
+ *
+ * </pre>
+ *
+ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such
+ * a block may be greater than the size of a normal spill slot or the word size.
+ * <p>
+ * A runtime can reserve space at the beginning of the overflow argument area. The calling
+ * convention can specify that the first overflow stack argument is not at offset 0, but at a
+ * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that
+ * call-free methods also have this space reserved. Then the VM can use the memory at offset 0
+ * relative to the stack pointer.
+ */
+public final class SPARCFrameMap extends FrameMap {
+
+    public SPARCFrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
+        // Initial spill size is set to register save area size (SPARC register window)
+        initialSpillSize = 0;
+        spillSize = initialSpillSize;
+    }
+
+    @Override
+    public int totalFrameSize() {
+        return frameSize();
+    }
+
+    @Override
+    public int currentFrameSize() {
+        return alignFrameSize(SPARC.REGISTER_SAFE_AREA_SIZE + outgoingSize + spillSize);
+    }
+
+    /**
+     * In SPARC we have spill slots word aligned.
+     */
+    @Override
+    public int spillSlotSize(ValueKind<?> kind) {
+        return kind.getPlatformKind().getSizeInBytes();
+    }
+
+    @Override
+    public int offsetForStackSlot(StackSlot slot) {
+        // @formatter:off
+        assert (!slot.getRawAddFrameSize() && slot.getRawOffset() <  outgoingSize + SPARC.REGISTER_SAFE_AREA_SIZE) ||
+               (slot.getRawAddFrameSize() && slot.getRawOffset()  <  0 && -slot.getRawOffset() <= spillSize) ||
+               (slot.getRawAddFrameSize() && slot.getRawOffset()  >= 0) :
+                   String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize);
+        // @formatter:on
+        return super.offsetForStackSlot(slot);
+    }
+
+    @Override
+    public boolean frameNeedsAllocating() {
+        return super.frameNeedsAllocating() || spillSize > 0;
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        assert spillSize == initialSpillSize : "Deoptimization rescue slot must be the first stack slot";
+        return allocateSpillSlot(LIRKind.value(SPARCKind.XWORD));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMapBuilder.java
new file mode 100644
index 0000000..e7386ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCFrameMapBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderImpl;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+public class SPARCFrameMapBuilder extends FrameMapBuilderImpl {
+
+    public SPARCFrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+        super(frameMap, codeCache, registerConfig);
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        return ((SPARCFrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCImmediateAddressValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCImmediateAddressValue.java
new file mode 100644
index 0000000..c6cead8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCImmediateAddressValue.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class SPARCImmediateAddressValue extends SPARCAddressValue {
+
+    @Component({REG}) protected AllocatableValue base;
+    protected final int displacement;
+
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG);
+
+    public SPARCImmediateAddressValue(ValueKind<?> kind, AllocatableValue base, int displacement) {
+        super(kind);
+        assert SPARCAssembler.isSimm13(displacement);
+        this.base = base;
+        this.displacement = displacement;
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        if (!base.identityEquals(newBase)) {
+            return new SPARCImmediateAddressValue(getValueKind(), newBase, displacement);
+        }
+        return this;
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+    }
+
+    @Override
+    public SPARCAddress toAddress() {
+        return new SPARCAddress(asRegister(base), displacement);
+    }
+
+    @Override
+    public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) {
+        return value.equals(base) && displacement >= 0 && displacement < implicitNullCheckLimit;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SPARCImmediateAddressValue) {
+            SPARCImmediateAddressValue addr = (SPARCImmediateAddressValue) obj;
+            return getValueKind().equals(addr.getValueKind()) && displacement == addr.displacement && base.equals(addr.base);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ (displacement << 4) ^ getValueKind().hashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCIndexedAddressValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCIndexedAddressValue.java
new file mode 100644
index 0000000..836543d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCIndexedAddressValue.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class SPARCIndexedAddressValue extends SPARCAddressValue {
+
+    @Component({REG}) protected AllocatableValue base;
+    @Component({REG}) protected AllocatableValue index;
+
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG);
+
+    public SPARCIndexedAddressValue(ValueKind<?> kind, AllocatableValue base, AllocatableValue index) {
+        super(kind);
+        this.base = base;
+        this.index = index;
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags);
+        if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) {
+            return new SPARCIndexedAddressValue(getValueKind(), newBase, newIndex);
+        }
+        return this;
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, index, mode, flags);
+    }
+
+    @Override
+    public SPARCAddress toAddress() {
+        return new SPARCAddress(asRegister(base), asRegister(index));
+    }
+
+    @Override
+    public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) {
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (isLegal(index)) {
+            s.append(sep).append(index);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SPARCIndexedAddressValue) {
+            SPARCIndexedAddressValue addr = (SPARCIndexedAddressValue) obj;
+            return getValueKind().equals(addr.getValueKind()) && base.equals(addr.base) && index.equals(addr.index);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ index.hashCode() ^ getValueKind().hashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCJumpOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCJumpOp.java
new file mode 100644
index 0000000..7962057
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCJumpOp.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class SPARCJumpOp extends JumpOp implements SPARCDelayedControlTransfer, SPARCLIRInstructionMixin {
+    public static final LIRInstructionClass<SPARCJumpOp> TYPE = LIRInstructionClass.create(SPARCJumpOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+    private boolean emitDone = false;
+    private int delaySlotPosition = -1;
+    private final SPARCLIRInstructionMixinStore store;
+
+    public SPARCJumpOp(LabelRef destination) {
+        super(TYPE, destination);
+        this.store = new SPARCLIRInstructionMixinStore(SIZE);
+    }
+
+    @Override
+    public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        assert !emitDone;
+        if (!crb.isSuccessorEdge(destination())) {
+            BPCC.emit(masm, Xcc, Always, NOT_ANNUL, PREDICT_TAKEN, destination().label());
+            delaySlotPosition = masm.position();
+        }
+        emitDone = true;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        if (!crb.isSuccessorEdge(destination())) {
+            if (!emitDone) {
+                SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+                masm.jmp(destination().label());
+            } else {
+                int disp = crb.asm.position() - delaySlotPosition;
+                assert disp == 4 : disp;
+            }
+        }
+    }
+
+    @Override
+    public void resetState() {
+        delaySlotPosition = -1;
+        emitDone = false;
+    }
+
+    @Override
+    public SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore() {
+        return store;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstruction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstruction.java
new file mode 100644
index 0000000..d3b1a60
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstruction.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * Convenience class to provide SPARCMacroAssembler for the {@link #emitCode} method.
+ */
+public abstract class SPARCLIRInstruction extends LIRInstruction implements SPARCLIRInstructionMixin {
+    public static final LIRInstructionClass<SPARCLIRInstruction> TYPE = LIRInstructionClass.create(SPARCLIRInstruction.class);
+    private final SPARCLIRInstructionMixinStore store;
+
+    protected SPARCLIRInstruction(LIRInstructionClass<? extends LIRInstruction> c) {
+        this(c, null);
+    }
+
+    protected SPARCLIRInstruction(LIRInstructionClass<? extends LIRInstruction> c, SizeEstimate size) {
+        super(c);
+        store = new SPARCLIRInstructionMixinStore(size);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (SPARCMacroAssembler) crb.asm);
+    }
+
+    protected abstract void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm);
+
+    @Override
+    public SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore() {
+        return store;
+    }
+
+    protected static int asImmediate(JavaConstant value) {
+        if (value.isNull()) {
+            return 0;
+        } else {
+            long val = value.asLong();
+            assert NumUtil.isInt(val);
+            return (int) val;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstructionMixin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstructionMixin.java
new file mode 100644
index 0000000..1bc88f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLIRInstructionMixin.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+public interface SPARCLIRInstructionMixin {
+
+    default boolean leavesRegisterWindow() {
+        return false;
+    }
+
+    default SizeEstimate estimateSize() {
+        return getSPARCLIRInstructionStore().estimate;
+    }
+
+    SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore();
+
+    /**
+     * This class represents a size estimation of a particular LIR instruction. It contains a
+     * pessimistic estimate of emitted SPARC instructions and emitted bytes into the constant
+     * section.
+     */
+    class SizeEstimate {
+        /**
+         * Cache the first size definition (with just 0 as constant size).
+         */
+        private static final SizeEstimate[] cache = new SizeEstimate[5];
+
+        static {
+            for (int i = 0; i < cache.length; i++) {
+                cache[i] = new SizeEstimate(i, 0);
+            }
+        }
+
+        public final int instructionSize;
+        public final int constantSize;
+
+        public SizeEstimate(int instructionSize, int constantSize) {
+            this.instructionSize = instructionSize;
+            this.constantSize = constantSize;
+        }
+
+        public static SizeEstimate create(int instructionSize, int constantSize) {
+            if (constantSize == 0 && instructionSize < cache.length) {
+                return cache[instructionSize];
+            } else {
+                return new SizeEstimate(instructionSize, constantSize);
+            }
+        }
+
+        public static SizeEstimate create(int instructionSize) {
+            if (instructionSize < cache.length) {
+                return cache[instructionSize];
+            } else {
+                return new SizeEstimate(instructionSize, 0);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SE[i=" + instructionSize + ", c=" + constantSize + "]";
+        }
+    }
+
+    class SPARCLIRInstructionMixinStore {
+        public final SizeEstimate estimate;
+        public SPARCDelayedControlTransfer delayedControlTransfer = SPARCDelayedControlTransfer.DUMMY;
+
+        public SPARCLIRInstructionMixinStore(SizeEstimate estimate) {
+            this.estimate = estimate;
+        }
+
+        @Override
+        public String toString() {
+            return estimate != null ? estimate.toString() : "";
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLoadConstantTableBaseOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLoadConstantTableBaseOp.java
new file mode 100644
index 0000000..bb47d83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLoadConstantTableBaseOp.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.StandardOp.NoOp;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Loads the constant section base into a register.
+ *
+ * <p>
+ * Layout:
+ *
+ * <pre>
+ * +----constant section----+--pad--+---code section--+
+ * |<-------------------_------------------->|
+ *                      ^- Constant section base pointer
+ * </pre>
+ *
+ * The constant section base pointer is placed as such that the lowest offset -4096 points to the
+ * start of the constant section.
+ * <p>
+ * If the constant section grows beyond 8k size, the immediate addressing cannot be used anymore; in
+ * this case absolute addressing (without using the base pointer is used). See also:
+ * CodeInstaller::pd_patch_DataSectionReference
+ *
+ * @see SPARCMove#loadFromConstantTable(CompilationResultBuilder, SPARCMacroAssembler, int,
+ *      Register, jdk.vm.ci.meta.Constant, Register, SPARCDelayedControlTransfer)
+ */
+public class SPARCLoadConstantTableBaseOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCLoadConstantTableBaseOp> TYPE = LIRInstructionClass.create(SPARCLoadConstantTableBaseOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(9);
+
+    private final NoOp placeHolder;
+    @Def({REG}) private AllocatableValue base;
+
+    public SPARCLoadConstantTableBaseOp(Variable base, NoOp placeHolder) {
+        super(TYPE, SIZE);
+        this.base = base;
+        this.placeHolder = placeHolder;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        Register baseRegister = asRegister(base);
+        int beforePosition = masm.position();
+        masm.rdpc(baseRegister);
+        // Must match with CodeInstaller::pd_patch_DataSectionReference
+        masm.add(baseRegister, (int) SPARCAssembler.minSimm(13), baseRegister);
+        masm.sub(baseRegister, beforePosition, baseRegister);
+    }
+
+    public AllocatableValue getResult() {
+        return base;
+    }
+
+    public void setAlive(LIR lir, boolean alive) {
+        if (alive) {
+            placeHolder.replace(lir, this);
+        } else {
+            placeHolder.remove(lir);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCMove.java
new file mode 100644
index 0000000..b35e9b5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCMove.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MEMBAR_STORE_LOAD;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isCPURegister;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isDoubleFloatRegister;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSingleFloatRegister;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static java.lang.Math.max;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
+import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
+
+import java.util.Set;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.NullCheck;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+import jdk.vm.ci.sparc.SPARCKind;
+
+public class SPARCMove {
+
+    public static class LoadInlineConstant extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, LoadConstantOp {
+        public static final LIRInstructionClass<LoadInlineConstant> TYPE = LIRInstructionClass.create(LoadInlineConstant.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+        private JavaConstant constant;
+        @Def({REG, STACK}) AllocatableValue result;
+
+        public LoadInlineConstant(JavaConstant constant, AllocatableValue result) {
+            super(TYPE, SIZE);
+            this.constant = constant;
+            this.result = result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, result, g0, constant, getDelayedControlTransfer());
+            } else if (isStackSlot(result)) {
+                StackSlot slot = asStackSlot(result);
+                const2stack(crb, masm, slot, g0, getDelayedControlTransfer(), constant);
+            }
+        }
+
+        @Override
+        public Constant getConstant() {
+            return constant;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static class LoadConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadConstantFromTable> TYPE = LIRInstructionClass.create(LoadConstantFromTable.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1, 8);
+
+        private Constant constant;
+        @Def({REG, STACK}) AllocatableValue result;
+        @Use({REG}) private AllocatableValue constantTableBase;
+
+        public LoadConstantFromTable(Constant constant, AllocatableValue constantTableBase, AllocatableValue result) {
+            super(TYPE, SIZE);
+            this.constant = constant;
+            this.result = result;
+            this.constantTableBase = constantTableBase;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            final int byteCount = result.getPlatformKind().getSizeInBytes();
+            assert byteCount > 1 : "Byte values must not be loaded via constant table";
+            Register baseRegister = asRegister(constantTableBase);
+            if (isRegister(result)) {
+                Register resultRegister = asRegister(result);
+                loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, resultRegister, getDelayedControlTransfer());
+            } else if (isStackSlot(result)) {
+                try (ScratchRegister scratch = masm.getScratchRegister()) {
+                    Register scratchRegister = scratch.getRegister();
+                    loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, scratchRegister, getDelayedControlTransfer());
+                    StackSlot slot = asStackSlot(result);
+                    reg2stack(crb, masm, slot, scratchRegister.asValue(), getDelayedControlTransfer());
+                }
+            }
+        }
+    }
+
+    @Opcode("MOVE")
+    public static class Move extends SPARCLIRInstruction implements ValueMoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<Move> TYPE = LIRInstructionClass.create(Move.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(8);
+
+        @Def({REG, STACK, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue input;
+
+        public Move(AllocatableValue result, AllocatableValue input) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            move(crb, masm, getResult(), getInput(), getDelayedControlTransfer());
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    /**
+     * Move between floating-point and general purpose register domain.
+     */
+    @Opcode("MOVE_FPGP")
+    public static final class MoveFpGp extends SPARCLIRInstruction implements ValueMoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MoveFpGp> TYPE = LIRInstructionClass.create(MoveFpGp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Temp({STACK, ILLEGAL}) protected AllocatableValue temp;
+
+        public MoveFpGp(AllocatableValue result, AllocatableValue input, AllocatableValue temp) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.input = input;
+            this.temp = temp;
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            SPARCKind inputKind = (SPARCKind) input.getPlatformKind();
+            SPARCKind resultKind = (SPARCKind) result.getPlatformKind();
+            if (AllocatableValue.ILLEGAL.equals(temp)) {
+                moveDirect(crb, masm, inputKind, resultKind);
+            } else {
+                moveViaStack(crb, masm, inputKind, resultKind);
+            }
+        }
+
+        private void moveDirect(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind inputKind, SPARCKind resultKind) {
+            getDelayedControlTransfer().emitControlTransfer(crb, masm);
+            if (resultKind == SINGLE) {
+                if (inputKind == WORD) {
+                    masm.movwtos(asRegister(input, WORD), asRegister(result, SINGLE));
+                } else {
+                    throw GraalError.shouldNotReachHere("inputKind: " + inputKind);
+                }
+            } else if (resultKind == DOUBLE) {
+                if (inputKind == WORD) {
+                    masm.movxtod(asRegister(input, WORD), asRegister(result, DOUBLE));
+                } else {
+                    masm.movxtod(asRegister(input, XWORD), asRegister(result, DOUBLE));
+                }
+            } else if (inputKind == SINGLE) {
+                if (resultKind == WORD) {
+                    masm.movstosw(asRegister(input, SINGLE), asRegister(result, WORD));
+                } else {
+                    masm.movstouw(asRegister(input, SINGLE), asRegister(result, WORD));
+                }
+            } else if (inputKind == DOUBLE) {
+                if (resultKind == XWORD) {
+                    masm.movdtox(asRegister(input, DOUBLE), asRegister(result, XWORD));
+                } else {
+                    throw GraalError.shouldNotReachHere();
+                }
+            }
+        }
+
+        private void moveViaStack(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind inputKind, SPARCKind resultKind) {
+            int resultKindSize = resultKind.getSizeInBytes();
+            assert inputKind.getSizeInBytes() == resultKindSize;
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                SPARCAddress tempAddress = generateSimm13OffsetLoad((SPARCAddress) crb.asAddress(temp), masm, scratch);
+                masm.st(asRegister(input), tempAddress, resultKindSize);
+                getDelayedControlTransfer().emitControlTransfer(crb, masm);
+                masm.ld(tempAddress, asRegister(result), resultKindSize, false);
+            }
+        }
+    }
+
+    public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemOp> TYPE = LIRInstructionClass.create(MemOp.class);
+
+        protected final PlatformKind kind;
+        @Use({COMPOSITE}) protected SPARCAddressValue address;
+        @State protected LIRFrameState state;
+
+        public MemOp(LIRInstructionClass<? extends MemOp> c, SizeEstimate size, PlatformKind kind, SPARCAddressValue address, LIRFrameState state) {
+            super(c, size);
+            this.kind = kind;
+            this.address = address;
+            this.state = state;
+        }
+
+        protected abstract void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm);
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            emitMemAccess(crb, masm);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && address.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    public static final class LoadOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        @Def({REG}) protected AllocatableValue result;
+        protected boolean signExtend;
+
+        public LoadOp(PlatformKind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) {
+            this(kind, result, address, state, false);
+        }
+
+        public LoadOp(PlatformKind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state, boolean signExtend) {
+            super(TYPE, SIZE, kind, address, state);
+            this.result = result;
+            this.signExtend = signExtend;
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            emitLoad(crb, masm, address.toAddress(), result, signExtend, kind, getDelayedControlTransfer(), state);
+        }
+    }
+
+    public static final class LoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(8);
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue;
+
+        public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.addressValue = address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            SPARCAddress address = addressValue.toAddress();
+            loadEffectiveAddress(crb, masm, address, asRegister(result, XWORD), getDelayedControlTransfer());
+        }
+    }
+
+    public static final class LoadDataAddressOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<LoadDataAddressOp> TYPE = LIRInstructionClass.create(LoadDataAddressOp.class);
+
+        @Def({REG}) protected AllocatableValue result;
+        private final DataPointerConstant data;
+
+        public LoadDataAddressOp(AllocatableValue result, DataPointerConstant data) {
+            super(TYPE);
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            // HotSpot for SPARC requires at least word alignment
+            SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(data, max(SPARCKind.WORD.getSizeInBytes(), data.getAlignment()));
+            assert addr == masm.getPlaceholder(-1);
+            final boolean forceRelocatable = true;
+            Register dstReg = asRegister(result);
+            masm.setx(0, dstReg, forceRelocatable);
+        }
+
+        @Override
+        public SizeEstimate estimateSize() {
+            return SizeEstimate.create(8, data.getSerializedSize());
+        }
+    }
+
+    public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        private final int barriers;
+
+        public MembarOp(final int barriers) {
+            super(TYPE, SIZE);
+            this.barriers = barriers;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            getDelayedControlTransfer().emitControlTransfer(crb, masm);
+            masm.membar(MEMBAR_STORE_LOAD);
+        }
+
+        @Override
+        public void verify() {
+            assert barriers == STORE_LOAD : String.format("Got barriers 0x%x; On SPARC only STORE_LOAD barriers are accepted; all other barriers are not neccessary due to TSO", barriers);
+        }
+    }
+
+    public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        @Use({COMPOSITE}) protected SPARCAddressValue input;
+        @State protected LIRFrameState state;
+
+        public NullCheckOp(SPARCAddressValue input, LIRFrameState state) {
+            super(TYPE, SIZE);
+            this.input = input;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            getDelayedControlTransfer().emitControlTransfer(crb, masm);
+            SPARCAddress addr = input.toAddress();
+            crb.recordImplicitException(masm.position(), state);
+            // Just need to check whether this is a valid address or not; alignment is not
+            // checked
+            masm.ldub(addr, g0);
+        }
+
+        @Override
+        public Value getCheckedValue() {
+            return input;
+        }
+
+        @Override
+        public LIRFrameState getState() {
+            return state;
+        }
+    }
+
+    @Opcode("CAS")
+    public static final class CompareAndSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Alive({REG}) protected AllocatableValue address;
+        @Alive({REG}) protected AllocatableValue cmpValue;
+        @Use({REG}) protected AllocatableValue newValue;
+
+        public CompareAndSwapOp(AllocatableValue result, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.address = address;
+            this.cmpValue = cmpValue;
+            this.newValue = newValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY);
+            compareAndSwap(crb, masm, address, cmpValue, result, getDelayedControlTransfer());
+        }
+    }
+
+    public static final class StackLoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot;
+
+        public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) {
+            super(TYPE, SIZE);
+            this.result = result;
+            this.slot = slot;
+            assert slot instanceof VirtualStackSlot || slot instanceof StackSlot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            SPARCAddress address = (SPARCAddress) crb.asAddress(slot);
+            loadEffectiveAddress(crb, masm, address, asRegister(result, XWORD), getDelayedControlTransfer());
+        }
+    }
+
+    private static void loadEffectiveAddress(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Register result, SPARCDelayedControlTransfer delaySlotHolder) {
+        if (address.getIndex().equals(Register.None)) {
+            if (isSimm13(address.getDisplacement())) {
+                delaySlotHolder.emitControlTransfer(crb, masm);
+                masm.add(address.getBase(), address.getDisplacement(), result);
+            } else {
+                assert result.encoding() != address.getBase().encoding();
+                masm.setx(address.getDisplacement(), result, false);
+                // No relocation, therefore, the add can be delayed as well
+                delaySlotHolder.emitControlTransfer(crb, masm);
+                masm.add(address.getBase(), result, result);
+            }
+        } else {
+            delaySlotHolder.emitControlTransfer(crb, masm);
+            masm.add(address.getBase(), address.getIndex(), result);
+        }
+    }
+
+    public static class StoreOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+        @Use({REG}) protected AllocatableValue input;
+
+        public StoreOp(PlatformKind kind, SPARCAddressValue address, AllocatableValue input, LIRFrameState state) {
+            super(TYPE, SIZE, kind, address, state);
+            this.input = input;
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            emitStore(input, address.toAddress(), kind, getDelayedControlTransfer(), state, crb, masm);
+        }
+    }
+
+    public static final class StoreConstantOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
+        public static final SizeEstimate SIZE = SizeEstimate.create(2);
+
+        protected final JavaConstant input;
+
+        public StoreConstantOp(PlatformKind kind, SPARCAddressValue address, JavaConstant input, LIRFrameState state) {
+            super(TYPE, SIZE, kind, address, state);
+            this.input = input;
+            if (!input.isDefaultForKind()) {
+                throw GraalError.shouldNotReachHere("Can only store null constants to memory");
+            }
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
+                getDelayedControlTransfer().emitControlTransfer(crb, masm);
+                if (state != null) {
+                    crb.recordImplicitException(masm.position(), state);
+                }
+                int byteCount = kind.getSizeInBytes();
+                masm.st(g0, addr, byteCount);
+            }
+        }
+    }
+
+    public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
+        move(crb, masm, result, g0, input, delaySlotLir);
+    }
+
+    public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, Value input, SPARCDelayedControlTransfer delaySlotLir) {
+        if (isRegister(input)) {
+            if (isRegister(result)) {
+                reg2reg(crb, masm, result, input, delaySlotLir);
+            } else if (isStackSlot(result)) {
+                reg2stack(crb, masm, result, input, delaySlotLir);
+            } else {
+                throw GraalError.shouldNotReachHere("Result is a: " + result);
+            }
+        } else if (isStackSlot(input)) {
+            if (isRegister(result)) {
+                SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input);
+                emitLoad(crb, masm, inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null);
+            } else if (isStackSlot(result)) {
+                stack2stack(crb, masm, result, input, delaySlotLir);
+            } else {
+                throw GraalError.shouldNotReachHere("Result is a: " + result);
+            }
+        } else if (isJavaConstant(input)) {
+            JavaConstant constant = asJavaConstant(input);
+            if (isRegister(result)) {
+                const2reg(crb, masm, result, constantTableBase, constant, delaySlotLir);
+            } else if (isStackSlot(result)) {
+                const2stack(crb, masm, result, constantTableBase, delaySlotLir, constant);
+            } else {
+                throw GraalError.shouldNotReachHere("Result is a: " + result);
+            }
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public static void const2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, SPARCDelayedControlTransfer delaySlotLir, JavaConstant constant) {
+        if (constant.isDefaultForKind() || constant.isNull()) {
+            SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+            emitStore(g0.asValue(LIRKind.combine(result)), resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm);
+        } else {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(result));
+                const2reg(crb, masm, scratchRegisterValue, constantTableBase, constant, SPARCDelayedControlTransfer.DUMMY);
+                SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+                emitStore(scratchRegisterValue, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm);
+            }
+        }
+    }
+
+    public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, PlatformKind resultKind, PlatformKind inputKind, Value result, Value input,
+                    SPARCDelayedControlTransfer delaySlotLir) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input);
+            Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input));
+            emitLoad(crb, masm, inputAddress, scratchRegisterValue, false, inputKind, SPARCDelayedControlTransfer.DUMMY, null);
+            SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+            emitStore(scratchRegisterValue, resultAddress, resultKind, delaySlotLir, null, crb, masm);
+        }
+    }
+
+    public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
+        stack2stack(crb, masm, result.getPlatformKind(), input.getPlatformKind(), result, input, delaySlotLir);
+    }
+
+    public static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
+        SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result);
+        emitStore(input, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm);
+    }
+
+    public static void reg2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
+        final Register src = asRegister(input);
+        final Register dst = asRegister(result);
+        if (src.equals(dst)) {
+            return;
+        }
+        delaySlotLir.emitControlTransfer(crb, masm);
+        if (isCPURegister(src) && isCPURegister(dst)) {
+            masm.mov(src, dst);
+        } else if (isSingleFloatRegister(src) && isSingleFloatRegister(dst)) {
+            masm.fsrc2s(src, dst);
+        } else if (isDoubleFloatRegister(src) && isDoubleFloatRegister(dst)) {
+            masm.fsrc2d(src, dst);
+        } else {
+            throw GraalError.shouldNotReachHere(String.format("Trying to move between register domains src: %s dst: %s", src, dst));
+        }
+    }
+
+    /**
+     * Guarantees that the given SPARCAddress given before is loadable by subsequent load/store
+     * instruction. If the displacement exceeds the simm13 value range, the value is put into a
+     * scratch register.
+     *
+     * @param addr Address to modify
+     * @param masm assembler to output the potential code to store the value in the scratch register
+     * @param scratch The register as scratch to use
+     * @return a loadable SPARCAddress
+     */
+    public static SPARCAddress generateSimm13OffsetLoad(SPARCAddress addr, SPARCMacroAssembler masm, Register scratch) {
+        boolean displacementOutOfBound = addr.getIndex().equals(Register.None) && !SPARCAssembler.isSimm13(addr.getDisplacement());
+        if (displacementOutOfBound) {
+            masm.setx(addr.getDisplacement(), scratch, false);
+            return new SPARCAddress(addr.getBase(), scratch);
+        } else {
+            return addr;
+        }
+    }
+
+    public static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            Set<CPUFeature> cpuFeatures = ((SPARC) masm.target.arch).getFeatures();
+            boolean hasVIS1 = cpuFeatures.contains(CPUFeature.VIS1);
+            boolean hasVIS3 = cpuFeatures.contains(CPUFeature.VIS3);
+            Register resultRegister = asRegister(result);
+            int byteCount = result.getPlatformKind().getSizeInBytes();
+            switch (input.getJavaKind().getStackKind()) {
+                case Int:
+                    if (input.isDefaultForKind()) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.clr(resultRegister);
+                    } else if (isSimm13(input.asInt())) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.or(g0, input.asInt(), resultRegister);
+                    } else {
+                        if (constantTableBase.equals(g0)) {
+                            throw GraalError.shouldNotReachHere();
+                        } else {
+                            loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+                        }
+                    }
+                    break;
+                case Long:
+                    if (input.isDefaultForKind()) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.clr(resultRegister);
+                    } else if (isSimm13(input.asLong())) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.or(g0, (int) input.asLong(), resultRegister);
+                    } else {
+                        loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+                    }
+                    break;
+                case Float: {
+                    float constant = input.asFloat();
+                    int constantBits = java.lang.Float.floatToIntBits(constant);
+                    if (hasVIS1 && constantBits == 0) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.fzeros(resultRegister);
+                    } else {
+                        if (hasVIS3 && isSimm13(constantBits)) {
+                            masm.or(g0, constantBits, scratch);
+                            delaySlotLir.emitControlTransfer(crb, masm);
+                            masm.movwtos(scratch, resultRegister);
+                        } else {
+                            // First load the address into the scratch register
+                            loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+                        }
+                    }
+                    break;
+                }
+                case Double: {
+                    double constant = input.asDouble();
+                    long constantBits = java.lang.Double.doubleToRawLongBits(constant);
+                    if (hasVIS1 && constantBits == 0) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.fzerod(resultRegister);
+                    } else {
+                        if (hasVIS3 && isSimm13(constantBits)) {
+                            masm.or(g0, (int) constantBits, scratch);
+                            delaySlotLir.emitControlTransfer(crb, masm);
+                            masm.movxtod(scratch, resultRegister);
+                        } else {
+                            loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+                        }
+                    }
+                    break;
+                }
+                case Object:
+                    if (input.isNull()) {
+                        delaySlotLir.emitControlTransfer(crb, masm);
+                        masm.clr(resultRegister);
+                    } else {
+                        loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+                    }
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere("missing: " + input.getJavaKind());
+            }
+        }
+    }
+
+    protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue,
+                    SPARCDelayedControlTransfer delay) {
+        delay.emitControlTransfer(crb, masm);
+        switch ((SPARCKind) cmpValue.getPlatformKind()) {
+            case WORD:
+                masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue));
+                break;
+            case XWORD:
+                masm.casx(asRegister(address), asRegister(cmpValue), asRegister(newValue));
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    public static void emitLoad(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Value result, boolean signExtend, PlatformKind kind,
+                    SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch);
+            final Register dst = asRegister(result);
+            delayedControlTransfer.emitControlTransfer(crb, masm);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            int byteCount = kind.getSizeInBytes();
+            masm.ld(addr, dst, byteCount, signExtend);
+        }
+    }
+
+    public static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb,
+                    SPARCMacroAssembler masm) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch);
+            delayedControlTransfer.emitControlTransfer(crb, masm);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            int byteCount = kind.getSizeInBytes();
+            masm.st(asRegister(input), addr, byteCount);
+        }
+    }
+
+    /**
+     * This method creates a load from the constant section. It automatically respects the different
+     * patterns used for small constant sections (<8k) and large constant sections (>=8k). The
+     * generated patterns by this method must be understood by
+     * CodeInstaller::pd_patch_DataSectionReference (jvmciCodeInstaller_sparc.cpp).
+     */
+    public static void loadFromConstantTable(CompilationResultBuilder crb, SPARCMacroAssembler masm, int byteCount, Register constantTableBase, Constant input, Register dest,
+                    SPARCDelayedControlTransfer delaySlotInstruction) {
+        SPARCAddress address;
+        ScratchRegister scratch = null;
+        try {
+            if (masm.isImmediateConstantLoad()) {
+                address = new SPARCAddress(constantTableBase, 0);
+                // Make delayed only, when using immediate constant load.
+                delaySlotInstruction.emitControlTransfer(crb, masm);
+                crb.recordDataReferenceInCode(input, byteCount);
+            } else {
+                scratch = masm.getScratchRegister();
+                Register sr = scratch.getRegister();
+                crb.recordDataReferenceInCode(input, byteCount);
+                masm.sethix(0, sr, true);
+                address = new SPARCAddress(sr, 0);
+            }
+            masm.ld(address, dest, byteCount, false);
+        } finally {
+            if (scratch != null) {
+                scratch.close();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOP3Op.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOP3Op.java
new file mode 100644
index 0000000..2d67eb9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOP3Op.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
+import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public final class SPARCOP3Op extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCOP3Op> TYPE = LIRInstructionClass.create(SPARCOP3Op.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    @Opcode private final Op3s op3;
+    @Use({REG}) protected Value rs1;
+    @Use({REG, CONST}) protected Value rs2;
+    @Def({REG}) protected Value rd;
+    @State protected LIRFrameState state;
+
+    public static SPARCOP3Op newUnary(Op3s op3, Value rs2, Value rd) {
+        return newUnary(op3, rs2, rd, null);
+    }
+
+    public static SPARCOP3Op newUnary(Op3s op3, Value rs2, Value rd, LIRFrameState state) {
+        return new SPARCOP3Op(op3, g0.asValue(LIRKind.value(rs2.getPlatformKind())), rs2, rd, state);
+    }
+
+    public static SPARCOP3Op newBinaryVoid(Op3s op3, Value rs1, Value rs2) {
+        return newBinaryVoid(op3, rs1, rs2, null);
+    }
+
+    public static SPARCOP3Op newBinaryVoid(Op3s op3, Value rs1, Value rs2, LIRFrameState state) {
+        return new SPARCOP3Op(op3, rs1, rs2, g0.asValue(LIRKind.value(rs2.getPlatformKind())), state);
+    }
+
+    public SPARCOP3Op(Op3s op3, Value rs1, Value rs2, Value rd) {
+        this(op3, rs1, rs2, rd, null);
+    }
+
+    public SPARCOP3Op(Op3s op3, Value rs1, Value rs2, Value rd, LIRFrameState state) {
+        super(TYPE, SIZE);
+        this.op3 = op3;
+        this.rs1 = rs1;
+        this.rs2 = rs2;
+        this.rd = rd;
+        this.state = state;
+    }
+
+    @Override
+    protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        emitOp3(masm, op3, rs1, rs2, rd);
+    }
+
+    public static void emitOp3(SPARCMacroAssembler masm, Op3s op3, Value rs1, Value rs2) {
+        emitOp3(masm, op3, rs1, rs2, g0.asValue(LIRKind.value(rs2.getPlatformKind())));
+    }
+
+    public static void emitOp3(SPARCMacroAssembler masm, Op3s op3, Value rs1, Value rs2, Value rd) {
+        assert isRegister(rs1) : rs1;
+        if (isJavaConstant(rs2)) {
+            JavaConstant constant = asJavaConstant(rs2);
+            long simm13;
+            if (constant.isNull()) {
+                simm13 = 0;
+            } else {
+                // Cast is safe, as isSimm13 assertion is done
+                simm13 = constant.asLong();
+            }
+            assert isSimm13(constant);
+            SPARCAssembler.Op3Op.emit(masm, op3, asRegister(rs1), (int) simm13, asRegister(rd));
+        } else if (isRegister(rs2)) {
+            SPARCAssembler.Op3Op.emit(masm, op3, asRegister(rs1), asRegister(rs2), asRegister(rd));
+        } else {
+            throw shouldNotReachHere(String.format("Got values a: %s b: %s", rs1, rs2));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOPFOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOPFOp.java
new file mode 100644
index 0000000..f41d14c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCOPFOp.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARCKind;
+
+public final class SPARCOPFOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCOPFOp> TYPE = LIRInstructionClass.create(SPARCOPFOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    @Opcode protected final Opfs opf;
+    @Use({REG}) protected Value rs1;
+    @Use({REG}) protected Value rs2;
+    @Def({REG}) protected Value rd;
+    @State protected LIRFrameState state;
+
+    public SPARCOPFOp(Opfs opf, Value rs2, Value rd) {
+        this(opf, SPARC.g0.asValue(LIRKind.value(SPARCKind.SINGLE)), rs2, rd);
+    }
+
+    public SPARCOPFOp(Opfs opf, Value rs1, Value rs2, Value rd) {
+        this(opf, rs1, rs2, rd, null);
+    }
+
+    public SPARCOPFOp(Opfs opf, Value rs1, Value rs2, Value rd, LIRFrameState state) {
+        super(TYPE, SIZE);
+        this.opf = opf;
+        this.rs1 = rs1;
+        this.rs2 = rs2;
+        this.rd = rd;
+        this.state = state;
+    }
+
+    @Override
+    protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        getDelayedControlTransfer().emitControlTransfer(crb, masm);
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        SPARCAssembler.OpfOp.emit(masm, opf, asRegister(rs1), asRegister(rs2), asRegister(rd));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPauseOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPauseOp.java
new file mode 100644
index 0000000..2eb8e57
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPauseOp.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+/**
+ * Emits a pause.
+ */
+@Opcode("PAUSE")
+public final class SPARCPauseOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCPauseOp> TYPE = LIRInstructionClass.create(SPARCPauseOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    public SPARCPauseOp() {
+        super(TYPE, SIZE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        masm.pause();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java
new file mode 100644
index 0000000..88040af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class SPARCPrefetchOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCPrefetchOp> TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class);
+    public static final SizeEstimate SIZE = SizeEstimate.create(1);
+
+    private final int instr;  // AllocatePrefetchInstr
+    @Alive({COMPOSITE}) protected SPARCAddressValue address;
+
+    public SPARCPrefetchOp(SPARCAddressValue address, int instr) {
+        super(TYPE, SIZE);
+        this.address = address;
+        this.instr = instr;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        assert instr >= 0 && instr < SPARCAssembler.Fcn.values().length : instr;
+        masm.prefetch(address.toAddress(), SPARCAssembler.Fcn.values()[instr]);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java
new file mode 100644
index 0000000..0a0fe3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer.DUMMY;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.sparc.SPARC;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<SPARCSaveRegistersOp> TYPE = LIRInstructionClass.create(SPARCSaveRegistersOp.class);
+    public static final Register RETURN_REGISTER_STORAGE = SPARC.d62;
+    public static final SizeEstimate SIZE = SizeEstimate.create(32);
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final AllocatableValue[] slots;
+
+    /**
+     * Specifies if {@link #remove(Set)} should have an effect.
+     */
+    protected final boolean supportsRemove;
+
+    /**
+     *
+     * @param savedRegisters the registers saved by this operation which may be subject to
+     *            {@linkplain #remove(Set) pruning}
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+     */
+    public SPARCSaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        super(TYPE, SIZE);
+        assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
+        this.savedRegisters = savedRegisters;
+        this.slots = savedRegisterLocations;
+        this.supportsRemove = supportsRemove;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Can be used with VIS3
+        // new Movxtod(SPARC.i0, RETURN_REGISTER_STORAGE).emit(masm);
+        // We abuse the first stackslot for transferring i0 to return_register_storage
+        // assert slots.length >= 1;
+        SPARCAddress slot0Address = (SPARCAddress) crb.asAddress(slots[0]);
+        masm.stx(SPARC.i0, slot0Address);
+        masm.lddf(slot0Address, RETURN_REGISTER_STORAGE);
+
+        // Now save the registers
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+                Register savedRegister = savedRegisters[i];
+                StackSlot slot = asStackSlot(slots[i]);
+                SPARCAddress slotAddress = (SPARCAddress) crb.asAddress(slot);
+                RegisterValue input = savedRegister.asValue(slot.getValueKind());
+                SPARCMove.emitStore(input, slotAddress, slot.getPlatformKind(), DUMMY, null, crb, masm);
+            }
+        }
+    }
+
+    public AllocatableValue[] getSlots() {
+        return slots;
+    }
+
+    @Override
+    public boolean supportsRemove() {
+        return supportsRemove;
+    }
+
+    @Override
+    public int remove(Set<Register> doNotSave) {
+        if (!supportsRemove) {
+            throw new UnsupportedOperationException();
+        }
+        return prune(doNotSave, savedRegisters);
+    }
+
+    static int prune(Set<Register> toRemove, Register[] registers) {
+        int pruned = 0;
+        for (int i = 0; i < registers.length; i++) {
+            if (registers[i] != null) {
+                if (toRemove.contains(registers[i])) {
+                    registers[i] = null;
+                    pruned++;
+                }
+            }
+        }
+        return pruned;
+    }
+
+    @Override
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        int total = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                total++;
+            }
+        }
+        Register[] keys = new Register[total];
+        int[] values = new int[total];
+        if (total != 0) {
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+                    StackSlot slot = asStackSlot(slots[i]);
+                    values[mapIndex] = indexForStackSlot(frameMap, slot);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == total;
+        }
+        return new RegisterSaveLayout(keys, values);
+    }
+
+    /**
+     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
+     * slots in the reference map.
+     *
+     * @param slot a stack slot
+     * @return the index of the stack slot
+     */
+    private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) {
+        assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0;
+        int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize;
+        return value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCTailDelayedLIRInstruction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCTailDelayedLIRInstruction.java
new file mode 100644
index 0000000..662fd00
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCTailDelayedLIRInstruction.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.sparc;
+
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.lir.LIRInstruction;
+
+/**
+ * Implementors of this interface are able to place its last instruction into the delay slot of a
+ * {@link SPARCDelayedControlTransfer} instruction.
+ *
+ * The implementor has to do following steps to emit code into the delay slot for the
+ * DelayedControlTransfer instruction:
+ * <ol>
+ * <li>Emit everything up to the second last instruction.</li>
+ * <li>Call
+ * {@link SPARCDelayedControlTransfer#emitControlTransfer(org.graalvm.compiler.lir.asm.CompilationResultBuilder, SPARCMacroAssembler)}
+ * to let the DelayedControlTransfer instruction emit its own code (But must not stuff the delay
+ * slot with Nop)</li>
+ * <li>emit the last instruction for this {@link LIRInstruction}</li>
+ * </ol>
+ *
+ * Note: If this instruction decides not to use the delay slot, it can skip the call of
+ * {@link SPARCDelayedControlTransfer#emitControlTransfer(org.graalvm.compiler.lir.asm.CompilationResultBuilder, SPARCMacroAssembler)}
+ * . The DelayedControlTransfer instruction will emit the code just with Nop in the delay slot.
+ */
+public interface SPARCTailDelayedLIRInstruction extends SPARCLIRInstructionMixin {
+    default void setDelayedControlTransfer(SPARCDelayedControlTransfer holder) {
+        getSPARCLIRInstructionStore().delayedControlTransfer = holder;
+    }
+
+    default SPARCDelayedControlTransfer getDelayedControlTransfer() {
+        return getSPARCLIRInstructionStore().delayedControlTransfer;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/CompositeValueReplacementTest1.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/CompositeValueReplacementTest1.java
new file mode 100644
index 0000000..fdf5711
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/CompositeValueReplacementTest1.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.test;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This test verifies that {@link CompositeValue}s are immutable, i.e. that a write to a component
+ * of a {@link CompositeValue} results in a new {@link CompositeValue}.
+ */
+public class CompositeValueReplacementTest1 {
+
+    private static class TestCompositeValue extends CompositeValue {
+
+        @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
+
+        TestCompositeValue(Value value) {
+            super(LIRKind.Illegal);
+            this.value = value;
+        }
+
+        private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
+        @Override
+        public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+            Value newValue = proc.doValue(inst, value, mode, flags);
+            if (!value.identityEquals(newValue)) {
+                return new TestCompositeValue(newValue);
+            }
+            return this;
+        }
+
+        @Override
+        protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+            proc.visitValue(inst, value, mode, flags);
+        }
+    }
+
+    private static class DummyValue extends Value {
+
+        private final int id;
+        private static int counter = 1;
+
+        protected DummyValue() {
+            super(LIRKind.Illegal);
+            this.id = counter++;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + id;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            DummyValue other = (DummyValue) obj;
+            if (id != other.id) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "DummyValue [id=" + id + "]";
+        }
+
+    }
+
+    private static final class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
+
+        @Use({COMPOSITE}) protected TestCompositeValue compValue;
+
+        TestOp(TestCompositeValue compValue) {
+            super(TYPE);
+            this.compValue = compValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            fail("should not reach!");
+        }
+
+    }
+
+    @Test
+    public void replaceCompValueTest0() {
+        DummyValue dummyValue1 = new DummyValue();
+        DummyValue dummyValue2 = new DummyValue();
+        DummyValue dummyValue3 = new DummyValue();
+        TestCompositeValue compValue1 = new TestCompositeValue(dummyValue1);
+        LIRInstruction op1 = new TestOp(compValue1);
+        LIRInstruction op2 = new TestOp(compValue1);
+
+        op1.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue2;
+        });
+
+        op2.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue3;
+        });
+
+        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
+        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/GenericValueMapTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/GenericValueMapTest.java
new file mode 100644
index 0000000..011b1a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/GenericValueMapTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.util.GenericValueMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.PlatformKind;
+
+public class GenericValueMapTest {
+
+    private enum DummyKind implements PlatformKind {
+        Long;
+
+        private EnumKey<DummyKind> key = new EnumKey<>(this);
+
+        @Override
+        public Key getKey() {
+            return key;
+        }
+
+        @Override
+        public int getSizeInBytes() {
+            return 8;
+        }
+
+        @Override
+        public int getVectorLength() {
+            return 1;
+        }
+
+        @Override
+        public char getTypeChar() {
+            return 'l';
+        }
+    }
+
+    @Test
+    public void run0() {
+        RegisterCategory cat = new RegisterCategory("regs");
+
+        RegisterValue reg = new Register(0, 0, "reg0", cat).asValue();
+        Variable var = new Variable(LIRKind.value(DummyKind.Long), 0);
+        Object obj0 = new Object();
+        Object obj1 = new Object();
+
+        GenericValueMap<Object> map = new GenericValueMap<>();
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+
+        map.put(reg, obj0);
+        map.put(var, obj1);
+
+        assertEquals(obj0, map.get(reg));
+        assertEquals(obj1, map.get(var));
+
+        map.remove(reg);
+        map.remove(var);
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+
+        map.put(reg, obj0);
+        map.put(var, obj1);
+
+        map.put(var, obj0);
+        map.put(reg, obj1);
+
+        assertEquals(obj1, map.get(reg));
+        assertEquals(obj0, map.get(var));
+
+        map.put(reg, null);
+        map.put(var, null);
+
+        assertNull(map.get(reg));
+        assertNull(map.get(var));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java
new file mode 100644
index 0000000..4b1641d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.test.alloc.trace;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
+import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Test global move resolver of the trace register allocator.
+ *
+ * Especially the mapping of LabelOp.incoming and BlockEndOp.outgoing.
+ */
+public class TraceGlobalMoveResolutionMappingTest {
+
+    private static final class MoveResolverMock extends TraceGlobalMoveResolutionPhase.MoveResolver {
+
+        private static final class Pair {
+
+            @Override
+            public int hashCode() {
+                final int prime = 31;
+                int result = 1;
+                result = prime * result + ((dst == null) ? 0 : dst.hashCode());
+                result = prime * result + ((src == null) ? 0 : src.hashCode());
+                return result;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (this == obj) {
+                    return true;
+                }
+                if (obj == null) {
+                    return false;
+                }
+                if (getClass() != obj.getClass()) {
+                    return false;
+                }
+                Pair other = (Pair) obj;
+                if (dst == null) {
+                    if (other.dst != null) {
+                        return false;
+                    }
+                } else if (!dst.equals(other.dst)) {
+                    return false;
+                }
+                if (src == null) {
+                    if (other.src != null) {
+                        return false;
+                    }
+                } else if (!src.equals(other.src)) {
+                    return false;
+                }
+                return true;
+            }
+
+            private final Value src;
+            private final AllocatableValue dst;
+
+            Pair(Value src, AllocatableValue dst) {
+                this.src = src;
+                this.dst = dst;
+            }
+
+            @Override
+            public String toString() {
+                return dst.toString() + " <- " + src;
+            }
+        }
+
+        private final HashSet<Pair> mapping = new HashSet<>();
+
+        @Override
+        public void addMapping(Value src, AllocatableValue dst, Value srcStack) {
+            mapping.add(new Pair(src, dst));
+        }
+
+        public int size() {
+            return mapping.size();
+        }
+
+        public boolean contains(Value src, AllocatableValue dst) {
+            return mapping.contains(new Pair(src, dst));
+        }
+
+        @Override
+        public String toString() {
+            return mapping.toString();
+        }
+
+    }
+
+    private static final RegisterCategory CPU = new RegisterCategory("CPU");
+
+    private static final Register r0 = new Register(0, 0, "r0", CPU);
+    private static final Register r1 = new Register(1, 1, "r1", CPU);
+
+    private enum DummyPlatformKind implements PlatformKind {
+        Long;
+
+        private EnumKey<DummyPlatformKind> key = new EnumKey<>(this);
+
+        @Override
+        public Key getKey() {
+            return key;
+        }
+
+        @Override
+        public int getSizeInBytes() {
+            return 8;
+        }
+
+        @Override
+        public int getVectorLength() {
+            return 1;
+        }
+
+        @Override
+        public char getTypeChar() {
+            return 'l';
+        }
+    }
+
+    private static final LIRKind kind = LIRKind.value(DummyPlatformKind.Long);
+
+    private MoveResolverMock resolver;
+
+    @Before
+    public void setUp() {
+        resolver = new MoveResolverMock();
+    }
+
+    private void addMapping(Value src, Value dst) {
+        TraceGlobalMoveResolutionPhase.addMapping(resolver, src, dst);
+    }
+
+    /** Create RegisterValue. */
+    private static RegisterValue v(Register r) {
+        return r.asValue(kind);
+    }
+
+    /** Create StackSlot. */
+    private static StackSlot s(int offset) {
+        return StackSlot.get(kind, -offset, true);
+    }
+
+    /** Create ShadowedRegisterValue. */
+    private static ShadowedRegisterValue sd(Register reg, int offset) {
+        return new ShadowedRegisterValue(v(reg), s(offset));
+    }
+
+    private void assertContains(Value src, AllocatableValue dst) {
+        assertTrue(String.format("Expected move from %s to %s. %s", src, dst, resolver), resolver.contains(src, dst));
+    }
+
+    private void assertSize(int expected) {
+        assertEquals(resolver.toString(), expected, resolver.size());
+    }
+
+    @Test
+    public void testReg2Reg0() {
+        addMapping(v(r0), v(r1));
+        assertContains(v(r0), v(r1));
+    }
+
+    @Test
+    public void testReg2Reg1() {
+        addMapping(v(r0), v(r0));
+        assertSize(0);
+    }
+
+    @Test
+    public void testStack2Stack0() {
+        addMapping(s(1), s(2));
+        assertContains(s(1), s(2));
+    }
+
+    @Test
+    public void testStack2Stack1() {
+        addMapping(s(1), s(1));
+        assertSize(0);
+    }
+
+    @Test
+    public void testStack2Reg() {
+        addMapping(s(1), v(r1));
+        assertContains(s(1), v(r1));
+    }
+
+    @Test
+    public void testReg2Stack() {
+        addMapping(v(r0), s(1));
+        assertContains(v(r0), s(1));
+    }
+
+    @Test
+    public void testShadowed2Reg() {
+        addMapping(sd(r0, 1), v(r1));
+        assertContains(v(r0), v(r1));
+    }
+
+    @Test
+    public void testReg2Shadowed0() {
+        addMapping(v(r0), sd(r1, 1));
+        assertSize(2);
+        assertContains(v(r0), v(r1));
+        assertContains(v(r0), s(1));
+    }
+
+    @Test
+    public void testReg2Shadowed1() {
+        addMapping(v(r0), sd(r0, 1));
+        assertSize(1);
+        assertContains(v(r0), s(1));
+    }
+
+    @Test
+    @Ignore("Cannot express mapping dependencies (yet)")
+    public void testStack2Shadowed0() {
+        addMapping(s(2), sd(r1, 1));
+        assertSize(2);
+        assertContains(s(2), v(r1));
+        assertContains(v(r1), s(1));
+    }
+
+    @Test
+    public void testStack2Shadowed0WorkArount() {
+        addMapping(s(2), sd(r1, 1));
+        assertSize(2);
+        assertContains(s(2), v(r1));
+        assertContains(s(2), s(1));
+    }
+
+    @Test
+    public void testStack2Shadowed1() {
+        addMapping(s(1), sd(r1, 1));
+        assertSize(1);
+        assertContains(s(1), v(r1));
+    }
+
+    @Test
+    public void testShadowed2Shadowed0() {
+        addMapping(sd(r0, 1), sd(r1, 2));
+        assertSize(2);
+        assertContains(v(r0), v(r1));
+        assertContains(v(r0), s(2));
+    }
+
+    @Test
+    public void testShadowed2Shadowed1() {
+        addMapping(sd(r0, 1), sd(r1, 1));
+        assertSize(1);
+        assertContains(v(r0), v(r1));
+    }
+
+    @Test
+    public void testShadowed2Shadowed2() {
+        addMapping(sd(r0, 1), sd(r0, 1));
+        assertSize(0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/BailoutAndRestartBackendException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/BailoutAndRestartBackendException.java
new file mode 100644
index 0000000..e2531be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/BailoutAndRestartBackendException.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.options.StableOptionValue;
+
+/**
+ * Restarts the {@link LIR low-level} compilation with a modified configuration.
+ * {@link BailoutAndRestartBackendException.Options#LIRUnlockBackendRestart LIRUnlockBackendRestart}
+ * needs to be enabled. Use only for debugging purposes only.
+ */
+public abstract class BailoutAndRestartBackendException extends PermanentBailoutException {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Unlock backend restart feature.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> LIRUnlockBackendRestart = new StableOptionValue<>(false);
+        // @formatter:on
+    }
+
+    private static final long serialVersionUID = 792969002851591180L;
+
+    public BailoutAndRestartBackendException(String msg) {
+        super(msg);
+    }
+
+    public BailoutAndRestartBackendException(Throwable cause, String msg) {
+        super(cause, msg);
+    }
+
+    /** Returns {@code true} if the low-level compilation should be restarted. */
+    public abstract boolean shouldRestart();
+
+    /**
+     * Returns an {@link OverrideScope} to change {@link OptionValue OptionValues} or {@code null}
+     * if no changes are required.
+     */
+    public abstract OverrideScope getOverrideScope();
+
+    /**
+     * Updates the {@link LIRSuites} used by the low-level compiler. Note that {@link LIRSuites} are
+     * usually shared, so a modified input parameter will affect other compilations. In case only
+     * the current compilation should be altered, create a copy using {@link LIRSuites#copy()}.
+     */
+    public abstract LIRSuites updateLIRSuites(LIRSuites lirSuites);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValue.java
new file mode 100644
index 0000000..d85fe9ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValue.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Base class to represent values that need to be stored in more than one register. This is mainly
+ * intended to support addresses and not general arbitrary nesting of composite values. Because of
+ * the possibility of sharing of CompositeValues they should be immutable.
+ */
+public abstract class CompositeValue extends Value {
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Component {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    private static final DebugCounter COMPOSITE_VALUE_COUNT = Debug.counter("CompositeValues");
+
+    public CompositeValue(ValueKind<?> kind) {
+        super(kind);
+        COMPOSITE_VALUE_COUNT.increment();
+        assert CompositeValueClass.get(getClass()) != null;
+    }
+
+    /**
+     * Invoke {@code proc} on each {@link Value} element of this {@link CompositeValue}. If
+     * {@code proc} replaces any value then a new CompositeValue should be returned.
+     *
+     * @param inst
+     * @param mode
+     * @param proc
+     * @return the original CompositeValue or a copy with any modified values
+     */
+    public abstract CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc);
+
+    /**
+     * A helper method to visit {@link Value}[] ensuring that a copy of the array is made if it's
+     * needed.
+     *
+     * @param inst
+     * @param values
+     * @param mode
+     * @param proc
+     * @param flags
+     * @return the original {@code values} array or a copy if values changed
+     */
+    protected Value[] visitValueArray(LIRInstruction inst, Value[] values, OperandMode mode, InstructionValueProcedure proc, EnumSet<OperandFlag> flags) {
+        Value[] newValues = null;
+        for (int i = 0; i < values.length; i++) {
+            Value value = values[i];
+            Value newValue = proc.doValue(inst, value, mode, flags);
+            if (!value.identityEquals(newValue)) {
+                if (newValues == null) {
+                    newValues = values.clone();
+                }
+                newValues[i] = value;
+            }
+        }
+        return newValues != null ? newValues : values;
+    }
+
+    protected abstract void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc);
+
+    @Override
+    public String toString() {
+        return CompositeValueClass.format(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return 53 * super.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof CompositeValue) {
+            CompositeValue other = (CompositeValue) obj;
+            return super.equals(other);
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValueClass.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValueClass.java
new file mode 100644
index 0000000..d8f0294
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/CompositeValueClass.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.core.common.FieldIntrospection;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.FieldsScanner;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.CompositeValue.Component;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRIntrospection.LIRFieldsScanner;
+import org.graalvm.compiler.lir.LIRIntrospection.OperandModeAnnotation;
+import org.graalvm.compiler.lir.LIRIntrospection.Values;
+
+/**
+ * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes:
+ * <ul>
+ * <li>The offsets of fields annotated with {@link Component} as well as methods for iterating over
+ * such fields.</li>
+ * </ul>
+ */
+public final class CompositeValueClass<T> extends FieldIntrospection<T> {
+
+    /**
+     * The CompositeValueClass is only used for formatting for the most part so cache it as a
+     * ClassValue.
+     */
+    private static final ClassValue<CompositeValueClass<?>> compositeClass = new ClassValue<CompositeValueClass<?>>() {
+
+        @Override
+        protected CompositeValueClass<?> computeValue(Class<?> type) {
+            CompositeValueClass<?> compositeValueClass = new CompositeValueClass<>(type);
+            assert compositeValueClass.values.getDirectCount() == compositeValueClass.values.getCount() : "only direct fields are allowed in composites";
+            return compositeValueClass;
+        }
+
+    };
+
+    @SuppressWarnings("unchecked")
+    public static <T> CompositeValueClass<T> get(Class<T> type) {
+        return (CompositeValueClass<T>) compositeClass.get(type);
+    }
+
+    private final Values values;
+
+    private CompositeValueClass(Class<T> clazz) {
+        super(clazz);
+
+        CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset());
+        vfs.scan(clazz, CompositeValue.class, false);
+
+        values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
+        data = new Fields(vfs.data);
+    }
+
+    private static class CompositeValueFieldsScanner extends LIRFieldsScanner {
+
+        CompositeValueFieldsScanner(FieldsScanner.CalcOffset calc) {
+            super(calc);
+            valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
+            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
+            if (field.isAnnotationPresent(CompositeValue.Component.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value()));
+            } else {
+                GraalError.shouldNotReachHere();
+            }
+            return result;
+        }
+    }
+
+    @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, values};
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
+        values.appendFields(str);
+        str.append("] data[");
+        data.appendFields(str);
+        str.append("]");
+        return str.toString();
+    }
+
+    public static String format(CompositeValue obj) {
+        CompositeValueClass<?> valueClass = compositeClass.get(obj.getClass());
+        StringBuilder result = new StringBuilder();
+
+        LIRIntrospection.appendValues(result, obj, "", "", "{", "}", new String[]{""}, valueClass.values);
+
+        for (int i = 0; i < valueClass.data.getCount(); i++) {
+            result.append(" ").append(valueClass.data.getName(i)).append(": ").append(LIRIntrospection.getFieldString(obj, i, valueClass.data));
+        }
+
+        return result.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ConstantValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ConstantValue.java
new file mode 100644
index 0000000..533dbd3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ConstantValue.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents an inlined {@link Constant} value.
+ */
+public class ConstantValue extends Value {
+
+    private final Constant constant;
+
+    public ConstantValue(ValueKind<?> kind, Constant constant) {
+        super(kind);
+        this.constant = constant;
+    }
+
+    public Constant getConstant() {
+        return constant;
+    }
+
+    public boolean isJavaConstant() {
+        return constant instanceof JavaConstant;
+    }
+
+    public JavaConstant getJavaConstant() {
+        return (JavaConstant) constant;
+    }
+
+    @Override
+    public String toString() {
+        return constant.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof ConstantValue) {
+            ConstantValue other = (ConstantValue) obj;
+            return super.equals(other) && this.constant.equals(other.constant);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return constant.hashCode() + super.hashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ControlFlowOptimizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ControlFlowOptimizer.java
new file mode 100644
index 0000000..0e1b102
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ControlFlowOptimizer.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIR.verifyBlocks;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * This class performs basic optimizations on the control flow graph after LIR generation.
+ */
+public final class ControlFlowOptimizer extends PostAllocationOptimizationPhase {
+
+    /**
+     * Performs control flow optimizations on the given LIR graph.
+     */
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        LIR lir = lirGenRes.getLIR();
+        new Optimizer(lir).deleteEmptyBlocks(lir.codeEmittingOrder());
+    }
+
+    private static final class Optimizer {
+
+        private final LIR lir;
+
+        private Optimizer(LIR lir) {
+            this.lir = lir;
+        }
+
+        private static final DebugCounter BLOCKS_DELETED = Debug.counter("BlocksDeleted");
+
+        /**
+         * Checks whether a block can be deleted. Only blocks with exactly one successor and an
+         * unconditional branch to this successor are eligable.
+         *
+         * @param block the block checked for deletion
+         * @return whether the block can be deleted
+         */
+        private boolean canDeleteBlock(AbstractBlockBase<?> block) {
+            if (block == null || block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors()[0] == block) {
+                return false;
+            }
+
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+            assert instructions.size() >= 2 : "block must have label and branch";
+            assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
+            assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
+            assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors()[0]).get(
+                            0)).getLabel() : "branch target must be the successor";
+
+            // Block must have exactly one successor.
+            return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
+        }
+
+        private void alignBlock(AbstractBlockBase<?> block) {
+            if (!block.isAligned()) {
+                block.setAlign(true);
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
+                StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
+                instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
+            }
+        }
+
+        private void deleteEmptyBlocks(AbstractBlockBase<?>[] blocks) {
+            assert verifyBlocks(lir, blocks);
+            for (int i = 0; i < blocks.length; i++) {
+                AbstractBlockBase<?> block = blocks[i];
+                if (canDeleteBlock(block)) {
+
+                    block.delete();
+                    // adjust successor and predecessor lists
+                    AbstractBlockBase<?> other = block.getSuccessors()[0];
+                    if (block.isAligned()) {
+                        alignBlock(other);
+                    }
+
+                    BLOCKS_DELETED.increment();
+                    blocks[i] = null;
+                }
+            }
+            assert verifyBlocks(lir, blocks);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java
new file mode 100644
index 0000000..1db7fd5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * This class optimizes moves, particularly those that result from eliminating SSA form.
+ * <p>
+ * When a block has more than one predecessor, and all predecessors end with the
+ * {@linkplain Optimizer#same(LIRInstruction, LIRInstruction) same} sequence of {@linkplain MoveOp
+ * move} instructions, then these sequences can be replaced with a single copy of the sequence at
+ * the beginning of the block.
+ * <p>
+ * Similarly, when a block has more than one successor, then same sequences of moves at the
+ * beginning of the successors can be placed once at the end of the block. But because the moves
+ * must be inserted before all branch instructions, this works only when there is exactly one
+ * conditional branch at the end of the block (because the moves must be inserted before all
+ * branches, but after all compares).
+ * <p>
+ * This optimization affects all kind of moves (reg-&gt;reg, reg-&gt;stack and stack-&gt;reg).
+ * Because this optimization works best when a block contains only a few moves, it has a huge impact
+ * on the number of blocks that are totally empty.
+ */
+public final class EdgeMoveOptimizer extends PostAllocationOptimizationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        LIR ir = lirGenRes.getLIR();
+        Optimizer optimizer = new Optimizer(ir);
+
+        AbstractBlockBase<?>[] blockList = ir.linearScanOrder();
+        // ignore the first block in the list (index 0 is not processed)
+        for (int i = blockList.length - 1; i >= 1; i--) {
+            AbstractBlockBase<?> block = blockList[i];
+
+            if (block.getPredecessorCount() > 1) {
+                optimizer.optimizeMovesAtBlockEnd(block);
+            }
+            if (block.getSuccessorCount() == 2) {
+                optimizer.optimizeMovesAtBlockBegin(block);
+            }
+        }
+    }
+
+    private static final class Optimizer {
+        private final List<List<LIRInstruction>> edgeInstructionSeqences;
+        private LIR ir;
+
+        Optimizer(LIR ir) {
+            this.ir = ir;
+            edgeInstructionSeqences = new ArrayList<>(4);
+        }
+
+        /**
+         * Determines if two operations are both {@linkplain MoveOp moves} that have the same source
+         * and {@linkplain MoveOp#getResult() destination} operands.
+         *
+         * @param op1 the first instruction to compare
+         * @param op2 the second instruction to compare
+         * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm
+         */
+        private static boolean same(LIRInstruction op1, LIRInstruction op2) {
+            assert op1 != null;
+            assert op2 != null;
+
+            if (op1 instanceof ValueMoveOp && op2 instanceof ValueMoveOp) {
+                ValueMoveOp move1 = (ValueMoveOp) op1;
+                ValueMoveOp move2 = (ValueMoveOp) op2;
+                if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
+                    // these moves are exactly equal and can be optimized
+                    return true;
+                }
+            } else if (op1 instanceof LoadConstantOp && op2 instanceof LoadConstantOp) {
+                LoadConstantOp move1 = (LoadConstantOp) op1;
+                LoadConstantOp move2 = (LoadConstantOp) op2;
+                if (move1.getConstant().equals(move2.getConstant()) && move1.getResult().equals(move2.getResult())) {
+                    // these moves are exactly equal and can be optimized
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
+         * {@code block} to the start of {@code block}.
+         */
+        private void optimizeMovesAtBlockEnd(AbstractBlockBase<?> block) {
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                if (pred == block) {
+                    // currently we can't handle this correctly.
+                    return;
+                }
+            }
+
+            // clear all internal data structures
+            edgeInstructionSeqences.clear();
+
+            int numPreds = block.getPredecessorCount();
+            assert numPreds > 1 : "do not call otherwise";
+
+            // setup a list with the LIR instructions of all predecessors
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                assert pred != null;
+                assert ir.getLIRforBlock(pred) != null;
+                List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
+
+                if (pred.getSuccessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
+                    return;
+                }
+
+                assert pred.getSuccessors()[0] == block : "invalid control flow";
+                assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
+
+                if (predInstructions.get(predInstructions.size() - 1).hasState()) {
+                    // can not optimize instructions that have debug info
+                    return;
+                }
+
+                // ignore the unconditional branch at the end of the block
+                List<LIRInstruction> seq = predInstructions.subList(0, predInstructions.size() - 1);
+                edgeInstructionSeqences.add(seq);
+            }
+
+            // process lir-instructions while all predecessors end with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
+
+                LIRInstruction op = last(seq);
+                for (int i = 1; i < numPreds; ++i) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, last(otherSeq))) {
+                        return;
+                    }
+                }
+
+                // insert the instruction at the beginning of the current block
+                ir.getLIRforBlock(block).add(1, op);
+
+                // delete the instruction at the end of all predecessors
+                for (int i = 0; i < numPreds; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeLast(seq);
+                }
+            }
+        }
+
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the start of all successors of
+         * {@code block} to the end of {@code block} just prior to the branch instruction ending
+         * {@code block}.
+         */
+        private void optimizeMovesAtBlockBegin(AbstractBlockBase<?> block) {
+
+            edgeInstructionSeqences.clear();
+            int numSux = block.getSuccessorCount();
+
+            List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+
+            assert numSux == 2 : "method should not be called otherwise";
+
+            LIRInstruction lastInstruction = instructions.get(instructions.size() - 1);
+            if (lastInstruction.hasState()) {
+                // cannot optimize instructions when debug info is needed
+                return;
+            }
+
+            LIRInstruction branch = lastInstruction;
+            if (!(branch instanceof StandardOp.BranchOp) || branch.hasOperands()) {
+                // Only blocks that end with a conditional branch are optimized.
+                // In addition, a conditional branch with operands (including state) cannot
+                // be optimized. Moving a successor instruction before such a branch may
+                // interfere with the operands of the branch. For example, a successive move
+                // instruction may redefine an input operand of the branch.
+                return;
+            }
+
+            // Now it is guaranteed that the block ends with a conditional branch.
+            // The instructions are inserted at the end of the block before the branch.
+            int insertIdx = instructions.size() - 1;
+
+            // setup a list with the lir-instructions of all successors
+            for (AbstractBlockBase<?> sux : block.getSuccessors()) {
+                List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
+
+                assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+
+                if (sux.getPredecessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
+                    return;
+                }
+                assert sux.getPredecessors()[0] == block : "invalid control flow";
+
+                // ignore the label at the beginning of the block
+                List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
+                edgeInstructionSeqences.add(seq);
+            }
+
+            // process LIR instructions while all successors begin with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
+
+                LIRInstruction op = first(seq);
+                for (int i = 1; i < numSux; i++) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, first(otherSeq))) {
+                        // these instructions are different and cannot be optimized .
+                        // no further optimization possible
+                        return;
+                    }
+                }
+
+                // insert instruction at end of current block
+                ir.getLIRforBlock(block).add(insertIdx, op);
+                insertIdx++;
+
+                // delete the instructions at the beginning of all successors
+                for (int i = 0; i < numSux; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeFirst(seq);
+                }
+            }
+        }
+
+        /**
+         * Gets the first element from a LIR instruction sequence.
+         */
+        private static LIRInstruction first(List<LIRInstruction> seq) {
+            return seq.get(0);
+        }
+
+        /**
+         * Gets the last element from a LIR instruction sequence.
+         */
+        private static LIRInstruction last(List<LIRInstruction> seq) {
+            return seq.get(seq.size() - 1);
+        }
+
+        /**
+         * Removes the first element from a LIR instruction sequence.
+         */
+        private static void removeFirst(List<LIRInstruction> seq) {
+            seq.remove(0);
+        }
+
+        /**
+         * Removes the last element from a LIR instruction sequence.
+         */
+        private static void removeLast(List<LIRInstruction> seq) {
+            seq.remove(seq.size() - 1);
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java
new file mode 100644
index 0000000..3f2d0cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.site.InfopointReason;
+
+/**
+ * Emits an infopoint (only mark the position).
+ */
+@Opcode("INFOPOINT")
+public final class FullInfopointOp extends LIRInstruction {
+    public static final LIRInstructionClass<FullInfopointOp> TYPE = LIRInstructionClass.create(FullInfopointOp.class);
+
+    @State protected LIRFrameState state;
+
+    private final InfopointReason reason;
+
+    public FullInfopointOp(LIRFrameState state, InfopointReason reason) {
+        super(TYPE);
+        this.state = state;
+        this.reason = reason;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        crb.asm.ensureUniquePC();
+        crb.recordInfopoint(crb.asm.position(), state, reason);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionStateProcedure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionStateProcedure.java
new file mode 100644
index 0000000..959f036
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionStateProcedure.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+@FunctionalInterface
+public interface InstructionStateProcedure {
+
+    void doState(LIRInstruction instruction, LIRFrameState state);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueConsumer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueConsumer.java
new file mode 100644
index 0000000..47ee795
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueConsumer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Functional interface for iterating over a list of values without modifying them. See
+ * {@link InstructionValueProcedure} for a version that can modify values.
+ */
+@FunctionalInterface
+public interface InstructionValueConsumer {
+
+    /**
+     * Iterator method to be overwritten.
+     *
+     * @param instruction The current instruction.
+     * @param value The value that is iterated.
+     * @param mode The operand mode for the value.
+     * @param flags A set of flags for the value.
+     */
+    void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueProcedure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueProcedure.java
new file mode 100644
index 0000000..0c14d4f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/InstructionValueProcedure.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Functional interface for iterating over a list of values, possibly returning a value to replace
+ * the old value.
+ */
+@FunctionalInterface
+public interface InstructionValueProcedure {
+
+    /**
+     * Iterator method to be overwritten.
+     *
+     * @param instruction The current instruction.
+     * @param value The value that is iterated.
+     * @param mode The operand mode for the value.
+     * @param flags A set of flags for the value.
+     * @return The new value to replace the value that was passed in.
+     */
+    Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIR.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIR.java
new file mode 100644
index 0000000..969a13b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIR.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+
+/**
+ * This class implements the overall container for the LIR graph and directs its construction,
+ * optimization, and finalization.
+ */
+public final class LIR extends LIRGenerator.VariableProvider {
+
+    private final AbstractControlFlowGraph<?> cfg;
+
+    /**
+     * The linear-scan ordered list of blocks.
+     */
+    private final AbstractBlockBase<?>[] linearScanOrder;
+
+    /**
+     * The order in which the code is emitted.
+     */
+    private final AbstractBlockBase<?>[] codeEmittingOrder;
+
+    /**
+     * Map from {@linkplain AbstractBlockBase block} to {@linkplain LIRInstruction}s. Note that we
+     * are using {@link ArrayList} instead of {@link List} to avoid interface dispatch.
+     */
+    private final BlockMap<ArrayList<LIRInstruction>> lirInstructions;
+
+    private boolean hasArgInCallerFrame;
+
+    /**
+     * Creates a new LIR instance for the specified compilation.
+     */
+    public LIR(AbstractControlFlowGraph<?> cfg, AbstractBlockBase<?>[] linearScanOrder, AbstractBlockBase<?>[] codeEmittingOrder) {
+        this.cfg = cfg;
+        this.codeEmittingOrder = codeEmittingOrder;
+        this.linearScanOrder = linearScanOrder;
+        this.lirInstructions = new BlockMap<>(cfg);
+    }
+
+    public AbstractControlFlowGraph<?> getControlFlowGraph() {
+        return cfg;
+    }
+
+    /**
+     * Determines if any instruction in the LIR has debug info associated with it.
+     */
+    public boolean hasDebugInfo() {
+        for (AbstractBlockBase<?> b : linearScanOrder()) {
+            for (LIRInstruction op : getLIRforBlock(b)) {
+                if (op.hasState()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public ArrayList<LIRInstruction> getLIRforBlock(AbstractBlockBase<?> block) {
+        return lirInstructions.get(block);
+    }
+
+    public void setLIRforBlock(AbstractBlockBase<?> block, ArrayList<LIRInstruction> list) {
+        assert getLIRforBlock(block) == null : "lir instruction list should only be initialized once";
+        lirInstructions.put(block, list);
+    }
+
+    /**
+     * Gets the linear scan ordering of blocks as an array.
+     *
+     * @return the blocks in linear scan order
+     */
+    public AbstractBlockBase<?>[] linearScanOrder() {
+        return linearScanOrder;
+    }
+
+    public AbstractBlockBase<?>[] codeEmittingOrder() {
+        return codeEmittingOrder;
+    }
+
+    public void setHasArgInCallerFrame() {
+        hasArgInCallerFrame = true;
+    }
+
+    /**
+     * Determines if any of the parameters to the method are passed via the stack where the
+     * parameters are located in the caller's frame.
+     */
+    public boolean hasArgInCallerFrame() {
+        return hasArgInCallerFrame;
+    }
+
+    /**
+     * Gets the next non-{@code null} block in a list.
+     *
+     * @param blocks list of blocks
+     * @param blockIndex index of the current block
+     * @return the next block in the list that is none {@code null} or {@code null} if there is no
+     *         such block
+     */
+    public static AbstractBlockBase<?> getNextBlock(AbstractBlockBase<?>[] blocks, int blockIndex) {
+        for (int nextIndex = blockIndex + 1; nextIndex > 0 && nextIndex < blocks.length; nextIndex++) {
+            AbstractBlockBase<?> nextBlock = blocks[nextIndex];
+            if (nextBlock != null) {
+                return nextBlock;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the exception edge (if any) originating at a given operation.
+     */
+    public static LabelRef getExceptionEdge(LIRInstruction op) {
+        final LabelRef[] exceptionEdge = {null};
+        op.forEachState(state -> {
+            if (state.exceptionEdge != null) {
+                assert exceptionEdge[0] == null;
+                exceptionEdge[0] = state.exceptionEdge;
+            }
+        });
+        return exceptionEdge[0];
+    }
+
+    /**
+     * The maximum distance an operation with an {@linkplain #getExceptionEdge(LIRInstruction)
+     * exception edge} can be from the last instruction of a LIR block. The value of 3 is based on a
+     * non-void call operation that has an exception edge. Such a call may move the result to
+     * another register and then spill it.
+     * <p>
+     * The rationale for such a constant is to limit the search for an insertion point when adding
+     * move operations at the end of a block. Such moves must be inserted before all control flow
+     * instructions.
+     */
+    public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3;
+
+    public static boolean verifyBlock(LIR lir, AbstractBlockBase<?> block) {
+        ArrayList<LIRInstruction> ops = lir.getLIRforBlock(block);
+        if (ops.size() == 0) {
+            return false;
+        }
+        assert ops.get(0) instanceof LabelOp : String.format("Not a Label %s (Block %s)", ops.get(0).getClass(), block);
+        LIRInstruction opWithExceptionEdge = null;
+        int index = 0;
+        int lastIndex = ops.size() - 1;
+        for (LIRInstruction op : ops.subList(0, lastIndex)) {
+            assert !(op instanceof BlockEndOp) : String.format("BlockEndOp %s (Block %s)", op.getClass(), block);
+            LabelRef exceptionEdge = getExceptionEdge(op);
+            if (exceptionEdge != null) {
+                assert opWithExceptionEdge == null : "multiple ops with an exception edge not allowed";
+                opWithExceptionEdge = op;
+                int distanceFromEnd = lastIndex - index;
+                assert distanceFromEnd <= MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END;
+            }
+            index++;
+        }
+        LIRInstruction end = ops.get(lastIndex);
+        assert end instanceof BlockEndOp : String.format("Not a BlockEndOp %s (Block %s)", end.getClass(), block);
+        return true;
+    }
+
+    public static boolean verifyBlocks(LIR lir, AbstractBlockBase<?>[] blocks) {
+        for (AbstractBlockBase<?> block : blocks) {
+            if (block == null) {
+                continue;
+            }
+            for (AbstractBlockBase<?> sux : block.getSuccessors()) {
+                assert Arrays.asList(blocks).contains(sux) : "missing successor from: " + block + "to: " + sux;
+            }
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                assert Arrays.asList(blocks).contains(pred) : "missing predecessor from: " + block + "to: " + pred;
+            }
+            if (!verifyBlock(lir, block)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void resetLabels() {
+
+        for (AbstractBlockBase<?> block : codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            for (LIRInstruction inst : lirInstructions.get(block)) {
+                if (inst instanceof LabelOp) {
+                    ((LabelOp) inst).getLabel().reset();
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRFrameState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRFrameState.java
new file mode 100644
index 0000000..74d805c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRFrameState.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isConstantJavaValue;
+import static jdk.vm.ci.code.ValueUtil.isIllegalJavaValue;
+import static jdk.vm.ci.code.ValueUtil.isVirtualObject;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.util.IndexedValueMap;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.StackLockValue;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This class represents garbage collection and deoptimization information attached to a LIR
+ * instruction.
+ */
+public class LIRFrameState {
+
+    public final BytecodeFrame topFrame;
+    private final VirtualObject[] virtualObjects;
+    public final LabelRef exceptionEdge;
+    protected DebugInfo debugInfo;
+
+    private IndexedValueMap liveBasePointers;
+
+    public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
+        this.topFrame = topFrame;
+        this.virtualObjects = virtualObjects;
+        this.exceptionEdge = exceptionEdge;
+    }
+
+    public boolean hasDebugInfo() {
+        return debugInfo != null;
+    }
+
+    public DebugInfo debugInfo() {
+        assert debugInfo != null : "debug info not allocated yet";
+        return debugInfo;
+    }
+
+    /**
+     * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
+     *
+     * @param proc The procedure called for variables.
+     */
+    public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
+        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
+            processValues(inst, cur.values, proc);
+        }
+        if (virtualObjects != null) {
+            for (VirtualObject obj : virtualObjects) {
+                processValues(inst, obj.getValues(), proc);
+            }
+        }
+        if (liveBasePointers != null) {
+            liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
+        }
+    }
+
+    /**
+     * Iterates the frame state and calls the {@link InstructionValueConsumer} for every variable.
+     *
+     * @param proc The procedure called for variables.
+     */
+    public void visitEachState(LIRInstruction inst, InstructionValueConsumer proc) {
+        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
+            visitValues(inst, cur.values, proc);
+        }
+        if (virtualObjects != null) {
+            for (VirtualObject obj : virtualObjects) {
+                visitValues(inst, obj.getValues(), proc);
+            }
+        }
+        if (liveBasePointers != null) {
+            liveBasePointers.visitEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
+        }
+    }
+
+    /**
+     * We filter out constant and illegal values ourself before calling the procedure, so
+     * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
+     */
+    protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
+
+    protected void processValues(LIRInstruction inst, JavaValue[] values, InstructionValueProcedure proc) {
+        for (int i = 0; i < values.length; i++) {
+            JavaValue value = values[i];
+            if (isIllegalJavaValue(value)) {
+                continue;
+            }
+            if (value instanceof AllocatableValue) {
+                AllocatableValue allocatable = (AllocatableValue) value;
+                Value result = proc.doValue(inst, allocatable, OperandMode.ALIVE, STATE_FLAGS);
+                if (!allocatable.identityEquals(result)) {
+                    values[i] = (JavaValue) result;
+                }
+            } else if (value instanceof StackLockValue) {
+                StackLockValue monitor = (StackLockValue) value;
+                JavaValue owner = monitor.getOwner();
+                if (owner instanceof AllocatableValue) {
+                    monitor.setOwner((JavaValue) proc.doValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS));
+                }
+                Value slot = monitor.getSlot();
+                if (isVirtualStackSlot(slot)) {
+                    monitor.setSlot(asAllocatableValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
+                }
+            } else {
+                assert unprocessed(value);
+            }
+        }
+    }
+
+    protected void visitValues(LIRInstruction inst, JavaValue[] values, InstructionValueConsumer proc) {
+        for (int i = 0; i < values.length; i++) {
+            JavaValue value = values[i];
+            if (isIllegalJavaValue(value)) {
+                continue;
+            } else if (value instanceof AllocatableValue) {
+                proc.visitValue(inst, (AllocatableValue) value, OperandMode.ALIVE, STATE_FLAGS);
+            } else if (value instanceof StackLockValue) {
+                StackLockValue monitor = (StackLockValue) value;
+                JavaValue owner = monitor.getOwner();
+                if (owner instanceof AllocatableValue) {
+                    proc.visitValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS);
+                }
+                Value slot = monitor.getSlot();
+                if (isVirtualStackSlot(slot)) {
+                    proc.visitValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS);
+                }
+            } else {
+                assert unprocessed(value);
+            }
+        }
+    }
+
+    private boolean unprocessed(JavaValue value) {
+        if (isIllegalJavaValue(value)) {
+            // Ignore dead local variables.
+            return true;
+        } else if (isConstantJavaValue(value)) {
+            // Ignore constants, the register allocator does not need to see them.
+            return true;
+        } else if (isVirtualObject(value)) {
+            assert Arrays.asList(virtualObjects).contains(value);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Called by the register allocator to initialize the frame state.
+     *
+     * @param frameMap The frame map.
+     * @param canHaveRegisters True if there can be any register map entries.
+     */
+    public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
+        debugInfo = new DebugInfo(topFrame, virtualObjects);
+    }
+
+    public IndexedValueMap getLiveBasePointers() {
+        return liveBasePointers;
+    }
+
+    public void setLiveBasePointers(IndexedValueMap liveBasePointers) {
+        this.liveBasePointers = liveBasePointers;
+    }
+
+    @Override
+    public String toString() {
+        return debugInfo != null ? debugInfo.toString() : topFrame != null ? topFrame.toString() : "<empty>";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInsertionBuffer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInsertionBuffer.java
new file mode 100644
index 0000000..f46ef6e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInsertionBuffer.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A buffer to enqueue updates to a list. This avoids frequent re-sizing of the list and copying of
+ * list elements when insertions are done at multiple positions of the list. Additionally, it
+ * ensures that the list is not modified while it is, e.g., iterated, and instead only modified once
+ * after the iteration is done.
+ * <p>
+ * The buffer uses internal data structures to store the enqueued updates. To avoid allocations, a
+ * buffer can be re-used. Call the methods in the following order: {@link #init}, {@link #append},
+ * {@link #append}, ..., {@link #finish()}, {@link #init}, ...
+ * <p>
+ * Note: This class does not depend on LIRInstruction, so we could make it a generic utility class.
+ */
+public final class LIRInsertionBuffer {
+
+    /**
+     * The lir list where ops of this buffer should be inserted later (null when uninitialized).
+     */
+    private List<LIRInstruction> lir;
+
+    /**
+     * List of insertion points. index and count are stored alternately: indexAndCount[i * 2]: the
+     * index into lir list where "count" ops should be inserted indexAndCount[i * 2 + 1]: the number
+     * of ops to be inserted at index
+     */
+    private int[] indexAndCount;
+    private int indexAndCountSize;
+
+    /**
+     * The LIROps to be inserted.
+     */
+    private final List<LIRInstruction> ops;
+
+    public LIRInsertionBuffer() {
+        indexAndCount = new int[8];
+        ops = new ArrayList<>(4);
+    }
+
+    /**
+     * Initialize this buffer. This method must be called before using {@link #append}.
+     */
+    public void init(List<LIRInstruction> newLir) {
+        assert !initialized() : "already initialized";
+        assert indexAndCountSize == 0 && ops.size() == 0;
+        this.lir = newLir;
+    }
+
+    public boolean initialized() {
+        return lir != null;
+    }
+
+    public List<LIRInstruction> lirList() {
+        return lir;
+    }
+
+    /**
+     * Enqueue a new instruction that will be appended to the instruction list when
+     * {@link #finish()} is called. The new instruction is added <b>before</b> the existing
+     * instruction with the given index. This method can only be called with increasing values of
+     * index, e.g., once an instruction was appended with index 4, subsequent instructions can only
+     * be appended with index 4 or higher.
+     */
+    public void append(int index, LIRInstruction op) {
+        int i = numberOfInsertionPoints() - 1;
+        if (i < 0 || indexAt(i) < index) {
+            appendNew(index, 1);
+        } else {
+            assert indexAt(i) == index : "can append LIROps in ascending order only";
+            assert countAt(i) > 0 : "check";
+            setCountAt(i, countAt(i) + 1);
+        }
+        ops.add(op);
+
+        assert verify();
+    }
+
+    /**
+     * Append all enqueued instructions to the instruction list. After that, {@link #init(List)} can
+     * be called again to re-use this buffer.
+     */
+    public void finish() {
+        if (ops.size() > 0) {
+            int n = lir.size();
+            // increase size of instructions list
+            for (int i = 0; i < ops.size(); i++) {
+                lir.add(null);
+            }
+            // insert ops from buffer into instructions list
+            int opIndex = ops.size() - 1;
+            int ipIndex = numberOfInsertionPoints() - 1;
+            int fromIndex = n - 1;
+            int toIndex = lir.size() - 1;
+            while (ipIndex >= 0) {
+                int index = indexAt(ipIndex);
+                // make room after insertion point
+                while (fromIndex >= index) {
+                    lir.set(toIndex--, lir.get(fromIndex--));
+                }
+                // insert ops from buffer
+                for (int i = countAt(ipIndex); i > 0; i--) {
+                    lir.set(toIndex--, ops.get(opIndex--));
+                }
+                ipIndex--;
+            }
+            indexAndCountSize = 0;
+            ops.clear();
+        }
+        lir = null;
+    }
+
+    private void appendNew(int index, int count) {
+        int oldSize = indexAndCountSize;
+        int newSize = oldSize + 2;
+        if (newSize > this.indexAndCount.length) {
+            indexAndCount = Arrays.copyOf(indexAndCount, newSize * 2);
+        }
+        indexAndCount[oldSize] = index;
+        indexAndCount[oldSize + 1] = count;
+        this.indexAndCountSize = newSize;
+    }
+
+    private void setCountAt(int i, int value) {
+        indexAndCount[(i << 1) + 1] = value;
+    }
+
+    private int numberOfInsertionPoints() {
+        assert indexAndCount.length % 2 == 0 : "must have a count for each index";
+        return indexAndCountSize >> 1;
+    }
+
+    private int indexAt(int i) {
+        return indexAndCount[(i << 1)];
+    }
+
+    private int countAt(int i) {
+        return indexAndCount[(i << 1) + 1];
+    }
+
+    private boolean verify() {
+        int sum = 0;
+        int prevIdx = -1;
+
+        for (int i = 0; i < numberOfInsertionPoints(); i++) {
+            assert prevIdx < indexAt(i) : "index must be ordered ascending";
+            sum += countAt(i);
+        }
+        assert sum == ops.size() : "wrong total sum";
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java
new file mode 100644
index 0000000..c0c12af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.ALIVE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.DEF;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.TEMP;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * The base class for an {@code LIRInstruction}.
+ */
+public abstract class LIRInstruction {
+    /**
+     * Constants denoting how a LIR instruction uses an operand.
+     */
+    public enum OperandMode {
+        /**
+         * The value must have been defined before. It is alive before the instruction until the
+         * beginning of the instruction, but not necessarily throughout the instruction. A register
+         * assigned to it can also be assigned to a {@link #TEMP} or {@link #DEF} operand. The value
+         * can be used again after the instruction, so the instruction must not modify the register.
+         */
+        USE,
+
+        /**
+         * The value must have been defined before. It is alive before the instruction and
+         * throughout the instruction. A register assigned to it cannot be assigned to a
+         * {@link #TEMP} or {@link #DEF} operand. The value can be used again after the instruction,
+         * so the instruction must not modify the register.
+         */
+        ALIVE,
+
+        /**
+         * The value must not have been defined before, and must not be used after the instruction.
+         * The instruction can do whatever it wants with the register assigned to it (or not use it
+         * at all).
+         */
+        TEMP,
+
+        /**
+         * The value must not have been defined before. The instruction has to assign a value to the
+         * register. The value can (and most likely will) be used after the instruction.
+         */
+        DEF,
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Use {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Alive {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Temp {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Def {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface State {
+    }
+
+    /**
+     * Flags for an operand.
+     */
+    public enum OperandFlag {
+        /**
+         * The value can be a {@link RegisterValue}.
+         */
+        REG,
+
+        /**
+         * The value can be a {@link StackSlot}.
+         */
+        STACK,
+
+        /**
+         * The value can be a {@link CompositeValue}.
+         */
+        COMPOSITE,
+
+        /**
+         * The value can be a {@link JavaConstant}.
+         */
+        CONST,
+
+        /**
+         * The value can be {@link Value#ILLEGAL}.
+         */
+        ILLEGAL,
+
+        /**
+         * The register allocator should try to assign a certain register to improve code quality.
+         * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints.
+         */
+        HINT,
+
+        /**
+         * The value can be uninitialized, e.g., a stack slot that has not written to before. This
+         * is only used to avoid false positives in verification code.
+         */
+        UNINITIALIZED,
+
+        /** Outgoing block value. */
+        OUTGOING,
+    }
+
+    /**
+     * For validity checking of the operand flags defined by instruction subclasses.
+     */
+    protected static final EnumMap<OperandMode, EnumSet<OperandFlag>> ALLOWED_FLAGS;
+
+    static {
+        ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
+        ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED, OUTGOING));
+        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
+    }
+
+    /**
+     * The flags of the base and index value of an address.
+     */
+    protected static final EnumSet<OperandFlag> ADDRESS_FLAGS = EnumSet.of(REG, ILLEGAL);
+
+    private final LIRInstructionClass<?> instructionClass;
+
+    /**
+     * Instruction id for register allocation.
+     */
+    private int id;
+
+    /**
+     * The source position of the code that generated this instruction.
+     */
+    private NodeSourcePosition position;
+
+    private static final DebugCounter LIR_NODE_COUNT = Debug.counter("LIRNodes");
+
+    /**
+     * Constructs a new LIR instruction.
+     */
+    public LIRInstruction(LIRInstructionClass<? extends LIRInstruction> c) {
+        LIR_NODE_COUNT.increment();
+        instructionClass = c;
+        assert c.getClazz() == this.getClass();
+        id = -1;
+    }
+
+    public abstract void emitCode(CompilationResultBuilder crb);
+
+    public final int id() {
+        return id;
+    }
+
+    public final void setId(int id) {
+        this.id = id;
+    }
+
+    public final NodeSourcePosition getPosition() {
+        return position;
+    }
+
+    public final void setPosition(NodeSourcePosition position) {
+        this.position = position;
+    }
+
+    public final String name() {
+        return instructionClass.getOpcode(this);
+    }
+
+    public final boolean hasOperands() {
+        return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters();
+    }
+
+    public final boolean hasState() {
+        return instructionClass.hasState(this);
+    }
+
+    public boolean destroysCallerSavedRegisters() {
+        return false;
+    }
+
+    // InstructionValueProcedures
+    public final void forEachInput(InstructionValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void forEachAlive(InstructionValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void forEachTemp(InstructionValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void forEachOutput(InstructionValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
+    public final void forEachState(InstructionValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    // ValueProcedures
+    public final void forEachInput(ValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void forEachAlive(ValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void forEachTemp(ValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void forEachOutput(ValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
+    public final void forEachState(ValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    // States
+    public final void forEachState(InstructionStateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    public final void forEachState(StateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    // InstructionValueConsumers
+    public final void visitEachInput(InstructionValueConsumer proc) {
+        instructionClass.visitEachUse(this, proc);
+    }
+
+    public final void visitEachAlive(InstructionValueConsumer proc) {
+        instructionClass.visitEachAlive(this, proc);
+    }
+
+    public final void visitEachTemp(InstructionValueConsumer proc) {
+        instructionClass.visitEachTemp(this, proc);
+    }
+
+    public final void visitEachOutput(InstructionValueConsumer proc) {
+        instructionClass.visitEachDef(this, proc);
+    }
+
+    public final void visitEachState(InstructionValueConsumer proc) {
+        instructionClass.visitEachState(this, proc);
+    }
+
+    // ValueConsumers
+    public final void visitEachInput(ValueConsumer proc) {
+        instructionClass.visitEachUse(this, proc);
+    }
+
+    public final void visitEachAlive(ValueConsumer proc) {
+        instructionClass.visitEachAlive(this, proc);
+    }
+
+    public final void visitEachTemp(ValueConsumer proc) {
+        instructionClass.visitEachTemp(this, proc);
+    }
+
+    public final void visitEachOutput(ValueConsumer proc) {
+        instructionClass.visitEachDef(this, proc);
+    }
+
+    public final void visitEachState(ValueConsumer proc) {
+        instructionClass.visitEachState(this, proc);
+    }
+
+    @SuppressWarnings("unused")
+    public final Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc) {
+        return instructionClass.forEachRegisterHint(this, mode, proc);
+    }
+
+    @SuppressWarnings("unused")
+    public final Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
+        return instructionClass.forEachRegisterHint(this, mode, proc);
+    }
+
+    /**
+     * Utility method to add stack arguments to a list of temporaries. Useful for modeling calling
+     * conventions that kill outgoing argument space.
+     *
+     * @return additional temporaries
+     */
+    protected static Value[] addStackSlotsToTemporaries(Value[] parameters, Value[] temporaries) {
+        int extraTemps = 0;
+        for (Value p : parameters) {
+            if (isStackSlot(p)) {
+                extraTemps++;
+            }
+            assert !isVirtualStackSlot(p) : "only real stack slots in calling convention";
+        }
+        if (extraTemps != 0) {
+            int index = temporaries.length;
+            Value[] newTemporaries = Arrays.copyOf(temporaries, temporaries.length + extraTemps);
+            for (Value p : parameters) {
+                if (isStackSlot(p)) {
+                    newTemporaries[index++] = p;
+                }
+            }
+            return newTemporaries;
+        }
+        return temporaries;
+    }
+
+    public void verify() {
+    }
+
+    public final String toStringWithIdPrefix() {
+        if (id != -1) {
+            return String.format("%4d %s", id, toString());
+        }
+        return "     " + toString();
+    }
+
+    @Override
+    public String toString() {
+        return instructionClass.toString(this);
+    }
+
+    public LIRInstructionClass<?> getLIRInstructionClass() {
+        return instructionClass;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java
new file mode 100644
index 0000000..dcdb797
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.FieldsScanner;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Value;
+
+public class LIRInstructionClass<T> extends LIRIntrospection<T> {
+
+    public static <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) {
+        return new LIRInstructionClass<>(c);
+    }
+
+    private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
+    private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
+
+    private final Values uses;
+    private final Values alives;
+    private final Values temps;
+    private final Values defs;
+    private final Fields states;
+
+    private String opcodeConstant;
+    private int opcodeIndex;
+
+    private LIRInstructionClass(Class<T> clazz) {
+        this(clazz, new FieldsScanner.DefaultCalcOffset());
+    }
+
+    public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) {
+        super(clazz);
+        assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
+
+        LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset);
+        ifs.scan(clazz);
+
+        uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class));
+        alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class));
+        temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class));
+        defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class));
+
+        states = new Fields(ifs.states);
+        data = new Fields(ifs.data);
+
+        opcodeConstant = ifs.opcodeConstant;
+        if (ifs.opcodeField == null) {
+            opcodeIndex = -1;
+        } else {
+            opcodeIndex = ifs.data.indexOf(ifs.opcodeField);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> LIRInstructionClass<T> get(Class<T> clazz) {
+        try {
+            Field field = clazz.getDeclaredField("TYPE");
+            field.setAccessible(true);
+            return (LIRInstructionClass<T>) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {
+
+        private String opcodeConstant;
+
+        /**
+         * Field (if any) annotated by {@link Opcode}.
+         */
+        private FieldsScanner.FieldInfo opcodeField;
+
+        LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) {
+            super(calc);
+
+            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation());
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
+            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
+            // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so
+            // we have to duplicate the code for every operand mode.
+            // Unfortunately, annotations cannot have an EnumSet property, so we have to convert
+            // from arrays to EnumSet manually.
+            if (field.isAnnotationPresent(LIRInstruction.Use.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value()));
+            } else {
+                GraalError.shouldNotReachHere();
+            }
+            return result;
+        }
+
+        public void scan(Class<?> clazz) {
+            if (clazz.getAnnotation(Opcode.class) != null) {
+                opcodeConstant = clazz.getAnnotation(Opcode.class).value();
+            }
+            opcodeField = null;
+
+            super.scan(clazz, LIRInstruction.class, false);
+
+            if (opcodeConstant == null && opcodeField == null) {
+                opcodeConstant = clazz.getSimpleName();
+                if (opcodeConstant.endsWith("Op")) {
+                    opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2);
+                }
+            }
+        }
+
+        @Override
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
+            if (STATE_CLASS.isAssignableFrom(type)) {
+                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
+                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass()));
+            } else {
+                super.scanField(field, offset);
+            }
+
+            if (field.getAnnotation(Opcode.class) != null) {
+                assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type;
+                assert data.get(data.size() - 1).offset == offset;
+                opcodeField = data.get(data.size() - 1);
+            }
+        }
+    }
+
+    @Override
+    public Fields[] getAllFields() {
+        assert values == null;
+        return new Fields[]{data, uses, alives, temps, defs, states};
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
+        uses.appendFields(str);
+        str.append("] alive[");
+        alives.appendFields(str);
+        str.append("] temp[");
+        temps.appendFields(str);
+        str.append("] def[");
+        defs.appendFields(str);
+        str.append("] state[");
+        states.appendFields(str);
+        str.append("] data[");
+        data.appendFields(str);
+        str.append("]");
+        return str.toString();
+    }
+
+    Values getValues(OperandMode mode) {
+        switch (mode) {
+            case USE:
+                return uses;
+            case ALIVE:
+                return alives;
+            case TEMP:
+                return temps;
+            case DEF:
+                return defs;
+            default:
+                throw GraalError.shouldNotReachHere("unknown OperandMode: " + mode);
+        }
+    }
+
+    final String getOpcode(LIRInstruction obj) {
+        if (opcodeConstant != null) {
+            return opcodeConstant;
+        }
+        assert opcodeIndex != -1;
+        return String.valueOf(data.getObject(obj, opcodeIndex));
+    }
+
+    final boolean hasOperands() {
+        return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
+    }
+
+    final boolean hasState(LIRInstruction obj) {
+        for (int i = 0; i < states.getCount(); i++) {
+            if (states.getObject(obj, i) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, uses, OperandMode.USE, proc);
+    }
+
+    final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, alives, OperandMode.ALIVE, proc);
+    }
+
+    final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, temps, OperandMode.TEMP, proc);
+    }
+
+    final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, defs, OperandMode.DEF, proc);
+    }
+
+    final void visitEachUse(LIRInstruction obj, InstructionValueConsumer proc) {
+        visitEach(obj, uses, OperandMode.USE, proc);
+    }
+
+    final void visitEachAlive(LIRInstruction obj, InstructionValueConsumer proc) {
+        visitEach(obj, alives, OperandMode.ALIVE, proc);
+    }
+
+    final void visitEachTemp(LIRInstruction obj, InstructionValueConsumer proc) {
+        visitEach(obj, temps, OperandMode.TEMP, proc);
+    }
+
+    final void visitEachDef(LIRInstruction obj, InstructionValueConsumer proc) {
+        visitEach(obj, defs, OperandMode.DEF, proc);
+    }
+
+    final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) {
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
+            if (state != null) {
+                state.forEachState(obj, proc);
+            }
+        }
+    }
+
+    final void visitEachState(LIRInstruction obj, InstructionValueConsumer proc) {
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
+            if (state != null) {
+                state.visitEachState(obj, proc);
+            }
+        }
+    }
+
+    final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
+            if (state != null) {
+                proc.doState(obj, state);
+            }
+        }
+    }
+
+    final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
+        Values hints;
+        if (mode == OperandMode.USE) {
+            hints = defs;
+        } else if (mode == OperandMode.DEF) {
+            hints = uses;
+        } else {
+            return null;
+        }
+
+        for (int i = 0; i < hints.getCount(); i++) {
+            if (i < hints.getDirectCount()) {
+                Value hintValue = hints.getValue(obj, i);
+                Value result = proc.doValue(obj, hintValue, null, null);
+                if (result != null) {
+                    return result;
+                }
+            } else {
+                Value[] hintValues = hints.getValueArray(obj, i);
+                for (int j = 0; j < hintValues.length; j++) {
+                    Value hintValue = hintValues[j];
+                    Value result = proc.doValue(obj, hintValue, null, null);
+                    if (result != null) {
+                        return result;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    String toString(LIRInstruction obj) {
+        StringBuilder result = new StringBuilder();
+
+        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs);
+        result.append(String.valueOf(getOpcode(obj)).toUpperCase());
+        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives);
+        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps);
+
+        for (int i = 0; i < data.getCount(); i++) {
+            if (i == opcodeIndex) {
+                continue;
+            }
+            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
+        }
+
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
+            if (state != null) {
+                result.append(" ").append(states.getName(i)).append(" [bci:");
+                String sep = "";
+                for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) {
+                    result.append(sep).append(cur.getBCI());
+                    sep = ", ";
+                }
+                result.append("]");
+            }
+        }
+
+        return result.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java
new file mode 100644
index 0000000..92b31c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.core.common.FieldIntrospection;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.FieldsScanner;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.Value;
+
+abstract class LIRIntrospection<T> extends FieldIntrospection<T> {
+
+    private static final Class<Value> VALUE_CLASS = Value.class;
+    private static final Class<ConstantValue> CONSTANT_VALUE_CLASS = ConstantValue.class;
+    private static final Class<Variable> VARIABLE_CLASS = Variable.class;
+    private static final Class<RegisterValue> REGISTER_VALUE_CLASS = RegisterValue.class;
+    private static final Class<StackSlot> STACK_SLOT_CLASS = StackSlot.class;
+    private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class;
+
+    LIRIntrospection(Class<T> clazz) {
+        super(clazz);
+    }
+
+    protected static class Values extends Fields {
+        private final int directCount;
+        private final EnumSet<OperandFlag>[] flags;
+
+        public Values(OperandModeAnnotation mode) {
+            this(mode.directCount, mode.values);
+        }
+
+        @SuppressWarnings({"unchecked"})
+        public Values(int directCount, ArrayList<ValueFieldInfo> fields) {
+            super(fields);
+            this.directCount = directCount;
+            flags = (EnumSet<OperandFlag>[]) new EnumSet<?>[fields.size()];
+            for (int i = 0; i < fields.size(); i++) {
+                flags[i] = fields.get(i).flags;
+            }
+        }
+
+        public int getDirectCount() {
+            return directCount;
+        }
+
+        public EnumSet<OperandFlag> getFlags(int i) {
+            return flags[i];
+        }
+
+        protected Value getValue(Object obj, int index) {
+            return (Value) getObject(obj, index);
+        }
+
+        protected void setValue(Object obj, int index, Value value) {
+            putObject(obj, index, value);
+        }
+
+        protected Value[] getValueArray(Object obj, int index) {
+            return (Value[]) getObject(obj, index);
+        }
+
+        protected void setValueArray(Object obj, int index, Value[] valueArray) {
+            putObject(obj, index, valueArray);
+        }
+    }
+
+    /**
+     * The component values in an {@link LIRInstruction} or {@link CompositeValue}.
+     */
+    protected Values values;
+
+    protected static class ValueFieldInfo extends FieldsScanner.FieldInfo {
+
+        final EnumSet<OperandFlag> flags;
+
+        public ValueFieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass, EnumSet<OperandFlag> flags) {
+            super(offset, name, type, declaringClass);
+            assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type);
+            this.flags = flags;
+        }
+
+        /**
+         * Sorts non-array fields before array fields.
+         */
+        @Override
+        public int compareTo(FieldsScanner.FieldInfo o) {
+            if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) {
+                if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + flags;
+        }
+    }
+
+    protected static class OperandModeAnnotation {
+
+        /**
+         * Number of non-array fields in {@link #values}.
+         */
+        public int directCount;
+        public final ArrayList<ValueFieldInfo> values = new ArrayList<>();
+    }
+
+    protected abstract static class LIRFieldsScanner extends FieldsScanner {
+
+        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
+        public final ArrayList<FieldsScanner.FieldInfo> states = new ArrayList<>();
+
+        public LIRFieldsScanner(FieldsScanner.CalcOffset calc) {
+            super(calc);
+            valueAnnotations = new HashMap<>();
+        }
+
+        protected OperandModeAnnotation getOperandModeAnnotation(Field field) {
+            OperandModeAnnotation result = null;
+            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) {
+                Annotation annotation = field.getAnnotation(entry.getKey());
+                if (annotation != null) {
+                    assert result == null : "Field has two operand mode annotations: " + field;
+                    result = entry.getValue();
+                }
+            }
+            return result;
+        }
+
+        protected abstract EnumSet<OperandFlag> getFlags(Field field);
+
+        @Override
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
+            if (VALUE_CLASS.isAssignableFrom(type) && !CONSTANT_VALUE_CLASS.isAssignableFrom(type)) {
+                assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                EnumSet<OperandFlag> flags = getFlags(field);
+                assert verifyFlags(field, type, flags);
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
+                annotation.directCount++;
+            } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                EnumSet<OperandFlag> flags = getFlags(field);
+                assert verifyFlags(field, type.getComponentType(), flags);
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
+            } else {
+                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
+                super.scanField(field, offset);
+            }
+        }
+
+        private static boolean verifyFlags(Field field, Class<?> type, EnumSet<OperandFlag> flags) {
+            if (flags.contains(REG)) {
+                assert type.isAssignableFrom(REGISTER_VALUE_CLASS) || type.isAssignableFrom(VARIABLE_CLASS) : "Cannot assign RegisterValue / Variable to field with REG flag:" + field;
+            }
+            if (flags.contains(STACK)) {
+                assert type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field with STACK flag:" + field;
+            }
+            if (flags.contains(CONST)) {
+                assert type.isAssignableFrom(CONSTANT_VALUE_CLASS) : "Cannot assign Constant to field with CONST flag:" + field;
+            }
+            return true;
+        }
+    }
+
+    protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) {
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
+
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(inst, i);
+                Value newValue;
+                if (value instanceof CompositeValue) {
+                    CompositeValue composite = (CompositeValue) value;
+                    newValue = composite.forEachComponent(inst, mode, proc);
+                } else {
+                    newValue = proc.doValue(inst, value, mode, values.getFlags(i));
+                }
+                if (!value.identityEquals(newValue)) {
+                    values.setValue(inst, i, newValue);
+                }
+            } else {
+                Value[] valueArray = values.getValueArray(inst, i);
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
+                    Value newValue;
+                    if (value instanceof CompositeValue) {
+                        CompositeValue composite = (CompositeValue) value;
+                        newValue = composite.forEachComponent(inst, mode, proc);
+                    } else {
+                        newValue = proc.doValue(inst, value, mode, values.getFlags(i));
+                    }
+                    if (!value.identityEquals(newValue)) {
+                        valueArray[j] = newValue;
+                    }
+                }
+            }
+        }
+    }
+
+    protected static void visitEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueConsumer proc) {
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
+
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(inst, i);
+                if (value instanceof CompositeValue) {
+                    CompositeValue composite = (CompositeValue) value;
+                    composite.visitEachComponent(inst, mode, proc);
+                } else {
+                    proc.visitValue(inst, value, mode, values.getFlags(i));
+                }
+            } else {
+                Value[] valueArray = values.getValueArray(inst, i);
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
+                    if (value instanceof CompositeValue) {
+                        CompositeValue composite = (CompositeValue) value;
+                        composite.visitEachComponent(inst, mode, proc);
+                    } else {
+                        proc.visitValue(inst, value, mode, values.getFlags(i));
+                    }
+                }
+            }
+        }
+    }
+
+    protected static void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) {
+        int total = 0;
+        for (Fields fields : fieldsList) {
+            total += fields.getCount();
+        }
+        if (total == 0) {
+            return;
+        }
+
+        sb.append(start);
+        if (total > 1) {
+            sb.append(startMultiple);
+        }
+        String sep = "";
+        int i = 0;
+        for (Fields fields : fieldsList) {
+            for (int j = 0; j < fields.getCount(); j++) {
+                sb.append(sep).append(prefix[i]);
+                if (total > 1) {
+                    sb.append(fields.getName(j)).append(": ");
+                }
+                sb.append(getFieldString(obj, j, fields));
+                sep = ", ";
+            }
+            i++;
+        }
+        if (total > 1) {
+            sb.append(endMultiple);
+        }
+        sb.append(end);
+    }
+
+    protected static String getFieldString(Object obj, int index, Fields fields) {
+        Object value = fields.get(obj, index);
+        Class<?> type = fields.getType(index);
+        if (value == null || type.isPrimitive() || !type.isArray()) {
+            return String.valueOf(value);
+        }
+        if (type == int[].class) {
+            return Arrays.toString((int[]) value);
+        } else if (type == double[].class) {
+            return Arrays.toString((double[]) value);
+        } else if (type == byte[].class) {
+            byte[] byteValue = (byte[]) value;
+            if (isPrintableAsciiString(byteValue)) {
+                return toString(byteValue);
+            } else {
+                return Arrays.toString(byteValue);
+            }
+        } else if (!type.getComponentType().isPrimitive()) {
+            return Arrays.toString((Object[]) value);
+        }
+        assert false : "unhandled field type: " + type;
+        return "";
+    }
+
+    /**
+     * Tests if all values in this string are printable ASCII characters or value \0 (b in
+     * [0x20,0x7F]) or b == 0.
+     *
+     * @param array
+     * @return true if there are only printable ASCII characters and \0, false otherwise
+     */
+    private static boolean isPrintableAsciiString(byte[] array) {
+        for (byte b : array) {
+            char c = (char) b;
+            if (c != 0 && c < 0x20 && c > 0x7F) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static String toString(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('"');
+        for (byte b : bytes) {
+            if (b == 0) {
+                sb.append("\\0");
+            } else if (b == '"') {
+                sb.append("\\\"");
+            } else if (b == '\n') {
+                sb.append("\\n");
+            } else {
+                sb.append((char) b);
+            }
+        }
+        sb.append('"');
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRValueUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRValueUtil.java
new file mode 100644
index 0000000..f0f9e6e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRValueUtil.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public final class LIRValueUtil {
+
+    public static boolean isVariable(Value value) {
+        assert value != null;
+        return value instanceof Variable;
+    }
+
+    public static Variable asVariable(Value value) {
+        assert value != null;
+        return (Variable) value;
+    }
+
+    public static boolean isConstantValue(Value value) {
+        assert value != null;
+        return value instanceof ConstantValue;
+    }
+
+    public static ConstantValue asConstantValue(Value value) {
+        assert value != null;
+        return (ConstantValue) value;
+    }
+
+    public static Constant asConstant(Value value) {
+        return asConstantValue(value).getConstant();
+    }
+
+    public static boolean isJavaConstant(Value value) {
+        return isConstantValue(value) && asConstantValue(value).isJavaConstant();
+    }
+
+    public static JavaConstant asJavaConstant(Value value) {
+        return asConstantValue(value).getJavaConstant();
+    }
+
+    public static boolean isStackSlotValue(Value value) {
+        assert value != null;
+        return value instanceof StackSlot || value instanceof VirtualStackSlot;
+    }
+
+    public static boolean isVirtualStackSlot(Value value) {
+        assert value != null;
+        return value instanceof VirtualStackSlot;
+    }
+
+    public static VirtualStackSlot asVirtualStackSlot(Value value) {
+        assert value != null;
+        return (VirtualStackSlot) value;
+    }
+
+    public static boolean sameRegister(Value v1, Value v2) {
+        return isRegister(v1) && isRegister(v2) && asRegister(v1).equals(asRegister(v2));
+    }
+
+    public static boolean sameRegister(Value v1, Value v2, Value v3) {
+        return sameRegister(v1, v2) && sameRegister(v1, v3);
+    }
+
+    /**
+     * Checks if all the provided values are different physical registers. The parameters can be
+     * either {@link Register registers}, {@link Value values} or arrays of them. All values that
+     * are not {@link RegisterValue registers} are ignored.
+     */
+    public static boolean differentRegisters(Object... values) {
+        List<Register> registers = collectRegisters(values, new ArrayList<Register>());
+        for (int i = 1; i < registers.size(); i++) {
+            Register r1 = registers.get(i);
+            for (int j = 0; j < i; j++) {
+                Register r2 = registers.get(j);
+                if (r1.equals(r2)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private static List<Register> collectRegisters(Object[] values, List<Register> registers) {
+        for (Object o : values) {
+            if (o instanceof Register) {
+                registers.add((Register) o);
+            } else if (o instanceof Value) {
+                if (isRegister((Value) o)) {
+                    registers.add(asRegister((Value) o));
+                }
+            } else if (o instanceof Object[]) {
+                collectRegisters((Object[]) o, registers);
+            } else {
+                throw new IllegalArgumentException("Not a Register or Value: " + o);
+            }
+        }
+        return registers;
+    }
+
+    /**
+     * Subtract sets of registers (x - y).
+     *
+     * @param x a set of register to subtract from.
+     * @param y a set of registers to subtract.
+     * @return resulting set of registers (x - y).
+     */
+    public static Value[] subtractRegisters(Value[] x, Value[] y) {
+        ArrayList<Value> result = new ArrayList<>(x.length);
+        for (Value i : x) {
+            boolean append = true;
+            for (Value j : y) {
+                if (sameRegister(i, j)) {
+                    append = false;
+                    break;
+                }
+            }
+            if (append) {
+                result.add(i);
+            }
+        }
+        Value[] resultArray = new Value[result.size()];
+        return result.toArray(resultArray);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRVerifier.java
new file mode 100644
index 0000000..47c4a5d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRVerifier.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+public final class LIRVerifier {
+
+    private final LIR lir;
+    private final FrameMap frameMap;
+
+    private final boolean beforeRegisterAllocation;
+
+    private final BitSet[] blockLiveOut;
+    private final Object[] variableDefinitions;
+
+    private BitSet liveOutFor(AbstractBlockBase<?> block) {
+        return blockLiveOut[block.getId()];
+    }
+
+    private void setLiveOutFor(AbstractBlockBase<?> block, BitSet liveOut) {
+        blockLiveOut[block.getId()] = liveOut;
+    }
+
+    private int maxRegisterNum() {
+        return frameMap.getTarget().arch.getRegisters().size();
+    }
+
+    private boolean isAllocatableRegister(Value value) {
+        return isRegister(value) && frameMap.getRegisterConfig().getAttributesMap()[asRegister(value).number].isAllocatable();
+    }
+
+    public static boolean verify(final LIRInstruction op) {
+
+        op.visitEachInput(LIRVerifier::allowed);
+        op.visitEachAlive(LIRVerifier::allowed);
+        op.visitEachState(LIRVerifier::allowed);
+        op.visitEachTemp(LIRVerifier::allowed);
+        op.visitEachOutput(LIRVerifier::allowed);
+
+        op.verify();
+        return true;
+    }
+
+    public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
+        LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap);
+        verifier.verify();
+        return true;
+    }
+
+    private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
+        this.beforeRegisterAllocation = beforeRegisterAllocation;
+        this.lir = lir;
+        this.frameMap = frameMap;
+        this.blockLiveOut = new BitSet[lir.linearScanOrder().length];
+        this.variableDefinitions = new Object[lir.numVariables()];
+    }
+
+    private BitSet curVariablesLive;
+    private Value[] curRegistersLive;
+
+    private AbstractBlockBase<?> curBlock;
+    private Object curInstruction;
+    private BitSet curRegistersDefined;
+
+    private void verify() {
+        ValueConsumer useConsumer = new ValueConsumer() {
+
+            @Override
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                use(value, mode, flags);
+            }
+        };
+        ValueConsumer defConsumer = new ValueConsumer() {
+
+            @Override
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                def(value, mode, flags);
+            }
+        };
+
+        int maxRegisterNum = maxRegisterNum();
+        curRegistersDefined = new BitSet();
+        for (AbstractBlockBase<?> block : lir.linearScanOrder()) {
+            curBlock = block;
+            curVariablesLive = new BitSet();
+            curRegistersLive = new Value[maxRegisterNum];
+
+            if (block.getDominator() != null) {
+                curVariablesLive.or(liveOutFor(block.getDominator()));
+            }
+
+            assert lir.getLIRforBlock(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
+
+            if (block.getSuccessorCount() > 0) {
+                LIRInstruction last = lir.getLIRforBlock(block).get(lir.getLIRforBlock(block).size() - 1);
+                assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
+            }
+            if (block.getPredecessorCount() > 1) {
+                SSAUtil.verifyPhi(lir, block);
+            }
+
+            for (LIRInstruction op : lir.getLIRforBlock(block)) {
+                curInstruction = op;
+
+                op.visitEachInput(useConsumer);
+                if (op.destroysCallerSavedRegisters()) {
+                    for (Register register : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                        curRegistersLive[register.number] = null;
+                    }
+                }
+                curRegistersDefined.clear();
+                op.visitEachAlive(useConsumer);
+                op.visitEachState(useConsumer);
+                op.visitEachTemp(defConsumer);
+                op.visitEachOutput(defConsumer);
+
+                curInstruction = null;
+            }
+
+            setLiveOutFor(block, curVariablesLive);
+        }
+    }
+
+    private void use(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        allowed(curInstruction, value, mode, flags);
+
+        if (isVariable(value)) {
+            assert beforeRegisterAllocation;
+
+            int variableIdx = asVariable(value).index;
+            if (!curVariablesLive.get(variableIdx)) {
+                TTY.println("block %s  instruction %s", curBlock, curInstruction);
+                TTY.println("live variables: %s", curVariablesLive);
+                if (variableDefinitions[variableIdx] != null) {
+                    TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
+                }
+                TTY.println("ERROR: Use of variable %s that is not defined in dominator", value);
+                throw GraalError.shouldNotReachHere();
+            }
+
+        } else if (isAllocatableRegister(value)) {
+            int regNum = asRegister(value).number;
+            if (mode == OperandMode.ALIVE) {
+                curRegistersDefined.set(regNum);
+            }
+
+            if (beforeRegisterAllocation && !curRegistersLive[regNum].equals(value)) {
+                TTY.println("block %s  instruction %s", curBlock, curInstruction);
+                TTY.println("live registers: %s", Arrays.toString(curRegistersLive));
+                TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value);
+                throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    private void def(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        allowed(curInstruction, value, mode, flags);
+
+        if (isVariable(value)) {
+            assert beforeRegisterAllocation;
+
+            int variableIdx = asVariable(value).index;
+            if (variableDefinitions[variableIdx] != null) {
+                TTY.println("block %s  instruction %s", curBlock, curInstruction);
+                TTY.println("live variables: %s", curVariablesLive);
+                TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
+                TTY.println("ERROR: Variable %s defined multiple times", value);
+                throw GraalError.shouldNotReachHere();
+            }
+            assert curInstruction != null;
+            variableDefinitions[variableIdx] = curInstruction;
+            assert !curVariablesLive.get(variableIdx);
+            if (mode == OperandMode.DEF) {
+                curVariablesLive.set(variableIdx);
+            }
+
+        } else if (isAllocatableRegister(value)) {
+            int regNum = asRegister(value).number;
+            if (curRegistersDefined.get(regNum)) {
+                TTY.println("block %s  instruction %s", curBlock, curInstruction);
+                TTY.println("ERROR: Same register defined twice in the same instruction: %s", value);
+                throw GraalError.shouldNotReachHere();
+            }
+            curRegistersDefined.set(regNum);
+
+            if (beforeRegisterAllocation) {
+                if (mode == OperandMode.DEF) {
+                    curRegistersLive[regNum] = value;
+                } else {
+                    curRegistersLive[regNum] = null;
+                }
+            }
+        }
+    }
+
+    // @formatter:off
+    private static void allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if ((isVariable(value) && flags.contains(OperandFlag.REG)) ||
+            (isRegister(value) && flags.contains(OperandFlag.REG)) ||
+            (isStackSlotValue(value) && flags.contains(OperandFlag.STACK)) ||
+            (isJavaConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
+            (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
+            return;
+        }
+        throw new GraalError("Invalid LIR%n  Instruction: %s%n  Mode: %s%n  Flags: %s%n  Unexpected value: %s %s",
+                        op, mode, flags, value.getClass().getSimpleName(), value);
+    }
+    // @formatter:on
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LabelRef.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LabelRef.java
new file mode 100644
index 0000000..49ba71c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LabelRef.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.StandardOp.BranchOp;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+
+/**
+ * LIR instructions such as {@link JumpOp} and {@link BranchOp} need to reference their target
+ * {@link AbstractBlockBase}. However, direct references are not possible since the control flow
+ * graph (and therefore successors lists) can be changed by optimizations - and fixing the
+ * instructions is error prone. Therefore, we represent an edge to block B from block A via the
+ * tuple {@code (A,
+ * successor-index-of-B)}. That is, indirectly by storing the index into the successor list of A.
+ * Note therefore that the successor list cannot be re-ordered.
+ */
+public final class LabelRef {
+
+    private final LIR lir;
+    private final AbstractBlockBase<?> block;
+    private final int suxIndex;
+
+    /**
+     * Returns a new reference to a successor of the given block.
+     *
+     * @param block The base block that contains the successor list.
+     * @param suxIndex The index of the successor.
+     * @return The newly created label reference.
+     */
+    public static LabelRef forSuccessor(final LIR lir, final AbstractBlockBase<?> block, final int suxIndex) {
+        return new LabelRef(lir, block, suxIndex);
+    }
+
+    /**
+     * Returns a new reference to a successor of the given block.
+     *
+     * @param block The base block that contains the successor list.
+     * @param suxIndex The index of the successor.
+     */
+    private LabelRef(final LIR lir, final AbstractBlockBase<?> block, final int suxIndex) {
+        this.lir = lir;
+        this.block = block;
+        this.suxIndex = suxIndex;
+    }
+
+    public AbstractBlockBase<?> getSourceBlock() {
+        return block;
+    }
+
+    public AbstractBlockBase<?> getTargetBlock() {
+        return block.getSuccessors()[suxIndex];
+    }
+
+    public Label label() {
+        return ((StandardOp.LabelOp) lir.getLIRforBlock(getTargetBlock()).get(0)).getLabel();
+    }
+
+    @Override
+    public String toString() {
+        return getSourceBlock() + " -> " + (suxIndex < block.getSuccessors().length ? getTargetBlock() : "?");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/NullCheckOptimizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/NullCheckOptimizer.java
new file mode 100644
index 0000000..7bc19ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/NullCheckOptimizer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
+import org.graalvm.compiler.lir.StandardOp.NullCheck;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class NullCheckOptimizer extends PostAllocationOptimizationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        LIR ir = lirGenRes.getLIR();
+        AbstractBlockBase<?>[] blocks = ir.codeEmittingOrder();
+        NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
+    }
+
+    private static void foldNullChecks(LIR ir, AbstractBlockBase<?>[] blocks, int implicitNullCheckLimit) {
+        for (AbstractBlockBase<?> block : blocks) {
+            if (block == null) {
+                continue;
+            }
+            List<LIRInstruction> list = ir.getLIRforBlock(block);
+
+            if (!list.isEmpty()) {
+
+                LIRInstruction lastInstruction = list.get(0);
+                for (int i = 0; i < list.size(); i++) {
+                    LIRInstruction instruction = list.get(i);
+
+                    if (instruction instanceof ImplicitNullCheck && lastInstruction instanceof NullCheck) {
+                        NullCheck nullCheck = (NullCheck) lastInstruction;
+                        ImplicitNullCheck implicitNullCheck = (ImplicitNullCheck) instruction;
+                        if (implicitNullCheck.makeNullCheckFor(nullCheck.getCheckedValue(), nullCheck.getState(), implicitNullCheckLimit)) {
+                            list.remove(i - 1);
+                            if (i < list.size()) {
+                                instruction = list.get(i);
+                            }
+                        }
+                    }
+                    lastInstruction = instruction;
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Opcode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Opcode.java
new file mode 100644
index 0000000..ac28193
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Opcode.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes an opcode name for an annotated {@link LIRInstruction}.
+ * <p>
+ * Note: Unlike the other LIR related annotations declared as inner classes of
+ * {@link LIRInstruction}, this annotation is in a top level file to work around a
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=409824">bug</a> in Eclipse causing
+ * spurious warnings about unused imports.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.FIELD})
+public @interface Opcode {
+
+    String value() default "";
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java
new file mode 100644
index 0000000..54938ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Removes move instructions, where the destination value is already in place.
+ */
+public final class RedundantMoveElimination extends PostAllocationOptimizationPhase {
+
+    private static final DebugCounter deletedMoves = Debug.counter("RedundantMovesEliminated");
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        Optimization redundantMoveElimination = new Optimization(lirGenRes.getFrameMap());
+        redundantMoveElimination.doOptimize(lirGenRes.getLIR());
+    }
+
+    /**
+     * Holds the entry and exit states for each block for dataflow analysis. The state is an array
+     * with an element for each relevant location (register or stack slot). Each element holds the
+     * global number of the location's definition. A location definition is simply an output of an
+     * instruction. Note that because instructions can have multiple outputs it is not possible to
+     * use the instruction id for value numbering. In addition, the result of merging at block
+     * entries (= phi values) get unique value numbers.
+     *
+     * The value numbers also contain information if it is an object kind value or not: if the
+     * number is negative it is an object kind value.
+     */
+    private static final class BlockData {
+
+        BlockData(int stateSize) {
+            entryState = new int[stateSize];
+            exitState = new int[stateSize];
+        }
+
+        /*
+         * The state at block entry for global dataflow analysis. It contains a global value number
+         * for each location to optimize.
+         */
+        int[] entryState;
+
+        /*
+         * The state at block exit for global dataflow analysis. It contains a global value number
+         * for each location to optimize.
+         */
+        int[] exitState;
+
+        /*
+         * The starting number for global value numbering in this block.
+         */
+        int entryValueNum;
+    }
+
+    private static final class Optimization {
+
+        Map<AbstractBlockBase<?>, BlockData> blockData = CollectionsFactory.newMap();
+
+        RegisterArray callerSaveRegs;
+
+        /**
+         * Contains the register number for registers which can be optimized and -1 for the others.
+         */
+        int[] eligibleRegs;
+
+        /**
+         * A map from the {@link StackSlot} {@link #getOffset offset} to an index into the state.
+         * StackSlots of different kinds that map to the same location will map to the same index.
+         */
+        Map<Integer, Integer> stackIndices = CollectionsFactory.newMap();
+
+        int numRegs;
+
+        private final FrameMap frameMap;
+
+        /*
+         * Pseudo value for a not yet assigned location.
+         */
+        static final int INIT_VALUE = 0;
+
+        Optimization(FrameMap frameMap) {
+            this.frameMap = frameMap;
+        }
+
+        /**
+         * The main method doing the elimination of redundant moves.
+         */
+        @SuppressWarnings("try")
+        private void doOptimize(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
+
+                callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters();
+
+                initBlockData(lir);
+
+                // Compute a table of the registers which are eligible for move optimization.
+                // Unallocatable registers should never be optimized.
+                eligibleRegs = new int[numRegs];
+                Arrays.fill(eligibleRegs, -1);
+                for (Register reg : frameMap.getRegisterConfig().getAllocatableRegisters()) {
+                    if (reg.number < numRegs) {
+                        eligibleRegs[reg.number] = reg.number;
+                    }
+                }
+
+                if (!solveDataFlow(lir)) {
+                    return;
+                }
+
+                eliminateMoves(lir);
+            }
+        }
+
+        /**
+         * The maximum number of locations * blocks. This is a complexity limit for the inner loop
+         * in {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}.
+         */
+        private static final int COMPLEXITY_LIMIT = 30000;
+
+        private void initBlockData(LIR lir) {
+
+            AbstractBlockBase<?>[] blocks = lir.linearScanOrder();
+            numRegs = 0;
+
+            int maxStackLocations = COMPLEXITY_LIMIT / blocks.length;
+
+            /*
+             * Search for relevant locations which can be optimized. These are register or stack
+             * slots which occur as destinations of move instructions.
+             */
+            for (AbstractBlockBase<?> block : blocks) {
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (LIRInstruction op : instructions) {
+                    if (isEligibleMove(op)) {
+                        Value dest = ((MoveOp) op).getResult();
+                        if (isRegister(dest)) {
+                            int regNum = ((RegisterValue) dest).getRegister().number;
+                            if (regNum >= numRegs) {
+                                numRegs = regNum + 1;
+                            }
+                        } else if (isStackSlot(dest)) {
+                            StackSlot stackSlot = (StackSlot) dest;
+                            Integer offset = getOffset(stackSlot);
+                            if (!stackIndices.containsKey(offset) && stackIndices.size() < maxStackLocations) {
+                                stackIndices.put(offset, stackIndices.size());
+                            }
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Now we know the number of locations to optimize, so we can allocate the block states.
+             */
+            int numLocations = numRegs + stackIndices.size();
+            Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
+            for (AbstractBlockBase<?> block : blocks) {
+                BlockData data = new BlockData(numLocations);
+                blockData.put(block, data);
+            }
+        }
+
+        private int getOffset(StackSlot stackSlot) {
+            return stackSlot.getOffset(frameMap.totalFrameSize());
+        }
+
+        /**
+         * Calculates the entry and exit states for all basic blocks.
+         *
+         * @return Returns true on success and false if the the control flow is too complex.
+         */
+        @SuppressWarnings("try")
+        private boolean solveDataFlow(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("solve data flow")) {
+
+                AbstractBlockBase<?>[] blocks = lir.linearScanOrder();
+
+                int numIter = 0;
+
+                /*
+                 * Iterate until there are no more changes.
+                 */
+                int currentValueNum = 1;
+                boolean firstRound = true;
+                boolean changed;
+                do {
+                    changed = false;
+                    try (Indent indent2 = Debug.logAndIndent("new iteration")) {
+
+                        for (AbstractBlockBase<?> block : blocks) {
+
+                            BlockData data = blockData.get(block);
+                            /*
+                             * Initialize the number for global value numbering for this block. It
+                             * is essential that the starting number for a block is consistent at
+                             * all iterations and also in eliminateMoves().
+                             */
+                            if (firstRound) {
+                                data.entryValueNum = currentValueNum;
+                            }
+                            int valueNum = data.entryValueNum;
+                            assert valueNum > 0;
+                            boolean newState = false;
+
+                            if (block == blocks[0] || block.isExceptionEntry()) {
+                                /*
+                                 * The entry block has undefined values. And also exception handler
+                                 * blocks: the LinearScan can insert moves at the end of an
+                                 * exception handler predecessor block (after the invoke, which
+                                 * throws the exception), and in reality such moves are not in the
+                                 * control flow in case of an exception. So we assume a save default
+                                 * for exception handler blocks.
+                                 */
+                                Debug.log("kill all values at entry of block %d", block.getId());
+                                clearValues(data.entryState, valueNum);
+                            } else {
+                                /*
+                                 * Merge the states of predecessor blocks
+                                 */
+                                for (AbstractBlockBase<?> predecessor : block.getPredecessors()) {
+                                    BlockData predData = blockData.get(predecessor);
+                                    newState |= mergeState(data.entryState, predData.exitState, valueNum);
+                                }
+                            }
+                            // Advance by the value numbers which are "consumed" by
+                            // clearValues and mergeState
+                            valueNum += data.entryState.length;
+
+                            if (newState || firstRound) {
+                                try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
+
+                                    /*
+                                     * Derive the exit state from the entry state by iterating
+                                     * through all instructions of the block.
+                                     */
+                                    int[] iterState = data.exitState;
+                                    copyState(iterState, data.entryState);
+                                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                                    for (LIRInstruction op : instructions) {
+                                        valueNum = updateState(iterState, op, valueNum);
+                                    }
+                                    changed = true;
+                                }
+                            }
+                            if (firstRound) {
+                                currentValueNum = valueNum;
+                            }
+                        }
+                        firstRound = false;
+                    }
+                    numIter++;
+
+                    if (numIter > 5) {
+                        /*
+                         * This is _very_ seldom.
+                         */
+                        return false;
+                    }
+
+                } while (changed);
+
+            }
+
+            return true;
+        }
+
+        /**
+         * Deletes all move instructions where the target location already contains the source
+         * value.
+         */
+        @SuppressWarnings("try")
+        private void eliminateMoves(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("eliminate moves")) {
+
+                AbstractBlockBase<?>[] blocks = lir.linearScanOrder();
+
+                for (AbstractBlockBase<?> block : blocks) {
+
+                    try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
+
+                        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                        BlockData data = blockData.get(block);
+                        boolean hasDead = false;
+
+                        // Reuse the entry state for iteration, we don't need it later.
+                        int[] iterState = data.entryState;
+
+                        // Add the values which are "consumed" by clearValues and
+                        // mergeState in solveDataFlow
+                        int valueNum = data.entryValueNum + data.entryState.length;
+
+                        int numInsts = instructions.size();
+                        for (int idx = 0; idx < numInsts; idx++) {
+                            LIRInstruction op = instructions.get(idx);
+                            if (isEligibleMove(op)) {
+                                ValueMoveOp moveOp = (ValueMoveOp) op;
+                                int sourceIdx = getStateIdx(moveOp.getInput());
+                                int destIdx = getStateIdx(moveOp.getResult());
+                                if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
+                                    assert iterState[sourceIdx] != INIT_VALUE;
+                                    Debug.log("delete move %s", op);
+                                    instructions.set(idx, null);
+                                    hasDead = true;
+                                    if (deletedMoves.isEnabled()) {
+                                        deletedMoves.increment();
+                                    }
+                                }
+                            }
+                            // It doesn't harm if updateState is also called for a deleted move
+                            valueNum = updateState(iterState, op, valueNum);
+                        }
+                        if (hasDead) {
+                            instructions.removeAll(Collections.singleton(null));
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Updates the state for one instruction.
+         */
+        @SuppressWarnings("try")
+        private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
+
+            try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
+                if (isEligibleMove(op)) {
+                    /*
+                     * Handle the special case of a move instruction
+                     */
+                    ValueMoveOp moveOp = (ValueMoveOp) op;
+                    int sourceIdx = getStateIdx(moveOp.getInput());
+                    int destIdx = getStateIdx(moveOp.getResult());
+                    if (sourceIdx >= 0 && destIdx >= 0) {
+                        assert isObjectValue(state[sourceIdx]) || LIRKind.isValue(moveOp.getInput()) : "move op moves object but input is not defined as object";
+                        state[destIdx] = state[sourceIdx];
+                        Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
+                        return initValueNum;
+                    }
+                }
+
+                int valueNum = initValueNum;
+
+                if (op.destroysCallerSavedRegisters()) {
+                    Debug.log("kill all caller save regs");
+
+                    for (Register reg : callerSaveRegs) {
+                        if (reg.number < numRegs) {
+                            // Kind.Object is the save default
+                            state[reg.number] = encodeValueNum(valueNum++, true);
+                        }
+                    }
+                }
+
+                /*
+                 * Value procedure for the instruction's output and temp values
+                 */
+                class OutputValueConsumer implements ValueConsumer {
+
+                    int opValueNum;
+
+                    OutputValueConsumer(int opValueNum) {
+                        this.opValueNum = opValueNum;
+                    }
+
+                    @Override
+                    public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        int stateIdx = getStateIdx(operand);
+                        if (stateIdx >= 0) {
+                            /*
+                             * Assign a unique number to the output or temp location.
+                             */
+                            state[stateIdx] = encodeValueNum(opValueNum++, !LIRKind.isValue(operand));
+                            Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
+                        }
+                    }
+                }
+
+                OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
+
+                op.visitEachTemp(outputValueConsumer);
+                /*
+                 * Semantically the output values are written _after_ the temp values
+                 */
+                op.visitEachOutput(outputValueConsumer);
+
+                valueNum = outputValueConsumer.opValueNum;
+
+                if (op.hasState()) {
+                    /*
+                     * All instructions with framestates (mostly method calls), may do garbage
+                     * collection. GC will rewrite all object references which are live at this
+                     * point. So we can't rely on their values. It would be sufficient to just kill
+                     * all values which are referenced in the state (or all values which are not),
+                     * but for simplicity we kill all values.
+                     */
+                    Debug.log("kill all object values");
+                    clearValuesOfKindObject(state, valueNum);
+                    valueNum += state.length;
+                }
+
+                return valueNum;
+            }
+        }
+
+        /**
+         * The state merge function for dataflow joins.
+         */
+        private static boolean mergeState(int[] dest, int[] source, int defNum) {
+            assert dest.length == source.length;
+            boolean changed = false;
+            for (int idx = 0; idx < source.length; idx++) {
+                int phiNum = defNum + idx;
+                int dst = dest[idx];
+                int src = source[idx];
+                if (dst != src && src != INIT_VALUE && dst != encodeValueNum(phiNum, isObjectValue(dst))) {
+                    if (dst != INIT_VALUE) {
+                        dst = encodeValueNum(phiNum, isObjectValue(dst) || isObjectValue(src));
+                    } else {
+                        dst = src;
+                    }
+                    dest[idx] = dst;
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        private static void copyState(int[] dest, int[] source) {
+            assert dest.length == source.length;
+            for (int idx = 0; idx < source.length; idx++) {
+                dest[idx] = source[idx];
+            }
+        }
+
+        private static void clearValues(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                // Let the killed values assume to be object references: it's the save default.
+                state[idx] = encodeValueNum(phiNum, true);
+            }
+        }
+
+        private static void clearValuesOfKindObject(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                if (isObjectValue(state[idx])) {
+                    state[idx] = encodeValueNum(phiNum, true);
+                }
+            }
+        }
+
+        /**
+         * Returns the index to the state arrays in BlockData for a specific location.
+         */
+        private int getStateIdx(Value location) {
+            if (isRegister(location)) {
+                int regNum = ((RegisterValue) location).getRegister().number;
+                if (regNum < numRegs) {
+                    return eligibleRegs[regNum];
+                }
+                return -1;
+            }
+            if (isStackSlot(location)) {
+                StackSlot slot = (StackSlot) location;
+                Integer index = stackIndices.get(getOffset(slot));
+                if (index != null) {
+                    return index.intValue() + numRegs;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Encodes a value number + the is-object information to a number to be stored in a state.
+         */
+        private static int encodeValueNum(int valueNum, boolean isObjectKind) {
+            assert valueNum > 0;
+            if (isObjectKind) {
+                return -valueNum;
+            }
+            return valueNum;
+        }
+
+        /**
+         * Returns true if an encoded value number (which is stored in a state) refers to an object
+         * reference.
+         */
+        private static boolean isObjectValue(int encodedValueNum) {
+            return encodedValueNum < 0;
+        }
+
+        /**
+         * Returns true for a move instruction which is a candidate for elimination.
+         */
+        private static boolean isEligibleMove(LIRInstruction op) {
+            if (op instanceof ValueMoveOp) {
+                ValueMoveOp moveOp = (ValueMoveOp) op;
+                Value source = moveOp.getInput();
+                Value dest = moveOp.getResult();
+                /*
+                 * Moves with mismatching kinds are not moves, but memory loads/stores!
+                 */
+                return source.getValueKind().equals(dest.getValueKind());
+            }
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java
new file mode 100644
index 0000000..ff7ae69
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A collection of machine-independent LIR operations, as well as interfaces to be implemented for
+ * specific kinds or LIR operations.
+ */
+public class StandardOp {
+
+    /**
+     * A block delimiter. Every well formed block must contain exactly one such operation and it
+     * must be the last operation in the block.
+     */
+    public interface BlockEndOp {
+        void setOutgoingValues(Value[] values);
+
+        int getOutgoingSize();
+
+        Value getOutgoingValue(int idx);
+
+        int addOutgoingValues(Value[] values);
+
+        void clearOutgoingValues();
+
+        void forEachOutgoingValue(InstructionValueProcedure proc);
+
+        /**
+         * The number of {@link SSAUtil phi} operands in the {@link #getOutgoingValue outgoing}
+         * array.
+         */
+        int getPhiSize();
+    }
+
+    public interface NullCheck {
+        Value getCheckedValue();
+
+        LIRFrameState getState();
+    }
+
+    public interface ImplicitNullCheck {
+        boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit);
+    }
+
+    /**
+     * LIR operation that defines the position of a label.
+     */
+    public static final class LabelOp extends LIRInstruction {
+        public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class);
+        public static final EnumSet<OperandFlag> incomingFlags = EnumSet.of(REG, STACK);
+
+        /**
+         * In the LIR, every register and variable must be defined before it is used. For method
+         * parameters that are passed in fixed registers, exception objects passed to the exception
+         * handler in a fixed register, or any other use of a fixed register not defined in this
+         * method, an artificial definition is necessary. To avoid spill moves to be inserted
+         * between the label at the beginning of a block an an actual definition in the second
+         * instruction of a block, the registers are defined here in the label.
+         */
+        @Def({REG, STACK}) private Value[] incomingValues;
+        private final Label label;
+        private final boolean align;
+        private int numbPhis;
+
+        public LabelOp(Label label, boolean align) {
+            super(TYPE);
+            this.label = label;
+            this.align = align;
+            this.incomingValues = Value.NO_VALUES;
+            this.numbPhis = 0;
+        }
+
+        public void setPhiValues(Value[] values) {
+            setIncomingValues(values);
+            setNumberOfPhis(values.length);
+        }
+
+        private void setNumberOfPhis(int numPhis) {
+            assert numbPhis == 0;
+            numbPhis = numPhis;
+        }
+
+        /**
+         * @see BlockEndOp#getPhiSize
+         */
+        public int getPhiSize() {
+            return numbPhis;
+        }
+
+        public void setIncomingValues(Value[] values) {
+            assert this.incomingValues.length == 0;
+            assert values != null;
+            this.incomingValues = values;
+        }
+
+        public int getIncomingSize() {
+            return incomingValues.length;
+        }
+
+        public Value getIncomingValue(int idx) {
+            assert checkRange(idx);
+            return incomingValues[idx];
+        }
+
+        public void clearIncomingValues() {
+            incomingValues = Value.NO_VALUES;
+        }
+
+        public void addIncomingValues(Value[] values) {
+            if (incomingValues.length == 0) {
+                setIncomingValues(values);
+                return;
+            }
+            int t = incomingValues.length + values.length;
+            Value[] newArray = new Value[t];
+            System.arraycopy(incomingValues, 0, newArray, 0, incomingValues.length);
+            System.arraycopy(values, 0, newArray, incomingValues.length, values.length);
+            incomingValues = newArray;
+        }
+
+        private boolean checkRange(int idx) {
+            return idx < incomingValues.length;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            if (align) {
+                crb.asm.align(crb.target.wordSize * 2);
+            }
+            crb.asm.bind(label);
+        }
+
+        public Label getLabel() {
+            return label;
+        }
+
+        /**
+         * @return true if this label acts as a PhiIn.
+         */
+        public boolean isPhiIn() {
+            return getPhiSize() > 0;
+        }
+
+        public void forEachIncomingValue(InstructionValueProcedure proc) {
+            for (int i = 0; i < incomingValues.length; i++) {
+                incomingValues[i] = proc.doValue(this, incomingValues[i], OperandMode.DEF, incomingFlags);
+            }
+        }
+    }
+
+    public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<AbstractBlockEndOp> TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class);
+        public static final EnumSet<OperandFlag> outgoingFlags = EnumSet.of(REG, STACK, CONST, OUTGOING);
+
+        @Alive({REG, STACK, CONST, OUTGOING}) private Value[] outgoingValues;
+        private int numberOfPhis;
+
+        protected AbstractBlockEndOp(LIRInstructionClass<? extends AbstractBlockEndOp> c) {
+            super(c);
+            this.outgoingValues = Value.NO_VALUES;
+        }
+
+        public void setPhiValues(Value[] values) {
+            setOutgoingValues(values);
+            setNumberOfPhis(values.length);
+        }
+
+        private void setNumberOfPhis(int numPhis) {
+            assert numberOfPhis == 0;
+            numberOfPhis = numPhis;
+        }
+
+        @Override
+        public int getPhiSize() {
+            return numberOfPhis;
+        }
+
+        @Override
+        public void setOutgoingValues(Value[] values) {
+            assert this.outgoingValues.length == 0;
+            assert values != null;
+            this.outgoingValues = values;
+        }
+
+        @Override
+        public int getOutgoingSize() {
+            return outgoingValues.length;
+        }
+
+        @Override
+        public Value getOutgoingValue(int idx) {
+            assert checkRange(idx);
+            return outgoingValues[idx];
+        }
+
+        @Override
+        public void clearOutgoingValues() {
+            outgoingValues = Value.NO_VALUES;
+        }
+
+        @Override
+        public int addOutgoingValues(Value[] values) {
+            if (outgoingValues.length == 0) {
+                setOutgoingValues(values);
+                return values.length;
+            }
+            int t = outgoingValues.length + values.length;
+            Value[] newArray = new Value[t];
+            System.arraycopy(outgoingValues, 0, newArray, 0, outgoingValues.length);
+            System.arraycopy(values, 0, newArray, outgoingValues.length, values.length);
+            outgoingValues = newArray;
+            return t;
+        }
+
+        private boolean checkRange(int idx) {
+            return idx < outgoingValues.length;
+        }
+
+        @Override
+        public void forEachOutgoingValue(InstructionValueProcedure proc) {
+            for (int i = 0; i < outgoingValues.length; i++) {
+                outgoingValues[i] = proc.doValue(this, outgoingValues[i], OperandMode.ALIVE, outgoingFlags);
+            }
+        }
+    }
+
+    /**
+     * LIR operation that is an unconditional jump to a {@link #destination()}.
+     */
+    public static class JumpOp extends AbstractBlockEndOp {
+        public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class);
+
+        private final LabelRef destination;
+
+        public JumpOp(LabelRef destination) {
+            this(TYPE, destination);
+        }
+
+        protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) {
+            super(c);
+            this.destination = destination;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            if (!crb.isSuccessorEdge(destination)) {
+                crb.asm.jmp(destination.label());
+            }
+        }
+
+        public LabelRef destination() {
+            return destination;
+        }
+    }
+
+    /**
+     * Marker interface for a LIR operation that is a conditional jump.
+     */
+    public interface BranchOp extends BlockEndOp {
+    }
+
+    /**
+     * Marker interface for a LIR operation that moves a value to {@link #getResult()}.
+     */
+    public interface MoveOp {
+
+        AllocatableValue getResult();
+    }
+
+    /**
+     * Marker interface for a LIR operation that moves some non-constant value to another location.
+     */
+    public interface ValueMoveOp extends MoveOp {
+
+        AllocatableValue getInput();
+    }
+
+    /**
+     * Marker interface for a LIR operation that loads a {@link #getConstant()}.
+     */
+    public interface LoadConstantOp extends MoveOp {
+
+        Constant getConstant();
+    }
+
+    /**
+     * An operation that saves registers to the stack. The set of saved registers can be
+     * {@linkplain #remove(Set) pruned} and a mapping from registers to the frame slots in which
+     * they are saved can be {@linkplain #getMap(FrameMap) retrieved}.
+     */
+    public interface SaveRegistersOp {
+
+        /**
+         * Determines if the {@link #remove(Set)} operation is supported for this object.
+         */
+        boolean supportsRemove();
+
+        /**
+         * Prunes {@code doNotSave} from the registers saved by this operation.
+         *
+         * @param doNotSave registers that should not be saved by this operation
+         * @return the number of registers pruned
+         * @throws UnsupportedOperationException if removal is not {@linkplain #supportsRemove()
+         *             supported}
+         */
+        int remove(Set<Register> doNotSave);
+
+        /**
+         * Gets a map from the saved registers saved by this operation to the frame slots in which
+         * they are saved.
+         *
+         * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a
+         *            virtual slot to a frame slot index
+         */
+        RegisterSaveLayout getMap(FrameMap frameMap);
+
+    }
+
+    /**
+     * A LIR operation that does nothing. If the operation records its position, it can be
+     * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}.
+     */
+    public static final class NoOp extends LIRInstruction {
+        public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class);
+
+        /**
+         * The block in which this instruction is located.
+         */
+        final AbstractBlockBase<?> block;
+
+        /**
+         * The block index of this instruction.
+         */
+        final int index;
+
+        public NoOp(AbstractBlockBase<?> block, int index) {
+            super(TYPE);
+            this.block = block;
+            this.index = index;
+        }
+
+        public void replace(LIR lir, LIRInstruction replacement) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this);
+            instructions.set(index, replacement);
+        }
+
+        public void remove(LIR lir) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.get(index).equals(this) : String.format("Removing the wrong instruction: %s instead of %s", instructions.get(index), this);
+            instructions.remove(index);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            if (block != null) {
+                throw new GraalError(this + " should have been replaced");
+            }
+        }
+    }
+
+    @Opcode("BLACKHOLE")
+    public static final class BlackholeOp extends LIRInstruction {
+        public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class);
+
+        @Use({REG, STACK, CONST}) private Value value;
+
+        public BlackholeOp(Value value) {
+            super(TYPE);
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            // do nothing, just keep value alive until at least here
+        }
+    }
+
+    public static final class BindToRegisterOp extends LIRInstruction {
+        public static final LIRInstructionClass<BindToRegisterOp> TYPE = LIRInstructionClass.create(BindToRegisterOp.class);
+
+        @Use({REG}) private Value value;
+
+        public BindToRegisterOp(Value value) {
+            super(TYPE);
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            // do nothing, just keep value alive until at least here
+        }
+    }
+
+    @Opcode("SPILLREGISTERS")
+    public static final class SpillRegistersOp extends LIRInstruction {
+        public static final LIRInstructionClass<SpillRegistersOp> TYPE = LIRInstructionClass.create(SpillRegistersOp.class);
+
+        public SpillRegistersOp() {
+            super(TYPE);
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return true;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            // do nothing, just keep value alive until at least here
+        }
+    }
+
+    public static final class StackMove extends LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<StackMove> TYPE = LIRInstructionClass.create(StackMove.class);
+
+        @Def({STACK, HINT}) protected AllocatableValue result;
+        @Use({STACK}) protected AllocatableValue input;
+
+        public StackMove(AllocatableValue result, AllocatableValue input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            throw new GraalError(this + " should have been removed");
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StateProcedure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StateProcedure.java
new file mode 100644
index 0000000..d741762
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StateProcedure.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+@FunctionalInterface
+public interface StateProcedure extends InstructionStateProcedure {
+
+    void doState(LIRFrameState state);
+
+    @Override
+    default void doState(LIRInstruction instruction, LIRFrameState state) {
+        doState(state);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java
new file mode 100644
index 0000000..6a72bd2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * This class encapsulates different strategies on how to generate code for switch instructions.
+ *
+ * The {@link #getBestStrategy(double[], JavaConstant[], LabelRef[])} method can be used to get
+ * strategy with the smallest average effort (average number of comparisons until a decision is
+ * reached). The strategy returned by this method will have its averageEffort set, while a strategy
+ * constructed directly will not.
+ */
+public abstract class SwitchStrategy {
+
+    private interface SwitchClosure {
+        /**
+         * Generates a conditional or unconditional jump. The jump will be unconditional if
+         * condition is null. If defaultTarget is true, then the jump will go the the default.
+         *
+         * @param index Index of the value and the jump target (only used if defaultTarget == false)
+         * @param condition The condition on which to jump (can be null)
+         * @param defaultTarget true if the jump should go to the default target, false if index
+         *            should be used.
+         */
+        void conditionalJump(int index, Condition condition, boolean defaultTarget);
+
+        /**
+         * Generates a conditional jump to the target with the specified index. The fall through
+         * should go to the default target.
+         *
+         * @param index Index of the value and the jump target
+         * @param condition The condition on which to jump
+         * @param canFallThrough true if this is the last instruction in the switch statement, to
+         *            allow for fall-through optimizations.
+         */
+        void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough);
+
+        /**
+         * Create a new label and generate a conditional jump to it.
+         *
+         * @param index Index of the value and the jump target
+         * @param condition The condition on which to jump
+         * @return a new Label
+         */
+        Label conditionalJump(int index, Condition condition);
+
+        /**
+         * Binds a label returned by {@link #conditionalJump(int, Condition)}.
+         */
+        void bind(Label label);
+
+        /**
+         * Return true iff the target of both indexes is the same.
+         */
+        boolean isSameTarget(int index1, int index2);
+    }
+
+    /**
+     * Backends can subclass this abstract class and generate code for switch strategies by
+     * implementing the {@link #conditionalJump(int, Condition, Label)} method.
+     */
+    public abstract static class BaseSwitchClosure implements SwitchClosure {
+
+        private final CompilationResultBuilder crb;
+        private final Assembler masm;
+        private final LabelRef[] keyTargets;
+        private final LabelRef defaultTarget;
+
+        public BaseSwitchClosure(CompilationResultBuilder crb, Assembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) {
+            this.crb = crb;
+            this.masm = masm;
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+        }
+
+        /**
+         * This method generates code for a comparison between the actual value and the constant at
+         * the given index and a condition jump to target.
+         */
+        protected abstract void conditionalJump(int index, Condition condition, Label target);
+
+        @Override
+        public void conditionalJump(int index, Condition condition, boolean targetDefault) {
+            Label target = targetDefault ? defaultTarget.label() : keyTargets[index].label();
+            if (condition == null) {
+                masm.jmp(target);
+            } else {
+                conditionalJump(index, condition, target);
+            }
+        }
+
+        @Override
+        public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) {
+            if (canFallThrough && crb.isSuccessorEdge(defaultTarget)) {
+                conditionalJump(index, condition, keyTargets[index].label());
+            } else if (canFallThrough && crb.isSuccessorEdge(keyTargets[index])) {
+                conditionalJump(index, condition.negate(), defaultTarget.label());
+            } else {
+                conditionalJump(index, condition, keyTargets[index].label());
+                masm.jmp(defaultTarget.label());
+            }
+        }
+
+        @Override
+        public Label conditionalJump(int index, Condition condition) {
+            Label label = new Label();
+            conditionalJump(index, condition, label);
+            return label;
+        }
+
+        @Override
+        public void bind(Label label) {
+            masm.bind(label);
+        }
+
+        @Override
+        public boolean isSameTarget(int index1, int index2) {
+            return keyTargets[index1] == keyTargets[index2];
+        }
+
+    }
+
+    /**
+     * This closure is used internally to determine the average effort for a certain strategy on a
+     * given switch instruction.
+     */
+    private class EffortClosure implements SwitchClosure {
+
+        private int defaultEffort;
+        private int defaultCount;
+        private final int[] keyEfforts = new int[keyProbabilities.length];
+        private final int[] keyCounts = new int[keyProbabilities.length];
+        private final LabelRef[] keyTargets;
+
+        EffortClosure(LabelRef[] keyTargets) {
+            this.keyTargets = keyTargets;
+        }
+
+        @Override
+        public void conditionalJump(int index, Condition condition, boolean defaultTarget) {
+            // nothing to do
+        }
+
+        @Override
+        public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) {
+            // nothing to do
+        }
+
+        @Override
+        public Label conditionalJump(int index, Condition condition) {
+            // nothing to do
+            return null;
+        }
+
+        @Override
+        public void bind(Label label) {
+            // nothing to do
+        }
+
+        @Override
+        public boolean isSameTarget(int index1, int index2) {
+            return keyTargets[index1] == keyTargets[index2];
+        }
+
+        public double getAverageEffort() {
+            double defaultProbability = 1;
+            double effort = 0;
+            for (int i = 0; i < keyProbabilities.length; i++) {
+                effort += keyEfforts[i] * keyProbabilities[i] / keyCounts[i];
+                defaultProbability -= keyProbabilities[i];
+            }
+            return effort + defaultEffort * defaultProbability / defaultCount;
+        }
+    }
+
+    public final double[] keyProbabilities;
+    private double averageEffort = -1;
+    private EffortClosure effortClosure;
+
+    public SwitchStrategy(double[] keyProbabilities) {
+        assert keyProbabilities.length >= 2;
+        this.keyProbabilities = keyProbabilities;
+    }
+
+    public abstract Constant[] getKeyConstants();
+
+    public double getAverageEffort() {
+        assert averageEffort >= 0 : "average effort was not calculated yet for this strategy";
+        return averageEffort;
+    }
+
+    /**
+     * Tells the system that the given (inclusive) range of keys is reached after depth number of
+     * comparisons, which is used to calculate the average effort.
+     */
+    protected void registerEffort(int rangeStart, int rangeEnd, int depth) {
+        if (effortClosure != null) {
+            for (int i = rangeStart; i <= rangeEnd; i++) {
+                effortClosure.keyEfforts[i] += depth;
+                effortClosure.keyCounts[i]++;
+            }
+        }
+    }
+
+    /**
+     * Tells the system that the default successor is reached after depth number of comparisons,
+     * which is used to calculate average effort.
+     */
+    protected void registerDefaultEffort(int depth) {
+        if (effortClosure != null) {
+            effortClosure.defaultEffort += depth;
+            effortClosure.defaultCount++;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[avgEffort=" + averageEffort + "]";
+    }
+
+    /**
+     * This strategy orders the keys according to their probability and creates one equality
+     * comparison per key.
+     */
+    public static class SequentialStrategy extends SwitchStrategy {
+        private final Integer[] indexes;
+        private final Constant[] keyConstants;
+
+        public SequentialStrategy(final double[] keyProbabilities, Constant[] keyConstants) {
+            super(keyProbabilities);
+            assert keyProbabilities.length == keyConstants.length;
+
+            this.keyConstants = keyConstants;
+            int keyCount = keyConstants.length;
+            indexes = new Integer[keyCount];
+            for (int i = 0; i < keyCount; i++) {
+                indexes[i] = i;
+            }
+            Arrays.sort(indexes, new Comparator<Integer>() {
+                @Override
+                public int compare(Integer o1, Integer o2) {
+                    return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0;
+                }
+            });
+        }
+
+        @Override
+        public Constant[] getKeyConstants() {
+            return keyConstants;
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            for (int i = 0; i < keyConstants.length - 1; i++) {
+                closure.conditionalJump(indexes[i], Condition.EQ, false);
+                registerEffort(indexes[i], indexes[i], i + 1);
+            }
+            closure.conditionalJumpOrDefault(indexes[keyConstants.length - 1], Condition.EQ, true);
+            registerEffort(indexes[keyConstants.length - 1], indexes[keyConstants.length - 1], keyConstants.length);
+            registerDefaultEffort(keyConstants.length);
+        }
+    }
+
+    /**
+     * Base class for strategies that rely on primitive integer keys.
+     */
+    private abstract static class PrimitiveStrategy extends SwitchStrategy {
+        protected final JavaConstant[] keyConstants;
+
+        protected PrimitiveStrategy(double[] keyProbabilities, JavaConstant[] keyConstants) {
+            super(keyProbabilities);
+            assert keyProbabilities.length == keyConstants.length;
+            this.keyConstants = keyConstants;
+        }
+
+        @Override
+        public JavaConstant[] getKeyConstants() {
+            return keyConstants;
+        }
+
+        /**
+         * Looks for the end of a stretch of key constants that are successive numbers and have the
+         * same target.
+         */
+        protected int getSliceEnd(SwitchClosure closure, int pos) {
+            int slice = pos;
+            while (slice < (keyConstants.length - 1) && keyConstants[slice + 1].asLong() == keyConstants[slice].asLong() + 1 && closure.isSameTarget(slice, slice + 1)) {
+                slice++;
+            }
+            return slice;
+        }
+    }
+
+    /**
+     * This strategy divides the keys into ranges of successive keys with the same target and
+     * creates comparisons for these ranges.
+     */
+    public static class RangesStrategy extends PrimitiveStrategy {
+        private final Integer[] indexes;
+
+        public RangesStrategy(final double[] keyProbabilities, JavaConstant[] keyConstants) {
+            super(keyProbabilities, keyConstants);
+
+            int keyCount = keyConstants.length;
+            indexes = new Integer[keyCount];
+            for (int i = 0; i < keyCount; i++) {
+                indexes[i] = i;
+            }
+            Arrays.sort(indexes, new Comparator<Integer>() {
+                @Override
+                public int compare(Integer o1, Integer o2) {
+                    return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0;
+                }
+            });
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            int depth = 0;
+            closure.conditionalJump(0, Condition.LT, true);
+            registerDefaultEffort(++depth);
+            int rangeStart = 0;
+            int rangeEnd = getSliceEnd(closure, rangeStart);
+            while (rangeEnd != keyConstants.length - 1) {
+                if (rangeStart == rangeEnd) {
+                    closure.conditionalJump(rangeStart, Condition.EQ, false);
+                    registerEffort(rangeStart, rangeEnd, ++depth);
+                } else {
+                    if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) {
+                        closure.conditionalJump(rangeStart, Condition.LT, true);
+                        registerDefaultEffort(++depth);
+                    }
+                    closure.conditionalJump(rangeEnd, Condition.LE, false);
+                    registerEffort(rangeStart, rangeEnd, ++depth);
+                }
+                rangeStart = rangeEnd + 1;
+                rangeEnd = getSliceEnd(closure, rangeStart);
+            }
+            if (rangeStart == rangeEnd) {
+                closure.conditionalJumpOrDefault(rangeStart, Condition.EQ, true);
+                registerEffort(rangeStart, rangeEnd, ++depth);
+                registerDefaultEffort(depth);
+            } else {
+                if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) {
+                    closure.conditionalJump(rangeStart, Condition.LT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJumpOrDefault(rangeEnd, Condition.LE, true);
+                registerEffort(rangeStart, rangeEnd, ++depth);
+                registerDefaultEffort(depth);
+            }
+        }
+    }
+
+    /**
+     * This strategy recursively subdivides the list of keys to create a binary search based on
+     * probabilities.
+     */
+    public static class BinaryStrategy extends PrimitiveStrategy {
+
+        private static final double MIN_PROBABILITY = 0.00001;
+
+        private final double[] probabilitySums;
+
+        public BinaryStrategy(double[] keyProbabilities, JavaConstant[] keyConstants) {
+            super(keyProbabilities, keyConstants);
+            probabilitySums = new double[keyProbabilities.length + 1];
+            double sum = 0;
+            for (int i = 0; i < keyConstants.length; i++) {
+                sum += Math.max(keyProbabilities[i], MIN_PROBABILITY);
+                probabilitySums[i + 1] = sum;
+            }
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            recurseBinarySwitch(closure, 0, keyConstants.length - 1, 0);
+        }
+
+        /**
+         * Recursively generate a list of comparisons that always subdivides the keys in the given
+         * (inclusive) range in the middle (in terms of probability, not index). If left is bigger
+         * than zero, then we always know that the value is equal to or bigger than the left key.
+         * This does not hold for the right key, as there may be a gap afterwards.
+         */
+        private void recurseBinarySwitch(SwitchClosure closure, int left, int right, int startDepth) {
+            assert startDepth < keyConstants.length * 3 : "runaway recursion in binary switch";
+            int depth = startDepth;
+            boolean leftBorder = left == 0;
+            boolean rightBorder = right == keyConstants.length - 1;
+
+            if (left + 1 == right) {
+                // only two possible values
+                if (leftBorder || rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong() || keyConstants[left].asLong() + 1 != keyConstants[right].asLong()) {
+                    closure.conditionalJump(left, Condition.EQ, false);
+                    registerEffort(left, left, ++depth);
+                    closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder);
+                    registerEffort(right, right, ++depth);
+                    registerDefaultEffort(depth);
+                } else {
+                    // here we know that the value can only be one of these two keys in the range
+                    closure.conditionalJump(left, Condition.EQ, false);
+                    registerEffort(left, left, ++depth);
+                    closure.conditionalJump(right, null, false);
+                    registerEffort(right, right, depth);
+                }
+                return;
+            }
+            double probabilityStart = probabilitySums[left];
+            double probabilityMiddle = (probabilityStart + probabilitySums[right + 1]) / 2;
+            assert probabilityStart >= probabilityStart;
+            int middle = left;
+            while (getSliceEnd(closure, middle + 1) < right && probabilitySums[getSliceEnd(closure, middle + 1)] < probabilityMiddle) {
+                middle = getSliceEnd(closure, middle + 1);
+            }
+            middle = getSliceEnd(closure, middle);
+            assert middle < keyConstants.length - 1;
+
+            if (getSliceEnd(closure, left) == middle) {
+                if (left == 0) {
+                    closure.conditionalJump(0, Condition.LT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJump(middle, Condition.LE, false);
+                registerEffort(left, middle, ++depth);
+
+                if (middle + 1 == right) {
+                    closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder);
+                    registerEffort(right, right, ++depth);
+                    registerDefaultEffort(depth);
+                } else {
+                    if (keyConstants[middle].asLong() + 1 != keyConstants[middle + 1].asLong()) {
+                        closure.conditionalJump(middle + 1, Condition.LT, true);
+                        registerDefaultEffort(++depth);
+                    }
+                    if (getSliceEnd(closure, middle + 1) == right) {
+                        if (right == keyConstants.length - 1 || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) {
+                            closure.conditionalJumpOrDefault(right, Condition.LE, rightBorder);
+                            registerEffort(middle + 1, right, ++depth);
+                            registerDefaultEffort(depth);
+                        } else {
+                            closure.conditionalJump(middle + 1, null, false);
+                            registerEffort(middle + 1, right, depth);
+                        }
+                    } else {
+                        recurseBinarySwitch(closure, middle + 1, right, depth);
+                    }
+                }
+            } else if (getSliceEnd(closure, middle + 1) == right) {
+                if (rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) {
+                    closure.conditionalJump(right, Condition.GT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJump(middle + 1, Condition.GE, false);
+                registerEffort(middle + 1, right, ++depth);
+                recurseBinarySwitch(closure, left, middle, depth);
+            } else {
+                Label label = closure.conditionalJump(middle + 1, Condition.GE);
+                depth++;
+                recurseBinarySwitch(closure, left, middle, depth);
+                closure.bind(label);
+                recurseBinarySwitch(closure, middle + 1, right, depth);
+            }
+        }
+    }
+
+    public abstract void run(SwitchClosure closure);
+
+    private static SwitchStrategy[] getStrategies(double[] keyProbabilities, JavaConstant[] keyConstants, LabelRef[] keyTargets) {
+        SwitchStrategy[] strategies = new SwitchStrategy[]{new SequentialStrategy(keyProbabilities, keyConstants), new RangesStrategy(keyProbabilities, keyConstants),
+                        new BinaryStrategy(keyProbabilities, keyConstants)};
+        for (SwitchStrategy strategy : strategies) {
+            strategy.effortClosure = strategy.new EffortClosure(keyTargets);
+            strategy.run(strategy.effortClosure);
+            strategy.averageEffort = strategy.effortClosure.getAverageEffort();
+            strategy.effortClosure = null;
+        }
+        return strategies;
+    }
+
+    /**
+     * Creates all switch strategies for the given switch, evaluates them (based on average effort)
+     * and returns the best one.
+     */
+    public static SwitchStrategy getBestStrategy(double[] keyProbabilities, JavaConstant[] keyConstants, LabelRef[] keyTargets) {
+        SwitchStrategy[] strategies = getStrategies(keyProbabilities, keyConstants, keyTargets);
+        double bestEffort = Integer.MAX_VALUE;
+        SwitchStrategy bestStrategy = null;
+        for (SwitchStrategy strategy : strategies) {
+            if (strategy.getAverageEffort() < bestEffort) {
+                bestEffort = strategy.getAverageEffort();
+                bestStrategy = strategy;
+            }
+        }
+        return bestStrategy;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueConsumer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueConsumer.java
new file mode 100644
index 0000000..5ab8ec7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueConsumer.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Non-modifying version of {@link ValueProcedure}.
+ */
+@FunctionalInterface
+public interface ValueConsumer extends InstructionValueConsumer {
+
+    /**
+     * Iterator method to be overwritten.
+     *
+     * @param value The value that is iterated.
+     * @param mode The operand mode for the value.
+     * @param flags A set of flags for the value.
+     */
+    void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags);
+
+    @Override
+    default void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        visitValue(value, mode, flags);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueProcedure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueProcedure.java
new file mode 100644
index 0000000..b8bc9e8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ValueProcedure.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Similar to {@link InstructionValueProcedure} but without an {@link LIRInstruction} parameter.
+ */
+@FunctionalInterface
+public interface ValueProcedure extends InstructionValueProcedure {
+
+    /**
+     * Iterator method to be overwritten.
+     *
+     * @param value The value that is iterated.
+     * @param mode The operand mode for the value.
+     * @param flags A set of flags for the value.
+     * @return The new value to replace the value that was passed in.
+     */
+    Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags);
+
+    @Override
+    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        return doValue(value, mode, flags);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Variable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Variable.java
new file mode 100644
index 0000000..fe39492
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/Variable.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents a value that is yet to be bound to a machine location (such as a {@link RegisterValue}
+ * or {@link StackSlot}) by a register allocator.
+ */
+public final class Variable extends AllocatableValue {
+
+    /**
+     * The identifier of the variable. This is a non-zero index in a contiguous 0-based name space.
+     */
+    public final int index;
+
+    private String name;
+
+    /**
+     * Creates a new variable.
+     *
+     * @param kind
+     * @param index
+     */
+    public Variable(ValueKind<?> kind, int index) {
+        super(kind);
+        assert index >= 0;
+        this.index = index;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        if (name != null) {
+            return name;
+        } else {
+            return "v" + index + getKindSuffix();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return 71 * super.hashCode() + index;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Variable) {
+            Variable other = (Variable) obj;
+            return super.equals(other) && index == other.index;
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/VirtualStackSlot.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/VirtualStackSlot.java
new file mode 100644
index 0000000..0fc7c2f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/VirtualStackSlot.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * {@link VirtualStackSlot}s are stack slots that are not yet fixed to specific frame offset. They
+ * are replaced by real {@link StackSlot}s with a fixed position in the frame before code emission.
+ */
+public abstract class VirtualStackSlot extends AllocatableValue {
+
+    private final int id;
+
+    public VirtualStackSlot(int id, ValueKind<?> kind) {
+        super(kind);
+        this.id = id;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return "vstack:" + id + getKindSuffix();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + id;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        VirtualStackSlot other = (VirtualStackSlot) obj;
+        if (id != other.id) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/AllocationStageVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/AllocationStageVerifier.java
new file mode 100644
index 0000000..82c4094
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/AllocationStageVerifier.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+
+import java.util.EnumSet;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Verifies that all virtual operands have been replaced by concrete values.
+ */
+public class AllocationStageVerifier extends AllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        verifyLIR(lirGenRes.getLIR());
+
+    }
+
+    protected void verifyLIR(LIR lir) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            verifyBlock(lir, block);
+        }
+    }
+
+    protected void verifyBlock(LIR lir, AbstractBlockBase<?> block) {
+        for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+            verifyInstruction(inst);
+        }
+    }
+
+    protected void verifyInstruction(LIRInstruction inst) {
+        inst.visitEachInput(this::verifyOperands);
+        inst.visitEachOutput(this::verifyOperands);
+        inst.visitEachAlive(this::verifyOperands);
+        inst.visitEachTemp(this::verifyOperands);
+    }
+
+    /**
+     * @param instruction
+     * @param value
+     * @param mode
+     * @param flags
+     */
+    protected void verifyOperands(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        assert !isVirtualStackSlot(value) && !isVariable(value) : "Virtual values not allowed after allocation stage: " + value;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/OutOfRegistersException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/OutOfRegistersException.java
new file mode 100644
index 0000000..73c0586
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/OutOfRegistersException.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
+import static org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.ALL_REGISTERS;
+
+import org.graalvm.compiler.lir.BailoutAndRestartBackendException;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+/**
+ * Thrown if the register allocator runs out of registers. This should never happen in normal mode.
+ */
+public final class OutOfRegistersException extends BailoutAndRestartBackendException {
+
+    private static final long serialVersionUID = -3479786650143432195L;
+
+    private final String description;
+
+    public OutOfRegistersException(String msg) {
+        super(msg);
+        this.description = "";
+    }
+
+    public OutOfRegistersException(Throwable cause, String msg) {
+        super(cause, msg);
+        this.description = "";
+    }
+
+    public OutOfRegistersException(String msg, String description) {
+        super(msg);
+        this.description = description;
+    }
+
+    public OutOfRegistersException(Throwable cause, String msg, String description) {
+        super(cause, msg);
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public boolean shouldRestart() {
+        return RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS);
+    }
+
+    @Override
+    public OverrideScope getOverrideScope() {
+        return OptionValue.override(RegisterPressure, ALL_REGISTERS);
+    }
+
+    @Override
+    public LIRSuites updateLIRSuites(LIRSuites lirSuites) {
+        return lirSuites;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/SaveCalleeSaveRegisters.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/SaveCalleeSaveRegisters.java
new file mode 100644
index 0000000..f86d338
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/SaveCalleeSaveRegisters.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase;
+import org.graalvm.compiler.lir.util.RegisterMap;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.PlatformKind;
+
+public class SaveCalleeSaveRegisters extends PreAllocationOptimizationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
+        FrameMapBuilder frameMapBuilder = lirGenRes.getFrameMapBuilder();
+        RegisterArray calleeSaveRegisters = frameMapBuilder.getCodeCache().getRegisterConfig().getCalleeSaveRegisters();
+        if (calleeSaveRegisters == null || calleeSaveRegisters.size() == 0) {
+            return;
+        }
+        LIR lir = lirGenRes.getLIR();
+        RegisterMap<Variable> savedRegisters = saveAtEntry(lir, context.lirGen, calleeSaveRegisters, target.arch);
+
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            if (block == null) {
+                continue;
+            }
+            if (block.getSuccessorCount() == 0) {
+                restoreAtExit(lir, context.lirGen.getSpillMoveFactory(), savedRegisters, block);
+            }
+        }
+    }
+
+    private static RegisterMap<Variable> saveAtEntry(LIR lir, LIRGeneratorTool lirGen, RegisterArray calleeSaveRegisters, Architecture arch) {
+        AbstractBlockBase<?> startBlock = lir.getControlFlowGraph().getStartBlock();
+        List<LIRInstruction> instructions = lir.getLIRforBlock(startBlock);
+        int insertionIndex = 1;
+        LIRInsertionBuffer buffer = new LIRInsertionBuffer();
+        buffer.init(instructions);
+        StandardOp.LabelOp entry = (StandardOp.LabelOp) instructions.get(insertionIndex - 1);
+        RegisterValue[] savedRegisterValues = new RegisterValue[calleeSaveRegisters.size()];
+        int savedRegisterValueIndex = 0;
+        RegisterMap<Variable> saveMap = new RegisterMap<>(arch);
+        for (Register register : calleeSaveRegisters) {
+            PlatformKind registerPlatformKind = arch.getLargestStorableKind(register.getRegisterCategory());
+            LIRKind lirKind = LIRKind.value(registerPlatformKind);
+            RegisterValue registerValue = register.asValue(lirKind);
+            Variable saveVariable = lirGen.newVariable(lirKind);
+            LIRInstruction save = lirGen.getSpillMoveFactory().createMove(saveVariable, registerValue);
+            buffer.append(insertionIndex, save);
+            saveMap.put(register, saveVariable);
+            savedRegisterValues[savedRegisterValueIndex++] = registerValue;
+        }
+        entry.addIncomingValues(savedRegisterValues);
+        buffer.finish();
+        return saveMap;
+    }
+
+    private static void restoreAtExit(LIR lir, LIRGeneratorTool.MoveFactory moveFactory, RegisterMap<Variable> calleeSaveRegisters, AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int insertionIndex = instructions.size() - 1;
+        LIRInsertionBuffer buffer = new LIRInsertionBuffer();
+        buffer.init(instructions);
+        assert instructions.get(insertionIndex) instanceof StandardOp.BlockEndOp;
+        calleeSaveRegisters.forEach((Register register, Variable saved) -> {
+            LIRInstruction restore = moveFactory.createMove(register.asValue(saved.getValueKind()), saved);
+            buffer.append(insertionIndex, restore);
+        });
+        buffer.finish();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java
new file mode 100644
index 0000000..dc2ef3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Interval.java
@@ -0,0 +1,1322 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.util.IntList;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents an interval in the {@linkplain LinearScan linear scan register allocator}.
+ */
+public final class Interval {
+
+    /**
+     * A pair of intervals.
+     */
+    static final class Pair {
+
+        public final Interval first;
+        public final Interval second;
+
+        Pair(Interval first, Interval second) {
+            this.first = first;
+            this.second = second;
+        }
+    }
+
+    /**
+     * A set of interval lists, one per {@linkplain RegisterBinding binding} type.
+     */
+    static final class RegisterBindingLists {
+
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Fixed}.
+         */
+        public Interval fixed;
+
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Any}.
+         */
+        public Interval any;
+
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Stack}.
+         */
+        public Interval stack;
+
+        RegisterBindingLists(Interval fixed, Interval any, Interval stack) {
+            this.fixed = fixed;
+            this.any = any;
+            this.stack = stack;
+        }
+
+        /**
+         * Gets the list for a specified binding.
+         *
+         * @param binding specifies the list to be returned
+         * @return the list of intervals whose binding is {@code binding}
+         */
+        public Interval get(RegisterBinding binding) {
+            switch (binding) {
+                case Any:
+                    return any;
+                case Fixed:
+                    return fixed;
+                case Stack:
+                    return stack;
+            }
+            throw GraalError.shouldNotReachHere();
+        }
+
+        /**
+         * Sets the list for a specified binding.
+         *
+         * @param binding specifies the list to be replaced
+         * @param list a list of intervals whose binding is {@code binding}
+         */
+        public void set(RegisterBinding binding, Interval list) {
+            assert list != null;
+            switch (binding) {
+                case Any:
+                    any = list;
+                    break;
+                case Fixed:
+                    fixed = list;
+                    break;
+                case Stack:
+                    stack = list;
+                    break;
+            }
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from}
+         * positions.
+         *
+         * @param binding specifies the list to be updated
+         * @param interval the interval to add
+         */
+        public void addToListSortedByCurrentFromPositions(RegisterBinding binding, Interval interval) {
+            Interval list = get(binding);
+            Interval prev = null;
+            Interval cur = list;
+            while (cur.currentFrom() < interval.currentFrom()) {
+                prev = cur;
+                cur = cur.next;
+            }
+            Interval result = list;
+            if (prev == null) {
+                // add to head of list
+                result = interval;
+            } else {
+                // add before 'cur'
+                prev.next = interval;
+            }
+            interval.next = cur;
+            set(binding, result);
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and
+         * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions.
+         *
+         * @param binding specifies the list to be updated
+         * @param interval the interval to add
+         */
+        public void addToListSortedByStartAndUsePositions(RegisterBinding binding, Interval interval) {
+            Interval list = get(binding);
+            Interval prev = null;
+            Interval cur = list;
+            while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                list = interval;
+            } else {
+                prev.next = interval;
+            }
+            interval.next = cur;
+            set(binding, list);
+        }
+
+        /**
+         * Removes an interval from a list.
+         *
+         * @param binding specifies the list to be updated
+         * @param i the interval to remove
+         */
+        public void remove(RegisterBinding binding, Interval i) {
+            Interval list = get(binding);
+            Interval prev = null;
+            Interval cur = list;
+            while (cur != i) {
+                assert cur != null && cur != Interval.EndMarker : "interval has not been found in list: " + i;
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                set(binding, cur.next);
+            } else {
+                prev.next = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Constants denoting the register usage priority for an interval. The constants are declared in
+     * increasing order of priority are are used to optimize spilling when multiple overlapping
+     * intervals compete for limited registers.
+     */
+    public enum RegisterPriority {
+        /**
+         * No special reason for an interval to be allocated a register.
+         */
+        None,
+
+        /**
+         * Priority level for intervals live at the end of a loop.
+         */
+        LiveAtLoopEnd,
+
+        /**
+         * Priority level for intervals that should be allocated to a register.
+         */
+        ShouldHaveRegister,
+
+        /**
+         * Priority level for intervals that must be allocated to a register.
+         */
+        MustHaveRegister;
+
+        public static final RegisterPriority[] VALUES = values();
+
+        /**
+         * Determines if this priority is higher than or equal to a given priority.
+         */
+        public boolean greaterEqual(RegisterPriority other) {
+            return ordinal() >= other.ordinal();
+        }
+
+        /**
+         * Determines if this priority is lower than a given priority.
+         */
+        public boolean lessThan(RegisterPriority other) {
+            return ordinal() < other.ordinal();
+        }
+    }
+
+    /**
+     * Constants denoting whether an interval is bound to a specific register. This models platform
+     * dependencies on register usage for certain instructions.
+     */
+    enum RegisterBinding {
+        /**
+         * Interval is bound to a specific register as required by the platform.
+         */
+        Fixed,
+
+        /**
+         * Interval has no specific register requirements.
+         */
+        Any,
+
+        /**
+         * Interval is bound to a stack slot.
+         */
+        Stack;
+
+        public static final RegisterBinding[] VALUES = values();
+    }
+
+    /**
+     * Constants denoting the linear-scan states an interval may be in with respect to the
+     * {@linkplain Interval#from() start} {@code position} of the interval being processed.
+     */
+    enum State {
+        /**
+         * An interval that starts after {@code position}.
+         */
+        Unhandled,
+
+        /**
+         * An interval that {@linkplain Interval#covers covers} {@code position} and has an assigned
+         * register.
+         */
+        Active,
+
+        /**
+         * An interval that starts before and ends after {@code position} but does not
+         * {@linkplain Interval#covers cover} it due to a lifetime hole.
+         */
+        Inactive,
+
+        /**
+         * An interval that ends before {@code position} or is spilled to memory.
+         */
+        Handled;
+    }
+
+    /**
+     * Constants used in optimization of spilling of an interval.
+     */
+    public enum SpillState {
+        /**
+         * Starting state of calculation: no definition found yet.
+         */
+        NoDefinitionFound,
+
+        /**
+         * One definition has already been found. Two consecutive definitions are treated as one
+         * (e.g. a consecutive move and add because of two-operand LIR form). The position of this
+         * definition is given by {@link Interval#spillDefinitionPos()}.
+         */
+        NoSpillStore,
+
+        /**
+         * One spill move has already been inserted.
+         */
+        OneSpillStore,
+
+        /**
+         * The interval is spilled multiple times or is spilled in a loop. Place the store somewhere
+         * on the dominator path between the definition and the usages.
+         */
+        SpillInDominator,
+
+        /**
+         * The interval should be stored immediately after its definition to prevent multiple
+         * redundant stores.
+         */
+        StoreAtDefinition,
+
+        /**
+         * The interval starts in memory (e.g. method parameter), so a store is never necessary.
+         */
+        StartInMemory,
+
+        /**
+         * The interval has more than one definition (e.g. resulting from phi moves), so stores to
+         * memory are not optimized.
+         */
+        NoOptimization;
+
+        public static final EnumSet<SpillState> ALWAYS_IN_MEMORY = EnumSet.of(SpillInDominator, StoreAtDefinition, StartInMemory);
+    }
+
+    /**
+     * List of use positions. Each entry in the list records the use position and register priority
+     * associated with the use position. The entries in the list are in descending order of use
+     * position.
+     *
+     */
+    public static final class UsePosList {
+
+        private IntList list;
+
+        /**
+         * Creates a use list.
+         *
+         * @param initialCapacity the initial capacity of the list in terms of entries
+         */
+        public UsePosList(int initialCapacity) {
+            list = new IntList(initialCapacity * 2);
+        }
+
+        private UsePosList(IntList list) {
+            this.list = list;
+        }
+
+        /**
+         * Splits this list around a given position. All entries in this list with a use position
+         * greater or equal than {@code splitPos} are removed from this list and added to the
+         * returned list.
+         *
+         * @param splitPos the position for the split
+         * @return a use position list containing all entries removed from this list that have a use
+         *         position greater or equal than {@code splitPos}
+         */
+        public UsePosList splitAt(int splitPos) {
+            int i = size() - 1;
+            int len = 0;
+            while (i >= 0 && usePos(i) < splitPos) {
+                --i;
+                len += 2;
+            }
+            int listSplitIndex = (i + 1) * 2;
+            IntList childList = list;
+            list = IntList.copy(this.list, listSplitIndex, len);
+            childList.setSize(listSplitIndex);
+            UsePosList child = new UsePosList(childList);
+            return child;
+        }
+
+        /**
+         * Gets the use position at a specified index in this list.
+         *
+         * @param index the index of the entry for which the use position is returned
+         * @return the use position of entry {@code index} in this list
+         */
+        public int usePos(int index) {
+            return list.get(index << 1);
+        }
+
+        /**
+         * Gets the register priority for the use position at a specified index in this list.
+         *
+         * @param index the index of the entry for which the register priority is returned
+         * @return the register priority of entry {@code index} in this list
+         */
+        public RegisterPriority registerPriority(int index) {
+            return RegisterPriority.VALUES[list.get((index << 1) + 1)];
+        }
+
+        public void add(int usePos, RegisterPriority registerPriority) {
+            assert list.size() == 0 || usePos(size() - 1) > usePos;
+            list.add(usePos);
+            list.add(registerPriority.ordinal());
+        }
+
+        public int size() {
+            return list.size() >> 1;
+        }
+
+        public void removeLowestUsePos() {
+            list.setSize(list.size() - 2);
+        }
+
+        public void setRegisterPriority(int index, RegisterPriority registerPriority) {
+            list.set((index << 1) + 1, registerPriority.ordinal());
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder("[");
+            for (int i = size() - 1; i >= 0; --i) {
+                if (buf.length() != 1) {
+                    buf.append(", ");
+                }
+                RegisterPriority prio = registerPriority(i);
+                buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio);
+            }
+            return buf.append("]").toString();
+        }
+    }
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
+     * prior to register allocation.
+     */
+    public final AllocatableValue operand;
+
+    /**
+     * The operand number for this interval's {@linkplain #operand operand}.
+     */
+    public final int operandNumber;
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
+     * interval. In case of a spilled interval which is re-materialized this is
+     * {@link Value#ILLEGAL}.
+     */
+    private AllocatableValue location;
+
+    /**
+     * The stack slot to which all splits of this interval are spilled if necessary.
+     */
+    private AllocatableValue spillSlot;
+
+    /**
+     * The kind of this interval.
+     */
+    private ValueKind<?> kind;
+
+    /**
+     * The head of the list of ranges describing this interval. This list is sorted by
+     * {@linkplain LIRInstruction#id instruction ids}.
+     */
+    private Range first;
+
+    /**
+     * List of (use-positions, register-priorities) pairs, sorted by use-positions.
+     */
+    private UsePosList usePosList;
+
+    /**
+     * Iterator used to traverse the ranges of an interval.
+     */
+    private Range current;
+
+    /**
+     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
+     */
+    Interval next;
+
+    /**
+     * The linear-scan state of this interval.
+     */
+    State state;
+
+    private int cachedTo; // cached value: to of last range (-1: not cached)
+
+    /**
+     * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split
+     * parent}, it points to itself.
+     */
+    private Interval splitParent;
+
+    /**
+     * List of all intervals that are split off from this interval. This is only used if this is a
+     * {@linkplain #isSplitParent() split parent}.
+     */
+    private List<Interval> splitChildren = Collections.emptyList();
+
+    /**
+     * Current split child that has been active or inactive last (always stored in split parents).
+     */
+    private Interval currentSplitChild;
+
+    /**
+     * Specifies if move is inserted between currentSplitChild and this interval when interval gets
+     * active the first time.
+     */
+    private boolean insertMoveWhenActivated;
+
+    /**
+     * For spill move optimization.
+     */
+    private SpillState spillState;
+
+    /**
+     * Position where this interval is defined (if defined only once).
+     */
+    private int spillDefinitionPos;
+
+    /**
+     * This interval should be assigned the same location as the hint interval.
+     */
+    private Interval locationHint;
+
+    /**
+     * The value with which a spilled child interval can be re-materialized. Currently this must be
+     * a Constant.
+     */
+    private Constant materializedValue;
+
+    /**
+     * The number of times {@link #addMaterializationValue(Constant)} is called.
+     */
+    private int numMaterializationValuesAdded;
+
+    void assignLocation(AllocatableValue newLocation) {
+        if (isRegister(newLocation)) {
+            assert this.location == null : "cannot re-assign location for " + this;
+            if (newLocation.getValueKind().equals(LIRKind.Illegal) && !kind.equals(LIRKind.Illegal)) {
+                this.location = asRegister(newLocation).asValue(kind);
+                return;
+            }
+        } else if (isIllegal(newLocation)) {
+            assert canMaterialize();
+        } else {
+            assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this;
+            assert isStackSlotValue(newLocation);
+            assert !newLocation.getValueKind().equals(LIRKind.Illegal);
+            assert newLocation.getValueKind().equals(this.kind);
+        }
+        this.location = newLocation;
+    }
+
+    /**
+     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
+     * this interval.
+     */
+    public AllocatableValue location() {
+        return location;
+    }
+
+    public ValueKind<?> kind() {
+        assert !isRegister(operand) : "cannot access type for fixed interval";
+        return kind;
+    }
+
+    public void setKind(ValueKind<?> kind) {
+        assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type";
+        this.kind = kind;
+    }
+
+    public Range first() {
+        return first;
+    }
+
+    public int from() {
+        return first.from;
+    }
+
+    int to() {
+        if (cachedTo == -1) {
+            cachedTo = calcTo();
+        }
+        assert cachedTo == calcTo() : "invalid cached value";
+        return cachedTo;
+    }
+
+    int numUsePositions() {
+        return usePosList.size();
+    }
+
+    public void setLocationHint(Interval interval) {
+        locationHint = interval;
+    }
+
+    public boolean isSplitParent() {
+        return splitParent == this;
+    }
+
+    boolean isSplitChild() {
+        return splitParent != this;
+    }
+
+    /**
+     * Gets the split parent for this interval.
+     */
+    public Interval splitParent() {
+        assert splitParent.isSplitParent() : "not a split parent: " + this;
+        return splitParent;
+    }
+
+    /**
+     * Gets the canonical spill slot for this interval.
+     */
+    public AllocatableValue spillSlot() {
+        return splitParent().spillSlot;
+    }
+
+    public void setSpillSlot(AllocatableValue slot) {
+        assert isStackSlotValue(slot);
+        assert splitParent().spillSlot == null || (isVirtualStackSlot(splitParent().spillSlot) && isStackSlot(slot)) : "connot overwrite existing spill slot";
+        splitParent().spillSlot = slot;
+    }
+
+    Interval currentSplitChild() {
+        return splitParent().currentSplitChild;
+    }
+
+    void makeCurrentSplitChild() {
+        splitParent().currentSplitChild = this;
+    }
+
+    boolean insertMoveWhenActivated() {
+        return insertMoveWhenActivated;
+    }
+
+    void setInsertMoveWhenActivated(boolean b) {
+        insertMoveWhenActivated = b;
+    }
+
+    // for spill optimization
+    public SpillState spillState() {
+        return splitParent().spillState;
+    }
+
+    public int spillDefinitionPos() {
+        return splitParent().spillDefinitionPos;
+    }
+
+    public void setSpillState(SpillState state) {
+        assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
+        splitParent().spillState = state;
+    }
+
+    public void setSpillDefinitionPos(int pos) {
+        assert spillState() == SpillState.SpillInDominator || spillState() == SpillState.NoDefinitionFound || spillDefinitionPos() == -1 : "cannot set the position twice";
+        splitParent().spillDefinitionPos = pos;
+    }
+
+    // returns true if this interval has a shadow copy on the stack that is always correct
+    public boolean alwaysInMemory() {
+        return SpillState.ALWAYS_IN_MEMORY.contains(spillState()) && !canMaterialize();
+    }
+
+    void removeFirstUsePos() {
+        usePosList.removeLowestUsePos();
+    }
+
+    // test intersection
+    boolean intersects(Interval i) {
+        return first.intersects(i.first);
+    }
+
+    int intersectsAt(Interval i) {
+        return first.intersectsAt(i.first);
+    }
+
+    // range iteration
+    void rewindRange() {
+        current = first;
+    }
+
+    void nextRange() {
+        assert this != EndMarker : "not allowed on sentinel";
+        current = current.next;
+    }
+
+    int currentFrom() {
+        return current.from;
+    }
+
+    int currentTo() {
+        return current.to;
+    }
+
+    boolean currentAtEnd() {
+        return current == Range.EndMarker;
+    }
+
+    boolean currentIntersects(Interval it) {
+        return current.intersects(it.current);
+    }
+
+    int currentIntersectsAt(Interval it) {
+        return current.intersectsAt(it.current);
+    }
+
+    /**
+     * Sentinel interval to denote the end of an interval list.
+     */
+    static final Interval EndMarker = new Interval(Value.ILLEGAL, -1);
+
+    Interval(AllocatableValue operand, int operandNumber) {
+        assert operand != null;
+        this.operand = operand;
+        this.operandNumber = operandNumber;
+        if (isRegister(operand)) {
+            location = operand;
+        } else {
+            assert isIllegal(operand) || isVariable(operand);
+        }
+        this.kind = LIRKind.Illegal;
+        this.first = Range.EndMarker;
+        this.usePosList = new UsePosList(4);
+        this.current = Range.EndMarker;
+        this.next = EndMarker;
+        this.cachedTo = -1;
+        this.spillState = SpillState.NoDefinitionFound;
+        this.spillDefinitionPos = -1;
+        splitParent = this;
+        currentSplitChild = this;
+    }
+
+    /**
+     * Sets the value which is used for re-materialization.
+     */
+    public void addMaterializationValue(Constant value) {
+        if (numMaterializationValuesAdded == 0) {
+            materializedValue = value;
+        } else {
+            // Interval is defined on multiple places -> no materialization is possible.
+            materializedValue = null;
+        }
+        numMaterializationValuesAdded++;
+    }
+
+    /**
+     * Returns true if this interval can be re-materialized when spilled. This means that no
+     * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored.
+     */
+    public boolean canMaterialize() {
+        return getMaterializedValue() != null;
+    }
+
+    /**
+     * Returns a value which can be moved to a register instead of a restore-move from stack.
+     */
+    public Constant getMaterializedValue() {
+        return splitParent().materializedValue;
+    }
+
+    int calcTo() {
+        assert first != Range.EndMarker : "interval has no range";
+
+        Range r = first;
+        while (r.next != Range.EndMarker) {
+            r = r.next;
+        }
+        return r.to;
+    }
+
+    // consistency check of split-children
+    boolean checkSplitChildren() {
+        if (!splitChildren.isEmpty()) {
+            assert isSplitParent() : "only split parents can have children";
+
+            for (int i = 0; i < splitChildren.size(); i++) {
+                Interval i1 = splitChildren.get(i);
+
+                assert i1.splitParent() == this : "not a split child of this interval";
+                assert i1.kind().equals(kind()) : "must be equal for all split children";
+                assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
+
+                for (int j = i + 1; j < splitChildren.size(); j++) {
+                    Interval i2 = splitChildren.get(j);
+
+                    assert !i1.operand.equals(i2.operand) : "same register number";
+
+                    if (i1.from() < i2.from()) {
+                        assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
+                    } else {
+                        assert i2.from() < i1.from() : "intervals start at same opId";
+                        assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public Interval locationHint(boolean searchSplitChild) {
+        if (!searchSplitChild) {
+            return locationHint;
+        }
+
+        if (locationHint != null) {
+            assert locationHint.isSplitParent() : "ony split parents are valid hint registers";
+
+            if (locationHint.location != null && isRegister(locationHint.location)) {
+                return locationHint;
+            } else if (!locationHint.splitChildren.isEmpty()) {
+                // search the first split child that has a register assigned
+                int len = locationHint.splitChildren.size();
+                for (int i = 0; i < len; i++) {
+                    Interval interval = locationHint.splitChildren.get(i);
+                    if (interval.location != null && isRegister(interval.location)) {
+                        return interval;
+                    }
+                }
+            }
+        }
+
+        // no hint interval found that has a register assigned
+        return null;
+    }
+
+    Interval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, LinearScan allocator) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            assert this.covers(opId, mode) : this + " does not cover " + opId;
+            return this;
+        } else {
+            Interval result = null;
+            int len = splitChildren.size();
+
+            // in outputMode, the end of the interval (opId == cur.to()) is not valid
+            int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
+
+            int i;
+            for (i = 0; i < len; i++) {
+                Interval cur = splitChildren.get(i);
+                if (cur.from() <= opId && opId < cur.to() + toOffset) {
+                    if (i > 0) {
+                        // exchange current split child to start of list (faster access for next
+                        // call)
+                        Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
+                        Util.atPutGrow(splitChildren, 0, cur, null);
+                    }
+
+                    // interval found
+                    result = cur;
+                    break;
+                }
+            }
+
+            assert checkSplitChild(result, opId, allocator, toOffset, mode);
+            return result;
+        }
+    }
+
+    private boolean checkSplitChild(Interval result, int opId, LinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) {
+        if (result == null) {
+            // this is an error
+            StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
+            if (!splitChildren.isEmpty()) {
+                Interval firstChild = splitChildren.get(0);
+                Interval lastChild = splitChildren.get(splitChildren.size() - 1);
+                msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")");
+            }
+            throw new GraalError("Linear Scan Error: %s", msg);
+        }
+
+        if (!splitChildren.isEmpty()) {
+            for (Interval interval : splitChildren) {
+                if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
+                    /*
+                     * Should not happen: Try another compilation as it is very unlikely to happen
+                     * again.
+                     */
+                    throw new GraalError("two valid result intervals found for opId %d: %d and %d\n%s\n", opId, result.operandNumber, interval.operandNumber,
+                                    result.logString(allocator), interval.logString(allocator));
+                }
+            }
+        }
+        assert result.covers(opId, mode) : "opId not covered by interval";
+        return true;
+    }
+
+    // returns the interval that covers the given opId or null if there is none
+    Interval getIntervalCoveringOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+        assert opId < to() : "can only look into the past";
+
+        if (opId >= from()) {
+            return this;
+        }
+
+        Interval parent = splitParent();
+        Interval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            Interval cur = parent.splitChildren.get(i);
+            if (cur.from() <= opId && opId < cur.to()) {
+                assert result == null : "covered by multiple split children " + result + " and " + cur;
+                result = cur;
+            }
+        }
+
+        return result;
+    }
+
+    // returns the last split child that ends before the given opId
+    Interval getSplitChildBeforeOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+
+        Interval parent = splitParent();
+        Interval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            Interval cur = parent.splitChildren.get(i);
+            if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
+                result = cur;
+            }
+        }
+
+        assert result != null : "no split child found";
+        return result;
+    }
+
+    // checks if opId is covered by any split child
+    boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            // simple case if interval was not split
+            return covers(opId, mode);
+
+        } else {
+            // extended case: check all split children
+            int len = splitChildren.size();
+            for (int i = 0; i < len; i++) {
+                Interval cur = splitChildren.get(i);
+                if (cur.covers(opId, mode)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private RegisterPriority adaptPriority(RegisterPriority priority) {
+        /*
+         * In case of re-materialized values we require that use-operands are registers, because we
+         * don't have the value in a stack location. (Note that ShouldHaveRegister means that the
+         * operand can also be a StackSlot).
+         */
+        if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
+            return RegisterPriority.MustHaveRegister;
+        }
+        return priority;
+    }
+
+    // Note: use positions are sorted descending . first use has highest index
+    int firstUsage(RegisterPriority minRegisterPriority) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            RegisterPriority registerPriority = adaptPriority(usePosList.registerPriority(i));
+            if (registerPriority.greaterEqual(minRegisterPriority)) {
+                return usePosList.usePos(i);
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)) == exactRegisterPriority) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int previousUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        int prev = -1;
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos > from) {
+                return prev;
+            }
+            if (adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
+                prev = usePos;
+            }
+        }
+        return prev;
+    }
+
+    public void addUsePos(int pos, RegisterPriority registerPriority) {
+        assert covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
+
+        // do not add use positions for precolored intervals because they are never used
+        if (registerPriority != RegisterPriority.None && isVariable(operand)) {
+            if (DetailedAsserts.getValue()) {
+                for (int i = 0; i < usePosList.size(); i++) {
+                    assert pos <= usePosList.usePos(i) : "already added a use-position with lower position";
+                    if (i > 0) {
+                        assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending";
+                    }
+                }
+            }
+
+            // Note: addUse is called in descending order, so list gets sorted
+            // automatically by just appending new use positions
+            int len = usePosList.size();
+            if (len == 0 || usePosList.usePos(len - 1) > pos) {
+                usePosList.add(pos, registerPriority);
+            } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) {
+                assert usePosList.usePos(len - 1) == pos : "list not sorted correctly";
+                usePosList.setRegisterPriority(len - 1, registerPriority);
+            }
+        }
+    }
+
+    public void addRange(int from, int to) {
+        assert from < to : "invalid range";
+        assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval";
+        assert from <= first().to : "not inserting at begin of interval";
+
+        if (first.from <= to) {
+            assert first != Range.EndMarker;
+            // join intersecting ranges
+            first.from = Math.min(from, first().from);
+            first.to = Math.max(to, first().to);
+        } else {
+            // insert new range
+            first = new Range(from, to, first());
+        }
+    }
+
+    Interval newSplitChild(LinearScan allocator) {
+        // allocate new interval
+        Interval parent = splitParent();
+        Interval result = allocator.createDerivedInterval(parent);
+        result.setKind(kind());
+
+        result.splitParent = parent;
+        result.setLocationHint(parent);
+
+        // insert new interval in children-list of parent
+        if (parent.splitChildren.isEmpty()) {
+            assert isSplitParent() : "list must be initialized at first split";
+
+            // Create new non-shared list
+            parent.splitChildren = new ArrayList<>(4);
+            parent.splitChildren.add(this);
+        }
+        parent.splitChildren.add(result);
+
+        return result;
+    }
+
+    /**
+     * Splits this interval at a specified position and returns the remainder as a new <i>child</i>
+     * interval of this interval's {@linkplain #splitParent() parent} interval.
+     * <p>
+     * When an interval is split, a bi-directional link is established between the original
+     * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval.
+     * When a split child is split again, the new created interval is a direct child of the original
+     * parent. That is, there is no tree of split children stored, just a flat list. All split
+     * children are spilled to the same {@linkplain #spillSlot spill slot}.
+     *
+     * @param splitPos the position at which to split this interval
+     * @param allocator the register allocator context
+     * @return the child interval split off from this interval
+     */
+    Interval split(int splitPos, LinearScan allocator) {
+        assert isVariable(operand) : "cannot split fixed intervals";
+
+        // allocate new interval
+        Interval result = newSplitChild(allocator);
+
+        // split the ranges
+        Range prev = null;
+        Range cur = first;
+        while (cur != Range.EndMarker && cur.to <= splitPos) {
+            prev = cur;
+            cur = cur.next;
+        }
+        assert cur != Range.EndMarker : "split interval after end of last range";
+
+        if (cur.from < splitPos) {
+            result.first = new Range(splitPos, cur.to, cur.next);
+            cur.to = splitPos;
+            cur.next = Range.EndMarker;
+
+        } else {
+            assert prev != null : "split before start of first range";
+            result.first = cur;
+            prev.next = Range.EndMarker;
+        }
+        result.current = result.first;
+        cachedTo = -1; // clear cached value
+
+        // split list of use positions
+        result.usePosList = usePosList.splitAt(splitPos);
+
+        if (DetailedAsserts.getValue()) {
+            for (int i = 0; i < usePosList.size(); i++) {
+                assert usePosList.usePos(i) < splitPos;
+            }
+            for (int i = 0; i < result.usePosList.size(); i++) {
+                assert result.usePosList.usePos(i) >= splitPos;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Splits this interval at a specified position and returns the head as a new interval (this
+     * interval is the tail).
+     *
+     * Currently, only the first range can be split, and the new interval must not have split
+     * positions
+     */
+    Interval splitFromStart(int splitPos, LinearScan allocator) {
+        assert isVariable(operand) : "cannot split fixed intervals";
+        assert splitPos > from() && splitPos < to() : "can only split inside interval";
+        assert splitPos > first.from && splitPos <= first.to : "can only split inside first range";
+        assert firstUsage(RegisterPriority.None) > splitPos : "can not split when use positions are present";
+
+        // allocate new interval
+        Interval result = newSplitChild(allocator);
+
+        // the new interval has only one range (checked by assertion above,
+        // so the splitting of the ranges is very simple
+        result.addRange(first.from, splitPos);
+
+        if (splitPos == first.to) {
+            assert first.next != Range.EndMarker : "must not be at end";
+            first = first.next;
+        } else {
+            first.from = splitPos;
+        }
+
+        return result;
+    }
+
+    // returns true if the opId is inside the interval
+    boolean covers(int opId, LIRInstruction.OperandMode mode) {
+        Range cur = first;
+
+        while (cur != Range.EndMarker && cur.to < opId) {
+            cur = cur.next;
+        }
+        if (cur != Range.EndMarker) {
+            assert cur.to != cur.next.from : "ranges not separated";
+
+            if (mode == LIRInstruction.OperandMode.DEF) {
+                return cur.from <= opId && opId < cur.to;
+            } else {
+                return cur.from <= opId && opId <= cur.to;
+            }
+        }
+        return false;
+    }
+
+    // returns true if the interval has any hole between holeFrom and holeTo
+    // (even if the hole has only the length 1)
+    boolean hasHoleBetween(int holeFrom, int holeTo) {
+        assert holeFrom < holeTo : "check";
+        assert from() <= holeFrom && holeTo <= to() : "index out of interval";
+
+        Range cur = first;
+        while (cur != Range.EndMarker) {
+            assert cur.to < cur.next.from : "no space between ranges";
+
+            // hole-range starts before this range . hole
+            if (holeFrom < cur.from) {
+                return true;
+
+                // hole-range completely inside this range . no hole
+            } else {
+                if (holeTo <= cur.to) {
+                    return false;
+
+                    // overlapping of hole-range with this range . hole
+                } else {
+                    if (holeFrom <= cur.to) {
+                        return true;
+                    }
+                }
+            }
+
+            cur = cur.next;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        String from = "?";
+        String to = "?";
+        if (first != null && first != Range.EndMarker) {
+            from = String.valueOf(from());
+            // to() may cache a computed value, modifying the current object, which is a bad idea
+            // for a printing function. Compute it directly instead.
+            to = String.valueOf(calcTo());
+        }
+        String locationString = this.location == null ? "" : "@" + this.location;
+        return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
+    }
+
+    /**
+     * Gets the use position information for this interval.
+     */
+    public UsePosList usePosList() {
+        return usePosList;
+    }
+
+    /**
+     * Gets a single line string for logging the details of this interval to a log stream.
+     *
+     * @param allocator the register allocator context
+     */
+    public String logString(LinearScan allocator) {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append(operandNumber).append(':').append(operand).append(' ');
+        if (!isRegister(operand)) {
+            if (location != null) {
+                buf.append("location{").append(location).append("} ");
+            }
+        }
+
+        buf.append("hints{").append(splitParent.operandNumber);
+        Interval hint = locationHint(false);
+        if (hint != null && hint.operandNumber != splitParent.operandNumber) {
+            buf.append(", ").append(hint.operandNumber);
+        }
+        buf.append("} ranges{");
+
+        // print ranges
+        Range cur = first;
+        while (cur != Range.EndMarker) {
+            if (cur != first) {
+                buf.append(", ");
+            }
+            buf.append(cur);
+            cur = cur.next;
+            assert cur != null : "range list not closed with range sentinel";
+        }
+        buf.append("} uses{");
+
+        // print use positions
+        int prev = -1;
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            assert prev < usePosList.usePos(i) : "use positions not sorted";
+            if (i != usePosList.size() - 1) {
+                buf.append(", ");
+            }
+            buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i));
+            prev = usePosList.usePos(i);
+        }
+        buf.append("} spill-state{").append(spillState()).append("}");
+        if (canMaterialize()) {
+            buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
+        }
+        return buf.toString();
+    }
+
+    List<Interval> getSplitChildren() {
+        return Collections.unmodifiableList(splitChildren);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/IntervalWalker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/IntervalWalker.java
new file mode 100644
index 0000000..4b28b96
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/IntervalWalker.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBinding;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBindingLists;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.State;
+
+/**
+ */
+public class IntervalWalker {
+
+    protected final LinearScan allocator;
+
+    /**
+     * Sorted list of intervals, not live before the current position.
+     */
+    protected RegisterBindingLists unhandledLists;
+
+    /**
+     * Sorted list of intervals, live at the current position.
+     */
+    protected RegisterBindingLists activeLists;
+
+    /**
+     * Sorted list of intervals in a life time hole at the current position.
+     */
+    protected RegisterBindingLists inactiveLists;
+
+    /**
+     * The current position (intercept point through the intervals).
+     */
+    protected int currentPosition;
+
+    /**
+     * The binding of the current interval being processed.
+     */
+    protected RegisterBinding currentBinding;
+
+    /**
+     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
+     * to it and thus allow it to be moved to a list of {@linkplain #activeLists active} intervals.
+     *
+     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
+     */
+    protected boolean activateCurrent(@SuppressWarnings({"unused"}) Interval currentInterval) {
+        return true;
+    }
+
+    void walkBefore(int lirOpId) {
+        walkTo(lirOpId - 1);
+    }
+
+    void walk() {
+        walkTo(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a new interval walker.
+     *
+     * @param allocator the register allocator context
+     * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
+     *            intervals
+     * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed}
+     *            intervals
+     */
+    IntervalWalker(LinearScan allocator, Interval unhandledFixed, Interval unhandledAny) {
+        this.allocator = allocator;
+
+        unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny, Interval.EndMarker);
+        activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
+        inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
+        currentPosition = -1;
+    }
+
+    protected void removeFromList(Interval interval) {
+        if (interval.state == State.Active) {
+            activeLists.remove(RegisterBinding.Any, interval);
+        } else {
+            assert interval.state == State.Inactive : "invalid state";
+            inactiveLists.remove(RegisterBinding.Any, interval);
+        }
+    }
+
+    private void walkTo(State state, int from) {
+        assert state == State.Active || state == State.Inactive : "wrong state";
+        for (RegisterBinding binding : RegisterBinding.VALUES) {
+            walkTo(state, from, binding);
+        }
+    }
+
+    private void walkTo(State state, int from, RegisterBinding binding) {
+        Interval prevprev = null;
+        Interval prev = (state == State.Active) ? activeLists.get(binding) : inactiveLists.get(binding);
+        Interval next = prev;
+        while (next.currentFrom() <= from) {
+            Interval cur = next;
+            next = cur.next;
+
+            boolean rangeHasChanged = false;
+            while (cur.currentTo() <= from) {
+                cur.nextRange();
+                rangeHasChanged = true;
+            }
+
+            // also handle move from inactive list to active list
+            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+
+            if (rangeHasChanged) {
+                // remove cur from list
+                if (prevprev == null) {
+                    if (state == State.Active) {
+                        activeLists.set(binding, next);
+                    } else {
+                        inactiveLists.set(binding, next);
+                    }
+                } else {
+                    prevprev.next = next;
+                }
+                prev = next;
+                Interval.State newState;
+                if (cur.currentAtEnd()) {
+                    // move to handled state (not maintained as a list)
+                    newState = State.Handled;
+                    cur.state = newState;
+                } else {
+                    if (cur.currentFrom() <= from) {
+                        // sort into active list
+                        activeLists.addToListSortedByCurrentFromPositions(binding, cur);
+                        newState = State.Active;
+                    } else {
+                        // sort into inactive list
+                        inactiveLists.addToListSortedByCurrentFromPositions(binding, cur);
+                        newState = State.Inactive;
+                    }
+                    cur.state = newState;
+                    if (prev == cur) {
+                        assert state == newState;
+                        prevprev = prev;
+                        prev = cur.next;
+                    }
+                }
+                intervalMoved(cur, state, newState);
+            } else {
+                prevprev = prev;
+                prev = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Get the next interval from {@linkplain #unhandledLists} which starts before or at
+     * {@code toOpId}. The returned interval is removed and {@link #currentBinding} is set.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledLists} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledLists unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private Interval nextInterval(int toOpId) {
+        RegisterBinding binding;
+        Interval any = unhandledLists.any;
+        Interval fixed = unhandledLists.fixed;
+
+        if (any != Interval.EndMarker) {
+            // intervals may start at same position . prefer fixed interval
+            binding = fixed != Interval.EndMarker && fixed.from() <= any.from() ? RegisterBinding.Fixed : RegisterBinding.Any;
+
+            assert binding == RegisterBinding.Fixed && fixed.from() <= any.from() || binding == RegisterBinding.Any && any.from() <= fixed.from() : "wrong interval!!!";
+            assert any == Interval.EndMarker || fixed == Interval.EndMarker || any.from() != fixed.from() ||
+                            binding == RegisterBinding.Fixed : "if fixed and any-Interval start at same position, fixed must be processed first";
+
+        } else if (fixed != Interval.EndMarker) {
+            binding = RegisterBinding.Fixed;
+        } else {
+            return null;
+        }
+        Interval currentInterval = unhandledLists.get(binding);
+
+        if (toOpId < currentInterval.from()) {
+            return null;
+        }
+
+        currentBinding = binding;
+        unhandledLists.set(binding, currentInterval.next);
+        currentInterval.next = Interval.EndMarker;
+        currentInterval.rewindRange();
+        return currentInterval;
+    }
+
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeLists} and
+     *                {@link #inactiveLists} are populated and {@link Interval#state}s are up to
+     *                date.
+     */
+    @SuppressWarnings("try")
+    protected void walkTo(int toOpId) {
+        assert currentPosition <= toOpId : "can not walk backwards";
+        for (Interval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
+
+            // set currentPosition prior to call of walkTo
+            currentPosition = opId;
+
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(opId);
+
+            // call walkTo even if currentPosition == id
+            walkTo(State.Active, opId);
+            walkTo(State.Inactive, opId);
+
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                currentInterval.state = State.Active;
+                if (activateCurrent(currentInterval)) {
+                    activeLists.addToListSortedByCurrentFromPositions(currentBinding, currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
+
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkTo(State.Active, toOpId);
+            walkTo(State.Inactive, toOpId);
+        }
+    }
+
+    private void intervalMoved(Interval interval, State from, State to) {
+        // intervalMoved() is called whenever an interval moves from one interval list to another.
+        // In the implementation of this method it is prohibited to move the interval to any list.
+        if (Debug.isLogEnabled()) {
+            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString(allocator));
+        }
+    }
+
+    /**
+     * Move {@linkplain #unhandledLists unhandled} stack intervals to
+     * {@linkplain IntervalWalker #activeLists active}.
+     *
+     * Note that for {@linkplain RegisterBinding#Fixed fixed} and {@linkplain RegisterBinding#Any
+     * any} intervals this is done in {@link #nextInterval(int)}.
+     */
+    private void updateUnhandledStackIntervals(int opId) {
+        Interval currentInterval = unhandledLists.get(RegisterBinding.Stack);
+        while (currentInterval != Interval.EndMarker && currentInterval.from() <= opId) {
+            Interval next = currentInterval.next;
+            if (currentInterval.to() > opId) {
+                currentInterval.state = State.Active;
+                activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, currentInterval);
+                intervalMoved(currentInterval, State.Unhandled, State.Active);
+            } else {
+                currentInterval.state = State.Handled;
+                intervalMoved(currentInterval, State.Unhandled, State.Handled);
+            }
+            currentInterval = next;
+        }
+        unhandledLists.set(RegisterBinding.Stack, currentInterval);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java
new file mode 100644
index 0000000..fb1263e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java
@@ -0,0 +1,928 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+import static jdk.vm.ci.code.CodeUtil.isEven;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBinding;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * An implementation of the linear scan register allocator algorithm described in
+ * <a href="http://doi.acm.org/10.1145/1064979.1064998" > "Optimized Interval Splitting in a Linear
+ * Scan Register Allocator"</a> by Christian Wimmer and Hanspeter Moessenboeck.
+ */
+public class LinearScan {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable spill position optimization", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptLSRAOptimizeSpillPosition = new NestedBooleanOptionValue(LIROptimization, true);
+        // @formatter:on
+    }
+
+    public static class BlockData {
+
+        /**
+         * Bit map specifying which operands are live upon entry to this block. These are values
+         * used in this block or any of its successors where such value are not defined in this
+         * block. The bit index of an operand is its {@linkplain LinearScan#operandNumber(Value)
+         * operand number}.
+         */
+        public BitSet liveIn;
+
+        /**
+         * Bit map specifying which operands are live upon exit from this block. These are values
+         * used in a successor block that are either defined in this block or were live upon entry
+         * to this block. The bit index of an operand is its
+         * {@linkplain LinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveOut;
+
+        /**
+         * Bit map specifying which operands are used (before being defined) in this block. That is,
+         * these are the values that are live upon entry to the block. The bit index of an operand
+         * is its {@linkplain LinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveGen;
+
+        /**
+         * Bit map specifying which operands are defined/overwritten in this block. The bit index of
+         * an operand is its {@linkplain LinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveKill;
+    }
+
+    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
+    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+
+    private final LIR ir;
+    private final FrameMapBuilder frameMapBuilder;
+    private final RegisterAttributes[] registerAttributes;
+    private final RegisterArray registers;
+    private final RegisterAllocationConfig regAllocConfig;
+    private final MoveFactory moveFactory;
+
+    private final BlockMap<BlockData> blockData;
+
+    /**
+     * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
+     */
+    private final AbstractBlockBase<?>[] sortedBlocks;
+
+    /**
+     * @see #intervals()
+     */
+    private Interval[] intervals;
+
+    /**
+     * The number of valid entries in {@link #intervals}.
+     */
+    private int intervalsSize;
+
+    /**
+     * The index of the first entry in {@link #intervals} for a
+     * {@linkplain #createDerivedInterval(Interval) derived interval}.
+     */
+    private int firstDerivedIntervalIndex = -1;
+
+    /**
+     * Intervals sorted by {@link Interval#from()}.
+     */
+    private Interval[] sortedIntervals;
+
+    /**
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries should
+     * be retrieved with {@link #instructionForId(int)} as the id is not simply an index into this
+     * array.
+     */
+    private LIRInstruction[] opIdToInstructionMap;
+
+    /**
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the
+     * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved
+     * with {@link #blockForId(int)} as the id is not simply an index into this array.
+     */
+    private AbstractBlockBase<?>[] opIdToBlockMap;
+
+    /**
+     * The {@linkplain #operandNumber(Value) number} of the first variable operand allocated.
+     */
+    private final int firstVariableNumber;
+    /**
+     * Number of variables.
+     */
+    private int numVariables;
+    private final boolean neverSpillConstants;
+
+    protected LinearScan(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, AbstractBlockBase<?>[] sortedBlocks,
+                    boolean neverSpillConstants) {
+        this.ir = res.getLIR();
+        this.moveFactory = spillMoveFactory;
+        this.frameMapBuilder = res.getFrameMapBuilder();
+        this.sortedBlocks = sortedBlocks;
+        this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
+        this.regAllocConfig = regAllocConfig;
+
+        this.registers = target.arch.getRegisters();
+        this.firstVariableNumber = getRegisters().size();
+        this.numVariables = ir.numVariables();
+        this.blockData = new BlockMap<>(ir.getControlFlowGraph());
+        this.neverSpillConstants = neverSpillConstants;
+    }
+
+    public int getFirstLirInstructionId(AbstractBlockBase<?> block) {
+        int result = ir.getLIRforBlock(block).get(0).id();
+        assert result >= 0;
+        return result;
+    }
+
+    public int getLastLirInstructionId(AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+        int result = instructions.get(instructions.size() - 1).id();
+        assert result >= 0;
+        return result;
+    }
+
+    public MoveFactory getSpillMoveFactory() {
+        return moveFactory;
+    }
+
+    protected MoveResolver createMoveResolver() {
+        MoveResolver moveResolver = new MoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    public static boolean isVariableOrRegister(Value value) {
+        return isVariable(value) || isRegister(value);
+    }
+
+    /**
+     * Converts an operand (variable or register) to an index in a flat address space covering all
+     * the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being processed
+     * by this allocator.
+     */
+    int operandNumber(Value operand) {
+        if (isRegister(operand)) {
+            int number = asRegister(operand).number;
+            assert number < firstVariableNumber;
+            return number;
+        }
+        assert isVariable(operand) : operand;
+        return firstVariableNumber + ((Variable) operand).index;
+    }
+
+    /**
+     * Gets the number of operands. This value will increase by 1 for new variable.
+     */
+    int operandSize() {
+        return firstVariableNumber + numVariables;
+    }
+
+    /**
+     * Gets the highest operand number for a register operand. This value will never change.
+     */
+    int maxRegisterNumber() {
+        return firstVariableNumber - 1;
+    }
+
+    public BlockData getBlockData(AbstractBlockBase<?> block) {
+        return blockData.get(block);
+    }
+
+    void initBlockData(AbstractBlockBase<?> block) {
+        blockData.put(block, new BlockData());
+    }
+
+    static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(Interval i) {
+            return isRegister(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(Interval i) {
+            return isVariable(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(Interval i) {
+            return !isRegister(i.operand);
+        }
+    };
+
+    /**
+     * Gets an object describing the attributes of a given register according to this register
+     * configuration.
+     */
+    public RegisterAttributes attributes(Register reg) {
+        return registerAttributes[reg.number];
+    }
+
+    void assignSpillSlot(Interval interval) {
+        /*
+         * Assign the canonical spill slot of the parent (if a part of the interval is already
+         * spilled) or allocate a new spill slot.
+         */
+        if (interval.canMaterialize()) {
+            interval.assignLocation(Value.ILLEGAL);
+        } else if (interval.spillSlot() != null) {
+            interval.assignLocation(interval.spillSlot());
+        } else {
+            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(interval.kind());
+            interval.setSpillSlot(slot);
+            interval.assignLocation(slot);
+        }
+    }
+
+    /**
+     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+     */
+    public Interval[] intervals() {
+        return intervals;
+    }
+
+    void initIntervals() {
+        intervalsSize = operandSize();
+        intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
+    }
+
+    /**
+     * Creates a new interval.
+     *
+     * @param operand the operand for the interval
+     * @return the created interval
+     */
+    Interval createInterval(AllocatableValue operand) {
+        assert isLegal(operand);
+        int operandNumber = operandNumber(operand);
+        Interval interval = new Interval(operand, operandNumber);
+        assert operandNumber < intervalsSize;
+        assert intervals[operandNumber] == null;
+        intervals[operandNumber] = interval;
+        return interval;
+    }
+
+    /**
+     * Creates an interval as a result of splitting or spilling another interval.
+     *
+     * @param source an interval being split of spilled
+     * @return a new interval derived from {@code source}
+     */
+    Interval createDerivedInterval(Interval source) {
+        if (firstDerivedIntervalIndex == -1) {
+            firstDerivedIntervalIndex = intervalsSize;
+        }
+        if (intervalsSize == intervals.length) {
+            intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT) + 1);
+        }
+        intervalsSize++;
+        assert intervalsSize <= intervals.length;
+        /*
+         * Note that these variables are not managed and must therefore never be inserted into the
+         * LIR
+         */
+        Variable variable = new Variable(source.kind(), numVariables++);
+
+        Interval interval = createInterval(variable);
+        assert intervals[intervalsSize - 1] == interval;
+        return interval;
+    }
+
+    // access to block list (sorted in linear scan order)
+    public int blockCount() {
+        return sortedBlocks.length;
+    }
+
+    public AbstractBlockBase<?> blockAt(int index) {
+        return sortedBlocks[index];
+    }
+
+    /**
+     * Gets the size of the {@link BlockData#liveIn} and {@link BlockData#liveOut} sets for a basic
+     * block. These sets do not include any operands allocated as a result of creating
+     * {@linkplain #createDerivedInterval(Interval) derived intervals}.
+     */
+    public int liveSetSize() {
+        return firstDerivedIntervalIndex == -1 ? operandSize() : firstDerivedIntervalIndex;
+    }
+
+    int numLoops() {
+        return ir.getControlFlowGraph().getLoops().size();
+    }
+
+    Interval intervalFor(int operandNumber) {
+        return intervals[operandNumber];
+    }
+
+    public Interval intervalFor(Value operand) {
+        int operandNumber = operandNumber(operand);
+        assert operandNumber < intervalsSize;
+        return intervals[operandNumber];
+    }
+
+    public Interval getOrCreateInterval(AllocatableValue operand) {
+        Interval ret = intervalFor(operand);
+        if (ret == null) {
+            return createInterval(operand);
+        } else {
+            return ret;
+        }
+    }
+
+    void initOpIdMaps(int numInstructions) {
+        opIdToInstructionMap = new LIRInstruction[numInstructions];
+        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
+    }
+
+    void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase<?> block) {
+        opIdToInstructionMap[index] = op;
+        opIdToBlockMap[index] = block;
+    }
+
+    /**
+     * Gets the highest instruction id allocated by this object.
+     */
+    int maxOpId() {
+        assert opIdToInstructionMap.length > 0 : "no operations";
+        return (opIdToInstructionMap.length - 1) << 1;
+    }
+
+    /**
+     * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR
+     * instructions in a method have an index one greater than their linear-scan order predecessor
+     * with the first instruction having an index of 0.
+     */
+    private static int opIdToIndex(int opId) {
+        return opId >> 1;
+    }
+
+    /**
+     * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
+     */
+    public LIRInstruction instructionForId(int opId) {
+        assert isEven(opId) : "opId not even";
+        LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
+        assert instr.id() == opId;
+        return instr;
+    }
+
+    /**
+     * Gets the block containing a given instruction.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return the block containing the instruction denoted by {@code opId}
+     */
+    public AbstractBlockBase<?> blockForId(int opId) {
+        assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range";
+        return opIdToBlockMap[opIdToIndex(opId)];
+    }
+
+    boolean isBlockBegin(int opId) {
+        return opId == 0 || blockForId(opId) != blockForId(opId - 1);
+    }
+
+    boolean coversBlockBegin(int opId1, int opId2) {
+        return blockForId(opId1) != blockForId(opId2);
+    }
+
+    /**
+     * Determines if an {@link LIRInstruction} destroys all caller saved registers.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved
+     *         registers.
+     */
+    boolean hasCall(int opId) {
+        assert isEven(opId) : "opId not even";
+        return instructionForId(opId).destroysCallerSavedRegisters();
+    }
+
+    abstract static class IntervalPredicate {
+
+        abstract boolean apply(Interval i);
+    }
+
+    public boolean isProcessed(Value operand) {
+        return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
+    }
+
+    // * Phase 5: actual register allocation
+
+    private static boolean isSorted(Interval[] intervals) {
+        int from = -1;
+        for (Interval interval : intervals) {
+            assert interval != null;
+            assert from <= interval.from();
+            from = interval.from();
+        }
+        return true;
+    }
+
+    static Interval addToList(Interval first, Interval prev, Interval interval) {
+        Interval newFirst = first;
+        if (prev != null) {
+            prev.next = interval;
+        } else {
+            newFirst = interval;
+        }
+        return newFirst;
+    }
+
+    Interval.Pair createUnhandledLists(IntervalPredicate isList1, IntervalPredicate isList2) {
+        assert isSorted(sortedIntervals) : "interval list is not sorted";
+
+        Interval list1 = Interval.EndMarker;
+        Interval list2 = Interval.EndMarker;
+
+        Interval list1Prev = null;
+        Interval list2Prev = null;
+        Interval v;
+
+        int n = sortedIntervals.length;
+        for (int i = 0; i < n; i++) {
+            v = sortedIntervals[i];
+            if (v == null) {
+                continue;
+            }
+
+            if (isList1.apply(v)) {
+                list1 = addToList(list1, list1Prev, v);
+                list1Prev = v;
+            } else if (isList2 == null || isList2.apply(v)) {
+                list2 = addToList(list2, list2Prev, v);
+                list2Prev = v;
+            }
+        }
+
+        if (list1Prev != null) {
+            list1Prev.next = Interval.EndMarker;
+        }
+        if (list2Prev != null) {
+            list2Prev.next = Interval.EndMarker;
+        }
+
+        assert list1Prev == null || list1Prev.next == Interval.EndMarker : "linear list ends not with sentinel";
+        assert list2Prev == null || list2Prev.next == Interval.EndMarker : "linear list ends not with sentinel";
+
+        return new Interval.Pair(list1, list2);
+    }
+
+    protected void sortIntervalsBeforeAllocation() {
+        int sortedLen = 0;
+        for (Interval interval : intervals) {
+            if (interval != null) {
+                sortedLen++;
+            }
+        }
+
+        Interval[] sortedList = new Interval[sortedLen];
+        int sortedIdx = 0;
+        int sortedFromMax = -1;
+
+        // special sorting algorithm: the original interval-list is almost sorted,
+        // only some intervals are swapped. So this is much faster than a complete QuickSort
+        for (Interval interval : intervals) {
+            if (interval != null) {
+                int from = interval.from();
+
+                if (sortedFromMax <= from) {
+                    sortedList[sortedIdx++] = interval;
+                    sortedFromMax = interval.from();
+                } else {
+                    // the assumption that the intervals are already sorted failed,
+                    // so this interval must be sorted in manually
+                    int j;
+                    for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) {
+                        sortedList[j + 1] = sortedList[j];
+                    }
+                    sortedList[j + 1] = interval;
+                    sortedIdx++;
+                }
+            }
+        }
+        sortedIntervals = sortedList;
+    }
+
+    void sortIntervalsAfterAllocation() {
+        if (firstDerivedIntervalIndex == -1) {
+            // no intervals have been added during allocation, so sorted list is already up to date
+            return;
+        }
+
+        Interval[] oldList = sortedIntervals;
+        Interval[] newList = Arrays.copyOfRange(intervals, firstDerivedIntervalIndex, intervalsSize);
+        int oldLen = oldList.length;
+        int newLen = newList.length;
+
+        // conventional sort-algorithm for new intervals
+        Arrays.sort(newList, (Interval a, Interval b) -> a.from() - b.from());
+
+        // merge old and new list (both already sorted) into one combined list
+        Interval[] combinedList = new Interval[oldLen + newLen];
+        int oldIdx = 0;
+        int newIdx = 0;
+
+        while (oldIdx + newIdx < combinedList.length) {
+            if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) {
+                combinedList[oldIdx + newIdx] = oldList[oldIdx];
+                oldIdx++;
+            } else {
+                combinedList[oldIdx + newIdx] = newList[newIdx];
+                newIdx++;
+            }
+        }
+
+        sortedIntervals = combinedList;
+    }
+
+    // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
+    // instead of returning null
+    public Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) {
+        Interval result = interval.getSplitChildAtOpId(opId, mode, this);
+
+        if (result != null) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
+            }
+            return result;
+        }
+        throw new GraalError("LinearScan: interval is null");
+    }
+
+    static AllocatableValue canonicalSpillOpr(Interval interval) {
+        assert interval.spillSlot() != null : "canonical spill slot not set";
+        return interval.spillSlot();
+    }
+
+    boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
+        Interval interval = intervalFor(operand);
+        assert interval != null : "interval must exist";
+
+        if (opId != -1) {
+            /*
+             * Operands are not changed when an interval is split during allocation, so search the
+             * right interval here.
+             */
+            interval = splitChildAtOpId(interval, opId, mode);
+        }
+
+        return isIllegal(interval.location()) && interval.canMaterialize();
+    }
+
+    boolean isCallerSave(Value operand) {
+        return attributes(asRegister(operand)).isCallerSave();
+    }
+
+    @SuppressWarnings("try")
+    protected void allocate(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
+
+        /*
+         * This is the point to enable debug logging for the whole register allocation.
+         */
+        try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
+            AllocationContext context = new AllocationContext(spillMoveFactory, registerAllocationConfig);
+
+            createLifetimeAnalysisPhase().apply(target, lirGenRes, context);
+
+            try (Scope s = Debug.scope("AfterLifetimeAnalysis", (Object) intervals)) {
+                sortIntervalsBeforeAllocation();
+
+                createRegisterAllocationPhase().apply(target, lirGenRes, context);
+
+                if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
+                    createOptimizeSpillPositionPhase().apply(target, lirGenRes, context);
+                }
+                createResolveDataFlowPhase().apply(target, lirGenRes, context);
+
+                sortIntervalsAfterAllocation();
+
+                if (DetailedAsserts.getValue()) {
+                    verify();
+                }
+                beforeSpillMoveElimination();
+                createSpillMoveEliminationPhase().apply(target, lirGenRes, context);
+                createAssignLocationsPhase().apply(target, lirGenRes, context);
+
+                if (DetailedAsserts.getValue()) {
+                    verifyIntervals();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+    }
+
+    protected void beforeSpillMoveElimination() {
+    }
+
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new LinearScanLifetimeAnalysisPhase(this);
+    }
+
+    protected LinearScanRegisterAllocationPhase createRegisterAllocationPhase() {
+        return new LinearScanRegisterAllocationPhase(this);
+    }
+
+    protected LinearScanOptimizeSpillPositionPhase createOptimizeSpillPositionPhase() {
+        return new LinearScanOptimizeSpillPositionPhase(this);
+    }
+
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new LinearScanResolveDataFlowPhase(this);
+    }
+
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new LinearScanEliminateSpillMovePhase(this);
+    }
+
+    protected LinearScanAssignLocationsPhase createAssignLocationsPhase() {
+        return new LinearScanAssignLocationsPhase(this);
+    }
+
+    @SuppressWarnings("try")
+    public void printIntervals(String label) {
+        if (Debug.isLogEnabled()) {
+            try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
+                for (Interval interval : intervals) {
+                    if (interval != null) {
+                        Debug.log("%s", interval.logString(this));
+                    }
+                }
+
+                try (Indent indent2 = Debug.logAndIndent("Basic Blocks")) {
+                    for (int i = 0; i < blockCount(); i++) {
+                        AbstractBlockBase<?> block = blockAt(i);
+                        Debug.log("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop());
+                    }
+                }
+            }
+        }
+        Debug.dump(Debug.BASIC_LOG_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
+    }
+
+    public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
+        Debug.dump(Debug.INFO_LOG_LEVEL, ir, label);
+    }
+
+    boolean verify() {
+        // (check that all intervals have a correct register and that no registers are overwritten)
+        verifyIntervals();
+
+        verifyRegisters();
+
+        Debug.log("no errors found");
+
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    private void verifyRegisters() {
+        // Enable this logging to get output for the verification process.
+        try (Indent indent = Debug.logAndIndent("verifying register allocation")) {
+            RegisterVerifier verifier = new RegisterVerifier(this);
+            verifier.verify(blockAt(0));
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void verifyIntervals() {
+        try (Indent indent = Debug.logAndIndent("verifying intervals")) {
+            int len = intervalsSize;
+
+            for (int i = 0; i < len; i++) {
+                Interval i1 = intervals[i];
+                if (i1 == null) {
+                    continue;
+                }
+
+                i1.checkSplitChildren();
+
+                if (i1.operandNumber != i) {
+                    Debug.log("Interval %d is on position %d in list", i1.operandNumber, i);
+                    Debug.log(i1.logString(this));
+                    throw new GraalError("");
+                }
+
+                if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
+                    Debug.log("Interval %d has no type assigned", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new GraalError("");
+                }
+
+                if (i1.location() == null) {
+                    Debug.log("Interval %d has no register assigned", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new GraalError("");
+                }
+
+                if (i1.first() == Range.EndMarker) {
+                    Debug.log("Interval %d has no Range", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new GraalError("");
+                }
+
+                for (Range r = i1.first(); r != Range.EndMarker; r = r.next) {
+                    if (r.from >= r.to) {
+                        Debug.log("Interval %d has zero length range", i1.operandNumber);
+                        Debug.log(i1.logString(this));
+                        throw new GraalError("");
+                    }
+                }
+
+                for (int j = i + 1; j < len; j++) {
+                    Interval i2 = intervals[j];
+                    if (i2 == null) {
+                        continue;
+                    }
+
+                    // special intervals that are created in MoveResolver
+                    // . ignore them because the range information has no meaning there
+                    if (i1.from() == 1 && i1.to() == 2) {
+                        continue;
+                    }
+                    if (i2.from() == 1 && i2.to() == 2) {
+                        continue;
+                    }
+                    Value l1 = i1.location();
+                    Value l2 = i2.location();
+                    if (i1.intersects(i2) && !isIllegal(l1) && (l1.equals(l2))) {
+                        throw GraalError.shouldNotReachHere(String.format("Intervals %d and %d overlap and have the same register assigned\n%s\n%s", i1.operandNumber, i2.operandNumber,
+                                        i1.logString(this), i2.logString(this)));
+                    }
+                }
+            }
+        }
+    }
+
+    class CheckConsumer implements ValueConsumer {
+
+        boolean ok;
+        Interval curInterval;
+
+        @Override
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isRegister(operand)) {
+                if (intervalFor(operand) == curInterval) {
+                    ok = true;
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    void verifyNoOopsInFixedIntervals() {
+        try (Indent indent = Debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
+            CheckConsumer checkConsumer = new CheckConsumer();
+
+            Interval fixedIntervals;
+            Interval otherIntervals;
+            fixedIntervals = createUnhandledLists(IS_PRECOLORED_INTERVAL, null).first;
+            // to ensure a walking until the last instruction id, add a dummy interval
+            // with a high operation id
+            otherIntervals = new Interval(Value.ILLEGAL, -1);
+            otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
+            IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals);
+
+            for (AbstractBlockBase<?> block : sortedBlocks) {
+                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+
+                for (int j = 0; j < instructions.size(); j++) {
+                    LIRInstruction op = instructions.get(j);
+
+                    if (op.hasState()) {
+                        iw.walkBefore(op.id());
+                        boolean checkLive = true;
+
+                        /*
+                         * Make sure none of the fixed registers is live across an oopmap since we
+                         * can't handle that correctly.
+                         */
+                        if (checkLive) {
+                            for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) {
+                                if (interval.currentTo() > op.id() + 1) {
+                                    /*
+                                     * This interval is live out of this op so make sure that this
+                                     * interval represents some value that's referenced by this op
+                                     * either as an input or output.
+                                     */
+                                    checkConsumer.curInterval = interval;
+                                    checkConsumer.ok = false;
+
+                                    op.visitEachInput(checkConsumer);
+                                    op.visitEachAlive(checkConsumer);
+                                    op.visitEachTemp(checkConsumer);
+                                    op.visitEachOutput(checkConsumer);
+
+                                    assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public LIR getLIR() {
+        return ir;
+    }
+
+    public FrameMapBuilder getFrameMapBuilder() {
+        return frameMapBuilder;
+    }
+
+    public AbstractBlockBase<?>[] sortedBlocks() {
+        return sortedBlocks;
+    }
+
+    public RegisterArray getRegisters() {
+        return registers;
+    }
+
+    public RegisterAllocationConfig getRegisterAllocationConfig() {
+        return regAllocConfig;
+    }
+
+    public boolean callKillsRegisters() {
+        return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
+    }
+
+    boolean neverSpillConstants() {
+        return neverSpillConstants;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java
new file mode 100644
index 0000000..1be5383
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Phase 7: Assign register numbers back to LIR.
+ */
+public class LinearScanAssignLocationsPhase extends AllocationPhase {
+
+    protected final LinearScan allocator;
+
+    public LinearScanAssignLocationsPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        assignLocations();
+    }
+
+    /**
+     * Assigns the allocated location for an LIR instruction operand back into the instruction.
+     *
+     * @param op current {@link LIRInstruction}
+     * @param operand an LIR instruction operand
+     * @param mode the usage mode for {@code operand} by the instruction
+     * @return the location assigned for the operand
+     */
+    protected Value colorLirOperand(LIRInstruction op, Variable operand, OperandMode mode) {
+        int opId = op.id();
+        Interval interval = allocator.intervalFor(operand);
+        assert interval != null : "interval must exist";
+
+        if (opId != -1) {
+            if (DetailedAsserts.getValue()) {
+                AbstractBlockBase<?> block = allocator.blockForId(opId);
+                if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) {
+                    /*
+                     * Check if spill moves could have been appended at the end of this block, but
+                     * before the branch instruction. So the split child information for this branch
+                     * would be incorrect.
+                     */
+                    LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
+                    if (instr instanceof StandardOp.JumpOp) {
+                        if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                            assert false : String.format(
+                                            "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s",
+                                            block, instr, operand);
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Operands are not changed when an interval is split during allocation, so search the
+             * right interval here.
+             */
+            interval = allocator.splitChildAtOpId(interval, opId, mode);
+        }
+
+        if (isIllegal(interval.location()) && interval.canMaterialize()) {
+            assert mode != OperandMode.DEF;
+            return new ConstantValue(interval.kind(), interval.getMaterializedValue());
+        }
+        return interval.location();
+    }
+
+    /**
+     * @param op
+     * @param operand
+     * @param valueMode
+     * @param flags
+     * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
+     */
+    private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+        if (isVirtualStackSlot(operand)) {
+            return operand;
+        }
+        int tempOpId = op.id();
+        OperandMode mode = OperandMode.USE;
+        AbstractBlockBase<?> block = allocator.blockForId(tempOpId);
+        if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) {
+            /*
+             * Generating debug information for the last instruction of a block. If this instruction
+             * is a branch, spill moves are inserted before this branch and so the wrong operand
+             * would be returned (spill moves at block boundaries are not considered in the live
+             * ranges of intervals).
+             *
+             * Solution: use the first opId of the branch target block instead.
+             */
+            final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                    tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors()[0]);
+                    mode = OperandMode.DEF;
+                }
+            }
+        }
+
+        /*
+         * Get current location of operand. The operand must be live because debug information is
+         * considered when building the intervals if the interval is not live, colorLirOperand will
+         * cause an assert on failure.
+         */
+        Value result = colorLirOperand(op, (Variable) operand, mode);
+        assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isJavaConstant(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls";
+        return result;
+    }
+
+    private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
+        info.forEachState(op, this::debugInfoProcedure);
+    }
+
+    private void assignLocations(List<LIRInstruction> instructions) {
+        int numInst = instructions.size();
+        boolean hasDead = false;
+
+        for (int j = 0; j < numInst; j++) {
+            final LIRInstruction op = instructions.get(j);
+            if (op == null) {
+                /*
+                 * this can happen when spill-moves are removed in eliminateSpillMoves
+                 */
+                hasDead = true;
+            } else if (assignLocations(op)) {
+                instructions.set(j, null);
+                hasDead = true;
+            }
+        }
+
+        if (hasDead) {
+            // Remove null values from the list.
+            instructions.removeAll(Collections.singleton(null));
+        }
+    }
+
+    /**
+     * Assigns the operand of an {@link LIRInstruction}.
+     *
+     * @param op The {@link LIRInstruction} that should be colored.
+     * @return {@code true} if the instruction should be deleted.
+     */
+    protected boolean assignLocations(LIRInstruction op) {
+        assert op != null;
+
+        InstructionValueProcedure assignProc = (inst, operand, mode, flags) -> isVariable(operand) ? colorLirOperand(inst, (Variable) operand, mode) : operand;
+        // remove useless moves
+        if (op instanceof MoveOp) {
+            AllocatableValue result = ((MoveOp) op).getResult();
+            if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
+                /*
+                 * This happens if a materializable interval is originally not spilled but then
+                 * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
+                 * interval this move operation was already generated.
+                 */
+                return true;
+            }
+        }
+
+        op.forEachInput(assignProc);
+        op.forEachAlive(assignProc);
+        op.forEachTemp(assignProc);
+        op.forEachOutput(assignProc);
+
+        // compute reference map and debug information
+        op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+
+        // remove useless moves
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (move.getInput().equals(move.getResult())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("try")
+    private void assignLocations() {
+        try (Indent indent = Debug.logAndIndent("assign locations")) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
+                    assignLocations(allocator.getLIR().getLIRforBlock(block));
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java
new file mode 100644
index 0000000..9233eaf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan.IntervalPredicate;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public class LinearScanEliminateSpillMovePhase extends AllocationPhase {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable spill move elimination.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptLSRAEliminateSpillMoves = new NestedBooleanOptionValue(LIROptimization, true);
+        // @formatter:on
+    }
+
+    private static final IntervalPredicate mustStoreAtDefinition = new LinearScan.IntervalPredicate() {
+
+        @Override
+        public boolean apply(Interval i) {
+            return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition;
+        }
+    };
+
+    protected final LinearScan allocator;
+
+    protected LinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        eliminateSpillMoves();
+    }
+
+    /**
+     * @return the index of the first instruction that is of interest for
+     *         {@link #eliminateSpillMoves()}
+     */
+    protected int firstInstructionOfInterest() {
+        // skip the first because it is always a label
+        return 1;
+    }
+
+    // called once before assignment of register numbers
+    @SuppressWarnings("try")
+    void eliminateSpillMoves() {
+        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) {
+
+            /*
+             * collect all intervals that must be stored after their definition. The list is sorted
+             * by Interval.spillDefinitionPos.
+             */
+            Interval interval;
+            interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).first;
+            if (DetailedAsserts.getValue()) {
+                checkIntervals(interval);
+            }
+
+            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                    int numInst = instructions.size();
+
+                    // iterate all instructions of the block.
+                    for (int j = firstInstructionOfInterest(); j < numInst; j++) {
+                        LIRInstruction op = instructions.get(j);
+                        int opId = op.id();
+
+                        if (opId == -1) {
+                            MoveOp move = (MoveOp) op;
+                            /*
+                             * Remove move from register to stack if the stack slot is guaranteed to
+                             * be correct. Only moves that have been inserted by LinearScan can be
+                             * removed.
+                             */
+                            if (Options.LIROptLSRAEliminateSpillMoves.getValue() && canEliminateSpillMove(block, move)) {
+                                /*
+                                 * Move target is a stack slot that is always correct, so eliminate
+                                 * instruction.
+                                 */
+                                if (Debug.isLogEnabled()) {
+                                    if (move instanceof ValueMoveOp) {
+                                        ValueMoveOp vmove = (ValueMoveOp) move;
+                                        Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
+                                                        allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
+                                    } else {
+                                        LoadConstantOp load = (LoadConstantOp) move;
+                                        Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(), block);
+                                    }
+                                }
+
+                                // null-instructions are deleted by assignRegNum
+                                instructions.set(j, null);
+                            }
+
+                        } else {
+                            /*
+                             * Insert move from register to stack just after the beginning of the
+                             * interval.
+                             */
+                            assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order";
+                            assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
+
+                            while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) {
+                                if (!interval.canMaterialize()) {
+                                    if (!insertionBuffer.initialized()) {
+                                        /*
+                                         * prepare insertion buffer (appended when all instructions
+                                         * in the block are processed)
+                                         */
+                                        insertionBuffer.init(instructions);
+                                    }
+
+                                    AllocatableValue fromLocation = interval.location();
+                                    AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
+                                    if (!fromLocation.equals(toLocation)) {
+
+                                        assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
+                                                        interval.spillState();
+                                        assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
+
+                                        LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                        insertionBuffer.append(j + 1, move);
+
+                                        if (Debug.isLogEnabled()) {
+                                            Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                        }
+                                    }
+                                }
+                                interval = interval.next;
+                            }
+                        }
+                    } // end of instruction iteration
+
+                    if (insertionBuffer.initialized()) {
+                        insertionBuffer.finish();
+                    }
+                }
+            } // end of block iteration
+
+            assert interval == Interval.EndMarker : "missed an interval";
+        }
+    }
+
+    /**
+     * @param block The block {@code move} is located in.
+     * @param move Spill move.
+     */
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
+
+        Interval curInterval = allocator.intervalFor(move.getResult());
+
+        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
+            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+            return true;
+        }
+        return false;
+    }
+
+    private static void checkIntervals(Interval interval) {
+        Interval prev = null;
+        Interval temp = interval;
+        while (temp != Interval.EndMarker) {
+            assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos";
+            if (prev != null) {
+                assert temp.from() >= prev.from() : "intervals not sorted";
+                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
+            }
+
+            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
+            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
+            assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            }
+
+            prev = temp;
+            temp = temp.next;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanIntervalDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanIntervalDumper.java
new file mode 100644
index 0000000..9092cf6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanIntervalDumper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.lir.alloc.lsra.Interval.UsePosList;
+import org.graalvm.compiler.lir.debug.IntervalDumper;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+class LinearScanIntervalDumper implements IntervalDumper {
+    private final Interval[] intervals;
+
+    LinearScanIntervalDumper(Interval[] intervals) {
+        this.intervals = intervals;
+    }
+
+    @Override
+    public void visitIntervals(IntervalVisitor visitor) {
+        for (Interval interval : intervals) {
+            if (interval != null) {
+                printInterval(interval, visitor);
+            }
+        }
+    }
+
+    private static void printInterval(Interval interval, IntervalVisitor visitor) {
+        Value hint = interval.locationHint(false) != null ? interval.locationHint(false).operand : null;
+        AllocatableValue operand = interval.operand;
+        String type = isRegister(operand) ? "fixed" : operand.getValueKind().getPlatformKind().toString();
+        visitor.visitIntervalStart(interval.splitParent().operand, operand, interval.location(), hint, type);
+
+        // print ranges
+        Range cur = interval.first();
+        while (cur != Range.EndMarker) {
+            visitor.visitRange(cur.from, cur.to);
+            cur = cur.next;
+            assert cur != null : "range list not closed with range sentinel";
+        }
+
+        // print use positions
+        int prev = -1;
+        UsePosList usePosList = interval.usePosList();
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            assert prev < usePosList.usePos(i) : "use positions not sorted";
+            visitor.visitUsePos(usePosList.usePos(i), usePosList.registerPriority(i));
+            prev = usePosList.usePos(i);
+        }
+
+        visitor.visitIntervalEnd(interval.spillState());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java
new file mode 100644
index 0000000..27d4239
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.debug.LIRGenerationDebugContext.getSourceForOperandFromDebugContext;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayDeque;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.BitMap2D;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
+
+    protected final LinearScan allocator;
+
+    /**
+     * @param linearScan
+     */
+    protected LinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        allocator = linearScan;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        numberInstructions();
+        allocator.printLir("Before register allocation", true);
+        computeLocalLiveSets();
+        computeGlobalLiveSets();
+        buildIntervals();
+    }
+
+    /**
+     * Bit set for each variable that is contained in each loop.
+     */
+    private BitMap2D intervalInLoop;
+
+    boolean isIntervalInLoop(int interval, int loop) {
+        return intervalInLoop.at(interval, loop);
+    }
+
+    /**
+     * Numbers all instructions in all blocks. The numbering follows the
+     * {@linkplain ComputeBlockOrder linear scan order}.
+     */
+    protected void numberInstructions() {
+
+        allocator.initIntervals();
+
+        ValueConsumer setVariableConsumer = (value, mode, flags) -> {
+            if (isVariable(value)) {
+                allocator.getOrCreateInterval(asVariable(value));
+            }
+        };
+
+        // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
+        int numInstructions = 0;
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            numInstructions += allocator.getLIR().getLIRforBlock(block).size();
+        }
+
+        // initialize with correct length
+        allocator.initOpIdMaps(numInstructions);
+
+        int opId = 0;
+        int index = 0;
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            allocator.initBlockData(block);
+
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+
+            int numInst = instructions.size();
+            for (int j = 0; j < numInst; j++) {
+                LIRInstruction op = instructions.get(j);
+                op.setId(opId);
+
+                allocator.putOpIdMaps(index, op, block);
+                assert allocator.instructionForId(opId) == op : "must match";
+
+                op.visitEachTemp(setVariableConsumer);
+                op.visitEachOutput(setVariableConsumer);
+
+                index++;
+                opId += 2; // numbering of lirOps by two
+            }
+        }
+        assert index == numInstructions : "must match";
+        assert (index << 1) == opId : "must match: " + (index << 1);
+    }
+
+    /**
+     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
+     * separately for each block.
+     */
+    @SuppressWarnings("try")
+    void computeLocalLiveSets() {
+        int liveSize = allocator.liveSetSize();
+
+        intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops());
+
+        // iterate all blocks
+        for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) {
+
+                final BitSet liveGen = new BitSet(liveSize);
+                final BitSet liveKill = new BitSet(liveSize);
+
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                int numInst = instructions.size();
+
+                ValueConsumer useConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
+                        int operandNum = allocator.operandNumber(operand);
+                        if (!liveKill.get(operandNum)) {
+                            liveGen.set(operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen for operand %d(%s)", operandNum, operand);
+                            }
+                        }
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
+                        }
+                    }
+
+                    if (DetailedAsserts.getValue()) {
+                        verifyInput(block, liveKill, operand);
+                    }
+                };
+                ValueConsumer stateConsumer = (operand, mode, flags) -> {
+                    if (LinearScan.isVariableOrRegister(operand)) {
+                        int operandNum = allocator.operandNumber(operand);
+                        if (!liveKill.get(operandNum)) {
+                            liveGen.set(operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen in state for operand %d(%s)", operandNum, operand);
+                            }
+                        }
+                    }
+                };
+                ValueConsumer defConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
+                        int varNum = allocator.operandNumber(operand);
+                        liveKill.set(varNum);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("liveKill for operand %d(%s)", varNum, operand);
+                        }
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(varNum, block.getLoop().getIndex());
+                        }
+                    }
+
+                    if (DetailedAsserts.getValue()) {
+                        /*
+                         * Fixed intervals are never live at block boundaries, so they need not be
+                         * processed in live sets. Process them only in debug mode so that this can
+                         * be checked
+                         */
+                        verifyTemp(liveKill, operand);
+                    }
+                };
+
+                // iterate all instructions of the block
+                for (int j = 0; j < numInst; j++) {
+                    final LIRInstruction op = instructions.get(j);
+
+                    try (Indent indent2 = Debug.logAndIndent("handle op %d: %s", op.id(), op)) {
+                        op.visitEachInput(useConsumer);
+                        op.visitEachAlive(useConsumer);
+                        /*
+                         * Add uses of live locals from interpreter's point of view for proper debug
+                         * information generation.
+                         */
+                        op.visitEachState(stateConsumer);
+                        op.visitEachTemp(defConsumer);
+                        op.visitEachOutput(defConsumer);
+                    }
+                } // end of instruction iteration
+
+                BlockData blockSets = allocator.getBlockData(block);
+                blockSets.liveGen = liveGen;
+                blockSets.liveKill = liveKill;
+                blockSets.liveIn = new BitSet(liveSize);
+                blockSets.liveOut = new BitSet(liveSize);
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
+                    Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+                }
+
+            }
+        } // end of block iteration
+    }
+
+    private void verifyTemp(BitSet liveKill, Value operand) {
+        /*
+         * Fixed intervals are never live at block boundaries, so they need not be processed in live
+         * sets. Process them only in debug mode so that this can be checked
+         */
+        if (isRegister(operand)) {
+            if (allocator.isProcessed(operand)) {
+                liveKill.set(allocator.operandNumber(operand));
+            }
+        }
+    }
+
+    private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) {
+        /*
+         * Fixed intervals are never live at block boundaries, so they need not be processed in live
+         * sets. This is checked by these assertions to be sure about it. The entry block may have
+         * incoming values in registers, which is ok.
+         */
+        if (isRegister(operand) && block != allocator.getLIR().getControlFlowGraph().getStartBlock()) {
+            if (allocator.isProcessed(operand)) {
+                assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register " + asRegister(operand) + " that is not defined in this block " + block;
+            }
+        }
+    }
+
+    /**
+     * Performs a backward dataflow analysis to compute global live sets (i.e.
+     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
+     */
+    @SuppressWarnings("try")
+    protected void computeGlobalLiveSets() {
+        try (Indent indent = Debug.logAndIndent("compute global live sets")) {
+            int numBlocks = allocator.blockCount();
+            boolean changeOccurred;
+            boolean changeOccurredInBlock;
+            int iterationCount = 0;
+            BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations
+
+            /*
+             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
+             * The loop is executed until a fixpoint is reached (no changes in an iteration).
+             */
+            do {
+                changeOccurred = false;
+
+                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
+
+                    // iterate all blocks in reverse order
+                    for (int i = numBlocks - 1; i >= 0; i--) {
+                        AbstractBlockBase<?> block = allocator.blockAt(i);
+                        BlockData blockSets = allocator.getBlockData(block);
+
+                        changeOccurredInBlock = false;
+
+                        /*
+                         * liveOut(block) is the union of liveIn(sux), for successors sux of block.
+                         */
+                        int n = block.getSuccessorCount();
+                        if (n > 0) {
+                            liveOut.clear();
+                            // block has successors
+                            if (n > 0) {
+                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                    liveOut.or(allocator.getBlockData(successor).liveIn);
+                                }
+                            }
+
+                            if (!blockSets.liveOut.equals(liveOut)) {
+                                /*
+                                 * A change occurred. Swap the old and new live out sets to avoid
+                                 * copying.
+                                 */
+                                BitSet temp = blockSets.liveOut;
+                                blockSets.liveOut = liveOut;
+                                liveOut = temp;
+
+                                changeOccurred = true;
+                                changeOccurredInBlock = true;
+                            }
+                        }
+
+                        if (iterationCount == 0 || changeOccurredInBlock) {
+                            /*
+                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
+                             * !liveKill(block)).
+                             *
+                             * Note: liveIn has to be computed only in first iteration or if liveOut
+                             * has changed!
+                             */
+                            BitSet liveIn = blockSets.liveIn;
+                            liveIn.clear();
+                            liveIn.or(blockSets.liveOut);
+                            liveIn.andNot(blockSets.liveKill);
+                            liveIn.or(blockSets.liveGen);
+
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            }
+                        }
+                    }
+                    iterationCount++;
+
+                    if (changeOccurred && iterationCount > 50) {
+                        /*
+                         * Very unlikely should never happen: If it happens we cannot guarantee it
+                         * won't happen again.
+                         */
+                        throw new PermanentBailoutException("too many iterations in computeGlobalLiveSets");
+                    }
+                }
+            } while (changeOccurred);
+
+            if (DetailedAsserts.getValue()) {
+                verifyLiveness();
+            }
+
+            // check that the liveIn set of the first block is empty
+            AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock();
+            if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
+                if (DetailedAsserts.getValue()) {
+                    reportFailure(numBlocks);
+                }
+                // bailout if this occurs in product mode.
+                throw new GraalError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void reportFailure(int numBlocks) {
+        try (Scope s = Debug.forceLog()) {
+            try (Indent indent = Debug.logAndIndent("report failure")) {
+
+                BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn;
+                try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
+                    for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+                        Interval interval = allocator.intervalFor(operandNum);
+                        if (interval != null) {
+                            Value operand = interval.operand;
+                            Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand));
+                        } else {
+                            Debug.log("var %d; missing operand", operandNum);
+                        }
+                    }
+                }
+
+                // print some additional information to simplify debugging
+                for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
+                    Interval interval = allocator.intervalFor(operandNum);
+                    Value operand = null;
+                    Object valueForOperandFromDebugContext = null;
+                    if (interval != null) {
+                        operand = interval.operand;
+                        valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand);
+                    }
+                    try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
+
+                        Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
+                        HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
+                        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                            if (allocator.getBlockData(block).liveGen.get(operandNum)) {
+                                usedIn.add(block);
+                                try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
+                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
+                                        try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
+                                            ins.forEachState((liveStateOperand, mode, flags) -> {
+                                                Debug.log("operand=%s", liveStateOperand);
+                                                return liveStateOperand;
+                                            });
+                                        }
+                                    }
+                                }
+                            }
+                            if (allocator.getBlockData(block).liveKill.get(operandNum)) {
+                                definedIn.add(block);
+                                try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) {
+                                    for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
+                                        Debug.log("%d: %s", ins.id(), ins);
+                                    }
+                                }
+                            }
+                        }
+
+                        int[] hitCount = new int[numBlocks];
+
+                        while (!definedIn.isEmpty()) {
+                            AbstractBlockBase<?> block = definedIn.removeFirst();
+                            usedIn.remove(block);
+                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                if (successor.isLoopHeader()) {
+                                    if (!block.isLoopEnd()) {
+                                        definedIn.add(successor);
+                                    }
+                                } else {
+                                    if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
+                                        definedIn.add(successor);
+                                    }
+                                }
+                            }
+                        }
+                        try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) {
+                            for (AbstractBlockBase<?> block : usedIn) {
+                                Debug.log("B%d", block.getId());
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected void verifyLiveness() {
+        /*
+         * Check that fixed intervals are not live at block boundaries (live set must be empty at
+         * fixed intervals).
+         */
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+            for (int j = 0; j <= allocator.maxRegisterNumber(); j++) {
+                assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
+                assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
+                assert !allocator.getBlockData(block).liveGen.get(j) : "liveGen set of fixed register must be empty";
+            }
+        }
+    }
+
+    protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, ValueKind<?> kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        interval.addRange(from, to);
+
+        // Register use position at even instruction id.
+        interval.addUsePos(to & ~1, registerPriority);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
+        }
+    }
+
+    protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, ValueKind<?> kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        interval.addRange(tempPos, tempPos + 1);
+        interval.addUsePos(tempPos, registerPriority);
+        interval.addMaterializationValue(null);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+        }
+    }
+
+    protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, ValueKind<?> kind) {
+        if (!allocator.isProcessed(operand)) {
+            return;
+        }
+        int defPos = op.id();
+
+        Interval interval = allocator.getOrCreateInterval(operand);
+        if (!kind.equals(LIRKind.Illegal)) {
+            interval.setKind(kind);
+        }
+
+        Range r = interval.first();
+        if (r.from <= defPos) {
+            /*
+             * Update the starting point (when a range is first created for a use, its start is the
+             * beginning of the current block until a def is encountered).
+             */
+            r.from = defPos;
+            interval.addUsePos(defPos, registerPriority);
+
+        } else {
+            /*
+             * Dead value - make vacuous interval also add register priority for dead intervals
+             */
+            interval.addRange(defPos, defPos + 1);
+            interval.addUsePos(defPos, registerPriority);
+            if (Debug.isLogEnabled()) {
+                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+            }
+        }
+
+        changeSpillDefinitionPos(op, operand, interval, defPos);
+        if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
+            // detection of method-parameters and roundfp-results
+            interval.setSpillState(SpillState.StartInMemory);
+        }
+        interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+        }
+    }
+
+    /**
+     * Optimizes moves related to incoming stack based arguments. The interval for the destination
+     * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
+     */
+    protected void handleMethodArguments(LIRInstruction op) {
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (optimizeMethodArgument(move.getInput())) {
+                StackSlot slot = asStackSlot(move.getInput());
+                if (DetailedAsserts.getValue()) {
+                    assert op.id() > 0 : "invalid id";
+                    assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block";
+                    assert isVariable(move.getResult()) : "result of move must be a variable";
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("found move from stack slot %s to %s", slot, move.getResult());
+                    }
+                }
+
+                Interval interval = allocator.intervalFor(move.getResult());
+                interval.setSpillSlot(slot);
+                interval.assignLocation(slot);
+            }
+        }
+    }
+
+    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) {
+
+            op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+                    Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+                    /* hints always point from def to use */
+                    if (hintAtDef) {
+                        to.setLocationHint(from);
+                    } else {
+                        from.setLocationHint(to);
+                    }
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                    }
+
+                    return registerHint;
+                }
+                return null;
+            });
+        }
+    }
+
+    /**
+     * Eliminates moves from register to stack if the stack slot is known to be correct.
+     *
+     * @param op
+     * @param operand
+     */
+    protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) {
+        assert interval.isSplitParent() : "can only be called for split parents";
+
+        switch (interval.spillState()) {
+            case NoDefinitionFound:
+                assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                interval.setSpillDefinitionPos(defPos);
+                interval.setSpillState(SpillState.NoSpillStore);
+                break;
+
+            case NoSpillStore:
+                assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                if (defPos < interval.spillDefinitionPos() - 2) {
+                    // second definition found, so no spill optimization possible for this interval
+                    interval.setSpillState(SpillState.NoOptimization);
+                } else {
+                    // two consecutive definitions (because of two-operand LIR form)
+                    assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                }
+                break;
+
+            case NoOptimization:
+                // nothing to do
+                break;
+
+            default:
+                throw GraalError.shouldNotReachHere("other states not allowed at this time");
+        }
+    }
+
+    private static boolean optimizeMethodArgument(Value value) {
+        /*
+         * Object method arguments that are passed on the stack are currently not optimized because
+         * this requires that the runtime visits method arguments during stack walking.
+         */
+        return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && LIRKind.isValue(value);
+    }
+
+    /**
+     * Determines the register priority for an instruction's output/result operand.
+     */
+    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (optimizeMethodArgument(move.getInput())) {
+                return RegisterPriority.None;
+            }
+        }
+
+        // all other operands require a register
+        return RegisterPriority.MustHaveRegister;
+    }
+
+    /**
+     * Determines the priority which with an instruction's input operand will be allocated a
+     * register.
+     */
+    protected static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+        if (flags.contains(OperandFlag.STACK)) {
+            return RegisterPriority.ShouldHaveRegister;
+        }
+        // all other operands require a register
+        return RegisterPriority.MustHaveRegister;
+    }
+
+    @SuppressWarnings("try")
+    protected void buildIntervals() {
+
+        try (Indent indent = Debug.logAndIndent("build intervals")) {
+            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getValueKind());
+                    addRegisterHint(op, operand, mode, flags, true);
+                }
+            };
+
+            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getValueKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getValueKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getValueKind());
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            };
+
+            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
+                if (LinearScan.isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getValueKind());
+                }
+            };
+
+            // create a list with all caller-save registers (cpu, fpu, xmm)
+            RegisterArray callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
+
+            // iterate all blocks in reverse order
+            for (int i = allocator.blockCount() - 1; i >= 0; i--) {
+
+                AbstractBlockBase<?> block = allocator.blockAt(i);
+                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
+
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                    final int blockFrom = allocator.getFirstLirInstructionId(block);
+                    int blockTo = allocator.getLastLirInstructionId(block);
+
+                    assert blockFrom == instructions.get(0).id();
+                    assert blockTo == instructions.get(instructions.size() - 1).id();
+
+                    // Update intervals for operands live at the end of this block;
+                    BitSet live = allocator.getBlockData(block).liveOut;
+                    for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
+                        assert live.get(operandNum) : "should not stop here otherwise";
+                        AllocatableValue operand = allocator.intervalFor(operandNum).operand;
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("live in %d: %s", operandNum, operand);
+                        }
+
+                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
+
+                        /*
+                         * Add special use positions for loop-end blocks when the interval is used
+                         * anywhere inside this loop. It's possible that the block was part of a
+                         * non-natural loop, so it might have an invalid loop index.
+                         */
+                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
+                            allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
+                        }
+                    }
+
+                    /*
+                     * Iterate all instructions of the block in reverse order. definitions of
+                     * intervals are processed before uses.
+                     */
+                    for (int j = instructions.size() - 1; j >= 0; j--) {
+                        final LIRInstruction op = instructions.get(j);
+                        final int opId = op.id();
+
+                        try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
+
+                            // add a temp range for each register if operation destroys
+                            // caller-save registers
+                            if (op.destroysCallerSavedRegisters()) {
+                                for (Register r : callerSaveRegs) {
+                                    if (allocator.attributes(r).isAllocatable()) {
+                                        addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
+                                    }
+                                }
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("operation destroys all caller-save registers");
+                                }
+                            }
+
+                            op.visitEachOutput(outputConsumer);
+                            op.visitEachTemp(tempConsumer);
+                            op.visitEachAlive(aliveConsumer);
+                            op.visitEachInput(inputConsumer);
+
+                            /*
+                             * Add uses of live locals from interpreter's point of view for proper
+                             * debug information generation. Treat these operands as temp values (if
+                             * the live range is extended to a call site, the value would be in a
+                             * register at the call otherwise).
+                             */
+                            op.visitEachState(stateProc);
+
+                            // special steps for some instructions (especially moves)
+                            handleMethodArguments(op);
+
+                        }
+
+                    } // end of instruction iteration
+                }
+            } // end of block iteration
+
+            /*
+             * Add the range [0, 1] to all fixed intervals. the register allocator need not handle
+             * unhandled fixed intervals.
+             */
+            for (Interval interval : allocator.intervals()) {
+                if (interval != null && isRegister(interval.operand)) {
+                    interval.addRange(0, 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a value for a interval definition, which can be used for re-materialization.
+     *
+     * @param op An instruction which defines a value
+     * @param operand The destination operand of the instruction
+     * @param interval The interval for this defined value.
+     * @return Returns the value which is moved to the instruction and which can be reused at all
+     *         reload-locations in case the interval of this instruction is spilled. Currently this
+     *         can only be a {@link JavaConstant}.
+     */
+    protected Constant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
+        if (op instanceof LoadConstantOp) {
+            LoadConstantOp move = (LoadConstantOp) op;
+
+            if (!allocator.neverSpillConstants()) {
+                /*
+                 * Check if the interval has any uses which would accept an stack location (priority
+                 * == ShouldHaveRegister). Rematerialization of such intervals can result in a
+                 * degradation, because rematerialization always inserts a constant load, even if
+                 * the value is not needed in a register.
+                 */
+                Interval.UsePosList usePosList = interval.usePosList();
+                int numUsePos = usePosList.size();
+                for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
+                    Interval.RegisterPriority priority = usePosList.registerPriority(useIdx);
+                    if (priority == Interval.RegisterPriority.ShouldHaveRegister) {
+                        return null;
+                    }
+                }
+            }
+            return move.getConstant();
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java
new file mode 100644
index 0000000..9fd9e82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.commonDominator;
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.dominates;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+
+import java.util.Iterator;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
+
+    private static final DebugCounter betterSpillPos = Debug.counter("BetterSpillPosition");
+    private static final DebugCounter betterSpillPosWithLowerProbability = Debug.counter("BetterSpillPositionWithLowerProbability");
+
+    private final LinearScan allocator;
+
+    LinearScanOptimizeSpillPositionPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        optimizeSpillPosition();
+        allocator.printIntervals("After optimize spill position");
+    }
+
+    @SuppressWarnings("try")
+    private void optimizeSpillPosition() {
+        try (Indent indent0 = Debug.logAndIndent("OptimizeSpillPositions")) {
+            LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.getLIR().linearScanOrder().length];
+            for (Interval interval : allocator.intervals()) {
+                optimizeInterval(insertionBuffers, interval);
+            }
+            for (LIRInsertionBuffer insertionBuffer : insertionBuffers) {
+                if (insertionBuffer != null) {
+                    assert insertionBuffer.initialized() : "Insertion buffer is nonnull but not initialized!";
+                    insertionBuffer.finish();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void optimizeInterval(LIRInsertionBuffer[] insertionBuffers, Interval interval) {
+        if (interval == null || !interval.isSplitParent() || interval.spillState() != SpillState.SpillInDominator) {
+            return;
+        }
+        AbstractBlockBase<?> defBlock = allocator.blockForId(interval.spillDefinitionPos());
+        AbstractBlockBase<?> spillBlock = null;
+        Interval firstSpillChild = null;
+        try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) {
+            for (Interval splitChild : interval.getSplitChildren()) {
+                if (isStackSlotValue(splitChild.location())) {
+                    if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) {
+                        firstSpillChild = splitChild;
+                    } else {
+                        assert firstSpillChild.from() < splitChild.from();
+                    }
+                    // iterate all blocks where the interval has use positions
+                    for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
+                        if (dominates(defBlock, splitBlock)) {
+                            Debug.log("Split interval %s, block %s", splitChild, splitBlock);
+                            if (spillBlock == null) {
+                                spillBlock = splitBlock;
+                            } else {
+                                spillBlock = commonDominator(spillBlock, splitBlock);
+                                assert spillBlock != null;
+                            }
+                        }
+                    }
+                }
+            }
+            if (spillBlock == null) {
+                Debug.log("not spill interval found");
+                // no spill interval
+                interval.setSpillState(SpillState.StoreAtDefinition);
+                return;
+            }
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (initial): %s", spillBlock);
+            // move out of loops
+            if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) {
+                spillBlock = moveSpillOutOfLoop(defBlock, spillBlock);
+            }
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock);
+
+            /*
+             * The spill block is the begin of the first split child (aka the value is on the
+             * stack).
+             *
+             * The problem is that if spill block has more than one predecessor, the values at the
+             * end of the predecessors might differ. Therefore, we would need a spill move in all
+             * predecessors. To avoid this we spill in the dominator.
+             */
+            assert firstSpillChild != null;
+            if (!defBlock.equals(spillBlock) && spillBlock.equals(allocator.blockForId(firstSpillChild.from()))) {
+                AbstractBlockBase<?> dom = spillBlock.getDominator();
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
+                }
+                spillBlock = dom;
+            }
+            if (defBlock.equals(spillBlock)) {
+                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition is the best choice: %s", defBlock);
+                // definition is the best choice
+                interval.setSpillState(SpillState.StoreAtDefinition);
+                return;
+            }
+            assert dominates(defBlock, spillBlock);
+            betterSpillPos.increment();
+            if (Debug.isLogEnabled()) {
+                Debug.log("Better spill position found (Block %s)", spillBlock);
+            }
+
+            if (defBlock.probability() <= spillBlock.probability()) {
+                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock,
+                                spillBlock.probability());
+                // better spill block has the same probability -> do nothing
+                interval.setSpillState(SpillState.StoreAtDefinition);
+                return;
+            }
+
+            LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()];
+            if (insertionBuffer == null) {
+                insertionBuffer = new LIRInsertionBuffer();
+                insertionBuffers[spillBlock.getId()] = insertionBuffer;
+                insertionBuffer.init(allocator.getLIR().getLIRforBlock(spillBlock));
+            }
+            int spillOpId = allocator.getFirstLirInstructionId(spillBlock);
+            // insert spill move
+            AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location();
+            AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
+            LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Insert spill move %s", move);
+            move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID);
+            /*
+             * We can use the insertion buffer directly because we always insert at position 1.
+             */
+            insertionBuffer.append(1, move);
+
+            betterSpillPosWithLowerProbability.increment();
+            interval.setSpillDefinitionPos(spillOpId);
+        }
+    }
+
+    /**
+     * Iterate over all {@link AbstractBlockBase blocks} of an interval.
+     */
+    private class IntervalBlockIterator implements Iterator<AbstractBlockBase<?>> {
+
+        Range range;
+        AbstractBlockBase<?> block;
+
+        IntervalBlockIterator(Interval interval) {
+            range = interval.first();
+            block = allocator.blockForId(range.from);
+        }
+
+        @Override
+        public AbstractBlockBase<?> next() {
+            AbstractBlockBase<?> currentBlock = block;
+            int nextBlockIndex = block.getLinearScanNumber() + 1;
+            if (nextBlockIndex < allocator.sortedBlocks().length) {
+                block = allocator.sortedBlocks()[nextBlockIndex];
+                if (range.to <= allocator.getFirstLirInstructionId(block)) {
+                    range = range.next;
+                    if (range == Range.EndMarker) {
+                        block = null;
+                    } else {
+                        block = allocator.blockForId(range.from);
+                    }
+                }
+            } else {
+                block = null;
+            }
+            return currentBlock;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return block != null;
+        }
+    }
+
+    private Iterable<AbstractBlockBase<?>> blocksForInterval(Interval interval) {
+        return new Iterable<AbstractBlockBase<?>>() {
+            @Override
+            public Iterator<AbstractBlockBase<?>> iterator() {
+                return new IntervalBlockIterator(interval);
+            }
+        };
+    }
+
+    private static AbstractBlockBase<?> moveSpillOutOfLoop(AbstractBlockBase<?> defBlock, AbstractBlockBase<?> spillBlock) {
+        int defLoopDepth = defBlock.getLoopDepth();
+        for (AbstractBlockBase<?> block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) {
+            assert block != null : "spill block not dominated by definition block?";
+            if (block.getLoopDepth() <= defLoopDepth) {
+                assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!";
+                return block;
+            }
+        }
+        return defBlock;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java
new file mode 100644
index 0000000..06f4d82
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.lir.alloc.lsra.ssa.SSALinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class LinearScanPhase extends AllocationPhase {
+
+    private boolean neverSpillConstants;
+
+    public void setNeverSpillConstants(boolean neverSpillConstants) {
+        this.neverSpillConstants = neverSpillConstants;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig;
+        final LinearScan allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, lirGenRes.getLIR().linearScanOrder(), neverSpillConstants);
+        allocator.allocate(target, lirGenRes, spillMoveFactory, registerAllocationConfig);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java
new file mode 100644
index 0000000..8b33313
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class LinearScanRegisterAllocationPhase extends AllocationPhase {
+
+    private final LinearScan allocator;
+
+    LinearScanRegisterAllocationPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        allocator.printIntervals("Before register allocation");
+        allocateRegisters();
+        allocator.printIntervals("After register allocation");
+    }
+
+    @SuppressWarnings("try")
+    void allocateRegisters() {
+        try (Indent indent = Debug.logAndIndent("allocate registers")) {
+            Interval precoloredIntervals;
+            Interval notPrecoloredIntervals;
+
+            Interval.Pair result = allocator.createUnhandledLists(LinearScan.IS_PRECOLORED_INTERVAL, LinearScan.IS_VARIABLE_INTERVAL);
+            precoloredIntervals = result.first;
+            notPrecoloredIntervals = result.second;
+
+            // allocate cpu registers
+            LinearScanWalker lsw;
+            if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) {
+                lsw = new OptimizingLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            } else {
+                lsw = new LinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            }
+            lsw.walk();
+            lsw.finishAllocation();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java
new file mode 100644
index 0000000..a8f5f1f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+
+import java.util.BitSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Phase 6: resolve data flow
+ *
+ * Insert moves at edges between blocks if intervals have been split.
+ */
+public class LinearScanResolveDataFlowPhase extends AllocationPhase {
+
+    protected final LinearScan allocator;
+
+    protected LinearScanResolveDataFlowPhase(LinearScan allocator) {
+        this.allocator = allocator;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        resolveDataFlow();
+        allocator.printIntervals("After resolve data flow");
+    }
+
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        assert moveResolver.checkEmpty();
+        assert midBlock == null ||
+                        (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors()[0].equals(fromBlock) && midBlock.getSuccessors()[0].equals(
+                                        toBlock));
+
+        int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+        int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+        int numOperands = allocator.operandSize();
+        BitSet liveAtEdge = allocator.getBlockData(toBlock).liveIn;
+
+        // visit all variables for which the liveAtEdge bit is set
+        for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
+            assert operandNum < numOperands : "live information set for not exisiting interval";
+            assert allocator.getBlockData(fromBlock).liveOut.get(operandNum) && allocator.getBlockData(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
+
+            Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
+            Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+
+            if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                // need to insert move instruction
+                moveResolver.addMapping(fromInterval, toInterval);
+            }
+        }
+    }
+
+    void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
+        if (fromBlock.getSuccessorCount() <= 1) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+            }
+
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock);
+            LIRInstruction instr = instructions.get(instructions.size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                // insert moves before branch
+                moveResolver.setInsertPosition(instructions, instructions.size() - 1);
+            } else {
+                moveResolver.setInsertPosition(instructions, instructions.size());
+            }
+
+        } else {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+            }
+
+            if (DetailedAsserts.getValue()) {
+                assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+
+                /*
+                 * Because the number of predecessor edges matches the number of successor edges,
+                 * blocks which are reached by switch statements may have be more than one
+                 * predecessor but it will be guaranteed that all predecessors will be the same.
+                 */
+                for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
+                    assert fromBlock == predecessor : "all critical edges must be broken";
+                }
+            }
+
+            moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1);
+        }
+    }
+
+    /**
+     * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that
+     * have been split.
+     */
+    @SuppressWarnings("try")
+    protected void resolveDataFlow() {
+        try (Indent indent = Debug.logAndIndent("resolve data flow")) {
+
+            MoveResolver moveResolver = allocator.createMoveResolver();
+            BitSet blockCompleted = new BitSet(allocator.blockCount());
+
+            optimizeEmptyBlocks(moveResolver, blockCompleted);
+
+            resolveDataFlow0(moveResolver, blockCompleted);
+
+        }
+    }
+
+    protected void optimizeEmptyBlocks(MoveResolver moveResolver, BitSet blockCompleted) {
+        for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+
+            // check if block has only one predecessor and only one successor
+            if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+                assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
+
+                // check if block is empty (only label and branch)
+                if (instructions.size() == 2) {
+                    AbstractBlockBase<?> pred = block.getPredecessors()[0];
+                    AbstractBlockBase<?> sux = block.getSuccessors()[0];
+
+                    // prevent optimization of two consecutive blocks
+                    if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+                        }
+
+                        blockCompleted.set(block.getLinearScanNumber());
+
+                        /*
+                         * Directly resolve between pred and sux (without looking at the empty block
+                         * between).
+                         */
+                        resolveCollectMappings(pred, sux, block, moveResolver);
+                        if (moveResolver.hasMappings()) {
+                            moveResolver.setInsertPosition(instructions, 1);
+                            moveResolver.resolveAndAppendMoves();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected void resolveDataFlow0(MoveResolver moveResolver, BitSet blockCompleted) {
+        BitSet alreadyResolved = new BitSet(allocator.blockCount());
+        for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks()) {
+            if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
+                alreadyResolved.clear();
+                alreadyResolved.or(blockCompleted);
+
+                for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
+
+                    /*
+                     * Check for duplicate edges between the same blocks (can happen with switch
+                     * blocks).
+                     */
+                    if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId());
+                        }
+
+                        alreadyResolved.set(toBlock.getLinearScanNumber());
+
+                        // collect all intervals that have been split between
+                        // fromBlock and toBlock
+                        resolveCollectMappings(fromBlock, toBlock, null, moveResolver);
+                        if (moveResolver.hasMappings()) {
+                            resolveFindInsertPos(fromBlock, toBlock, moveResolver);
+                            moveResolver.resolveAndAppendMoves();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java
new file mode 100644
index 0000000..00b6d29
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.CodeUtil.isOdd;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBinding;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.State;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+class LinearScanWalker extends IntervalWalker {
+
+    protected Register[] availableRegs;
+
+    protected final int[] usePos;
+    protected final int[] blockPos;
+
+    protected List<Interval>[] spillIntervals;
+
+    private MoveResolver moveResolver; // for ordering spill moves
+
+    private int minReg;
+
+    private int maxReg;
+
+    /**
+     * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
+     * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
+     * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker
+     * value, and allocate a "real" list only on demand in {@link #setUsePos}.
+     */
+    private static final List<Interval> EMPTY_LIST = new ArrayList<>(0);
+
+    // accessors mapped to same functions in class LinearScan
+    int blockCount() {
+        return allocator.blockCount();
+    }
+
+    AbstractBlockBase<?> blockAt(int idx) {
+        return allocator.blockAt(idx);
+    }
+
+    AbstractBlockBase<?> blockOfOpWithId(int opId) {
+        return allocator.blockForId(opId);
+    }
+
+    LinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+
+        moveResolver = allocator.createMoveResolver();
+        spillIntervals = Util.uncheckedCast(new List<?>[allocator.getRegisters().size()]);
+        for (int i = 0; i < allocator.getRegisters().size(); i++) {
+            spillIntervals[i] = EMPTY_LIST;
+        }
+        usePos = new int[allocator.getRegisters().size()];
+        blockPos = new int[allocator.getRegisters().size()];
+    }
+
+    void initUseLists(boolean onlyProcessUsePos) {
+        for (Register register : availableRegs) {
+            int i = register.number;
+            usePos[i] = Integer.MAX_VALUE;
+
+            if (!onlyProcessUsePos) {
+                blockPos[i] = Integer.MAX_VALUE;
+                spillIntervals[i].clear();
+            }
+        }
+    }
+
+    int maxRegisterNumber() {
+        return maxReg;
+    }
+
+    int minRegisterNumber() {
+        return minReg;
+    }
+
+    boolean isRegisterInRange(int reg) {
+        return reg >= minRegisterNumber() && reg <= maxRegisterNumber();
+    }
+
+    void excludeFromUse(Interval i) {
+        Value location = i.location();
+        int i1 = asRegister(location).number;
+        if (isRegisterInRange(i1)) {
+            usePos[i1] = 0;
+        }
+    }
+
+    void setUsePos(Interval interval, int usePos, boolean onlyProcessUsePos) {
+        if (usePos != -1) {
+            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
+            int i = asRegister(interval.location()).number;
+            if (isRegisterInRange(i)) {
+                if (this.usePos[i] > usePos) {
+                    this.usePos[i] = usePos;
+                }
+                if (!onlyProcessUsePos) {
+                    List<Interval> list = spillIntervals[i];
+                    if (list == EMPTY_LIST) {
+                        list = new ArrayList<>(2);
+                        spillIntervals[i] = list;
+                    }
+                    list.add(interval);
+                }
+            }
+        }
+    }
+
+    void setBlockPos(Interval i, int blockPos) {
+        if (blockPos != -1) {
+            int reg = asRegister(i.location()).number;
+            if (isRegisterInRange(reg)) {
+                if (this.blockPos[reg] > blockPos) {
+                    this.blockPos[reg] = blockPos;
+                }
+                if (usePos[reg] > blockPos) {
+                    usePos[reg] = blockPos;
+                }
+            }
+        }
+    }
+
+    void freeExcludeActiveFixed() {
+        Interval interval = activeLists.get(RegisterBinding.Fixed);
+        while (interval != Interval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    void freeExcludeActiveAny() {
+        Interval interval = activeLists.get(RegisterBinding.Any);
+        while (interval != Interval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    void freeCollectInactiveFixed(Interval current) {
+        Interval interval = inactiveLists.get(RegisterBinding.Fixed);
+        while (interval != Interval.EndMarker) {
+            if (current.to() <= interval.currentFrom()) {
+                assert interval.currentIntersectsAt(current) == -1 : "must not intersect";
+                setUsePos(interval, interval.currentFrom(), true);
+            } else {
+                setUsePos(interval, interval.currentIntersectsAt(current), true);
+            }
+            interval = interval.next;
+        }
+    }
+
+    void freeCollectInactiveAny(Interval current) {
+        Interval interval = inactiveLists.get(RegisterBinding.Any);
+        while (interval != Interval.EndMarker) {
+            setUsePos(interval, interval.currentIntersectsAt(current), true);
+            interval = interval.next;
+        }
+    }
+
+    void freeCollectUnhandled(RegisterBinding kind, Interval current) {
+        Interval interval = unhandledLists.get(kind);
+        while (interval != Interval.EndMarker) {
+            setUsePos(interval, interval.intersectsAt(current), true);
+            if (kind == RegisterBinding.Fixed && current.to() <= interval.from()) {
+                setUsePos(interval, interval.from(), true);
+            }
+            interval = interval.next;
+        }
+    }
+
+    void spillExcludeActiveFixed() {
+        Interval interval = activeLists.get(RegisterBinding.Fixed);
+        while (interval != Interval.EndMarker) {
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    void spillBlockUnhandledFixed(Interval current) {
+        Interval interval = unhandledLists.get(RegisterBinding.Fixed);
+        while (interval != Interval.EndMarker) {
+            setBlockPos(interval, interval.intersectsAt(current));
+            interval = interval.next;
+        }
+    }
+
+    void spillBlockInactiveFixed(Interval current) {
+        Interval interval = inactiveLists.get(RegisterBinding.Fixed);
+        while (interval != Interval.EndMarker) {
+            if (current.to() > interval.currentFrom()) {
+                setBlockPos(interval, interval.currentIntersectsAt(current));
+            } else {
+                assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect";
+            }
+
+            interval = interval.next;
+        }
+    }
+
+    void spillCollectActiveAny(RegisterPriority registerPriority) {
+        Interval interval = activeLists.get(RegisterBinding.Any);
+        while (interval != Interval.EndMarker) {
+            setUsePos(interval, Math.min(interval.nextUsage(registerPriority, currentPosition), interval.to()), false);
+            interval = interval.next;
+        }
+    }
+
+    void spillCollectInactiveAny(Interval current) {
+        Interval interval = inactiveLists.get(RegisterBinding.Any);
+        while (interval != Interval.EndMarker) {
+            if (interval.currentIntersects(current)) {
+                setUsePos(interval, Math.min(interval.nextUsage(RegisterPriority.LiveAtLoopEnd, currentPosition), interval.to()), false);
+            }
+            interval = interval.next;
+        }
+    }
+
+    void insertMove(int operandId, Interval srcIt, Interval dstIt) {
+        // output all moves here. When source and target are equal, the move is
+        // optimized away later in assignRegNums
+
+        int opId = (operandId + 1) & ~1;
+        AbstractBlockBase<?> opBlock = allocator.blockForId(opId);
+        assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary";
+
+        // calculate index of instruction inside instruction list of current block
+        // the minimal index (for a block with no spill moves) can be calculated because the
+        // numbering of instructions is known.
+        // When the block already contains spill moves, the index must be increased until the
+        // correct index is reached.
+        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock);
+        int index = (opId - instructions.get(0).id()) >> 1;
+        assert instructions.get(index).id() <= opId : "error in calculation";
+
+        while (instructions.get(index).id() != opId) {
+            index++;
+            assert 0 <= index && index < instructions.size() : "index out of bounds";
+        }
+        assert 1 <= index && index < instructions.size() : "index out of bounds";
+        assert instructions.get(index).id() == opId : "error in calculation";
+
+        // insert new instruction before instruction at position index
+        moveResolver.moveInsertPosition(instructions, index);
+        moveResolver.addMapping(srcIt, dstIt);
+    }
+
+    int findOptimalSplitPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
+        int fromBlockNr = minBlock.getLinearScanNumber();
+        int toBlockNr = maxBlock.getLinearScanNumber();
+
+        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
+        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
+        assert fromBlockNr < toBlockNr : "must cross block boundary";
+
+        // Try to split at end of maxBlock. If this would be after
+        // maxSplitPos, then use the begin of maxBlock
+        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) + 2;
+        if (optimalSplitPos > maxSplitPos) {
+            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
+        }
+
+        int minLoopDepth = maxBlock.getLoopDepth();
+        for (int i = toBlockNr - 1; minLoopDepth > 0 && i >= fromBlockNr; i--) {
+            AbstractBlockBase<?> cur = blockAt(i);
+
+            if (cur.getLoopDepth() < minLoopDepth) {
+                // block with lower loop-depth found . split at the end of this block
+                minLoopDepth = cur.getLoopDepth();
+                optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2;
+            }
+        }
+        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary";
+
+        return optimalSplitPos;
+    }
+
+    int findOptimalSplitPos(Interval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
+        int optimalSplitPos = -1;
+        if (minSplitPos == maxSplitPos) {
+            // trivial case, no optimization of split position possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
+            optimalSplitPos = minSplitPos;
+
+        } else {
+            assert minSplitPos < maxSplitPos : "must be true then";
+            assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise";
+
+            // reason for using minSplitPos - 1: when the minimal split pos is exactly at the
+            // beginning of a block, then minSplitPos is also a possible split position.
+            // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 ==
+            // minSplitPos
+            AbstractBlockBase<?> minBlock = allocator.blockForId(minSplitPos - 1);
+
+            // reason for using maxSplitPos - 1: otherwise there would be an assert on failure
+            // when an interval ends at the end of the last block of the method
+            // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no
+            // block at this opId)
+            AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
+
+            assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
+            if (minBlock == maxBlock) {
+                // split position cannot be moved to block boundary : so split as late as possible
+                if (Debug.isLogEnabled()) {
+                    Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+                }
+                optimalSplitPos = maxSplitPos;
+
+            } else {
+                if (interval.hasHoleBetween(maxSplitPos - 1, maxSplitPos) && !allocator.isBlockBegin(maxSplitPos)) {
+                    // Do not move split position if the interval has a hole before maxSplitPos.
+                    // Intervals resulting from Phi-Functions have more than one definition (marked
+                    // as mustHaveRegister) with a hole before each definition. When the register is
+                    // needed
+                    // for the second definition : an earlier reloading is unnecessary.
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("interval has hole just before maxSplitPos, so splitting at maxSplitPos");
+                    }
+                    optimalSplitPos = maxSplitPos;
+
+                } else {
+                    // seach optimal block boundary between minSplitPos and maxSplitPos
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+                    }
+
+                    if (doLoopOptimization) {
+                        // Loop optimization: if a loop-end marker is found between min- and
+                        // max-position :
+                        // then split before this loop
+                        int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, allocator.getLastLirInstructionId(minBlock) + 2);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("loop optimization: loop end found at pos %d", loopEndPos);
+                        }
+
+                        assert loopEndPos > minSplitPos : "invalid order";
+                        if (loopEndPos < maxSplitPos) {
+                            // loop-end marker found between min- and max-position
+                            // if it is not the end marker for the same loop as the min-position :
+                            // then move
+                            // the max-position to this loop block.
+                            // Desired result: uses tagged as shouldHaveRegister inside a loop cause
+                            // a reloading
+                            // of the interval (normally, only mustHaveRegister causes a reloading)
+                            AbstractBlockBase<?> loopBlock = allocator.blockForId(loopEndPos);
+
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
+                            }
+                            assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between";
+
+                            int maxSpillPos = allocator.getLastLirInstructionId(loopBlock) + 2;
+                            optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, maxSpillPos);
+                            if (optimalSplitPos == maxSpillPos) {
+                                optimalSplitPos = -1;
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("loop optimization not necessary");
+                                }
+                            } else {
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("loop optimization successful");
+                                }
+                            }
+                        }
+                    }
+
+                    if (optimalSplitPos == -1) {
+                        // not calculated by loop optimization
+                        optimalSplitPos = findOptimalSplitPos(minBlock, maxBlock, maxSplitPos);
+                    }
+                }
+            }
+        }
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal split position: %d", optimalSplitPos);
+        }
+
+        return optimalSplitPos;
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is sorted into to the unhandled-list
+    @SuppressWarnings("try")
+    void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) {
+
+        try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.from() < minSplitPos : "cannot split at start of interval";
+            assert currentPosition < minSplitPos : "cannot split before current position";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos <= interval.to() : "cannot split after end of interval";
+
+            int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
+
+            assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+            assert optimalSplitPos <= interval.to() : "cannot split after end of interval";
+            assert optimalSplitPos > interval.from() : "cannot split at start of interval";
+
+            if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
+                return;
+            }
+
+            // must calculate this before the actual split is performed and before split position is
+            // moved to odd opId
+            boolean moveNecessary = !allocator.isBlockBegin(optimalSplitPos) && !interval.hasHoleBetween(optimalSplitPos - 1, optimalSplitPos);
+
+            if (!allocator.isBlockBegin(optimalSplitPos)) {
+                // move position before actual instruction (odd opId)
+                optimalSplitPos = (optimalSplitPos - 1) | 1;
+            }
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("splitting at position %d", optimalSplitPos);
+            }
+
+            assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
+            assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
+
+            Interval splitPart = interval.split(optimalSplitPos, allocator);
+
+            splitPart.setInsertMoveWhenActivated(moveNecessary);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString(allocator));
+                Debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
+            }
+        }
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is always on the stack and therefore ignored in further processing
+    @SuppressWarnings("try")
+    void splitForSpilling(Interval interval) {
+        // calculate allowed range of splitting position
+        int maxSplitPos = currentPosition;
+        int previousUsage = interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos);
+        if (previousUsage == currentPosition) {
+            /*
+             * If there is a usage with ShouldHaveRegister priority at the current position fall
+             * back to MustHaveRegister priority. This only happens if register priority was
+             * downgraded to MustHaveRegister in #allocLockedRegister.
+             */
+            previousUsage = interval.previousUsage(RegisterPriority.MustHaveRegister, maxSplitPos);
+        }
+        int minSplitPos = Math.max(previousUsage + 1, interval.from());
+
+        try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.state == State.Active : "why spill interval that is not active?";
+            assert interval.from() <= minSplitPos : "cannot split before start of interval";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos < interval.to() : "cannot split at end end of interval";
+            assert currentPosition < interval.to() : "interval must not end before current position";
+
+            if (minSplitPos == interval.from()) {
+                // the whole interval is never used, so spill it entirely to memory
+
+                try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
+
+                    assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
+                                    currentPosition);
+
+                    allocator.assignSpillSlot(interval);
+                    handleSpillSlot(interval);
+                    changeSpillState(interval, minSplitPos);
+
+                    // Also kick parent intervals out of register to memory when they have no use
+                    // position. This avoids short interval in register surrounded by intervals in
+                    // memory . avoid useless moves from memory to register and back
+                    Interval parent = interval;
+                    while (parent != null && parent.isSplitChild()) {
+                        parent = parent.getSplitChildBeforeOpId(parent.from());
+
+                        if (isRegister(parent.location())) {
+                            if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
+                                // parent is never used, so kick it out of its assigned register
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                }
+                                allocator.assignSpillSlot(parent);
+                                handleSpillSlot(parent);
+                            } else {
+                                // do not go further back because the register is actually used by
+                                // the interval
+                                parent = null;
+                            }
+                        }
+                    }
+                }
+
+            } else {
+                // search optimal split pos, split interval and spill only the right hand part
+                int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
+
+                assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+                assert optimalSplitPos < interval.to() : "cannot split at end of interval";
+                assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
+
+                if (!allocator.isBlockBegin(optimalSplitPos)) {
+                    // move position before actual instruction (odd opId)
+                    optimalSplitPos = (optimalSplitPos - 1) | 1;
+                }
+
+                try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
+                    assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
+                    assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
+
+                    Interval spilledPart = interval.split(optimalSplitPos, allocator);
+                    allocator.assignSpillSlot(spilledPart);
+                    handleSpillSlot(spilledPart);
+                    changeSpillState(spilledPart, optimalSplitPos);
+
+                    if (!allocator.isBlockBegin(optimalSplitPos)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                        }
+                        insertMove(optimalSplitPos, interval, spilledPart);
+                    }
+
+                    // the currentSplitChild is needed later when moves are inserted for reloading
+                    assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
+                    spilledPart.makeCurrentSplitChild();
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("left interval: %s", interval.logString(allocator));
+                        Debug.log("spilled interval   : %s", spilledPart.logString(allocator));
+                    }
+                }
+            }
+        }
+    }
+
+    // called during register allocation
+    private void changeSpillState(Interval interval, int spillPos) {
+        switch (interval.spillState()) {
+            case NoSpillStore: {
+                int defLoopDepth = allocator.blockForId(interval.spillDefinitionPos()).getLoopDepth();
+                int spillLoopDepth = allocator.blockForId(spillPos).getLoopDepth();
+
+                if (defLoopDepth < spillLoopDepth) {
+                    /*
+                     * The loop depth of the spilling position is higher then the loop depth at the
+                     * definition of the interval. Move write to memory out of loop.
+                     */
+                    if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
+                        // find best spill position in dominator the tree
+                        interval.setSpillState(SpillState.SpillInDominator);
+                    } else {
+                        // store at definition of the interval
+                        interval.setSpillState(SpillState.StoreAtDefinition);
+                    }
+                } else {
+                    /*
+                     * The interval is currently spilled only once, so for now there is no reason to
+                     * store the interval at the definition.
+                     */
+                    interval.setSpillState(SpillState.OneSpillStore);
+                }
+                break;
+            }
+
+            case OneSpillStore: {
+                if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) {
+                    // the interval is spilled more then once
+                    interval.setSpillState(SpillState.SpillInDominator);
+                } else {
+                    // It is better to store it to memory at the definition.
+                    interval.setSpillState(SpillState.StoreAtDefinition);
+                }
+                break;
+            }
+
+            case SpillInDominator:
+            case StoreAtDefinition:
+            case StartInMemory:
+            case NoOptimization:
+            case NoDefinitionFound:
+                // nothing to do
+                break;
+
+            default:
+                throw GraalError.shouldNotReachHere("other states not allowed at this time");
+        }
+    }
+
+    /**
+     * This is called for every interval that is assigned to a stack slot.
+     */
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null && (interval.canMaterialize() || isStackSlotValue(interval.location())) : "interval not assigned to a stack slot " + interval;
+        // Do nothing. Stack slots are not processed in this implementation.
+    }
+
+    void splitStackInterval(Interval interval) {
+        int minSplitPos = currentPosition + 1;
+        int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
+
+        splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+    }
+
+    void splitWhenPartialRegisterAvailable(Interval interval, int registerAvailableUntil) {
+        int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1);
+        splitBeforeUsage(interval, minSplitPos, registerAvailableUntil);
+    }
+
+    void splitAndSpillInterval(Interval interval) {
+        assert interval.state == State.Active || interval.state == State.Inactive : "other states not allowed";
+
+        int currentPos = currentPosition;
+        if (interval.state == State.Inactive) {
+            // the interval is currently inactive, so no spill slot is needed for now.
+            // when the split part is activated, the interval has a new chance to get a register,
+            // so in the best case no stack slot is necessary
+            assert interval.hasHoleBetween(currentPos - 1, currentPos + 1) : "interval can not be inactive otherwise";
+            splitBeforeUsage(interval, currentPos + 1, currentPos + 1);
+
+        } else {
+            // search the position where the interval must have a register and split
+            // at the optimal position before.
+            // The new created part is added to the unhandled list and will get a register
+            // when it is activated
+            int minSplitPos = currentPos + 1;
+            int maxSplitPos = Math.min(interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos), interval.to());
+
+            splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+
+            assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register";
+            splitForSpilling(interval);
+        }
+    }
+
+    @SuppressWarnings("try")
+    boolean allocFreeRegister(Interval interval) {
+        try (Indent indent = Debug.logAndIndent("trying to find free register for %s", interval)) {
+
+            initUseLists(true);
+            freeExcludeActiveFixed();
+            freeExcludeActiveAny();
+            freeCollectInactiveFixed(interval);
+            freeCollectInactiveAny(interval);
+            // freeCollectUnhandled(fixedKind, cur);
+            assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
+
+            // usePos contains the start of the next interval that has this register assigned
+            // (either as a fixed register or a normal allocated register in the past)
+            // only intervals overlapping with cur are processed, non-overlapping invervals can be
+            // ignored safely
+            if (Debug.isLogEnabled()) {
+                // Enable this logging to see all register states
+                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                    for (Register register : availableRegs) {
+                        int i = register.number;
+                        Debug.log("reg %d: usePos: %d", register.number, usePos[i]);
+                    }
+                }
+            }
+
+            Register hint = null;
+            Interval locationHint = interval.locationHint(true);
+            if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
+                hint = asRegister(locationHint.location());
+                if (Debug.isLogEnabled()) {
+                    Debug.log("hint register %d from interval %s", hint.number, locationHint);
+                }
+            }
+            assert interval.location() == null : "register already assigned to interval";
+
+            // the register must be free at least until this position
+            int regNeededUntil = interval.from() + 1;
+            int intervalTo = interval.to();
+
+            boolean needSplit = false;
+            int splitPos = -1;
+
+            Register reg = null;
+            Register minFullReg = null;
+            Register maxPartialReg = null;
+
+            for (Register availableReg : availableRegs) {
+                int number = availableReg.number;
+                if (usePos[number] >= intervalTo) {
+                    // this register is free for the full interval
+                    if (minFullReg == null || availableReg.equals(hint) || (usePos[number] < usePos[minFullReg.number] && !minFullReg.equals(hint))) {
+                        minFullReg = availableReg;
+                    }
+                } else if (usePos[number] > regNeededUntil) {
+                    // this register is at least free until regNeededUntil
+                    if (maxPartialReg == null || availableReg.equals(hint) || (usePos[number] > usePos[maxPartialReg.number] && !maxPartialReg.equals(hint))) {
+                        maxPartialReg = availableReg;
+                    }
+                }
+            }
+
+            if (minFullReg != null) {
+                reg = minFullReg;
+            } else if (maxPartialReg != null) {
+                needSplit = true;
+                reg = maxPartialReg;
+            } else {
+                return false;
+            }
+
+            splitPos = usePos[reg.number];
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (Debug.isLogEnabled()) {
+                Debug.log("selected register %d", reg.number);
+            }
+
+            assert splitPos > 0 : "invalid splitPos";
+            if (needSplit) {
+                // register not available for full interval, so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+            // only return true if interval is completely assigned
+            return true;
+        }
+    }
+
+    void splitAndSpillIntersectingIntervals(Register reg) {
+        assert reg != null : "no register assigned";
+
+        for (int i = 0; i < spillIntervals[reg.number].size(); i++) {
+            Interval interval = spillIntervals[reg.number].get(i);
+            removeFromList(interval);
+            splitAndSpillInterval(interval);
+        }
+    }
+
+    // Split an Interval and spill it to memory so that cur can be placed in a register
+    @SuppressWarnings("try")
+    void allocLockedRegister(Interval interval) {
+        try (Indent indent = Debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", interval)) {
+
+            // the register must be free at least until this position
+            int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister);
+            int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
+            int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
+            int intervalTo = interval.to();
+            assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
+
+            Register reg;
+            Register ignore;
+            /*
+             * In the common case we don't spill registers that have _any_ use position that is
+             * closer than the next use of the current interval, but if we can't spill the current
+             * interval we weaken this strategy and also allow spilling of intervals that have a
+             * non-mandatory requirements (no MustHaveRegister use position).
+             */
+            for (RegisterPriority registerPriority = RegisterPriority.LiveAtLoopEnd; true; registerPriority = RegisterPriority.MustHaveRegister) {
+                // collect current usage of registers
+                initUseLists(false);
+                spillExcludeActiveFixed();
+                // spillBlockUnhandledFixed(cur);
+                assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
+                spillBlockInactiveFixed(interval);
+                spillCollectActiveAny(registerPriority);
+                spillCollectInactiveAny(interval);
+                if (Debug.isLogEnabled()) {
+                    printRegisterState();
+                }
+
+                reg = null;
+                ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
+
+                for (Register availableReg : availableRegs) {
+                    int number = availableReg.number;
+                    if (availableReg.equals(ignore)) {
+                        // this register must be ignored
+                    } else if (usePos[number] > regNeededUntil) {
+                        if (reg == null || (usePos[number] > usePos[reg.number])) {
+                            reg = availableReg;
+                        }
+                    }
+                }
+
+                int regUsePos = (reg == null ? 0 : usePos[reg.number]);
+                if (regUsePos <= firstShouldHaveUsage) {
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
+                    }
+
+                    if (firstUsage <= interval.from() + 1) {
+                        if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
+                            /*
+                             * Tool of last resort: we can not spill the current interval so we try
+                             * to spill an active interval that has a usage but do not require a
+                             * register.
+                             */
+                            Debug.log("retry with register priority must have register");
+                            continue;
+                        }
+                        String description = generateOutOfRegErrorMsg(interval, firstUsage, availableRegs);
+                        /*
+                         * assign a reasonable register and do a bailout in product mode to avoid
+                         * errors
+                         */
+                        allocator.assignSpillSlot(interval);
+                        Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description);
+                        allocator.printIntervals(description);
+                        throw new OutOfRegistersException("LinearScan: no register found", description);
+                    }
+
+                    splitAndSpillInterval(interval);
+                    return;
+                }
+                break;
+            }
+
+            boolean needSplit = blockPos[reg.number] <= intervalTo;
+
+            int splitPos = blockPos[reg.number];
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("decided to use register %d", reg.number);
+            }
+            assert splitPos > 0 : "invalid splitPos";
+            assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (needSplit) {
+                // register not available for full interval : so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+
+            // perform splitting and spilling for all affected intervals
+            splitAndSpillIntersectingIntervals(reg);
+            return;
+        }
+    }
+
+    private static String generateOutOfRegErrorMsg(Interval interval, int firstUsage, Register[] availableRegs) {
+        return "Cannot spill interval (" + interval + ") that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage +
+                        ", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
+    }
+
+    @SuppressWarnings("try")
+    void printRegisterState() {
+        try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+            for (Register reg : availableRegs) {
+                int i = reg.number;
+                try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
+                    for (int j = 0; j < spillIntervals[i].size(); j++) {
+                        Debug.log("%s ", spillIntervals[i].get(j));
+                    }
+                }
+            }
+        }
+    }
+
+    boolean noAllocationPossible(Interval interval) {
+        if (allocator.callKillsRegisters()) {
+            // fast calculation of intervals that can never get a register because the
+            // the next instruction is a call that blocks all registers
+            // Note: this only works if a call kills all registers
+
+            // check if this interval is the result of a split operation
+            // (an interval got a register until this position)
+            int pos = interval.from();
+            if (isOdd(pos)) {
+                // the current instruction is a call that blocks all registers
+                if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("free register cannot be available because all registers blocked by following call");
+                    }
+
+                    // safety check that there is really no register available
+                    assert !allocFreeRegister(interval) : "found a register for this interval";
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    void initVarsForAlloc(Interval interval) {
+        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
+        availableRegs = allocatableRegisters.allocatableRegisters;
+        minReg = allocatableRegisters.minRegisterNumber;
+        maxReg = allocatableRegisters.maxRegisterNumber;
+    }
+
+    static boolean isMove(LIRInstruction op, Interval from, Interval to) {
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (isVariable(move.getInput()) && isVariable(move.getResult())) {
+                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
+            }
+        }
+        return false;
+    }
+
+    // optimization (especially for phi functions of nested loops):
+    // assign same spill slot to non-intersecting intervals
+    void combineSpilledIntervals(Interval interval) {
+        if (interval.isSplitChild()) {
+            // optimization is only suitable for split parents
+            return;
+        }
+
+        Interval registerHint = interval.locationHint(false);
+        if (registerHint == null) {
+            // cur is not the target of a move : otherwise registerHint would be set
+            return;
+        }
+        assert registerHint.isSplitParent() : "register hint must be split parent";
+
+        if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) {
+            // combining the stack slots for intervals where spill move optimization is applied
+            // is not benefitial and would cause problems
+            return;
+        }
+
+        int beginPos = interval.from();
+        int endPos = interval.to();
+        if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) {
+            // safety check that lirOpWithId is allowed
+            return;
+        }
+
+        if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) {
+            // cur and registerHint are not connected with two moves
+            return;
+        }
+
+        Interval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.USE, allocator);
+        Interval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.DEF, allocator);
+        if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) {
+            // registerHint must be split : otherwise the re-writing of use positions does not work
+            return;
+        }
+
+        assert beginHint.location() != null : "must have register assigned";
+        assert endHint.location() == null : "must not have register assigned";
+        assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move";
+        assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move";
+
+        if (isRegister(beginHint.location())) {
+            // registerHint is not spilled at beginPos : so it would not be benefitial to
+            // immediately spill cur
+            return;
+        }
+        assert registerHint.spillSlot() != null : "must be set when part of interval was spilled";
+
+        // modify intervals such that cur gets the same stack slot as registerHint
+        // delete use positions to prevent the intervals to get a register at beginning
+        interval.setSpillSlot(registerHint.spillSlot());
+        interval.removeFirstUsePos();
+        endHint.removeFirstUsePos();
+    }
+
+    // allocate a physical register or memory location to an interval
+    @Override
+    @SuppressWarnings("try")
+    protected boolean activateCurrent(Interval interval) {
+        boolean result = true;
+
+        try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
+
+            final Value operand = interval.operand;
+            if (interval.location() != null && isStackSlotValue(interval.location())) {
+                // activating an interval that has a stack slot assigned . split it at first use
+                // position
+                // used for method parameters
+                if (Debug.isLogEnabled()) {
+                    Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                }
+                splitStackInterval(interval);
+                result = false;
+
+            } else {
+                if (interval.location() == null) {
+                    // interval has not assigned register . normal allocation
+                    // (this is the normal case for most intervals)
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("normal allocation of register");
+                    }
+
+                    // assign same spill slot to non-intersecting intervals
+                    combineSpilledIntervals(interval);
+
+                    initVarsForAlloc(interval);
+                    if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
+                        // no empty register available.
+                        // split and spill another interval so that this interval gets a register
+                        allocLockedRegister(interval);
+                    }
+
+                    // spilled intervals need not be move to active-list
+                    if (!isRegister(interval.location())) {
+                        result = false;
+                    }
+                }
+            }
+
+            // load spilled values that become active from stack slot to register
+            if (interval.insertMoveWhenActivated()) {
+                assert interval.isSplitChild();
+                assert interval.currentSplitChild() != null;
+                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+                }
+
+                insertMove(interval.from(), interval.currentSplitChild(), interval);
+            }
+            interval.makeCurrentSplitChild();
+
+        }
+
+        return result; // true = interval is moved to active list
+    }
+
+    public void finishAllocation() {
+        // must be called when all intervals are allocated
+        moveResolver.resolveAndAppendMoves();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java
new file mode 100644
index 0000000..b9df293
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRValueUtil;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+public class MoveResolver {
+
+    private static final DebugCounter cycleBreakingSlotsAllocated = Debug.counter("LSRA[cycleBreakingSlotsAllocated]");
+
+    private final LinearScan allocator;
+
+    private int insertIdx;
+    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
+
+    private final List<Interval> mappingFrom;
+    private final List<Constant> mappingFromOpr;
+    private final List<Interval> mappingTo;
+    private boolean multipleReadsAllowed;
+    private final int[] registerBlocked;
+
+    protected void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isRegister(location)) {
+            registerBlocked[asRegister(location).number] += direction;
+        } else {
+            throw GraalError.shouldNotReachHere("unhandled value " + location);
+        }
+    }
+
+    protected Interval getMappingFrom(int i) {
+        return mappingFrom.get(i);
+    }
+
+    protected int mappingFromSize() {
+        return mappingFrom.size();
+    }
+
+    protected int valueBlocked(Value location) {
+        if (isRegister(location)) {
+            return registerBlocked[asRegister(location).number];
+        }
+        throw GraalError.shouldNotReachHere("unhandled value " + location);
+    }
+
+    void setMultipleReadsAllowed() {
+        multipleReadsAllowed = true;
+    }
+
+    protected boolean areMultipleReadsAllowed() {
+        return multipleReadsAllowed;
+    }
+
+    boolean hasMappings() {
+        return mappingFrom.size() > 0;
+    }
+
+    protected LinearScan getAllocator() {
+        return allocator;
+    }
+
+    protected MoveResolver(LinearScan allocator) {
+
+        this.allocator = allocator;
+        this.multipleReadsAllowed = false;
+        this.mappingFrom = new ArrayList<>(8);
+        this.mappingFromOpr = new ArrayList<>(8);
+        this.mappingTo = new ArrayList<>(8);
+        this.insertIdx = -1;
+        this.insertionBuffer = new LIRInsertionBuffer();
+        this.registerBlocked = new int[allocator.getRegisters().size()];
+    }
+
+    protected boolean checkEmpty() {
+        assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
+        for (int i = 0; i < getAllocator().getRegisters().size(); i++) {
+            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
+        }
+        checkMultipleReads();
+        return true;
+    }
+
+    protected void checkMultipleReads() {
+        assert !areMultipleReadsAllowed() : "must have default value";
+    }
+
+    private boolean verifyBeforeResolve() {
+        assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal";
+        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
+        assert insertIdx != -1 : "insert position not set";
+
+        int i;
+        int j;
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                for (j = i + 1; j < mappingFrom.size(); j++) {
+                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
+                }
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            for (j = i + 1; j < mappingTo.size(); j++) {
+                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
+            }
+        }
+
+        HashSet<Value> usedRegs = new HashSet<>();
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                Interval interval = mappingFrom.get(i);
+                if (interval != null && !isIllegal(interval.location())) {
+                    boolean unique = usedRegs.add(interval.location());
+                    assert unique : "cannot read from same register twice";
+                }
+            }
+        }
+
+        usedRegs.clear();
+        for (i = 0; i < mappingTo.size(); i++) {
+            Interval interval = mappingTo.get(i);
+            if (isIllegal(interval.location())) {
+                // After insertion the location may become illegal, so don't check it since multiple
+                // intervals might be illegal.
+                continue;
+            }
+            boolean unique = usedRegs.add(interval.location());
+            assert unique : "cannot write to same register twice";
+        }
+
+        verifyStackSlotMapping();
+
+        return true;
+    }
+
+    protected void verifyStackSlotMapping() {
+        HashSet<Value> usedRegs = new HashSet<>();
+        for (int i = 0; i < mappingFrom.size(); i++) {
+            Interval interval = mappingFrom.get(i);
+            if (interval != null && !isRegister(interval.location())) {
+                usedRegs.add(interval.location());
+            }
+        }
+        for (int i = 0; i < mappingTo.size(); i++) {
+            Interval interval = mappingTo.get(i);
+            assert !usedRegs.contains(interval.location()) ||
+                            checkIntervalLocation(mappingFrom.get(i), interval, mappingFromOpr.get(i)) : "stack slots used in mappingFrom must be disjoint to mappingTo";
+        }
+    }
+
+    private static boolean checkIntervalLocation(Interval from, Interval to, Constant fromOpr) {
+        if (from == null) {
+            return fromOpr != null;
+        } else {
+            return to.location().equals(from.location());
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as blocked
+    private void blockRegisters(Interval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
+            int direction = 1;
+            setValueBlocked(location, direction);
+            Debug.log("block %s", location);
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as unblocked
+    private void unblockRegisters(Interval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
+            setValueBlocked(location, -1);
+            Debug.log("unblock %s", location);
+        }
+    }
+
+    /**
+     * Checks if the {@linkplain Interval#location() location} of {@code to} is not blocked or is
+     * only blocked by {@code from}.
+     */
+    private boolean safeToProcessMove(Interval from, Interval to) {
+        Value fromReg = from != null ? from.location() : null;
+
+        Value location = to.location();
+        if (mightBeBlocked(location)) {
+            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    protected boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
+    protected boolean mightBeBlocked(Value location) {
+        return isRegister(location);
+    }
+
+    private void createInsertionBuffer(List<LIRInstruction> list) {
+        assert !insertionBuffer.initialized() : "overwriting existing buffer";
+        insertionBuffer.init(list);
+    }
+
+    private void appendInsertionBuffer() {
+        if (insertionBuffer.initialized()) {
+            insertionBuffer.finish();
+        }
+        assert !insertionBuffer.initialized() : "must be uninitialized now";
+
+        insertIdx = -1;
+    }
+
+    private void insertMove(Interval fromInterval, Interval toInterval) {
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
+        assert insertIdx != -1 : "must setup insert position first";
+
+        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
+        }
+    }
+
+    /**
+     * @param fromOpr {@link Interval#operand operand} of the {@code from} interval
+     * @param toOpr {@link Interval#operand operand} of the {@code to} interval
+     * @param fromLocation {@link Interval#location() location} of the {@code to} interval
+     * @param toLocation {@link Interval#location() location} of the {@code to} interval
+     */
+    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
+        return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
+    }
+
+    private void insertMove(Constant fromOpr, Interval toInterval) {
+        assert insertIdx != -1 : "must setup insert position first";
+
+        AllocatableValue toOpr = toInterval.operand;
+        LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
+        insertionBuffer.append(insertIdx, move);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void resolveMappings() {
+        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
+            assert verifyBeforeResolve();
+            if (Debug.isLogEnabled()) {
+                printMapping();
+            }
+
+            // Block all registers that are used as input operands of a move.
+            // When a register is blocked, no move to this register is emitted.
+            // This is necessary for detecting cycles in moves.
+            int i;
+            for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                Interval fromInterval = mappingFrom.get(i);
+                if (fromInterval != null) {
+                    blockRegisters(fromInterval);
+                }
+            }
+
+            ArrayList<AllocatableValue> busySpillSlots = null;
+            while (mappingFrom.size() > 0) {
+                boolean processedInterval = false;
+
+                int spillCandidate = -1;
+                for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                    Interval fromInterval = mappingFrom.get(i);
+                    Interval toInterval = mappingTo.get(i);
+
+                    if (safeToProcessMove(fromInterval, toInterval)) {
+                        // this interval can be processed because target is free
+                        if (fromInterval != null) {
+                            insertMove(fromInterval, toInterval);
+                            unblockRegisters(fromInterval);
+                        } else {
+                            insertMove(mappingFromOpr.get(i), toInterval);
+                        }
+                        if (LIRValueUtil.isStackSlotValue(toInterval.location())) {
+                            if (busySpillSlots == null) {
+                                busySpillSlots = new ArrayList<>(2);
+                            }
+                            busySpillSlots.add(toInterval.location());
+                        }
+                        mappingFrom.remove(i);
+                        mappingFromOpr.remove(i);
+                        mappingTo.remove(i);
+
+                        processedInterval = true;
+                    } else if (fromInterval != null && isRegister(fromInterval.location()) &&
+                                    (busySpillSlots == null || !busySpillSlots.contains(fromInterval.spillSlot()))) {
+                        // this interval cannot be processed now because target is not free
+                        // it starts in a register, so it is a possible candidate for spilling
+                        spillCandidate = i;
+                    }
+                }
+
+                if (!processedInterval) {
+                    breakCycle(spillCandidate);
+                }
+            }
+        }
+
+        // reset to default value
+        multipleReadsAllowed = false;
+
+        // check that all intervals have been processed
+        assert checkEmpty();
+    }
+
+    protected void breakCycle(int spillCandidate) {
+        // no move could be processed because there is a cycle in the move list
+        // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
+        assert spillCandidate != -1 : "no interval in register for spilling found";
+
+        // create a new spill interval and assign a stack slot to it
+        Interval fromInterval = mappingFrom.get(spillCandidate);
+        // do not allocate a new spill slot for temporary interval, but
+        // use spill slot assigned to fromInterval. Otherwise moves from
+        // one stack slot to another can happen (not allowed by LIRAssembler
+        AllocatableValue spillSlot = fromInterval.spillSlot();
+        if (spillSlot == null) {
+            spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+            fromInterval.setSpillSlot(spillSlot);
+            cycleBreakingSlotsAllocated.increment();
+        }
+        spillInterval(spillCandidate, fromInterval, spillSlot);
+    }
+
+    protected void spillInterval(int spillCandidate, Interval fromInterval, AllocatableValue spillSlot) {
+        assert mappingFrom.get(spillCandidate).equals(fromInterval);
+        Interval spillInterval = getAllocator().createDerivedInterval(fromInterval);
+        spillInterval.setKind(fromInterval.kind());
+
+        // add a dummy range because real position is difficult to calculate
+        // Note: this range is a special case when the integrity of the allocation is
+        // checked
+        spillInterval.addRange(1, 2);
+
+        spillInterval.assignLocation(spillSlot);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("created new Interval for spilling: %s", spillInterval);
+        }
+        blockRegisters(spillInterval);
+
+        // insert a move from register to stack and update the mapping
+        insertMove(fromInterval, spillInterval);
+        mappingFrom.set(spillCandidate, spillInterval);
+        unblockRegisters(fromInterval);
+    }
+
+    @SuppressWarnings("try")
+    private void printMapping() {
+        try (Indent indent = Debug.logAndIndent("Mapping")) {
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                Interval fromInterval = mappingFrom.get(i);
+                Interval toInterval = mappingTo.get(i);
+                String from;
+                Value to = toInterval.location();
+                if (fromInterval == null) {
+                    from = mappingFromOpr.get(i).toString();
+                } else {
+                    from = fromInterval.location().toString();
+                }
+                Debug.log("move %s <- %s", from, to);
+            }
+        }
+    }
+
+    void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
+        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
+
+        createInsertionBuffer(insertList);
+        this.insertIdx = insertIdx;
+    }
+
+    void moveInsertPosition(List<LIRInstruction> newInsertList, int newInsertIdx) {
+        if (insertionBuffer.lirList() != null && (insertionBuffer.lirList() != newInsertList || this.insertIdx != newInsertIdx)) {
+            // insert position changed . resolve current mappings
+            resolveMappings();
+        }
+
+        if (insertionBuffer.lirList() != newInsertList) {
+            // block changed . append insertionBuffer because it is
+            // bound to a specific block and create a new insertionBuffer
+            appendInsertionBuffer();
+            createInsertionBuffer(newInsertList);
+        }
+
+        this.insertIdx = newInsertIdx;
+    }
+
+    public void addMapping(Interval fromInterval, Interval toInterval) {
+
+        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("no store to rematerializable interval %s needed", toInterval);
+            }
+            return;
+        }
+        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
+            // Instead of a reload, re-materialize the value
+            Constant rematValue = fromInterval.getMaterializedValue();
+            addMapping(rematValue, toInterval);
+            return;
+        }
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
+        }
+
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
+                        toInterval);
+        mappingFrom.add(fromInterval);
+        mappingFromOpr.add(null);
+        mappingTo.add(toInterval);
+    }
+
+    public void addMapping(Constant fromOpr, Interval toInterval) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+        }
+
+        mappingFrom.add(null);
+        mappingFromOpr.add(fromOpr);
+        mappingTo.add(toInterval);
+    }
+
+    void resolveAndAppendMoves() {
+        if (hasMappings()) {
+            resolveMappings();
+        }
+        appendInsertionBuffer();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/OptimizingLinearScanWalker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/OptimizingLinearScanWalker.java
new file mode 100644
index 0000000..cc876b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/OptimizingLinearScanWalker.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBinding;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterBindingLists;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.State;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public class OptimizingLinearScanWalker extends LinearScanWalker {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable LSRA optimization", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LSRAOptimization = new OptionValue<>(false);
+        @Option(help = "LSRA optimization: Only split but do not reassign", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LSRAOptSplitOnly = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    OptimizingLinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+    }
+
+    @SuppressWarnings("try")
+    @Override
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null : "interval  not assigned " + interval;
+        if (interval.canMaterialize()) {
+            assert !isStackSlotValue(interval.location()) : "interval can materialize but assigned to a stack slot " + interval;
+            return;
+        }
+        assert isStackSlotValue(interval.location()) : "interval not assigned to a stack slot " + interval;
+        try (Scope s1 = Debug.scope("LSRAOptimization")) {
+            Debug.log("adding stack to unhandled list %s", interval);
+            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Stack, interval);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void printRegisterBindingList(RegisterBindingLists list, RegisterBinding binding) {
+        for (Interval interval = list.get(binding); interval != Interval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval);
+        }
+    }
+
+    @SuppressWarnings("try")
+    @Override
+    void walk() {
+        try (Scope s = Debug.scope("OptimizingLinearScanWalker")) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                optimizeBlock(block);
+            }
+        }
+        super.walk();
+    }
+
+    @SuppressWarnings("try")
+    private void optimizeBlock(AbstractBlockBase<?> block) {
+        if (block.getPredecessorCount() == 1) {
+            int nextBlock = allocator.getFirstLirInstructionId(block);
+            try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                Debug.log("next block: %s (%d)", block, nextBlock);
+            }
+            try (Indent indent0 = Debug.indent()) {
+                walkTo(nextBlock);
+
+                try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                    boolean changed = true;
+                    // we need to do this because the active lists might change
+                    loop: while (changed) {
+                        changed = false;
+                        try (Indent indent1 = Debug.logAndIndent("Active intervals: (block %s [%d])", block, nextBlock)) {
+                            for (Interval active = activeLists.get(RegisterBinding.Any); active != Interval.EndMarker; active = active.next) {
+                                Debug.log("active   (any): %s", active);
+                                if (optimize(nextBlock, block, active, RegisterBinding.Any)) {
+                                    changed = true;
+                                    break loop;
+                                }
+                            }
+                            for (Interval active = activeLists.get(RegisterBinding.Stack); active != Interval.EndMarker; active = active.next) {
+                                Debug.log("active (stack): %s", active);
+                                if (optimize(nextBlock, block, active, RegisterBinding.Stack)) {
+                                    changed = true;
+                                    break loop;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private boolean optimize(int currentPos, AbstractBlockBase<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
+        // BEGIN initialize and sanity checks
+        assert currentBlock != null : "block must not be null";
+        assert currentInterval != null : "interval must not be null";
+
+        assert currentBlock.getPredecessorCount() == 1 : "more than one predecessors -> optimization not possible";
+
+        if (!currentInterval.isSplitChild()) {
+            // interval is not a split child -> no need for optimization
+            return false;
+        }
+
+        if (currentInterval.from() == currentPos) {
+            // the interval starts at the current position so no need for splitting
+            return false;
+        }
+
+        // get current location
+        AllocatableValue currentLocation = currentInterval.location();
+        assert currentLocation != null : "active intervals must have a location assigned!";
+
+        // get predecessor stuff
+        AbstractBlockBase<?> predecessorBlock = currentBlock.getPredecessors()[0];
+        int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
+        Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
+        assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
+        AllocatableValue predecessorLocation = predecessorInterval.location();
+        assert predecessorLocation != null : "handled intervals must have a location assigned!";
+
+        // END initialize and sanity checks
+
+        if (currentLocation.equals(predecessorLocation)) {
+            // locations are already equal -> nothing to optimize
+            return false;
+        }
+
+        if (!isStackSlotValue(predecessorLocation) && !isRegister(predecessorLocation)) {
+            assert predecessorInterval.canMaterialize();
+            // value is materialized -> no need for optimization
+            return false;
+        }
+
+        assert isStackSlotValue(currentLocation) || isRegister(currentLocation) : "current location not a register or stack slot " + currentLocation;
+
+        try (Indent indent = Debug.logAndIndent("location differs: %s vs. %s", predecessorLocation, currentLocation)) {
+            // split current interval at current position
+            Debug.log("splitting at position %d", currentPos);
+
+            assert allocator.isBlockBegin(currentPos) && ((currentPos & 1) == 0) : "split pos must be even when on block boundary";
+
+            Interval splitPart = currentInterval.split(currentPos, allocator);
+            activeLists.remove(binding, currentInterval);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+
+            // the currentSplitChild is needed later when moves are inserted for reloading
+            assert splitPart.currentSplitChild() == currentInterval : "overwriting wrong currentSplitChild";
+            splitPart.makeCurrentSplitChild();
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  : %s", currentInterval.logString(allocator));
+                Debug.log("right interval : %s", splitPart.logString(allocator));
+            }
+
+            if (Options.LSRAOptSplitOnly.getValue()) {
+                // just add the split interval to the unhandled list
+                unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+            } else {
+                if (isRegister(predecessorLocation)) {
+                    splitRegisterInterval(splitPart, asRegister(predecessorLocation));
+                } else {
+                    assert isStackSlotValue(predecessorLocation);
+                    Debug.log("assigning interval %s to %s", splitPart, predecessorLocation);
+                    splitPart.assignLocation(predecessorLocation);
+                    // activate interval
+                    activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, splitPart);
+                    splitPart.state = State.Active;
+
+                    splitStackInterval(splitPart);
+                }
+            }
+        }
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    private void splitRegisterInterval(Interval interval, Register reg) {
+        // collect current usage of registers
+        initVarsForAlloc(interval);
+        initUseLists(false);
+        spillExcludeActiveFixed();
+        // spillBlockUnhandledFixed(cur);
+        assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
+        spillBlockInactiveFixed(interval);
+        spillCollectActiveAny(RegisterPriority.LiveAtLoopEnd);
+        spillCollectInactiveAny(interval);
+
+        if (Debug.isLogEnabled()) {
+            try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                for (Register register : availableRegs) {
+                    int i = register.number;
+                    try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
+                        for (int j = 0; j < spillIntervals[i].size(); j++) {
+                            Debug.log("%d ", spillIntervals[i].get(j).operandNumber);
+                        }
+                    }
+                }
+            }
+        }
+
+        // the register must be free at least until this position
+        boolean needSplit = blockPos[reg.number] <= interval.to();
+
+        int splitPos = blockPos[reg.number];
+
+        assert splitPos > 0 : "invalid splitPos";
+        assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+        Debug.log("assigning interval %s to %s", interval, reg);
+        interval.assignLocation(reg.asValue(interval.kind()));
+        if (needSplit) {
+            // register not available for full interval : so split it
+            splitWhenPartialRegisterAvailable(interval, splitPos);
+        }
+
+        // perform splitting and spilling for all affected intervals
+        splitAndSpillIntersectingIntervals(reg);
+
+        // activate interval
+        activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Any, interval);
+        interval.state = State.Active;
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Range.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Range.java
new file mode 100644
index 0000000..bffec5c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/Range.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+/**
+ * Represents a range of integers from a start (inclusive) to an end (exclusive.
+ */
+public final class Range {
+
+    public static final Range EndMarker = new Range(Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+
+    /**
+     * The start of the range, inclusive.
+     */
+    public int from;
+
+    /**
+     * The end of the range, exclusive.
+     */
+    public int to;
+
+    /**
+     * A link to allow the range to be put into a singly linked list.
+     */
+    public Range next;
+
+    boolean intersects(Range r) {
+        return intersectsAt(r) != -1;
+    }
+
+    /**
+     * Creates a new range.
+     *
+     * @param from the start of the range, inclusive
+     * @param to the end of the range, exclusive
+     * @param next link to the next range in a linked list
+     */
+    Range(int from, int to, Range next) {
+        this.from = from;
+        this.to = to;
+        this.next = next;
+    }
+
+    int intersectsAt(Range other) {
+        Range r1 = this;
+        Range r2 = other;
+
+        assert r2 != null : "null ranges not allowed";
+        assert r1 != EndMarker && r2 != EndMarker : "empty ranges not allowed";
+
+        do {
+            if (r1.from < r2.from) {
+                if (r1.to <= r2.from) {
+                    r1 = r1.next;
+                    if (r1 == EndMarker) {
+                        return -1;
+                    }
+                } else {
+                    return r2.from;
+                }
+            } else {
+                if (r2.from < r1.from) {
+                    if (r2.to <= r1.from) {
+                        r2 = r2.next;
+                        if (r2 == EndMarker) {
+                            return -1;
+                        }
+                    } else {
+                        return r1.from;
+                    }
+                } else { // r1.from() == r2.from()
+                    if (r1.from == r1.to) {
+                        r1 = r1.next;
+                        if (r1 == EndMarker) {
+                            return -1;
+                        }
+                    } else {
+                        if (r2.from == r2.to) {
+                            r2 = r2.next;
+                            if (r2 == EndMarker) {
+                                return -1;
+                            }
+                        } else {
+                            return r1.from;
+                        }
+                    }
+                }
+            }
+        } while (true);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + from + ", " + to + "]";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/RegisterVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/RegisterVerifier.java
new file mode 100644
index 0000000..57c89e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/RegisterVerifier.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.ArrayMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+final class RegisterVerifier {
+
+    LinearScan allocator;
+    List<AbstractBlockBase<?>> workList; // all blocks that must be processed
+    ArrayMap<Interval[]> savedStates; // saved information of previous check
+
+    // simplified access to methods of LinearScan
+    Interval intervalAt(Value operand) {
+        return allocator.intervalFor(operand);
+    }
+
+    // currently, only registers are processed
+    int stateSize() {
+        return allocator.maxRegisterNumber() + 1;
+    }
+
+    // accessors
+    Interval[] stateForBlock(AbstractBlockBase<?> block) {
+        return savedStates.get(block.getId());
+    }
+
+    void setStateForBlock(AbstractBlockBase<?> block, Interval[] savedState) {
+        savedStates.put(block.getId(), savedState);
+    }
+
+    void addToWorkList(AbstractBlockBase<?> block) {
+        if (!workList.contains(block)) {
+            workList.add(block);
+        }
+    }
+
+    RegisterVerifier(LinearScan allocator) {
+        this.allocator = allocator;
+        workList = new ArrayList<>(16);
+        this.savedStates = new ArrayMap<>();
+
+    }
+
+    @SuppressWarnings("try")
+    void verify(AbstractBlockBase<?> start) {
+        try (Scope s = Debug.scope("RegisterVerifier")) {
+            // setup input registers (method arguments) for first block
+            Interval[] inputState = new Interval[stateSize()];
+            setStateForBlock(start, inputState);
+            addToWorkList(start);
+
+            // main loop for verification
+            do {
+                AbstractBlockBase<?> block = workList.get(0);
+                workList.remove(0);
+
+                processBlock(block);
+            } while (!workList.isEmpty());
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void processBlock(AbstractBlockBase<?> block) {
+        try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) {
+            // must copy state because it is modified
+            Interval[] inputState = copy(stateForBlock(block));
+
+            try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // process all operations of the block
+            processOperations(block, inputState);
+
+            try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // iterate all successors
+            for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+                processSuccessor(succ, inputState);
+            }
+        }
+    }
+
+    protected void printState(Interval[] inputState) {
+        for (int i = 0; i < stateSize(); i++) {
+            Register reg = allocator.getRegisters().get(i);
+            assert reg.number == i;
+            if (inputState[i] != null) {
+                Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
+            } else {
+                Debug.log(" %6s   __", reg);
+            }
+        }
+    }
+
+    private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) {
+        Interval[] savedState = stateForBlock(block);
+
+        if (savedState != null) {
+            // this block was already processed before.
+            // check if new inputState is consistent with savedState
+
+            boolean savedStateCorrect = true;
+            for (int i = 0; i < stateSize(); i++) {
+                if (inputState[i] != savedState[i]) {
+                    // current inputState and previous savedState assume a different
+                    // interval in this register . assume that this register is invalid
+                    if (savedState[i] != null) {
+                        // invalidate old calculation only if it assumed that
+                        // register was valid. when the register was already invalid,
+                        // then the old calculation was correct.
+                        savedStateCorrect = false;
+                        savedState[i] = null;
+
+                        Debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i);
+                    }
+                }
+            }
+
+            if (savedStateCorrect) {
+                // already processed block with correct inputState
+                Debug.log("processSuccessor B%d: previous visit already correct", block.getId());
+            } else {
+                // must re-visit this block
+                Debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId());
+                addToWorkList(block);
+            }
+
+        } else {
+            // block was not processed before, so set initial inputState
+            Debug.log("processSuccessor B%d: initial visit", block.getId());
+
+            setStateForBlock(block, copy(inputState));
+            addToWorkList(block);
+        }
+    }
+
+    static Interval[] copy(Interval[] inputState) {
+        return inputState.clone();
+    }
+
+    static void statePut(Interval[] inputState, Value location, Interval interval) {
+        if (location != null && isRegister(location)) {
+            Register reg = asRegister(location);
+            int regNum = reg.number;
+            if (interval != null) {
+                Debug.log("%s = %s", reg, interval.operand);
+            } else if (inputState[regNum] != null) {
+                Debug.log("%s = null", reg);
+            }
+
+            inputState[regNum] = interval;
+        }
+    }
+
+    static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, Interval[] inputState, Value operand, Value reg, Interval interval) {
+        if (reg != null && isRegister(reg)) {
+            if (inputState[asRegister(reg).number] != interval) {
+                throw new GraalError(
+                                "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s",
+                                op, block, reg, operand, interval, inputState[asRegister(reg).number]);
+            }
+        }
+        return true;
+    }
+
+    void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) {
+        List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                // we skip spill moves inserted by the spill position optimization
+                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != LinearScan.DOMINATOR_SPILL_MOVE_ID) {
+                    Interval interval = intervalAt(operand);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                    }
+
+                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
+            if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                Interval interval = intervalAt(operand);
+                if (op.id() != -1) {
+                    interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                }
+
+                statePut(inputState, interval.location(), interval.splitParent());
+            }
+        };
+
+        // visit all instructions of the block
+        for (int i = 0; i < ops.size(); i++) {
+            final LIRInstruction op = ops.get(i);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("%s", op.toStringWithIdPrefix());
+            }
+
+            // check if input operands are correct
+            op.visitEachInput(useConsumer);
+            // invalidate all caller save registers at calls
+            if (op.destroysCallerSavedRegisters()) {
+                for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
+                    statePut(inputState, r.asValue(), null);
+                }
+            }
+            op.visitEachAlive(useConsumer);
+            // set temp operands (some operations use temp operands also as output operands, so
+            // can't set them null)
+            op.visitEachTemp(defConsumer);
+            // set output operands
+            op.visitEachOutput(defConsumer);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScan.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScan.java
new file mode 100644
index 0000000..ffe360d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScan.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra.ssa;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanEliminateSpillMovePhase;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanResolveDataFlowPhase;
+import org.graalvm.compiler.lir.alloc.lsra.MoveResolver;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public final class SSALinearScan extends LinearScan {
+
+    public SSALinearScan(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, AbstractBlockBase<?>[] sortedBlocks,
+                    boolean neverSpillConstants) {
+        super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks, neverSpillConstants);
+    }
+
+    @Override
+    protected MoveResolver createMoveResolver() {
+        SSAMoveResolver moveResolver = new SSAMoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    @Override
+    protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() {
+        return new SSALinearScanLifetimeAnalysisPhase(this);
+    }
+
+    @Override
+    protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() {
+        return new SSALinearScanResolveDataFlowPhase(this);
+    }
+
+    @Override
+    protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() {
+        return new SSALinearScanEliminateSpillMovePhase(this);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void beforeSpillMoveElimination() {
+        /*
+         * PHI Ins are needed for the RegisterVerifier, otherwise PHIs where the Out and In value
+         * matches (ie. there is no resolution move) are falsely detected as errors.
+         */
+        try (Scope s1 = Debug.scope("Remove Phi In")) {
+            for (AbstractBlockBase<?> toBlock : sortedBlocks()) {
+                if (toBlock.getPredecessorCount() > 1) {
+                    SSAUtil.removePhiIn(getLIR(), toBlock);
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java
new file mode 100644
index 0000000..85aac97
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra.ssa;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.alloc.lsra.Interval;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanEliminateSpillMovePhase;
+
+public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase {
+
+    SSALinearScanEliminateSpillMovePhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected int firstInstructionOfInterest() {
+        // also look at Labels as they define PHI values
+        return 0;
+    }
+
+    @Override
+    protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) {
+        if (super.canEliminateSpillMove(block, move)) {
+            // SSA Linear Scan might introduce moves to stack slots
+            Interval curInterval = allocator.intervalFor(move.getResult());
+            assert !isRegister(curInterval.location()) && curInterval.alwaysInMemory();
+            if (!isPhiResolutionMove(block, move, curInterval)) {
+                assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("try")
+    private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) {
+        if (!toInterval.isSplitParent()) {
+            return false;
+        }
+        if ((toInterval.from() & 1) == 1) {
+            // phi intervals start at even positions.
+            return false;
+        }
+        if (block.getSuccessorCount() != 1) {
+            return false;
+        }
+        LIRInstruction op = allocator.instructionForId(toInterval.from());
+        if (!(op instanceof LabelOp)) {
+            return false;
+        }
+        AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from());
+        assert allocator.getLIR().getLIRforBlock(intStartBlock).get(0).equals(op);
+        if (!block.getSuccessors()[0].equals(intStartBlock)) {
+            return false;
+        }
+        try (Indent indet = Debug.indent()) {
+            Debug.log("Is a move (%s) to phi interval %s", move, toInterval);
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java
new file mode 100644
index 0000000..ce8b15c63
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra.ssa;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.alloc.lsra.Interval;
+import org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase {
+
+    SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) {
+        super(linearScan);
+    }
+
+    @Override
+    protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+        super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
+
+        if (hintAtDef && op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+
+            Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
+
+            SSAUtil.forEachPhiRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
+                if (LinearScan.isVariableOrRegister(registerHint)) {
+                    Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
+
+                    setHint(op, to, from);
+                    setHint(op, from, to);
+                }
+            });
+        }
+    }
+
+    public static void setHint(final LIRInstruction op, Interval target, Interval source) {
+        Interval currentHint = target.locationHint(false);
+        if (currentHint == null || currentHint.from() > target.from()) {
+            /*
+             * Update hint if there was none or if the hint interval starts after the hinted
+             * interval.
+             */
+            target.setLocationHint(source);
+            if (Debug.isLogEnabled()) {
+                Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber);
+            }
+        }
+    }
+
+    @Override
+    protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+        if (op instanceof LabelOp) {
+            LabelOp label = (LabelOp) op;
+            if (label.isPhiIn()) {
+                return RegisterPriority.None;
+            }
+        }
+        return super.registerPriorityOfOutputOperand(op);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanResolveDataFlowPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanResolveDataFlowPhase.java
new file mode 100644
index 0000000..e43c537
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSALinearScanResolveDataFlowPhase.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra.ssa;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.alloc.lsra.Interval;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanResolveDataFlowPhase;
+import org.graalvm.compiler.lir.alloc.lsra.MoveResolver;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
+
+import jdk.vm.ci.meta.Value;
+
+class SSALinearScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase {
+
+    private static final DebugCounter numPhiResolutionMoves = Debug.counter("SSA LSRA[numPhiResolutionMoves]");
+    private static final DebugCounter numStackToStackMoves = Debug.counter("SSA LSRA[numStackToStackMoves]");
+
+    SSALinearScanResolveDataFlowPhase(LinearScan allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
+        super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
+
+        if (toBlock.getPredecessorCount() > 1) {
+            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+
+            AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
+            List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(phiOutBlock);
+            int phiOutIdx = SSAUtil.phiOutIndex(allocator.getLIR(), phiOutBlock);
+            int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
+            assert phiOutId >= 0;
+
+            PhiValueVisitor visitor = new PhiValueVisitor() {
+
+                @Override
+                public void visit(Value phiIn, Value phiOut) {
+                    assert !isRegister(phiOut) : "phiOut is a register: " + phiOut;
+                    assert !isRegister(phiIn) : "phiIn is a register: " + phiIn;
+                    Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+                    if (isConstantValue(phiOut)) {
+                        numPhiResolutionMoves.increment();
+                        moveResolver.addMapping(asConstant(phiOut), toInterval);
+                    } else {
+                        Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
+                        if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                            numPhiResolutionMoves.increment();
+                            if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            } else {
+                                numStackToStackMoves.increment();
+                                moveResolver.addMapping(fromInterval, toInterval);
+                            }
+                        }
+                    }
+                }
+            };
+
+            SSAUtil.forEachPhiValuePair(allocator.getLIR(), toBlock, phiOutBlock, visitor);
+            SSAUtil.removePhiOut(allocator.getLIR(), phiOutBlock);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSAMoveResolver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSAMoveResolver.java
new file mode 100644
index 0000000..4cb1597
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/ssa/SSAMoveResolver.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.lsra.ssa;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.alloc.lsra.Interval;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScan;
+import org.graalvm.compiler.lir.alloc.lsra.MoveResolver;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public final class SSAMoveResolver extends MoveResolver {
+
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+
+    public SSAMoveResolver(LinearScan allocator) {
+        super(allocator);
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    @Override
+    public boolean checkEmpty() {
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        return super.checkEmpty();
+    }
+
+    @Override
+    protected void checkMultipleReads() {
+        // multiple reads are allowed in SSA LSRA
+    }
+
+    @Override
+    protected void verifyStackSlotMapping() {
+        // relax disjoint stack maps invariant
+    }
+
+    @Override
+    protected boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    @Override
+    protected boolean mightBeBlocked(Value location) {
+        if (super.mightBeBlocked(location)) {
+            return true;
+        }
+        if (isStackSlotValue(location)) {
+            return true;
+        }
+        return false;
+    }
+
+    private int getStackArrayIndex(Value stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw GraalError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+    @Override
+    protected void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            super.setValueBlocked(location, direction);
+        }
+    }
+
+    @Override
+    protected int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        return super.valueBlocked(location);
+    }
+
+    @Override
+    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
+        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
+            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
+        }
+        return super.createMove(fromOpr, toOpr, fromLocation, toLocation);
+    }
+
+    @Override
+    protected void breakCycle(int spillCandidate) {
+        if (spillCandidate != -1) {
+            super.breakCycle(spillCandidate);
+            return;
+        }
+        assert mappingFromSize() > 1;
+        // Arbitrarily select the first entry for spilling.
+        int stackSpillCandidate = 0;
+        Interval fromInterval = getMappingFrom(stackSpillCandidate);
+        // allocate new stack slot
+        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java
new file mode 100644
index 0000000..a882cdb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPolicy.AllocationStrategy;
+import org.graalvm.compiler.lir.alloc.trace.bu.BottomUpAllocator;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.options.EnumOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.StableOptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Manages the selection of allocation strategies.
+ */
+public final class DefaultTraceRegisterAllocationPolicy {
+
+    public enum TraceRAPolicies {
+        Default,
+        LinearScanOnly,
+        BottomUpOnly
+    }
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use special allocator for trivial blocks.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRAtrivialBlockAllocator = new StableOptionValue<>(true);
+        @Option(help = "Use LSRA / BottomUp ratio", type = OptionType.Debug)
+        public static final StableOptionValue<Double> TraceRAbottomUpRatio = new StableOptionValue<>(0.0);
+        @Option(help = "TraceRA allocation policy to use.", type = OptionType.Debug)
+        public static final EnumOptionValue<TraceRAPolicies> TraceRAPolicy = new EnumOptionValue<>(TraceRAPolicies.Default);
+        // @formatter:on
+    }
+
+    public static final class TrivialTraceStrategy extends AllocationStrategy {
+
+        public TrivialTraceStrategy(TraceRegisterAllocationPolicy plan) {
+            plan.super();
+        }
+
+        @Override
+        public boolean shouldApplyTo(Trace trace) {
+            return TraceUtil.isTrivialTrace(getLIR(), trace);
+        }
+
+        @Override
+        protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
+                        RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
+                        ArrayList<AllocationStrategy> strategies) {
+            return new TrivialTraceAllocator();
+        }
+    }
+
+    public static class BottomUpStrategy extends AllocationStrategy {
+
+        public BottomUpStrategy(TraceRegisterAllocationPolicy plan) {
+            // explicitly specify the enclosing instance for the superclass constructor call
+            plan.super();
+        }
+
+        @Override
+        public boolean shouldApplyTo(Trace trace) {
+            return !containsExceptionEdge(trace);
+        }
+
+        private static boolean containsExceptionEdge(Trace trace) {
+            for (AbstractBlockBase<?> block : trace.getBlocks()) {
+                // check if one of the successors is an exception handler
+                for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+                    if (succ.isExceptionEntry()) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override
+        protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
+                        RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
+                        ArrayList<AllocationStrategy> strategies) {
+            return new BottomUpAllocator(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant);
+        }
+    }
+
+    public static final class TraceLinearScanStrategy extends AllocationStrategy {
+
+        public TraceLinearScanStrategy(TraceRegisterAllocationPolicy plan) {
+            // explicitly specify the enclosing instance for the superclass constructor call
+            plan.super();
+        }
+
+        @Override
+        public boolean shouldApplyTo(Trace trace) {
+            return true;
+        }
+
+        @Override
+        protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
+                        RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
+                        ArrayList<AllocationStrategy> strategies) {
+            return new TraceLinearScanPhase(target, lirGenRes, spillMoveFactory, registerAllocationConfig, resultTraces, neverSpillConstant, cachedStackSlots);
+        }
+    }
+
+    public static TraceRegisterAllocationPolicy allocationPolicy(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant) {
+        TraceRegisterAllocationPolicy plan = new TraceRegisterAllocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant);
+        if (Options.TraceRAtrivialBlockAllocator.getValue()) {
+            plan.appendStrategy(new TrivialTraceStrategy(plan));
+        }
+        switch (Options.TraceRAPolicy.getValue()) {
+            case Default:
+            case LinearScanOnly:
+                plan.appendStrategy(new TraceLinearScanStrategy(plan));
+                break;
+            case BottomUpOnly:
+                plan.appendStrategy(new BottomUpStrategy(plan));
+                // Fallback
+                plan.appendStrategy(new TraceLinearScanStrategy(plan));
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+        return plan;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/ShadowedRegisterValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/ShadowedRegisterValue.java
new file mode 100644
index 0000000..24340a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/ShadowedRegisterValue.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.CompositeValue;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Represents a {@link #register} which has a shadow copy on the {@link #stackslot stack}.
+ */
+public final class ShadowedRegisterValue extends CompositeValue {
+    private static final EnumSet<OperandFlag> registerFlags = EnumSet.of(REG);
+    private static final EnumSet<OperandFlag> stackslotFlags = EnumSet.of(STACK);
+
+    @Component({REG}) protected RegisterValue register;
+    @Component({STACK}) protected AllocatableValue stackslot;
+
+    public ShadowedRegisterValue(RegisterValue register, AllocatableValue stackslot) {
+        super(register.getValueKind());
+        assert (register.getValueKind().equals(stackslot.getValueKind()));
+        this.register = register;
+        this.stackslot = stackslot;
+    }
+
+    public RegisterValue getRegister() {
+        return register;
+    }
+
+    public AllocatableValue getStackSlot() {
+        return stackslot;
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        RegisterValue newRegister = (RegisterValue) proc.doValue(inst, register, mode, registerFlags);
+        AllocatableValue newStackSlot = (AllocatableValue) proc.doValue(inst, stackslot, mode, stackslotFlags);
+        if (register.equals(newRegister) || stackslot.equals(newStackSlot)) {
+            return this;
+        }
+        return new ShadowedRegisterValue(newRegister, newStackSlot);
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, register, mode, registerFlags);
+        proc.visitValue(inst, stackslot, mode, stackslotFlags);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ShadowedRegisterValue other = (ShadowedRegisterValue) obj;
+        assert register != null;
+        assert stackslot != null;
+        assert other.register != null;
+        assert other.stackslot != null;
+        if (!register.equals(other.register)) {
+            return false;
+        }
+        if (!stackslot.equals(other.stackslot)) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAllocationPhase.java
new file mode 100644
index 0000000..db1d458
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAllocationPhase.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.phases.LIRPhase.LIRPhaseStatistics;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public abstract class TraceAllocationPhase<C extends TraceAllocationPhase.TraceAllocationContext> {
+
+    public static class TraceAllocationContext {
+        public final MoveFactory spillMoveFactory;
+        public final RegisterAllocationConfig registerAllocationConfig;
+        public final TraceBuilderResult resultTraces;
+
+        public TraceAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult resultTraces) {
+            this.spillMoveFactory = spillMoveFactory;
+            this.registerAllocationConfig = registerAllocationConfig;
+            this.resultTraces = resultTraces;
+        }
+    }
+
+    /**
+     * Records time spent within {@link #apply}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Records memory usage within {@link #apply}.
+     */
+    private final DebugMemUseTracker memUseTracker;
+
+    /**
+     * Records the number of traces allocated with this phase.
+     */
+    private final DebugCounter allocatedTraces;
+
+    private static final class AllocationStatistics {
+        private final DebugCounter allocatedTraces;
+
+        private AllocationStatistics(Class<?> clazz) {
+            allocatedTraces = Debug.counter("TraceRA[%s]", clazz);
+        }
+    }
+
+    private static final ClassValue<AllocationStatistics> counterClassValue = new ClassValue<AllocationStatistics>() {
+        @Override
+        protected AllocationStatistics computeValue(Class<?> c) {
+            return new AllocationStatistics(c);
+        }
+    };
+
+    public TraceAllocationPhase() {
+        LIRPhaseStatistics statistics = LIRPhase.statisticsClassValue.get(getClass());
+        timer = statistics.timer;
+        memUseTracker = statistics.memUseTracker;
+        allocatedTraces = counterClassValue.get(getClass()).allocatedTraces;
+    }
+
+    public final CharSequence getName() {
+        return LIRPhase.createName(getClass());
+    }
+
+    @Override
+    public final String toString() {
+        return getName().toString();
+    }
+
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, C context) {
+        apply(target, lirGenRes, trace, context, true);
+    }
+
+    @SuppressWarnings("try")
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, C context, boolean dumpTrace) {
+        try (Scope s = Debug.scope(getName(), this)) {
+            try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
+                if (dumpTrace && Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL + 1)) {
+                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL + 1, trace, "%s before (Trace%s: %s)", getName(), trace.getId(), trace);
+                }
+                run(target, lirGenRes, trace, context);
+                allocatedTraces.increment();
+                if (dumpTrace && Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
+                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, trace, "%s (Trace%s: %s)", getName(), trace.getId(), trace);
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, C context);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java
new file mode 100644
index 0000000..62a99ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.BiDirectionalTraceBuilder;
+import org.graalvm.compiler.core.common.alloc.SingleBlockTraceBuilder;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate;
+import org.graalvm.compiler.core.common.alloc.TraceStatisticsPrinter;
+import org.graalvm.compiler.core.common.alloc.UniDirectionalTraceBuilder;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.options.EnumOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class TraceBuilderPhase extends AllocationPhase {
+
+    public enum TraceBuilder {
+        UniDirectional,
+        BiDirectional,
+        SingleBlock
+    }
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Trace building algorithm.", type = OptionType.Debug)
+        public static final EnumOptionValue<TraceBuilder> TraceBuilding = new EnumOptionValue<>(TraceBuilder.UniDirectional);
+        @Option(help = "Schedule trivial traces as early as possible.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> TraceRAScheduleTrivialTracesEarly = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    private static final int TRACE_LOG_LEVEL = 1;
+    public static final int TRACE_DUMP_LEVEL = 3;
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        AbstractBlockBase<?>[] linearScanOrder = lirGenRes.getLIR().linearScanOrder();
+        AbstractBlockBase<?> startBlock = linearScanOrder[0];
+        LIR lir = lirGenRes.getLIR();
+        assert startBlock.equals(lir.getControlFlowGraph().getStartBlock());
+
+        final TraceBuilderResult traceBuilderResult = getTraceBuilderResult(lir, startBlock, linearScanOrder);
+
+        if (Debug.isLogEnabled(TRACE_LOG_LEVEL)) {
+            List<Trace> traces = traceBuilderResult.getTraces();
+            for (int i = 0; i < traces.size(); i++) {
+                Trace trace = traces.get(i);
+                Debug.log(TRACE_LOG_LEVEL, "Trace %5d: %s%s", i, trace, isTrivialTrace(lirGenRes.getLIR(), trace) ? " (trivial)" : "");
+            }
+        }
+        TraceStatisticsPrinter.printTraceStatistics(traceBuilderResult, lirGenRes.getCompilationUnitName());
+        Debug.dump(TRACE_DUMP_LEVEL, traceBuilderResult, "After TraceBuilding");
+        context.contextAdd(traceBuilderResult);
+    }
+
+    private static TraceBuilderResult getTraceBuilderResult(LIR lir, AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] linearScanOrder) {
+        TraceBuilderResult.TrivialTracePredicate pred = getTrivialTracePredicate(lir);
+
+        TraceBuilder selectedTraceBuilder = Options.TraceBuilding.getValue();
+        Debug.log(TRACE_LOG_LEVEL, "Building Traces using %s", selectedTraceBuilder);
+        switch (Options.TraceBuilding.getValue()) {
+            case SingleBlock:
+                return SingleBlockTraceBuilder.computeTraces(startBlock, linearScanOrder, pred);
+            case BiDirectional:
+                return BiDirectionalTraceBuilder.computeTraces(startBlock, linearScanOrder, pred);
+            case UniDirectional:
+                return UniDirectionalTraceBuilder.computeTraces(startBlock, linearScanOrder, pred);
+        }
+        throw GraalError.shouldNotReachHere("Unknown trace building algorithm: " + Options.TraceBuilding.getValue());
+    }
+
+    public static TraceBuilderResult.TrivialTracePredicate getTrivialTracePredicate(LIR lir) {
+        if (!Options.TraceRAScheduleTrivialTracesEarly.getValue()) {
+            return null;
+        }
+        return new TrivialTracePredicate() {
+            @Override
+            public boolean isTrivialTrace(Trace trace) {
+                return TraceUtil.isTrivialTrace(lir, trace);
+            }
+        };
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java
new file mode 100644
index 0000000..afb659d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+public final class TraceGlobalMoveResolutionPhase extends LIRPhase<TraceAllocationPhase.TraceAllocationContext> {
+
+    /**
+     * Abstract move resolver interface for testing.
+     */
+    public abstract static class MoveResolver {
+        public abstract void addMapping(Value src, AllocatableValue dst, Value fromStack);
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        resolveGlobalDataFlow(context.resultTraces, lirGenRes, spillMoveFactory, target.arch);
+    }
+
+    @SuppressWarnings("try")
+    private static void resolveGlobalDataFlow(TraceBuilderResult resultTraces, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, Architecture arch) {
+        LIR lir = lirGenRes.getLIR();
+        /* Resolve trace global data-flow mismatch. */
+        TraceGlobalMoveResolver moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, arch);
+        PhiValueVisitor visitor = (Value phiIn, Value phiOut) -> {
+            if (!isIllegal(phiIn)) {
+                addMapping(moveResolver, phiOut, phiIn);
+            }
+        };
+
+        try (Indent indent = Debug.logAndIndent("Trace global move resolution")) {
+            for (Trace trace : resultTraces.getTraces()) {
+                for (AbstractBlockBase<?> fromBlock : trace.getBlocks()) {
+                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
+                        if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) {
+                            try (Indent indent0 = Debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock,
+                                            resultTraces.getTraceForBlock(toBlock).getId())) {
+
+                                final List<LIRInstruction> instructions;
+                                final int insertIdx;
+                                if (fromBlock.getSuccessorCount() == 1) {
+                                    instructions = lir.getLIRforBlock(fromBlock);
+                                    insertIdx = instructions.size() - 1;
+                                } else {
+                                    assert toBlock.getPredecessorCount() == 1;
+                                    instructions = lir.getLIRforBlock(toBlock);
+                                    insertIdx = 1;
+                                }
+
+                                moveResolver.setInsertPosition(instructions, insertIdx);
+                                SSIUtil.forEachValuePair(lir, toBlock, fromBlock, visitor);
+                                moveResolver.resolveAndAppendMoves();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static void addMapping(MoveResolver moveResolver, Value from, Value to) {
+        assert !isIllegal(to);
+        if (isShadowedRegisterValue(to)) {
+            ShadowedRegisterValue toSh = asShadowedRegisterValue(to);
+            addMappingToRegister(moveResolver, from, toSh.getRegister());
+            addMappingToStackSlot(moveResolver, from, toSh.getStackSlot());
+        } else {
+            if (isRegister(to)) {
+                addMappingToRegister(moveResolver, from, asRegisterValue(to));
+            } else {
+                assert isStackSlotValue(to) : "Expected stack slot: " + to;
+                addMappingToStackSlot(moveResolver, from, (AllocatableValue) to);
+            }
+        }
+    }
+
+    private static void addMappingToRegister(MoveResolver moveResolver, Value from, RegisterValue register) {
+        if (isShadowedRegisterValue(from)) {
+            RegisterValue fromReg = asShadowedRegisterValue(from).getRegister();
+            AllocatableValue fromStack = asShadowedRegisterValue(from).getStackSlot();
+            checkAndAddMapping(moveResolver, fromReg, register, fromStack);
+        } else {
+            checkAndAddMapping(moveResolver, from, register, null);
+        }
+    }
+
+    private static void addMappingToStackSlot(MoveResolver moveResolver, Value from, AllocatableValue stack) {
+        if (isShadowedRegisterValue(from)) {
+            ShadowedRegisterValue shadowedFrom = asShadowedRegisterValue(from);
+            RegisterValue fromReg = shadowedFrom.getRegister();
+            AllocatableValue fromStack = shadowedFrom.getStackSlot();
+            if (!fromStack.equals(stack)) {
+                checkAndAddMapping(moveResolver, fromReg, stack, fromStack);
+            }
+        } else {
+            checkAndAddMapping(moveResolver, from, stack, null);
+        }
+
+    }
+
+    private static void checkAndAddMapping(MoveResolver moveResolver, Value from, AllocatableValue to, AllocatableValue fromStack) {
+        if (!from.equals(to) && (fromStack == null || !fromStack.equals(to))) {
+            moveResolver.addMapping(from, to, fromStack);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java
new file mode 100644
index 0000000..9807c9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhase.MoveResolver {
+
+    private static final DebugCounter cycleBreakingSlotsAllocated = Debug.counter("TraceRA[cycleBreakingSlotsAllocated(global)]");
+    private static final DebugCounter cycleBreakingSlotsReused = Debug.counter("TraceRA[cycleBreakingSlotsReused(global)]");
+
+    private int insertIdx;
+    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
+
+    private final List<Value> mappingFrom;
+    private final List<Value> mappingFromStack;
+    private final List<AllocatableValue> mappingTo;
+    private final int[] registerBlocked;
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+    private final MoveFactory spillMoveFactory;
+    private final FrameMapBuilder frameMapBuilder;
+
+    private void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            assert direction == 1 || direction == -1 : "out of bounds";
+            if (isRegister(location)) {
+                registerBlocked[asRegister(location).number] += direction;
+            } else {
+                throw GraalError.shouldNotReachHere("unhandled value " + location);
+            }
+        }
+    }
+
+    private int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        if (isRegister(location)) {
+            return registerBlocked[asRegister(location).number];
+        }
+        throw GraalError.shouldNotReachHere("unhandled value " + location);
+    }
+
+    private static boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    private boolean hasMappings() {
+        return mappingFrom.size() > 0;
+    }
+
+    private MoveFactory getSpillMoveFactory() {
+        return spillMoveFactory;
+    }
+
+    private RegisterArray getRegisters() {
+        return frameMapBuilder.getRegisterConfig().getAllocatableRegisters();
+    }
+
+    public TraceGlobalMoveResolver(LIRGenerationResult res, MoveFactory spillMoveFactory, Architecture arch) {
+
+        this.mappingFrom = new ArrayList<>(8);
+        this.mappingFromStack = new ArrayList<>(8);
+        this.mappingTo = new ArrayList<>(8);
+        this.insertIdx = -1;
+        this.insertionBuffer = new LIRInsertionBuffer();
+
+        this.frameMapBuilder = res.getFrameMapBuilder();
+        this.spillMoveFactory = spillMoveFactory;
+        this.registerBlocked = new int[arch.getRegisters().size()];
+
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder;
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    private boolean checkEmpty() {
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        assert mappingFrom.size() == 0 && mappingTo.size() == 0 && mappingFromStack.size() == 0 : "list must be empty before and after processing";
+        for (int i = 0; i < getRegisters().size(); i++) {
+            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
+        }
+        return true;
+    }
+
+    private boolean verifyBeforeResolve() {
+        assert mappingFrom.size() == mappingTo.size() && mappingFrom.size() == mappingFromStack.size() : "length must be equal";
+        assert insertIdx != -1 : "insert position not set";
+
+        int i;
+        int j;
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                for (j = i + 1; j < mappingFrom.size(); j++) {
+                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
+                }
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            for (j = i + 1; j < mappingTo.size(); j++) {
+                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            Value to = mappingTo.get(i);
+            assert !isStackSlotValue(to) || getStackArrayIndex(to) != STACK_SLOT_IN_CALLER_FRAME_IDX : "Cannot move to in argument: " + to;
+        }
+
+        HashSet<Value> usedRegs = new HashSet<>();
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                Value from = mappingFrom.get(i);
+                if (from != null && !isIllegal(from)) {
+                    boolean unique = usedRegs.add(from);
+                    assert unique : "cannot read from same register twice";
+                }
+            }
+        }
+
+        usedRegs.clear();
+        for (i = 0; i < mappingTo.size(); i++) {
+            Value to = mappingTo.get(i);
+            if (isIllegal(to)) {
+                // After insertion the location may become illegal, so don't check it since multiple
+                // intervals might be illegal.
+                continue;
+            }
+            boolean unique = usedRegs.add(to);
+            assert unique : "cannot write to same register twice";
+        }
+
+        return true;
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as blocked
+    private void block(Value location) {
+        if (mightBeBlocked(location)) {
+            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
+            setValueBlocked(location, 1);
+            Debug.log("block %s", location);
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as unblocked
+    private void unblock(Value location) {
+        if (mightBeBlocked(location)) {
+            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
+            setValueBlocked(location, -1);
+            Debug.log("unblock %s", location);
+        }
+    }
+
+    /**
+     * Checks if {@code to} is not blocked or is only blocked by {@code from}.
+     */
+    private boolean safeToProcessMove(Value fromLocation, Value toLocation) {
+        if (mightBeBlocked(toLocation)) {
+            if ((valueBlocked(toLocation) > 1 || (valueBlocked(toLocation) == 1 && !isMoveToSelf(fromLocation, toLocation)))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from == null) {
+            return false;
+        }
+        if (isShadowedRegisterValue(from)) {
+            /* From is a shadowed register. */
+            if (isShadowedRegisterValue(to)) {
+                // both shadowed but not equal
+                return false;
+            }
+            ShadowedRegisterValue shadowed = asShadowedRegisterValue(from);
+            if (isRegisterToRegisterMoveToSelf(shadowed.getRegister(), to)) {
+                return true;
+            }
+            if (isStackSlotValue(to)) {
+                return to.equals(shadowed.getStackSlot());
+            }
+        } else {
+            /*
+             * A shadowed destination value is never a self move it both values are not equal. Fall
+             * through.
+             */
+            // if (isShadowedRegisterValue(to)) return false;
+
+            return isRegisterToRegisterMoveToSelf(from, to);
+        }
+        return false;
+    }
+
+    private static boolean isRegisterToRegisterMoveToSelf(Value from, Value to) {
+        if (to.equals(from)) {
+            return true;
+        }
+        if (isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            // Values differ but Registers are the same
+            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean mightBeBlocked(Value location) {
+        return isRegister(location) || isStackSlotValue(location);
+    }
+
+    private void createInsertionBuffer(List<LIRInstruction> list) {
+        assert !insertionBuffer.initialized() : "overwriting existing buffer";
+        insertionBuffer.init(list);
+    }
+
+    private void appendInsertionBuffer() {
+        if (insertionBuffer.initialized()) {
+            insertionBuffer.finish();
+        }
+        assert !insertionBuffer.initialized() : "must be uninitialized now";
+
+        insertIdx = -1;
+    }
+
+    private void insertMove(Value fromOperand, AllocatableValue toOperand) {
+        assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
+        assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind()) : "move between different types";
+        assert insertIdx != -1 : "must setup insert position first";
+
+        insertionBuffer.append(insertIdx, createMove(fromOperand, toOperand));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx);
+        }
+    }
+
+    /**
+     * @param fromOpr Operand of the {@code from} interval
+     * @param toOpr Operand of the {@code to} interval
+     */
+    private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) {
+        if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) {
+            return getSpillMoveFactory().createStackMove(toOpr, asAllocatableValue(fromOpr));
+        }
+        return getSpillMoveFactory().createMove(toOpr, fromOpr);
+    }
+
+    @SuppressWarnings("try")
+    private void resolveMappings() {
+        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
+            assert verifyBeforeResolve();
+            if (Debug.isLogEnabled()) {
+                printMapping();
+            }
+
+            // Block all registers that are used as input operands of a move.
+            // When a register is blocked, no move to this register is emitted.
+            // This is necessary for detecting cycles in moves.
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                Value from = mappingFrom.get(i);
+                block(from);
+            }
+
+            ArrayList<AllocatableValue> busySpillSlots = null;
+            while (mappingFrom.size() > 0) {
+                boolean processedInterval = false;
+
+                int spillCandidate = -1;
+                for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                    Value fromLocation = mappingFrom.get(i);
+                    AllocatableValue toLocation = mappingTo.get(i);
+                    if (safeToProcessMove(fromLocation, toLocation)) {
+                        // this interval can be processed because target is free
+                        insertMove(fromLocation, toLocation);
+                        unblock(fromLocation);
+                        if (isStackSlotValue(toLocation)) {
+                            if (busySpillSlots == null) {
+                                busySpillSlots = new ArrayList<>(2);
+                            }
+                            busySpillSlots.add(toLocation);
+                        }
+                        mappingFrom.remove(i);
+                        mappingFromStack.remove(i);
+                        mappingTo.remove(i);
+
+                        processedInterval = true;
+                    } else if (fromLocation != null) {
+                        if (isRegister(fromLocation) && (busySpillSlots == null || !busySpillSlots.contains(mappingFromStack.get(i)))) {
+                            // this interval cannot be processed now because target is not free
+                            // it starts in a register, so it is a possible candidate for spilling
+                            spillCandidate = i;
+                        } else if (isStackSlotValue(fromLocation) && spillCandidate == -1) {
+                            // fall back to spill a stack slot in case no other candidate is found
+                            spillCandidate = i;
+                        }
+                    }
+                }
+
+                if (!processedInterval) {
+                    breakCycle(spillCandidate);
+                }
+            }
+        }
+
+        // check that all intervals have been processed
+        assert checkEmpty();
+    }
+
+    @SuppressWarnings("try")
+    private void breakCycle(int spillCandidate) {
+        // no move could be processed because there is a cycle in the move list
+        // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
+        assert spillCandidate != -1 : "no interval in register for spilling found";
+
+        // create a new spill interval and assign a stack slot to it
+        Value from = mappingFrom.get(spillCandidate);
+        try (Indent indent = Debug.logAndIndent("BreakCycle: %s", from)) {
+            AllocatableValue spillSlot = null;
+            if (TraceRegisterAllocationPhase.Options.TraceRAreuseStackSlotsForMoveResolutionCycleBreaking.getValue() && !isStackSlotValue(from)) {
+                // don't use the stack slot if from is already the stack slot
+                Value fromStack = mappingFromStack.get(spillCandidate);
+                if (fromStack != null) {
+                    spillSlot = (AllocatableValue) fromStack;
+                    cycleBreakingSlotsReused.increment();
+                    Debug.log("reuse slot for spilling: %s", spillSlot);
+                }
+            }
+            if (spillSlot == null) {
+                spillSlot = frameMapBuilder.allocateSpillSlot(from.getValueKind());
+                cycleBreakingSlotsAllocated.increment();
+                Debug.log("created new slot for spilling: %s", spillSlot);
+                // insert a move from register to stack and update the mapping
+                insertMove(from, spillSlot);
+            }
+            block(spillSlot);
+            mappingFrom.set(spillCandidate, spillSlot);
+            unblock(from);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void printMapping() {
+        try (Indent indent = Debug.logAndIndent("Mapping")) {
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                Debug.log("move %s <- %s (%s)", mappingTo.get(i), mappingFrom.get(i), mappingFromStack.get(i));
+            }
+        }
+    }
+
+    public void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
+        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
+
+        createInsertionBuffer(insertList);
+        this.insertIdx = insertIdx;
+    }
+
+    @Override
+    public void addMapping(Value from, AllocatableValue to, Value fromStack) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", from, to);
+        }
+
+        assert !from.equals(to) : "from and to interval equal: " + from;
+        assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getValueKind(), to.getValueKind(), from, to);
+        assert fromStack == null || LIRKind.verifyMoveKinds(to.getValueKind(), fromStack.getValueKind()) : String.format("Kind mismatch: %s vs. %s, fromStack=%s, to=%s", fromStack.getValueKind(),
+                        to.getValueKind(), fromStack, to);
+        mappingFrom.add(from);
+        mappingFromStack.add(fromStack);
+        mappingTo.add(to);
+    }
+
+    public void resolveAndAppendMoves() {
+        if (hasMappings()) {
+            resolveMappings();
+        }
+        appendInsertionBuffer();
+    }
+
+    private int getStackArrayIndex(Value stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw GraalError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java
new file mode 100644
index 0000000..601051f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+import org.graalvm.compiler.lir.ssi.SSIVerifier;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.StableOptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Implements the Trace Register Allocation approach as described in
+ * <a href="http://dx.doi.org/10.1145/2972206.2972211">"Trace-based Register Allocation in a JIT
+ * Compiler"</a> by Josef Eisl et al.
+ */
+public final class TraceRegisterAllocationPhase extends AllocationPhase {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use inter-trace register hints.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRAuseInterTraceHints = new StableOptionValue<>(true);
+        @Option(help = "Share information about spilled values to other traces.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRAshareSpillInformation = new StableOptionValue<>(true);
+        @Option(help = "Reuse spill slots for global move resolution cycle breaking.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRAreuseStackSlotsForMoveResolutionCycleBreaking = new StableOptionValue<>(true);
+        @Option(help = "Cache stack slots globally (i.e. a variable always gets the same slot in every trace).", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRACacheStackSlots = new StableOptionValue<>(true);
+        // @formatter:on
+    }
+
+    private static final TraceGlobalMoveResolutionPhase TRACE_GLOBAL_MOVE_RESOLUTION_PHASE = new TraceGlobalMoveResolutionPhase();
+
+    private static final DebugCounter tracesCounter = Debug.counter("TraceRA[traces]");
+
+    public static final DebugCounter globalStackSlots = Debug.counter("TraceRA[GlobalStackSlots]");
+    public static final DebugCounter allocatedStackSlots = Debug.counter("TraceRA[AllocatedStackSlots]");
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig;
+        LIR lir = lirGenRes.getLIR();
+        assert SSIVerifier.verify(lir) : "LIR not in SSI form.";
+        TraceBuilderResult resultTraces = context.contextLookup(TraceBuilderResult.class);
+
+        TraceAllocationContext traceContext = new TraceAllocationContext(spillMoveFactory, registerAllocationConfig, resultTraces);
+        AllocatableValue[] cachedStackSlots = Options.TraceRACacheStackSlots.getValue() ? new AllocatableValue[lir.numVariables()] : null;
+
+        // currently this is not supported
+        boolean neverSpillConstant = false;
+
+        final TraceRegisterAllocationPolicy plan = DefaultTraceRegisterAllocationPolicy.allocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots,
+                        resultTraces, neverSpillConstant);
+
+        Debug.dump(Debug.INFO_LOG_LEVEL, lir, "Before TraceRegisterAllocation");
+        try (Scope s0 = Debug.scope("AllocateTraces", resultTraces)) {
+            for (Trace trace : resultTraces.getTraces()) {
+                tracesCounter.increment();
+                TraceAllocationPhase<TraceAllocationContext> allocator = plan.selectStrategy(trace);
+                try (Indent i = Debug.logAndIndent("Allocating Trace%d: %s (%s)", trace.getId(), trace, allocator); Scope s = Debug.scope("AllocateTrace", trace)) {
+                    allocator.apply(target, lirGenRes, trace, traceContext);
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            unnumberInstructions(lir);
+            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After trace allocation");
+        }
+
+        TRACE_GLOBAL_MOVE_RESOLUTION_PHASE.apply(target, lirGenRes, traceContext);
+        deconstructSSIForm(lir);
+    }
+
+    /**
+     * Remove Phi/Sigma In/Out.
+     *
+     * Note: Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the
+     * Out and In value matches (ie. there is no resolution move) are falsely detected as errors.
+     */
+    @SuppressWarnings("try")
+    private static void deconstructSSIForm(LIR lir) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            try (Indent i = Debug.logAndIndent("Fixup Block %s", block)) {
+                if (block.getPredecessorCount() != 0) {
+                    SSIUtil.removeIncoming(lir, block);
+                } else {
+                    assert lir.getControlFlowGraph().getStartBlock().equals(block);
+                }
+                SSIUtil.removeOutgoing(lir, block);
+            }
+        }
+    }
+
+    private static void unnumberInstructions(LIR lir) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            for (LIRInstruction op : lir.getLIRforBlock(block)) {
+                op.setId(-1);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPolicy.java
new file mode 100644
index 0000000..05d3e58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPolicy.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Manages the selection of allocation strategies.
+ */
+public final class TraceRegisterAllocationPolicy {
+
+    protected abstract class AllocationStrategy {
+        TraceAllocationPhase<TraceAllocationContext> allocator;
+
+        public final TraceAllocationPhase<TraceAllocationContext> getAllocator() {
+            if (allocator == null) {
+                allocator = initAllocator(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstants, strategies);
+            }
+            return allocator;
+        }
+
+        protected final LIR getLIR() {
+            return lirGenRes.getLIR();
+        }
+
+        protected final LIRGenerationResult getLIRGenerationResult() {
+            return lirGenRes;
+        }
+
+        protected final TraceBuilderResult getTraceBuilderResult() {
+            return resultTraces;
+        }
+
+        /**
+         * Returns {@code true} if the allocation strategy should be used for {@code trace}.
+         */
+        public abstract boolean shouldApplyTo(Trace trace);
+
+        @SuppressWarnings("hiding")
+        protected abstract TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
+                        RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
+                        ArrayList<AllocationStrategy> strategies);
+    }
+
+    private final TargetDescription target;
+    private final LIRGenerationResult lirGenRes;
+    private final MoveFactory spillMoveFactory;
+    private final RegisterAllocationConfig registerAllocationConfig;
+    private final AllocatableValue[] cachedStackSlots;
+    private final TraceBuilderResult resultTraces;
+    private final boolean neverSpillConstants;
+
+    private final ArrayList<AllocationStrategy> strategies;
+
+    public TraceRegisterAllocationPolicy(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant) {
+        this.target = target;
+        this.lirGenRes = lirGenRes;
+        this.spillMoveFactory = spillMoveFactory;
+        this.registerAllocationConfig = registerAllocationConfig;
+        this.cachedStackSlots = cachedStackSlots;
+        this.resultTraces = resultTraces;
+        this.neverSpillConstants = neverSpillConstant;
+
+        this.strategies = new ArrayList<>(3);
+    }
+
+    public void appendStrategy(AllocationStrategy strategy) {
+        strategies.add(strategy);
+    }
+
+    public TraceAllocationPhase<TraceAllocationContext> selectStrategy(Trace trace) {
+        for (AllocationStrategy strategy : strategies) {
+            if (strategy.shouldApplyTo(trace)) {
+                return strategy.getAllocator();
+            }
+        }
+        throw JVMCIError.shouldNotReachHere("No Allocation Strategy found!");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java
new file mode 100644
index 0000000..3412353
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+
+import jdk.vm.ci.meta.Value;
+
+public class TraceUtil {
+
+    public static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult traceResult, AbstractBlockBase<?> block) {
+        AbstractBlockBase<?> bestPred = null;
+        int bestTraceId = traceResult.getTraceForBlock(block).getId();
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            int predTraceId = traceResult.getTraceForBlock(pred).getId();
+            if (predTraceId < bestTraceId) {
+                bestPred = pred;
+                bestTraceId = predTraceId;
+            }
+        }
+        return bestPred;
+    }
+
+    public static boolean isShadowedRegisterValue(Value value) {
+        assert value != null;
+        return value instanceof ShadowedRegisterValue;
+    }
+
+    public static ShadowedRegisterValue asShadowedRegisterValue(Value value) {
+        assert isShadowedRegisterValue(value);
+        return (ShadowedRegisterValue) value;
+    }
+
+    public static boolean isTrivialTrace(LIR lir, Trace trace) {
+        if (trace.size() != 1) {
+            return false;
+        }
+        List<LIRInstruction> instructions = lir.getLIRforBlock(trace.getBlocks()[0]);
+        if (instructions.size() != 2) {
+            return false;
+        }
+        assert instructions.get(0) instanceof LabelOp : "First instruction not a LabelOp: " + instructions.get(0);
+        if (((LabelOp) instructions.get(0)).isPhiIn()) {
+            /*
+             * Merge blocks are in general not trivial block because variables defined by a PHI
+             * always need a location. If the outgoing value of the predecessor is a constant we
+             * need to find an appropriate location (register or stack).
+             *
+             * Note that this case should not happen in practice since the trace containing the
+             * merge block should also contain one of the predecessors. For non-standard trace
+             * builders (e.g. the single block trace builder) this is not the true, though.
+             */
+            return false;
+        }
+        /*
+         * Now we need to check if the BlockEndOp has no special operand requirements (i.e.
+         * stack-slot, register). For now we just check for JumpOp because we know that it doesn't.
+         */
+        return instructions.get(1) instanceof JumpOp;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java
new file mode 100644
index 0000000..076ac20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+import org.graalvm.compiler.lir.util.VariableVirtualStackValueMap;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other
+ * than the {@link LabelOp} and the {@link JumpOp}.
+ */
+final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
+        LIR lir = lirGenRes.getLIR();
+        TraceBuilderResult resultTraces = context.resultTraces;
+        assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
+        AbstractBlockBase<?> block = trace.getBlocks()[0];
+
+        AbstractBlockBase<?> pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block);
+
+        VariableVirtualStackValueMap<Variable, Value> variableMap = new VariableVirtualStackValueMap<>(lir.numVariables(), 0);
+        SSIUtil.forEachValuePair(lir, block, pred, (to, from) -> {
+            if (isVariable(to)) {
+                variableMap.put(asVariable(to), from);
+            }
+        });
+
+        ValueProcedure outputConsumer = (value, mode, flags) -> {
+            if (isVariable(value)) {
+                Value incomingValue = variableMap.get(asVariable(value));
+                assert !flags.contains(OperandFlag.COMPOSITE);
+                assert !(SSIUtil.incoming(lir, block).isPhiIn() && isConstantValue(incomingValue)) : "Phi variable cannot be constant: " + incomingValue + " -> " + value;
+                return incomingValue;
+            }
+            return value;
+        };
+
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        for (LIRInstruction op : instructions) {
+
+            op.forEachOutput(outputConsumer);
+            op.forEachTemp(outputConsumer);
+            op.forEachAlive(outputConsumer);
+            op.forEachInput(outputConsumer);
+            op.forEachState(outputConsumer);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
new file mode 100644
index 0000000..eaf2f3a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.bu;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.RedundantMoveElimination;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolver;
+import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Allocates registers within a trace in a greedy, bottom-up fashion. The liveness information is
+ * computed on the fly as the instructions are traversed instead of computing it in a separate pass.
+ * The goal of this allocator is to provide a simple and fast algorithm for situations where code
+ * quality is not the primary target.
+ *
+ * This implementation does not (yet) exploit hinting information and might introduce multiple spill
+ * moves to the same stack slot (which are likely to be remove by {@link RedundantMoveElimination}.
+ *
+ * The current implementation cannot deal with {@link AbstractBlockBase blocks} with edges to
+ * compiled exception handlers since it might introduce spill code after the {@link LIRInstruction
+ * instruction} that triggers the exception.
+ */
+public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocationContext> {
+    private final TargetDescription target;
+    private final LIRGenerationResult lirGenRes;
+    private final MoveFactory spillMoveFactory;
+    private final RegisterAllocationConfig registerAllocationConfig;
+    private final RegisterArray callerSaveRegs;
+    private final RegisterAttributes[] registerAttributes;
+    private final BitSet allocatedBlocks;
+    private final TraceBuilderResult resultTraces;
+    private final TraceGlobalMoveResolver moveResolver;
+
+    /**
+     * Maps from {@link Variable#index} to a spill stack slot. If
+     * {@linkplain org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options#TraceRACacheStackSlots
+     * enabled} a {@link Variable} is always assigned to the same stack slot.
+     */
+    private final AllocatableValue[] stackSlots;
+
+    private final ArrayList<LIRInstruction> insertInstructionsBefore;
+    private final ArrayList<LIRInstruction> insertInstructionsAfter;
+    private final boolean neverSpillConstants;
+
+    public BottomUpAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant) {
+        this.target = target;
+        this.lirGenRes = lirGenRes;
+        this.spillMoveFactory = spillMoveFactory;
+        this.registerAllocationConfig = registerAllocationConfig;
+        this.callerSaveRegs = registerAllocationConfig.getRegisterConfig().getCallerSaveRegisters();
+        this.registerAttributes = registerAllocationConfig.getRegisterConfig().getAttributesMap();
+        this.allocatedBlocks = new BitSet(lirGenRes.getLIR().getControlFlowGraph().getBlocks().length);
+        this.resultTraces = resultTraces;
+        this.moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, target.arch);
+        this.neverSpillConstants = neverSpillConstant;
+
+        this.insertInstructionsBefore = new ArrayList<>(4);
+        this.insertInstructionsAfter = new ArrayList<>(4);
+
+        if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue()) {
+            this.stackSlots = cachedStackSlots;
+        } else {
+            this.stackSlots = new AllocatableValue[lirGenRes.getLIR().numVariables()];
+        }
+
+    }
+
+    private LIR getLIR() {
+        return lirGenRes.getLIR();
+    }
+
+    /**
+     * Gets an object describing the attributes of a given register according to this register
+     * configuration.
+     */
+    private RegisterAttributes attributes(Register reg) {
+        return registerAttributes[reg.number];
+    }
+
+    /**
+     * Returns a new spill slot or a cached entry if there is already one for the variable.
+     */
+    private AllocatableValue allocateSpillSlot(Variable var) {
+        int variableIndex = var.index;
+        AllocatableValue cachedStackSlot = stackSlots[variableIndex];
+        if (cachedStackSlot != null) {
+            TraceRegisterAllocationPhase.globalStackSlots.increment();
+            assert cachedStackSlot.getValueKind().equals(var.getValueKind()) : "CachedStackSlot: kind mismatch? " + var.getValueKind() + " vs. " + cachedStackSlot.getValueKind();
+            return cachedStackSlot;
+        }
+        VirtualStackSlot slot = lirGenRes.getFrameMapBuilder().allocateSpillSlot(var.getValueKind());
+        stackSlots[variableIndex] = slot;
+        TraceRegisterAllocationPhase.allocatedStackSlots.increment();
+        return slot;
+    }
+
+    private final PhiValueVisitor resolveLoopBackEdgeVisitor = (Value in, Value out) -> {
+        resolveBackEdge(in, out);
+    };
+
+    private void resolveBackEdge(Value in, Value out) {
+        if (!isIllegal(in) && !TraceGlobalMoveResolver.isMoveToSelf(out, in)) {
+            TraceGlobalMoveResolutionPhase.addMapping(moveResolver, out, in);
+        }
+    }
+
+    @Override
+    protected void run(@SuppressWarnings("hiding") TargetDescription target, @SuppressWarnings("hiding") LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
+        allocate(trace);
+    }
+
+    private void allocate(Trace trace) {
+        if (neverSpillConstants) {
+            throw JVMCIError.unimplemented("NeverSpillConstant not supported!");
+        }
+        new Allocator().allocateTrace(trace);
+        assert verify(trace);
+    }
+
+    private boolean verify(Trace trace) {
+        for (AbstractBlockBase<?> block : trace.getBlocks()) {
+            assert LIR.verifyBlock(lirGenRes.getLIR(), block);
+        }
+        return true;
+    }
+
+    private static boolean requiresRegisters(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        assert isVariable(value) : "Not a variable " + value;
+        if (instruction instanceof LabelOp) {
+            // phi and incoming values do not require a register
+            return false;
+        }
+        if (mode == OperandMode.DEF || mode == OperandMode.TEMP) {
+            return true;
+        }
+        return !flags.contains(OperandFlag.STACK);
+    }
+
+    private void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock) {
+        LIR lir = lirGenRes.getLIR();
+        if (fromBlock.getSuccessorCount() <= 1) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+            }
+
+            List<LIRInstruction> instructions = lir.getLIRforBlock(fromBlock);
+            LIRInstruction instr = instructions.get(instructions.size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                // insert moves before branch
+                moveResolver.setInsertPosition(instructions, instructions.size() - 1);
+            } else {
+                moveResolver.setInsertPosition(instructions, instructions.size());
+            }
+
+        } else {
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+            }
+
+            if (DetailedAsserts.getValue()) {
+                assert lir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+
+                /*
+                 * Because the number of predecessor edges matches the number of successor edges,
+                 * blocks which are reached by switch statements may have be more than one
+                 * predecessor but it will be guaranteed that all predecessors will be the same.
+                 */
+                for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
+                    assert fromBlock == predecessor : "all critical edges must be broken";
+                }
+            }
+
+            moveResolver.setInsertPosition(lir.getLIRforBlock(toBlock), 1);
+        }
+    }
+
+    private final class Allocator {
+
+        /**
+         * Maps from {@linkplain Register#number register} to the current {@linkplain Variable
+         * variable}.
+         */
+        private final AllocatableValue[] currentRegisterMapping;
+        /**
+         * Maps from {@linkplain Variable#index variable} to its current location.
+         */
+        private final AllocatableValue[] locations;
+
+        private final int[] lastRegisterUsage;
+        private final int[] lastRegisterKill;
+
+        private ArrayList<LIRInstruction> currentInstructions;
+        private int currentInstructionIndex;
+        private int currentOpId;
+
+        private Allocator() {
+            RegisterArray registers = target.arch.getRegisters();
+            int numRegs = registers.size();
+            int numVar = getLIR().numVariables();
+            currentRegisterMapping = new AllocatableValue[numRegs];
+            lastRegisterUsage = new int[numRegs];
+            lastRegisterKill = new int[numRegs];
+            locations = new AllocatableValue[numVar];
+            // we start at offset 2 to distinguish if from the default value
+            currentOpId = 2;
+        }
+
+        private void setCurrentValue(Register reg, AllocatableValue val) {
+            currentRegisterMapping[reg.number] = val;
+        }
+
+        private AllocatableValue getCurrentValue(Register reg) {
+            return currentRegisterMapping[reg.number];
+        }
+
+        private int getLastRegisterUsage(Register reg) {
+            return lastRegisterUsage[reg.number];
+        }
+
+        private void setLastRegisterUsage(Register reg, int pos) {
+            Debug.log("Register %s last used %d", reg, pos);
+            lastRegisterUsage[reg.number] = pos;
+        }
+
+        private int getLastRegisterKill(Register reg) {
+            return lastRegisterKill[reg.number];
+        }
+
+        private void setLastRegisterKill(Register reg, int pos) {
+            Debug.log("Register %s killed %d", reg, pos);
+            lastRegisterKill[reg.number] = pos;
+        }
+
+        private void setCurrentLocation(Variable var, AllocatableValue location) {
+            locations[var.index] = location;
+        }
+
+        private AllocatableValue getCurrentLocation(Variable var) {
+            return locations[var.index];
+        }
+
+        private void insertSpillMoveBefore(AllocatableValue dst, Value src) {
+            LIRInstruction move = spillMoveFactory.createMove(dst, src);
+            insertInstructionsBefore.add(move);
+            Debug.log("insert before %s", move);
+        }
+
+        private void insertSpillMoveAfter(AllocatableValue dst, Value src) {
+            LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
+            if (!(inst instanceof BlockEndOp)) {
+                LIRInstruction move = spillMoveFactory.createMove(dst, src);
+                insertInstructionsAfter.add(move);
+                Debug.log("insert after %s", move);
+            } else {
+                Debug.log("Block end op. No from %s to %s necessary.", src, dst);
+            }
+        }
+
+        private void insertInstructions() {
+            // TODO (je) this is can probably be improved
+            currentInstructions.ensureCapacity(currentInstructions.size() + insertInstructionsBefore.size() + insertInstructionsAfter.size());
+            LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
+            // insert after
+            if (insertInstructionsAfter.size() != 0) {
+                Collections.reverse(insertInstructionsAfter);
+                assert !(inst instanceof BlockEndOp) : "Cannot insert instruction after the block end op: " + inst;
+                currentInstructions.addAll(currentInstructionIndex + 1, insertInstructionsAfter);
+                insertInstructionsAfter.clear();
+            }
+            // insert before
+            if (insertInstructionsBefore.size() != 0) {
+                assert !(inst instanceof LabelOp) : "Cannot insert instruction before the label op: " + inst;
+                currentInstructions.addAll(currentInstructionIndex, insertInstructionsBefore);
+                insertInstructionsBefore.clear();
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void allocateTrace(Trace trace) {
+            try (Scope s = Debug.scope("BottomUpAllocator", trace.getBlocks()); Indent indent = Debug.logAndIndent("%s (Trace%d)", trace, trace.getId())) {
+                AbstractBlockBase<?> successorBlock = null;
+                for (int i = trace.getBlocks().length - 1; i >= 0; i--) {
+                    AbstractBlockBase<?> block = trace.getBlocks()[i];
+                    // handle PHIs
+                    if (successorBlock != null) {
+                        resolvePhis(successorBlock, block);
+                    }
+                    allocateBlock(block);
+                    successorBlock = block;
+                }
+                resolveLocalDataFlow(trace);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        /**
+         * Resolve phi values, i.e. set the current location of values in the predecessors block
+         * (which is not yet allocated) to the location of the variable defined by the phi in the
+         * successor (which is already allocated). For constant inputs we insert moves.
+         */
+        private void resolvePhis(AbstractBlockBase<?> successorBlock, AbstractBlockBase<?> block) {
+            // Note that we are only visiting PHI values, not transient SSI values.
+            phiVisitor.loads.clear();
+            SSAUtil.forEachPhiValuePair(getLIR(), successorBlock, block, phiVisitor);
+            if (phiVisitor.loads.size() > 0) {
+                ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+                instructions.addAll(instructions.size() - 1, phiVisitor.loads);
+            }
+        }
+
+        private final PhiVisitor phiVisitor = new PhiVisitor();
+
+        private final class PhiVisitor implements PhiValueVisitor {
+
+            private final ArrayList<LIRInstruction> loads = new ArrayList<>();
+
+            @Override
+            public void visit(Value phiIn, Value phiOut) {
+                assert isStackSlotValue(phiIn) || isRegister(phiIn) : "PHI defined values is not a register or stack slot: " + phiIn;
+                AllocatableValue in = asAllocatableValue(phiIn);
+
+                AllocatableValue dest = isRegister(in) ? getCurrentValue(asRegister(in)) : in;
+                final LIRInstruction load;
+                if (isConstantValue(phiOut)) {
+                    // insert move from constant
+                    load = spillMoveFactory.createLoad(dest, LIRValueUtil.asConstant(phiOut));
+                } else {
+                    assert isVariable(phiOut) : "Not a variable or constant: " + phiOut;
+                    // insert move from variable
+                    load = spillMoveFactory.createMove(dest, asVariable(phiOut));
+                }
+                Debug.log("Inserting load %s", load);
+                loads.add(load);
+                return;
+            }
+        }
+
+        private void resolveLocalDataFlow(Trace trace) {
+            for (AbstractBlockBase<?> block : trace.getBlocks()) {
+                for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                    if (resultTraces.getTraceForBlock(pred).equals(trace)) {
+                        resolveFindInsertPos(pred, block);
+                        SSIUtil.forEachValuePair(getLIR(), block, pred, resolveLoopBackEdgeVisitor);
+                        moveResolver.resolveAndAppendMoves();
+                    }
+                }
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void allocateBlock(AbstractBlockBase<?> block) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                currentInstructions = getLIR().getLIRforBlock(block);
+                for (currentInstructionIndex = currentInstructions.size() - 1; currentInstructionIndex >= 0; currentInstructionIndex--) {
+                    LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
+                    if (inst != null) {
+                        inst.setId(currentOpId);
+                        allocateInstruction(inst);
+                    }
+                }
+                allocatedBlocks.set(block.getId());
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void allocateInstruction(LIRInstruction op) {
+            assert op != null && op.id() == currentOpId;
+            try (Indent indent = Debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
+                try (Indent indent1 = Debug.logAndIndent("output pos")) {
+                    // spill caller saved registers
+                    if (op.destroysCallerSavedRegisters()) {
+                        spillCallerSavedRegisters();
+                    }
+
+                    // fixed
+                    op.forEachOutput(allocFixedRegisterProcedure);
+                    op.forEachTemp(allocFixedRegisterProcedure);
+                    op.forEachAlive(allocFixedRegisterProcedure);
+                    // variable
+                    op.forEachOutput(allocRegisterProcedure);
+                    op.forEachTemp(allocRegisterProcedure);
+                    op.forEachAlive(allocRegisterProcedure);
+                    /* state do never require a register */
+                    // op.forEachState(allocRegisterProcedure);
+
+                    // should have
+                    op.forEachTemp(allocStackOrRegisterProcedure);
+                    op.forEachOutput(allocStackOrRegisterProcedure);
+                }
+                try (Indent indent1 = Debug.logAndIndent("input pos")) {
+
+                    currentOpId++;
+
+                    // fixed
+                    op.forEachInput(allocFixedRegisterProcedure);
+                    // variable
+                    op.forEachInput(allocRegisterProcedure);
+
+                    op.forEachAlive(allocStackOrRegisterProcedure);
+                    op.forEachState(allocStackOrRegisterProcedure);
+                    op.forEachInput(allocStackOrRegisterProcedure);
+                }
+
+                // insert spill/load instructions
+                insertInstructions();
+                currentOpId++;
+            }
+        }
+
+        private void spillCallerSavedRegisters() {
+            for (Register reg : callerSaveRegs) {
+                if (attributes(reg).isAllocatable()) {
+                    evacuateRegisterAndSpill(reg);
+                    assert checkRegisterUsage(reg);
+                    evacuateRegisterAndSpill(reg);
+                    // setCurrentValue(reg, reg.asValue());
+                    setLastRegisterUsage(reg, currentOpId);
+                }
+            }
+            if (Debug.isLogEnabled()) {
+                Debug.log("operation destroys all caller-save registers");
+            }
+        }
+
+        private final InstructionValueProcedure allocFixedRegisterProcedure = new InstructionValueProcedure() {
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                return allocFixedRegister(value);
+            }
+        };
+        private final InstructionValueProcedure allocRegisterProcedure = new InstructionValueProcedure() {
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                return allocRegister(instruction, value, mode, flags);
+            }
+        };
+        private final InstructionValueProcedure allocStackOrRegisterProcedure = new InstructionValueProcedure() {
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                return allocStackOrRegister(instruction, value, mode, flags);
+            }
+        };
+
+        private Value allocFixedRegister(Value value) {
+            if (isRegister(value)) {
+                Register reg = asRegister(value);
+                assert checkRegisterUsage(reg);
+                evacuateRegisterAndSpill(reg);
+                setRegisterUsage(reg, asAllocatableValue(value));
+            }
+            return value;
+        }
+
+        private Value allocRegister(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isVariable(value) && requiresRegisters(instruction, value, mode, flags)) {
+                Variable var = asVariable(value);
+                // check if available
+                AllocatableValue currentLocation = getCurrentLocation(var);
+                if (currentLocation == null) {
+                    // nothing yet assigned
+                    return allocRegister(var, mode);
+                }
+                // already a location assigned
+                if (isRegister(currentLocation)) {
+                    // register assigned -> nothing todo
+                    setLastRegisterUsage(asRegister(currentLocation), currentOpId);
+                    return currentLocation;
+                }
+                assert isStackSlotValue(currentLocation);
+                // stackSlot assigned but need register -> spill
+                Value allocatedRegister = allocRegister(var, mode);
+                if (mode == OperandMode.USE) {
+                    // input might be destroyed at the def position
+                    // but it must be available before the instruction
+                    insertSpillMoveBefore(currentLocation, allocatedRegister);
+                } else {
+                    insertSpillMoveAfter(currentLocation, allocatedRegister);
+                }
+                return allocatedRegister;
+            }
+            return value;
+        }
+
+        private Value allocRegister(Variable var, OperandMode mode) {
+            PlatformKind platformKind = var.getPlatformKind();
+            Register freeRegister = findFreeRegister(platformKind, mode);
+            if (freeRegister == null) {
+                // no free register found, looking for a blocked one
+                freeRegister = findLockedRegister(platformKind, mode);
+                if (freeRegister == null) {
+                    throw new OutOfRegistersException("TraceRA[BottomUp]: no register found");
+                }
+            }
+            // found a register
+            setRegisterUsage(freeRegister, var);
+            RegisterValue registerValue = freeRegister.asValue(var.getValueKind());
+            setCurrentLocation(var, registerValue);
+            Debug.log("AllocateRegister[%5s] %s for %s", mode, freeRegister, var);
+            return registerValue;
+        }
+
+        private Value allocStackOrRegister(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isRegister(value)) {
+                if ((mode == OperandMode.DEF || mode == OperandMode.TEMP) && !(instruction instanceof LabelOp)) {
+                    freeRegister(asRegister(value));
+                }
+                return value;
+            }
+            if (isVariable(value)) {
+                assert !requiresRegisters(instruction, value, mode, flags) : "Should have a register already: " + value;
+                Variable var = asVariable(value);
+                // check if available
+                AllocatableValue currentLocation = getCurrentLocation(var);
+                if (currentLocation != null) {
+                    // already a location assigned -> nothing todo
+                    if (isRegister(currentLocation)) {
+                        Register reg = asRegister(currentLocation);
+                        if (mode == OperandMode.ALIVE && killedAtDef(reg)) {
+                            AllocatableValue spillSlot = allocateSpillSlot(var);
+                            insertSpillMoveBefore(spillSlot, currentLocation);
+                            Debug.log("AllocateStackOrReg[%5s] temporary use %s for %s since current location %s is destroyed at def", mode, spillSlot, var, currentLocation);
+                            return spillSlot;
+                        }
+                        // update register usage
+                        setLastRegisterUsage(reg, currentOpId);
+                    }
+                    Debug.log(3, "AllocateStackOrReg[%5s] %s already in %s", mode, var, currentLocation);
+                    return currentLocation;
+                }
+                // no location available
+                PlatformKind platformKind = var.getPlatformKind();
+                Register freeRegister = findFreeRegister(platformKind, mode);
+                if (freeRegister == null) {
+                    // no free register available -> either spill current or free a register
+                    AllocatableValue spillSlot = allocateSpillSlot(var);
+                    setCurrentLocation(var, spillSlot);
+                    return spillSlot;
+                }
+                assert freeRegister != null;
+                // found a register
+                setRegisterUsage(freeRegister, var);
+                RegisterValue registerValue = freeRegister.asValue(var.getValueKind());
+                setCurrentLocation(var, registerValue);
+                Debug.log("AllocateStackOrReg[%5s] %s for %s", mode, freeRegister, var);
+                return registerValue;
+            }
+            return value;
+        }
+
+        private boolean killedAtDef(Register reg) {
+            return getLastRegisterKill(reg) == currentOpId - 1;
+        }
+
+        /**
+         * Searches for a free register.
+         */
+        @SuppressWarnings("try")
+        private Register findFreeRegister(PlatformKind kind, OperandMode mode) {
+            AllocatableRegisters allocatableRegisters = registerAllocationConfig.getAllocatableRegisters(kind);
+            Register[] availableRegs = allocatableRegisters.allocatableRegisters;
+            for (Register reg : availableRegs) {
+                AllocatableValue currentVal = getCurrentValue(reg);
+                if (currentVal == null && !isCurrentlyUsed(reg, mode)) {
+                    return reg;
+                }
+            }
+            if (Debug.isLogEnabled()) {
+                try (Indent i = Debug.logAndIndent("All Registers occupied:")) {
+                    for (Register reg : availableRegs) {
+                        Debug.log("%6s: last used %4d %s", reg, getLastRegisterUsage(reg), getCurrentValue(reg));
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Searches for a occupied register to spill.
+         */
+        @SuppressWarnings("try")
+        private Register findLockedRegister(PlatformKind kind, OperandMode mode) {
+            AllocatableRegisters allocatableRegisters = registerAllocationConfig.getAllocatableRegisters(kind);
+            Register[] availableRegs = allocatableRegisters.allocatableRegisters;
+            // TODO (je): better strategies for spilling
+            // TODO (je): we need to ensure that we do not use the register in the current
+            // instruction!
+            Register lockedReg = null;
+            for (Register reg : availableRegs) {
+                if (!isCurrentlyUsed(reg, mode) && !isActiveFixedRegister(reg)) {
+                    lockedReg = reg;
+                    break;
+                }
+            }
+            if (lockedReg == null) {
+                return null;
+            }
+            evacuateRegisterAndSpill(lockedReg);
+            return lockedReg;
+        }
+
+        private boolean isActiveFixedRegister(Register reg) {
+            return isRegister(getCurrentValue(reg));
+        }
+
+        private boolean isCurrentlyUsed(Register reg, OperandMode mode) {
+            int lastRegUsage = getLastRegisterUsage(reg);
+            if (lastRegUsage == currentOpId) {
+                return true;
+            }
+            return mode == OperandMode.ALIVE && lastRegUsage == (currentOpId & ~1);
+        }
+
+        private void freeRegister(Register reg) {
+            AllocatableValue val = getCurrentValue(reg);
+            setCurrentValue(reg, null);
+            setLastRegisterKill(reg, currentOpId);
+            if (val != null && isVariable(val)) {
+                Variable var = asVariable(val);
+                setCurrentLocation(var, null);
+                Debug.log("Free Registers %s (was %s)", reg, var);
+            } else {
+                Debug.log("Free Registers %s", reg);
+            }
+        }
+
+        private void setRegisterUsage(Register reg, AllocatableValue currentValue) {
+            assert checkRegisterUsage(reg);
+            setCurrentValue(reg, currentValue);
+            setLastRegisterUsage(reg, currentOpId);
+        }
+
+        private boolean checkRegisterUsage(Register reg) {
+            AllocatableValue currentValue = getCurrentValue(reg);
+            assert getLastRegisterUsage(reg) < currentOpId || currentValue == null || isRegister(currentValue) && asRegister(currentValue).equals(reg) : String.format("Register %s is occupied", reg);
+            return true;
+        }
+
+        /**
+         * Frees a registers and spill the variable that is currently occupying it.
+         *
+         * @return The value that currently occupies the register or {@code null} if there is none.
+         */
+        private AllocatableValue evacuateRegisterAndSpill(Register reg) {
+            AllocatableValue val = evacuateRegister(reg);
+            spillVariable(val, reg);
+            return val;
+        }
+
+        /**
+         * Frees a registers. The variable that is currently occupying it is <em>not</em> spilled.
+         *
+         * @return The value that currently occupies the register or {@code null} if there is none.
+         */
+        private AllocatableValue evacuateRegister(Register reg) {
+            AllocatableValue val = getCurrentValue(reg);
+            if (val == null) {
+                return null;
+            }
+            setCurrentValue(reg, null);
+            return val;
+        }
+
+        private void spillVariable(AllocatableValue val, Register reg) {
+            if (val != null && isVariable(val)) {
+                Variable var = asVariable(val);
+                Debug.log("Spill Variable %s from %s", var, reg);
+                // insert reload
+                AllocatableValue spillSlot = allocateSpillSlot(var);
+                setCurrentLocation(var, spillSlot);
+                insertSpillMoveAfter(reg.asValue(var.getValueKind()), spillSlot);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedInterval.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedInterval.java
new file mode 100644
index 0000000..5af2ed8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedInterval.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import org.graalvm.compiler.lir.LIRInstruction;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents a fixed interval.
+ */
+final class FixedInterval extends IntervalHint {
+
+    static final class FixedList {
+
+        public FixedInterval fixed;
+
+        FixedList(FixedInterval fixed) {
+            this.fixed = fixed;
+        }
+
+        /**
+         * Gets the fixed list.
+         */
+        public FixedInterval getFixed() {
+            return fixed;
+        }
+
+        /**
+         * Sets the fixed list.
+         */
+        public void setFixed(FixedInterval list) {
+            fixed = list;
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current
+         * from} positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByCurrentFromPositions(FixedInterval interval) {
+            FixedInterval list = getFixed();
+            FixedInterval prev = null;
+            FixedInterval cur = list;
+            while (cur.currentFrom() < interval.currentFrom()) {
+                prev = cur;
+                cur = cur.next;
+            }
+            FixedInterval result = list;
+            if (prev == null) {
+                // add to head of list
+                result = interval;
+            } else {
+                // add before 'cur'
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setFixed(result);
+        }
+
+    }
+
+    /**
+     * The fixed operand of this interval.
+     */
+    public final AllocatableValue operand;
+
+    /**
+     * The head of the list of ranges describing this interval. This list is sorted by
+     * {@linkplain LIRInstruction#id instruction ids}.
+     */
+    private FixedRange first;
+
+    /**
+     * Iterator used to traverse the ranges of an interval.
+     */
+    private FixedRange current;
+
+    /**
+     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
+     */
+    FixedInterval next;
+
+    private int cachedTo; // cached value: to of last range (-1: not cached)
+
+    public FixedRange first() {
+        return first;
+    }
+
+    @Override
+    public int from() {
+        return first.from;
+    }
+
+    public int to() {
+        if (cachedTo == -1) {
+            cachedTo = calcTo();
+        }
+        assert cachedTo == calcTo() : "invalid cached value";
+        return cachedTo;
+    }
+
+    // test intersection
+    boolean intersects(TraceInterval i) {
+        return first.intersects(i);
+    }
+
+    int intersectsAt(TraceInterval i) {
+        return first.intersectsAt(i);
+    }
+
+    // range iteration
+    void rewindRange() {
+        current = first;
+    }
+
+    void nextRange() {
+        assert this != EndMarker : "not allowed on sentinel";
+        current = current.next;
+    }
+
+    int currentFrom() {
+        return current.from;
+    }
+
+    int currentTo() {
+        return current.to;
+    }
+
+    boolean currentAtEnd() {
+        return current == FixedRange.EndMarker;
+    }
+
+    boolean currentIntersects(TraceInterval it) {
+        return current.intersects(it);
+    }
+
+    int currentIntersectsAt(TraceInterval it) {
+        return current.intersectsAt(it);
+    }
+
+    // range creation
+    public void setFrom(int from) {
+        assert !isEmpty();
+        first().from = from;
+    }
+
+    private boolean isEmpty() {
+        return first() == FixedRange.EndMarker;
+    }
+
+    public void addRange(int from, int to) {
+        if (isEmpty()) {
+            first = new FixedRange(from, to, first());
+            return;
+        }
+        if (to <= to() && from >= from()) {
+            return;
+        }
+        if (from() == to) {
+            first().from = from;
+        } else {
+            first = new FixedRange(from, to, first());
+        }
+    }
+
+    @Override
+    public AllocatableValue location() {
+        return operand;
+    }
+
+    /**
+     * Sentinel interval to denote the end of an interval list.
+     */
+    static final FixedInterval EndMarker = new FixedInterval(Value.ILLEGAL);
+
+    FixedInterval(AllocatableValue operand) {
+        assert operand != null;
+        this.operand = operand;
+        this.first = FixedRange.EndMarker;
+        this.current = FixedRange.EndMarker;
+        this.next = FixedInterval.EndMarker;
+        this.cachedTo = -1;
+    }
+
+    int calcTo() {
+        assert first != FixedRange.EndMarker : "interval has no range";
+
+        FixedRange r = first;
+        while (r.next != FixedRange.EndMarker) {
+            r = r.next;
+        }
+        return r.to;
+    }
+
+    // returns true if the opId is inside the interval
+    boolean covers(int opId, LIRInstruction.OperandMode mode) {
+        FixedRange cur = first;
+
+        while (cur != FixedRange.EndMarker && cur.to < opId) {
+            cur = cur.next;
+        }
+        if (cur != FixedRange.EndMarker) {
+            assert cur.to != cur.next.from : "ranges not separated";
+
+            if (mode == LIRInstruction.OperandMode.DEF) {
+                return cur.from <= opId && opId < cur.to;
+            } else {
+                return cur.from <= opId && opId <= cur.to;
+            }
+        }
+        return false;
+    }
+
+    // returns true if the interval has any hole between holeFrom and holeTo
+    // (even if the hole has only the length 1)
+    boolean hasHoleBetween(int holeFrom, int holeTo) {
+        assert holeFrom < holeTo : "check";
+        assert from() <= holeFrom && holeTo <= to() : "index out of interval";
+
+        FixedRange cur = first;
+        while (cur != FixedRange.EndMarker) {
+            assert cur.to < cur.next.from : "no space between ranges";
+
+            // hole-range starts before this range . hole
+            if (holeFrom < cur.from) {
+                return true;
+
+                // hole-range completely inside this range . no hole
+            } else {
+                if (holeTo <= cur.to) {
+                    return false;
+
+                    // overlapping of hole-range with this range . hole
+                } else {
+                    if (holeFrom <= cur.to) {
+                        return true;
+                    }
+                }
+            }
+
+            cur = cur.next;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        if (this == EndMarker) {
+            return "EndMarker [?,?]";
+        }
+        String from = "?";
+        String to = "?";
+        if (first != null && first != FixedRange.EndMarker) {
+            from = String.valueOf(from());
+            // to() may cache a computed value, modifying the current object, which is a bad idea
+            // for a printing function. Compute it directly instead.
+            to = String.valueOf(calcTo());
+        }
+        String locationString = "@" + this.operand;
+        return asRegister(operand).number + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
+    }
+
+    /**
+     * Gets a single line string for logging the details of this interval to a log stream.
+     */
+    @Override
+    public String logString() {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append("fix ").append(asRegister(operand).number).append(':').append(operand).append(' ');
+
+        buf.append(" ranges{");
+
+        // print ranges
+        FixedRange cur = first;
+        while (cur != FixedRange.EndMarker) {
+            if (cur != first) {
+                buf.append(", ");
+            }
+            buf.append(cur);
+            cur = cur.next;
+            assert cur != null : "range list not closed with range sentinel";
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedRange.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedRange.java
new file mode 100644
index 0000000..7e02ce6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedRange.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+/**
+ * Represents a range of integers from a start (inclusive) to an end (exclusive).
+ */
+final class FixedRange {
+
+    public static final FixedRange EndMarker = new FixedRange(Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+
+    /**
+     * The start of the range, inclusive.
+     */
+    public int from;
+
+    /**
+     * The end of the range, exclusive.
+     */
+    public int to;
+
+    /**
+     * A link to allow the range to be put into a singly linked list.
+     */
+    public FixedRange next;
+
+    boolean intersects(TraceInterval i) {
+        return intersectsAt(i) != -1;
+    }
+
+    /**
+     * Creates a new range.
+     *
+     * @param from the start of the range, inclusive
+     * @param to the end of the range, exclusive
+     * @param next link to the next range in a linked list
+     */
+    FixedRange(int from, int to, FixedRange next) {
+        this.from = from;
+        this.to = to;
+        this.next = next;
+    }
+
+    int intersectsAt(TraceInterval other) {
+        FixedRange range = this;
+        assert other != null : "null ranges not allowed";
+        assert range != EndMarker && other != TraceInterval.EndMarker : "empty ranges not allowed";
+        int intervalFrom = other.from();
+        int intervalTo = other.to();
+
+        do {
+            if (range.from < intervalFrom) {
+                if (range.to <= intervalFrom) {
+                    range = range.next;
+                    if (range == EndMarker) {
+                        return -1;
+                    }
+                } else {
+                    return intervalFrom;
+                }
+            } else {
+                if (intervalFrom < range.from) {
+                    if (intervalTo <= range.from) {
+                        return -1;
+                    }
+                    return range.from;
+                } else {
+                    assert range.from == intervalFrom;
+                    if (range.from == range.to) {
+                        range = range.next;
+                        if (range == EndMarker) {
+                            return -1;
+                        }
+                    } else {
+                        if (intervalFrom == intervalTo) {
+                            return -1;
+                        }
+                        return range.from;
+                    }
+                }
+            }
+        } while (true);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + from + ", " + to + "]";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/IntervalHint.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/IntervalHint.java
new file mode 100644
index 0000000..4818be4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/IntervalHint.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * An interval that is a hint for an {@code TraceInterval interval}.
+ */
+abstract class IntervalHint {
+
+    public abstract AllocatableValue location();
+
+    public abstract int from();
+
+    public abstract String logString();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/RegisterVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/RegisterVerifier.java
new file mode 100644
index 0000000..7a9542d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/RegisterVerifier.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.isVariableOrRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.ArrayMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+final class RegisterVerifier {
+
+    TraceLinearScan allocator;
+    List<AbstractBlockBase<?>> workList; // all blocks that must be processed
+    ArrayMap<TraceInterval[]> savedStates; // saved information of previous check
+
+    // simplified access to methods of LinearScan
+    TraceInterval intervalAt(Value operand) {
+        return allocator.intervalFor(operand);
+    }
+
+    // currently, only registers are processed
+    int stateSize() {
+        return allocator.numRegisters();
+    }
+
+    // accessors
+    TraceInterval[] stateForBlock(AbstractBlockBase<?> block) {
+        return savedStates.get(block.getId());
+    }
+
+    void setStateForBlock(AbstractBlockBase<?> block, TraceInterval[] savedState) {
+        savedStates.put(block.getId(), savedState);
+    }
+
+    void addToWorkList(AbstractBlockBase<?> block) {
+        if (!workList.contains(block)) {
+            workList.add(block);
+        }
+    }
+
+    RegisterVerifier(TraceLinearScan allocator) {
+        this.allocator = allocator;
+        workList = new ArrayList<>(16);
+        this.savedStates = new ArrayMap<>();
+
+    }
+
+    @SuppressWarnings("try")
+    void verify(AbstractBlockBase<?> start) {
+        try (Scope s = Debug.scope("RegisterVerifier")) {
+            // setup input registers (method arguments) for first block
+            TraceInterval[] inputState = new TraceInterval[stateSize()];
+            setStateForBlock(start, inputState);
+            addToWorkList(start);
+
+            // main loop for verification
+            do {
+                AbstractBlockBase<?> block = workList.get(0);
+                workList.remove(0);
+
+                processBlock(block);
+            } while (!workList.isEmpty());
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void processBlock(AbstractBlockBase<?> block) {
+        try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) {
+            // must copy state because it is modified
+            TraceInterval[] inputState = copy(stateForBlock(block));
+
+            try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // process all operations of the block
+            processOperations(block, inputState);
+
+            try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // iterate all successors
+            for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+                processSuccessor(succ, inputState);
+            }
+        }
+    }
+
+    protected void printState(TraceInterval[] inputState) {
+        for (int i = 0; i < stateSize(); i++) {
+            Register reg = allocator.getRegisters().get(i);
+            assert reg.number == i;
+            if (inputState[i] != null) {
+                Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
+            } else {
+                Debug.log(" %6s   __", reg);
+            }
+        }
+    }
+
+    private void processSuccessor(AbstractBlockBase<?> block, TraceInterval[] inputState) {
+        TraceInterval[] savedState = stateForBlock(block);
+
+        if (savedState != null) {
+            // this block was already processed before.
+            // check if new inputState is consistent with savedState
+
+            boolean savedStateCorrect = true;
+            for (int i = 0; i < stateSize(); i++) {
+                if (inputState[i] != savedState[i]) {
+                    // current inputState and previous savedState assume a different
+                    // interval in this register . assume that this register is invalid
+                    if (savedState[i] != null) {
+                        // invalidate old calculation only if it assumed that
+                        // register was valid. when the register was already invalid,
+                        // then the old calculation was correct.
+                        savedStateCorrect = false;
+                        savedState[i] = null;
+
+                        Debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i);
+                    }
+                }
+            }
+
+            if (savedStateCorrect) {
+                // already processed block with correct inputState
+                Debug.log("processSuccessor B%d: previous visit already correct", block.getId());
+            } else {
+                // must re-visit this block
+                Debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId());
+                addToWorkList(block);
+            }
+
+        } else {
+            // block was not processed before, so set initial inputState
+            Debug.log("processSuccessor B%d: initial visit", block.getId());
+
+            setStateForBlock(block, copy(inputState));
+            addToWorkList(block);
+        }
+    }
+
+    static TraceInterval[] copy(TraceInterval[] inputState) {
+        return inputState.clone();
+    }
+
+    static void statePut(TraceInterval[] inputState, Value location, TraceInterval interval) {
+        if (location != null && isRegister(location)) {
+            Register reg = asRegister(location);
+            int regNum = reg.number;
+            if (interval != null) {
+                Debug.log("%s = %s", reg, interval.operand);
+            } else if (inputState[regNum] != null) {
+                Debug.log("%s = null", reg);
+            }
+
+            inputState[regNum] = interval;
+        }
+    }
+
+    static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, TraceInterval[] inputState, Value operand, Value reg, TraceInterval interval) {
+        if (reg != null && isRegister(reg)) {
+            if (inputState[asRegister(reg).number] != interval) {
+                throw new GraalError(
+                                "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s",
+                                op, block, reg, operand, interval, inputState[asRegister(reg).number]);
+            }
+        }
+        return true;
+    }
+
+    void processOperations(AbstractBlockBase<?> block, final TraceInterval[] inputState) {
+        List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                // we skip spill moves inserted by the spill position optimization
+                if (isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != TraceLinearScanPhase.DOMINATOR_SPILL_MOVE_ID) {
+                    TraceInterval interval = intervalAt(operand);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), mode);
+                    }
+
+                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
+            if (isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                TraceInterval interval = intervalAt(operand);
+                if (op.id() != -1) {
+                    interval = interval.getSplitChildAtOpId(op.id(), mode);
+                }
+
+                statePut(inputState, interval.location(), interval.splitParent());
+            }
+        };
+
+        // visit all instructions of the block
+        for (int i = 0; i < ops.size(); i++) {
+            final LIRInstruction op = ops.get(i);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("%s", op.toStringWithIdPrefix());
+            }
+
+            // check if input operands are correct
+            op.visitEachInput(useConsumer);
+            // invalidate all caller save registers at calls
+            if (op.destroysCallerSavedRegisters()) {
+                for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
+                    statePut(inputState, r.asValue(), null);
+                }
+            }
+            op.visitEachAlive(useConsumer);
+            // set temp operands (some operations use temp operands also as output operands, so
+            // can't set them null)
+            op.visitEachTemp(defConsumer);
+            // set output operands
+            op.visitEachOutput(defConsumer);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java
new file mode 100644
index 0000000..1efdb95e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents an interval in the {@linkplain TraceLinearScan linear scan register allocator}.
+ */
+final class TraceInterval extends IntervalHint {
+
+    static final class AnyList {
+
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Any}.
+         */
+        public TraceInterval any;
+
+        AnyList(TraceInterval any) {
+            this.any = any;
+        }
+
+        /**
+         * Gets the any list.
+         */
+        public TraceInterval getAny() {
+            return any;
+        }
+
+        /**
+         * Sets the any list.
+         */
+        public void setAny(TraceInterval list) {
+            any = list;
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() current from}
+         * positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByFromPositions(TraceInterval interval) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur.from() < interval.from()) {
+                prev = cur;
+                cur = cur.next;
+            }
+            TraceInterval result = list;
+            if (prev == null) {
+                // add to head of list
+                result = interval;
+            } else {
+                // add before 'cur'
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setAny(result);
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() start} positions
+         * and {@linkplain TraceInterval#firstUsage(RegisterPriority) first usage} positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByStartAndUsePositions(TraceInterval interval) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                list = interval;
+            } else {
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setAny(list);
+        }
+
+        /**
+         * Removes an interval from a list.
+         *
+         * @param i the interval to remove
+         */
+        public void removeAny(TraceInterval i) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur != i) {
+                assert cur != null && cur != TraceInterval.EndMarker : "interval has not been found in list: " + i;
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                setAny(cur.next);
+            } else {
+                prev.next = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Constants denoting the register usage priority for an interval. The constants are declared in
+     * increasing order of priority are are used to optimize spilling when multiple overlapping
+     * intervals compete for limited registers.
+     */
+    public enum RegisterPriority {
+        /**
+         * No special reason for an interval to be allocated a register.
+         */
+        None,
+
+        /**
+         * Priority level for intervals live at the end of a loop.
+         */
+        LiveAtLoopEnd,
+
+        /**
+         * Priority level for intervals that should be allocated to a register.
+         */
+        ShouldHaveRegister,
+
+        /**
+         * Priority level for intervals that must be allocated to a register.
+         */
+        MustHaveRegister;
+
+        public static final RegisterPriority[] VALUES = values();
+
+        /**
+         * Determines if this priority is higher than or equal to a given priority.
+         */
+        public boolean greaterEqual(RegisterPriority other) {
+            return ordinal() >= other.ordinal();
+        }
+
+        /**
+         * Determines if this priority is lower than a given priority.
+         */
+        public boolean lessThan(RegisterPriority other) {
+            return ordinal() < other.ordinal();
+        }
+
+        public CharSequence shortName() {
+            return name().subSequence(0, 1);
+        }
+    }
+
+    /**
+     * Constants denoting whether an interval is bound to a specific register. This models platform
+     * dependencies on register usage for certain instructions.
+     */
+    enum RegisterBinding {
+        /**
+         * Interval is bound to a specific register as required by the platform.
+         */
+        Fixed,
+
+        /**
+         * Interval has no specific register requirements.
+         */
+        Any,
+
+        /**
+         * Interval is bound to a stack slot.
+         */
+        Stack;
+
+        public static final RegisterBinding[] VALUES = values();
+    }
+
+    /**
+     * Constants denoting the linear-scan states an interval may be in with respect to the
+     * {@linkplain TraceInterval#from() start} {@code position} of the interval being processed.
+     */
+    enum State {
+        /**
+         * An interval that starts after {@code position}.
+         */
+        Unhandled,
+
+        /**
+         * An interval that {@linkplain TraceInterval#covers covers} {@code position} and has an
+         * assigned register.
+         */
+        Active,
+
+        /**
+         * An interval that starts before and ends after {@code position} but does not
+         * {@linkplain TraceInterval#covers cover} it due to a lifetime hole.
+         */
+        Inactive,
+
+        /**
+         * An interval that ends before {@code position} or is spilled to memory.
+         */
+        Handled;
+    }
+
+    /**
+     * Constants used in optimization of spilling of an interval.
+     */
+    public enum SpillState {
+        /**
+         * Starting state of calculation: no definition found yet.
+         */
+        NoDefinitionFound,
+
+        /**
+         * One definition has already been found. Two consecutive definitions are treated as one
+         * (e.g. a consecutive move and add because of two-operand LIR form). The position of this
+         * definition is given by {@link TraceInterval#spillDefinitionPos()}.
+         */
+        NoSpillStore,
+
+        /**
+         * A spill move has already been inserted.
+         */
+        SpillStore,
+
+        /**
+         * The interval starts in memory (e.g. method parameter), so a store is never necessary.
+         */
+        StartInMemory,
+
+        /**
+         * The interval has more than one definition (e.g. resulting from phi moves), so stores to
+         * memory are not optimized.
+         */
+        NoOptimization;
+
+        public static final EnumSet<SpillState> IN_MEMORY = EnumSet.of(SpillStore, StartInMemory);
+    }
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
+     * prior to register allocation.
+     */
+    public final AllocatableValue operand;
+
+    /**
+     * The operand number for this interval's {@linkplain #operand operand}.
+     */
+    public final int operandNumber;
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
+     * interval. In case of a spilled interval which is re-materialized this is
+     * {@link Value#ILLEGAL}.
+     */
+    private AllocatableValue location;
+
+    /**
+     * The stack slot to which all splits of this interval are spilled if necessary.
+     */
+    private AllocatableValue spillSlot;
+
+    /**
+     * The start of the range, inclusive.
+     */
+    private int intFrom;
+
+    /**
+     * The end of the range, exclusive.
+     */
+    private int intTo;
+
+    /**
+     * List of (use-positions, register-priorities) pairs, sorted by use-positions.
+     */
+    private int[] usePosListArray;
+    private int usePosListSize;
+
+    /**
+     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
+     */
+    TraceInterval next;
+
+    /**
+     * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split
+     * parent}, it points to itself.
+     */
+    private TraceInterval splitParent;
+
+    /**
+     * List of all intervals that are split off from this interval. This is only used if this is a
+     * {@linkplain #isSplitParent() split parent}.
+     */
+    private List<TraceInterval> splitChildren = Collections.emptyList();
+
+    /**
+     * Current split child that has been active or inactive last (always stored in split parents).
+     */
+    private TraceInterval currentSplitChild;
+
+    /**
+     * Specifies if move is inserted between currentSplitChild and this interval when interval gets
+     * active the first time.
+     */
+    private boolean insertMoveWhenActivated;
+
+    /**
+     * For spill move optimization.
+     */
+    private SpillState spillState;
+
+    /**
+     * Position where this interval is defined (if defined only once).
+     */
+    private int spillDefinitionPos;
+
+    /**
+     * This interval should be assigned the same location as the hint interval.
+     */
+    private IntervalHint locationHint;
+
+    /**
+     * The value with which a spilled child interval can be re-materialized. Currently this must be
+     * a Constant.
+     */
+    private JavaConstant materializedValue;
+
+    /**
+     * The number of times {@link #addMaterializationValue(JavaConstant)} is called.
+     */
+    private int numMaterializationValuesAdded;
+
+    void assignLocation(AllocatableValue newLocation) {
+        if (isRegister(newLocation)) {
+            assert this.location == null : "cannot re-assign location for " + this;
+            if (newLocation.getValueKind().equals(LIRKind.Illegal) && !kind().equals(LIRKind.Illegal)) {
+                this.location = asRegister(newLocation).asValue(kind());
+                return;
+            }
+        } else if (isIllegal(newLocation)) {
+            assert canMaterialize();
+        } else {
+            assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this;
+            assert isStackSlotValue(newLocation);
+            assert !newLocation.getValueKind().equals(LIRKind.Illegal);
+            assert newLocation.getValueKind().equals(this.kind());
+        }
+        this.location = newLocation;
+    }
+
+    /**
+     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
+     * this interval.
+     */
+    @Override
+    public AllocatableValue location() {
+        return location;
+    }
+
+    public ValueKind<?> kind() {
+        return operand.getValueKind();
+    }
+
+    public boolean isEmpty() {
+        return intFrom == Integer.MAX_VALUE && intTo == Integer.MAX_VALUE;
+    }
+
+    public void setTo(int pos) {
+        assert intFrom == Integer.MAX_VALUE || intFrom < pos;
+        intTo = pos;
+    }
+
+    public void setFrom(int pos) {
+        assert intTo == Integer.MAX_VALUE || pos < intTo;
+        intFrom = pos;
+    }
+
+    @Override
+    public int from() {
+        return intFrom;
+    }
+
+    int to() {
+        return intTo;
+    }
+
+    int numUsePositions() {
+        return numUsePos();
+    }
+
+    public void setLocationHint(IntervalHint interval) {
+        locationHint = interval;
+    }
+
+    public boolean isSplitParent() {
+        return splitParent == this;
+    }
+
+    boolean isSplitChild() {
+        return splitParent != this;
+    }
+
+    /**
+     * Gets the split parent for this interval.
+     */
+    public TraceInterval splitParent() {
+        assert splitParent.isSplitParent() : "not a split parent: " + this;
+        return splitParent;
+    }
+
+    /**
+     * Gets the canonical spill slot for this interval.
+     */
+    public AllocatableValue spillSlot() {
+        return splitParent().spillSlot;
+    }
+
+    public void setSpillSlot(AllocatableValue slot) {
+        assert isStackSlotValue(slot);
+        assert spillSlot() == null || (isVirtualStackSlot(spillSlot()) && isStackSlot(slot)) : String.format("cannot overwrite existing spill slot %s of interval %s with %s", spillSlot(), this, slot);
+        splitParent().spillSlot = slot;
+    }
+
+    TraceInterval currentSplitChild() {
+        return splitParent().currentSplitChild;
+    }
+
+    void makeCurrentSplitChild() {
+        splitParent().currentSplitChild = this;
+    }
+
+    boolean insertMoveWhenActivated() {
+        return insertMoveWhenActivated;
+    }
+
+    void setInsertMoveWhenActivated(boolean b) {
+        insertMoveWhenActivated = b;
+    }
+
+    // for spill optimization
+    public SpillState spillState() {
+        return splitParent().spillState;
+    }
+
+    public int spillDefinitionPos() {
+        return splitParent().spillDefinitionPos;
+    }
+
+    public void setSpillState(SpillState state) {
+        assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
+        splitParent().spillState = state;
+    }
+
+    public void setSpillDefinitionPos(int pos) {
+        assert spillState() == SpillState.NoDefinitionFound || spillState() == SpillState.NoSpillStore || spillDefinitionPos() == -1 : "cannot set the position twice";
+        int to = to();
+        assert pos < to : String.format("Cannot spill %s at %d", this, pos);
+        splitParent().spillDefinitionPos = pos;
+    }
+
+    /**
+     * Returns true if this interval has a shadow copy on the stack that is correct after
+     * {@code opId}.
+     */
+    public boolean inMemoryAt(int opId) {
+        SpillState spillSt = spillState();
+        return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
+    }
+
+    // test intersection
+    boolean intersects(TraceInterval i) {
+        return intersectsAt(i) != -1;
+    }
+
+    int intersectsAt(TraceInterval i) {
+        TraceInterval i1;
+        TraceInterval i2;
+        if (i.from() < this.from()) {
+            i1 = i;
+            i2 = this;
+        } else {
+            i1 = this;
+            i2 = i;
+        }
+        assert i1.from() <= i2.from();
+
+        if (i1.to() <= i2.from()) {
+            return -1;
+        }
+        return i2.from();
+    }
+
+    /**
+     * Sentinel interval to denote the end of an interval list.
+     */
+    static final TraceInterval EndMarker = new TraceInterval(Value.ILLEGAL, -1);
+
+    TraceInterval(AllocatableValue operand, int operandNumber) {
+        assert operand != null;
+        this.operand = operand;
+        this.operandNumber = operandNumber;
+        if (isRegister(operand)) {
+            location = operand;
+        } else {
+            assert isIllegal(operand) || isVariable(operand);
+        }
+        this.intFrom = Integer.MAX_VALUE;
+        this.intTo = Integer.MAX_VALUE;
+        this.usePosListArray = new int[4 * 2];
+        this.next = EndMarker;
+        this.spillState = SpillState.NoDefinitionFound;
+        this.spillDefinitionPos = -1;
+        splitParent = this;
+        currentSplitChild = this;
+    }
+
+    /**
+     * Sets the value which is used for re-materialization.
+     */
+    public void addMaterializationValue(JavaConstant value) {
+        if (numMaterializationValuesAdded == 0) {
+            materializedValue = value;
+        } else {
+            // Interval is defined on multiple places -> no materialization is possible.
+            materializedValue = null;
+        }
+        numMaterializationValuesAdded++;
+    }
+
+    /**
+     * Returns true if this interval can be re-materialized when spilled. This means that no
+     * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored.
+     */
+    public boolean canMaterialize() {
+        return getMaterializedValue() != null;
+    }
+
+    /**
+     * Returns a value which can be moved to a register instead of a restore-move from stack.
+     */
+    public JavaConstant getMaterializedValue() {
+        return splitParent().materializedValue;
+    }
+
+    // consistency check of split-children
+    boolean checkSplitChildren() {
+        if (!splitChildren.isEmpty()) {
+            assert isSplitParent() : "only split parents can have children";
+
+            for (int i = 0; i < splitChildren.size(); i++) {
+                TraceInterval i1 = splitChildren.get(i);
+
+                assert i1.splitParent() == this : "not a split child of this interval";
+                assert i1.kind().equals(kind()) : "must be equal for all split children";
+                assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
+
+                for (int j = i + 1; j < splitChildren.size(); j++) {
+                    TraceInterval i2 = splitChildren.get(j);
+
+                    assert !i1.operand.equals(i2.operand) : "same register number";
+
+                    if (i1.from() < i2.from()) {
+                        assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
+                    } else {
+                        assert i2.from() < i1.from() : "intervals start at same opId";
+                        assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public IntervalHint locationHint(boolean searchSplitChild) {
+        if (!searchSplitChild) {
+            return locationHint;
+        }
+
+        if (locationHint != null) {
+            assert !(locationHint instanceof TraceInterval) || ((TraceInterval) locationHint).isSplitParent() : "ony split parents are valid hint registers";
+
+            if (locationHint.location() != null && isRegister(locationHint.location())) {
+                return locationHint;
+            } else if (locationHint instanceof TraceInterval) {
+                TraceInterval hint = (TraceInterval) locationHint;
+                if (!hint.splitChildren.isEmpty()) {
+                    // search the first split child that has a register assigned
+                    int len = hint.splitChildren.size();
+                    for (int i = 0; i < len; i++) {
+                        TraceInterval interval = hint.splitChildren.get(i);
+                        if (interval.location != null && isRegister(interval.location)) {
+                            return interval;
+                        }
+                    }
+                }
+            }
+        }
+
+        // no hint interval found that has a register assigned
+        return null;
+    }
+
+    TraceInterval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            assert this.covers(opId, mode) : this + " does not cover " + opId;
+            return this;
+        } else {
+            TraceInterval result = null;
+            int len = splitChildren.size();
+
+            // in outputMode, the end of the interval (opId == cur.to()) is not valid
+            int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
+
+            int i;
+            for (i = 0; i < len; i++) {
+                TraceInterval cur = splitChildren.get(i);
+                if (cur.from() <= opId && opId < cur.to() + toOffset) {
+                    if (i > 0) {
+                        // exchange current split child to start of list (faster access for next
+                        // call)
+                        Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
+                        Util.atPutGrow(splitChildren, 0, cur, null);
+                    }
+
+                    // interval found
+                    result = cur;
+                    break;
+                }
+            }
+
+            assert checkSplitChild(result, opId, toOffset, mode);
+            return result;
+        }
+    }
+
+    private boolean checkSplitChild(TraceInterval result, int opId, int toOffset, LIRInstruction.OperandMode mode) {
+        if (result == null) {
+            // this is an error
+            StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
+            if (!splitChildren.isEmpty()) {
+                TraceInterval firstChild = splitChildren.get(0);
+                TraceInterval lastChild = splitChildren.get(splitChildren.size() - 1);
+                msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")");
+            }
+            throw new GraalError("Linear Scan Error: %s", msg);
+        }
+
+        if (!splitChildren.isEmpty()) {
+            for (TraceInterval interval : splitChildren) {
+                if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
+                    /*
+                     * Should not happen: Try another compilation as it is very unlikely to happen
+                     * again.
+                     */
+                    throw new GraalError("two valid result intervals found for opId %d: %d and %d\n%s\n", opId, result.operandNumber, interval.operandNumber,
+                                    result.logString(), interval.logString());
+                }
+            }
+        }
+        assert result.covers(opId, mode) : "opId not covered by interval";
+        return true;
+    }
+
+    // returns the interval that covers the given opId or null if there is none
+    TraceInterval getIntervalCoveringOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+        assert opId < to() : "can only look into the past";
+
+        if (opId >= from()) {
+            return this;
+        }
+
+        TraceInterval parent = splitParent();
+        TraceInterval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            TraceInterval cur = parent.splitChildren.get(i);
+            if (cur.from() <= opId && opId < cur.to()) {
+                assert result == null : "covered by multiple split children " + result + " and " + cur;
+                result = cur;
+            }
+        }
+
+        return result;
+    }
+
+    // returns the last split child that ends before the given opId
+    TraceInterval getSplitChildBeforeOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+
+        TraceInterval parent = splitParent();
+        TraceInterval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            TraceInterval cur = parent.splitChildren.get(i);
+            if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
+                result = cur;
+            }
+        }
+
+        assert result != null : "no split child found";
+        return result;
+    }
+
+    // checks if opId is covered by any split child
+    boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            // simple case if interval was not split
+            return covers(opId, mode);
+
+        } else {
+            // extended case: check all split children
+            int len = splitChildren.size();
+            for (int i = 0; i < len; i++) {
+                TraceInterval cur = splitChildren.get(i);
+                if (cur.covers(opId, mode)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private RegisterPriority adaptPriority(RegisterPriority priority) {
+        /*
+         * In case of re-materialized values we require that use-operands are registers, because we
+         * don't have the value in a stack location. (Note that ShouldHaveRegister means that the
+         * operand can also be a StackSlot).
+         */
+        if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
+            return RegisterPriority.MustHaveRegister;
+        }
+        return priority;
+    }
+
+    // Note: use positions are sorted descending . first use has highest index
+    int firstUsage(RegisterPriority minRegisterPriority) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = numUsePos() - 1; i >= 0; --i) {
+            RegisterPriority registerPriority = adaptPriority(getUsePosRegisterPriority(i));
+            if (registerPriority.greaterEqual(minRegisterPriority)) {
+                return getUsePos(i);
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = numUsePos() - 1; i >= 0; --i) {
+            int usePos = getUsePos(i);
+            if (usePos >= from && adaptPriority(getUsePosRegisterPriority(i)).greaterEqual(minRegisterPriority)) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = numUsePos() - 1; i >= 0; --i) {
+            int usePos = getUsePos(i);
+            if (usePos >= from && adaptPriority(getUsePosRegisterPriority(i)) == exactRegisterPriority) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int previousUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        int prev = -1;
+        for (int i = numUsePos() - 1; i >= 0; --i) {
+            int usePos = getUsePos(i);
+            if (usePos > from) {
+                return prev;
+            }
+            if (adaptPriority(getUsePosRegisterPriority(i)).greaterEqual(minRegisterPriority)) {
+                prev = usePos;
+            }
+        }
+        return prev;
+    }
+
+    public void addUsePos(int pos, RegisterPriority registerPriority) {
+        assert isEmpty() || covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
+
+        // do not add use positions for precolored intervals because they are never used
+        if (registerPriority != RegisterPriority.None && isVariable(operand)) {
+            if (DetailedAsserts.getValue()) {
+                for (int i = 0; i < numUsePos(); i++) {
+                    assert pos <= getUsePos(i) : "already added a use-position with lower position";
+                    if (i > 0) {
+                        assert getUsePos(i) < getUsePos(i - 1) : "not sorted descending";
+                    }
+                }
+            }
+
+            // Note: addUse is called in descending order, so list gets sorted
+            // automatically by just appending new use positions
+            int len = numUsePos();
+            if (len == 0 || getUsePos(len - 1) > pos) {
+                usePosAdd(pos, registerPriority);
+            } else if (getUsePosRegisterPriority(len - 1).lessThan(registerPriority)) {
+                assert getUsePos(len - 1) == pos : "list not sorted correctly";
+                setUsePosRegisterPriority(len - 1, registerPriority);
+            }
+        }
+    }
+
+    public void addRange(int from, int to) {
+        assert from < to : "invalid range";
+
+        if (from < intFrom) {
+            setFrom(from);
+        }
+        if (intTo == Integer.MAX_VALUE || intTo < to) {
+            setTo(to);
+        }
+    }
+
+    TraceInterval newSplitChild(TraceLinearScan allocator) {
+        // allocate new interval
+        TraceInterval parent = splitParent();
+        TraceInterval result = allocator.createDerivedInterval(parent);
+
+        result.splitParent = parent;
+        result.setLocationHint(parent);
+
+        // insert new interval in children-list of parent
+        if (parent.splitChildren.isEmpty()) {
+            assert isSplitParent() : "list must be initialized at first split";
+
+            // Create new non-shared list
+            parent.splitChildren = new ArrayList<>(4);
+            parent.splitChildren.add(this);
+        }
+        parent.splitChildren.add(result);
+
+        return result;
+    }
+
+    /**
+     * Splits this interval at a specified position and returns the remainder as a new <i>child</i>
+     * interval of this interval's {@linkplain #splitParent() parent} interval.
+     * <p>
+     * When an interval is split, a bi-directional link is established between the original
+     * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval.
+     * When a split child is split again, the new created interval is a direct child of the original
+     * parent. That is, there is no tree of split children stored, just a flat list. All split
+     * children are spilled to the same {@linkplain #spillSlot spill slot}.
+     *
+     * @param splitPos the position at which to split this interval
+     * @param allocator the register allocator context
+     * @return the child interval split off from this interval
+     */
+    TraceInterval split(int splitPos, TraceLinearScan allocator) {
+        assert isVariable(operand) : "cannot split fixed intervals";
+
+        // allocate new interval
+        TraceInterval result = newSplitChild(allocator);
+
+        // split the ranges
+        result.setTo(intTo);
+        result.setFrom(splitPos);
+        intTo = splitPos;
+
+        // split list of use positions
+        splitUsePosAt(result, splitPos);
+
+        if (DetailedAsserts.getValue()) {
+            for (int i = 0; i < numUsePos(); i++) {
+                assert getUsePos(i) < splitPos;
+            }
+            for (int i = 0; i < result.numUsePos(); i++) {
+                assert result.getUsePos(i) >= splitPos;
+            }
+        }
+        return result;
+    }
+
+    // returns true if the opId is inside the interval
+    boolean covers(int opId, LIRInstruction.OperandMode mode) {
+        if (mode == LIRInstruction.OperandMode.DEF) {
+            return from() <= opId && opId < to();
+        }
+        return from() <= opId && opId <= to();
+    }
+
+    @Override
+    public String toString() {
+        String from = "?";
+        String to = "?";
+        if (!isEmpty()) {
+            from = String.valueOf(from());
+            to = String.valueOf(to());
+        }
+        String locationString = this.location == null ? "" : "@" + this.location;
+        return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
+    }
+
+    /**
+     * Gets a single line string for logging the details of this interval to a log stream.
+     */
+    @Override
+    public String logString() {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append("any ").append(operandNumber).append(':').append(operand).append(' ');
+        if (!isRegister(operand)) {
+            if (location != null) {
+                buf.append("location{").append(location).append("} ");
+            }
+        }
+
+        buf.append("hints{").append(splitParent.operandNumber);
+        IntervalHint hint = locationHint(false);
+        if (hint != null) {
+            buf.append(", ").append(hint.location());
+        }
+        buf.append("} ranges{");
+
+        // print range
+        buf.append("[" + from() + ", " + to() + "]");
+        buf.append("} uses{");
+
+        // print use positions
+        int prev = -1;
+        for (int i = numUsePos() - 1; i >= 0; --i) {
+            assert prev < getUsePos(i) : "use positions not sorted";
+            if (i != numUsePos() - 1) {
+                buf.append(", ");
+            }
+            buf.append(getUsePos(i)).append(':').append(getUsePosRegisterPriority(i).shortName());
+            prev = getUsePos(i);
+        }
+        buf.append("} spill-state{").append(spillState()).append("}");
+        if (canMaterialize()) {
+            buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
+        }
+        return buf.toString();
+    }
+
+    List<TraceInterval> getSplitChildren() {
+        return Collections.unmodifiableList(splitChildren);
+    }
+
+    boolean isFixedInterval() {
+        return isRegister(operand);
+    }
+
+    private static boolean isDefinitionPosition(int usePos) {
+        return (usePos & 1) == 1;
+    }
+
+    int currentFrom(int currentPosition) {
+        assert isFixedInterval();
+        for (int i = 0; i < numUsePos(); i++) {
+            int usePos = getUsePos(i);
+            if (usePos <= currentPosition && isDefinitionPosition(usePos)) {
+                return usePos;
+            }
+
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int currentIntersectsAt(int currentPosition, TraceInterval current) {
+        assert isFixedInterval();
+        assert !current.isFixedInterval();
+        int from = Integer.MAX_VALUE;
+        int to = Integer.MIN_VALUE;
+
+        for (int i = 0; i < numUsePos(); i++) {
+            int usePos = getUsePos(i);
+            if (isDefinitionPosition(usePos)) {
+                if (usePos <= currentPosition) {
+                    from = usePos;
+                    break;
+                }
+                to = Integer.MIN_VALUE;
+            } else {
+                if (to < usePos) {
+                    to = usePos;
+                }
+            }
+        }
+        if (from < current.from()) {
+            if (to <= current.from()) {
+                return -1;
+            }
+            return current.from();
+        } else {
+            if (current.to() <= from) {
+                return -1;
+            }
+            return from;
+        }
+    }
+
+    /*
+     * UsePos
+     *
+     * List of use positions. Each entry in the list records the use position and register priority
+     * associated with the use position. The entries in the list are in descending order of use
+     * position.
+     *
+     */
+
+    /**
+     * Gets the use position at a specified index in this list.
+     *
+     * @param index the index of the entry for which the use position is returned
+     * @return the use position of entry {@code index} in this list
+     */
+    int getUsePos(int index) {
+        return intListGet(index << 1);
+    }
+
+    int numUsePos() {
+        return usePosListSize >> 1;
+    }
+
+    /**
+     * Gets the register priority for the use position at a specified index in this list.
+     *
+     * @param index the index of the entry for which the register priority is returned
+     * @return the register priority of entry {@code index} in this list
+     */
+    RegisterPriority getUsePosRegisterPriority(int index) {
+        return RegisterPriority.VALUES[intListGet((index << 1) + 1)];
+    }
+
+    void removeFirstUsePos() {
+        intListSetSize(usePosListSize - 2);
+    }
+
+    // internal
+
+    private void setUsePosRegisterPriority(int pos, RegisterPriority registerPriority) {
+        int index = (pos << 1) + 1;
+        int value = registerPriority.ordinal();
+        intListSet(index, value);
+    }
+
+    private void usePosAdd(int pos, RegisterPriority registerPriority) {
+        assert usePosListSize == 0 || getUsePos(numUsePos() - 1) > pos;
+        intListAdd(pos);
+        intListAdd(registerPriority.ordinal());
+    }
+
+    private void splitUsePosAt(TraceInterval result, int splitPos) {
+        int i = numUsePos() - 1;
+        int len = 0;
+        while (i >= 0 && getUsePos(i) < splitPos) {
+            --i;
+            len += 2;
+        }
+        int listSplitIndex = (i + 1) * 2;
+        int[] array = new int[len];
+        System.arraycopy(usePosListArray, listSplitIndex, array, 0, len);
+        if (listSplitIndex < usePosListSize) {
+            usePosListSize = listSplitIndex;
+        } else {
+            assert listSplitIndex == usePosListSize : "splitting cannot grow the use position array!";
+        }
+        result.usePosListArray = usePosListArray;
+        result.usePosListSize = usePosListSize;
+        usePosListArray = array;
+        usePosListSize = len;
+    }
+
+    // IntList
+
+    private int intListGet(int index) {
+        if (index >= usePosListSize) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + usePosListSize);
+        }
+        return usePosListArray[index];
+    }
+
+    private void intListSet(int index, int value) {
+        if (index >= usePosListSize) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + usePosListSize);
+        }
+        usePosListArray[index] = value;
+    }
+
+    private void intListAdd(int pos) {
+        if (usePosListSize == usePosListArray.length) {
+            int newSize = (usePosListSize * 3) / 2 + 1;
+            usePosListArray = Arrays.copyOf(usePosListArray, newSize);
+        }
+        usePosListArray[usePosListSize++] = pos;
+    }
+
+    private void intListSetSize(int newSize) {
+        if (newSize < usePosListSize) {
+            usePosListSize = newSize;
+        } else if (newSize > usePosListSize) {
+            usePosListArray = Arrays.copyOf(usePosListArray, newSize);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceIntervalWalker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceIntervalWalker.java
new file mode 100644
index 0000000..bb39397
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceIntervalWalker.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.alloc.trace.lsra.FixedInterval.FixedList;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.AnyList;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterBinding;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.State;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+
+/**
+ */
+class TraceIntervalWalker {
+
+    protected final TraceLinearScan allocator;
+
+    /**
+     * Sorted list of intervals, not live before the current position.
+     */
+    protected AnyList unhandledAnyList;
+
+    /**
+     * Sorted list of intervals, live at the current position.
+     */
+    protected AnyList activeAnyList;
+    protected FixedList activeFixedList;
+
+    /**
+     * Sorted list of intervals in a life time hole at the current position.
+     */
+    protected FixedList inactiveFixedList;
+
+    /**
+     * The current position (intercept point through the intervals).
+     */
+    protected int currentPosition;
+
+    /**
+     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
+     * to it and thus allow it to be moved to a list of {@linkplain #activeAnyList active}
+     * intervals.
+     *
+     * @param currentInterval The interval to be activated.
+     *
+     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
+     */
+    protected boolean activateCurrent(TraceInterval currentInterval) {
+        if (Debug.isLogEnabled()) {
+            logCurrentStatus();
+        }
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    protected void logCurrentStatus() {
+        try (Indent i = Debug.logAndIndent("active:")) {
+            logList(activeFixedList.getFixed());
+            logList(activeAnyList.getAny());
+        }
+        try (Indent i = Debug.logAndIndent("inactive(fixed):")) {
+            logList(inactiveFixedList.getFixed());
+        }
+    }
+
+    private static void logList(FixedInterval i) {
+        for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString());
+        }
+    }
+
+    private static void logList(TraceInterval i) {
+        for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString());
+        }
+    }
+
+    void walkBefore(int lirOpId) {
+        walkTo(lirOpId - 1);
+    }
+
+    void walk() {
+        walkTo(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a new interval walker.
+     *
+     * @param allocator the register allocator context
+     * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
+     *            intervals
+     * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed}
+     *            intervals
+     */
+    TraceIntervalWalker(TraceLinearScan allocator, FixedInterval unhandledFixed, TraceInterval unhandledAny) {
+        this.allocator = allocator;
+
+        unhandledAnyList = new AnyList(unhandledAny);
+        activeAnyList = new AnyList(TraceInterval.EndMarker);
+        activeFixedList = new FixedList(FixedInterval.EndMarker);
+        // we don't need a separate unhandled list for fixed.
+        inactiveFixedList = new FixedList(unhandledFixed);
+        currentPosition = -1;
+    }
+
+    protected void removeFromList(TraceInterval interval) {
+        activeAnyList.removeAny(interval);
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}.
+     *
+     * Fixed intervals can switch back and forth between the states {@link State#Active} and
+     * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not
+     * managed).
+     */
+    @SuppressWarnings("try")
+    private void walkToFixed(State state, int from) {
+        assert state == State.Active || state == State.Inactive : "wrong state";
+        FixedInterval prevprev = null;
+        FixedInterval prev = (state == State.Active) ? activeFixedList.getFixed() : inactiveFixedList.getFixed();
+        FixedInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) {
+                logList(next);
+            }
+        }
+        while (next.currentFrom() <= from) {
+            FixedInterval cur = next;
+            next = cur.next;
+
+            boolean rangeHasChanged = false;
+            while (cur.currentTo() <= from) {
+                cur.nextRange();
+                rangeHasChanged = true;
+            }
+
+            // also handle move from inactive list to active list
+            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+
+            if (rangeHasChanged) {
+                // remove cur from list
+                if (prevprev == null) {
+                    if (state == State.Active) {
+                        activeFixedList.setFixed(next);
+                    } else {
+                        inactiveFixedList.setFixed(next);
+                    }
+                } else {
+                    prevprev.next = next;
+                }
+                prev = next;
+                TraceInterval.State newState;
+                if (cur.currentAtEnd()) {
+                    // move to handled state (not maintained as a list)
+                    newState = State.Handled;
+                } else {
+                    if (cur.currentFrom() <= from) {
+                        // sort into active list
+                        activeFixedList.addToListSortedByCurrentFromPositions(cur);
+                        newState = State.Active;
+                    } else {
+                        // sort into inactive list
+                        inactiveFixedList.addToListSortedByCurrentFromPositions(cur);
+                        newState = State.Inactive;
+                    }
+                    if (prev == cur) {
+                        assert state == newState;
+                        prevprev = prev;
+                        prev = cur.next;
+                    }
+                }
+                intervalMoved(cur, state, newState);
+            } else {
+                prevprev = prev;
+                prev = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}.
+     *
+     * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then
+     * to {@link State#Handled} but handled intervals are not managed.
+     */
+    @SuppressWarnings("try")
+    private void walkToAny(int from) {
+        TraceInterval prevprev = null;
+        TraceInterval prev = activeAnyList.getAny();
+        TraceInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) {
+                logList(next);
+            }
+        }
+        while (next.from() <= from) {
+            TraceInterval cur = next;
+            next = cur.next;
+
+            if (cur.to() <= from) {
+                // remove cur from list
+                if (prevprev == null) {
+                    activeAnyList.setAny(next);
+                } else {
+                    prevprev.next = next;
+                }
+                intervalMoved(cur, State.Active, State.Handled);
+            } else {
+                prevprev = prev;
+            }
+            prev = next;
+        }
+    }
+
+    /**
+     * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at
+     * {@code toOpId}. The returned interval is removed.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private TraceInterval nextInterval(int toOpId) {
+        TraceInterval any = unhandledAnyList.getAny();
+
+        if (any != TraceInterval.EndMarker) {
+            TraceInterval currentInterval = unhandledAnyList.getAny();
+            if (toOpId < currentInterval.from()) {
+                return null;
+            }
+
+            unhandledAnyList.setAny(currentInterval.next);
+            currentInterval.next = TraceInterval.EndMarker;
+            return currentInterval;
+        }
+        return null;
+
+    }
+
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList}
+     *                and {@link #inactiveFixedList} are populated.
+     */
+    @SuppressWarnings("try")
+    protected void walkTo(int toOpId) {
+        assert currentPosition <= toOpId : "can not walk backwards";
+        for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
+
+            // set currentPosition prior to call of walkTo
+            currentPosition = opId;
+
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(opId);
+
+            // call walkTo even if currentPosition == id
+            walkToFixed(State.Active, opId);
+            walkToFixed(State.Inactive, opId);
+            walkToAny(opId);
+
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                if (activateCurrent(currentInterval)) {
+                    activeAnyList.addToListSortedByFromPositions(currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
+
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkToFixed(State.Active, toOpId);
+            walkToFixed(State.Inactive, toOpId);
+            walkToAny(toOpId);
+        }
+    }
+
+    private static void intervalMoved(IntervalHint interval, State from, State to) {
+        // intervalMoved() is called whenever an interval moves from one interval list to another.
+        // In the implementation of this method it is prohibited to move the interval to any list.
+        if (Debug.isLogEnabled()) {
+            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java
new file mode 100644
index 0000000..abfa0b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+abstract class TraceLinearScanAllocationPhase extends TraceAllocationPhase<TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext> {
+
+    static final class TraceLinearScanAllocationContext extends TraceAllocationPhase.TraceAllocationContext {
+        public final TraceLinearScan allocator;
+
+        TraceLinearScanAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
+            super(spillMoveFactory, registerAllocationConfig, traceBuilderResult);
+            this.allocator = allocator;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java
new file mode 100644
index 0000000..5ae77d6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Specialization of {@link org.graalvm.compiler.lir.alloc.lsra.LinearScanAssignLocationsPhase} that
+ * inserts {@link ShadowedRegisterValue}s to describe {@link RegisterValue}s that are also available
+ * on the {@link StackSlot stack}.
+ */
+final class TraceLinearScanAssignLocationsPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
+        TraceLinearScan allocator = context.allocator;
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        new Assigner(allocator, spillMoveFactory).assignLocations();
+    }
+
+    private static final class Assigner {
+        private final TraceLinearScan allocator;
+        private final MoveFactory spillMoveFactory;
+
+        private Assigner(TraceLinearScan allocator, MoveFactory spillMoveFactory) {
+            this.allocator = allocator;
+            this.spillMoveFactory = spillMoveFactory;
+        }
+
+        /**
+         * Assigns the allocated location for an LIR instruction operand back into the instruction.
+         *
+         * @param op current {@link LIRInstruction}
+         * @param operand an LIR instruction operand
+         * @param mode the usage mode for {@code operand} by the instruction
+         * @return the location assigned for the operand
+         */
+        private Value colorLirOperand(LIRInstruction op, Variable operand, OperandMode mode) {
+            int opId = op.id();
+            TraceInterval interval = allocator.intervalFor(operand);
+            assert interval != null : "interval must exist";
+
+            if (opId != -1) {
+                /*
+                 * Operands are not changed when an interval is split during allocation, so search
+                 * the right interval here.
+                 */
+                interval = allocator.splitChildAtOpId(interval, opId, mode);
+            }
+
+            if (isIllegal(interval.location()) && interval.canMaterialize()) {
+                if (op instanceof LabelOp) {
+                    /*
+                     * Spilled materialized value in a LabelOp (i.e. incoming): no need for move
+                     * resolution so we can ignore it.
+                     */
+                    return Value.ILLEGAL;
+                }
+                assert mode != OperandMode.DEF;
+                return new ConstantValue(interval.kind(), interval.getMaterializedValue());
+            }
+            return interval.location();
+        }
+
+        /**
+         * @param op
+         * @param operand
+         * @param valueMode
+         * @param flags
+         * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
+         */
+        private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+            if (isVirtualStackSlot(operand)) {
+                return operand;
+            }
+            int tempOpId = op.id();
+            OperandMode mode = OperandMode.USE;
+            AbstractBlockBase<?> block = allocator.blockForId(tempOpId);
+            if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) {
+                /*
+                 * Generating debug information for the last instruction of a block. If this
+                 * instruction is a branch, spill moves are inserted before this branch and so the
+                 * wrong operand would be returned (spill moves at block boundaries are not
+                 * considered in the live ranges of intervals).
+                 *
+                 * Solution: use the first opId of the branch target block instead.
+                 */
+                final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
+                if (instr instanceof StandardOp.JumpOp) {
+                    throw GraalError.unimplemented("DebugInfo on jumps are not supported!");
+                }
+            }
+
+            /*
+             * Get current location of operand. The operand must be live because debug information
+             * is considered when building the intervals if the interval is not live,
+             * colorLirOperand will cause an assert on failure.
+             */
+            Value result = colorLirOperand(op, (Variable) operand, mode);
+            assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstantValue(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls";
+            return result;
+        }
+
+        private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
+            info.forEachState(op, this::debugInfoProcedure);
+        }
+
+        private void assignLocations(List<LIRInstruction> instructions) {
+            int numInst = instructions.size();
+            boolean hasDead = false;
+
+            for (int j = 0; j < numInst; j++) {
+                final LIRInstruction op = instructions.get(j);
+                if (op == null) {
+                    /*
+                     * this can happen when spill-moves are removed in eliminateSpillMoves
+                     */
+                    hasDead = true;
+                } else if (assignLocations(op, instructions, j)) {
+                    hasDead = true;
+                }
+            }
+
+            if (hasDead) {
+                // Remove null values from the list.
+                instructions.removeAll(Collections.singleton(null));
+            }
+        }
+
+        private final InstructionValueProcedure assignProc = new InstructionValueProcedure() {
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariable(value)) {
+                    return colorLirOperand(instruction, (Variable) value, mode);
+                }
+                return value;
+            }
+        };
+
+        /**
+         * Assigns the operand of an {@link LIRInstruction}.
+         *
+         * @param op The {@link LIRInstruction} that should be colored.
+         * @param j The index of {@code op} in the {@code instructions} list.
+         * @param instructions The instructions of the current block.
+         * @return {@code true} if the instruction was deleted.
+         */
+        private boolean assignLocations(LIRInstruction op, List<LIRInstruction> instructions, int j) {
+            assert op != null && instructions.get(j) == op;
+            if (TraceRAshareSpillInformation.getValue()) {
+                if (op instanceof BlockEndOp) {
+                    ((BlockEndOp) op).forEachOutgoingValue(colorOutgoingIncomingValues);
+                } else if (op instanceof LabelOp) {
+                    ((LabelOp) op).forEachIncomingValue(colorOutgoingIncomingValues);
+                }
+            }
+
+            // remove useless moves
+            if (op instanceof MoveOp) {
+                AllocatableValue result = ((MoveOp) op).getResult();
+                if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
+                    /*
+                     * This happens if a materializable interval is originally not spilled but then
+                     * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
+                     * interval this move operation was already generated.
+                     */
+                    instructions.set(j, null);
+                    return true;
+                }
+            }
+
+            op.forEachInput(assignProc);
+            op.forEachAlive(assignProc);
+            op.forEachTemp(assignProc);
+            op.forEachOutput(assignProc);
+
+            // compute reference map and debug information
+            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+
+            // remove useless moves
+            if (op instanceof ValueMoveOp) {
+                ValueMoveOp move = (ValueMoveOp) op;
+                if (move.getInput().equals(move.getResult())) {
+                    instructions.set(j, null);
+                    return true;
+                }
+                if (isStackSlotValue(move.getInput()) && isStackSlotValue(move.getResult())) {
+                    // rewrite stack to stack moves
+                    instructions.set(j, spillMoveFactory.createStackMove(move.getResult(), move.getInput()));
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @SuppressWarnings("try")
+        private void assignLocations() {
+            try (Indent indent = Debug.logAndIndent("assign locations")) {
+                for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                    try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
+                        assignLocations(allocator.getLIR().getLIRforBlock(block));
+                    }
+                }
+            }
+        }
+
+        private final InstructionValueProcedure colorOutgoingIncomingValues = new InstructionValueProcedure() {
+
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariable(value)) {
+                    TraceInterval interval = allocator.intervalFor(value);
+                    assert interval != null : "interval must exist";
+                    interval = allocator.splitChildAtOpId(interval, instruction.id(), mode);
+
+                    if (interval.inMemoryAt(instruction.id()) && isRegister(interval.location())) {
+                        return new ShadowedRegisterValue((RegisterValue) interval.location(), interval.spillSlot());
+                    }
+                }
+                return value;
+            }
+        };
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java
new file mode 100644
index 0000000..3d5841b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.IntervalPredicate;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAllocationPhase {
+
+    private static final IntervalPredicate spilledIntervals = new TraceLinearScanPhase.IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return i.isSplitParent() && SpillState.IN_MEMORY.contains(i.spillState());
+        }
+    };
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
+        TraceBuilderResult traceBuilderResult = context.resultTraces;
+        TraceLinearScan allocator = context.allocator;
+        boolean shouldEliminateSpillMoves = shouldEliminateSpillMoves(traceBuilderResult, allocator);
+        eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult);
+    }
+
+    private static boolean shouldEliminateSpillMoves(TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
+        return !traceBuilderResult.incomingSideEdges(traceBuilderResult.getTraceForBlock(allocator.blockAt(0)));
+    }
+
+    // called once before assignment of register numbers
+    @SuppressWarnings("try")
+    private static void eliminateSpillMoves(TraceLinearScan allocator, boolean shouldEliminateSpillMoves, TraceBuilderResult traceBuilderResult) {
+        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves: Trace%d", traceBuilderResult.getTraceForBlock(allocator.blockAt(0)).getId())) {
+            allocator.sortIntervalsBySpillPos();
+
+            /*
+             * collect all intervals that must be stored after their definition. The list is sorted
+             * by Interval.spillDefinitionPos.
+             */
+            TraceInterval interval = allocator.createUnhandledListBySpillPos(spilledIntervals);
+            if (DetailedAsserts.getValue()) {
+                checkIntervals(interval);
+            }
+            if (Debug.isLogEnabled()) {
+                try (Indent indent2 = Debug.logAndIndent("Sorted intervals")) {
+                    for (TraceInterval i = interval; i != null; i = i.next) {
+                        Debug.log("%5d: %s", i.spillDefinitionPos(), i);
+                    }
+                }
+            }
+
+            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                    int numInst = instructions.size();
+
+                    int lastOpId = -1;
+                    // iterate all instructions of the block.
+                    for (int j = 0; j < numInst; j++) {
+                        LIRInstruction op = instructions.get(j);
+                        int opId = op.id();
+                        try (Indent indent2 = Debug.logAndIndent("%5d %s", opId, op)) {
+
+                            if (opId == -1) {
+                                MoveOp move = (MoveOp) op;
+                                /*
+                                 * Remove move from register to stack if the stack slot is
+                                 * guaranteed to be correct. Only moves that have been inserted by
+                                 * LinearScan can be removed.
+                                 */
+                                if (shouldEliminateSpillMoves && canEliminateSpillMove(allocator, block, move, lastOpId)) {
+                                    /*
+                                     * Move target is a stack slot that is always correct, so
+                                     * eliminate instruction.
+                                     */
+                                    if (Debug.isLogEnabled()) {
+                                        if (move instanceof ValueMoveOp) {
+                                            ValueMoveOp vmove = (ValueMoveOp) move;
+                                            Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
+                                                            allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
+                                        } else {
+                                            LoadConstantOp load = (LoadConstantOp) move;
+                                            Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(),
+                                                            block);
+                                        }
+                                    }
+
+                                    // null-instructions are deleted by assignRegNum
+                                    instructions.set(j, null);
+                                }
+
+                            } else {
+                                lastOpId = opId;
+                                /*
+                                 * Insert move from register to stack just after the beginning of
+                                 * the interval.
+                                 */
+                                // assert interval == TraceInterval.EndMarker ||
+                                // interval.spillDefinitionPos() >= opId : "invalid order";
+                                assert interval == TraceInterval.EndMarker || (interval.isSplitParent() && SpillState.IN_MEMORY.contains(interval.spillState())) : "invalid interval";
+
+                                while (interval != TraceInterval.EndMarker && interval.spillDefinitionPos() == opId) {
+                                    Debug.log("handle %s", interval);
+                                    if (!interval.canMaterialize() && interval.spillState() != SpillState.StartInMemory) {
+
+                                        AllocatableValue fromLocation = interval.getSplitChildAtOpId(opId, OperandMode.DEF).location();
+                                        AllocatableValue toLocation = allocator.canonicalSpillOpr(interval);
+                                        if (!fromLocation.equals(toLocation)) {
+
+                                            if (!insertionBuffer.initialized()) {
+                                                /*
+                                                 * prepare insertion buffer (appended when all
+                                                 * instructions in the block are processed)
+                                                 */
+                                                insertionBuffer.init(instructions);
+                                            }
+
+                                            assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
+                                                            interval.spillState();
+                                            assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
+
+                                            LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                            insertionBuffer.append(j + 1, move);
+
+                                            if (Debug.isLogEnabled()) {
+                                                Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                            }
+                                        }
+                                    }
+                                    interval = interval.next;
+                                }
+                            }
+                        }
+                    }   // end of instruction iteration
+
+                    if (insertionBuffer.initialized()) {
+                        insertionBuffer.finish();
+                    }
+                }
+            }   // end of block iteration
+
+            assert interval == TraceInterval.EndMarker : "missed an interval";
+        }
+    }
+
+    /**
+     * @param allocator
+     * @param block The block {@code move} is located in.
+     * @param move Spill move.
+     * @param lastOpId The id of last "normal" instruction before the spill move. (Spill moves have
+     *            no valid opId but -1.)
+     */
+    private static boolean canEliminateSpillMove(TraceLinearScan allocator, AbstractBlockBase<?> block, MoveOp move, int lastOpId) {
+        assert ((LIRInstruction) move).id() == -1 : "Not a spill move: " + move;
+        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
+        assert lastOpId >= 0 : "Invalid lastOpId: " + lastOpId;
+
+        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+
+        if (!isRegister(curInterval.location()) && curInterval.inMemoryAt(lastOpId) && !isPhiResolutionMove(allocator, move)) {
+            /* Phi resolution moves cannot be removed because they define the value. */
+            // TODO (je) check if the comment is still valid!
+            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks if a (spill or split) move is a Phi resolution move.
+     *
+     * A spill or split move connects a split parent or a split child with another split child.
+     * Therefore the destination of the move is always a split child. Phi resolution moves look like
+     * spill moves (i.e. {@link LIRInstruction#id() id} is {@code 0}, but they define a new
+     * variable. As a result the destination interval is a split parent.
+     */
+    private static boolean isPhiResolutionMove(TraceLinearScan allocator, MoveOp move) {
+        assert ((LIRInstruction) move).id() == -1 : "Not a spill move: " + move;
+        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+        return curInterval.isSplitParent();
+    }
+
+    private static void checkIntervals(TraceInterval interval) {
+        TraceInterval prev = null;
+        TraceInterval temp = interval;
+        while (temp != TraceInterval.EndMarker) {
+            assert temp.spillDefinitionPos() >= 0 : "invalid spill definition pos";
+            if (prev != null) {
+                // assert temp.from() >= prev.from() : "intervals not sorted";
+                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
+            }
+
+            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
+            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
+            // assert temp.spillDefinitionPos() <= temp.from() + 2 :
+            // "only intervals defined once at their start-pos can be optimized";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            }
+
+            prev = temp;
+            temp = temp.next;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java
new file mode 100644
index 0000000..086cf75
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
+import static org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
+import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
+import static org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.isVariableOrRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
+        TraceBuilderResult traceBuilderResult = context.resultTraces;
+        TraceLinearScan allocator = context.allocator;
+        new Analyser(allocator, traceBuilderResult).analyze();
+    }
+
+    public static final class Analyser {
+        private static final int DUMP_DURING_ANALYSIS_LEVEL = 4;
+        private final TraceLinearScan allocator;
+        private final TraceBuilderResult traceBuilderResult;
+        private int numInstructions;
+
+        public Analyser(TraceLinearScan allocator, TraceBuilderResult traceBuilderResult) {
+            this.allocator = allocator;
+            this.traceBuilderResult = traceBuilderResult;
+        }
+
+        private AbstractBlockBase<?>[] sortedBlocks() {
+            return allocator.sortedBlocks();
+        }
+
+        private LIR getLIR() {
+            return allocator.getLIR();
+        }
+
+        private RegisterArray getCallerSavedRegisters() {
+            return allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
+        }
+
+        public void analyze() {
+            countInstructions();
+            buildIntervals();
+        }
+
+        private boolean sameTrace(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+            return traceBuilderResult.getTraceForBlock(b) == traceBuilderResult.getTraceForBlock(a);
+        }
+
+        private boolean isAllocatedOrCurrent(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
+            return traceBuilderResult.getTraceForBlock(other).getId() <= traceBuilderResult.getTraceForBlock(currentBlock).getId();
+        }
+
+        /**
+         * Count instructions in all blocks. The numbering follows the
+         * {@linkplain TraceLinearScan#sortedBlocks() register allocation order}.
+         */
+        private void countInstructions() {
+
+            allocator.initIntervals();
+
+            int numberInstructions = 0;
+            for (AbstractBlockBase<?> block : sortedBlocks()) {
+                numberInstructions += getLIR().getLIRforBlock(block).size();
+            }
+            numInstructions = numberInstructions;
+
+            // initialize with correct length
+            allocator.initOpIdMaps(numberInstructions);
+        }
+
+        private final InstructionValueConsumer outputConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariableOrRegister(operand)) {
+                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op));
+                    addRegisterHint(op, operand, mode, flags, true);
+                }
+            }
+        };
+
+        private final InstructionValueConsumer tempConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariableOrRegister(operand)) {
+                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister);
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            }
+        };
+        private final InstructionValueConsumer aliveConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariableOrRegister(operand)) {
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int opId = op.id();
+                    int blockFrom = 0;
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p);
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            }
+        };
+
+        private final InstructionValueConsumer inputConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int blockFrom = 0;
+                    addUse((AllocatableValue) operand, blockFrom, opId, p);
+                    addRegisterHint(op, operand, mode, flags, false);
+                }
+            }
+
+        };
+
+        private final InstructionValueConsumer stateProc = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = 0;
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None);
+                }
+            }
+        };
+
+        private void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedUse(asRegisterValue(operand), from, to);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableUse(asVariable(operand), from, to, registerPriority);
+            }
+        }
+
+        private void addFixedUse(RegisterValue reg, int from, int to) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            interval.addRange(from, to);
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed use: %s, at %d", interval, to);
+            }
+        }
+
+        private void addVariableUse(Variable operand, int from, int to, RegisterPriority registerPriority) {
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+            interval.addRange(from, to);
+
+            // Register use position at even instruction id.
+            interval.addUsePos(to & ~1, registerPriority);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
+            }
+        }
+
+        private void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedDef(asRegisterValue(operand), op);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableDef(asVariable(operand), op, registerPriority);
+            }
+        }
+
+        private void addFixedDef(RegisterValue reg, LIRInstruction op) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            int defPos = op.id();
+            if (interval.from() <= defPos) {
+                /*
+                 * Update the starting point (when a range is first created for a use, its start is
+                 * the beginning of the current block until a def is encountered).
+                 */
+                interval.setFrom(defPos);
+
+            } else {
+                /*
+                 * Dead value - make vacuous interval also add register priority for dead intervals
+                 */
+                interval.addRange(defPos, defPos + 1);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Warning: def of operand %s at %d occurs without use", reg, defPos);
+                }
+            }
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed def: %s, at %d", interval, defPos);
+            }
+        }
+
+        private void addVariableDef(Variable operand, LIRInstruction op, RegisterPriority registerPriority) {
+            int defPos = op.id();
+
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+
+            if (interval.isEmpty()) {
+                /*
+                 * Dead value - make vacuous interval also add register priority for dead intervals
+                 */
+                interval.addRange(defPos, defPos + 1);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+                }
+            } else {
+                /*
+                 * Update the starting point (when a range is first created for a use, its start is
+                 * the beginning of the current block until a def is encountered).
+                 */
+                interval.setFrom(defPos);
+            }
+            if (!(op instanceof LabelOp)) {
+                // no use positions for labels
+                interval.addUsePos(defPos, registerPriority);
+            }
+
+            changeSpillDefinitionPos(op, operand, interval, defPos);
+            if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
+                // detection of method-parameters and roundfp-results
+                interval.setSpillState(SpillState.StartInMemory);
+            }
+            interval.addMaterializationValue(getMaterializedValue(op, operand, interval, allocator.neverSpillConstants(), allocator.getSpillMoveFactory()));
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+            }
+        }
+
+        private void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedTemp(asRegisterValue(operand), tempPos);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableTemp(asVariable(operand), tempPos, registerPriority);
+            }
+        }
+
+        private void addFixedTemp(RegisterValue reg, int tempPos) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            interval.addRange(tempPos, tempPos + 1);
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed temp: %s, at %d", interval, tempPos);
+            }
+        }
+
+        private void addVariableTemp(Variable operand, int tempPos, RegisterPriority registerPriority) {
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+
+            if (interval.isEmpty()) {
+                interval.addRange(tempPos, tempPos + 1);
+            } else if (interval.from() > tempPos) {
+                interval.setFrom(tempPos);
+            }
+
+            interval.addUsePos(tempPos, registerPriority);
+            interval.addMaterializationValue(null);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+            }
+        }
+
+        /**
+         * Eliminates moves from register to stack if the stack slot is known to be correct.
+         *
+         * @param op
+         * @param operand
+         */
+        private void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, TraceInterval interval, int defPos) {
+            assert interval.isSplitParent() : "can only be called for split parents";
+
+            switch (interval.spillState()) {
+                case NoDefinitionFound:
+                    // assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                    interval.setSpillDefinitionPos(defPos);
+                    if (!(op instanceof LabelOp)) {
+                        // Do not update state for labels. This will be done afterwards.
+                        interval.setSpillState(SpillState.NoSpillStore);
+                    }
+                    break;
+
+                case NoSpillStore:
+                    assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                    if (defPos < interval.spillDefinitionPos() - 2) {
+                        /*
+                         * Second definition found, so no spill optimization possible for this
+                         * interval.
+                         */
+                        interval.setSpillState(SpillState.NoOptimization);
+                    } else {
+                        // two consecutive definitions (because of two-operand LIR form)
+                        assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                    }
+                    break;
+
+                case NoOptimization:
+                    // nothing to do
+                    break;
+
+                default:
+                    throw GraalError.shouldNotReachHere("other states not allowed at this time");
+            }
+        }
+
+        private void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+            if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) {
+
+                ValueProcedure registerHintProc = new ValueProcedure() {
+                    @Override
+                    public Value doValue(Value registerHint, OperandMode valueMode, EnumSet<OperandFlag> valueFlags) {
+                        if (isVariableOrRegister(registerHint)) {
+                            /*
+                             * TODO (je): clean up
+                             */
+                            final AllocatableValue fromValue;
+                            final AllocatableValue toValue;
+                            /* hints always point from def to use */
+                            if (hintAtDef) {
+                                fromValue = (AllocatableValue) registerHint;
+                                toValue = (AllocatableValue) targetValue;
+                            } else {
+                                fromValue = (AllocatableValue) targetValue;
+                                toValue = (AllocatableValue) registerHint;
+                            }
+                            Debug.log("addRegisterHint %s to %s", fromValue, toValue);
+                            final TraceInterval to;
+                            final IntervalHint from;
+                            if (isRegister(toValue)) {
+                                if (isRegister(fromValue)) {
+                                    // fixed to fixed move
+                                    return null;
+                                }
+                                from = getIntervalHint(toValue);
+                                to = allocator.getOrCreateInterval(fromValue);
+                            } else {
+                                to = allocator.getOrCreateInterval(toValue);
+                                from = getIntervalHint(fromValue);
+                            }
+
+                            to.setLocationHint(from);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
+                            }
+
+                            return registerHint;
+                        }
+                        return null;
+                    }
+                };
+                op.forEachRegisterHint(targetValue, mode, registerHintProc);
+            }
+        }
+
+        private static boolean optimizeMethodArgument(Value value) {
+            /*
+             * Object method arguments that are passed on the stack are currently not optimized
+             * because this requires that the runtime visits method arguments during stack walking.
+             */
+            return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && LIRKind.isValue(value);
+        }
+
+        /**
+         * Determines the register priority for an instruction's output/result operand.
+         */
+        private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+            if (op instanceof LabelOp) {
+                // skip method header
+                return RegisterPriority.None;
+            }
+            if (op instanceof ValueMoveOp) {
+                ValueMoveOp move = (ValueMoveOp) op;
+                if (optimizeMethodArgument(move.getInput())) {
+                    return RegisterPriority.None;
+                }
+            }
+
+            // all other operands require a register
+            return RegisterPriority.MustHaveRegister;
+        }
+
+        /**
+         * Determines the priority which with an instruction's input operand will be allocated a
+         * register.
+         */
+        private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+            if (flags.contains(OperandFlag.OUTGOING)) {
+                return RegisterPriority.None;
+            }
+            if (flags.contains(OperandFlag.STACK)) {
+                return RegisterPriority.ShouldHaveRegister;
+            }
+            // all other operands require a register
+            return RegisterPriority.MustHaveRegister;
+        }
+
+        @SuppressWarnings("try")
+        private void buildIntervals() {
+
+            try (Indent indent = Debug.logAndIndent("build intervals")) {
+
+                // create a list with all caller-save registers (cpu, fpu, xmm)
+                RegisterArray callerSaveRegs = getCallerSavedRegisters();
+                int instructionIndex = numInstructions;
+
+                // iterate all blocks in reverse order
+                AbstractBlockBase<?>[] blocks = sortedBlocks();
+                for (int i = blocks.length - 1; i >= 0; i--) {
+                    final AbstractBlockBase<?> block = blocks[i];
+
+                    try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
+
+                        /*
+                         * Iterate all instructions of the block in reverse order. definitions of
+                         * intervals are processed before uses.
+                         */
+                        List<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+                        ListIterator<LIRInstruction> instIt = instructions.listIterator(instructions.size());
+                        while (instIt.hasPrevious()) {
+                            final LIRInstruction op = instIt.previous();
+                            // number instruction
+                            instructionIndex--;
+                            final int opId = instructionIndex << 1;
+                            numberInstruction(block, op, instructionIndex);
+
+                            try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
+
+                                /*
+                                 * Add a temp range for each register if operation destroys
+                                 * caller-save registers.
+                                 */
+                                if (op.destroysCallerSavedRegisters()) {
+                                    for (Register r : callerSaveRegs) {
+                                        if (allocator.attributes(r).isAllocatable()) {
+                                            addTemp(r.asValue(), opId, RegisterPriority.None);
+                                        }
+                                    }
+                                    if (Debug.isLogEnabled()) {
+                                        Debug.log("operation destroys all caller-save registers");
+                                    }
+                                }
+
+                                op.visitEachOutput(outputConsumer);
+                                op.visitEachTemp(tempConsumer);
+                                op.visitEachAlive(aliveConsumer);
+                                op.visitEachInput(inputConsumer);
+
+                                /*
+                                 * Add uses of live locals from interpreter's point of view for
+                                 * proper debug information generation. Treat these operands as temp
+                                 * values (if the live range is extended to a call site, the value
+                                 * would be in a register at the call otherwise).
+                                 */
+                                op.visitEachState(stateProc);
+                            }
+
+                        }   // end of instruction iteration
+                    }
+                    if (Debug.isDumpEnabled(DUMP_DURING_ANALYSIS_LEVEL)) {
+                        allocator.printIntervals("After Block " + block);
+                    }
+                }   // end of block iteration
+                assert instructionIndex == 0 : "not at start?" + instructionIndex;
+
+                // fix spill state for phi/sigma intervals
+                for (TraceInterval interval : allocator.intervals()) {
+                    if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+                        // there was a definition in a phi/sigma
+                        interval.setSpillState(SpillState.NoSpillStore);
+                    }
+                }
+                if (TraceRAuseInterTraceHints.getValue()) {
+                    addInterTraceHints();
+                }
+                for (FixedInterval interval1 : allocator.fixedIntervals()) {
+                    if (interval1 != null) {
+                        /* We use [-1, 0] to avoid intersection with incoming values. */
+                        interval1.addRange(-1, 0);
+                    }
+                }
+            }
+        }
+
+        private void numberInstruction(AbstractBlockBase<?> block, LIRInstruction op, int index) {
+            int opId = index << 1;
+            assert op.id() == -1 || op.id() == opId : "must match";
+            op.setId(opId);
+            allocator.putOpIdMaps(index, op, block);
+            assert allocator.instructionForId(opId) == op : "must match";
+        }
+
+        @SuppressWarnings("try")
+        private void addInterTraceHints() {
+            try (Scope s = Debug.scope("InterTraceHints", allocator)) {
+                // set hints for phi/sigma intervals
+                for (AbstractBlockBase<?> block : sortedBlocks()) {
+                    LabelOp label = SSIUtil.incoming(getLIR(), block);
+                    for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                        if (isAllocatedOrCurrent(block, pred)) {
+                            BlockEndOp outgoing = SSIUtil.outgoing(getLIR(), pred);
+                            // do not look at phi variables as they are not same value!
+                            for (int i = outgoing.getPhiSize(); i < outgoing.getOutgoingSize(); i++) {
+                                Value toValue = label.getIncomingValue(i);
+                                assert !isShadowedRegisterValue(toValue) : "Shadowed Registers are not allowed here: " + toValue;
+                                if (isVariable(toValue)) {
+                                    Value fromValue = outgoing.getOutgoingValue(i);
+                                    assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue;
+                                    if (!LIRValueUtil.isConstantValue(fromValue)) {
+                                        addInterTraceHint(label, (AllocatableValue) toValue, fromValue);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        private void addInterTraceHint(LabelOp label, AllocatableValue toValue, Value fromValue) {
+            assert isVariable(toValue) : "Wrong toValue: " + toValue;
+            assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
+            TraceInterval to = allocator.getOrCreateInterval(toValue);
+            if (isVariableOrRegister(fromValue)) {
+                IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
+                setHint(label, to, from);
+            } else if (isStackSlotValue(fromValue)) {
+                setSpillSlot(label, to, (AllocatableValue) fromValue);
+            } else if (TraceRAshareSpillInformation.getValue() && isShadowedRegisterValue(fromValue)) {
+                ShadowedRegisterValue shadowedRegisterValue = asShadowedRegisterValue(fromValue);
+                IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
+                setHint(label, to, from);
+                setSpillSlot(label, to, shadowedRegisterValue.getStackSlot());
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        }
+
+        private static void setHint(final LIRInstruction op, TraceInterval to, IntervalHint from) {
+            IntervalHint currentHint = to.locationHint(false);
+            if (currentHint == null) {
+                /*
+                 * Update hint if there was none or if the hint interval starts after the hinted
+                 * interval.
+                 */
+                to.setLocationHint(from);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
+                }
+            }
+        }
+
+        private static void setSpillSlot(LIRInstruction op, TraceInterval interval, AllocatableValue spillSlot) {
+            if (interval.spillSlot() == null) {
+                interval.setSpillSlot(spillSlot);
+                interval.setSpillState(SpillState.StartInMemory);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("operation at opId %d: added spill slot %s to interval %s", op.id(), spillSlot, interval);
+                }
+            } else if (Debug.isLogEnabled()) {
+                Debug.log("operation at opId %d: has already a slot assigned %s", op.id(), interval.spillSlot());
+            }
+        }
+
+        private IntervalHint getIntervalHint(AllocatableValue from) {
+            if (isRegister(from)) {
+                return allocator.getOrCreateFixedInterval(asRegisterValue(from));
+            }
+            return allocator.getOrCreateInterval(from);
+        }
+
+    }
+
+    /**
+     * Returns a value for a interval definition, which can be used for re-materialization.
+     *
+     * @param op An instruction which defines a value
+     * @param operand The destination operand of the instruction
+     * @param interval The interval for this defined value.
+     * @return Returns the value which is moved to the instruction and which can be reused at all
+     *         reload-locations in case the interval of this instruction is spilled. Currently this
+     *         can only be a {@link JavaConstant}.
+     */
+    private static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, TraceInterval interval, boolean neverSpillConstants, MoveFactory spillMoveFactory) {
+        if (op instanceof LoadConstantOp) {
+            LoadConstantOp move = (LoadConstantOp) op;
+            if (move.getConstant() instanceof JavaConstant) {
+                if (!neverSpillConstants) {
+                    if (!spillMoveFactory.allowConstantToStackMove(move.getConstant())) {
+                        return null;
+                    }
+                    /*
+                     * Check if the interval has any uses which would accept an stack location
+                     * (priority == ShouldHaveRegister). Rematerialization of such intervals can
+                     * result in a degradation, because rematerialization always inserts a constant
+                     * load, even if the value is not needed in a register.
+                     */
+                    int numUsePos = interval.numUsePos();
+                    for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
+                        TraceInterval.RegisterPriority priority = interval.getUsePosRegisterPriority(useIdx);
+                        if (priority == TraceInterval.RegisterPriority.ShouldHaveRegister) {
+                            return null;
+                        }
+                    }
+                }
+                return (JavaConstant) move.getConstant();
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java
new file mode 100644
index 0000000..281bd43
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java
@@ -0,0 +1,1209 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.CodeUtil.isEven;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext;
+import org.graalvm.compiler.lir.debug.IntervalDumper;
+import org.graalvm.compiler.lir.debug.IntervalDumper.IntervalVisitor;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Implementation of the Linear Scan allocation approach for traces described in
+ * <a href="http://dx.doi.org/10.1145/2972206.2972211">"Trace-based Register Allocation in a JIT
+ * Compiler"</a> by Josef Eisl et al. It is derived from
+ * <a href="http://doi.acm.org/10.1145/1064979.1064998" > "Optimized Interval Splitting in a Linear
+ * Scan Register Allocator"</a> by Christian Wimmer and Hanspeter Moessenboeck.
+ */
+public final class TraceLinearScanPhase extends TraceAllocationPhase<TraceAllocationContext> {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable spill position optimization", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptTraceRAEliminateSpillMoves = new NestedBooleanOptionValue(LIRPhase.Options.LIROptimization, true);
+        // @formatter:on
+    }
+
+    private static final TraceLinearScanRegisterAllocationPhase TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE = new TraceLinearScanRegisterAllocationPhase();
+    private static final TraceLinearScanAssignLocationsPhase TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE = new TraceLinearScanAssignLocationsPhase();
+    private static final TraceLinearScanEliminateSpillMovePhase TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE = new TraceLinearScanEliminateSpillMovePhase();
+    private static final TraceLinearScanResolveDataFlowPhase TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE = new TraceLinearScanResolveDataFlowPhase();
+    private static final TraceLinearScanLifetimeAnalysisPhase TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE = new TraceLinearScanLifetimeAnalysisPhase();
+
+    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
+
+    private final FrameMapBuilder frameMapBuilder;
+    private final RegisterAttributes[] registerAttributes;
+    private final RegisterArray registers;
+    private final RegisterAllocationConfig regAllocConfig;
+    private final MoveFactory moveFactory;
+
+    protected final TraceBuilderResult traceBuilderResult;
+
+    private final boolean neverSpillConstants;
+
+    /**
+     * Maps from {@link Variable#index} to a spill stack slot. If
+     * {@linkplain org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options#TraceRACacheStackSlots
+     * enabled} a {@link Variable} is always assigned to the same stack slot.
+     */
+    private final AllocatableValue[] cachedStackSlots;
+
+    private final LIRGenerationResult res;
+
+    public TraceLinearScanPhase(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, TraceBuilderResult traceBuilderResult,
+                    boolean neverSpillConstants, AllocatableValue[] cachedStackSlots) {
+        this.res = res;
+        this.moveFactory = spillMoveFactory;
+        this.frameMapBuilder = res.getFrameMapBuilder();
+        this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
+        this.regAllocConfig = regAllocConfig;
+
+        this.registers = target.arch.getRegisters();
+        this.traceBuilderResult = traceBuilderResult;
+        this.neverSpillConstants = neverSpillConstants;
+        this.cachedStackSlots = cachedStackSlots;
+
+    }
+
+    public static boolean isVariableOrRegister(Value value) {
+        return isVariable(value) || isRegister(value);
+    }
+
+    abstract static class IntervalPredicate {
+
+        abstract boolean apply(TraceInterval i);
+    }
+
+    static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return isRegister(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return isVariable(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return !isRegister(i.operand);
+        }
+    };
+
+    public TraceLinearScan createAllocator(Trace trace) {
+        return new TraceLinearScan(trace);
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext traceContext) {
+        createAllocator(trace).allocate(target, lirGenRes, traceContext);
+    }
+
+    private static <T extends IntervalHint> boolean isSortedByFrom(T[] intervals) {
+        int from = -1;
+        for (T interval : intervals) {
+            assert interval != null;
+            assert from <= interval.from();
+            from = interval.from();
+        }
+        return true;
+    }
+
+    private static boolean isSortedBySpillPos(TraceInterval[] intervals) {
+        int from = -1;
+        for (TraceInterval interval : intervals) {
+            assert interval != null;
+            assert from <= interval.spillDefinitionPos();
+            from = interval.spillDefinitionPos();
+        }
+        return true;
+    }
+
+    private static <T extends IntervalHint> T[] sortIntervalsBeforeAllocation(T[] intervals, T[] sortedList) {
+        int sortedIdx = 0;
+        int sortedFromMax = -1;
+
+        // special sorting algorithm: the original interval-list is almost sorted,
+        // only some intervals are swapped. So this is much faster than a complete QuickSort
+        for (T interval : intervals) {
+            if (interval != null) {
+                int from = interval.from();
+
+                if (sortedFromMax <= from) {
+                    sortedList[sortedIdx++] = interval;
+                    sortedFromMax = interval.from();
+                } else {
+                    // the assumption that the intervals are already sorted failed,
+                    // so this interval must be sorted in manually
+                    int j;
+                    for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) {
+                        sortedList[j + 1] = sortedList[j];
+                    }
+                    sortedList[j + 1] = interval;
+                    sortedIdx++;
+                }
+            }
+        }
+        return sortedList;
+    }
+
+    public final class TraceLinearScan implements IntervalDumper {
+
+        /**
+         * Intervals sorted by {@link TraceInterval#from()}.
+         */
+        private TraceInterval[] sortedIntervals;
+
+        /**
+         * Fixed intervals sorted by {@link FixedInterval#from()}.
+         */
+        private FixedInterval[] sortedFixedIntervals;
+
+        private final Trace trace;
+
+        public TraceLinearScan(Trace trace) {
+            this.trace = trace;
+            this.fixedIntervals = new FixedInterval[registers.size()];
+        }
+
+        /**
+         * Converts an operand (variable or register) to an index in a flat address space covering
+         * all the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being
+         * processed by this allocator.
+         */
+        int operandNumber(Value operand) {
+            assert !isRegister(operand) : "Register do not have operand numbers: " + operand;
+            assert isVariable(operand) : "Unsupported Value " + operand;
+            return ((Variable) operand).index;
+        }
+
+        /**
+         * Gets the number of operands. This value will increase by 1 for new variable.
+         */
+        int operandSize() {
+            return getLIR().numVariables();
+        }
+
+        /**
+         * Gets the number of registers. This value will never change.
+         */
+        int numRegisters() {
+            return registers.size();
+        }
+
+        public int getFirstLirInstructionId(AbstractBlockBase<?> block) {
+            int result = getLIR().getLIRforBlock(block).get(0).id();
+            assert result >= 0;
+            return result;
+        }
+
+        public int getLastLirInstructionId(AbstractBlockBase<?> block) {
+            List<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+            int result = instructions.get(instructions.size() - 1).id();
+            assert result >= 0;
+            return result;
+        }
+
+        /**
+         * Gets an object describing the attributes of a given register according to this register
+         * configuration.
+         */
+        public RegisterAttributes attributes(Register reg) {
+            return registerAttributes[reg.number];
+        }
+
+        public MoveFactory getSpillMoveFactory() {
+            return moveFactory;
+        }
+
+        protected TraceLocalMoveResolver createMoveResolver() {
+            TraceLocalMoveResolver moveResolver = new TraceLocalMoveResolver(this);
+            assert moveResolver.checkEmpty();
+            return moveResolver;
+        }
+
+        void assignSpillSlot(TraceInterval interval) {
+            /*
+             * Assign the canonical spill slot of the parent (if a part of the interval is already
+             * spilled) or allocate a new spill slot.
+             */
+            if (interval.canMaterialize()) {
+                interval.assignLocation(Value.ILLEGAL);
+            } else if (interval.spillSlot() != null) {
+                interval.assignLocation(interval.spillSlot());
+            } else {
+                AllocatableValue slot = allocateSpillSlot(interval);
+                interval.setSpillSlot(slot);
+                interval.assignLocation(slot);
+            }
+        }
+
+        /**
+         * Returns a new spill slot or a cached entry if there is already one for the
+         * {@linkplain TraceInterval#operand variable}.
+         */
+        private AllocatableValue allocateSpillSlot(TraceInterval interval) {
+            int variableIndex = LIRValueUtil.asVariable(interval.splitParent().operand).index;
+            if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue()) {
+                AllocatableValue cachedStackSlot = cachedStackSlots[variableIndex];
+                if (cachedStackSlot != null) {
+                    TraceRegisterAllocationPhase.globalStackSlots.increment();
+                    assert cachedStackSlot.getValueKind().equals(interval.kind()) : "CachedStackSlot: kind mismatch? " + interval.kind() + " vs. " + cachedStackSlot.getValueKind();
+                    return cachedStackSlot;
+                }
+            }
+            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(interval.kind());
+            if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue()) {
+                cachedStackSlots[variableIndex] = slot;
+            }
+            TraceRegisterAllocationPhase.allocatedStackSlots.increment();
+            return slot;
+        }
+
+        // access to block list (sorted in linear scan order)
+        public int blockCount() {
+            return sortedBlocks().length;
+        }
+
+        public AbstractBlockBase<?> blockAt(int index) {
+            return sortedBlocks()[index];
+        }
+
+        int numLoops() {
+            return getLIR().getControlFlowGraph().getLoops().size();
+        }
+
+        boolean isBlockBegin(int opId) {
+            return opId == 0 || blockForId(opId) != blockForId(opId - 1);
+        }
+
+        boolean isBlockEnd(int opId) {
+            boolean isBlockBegin = isBlockBegin(opId + 2);
+            assert isBlockBegin == (instructionForId(opId & (~1)) instanceof BlockEndOp);
+            return isBlockBegin;
+        }
+
+        boolean coversBlockBegin(int opId1, int opId2) {
+            return blockForId(opId1) != blockForId(opId2);
+        }
+
+        /**
+         * Determines if an {@link LIRInstruction} destroys all caller saved registers.
+         *
+         * @param opId an instruction {@linkplain LIRInstruction#id id}
+         * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved
+         *         registers.
+         */
+        boolean hasCall(int opId) {
+            assert isEven(opId) : "opId not even";
+            return instructionForId(opId).destroysCallerSavedRegisters();
+        }
+
+        public boolean isProcessed(Value operand) {
+            return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
+        }
+
+        // * Phase 5: actual register allocation
+
+        private TraceInterval addToList(TraceInterval first, TraceInterval prev, TraceInterval interval) {
+            TraceInterval newFirst = first;
+            if (prev != null) {
+                prev.next = interval;
+            } else {
+                newFirst = interval;
+            }
+            return newFirst;
+        }
+
+        TraceInterval createUnhandledListByFrom(IntervalPredicate isList1) {
+            assert isSortedByFrom(sortedIntervals) : "interval list is not sorted";
+            return createUnhandledList(isList1);
+        }
+
+        TraceInterval createUnhandledListBySpillPos(IntervalPredicate isList1) {
+            assert isSortedBySpillPos(sortedIntervals) : "interval list is not sorted";
+            return createUnhandledList(isList1);
+        }
+
+        private TraceInterval createUnhandledList(IntervalPredicate isList1) {
+
+            TraceInterval list1 = TraceInterval.EndMarker;
+
+            TraceInterval list1Prev = null;
+            TraceInterval v;
+
+            int n = sortedIntervals.length;
+            for (int i = 0; i < n; i++) {
+                v = sortedIntervals[i];
+                if (v == null) {
+                    continue;
+                }
+
+                if (isList1.apply(v)) {
+                    list1 = addToList(list1, list1Prev, v);
+                    list1Prev = v;
+                }
+            }
+
+            if (list1Prev != null) {
+                list1Prev.next = TraceInterval.EndMarker;
+            }
+
+            assert list1Prev == null || list1Prev.next == TraceInterval.EndMarker : "linear list ends not with sentinel";
+
+            return list1;
+        }
+
+        private FixedInterval addToList(FixedInterval first, FixedInterval prev, FixedInterval interval) {
+            FixedInterval newFirst = first;
+            if (prev != null) {
+                prev.next = interval;
+            } else {
+                newFirst = interval;
+            }
+            return newFirst;
+        }
+
+        FixedInterval createFixedUnhandledList() {
+            assert isSortedByFrom(sortedFixedIntervals) : "interval list is not sorted";
+
+            FixedInterval list1 = FixedInterval.EndMarker;
+
+            FixedInterval list1Prev = null;
+            FixedInterval v;
+
+            int n = sortedFixedIntervals.length;
+            for (int i = 0; i < n; i++) {
+                v = sortedFixedIntervals[i];
+                if (v == null) {
+                    continue;
+                }
+
+                v.rewindRange();
+                list1 = addToList(list1, list1Prev, v);
+                list1Prev = v;
+            }
+
+            if (list1Prev != null) {
+                list1Prev.next = FixedInterval.EndMarker;
+            }
+
+            assert list1Prev == null || list1Prev.next == FixedInterval.EndMarker : "linear list ends not with sentinel";
+
+            return list1;
+        }
+
+        // SORTING
+
+        protected void sortIntervalsBeforeAllocation() {
+            int sortedLen = 0;
+            for (TraceInterval interval : intervals()) {
+                if (interval != null) {
+                    sortedLen++;
+                }
+            }
+            sortedIntervals = TraceLinearScanPhase.sortIntervalsBeforeAllocation(intervals(), new TraceInterval[sortedLen]);
+        }
+
+        protected void sortFixedIntervalsBeforeAllocation() {
+            int sortedLen = 0;
+            for (FixedInterval interval : fixedIntervals()) {
+                if (interval != null) {
+                    sortedLen++;
+                }
+            }
+            sortedFixedIntervals = TraceLinearScanPhase.sortIntervalsBeforeAllocation(fixedIntervals(), new FixedInterval[sortedLen]);
+        }
+
+        void sortIntervalsAfterAllocation() {
+            if (hasDerivedIntervals()) {
+                // no intervals have been added during allocation, so sorted list is already up to
+                // date
+                return;
+            }
+
+            TraceInterval[] oldList = sortedIntervals;
+            TraceInterval[] newList = Arrays.copyOfRange(intervals(), firstDerivedIntervalIndex(), intervalsSize());
+            int oldLen = oldList.length;
+            int newLen = newList.length;
+
+            // conventional sort-algorithm for new intervals
+            Arrays.sort(newList, (TraceInterval a, TraceInterval b) -> a.from() - b.from());
+
+            // merge old and new list (both already sorted) into one combined list
+            TraceInterval[] combinedList = new TraceInterval[oldLen + newLen];
+            int oldIdx = 0;
+            int newIdx = 0;
+
+            while (oldIdx + newIdx < combinedList.length) {
+                if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) {
+                    combinedList[oldIdx + newIdx] = oldList[oldIdx];
+                    oldIdx++;
+                } else {
+                    combinedList[oldIdx + newIdx] = newList[newIdx];
+                    newIdx++;
+                }
+            }
+
+            sortedIntervals = combinedList;
+        }
+
+        void sortIntervalsBySpillPos() {
+            // TODO (JE): better algorithm?
+            // conventional sort-algorithm for new intervals
+            Arrays.sort(sortedIntervals, (TraceInterval a, TraceInterval b) -> a.spillDefinitionPos() - b.spillDefinitionPos());
+        }
+
+        // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
+        // instead of returning null
+        public TraceInterval splitChildAtOpId(TraceInterval interval, int opId, LIRInstruction.OperandMode mode) {
+            TraceInterval result = interval.getSplitChildAtOpId(opId, mode);
+
+            if (result != null) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
+                }
+                return result;
+            }
+            throw new GraalError("LinearScan: interval is null");
+        }
+
+        AllocatableValue canonicalSpillOpr(TraceInterval interval) {
+            assert interval.spillSlot() != null : "canonical spill slot not set";
+            return interval.spillSlot();
+        }
+
+        boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
+            TraceInterval interval = intervalFor(operand);
+            assert interval != null : "interval must exist";
+
+            if (opId != -1) {
+                /*
+                 * Operands are not changed when an interval is split during allocation, so search
+                 * the right interval here.
+                 */
+                interval = splitChildAtOpId(interval, opId, mode);
+            }
+
+            return isIllegal(interval.location()) && interval.canMaterialize();
+        }
+
+        boolean isCallerSave(Value operand) {
+            return attributes(asRegister(operand)).isCallerSave();
+        }
+
+        @SuppressWarnings("try")
+        protected void allocate(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext traceContext) {
+            /*
+             * This is the point to enable debug logging for the whole register allocation.
+             */
+            try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
+                TraceLinearScanAllocationContext context = new TraceLinearScanAllocationContext(traceContext.spillMoveFactory, traceContext.registerAllocationConfig, traceBuilderResult, this);
+
+                TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE.apply(target, lirGenRes, trace, context, false);
+
+                try (Scope s = Debug.scope("AfterLifetimeAnalysis", this)) {
+
+                    printLir("Before register allocation", true);
+                    printIntervals("Before register allocation");
+
+                    sortIntervalsBeforeAllocation();
+                    sortFixedIntervalsBeforeAllocation();
+
+                    TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, trace, context, false);
+                    printIntervals("After register allocation");
+
+                    // resolve intra-trace data-flow
+                    TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.apply(target, lirGenRes, trace, context, false);
+                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.getName());
+
+                    // eliminate spill moves
+                    if (Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
+                        TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.apply(target, lirGenRes, trace, context, false);
+                        Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.getName());
+                    }
+
+                    TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, trace, context, false);
+
+                    if (DetailedAsserts.getValue()) {
+                        verifyIntervals();
+                    }
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+        }
+
+        public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
+            if (Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
+                Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label);
+            }
+        }
+
+        boolean verify() {
+            // (check that all intervals have a correct register and that no registers are
+            // overwritten)
+            verifyIntervals();
+
+            verifyRegisters();
+
+            Debug.log("no errors found");
+
+            return true;
+        }
+
+        @SuppressWarnings("try")
+        private void verifyRegisters() {
+            // Enable this logging to get output for the verification process.
+            try (Indent indent = Debug.logAndIndent("verifying register allocation")) {
+                RegisterVerifier verifier = new RegisterVerifier(this);
+                verifier.verify(blockAt(0));
+            }
+        }
+
+        @SuppressWarnings("try")
+        protected void verifyIntervals() {
+            try (Indent indent = Debug.logAndIndent("verifying intervals")) {
+                int len = intervalsSize();
+
+                for (int i = 0; i < len; i++) {
+                    final TraceInterval i1 = intervals()[i];
+                    if (i1 == null) {
+                        continue;
+                    }
+
+                    i1.checkSplitChildren();
+
+                    if (i1.operandNumber != i) {
+                        Debug.log("Interval %d is on position %d in list", i1.operandNumber, i);
+                        Debug.log(i1.logString());
+                        throw new GraalError("");
+                    }
+
+                    if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
+                        Debug.log("Interval %d has no type assigned", i1.operandNumber);
+                        Debug.log(i1.logString());
+                        throw new GraalError("");
+                    }
+
+                    if (i1.location() == null) {
+                        Debug.log("Interval %d has no register assigned", i1.operandNumber);
+                        Debug.log(i1.logString());
+                        throw new GraalError("");
+                    }
+
+                    if (i1.isEmpty()) {
+                        Debug.log("Interval %d has no Range", i1.operandNumber);
+                        Debug.log(i1.logString());
+                        throw new GraalError("");
+                    }
+
+                    if (i1.from() >= i1.to()) {
+                        Debug.log("Interval %d has zero length range", i1.operandNumber);
+                        Debug.log(i1.logString());
+                        throw new GraalError("");
+                    }
+
+                    // special intervals that are created in MoveResolver
+                    // . ignore them because the range information has no meaning there
+                    if (i1.from() == 1 && i1.to() == 2) {
+                        continue;
+                    }
+                    // check any intervals
+                    for (int j = i + 1; j < len; j++) {
+                        final TraceInterval i2 = intervals()[j];
+                        if (i2 == null) {
+                            continue;
+                        }
+
+                        // special intervals that are created in MoveResolver
+                        // . ignore them because the range information has no meaning there
+                        if (i2.from() == 1 && i2.to() == 2) {
+                            continue;
+                        }
+                        Value l1 = i1.location();
+                        Value l2 = i2.location();
+                        boolean intersects = i1.intersects(i2);
+                        if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
+                            throw GraalError.shouldNotReachHere(String.format("Intervals %s and %s overlap and have the same register assigned\n%s\n%s", i1, i2, i1.logString(), i2.logString()));
+                        }
+                    }
+                    // check fixed intervals
+                    for (FixedInterval i2 : fixedIntervals()) {
+                        if (i2 == null) {
+                            continue;
+                        }
+
+                        Value l1 = i1.location();
+                        Value l2 = i2.location();
+                        boolean intersects = i2.intersects(i1);
+                        if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
+                            throw GraalError.shouldNotReachHere(String.format("Intervals %s and %s overlap and have the same register assigned\n%s\n%s", i1, i2, i1.logString(), i2.logString()));
+                        }
+                    }
+                }
+            }
+        }
+
+        class CheckConsumer implements ValueConsumer {
+
+            boolean ok;
+            FixedInterval curInterval;
+
+            @Override
+            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isRegister(operand)) {
+                    if (fixedIntervalFor(asRegisterValue(operand)) == curInterval) {
+                        ok = true;
+                    }
+                }
+            }
+        }
+
+        @SuppressWarnings("try")
+        void verifyNoOopsInFixedIntervals() {
+            try (Indent indent = Debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
+                CheckConsumer checkConsumer = new CheckConsumer();
+
+                TraceInterval otherIntervals;
+                FixedInterval fixedInts = createFixedUnhandledList();
+                // to ensure a walking until the last instruction id, add a dummy interval
+                // with a high operation id
+                otherIntervals = new TraceInterval(Value.ILLEGAL, -1);
+                otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
+                TraceIntervalWalker iw = new TraceIntervalWalker(this, fixedInts, otherIntervals);
+
+                for (AbstractBlockBase<?> block : sortedBlocks()) {
+                    List<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+
+                    for (int j = 0; j < instructions.size(); j++) {
+                        LIRInstruction op = instructions.get(j);
+
+                        if (op.hasState()) {
+                            iw.walkBefore(op.id());
+                            boolean checkLive = true;
+
+                            /*
+                             * Make sure none of the fixed registers is live across an oopmap since
+                             * we can't handle that correctly.
+                             */
+                            if (checkLive) {
+                                for (FixedInterval interval = iw.activeFixedList.getFixed(); interval != FixedInterval.EndMarker; interval = interval.next) {
+                                    if (interval.to() > op.id() + 1) {
+                                        /*
+                                         * This interval is live out of this op so make sure that
+                                         * this interval represents some value that's referenced by
+                                         * this op either as an input or output.
+                                         */
+                                        checkConsumer.curInterval = interval;
+                                        checkConsumer.ok = false;
+
+                                        op.visitEachInput(checkConsumer);
+                                        op.visitEachAlive(checkConsumer);
+                                        op.visitEachTemp(checkConsumer);
+                                        op.visitEachOutput(checkConsumer);
+
+                                        assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        public LIR getLIR() {
+            return res.getLIR();
+        }
+
+        public FrameMapBuilder getFrameMapBuilder() {
+            return frameMapBuilder;
+        }
+
+        public AbstractBlockBase<?>[] sortedBlocks() {
+            return trace.getBlocks();
+        }
+
+        public RegisterArray getRegisters() {
+            return registers;
+        }
+
+        public RegisterAllocationConfig getRegisterAllocationConfig() {
+            return regAllocConfig;
+        }
+
+        public boolean callKillsRegisters() {
+            return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
+        }
+
+        boolean neverSpillConstants() {
+            return neverSpillConstants;
+        }
+
+        // IntervalData
+
+        private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+
+        /**
+         * The index of the first entry in {@link #intervals} for a
+         * {@linkplain #createDerivedInterval(TraceInterval) derived interval}.
+         */
+        private int firstDerivedIntervalIndex = -1;
+
+        /**
+         * @see #fixedIntervals()
+         */
+        private final FixedInterval[] fixedIntervals;
+
+        /**
+         * @see #intervals()
+         */
+        private TraceInterval[] intervals;
+
+        /**
+         * The number of valid entries in {@link #intervals}.
+         */
+        private int intervalsSize;
+
+        /**
+         * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries
+         * should be retrieved with {@link #instructionForId(int)} as the id is not simply an index
+         * into this array.
+         */
+        private LIRInstruction[] opIdToInstructionMap;
+
+        /**
+         * Map from an instruction {@linkplain LIRInstruction#id id} to the
+         * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be
+         * retrieved with {@link #blockForId(int)} as the id is not simply an index into this array.
+         */
+        private AbstractBlockBase<?>[] opIdToBlockMap;
+
+        /**
+         * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+         */
+        TraceInterval[] intervals() {
+            return intervals;
+        }
+
+        /**
+         * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+         */
+        FixedInterval[] fixedIntervals() {
+            return fixedIntervals;
+        }
+
+        void initIntervals() {
+            intervalsSize = operandSize();
+            intervals = new TraceInterval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
+        }
+
+        /**
+         * Creates a new fixed interval.
+         *
+         * @param reg the operand for the interval
+         * @return the created interval
+         */
+        private FixedInterval createFixedInterval(RegisterValue reg) {
+            FixedInterval interval = new FixedInterval(reg);
+            int operandNumber = reg.getRegister().number;
+            assert fixedIntervals[operandNumber] == null;
+            fixedIntervals[operandNumber] = interval;
+            return interval;
+        }
+
+        /**
+         * Creates a new interval.
+         *
+         * @param operand the operand for the interval
+         * @return the created interval
+         */
+        private TraceInterval createInterval(AllocatableValue operand) {
+            assert isLegal(operand);
+            int operandNumber = operandNumber(operand);
+            TraceInterval interval = new TraceInterval(operand, operandNumber);
+            assert operandNumber < intervalsSize;
+            assert intervals[operandNumber] == null;
+            intervals[operandNumber] = interval;
+            return interval;
+        }
+
+        /**
+         * Creates an interval as a result of splitting or spilling another interval.
+         *
+         * @param source an interval being split of spilled
+         * @return a new interval derived from {@code source}
+         */
+        TraceInterval createDerivedInterval(TraceInterval source) {
+            if (firstDerivedIntervalIndex == -1) {
+                firstDerivedIntervalIndex = intervalsSize;
+            }
+            if (intervalsSize == intervals.length) {
+                intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT) + 1);
+            }
+            // increments intervalsSize
+            Variable variable = createVariable(source.kind());
+
+            assert intervalsSize <= intervals.length;
+
+            TraceInterval interval = createInterval(variable);
+            assert intervals[intervalsSize - 1] == interval;
+            return interval;
+        }
+
+        /**
+         * Creates a new variable for a derived interval. Note that the variable is not
+         * {@linkplain LIR#numVariables() managed} so it must not be inserted into the {@link LIR}.
+         */
+        private Variable createVariable(ValueKind<?> kind) {
+            return new Variable(kind, intervalsSize++);
+        }
+
+        boolean hasDerivedIntervals() {
+            return firstDerivedIntervalIndex != -1;
+        }
+
+        int firstDerivedIntervalIndex() {
+            return firstDerivedIntervalIndex;
+        }
+
+        public int intervalsSize() {
+            return intervalsSize;
+        }
+
+        FixedInterval fixedIntervalFor(RegisterValue reg) {
+            return fixedIntervals[reg.getRegister().number];
+        }
+
+        FixedInterval getOrCreateFixedInterval(RegisterValue reg) {
+            FixedInterval ret = fixedIntervalFor(reg);
+            if (ret == null) {
+                return createFixedInterval(reg);
+            } else {
+                return ret;
+            }
+        }
+
+        TraceInterval intervalFor(Value operand) {
+            int operandNumber = operandNumber(operand);
+            assert operandNumber < intervalsSize;
+            return intervals[operandNumber];
+        }
+
+        TraceInterval getOrCreateInterval(AllocatableValue operand) {
+            TraceInterval ret = intervalFor(operand);
+            if (ret == null) {
+                return createInterval(operand);
+            } else {
+                return ret;
+            }
+        }
+
+        void initOpIdMaps(int numInstructions) {
+            opIdToInstructionMap = new LIRInstruction[numInstructions];
+            opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
+        }
+
+        void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase<?> block) {
+            opIdToInstructionMap[index] = op;
+            opIdToBlockMap[index] = block;
+        }
+
+        /**
+         * Gets the highest instruction id allocated by this object.
+         */
+        int maxOpId() {
+            assert opIdToInstructionMap.length > 0 : "no operations";
+            return (opIdToInstructionMap.length - 1) << 1;
+        }
+
+        /**
+         * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All
+         * LIR instructions in a method have an index one greater than their linear-scan order
+         * predecessor with the first instruction having an index of 0.
+         */
+        private int opIdToIndex(int opId) {
+            return opId >> 1;
+        }
+
+        /**
+         * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
+         *
+         * @param opId an instruction {@linkplain LIRInstruction#id id}
+         * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
+         */
+        LIRInstruction instructionForId(int opId) {
+            assert isEven(opId) : "opId not even";
+            LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
+            assert instr.id() == opId;
+            return instr;
+        }
+
+        /**
+         * Gets the block containing a given instruction.
+         *
+         * @param opId an instruction {@linkplain LIRInstruction#id id}
+         * @return the block containing the instruction denoted by {@code opId}
+         */
+        AbstractBlockBase<?> blockForId(int opId) {
+            assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range: " + opId;
+            return opIdToBlockMap[opIdToIndex(opId)];
+        }
+
+        @SuppressWarnings("try")
+        public void printIntervals(String label) {
+            if (Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
+                if (Debug.isLogEnabled()) {
+                    try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
+                        for (FixedInterval interval : fixedIntervals) {
+                            if (interval != null) {
+                                Debug.log("%s", interval.logString());
+                            }
+                        }
+
+                        for (TraceInterval interval : intervals) {
+                            if (interval != null) {
+                                Debug.log("%s", interval.logString());
+                            }
+                        }
+
+                        try (Indent indent2 = Debug.logAndIndent("Basic Blocks")) {
+                            for (AbstractBlockBase<?> block : trace.getBlocks()) {
+                                Debug.log("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop());
+                            }
+                        }
+                    }
+                }
+                Debug.dump(Debug.INFO_LOG_LEVEL, this, label);
+            }
+        }
+
+        @Override
+        public void visitIntervals(IntervalVisitor visitor) {
+            for (FixedInterval interval : fixedIntervals) {
+                if (interval != null) {
+                    printFixedInterval(interval, visitor);
+                }
+            }
+            for (TraceInterval interval : intervals) {
+                if (interval != null) {
+                    printInterval(interval, visitor);
+                }
+            }
+        }
+
+    }
+
+    public static boolean verifyEquals(TraceLinearScan a, TraceLinearScan b) {
+        assert compareFixed(a.fixedIntervals(), b.fixedIntervals());
+        assert compareIntervals(a.intervals(), b.intervals());
+        return true;
+    }
+
+    private static boolean compareIntervals(TraceInterval[] a, TraceInterval[] b) {
+        for (int i = 0; i < Math.max(a.length, b.length); i++) {
+            if (i >= a.length) {
+                assert b[i] == null : "missing a interval: " + i + " b: " + b[i];
+                continue;
+            }
+            if (i >= b.length) {
+                assert a[i] == null : "missing b interval: " + i + " a: " + a[i];
+                continue;
+            }
+            compareInterval(a[i], b[i]);
+        }
+        return true;
+    }
+
+    private static void compareInterval(TraceInterval a, TraceInterval b) {
+        if (a == null) {
+            assert b == null : "First interval is null but second is: " + b;
+            return;
+        }
+        assert b != null : "Second interval is null but forst is: " + a;
+        assert a.operand.equals(b.operand) : "Operand mismatch: " + a + " vs. " + b;
+        assert a.from() == b.from() : "From mismatch: " + a + " vs. " + b;
+        assert a.to() == b.to() : "To mismatch: " + a + " vs. " + b;
+        assert verifyIntervalsEquals(a, b);
+    }
+
+    private static boolean verifyIntervalsEquals(TraceInterval a, TraceInterval b) {
+        for (int i = 0; i < Math.max(a.numUsePos(), b.numUsePos()); i++) {
+            assert i < a.numUsePos() : "missing a usepos: " + i + " b: " + b;
+            assert i < b.numUsePos() : "missing b usepos: " + i + " a: " + a;
+            int aPos = a.getUsePos(i);
+            int bPos = b.getUsePos(i);
+            assert aPos == bPos : "Use Positions differ: " + aPos + " vs. " + bPos;
+            RegisterPriority aReg = a.getUsePosRegisterPriority(i);
+            RegisterPriority bReg = b.getUsePosRegisterPriority(i);
+            assert aReg == bReg : "Register priority differ: " + aReg + " vs. " + bReg;
+        }
+        return true;
+    }
+
+    private static boolean compareFixed(FixedInterval[] a, FixedInterval[] b) {
+        for (int i = 0; i < Math.max(a.length, b.length); i++) {
+            if (i >= a.length) {
+                assert b[i] == null : "missing a interval: " + i + " b: " + b[i];
+                continue;
+            }
+            if (i >= b.length) {
+                assert a[i] == null : "missing b interval: " + i + " a: " + a[i];
+                continue;
+            }
+            compareFixedInterval(a[i], b[i]);
+        }
+        return true;
+    }
+
+    private static void compareFixedInterval(FixedInterval a, FixedInterval b) {
+        if (a == null) {
+            assert b == null || isEmptyInterval(b) : "First interval is null but second is: " + b;
+            return;
+        }
+        if (b == null) {
+            assert isEmptyInterval(a) : "Second interval is null but first is: " + a;
+            return;
+        }
+        assert a.operand.equals(b.operand) : "Operand mismatch: " + a + " vs. " + b;
+        assert a.from() == b.from() : "From mismatch: " + a + " vs. " + b;
+        assert a.to() == b.to() : "To mismatch: " + a + " vs. " + b;
+        assert verifyFixeEquas(a, b);
+    }
+
+    private static boolean verifyFixeEquas(FixedInterval a, FixedInterval b) {
+        a.rewindRange();
+        b.rewindRange();
+        while (!a.currentAtEnd()) {
+            assert !b.currentAtEnd() : "Fixed range mismatch: " + a + " vs. " + b;
+            assert a.currentFrom() == b.currentFrom() : "From range mismatch: " + a + " vs. " + b + " from: " + a.currentFrom() + " vs. " + b.currentFrom();
+            assert a.currentTo() == b.currentTo() : "To range mismatch: " + a + " vs. " + b + " from: " + a.currentTo() + " vs. " + b.currentTo();
+            a.nextRange();
+            b.nextRange();
+        }
+        assert b.currentAtEnd() : "Fixed range mismatch: " + a + " vs. " + b;
+        return true;
+    }
+
+    private static boolean isEmptyInterval(FixedInterval fixed) {
+        return fixed.from() == -1 && fixed.to() == 0;
+    }
+
+    private static void printFixedInterval(FixedInterval interval, IntervalVisitor visitor) {
+        Value hint = null;
+        AllocatableValue operand = interval.operand;
+        String type = "fixed";
+        visitor.visitIntervalStart(operand, operand, operand, hint, type);
+
+        // print ranges
+        for (FixedRange range = interval.first(); range != FixedRange.EndMarker; range = range.next) {
+            visitor.visitRange(range.from, range.to);
+        }
+
+        // no use positions
+
+        visitor.visitIntervalEnd("NOT_SUPPORTED");
+
+    }
+
+    private static void printInterval(TraceInterval interval, IntervalVisitor visitor) {
+        Value hint = interval.locationHint(false) != null ? interval.locationHint(false).location() : null;
+        AllocatableValue operand = interval.operand;
+        String type = isRegister(operand) ? "fixed" : operand.getValueKind().getPlatformKind().toString();
+        visitor.visitIntervalStart(interval.splitParent().operand, operand, interval.location(), hint, type);
+
+        // print ranges
+        visitor.visitRange(interval.from(), interval.to());
+
+        // print use positions
+        int prev = -1;
+        for (int i = interval.numUsePos() - 1; i >= 0; --i) {
+            assert prev < interval.getUsePos(i) : "use positions not sorted";
+            visitor.visitUsePos(interval.getUsePos(i), interval.getUsePosRegisterPriority(i));
+            prev = interval.getUsePos(i);
+        }
+
+        visitor.visitIntervalEnd(interval.spillState());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java
new file mode 100644
index 0000000..83133f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.TargetDescription;
+
+final class TraceLinearScanRegisterAllocationPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
+        TraceLinearScan allocator = context.allocator;
+        allocateRegisters(allocator);
+    }
+
+    @SuppressWarnings("try")
+    private static void allocateRegisters(TraceLinearScan allocator) {
+        try (Indent indent = Debug.logAndIndent("allocate registers")) {
+            FixedInterval precoloredIntervals = allocator.createFixedUnhandledList();
+            TraceInterval notPrecoloredIntervals = allocator.createUnhandledListByFrom(TraceLinearScanPhase.IS_VARIABLE_INTERVAL);
+
+            // allocate cpu registers
+            TraceLinearScanWalker lsw = new TraceLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            lsw.walk();
+            lsw.finishAllocation();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java
new file mode 100644
index 0000000..67200c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
+import org.graalvm.compiler.lir.ssi.SSIUtil;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Phase 6: resolve data flow
+ *
+ * Insert moves at edges between blocks if intervals have been split.
+ */
+final class TraceLinearScanResolveDataFlowPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
+        TraceBuilderResult traceBuilderResult = context.resultTraces;
+        TraceLinearScan allocator = context.allocator;
+        new Resolver(allocator, traceBuilderResult).resolveDataFlow(trace, allocator.sortedBlocks());
+    }
+
+    private static final class Resolver {
+        private final TraceLinearScan allocator;
+        private final TraceBuilderResult traceBuilderResult;
+
+        private Resolver(TraceLinearScan allocator, TraceBuilderResult traceBuilderResult) {
+            this.allocator = allocator;
+            this.traceBuilderResult = traceBuilderResult;
+        }
+
+        private void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            if (fromBlock.getSuccessorCount() <= 1) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+                }
+
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock);
+                LIRInstruction instr = instructions.get(instructions.size() - 1);
+                if (instr instanceof StandardOp.JumpOp) {
+                    // insert moves before branch
+                    moveResolver.setInsertPosition(instructions, instructions.size() - 1);
+                } else {
+                    moveResolver.setInsertPosition(instructions, instructions.size());
+                }
+
+            } else {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+                }
+
+                if (DetailedAsserts.getValue()) {
+                    assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+
+                    /*
+                     * Because the number of predecessor edges matches the number of successor
+                     * edges, blocks which are reached by switch statements may have be more than
+                     * one predecessor but it will be guaranteed that all predecessors will be the
+                     * same.
+                     */
+                    for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
+                        assert fromBlock == predecessor : "all critical edges must be broken";
+                    }
+                }
+
+                moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1);
+            }
+        }
+
+        /**
+         * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals
+         * that have been split.
+         */
+        @SuppressWarnings("try")
+        private void resolveDataFlow(Trace currentTrace, AbstractBlockBase<?>[] blocks) {
+            if (blocks.length < 2) {
+                // no resolution necessary
+                return;
+            }
+            try (Indent indent = Debug.logAndIndent("resolve data flow")) {
+
+                TraceLocalMoveResolver moveResolver = allocator.createMoveResolver();
+                AbstractBlockBase<?> toBlock = null;
+                for (int i = 0; i < blocks.length - 1; i++) {
+                    AbstractBlockBase<?> fromBlock = blocks[i];
+                    toBlock = blocks[i + 1];
+                    assert containedInTrace(currentTrace, fromBlock) : "Not in Trace: " + fromBlock;
+                    assert containedInTrace(currentTrace, toBlock) : "Not in Trace: " + toBlock;
+                    resolveCollectMappings(fromBlock, toBlock, moveResolver);
+                }
+                assert blocks[blocks.length - 1].equals(toBlock);
+                if (toBlock.isLoopEnd()) {
+                    assert toBlock.getSuccessorCount() == 1;
+                    AbstractBlockBase<?> loopHeader = toBlock.getSuccessors()[0];
+                    if (containedInTrace(currentTrace, loopHeader)) {
+                        resolveCollectMappings(toBlock, loopHeader, moveResolver);
+                    }
+                }
+
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            try (Indent indent0 = Debug.logAndIndent("Edge %s -> %s", fromBlock, toBlock)) {
+                // collect all intervals that have been split between
+                // fromBlock and toBlock
+                SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MappingCollector(moveResolver, toBlock, fromBlock));
+                if (moveResolver.hasMappings()) {
+                    resolveFindInsertPos(fromBlock, toBlock, moveResolver);
+                    moveResolver.resolveAndAppendMoves();
+                }
+            }
+        }
+
+        private boolean containedInTrace(Trace currentTrace, AbstractBlockBase<?> block) {
+            return currentTrace.getId() == traceBuilderResult.getTraceForBlock(block).getId();
+        }
+
+        private static final DebugCounter numSSIResolutionMoves = Debug.counter("SSI LSRA[numSSIResolutionMoves]");
+        private static final DebugCounter numStackToStackMoves = Debug.counter("SSI LSRA[numStackToStackMoves]");
+
+        private class MappingCollector implements PhiValueVisitor {
+            final TraceLocalMoveResolver moveResolver;
+            final int toId;
+            final int fromId;
+
+            MappingCollector(TraceLocalMoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) {
+                this.moveResolver = moveResolver;
+                toId = allocator.getFirstLirInstructionId(toBlock);
+                fromId = allocator.getLastLirInstructionId(fromBlock);
+                assert fromId >= 0;
+            }
+
+            @Override
+            public void visit(Value phiIn, Value phiOut) {
+                assert !isRegister(phiOut) : "Out is a register: " + phiOut;
+                assert !isRegister(phiIn) : "In is a register: " + phiIn;
+                if (Value.ILLEGAL.equals(phiIn)) {
+                    // The value not needed in this branch.
+                    return;
+                }
+                if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) {
+                    // no need to handle virtual stack slots
+                    return;
+                }
+                TraceInterval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF);
+                if (isConstantValue(phiOut)) {
+                    numSSIResolutionMoves.increment();
+                    moveResolver.addMapping(asConstant(phiOut), toInterval);
+                } else {
+                    TraceInterval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF);
+                    if (fromInterval != toInterval) {
+                        numSSIResolutionMoves.increment();
+                        if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                            moveResolver.addMapping(fromInterval, toInterval);
+                        } else {
+                            numStackToStackMoves.increment();
+                            moveResolver.addMapping(fromInterval, toInterval);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java
new file mode 100644
index 0000000..d28d653
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.CodeUtil.isOdd;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+final class TraceLinearScanWalker extends TraceIntervalWalker {
+
+    private Register[] availableRegs;
+
+    private final int[] usePos;
+    private final int[] blockPos;
+    private final BitSet isInMemory;
+
+    private List<TraceInterval>[] spillIntervals;
+
+    private TraceLocalMoveResolver moveResolver; // for ordering spill moves
+
+    private int minReg;
+
+    private int maxReg;
+
+    /**
+     * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
+     * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
+     * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker
+     * value, and allocate a "real" list only on demand in {@link #setUsePos}.
+     */
+    private static final List<TraceInterval> EMPTY_LIST = new ArrayList<>(0);
+
+    // accessors mapped to same functions in class LinearScan
+    private int blockCount() {
+        return allocator.blockCount();
+    }
+
+    private AbstractBlockBase<?> blockAt(int idx) {
+        return allocator.blockAt(idx);
+    }
+
+    @SuppressWarnings("unused")
+    private AbstractBlockBase<?> blockOfOpWithId(int opId) {
+        return allocator.blockForId(opId);
+    }
+
+    TraceLinearScanWalker(TraceLinearScan allocator, FixedInterval unhandledFixedFirst, TraceInterval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+
+        moveResolver = allocator.createMoveResolver();
+        int numRegs = allocator.getRegisters().size();
+        spillIntervals = Util.uncheckedCast(new List<?>[numRegs]);
+        for (int i = 0; i < numRegs; i++) {
+            spillIntervals[i] = EMPTY_LIST;
+        }
+        usePos = new int[numRegs];
+        blockPos = new int[numRegs];
+        isInMemory = new BitSet(numRegs);
+    }
+
+    private void initUseLists(boolean onlyProcessUsePos) {
+        for (Register register : availableRegs) {
+            int i = register.number;
+            usePos[i] = Integer.MAX_VALUE;
+
+            if (!onlyProcessUsePos) {
+                blockPos[i] = Integer.MAX_VALUE;
+                spillIntervals[i].clear();
+                isInMemory.clear(i);
+            }
+        }
+    }
+
+    private int maxRegisterNumber() {
+        return maxReg;
+    }
+
+    private int minRegisterNumber() {
+        return minReg;
+    }
+
+    private boolean isRegisterInRange(int reg) {
+        return reg >= minRegisterNumber() && reg <= maxRegisterNumber();
+    }
+
+    private void excludeFromUse(IntervalHint i) {
+        Value location = i.location();
+        int i1 = asRegister(location).number;
+        if (isRegisterInRange(i1)) {
+            usePos[i1] = 0;
+        }
+    }
+
+    private void setUsePos(TraceInterval interval, int usePos, boolean onlyProcessUsePos) {
+        if (usePos != -1) {
+            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
+            int i = asRegister(interval.location()).number;
+            if (isRegisterInRange(i)) {
+                if (this.usePos[i] > usePos) {
+                    this.usePos[i] = usePos;
+                }
+                if (!onlyProcessUsePos) {
+                    List<TraceInterval> list = spillIntervals[i];
+                    if (list == EMPTY_LIST) {
+                        list = new ArrayList<>(2);
+                        spillIntervals[i] = list;
+                    }
+                    list.add(interval);
+                    // set is in memory flag
+                    if (interval.inMemoryAt(currentPosition)) {
+                        isInMemory.set(i);
+                    }
+                }
+            }
+        }
+    }
+
+    private void setUsePos(FixedInterval interval, int usePos, boolean onlyProcessUsePos) {
+        assert onlyProcessUsePos;
+        if (usePos != -1) {
+            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
+            int i = asRegister(interval.location()).number;
+            if (isRegisterInRange(i)) {
+                if (this.usePos[i] > usePos) {
+                    this.usePos[i] = usePos;
+                }
+            }
+        }
+    }
+
+    private void setBlockPos(IntervalHint i, int blockPos) {
+        if (blockPos != -1) {
+            int reg = asRegister(i.location()).number;
+            if (isRegisterInRange(reg)) {
+                if (this.blockPos[reg] > blockPos) {
+                    this.blockPos[reg] = blockPos;
+                }
+                if (usePos[reg] > blockPos) {
+                    usePos[reg] = blockPos;
+                }
+            }
+        }
+    }
+
+    private void freeExcludeActiveFixed() {
+        FixedInterval interval = activeFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void freeExcludeActiveAny() {
+        TraceInterval interval = activeAnyList.getAny();
+        while (interval != TraceInterval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void freeCollectInactiveFixed(TraceInterval current) {
+        FixedInterval interval = inactiveFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            if (current.to() <= interval.from()) {
+                assert interval.intersectsAt(current) == -1 : "must not intersect";
+                setUsePos(interval, interval.from(), true);
+            } else {
+                setUsePos(interval, interval.currentIntersectsAt(current), true);
+            }
+            interval = interval.next;
+        }
+    }
+
+    private void spillExcludeActiveFixed() {
+        FixedInterval interval = activeFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void spillBlockInactiveFixed(TraceInterval current) {
+        FixedInterval interval = inactiveFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            if (current.to() > interval.currentFrom()) {
+                setBlockPos(interval, interval.currentIntersectsAt(current));
+            } else {
+                assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect";
+            }
+
+            interval = interval.next;
+        }
+    }
+
+    private void spillCollectActiveAny(RegisterPriority registerPriority) {
+        TraceInterval interval = activeAnyList.getAny();
+        while (interval != TraceInterval.EndMarker) {
+            setUsePos(interval, Math.min(interval.nextUsage(registerPriority, currentPosition), interval.to()), false);
+            interval = interval.next;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private int insertIdAtBasicBlockBoundary(int opId) {
+        assert allocator.isBlockBegin(opId) : "Not a block begin: " + opId;
+        assert allocator.instructionForId(opId) instanceof LabelOp;
+        assert allocator.instructionForId(opId - 2) instanceof BlockEndOp;
+
+        AbstractBlockBase<?> toBlock = allocator.blockForId(opId);
+        AbstractBlockBase<?> fromBlock = allocator.blockForId(opId - 2);
+
+        if (fromBlock.getSuccessorCount() == 1) {
+            // insert move in predecessor
+            return opId - 2;
+        }
+        assert toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s->%s", fromBlock, toBlock);
+        // insert move in successor
+        return opId + 2;
+    }
+
+    private void insertMove(int operandId, TraceInterval srcIt, TraceInterval dstIt) {
+        // output all moves here. When source and target are equal, the move is
+        // optimized away later in assignRegNums
+
+        int opId = (operandId + 1) & ~1;
+        AbstractBlockBase<?> opBlock = allocator.blockForId(opId);
+        assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary";
+
+        // calculate index of instruction inside instruction list of current block
+        // the minimal index (for a block with no spill moves) can be calculated because the
+        // numbering of instructions is known.
+        // When the block already contains spill moves, the index must be increased until the
+        // correct index is reached.
+        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock);
+        int index = (opId - instructions.get(0).id()) >> 1;
+        assert instructions.get(index).id() <= opId : "error in calculation";
+
+        while (instructions.get(index).id() != opId) {
+            index++;
+            assert 0 <= index && index < instructions.size() : "index out of bounds";
+        }
+        assert 1 <= index && index < instructions.size() : "index out of bounds";
+        assert instructions.get(index).id() == opId : "error in calculation";
+
+        // insert new instruction before instruction at position index
+        moveResolver.moveInsertPosition(instructions, index);
+        moveResolver.addMapping(srcIt, dstIt);
+    }
+
+    private int findOptimalSplitPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
+        int fromBlockNr = minBlock.getLinearScanNumber();
+        int toBlockNr = maxBlock.getLinearScanNumber();
+
+        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
+        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
+        assert fromBlockNr < toBlockNr : "must cross block boundary";
+
+        // Try to split at end of maxBlock. If this would be after
+        // maxSplitPos, then use the begin of maxBlock
+        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) + 2;
+        if (optimalSplitPos > maxSplitPos) {
+            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
+        }
+
+        // minimal block probability
+        double minProbability = maxBlock.probability();
+        for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
+            AbstractBlockBase<?> cur = blockAt(i);
+
+            if (cur.probability() < minProbability) {
+                // Block with lower probability found. Split at the end of this block.
+                minProbability = cur.probability();
+                optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2;
+            }
+        }
+        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary";
+
+        return optimalSplitPos;
+    }
+
+    @SuppressWarnings({"unused"})
+    private int findOptimalSplitPos(TraceInterval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
+        int optimalSplitPos = findOptimalSplitPos0(minSplitPos, maxSplitPos);
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal split position: %d", optimalSplitPos);
+        }
+        return optimalSplitPos;
+    }
+
+    private int findOptimalSplitPos0(int minSplitPos, int maxSplitPos) {
+        if (minSplitPos == maxSplitPos) {
+            // trivial case, no optimization of split position possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
+            return minSplitPos;
+
+        }
+        assert minSplitPos < maxSplitPos : "must be true then";
+        assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise";
+
+        // reason for using minSplitPos - 1: when the minimal split pos is exactly at the
+        // beginning of a block, then minSplitPos is also a possible split position.
+        // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 ==
+        // minSplitPos
+        AbstractBlockBase<?> minBlock = allocator.blockForId(minSplitPos - 1);
+
+        // reason for using maxSplitPos - 1: otherwise there would be an assert on failure
+        // when an interval ends at the end of the last block of the method
+        // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no
+        // block at this opId)
+        AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
+
+        assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
+        if (minBlock == maxBlock) {
+            // split position cannot be moved to block boundary : so split as late as possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+            }
+            return maxSplitPos;
+
+        }
+        // seach optimal block boundary between minSplitPos and maxSplitPos
+        if (Debug.isLogEnabled()) {
+            Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+        }
+
+        return findOptimalSplitPos(minBlock, maxBlock, maxSplitPos);
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is sorted into to the unhandled-list
+    @SuppressWarnings("try")
+    private void splitBeforeUsage(TraceInterval interval, int minSplitPos, int maxSplitPos) {
+
+        try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.from() < minSplitPos : "cannot split at start of interval";
+            assert currentPosition < minSplitPos : "cannot split before current position";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos <= interval.to() : "cannot split after end of interval";
+
+            final int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
+
+            if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
+                return;
+            }
+            // must calculate this before the actual split is performed and before split position is
+            // moved to odd opId
+            final int optimalSplitPosFinal;
+            boolean blockBegin = allocator.isBlockBegin(optimalSplitPos);
+            if (blockBegin) {
+                assert (optimalSplitPos & 1) == 0 : "Block begins must be even: " + optimalSplitPos;
+                // move position after the label (odd optId)
+                optimalSplitPosFinal = optimalSplitPos + 1;
+            } else {
+                // move position before actual instruction (odd opId)
+                optimalSplitPosFinal = (optimalSplitPos - 1) | 1;
+            }
+
+            // TODO( je) better define what min split pos max split pos mean.
+            assert minSplitPos <= optimalSplitPosFinal && optimalSplitPosFinal <= maxSplitPos || minSplitPos == maxSplitPos && optimalSplitPosFinal == minSplitPos - 1 : "out of range";
+            assert optimalSplitPosFinal <= interval.to() : "cannot split after end of interval";
+            assert optimalSplitPosFinal > interval.from() : "cannot split at start of interval";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("splitting at position %d", optimalSplitPosFinal);
+            }
+            assert optimalSplitPosFinal > currentPosition : "Can not split interval " + interval + " at current position: " + currentPosition;
+
+            // was:
+            // assert isBlockBegin || ((optimalSplitPos1 & 1) == 1) :
+            // "split pos must be odd when not on block boundary";
+            // assert !isBlockBegin || ((optimalSplitPos1 & 1) == 0) :
+            // "split pos must be even on block boundary";
+            assert (optimalSplitPosFinal & 1) == 1 : "split pos must be odd";
+
+            // TODO (je) duplicate code. try to fold
+            if (optimalSplitPosFinal == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
+                return;
+            }
+            TraceInterval splitPart = interval.split(optimalSplitPosFinal, allocator);
+
+            boolean moveNecessary = true;
+            splitPart.setInsertMoveWhenActivated(moveNecessary);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+            unhandledAnyList.addToListSortedByStartAndUsePositions(splitPart);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString());
+                Debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString());
+            }
+        }
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is always on the stack and therefore ignored in further processing
+    @SuppressWarnings("try")
+    private void splitForSpilling(TraceInterval interval) {
+        // calculate allowed range of splitting position
+        int maxSplitPos = currentPosition;
+        int previousUsage = interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos);
+        if (previousUsage == currentPosition) {
+            /*
+             * If there is a usage with ShouldHaveRegister priority at the current position fall
+             * back to MustHaveRegister priority. This only happens if register priority was
+             * downgraded to MustHaveRegister in #allocLockedRegister.
+             */
+            previousUsage = interval.previousUsage(RegisterPriority.MustHaveRegister, maxSplitPos);
+        }
+        int minSplitPos = Math.max(previousUsage + 1, interval.from());
+
+        try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.from() <= minSplitPos : "cannot split before start of interval";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos < interval.to() : "cannot split at end end of interval";
+            assert currentPosition < interval.to() : "interval must not end before current position";
+
+            if (minSplitPos == interval.from()) {
+                // the whole interval is never used, so spill it entirely to memory
+
+                try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.numUsePos())) {
+
+                    assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
+                                    currentPosition);
+
+                    allocator.assignSpillSlot(interval);
+                    handleSpillSlot(interval);
+                    changeSpillState(interval, minSplitPos);
+
+                    // Also kick parent intervals out of register to memory when they have no use
+                    // position. This avoids short interval in register surrounded by intervals in
+                    // memory . avoid useless moves from memory to register and back
+                    TraceInterval parent = interval;
+                    while (parent != null && parent.isSplitChild()) {
+                        parent = parent.getSplitChildBeforeOpId(parent.from());
+
+                        if (isRegister(parent.location())) {
+                            if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
+                                // parent is never used, so kick it out of its assigned register
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                }
+                                allocator.assignSpillSlot(parent);
+                                handleSpillSlot(parent);
+                            } else {
+                                // do not go further back because the register is actually used by
+                                // the interval
+                                parent = null;
+                            }
+                        }
+                    }
+                }
+
+            } else {
+                // search optimal split pos, split interval and spill only the right hand part
+                int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
+
+                assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+                assert optimalSplitPos < interval.to() : "cannot split at end of interval";
+                assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
+
+                if (!allocator.isBlockBegin(optimalSplitPos)) {
+                    // move position before actual instruction (odd opId)
+                    optimalSplitPos = (optimalSplitPos - 1) | 1;
+                }
+
+                try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
+                    assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
+                    assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
+
+                    TraceInterval spilledPart = interval.split(optimalSplitPos, allocator);
+                    allocator.assignSpillSlot(spilledPart);
+                    handleSpillSlot(spilledPart);
+                    changeSpillState(spilledPart, optimalSplitPos);
+
+                    if (!allocator.isBlockBegin(optimalSplitPos)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("inserting move from interval %s to %s", interval, spilledPart);
+                        }
+                        insertMove(optimalSplitPos, interval, spilledPart);
+                    } else {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("no need to insert move. done by data-flow resolution");
+                        }
+                    }
+
+                    // the currentSplitChild is needed later when moves are inserted for reloading
+                    assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
+                    spilledPart.makeCurrentSplitChild();
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("left interval: %s", interval.logString());
+                        Debug.log("spilled interval   : %s", spilledPart.logString());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Change spill state of an interval.
+     *
+     * Note: called during register allocation.
+     *
+     * @param spillPos position of the spill
+     */
+    private void changeSpillState(TraceInterval interval, int spillPos) {
+        if (TraceLinearScanPhase.Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
+            switch (interval.spillState()) {
+                case NoSpillStore:
+                    final int minSpillPos = interval.spillDefinitionPos();
+                    final int maxSpillPost = spillPos;
+
+                    final int optimalSpillPos = findOptimalSpillPos(minSpillPos, maxSpillPost);
+
+                    // assert !allocator.isBlockBegin(optimalSpillPos);
+                    assert !allocator.isBlockEnd(optimalSpillPos);
+                    assert (optimalSpillPos & 1) == 0 : "Spill pos must be even";
+
+                    interval.setSpillDefinitionPos(optimalSpillPos);
+                    interval.setSpillState(SpillState.SpillStore);
+                    break;
+                case SpillStore:
+                case StartInMemory:
+                case NoOptimization:
+                case NoDefinitionFound:
+                    // nothing to do
+                    break;
+
+                default:
+                    throw GraalError.shouldNotReachHere("other states not allowed at this time");
+            }
+        } else {
+            interval.setSpillState(SpillState.NoOptimization);
+        }
+    }
+
+    /**
+     * @param minSpillPos minimal spill position
+     * @param maxSpillPos maximal spill position
+     */
+    private int findOptimalSpillPos(int minSpillPos, int maxSpillPos) {
+        int optimalSpillPos = findOptimalSpillPos0(minSpillPos, maxSpillPos) & (~1);
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal spill position: %d", optimalSpillPos);
+        }
+        return optimalSpillPos;
+    }
+
+    private int findOptimalSpillPos0(int minSpillPos, int maxSpillPos) {
+        if (minSpillPos == maxSpillPos) {
+            // trivial case, no optimization of split position possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
+            return minSpillPos;
+
+        }
+        assert minSpillPos < maxSpillPos : "must be true then";
+        assert minSpillPos >= 0 : "cannot access minSplitPos - 1 otherwise";
+
+        AbstractBlockBase<?> minBlock = allocator.blockForId(minSpillPos);
+        AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSpillPos);
+
+        assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
+        if (minBlock == maxBlock) {
+            // split position cannot be moved to block boundary : so split as late as possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+            }
+            return maxSpillPos;
+
+        }
+        // search optimal block boundary between minSplitPos and maxSplitPos
+        if (Debug.isLogEnabled()) {
+            Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+        }
+
+        // currently using the same heuristic as for splitting
+        return findOptimalSpillPos(minBlock, maxBlock, maxSpillPos);
+    }
+
+    private int findOptimalSpillPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
+        int fromBlockNr = minBlock.getLinearScanNumber();
+        int toBlockNr = maxBlock.getLinearScanNumber();
+
+        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
+        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
+        assert fromBlockNr < toBlockNr : "must cross block boundary";
+
+        /*
+         * Try to split at end of maxBlock. If this would be after maxSplitPos, then use the begin
+         * of maxBlock. We use last instruction -2 because we want to insert the move before the
+         * block end op.
+         */
+        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) - 2;
+        if (optimalSplitPos > maxSplitPos) {
+            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
+        }
+
+        // minimal block probability
+        double minProbability = maxBlock.probability();
+        for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
+            AbstractBlockBase<?> cur = blockAt(i);
+
+            if (cur.probability() < minProbability) {
+                // Block with lower probability found. Split at the end of this block.
+                minProbability = cur.probability();
+                optimalSplitPos = allocator.getLastLirInstructionId(cur) - 2;
+            }
+        }
+        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) || allocator.isBlockEnd(optimalSplitPos + 2) : "algorithm must move split pos to block boundary";
+
+        return optimalSplitPos;
+    }
+
+    /**
+     * This is called for every interval that is assigned to a stack slot.
+     */
+    private static void handleSpillSlot(TraceInterval interval) {
+        assert interval.location() != null && (interval.canMaterialize() || isStackSlotValue(interval.location())) : "interval not assigned to a stack slot " + interval;
+        // Do nothing. Stack slots are not processed in this implementation.
+    }
+
+    private void splitStackInterval(TraceInterval interval) {
+        int minSplitPos = currentPosition + 1;
+        int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
+
+        splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+    }
+
+    private void splitWhenPartialRegisterAvailable(TraceInterval interval, int registerAvailableUntil) {
+        int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1);
+        splitBeforeUsage(interval, minSplitPos, registerAvailableUntil);
+    }
+
+    private void splitAndSpillInterval(TraceInterval interval) {
+        int currentPos = currentPosition;
+        /*
+         * Search the position where the interval must have a register and split at the optimal
+         * position before. The new created part is added to the unhandled list and will get a
+         * register when it is activated.
+         */
+        int minSplitPos = currentPos + 1;
+        int maxSplitPos = interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos);
+
+        if (maxSplitPos <= interval.to()) {
+            splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+        } else {
+            Debug.log("No more usage, no need to split: %s", interval);
+        }
+
+        assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register";
+        splitForSpilling(interval);
+    }
+
+    @SuppressWarnings("try")
+    private boolean allocFreeRegister(TraceInterval interval) {
+        try (Indent indent = Debug.logAndIndent("trying to find free register for %s", interval)) {
+
+            initUseLists(true);
+            freeExcludeActiveFixed();
+            freeCollectInactiveFixed(interval);
+            freeExcludeActiveAny();
+            // freeCollectUnhandled(fixedKind, cur);
+
+            // usePos contains the start of the next interval that has this register assigned
+            // (either as a fixed register or a normal allocated register in the past)
+            // only intervals overlapping with cur are processed, non-overlapping invervals can be
+            // ignored safely
+            if (Debug.isLogEnabled()) {
+                // Enable this logging to see all register states
+                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                    for (Register register : availableRegs) {
+                        int i = register.number;
+                        Debug.log("reg %d (%s): usePos: %d", register.number, register, usePos[i]);
+                    }
+                }
+            }
+
+            Register hint = null;
+            IntervalHint locationHint = interval.locationHint(true);
+            if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
+                hint = asRegister(locationHint.location());
+                if (Debug.isLogEnabled()) {
+                    Debug.log("hint register %3d (%4s) from interval %s", hint.number, hint, locationHint);
+                }
+            }
+            assert interval.location() == null : "register already assigned to interval";
+
+            // the register must be free at least until this position
+            int regNeededUntil = interval.from() + 1;
+            int intervalTo = interval.to();
+
+            boolean needSplit = false;
+            int splitPos = -1;
+
+            Register reg = null;
+            Register minFullReg = null;
+            Register maxPartialReg = null;
+
+            for (Register availableReg : availableRegs) {
+                int number = availableReg.number;
+                if (usePos[number] >= intervalTo) {
+                    // this register is free for the full interval
+                    if (minFullReg == null || availableReg.equals(hint) || (usePos[number] < usePos[minFullReg.number] && !minFullReg.equals(hint))) {
+                        minFullReg = availableReg;
+                    }
+                } else if (usePos[number] > regNeededUntil) {
+                    // this register is at least free until regNeededUntil
+                    if (maxPartialReg == null || availableReg.equals(hint) || (usePos[number] > usePos[maxPartialReg.number] && !maxPartialReg.equals(hint))) {
+                        maxPartialReg = availableReg;
+                    }
+                }
+            }
+
+            if (minFullReg != null) {
+                reg = minFullReg;
+            } else if (maxPartialReg != null) {
+                needSplit = true;
+                reg = maxPartialReg;
+            } else {
+                return false;
+            }
+
+            splitPos = usePos[reg.number];
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (Debug.isLogEnabled()) {
+                Debug.log("selected register %d (%s)", reg.number, reg);
+            }
+
+            assert splitPos > 0 : "invalid splitPos";
+            if (needSplit) {
+                // register not available for full interval, so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+            // only return true if interval is completely assigned
+            return true;
+        }
+    }
+
+    private void splitAndSpillIntersectingIntervals(Register reg) {
+        assert reg != null : "no register assigned";
+
+        for (int i = 0; i < spillIntervals[reg.number].size(); i++) {
+            TraceInterval interval = spillIntervals[reg.number].get(i);
+            removeFromList(interval);
+            splitAndSpillInterval(interval);
+        }
+    }
+
+    // Split an Interval and spill it to memory so that cur can be placed in a register
+    @SuppressWarnings("try")
+    private void allocLockedRegister(TraceInterval interval) {
+        try (Indent indent = Debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", interval)) {
+
+            // the register must be free at least until this position
+            int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister);
+            int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
+            int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
+            int intervalTo = interval.to();
+            assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
+
+            Register reg;
+            Register ignore;
+            /*
+             * In the common case we don't spill registers that have _any_ use position that is
+             * closer than the next use of the current interval, but if we can't spill the current
+             * interval we weaken this strategy and also allow spilling of intervals that have a
+             * non-mandatory requirements (no MustHaveRegister use position).
+             */
+            for (RegisterPriority registerPriority = RegisterPriority.LiveAtLoopEnd; true; registerPriority = RegisterPriority.MustHaveRegister) {
+                // collect current usage of registers
+                initUseLists(false);
+                spillExcludeActiveFixed();
+                // spillBlockUnhandledFixed(cur);
+                spillBlockInactiveFixed(interval);
+                spillCollectActiveAny(registerPriority);
+                if (Debug.isLogEnabled()) {
+                    printRegisterState();
+                }
+
+                reg = null;
+                ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
+
+                for (Register availableReg : availableRegs) {
+                    int number = availableReg.number;
+                    if (availableReg.equals(ignore)) {
+                        // this register must be ignored
+                    } else if (usePos[number] > regNeededUntil) {
+                        /*
+                         * If the use position is the same, prefer registers (active intervals)
+                         * where the value is already on the stack.
+                         */
+                        if (reg == null || (usePos[number] > usePos[reg.number]) || (usePos[number] == usePos[reg.number] && (!isInMemory.get(reg.number) && isInMemory.get(number)))) {
+                            reg = availableReg;
+                        }
+                    }
+                }
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Register Selected: %s", reg);
+                }
+
+                int regUsePos = (reg == null ? 0 : usePos[reg.number]);
+                if (regUsePos <= firstShouldHaveUsage) {
+                    /* Check if there is another interval that is already in memory. */
+                    if (reg == null || interval.inMemoryAt(currentPosition) || !isInMemory.get(reg.number)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
+                        }
+
+                        if (firstUsage <= interval.from() + 1) {
+                            if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
+                                /*
+                                 * Tool of last resort: we can not spill the current interval so we
+                                 * try to spill an active interval that has a usage but do not
+                                 * require a register.
+                                 */
+                                Debug.log("retry with register priority must have register");
+                                continue;
+                            }
+                            String description = "cannot spill interval (" + interval + ") that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage +
+                                            ", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
+                            /*
+                             * assign a reasonable register and do a bailout in product mode to
+                             * avoid errors
+                             */
+                            allocator.assignSpillSlot(interval);
+                            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+                                dumpLIRAndIntervals(description);
+                            }
+                            throw new OutOfRegistersException("LinearScan: no register found", description);
+                        }
+
+                        splitAndSpillInterval(interval);
+                        return;
+                    }
+                }
+                // common case: break out of the loop
+                break;
+            }
+
+            boolean needSplit = blockPos[reg.number] <= intervalTo;
+
+            int splitPos = blockPos[reg.number];
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("decided to use register %d", reg.number);
+            }
+            assert splitPos > 0 : "invalid splitPos";
+            assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (needSplit) {
+                // register not available for full interval : so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+
+            // perform splitting and spilling for all affected intervals
+            splitAndSpillIntersectingIntervals(reg);
+            return;
+        }
+    }
+
+    protected void dumpLIRAndIntervals(String description) {
+        Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description);
+        allocator.printIntervals(description);
+    }
+
+    @SuppressWarnings("try")
+    private void printRegisterState() {
+        try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+            for (Register reg : availableRegs) {
+                int i = reg.number;
+                try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, inMemory: %b, intervals: ", i, usePos[i], blockPos[i], isInMemory.get(i))) {
+                    for (int j = 0; j < spillIntervals[i].size(); j++) {
+                        Debug.log("%s", spillIntervals[i].get(j));
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean noAllocationPossible(TraceInterval interval) {
+        if (allocator.callKillsRegisters()) {
+            // fast calculation of intervals that can never get a register because the
+            // the next instruction is a call that blocks all registers
+            // Note: this only works if a call kills all registers
+
+            // check if this interval is the result of a split operation
+            // (an interval got a register until this position)
+            int pos = interval.from();
+            if (isOdd(pos)) {
+                // the current instruction is a call that blocks all registers
+                if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("free register cannot be available because all registers blocked by following call");
+                    }
+
+                    // safety check that there is really no register available
+                    assert !allocFreeRegister(interval) : "found a register for this interval";
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void initVarsForAlloc(TraceInterval interval) {
+        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
+        availableRegs = allocatableRegisters.allocatableRegisters;
+        minReg = allocatableRegisters.minRegisterNumber;
+        maxReg = allocatableRegisters.maxRegisterNumber;
+    }
+
+    private static boolean isMove(LIRInstruction op, TraceInterval from, TraceInterval to) {
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (isVariable(move.getInput()) && isVariable(move.getResult())) {
+                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
+            }
+        }
+        return false;
+    }
+
+    // optimization (especially for phi functions of nested loops):
+    // assign same spill slot to non-intersecting intervals
+    private void combineSpilledIntervals(TraceInterval interval) {
+        if (interval.isSplitChild()) {
+            // optimization is only suitable for split parents
+            return;
+        }
+
+        IntervalHint locationHint = interval.locationHint(false);
+        if (locationHint == null || !(locationHint instanceof TraceInterval)) {
+            return;
+        }
+        TraceInterval registerHint = (TraceInterval) locationHint;
+        assert registerHint.isSplitParent() : "register hint must be split parent";
+
+        if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) {
+            // combining the stack slots for intervals where spill move optimization is applied
+            // is not benefitial and would cause problems
+            return;
+        }
+
+        int beginPos = interval.from();
+        int endPos = interval.to();
+        if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) {
+            // safety check that lirOpWithId is allowed
+            return;
+        }
+
+        if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) {
+            // cur and registerHint are not connected with two moves
+            return;
+        }
+
+        TraceInterval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.USE);
+        TraceInterval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.DEF);
+        if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) {
+            // registerHint must be split : otherwise the re-writing of use positions does not work
+            return;
+        }
+
+        assert beginHint.location() != null : "must have register assigned";
+        assert endHint.location() == null : "must not have register assigned";
+        assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move";
+        assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move";
+
+        if (isRegister(beginHint.location())) {
+            // registerHint is not spilled at beginPos : so it would not be benefitial to
+            // immediately spill cur
+            return;
+        }
+        assert registerHint.spillSlot() != null : "must be set when part of interval was spilled";
+
+        // modify intervals such that cur gets the same stack slot as registerHint
+        // delete use positions to prevent the intervals to get a register at beginning
+        interval.setSpillSlot(registerHint.spillSlot());
+        interval.removeFirstUsePos();
+        endHint.removeFirstUsePos();
+    }
+
+    // allocate a physical register or memory location to an interval
+    @Override
+    @SuppressWarnings("try")
+    protected boolean activateCurrent(TraceInterval interval) {
+        if (Debug.isLogEnabled()) {
+            logCurrentStatus();
+        }
+        boolean result = true;
+
+        try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
+
+            final Value operand = interval.operand;
+            if (interval.location() != null && isStackSlotValue(interval.location())) {
+                // activating an interval that has a stack slot assigned . split it at first use
+                // position
+                // used for method parameters
+                if (Debug.isLogEnabled()) {
+                    Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                }
+                splitStackInterval(interval);
+                result = false;
+
+            } else {
+                if (interval.location() == null) {
+                    // interval has not assigned register . normal allocation
+                    // (this is the normal case for most intervals)
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("normal allocation of register");
+                    }
+
+                    // assign same spill slot to non-intersecting intervals
+                    combineSpilledIntervals(interval);
+
+                    initVarsForAlloc(interval);
+                    if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
+                        // no empty register available.
+                        // split and spill another interval so that this interval gets a register
+                        allocLockedRegister(interval);
+                    }
+
+                    // spilled intervals need not be move to active-list
+                    if (!isRegister(interval.location())) {
+                        result = false;
+                    }
+                }
+            }
+
+            // load spilled values that become active from stack slot to register
+            if (interval.insertMoveWhenActivated()) {
+                assert interval.isSplitChild();
+                assert interval.currentSplitChild() != null;
+                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+                }
+
+                insertMove(interval.from(), interval.currentSplitChild(), interval);
+            }
+            interval.makeCurrentSplitChild();
+
+        }
+
+        return result; // true = interval is moved to active list
+    }
+
+    void finishAllocation() {
+        // must be called when all intervals are allocated
+        moveResolver.resolveAndAppendMoves();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java
new file mode 100644
index 0000000..ce8eb60
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.alloc.trace.lsra;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ */
+final class TraceLocalMoveResolver {
+
+    private static final DebugCounter cycleBreakingSlotsAllocated = Debug.counter("TraceRA[cycleBreakingSlotsAllocated(local)]");
+
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private final TraceLinearScan allocator;
+
+    private int insertIdx;
+    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
+
+    private final List<TraceInterval> mappingFrom;
+    private final List<Constant> mappingFromOpr;
+    private final List<TraceInterval> mappingTo;
+    private final int[] registerBlocked;
+
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+
+    private int getStackArrayIndex(Value stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw GraalError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+    protected void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            assert direction == 1 || direction == -1 : "out of bounds";
+            if (isRegister(location)) {
+                registerBlocked[asRegister(location).number] += direction;
+            } else {
+                throw GraalError.shouldNotReachHere("unhandled value " + location);
+            }
+        }
+    }
+
+    protected TraceInterval getMappingFrom(int i) {
+        return mappingFrom.get(i);
+    }
+
+    protected int mappingFromSize() {
+        return mappingFrom.size();
+    }
+
+    protected int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        if (isRegister(location)) {
+            return registerBlocked[asRegister(location).number];
+        }
+        throw GraalError.shouldNotReachHere("unhandled value " + location);
+    }
+
+    /*
+     * TODO (je) remove?
+     */
+    protected static boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    boolean hasMappings() {
+        return mappingFrom.size() > 0;
+    }
+
+    protected TraceLinearScan getAllocator() {
+        return allocator;
+    }
+
+    protected TraceLocalMoveResolver(TraceLinearScan allocator) {
+
+        this.allocator = allocator;
+        this.mappingFrom = new ArrayList<>(8);
+        this.mappingFromOpr = new ArrayList<>(8);
+        this.mappingTo = new ArrayList<>(8);
+        this.insertIdx = -1;
+        this.insertionBuffer = new LIRInsertionBuffer();
+        this.registerBlocked = new int[allocator.getRegisters().size()];
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    protected boolean checkEmpty() {
+        assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        for (int i = 0; i < getAllocator().getRegisters().size(); i++) {
+            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
+        }
+        checkMultipleReads();
+        return true;
+    }
+
+    protected void checkMultipleReads() {
+        // multiple reads are allowed in SSA LSRA
+    }
+
+    private boolean verifyBeforeResolve() {
+        assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal";
+        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
+        assert insertIdx != -1 : "insert position not set";
+
+        int i;
+        int j;
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                for (j = i + 1; j < mappingFrom.size(); j++) {
+                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
+                }
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            for (j = i + 1; j < mappingTo.size(); j++) {
+                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
+            }
+        }
+
+        HashSet<Value> usedRegs = new HashSet<>();
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                TraceInterval interval = mappingFrom.get(i);
+                if (interval != null && !isIllegal(interval.location())) {
+                    boolean unique = usedRegs.add(interval.location());
+                    assert unique : "cannot read from same register twice";
+                }
+            }
+        }
+
+        usedRegs.clear();
+        for (i = 0; i < mappingTo.size(); i++) {
+            TraceInterval interval = mappingTo.get(i);
+            if (isIllegal(interval.location())) {
+                // After insertion the location may become illegal, so don't check it since multiple
+                // intervals might be illegal.
+                continue;
+            }
+            boolean unique = usedRegs.add(interval.location());
+            assert unique : "cannot write to same register twice";
+        }
+
+        verifyStackSlotMapping();
+
+        return true;
+    }
+
+    protected void verifyStackSlotMapping() {
+        // relax disjoint stack maps invariant
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as blocked
+    private void blockRegisters(TraceInterval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
+            int direction = 1;
+            setValueBlocked(location, direction);
+            Debug.log("block %s", location);
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as unblocked
+    private void unblockRegisters(TraceInterval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
+            setValueBlocked(location, -1);
+            Debug.log("unblock %s", location);
+        }
+    }
+
+    /**
+     * Checks if the {@linkplain TraceInterval#location() location} of {@code to} is not blocked or
+     * is only blocked by {@code from}.
+     */
+    private boolean safeToProcessMove(TraceInterval from, TraceInterval to) {
+        Value fromReg = from != null ? from.location() : null;
+
+        Value location = to.location();
+        if (mightBeBlocked(location)) {
+            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    protected static boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
+    protected static boolean mightBeBlocked(Value location) {
+        if (isRegister(location)) {
+            return true;
+        }
+        if (isStackSlotValue(location)) {
+            return true;
+        }
+        return false;
+    }
+
+    private void createInsertionBuffer(List<LIRInstruction> list) {
+        assert !insertionBuffer.initialized() : "overwriting existing buffer";
+        insertionBuffer.init(list);
+    }
+
+    private void appendInsertionBuffer() {
+        if (insertionBuffer.initialized()) {
+            insertionBuffer.finish();
+        }
+        assert !insertionBuffer.initialized() : "must be uninitialized now";
+
+        insertIdx = -1;
+    }
+
+    private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
+        assert insertIdx != -1 : "must setup insert position first";
+
+        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
+        }
+    }
+
+    /**
+     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
+     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
+     * @param fromLocation {@link TraceInterval#location() location} of the {@code to} interval
+     * @param toLocation {@link TraceInterval#location() location} of the {@code to} interval
+     */
+    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
+        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
+            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
+        }
+        return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
+    }
+
+    private void insertMove(Constant fromOpr, TraceInterval toInterval) {
+        assert insertIdx != -1 : "must setup insert position first";
+
+        AllocatableValue toOpr = toInterval.operand;
+        LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
+        insertionBuffer.append(insertIdx, move);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void resolveMappings() {
+        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
+            assert verifyBeforeResolve();
+            if (Debug.isLogEnabled()) {
+                printMapping();
+            }
+
+            // Block all registers that are used as input operands of a move.
+            // When a register is blocked, no move to this register is emitted.
+            // This is necessary for detecting cycles in moves.
+            int i;
+            for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                TraceInterval fromInterval = mappingFrom.get(i);
+                if (fromInterval != null) {
+                    blockRegisters(fromInterval);
+                }
+            }
+
+            ArrayList<AllocatableValue> busySpillSlots = null;
+            while (mappingFrom.size() > 0) {
+                boolean processedInterval = false;
+
+                int spillCandidate = -1;
+                for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                    TraceInterval fromInterval = mappingFrom.get(i);
+                    TraceInterval toInterval = mappingTo.get(i);
+
+                    if (safeToProcessMove(fromInterval, toInterval)) {
+                        // this interval can be processed because target is free
+                        if (fromInterval != null) {
+                            insertMove(fromInterval, toInterval);
+                            unblockRegisters(fromInterval);
+                        } else {
+                            insertMove(mappingFromOpr.get(i), toInterval);
+                        }
+                        if (isStackSlotValue(toInterval.location())) {
+                            if (busySpillSlots == null) {
+                                busySpillSlots = new ArrayList<>(2);
+                            }
+                            busySpillSlots.add(toInterval.location());
+                        }
+                        mappingFrom.remove(i);
+                        mappingFromOpr.remove(i);
+                        mappingTo.remove(i);
+
+                        processedInterval = true;
+                    } else if (fromInterval != null && isRegister(fromInterval.location()) && (busySpillSlots == null || !busySpillSlots.contains(fromInterval.spillSlot()))) {
+                        // this interval cannot be processed now because target is not free
+                        // it starts in a register, so it is a possible candidate for spilling
+                        spillCandidate = i;
+                    }
+                }
+
+                if (!processedInterval) {
+                    breakCycle(spillCandidate);
+                }
+            }
+        }
+
+        // check that all intervals have been processed
+        assert checkEmpty();
+    }
+
+    protected void breakCycle(int spillCandidate) {
+        if (spillCandidate != -1) {
+            // no move could be processed because there is a cycle in the move list
+            // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
+            assert spillCandidate != -1 : "no interval in register for spilling found";
+
+            // create a new spill interval and assign a stack slot to it
+            TraceInterval fromInterval1 = mappingFrom.get(spillCandidate);
+            // do not allocate a new spill slot for temporary interval, but
+            // use spill slot assigned to fromInterval. Otherwise moves from
+            // one stack slot to another can happen (not allowed by LIRAssembler
+            AllocatableValue spillSlot1 = fromInterval1.spillSlot();
+            if (spillSlot1 == null) {
+                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
+                fromInterval1.setSpillSlot(spillSlot1);
+                cycleBreakingSlotsAllocated.increment();
+            }
+            spillInterval(spillCandidate, fromInterval1, spillSlot1);
+            return;
+        }
+        assert mappingFromSize() > 1;
+        // Arbitrarily select the first entry for spilling.
+        int stackSpillCandidate = 0;
+        TraceInterval fromInterval = getMappingFrom(stackSpillCandidate);
+        // allocate new stack slot
+        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
+    }
+
+    protected void spillInterval(int spillCandidate, TraceInterval fromInterval, AllocatableValue spillSlot) {
+        assert mappingFrom.get(spillCandidate).equals(fromInterval);
+        TraceInterval spillInterval = getAllocator().createDerivedInterval(fromInterval);
+
+        // add a dummy range because real position is difficult to calculate
+        // Note: this range is a special case when the integrity of the allocation is
+        // checked
+        spillInterval.addRange(1, 2);
+
+        spillInterval.assignLocation(spillSlot);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("created new Interval for spilling: %s", spillInterval);
+        }
+        blockRegisters(spillInterval);
+
+        // insert a move from register to stack and update the mapping
+        insertMove(fromInterval, spillInterval);
+        mappingFrom.set(spillCandidate, spillInterval);
+        unblockRegisters(fromInterval);
+    }
+
+    @SuppressWarnings("try")
+    private void printMapping() {
+        try (Indent indent = Debug.logAndIndent("Mapping")) {
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                TraceInterval fromInterval = mappingFrom.get(i);
+                TraceInterval toInterval = mappingTo.get(i);
+                String from;
+                Value to = toInterval.location();
+                if (fromInterval == null) {
+                    from = mappingFromOpr.get(i).toString();
+                } else {
+                    from = fromInterval.location().toString();
+                }
+                Debug.log("move %s <- %s", from, to);
+            }
+        }
+    }
+
+    void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
+        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
+
+        createInsertionBuffer(insertList);
+        this.insertIdx = insertIdx;
+    }
+
+    void moveInsertPosition(List<LIRInstruction> newInsertList, int newInsertIdx) {
+        if (insertionBuffer.lirList() != null && (insertionBuffer.lirList() != newInsertList || this.insertIdx != newInsertIdx)) {
+            // insert position changed . resolve current mappings
+            resolveMappings();
+        }
+
+        assert insertionBuffer.lirList() != newInsertList || newInsertIdx >= insertIdx : String.format("Decreasing insert index: old=%d new=%d", insertIdx, newInsertIdx);
+
+        if (insertionBuffer.lirList() != newInsertList) {
+            // block changed . append insertionBuffer because it is
+            // bound to a specific block and create a new insertionBuffer
+            appendInsertionBuffer();
+            createInsertionBuffer(newInsertList);
+        }
+
+        this.insertIdx = newInsertIdx;
+    }
+
+    public void addMapping(TraceInterval fromInterval, TraceInterval toInterval) {
+
+        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("no store to rematerializable interval %s needed", toInterval);
+            }
+            return;
+        }
+        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
+            // Instead of a reload, re-materialize the value
+            JavaConstant rematValue = fromInterval.getMaterializedValue();
+            addMapping(rematValue, toInterval);
+            return;
+        }
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
+        }
+
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
+                        toInterval);
+        mappingFrom.add(fromInterval);
+        mappingFromOpr.add(null);
+        mappingTo.add(toInterval);
+    }
+
+    public void addMapping(Constant fromOpr, TraceInterval toInterval) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+        }
+
+        mappingFrom.add(null);
+        mappingFromOpr.add(fromOpr);
+        mappingTo.add(toInterval);
+    }
+
+    void resolveAndAppendMoves() {
+        if (hasMappings()) {
+            resolveMappings();
+        }
+        appendInsertionBuffer();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/ArrayDataPointerConstant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/ArrayDataPointerConstant.java
new file mode 100644
index 0000000..82cd713
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/ArrayDataPointerConstant.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.asm;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+
+/**
+ * Class for chunks of data that go into the data section.
+ */
+public class ArrayDataPointerConstant extends DataPointerConstant {
+
+    private final byte[] data;
+
+    public ArrayDataPointerConstant(byte[] array, int alignment) {
+        super(alignment);
+        data = array.clone();
+    }
+
+    public ArrayDataPointerConstant(short[] array, int alignment) {
+        super(alignment);
+        ByteBuffer byteBuffer = ByteBuffer.allocate(array.length * 2);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.asShortBuffer().put(array);
+        data = byteBuffer.array();
+    }
+
+    public ArrayDataPointerConstant(int[] array, int alignment) {
+        super(alignment);
+        ByteBuffer byteBuffer = ByteBuffer.allocate(array.length * 4);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.asIntBuffer().put(array);
+        data = byteBuffer.array();
+    }
+
+    public ArrayDataPointerConstant(float[] array, int alignment) {
+        super(alignment);
+        ByteBuffer byteBuffer = ByteBuffer.allocate(array.length * 4);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.asFloatBuffer().put(array);
+        data = byteBuffer.array();
+    }
+
+    public ArrayDataPointerConstant(double[] array, int alignment) {
+        super(alignment);
+        ByteBuffer byteBuffer = ByteBuffer.allocate(array.length * 8);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.asDoubleBuffer().put(array);
+        data = byteBuffer.array();
+    }
+
+    public ArrayDataPointerConstant(long[] array, int alignment) {
+        super(alignment);
+        ByteBuffer byteBuffer = ByteBuffer.allocate(array.length * 8);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.asLongBuffer().put(array);
+        data = byteBuffer.array();
+    }
+
+    @Override
+    public boolean isDefaultForKind() {
+        return false;
+    }
+
+    @Override
+    public void serialize(ByteBuffer buffer) {
+        buffer.put(data);
+    }
+
+    @Override
+    public int getSerializedSize() {
+        return data.length;
+    }
+
+    @Override
+    public String toValueString() {
+        return "ArrayDataPointerConstant" + Arrays.toString(data);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java
new file mode 100644
index 0000000..6601762
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.asm;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.graalvm.compiler.asm.AbstractAddress;
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.code.DataSection.RawData;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataSectionReference;
+import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.VMConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Fills in a {@link CompilationResult} as its code is being assembled.
+ *
+ * @see CompilationResultBuilderFactory
+ */
+public class CompilationResultBuilder {
+
+    // @formatter:off
+    @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintLIRWithAssembly = new OptionValue<>(false);
+    // @formatter:on
+
+    private static class ExceptionInfo {
+
+        public final int codeOffset;
+        public final LabelRef exceptionEdge;
+
+        ExceptionInfo(int pcOffset, LabelRef exceptionEdge) {
+            this.codeOffset = pcOffset;
+            this.exceptionEdge = exceptionEdge;
+        }
+    }
+
+    /**
+     * Wrapper for a code annotation that was produced by the {@link Assembler}.
+     */
+    public static final class AssemblerAnnotation extends CodeAnnotation {
+
+        public final Assembler.CodeAnnotation assemblerCodeAnnotation;
+
+        public AssemblerAnnotation(Assembler.CodeAnnotation assemblerCodeAnnotation) {
+            super(assemblerCodeAnnotation.instructionPosition);
+            this.assemblerCodeAnnotation = assemblerCodeAnnotation;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+
+        @Override
+        public String toString() {
+            return assemblerCodeAnnotation.toString();
+        }
+    }
+
+    public final Assembler asm;
+    public final DataBuilder dataBuilder;
+    public final CompilationResult compilationResult;
+    public final TargetDescription target;
+    public final CodeCacheProvider codeCache;
+    public final ForeignCallsProvider foreignCalls;
+    public final FrameMap frameMap;
+
+    /**
+     * The LIR for which code is being generated.
+     */
+    private LIR lir;
+
+    /**
+     * The index of the block currently being emitted.
+     */
+    private int currentBlockIndex;
+
+    /**
+     * The object that emits code for managing a method's frame.
+     */
+    public final FrameContext frameContext;
+
+    private List<ExceptionInfo> exceptionInfoList;
+
+    private final Map<Constant, Data> dataCache;
+
+    private Consumer<LIRInstruction> beforeOp;
+    private Consumer<LIRInstruction> afterOp;
+
+    public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, FrameContext frameContext,
+                    CompilationResult compilationResult) {
+        // constants are already GVNed in the high level graph, so we can use an IdentityHashMap
+        this(codeCache, foreignCalls, frameMap, asm, dataBuilder, frameContext, compilationResult, new IdentityHashMap<>());
+    }
+
+    public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, FrameContext frameContext,
+                    CompilationResult compilationResult, Map<Constant, Data> dataCache) {
+        this.target = codeCache.getTarget();
+        this.codeCache = codeCache;
+        this.foreignCalls = foreignCalls;
+        this.frameMap = frameMap;
+        this.asm = asm;
+        this.dataBuilder = dataBuilder;
+        this.compilationResult = compilationResult;
+        this.frameContext = frameContext;
+        assert frameContext != null;
+        this.dataCache = dataCache;
+
+        boolean assertionsEnabled = false;
+        assert (assertionsEnabled = true) == true;
+        if (dataBuilder.needDetailedPatchingInformation() || assertionsEnabled) {
+            /*
+             * Always enabled in debug mode, even when the VM does not request detailed information,
+             * to increase test coverage.
+             */
+            asm.setCodePatchingAnnotationConsumer(assemblerCodeAnnotation -> compilationResult.addAnnotation(new AssemblerAnnotation(assemblerCodeAnnotation)));
+        }
+    }
+
+    public void setTotalFrameSize(int frameSize) {
+        compilationResult.setTotalFrameSize(frameSize);
+    }
+
+    public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) {
+        compilationResult.setMaxInterpreterFrameSize(maxInterpreterFrameSize);
+    }
+
+    public Mark recordMark(Object id) {
+        return compilationResult.recordMark(asm.position(), id);
+    }
+
+    public void blockComment(String s) {
+        compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.position(), s));
+    }
+
+    /**
+     * Sets the {@linkplain CompilationResult#setTargetCode(byte[], int) code} and
+     * {@linkplain CompilationResult#recordExceptionHandler(int, int) exception handler} fields of
+     * the compilation result and then {@linkplain #closeCompilationResult() closes} it.
+     */
+    public void finish() {
+        int position = asm.position();
+        compilationResult.setTargetCode(asm.close(false), position);
+
+        // Record exception handlers if they exist
+        if (exceptionInfoList != null) {
+            for (ExceptionInfo ei : exceptionInfoList) {
+                int codeOffset = ei.codeOffset;
+                compilationResult.recordExceptionHandler(codeOffset, ei.exceptionEdge.label().position());
+            }
+        }
+        closeCompilationResult();
+    }
+
+    /**
+     * Calls {@link CompilationResult#close()} on {@link #compilationResult}.
+     */
+    protected void closeCompilationResult() {
+        compilationResult.close();
+    }
+
+    public void recordExceptionHandlers(int pcOffset, LIRFrameState info) {
+        if (info != null) {
+            if (info.exceptionEdge != null) {
+                if (exceptionInfoList == null) {
+                    exceptionInfoList = new ArrayList<>(4);
+                }
+                exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge));
+            }
+        }
+    }
+
+    public void recordImplicitException(int pcOffset, LIRFrameState info) {
+        compilationResult.recordInfopoint(pcOffset, info.debugInfo(), InfopointReason.IMPLICIT_EXCEPTION);
+        assert info.exceptionEdge == null;
+    }
+
+    public void recordDirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) {
+        DebugInfo debugInfo = info != null ? info.debugInfo() : null;
+        compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true);
+    }
+
+    public void recordIndirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) {
+        DebugInfo debugInfo = info != null ? info.debugInfo() : null;
+        compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false);
+    }
+
+    public void recordInfopoint(int pos, LIRFrameState info, InfopointReason reason) {
+        // infopoints always need debug info
+        DebugInfo debugInfo = info.debugInfo();
+        recordInfopoint(pos, debugInfo, reason);
+    }
+
+    public void recordInfopoint(int pos, DebugInfo debugInfo, InfopointReason reason) {
+        compilationResult.recordInfopoint(pos, debugInfo, reason);
+    }
+
+    public void recordSourceMapping(int pcOffset, int endPcOffset, NodeSourcePosition sourcePosition) {
+        compilationResult.recordSourceMapping(pcOffset, endPcOffset, sourcePosition);
+    }
+
+    public void recordInlineDataInCode(Constant data) {
+        assert data != null;
+        int pos = asm.position();
+        Debug.log("Inline data in code: pos = %d, data = %s", pos, data);
+        if (data instanceof VMConstant) {
+            compilationResult.recordDataPatch(pos, new ConstantReference((VMConstant) data));
+        }
+    }
+
+    public void recordInlineDataInCodeWithNote(Constant data, Object note) {
+        assert data != null;
+        int pos = asm.position();
+        Debug.log("Inline data in code: pos = %d, data = %s, note = %s", pos, data, note);
+        if (data instanceof VMConstant) {
+            compilationResult.recordDataPatchWithNote(pos, new ConstantReference((VMConstant) data), note);
+        }
+    }
+
+    public AbstractAddress recordDataSectionReference(Data data) {
+        assert data != null;
+        DataSectionReference reference = compilationResult.getDataSection().insertData(data);
+        int instructionStart = asm.position();
+        compilationResult.recordDataPatch(instructionStart, reference);
+        return asm.getPlaceholder(instructionStart);
+    }
+
+    public AbstractAddress recordDataReferenceInCode(DataPointerConstant constant) {
+        return recordDataReferenceInCode(constant, constant.getAlignment());
+    }
+
+    public AbstractAddress recordDataReferenceInCode(Constant constant, int alignment) {
+        assert constant != null;
+        Debug.log("Constant reference in code: pos = %d, data = %s", asm.position(), constant);
+        Data data = dataCache.get(constant);
+        if (data == null) {
+            data = dataBuilder.createDataItem(constant);
+            dataCache.put(constant, data);
+        }
+        data.updateAlignment(alignment);
+        return recordDataSectionReference(data);
+    }
+
+    public AbstractAddress recordDataReferenceInCode(byte[] data, int alignment) {
+        assert data != null;
+        if (Debug.isLogEnabled()) {
+            Debug.log("Data reference in code: pos = %d, data = %s", asm.position(), Arrays.toString(data));
+        }
+        return recordDataSectionReference(new RawData(data, alignment));
+    }
+
+    /**
+     * Returns the integer value of any constant that can be represented by a 32-bit integer value,
+     * including long constants that fit into the 32-bit range.
+     */
+    public int asIntConst(Value value) {
+        assert isJavaConstant(value) && asJavaConstant(value).getJavaKind().isNumericInteger();
+        JavaConstant constant = asJavaConstant(value);
+        long c = constant.asLong();
+        if (!NumUtil.isInt(c)) {
+            throw GraalError.shouldNotReachHere();
+        }
+        return (int) c;
+    }
+
+    /**
+     * Returns the float value of any constant that can be represented by a 32-bit float value.
+     */
+    public float asFloatConst(Value value) {
+        assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Float;
+        JavaConstant constant = asJavaConstant(value);
+        return constant.asFloat();
+    }
+
+    /**
+     * Returns the long value of any constant that can be represented by a 64-bit long value.
+     */
+    public long asLongConst(Value value) {
+        assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Long;
+        JavaConstant constant = asJavaConstant(value);
+        return constant.asLong();
+    }
+
+    /**
+     * Returns the double value of any constant that can be represented by a 64-bit float value.
+     */
+    public double asDoubleConst(Value value) {
+        assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Double;
+        JavaConstant constant = asJavaConstant(value);
+        return constant.asDouble();
+    }
+
+    /**
+     * Returns the address of a float constant that is embedded as a data reference into the code.
+     */
+    public AbstractAddress asFloatConstRef(JavaConstant value) {
+        return asFloatConstRef(value, 4);
+    }
+
+    public AbstractAddress asFloatConstRef(JavaConstant value, int alignment) {
+        assert value.getJavaKind() == JavaKind.Float;
+        return recordDataReferenceInCode(value, alignment);
+    }
+
+    /**
+     * Returns the address of a double constant that is embedded as a data reference into the code.
+     */
+    public AbstractAddress asDoubleConstRef(JavaConstant value) {
+        return asDoubleConstRef(value, 8);
+    }
+
+    public AbstractAddress asDoubleConstRef(JavaConstant value, int alignment) {
+        assert value.getJavaKind() == JavaKind.Double;
+        return recordDataReferenceInCode(value, alignment);
+    }
+
+    /**
+     * Returns the address of a long constant that is embedded as a data reference into the code.
+     */
+    public AbstractAddress asLongConstRef(JavaConstant value) {
+        assert value.getJavaKind() == JavaKind.Long;
+        return recordDataReferenceInCode(value, 8);
+    }
+
+    /**
+     * Returns the address of an object constant that is embedded as a data reference into the code.
+     */
+    public AbstractAddress asObjectConstRef(JavaConstant value) {
+        assert value.getJavaKind() == JavaKind.Object;
+        return recordDataReferenceInCode(value, 8);
+    }
+
+    public AbstractAddress asByteAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Byte.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asShortAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Short.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asIntAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Int.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asLongAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Long.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asFloatAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Float.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asDoubleAddr(Value value) {
+        assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Double.getByteCount();
+        return asAddress(value);
+    }
+
+    public AbstractAddress asAddress(Value value) {
+        assert isStackSlot(value);
+        StackSlot slot = asStackSlot(value);
+        return asm.makeAddress(frameMap.getRegisterConfig().getFrameRegister(), frameMap.offsetForStackSlot(slot));
+    }
+
+    /**
+     * Determines if a given edge from the block currently being emitted goes to its lexical
+     * successor.
+     */
+    public boolean isSuccessorEdge(LabelRef edge) {
+        assert lir != null;
+        AbstractBlockBase<?>[] order = lir.codeEmittingOrder();
+        assert order[currentBlockIndex] == edge.getSourceBlock();
+        AbstractBlockBase<?> nextBlock = LIR.getNextBlock(order, currentBlockIndex);
+        return nextBlock == edge.getTargetBlock();
+    }
+
+    /**
+     * Emits code for {@code lir} in its {@linkplain LIR#codeEmittingOrder() code emitting order}.
+     */
+    public void emit(@SuppressWarnings("hiding") LIR lir) {
+        assert this.lir == null;
+        assert currentBlockIndex == 0;
+        this.lir = lir;
+        this.currentBlockIndex = 0;
+        frameContext.enter(this);
+        for (AbstractBlockBase<?> b : lir.codeEmittingOrder()) {
+            assert (b == null && lir.codeEmittingOrder()[currentBlockIndex] == null) || lir.codeEmittingOrder()[currentBlockIndex].equals(b);
+            emitBlock(b);
+            currentBlockIndex++;
+        }
+        this.lir = null;
+        this.currentBlockIndex = 0;
+    }
+
+    private void emitBlock(AbstractBlockBase<?> block) {
+        if (block == null) {
+            return;
+        }
+        if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL) || PrintLIRWithAssembly.getValue()) {
+            blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
+        }
+
+        for (LIRInstruction op : lir.getLIRforBlock(block)) {
+            if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL) || PrintLIRWithAssembly.getValue()) {
+                blockComment(String.format("%d %s", op.id(), op));
+            }
+
+            try {
+                if (beforeOp != null) {
+                    beforeOp.accept(op);
+                }
+                emitOp(this, op);
+                if (afterOp != null) {
+                    afterOp.accept(op);
+                }
+            } catch (GraalError e) {
+                throw e.addContext("lir instruction", block + "@" + op.id() + " " + op + "\n" + Arrays.toString(lir.codeEmittingOrder()));
+            }
+        }
+    }
+
+    private static void emitOp(CompilationResultBuilder crb, LIRInstruction op) {
+        try {
+            int start = crb.asm.position();
+            op.emitCode(crb);
+            if (op.getPosition() != null) {
+                crb.recordSourceMapping(start, crb.asm.position(), op.getPosition());
+            }
+        } catch (AssertionError t) {
+            throw new GraalError(t);
+        } catch (RuntimeException t) {
+            throw new GraalError(t);
+        }
+    }
+
+    public void resetForEmittingCode() {
+        asm.reset();
+        compilationResult.resetForEmittingCode();
+        if (exceptionInfoList != null) {
+            exceptionInfoList.clear();
+        }
+        if (dataCache != null) {
+            dataCache.clear();
+        }
+    }
+
+    public void setOpCallback(Consumer<LIRInstruction> beforeOp, Consumer<LIRInstruction> afterOp) {
+        this.beforeOp = beforeOp;
+        this.afterOp = afterOp;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilderFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilderFactory.java
new file mode 100644
index 0000000..13d3180
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilderFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.asm;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+
+/**
+ * Factory class for creating {@link CompilationResultBuilder}s.
+ */
+public interface CompilationResultBuilderFactory {
+
+    /**
+     * Creates a new {@link CompilationResultBuilder}.
+     */
+    CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, FrameContext frameContext,
+                    CompilationResult compilationResult);
+
+    /**
+     * The default factory creates a standard {@link CompilationResultBuilder}.
+     */
+    CompilationResultBuilderFactory Default = new CompilationResultBuilderFactory() {
+
+        @Override
+        public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder,
+                        FrameContext frameContext, CompilationResult compilationResult) {
+            return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, dataBuilder, frameContext, compilationResult);
+        }
+    };
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/DataBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/DataBuilder.java
new file mode 100644
index 0000000..98e1eb4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/DataBuilder.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.asm;
+
+import org.graalvm.compiler.code.DataSection.Data;
+
+import jdk.vm.ci.meta.Constant;
+
+public abstract class DataBuilder {
+
+    /**
+     * When the method returns true, then Graal must produce detailed information that allows code
+     * patching without decoding instructions, i.e., Graal must produce annotations for the machine
+     * code that describe the exact locations of operands within instructions.
+     */
+    public abstract boolean needDetailedPatchingInformation();
+
+    public abstract Data createDataItem(Constant c);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java
new file mode 100644
index 0000000..3285390
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.asm;
+
+/**
+ * Code for managing a method's native frame.
+ */
+public interface FrameContext {
+
+    /**
+     * Emits code common to all entry points of a method. This may include:
+     * <ul>
+     * <li>setting up the stack frame</li>
+     * <li>saving callee-saved registers</li>
+     * <li>stack overflow checking</li>
+     * </ul>
+     */
+    void enter(CompilationResultBuilder crb);
+
+    /**
+     * Emits code to be executed just prior to returning from a method. This may include:
+     * <ul>
+     * <li>restoring callee-saved registers</li>
+     * <li>performing a safepoint</li>
+     * <li>destroying the stack frame</li>
+     * </ul>
+     */
+    void leave(CompilationResultBuilder crb);
+
+    /**
+     * Determines if a frame is set up and torn down by this object.
+     */
+    boolean hasFrame();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java
new file mode 100644
index 0000000..0b9b940
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.constopt.ConstantTree.Flags;
+import org.graalvm.compiler.lir.constopt.ConstantTree.NodeCost;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * This optimization tries to improve the handling of constants by replacing a single definition of
+ * a constant, which is potentially scheduled into a block with high probability, with one or more
+ * definitions in blocks with a lower probability.
+ */
+public final class ConstantLoadOptimization extends PreAllocationOptimizationPhase {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable constant load optimization.", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptConstantLoadOptimization = new NestedBooleanOptionValue(LIROptimization, true);
+        // @formatter:on
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
+        LIRGeneratorTool lirGen = context.lirGen;
+        new Optimization(lirGenRes.getLIR(), lirGen).apply();
+    }
+
+    private static final DebugCounter constantsTotal = Debug.counter("ConstantLoadOptimization[total]");
+    private static final DebugCounter phiConstantsSkipped = Debug.counter("ConstantLoadOptimization[PhisSkipped]");
+    private static final DebugCounter singleUsageConstantsSkipped = Debug.counter("ConstantLoadOptimization[SingleUsageSkipped]");
+    private static final DebugCounter usageAtDefinitionSkipped = Debug.counter("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
+    private static final DebugCounter materializeAtDefinitionSkipped = Debug.counter("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
+    private static final DebugCounter constantsOptimized = Debug.counter("ConstantLoadOptimization[optimized]");
+
+    private static final class Optimization {
+        private final LIR lir;
+        private final LIRGeneratorTool lirGen;
+        private final VariableMap<DefUseTree> map;
+        private final BitSet phiConstants;
+        private final BitSet defined;
+        private final BlockMap<List<UseEntry>> blockMap;
+        private final BlockMap<LIRInsertionBuffer> insertionBuffers;
+
+        private Optimization(LIR lir, LIRGeneratorTool lirGen) {
+            this.lir = lir;
+            this.lirGen = lirGen;
+            this.map = new VariableMap<>();
+            this.phiConstants = new BitSet();
+            this.defined = new BitSet();
+            this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
+            this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
+        }
+
+        @SuppressWarnings("try")
+        private void apply() {
+            try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
+                try (Scope s = Debug.scope("BuildDefUseTree")) {
+                    // build DefUseTree
+                    for (AbstractBlockBase<?> b : lir.getControlFlowGraph().getBlocks()) {
+                        this.analyzeBlock(b);
+                    }
+                    // remove all with only one use
+                    map.filter(t -> {
+                        if (t.usageCount() > 1) {
+                            return true;
+                        } else {
+                            singleUsageConstantsSkipped.increment();
+                            return false;
+                        }
+                    });
+                    // collect block map
+                    map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+
+                try (Scope s = Debug.scope("BuildConstantTree")) {
+                    // create ConstantTree
+                    map.forEach(this::createConstantTree);
+
+                    // insert moves, delete null instructions and reset instruction ids
+                    for (AbstractBlockBase<?> b : lir.getControlFlowGraph().getBlocks()) {
+                        this.rewriteBlock(b);
+                    }
+
+                    assert verifyStates();
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+        }
+
+        private boolean verifyStates() {
+            map.forEach(this::verifyStateUsage);
+            return true;
+        }
+
+        private void verifyStateUsage(DefUseTree tree) {
+            Variable var = tree.getVariable();
+            ValueConsumer stateConsumer = new ValueConsumer() {
+
+                @Override
+                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    assert !operand.equals(var) : "constant usage through variable in frame state " + var;
+                }
+            };
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.visitEachState(stateConsumer);
+                }
+            }
+        }
+
+        private static boolean isConstantLoad(LIRInstruction inst) {
+            if (!(inst instanceof LoadConstantOp)) {
+                return false;
+            }
+            LoadConstantOp load = (LoadConstantOp) inst;
+            return isVariable(load.getResult());
+        }
+
+        private void addUsageToBlockMap(UseEntry entry) {
+            AbstractBlockBase<?> block = entry.getBlock();
+            List<UseEntry> list = blockMap.get(block);
+            if (list == null) {
+                list = new ArrayList<>();
+                blockMap.put(block, list);
+            }
+            list.add(entry);
+        }
+
+        /**
+         * Collects def-use information for a {@code block}.
+         */
+        @SuppressWarnings("try")
+        private void analyzeBlock(AbstractBlockBase<?> block) {
+            try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
+
+                InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+
+                        if (!phiConstants.get(var.index)) {
+                            if (!defined.get(var.index)) {
+                                defined.set(var.index);
+                                if (isConstantLoad(instruction)) {
+                                    Debug.log("constant load: %s", instruction);
+                                    map.put(var, new DefUseTree(instruction, block));
+                                    constantsTotal.increment();
+                                }
+                            } else {
+                                // Variable is redefined, this only happens for constant loads
+                                // introduced by phi resolution -> ignore.
+                                DefUseTree removed = map.remove(var);
+                                if (removed != null) {
+                                    phiConstantsSkipped.increment();
+                                }
+                                phiConstants.set(var.index);
+                                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Removing phi variable: %s", var);
+                            }
+                        } else {
+                            assert defined.get(var.index) : "phi but not defined? " + var;
+                        }
+                    }
+                };
+
+                InstructionValueConsumer useConsumer = (instruction, value, mode, flags) -> {
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+                        if (!phiConstants.get(var.index)) {
+                            DefUseTree tree = map.get(var);
+                            if (tree != null) {
+                                tree.addUsage(block, instruction, value);
+                                Debug.log("usage of %s : %s", var, instruction);
+                            }
+                        }
+                    }
+                };
+
+                int opId = 0;
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.setId(opId++);
+                    inst.visitEachOutput(loadConsumer);
+                    inst.visitEachInput(useConsumer);
+                    inst.visitEachAlive(useConsumer);
+
+                }
+            }
+        }
+
+        /**
+         * Creates the dominator tree and searches for an solution.
+         */
+        @SuppressWarnings("try")
+        private void createConstantTree(DefUseTree tree) {
+            ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
+            constTree.set(Flags.SUBTREE, tree.getBlock());
+            tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
+
+            if (constTree.get(Flags.USAGE, tree.getBlock())) {
+                // usage in the definition block -> no optimization
+                usageAtDefinitionSkipped.increment();
+                return;
+            }
+
+            constTree.markBlocks();
+
+            NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
+            int usageCount = cost.getUsages().size();
+            assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
+
+            if (Debug.isLogEnabled()) {
+                try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
+                    Debug.log("Usages result: %s", cost);
+                }
+
+            }
+
+            if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
+                try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
+                    // mark original load for removal
+                    deleteInstruction(tree);
+                    constantsOptimized.increment();
+
+                    // collect result
+                    createLoads(tree, constTree, tree.getBlock());
+
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            } else {
+                // no better solution found
+                materializeAtDefinitionSkipped.increment();
+            }
+            Debug.dump(Debug.INFO_LOG_LEVEL, constTree, "ConstantTree for %s", tree.getVariable());
+        }
+
+        private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase<?> startBlock) {
+            Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
+            worklist.add(startBlock);
+            while (!worklist.isEmpty()) {
+                AbstractBlockBase<?> block = worklist.pollLast();
+                if (constTree.get(Flags.CANDIDATE, block)) {
+                    constTree.set(Flags.MATERIALIZE, block);
+                    // create and insert load
+                    insertLoad(tree.getConstant(), tree.getVariable().getValueKind(), block, constTree.getCost(block).getUsages());
+                } else {
+                    for (AbstractBlockBase<?> dominated : block.getDominated()) {
+                        if (constTree.isMarked(dominated)) {
+                            worklist.addLast(dominated);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void insertLoad(Constant constant, ValueKind<?> kind, AbstractBlockBase<?> block, List<UseEntry> usages) {
+            assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
+            // create variable
+            Variable variable = lirGen.newVariable(kind);
+            // create move
+            LIRInstruction move = lirGen.getSpillMoveFactory().createLoad(variable, constant);
+            // insert instruction
+            getInsertionBuffer(block).append(1, move);
+            Debug.log("new move (%s) and inserted in block %s", move, block);
+            // update usages
+            for (UseEntry u : usages) {
+                u.setValue(variable);
+                Debug.log("patched instruction %s", u.getInstruction());
+            }
+        }
+
+        /**
+         * Inserts the constant loads created in {@link #createConstantTree} and deletes the
+         * original definition.
+         */
+        private void rewriteBlock(AbstractBlockBase<?> block) {
+            // insert moves
+            LIRInsertionBuffer buffer = insertionBuffers.get(block);
+            if (buffer != null) {
+                assert buffer.initialized() : "not initialized?";
+                buffer.finish();
+            }
+
+            // delete instructions
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            boolean hasDead = false;
+            for (LIRInstruction inst : instructions) {
+                if (inst == null) {
+                    hasDead = true;
+                } else {
+                    inst.setId(-1);
+                }
+            }
+            if (hasDead) {
+                // Remove null values from the list.
+                instructions.removeAll(Collections.singleton(null));
+            }
+        }
+
+        private void deleteInstruction(DefUseTree tree) {
+            AbstractBlockBase<?> block = tree.getBlock();
+            LIRInstruction instruction = tree.getInstruction();
+            Debug.log("deleting instruction %s from block %s", instruction, block);
+            lir.getLIRforBlock(block).set(instruction.id(), null);
+        }
+
+        private LIRInsertionBuffer getInsertionBuffer(AbstractBlockBase<?> block) {
+            LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
+            if (insertionBuffer == null) {
+                insertionBuffer = new LIRInsertionBuffer();
+                insertionBuffers.put(block, insertionBuffer);
+                assert !insertionBuffer.initialized() : "already initialized?";
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                insertionBuffer.init(instructions);
+            }
+            return insertionBuffer;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java
new file mode 100644
index 0000000..095d95d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.cfg.PrintableDominatorOptimizationProblem;
+import org.graalvm.compiler.core.common.cfg.PropertyConsumable;
+
+/**
+ * Represents a dominator (sub-)tree for a constant definition.
+ */
+public class ConstantTree extends PrintableDominatorOptimizationProblem<ConstantTree.Flags, ConstantTree.NodeCost> {
+
+    public enum Flags {
+        SUBTREE,
+        USAGE,
+        MATERIALIZE,
+        CANDIDATE,
+    }
+
+    /**
+     * Costs associated with a block.
+     */
+    public static class NodeCost implements PropertyConsumable {
+        private List<UseEntry> usages;
+        private double bestCost;
+        private int numMat;
+
+        public NodeCost(double bestCost, List<UseEntry> usages, int numMat) {
+            this.bestCost = bestCost;
+            this.usages = usages;
+            this.numMat = numMat;
+        }
+
+        @Override
+        public void forEachProperty(BiConsumer<String, String> action) {
+            action.accept("bestCost", Double.toString(getBestCost()));
+            action.accept("numMat", Integer.toString(getNumMaterializations()));
+            action.accept("numUsages", Integer.toString(usages.size()));
+        }
+
+        public void addUsage(UseEntry usage) {
+            if (usages == null) {
+                usages = new ArrayList<>();
+            }
+            usages.add(usage);
+        }
+
+        public List<UseEntry> getUsages() {
+            if (usages == null) {
+                Collections.emptyList();
+            }
+            return usages;
+        }
+
+        public double getBestCost() {
+            return bestCost;
+        }
+
+        public int getNumMaterializations() {
+            return numMat;
+        }
+
+        public void setBestCost(double cost) {
+            bestCost = cost;
+        }
+
+        @Override
+        public String toString() {
+            return "NodeCost [bestCost=" + bestCost + ", numUsages=" + usages.size() + ", numMat=" + numMat + "]";
+        }
+    }
+
+    private final BlockMap<List<UseEntry>> blockMap;
+
+    public ConstantTree(AbstractControlFlowGraph<?> cfg, DefUseTree tree) {
+        super(Flags.class, cfg);
+        this.blockMap = new BlockMap<>(cfg);
+        tree.forEach(u -> getOrInitList(u.getBlock()).add(u));
+    }
+
+    private List<UseEntry> getOrInitList(AbstractBlockBase<?> block) {
+        List<UseEntry> list = blockMap.get(block);
+        if (list == null) {
+            list = new ArrayList<>();
+            blockMap.put(block, list);
+        }
+        return list;
+    }
+
+    public List<UseEntry> getUsages(AbstractBlockBase<?> block) {
+        List<UseEntry> list = blockMap.get(block);
+        if (list == null) {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /**
+     * Returns the cost object associated with {@code block}. If there is none, a new cost object is
+     * created.
+     */
+    NodeCost getOrInitCost(AbstractBlockBase<?> block) {
+        NodeCost cost = getCost(block);
+        if (cost == null) {
+            cost = new NodeCost(block.probability(), blockMap.get(block), 1);
+            setCost(block, cost);
+        }
+        return cost;
+    }
+
+    @Override
+    public String getName(Flags type) {
+        switch (type) {
+            case USAGE:
+                return "hasUsage";
+            case SUBTREE:
+                return "inSubtree";
+            case MATERIALIZE:
+                return "materialize";
+            case CANDIDATE:
+                return "candidate";
+        }
+        return super.getName(type);
+    }
+
+    @Override
+    public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
+        if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) {
+            action.accept("hasDefinition", "true");
+        }
+        super.forEachPropertyPair(block, action);
+    }
+
+    public long subTreeSize() {
+        return stream(Flags.SUBTREE).count();
+    }
+
+    public AbstractBlockBase<?> getStartBlock() {
+        return stream(Flags.SUBTREE).findFirst().get();
+    }
+
+    public void markBlocks() {
+        for (AbstractBlockBase<?> block : getBlocks()) {
+            if (get(Flags.USAGE, block)) {
+                setDominatorPath(Flags.SUBTREE, block);
+            }
+        }
+    }
+
+    public boolean isMarked(AbstractBlockBase<?> block) {
+        return get(Flags.SUBTREE, block);
+    }
+
+    public boolean isLeafBlock(AbstractBlockBase<?> block) {
+        for (AbstractBlockBase<?> dom : block.getDominated()) {
+            if (isMarked(dom)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void setSolution(AbstractBlockBase<?> block) {
+        set(Flags.MATERIALIZE, block);
+    }
+
+    public int size() {
+        return getBlocks().length;
+    }
+
+    public void traverseTreeWhileTrue(AbstractBlockBase<?> block, Predicate<AbstractBlockBase<?>> action) {
+        assert block != null : "block must not be null!";
+        if (action.test(block)) {
+            block.getDominated().stream().filter(this::isMarked).forEach(dominated -> traverseTreeWhileTrue(dominated, action));
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java
new file mode 100644
index 0000000..9629e53
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.constopt.ConstantTree.Flags;
+import org.graalvm.compiler.lir.constopt.ConstantTree.NodeCost;
+
+/**
+ * Analyzes a {@link ConstantTree} and marks potential materialization positions.
+ */
+public final class ConstantTreeAnalyzer {
+    private final ConstantTree tree;
+    private final BitSet visited;
+
+    @SuppressWarnings("try")
+    public static NodeCost analyze(ConstantTree tree, AbstractBlockBase<?> startBlock) {
+        try (Scope s = Debug.scope("ConstantTreeAnalyzer")) {
+            ConstantTreeAnalyzer analyzer = new ConstantTreeAnalyzer(tree);
+            analyzer.analyzeBlocks(startBlock);
+            return tree.getCost(startBlock);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private ConstantTreeAnalyzer(ConstantTree tree) {
+        this.tree = tree;
+        this.visited = new BitSet(tree.size());
+    }
+
+    /**
+     * Queues all relevant blocks for {@linkplain #process processing}.
+     *
+     * This is a worklist-style algorithm because a (more elegant) recursive implementation may
+     * cause {@linkplain StackOverflowError stack overflows} on larger graphs.
+     *
+     * @param startBlock The start block of the dominator subtree.
+     */
+    @SuppressWarnings("try")
+    private void analyzeBlocks(AbstractBlockBase<?> startBlock) {
+        Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
+        worklist.offerLast(startBlock);
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<?> block = worklist.pollLast();
+            try (Indent i = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "analyze: %s", block)) {
+                assert block != null : "worklist is empty!";
+                assert isMarked(block) : "Block not part of the dominator tree: " + block;
+
+                if (isLeafBlock(block)) {
+                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "leaf block");
+                    leafCost(block);
+                    continue;
+                }
+
+                if (!visited.get(block.getId())) {
+                    // if not yet visited (and not a leaf block) process all children first!
+                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "not marked");
+                    worklist.offerLast(block);
+                    List<? extends AbstractBlockBase<?>> children = block.getDominated();
+                    children.forEach(child -> filteredPush(worklist, child));
+                    visited.set(block.getId());
+                } else {
+                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "marked");
+                    // otherwise, process block
+                    process(block);
+                }
+            }
+        }
+    }
+
+    /**
+     * Calculates the cost of a {@code block}. It is assumed that all {@code children} have already
+     * been {@linkplain #process processed}
+     *
+     * @param block The block to be processed.
+     */
+    private void process(AbstractBlockBase<?> block) {
+        List<UseEntry> usages = new ArrayList<>();
+        double bestCost = 0;
+        int numMat = 0;
+        List<? extends AbstractBlockBase<?>> children = block.getDominated();
+        assert children.stream().anyMatch(this::isMarked) : "no children? should have called leafCost(): " + block;
+
+        // collect children costs
+        for (AbstractBlockBase<?> child : children) {
+            if (isMarked(child)) {
+                NodeCost childCost = tree.getCost(child);
+                assert childCost != null : "Child with null cost? block: " + child;
+                usages.addAll(childCost.getUsages());
+                numMat += childCost.getNumMaterializations();
+                bestCost += childCost.getBestCost();
+            }
+        }
+        assert numMat > 0 : "No materialization? " + numMat;
+
+        // choose block
+        List<UseEntry> usagesBlock = tree.getUsages(block);
+        double probabilityBlock = block.probability();
+
+        if (!usagesBlock.isEmpty() || shouldMaterializerInCurrentBlock(probabilityBlock, bestCost, numMat)) {
+            // mark current block as potential materialization position
+            usages.addAll(usagesBlock);
+            bestCost = probabilityBlock;
+            numMat = 1;
+            tree.set(Flags.CANDIDATE, block);
+        } else {
+            // stick with the current solution
+        }
+
+        assert (new HashSet<>(usages)).size() == usages.size() : "doulbe entries? " + usages;
+        NodeCost nodeCost = new NodeCost(bestCost, usages, numMat);
+        tree.setCost(block, nodeCost);
+    }
+
+    /**
+     * This is the cost function that decides whether a materialization should be inserted in the
+     * current block.
+     * <p>
+     * Note that this function does not take into account if a materialization is required despite
+     * the probabilities (e.g. there are usages in the current block).
+     *
+     * @param probabilityBlock Probability of the current block.
+     * @param probabilityChildren Accumulated probability of the children.
+     * @param numMat Number of materializations along the subtrees. We use {@code numMat - 1} to
+     *            insert materializations as late as possible if the probabilities are the same.
+     */
+    private static boolean shouldMaterializerInCurrentBlock(double probabilityBlock, double probabilityChildren, int numMat) {
+        return probabilityBlock * Math.pow(0.9, numMat - 1) < probabilityChildren;
+    }
+
+    private void filteredPush(Deque<AbstractBlockBase<?>> worklist, AbstractBlockBase<?> block) {
+        if (isMarked(block)) {
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "adding %s to the worklist", block);
+            worklist.offerLast(block);
+        }
+    }
+
+    private void leafCost(AbstractBlockBase<?> block) {
+        tree.set(Flags.CANDIDATE, block);
+        tree.getOrInitCost(block);
+    }
+
+    private boolean isMarked(AbstractBlockBase<?> block) {
+        return tree.isMarked(block);
+    }
+
+    private boolean isLeafBlock(AbstractBlockBase<?> block) {
+        return tree.isLeafBlock(block);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java
new file mode 100644
index 0000000..9f60d4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents def-use tree of a constant.
+ */
+class DefUseTree {
+    private final LoadConstantOp instruction;
+    private final AbstractBlockBase<?> block;
+    private final List<UseEntry> uses;
+
+    DefUseTree(LIRInstruction instruction, AbstractBlockBase<?> block) {
+        assert instruction instanceof LoadConstantOp : "Not a LoadConstantOp: " + instruction;
+        this.instruction = (LoadConstantOp) instruction;
+        this.block = block;
+        this.uses = new ArrayList<>();
+    }
+
+    public Variable getVariable() {
+        return (Variable) instruction.getResult();
+    }
+
+    public Constant getConstant() {
+        return instruction.getConstant();
+    }
+
+    public LIRInstruction getInstruction() {
+        return (LIRInstruction) instruction;
+    }
+
+    public AbstractBlockBase<?> getBlock() {
+        return block;
+    }
+
+    @Override
+    public String toString() {
+        return "DefUseTree [" + instruction + "|" + block + "," + uses + "]";
+    }
+
+    public void addUsage(AbstractBlockBase<?> b, LIRInstruction inst, Value value) {
+        uses.add(new UseEntry(b, inst, value));
+    }
+
+    public int usageCount() {
+        return uses.size();
+    }
+
+    public void forEach(Consumer<? super UseEntry> action) {
+        uses.forEach(action);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/UseEntry.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/UseEntry.java
new file mode 100644
index 0000000..f9d6a78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/UseEntry.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.ValueProcedure;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents a usage of a constant.
+ */
+class UseEntry {
+
+    private final AbstractBlockBase<?> block;
+    private final LIRInstruction instruction;
+    private final Value value;
+
+    UseEntry(AbstractBlockBase<?> block, LIRInstruction instruction, Value value) {
+        this.block = block;
+        this.instruction = instruction;
+        this.value = value;
+    }
+
+    public LIRInstruction getInstruction() {
+        return instruction;
+    }
+
+    public AbstractBlockBase<?> getBlock() {
+        return block;
+    }
+
+    public void setValue(Value newValue) {
+        replaceValue(instruction, value, newValue);
+    }
+
+    private static void replaceValue(LIRInstruction op, Value oldValue, Value newValue) {
+        ValueProcedure proc = (value, mode, flags) -> value.identityEquals(oldValue) ? newValue : value;
+        op.forEachAlive(proc);
+        op.forEachInput(proc);
+        op.forEachOutput(proc);
+        op.forEachTemp(proc);
+        op.forEachState(proc);
+    }
+
+    public Value getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return "Use[" + getValue() + ":" + instruction + ":" + block + "]";
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/VariableMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/VariableMap.java
new file mode 100644
index 0000000..1365c35
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/VariableMap.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.constopt;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import org.graalvm.compiler.lir.Variable;
+
+/**
+ * Maps variables to a generic type.
+ *
+ * TODO (je) evaluate data structure
+ */
+class VariableMap<T> {
+
+    private final ArrayList<T> content;
+
+    VariableMap() {
+        content = new ArrayList<>();
+    }
+
+    public T get(Variable key) {
+        if (key == null || key.index >= content.size()) {
+            return null;
+        }
+        return content.get(key.index);
+    }
+
+    public T put(Variable key, T value) {
+        assert key != null : "Key cannot be null";
+        assert value != null : "Value cannot be null";
+        while (key.index >= content.size()) {
+            content.add(null);
+        }
+        return content.set(key.index, value);
+    }
+
+    public T remove(Variable key) {
+        assert key != null : "Key cannot be null";
+        if (key.index >= content.size()) {
+            return null;
+        }
+        return content.set(key.index, null);
+    }
+
+    public void forEach(Consumer<T> action) {
+        for (T e : content) {
+            if (e != null) {
+                action.accept(e);
+            }
+        }
+    }
+
+    /**
+     * Keeps only keys which match the given predicate.
+     */
+    public void filter(Predicate<T> predicate) {
+        for (int i = 0; i < content.size(); i++) {
+            T e = content.get(i);
+            if (e != null && !predicate.test(e)) {
+                content.set(i, null);
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/IntervalDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/IntervalDumper.java
new file mode 100644
index 0000000..88852c7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/IntervalDumper.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.debug;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Provides abstract access to intervals for dumping.
+ */
+public interface IntervalDumper {
+
+    public interface IntervalVisitor {
+        void visitIntervalStart(Value parentOperand, Value splitOperand, Value location, Value hint, String typeName);
+
+        void visitRange(int from, int to);
+
+        void visitUsePos(int pos, Object registerPrioObject);
+
+        void visitIntervalEnd(Object spillState);
+
+    }
+
+    /**
+     * Visits the {@link IntervalVisitor} for every interval.
+     *
+     * The order is as follows:
+     * <ul>
+     * <li>Call {@link IntervalVisitor#visitIntervalStart}</li>
+     * <li>For every range:
+     * <ul>
+     * <li>Call {@link IntervalVisitor#visitRange}</li>
+     * </ul>
+     * <li>For every use position:
+     * <ul>
+     * <li>Call {@link IntervalVisitor#visitUsePos}</li>
+     * </ul>
+     * </li>
+     * <li>call {@link IntervalVisitor#visitIntervalEnd}</li>
+     * </ul>
+     */
+    void visitIntervals(IntervalVisitor visitor);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/LIRGenerationDebugContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/LIRGenerationDebugContext.java
new file mode 100644
index 0000000..aee4ed4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/debug/LIRGenerationDebugContext.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.debug;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.lir.LIR;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Provides information about {@link LIR} generation for debugging purposes.
+ */
+public interface LIRGenerationDebugContext {
+
+    /**
+     * Gets an object that represents the source of an {@link LIR} {@link Value operand} in a higher
+     * representation.
+     */
+    Object getSourceForOperand(Value value);
+
+    static LIRGenerationDebugContext getFromDebugContext() {
+        if (Debug.isEnabled()) {
+            LIRGenerationDebugContext lirGen = Debug.contextLookup(LIRGenerationDebugContext.class);
+            assert lirGen != null;
+            return lirGen;
+        }
+        return null;
+    }
+
+    static Object getSourceForOperandFromDebugContext(Value value) {
+        LIRGenerationDebugContext gen = getFromDebugContext();
+        if (gen != null) {
+            return gen.getSourceForOperand(value);
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarker.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarker.java
new file mode 100644
index 0000000..4e75e9e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarker.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.dfa;
+
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionStateProcedure;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.util.ValueSet;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public abstract class LocationMarker<S extends ValueSet<S>> {
+
+    private final LIR lir;
+    private final BlockMap<S> liveInMap;
+    private final BlockMap<S> liveOutMap;
+
+    protected final FrameMap frameMap;
+
+    protected LocationMarker(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    protected abstract S newLiveValueSet();
+
+    protected abstract boolean shouldProcessValue(Value operand);
+
+    protected abstract void processState(LIRInstruction op, LIRFrameState info, S values);
+
+    void build() {
+        AbstractBlockBase<?>[] blocks = lir.getControlFlowGraph().getBlocks();
+        UniqueWorkList worklist = new UniqueWorkList(blocks.length);
+        for (int i = blocks.length - 1; i >= 0; i--) {
+            worklist.add(blocks[i]);
+        }
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            liveInMap.put(block, newLiveValueSet());
+        }
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<?> block = worklist.poll();
+            processBlock(block, worklist);
+        }
+    }
+
+    /**
+     * Merge outSet with in-set of successors.
+     */
+    private boolean updateOutBlock(AbstractBlockBase<?> block) {
+        S union = newLiveValueSet();
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            union.putAll(liveInMap.get(succ));
+        }
+        S outSet = liveOutMap.get(block);
+        // check if changed
+        if (outSet == null || !union.equals(outSet)) {
+            liveOutMap.put(block, union);
+            return true;
+        }
+        return false;
+    }
+
+    @SuppressWarnings("try")
+    private void processBlock(AbstractBlockBase<?> block, UniqueWorkList worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                currentSet = liveOutMap.get(block).copy();
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (int i = instructions.size() - 1; i >= 0; i--) {
+                    LIRInstruction inst = instructions.get(i);
+                    processInstructionBottomUp(inst);
+                }
+                liveInMap.put(block, currentSet);
+                currentSet = null;
+                for (AbstractBlockBase<?> b : block.getPredecessors()) {
+                    worklist.add(b);
+                }
+            }
+        }
+    }
+
+    private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
+
+    private S currentSet;
+
+    /**
+     * Process all values of an instruction bottom-up, i.e. definitions before usages. Values that
+     * start or end at the current operation are not included.
+     */
+    @SuppressWarnings("try")
+    private void processInstructionBottomUp(LIRInstruction op) {
+        try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+            // kills
+
+            op.visitEachTemp(defConsumer);
+            op.visitEachOutput(defConsumer);
+            if (frameMap != null && op.destroysCallerSavedRegisters()) {
+                for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                    PlatformKind kind = frameMap.getTarget().arch.getLargestStorableKind(reg.getRegisterCategory());
+                    defConsumer.visitValue(reg.asValue(LIRKind.value(kind)), OperandMode.TEMP, REGISTER_FLAG_SET);
+                }
+            }
+
+            // gen - values that are considered alive for this state
+            op.visitEachAlive(useConsumer);
+            op.visitEachState(useConsumer);
+            // mark locations
+            op.forEachState(stateConsumer);
+            // gen
+            op.visitEachInput(useConsumer);
+        }
+    }
+
+    InstructionStateProcedure stateConsumer = new InstructionStateProcedure() {
+        @Override
+        public void doState(LIRInstruction inst, LIRFrameState info) {
+            processState(inst, info, currentSet);
+        }
+    };
+
+    ValueConsumer useConsumer = new ValueConsumer() {
+        @Override
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (shouldProcessValue(operand)) {
+                // no need to insert values and derived reference
+                if (Debug.isLogEnabled()) {
+                    Debug.log("set operand: %s", operand);
+                }
+                currentSet.put(operand);
+            }
+        }
+    };
+
+    ValueConsumer defConsumer = new ValueConsumer() {
+        @Override
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (shouldProcessValue(operand)) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("clear operand: %s", operand);
+                }
+                currentSet.remove(operand);
+            } else {
+                assert isIllegal(operand) || !operand.getValueKind().equals(LIRKind.Illegal) || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
+                                operand, mode);
+            }
+        }
+    };
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarkerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarkerPhase.java
new file mode 100644
index 0000000..d4b959e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarkerPhase.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.dfa;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Mark all live references for a frame state. The frame state use this information to build the OOP
+ * maps.
+ */
+public final class LocationMarkerPhase extends AllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
+    }
+
+    static final class Marker extends LocationMarker<RegStackValueSet> {
+
+        private final RegisterAttributes[] registerAttributes;
+
+        private Marker(LIR lir, FrameMap frameMap) {
+            super(lir, frameMap);
+            this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
+        }
+
+        @Override
+        protected RegStackValueSet newLiveValueSet() {
+            return new RegStackValueSet(frameMap);
+        }
+
+        @Override
+        protected boolean shouldProcessValue(Value operand) {
+            if (isRegister(operand)) {
+                Register reg = asRegister(operand);
+                if (!reg.mayContainReference() || !attributes(reg).isAllocatable()) {
+                    // register that's not allocatable or not part of the reference map
+                    return false;
+                }
+            } else if (!isStackSlot(operand)) {
+                // neither register nor stack slot
+                return false;
+            }
+
+            return !operand.getValueKind().equals(LIRKind.Illegal);
+        }
+
+        /**
+         * This method does the actual marking.
+         */
+        @Override
+        protected void processState(LIRInstruction op, LIRFrameState info, RegStackValueSet values) {
+            if (!info.hasDebugInfo()) {
+                info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
+            }
+
+            ReferenceMapBuilder refMap = frameMap.newReferenceMapBuilder();
+            frameMap.addLiveValues(refMap);
+            values.addLiveValues(refMap);
+
+            info.debugInfo().setReferenceMap(refMap.finish(info));
+        }
+
+        /**
+         * Gets an object describing the attributes of a given register according to this register
+         * configuration.
+         */
+        private RegisterAttributes attributes(Register reg) {
+            return registerAttributes[reg.number];
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/MarkBasePointersPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/MarkBasePointersPhase.java
new file mode 100644
index 0000000..355dbeb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/MarkBasePointersPhase.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.dfa;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.util.IndexedValueMap;
+import org.graalvm.compiler.lir.util.ValueSet;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Record all derived reference base pointers in a frame state.
+ */
+public final class MarkBasePointersPhase extends AllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        new Marker(lirGenRes.getLIR(), null).build();
+    }
+
+    private static final class Marker extends LocationMarker<Marker.BasePointersSet> {
+
+        private final class BasePointersSet extends ValueSet<Marker.BasePointersSet> {
+
+            private final IndexedValueMap variables;
+
+            BasePointersSet() {
+                variables = new IndexedValueMap();
+            }
+
+            private BasePointersSet(BasePointersSet s) {
+                variables = new IndexedValueMap(s.variables);
+            }
+
+            @Override
+            public Marker.BasePointersSet copy() {
+                return new BasePointersSet(this);
+            }
+
+            @Override
+            public void put(Value v) {
+                Variable base = (Variable) v.getValueKind(LIRKind.class).getDerivedReferenceBase();
+                assert !base.getValueKind(LIRKind.class).isValue();
+                variables.put(base.index, base);
+            }
+
+            @Override
+            public void putAll(BasePointersSet v) {
+                variables.putAll(v.variables);
+            }
+
+            @Override
+            public void remove(Value v) {
+                Variable base = (Variable) v.getValueKind(LIRKind.class).getDerivedReferenceBase();
+                assert !base.getValueKind(LIRKind.class).isValue();
+                variables.put(base.index, null);
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (obj instanceof Marker.BasePointersSet) {
+                    BasePointersSet other = (BasePointersSet) obj;
+                    return variables.equals(other.variables);
+                } else {
+                    return false;
+                }
+            }
+
+            @Override
+            public int hashCode() {
+                throw new UnsupportedOperationException();
+            }
+        }
+
+        private Marker(LIR lir, FrameMap frameMap) {
+            super(lir, frameMap);
+        }
+
+        @Override
+        protected Marker.BasePointersSet newLiveValueSet() {
+            return new BasePointersSet();
+        }
+
+        @Override
+        protected boolean shouldProcessValue(Value operand) {
+            ValueKind<?> kind = operand.getValueKind();
+            if (kind instanceof LIRKind) {
+                return ((LIRKind) kind).isDerivedReference();
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        protected void processState(LIRInstruction op, LIRFrameState info, BasePointersSet values) {
+            info.setLiveBasePointers(new IndexedValueMap(values.variables));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/RegStackValueSet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/RegStackValueSet.java
new file mode 100644
index 0000000..20ddab9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/RegStackValueSet.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.dfa;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
+import org.graalvm.compiler.lir.util.IndexedValueMap;
+import org.graalvm.compiler.lir.util.ValueSet;
+
+import jdk.vm.ci.meta.Value;
+
+final class RegStackValueSet extends ValueSet<RegStackValueSet> {
+
+    private final FrameMap frameMap;
+    private final IndexedValueMap registers;
+    private final IndexedValueMap stack;
+    private Set<Value> extraStack;
+
+    RegStackValueSet(FrameMap frameMap) {
+        this.frameMap = frameMap;
+        registers = new IndexedValueMap();
+        stack = new IndexedValueMap();
+    }
+
+    private RegStackValueSet(FrameMap frameMap, RegStackValueSet s) {
+        this.frameMap = frameMap;
+        registers = new IndexedValueMap(s.registers);
+        stack = new IndexedValueMap(s.stack);
+        if (s.extraStack != null) {
+            extraStack = new HashSet<>(s.extraStack);
+        }
+    }
+
+    @Override
+    public RegStackValueSet copy() {
+        return new RegStackValueSet(frameMap, this);
+    }
+
+    @Override
+    public void put(Value v) {
+        if (!shouldProcessValue(v)) {
+            return;
+        }
+        if (isRegister(v)) {
+            int index = asRegister(v).number;
+            registers.put(index, v);
+        } else if (isStackSlot(v)) {
+            int index = frameMap.offsetForStackSlot(asStackSlot(v));
+            assert index >= 0;
+            if (index % 4 == 0) {
+                stack.put(index / 4, v);
+            } else {
+                if (extraStack == null) {
+                    extraStack = new HashSet<>();
+                }
+                extraStack.add(v);
+            }
+        }
+    }
+
+    @Override
+    public void putAll(RegStackValueSet v) {
+        registers.putAll(v.registers);
+        stack.putAll(v.stack);
+        if (v.extraStack != null) {
+            if (extraStack == null) {
+                extraStack = new HashSet<>();
+            }
+            extraStack.addAll(v.extraStack);
+        }
+    }
+
+    @Override
+    public void remove(Value v) {
+        if (!shouldProcessValue(v)) {
+            return;
+        }
+        if (isRegister(v)) {
+            int index = asRegister(v).number;
+            registers.put(index, null);
+        } else if (isStackSlot(v)) {
+            int index = frameMap.offsetForStackSlot(asStackSlot(v));
+            assert index >= 0;
+            if (index % 4 == 0) {
+                stack.put(index / 4, null);
+            } else if (extraStack != null) {
+                extraStack.remove(v);
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof RegStackValueSet) {
+            RegStackValueSet other = (RegStackValueSet) obj;
+            return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    private static boolean shouldProcessValue(Value v) {
+        /*
+         * We always process registers because we have to track the largest register size that is
+         * alive across safepoints in order to save and restore them.
+         */
+        return isRegister(v) || !LIRKind.isValue(v);
+    }
+
+    public void addLiveValues(ReferenceMapBuilder refMap) {
+        ValueConsumer addLiveValue = new ValueConsumer() {
+            @Override
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                refMap.addLiveValue(value);
+            }
+        };
+        registers.visitEach(null, null, null, addLiveValue);
+        stack.visitEach(null, null, null, addLiveValue);
+        if (extraStack != null) {
+            for (Value v : extraStack) {
+                refMap.addLiveValue(v);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/UniqueWorkList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/UniqueWorkList.java
new file mode 100644
index 0000000..b921212
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/UniqueWorkList.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.dfa;
+
+import java.util.ArrayDeque;
+import java.util.BitSet;
+import java.util.Collection;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+
+/**
+ * Ensures that an element is only in the worklist once.
+ *
+ */
+class UniqueWorkList extends ArrayDeque<AbstractBlockBase<?>> {
+    private static final long serialVersionUID = 8009554570990975712L;
+    BitSet valid;
+
+    UniqueWorkList(int size) {
+        this.valid = new BitSet(size);
+    }
+
+    @Override
+    public AbstractBlockBase<?> poll() {
+        AbstractBlockBase<?> result = super.poll();
+        if (result != null) {
+            valid.set(result.getId(), false);
+        }
+        return result;
+    }
+
+    @Override
+    public boolean add(AbstractBlockBase<?> pred) {
+        if (!valid.get(pred.getId())) {
+            valid.set(pred.getId(), true);
+            return super.add(pred);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends AbstractBlockBase<?>> collection) {
+        boolean changed = false;
+        for (AbstractBlockBase<?> element : collection) {
+            if (!valid.get(element.getId())) {
+                valid.set(element.getId(), true);
+                super.add(element);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMap.java
new file mode 100644
index 0000000..c9290c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMap.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.LIRKind;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * This class is used to build the stack frame layout for a compiled method. A {@link StackSlot} is
+ * used to index slots of the frame relative to the stack pointer. The frame size is only fixed
+ * after register allocation when all spill slots have been allocated. Both the outgoing argument
+ * area and the spill are can grow until then. Therefore, outgoing arguments are indexed from the
+ * stack pointer, while spill slots are indexed from the beginning of the frame (and the total frame
+ * size has to be added to get the actual offset from the stack pointer).
+ */
+public abstract class FrameMap {
+
+    private final TargetDescription target;
+    private final RegisterConfig registerConfig;
+
+    public interface ReferenceMapBuilderFactory {
+
+        ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize);
+    }
+
+    private final ReferenceMapBuilderFactory referenceMapFactory;
+
+    /**
+     * The final frame size, not including the size of the
+     * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after
+     * register allocation is complete, i.e., after all spill slots have been allocated.
+     */
+    private int frameSize;
+
+    /**
+     * Initial size of the area occupied by spill slots and other stack-allocated memory blocks.
+     */
+    protected int initialSpillSize;
+
+    /**
+     * Size of the area occupied by spill slots and other stack-allocated memory blocks.
+     */
+    protected int spillSize;
+
+    /**
+     * Size of the area occupied by outgoing overflow arguments. This value is adjusted as calling
+     * conventions for outgoing calls are retrieved. On some platforms, there is a minimum outgoing
+     * size even if no overflow arguments are on the stack.
+     */
+    protected int outgoingSize;
+
+    /**
+     * Determines if this frame has values on the stack for outgoing calls.
+     */
+    protected boolean hasOutgoingStackArguments;
+
+    /**
+     * The list of stack slots allocated in this frame that are present in every reference map.
+     */
+    private final List<StackSlot> objectStackSlots;
+
+    /**
+     * Records whether an offset to an incoming stack argument was ever returned by
+     * {@link #offsetForStackSlot(StackSlot)}.
+     */
+    private boolean accessesCallerFrame;
+
+    /**
+     * Creates a new frame map for the specified method. The given registerConfig is optional, in
+     * case null is passed the default RegisterConfig from the CodeCacheProvider will be used.
+     */
+    public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        this.target = codeCache.getTarget();
+        this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
+        this.frameSize = -1;
+        this.outgoingSize = codeCache.getMinimumOutgoingSize();
+        this.objectStackSlots = new ArrayList<>();
+        this.referenceMapFactory = referenceMapFactory;
+    }
+
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+
+    public TargetDescription getTarget() {
+        return target;
+    }
+
+    public void addLiveValues(ReferenceMapBuilder refMap) {
+        for (Value value : objectStackSlots) {
+            refMap.addLiveValue(value);
+        }
+    }
+
+    protected int returnAddressSize() {
+        return getTarget().arch.getReturnAddressSize();
+    }
+
+    /**
+     * Determines if an offset to an incoming stack argument was ever returned by
+     * {@link #offsetForStackSlot(StackSlot)}.
+     */
+    public boolean accessesCallerFrame() {
+        return accessesCallerFrame;
+    }
+
+    /**
+     * Gets the frame size of the compiled frame, not including the size of the
+     * {@link Architecture#getReturnAddressSize() return address slot}.
+     *
+     * @return The size of the frame (in bytes).
+     */
+    public int frameSize() {
+        assert frameSize != -1 : "frame size not computed yet";
+        return frameSize;
+    }
+
+    public int outgoingSize() {
+        return outgoingSize;
+    }
+
+    /**
+     * Determines if any space is used in the frame apart from the
+     * {@link Architecture#getReturnAddressSize() return address slot}.
+     */
+    public boolean frameNeedsAllocating() {
+        int unalignedFrameSize = spillSize - returnAddressSize();
+        return hasOutgoingStackArguments || unalignedFrameSize != 0;
+    }
+
+    /**
+     * Gets the total frame size of the compiled frame, including the size of the
+     * {@link Architecture#getReturnAddressSize() return address slot}.
+     *
+     * @return The total size of the frame (in bytes).
+     */
+    public abstract int totalFrameSize();
+
+    /**
+     * Gets the current size of this frame. This is the size that would be returned by
+     * {@link #frameSize()} if {@link #finish()} were called now.
+     */
+    public abstract int currentFrameSize();
+
+    /**
+     * Aligns the given frame size to the stack alignment size and return the aligned size.
+     *
+     * @param size the initial frame size to be aligned
+     * @return the aligned frame size
+     */
+    protected int alignFrameSize(int size) {
+        return NumUtil.roundUp(size, getTarget().stackAlignment);
+    }
+
+    /**
+     * Computes the final size of this frame. After this method has been called, methods that change
+     * the frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can
+     * be requested.
+     */
+    public void finish() {
+        frameSize = currentFrameSize();
+        if (frameSize > getRegisterConfig().getMaximumFrameSize()) {
+            throw new PermanentBailoutException("Frame size (%d) exceeded maximum allowed frame size (%d).", frameSize, getRegisterConfig().getMaximumFrameSize());
+        }
+    }
+
+    /**
+     * Computes the offset of a stack slot relative to the frame register.
+     *
+     * @param slot a stack slot
+     * @return the offset of the stack slot
+     */
+    public int offsetForStackSlot(StackSlot slot) {
+        if (slot.isInCallerFrame()) {
+            accessesCallerFrame = true;
+        }
+        return slot.getOffset(totalFrameSize());
+    }
+
+    /**
+     * Informs the frame map that the compiled code calls a particular method, which may need stack
+     * space for outgoing arguments.
+     *
+     * @param cc The calling convention for the called method.
+     */
+    public void callsMethod(CallingConvention cc) {
+        reserveOutgoing(cc.getStackSize());
+    }
+
+    /**
+     * Reserves space for stack-based outgoing arguments.
+     *
+     * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments.
+     */
+    public void reserveOutgoing(int argsSize) {
+        assert frameSize == -1 : "frame size must not yet be fixed";
+        outgoingSize = Math.max(outgoingSize, argsSize);
+        hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0;
+    }
+
+    /**
+     * Reserves a new spill slot in the frame of the method being compiled. The returned slot is
+     * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte
+     * boundary.
+     *
+     * @param kind The kind of the spill slot to be reserved.
+     * @param additionalOffset
+     * @return A spill slot denoting the reserved memory area.
+     */
+    protected StackSlot allocateNewSpillSlot(ValueKind<?> kind, int additionalOffset) {
+        return StackSlot.get(kind, -spillSize + additionalOffset, true);
+    }
+
+    /**
+     * Returns the spill slot size for the given {@link ValueKind}. The default value is the size in
+     * bytes for the target architecture.
+     *
+     * @param kind the {@link ValueKind} to be stored in the spill slot.
+     * @return the size in bytes
+     */
+    public int spillSlotSize(ValueKind<?> kind) {
+        return kind.getPlatformKind().getSizeInBytes();
+    }
+
+    /**
+     * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned
+     * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary, unless
+     * overridden by a subclass.
+     *
+     * @param kind The kind of the spill slot to be reserved.
+     * @return A spill slot denoting the reserved memory area.
+     */
+    public StackSlot allocateSpillSlot(ValueKind<?> kind) {
+        assert frameSize == -1 : "frame size must not yet be fixed";
+        int size = spillSlotSize(kind);
+        spillSize = NumUtil.roundUp(spillSize + size, size);
+        return allocateNewSpillSlot(kind, 0);
+    }
+
+    /**
+     * Returns the size of the stack slot range for {@code slots} objects.
+     *
+     * @param slots The number of slots.
+     * @return The size in byte
+     */
+    public int spillSlotRangeSize(int slots) {
+        return slots * getTarget().wordSize;
+    }
+
+    /**
+     * Reserves a number of contiguous slots in the frame of the method being compiled. If the
+     * requested number of slots is 0, this method returns {@code null}.
+     *
+     * @param slots the number of slots to reserve
+     * @param objects specifies the indexes of the object pointer slots. The caller is responsible
+     *            for guaranteeing that each such object pointer slot is initialized before any
+     *            instruction that uses a reference map. Without this guarantee, the garbage
+     *            collector could see garbage object values.
+     * @return the first reserved stack slot (i.e., at the lowest address)
+     */
+    public StackSlot allocateStackSlots(int slots, BitSet objects) {
+        assert frameSize == -1 : "frame size must not yet be fixed";
+        if (slots == 0) {
+            return null;
+        }
+        spillSize += spillSlotRangeSize(slots);
+
+        if (!objects.isEmpty()) {
+            assert objects.length() <= slots;
+            StackSlot result = null;
+            for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
+                StackSlot objectSlot = null;
+                if (objects.get(slotIndex)) {
+                    objectSlot = allocateNewSpillSlot(LIRKind.reference(getTarget().arch.getWordKind()), slotIndex * getTarget().wordSize);
+                    addObjectStackSlot(objectSlot);
+                }
+                if (slotIndex == 0) {
+                    if (objectSlot != null) {
+                        result = objectSlot;
+                    } else {
+                        result = allocateNewSpillSlot(LIRKind.value(getTarget().arch.getWordKind()), 0);
+                    }
+                }
+            }
+            assert result != null;
+            return result;
+
+        } else {
+            return allocateNewSpillSlot(LIRKind.value(getTarget().arch.getWordKind()), 0);
+        }
+    }
+
+    protected void addObjectStackSlot(StackSlot objectSlot) {
+        objectStackSlots.add(objectSlot);
+    }
+
+    public ReferenceMapBuilder newReferenceMapBuilder() {
+        return referenceMapFactory.newReferenceMapBuilder(totalFrameSize());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilder.java
new file mode 100644
index 0000000..caa9a71
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilder.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import java.util.BitSet;
+import java.util.List;
+
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * A {@link FrameMapBuilder} is used to collect all information necessary to
+ * {@linkplain #buildFrameMap create} a {@link FrameMap}.
+ */
+public abstract class FrameMapBuilder {
+
+    /**
+     * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned
+     * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary, unless
+     * overridden by a subclass.
+     *
+     * @param kind The kind of the spill slot to be reserved.
+     * @return A spill slot denoting the reserved memory area.
+     */
+    public abstract VirtualStackSlot allocateSpillSlot(ValueKind<?> kind);
+
+    /**
+     * Reserves a number of contiguous slots in the frame of the method being compiled. If the
+     * requested number of slots is 0, this method returns {@code null}.
+     *
+     * @param slots the number of slots to reserve
+     * @param objects specifies the indexes of the object pointer slots. The caller is responsible
+     *            for guaranteeing that each such object pointer slot is initialized before any
+     *            instruction that uses a reference map. Without this guarantee, the garbage
+     *            collector could see garbage object values.
+     * @param outObjectStackSlots if non-null, the object pointer slots allocated are added to this
+     *            list
+     * @return the first reserved stack slot (i.e., at the lowest address)
+     */
+    public abstract VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots);
+
+    public abstract RegisterConfig getRegisterConfig();
+
+    public abstract CodeCacheProvider getCodeCache();
+
+    /**
+     * Informs the frame map that the compiled code calls a particular method, which may need stack
+     * space for outgoing arguments.
+     *
+     * @param cc The calling convention for the called method.
+     */
+    public abstract void callsMethod(CallingConvention cc);
+
+    /**
+     * Creates a {@linkplain FrameMap} based on the information collected by this
+     * {@linkplain FrameMapBuilder}.
+     */
+    public abstract FrameMap buildFrameMap(LIRGenerationResult result);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderImpl.java
new file mode 100644
index 0000000..58f3e90
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderImpl.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * A FrameMapBuilder that records allocation.
+ */
+public class FrameMapBuilderImpl extends FrameMapBuilderTool {
+
+    private final RegisterConfig registerConfig;
+    private final CodeCacheProvider codeCache;
+    private final FrameMap frameMap;
+    private final List<VirtualStackSlot> stackSlots;
+    private final List<CallingConvention> calls;
+    private int numStackSlots;
+
+    public FrameMapBuilderImpl(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+        assert registerConfig != null : "No register config!";
+        this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
+        this.codeCache = codeCache;
+        this.frameMap = frameMap;
+        this.stackSlots = new ArrayList<>();
+        this.calls = new ArrayList<>();
+        this.numStackSlots = 0;
+    }
+
+    @Override
+    public VirtualStackSlot allocateSpillSlot(ValueKind<?> kind) {
+        SimpleVirtualStackSlot slot = new SimpleVirtualStackSlot(numStackSlots++, kind);
+        stackSlots.add(slot);
+        return slot;
+    }
+
+    @Override
+    public VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots) {
+        if (slots == 0) {
+            return null;
+        }
+        if (outObjectStackSlots != null) {
+            throw GraalError.unimplemented();
+        }
+        VirtualStackSlotRange slot = new VirtualStackSlotRange(numStackSlots++, slots, objects, LIRKind.fromJavaKind(frameMap.getTarget().arch, JavaKind.Object));
+        stackSlots.add(slot);
+        return slot;
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+
+    @Override
+    public CodeCacheProvider getCodeCache() {
+        return codeCache;
+    }
+
+    @Override
+    public FrameMap getFrameMap() {
+        return frameMap;
+    }
+
+    @Override
+    public int getNumberOfStackSlots() {
+        return numStackSlots;
+    }
+
+    @Override
+    public void callsMethod(CallingConvention cc) {
+        calls.add(cc);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public FrameMap buildFrameMap(LIRGenerationResult res) {
+        if (Debug.isEnabled()) {
+            verifyStackSlotAllocation(res);
+        }
+        for (CallingConvention cc : calls) {
+            frameMap.callsMethod(cc);
+        }
+        frameMap.finish();
+        return frameMap;
+    }
+
+    private static void verifyStackSlotAllocation(LIRGenerationResult res) {
+        LIR lir = res.getLIR();
+        InstructionValueConsumer verifySlots = (LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) -> {
+            assert !isVirtualStackSlot(value) : String.format("Instruction %s contains a virtual stack slot %s", op, value);
+        };
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            lir.getLIRforBlock(block).forEach(op -> {
+                op.visitEachInput(verifySlots);
+                op.visitEachAlive(verifySlots);
+                op.visitEachState(verifySlots);
+
+                op.visitEachTemp(verifySlots);
+                op.visitEachOutput(verifySlots);
+            });
+        }
+    }
+
+    @Override
+    public List<VirtualStackSlot> getStackSlots() {
+        return stackSlots;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderTool.java
new file mode 100644
index 0000000..f10c06d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderTool.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import java.util.List;
+
+import org.graalvm.compiler.lir.VirtualStackSlot;
+
+/**
+ * A {@link FrameMapBuilder} that allows access to the underlying {@link FrameMap}.
+ */
+public abstract class FrameMapBuilderTool extends FrameMapBuilder {
+
+    /**
+     * Returns the number of {@link VirtualStackSlot}s created by this {@link FrameMapBuilder}. Can
+     * be used as an upper bound for an array indexed by {@link VirtualStackSlot#getId()}.
+     */
+    public abstract int getNumberOfStackSlots();
+
+    public abstract List<VirtualStackSlot> getStackSlots();
+
+    public abstract FrameMap getFrameMap();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/ReferenceMapBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/ReferenceMapBuilder.java
new file mode 100644
index 0000000..189aed5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/ReferenceMapBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import org.graalvm.compiler.lir.LIRFrameState;
+
+import jdk.vm.ci.code.ReferenceMap;
+import jdk.vm.ci.meta.Value;
+
+public abstract class ReferenceMapBuilder {
+
+    public abstract void addLiveValue(Value value);
+
+    public abstract ReferenceMap finish(LIRFrameState state);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/SimpleVirtualStackSlot.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/SimpleVirtualStackSlot.java
new file mode 100644
index 0000000..77b58173
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/SimpleVirtualStackSlot.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import org.graalvm.compiler.lir.VirtualStackSlot;
+
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Represents a {@link VirtualStackSlot virtual stack slot} for a specific {@link ValueKind kind}.
+ */
+public class SimpleVirtualStackSlot extends VirtualStackSlot {
+
+    public SimpleVirtualStackSlot(int id, ValueKind<?> kind) {
+        super(id, kind);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/VirtualStackSlotRange.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/VirtualStackSlotRange.java
new file mode 100644
index 0000000..468209f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/VirtualStackSlotRange.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.framemap;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Represents a {@link #getSlots() numbered} range of {@link VirtualStackSlot virtual stack slot} of
+ * size {@link TargetDescription#wordSize}.
+ */
+public class VirtualStackSlotRange extends VirtualStackSlot {
+
+    private final BitSet objects;
+    private final int slots;
+
+    public VirtualStackSlotRange(int id, int slots, BitSet objects, LIRKind kind) {
+        super(id, kind);
+        this.slots = slots;
+        this.objects = (BitSet) objects.clone();
+    }
+
+    public int getSlots() {
+        return slots;
+    }
+
+    public BitSet getObjects() {
+        return (BitSet) objects.clone();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java
new file mode 100644
index 0000000..a475f20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class ArithmeticLIRGenerator implements ArithmeticLIRGeneratorTool {
+
+    LIRGenerator lirGen;
+
+    public LIRGenerator getLIRGen() {
+        return lirGen;
+    }
+
+    // automatic derived reference handling
+
+    protected abstract boolean isNumericInteger(PlatformKind kind);
+
+    protected abstract Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags);
+
+    @Override
+    public final Variable emitAdd(Value aVal, Value bVal, boolean setFlags) {
+        LIRKind resultKind;
+        Value a = aVal;
+        Value b = bVal;
+
+        if (isNumericInteger(a.getPlatformKind())) {
+            LIRKind aKind = a.getValueKind(LIRKind.class);
+            LIRKind bKind = b.getValueKind(LIRKind.class);
+            assert a.getPlatformKind() == b.getPlatformKind();
+
+            if (aKind.isUnknownReference()) {
+                resultKind = aKind;
+            } else if (bKind.isUnknownReference()) {
+                resultKind = bKind;
+            } else if (aKind.isValue() && bKind.isValue()) {
+                resultKind = aKind;
+            } else if (aKind.isValue()) {
+                if (bKind.isDerivedReference()) {
+                    resultKind = bKind;
+                } else {
+                    AllocatableValue allocatable = getLIRGen().asAllocatable(b);
+                    resultKind = bKind.makeDerivedReference(allocatable);
+                    b = allocatable;
+                }
+            } else if (bKind.isValue()) {
+                if (aKind.isDerivedReference()) {
+                    resultKind = aKind;
+                } else {
+                    AllocatableValue allocatable = getLIRGen().asAllocatable(a);
+                    resultKind = aKind.makeDerivedReference(allocatable);
+                    a = allocatable;
+                }
+            } else {
+                resultKind = aKind.makeUnknownReference();
+            }
+        } else {
+            resultKind = LIRKind.combine(a, b);
+        }
+
+        return emitAdd(resultKind, a, b, setFlags);
+    }
+
+    protected abstract Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags);
+
+    @Override
+    public final Variable emitSub(Value aVal, Value bVal, boolean setFlags) {
+        LIRKind resultKind;
+        Value a = aVal;
+        Value b = bVal;
+
+        if (isNumericInteger(a.getPlatformKind())) {
+            LIRKind aKind = a.getValueKind(LIRKind.class);
+            LIRKind bKind = b.getValueKind(LIRKind.class);
+            assert a.getPlatformKind() == b.getPlatformKind();
+
+            if (aKind.isUnknownReference()) {
+                resultKind = aKind;
+            } else if (bKind.isUnknownReference()) {
+                resultKind = bKind;
+            }
+
+            if (aKind.isValue() && bKind.isValue()) {
+                resultKind = aKind;
+            } else if (bKind.isValue()) {
+                if (aKind.isDerivedReference()) {
+                    resultKind = aKind;
+                } else {
+                    AllocatableValue allocatable = getLIRGen().asAllocatable(a);
+                    resultKind = aKind.makeDerivedReference(allocatable);
+                    a = allocatable;
+                }
+            } else if (aKind.isDerivedReference() && bKind.isDerivedReference() && aKind.getDerivedReferenceBase().equals(bKind.getDerivedReferenceBase())) {
+                resultKind = LIRKind.value(a.getPlatformKind());
+            } else {
+                resultKind = aKind.makeUnknownReference();
+            }
+        } else {
+            resultKind = LIRKind.combine(a, b);
+        }
+
+        return emitSub(resultKind, a, b, setFlags);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java
new file mode 100644
index 0000000..ab76980
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * This interface can be used to generate LIR for arithmetic and simple memory access operations.
+ *
+ * The setFlags flag in emitAdd, emitSub and emitMul indicates, that the instruction must set the
+ * flags register to be used for a later branch. (On AMD64, the condition codes are set in every
+ * arithmetic instruction, but other architectures optionally set the flags register) If setFlags is
+ * set, the instruction must set the flags register; if false, the instruction may or may not set
+ * the flags register.
+ */
+public interface ArithmeticLIRGeneratorTool {
+
+    Value emitNegate(Value input);
+
+    Value emitAdd(Value a, Value b, boolean setFlags);
+
+    Value emitSub(Value a, Value b, boolean setFlags);
+
+    Value emitMul(Value a, Value b, boolean setFlags);
+
+    Value emitMulHigh(Value a, Value b);
+
+    Value emitUMulHigh(Value a, Value b);
+
+    Value emitDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitRem(Value a, Value b, LIRFrameState state);
+
+    Value emitUDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitURem(Value a, Value b, LIRFrameState state);
+
+    Value emitNot(Value input);
+
+    Value emitAnd(Value a, Value b);
+
+    Value emitOr(Value a, Value b);
+
+    Value emitXor(Value a, Value b);
+
+    Value emitShl(Value a, Value b);
+
+    Value emitShr(Value a, Value b);
+
+    Value emitUShr(Value a, Value b);
+
+    Value emitFloatConvert(FloatConvert op, Value inputVal);
+
+    Value emitReinterpret(LIRKind to, Value inputVal);
+
+    Value emitNarrow(Value inputVal, int bits);
+
+    Value emitSignExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitZeroExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitMathAbs(Value input);
+
+    Value emitMathSqrt(Value input);
+
+    Value emitBitCount(Value operand);
+
+    Value emitBitScanForward(Value operand);
+
+    Value emitBitScanReverse(Value operand);
+
+    Variable emitLoad(LIRKind kind, Value address, LIRFrameState state);
+
+    void emitStore(ValueKind<?> kind, Value address, Value input, LIRFrameState state);
+
+    @SuppressWarnings("unused")
+    default Value emitMathLog(Value input, boolean base10) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+    @SuppressWarnings("unused")
+    default Value emitMathCos(Value input) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+    @SuppressWarnings("unused")
+    default Value emitMathSin(Value input) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+    @SuppressWarnings("unused")
+    default Value emitMathTan(Value input) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+    @SuppressWarnings("unused")
+    default Value emitMathExp(Value input) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+    @SuppressWarnings("unused")
+    default Value emitMathPow(Value x, Value y) {
+        throw GraalError.unimplemented("No specialized implementation available");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/BlockValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/BlockValueMap.java
new file mode 100644
index 0000000..0c6c20e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/BlockValueMap.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+
+import jdk.vm.ci.meta.Value;
+
+public interface BlockValueMap {
+
+    void accessOperand(Value operand, AbstractBlockBase<?> block);
+
+    void defineOperand(Value operand, AbstractBlockBase<?> block);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/DiagnosticLIRGeneratorTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/DiagnosticLIRGeneratorTool.java
new file mode 100644
index 0000000..7578f61
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/DiagnosticLIRGeneratorTool.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public interface DiagnosticLIRGeneratorTool {
+    LIRInstruction createBenchmarkCounter(String name, String group, Value increment);
+
+    LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments);
+
+    /**
+     * Creates a {@link SaveRegistersOp} that fills a given set of registers with known garbage
+     * value.
+     *
+     * The set of registers actually touched might be {@link SaveRegistersOp#remove reduced} later.
+     *
+     * @param zappedRegisters registers to be zapped
+     * @param zapValues values used for zapping
+     *
+     * @see DiagnosticLIRGeneratorTool#createZapRegisters()
+     */
+    SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues);
+
+    /**
+     * Creates a {@link SaveRegistersOp} that fills all
+     * {@link RegisterConfig#getAllocatableRegisters() allocatable registers} with a
+     * {@link LIRGenerator#zapValueForKind known garbage value}.
+     *
+     * The set of registers actually touched might be {@link SaveRegistersOp#remove reduced} later.
+     *
+     * @see DiagnosticLIRGeneratorTool#createZapRegisters(Register[], JavaConstant[])
+     */
+    SaveRegistersOp createZapRegisters();
+
+    /**
+     * Marker interface for {@link LIRInstruction instructions} that should be succeeded with a
+     * {@link DiagnosticLIRGeneratorTool#createZapRegisters() ZapRegisterOp} if assertions are
+     * enabled.
+     */
+    interface ZapRegistersAfterInstruction {
+    }
+
+    /**
+     * Marker interface for {@link LIRInstruction instructions} that should be preceded with a
+     * {@link DiagnosticLIRGeneratorTool#zapArgumentSpace ZapArgumentSpaceOp} if assertions are
+     * enabled.
+     */
+    interface ZapStackArgumentSpaceBeforeInstruction {
+    }
+
+    LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues);
+
+    LIRInstruction zapArgumentSpace();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java
new file mode 100644
index 0000000..ed43eb7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+
+import jdk.vm.ci.code.CallingConvention;
+
+public class LIRGenerationResult {
+
+    private final LIR lir;
+    private final FrameMapBuilder frameMapBuilder;
+    private FrameMap frameMap;
+    private final CallingConvention callingConvention;
+    /**
+     * Records whether the code being generated makes at least one foreign call.
+     */
+    private boolean hasForeignCall;
+    /**
+     * Unique identifier of this compilation.
+     */
+    private final CompilationIdentifier compilationId;
+
+    public LIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, CallingConvention callingConvention) {
+        this.lir = lir;
+        this.frameMapBuilder = frameMapBuilder;
+        this.callingConvention = callingConvention;
+        this.compilationId = compilationId;
+    }
+
+    /**
+     * Returns the incoming calling convention for the parameters of the method that is compiled.
+     */
+    public CallingConvention getCallingConvention() {
+        return callingConvention;
+    }
+
+    /**
+     * Returns the {@link FrameMapBuilder} for collecting the information to build a
+     * {@link FrameMap}.
+     *
+     * This method can only be used prior calling {@link #buildFrameMap}.
+     */
+    public final FrameMapBuilder getFrameMapBuilder() {
+        assert frameMap == null : "getFrameMapBuilder() can only be used before calling buildFrameMap()!";
+        return frameMapBuilder;
+    }
+
+    /**
+     * Creates a {@link FrameMap} out of the {@link FrameMapBuilder}. This method should only be
+     * called once. After calling it, {@link #getFrameMapBuilder()} can no longer be used.
+     *
+     * @see FrameMapBuilder#buildFrameMap
+     */
+    public void buildFrameMap() {
+        assert frameMap == null : "buildFrameMap() can only be called once!";
+        frameMap = frameMapBuilder.buildFrameMap(this);
+    }
+
+    /**
+     * Returns the {@link FrameMap} associated with this {@link LIRGenerationResult}.
+     *
+     * This method can only be called after {@link #buildFrameMap}.
+     */
+    public FrameMap getFrameMap() {
+        assert frameMap != null : "getFrameMap() can only be used after calling buildFrameMap()!";
+        return frameMap;
+    }
+
+    public LIR getLIR() {
+        return lir;
+    }
+
+    /**
+     * Determines whether the code being generated makes at least one foreign call.
+     */
+    public boolean hasForeignCall() {
+        return hasForeignCall;
+    }
+
+    public final void setForeignCall(boolean hasForeignCall) {
+        this.hasForeignCall = hasForeignCall;
+    }
+
+    public String getCompilationUnitName() {
+        if (compilationId == null || compilationId == CompilationIdentifier.INVALID_COMPILATION_ID) {
+            return "<unknown>";
+        }
+        return compilationId.toString(Verbosity.NAME);
+    }
+
+    /**
+     * Returns a unique identifier of the current compilation.
+     */
+    public CompilationIdentifier getCompilationId() {
+        return compilationId;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java
new file mode 100644
index 0000000..f319b80
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.spi.CodeGenProviders;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRVerifier;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class LIRGenerator implements LIRGeneratorTool {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Print HIR along side LIR as the latter is generated", type = OptionType.Debug)
+        public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
+        @Option(help = "The trace level for the LIR generator", type = OptionType.Debug)
+        public static final OptionValue<Integer> TraceLIRGeneratorLevel = new OptionValue<>(0);
+        // @formatter:on
+    }
+
+    private final LIRKindTool lirKindTool;
+
+    private final CodeGenProviders providers;
+
+    private AbstractBlockBase<?> currentBlock;
+
+    private LIRGenerationResult res;
+
+    protected final ArithmeticLIRGenerator arithmeticLIRGen;
+    private final MoveFactory moveFactory;
+
+    public LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, CodeGenProviders providers, LIRGenerationResult res) {
+        this.lirKindTool = lirKindTool;
+        this.arithmeticLIRGen = arithmeticLIRGen;
+        this.res = res;
+        this.providers = providers;
+
+        assert arithmeticLIRGen.lirGen == null;
+        arithmeticLIRGen.lirGen = this;
+        this.moveFactory = moveFactory;
+    }
+
+    @Override
+    public ArithmeticLIRGeneratorTool getArithmetic() {
+        return arithmeticLIRGen;
+    }
+
+    @Override
+    public MoveFactory getMoveFactory() {
+        return moveFactory;
+    }
+
+    private MoveFactory spillMoveFactory;
+
+    @Override
+    public MoveFactory getSpillMoveFactory() {
+        if (spillMoveFactory == null) {
+            boolean verify = false;
+            assert (verify = true) == true;
+            if (verify) {
+                spillMoveFactory = new VerifyingMoveFactory(moveFactory);
+            } else {
+                spillMoveFactory = moveFactory;
+            }
+        }
+        return spillMoveFactory;
+    }
+
+    @Override
+    public LIRKind getValueKind(JavaKind javaKind) {
+        return LIRKind.fromJavaKind(target().arch, javaKind);
+    }
+
+    @Override
+    public TargetDescription target() {
+        return getCodeCache().getTarget();
+    }
+
+    @Override
+    public CodeGenProviders getProviders() {
+        return providers;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public CodeCacheProvider getCodeCache() {
+        return providers.getCodeCache();
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return providers.getForeignCalls();
+    }
+
+    public LIRKindTool getLIRKindTool() {
+        return lirKindTool;
+    }
+
+    /**
+     * Hide {@link #nextVariable()} from other users.
+     */
+    public abstract static class VariableProvider {
+        private int numVariables;
+
+        public int numVariables() {
+            return numVariables;
+        }
+
+        private int nextVariable() {
+            return numVariables++;
+        }
+    }
+
+    @Override
+    public Variable newVariable(ValueKind<?> valueKind) {
+        return new Variable(valueKind, ((VariableProvider) res.getLIR()).nextVariable());
+    }
+
+    @Override
+    public RegisterAttributes attributes(Register register) {
+        return res.getFrameMapBuilder().getRegisterConfig().getAttributesMap()[register.number];
+    }
+
+    @Override
+    public Variable emitMove(Value input) {
+        assert !(input instanceof Variable) : "Creating a copy of a variable via this method is not supported (and potentially a bug): " + input;
+        Variable result = newVariable(input.getValueKind());
+        emitMove(result, input);
+        return result;
+    }
+
+    @Override
+    public void emitMove(AllocatableValue dst, Value src) {
+        append(moveFactory.createMove(dst, src));
+    }
+
+    @Override
+    public void emitMoveConstant(AllocatableValue dst, Constant src) {
+        append(moveFactory.createLoad(dst, src));
+    }
+
+    @Override
+    public Value emitConstant(LIRKind kind, Constant constant) {
+        if (constant instanceof JavaConstant && moveFactory.canInlineConstant((JavaConstant) constant)) {
+            return new ConstantValue(toRegisterKind(kind), constant);
+        } else {
+            return emitLoadConstant(kind, constant);
+        }
+    }
+
+    @Override
+    public Value emitJavaConstant(JavaConstant constant) {
+        return emitConstant(getValueKind(constant.getJavaKind()), constant);
+    }
+
+    @Override
+    public AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant) {
+        Variable result = newVariable(kind);
+        emitMoveConstant(result, constant);
+        return result;
+    }
+
+    @Override
+    public AllocatableValue asAllocatable(Value value) {
+        if (isAllocatableValue(value)) {
+            return asAllocatableValue(value);
+        } else if (isConstantValue(value)) {
+            return emitLoadConstant(value.getValueKind(), asConstant(value));
+        } else {
+            return emitMove(value);
+        }
+    }
+
+    @Override
+    public Variable load(Value value) {
+        if (!isVariable(value)) {
+            return emitMove(value);
+        }
+        return (Variable) value;
+    }
+
+    @Override
+    public Value loadNonConst(Value value) {
+        if (isJavaConstant(value) && !moveFactory.canInlineConstant(asJavaConstant(value))) {
+            return emitMove(value);
+        }
+        return value;
+    }
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    @Override
+    public boolean needOnlyOopMaps() {
+        return false;
+    }
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param javaKind the kind of value being returned
+     * @param valueKind the backend type of the value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    @Override
+    public AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind) {
+        Register reg = res.getFrameMapBuilder().getRegisterConfig().getReturnRegister(javaKind);
+        assert target().arch.canStoreValue(reg.getRegisterCategory(), valueKind.getPlatformKind()) : reg.getRegisterCategory() + " " + valueKind.getPlatformKind();
+        return reg.asValue(valueKind);
+    }
+
+    NodeSourcePosition currentPosition;
+
+    @Override
+    public void setSourcePosition(NodeSourcePosition position) {
+        currentPosition = position;
+    }
+
+    @Override
+    public <I extends LIRInstruction> I append(I op) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
+            TTY.println(op.toStringWithIdPrefix());
+            TTY.println();
+        }
+        assert LIRVerifier.verify(op);
+        List<LIRInstruction> lirForBlock = res.getLIR().getLIRforBlock(getCurrentBlock());
+        op.setPosition(currentPosition);
+        lirForBlock.add(op);
+        return op;
+    }
+
+    @Override
+    public boolean hasBlockEnd(AbstractBlockBase<?> block) {
+        List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
+        if (ops.size() == 0) {
+            return false;
+        }
+        return ops.get(ops.size() - 1) instanceof BlockEndOp;
+    }
+
+    private final class BlockScopeImpl extends BlockScope {
+
+        private BlockScopeImpl(AbstractBlockBase<?> block) {
+            currentBlock = block;
+        }
+
+        private void doBlockStart() {
+            if (Options.PrintIRWithLIR.getValue()) {
+                TTY.print(currentBlock.toString());
+            }
+
+            // set up the list of LIR instructions
+            assert res.getLIR().getLIRforBlock(currentBlock) == null : "LIR list already computed for this block";
+            res.getLIR().setLIRforBlock(currentBlock, new ArrayList<LIRInstruction>());
+
+            append(new LabelOp(new Label(currentBlock.getId()), currentBlock.isAligned()));
+
+            if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+                TTY.println("BEGIN Generating LIR for block B" + currentBlock.getId());
+            }
+        }
+
+        private void doBlockEnd() {
+            if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+                TTY.println("END Generating LIR for block B" + currentBlock.getId());
+            }
+
+            if (Options.PrintIRWithLIR.getValue()) {
+                TTY.println();
+            }
+            currentBlock = null;
+        }
+
+        @Override
+        public AbstractBlockBase<?> getCurrentBlock() {
+            return currentBlock;
+        }
+
+        @Override
+        public void close() {
+            doBlockEnd();
+        }
+
+    }
+
+    @Override
+    public final BlockScope getBlockScope(AbstractBlockBase<?> block) {
+        BlockScopeImpl blockScope = new BlockScopeImpl(block);
+        blockScope.doBlockStart();
+        return blockScope;
+    }
+
+    @Override
+    public void emitIncomingValues(Value[] params) {
+        ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params);
+    }
+
+    @Override
+    public abstract void emitJump(LabelRef label);
+
+    @Override
+    public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    @Override
+    public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability);
+
+    @Override
+    public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    @Override
+    public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    @Override
+    public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    /**
+     * Emits the single call operation at the heart of generating LIR for a
+     * {@linkplain #emitForeignCall(ForeignCallLinkage, LIRFrameState, Value...) foreign call}.
+     */
+    protected abstract void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) {
+        LIRFrameState state = null;
+        if (linkage.needsDebugInfo()) {
+            if (frameState != null) {
+                state = frameState;
+            } else {
+                assert needOnlyOopMaps();
+                state = new LIRFrameState(null, null, null);
+            }
+        }
+
+        // move the arguments into the correct location
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        res.getFrameMapBuilder().callsMethod(linkageCc);
+        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
+        Value[] argLocations = new Value[args.length];
+        for (int i = 0; i < args.length; i++) {
+            Value arg = args[i];
+            AllocatableValue loc = linkageCc.getArgument(i);
+            emitMove(loc, arg);
+            argLocations[i] = loc;
+        }
+        res.setForeignCall(true);
+        emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
+
+        if (isLegal(linkageCc.getReturn())) {
+            return emitMove(linkageCc.getReturn());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+        int keyCount = keyConstants.length;
+        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
+        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
+        double tableSwitchDensity = keyCount / (double) valueRange;
+        /*
+         * This heuristic tries to find a compromise between the effort for the best switch strategy
+         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
+         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
+         * gradually with additional effort.
+         */
+        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
+            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
+        } else {
+            int minValue = keyConstants[0].asInt();
+            assert valueRange < Integer.MAX_VALUE;
+            LabelRef[] targets = new LabelRef[(int) valueRange];
+            for (int i = 0; i < valueRange; i++) {
+                targets[i] = defaultTarget;
+            }
+            for (int i = 0; i < keyCount; i++) {
+                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
+            }
+            emitTableSwitch(minValue, defaultTarget, targets, value);
+        }
+    }
+
+    @Override
+    public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
+
+    @Override
+    public void beforeRegisterAllocation() {
+    }
+
+    /**
+     * Gets a garbage value for a given kind.
+     */
+    protected abstract JavaConstant zapValueForKind(PlatformKind kind);
+
+    @Override
+    public LIRKind getLIRKind(Stamp stamp) {
+        return stamp.getLIRKind(lirKindTool);
+    }
+
+    protected LIRKind getAddressKind(Value base, long displacement, Value index) {
+        if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) {
+            return LIRKind.value(target().arch.getWordKind());
+        } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
+            return LIRKind.reference(target().arch.getWordKind());
+        } else {
+            return LIRKind.unknownReference(target().arch.getWordKind());
+        }
+    }
+
+    @Override
+    public AbstractBlockBase<?> getCurrentBlock() {
+        return currentBlock;
+    }
+
+    @Override
+    public LIRGenerationResult getResult() {
+        return res;
+    }
+
+    @Override
+    public void emitBlackhole(Value operand) {
+        append(new StandardOp.BlackholeOp(operand));
+    }
+
+    @Override
+    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
+        throw GraalError.unimplemented();
+    }
+
+    @Override
+    public abstract SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues);
+
+    @Override
+    public SaveRegistersOp createZapRegisters() {
+        Register[] zappedRegisters = getResult().getFrameMap().getRegisterConfig().getAllocatableRegisters().toArray();
+        JavaConstant[] zapValues = new JavaConstant[zappedRegisters.length];
+        for (int i = 0; i < zappedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory());
+            zapValues[i] = zapValueForKind(kind);
+        }
+        return createZapRegisters(zappedRegisters, zapValues);
+    }
+
+    @Override
+    public abstract LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues);
+
+    @Override
+    public LIRInstruction zapArgumentSpace() {
+        List<StackSlot> slots = null;
+        for (AllocatableValue arg : res.getCallingConvention().getArguments()) {
+            if (isStackSlot(arg)) {
+                if (slots == null) {
+                    slots = new ArrayList<>();
+                }
+                slots.add((StackSlot) arg);
+            } else {
+                assert !isVirtualStackSlot(arg);
+            }
+        }
+        if (slots == null) {
+            return null;
+        }
+        StackSlot[] zappedStack = slots.toArray(new StackSlot[slots.size()]);
+        JavaConstant[] zapValues = new JavaConstant[zappedStack.length];
+        for (int i = 0; i < zappedStack.length; i++) {
+            PlatformKind kind = zappedStack[i].getPlatformKind();
+            zapValues[i] = zapValueForKind(kind);
+        }
+        return createZapArgumentSpace(zappedStack, zapValues);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
new file mode 100644
index 0000000..0972993
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.spi.CodeGenProviders;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LabelRef;
+import org.graalvm.compiler.lir.SwitchStrategy;
+import org.graalvm.compiler.lir.Variable;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.ValueKindFactory;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindFactory<LIRKind> {
+
+    /**
+     * Factory for creating moves.
+     */
+    public interface MoveFactory {
+
+        /**
+         * Checks whether the supplied constant can be used without loading it into a register for
+         * most operations, i.e., for commonly used arithmetic, logical, and comparison operations.
+         *
+         * @param c The constant to check.
+         * @return True if the constant can be used directly, false if the constant needs to be in a
+         *         register.
+         */
+        boolean canInlineConstant(JavaConstant c);
+
+        /**
+         * @param constant The constant that might be moved to a stack slot.
+         * @return {@code true} if constant to stack moves are supported for this constant.
+         */
+        boolean allowConstantToStackMove(Constant constant);
+
+        LIRInstruction createMove(AllocatableValue result, Value input);
+
+        LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input);
+
+        LIRInstruction createLoad(AllocatableValue result, Constant input);
+    }
+
+    abstract class BlockScope implements AutoCloseable {
+
+        public abstract AbstractBlockBase<?> getCurrentBlock();
+
+        @Override
+        public abstract void close();
+
+    }
+
+    ArithmeticLIRGeneratorTool getArithmetic();
+
+    CodeGenProviders getProviders();
+
+    TargetDescription target();
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    AbstractBlockBase<?> getCurrentBlock();
+
+    LIRGenerationResult getResult();
+
+    boolean hasBlockEnd(AbstractBlockBase<?> block);
+
+    MoveFactory getMoveFactory();
+
+    /**
+     * Get a special {@link MoveFactory} for spill moves.
+     *
+     * The instructions returned by this factory must only depend on the input values. References to
+     * values that require interaction with register allocation are strictly forbidden.
+     */
+    MoveFactory getSpillMoveFactory();
+
+    BlockScope getBlockScope(AbstractBlockBase<?> block);
+
+    Value emitConstant(LIRKind kind, Constant constant);
+
+    Value emitJavaConstant(JavaConstant constant);
+
+    /**
+     * Some backends need to convert sub-word kinds to a larger kind in
+     * {@link ArithmeticLIRGeneratorTool#emitLoad} and {@link #emitLoadConstant} because sub-word
+     * registers can't be accessed. This method converts the {@link LIRKind} of a memory location or
+     * constant to the {@link LIRKind} that will be used when it is loaded into a register.
+     */
+    <K extends ValueKind<K>> K toRegisterKind(K kind);
+
+    AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant);
+
+    void emitNullCheck(Value address, LIRFrameState state);
+
+    Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
+
+    /**
+     * Emit an atomic read-and-add instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param delta the value to be added
+     */
+    default Value emitAtomicReadAndAdd(Value address, Value delta) {
+        throw GraalError.unimplemented();
+    }
+
+    /**
+     * Emit an atomic read-and-write instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param newValue the new value to be written
+     */
+    default Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        throw GraalError.unimplemented();
+    }
+
+    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state);
+
+    Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
+
+    RegisterAttributes attributes(Register register);
+
+    /**
+     * Create a new {@link Variable}.
+     *
+     * @param kind The type of the value that will be stored in this {@link Variable}. See
+     *            {@link LIRKind} for documentation on what to pass here. Note that in most cases,
+     *            simply passing {@link Value#getValueKind()} is wrong.
+     * @return A new {@link Variable}.
+     */
+    Variable newVariable(ValueKind<?> kind);
+
+    Variable emitMove(Value input);
+
+    void emitMove(AllocatableValue dst, Value src);
+
+    void emitMoveConstant(AllocatableValue dst, Constant src);
+
+    Variable emitAddress(AllocatableValue stackslot);
+
+    void emitMembar(int barriers);
+
+    void emitUnwind(Value operand);
+
+    /**
+     * Called just before register allocation is performed on the LIR owned by this generator.
+     * Overriding implementations of this method must call the overridden method.
+     */
+    void beforeRegisterAllocation();
+
+    void emitIncomingValues(Value[] params);
+
+    /**
+     * Emits a return instruction. Implementations need to insert a move if the input is not in the
+     * correct location.
+     */
+    void emitReturn(JavaKind javaKind, Value input);
+
+    AllocatableValue asAllocatable(Value value);
+
+    Variable load(Value value);
+
+    Value loadNonConst(Value value);
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    boolean needOnlyOopMaps();
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param javaKind the {@link JavaKind} of value being returned
+     * @param valueKind the backend type of the value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind);
+
+    <I extends LIRInstruction> I append(I op);
+
+    void setSourcePosition(NodeSourcePosition position);
+
+    void emitJump(LabelRef label);
+
+    void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability);
+
+    void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value);
+
+    void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    Variable emitByteSwap(Value operand);
+
+    Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length);
+
+    void emitBlackhole(Value operand);
+
+    LIRKind getLIRKind(Stamp stamp);
+
+    void emitPause();
+
+    void emitPrefetchAllocate(Value address);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java
new file mode 100644
index 0000000..c5fe857
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.meta.Value.ILLEGAL;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Converts phi instructions into moves.
+ *
+ * Resolves cycles:
+ *
+ * <pre>
+ *
+ *  r1 := r2  becomes  temp := r1
+ *  r2 := r1           r1 := r2
+ *                     r2 := temp
+ * </pre>
+ *
+ * and orders moves:
+ *
+ * <pre>
+ *  r2 := r3  becomes  r1 := r2
+ *  r1 := r2           r2 := r3
+ * </pre>
+ */
+public class PhiResolver {
+
+    /**
+     * Tracks a data flow dependency between a source operand and any number of the destination
+     * operands.
+     */
+    static class PhiResolverNode {
+
+        /**
+         * A source operand whose value flows into the {@linkplain #destinations destination}
+         * operands.
+         */
+        final Value operand;
+
+        /**
+         * The operands whose values are defined by the {@linkplain #operand source} operand.
+         */
+        final ArrayList<PhiResolverNode> destinations;
+
+        /**
+         * Denotes if a move instruction has already been emitted to initialize the value of
+         * {@link #operand}.
+         */
+        boolean assigned;
+
+        /**
+         * Specifies if this operand been visited for the purpose of emitting a move instruction.
+         */
+        boolean visited;
+
+        /**
+         * Specifies if this is the initial definition in data flow path for a given value.
+         */
+        boolean startNode;
+
+        PhiResolverNode(Value operand) {
+            this.operand = operand;
+            destinations = new ArrayList<>(4);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder(operand.toString());
+            if (!destinations.isEmpty()) {
+                buf.append(" ->");
+                for (PhiResolverNode node : destinations) {
+                    buf.append(' ').append(node.operand);
+                }
+            }
+            return buf.toString();
+        }
+    }
+
+    private final LIRGeneratorTool gen;
+    private final MoveFactory moveFactory;
+    private final LIRInsertionBuffer buffer;
+    private final int insertBefore;
+
+    /**
+     * The operand loop header phi for the operand currently being process in {@link #dispose()}.
+     */
+    private PhiResolverNode loop;
+
+    private Value temp;
+
+    private final ArrayList<PhiResolverNode> variableOperands = new ArrayList<>(3);
+    private final ArrayList<PhiResolverNode> otherOperands = new ArrayList<>(3);
+
+    /**
+     * Maps operands to nodes.
+     */
+    private final HashMap<Value, PhiResolverNode> operandToNodeMap = CollectionsFactory.newMap();
+
+    public static PhiResolver create(LIRGeneratorTool gen) {
+        AbstractBlockBase<?> block = gen.getCurrentBlock();
+        assert block != null;
+        List<LIRInstruction> instructions = gen.getResult().getLIR().getLIRforBlock(block);
+
+        return new PhiResolver(gen, new LIRInsertionBuffer(), instructions, instructions.size());
+    }
+
+    public static PhiResolver create(LIRGeneratorTool gen, LIRInsertionBuffer buffer, List<LIRInstruction> instructions, int insertBefore) {
+        return new PhiResolver(gen, buffer, instructions, insertBefore);
+    }
+
+    protected PhiResolver(LIRGeneratorTool gen, LIRInsertionBuffer buffer, List<LIRInstruction> instructions, int insertBefore) {
+        this.gen = gen;
+        moveFactory = gen.getSpillMoveFactory();
+        temp = ILLEGAL;
+
+        this.buffer = buffer;
+        this.buffer.init(instructions);
+        this.insertBefore = insertBefore;
+
+    }
+
+    public void dispose() {
+        // resolve any cycles in moves from and to variables
+        for (int i = variableOperands.size() - 1; i >= 0; i--) {
+            PhiResolverNode node = variableOperands.get(i);
+            if (!node.visited) {
+                loop = null;
+                move(node, null);
+                node.startNode = true;
+                assert isIllegal(temp) : "moveTempTo() call missing";
+            }
+        }
+
+        // generate move for move from non variable to arbitrary destination
+        for (int i = otherOperands.size() - 1; i >= 0; i--) {
+            PhiResolverNode node = otherOperands.get(i);
+            for (int j = node.destinations.size() - 1; j >= 0; j--) {
+                emitMove(node.destinations.get(j).operand, node.operand);
+            }
+        }
+        buffer.finish();
+    }
+
+    public void move(Value dest, Value src) {
+        assert isVariable(dest) : "destination must be virtual";
+        // tty.print("move "); src.print(); tty.print(" to "); dest.print(); tty.cr();
+        assert isLegal(src) : "source for phi move is illegal";
+        assert isLegal(dest) : "destination for phi move is illegal";
+        PhiResolverNode srcNode = sourceNode(src);
+        PhiResolverNode destNode = destinationNode(dest);
+        srcNode.destinations.add(destNode);
+    }
+
+    private PhiResolverNode createNode(Value operand, boolean source) {
+        PhiResolverNode node;
+        if (isVariable(operand)) {
+            node = operandToNodeMap.get(operand);
+            assert node == null || node.operand.equals(operand);
+            if (node == null) {
+                node = new PhiResolverNode(operand);
+                operandToNodeMap.put(operand, node);
+            }
+            // Make sure that all variables show up in the list when
+            // they are used as the source of a move.
+            if (source) {
+                if (!variableOperands.contains(node)) {
+                    variableOperands.add(node);
+                }
+            }
+        } else {
+            assert source;
+            node = new PhiResolverNode(operand);
+            otherOperands.add(node);
+        }
+        return node;
+    }
+
+    private PhiResolverNode destinationNode(Value opr) {
+        return createNode(opr, false);
+    }
+
+    private void emitMove(Value dest, Value src) {
+        assert isLegal(src);
+        assert isLegal(dest);
+        LIRInstruction move = moveFactory.createMove((AllocatableValue) dest, src);
+        buffer.append(insertBefore, move);
+    }
+
+    // Traverse assignment graph in depth first order and generate moves in post order
+    // ie. two assignments: b := c, a := b start with node c:
+    // Call graph: move(c, NULL) -> move(b, c) -> move(a, b)
+    // Generates moves in this order: move b to a and move c to b
+    // ie. cycle a := b, b := a start with node a
+    // Call graph: move(a, NULL) -> move(b, a) -> move(a, b)
+    // Generates moves in this order: move b to temp, move a to b, move temp to a
+    private void move(PhiResolverNode dest, PhiResolverNode src) {
+        if (!dest.visited) {
+            dest.visited = true;
+            for (int i = dest.destinations.size() - 1; i >= 0; i--) {
+                move(dest.destinations.get(i), dest);
+            }
+        } else if (!dest.startNode) {
+            // cycle in graph detected
+            assert loop == null : "only one loop valid!";
+            loop = dest;
+            moveToTemp(src.operand);
+            return;
+        } // else dest is a start node
+
+        if (!dest.assigned) {
+            if (loop == dest) {
+                moveTempTo(dest.operand);
+                dest.assigned = true;
+            } else if (src != null) {
+                emitMove(dest.operand, src.operand);
+                dest.assigned = true;
+            }
+        }
+    }
+
+    private void moveTempTo(Value dest) {
+        assert isLegal(temp);
+        emitMove(dest, temp);
+        temp = ILLEGAL;
+    }
+
+    private void moveToTemp(Value src) {
+        assert isIllegal(temp);
+        temp = gen.newVariable(src.getValueKind());
+        emitMove(temp, src);
+    }
+
+    private PhiResolverNode sourceNode(Value opr) {
+        return createNode(opr, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java
new file mode 100644
index 0000000..0456f30
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.gen;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Wrapper for {@link MoveFactory} that checks that the instructions created adhere to the contract
+ * of {@link MoveFactory}.
+ */
+public final class VerifyingMoveFactory implements MoveFactory {
+
+    private final MoveFactory inner;
+
+    public VerifyingMoveFactory(MoveFactory inner) {
+        this.inner = inner;
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        return inner.canInlineConstant(c);
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant constant) {
+        return inner.allowConstantToStackMove(constant);
+    }
+
+    @Override
+    public LIRInstruction createMove(AllocatableValue result, Value input) {
+        LIRInstruction inst = inner.createMove(result, input);
+        assert checkResult(inst, result, input);
+        return inst;
+    }
+
+    @Override
+    public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        LIRInstruction inst = inner.createStackMove(result, input);
+        assert checkResult(inst, result, input);
+        return inst;
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue result, Constant input) {
+        LIRInstruction inst = inner.createLoad(result, input);
+        assert inst instanceof LoadConstantOp && checkResult(inst, result, null);
+        return inst;
+    }
+
+    /** Closure for {@link VerifyingMoveFactory#checkResult}. */
+    @SuppressWarnings("unused")
+    private static class CheckClosure {
+
+        private final AllocatableValue result;
+        private final Value input;
+
+        private int tempCount = 0;
+        private int aliveCount = 0;
+        private int stateCount = 0;
+        private int inputCount = 0;
+        private int outputCount = 0;
+
+        CheckClosure(AllocatableValue result, Value input) {
+            this.result = result;
+            this.input = input;
+        }
+
+        void tempProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode);
+            tempCount++;
+        }
+
+        void stateProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode);
+            stateCount++;
+        }
+
+        void aliveProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            assert !isVariable(value) && flags.contains(OperandFlag.UNINITIALIZED) : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode);
+            aliveCount++;
+        }
+
+        void inputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            assert value.equals(input) || isJavaConstant(value) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value);
+            inputCount++;
+        }
+
+        void outputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            assert value.equals(result) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value);
+            outputCount++;
+        }
+    }
+
+    /**
+     * Checks that the instructions adheres to the contract of {@link MoveFactory}.
+     */
+    private static boolean checkResult(LIRInstruction inst, AllocatableValue result, Value input) {
+
+        VerifyingMoveFactory.CheckClosure c = new CheckClosure(result, input);
+        inst.visitEachInput(c::inputProc);
+        inst.visitEachOutput(c::outputProc);
+        inst.visitEachAlive(c::aliveProc);
+        inst.visitEachTemp(c::tempProc);
+        inst.visitEachState(c::stateProc);
+
+        assert c.outputCount >= 1 : "no output produced" + inst;
+        assert c.stateCount == 0 : "SpillMoveFactory: instruction must not have a state: " + inst;
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationPhase.java
new file mode 100644
index 0000000..d7105b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationPhase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+
+public abstract class AllocationPhase extends LIRPhase<AllocationPhase.AllocationContext> {
+
+    public static final class AllocationContext extends GenericContext {
+        public final MoveFactory spillMoveFactory;
+        public final RegisterAllocationConfig registerAllocationConfig;
+
+        public AllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
+            this.spillMoveFactory = spillMoveFactory;
+            this.registerAllocationConfig = registerAllocationConfig;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java
new file mode 100644
index 0000000..521942e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.lir.alloc.AllocationStageVerifier;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
+import org.graalvm.compiler.lir.dfa.LocationMarkerPhase;
+import org.graalvm.compiler.lir.dfa.MarkBasePointersPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.ssi.SSIConstructionPhase;
+import org.graalvm.compiler.lir.stackslotalloc.LSStackSlotAllocator;
+import org.graalvm.compiler.lir.stackslotalloc.SimpleStackSlotAllocator;
+
+public class AllocationStage extends LIRPhaseSuite<AllocationContext> {
+
+    public AllocationStage() {
+        appendPhase(new MarkBasePointersPhase());
+        if (TraceRA.getValue()) {
+            appendPhase(new TraceBuilderPhase());
+            appendPhase(new SSIConstructionPhase());
+            appendPhase(new TraceRegisterAllocationPhase());
+        } else {
+            appendPhase(new LinearScanPhase());
+        }
+
+        // build frame map
+        if (LSStackSlotAllocator.Options.LIROptLSStackSlotAllocator.getValue()) {
+            appendPhase(new LSStackSlotAllocator());
+        } else {
+            appendPhase(new SimpleStackSlotAllocator());
+        }
+        // currently we mark locations only if we do register allocation
+        appendPhase(new LocationMarkerPhase());
+
+        if (GraalOptions.DetailedAsserts.getValue()) {
+            appendPhase(new AllocationStageVerifier());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java
new file mode 100644
index 0000000..f28b9c6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanPhase;
+import org.graalvm.compiler.lir.dfa.LocationMarkerPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.stackslotalloc.SimpleStackSlotAllocator;
+
+public class EconomyAllocationStage extends LIRPhaseSuite<AllocationContext> {
+    public EconomyAllocationStage() {
+        appendPhase(new LinearScanPhase());
+
+        // build frame map
+        appendPhase(new SimpleStackSlotAllocator());
+
+        // currently we mark locations only if we do register allocation
+        appendPhase(new LocationMarkerPhase());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPostAllocationOptimizationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPostAllocationOptimizationStage.java
new file mode 100644
index 0000000..32f4a54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPostAllocationOptimizationStage.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+
+public class EconomyPostAllocationOptimizationStage extends LIRPhaseSuite<PostAllocationOptimizationContext> {
+    public EconomyPostAllocationOptimizationStage() {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPreAllocationOptimizationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPreAllocationOptimizationStage.java
new file mode 100644
index 0000000..b6eff94
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyPreAllocationOptimizationStage.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+
+public class EconomyPreAllocationOptimizationStage extends LIRPhaseSuite<PreAllocationOptimizationContext> {
+    public EconomyPreAllocationOptimizationStage() {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/GenericContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/GenericContext.java
new file mode 100644
index 0000000..2f9dc03
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/GenericContext.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import java.util.ArrayList;
+import java.util.ListIterator;
+
+/**
+ * Allows storing of arbitrary data.
+ */
+public class GenericContext {
+
+    private ArrayList<Object> context;
+
+    public GenericContext() {
+        context = null;
+    }
+
+    public <T> void contextAdd(T obj) {
+        if (context == null) {
+            context = new ArrayList<>();
+        }
+        context.add(obj);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T contextLookup(Class<T> clazz) {
+        if (context != null) {
+            for (Object e : context) {
+                if (clazz.isInstance(e)) {
+                    return (T) e;
+                }
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T contextRemove(Class<T> clazz) {
+        if (context != null) {
+            ListIterator<Object> it = context.listIterator();
+            while (it.hasNext()) {
+                Object e = it.next();
+                if (clazz.isInstance(e)) {
+                    // remove entry
+                    it.remove();
+                    if (context.isEmpty()) {
+                        context = null;
+                    }
+                    return (T) e;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java
new file mode 100644
index 0000000..a799a9c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
+ * one global instance for each phase that is shared for all compilations.
+ */
+public abstract class LIRPhase<C> {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable LIR level optimiztations.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptimization = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    /**
+     * Records time spent within {@link #apply}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Records memory usage within {@link #apply}.
+     */
+    private final DebugMemUseTracker memUseTracker;
+
+    public static final class LIRPhaseStatistics {
+        /**
+         * Records time spent within {@link #apply}.
+         */
+        public final DebugTimer timer;
+
+        /**
+         * Records memory usage within {@link #apply}.
+         */
+        public final DebugMemUseTracker memUseTracker;
+
+        private LIRPhaseStatistics(Class<?> clazz) {
+            timer = Debug.timer("LIRPhaseTime_%s", clazz);
+            memUseTracker = Debug.memUseTracker("LIRPhaseMemUse_%s", clazz);
+        }
+    }
+
+    public static final ClassValue<LIRPhaseStatistics> statisticsClassValue = new ClassValue<LIRPhaseStatistics>() {
+        @Override
+        protected LIRPhaseStatistics computeValue(Class<?> c) {
+            return new LIRPhaseStatistics(c);
+        }
+    };
+
+    /** Lazy initialization to create pattern only when assertions are enabled. */
+    static class NamePatternHolder {
+        static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
+    }
+
+    private static boolean checkName(CharSequence name) {
+        assert name == null || NamePatternHolder.NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
+        return true;
+    }
+
+    public LIRPhase() {
+        LIRPhaseStatistics statistics = statisticsClassValue.get(getClass());
+        timer = statistics.timer;
+        memUseTracker = statistics.memUseTracker;
+    }
+
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, C context) {
+        apply(target, lirGenRes, context, true);
+    }
+
+    @SuppressWarnings("try")
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, C context, boolean dumpLIR) {
+        try (Scope s = Debug.scope(getName(), this)) {
+            try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
+                run(target, lirGenRes, context);
+                if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+                    Debug.dump(Debug.BASIC_LOG_LEVEL, lirGenRes.getLIR(), "%s", getName());
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, C context);
+
+    public static CharSequence createName(Class<?> clazz) {
+        String className = clazz.getName();
+        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
+        int innerClassPos = s.indexOf('$');
+        if (innerClassPos > 0) {
+            /* Remove inner class name. */
+            s = s.substring(0, innerClassPos);
+        }
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
+    protected CharSequence createName() {
+        return createName(getClass());
+    }
+
+    public final CharSequence getName() {
+        CharSequence name = createName();
+        assert checkName(name);
+        return name;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java
new file mode 100644
index 0000000..0bb2d99
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class LIRPhaseSuite<C> extends LIRPhase<C> {
+    private List<LIRPhase<C>> phases;
+    private boolean immutable;
+
+    public LIRPhaseSuite() {
+        phases = new ArrayList<>();
+    }
+
+    /**
+     * Add a new phase at the beginning of this suite.
+     */
+    public final void prependPhase(LIRPhase<C> phase) {
+        phases.add(0, phase);
+    }
+
+    /**
+     * Add a new phase at the end of this suite.
+     */
+    public final void appendPhase(LIRPhase<C> phase) {
+        phases.add(phase);
+    }
+
+    public final ListIterator<LIRPhase<C>> findPhase(Class<? extends LIRPhase<C>> phaseClass) {
+        ListIterator<LIRPhase<C>> it = phases.listIterator();
+        if (findNextPhase(it, phaseClass)) {
+            return it;
+        } else {
+            return null;
+        }
+    }
+
+    public final <T extends LIRPhase<C>> T findPhaseInstance(Class<T> phaseClass) {
+        ListIterator<LIRPhase<C>> it = phases.listIterator();
+        while (it.hasNext()) {
+            LIRPhase<C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                return phaseClass.cast(phase);
+            }
+        }
+        return null;
+    }
+
+    public static <C> boolean findNextPhase(ListIterator<LIRPhase<C>> it, Class<? extends LIRPhase<C>> phaseClass) {
+        while (it.hasNext()) {
+            LIRPhase<C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected final void run(TargetDescription target, LIRGenerationResult lirGenRes, C context) {
+        for (LIRPhase<C> phase : phases) {
+            phase.apply(target, lirGenRes, context);
+        }
+    }
+
+    public LIRPhaseSuite<C> copy() {
+        LIRPhaseSuite<C> suite = new LIRPhaseSuite<>();
+        suite.phases.addAll(phases);
+        return suite;
+    }
+
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    public synchronized void setImmutable() {
+        if (!immutable) {
+            phases = Collections.unmodifiableList(phases);
+            immutable = true;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRSuites.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRSuites.java
new file mode 100644
index 0000000..fe748f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRSuites.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+
+import jdk.vm.ci.code.StackSlot;
+
+public class LIRSuites {
+
+    private final LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage;
+    private final LIRPhaseSuite<AllocationContext> allocStage;
+    private final LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage;
+    private boolean immutable;
+
+    public LIRSuites(LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage, LIRPhaseSuite<AllocationContext> allocStage, LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage) {
+        this.preAllocOptStage = preAllocOptStage;
+        this.allocStage = allocStage;
+        this.postAllocStage = postAllocStage;
+    }
+
+    public LIRSuites(LIRSuites other) {
+        this(other.getPreAllocationOptimizationStage().copy(), other.getAllocationStage().copy(), other.getPostAllocationOptimizationStage().copy());
+    }
+
+    /**
+     * {@link PreAllocationOptimizationPhase}s are executed between {@link LIR} generation and
+     * register allocation.
+     * <p>
+     * {@link PreAllocationOptimizationPhase Implementers} can create new
+     * {@link LIRGeneratorTool#newVariable variables}, {@link LIRGenerationResult#getFrameMap stack
+     * slots} and {@link LIRGenerationResult#getFrameMapBuilder virtual stack slots}.
+     */
+    public LIRPhaseSuite<PreAllocationOptimizationContext> getPreAllocationOptimizationStage() {
+        return preAllocOptStage;
+    }
+
+    /**
+     * {@link AllocationPhase}s are responsible for register allocation and translating
+     * {@link VirtualStackSlot}s into {@link StackSlot}s.
+     * <p>
+     * After the {@link AllocationStage} there should be no more {@link Variable}s and
+     * {@link VirtualStackSlot}s.
+     */
+    public LIRPhaseSuite<AllocationContext> getAllocationStage() {
+        return allocStage;
+    }
+
+    /**
+     * {@link PostAllocationOptimizationPhase}s are executed after register allocation and before
+     * machine code generation.
+     * <p>
+     * A {@link PostAllocationOptimizationPhase} must not introduce new {@link Variable}s,
+     * {@link VirtualStackSlot}s or {@link StackSlot}s. Blocks might be removed from
+     * {@link LIR#codeEmittingOrder()} by overwriting them with {@code null}.
+     */
+    public LIRPhaseSuite<PostAllocationOptimizationContext> getPostAllocationOptimizationStage() {
+        return postAllocStage;
+    }
+
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    public synchronized void setImmutable() {
+        if (!immutable) {
+            preAllocOptStage.setImmutable();
+            allocStage.setImmutable();
+            postAllocStage.setImmutable();
+            immutable = true;
+        }
+    }
+
+    public LIRSuites copy() {
+        return new LIRSuites(preAllocOptStage.copy(), allocStage.copy(), postAllocStage.copy());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationPhase.java
new file mode 100644
index 0000000..963d52d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationPhase.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
+
+public abstract class PostAllocationOptimizationPhase extends LIRPhase<PostAllocationOptimizationPhase.PostAllocationOptimizationContext> {
+
+    public static final class PostAllocationOptimizationContext {
+        public final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
+
+        public PostAllocationOptimizationContext(DiagnosticLIRGeneratorTool diagnosticTool) {
+            this.diagnosticLirGenTool = diagnosticTool;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationStage.java
new file mode 100644
index 0000000..3062afd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PostAllocationOptimizationStage.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+
+import org.graalvm.compiler.lir.ControlFlowOptimizer;
+import org.graalvm.compiler.lir.EdgeMoveOptimizer;
+import org.graalvm.compiler.lir.NullCheckOptimizer;
+import org.graalvm.compiler.lir.RedundantMoveElimination;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.profiling.MethodProfilingPhase;
+import org.graalvm.compiler.lir.profiling.MoveProfilingPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+public class PostAllocationOptimizationStage extends LIRPhaseSuite<PostAllocationOptimizationContext> {
+    public static class Options {
+        // @formatter:off
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptEdgeMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptControlFlowOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptRedundantMoveElimination = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptNullCheckOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "Enables profiling of move types on LIR level. " +
+                       "Move types are for example stores (register to stack), " +
+                       "constant loads (constant to register) or copies (register to register).", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIRProfileMoves = new OptionValue<>(false);
+        @Option(help = "Enables profiling of methods.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIRProfileMethods = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    public PostAllocationOptimizationStage() {
+        if (Options.LIROptEdgeMoveOptimizer.getValue()) {
+            appendPhase(new EdgeMoveOptimizer());
+        }
+        if (Options.LIROptControlFlowOptimizer.getValue()) {
+            appendPhase(new ControlFlowOptimizer());
+        }
+        if (Options.LIROptRedundantMoveElimination.getValue()) {
+            appendPhase(new RedundantMoveElimination());
+        }
+        if (Options.LIROptNullCheckOptimizer.getValue()) {
+            appendPhase(new NullCheckOptimizer());
+        }
+        if (Options.LIRProfileMoves.getValue()) {
+            appendPhase(new MoveProfilingPhase());
+        }
+        if (Options.LIRProfileMethods.getValue()) {
+            appendPhase(new MethodProfilingPhase());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationPhase.java
new file mode 100644
index 0000000..f179a8e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationPhase.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+public abstract class PreAllocationOptimizationPhase extends LIRPhase<PreAllocationOptimizationPhase.PreAllocationOptimizationContext> {
+
+    public static final class PreAllocationOptimizationContext {
+        public final LIRGeneratorTool lirGen;
+
+        public PreAllocationOptimizationContext(LIRGeneratorTool lirGen) {
+            this.lirGen = lirGen;
+        }
+
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java
new file mode 100644
index 0000000..35a1c04
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.phases;
+
+import org.graalvm.compiler.lir.alloc.SaveCalleeSaveRegisters;
+import org.graalvm.compiler.lir.constopt.ConstantLoadOptimization;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+
+public class PreAllocationOptimizationStage extends LIRPhaseSuite<PreAllocationOptimizationContext> {
+    public PreAllocationOptimizationStage() {
+        if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) {
+            appendPhase(new ConstantLoadOptimization());
+            appendPhase(new SaveCalleeSaveRegisters());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MethodProfilingPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MethodProfilingPhase.java
new file mode 100644
index 0000000..fb613aa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MethodProfilingPhase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.profiling;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+public class MethodProfilingPhase extends PostAllocationOptimizationPhase {
+    public static final String INVOCATION_GROUP = "METHOD_INVOCATION_COUNTER";
+    public static final String ITERATION_GROUP = "METHOD_ITERATION_COUNTER";
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), context.diagnosticLirGenTool).run();
+    }
+
+    private class Analyzer {
+        private final LIR lir;
+        private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
+        private final LIRInsertionBuffer buffer;
+        private final String compilationUnitName;
+        private final ConstantValue increment;
+
+        Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
+            this.lir = lir;
+            this.compilationUnitName = compilationUnitName;
+            this.diagnosticLirGenTool = diagnosticLirGenTool;
+            this.buffer = new LIRInsertionBuffer();
+            this.increment = new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.INT_1);
+        }
+
+        public void run() {
+            // insert counter at method entry
+            doBlock(lir.getControlFlowGraph().getStartBlock(), INVOCATION_GROUP);
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                if (block.isLoopHeader()) {
+                    // insert counter at loop header
+                    doBlock(block, ITERATION_GROUP);
+                }
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block, String group) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+
+            LIRInstruction op = diagnosticLirGenTool.createBenchmarkCounter(compilationUnitName, group, increment);
+            buffer.init(instructions);
+            buffer.append(1, op);
+            buffer.finish();
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java
new file mode 100644
index 0000000..8bad1ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.profiling;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+
+public final class MoveProfiler {
+
+    public static BlockMap<MoveStatistics> profile(LIR lir) {
+        MoveProfiler profiler = new MoveProfiler(lir);
+        profiler.run();
+        return profiler.blockMap;
+    }
+
+    static class MoveStatistics {
+
+        private final int[] cnt;
+
+        MoveStatistics() {
+            cnt = new int[MoveType.values().length];
+
+        }
+
+        public void add(MoveType moveType) {
+            cnt[moveType.ordinal()]++;
+        }
+
+        public int get(MoveType moveType) {
+            return cnt[moveType.ordinal()];
+        }
+
+        public void add(MoveType moveType, int value) {
+            cnt[moveType.ordinal()] += value;
+        }
+    }
+
+    private final LIR lir;
+    private final BlockMap<MoveStatistics> blockMap;
+
+    private MoveProfiler(LIR lir) {
+        this.lir = lir;
+        blockMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    private void run() {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            doBlock(block);
+        }
+    }
+
+    private void doBlock(AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+        assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+        assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+        assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+        assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+
+        MoveStatistics stats = null;
+        // analysis phase
+        for (LIRInstruction inst : instructions) {
+            if (inst instanceof MoveOp) {
+                if (stats == null) {
+                    stats = new MoveStatistics();
+                    blockMap.put(block, stats);
+                }
+                stats.add(MoveType.get((MoveOp) inst));
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfilingPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfilingPhase.java
new file mode 100644
index 0000000..2eb5224
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfilingPhase.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.profiling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInsertionBuffer;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+import org.graalvm.compiler.lir.profiling.MoveProfiler.MoveStatistics;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Inserts counters into the {@link LIR} code to the number of move instruction dynamically
+ * executed.
+ */
+public class MoveProfilingPhase extends PostAllocationOptimizationPhase {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable dynamic move profiling per method.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIRDynMoveProfilMethod = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    private static final String MOVE_OPERATIONS = "MoveOperations";
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        new Analyzer(target, lirGenRes, context.diagnosticLirGenTool).run();
+    }
+
+    static class Analyzer {
+        private final TargetDescription target;
+        private final LIRGenerationResult lirGenRes;
+        private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
+        private final LIRInsertionBuffer buffer;
+        private String cachedGroupName;
+        private final List<String> names;
+        private final List<String> groups;
+        private final List<Value> increments;
+
+        Analyzer(TargetDescription target, LIRGenerationResult lirGenRes, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
+            this.target = target;
+            this.lirGenRes = lirGenRes;
+            this.diagnosticLirGenTool = diagnosticLirGenTool;
+            this.buffer = new LIRInsertionBuffer();
+            this.names = new ArrayList<>();
+            this.groups = new ArrayList<>();
+            this.increments = new ArrayList<>();
+        }
+
+        public void run() {
+            LIR lir = lirGenRes.getLIR();
+            BlockMap<MoveStatistics> collected = MoveProfiler.profile(lir);
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                MoveStatistics moveStatistics = collected.get(block);
+                if (moveStatistics != null) {
+                    names.clear();
+                    groups.clear();
+                    increments.clear();
+                    doBlock(block, moveStatistics);
+                }
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block, MoveStatistics moveStatistics) {
+            // counter insertion phase
+            for (MoveType type : MoveType.values()) {
+                String name = type.toString();
+                // current run
+                addEntry(name, getGroupName(), moveStatistics.get(type));
+            }
+            insertBenchmarkCounter(block);
+        }
+
+        protected final void addEntry(String name, String groupName, int count) {
+            if (count > 0) {
+                names.add(name);
+                groups.add(groupName);
+                increments.add(new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.forInt(count)));
+            }
+        }
+
+        protected final void insertBenchmarkCounter(AbstractBlockBase<?> block) {
+            int size = names.size();
+            if (size > 0) { // Don't pollute LIR when nothing has to be done
+                assert size > 0 && size == groups.size() && size == increments.size();
+                List<LIRInstruction> instructions = lirGenRes.getLIR().getLIRforBlock(block);
+                LIRInstruction inst = diagnosticLirGenTool.createMultiBenchmarkCounter(names.toArray(new String[size]), groups.toArray(new String[size]),
+                                increments.toArray(new Value[size]));
+                assert inst != null;
+                buffer.init(instructions);
+                buffer.append(1, inst);
+                buffer.finish();
+            }
+        }
+
+        protected final String getGroupName() {
+            if (cachedGroupName == null) {
+                cachedGroupName = createGroupName();
+            }
+            return cachedGroupName;
+        }
+
+        protected String createGroupName() {
+            if (Options.LIRDynMoveProfilMethod.getValue()) {
+                return new StringBuilder('"').append(MOVE_OPERATIONS).append(':').append(lirGenRes.getCompilationUnitName()).append('"').toString();
+            }
+            return MOVE_OPERATIONS;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java
new file mode 100644
index 0000000..48fe1e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.profiling;
+
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+enum MoveType {
+    REG2REG("Reg", "Reg"),
+    STACK2REG("Reg", "Stack"),
+    CONST2REG("Reg", "Const"),
+    REG2STACK("Stack", "Reg"),
+    CONST2STACK("Stack", "Const"),
+    STACK2STACK("Stack", "Stack");
+
+    private final String name;
+
+    MoveType(String dst, String src) {
+        this.name = src + '2' + dst;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public static MoveType get(MoveOp move) {
+        AllocatableValue dst = move.getResult();
+        Value src = null;
+        if (move instanceof LoadConstantOp) {
+            if (isRegister(dst)) {
+                return CONST2REG;
+            } else if (isStackSlot(dst)) {
+                return CONST2STACK;
+            }
+        } else if (move instanceof ValueMoveOp) {
+            src = ((ValueMoveOp) move).getInput();
+            if (isRegister(dst)) {
+                if (isRegister(src)) {
+                    return REG2REG;
+                } else if (isStackSlot(src)) {
+                    return STACK2REG;
+                }
+            } else if (isStackSlot(dst)) {
+                if (isRegister(src)) {
+                    return REG2STACK;
+                } else if (isStackSlot(src)) {
+                    return STACK2STACK;
+                }
+            }
+        }
+        throw GraalError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java
new file mode 100644
index 0000000..10240c8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssa;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.JumpOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Utilities for working with Static-Single-Assignment LIR form.
+ *
+ * <h2>Representation of <code>PHI</code>s</h2>
+ *
+ * There is no explicit <code>PHI</code> {@linkplain LIRInstruction}. Instead, they are implemented
+ * as parallel copy that span across a control-flow edge.
+ *
+ * The variables introduced by <code>PHI</code>s of a specific {@linkplain AbstractBlockBase merge
+ * block} are {@linkplain LabelOp#setIncomingValues attached} to the {@linkplain LabelOp} of the
+ * block. The outgoing values from the predecessor are {@link JumpOp#setOutgoingValues input} to the
+ * {@linkplain BlockEndOp} of the predecessor. Because there are no critical edges we know that the
+ * {@link BlockEndOp} of the predecessor has to be a {@link JumpOp}.
+ *
+ * <h3>Example:</h3>
+ *
+ * <pre>
+ * B0 -> B1
+ *   ...
+ *   v0|i = ...
+ *   JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1
+ * ________________________________________________
+ *
+ * B2 -> B1
+ *   ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   JUMP ~[v1|i, v2|i] destination: B2 -> B1
+ * ________________________________________________
+ *
+ * B1 <- B0,B2
+ *   [v3|i, v4|i] = LABEL
+ *   ...
+ * </pre>
+ */
+public final class SSAUtil {
+
+    public interface PhiValueVisitor {
+        /**
+         * @param phiIn the incoming value at the merge block
+         * @param phiOut the outgoing value from the predecessor block
+         */
+        void visit(Value phiIn, Value phiOut);
+    }
+
+    /**
+     * Visits each phi value pair of an edge, i.e. the outgoing value from the predecessor and the
+     * incoming value to the merge block.
+     */
+    public static void forEachPhiValuePair(LIR lir, AbstractBlockBase<?> merge, AbstractBlockBase<?> pred, PhiValueVisitor visitor) {
+        if (merge.getPredecessorCount() < 2) {
+            return;
+        }
+        assert Arrays.asList(merge.getPredecessors()).contains(pred) : String.format("%s not in predecessor list: %s", pred, Arrays.toString(merge.getPredecessors()));
+        assert pred.getSuccessorCount() == 1 : String.format("Merge predecessor block %s has more than one successor? %s", pred, Arrays.toString(pred.getSuccessors()));
+        assert pred.getSuccessors()[0] == merge : String.format("Predecessor block %s has wrong successor: %s, should be: %s", pred, pred.getSuccessors()[0], merge);
+
+        JumpOp jump = phiOut(lir, pred);
+        LabelOp label = phiIn(lir, merge);
+
+        assert label.getIncomingSize() == jump.getOutgoingSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getIncomingSize(), jump.getOutgoingSize());
+        assert label.getPhiSize() == jump.getPhiSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getPhiSize(), jump.getPhiSize());
+
+        for (int i = 0; i < label.getPhiSize(); i++) {
+            visitor.visit(label.getIncomingValue(i), jump.getOutgoingValue(i));
+        }
+    }
+
+    private static JumpOp phiOut(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getSuccessorCount() == 1;
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        LIRInstruction op = instructions.get(index);
+        return (JumpOp) op;
+    }
+
+    public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getSuccessorCount() == 1;
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        assert instructions.get(index) instanceof JumpOp;
+        return index;
+    }
+
+    private static LabelOp phiIn(LIR lir, AbstractBlockBase<?> block) {
+        assert block.getPredecessorCount() > 1;
+        LabelOp label = (LabelOp) lir.getLIRforBlock(block).get(0);
+        return label;
+    }
+
+    public static void removePhiOut(LIR lir, AbstractBlockBase<?> block) {
+        JumpOp jump = phiOut(lir, block);
+        jump.clearOutgoingValues();
+    }
+
+    public static void removePhiIn(LIR lir, AbstractBlockBase<?> block) {
+        LabelOp label = phiIn(lir, block);
+        label.clearIncomingValues();
+    }
+
+    public static boolean verifySSAForm(LIR lir) {
+        return new SSAVerifier(lir).verify();
+    }
+
+    public static void verifyPhi(LIR lir, AbstractBlockBase<?> merge) {
+        assert merge.getPredecessorCount() > 1;
+        for (AbstractBlockBase<?> pred : merge.getPredecessors()) {
+            forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> {
+                assert phiIn.getValueKind().equals(phiOut.getValueKind()) ||
+                                (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && LIRKind.isUnknownReference(phiIn) && LIRKind.isValue(phiOut));
+            });
+        }
+    }
+
+    public static void forEachPhiRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) {
+        assert mode == OperandMode.DEF : "Wrong operand mode: " + mode;
+        assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label);
+
+        if (!label.isPhiIn()) {
+            return;
+        }
+        int idx = indexOfValue(label, targetValue);
+        assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label);
+
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            JumpOp jump = phiOut(lir, pred);
+            Value sourceValue = jump.getOutgoingValue(idx);
+            valueConsumer.visitValue(jump, sourceValue, null, null);
+        }
+
+    }
+
+    private static int indexOfValue(LabelOp label, Value value) {
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            if (label.getIncomingValue(i).equals(value)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java
new file mode 100644
index 0000000..abba3db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.lir.ssa;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.HashMap;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+final class SSAVerifier {
+    private static class Entry {
+        private final LIRInstruction inst;
+        private final AbstractBlockBase<?> block;
+
+        Entry(LIRInstruction inst, AbstractBlockBase<?> block) {
+            this.inst = inst;
+            this.block = block;
+        }
+    }
+
+    private final LIR lir;
+    private final BitSet visited;
+    private final HashMap<Value, Entry> defined;
+    private AbstractBlockBase<?> currentBlock;
+
+    SSAVerifier(LIR lir) {
+        this.lir = lir;
+        this.visited = new BitSet(lir.getControlFlowGraph().getBlocks().length);
+        this.defined = new HashMap<>();
+    }
+
+    @SuppressWarnings("try")
+    public boolean verify() {
+        try (Scope s = Debug.scope("SSAVerifier", lir)) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    private void doBlock(AbstractBlockBase<?> b) {
+        if (visited.get(b.getId())) {
+            return;
+        }
+        for (AbstractBlockBase<?> pred : b.getPredecessors()) {
+            if (!b.isLoopHeader() || !pred.isLoopEnd()) {
+                doBlock(pred);
+            }
+        }
+        try (Indent indent = Debug.logAndIndent(Debug.INFO_LOG_LEVEL, "handle block %s", b)) {
+            assert verifyBlock(b);
+        }
+    }
+
+    private boolean verifyBlock(AbstractBlockBase<?> block) {
+        currentBlock = block;
+        assert !visited.get(block.getId()) : "Block already visited: " + block;
+        visited.set(block.getId());
+        for (LIRInstruction op : lir.getLIRforBlock(block)) {
+            op.visitEachAlive(this::useConsumer);
+            op.visitEachState(this::useConsumer);
+            op.visitEachInput(this::useConsumer);
+
+            op.visitEachTemp(this::defConsumer);
+            op.visitEachOutput(this::defConsumer);
+
+        }
+        currentBlock = null;
+        return true;
+    }
+
+    /**
+     * @see InstructionValueConsumer
+     * @param mode
+     * @param flags
+     */
+    private void useConsumer(LIRInstruction inst, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if (shouldProcess(value)) {
+            assert defined.keySet().contains(value) || flags.contains(OperandFlag.UNINITIALIZED) : String.format("Value %s used at instruction %s in block %s but never defined", value, inst,
+                            currentBlock);
+        }
+    }
+
+    /**
+     * @see InstructionValueConsumer
+     * @param mode
+     * @param flags
+     */
+    private void defConsumer(LIRInstruction inst, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if (shouldProcess(value)) {
+            assert !defined.keySet().contains(value) : String.format("Value %s redefined at %s but never defined (previous definition %s in block %s)", value, inst, defined.get(value).inst,
+                            defined.get(value).block);
+            defined.put(value, new Entry(inst, currentBlock));
+        }
+    }
+
+    private static boolean shouldProcess(Value value) {
+        return !value.equals(Value.ILLEGAL) && !isJavaConstant(value) && !isRegister(value) && !isStackSlotValue(value);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/FastSSIBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/FastSSIBuilder.java
new file mode 100644
index 0000000..f1b2f41
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/FastSSIBuilder.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+public final class FastSSIBuilder extends SSIBuilderBase {
+
+    /**
+     * Bit map specifying which operands are live upon entry to this block. These are values used in
+     * this block or any of its successors where such value are not defined in this block. The bit
+     * index of an operand is its {@linkplain #operandNumber operand number}.
+     */
+    private final BitSet[] liveIns;
+
+    /**
+     * Bit map specifying which operands are live upon exit from this block. These are values used
+     * in a successor block that are either defined in this block or were live upon entry to this
+     * block. The bit index of an operand is its {@linkplain #operandNumber operand number}.
+     */
+    private final BitSet[] liveOuts;
+
+    private final AbstractBlockBase<?>[] blocks;
+
+    protected FastSSIBuilder(LIR lir) {
+        super(lir);
+        int numBlocks = lir.getControlFlowGraph().getBlocks().length;
+        this.liveIns = new BitSet[numBlocks];
+        this.liveOuts = new BitSet[numBlocks];
+        this.blocks = lir.getControlFlowGraph().getBlocks();
+    }
+
+    @Override
+    BitSet getLiveIn(final AbstractBlockBase<?> block) {
+        return liveIns[block.getId()];
+    }
+
+    @Override
+    BitSet getLiveOut(final AbstractBlockBase<?> block) {
+        return liveOuts[block.getId()];
+    }
+
+    private void setLiveIn(final AbstractBlockBase<?> block, final BitSet liveIn) {
+        liveIns[block.getId()] = liveIn;
+    }
+
+    private void setLiveOut(final AbstractBlockBase<?> block, final BitSet liveOut) {
+        liveOuts[block.getId()] = liveOut;
+    }
+
+    @Override
+    protected void buildIntern() {
+        Debug.log(1, "SSIConstruction block order: %s", Arrays.asList(blocks));
+        computeLiveness();
+    }
+
+    /**
+     * Gets the size of the {@link #liveIns} and {@link #liveOuts} sets for a basic block.
+     */
+    private int liveSetSize() {
+        return lir.numVariables();
+    }
+
+    private static int operandNumber(Value operand) {
+        if (isVariable(operand)) {
+            return asVariable(operand).index;
+        }
+        throw GraalError.shouldNotReachHere("Can only handle Variables: " + operand);
+    }
+
+    /**
+     * Computes live sets for each block.
+     */
+    @SuppressWarnings("try")
+    private void computeLiveness() {
+        // iterate all blocks
+        for (int i = blocks.length - 1; i >= 0; i--) {
+            final AbstractBlockBase<?> block = blocks[i];
+            try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "compute local live sets for block %s", block)) {
+
+                final BitSet liveIn = mergeLiveSets(block);
+                setLiveOut(block, (BitSet) liveIn.clone());
+
+                InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processUse(liveIn, operand);
+                    }
+                };
+                InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processDef(liveIn, operand, operands);
+                    }
+                };
+                if (Debug.isLogEnabled()) {
+                    Debug.log(LOG_LEVEL, "liveOut B%d %s", block.getId(), getLiveOut(block));
+                }
+
+                // iterate all instructions of the block
+                ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+                for (int j = instructions.size() - 1; j >= 0; j--) {
+                    final LIRInstruction op = instructions.get(j);
+
+                    try (Indent indent2 = Debug.logAndIndent(LOG_LEVEL, "handle op %d: %s", op.id(), op)) {
+                        op.visitEachOutput(defConsumer);
+                        op.visitEachTemp(defConsumer);
+                        op.visitEachState(useConsumer);
+                        op.visitEachAlive(useConsumer);
+                        op.visitEachInput(useConsumer);
+                    }
+                } // end of instruction iteration
+
+                setLiveIn(block, liveIn);
+                if (block.isLoopHeader()) {
+                    handleLoopHeader(block.getLoop(), liveIn);
+                }
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log(LOG_LEVEL, "liveIn  B%d %s", block.getId(), getLiveIn(block));
+                }
+
+            }
+        } // end of block iteration
+    }
+
+    /**
+     * All variables live at the beginning of a loop are live throughout the loop.
+     */
+    private void handleLoopHeader(Loop<?> loop, BitSet live) {
+        for (AbstractBlockBase<?> block : loop.getBlocks()) {
+            getLiveIn(block).or(live);
+            getLiveOut(block).or(live);
+        }
+    }
+
+    private BitSet mergeLiveSets(final AbstractBlockBase<?> block) {
+        assert block != null;
+        final BitSet liveOut = new BitSet(liveSetSize());
+        for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+            BitSet succLiveIn = getLiveIn(successor);
+            if (succLiveIn != null) {
+                liveOut.or(succLiveIn);
+            } else {
+                assert successor.isLoopHeader() : "Successor of " + block + " not yet processed and not loop header: " + successor;
+            }
+        }
+        return liveOut;
+    }
+
+    private static void processUse(final BitSet liveGen, Value operand) {
+        if (isVariable(operand)) {
+            int operandNum = operandNumber(operand);
+            liveGen.set(operandNum);
+            if (Debug.isLogEnabled()) {
+                Debug.log(LOG_LEVEL, "liveGen for operand %d(%s)", operandNum, operand);
+            }
+        }
+    }
+
+    private static void processDef(final BitSet liveGen, Value operand, Value[] operands) {
+        if (isVariable(operand)) {
+            int operandNum = operandNumber(operand);
+            if (operands[operandNum] == null) {
+                operands[operandNum] = operand;
+            }
+            liveGen.clear(operandNum);
+            if (Debug.isLogEnabled()) {
+                Debug.log(LOG_LEVEL, "liveKill for operand %d(%s)", operandNum, operand);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilder.java
new file mode 100644
index 0000000..41703eb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilder.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+public final class SSIBuilder extends SSIBuilderBase {
+
+    private static class BlockData {
+
+        /**
+         * Bit map specifying which operands are live upon entry to this block. These are values
+         * used in this block or any of its successors where such value are not defined in this
+         * block. The bit index of an operand is its {@linkplain #operandNumber operand number}.
+         */
+        public BitSet liveIn;
+
+        /**
+         * Bit map specifying which operands are live upon exit from this block. These are values
+         * used in a successor block that are either defined in this block or were live upon entry
+         * to this block. The bit index of an operand is its {@linkplain #operandNumber operand
+         * number}.
+         */
+        public BitSet liveOut;
+
+        /**
+         * Bit map specifying which operands are used (before being defined) in this block. That is,
+         * these are the values that are live upon entry to the block. The bit index of an operand
+         * is its {@linkplain #operandNumber operand number}.
+         */
+        public BitSet liveGen;
+
+        /**
+         * Bit map specifying which operands are defined/overwritten in this block. The bit index of
+         * an operand is its {@linkplain #operandNumber operand number}.
+         */
+        public BitSet liveKill;
+    }
+
+    private final BlockMap<SSIBuilder.BlockData> blockData;
+
+    protected SSIBuilder(LIR lir) {
+        super(lir);
+        this.blockData = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    @Override
+    protected void buildIntern() {
+        init();
+        computeLocalLiveSets();
+        computeGlobalLiveSets();
+    }
+
+    /**
+     * Gets the size of the {@link BlockData#liveIn} and {@link BlockData#liveOut} sets for a basic
+     * block.
+     */
+    private int liveSetSize() {
+        return getLIR().numVariables();
+    }
+
+    AbstractBlockBase<?>[] getBlocks() {
+        return getLIR().getControlFlowGraph().getBlocks();
+    }
+
+    static int operandNumber(Value operand) {
+        if (isVariable(operand)) {
+            return asVariable(operand).index;
+        }
+        throw GraalError.shouldNotReachHere("Can only handle Variables: " + operand);
+    }
+
+    private SSIBuilder.BlockData getBlockData(AbstractBlockBase<?> block) {
+        return blockData.get(block);
+    }
+
+    private void initBlockData(AbstractBlockBase<?> block) {
+        blockData.put(block, new SSIBuilder.BlockData());
+    }
+
+    private void init() {
+        for (AbstractBlockBase<?> block : getBlocks()) {
+            initBlockData(block);
+        }
+    }
+
+    /**
+     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
+     * separately for each block.
+     */
+    @SuppressWarnings("try")
+    private void computeLocalLiveSets() {
+        int liveSize = liveSetSize();
+
+        // iterate all blocks
+        AbstractBlockBase<?>[] blocks = getBlocks();
+        for (int i = blocks.length - 1; i >= 0; i--) {
+            final AbstractBlockBase<?> block = blocks[i];
+            try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "compute local live sets for block %s", block)) {
+
+                final BitSet liveGen = new BitSet(liveSize);
+                final BitSet liveKill = new BitSet(liveSize);
+
+                InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processLocalUse(liveGen, operand);
+                    }
+                };
+                InstructionValueConsumer aliveConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processLocalUse(liveGen, operand);
+                    }
+                };
+                InstructionValueConsumer stateConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        if (isVariable(operand)) {
+                            int operandNum = operandNumber(operand);
+                            if (!liveKill.get(operandNum)) {
+                                liveGen.set(operandNum);
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log(LOG_LEVEL, "liveGen in state for operand %d(%s)", operandNum, operand);
+                                }
+                            }
+                        }
+                    }
+                };
+                InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processLocalDef(liveGen, liveKill, operand, operands);
+                    }
+                };
+                InstructionValueConsumer tempConsumer = new InstructionValueConsumer() {
+                    @Override
+                    public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        processLocalDef(liveGen, liveKill, operand, operands);
+                    }
+                };
+
+                // iterate all instructions of the block
+                List<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
+                ListIterator<LIRInstruction> instIt = instructions.listIterator(instructions.size());
+                while (instIt.hasPrevious()) {
+                    final LIRInstruction op = instIt.previous();
+
+                    try (Indent indent2 = Debug.logAndIndent(LOG_LEVEL, "handle op %d: %s", op.id(), op)) {
+                        op.visitEachOutput(defConsumer);
+                        op.visitEachTemp(tempConsumer);
+                        op.visitEachState(stateConsumer);
+                        op.visitEachAlive(aliveConsumer);
+                        op.visitEachInput(useConsumer);
+                    }
+                } // end of instruction iteration
+
+                SSIBuilder.BlockData blockSets = getBlockData(block);
+                blockSets.liveGen = liveGen;
+                blockSets.liveKill = liveKill;
+                blockSets.liveIn = new BitSet(liveSize);
+                blockSets.liveOut = new BitSet(liveSize);
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log(LOG_LEVEL, "liveGen  B%d %s", block.getId(), blockSets.liveGen);
+                    Debug.log(LOG_LEVEL, "liveKill B%d %s", block.getId(), blockSets.liveKill);
+                }
+
+            }
+        } // end of block iteration
+    }
+
+    private static void processLocalUse(final BitSet liveGen, Value operand) {
+        if (isVariable(operand)) {
+            int operandNum = operandNumber(operand);
+            liveGen.set(operandNum);
+            if (Debug.isLogEnabled()) {
+                Debug.log(LOG_LEVEL, "liveGen for operand %d(%s)", operandNum, operand);
+            }
+        }
+    }
+
+    private static void processLocalDef(final BitSet liveGen, final BitSet liveKill, Value operand, Value[] operands) {
+        if (isVariable(operand)) {
+            int operandNum = operandNumber(operand);
+            if (operands[operandNum] == null) {
+                operands[operandNum] = operand;
+            }
+            liveKill.set(operandNum);
+            liveGen.clear(operandNum);
+            if (Debug.isLogEnabled()) {
+                Debug.log(LOG_LEVEL, "liveKill for operand %d(%s)", operandNum, operand);
+            }
+        }
+    }
+
+    /**
+     * Performs a backward dataflow analysis to compute global live sets (i.e.
+     * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
+     */
+    @SuppressWarnings("try")
+    private void computeGlobalLiveSets() {
+        try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "compute global live sets")) {
+            boolean changeOccurred;
+            boolean changeOccurredInBlock;
+            int iterationCount = 0;
+            BitSet liveOut = new BitSet(liveSetSize()); // scratch set for
+                                                        // calculations
+
+            /*
+             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
+             * The loop is executed until a fixpoint is reached (no changes in an iteration).
+             */
+            do {
+                changeOccurred = false;
+
+                try (Indent indent2 = Debug.logAndIndent(LOG_LEVEL, "new iteration %d", iterationCount)) {
+
+                    // iterate all blocks in reverse order
+                    AbstractBlockBase<?>[] blocks = getBlocks();
+                    for (int i = blocks.length - 1; i >= 0; i--) {
+                        final AbstractBlockBase<?> block = blocks[i];
+                        SSIBuilder.BlockData blockSets = getBlockData(block);
+
+                        changeOccurredInBlock = false;
+
+                        /*
+                         * liveOut(block) is the union of liveIn(sux), for successors sux of block.
+                         */
+                        int n = block.getSuccessorCount();
+                        if (n > 0) {
+                            // block has successors
+                            liveOut.clear();
+                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+                                liveOut.or(getBlockData(successor).liveIn);
+                            }
+
+                            if (!blockSets.liveOut.equals(liveOut)) {
+                                /*
+                                 * A change occurred. Swap the old and new live out sets to avoid
+                                 * copying.
+                                 */
+                                BitSet temp = blockSets.liveOut;
+                                blockSets.liveOut = liveOut;
+                                liveOut = temp;
+
+                                changeOccurred = true;
+                                changeOccurredInBlock = true;
+                            }
+                        }
+
+                        if (iterationCount == 0 || changeOccurredInBlock) {
+                            /*
+                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
+                             * !liveKill(block)).
+                             *
+                             * Note: liveIn has to be computed only in first iteration or if liveOut
+                             * has changed!
+                             */
+                            BitSet liveIn = blockSets.liveIn;
+                            liveIn.clear();
+                            liveIn.or(blockSets.liveOut);
+                            liveIn.andNot(blockSets.liveKill);
+                            liveIn.or(blockSets.liveGen);
+
+                            if (Debug.isLogEnabled()) {
+                                Debug.log(LOG_LEVEL, "block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            }
+                        }
+                    }
+                    iterationCount++;
+
+                    if (changeOccurred && iterationCount > 50) {
+                        /*
+                         * Very unlikely should never happen: If it happens we cannot guarantee it
+                         * won't happen again.
+                         */
+                        throw new PermanentBailoutException("too many iterations in computeGlobalLiveSets");
+                    }
+                }
+            } while (changeOccurred);
+        }
+    }
+
+    @Override
+    BitSet getLiveIn(final AbstractBlockBase<?> block) {
+        return getBlockData(block).liveIn;
+    }
+
+    @Override
+    BitSet getLiveOut(final AbstractBlockBase<?> block) {
+        return getBlockData(block).liveOut;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilderBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilderBase.java
new file mode 100644
index 0000000..1266b7b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIBuilderBase.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+
+import jdk.vm.ci.meta.Value;
+
+public abstract class SSIBuilderBase {
+
+    protected static final int LOG_LEVEL = Debug.INFO_LOG_LEVEL;
+    protected final Value[] operands;
+    protected final LIR lir;
+
+    public SSIBuilderBase(LIR lir) {
+        this.lir = lir;
+        this.operands = new Value[lir.numVariables()];
+    }
+
+    protected LIR getLIR() {
+        return lir;
+    }
+
+    abstract BitSet getLiveIn(AbstractBlockBase<?> block);
+
+    abstract BitSet getLiveOut(AbstractBlockBase<?> block);
+
+    public final void build() {
+        buildIntern();
+        // check that the liveIn set of the first block is empty
+        AbstractBlockBase<?> startBlock = getLIR().getControlFlowGraph().getStartBlock();
+        if (getLiveIn(startBlock).cardinality() != 0) {
+            // bailout if this occurs in product mode.
+            throw new GraalError("liveIn set of first block must be empty: " + getLiveIn(startBlock));
+        }
+    }
+
+    protected abstract void buildIntern();
+
+    @SuppressWarnings("try")
+    public final void finish() {
+        // iterate all blocks in reverse order
+        for (AbstractBlockBase<?> block : (AbstractBlockBase<?>[]) lir.getControlFlowGraph().getBlocks()) {
+            try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "Finish Block %s", block)) {
+                // set label
+                buildOutgoing(block, getLiveOut(block));
+                buildIncoming(block, getLiveIn(block));
+            }
+        }
+    }
+
+    private void buildIncoming(AbstractBlockBase<?> block, BitSet liveIn) {
+        /*
+         * Collect live out of predecessors since there might be values not used in this block which
+         * might cause out/in mismatch.
+         */
+        BitSet predLiveOut = new BitSet(liveIn.length());
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            predLiveOut.or(getLiveOut(pred));
+        }
+        if (predLiveOut.isEmpty()) {
+            return;
+        }
+
+        Value[] values = new Value[predLiveOut.cardinality()];
+        assert values.length > 0;
+        int cnt = 0;
+        for (int i = predLiveOut.nextSetBit(0); i >= 0; i = predLiveOut.nextSetBit(i + 1)) {
+            values[cnt++] = liveIn.get(i) ? operands[i] : Value.ILLEGAL;
+        }
+        LabelOp label = SSIUtil.incoming(getLIR(), block);
+        label.addIncomingValues(values);
+    }
+
+    private void buildOutgoing(AbstractBlockBase<?> block, BitSet liveOut) {
+        if (liveOut.isEmpty()) {
+            return;
+        }
+        Value[] values = new Value[liveOut.cardinality()];
+        assert values.length > 0;
+        int cnt = 0;
+        for (int i = liveOut.nextSetBit(0); i >= 0; i = liveOut.nextSetBit(i + 1)) {
+            values[cnt++] = operands[i];
+        }
+        BlockEndOp blockEndOp = SSIUtil.outgoing(getLIR(), block);
+        blockEndOp.addOutgoingValues(values);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIConstructionPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIConstructionPhase.java
new file mode 100644
index 0000000..1cf418d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIConstructionPhase.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.ssa.SSAUtil;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.StableOptionValue;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+
+/**
+ * Constructs {@linkplain SSIUtil SSI LIR} using a liveness analysis.
+ *
+ * Implementation derived from {@link LinearScanLifetimeAnalysisPhase}.
+ *
+ * @see SSIUtil
+ */
+public final class SSIConstructionPhase extends AllocationPhase {
+
+    static class Options {
+
+        //@formatter:off
+        @Option(help = "Use fast SSI builder.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceRAFastSSIBuilder = new StableOptionValue<>(true);
+        //@formatter:on
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
+        if (Options.TraceRAFastSSIBuilder.getValue()) {
+            FastSSIBuilder fastSSIBuilder = new FastSSIBuilder(lirGenRes.getLIR());
+            fastSSIBuilder.build();
+            fastSSIBuilder.finish();
+        } else {
+            SSIBuilder ssiBuilder = new SSIBuilder(lirGenRes.getLIR());
+            ssiBuilder.build();
+            ssiBuilder.finish();
+        }
+    }
+
+    static void check(AbstractBlockBase<?>[] blocks, SSIBuilderBase liveSets1, SSIBuilderBase liveSets2) {
+        for (AbstractBlockBase<?> block : blocks) {
+            check(block, liveSets1.getLiveIn(block), liveSets2.getLiveIn(block));
+            check(block, liveSets1.getLiveOut(block), liveSets2.getLiveOut(block));
+        }
+    }
+
+    private static void check(AbstractBlockBase<?> block, BitSet liveIn1, BitSet liveIn2) {
+        if (!liveIn1.equals(liveIn2)) {
+            throw JVMCIError.shouldNotReachHere(String.format("%s LiveSet differ: %s vs %s", block, liveIn1, liveIn2));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIUtil.java
new file mode 100644
index 0000000..f48a8e5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIUtil.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+import org.graalvm.compiler.lir.ValueConsumer;
+import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Utilities for working with Static-Single-Information LIR form.
+ *
+ * <h2>Representation of &phi; and &sigma;</h2>
+ *
+ * There are no explicit &phi;/&sigma; {@link LIRInstruction}s. Instead, they are implemented as
+ * parallel copy that spans across a control-flow edge.
+ *
+ * The variables introduced by &phi;/&sigma; of a specific {@linkplain AbstractBlockBase block} are
+ * {@linkplain LabelOp#setIncomingValues attached} to the {@link LabelOp} of the block. The outgoing
+ * values from the predecessor are {@linkplain BlockEndOp#setOutgoingValues input} to the
+ * {@link BlockEndOp} of the predecessor.
+ *
+ * When it does not matter whether we are talking about a &phi; or a &sigma; we call the values that
+ * are defined by a label {@linkplain LabelOp#setIncomingValues incoming} and the values that are
+ * input to the {@link BlockEndOp} of the predecessor {@linkplain BlockEndOp#setOutgoingValues
+ * outgoing}.
+ *
+ * <h2>Implementation Details</h2>
+ *
+ * For our purposes we want a <em>maximal</em> SSI form, which means that all values that are alive
+ * across basic block boundaries are gated with a &phi;/&sigma;. In other words the outgoing and
+ * incoming values of the {@link BlockEndOp} and {@link LabelOp} are equivalent to the live-out and
+ * live-in set of the corresponding block.
+ *
+ * As a side effect variables are local to a block. We reuse the name of the predecessor if they
+ * represent the same value (i.e. not a real &phi; definition).
+ *
+ * <h2>Examples</h2>
+ *
+ * <h3>Merge (&phi;)</h3>
+ *
+ * <pre>
+ * B0 -> B1
+ *   ...
+ *   v0|i = ...
+ *   JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1
+ * ________________________________________________
+ *
+ * B2 -> B1
+ *   ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   JUMP ~[v1|i, v2|i] destination: B2 -> B1
+ * ________________________________________________
+ *
+ * B1 <- B0,B2
+ *   [v3|i, v4|i] = LABEL
+ *   ...
+ * </pre>
+ *
+ * Note: the outgoing values of a block can contain constants (see <code>B0</code>).
+ *
+ * <h3>Split (&sigma;)</h3>
+ *
+ * <pre>
+ * B0 -> B1,B2
+ *   ...
+ *   v0|i = ...
+ *   v1|i = ...
+ *   v2|i = ...
+ *   TEST (x: v1|i, y: v1|i)
+ *   BRANCH ~[v2|i, v0|j] condition: <, true: B1 false: B2
+ * ________________________________________________
+ *
+ * B1 <- B0
+ *   [-, v0|j] = LABEL
+ *   ...
+ * ________________________________________________
+ *
+ * B2 <- B0
+ *   [v2|i, v0|j] = LABEL
+ *   ...
+ * </pre>
+ *
+ * Note: If a incoming value is not needed in a branch it is {@link Value#ILLEGAL ignored} (see
+ * <code>B1<code>).
+ */
+public final class SSIUtil {
+
+    public static BlockEndOp outgoing(LIR lir, AbstractBlockBase<?> block) {
+        return (BlockEndOp) outgoingInst(lir, block);
+    }
+
+    public static LIRInstruction outgoingInst(LIR lir, AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        int index = instructions.size() - 1;
+        LIRInstruction op = instructions.get(index);
+        return op;
+    }
+
+    public static LabelOp incoming(LIR lir, AbstractBlockBase<?> block) {
+        return (LabelOp) incomingInst(lir, block);
+    }
+
+    private static LIRInstruction incomingInst(LIR lir, AbstractBlockBase<?> block) {
+        return lir.getLIRforBlock(block).get(0);
+    }
+
+    public static void removeIncoming(LIR lir, AbstractBlockBase<?> block) {
+        incoming(lir, block).clearIncomingValues();
+    }
+
+    public static void removeOutgoing(LIR lir, AbstractBlockBase<?> block) {
+        outgoing(lir, block).clearOutgoingValues();
+    }
+
+    /**
+     * Visits each SIGMA/PHI value pair of an edge, i.e. the outgoing value from the predecessor and
+     * the incoming value to the merge block.
+     */
+    public static void forEachValuePair(LIR lir, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock, PhiValueVisitor visitor) {
+        assert Arrays.asList(toBlock.getPredecessors()).contains(fromBlock) : String.format("%s not in predecessor list: %s", fromBlock, Arrays.toString(toBlock.getPredecessors()));
+        assert fromBlock.getSuccessorCount() == 1 || toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s has %d successors and %s has %d predecessors", fromBlock,
+                        fromBlock.getSuccessorCount(), toBlock, toBlock.getPredecessorCount());
+        assert Arrays.asList(fromBlock.getSuccessors()).contains(toBlock) : String.format("Predecessor block %s has wrong successor: %s, should contain: %s", fromBlock,
+                        Arrays.toString(fromBlock.getSuccessors()), toBlock);
+
+        BlockEndOp blockEnd = outgoing(lir, fromBlock);
+        LabelOp label = incoming(lir, toBlock);
+
+        assert label.getIncomingSize() == blockEnd.getOutgoingSize() : String.format("In/Out size mismatch: in=%d vs. out=%d, blocks %s vs. %s", label.getIncomingSize(), blockEnd.getOutgoingSize(),
+                        toBlock, fromBlock);
+        assert label.getPhiSize() == blockEnd.getPhiSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getPhiSize(), blockEnd.getPhiSize());
+
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            visitor.visit(label.getIncomingValue(i), blockEnd.getOutgoingValue(i));
+        }
+    }
+
+    public static void forEachRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) {
+        assert mode == OperandMode.DEF : "Wrong operand mode: " + mode;
+        assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label);
+
+        if (!label.isPhiIn()) {
+            return;
+        }
+        int idx = indexOfValue(label, targetValue);
+        assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label);
+
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            BlockEndOp blockEnd = outgoing(lir, pred);
+            Value sourceValue = blockEnd.getOutgoingValue(idx);
+            valueConsumer.visitValue((LIRInstruction) blockEnd, sourceValue, null, null);
+        }
+
+    }
+
+    private static int indexOfValue(LabelOp label, Value value) {
+        for (int i = 0; i < label.getIncomingSize(); i++) {
+            if (label.getIncomingValue(i).equals(value)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIVerifier.java
new file mode 100644
index 0000000..e14b2f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/SSIVerifier.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.ssi;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelOp;
+
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class SSIVerifier {
+
+    public static boolean verify(LIR lir) {
+        return new SSIVerifier(lir).verify();
+    }
+
+    private final LIR lir;
+
+    private SSIVerifier(LIR lir) {
+        this.lir = lir;
+    }
+
+    @SuppressWarnings("try")
+    private boolean verify() {
+        try (Scope s = Debug.scope("SSIVerifier", lir)) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return true;
+    }
+
+    private void doBlock(AbstractBlockBase<?> block) {
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            verifyEdge(block, succ);
+        }
+        verifyInstructions(block);
+    }
+
+    private void verifyEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+        BlockEndOp out = SSIUtil.outgoing(lir, from);
+        LabelOp in = SSIUtil.incoming(lir, to);
+        int outgoingSize = out.getOutgoingSize();
+        int incomingSize = in.getIncomingSize();
+        assert outgoingSize == incomingSize : String.format("Outgoing size %d and incoming size %d do not match", outgoingSize, incomingSize);
+
+        for (int i = 0; i < outgoingSize; i++) {
+            Value incomingValue = in.getIncomingValue(i);
+            Value outgoingValue = out.getOutgoingValue(i);
+            ValueKind<?> inLIRKind = incomingValue.getValueKind();
+            ValueKind<?> outLIRKind = outgoingValue.getValueKind();
+            assert LIRKind.verifyMoveKinds(inLIRKind, outLIRKind) || incomingValue.equals(Value.ILLEGAL) : String.format("Outgoing LIRKind %s (%s) an and incoming LIRKind %s (%s) do not match",
+                            outgoingValue, outLIRKind, incomingValue, inLIRKind);
+        }
+    }
+
+    private void verifyInstructions(AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        HashMap<Value, LIRInstruction> defined = new HashMap<>();
+
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (checkUsage(value)) {
+                    assert defined.containsKey(value) || flags.contains(OperandFlag.UNINITIALIZED) : String.format("Value %s is used by instruction %s in block %s but not defined.", value,
+                                    instruction, block);
+                }
+            }
+        };
+        InstructionValueConsumer stateConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (checkUsage(value)) {
+                    /*
+                     * TODO (je): There are undefined stack values used for locks. Ignore them for
+                     * the time being.
+                     */
+                    assert defined.containsKey(value) || isVirtualStackSlot(value) : String.format("Value %s is used in state of instruction %s in block %s but not defined.", value, instruction,
+                                    block);
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (trackDefinition(value)) {
+                    assert !defined.containsKey(value) : String.format("Value %s is redefined by instruction %s in block %s but already defined by %s.", value, instruction, block, defined.get(value));
+                    defined.put(value, instruction);
+                }
+            }
+        };
+
+        for (LIRInstruction op : instructions) {
+            op.visitEachAlive(useConsumer);
+            op.visitEachInput(useConsumer);
+            op.visitEachState(stateConsumer);
+
+            op.visitEachTemp(defConsumer);
+            op.visitEachOutput(defConsumer);
+        }
+    }
+
+    private static boolean trackDefinition(Value value) {
+        if (isRegister(value)) {
+            // registers can be redefined
+            return false;
+        }
+        if (isStackSlotValue(value) && !isVirtualStackSlot(value)) {
+            // non-virtual stack slots can be redefined
+            return false;
+        }
+        if (value.equals(Value.ILLEGAL)) {
+            // Don't care about illegal values
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean checkUsage(Value value) {
+        if (isConstantValue(value)) {
+            // Constants do not need to be defined
+            return false;
+        }
+        if (isRegister(value)) {
+            // Assume fixed registers are correct
+            return false;
+        }
+        if (isStackSlotValue(value)) {
+            // stack slots are assumed to be correct
+            return false;
+        }
+        if (value.equals(Value.ILLEGAL)) {
+            // Don't care about illegal values
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java
new file mode 100644
index 0000000..3494511
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+
+import java.util.ArrayDeque;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Calculates the stack intervals using a worklist-based backwards data-flow analysis.
+ */
+final class FixPointIntervalBuilder {
+    private final BlockMap<BitSet> liveInMap;
+    private final BlockMap<BitSet> liveOutMap;
+    private final LIR lir;
+    private final int maxOpId;
+    private final StackInterval[] stackSlotMap;
+    private final HashSet<LIRInstruction> usePos;
+
+    /**
+     * The number of allocated stack slots.
+     */
+    private static final DebugCounter uninitializedSlots = Debug.counter("StackSlotAllocator[uninitializedSlots]");
+
+    FixPointIntervalBuilder(LIR lir, StackInterval[] stackSlotMap, int maxOpId) {
+        this.lir = lir;
+        this.stackSlotMap = stackSlotMap;
+        this.maxOpId = maxOpId;
+        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+        this.usePos = new HashSet<>();
+    }
+
+    /**
+     * Builds the lifetime intervals for {@link VirtualStackSlot virtual stack slots}, sets up
+     * {@link #stackSlotMap} and returns a set of use positions, i.e. instructions that contain
+     * virtual stack slots.
+     */
+    Set<LIRInstruction> build() {
+        Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
+        AbstractBlockBase<?>[] blocks = lir.getControlFlowGraph().getBlocks();
+        for (int i = blocks.length - 1; i >= 0; i--) {
+            worklist.add(blocks[i]);
+        }
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            liveInMap.put(block, new BitSet(stackSlotMap.length));
+        }
+        while (!worklist.isEmpty()) {
+            AbstractBlockBase<?> block = worklist.poll();
+            processBlock(block, worklist);
+        }
+        return usePos;
+    }
+
+    /**
+     * Merge outSet with in-set of successors.
+     */
+    private boolean updateOutBlock(AbstractBlockBase<?> block) {
+        BitSet union = new BitSet(stackSlotMap.length);
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            union.or(liveInMap.get(succ));
+        }
+        BitSet outSet = liveOutMap.get(block);
+        // check if changed
+        if (outSet == null || !union.equals(outSet)) {
+            liveOutMap.put(block, union);
+            return true;
+        }
+        return false;
+    }
+
+    @SuppressWarnings("try")
+    private void processBlock(AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                // get out set and mark intervals
+                BitSet outSet = liveOutMap.get(block);
+                markOutInterval(outSet, getBlockEnd(instructions));
+                printLiveSet("liveOut", outSet);
+
+                // process instructions
+                BlockClosure closure = new BlockClosure((BitSet) outSet.clone());
+                for (int i = instructions.size() - 1; i >= 0; i--) {
+                    LIRInstruction inst = instructions.get(i);
+                    closure.processInstructionBottomUp(inst);
+                }
+
+                // add predecessors to work list
+                for (AbstractBlockBase<?> b : block.getPredecessors()) {
+                    worklist.add(b);
+                }
+                // set in set and mark intervals
+                BitSet inSet = closure.getCurrentSet();
+                liveInMap.put(block, inSet);
+                markInInterval(inSet, getBlockBegin(instructions));
+                printLiveSet("liveIn", inSet);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void printLiveSet(String label, BitSet liveSet) {
+        if (Debug.isLogEnabled()) {
+            try (Indent indent = Debug.logAndIndent(label)) {
+                Debug.log("%s", liveSetToString(liveSet));
+            }
+        }
+    }
+
+    private String liveSetToString(BitSet liveSet) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            sb.append(interval.getOperand()).append(" ");
+        }
+        return sb.toString();
+    }
+
+    private void markOutInterval(BitSet outSet, int blockEndOpId) {
+        for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            Debug.log("mark live operand: %s", interval.getOperand());
+            interval.addTo(blockEndOpId);
+        }
+    }
+
+    private void markInInterval(BitSet inSet, int blockFirstOpId) {
+        for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) {
+            StackInterval interval = getIntervalFromStackId(i);
+            Debug.log("mark live operand: %s", interval.getOperand());
+            interval.addFrom(blockFirstOpId);
+        }
+    }
+
+    private final class BlockClosure {
+        private final BitSet currentSet;
+
+        private BlockClosure(BitSet set) {
+            currentSet = set;
+        }
+
+        private BitSet getCurrentSet() {
+            return currentSet;
+        }
+
+        /**
+         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
+         * that start or end at the current operation are not included.
+         */
+        @SuppressWarnings("try")
+        private void processInstructionBottomUp(LIRInstruction op) {
+            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+                // kills
+                op.visitEachTemp(defConsumer);
+                op.visitEachOutput(defConsumer);
+
+                // gen - values that are considered alive for this state
+                op.visitEachAlive(useConsumer);
+                op.visitEachState(useConsumer);
+                // mark locations
+                // gen
+                op.visitEachInput(useConsumer);
+            }
+        }
+
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(operand)) {
+                    VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                    addUse(vslot, inst, flags);
+                    addRegisterHint(inst, vslot, mode, flags, false);
+                    usePos.add(inst);
+                    Debug.log("set operand: %s", operand);
+                    currentSet.set(vslot.getId());
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+            @Override
+            public void visitValue(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(operand)) {
+                    VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                    addDef(vslot, inst);
+                    addRegisterHint(inst, vslot, mode, flags, true);
+                    usePos.add(inst);
+                    Debug.log("clear operand: %s", operand);
+                    currentSet.clear(vslot.getId());
+                }
+
+            }
+        };
+
+        private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet<OperandFlag> flags) {
+            StackInterval interval = getOrCreateInterval(stackSlot);
+            if (flags.contains(OperandFlag.UNINITIALIZED)) {
+                // Stack slot is marked uninitialized so we have to assume it is live all
+                // the time.
+                if (Debug.isCountEnabled() && !(interval.from() == 0 && interval.to() == maxOpId)) {
+                    uninitializedSlots.increment();
+                }
+                interval.addFrom(0);
+                interval.addTo(maxOpId);
+            } else {
+                interval.addTo(inst.id());
+            }
+        }
+
+        private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) {
+            StackInterval interval = getOrCreateInterval(stackSlot);
+            interval.addFrom(inst.id());
+        }
+
+        void addRegisterHint(final LIRInstruction op, VirtualStackSlot targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+            if (flags.contains(OperandFlag.HINT)) {
+                InstructionValueProcedure proc = new InstructionValueProcedure() {
+                    @Override
+                    public Value doValue(LIRInstruction instruction, Value registerHint, OperandMode vaueMode, EnumSet<OperandFlag> valueFlags) {
+                        if (isVirtualStackSlot(registerHint)) {
+                            StackInterval from = getOrCreateInterval((VirtualStackSlot) registerHint);
+                            StackInterval to = getOrCreateInterval(targetValue);
+
+                            // hints always point from def to use
+                            if (hintAtDef) {
+                                to.setLocationHint(from);
+                            } else {
+                                from.setLocationHint(to);
+                            }
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("operation %s at opId %d: added hint from interval %d to %d", op, op.id(), from, to);
+                            }
+
+                            return registerHint;
+                        }
+                        return null;
+                    }
+                };
+                op.forEachRegisterHint(targetValue, mode, proc);
+            }
+        }
+
+    }
+
+    private StackInterval get(VirtualStackSlot stackSlot) {
+        return stackSlotMap[stackSlot.getId()];
+    }
+
+    private void put(VirtualStackSlot stackSlot, StackInterval interval) {
+        stackSlotMap[stackSlot.getId()] = interval;
+    }
+
+    private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) {
+        StackInterval interval = get(stackSlot);
+        if (interval == null) {
+            interval = new StackInterval(stackSlot, stackSlot.getValueKind());
+            put(stackSlot, interval);
+        }
+        return interval;
+    }
+
+    private StackInterval getIntervalFromStackId(int id) {
+        return stackSlotMap[id];
+    }
+
+    private static int getBlockBegin(List<LIRInstruction> instructions) {
+        return instructions.get(0).id();
+    }
+
+    private static int getBlockEnd(List<LIRInstruction> instructions) {
+        return instructions.get(instructions.size() - 1).id() + 1;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java
new file mode 100644
index 0000000..c592820
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static org.graalvm.compiler.lir.phases.LIRPhase.Options.LIROptimization;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
+import org.graalvm.compiler.lir.framemap.SimpleVirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.VirtualStackSlotRange;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Linear Scan {@link StackSlotAllocatorUtil stack slot allocator}.
+ * <p>
+ * <b>Remark:</b> The analysis works under the assumption that a stack slot is no longer live after
+ * its last usage. If an {@link LIRInstruction instruction} transfers the raw address of the stack
+ * slot to another location, e.g. a registers, and this location is referenced later on, the
+ * {@link org.graalvm.compiler.lir.LIRInstruction.Use usage} of the stack slot must be marked with
+ * the {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
+ * destroyed.
+ */
+public final class LSStackSlotAllocator extends AllocationPhase {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use linear scan stack slot allocation.", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptLSStackSlotAllocator = new NestedBooleanOptionValue(LIROptimization, true);
+        // @formatter:on
+    }
+
+    private static final DebugTimer MainTimer = Debug.timer("LSStackSlotAllocator");
+    private static final DebugTimer NumInstTimer = Debug.timer("LSStackSlotAllocator[NumberInstruction]");
+    private static final DebugTimer BuildIntervalsTimer = Debug.timer("LSStackSlotAllocator[BuildIntervals]");
+    private static final DebugTimer VerifyIntervalsTimer = Debug.timer("LSStackSlotAllocator[VerifyIntervals]");
+    private static final DebugTimer AllocateSlotsTimer = Debug.timer("LSStackSlotAllocator[AllocateSlots]");
+    private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        allocateStackSlots((FrameMapBuilderTool) lirGenRes.getFrameMapBuilder(), lirGenRes);
+        lirGenRes.buildFrameMap();
+    }
+
+    @SuppressWarnings("try")
+    public static void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
+        if (builder.getNumberOfStackSlots() > 0) {
+            try (DebugCloseable t = MainTimer.start()) {
+                new Allocator(res.getLIR(), builder).allocate();
+            }
+        }
+    }
+
+    private static final class Allocator {
+        private final LIR lir;
+        private final FrameMapBuilderTool frameMapBuilder;
+        private final StackInterval[] stackSlotMap;
+        private final PriorityQueue<StackInterval> unhandled;
+        private final PriorityQueue<StackInterval> active;
+        private final AbstractBlockBase<?>[] sortedBlocks;
+        private final int maxOpId;
+
+        @SuppressWarnings("try")
+        private Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) {
+            this.lir = lir;
+            this.frameMapBuilder = frameMapBuilder;
+            this.stackSlotMap = new StackInterval[frameMapBuilder.getNumberOfStackSlots()];
+            this.sortedBlocks = lir.getControlFlowGraph().getBlocks();
+
+            // insert by from
+            this.unhandled = new PriorityQueue<>((a, b) -> a.from() - b.from());
+            // insert by to
+            this.active = new PriorityQueue<>((a, b) -> a.to() - b.to());
+
+            try (DebugCloseable t = NumInstTimer.start()) {
+                // step 1: number instructions
+                this.maxOpId = numberInstructions(lir, sortedBlocks);
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void allocate() {
+            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot numbering");
+
+            long currentFrameSize = StackSlotAllocatorUtil.allocatedFramesize.isEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0;
+            Set<LIRInstruction> usePos;
+            // step 2: build intervals
+            try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals"); DebugCloseable t = BuildIntervalsTimer.start()) {
+                usePos = buildIntervals();
+            }
+            // step 3: verify intervals
+            if (Debug.isEnabled()) {
+                try (DebugCloseable t = VerifyIntervalsTimer.start()) {
+                    assert verifyIntervals();
+                }
+            }
+            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+                dumpIntervals("Before stack slot allocation");
+            }
+            // step 4: allocate stack slots
+            try (DebugCloseable t = AllocateSlotsTimer.start()) {
+                allocateStackSlots();
+            }
+            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+                dumpIntervals("After stack slot allocation");
+            }
+
+            // step 5: assign stack slots
+            try (DebugCloseable t = AssignSlotsTimer.start()) {
+                assignStackSlots(usePos);
+            }
+            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot assignment");
+            if (StackSlotAllocatorUtil.allocatedFramesize.isEnabled()) {
+                StackSlotAllocatorUtil.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
+            }
+        }
+
+        // ====================
+        // step 1: number instructions
+        // ====================
+
+        /**
+         * Numbers all instructions in all blocks.
+         *
+         * @return The id of the last operation.
+         */
+        private static int numberInstructions(LIR lir, AbstractBlockBase<?>[] sortedBlocks) {
+            int opId = 0;
+            int index = 0;
+            for (AbstractBlockBase<?> block : sortedBlocks) {
+
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                int numInst = instructions.size();
+                for (int j = 0; j < numInst; j++) {
+                    LIRInstruction op = instructions.get(j);
+                    op.setId(opId);
+
+                    index++;
+                    opId += 2; // numbering of lirOps by two
+                }
+            }
+            assert (index << 1) == opId : "must match: " + (index << 1);
+            return opId - 2;
+        }
+
+        // ====================
+        // step 2: build intervals
+        // ====================
+
+        private Set<LIRInstruction> buildIntervals() {
+            return new FixPointIntervalBuilder(lir, stackSlotMap, maxOpId()).build();
+        }
+
+        // ====================
+        // step 3: verify intervals
+        // ====================
+
+        private boolean verifyIntervals() {
+            for (StackInterval interval : stackSlotMap) {
+                if (interval != null) {
+                    assert interval.verify(maxOpId());
+                }
+            }
+            return true;
+        }
+
+        // ====================
+        // step 4: allocate stack slots
+        // ====================
+
+        @SuppressWarnings("try")
+        private void allocateStackSlots() {
+            // create unhandled lists
+            for (StackInterval interval : stackSlotMap) {
+                if (interval != null) {
+                    unhandled.add(interval);
+                }
+            }
+
+            for (StackInterval current = activateNext(); current != null; current = activateNext()) {
+                try (Indent indent = Debug.logAndIndent("allocate %s", current)) {
+                    allocateSlot(current);
+                }
+            }
+
+        }
+
+        private void allocateSlot(StackInterval current) {
+            VirtualStackSlot virtualSlot = current.getOperand();
+            final StackSlot location;
+            if (virtualSlot instanceof VirtualStackSlotRange) {
+                // No reuse of ranges (yet).
+                VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot;
+                location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots(), slotRange.getObjects());
+                StackSlotAllocatorUtil.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
+                StackSlotAllocatorUtil.allocatedSlots.increment();
+            } else {
+                assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpected VirtualStackSlot type: " + virtualSlot;
+                StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot);
+                if (slot != null) {
+                    /*
+                     * Free stack slot available. Note that we create a new one because the kind
+                     * might not match.
+                     */
+                    location = StackSlot.get(current.kind(), slot.getRawOffset(), slot.getRawAddFrameSize());
+                    StackSlotAllocatorUtil.reusedSlots.increment();
+                    Debug.log(Debug.BASIC_LOG_LEVEL, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot);
+                } else {
+                    // Allocate new stack slot.
+                    location = frameMapBuilder.getFrameMap().allocateSpillSlot(virtualSlot.getValueKind());
+                    StackSlotAllocatorUtil.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotSize(virtualSlot.getValueKind()));
+                    StackSlotAllocatorUtil.allocatedSlots.increment();
+                    Debug.log(Debug.BASIC_LOG_LEVEL, "New stack slot %s for virtual stack slot %s", location, virtualSlot);
+                }
+            }
+            Debug.log("Allocate location %s for interval %s", location, current);
+            current.setLocation(location);
+        }
+
+        private enum SlotSize {
+            Size1,
+            Size2,
+            Size4,
+            Size8,
+            Illegal;
+        }
+
+        private SlotSize forKind(ValueKind<?> kind) {
+            switch (frameMapBuilder.getFrameMap().spillSlotSize(kind)) {
+                case 1:
+                    return SlotSize.Size1;
+                case 2:
+                    return SlotSize.Size2;
+                case 4:
+                    return SlotSize.Size4;
+                case 8:
+                    return SlotSize.Size8;
+                default:
+                    return SlotSize.Illegal;
+            }
+        }
+
+        private EnumMap<SlotSize, Deque<StackSlot>> freeSlots;
+
+        /**
+         * @return The list of free stack slots for {@code size} or {@code null} if there is none.
+         */
+        private Deque<StackSlot> getOrNullFreeSlots(SlotSize size) {
+            if (freeSlots == null) {
+                return null;
+            }
+            return freeSlots.get(size);
+        }
+
+        /**
+         * @return the list of free stack slots for {@code size}. If there is none a list is
+         *         created.
+         */
+        private Deque<StackSlot> getOrInitFreeSlots(SlotSize size) {
+            assert size != SlotSize.Illegal;
+            Deque<StackSlot> freeList;
+            if (freeSlots != null) {
+                freeList = freeSlots.get(size);
+            } else {
+                freeSlots = new EnumMap<>(SlotSize.class);
+                freeList = null;
+            }
+            if (freeList == null) {
+                freeList = new ArrayDeque<>();
+                freeSlots.put(size, freeList);
+            }
+            assert freeList != null;
+            return freeList;
+        }
+
+        /**
+         * Gets a free stack slot for {@code slot} or {@code null} if there is none.
+         */
+        private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) {
+            assert slot != null;
+            SlotSize size = forKind(slot.getValueKind());
+            if (size == SlotSize.Illegal) {
+                return null;
+            }
+            Deque<StackSlot> freeList = getOrNullFreeSlots(size);
+            if (freeList == null) {
+                return null;
+            }
+            return freeList.pollLast();
+        }
+
+        /**
+         * Adds a stack slot to the list of free slots.
+         */
+        private void freeSlot(StackSlot slot) {
+            SlotSize size = forKind(slot.getValueKind());
+            if (size == SlotSize.Illegal) {
+                return;
+            }
+            getOrInitFreeSlots(size).addLast(slot);
+        }
+
+        /**
+         * Gets the next unhandled interval and finishes handled intervals.
+         */
+        private StackInterval activateNext() {
+            if (unhandled.isEmpty()) {
+                return null;
+            }
+            StackInterval next = unhandled.poll();
+            // finish handled intervals
+            for (int id = next.from(); activePeekId() < id;) {
+                finished(active.poll());
+            }
+            Debug.log("active %s", next);
+            active.add(next);
+            return next;
+        }
+
+        /**
+         * Gets the lowest {@link StackInterval#to() end position} of all active intervals. If there
+         * is none {@link Integer#MAX_VALUE} is returned.
+         */
+        private int activePeekId() {
+            StackInterval first = active.peek();
+            if (first == null) {
+                return Integer.MAX_VALUE;
+            }
+            return first.to();
+        }
+
+        /**
+         * Finishes {@code interval} by adding its location to the list of free stack slots.
+         */
+        private void finished(StackInterval interval) {
+            StackSlot location = interval.location();
+            Debug.log("finished %s (freeing %s)", interval, location);
+            freeSlot(location);
+        }
+
+        // ====================
+        // step 5: assign stack slots
+        // ====================
+
+        private void assignStackSlots(Set<LIRInstruction> usePos) {
+            for (LIRInstruction op : usePos) {
+                op.forEachInput(assignSlot);
+                op.forEachAlive(assignSlot);
+                op.forEachState(assignSlot);
+
+                op.forEachTemp(assignSlot);
+                op.forEachOutput(assignSlot);
+            }
+        }
+
+        ValueProcedure assignSlot = new ValueProcedure() {
+            @Override
+            public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(value)) {
+                    VirtualStackSlot slot = asVirtualStackSlot(value);
+                    StackInterval interval = get(slot);
+                    assert interval != null;
+                    return interval.location();
+                }
+                return value;
+            }
+        };
+
+        // ====================
+        //
+        // ====================
+
+        /**
+         * Gets the highest instruction id.
+         */
+        private int maxOpId() {
+            return maxOpId;
+        }
+
+        private StackInterval get(VirtualStackSlot stackSlot) {
+            return stackSlotMap[stackSlot.getId()];
+        }
+
+        private void dumpIntervals(String label) {
+            Debug.dump(Debug.INFO_LOG_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label);
+        }
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/SimpleStackSlotAllocator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/SimpleStackSlotAllocator.java
new file mode 100644
index 0000000..5628269
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/SimpleStackSlotAllocator.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+import static org.graalvm.compiler.lir.stackslotalloc.StackSlotAllocatorUtil.allocatedFramesize;
+import static org.graalvm.compiler.lir.stackslotalloc.StackSlotAllocatorUtil.allocatedSlots;
+import static org.graalvm.compiler.lir.stackslotalloc.StackSlotAllocatorUtil.virtualFramesize;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
+import org.graalvm.compiler.lir.framemap.SimpleVirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.VirtualStackSlotRange;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+
+public class SimpleStackSlotAllocator extends AllocationPhase {
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        allocateStackSlots((FrameMapBuilderTool) lirGenRes.getFrameMapBuilder(), lirGenRes);
+        lirGenRes.buildFrameMap();
+    }
+
+    public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
+        StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()];
+        long currentFrameSize = allocatedFramesize.isEnabled() ? builder.getFrameMap().currentFrameSize() : 0;
+        for (VirtualStackSlot virtualSlot : builder.getStackSlots()) {
+            final StackSlot slot;
+            if (virtualSlot instanceof SimpleVirtualStackSlot) {
+                slot = mapSimpleVirtualStackSlot(builder, (SimpleVirtualStackSlot) virtualSlot);
+                virtualFramesize.add(builder.getFrameMap().spillSlotSize(virtualSlot.getValueKind()));
+            } else if (virtualSlot instanceof VirtualStackSlotRange) {
+                VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot;
+                slot = mapVirtualStackSlotRange(builder, slotRange);
+                virtualFramesize.add(builder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
+            } else {
+                throw GraalError.shouldNotReachHere("Unknown VirtualStackSlot: " + virtualSlot);
+            }
+            allocatedSlots.increment();
+            mapping[virtualSlot.getId()] = slot;
+        }
+        updateLIR(res, mapping);
+        if (allocatedFramesize.isEnabled()) {
+            allocatedFramesize.add(builder.getFrameMap().currentFrameSize() - currentFrameSize);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void updateLIR(LIRGenerationResult res, StackSlot[] mapping) {
+        try (Scope scope = Debug.scope("StackSlotMappingLIR")) {
+            ValueProcedure updateProc = (value, mode, flags) -> {
+                if (isVirtualStackSlot(value)) {
+                    StackSlot stackSlot = mapping[asVirtualStackSlot(value).getId()];
+                    Debug.log("map %s -> %s", value, stackSlot);
+                    return stackSlot;
+                }
+                return value;
+            };
+            for (AbstractBlockBase<?> block : res.getLIR().getControlFlowGraph().getBlocks()) {
+                try (Indent indent0 = Debug.logAndIndent("block: %s", block)) {
+                    for (LIRInstruction inst : res.getLIR().getLIRforBlock(block)) {
+                        try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) {
+                            inst.forEachAlive(updateProc);
+                            inst.forEachInput(updateProc);
+                            inst.forEachOutput(updateProc);
+                            inst.forEachTemp(updateProc);
+                            inst.forEachState(updateProc);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected StackSlot mapSimpleVirtualStackSlot(FrameMapBuilderTool builder, SimpleVirtualStackSlot virtualStackSlot) {
+        return builder.getFrameMap().allocateSpillSlot(virtualStackSlot.getValueKind());
+    }
+
+    protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderTool builder, VirtualStackSlotRange virtualStackSlot) {
+        return builder.getFrameMap().allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackInterval.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackInterval.java
new file mode 100644
index 0000000..2947d06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackInterval.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import org.graalvm.compiler.lir.VirtualStackSlot;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.ValueKind;
+
+public final class StackInterval {
+
+    private static final int INVALID_START = Integer.MAX_VALUE;
+    private static final int INVALID_END = Integer.MIN_VALUE;
+    private final VirtualStackSlot operand;
+    private StackInterval hint;
+    private final ValueKind<?> kind;
+    private int from = INVALID_START;
+    private int to = INVALID_END;
+    private StackSlot location;
+
+    public StackInterval(VirtualStackSlot operand, ValueKind<?> kind) {
+        this.operand = operand;
+        this.kind = kind;
+    }
+
+    public boolean verify(int maxOpId) {
+        // maxOpId + 1 is the last position in the last block (i.e. the "write position")
+        assert 0 <= from && from <= to && to <= maxOpId + 1 : String.format("from %d, to %d, maxOpId %d", from, to, maxOpId);
+        return true;
+    }
+
+    public VirtualStackSlot getOperand() {
+        return operand;
+    }
+
+    public void addTo(int opId) {
+        if (opId >= to) {
+            to = opId;
+        }
+    }
+
+    protected void addFrom(int opId) {
+        if (from > opId) {
+            from = opId;
+            // set opId also as to if it has not yet been set
+            if (to == INVALID_END) {
+                to = opId;
+            }
+        }
+    }
+
+    public ValueKind<?> kind() {
+        return kind;
+    }
+
+    public StackSlot location() {
+        return location;
+    }
+
+    public void setLocation(StackSlot location) {
+        this.location = location;
+    }
+
+    public int from() {
+        return from;
+    }
+
+    public int to() {
+        return to;
+    }
+
+    public void fixFrom() {
+        if (from == INVALID_START) {
+            from = 0;
+        }
+    }
+
+    public boolean isFixed() {
+        return from == 0;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SI[%d-%d] k=%s o=%s l=%s h=%s", from, to, kind, operand, location, hint != null ? hint.getOperand() : "null");
+    }
+
+    public void setLocationHint(StackInterval locationHint) {
+        hint = locationHint;
+    }
+
+    public StackInterval locationHint() {
+        return hint;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackIntervalDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackIntervalDumper.java
new file mode 100644
index 0000000..11466d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackIntervalDumper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.debug.IntervalDumper;
+
+import jdk.vm.ci.meta.Value;
+
+class StackIntervalDumper implements IntervalDumper {
+    private final StackInterval[] intervals;
+
+    StackIntervalDumper(StackInterval[] intervals) {
+        this.intervals = intervals;
+    }
+
+    @Override
+    public void visitIntervals(IntervalVisitor visitor) {
+        for (StackInterval interval : intervals) {
+            if (interval != null) {
+                printInterval(interval, visitor);
+            }
+        }
+    }
+
+    private static void printInterval(StackInterval interval, IntervalVisitor visitor) {
+        Value hint = interval.locationHint() != null ? interval.locationHint().getOperand() : null;
+        VirtualStackSlot operand = interval.getOperand();
+        String type = operand.getValueKind().getPlatformKind().toString();
+        visitor.visitIntervalStart(operand, operand, interval.location(), hint, type);
+
+        // print ranges
+        visitor.visitRange(interval.from(), interval.to());
+
+        // no use positions
+
+        visitor.visitIntervalEnd("NOT_SUPPORTED");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackSlotAllocatorUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackSlotAllocatorUtil.java
new file mode 100644
index 0000000..fb99e95
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/StackSlotAllocatorUtil.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.stackslotalloc;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.code.StackSlot;
+
+/**
+ * A stack slot allocator is responsible for translating {@link VirtualStackSlot virtual} stack
+ * slots into {@link StackSlot real} stack slots. This includes changing all occurrences of
+ * {@link VirtualStackSlot} in the {@link LIRGenerationResult#getLIR() LIR} to {@link StackSlot}.
+ */
+public final class StackSlotAllocatorUtil {
+    /**
+     * The number of allocated stack slots.
+     */
+    public static DebugCounter allocatedSlots = Debug.counter("StackSlotAllocator[allocatedSlots]");
+    /**
+     * The number of reused stack slots.
+     */
+    public static DebugCounter reusedSlots = Debug.counter("StackSlotAllocator[reusedSlots]");
+    /**
+     * The size (in bytes) required for all allocated stack slots. Note that this number corresponds
+     * to the actual frame size and might include alignment.
+     */
+    public static DebugCounter allocatedFramesize = Debug.counter("StackSlotAllocator[AllocatedFramesize]");
+    /** The size (in bytes) required for all virtual stack slots. */
+    public static DebugCounter virtualFramesize = Debug.counter("StackSlotAllocator[VirtualFramesize]");
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java
new file mode 100644
index 0000000..a7fa503
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+
+import jdk.vm.ci.meta.Value;
+
+public final class GenericValueMap<T> extends ValueMap<Value, T> {
+
+    private final Map<Value, T> data;
+
+    public GenericValueMap() {
+        data = CollectionsFactory.newMap();
+    }
+
+    @Override
+    public T get(Value value) {
+        return data.get(value);
+    }
+
+    @Override
+    public void remove(Value value) {
+        data.remove(value);
+    }
+
+    @Override
+    public void put(Value value, T object) {
+        data.put(value, object);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/IndexedValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/IndexedValueMap.java
new file mode 100644
index 0000000..a53d102
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/IndexedValueMap.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import java.util.EnumSet;
+import java.util.Objects;
+
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.InstructionValueProcedure;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+import jdk.vm.ci.meta.Value;
+
+public final class IndexedValueMap {
+    private Value[] values;
+
+    public IndexedValueMap() {
+        values = Value.NO_VALUES;
+    }
+
+    public IndexedValueMap(IndexedValueMap other) {
+        int limit = other.values.length;
+        while (limit > 0) {
+            if (other.values[limit - 1] == null) {
+                limit--;
+                continue;
+            }
+            break;
+        }
+        values = new Value[limit];
+        System.arraycopy(other.values, 0, values, 0, values.length);
+    }
+
+    public Value get(int index) {
+        return values[index];
+    }
+
+    public void put(int index, Value value) {
+        if (values.length <= index) {
+            if (value == null) {
+                return;
+            }
+            Value[] newValues = new Value[index + 1];
+            System.arraycopy(values, 0, newValues, 0, values.length);
+            values = newValues;
+            values[index] = value;
+        } else {
+            values[index] = value;
+        }
+    }
+
+    public void putAll(IndexedValueMap stack) {
+        Value[] otherValues = stack.values;
+        int limit = otherValues.length;
+        if (limit > values.length) {
+            while (limit > 0) {
+                if (otherValues[limit - 1] == null) {
+                    limit--;
+                    continue;
+                }
+                break;
+            }
+            if (limit > values.length) {
+                Value[] newValues = new Value[limit];
+                System.arraycopy(values, 0, newValues, 0, values.length);
+                values = newValues;
+            }
+        }
+        for (int i = 0; i < limit; i++) {
+            Value value = otherValues[i];
+            if (value != null) {
+                values[i] = value;
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof IndexedValueMap) {
+            IndexedValueMap that = (IndexedValueMap) other;
+            int limit = Math.min(values.length, that.values.length);
+            for (int i = 0; i < limit; i++) {
+                if (!Objects.equals(values[i], that.values[i])) {
+                    return false;
+                }
+            }
+            for (int i = limit; i < values.length; i++) {
+                if (values[i] != null) {
+                    return false;
+                }
+            }
+            for (int i = limit; i < that.values.length; i++) {
+                if (that.values[i] != null) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueProcedure proc) {
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                values[i] = proc.doValue(inst, values[i], mode, flags);
+            }
+        }
+    }
+
+    public void visitEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueConsumer consumer) {
+        for (Value v : values) {
+            if (v != null) {
+                consumer.visitValue(inst, v, mode, flags);
+            }
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[");
+        boolean comma = false;
+
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                if (comma) {
+                    sb.append(", ");
+                } else {
+                    comma = true;
+                }
+
+                sb.append(i);
+                sb.append(": ");
+                sb.append(values[i]);
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/RegisterMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/RegisterMap.java
new file mode 100644
index 0000000..cf803d3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/RegisterMap.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import java.util.function.BiConsumer;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterArray;
+
+public class RegisterMap<T> {
+    private final Object[] values;
+    private final Architecture architecture;
+
+    public RegisterMap(Architecture arch) {
+        assert checkArchitecture(arch);
+        this.values = new Object[arch.getRegisters().size()];
+        this.architecture = arch;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T get(Register reg) {
+        return (T) values[index(reg)];
+    }
+
+    public void remove(Register reg) {
+        values[index(reg)] = null;
+    }
+
+    public void put(Register reg, T value) {
+        values[index(reg)] = value;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void forEach(BiConsumer<? super Register, ? super T> consumer) {
+        for (int i = 0; i < values.length; ++i) {
+            T value = (T) values[i];
+            if (value != null) {
+                consumer.accept(architecture.getRegisters().get(i), value);
+            }
+        }
+    }
+
+    private static int index(Register reg) {
+        return reg.number;
+    }
+
+    private static boolean checkArchitecture(Architecture arch) {
+        RegisterArray registers = arch.getRegisters();
+        for (int i = 0; i < registers.size(); ++i) {
+            assert registers.get(i).number == i : registers.get(i) + ": " + registers.get(i).number + "!=" + i;
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueMap.java
new file mode 100644
index 0000000..8554f0c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueMap.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A map interface to map {@link Value}s to other objects.
+ */
+public abstract class ValueMap<K extends Value, T> {
+
+    /**
+     * Gets the object associated with {@code value} or {@code null} if there is no such mapping.
+     */
+    public abstract T get(K value);
+
+    /**
+     * Removes the object associated with {@code value} from the map.
+     */
+    public abstract void remove(K value);
+
+    /**
+     * Associates {@code object} with {@code value}.
+     */
+    public abstract void put(K value, T object);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueSet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueSet.java
new file mode 100644
index 0000000..1d29ad7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/ValueSet.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import jdk.vm.ci.meta.Value;
+
+public abstract class ValueSet<S extends ValueSet<S>> {
+
+    public abstract void put(Value v);
+
+    public abstract void remove(Value v);
+
+    public abstract void putAll(S s);
+
+    public abstract S copy();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/VariableVirtualStackValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/VariableVirtualStackValueMap.java
new file mode 100644
index 0000000..d549c37
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/VariableVirtualStackValueMap.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.util;
+
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
+
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.Value;
+
+public class VariableVirtualStackValueMap<K extends Value, T> extends ValueMap<K, T> {
+
+    private final Object[] variables;
+    private final Object[] slots;
+
+    public VariableVirtualStackValueMap(int initialVariableCapacity, int initialStackSlotCapacity) {
+        variables = new Object[initialVariableCapacity];
+        slots = new Object[initialStackSlotCapacity];
+    }
+
+    @Override
+    public T get(K value) {
+        if (isVariable(value)) {
+            return get(variables, asVariable(value).index);
+        }
+        if (isVirtualStackSlot(value)) {
+            return get(slots, asVirtualStackSlot(value).getId());
+        }
+        throw GraalError.shouldNotReachHere("Unsupported Value: " + value);
+    }
+
+    @Override
+    public void remove(K value) {
+        if (isVariable(value)) {
+            remove(variables, asVariable(value).index);
+        } else if (isVirtualStackSlot(value)) {
+            remove(slots, asVirtualStackSlot(value).getId());
+        } else {
+            throw GraalError.shouldNotReachHere("Unsupported Value: " + value);
+        }
+    }
+
+    @Override
+    public void put(K value, T object) {
+        if (isVariable(value)) {
+            put(variables, asVariable(value).index, object);
+        } else if (isVirtualStackSlot(value)) {
+            put(slots, asVirtualStackSlot(value).getId(), object);
+        } else {
+            throw GraalError.shouldNotReachHere("Unsupported Value: " + value);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T get(Object[] array, int index) {
+        if (index >= array.length) {
+            return null;
+        }
+        return (T) array[index];
+    }
+
+    private static void remove(Object[] array, int index) {
+        if (index >= array.length) {
+            return;
+        }
+        array[index] = null;
+    }
+
+    private static <T> Object[] put(Object[] array, int index, T object) {
+        if (index >= array.length) {
+            Object[] newArray = new Object[index + 1];
+            System.arraycopy(array, 0, newArray, 0, array.length);
+            newArray[index] = object;
+            return newArray;
+        }
+        array[index] = object;
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ContextlessLoopPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ContextlessLoopPhase.java
new file mode 100644
index 0000000..89aed93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ContextlessLoopPhase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public abstract class ContextlessLoopPhase<P extends LoopPolicies> extends LoopPhase<P> {
+
+    public ContextlessLoopPhase(P policies) {
+        super(policies);
+    }
+
+    public final void apply(final StructuredGraph graph) {
+        apply(graph, true);
+    }
+
+    public final void apply(final StructuredGraph graph, final boolean dumpGraph) {
+        apply(graph, null, dumpGraph);
+    }
+
+    protected abstract void run(StructuredGraph graph);
+
+    @Override
+    protected final void run(StructuredGraph graph, PhaseContext context) {
+        run(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java
new file mode 100644
index 0000000..b9b49cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
+
+    private static final DebugCounter FULLY_UNROLLED_LOOPS = Debug.counter("FullUnrolls");
+    private final CanonicalizerPhase canonicalizer;
+
+    public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer, LoopPolicies policies) {
+        super(policies);
+        this.canonicalizer = canonicalizer;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (graph.hasLoops()) {
+            boolean peeled;
+            do {
+                peeled = false;
+                final LoopsData dataCounted = new LoopsData(graph);
+                dataCounted.detectedCountedLoops();
+                for (LoopEx loop : dataCounted.countedLoops()) {
+                    if (getPolicies().shouldFullUnroll(loop)) {
+                        Debug.log("FullUnroll %s", loop);
+                        LoopTransformations.fullUnroll(loop, context, canonicalizer);
+                        FULLY_UNROLLED_LOOPS.increment();
+                        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "FullUnroll %s", loop);
+                        peeled = true;
+                        break;
+                    }
+                }
+                dataCounted.deleteUnusedNodes();
+            } while (peeled);
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java
new file mode 100644
index 0000000..9a95226
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class LoopPeelingPhase extends LoopPhase<LoopPolicies> {
+
+    public LoopPeelingPhase(LoopPolicies policies) {
+        super(policies);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (graph.hasLoops()) {
+            LoopsData data = new LoopsData(graph);
+            try (Debug.Scope s = Debug.scope("peeling", data.getCFG())) {
+                for (LoopEx loop : data.outerFirst()) {
+                    if (getPolicies().shouldPeel(loop, data.getCFG(), context.getMetaAccess())) {
+                        Debug.log("Peeling %s", loop);
+                        LoopTransformations.peel(loop);
+                        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Peeling %s", loop);
+                    }
+                }
+                data.deleteUnusedNodes();
+            } catch (Throwable t) {
+                throw Debug.handle(t);
+            }
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 5.0f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPhase.java
new file mode 100644
index 0000000..6b50348
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPhase.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public abstract class LoopPhase<P extends LoopPolicies> extends BasePhase<PhaseContext> {
+    private P policies;
+
+    public LoopPhase(P policies) {
+        this.policies = policies;
+    }
+
+    protected P getPolicies() {
+        return policies;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopSafepointEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopSafepointEliminationPhase.java
new file mode 100644
index 0000000..7de44fc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopSafepointEliminationPhase.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class LoopSafepointEliminationPhase extends BasePhase<MidTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        LoopsData loops = new LoopsData(graph);
+        if (context.getOptimisticOptimizations().useLoopLimitChecks() && graph.getGuardsStage().allowsFloatingGuards()) {
+            loops.detectedCountedLoops();
+            for (LoopEx loop : loops.countedLoops()) {
+                if (loop.loop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
+                    boolean hasSafepoint = false;
+                    for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                        hasSafepoint |= loopEnd.canSafepoint();
+                    }
+                    if (hasSafepoint) {
+                        loop.counted().createOverFlowGuard();
+                        loop.loopBegin().disableSafepoint();
+                    }
+                }
+            }
+        }
+        for (LoopEx loop : loops.loops()) {
+            for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                Block b = loops.getCFG().blockFor(loopEnd);
+                blocks: while (b != loop.loop().getHeader()) {
+                    assert b != null;
+                    for (FixedNode node : b.getNodes()) {
+                        if (node instanceof Invoke || (node instanceof ForeignCallNode && ((ForeignCallNode) node).isGuaranteedSafepoint())) {
+                            loopEnd.disableSafepoint();
+                            break blocks;
+                        }
+                    }
+                    b = b.getDominator();
+                }
+            }
+        }
+        loops.deleteUnusedNodes();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java
new file mode 100644
index 0000000..8a224bb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopFragmentWhole;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public abstract class LoopTransformations {
+
+    private LoopTransformations() {
+        // does not need to be instantiated
+    }
+
+    public static void peel(LoopEx loop) {
+        loop.inside().duplicate().insertBefore(loop);
+        loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
+    }
+
+    public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
+        // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count
+        LoopBeginNode loopBegin = loop.loopBegin();
+        StructuredGraph graph = loopBegin.graph();
+        int initialNodeCount = graph.getNodeCount();
+        while (!loopBegin.isDeleted()) {
+            Mark mark = graph.getMark();
+            peel(loop);
+            canonicalizer.applyIncremental(graph, context, mark);
+            loop.invalidateFragments();
+            if (graph.getNodeCount() > initialNodeCount + MaximumDesiredSize.getValue() * 2) {
+                throw new RetryableBailoutException("FullUnroll : Graph seems to grow out of proportion");
+            }
+        }
+    }
+
+    public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet) {
+        ControlSplitNode firstNode = controlSplitNodeSet.iterator().next();
+        LoopFragmentWhole originalLoop = loop.whole();
+        StructuredGraph graph = firstNode.graph();
+
+        loop.loopBegin().incrementUnswitches();
+
+        // create new control split out of loop
+        ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
+        originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
+
+        /*
+         * The code below assumes that all of the control split nodes have the same successor
+         * structure, which should have been enforced by findUnswitchable.
+         */
+        Iterator<Position> successors = firstNode.successorPositions().iterator();
+        assert successors.hasNext();
+        // original loop is used as first successor
+        Position firstPosition = successors.next();
+        AbstractBeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
+        firstPosition.set(newControlSplit, originalLoopBegin);
+
+        while (successors.hasNext()) {
+            Position position = successors.next();
+            // create a new loop duplicate and connect it.
+            LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
+            AbstractBeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
+            position.set(newControlSplit, newBegin);
+
+            // For each cloned ControlSplitNode, simplify the proper path
+            for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+                ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
+                if (duplicatedControlSplit.isAlive()) {
+                    AbstractBeginNode survivingSuccessor = (AbstractBeginNode) position.get(duplicatedControlSplit);
+                    survivingSuccessor.replaceAtUsages(InputType.Guard, newBegin);
+                    graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
+                }
+            }
+        }
+        // original loop is simplified last to avoid deleting controlSplitNode too early
+        for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+            if (controlSplitNode.isAlive()) {
+                AbstractBeginNode survivingSuccessor = (AbstractBeginNode) firstPosition.get(controlSplitNode);
+                survivingSuccessor.replaceAtUsages(InputType.Guard, originalLoopBegin);
+                graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
+            }
+        }
+
+        // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
+    }
+
+    public static List<ControlSplitNode> findUnswitchable(LoopEx loop) {
+        List<ControlSplitNode> controls = null;
+        ValueNode invariantValue = null;
+        for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) {
+            if (loop.isOutsideLoop(ifNode.condition())) {
+                if (controls == null) {
+                    invariantValue = ifNode.condition();
+                    controls = new ArrayList<>();
+                    controls.add(ifNode);
+                } else if (ifNode.condition() == invariantValue) {
+                    controls.add(ifNode);
+                }
+            }
+        }
+        if (controls == null) {
+            SwitchNode firstSwitch = null;
+            for (SwitchNode switchNode : loop.whole().nodes().filter(SwitchNode.class)) {
+                if (switchNode.successors().count() > 1 && loop.isOutsideLoop(switchNode.value())) {
+                    if (controls == null) {
+                        firstSwitch = switchNode;
+                        invariantValue = switchNode.value();
+                        controls = new ArrayList<>();
+                        controls.add(switchNode);
+                    } else if (switchNode.value() == invariantValue && firstSwitch.structureEquals(switchNode)) {
+                        // Only collect switches which test the same values in the same order
+                        controls.add(switchNode);
+                    }
+                }
+            }
+        }
+        return controls;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java
new file mode 100644
index 0000000..a2eda92
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public class LoopUnswitchingPhase extends ContextlessLoopPhase<LoopPolicies> {
+    private static final DebugCounter UNSWITCHED = Debug.counter("Unswitched");
+    private static final DebugCounter UNSWITCH_CANDIDATES = Debug.counter("UnswitchCandidates");
+    private static final DebugCounter UNSWITCH_EARLY_REJECTS = Debug.counter("UnswitchEarlyRejects");
+
+    public LoopUnswitchingPhase(LoopPolicies policies) {
+        super(policies);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            boolean unswitched;
+            do {
+                unswitched = false;
+                final LoopsData dataUnswitch = new LoopsData(graph);
+                for (LoopEx loop : dataUnswitch.outerFirst()) {
+                    if (getPolicies().shouldTryUnswitch(loop)) {
+                        List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
+                        if (controlSplits != null) {
+                            UNSWITCH_CANDIDATES.increment();
+                            if (getPolicies().shouldUnswitch(loop, controlSplits)) {
+                                if (Debug.isLogEnabled()) {
+                                    logUnswitch(loop, controlSplits);
+                                }
+                                LoopTransformations.unswitch(loop, controlSplits);
+                                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "After unswitch %s", controlSplits);
+                                UNSWITCHED.increment();
+                                unswitched = true;
+                                break;
+                            }
+                        }
+                    } else {
+                        UNSWITCH_EARLY_REJECTS.increment();
+                    }
+                }
+            } while (unswitched);
+        }
+    }
+
+    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        StringBuilder sb = new StringBuilder("Unswitching ");
+        sb.append(loop).append(" at ");
+        for (ControlSplitNode controlSplit : controlSplits) {
+            sb.append(controlSplit).append(" [");
+            Iterator<Node> it = controlSplit.successors().iterator();
+            while (it.hasNext()) {
+                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
+                if (it.hasNext()) {
+                    sb.append(", ");
+                }
+            }
+            sb.append("]");
+        }
+        Debug.log("%s", sb);
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 10.0f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java
new file mode 100644
index 0000000..2c84d78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ReassociateInvariantPhase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop.phases;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.Phase;
+
+public class ReassociateInvariantPhase extends Phase {
+
+    @SuppressWarnings("try")
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            final LoopsData dataReassociate = new LoopsData(graph);
+            try (Scope s = Debug.scope("ReassociateInvariants")) {
+                for (LoopEx loop : dataReassociate.loops()) {
+                    loop.reassociateInvariants();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            dataReassociate.deleteUnusedNodes();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java
new file mode 100644
index 0000000..2720b84
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.loop.MathUtil.add;
+import static org.graalvm.compiler.loop.MathUtil.mul;
+import static org.graalvm.compiler.loop.MathUtil.sub;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+
+public class BasicInductionVariable extends InductionVariable {
+
+    private final ValuePhiNode phi;
+    private final ValueNode init;
+    private final ValueNode rawStride;
+    private final BinaryArithmeticNode<?> op;
+
+    public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, BinaryArithmeticNode<?> op) {
+        super(loop);
+        this.phi = phi;
+        this.init = init;
+        this.rawStride = rawStride;
+        this.op = op;
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return phi.graph();
+    }
+
+    public BinaryArithmeticNode<?> getOp() {
+        return op;
+    }
+
+    @Override
+    public Direction direction() {
+        Stamp stamp = rawStride.stamp();
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp integerStamp = (IntegerStamp) stamp;
+            Direction dir = null;
+            if (integerStamp.isStrictlyPositive()) {
+                dir = Direction.Up;
+            } else if (integerStamp.isStrictlyNegative()) {
+                dir = Direction.Down;
+            }
+            if (dir != null) {
+                if (op instanceof AddNode) {
+                    return dir;
+                } else {
+                    assert op instanceof SubNode;
+                    return dir.opposite();
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValuePhiNode valueNode() {
+        return phi;
+    }
+
+    @Override
+    public ValueNode initNode() {
+        return init;
+    }
+
+    @Override
+    public ValueNode strideNode() {
+        if (op instanceof AddNode) {
+            return rawStride;
+        }
+        if (op instanceof SubNode) {
+            return graph().unique(new NegateNode(rawStride));
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public boolean isConstantInit() {
+        return init.isConstant();
+    }
+
+    @Override
+    public boolean isConstantStride() {
+        return rawStride.isConstant();
+    }
+
+    @Override
+    public long constantInit() {
+        return init.asJavaConstant().asLong();
+    }
+
+    @Override
+    public long constantStride() {
+        if (op instanceof AddNode) {
+            return rawStride.asJavaConstant().asLong();
+        }
+        if (op instanceof SubNode) {
+            return -rawStride.asJavaConstant().asLong();
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
+        Stamp fromStamp = phi.stamp();
+        StructuredGraph graph = graph();
+        ValueNode stride = strideNode();
+        ValueNode initNode = this.initNode();
+        if (!fromStamp.isCompatible(stamp)) {
+            stride = IntegerConvertNode.convert(stride, stamp, graph());
+            initNode = IntegerConvertNode.convert(initNode, stamp, graph());
+        }
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
+        if (!maxTripCount.stamp().isCompatible(stamp)) {
+            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
+        }
+        return add(graph, mul(graph, stride, sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
+    }
+
+    @Override
+    public ValueNode exitValueNode() {
+        Stamp stamp = phi.stamp();
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(false);
+        if (!maxTripCount.stamp().isCompatible(stamp)) {
+            maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
+        }
+        return add(graph(), mul(graph(), strideNode(), maxTripCount), initNode());
+    }
+
+    @Override
+    public boolean isConstantExtremum() {
+        return isConstantInit() && isConstantStride() && loop.counted().isConstantMaxTripCount();
+    }
+
+    @Override
+    public long constantExtremum() {
+        return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit();
+    }
+
+    @Override
+    public void deleteUnusedNodes() {
+    }
+
+    @Override
+    public String toString() {
+        return String.format("BasicInductionVariable %s %s %s %s", initNode(), phi, op.getNodeClass().shortName(), strideNode());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java
new file mode 100644
index 0000000..0b0f925
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.loop.MathUtil.add;
+import static org.graalvm.compiler.loop.MathUtil.divBefore;
+import static org.graalvm.compiler.loop.MathUtil.sub;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.loop.InductionVariable.Direction;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class CountedLoopInfo {
+
+    private final LoopEx loop;
+    private InductionVariable iv;
+    private ValueNode end;
+    private boolean oneOff;
+    private AbstractBeginNode body;
+
+    CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff, AbstractBeginNode body) {
+        this.loop = loop;
+        this.iv = iv;
+        this.end = end;
+        this.oneOff = oneOff;
+        this.body = body;
+    }
+
+    public ValueNode maxTripCountNode() {
+        return maxTripCountNode(false);
+    }
+
+    public ValueNode maxTripCountNode(boolean assumePositive) {
+        StructuredGraph graph = iv.valueNode().graph();
+        Stamp stamp = iv.valueNode().stamp();
+        ValueNode range = sub(graph, end, iv.initNode());
+
+        ValueNode oneDirection;
+        if (iv.direction() == Direction.Up) {
+            oneDirection = ConstantNode.forIntegerStamp(stamp, 1, graph);
+        } else {
+            assert iv.direction() == Direction.Down;
+            oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph);
+        }
+        if (oneOff) {
+            range = add(graph, range, oneDirection);
+        }
+        // round-away-from-zero divison: (range + stride -/+ 1) / stride
+        ValueNode denominator = add(graph, sub(graph, range, oneDirection), iv.strideNode());
+        ValueNode div = divBefore(graph, loop.entryPoint(), denominator, iv.strideNode());
+
+        if (assumePositive) {
+            return div;
+        }
+        ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph);
+        return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero));
+    }
+
+    public boolean isConstantMaxTripCount() {
+        return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride();
+    }
+
+    public long constantMaxTripCount() {
+        assert iv.direction() != null;
+        long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0;
+        long max = (((ConstantNode) end).asJavaConstant().asLong() + off - iv.constantInit()) / iv.constantStride();
+        return Math.max(0, max);
+    }
+
+    public boolean isExactTripCount() {
+        return loop.loopBegin().loopExits().count() == 1;
+    }
+
+    public ValueNode exactTripCountNode() {
+        assert isExactTripCount();
+        return maxTripCountNode();
+    }
+
+    public boolean isConstantExactTripCount() {
+        assert isExactTripCount();
+        return isConstantMaxTripCount();
+    }
+
+    public long constantExactTripCount() {
+        assert isExactTripCount();
+        return constantMaxTripCount();
+    }
+
+    @Override
+    public String toString() {
+        return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : "");
+    }
+
+    public ValueNode getLimit() {
+        return end;
+    }
+
+    public ValueNode getStart() {
+        return iv.initNode();
+    }
+
+    public boolean isLimitIncluded() {
+        return oneOff;
+    }
+
+    public AbstractBeginNode getBody() {
+        return body;
+    }
+
+    public Direction getDirection() {
+        return iv.direction();
+    }
+
+    public InductionVariable getCounter() {
+        return iv;
+    }
+
+    public GuardingNode getOverFlowGuard() {
+        return loop.loopBegin().getOverflowGuard();
+    }
+
+    public GuardingNode createOverFlowGuard() {
+        GuardingNode overflowGuard = getOverFlowGuard();
+        if (overflowGuard != null) {
+            return overflowGuard;
+        }
+        IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp();
+        StructuredGraph graph = iv.valueNode().graph();
+        CompareNode cond; // we use a negated guard with a < condition to achieve a >=
+        ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
+        if (iv.direction() == Direction.Up) {
+            ValueNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one));
+            if (oneOff) {
+                v1 = sub(graph, v1, one);
+            }
+            cond = graph.unique(new IntegerLessThanNode(v1, end));
+        } else {
+            assert iv.direction() == Direction.Down;
+            ValueNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode()));
+            if (oneOff) {
+                v1 = add(graph, v1, one);
+            }
+            cond = graph.unique(new IntegerLessThanNode(end, v1));
+        }
+        assert graph.getGuardsStage().allowsFloatingGuards();
+        overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true,
+                        JavaConstant.NULL_POINTER)); // TODO gd: use speculation
+        loop.loopBegin().setOverflowGuard(overflowGuard);
+        return overflowGuard;
+    }
+
+    public IntegerStamp getStamp() {
+        return (IntegerStamp) iv.valueNode().stamp();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java
new file mode 100644
index 0000000..6bc76eb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.core.common.GraalOptions.LoopMaxUnswitch;
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize;
+import static org.graalvm.compiler.core.common.GraalOptions.MinimumPeelProbability;
+
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.VirtualState.VirtualClosure;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.java.TypeSwitchNode;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class DefaultLoopPolicies implements LoopPolicies {
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(500);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchTrivial = new OptionValue<>(10);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Double> LoopUnswitchFrequencyBoost = new OptionValue<>(10.0);
+
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxIterations = new OptionValue<>(600);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
+
+    @Override
+    public boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess) {
+        LoopBeginNode loopBegin = loop.loopBegin();
+        double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).probability();
+        if (entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue()) {
+            // check whether we're allowed to peel this loop
+            return loop.canDuplicateLoop();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean shouldFullUnroll(LoopEx loop) {
+        if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) {
+            return false;
+        }
+        CountedLoopInfo counted = loop.counted();
+        long maxTrips = counted.constantMaxTripCount();
+        int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue();
+        maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount()));
+        int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
+        if (maxTrips <= FullUnrollMaxIterations.getValue() && size * (maxTrips - 1) <= maxNodes) {
+            // check whether we're allowed to unroll this loop
+            return loop.canDuplicateLoop();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean shouldTryUnswitch(LoopEx loop) {
+        LoopBeginNode loopBegin = loop.loopBegin();
+        double loopFrequency = loopBegin.loopFrequency();
+        if (loopFrequency <= 1.0) {
+            return false;
+        }
+        return loopBegin.unswitches() <= LoopMaxUnswitch.getValue();
+    }
+
+    private static final class CountingClosure implements VirtualClosure {
+        int count;
+
+        @Override
+        public void apply(VirtualState node) {
+            count++;
+        }
+    }
+
+    private static class IsolatedInitialization {
+        static final DebugCounter UNSWITCH_SPLIT_WITH_PHIS = Debug.counter("UnswitchSplitWithPhis");
+    }
+
+    @Override
+    public boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        int phis = 0;
+        NodeBitMap branchNodes = loop.loopBegin().graph().createNodeBitMap();
+        for (ControlSplitNode controlSplit : controlSplits) {
+            for (Node successor : controlSplit.successors()) {
+                AbstractBeginNode branch = (AbstractBeginNode) successor;
+                // this may count twice because of fall-through in switches
+                loop.nodesInLoopBranch(branchNodes, branch);
+            }
+            Block postDomBlock = loop.loopsData().getCFG().blockFor(controlSplit).getPostdominator();
+            if (postDomBlock != null) {
+                IsolatedInitialization.UNSWITCH_SPLIT_WITH_PHIS.increment();
+                phis += ((MergeNode) postDomBlock.getBeginNode()).phis().count();
+            }
+        }
+        int inBranchTotal = branchNodes.count();
+
+        CountingClosure stateNodesCount = new CountingClosure();
+        double loopFrequency = loop.loopBegin().loopFrequency();
+        int maxDiff = LoopUnswitchTrivial.getValue() + (int) (LoopUnswitchFrequencyBoost.getValue() * (loopFrequency - 1.0 + phis));
+
+        maxDiff = Math.min(maxDiff, LoopUnswitchMaxIncrease.getValue());
+        int remainingGraphSpace = MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount();
+        maxDiff = Math.min(maxDiff, remainingGraphSpace);
+
+        loop.loopBegin().stateAfter().applyToVirtual(stateNodesCount);
+        int loopTotal = loop.size() - loop.loopBegin().phis().count() - stateNodesCount.count - 1;
+        int actualDiff = (loopTotal - inBranchTotal);
+        ControlSplitNode firstSplit = controlSplits.get(0);
+        if (firstSplit instanceof TypeSwitchNode) {
+            int copies = firstSplit.successors().count() - 1;
+            for (Node succ : firstSplit.successors()) {
+                FixedNode current = (FixedNode) succ;
+                while (current instanceof FixedWithNextNode) {
+                    current = ((FixedWithNextNode) current).next();
+                }
+                if (current instanceof DeoptimizeNode) {
+                    copies--;
+                }
+            }
+            actualDiff = actualDiff * copies;
+        }
+
+        Debug.log("shouldUnswitch(%s, %s) : delta=%d (%.2f%% inside of branches), max=%d, f=%.2f, phis=%d -> %b", loop, controlSplits, actualDiff, (double) (inBranchTotal) / loopTotal * 100, maxDiff,
+                        loopFrequency, phis, actualDiff <= maxDiff);
+        if (actualDiff <= maxDiff) {
+            // check whether we're allowed to unswitch this loop
+            return loop.canDuplicateLoop();
+        } else {
+            return false;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedConvertedInductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedConvertedInductionVariable.java
new file mode 100644
index 0000000..dc0ef63
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedConvertedInductionVariable.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+
+public class DerivedConvertedInductionVariable extends DerivedInductionVariable {
+
+    private final Stamp stamp;
+    private final ValueNode value;
+
+    public DerivedConvertedInductionVariable(LoopEx loop, InductionVariable base, Stamp stamp, ValueNode value) {
+        super(loop, base);
+        this.stamp = stamp;
+        this.value = value;
+    }
+
+    @Override
+    public ValueNode valueNode() {
+        return value;
+    }
+
+    @Override
+    public Direction direction() {
+        return base.direction();
+    }
+
+    @Override
+    public ValueNode initNode() {
+        return IntegerConvertNode.convert(base.initNode(), stamp, graph());
+    }
+
+    @Override
+    public ValueNode strideNode() {
+        return IntegerConvertNode.convert(base.strideNode(), stamp, graph());
+    }
+
+    @Override
+    public boolean isConstantInit() {
+        return base.isConstantInit();
+    }
+
+    @Override
+    public boolean isConstantStride() {
+        return base.isConstantStride();
+    }
+
+    @Override
+    public long constantInit() {
+        return base.constantInit();
+    }
+
+    @Override
+    public long constantStride() {
+        return base.constantStride();
+    }
+
+    @Override
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp s) {
+        return base.extremumNode(assumePositiveTripCount, s);
+    }
+
+    @Override
+    public ValueNode exitValueNode() {
+        return IntegerConvertNode.convert(base.exitValueNode(), stamp, graph());
+    }
+
+    @Override
+    public boolean isConstantExtremum() {
+        return base.isConstantExtremum();
+    }
+
+    @Override
+    public long constantExtremum() {
+        return base.constantExtremum();
+    }
+
+    @Override
+    public void deleteUnusedNodes() {
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DerivedConvertedInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), stamp);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedInductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedInductionVariable.java
new file mode 100644
index 0000000..16f9eb8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedInductionVariable.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * Base class of the derived induction variables.
+ */
+public abstract class DerivedInductionVariable extends InductionVariable {
+
+    protected final InductionVariable base;
+
+    public DerivedInductionVariable(LoopEx loop, InductionVariable base) {
+        super(loop);
+        this.base = base;
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return base.graph();
+    }
+
+    public InductionVariable getBase() {
+        return base;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java
new file mode 100644
index 0000000..82dbae6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.loop.MathUtil.add;
+import static org.graalvm.compiler.loop.MathUtil.sub;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+
+public class DerivedOffsetInductionVariable extends DerivedInductionVariable {
+
+    private final ValueNode offset;
+    private final BinaryArithmeticNode<?> value;
+
+    public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode<?> value) {
+        super(loop, base);
+        this.offset = offset;
+        this.value = value;
+    }
+
+    public ValueNode getOffset() {
+        return offset;
+    }
+
+    @Override
+    public Direction direction() {
+        return base.direction();
+    }
+
+    @Override
+    public ValueNode valueNode() {
+        return value;
+    }
+
+    @Override
+    public boolean isConstantInit() {
+        return offset.isConstant() && base.isConstantInit();
+    }
+
+    @Override
+    public boolean isConstantStride() {
+        return base.isConstantStride();
+    }
+
+    @Override
+    public long constantInit() {
+        return op(base.constantInit(), offset.asJavaConstant().asLong());
+    }
+
+    @Override
+    public long constantStride() {
+        if (value instanceof SubNode && base.valueNode() == value.getY()) {
+            return -base.constantStride();
+        }
+        return base.constantStride();
+    }
+
+    @Override
+    public ValueNode initNode() {
+        return op(base.initNode(), offset);
+    }
+
+    @Override
+    public ValueNode strideNode() {
+        if (value instanceof SubNode && base.valueNode() == value.getY()) {
+            return graph().unique(new NegateNode(base.strideNode()));
+        }
+        return base.strideNode();
+    }
+
+    @Override
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
+        return op(base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(offset, stamp, graph()));
+    }
+
+    @Override
+    public ValueNode exitValueNode() {
+        return op(base.exitValueNode(), offset);
+    }
+
+    @Override
+    public boolean isConstantExtremum() {
+        return offset.isConstant() && base.isConstantExtremum();
+    }
+
+    @Override
+    public long constantExtremum() {
+        return op(base.constantExtremum(), offset.asJavaConstant().asLong());
+    }
+
+    private long op(long b, long o) {
+        if (value instanceof AddNode) {
+            return b + o;
+        }
+        if (value instanceof SubNode) {
+            if (base.valueNode() == value.getX()) {
+                return b - o;
+            } else {
+                assert base.valueNode() == value.getY();
+                return o - b;
+            }
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    private ValueNode op(ValueNode b, ValueNode o) {
+        if (value instanceof AddNode) {
+            return add(graph(), b, o);
+        }
+        if (value instanceof SubNode) {
+            if (base.valueNode() == value.getX()) {
+                return sub(graph(), b, o);
+            } else {
+                assert base.valueNode() == value.getY();
+                return sub(graph(), o, b);
+            }
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public void deleteUnusedNodes() {
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DerivedOffsetInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), offset);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java
new file mode 100644
index 0000000..2a3cc7a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.loop.MathUtil.mul;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+public class DerivedScaledInductionVariable extends DerivedInductionVariable {
+
+    private final ValueNode scale;
+    private final ValueNode value;
+
+    public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, ValueNode scale, ValueNode value) {
+        super(loop, base);
+        this.scale = scale;
+        this.value = value;
+    }
+
+    public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) {
+        super(loop, base);
+        this.scale = ConstantNode.forIntegerStamp(value.stamp(), -1, value.graph());
+        this.value = value;
+    }
+
+    public ValueNode getScale() {
+        return scale;
+    }
+
+    @Override
+    public ValueNode valueNode() {
+        return value;
+    }
+
+    @Override
+    public Direction direction() {
+        Stamp stamp = scale.stamp();
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp integerStamp = (IntegerStamp) stamp;
+            if (integerStamp.isStrictlyPositive()) {
+                return base.direction();
+            } else if (integerStamp.isStrictlyNegative()) {
+                return base.direction().opposite();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode initNode() {
+        return mul(graph(), base.initNode(), scale);
+    }
+
+    @Override
+    public ValueNode strideNode() {
+        return mul(graph(), base.strideNode(), scale);
+    }
+
+    @Override
+    public boolean isConstantInit() {
+        return scale.isConstant() && base.isConstantInit();
+    }
+
+    @Override
+    public boolean isConstantStride() {
+        return scale.isConstant() && base.isConstantStride();
+    }
+
+    @Override
+    public long constantInit() {
+        return base.constantInit() * scale.asJavaConstant().asLong();
+    }
+
+    @Override
+    public long constantStride() {
+        return base.constantStride() * scale.asJavaConstant().asLong();
+    }
+
+    @Override
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
+        return mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp, graph()));
+    }
+
+    @Override
+    public ValueNode exitValueNode() {
+        return mul(graph(), base.exitValueNode(), scale);
+    }
+
+    @Override
+    public boolean isConstantExtremum() {
+        return scale.isConstant() && base.isConstantExtremum();
+    }
+
+    @Override
+    public long constantExtremum() {
+        return base.constantExtremum() * scale.asJavaConstant().asLong();
+    }
+
+    @Override
+    public void deleteUnusedNodes() {
+        if (scale.isAlive() && scale.hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(scale);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DerivedScaleInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), scale);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/InductionVariable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/InductionVariable.java
new file mode 100644
index 0000000..2384ad8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/InductionVariable.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * This class describes a value node that is an induction variable in a counted loop.
+ */
+public abstract class InductionVariable {
+
+    public enum Direction {
+        Up,
+        Down;
+
+        public Direction opposite() {
+            switch (this) {
+                case Up:
+                    return Down;
+                case Down:
+                    return Up;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public abstract StructuredGraph graph();
+
+    protected final LoopEx loop;
+
+    public InductionVariable(LoopEx loop) {
+        this.loop = loop;
+    }
+
+    public LoopEx getLoop() {
+        return loop;
+    }
+
+    public abstract Direction direction();
+
+    /**
+     * Returns the value node that is described by this induction variable.
+     */
+    public abstract ValueNode valueNode();
+
+    /**
+     * Returns the node that gives the initial value of this induction variable.
+     */
+    public abstract ValueNode initNode();
+
+    /**
+     * Returns the stride of the induction variable. The stride is the value that is added to the
+     * induction variable at each iteration.
+     */
+    public abstract ValueNode strideNode();
+
+    public abstract boolean isConstantInit();
+
+    public abstract boolean isConstantStride();
+
+    public abstract long constantInit();
+
+    public abstract long constantStride();
+
+    /**
+     * Returns the extremum value of the induction variable. The extremum value is the value of the
+     * induction variable in the loop body of the last iteration, only taking into account the main
+     * loop limit test. It's possible for the loop to exit before this value if
+     * {@link CountedLoopInfo#isExactTripCount()} returns false for the containing loop.
+     */
+    public ValueNode extremumNode() {
+        return extremumNode(false, valueNode().stamp());
+    }
+
+    public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp);
+
+    public abstract boolean isConstantExtremum();
+
+    public abstract long constantExtremum();
+
+    /**
+     * Returns the exit value of the induction variable. The exit value is the value of the
+     * induction variable at the loop exit.
+     */
+    public abstract ValueNode exitValueNode();
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public abstract void deleteUnusedNodes();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java
new file mode 100644
index 0000000..27c9d66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import static org.graalvm.compiler.graph.Node.newIdentityMap;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.iterators.NodePredicate;
+import org.graalvm.compiler.loop.InductionVariable.Direction;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.BytecodeFrame;
+
+public class LoopEx {
+
+    private final Loop<Block> loop;
+    private LoopFragmentInside inside;
+    private LoopFragmentWhole whole;
+    private CountedLoopInfo counted;
+    private LoopsData data;
+    private Map<Node, InductionVariable> ivs;
+
+    LoopEx(Loop<Block> loop, LoopsData data) {
+        this.loop = loop;
+        this.data = data;
+    }
+
+    public Loop<Block> loop() {
+        return loop;
+    }
+
+    public LoopFragmentInside inside() {
+        if (inside == null) {
+            inside = new LoopFragmentInside(this);
+        }
+        return inside;
+    }
+
+    public LoopFragmentWhole whole() {
+        if (whole == null) {
+            whole = new LoopFragmentWhole(this);
+        }
+        return whole;
+    }
+
+    public void invalidateFragments() {
+        inside = null;
+        whole = null;
+    }
+
+    @SuppressWarnings("unused")
+    public LoopFragmentInsideFrom insideFrom(FixedNode point) {
+        // TODO (gd)
+        return null;
+    }
+
+    @SuppressWarnings("unused")
+    public LoopFragmentInsideBefore insideBefore(FixedNode point) {
+        // TODO (gd)
+        return null;
+    }
+
+    public boolean isOutsideLoop(Node n) {
+        return !whole().contains(n);
+    }
+
+    public LoopBeginNode loopBegin() {
+        return (LoopBeginNode) loop().getHeader().getBeginNode();
+    }
+
+    public FixedNode predecessor() {
+        return (FixedNode) loopBegin().forwardEnd().predecessor();
+    }
+
+    public FixedNode entryPoint() {
+        return loopBegin().forwardEnd();
+    }
+
+    public boolean isCounted() {
+        return counted != null;
+    }
+
+    public CountedLoopInfo counted() {
+        return counted;
+    }
+
+    public LoopEx parent() {
+        if (loop.getParent() == null) {
+            return null;
+        }
+        return data.loop(loop.getParent());
+    }
+
+    public int size() {
+        return whole().nodes().count();
+    }
+
+    @Override
+    public String toString() {
+        return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + loop().getDepth() + ") " + loopBegin();
+    }
+
+    private class InvariantPredicate implements NodePredicate {
+
+        @Override
+        public boolean apply(Node n) {
+            return isOutsideLoop(n);
+        }
+    }
+
+    public void reassociateInvariants() {
+        InvariantPredicate invariant = new InvariantPredicate();
+        StructuredGraph graph = loopBegin().graph();
+        for (BinaryArithmeticNode<?> binary : whole().nodes().filter(BinaryArithmeticNode.class)) {
+            if (!binary.isAssociative()) {
+                continue;
+            }
+            BinaryArithmeticNode<?> result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY());
+            if (result != binary) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result);
+                }
+                if (!result.isAlive()) {
+                    assert !result.isDeleted();
+                    result = graph.addOrUniqueWithInputs(result);
+                }
+                binary.replaceAtUsages(result);
+                GraphUtil.killWithUnusedFloatingInputs(binary);
+            }
+        }
+    }
+
+    public boolean detectCounted() {
+        LoopBeginNode loopBegin = loopBegin();
+        FixedNode next = loopBegin.next();
+        while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode || next instanceof FullInfopointNode) {
+            next = ((FixedWithNextNode) next).next();
+        }
+        if (next instanceof IfNode) {
+            IfNode ifNode = (IfNode) next;
+            boolean negated = false;
+            if (!loopBegin.isLoopExit(ifNode.falseSuccessor())) {
+                if (!loopBegin.isLoopExit(ifNode.trueSuccessor())) {
+                    return false;
+                }
+                negated = true;
+            }
+            LogicNode ifTest = ifNode.condition();
+            if (!(ifTest instanceof IntegerLessThanNode) && !(ifTest instanceof IntegerEqualsNode)) {
+                if (ifTest instanceof IntegerBelowNode) {
+                    Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin);
+                }
+                return false;
+            }
+            CompareNode lessThan = (CompareNode) ifTest;
+            Condition condition = null;
+            InductionVariable iv = null;
+            ValueNode limit = null;
+            if (isOutsideLoop(lessThan.getX())) {
+                iv = getInductionVariables().get(lessThan.getY());
+                if (iv != null) {
+                    condition = lessThan.condition().mirror();
+                    limit = lessThan.getX();
+                }
+            } else if (isOutsideLoop(lessThan.getY())) {
+                iv = getInductionVariables().get(lessThan.getX());
+                if (iv != null) {
+                    condition = lessThan.condition();
+                    limit = lessThan.getY();
+                }
+            }
+            if (condition == null) {
+                return false;
+            }
+            if (negated) {
+                condition = condition.negate();
+            }
+            boolean oneOff = false;
+            switch (condition) {
+                case EQ:
+                    return false;
+                case NE: {
+                    if (!iv.isConstantStride() || Math.abs(iv.constantStride()) != 1) {
+                        return false;
+                    }
+                    IntegerStamp initStamp = (IntegerStamp) iv.initNode().stamp();
+                    IntegerStamp limitStamp = (IntegerStamp) limit.stamp();
+                    if (iv.direction() == Direction.Up) {
+                        if (initStamp.upperBound() > limitStamp.lowerBound()) {
+                            return false;
+                        }
+                    } else if (iv.direction() == Direction.Down) {
+                        if (initStamp.lowerBound() < limitStamp.upperBound()) {
+                            return false;
+                        }
+                    } else {
+                        return false;
+                    }
+                    break;
+                }
+                case LE:
+                    oneOff = true;
+                    if (iv.direction() != Direction.Up) {
+                        return false;
+                    }
+                    break;
+                case LT:
+                    if (iv.direction() != Direction.Up) {
+                        return false;
+                    }
+                    break;
+                case GE:
+                    oneOff = true;
+                    if (iv.direction() != Direction.Down) {
+                        return false;
+                    }
+                    break;
+                case GT:
+                    if (iv.direction() != Direction.Down) {
+                        return false;
+                    }
+                    break;
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+            counted = new CountedLoopInfo(this, iv, limit, oneOff, negated ? ifNode.falseSuccessor() : ifNode.trueSuccessor());
+            return true;
+        }
+        return false;
+    }
+
+    public LoopsData loopsData() {
+        return data;
+    }
+
+    public void nodesInLoopBranch(NodeBitMap branchNodes, AbstractBeginNode branch) {
+        Collection<AbstractBeginNode> blocks = new LinkedList<>();
+        Collection<LoopExitNode> exits = new LinkedList<>();
+        Queue<Block> work = new LinkedList<>();
+        ControlFlowGraph cfg = loopsData().getCFG();
+        work.add(cfg.blockFor(branch));
+        while (!work.isEmpty()) {
+            Block b = work.remove();
+            if (loop().getExits().contains(b)) {
+                exits.add((LoopExitNode) b.getBeginNode());
+            } else {
+                blocks.add(b.getBeginNode());
+                for (Block d : b.getDominated()) {
+                    if (loop.getBlocks().contains(d)) {
+                        work.add(d);
+                    }
+                }
+            }
+        }
+        LoopFragment.computeNodes(branchNodes, branch.graph(), blocks, exits);
+    }
+
+    public Map<Node, InductionVariable> getInductionVariables() {
+        if (ivs == null) {
+            ivs = findInductionVariables(this);
+        }
+        return ivs;
+    }
+
+    /**
+     * Collect all the basic induction variables for the loop and the find any induction variables
+     * which are derived from the basic ones.
+     *
+     * @param loop
+     * @return a map from node to induction variable
+     */
+    private static Map<Node, InductionVariable> findInductionVariables(LoopEx loop) {
+        Map<Node, InductionVariable> ivs = newIdentityMap();
+
+        Queue<InductionVariable> scanQueue = new LinkedList<>();
+        LoopBeginNode loopBegin = loop.loopBegin();
+        AbstractEndNode forwardEnd = loopBegin.forwardEnd();
+        for (PhiNode phi : loopBegin.phis().filter(ValuePhiNode.class)) {
+            ValueNode backValue = phi.singleBackValue();
+            if (backValue == PhiNode.MULTIPLE_VALUES) {
+                continue;
+            }
+            ValueNode stride = addSub(loop, backValue, phi);
+            if (stride != null) {
+                BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (BinaryArithmeticNode<?>) backValue);
+                ivs.put(phi, biv);
+                scanQueue.add(biv);
+            }
+        }
+
+        while (!scanQueue.isEmpty()) {
+            InductionVariable baseIv = scanQueue.remove();
+            ValueNode baseIvNode = baseIv.valueNode();
+            for (ValueNode op : baseIvNode.usages().filter(ValueNode.class)) {
+                if (loop.isOutsideLoop(op)) {
+                    continue;
+                }
+                if (op.usages().count() == 1 && op.usages().first() == baseIvNode) {
+                    /*
+                     * This is just the base induction variable increment with no other uses so
+                     * don't bother reporting it.
+                     */
+                    continue;
+                }
+                InductionVariable iv = null;
+                ValueNode offset = addSub(loop, op, baseIvNode);
+                ValueNode scale;
+                if (offset != null) {
+                    iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (BinaryArithmeticNode<?>) op);
+                } else if (op instanceof NegateNode) {
+                    iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op);
+                } else if ((scale = mul(loop, op, baseIvNode)) != null) {
+                    iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op);
+                } else {
+                    boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode;
+                    if (!isValidConvert && op instanceof ZeroExtendNode) {
+                        IntegerStamp inputStamp = (IntegerStamp) ((ZeroExtendNode) op).getValue().stamp();
+                        isValidConvert = inputStamp.isPositive();
+                    }
+
+                    if (isValidConvert) {
+                        iv = new DerivedConvertedInductionVariable(loop, baseIv, op.stamp(), op);
+                    }
+                }
+
+                if (iv != null) {
+                    ivs.put(op, iv);
+                    scanQueue.offer(iv);
+                }
+            }
+        }
+        return Collections.unmodifiableMap(ivs);
+    }
+
+    private static ValueNode addSub(LoopEx loop, ValueNode op, ValueNode base) {
+        if (op.stamp() instanceof IntegerStamp && (op instanceof AddNode || op instanceof SubNode)) {
+            BinaryArithmeticNode<?> aritOp = (BinaryArithmeticNode<?>) op;
+            if (aritOp.getX() == base && loop.isOutsideLoop(aritOp.getY())) {
+                return aritOp.getY();
+            } else if (aritOp.getY() == base && loop.isOutsideLoop(aritOp.getX())) {
+                return aritOp.getX();
+            }
+        }
+        return null;
+    }
+
+    private static ValueNode mul(LoopEx loop, ValueNode op, ValueNode base) {
+        if (op instanceof MulNode) {
+            MulNode mul = (MulNode) op;
+            if (mul.getX() == base && loop.isOutsideLoop(mul.getY())) {
+                return mul.getY();
+            } else if (mul.getY() == base && loop.isOutsideLoop(mul.getX())) {
+                return mul.getX();
+            }
+        }
+        if (op instanceof LeftShiftNode) {
+            LeftShiftNode shift = (LeftShiftNode) op;
+            if (shift.getX() == base && shift.getY().isConstant()) {
+                return ConstantNode.forIntegerStamp(base.stamp(), 1 << shift.getY().asJavaConstant().asInt(), base.graph());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+        if (ivs != null) {
+            for (InductionVariable iv : ivs.values()) {
+                iv.deleteUnusedNodes();
+            }
+        }
+    }
+
+    /**
+     * @return true if all nodes in the loop can be duplicated.
+     */
+    public boolean canDuplicateLoop() {
+        for (Node node : inside().nodes()) {
+            if (node instanceof ControlFlowAnchorNode) {
+                return false;
+            }
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || frameState.bci == BytecodeFrame.UNWIND_BCI) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java
new file mode 100644
index 0000000..dea444f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.GuardPhiNode;
+import org.graalvm.compiler.nodes.GuardProxyNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.java.MonitorEnterNode;
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+public abstract class LoopFragment {
+
+    private final LoopEx loop;
+    private final LoopFragment original;
+    protected NodeBitMap nodes;
+    protected boolean nodesReady;
+    private Map<Node, Node> duplicationMap;
+
+    public LoopFragment(LoopEx loop) {
+        this(loop, null);
+        this.nodesReady = true;
+    }
+
+    public LoopFragment(LoopEx loop, LoopFragment original) {
+        this.loop = loop;
+        this.original = original;
+        this.nodesReady = false;
+    }
+
+    public LoopEx loop() {
+        return loop;
+    }
+
+    public abstract LoopFragment duplicate();
+
+    public abstract void insertBefore(LoopEx l);
+
+    public void disconnect() {
+        // TODO (gd) possibly abstract
+    }
+
+    public boolean contains(Node n) {
+        return nodes().isMarkedAndGrow(n);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <New extends Node, Old extends New> New getDuplicatedNode(Old n) {
+        assert isDuplicate();
+        return (New) duplicationMap.get(n);
+    }
+
+    protected <New extends Node, Old extends New> void putDuplicatedNode(Old oldNode, New newNode) {
+        duplicationMap.put(oldNode, newNode);
+    }
+
+    /**
+     * Gets the corresponding value in this fragment. Should be called on duplicate fragments with a
+     * node from the original fragment as argument.
+     *
+     * @param b original value
+     * @return corresponding value in the peel
+     */
+    protected abstract ValueNode prim(ValueNode b);
+
+    public boolean isDuplicate() {
+        return original != null;
+    }
+
+    public LoopFragment original() {
+        return original;
+    }
+
+    public abstract NodeBitMap nodes();
+
+    public StructuredGraph graph() {
+        LoopEx l;
+        if (isDuplicate()) {
+            l = original().loop();
+        } else {
+            l = loop();
+        }
+        return l.loopBegin().graph();
+    }
+
+    protected abstract DuplicationReplacement getDuplicationReplacement();
+
+    protected abstract void finishDuplication();
+
+    protected void patchNodes(final DuplicationReplacement dataFix) {
+        if (isDuplicate() && !nodesReady) {
+            assert !original.isDuplicate();
+            final DuplicationReplacement cfgFix = original().getDuplicationReplacement();
+            DuplicationReplacement dr;
+            if (cfgFix == null && dataFix != null) {
+                dr = dataFix;
+            } else if (cfgFix != null && dataFix == null) {
+                dr = cfgFix;
+            } else if (cfgFix != null && dataFix != null) {
+                dr = new DuplicationReplacement() {
+
+                    @Override
+                    public Node replacement(Node o) {
+                        Node r1 = dataFix.replacement(o);
+                        if (r1 != o) {
+                            assert cfgFix.replacement(o) == o;
+                            return r1;
+                        }
+                        Node r2 = cfgFix.replacement(o);
+                        if (r2 != o) {
+                            return r2;
+                        }
+                        return o;
+                    }
+                };
+            } else {
+                dr = null;
+            }
+            NodeIterable<Node> nodesIterable = original().nodes();
+            duplicationMap = graph().addDuplicates(nodesIterable, graph(), nodesIterable.count(), dr);
+            finishDuplication();
+            nodesReady = true;
+        } else {
+            // TODO (gd) apply fix ?
+        }
+    }
+
+    protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks) {
+        return computeNodes(graph, blocks, Collections.emptyList());
+    }
+
+    protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<LoopExitNode> earlyExits) {
+        final NodeBitMap nodes = graph.createNodeBitMap();
+        computeNodes(nodes, graph, blocks, earlyExits);
+        return nodes;
+    }
+
+    protected static void computeNodes(NodeBitMap nodes, Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<LoopExitNode> earlyExits) {
+        for (AbstractBeginNode b : blocks) {
+            if (b.isDeleted()) {
+                continue;
+            }
+
+            for (Node n : b.getBlockNodes()) {
+                if (n instanceof Invoke) {
+                    nodes.mark(((Invoke) n).callTarget());
+                }
+                if (n instanceof NodeWithState) {
+                    NodeWithState withState = (NodeWithState) n;
+                    withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node)));
+                }
+                nodes.mark(n);
+            }
+        }
+        for (LoopExitNode earlyExit : earlyExits) {
+            if (earlyExit.isDeleted()) {
+                continue;
+            }
+
+            FrameState stateAfter = earlyExit.stateAfter();
+            if (stateAfter != null) {
+                stateAfter.applyToVirtual(node -> nodes.mark(node));
+            }
+            nodes.mark(earlyExit);
+            for (ProxyNode proxy : earlyExit.proxies()) {
+                nodes.mark(proxy);
+            }
+        }
+
+        final NodeBitMap notloopNodes = graph.createNodeBitMap();
+        for (AbstractBeginNode b : blocks) {
+            if (b.isDeleted()) {
+                continue;
+            }
+
+            for (Node n : b.getBlockNodes()) {
+                if (n instanceof CommitAllocationNode) {
+                    for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
+                        markFloating(obj, nodes, notloopNodes);
+                    }
+                }
+                if (n instanceof MonitorEnterNode) {
+                    markFloating(((MonitorEnterNode) n).getMonitorId(), nodes, notloopNodes);
+                }
+                for (Node usage : n.usages()) {
+                    markFloating(usage, nodes, notloopNodes);
+                }
+            }
+        }
+    }
+
+    private static boolean markFloating(Node n, NodeBitMap loopNodes, NodeBitMap notloopNodes) {
+        if (loopNodes.isMarked(n)) {
+            return true;
+        }
+        if (notloopNodes.isMarked(n)) {
+            return false;
+        }
+        if (n instanceof FixedNode) {
+            return false;
+        }
+        boolean mark = false;
+        if (n instanceof PhiNode) {
+            PhiNode phi = (PhiNode) n;
+            mark = loopNodes.isMarked(phi.merge());
+            if (mark) {
+                loopNodes.mark(n);
+            } else {
+                notloopNodes.mark(n);
+                return false;
+            }
+        }
+        for (Node usage : n.usages()) {
+            if (markFloating(usage, loopNodes, notloopNodes)) {
+                mark = true;
+            }
+        }
+        if (mark) {
+            loopNodes.mark(n);
+            return true;
+        }
+        notloopNodes.mark(n);
+        return false;
+    }
+
+    public static NodeIterable<AbstractBeginNode> toHirBlocks(final Iterable<Block> blocks) {
+        return new NodeIterable<AbstractBeginNode>() {
+
+            @Override
+            public Iterator<AbstractBeginNode> iterator() {
+                final Iterator<Block> it = blocks.iterator();
+                return new Iterator<AbstractBeginNode>() {
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+
+                    @Override
+                    public AbstractBeginNode next() {
+                        return it.next().getBeginNode();
+                    }
+
+                    @Override
+                    public boolean hasNext() {
+                        return it.hasNext();
+                    }
+                };
+            }
+
+        };
+    }
+
+    public static NodeIterable<LoopExitNode> toHirExits(final Iterable<Block> blocks) {
+        return new NodeIterable<LoopExitNode>() {
+
+            @Override
+            public Iterator<LoopExitNode> iterator() {
+                final Iterator<Block> it = blocks.iterator();
+                return new Iterator<LoopExitNode>() {
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+
+                    @Override
+                    public LoopExitNode next() {
+                        return (LoopExitNode) it.next().getBeginNode();
+                    }
+
+                    @Override
+                    public boolean hasNext() {
+                        return it.hasNext();
+                    }
+                };
+            }
+
+        };
+    }
+
+    /**
+     * Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with
+     * the original fragment's exits.
+     */
+    protected void mergeEarlyExits() {
+        assert isDuplicate();
+        StructuredGraph graph = graph();
+        for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().loop().getExits())) {
+            LoopExitNode loopEarlyExit = (LoopExitNode) earlyExit;
+            FixedNode next = loopEarlyExit.next();
+            if (loopEarlyExit.isDeleted() || !this.original().contains(loopEarlyExit)) {
+                continue;
+            }
+            AbstractBeginNode newEarlyExit = getDuplicatedNode(loopEarlyExit);
+            if (newEarlyExit == null) {
+                continue;
+            }
+            MergeNode merge = graph.add(new MergeNode());
+            EndNode originalEnd = graph.add(new EndNode());
+            EndNode newEnd = graph.add(new EndNode());
+            merge.addForwardEnd(originalEnd);
+            merge.addForwardEnd(newEnd);
+            loopEarlyExit.setNext(originalEnd);
+            newEarlyExit.setNext(newEnd);
+            merge.setNext(next);
+
+            FrameState exitState = loopEarlyExit.stateAfter();
+            if (exitState != null) {
+                FrameState originalExitState = exitState;
+                exitState = exitState.duplicateWithVirtualState();
+                loopEarlyExit.setStateAfter(exitState);
+                merge.setStateAfter(originalExitState);
+                /*
+                 * Using the old exit's state as the merge's state is necessary because some of the
+                 * VirtualState nodes contained in the old exit's state may be shared by other
+                 * dominated VirtualStates. Those dominated virtual states need to see the
+                 * proxy->phi update that are applied below.
+                 *
+                 * We now update the original fragment's nodes accordingly:
+                 */
+                originalExitState.applyToVirtual(node -> original.nodes.clearAndGrow(node));
+                exitState.applyToVirtual(node -> original.nodes.markAndGrow(node));
+            }
+            FrameState finalExitState = exitState;
+
+            for (Node anchored : loopEarlyExit.anchored().snapshot()) {
+                anchored.replaceFirstInput(loopEarlyExit, merge);
+            }
+
+            boolean newEarlyExitIsLoopExit = newEarlyExit instanceof LoopExitNode;
+            for (ProxyNode vpn : loopEarlyExit.proxies().snapshot()) {
+                if (vpn.hasNoUsages()) {
+                    continue;
+                }
+                if (vpn.value() == null) {
+                    assert vpn instanceof GuardProxyNode;
+                    vpn.replaceAtUsages(null);
+                    continue;
+                }
+                final ValueNode replaceWith;
+                ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value());
+                if (newVpn != null) {
+                    PhiNode phi;
+                    if (vpn instanceof ValueProxyNode) {
+                        phi = graph.addWithoutUnique(new ValuePhiNode(vpn.stamp(), merge));
+                    } else if (vpn instanceof GuardProxyNode) {
+                        phi = graph.addWithoutUnique(new GuardPhiNode(merge));
+                    } else {
+                        throw GraalError.shouldNotReachHere();
+                    }
+                    phi.addInput(vpn);
+                    phi.addInput(newVpn);
+                    replaceWith = phi;
+                } else {
+                    replaceWith = vpn.value();
+                }
+                vpn.replaceAtMatchingUsages(replaceWith, usage -> {
+                    if (merge.isPhiAtMerge(usage)) {
+                        return false;
+                    }
+                    if (usage instanceof VirtualState) {
+                        VirtualState stateUsage = (VirtualState) usage;
+                        if (finalExitState != null && finalExitState.isPartOfThisState(stateUsage)) {
+                            return false;
+                        }
+                    }
+                    return true;
+                });
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java
new file mode 100644
index 0000000..7b80428
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.GuardPhiNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.VirtualState.NodeClosure;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+public class LoopFragmentInside extends LoopFragment {
+
+    /**
+     * mergedInitializers. When an inside fragment's (loop)ends are merged to create a unique exit
+     * point, some phis must be created : they phis together all the back-values of the loop-phis
+     * These can then be used to update the loop-phis' forward edge value ('initializer') in the
+     * peeling case. In the unrolling case they will be used as the value that replace the loop-phis
+     * of the duplicated inside fragment
+     */
+    private Map<ValuePhiNode, ValueNode> mergedInitializers;
+    private final DuplicationReplacement dataFixBefore = new DuplicationReplacement() {
+
+        @Override
+        public Node replacement(Node oriInput) {
+            if (!(oriInput instanceof ValueNode)) {
+                return oriInput;
+            }
+            return prim((ValueNode) oriInput);
+        }
+    };
+
+    public LoopFragmentInside(LoopEx loop) {
+        super(loop);
+    }
+
+    public LoopFragmentInside(LoopFragmentInside original) {
+        super(null, original);
+    }
+
+    @Override
+    public LoopFragmentInside duplicate() {
+        assert !isDuplicate();
+        return new LoopFragmentInside(this);
+    }
+
+    @Override
+    public LoopFragmentInside original() {
+        return (LoopFragmentInside) super.original();
+    }
+
+    @SuppressWarnings("unused")
+    public void appendInside(LoopEx loop) {
+        // TODO (gd)
+    }
+
+    @Override
+    public LoopEx loop() {
+        assert !this.isDuplicate();
+        return super.loop();
+    }
+
+    @Override
+    public void insertBefore(LoopEx loop) {
+        assert this.isDuplicate() && this.original().loop() == loop;
+
+        patchNodes(dataFixBefore);
+
+        AbstractBeginNode end = mergeEnds();
+
+        mergeEarlyExits();
+
+        original().patchPeeling(this);
+
+        AbstractBeginNode entry = getDuplicatedNode(loop.loopBegin());
+        loop.entryPoint().replaceAtPredecessor(entry);
+        end.setNext(loop.entryPoint());
+    }
+
+    @Override
+    public NodeBitMap nodes() {
+        if (nodes == null) {
+            LoopFragmentWhole whole = loop().whole();
+            whole.nodes(); // init nodes bitmap in whole
+            nodes = whole.nodes.copy();
+            // remove the phis
+            LoopBeginNode loopBegin = loop().loopBegin();
+            for (PhiNode phi : loopBegin.phis()) {
+                nodes.clear(phi);
+            }
+            clearStateNodes(loopBegin);
+            for (LoopExitNode exit : exits()) {
+                clearStateNodes(exit);
+                for (ProxyNode proxy : exit.proxies()) {
+                    nodes.clear(proxy);
+                }
+            }
+        }
+        return nodes;
+    }
+
+    private void clearStateNodes(StateSplit stateSplit) {
+        FrameState loopState = stateSplit.stateAfter();
+        if (loopState != null) {
+            loopState.applyToVirtual(v -> {
+                if (v.usages().filter(n -> nodes.isMarked(n) && n != stateSplit).isEmpty()) {
+                    nodes.clear(v);
+                }
+            });
+        }
+    }
+
+    public NodeIterable<LoopExitNode> exits() {
+        return loop().loopBegin().loopExits();
+    }
+
+    @Override
+    protected DuplicationReplacement getDuplicationReplacement() {
+        final LoopBeginNode loopBegin = loop().loopBegin();
+        final StructuredGraph graph = graph();
+        return new DuplicationReplacement() {
+
+            private Map<Node, Node> seenNode = Node.newMap();
+
+            @Override
+            public Node replacement(Node original) {
+                if (original == loopBegin) {
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    AbstractBeginNode newValue = graph.add(new BeginNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
+                }
+                if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) {
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    AbstractBeginNode newValue = graph.add(new BeginNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
+                }
+                if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) {
+                    Node value = seenNode.get(original);
+                    if (value != null) {
+                        return value;
+                    }
+                    EndNode newValue = graph.add(new EndNode());
+                    seenNode.put(original, newValue);
+                    return newValue;
+                }
+                return original;
+            }
+        };
+    }
+
+    @Override
+    protected void finishDuplication() {
+        // TODO (gd) ?
+    }
+
+    private static PhiNode patchPhi(StructuredGraph graph, PhiNode phi, AbstractMergeNode merge) {
+        PhiNode ret;
+        if (phi instanceof ValuePhiNode) {
+            ret = new ValuePhiNode(phi.stamp(), merge);
+        } else if (phi instanceof GuardPhiNode) {
+            ret = new GuardPhiNode(merge);
+        } else if (phi instanceof MemoryPhiNode) {
+            ret = new MemoryPhiNode(merge, ((MemoryPhiNode) phi).getLocationIdentity());
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+        return graph.addWithoutUnique(ret);
+    }
+
+    private void patchPeeling(LoopFragmentInside peel) {
+        LoopBeginNode loopBegin = loop().loopBegin();
+        StructuredGraph graph = loopBegin.graph();
+        List<PhiNode> newPhis = new LinkedList<>();
+
+        NodeBitMap usagesToPatch = nodes.copy();
+        for (LoopExitNode exit : exits()) {
+            markStateNodes(exit, usagesToPatch);
+            for (ProxyNode proxy : exit.proxies()) {
+                usagesToPatch.markAndGrow(proxy);
+            }
+        }
+        markStateNodes(loopBegin, usagesToPatch);
+
+        List<PhiNode> oldPhis = loopBegin.phis().snapshot();
+        for (PhiNode phi : oldPhis) {
+            if (phi.hasNoUsages()) {
+                continue;
+            }
+            ValueNode first;
+            if (loopBegin.loopEnds().count() == 1) {
+                ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value
+                first = peel.prim(b); // corresponding value in the peel
+            } else {
+                first = peel.mergedInitializers.get(phi);
+            }
+            // create a new phi (we don't patch the old one since some usages of the old one may
+            // still be valid)
+            PhiNode newPhi = patchPhi(graph, phi, loopBegin);
+            newPhi.addInput(first);
+            for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
+                newPhi.addInput(phi.valueAt(end));
+            }
+            peel.putDuplicatedNode(phi, newPhi);
+            newPhis.add(newPhi);
+            for (Node usage : phi.usages().snapshot()) {
+                // patch only usages that should use the new phi ie usages that were peeled
+                if (usagesToPatch.isMarkedAndGrow(usage)) {
+                    usage.replaceFirstInput(phi, newPhi);
+                }
+            }
+        }
+        // check new phis to see if they have as input some old phis, replace those inputs with the
+        // new corresponding phis
+        for (PhiNode phi : newPhis) {
+            for (int i = 0; i < phi.valueCount(); i++) {
+                ValueNode v = phi.valueAt(i);
+                if (loopBegin.isPhiAtMerge(v)) {
+                    PhiNode newV = peel.getDuplicatedNode((ValuePhiNode) v);
+                    if (newV != null) {
+                        phi.setValueAt(i, newV);
+                    }
+                }
+            }
+        }
+
+        boolean progress = true;
+        while (progress) {
+            progress = false;
+            int i = 0;
+            outer: while (i < oldPhis.size()) {
+                PhiNode oldPhi = oldPhis.get(i);
+                for (Node usage : oldPhi.usages()) {
+                    if (usage instanceof PhiNode && oldPhis.contains(usage)) {
+                        // Do not mark.
+                    } else {
+                        // Mark alive by removing from delete set.
+                        oldPhis.remove(i);
+                        progress = true;
+                        continue outer;
+                    }
+                }
+                i++;
+            }
+        }
+
+        for (PhiNode deadPhi : oldPhis) {
+            deadPhi.clearInputs();
+        }
+
+        for (PhiNode deadPhi : oldPhis) {
+            if (deadPhi.isAlive()) {
+                GraphUtil.killWithUnusedFloatingInputs(deadPhi);
+            }
+        }
+    }
+
+    private static void markStateNodes(StateSplit stateSplit, NodeBitMap marks) {
+        FrameState exitState = stateSplit.stateAfter();
+        if (exitState != null) {
+            exitState.applyToVirtual(v -> marks.markAndGrow(v));
+        }
+    }
+
+    /**
+     * Gets the corresponding value in this fragment.
+     *
+     * @param b original value
+     * @return corresponding value in the peel
+     */
+    @Override
+    protected ValueNode prim(ValueNode b) {
+        assert isDuplicate();
+        LoopBeginNode loopBegin = original().loop().loopBegin();
+        if (loopBegin.isPhiAtMerge(b)) {
+            PhiNode phi = (PhiNode) b;
+            return phi.valueAt(loopBegin.forwardEnd());
+        } else if (nodesReady) {
+            ValueNode v = getDuplicatedNode(b);
+            if (v == null) {
+                return b;
+            }
+            return v;
+        } else {
+            return b;
+        }
+    }
+
+    private AbstractBeginNode mergeEnds() {
+        assert isDuplicate();
+        List<EndNode> endsToMerge = new LinkedList<>();
+        // map peel exits to the corresponding loop exits
+        Map<AbstractEndNode, LoopEndNode> reverseEnds = CollectionsFactory.newMap();
+        LoopBeginNode loopBegin = original().loop().loopBegin();
+        for (LoopEndNode le : loopBegin.loopEnds()) {
+            AbstractEndNode duplicate = getDuplicatedNode(le);
+            if (duplicate != null) {
+                endsToMerge.add((EndNode) duplicate);
+                reverseEnds.put(duplicate, le);
+            }
+        }
+        mergedInitializers = Node.newIdentityMap();
+        AbstractBeginNode newExit;
+        StructuredGraph graph = graph();
+        if (endsToMerge.size() == 1) {
+            AbstractEndNode end = endsToMerge.get(0);
+            assert end.hasNoUsages();
+            newExit = graph.add(new BeginNode());
+            end.replaceAtPredecessor(newExit);
+            end.safeDelete();
+        } else {
+            assert endsToMerge.size() > 1;
+            AbstractMergeNode newExitMerge = graph.add(new MergeNode());
+            newExit = newExitMerge;
+            FrameState state = loopBegin.stateAfter();
+            FrameState duplicateState = null;
+            if (state != null) {
+                duplicateState = state.duplicateWithVirtualState();
+                newExitMerge.setStateAfter(duplicateState);
+            }
+            for (EndNode end : endsToMerge) {
+                newExitMerge.addForwardEnd(end);
+            }
+
+            for (final PhiNode phi : loopBegin.phis().snapshot()) {
+                if (phi.hasNoUsages()) {
+                    continue;
+                }
+                final PhiNode firstPhi = patchPhi(graph, phi, newExitMerge);
+                for (AbstractEndNode end : newExitMerge.forwardEnds()) {
+                    LoopEndNode loopEnd = reverseEnds.get(end);
+                    ValueNode prim = prim(phi.valueAt(loopEnd));
+                    assert prim != null;
+                    firstPhi.addInput(prim);
+                }
+                ValueNode initializer = firstPhi;
+                if (duplicateState != null) {
+                    // fix the merge's state after
+                    duplicateState.applyToNonVirtual(new NodeClosure<ValueNode>() {
+
+                        @Override
+                        public void apply(Node from, ValueNode node) {
+                            if (node == phi) {
+                                from.replaceFirstInput(phi, firstPhi);
+                            }
+                        }
+                    });
+                }
+                mergedInitializers.put((ValuePhiNode) phi, initializer);
+            }
+        }
+        return newExit;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideBefore.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideBefore.java
new file mode 100644
index 0000000..b883252
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideBefore.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.FixedNode;
+
+public class LoopFragmentInsideBefore extends LoopFragmentInside {
+
+    private final FixedNode point;
+
+    public LoopFragmentInsideBefore(LoopEx loop, FixedNode point) {
+        super(loop);
+        this.point = point;
+    }
+
+    // duplicates lazily
+    public LoopFragmentInsideBefore(LoopFragmentInsideBefore original) {
+        super(original);
+        this.point = original.point();
+    }
+
+    public FixedNode point() {
+        return point;
+    }
+
+    @Override
+    public LoopFragmentInsideBefore duplicate() {
+        return new LoopFragmentInsideBefore(this);
+    }
+
+    @Override
+    public NodeBitMap nodes() {
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideFrom.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideFrom.java
new file mode 100644
index 0000000..c07bab6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInsideFrom.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.FixedNode;
+
+public class LoopFragmentInsideFrom extends LoopFragmentInside {
+
+    private final FixedNode point;
+
+    public LoopFragmentInsideFrom(LoopEx loop, FixedNode point) {
+        super(loop);
+        this.point = point;
+    }
+
+    // duplicates lazily
+    public LoopFragmentInsideFrom(LoopFragmentInsideFrom original) {
+        super(original);
+        this.point = original.point();
+    }
+
+    public FixedNode point() {
+        return point;
+    }
+
+    @Override
+    public LoopFragmentInsideFrom duplicate() {
+        return new LoopFragmentInsideFrom(this);
+    }
+
+    @Override
+    public NodeBitMap nodes() {
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java
new file mode 100644
index 0000000..93de2186
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+
+public class LoopFragmentWhole extends LoopFragment {
+
+    public LoopFragmentWhole(LoopEx loop) {
+        super(loop);
+    }
+
+    public LoopFragmentWhole(LoopFragmentWhole original) {
+        super(null, original);
+    }
+
+    @Override
+    public LoopFragmentWhole duplicate() {
+        LoopFragmentWhole loopFragmentWhole = new LoopFragmentWhole(this);
+        loopFragmentWhole.reify();
+        return loopFragmentWhole;
+    }
+
+    private void reify() {
+        assert this.isDuplicate();
+
+        patchNodes(null);
+
+        mergeEarlyExits();
+    }
+
+    @Override
+    public NodeBitMap nodes() {
+        if (nodes == null) {
+            Loop<Block> loop = loop().loop();
+            if (loop.getHeader().getBeginNode().graph().getGuardsStage() == GuardsStage.AFTER_FSA) {
+                nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(loop.getBlocks()), Collections.emptyList());
+            } else {
+                nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(loop.getBlocks()), LoopFragment.toHirExits(loop.getExits()));
+            }
+        }
+        return nodes;
+    }
+
+    @Override
+    protected ValueNode prim(ValueNode b) {
+        return getDuplicatedNode(b);
+    }
+
+    @Override
+    protected DuplicationReplacement getDuplicationReplacement() {
+        final FixedNode entry = loop().entryPoint();
+        final Graph graph = this.graph();
+        return new DuplicationReplacement() {
+
+            private EndNode endNode;
+
+            @Override
+            public Node replacement(Node o) {
+                if (o == entry) {
+                    if (endNode == null) {
+                        endNode = graph.add(new EndNode());
+                    }
+                    return endNode;
+                }
+                return o;
+            }
+        };
+    }
+
+    public FixedNode entryPoint() {
+        if (isDuplicate()) {
+            LoopBeginNode newLoopBegin = getDuplicatedNode(original().loop().loopBegin());
+            return newLoopBegin.forwardEnd();
+        }
+        return loop().entryPoint();
+    }
+
+    @Override
+    protected void finishDuplication() {
+        // TODO (gd) ?
+    }
+
+    @Override
+    public void insertBefore(LoopEx loop) {
+        // TODO Auto-generated method stub
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java
new file mode 100644
index 0000000..a6549b2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import java.util.List;
+
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public interface LoopPolicies {
+    boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess);
+
+    boolean shouldFullUnroll(LoopEx loop);
+
+    boolean shouldTryUnswitch(LoopEx loop);
+
+    boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java
new file mode 100644
index 0000000..d14f1ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+
+public class LoopsData {
+
+    private Map<Loop<Block>, LoopEx> loopToEx = CollectionsFactory.newIdentityMap();
+    private Map<LoopBeginNode, LoopEx> loopBeginToEx = Node.newIdentityMap();
+    private ControlFlowGraph cfg;
+
+    @SuppressWarnings("try")
+    public LoopsData(final StructuredGraph graph) {
+        try (Scope s = Debug.scope("ControlFlowGraph")) {
+            cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        for (Loop<Block> loop : cfg.getLoops()) {
+            LoopEx ex = new LoopEx(loop, this);
+            loopToEx.put(loop, ex);
+            loopBeginToEx.put(ex.loopBegin(), ex);
+        }
+    }
+
+    public LoopEx loop(Loop<?> loop) {
+        return loopToEx.get(loop);
+    }
+
+    public LoopEx loop(LoopBeginNode loopBegin) {
+        return loopBeginToEx.get(loopBegin);
+    }
+
+    public Collection<LoopEx> loops() {
+        return loopToEx.values();
+    }
+
+    public List<LoopEx> outerFirst() {
+        ArrayList<LoopEx> loops = new ArrayList<>(loops());
+        Collections.sort(loops, new Comparator<LoopEx>() {
+
+            @Override
+            public int compare(LoopEx o1, LoopEx o2) {
+                return o1.loop().getDepth() - o2.loop().getDepth();
+            }
+        });
+        return loops;
+    }
+
+    public List<LoopEx> innerFirst() {
+        ArrayList<LoopEx> loops = new ArrayList<>(loops());
+        Collections.sort(loops, new Comparator<LoopEx>() {
+
+            @Override
+            public int compare(LoopEx o1, LoopEx o2) {
+                return o2.loop().getDepth() - o1.loop().getDepth();
+            }
+        });
+        return loops;
+    }
+
+    public Collection<LoopEx> countedLoops() {
+        List<LoopEx> counted = new LinkedList<>();
+        for (LoopEx loop : loops()) {
+            if (loop.isCounted()) {
+                counted.add(loop);
+            }
+        }
+        return counted;
+    }
+
+    public void detectedCountedLoops() {
+        for (LoopEx loop : loops()) {
+            loop.detectCounted();
+        }
+    }
+
+    public ControlFlowGraph getCFG() {
+        return cfg;
+    }
+
+    public InductionVariable getInductionVariable(ValueNode value) {
+        InductionVariable match = null;
+        for (LoopEx loop : loops()) {
+            InductionVariable iv = loop.getInductionVariables().get(value);
+            if (iv != null) {
+                if (match != null) {
+                    return null;
+                }
+                match = iv;
+            }
+        }
+        return match;
+    }
+
+    /**
+     * Deletes any nodes created within the scope of this object that have no usages.
+     */
+    public void deleteUnusedNodes() {
+        for (LoopEx loop : loops()) {
+            loop.deleteUnusedNodes();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java
new file mode 100644
index 0000000..9c4333e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.loop;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.SignedDivNode;
+
+/**
+ * Utility methods to perform integer math with some obvious constant folding first.
+ */
+public class MathUtil {
+    private static boolean isConstantOne(ValueNode v1) {
+        return v1.isConstant() && v1.stamp() instanceof IntegerStamp && v1.asJavaConstant().asLong() == 1;
+    }
+
+    private static boolean isConstantZero(ValueNode v1) {
+        return v1.isConstant() && v1.stamp() instanceof IntegerStamp && v1.asJavaConstant().asLong() == 0;
+    }
+
+    public static ValueNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        if (isConstantZero(v1)) {
+            return v2;
+        }
+        if (isConstantZero(v2)) {
+            return v1;
+        }
+        return BinaryArithmeticNode.add(graph, v1, v2);
+    }
+
+    public static ValueNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        if (isConstantOne(v1)) {
+            return v2;
+        }
+        if (isConstantOne(v2)) {
+            return v1;
+        }
+        return BinaryArithmeticNode.mul(graph, v1, v2);
+    }
+
+    public static ValueNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        if (isConstantZero(v2)) {
+            return v1;
+        }
+        return BinaryArithmeticNode.sub(graph, v1, v2);
+    }
+
+    public static ValueNode divBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) {
+        if (isConstantOne(divisor)) {
+            return dividend;
+        }
+        SignedDivNode div = graph.add(new SignedDivNode(dividend, divisor));
+        graph.addBeforeFixed(before, div);
+        return div;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayDuplicationBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayDuplicationBenchmark.java
new file mode 100644
index 0000000..ef4fdaa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayDuplicationBenchmark.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package micro.benchmarks;
+
+import java.util.Arrays;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.OperationsPerInvocation;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+@State(Scope.Thread)
+public class ArrayDuplicationBenchmark extends GraalBenchmark {
+
+    /** How large should the test-arrays be. */
+    private static final int TESTSIZE = 300;
+
+    private Object[][] testObjectArray;
+
+    private Object[] dummy;
+
+    @Setup
+    public void setup() {
+        testObjectArray = new Object[TESTSIZE][];
+        for (int i = 0; i < TESTSIZE; i++) {
+            testObjectArray[i] = new Object[20];
+        }
+    }
+
+    @Setup(Level.Iteration)
+    public void iterationSetup() {
+        dummy = new Object[TESTSIZE * 3];
+    }
+
+    @TearDown(Level.Iteration)
+    public void iterationTearDown() {
+        dummy = null;
+    }
+
+    @Benchmark
+    @OperationsPerInvocation(TESTSIZE)
+    public Object[] normalArraycopy() {
+        int j = 0;
+        for (int i = 0; i < TESTSIZE; i++) {
+            dummy[j++] = normalArraycopy(testObjectArray[i]);
+        }
+        return dummy;
+    }
+
+    public Object[] normalArraycopy(Object[] cache) {
+        Object[] result = new Object[cache.length];
+        System.arraycopy(cache, 0, result, 0, result.length);
+        return result;
+    }
+
+    @Benchmark
+    @OperationsPerInvocation(TESTSIZE)
+    public Object[] arraysCopyOf() {
+        int j = 0;
+        for (int i = 0; i < TESTSIZE; i++) {
+            dummy[j++] = arraysCopyOf(testObjectArray[i]);
+        }
+        return dummy;
+    }
+
+    public Object[] arraysCopyOf(Object[] cache) {
+        return Arrays.copyOf(cache, cache.length);
+    }
+
+    @Benchmark
+    @OperationsPerInvocation(TESTSIZE)
+    public Object[] cloneObjectArray() {
+        int j = 0;
+        for (int i = 0; i < TESTSIZE; i++) {
+            dummy[j++] = arraysClone(testObjectArray[i]);
+        }
+        return dummy;
+    }
+
+    @SuppressWarnings("cast")
+    public Object[] arraysClone(Object[] cache) {
+        return (Object[]) cache.clone();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/GuardedIntrinsicBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/GuardedIntrinsicBenchmark.java
new file mode 100644
index 0000000..1ace3e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/GuardedIntrinsicBenchmark.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package micro.benchmarks;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+/**
+ * Benchmarks cost of guarded intrinsics at indirect call sites.
+ */
+public class GuardedIntrinsicBenchmark extends GraalBenchmark {
+
+    public static class HashcodeState {
+        public Object val1;
+        public Object val2;
+
+        public HashcodeState(Object val1, Object val2) {
+            this.val1 = val1;
+            this.val2 = val2;
+        }
+
+        int getNextHashCode() {
+            return val1.hashCode();
+        }
+
+        protected void swap() {
+            Object tmp = val1;
+            val1 = val2;
+            val2 = tmp;
+        }
+    }
+
+    /**
+     * Objects that all override {@link Object#hashCode()}. The objects used have hashCode
+     * implementations that are basically getters as we want to measure the overhead of hashCode
+     * dispatch, not the cost of the hashCode implementation.
+     */
+    @State(Scope.Benchmark)
+    public static class OverrideHashcode extends HashcodeState {
+        public OverrideHashcode() {
+            super(Short.valueOf((short) 100), Integer.valueOf(42));
+        }
+
+        @Setup(Level.Invocation)
+        public void beforeInvocation() {
+            swap();
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 10)
+    public int overrideHashCode(OverrideHashcode state) {
+        return state.getNextHashCode();
+    }
+
+    /**
+     * Objects that do not override {@link Object#hashCode()}.
+     */
+    @State(Scope.Benchmark)
+    public static class InheritHashcode extends HashcodeState {
+        public InheritHashcode() {
+            super(Class.class, Runtime.getRuntime());
+        }
+
+        @Setup(Level.Invocation)
+        public void beforeInvocation() {
+            swap();
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 10)
+    public int inheritHashCode(InheritHashcode state) {
+        return state.getNextHashCode();
+    }
+
+    /**
+     * Some objects that override {@link Object#hashCode()} and some that don't.
+     */
+    @State(Scope.Benchmark)
+    public static class MixedHashcode extends HashcodeState {
+        public MixedHashcode() {
+            super(Short.valueOf((short) 100), Runtime.getRuntime());
+        }
+
+        @Setup(Level.Invocation)
+        public void beforeInvocation() {
+            swap();
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 10)
+    public int mixedHashCode(MixedHashcode state) {
+        return state.getNextHashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/MathFunctionBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/MathFunctionBenchmark.java
new file mode 100644
index 0000000..b5c1c06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/MathFunctionBenchmark.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package micro.benchmarks;
+
+import java.util.Random;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+/**
+ * Benchmarks cost of Math intrinsics.
+ */
+public class MathFunctionBenchmark extends GraalBenchmark {
+
+    @State(Scope.Benchmark)
+    public static class ThreadState {
+        double[] data = randomDoubles(100);
+        double[] result = new double[100];
+
+        static double[] randomDoubles(int len) {
+            double[] data = new double[len];
+            Random r = new Random();
+            for (int i = 0; i < data.length; i++) {
+                data[i] = r.nextDouble();
+            }
+            return data;
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public void mathLog(ThreadState state) {
+        double[] data = state.data;
+        for (int i = 0; i < data.length; i++) {
+            double[] result = state.result;
+            result[i] = Math.log(data[i]);
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public void mathLog10(ThreadState state) {
+        double[] data = state.data;
+        for (int i = 0; i < data.length; i++) {
+            double[] result = state.result;
+            result[i] = Math.log10(data[i]);
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public void mathSin(ThreadState state) {
+        double[] data = state.data;
+        for (int i = 0; i < data.length; i++) {
+            double[] result = state.result;
+            result[i] = Math.sin(data[i]);
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public void mathCos(ThreadState state) {
+        double[] data = state.data;
+        for (int i = 0; i < data.length; i++) {
+            double[] result = state.result;
+            result[i] = Math.cos(data[i]);
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public void mathTan(ThreadState state) {
+        double[] data = state.data;
+        for (int i = 0; i < data.length; i++) {
+            double[] result = state.result;
+            result[i] = Math.tan(data[i]);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/SimpleSyncBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/SimpleSyncBenchmark.java
new file mode 100644
index 0000000..834b336
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/SimpleSyncBenchmark.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package micro.benchmarks;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+/**
+ * Benchmarks cost of non-contended synchronization.
+ */
+public class SimpleSyncBenchmark extends GraalBenchmark {
+
+    public static class Person {
+        public int age;
+
+        public Person(int age) {
+            this.age = age;
+        }
+
+        public synchronized int getAge() {
+            return age;
+        }
+
+        public synchronized void setAge(int age) {
+            this.age = age;
+        }
+
+        public synchronized void setAgeIfNonZero(int age) {
+            if (age != 0) {
+                this.age = age;
+            }
+        }
+    }
+
+    @State(Scope.Benchmark)
+    public static class ThreadState {
+        Person person = new Person(22);
+        int newAge = 45;
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public void setAgeCond(ThreadState state) {
+        Person person = state.person;
+        person.setAgeIfNonZero(state.newAge);
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int getAge(ThreadState state) {
+        Person person = state.person;
+        return person.getAge();
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int getAndIncAge(ThreadState state) {
+        Person person = state.person;
+        int oldAge = person.getAge();
+        person.setAge(oldAge + 1);
+        return oldAge;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/package-info.java
new file mode 100644
index 0000000..b584106
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/**
+ * This package contains micro benchmarks outside the org.graalvm.compiler namespace so that they
+ * will be subject to Graal compilation even if {@code -Dgraal.CompileGraalWithC1Only=true}.
+ */
+package micro.benchmarks;
\ No newline at end of file
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java
new file mode 100644
index 0000000..d11779b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraphState;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class ConditionalEliminationBenchmark extends GraalBenchmark {
+
+    @MethodSpec(declaringClass = ConditionalEliminationBenchmark.class, name = "nullnessSnippet")
+    public static class Nullness extends GraphState {
+    }
+
+    @SuppressWarnings("unused")
+    public static int nullnessSnippet(Object a, Object b) {
+        if (a == null) {
+            if (a == b) {
+                if (b == null) {
+                    return 1;
+                } else {
+                    return -2;
+                }
+            } else {
+                if (b == null) {
+                    return -3;
+                } else {
+                    return 4;
+                }
+            }
+        } else {
+            if (a == b) {
+                if (b == null) {
+                    return -5;
+                } else {
+                    return 6;
+                }
+            } else {
+                if (b == null) {
+                    return 7;
+                } else {
+                    return 8;
+                }
+            }
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public void nullness(Nullness s, GraalState g) {
+        new DominatorConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+    }
+
+    @MethodSpec(declaringClass = ConditionalEliminationBenchmark.class, name = "searchSnippet")
+    public static class Search extends GraphState {
+    }
+
+    static class Entry {
+        final String name;
+
+        Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+        EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry searchSnippet(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    @Benchmark
+    public void search(Search s, GraalState g) {
+        new DominatorConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/FrameStateAssigmentPhaseBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/FrameStateAssigmentPhaseBenchmark.java
new file mode 100644
index 0000000..4f5c955
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/FrameStateAssigmentPhaseBenchmark.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import java.util.StringTokenizer;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.util.FrameStateAssignmentState;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+
+@Warmup(iterations = 15)
+public class FrameStateAssigmentPhaseBenchmark extends GraalBenchmark {
+
+    @MethodSpec(declaringClass = StringTokenizer.class, name = "nextToken", parameters = {String.class})
+    public static class StringTokenizedNextToken extends FrameStateAssignmentState {
+    }
+
+    @Benchmark
+    public void nextToken(StringTokenizedNextToken s) {
+        s.phase.apply(s.graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java
new file mode 100644
index 0000000..6aca9fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import static org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark.Defaults.FORKS;
+import static org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark.Defaults.MEASUREMENT_ITERATIONS;
+import static org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark.Defaults.WARMUP_ITERATIONS;
+
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * All classes defining Graal benchmarks must subclass this class as it defines the default value
+ * for each benchmark option. Individual options can be overridden in the subclasses or by an
+ * individual benchmark.
+ */
+@Warmup(iterations = WARMUP_ITERATIONS)
+@Measurement(iterations = MEASUREMENT_ITERATIONS)
+@Fork(FORKS)
+public class GraalBenchmark {
+
+    public static class Defaults {
+        public static final int MEASUREMENT_ITERATIONS = 10;
+        public static final int WARMUP_ITERATIONS = 10;
+        public static final int FORKS = 1;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraphCopyBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraphCopyBenchmark.java
new file mode 100644
index 0000000..960d856
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraphCopyBenchmark.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraphState;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * Benchmarks the performance of {@link Graph#copy()}.
+ */
+public class GraphCopyBenchmark extends GraalBenchmark {
+
+    @MethodSpec(declaringClass = ConditionalEliminationBenchmark.class, name = "nullnessSnippet")
+    public static class Nullness extends GraphState {
+    }
+
+    @SuppressWarnings("unused")
+    public static int nullnessSnippet(Object a, Object b) {
+        if (a == null) {
+            if (a == b) {
+                if (b == null) {
+                    return 1;
+                } else {
+                    return -2;
+                }
+            } else {
+                if (b == null) {
+                    return -3;
+                } else {
+                    return 4;
+                }
+            }
+        } else {
+            if (a == b) {
+                if (b == null) {
+                    return -5;
+                } else {
+                    return 6;
+                }
+            } else {
+                if (b == null) {
+                    return 7;
+                } else {
+                    return 8;
+                }
+            }
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public StructuredGraph nullness(Nullness s, @SuppressWarnings("unused") GraalState g) {
+        return (StructuredGraph) s.graph.copy();
+    }
+
+    @MethodSpec(declaringClass = GraphCopyBenchmark.class, name = "searchSnippet")
+    public static class Search extends GraphState {
+    }
+
+    static class Entry {
+        final String name;
+
+        Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+        EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry searchSnippet(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public StructuredGraph search(Search s, @SuppressWarnings("unused") GraalState g) {
+        return (StructuredGraph) s.graph.copy();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/NodeBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/NodeBenchmark.java
new file mode 100644
index 0000000..2ffc00a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/NodeBenchmark.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import java.util.HashMap;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.microbenchmarks.graal.util.NodesState;
+import org.graalvm.compiler.microbenchmarks.graal.util.NodesState.NodePair;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+public class NodeBenchmark extends GraalBenchmark {
+
+    @MethodSpec(declaringClass = String.class, name = "equals")
+    public static class StringEquals extends NodesState {
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int getNodeClass(StringEquals s) {
+        int sum = 0;
+        for (Node n : s.nodes) {
+            sum += n.getNodeClass().iterableId();
+        }
+        return sum;
+    }
+
+    @Benchmark
+    public void dataEquals(StringEquals s, Blackhole bh) {
+        for (Node n : s.nodes) {
+            bh.consume(n.getNodeClass().dataEquals(n, n));
+        }
+    }
+
+    @Benchmark
+    public void replaceFirstInput(StringEquals s, Blackhole bh) {
+        for (Node n : s.nodes) {
+            bh.consume(n.getNodeClass().replaceFirstInput(n, n, n));
+        }
+    }
+
+    @Benchmark
+    public void inputsEquals(StringEquals s, Blackhole bh) {
+        for (Node n : s.nodes) {
+            bh.consume(n.getNodeClass().equalInputs(n, n));
+        }
+    }
+
+    @Benchmark
+    public void inputs(StringEquals s, Blackhole bh) {
+        for (Node n : s.nodes) {
+            for (Node input : n.inputs()) {
+                bh.consume(input);
+            }
+        }
+    }
+
+    @Benchmark
+    public void acceptInputs(StringEquals s, Blackhole bh) {
+        Node.EdgeVisitor consumer = new Node.EdgeVisitor() {
+            @Override
+            public Node apply(Node t, Node u) {
+                bh.consume(u);
+                return u;
+            }
+        };
+        for (Node n : s.nodes) {
+            n.applyInputs(consumer);
+        }
+    }
+
+    @Benchmark
+    public void createAndDeleteAdd(StringEquals s, Blackhole bh) {
+        AddNode addNode = new AddNode(ConstantNode.forInt(40), ConstantNode.forInt(2));
+        s.graph.addOrUniqueWithInputs(addNode);
+        GraphUtil.killWithUnusedFloatingInputs(addNode);
+        bh.consume(addNode);
+    }
+
+    @Benchmark
+    public void createAndDeleteConstant(StringEquals s, Blackhole bh) {
+        ConstantNode constantNode = ConstantNode.forInt(42);
+        s.graph.addOrUnique(constantNode);
+        GraphUtil.killWithUnusedFloatingInputs(constantNode);
+        bh.consume(constantNode);
+    }
+
+    @Benchmark
+    public void usages(StringEquals s, Blackhole bh) {
+        for (Node n : s.nodes) {
+            for (Node input : n.usages()) {
+                bh.consume(input);
+            }
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public void nodeBitmap(StringEquals s, @SuppressWarnings("unused") GraalState g) {
+        NodeBitMap bitMap = s.graph.createNodeBitMap();
+        for (Node node : s.graph.getNodes()) {
+            if (!bitMap.isMarked(node)) {
+                bitMap.mark(node);
+            }
+        }
+        for (Node node : s.graph.getNodes()) {
+            if (bitMap.isMarked(node)) {
+                bitMap.clear(node);
+            }
+        }
+    }
+
+    @MethodSpec(declaringClass = HashMap.class, name = "computeIfAbsent")
+    public static class HashMapComputeIfAbsent extends NodesState {
+    }
+
+    // Checkstyle: stop method name check
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int valueEquals_STRING_EQUALS(StringEquals s) {
+        int result = 0;
+        for (NodePair np : s.valueEqualsNodePairs) {
+            if (np.n1.valueEquals(np.n2)) {
+                result += 27;
+            } else {
+                result += 31;
+            }
+        }
+        return result;
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int valueEquals_HASHMAP_COMPUTE_IF_ABSENT(HashMapComputeIfAbsent s) {
+        int result = 0;
+        for (NodePair np : s.valueEqualsNodePairs) {
+            if (np.n1.valueEquals(np.n2)) {
+                result += 27;
+            } else {
+                result += 31;
+            }
+        }
+        return result;
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int valueNumberLeaf_HASHMAP_COMPUTE_IF_ABSENT(HashMapComputeIfAbsent s) {
+        int result = 0;
+        for (Node n : s.valueNumberableLeafNodes) {
+            result += (n.getNodeClass().isLeafNode() ? 1 : 0);
+        }
+        return result;
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int valueNumberLeaf_STRING_EQUALS(StringEquals s) {
+        int result = 0;
+        for (Node n : s.valueNumberableLeafNodes) {
+            result += (n.getNodeClass().isLeafNode() ? 1 : 0);
+        }
+        return result;
+    }
+    // Checkstyle: resume method name check
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java
new file mode 100644
index 0000000..82e4900
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import java.util.Arrays;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.microbenchmarks.graal.util.ScheduleState;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+
+@Warmup(iterations = 15)
+public class SchedulePhaseBenchmark extends GraalBenchmark {
+
+    @MethodSpec(declaringClass = String.class, name = "equals")
+    public static class StringEquals extends ScheduleState {
+    }
+
+    @Benchmark
+    public void stringEquals(StringEquals s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @Benchmark
+    public void cfgCompute1(StringEquals s) {
+        ControlFlowGraph.compute(s.graph, true, false, false, false);
+    }
+
+    @Benchmark
+    public void cfgCompute2(StringEquals s) {
+        ControlFlowGraph.compute(s.graph, true, true, false, false);
+    }
+
+    @Benchmark
+    public void cfgCompute3(StringEquals s) {
+        ControlFlowGraph.compute(s.graph, true, true, true, false);
+    }
+
+    @Benchmark
+    public void cfgCompute4(StringEquals s) {
+        ControlFlowGraph.compute(s.graph, true, true, true, true);
+    }
+
+    public static int[] intersectionSnippet(int[] in1, int[] in2) {
+        int[] result = new int[Math.min(in1.length, in2.length)];
+        int next = 0;
+        for (int i1 : in1) {
+            for (int i2 : in2) {
+                if (i2 == i1) {
+                    result[next++] = i1;
+                    break;
+                }
+            }
+        }
+        if (next < result.length) {
+            result = Arrays.copyOf(result, next);
+        }
+        return result;
+    }
+
+    // Checkstyle: stop method name check
+    @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet")
+    public static class IntersectionState_LATEST_OPTIMAL extends ScheduleState {
+        public IntersectionState_LATEST_OPTIMAL() {
+            super(SchedulingStrategy.LATEST);
+        }
+    }
+
+    @Benchmark
+    public void intersection_LATEST_OPTIMAL(IntersectionState_LATEST_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet")
+    public static class IntersectionState_LATEST_OUT_OF_LOOPS_OPTIMAL extends ScheduleState {
+        public IntersectionState_LATEST_OUT_OF_LOOPS_OPTIMAL() {
+            super(SchedulingStrategy.LATEST_OUT_OF_LOOPS);
+        }
+    }
+
+    @Benchmark
+    public void intersection_LATEST_OUT_OF_LOOPS_OPTIMAL(IntersectionState_LATEST_OUT_OF_LOOPS_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet")
+    public static class IntersectionState_EARLIEST_OPTIMAL extends ScheduleState {
+        public IntersectionState_EARLIEST_OPTIMAL() {
+            super(SchedulingStrategy.EARLIEST);
+        }
+    }
+
+    @Benchmark
+    public void intersection_EARLIEST_OPTIMAL(IntersectionState_EARLIEST_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+    // Checkstyle: resume method name check
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java
new file mode 100644
index 0000000..97ff80b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Warmup(iterations = 1)
+@Measurement(iterations = 1)
+@Fork(1)
+/**
+ * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
+ */
+public class TestJMH {
+
+    @Benchmark
+    public void testJMH() {
+        // This method was intentionally left blank.
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java
new file mode 100644
index 0000000..8f5455b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+
+public class FrameStateAssignmentState extends GraphState {
+
+    public FrameStateAssignmentPhase phase;
+
+    @Override
+    protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) {
+        new GuardLoweringPhase().apply(structuredGraph, null);
+        return structuredGraph;
+    }
+
+    @Override
+    public void beforeInvocation() {
+        phase = new FrameStateAssignmentPhase();
+        super.beforeInvocation();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalState.java
new file mode 100644
index 0000000..ccfdd14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalState.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+/**
+ * Read-only, benchmark-wide state providing Graal runtime context.
+ */
+@State(Scope.Benchmark)
+public class GraalState {
+
+    public final Backend backend;
+    public final Providers providers;
+    public final MetaAccessProvider metaAccess;
+
+    public GraalState() {
+        backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        providers = backend.getProviders();
+        metaAccess = providers.getMetaAccess();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java
new file mode 100644
index 0000000..bd1e4a4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class GraalUtil {
+
+    public static Method getMethod(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        try {
+            if (parameterTypes == null) {
+                Method found = null;
+                for (Method m : declaringClass.getDeclaredMethods()) {
+                    if (m.getName().equals(name)) {
+                        if (found != null) {
+                            throw new RuntimeException("more than one method named " + name + " in " + declaringClass);
+                        }
+                        found = m;
+                    }
+                }
+                if (found == null) {
+                    throw new NoSuchMethodException(declaringClass.getName() + "." + name);
+                }
+                return found;
+            } else {
+                return declaringClass.getDeclaredMethod(name, parameterTypes);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the first {@link MethodSpec} annotation encountered in the class hierarchy terminated by
+     * {@code startClass}.
+     */
+    public static MethodSpec getMethodSpec(Class<?> startClass) {
+        Class<?> c = startClass;
+        while (c != null) {
+            MethodSpec methodSpec = c.getAnnotation(MethodSpec.class);
+            if (methodSpec != null) {
+                return methodSpec;
+            }
+            c = c.getSuperclass();
+        }
+        throw new RuntimeException("Could not find class annotated with " + MethodSpec.class.getSimpleName() + " in hierarchy of " + startClass);
+    }
+
+    /**
+     * Gets the method specified by the first {@link MethodSpec} annotation encountered in the class
+     * hierarchy terminated by {@code startClass}.
+     */
+    public static Method getMethodFromMethodSpec(Class<?> startClass) {
+        MethodSpec methodSpec = getMethodSpec(startClass);
+        Class<?> declaringClass = methodSpec.declaringClass();
+        if (declaringClass == MethodSpec.class) {
+            declaringClass = startClass;
+        }
+        String name = methodSpec.name();
+        Class<?>[] parameters = methodSpec.parameters();
+        if (parameters.length == 1 && parameters[0] == void.class) {
+            parameters = null;
+        }
+        return getMethod(declaringClass, name, parameters);
+    }
+
+    /**
+     * Gets the graph for the method specified by the first {@link MethodSpec} annotation
+     * encountered in the class hierarchy terminated by {@code startClass}.
+     */
+    public static StructuredGraph getGraphFromMethodSpec(Class<?> startClass) {
+        MethodSpec methodSpec = getMethodSpec(startClass);
+        Class<?> declaringClass = methodSpec.declaringClass();
+        if (declaringClass == MethodSpec.class) {
+            declaringClass = startClass;
+        }
+        String name = methodSpec.name();
+        Class<?>[] parameters = methodSpec.parameters();
+        if (parameters.length == 1 && parameters[0] == void.class) {
+            parameters = null;
+        }
+        return getGraph(declaringClass, name, parameters);
+    }
+
+    public static StructuredGraph getGraph(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        return getGraph(getMethod(declaringClass, name, parameterTypes));
+    }
+
+    public static StructuredGraph getGraph(Method method) {
+        GraalState graal = new GraalState();
+        ResolvedJavaMethod javaMethod = graal.metaAccess.lookupJavaMethod(method);
+        return getGraph(graal, javaMethod);
+    }
+
+    public static StructuredGraph getGraph(GraalState graal, ResolvedJavaMethod javaMethod) {
+        return getGraph(graal, javaMethod, StructuredGraph.USE_PROFILING_INFO);
+    }
+
+    public static StructuredGraph getGraph(GraalState graal, ResolvedJavaMethod javaMethod, boolean useProfilingInfo) {
+        StructuredGraph graph = new StructuredGraph(javaMethod, StructuredGraph.AllowAssumptions.YES, useProfilingInfo, INVALID_COMPILATION_ID);
+        PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
+        MetaAccessProvider metaAccess = graal.providers.getMetaAccess();
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins(metaAccess)))));
+        graphBuilderSuite.apply(graph, new HighTierContext(graal.providers, graphBuilderSuite, OptimisticOptimizations.ALL));
+        return graph;
+    }
+
+    public static Node[] getNodes(StructuredGraph graph) {
+        List<Node> nodeList = graph.getNodes().snapshot();
+        return nodeList.toArray(new Node[nodeList.size()]);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java
new file mode 100644
index 0000000..064c191
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getGraph;
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getMethodFromMethodSpec;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * State providing a new copy of a graph for each invocation of a benchmark. Subclasses of this
+ * class are annotated with {@link MethodSpec} to specify the Java method that will be parsed to
+ * obtain the original graph.
+ */
+@State(Scope.Thread)
+public abstract class GraphState {
+
+    @SuppressWarnings("try")
+    public GraphState() {
+        // Ensure a debug configuration for this thread is initialized
+        if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+            DebugEnvironment.initialize(System.out);
+        }
+
+        GraalState graal = new GraalState();
+        ResolvedJavaMethod method = graal.metaAccess.lookupJavaMethod(getMethodFromMethodSpec(getClass()));
+        StructuredGraph structuredGraph = null;
+        try (Debug.Scope s = Debug.scope("GraphState", method)) {
+            structuredGraph = preprocessOriginal(getGraph(graal, method));
+        } catch (Throwable t) {
+            Debug.handle(t);
+        }
+        this.originalGraph = structuredGraph;
+    }
+
+    protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) {
+        return structuredGraph;
+    }
+
+    /**
+     * Original graph from which the per-benchmark invocation {@link #graph} is cloned.
+     */
+    private final StructuredGraph originalGraph;
+
+    /**
+     * The graph processed by the benchmark.
+     */
+    public StructuredGraph graph;
+
+    @Setup(Level.Invocation)
+    public void beforeInvocation() {
+        graph = (StructuredGraph) originalGraph.copy();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/MethodSpec.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/MethodSpec.java
new file mode 100644
index 0000000..f635422
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/MethodSpec.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying a method based on a declaring class, a name and parameter types.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MethodSpec {
+    /**
+     * The class in which the method is declared. If not specified, the annotated class is used as
+     * the declaring class.
+     */
+    Class<?> declaringClass() default MethodSpec.class;
+
+    /**
+     * The name of the method.
+     */
+    String name();
+
+    /**
+     * The types of the method's parameters. If not specified, then the {@linkplain #name() name} is
+     * expected to be unique within the declaring class.
+     */
+    Class<?>[] parameters() default {void.class};
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/NodesState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/NodesState.java
new file mode 100644
index 0000000..5862779
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/NodesState.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getGraphFromMethodSpec;
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getNodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * State providing the nodes in a graph. Subclasses of this class are annotated with
+ * {@link MethodSpec} to specify the Java method that will be parsed to obtain the original graph.
+ */
+@State(Scope.Benchmark)
+public abstract class NodesState {
+
+    public NodesState() {
+        this.graph = getGraphFromMethodSpec(getClass());
+        this.nodes = getNodes(graph);
+        this.originalNodes = nodes.clone();
+        List<Node> vnln = new ArrayList<>(nodes.length);
+        List<NodePair> list2 = new ArrayList<>(nodes.length);
+        for (int i = 0; i < nodes.length; i++) {
+            Node n = nodes[i];
+            NodeClass<?> nc = n.getNodeClass();
+            if (nc.valueNumberable() && nc.isLeafNode()) {
+                vnln.add(n);
+            }
+            for (int j = i + i; j < nodes.length; j++) {
+                Node o = nodes[j];
+                if (o.getClass() == n.getClass()) {
+                    list2.add(new NodePair(n, o));
+                }
+            }
+        }
+        valueNumberableLeafNodes = vnln.toArray(new Node[vnln.size()]);
+        valueEqualsNodePairs = list2.toArray(new NodePair[list2.size()]);
+    }
+
+    /**
+     * Used to check that benchmark does not mutate {@link #nodes}.
+     */
+    private final Node[] originalNodes;
+
+    /**
+     * The nodes processed by the benchmark. These arrays must be treated as read-only within the
+     * benchmark method.
+     */
+    public final StructuredGraph graph;
+    public final Node[] nodes;
+    public final Node[] valueNumberableLeafNodes;
+    public final NodePair[] valueEqualsNodePairs;
+
+    public final class NodePair {
+        public final Node n1;
+        public final Node n2;
+
+        public NodePair(Node n1, Node n2) {
+            this.n1 = n1;
+            this.n2 = n2;
+        }
+    }
+
+    private int invocation;
+
+    @TearDown(Level.Invocation)
+    public void afterInvocation() {
+        if (invocation == 0) {
+            // Only need to check the first invocation
+            invocation++;
+            for (int i = 0; i < nodes.length; i++) {
+                if (nodes[i] != originalNodes[i]) {
+                    throw new InternalError(String.format("Benchmark method mutated node %d: original=%s, current=%s", i, originalNodes[i], nodes[i]));
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java
new file mode 100644
index 0000000..d940122
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal.util;
+
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+
+public class ScheduleState extends GraphState {
+
+    public SchedulePhase schedule;
+
+    private final SchedulingStrategy selectedStrategy;
+
+    public ScheduleState(SchedulingStrategy selectedStrategy) {
+        this.selectedStrategy = selectedStrategy;
+    }
+
+    public ScheduleState() {
+        this(SchedulingStrategy.EARLIEST);
+    }
+
+    @Override
+    public void beforeInvocation() {
+        schedule = new SchedulePhase(selectedStrategy);
+        super.beforeInvocation();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/CompileTimeBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/CompileTimeBenchmark.java
new file mode 100644
index 0000000..e806eb8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/CompileTimeBenchmark.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Param;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public class CompileTimeBenchmark extends GraalBenchmark {
+
+    public static class CompileState extends GraalCompilerState.Compile {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
+    }
+
+    @Benchmark
+    public CompilationResult compile(CompileState s) {
+        return s.compile();
+    }
+
+    public static class FrontEndState extends GraalCompilerState.FrontEndOnly {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
+    }
+
+    @Benchmark
+    public StructuredGraph frontend(FrontEndState s) {
+        return s.compile();
+    }
+
+    public static class BackEndEndState extends GraalCompilerState.BackEndOnly {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
+    }
+
+    @Benchmark
+    public CompilationResult backend(BackEndEndState s) {
+        return s.compile();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java
new file mode 100644
index 0000000..1f22021
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir;
+
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getGraph;
+import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getMethodFromMethodSpec;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.GraalCompiler.Request;
+import org.graalvm.compiler.core.LIRGenerationPhase;
+import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.internal.DebugScope;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.options.DerivedOptionValue;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.phases.tiers.TargetProvider;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * State providing a new copy of a graph for each invocation of a benchmark. Subclasses of this
+ * class are annotated with {@link MethodSpec} to specify the Java method that will be parsed to
+ * obtain the original graph.
+ */
+@State(Scope.Thread)
+public abstract class GraalCompilerState {
+
+    /**
+     * Original graph from which the per-benchmark invocation {@link #graph} is cloned.
+     */
+    private StructuredGraph originalGraph;
+
+    /**
+     * The graph processed by the benchmark.
+     */
+    private StructuredGraph graph;
+    private final Backend backend;
+    private final Providers providers;
+    private final DerivedOptionValue<Suites> suites;
+    private final DerivedOptionValue<LIRSuites> lirSuites;
+
+    /**
+     * We only allow inner classes to subclass this to ensure that the {@link Setup} methods are
+     * executed in the right order.
+     */
+    @SuppressWarnings("try")
+    protected GraalCompilerState() {
+        this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        this.providers = backend.getProviders();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
+
+        // Ensure a debug configuration for this thread is initialized
+        if (Debug.isEnabled() && DebugScope.getConfig() == null) {
+            DebugEnvironment.initialize(System.out);
+        }
+
+    }
+
+    protected boolean useProfilingInfo() {
+        return false;
+    }
+
+    @SuppressWarnings("try")
+    protected void initializeMethod() {
+        GraalState graal = new GraalState();
+        ResolvedJavaMethod method = graal.metaAccess.lookupJavaMethod(getMethod());
+        StructuredGraph structuredGraph = null;
+        try (Debug.Scope s = Debug.scope("GraphState", method)) {
+            structuredGraph = preprocessOriginal(getGraph(graal, method, useProfilingInfo()));
+        } catch (Throwable t) {
+            Debug.handle(t);
+        }
+        this.originalGraph = structuredGraph;
+    }
+
+    protected Method getMethod() {
+        Class<?> c = getClass();
+        if (isMethodSpecAnnotationPresent(c)) {
+            return getMethodFromMethodSpec(c);
+        }
+        return findParamField(this);
+    }
+
+    protected boolean isMethodSpecAnnotationPresent(Class<?> startClass) {
+        Class<?> c = startClass;
+        while (c != null) {
+            if (c.isAnnotationPresent(MethodSpec.class)) {
+                return true;
+            }
+            c = c.getSuperclass();
+        }
+        return false;
+    }
+
+    /**
+     * Declares {@link GraalCompilerState#getMethodFromString(String) method description field}. The
+     * field must be a {@link String} and have a {@link Param} annotation.
+     */
+    @Inherited
+    @Target({ElementType.FIELD})
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface MethodDescString {
+    }
+
+    private static Method findParamField(Object obj) {
+        Class<?> c = obj.getClass();
+        Class<? extends Annotation> annotationClass = MethodDescString.class;
+        try {
+            for (Field f : c.getFields()) {
+                if (f.isAnnotationPresent(annotationClass)) {
+                    // these checks could be done by an annotation processor
+                    if (!f.getType().equals(String.class)) {
+                        throw new RuntimeException("Found a field annotated with " + annotationClass.getSimpleName() + " in " + c + " which is not a " + String.class.getSimpleName());
+                    }
+                    if (!f.isAnnotationPresent(Param.class)) {
+                        throw new RuntimeException("Found a field annotated with " + annotationClass.getSimpleName() + " in " + c + " which is not annotated with " + Param.class.getSimpleName());
+                    }
+                    String methodName;
+                    methodName = (String) f.get(obj);
+                    assert methodName != null;
+                    return getMethodFromString(methodName);
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        throw new RuntimeException("Could not find class annotated with " + annotationClass.getSimpleName() + " in hierarchy of " + c);
+    }
+
+    /**
+     * Gets a {@link Method} from a method description string. The format is as follows:
+     *
+     * <pre>
+     * ClassName#MethodName
+     * ClassName#MethodName(ClassName, ClassName, ...)
+     * </pre>
+     *
+     * <code>CodeName</code> is passed to {@link Class#forName(String)}. <br>
+     * <b>Examples:</b>
+     *
+     * <pre>
+     * java.lang.String#equals
+     * java.lang.String#equals(java.lang.Object)
+     * </pre>
+     */
+    protected static Method getMethodFromString(String methodDesc) {
+        try {
+            String[] s0 = methodDesc.split("#", 2);
+            if (s0.length != 2) {
+                throw new RuntimeException("Missing method description? " + methodDesc);
+            }
+            String className = s0[0];
+            Class<?> clazz = Class.forName(className);
+            String[] s1 = s0[1].split("\\(", 2);
+            String name = s1[0];
+            Class<?>[] parameters = null;
+            if (s1.length > 1) {
+                String parametersPart = s1[1];
+                if (parametersPart.charAt(parametersPart.length() - 1) != ')') {
+                    throw new RuntimeException("Missing closing ')'? " + methodDesc);
+                }
+                String[] s2 = parametersPart.substring(0, parametersPart.length() - 1).split(",");
+                parameters = new Class<?>[s2.length];
+                for (int i = 0; i < s2.length; i++) {
+                    parameters[i] = Class.forName(s2[i]);
+                }
+            }
+            return GraalUtil.getMethod(clazz, name, parameters);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) {
+        return structuredGraph;
+    }
+
+    protected Suites createSuites() {
+        Suites ret = backend.getSuites().getDefaultSuites().copy();
+        return ret;
+    }
+
+    protected LIRSuites createLIRSuites() {
+        LIRSuites ret = backend.getSuites().getDefaultLIRSuites().copy();
+        return ret;
+    }
+
+    protected Backend getBackend() {
+        return backend;
+    }
+
+    protected Suites getSuites() {
+        return suites.getValue();
+    }
+
+    protected LIRSuites getOriginalLIRSuites() {
+        return lirSuites.getValue();
+    }
+
+    protected Providers getProviders() {
+        return providers;
+    }
+
+    protected SnippetReflectionProvider getSnippetReflection() {
+        return Graal.getRequiredCapability(SnippetReflectionProvider.class);
+    }
+
+    protected TargetDescription getTarget() {
+        return getTargetProvider().getTarget();
+    }
+
+    protected TargetProvider getTargetProvider() {
+        return getBackend();
+    }
+
+    protected CodeCacheProvider getCodeCache() {
+        return getProviders().getCodeCache();
+    }
+
+    protected ConstantReflectionProvider getConstantReflection() {
+        return getProviders().getConstantReflection();
+    }
+
+    protected MetaAccessProvider getMetaAccess() {
+        return getProviders().getMetaAccess();
+    }
+
+    protected LoweringProvider getLowerer() {
+        return getProviders().getLowerer();
+    }
+
+    protected PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
+        // defensive copying
+        return backend.getSuites().getDefaultGraphBuilderSuite().copy();
+    }
+
+    protected LIRSuites getLIRSuites() {
+        return request.lirSuites;
+    }
+
+    private Request<CompilationResult> request;
+    private LIRGenerationResult lirGenRes;
+    private LIRGeneratorTool lirGenTool;
+    private NodeLIRBuilderTool nodeLirGen;
+    private RegisterConfig registerConfig;
+    private ScheduleResult schedule;
+    private AbstractBlockBase<?>[] codeEmittingOrder;
+    private AbstractBlockBase<?>[] linearScanOrder;
+
+    /**
+     * Copies the {@link #originalGraph original graph} and prepares the {@link #request}.
+     *
+     * The {@link Suites} can be changed by overriding {@link #createSuites()}. {@link LIRSuites}
+     * can be changed by overriding {@link #createLIRSuites()}.
+     */
+    protected final void prepareRequest() {
+        assert originalGraph != null : "call initialzeMethod first";
+        CompilationIdentifier compilationId = backend.getCompilationIdentifier(originalGraph.method());
+        graph = originalGraph.copyWithIdentifier(compilationId);
+        assert !graph.isFrozen();
+        ResolvedJavaMethod installedCodeOwner = graph.method();
+        request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
+                        graph.getProfilingInfo(), getSuites(), getOriginalLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+    }
+
+    /**
+     * Executes the high-level (FrontEnd) part of the compiler.
+     */
+    protected final void emitFrontEnd() {
+        GraalCompiler.emitFrontEnd(request.providers, request.backend, request.graph, request.graphBuilderSuite, request.optimisticOpts, request.profilingInfo, request.suites);
+        request.graph.freeze();
+    }
+
+    /**
+     * Executes the low-level (BackEnd) part of the compiler.
+     */
+    protected final void emitBackEnd() {
+        emitLIR();
+        emitCode();
+    }
+
+    /**
+     * Generates {@link LIR} and executes the {@link LIR} pipeline.
+     */
+    protected final void emitLIR() {
+        generateLIR();
+        emitLowLevel();
+    }
+
+    /**
+     * Generates the initial {@link LIR}.
+     */
+    protected final void generateLIR() {
+        preLIRGeneration();
+        lirGeneration();
+    }
+
+    /**
+     * Sets up {@link LIR} generation.
+     */
+    protected final void preLIRGeneration() {
+        assert request.graph.isFrozen() : "Graph not frozen.";
+        Object stub = null;
+        schedule = request.graph.getLastSchedule();
+        ControlFlowGraph cfg = deepCopy(schedule.getCFG());
+        Block[] blocks = cfg.getBlocks();
+        Block startBlock = cfg.getStartBlock();
+        assert startBlock != null;
+        assert startBlock.getPredecessorCount() == 0;
+
+        codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
+        linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
+
+        LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
+        FrameMapBuilder frameMapBuilder = request.backend.newFrameMapBuilder(registerConfig);
+        lirGenRes = request.backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, request.graph, stub);
+        lirGenTool = request.backend.newLIRGenerator(lirGenRes);
+        nodeLirGen = request.backend.newNodeLIRBuilder(request.graph, lirGenTool);
+    }
+
+    private static ControlFlowGraph deepCopy(ControlFlowGraph cfg) {
+        return ControlFlowGraph.compute(cfg.graph, true, true, true, true);
+    }
+
+    /**
+     * Executes the {@link LIRGenerationPhase}.
+     */
+    protected final void lirGeneration() {
+        LIRGenerationContext context = new LIRGenerationContext(lirGenTool, nodeLirGen, request.graph, schedule);
+        new LIRGenerationPhase().apply(request.backend.getTarget(), lirGenRes, context);
+    }
+
+    /**
+     * Executes the low-level compiler stages.
+     */
+    protected final void emitLowLevel() {
+        preAllocationStage();
+        allocationStage();
+        postAllocationStage();
+    }
+
+    /**
+     * Executes a {@link LIRPhase} within a given {@code context}.
+     */
+    protected <C> void applyLIRPhase(LIRPhase<C> phase, C context) {
+        phase.apply(request.backend.getTarget(), lirGenRes, context);
+    }
+
+    /**
+     * Executes the {@link PreAllocationStage}.
+     *
+     * {@link LIRPhase phases} can be changed by overriding {@link #createLIRSuites()}.
+     */
+    protected final void preAllocationStage() {
+        applyLIRPhase(getLIRSuites().getPreAllocationOptimizationStage(), createPreAllocationOptimizationContext());
+    }
+
+    protected PreAllocationOptimizationContext createPreAllocationOptimizationContext() {
+        return new PreAllocationOptimizationContext(lirGenTool);
+    }
+
+    /**
+     * Executes the {@link AllocationStage}.
+     *
+     * {@link LIRPhase phases} can be changed by overriding {@link #createLIRSuites()}.
+     */
+    protected final void allocationStage() {
+        applyLIRPhase(getLIRSuites().getAllocationStage(), createAllocationContext());
+    }
+
+    protected AllocationContext createAllocationContext() {
+        return new AllocationContext(lirGenTool.getSpillMoveFactory(), request.backend.newRegisterAllocationConfig(registerConfig));
+    }
+
+    /**
+     * Executes the {@link PostAllocationStage}.
+     *
+     * {@link LIRPhase phases} can be changed by overriding {@link #createLIRSuites()}.
+     */
+    protected final void postAllocationStage() {
+        applyLIRPhase(getLIRSuites().getPostAllocationOptimizationStage(), createPostAllocationOptimizationContext());
+    }
+
+    protected PostAllocationOptimizationContext createPostAllocationOptimizationContext() {
+        return new PostAllocationOptimizationContext(lirGenTool);
+    }
+
+    /**
+     * Emits the machine code.
+     */
+    protected final void emitCode() {
+        int bytecodeSize = request.graph.method() == null ? 0 : request.graph.getBytecodeSize();
+        request.compilationResult.setHasUnsafeAccess(request.graph.hasUnsafeAccess());
+        GraalCompiler.emitCode(request.backend, request.graph.getAssumptions(), request.graph.method(), request.graph.getMethods(), request.graph.getFields(), bytecodeSize, lirGenRes,
+                        request.compilationResult, request.installedCodeOwner, request.factory);
+    }
+
+    protected StructuredGraph graph() {
+        return graph;
+    }
+
+    protected LIR getLIR() {
+        return lirGenRes.getLIR();
+    }
+
+    public abstract static class Compile extends GraalCompilerState {
+
+        @Setup(Level.Trial)
+        public void init() {
+            initializeMethod();
+        }
+
+        @Setup(Level.Invocation)
+        public void setup() {
+            prepareRequest();
+        }
+
+        public CompilationResult compile() {
+            emitFrontEnd();
+            emitBackEnd();
+            return super.request.compilationResult;
+        }
+
+    }
+
+    public abstract static class FrontEndOnly extends GraalCompilerState {
+
+        @Setup(Level.Trial)
+        public void init() {
+            initializeMethod();
+        }
+
+        @Setup(Level.Invocation)
+        public void setup() {
+            prepareRequest();
+        }
+
+        public StructuredGraph compile() {
+            emitFrontEnd();
+            return super.graph;
+        }
+
+    }
+
+    public abstract static class BackEndOnly extends GraalCompilerState {
+
+        @Setup(Level.Trial)
+        public void init() {
+            initializeMethod();
+        }
+
+        /**
+         * Cannot do this {@link Level#Trial only once} since {@link #emitCode()} closes the
+         * {@link CompilationResult}.
+         */
+        @Setup(Level.Invocation)
+        public void setupGraph() {
+            prepareRequest();
+            emitFrontEnd();
+        }
+
+        public CompilationResult compile() {
+            emitBackEnd();
+            return super.request.compilationResult;
+        }
+    }
+
+    public abstract static class PreAllocationStage extends GraalCompilerState {
+        /**
+         * No need to rebuild the graph for every invocation since it is not altered by the backend.
+         */
+        @Setup(Level.Trial)
+        public void setupGraph() {
+            initializeMethod();
+            prepareRequest();
+            emitFrontEnd();
+        }
+
+        @Setup(Level.Invocation)
+        public void setup() {
+            generateLIR();
+        }
+
+        public LIRGenerationResult compile() {
+            preAllocationStage();
+            return super.lirGenRes;
+        }
+    }
+
+    public abstract static class AllocationStage extends GraalCompilerState {
+        /**
+         * No need to rebuild the graph for every invocation since it is not altered by the backend.
+         */
+        @Setup(Level.Trial)
+        public void setupGraph() {
+            initializeMethod();
+            prepareRequest();
+            emitFrontEnd();
+        }
+
+        @Setup(Level.Invocation)
+        public void setup() {
+            generateLIR();
+            preAllocationStage();
+        }
+
+        public LIRGenerationResult compile() {
+            allocationStage();
+            return super.lirGenRes;
+        }
+    }
+
+    public abstract static class PostAllocationStage extends GraalCompilerState {
+        /**
+         * No need to rebuild the graph for every invocation since it is not altered by the backend.
+         */
+        @Setup(Level.Trial)
+        public void setupGraph() {
+            initializeMethod();
+            prepareRequest();
+            emitFrontEnd();
+        }
+
+        @Setup(Level.Invocation)
+        public void setup() {
+            generateLIR();
+            preAllocationStage();
+            allocationStage();
+        }
+
+        public LIRGenerationResult compile() {
+            postAllocationStage();
+            return super.lirGenRes;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java
new file mode 100644
index 0000000..4e0e1be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir;
+
+import java.util.HashMap;
+
+import org.openjdk.jmh.annotations.Benchmark;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+public class RegisterAllocationTimeBenchmark extends GraalBenchmark {
+
+    // Checkstyle: stop method name check
+    public static class LSRA_Allocation extends GraalCompilerState.AllocationStage {
+        @SuppressWarnings("try")
+        @Override
+        protected LIRSuites createLIRSuites() {
+            try (OverrideScope os = OptionValue.override(GraalOptions.TraceRA, false)) {
+                return super.createLIRSuites();
+            }
+        }
+    }
+
+    @MethodSpec(declaringClass = String.class, name = "equals")
+    public static class LSRA_StringEquals extends LSRA_Allocation {
+    }
+
+    @MethodSpec(declaringClass = HashMap.class, name = "computeIfAbsent")
+    public static class LSRA_HashMapComputeIfAbsent extends LSRA_Allocation {
+    }
+
+    @Benchmark
+    public LIRGenerationResult lsra_STRING_equals(LSRA_StringEquals s) {
+        return s.compile();
+    }
+
+    @Benchmark
+    public LIRGenerationResult lsra_HASHMAP_computeIfAbsent(LSRA_HashMapComputeIfAbsent s) {
+        return s.compile();
+    }
+
+    public static class TraceRA_Allocation extends GraalCompilerState.AllocationStage {
+        @SuppressWarnings("try")
+        @Override
+        protected LIRSuites createLIRSuites() {
+            try (OverrideScope os = OptionValue.override(GraalOptions.TraceRA, true)) {
+                return super.createLIRSuites();
+            }
+        }
+    }
+
+    @MethodSpec(declaringClass = String.class, name = "equals")
+    public static class TraceRA_StringEquals extends TraceRA_Allocation {
+    }
+
+    @MethodSpec(declaringClass = HashMap.class, name = "computeIfAbsent")
+    public static class TraceRA_HashMapComputeIfAbsent extends TraceRA_Allocation {
+    }
+
+    @Benchmark
+    public LIRGenerationResult tracera_STRING_equals(TraceRA_StringEquals s) {
+        return s.compile();
+    }
+
+    @Benchmark
+    public LIRGenerationResult tracera_HASHMAP_computeIfAbsent(TraceRA_HashMapComputeIfAbsent s) {
+        return s.compile();
+    }
+    // Checkstyle: resume method name check
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/ControlFlowGraphState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/ControlFlowGraphState.java
new file mode 100644
index 0000000..81dc2bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/ControlFlowGraphState.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir.trace;
+
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Setup;
+
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.microbenchmarks.lir.GraalCompilerState;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+
+/**
+ * State class for working with {@link ControlFlowGraph} and {@link LIR}.
+ */
+public abstract class ControlFlowGraphState extends GraalCompilerState {
+
+    public ControlFlowGraph cfg;
+
+    @Setup(Level.Trial)
+    public void beforeBenchmark() {
+        // setup graph
+        initializeMethod();
+        prepareRequest();
+        emitFrontEnd();
+        generateLIR();
+        // compute cfg
+        this.cfg = (ControlFlowGraph) getLIR().getControlFlowGraph();
+    }
+
+    @Override
+    public LIR getLIR() {
+        return super.getLIR();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceBuilderBenchmark.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceBuilderBenchmark.java
new file mode 100644
index 0000000..c925ab2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceBuilderBenchmark.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir.trace;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.core.common.alloc.BiDirectionalTraceBuilder;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.alloc.UniDirectionalTraceBuilder;
+import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+@Warmup(iterations = 15)
+public class TraceBuilderBenchmark extends GraalBenchmark {
+
+    public static class State extends ControlFlowGraphState {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
+    }
+
+    @Benchmark
+    public TraceBuilderResult uniDirectionalTraceBuilder(State s) {
+        return UniDirectionalTraceBuilder.computeTraces(s.cfg.getStartBlock(), s.cfg.getBlocks(), TraceBuilderPhase.getTrivialTracePredicate(s.getLIR()));
+    }
+
+    @Benchmark
+    public TraceBuilderResult biDirectionalTraceBuilder(State s) {
+        return BiDirectionalTraceBuilder.computeTraces(s.cfg.getStartBlock(), s.cfg.getBlocks(), TraceBuilderPhase.getTrivialTracePredicate(s.getLIR()));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java
new file mode 100644
index 0000000..6a0c90c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.lir.trace;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Setup;
+
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase.Analyser;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.lir.ssi.SSIConstructionPhase;
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+import org.graalvm.compiler.microbenchmarks.lir.GraalCompilerState;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Benchmarks {@link TraceLinearScan TraceRA} {@link TraceLinearScanLifetimeAnalysisPhase lifetime
+ * analysis phase}.
+ */
+public class TraceLSRAIntervalBuildingBench extends GraalBenchmark {
+
+    private static class DummyTraceAllocatorPhase extends AllocationPhase {
+        private TraceLinearScan allocator;
+
+        @Override
+        @SuppressWarnings("try")
+        protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+            MoveFactory spillMoveFactory = context.spillMoveFactory;
+            RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig;
+            TraceBuilderResult resultTraces = context.contextLookup(TraceBuilderResult.class);
+            TraceLinearScanPhase phase = new TraceLinearScanPhase(target, lirGenRes, spillMoveFactory, registerAllocationConfig, resultTraces, false, null);
+            for (Trace trace : resultTraces.getTraces()) {
+                allocator = phase.createAllocator(trace);
+                Analyser a = new TraceLinearScanLifetimeAnalysisPhase.Analyser(allocator, resultTraces);
+                a.analyze();
+            }
+        }
+    }
+
+    public abstract static class AllocationState extends GraalCompilerState {
+
+        private static final DummyTraceAllocatorPhase LTA_PHASE = new DummyTraceAllocatorPhase();
+        private static final SSIConstructionPhase SSI_CONSTRUCTION_PHASE = new SSIConstructionPhase();
+        private static final TraceBuilderPhase TRACE_BUILDER_PHASE = new TraceBuilderPhase();
+
+        private AllocationContext allocationContext;
+
+        @Override
+        protected LIRSuites getLIRSuites() {
+            LIRSuites ls = super.getLIRSuites();
+            LIRPhaseSuite<AllocationContext> allocationStage = new LIRPhaseSuite<>();
+            allocationStage.appendPhase(TRACE_BUILDER_PHASE);
+            allocationStage.appendPhase(SSI_CONSTRUCTION_PHASE);
+            return new LIRSuites(ls.getPreAllocationOptimizationStage(), allocationStage, ls.getPostAllocationOptimizationStage());
+        }
+
+        @Setup(Level.Trial)
+        public void setup() {
+            initializeMethod();
+            prepareRequest();
+            emitFrontEnd();
+            generateLIR();
+            preAllocationStage();
+            // context for all allocation phases
+            allocationContext = createAllocationContext();
+            applyLIRPhase(TRACE_BUILDER_PHASE, allocationContext);
+            applyLIRPhase(SSI_CONSTRUCTION_PHASE, allocationContext);
+        }
+
+        public TraceLinearScan compile() {
+            applyLIRPhase(LTA_PHASE, allocationContext);
+            return LTA_PHASE.allocator;
+        }
+
+    }
+
+    public static class State extends AllocationState {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
+    }
+
+    @Benchmark
+    public TraceLinearScan buildIntervals(State s) {
+        return s.compile();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..04e4d59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.graalvm.compiler.nodeinfo.processor.GraphNodeProcessor
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/ElementException.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/ElementException.java
new file mode 100644
index 0000000..7a0d695
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/ElementException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo.processor;
+
+import javax.lang.model.element.Element;
+
+/**
+ * Denotes an error encountered while processing an element.
+ */
+@SuppressWarnings("serial")
+public class ElementException extends RuntimeException {
+    public final Element element;
+
+    public ElementException(Element element, String format, Object... args) {
+        super(String.format(format, args));
+        this.element = element;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java
new file mode 100644
index 0000000..1d21ccb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo.processor;
+
+import static java.util.Collections.reverse;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
+@SupportedAnnotationTypes({"org.graalvm.compiler.nodeinfo.NodeInfo"})
+public class GraphNodeProcessor extends AbstractProcessor {
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    /**
+     * Node class currently being processed.
+     */
+    private Element scope;
+
+    public static boolean isEnclosedIn(Element e, Element scopeElement) {
+        List<Element> elementHierarchy = getElementHierarchy(e);
+        return elementHierarchy.contains(scopeElement);
+    }
+
+    void errorMessage(Element element, String format, Object... args) {
+        message(Kind.ERROR, element, format, args);
+    }
+
+    void message(Kind kind, Element element, String format, Object... args) {
+        if (scope != null && !isEnclosedIn(element, scope)) {
+            // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=428357#c1
+            List<Element> elementHierarchy = getElementHierarchy(element);
+            reverse(elementHierarchy);
+            String loc = elementHierarchy.stream().filter(e -> e.getKind() != ElementKind.PACKAGE).map(Object::toString).collect(Collectors.joining("."));
+            processingEnv.getMessager().printMessage(kind, String.format(loc + ": " + format, args), scope);
+        } else {
+            processingEnv.getMessager().printMessage(kind, String.format(format, args), element);
+        }
+    }
+
+    private static List<Element> getElementHierarchy(Element e) {
+        List<Element> elements = new ArrayList<>();
+        elements.add(e);
+
+        Element enclosing = e.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            elements.add(enclosing);
+            enclosing = enclosing.getEnclosingElement();
+        }
+        if (enclosing != null) {
+            elements.add(enclosing);
+        }
+        return elements;
+    }
+
+    /**
+     * Bugs in an annotation processor can cause silent failure so try to report any exception
+     * throws as errors.
+     */
+    private void reportException(Kind kind, Element element, Throwable t) {
+        StringWriter buf = new StringWriter();
+        t.printStackTrace(new PrintWriter(buf));
+        buf.toString();
+        message(kind, element, "Exception thrown during processing: %s", buf.toString());
+    }
+
+    ProcessingEnvironment getProcessingEnv() {
+        return processingEnv;
+    }
+
+    boolean isNodeType(Element element) {
+        if (element.getKind() != ElementKind.CLASS) {
+            return false;
+        }
+        TypeElement type = (TypeElement) element;
+        Types types = processingEnv.getTypeUtils();
+
+        while (type != null) {
+            if (type.toString().equals("org.graalvm.compiler.graph.Node")) {
+                return true;
+            }
+            type = (TypeElement) types.asElement(type.getSuperclass());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return false;
+        }
+
+        GraphNodeVerifier verifier = new GraphNodeVerifier(this);
+
+        for (Element element : roundEnv.getElementsAnnotatedWith(NodeInfo.class)) {
+            scope = element;
+            try {
+                if (!isNodeType(element)) {
+                    errorMessage(element, "%s can only be applied to Node subclasses", NodeInfo.class.getSimpleName());
+                    continue;
+                }
+
+                NodeInfo nodeInfo = element.getAnnotation(NodeInfo.class);
+                if (nodeInfo == null) {
+                    errorMessage(element, "Cannot get %s annotation from annotated element", NodeInfo.class.getSimpleName());
+                    continue;
+                }
+
+                TypeElement typeElement = (TypeElement) element;
+
+                Set<Modifier> modifiers = typeElement.getModifiers();
+                if (!modifiers.contains(Modifier.FINAL) && !modifiers.contains(Modifier.ABSTRACT)) {
+                    // TODO(thomaswue): Reenable this check.
+                    // errorMessage(element, "%s annotated class must be either final or abstract",
+                    // NodeInfo.class.getSimpleName());
+                    // continue;
+                }
+                boolean found = false;
+                for (Element e : typeElement.getEnclosedElements()) {
+                    if (e.getKind() == ElementKind.FIELD) {
+                        if (e.getSimpleName().toString().equals("TYPE")) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                if (!found) {
+                    errorMessage(element, "%s annotated class must have a field named TYPE", NodeInfo.class.getSimpleName());
+                }
+
+                if (!typeElement.equals(verifier.Node) && !modifiers.contains(Modifier.ABSTRACT)) {
+                    verifier.verify(typeElement);
+                }
+            } catch (ElementException ee) {
+                errorMessage(ee.element, ee.getMessage());
+            } catch (Throwable t) {
+                reportException(isBug367599(t) ? Kind.NOTE : Kind.ERROR, element, t);
+            } finally {
+                scope = null;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines if a given exception is (most likely) caused by
+     * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
+     */
+    public static boolean isBug367599(Throwable t) {
+        if (t instanceof FilerException) {
+            for (StackTraceElement ste : t.getStackTrace()) {
+                if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
+                    // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
+                    return true;
+                }
+            }
+        }
+        if (t.getCause() != null) {
+            return isBug367599(t.getCause());
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeVerifier.java
new file mode 100644
index 0000000..108d6ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeVerifier.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo.processor;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.element.Modifier.TRANSIENT;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+/**
+ * Verifies static constraints on nodes.
+ */
+public class GraphNodeVerifier {
+
+    private final GraphNodeProcessor env;
+    private final Types types;
+    private final Elements elements;
+
+    // Checkstyle: stop
+    private final TypeElement Input;
+    private final TypeElement OptionalInput;
+    private final TypeElement Successor;
+
+    final TypeElement Node;
+    private final TypeElement NodeInputList;
+    private final TypeElement NodeSuccessorList;
+
+    private final TypeElement object;
+
+    // Checkstyle: resume
+
+    public GraphNodeVerifier(GraphNodeProcessor processor) {
+        this.env = processor;
+
+        this.types = processor.getProcessingEnv().getTypeUtils();
+        this.elements = processor.getProcessingEnv().getElementUtils();
+
+        this.Input = getTypeElement("org.graalvm.compiler.graph.Node.Input");
+        this.OptionalInput = getTypeElement("org.graalvm.compiler.graph.Node.OptionalInput");
+        this.Successor = getTypeElement("org.graalvm.compiler.graph.Node.Successor");
+        this.Node = getTypeElement("org.graalvm.compiler.graph.Node");
+        this.NodeInputList = getTypeElement("org.graalvm.compiler.graph.NodeInputList");
+        this.NodeSuccessorList = getTypeElement("org.graalvm.compiler.graph.NodeSuccessorList");
+        this.object = getTypeElement("java.lang.Object");
+    }
+
+    /**
+     * Returns a type element given a canonical name.
+     *
+     * @throw {@link NoClassDefFoundError} if a type element does not exist for {@code name}
+     */
+    public TypeElement getTypeElement(String name) {
+        TypeElement typeElement = elements.getTypeElement(name);
+        if (typeElement == null) {
+            throw new NoClassDefFoundError(name);
+        }
+        return typeElement;
+    }
+
+    public TypeElement getTypeElement(Class<?> cls) {
+        return getTypeElement(cls.getName());
+    }
+
+    public TypeMirror getType(String name) {
+        return getTypeElement(name).asType();
+    }
+
+    public ProcessingEnvironment getProcessingEnv() {
+        return env.getProcessingEnv();
+    }
+
+    public boolean isAssignableWithErasure(Element from, Element to) {
+        TypeMirror fromType = types.erasure(from.asType());
+        TypeMirror toType = types.erasure(to.asType());
+        return types.isAssignable(fromType, toType);
+    }
+
+    private void scanFields(TypeElement node) {
+        TypeElement currentClazz = node;
+        do {
+            for (VariableElement field : ElementFilter.fieldsIn(currentClazz.getEnclosedElements())) {
+                Set<Modifier> modifiers = field.getModifiers();
+                if (modifiers.contains(STATIC) || modifiers.contains(TRANSIENT)) {
+                    continue;
+                }
+
+                List<? extends AnnotationMirror> annotations = field.getAnnotationMirrors();
+
+                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;
+                boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;
+                boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;
+
+                if (isNonOptionalInput || isOptionalInput) {
+                    if (findAnnotationMirror(annotations, Successor) != null) {
+                        throw new ElementException(field, "Field cannot be both input and successor");
+                    } else if (isNonOptionalInput && isOptionalInput) {
+                        throw new ElementException(field, "Inputs must be either optional or non-optional");
+                    } else if (isAssignableWithErasure(field, NodeInputList)) {
+                        if (modifiers.contains(FINAL)) {
+                            throw new ElementException(field, "Input list field must not be final");
+                        }
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input list field must not be public");
+                        }
+                    } else {
+                        if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {
+                            throw new ElementException(field, "Input field type must be an interface or assignable to Node");
+                        }
+                        if (modifiers.contains(FINAL)) {
+                            throw new ElementException(field, "Input field must not be final");
+                        }
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input field must not be public");
+                        }
+                    }
+                } else if (isSuccessor) {
+                    if (isAssignableWithErasure(field, NodeSuccessorList)) {
+                        if (modifiers.contains(FINAL)) {
+                            throw new ElementException(field, "Successor list field must not be final");
+                        }
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Successor list field must not be public");
+                        }
+                    } else {
+                        if (!isAssignableWithErasure(field, Node)) {
+                            throw new ElementException(field, "Successor field must be a Node type");
+                        }
+                        if (modifiers.contains(FINAL)) {
+                            throw new ElementException(field, "Successor field must not be final");
+                        }
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Successor field must not be public");
+                        }
+                    }
+
+                } else {
+                    if (isAssignableWithErasure(field, Node) && !field.getSimpleName().contentEquals("Null")) {
+                        throw new ElementException(field, "Node field must be annotated with @" + Input.getSimpleName() + ", @" + OptionalInput.getSimpleName() + " or @" + Successor.getSimpleName());
+                    }
+                    if (isAssignableWithErasure(field, NodeInputList)) {
+                        throw new ElementException(field, "NodeInputList field must be annotated with @" + Input.getSimpleName() + " or @" + OptionalInput.getSimpleName());
+                    }
+                    if (isAssignableWithErasure(field, NodeSuccessorList)) {
+                        throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName());
+                    }
+                    if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) {
+                        throw new ElementException(field, "Data field must be final if public");
+                    }
+                }
+            }
+            currentClazz = getSuperType(currentClazz);
+        } while (!isObject(getSuperType(currentClazz).asType()));
+    }
+
+    private AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) {
+        for (AnnotationMirror mirror : mirrors) {
+            if (sameType(mirror.getAnnotationType(), expectedAnnotationType.asType())) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
+    private boolean isObject(TypeMirror type) {
+        return sameType(object.asType(), type);
+    }
+
+    private boolean sameType(TypeMirror type1, TypeMirror type2) {
+        return env.getProcessingEnv().getTypeUtils().isSameType(type1, type2);
+    }
+
+    private TypeElement getSuperType(TypeElement element) {
+        if (element.getSuperclass() != null) {
+            return (TypeElement) env.getProcessingEnv().getTypeUtils().asElement(element.getSuperclass());
+        }
+        return null;
+    }
+
+    void verify(TypeElement node) {
+        scanFields(node);
+
+        boolean foundValidConstructor = false;
+        for (ExecutableElement constructor : ElementFilter.constructorsIn(node.getEnclosedElements())) {
+            if (constructor.getModifiers().contains(PRIVATE)) {
+                continue;
+            } else if (!constructor.getModifiers().contains(PUBLIC) && !constructor.getModifiers().contains(PROTECTED)) {
+                throw new ElementException(constructor, "Node class constructor must be public or protected");
+            }
+
+            foundValidConstructor = true;
+        }
+
+        if (!foundValidConstructor) {
+            throw new ElementException(node, "Node class must have at least one protected constructor");
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java
new file mode 100644
index 0000000..3f43060
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+public enum InputType {
+    /**
+     * Inputs that consume an actual value generated by the referenced node.
+     */
+    Value,
+    /**
+     * Inputs that consume the memory state of the referenced node.
+     */
+    Memory,
+    /**
+     * Inputs that reference a condition.
+     */
+    Condition,
+    /**
+     * Inputs that reference a frame state.
+     */
+    State,
+    /**
+     * Inputs that reference a guard (guards, begin nodes).
+     */
+    Guard,
+    /**
+     * Inputs that reference an anchor (begin nodes, value anchors).
+     */
+    Anchor,
+    /**
+     * Inputs that represent an association between nodes, e.g., a phi and the merge or a loop begin
+     * and loop exits and ends.
+     */
+    Association,
+    /**
+     * Inputs that connect tightly coupled nodes, e.g., an InvokeNode and its CallTargetNode.
+     */
+    Extension,
+    /**
+     * Inputs of this type are temporarily exempt from type checking. This should only be used in
+     * exceptional cases and should never survive to later stages of compilation.
+     */
+    Unchecked
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java
new file mode 100644
index 0000000..c4af1b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+/**
+ * Constants representing an estimation of the number of CPU cycles needed to execute a certain
+ * compiler node.
+ */
+public enum NodeCycles {
+
+    /**
+     * The default value of the {@link NodeInfo#cycles()} property.
+     * <p>
+     * For further information about the use of {@code CYCLES_UNSET} see {@link NodeInfo#cycles()}.
+     */
+    CYCLES_UNSET(0),
+    /**
+     * Nodes for which, due to arbitrary reasons, no estimation can be made either (1) statically
+     * without inspecting the properties of a node or (2) at all (like e.g. for an invocation).
+     * <p>
+     * Nodes annotated with {@code CYCLES_UNKNOWN} should specify the
+     * {@link NodeInfo#cyclesRationale()} property to clarify why an estimation cannot be done.
+     */
+    CYCLES_UNKNOWN(0),
+    /**
+     * Nodes for which runtime information is irrelevant and can be ignored, e.g. for test nodes.
+     */
+    CYCLES_IGNORED(0),
+    /**
+     * Nodes that do not consume any CPU time during the "execution", e.g. Constants.
+     */
+    CYCLES_0(0),
+    CYCLES_1(1),
+    CYCLES_2(2),
+    CYCLES_3(3),
+    CYCLES_4(4),
+    CYCLES_5(5),
+    CYCLES_6(6),
+    CYCLES_8(8),
+    CYCLES_10(10),
+    CYCLES_15(15),
+    CYCLES_20(20),
+    CYCLES_30(30),
+    CYCLES_40(40),
+    CYCLES_50(50),
+    CYCLES_80(80),
+    CYCLES_100(100),
+    CYCLES_200(200),
+    CYCLES_500(500);
+
+    public final int estimatedCPUCycles;
+
+    NodeCycles(int estimatedCPUCycles) {
+        this.estimatedCPUCycles = estimatedCPUCycles;
+    }
+
+    public static final int IGNORE_CYCLES_CONTRACT_FACTOR = 0xFFFF;
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeInfo.java
new file mode 100644
index 0000000..146a3e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNSET;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNSET;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface NodeInfo {
+
+    String shortName() default "";
+
+    /**
+     * The template used to build the {@link Verbosity#Name} version. Variable part are specified
+     * using &#123;i#inputName&#125; or &#123;p#propertyName&#125;.
+     */
+    String nameTemplate() default "";
+
+    InputType[] allowedUsageTypes() default {};
+
+    /**
+     * An estimation of the number of CPU cycles needed to execute this node that can be used to
+     * compare its execution cost against other nodes.
+     *
+     * Implementations of graph cost models based on this value might throw an exception if a node's
+     * {@link NodeCycles} value is {@link NodeCycles#CYCLES_UNSET}. As such, it is recommended to
+     * specify a value for nodes likely to be inputs to a graph cost model.
+     */
+    NodeCycles cycles() default CYCLES_UNSET;
+
+    /**
+     * A rationale for the chosen {@link NodeInfo#cycles()} value.
+     */
+    String cyclesRationale() default "";
+
+    /**
+     * An estimation of the code size needed to represent this node in machine code that can be used
+     * to compare its size cost against other nodes.
+     *
+     * Implementations of graph cost models based on this value might throw an exception if a node's
+     * {@link NodeSize} value is {@link NodeSize#SIZE_UNSET}. As such, it is recommended to specify
+     * a value for nodes likely to be inputs to a graph cost model.
+     */
+    NodeSize size() default SIZE_UNSET;
+
+    /**
+     * A rationale for the chosen {@link NodeInfo#size()} value.
+     */
+    String sizeRationale() default "";
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeSize.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeSize.java
new file mode 100644
index 0000000..d268aa0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeSize.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+/**
+ * Constants representing an estimation of of the size needed to represent a compiler node in
+ * machine code.
+ */
+public enum NodeSize {
+
+    /**
+     * The default value of the {@link NodeInfo#size()} property.
+     * <p>
+     * For further information about the use of {@code SIZE_UNSET} see {@link NodeInfo#size()}.
+     */
+    SIZE_UNSET(0),
+    /**
+     * Nodes for which, due to arbitrary reasons, no estimation can be made either (1) statically
+     * without inspecting the properties of a node or (2) at all (like e.g. for an invocation).
+     * <p>
+     * Nodes annotated with {@code SIZE_UNKNOWN} should specify the {@link NodeInfo#sizeRationale()}
+     * property to clarify why an estimation cannot be done.
+     */
+    SIZE_UNKNOWN(0),
+    /**
+     * Nodes for which code size information is irrelevant and can be ignored, e.g. for test nodes.
+     */
+    SIZE_IGNORED(0),
+    /**
+     * Nodes that do not require any code to be generated in order to be "executed", e.g. a phi
+     * node.
+     */
+    SIZE_0(0),
+    SIZE_1(1),
+    SIZE_2(2),
+    SIZE_3(3),
+    SIZE_4(4),
+    SIZE_6(6),
+    SIZE_8(8),
+    SIZE_10(10),
+    SIZE_15(15),
+    SIZE_20(20),
+    SIZE_30(30),
+    SIZE_40(40),
+    SIZE_50(50),
+    SIZE_80(80),
+    SIZE_100(100),
+    SIZE_200(200);
+
+    public final int estimatedCodeSize;
+
+    NodeSize(int estimatedCodeSize) {
+        this.estimatedCodeSize = estimatedCodeSize;
+    }
+
+    public static final int IGNORE_SIZE_CONTRACT_FACTOR = 0xFFFF;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/StructuralInput.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/StructuralInput.java
new file mode 100644
index 0000000..3b6c79d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/StructuralInput.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker type for describing node inputs in snippets that are not of type {@link InputType#Value}.
+ */
+public abstract class StructuralInput {
+
+    private StructuralInput() {
+        throw new Error("Illegal instance of StructuralInput. This class should be used in snippets only.");
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface MarkerType {
+        InputType value();
+    }
+
+    /**
+     * Marker type for {@link InputType#Memory} edges in snippets.
+     */
+    @MarkerType(InputType.Memory)
+    public abstract static class Memory extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Condition} edges in snippets.
+     */
+    @MarkerType(InputType.Condition)
+    public abstract static class Condition extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#State} edges in snippets.
+     */
+    @MarkerType(InputType.State)
+    public abstract static class State extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Guard} edges in snippets.
+     */
+    @MarkerType(InputType.Guard)
+    public abstract static class Guard extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Anchor} edges in snippets.
+     */
+    @MarkerType(InputType.Anchor)
+    public abstract static class Anchor extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Association} edges in snippets.
+     */
+    @MarkerType(InputType.Association)
+    public abstract static class Association extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Extension} edges in snippets.
+     */
+    @MarkerType(InputType.Extension)
+    public abstract static class Extension extends StructuralInput {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/Verbosity.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/Verbosity.java
new file mode 100644
index 0000000..c22f264
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/Verbosity.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodeinfo;
+
+public enum Verbosity {
+    /**
+     * Only the id of the node.
+     */
+    Id,
+    /**
+     * Only the name of the node, which may contain some more information for certain node types
+     * (constants, ...).
+     */
+    Name,
+    /**
+     * {@link #Id} + {@link #Name}.
+     */
+    Short,
+    /**
+     * Defaults to {@link #Short} and may be enhanced by subclasses.
+     */
+    Long,
+    /**
+     * For use by a custom formatting facility in an IDE.
+     */
+    Debugger,
+    /**
+     * All the other information plus all debug properties of the node.
+     */
+    All
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/AbstractObjectStampTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/AbstractObjectStampTest.java
new file mode 100644
index 0000000..680cea8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/AbstractObjectStampTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.junit.Assert;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+public abstract class AbstractObjectStampTest extends GraalCompilerTest {
+
+    protected static class A {
+
+    }
+
+    protected static class B extends A {
+
+    }
+
+    protected static class C extends B implements I {
+
+    }
+
+    protected static class D extends A {
+
+    }
+
+    protected abstract static class E extends A {
+
+    }
+
+    protected interface I {
+
+    }
+
+    protected interface OtherI {
+
+    }
+
+    protected interface SubI1 extends I {
+
+    }
+
+    protected interface SubI2 extends I {
+
+    }
+
+    protected interface SubI3 extends I {
+
+    }
+
+    protected interface SubI4 extends SubI3, SubI1 {
+    }
+
+    protected interface SubI5 extends SubI3, OtherI {
+
+    }
+
+    protected interface SubI6 extends OtherI {
+
+    }
+
+    protected interface Base1 {
+
+    }
+
+    protected interface Base2 {
+
+    }
+
+    protected interface ImplOrder1 extends Base1, Base2 {
+
+    }
+
+    protected interface ImplOrder2 extends Base2, Base1 {
+
+    }
+
+    /* Example of a deep interface hierarchy. */
+
+    protected interface I45 {
+
+    }
+
+    protected interface I46 {
+
+    }
+
+    protected interface I41 extends I45 {
+
+    }
+
+    protected interface I42 extends I45 {
+
+    }
+
+    protected interface I43 extends I46 {
+
+    }
+
+    protected interface I44 extends I46 {
+
+    }
+
+    protected interface I35 extends I41, I42 {
+
+    }
+
+    protected interface I36 extends I43, I44 {
+
+    }
+
+    protected interface I31 extends I35 {
+
+    }
+
+    protected interface I32 extends I35 {
+
+    }
+
+    protected interface I33 extends I36 {
+
+    }
+
+    protected interface I34 extends I36 {
+
+    }
+
+    protected interface I25 extends I31, I32 {
+
+    }
+
+    protected interface I26 extends I33, I34 {
+
+    }
+
+    protected interface I21 extends I25 {
+
+    }
+
+    protected interface I22 extends I25 {
+
+    }
+
+    protected interface I23 extends I26 {
+
+    }
+
+    protected interface I24 extends I26 {
+
+    }
+
+    protected interface I15 extends I21, I22 {
+
+    }
+
+    protected interface I16 extends I23, I24 {
+
+    }
+
+    protected interface I11 extends I15 {
+
+    }
+
+    protected interface I12 extends I15 {
+
+    }
+
+    protected interface I13 extends I16 {
+
+    }
+
+    protected interface I14 extends I16 {
+
+    }
+
+    protected interface I5 extends I11, I12 {
+
+    }
+
+    protected interface I6 extends I13, I14 {
+
+    }
+
+    protected interface I1 extends I5 {
+
+    }
+
+    protected interface I2 extends I5 {
+
+    }
+
+    protected interface I3 extends I6 {
+
+    }
+
+    protected interface I4 extends I6 {
+
+    }
+
+    protected interface Deep1 extends I1, I2 {
+
+    }
+
+    protected interface Deep2 extends I3, I4 {
+
+    }
+
+    /**
+     * Joins the two stamps and also asserts that the meet operation is commutative.
+     */
+    protected static Stamp join(Stamp a, Stamp b) {
+        Stamp ab = a.join(b);
+        Stamp ba = b.join(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    /**
+     * Meets the two stamps and also asserts that the meet operation is commutative.
+     */
+    protected static Stamp meet(Stamp a, Stamp b) {
+        Stamp ab = a.meet(b);
+        Stamp ba = b.meet(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    protected TypeReference getType(Class<?> clazz) {
+        return TypeReference.createTrustedWithoutAssumptions(getMetaAccess().lookupJavaType(clazz));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java
new file mode 100644
index 0000000..d14725b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * A few tests of expected simplifications by
+ * {@link IfNode#simplify(org.graalvm.compiler.graph.spi.SimplifierTool)}.
+ */
+public class IfNodeCanonicalizationTest extends GraalCompilerTest {
+
+    static int value;
+
+    static final byte[] testValues = {-128, -1, 0, 1, 127};
+
+    @Test
+    public void test1() {
+        /*
+         * exercise conversion of x - y < 0 into x < y, both by checking expected graph shape and
+         * that the transformed code produces the right answer.
+         */
+        test("testSnippet1", SubNode.class, 0);
+        byte[] values = new byte[4];
+        for (byte a : testValues) {
+            values[0] = a;
+            for (byte b : testValues) {
+                values[1] = b;
+                for (byte c : testValues) {
+                    values[2] = c;
+                    for (byte d : testValues) {
+                        values[3] = d;
+                        value = 2;
+                        super.test("testSnippet1", values, true);
+                        super.test("testSnippet1", values, false);
+                    }
+                }
+            }
+        }
+    }
+
+    public int testSnippet1(byte[] values, boolean test) {
+        int v = values[0] - values[1];
+        if (test) {
+            v = values[2] - values[3];
+        }
+        if (v < 0) {
+            value = 1;
+        }
+        return value;
+    }
+
+    @Test
+    public void test2() {
+        test("testSnippet2", 1);
+    }
+
+    public boolean testSnippet2(int a, int[] limit) {
+        int l = limit.length;
+        if (!(a >= 0 && a < l)) {
+            value = a;
+            return true;
+        }
+        return false;
+    }
+
+    @Ignore("currently not working because swapped case isn't handled")
+    @Test
+    public void test3() {
+        test("testSnippet3", 1);
+    }
+
+    public boolean testSnippet3(int a, int[] limit) {
+        int l = limit.length;
+        if (a < l && a >= 0) {
+            value = 9;
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void test4() {
+        test("testSnippet4", 1);
+    }
+
+    public boolean testSnippet4(int a, int[] limit) {
+        int l = limit.length;
+        if (a < 0) {
+            GraalDirectives.deoptimize();
+        }
+        if (a >= l) {
+            GraalDirectives.deoptimize();
+        }
+        return true;
+    }
+
+    @Ignore("Reversed conditions aren't working with guards")
+    @Test
+    public void test5() {
+        test("testSnippet5", 1);
+    }
+
+    public boolean testSnippet5(int a, int[] limit) {
+        int l = limit.length;
+        if (a >= l) {
+            GraalDirectives.deoptimize();
+        }
+        if (a < 0) {
+            GraalDirectives.deoptimize();
+        }
+        return true;
+    }
+
+    public void test(String name, int logicCount) {
+        test(name, LogicNode.class, logicCount);
+    }
+
+    public void test(String name, Class<? extends Node> expectedClass, int expectedCount) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        graph.clearAllStateAfter();
+        canonicalizer.apply(graph, context);
+
+        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+        // new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        Assert.assertEquals(expectedCount, graph.getNodes().filter(expectedClass).count());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java
new file mode 100644
index 0000000..00cf3af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+/**
+ * This class tests that integer stamps are created correctly for constants.
+ */
+public class IntegerStampTest {
+
+    private StructuredGraph graph;
+
+    private static Stamp addIntStamp(Stamp a, Stamp b) {
+        return IntegerStamp.OPS.getAdd().foldStamp(a, b);
+    }
+
+    @Before
+    public void before() {
+        graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID);
+    }
+
+    @Test
+    public void testBooleanConstant() {
+        assertEquals(new IntegerStamp(32, 1, 1, 0x1, 0x1), ConstantNode.forBoolean(true, graph).stamp());
+        assertEquals(new IntegerStamp(32, 0, 0, 0x0, 0x0), ConstantNode.forBoolean(false, graph).stamp());
+    }
+
+    @Test
+    public void testByteConstant() {
+        assertEquals(new IntegerStamp(32, 0, 0, 0x0, 0x0), ConstantNode.forByte((byte) 0, graph).stamp());
+        assertEquals(new IntegerStamp(32, 16, 16, 0x10, 0x10), ConstantNode.forByte((byte) 16, graph).stamp());
+        assertEquals(new IntegerStamp(32, -16, -16, 0xfffffff0L, 0xfffffff0L), ConstantNode.forByte((byte) -16, graph).stamp());
+        assertEquals(new IntegerStamp(32, 127, 127, 0x7f, 0x7f), ConstantNode.forByte((byte) 127, graph).stamp());
+        assertEquals(new IntegerStamp(32, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forByte((byte) -128, graph).stamp());
+    }
+
+    @Test
+    public void testShortConstant() {
+        assertEquals(new IntegerStamp(32, 0, 0, 0x0, 0x0), ConstantNode.forShort((short) 0, graph).stamp());
+        assertEquals(new IntegerStamp(32, 128, 128, 0x80, 0x80), ConstantNode.forShort((short) 128, graph).stamp());
+        assertEquals(new IntegerStamp(32, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forShort((short) -128, graph).stamp());
+        assertEquals(new IntegerStamp(32, 32767, 32767, 0x7fff, 0x7fff), ConstantNode.forShort((short) 32767, graph).stamp());
+        assertEquals(new IntegerStamp(32, -32768, -32768, 0xffff8000L, 0xffff8000L), ConstantNode.forShort((short) -32768, graph).stamp());
+    }
+
+    @Test
+    public void testCharConstant() {
+        assertEquals(new IntegerStamp(32, 0, 0, 0x0, 0x0), ConstantNode.forChar((char) 0, graph).stamp());
+        assertEquals(new IntegerStamp(32, 'A', 'A', 'A', 'A'), ConstantNode.forChar('A', graph).stamp());
+        assertEquals(new IntegerStamp(32, 128, 128, 0x80, 0x80), ConstantNode.forChar((char) 128, graph).stamp());
+        assertEquals(new IntegerStamp(32, 65535, 65535, 0xffff, 0xffff), ConstantNode.forChar((char) 65535, graph).stamp());
+    }
+
+    @Test
+    public void testIntConstant() {
+        assertEquals(new IntegerStamp(32, 0, 0, 0x0, 0x0), ConstantNode.forInt(0, graph).stamp());
+        assertEquals(new IntegerStamp(32, 128, 128, 0x80, 0x80), ConstantNode.forInt(128, graph).stamp());
+        assertEquals(new IntegerStamp(32, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forInt(-128, graph).stamp());
+        assertEquals(new IntegerStamp(32, Integer.MAX_VALUE, Integer.MAX_VALUE, 0x7fffffff, 0x7fffffff), ConstantNode.forInt(Integer.MAX_VALUE, graph).stamp());
+        assertEquals(new IntegerStamp(32, Integer.MIN_VALUE, Integer.MIN_VALUE, 0x80000000L, 0x80000000L), ConstantNode.forInt(Integer.MIN_VALUE, graph).stamp());
+    }
+
+    @Test
+    public void testLongConstant() {
+        assertEquals(new IntegerStamp(64, 0, 0, 0x0, 0x0), ConstantNode.forLong(0, graph).stamp());
+        assertEquals(new IntegerStamp(64, 128, 128, 0x80, 0x80), ConstantNode.forLong(128, graph).stamp());
+        assertEquals(new IntegerStamp(64, -128, -128, 0xffffffffffffff80L, 0xffffffffffffff80L), ConstantNode.forLong(-128, graph).stamp());
+        assertEquals(new IntegerStamp(64, Long.MAX_VALUE, Long.MAX_VALUE, 0x7fffffffffffffffL, 0x7fffffffffffffffL), ConstantNode.forLong(Long.MAX_VALUE, graph).stamp());
+        assertEquals(new IntegerStamp(64, Long.MIN_VALUE, Long.MIN_VALUE, 0x8000000000000000L, 0x8000000000000000L), ConstantNode.forLong(Long.MIN_VALUE, graph).stamp());
+    }
+
+    @Test
+    public void testPositiveRanges() {
+        assertEquals(new IntegerStamp(32, 0, 0, 0, 0), StampFactory.forInteger(JavaKind.Int, 0, 0));
+        assertEquals(new IntegerStamp(32, 0, 1, 0, 1), StampFactory.forInteger(JavaKind.Int, 0, 1));
+        assertEquals(new IntegerStamp(32, 0, 0x123, 0, 0x1ff), StampFactory.forInteger(JavaKind.Int, 0, 0x123));
+        assertEquals(new IntegerStamp(32, 0x120, 0x123, 0x120, 0x123), StampFactory.forInteger(JavaKind.Int, 0x120, 0x123));
+        assertEquals(new IntegerStamp(32, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(JavaKind.Int, 10000, 15000));
+        assertEquals(new IntegerStamp(64, 0, 1, 0, 1), StampFactory.forInteger(JavaKind.Long, 0, 1));
+        assertEquals(new IntegerStamp(64, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(JavaKind.Long, 10000, 15000));
+        assertEquals(new IntegerStamp(64, 140000000000L, 150000000000L, 0x2000000000L, 0x23ffffffffL), StampFactory.forInteger(JavaKind.Long, 140000000000L, 150000000000L));
+    }
+
+    @Test
+    public void testNegativeRanges() {
+        assertEquals(new IntegerStamp(32, -2, -1, 0xfffffffeL, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -2, -1));
+        assertEquals(new IntegerStamp(32, -20, -10, 0xffffffe0L, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -20, -10));
+        assertEquals(new IntegerStamp(32, -10000, 0, 0, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -10000, 0));
+        assertEquals(new IntegerStamp(32, -10000, -1, 0xffffc000L, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -10000, -1));
+        assertEquals(new IntegerStamp(32, -10010, -10000, 0xffffd8e0L, 0xffffd8ffL), StampFactory.forInteger(JavaKind.Int, -10010, -10000));
+        assertEquals(new IntegerStamp(64, -2, -1, 0xfffffffffffffffeL, 0xffffffffffffffffL), StampFactory.forInteger(JavaKind.Long, -2, -1));
+        assertEquals(new IntegerStamp(64, -10010, -10000, 0xffffffffffffd8e0L, 0xffffffffffffd8ffL), StampFactory.forInteger(JavaKind.Long, -10010, -10000));
+        assertEquals(new IntegerStamp(64, -150000000000L, -140000000000L, 0xffffffdc00000000L, 0xffffffdfffffffffL), StampFactory.forInteger(JavaKind.Long, -150000000000L, -140000000000L));
+    }
+
+    @Test
+    public void testMixedRanges() {
+        assertEquals(new IntegerStamp(32, -1, 0, 0, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -1, 0));
+        assertEquals(new IntegerStamp(32, -10000, 1000, 0, 0xffffffffL), StampFactory.forInteger(JavaKind.Int, -10000, 1000));
+        assertEquals(new IntegerStamp(64, -10000, 1000, 0, 0xffffffffffffffffL), StampFactory.forInteger(JavaKind.Long, -10000, 1000));
+    }
+
+    private static Stamp narrowingKindConversion(IntegerStamp stamp, JavaKind kind) {
+        Stamp narrow = IntegerStamp.OPS.getNarrow().foldStamp(stamp.getBits(), kind.getBitCount(), stamp);
+        IntegerConvertOp<?> implicitExtend = kind.isUnsigned() ? IntegerStamp.OPS.getZeroExtend() : IntegerStamp.OPS.getSignExtend();
+        return implicitExtend.foldStamp(kind.getBitCount(), 32, narrow);
+    }
+
+    @Test
+    public void testNarrowingConversions() {
+        // byte cases
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 0), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 0, 0), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 10), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 0, 10), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 10, 20), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 10, 20), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, -10, 0), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -10, 0), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, -20, -10), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -20, -10), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 100, 200), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -100, 200), JavaKind.Byte));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -200, -100), JavaKind.Byte));
+        // char cases
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 10), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 0, 10), JavaKind.Char));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 10, 20), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 10, 20), JavaKind.Char));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Character.MIN_VALUE, Character.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 20000, 80000), JavaKind.Char));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Character.MIN_VALUE, Character.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -10000, 40000), JavaKind.Char));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Character.MIN_VALUE, Character.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -40000, -10000), JavaKind.Char));
+        // short cases
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 10), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 0, 10), JavaKind.Short));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 10, 20), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 10, 20), JavaKind.Short));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Short.MIN_VALUE, Short.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, 20000, 40000), JavaKind.Short));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Short.MIN_VALUE, Short.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -10000, 40000), JavaKind.Short));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Short.MIN_VALUE, Short.MAX_VALUE), narrowingKindConversion(StampFactory.forInteger(JavaKind.Int, -40000, -10000), JavaKind.Short));
+        // int cases
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 10), narrowingKindConversion(StampFactory.forInteger(JavaKind.Long, 0, 10), JavaKind.Int));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 10, 20), narrowingKindConversion(StampFactory.forInteger(JavaKind.Long, 10, 20), JavaKind.Int));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        narrowingKindConversion(StampFactory.forInteger(JavaKind.Long, 20000000000L, 40000000000L), JavaKind.Int));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        narrowingKindConversion(StampFactory.forInteger(JavaKind.Long, -10000000000L, 40000000000L), JavaKind.Int));
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        narrowingKindConversion(StampFactory.forInteger(JavaKind.Long, -40000000000L, -10000000000L), JavaKind.Int));
+    }
+
+    @Test
+    public void testXor() {
+        assertEquals(new IntegerStamp(32, 0, 0xff, 0, 0xff), IntegerStamp.OPS.getXor().foldStamp(new IntegerStamp(32, 0, 0, 0, 0), new IntegerStamp(32, 0, 0xff, 0, 0xff)));
+        assertEquals(new IntegerStamp(32, 0x10, 0x1f, 0x10, 0x1f), IntegerStamp.OPS.getXor().foldStamp(new IntegerStamp(32, 0, 0, 0, 0), new IntegerStamp(32, 0x10, 0x1f, 0x10, 0x1f)));
+        assertEquals(new IntegerStamp(32, 0x0, 0xf, 0x0, 0xf), IntegerStamp.OPS.getXor().foldStamp(new IntegerStamp(32, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(32, 0x10, 0x1f, 0x10, 0x1f)));
+        assertEquals(new IntegerStamp(32, 0x10, 0x1f, 0x10, 0x1f), IntegerStamp.OPS.getXor().foldStamp(new IntegerStamp(32, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(32, 0x0, 0xf, 0x0, 0xf)));
+    }
+
+    @Test
+    public void testNot() {
+        assertEquals(new IntegerStamp(32, -11, -1, 0xffff_fff0L, 0xffff_ffffL), IntegerStamp.OPS.getNot().foldStamp(new IntegerStamp(32, 0, 10, 0, 0xf)));
+    }
+
+    @Test
+    public void testAddIntSimple() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 30, 0, 31), addIntStamp(StampFactory.forInteger(JavaKind.Int, 0, 10), StampFactory.forInteger(JavaKind.Int, 0, 20)));
+    }
+
+    @Test
+    public void testAddNegativeOverFlowInt1() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0xffff_ffffL),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, 0), StampFactory.forInteger(JavaKind.Int, -1, 0)));
+    }
+
+    @Test
+    public void testAddNegativeOverFlowInt2() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MAX_VALUE - 2, Integer.MAX_VALUE, 0x7fff_fffcL, 0x7fff_ffffL),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MIN_VALUE + 1), StampFactory.forInteger(JavaKind.Int, -3, -2)));
+    }
+
+    @Test
+    public void testAddPositiveOverFlowInt1() {
+        assertEquals(StampFactory.forKind(JavaKind.Int), addIntStamp(StampFactory.forInteger(JavaKind.Int, 0, 1), StampFactory.forInteger(JavaKind.Int, 0, Integer.MAX_VALUE)));
+    }
+
+    @Test
+    public void testAddPositiveOverFlowInt2() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MIN_VALUE + 2),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Int, Integer.MAX_VALUE - 1, Integer.MAX_VALUE), StampFactory.forInteger(JavaKind.Int, 2, 3)));
+    }
+
+    @Test
+    public void testAddOverFlowsInt() {
+        assertEquals(StampFactory.forKind(JavaKind.Int), addIntStamp(StampFactory.forInteger(JavaKind.Int, -1, 1), StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE)));
+    }
+
+    @Test
+    public void testAddLongSimple() {
+        assertEquals(StampFactory.forInteger(JavaKind.Long, 0, 30, 0, 31), addIntStamp(StampFactory.forInteger(JavaKind.Long, 0, 10), StampFactory.forInteger(JavaKind.Long, 0, 20)));
+    }
+
+    @Test
+    public void testAddNegativOverFlowLong1() {
+        assertEquals(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MAX_VALUE, 0, 0xffff_ffff_ffff_ffffL),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MIN_VALUE + 1), StampFactory.forInteger(JavaKind.Long, Integer.MIN_VALUE, Integer.MAX_VALUE)));
+    }
+
+    @Test
+    public void testAddNegativeOverFlowLong2() {
+        assertEquals(StampFactory.forInteger(JavaKind.Long, Long.MAX_VALUE - 2, Long.MAX_VALUE),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MIN_VALUE + 1), StampFactory.forInteger(JavaKind.Long, -3, -2)));
+    }
+
+    @Test
+    public void testAddPositiveOverFlowLong1() {
+        assertEquals(StampFactory.forKind(JavaKind.Long), addIntStamp(StampFactory.forInteger(JavaKind.Long, 0, 1), StampFactory.forInteger(JavaKind.Long, 0, Long.MAX_VALUE)));
+    }
+
+    @Test
+    public void testAddPositiveOverFlowLong2() {
+        assertEquals(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MIN_VALUE + 2),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Long, Long.MAX_VALUE - 1, Long.MAX_VALUE), StampFactory.forInteger(JavaKind.Long, 2, 3)));
+    }
+
+    @Test
+    public void testAddOverFlowsLong() {
+        assertEquals(StampFactory.forKind(JavaKind.Long), addIntStamp(StampFactory.forInteger(JavaKind.Long, -1, 1), StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MAX_VALUE)));
+    }
+
+    @Test
+    public void testAdd1() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE + 1, 31 + (Integer.MIN_VALUE + 1)),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Int, 0, 31), StampFactory.forInteger(JavaKind.Int, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 1)));
+    }
+
+    @Test
+    public void testAdd2() {
+        assertEquals(StampFactory.forInteger(JavaKind.Int, 0x8000_007e, 0x8000_007f, 0x8000_007eL, 0x8000_007fL),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Int, 0x7fff_fffe, 0x7fff_ffff, 0x7fff_fffeL, 0x7ffff_fffL), StampFactory.forInteger(JavaKind.Int, 128, 128)));
+    }
+
+    @Test
+    public void testAdd3() {
+        assertEquals(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MAX_VALUE - 1, 0, 0xffff_ffff_ffff_fffeL),
+                        addIntStamp(StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MAX_VALUE - 1, 0, 0xffff_ffff_ffff_fffeL),
+                                        StampFactory.forInteger(JavaKind.Long, Long.MIN_VALUE, Long.MAX_VALUE - 1, 0, 0xffff_ffff_ffff_fffeL)));
+
+    }
+
+    @Test
+    public void testAnd() {
+        assertEquals(new IntegerStamp(32, Integer.MIN_VALUE, 0x40000000L, 0, 0xc0000000L),
+                        IntegerStamp.OPS.getAnd().foldStamp(StampFactory.forKind(JavaKind.Int), StampFactory.forConstant(JavaConstant.forInt(0xc0000000))));
+    }
+
+    private static void testSignExtendShort(long lower, long upper) {
+        Stamp shortStamp = StampFactory.forInteger(16, lower, upper);
+        Stamp intStamp = IntegerStamp.OPS.getSignExtend().foldStamp(16, 32, shortStamp);
+        assertEquals(StampFactory.forInteger(32, lower, upper), intStamp);
+    }
+
+    @Test
+    public void testSignExtend() {
+        testSignExtendShort(5, 7);
+        testSignExtendShort(0, 42);
+        testSignExtendShort(-42, -1);
+        testSignExtendShort(-42, 0);
+        testSignExtendShort(-1, 1);
+        testSignExtendShort(Short.MIN_VALUE, Short.MAX_VALUE);
+    }
+
+    private static void testZeroExtendShort(long lower, long upper, long newLower, long newUpper) {
+        Stamp shortStamp = StampFactory.forInteger(16, lower, upper);
+        Stamp intStamp = IntegerStamp.OPS.getZeroExtend().foldStamp(16, 32, shortStamp);
+        assertEquals(StampFactory.forInteger(32, newLower, newUpper), intStamp);
+    }
+
+    @Test
+    public void testZeroExtend() {
+        testZeroExtendShort(5, 7, 5, 7);
+        testZeroExtendShort(0, 42, 0, 42);
+        testZeroExtendShort(-42, -1, 0xFFFF - 41, 0xFFFF);
+        testZeroExtendShort(-42, 0, 0, 0xFFFF);
+        testZeroExtendShort(-1, 1, 0, 0xFFFF);
+        testZeroExtendShort(Short.MIN_VALUE, Short.MAX_VALUE, 0, 0xFFFF);
+    }
+
+    @Test
+    public void testIllegalJoin() {
+        assertFalse(new IntegerStamp(32, 0, 0xff00, 0, 0xff00).join(new IntegerStamp(32, 1, 0xff, 0x00, 0xff)).hasValues());
+        assertFalse(new IntegerStamp(32, 0x100, 0xff00, 0, 0xff00).join(new IntegerStamp(32, 0, 0xff, 0x00, 0xff)).hasValues());
+    }
+
+    @Test
+    public void testShiftLeft() {
+        ShiftOp<?> shl = IntegerStamp.OPS.getShl();
+        assertEquals(new IntegerStamp(32, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
+        assertEquals(new IntegerStamp(32, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        assertEquals(new IntegerStamp(32, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(32, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+
+        assertEquals(new IntegerStamp(64, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
+        assertEquals(new IntegerStamp(64, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        assertEquals(new IntegerStamp(64, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(64, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopLivenessTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopLivenessTest.java
new file mode 100644
index 0000000..6332623
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopLivenessTest.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.java.LargeLocalLiveness;
+import org.graalvm.compiler.java.SmallLocalLiveness;
+
+public class LoopLivenessTest extends GraalCompilerTest {
+
+    /**
+     * Exercise {@link SmallLocalLiveness} with 64 loops.
+     */
+    public static void manyLoopsSmall() {
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+    }
+
+    /**
+     * Exercise {@link LargeLocalLiveness} with 64 loops.
+     */
+    @SuppressWarnings("unused")
+    public static void manyLoopsLarge() {
+        int i0;
+        int i1;
+        int i2;
+        int i3;
+        int i4;
+        int i5;
+        int i6;
+        int i7;
+        int i8;
+        int i9;
+        int i10;
+        int i11;
+        int i12;
+        int i13;
+        int i14;
+        int i15;
+        int i16;
+        int i17;
+        int i18;
+        int i19;
+        int i20;
+        int i21;
+        int i22;
+        int i23;
+        int i24;
+        int i25;
+        int i26;
+        int i27;
+        int i28;
+        int i29;
+        int i30;
+        int i31;
+        int i32;
+        int i33;
+        int i34;
+        int i35;
+        int i36;
+        int i37;
+        int i38;
+        int i39;
+        int i40;
+        int i41;
+        int i42;
+        int i43;
+        int i44;
+        int i45;
+        int i46;
+        int i47;
+        int i48;
+        int i49;
+        int i50;
+        int i51;
+        int i52;
+        int i53;
+        int i54;
+        int i55;
+        int i56;
+        int i57;
+        int i58;
+        int i59;
+        int i60;
+        int i61;
+        int i62;
+        int i63;
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+        for (int i = 0; i < 10; i++) {
+            for (int j = 0; j < 10; j++) {
+            }
+        }
+    }
+
+    @Test
+    public void testManyLoopsSmall() {
+        test("manyLoopsSmall");
+    }
+
+    @Test
+    public void testManyLoopsLarge() {
+        test("manyLoopsLarge");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java
new file mode 100644
index 0000000..d8e3d16
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.iterators.NodePredicate;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class LoopPhiCanonicalizerTest extends GraalCompilerTest {
+
+    private static int[] array = new int[1000];
+
+    @BeforeClass
+    public static void before() {
+        for (int i = 0; i < array.length; i++) {
+            array[i] = i;
+        }
+    }
+
+    public static long loopSnippet() {
+        int a = 0;
+        int b = 0;
+        int c = 0;
+        int d = 0;
+
+        long sum = 0;
+        while (d < 1000) {
+            sum += array[a++] + array[b++] + array[c++] + array[d++];
+        }
+        return sum;
+    }
+
+    @Test
+    public void test() {
+        StructuredGraph graph = parseEager("loopSnippet", AllowAssumptions.YES);
+        NodePredicate loopPhis = node -> node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode;
+
+        PhaseContext context = new PhaseContext(getProviders());
+        Assert.assertEquals(5, graph.getNodes().filter(loopPhis).count());
+        new CanonicalizerPhase().apply(graph, context);
+        Assert.assertEquals(2, graph.getNodes().filter(loopPhis).count());
+
+        test("loopSnippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java
new file mode 100644
index 0000000..652fc8b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.junit.Assert.assertEquals;
+import jdk.vm.ci.meta.JavaConstant;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+
+/**
+ * This class tests that the canonicalization for constant negate nodes cover all cases.
+ */
+public class NegateNodeCanonicalizationTest {
+
+    private StructuredGraph graph;
+
+    @Before
+    public void before() {
+        graph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID);
+    }
+
+    @Test
+    public void testByte() {
+        byte[] a = new byte[]{Byte.MIN_VALUE, Byte.MIN_VALUE + 1, -1, 0, 1, Byte.MAX_VALUE - 1, Byte.MAX_VALUE};
+        for (byte i : a) {
+            ConstantNode node = ConstantNode.forByte(i, graph);
+            JavaConstant expected = JavaConstant.forInt(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testChar() {
+        char[] a = new char[]{Character.MIN_VALUE, Character.MIN_VALUE + 1, 0, 1, Character.MAX_VALUE - 1, Character.MAX_VALUE};
+        for (char i : a) {
+            ConstantNode node = ConstantNode.forChar(i, graph);
+            JavaConstant expected = JavaConstant.forInt(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testShort() {
+        short[] a = new short[]{Short.MIN_VALUE, Short.MIN_VALUE + 1, -1, 0, 1, Short.MAX_VALUE - 1, Short.MAX_VALUE};
+        for (short i : a) {
+            ConstantNode node = ConstantNode.forShort(i, graph);
+            JavaConstant expected = JavaConstant.forInt(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testInt() {
+        int[] a = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1, 0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE};
+        for (int i : a) {
+            ConstantNode node = ConstantNode.forInt(i, graph);
+            JavaConstant expected = JavaConstant.forInt(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testLong() {
+        long[] a = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1, 0, 1, Long.MAX_VALUE - 1, Long.MAX_VALUE};
+        for (long i : a) {
+            ConstantNode node = ConstantNode.forLong(i, graph);
+            JavaConstant expected = JavaConstant.forLong(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testFloat() {
+        float[] a = new float[]{Float.MIN_VALUE, Float.MIN_VALUE + 1, -1, 0, 1, Float.MAX_VALUE - 1, Float.MAX_VALUE};
+        for (float i : a) {
+            ConstantNode node = ConstantNode.forFloat(i, graph);
+            JavaConstant expected = JavaConstant.forFloat(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+    @Test
+    public void testDouble() {
+        double[] a = new double[]{Double.MIN_VALUE, Double.MIN_VALUE + 1, -1, 0, 1, Double.MAX_VALUE - 1, Double.MAX_VALUE};
+        for (double i : a) {
+            ConstantNode node = ConstantNode.forDouble(i, graph);
+            JavaConstant expected = JavaConstant.forDouble(-i);
+            assertEquals(expected, ArithmeticOpTable.forStamp(node.stamp()).getNeg().foldConstant(node.asConstant()));
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampJoinTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampJoinTest.java
new file mode 100644
index 0000000..1f09bdd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampJoinTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+public class ObjectStampJoinTest extends AbstractObjectStampTest {
+
+    // class A
+    // class B extends A
+    // class C extends B implements I
+    // class D extends A
+    // abstract class E extends A
+    // interface I
+
+    @Test
+    public void testJoin0() {
+        Stamp a = StampFactory.object(getType(A.class));
+        Stamp b = StampFactory.object(getType(B.class));
+        Assert.assertEquals(b, join(a, b));
+    }
+
+    @Test
+    public void testJoin1() {
+        Stamp aNonNull = StampFactory.objectNonNull(getType(A.class));
+        Stamp b = StampFactory.object(getType(B.class));
+        Stamp bNonNull = StampFactory.objectNonNull(getType(B.class));
+        Assert.assertEquals(bNonNull, join(aNonNull, b));
+    }
+
+    @Test
+    public void testJoin2() {
+        Stamp aExact = StampFactory.objectNonNull(getType(A.class).asExactReference());
+        Stamp b = StampFactory.object(getType(B.class));
+        Assert.assertEquals(StampFactory.empty(JavaKind.Object), join(aExact, b));
+    }
+
+    @Test
+    public void testJoin3() {
+        Stamp d = StampFactory.object(getType(D.class));
+        Stamp c = StampFactory.object(getType(C.class));
+        Assert.assertTrue(StampTool.isPointerAlwaysNull(join(c, d)));
+    }
+
+    @Test
+    public void testJoin4() {
+        Stamp dExactNonNull = StampFactory.objectNonNull(getType(D.class));
+        Stamp c = StampFactory.object(getType(C.class));
+        Assert.assertEquals(StampFactory.empty(JavaKind.Object), join(c, dExactNonNull));
+    }
+
+    @Test
+    public void testJoin5() {
+        Stamp dExact = StampFactory.object(getType(D.class).asExactReference());
+        Stamp c = StampFactory.object(getType(C.class));
+        Stamp join = join(c, dExact);
+        Assert.assertTrue(StampTool.isPointerAlwaysNull(join));
+        Assert.assertNull(StampTool.typeReferenceOrNull(join));
+        Assert.assertFalse(StampTool.isExactType(join));
+    }
+
+    @Test
+    public void testJoin6() {
+        Stamp dExactNonNull = StampFactory.objectNonNull(getType(D.class).asExactReference());
+        Stamp alwaysNull = StampFactory.alwaysNull();
+        Stamp join = join(alwaysNull, dExactNonNull);
+        Assert.assertFalse(join.hasValues());
+        Assert.assertFalse(StampTool.isPointerAlwaysNull(join));
+    }
+
+    @Test
+    public void testJoin7() {
+        Stamp aExact = StampFactory.object(getType(A.class).asExactReference());
+        Stamp e = StampFactory.object(getType(E.class));
+        Stamp join = join(aExact, e);
+        Assert.assertTrue(StampTool.isPointerAlwaysNull(join));
+        Assert.assertNull(StampTool.typeReferenceOrNull(join));
+        Assert.assertFalse(StampTool.isExactType(join));
+    }
+
+    @Test
+    public void testJoin8() {
+        Stamp bExact = StampFactory.objectNonNull(getType(B.class).asExactReference());
+        Stamp dExact = StampFactory.object(getType(D.class).asExactReference());
+        Stamp join = join(bExact, dExact);
+        Assert.assertFalse(join.hasValues());
+    }
+
+    @Test
+    public void testJoin9() {
+        Stamp bExact = StampFactory.object(getType(B.class).asExactReference());
+        Stamp dExact = StampFactory.object(getType(D.class).asExactReference());
+        Stamp join = join(bExact, dExact);
+        Assert.assertTrue(StampTool.isPointerAlwaysNull(join));
+        Assert.assertNull(StampTool.typeReferenceOrNull(join));
+        Assert.assertNull(StampTool.typeReferenceOrNull(join));
+    }
+
+    @Test
+    public void testJoinInterfaceSimple() {
+        // Tests joining of interface
+        testJoinInterface(A.class, B.class, I.class);
+    }
+
+    @Test
+    public void testJoinInterfaceArray() {
+        // Tests joining of arrays interface
+        testJoinInterface(A[].class, B[].class, I[].class);
+    }
+
+    @Test
+    public void testJoinInterfaceMultiArray() {
+        // Tests joining of multidimensional arrays of interface
+        testJoinInterface(A[][].class, B[][].class, I[][].class);
+    }
+
+    private void testJoinInterface(Class<?> typeA, Class<?> typeB, Class<?> typeI) {
+        testJoinInterface0(typeA, typeI);
+        testJoinInterface1(typeA, typeI);
+        testJoinInterface2(typeB, typeI);
+        testJoinInterface3(typeB, typeI);
+    }
+
+    private void testJoinInterface0(Class<?> typeA, Class<?> typeI) {
+        Stamp a = StampFactory.object(getType(typeA));
+        Stamp i = StampFactory.object(getType(typeI));
+        Assert.assertNotSame(StampFactory.empty(JavaKind.Object), join(a, i));
+    }
+
+    private void testJoinInterface1(Class<?> typeA, Class<?> typeI) {
+        Stamp aNonNull = StampFactory.objectNonNull(getType(typeA));
+        Stamp i = StampFactory.object(getType(typeI));
+        Stamp join = join(aNonNull, i);
+        Assert.assertTrue(join instanceof ObjectStamp);
+        Assert.assertTrue(((ObjectStamp) join).nonNull());
+    }
+
+    private void testJoinInterface2(Class<?> typeB, Class<?> typeI) {
+        Stamp bExact = StampFactory.objectNonNull(getType(typeB).asExactReference());
+        Stamp i = StampFactory.object(getType(typeI));
+        Stamp join = join(i, bExact);
+        Assert.assertEquals(StampFactory.empty(JavaKind.Object), join);
+    }
+
+    private void testJoinInterface3(Class<?> typeB, Class<?> typeI) {
+        Stamp bExact = StampFactory.objectNonNull(getType(typeB).asExactReference());
+        // Create non-trusted reference.
+        Stamp i = StampFactory.object(TypeReference.createWithoutAssumptions(getType(typeI).getType()));
+        Stamp join = join(i, bExact);
+        Assert.assertEquals(bExact, join);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampMeetTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampMeetTest.java
new file mode 100644
index 0000000..0bb70bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampMeetTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+
+public class ObjectStampMeetTest extends AbstractObjectStampTest {
+
+    @Test
+    public void testMeet0() {
+        check(A.class, B.class, A.class);
+    }
+
+    @Test
+    public void testMeet1() {
+        Stamp a = StampFactory.object(getType(A.class));
+        Stamp aNonNull = StampFactory.objectNonNull(getType(A.class));
+        Stamp b = StampFactory.object(getType(B.class));
+        Stamp bNonNull = StampFactory.objectNonNull(getType(B.class));
+        Assert.assertEquals(a, meet(aNonNull, b));
+        Assert.assertEquals(aNonNull, meet(aNonNull, bNonNull));
+    }
+
+    @Test
+    public void testMeet2() {
+        Stamp a = StampFactory.object(getType(A.class));
+        Stamp aExact = StampFactory.objectNonNull(getType(A.class).asExactReference());
+        Stamp b = StampFactory.object(getType(B.class));
+        Assert.assertEquals(a, meet(aExact, b));
+    }
+
+    @Test
+    public void testMeet3() {
+        check(C.class, D.class, A.class);
+    }
+
+    @Test
+    public void testMeet4() {
+        Stamp dExactNonNull = StampFactory.objectNonNull(getType(D.class).asExactReference());
+        Stamp cExactNonNull = StampFactory.objectNonNull(getType(C.class).asExactReference());
+        Stamp aNonNull = StampFactory.objectNonNull(getType(A.class));
+        Assert.assertEquals(aNonNull, meet(cExactNonNull, dExactNonNull));
+    }
+
+    @Test
+    public void testMeet5() {
+        Stamp dExact = StampFactory.object(getType(D.class).asExactReference());
+        Stamp c = StampFactory.object(getType(C.class));
+        Stamp a = StampFactory.object(getType(A.class));
+        Assert.assertEquals(a, meet(dExact, c));
+    }
+
+    @Test
+    public void testMeet6() {
+        Stamp dExactNonNull = StampFactory.objectNonNull(getType(D.class).asExactReference());
+        Stamp alwaysNull = StampFactory.alwaysNull();
+        Stamp dExact = StampFactory.object(getType(D.class).asExactReference());
+        Assert.assertEquals(dExact, meet(dExactNonNull, alwaysNull));
+    }
+
+    @Test
+    public void testMeet7() {
+        Stamp aExact = StampFactory.object(getType(A.class).asExactReference());
+        Stamp e = StampFactory.object(getType(E.class));
+        Stamp a = StampFactory.object(getType(A.class));
+        Assert.assertEquals(a, meet(aExact, e));
+    }
+
+    @Test
+    public void testMeet8() {
+        check(A.class, A.class, A.class);
+    }
+
+    @Test
+    public void testMeet9() {
+        Stamp base1 = StampFactory.object(getType(Base1.class));
+        Stamp ord1 = StampFactory.object(getType(ImplOrder1.class));
+        Stamp ord2 = StampFactory.object(getType(ImplOrder2.class));
+        Assert.assertEquals(base1, meet(ord1, ord2));
+    }
+
+    @Test
+    public void testMeet10() {
+        Stamp base1 = StampFactory.object(getType(Object.class));
+        Stamp ord1 = StampFactory.object(getType(Deep1.class));
+        Stamp ord2 = StampFactory.object(getType(Deep2.class));
+        Assert.assertEquals(base1, meet(ord1, ord2));
+    }
+
+    @Test
+    public void testMeetInterface0() {
+        check(C.class, I.class, I.class);
+    }
+
+    @Test
+    public void testMeetInterface1() {
+        check(I.class, SubI1.class, I.class);
+    }
+
+    @Test
+    public void testMeetInterface2() {
+        check(SubI1.class, SubI2.class, I.class);
+    }
+
+    @Test
+    public void testMeetInterface3() {
+        check(SubI4.class, SubI5.class, SubI3.class);
+    }
+
+    @Test
+    public void testMeetInterface4() {
+        check(SubI4.class, SubI6.class, Object.class);
+    }
+
+    private void check(Class<?> a, Class<?> b, Class<?> result) {
+        Stamp aStamp = StampFactory.object(getType(a));
+        Stamp bStamp = StampFactory.object(getType(b));
+        ObjectStamp resultStamp = StampFactory.object(getType(result));
+        Assert.assertEquals(resultStamp, meet(aStamp, bStamp));
+    }
+
+    @Test
+    public void testMeetIllegal1() {
+        for (Class<?> clazz : new Class<?>[]{A.class, B.class, C.class, D.class, E.class, I.class, Object.class}) {
+            TypeReference type = getType(clazz);
+            for (Stamp test : new Stamp[]{StampFactory.object(type), StampFactory.objectNonNull(type), StampFactory.object(type.asExactReference()),
+                            StampFactory.objectNonNull(type.asExactReference())}) {
+                if (type.getType().isConcrete() || !((ObjectStamp) test).isExactType()) {
+                    Assert.assertEquals("meeting empty and " + test, test, meet(StampFactory.empty(JavaKind.Object), test));
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampTest.java
new file mode 100644
index 0000000..31f893d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ObjectStampTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+
+public class ObjectStampTest extends AbstractObjectStampTest {
+    @Test
+    public void testInterfaceTrust0() {
+        Stamp notTrusted = StampFactory.object(TypeReference.createWithoutAssumptions(getMetaAccess().lookupJavaType(I.class)));
+        Assert.assertEquals(StampFactory.object(), notTrusted);
+    }
+
+    private interface TrustedI {
+
+    }
+
+    @Test
+    public void testInterfaceTrust1() {
+        Stamp trusted = StampFactory.object(getType(TrustedI.class));
+        Assert.assertNotEquals(StampFactory.object(), trusted);
+        Assert.assertTrue("Should be an AbstractObjectStamp", trusted instanceof AbstractObjectStamp);
+        AbstractObjectStamp trustedObjectStamp = (AbstractObjectStamp) trusted;
+        Assert.assertNotNull(trustedObjectStamp.type());
+        Assert.assertTrue("Should be an interface", trustedObjectStamp.type().isInterface());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampDoubleToLongTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampDoubleToLongTest.java
new file mode 100644
index 0000000..f2575f2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampDoubleToLongTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@RunWith(Parameterized.class)
+public class ReinterpretStampDoubleToLongTest extends ReinterpretStampTest {
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        List<Object[]> ret = new ArrayList<>();
+
+        for (long x : interestingLongs) {
+            double lowerBound = Double.longBitsToDouble(x);
+            if (Double.isNaN(lowerBound)) {
+                continue;
+            }
+
+            for (long y : interestingLongs) {
+                double upperBound = Double.longBitsToDouble(y);
+                if (Double.isNaN(upperBound)) {
+                    continue;
+                }
+
+                if (Double.compare(lowerBound, upperBound) <= 0) {
+                    ret.add(new Object[]{new FloatStamp(Double.SIZE, lowerBound, upperBound, true)});
+                    ret.add(new Object[]{new FloatStamp(Double.SIZE, lowerBound, upperBound, false)});
+                }
+            }
+        }
+
+        ret.add(new Object[]{new FloatStamp(Double.SIZE, Double.NaN, Double.NaN, false)});
+
+        return ret;
+    }
+
+    @Parameter(value = 0) public FloatStamp inputStamp;
+
+    @Test
+    public void run() {
+        ParameterNode param = new ParameterNode(0, StampPair.createSingle(inputStamp));
+        ReinterpretNode reinterpret = new ReinterpretNode(JavaKind.Long, param);
+
+        IntegerStamp resultStamp = (IntegerStamp) reinterpret.stamp();
+        Assert.assertEquals(Long.SIZE, resultStamp.getBits());
+
+        for (long result : interestingLongs) {
+            double input = Double.longBitsToDouble(result);
+
+            if (inputStamp.contains(input) && !resultStamp.contains(result)) {
+                Assert.fail(String.format("value %f (0x%x) is in input stamp, but not in result stamp (%s)", input, result, resultStamp));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampFloatToIntTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampFloatToIntTest.java
new file mode 100644
index 0000000..b24285d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampFloatToIntTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@RunWith(Parameterized.class)
+public class ReinterpretStampFloatToIntTest extends ReinterpretStampTest {
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        List<Object[]> ret = new ArrayList<>();
+
+        for (int x : interestingInts) {
+            float lowerBound = Float.intBitsToFloat(x);
+            if (Float.isNaN(lowerBound)) {
+                continue;
+            }
+
+            for (int y : interestingInts) {
+                float upperBound = Float.intBitsToFloat(y);
+                if (Float.isNaN(upperBound)) {
+                    continue;
+                }
+
+                if (Float.compare(lowerBound, upperBound) <= 0) {
+                    ret.add(new Object[]{new FloatStamp(Float.SIZE, lowerBound, upperBound, true)});
+                    ret.add(new Object[]{new FloatStamp(Float.SIZE, lowerBound, upperBound, false)});
+                }
+            }
+        }
+
+        ret.add(new Object[]{new FloatStamp(Float.SIZE, Float.NaN, Float.NaN, false)});
+
+        return ret;
+    }
+
+    @Parameter(value = 0) public FloatStamp inputStamp;
+
+    @Test
+    public void run() {
+        ParameterNode param = new ParameterNode(0, StampPair.createSingle(inputStamp));
+        ReinterpretNode reinterpret = new ReinterpretNode(JavaKind.Int, param);
+        reinterpret.inferStamp();
+
+        IntegerStamp resultStamp = (IntegerStamp) reinterpret.stamp();
+        Assert.assertEquals(Integer.SIZE, resultStamp.getBits());
+
+        for (int result : interestingInts) {
+            float input = Float.intBitsToFloat(result);
+
+            if (inputStamp.contains(input) && !resultStamp.contains(result)) {
+                Assert.fail(String.format("value %f (0x%x) is in input stamp, but not in result stamp (%s)", input, result, resultStamp));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampIntToFloatTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampIntToFloatTest.java
new file mode 100644
index 0000000..b4fd7b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampIntToFloatTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@RunWith(Parameterized.class)
+public class ReinterpretStampIntToFloatTest extends ReinterpretStampTest {
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        List<Object[]> ret = new ArrayList<>();
+
+        for (int lowerBound : interestingInts) {
+            for (int upperBound : interestingInts) {
+                if (lowerBound <= upperBound) {
+                    ret.add(new Object[]{StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound)});
+                }
+                if ((lowerBound & ~upperBound) == 0) {
+                    ret.add(new Object[]{IntegerStamp.stampForMask(Integer.SIZE, lowerBound & 0xFFFF_FFFFL, upperBound & 0xFFFF_FFFFL)});
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    @Parameter(value = 0) public IntegerStamp inputStamp;
+
+    @Test
+    public void run() {
+        ParameterNode param = new ParameterNode(0, StampPair.createSingle(inputStamp));
+        ReinterpretNode reinterpret = new ReinterpretNode(JavaKind.Float, param);
+        reinterpret.inferStamp();
+
+        FloatStamp resultStamp = (FloatStamp) reinterpret.stamp();
+        Assert.assertEquals(Float.SIZE, resultStamp.getBits());
+
+        for (int input : interestingInts) {
+            float result = Float.intBitsToFloat(input);
+
+            if (inputStamp.contains(input) && !resultStamp.contains(result)) {
+                Assert.fail(String.format("value 0x%x (%f) is in input stamp, but not in result stamp (%s)", input, result, resultStamp));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampLongToDoubleTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampLongToDoubleTest.java
new file mode 100644
index 0000000..08642f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampLongToDoubleTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@RunWith(Parameterized.class)
+public class ReinterpretStampLongToDoubleTest extends ReinterpretStampTest {
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        List<Object[]> ret = new ArrayList<>();
+
+        for (long lowerBound : interestingLongs) {
+            for (long upperBound : interestingLongs) {
+                if (lowerBound <= upperBound) {
+                    ret.add(new Object[]{StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound)});
+                }
+                if ((lowerBound & ~upperBound) == 0) {
+                    ret.add(new Object[]{IntegerStamp.stampForMask(Long.SIZE, lowerBound, upperBound)});
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    @Parameter(value = 0) public IntegerStamp inputStamp;
+
+    @Test
+    public void run() {
+        ParameterNode param = new ParameterNode(0, StampPair.createSingle(inputStamp));
+        ReinterpretNode reinterpret = new ReinterpretNode(JavaKind.Double, param);
+        reinterpret.inferStamp();
+
+        FloatStamp resultStamp = (FloatStamp) reinterpret.stamp();
+        Assert.assertEquals(Double.SIZE, resultStamp.getBits());
+
+        for (long input : interestingLongs) {
+            double result = Double.longBitsToDouble(input);
+
+            if (inputStamp.contains(input) && !resultStamp.contains(result)) {
+                Assert.fail(String.format("value 0x%x (%f) is in input stamp, but not in result stamp (%s)", input, result, resultStamp));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampTest.java
new file mode 100644
index 0000000..2fc40d4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ReinterpretStampTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+
+/**
+ * Unit tests for the {@link ReinterpretNode#inferStamp} method.
+ */
+public class ReinterpretStampTest {
+
+    protected static final long[] interestingLongs = {
+                    // @formatter:off
+                    Long.MIN_VALUE,                                        // -0.0d
+                    Long.MIN_VALUE + 1,                                    // largest negative number
+                    Double.doubleToLongBits(-42.0),                        // random negative number
+                    Double.doubleToLongBits(Double.NEGATIVE_INFINITY) - 1, // smallest negative number
+                    Double.doubleToLongBits(Double.NEGATIVE_INFINITY),     // -Inf
+                    Double.doubleToLongBits(Double.NEGATIVE_INFINITY) + 1, // smallest negative NaN
+                    -42,                                                   // random negative NaN
+                    -1,                                                    // largest negative NaN
+                    0,                                                     // 0.0d
+                    1,                                                     // smallest positive number
+                    Double.doubleToLongBits(42.0),                         // random positive number
+                    Double.doubleToLongBits(Double.POSITIVE_INFINITY) - 1, // largest positive number
+                    Double.doubleToLongBits(Double.POSITIVE_INFINITY),     // +Inf
+                    Double.doubleToLongBits(Double.POSITIVE_INFINITY) + 1, // smallest positive NaN
+                    Long.MAX_VALUE - 42,                                   // random positive NaN
+                    Long.MAX_VALUE,                                        // largest positive NaN
+                    // @formatter:on
+    };
+
+    protected static final int[] interestingInts = {
+                    // @formatter:off
+                    Integer.MIN_VALUE,                                 // -0.0f
+                    Integer.MIN_VALUE + 1,                             // largest negative number
+                    Float.floatToIntBits(-42.0f),                      // random negative number
+                    Float.floatToIntBits(Float.NEGATIVE_INFINITY) - 1, // smallest negative number
+                    Float.floatToIntBits(Float.NEGATIVE_INFINITY),     // -Inf
+                    Float.floatToIntBits(Float.NEGATIVE_INFINITY) + 1, // smallest negative NaN
+                    -42,                                               // random negative NaN
+                    -1,                                                // largest negative NaN
+                    0,                                                 // 0.0f
+                    1,                                                 // smallest positive number
+                    Float.floatToIntBits(42.0f),                       // random positive number
+                    Float.floatToIntBits(Float.POSITIVE_INFINITY) - 1, // largest positive number
+                    Float.floatToIntBits(Float.POSITIVE_INFINITY),     // +Inf
+                    Float.floatToIntBits(Float.POSITIVE_INFINITY) + 1, // smallest positive NaN
+                    Integer.MAX_VALUE - 42,                            // random positive NaN
+                    Integer.MAX_VALUE,                                 // largest positive NaN
+                    // @formatter:on
+    };
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java
new file mode 100644
index 0000000..f2fe97b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.function.Function;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ShortCircuitOrNodeTest extends GraalCompilerTest {
+    static boolean shortCircuitOr(boolean b1, boolean b2) {
+        return b1 || b2;
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), ShortCircuitOrNodeTest.class);
+        r.register2("shortCircuitOr", boolean.class, boolean.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode b1, ValueNode b2) {
+                LogicNode x = b.add(new IntegerEqualsNode(b1, b.add(ConstantNode.forInt(1))));
+                LogicNode y = b.add(new IntegerEqualsNode(b2, b.add(ConstantNode.forInt(1))));
+                ShortCircuitOrNode compare = b.add(new ShortCircuitOrNode(x, false, y, false, 0.5));
+                b.addPush(JavaKind.Boolean, new ConditionalNode(compare, b.add(ConstantNode.forBoolean(true)), b.add(ConstantNode.forBoolean(false))));
+                return true;
+            }
+        });
+
+        return plugins;
+    }
+
+    public static int testSharedConditionSnippet(Object o) {
+        boolean b2 = o != null;
+        boolean b1 = o instanceof Function;
+        if (b1) {
+            if (shortCircuitOr(b1, b2)) {
+                return 4;
+            } else {
+                return 3;
+            }
+        }
+        return 1;
+    }
+
+    @Test
+    public void testSharedCondition() {
+        test("testSharedConditionSnippet", "String");
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java
new file mode 100644
index 0000000..ecc64e8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
+public abstract class AbstractBeginNode extends FixedWithNextNode implements LIRLowerable, GuardingNode, AnchoringNode, IterableNodeType {
+
+    public static final NodeClass<AbstractBeginNode> TYPE = NodeClass.create(AbstractBeginNode.class);
+
+    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c) {
+        this(c, StampFactory.forVoid());
+    }
+
+    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    public static AbstractBeginNode prevBegin(FixedNode from) {
+        Node next = from;
+        while (next != null) {
+            if (next instanceof AbstractBeginNode) {
+                AbstractBeginNode begin = (AbstractBeginNode) next;
+                return begin;
+            }
+            next = next.predecessor();
+        }
+        return null;
+    }
+
+    private void evacuateGuards(FixedNode evacuateFrom) {
+        if (!hasNoUsages()) {
+            AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
+            assert prevBegin != null;
+            for (Node anchored : anchored().snapshot()) {
+                anchored.replaceFirstInput(this, prevBegin);
+            }
+        }
+    }
+
+    public void prepareDelete() {
+        prepareDelete((FixedNode) predecessor());
+    }
+
+    public void prepareDelete(FixedNode evacuateFrom) {
+        evacuateGuards(evacuateFrom);
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(predecessor() != null || this == graph().start() || this instanceof AbstractMergeNode, "begin nodes must be connected");
+        return super.verify();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // nop
+    }
+
+    public NodeIterable<GuardNode> guards() {
+        return usages().filter(GuardNode.class);
+    }
+
+    public NodeIterable<Node> anchored() {
+        return usages();
+    }
+
+    public NodeIterable<FixedNode> getBlockNodes() {
+        return new NodeIterable<FixedNode>() {
+
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new BlockNodeIterator(AbstractBeginNode.this);
+            }
+        };
+    }
+
+    private class BlockNodeIterator implements Iterator<FixedNode> {
+
+        private FixedNode current;
+
+        BlockNodeIterator(FixedNode next) {
+            this.current = next;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        @Override
+        public FixedNode next() {
+            FixedNode ret = current;
+            if (ret == null) {
+                throw new NoSuchElementException();
+            }
+            if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) {
+                current = null;
+            } else {
+                current = ((FixedWithNextNode) current).next();
+            }
+            return ret;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractDeoptimizeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractDeoptimizeNode.java
new file mode 100644
index 0000000..85666a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractDeoptimizeNode.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * This node represents an unconditional explicit request for immediate deoptimization.
+ *
+ * After this node, execution will continue using a fallback execution engine (such as an
+ * interpreter) at the position described by the {@link #stateBefore() deoptimization state}.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "The cycles for a deopt are as high as possible as we continue execution in the interpreter, " +
+                            "but they pollute the cost model, thus we do not care about their cycles.",
+          size = SIZE_UNKNOWN,
+          sizeRationale = "Deopts carry the meta information necessary to map the state back in the interpreter, but they pollute the cost model," +
+                          "thus we do not care about their size.")
+// @formatter:on
+public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode.DeoptBefore {
+
+    public static final NodeClass<AbstractDeoptimizeNode> TYPE = NodeClass.create(AbstractDeoptimizeNode.class);
+    @OptionalInput(State) FrameState stateBefore;
+
+    protected AbstractDeoptimizeNode(NodeClass<? extends AbstractDeoptimizeNode> c, FrameState stateBefore) {
+        super(c, StampFactory.forVoid());
+        this.stateBefore = stateBefore;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+
+    public abstract ValueNode getActionAndReason(MetaAccessProvider metaAccess);
+
+    public abstract ValueNode getSpeculation(MetaAccessProvider metaAccess);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractEndNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractEndNode.java
new file mode 100644
index 0000000..38b5167
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractEndNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public abstract class AbstractEndNode extends FixedNode implements IterableNodeType, LIRLowerable {
+
+    public static final NodeClass<AbstractEndNode> TYPE = NodeClass.create(AbstractEndNode.class);
+
+    protected AbstractEndNode(NodeClass<? extends AbstractEndNode> c) {
+        super(c, StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.visitEndNode(this);
+    }
+
+    public AbstractMergeNode merge() {
+        return (AbstractMergeNode) usages().first();
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(getUsageCount() <= 1, "at most one usage");
+        return super.verify();
+    }
+
+    @Override
+    public Iterable<? extends Node> cfgSuccessors() {
+        AbstractMergeNode merge = merge();
+        if (merge != null) {
+            return Arrays.asList(merge);
+        }
+        return Collections.emptyList();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java
new file mode 100644
index 0000000..f6ff25e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+@NodeInfo
+public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode, DeoptimizingGuard {
+
+    public static final NodeClass<AbstractFixedGuardNode> TYPE = NodeClass.create(AbstractFixedGuardNode.class);
+    @Input(InputType.Condition) protected LogicNode condition;
+    protected final DeoptimizationReason reason;
+    protected final DeoptimizationAction action;
+    protected JavaConstant speculation;
+    protected boolean negated;
+
+    @Override
+    public LogicNode getCondition() {
+        return condition;
+    }
+
+    public LogicNode condition() {
+        return getCondition();
+    }
+
+    @Override
+    public void setCondition(LogicNode x, boolean negated) {
+        updateUsages(condition, x);
+        condition = x;
+        this.negated = negated;
+    }
+
+    protected AbstractFixedGuardNode(NodeClass<? extends AbstractFixedGuardNode> c, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation,
+                    boolean negated) {
+        super(c, StampFactory.forVoid());
+        this.action = action;
+        this.speculation = speculation;
+        this.negated = negated;
+        this.condition = condition;
+        this.reason = deoptReason;
+    }
+
+    @Override
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    @Override
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
+    @Override
+    public JavaConstant getSpeculation() {
+        return speculation;
+    }
+
+    @Override
+    public boolean isNegated() {
+        return negated;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        while (condition instanceof LogicNegationNode) {
+            LogicNegationNode negation = (LogicNegationNode) condition;
+            setCondition(negation.getValue(), !negated);
+        }
+    }
+
+    public DeoptimizeNode lowerToIf() {
+        FixedNode currentNext = next();
+        setNext(null);
+        DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation));
+        deopt.setStateBefore(stateBefore());
+        IfNode ifNode;
+        AbstractBeginNode noDeoptSuccessor;
+        if (negated) {
+            ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0));
+            noDeoptSuccessor = ifNode.falseSuccessor();
+        } else {
+            ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1));
+            noDeoptSuccessor = ifNode.trueSuccessor();
+        }
+        ((FixedWithNextNode) predecessor()).setNext(ifNode);
+        this.replaceAtUsages(noDeoptSuccessor);
+        GraphUtil.killWithUnusedFloatingInputs(this);
+
+        return deopt;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractLocalNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractLocalNode.java
new file mode 100644
index 0000000..9c8bee8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractLocalNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_1)
+public abstract class AbstractLocalNode extends FloatingNode {
+
+    public static final NodeClass<AbstractLocalNode> TYPE = NodeClass.create(AbstractLocalNode.class);
+    protected final int index;
+
+    protected AbstractLocalNode(NodeClass<? extends AbstractLocalNode> c, int index, Stamp stamp) {
+        super(c, stamp);
+        this.index = index;
+    }
+
+    /**
+     * Gets the index of this local in the array of parameters. This is NOT the JVM local index.
+     *
+     * @return the index
+     */
+    public int index() {
+        return index;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "(" + index + ")";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractMergeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractMergeNode.java
new file mode 100644
index 0000000..7858e8a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractMergeNode.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+/**
+ * Denotes the merging of multiple control-flow paths.
+ */
+@NodeInfo(allowedUsageTypes = Association, cycles = CYCLES_0, size = SIZE_0)
+public abstract class AbstractMergeNode extends BeginStateSplitNode implements IterableNodeType, Simplifiable, LIRLowerable {
+    public static final NodeClass<AbstractMergeNode> TYPE = NodeClass.create(AbstractMergeNode.class);
+
+    protected AbstractMergeNode(NodeClass<? extends AbstractMergeNode> c) {
+        super(c);
+    }
+
+    @Input(Association) protected NodeInputList<EndNode> ends = new NodeInputList<>(this);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.visitMerge(this);
+    }
+
+    public int forwardEndIndex(EndNode end) {
+        return ends.indexOf(end);
+    }
+
+    public void addForwardEnd(EndNode end) {
+        ends.add(end);
+    }
+
+    public final int forwardEndCount() {
+        return ends.size();
+    }
+
+    public final EndNode forwardEndAt(int index) {
+        return ends.get(index);
+    }
+
+    @Override
+    public NodeIterable<EndNode> cfgPredecessors() {
+        return ends;
+    }
+
+    /**
+     * Determines if a given node is a phi whose {@linkplain PhiNode#merge() merge} is this node.
+     *
+     * @param value the instruction to test
+     * @return {@code true} if {@code value} is a phi and its merge is {@code this}
+     */
+    public boolean isPhiAtMerge(Node value) {
+        return value instanceof PhiNode && ((PhiNode) value).merge() == this;
+    }
+
+    /**
+     * Removes the given end from the merge, along with the entries corresponding to this end in the
+     * phis connected to the merge.
+     *
+     * @param pred the end to remove
+     */
+    public void removeEnd(AbstractEndNode pred) {
+        int predIndex = phiPredecessorIndex(pred);
+        assert predIndex != -1;
+        deleteEnd(pred);
+        for (PhiNode phi : phis().snapshot()) {
+            if (phi.isDeleted()) {
+                continue;
+            }
+            ValueNode removedValue = phi.valueAt(predIndex);
+            phi.removeInput(predIndex);
+            if (removedValue != null && removedValue.isAlive() && removedValue.hasNoUsages() && GraphUtil.isFloatingNode(removedValue)) {
+                GraphUtil.killWithUnusedFloatingInputs(removedValue);
+            }
+        }
+    }
+
+    protected void deleteEnd(AbstractEndNode end) {
+        ends.remove(end);
+    }
+
+    public void clearEnds() {
+        ends.clear();
+    }
+
+    public NodeInputList<EndNode> forwardEnds() {
+        return ends;
+    }
+
+    public int phiPredecessorCount() {
+        return forwardEndCount();
+    }
+
+    public int phiPredecessorIndex(AbstractEndNode pred) {
+        return forwardEndIndex((EndNode) pred);
+    }
+
+    public AbstractEndNode phiPredecessorAt(int index) {
+        return forwardEndAt(index);
+    }
+
+    public NodeIterable<PhiNode> phis() {
+        return this.usages().filter(PhiNode.class).filter(this::isPhiAtMerge);
+    }
+
+    public NodeIterable<ValuePhiNode> valuePhis() {
+        return this.usages().filter(ValuePhiNode.class).filter(this::isPhiAtMerge);
+    }
+
+    @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(n -> !isPhiAtMerge(n));
+    }
+
+    /**
+     * This simplify method can deal with a null value for tool, so that it can be used outside of
+     * canonicalization.
+     */
+    @Override
+    public void simplify(SimplifierTool tool) {
+        FixedNode currentNext = next();
+        if (currentNext instanceof AbstractEndNode) {
+            AbstractEndNode origLoopEnd = (AbstractEndNode) currentNext;
+            AbstractMergeNode merge = origLoopEnd.merge();
+            if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) {
+                return;
+            }
+            // in order to move anchored values to the other merge we would need to check if the
+            // anchors are used by phis of the other merge
+            if (this.anchored().isNotEmpty()) {
+                return;
+            }
+            if (merge.stateAfter() == null && this.stateAfter() != null) {
+                // We hold a state, but the succeeding merge does not => do not combine.
+                return;
+            }
+            for (PhiNode phi : phis()) {
+                for (Node usage : phi.usages()) {
+                    if (!(usage instanceof VirtualState) && !merge.isPhiAtMerge(usage)) {
+                        return;
+                    }
+                }
+            }
+            Debug.log("Split %s into ends for %s.", this, merge);
+            int numEnds = this.forwardEndCount();
+            for (int i = 0; i < numEnds - 1; i++) {
+                AbstractEndNode end = forwardEndAt(numEnds - 1 - i);
+                if (tool != null) {
+                    tool.addToWorkList(end);
+                }
+                AbstractEndNode newEnd;
+                if (merge instanceof LoopBeginNode) {
+                    newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
+                } else {
+                    EndNode tmpEnd = graph().add(new EndNode());
+                    merge.addForwardEnd(tmpEnd);
+                    newEnd = tmpEnd;
+                }
+                for (PhiNode phi : merge.phis()) {
+                    ValueNode v = phi.valueAt(origLoopEnd);
+                    ValueNode newInput;
+                    if (isPhiAtMerge(v)) {
+                        PhiNode endPhi = (PhiNode) v;
+                        newInput = endPhi.valueAt(end);
+                    } else {
+                        newInput = v;
+                    }
+                    phi.addInput(newInput);
+                }
+                this.removeEnd(end);
+                end.replaceAtPredecessor(newEnd);
+                end.safeDelete();
+                if (tool != null) {
+                    tool.addToWorkList(newEnd.predecessor());
+                }
+            }
+            graph().reduceTrivialMerge(this);
+        } else if (currentNext instanceof ReturnNode) {
+            ReturnNode returnNode = (ReturnNode) currentNext;
+            if (anchored().isNotEmpty() || returnNode.getMemoryMap() != null) {
+                return;
+            }
+            List<PhiNode> phis = phis().snapshot();
+            for (PhiNode phi : phis) {
+                for (Node usage : phi.usages()) {
+                    if (usage != returnNode && !(usage instanceof FrameState)) {
+                        return;
+                    }
+                }
+            }
+
+            ValuePhiNode returnValuePhi = returnNode.result() == null || !isPhiAtMerge(returnNode.result()) ? null : (ValuePhiNode) returnNode.result();
+            List<EndNode> endNodes = forwardEnds().snapshot();
+            for (EndNode end : endNodes) {
+                ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
+                if (tool != null) {
+                    tool.addToWorkList(end.predecessor());
+                }
+                end.replaceAtPredecessor(newReturn);
+            }
+            GraphUtil.killCFG(this);
+            for (EndNode end : endNodes) {
+                end.safeDelete();
+            }
+            for (PhiNode phi : phis) {
+                if (tool.allUsagesAvailable() && phi.isAlive() && phi.hasNoUsages()) {
+                    GraphUtil.killWithUnusedFloatingInputs(phi);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractStateSplit.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractStateSplit.java
new file mode 100644
index 0000000..dc571aa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractStateSplit.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+@NodeInfo
+public abstract class AbstractStateSplit extends FixedWithNextNode implements StateSplit {
+
+    public static final NodeClass<AbstractStateSplit> TYPE = NodeClass.create(AbstractStateSplit.class);
+    @OptionalInput(InputType.State) protected FrameState stateAfter;
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    protected AbstractStateSplit(NodeClass<? extends AbstractStateSplit> c, Stamp stamp) {
+        this(c, stamp, null);
+    }
+
+    protected AbstractStateSplit(NodeClass<? extends AbstractStateSplit> c, Stamp stamp, FrameState stateAfter) {
+        super(c, stamp);
+        this.stateAfter = stateAfter;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ArithmeticOperation.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ArithmeticOperation.java
new file mode 100644
index 0000000..d698a0c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ArithmeticOperation.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.Op;
+
+/**
+ * An {@code ArithmeticOperation} is an operation that does primitive value arithmetic without side
+ * effect.
+ */
+public interface ArithmeticOperation {
+
+    Op getArithmeticOp();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java
new file mode 100644
index 0000000..1bf6617
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class BeginNode extends AbstractBeginNode implements Simplifiable {
+
+    public static final NodeClass<BeginNode> TYPE = NodeClass.create(BeginNode.class);
+
+    public BeginNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public BeginNode(Stamp stamp) {
+        super(TYPE, stamp);
+    }
+
+    public void trySimplify() {
+        FixedNode prev = (FixedNode) this.predecessor();
+        if (prev instanceof ControlSplitNode) {
+            // This begin node is necessary.
+        } else {
+            // This begin node can be removed and all guards moved up to the preceding begin node.
+            prepareDelete();
+            graph().removeFixed(this);
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        FixedNode prev = (FixedNode) this.predecessor();
+        if (prev == null) {
+            // This is the start node.
+        } else if (prev instanceof ControlSplitNode) {
+            // This begin node is necessary.
+        } else {
+            // This begin node can be removed and all guards moved up to the preceding begin node.
+            prepareDelete();
+            tool.addToWorkList(next());
+            graph().removeFixed(this);
+        }
+    }
+
+    public static AbstractBeginNode begin(FixedNode with) {
+        if (with instanceof AbstractBeginNode) {
+            return (AbstractBeginNode) with;
+        }
+        BeginNode begin = with.graph().add(new BeginNode());
+        begin.setNext(with);
+        return begin;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginStateSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginStateSplitNode.java
new file mode 100644
index 0000000..a1da2cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginStateSplitNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Base class for {@link AbstractBeginNode}s that are associated with a frame state.
+ *
+ * TODO (dnsimon) this not needed until {@link AbstractBeginNode} no longer implements
+ * {@link StateSplit} which is not possible until loop peeling works without requiring begin nodes
+ * to have frames states.
+ */
+@NodeInfo
+public abstract class BeginStateSplitNode extends AbstractBeginNode implements StateSplit {
+
+    public static final NodeClass<BeginStateSplitNode> TYPE = NodeClass.create(BeginStateSplitNode.class);
+    @OptionalInput(InputType.State) protected FrameState stateAfter;
+
+    protected BeginStateSplitNode(NodeClass<? extends BeginStateSplitNode> c) {
+        super(c);
+    }
+
+    protected BeginStateSplitNode(NodeClass<? extends BeginStateSplitNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    /**
+     * A begin node has no side effect.
+     */
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BinaryOpLogicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BinaryOpLogicNode.java
new file mode 100644
index 0000000..1c0b45d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BinaryOpLogicNode.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Binary<ValueNode> {
+
+    public static final NodeClass<BinaryOpLogicNode> TYPE = NodeClass.create(BinaryOpLogicNode.class);
+    @Input protected ValueNode x;
+    @Input protected ValueNode y;
+
+    @Override
+    public ValueNode getX() {
+        return x;
+    }
+
+    @Override
+    public ValueNode getY() {
+        return y;
+    }
+
+    public BinaryOpLogicNode(NodeClass<? extends BinaryOpLogicNode> c, ValueNode x, ValueNode y) {
+        super(c);
+        assert x != null && y != null;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public boolean verify() {
+        return super.verify();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+
+    /**
+     * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order the
+     * inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on the node
+     * if it's currently in a graph.
+     *
+     * @return the original node or another node with the same inputs, ignoring ordering.
+     */
+    @SuppressWarnings("deprecation")
+    public LogicNode maybeCommuteInputs() {
+        assert this instanceof BinaryCommutative;
+        if (!y.isConstant() && x.getId() > y.getId()) {
+            ValueNode tmp = x;
+            x = y;
+            y = tmp;
+            if (graph() != null) {
+                // See if this node already exists
+                LogicNode duplicate = graph().findDuplicate(this);
+                if (duplicate != null) {
+                    return duplicate;
+                }
+            }
+        }
+        return this;
+    }
+
+    public abstract Stamp getSucceedingStampForX(boolean negated);
+
+    public abstract Stamp getSucceedingStampForY(boolean negated);
+
+    public abstract TriState tryFold(Stamp xStamp, Stamp yStamp);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BreakpointNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BreakpointNode.java
new file mode 100644
index 0000000..37b0f8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BreakpointNode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * A node that results in a platform dependent breakpoint instruction being emitted. A number of
+ * arguments can be associated with such a node for placing values of interest in the Java ABI
+ * specified parameter locations corresponding to the kinds of the values. That is, the arguments
+ * are set up as if the breakpoint instruction was a call to a compiled Java method.
+ * <p>
+ * A breakpoint is usually place by defining a node intrinsic method as follows:
+ *
+ * <pre>
+ *     {@literal @}NodeIntrinsic(BreakpointNode.class)
+ *     static void breakpoint(Object object, Word mark, Word value) {
+ *          throw new GraalError("");
+ *     }
+ * </pre>
+ *
+ * Note that the signature is arbitrary. It's sole purpose is to capture values you may want to
+ * inspect in the native debugger when the breakpoint is hit.
+ */
+@NodeInfo
+public final class BreakpointNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<BreakpointNode> TYPE = NodeClass.create(BreakpointNode.class);
+    @Input NodeInputList<ValueNode> arguments;
+
+    public BreakpointNode(ValueNode... arguments) {
+        super(TYPE, StampFactory.forVoid());
+        this.arguments = new NodeInputList<>(this, arguments);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.visitBreakpointNode(this);
+    }
+
+    public NodeInputList<ValueNode> arguments() {
+        return arguments;
+    }
+
+    @NodeIntrinsic
+    public static native void breakpoint();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CallTargetNode.java
new file mode 100644
index 0000000..761b9d5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CallTargetNode.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(allowedUsageTypes = Extension, cycles = CYCLES_0, size = SIZE_0)
+public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
+    public static final NodeClass<CallTargetNode> TYPE = NodeClass.create(CallTargetNode.class);
+
+    public enum InvokeKind {
+        Interface(false),
+        Special(true),
+        Static(true),
+        Virtual(false);
+
+        InvokeKind(boolean direct) {
+            this.direct = direct;
+        }
+
+        private final boolean direct;
+
+        public boolean hasReceiver() {
+            return this != Static;
+        }
+
+        public boolean isDirect() {
+            return direct;
+        }
+
+        public boolean isIndirect() {
+            return !direct;
+        }
+
+        public boolean isInterface() {
+            return this == InvokeKind.Interface;
+        }
+    }
+
+    @Input protected NodeInputList<ValueNode> arguments;
+    protected ResolvedJavaMethod targetMethod;
+    protected InvokeKind invokeKind;
+    protected final StampPair returnStamp;
+
+    protected CallTargetNode(NodeClass<? extends CallTargetNode> c, ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, StampPair returnStamp) {
+        super(c, StampFactory.forVoid());
+        this.targetMethod = targetMethod;
+        this.invokeKind = invokeKind;
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.returnStamp = returnStamp;
+    }
+
+    public NodeInputList<ValueNode> arguments() {
+        return arguments;
+    }
+
+    public static Stamp createReturnStamp(Assumptions assumptions, JavaType returnType) {
+        JavaKind kind = returnType.getJavaKind();
+        if (kind == JavaKind.Object && returnType instanceof ResolvedJavaType) {
+            return StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) returnType));
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    public StampPair returnStamp() {
+        return this.returnStamp;
+    }
+
+    /**
+     * A human-readable representation of the target, used for debug printing only.
+     */
+    public abstract String targetName();
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // nop
+    }
+
+    public void setTargetMethod(ResolvedJavaMethod method) {
+        targetMethod = method;
+    }
+
+    /**
+     * Gets the target method for this invocation instruction.
+     *
+     * @return the target method
+     */
+    public ResolvedJavaMethod targetMethod() {
+        return targetMethod;
+    }
+
+    public InvokeKind invokeKind() {
+        return invokeKind;
+    }
+
+    public void setInvokeKind(InvokeKind kind) {
+        this.invokeKind = kind;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java
new file mode 100644
index 0000000..6fdd8fe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+public interface CanonicalizableLocation {
+    ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConditionAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConditionAnchorNode.java
new file mode 100644
index 0000000..7daf36f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConditionAnchorNode.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Condition;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(nameTemplate = "ConditionAnchor(!={p#negated})", allowedUsageTypes = Guard, cycles = CYCLES_0, size = SIZE_0)
+public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable.Unary<Node>, Lowerable, GuardingNode {
+
+    public static final NodeClass<ConditionAnchorNode> TYPE = NodeClass.create(ConditionAnchorNode.class);
+    @Input(Condition) LogicNode condition;
+    protected boolean negated;
+
+    public ConditionAnchorNode(LogicNode condition) {
+        this(condition, false);
+    }
+
+    public ConditionAnchorNode(LogicNode condition, boolean negated) {
+        super(TYPE, StampFactory.forVoid());
+        this.negated = negated;
+        this.condition = condition;
+    }
+
+    public LogicNode condition() {
+        return condition;
+    }
+
+    public boolean isNegated() {
+        return negated;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool, Node forValue) {
+        if (forValue instanceof LogicNegationNode) {
+            LogicNegationNode negation = (LogicNegationNode) forValue;
+            return new ConditionAnchorNode(negation.getValue(), !negated);
+        }
+        if (forValue instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) forValue;
+            if (c.getValue() != negated) {
+                return null;
+            } else {
+                return new ValueAnchorNode(null);
+            }
+        }
+        if (tool.allUsagesAvailable() && this.hasNoUsages()) {
+            return null;
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(null));
+            graph().replaceFixedWithFixed(this, newAnchor);
+        }
+    }
+
+    @Override
+    public Node getValue() {
+        return condition;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConstantNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConstantNode.java
new file mode 100644
index 0000000..73c807f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConstantNode.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+/**
+ * The {@code ConstantNode} represents a {@link Constant constant}.
+ */
+@NodeInfo(nameTemplate = "C({p#rawvalue})", cycles = CYCLES_0, size = SIZE_1)
+public final class ConstantNode extends FloatingNode implements LIRLowerable {
+
+    public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
+
+    protected final Constant value;
+
+    private final int stableDimension;
+    private final boolean isDefaultStable;
+
+    private static ConstantNode createPrimitive(JavaConstant value) {
+        assert value.getJavaKind() != JavaKind.Object;
+        return new ConstantNode(value, StampFactory.forConstant(value));
+    }
+
+    /**
+     * Constructs a new node representing the specified constant.
+     *
+     * @param value the constant
+     */
+    public ConstantNode(Constant value, Stamp stamp) {
+        this(value, stamp, 0, false);
+    }
+
+    private ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable) {
+        super(TYPE, stamp);
+        assert stamp != null && stamp.isCompatible(value) : stamp + " " + value;
+        this.value = value;
+        this.stableDimension = stableDimension;
+        if (stableDimension == 0) {
+            /*
+             * Ensure that isDefaultStable has a canonical value to avoid having two constant nodes
+             * that only differ in this field. The value of isDefaultStable is only used when we
+             * have a stable array dimension.
+             */
+            this.isDefaultStable = false;
+        } else {
+            this.isDefaultStable = isDefaultStable;
+        }
+    }
+
+    /**
+     * @return the constant value represented by this node
+     */
+    public Constant getValue() {
+        return value;
+    }
+
+    /**
+     * @return the number of stable dimensions if this is a stable array, otherwise 0
+     */
+    public int getStableDimension() {
+        return stableDimension;
+    }
+
+    /**
+     * @return true if this is a stable array and the default elements are considered stable
+     */
+    public boolean isDefaultStable() {
+        return isDefaultStable;
+    }
+
+    /**
+     * Gathers all the {@link ConstantNode}s that are inputs to the
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
+     */
+    public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
+        return graph.getNodes().filter(ConstantNode.class);
+    }
+
+    /**
+     * Replaces this node at its usages with another node.
+     */
+    public void replace(StructuredGraph graph, Node replacement) {
+        assert graph == graph();
+        replaceAtUsagesAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+        if (onlyUsedInVirtualState()) {
+            gen.setResult(this, new ConstantValue(kind, value));
+        } else {
+            gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value));
+        }
+    }
+
+    private boolean onlyUsedInVirtualState() {
+        for (Node n : this.usages()) {
+            if (n instanceof VirtualState) {
+                // Only virtual usage.
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static ConstantNode forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
+        if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
+            return forInt(constant.asInt(), graph);
+        }
+        if (constant.getJavaKind() == JavaKind.Object) {
+            return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
+        } else {
+            return unique(graph, createPrimitive(constant));
+        }
+    }
+
+    public static ConstantNode forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
+        if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
+            return forInt(constant.asInt());
+        }
+        if (constant.getJavaKind() == JavaKind.Object) {
+            return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess), stableDimension, isDefaultStable);
+        } else {
+            assert stableDimension == 0;
+            return createPrimitive(constant);
+        }
+    }
+
+    public static ConstantNode forConstant(JavaConstant array, MetaAccessProvider metaAccess) {
+        return forConstant(array, 0, false, metaAccess);
+    }
+
+    public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
+        return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
+    }
+
+    public static ConstantNode forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
+        return new ConstantNode(constant, stamp.constant(constant, metaAccess), stableDimension, isDefaultStable);
+    }
+
+    public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) {
+        return new ConstantNode(constant, stamp.constant(constant, metaAccess));
+    }
+
+    /**
+     * Returns a node for a Java primitive.
+     */
+    public static ConstantNode forPrimitive(JavaConstant constant, StructuredGraph graph) {
+        assert constant.getJavaKind() != JavaKind.Object;
+        return forConstant(constant, null, graph);
+    }
+
+    /**
+     * Returns a node for a Java primitive.
+     */
+    public static ConstantNode forPrimitive(JavaConstant constant) {
+        assert constant.getJavaKind() != JavaKind.Object;
+        return forConstant(constant, null);
+    }
+
+    /**
+     * Returns a node for a primitive of a given type.
+     */
+    public static ConstantNode forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph) {
+        if (stamp instanceof IntegerStamp) {
+            assert constant.getJavaKind().isNumericInteger() && stamp.getStackKind() == constant.getJavaKind().getStackKind();
+            IntegerStamp istamp = (IntegerStamp) stamp;
+            return forIntegerBits(istamp.getBits(), constant, graph);
+        } else {
+            assert constant.getJavaKind().isNumericFloat() && stamp.getStackKind() == constant.getJavaKind();
+            return forPrimitive(constant, graph);
+        }
+    }
+
+    /**
+     * Returns a node for a primitive of a given type.
+     */
+    public static ConstantNode forPrimitive(Stamp stamp, Constant constant) {
+        if (stamp instanceof IntegerStamp) {
+            PrimitiveConstant primitive = (PrimitiveConstant) constant;
+            assert primitive.getJavaKind().isNumericInteger() && stamp.getStackKind() == primitive.getJavaKind().getStackKind();
+            IntegerStamp istamp = (IntegerStamp) stamp;
+            return forIntegerBits(istamp.getBits(), primitive);
+        } else if (stamp instanceof FloatStamp) {
+            PrimitiveConstant primitive = (PrimitiveConstant) constant;
+            assert primitive.getJavaKind().isNumericFloat() && stamp.getStackKind() == primitive.getJavaKind();
+            return forConstant(primitive, null);
+        } else {
+            assert !(stamp instanceof AbstractObjectStamp);
+            return new ConstantNode(constant, stamp.constant(constant, null));
+        }
+    }
+
+    /**
+     * Returns a node for a double constant.
+     *
+     * @param d the double value for which to create the instruction
+     * @return a node for a double constant
+     */
+    public static ConstantNode forDouble(double d, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forDouble(d)));
+    }
+
+    /**
+     * Returns a node for a double constant.
+     *
+     * @param d the double value for which to create the instruction
+     * @return a node for a double constant
+     */
+    public static ConstantNode forDouble(double d) {
+        return createPrimitive(JavaConstant.forDouble(d));
+    }
+
+    /**
+     * Returns a node for a float constant.
+     *
+     * @param f the float value for which to create the instruction
+     * @return a node for a float constant
+     */
+    public static ConstantNode forFloat(float f, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forFloat(f)));
+    }
+
+    /**
+     * Returns a node for a float constant.
+     *
+     * @param f the float value for which to create the instruction
+     * @return a node for a float constant
+     */
+    public static ConstantNode forFloat(float f) {
+        return createPrimitive(JavaConstant.forFloat(f));
+    }
+
+    /**
+     * Returns a node for an long constant.
+     *
+     * @param i the long value for which to create the instruction
+     * @return a node for an long constant
+     */
+    public static ConstantNode forLong(long i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forLong(i)));
+    }
+
+    /**
+     * Returns a node for an long constant.
+     *
+     * @param i the long value for which to create the instruction
+     * @return a node for an long constant
+     */
+    public static ConstantNode forLong(long i) {
+        return createPrimitive(JavaConstant.forLong(i));
+    }
+
+    /**
+     * Returns a node for an integer constant.
+     *
+     * @param i the integer value for which to create the instruction
+     * @return a node for an integer constant
+     */
+    public static ConstantNode forInt(int i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forInt(i)));
+    }
+
+    /**
+     * Returns a node for an integer constant.
+     *
+     * @param i the integer value for which to create the instruction
+     * @return a node for an integer constant
+     */
+    public static ConstantNode forInt(int i) {
+        return createPrimitive(JavaConstant.forInt(i));
+    }
+
+    /**
+     * Returns a node for a boolean constant.
+     *
+     * @param i the boolean value for which to create the instruction
+     * @return a node representing the boolean
+     */
+    public static ConstantNode forBoolean(boolean i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forInt(i ? 1 : 0)));
+    }
+
+    /**
+     * Returns a node for a boolean constant.
+     *
+     * @param i the boolean value for which to create the instruction
+     * @return a node representing the boolean
+     */
+    public static ConstantNode forBoolean(boolean i) {
+        return createPrimitive(JavaConstant.forInt(i ? 1 : 0));
+    }
+
+    /**
+     * Returns a node for a byte constant.
+     *
+     * @param i the byte value for which to create the instruction
+     * @return a node representing the byte
+     */
+    public static ConstantNode forByte(byte i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forInt(i)));
+    }
+
+    /**
+     * Returns a node for a char constant.
+     *
+     * @param i the char value for which to create the instruction
+     * @return a node representing the char
+     */
+    public static ConstantNode forChar(char i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forInt(i)));
+    }
+
+    /**
+     * Returns a node for a short constant.
+     *
+     * @param i the short value for which to create the instruction
+     * @return a node representing the short
+     */
+    public static ConstantNode forShort(short i, StructuredGraph graph) {
+        return unique(graph, createPrimitive(JavaConstant.forInt(i)));
+    }
+
+    private static ConstantNode unique(StructuredGraph graph, ConstantNode node) {
+        return graph.unique(node);
+    }
+
+    private static ConstantNode forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph) {
+        long value = constant.asLong();
+        long bounds = CodeUtil.signExtend(value, bits);
+        return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds)));
+    }
+
+    /**
+     * Returns a node for a constant integer that's not directly representable as Java primitive
+     * (e.g. short).
+     */
+    public static ConstantNode forIntegerBits(int bits, long value, StructuredGraph graph) {
+        return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value), graph);
+    }
+
+    private static ConstantNode forIntegerBits(int bits, JavaConstant constant) {
+        long value = constant.asLong();
+        long bounds = CodeUtil.signExtend(value, bits);
+        return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds));
+    }
+
+    /**
+     * Returns a node for a constant integer that's not directly representable as Java primitive
+     * (e.g. short).
+     */
+    public static ConstantNode forIntegerBits(int bits, long value) {
+        return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value));
+    }
+
+    /**
+     * Returns a node for a constant integer that's compatible to a given stamp.
+     */
+    public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) {
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp intStamp = (IntegerStamp) stamp;
+            return forIntegerBits(intStamp.getBits(), value, graph);
+        } else {
+            return forIntegerKind(stamp.getStackKind(), value, graph);
+        }
+    }
+
+    /**
+     * Returns a node for a constant integer that's compatible to a given stamp.
+     */
+    public static ConstantNode forIntegerStamp(Stamp stamp, long value) {
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp intStamp = (IntegerStamp) stamp;
+            return forIntegerBits(intStamp.getBits(), value);
+        } else {
+            return forIntegerKind(stamp.getStackKind(), value);
+        }
+    }
+
+    public static ConstantNode forIntegerKind(JavaKind kind, long value, StructuredGraph graph) {
+        switch (kind) {
+            case Byte:
+            case Short:
+            case Int:
+                return ConstantNode.forInt((int) value, graph);
+            case Long:
+                return ConstantNode.forLong(value, graph);
+            default:
+                throw GraalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
+    public static ConstantNode forIntegerKind(JavaKind kind, long value) {
+        switch (kind) {
+            case Byte:
+            case Short:
+            case Int:
+                return createPrimitive(JavaConstant.forInt((int) value));
+            case Long:
+                return createPrimitive(JavaConstant.forLong(value));
+            default:
+                throw GraalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
+    public static ConstantNode forFloatingKind(JavaKind kind, double value, StructuredGraph graph) {
+        switch (kind) {
+            case Float:
+                return ConstantNode.forFloat((float) value, graph);
+            case Double:
+                return ConstantNode.forDouble(value, graph);
+            default:
+                throw GraalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
+    public static ConstantNode forFloatingKind(JavaKind kind, double value) {
+        switch (kind) {
+            case Float:
+                return ConstantNode.forFloat((float) value);
+            case Double:
+                return ConstantNode.forDouble(value);
+            default:
+                throw GraalError.shouldNotReachHere("unknown kind " + kind);
+        }
+    }
+
+    /**
+     * Returns a node for a constant double that's compatible to a given stamp.
+     */
+    public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) {
+        return forFloatingKind(stamp.getStackKind(), value, graph);
+    }
+
+    /**
+     * Returns a node for a constant double that's compatible to a given stamp.
+     */
+    public static ConstantNode forFloatingStamp(Stamp stamp, double value) {
+        return forFloatingKind(stamp.getStackKind(), value);
+    }
+
+    public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) {
+        return unique(graph, defaultForKind(kind));
+    }
+
+    public static ConstantNode defaultForKind(JavaKind kind) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+                return ConstantNode.forInt(0);
+            case Double:
+                return ConstantNode.forDouble(0.0);
+            case Float:
+                return ConstantNode.forFloat(0.0f);
+            case Long:
+                return ConstantNode.forLong(0L);
+            case Object:
+                return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> properties = super.getDebugProperties(map);
+        properties.put("rawvalue", value.toValueString());
+        return properties;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "(" + value.toValueString() + ")";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSinkNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSinkNode.java
new file mode 100644
index 0000000..e6707b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSinkNode.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo
+public abstract class ControlSinkNode extends FixedNode {
+    public static final NodeClass<ControlSinkNode> TYPE = NodeClass.create(ControlSinkNode.class);
+
+    protected ControlSinkNode(NodeClass<? extends ControlSinkNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java
new file mode 100644
index 0000000..994db11
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * The {@code ControlSplitNode} is a base class for all instructions that split the control flow
+ * (ie. have more than one successor).
+ */
+@NodeInfo
+public abstract class ControlSplitNode extends FixedNode implements IterableNodeType {
+    public static final NodeClass<ControlSplitNode> TYPE = NodeClass.create(ControlSplitNode.class);
+
+    protected ControlSplitNode(NodeClass<? extends ControlSplitNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    public abstract double probability(AbstractBeginNode successor);
+
+    /**
+     * Primary successor of the control split. Data dependencies on the node have to be scheduled in
+     * the primary successor.
+     *
+     * @return the primary successor
+     */
+    public abstract AbstractBeginNode getPrimarySuccessor();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java
new file mode 100644
index 0000000..1b5631a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
+public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
+    public static final int DEFAULT_DEBUG_ID = 0;
+
+    public static final NodeClass<DeoptimizeNode> TYPE = NodeClass.create(DeoptimizeNode.class);
+    protected final DeoptimizationAction action;
+    protected final DeoptimizationReason reason;
+    protected final int debugId;
+    protected final JavaConstant speculation;
+
+    public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason) {
+        this(action, reason, DEFAULT_DEBUG_ID, JavaConstant.NULL_POINTER, null);
+    }
+
+    public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, JavaConstant speculation) {
+        this(action, reason, DEFAULT_DEBUG_ID, speculation, null);
+    }
+
+    public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, int debugId, JavaConstant speculation, FrameState stateBefore) {
+        super(TYPE, stateBefore);
+        assert action != null;
+        assert reason != null;
+        assert speculation.getJavaKind() == JavaKind.Object;
+        this.action = action;
+        this.reason = reason;
+        this.debugId = debugId;
+        this.speculation = speculation;
+    }
+
+    public DeoptimizationAction action() {
+        return action;
+    }
+
+    public DeoptimizationReason reason() {
+        return reason;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @SuppressWarnings("deprecation")
+    public int getDebugId() {
+        int deoptDebugId = debugId;
+        if (deoptDebugId == DEFAULT_DEBUG_ID && (Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod())) {
+            deoptDebugId = this.getId();
+        }
+        return deoptDebugId;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+        Value actionAndReason = tool.emitJavaConstant(tool.getMetaAccess().encodeDeoptActionAndReason(action, reason, getDebugId()));
+        Value speculationValue = tool.emitJavaConstant(speculation);
+        gen.getLIRGeneratorTool().emitDeoptimize(actionAndReason, speculationValue, gen.state(this));
+    }
+
+    @Override
+    public ValueNode getActionAndReason(MetaAccessProvider metaAccess) {
+        return ConstantNode.forConstant(metaAccess.encodeDeoptActionAndReason(action, reason, getDebugId()), metaAccess, graph());
+    }
+
+    @Override
+    public ValueNode getSpeculation(MetaAccessProvider metaAccess) {
+        return ConstantNode.forConstant(speculation, metaAccess, graph());
+    }
+
+    public JavaConstant getSpeculation() {
+        return speculation;
+    }
+
+    @NodeIntrinsic
+    public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingFixedWithNextNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingFixedWithNextNode.java
new file mode 100644
index 0000000..2716b30
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingFixedWithNextNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo
+public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode.DeoptBefore {
+
+    public static final NodeClass<DeoptimizingFixedWithNextNode> TYPE = NodeClass.create(DeoptimizingFixedWithNextNode.class);
+    @OptionalInput(InputType.State) protected FrameState stateBefore;
+
+    protected DeoptimizingFixedWithNextNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    protected DeoptimizingFixedWithNextNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, Stamp stamp, FrameState stateBefore) {
+        super(c, stamp);
+        this.stateBefore = stateBefore;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java
new file mode 100644
index 0000000..3595b2e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * Shared interface to capture core methods of {@link AbstractFixedGuardNode} and {@link GuardNode}.
+ *
+ */
+public interface DeoptimizingGuard extends ValueNodeInterface {
+
+    LogicNode getCondition();
+
+    void setCondition(LogicNode x, boolean negated);
+
+    DeoptimizationReason getReason();
+
+    DeoptimizationAction getAction();
+
+    JavaConstant getSpeculation();
+
+    boolean isNegated();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingNode.java
new file mode 100644
index 0000000..f8cacdd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+
+/**
+ * Interface implemented by nodes which may need {@linkplain FrameState deoptimization information}.
+ */
+public interface DeoptimizingNode extends NodeWithState {
+
+    /**
+     * Determines if this node needs deoptimization information.
+     */
+    boolean canDeoptimize();
+
+    /**
+     * Interface for nodes that need a {@link FrameState} for deoptimizing to a point before their
+     * execution.
+     */
+    public interface DeoptBefore extends DeoptimizingNode {
+
+        /**
+         * Sets the {@link FrameState} describing the program state before the execution of this
+         * node.
+         */
+        void setStateBefore(FrameState state);
+
+        FrameState stateBefore();
+    }
+
+    /**
+     * Interface for nodes that need a {@link FrameState} for deoptimizing to a point after their
+     * execution.
+     */
+    public interface DeoptAfter extends DeoptimizingNode, StateSplit {
+    }
+
+    /**
+     * Interface for nodes that need a special {@link FrameState} for deoptimizing during their
+     * execution (e.g. {@link Invoke}).
+     */
+    public interface DeoptDuring extends DeoptimizingNode, StateSplit {
+
+        FrameState stateDuring();
+
+        /**
+         * Sets the {@link FrameState} describing the program state during the execution of this
+         * node.
+         */
+        void setStateDuring(FrameState state);
+
+        /**
+         * Compute the {@link FrameState} describing the program state during the execution of this
+         * node from an input {@link FrameState} describing the program state after finishing the
+         * execution of this node.
+         */
+        void computeStateDuring(FrameState stateAfter);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DirectCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DirectCallTargetNode.java
new file mode 100644
index 0000000..4069133
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DirectCallTargetNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public class DirectCallTargetNode extends LoweredCallTargetNode {
+
+    public static final NodeClass<DirectCallTargetNode> TYPE = NodeClass.create(DirectCallTargetNode.class);
+
+    public DirectCallTargetNode(ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType,
+                    InvokeKind invokeKind) {
+        this(TYPE, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
+    protected DirectCallTargetNode(NodeClass<? extends DirectCallTargetNode> c, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target,
+                    CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
+    @Override
+    public String targetName() {
+        return targetMethod().format("Direct#%h.%n");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicDeoptimizeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicDeoptimizeNode.java
new file mode 100644
index 0000000..f4da0f8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicDeoptimizeNode.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+@NodeInfo
+public final class DynamicDeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable, Lowerable, Canonicalizable {
+    public static final NodeClass<DynamicDeoptimizeNode> TYPE = NodeClass.create(DynamicDeoptimizeNode.class);
+    @Input ValueNode actionAndReason;
+    @Input ValueNode speculation;
+
+    public DynamicDeoptimizeNode(ValueNode actionAndReason, ValueNode speculation) {
+        super(TYPE, null);
+        this.actionAndReason = actionAndReason;
+        this.speculation = speculation;
+    }
+
+    public ValueNode getActionAndReason() {
+        return actionAndReason;
+    }
+
+    public ValueNode getSpeculation() {
+        return speculation;
+    }
+
+    @Override
+    public ValueNode getActionAndReason(MetaAccessProvider metaAccess) {
+        return getActionAndReason();
+    }
+
+    @Override
+    public ValueNode getSpeculation(MetaAccessProvider metaAccess) {
+        return getSpeculation();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), generator.state(this));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (actionAndReason.isConstant() && speculation.isConstant()) {
+            JavaConstant constant = actionAndReason.asJavaConstant();
+            JavaConstant speculationConstant = speculation.asJavaConstant();
+            DeoptimizeNode newDeopt = new DeoptimizeNode(tool.getMetaAccess().decodeDeoptAction(constant), tool.getMetaAccess().decodeDeoptReason(constant), tool.getMetaAccess().decodeDebugId(
+                            constant), speculationConstant, stateBefore());
+            return newDeopt;
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java
new file mode 100644
index 0000000..859375b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A {@link PiNode} where the type is not yet known. If the type becomes known at a later point in
+ * the compilation, this can canonicalize to a regular {@link PiNode}.
+ */
+@NodeInfo
+public final class DynamicPiNode extends PiNode {
+
+    public static final NodeClass<DynamicPiNode> TYPE = NodeClass.create(DynamicPiNode.class);
+    @Input ValueNode typeMirror;
+
+    public DynamicPiNode(ValueNode object, GuardingNode guard, ValueNode typeMirror) {
+        super(TYPE, object, StampFactory.object(), guard);
+        this.typeMirror = typeMirror;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (typeMirror.isConstant()) {
+            ResolvedJavaType t = tool.getConstantReflection().asJavaType(typeMirror.asConstant());
+            if (t != null) {
+                Stamp staticPiStamp;
+                if (t.isPrimitive()) {
+                    staticPiStamp = StampFactory.alwaysNull();
+                } else {
+                    TypeReference type = TypeReference.createTrusted(tool.getAssumptions(), t);
+                    staticPiStamp = StampFactory.object(type);
+                }
+
+                return new PiNode(object(), staticPiStamp, (ValueNode) getGuard()).canonical(tool);
+            }
+        }
+
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java
new file mode 100644
index 0000000..ed8c1e0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.List;
+
+import org.graalvm.compiler.graph.NodeClass;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A {@link StructuredGraph} encoded in a compact binary representation as a byte[] array. See
+ * {@link GraphEncoder} for a description of the encoding format. Use {@link GraphDecoder} for
+ * decoding.
+ */
+public class EncodedGraph {
+
+    private final byte[] encoding;
+    private final long startOffset;
+    private final Object[] objects;
+    private final NodeClass<?>[] types;
+    private final Assumptions assumptions;
+    private final List<ResolvedJavaMethod> inlinedMethods;
+
+    /**
+     * The "table of contents" of the encoded graph, i.e., the mapping from orderId numbers to the
+     * offset in the encoded byte[] array. Used as a cache during decoding.
+     */
+    protected long[] nodeStartOffsets;
+
+    public EncodedGraph(byte[] encoding, long startOffset, Object[] objects, NodeClass<?>[] types, Assumptions assumptions, List<ResolvedJavaMethod> inlinedMethods) {
+        this.encoding = encoding;
+        this.startOffset = startOffset;
+        this.objects = objects;
+        this.types = types;
+        this.assumptions = assumptions;
+        this.inlinedMethods = inlinedMethods;
+    }
+
+    public byte[] getEncoding() {
+        return encoding;
+    }
+
+    public long getStartOffset() {
+        return startOffset;
+    }
+
+    public Object[] getObjects() {
+        return objects;
+    }
+
+    public NodeClass<?>[] getNodeClasses() {
+        return types;
+    }
+
+    public Assumptions getAssumptions() {
+        return assumptions;
+    }
+
+    public List<ResolvedJavaMethod> getInlinedMethods() {
+        return inlinedMethods;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EndNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EndNode.java
new file mode 100644
index 0000000..8780415
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EndNode.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo(allowedUsageTypes = {InputType.Association}, nameTemplate = "End")
+public final class EndNode extends AbstractEndNode {
+    public static final NodeClass<EndNode> TYPE = NodeClass.create(EndNode.class);
+
+    public EndNode() {
+        super(TYPE);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryMarkerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryMarkerNode.java
new file mode 100644
index 0000000..bdafa56
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryMarkerNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * This node will be inserted at point specified by {@link StructuredGraph#getEntryBCI()}, usually
+ * by the graph builder.
+ */
+@NodeInfo(allowedUsageTypes = Association, cycles = CYCLES_0, size = SIZE_0)
+public final class EntryMarkerNode extends BeginStateSplitNode implements IterableNodeType, LIRLowerable {
+    public static final NodeClass<EntryMarkerNode> TYPE = NodeClass.create(EntryMarkerNode.class);
+
+    public EntryMarkerNode() {
+        super(TYPE);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw new GraalError("OnStackReplacementNode should not survive");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryProxyNode.java
new file mode 100644
index 0000000..b90cf42
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EntryProxyNode.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+
+/**
+ * Proxy node that is used in OSR. This node drops the stamp information from the value, since the
+ * types we see during OSR may be too precise (if a branch was not parsed for example).
+ */
+@NodeInfo(nameTemplate = "EntryProxy({i#value})", cycles = CYCLES_0, size = SIZE_0)
+public final class EntryProxyNode extends FloatingNode implements ValueProxy {
+
+    public static final NodeClass<EntryProxyNode> TYPE = NodeClass.create(EntryProxyNode.class);
+    @Input(Association) EntryMarkerNode proxyPoint;
+    @Input ValueNode value;
+
+    public EntryProxyNode(ValueNode value, EntryMarkerNode proxyPoint) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+        this.proxyPoint = proxyPoint;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public ValueNode getOriginalNode() {
+        return value();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java
new file mode 100644
index 0000000..dc15026
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+import jdk.vm.ci.meta.JavaKind.FormatWithToString;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+public class FieldLocationIdentity extends LocationIdentity implements FormatWithToString {
+
+    private final ResolvedJavaField inner;
+
+    public FieldLocationIdentity(ResolvedJavaField inner) {
+        this.inner = inner;
+    }
+
+    @Override
+    public boolean isImmutable() {
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof FieldLocationIdentity) {
+            FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj;
+            return inner.equals(fieldLocationIdentity.inner);
+
+        }
+        return false;
+    }
+
+    public ResolvedJavaField getField() {
+        return inner;
+    }
+
+    @Override
+    public int hashCode() {
+        return inner.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return inner.format("%h.%n") + (isImmutable() ? ":immutable" : "");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java
new file mode 100644
index 0000000..feed810
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+@NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}", allowedUsageTypes = Guard, size = SIZE_2, cycles = CYCLES_2)
+public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType {
+    public static final NodeClass<FixedGuardNode> TYPE = NodeClass.create(FixedGuardNode.class);
+
+    public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
+        this(condition, deoptReason, action, JavaConstant.NULL_POINTER, false);
+    }
+
+    public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
+        this(condition, deoptReason, action, JavaConstant.NULL_POINTER, negated);
+    }
+
+    public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated) {
+        super(TYPE, condition, deoptReason, action, speculation, negated);
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        super.simplify(tool);
+
+        if (getCondition() instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) getCondition();
+            if (c.getValue() == isNegated()) {
+                FixedNode currentNext = this.next();
+                if (currentNext != null) {
+                    tool.deleteBranch(currentNext);
+                }
+
+                DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason(), getSpeculation()));
+                deopt.setStateBefore(stateBefore());
+                setNext(deopt);
+            }
+            this.replaceAtUsages(null);
+            graph().removeFixed(this);
+        } else if (getCondition() instanceof ShortCircuitOrNode) {
+            ShortCircuitOrNode shortCircuitOr = (ShortCircuitOrNode) getCondition();
+            if (isNegated() && hasNoUsages()) {
+                graph().addAfterFixed(this, graph().add(new FixedGuardNode(shortCircuitOr.getY(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isYNegated())));
+                graph().replaceFixedWithFixed(this, graph().add(new FixedGuardNode(shortCircuitOr.getX(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isXNegated())));
+            }
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage().allowsFloatingGuards()) {
+            /*
+             * Don't allow guards with action None and reason RuntimeConstraint to float. In cases
+             * where 2 guards are testing equivalent conditions they might be lowered at the same
+             * location. If the guard with the None action is lowered before the the other guard
+             * then the code will be stuck repeatedly deoptimizing without invalidating the code.
+             * Conditional elimination will eliminate the guard if it's truly redundant in this
+             * case.
+             */
+            if (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint) {
+                ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode();
+                this.replaceAtUsages(guard);
+                ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
+                graph().replaceFixedWithFixed(this, newAnchor);
+            }
+        } else {
+            lowerToIf().lower(tool);
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java
new file mode 100644
index 0000000..ffb8888
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo
+public abstract class FixedNode extends ValueNode implements FixedNodeInterface {
+    public static final NodeClass<FixedNode> TYPE = NodeClass.create(FixedNode.class);
+
+    protected FixedNode(NodeClass<? extends FixedNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float");
+        return super.verify();
+    }
+
+    @Override
+    public FixedNode asNode() {
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java
new file mode 100644
index 0000000..aa4c180
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+public interface FixedNodeInterface extends ValueNodeInterface {
+    @Override
+    FixedNode asNode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java
new file mode 100644
index 0000000..d813151
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Base class of all nodes that are fixed within the control flow graph and have an immediate
+ * successor.
+ */
+@NodeInfo
+public abstract class FixedWithNextNode extends FixedNode {
+    public static final NodeClass<FixedWithNextNode> TYPE = NodeClass.create(FixedWithNextNode.class);
+
+    @Successor protected FixedNode next;
+
+    public FixedNode next() {
+        return next;
+    }
+
+    public void setNext(FixedNode x) {
+        updatePredecessor(next, x);
+        next = x;
+    }
+
+    public FixedWithNextNode(NodeClass<? extends FixedWithNextNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    @Override
+    public FixedWithNextNode asNode() {
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingAnchoredNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingAnchoredNode.java
new file mode 100644
index 0000000..ea37a8caa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingAnchoredNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+
+@NodeInfo
+public abstract class FloatingAnchoredNode extends FloatingNode {
+    public static final NodeClass<FloatingAnchoredNode> TYPE = NodeClass.create(FloatingAnchoredNode.class);
+
+    @Input(InputType.Anchor) protected AnchoringNode anchor;
+
+    public FloatingAnchoredNode(NodeClass<? extends FloatingAnchoredNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    public FloatingAnchoredNode(NodeClass<? extends FloatingAnchoredNode> c, Stamp stamp, AnchoringNode anchor) {
+        super(c, stamp);
+        this.anchor = anchor;
+    }
+
+    public AnchoringNode getAnchor() {
+        return anchor;
+    }
+
+    public void setAnchor(AnchoringNode x) {
+        updateUsagesInterface(this.anchor, x);
+        this.anchor = x;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingGuardedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingGuardedNode.java
new file mode 100644
index 0000000..77985ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FloatingGuardedNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+@NodeInfo
+public abstract class FloatingGuardedNode extends FloatingNode implements GuardedNode {
+    public static final NodeClass<FloatingGuardedNode> TYPE = NodeClass.create(FloatingGuardedNode.class);
+
+    @OptionalInput(InputType.Guard) protected GuardingNode guard;
+
+    protected FloatingGuardedNode(NodeClass<? extends FloatingGuardedNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    protected FloatingGuardedNode(NodeClass<? extends FloatingGuardedNode> c, Stamp stamp, GuardingNode guard) {
+        super(c, stamp);
+        this.guard = guard;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java
new file mode 100644
index 0000000..9c92560
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static jdk.vm.ci.code.BytecodeFrame.getPlaceholderBciName;
+import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * The {@code FrameState} class encapsulates the frame state (i.e. local variables and operand
+ * stack) at a particular point in the abstract interpretation.
+ *
+ * This can be used as debug or deoptimization information.
+ */
+@NodeInfo(nameTemplate = "@{p#code/s}:{p#bci}", cycles = CYCLES_0, size = SIZE_1)
+public final class FrameState extends VirtualState implements IterableNodeType {
+    public static final NodeClass<FrameState> TYPE = NodeClass.create(FrameState.class);
+
+    private static final DebugCounter FRAMESTATES_COUNTER = Debug.counter("FrameStateCount");
+
+    /**
+     * Marker value for the second slot of values that occupy two local variable or expression stack
+     * slots. The marker value is used by the bytecode parser, but replaced with {@code null} in the
+     * {@link #values} of the {@link FrameState}.
+     */
+    public static final ValueNode TWO_SLOT_MARKER = new TwoSlotMarker();
+
+    @NodeInfo
+    private static final class TwoSlotMarker extends ValueNode {
+        public static final NodeClass<TwoSlotMarker> TYPE = NodeClass.create(TwoSlotMarker.class);
+
+        protected TwoSlotMarker() {
+            super(TYPE, StampFactory.forKind(JavaKind.Illegal));
+        }
+    }
+
+    protected final int localsSize;
+
+    protected final int stackSize;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    protected boolean rethrowException;
+
+    protected final boolean duringCall;
+
+    @OptionalInput(value = InputType.State) FrameState outerFrameState;
+
+    /**
+     * Contains the locals, the expressions and the locked objects, in this order.
+     */
+    @OptionalInput NodeInputList<ValueNode> values;
+
+    @OptionalInput(Association) NodeInputList<MonitorIdNode> monitorIds;
+
+    @OptionalInput(State) NodeInputList<EscapeObjectState> virtualObjectMappings;
+
+    /**
+     * The bytecode index to which this frame state applies.
+     */
+    public final int bci;
+
+    /**
+     * The bytecode to which this frame state applies.
+     */
+    protected final Bytecode code;
+
+    public FrameState(FrameState outerFrameState, Bytecode code, int bci, int localsSize, int stackSize, int lockSize, boolean rethrowException, boolean duringCall,
+                    List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) {
+        super(TYPE);
+        if (code != null) {
+            /*
+             * Make sure the bci is within range of the bytecodes. If the code size is 0 then allow
+             * any value, otherwise the bci must be less than the code size. Any negative value is
+             * also allowed to represent special bytecode states.
+             */
+            int codeSize = code.getCodeSize();
+            if (codeSize != 0 && bci >= codeSize) {
+                throw new GraalError("bci %d is out of range for %s %d bytes", bci, code.getMethod().format("%H.%n(%p)"), codeSize);
+            }
+        }
+        assert stackSize >= 0;
+        this.outerFrameState = outerFrameState;
+        this.code = code;
+        this.bci = bci;
+        this.localsSize = localsSize;
+        this.stackSize = stackSize;
+        this.values = new NodeInputList<>(this, localsSize + stackSize + lockSize);
+
+        if (monitorIds != null && monitorIds.size() > 0) {
+            this.monitorIds = new NodeInputList<>(this, monitorIds);
+        }
+
+        if (virtualObjectMappings != null && virtualObjectMappings.size() > 0) {
+            this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
+        }
+
+        this.rethrowException = rethrowException;
+        this.duringCall = duringCall;
+        assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
+        assert this.locksSize() == this.monitorIdCount();
+        FRAMESTATES_COUNTER.increment();
+    }
+
+    public FrameState(FrameState outerFrameState, Bytecode code, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall,
+                    List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) {
+        this(outerFrameState, code, bci, localsSize, stackSize, values.size() - localsSize - stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings);
+        for (int i = 0; i < values.size(); ++i) {
+            this.values.initialize(i, values.get(i));
+        }
+    }
+
+    private void verifyAfterExceptionState() {
+        if (this.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+            assert this.outerFrameState == null;
+            for (int i = 0; i < this.localsSize; i++) {
+                assertTrue(this.values.get(i) == null, "locals should be null in AFTER_EXCEPTION_BCI state");
+            }
+        }
+    }
+
+    public FrameState(int bci) {
+        this(null, null, bci, 0, 0, 0, false, false, null, Collections.<EscapeObjectState> emptyList());
+        assert bci == BytecodeFrame.BEFORE_BCI || bci == BytecodeFrame.AFTER_BCI || bci == BytecodeFrame.AFTER_EXCEPTION_BCI || bci == BytecodeFrame.UNKNOWN_BCI ||
+                        bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
+    }
+
+    /**
+     * Creates a placeholder frame state with a single element on the stack representing a return
+     * value. This allows the parsing of an intrinsic to communicate the returned value in a
+     * {@link StateSplit#stateAfter() stateAfter} to the inlining call site.
+     *
+     * @param bci this must be {@link BytecodeFrame#AFTER_BCI}
+     */
+    public FrameState(int bci, ValueNode returnValue) {
+        this(null, null, bci, 0, returnValue.getStackKind().getSlotCount(), 0, false, false, null, Collections.<EscapeObjectState> emptyList());
+        assert bci == BytecodeFrame.AFTER_BCI;
+        this.values.initialize(0, returnValue);
+    }
+
+    public FrameState(FrameState outerFrameState, Bytecode code, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List<MonitorIdNode> monitorIds,
+                    boolean rethrowException, boolean duringCall) {
+        this(outerFrameState, code, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections.<EscapeObjectState> emptyList());
+        createValues(locals, stack, locks);
+    }
+
+    private void createValues(ValueNode[] locals, ValueNode[] stack, ValueNode[] locks) {
+        int index = 0;
+        for (int i = 0; i < locals.length; ++i) {
+            ValueNode value = locals[i];
+            if (value == TWO_SLOT_MARKER) {
+                value = null;
+            }
+            this.values.initialize(index++, value);
+        }
+        for (int i = 0; i < stackSize; ++i) {
+            ValueNode value = stack[i];
+            if (value == TWO_SLOT_MARKER) {
+                value = null;
+            }
+            this.values.initialize(index++, value);
+        }
+        for (int i = 0; i < locks.length; ++i) {
+            ValueNode value = locks[i];
+            assert value != TWO_SLOT_MARKER;
+            this.values.initialize(index++, value);
+        }
+    }
+
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+
+    public NodeInputList<MonitorIdNode> monitorIds() {
+        return monitorIds;
+    }
+
+    public FrameState outerFrameState() {
+        return outerFrameState;
+    }
+
+    public void setOuterFrameState(FrameState x) {
+        assert x == null || !x.isDeleted();
+        updateUsages(this.outerFrameState, x);
+        this.outerFrameState = x;
+    }
+
+    public static NodeSourcePosition toSourcePosition(FrameState fs) {
+        if (fs == null) {
+            return null;
+        }
+        return new NodeSourcePosition(null, toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci);
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public boolean rethrowException() {
+        return rethrowException;
+    }
+
+    public boolean duringCall() {
+        return duringCall;
+    }
+
+    public Bytecode getCode() {
+        return code;
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return code == null ? null : code.getMethod();
+    }
+
+    /**
+     * Determines if this frame state can be converted to a {@link BytecodeFrame}.
+     *
+     * Since a {@link BytecodeFrame} encodes {@link #getMethod()} and {@link #bci}, it does not
+     * preserve {@link #getCode()}. {@link #bci} is only guaranteed to be valid in terms of
+     * {@code getCode().getCode()} which may be different from {@code getMethod().getCode()} if the
+     * latter has been subject to instrumentation.
+     */
+    public boolean canProduceBytecodeFrame() {
+        return code != null && code.getCode() == code.getMethod().getCode();
+    }
+
+    public void addVirtualObjectMapping(EscapeObjectState virtualObject) {
+        if (virtualObjectMappings == null) {
+            virtualObjectMappings = new NodeInputList<>(this);
+        }
+        virtualObjectMappings.add(virtualObject);
+    }
+
+    public int virtualObjectMappingCount() {
+        if (virtualObjectMappings == null) {
+            return 0;
+        }
+        return virtualObjectMappings.size();
+    }
+
+    public EscapeObjectState virtualObjectMappingAt(int i) {
+        return virtualObjectMappings.get(i);
+    }
+
+    public NodeInputList<EscapeObjectState> virtualObjectMappings() {
+        return virtualObjectMappings;
+    }
+
+    /**
+     * Gets a copy of this frame state.
+     */
+    public FrameState duplicate(int newBci) {
+        return graph().add(new FrameState(outerFrameState(), code, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
+    }
+
+    /**
+     * Gets a copy of this frame state.
+     */
+    public FrameState duplicate() {
+        return duplicate(bci);
+    }
+
+    /**
+     * Duplicates a FrameState, along with a deep copy of all connected VirtualState (outer
+     * FrameStates, VirtualObjectStates, ...).
+     */
+    @Override
+    public FrameState duplicateWithVirtualState() {
+        FrameState newOuterFrameState = outerFrameState();
+        if (newOuterFrameState != null) {
+            newOuterFrameState = newOuterFrameState.duplicateWithVirtualState();
+        }
+        ArrayList<EscapeObjectState> newVirtualMappings = null;
+        if (virtualObjectMappings != null) {
+            newVirtualMappings = new ArrayList<>(virtualObjectMappings.size());
+            for (EscapeObjectState state : virtualObjectMappings) {
+                newVirtualMappings.add(state.duplicateWithVirtualState());
+            }
+        }
+        return graph().add(new FrameState(newOuterFrameState, code, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings));
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type {@code popKind} popped from
+     * the stack.
+     */
+    public FrameState duplicateModifiedDuringCall(int newBci, JavaKind popKind) {
+        return duplicateModified(graph(), newBci, rethrowException, true, popKind, null, null);
+    }
+
+    public FrameState duplicateModifiedBeforeCall(int newBci, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        return duplicateModified(graph(), newBci, rethrowException, false, popKind, pushedSlotKinds, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type {@code popKind} popped from
+     * the stack and the values in {@code pushedValues} pushed on the stack. The
+     * {@code pushedValues} will be formatted correctly in slot encoding: a long or double will be
+     * followed by a null slot.
+     */
+    public FrameState duplicateModified(int newBci, boolean newRethrowException, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedSlotKinds, pushedValues);
+    }
+
+    public FrameState duplicateModified(int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        return duplicateModified(graph(), newBci, newRethrowException, newDuringCall, popKind, pushedSlotKinds, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with the top of stack replaced with with
+     * {@code pushedValue} which must be of type {@code popKind}.
+     */
+    public FrameState duplicateModified(JavaKind popKind, JavaKind pushedSlotKind, ValueNode pushedValue) {
+        assert pushedValue != null && pushedValue.getStackKind() == popKind;
+        return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, new JavaKind[]{pushedSlotKind}, new ValueNode[]{pushedValue});
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type popKind popped from the
+     * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
+     * correctly in slot encoding: a long or double will be followed by a null slot. The bci will be
+     * changed to newBci.
+     */
+    public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        ArrayList<ValueNode> copy;
+        if (newRethrowException && !rethrowException && popKind == JavaKind.Void) {
+            assert popKind == JavaKind.Void;
+            copy = new ArrayList<>(values.subList(0, localsSize));
+        } else {
+            copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
+            if (popKind != JavaKind.Void) {
+                if (stackAt(stackSize() - 1) == null) {
+                    copy.remove(copy.size() - 1);
+                }
+                ValueNode lastSlot = copy.get(copy.size() - 1);
+                assert lastSlot.getStackKind() == popKind.getStackKind();
+                copy.remove(copy.size() - 1);
+            }
+        }
+        if (pushedValues != null) {
+            assert pushedSlotKinds.length == pushedValues.length;
+            for (int i = 0; i < pushedValues.length; i++) {
+                copy.add(pushedValues[i]);
+                if (pushedSlotKinds[i].needsTwoSlots()) {
+                    copy.add(null);
+                }
+            }
+        }
+        int newStackSize = copy.size() - localsSize;
+        copy.addAll(values.subList(localsSize + stackSize, values.size()));
+
+        assert checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException);
+        return graph.add(new FrameState(outerFrameState(), code, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, virtualObjectMappings));
+    }
+
+    /**
+     * Perform a few sanity checks on the transformation of the stack state. The current expectation
+     * is that a stateAfter is being transformed into a stateDuring, so the stack depth may change.
+     */
+    private boolean checkStackDepth(int oldBci, int oldStackSize, boolean oldDuringCall, boolean oldRethrowException, int newBci, int newStackSize, boolean newDuringCall,
+                    boolean newRethrowException) {
+        if (BytecodeFrame.isPlaceholderBci(oldBci)) {
+            return true;
+        }
+        /*
+         * It would be nice to have a complete check of the shape of the FrameState based on a
+         * dataflow of the bytecodes but for now just check for obvious expression stack depth
+         * mistakes.
+         */
+        byte[] codes = code.getCode();
+        if (codes == null) {
+            /* Graph was constructed manually. */
+            return true;
+        }
+        byte newCode = codes[newBci];
+        if (oldBci == newBci) {
+            assert oldStackSize == newStackSize || oldDuringCall != newDuringCall || oldRethrowException != newRethrowException : "bci is unchanged, stack depth shouldn't change";
+        } else {
+            byte oldCode = codes[oldBci];
+            assert Bytecodes.lengthOf(newCode) + newBci == oldBci || Bytecodes.lengthOf(oldCode) + oldBci == newBci : "expecting roll back or forward";
+        }
+        return true;
+    }
+
+    /**
+     * Gets the size of the local variables.
+     */
+    public int localsSize() {
+        return localsSize;
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackSize;
+    }
+
+    /**
+     * Gets the number of locked monitors in this frame state.
+     */
+    public int locksSize() {
+        return values.size() - localsSize - stackSize;
+    }
+
+    /**
+     * Gets the number of locked monitors in this frame state and all {@linkplain #outerFrameState()
+     * outer} frame states.
+     */
+    public int nestedLockDepth() {
+        int depth = locksSize();
+        for (FrameState outer = outerFrameState(); outer != null; outer = outer.outerFrameState()) {
+            depth += outer.locksSize();
+        }
+        return depth;
+    }
+
+    /**
+     * Gets the value in the local variables at the specified index.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public ValueNode localAt(int i) {
+        assert i >= 0 && i < localsSize : "local variable index out of range: " + i;
+        return values.get(i);
+    }
+
+    /**
+     * Get the value on the stack at the specified stack index.
+     *
+     * @param i the index into the stack, with {@code 0} being the bottom of the stack
+     * @return the instruction at the specified position in the stack
+     */
+    public ValueNode stackAt(int i) {
+        assert i >= 0 && i < stackSize;
+        return values.get(localsSize + i);
+    }
+
+    /**
+     * Get the monitor owner at the specified index.
+     *
+     * @param i the index into the list of locked monitors.
+     * @return the lock owner at the given index.
+     */
+    public ValueNode lockAt(int i) {
+        assert i >= 0 && i < locksSize();
+        return values.get(localsSize + stackSize + i);
+    }
+
+    /**
+     * Get the MonitorIdNode that corresponds to the locked object at the specified index.
+     */
+    public MonitorIdNode monitorIdAt(int i) {
+        assert monitorIds != null && i >= 0 && i < locksSize();
+        return monitorIds.get(i);
+    }
+
+    public int monitorIdCount() {
+        if (monitorIds == null) {
+            return 0;
+        } else {
+            return monitorIds.size();
+        }
+    }
+
+    public NodeIterable<FrameState> innerFrameStates() {
+        return usages().filter(FrameState.class);
+    }
+
+    private static String toString(FrameState frameState) {
+        StringBuilder sb = new StringBuilder();
+        String nl = CodeUtil.NEW_LINE;
+        FrameState fs = frameState;
+        while (fs != null) {
+            Bytecode.appendLocation(sb, fs.getCode(), fs.bci);
+            if (BytecodeFrame.isPlaceholderBci(fs.bci)) {
+                sb.append("//").append(getPlaceholderBciName(fs.bci));
+            }
+            sb.append(nl);
+            sb.append("locals: [");
+            for (int i = 0; i < fs.localsSize(); i++) {
+                sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id));
+            }
+            sb.append("]").append(nl).append("stack: [");
+            for (int i = 0; i < fs.stackSize(); i++) {
+                sb.append(i == 0 ? "" : ", ").append(fs.stackAt(i) == null ? "_" : fs.stackAt(i).toString(Verbosity.Id));
+            }
+            sb.append("]").append(nl).append("locks: [");
+            for (int i = 0; i < fs.locksSize(); i++) {
+                sb.append(i == 0 ? "" : ", ").append(fs.lockAt(i) == null ? "_" : fs.lockAt(i).toString(Verbosity.Id));
+            }
+            sb.append(']').append(nl);
+            fs = fs.outerFrameState();
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Debugger) {
+            return toString(this);
+        } else if (verbosity == Verbosity.Name) {
+            String res = super.toString(Verbosity.Name) + "@" + bci;
+            if (BytecodeFrame.isPlaceholderBci(bci)) {
+                res += "[" + getPlaceholderBciName(bci) + "]";
+            }
+            return res;
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> properties = super.getDebugProperties(map);
+        if (code != null) {
+            // properties.put("method", MetaUtil.format("%H.%n(%p):%r", method));
+            StackTraceElement ste = code.asStackTraceElement(bci);
+            if (ste.getFileName() != null && ste.getLineNumber() >= 0) {
+                properties.put("sourceFile", ste.getFileName());
+                properties.put("sourceLine", ste.getLineNumber());
+            }
+        }
+        if (isPlaceholderBci(bci)) {
+            properties.put("bci", getPlaceholderBciName(bci));
+        }
+        properties.put("locksSize", values.size() - stackSize - localsSize);
+        return properties;
+    }
+
+    @Override
+    public boolean verify() {
+        if (virtualObjectMappingCount() > 0) {
+            for (EscapeObjectState state : virtualObjectMappings()) {
+                assertTrue(state != null, "must be non-null");
+            }
+        }
+        /*
+         * The outermost FrameState should have a method that matches StructuredGraph.method except
+         * when it's a substitution or it's null.
+         */
+        assertTrue(outerFrameState != null || graph() == null || graph().method() == null || code == null || Objects.equals(code.getMethod(), graph().method()) ||
+                        graph().method().getAnnotation(MethodSubstitution.class) != null, "wrong outerFrameState %s != %s", code == null ? "null" : code.getMethod(), graph().method());
+        if (monitorIds() != null && monitorIds().size() > 0) {
+            int depth = outerLockDepth();
+            for (MonitorIdNode monitor : monitorIds()) {
+                assertTrue(monitor.getLockDepth() == depth++, "wrong depth");
+            }
+        }
+        assertTrue(locksSize() == monitorIdCount(), "mismatch in number of locks");
+        for (ValueNode value : values) {
+            assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes: %s", value);
+            assertTrue(value == null || value instanceof VirtualObjectNode || (value.getStackKind() != JavaKind.Void), "unexpected value: %s", value);
+        }
+        verifyAfterExceptionState();
+        return super.verify();
+    }
+
+    private int outerLockDepth() {
+        int depth = 0;
+        FrameState outer = outerFrameState;
+        while (outer != null) {
+            depth += outer.monitorIdCount();
+            outer = outer.outerFrameState;
+        }
+        return depth;
+    }
+
+    @Override
+    public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) {
+        for (ValueNode value : values) {
+            if (value != null) {
+                closure.apply(this, value);
+            }
+        }
+
+        if (monitorIds != null) {
+            for (MonitorIdNode monitorId : monitorIds) {
+                if (monitorId != null) {
+                    closure.apply(this, monitorId);
+                }
+            }
+        }
+
+        if (virtualObjectMappings != null) {
+            for (EscapeObjectState state : virtualObjectMappings) {
+                state.applyToNonVirtual(closure);
+            }
+        }
+
+        if (outerFrameState() != null) {
+            outerFrameState().applyToNonVirtual(closure);
+        }
+    }
+
+    @Override
+    public void applyToVirtual(VirtualClosure closure) {
+        closure.apply(this);
+        if (virtualObjectMappings != null) {
+            for (EscapeObjectState state : virtualObjectMappings) {
+                state.applyToVirtual(closure);
+            }
+        }
+        if (outerFrameState() != null) {
+            outerFrameState().applyToVirtual(closure);
+        }
+    }
+
+    @Override
+    public boolean isPartOfThisState(VirtualState state) {
+        if (state == this) {
+            return true;
+        }
+        if (outerFrameState() != null && outerFrameState().isPartOfThisState(state)) {
+            return true;
+        }
+        if (virtualObjectMappings != null) {
+            for (EscapeObjectState objectState : virtualObjectMappings) {
+                if (objectState.isPartOfThisState(state)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FullInfopointNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FullInfopointNode.java
new file mode 100644
index 0000000..c4c1a78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FullInfopointNode.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+
+import jdk.vm.ci.code.site.InfopointReason;
+
+/**
+ * Nodes of this type are inserted into the graph to denote points of interest to debugging.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class FullInfopointNode extends FixedWithNextNode implements LIRLowerable, NodeWithState, Simplifiable {
+    public static final NodeClass<FullInfopointNode> TYPE = NodeClass.create(FullInfopointNode.class);
+    protected final InfopointReason reason;
+    @Input(State) FrameState state;
+    @OptionalInput ValueNode escapedReturnValue;
+
+    public FullInfopointNode(InfopointReason reason, FrameState state, ValueNode escapedReturnValue) {
+        super(TYPE, StampFactory.forVoid());
+        this.reason = reason;
+        this.state = state;
+        this.escapedReturnValue = escapedReturnValue;
+    }
+
+    public InfopointReason getReason() {
+        return reason;
+    }
+
+    private void setEscapedReturnValue(ValueNode x) {
+        updateUsages(escapedReturnValue, x);
+        escapedReturnValue = x;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (escapedReturnValue != null && state != null && state.outerFrameState() != null) {
+            ValueNode returnValue = escapedReturnValue;
+            setEscapedReturnValue(null);
+            tool.removeIfUnused(returnValue);
+        }
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.visitFullInfopointNode(this);
+    }
+
+    public FrameState getState() {
+        return state;
+    }
+
+    @Override
+    public boolean verify() {
+        return state != null && super.verify();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
new file mode 100644
index 0000000..5cee499
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
@@ -0,0 +1,1863 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.util.TypeReader;
+import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.NodeSuccessorList;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.GraphDecoder.MethodScope;
+import org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for
+ * loop explosion during decoding is built into this class, because it requires many interactions
+ * with the decoding process. Subclasses can provide canonicalization and simplification of nodes
+ * during decoding, as well as method inlining during decoding.
+ */
+public class GraphDecoder {
+
+    /** Decoding state maintained for each encoded graph. */
+    protected class MethodScope {
+        /** The loop that contains the call. Only non-null during method inlining. */
+        public final LoopScope callerLoopScope;
+        /** The target graph where decoded nodes are added to. */
+        public final StructuredGraph graph;
+        /**
+         * Mark for nodes that were present before the decoding of this method started. Note that
+         * nodes that were decoded after the mark can still be part of an outer method, since
+         * floating nodes of outer methods are decoded lazily.
+         */
+        public final Graph.Mark methodStartMark;
+        /** The encode graph that is decoded. */
+        public final EncodedGraph encodedGraph;
+        /** Access to the encoded graph. */
+        public final TypeReader reader;
+        /** The kind of loop explosion to be performed during decoding. */
+        public final LoopExplosionKind loopExplosion;
+        /** A list of tasks to run before the method scope is closed. */
+        public final List<Runnable> cleanupTasks;
+
+        /** All return nodes encountered during decoding. */
+        public final List<ReturnNode> returnNodes;
+        /** The exception unwind node encountered during decoding, or null. */
+        public final List<UnwindNode> unwindNodes;
+
+        /** All merges created during loop explosion. */
+        public final NodeBitMap loopExplosionMerges;
+        /**
+         * The start of explosion, and the merge point for when irreducible loops are detected. Only
+         * used when {@link MethodScope#loopExplosion} is {@link LoopExplosionKind#MERGE_EXPLODE}.
+         */
+        public MergeNode loopExplosionHead;
+
+        protected MethodScope(LoopScope callerLoopScope, StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) {
+            this.callerLoopScope = callerLoopScope;
+            this.graph = graph;
+            this.methodStartMark = graph.getMark();
+            this.encodedGraph = encodedGraph;
+            this.loopExplosion = loopExplosion;
+            this.cleanupTasks = new ArrayList<>();
+            this.returnNodes = new ArrayList<>();
+            this.unwindNodes = new ArrayList<>();
+
+            if (encodedGraph != null) {
+                reader = UnsafeArrayTypeReader.create(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), architecture.supportsUnalignedMemoryAccess());
+                if (encodedGraph.nodeStartOffsets == null) {
+                    int nodeCount = reader.getUVInt();
+                    long[] nodeStartOffsets = new long[nodeCount];
+                    for (int i = 0; i < nodeCount; i++) {
+                        nodeStartOffsets[i] = encodedGraph.getStartOffset() - reader.getUV();
+                    }
+                    encodedGraph.nodeStartOffsets = nodeStartOffsets;
+                }
+            } else {
+                reader = null;
+            }
+
+            if (loopExplosion != LoopExplosionKind.NONE) {
+                loopExplosionMerges = new NodeBitMap(graph);
+            } else {
+                loopExplosionMerges = null;
+            }
+        }
+    }
+
+    /** Decoding state maintained for each loop in the encoded graph. */
+    protected static class LoopScope {
+        public final MethodScope methodScope;
+        public final LoopScope outer;
+        public final int loopDepth;
+        public final int loopIteration;
+        /**
+         * Upcoming loop iterations during loop explosions that have not been processed yet. Only
+         * used when {@link MethodScope#loopExplosion} is not {@link LoopExplosionKind#NONE}.
+         */
+        public Deque<LoopScope> nextIterations;
+        /**
+         * Information about already processed loop iterations for state merging during loop
+         * explosion. Only used when {@link MethodScope#loopExplosion} is
+         * {@link LoopExplosionKind#MERGE_EXPLODE}.
+         */
+        public final Map<LoopExplosionState, LoopExplosionState> iterationStates;
+        public final int loopBeginOrderId;
+        /**
+         * The worklist of fixed nodes to process. Since we already the correct processing order
+         * from the orderId, we just set the orderId bit in the bitset when a node is ready for
+         * processing. The lowest set bit is the next node to process.
+         */
+        public final BitSet nodesToProcess;
+        /** Nodes that have been created, indexed by the orderId. */
+        public final Node[] createdNodes;
+        /**
+         * Nodes that have been created in outer loop scopes and existed before starting to process
+         * this loop, indexed by the orderId.
+         */
+        public final Node[] initialCreatedNodes;
+
+        protected LoopScope(MethodScope methodScope) {
+            this.methodScope = methodScope;
+            this.outer = null;
+            this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>() : null;
+            this.loopDepth = 0;
+            this.loopIteration = 0;
+            this.iterationStates = null;
+            this.loopBeginOrderId = -1;
+
+            int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length;
+            this.nodesToProcess = new BitSet(nodeCount);
+            this.initialCreatedNodes = new Node[nodeCount];
+            this.createdNodes = new Node[nodeCount];
+        }
+
+        protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes,
+                        Deque<LoopScope> nextIterations, Map<LoopExplosionState, LoopExplosionState> iterationStates) {
+            this.methodScope = methodScope;
+            this.outer = outer;
+            this.loopDepth = loopDepth;
+            this.loopIteration = loopIteration;
+            this.nextIterations = nextIterations;
+            this.iterationStates = iterationStates;
+            this.loopBeginOrderId = loopBeginOrderId;
+            this.nodesToProcess = new BitSet(initialCreatedNodes.length);
+            this.initialCreatedNodes = initialCreatedNodes;
+            this.createdNodes = Arrays.copyOf(createdNodes, createdNodes.length);
+        }
+
+        @Override
+        public String toString() {
+            return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId);
+        }
+    }
+
+    protected static class LoopExplosionState {
+        public final FrameState state;
+        public final MergeNode merge;
+        public final int hashCode;
+
+        protected LoopExplosionState(FrameState state, MergeNode merge) {
+            this.state = state;
+            this.merge = merge;
+
+            int h = 0;
+            for (ValueNode value : state.values()) {
+                if (value == null) {
+                    h = h * 31 + 1234;
+                } else {
+                    h = h * 31 + ProxyPlaceholder.unwrap(value).hashCode();
+                }
+            }
+            this.hashCode = h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof LoopExplosionState)) {
+                return false;
+            }
+
+            FrameState otherState = ((LoopExplosionState) obj).state;
+            FrameState thisState = state;
+            assert thisState.outerFrameState() == otherState.outerFrameState();
+
+            Iterator<ValueNode> thisIter = thisState.values().iterator();
+            Iterator<ValueNode> otherIter = otherState.values().iterator();
+            while (thisIter.hasNext() && otherIter.hasNext()) {
+                ValueNode thisValue = ProxyPlaceholder.unwrap(thisIter.next());
+                ValueNode otherValue = ProxyPlaceholder.unwrap(otherIter.next());
+                if (thisValue != otherValue) {
+                    return false;
+                }
+            }
+            return thisIter.hasNext() == otherIter.hasNext();
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+    }
+
+    /**
+     * Additional information encoded for {@link Invoke} nodes to allow method inlining without
+     * decoding the frame state and successors beforehand.
+     */
+    protected static class InvokeData {
+        public final Invoke invoke;
+        public final ResolvedJavaType contextType;
+        public final int invokeOrderId;
+        public final int callTargetOrderId;
+        public final int stateAfterOrderId;
+        public final int nextOrderId;
+
+        public final int nextNextOrderId;
+        public final int exceptionOrderId;
+        public final int exceptionStateOrderId;
+        public final int exceptionNextOrderId;
+        public JavaConstant constantReceiver;
+
+        protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, int stateAfterOrderId, int nextOrderId, int nextNextOrderId, int exceptionOrderId,
+                        int exceptionStateOrderId, int exceptionNextOrderId) {
+            this.invoke = invoke;
+            this.contextType = contextType;
+            this.invokeOrderId = invokeOrderId;
+            this.callTargetOrderId = callTargetOrderId;
+            this.stateAfterOrderId = stateAfterOrderId;
+            this.nextOrderId = nextOrderId;
+            this.nextNextOrderId = nextNextOrderId;
+            this.exceptionOrderId = exceptionOrderId;
+            this.exceptionStateOrderId = exceptionStateOrderId;
+            this.exceptionNextOrderId = exceptionNextOrderId;
+        }
+    }
+
+    /**
+     * A node that is created during {@link LoopExplosionKind#MERGE_EXPLODE loop explosion} that can
+     * later be replaced by a ProxyNode if {@link LoopDetector loop detection} finds out that the
+     * value is defined in the loop, but used outside the loop.
+     */
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    protected static final class ProxyPlaceholder extends FloatingNode implements Canonicalizable {
+        public static final NodeClass<ProxyPlaceholder> TYPE = NodeClass.create(ProxyPlaceholder.class);
+
+        @Input ValueNode value;
+        @Input(InputType.Unchecked) Node proxyPoint;
+
+        public ProxyPlaceholder(ValueNode value, MergeNode proxyPoint) {
+            super(TYPE, value.stamp());
+            this.value = value;
+            this.proxyPoint = proxyPoint;
+        }
+
+        void setValue(ValueNode value) {
+            updateUsages(this.value, value);
+            this.value = value;
+        }
+
+        @Override
+        public Node canonical(CanonicalizerTool tool) {
+            if (tool.allUsagesAvailable()) {
+                /* The node is always unnecessary after graph decoding. */
+                return value;
+            } else {
+                return this;
+            }
+        }
+
+        public static ValueNode unwrap(ValueNode value) {
+            ValueNode result = value;
+            while (result instanceof ProxyPlaceholder) {
+                result = ((ProxyPlaceholder) result).value;
+            }
+            return result;
+        }
+    }
+
+    protected final Architecture architecture;
+
+    public GraphDecoder(Architecture architecture) {
+        this.architecture = architecture;
+    }
+
+    @SuppressWarnings("try")
+    public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
+        try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) {
+            MethodScope methodScope = new MethodScope(null, graph, encodedGraph, LoopExplosionKind.NONE);
+            decode(createInitialLoopScope(methodScope, null));
+            cleanupGraph(methodScope);
+            assert methodScope.graph.verify();
+        } catch (Throwable ex) {
+            Debug.handle(ex);
+        }
+    }
+
+    protected final LoopScope createInitialLoopScope(MethodScope methodScope, FixedWithNextNode startNode) {
+        LoopScope loopScope = new LoopScope(methodScope);
+        FixedNode firstNode;
+        if (startNode != null) {
+            /*
+             * The start node of a graph can be referenced as the guard for a GuardedNode. We
+             * register the previous block node, so that such guards are correctly anchored when
+             * doing inlining during graph decoding.
+             */
+            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false);
+
+            firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID);
+            startNode.setNext(firstNode);
+            loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID);
+        } else {
+            firstNode = methodScope.graph.start();
+            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false);
+            loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID);
+        }
+
+        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+            methodScope.cleanupTasks.add(new LoopDetector(methodScope, startNode));
+        }
+        return loopScope;
+    }
+
+    protected final void decode(LoopScope initialLoopScope) {
+        LoopScope loopScope = initialLoopScope;
+        /* Process inlined methods. */
+        while (loopScope != null) {
+            MethodScope methodScope = loopScope.methodScope;
+
+            /* Process loops of method. */
+            while (loopScope != null) {
+
+                /* Process nodes of loop. */
+                while (!loopScope.nodesToProcess.isEmpty()) {
+                    loopScope = processNextNode(methodScope, loopScope);
+                    methodScope = loopScope.methodScope;
+                    /*
+                     * We can have entered a new loop, and we can have entered a new inlined method.
+                     */
+                }
+
+                /* Finished with a loop. */
+                if (loopScope.nextIterations != null && !loopScope.nextIterations.isEmpty()) {
+                    /* Loop explosion: process the loop iteration. */
+                    assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1;
+                    loopScope = loopScope.nextIterations.removeFirst();
+                } else {
+                    propagateCreatedNodes(loopScope);
+                    loopScope = loopScope.outer;
+                }
+            }
+
+            /*
+             * Finished with an inlined method. Perform all registered end-of-method cleanup tasks
+             * and continue with loop that contained the call.
+             */
+            for (Runnable task : methodScope.cleanupTasks) {
+                task.run();
+            }
+            loopScope = methodScope.callerLoopScope;
+        }
+    }
+
+    private static void propagateCreatedNodes(LoopScope loopScope) {
+        if (loopScope.outer == null) {
+            return;
+        }
+
+        /* Register nodes that were created while decoding the loop to the outside scope. */
+        for (int i = 0; i < loopScope.createdNodes.length; i++) {
+            if (loopScope.outer.createdNodes[i] == null) {
+                loopScope.outer.createdNodes[i] = loopScope.createdNodes[i];
+            }
+        }
+    }
+
+    protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) {
+        int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0);
+        loopScope.nodesToProcess.clear(nodeOrderId);
+
+        FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId);
+        if (node.isDeleted()) {
+            return loopScope;
+        }
+
+        if ((node instanceof MergeNode ||
+                        (node instanceof LoopBeginNode && (methodScope.loopExplosion == LoopExplosionKind.FULL_UNROLL || methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE ||
+                                        methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN))) &&
+                        ((AbstractMergeNode) node).forwardEndCount() == 1) {
+            AbstractMergeNode merge = (AbstractMergeNode) node;
+            EndNode singleEnd = merge.forwardEndAt(0);
+
+            /* Nodes that would use this merge as the guard need to use the previous block. */
+            registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
+
+            FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET);
+            singleEnd.replaceAtPredecessor(next);
+
+            merge.safeDelete();
+            singleEnd.safeDelete();
+            return loopScope;
+        }
+
+        LoopScope successorAddScope = loopScope;
+        boolean updatePredecessors = true;
+        if (node instanceof LoopExitNode) {
+            if (methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN || (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth > 1)) {
+                /*
+                 * We do not want to merge loop exits of inner loops. Instead, we want to keep
+                 * exploding the outer loop separately for every loop exit and then merge the outer
+                 * loop. Therefore, we create a new LoopScope of the outer loop for every loop exit
+                 * of the inner loop.
+                 */
+                LoopScope outerScope = loopScope.outer;
+                int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1;
+                successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes,
+                                loopScope.initialCreatedNodes, outerScope.nextIterations, outerScope.iterationStates);
+                checkLoopExplosionIteration(methodScope, successorAddScope);
+
+                /*
+                 * Nodes that are still unprocessed in the outer scope might be merge nodes that are
+                 * also reachable from the new exploded scope. Clearing them ensures that we do not
+                 * merge, but instead keep exploding.
+                 */
+                for (int id = outerScope.nodesToProcess.nextSetBit(0); id >= 0; id = outerScope.nodesToProcess.nextSetBit(id + 1)) {
+                    successorAddScope.createdNodes[id] = null;
+                }
+
+                outerScope.nextIterations.addLast(successorAddScope);
+            } else {
+                successorAddScope = loopScope.outer;
+            }
+            updatePredecessors = methodScope.loopExplosion == LoopExplosionKind.NONE;
+        }
+
+        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
+        int typeId = methodScope.reader.getUVInt();
+        assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId];
+        readProperties(methodScope, node);
+        makeSuccessorStubs(methodScope, successorAddScope, node, updatePredecessors);
+        makeInputNodes(methodScope, loopScope, node, true);
+
+        LoopScope resultScope = loopScope;
+        if (node instanceof LoopBeginNode) {
+            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+                handleLoopExplosionBegin(methodScope, loopScope, (LoopBeginNode) node);
+            }
+
+        } else if (node instanceof LoopExitNode) {
+            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+                handleLoopExplosionProxyNodes(methodScope, loopScope, successorAddScope, (LoopExitNode) node, nodeOrderId);
+            } else {
+                handleProxyNodes(methodScope, loopScope, (LoopExitNode) node);
+            }
+
+        } else if (node instanceof MergeNode) {
+            handleMergeNode(((MergeNode) node));
+
+        } else if (node instanceof AbstractEndNode) {
+            LoopScope phiInputScope = loopScope;
+            LoopScope phiNodeScope = loopScope;
+
+            if (methodScope.loopExplosion != LoopExplosionKind.NONE && node instanceof LoopEndNode) {
+                node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node);
+                phiNodeScope = loopScope.nextIterations.getLast();
+            }
+
+            int mergeOrderId = readOrderId(methodScope);
+            AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId);
+            if (merge == null) {
+                merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId);
+
+                if (merge instanceof LoopBeginNode) {
+                    assert phiNodeScope == phiInputScope && phiNodeScope == loopScope;
+                    resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId,
+                                    Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length), loopScope.createdNodes, //
+                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>() : null, //
+                                    methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? new HashMap<>() : null);
+                    phiInputScope = resultScope;
+                    phiNodeScope = resultScope;
+
+                    registerNode(loopScope, mergeOrderId, null, true, true);
+                    loopScope.nodesToProcess.clear(mergeOrderId);
+                    resultScope.nodesToProcess.set(mergeOrderId);
+                }
+            }
+
+            handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge);
+
+        } else if (node instanceof Invoke) {
+            InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
+            resultScope = handleInvoke(methodScope, loopScope, invokeData);
+
+        } else if (node instanceof ReturnNode) {
+            methodScope.returnNodes.add((ReturnNode) node);
+        } else if (node instanceof UnwindNode) {
+            methodScope.unwindNodes.add((UnwindNode) node);
+
+        } else {
+            handleFixedNode(methodScope, loopScope, nodeOrderId, node);
+        }
+
+        return resultScope;
+    }
+
+    private InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
+        ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope);
+        int callTargetOrderId = readOrderId(methodScope);
+        int stateAfterOrderId = readOrderId(methodScope);
+        int nextOrderId = readOrderId(methodScope);
+
+        if (invoke instanceof InvokeWithExceptionNode) {
+            int nextNextOrderId = readOrderId(methodScope);
+            int exceptionOrderId = readOrderId(methodScope);
+            int exceptionStateOrderId = readOrderId(methodScope);
+            int exceptionNextOrderId = readOrderId(methodScope);
+            return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, nextNextOrderId, exceptionOrderId, exceptionStateOrderId,
+                            exceptionNextOrderId);
+        } else {
+            return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, -1, -1, -1, -1);
+        }
+    }
+
+    /**
+     * {@link Invoke} nodes do not have the {@link CallTargetNode}, {@link FrameState}, and
+     * successors encoded. Instead, this information is provided separately to allow method inlining
+     * without decoding and adding them to the graph upfront. For non-inlined methods, this method
+     * restores the normal state. Subclasses can override it to perform method inlining.
+     *
+     * The return value is the loop scope where decoding should continue. When method inlining
+     * should be performed, the returned loop scope must be a new loop scope for the inlined method.
+     * Without inlining, the original loop scope must be returned.
+     */
+    protected LoopScope handleInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
+        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
+        CallTargetNode callTarget = (CallTargetNode) ensureNodeCreated(methodScope, loopScope, invokeData.callTargetOrderId);
+        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            ((InvokeWithExceptionNode) invokeData.invoke).setCallTarget(callTarget);
+        } else {
+            ((InvokeNode) invokeData.invoke).setCallTarget(callTarget);
+        }
+
+        assert invokeData.invoke.stateAfter() == null && invokeData.invoke.stateDuring() == null : "FrameState edges are ignored during decoding of Invoke";
+        invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
+
+        invokeData.invoke.setNext(makeStubNode(methodScope, loopScope, invokeData.nextOrderId));
+        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            ((InvokeWithExceptionNode) invokeData.invoke).setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId));
+        }
+        return loopScope;
+    }
+
+    /**
+     * Hook for subclasses to perform simplifications for a non-loop-header control flow merge.
+     *
+     * @param merge The control flow merge.
+     */
+    protected void handleMergeNode(MergeNode merge) {
+    }
+
+    protected void handleLoopExplosionBegin(MethodScope methodScope, LoopScope loopScope, LoopBeginNode loopBegin) {
+        checkLoopExplosionIteration(methodScope, loopScope);
+
+        List<EndNode> predecessors = loopBegin.forwardEnds().snapshot();
+        FixedNode successor = loopBegin.next();
+        FrameState frameState = loopBegin.stateAfter();
+
+        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+            LoopExplosionState queryState = new LoopExplosionState(frameState, null);
+            LoopExplosionState existingState = loopScope.iterationStates.get(queryState);
+            if (existingState != null) {
+                loopBegin.replaceAtUsagesAndDelete(existingState.merge);
+                successor.safeDelete();
+                for (EndNode predecessor : predecessors) {
+                    existingState.merge.addForwardEnd(predecessor);
+                }
+                return;
+            }
+        }
+
+        MergeNode merge = methodScope.graph.add(new MergeNode());
+        methodScope.loopExplosionMerges.markAndGrow(merge);
+
+        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+            if (loopScope.iterationStates.size() == 0 && loopScope.loopDepth == 1) {
+                if (methodScope.loopExplosionHead != null) {
+                    throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion must not have more than one top-level loop", LoopExplosionKind.MERGE_EXPLODE);
+                }
+                methodScope.loopExplosionHead = merge;
+            }
+
+            List<ValueNode> newFrameStateValues = new ArrayList<>();
+            for (ValueNode frameStateValue : frameState.values) {
+                if (frameStateValue == null || frameStateValue.isConstant() || !methodScope.graph.isNew(methodScope.methodStartMark, frameStateValue)) {
+                    newFrameStateValues.add(frameStateValue);
+
+                } else {
+                    ProxyPlaceholder newFrameStateValue = methodScope.graph.unique(new ProxyPlaceholder(frameStateValue, merge));
+                    newFrameStateValues.add(newFrameStateValue);
+
+                    /*
+                     * We do not have the orderID of the value anymore, so we need to search through
+                     * the complete list of nodes to find a match.
+                     */
+                    for (int i = 0; i < loopScope.createdNodes.length; i++) {
+                        if (loopScope.createdNodes[i] == frameStateValue) {
+                            loopScope.createdNodes[i] = newFrameStateValue;
+                        }
+                        if (loopScope.initialCreatedNodes[i] == frameStateValue) {
+                            loopScope.initialCreatedNodes[i] = newFrameStateValue;
+                        }
+                    }
+                }
+            }
+
+            FrameState newFrameState = methodScope.graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(),
+                            frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings()));
+
+            frameState.replaceAtUsages(newFrameState);
+            frameState.safeDelete();
+            frameState = newFrameState;
+        }
+
+        loopBegin.replaceAtUsagesAndDelete(merge);
+        merge.setStateAfter(frameState);
+        merge.setNext(successor);
+        for (EndNode predecessor : predecessors) {
+            merge.addForwardEnd(predecessor);
+        }
+
+        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+            LoopExplosionState explosionState = new LoopExplosionState(frameState, merge);
+            loopScope.iterationStates.put(explosionState, explosionState);
+        }
+    }
+
+    /**
+     * Hook for subclasses.
+     *
+     * @param methodScope The current method.
+     * @param loopScope The current loop.
+     */
+    protected void checkLoopExplosionIteration(MethodScope methodScope, LoopScope loopScope) {
+        throw shouldNotReachHere("when subclass uses loop explosion, it needs to implement this method");
+    }
+
+    protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) {
+        EndNode replacementNode = methodScope.graph.add(new EndNode());
+        loopEnd.replaceAtPredecessor(replacementNode);
+        loopEnd.safeDelete();
+
+        assert methodScope.loopExplosion != LoopExplosionKind.NONE;
+        if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) {
+            int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
+            LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes,
+                            loopScope.initialCreatedNodes, loopScope.nextIterations, loopScope.iterationStates);
+            checkLoopExplosionIteration(methodScope, nextIterationScope);
+            loopScope.nextIterations.addLast(nextIterationScope);
+            registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true);
+            makeStubNode(methodScope, nextIterationScope, loopScope.loopBeginOrderId);
+        }
+        return replacementNode;
+    }
+
+    /**
+     * Hook for subclasses.
+     *
+     * @param methodScope The current method.
+     * @param loopScope The current loop.
+     * @param nodeOrderId The orderId of the node.
+     * @param node The node to be simplified.
+     */
+    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+    }
+
+    protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) {
+        assert loopExit.stateAfter() == null;
+        int stateAfterOrderId = readOrderId(methodScope);
+        loopExit.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId));
+
+        int numProxies = methodScope.reader.getUVInt();
+        for (int i = 0; i < numProxies; i++) {
+            int proxyOrderId = readOrderId(methodScope);
+            ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId);
+            /*
+             * The ProxyNode transports a value from the loop to the outer scope. We therefore
+             * register it in the outer scope.
+             */
+            registerNode(loopScope.outer, proxyOrderId, proxy, false, false);
+        }
+    }
+
+    protected void handleLoopExplosionProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopScope outerScope, LoopExitNode loopExit, int loopExitOrderId) {
+        assert loopExit.stateAfter() == null;
+        int stateAfterOrderId = readOrderId(methodScope);
+
+        BeginNode begin = methodScope.graph.add(new BeginNode());
+
+        FixedNode loopExitSuccessor = loopExit.next();
+        loopExit.replaceAtPredecessor(begin);
+
+        MergeNode loopExitPlaceholder = null;
+        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth == 1) {
+            /*
+             * This exit might end up as a loop exit of a loop detected after partial evaluation. We
+             * need to be able to create a FrameState and the necessary proxy nodes in this case.
+             */
+            loopExitPlaceholder = methodScope.graph.add(new MergeNode());
+            methodScope.loopExplosionMerges.markAndGrow(loopExitPlaceholder);
+
+            EndNode end = methodScope.graph.add(new EndNode());
+            begin.setNext(end);
+            loopExitPlaceholder.addForwardEnd(end);
+
+            begin = methodScope.graph.add(new BeginNode());
+            loopExitPlaceholder.setNext(begin);
+        }
+
+        /*
+         * In the original graph, the loop exit is not a merge node. Multiple exploded loop
+         * iterations now take the same loop exit, so we have to introduce a new merge node to
+         * handle the merge.
+         */
+        MergeNode merge = null;
+        Node existingExit = lookupNode(outerScope, loopExitOrderId);
+        if (existingExit == null) {
+            /* First loop iteration that exits. No merge necessary yet. */
+            registerNode(outerScope, loopExitOrderId, begin, false, false);
+            begin.setNext(loopExitSuccessor);
+
+        } else if (existingExit instanceof BeginNode) {
+            /* Second loop iteration that exits. Create the merge. */
+            merge = methodScope.graph.add(new MergeNode());
+            registerNode(outerScope, loopExitOrderId, merge, true, false);
+            /* Add the first iteration. */
+            EndNode firstEnd = methodScope.graph.add(new EndNode());
+            ((BeginNode) existingExit).setNext(firstEnd);
+            merge.addForwardEnd(firstEnd);
+            merge.setNext(loopExitSuccessor);
+
+        } else {
+            /* Subsequent loop iteration. Merge already created. */
+            merge = (MergeNode) existingExit;
+        }
+
+        if (merge != null) {
+            EndNode end = methodScope.graph.add(new EndNode());
+            begin.setNext(end);
+            merge.addForwardEnd(end);
+        }
+
+        /*
+         * Possibly create phi nodes for the original proxy nodes that flow out of the loop. Note
+         * that we definitely do not need a proxy node itself anymore, since the loop was exploded
+         * and is no longer present.
+         */
+        int numProxies = methodScope.reader.getUVInt();
+        boolean phiCreated = false;
+        for (int i = 0; i < numProxies; i++) {
+            int proxyOrderId = readOrderId(methodScope);
+            ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId);
+            ValueNode phiInput = proxy.value();
+
+            if (loopExitPlaceholder != null) {
+                if (!phiInput.isConstant()) {
+                    phiInput = methodScope.graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder));
+                }
+                registerNode(loopScope, proxyOrderId, phiInput, true, false);
+            }
+
+            ValueNode replacement;
+            ValueNode existing = (ValueNode) outerScope.createdNodes[proxyOrderId];
+            if (existing == null || existing == phiInput) {
+                /*
+                 * We are at the first loop exit, or the proxy carries the same value for all exits.
+                 * We do not need a phi node yet.
+                 */
+                registerNode(outerScope, proxyOrderId, phiInput, true, false);
+                replacement = phiInput;
+
+            } else if (!merge.isPhiAtMerge(existing)) {
+                /* Now we have two different values, so we need to create a phi node. */
+                PhiNode phi = methodScope.graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge));
+                /* Add the inputs from all previous exits. */
+                for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
+                    phi.addInput(existing);
+                }
+                /* Add the input from this exit. */
+                phi.addInput(phiInput);
+                registerNode(outerScope, proxyOrderId, phi, true, false);
+                replacement = phi;
+                phiCreated = true;
+
+            } else {
+                /* Phi node has been created before, so just add the new input. */
+                PhiNode phi = (PhiNode) existing;
+                phi.addInput(phiInput);
+                replacement = phi;
+            }
+
+            proxy.replaceAtUsagesAndDelete(replacement);
+        }
+
+        if (loopExitPlaceholder != null) {
+            registerNode(loopScope, stateAfterOrderId, null, true, true);
+            loopExitPlaceholder.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId));
+        }
+
+        if (merge != null && (merge.stateAfter() == null || phiCreated)) {
+            FrameState oldStateAfter = merge.stateAfter();
+            registerNode(outerScope, stateAfterOrderId, null, true, true);
+            merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, outerScope, stateAfterOrderId));
+            if (oldStateAfter != null) {
+                oldStateAfter.safeDelete();
+            }
+        }
+        loopExit.safeDelete();
+        assert loopExitSuccessor.predecessor() == null;
+        if (merge != null) {
+            merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor);
+        } else {
+            begin.getNodeClass().getSuccessorEdges().update(begin, null, loopExitSuccessor);
+        }
+    }
+
+    protected void handlePhiFunctions(MethodScope methodScope, LoopScope phiInputScope, LoopScope phiNodeScope, AbstractEndNode end, AbstractMergeNode merge) {
+
+        if (end instanceof LoopEndNode) {
+            /*
+             * Fix the loop end index and the number of loop ends. When we do canonicalization
+             * during decoding, we can end up with fewer ends than the encoded graph had. And the
+             * order of loop ends can be different.
+             */
+            int numEnds = ((LoopBeginNode) merge).loopEnds().count();
+            ((LoopBeginNode) merge).nextEndIndex = numEnds;
+            ((LoopEndNode) end).endIndex = numEnds - 1;
+
+        } else {
+            if (merge.ends == null) {
+                merge.ends = new NodeInputList<>(merge);
+            }
+            merge.addForwardEnd((EndNode) end);
+        }
+
+        /*
+         * We create most phi functions lazily. Canonicalization and simplification during decoding
+         * can lead to dead branches that are not decoded, so we might not need all phi functions
+         * that the original graph contained. Since we process all predecessors before actually
+         * processing the merge node, we have the final phi function when processing the merge node.
+         * The only exception are loop headers of non-exploded loops: since backward branches are
+         * not processed yet when processing the loop body, we need to create all phi functions
+         * upfront.
+         */
+        boolean lazyPhi = allowLazyPhis() && (!(merge instanceof LoopBeginNode) || methodScope.loopExplosion != LoopExplosionKind.NONE);
+        int numPhis = methodScope.reader.getUVInt();
+        for (int i = 0; i < numPhis; i++) {
+            int phiInputOrderId = readOrderId(methodScope);
+            int phiNodeOrderId = readOrderId(methodScope);
+
+            ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId);
+
+            ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
+            if (lazyPhi && (existing == null || existing == phiInput)) {
+                /* Phi function not yet necessary. */
+                registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false);
+
+            } else if (!merge.isPhiAtMerge(existing)) {
+                /*
+                 * Phi function is necessary. Create it and fill it with existing inputs as well as
+                 * the new input.
+                 */
+                registerNode(phiNodeScope, phiNodeOrderId, null, true, true);
+                PhiNode phi = (PhiNode) ensureNodeCreated(methodScope, phiNodeScope, phiNodeOrderId);
+
+                phi.setMerge(merge);
+                for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
+                    phi.addInput(existing);
+                }
+                phi.addInput(phiInput);
+
+            } else {
+                /* Phi node has been created before, so just add the new input. */
+                PhiNode phi = (PhiNode) existing;
+                phi.addInput(phiInput);
+            }
+        }
+    }
+
+    protected boolean allowLazyPhis() {
+        /* We need to exactly reproduce the encoded graph, including unnecessary phi functions. */
+        return false;
+    }
+
+    protected Node instantiateNode(MethodScope methodScope, int nodeOrderId) {
+        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
+        NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
+        return nodeClass.allocateInstance();
+    }
+
+    protected void readProperties(MethodScope methodScope, Node node) {
+        node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope));
+        Fields fields = node.getNodeClass().getData();
+        for (int pos = 0; pos < fields.getCount(); pos++) {
+            if (fields.getType(pos).isPrimitive()) {
+                long primitive = methodScope.reader.getSV();
+                fields.setRawPrimitive(node, pos, primitive);
+            } else {
+                Object value = readObject(methodScope);
+                fields.set(node, pos, value);
+            }
+        }
+    }
+
+    /**
+     * Process the input edges of a node. Input nodes that have not yet been created must be
+     * non-fixed nodes (because fixed nodes are processed in reverse postorder. Such non-fixed nodes
+     * are created on demand (recursively since they can themselves reference not yet created
+     * nodes).
+     */
+    protected void makeInputNodes(MethodScope methodScope, LoopScope loopScope, Node node, boolean updateUsages) {
+        Edges edges = node.getNodeClass().getEdges(Edges.Type.Inputs);
+        for (int index = 0; index < edges.getDirectCount(); index++) {
+            if (skipEdge(node, edges, index, true, true)) {
+                continue;
+            }
+            int orderId = readOrderId(methodScope);
+            Node value = ensureNodeCreated(methodScope, loopScope, orderId);
+            edges.initializeNode(node, index, value);
+            if (updateUsages && value != null && !value.isDeleted()) {
+                edges.update(node, null, value);
+
+            }
+        }
+        for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
+            if (skipEdge(node, edges, index, false, true)) {
+                continue;
+            }
+            int size = methodScope.reader.getSVInt();
+            if (size != -1) {
+                NodeList<Node> nodeList = new NodeInputList<>(node, size);
+                edges.initializeList(node, index, nodeList);
+                for (int idx = 0; idx < size; idx++) {
+                    int orderId = readOrderId(methodScope);
+                    Node value = ensureNodeCreated(methodScope, loopScope, orderId);
+                    nodeList.initialize(idx, value);
+                    if (updateUsages && value != null && !value.isDeleted()) {
+                        edges.update(node, null, value);
+                    }
+                }
+            }
+        }
+    }
+
+    protected Node ensureNodeCreated(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
+        if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) {
+            return null;
+        }
+        Node node = lookupNode(loopScope, nodeOrderId);
+        if (node != null) {
+            return node;
+        }
+
+        node = decodeFloatingNode(methodScope, loopScope, nodeOrderId);
+
+        if (node instanceof ProxyNode || node instanceof PhiNode) {
+            /*
+             * We need these nodes as they were in the original graph, without any canonicalization
+             * or value numbering.
+             */
+            node = methodScope.graph.addWithoutUnique(node);
+        } else {
+            /* Allow subclasses to canonicalize and intercept nodes. */
+            node = handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
+            if (!node.isAlive()) {
+                node = addFloatingNode(methodScope, node);
+            }
+            node = handleFloatingNodeAfterAdd(methodScope, loopScope, node);
+        }
+        registerNode(loopScope, nodeOrderId, node, false, false);
+        return node;
+    }
+
+    protected Node addFloatingNode(MethodScope methodScope, Node node) {
+        /*
+         * We want to exactly reproduce the encoded graph. Even though nodes should be unique in the
+         * encoded graph, this is not always guaranteed.
+         */
+        return methodScope.graph.addWithoutUnique(node);
+    }
+
+    /**
+     * Decodes a non-fixed node, but does not do any post-processing and does not register it.
+     */
+    protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
+        long readerByteIndex = methodScope.reader.getByteIndex();
+        Node node = instantiateNode(methodScope, nodeOrderId);
+        if (node instanceof FixedNode) {
+            /*
+             * This is a severe error that will lead to a corrupted graph, so it is better not to
+             * continue decoding at all.
+             */
+            throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
+        }
+
+        /* Read the properties of the node. */
+        readProperties(methodScope, node);
+        /* There must not be any successors to read, since it is a non-fixed node. */
+        assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0;
+        /* Read the inputs of the node, possibly creating them recursively. */
+        makeInputNodes(methodScope, loopScope, node, false);
+        methodScope.reader.setByteIndex(readerByteIndex);
+        return node;
+    }
+
+    /**
+     * Hook for subclasses to process a non-fixed node before it is added to the graph.
+     *
+     * @param methodScope The current method.
+     * @param loopScope The current loop.
+     * @param node The node to be canonicalized.
+     * @return The replacement for the node, or the node itself.
+     */
+    protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
+        return node;
+    }
+
+    /**
+     * Hook for subclasses to process a non-fixed node after it is added to the graph.
+     *
+     * If this method replaces a node with another node, it must update its source position if the
+     * original node has the source position set.
+     *
+     * @param methodScope The current method.
+     * @param loopScope The current loop.
+     * @param node The node to be canonicalized.
+     * @return The replacement for the node, or the node itself.
+     */
+    protected Node handleFloatingNodeAfterAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
+        return node;
+    }
+
+    /**
+     * Process successor edges of a node. We create the successor nodes so that we can fill the
+     * successor list, but no properties or edges are loaded yet. That is done when the successor is
+     * on top of the worklist in {@link #processNextNode}.
+     */
+    protected void makeSuccessorStubs(MethodScope methodScope, LoopScope loopScope, Node node, boolean updatePredecessors) {
+        Edges edges = node.getNodeClass().getEdges(Edges.Type.Successors);
+        for (int index = 0; index < edges.getDirectCount(); index++) {
+            if (skipEdge(node, edges, index, true, true)) {
+                continue;
+            }
+            int orderId = readOrderId(methodScope);
+            Node value = makeStubNode(methodScope, loopScope, orderId);
+            edges.initializeNode(node, index, value);
+            if (updatePredecessors && value != null) {
+                edges.update(node, null, value);
+            }
+        }
+        for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
+            if (skipEdge(node, edges, index, false, true)) {
+                continue;
+            }
+            int size = methodScope.reader.getSVInt();
+            if (size != -1) {
+                NodeList<Node> nodeList = new NodeSuccessorList<>(node, size);
+                edges.initializeList(node, index, nodeList);
+                for (int idx = 0; idx < size; idx++) {
+                    int orderId = readOrderId(methodScope);
+                    Node value = makeStubNode(methodScope, loopScope, orderId);
+                    nodeList.initialize(idx, value);
+                    if (updatePredecessors && value != null) {
+                        edges.update(node, null, value);
+                    }
+                }
+            }
+        }
+    }
+
+    protected FixedNode makeStubNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
+        if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) {
+            return null;
+        }
+        FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId);
+        if (node != null) {
+            return node;
+        }
+
+        long readerByteIndex = methodScope.reader.getByteIndex();
+        node = (FixedNode) methodScope.graph.add(instantiateNode(methodScope, nodeOrderId));
+        /* Properties and edges are not filled yet, the node remains uninitialized. */
+        methodScope.reader.setByteIndex(readerByteIndex);
+
+        registerNode(loopScope, nodeOrderId, node, false, false);
+        loopScope.nodesToProcess.set(nodeOrderId);
+        return node;
+    }
+
+    /**
+     * Returns false for {@link Edges} that are not necessary in the encoded graph because they are
+     * reconstructed using other sources of information.
+     */
+    protected static boolean skipEdge(Node node, Edges edges, int index, boolean direct, boolean decode) {
+        if (node instanceof PhiNode) {
+            /* The inputs of phi functions are filled manually when the end nodes are processed. */
+            assert edges.type() == Edges.Type.Inputs;
+            if (direct) {
+                assert index == edges.getDirectCount() - 1 : "PhiNode has one direct input (the MergeNode)";
+            } else {
+                assert index == edges.getCount() - 1 : "PhiNode has one variable size input (the values)";
+                if (decode) {
+                    /* The values must not be null, so initialize with an empty list. */
+                    edges.initializeList(node, index, new NodeInputList<>(node));
+                }
+            }
+            return true;
+
+        } else if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs && !direct) {
+            /* The ends of merge nodes are filled manually when the ends are processed. */
+            assert index == edges.getCount() - 1 : "MergeNode has one variable size input (the ends)";
+            assert Edges.getNodeList(node, edges.getOffsets(), index) != null : "Input list must have been already created";
+            return true;
+
+        } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) {
+            /* The stateAfter of the loop exit is filled manually. */
+            return true;
+
+        } else if (node instanceof Invoke) {
+            assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode : "The only two Invoke node classes. Got " + node.getClass();
+            assert direct : "Invoke and InvokeWithException only have direct successor and input edges";
+            if (edges.type() == Edges.Type.Successors) {
+                assert edges.getCount() == (node instanceof InvokeWithExceptionNode ? 2 : 1) : "InvokeNode has one successor (next); InvokeWithExceptionNode has two successors (next, exceptionEdge)";
+                return true;
+            } else {
+                assert edges.type() == Edges.Type.Inputs;
+                if (edges.getType(index) == CallTargetNode.class) {
+                    return true;
+                } else if (edges.getType(index) == FrameState.class) {
+                    assert edges.get(node, index) == null || edges.get(node, index) == ((Invoke) node).stateAfter() : "Only stateAfter can be a FrameState during encoding";
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    protected Node lookupNode(LoopScope loopScope, int nodeOrderId) {
+        return loopScope.createdNodes[nodeOrderId];
+    }
+
+    protected void registerNode(LoopScope loopScope, int nodeOrderId, Node node, boolean allowOverwrite, boolean allowNull) {
+        assert node == null || node.isAlive();
+        assert allowNull || node != null;
+        assert allowOverwrite || lookupNode(loopScope, nodeOrderId) == null;
+        loopScope.createdNodes[nodeOrderId] = node;
+    }
+
+    protected int readOrderId(MethodScope methodScope) {
+        return methodScope.reader.getUVInt();
+    }
+
+    protected Object readObject(MethodScope methodScope) {
+        return methodScope.encodedGraph.getObjects()[methodScope.reader.getUVInt()];
+    }
+
+    /**
+     * Removes unnecessary nodes from the graph after decoding.
+     *
+     * @param methodScope The current method.
+     */
+    protected void cleanupGraph(MethodScope methodScope) {
+        assert verifyEdges(methodScope);
+    }
+
+    protected boolean verifyEdges(MethodScope methodScope) {
+        for (Node node : methodScope.graph.getNodes()) {
+            assert node.isAlive();
+            for (Node i : node.inputs()) {
+                assert i.isAlive();
+                assert i.usages().contains(node);
+            }
+            for (Node s : node.successors()) {
+                assert s.isAlive();
+                assert s.predecessor() == node;
+            }
+
+            for (Node usage : node.usages()) {
+                assert usage.isAlive();
+                assert usage.inputs().contains(node) : node + " / " + usage + " / " + usage.inputs().count();
+            }
+            if (node.predecessor() != null) {
+                assert node.predecessor().isAlive();
+                assert node.predecessor().successors().contains(node);
+            }
+        }
+        return true;
+    }
+}
+
+class LoopDetector implements Runnable {
+
+    /**
+     * Information about loops before the actual loop nodes are inserted.
+     */
+    static class Loop {
+        /**
+         * The header, i.e., the target of backward branches.
+         */
+        MergeNode header;
+        /**
+         * The ends, i.e., the source of backward branches. The {@link EndNode#successors successor}
+         * is the {@link #header loop header}.
+         */
+        List<EndNode> ends = new ArrayList<>();
+        /**
+         * Exits of the loop. The successor is a {@link MergeNode} marked in
+         * {@link MethodScope#loopExplosionMerges}.
+         */
+        List<AbstractEndNode> exits = new ArrayList<>();
+        /**
+         * Set to true when the loop is irreducible, i.e., has multiple entries. See
+         * {@link #handleIrreducibleLoop} for details on the handling.
+         */
+        boolean irreducible;
+    }
+
+    private final MethodScope methodScope;
+    private final FixedNode startInstruction;
+
+    private Loop irreducibleLoopHandler;
+    private IntegerSwitchNode irreducibleLoopSwitch;
+
+    protected LoopDetector(MethodScope methodScope, FixedNode startInstruction) {
+        this.methodScope = methodScope;
+        this.startInstruction = startInstruction;
+    }
+
+    @Override
+    public void run() {
+        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "Before loop detection");
+
+        List<Loop> orderedLoops = findLoops();
+        assert orderedLoops.get(orderedLoops.size() - 1) == irreducibleLoopHandler : "outermost loop must be the last element in the list";
+
+        for (Loop loop : orderedLoops) {
+            if (loop.ends.isEmpty()) {
+                assert loop == irreducibleLoopHandler;
+                continue;
+            }
+
+            /*
+             * The algorithm to find loop exits requires that inner loops have already been
+             * processed. Therefore, we need to iterate the loops in order (inner loops before outer
+             * loops), and we cannot find the exits for all loops before we start inserting nodes.
+             */
+            findLoopExits(loop);
+
+            if (loop.irreducible) {
+                handleIrreducibleLoop(loop);
+            } else {
+                insertLoopNodes(loop);
+            }
+            Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After handling of loop %s", loop.header);
+        }
+
+        logIrreducibleLoops();
+        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After loop detection");
+    }
+
+    private List<Loop> findLoops() {
+        /* Mapping from the loop header node to additional loop information. */
+        Map<MergeNode, Loop> unorderedLoops = new HashMap<>();
+        /* Loops in reverse order of, i.e., inner loops before outer loops. */
+        List<Loop> orderedLoops = new ArrayList<>();
+
+        /*
+         * Ensure we have an outermost loop that we can use to eliminate irreducible loops. This
+         * loop can remain empty (no ends), in which case it is ignored.
+         */
+        irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead);
+
+        NodeBitMap visited = methodScope.graph.createNodeBitMap();
+        NodeBitMap active = methodScope.graph.createNodeBitMap();
+        Deque<Node> stack = new ArrayDeque<>();
+        visited.mark(startInstruction);
+        stack.push(startInstruction);
+
+        while (!stack.isEmpty()) {
+            Node current = stack.peek();
+            assert visited.isMarked(current);
+
+            if (active.isMarked(current)) {
+                /* We are back-tracking, i.e., all successor nodes have been processed. */
+                stack.pop();
+                active.clear(current);
+
+                Loop loop = unorderedLoops.get(current);
+                if (loop != null) {
+                    /*
+                     * Since nodes are popped in reverse order that they were pushed, we add inner
+                     * loops before outer loops here.
+                     */
+                    assert !orderedLoops.contains(loop);
+                    orderedLoops.add(loop);
+                }
+
+            } else {
+                /*
+                 * Process the node. Note that we do not remove the node from the stack, i.e., we
+                 * will peek it again. But the next time the node is marked as active, so we do not
+                 * execute this code again.
+                 */
+                active.mark(current);
+                for (Node successor : current.cfgSuccessors()) {
+                    if (active.isMarked(successor)) {
+                        /* Detected a cycle, i.e., a backward branch of a loop. */
+                        Loop loop = findOrCreateLoop(unorderedLoops, (MergeNode) successor);
+                        assert !loop.ends.contains(current);
+                        loop.ends.add((EndNode) current);
+
+                    } else if (visited.isMarked(successor)) {
+                        /* Forward merge into a branch we are already exploring. */
+
+                    } else {
+                        /* Forward branch to a node we have not seen yet. */
+                        visited.mark(successor);
+                        stack.push(successor);
+                    }
+                }
+            }
+        }
+        return orderedLoops;
+    }
+
+    private Loop findOrCreateLoop(Map<MergeNode, Loop> unorderedLoops, MergeNode loopHeader) {
+        assert methodScope.loopExplosionMerges.isMarkedAndGrow(loopHeader) : loopHeader;
+        Loop loop = unorderedLoops.get(loopHeader);
+        if (loop == null) {
+            loop = new Loop();
+            loop.header = loopHeader;
+            unorderedLoops.put(loopHeader, loop);
+        }
+        return loop;
+    }
+
+    private void findLoopExits(Loop loop) {
+        /*
+         * Backward marking of loop nodes: Starting with the known loop ends, we mark all nodes that
+         * are reachable until we hit the loop begin. All successors of loop nodes that are not
+         * marked as loop nodes themselves are exits of the loop. We mark all successors, and then
+         * subtract the loop nodes, to find the exits.
+         */
+
+        NodeBitMap possibleExits = methodScope.graph.createNodeBitMap();
+        NodeBitMap visited = methodScope.graph.createNodeBitMap();
+        Deque<Node> stack = new ArrayDeque<>();
+        for (EndNode loopEnd : loop.ends) {
+            stack.push(loopEnd);
+            visited.mark(loopEnd);
+        }
+
+        while (!stack.isEmpty()) {
+            Node current = stack.pop();
+            if (current == loop.header) {
+                continue;
+            }
+            if (!methodScope.graph.isNew(methodScope.methodStartMark, current)) {
+                /*
+                 * The current node is before the method that contains the exploded loop. The loop
+                 * must have a second entry point, i.e., it is an irreducible loop.
+                 */
+                loop.irreducible = true;
+                return;
+            }
+
+            for (Node predecessor : current.cfgPredecessors()) {
+                if (predecessor instanceof LoopExitNode) {
+                    /*
+                     * Inner loop. We do not need to mark every node of it, instead we just continue
+                     * marking at the loop header.
+                     */
+                    LoopBeginNode innerLoopBegin = ((LoopExitNode) predecessor).loopBegin();
+                    if (!visited.isMarked(innerLoopBegin)) {
+                        stack.push(innerLoopBegin);
+                        visited.mark(innerLoopBegin);
+
+                        /*
+                         * All loop exits of the inner loop possibly need a LoopExit of our loop.
+                         * Because we are processing inner loops first, we are guaranteed to already
+                         * have all exits of the inner loop.
+                         */
+                        for (LoopExitNode exit : innerLoopBegin.loopExits()) {
+                            possibleExits.mark(exit);
+                        }
+                    }
+
+                } else if (!visited.isMarked(predecessor)) {
+                    stack.push(predecessor);
+                    visited.mark(predecessor);
+
+                    if (predecessor instanceof ControlSplitNode) {
+                        for (Node succ : predecessor.cfgSuccessors()) {
+                            /*
+                             * We would not need to mark the current node, and would not need to
+                             * mark visited nodes. But it is easier to just mark everything, since
+                             * we subtract all visited nodes in the end anyway. Note that at this
+                             * point we do not have the complete visited information, so we would
+                             * always mark too many possible exits.
+                             */
+                            possibleExits.mark(succ);
+                        }
+                    }
+                }
+            }
+        }
+
+        /* All visited nodes are not exits of our loop. */
+        possibleExits.subtract(visited);
+
+        /*
+         * Now we know all the actual loop exits. Ideally, we would insert LoopExit nodes for them.
+         * However, a LoopExit needs a valid FrameState that captures the state at the point where
+         * we exit the loop. During graph decoding, we create a FrameState for every exploded loop
+         * iteration. We need to do a forward marking until we hit the next such point. This puts
+         * some nodes into the loop that are actually not part of the loop.
+         *
+         * In some cases, we did not create a FrameState during graph decoding: when there was no
+         * LoopExit in the original loop that we exploded. This happens for code paths that lead
+         * immediately to a DeoptimizeNode.
+         *
+         * Both cases mimic the behavior of the BytecodeParser, which also puts more nodes than
+         * necessary into a loop because it computes loop information based on bytecodes, before the
+         * actual parsing.
+         */
+
+        for (Node succ : possibleExits) {
+            stack.push(succ);
+            visited.mark(succ);
+            assert !methodScope.loopExplosionMerges.isMarkedAndGrow(succ);
+        }
+
+        while (!stack.isEmpty()) {
+            Node current = stack.pop();
+            assert visited.isMarked(current);
+            assert current instanceof ControlSinkNode || current instanceof LoopEndNode || current.cfgSuccessors().iterator().hasNext() : "Must not reach a node that has not been decoded yet";
+
+            for (Node successor : current.cfgSuccessors()) {
+                if (visited.isMarked(successor)) {
+                    /* Already processed this successor. */
+
+                } else if (methodScope.loopExplosionMerges.isMarkedAndGrow(successor)) {
+                    /*
+                     * We have a FrameState for the successor. The LoopExit will be inserted between
+                     * the current node and the successor node. Since the successor node is a
+                     * MergeNode, the current node mus be a AbstractEndNode with only that MergeNode
+                     * as the successor.
+                     */
+                    assert successor instanceof MergeNode;
+                    assert !loop.exits.contains(current);
+                    loop.exits.add((AbstractEndNode) current);
+
+                } else {
+                    /* Node we have not seen yet. */
+                    visited.mark(successor);
+                    stack.push(successor);
+                }
+            }
+        }
+    }
+
+    private void insertLoopNodes(Loop loop) {
+        MergeNode merge = loop.header;
+        FrameState stateAfter = merge.stateAfter().duplicate();
+        FixedNode afterMerge = merge.next();
+        merge.setNext(null);
+        EndNode preLoopEnd = methodScope.graph.add(new EndNode());
+        LoopBeginNode loopBegin = methodScope.graph.add(new LoopBeginNode());
+
+        merge.setNext(preLoopEnd);
+        /* Add the single non-loop predecessor of the loop header. */
+        loopBegin.addForwardEnd(preLoopEnd);
+        loopBegin.setNext(afterMerge);
+        loopBegin.setStateAfter(stateAfter);
+
+        /*
+         * Phi functions of the original merge need to be split: inputs that come from forward edges
+         * remain with the original phi function; inputs that come from backward edges are added to
+         * new phi functions.
+         */
+        List<PhiNode> mergePhis = merge.phis().snapshot();
+        List<PhiNode> loopBeginPhis = new ArrayList<>(mergePhis.size());
+        for (int i = 0; i < mergePhis.size(); i++) {
+            PhiNode mergePhi = mergePhis.get(i);
+            PhiNode loopBeginPhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin));
+            mergePhi.replaceAtUsages(loopBeginPhi);
+            /*
+             * The first input of the new phi function is the original phi function, for the one
+             * forward edge of the LoopBeginNode.
+             */
+            loopBeginPhi.addInput(mergePhi);
+            loopBeginPhis.add(loopBeginPhi);
+        }
+
+        for (EndNode endNode : loop.ends) {
+            for (int i = 0; i < mergePhis.size(); i++) {
+                PhiNode mergePhi = mergePhis.get(i);
+                PhiNode loopBeginPhi = loopBeginPhis.get(i);
+                loopBeginPhi.addInput(mergePhi.valueAt(endNode));
+            }
+
+            merge.removeEnd(endNode);
+            LoopEndNode loopEnd = methodScope.graph.add(new LoopEndNode(loopBegin));
+            endNode.replaceAndDelete(loopEnd);
+        }
+
+        /*
+         * Insert the LoopExit nodes (the easy part) and compute the FrameState for the new exits
+         * (the difficult part).
+         */
+        for (AbstractEndNode exit : loop.exits) {
+            AbstractMergeNode loopExplosionMerge = exit.merge();
+            assert methodScope.loopExplosionMerges.isMarkedAndGrow(loopExplosionMerge);
+
+            LoopExitNode loopExit = methodScope.graph.add(new LoopExitNode(loopBegin));
+            exit.replaceAtPredecessor(loopExit);
+            loopExit.setNext(exit);
+            assignLoopExitState(loopExit, loopExplosionMerge, exit);
+        }
+    }
+
+    /**
+     * During graph decoding, we create a FrameState for every exploded loop iteration. This is
+     * mostly the state that we want, we only need to tweak it a little bit: we need to insert the
+     * appropriate ProxyNodes for all values that are created inside the loop and that flow out of
+     * the loop.
+     */
+    private void assignLoopExitState(LoopExitNode loopExit, AbstractMergeNode loopExplosionMerge, AbstractEndNode loopExplosionEnd) {
+        FrameState oldState = loopExplosionMerge.stateAfter();
+
+        /* Collect all nodes that are in the FrameState at the LoopBegin. */
+        NodeBitMap loopBeginValues = new NodeBitMap(methodScope.graph);
+        for (FrameState state = loopExit.loopBegin().stateAfter(); state != null; state = state.outerFrameState()) {
+            for (ValueNode value : state.values()) {
+                if (value != null && !value.isConstant() && !loopExit.loopBegin().isPhiAtMerge(value)) {
+                    loopBeginValues.mark(ProxyPlaceholder.unwrap(value));
+                }
+            }
+        }
+
+        List<ValueNode> newValues = new ArrayList<>(oldState.values().size());
+        for (ValueNode v : oldState.values()) {
+            ValueNode value = v;
+            ValueNode realValue = ProxyPlaceholder.unwrap(value);
+
+            /*
+             * The LoopExit is inserted before the existing merge, i.e., separately for every branch
+             * that leads to the merge. So for phi functions of the merge, we need to take the input
+             * that corresponds to our branch.
+             */
+            if (realValue instanceof PhiNode && loopExplosionMerge.isPhiAtMerge(realValue)) {
+                value = ((PhiNode) realValue).valueAt(loopExplosionEnd);
+                realValue = ProxyPlaceholder.unwrap(value);
+            }
+
+            if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !methodScope.graph.isNew(methodScope.methodStartMark, realValue)) {
+                newValues.add(realValue);
+            } else {
+                /*
+                 * The node is not in the FrameState of the LoopBegin, i.e., it is a value computed
+                 * inside the loop.
+                 */
+                GraalError.guarantee(value instanceof ProxyPlaceholder && ((ProxyPlaceholder) value).proxyPoint == loopExplosionMerge,
+                                "Value flowing out of loop, but we are not prepared to insert a ProxyNode");
+
+                ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value;
+                ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, methodScope.graph);
+                proxyPlaceholder.setValue(proxy);
+                newValues.add(proxy);
+            }
+        }
+
+        FrameState newState = new FrameState(oldState.outerFrameState(), oldState.getCode(), oldState.bci, newValues, oldState.localsSize(), oldState.stackSize(), oldState.rethrowException(),
+                        oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings());
+
+        assert loopExit.stateAfter() == null;
+        loopExit.setStateAfter(methodScope.graph.add(newState));
+    }
+
+    /**
+     * Graal does not support irreducible loops (loops with more than one entry point). There are
+     * two ways to make them reducible: 1) duplicate nodes (peel a loop iteration starting at the
+     * second entry point until we reach the first entry point), or 2) insert a big outer loop
+     * covering the whole method and build a state machine for the different loop entry points.
+     * Since node duplication can lead to an exponential explosion of nodes in the worst case, we
+     * use the second approach.
+     *
+     * We already did some preparations to insert a big outer loop:
+     * {@link MethodScope#loopExplosionHead} is the loop header for the outer loop, and we ensured
+     * that we have a {@link Loop} data object for it in {@link #irreducibleLoopHandler}.
+     *
+     * Now we need to insert the state machine. We have several implementation restrictions to make
+     * that efficient:
+     * <ul>
+     * <li>There must be only one loop variable, i.e., one value that is different in the
+     * {@link FrameState} of the different loop headers.</li>
+     * <li>The loop variable must use the primitive {@code int} type, because Graal only has a
+     * {@link IntegerSwitchNode switch node} for {@code int}.</li>
+     * <li>The values of the loop variable that are merged are {@link PrimitiveConstant compile time
+     * constants}.</li>
+     * </ul>
+     */
+    private void handleIrreducibleLoop(Loop loop) {
+        assert loop != irreducibleLoopHandler;
+
+        FrameState loopState = loop.header.stateAfter();
+        FrameState explosionHeadState = irreducibleLoopHandler.header.stateAfter();
+        assert loopState.outerFrameState() == explosionHeadState.outerFrameState();
+        NodeInputList<ValueNode> loopValues = loopState.values();
+        NodeInputList<ValueNode> explosionHeadValues = explosionHeadState.values();
+        assert loopValues.size() == explosionHeadValues.size();
+
+        /*
+         * Find the loop variable, and the value of the loop variable for our loop and the outermost
+         * loop. There must be exactly one loop variable.
+         */
+        int loopVariableIndex = -1;
+        ValueNode loopValue = null;
+        ValueNode explosionHeadValue = null;
+        for (int i = 0; i < loopValues.size(); i++) {
+            ValueNode curLoopValue = loopValues.get(i);
+            ValueNode curExplosionHeadValue = explosionHeadValues.get(i);
+
+            if (curLoopValue != curExplosionHeadValue) {
+                if (loopVariableIndex != -1) {
+                    throw bailout("must have only one variable that is changed in loop. " + loopValue + " != " + explosionHeadValue + " and " + curLoopValue + " != " + curExplosionHeadValue);
+                }
+
+                loopVariableIndex = i;
+                loopValue = curLoopValue;
+                explosionHeadValue = curExplosionHeadValue;
+            }
+        }
+        assert loopVariableIndex != -1;
+
+        ValuePhiNode loopVariablePhi;
+        SortedMap<Integer, AbstractBeginNode> dispatchTable = new TreeMap<>();
+        AbstractBeginNode unreachableDefaultSuccessor;
+        if (irreducibleLoopSwitch == null) {
+            /*
+             * This is the first irreducible loop. We need to build the initial state machine
+             * (dispatch for the loop header of the outermost loop).
+             */
+            assert !irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue);
+            assert irreducibleLoopHandler.header.phis().isEmpty();
+
+            /* The new phi function for the loop variable. */
+            loopVariablePhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header));
+            for (int i = 0; i < irreducibleLoopHandler.header.phiPredecessorCount(); i++) {
+                loopVariablePhi.addInput(explosionHeadValue);
+            }
+
+            /*
+             * Build the new FrameState for the loop header. There is only once change in comparison
+             * to the old FrameState: the loop variable is replaced with the phi function.
+             */
+            FrameState oldFrameState = explosionHeadState;
+            List<ValueNode> newFrameStateValues = new ArrayList<>();
+            for (int i = 0; i < explosionHeadValues.size(); i++) {
+                if (i == loopVariableIndex) {
+                    newFrameStateValues.add(loopVariablePhi);
+                } else {
+                    newFrameStateValues.add(explosionHeadValues.get(i));
+                }
+            }
+            FrameState newFrameState = methodScope.graph.add(
+                            new FrameState(oldFrameState.outerFrameState(), oldFrameState.getCode(), oldFrameState.bci, newFrameStateValues, oldFrameState.localsSize(),
+                                            oldFrameState.stackSize(), oldFrameState.rethrowException(), oldFrameState.duringCall(), oldFrameState.monitorIds(),
+                                            oldFrameState.virtualObjectMappings()));
+            oldFrameState.replaceAtUsages(newFrameState);
+
+            /*
+             * Disconnect the outermost loop header from its loop body, so that we can later on
+             * insert the switch node. Collect dispatch information for the outermost loop.
+             */
+            FixedNode handlerNext = irreducibleLoopHandler.header.next();
+            irreducibleLoopHandler.header.setNext(null);
+            BeginNode handlerBegin = methodScope.graph.add(new BeginNode());
+            handlerBegin.setNext(handlerNext);
+            dispatchTable.put(asInt(explosionHeadValue), handlerBegin);
+
+            /*
+             * We know that there will always be a matching key in the switch. But Graal always
+             * wants a default successor, so we build a dummy block that just deoptimizes.
+             */
+            unreachableDefaultSuccessor = methodScope.graph.add(new BeginNode());
+            DeoptimizeNode deopt = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
+            unreachableDefaultSuccessor.setNext(deopt);
+
+        } else {
+            /*
+             * This is the second or a subsequent irreducible loop, i.e., we already inserted a
+             * switch node before. We re-create the dispatch state machine of that switch, so that
+             * we can extend it with one more branch.
+             */
+            assert irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue);
+            assert irreducibleLoopHandler.header.phis().count() == 1 && irreducibleLoopHandler.header.phis().first() == explosionHeadValue;
+            assert irreducibleLoopSwitch.value() == explosionHeadValue;
+
+            /* We can modify the phi function used by the old switch node. */
+            loopVariablePhi = (ValuePhiNode) explosionHeadValue;
+
+            /*
+             * We cannot modify the old switch node. Insert all information from the old switch node
+             * into our temporary data structures for the new, larger, switch node.
+             */
+            for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) {
+                int key = irreducibleLoopSwitch.keyAt(i).asInt();
+                dispatchTable.put(key, irreducibleLoopSwitch.successorAtKey(key));
+            }
+            unreachableDefaultSuccessor = irreducibleLoopSwitch.defaultSuccessor();
+
+            /* Unlink and delete the old switch node, we do not need it anymore. */
+            assert irreducibleLoopHandler.header.next() == irreducibleLoopSwitch;
+            irreducibleLoopHandler.header.setNext(null);
+            irreducibleLoopSwitch.clearSuccessors();
+            irreducibleLoopSwitch.safeDelete();
+        }
+
+        /* Insert our loop into the dispatch state machine. */
+        assert loop.header.phis().isEmpty();
+        BeginNode dispatchBegin = methodScope.graph.add(new BeginNode());
+        EndNode dispatchEnd = methodScope.graph.add(new EndNode());
+        dispatchBegin.setNext(dispatchEnd);
+        loop.header.addForwardEnd(dispatchEnd);
+        int intLoopValue = asInt(loopValue);
+        assert !dispatchTable.containsKey(intLoopValue);
+        dispatchTable.put(intLoopValue, dispatchBegin);
+
+        /* Disconnect the ends of our loop and re-connect them to the outermost loop header. */
+        for (EndNode end : loop.ends) {
+            loop.header.removeEnd(end);
+            irreducibleLoopHandler.ends.add(end);
+            irreducibleLoopHandler.header.addForwardEnd(end);
+            loopVariablePhi.addInput(loopValue);
+        }
+
+        /* Build and insert the switch node. */
+        irreducibleLoopSwitch = methodScope.graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor));
+        irreducibleLoopHandler.header.setNext(irreducibleLoopSwitch);
+    }
+
+    private static int asInt(ValueNode node) {
+        if (!node.isConstant() || node.asJavaConstant().getJavaKind() != JavaKind.Int) {
+            throw bailout("must have a loop variable of type int. " + node);
+        }
+        return node.asJavaConstant().asInt();
+    }
+
+    private static RuntimeException bailout(String msg) {
+        throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion %s", LoopExplosionKind.MERGE_EXPLODE, msg);
+    }
+
+    private static IntegerSwitchNode createSwitch(ValuePhiNode switchedValue, SortedMap<Integer, AbstractBeginNode> dispatchTable, AbstractBeginNode defaultSuccessor) {
+        int numKeys = dispatchTable.size();
+        int numSuccessors = numKeys + 1;
+
+        AbstractBeginNode[] switchSuccessors = new AbstractBeginNode[numSuccessors];
+        int[] switchKeys = new int[numKeys];
+        double[] switchKeyProbabilities = new double[numSuccessors];
+        int[] switchKeySuccessors = new int[numSuccessors];
+
+        int idx = 0;
+        for (Map.Entry<Integer, AbstractBeginNode> entry : dispatchTable.entrySet()) {
+            switchSuccessors[idx] = entry.getValue();
+            switchKeys[idx] = entry.getKey();
+            switchKeyProbabilities[idx] = 1d / numKeys;
+            switchKeySuccessors[idx] = idx;
+            idx++;
+        }
+        switchSuccessors[idx] = defaultSuccessor;
+        /* We know the default branch is never going to be executed. */
+        switchKeyProbabilities[idx] = 0;
+        switchKeySuccessors[idx] = idx;
+
+        return new IntegerSwitchNode(switchedValue, switchSuccessors, switchKeys, switchKeyProbabilities, switchKeySuccessors);
+    }
+
+    /**
+     * Print information about irreducible loops, when enabled with -Dgraal.Log=IrreducibleLoops.
+     */
+    @SuppressWarnings("try")
+    private void logIrreducibleLoops() {
+        try (Debug.Scope s = Debug.scope("IrreducibleLoops")) {
+            if (Debug.isLogEnabled(Debug.BASIC_LOG_LEVEL) && irreducibleLoopSwitch != null) {
+                StringBuilder msg = new StringBuilder("Inserted state machine to remove irreducible loops. Dispatching to the following states: ");
+                String sep = "";
+                for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) {
+                    msg.append(sep).append(irreducibleLoopSwitch.keyAt(i).asInt());
+                    sep = ", ";
+                }
+                Debug.log(Debug.BASIC_LOG_LEVEL, "%s", msg);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java
new file mode 100644
index 0000000..3bf5137
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.util.FrequencyEncoder;
+import org.graalvm.compiler.core.common.util.TypeConversion;
+import org.graalvm.compiler.core.common.util.TypeReader;
+import org.graalvm.compiler.core.common.util.TypeWriter;
+import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
+
+import jdk.vm.ci.code.Architecture;
+
+/**
+ * Encodes a {@link StructuredGraph} to a compact byte[] array. All nodes of the graph and edges
+ * between the nodes are encoded. Primitive data fields of nodes are stored in the byte[] array.
+ * Object data fields of nodes are stored in a separate Object[] array.
+ *
+ * One encoder instance can be used to encode multiple graphs. This requires that {@link #prepare}
+ * is called for all graphs first, followed by one call to {@link #finishPrepare}. Then
+ * {@link #encode} can be called for all graphs. The {@link #getObjects() objects} and
+ * {@link #getNodeClasses() node classes} arrays do not change anymore after preparation.
+ *
+ * Multiple encoded graphs share the Object[] array, and elements of the Object[] array are
+ * de-duplicated using {@link Object#equals Object equality}. This uses the assumption and good
+ * coding practice that data objects are immutable if {@link Object#equals} is implemented.
+ * Unfortunately, this cannot be enforced.
+ *
+ * The Graal {@link NodeClass} does not have a unique id that allows class lookup from an id.
+ * Therefore, the encoded graph contains a {@link NodeClass}[] array for lookup, and type ids are
+ * encoding-local.
+ *
+ * The encoded graph has the following structure: First, all nodes and their edges are serialized.
+ * The start offset of every node is then known. The raw node data is followed by a "table of
+ * contents" that lists the start offset for every node.
+ *
+ * The beginning of that table of contents is the return value of {@link #encode} and stored in
+ * {@link EncodedGraph#getStartOffset()}. The order of nodes in the table of contents is the
+ * {@link NodeOrder#orderIds orderId} of a node. Note that the orderId is not the regular node id
+ * that every Graal graph node gets assigned. The orderId is computed and used just for encoding and
+ * decoding. The orderId of fixed nodes is assigned in reverse postorder. The decoder processes
+ * nodes using that order, which ensures that all predecessors of a node (including all
+ * {@link EndNode predecessors} of a {@link AbstractBeginNode block}) are decoded before the node.
+ * The order id of floating node does not matter during decoding, so floating nodes get order ids
+ * after all fixed nodes. The order id is used to encode edges between nodes
+ *
+ * Structure of an encoded node:
+ *
+ * <pre>
+ * struct Node {
+ *   unsigned typeId
+ *   signed[] properties
+ *   unsigned[] successorOrderIds
+ *   unsigned[] inputOrderIds
+ * }
+ * </pre>
+ *
+ * All numbers (unsigned and signed) are stored using a variable-length encoding as defined in
+ * {@link TypeReader} and {@link TypeWriter}. Especially orderIds are small, so the variable-length
+ * encoding is important to keep the encoding compact.
+ *
+ * The properties, successors, and inputs are written in the order as defined in
+ * {@link NodeClass#getData}, {@link NodeClass#getSuccessorEdges()}, and
+ * {@link NodeClass#getInputEdges()}. For variable-length successors and input lists, first the
+ * length is written and then the orderIds. There is a distinction between null lists (encoded as
+ * length -1) and empty lists (encoded as length 0). No reverse edges are written (predecessors,
+ * usages) since that information can be easily restored during decoding.
+ *
+ * Some nodes have additional information written after the properties, successors, and inputs:
+ * <li><item>{@link AbstractEndNode}: the orderId of the merge node and then all {@link PhiNode phi
+ * mappings} from this end to the merge node are written. <item>{@link LoopExitNode}: the orderId of
+ * all {@link ProxyNode proxy nodes} of the loop exit is written.</li>
+ */
+public class GraphEncoder {
+
+    /** The orderId that always represents {@code null}. */
+    public static final int NULL_ORDER_ID = 0;
+    /** The orderId of the {@link StructuredGraph#start() start node} of the encoded graph. */
+    public static final int START_NODE_ORDER_ID = 1;
+    /**
+     * The orderId of the first actual node after the {@link StructuredGraph#start() start node}.
+     */
+    public static final int FIRST_NODE_ORDER_ID = 2;
+
+    /**
+     * The known offset between the orderId of a {@link AbstractBeginNode} and its
+     * {@link AbstractBeginNode#next() successor}.
+     */
+    protected static final int BEGIN_NEXT_ORDER_ID_OFFSET = 1;
+
+    protected final Architecture architecture;
+
+    /**
+     * Collects all non-primitive data referenced from nodes. The encoding uses an index into an
+     * array for decoding. Because of the variable-length encoding, it is beneficial that frequently
+     * used objects have the small indices.
+     */
+    protected final FrequencyEncoder<Object> objects;
+    /**
+     * Collects all node classes referenced in graphs. This is necessary because {@link NodeClass}
+     * currently does not have a unique id.
+     */
+    protected final FrequencyEncoder<NodeClass<?>> nodeClasses;
+    /** The writer for the encoded graphs. */
+    protected final UnsafeArrayTypeWriter writer;
+
+    /** The last snapshot of {@link #objects} that was retrieved. */
+    protected Object[] objectsArray;
+    /** The last snapshot of {@link #nodeClasses} that was retrieved. */
+    protected NodeClass<?>[] nodeClassesArray;
+
+    /**
+     * Utility method that does everything necessary to encode a single graph.
+     */
+    public static EncodedGraph encodeSingleGraph(StructuredGraph graph, Architecture architecture) {
+        GraphEncoder encoder = new GraphEncoder(architecture);
+        encoder.prepare(graph);
+        encoder.finishPrepare();
+        long startOffset = encoder.encode(graph);
+        return new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph.getAssumptions(), graph.getMethods());
+    }
+
+    public GraphEncoder(Architecture architecture) {
+        this.architecture = architecture;
+        objects = FrequencyEncoder.createEqualityEncoder();
+        nodeClasses = FrequencyEncoder.createIdentityEncoder();
+        writer = UnsafeArrayTypeWriter.create(architecture.supportsUnalignedMemoryAccess());
+    }
+
+    /**
+     * Must be invoked before {@link #finishPrepare()} and {@link #encode}.
+     */
+    public void prepare(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            nodeClasses.addObject(node.getNodeClass());
+
+            NodeClass<?> nodeClass = node.getNodeClass();
+            objects.addObject(node.getNodeSourcePosition());
+            for (int i = 0; i < nodeClass.getData().getCount(); i++) {
+                if (!nodeClass.getData().getType(i).isPrimitive()) {
+                    objects.addObject(nodeClass.getData().get(node, i));
+                }
+            }
+            if (node instanceof Invoke) {
+                objects.addObject(((Invoke) node).getContextType());
+            }
+        }
+    }
+
+    public void finishPrepare() {
+        objectsArray = objects.encodeAll(new Object[objects.getLength()]);
+        nodeClassesArray = nodeClasses.encodeAll(new NodeClass<?>[nodeClasses.getLength()]);
+    }
+
+    public Object[] getObjects() {
+        return objectsArray;
+    }
+
+    public NodeClass<?>[] getNodeClasses() {
+        return nodeClassesArray;
+    }
+
+    /**
+     * Compresses a graph to a byte array. Multiple graphs can be compressed with the same
+     * {@link GraphEncoder}.
+     *
+     * @param graph The graph to encode
+     */
+    public long encode(StructuredGraph graph) {
+        assert objectsArray != null && nodeClassesArray != null : "finishPrepare() must be called before encode()";
+
+        NodeOrder nodeOrder = new NodeOrder(graph);
+        int nodeCount = nodeOrder.nextOrderId;
+        assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
+        assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
+        assert nodeCount == graph.getNodeCount() + 1;
+
+        long[] nodeStartOffsets = new long[nodeCount];
+        for (Map.Entry<Node, Integer> entry : nodeOrder.orderIds.entries()) {
+            Node node = entry.getKey();
+            Integer orderId = entry.getValue();
+
+            assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
+            nodeStartOffsets[orderId] = writer.getBytesWritten();
+
+            /* Write out the type, properties, and edges. */
+            NodeClass<?> nodeClass = node.getNodeClass();
+            writer.putUV(nodeClasses.getIndex(nodeClass));
+            writeProperties(node, nodeClass.getData());
+            writeEdges(node, nodeClass.getEdges(Edges.Type.Successors), nodeOrder);
+            writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder);
+
+            /* Special handling for some nodes that require additional information for decoding. */
+            if (node instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) node;
+                AbstractMergeNode merge = end.merge();
+                /*
+                 * Write the orderId of the merge. The merge is not a successor in the Graal graph
+                 * (only the merge has an input edge to the EndNode).
+                 */
+                writeOrderId(merge, nodeOrder);
+
+                /*
+                 * Write all phi mappings (the oderId of the phi input for this EndNode, and the
+                 * orderId of the phi node.
+                 */
+                writer.putUV(merge.phis().count());
+                for (PhiNode phi : merge.phis()) {
+                    writeOrderId(phi.valueAt(end), nodeOrder);
+                    writeOrderId(phi, nodeOrder);
+                }
+
+            } else if (node instanceof LoopExitNode) {
+                LoopExitNode exit = (LoopExitNode) node;
+                writeOrderId(exit.stateAfter(), nodeOrder);
+                /* Write all proxy nodes of the LoopExitNode. */
+                writer.putUV(exit.proxies().count());
+                for (ProxyNode proxy : exit.proxies()) {
+                    writeOrderId(proxy, nodeOrder);
+                }
+
+            } else if (node instanceof Invoke) {
+                Invoke invoke = (Invoke) node;
+                assert invoke.stateDuring() == null : "stateDuring is not used in high-level graphs";
+
+                writeObjectId(invoke.getContextType());
+                writeOrderId(invoke.callTarget(), nodeOrder);
+                writeOrderId(invoke.stateAfter(), nodeOrder);
+                writeOrderId(invoke.next(), nodeOrder);
+                if (invoke instanceof InvokeWithExceptionNode) {
+                    InvokeWithExceptionNode invokeWithExcpetion = (InvokeWithExceptionNode) invoke;
+                    ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExcpetion.exceptionEdge();
+
+                    writeOrderId(invokeWithExcpetion.next().next(), nodeOrder);
+                    writeOrderId(invokeWithExcpetion.exceptionEdge(), nodeOrder);
+                    writeOrderId(exceptionEdge.stateAfter(), nodeOrder);
+                    writeOrderId(exceptionEdge.next(), nodeOrder);
+                }
+            }
+        }
+
+        /* Write out the table of contents with the start offset for all nodes. */
+        long nodeTableStart = writer.getBytesWritten();
+        writer.putUV(nodeCount);
+        for (int i = 0; i < nodeCount; i++) {
+            assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
+            writer.putUV(nodeTableStart - nodeStartOffsets[i]);
+        }
+
+        /* Check that the decoding of the encode graph is the same as the input. */
+        assert verifyEncoding(graph, new EncodedGraph(getEncoding(), nodeTableStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()), architecture);
+
+        return nodeTableStart;
+    }
+
+    public byte[] getEncoding() {
+        return writer.toArray(new byte[TypeConversion.asS4(writer.getBytesWritten())]);
+    }
+
+    static class NodeOrder {
+        protected final NodeMap<Integer> orderIds;
+        protected int nextOrderId;
+
+        NodeOrder(StructuredGraph graph) {
+            this.orderIds = new NodeMap<>(graph);
+            this.nextOrderId = START_NODE_ORDER_ID;
+
+            /* Order the fixed nodes of the graph in reverse postorder. */
+            Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
+            FixedNode current = graph.start();
+            do {
+                add(current);
+                if (current instanceof AbstractBeginNode) {
+                    add(((AbstractBeginNode) current).next());
+                }
+
+                if (current instanceof FixedWithNextNode) {
+                    current = ((FixedWithNextNode) current).next;
+                } else {
+                    if (current instanceof ControlSplitNode) {
+                        for (Node successor : current.successors()) {
+                            if (successor != null) {
+                                nodeQueue.addFirst((AbstractBeginNode) successor);
+                            }
+                        }
+                    } else if (current instanceof EndNode) {
+                        AbstractMergeNode merge = ((AbstractEndNode) current).merge();
+                        boolean allForwardEndsVisited = true;
+                        for (int i = 0; i < merge.forwardEndCount(); i++) {
+                            if (orderIds.get(merge.forwardEndAt(i)) == null) {
+                                allForwardEndsVisited = false;
+                                break;
+                            }
+                        }
+                        if (allForwardEndsVisited) {
+                            nodeQueue.add(merge);
+                        }
+                    }
+                    current = nodeQueue.pollFirst();
+                }
+            } while (current != null);
+
+            for (Node node : graph.getNodes()) {
+                assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered";
+                add(node);
+            }
+        }
+
+        private void add(Node node) {
+            if (orderIds.get(node) == null) {
+                orderIds.set(node, nextOrderId);
+                nextOrderId++;
+            }
+        }
+    }
+
+    protected void writeProperties(Node node, Fields fields) {
+        writeObjectId(node.getNodeSourcePosition());
+        for (int idx = 0; idx < fields.getCount(); idx++) {
+            if (fields.getType(idx).isPrimitive()) {
+                long primitive = fields.getRawPrimitive(node, idx);
+                writer.putSV(primitive);
+            } else {
+                Object property = fields.get(node, idx);
+                writeObjectId(property);
+            }
+        }
+    }
+
+    protected void writeEdges(Node node, Edges edges, NodeOrder nodeOrder) {
+        for (int idx = 0; idx < edges.getDirectCount(); idx++) {
+            if (GraphDecoder.skipEdge(node, edges, idx, true, false)) {
+                /* Edge is not needed for decoding, so we must not write it. */
+                continue;
+            }
+            Node edge = Edges.getNode(node, edges.getOffsets(), idx);
+            writeOrderId(edge, nodeOrder);
+        }
+        for (int idx = edges.getDirectCount(); idx < edges.getCount(); idx++) {
+            if (GraphDecoder.skipEdge(node, edges, idx, false, false)) {
+                /* Edge is not needed for decoding, so we must not write it. */
+                continue;
+            }
+            NodeList<Node> edgeList = Edges.getNodeList(node, edges.getOffsets(), idx);
+            if (edgeList == null) {
+                writer.putSV(-1);
+            } else {
+                writer.putSV(edgeList.size());
+                for (Node edge : edgeList) {
+                    writeOrderId(edge, nodeOrder);
+                }
+            }
+        }
+    }
+
+    protected void writeOrderId(Node node, NodeOrder nodeOrder) {
+        writer.putUV(node == null ? NULL_ORDER_ID : nodeOrder.orderIds.get(node));
+    }
+
+    protected void writeObjectId(Object object) {
+        writer.putUV(objects.getIndex(object));
+    }
+
+    /**
+     * Verification code that checks that the decoding of an encode graph is the same as the
+     * original graph.
+     */
+    @SuppressWarnings("try")
+    public static boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encodedGraph, Architecture architecture) {
+        StructuredGraph decodedGraph = new StructuredGraph(originalGraph.method(), AllowAssumptions.YES, INVALID_COMPILATION_ID);
+        GraphDecoder decoder = new GraphDecoder(architecture);
+        decoder.decode(decodedGraph, encodedGraph);
+
+        decodedGraph.verify();
+        try {
+            GraphComparison.verifyGraphsEqual(originalGraph, decodedGraph);
+        } catch (Throwable ex) {
+            try (Debug.Scope scope = Debug.scope("GraphEncoder")) {
+                Debug.dump(Debug.INFO_LOG_LEVEL, originalGraph, "Original Graph");
+                Debug.dump(Debug.INFO_LOG_LEVEL, decodedGraph, "Decoded Graph");
+            }
+            throw ex;
+        }
+        return true;
+    }
+}
+
+class GraphComparison {
+    public static boolean verifyGraphsEqual(StructuredGraph expectedGraph, StructuredGraph actualGraph) {
+        NodeMap<Node> nodeMapping = new NodeMap<>(expectedGraph);
+        Deque<Pair<Node, Node>> workList = new ArrayDeque<>();
+
+        pushToWorklist(expectedGraph.start(), actualGraph.start(), nodeMapping, workList);
+        while (!workList.isEmpty()) {
+            Pair<Node, Node> pair = workList.removeFirst();
+            Node expectedNode = pair.first;
+            Node actualNode = pair.second;
+            assert expectedNode.getClass() == actualNode.getClass();
+
+            NodeClass<?> nodeClass = expectedNode.getNodeClass();
+            assert nodeClass == actualNode.getNodeClass();
+
+            if (expectedNode instanceof MergeNode) {
+                /* The order of the ends can be different, so ignore them. */
+                verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, true);
+            } else if (expectedNode instanceof PhiNode) {
+                verifyPhi((PhiNode) expectedNode, (PhiNode) actualNode, nodeMapping, workList);
+            } else {
+                verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, false);
+            }
+            verifyNodesEqual(expectedNode.successors(), actualNode.successors(), nodeMapping, workList, false);
+
+            if (expectedNode instanceof LoopEndNode) {
+                LoopEndNode actualLoopEnd = (LoopEndNode) actualNode;
+                assert actualLoopEnd.loopBegin().loopEnds().snapshot().indexOf(actualLoopEnd) == actualLoopEnd.endIndex();
+            } else {
+                for (int i = 0; i < nodeClass.getData().getCount(); i++) {
+                    Object expectedProperty = nodeClass.getData().get(expectedNode, i);
+                    Object actualProperty = nodeClass.getData().get(actualNode, i);
+                    assert Objects.equals(expectedProperty, actualProperty);
+                }
+            }
+
+            if (expectedNode instanceof EndNode) {
+                /* Visit the merge node, which is the one and only usage of the EndNode. */
+                assert expectedNode.usages().count() == 1;
+                assert actualNode.usages().count() == 1;
+                verifyNodesEqual(expectedNode.usages(), actualNode.usages(), nodeMapping, workList, false);
+            }
+
+            if (expectedNode instanceof AbstractEndNode) {
+                /* Visit the input values of the merge phi functions for this EndNode. */
+                verifyPhis((AbstractEndNode) expectedNode, (AbstractEndNode) actualNode, nodeMapping, workList);
+            }
+        }
+
+        return true;
+    }
+
+    protected static void verifyPhi(PhiNode expectedPhi, PhiNode actualPhi, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList) {
+        AbstractMergeNode expectedMergeNode = expectedPhi.merge();
+        AbstractMergeNode actualMergeNode = actualPhi.merge();
+        assert actualMergeNode == nodeMapping.get(expectedMergeNode);
+
+        for (EndNode expectedEndNode : expectedMergeNode.ends) {
+            EndNode actualEndNode = (EndNode) nodeMapping.get(expectedEndNode);
+            if (actualEndNode != null) {
+                ValueNode expectedPhiInput = expectedPhi.valueAt(expectedEndNode);
+                ValueNode actualPhiInput = actualPhi.valueAt(actualEndNode);
+                verifyNodeEqual(expectedPhiInput, actualPhiInput, nodeMapping, workList, false);
+            }
+        }
+    }
+
+    protected static void verifyPhis(AbstractEndNode expectedEndNode, AbstractEndNode actualEndNode, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList) {
+        AbstractMergeNode expectedMergeNode = expectedEndNode.merge();
+        AbstractMergeNode actualMergeNode = (AbstractMergeNode) nodeMapping.get(expectedMergeNode);
+        assert actualMergeNode != null;
+
+        for (PhiNode expectedPhi : expectedMergeNode.phis()) {
+            PhiNode actualPhi = (PhiNode) nodeMapping.get(expectedPhi);
+            if (actualPhi != null) {
+                ValueNode expectedPhiInput = expectedPhi.valueAt(expectedEndNode);
+                ValueNode actualPhiInput = actualPhi.valueAt(actualEndNode);
+                verifyNodeEqual(expectedPhiInput, actualPhiInput, nodeMapping, workList, false);
+            }
+        }
+    }
+
+    private static void verifyNodesEqual(NodeIterable<Node> expectedNodes, NodeIterable<Node> actualNodes, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList, boolean ignoreEndNode) {
+        Iterator<Node> actualIter = actualNodes.iterator();
+        for (Node expectedNode : expectedNodes) {
+            verifyNodeEqual(expectedNode, actualIter.next(), nodeMapping, workList, ignoreEndNode);
+        }
+        assert !actualIter.hasNext();
+    }
+
+    protected static void verifyNodeEqual(Node expectedNode, Node actualNode, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList, boolean ignoreEndNode) {
+        assert expectedNode.getClass() == actualNode.getClass();
+        if (ignoreEndNode && expectedNode instanceof EndNode) {
+            return;
+        }
+
+        Node existing = nodeMapping.get(expectedNode);
+        if (existing != null) {
+            assert existing == actualNode;
+        } else {
+            pushToWorklist(expectedNode, actualNode, nodeMapping, workList);
+        }
+    }
+
+    protected static void pushToWorklist(Node expectedNode, Node actualNode, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList) {
+        nodeMapping.set(expectedNode, actualNode);
+        if (expectedNode instanceof AbstractEndNode) {
+            /* To ensure phi nodes have been added, we handle everything before block ends. */
+            workList.addLast(new Pair<>(expectedNode, actualNode));
+        } else {
+            workList.addFirst(new Pair<>(expectedNode, actualNode));
+        }
+    }
+}
+
+class Pair<F, S> {
+    public final F first;
+    public final S second;
+
+    Pair(F first, S second) {
+        this.first = first;
+        this.second = second;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java
new file mode 100644
index 0000000..c57e9a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Condition;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * A guard is a node that deoptimizes based on a conditional expression. Guards are not attached to
+ * a certain frame state, they can move around freely and will always use the correct frame state
+ * when the nodes are scheduled (i.e., the last emitted frame state). The node that is guarded has a
+ * data dependency on the guard and the guard in turn has a data dependency on the condition. A
+ * guard may only be executed if it is guaranteed that the guarded node is executed too (if no
+ * exceptions are thrown). Therefore, an anchor is placed after a control flow split and the guard
+ * has a data dependency to the anchor. The anchor is the most distant node that is post-dominated
+ * by the guarded node and the guard can be scheduled anywhere between those two nodes. This ensures
+ * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the
+ * control flow would have reached the guarded node (without taking exceptions into account).
+ */
+@NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}", allowedUsageTypes = {Guard}, size = SIZE_2, cycles = CYCLES_2)
+public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, GuardingNode, DeoptimizingGuard {
+
+    public static final NodeClass<GuardNode> TYPE = NodeClass.create(GuardNode.class);
+    @Input(Condition) protected LogicNode condition;
+    protected final DeoptimizationReason reason;
+    protected JavaConstant speculation;
+    protected DeoptimizationAction action;
+    protected boolean negated;
+
+    public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
+        this(TYPE, condition, anchor, reason, action, negated, speculation);
+    }
+
+    protected GuardNode(NodeClass<? extends GuardNode> c, LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated,
+                    JavaConstant speculation) {
+        super(c, StampFactory.forVoid(), anchor);
+        this.condition = condition;
+        this.reason = reason;
+        this.action = action;
+        this.negated = negated;
+        this.speculation = speculation;
+    }
+
+    /**
+     * The instruction that produces the tested boolean value.
+     */
+    @Override
+    public LogicNode getCondition() {
+        return condition;
+    }
+
+    @Override
+    public void setCondition(LogicNode x, boolean negated) {
+        updateUsages(condition, x);
+        condition = x;
+        this.negated = negated;
+    }
+
+    @Override
+    public boolean isNegated() {
+        return negated;
+    }
+
+    @Override
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    @Override
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
+    @Override
+    public JavaConstant getSpeculation() {
+        return speculation;
+    }
+
+    public void setSpeculation(JavaConstant speculation) {
+        this.speculation = speculation;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getCondition() instanceof LogicNegationNode) {
+            LogicNegationNode negation = (LogicNegationNode) getCondition();
+            return new GuardNode(negation.getValue(), getAnchor(), reason, action, !negated, speculation);
+        }
+        if (getCondition() instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) getCondition();
+            if (c.getValue() != negated) {
+                return null;
+            }
+        }
+        return this;
+    }
+
+    public FixedWithNextNode lowerGuard() {
+        return null;
+    }
+
+    public void negate() {
+        negated = !negated;
+    }
+
+    public void setAction(DeoptimizationAction invalidaterecompile) {
+        this.action = invalidaterecompile;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardPhiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardPhiNode.java
new file mode 100644
index 0000000..5996b38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardPhiNode.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+/**
+ * Guard {@link PhiNode}s merge guard dependencies at control flow merges.
+ */
+@NodeInfo(nameTemplate = "GuardPhi({i#values})", allowedUsageTypes = {InputType.Guard})
+public final class GuardPhiNode extends PhiNode implements GuardingNode {
+
+    public static final NodeClass<GuardPhiNode> TYPE = NodeClass.create(GuardPhiNode.class);
+    @OptionalInput(InputType.Guard) NodeInputList<ValueNode> values;
+
+    public GuardPhiNode(AbstractMergeNode merge) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.values = new NodeInputList<>(this);
+    }
+
+    public GuardPhiNode(AbstractMergeNode merge, ValueNode[] values) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    @Override
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+
+    @Override
+    public boolean hasValidInput() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java
new file mode 100644
index 0000000..78ac270
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Proxy;
+
+@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "Proxy({i#value})")
+public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable, Canonicalizable {
+
+    public static final NodeClass<GuardProxyNode> TYPE = NodeClass.create(GuardProxyNode.class);
+    @OptionalInput(InputType.Guard) GuardingNode value;
+
+    public GuardProxyNode(GuardingNode value, LoopExitNode proxyPoint) {
+        super(TYPE, StampFactory.forVoid(), proxyPoint);
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+    }
+
+    public void setValue(GuardingNode newValue) {
+        this.updateUsages(value.asNode(), newValue.asNode());
+        this.value = newValue;
+    }
+
+    @Override
+    public ValueNode value() {
+        return (value == null ? null : value.asNode());
+    }
+
+    @Override
+    public Node getOriginalNode() {
+        return (value == null ? null : value.asNode());
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value == null) {
+            return null;
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java
new file mode 100644
index 0000000..3e5f0ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode
+ * is used to keep the nodes depending on guards inside a loop during speculative guard movement.
+ *
+ * A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
+
+    public static final NodeClass<GuardedValueNode> TYPE = NodeClass.create(GuardedValueNode.class);
+    @Input ValueNode object;
+    protected final Stamp piStamp;
+
+    public GuardedValueNode(ValueNode object, GuardingNode guard, Stamp stamp) {
+        super(TYPE, computeStamp(stamp, object), guard);
+        this.object = object;
+        this.piStamp = stamp;
+    }
+
+    public GuardedValueNode(ValueNode object, GuardingNode guard) {
+        this(object, guard, object.stamp());
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        if (object.getStackKind() != JavaKind.Void && object.getStackKind() != JavaKind.Illegal) {
+            generator.setResult(this, generator.operand(object));
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(computeStamp(piStamp, object()));
+    }
+
+    static Stamp computeStamp(Stamp piStamp, ValueNode object) {
+        return piStamp.improveWith(object.stamp());
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            tool.replaceWithVirtual((VirtualObjectNode) alias);
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getGuard() == null) {
+            if (stamp().equals(object().stamp())) {
+                return object();
+            } else {
+                return new PiNode(object(), stamp());
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ValueNode getOriginalNode() {
+        return object;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
new file mode 100644
index 0000000..b62e20f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
@@ -0,0 +1,1187 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+/**
+ * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
+ * of a comparison.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2, sizeRationale = "2 jmps")
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+    public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
+
+    private static final DebugCounter CORRECTED_PROBABILITIES = Debug.counter("CorrectedProbabilities");
+
+    @Successor AbstractBeginNode trueSuccessor;
+    @Successor AbstractBeginNode falseSuccessor;
+    @Input(InputType.Condition) LogicNode condition;
+    protected double trueSuccessorProbability;
+
+    public LogicNode condition() {
+        return condition;
+    }
+
+    public void setCondition(LogicNode x) {
+        updateUsages(condition, x);
+        condition = x;
+    }
+
+    public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
+        this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
+    }
+
+    public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
+        super(TYPE, StampFactory.forVoid());
+        this.condition = condition;
+        this.falseSuccessor = falseSuccessor;
+        this.trueSuccessor = trueSuccessor;
+        setTrueSuccessorProbability(trueSuccessorProbability);
+    }
+
+    /**
+     * Gets the true successor.
+     *
+     * @return the true successor
+     */
+    public AbstractBeginNode trueSuccessor() {
+        return trueSuccessor;
+    }
+
+    /**
+     * Gets the false successor.
+     *
+     * @return the false successor
+     */
+    public AbstractBeginNode falseSuccessor() {
+        return falseSuccessor;
+    }
+
+    public double getTrueSuccessorProbability() {
+        return this.trueSuccessorProbability;
+    }
+
+    public void setTrueSuccessor(AbstractBeginNode node) {
+        updatePredecessor(trueSuccessor, node);
+        trueSuccessor = node;
+    }
+
+    public void setFalseSuccessor(AbstractBeginNode node) {
+        updatePredecessor(falseSuccessor, node);
+        falseSuccessor = node;
+    }
+
+    /**
+     * Gets the node corresponding to the specified outcome of the branch.
+     *
+     * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
+     * @return the corresponding successor
+     */
+    public AbstractBeginNode successor(boolean istrue) {
+        return istrue ? trueSuccessor : falseSuccessor;
+    }
+
+    public void setTrueSuccessorProbability(double prob) {
+        assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob;
+        trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob));
+    }
+
+    @Override
+    public double probability(AbstractBeginNode successor) {
+        return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.emitIf(this);
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(condition() != null, "missing condition");
+        assertTrue(trueSuccessor() != null, "missing trueSuccessor");
+        assertTrue(falseSuccessor() != null, "missing falseSuccessor");
+        return super.verify();
+    }
+
+    public void eliminateNegation() {
+        AbstractBeginNode oldTrueSuccessor = trueSuccessor;
+        AbstractBeginNode oldFalseSuccessor = falseSuccessor;
+        trueSuccessor = oldFalseSuccessor;
+        falseSuccessor = oldTrueSuccessor;
+        trueSuccessorProbability = 1 - trueSuccessorProbability;
+        setCondition(((LogicNegationNode) condition).getValue());
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (trueSuccessor().next() instanceof DeoptimizeNode) {
+            if (trueSuccessorProbability != 0) {
+                CORRECTED_PROBABILITIES.increment();
+                trueSuccessorProbability = 0;
+            }
+        } else if (falseSuccessor().next() instanceof DeoptimizeNode) {
+            if (trueSuccessorProbability != 1) {
+                CORRECTED_PROBABILITIES.increment();
+                trueSuccessorProbability = 1;
+            }
+        }
+
+        if (condition() instanceof LogicNegationNode) {
+            eliminateNegation();
+        }
+        if (condition() instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) condition();
+            if (c.getValue()) {
+                tool.deleteBranch(falseSuccessor());
+                tool.addToWorkList(trueSuccessor());
+                graph().removeSplit(this, trueSuccessor());
+            } else {
+                tool.deleteBranch(trueSuccessor());
+                tool.addToWorkList(falseSuccessor());
+                graph().removeSplit(this, falseSuccessor());
+            }
+            return;
+        }
+        if (tool.allUsagesAvailable() && trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages()) {
+
+            pushNodesThroughIf(tool);
+
+            if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
+                return;
+            }
+        }
+
+        if (removeIntermediateMaterialization(tool)) {
+            return;
+        }
+
+        if (splitIfAtPhi(tool)) {
+            return;
+        }
+
+        if (conditionalNodeOptimization(tool)) {
+            return;
+        }
+
+        if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
+            AbstractBeginNode intermediateBegin = falseSuccessor();
+            IfNode nextIf = (IfNode) intermediateBegin.next();
+            double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
+            if (this.trueSuccessorProbability < probabilityB) {
+                // Reordering of those two if statements is beneficial from the point of view of
+                // their probabilities.
+                if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition())) {
+                    // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
+                    assert intermediateBegin.next() == nextIf;
+                    AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
+                    nextIf.setFalseSuccessor(null);
+                    intermediateBegin.setNext(null);
+                    this.setFalseSuccessor(null);
+
+                    this.replaceAtPredecessor(nextIf);
+                    nextIf.setFalseSuccessor(intermediateBegin);
+                    intermediateBegin.setNext(this);
+                    this.setFalseSuccessor(bothFalseBegin);
+                    nextIf.setTrueSuccessorProbability(probabilityB);
+                    if (probabilityB == 1.0) {
+                        this.setTrueSuccessorProbability(0.0);
+                    } else {
+                        double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB);
+                        this.setTrueSuccessorProbability(Math.min(1.0, newProbability));
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Try to optimize this as if it were a {@link ConditionalNode}.
+     */
+    private boolean conditionalNodeOptimization(SimplifierTool tool) {
+        if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
+            AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
+            AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
+            if (trueEnd.merge() != falseEnd.merge()) {
+                return false;
+            }
+            if (!(trueEnd.merge() instanceof MergeNode)) {
+                return false;
+            }
+            MergeNode merge = (MergeNode) trueEnd.merge();
+            if (merge.usages().count() != 1 || merge.phis().count() != 1) {
+                return false;
+            }
+            PhiNode phi = merge.phis().first();
+            ValueNode falseValue = phi.valueAt(falseEnd);
+            ValueNode trueValue = phi.valueAt(trueEnd);
+
+            ValueNode result = ConditionalNode.canonicalizeConditional(condition, trueValue, falseValue, phi.stamp());
+            if (result != null) {
+                /*
+                 * canonicalizeConditional returns possibly new nodes so add them to the graph.
+                 */
+                if (result.graph() == null) {
+                    result = graph().addOrUniqueWithInputs(result);
+                }
+                /*
+                 * This optimization can be performed even if multiple values merge at this phi
+                 * since the two inputs get simplified into one.
+                 */
+                phi.setValueAt(trueEnd, result);
+                removeThroughFalseBranch(tool);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private void pushNodesThroughIf(SimplifierTool tool) {
+        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
+        // push similar nodes upwards through the if, thereby deduplicating them
+        do {
+            AbstractBeginNode trueSucc = trueSuccessor();
+            AbstractBeginNode falseSucc = falseSuccessor();
+            if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
+                FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
+                FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
+                NodeClass<?> nodeClass = trueNext.getNodeClass();
+                if (trueNext.getClass() == falseNext.getClass()) {
+                    if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
+                        falseNext.replaceAtUsages(trueNext);
+                        graph().removeFixed(falseNext);
+                        GraphUtil.unlinkFixedNode(trueNext);
+                        graph().addBeforeFixed(this, trueNext);
+                        for (Node usage : trueNext.usages().snapshot()) {
+                            if (usage.isAlive()) {
+                                NodeClass<?> usageNodeClass = usage.getNodeClass();
+                                if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
+                                    Node newNode = graph().findDuplicate(usage);
+                                    if (newNode != null) {
+                                        usage.replaceAtUsagesAndDelete(newNode);
+                                    }
+                                }
+                                if (usage.isAlive()) {
+                                    tool.addToWorkList(usage);
+                                }
+                            }
+                        }
+                        continue;
+                    }
+                }
+            }
+            break;
+        } while (true);
+    }
+
+    /**
+     * Recognize a couple patterns that can be merged into an unsigned compare.
+     *
+     * @param tool
+     * @return true if a replacement was done.
+     */
+    private boolean checkForUnsignedCompare(SimplifierTool tool) {
+        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
+        if (condition() instanceof IntegerLessThanNode) {
+            IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
+            Constant y = lessThan.getY().stamp().asConstant();
+            if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
+                IfNode ifNode2 = (IfNode) falseSuccessor().next();
+                if (ifNode2.condition() instanceof IntegerLessThanNode) {
+                    IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
+                    AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
+                    AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
+                    IntegerBelowNode below = null;
+                    /*
+                     * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
+                     * <positive> into an unsigned compare.
+                     */
+                    if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() &&
+                                    sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
+                        below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
+                        // swap direction
+                        AbstractBeginNode tmp = falseSucc;
+                        falseSucc = trueSucc;
+                        trueSucc = tmp;
+                    } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
+                        /*
+                         * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
+                         * !(<positive> > x), into x <| positive + 1. This can only be done for
+                         * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
+                         * appear to be interesting.
+                         */
+                        JavaConstant positive = lessThan2.getX().asJavaConstant();
+                        if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getJavaKind().getMaxValue()) {
+                            ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(), positive.asLong() + 1, graph());
+                            below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
+                        }
+                    }
+                    if (below != null) {
+                        ifNode2.setTrueSuccessor(null);
+                        ifNode2.setFalseSuccessor(null);
+
+                        IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
+                        // Remove the < 0 test.
+                        tool.deleteBranch(trueSuccessor);
+                        graph().removeSplit(this, falseSuccessor);
+
+                        // Replace the second test with the new one.
+                        ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
+                        ifNode2.safeDelete();
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check it these two blocks end up at the same place. Meeting at the same merge, or
+     * deoptimizing in the same way.
+     */
+    private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) {
+        Node next1 = succ1.next();
+        Node next2 = succ2.next();
+        if (next1 instanceof EndNode && next2 instanceof EndNode) {
+            EndNode end1 = (EndNode) next1;
+            EndNode end2 = (EndNode) next2;
+            if (end1.merge() == end2.merge()) {
+                for (PhiNode phi : end1.merge().phis()) {
+                    if (phi.valueAt(end1) != phi.valueAt(end2)) {
+                        return false;
+                    }
+                }
+                // They go to the same MergeNode and merge the same values
+                return true;
+            }
+        } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
+            DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
+            DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
+            if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
+                // Same deoptimization reason and action.
+                return true;
+            }
+        } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
+            LoopExitNode exit1 = (LoopExitNode) next1;
+            LoopExitNode exit2 = (LoopExitNode) next2;
+            if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
+                // Exit the same loop and end up at the same place.
+                return true;
+            }
+        } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
+            ReturnNode exit1 = (ReturnNode) next1;
+            ReturnNode exit2 = (ReturnNode) next2;
+            if (exit1.result() == exit2.result()) {
+                // Exit the same loop and end up at the same place.
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b) {
+        if (a instanceof InstanceOfNode) {
+            InstanceOfNode instanceOfA = (InstanceOfNode) a;
+            if (b instanceof IsNullNode) {
+                IsNullNode isNullNode = (IsNullNode) b;
+                if (isNullNode.getValue() == instanceOfA.getValue()) {
+                    Debug.log("Can swap instanceof and isnull if");
+                    return true;
+                }
+            } else if (b instanceof InstanceOfNode) {
+                InstanceOfNode instanceOfB = (InstanceOfNode) b;
+                if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().getType().isInterface() && !instanceOfB.type().getType().isInterface() &&
+                                !instanceOfA.type().getType().isAssignableFrom(instanceOfB.type().getType()) && !instanceOfB.type().getType().isAssignableFrom(instanceOfA.type().getType())) {
+                    // Two instanceof on the same value with mutually exclusive types.
+                    Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
+                    return true;
+                }
+            }
+        } else if (a instanceof CompareNode) {
+            CompareNode compareA = (CompareNode) a;
+            Condition conditionA = compareA.condition();
+            if (compareA.unorderedIsTrue()) {
+                return false;
+            }
+            if (b instanceof CompareNode) {
+                CompareNode compareB = (CompareNode) b;
+                if (compareA == compareB) {
+                    Debug.log("Same conditions => do not swap and leave the work for global value numbering.");
+                    return false;
+                }
+                if (compareB.unorderedIsTrue()) {
+                    return false;
+                }
+                Condition comparableCondition = null;
+                Condition conditionB = compareB.condition();
+                if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
+                    comparableCondition = conditionB;
+                } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
+                    comparableCondition = conditionB.mirror();
+                }
+
+                if (comparableCondition != null) {
+                    Condition combined = conditionA.join(comparableCondition);
+                    if (combined == null) {
+                        // The two conditions are disjoint => can reorder.
+                        Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
+                        return true;
+                    }
+                } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
+                    boolean canSwap = false;
+                    if ((compareA.getX() == compareB.getX() && valuesDistinct(constantReflection, compareA.getY(), compareB.getY()))) {
+                        canSwap = true;
+                    } else if ((compareA.getX() == compareB.getY() && valuesDistinct(constantReflection, compareA.getY(), compareB.getX()))) {
+                        canSwap = true;
+                    } else if ((compareA.getY() == compareB.getX() && valuesDistinct(constantReflection, compareA.getX(), compareB.getY()))) {
+                        canSwap = true;
+                    } else if ((compareA.getY() == compareB.getY() && valuesDistinct(constantReflection, compareA.getX(), compareB.getX()))) {
+                        canSwap = true;
+                    }
+
+                    if (canSwap) {
+                        Debug.log("Can swap equality condition with one shared and one disjoint value.");
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean valuesDistinct(ConstantReflectionProvider constantReflection, ValueNode a, ValueNode b) {
+        if (a.isConstant() && b.isConstant()) {
+            Boolean equal = constantReflection.constantEquals(a.asConstant(), b.asConstant());
+            if (equal != null) {
+                return !equal.booleanValue();
+            }
+        }
+
+        Stamp stampA = a.stamp();
+        Stamp stampB = b.stamp();
+        return stampA.alwaysDistinct(stampB);
+    }
+
+    /**
+     * Tries to remove an empty if construct or replace an if construct with a materialization.
+     *
+     * @return true if a transformation was made, false otherwise
+     */
+    private boolean removeOrMaterializeIf(SimplifierTool tool) {
+        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
+        if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
+            AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
+            AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
+            AbstractMergeNode merge = trueEnd.merge();
+            if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
+                PhiNode singlePhi = null;
+                int distinct = 0;
+                for (PhiNode phi : merge.phis()) {
+                    ValueNode trueValue = phi.valueAt(trueEnd);
+                    ValueNode falseValue = phi.valueAt(falseEnd);
+                    if (trueValue != falseValue) {
+                        distinct++;
+                        singlePhi = phi;
+                    }
+                }
+                if (distinct == 0) {
+                    /*
+                     * Multiple phis but merging same values for true and false, so simply delete
+                     * the path
+                     */
+                    removeThroughFalseBranch(tool);
+                    return true;
+                } else if (distinct == 1) {
+                    ValueNode trueValue = singlePhi.valueAt(trueEnd);
+                    ValueNode falseValue = singlePhi.valueAt(falseEnd);
+                    ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
+                    if (conditional != null) {
+                        singlePhi.setValueAt(trueEnd, conditional);
+                        removeThroughFalseBranch(tool);
+                        return true;
+                    }
+                }
+            }
+        }
+        if (trueSuccessor().next() instanceof ReturnNode && falseSuccessor().next() instanceof ReturnNode) {
+            ReturnNode trueEnd = (ReturnNode) trueSuccessor().next();
+            ReturnNode falseEnd = (ReturnNode) falseSuccessor().next();
+            ValueNode trueValue = trueEnd.result();
+            ValueNode falseValue = falseEnd.result();
+            ValueNode value = null;
+            if (trueValue != null) {
+                if (trueValue == falseValue) {
+                    value = trueValue;
+                } else {
+                    value = canonicalizeConditionalCascade(trueValue, falseValue);
+                    if (value == null) {
+                        return false;
+                    }
+                }
+            }
+            ReturnNode newReturn = graph().add(new ReturnNode(value));
+            replaceAtPredecessor(newReturn);
+            GraphUtil.killCFG(this);
+            return true;
+        }
+        return false;
+    }
+
+    protected void removeThroughFalseBranch(SimplifierTool tool) {
+        AbstractBeginNode trueBegin = trueSuccessor();
+        graph().removeSplitPropagate(this, trueBegin, tool);
+        tool.addToWorkList(trueBegin);
+        if (condition() != null && condition().isAlive() && condition().hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(condition());
+        }
+    }
+
+    private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
+        if (trueValue.getStackKind() != falseValue.getStackKind()) {
+            return null;
+        }
+        if (trueValue.getStackKind() != JavaKind.Int && trueValue.getStackKind() != JavaKind.Long) {
+            return null;
+        }
+        if (trueValue.isConstant() && falseValue.isConstant()) {
+            return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
+        } else {
+            ConditionalNode conditional = null;
+            ValueNode constant = null;
+            boolean negateCondition;
+            if (trueValue instanceof ConditionalNode && falseValue.isConstant()) {
+                conditional = (ConditionalNode) trueValue;
+                constant = falseValue;
+                negateCondition = true;
+            } else if (falseValue instanceof ConditionalNode && trueValue.isConstant()) {
+                conditional = (ConditionalNode) falseValue;
+                constant = trueValue;
+                negateCondition = false;
+            } else {
+                return null;
+            }
+            boolean negateConditionalCondition;
+            ValueNode otherValue;
+            if (constant == conditional.trueValue()) {
+                otherValue = conditional.falseValue();
+                negateConditionalCondition = false;
+            } else if (constant == conditional.falseValue()) {
+                otherValue = conditional.trueValue();
+                negateConditionalCondition = true;
+            } else {
+                return null;
+            }
+            if (otherValue.isConstant()) {
+                double shortCutProbability = probability(trueSuccessor());
+                LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
+                return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Take an if that is immediately dominated by a merge with a single phi and split off any paths
+     * where the test would be statically decidable creating a new merge below the approriate side
+     * of the IfNode. Any undecidable tests will continue to use the original IfNode.
+     *
+     * @param tool
+     */
+    private boolean splitIfAtPhi(SimplifierTool tool) {
+        if (!(predecessor() instanceof MergeNode)) {
+            return false;
+        }
+        MergeNode merge = (MergeNode) predecessor();
+        if (merge.forwardEndCount() == 1) {
+            // Don't bother.
+            return false;
+        }
+        if (merge.usages().count() != 1 || merge.phis().count() != 1) {
+            return false;
+        }
+        if (merge.stateAfter() != null) {
+            /* We'll get the chance to simplify this after frame state assignment. */
+            return false;
+        }
+        PhiNode phi = merge.phis().first();
+        if (phi.usages().count() != 1) {
+            /*
+             * For simplicity the below code assumes assumes the phi goes dead at the end so skip
+             * this case.
+             */
+            return false;
+        }
+
+        /*
+         * Check that the condition uses the phi and that there is only one user of the condition
+         * expression.
+         */
+        if (!conditionUses(condition(), phi)) {
+            return false;
+        }
+
+        /*
+         * We could additionally filter for the case that at least some of the Phi inputs or one of
+         * the condition inputs are constants but there are cases where a non-constant is
+         * simplifiable, usually where the stamp allows the question to be answered.
+         */
+
+        /* Each successor of the if gets a new merge if needed. */
+        MergeNode trueMerge = null;
+        MergeNode falseMerge = null;
+        assert merge.stateAfter() == null;
+
+        for (EndNode end : merge.forwardEnds().snapshot()) {
+            Node value = phi.valueAt(end);
+            LogicNode result = computeCondition(tool, condition, phi, value);
+            if (result instanceof LogicConstantNode) {
+                merge.removeEnd(end);
+                if (((LogicConstantNode) result).getValue()) {
+                    if (trueMerge == null) {
+                        trueMerge = insertMerge(trueSuccessor());
+                    }
+                    trueMerge.addForwardEnd(end);
+                } else {
+                    if (falseMerge == null) {
+                        falseMerge = insertMerge(falseSuccessor());
+                    }
+                    falseMerge.addForwardEnd(end);
+                }
+            } else if (result != condition) {
+                // Build a new IfNode using the new condition
+                BeginNode trueBegin = graph().add(new BeginNode());
+                BeginNode falseBegin = graph().add(new BeginNode());
+
+                if (result.graph() == null) {
+                    result = graph().addOrUniqueWithInputs(result);
+                }
+                IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
+                merge.removeEnd(end);
+                ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
+
+                if (trueMerge == null) {
+                    trueMerge = insertMerge(trueSuccessor());
+                }
+                trueBegin.setNext(graph().add(new EndNode()));
+                trueMerge.addForwardEnd((EndNode) trueBegin.next());
+
+                if (falseMerge == null) {
+                    falseMerge = insertMerge(falseSuccessor());
+                }
+                falseBegin.setNext(graph().add(new EndNode()));
+                falseMerge.addForwardEnd((EndNode) falseBegin.next());
+
+                end.safeDelete();
+            }
+        }
+        transferProxies(trueSuccessor(), trueMerge);
+        transferProxies(falseSuccessor(), falseMerge);
+
+        cleanupMerge(tool, merge);
+        cleanupMerge(tool, trueMerge);
+        cleanupMerge(tool, falseMerge);
+
+        return true;
+    }
+
+    /**
+     * @param condition
+     * @param phi
+     * @return true if the passed in {@code condition} uses {@code phi} and the condition is only
+     *         used once. Since the phi will go dead the condition using it will also have to be
+     *         dead after the optimization.
+     */
+    private static boolean conditionUses(LogicNode condition, PhiNode phi) {
+        if (condition.usages().count() != 1) {
+            return false;
+        }
+        if (condition instanceof ShortCircuitOrNode) {
+            if (condition.graph().getGuardsStage().areDeoptsFixed()) {
+                /*
+                 * It can be unsafe to simplify a ShortCircuitOr before deopts are fixed because
+                 * conversion to guards assumes that all the required conditions are being tested.
+                 * Simplfying the condition based on context before this happens may lose a
+                 * condition.
+                 */
+                ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
+                return (conditionUses(orNode.x, phi) || conditionUses(orNode.y, phi));
+            }
+        } else if (condition instanceof Canonicalizable.Unary<?>) {
+            Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition;
+            return unary.getValue() == phi;
+        } else if (condition instanceof Canonicalizable.Binary<?>) {
+            Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition;
+            return binary.getX() == phi || binary.getY() == phi;
+        }
+        return false;
+    }
+
+    /**
+     * Canonicalize {@code} condition using {@code value} in place of {@code phi}.
+     *
+     * @param tool
+     * @param condition
+     * @param phi
+     * @param value
+     * @return an improved LogicNode or the original condition
+     */
+    @SuppressWarnings("unchecked")
+    private static LogicNode computeCondition(SimplifierTool tool, LogicNode condition, PhiNode phi, Node value) {
+        if (condition instanceof ShortCircuitOrNode) {
+            if (condition.graph().getGuardsStage().areDeoptsFixed()) {
+                ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
+                LogicNode resultX = computeCondition(tool, orNode.x, phi, value);
+                LogicNode resultY = computeCondition(tool, orNode.y, phi, value);
+                if (resultX != orNode.x || resultY != orNode.y) {
+                    LogicNode result = orNode.canonical(tool, resultX, resultY);
+                    if (result != orNode) {
+                        return result;
+                    }
+                    /*
+                     * Create a new node to carry the optimized inputs.
+                     */
+                    ShortCircuitOrNode newOr = new ShortCircuitOrNode(resultX, orNode.xNegated, resultY,
+                                    orNode.yNegated, orNode.getShortCircuitProbability());
+                    return newOr.canonical(tool);
+                }
+                return orNode;
+            }
+        } else if (condition instanceof Canonicalizable.Binary<?>) {
+            Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
+            if (compare.getX() == phi) {
+                return (LogicNode) compare.canonical(tool, value, compare.getY());
+            } else if (compare.getY() == phi) {
+                return (LogicNode) compare.canonical(tool, compare.getX(), value);
+            }
+        } else if (condition instanceof Canonicalizable.Unary<?>) {
+            Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
+            if (compare.getValue() == phi) {
+                return (LogicNode) compare.canonical(tool, value);
+            }
+        }
+        if (condition instanceof Canonicalizable) {
+            return (LogicNode) ((Canonicalizable) condition).canonical(tool);
+        }
+        return condition;
+    }
+
+    private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
+        if (successor instanceof LoopExitNode && falseMerge != null) {
+            LoopExitNode loopExitNode = (LoopExitNode) successor;
+            for (ProxyNode proxy : loopExitNode.proxies().snapshot()) {
+                proxy.replaceFirstInput(successor, falseMerge);
+            }
+        }
+    }
+
+    private void cleanupMerge(SimplifierTool tool, MergeNode merge) {
+        if (merge != null && merge.isAlive()) {
+            if (merge.forwardEndCount() == 0) {
+                GraphUtil.killCFG(merge, tool);
+            } else if (merge.forwardEndCount() == 1) {
+                graph().reduceTrivialMerge(merge);
+            }
+        }
+    }
+
+    private MergeNode insertMerge(AbstractBeginNode begin) {
+        MergeNode merge = graph().add(new MergeNode());
+        if (!begin.anchored().isEmpty()) {
+            Object before = null;
+            before = begin.anchored().snapshot();
+            begin.replaceAtUsages(InputType.Guard, merge);
+            begin.replaceAtUsages(InputType.Anchor, merge);
+            assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();
+        }
+
+        AbstractBeginNode theBegin = begin;
+        if (begin instanceof LoopExitNode) {
+            // Insert an extra begin to make it easier.
+            theBegin = graph().add(new BeginNode());
+            begin.replaceAtPredecessor(theBegin);
+            theBegin.setNext(begin);
+        }
+        FixedNode next = theBegin.next();
+        next.replaceAtPredecessor(merge);
+        theBegin.setNext(graph().add(new EndNode()));
+        merge.addForwardEnd((EndNode) theBegin.next());
+        merge.setNext(next);
+        return merge;
+    }
+
+    /**
+     * Tries to connect code that initializes a variable directly with the successors of an if
+     * construct that switches on the variable. For example, the pseudo code below:
+     *
+     * <pre>
+     * contains(list, e, yes, no) {
+     *     if (list == null || e == null) {
+     *         condition = false;
+     *     } else {
+     *         condition = false;
+     *         for (i in list) {
+     *             if (i.equals(e)) {
+     *                 condition = true;
+     *                 break;
+     *             }
+     *         }
+     *     }
+     *     if (condition) {
+     *         return yes;
+     *     } else {
+     *         return no;
+     *     }
+     * }
+     * </pre>
+     *
+     * will be transformed into:
+     *
+     * <pre>
+     * contains(list, e, yes, no) {
+     *     if (list == null || e == null) {
+     *         return no;
+     *     } else {
+     *         condition = false;
+     *         for (i in list) {
+     *             if (i.equals(e)) {
+     *                 return yes;
+     *             }
+     *         }
+     *         return no;
+     *     }
+     * }
+     * </pre>
+     *
+     * @return true if a transformation was made, false otherwise
+     */
+    private boolean removeIntermediateMaterialization(SimplifierTool tool) {
+        if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) {
+            return false;
+        }
+        AbstractMergeNode merge = (AbstractMergeNode) predecessor();
+
+        if (!(condition() instanceof CompareNode)) {
+            return false;
+        }
+
+        CompareNode compare = (CompareNode) condition();
+        if (compare.getUsageCount() != 1) {
+            return false;
+        }
+
+        // Only consider merges with a single usage that is both a phi and an operand of the
+        // comparison
+        NodeIterable<Node> mergeUsages = merge.usages();
+        if (mergeUsages.count() != 1) {
+            return false;
+        }
+        Node singleUsage = mergeUsages.first();
+        if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
+            return false;
+        }
+
+        // Ensure phi is used by at most the comparison and the merge's frame state (if any)
+        ValuePhiNode phi = (ValuePhiNode) singleUsage;
+        NodeIterable<Node> phiUsages = phi.usages();
+        if (phiUsages.count() > 2) {
+            return false;
+        }
+        for (Node usage : phiUsages) {
+            if (usage != compare && usage != merge.stateAfter()) {
+                return false;
+            }
+        }
+
+        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        assert phi.valueCount() == merge.forwardEndCount();
+
+        Constant[] xs = constantValues(compare.getX(), merge, false);
+        Constant[] ys = constantValues(compare.getY(), merge, false);
+        if (xs == null || ys == null) {
+            return false;
+        }
+
+        // Sanity check that both ends are not followed by a merge without frame state.
+        if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
+            return false;
+        }
+
+        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+        Map<AbstractEndNode, ValueNode> phiValues = CollectionsFactory.newMap(mergePredecessors.size());
+
+        AbstractBeginNode oldFalseSuccessor = falseSuccessor();
+        AbstractBeginNode oldTrueSuccessor = trueSuccessor();
+
+        setFalseSuccessor(null);
+        setTrueSuccessor(null);
+
+        Iterator<EndNode> ends = mergePredecessors.iterator();
+        for (int i = 0; i < xs.length; i++) {
+            EndNode end = ends.next();
+            phiValues.put(end, phi.valueAt(end));
+            if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
+                trueEnds.add(end);
+            } else {
+                falseEnds.add(end);
+            }
+        }
+        assert !ends.hasNext();
+        assert falseEnds.size() + trueEnds.size() == xs.length;
+
+        connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
+        connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
+
+        if (this.trueSuccessorProbability == 0.0) {
+            for (AbstractEndNode endNode : trueEnds) {
+                propagateZeroProbability(endNode);
+            }
+        }
+
+        if (this.trueSuccessorProbability == 1.0) {
+            for (AbstractEndNode endNode : falseEnds) {
+                propagateZeroProbability(endNode);
+            }
+        }
+
+        /*
+         * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
+         * oldFalseSuccessor might have been removed if it is a LoopExitNode.
+         */
+        if (falseEnds.isEmpty()) {
+            GraphUtil.killCFG(oldFalseSuccessor);
+        }
+        if (trueEnds.isEmpty()) {
+            GraphUtil.killCFG(oldTrueSuccessor);
+        }
+        GraphUtil.killCFG(merge);
+
+        assert !merge.isAlive() : merge;
+        assert !phi.isAlive() : phi;
+        assert !compare.isAlive() : compare;
+        assert !this.isAlive() : this;
+
+        return true;
+    }
+
+    private void propagateZeroProbability(FixedNode startNode) {
+        Node prev = null;
+        for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
+            if (node instanceof IfNode) {
+                IfNode ifNode = (IfNode) node;
+                if (ifNode.trueSuccessor() == prev) {
+                    if (ifNode.trueSuccessorProbability == 0.0) {
+                        return;
+                    } else if (ifNode.trueSuccessorProbability == 1.0) {
+                        continue;
+                    } else {
+                        ifNode.setTrueSuccessorProbability(0.0);
+                        return;
+                    }
+                } else if (ifNode.falseSuccessor() == prev) {
+                    if (ifNode.trueSuccessorProbability == 1.0) {
+                        return;
+                    } else if (ifNode.trueSuccessorProbability == 0.0) {
+                        continue;
+                    } else {
+                        ifNode.setTrueSuccessorProbability(1.0);
+                        return;
+                    }
+                } else {
+                    throw new GraalError("Illegal state");
+                }
+            } else if (node instanceof AbstractMergeNode && !(node instanceof LoopBeginNode)) {
+                for (AbstractEndNode endNode : ((AbstractMergeNode) node).cfgPredecessors()) {
+                    propagateZeroProbability(endNode);
+                }
+                return;
+            }
+            prev = node;
+        }
+    }
+
+    private static boolean checkFrameState(FixedNode start) {
+        FixedNode node = start;
+        while (true) {
+            if (node instanceof AbstractMergeNode) {
+                AbstractMergeNode mergeNode = (AbstractMergeNode) node;
+                if (mergeNode.stateAfter() == null) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else if (node instanceof StateSplit) {
+                StateSplit stateSplitNode = (StateSplit) node;
+                if (stateSplitNode.stateAfter() != null) {
+                    return true;
+                }
+            }
+
+            if (node instanceof ControlSplitNode) {
+                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    if (checkFrameState((FixedNode) succ)) {
+                        return true;
+                    }
+                }
+                return false;
+            } else if (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                node = fixedWithNextNode.next();
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
+                node = endNode.merge();
+            } else if (node instanceof ControlSinkNode) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Connects a set of ends to a given successor, inserting a merge node if there is more than one
+     * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s
+     * {@linkplain SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node) work list}.
+     *
+     * @param oldMerge the merge being removed
+     * @param phiValues the values of the phi at the merge, keyed by the merge ends
+     */
+    private void connectEnds(List<EndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
+        if (!ends.isEmpty()) {
+            if (ends.size() == 1) {
+                AbstractEndNode end = ends.get(0);
+                ((FixedWithNextNode) end.predecessor()).setNext(successor);
+                oldMerge.removeEnd(end);
+                GraphUtil.killCFG(end);
+            } else {
+                // Need a new phi in case the frame state is used by more than the merge being
+                // removed
+                AbstractMergeNode newMerge = graph().add(new MergeNode());
+                PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
+                PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(), newMerge));
+
+                for (EndNode end : ends) {
+                    newPhi.addInput(phiValues.get(end));
+                    newMerge.addForwardEnd(end);
+                }
+
+                FrameState stateAfter = oldMerge.stateAfter();
+                if (stateAfter != null) {
+                    stateAfter = stateAfter.duplicate();
+                    stateAfter.replaceFirstInput(oldPhi, newPhi);
+                    newMerge.setStateAfter(stateAfter);
+                }
+
+                newMerge.setNext(successor);
+            }
+            tool.addToWorkList(successor);
+        }
+    }
+
+    /**
+     * Gets an array of constants derived from a node that is either a {@link ConstantNode} or a
+     * {@link PhiNode} whose input values are all constants. The length of the returned array is
+     * equal to the number of ends terminating in a given merge node.
+     *
+     * @return null if {@code node} is neither a {@link ConstantNode} nor a {@link PhiNode} whose
+     *         input values are all constants
+     */
+    public static Constant[] constantValues(ValueNode node, AbstractMergeNode merge, boolean allowNull) {
+        if (node.isConstant()) {
+            Constant[] result = new Constant[merge.forwardEndCount()];
+            Arrays.fill(result, node.asConstant());
+            return result;
+        }
+
+        if (node instanceof PhiNode) {
+            PhiNode phi = (PhiNode) node;
+            if (phi.merge() == merge && phi instanceof ValuePhiNode && phi.valueCount() == merge.forwardEndCount()) {
+                Constant[] result = new Constant[merge.forwardEndCount()];
+                int i = 0;
+                for (ValueNode n : phi.values()) {
+                    if (!allowNull && !n.isConstant()) {
+                        return null;
+                    }
+                    result[i++] = n.asConstant();
+                }
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public AbstractBeginNode getPrimarySuccessor() {
+        return this.trueSuccessor();
+    }
+
+    public AbstractBeginNode getSuccessor(boolean result) {
+        return result ? this.trueSuccessor() : this.falseSuccessor();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IndirectCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IndirectCallTargetNode.java
new file mode 100644
index 0000000..ac14f67
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IndirectCallTargetNode.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public class IndirectCallTargetNode extends LoweredCallTargetNode {
+    public static final NodeClass<IndirectCallTargetNode> TYPE = NodeClass.create(IndirectCallTargetNode.class);
+
+    @Input protected ValueNode computedAddress;
+
+    public IndirectCallTargetNode(ValueNode computedAddress, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target,
+                    CallingConvention.Type callType,
+                    InvokeKind invokeKind) {
+        this(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
+    protected IndirectCallTargetNode(NodeClass<? extends IndirectCallTargetNode> c, ValueNode computedAddress, ValueNode[] arguments, StampPair returnStamp,
+                    JavaType[] signature,
+                    ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, returnStamp, signature, target, callType, invokeKind);
+        this.computedAddress = computedAddress;
+    }
+
+    public ValueNode computedAddress() {
+        return computedAddress;
+    }
+
+    @Override
+    public String targetName() {
+        return targetMethod().format("Indirect#%h.%n");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java
new file mode 100644
index 0000000..6833216
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode, FixedNodeInterface {
+
+    FixedNode next();
+
+    void setNext(FixedNode x);
+
+    CallTargetNode callTarget();
+
+    int bci();
+
+    Node predecessor();
+
+    ValueNode classInit();
+
+    void setClassInit(ValueNode node);
+
+    void intrinsify(Node node);
+
+    boolean useForInlining();
+
+    void setUseForInlining(boolean value);
+
+    /**
+     * True if this invocation is almost certainly polymorphic, false when in doubt.
+     */
+    boolean isPolymorphic();
+
+    void setPolymorphic(boolean value);
+
+    /**
+     * Returns the {@linkplain ResolvedJavaMethod method} from which this invoke is executed. This
+     * is the caller method and in the case of inlining may be different from the method of the
+     * graph this node is in.
+     *
+     * @return the method from which this invoke is executed.
+     */
+    default ResolvedJavaMethod getContextMethod() {
+        FrameState state = stateAfter();
+        if (state == null) {
+            state = stateDuring();
+        }
+        return state.getMethod();
+    }
+
+    /**
+     * Returns the {@linkplain ResolvedJavaType type} from which this invoke is executed. This is
+     * the declaring type of the caller method.
+     *
+     * @return the type from which this invoke is executed.
+     */
+    default ResolvedJavaType getContextType() {
+        ResolvedJavaMethod contextMethod = getContextMethod();
+        if (contextMethod == null) {
+            return null;
+        }
+        return contextMethod.getDeclaringClass();
+    }
+
+    @Override
+    default void computeStateDuring(FrameState stateAfter) {
+        FrameState newStateDuring = stateAfter.duplicateModifiedDuringCall(bci(), asNode().getStackKind());
+        setStateDuring(newStateDuring);
+    }
+
+    default ValueNode getReceiver() {
+        assert getInvokeKind().hasReceiver();
+        return callTarget().arguments().get(0);
+    }
+
+    default ResolvedJavaType getReceiverType() {
+        ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver());
+        if (receiverType == null) {
+            receiverType = ((MethodCallTargetNode) callTarget()).targetMethod().getDeclaringClass();
+        }
+        return receiverType;
+    }
+
+    default InvokeKind getInvokeKind() {
+        return callTarget().invokeKind();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java
new file mode 100644
index 0000000..fea0fe9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code InvokeNode} represents all kinds of method calls.
+ */
+// @formatter:off
+@NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}",
+          allowedUsageTypes = {Memory},
+          cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "We cannot estimate the runtime cost of a call, it is a blackhole." +
+                            "However, we can estimate, dyanmically, the cost of the call operation itself based on the type of the call.",
+          size = SIZE_UNKNOWN,
+          sizeRationale = "We can only dyanmically, based on the type of the call (special, static, virtual, interface) decide" +
+                          "how much code is generated for the call.")
+// @formatter:on
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, UncheckedInterfaceProvider {
+    public static final NodeClass<InvokeNode> TYPE = NodeClass.create(InvokeNode.class);
+
+    @OptionalInput ValueNode classInit;
+    @Input(Extension) CallTargetNode callTarget;
+    @OptionalInput(State) FrameState stateDuring;
+    @OptionalInput(Guard) GuardingNode guard;
+    protected final int bci;
+    protected boolean polymorphic;
+    protected boolean useForInlining;
+
+    public InvokeNode(CallTargetNode callTarget, int bci) {
+        this(callTarget, bci, callTarget.returnStamp().getTrustedStamp());
+    }
+
+    public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp) {
+        super(TYPE, stamp);
+        this.callTarget = callTarget;
+        this.bci = bci;
+        this.polymorphic = false;
+        this.useForInlining = true;
+    }
+
+    @Override
+    public CallTargetNode callTarget() {
+        return callTarget;
+    }
+
+    void setCallTarget(CallTargetNode callTarget) {
+        updateUsages(this.callTarget, callTarget);
+        this.callTarget = callTarget;
+    }
+
+    @Override
+    public boolean isPolymorphic() {
+        return polymorphic;
+    }
+
+    @Override
+    public void setPolymorphic(boolean value) {
+        this.polymorphic = value;
+    }
+
+    @Override
+    public boolean useForInlining() {
+        return useForInlining;
+    }
+
+    @Override
+    public void setUseForInlining(boolean value) {
+        this.useForInlining = value;
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        if (!super.isAllowedUsageType(type)) {
+            if (getStackKind() != JavaKind.Void) {
+                if (callTarget instanceof MethodCallTargetNode && ((MethodCallTargetNode) callTarget).targetMethod().getAnnotation(NodeIntrinsic.class) != null) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> debugProperties = super.getDebugProperties(map);
+        if (callTarget != null) {
+            debugProperties.put("targetMethod", callTarget.targetName());
+        }
+        return debugProperties;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.emitInvoke(this);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Long) {
+            return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
+        } else if (verbosity == Verbosity.Name) {
+            return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public int bci() {
+        return bci;
+    }
+
+    @Override
+    public void intrinsify(Node node) {
+        assert !(node instanceof ValueNode) || node.isAllowedUsageType(InputType.Value) == isAllowedUsageType(InputType.Value) : "replacing " + this + " with " + node;
+        CallTargetNode call = callTarget;
+        FrameState currentStateAfter = stateAfter();
+        if (node instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) node;
+            stateSplit.setStateAfter(currentStateAfter);
+        }
+        if (node instanceof ForeignCallNode) {
+            ForeignCallNode foreign = (ForeignCallNode) node;
+            foreign.setBci(bci());
+        }
+        if (node instanceof FixedWithNextNode) {
+            graph().replaceFixedWithFixed(this, (FixedWithNextNode) node);
+        } else if (node instanceof ControlSinkNode) {
+            this.replaceAtPredecessor(node);
+            this.replaceAtUsages(null);
+            GraphUtil.killCFG(this);
+            return;
+        } else {
+            graph().replaceFixed(this, node);
+        }
+        GraphUtil.killWithUnusedFloatingInputs(call);
+        if (currentStateAfter.hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(currentStateAfter);
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    @Override
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+
+    @Override
+    public Stamp uncheckedStamp() {
+        return this.callTarget.returnStamp().getUncheckedStamp();
+    }
+
+    @Override
+    public void setClassInit(ValueNode classInit) {
+        this.classInit = classInit;
+        updateUsages(null, classInit);
+    }
+
+    @Override
+    public ValueNode classInit() {
+        return classInit;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java
new file mode 100644
index 0000000..6a2a7cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}", allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, MemoryCheckpoint.Single, LIRLowerable, UncheckedInterfaceProvider {
+    public static final NodeClass<InvokeWithExceptionNode> TYPE = NodeClass.create(InvokeWithExceptionNode.class);
+
+    private static final double EXCEPTION_PROBA = 1e-5;
+
+    @Successor AbstractBeginNode next;
+    @Successor AbstractBeginNode exceptionEdge;
+    @OptionalInput ValueNode classInit;
+    @Input(Extension) CallTargetNode callTarget;
+    @OptionalInput(State) FrameState stateDuring;
+    @OptionalInput(State) FrameState stateAfter;
+    @OptionalInput(Guard) GuardingNode guard;
+    protected final int bci;
+    protected boolean polymorphic;
+    protected boolean useForInlining;
+    protected double exceptionProbability;
+
+    public InvokeWithExceptionNode(CallTargetNode callTarget, AbstractBeginNode exceptionEdge, int bci) {
+        super(TYPE, callTarget.returnStamp().getTrustedStamp());
+        this.exceptionEdge = exceptionEdge;
+        this.bci = bci;
+        this.callTarget = callTarget;
+        this.polymorphic = false;
+        this.useForInlining = true;
+        this.exceptionProbability = EXCEPTION_PROBA;
+    }
+
+    public AbstractBeginNode exceptionEdge() {
+        return exceptionEdge;
+    }
+
+    public void setExceptionEdge(AbstractBeginNode x) {
+        updatePredecessor(exceptionEdge, x);
+        exceptionEdge = x;
+    }
+
+    @Override
+    public AbstractBeginNode next() {
+        return next;
+    }
+
+    public void setNext(AbstractBeginNode x) {
+        updatePredecessor(next, x);
+        next = x;
+    }
+
+    @Override
+    public CallTargetNode callTarget() {
+        return callTarget;
+    }
+
+    void setCallTarget(CallTargetNode callTarget) {
+        updateUsages(this.callTarget, callTarget);
+        this.callTarget = callTarget;
+    }
+
+    public MethodCallTargetNode methodCallTarget() {
+        return (MethodCallTargetNode) callTarget;
+    }
+
+    @Override
+    public boolean isPolymorphic() {
+        return polymorphic;
+    }
+
+    @Override
+    public void setPolymorphic(boolean value) {
+        this.polymorphic = value;
+    }
+
+    @Override
+    public boolean useForInlining() {
+        return useForInlining;
+    }
+
+    @Override
+    public void setUseForInlining(boolean value) {
+        this.useForInlining = value;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Long) {
+            return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
+        } else if (verbosity == Verbosity.Name) {
+            return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public int bci() {
+        return bci;
+    }
+
+    @Override
+    public void setNext(FixedNode x) {
+        if (x != null) {
+            this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
+        } else {
+            this.setNext(null);
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.emitInvoke(this);
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState stateAfter) {
+        updateUsages(this.stateAfter, stateAfter);
+        this.stateAfter = stateAfter;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> debugProperties = super.getDebugProperties(map);
+        if (callTarget != null) {
+            debugProperties.put("targetMethod", callTarget.targetName());
+        }
+        return debugProperties;
+    }
+
+    public void killExceptionEdge() {
+        AbstractBeginNode edge = exceptionEdge();
+        setExceptionEdge(null);
+        GraphUtil.killCFG(edge);
+    }
+
+    @Override
+    public void intrinsify(Node node) {
+        assert !(node instanceof ValueNode) || (((ValueNode) node).getStackKind() == JavaKind.Void) == (getStackKind() == JavaKind.Void);
+        CallTargetNode call = callTarget;
+        FrameState state = stateAfter();
+        killExceptionEdge();
+        if (node instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) node;
+            stateSplit.setStateAfter(state);
+        }
+        if (node instanceof ForeignCallNode) {
+            ForeignCallNode foreign = (ForeignCallNode) node;
+            foreign.setBci(bci());
+        }
+        if (node == null) {
+            assert getStackKind() == JavaKind.Void && hasNoUsages();
+            graph().removeSplit(this, next());
+        } else if (node instanceof ControlSinkNode) {
+            this.replaceAtPredecessor(node);
+            this.replaceAtUsages(null);
+            GraphUtil.killCFG(this);
+            return;
+        } else {
+            graph().replaceSplit(this, node, next());
+        }
+        GraphUtil.killWithUnusedFloatingInputs(call);
+        if (state.hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(state);
+        }
+    }
+
+    @Override
+    public double probability(AbstractBeginNode successor) {
+        return successor == next ? 1 - exceptionProbability : exceptionProbability;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    @Override
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+
+    @Override
+    public AbstractBeginNode getPrimarySuccessor() {
+        return this.next();
+    }
+
+    @Override
+    public Stamp uncheckedStamp() {
+        return this.callTarget.returnStamp().getUncheckedStamp();
+    }
+
+    @Override
+    public void setClassInit(ValueNode classInit) {
+        this.classInit = classInit;
+        updateUsages(null, classInit);
+    }
+
+    @Override
+    public ValueNode classInit() {
+        return classInit;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java
new file mode 100644
index 0000000..6deb395
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+@NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_0, size = SIZE_0)
+public final class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single {
+
+    public static final NodeClass<KillingBeginNode> TYPE = NodeClass.create(KillingBeginNode.class);
+    protected LocationIdentity locationIdentity;
+
+    public KillingBeginNode(LocationIdentity locationIdentity) {
+        super(TYPE);
+        this.locationIdentity = locationIdentity;
+    }
+
+    public static KillingBeginNode begin(FixedNode with, LocationIdentity locationIdentity) {
+        if (with instanceof KillingBeginNode) {
+            return (KillingBeginNode) with;
+        }
+        KillingBeginNode begin = with.graph().add(new KillingBeginNode(locationIdentity));
+        begin.setNext(with);
+        return begin;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicConstantNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicConstantNode.java
new file mode 100644
index 0000000..68e7a19
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicConstantNode.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code LogicConstantNode} represents a boolean constant.
+ */
+@NodeInfo(nameTemplate = "{p#value}", cycles = CYCLES_0, size = SIZE_0)
+public final class LogicConstantNode extends LogicNode implements LIRLowerable {
+
+    public static final NodeClass<LogicConstantNode> TYPE = NodeClass.create(LogicConstantNode.class);
+    protected final boolean value;
+
+    public LogicConstantNode(boolean value) {
+        super(TYPE);
+        this.value = value;
+    }
+
+    /**
+     * Returns a node for a boolean constant.
+     *
+     * @param v the boolean value for which to create the instruction
+     * @param graph
+     * @return a node representing the boolean
+     */
+    public static LogicConstantNode forBoolean(boolean v, Graph graph) {
+        return graph.unique(new LogicConstantNode(v));
+    }
+
+    /**
+     * Returns a node for a boolean constant.
+     *
+     * @param v the boolean value for which to create the instruction
+     * @return a node representing the boolean
+     */
+    public static LogicConstantNode forBoolean(boolean v) {
+        return new LogicConstantNode(v);
+    }
+
+    /**
+     * Gets a constant for {@code true}.
+     */
+    public static LogicConstantNode tautology(Graph graph) {
+        return forBoolean(true, graph);
+    }
+
+    /**
+     * Gets a constant for {@code false}.
+     */
+    public static LogicConstantNode contradiction(Graph graph) {
+        return forBoolean(false, graph);
+    }
+
+    /**
+     * Gets a constant for {@code true}.
+     */
+    public static LogicConstantNode tautology() {
+        return forBoolean(true);
+    }
+
+    /**
+     * Gets a constant for {@code false}.
+     */
+    public static LogicConstantNode contradiction() {
+        return forBoolean(false);
+    }
+
+    public boolean getValue() {
+        return value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // nothing to do
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNegationNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNegationNode.java
new file mode 100644
index 0000000..d97b7ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNegationNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Condition;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Logic node that negates its argument.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class LogicNegationNode extends LogicNode implements Canonicalizable.Unary<LogicNode> {
+
+    public static final NodeClass<LogicNegationNode> TYPE = NodeClass.create(LogicNegationNode.class);
+    @Input(Condition) LogicNode value;
+
+    public LogicNegationNode(LogicNode value) {
+        super(TYPE);
+        this.value = value;
+    }
+
+    public static LogicNode create(LogicNode value) {
+        LogicNode synonym = findSynonym(value);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new LogicNegationNode(value);
+    }
+
+    private static LogicNode findSynonym(LogicNode value) {
+        if (value instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) value;
+            return LogicConstantNode.forBoolean(!logicConstantNode.getValue());
+        } else if (value instanceof LogicNegationNode) {
+            return ((LogicNegationNode) value).getValue();
+        }
+        return null;
+    }
+
+    @Override
+    public LogicNode getValue() {
+        return value;
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool, LogicNode forValue) {
+        LogicNode synonym = findSynonym(forValue);
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNode.java
new file mode 100644
index 0000000..ae66411
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNode.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Condition;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+@NodeInfo(allowedUsageTypes = {Condition}, size = SIZE_1)
+public abstract class LogicNode extends FloatingNode implements IndirectCanonicalization {
+
+    public static final NodeClass<LogicNode> TYPE = NodeClass.create(LogicNode.class);
+
+    public LogicNode(NodeClass<? extends LogicNode> c) {
+        super(c, StampFactory.forVoid());
+    }
+
+    public static LogicNode and(LogicNode a, LogicNode b, double shortCircuitProbability) {
+        return and(a, false, b, false, shortCircuitProbability);
+    }
+
+    public static LogicNode and(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
+        StructuredGraph graph = a.graph();
+        ShortCircuitOrNode notAorNotB = graph.unique(new ShortCircuitOrNode(a, !negateA, b, !negateB, shortCircuitProbability));
+        return graph.unique(new LogicNegationNode(notAorNotB));
+    }
+
+    public static LogicNode or(LogicNode a, LogicNode b, double shortCircuitProbability) {
+        return or(a, false, b, false, shortCircuitProbability);
+    }
+
+    public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
+        return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability));
+    }
+
+    public final boolean isTautology() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return logicConstantNode.getValue();
+        }
+
+        return false;
+    }
+
+    public final boolean isContradiction() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return !logicConstantNode.getValue();
+        }
+
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java
new file mode 100644
index 0000000..cee9559
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+@NodeInfo
+public final class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable {
+
+    public static final NodeClass<LoopBeginNode> TYPE = NodeClass.create(LoopBeginNode.class);
+    protected double loopFrequency;
+    protected int nextEndIndex;
+    protected int unswitches;
+    protected int inversionCount;
+
+    /** See {@link LoopEndNode#canSafepoint} for more information. */
+    boolean canEndsSafepoint;
+
+    @OptionalInput(InputType.Guard) GuardingNode overflowGuard;
+
+    public LoopBeginNode() {
+        super(TYPE);
+        loopFrequency = 1;
+        this.canEndsSafepoint = true;
+    }
+
+    /** Disables safepoint for the whole loop, i.e., for all {@link LoopEndNode loop ends}. */
+    public void disableSafepoint() {
+        /* Store flag locally in case new loop ends are created later on. */
+        this.canEndsSafepoint = false;
+        /* Propagate flag to all existing loop ends. */
+        for (LoopEndNode loopEnd : loopEnds()) {
+            loopEnd.disableSafepoint();
+        }
+    }
+
+    public double loopFrequency() {
+        return loopFrequency;
+    }
+
+    public void setLoopFrequency(double loopFrequency) {
+        assert loopFrequency >= 0;
+        this.loopFrequency = loopFrequency;
+    }
+
+    /**
+     * Returns the <b>unordered</b> set of {@link LoopEndNode} that correspond to back-edges for
+     * this loop. The order of the back-edges is unspecified, if you need to get an ordering
+     * compatible for {@link PhiNode} creation, use {@link #orderedLoopEnds()}.
+     *
+     * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
+     */
+    public NodeIterable<LoopEndNode> loopEnds() {
+        return usages().filter(LoopEndNode.class);
+    }
+
+    public NodeIterable<LoopExitNode> loopExits() {
+        return usages().filter(LoopExitNode.class);
+    }
+
+    @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(isNotA(LoopEndNode.class).nor(LoopExitNode.class));
+    }
+
+    /**
+     * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, in
+     * increasing {@link #phiPredecessorIndex} order. This method is suited to create new loop
+     * {@link PhiNode}.<br>
+     *
+     * For example a new PhiNode may be added as follow:
+     *
+     * <pre>
+     * PhiNode phi = new ValuePhiNode(stamp, loop);
+     * phi.addInput(forwardEdgeValue);
+     * for (LoopEndNode loopEnd : loop.orderedLoopEnds()) {
+     *     phi.addInput(backEdgeValue(loopEnd));
+     * }
+     * </pre>
+     *
+     * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
+     */
+    public LoopEndNode[] orderedLoopEnds() {
+        LoopEndNode[] result = new LoopEndNode[this.getLoopEndCount()];
+        for (LoopEndNode end : loopEnds()) {
+            result[end.endIndex()] = end;
+        }
+        return result;
+    }
+
+    public AbstractEndNode forwardEnd() {
+        assert forwardEndCount() == 1;
+        return forwardEndAt(0);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // Nothing to emit, since this is node is used for structural purposes only.
+    }
+
+    @Override
+    protected void deleteEnd(AbstractEndNode end) {
+        if (end instanceof LoopEndNode) {
+            LoopEndNode loopEnd = (LoopEndNode) end;
+            loopEnd.setLoopBegin(null);
+            int idx = loopEnd.endIndex();
+            for (LoopEndNode le : loopEnds()) {
+                int leIdx = le.endIndex();
+                assert leIdx != idx;
+                if (leIdx > idx) {
+                    le.setEndIndex(leIdx - 1);
+                }
+            }
+            nextEndIndex--;
+        } else {
+            super.deleteEnd(end);
+        }
+    }
+
+    @Override
+    public int phiPredecessorCount() {
+        return forwardEndCount() + loopEnds().count();
+    }
+
+    @Override
+    public int phiPredecessorIndex(AbstractEndNode pred) {
+        if (pred instanceof LoopEndNode) {
+            LoopEndNode loopEnd = (LoopEndNode) pred;
+            if (loopEnd.loopBegin() == this) {
+                assert loopEnd.endIndex() < loopEnds().count() : "Invalid endIndex : " + loopEnd;
+                return loopEnd.endIndex() + forwardEndCount();
+            }
+        } else {
+            return super.forwardEndIndex((EndNode) pred);
+        }
+        throw ValueNodeUtil.shouldNotReachHere("unknown pred : " + pred);
+    }
+
+    @Override
+    public AbstractEndNode phiPredecessorAt(int index) {
+        if (index < forwardEndCount()) {
+            return forwardEndAt(index);
+        }
+        for (LoopEndNode end : loopEnds()) {
+            int idx = index - forwardEndCount();
+            assert idx >= 0;
+            if (end.endIndex() == idx) {
+                return end;
+            }
+        }
+        throw ValueNodeUtil.shouldNotReachHere();
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(loopEnds().isNotEmpty(), "missing loopEnd");
+        return super.verify();
+    }
+
+    int nextEndIndex() {
+        return nextEndIndex++;
+    }
+
+    public int getLoopEndCount() {
+        return nextEndIndex;
+    }
+
+    public int unswitches() {
+        return unswitches;
+    }
+
+    public void incrementUnswitches() {
+        unswitches++;
+    }
+
+    public int getInversionCount() {
+        return inversionCount;
+    }
+
+    public void setInversionCount(int count) {
+        inversionCount = count;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        canonicalizePhis(tool);
+    }
+
+    public boolean isLoopExit(AbstractBeginNode begin) {
+        return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
+    }
+
+    public void removeExits() {
+        for (LoopExitNode loopexit : loopExits().snapshot()) {
+            loopexit.removeProxies();
+            FrameState loopStateAfter = loopexit.stateAfter();
+            graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
+            if (loopStateAfter != null && loopStateAfter.isAlive() && loopStateAfter.hasNoUsages()) {
+                GraphUtil.killWithUnusedFloatingInputs(loopStateAfter);
+            }
+        }
+    }
+
+    public GuardingNode getOverflowGuard() {
+        return overflowGuard;
+    }
+
+    public void setOverflowGuard(GuardingNode overflowGuard) {
+        updateUsagesInterface(this.overflowGuard, overflowGuard);
+        this.overflowGuard = overflowGuard;
+    }
+
+    private static final int NO_INCREMENT = Integer.MIN_VALUE;
+
+    /**
+     * Returns an array with one entry for each input of the phi, which is either
+     * {@link #NO_INCREMENT} or the increment, i.e., the value by which the phi is incremented in
+     * the corresponding branch.
+     */
+    private static int[] getSelfIncrements(PhiNode phi) {
+        int[] selfIncrement = new int[phi.valueCount()];
+        for (int i = 0; i < phi.valueCount(); i++) {
+            ValueNode input = phi.valueAt(i);
+            long increment = NO_INCREMENT;
+            if (input != null && input instanceof AddNode && input.stamp() instanceof IntegerStamp) {
+                AddNode add = (AddNode) input;
+                if (add.getX() == phi && add.getY().isConstant()) {
+                    increment = add.getY().asJavaConstant().asLong();
+                } else if (add.getY() == phi && add.getX().isConstant()) {
+                    increment = add.getX().asJavaConstant().asLong();
+                }
+            } else if (input == phi) {
+                increment = 0;
+            }
+            if (increment < Integer.MIN_VALUE || increment > Integer.MAX_VALUE || increment == NO_INCREMENT) {
+                increment = NO_INCREMENT;
+            }
+            selfIncrement[i] = (int) increment;
+        }
+        return selfIncrement;
+    }
+
+    /**
+     * Coalesces loop phis that represent the same value (which is not handled by normal Global
+     * Value Numbering).
+     */
+    public void canonicalizePhis(SimplifierTool tool) {
+        int phiCount = phis().count();
+        if (phiCount > 1) {
+            int phiInputCount = phiPredecessorCount();
+            int phiIndex = 0;
+            int[][] selfIncrement = new int[phiCount][];
+            PhiNode[] phis = this.phis().snapshot().toArray(new PhiNode[phiCount]);
+
+            for (phiIndex = 0; phiIndex < phiCount; phiIndex++) {
+                PhiNode phi = phis[phiIndex];
+                if (phi != null) {
+                    nextPhi: for (int otherPhiIndex = phiIndex + 1; otherPhiIndex < phiCount; otherPhiIndex++) {
+                        PhiNode otherPhi = phis[otherPhiIndex];
+                        if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.valueEquals(otherPhi)) {
+                            continue nextPhi;
+                        }
+                        if (selfIncrement[phiIndex] == null) {
+                            selfIncrement[phiIndex] = getSelfIncrements(phi);
+                        }
+                        if (selfIncrement[otherPhiIndex] == null) {
+                            selfIncrement[otherPhiIndex] = getSelfIncrements(otherPhi);
+                        }
+                        int[] phiIncrement = selfIncrement[phiIndex];
+                        int[] otherPhiIncrement = selfIncrement[otherPhiIndex];
+                        for (int inputIndex = 0; inputIndex < phiInputCount; inputIndex++) {
+                            if (phiIncrement[inputIndex] == NO_INCREMENT) {
+                                if (phi.valueAt(inputIndex) != otherPhi.valueAt(inputIndex)) {
+                                    continue nextPhi;
+                                }
+                            }
+                            if (phiIncrement[inputIndex] != otherPhiIncrement[inputIndex]) {
+                                continue nextPhi;
+                            }
+                        }
+                        if (tool != null) {
+                            tool.addToWorkList(otherPhi.usages());
+                        }
+                        otherPhi.replaceAtUsages(phi);
+                        GraphUtil.killWithUnusedFloatingInputs(otherPhi);
+                        phis[otherPhiIndex] = null;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java
new file mode 100644
index 0000000..e8d33f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.Collections;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * LoopEnd nodes represent a loop back-edge. When a LoopEnd is reached, execution continues at the
+ * {@linkplain #loopBegin() loop header}.
+ */
+@NodeInfo(cycles = CYCLES_1, cyclesRationale = "Backedge jmp", size = SIZE_1, sizeRationale = "Backedge jmp")
+public final class LoopEndNode extends AbstractEndNode {
+
+    public static final NodeClass<LoopEndNode> TYPE = NodeClass.create(LoopEndNode.class);
+
+    /*
+     * The declared type of the field cannot be LoopBeginNode, because loop explosion during partial
+     * evaluation can temporarily assign a non-loop begin. This node will then be deleted shortly
+     * after - but we still must not have type system violations for that short amount of time.
+     */
+    @Input(Association) AbstractBeginNode loopBegin;
+    protected int endIndex;
+
+    /**
+     * Most loop ends need a safepoint (flag set to true) so that garbage collection can interrupt a
+     * long-running (possibly endless) loop. Safepoints may be disabled for two reasons: 1) Some
+     * code must be safepoint free, i.e., uninterruptible by garbage collection. 2) An optimization
+     * phase determined that the loop already has another safepoint or cannot be endless, so there
+     * is no need for a loop-end safepoint.
+     *
+     * Note that 1) is a hard correctness issue: emitting a safepoint in uninterruptible code is a
+     * bug, i.e., it is not allowed to set the flag back to true once it is false. To ensure that
+     * loop ends that are created late, e.g., during control flow simplifications, have no
+     * safepoints in such cases, the safepoints are actually disabled for the
+     * {@link LoopBeginNode#canEndsSafepoint loop begin}. New loop ends inherit the flag value from
+     * the loop begin.
+     */
+    boolean canSafepoint;
+
+    public LoopEndNode(LoopBeginNode begin) {
+        super(TYPE);
+        int idx = begin.nextEndIndex();
+        assert idx >= 0;
+        this.endIndex = idx;
+        this.loopBegin = begin;
+        this.canSafepoint = begin.canEndsSafepoint;
+    }
+
+    @Override
+    public AbstractMergeNode merge() {
+        return loopBegin();
+    }
+
+    public LoopBeginNode loopBegin() {
+        return (LoopBeginNode) loopBegin;
+    }
+
+    public void setLoopBegin(LoopBeginNode x) {
+        updateUsages(this.loopBegin, x);
+        this.loopBegin = x;
+    }
+
+    /**
+     * Disables safepoints for only this loop end (in contrast to disabling it for
+     * {@link LoopBeginNode#disableSafepoint() the whole loop}.
+     */
+    public void disableSafepoint() {
+        this.canSafepoint = false;
+    }
+
+    public boolean canSafepoint() {
+        assert !canSafepoint || loopBegin().canEndsSafepoint : "When safepoints are disabled for loop begin, safepoints must be disabled for all loop ends";
+        return canSafepoint;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.visitLoopEnd(this);
+        super.generate(gen);
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(loopBegin != null, "must have a loop begin");
+        assertTrue(hasNoUsages(), "LoopEnds can not be used");
+        return super.verify();
+    }
+
+    /**
+     * Returns the index of this loop end amongst its {@link LoopBeginNode}'s loop ends.<br>
+     *
+     * Since a LoopBeginNode also has {@linkplain LoopBeginNode#forwardEnds() forward ends}, this is
+     * <b>not</b> the index into {@link PhiNode} values at the loop begin. Use
+     * {@link LoopBeginNode#phiPredecessorIndex(AbstractEndNode)} for this purpose.
+     *
+     */
+    int endIndex() {
+        return endIndex;
+    }
+
+    void setEndIndex(int idx) {
+        this.endIndex = idx;
+    }
+
+    @Override
+    public Iterable<? extends Node> cfgSuccessors() {
+        return Collections.emptyList();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java
new file mode 100644
index 0000000..f1419ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo(allowedUsageTypes = {Association}, cycles = CYCLES_0, size = SIZE_0)
+public final class LoopExitNode extends BeginStateSplitNode implements IterableNodeType, Simplifiable {
+
+    public static final NodeClass<LoopExitNode> TYPE = NodeClass.create(LoopExitNode.class);
+
+    /*
+     * The declared type of the field cannot be LoopBeginNode, because loop explosion during partial
+     * evaluation can temporarily assign a non-loop begin. This node will then be deleted shortly
+     * after - but we still must not have type system violations for that short amount of time.
+     */
+    @Input(Association) AbstractBeginNode loopBegin;
+
+    public LoopExitNode(LoopBeginNode loop) {
+        super(TYPE);
+        assert loop != null;
+        loopBegin = loop;
+    }
+
+    public LoopBeginNode loopBegin() {
+        return (LoopBeginNode) loopBegin;
+    }
+
+    @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(n -> {
+            if (n instanceof ProxyNode) {
+                ProxyNode proxyNode = (ProxyNode) n;
+                return proxyNode.proxyPoint() != this;
+            }
+            return true;
+        });
+    }
+
+    @Override
+    public void prepareDelete(FixedNode evacuateFrom) {
+        removeProxies();
+        super.prepareDelete(evacuateFrom);
+    }
+
+    public void removeProxies() {
+        if (this.hasUsages()) {
+            outer: while (true) {
+                for (ProxyNode vpn : proxies().snapshot()) {
+                    ValueNode value = vpn.value();
+                    vpn.replaceAtUsagesAndDelete(value);
+                    if (value == this) {
+                        // Guard proxy could have this input as value.
+                        continue outer;
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public NodeIterable<ProxyNode> proxies() {
+        return (NodeIterable) usages().filter(n -> {
+            if (n instanceof ProxyNode) {
+                ProxyNode proxyNode = (ProxyNode) n;
+                return proxyNode.proxyPoint() == this;
+            }
+            return false;
+        });
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        Node prev = this.predecessor();
+        while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) {
+            AbstractBeginNode begin = (AbstractBeginNode) prev;
+            prev = prev.predecessor();
+            graph().removeFixed(begin);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoweredCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoweredCallTargetNode.java
new file mode 100644
index 0000000..b43ba2e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoweredCallTargetNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
+public abstract class LoweredCallTargetNode extends CallTargetNode {
+
+    public static final NodeClass<LoweredCallTargetNode> TYPE = NodeClass.create(LoweredCallTargetNode.class);
+    protected final JavaType[] signature;
+    protected final CallingConvention.Type callType;
+
+    protected LoweredCallTargetNode(NodeClass<? extends LoweredCallTargetNode> c, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature,
+                    ResolvedJavaMethod target,
+                    CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, target, invokeKind, returnStamp);
+        this.signature = signature;
+        this.callType = callType;
+    }
+
+    public JavaType[] signature() {
+        return signature;
+    }
+
+    public CallingConvention.Type callType() {
+        return callType;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/MergeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/MergeNode.java
new file mode 100644
index 0000000..b5e78b6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/MergeNode.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Denotes the merging of multiple control-flow paths.
+ */
+@NodeInfo
+public final class MergeNode extends AbstractMergeNode {
+
+    public static final NodeClass<MergeNode> TYPE = NodeClass.create(MergeNode.class);
+
+    public MergeNode() {
+        super(TYPE);
+    }
+
+    public static void removeMergeIfDegenerated(MergeNode node) {
+        if (node.forwardEndCount() == 1 && node.hasNoUsages()) {
+            FixedNode currentNext = node.next();
+            node.setNext(null);
+            EndNode forwardEnd = node.forwardEndAt(0);
+            forwardEnd.replaceAtPredecessor(currentNext);
+            node.markDeleted();
+            forwardEnd.markDeleted();
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(this.forwardEndCount() > 1, "Must merge more than one end.");
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java
new file mode 100644
index 0000000..70df123
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.EnumMap;
+import java.util.HashSet;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaKind.FormatWithToString;
+
+/**
+ * A {@link LocationIdentity} with a name.
+ */
+public class NamedLocationIdentity extends LocationIdentity implements FormatWithToString {
+
+    /**
+     * Map for asserting all {@link NamedLocationIdentity} instances have a unique name.
+     */
+    static class DB {
+        private static final HashSet<String> map = new HashSet<>();
+
+        static boolean checkUnique(String name) {
+            if (!map.add(name)) {
+                throw new AssertionError("identity " + name + " already exists");
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Denotes the location of a value that is guaranteed to be unchanging.
+     */
+    public static final LocationIdentity FINAL_LOCATION = NamedLocationIdentity.immutable("FINAL_LOCATION");
+
+    /**
+     * Denotes the location of the length field of a Java array.
+     */
+    public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
+
+    public static LocationIdentity any() {
+        return ANY_LOCATION;
+    }
+
+    private final String name;
+    private final boolean immutable;
+
+    protected NamedLocationIdentity(String name, boolean immutable) {
+        this.name = name;
+        this.immutable = immutable;
+        assert DB.checkUnique(name);
+    }
+
+    /**
+     * Creates a named unique location identity for read and write operations against mutable
+     * memory.
+     *
+     * @param name the name of the new location identity
+     */
+    public static NamedLocationIdentity mutable(String name) {
+        return create(name, false);
+    }
+
+    /**
+     * Creates a named unique location identity for read operations against immutable memory.
+     * Immutable memory will never have a visible write in the graph, which is more restictive than
+     * Java final.
+     *
+     * @param name the name of the new location identity
+     */
+    public static NamedLocationIdentity immutable(String name) {
+        return create(name, true);
+    }
+
+    /**
+     * Creates a named unique location identity for read and write operations.
+     *
+     * @param name the name of the new location identity
+     * @param immutable true if the location is immutable
+     */
+    private static NamedLocationIdentity create(String name, boolean immutable) {
+        return new NamedLocationIdentity(name, immutable);
+    }
+
+    @Override
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    @Override
+    public String toString() {
+        return name + (isImmutable() ? ":final" : "");
+    }
+
+    /**
+     * Returns the named location identity for an array of the given element kind. Array accesses of
+     * the same kind must have the same location identity unless an alias analysis guarantees that
+     * two distinct arrays are accessed.
+     */
+    public static LocationIdentity getArrayLocation(JavaKind elementKind) {
+        return ARRAY_LOCATIONS.get(elementKind);
+    }
+
+    private static final EnumMap<JavaKind, LocationIdentity> ARRAY_LOCATIONS = initArrayLocations();
+
+    private static EnumMap<JavaKind, LocationIdentity> initArrayLocations() {
+        EnumMap<JavaKind, LocationIdentity> result = new EnumMap<>(JavaKind.class);
+        for (JavaKind kind : JavaKind.values()) {
+            result.put(kind, NamedLocationIdentity.mutable("Array: " + kind.getJavaName()));
+        }
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ParameterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ParameterNode.java
new file mode 100644
index 0000000..247e6d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ParameterNode.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
+
+/**
+ * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call.
+ */
+@NodeInfo(nameTemplate = "P({p#index})")
+public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider {
+
+    public static final NodeClass<ParameterNode> TYPE = NodeClass.create(ParameterNode.class);
+
+    private Stamp uncheckedStamp;
+
+    public ParameterNode(int index, StampPair stamp) {
+        super(TYPE, index, stamp.getTrustedStamp());
+        this.uncheckedStamp = stamp.getUncheckedStamp();
+    }
+
+    @Override
+    public Stamp uncheckedStamp() {
+        return uncheckedStamp;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PauseNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PauseNode.java
new file mode 100644
index 0000000..0c47efb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PauseNode.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/** A node that results in a platform dependent pause instruction being emitted. */
+@NodeInfo(cycles = NodeCycles.CYCLES_500, size = NodeSize.SIZE_1)
+public final class PauseNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<PauseNode> TYPE = NodeClass.create(PauseNode.class);
+
+    public PauseNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().emitPause();
+    }
+
+    @NodeIntrinsic
+    public static native void pause();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PhiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PhiNode.java
new file mode 100644
index 0000000..d278dc4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PhiNode.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+/**
+ * {@code PhiNode}s represent the merging of edges at a control flow merges (
+ * {@link AbstractMergeNode} or {@link LoopBeginNode}). For a {@link AbstractMergeNode}, the order
+ * of the values corresponds to the order of the ends. For {@link LoopBeginNode}s, the first value
+ * corresponds to the loop's predecessor, while the rest of the values correspond to the
+ * {@link LoopEndNode}s.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_1)
+public abstract class PhiNode extends FloatingNode implements Canonicalizable {
+
+    public static final NodeClass<PhiNode> TYPE = NodeClass.create(PhiNode.class);
+    @Input(Association) protected AbstractMergeNode merge;
+
+    protected PhiNode(NodeClass<? extends PhiNode> c, Stamp stamp, AbstractMergeNode merge) {
+        super(c, stamp);
+        this.merge = merge;
+    }
+
+    public abstract NodeInputList<ValueNode> values();
+
+    public AbstractMergeNode merge() {
+        return merge;
+    }
+
+    public void setMerge(AbstractMergeNode x) {
+        updateUsages(merge, x);
+        merge = x;
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(merge() != null, "missing merge");
+        assertTrue(merge().phiPredecessorCount() == valueCount(), "mismatch between merge predecessor count and phi value count: %d != %d", merge().phiPredecessorCount(), valueCount());
+        return super.verify();
+    }
+
+    /**
+     * Get the instruction that produces the value associated with the i'th predecessor of the
+     * merge.
+     *
+     * @param i the index of the predecessor
+     * @return the instruction that produced the value in the i'th predecessor
+     */
+    public ValueNode valueAt(int i) {
+        return values().get(i);
+    }
+
+    /**
+     * Sets the value at the given index and makes sure that the values list is large enough.
+     *
+     * @param i the index at which to set the value
+     * @param x the new phi input value for the given location
+     */
+    public void initializeValueAt(int i, ValueNode x) {
+        while (values().size() <= i) {
+            values().add(null);
+        }
+        values().set(i, x);
+    }
+
+    public void setValueAt(int i, ValueNode x) {
+        values().set(i, x);
+    }
+
+    public void setValueAt(AbstractEndNode end, ValueNode x) {
+        setValueAt(merge().phiPredecessorIndex(end), x);
+    }
+
+    public ValueNode valueAt(AbstractEndNode pred) {
+        return valueAt(merge().phiPredecessorIndex(pred));
+    }
+
+    /**
+     * Get the number of inputs to this phi (i.e. the number of predecessors to the merge).
+     *
+     * @return the number of inputs in this phi
+     */
+    public int valueCount() {
+        return values().size();
+    }
+
+    public void clearValues() {
+        values().clear();
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            StringBuilder str = new StringBuilder();
+            for (int i = 0; i < valueCount(); ++i) {
+                if (i != 0) {
+                    str.append(' ');
+                }
+                str.append(valueAt(i) == null ? "-" : valueAt(i).toString(Verbosity.Id));
+            }
+            return super.toString(Verbosity.Name) + "(" + str + ")";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    public void addInput(ValueNode x) {
+        assert !(x instanceof ValuePhiNode) || ((ValuePhiNode) x).merge() instanceof LoopBeginNode || ((ValuePhiNode) x).merge() != this.merge();
+        assert !(this instanceof ValuePhiNode) || x.stamp().isCompatible(stamp());
+        values().add(x);
+    }
+
+    public void removeInput(int index) {
+        values().remove(index);
+    }
+
+    public NodeIterable<ValueNode> backValues() {
+        return values().subList(merge().forwardEndCount());
+    }
+
+    @NodeInfo
+    static final class MultipleValuesNode extends ValueNode {
+
+        public static final NodeClass<MultipleValuesNode> TYPE = NodeClass.create(MultipleValuesNode.class);
+
+        protected MultipleValuesNode() {
+            super(TYPE, null);
+        }
+
+    }
+
+    public static final ValueNode MULTIPLE_VALUES = new MultipleValuesNode();
+
+    /**
+     * If all inputs are the same value, this value is returned, otherwise {@link #MULTIPLE_VALUES}.
+     * Note that {@code null} is a valid return value, since {@link GuardPhiNode}s can have
+     * {@code null} inputs.
+     */
+    public ValueNode singleValue() {
+        ValueNode singleValue = valueAt(0);
+        int count = valueCount();
+        for (int i = 1; i < count; ++i) {
+            ValueNode value = valueAt(i);
+            if (value != this) {
+                if (value != singleValue) {
+                    return MULTIPLE_VALUES;
+                }
+            }
+        }
+        return singleValue;
+    }
+
+    /**
+     * If all inputs (but the first one) are the same value, this value is returned, otherwise
+     * {@link #MULTIPLE_VALUES}. Note that {@code null} is a valid return value, since
+     * {@link GuardPhiNode}s can have {@code null} inputs.
+     */
+    public ValueNode singleBackValue() {
+        assert merge() instanceof LoopBeginNode;
+        Iterator<ValueNode> iterator = values().iterator();
+        iterator.next();
+        ValueNode singleValue = iterator.next();
+        while (iterator.hasNext()) {
+            if (iterator.next() != singleValue) {
+                return MULTIPLE_VALUES;
+            }
+        }
+        return singleValue;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+
+        if (isLoopPhi()) {
+            if (singleBackValue() == this) {
+                return firstValue();
+            }
+
+            boolean onlySelfUsage = true;
+            for (Node n : this.usages()) {
+                if (n != this) {
+                    onlySelfUsage = false;
+                    break;
+                }
+            }
+
+            if (onlySelfUsage) {
+                return null;
+            }
+        }
+
+        ValueNode singleValue = singleValue();
+        if (singleValue != MULTIPLE_VALUES) {
+            return singleValue;
+        }
+        return this;
+    }
+
+    public ValueNode firstValue() {
+        return valueAt(0);
+    }
+
+    public boolean isLoopPhi() {
+        return merge() instanceof LoopBeginNode;
+    }
+
+    public boolean hasValidInput() {
+        for (ValueNode n : values()) {
+            if (n != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java
new file mode 100644
index 0000000..aff6b98
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+/**
+ * A {@link PiNode} that also provides an array length in addition to a more refined stamp. A usage
+ * that reads the array length, such as an {@link ArrayLengthNode}, can be canonicalized based on
+ * this information.
+ */
+@NodeInfo
+public final class PiArrayNode extends PiNode implements ArrayLengthProvider {
+
+    public static final NodeClass<PiArrayNode> TYPE = NodeClass.create(PiArrayNode.class);
+    @Input ValueNode length;
+
+    @Override
+    public ValueNode length() {
+        return length;
+    }
+
+    public PiArrayNode(ValueNode object, ValueNode length, Stamp stamp) {
+        super(TYPE, object, stamp, null);
+        this.length = length;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (GraphUtil.arrayLength(object()) != length()) {
+            return this;
+        }
+        return super.canonical(tool);
+    }
+
+    @NodeIntrinsic
+    public static native Object piArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java
new file mode 100644
index 0000000..7554dd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+//JaCoCo Exclude
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A node that changes the type of its input, usually narrowing it. For example, a {@link PiNode}
+ * refines the type of a receiver during type-guarded inlining to be the type tested by the guard.
+ *
+ * In contrast to a {@link GuardedValueNode}, a {@link PiNode} is useless as soon as the type of its
+ * input is as narrow or narrower than the {@link PiNode}'s type. The {@link PiNode}, and therefore
+ * also the scheduling restriction enforced by the anchor, will go away.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
+
+    public static final NodeClass<PiNode> TYPE = NodeClass.create(PiNode.class);
+    @Input ValueNode object;
+    protected final Stamp piStamp;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    protected PiNode(NodeClass<? extends PiNode> c, ValueNode object, Stamp stamp, GuardingNode guard) {
+        super(c, stamp, guard);
+        this.object = object;
+        this.piStamp = stamp;
+        inferStamp();
+    }
+
+    public PiNode(ValueNode object, Stamp stamp) {
+        this(object, stamp, null);
+    }
+
+    public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
+        this(TYPE, object, stamp, (GuardingNode) anchor);
+    }
+
+    public PiNode(ValueNode object, ValueNode anchor) {
+        this(object, object.stamp().join(StampFactory.objectNonNull()), anchor);
+    }
+
+    public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
+        this(object, StampFactory.object(exactType ? TypeReference.createExactTrusted(toType) : TypeReference.createWithoutAssumptions(toType), nonNull || StampTool.isPointerNonNull(object.stamp())));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        if (object.getStackKind() != JavaKind.Void && object.getStackKind() != JavaKind.Illegal) {
+            generator.setResult(this, generator.operand(object));
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(computeStamp());
+    }
+
+    private Stamp computeStamp() {
+        // When piStamp == StampFactory.forNodeIntrinsic() then stamp is either
+        // StampFactory.forNodeIntrinsic() or it has been updated during snippet
+        // lowering to be the stamp of the node being replaced by the snippet.
+        if (piStamp == StampFactory.forNodeIntrinsic()) {
+            return stamp;
+        }
+        return piStamp.improveWith(object().stamp());
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) {
+                tool.replaceWithVirtual(virtual);
+            }
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (stamp() == StampFactory.forNodeIntrinsic()) {
+            /* The actual stamp has not been set yet. */
+            return this;
+        }
+        // Use most up to date stamp.
+        Stamp computedStamp = computeStamp();
+
+        ValueNode o = object();
+
+        // The pi node does not give any additional information => skip it.
+        if (computedStamp.equals(o.stamp())) {
+            return o;
+        }
+
+        GuardingNode g = getGuard();
+        if (g == null) {
+
+            // Try to merge the pi node with a load node.
+            if (o instanceof LoadFieldNode) {
+                LoadFieldNode loadFieldNode = (LoadFieldNode) o;
+                loadFieldNode.setStamp(loadFieldNode.stamp().improveWith(this.piStamp));
+                return loadFieldNode;
+            } else if (o instanceof UnsafeLoadNode) {
+                UnsafeLoadNode unsafeLoadNode = (UnsafeLoadNode) o;
+                unsafeLoadNode.setStamp(unsafeLoadNode.stamp().improveWith(this.piStamp));
+                return unsafeLoadNode;
+            }
+        } else {
+            for (Node n : g.asNode().usages()) {
+                if (n instanceof PiNode) {
+                    PiNode otherPi = (PiNode) n;
+                    if (o == otherPi.object() && computedStamp.equals(otherPi.stamp())) {
+                        /*
+                         * Two PiNodes with the same guard and same result, so return the one with
+                         * the more precise piStamp.
+                         */
+                        Stamp newStamp = piStamp.join(otherPi.piStamp);
+                        if (newStamp.equals(otherPi.piStamp)) {
+                            return otherPi;
+                        }
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ValueNode getOriginalNode() {
+        return object;
+    }
+
+    /**
+     * Casts an object to have an exact, non-null stamp representing {@link Class}.
+     */
+    public static Class<?> asNonNullClass(Object object) {
+        return asNonNullClassIntrinsic(object, Class.class, true, true);
+    }
+
+    /**
+     * Casts an object to have an exact, non-null stamp representing {@link Class}.
+     */
+    public static Class<?> asNonNullObject(Object object) {
+        return asNonNullClassIntrinsic(object, Object.class, false, true);
+    }
+
+    @NodeIntrinsic(PiNode.class)
+    private static native Class<?> asNonNullClassIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
+
+    /**
+     * Changes the stamp of an object.
+     */
+    @NodeIntrinsic
+    public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp);
+
+    /**
+     * Changes the stamp of an object and ensures the newly stamped value does not float above a
+     * given anchor.
+     */
+    @NodeIntrinsic
+    public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
+
+    /**
+     * Changes the stamp of an object and ensures the newly stamped value is non-null and does not
+     * float above a given anchor.
+     */
+    @NodeIntrinsic
+    public static native Object piCastNonNull(Object object, GuardingNode anchor);
+
+    /**
+     * Changes the stamp of an object to represent a given type and to indicate that the object is
+     * not null.
+     */
+    public static Object piCastNonNull(Object object, @ConstantNodeParameter Class<?> toType) {
+        return piCast(object, toType, false, true);
+    }
+
+    @NodeIntrinsic
+    public static native Object piCast(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PrefetchAllocateNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PrefetchAllocateNode.java
new file mode 100644
index 0000000..62a2e42
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PrefetchAllocateNode.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
+public final class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<PrefetchAllocateNode> TYPE = NodeClass.create(PrefetchAllocateNode.class);
+    @Input(Association) AddressNode address;
+
+    public PrefetchAllocateNode(ValueNode address) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = (AddressNode) address;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().emitPrefetchAllocate(gen.operand(address));
+    }
+
+    @NodeIntrinsic
+    public static native void prefetch(Address address);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java
new file mode 100644
index 0000000..bcaaa38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+/**
+ * A proxy is inserted at loop exits for any value that is created inside the loop (i.e. was not
+ * live on entry to the loop) and is (potentially) used after the loop.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public abstract class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable {
+
+    public static final NodeClass<ProxyNode> TYPE = NodeClass.create(ProxyNode.class);
+    @Input(Association) LoopExitNode loopExit;
+
+    protected ProxyNode(NodeClass<? extends ProxyNode> c, Stamp stamp, LoopExitNode proxyPoint) {
+        super(c, stamp);
+        assert proxyPoint != null;
+        this.loopExit = proxyPoint;
+    }
+
+    public abstract ValueNode value();
+
+    public LoopExitNode proxyPoint() {
+        return loopExit;
+    }
+
+    @Override
+    public boolean verify() {
+        assert !(value() instanceof ProxyNode) || ((ProxyNode) value()).loopExit != loopExit;
+        return super.verify();
+    }
+
+    public static ValueProxyNode forValue(ValueNode value, LoopExitNode exit, StructuredGraph graph) {
+        return graph.unique(new ValueProxyNode(value, exit));
+    }
+
+    public static GuardProxyNode forGuard(GuardingNode value, LoopExitNode exit, StructuredGraph graph) {
+        return graph.unique(new GuardProxyNode(value, exit));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ReturnNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ReturnNode.java
new file mode 100644
index 0000000..d5f6281
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ReturnNode.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.MemoryMapNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class ReturnNode extends ControlSinkNode implements LIRLowerable, IterableNodeType {
+
+    public static final NodeClass<ReturnNode> TYPE = NodeClass.create(ReturnNode.class);
+    @OptionalInput ValueNode result;
+    @OptionalInput(Extension) MemoryMapNode memoryMap;
+
+    public ValueNode result() {
+        return result;
+    }
+
+    public ReturnNode(ValueNode result) {
+        this(result, null);
+    }
+
+    public ReturnNode(ValueNode result, MemoryMapNode memoryMap) {
+        super(TYPE, StampFactory.forVoid());
+        this.result = result;
+        this.memoryMap = memoryMap;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert verifyReturn(gen.getLIRGeneratorTool().target());
+        if (result == null) {
+            gen.getLIRGeneratorTool().emitReturn(JavaKind.Void, null);
+        } else {
+            gen.getLIRGeneratorTool().emitReturn(result.getStackKind(), gen.operand(result));
+        }
+    }
+
+    public void setMemoryMap(MemoryMapNode memoryMap) {
+        updateUsages(this.memoryMap, memoryMap);
+        this.memoryMap = memoryMap;
+    }
+
+    public MemoryMapNode getMemoryMap() {
+        return memoryMap;
+    }
+
+    private boolean verifyReturn(TargetDescription target) {
+        if (graph().method() != null) {
+            JavaKind actual = result == null ? JavaKind.Void : result.getStackKind();
+            JavaKind expected = graph().method().getSignature().getReturnKind().getStackKind();
+            if (actual == target.wordJavaKind && expected == JavaKind.Object) {
+                // OK, we're compiling a snippet that returns a Word
+                return true;
+            }
+            assert actual == expected : "return kind doesn't match: actual " + actual + ", expected: " + expected;
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SafepointNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SafepointNode.java
new file mode 100644
index 0000000..e71973c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SafepointNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Marks a position in the graph where a safepoint should be emitted.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "We don't know how long a safepoint would take if it is executed",
+          size = SIZE_6)
+// @formatter:on
+public final class SafepointNode extends DeoptimizingFixedWithNextNode implements Lowerable, LIRLowerable {
+
+    public static final NodeClass<SafepointNode> TYPE = NodeClass.create(SafepointNode.class);
+
+    public SafepointNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.visitSafepointNode(this);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java
new file mode 100644
index 0000000..1780ee9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Condition;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
+
+    public static final NodeClass<ShortCircuitOrNode> TYPE = NodeClass.create(ShortCircuitOrNode.class);
+    @Input(Condition) LogicNode x;
+    @Input(Condition) LogicNode y;
+    protected boolean xNegated;
+    protected boolean yNegated;
+    protected double shortCircuitProbability;
+
+    public ShortCircuitOrNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
+        super(TYPE);
+        this.x = x;
+        this.xNegated = xNegated;
+        this.y = y;
+        this.yNegated = yNegated;
+        this.shortCircuitProbability = shortCircuitProbability;
+    }
+
+    @Override
+    public LogicNode getX() {
+        return x;
+    }
+
+    @Override
+    public LogicNode getY() {
+        return y;
+    }
+
+    public boolean isXNegated() {
+        return xNegated;
+    }
+
+    public boolean isYNegated() {
+        return yNegated;
+    }
+
+    /**
+     * Gets the probability that the {@link #getY() y} part of this binary node is <b>not</b>
+     * evaluated. This is the probability that this operator will short-circuit its execution.
+     */
+    public double getShortCircuitProbability() {
+        return shortCircuitProbability;
+    }
+
+    protected ShortCircuitOrNode canonicalizeNegation(LogicNode forX, LogicNode forY) {
+        LogicNode xCond = forX;
+        boolean xNeg = xNegated;
+        while (xCond instanceof LogicNegationNode) {
+            xCond = ((LogicNegationNode) xCond).getValue();
+            xNeg = !xNeg;
+        }
+
+        LogicNode yCond = forY;
+        boolean yNeg = yNegated;
+        while (yCond instanceof LogicNegationNode) {
+            yCond = ((LogicNegationNode) yCond).getValue();
+            yNeg = !yNeg;
+        }
+
+        if (xCond != forX || yCond != forY) {
+            return new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, shortCircuitProbability);
+        } else {
+            return this;
+        }
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool, LogicNode forX, LogicNode forY) {
+        ShortCircuitOrNode ret = canonicalizeNegation(forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX == forY) {
+            // @formatter:off
+            //  a ||  a = a
+            //  a || !a = true
+            // !a ||  a = true
+            // !a || !a = !a
+            // @formatter:on
+            if (isXNegated()) {
+                if (isYNegated()) {
+                    // !a || !a = !a
+                    return LogicNegationNode.create(forX);
+                } else {
+                    // !a || a = true
+                    return LogicConstantNode.tautology();
+                }
+            } else {
+                if (isYNegated()) {
+                    // a || !a = true
+                    return LogicConstantNode.tautology();
+                } else {
+                    // a || a = a
+                    return forX;
+                }
+            }
+        }
+        if (forX instanceof LogicConstantNode) {
+            if (((LogicConstantNode) forX).getValue() ^ isXNegated()) {
+                return LogicConstantNode.tautology();
+            } else {
+                if (isYNegated()) {
+                    return new LogicNegationNode(forY);
+                } else {
+                    return forY;
+                }
+            }
+        }
+        if (forY instanceof LogicConstantNode) {
+            if (((LogicConstantNode) forY).getValue() ^ isYNegated()) {
+                return LogicConstantNode.tautology();
+            } else {
+                if (isXNegated()) {
+                    return new LogicNegationNode(forX);
+                } else {
+                    return forX;
+                }
+            }
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java
new file mode 100644
index 0000000..f26b300
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Graph decoder that simplifies nodes during decoding. The standard
+ * {@link Canonicalizable#canonical node canonicalization} interface is used to canonicalize nodes
+ * during decoding. Additionally, {@link IfNode branches} and {@link IntegerSwitchNode switches}
+ * with constant conditions are simplified.
+ */
+public class SimplifyingGraphDecoder extends GraphDecoder {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final ConstantReflectionProvider constantReflection;
+    protected final ConstantFieldProvider constantFieldProvider;
+    protected final StampProvider stampProvider;
+    protected final boolean canonicalizeReads;
+
+    protected class PECanonicalizerTool implements CanonicalizerTool {
+
+        private final Assumptions assumptions;
+
+        public PECanonicalizerTool(Assumptions assumptions) {
+            this.assumptions = assumptions;
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return metaAccess;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return constantReflection;
+        }
+
+        @Override
+        public ConstantFieldProvider getConstantFieldProvider() {
+            return constantFieldProvider;
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return canonicalizeReads;
+        }
+
+        @Override
+        public boolean allUsagesAvailable() {
+            return false;
+        }
+
+        @Override
+        public Assumptions getAssumptions() {
+            return assumptions;
+        }
+
+        @Override
+        public boolean supportSubwordCompare(int bits) {
+            // to be safe, just report false here
+            // there will be more opportunities for this optimization later
+            return false;
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class CanonicalizeToNullNode extends FloatingNode implements Canonicalizable, GuardingNode {
+        public static final NodeClass<CanonicalizeToNullNode> TYPE = NodeClass.create(CanonicalizeToNullNode.class);
+
+        protected CanonicalizeToNullNode(Stamp stamp) {
+            super(TYPE, stamp);
+        }
+
+        @Override
+        public Node canonical(CanonicalizerTool tool) {
+            return null;
+        }
+    }
+
+    public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
+                    boolean canonicalizeReads, Architecture architecture) {
+        super(architecture);
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.stampProvider = stampProvider;
+        this.canonicalizeReads = canonicalizeReads;
+    }
+
+    @Override
+    protected void cleanupGraph(MethodScope methodScope) {
+        GraphUtil.normalizeLoops(methodScope.graph);
+        super.cleanupGraph(methodScope);
+
+        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.forwardEndCount() == 1) {
+                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
+            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
+                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
+                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
+                    node.safeDelete();
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
+            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
+                GraphUtil.killCFG(node);
+            }
+        }
+    }
+
+    @Override
+    protected boolean allowLazyPhis() {
+        /*
+         * We do not need to exactly reproduce the encoded graph, so we want to avoid unnecessary
+         * phi functions.
+         */
+        return true;
+    }
+
+    @Override
+    protected void handleMergeNode(MergeNode merge) {
+        /*
+         * All inputs of non-loop phi nodes are known by now. We can infer the stamp for the phi, so
+         * that parsing continues with more precise type information.
+         */
+        for (ValuePhiNode phi : merge.valuePhis()) {
+            phi.inferStamp();
+        }
+    }
+
+    @Override
+    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+        if (node instanceof IfNode) {
+            IfNode ifNode = (IfNode) node;
+            if (ifNode.condition() instanceof LogicNegationNode) {
+                ifNode.eliminateNegation();
+            }
+            if (ifNode.condition() instanceof LogicConstantNode) {
+                boolean condition = ((LogicConstantNode) ifNode.condition()).getValue();
+                AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition);
+                AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition);
+
+                methodScope.graph.removeSplit(ifNode, survivingSuccessor);
+                assert deadSuccessor.next() == null : "must not be parsed yet";
+                deadSuccessor.safeDelete();
+            }
+
+        } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) {
+            IntegerSwitchNode switchNode = (IntegerSwitchNode) node;
+            int value = switchNode.value().asJavaConstant().asInt();
+            AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value);
+            List<Node> allSuccessors = switchNode.successors().snapshot();
+
+            methodScope.graph.removeSplit(switchNode, survivingSuccessor);
+            for (Node successor : allSuccessors) {
+                if (successor != survivingSuccessor) {
+                    assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet";
+                    successor.safeDelete();
+                }
+            }
+
+        } else if (node instanceof FixedGuardNode) {
+            FixedGuardNode guard = (FixedGuardNode) node;
+            if (guard.getCondition() instanceof LogicConstantNode) {
+                LogicConstantNode condition = (LogicConstantNode) guard.getCondition();
+                Node canonical;
+                if (condition.getValue() == guard.isNegated()) {
+                    DeoptimizeNode deopt = new DeoptimizeNode(guard.getAction(), guard.getReason(), guard.getSpeculation());
+                    if (guard.stateBefore() != null) {
+                        deopt.setStateBefore(guard.stateBefore());
+                    }
+                    canonical = deopt;
+                } else {
+                    /*
+                     * The guard is unnecessary, but we cannot remove the node completely yet
+                     * because there might be nodes that use it as a guard input. Therefore, we
+                     * replace it with a more lightweight node (which is floating and has no
+                     * inputs).
+                     */
+                    canonical = new CanonicalizeToNullNode(node.stamp);
+                }
+                handleCanonicalization(methodScope, loopScope, nodeOrderId, node, canonical);
+            }
+
+        } else if (node instanceof Canonicalizable) {
+            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool(methodScope.graph.getAssumptions()));
+            if (canonical != node) {
+                handleCanonicalization(methodScope, loopScope, nodeOrderId, node, canonical);
+            }
+        }
+    }
+
+    private void handleCanonicalization(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node, Node c) {
+        Node canonical = c;
+
+        if (canonical == null) {
+            /*
+             * This is a possible return value of canonicalization. However, we might need to add
+             * additional usages later on for which we need a node. Therefore, we just do nothing
+             * and leave the node in place.
+             */
+            return;
+        }
+
+        if (!canonical.isAlive()) {
+            assert !canonical.isDeleted();
+            canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
+            if (canonical instanceof FixedWithNextNode) {
+                methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
+            } else if (canonical instanceof ControlSinkNode) {
+                FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor();
+                predecessor.setNext((ControlSinkNode) canonical);
+                List<Node> successorSnapshot = node.successors().snapshot();
+                node.safeDelete();
+                for (Node successor : successorSnapshot) {
+                    successor.safeDelete();
+                }
+
+            } else {
+                assert !(canonical instanceof FixedNode);
+            }
+        }
+        if (!node.isDeleted()) {
+            GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+            node.replaceAtUsagesAndDelete(canonical);
+        }
+        assert lookupNode(loopScope, nodeOrderId) == node;
+        registerNode(loopScope, nodeOrderId, canonical, true, false);
+    }
+
+    @Override
+    protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
+        if (node instanceof ValueNode) {
+            ((ValueNode) node).inferStamp();
+        }
+        if (node instanceof Canonicalizable) {
+            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool(methodScope.graph.getAssumptions()));
+            if (canonical == null) {
+                /*
+                 * This is a possible return value of canonicalization. However, we might need to
+                 * add additional usages later on for which we need a node. Therefore, we just do
+                 * nothing and leave the node in place.
+                 */
+            } else if (canonical != node) {
+                if (!canonical.isAlive()) {
+                    assert !canonical.isDeleted();
+                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
+                }
+                assert node.hasNoUsages();
+                // methodScope.graph.replaceFloating((FloatingNode) node, canonical);
+                return canonical;
+            }
+        }
+        return node;
+    }
+
+    @Override
+    protected Node addFloatingNode(MethodScope methodScope, Node node) {
+        /*
+         * In contrast to the base class implementation, we do not need to exactly reproduce the
+         * encoded graph. Since we do canonicalization, we also want nodes to be unique.
+         */
+        return methodScope.graph.addOrUnique(node);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java
new file mode 100644
index 0000000..0024d51
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+/**
+ * The start node of a graph.
+ */
+@NodeInfo(allowedUsageTypes = {Memory}, nameTemplate = "Start", cycles = CYCLES_0, size = SIZE_0)
+public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint.Single {
+    public static final NodeClass<StartNode> TYPE = NodeClass.create(StartNode.class);
+
+    protected StartNode(NodeClass<? extends StartNode> c) {
+        super(c);
+    }
+
+    public StartNode() {
+        super(TYPE);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StateSplit.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StateSplit.java
new file mode 100644
index 0000000..47f8807
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StateSplit.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+
+/**
+ * A state split is a node that may have a frame state associated with it.
+ */
+public interface StateSplit extends NodeWithState {
+
+    /**
+     * Gets the {@link FrameState} corresponding to the state of the JVM after execution of this
+     * node.
+     */
+    FrameState stateAfter();
+
+    /**
+     * Sets the {@link FrameState} corresponding to the state of the JVM after execution of this
+     * node.
+     */
+    void setStateAfter(FrameState x);
+
+    /**
+     * Determines if this node has a side-effect. Such nodes cannot be safely re-executed because
+     * they modify state which is visible to other threads or modify state beyond what is captured
+     * in {@link FrameState} nodes.
+     */
+    boolean hasSideEffect();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
new file mode 100644
index 0000000..af89e27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.JavaMethodContext;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.SpeculationLog;
+import jdk.vm.ci.meta.TriState;
+import jdk.vm.ci.runtime.JVMCICompiler;
+
+/**
+ * A graph that contains at least one distinguished node : the {@link #start() start} node. This
+ * node is the start of the control flow of the graph.
+ */
+public class StructuredGraph extends Graph implements JavaMethodContext {
+
+    /**
+     * The different stages of the compilation of a {@link Graph} regarding the status of
+     * {@link GuardNode guards}, {@link DeoptimizingNode deoptimizations} and {@link FrameState
+     * framestates}. The stage of a graph progresses monotonously.
+     *
+     */
+    public enum GuardsStage {
+        /**
+         * During this stage, there can be {@link FloatingNode floating} {@link DeoptimizingNode}
+         * such as {@link GuardNode GuardNodes}. New {@link DeoptimizingNode DeoptimizingNodes} can
+         * be introduced without constraints. {@link FrameState} nodes are associated with
+         * {@link StateSplit} nodes.
+         */
+        FLOATING_GUARDS,
+        /**
+         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
+         * {@link FixedNode fixed} but new {@link DeoptimizingNode DeoptimizingNodes} can still be
+         * introduced. {@link FrameState} nodes are still associated with {@link StateSplit} nodes.
+         */
+        FIXED_DEOPTS,
+        /**
+         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
+         * {@link FixedNode fixed}. New {@link DeoptimizingNode DeoptimizingNodes} can not be
+         * introduced any more. {@link FrameState} nodes are now associated with
+         * {@link DeoptimizingNode} nodes.
+         */
+        AFTER_FSA;
+
+        public boolean allowsFloatingGuards() {
+            return this == FLOATING_GUARDS;
+        }
+
+        public boolean areFrameStatesAtDeopts() {
+            return this == AFTER_FSA;
+        }
+
+        public boolean areFrameStatesAtSideEffects() {
+            return !this.areFrameStatesAtDeopts();
+        }
+
+        public boolean areDeoptsFixed() {
+            return this.ordinal() >= FIXED_DEOPTS.ordinal();
+        }
+    }
+
+    /**
+     * Constants denoting whether or not {@link Assumption}s can be made while processing a graph.
+     */
+    public enum AllowAssumptions {
+        YES,
+        NO;
+        public static AllowAssumptions from(boolean flag) {
+            return flag ? YES : NO;
+        }
+    }
+
+    public static class ScheduleResult {
+        private final ControlFlowGraph cfg;
+        private final NodeMap<Block> nodeToBlockMap;
+        private final BlockMap<List<Node>> blockToNodesMap;
+
+        public ScheduleResult(ControlFlowGraph cfg, NodeMap<Block> nodeToBlockMap, BlockMap<List<Node>> blockToNodesMap) {
+            this.cfg = cfg;
+            this.nodeToBlockMap = nodeToBlockMap;
+            this.blockToNodesMap = blockToNodesMap;
+        }
+
+        public ControlFlowGraph getCFG() {
+            return cfg;
+        }
+
+        public NodeMap<Block> getNodeToBlockMap() {
+            return nodeToBlockMap;
+        }
+
+        public BlockMap<List<Node>> getBlockToNodesMap() {
+            return blockToNodesMap;
+        }
+
+        public List<Node> nodesFor(Block block) {
+            return blockToNodesMap.get(block);
+        }
+    }
+
+    public static final long INVALID_GRAPH_ID = -1;
+    private static final AtomicLong uniqueGraphIds = new AtomicLong();
+
+    private StartNode start;
+    private ResolvedJavaMethod rootMethod;
+    private final long graphId;
+    private final CompilationIdentifier compilationId;
+    private final int entryBCI;
+    private GuardsStage guardsStage = GuardsStage.FLOATING_GUARDS;
+    private boolean isAfterFloatingReadPhase = false;
+    private boolean hasValueProxies = true;
+    private final boolean useProfilingInfo;
+
+    /**
+     * The assumptions made while constructing and transforming this graph.
+     */
+    private final Assumptions assumptions;
+
+    private final SpeculationLog speculationLog;
+
+    private ScheduleResult lastSchedule;
+
+    /**
+     * Records the methods that were used while constructing this graph, one entry for each time a
+     * specific method is used.
+     */
+    private final List<ResolvedJavaMethod> methods = new ArrayList<>();
+
+    /**
+     * Records the fields that were accessed while constructing this graph.
+     */
+
+    private final Set<ResolvedJavaField> fields = new HashSet<>();
+
+    private enum UnsafeAccessState {
+        NO_ACCESS,
+        HAS_ACCESS,
+        DISABLED
+    }
+
+    private UnsafeAccessState hasUnsafeAccess = UnsafeAccessState.NO_ACCESS;
+
+    /**
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
+     * start} node.
+     */
+    public StructuredGraph(AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        this(null, null, allowAssumptions, compilationId);
+    }
+
+    public static final boolean USE_PROFILING_INFO = true;
+
+    public static final boolean NO_PROFILING_INFO = false;
+
+    private static final SpeculationLog NO_SPECULATION_LOG = null;
+
+    /**
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
+     * start} node.
+     */
+    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        this(name, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, NO_SPECULATION_LOG, USE_PROFILING_INFO, compilationId);
+    }
+
+    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, CompilationIdentifier compilationId) {
+        this(name, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, speculationLog, USE_PROFILING_INFO, compilationId);
+    }
+
+    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, boolean useProfilingInfo, CompilationIdentifier compilationId) {
+        this(name, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, speculationLog, useProfilingInfo, compilationId);
+    }
+
+    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        this(null, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, NO_SPECULATION_LOG, USE_PROFILING_INFO, compilationId);
+    }
+
+    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, boolean useProfilingInfo, CompilationIdentifier compilationId) {
+        this(null, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, NO_SPECULATION_LOG, useProfilingInfo, compilationId);
+    }
+
+    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, CompilationIdentifier compilationId) {
+        this(null, method, JVMCICompiler.INVOCATION_ENTRY_BCI, allowAssumptions, speculationLog, USE_PROFILING_INFO, compilationId);
+    }
+
+    public StructuredGraph(ResolvedJavaMethod method, int entryBCI, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, CompilationIdentifier compilationId) {
+        this(null, method, entryBCI, allowAssumptions, speculationLog, USE_PROFILING_INFO, compilationId);
+    }
+
+    public StructuredGraph(ResolvedJavaMethod method, int entryBCI, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, boolean useProfilingInfo, CompilationIdentifier compilationId) {
+        this(null, method, entryBCI, allowAssumptions, speculationLog, useProfilingInfo, compilationId);
+    }
+
+    private StructuredGraph(String name, ResolvedJavaMethod method, int entryBCI, AllowAssumptions allowAssumptions, SpeculationLog speculationLog, boolean useProfilingInfo,
+                    CompilationIdentifier compilationId) {
+        super(name);
+        this.setStart(add(new StartNode()));
+        this.rootMethod = method;
+        this.graphId = uniqueGraphIds.incrementAndGet();
+        this.compilationId = compilationId;
+        this.entryBCI = entryBCI;
+        this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null;
+        this.speculationLog = speculationLog;
+        this.useProfilingInfo = useProfilingInfo;
+    }
+
+    public void setLastSchedule(ScheduleResult result) {
+        lastSchedule = result;
+    }
+
+    public ScheduleResult getLastSchedule() {
+        return lastSchedule;
+    }
+
+    public void clearLastSchedule() {
+        setLastSchedule(null);
+    }
+
+    @Override
+    public boolean maybeCompress() {
+        if (super.maybeCompress()) {
+            /*
+             * The schedule contains a NodeMap which is unusable after compression.
+             */
+            clearLastSchedule();
+            return true;
+        }
+        return false;
+    }
+
+    public Stamp getReturnStamp() {
+        Stamp returnStamp = null;
+        for (ReturnNode returnNode : getNodes(ReturnNode.TYPE)) {
+            ValueNode result = returnNode.result();
+            if (result != null) {
+                if (returnStamp == null) {
+                    returnStamp = result.stamp();
+                } else {
+                    returnStamp = returnStamp.meet(result.stamp());
+                }
+            }
+        }
+        return returnStamp;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(getClass().getSimpleName() + ":" + graphId);
+        String sep = "{";
+        if (name != null) {
+            buf.append(sep);
+            buf.append(name);
+            sep = ", ";
+        }
+        if (method() != null) {
+            buf.append(sep);
+            buf.append(method());
+            sep = ", ";
+        }
+
+        if (!sep.equals("{")) {
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    public StartNode start() {
+        return start;
+    }
+
+    /**
+     * Gets the root method from which this graph was built.
+     *
+     * @return null if this method was not built from a method or the method is not available
+     */
+    public ResolvedJavaMethod method() {
+        return rootMethod;
+    }
+
+    public int getEntryBCI() {
+        return entryBCI;
+    }
+
+    public boolean isOSR() {
+        return entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
+    }
+
+    public long graphId() {
+        return graphId;
+    }
+
+    /**
+     * @see CompilationIdentifier
+     */
+    public CompilationIdentifier compilationId() {
+        return compilationId;
+    }
+
+    public void setStart(StartNode start) {
+        this.start = start;
+    }
+
+    /**
+     * Creates a copy of this graph.
+     *
+     * @param newName the name of the copy, used for debugging purposes (can be null)
+     * @param duplicationMapCallback consumer of the duplication map created during the copying
+     */
+    @Override
+    protected Graph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback) {
+        return copy(newName, duplicationMapCallback, compilationId);
+    }
+
+    private StructuredGraph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback, CompilationIdentifier newCompilationId) {
+        AllowAssumptions allowAssumptions = AllowAssumptions.from(assumptions != null);
+        StructuredGraph copy = new StructuredGraph(newName, method(), entryBCI, allowAssumptions, speculationLog, useProfilingInfo, newCompilationId);
+        if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
+            copy.assumptions.record(assumptions);
+        }
+        copy.hasUnsafeAccess = hasUnsafeAccess;
+        copy.setGuardsStage(getGuardsStage());
+        copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
+        copy.hasValueProxies = hasValueProxies;
+        Map<Node, Node> replacements = Node.newMap();
+        replacements.put(start, copy.start);
+        Map<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
+        if (duplicationMapCallback != null) {
+            duplicationMapCallback.accept(duplicates);
+        }
+        return copy;
+    }
+
+    public final StructuredGraph copyWithIdentifier(CompilationIdentifier newCompilationId) {
+        return copy(name, null, newCompilationId);
+    }
+
+    public ParameterNode getParameter(int index) {
+        for (ParameterNode param : getNodes(ParameterNode.TYPE)) {
+            if (param.index() == index) {
+                return param;
+            }
+        }
+        return null;
+    }
+
+    public Iterable<Invoke> getInvokes() {
+        final Iterator<MethodCallTargetNode> callTargets = getNodes(MethodCallTargetNode.TYPE).iterator();
+        return new Iterable<Invoke>() {
+
+            private Invoke next;
+
+            @Override
+            public Iterator<Invoke> iterator() {
+                return new Iterator<Invoke>() {
+
+                    @Override
+                    public boolean hasNext() {
+                        if (next == null) {
+                            while (callTargets.hasNext()) {
+                                Invoke i = callTargets.next().invoke();
+                                if (i != null) {
+                                    next = i;
+                                    return true;
+                                }
+                            }
+                            return false;
+                        } else {
+                            return true;
+                        }
+                    }
+
+                    @Override
+                    public Invoke next() {
+                        try {
+                            return next;
+                        } finally {
+                            next = null;
+                        }
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
+    public boolean hasLoops() {
+        return hasNode(LoopBeginNode.TYPE);
+    }
+
+    /**
+     * Unlinks a node from all its control flow neighbors and then removes it from its graph. The
+     * node must have no {@linkplain Node#usages() usages}.
+     *
+     * @param node the node to be unlinked and removed
+     */
+    public void removeFixed(FixedWithNextNode node) {
+        assert node != null;
+        if (node instanceof AbstractBeginNode) {
+            ((AbstractBeginNode) node).prepareDelete();
+        }
+        assert node.hasNoUsages() : node + " " + node.usages().count() + ", " + node.usages().first();
+        GraphUtil.unlinkFixedNode(node);
+        node.safeDelete();
+    }
+
+    public void replaceFixed(FixedWithNextNode node, Node replacement) {
+        if (replacement instanceof FixedWithNextNode) {
+            replaceFixedWithFixed(node, (FixedWithNextNode) replacement);
+        } else {
+            assert replacement != null : "cannot replace " + node + " with null";
+            assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement;
+            replaceFixedWithFloating(node, (FloatingNode) replacement);
+        }
+    }
+
+    public void replaceFixedWithFixed(FixedWithNextNode node, FixedWithNextNode replacement) {
+        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
+        FixedNode next = node.next();
+        node.setNext(null);
+        replacement.setNext(next);
+        node.replaceAndDelete(replacement);
+        if (node == start) {
+            setStart((StartNode) replacement);
+        }
+    }
+
+    public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) {
+        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
+        GraphUtil.unlinkFixedNode(node);
+        node.replaceAtUsagesAndDelete(replacement);
+    }
+
+    public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
+        assert node != null;
+        assert node.hasNoUsages();
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        node.replaceAtPredecessor(survivingSuccessor);
+        node.safeDelete();
+    }
+
+    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
+        removeSplitPropagate(node, survivingSuccessor, null);
+    }
+
+    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor, SimplifierTool tool) {
+        assert node != null;
+        assert node.hasNoUsages();
+        assert survivingSuccessor != null;
+        List<Node> snapshot = node.successors().snapshot();
+        node.clearSuccessors();
+        node.replaceAtPredecessor(survivingSuccessor);
+        node.safeDelete();
+        for (Node successor : snapshot) {
+            if (successor != null && successor.isAlive()) {
+                if (successor != survivingSuccessor) {
+                    GraphUtil.killCFG(successor, tool);
+                }
+            }
+        }
+    }
+
+    public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) {
+        if (replacement instanceof FixedWithNextNode) {
+            replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor);
+        } else {
+            assert replacement != null : "cannot replace " + node + " with null";
+            assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement;
+            replaceSplitWithFloating(node, (FloatingNode) replacement, survivingSuccessor);
+        }
+    }
+
+    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) {
+        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        replacement.setNext(survivingSuccessor);
+        node.replaceAndDelete(replacement);
+    }
+
+    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) {
+        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        node.replaceAtPredecessor(survivingSuccessor);
+        node.replaceAtUsagesAndDelete(replacement);
+    }
+
+    public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) {
+        assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " after " + node;
+        FixedNode next = node.next();
+        node.setNext(newNode);
+        if (next != null) {
+            assert newNode instanceof FixedWithNextNode;
+            FixedWithNextNode newFixedWithNext = (FixedWithNextNode) newNode;
+            assert newFixedWithNext.next() == null;
+            newFixedWithNext.setNext(next);
+        }
+    }
+
+    public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) {
+        assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node;
+        assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node;
+        assert newNode.next() == null : newNode;
+        assert !(node instanceof AbstractMergeNode);
+        FixedWithNextNode pred = (FixedWithNextNode) node.predecessor();
+        pred.setNext(newNode);
+        newNode.setNext(node);
+    }
+
+    public void reduceDegenerateLoopBegin(LoopBeginNode begin) {
+        assert begin.loopEnds().isEmpty() : "Loop begin still has backedges";
+        if (begin.forwardEndCount() == 1) { // bypass merge and remove
+            reduceTrivialMerge(begin);
+        } else { // convert to merge
+            AbstractMergeNode merge = this.add(new MergeNode());
+            this.replaceFixedWithFixed(begin, merge);
+        }
+    }
+
+    public void reduceTrivialMerge(AbstractMergeNode merge) {
+        assert merge.forwardEndCount() == 1;
+        assert !(merge instanceof LoopBeginNode) || ((LoopBeginNode) merge).loopEnds().isEmpty();
+        for (PhiNode phi : merge.phis().snapshot()) {
+            assert phi.valueCount() == 1;
+            ValueNode singleValue = phi.valueAt(0);
+            phi.replaceAtUsagesAndDelete(singleValue);
+        }
+        // remove loop exits
+        if (merge instanceof LoopBeginNode) {
+            ((LoopBeginNode) merge).removeExits();
+        }
+        AbstractEndNode singleEnd = merge.forwardEndAt(0);
+        FixedNode sux = merge.next();
+        FrameState stateAfter = merge.stateAfter();
+        // evacuateGuards
+        merge.prepareDelete((FixedNode) singleEnd.predecessor());
+        merge.safeDelete();
+        if (stateAfter != null && stateAfter.isAlive() && stateAfter.hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+        }
+        if (sux == null) {
+            singleEnd.replaceAtPredecessor(null);
+            singleEnd.safeDelete();
+        } else {
+            singleEnd.replaceAndDelete(sux);
+        }
+    }
+
+    public GuardsStage getGuardsStage() {
+        return guardsStage;
+    }
+
+    public void setGuardsStage(GuardsStage guardsStage) {
+        assert guardsStage.ordinal() >= this.guardsStage.ordinal();
+        this.guardsStage = guardsStage;
+    }
+
+    public boolean isAfterFloatingReadPhase() {
+        return isAfterFloatingReadPhase;
+    }
+
+    public void setAfterFloatingReadPhase(boolean state) {
+        assert state : "cannot 'unapply' floating read phase on graph";
+        isAfterFloatingReadPhase = state;
+    }
+
+    public boolean hasValueProxies() {
+        return hasValueProxies;
+    }
+
+    public void setHasValueProxies(boolean state) {
+        assert !state : "cannot 'unapply' value proxy removal on graph";
+        hasValueProxies = state;
+    }
+
+    /**
+     * Determines if {@link ProfilingInfo} is used during construction of this graph.
+     */
+    public boolean useProfilingInfo() {
+        return useProfilingInfo;
+    }
+
+    /**
+     * Gets the profiling info for the {@linkplain #method() root method} of this graph.
+     */
+    public ProfilingInfo getProfilingInfo() {
+        return getProfilingInfo(method());
+    }
+
+    /**
+     * Gets the profiling info for a given method that is or will be part of this graph, taking into
+     * account {@link #useProfilingInfo()}.
+     */
+    public ProfilingInfo getProfilingInfo(ResolvedJavaMethod m) {
+        if (useProfilingInfo && m != null) {
+            return m.getProfilingInfo();
+        } else {
+            return DefaultProfilingInfo.get(TriState.UNKNOWN);
+        }
+    }
+
+    /**
+     * Gets the object for recording assumptions while constructing of this graph.
+     *
+     * @return {@code null} if assumptions cannot be made for this graph
+     */
+    public Assumptions getAssumptions() {
+        return assumptions;
+    }
+
+    /**
+     * Gets the methods that were inlined while constructing this graph.
+     */
+    public List<ResolvedJavaMethod> getMethods() {
+        return methods;
+    }
+
+    /**
+     * Records that {@code method} was used to build this graph.
+     */
+    public void recordMethod(ResolvedJavaMethod method) {
+        methods.add(method);
+    }
+
+    /**
+     * Updates the {@linkplain #getMethods() methods} used to build this graph with the methods used
+     * to build another graph.
+     */
+    public void updateMethods(StructuredGraph other) {
+        assert this != other;
+        this.methods.addAll(other.methods);
+    }
+
+    /**
+     * Gets the fields that were accessed while constructing this graph.
+     */
+    public Set<ResolvedJavaField> getFields() {
+        return fields;
+    }
+
+    /**
+     * Records that {@code field} was accessed in this graph.
+     */
+    public void recordField(ResolvedJavaField field) {
+        fields.add(field);
+    }
+
+    /**
+     * Updates the {@linkplain #getFields() fields} of this graph with the accessed fields of
+     * another graph.
+     */
+    public void updateFields(StructuredGraph other) {
+        assert this != other;
+        this.fields.addAll(other.fields);
+    }
+
+    /**
+     * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this
+     * graph is constructed. This ignores how many bytecodes in each constituent method are actually
+     * parsed (which may be none for methods whose IR is retrieved from a cache or less than the
+     * full amount for any given method due to profile guided branch pruning).
+     */
+    public int getBytecodeSize() {
+        int res = 0;
+        for (ResolvedJavaMethod e : methods) {
+            res += e.getCodeSize();
+        }
+        return res;
+    }
+
+    /**
+     *
+     * @return true if the graph contains only a {@link StartNode} and {@link ReturnNode}
+     */
+    public boolean isTrivial() {
+        return !(start.next() instanceof ReturnNode);
+    }
+
+    @Override
+    public JavaMethod asJavaMethod() {
+        return method();
+    }
+
+    public boolean hasUnsafeAccess() {
+        return hasUnsafeAccess == UnsafeAccessState.HAS_ACCESS;
+    }
+
+    public void markUnsafeAccess() {
+        if (hasUnsafeAccess == UnsafeAccessState.DISABLED) {
+            return;
+        }
+        hasUnsafeAccess = UnsafeAccessState.HAS_ACCESS;
+    }
+
+    public void disableUnsafeAccessTracking() {
+        hasUnsafeAccess = UnsafeAccessState.DISABLED;
+    }
+
+    public boolean isUnsafeAccessTrackingEnabled() {
+        return hasUnsafeAccess != UnsafeAccessState.DISABLED;
+    }
+
+    public SpeculationLog getSpeculationLog() {
+        return speculationLog;
+    }
+
+    public final void clearAllStateAfter() {
+        for (Node node : getNodes()) {
+            if (node instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) node).stateAfter();
+                if (stateAfter != null) {
+                    ((StateSplit) node).setStateAfter(null);
+                    // 2 nodes referencing the same framestate
+                    if (stateAfter.isAlive()) {
+                        GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                    }
+                }
+            }
+        }
+    }
+
+    public final boolean hasVirtualizableAllocation() {
+        for (Node n : getNodes()) {
+            if (n instanceof VirtualizableAllocation) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/TypeCheckHints.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/TypeCheckHints.java
new file mode 100644
index 0000000..92cbbbc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/TypeCheckHints.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.type.TypeReference;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Utility for deriving hint types for a type check instruction (e.g. checkcast or instanceof) based
+ * on the target type of the check and any profiling information available for the instruction.
+ */
+public class TypeCheckHints {
+
+    /**
+     * A receiver type profiled in a type check instruction.
+     */
+    public static class Hint {
+
+        /**
+         * A type seen while profiling a type check instruction.
+         */
+        public final ResolvedJavaType type;
+
+        /**
+         * Specifies if {@link #type} is a sub-type of the checked type.
+         */
+        public final boolean positive;
+
+        Hint(ResolvedJavaType type, boolean positive) {
+            this.type = type;
+            this.positive = positive;
+        }
+    }
+
+    private static final Hint[] NO_HINTS = {};
+
+    /**
+     * If non-null, then this is the only type that could pass the type check because the target of
+     * the type check is a final class or has been speculated to be a final class and this value is
+     * the only concrete subclass of the target type.
+     */
+    public final ResolvedJavaType exact;
+
+    /**
+     * The most likely types that the type check instruction will see.
+     */
+    public final Hint[] hints;
+
+    /**
+     * The profile from which this information was derived.
+     */
+    public final JavaTypeProfile profile;
+
+    /**
+     * The total probability that the type check will hit one of the types in {@link #hints}.
+     */
+    public final double hintHitProbability;
+
+    /**
+     * Derives hint information for use when generating the code for a type check instruction.
+     *
+     * @param targetType the target type of the type check
+     * @param profile the profiling information available for the instruction (if any)
+     * @param assumptions the object in which speculations are recorded. This is null if
+     *            speculations are not supported.
+     * @param minHintHitProbability if the probability that the type check will hit one of the
+     *            profiled types (up to {@code maxHints}) is below this value, then {@link #hints}
+     *            will be null
+     * @param maxHints the maximum length of {@link #hints}
+     */
+    public TypeCheckHints(TypeReference targetType, JavaTypeProfile profile, Assumptions assumptions, double minHintHitProbability, int maxHints) {
+        this.profile = profile;
+        if (targetType != null && targetType.isExact()) {
+            exact = targetType.getType();
+        } else {
+            exact = null;
+        }
+        Double[] hitProbability = {null};
+        this.hints = makeHints(targetType, profile, minHintHitProbability, maxHints, hitProbability);
+        this.hintHitProbability = hitProbability[0];
+    }
+
+    private static Hint[] makeHints(TypeReference targetType, JavaTypeProfile profile, double minHintHitProbability, int maxHints, Double[] hitProbability) {
+        double hitProb = 0.0d;
+        Hint[] hintsBuf = NO_HINTS;
+        if (profile != null) {
+            double notRecordedTypes = profile.getNotRecordedProbability();
+            ProfiledType[] ptypes = profile.getTypes();
+            if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) {
+                hintsBuf = new Hint[ptypes.length];
+                int hintCount = 0;
+                for (ProfiledType ptype : ptypes) {
+                    if (targetType != null) {
+                        ResolvedJavaType hintType = ptype.getType();
+                        hintsBuf[hintCount++] = new Hint(hintType, targetType.getType().isAssignableFrom(hintType));
+                        hitProb += ptype.getProbability();
+                    }
+                    if (hintCount == maxHints) {
+                        break;
+                    }
+                }
+                if (hitProb >= minHintHitProbability) {
+                    if (hintsBuf.length != hintCount || hintCount > maxHints) {
+                        hintsBuf = Arrays.copyOf(hintsBuf, Math.min(maxHints, hintCount));
+                    }
+                } else {
+                    hintsBuf = NO_HINTS;
+                    hitProb = 0.0d;
+                }
+            }
+        }
+        hitProbability[0] = hitProb;
+        return hintsBuf;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnaryOpLogicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnaryOpLogicNode.java
new file mode 100644
index 0000000..ebf48d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnaryOpLogicNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Unary<ValueNode> {
+
+    public static final NodeClass<UnaryOpLogicNode> TYPE = NodeClass.create(UnaryOpLogicNode.class);
+    @Input protected ValueNode value;
+
+    @Override
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public UnaryOpLogicNode(NodeClass<? extends UnaryOpLogicNode> c, ValueNode value) {
+        super(c);
+        assert value != null;
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+
+    public abstract Stamp getSucceedingStampForValue(boolean negated);
+
+    public abstract TriState tryFold(Stamp valueStamp);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnwindNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnwindNode.java
new file mode 100644
index 0000000..7b8c614
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnwindNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Unwinds the current frame to an exception handler in the caller frame.
+ */
+@NodeInfo(cycles = CYCLES_8, size = SIZE_4)
+public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
+
+    public static final NodeClass<UnwindNode> TYPE = NodeClass.create(UnwindNode.class);
+    @Input ValueNode exception;
+
+    public ValueNode exception() {
+        return exception;
+    }
+
+    public UnwindNode(ValueNode exception) {
+        super(TYPE, StampFactory.forVoid());
+        assert exception.getStackKind() == JavaKind.Object;
+        this.exception = exception;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().emitUnwind(gen.operand(exception()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java
new file mode 100644
index 0000000..ad87cd6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodePredicate;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * This class represents a value within the graph, including local variables, phis, and all other
+ * instructions.
+ */
+@NodeInfo
+public abstract class ValueNode extends org.graalvm.compiler.graph.Node implements ValueNodeInterface {
+
+    public static final NodeClass<ValueNode> TYPE = NodeClass.create(ValueNode.class);
+    /**
+     * The kind of this value. This is {@link JavaKind#Void} for instructions that produce no value.
+     * This kind is guaranteed to be a {@linkplain JavaKind#getStackKind() stack kind}.
+     */
+    protected Stamp stamp;
+
+    public ValueNode(NodeClass<? extends ValueNode> c, Stamp stamp) {
+        super(c);
+        this.stamp = stamp;
+    }
+
+    public final Stamp stamp() {
+        return stamp;
+    }
+
+    public final void setStamp(Stamp stamp) {
+        this.stamp = stamp;
+        assert !isAlive() || !inferStamp() : "setStamp called on a node that overrides inferStamp: " + this;
+    }
+
+    @Override
+    public final StructuredGraph graph() {
+        return (StructuredGraph) super.graph();
+    }
+
+    /**
+     * Checks if the given stamp is different than the current one (
+     * {@code newStamp.equals(oldStamp) == false}). If it is different then the new stamp will
+     * become the current stamp for this node.
+     *
+     * @return true if the stamp has changed, false otherwise.
+     */
+    protected final boolean updateStamp(Stamp newStamp) {
+        if (newStamp == null || newStamp.equals(stamp)) {
+            return false;
+        } else {
+            stamp = newStamp;
+            return true;
+        }
+    }
+
+    /**
+     * This method can be overridden by subclasses of {@link ValueNode} if they need to recompute
+     * their stamp if their inputs change. A typical implementation will compute the stamp and pass
+     * it to {@link #updateStamp(Stamp)}, whose return value can be used as the result of this
+     * method.
+     *
+     * @return true if the stamp has changed, false otherwise.
+     */
+    public boolean inferStamp() {
+        return false;
+    }
+
+    public final JavaKind getStackKind() {
+        return stamp().getStackKind();
+    }
+
+    /**
+     * Checks whether this value is a constant (i.e. it is of type {@link ConstantNode}.
+     *
+     * @return {@code true} if this value is a constant
+     */
+    public final boolean isConstant() {
+        return this instanceof ConstantNode;
+    }
+
+    private static final NodePredicate IS_CONSTANT = new NodePredicate() {
+        @Override
+        public boolean apply(Node n) {
+            return n instanceof ConstantNode;
+        }
+    };
+
+    public static NodePredicate isConstantPredicate() {
+        return IS_CONSTANT;
+    }
+
+    /**
+     * Checks whether this value represents the null constant.
+     *
+     * @return {@code true} if this value represents the null constant
+     */
+    public final boolean isNullConstant() {
+        JavaConstant value = asJavaConstant();
+        return value != null && value.isNull();
+    }
+
+    /**
+     * Convert this value to a constant if it is a constant, otherwise return null.
+     *
+     * @return the {@link JavaConstant} represented by this value if it is a constant; {@code null}
+     *         otherwise
+     */
+    public final Constant asConstant() {
+        if (this instanceof ConstantNode) {
+            return ((ConstantNode) this).getValue();
+        } else {
+            return null;
+        }
+    }
+
+    public final JavaConstant asJavaConstant() {
+        Constant value = asConstant();
+        if (value instanceof JavaConstant) {
+            return (JavaConstant) value;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ValueNode asNode() {
+        return this;
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        if (getStackKind() != JavaKind.Void && type == InputType.Value) {
+            return true;
+        } else {
+            return super.isAllowedUsageType(type);
+        }
+    }
+
+    /**
+     * Checks if this node has usages other than the given node {@code node}.
+     *
+     * @param node node which is ignored when searching for usages
+     * @param nodeValueMap
+     * @return true if this node has other usages, false otherwise
+     */
+    public boolean hasUsagesOtherThan(ValueNode node, NodeValueMap nodeValueMap) {
+        for (Node usage : usages()) {
+            if (usage != node && usage instanceof ValueNode && nodeValueMap.hasOperand(usage)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java
new file mode 100644
index 0000000..45533d6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.NodeInterface;
+
+public interface ValueNodeInterface extends NodeInterface {
+    @Override
+    ValueNode asNode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeUtil.java
new file mode 100644
index 0000000..8776b2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeUtil.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import static java.lang.Character.toLowerCase;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class ValueNodeUtil {
+
+    public static ValueNode assertKind(JavaKind kind, ValueNode x) {
+        assert x != null && x.getStackKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getStackKind());
+        return x;
+    }
+
+    public static RuntimeException shouldNotReachHere(String msg) {
+        throw new InternalError("should not reach here: " + msg);
+    }
+
+    public static RuntimeException shouldNotReachHere() {
+        throw new InternalError("should not reach here");
+    }
+
+    public static ValueNode assertLong(ValueNode x) {
+        assert x != null && (x.getStackKind() == JavaKind.Long);
+        return x;
+    }
+
+    public static ValueNode assertInt(ValueNode x) {
+        assert x != null && (x.getStackKind() == JavaKind.Int);
+        return x;
+    }
+
+    public static ValueNode assertFloat(ValueNode x) {
+        assert x != null && (x.getStackKind() == JavaKind.Float);
+        return x;
+    }
+
+    public static ValueNode assertObject(ValueNode x) {
+        assert x != null && (x.getStackKind() == JavaKind.Object);
+        return x;
+    }
+
+    public static ValueNode assertDouble(ValueNode x) {
+        assert x != null && (x.getStackKind() == JavaKind.Double);
+        return x;
+    }
+
+    public static void assertHigh(ValueNode x) {
+        assert x == null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends Node> Collection<T> filter(Iterable<Node> nodes, Class<T> clazz) {
+        ArrayList<T> phis = new ArrayList<>();
+        for (Node node : nodes) {
+            if (clazz.isInstance(node)) {
+                phis.add((T) node);
+            }
+        }
+        return phis;
+    }
+
+    /**
+     * Converts a given instruction to a value string. The representation of an node as a value is
+     * formed by concatenating the {@linkplain jdk.vm.ci.meta.JavaKind#getTypeChar character}
+     * denoting its {@linkplain ValueNode#getStackKind kind} and its id. For example, {@code "i13"}.
+     *
+     * @param value the instruction to convert to a value string. If {@code value == null}, then "-"
+     *            is returned.
+     * @return the instruction representation as a string
+     */
+    public static String valueString(ValueNode value) {
+        return (value == null) ? "-" : ("" + toLowerCase(value.getStackKind().getTypeChar()) + value.toString(Verbosity.Id));
+    }
+
+    public static ValueNode asNode(MemoryNode node) {
+        if (node == null) {
+            return null;
+        } else {
+            return node.asNode();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java
new file mode 100644
index 0000000..769afd0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+/**
+ * Value {@link PhiNode}s merge data flow values at control flow merges.
+ */
+@NodeInfo(nameTemplate = "Phi({i#values})")
+public class ValuePhiNode extends PhiNode implements ArrayLengthProvider {
+
+    public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
+    @Input protected NodeInputList<ValueNode> values;
+
+    public ValuePhiNode(Stamp stamp, AbstractMergeNode merge) {
+        this(TYPE, stamp, merge);
+    }
+
+    protected ValuePhiNode(NodeClass<? extends ValuePhiNode> c, Stamp stamp, AbstractMergeNode merge) {
+        super(c, stamp, merge);
+        assert stamp != StampFactory.forVoid();
+        values = new NodeInputList<>(this);
+    }
+
+    public ValuePhiNode(Stamp stamp, AbstractMergeNode merge, ValueNode[] values) {
+        super(TYPE, stamp, merge);
+        assert stamp != StampFactory.forVoid();
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    @Override
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        /*
+         * Meet all the values feeding this Phi but don't use the stamp of this Phi since that's
+         * what's being computed.
+         */
+        Stamp valuesStamp = StampTool.meetOrNull(values(), this);
+        if (valuesStamp == null) {
+            valuesStamp = stamp;
+        } else if (stamp.isCompatible(valuesStamp)) {
+            valuesStamp = stamp.join(valuesStamp);
+        }
+        return updateStamp(valuesStamp);
+    }
+
+    @Override
+    public ValueNode length() {
+        if (merge() instanceof LoopBeginNode) {
+            return null;
+        }
+        ValueNode length = null;
+        for (ValueNode input : values()) {
+            ValueNode l = GraphUtil.arrayLength(input);
+            if (l == null) {
+                return null;
+            }
+            if (length == null) {
+                length = l;
+            } else if (length != l) {
+                return null;
+            }
+        }
+        return length;
+    }
+
+    @Override
+    public boolean verify() {
+        Stamp s = null;
+        for (ValueNode input : values()) {
+            if (s == null) {
+                s = input.stamp();
+            } else {
+                if (!s.isCompatible(input.stamp())) {
+                    fail("Phi Input Stamps are not compatible. Phi:%s inputs:%s", this, values().stream().map(x -> x.toString() + ":" + x.stamp()).collect(Collectors.joining(", ")));
+                }
+            }
+        }
+        return super.verify();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java
new file mode 100644
index 0000000..2c3af8a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+@NodeInfo(nameTemplate = "Proxy({i#value})")
+public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
+
+    public static final NodeClass<ValueProxyNode> TYPE = NodeClass.create(ValueProxyNode.class);
+    @Input ValueNode value;
+    private final boolean loopPhiProxy;
+
+    public ValueProxyNode(ValueNode value, LoopExitNode loopExit) {
+        super(TYPE, value.stamp(), loopExit);
+        this.value = value;
+        loopPhiProxy = loopExit.loopBegin().isPhiAtMerge(value);
+    }
+
+    @Override
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(value.stamp());
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode curValue = value;
+        if (curValue.isConstant()) {
+            return curValue;
+        }
+        if (loopPhiProxy && !loopExit.loopBegin().isPhiAtMerge(curValue)) {
+            return curValue;
+        }
+        return this;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(value);
+        if (alias instanceof VirtualObjectNode) {
+            tool.replaceWithVirtual((VirtualObjectNode) alias);
+        }
+    }
+
+    @Override
+    public ValueNode getOriginalNode() {
+        return value();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/VirtualState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/VirtualState.java
new file mode 100644
index 0000000..659103d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/VirtualState.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+
+/**
+ * Base class for nodes that contain "virtual" state, like FrameState and VirtualObjectState.
+ * Subclasses of this class will be treated in a special way by the scheduler.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.State})
+public abstract class VirtualState extends Node {
+
+    protected VirtualState(NodeClass<? extends VirtualState> c) {
+        super(c);
+    }
+
+    public static final NodeClass<VirtualState> TYPE = NodeClass.create(VirtualState.class);
+
+    public abstract static class NodeClosure<T extends Node> {
+
+        public abstract void apply(Node usage, T node);
+    }
+
+    public interface VirtualClosure {
+
+        void apply(VirtualState node);
+    }
+
+    public abstract VirtualState duplicateWithVirtualState();
+
+    public abstract void applyToNonVirtual(NodeClosure<? super ValueNode> closure);
+
+    /**
+     * Performs a <b>pre-order</b> iteration over all elements reachable from this state that are a
+     * subclass of {@link VirtualState}.
+     */
+    public abstract void applyToVirtual(VirtualClosure closure);
+
+    public abstract boolean isPartOfThisState(VirtualState state);
+
+    @Override
+    public final StructuredGraph graph() {
+        return (StructuredGraph) super.graph();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AbsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AbsNode.java
new file mode 100644
index 0000000..3d51d23
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AbsNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Absolute value.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class AbsNode extends UnaryArithmeticNode<Abs> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+    public static final NodeClass<AbsNode> TYPE = NodeClass.create(AbsNode.class);
+
+    public AbsNode(ValueNode x) {
+        super(TYPE, ArithmeticOpTable::getAbs, x);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+        if (forValue instanceof AbsNode) {
+            return forValue;
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitMathAbs(nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java
new file mode 100644
index 0000000..64cf28d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(shortName = "+")
+public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    public static final NodeClass<AddNode> TYPE = NodeClass.create(AddNode.class);
+
+    public AddNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected AddNode(NodeClass<? extends AddNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getAdd, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Add> op = ArithmeticOpTable.forStamp(x.stamp()).getAdd();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new AddNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            // we try to swap and canonicalize
+            ValueNode improvement = canonical(tool, forY, forX);
+            if (improvement != this) {
+                return improvement;
+            }
+            // if this fails we only swap
+            return new AddNode(forY, forX);
+        }
+        BinaryOp<Add> op = getOp(forX, forY);
+        boolean associative = op.isAssociative();
+        if (associative) {
+            if (forX instanceof SubNode) {
+                SubNode sub = (SubNode) forX;
+                if (sub.getY() == forY) {
+                    // (a - b) + b
+                    return sub.getX();
+                }
+            }
+            if (forY instanceof SubNode) {
+                SubNode sub = (SubNode) forY;
+                if (sub.getY() == forX) {
+                    // b + (a - b)
+                    return sub.getX();
+                }
+            }
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (op.isNeutral(c)) {
+                return forX;
+            }
+            if (associative) {
+                // canonicalize expressions like "(a + 1) + 2"
+                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+                if (reassociated != this) {
+                    return reassociated;
+                }
+            }
+        }
+        if (forX instanceof NegateNode) {
+            return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue());
+        } else if (forY instanceof NegateNode) {
+            return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value op1 = nodeValueMap.operand(getX());
+        assert op1 != null : getX() + ", this=" + this;
+        Value op2 = nodeValueMap.operand(getY());
+        if (shouldSwapInputs(nodeValueMap)) {
+            Value tmp = op1;
+            op1 = op2;
+            op2 = tmp;
+        }
+        nodeValueMap.setResult(this, gen.emitAdd(op1, op2, false));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java
new file mode 100644
index 0000000..69691db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(shortName = "&")
+public final class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    public static final NodeClass<AndNode> TYPE = NodeClass.create(AndNode.class);
+
+    public AndNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getAnd, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<And> op = ArithmeticOpTable.forStamp(x.stamp()).getAnd();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new AndNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return forX;
+        }
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new AndNode(forY, forX);
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp(forX, forY).isNeutral(c)) {
+                return forX;
+            }
+
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long rawY = ((PrimitiveConstant) c).asLong();
+                long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp()));
+                if ((rawY & mask) == 0) {
+                    return ConstantNode.forIntegerStamp(stamp(), 0);
+                }
+                if (forX instanceof SignExtendNode) {
+                    SignExtendNode ext = (SignExtendNode) forX;
+                    if (rawY == ((1L << ext.getInputBits()) - 1)) {
+                        return new ZeroExtendNode(ext.getValue(), ext.getResultBits());
+                    }
+                }
+                IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+                if (((xStamp.upMask() | xStamp.downMask()) & ~rawY) == 0) {
+                    // No bits are set which are outside the mask, so the mask will have no effect.
+                    return forX;
+                }
+            }
+
+            return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitAnd(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java
new file mode 100644
index 0000000..680af27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodePredicate;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ArithmeticOperation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.meta.Constant;
+
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public abstract class BinaryArithmeticNode<OP> extends BinaryNode implements ArithmeticOperation, ArithmeticLIRLowerable, Canonicalizable.Binary<ValueNode> {
+
+    @SuppressWarnings("rawtypes") public static final NodeClass<BinaryArithmeticNode> TYPE = NodeClass.create(BinaryArithmeticNode.class);
+
+    protected interface SerializableBinaryFunction<T> extends Function<ArithmeticOpTable, BinaryOp<T>>, Serializable {
+    }
+
+    protected final SerializableBinaryFunction<OP> getOp;
+
+    protected BinaryArithmeticNode(NodeClass<? extends BinaryArithmeticNode<OP>> c, SerializableBinaryFunction<OP> getOp, ValueNode x, ValueNode y) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), y.stamp()), x, y);
+        this.getOp = getOp;
+    }
+
+    protected final BinaryOp<OP> getOp(ValueNode forX, ValueNode forY) {
+        ArithmeticOpTable table = ArithmeticOpTable.forStamp(forX.stamp());
+        assert table.equals(ArithmeticOpTable.forStamp(forY.stamp()));
+        return getOp.apply(table);
+    }
+
+    @Override
+    public final BinaryOp<OP> getArithmeticOp() {
+        return getOp(getX(), getY());
+    }
+
+    public boolean isAssociative() {
+        return getArithmeticOp().isAssociative();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = tryConstantFold(getOp(forX, forY), forX, forY, stamp());
+        if (result != null) {
+            return result;
+        }
+        return this;
+    }
+
+    public static <OP> ConstantNode tryConstantFold(BinaryOp<OP> op, ValueNode forX, ValueNode forY, Stamp stamp) {
+        if (forX.isConstant() && forY.isConstant()) {
+            Constant ret = op.foldConstant(forX.asConstant(), forY.asConstant());
+            return ConstantNode.forPrimitive(stamp, ret);
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        assert stampX.isCompatible(x.stamp()) && stampY.isCompatible(y.stamp());
+        return getArithmeticOp().foldStamp(stampX, stampY);
+    }
+
+    public static AddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(new AddNode(v1, v2));
+    }
+
+    public static AddNode add(ValueNode v1, ValueNode v2) {
+        return new AddNode(v1, v2);
+    }
+
+    public static MulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(new MulNode(v1, v2));
+    }
+
+    public static MulNode mul(ValueNode v1, ValueNode v2) {
+        return new MulNode(v1, v2);
+    }
+
+    public static SubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(new SubNode(v1, v2));
+    }
+
+    public static SubNode sub(ValueNode v1, ValueNode v2) {
+        return new SubNode(v1, v2);
+    }
+
+    private enum ReassociateMatch {
+        x,
+        y;
+
+        public ValueNode getValue(BinaryNode binary) {
+            switch (this) {
+                case x:
+                    return binary.getX();
+                case y:
+                    return binary.getY();
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+
+        public ValueNode getOtherValue(BinaryNode binary) {
+            switch (this) {
+                case x:
+                    return binary.getY();
+                case y:
+                    return binary.getX();
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    private static ReassociateMatch findReassociate(BinaryNode binary, NodePredicate criterion) {
+        boolean resultX = criterion.apply(binary.getX());
+        boolean resultY = criterion.apply(binary.getY());
+        if (resultX && !resultY) {
+            return ReassociateMatch.x;
+        }
+        if (!resultX && resultY) {
+            return ReassociateMatch.y;
+        }
+        return null;
+    }
+
+    //@formatter:off
+    /*
+     * In reassociate, complexity comes from the handling of IntegerSub (non commutative) which can
+     * be mixed with IntegerAdd. It first tries to find m1, m2 which match the criterion :
+     * (a o m2) o m1
+     * (m2 o a) o m1
+     * m1 o (a o m2)
+     * m1 o (m2 o a)
+     * It then produces 4 boolean for the -/+ cases:
+     * invertA : should the final expression be like *-a (rather than a+*)
+     * aSub : should the final expression be like a-* (rather than a+*)
+     * invertM1 : should the final expression contain -m1
+     * invertM2 : should the final expression contain -m2
+     *
+     */
+    //@formatter:on
+    /**
+     * Tries to re-associate values which satisfy the criterion. For example with a constantness
+     * criterion: {@code (a + 2) + 1 => a + (1 + 2)}
+     * <p>
+     * This method accepts only {@linkplain BinaryOp#isAssociative() associative} operations such as
+     * +, -, *, &amp;, | and ^
+     *
+     * @param forY
+     * @param forX
+     */
+    public static BinaryArithmeticNode<?> reassociate(BinaryArithmeticNode<?> node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
+        assert node.getOp(forX, forY).isAssociative();
+        ReassociateMatch match1 = findReassociate(node, criterion);
+        if (match1 == null) {
+            return node;
+        }
+        ValueNode otherValue = match1.getOtherValue(node);
+        boolean addSub = false;
+        boolean subAdd = false;
+        if (otherValue.getClass() != node.getClass()) {
+            if (node instanceof AddNode && otherValue instanceof SubNode) {
+                addSub = true;
+            } else if (node instanceof SubNode && otherValue instanceof AddNode) {
+                subAdd = true;
+            } else {
+                return node;
+            }
+        }
+        BinaryNode other = (BinaryNode) otherValue;
+        ReassociateMatch match2 = findReassociate(other, criterion);
+        if (match2 == null) {
+            return node;
+        }
+        boolean invertA = false;
+        boolean aSub = false;
+        boolean invertM1 = false;
+        boolean invertM2 = false;
+        if (addSub) {
+            invertM2 = match2 == ReassociateMatch.y;
+            invertA = !invertM2;
+        } else if (subAdd) {
+            invertA = invertM2 = match1 == ReassociateMatch.x;
+            invertM1 = !invertM2;
+        } else if (node instanceof SubNode && other instanceof SubNode) {
+            invertA = match1 == ReassociateMatch.x ^ match2 == ReassociateMatch.x;
+            aSub = match1 == ReassociateMatch.y && match2 == ReassociateMatch.y;
+            invertM1 = match1 == ReassociateMatch.y && match2 == ReassociateMatch.x;
+            invertM2 = match1 == ReassociateMatch.x && match2 == ReassociateMatch.x;
+        }
+        assert !(invertM1 && invertM2) && !(invertA && aSub);
+        ValueNode m1 = match1.getValue(node);
+        ValueNode m2 = match2.getValue(other);
+        ValueNode a = match2.getOtherValue(other);
+        if (node instanceof AddNode || node instanceof SubNode) {
+            BinaryNode associated;
+            if (invertM1) {
+                associated = BinaryArithmeticNode.sub(m2, m1);
+            } else if (invertM2) {
+                associated = BinaryArithmeticNode.sub(m1, m2);
+            } else {
+                associated = BinaryArithmeticNode.add(m1, m2);
+            }
+            if (invertA) {
+                return BinaryArithmeticNode.sub(associated, a);
+            }
+            if (aSub) {
+                return BinaryArithmeticNode.sub(a, associated);
+            }
+            return BinaryArithmeticNode.add(a, associated);
+        } else if (node instanceof MulNode) {
+            return BinaryArithmeticNode.mul(a, AddNode.mul(m1, m2));
+        } else if (node instanceof AndNode) {
+            return new AndNode(a, new AndNode(m1, m2));
+        } else if (node instanceof OrNode) {
+            return new OrNode(a, new OrNode(m1, m2));
+        } else if (node instanceof XorNode) {
+            return new XorNode(a, new XorNode(m1, m2));
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order the
+     * inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on the node
+     * if it's currently in a graph. It's assumed that if there was a constant on the left it's been
+     * moved to the right by other code and that ordering is left alone.
+     *
+     * @return the original node or another node with the same input ordering
+     */
+    @SuppressWarnings("deprecation")
+    public BinaryNode maybeCommuteInputs() {
+        assert this instanceof BinaryCommutative;
+        if (!y.isConstant() && x.getId() > y.getId()) {
+            ValueNode tmp = x;
+            x = y;
+            y = tmp;
+            if (graph() != null) {
+                // See if this node already exists
+                BinaryNode duplicate = graph().findDuplicate(this);
+                if (duplicate != null) {
+                    return duplicate;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Determines if it would be better to swap the inputs in order to produce better assembly code.
+     * First we try to pick a value which is dead after this use. If both values are dead at this
+     * use then we try pick an induction variable phi to encourage the phi to live in a single
+     * register.
+     *
+     * @param nodeValueMap
+     * @return true if inputs should be swapped, false otherwise
+     */
+    protected boolean shouldSwapInputs(NodeValueMap nodeValueMap) {
+        final boolean xHasOtherUsages = getX().hasUsagesOtherThan(this, nodeValueMap);
+        final boolean yHasOtherUsages = getY().hasUsagesOtherThan(this, nodeValueMap);
+
+        if (!getY().isConstant() && !yHasOtherUsages) {
+            if (xHasOtherUsages == yHasOtherUsages) {
+                return getY() instanceof ValuePhiNode && getY().inputs().contains(this);
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryNode.java
new file mode 100644
index 0000000..3e45aa7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryNode.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * The {@code BinaryNode} class is the base of arithmetic and logic operations with two inputs.
+ */
+@NodeInfo
+public abstract class BinaryNode extends FloatingNode implements Canonicalizable.Binary<ValueNode> {
+
+    public static final NodeClass<BinaryNode> TYPE = NodeClass.create(BinaryNode.class);
+    @Input protected ValueNode x;
+    @Input protected ValueNode y;
+
+    @Override
+    public ValueNode getX() {
+        return x;
+    }
+
+    @Override
+    public ValueNode getY() {
+        return y;
+    }
+
+    public void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    public void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
+    /**
+     * Creates a new BinaryNode instance.
+     *
+     * @param stamp the result type of this instruction
+     * @param x the first input instruction
+     * @param y the second input instruction
+     */
+    protected BinaryNode(NodeClass<? extends BinaryNode> c, Stamp stamp, ValueNode x, ValueNode y) {
+        super(c, stamp);
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(foldStamp(getX().stamp(), getY().stamp()));
+    }
+
+    /**
+     * Compute an improved for this node using the passed in stamps. The stamps must be compatible
+     * with the current values of {@link #x} and {@link #y}. This code is used to provide the
+     * default implementation of {@link #inferStamp()} and may be used by external optimizations.
+     *
+     * @param stampX
+     * @param stampY
+     */
+    public abstract Stamp foldStamp(Stamp stampX, Stamp stampY);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java
new file mode 100644
index 0000000..f6b627c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+
+/* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node)
+ * But in the back-end the comparison should not always be materialized (for example in x86 the comparison result will not be in a register but in a flag)
+ *
+ * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
+ * into variants that do not materialize the value (CompareIf, CompareGuard...)
+ */
+@NodeInfo(cycles = CYCLES_1)
+public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode> {
+
+    public static final NodeClass<CompareNode> TYPE = NodeClass.create(CompareNode.class);
+    protected final Condition condition;
+    protected final boolean unorderedIsTrue;
+
+    /**
+     * Constructs a new Compare instruction.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    protected CompareNode(NodeClass<? extends CompareNode> c, Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
+        super(c, x, y);
+        this.condition = condition;
+        this.unorderedIsTrue = unorderedIsTrue;
+    }
+
+    /**
+     * Gets the condition (comparison operation) for this instruction.
+     *
+     * @return the condition
+     */
+    public final Condition condition() {
+        return condition;
+    }
+
+    /**
+     * Checks whether unordered inputs mean true or false (only applies to float operations).
+     *
+     * @return {@code true} if unordered inputs produce true
+     */
+    public final boolean unorderedIsTrue() {
+        return this.unorderedIsTrue;
+    }
+
+    private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
+        Constant trueConstant = conditionalNode.trueValue().asConstant();
+        Constant falseConstant = conditionalNode.falseValue().asConstant();
+
+        if (falseConstant != null && trueConstant != null && constantReflection != null) {
+            boolean trueResult = cond.foldCondition(trueConstant, constant, constantReflection, unorderedIsTrue());
+            boolean falseResult = cond.foldCondition(falseConstant, constant, constantReflection, unorderedIsTrue());
+
+            if (trueResult == falseResult) {
+                return LogicConstantNode.forBoolean(trueResult);
+            } else {
+                if (trueResult) {
+                    assert falseResult == false;
+                    return conditionalNode.condition();
+                } else {
+                    assert falseResult == true;
+                    return LogicNegationNode.create(conditionalNode.condition());
+
+                }
+            }
+        }
+        return this;
+    }
+
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        throw new GraalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+        LogicNode constantCondition = tryConstantFold(condition(), forX, forY, constantReflection, unorderedIsTrue());
+        if (constantCondition != null) {
+            return constantCondition;
+        }
+        ValueNode result;
+        if (forX.isConstant()) {
+            if ((result = canonicalizeSymmetricConstant(tool, forX.asConstant(), forY, true)) != this) {
+                return result;
+            }
+        } else if (forY.isConstant()) {
+            if ((result = canonicalizeSymmetricConstant(tool, forY.asConstant(), forX, false)) != this) {
+                return result;
+            }
+        } else if (forX instanceof ConvertNode && forY instanceof ConvertNode) {
+            ConvertNode convertX = (ConvertNode) forX;
+            ConvertNode convertY = (ConvertNode) forY;
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
+                boolean supported = true;
+                if (convertX.getValue().stamp() instanceof IntegerStamp) {
+                    IntegerStamp intStamp = (IntegerStamp) convertX.getValue().stamp();
+                    supported = tool.supportSubwordCompare(intStamp.getBits());
+                }
+
+                if (supported) {
+                    boolean multiUsage = (convertX.asNode().getUsageCount() > 1 || convertY.asNode().getUsageCount() > 1);
+                    if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) {
+                        // Do not perform for zero or sign extend if there are multiple usages of
+                        // the value.
+                        return this;
+                    }
+                    return duplicateModified(convertX.getValue(), convertY.getValue());
+                }
+            }
+        }
+        return this;
+    }
+
+    public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+        if (forX.isConstant() && forY.isConstant() && constantReflection != null) {
+            return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue));
+        }
+        return null;
+    }
+
+    /**
+     * Does this operation represent an identity check such that for x == y, x is exactly the same
+     * thing as y. This is generally true except for some floating point comparisons.
+     *
+     * @return true for identity comparisons
+     */
+    public boolean isIdentityComparison() {
+        return condition == Condition.EQ;
+    }
+
+    protected abstract LogicNode duplicateModified(ValueNode newX, ValueNode newY);
+
+    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (nonConstant instanceof ConditionalNode) {
+            return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
+        } else if (nonConstant instanceof NormalizeCompareNode) {
+            return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
+        } else if (nonConstant instanceof ConvertNode) {
+            ConvertNode convert = (ConvertNode) nonConstant;
+            boolean multiUsage = (convert.asNode().getUsageCount() > 1 && convert.getValue().getUsageCount() == 1);
+            if ((convert instanceof ZeroExtendNode || convert instanceof SignExtendNode) && multiUsage) {
+                // Do not perform for zero or sign extend if it could introduce
+                // new live values.
+                return this;
+            }
+
+            boolean supported = true;
+            if (convert.getValue().stamp() instanceof IntegerStamp) {
+                IntegerStamp intStamp = (IntegerStamp) convert.getValue().stamp();
+                supported = tool.supportSubwordCompare(intStamp.getBits());
+            }
+
+            if (supported) {
+                ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
+                if (newConstant != null) {
+                    if (mirrored) {
+                        return duplicateModified(newConstant, convert.getValue());
+                    } else {
+                        return duplicateModified(convert.getValue(), newConstant);
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    private ConstantNode canonicalConvertConstant(CanonicalizerTool tool, ConvertNode convert, Constant constant) {
+        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+        if (convert.preservesOrder(condition(), constant, constantReflection)) {
+            Constant reverseConverted = convert.reverse(constant, constantReflection);
+            if (reverseConverted != null && convert.convert(reverseConverted, constantReflection).equals(constant)) {
+                if (GeneratePIC.getValue()) {
+                    // We always want uncompressed constants
+                    return null;
+                }
+                return ConstantNode.forConstant(convert.getValue().stamp(), reverseConverted, tool.getMetaAccess());
+            }
+        }
+        return null;
+    }
+
+    public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = createCompareNode(condition, x, y, constantReflection);
+        return (result.graph() == null ? graph.unique(result) : result);
+    }
+
+    public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        assert x.getStackKind() == y.getStackKind();
+        assert condition.isCanonical() : "condition is not canonical: " + condition;
+        assert !x.getStackKind().isNumericFloat();
+
+        LogicNode comparison;
+        if (condition == Condition.EQ) {
+            if (x.stamp() instanceof AbstractObjectStamp) {
+                comparison = ObjectEqualsNode.create(x, y, constantReflection);
+            } else if (x.stamp() instanceof AbstractPointerStamp) {
+                comparison = PointerEqualsNode.create(x, y);
+            } else {
+                assert x.getStackKind().isNumericInteger();
+                comparison = IntegerEqualsNode.create(x, y, constantReflection);
+            }
+        } else if (condition == Condition.LT) {
+            assert x.getStackKind().isNumericInteger();
+            comparison = IntegerLessThanNode.create(x, y, constantReflection);
+        } else {
+            assert condition == Condition.BT;
+            assert x.getStackKind().isNumericInteger();
+            comparison = IntegerBelowNode.create(x, y, constantReflection);
+        }
+
+        return comparison;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java
new file mode 100644
index 0000000..acbecf4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
+ * that these nodes are not built directly from the bytecode but are introduced by canonicalization.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_2)
+public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
+
+    public static final NodeClass<ConditionalNode> TYPE = NodeClass.create(ConditionalNode.class);
+    @Input(InputType.Condition) LogicNode condition;
+    @Input ValueNode trueValue;
+    @Input ValueNode falseValue;
+
+    public LogicNode condition() {
+        return condition;
+    }
+
+    public ConditionalNode(LogicNode condition) {
+        this(condition, ConstantNode.forInt(1, condition.graph()), ConstantNode.forInt(0, condition.graph()));
+    }
+
+    public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
+        super(TYPE, trueValue.stamp().meet(falseValue.stamp()));
+        assert trueValue.stamp().isCompatible(falseValue.stamp());
+        this.condition = condition;
+        this.trueValue = trueValue;
+        this.falseValue = falseValue;
+    }
+
+    public static ValueNode create(LogicNode condition) {
+        return create(condition, ConstantNode.forInt(1, condition.graph()), ConstantNode.forInt(0, condition.graph()));
+    }
+
+    public static ValueNode create(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
+        ValueNode synonym = findSynonym(condition, trueValue, falseValue);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new ConditionalNode(condition, trueValue, falseValue);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        Stamp valueStamp = trueValue.stamp().meet(falseValue.stamp());
+        if (condition instanceof IntegerLessThanNode) {
+            IntegerLessThanNode lessThan = (IntegerLessThanNode) condition;
+            if (lessThan.getX() == trueValue && lessThan.getY() == falseValue) {
+                // this encodes a min operation
+                JavaConstant constant = lessThan.getX().asJavaConstant();
+                if (constant == null) {
+                    constant = lessThan.getY().asJavaConstant();
+                }
+                if (constant != null) {
+                    IntegerStamp bounds = StampFactory.forInteger(constant.getJavaKind(), constant.getJavaKind().getMinValue(), constant.asLong());
+                    valueStamp = valueStamp.join(bounds);
+                }
+            } else if (lessThan.getX() == falseValue && lessThan.getY() == trueValue) {
+                // this encodes a max operation
+                JavaConstant constant = lessThan.getX().asJavaConstant();
+                if (constant == null) {
+                    constant = lessThan.getY().asJavaConstant();
+                }
+                if (constant != null) {
+                    IntegerStamp bounds = StampFactory.forInteger(constant.getJavaKind(), constant.asLong(), constant.getJavaKind().getMaxValue());
+                    valueStamp = valueStamp.join(bounds);
+                }
+            }
+
+        }
+        return updateStamp(valueStamp);
+    }
+
+    public ValueNode trueValue() {
+        return trueValue;
+    }
+
+    public ValueNode falseValue() {
+        return falseValue;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        ValueNode synonym = findSynonym(condition, trueValue(), falseValue());
+        if (synonym != null) {
+            return synonym;
+        }
+
+        ValueNode result = canonicalizeConditional(condition, trueValue(), falseValue(), stamp);
+        if (result != null) {
+            return result;
+        }
+
+        return this;
+    }
+
+    public static ValueNode canonicalizeConditional(LogicNode condition, ValueNode trueValue, ValueNode falseValue, Stamp stamp) {
+        // this optimizes the case where a value that can only be 0 or 1 is materialized to 0 or 1
+        if (trueValue.isConstant() && falseValue.isConstant() && condition instanceof IntegerEqualsNode) {
+            IntegerEqualsNode equals = (IntegerEqualsNode) condition;
+            if (equals.getY().isConstant() && equals.getY().asConstant().equals(JavaConstant.INT_0) && equals.getX().stamp() instanceof IntegerStamp) {
+                IntegerStamp equalsXStamp = (IntegerStamp) equals.getX().stamp();
+                if (equalsXStamp.upMask() == 1) {
+                    if (trueValue.asConstant().equals(JavaConstant.INT_0) && falseValue.asConstant().equals(JavaConstant.INT_1)) {
+                        return IntegerConvertNode.convertUnsigned(equals.getX(), stamp);
+                    }
+                }
+            }
+        }
+        if (condition instanceof CompareNode && ((CompareNode) condition).isIdentityComparison()) {
+            // optimize the pattern (x == y) ? x : y
+            CompareNode compare = (CompareNode) condition;
+            if ((compare.getX() == trueValue && compare.getY() == falseValue) || (compare.getX() == falseValue && compare.getY() == trueValue)) {
+                return falseValue;
+            }
+        }
+        if (trueValue == falseValue) {
+            return trueValue;
+        }
+
+        if (condition instanceof IntegerLessThanNode && trueValue.stamp() instanceof IntegerStamp) {
+            /*
+             * Convert a conditional add ((x < 0) ? (x + y) : x) into (x + (y & (x >> (bits - 1))))
+             * to avoid the test.
+             */
+            IntegerLessThanNode lt = (IntegerLessThanNode) condition;
+            if (lt.getY().isConstant() && lt.getY().asConstant().isDefaultForKind()) {
+                if (falseValue == lt.getX()) {
+                    if (trueValue instanceof AddNode) {
+                        AddNode add = (AddNode) trueValue;
+                        if (add.getX() == falseValue) {
+                            int bits = ((IntegerStamp) trueValue.stamp()).getBits();
+                            ValueNode shift = new RightShiftNode(lt.getX(), ConstantNode.forIntegerBits(32, bits - 1));
+                            ValueNode and = new AndNode(shift, add.getY());
+                            return new AddNode(add.getX(), and);
+                        }
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private static ValueNode findSynonym(ValueNode condition, ValueNode trueValue, ValueNode falseValue) {
+        if (condition instanceof LogicNegationNode) {
+            LogicNegationNode negated = (LogicNegationNode) condition;
+            return ConditionalNode.create(negated.getValue(), falseValue, trueValue);
+        }
+        if (condition instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) condition;
+            if (c.getValue()) {
+                return trueValue;
+            } else {
+                return falseValue;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.emitConditional(this);
+    }
+
+    public ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+        this(createCompareNode(graph, condition, x, y, null));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java
new file mode 100644
index 0000000..18007e2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+
+/**
+ * Represents a conversion between primitive types.
+ */
+public interface ConvertNode extends ValueNodeInterface {
+
+    ValueNode getValue();
+
+    Constant convert(Constant c, ConstantReflectionProvider constantReflection);
+
+    Constant reverse(Constant c, ConstantReflectionProvider constantReflection);
+
+    /**
+     * Check whether a conversion is lossless.
+     *
+     * @return true iff reverse(convert(c)) == c for all c
+     */
+    boolean isLossless();
+
+    /**
+     * Check whether a conversion preserves comparison order.
+     *
+     * @param op a comparison operator
+     * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
+     */
+    default boolean preservesOrder(Condition op) {
+        return isLossless();
+    }
+
+    /**
+     * Check whether a conversion preserves comparison order against a particular constant value.
+     *
+     * @param op a comparison operator
+     * @param value
+     * @param constantReflection
+     * @return true iff (c1 op value) == (convert(c1) op convert(value)) for value and all c1
+     */
+    default boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) {
+        return preservesOrder(op);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java
new file mode 100644
index 0000000..9d42bbd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(shortName = "/", cycles = NodeCycles.CYCLES_30)
+public class DivNode extends BinaryArithmeticNode<Div> {
+
+    public static final NodeClass<DivNode> TYPE = NodeClass.create(DivNode.class);
+
+    public DivNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getDiv, x, y);
+    }
+
+    protected DivNode(NodeClass<? extends DivNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getDiv, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Div> op = ArithmeticOpTable.forStamp(x.stamp()).getDiv();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new DivNode(x, y);
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp(forX, forY).isNeutral(c)) {
+                return forX;
+            }
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long i = ((PrimitiveConstant) c).asLong();
+                boolean signFlip = false;
+                if (i < 0) {
+                    i = -i;
+                    signFlip = true;
+                }
+                ValueNode divResult = null;
+                if (CodeUtil.isPowerOf2(i)) {
+                    divResult = new RightShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
+                }
+                if (divResult != null) {
+                    if (signFlip) {
+                        return new NegateNode(divResult);
+                    } else {
+                        return divResult;
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitDiv(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FixedBinaryNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FixedBinaryNode.java
new file mode 100644
index 0000000..9bb6144
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FixedBinaryNode.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+@NodeInfo
+public abstract class FixedBinaryNode extends DeoptimizingFixedWithNextNode implements Canonicalizable.Binary<ValueNode> {
+    public static final NodeClass<FixedBinaryNode> TYPE = NodeClass.create(FixedBinaryNode.class);
+
+    @Input protected ValueNode x;
+    @Input protected ValueNode y;
+
+    public FixedBinaryNode(NodeClass<? extends FixedBinaryNode> c, Stamp stamp, ValueNode x, ValueNode y) {
+        super(c, stamp);
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public ValueNode getX() {
+        return x;
+    }
+
+    @Override
+    public ValueNode getY() {
+        return y;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatConvertNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatConvertNode.java
new file mode 100644
index 0000000..8723445
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatConvertNode.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_5;
+
+import java.util.EnumMap;
+
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+
+/**
+ * A {@code FloatConvert} converts between integers and floating point numbers according to Java
+ * semantics.
+ */
+@NodeInfo(cycles = CYCLES_5)
+public final class FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ConvertNode, Lowerable, ArithmeticLIRLowerable {
+    public static final NodeClass<FloatConvertNode> TYPE = NodeClass.create(FloatConvertNode.class);
+
+    protected final FloatConvert op;
+
+    private static final EnumMap<FloatConvert, SerializableUnaryFunction<FloatConvertOp>> getOps;
+    static {
+        getOps = new EnumMap<>(FloatConvert.class);
+        for (FloatConvert op : FloatConvert.values()) {
+            getOps.put(op, table -> table.getFloatConvert(op));
+        }
+    }
+
+    public FloatConvertNode(FloatConvert op, ValueNode input) {
+        super(TYPE, getOps.get(op), input);
+        this.op = op;
+    }
+
+    public static ValueNode create(FloatConvert op, ValueNode input) {
+        ValueNode synonym = findSynonym(input, ArithmeticOpTable.forStamp(input.stamp()).getFloatConvert(op));
+        if (synonym != null) {
+            return synonym;
+        }
+        return new FloatConvertNode(op, input);
+    }
+
+    public FloatConvert getFloatConvert() {
+        return op;
+    }
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        return getArithmeticOp().foldConstant(c);
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        FloatConvertOp reverse = ArithmeticOpTable.forStamp(stamp()).getFloatConvert(op.reverse());
+        return reverse.foldConstant(c);
+    }
+
+    @Override
+    public boolean isLossless() {
+        switch (getFloatConvert()) {
+            case F2D:
+            case I2D:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forValue instanceof FloatConvertNode) {
+            FloatConvertNode other = (FloatConvertNode) forValue;
+            if (other.isLossless() && other.op == this.op.reverse()) {
+                return other.getValue();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitFloatConvert(getFloatConvert(), nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java
new file mode 100644
index 0000000..3299be9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "==", cycles = NodeCycles.CYCLES_3)
+public final class FloatEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
+    public static final NodeClass<FloatEqualsNode> TYPE = NodeClass.create(FloatEqualsNode.class);
+
+    public FloatEqualsNode(ValueNode x, ValueNode y) {
+        super(TYPE, Condition.EQ, false, x, y);
+        assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp : x.stamp() + " " + y.stamp();
+        assert x.stamp().isCompatible(y.stamp());
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            return new FloatEqualsNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public boolean isIdentityComparison() {
+        FloatStamp xStamp = (FloatStamp) x.stamp();
+        FloatStamp yStamp = (FloatStamp) y.stamp();
+        /*
+         * If both stamps have at most one 0.0 and it's the same 0.0 then this is an identity
+         * comparison. FloatStamp isn't careful about tracking the presence of -0.0 so assume that
+         * anything that includes 0.0 might include -0.0. So if either one is non-zero then it's an
+         * identity comparison.
+         */
+        return (!xStamp.contains(0.0) || !yStamp.contains(0.0));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
+        Stamp xStampGeneric = forX.stamp();
+        Stamp yStampGeneric = forY.stamp();
+        if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) {
+            FloatStamp xStamp = (FloatStamp) xStampGeneric;
+            FloatStamp yStamp = (FloatStamp) yStampGeneric;
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+                return LogicConstantNode.tautology();
+            } else if (xStamp.alwaysDistinct(yStamp)) {
+                return LogicConstantNode.contradiction();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerEqualsNode(newX, newY);
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        if (!negated) {
+            return getX().stamp().join(getY().stamp());
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        if (!negated) {
+            return getX().stamp().join(getY().stamp());
+        }
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) {
+            FloatStamp xStamp = (FloatStamp) xStampGeneric;
+            FloatStamp yStamp = (FloatStamp) yStampGeneric;
+            if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            } else if (xStamp.neverDistinct(yStamp)) {
+                return TriState.TRUE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java
new file mode 100644
index 0000000..b20d4c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "<", cycles = NodeCycles.CYCLES_3)
+public final class FloatLessThanNode extends CompareNode {
+    public static final NodeClass<FloatLessThanNode> TYPE = NodeClass.create(FloatLessThanNode.class);
+
+    public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
+        super(TYPE, Condition.LT, unorderedIsTrue, x, y);
+        assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
+        assert x.stamp().isCompatible(y.stamp());
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, unorderedIsTrue);
+        if (result != null) {
+            return result;
+        } else {
+            return new FloatLessThanNode(x, y, unorderedIsTrue);
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
+            return LogicConstantNode.contradiction();
+        }
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatLessThanNode(newX, newY, unorderedIsTrue);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerLessThanNode(newX, newY);
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java
new file mode 100644
index 0000000..8947280
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+@NodeInfo
+public abstract class FloatingNode extends ValueNode implements ValueNumberable {
+    public static final NodeClass<FloatingNode> TYPE = NodeClass.create(FloatingNode.class);
+
+    public FloatingNode(NodeClass<? extends FloatingNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    @Override
+    public FloatingNode asNode() {
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java
new file mode 100644
index 0000000..af35849
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "|<|")
+public final class IntegerBelowNode extends CompareNode {
+    public static final NodeClass<IntegerBelowNode> TYPE = NodeClass.create(IntegerBelowNode.class);
+
+    public IntegerBelowNode(ValueNode x, ValueNode y) {
+        super(TYPE, Condition.BT, false, x, y);
+        assert x.stamp() instanceof IntegerStamp;
+        assert y.stamp() instanceof IntegerStamp;
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.BT, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            result = findSynonym(x, y);
+            if (result != null) {
+                return result;
+            }
+            return new IntegerBelowNode(x, y);
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
+        LogicNode synonym = findSynonym(forX, forY);
+        if (synonym != null) {
+            return synonym;
+        }
+        if (forX.isConstant() && forX.asJavaConstant().asLong() == 0) {
+            // 0 |<| y is the same as 0 != y
+            return LogicNegationNode.create(CompareNode.createCompareNode(Condition.EQ, forX, forY, tool.getConstantReflection()));
+        }
+        return this;
+    }
+
+    private static LogicNode findSynonym(ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.contradiction();
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (yStamp.isPositive()) {
+                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                    return LogicConstantNode.tautology();
+                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                    return LogicConstantNode.contradiction();
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerBelowNode(newX, newY);
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        Stamp xStampGeneric = getX().stamp();
+        Stamp yStampGeneric = getY().stamp();
+        if (xStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            int bits = xStamp.getBits();
+            if (yStampGeneric instanceof IntegerStamp) {
+                IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+                assert yStamp.getBits() == bits;
+                if (negated) {
+                    // x >= y
+                    if (xStamp.isPositive() && yStamp.isPositive()) {
+                        long xLowerBound = xStamp.lowerBound();
+                        long yLowerBound = yStamp.lowerBound();
+                        if (yLowerBound > xLowerBound) {
+                            return StampFactory.forIntegerWithMask(bits, yLowerBound, xStamp.upperBound(), xStamp);
+                        }
+                    }
+                } else {
+                    // x < y
+                    if (yStamp.isStrictlyPositive()) {
+                        // x >= 0 && x < y
+                        long xUpperBound = xStamp.upperBound();
+                        long yUpperBound = yStamp.upperBound();
+                        if (yUpperBound <= xUpperBound || !xStamp.isPositive()) {
+                            return StampFactory.forIntegerWithMask(bits, Math.max(0, xStamp.lowerBound()), Math.min(xUpperBound, yUpperBound - 1), xStamp);
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        Stamp xStampGeneric = getX().stamp();
+        Stamp yStampGeneric = getY().stamp();
+        if (xStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            int bits = xStamp.getBits();
+            if (yStampGeneric instanceof IntegerStamp) {
+                IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+                assert yStamp.getBits() == bits;
+                if (negated) {
+                    // y <= x
+                    if (xStamp.isPositive()) {
+                        long xUpperBound = xStamp.upperBound();
+                        long yUpperBound = yStamp.upperBound();
+                        if (xUpperBound < yUpperBound || !yStamp.isPositive()) {
+                            return StampFactory.forIntegerWithMask(bits, Math.max(0, yStamp.lowerBound()), Math.min(xUpperBound, yUpperBound), yStamp);
+                        }
+                    }
+                } else {
+                    // y > x
+                    if (xStamp.isPositive() && yStamp.isPositive()) {
+                        long xLowerBound = xStamp.lowerBound();
+                        long yLowerBound = yStamp.lowerBound();
+                        if (xLowerBound == CodeUtil.maxValue(bits)) {
+                            return null;
+                        } else if (xLowerBound >= yLowerBound) {
+                            assert xLowerBound != CodeUtil.maxValue(bits);
+                            return StampFactory.forIntegerWithMask(bits, xLowerBound + 1, yStamp.upperBound(), yStamp);
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            if (yStampGeneric instanceof IntegerStamp) {
+                IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+                if (yStamp.isPositive()) {
+                    if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                        return TriState.TRUE;
+                    } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                        return TriState.FALSE;
+                    }
+                }
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java
new file mode 100644
index 0000000..1d80557
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ArithmeticOperation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+
+/**
+ * An {@code IntegerConvert} converts an integer to an integer of different width.
+ */
+@NodeInfo
+public abstract class IntegerConvertNode<OP, REV> extends UnaryNode implements ArithmeticOperation, ConvertNode, ArithmeticLIRLowerable {
+    @SuppressWarnings("rawtypes") public static final NodeClass<IntegerConvertNode> TYPE = NodeClass.create(IntegerConvertNode.class);
+
+    protected final SerializableIntegerConvertFunction<OP> getOp;
+    protected final SerializableIntegerConvertFunction<REV> getReverseOp;
+
+    protected final int inputBits;
+    protected final int resultBits;
+
+    protected interface SerializableIntegerConvertFunction<T> extends Function<ArithmeticOpTable, IntegerConvertOp<T>>, Serializable {
+    }
+
+    protected IntegerConvertNode(NodeClass<? extends IntegerConvertNode<OP, REV>> c, SerializableIntegerConvertFunction<OP> getOp, SerializableIntegerConvertFunction<REV> getReverseOp, int inputBits,
+                    int resultBits, ValueNode input) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(input.stamp())).foldStamp(inputBits, resultBits, input.stamp()), input);
+        this.getOp = getOp;
+        this.getReverseOp = getReverseOp;
+        this.inputBits = inputBits;
+        this.resultBits = resultBits;
+    }
+
+    public int getInputBits() {
+        return inputBits;
+    }
+
+    public int getResultBits() {
+        return resultBits;
+    }
+
+    protected final IntegerConvertOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
+    }
+
+    @Override
+    public final IntegerConvertOp<OP> getArithmeticOp() {
+        return getOp(getValue());
+    }
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        return getArithmeticOp().foldConstant(getInputBits(), getResultBits(), c);
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        IntegerConvertOp<REV> reverse = getReverseOp.apply(ArithmeticOpTable.forStamp(stamp()));
+        return reverse.foldConstant(getResultBits(), getInputBits(), c);
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        return getArithmeticOp().foldStamp(inputBits, resultBits, newStamp);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode synonym = findSynonym(getOp(forValue), forValue, inputBits, resultBits, stamp());
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    protected static <T> ValueNode findSynonym(IntegerConvertOp<T> operation, ValueNode value, int inputBits, int resultBits, Stamp stamp) {
+        if (inputBits == resultBits) {
+            return value;
+        } else if (value.isConstant()) {
+            return ConstantNode.forPrimitive(stamp, operation.foldConstant(inputBits, resultBits, value.asConstant()));
+        }
+        return null;
+    }
+
+    public static ValueNode convert(ValueNode input, Stamp stamp) {
+        return convert(input, stamp, false);
+    }
+
+    public static ValueNode convert(ValueNode input, Stamp stamp, StructuredGraph graph) {
+        ValueNode convert = convert(input, stamp, false);
+        if (!convert.isAlive()) {
+            assert !convert.isDeleted();
+            convert = graph.addOrUnique(convert);
+        }
+        return convert;
+    }
+
+    public static ValueNode convertUnsigned(ValueNode input, Stamp stamp) {
+        return convert(input, stamp, true);
+    }
+
+    public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend) {
+        IntegerStamp fromStamp = (IntegerStamp) input.stamp();
+        IntegerStamp toStamp = (IntegerStamp) stamp;
+
+        ValueNode result;
+        if (toStamp.getBits() == fromStamp.getBits()) {
+            result = input;
+        } else if (toStamp.getBits() < fromStamp.getBits()) {
+            result = new NarrowNode(input, fromStamp.getBits(), toStamp.getBits());
+        } else if (zeroExtend) {
+            // toStamp.getBits() > fromStamp.getBits()
+            result = new ZeroExtendNode(input, toStamp.getBits());
+        } else {
+            // toStamp.getBits() > fromStamp.getBits()
+            result = new SignExtendNode(input, toStamp.getBits());
+        }
+
+        IntegerStamp resultStamp = (IntegerStamp) result.stamp();
+        assert toStamp.getBits() == resultStamp.getBits();
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java
new file mode 100644
index 0000000..b487347
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_40, size = SIZE_2)
+public abstract class IntegerDivRemNode extends FixedBinaryNode implements Lowerable {
+
+    public static final NodeClass<IntegerDivRemNode> TYPE = NodeClass.create(IntegerDivRemNode.class);
+
+    public enum Op {
+        DIV,
+        REM
+    }
+
+    public enum Type {
+        SIGNED,
+        UNSIGNED
+    }
+
+    private final Op op;
+    private final Type type;
+
+    protected IntegerDivRemNode(NodeClass<? extends IntegerDivRemNode> c, Stamp stamp, Op op, Type type, ValueNode x, ValueNode y) {
+        super(c, stamp, x, y);
+        this.op = op;
+        this.type = type;
+    }
+
+    public final Op getOp() {
+        return op;
+    }
+
+    public final Type getType() {
+        return type;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return !(getY().stamp() instanceof IntegerStamp) || ((IntegerStamp) getY().stamp()).contains(0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java
new file mode 100644
index 0000000..6c2699b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "==")
+public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode>, IterableNodeType {
+    public static final NodeClass<IntegerEqualsNode> TYPE = NodeClass.create(IntegerEqualsNode.class);
+
+    public IntegerEqualsNode(ValueNode x, ValueNode y) {
+        super(TYPE, Condition.EQ, false, x, y);
+        assert !x.getStackKind().isNumericFloat() && x.getStackKind() != JavaKind.Object;
+        assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object;
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            if (x instanceof ConditionalNode) {
+                ConditionalNode conditionalNode = (ConditionalNode) x;
+                if (conditionalNode.trueValue() == y) {
+                    return conditionalNode.condition();
+                }
+                if (conditionalNode.falseValue() == y) {
+                    return LogicNegationNode.create(conditionalNode.condition());
+                }
+            } else if (y instanceof ConditionalNode) {
+                ConditionalNode conditionalNode = (ConditionalNode) y;
+                if (conditionalNode.trueValue() == x) {
+                    return conditionalNode.condition();
+                }
+                if (conditionalNode.falseValue() == x) {
+                    return LogicNegationNode.create(conditionalNode.condition());
+                }
+            }
+
+            return new IntegerEqualsNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        PrimitiveConstant primitive = (PrimitiveConstant) constant;
+        if (primitive.getJavaKind() == JavaKind.Int && primitive.asInt() == 0) {
+            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
+            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
+
+            if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                return new FloatEqualsNode(a, b);
+            } else {
+                return new IntegerEqualsNode(a, b);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
+            return new IntegerEqualsNode(newX, newY);
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.tautology();
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return LogicConstantNode.contradiction();
+        }
+        return super.canonical(tool, forX, forY);
+    }
+
+    @Override
+    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (constant instanceof PrimitiveConstant && ((PrimitiveConstant) constant).asLong() == 0) {
+            if (nonConstant instanceof AndNode) {
+                AndNode andNode = (AndNode) nonConstant;
+                return new IntegerTestNode(andNode.getX(), andNode.getY());
+            } else if (nonConstant instanceof SubNode) {
+                SubNode subNode = (SubNode) nonConstant;
+                return IntegerEqualsNode.create(subNode.getX(), subNode.getY(), tool.getConstantReflection());
+            } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) {
+                if (nonConstant instanceof LeftShiftNode) {
+                    LeftShiftNode shift = (LeftShiftNode) nonConstant;
+                    if (shift.getY().isConstant()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.getY().asJavaConstant().asInt() & mask;
+                        if (shift.getX().getStackKind() == JavaKind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount));
+                        } else {
+                            assert shift.getX().getStackKind() == JavaKind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L >>> amount));
+                        }
+                    }
+                } else if (nonConstant instanceof RightShiftNode) {
+                    RightShiftNode shift = (RightShiftNode) nonConstant;
+                    if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp()).isPositive()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.getY().asJavaConstant().asInt() & mask;
+                        if (shift.getX().getStackKind() == JavaKind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
+                        } else {
+                            assert shift.getX().getStackKind() == JavaKind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                        }
+                    }
+                } else if (nonConstant instanceof UnsignedRightShiftNode) {
+                    UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
+                    if (shift.getY().isConstant()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.getY().asJavaConstant().asInt() & mask;
+                        if (shift.getX().getStackKind() == JavaKind.Int) {
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
+                        } else {
+                            assert shift.getX().getStackKind() == JavaKind.Long;
+                            return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                        }
+                    }
+                }
+            }
+        }
+        if (nonConstant instanceof AndNode) {
+            /*
+             * a & c == c is the same as a & c != 0, if c is a single bit.
+             */
+            AndNode andNode = (AndNode) nonConstant;
+            if (constant instanceof PrimitiveConstant && Long.bitCount(((PrimitiveConstant) constant).asLong()) == 1 && andNode.getY().isConstant() &&
+                            andNode.getY().asJavaConstant().equals(constant)) {
+                return new LogicNegationNode(new IntegerTestNode(andNode.getX(), andNode.getY()));
+            }
+        }
+        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        if (!negated) {
+            return getX().stamp().join(getY().stamp());
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        if (!negated) {
+            return getX().stamp().join(getY().stamp());
+        }
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof IntegerStamp && yStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+            if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            } else if (xStamp.neverDistinct(yStamp)) {
+                return TriState.TRUE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java
new file mode 100644
index 0000000..c5bd049
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "<")
+public final class IntegerLessThanNode extends CompareNode implements IterableNodeType {
+    public static final NodeClass<IntegerLessThanNode> TYPE = NodeClass.create(IntegerLessThanNode.class);
+
+    public IntegerLessThanNode(ValueNode x, ValueNode y) {
+        super(TYPE, Condition.LT, false, x, y);
+        assert !x.getStackKind().isNumericFloat() && x.getStackKind() != JavaKind.Object;
+        assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object;
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            result = findSynonym(x, y);
+            if (result != null) {
+                return result;
+            }
+            return new IntegerLessThanNode(x, y);
+        }
+    }
+
+    @Override
+    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        PrimitiveConstant primitive = (PrimitiveConstant) constant;
+        assert condition() == Condition.LT;
+        if (primitive.getJavaKind() == JavaKind.Int && primitive.asInt() == 0) {
+            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
+            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
+
+            if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                return new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess);
+            } else {
+                return new IntegerLessThanNode(a, b);
+            }
+        }
+        return this;
+    }
+
+    public static boolean subtractMayUnderflow(long x, long y, long minValue) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        return (((x ^ y) & (x ^ r)) < 0) || r <= minValue;
+    }
+
+    public static boolean subtractMayOverflow(long x, long y, long maxValue) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        return (((x ^ y) & (x ^ r)) < 0) || r > maxValue;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
+        ValueNode synonym = findSynonym(forX, forY);
+        if (synonym != null) {
+            return synonym;
+        }
+        if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) {
+                return new IntegerBelowNode(forX, forY);
+            }
+        }
+        if (forY.isConstant() && forY.asConstant().isDefaultForKind() && forX instanceof SubNode) {
+            // (x - y) < 0 when x - y is known not to underflow == x < y
+            SubNode sub = (SubNode) forX;
+            IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp();
+            IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp();
+            long minValue = CodeUtil.minValue(xStamp.getBits());
+            long maxValue = CodeUtil.maxValue(xStamp.getBits());
+
+            if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) {
+                return new IntegerLessThanNode(sub.getX(), sub.getY());
+            }
+        }
+        return this;
+    }
+
+    private static LogicNode findSynonym(ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.contradiction();
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (xStamp.upperBound() < yStamp.lowerBound()) {
+                return LogicConstantNode.tautology();
+            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
+                return LogicConstantNode.contradiction();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatLessThanNode(newX, newY, true);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerLessThanNode(newX, newY);
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        Stamp xStampGeneric = getX().stamp();
+        Stamp yStampGeneric = getY().stamp();
+        if (xStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            int bits = xStamp.getBits();
+            if (yStampGeneric instanceof IntegerStamp) {
+                IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+                assert yStamp.getBits() == bits;
+                if (negated) {
+                    // x >= y
+                    long xLowerBound = xStamp.lowerBound();
+                    long yLowerBound = yStamp.lowerBound();
+                    if (yLowerBound > xLowerBound) {
+                        return StampFactory.forIntegerWithMask(bits, yLowerBound, xStamp.upperBound(), xStamp);
+                    }
+                } else {
+                    // x < y
+                    long xUpperBound = xStamp.upperBound();
+                    long yUpperBound = yStamp.upperBound();
+                    if (yUpperBound == CodeUtil.minValue(bits)) {
+                        return null;
+                    } else if (yUpperBound <= xUpperBound) {
+                        assert yUpperBound != CodeUtil.minValue(bits);
+                        return StampFactory.forIntegerWithMask(bits, xStamp.lowerBound(), yUpperBound - 1, xStamp);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        Stamp xStampGeneric = getX().stamp();
+        Stamp yStampGeneric = getY().stamp();
+        if (xStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            int bits = xStamp.getBits();
+            if (yStampGeneric instanceof IntegerStamp) {
+                IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+                assert yStamp.getBits() == bits;
+                if (negated) {
+                    // y <= x
+                    long xUpperBound = xStamp.upperBound();
+                    long yUpperBound = yStamp.upperBound();
+                    if (xUpperBound < yUpperBound) {
+                        return StampFactory.forIntegerWithMask(bits, yStamp.lowerBound(), xUpperBound, yStamp);
+                    }
+                } else {
+                    // y > x
+                    long xLowerBound = xStamp.lowerBound();
+                    long yLowerBound = yStamp.lowerBound();
+                    if (xLowerBound == CodeUtil.maxValue(bits)) {
+                        return null;
+                    } else if (xLowerBound >= yLowerBound) {
+                        assert xLowerBound != CodeUtil.maxValue(bits);
+                        return StampFactory.forIntegerWithMask(bits, xLowerBound + 1, yStamp.upperBound(), yStamp);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof IntegerStamp && yStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+            if (xStamp.upperBound() < yStamp.lowerBound()) {
+                return TriState.TRUE;
+            }
+            if (xStamp.lowerBound() >= yStamp.upperBound()) {
+                return TriState.FALSE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java
new file mode 100644
index 0000000..252cc3b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * This node will perform a "test" operation on its arguments. Its result is equivalent to the
+ * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
+ * both x and y.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
+public final class IntegerTestNode extends BinaryOpLogicNode implements BinaryCommutative<ValueNode> {
+    public static final NodeClass<IntegerTestNode> TYPE = NodeClass.create(IntegerTestNode.class);
+
+    public IntegerTestNode(ValueNode x, ValueNode y) {
+        super(TYPE, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return LogicConstantNode.forBoolean((forX.asJavaConstant().asLong() & forY.asJavaConstant().asLong()) == 0);
+        }
+        if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if ((xStamp.upMask() & yStamp.upMask()) == 0) {
+                return LogicConstantNode.tautology();
+            } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
+                return LogicConstantNode.contradiction();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        Stamp xStampGeneric = this.getX().stamp();
+        Stamp yStampGeneric = this.getY().stamp();
+        return getSucceedingStamp(negated, xStampGeneric, yStampGeneric);
+    }
+
+    private static Stamp getSucceedingStamp(boolean negated, Stamp xStampGeneric, Stamp otherStampGeneric) {
+        if (xStampGeneric instanceof IntegerStamp && otherStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            IntegerStamp otherStamp = (IntegerStamp) otherStampGeneric;
+            if (negated) {
+                if (Long.bitCount(otherStamp.upMask()) == 1) {
+                    long newDownMask = xStamp.downMask() | otherStamp.upMask();
+                    if (xStamp.downMask() != newDownMask) {
+                        return IntegerStamp.stampForMask(xStamp.getBits(), newDownMask, xStamp.upMask()).join(xStamp);
+                    }
+                }
+            } else {
+                long restrictedUpMask = ((~otherStamp.downMask()) & xStamp.upMask());
+                if (xStamp.upMask() != restrictedUpMask) {
+                    return IntegerStamp.stampForMask(xStamp.getBits(), xStamp.downMask(), restrictedUpMask).join(xStamp);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        Stamp xStampGeneric = this.getX().stamp();
+        Stamp yStampGeneric = this.getY().stamp();
+        return getSucceedingStamp(negated, yStampGeneric, xStampGeneric);
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof IntegerStamp && yStampGeneric instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
+            IntegerStamp yStamp = (IntegerStamp) yStampGeneric;
+            if ((xStamp.upMask() & yStamp.upMask()) == 0) {
+                return TriState.TRUE;
+            } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
+                return TriState.FALSE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java
new file mode 100644
index 0000000..0479718
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.UnaryOpLogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.PiPushable;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
+ */
+@NodeInfo(cycles = NodeCycles.CYCLES_2)
+public final class IsNullNode extends UnaryOpLogicNode implements LIRLowerable, Virtualizable, PiPushable {
+
+    public static final NodeClass<IsNullNode> TYPE = NodeClass.create(IsNullNode.class);
+
+    public IsNullNode(ValueNode object) {
+        super(TYPE, object);
+        assert object != null;
+    }
+
+    public static LogicNode create(ValueNode forValue) {
+        LogicNode result = tryCanonicalize(forValue);
+        return result == null ? new IsNullNode(forValue) : result;
+    }
+
+    public static LogicNode tryCanonicalize(ValueNode forValue) {
+        if (StampTool.isPointerAlwaysNull(forValue)) {
+            return LogicConstantNode.tautology();
+        } else if (StampTool.isPointerNonNull(forValue)) {
+            return LogicConstantNode.contradiction();
+        }
+        return null;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // Nothing to do.
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(getValue() != null, "is null input must not be null");
+        assertTrue(getValue().stamp() instanceof AbstractPointerStamp, "input must be a pointer not %s", getValue().stamp());
+        return super.verify();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        LogicNode result = tryCanonicalize(forValue);
+        return result == null ? this : result;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getValue());
+        TriState fold = tryFold(alias.stamp());
+        if (fold != TriState.UNKNOWN) {
+            tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph()));
+        }
+    }
+
+    @Override
+    public boolean push(PiNode parent) {
+        if (parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp) {
+            ObjectStamp piStamp = (ObjectStamp) parent.stamp();
+            ObjectStamp piValueStamp = (ObjectStamp) parent.object().stamp();
+            if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) {
+                replaceFirstInput(parent, parent.object());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @NodeIntrinsic
+    public static native IsNullNode isNull(Object object);
+
+    @Override
+    public Stamp getSucceedingStampForValue(boolean negated) {
+        return negated ? getValue().stamp().join(StampFactory.objectNonNull()) : StampFactory.alwaysNull();
+    }
+
+    @Override
+    public TriState tryFold(Stamp valueStamp) {
+        if (valueStamp instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) valueStamp;
+            if (objectStamp.alwaysNull()) {
+                return TriState.TRUE;
+            } else if (objectStamp.nonNull()) {
+                return TriState.FALSE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java
new file mode 100644
index 0000000..87ecb87
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(shortName = "<<")
+public final class LeftShiftNode extends ShiftNode<Shl> {
+
+    public static final NodeClass<LeftShiftNode> TYPE = NodeClass.create(LeftShiftNode.class);
+
+    public LeftShiftNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getShl, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forY.isConstant()) {
+            int amount = forY.asJavaConstant().asInt();
+            int originalAmout = amount;
+            int mask = getShiftAmountMask();
+            amount &= mask;
+            if (amount == 0) {
+                return forX;
+            }
+            if (forX instanceof ShiftNode) {
+                ShiftNode<?> other = (ShiftNode<?>) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asJavaConstant().asInt() & mask;
+                    if (other instanceof LeftShiftNode) {
+                        int total = amount + otherAmount;
+                        if (total != (total & mask)) {
+                            return ConstantNode.forIntegerKind(getStackKind(), 0);
+                        }
+                        return new LeftShiftNode(other.getX(), ConstantNode.forInt(total));
+                    } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) {
+                        if (getStackKind() == JavaKind.Long) {
+                            return new AndNode(other.getX(), ConstantNode.forLong(-1L << amount));
+                        } else {
+                            assert getStackKind() == JavaKind.Int;
+                            return new AndNode(other.getX(), ConstantNode.forInt(-1 << amount));
+                        }
+                    }
+                }
+            }
+            if (originalAmout != amount) {
+                return new LeftShiftNode(forX, ConstantNode.forInt(amount));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitShl(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java
new file mode 100644
index 0000000..b5d0560
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(shortName = "*", cycles = NodeCycles.CYCLES_3)
+public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    public static final NodeClass<MulNode> TYPE = NodeClass.create(MulNode.class);
+
+    public MulNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected MulNode(NodeClass<? extends MulNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getMul, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Mul> op = ArithmeticOpTable.forStamp(x.stamp()).getMul();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new MulNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            // we try to swap and canonicalize
+            ValueNode improvement = canonical(tool, forY, forX);
+            if (improvement != this) {
+                return improvement;
+            }
+            // if this fails we only swap
+            return new MulNode(forY, forX);
+        }
+        if (forY.isConstant()) {
+            BinaryOp<Mul> op = getOp(forX, forY);
+            Constant c = forY.asConstant();
+            if (op.isNeutral(c)) {
+                return forX;
+            }
+
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long i = ((PrimitiveConstant) c).asLong();
+                if (i > 0 && CodeUtil.isPowerOf2(i)) {
+                    return new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
+                }
+                if (i == 0) {
+                    return ConstantNode.forIntegerStamp(stamp, 0);
+                }
+            }
+
+            if (op.isAssociative()) {
+                // canonicalize expressions like "(a * 1) * 2"
+                return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value op1 = nodeValueMap.operand(getX());
+        Value op2 = nodeValueMap.operand(getY());
+        if (shouldSwapInputs(nodeValueMap)) {
+            Value tmp = op1;
+            op1 = op2;
+            op2 = tmp;
+        }
+        nodeValueMap.setResult(this, gen.emitMul(op1, op2, false));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java
new file mode 100644
index 0000000..5331f35
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code NarrowNode} converts an integer to a narrower integer.
+ */
+@NodeInfo(cycles = CYCLES_1)
+public final class NarrowNode extends IntegerConvertNode<Narrow, SignExtend> {
+
+    public static final NodeClass<NarrowNode> TYPE = NodeClass.create(NarrowNode.class);
+
+    public NarrowNode(ValueNode input, int resultBits) {
+        this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+        assert 0 < resultBits && resultBits <= PrimitiveStamp.getBits(input.stamp());
+    }
+
+    public NarrowNode(ValueNode input, int inputBits, int resultBits) {
+        super(TYPE, ArithmeticOpTable::getNarrow, ArithmeticOpTable::getSignExtend, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<Narrow> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getNarrow();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new NarrowNode(input, inputBits, resultBits);
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forValue instanceof NarrowNode) {
+            // zzzzzzzz yyyyxxxx -(narrow)-> yyyyxxxx -(narrow)-> xxxx
+            // ==> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
+            NarrowNode other = (NarrowNode) forValue;
+            return new NarrowNode(other.getValue(), other.getInputBits(), getResultBits());
+        } else if (forValue instanceof IntegerConvertNode) {
+            // SignExtendNode or ZeroExtendNode
+            IntegerConvertNode<?, ?> other = (IntegerConvertNode<?, ?>) forValue;
+            if (other.getValue().getUsageCount() == 1 && other.getUsageCount() > 1) {
+                // Do not perform if this will introduce a new live value.
+                // If the original value's usage count is > 1, there is already another user.
+                // If the convert's usage count is <=1, it will be dead code eliminated.
+                return this;
+            }
+            if (getResultBits() == other.getInputBits()) {
+                // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
+                // ==> no-op
+                return other.getValue();
+            } else if (getResultBits() < other.getInputBits()) {
+                // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
+                // ==> yyyyxxxx -(narrow)-> xxxx
+                return new NarrowNode(other.getValue(), other.getInputBits(), getResultBits());
+            } else {
+                if (other instanceof SignExtendNode) {
+                    // sxxx -(sign-extend)-> ssssssss sssssxxx -(narrow)-> sssssxxx
+                    // ==> sxxx -(sign-extend)-> sssssxxx
+                    return new SignExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+                } else if (other instanceof ZeroExtendNode) {
+                    // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx
+                    // ==> xxxx -(zero-extend)-> 0000xxxx
+                    return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitNarrow(nodeValueMap.operand(getValue()), getResultBits()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowableArithmeticNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowableArithmeticNode.java
new file mode 100644
index 0000000..56e84f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowableArithmeticNode.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+/**
+ * Marker interface for nodes where it is valid to apply a {@link NarrowNode} to its inputs and do a
+ * narrow operation instead of doing the wide operation and applying the {@link NarrowNode} to the
+ * result.
+ */
+public interface NarrowableArithmeticNode {
+
+    /**
+     * Check whether this operation can be narrowed to {@code resultBits} bit without loss of
+     * precision.
+     *
+     * @param resultBits
+     */
+    default boolean isNarrowable(int resultBits) {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java
new file mode 100644
index 0000000..cb7f506
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code NegateNode} node negates its operand.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class NegateNode extends UnaryArithmeticNode<Neg> implements NarrowableArithmeticNode {
+
+    public static final NodeClass<NegateNode> TYPE = NodeClass.create(NegateNode.class);
+
+    public NegateNode(ValueNode value) {
+        super(TYPE, ArithmeticOpTable::getNeg, value);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+        if (forValue instanceof NegateNode) {
+            return ((NegateNode) forValue).getValue();
+        }
+        if (forValue instanceof SubNode && !(forValue.stamp() instanceof FloatStamp)) {
+            SubNode sub = (SubNode) forValue;
+            return new SubNode(sub.getY(), sub.getX());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitNegate(nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java
new file mode 100644
index 0000000..3b1e4dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Returns -1, 0, or 1 if either x &lt; y, x == y, or x &gt; y. If the comparison is undecided (one
+ * of the inputs is NaN), the result is 1 if isUnorderedLess is false and -1 if isUnorderedLess is
+ * true.
+ */
+@NodeInfo(cycles = NodeCycles.CYCLES_2, size = NodeSize.SIZE_4)
+public final class NormalizeCompareNode extends BinaryNode implements Lowerable {
+
+    public static final NodeClass<NormalizeCompareNode> TYPE = NodeClass.create(NormalizeCompareNode.class);
+    protected final boolean isUnorderedLess;
+
+    public NormalizeCompareNode(ValueNode x, ValueNode y, boolean isUnorderedLess) {
+        super(TYPE, StampFactory.forKind(JavaKind.Int), x, y);
+        this.isUnorderedLess = isUnorderedLess;
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y, boolean isUnorderedLess, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) result;
+            LogicNode resultLT = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, isUnorderedLess);
+            if (resultLT instanceof LogicConstantNode) {
+                LogicConstantNode logicConstantNodeLT = (LogicConstantNode) resultLT;
+                if (logicConstantNodeLT.getValue()) {
+                    return ConstantNode.forInt(-1);
+                } else if (logicConstantNode.getValue()) {
+                    return ConstantNode.forInt(0);
+                } else {
+                    return ConstantNode.forInt(1);
+                }
+            }
+        }
+
+        return new NormalizeCompareNode(x, y, isUnorderedLess);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        // nothing to do
+        return this;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return false;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        LogicNode equalComp;
+        LogicNode lessComp;
+        if (getX().stamp() instanceof FloatStamp) {
+            equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
+            lessComp = graph().unique(FloatLessThanNode.create(getX(), getY(), isUnorderedLess, tool.getConstantReflection()));
+        } else {
+            equalComp = graph().unique(IntegerEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
+            lessComp = graph().unique(IntegerLessThanNode.create(getX(), getY(), tool.getConstantReflection()));
+        }
+
+        ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
+        ConditionalNode value = graph().unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph()), equalValue));
+        replaceAtUsagesAndDelete(value);
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        return stamp();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NotNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NotNode.java
new file mode 100644
index 0000000..0430abe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NotNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Binary negation of long or integer values.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public final class NotNode extends UnaryArithmeticNode<Not> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+
+    public static final NodeClass<NotNode> TYPE = NodeClass.create(NotNode.class);
+
+    public NotNode(ValueNode x) {
+        super(TYPE, ArithmeticOpTable::getNot, x);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+        if (forValue instanceof NotNode) {
+            return ((NotNode) forValue).getValue();
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitNot(nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java
new file mode 100644
index 0000000..6f2727c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GetClassNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(shortName = "==")
+public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable {
+
+    public static final NodeClass<ObjectEqualsNode> TYPE = NodeClass.create(ObjectEqualsNode.class);
+
+    public ObjectEqualsNode(ValueNode x, ValueNode y) {
+        super(TYPE, x, y);
+        assert x.stamp() instanceof AbstractObjectStamp;
+        assert y.stamp() instanceof AbstractObjectStamp;
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result != null) {
+            return result;
+        } else {
+            result = findSynonym(x, y);
+            if (result != null) {
+                return result;
+            }
+            return new ObjectEqualsNode(x, y);
+        }
+    }
+
+    @Override
+    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        ResolvedJavaType type = tool.getConstantReflection().asJavaType(constant);
+        if (type != null && nonConstant instanceof GetClassNode) {
+            GetClassNode getClassNode = (GetClassNode) nonConstant;
+            ValueNode object = getClassNode.getObject();
+            assert ((ObjectStamp) object.stamp()).nonNull();
+            if (!type.isPrimitive() && (type.isConcrete() || type.isArray())) {
+                return InstanceOfNode.create(TypeReference.createExactTrusted(type), object);
+            }
+            return LogicConstantNode.forBoolean(false);
+        }
+        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
+    }
+
+    private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) {
+        if (virtual instanceof VirtualBoxingNode && other.isConstant()) {
+            VirtualBoxingNode virtualBoxingNode = (VirtualBoxingNode) virtual;
+            if (virtualBoxingNode.getBoxingKind() == JavaKind.Boolean) {
+                JavaConstant otherUnboxed = tool.getConstantReflectionProvider().unboxPrimitive(other.asJavaConstant());
+                if (otherUnboxed != null && otherUnboxed.getJavaKind() == JavaKind.Boolean) {
+                    int expectedValue = otherUnboxed.asBoolean() ? 1 : 0;
+                    IntegerEqualsNode equals = new IntegerEqualsNode(virtualBoxingNode.getBoxedValue(tool), ConstantNode.forInt(expectedValue, graph()));
+                    tool.addNode(equals);
+                    tool.replaceWithValue(equals);
+                } else {
+                    tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+                }
+            }
+        }
+        if (virtual.hasIdentity()) {
+            // one of them is virtual: they can never be the same objects
+            tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode xAlias = tool.getAlias(getX());
+        ValueNode yAlias = tool.getAlias(getY());
+
+        VirtualObjectNode xVirtual = xAlias instanceof VirtualObjectNode ? (VirtualObjectNode) xAlias : null;
+        VirtualObjectNode yVirtual = yAlias instanceof VirtualObjectNode ? (VirtualObjectNode) yAlias : null;
+
+        if (xVirtual != null && yVirtual == null) {
+            virtualizeNonVirtualComparison(xVirtual, yAlias, tool);
+        } else if (xVirtual == null && yVirtual != null) {
+            virtualizeNonVirtualComparison(yVirtual, xAlias, tool);
+        } else if (xVirtual != null && yVirtual != null) {
+            if (xVirtual.hasIdentity() ^ yVirtual.hasIdentity()) {
+                /*
+                 * One of the two objects has identity, the other doesn't. In code, this looks like
+                 * "Integer.valueOf(a) == new Integer(b)", which is always false.
+                 *
+                 * In other words: an object created via valueOf can never be equal to one created
+                 * by new in the same compilation unit.
+                 */
+                tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+            } else if (!xVirtual.hasIdentity() && !yVirtual.hasIdentity()) {
+                ResolvedJavaType type = xVirtual.type();
+                if (type.equals(yVirtual.type())) {
+                    MetaAccessProvider metaAccess = tool.getMetaAccessProvider();
+                    if (type.equals(metaAccess.lookupJavaType(Integer.class)) || type.equals(metaAccess.lookupJavaType(Long.class))) {
+                        // both are virtual without identity: check contents
+                        assert xVirtual.entryCount() == 1 && yVirtual.entryCount() == 1;
+                        assert xVirtual.entryKind(0).getStackKind() == JavaKind.Int || xVirtual.entryKind(0) == JavaKind.Long;
+                        IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0));
+                        tool.addNode(equals);
+                        tool.replaceWithValue(equals);
+                    }
+                }
+            } else {
+                // both are virtual with identity: check if they refer to the same object
+                tool.replaceWithValue(LogicConstantNode.forBoolean(xVirtual == yVirtual, graph()));
+            }
+        }
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof ObjectStamp && newY.stamp() instanceof ObjectStamp) {
+            return new ObjectEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
+            return new PointerEqualsNode(newX, newY);
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java
new file mode 100644
index 0000000..7b9fe94
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(shortName = "|")
+public final class OrNode extends BinaryArithmeticNode<Or> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
+
+    public static final NodeClass<OrNode> TYPE = NodeClass.create(OrNode.class);
+
+    public OrNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getOr, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new OrNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return forX;
+        }
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new OrNode(forY, forX);
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp(forX, forY).isNeutral(c)) {
+                return forX;
+            }
+
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long rawY = ((PrimitiveConstant) c).asLong();
+                long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp()));
+                if ((rawY & mask) == mask) {
+                    return ConstantNode.forIntegerStamp(stamp(), mask);
+                }
+            }
+            return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitOr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java
new file mode 100644
index 0000000..4fb84ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.LoadMethodNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.TriState;
+
+@NodeInfo(shortName = "==")
+public class PointerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
+
+    public static final NodeClass<PointerEqualsNode> TYPE = NodeClass.create(PointerEqualsNode.class);
+
+    public PointerEqualsNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    public static LogicNode create(ValueNode x, ValueNode y) {
+        LogicNode result = findSynonym(x, y);
+        if (result != null) {
+            return result;
+        }
+        return new PointerEqualsNode(x, y);
+    }
+
+    protected PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y) {
+        super(c, Condition.EQ, false, x, y);
+        assert x.stamp() instanceof AbstractPointerStamp;
+        assert y.stamp() instanceof AbstractPointerStamp;
+    }
+
+    /**
+     * Determines if this is a comparison used to determine whether dispatching on a receiver could
+     * select a certain method and if so, returns {@code true} if the answer is guaranteed to be
+     * false. Otherwise, returns {@code false}.
+     */
+    private boolean isAlwaysFailingVirtualDispatchTest(ValueNode forX, ValueNode forY) {
+        if (forY.isConstant()) {
+            if (forX instanceof LoadMethodNode && condition == Condition.EQ) {
+                LoadMethodNode lm = ((LoadMethodNode) forX);
+                if (lm.getMethod().getEncoding().equals(forY.asConstant())) {
+                    if (lm.getHub() instanceof LoadHubNode) {
+                        ValueNode object = ((LoadHubNode) lm.getHub()).getValue();
+                        ResolvedJavaType type = StampTool.typeOrNull(object);
+                        ResolvedJavaType declaringClass = lm.getMethod().getDeclaringClass();
+                        if (type != null && !type.equals(declaringClass) && declaringClass.isAssignableFrom(type)) {
+                            ResolvedJavaMethod override = type.resolveMethod(lm.getMethod(), lm.getCallerType());
+                            if (override != null && override != lm.getMethod()) {
+                                assert declaringClass.isAssignableFrom(override.getDeclaringClass());
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        LogicNode result = findSynonym(forX, forY);
+        if (result != null) {
+            return result;
+        }
+        if (isAlwaysFailingVirtualDispatchTest(forX, forY)) {
+            return LogicConstantNode.contradiction();
+        }
+        return super.canonical(tool, forX, forY);
+    }
+
+    public static LogicNode findSynonym(ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.tautology();
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return LogicConstantNode.contradiction();
+        } else if (((AbstractPointerStamp) forX.stamp()).alwaysNull()) {
+            return IsNullNode.create(forY);
+        } else if (((AbstractPointerStamp) forY.stamp()).alwaysNull()) {
+            return IsNullNode.create(forX);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new PointerEqualsNode(newX, newY);
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        if (!negated) {
+            Stamp xStamp = getX().stamp();
+            Stamp newStamp = xStamp.join(getY().stamp());
+            if (!newStamp.equals(xStamp)) {
+                return newStamp;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        if (!negated) {
+            Stamp yStamp = getY().stamp();
+            Stamp newStamp = yStamp.join(getX().stamp());
+            if (!newStamp.equals(yStamp)) {
+                return newStamp;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) {
+        if (xStampGeneric instanceof ObjectStamp && yStampGeneric instanceof ObjectStamp) {
+            ObjectStamp xStamp = (ObjectStamp) xStampGeneric;
+            ObjectStamp yStamp = (ObjectStamp) yStampGeneric;
+            if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            } else if (xStamp.neverDistinct(yStamp)) {
+                return TriState.TRUE;
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ReinterpretNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ReinterpretNode.java
new file mode 100644
index 0000000..494cfae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ReinterpretNode.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.ArithmeticStamp;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.SerializableConstant;
+
+/**
+ * The {@code ReinterpretNode} class represents a reinterpreting conversion that changes the stamp
+ * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
+ * the old stamp.
+ */
+@NodeInfo(cycles = CYCLES_1)
+public final class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<ReinterpretNode> TYPE = NodeClass.create(ReinterpretNode.class);
+
+    public ReinterpretNode(JavaKind to, ValueNode value) {
+        this(StampFactory.forKind(to), value);
+    }
+
+    public ReinterpretNode(Stamp to, ValueNode value) {
+        super(TYPE, getReinterpretStamp(to, value.stamp()), value);
+        assert to instanceof ArithmeticStamp;
+    }
+
+    private SerializableConstant evalConst(SerializableConstant c) {
+        /*
+         * We don't care about byte order here. Either would produce the correct result.
+         */
+        ByteBuffer buffer = ByteBuffer.wrap(new byte[c.getSerializedSize()]).order(ByteOrder.nativeOrder());
+        c.serialize(buffer);
+
+        buffer.rewind();
+        SerializableConstant ret = ((ArithmeticStamp) stamp()).deserialize(buffer);
+
+        assert !buffer.hasRemaining();
+        return ret;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst((SerializableConstant) forValue.asConstant()), null);
+        }
+        if (stamp().isCompatible(forValue.stamp())) {
+            return forValue;
+        }
+        if (forValue instanceof ReinterpretNode) {
+            ReinterpretNode reinterpret = (ReinterpretNode) forValue;
+            return new ReinterpretNode(stamp(), reinterpret.getValue());
+        }
+        return this;
+    }
+
+    /**
+     * Compute the {@link IntegerStamp} from a {@link FloatStamp}, losing as little information as
+     * possible.
+     *
+     * Sorting by their bit pattern reinterpreted as signed integers gives the following order of
+     * floating point numbers:
+     *
+     * -0 | negative numbers | -Inf | NaNs | 0 | positive numbers | +Inf | NaNs
+     *
+     * So we can compute a better integer range if we know that the input is positive, negative,
+     * finite, non-zero and/or not NaN.
+     */
+    private static IntegerStamp floatToInt(FloatStamp stamp) {
+        int bits = stamp.getBits();
+
+        long signBit = 1L << (bits - 1);
+        long exponentMask;
+        if (bits == 64) {
+            exponentMask = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
+        } else {
+            assert bits == 32;
+            exponentMask = Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
+        }
+
+        long positiveInfinity = exponentMask;
+        long negativeInfinity = CodeUtil.signExtend(signBit | positiveInfinity, bits);
+        long negativeZero = CodeUtil.signExtend(signBit | 0, bits);
+
+        if (stamp.isNaN()) {
+            // special case: in addition to the range, we know NaN has all exponent bits set
+            return new IntegerStamp(bits, negativeInfinity + 1, CodeUtil.maxValue(bits), exponentMask, CodeUtil.mask(bits));
+        }
+
+        long upperBound;
+        if (stamp.isNonNaN()) {
+            if (stamp.upperBound() < 0.0) {
+                if (stamp.lowerBound() > Double.NEGATIVE_INFINITY) {
+                    upperBound = negativeInfinity - 1;
+                } else {
+                    upperBound = negativeInfinity;
+                }
+            } else if (stamp.upperBound() == 0.0) {
+                upperBound = 0;
+            } else if (stamp.upperBound() < Double.POSITIVE_INFINITY) {
+                upperBound = positiveInfinity - 1;
+            } else {
+                upperBound = positiveInfinity;
+            }
+        } else {
+            upperBound = CodeUtil.maxValue(bits);
+        }
+
+        long lowerBound;
+        if (stamp.lowerBound() > 0.0) {
+            if (stamp.isNonNaN()) {
+                lowerBound = 1;
+            } else {
+                lowerBound = negativeInfinity + 1;
+            }
+        } else if (stamp.upperBound() == Double.NEGATIVE_INFINITY) {
+            lowerBound = negativeInfinity;
+        } else if (stamp.upperBound() < 0.0) {
+            lowerBound = negativeZero + 1;
+        } else {
+            lowerBound = negativeZero;
+        }
+
+        return StampFactory.forInteger(bits, lowerBound, upperBound);
+    }
+
+    /**
+     * Compute the {@link IntegerStamp} from a {@link FloatStamp}, losing as little information as
+     * possible.
+     *
+     * Sorting by their bit pattern reinterpreted as signed integers gives the following order of
+     * floating point numbers:
+     *
+     * -0 | negative numbers | -Inf | NaNs | 0 | positive numbers | +Inf | NaNs
+     *
+     * So from certain integer ranges we may be able to infer something about the sign, finiteness
+     * or NaN-ness of the result.
+     */
+    private static FloatStamp intToFloat(IntegerStamp stamp) {
+        int bits = stamp.getBits();
+
+        double minPositive;
+        double maxPositive;
+
+        long signBit = 1L << (bits - 1);
+        long exponentMask;
+        if (bits == 64) {
+            exponentMask = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
+            minPositive = Double.MIN_VALUE;
+            maxPositive = Double.MAX_VALUE;
+        } else {
+            assert bits == 32;
+            exponentMask = Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
+            minPositive = Float.MIN_VALUE;
+            maxPositive = Float.MAX_VALUE;
+        }
+
+        long significandMask = CodeUtil.mask(bits) & ~(signBit | exponentMask);
+
+        long positiveInfinity = exponentMask;
+        long negativeInfinity = CodeUtil.signExtend(signBit | positiveInfinity, bits);
+        long negativeZero = CodeUtil.signExtend(signBit | 0, bits);
+
+        if ((stamp.downMask() & exponentMask) == exponentMask && (stamp.downMask() & significandMask) != 0) {
+            // if all exponent bits and at least one significand bit are set, the result is NaN
+            return new FloatStamp(bits, Double.NaN, Double.NaN, false);
+        }
+
+        double upperBound;
+        if (stamp.upperBound() < negativeInfinity) {
+            if (stamp.lowerBound() > negativeZero) {
+                upperBound = -minPositive;
+            } else {
+                upperBound = -0.0;
+            }
+        } else if (stamp.upperBound() < 0) {
+            if (stamp.lowerBound() > negativeInfinity) {
+                return new FloatStamp(bits, Double.NaN, Double.NaN, false);
+            } else if (stamp.lowerBound() == negativeInfinity) {
+                upperBound = Double.NEGATIVE_INFINITY;
+            } else if (stamp.lowerBound() > negativeZero) {
+                upperBound = -minPositive;
+            } else {
+                upperBound = -0.0;
+            }
+        } else if (stamp.upperBound() == 0) {
+            upperBound = 0.0;
+        } else if (stamp.upperBound() < positiveInfinity) {
+            upperBound = maxPositive;
+        } else {
+            upperBound = Double.POSITIVE_INFINITY;
+        }
+
+        double lowerBound;
+        if (stamp.lowerBound() > positiveInfinity) {
+            return new FloatStamp(bits, Double.NaN, Double.NaN, false);
+        } else if (stamp.lowerBound() == positiveInfinity) {
+            lowerBound = Double.POSITIVE_INFINITY;
+        } else if (stamp.lowerBound() > 0) {
+            lowerBound = minPositive;
+        } else if (stamp.lowerBound() > negativeInfinity) {
+            lowerBound = 0.0;
+        } else {
+            lowerBound = Double.NEGATIVE_INFINITY;
+        }
+
+        boolean nonNaN;
+        if ((stamp.upMask() & exponentMask) != exponentMask) {
+            // NaN has all exponent bits set
+            nonNaN = true;
+        } else {
+            boolean negativeNaNBlock = stamp.lowerBound() < 0 && stamp.upperBound() > negativeInfinity;
+            boolean positiveNaNBlock = stamp.upperBound() > positiveInfinity;
+            nonNaN = !negativeNaNBlock && !positiveNaNBlock;
+        }
+
+        return new FloatStamp(bits, lowerBound, upperBound, nonNaN);
+    }
+
+    private static Stamp getReinterpretStamp(Stamp toStamp, Stamp fromStamp) {
+        if (toStamp instanceof IntegerStamp && fromStamp instanceof FloatStamp) {
+            return floatToInt((FloatStamp) fromStamp);
+        } else if (toStamp instanceof FloatStamp && fromStamp instanceof IntegerStamp) {
+            return intToFloat((IntegerStamp) fromStamp);
+        } else {
+            return toStamp;
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(getReinterpretStamp(stamp(), getValue().stamp()));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        LIRKind kind = builder.getLIRGeneratorTool().getLIRKind(stamp());
+        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(getValue())));
+    }
+
+    public static ValueNode reinterpret(JavaKind toKind, ValueNode value) {
+        return value.graph().unique(new ReinterpretNode(toKind, value));
+    }
+
+    @NodeIntrinsic
+    public static native float reinterpret(@ConstantNodeParameter JavaKind kind, int value);
+
+    @NodeIntrinsic
+    public static native int reinterpret(@ConstantNodeParameter JavaKind kind, float value);
+
+    @NodeIntrinsic
+    public static native double reinterpret(@ConstantNodeParameter JavaKind kind, long value);
+
+    @NodeIntrinsic
+    public static native long reinterpret(@ConstantNodeParameter JavaKind kind, double value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java
new file mode 100644
index 0000000..2a89202
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(shortName = "%", cycles = NodeCycles.CYCLES_30/* div */)
+public class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
+
+    public static final NodeClass<RemNode> TYPE = NodeClass.create(RemNode.class);
+
+    public RemNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected RemNode(NodeClass<? extends RemNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getRem, x, y);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitRem(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java
new file mode 100644
index 0000000..92aed78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+@NodeInfo(shortName = ">>")
+public final class RightShiftNode extends ShiftNode<Shr> {
+
+    public static final NodeClass<RightShiftNode> TYPE = NodeClass.create(RightShiftNode.class);
+
+    public RightShiftNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getShr, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
+            return new UnsignedRightShiftNode(forX, forY);
+        }
+
+        if (forY.isConstant()) {
+            int amount = forY.asJavaConstant().asInt();
+            int originalAmout = amount;
+            int mask = getShiftAmountMask();
+            amount &= mask;
+            if (amount == 0) {
+                return forX;
+            }
+            if (forX instanceof ShiftNode) {
+                ShiftNode<?> other = (ShiftNode<?>) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asJavaConstant().asInt() & mask;
+                    if (other instanceof RightShiftNode) {
+                        int total = amount + otherAmount;
+                        if (total != (total & mask)) {
+                            assert other.getX().stamp() instanceof IntegerStamp;
+                            IntegerStamp istamp = (IntegerStamp) other.getX().stamp();
+
+                            if (istamp.isPositive()) {
+                                return ConstantNode.forIntegerKind(getStackKind(), 0);
+                            }
+                            if (istamp.isStrictlyNegative()) {
+                                return ConstantNode.forIntegerKind(getStackKind(), -1L);
+                            }
+
+                            /*
+                             * if we cannot replace both shifts with a constant, replace them by a
+                             * full shift for this kind
+                             */
+                            assert total >= mask;
+                            return new RightShiftNode(other.getX(), ConstantNode.forInt(mask));
+                        }
+                        return new RightShiftNode(other.getX(), ConstantNode.forInt(total));
+                    }
+                }
+            }
+            if (originalAmout != amount) {
+                return new RightShiftNode(forX, ConstantNode.forInt(amount));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitShr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+
+    @Override
+    public boolean isNarrowable(int resultBits) {
+        if (super.isNarrowable(resultBits)) {
+            /*
+             * For signed right shifts, the narrow can be done before the shift if the cut off bits
+             * are all equal to the sign bit of the input. That's equivalent to the condition that
+             * the input is in the signed range of the narrow type.
+             */
+            IntegerStamp inputStamp = (IntegerStamp) getX().stamp();
+            return CodeUtil.minValue(resultBits) <= inputStamp.lowerBound() && inputStamp.upperBound() <= CodeUtil.maxValue(resultBits);
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java
new file mode 100644
index 0000000..269226a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ArithmeticOperation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code ShiftOp} class represents shift operations.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public abstract class ShiftNode<OP> extends BinaryNode implements ArithmeticOperation, ArithmeticLIRLowerable, NarrowableArithmeticNode {
+
+    @SuppressWarnings("rawtypes") public static final NodeClass<ShiftNode> TYPE = NodeClass.create(ShiftNode.class);
+
+    protected interface SerializableShiftFunction<T> extends Function<ArithmeticOpTable, ShiftOp<T>>, Serializable {
+    }
+
+    protected final SerializableShiftFunction<OP> getOp;
+
+    /**
+     * Creates a new shift operation.
+     *
+     * @param x the first input value
+     * @param s the second input value
+     */
+    protected ShiftNode(NodeClass<? extends ShiftNode<OP>> c, SerializableShiftFunction<OP> getOp, ValueNode x, ValueNode s) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), (IntegerStamp) s.stamp()), x, s);
+        assert ((IntegerStamp) s.stamp()).getBits() == 32;
+        this.getOp = getOp;
+    }
+
+    protected final ShiftOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
+    }
+
+    @Override
+    public final ShiftOp<OP> getArithmeticOp() {
+        return getOp(getX());
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        return getArithmeticOp().foldStamp(stampX, (IntegerStamp) stampY);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            JavaConstant amount = forY.asJavaConstant();
+            assert amount.getJavaKind() == JavaKind.Int;
+            return ConstantNode.forPrimitive(stamp(), getOp(forX).foldConstant(forX.asConstant(), amount.asInt()));
+        }
+        return this;
+    }
+
+    public int getShiftAmountMask() {
+        return getArithmeticOp().getShiftAmountMask(stamp());
+    }
+
+    @Override
+    public boolean isNarrowable(int resultBits) {
+        assert CodeUtil.isPowerOf2(resultBits);
+        int narrowMask = resultBits - 1;
+        int wideMask = getShiftAmountMask();
+        assert (wideMask & narrowMask) == narrowMask : String.format("wideMask %x should be wider than narrowMask %x", wideMask, narrowMask);
+
+        /*
+         * Shifts are special because narrowing them also changes the implicit mask of the shift
+         * amount. We can narrow only if (y & wideMask) == (y & narrowMask) for all possible values
+         * of y.
+         */
+        IntegerStamp yStamp = (IntegerStamp) getY().stamp();
+        return (yStamp.upMask() & (wideMask & ~narrowMask)) == 0;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java
new file mode 100644
index 0000000..78d67be
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code SignExtendNode} converts an integer to a wider integer using sign extension.
+ */
+@NodeInfo(cycles = CYCLES_1)
+public final class SignExtendNode extends IntegerConvertNode<SignExtend, Narrow> {
+
+    public static final NodeClass<SignExtendNode> TYPE = NodeClass.create(SignExtendNode.class);
+
+    public SignExtendNode(ValueNode input, int resultBits) {
+        this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+        assert 0 < PrimitiveStamp.getBits(input.stamp()) && PrimitiveStamp.getBits(input.stamp()) <= resultBits;
+    }
+
+    public SignExtendNode(ValueNode input, int inputBits, int resultBits) {
+        super(TYPE, ArithmeticOpTable::getSignExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<SignExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getSignExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new SignExtendNode(input, inputBits, resultBits);
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forValue instanceof SignExtendNode) {
+            // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx
+            // ==> sxxx -(sign-extend)-> ssssssss sssssxxx
+            SignExtendNode other = (SignExtendNode) forValue;
+            return new SignExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+        } else if (forValue instanceof ZeroExtendNode) {
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
+            if (other.getResultBits() > other.getInputBits()) {
+                // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx
+                // ==> sxxx -(zero-extend)-> 00000000 0000sxxx
+                return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+            }
+        }
+
+        if (forValue.stamp() instanceof IntegerStamp) {
+            IntegerStamp inputStamp = (IntegerStamp) forValue.stamp();
+            if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) {
+                // 0xxx -(sign-extend)-> 0000 0xxx
+                // ==> 0xxx -(zero-extend)-> 0000 0xxx
+                return new ZeroExtendNode(forValue, getInputBits(), getResultBits());
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitSignExtend(nodeValueMap.operand(getValue()), getInputBits(), getResultBits()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java
new file mode 100644
index 0000000..0a3b3e5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+@NodeInfo(shortName = "/")
+public class SignedDivNode extends IntegerDivRemNode implements LIRLowerable {
+
+    public static final NodeClass<SignedDivNode> TYPE = NodeClass.create(SignedDivNode.class);
+
+    public SignedDivNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected SignedDivNode(NodeClass<? extends SignedDivNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), Op.DIV, Type.SIGNED, x, y);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(IntegerStamp.OPS.getDiv().foldStamp(getX().stamp(), getY().stamp()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            @SuppressWarnings("hiding")
+            long y = forY.asJavaConstant().asLong();
+            if (y == 0) {
+                return this; // this will trap, can not canonicalize
+            }
+            return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() / y);
+        } else if (forY.isConstant()) {
+            long c = forY.asJavaConstant().asLong();
+            if (c == 1) {
+                return forX;
+            }
+            if (c == -1) {
+                return new NegateNode(forX);
+            }
+            long abs = Math.abs(c);
+            if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) {
+                ValueNode dividend = forX;
+                IntegerStamp stampX = (IntegerStamp) forX.stamp();
+                int log2 = CodeUtil.log2(abs);
+                // no rounding if dividend is positive or if its low bits are always 0
+                if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) {
+                    int bits = PrimitiveStamp.getBits(stamp());
+                    RightShiftNode sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1));
+                    UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2));
+                    dividend = BinaryArithmeticNode.add(dividend, round);
+                }
+                RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2));
+                if (c < 0) {
+                    return new NegateNode(shift);
+                }
+                return shift;
+            }
+        }
+
+        // Convert the expression ((a - a % b) / b) into (a / b).
+        if (forX instanceof SubNode) {
+            SubNode integerSubNode = (SubNode) forX;
+            if (integerSubNode.getY() instanceof SignedRemNode) {
+                SignedRemNode integerRemNode = (SignedRemNode) integerSubNode.getY();
+                if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.getX() == integerRemNode.getX() &&
+                                forY == integerRemNode.getY()) {
+                    return new SignedDivNode(integerSubNode.getX(), forY);
+                }
+            }
+        }
+
+        if (next() instanceof SignedDivNode) {
+            NodeClass<?> nodeClass = getNodeClass();
+            if (next().getClass() == this.getClass() && nodeClass.equalInputs(this, next()) && valueEquals(next())) {
+                return next();
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java
new file mode 100644
index 0000000..05196c5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+@NodeInfo(shortName = "%")
+public class SignedRemNode extends IntegerDivRemNode implements LIRLowerable {
+
+    public static final NodeClass<SignedRemNode> TYPE = NodeClass.create(SignedRemNode.class);
+
+    public SignedRemNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected SignedRemNode(NodeClass<? extends SignedRemNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), Op.REM, Type.SIGNED, x, y);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(IntegerStamp.OPS.getRem().foldStamp(getX().stamp(), getY().stamp()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            @SuppressWarnings("hiding")
+            long y = forY.asJavaConstant().asLong();
+            if (y == 0) {
+                return this; // this will trap, can not canonicalize
+            }
+            return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() % y);
+        } else if (forY.isConstant()) {
+            long c = forY.asJavaConstant().asLong();
+            if (c == 1 || c == -1) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
+                return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitRem(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SqrtNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SqrtNode.java
new file mode 100644
index 0000000..51252ae
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SqrtNode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Square root.
+ */
+@NodeInfo(cycles = CYCLES_30, size = SIZE_1)
+public final class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<SqrtNode> TYPE = NodeClass.create(SqrtNode.class);
+
+    public SqrtNode(ValueNode x) {
+        super(TYPE, ArithmeticOpTable::getSqrt, x);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitMathSqrt(nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java
new file mode 100644
index 0000000..a029b00
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(shortName = "-")
+public class SubNode extends BinaryArithmeticNode<Sub> implements NarrowableArithmeticNode {
+
+    public static final NodeClass<SubNode> TYPE = NodeClass.create(SubNode.class);
+
+    public SubNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected SubNode(NodeClass<? extends SubNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getSub, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Sub> op = ArithmeticOpTable.forStamp(x.stamp()).getSub();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new SubNode(x, y);
+        }
+    }
+
+    @SuppressWarnings("hiding")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        BinaryOp<Sub> op = getOp(forX, forY);
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            Constant zero = op.getZero(forX.stamp());
+            if (zero != null) {
+                return ConstantNode.forPrimitive(stamp(), zero);
+            }
+        }
+        boolean associative = op.isAssociative();
+        if (associative) {
+            if (forX instanceof AddNode) {
+                AddNode x = (AddNode) forX;
+                if (x.getY() == forY) {
+                    // (a + b) - b
+                    return x.getX();
+                }
+                if (x.getX() == forY) {
+                    // (a + b) - a
+                    return x.getY();
+                }
+            } else if (forX instanceof SubNode) {
+                SubNode x = (SubNode) forX;
+                if (x.getX() == forY) {
+                    // (a - b) - a
+                    return new NegateNode(x.getY());
+                }
+            }
+            if (forY instanceof AddNode) {
+                AddNode y = (AddNode) forY;
+                if (y.getX() == forX) {
+                    // a - (a + b)
+                    return new NegateNode(y.getY());
+                }
+                if (y.getY() == forX) {
+                    // b - (a + b)
+                    return new NegateNode(y.getX());
+                }
+            } else if (forY instanceof SubNode) {
+                SubNode y = (SubNode) forY;
+                if (y.getX() == forX) {
+                    // a - (a - b)
+                    return y.getY();
+                }
+            }
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (op.isNeutral(c)) {
+                return forX;
+            }
+            if (associative) {
+                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+                if (reassociated != this) {
+                    return reassociated;
+                }
+            }
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long i = ((PrimitiveConstant) c).asLong();
+                if (i < 0 || ((IntegerStamp) StampFactory.forKind(forY.getStackKind())).contains(-i)) {
+                    // Adding a negative is more friendly to the backend since adds are
+                    // commutative, so prefer add when it fits.
+                    return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -i));
+                }
+            }
+        } else if (forX.isConstant()) {
+            Constant c = forX.asConstant();
+            if (ArithmeticOpTable.forStamp(stamp()).getAdd().isNeutral(c)) {
+                /*
+                 * Note that for floating point numbers, + and - have different neutral elements. We
+                 * have to test for the neutral element of +, because we are doing this
+                 * transformation: 0 - x == (-x) + 0 == -x.
+                 */
+                return new NegateNode(forY);
+            }
+            if (associative) {
+                return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            }
+        }
+        if (forY instanceof NegateNode) {
+            return BinaryArithmeticNode.add(forX, ((NegateNode) forY).getValue());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitSub(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), false));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryArithmeticNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryArithmeticNode.java
new file mode 100644
index 0000000..7f3d019
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryArithmeticNode.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ArithmeticOperation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+
+@NodeInfo
+public abstract class UnaryArithmeticNode<OP> extends UnaryNode implements ArithmeticOperation, ArithmeticLIRLowerable {
+
+    @SuppressWarnings("rawtypes") public static final NodeClass<UnaryArithmeticNode> TYPE = NodeClass.create(UnaryArithmeticNode.class);
+
+    protected interface SerializableUnaryFunction<T> extends Function<ArithmeticOpTable, UnaryOp<T>>, Serializable {
+    }
+
+    protected final SerializableUnaryFunction<OP> getOp;
+
+    protected UnaryArithmeticNode(NodeClass<? extends UnaryArithmeticNode<OP>> c, SerializableUnaryFunction<OP> getOp, ValueNode value) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(value.stamp())).foldStamp(value.stamp()), value);
+        this.getOp = getOp;
+    }
+
+    protected final UnaryOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
+    }
+
+    @Override
+    public final UnaryOp<OP> getArithmeticOp() {
+        return getOp(getValue());
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        return getOp(getValue()).foldStamp(newStamp);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode synonym = findSynonym(forValue, getOp(forValue));
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    protected static <OP> ValueNode findSynonym(ValueNode forValue, UnaryOp<OP> op) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forPrimitive(op.foldStamp(forValue.stamp()), op.foldConstant(forValue.asConstant()));
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryNode.java
new file mode 100644
index 0000000..542dfaa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * The {@code UnaryNode} class is the base of arithmetic and bit logic operations with exactly one
+ * input.
+ */
+@NodeInfo(size = SIZE_1)
+public abstract class UnaryNode extends FloatingNode implements Canonicalizable.Unary<ValueNode> {
+
+    public static final NodeClass<UnaryNode> TYPE = NodeClass.create(UnaryNode.class);
+    @Input protected ValueNode value;
+
+    @Override
+    public ValueNode getValue() {
+        return value;
+    }
+
+    /**
+     * Creates a new UnaryNode instance.
+     *
+     * @param stamp the result type of this instruction
+     * @param value the input instruction
+     */
+    protected UnaryNode(NodeClass<? extends UnaryNode> c, Stamp stamp, ValueNode value) {
+        super(c, stamp);
+        this.value = value;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(foldStamp(value.stamp()));
+    }
+
+    /**
+     * Compute an improved for this node using the passed in stamp. The stamp must be compatible
+     * with the current value of {@link #value}. This code is used to provide the default
+     * implementation of {@link #inferStamp()} and may be used by external optimizations.
+     *
+     * @param newStamp
+     */
+    public Stamp foldStamp(Stamp newStamp) {
+        return stamp();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedDivNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedDivNode.java
new file mode 100644
index 0000000..070b344
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedDivNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+@NodeInfo(shortName = "|/|")
+public class UnsignedDivNode extends IntegerDivRemNode implements LIRLowerable {
+
+    public static final NodeClass<UnsignedDivNode> TYPE = NodeClass.create(UnsignedDivNode.class);
+
+    public UnsignedDivNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedDivNode(NodeClass<? extends UnsignedDivNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), Op.DIV, Type.UNSIGNED, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        int bits = ((IntegerStamp) stamp()).getBits();
+        if (forX.isConstant() && forY.isConstant()) {
+            long yConst = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
+            if (yConst == 0) {
+                return this; // this will trap, cannot canonicalize
+            }
+            return ConstantNode.forIntegerStamp(stamp(), Long.divideUnsigned(CodeUtil.zeroExtend(forX.asJavaConstant().asLong(), bits), yConst));
+        } else if (forY.isConstant()) {
+            long c = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
+            if (c == 1) {
+                return forX;
+            }
+            if (CodeUtil.isPowerOf2(c)) {
+                return new UnsignedRightShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(c)));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitUDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
+    }
+
+    @NodeIntrinsic
+    public static native int unsignedDivide(int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedDivide(long a, long b);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRemNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRemNode.java
new file mode 100644
index 0000000..465db44
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRemNode.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+@NodeInfo(shortName = "|%|")
+public class UnsignedRemNode extends IntegerDivRemNode implements LIRLowerable {
+
+    public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
+
+    public UnsignedRemNode(ValueNode x, ValueNode y) {
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), Op.REM, Type.UNSIGNED, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        int bits = ((IntegerStamp) stamp()).getBits();
+        if (forX.isConstant() && forY.isConstant()) {
+            long yConst = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
+            if (yConst == 0) {
+                return this; // this will trap, cannot canonicalize
+            }
+            return ConstantNode.forIntegerStamp(stamp(), Long.remainderUnsigned(CodeUtil.zeroExtend(forX.asJavaConstant().asLong(), bits), yConst));
+        } else if (forY.isConstant()) {
+            long c = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
+            if (c == 1) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (CodeUtil.isPowerOf2(c)) {
+                return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitURem(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
+    }
+
+    @NodeIntrinsic
+    public static native int unsignedRemainder(int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedRemainder(long a, long b);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java
new file mode 100644
index 0000000..7845b05
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(shortName = ">>>")
+public final class UnsignedRightShiftNode extends ShiftNode<UShr> {
+
+    public static final NodeClass<UnsignedRightShiftNode> TYPE = NodeClass.create(UnsignedRightShiftNode.class);
+
+    public UnsignedRightShiftNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getUShr, x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forY.isConstant()) {
+            int amount = forY.asJavaConstant().asInt();
+            int originalAmout = amount;
+            int mask = getShiftAmountMask();
+            amount &= mask;
+            if (amount == 0) {
+                return forX;
+            }
+            if (forX instanceof ShiftNode) {
+                ShiftNode<?> other = (ShiftNode<?>) forX;
+                if (other.getY().isConstant()) {
+                    int otherAmount = other.getY().asJavaConstant().asInt() & mask;
+                    if (other instanceof UnsignedRightShiftNode) {
+                        int total = amount + otherAmount;
+                        if (total != (total & mask)) {
+                            return ConstantNode.forIntegerKind(getStackKind(), 0);
+                        }
+                        return new UnsignedRightShiftNode(other.getX(), ConstantNode.forInt(total));
+                    } else if (other instanceof LeftShiftNode && otherAmount == amount) {
+                        if (getStackKind() == JavaKind.Long) {
+                            return new AndNode(other.getX(), ConstantNode.forLong(-1L >>> amount));
+                        } else {
+                            assert getStackKind() == JavaKind.Int;
+                            return new AndNode(other.getX(), ConstantNode.forInt(-1 >>> amount));
+                        }
+                    }
+                }
+            }
+            if (originalAmout != amount) {
+                return new UnsignedRightShiftNode(forX, ConstantNode.forInt(amount));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitUShr(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+
+    @Override
+    public boolean isNarrowable(int resultBits) {
+        if (super.isNarrowable(resultBits)) {
+            /*
+             * For unsigned right shifts, the narrow can be done before the shift if the cut off
+             * bits are all zero.
+             */
+            IntegerStamp inputStamp = (IntegerStamp) getX().stamp();
+            return (inputStamp.upMask() & ~(resultBits - 1)) == 0;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java
new file mode 100644
index 0000000..1946dbd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+@NodeInfo(shortName = "^")
+public final class XorNode extends BinaryArithmeticNode<Xor> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
+
+    public static final NodeClass<XorNode> TYPE = NodeClass.create(XorNode.class);
+
+    public XorNode(ValueNode x, ValueNode y) {
+        super(TYPE, ArithmeticOpTable::getXor, x, y);
+        assert x.stamp().isCompatible(y.stamp());
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp()).getXor();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new XorNode(x, y).maybeCommuteInputs();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forPrimitive(stamp(), getOp(forX, forY).getZero(forX.stamp()));
+        }
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new XorNode(forY, forX);
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp(forX, forY).isNeutral(c)) {
+                return forX;
+            }
+
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long rawY = ((PrimitiveConstant) c).asLong();
+                long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp()));
+                if ((rawY & mask) == mask) {
+                    return new NotNode(forX);
+                }
+            }
+            return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitXor(nodeValueMap.operand(getX()), nodeValueMap.operand(getY())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java
new file mode 100644
index 0000000..8f1d430
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+
+/**
+ * The {@code ZeroExtendNode} converts an integer to a wider integer using zero extension.
+ */
+@NodeInfo(cycles = CYCLES_1)
+public final class ZeroExtendNode extends IntegerConvertNode<ZeroExtend, Narrow> {
+
+    public static final NodeClass<ZeroExtendNode> TYPE = NodeClass.create(ZeroExtendNode.class);
+
+    public ZeroExtendNode(ValueNode input, int resultBits) {
+        this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+        assert 0 < PrimitiveStamp.getBits(input.stamp()) && PrimitiveStamp.getBits(input.stamp()) <= resultBits;
+    }
+
+    public ZeroExtendNode(ValueNode input, int inputBits, int resultBits) {
+        super(TYPE, ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<ZeroExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getZeroExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new ZeroExtendNode(input, inputBits, resultBits);
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
+    @Override
+    public boolean preservesOrder(Condition cond) {
+        switch (cond) {
+            case GE:
+            case GT:
+            case LE:
+            case LT:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode ret = super.canonical(tool, forValue);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forValue instanceof ZeroExtendNode) {
+            // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx
+            // ==> xxxx -(zero-extend)-> 00000000 0000xxxx
+            ZeroExtendNode other = (ZeroExtendNode) forValue;
+            return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+        }
+        if (forValue instanceof NarrowNode) {
+            NarrowNode narrow = (NarrowNode) forValue;
+            Stamp inputStamp = narrow.getValue().stamp();
+            if (inputStamp instanceof IntegerStamp && inputStamp.isCompatible(stamp())) {
+                IntegerStamp istamp = (IntegerStamp) inputStamp;
+                long mask = CodeUtil.mask(PrimitiveStamp.getBits(narrow.stamp()));
+                if (((istamp.upMask() | istamp.downMask()) & ~mask) == 0) {
+                    // The original value is in the range of the masked zero extended result so
+                    // simply return the original input.
+                    return narrow.getValue();
+                }
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitZeroExtend(nodeValueMap.operand(getValue()), getInputBits(), getResultBits()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java
new file mode 100644
index 0000000..644987f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.cfg;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+public final class Block extends AbstractBlockBase<Block> {
+
+    public static final Block[] EMPTY_ARRAY = new Block[0];
+
+    protected final AbstractBeginNode beginNode;
+
+    protected FixedNode endNode;
+
+    protected double probability;
+    protected Loop<Block> loop;
+
+    protected Block postdominator;
+    protected Block distancedDominatorCache;
+    private LocationSet killLocations;
+    private LocationSet killLocationsBetweenThisAndDominator;
+
+    protected Block(AbstractBeginNode node) {
+        this.beginNode = node;
+    }
+
+    public AbstractBeginNode getBeginNode() {
+        return beginNode;
+    }
+
+    public FixedNode getEndNode() {
+        return endNode;
+    }
+
+    @Override
+    public Loop<Block> getLoop() {
+        return loop;
+    }
+
+    public void setLoop(Loop<Block> loop) {
+        this.loop = loop;
+    }
+
+    @Override
+    public int getLoopDepth() {
+        return loop == null ? 0 : loop.getDepth();
+    }
+
+    @Override
+    public boolean isLoopHeader() {
+        return getBeginNode() instanceof LoopBeginNode;
+    }
+
+    @Override
+    public boolean isLoopEnd() {
+        return getEndNode() instanceof LoopEndNode;
+    }
+
+    @Override
+    public boolean isExceptionEntry() {
+        Node predecessor = getBeginNode().predecessor();
+        return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
+    }
+
+    public Block getFirstPredecessor() {
+        return getPredecessors()[0];
+    }
+
+    public Block getFirstSuccessor() {
+        return getSuccessors()[0];
+    }
+
+    public Block getEarliestPostDominated() {
+        Block b = this;
+        while (true) {
+            Block dom = b.getDominator();
+            if (dom != null && dom.getPostdominator() == b) {
+                b = dom;
+            } else {
+                break;
+            }
+        }
+        return b;
+    }
+
+    @Override
+    public Block getPostdominator() {
+        return postdominator;
+    }
+
+    private class NodeIterator implements Iterator<FixedNode> {
+
+        private FixedNode cur;
+
+        NodeIterator() {
+            cur = getBeginNode();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return cur != null;
+        }
+
+        @Override
+        public FixedNode next() {
+            FixedNode result = cur;
+            if (result instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) result;
+                FixedNode next = fixedWithNextNode.next();
+                if (next instanceof AbstractBeginNode) {
+                    next = null;
+                }
+                cur = next;
+            } else {
+                cur = null;
+            }
+            assert !(cur instanceof AbstractBeginNode);
+            return result;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public Iterable<FixedNode> getNodes() {
+        return new Iterable<FixedNode>() {
+
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new NodeIterator();
+            }
+
+            @Override
+            public String toString() {
+                StringBuilder str = new StringBuilder().append('[');
+                for (FixedNode node : this) {
+                    str.append(node).append(", ");
+                }
+                if (str.length() > 1) {
+                    str.setLength(str.length() - 2);
+                }
+                return str.append(']').toString();
+            }
+        };
+    }
+
+    @Override
+    public String toString() {
+        return "B" + id;
+    }
+
+    @Override
+    public double probability() {
+        return probability;
+    }
+
+    public void setProbability(double probability) {
+        assert probability >= 0 && Double.isFinite(probability);
+        this.probability = probability;
+    }
+
+    @Override
+    public Block getDominator(int distance) {
+        Block result = this;
+        for (int i = 0; i < distance; ++i) {
+            result = result.getDominator();
+        }
+        return result;
+    }
+
+    public boolean canKill(LocationIdentity location) {
+        if (location.isImmutable()) {
+            return false;
+        }
+        return getKillLocations().contains(location);
+    }
+
+    public LocationSet getKillLocations() {
+        if (killLocations == null) {
+            killLocations = calcKillLocations();
+        }
+        return killLocations;
+    }
+
+    private LocationSet calcKillLocations() {
+        LocationSet result = new LocationSet();
+        for (FixedNode node : this.getNodes()) {
+            if (node instanceof MemoryCheckpoint.Single) {
+                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+                result.add(identity);
+            } else if (node instanceof MemoryCheckpoint.Multi) {
+                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                    result.add(identity);
+                }
+            }
+            if (result.isAny()) {
+                break;
+            }
+        }
+        return result;
+    }
+
+    public boolean canKillBetweenThisAndDominator(LocationIdentity location) {
+        if (location.isImmutable()) {
+            return false;
+        }
+        return this.getKillLocationsBetweenThisAndDominator().contains(location);
+    }
+
+    private LocationSet getKillLocationsBetweenThisAndDominator() {
+        if (this.killLocationsBetweenThisAndDominator == null) {
+            LocationSet dominatorResult = new LocationSet();
+            Block stopBlock = getDominator();
+            if (this.isLoopHeader()) {
+                assert stopBlock.getLoopDepth() < this.getLoopDepth();
+                dominatorResult.addAll(((HIRLoop) this.getLoop()).getKillLocations());
+            } else {
+                for (Block b : this.getPredecessors()) {
+                    assert !this.isLoopHeader();
+                    if (b != stopBlock) {
+                        dominatorResult.addAll(b.getKillLocations());
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
+                        b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
+                    }
+                }
+            }
+            this.killLocationsBetweenThisAndDominator = dominatorResult;
+        }
+        return this.killLocationsBetweenThisAndDominator;
+    }
+
+    private void calcKillLocationsBetweenThisAndTarget(LocationSet result, Block stopBlock) {
+        assert AbstractControlFlowGraph.dominates(stopBlock, this);
+        if (stopBlock == this || result.isAny()) {
+            // We reached the stop block => nothing to do.
+            return;
+        } else {
+            if (stopBlock == this.getDominator()) {
+                result.addAll(this.getKillLocationsBetweenThisAndDominator());
+            } else {
+                // Divide and conquer: Aggregate kill locations from this to the dominator and then
+                // from the dominator onwards.
+                calcKillLocationsBetweenThisAndTarget(result, this.getDominator());
+                result.addAll(this.getDominator().getKillLocations());
+                if (result.isAny()) {
+                    return;
+                }
+                this.getDominator().calcKillLocationsBetweenThisAndTarget(result, stopBlock);
+            }
+        }
+    }
+
+    @Override
+    public void delete() {
+
+        // adjust successor and predecessor lists
+        Block next = getSuccessors()[0];
+        for (Block pred : getPredecessors()) {
+            Block[] predSuccs = pred.successors;
+            Block[] newPredSuccs = new Block[predSuccs.length];
+            for (int i = 0; i < predSuccs.length; ++i) {
+                if (predSuccs[i] == this) {
+                    newPredSuccs[i] = next;
+                } else {
+                    newPredSuccs[i] = predSuccs[i];
+                }
+            }
+            pred.setSuccessors(newPredSuccs);
+        }
+
+        ArrayList<Block> newPreds = new ArrayList<>();
+        for (int i = 0; i < next.getPredecessorCount(); i++) {
+            Block curPred = next.getPredecessors()[i];
+            if (curPred == this) {
+                for (Block b : getPredecessors()) {
+                    newPreds.add(b);
+                }
+            } else {
+                newPreds.add(curPred);
+            }
+        }
+
+        next.setPredecessors(newPreds.toArray(new Block[0]));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java
new file mode 100644
index 0000000..cd4ffcc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.cfg;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.CFGVerifier;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+
+public final class ControlFlowGraph implements AbstractControlFlowGraph<Block> {
+    /**
+     * Don't allow probability values to be become too small or too high as this makes frequency
+     * calculations over- or underflow the range of a double. This commonly happens with infinite
+     * loops within infinite loops. The value is chosen a bit lower than half the maximum exponent
+     * supported by double. That way we can never overflow to infinity when multiplying two
+     * probability values.
+     */
+    public static final double MIN_PROBABILITY = 0x1.0p-500;
+    public static final double MAX_PROBABILITY = 1 / MIN_PROBABILITY;
+
+    public final StructuredGraph graph;
+
+    private NodeMap<Block> nodeToBlock;
+    private Block[] reversePostOrder;
+    private List<Loop<Block>> loops;
+
+    public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) {
+        ControlFlowGraph cfg = new ControlFlowGraph(graph);
+        cfg.identifyBlocks();
+        cfg.computeProbabilities();
+
+        if (computeLoops) {
+            cfg.computeLoopInformation();
+        }
+        if (computeDominators) {
+            cfg.computeDominators();
+        }
+        if (computePostdominators) {
+            cfg.computePostdominators();
+        }
+        // there's not much to verify when connectBlocks == false
+        assert !(connectBlocks || computeLoops || computeDominators || computePostdominators) || CFGVerifier.verify(cfg);
+        return cfg;
+    }
+
+    private ControlFlowGraph(StructuredGraph graph) {
+        this.graph = graph;
+        this.nodeToBlock = graph.createNodeMap();
+    }
+
+    private void computeDominators() {
+        assert reversePostOrder[0].getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator";
+        Block[] blocks = reversePostOrder;
+        for (int i = 1; i < blocks.length; i++) {
+            Block block = blocks[i];
+            assert block.getPredecessorCount() > 0;
+            Block dominator = null;
+            for (Block pred : block.getPredecessors()) {
+                if (!pred.isLoopEnd()) {
+                    dominator = ((dominator == null) ? pred : commonDominatorRaw(dominator, pred));
+                }
+            }
+            // set dominator
+            block.setDominator(dominator);
+            if (dominator.getDominated().equals(Collections.emptyList())) {
+                dominator.setDominated(new ArrayList<>());
+            }
+            dominator.getDominated().add(block);
+        }
+        calcDominatorRanges(getStartBlock(), reversePostOrder.length);
+    }
+
+    private static void calcDominatorRanges(Block block, int size) {
+        Block[] stack = new Block[size];
+        stack[0] = block;
+        int tos = 0;
+        int myNumber = 0;
+
+        do {
+            Block cur = stack[tos];
+            List<Block> dominated = cur.getDominated();
+
+            if (cur.getDominatorNumber() == -1) {
+                cur.setDominatorNumber(myNumber);
+                if (dominated.size() > 0) {
+                    // Push children onto stack.
+                    for (Block b : dominated) {
+                        stack[++tos] = b;
+                    }
+                } else {
+                    cur.setMaxChildDomNumber(myNumber);
+                    --tos;
+                }
+                ++myNumber;
+            } else {
+                cur.setMaxChildDomNumber(dominated.get(0).getMaxChildDominatorNumber());
+                --tos;
+            }
+        } while (tos >= 0);
+    }
+
+    private static Block commonDominatorRaw(Block a, Block b) {
+        int aDomDepth = a.getDominatorDepth();
+        int bDomDepth = b.getDominatorDepth();
+        if (aDomDepth > bDomDepth) {
+            return commonDominatorRawSameDepth(a.getDominator(aDomDepth - bDomDepth), b);
+        } else {
+            return commonDominatorRawSameDepth(a, b.getDominator(bDomDepth - aDomDepth));
+        }
+    }
+
+    private static Block commonDominatorRawSameDepth(Block a, Block b) {
+        Block iterA = a;
+        Block iterB = b;
+        while (iterA != iterB) {
+            iterA = iterA.getDominator();
+            iterB = iterB.getDominator();
+        }
+        return iterA;
+    }
+
+    @Override
+    public Block[] getBlocks() {
+        return reversePostOrder;
+    }
+
+    @Override
+    public Block getStartBlock() {
+        return reversePostOrder[0];
+    }
+
+    public Block[] reversePostOrder() {
+        return reversePostOrder;
+    }
+
+    public NodeMap<Block> getNodeToBlock() {
+        return nodeToBlock;
+    }
+
+    public Block blockFor(Node node) {
+        return nodeToBlock.get(node);
+    }
+
+    @Override
+    public List<Loop<Block>> getLoops() {
+        return loops;
+    }
+
+    private void identifyBlock(Block block) {
+        FixedWithNextNode cur = block.getBeginNode();
+        while (true) {
+            assert !cur.isDeleted();
+            assert nodeToBlock.get(cur) == null;
+            nodeToBlock.set(cur, block);
+            FixedNode next = cur.next();
+            if (next instanceof AbstractBeginNode) {
+                block.endNode = cur;
+                return;
+            } else if (next instanceof FixedWithNextNode) {
+                cur = (FixedWithNextNode) next;
+            } else {
+                nodeToBlock.set(next, block);
+                block.endNode = next;
+                return;
+            }
+        }
+    }
+
+    /**
+     * Identify and connect blocks (including loop backward edges). Predecessors need to be in the
+     * order expected when iterating phi inputs.
+     */
+    private void identifyBlocks() {
+        // Find all block headers.
+        int numBlocks = 0;
+        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
+            Block block = new Block(begin);
+            identifyBlock(block);
+            numBlocks++;
+        }
+
+        // Compute reverse post order.
+        int count = 0;
+        NodeMap<Block> nodeMap = this.nodeToBlock;
+        Block[] stack = new Block[numBlocks];
+        int tos = 0;
+        Block startBlock = blockFor(graph.start());
+        stack[0] = startBlock;
+        startBlock.setPredecessors(Block.EMPTY_ARRAY);
+        do {
+            Block block = stack[tos];
+            int id = block.getId();
+            if (id == BLOCK_ID_INITIAL) {
+                // First time we see this block: push all successors.
+                FixedNode last = block.getEndNode();
+                if (last instanceof EndNode) {
+                    EndNode endNode = (EndNode) last;
+                    Block suxBlock = nodeMap.get(endNode.merge());
+                    if (suxBlock.getId() == BLOCK_ID_INITIAL) {
+                        stack[++tos] = suxBlock;
+                    }
+                    block.setSuccessors(new Block[]{suxBlock});
+                } else if (last instanceof IfNode) {
+                    IfNode ifNode = (IfNode) last;
+                    Block trueSucc = nodeMap.get(ifNode.trueSuccessor());
+                    stack[++tos] = trueSucc;
+                    Block falseSucc = nodeMap.get(ifNode.falseSuccessor());
+                    stack[++tos] = falseSucc;
+                    block.setSuccessors(new Block[]{trueSucc, falseSucc});
+                    Block[] ifPred = new Block[]{block};
+                    trueSucc.setPredecessors(ifPred);
+                    falseSucc.setPredecessors(ifPred);
+                } else if (last instanceof LoopEndNode) {
+                    LoopEndNode loopEndNode = (LoopEndNode) last;
+                    block.setSuccessors(new Block[]{nodeMap.get(loopEndNode.loopBegin())});
+                    // Nothing to do push onto the stack.
+                } else {
+                    assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode.";
+                    int startTos = tos;
+                    Block[] ifPred = new Block[]{block};
+                    for (Node suxNode : last.successors()) {
+                        Block sux = nodeMap.get(suxNode);
+                        stack[++tos] = sux;
+                        sux.setPredecessors(ifPred);
+                    }
+                    int suxCount = tos - startTos;
+                    Block[] successors = new Block[suxCount];
+                    System.arraycopy(stack, startTos + 1, successors, 0, suxCount);
+                    block.setSuccessors(successors);
+                }
+                block.setId(BLOCK_ID_VISITED);
+                AbstractBeginNode beginNode = block.getBeginNode();
+                if (beginNode instanceof LoopBeginNode) {
+                    computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode);
+                } else if (beginNode instanceof MergeNode) {
+                    MergeNode mergeNode = (MergeNode) beginNode;
+                    int forwardEndCount = mergeNode.forwardEndCount();
+                    Block[] predecessors = new Block[forwardEndCount];
+                    for (int i = 0; i < forwardEndCount; ++i) {
+                        predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i));
+                    }
+                    block.setPredecessors(predecessors);
+                }
+
+            } else if (id == BLOCK_ID_VISITED) {
+                // Second time we see this block: All successors have been processed, so add block
+                // to result list. Can safely reuse the stack for this.
+                --tos;
+                count++;
+                int index = numBlocks - count;
+                stack[index] = block;
+                block.setId(index);
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        } while (tos >= 0);
+
+        // Compute reverse postorder and number blocks.
+        assert count == numBlocks : "all blocks must be reachable";
+        this.reversePostOrder = stack;
+    }
+
+    private static void computeLoopPredecessors(NodeMap<Block> nodeMap, Block block, LoopBeginNode loopBeginNode) {
+        int forwardEndCount = loopBeginNode.forwardEndCount();
+        LoopEndNode[] loopEnds = loopBeginNode.orderedLoopEnds();
+        Block[] predecessors = new Block[forwardEndCount + loopEnds.length];
+        for (int i = 0; i < forwardEndCount; ++i) {
+            predecessors[i] = nodeMap.get(loopBeginNode.forwardEndAt(i));
+        }
+        for (int i = 0; i < loopEnds.length; ++i) {
+            predecessors[i + forwardEndCount] = nodeMap.get(loopEnds[i]);
+        }
+        block.setPredecessors(predecessors);
+    }
+
+    private void computeProbabilities() {
+
+        for (Block block : reversePostOrder) {
+            Block[] predecessors = block.getPredecessors();
+
+            double probability;
+            if (predecessors.length == 0) {
+                probability = 1D;
+            } else if (predecessors.length == 1) {
+                Block pred = predecessors[0];
+                probability = pred.probability;
+                if (pred.getSuccessorCount() > 1) {
+                    assert pred.getEndNode() instanceof ControlSplitNode;
+                    ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode();
+                    probability *= controlSplit.probability(block.getBeginNode());
+                }
+            } else {
+                probability = predecessors[0].probability;
+                for (int i = 1; i < predecessors.length; ++i) {
+                    probability += predecessors[i].probability;
+                }
+
+                if (block.getBeginNode() instanceof LoopBeginNode) {
+                    LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode();
+                    probability *= loopBegin.loopFrequency();
+                }
+            }
+            if (probability < MIN_PROBABILITY) {
+                block.setProbability(MIN_PROBABILITY);
+            } else if (probability > MAX_PROBABILITY) {
+                block.setProbability(MAX_PROBABILITY);
+            } else {
+                block.setProbability(probability);
+            }
+        }
+
+    }
+
+    private void computeLoopInformation() {
+        loops = new ArrayList<>();
+        if (graph.hasLoops()) {
+            Block[] stack = new Block[this.reversePostOrder.length];
+            for (Block block : reversePostOrder) {
+                AbstractBeginNode beginNode = block.getBeginNode();
+                if (beginNode instanceof LoopBeginNode) {
+                    Loop<Block> loop = new HIRLoop(block.getLoop(), loops.size(), block);
+                    loops.add(loop);
+                    block.loop = loop;
+                    loop.getBlocks().add(block);
+
+                    LoopBeginNode loopBegin = (LoopBeginNode) beginNode;
+                    for (LoopEndNode end : loopBegin.loopEnds()) {
+                        Block endBlock = nodeToBlock.get(end);
+                        computeLoopBlocks(endBlock, loop, stack, true);
+                    }
+
+                    if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) {
+                        for (LoopExitNode exit : loopBegin.loopExits()) {
+                            Block exitBlock = nodeToBlock.get(exit);
+                            assert exitBlock.getPredecessorCount() == 1;
+                            computeLoopBlocks(exitBlock.getFirstPredecessor(), loop, stack, true);
+                            loop.getExits().add(exitBlock);
+                        }
+
+                        // The following loop can add new blocks to the end of the loop's block
+                        // list.
+                        int size = loop.getBlocks().size();
+                        for (int i = 0; i < size; ++i) {
+                            Block b = loop.getBlocks().get(i);
+                            for (Block sux : b.getSuccessors()) {
+                                if (sux.loop != loop) {
+                                    AbstractBeginNode begin = sux.getBeginNode();
+                                    if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
+                                        Debug.log(Debug.VERBOSE_LOG_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux);
+                                        computeLoopBlocks(sux, loop, stack, false);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /*
+         * Compute the loop exit blocks after FSA.
+         */
+        if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) {
+            for (Block b : reversePostOrder) {
+                if (b.getLoop() != null) {
+                    for (Block succ : b.getSuccessors()) {
+                        // if the loop of the succ is a different one (or none)
+                        if (b.getLoop() != succ.getLoop()) {
+                            // and the succ loop is not a child loop of the curr one
+                            if (succ.getLoop() == null) {
+                                // we might exit multiple loops if b.loops is not a loop at depth 0
+                                Loop<Block> curr = b.getLoop();
+                                while (curr != null) {
+                                    curr.getExits().add(succ);
+                                    curr = curr.getParent();
+                                }
+                            } else {
+                                /*
+                                 * succ also has a loop, might be a child loop
+                                 *
+                                 * if it is a child loop we do not exit a loop. if it is a loop
+                                 * different than b.loop and not a child loop it must be a parent
+                                 * loop, thus we exit all loops between b.loop and succ.loop
+                                 *
+                                 * if we exit multiple loops immediately after each other the
+                                 * bytecode parser might generate loop exit nodes after another and
+                                 * the CFG will identify them as separate blocks, we just take the
+                                 * first one and exit all loops at this one
+                                 */
+                                if (succ.getLoop().getParent() != b.getLoop()) {
+                                    assert succ.getLoop().getDepth() < b.getLoop().getDepth();
+                                    // b.loop must not be a transitive parent of succ.loop
+                                    assert !Loop.transitiveParentLoop(succ.getLoop(), b.getLoop());
+                                    Loop<Block> curr = b.getLoop();
+                                    while (curr != null && curr != succ.getLoop()) {
+                                        curr.getExits().add(succ);
+                                        curr = curr.getParent();
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    private static void computeLoopBlocks(Block start, Loop<Block> loop, Block[] stack, boolean usePred) {
+        if (start.loop != loop) {
+            start.loop = loop;
+            stack[0] = start;
+            loop.getBlocks().add(start);
+            int tos = 0;
+            do {
+                Block block = stack[tos--];
+
+                // Add predecessors or successors to the loop.
+                for (Block b : (usePred ? block.getPredecessors() : block.getSuccessors())) {
+                    if (b.loop != loop) {
+                        stack[++tos] = b;
+                        b.loop = loop;
+                        loop.getBlocks().add(b);
+                    }
+                }
+            } while (tos >= 0);
+        }
+    }
+
+    public void computePostdominators() {
+
+        Block[] reversePostOrderTmp = this.reversePostOrder;
+
+        outer: for (int j = reversePostOrderTmp.length - 1; j >= 0; --j) {
+            Block block = reversePostOrderTmp[j];
+            if (block.isLoopEnd()) {
+                // We do not want the loop header registered as the postdominator of the loop end.
+                continue;
+            }
+            if (block.getSuccessorCount() == 0) {
+                // No successors => no postdominator.
+                continue;
+            }
+            Block firstSucc = block.getSuccessors()[0];
+            if (block.getSuccessorCount() == 1) {
+                block.postdominator = firstSucc;
+                continue;
+            }
+            Block postdominator = firstSucc;
+            for (Block sux : block.getSuccessors()) {
+                postdominator = commonPostdominator(postdominator, sux);
+                if (postdominator == null) {
+                    // There is a dead end => no postdominator available.
+                    continue outer;
+                }
+            }
+            assert !Arrays.asList(block.getSuccessors()).contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator;
+            block.postdominator = postdominator;
+        }
+    }
+
+    private static Block commonPostdominator(Block a, Block b) {
+        Block iterA = a;
+        Block iterB = b;
+        while (iterA != iterB) {
+            if (iterA.getId() < iterB.getId()) {
+                iterA = iterA.getPostdominator();
+                if (iterA == null) {
+                    return null;
+                }
+            } else {
+                assert iterB.getId() < iterA.getId();
+                iterB = iterB.getPostdominator();
+                if (iterB == null) {
+                    return null;
+                }
+            }
+        }
+        return iterA;
+    }
+
+    public void setNodeToBlock(NodeMap<Block> nodeMap) {
+        this.nodeToBlock = nodeMap;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java
new file mode 100644
index 0000000..8172dd3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.cfg;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+
+public final class HIRLoop extends Loop<Block> {
+
+    private LocationSet killLocations;
+
+    protected HIRLoop(Loop<Block> parent, int index, Block header) {
+        super(parent, index, header);
+    }
+
+    @Override
+    public long numBackedges() {
+        return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count();
+    }
+
+    public LocationSet getKillLocations() {
+        if (killLocations == null) {
+            killLocations = new LocationSet();
+            for (Block b : this.getBlocks()) {
+                if (b.getLoop() == this) {
+                    killLocations.addAll(b.getKillLocations());
+                    if (killLocations.isAny()) {
+                        break;
+                    }
+                }
+            }
+        }
+        for (Loop<Block> child : this.getChildren()) {
+            if (killLocations.isAny()) {
+                break;
+            }
+            killLocations.addAll(((HIRLoop) child).getKillLocations());
+        }
+        return killLocations;
+    }
+
+    public boolean canKill(LocationIdentity location) {
+        return getKillLocations().contains(location);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " header:" + getHeader().getBeginNode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java
new file mode 100644
index 0000000..2828c29
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.cfg;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+public class LocationSet {
+    private LocationIdentity firstLocation;
+    private List<LocationIdentity> list;
+
+    public LocationSet() {
+        list = null;
+    }
+
+    public LocationSet(LocationSet other) {
+        this.firstLocation = other.firstLocation;
+        if (other.list != null && other.list.size() > 0) {
+            list = new ArrayList<>(other.list);
+        }
+    }
+
+    private void initList() {
+        if (list == null) {
+            list = new ArrayList<>(4);
+        }
+    }
+
+    public boolean isEmpty() {
+        return firstLocation == null;
+    }
+
+    public boolean isAny() {
+        return firstLocation != null && firstLocation.isAny();
+    }
+
+    public void add(LocationIdentity location) {
+        if (this.isAny()) {
+            return;
+        } else if (location.isAny()) {
+            firstLocation = location;
+            list = null;
+        } else if (location.isImmutable()) {
+            return;
+        } else {
+            assert location.isMutable() && location.isSingle();
+            if (firstLocation == null) {
+                firstLocation = location;
+            } else if (location.equals(firstLocation)) {
+                return;
+            } else {
+                initList();
+                for (int i = 0; i < list.size(); ++i) {
+                    LocationIdentity value = list.get(i);
+                    if (location.equals(value)) {
+                        return;
+                    }
+                }
+                list.add(location);
+            }
+        }
+    }
+
+    public void addAll(LocationSet other) {
+        if (other.firstLocation != null) {
+            add(other.firstLocation);
+        }
+        List<LocationIdentity> otherList = other.list;
+        if (otherList != null) {
+            for (LocationIdentity l : otherList) {
+                add(l);
+            }
+        }
+    }
+
+    public boolean contains(LocationIdentity locationIdentity) {
+        assert locationIdentity.isSingle();
+        assert locationIdentity.isMutable();
+        if (LocationIdentity.any().equals(firstLocation)) {
+            return true;
+        }
+        if (locationIdentity.equals(firstLocation)) {
+            return true;
+        }
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                LocationIdentity value = list.get(i);
+                if (locationIdentity.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public List<LocationIdentity> getCopyAsList() {
+        ArrayList<LocationIdentity> result = new ArrayList<>();
+        if (firstLocation != null) {
+            result.add(firstLocation);
+        }
+        if (list != null) {
+            result.addAll(list);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        if (this.isAny()) {
+            return "ANY";
+        } else if (this.isEmpty()) {
+            return "EMPTY";
+        } else {
+            List<LocationIdentity> copyAsList = getCopyAsList();
+            return Arrays.toString(copyAsList.toArray(new LocationIdentity[0]));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BindToRegisterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BindToRegisterNode.java
new file mode 100644
index 0000000..2438be1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BindToRegisterNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class BindToRegisterNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<BindToRegisterNode> TYPE = NodeClass.create(BindToRegisterNode.class);
+    @Input ValueNode value;
+
+    public BindToRegisterNode(ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().append(new StandardOp.BindToRegisterOp(gen.getLIRGeneratorTool().asAllocatable(gen.operand(value))));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BlackholeNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BlackholeNode.java
new file mode 100644
index 0000000..300ac61
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/BlackholeNode.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Node is literally a blackhole", size = SIZE_UNKNOWN)
+public final class BlackholeNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<BlackholeNode> TYPE = NodeClass.create(BlackholeNode.class);
+    @Input ValueNode value;
+
+    public BlackholeNode(ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().emitBlackhole(gen.operand(value));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchorNode.java
new file mode 100644
index 0000000..15eaaca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchorNode.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class ControlFlowAnchorNode extends FixedWithNextNode implements LIRLowerable, ControlFlowAnchored {
+
+    public static final NodeClass<ControlFlowAnchorNode> TYPE = NodeClass.create(ControlFlowAnchorNode.class);
+
+    private static class Unique {
+    }
+
+    protected Unique unique;
+
+    public ControlFlowAnchorNode() {
+        super(TYPE, StampFactory.forVoid());
+        this.unique = new Unique();
+    }
+
+    /**
+     * Used by MacroSubstitution.
+     */
+    public ControlFlowAnchorNode(@SuppressWarnings("unused") Invoke invoke) {
+        this();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // do nothing
+    }
+
+    @Override
+    protected void afterClone(Node other) {
+        assert other.graph() != null && other.graph() != graph() : this + " should never be cloned in the same graph";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchored.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchored.java
new file mode 100644
index 0000000..d2cf7ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/ControlFlowAnchored.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+/**
+ * Marker interface for nodes that prevents control flow optimizations. The node should never be
+ * duplicated.
+ */
+public interface ControlFlowAnchored {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java
new file mode 100644
index 0000000..320a143
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * This node can be used to add a counter to the code that will estimate the dynamic number of calls
+ * by adding an increment to the compiled code. This should of course only be used for
+ * debugging/testing purposes.
+ *
+ * A unique counter will be created for each unique name passed to the constructor. Depending on the
+ * value of withContext, the name of the root method is added to the counter's name.
+ */
+@NodeInfo(size = SIZE_10, cycles = CYCLES_20)
+public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<DynamicCounterNode> TYPE = NodeClass.create(DynamicCounterNode.class);
+    @Input ValueNode increment;
+
+    protected final String name;
+    protected final String group;
+    protected final boolean withContext;
+
+    public DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) {
+        this(TYPE, name, group, increment, withContext);
+    }
+
+    protected DynamicCounterNode(NodeClass<? extends DynamicCounterNode> c, String name, String group, ValueNode increment, boolean withContext) {
+        super(c, StampFactory.forVoid());
+        this.name = name;
+        this.group = group;
+        this.increment = increment;
+        this.withContext = withContext;
+    }
+
+    public ValueNode getIncrement() {
+        return increment;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public boolean isWithContext() {
+        return withContext;
+    }
+
+    public static void addCounterBefore(String group, String name, long increment, boolean withContext, FixedNode position) {
+        StructuredGraph graph = position.graph();
+        graph.addBeforeFixed(position, position.graph().add(new DynamicCounterNode(name, group, ConstantNode.forLong(increment, position.graph()), withContext)));
+    }
+
+    @NodeIntrinsic
+    public static native void counter(@ConstantNodeParameter String name, @ConstantNodeParameter String group, long increment, @ConstantNodeParameter boolean addContext);
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        LIRGeneratorTool lirGen = generator.getLIRGeneratorTool();
+        String nameWithContext;
+        if (isWithContext()) {
+            nameWithContext = getName() + " @ ";
+            if (graph().method() != null) {
+                StackTraceElement stackTraceElement = graph().method().asStackTraceElement(0);
+                if (stackTraceElement != null) {
+                    nameWithContext += " " + stackTraceElement.toString();
+                } else {
+                    nameWithContext += graph().method().format("%h.%n");
+                }
+            }
+            if (graph().name != null) {
+                nameWithContext += " (" + graph().name + ")";
+            }
+
+        } else {
+            nameWithContext = getName();
+        }
+        LIRInstruction counterOp = lirGen.createBenchmarkCounter(nameWithContext, getGroup(), generator.operand(increment));
+        if (counterOp != null) {
+            lirGen.append(counterOp);
+        } else {
+            throw GraalError.unimplemented("Benchmark counters not enabled or not implemented by the back end.");
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java
new file mode 100644
index 0000000..62b564f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class OpaqueNode extends FloatingNode implements LIRLowerable {
+
+    public static final NodeClass<OpaqueNode> TYPE = NodeClass.create(OpaqueNode.class);
+    @Input protected ValueNode value;
+
+    public OpaqueNode(ValueNode value) {
+        super(TYPE, value.stamp().unrestricted());
+        this.value = value;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.setResult(this, gen.operand(value));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SpillRegistersNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SpillRegistersNode.java
new file mode 100644
index 0000000..e12214c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SpillRegistersNode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(cycles = CYCLES_2, size = SIZE_0)
+public final class SpillRegistersNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<SpillRegistersNode> TYPE = NodeClass.create(SpillRegistersNode.class);
+
+    protected Object unique;
+
+    public SpillRegistersNode() {
+        super(TYPE, StampFactory.forVoid());
+        // prevent control-flow optimization
+        this.unique = new Object();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.getLIRGeneratorTool().append(new StandardOp.SpillRegistersOp());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java
new file mode 100644
index 0000000..67b5efd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code StringToBytesNode} transforms a compilation-time String into a byte array in the
+ * compiled code.
+ */
+@NodeInfo(allowedUsageTypes = InputType.Memory, cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public final class StringToBytesNode extends FixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<StringToBytesNode> TYPE = NodeClass.create(StringToBytesNode.class);
+
+    private final String value;
+
+    public StringToBytesNode(String value, Stamp stamp) {
+        super(TYPE, stamp);
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return NamedLocationIdentity.getArrayLocation(JavaKind.Byte);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/VerifyHeapNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/VerifyHeapNode.java
new file mode 100644
index 0000000..a5888d6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/VerifyHeapNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+/**
+ * A node for platform dependent verification of the Java heap. Intended to be used for debugging
+ * heap corruption issues.
+ */
+@NodeInfo(cycles = CYCLES_30, size = SIZE_50)
+public final class VerifyHeapNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<VerifyHeapNode> TYPE = NodeClass.create(VerifyHeapNode.class);
+
+    public VerifyHeapNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public static void addBefore(FixedNode position) {
+        StructuredGraph graph = position.graph();
+        graph.addBeforeFixed(position, graph.add(new VerifyHeapNode()));
+    }
+
+    public static void addAfter(FixedWithNextNode position) {
+        StructuredGraph graph = position.graph();
+        graph.addAfterFixed(position, graph.add(new VerifyHeapNode()));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/WeakCounterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/WeakCounterNode.java
new file mode 100644
index 0000000..866925c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/WeakCounterNode.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * This is a special version of the dynamic counter node that removes itself as soon as it's the
+ * only usage of the associated node. This way it only increments the counter if the node is
+ * actually executed.
+ */
+@NodeInfo
+public final class WeakCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable {
+
+    public static final NodeClass<WeakCounterNode> TYPE = NodeClass.create(WeakCounterNode.class);
+    @Input ValueNode checkedValue;
+
+    public WeakCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) {
+        super(TYPE, group, name, increment, addContext);
+        this.checkedValue = checkedValue;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (checkedValue instanceof FloatingNode && checkedValue.getUsageCount() == 1) {
+            tool.addToWorkList(checkedValue);
+            graph().removeFixed(this);
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(checkedValue);
+        if (alias instanceof VirtualObjectNode) {
+            tool.delete();
+        }
+    }
+
+    public static void addCounterBefore(String group, String name, long increment, boolean addContext, ValueNode checkedValue, FixedNode position) {
+        StructuredGraph graph = position.graph();
+        WeakCounterNode counter = graph.add(new WeakCounterNode(name, group, ConstantNode.forLong(increment, graph), addContext, checkedValue));
+        graph.addBeforeFixed(position, counter);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationBeginNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationBeginNode.java
new file mode 100644
index 0000000..9accb66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationBeginNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code InstrumentationBeginNode} represents the boundary of the instrumentation. It also
+ * maintains the target of the instrumentation.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public final class InstrumentationBeginNode extends AbstractStateSplit implements LIRLowerable {
+
+    public static final NodeClass<InstrumentationBeginNode> TYPE = NodeClass.create(InstrumentationBeginNode.class);
+
+    @OptionalInput(value = InputType.Unchecked) protected ValueNode target;
+    private final boolean anchored;
+
+    public InstrumentationBeginNode(boolean anchored) {
+        super(TYPE, StampFactory.forVoid());
+        this.anchored = anchored;
+        this.target = null;
+
+    }
+
+    public boolean isAnchored() {
+        return anchored;
+    }
+
+    public ValueNode getTarget() {
+        return target;
+    }
+
+    public void setTarget(ValueNode target) {
+        updateUsages(this.target, target);
+        this.target = target;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // do nothing
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationEndNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationEndNode.java
new file mode 100644
index 0000000..d98e144
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationEndNode.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * The {@code InstrumentationEndNode} represents the boundary of the instrumentation.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public final class InstrumentationEndNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<InstrumentationEndNode> TYPE = NodeClass.create(InstrumentationEndNode.class);
+
+    public InstrumentationEndNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // do nothing
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationInliningCallback.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationInliningCallback.java
new file mode 100644
index 0000000..8964954
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationInliningCallback.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+/**
+ * Nodes implementing {@code InstrumentationInliningCallback} will be notify of the
+ * preInlineInstrumentation event and the postInlineInstrumentation event upon inlining
+ * instrumentation.
+ */
+public interface InstrumentationInliningCallback {
+
+    void preInlineInstrumentation(InstrumentationNode instrumentation);
+
+    void postInlineInstrumentation(InstrumentationNode instrumentation);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationNode.java
new file mode 100644
index 0000000..5f30f33
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/InstrumentationNode.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.AccessMonitorNode;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * The {@code InstrumentationNode} is a place holder of the instrumentation in the original graph.
+ * It is generated at the ExtractInstrumentationPhase and substituted at the
+ * InlineInstrumentationPhase. It maintains an instrumentation graph which contains the
+ * instrumentation nodes in the original graph (between InstrumentationBeginNode and
+ * InstrumentationEndNode). Any data dependency of the instrumentation nodes will be transformed
+ * into an input to the InstrumentationNode.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public class InstrumentationNode extends DeoptimizingFixedWithNextNode implements VirtualizableAllocation {
+
+    public static final NodeClass<InstrumentationNode> TYPE = NodeClass.create(InstrumentationNode.class);
+
+    @OptionalInput(value = InputType.Unchecked) protected ValueNode target;
+    @OptionalInput protected NodeInputList<ValueNode> weakDependencies;
+
+    protected StructuredGraph instrumentationGraph;
+    protected final boolean anchored;
+
+    public InstrumentationNode(ValueNode target, boolean anchored) {
+        this(target, anchored, 0, null);
+    }
+
+    private InstrumentationNode(ValueNode target, boolean anchored, int initialDependencySize, FrameState stateBefore) {
+        super(TYPE, StampFactory.forVoid(), stateBefore);
+
+        this.target = target;
+        this.anchored = anchored;
+        this.weakDependencies = new NodeInputList<>(this, initialDependencySize);
+    }
+
+    public ValueNode getTarget() {
+        return target;
+    }
+
+    public boolean isAnchored() {
+        return anchored;
+    }
+
+    public StructuredGraph getInstrumentationGraph() {
+        return instrumentationGraph;
+    }
+
+    public void setInstrumentationGraph(StructuredGraph graph) {
+        this.instrumentationGraph = graph;
+    }
+
+    public void addWeakDependency(ValueNode input) {
+        weakDependencies.add(input);
+    }
+
+    public ValueNode getWeakDependency(int index) {
+        return weakDependencies.get(index);
+    }
+
+    public NodeInputList<ValueNode> getWeakDependencies() {
+        return weakDependencies;
+    }
+
+    /**
+     * Clone the InstrumentationNode with the given new target. The weakDependencies will be
+     * initialized with aliased nodes.
+     */
+    private InstrumentationNode cloneWithNewTarget(ValueNode newTarget, VirtualizerTool tool) {
+        InstrumentationNode clone = new InstrumentationNode(newTarget, anchored, weakDependencies.size(), stateBefore);
+        clone.instrumentationGraph = instrumentationGraph;
+        for (int i = 0; i < weakDependencies.size(); i++) {
+            ValueNode input = weakDependencies.get(i);
+            if (!(input instanceof VirtualObjectNode)) {
+                ValueNode alias = tool.getAlias(input);
+                if (alias instanceof VirtualObjectNode) {
+                    clone.weakDependencies.initialize(i, alias);
+                    continue;
+                }
+            }
+            clone.weakDependencies.initialize(i, input);
+        }
+        return clone;
+    }
+
+    private boolean hasAliasedWeakDependency(VirtualizerTool tool) {
+        for (ValueNode input : weakDependencies) {
+            if (!(input instanceof VirtualObjectNode)) {
+                ValueNode alias = tool.getAlias(input);
+                if (alias instanceof VirtualObjectNode) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        // InstrumentationNode allows non-materialized inputs. During the inlining of the
+        // InstrumentationNode, non-materialized inputs will be replaced by null. The current
+        // InstrumentationNode is replaced with a clone InstrumentationNode, such that the escape
+        // analysis won't materialize non-materialized inputs at this point.
+        InstrumentationNode replacee = null;
+        if (target != null) {
+            if (target instanceof AccessMonitorNode) {
+                AccessMonitorNode monitor = (AccessMonitorNode) target;
+                ValueNode alias = tool.getAlias(monitor.object());
+                if (alias instanceof VirtualObjectNode) {
+                    MonitorProxyNode proxy = new MonitorProxyNode(null, monitor.getMonitorId());
+                    tool.addNode(proxy);
+                    replacee = cloneWithNewTarget(proxy, tool);
+                }
+            } else if (!(target instanceof VirtualObjectNode)) {
+                ValueNode alias = tool.getAlias(target);
+                if (alias instanceof VirtualObjectNode) {
+                    replacee = cloneWithNewTarget(alias, tool);
+                }
+            }
+        }
+        if (replacee == null && hasAliasedWeakDependency(tool)) {
+            replacee = cloneWithNewTarget(target, tool);
+        }
+        // in case of modification, we replace with the clone
+        if (replacee != null) {
+            tool.addNode(replacee);
+            tool.replaceWithValue(replacee);
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/IsMethodInlinedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/IsMethodInlinedNode.java
new file mode 100644
index 0000000..0e9771e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/IsMethodInlinedNode.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code IsMethodInlinedNode} represents a boolean value indicating whether it is inlined into
+ * the current graph. There are two clues for the decision: first, the parsing depth, which is a
+ * contextual information during bytecode parsing; second, the original graph upon cloning, which
+ * can detect the inlining when comparing to the current graph.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public final class IsMethodInlinedNode extends FixedWithNextNode implements Lowerable, InstrumentationInliningCallback {
+
+    public static final NodeClass<IsMethodInlinedNode> TYPE = NodeClass.create(IsMethodInlinedNode.class);
+
+    protected StructuredGraph originalGraph;
+    protected int parsingDepth;
+
+    public IsMethodInlinedNode(int depth) {
+        super(TYPE, StampFactory.forKind(JavaKind.Boolean));
+        this.parsingDepth = depth;
+    }
+
+    @Override
+    protected void afterClone(Node other) {
+        if (other instanceof IsMethodInlinedNode) {
+            // keep track of the original graph
+            IsMethodInlinedNode that = (IsMethodInlinedNode) other;
+            this.originalGraph = that.originalGraph == null ? that.graph() : that.originalGraph;
+        }
+    }
+
+    private void resolve(StructuredGraph target) {
+        // if parsingDepth is greater than 0, then inlined
+        // if the original graph is null, which means this node is never cloned, then not inlined
+        // if the original graph does not match the current graph, then inlined
+        replaceAtUsages(ConstantNode.forBoolean(parsingDepth > 0 || (originalGraph != null && originalGraph != target), graph()));
+        graph().removeFixed(this);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        resolve(graph());
+    }
+
+    @Override
+    public void preInlineInstrumentation(InstrumentationNode instrumentation) {
+        // This node will be further merged back to instrumentation.graph(). We care about if this
+        // node originates from instrumentation.graph().
+        resolve(instrumentation.graph());
+    }
+
+    @Override
+    public void postInlineInstrumentation(InstrumentationNode instrumentation) {
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/MonitorProxyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/MonitorProxyNode.java
new file mode 100644
index 0000000..e6d5355
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/MonitorProxyNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+
+/**
+ * The {@code MonitorProxyNode} represents the InstrumentationNode's target when the original
+ * MonitorEnterNode is invalid. Such situation occurs when the escape analysis removes the
+ * MonitorEnterNode and aggregates the monitor logic in a CommitAllocationNode.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public class MonitorProxyNode extends FloatingNode {
+
+    public static final NodeClass<MonitorProxyNode> TYPE = NodeClass.create(MonitorProxyNode.class);
+
+    @OptionalInput(value = InputType.Unchecked) protected ValueNode object;
+    @OptionalInput(value = InputType.Association) protected MonitorIdNode monitorId;
+
+    public MonitorProxyNode(ValueNode object, MonitorIdNode monitorId) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.monitorId = monitorId;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public MonitorIdNode getMonitorId() {
+        return monitorId;
+    }
+
+    /**
+     * @return the first RawMonitorEnterNode that shares the same MonitorIdNode and the same lock
+     *         object with this MonitorProxyNode.
+     */
+    public RawMonitorEnterNode findFirstMatch() {
+        for (RawMonitorEnterNode monitorEnter : monitorId.usages().filter(RawMonitorEnterNode.class)) {
+            if (monitorEnter.object() == object) {
+                return monitorEnter;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/RootNameNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/RootNameNode.java
new file mode 100644
index 0000000..482d9b9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/instrumentation/RootNameNode.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.debug.instrumentation;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.debug.StringToBytesNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * The {@code RootNameNode} represents the name of the compilation root.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public final class RootNameNode extends FixedWithNextNode implements Lowerable, InstrumentationInliningCallback, MemoryCheckpoint.Single {
+
+    public static final NodeClass<RootNameNode> TYPE = NodeClass.create(RootNameNode.class);
+
+    public RootNameNode(Stamp stamp) {
+        super(TYPE, stamp);
+    }
+
+    /**
+     * resolve this node and replace with a {@link StringToBytesNode} that constructs the root
+     * method name in the compiled code. To ensure the correct result, this method should be invoked
+     * after inlining.
+     */
+    private void resolve(StructuredGraph graph) {
+        ResolvedJavaMethod method = graph.method();
+        String rootName = method == null ? "<unresolved method>" : (method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor());
+        StringToBytesNode stringToByteNode = graph().add(new StringToBytesNode(rootName, stamp()));
+        graph().replaceFixedWithFixed(this, stringToByteNode);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        resolve(graph());
+    }
+
+    @Override
+    public void preInlineInstrumentation(InstrumentationNode instrumentation) {
+        // resolve to the method name of the original graph
+        resolve(instrumentation.graph());
+    }
+
+    @Override
+    public void postInlineInstrumentation(InstrumentationNode instrumentation) {
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return NamedLocationIdentity.getArrayLocation(JavaKind.Byte);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/AnchoringNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/AnchoringNode.java
new file mode 100644
index 0000000..80eee2b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/AnchoringNode.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+public interface AnchoringNode extends ValueNodeInterface {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java
new file mode 100644
index 0000000..c64a619
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+
+/**
+ * Base class for nodes that modify a range of an array.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint {
+
+    public static final NodeClass<ArrayRangeWriteNode> TYPE = NodeClass.create(ArrayRangeWriteNode.class);
+
+    protected ArrayRangeWriteNode(NodeClass<? extends ArrayRangeWriteNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    /**
+     * The array that is written to.
+     */
+    public abstract ValueNode getArray();
+
+    /**
+     * The first modified index.
+     */
+    public abstract ValueNode getIndex();
+
+    /**
+     * The length of the modified range.
+     */
+    public abstract ValueNode getLength();
+
+    /**
+     * Return true if the written array is an object array, false if it is a primitive array.
+     */
+    public abstract boolean isObjectArray();
+
+    /**
+     * Returns whether this write is the initialization of the written location. If it is true, the
+     * old value of the memory location is either uninitialized or zero. If it is false, the memory
+     * location is guaranteed to contain a valid value or zero.
+     */
+    public abstract boolean isInitialization();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java
new file mode 100644
index 0000000..1a83889
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
+ * methods in Integer, Long, etc.
+ */
+@NodeInfo(cycles = CYCLES_100, size = SIZE_50)
+public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Canonicalizable.Unary<ValueNode> {
+
+    public static final NodeClass<BoxNode> TYPE = NodeClass.create(BoxNode.class);
+    @Input private ValueNode value;
+    protected final JavaKind boxingKind;
+
+    public BoxNode(ValueNode value, ResolvedJavaType resultType, JavaKind boxingKind) {
+        this(TYPE, value, resultType, boxingKind);
+    }
+
+    public BoxNode(NodeClass<? extends BoxNode> c, ValueNode value, ResolvedJavaType resultType, JavaKind boxingKind) {
+        super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(resultType)));
+        this.value = value;
+        this.boxingKind = boxingKind;
+    }
+
+    public JavaKind getBoxingKind() {
+        return boxingKind;
+    }
+
+    @Override
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        }
+        return this;
+    }
+
+    protected VirtualBoxingNode createVirtualBoxingNode() {
+        return new VirtualBoxingNode(StampTool.typeOrNull(stamp()), boxingKind);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getValue());
+
+        VirtualBoxingNode newVirtual = createVirtualBoxingNode();
+        assert newVirtual.getFields().length == 1;
+
+        tool.createVirtualObject(newVirtual, new ValueNode[]{alias}, Collections.<MonitorIdNode> emptyList(), false);
+        tool.replaceWithVirtual(newVirtual);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java
new file mode 100644
index 0000000..b251526
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodePredicates;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+/**
+ * Instances of this node class will look for a preceding if node and put the given probability into
+ * the if node's taken probability. Then the branch probability node will be removed. This node is
+ * intended primarily for snippets, so that they can define their fast and slow paths.
+ */
+@NodeInfo(cycles = CYCLES_0, cyclesRationale = "Artificial Node", size = SIZE_0)
+public final class BranchProbabilityNode extends FloatingNode implements Simplifiable, Lowerable {
+
+    public static final NodeClass<BranchProbabilityNode> TYPE = NodeClass.create(BranchProbabilityNode.class);
+    public static final double LIKELY_PROBABILITY = 0.6;
+    public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY;
+
+    public static final double FREQUENT_PROBABILITY = 0.9;
+    public static final double NOT_FREQUENT_PROBABILITY = 1 - FREQUENT_PROBABILITY;
+
+    public static final double FAST_PATH_PROBABILITY = 0.99;
+    public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY;
+
+    public static final double VERY_FAST_PATH_PROBABILITY = 0.999;
+    public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_PATH_PROBABILITY;
+
+    @Input ValueNode probability;
+    @Input ValueNode condition;
+
+    public BranchProbabilityNode(ValueNode probability, ValueNode condition) {
+        super(TYPE, condition.stamp());
+        this.probability = probability;
+        this.condition = condition;
+    }
+
+    public ValueNode getProbability() {
+        return probability;
+    }
+
+    public ValueNode getCondition() {
+        return condition;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (probability.isConstant()) {
+            double probabilityValue = probability.asJavaConstant().asDouble();
+            if (probabilityValue < 0.0) {
+                throw new GraalError("A negative probability of " + probabilityValue + " is not allowed!");
+            } else if (probabilityValue > 1.0) {
+                throw new GraalError("A probability of more than 1.0 (" + probabilityValue + ") is not allowed!");
+            } else if (Double.isNaN(probabilityValue)) {
+                /*
+                 * We allow NaN if the node is in unreachable code that will eventually fall away,
+                 * or else an error will be thrown during lowering since we keep the node around.
+                 */
+                return;
+            }
+            boolean usageFound = false;
+            for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) {
+                if (node.condition() == Condition.EQ) {
+                    ValueNode other = node.getX();
+                    if (node.getX() == this) {
+                        other = node.getY();
+                    }
+                    if (other.isConstant()) {
+                        double probabilityToSet = probabilityValue;
+                        if (other.asJavaConstant().asInt() == 0) {
+                            probabilityToSet = 1.0 - probabilityToSet;
+                        }
+                        for (IfNode ifNodeUsages : node.usages().filter(IfNode.class)) {
+                            usageFound = true;
+                            ifNodeUsages.setTrueSuccessorProbability(probabilityToSet);
+                        }
+                        if (!usageFound) {
+                            usageFound = node.usages().filter(NodePredicates.isA(FixedGuardNode.class).or(ConditionalNode.class)).isNotEmpty();
+                        }
+                    }
+                }
+            }
+            if (usageFound) {
+                ValueNode currentCondition = condition;
+                replaceAndDelete(currentCondition);
+                if (tool != null) {
+                    tool.addToWorkList(currentCondition.usages());
+                }
+            } else {
+                if (!isSubstitutionGraph()) {
+                    throw new GraalError("Wrong usage of branch probability injection!");
+                }
+            }
+        }
+    }
+
+    private boolean isSubstitutionGraph() {
+        return getUsageCount() == 1 && usages().first() instanceof ReturnNode;
+    }
+
+    /**
+     * This intrinsic should only be used for the condition of an if statement. The parameter
+     * condition should also only denote a simple condition and not a combined condition involving
+     * &amp;&amp; or || operators. It injects the probability of the condition into the if
+     * statement.
+     *
+     * @param probability the probability that the given condition is true as a double value between
+     *            0.0 and 1.0.
+     * @param condition the simple condition without any &amp;&amp; or || operators
+     * @return the condition
+     */
+    @NodeIntrinsic
+    public static native boolean probability(double probability, boolean condition);
+
+    @Override
+    public void lower(LoweringTool tool) {
+        throw new GraalError("Branch probability could not be injected, because the probability value did not reduce to a constant value.");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java
new file mode 100644
index 0000000..86b6808
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * A node that represents an exception thrown implicitly by a Java bytecode. It can be lowered to
+ * either a {@linkplain ForeignCallDescriptor foreign} call or a pre-allocated exception object.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "Node will be lowered to a foreign call.",
+          size = SIZE_20)
+// @formatter:on
+public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<BytecodeExceptionNode> TYPE = NodeClass.create(BytecodeExceptionNode.class);
+    protected final Class<? extends Throwable> exceptionClass;
+    @Input NodeInputList<ValueNode> arguments;
+
+    public BytecodeExceptionNode(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
+        super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(exceptionClass))));
+        this.exceptionClass = exceptionClass;
+        this.arguments = new NodeInputList<>(this, arguments);
+    }
+
+    public Class<? extends Throwable> getExceptionClass() {
+        return exceptionClass;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + exceptionClass.getSimpleName();
+        }
+        return super.toString(verbosity);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public NodeInputList<ValueNode> getArguments() {
+        return arguments;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java
new file mode 100644
index 0000000..32792a6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/FixedValueAnchorNode.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy {
+    public static final NodeClass<FixedValueAnchorNode> TYPE = NodeClass.create(FixedValueAnchorNode.class);
+
+    @Input ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public FixedValueAnchorNode(ValueNode object) {
+        super(TYPE, object.stamp());
+        this.object = object;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(object.stamp());
+    }
+
+    @NodeIntrinsic
+    public static native Object getObject(Object object);
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.setResult(this, generator.operand(object));
+    }
+
+    @Override
+    public ValueNode getOriginalNode() {
+        return object;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java
new file mode 100644
index 0000000..374ab62
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Node for a {@linkplain ForeignCallDescriptor foreign} call.
+ */
+// @formatter:off
+@NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}",
+          allowedUsageTypes = Memory,
+          cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "A foreign call is a block box in terms of time spent in the callee.",
+          size = SIZE_20)
+// @formatter:on
+public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi {
+    public static final NodeClass<ForeignCallNode> TYPE = NodeClass.create(ForeignCallNode.class);
+
+    @Input protected NodeInputList<ValueNode> arguments;
+    @OptionalInput(State) protected FrameState stateDuring;
+    protected final ForeignCallsProvider foreignCalls;
+
+    protected final ForeignCallDescriptor descriptor;
+    protected int bci = BytecodeFrame.UNKNOWN_BCI;
+
+    public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod targetMethod, @InjectedNodeParameter Stamp returnStamp, @InjectedNodeParameter ForeignCallsProvider foreignCalls,
+                    ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        ForeignCallNode node = new ForeignCallNode(foreignCalls, descriptor, arguments);
+        node.setStamp(returnStamp);
+
+        assert verifyDescriptor(b, targetMethod, descriptor);
+
+        /*
+         * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the case
+         * that the foreign call can deoptimize. As with all deoptimization, we need a state in a
+         * non-intrinsic method.
+         */
+        GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
+        if (nonIntrinsicAncestor != null) {
+            node.setBci(nonIntrinsicAncestor.bci());
+        }
+
+        JavaKind returnKind = targetMethod.getSignature().getReturnKind();
+        if (returnKind == JavaKind.Void) {
+            b.add(node);
+        } else {
+            b.addPush(returnKind, node);
+        }
+
+        return true;
+    }
+
+    static boolean verifyDescriptor(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ForeignCallDescriptor descriptor) {
+        int parameters = 1;
+        for (Class<?> arg : descriptor.getArgumentTypes()) {
+            ResolvedJavaType res = b.getMetaAccess().lookupJavaType(arg);
+            ResolvedJavaType parameterType = (ResolvedJavaType) targetMethod.getSignature().getParameterType(parameters, targetMethod.getDeclaringClass());
+            assert parameterType.equals(res) : descriptor + ": parameter " + parameters + " mismatch: " + res + " != " + parameterType;
+            parameters++;
+        }
+        return true;
+    }
+
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        this(TYPE, foreignCalls, descriptor, arguments);
+    }
+
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
+        super(TYPE, stamp);
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+        this.foreignCalls = foreignCalls;
+        assert descriptor.getArgumentTypes().length == this.arguments.size() : "wrong number of arguments to " + this;
+    }
+
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+        super(TYPE, stamp);
+        this.arguments = new NodeInputList<>(this);
+        this.descriptor = descriptor;
+        this.foreignCalls = foreignCalls;
+    }
+
+    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(c, StampFactory.forKind(JavaKind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+        this.foreignCalls = foreignCalls;
+        assert descriptor.getArgumentTypes().length == this.arguments.size() : "wrong number of arguments to " + this;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return !foreignCalls.isReexecutable(descriptor);
+    }
+
+    public ForeignCallDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return foreignCalls.getKilledLocations(descriptor);
+    }
+
+    protected Value[] operands(NodeLIRBuilderTool gen) {
+        Value[] operands = new Value[arguments.size()];
+        for (int i = 0; i < operands.length; i++) {
+            operands[i] = gen.operand(arguments.get(i));
+        }
+        return operands;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
+        Value[] operands = operands(gen);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), operands);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert hasSideEffect() || x == null;
+        super.setStateAfter(x);
+    }
+
+    @Override
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    @Override
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    public int getBci() {
+        return bci;
+    }
+
+    /**
+     * Set the {@code bci} of the invoke bytecode for use when converting a stateAfter into a
+     * stateDuring.
+     */
+    public void setBci(int bci) {
+        assert this.bci == BytecodeFrame.UNKNOWN_BCI || this.bci == bci;
+        this.bci = bci;
+    }
+
+    @Override
+    public void computeStateDuring(FrameState currentStateAfter) {
+        FrameState newStateDuring;
+        if ((currentStateAfter.stackSize() > 0 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 1) == this) ||
+                        (currentStateAfter.stackSize() > 1 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 2) == this)) {
+            // The result of this call is on the top of stack, so roll back to the previous bci.
+            assert bci != BytecodeFrame.UNKNOWN_BCI : this;
+            newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, this.getStackKind());
+        } else {
+            newStateDuring = currentStateAfter;
+        }
+        setStateDuring(newStateDuring);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + descriptor;
+        }
+        return super.toString(verbosity);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return foreignCalls.canDeoptimize(descriptor);
+    }
+
+    public boolean isGuaranteedSafepoint() {
+        return foreignCalls.isGuaranteedSafepoint(descriptor);
+    }
+
+    public NodeInputList<ValueNode> getArguments() {
+        return arguments;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java
new file mode 100644
index 0000000..15f7393
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Loads an object's class (i.e., this node can be created for {@code object.getClass()}).
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class GetClassNode extends FloatingNode implements Lowerable, Canonicalizable, Virtualizable {
+
+    public static final NodeClass<GetClassNode> TYPE = NodeClass.create(GetClassNode.class);
+    @Input ValueNode object;
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public GetClassNode(Stamp stamp, ValueNode object) {
+        super(TYPE, stamp);
+        this.object = object;
+        assert ((ObjectStamp) object.stamp()).nonNull();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public static ValueNode tryFold(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode object) {
+        if (metaAccess != null && object != null && object.stamp() instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+            if (objectStamp.isExactType()) {
+                return ConstantNode.forConstant(constantReflection.asJavaClass(objectStamp.type()), metaAccess);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        ValueNode folded = tryFold(tool.getMetaAccess(), tool.getConstantReflection(), getObject());
+        return folded == null ? this : folded;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getObject());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            Constant javaClass = tool.getConstantReflectionProvider().asJavaClass(virtual.type());
+            tool.replaceWithValue(ConstantNode.forConstant(stamp(), javaClass, tool.getMetaAccessProvider(), graph()));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedNode.java
new file mode 100644
index 0000000..e24881e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedNode.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+/**
+ * A node that may be guarded by a {@linkplain GuardingNode guarding node}.
+ */
+public interface GuardedNode extends ValueNodeInterface {
+
+    GuardingNode getGuard();
+
+    void setGuard(GuardingNode guard);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java
new file mode 100644
index 0000000..0a18e69
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo
+public class GuardedUnsafeLoadNode extends UnsafeLoadNode implements GuardedNode {
+    public static final NodeClass<GuardedUnsafeLoadNode> TYPE = NodeClass.create(GuardedUnsafeLoadNode.class);
+
+    @OptionalInput(Guard) protected GuardingNode guard;
+
+    public GuardedUnsafeLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity, GuardingNode guard) {
+        super(TYPE, object, offset, accessKind, locationIdentity);
+        this.guard = guard;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardingNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardingNode.java
new file mode 100644
index 0000000..2086728
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardingNode.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+public interface GuardingNode extends ValueNodeInterface {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java
new file mode 100644
index 0000000..15ac8b5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code IntegerSwitchNode} represents a switch on integer keys, with a sorted array of key
+ * values. The actual implementation of the switch will be decided by the backend.
+ */
+@NodeInfo
+public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+    public static final NodeClass<IntegerSwitchNode> TYPE = NodeClass.create(IntegerSwitchNode.class);
+
+    protected final int[] keys;
+
+    public IntegerSwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+        super(TYPE, value, successors, keySuccessors, keyProbabilities);
+        assert keySuccessors.length == keys.length + 1;
+        assert keySuccessors.length == keyProbabilities.length;
+        this.keys = keys;
+        assert value.stamp() instanceof PrimitiveStamp && value.stamp().getStackKind().isNumericInteger();
+        assert assertSorted();
+    }
+
+    private boolean assertSorted() {
+        for (int i = 1; i < keys.length; i++) {
+            assert keys[i - 1] < keys[i];
+        }
+        return true;
+    }
+
+    public IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+        this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors);
+    }
+
+    @Override
+    public boolean isSorted() {
+        return true;
+    }
+
+    /**
+     * Gets the key at the specified index.
+     *
+     * @param i the index
+     * @return the key at that index
+     */
+    @Override
+    public JavaConstant keyAt(int i) {
+        return JavaConstant.forInt(keys[i]);
+    }
+
+    @Override
+    public int keyCount() {
+        return keys.length;
+    }
+
+    @Override
+    public boolean equalKeys(SwitchNode switchNode) {
+        if (!(switchNode instanceof IntegerSwitchNode)) {
+            return false;
+        }
+        IntegerSwitchNode other = (IntegerSwitchNode) switchNode;
+        return Arrays.equals(keys, other.keys);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.emitSwitch(this);
+    }
+
+    public AbstractBeginNode successorAtKey(int key) {
+        return blockSuccessor(successorIndexAtKey(key));
+    }
+
+    public int successorIndexAtKey(int key) {
+        for (int i = 0; i < keyCount(); i++) {
+            if (keys[i] == key) {
+                return keySuccessorIndex(i);
+            }
+        }
+        return keySuccessorIndex(keyCount());
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (blockSuccessorCount() == 1) {
+            tool.addToWorkList(defaultSuccessor());
+            graph().removeSplitPropagate(this, defaultSuccessor());
+        } else if (value() instanceof ConstantNode) {
+            killOtherSuccessors(tool, successorIndexAtKey(value().asJavaConstant().asInt()));
+        } else if (tryOptimizeEnumSwitch(tool)) {
+            return;
+        } else if (tryRemoveUnreachableKeys(tool)) {
+            return;
+        }
+    }
+
+    static final class KeyData {
+        final int key;
+        final double keyProbability;
+        final int keySuccessor;
+
+        KeyData(int key, double keyProbability, int keySuccessor) {
+            this.key = key;
+            this.keyProbability = keyProbability;
+            this.keySuccessor = keySuccessor;
+        }
+    }
+
+    /**
+     * Remove unreachable keys from the switch based on the stamp of the value, i.e., based on the
+     * known range of the switch value.
+     */
+    private boolean tryRemoveUnreachableKeys(SimplifierTool tool) {
+        if (!(value().stamp() instanceof IntegerStamp)) {
+            return false;
+        }
+        IntegerStamp integerStamp = (IntegerStamp) value().stamp();
+        if (integerStamp.isUnrestricted()) {
+            return false;
+        }
+
+        List<KeyData> newKeyDatas = new ArrayList<>(keys.length);
+        ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+        for (int i = 0; i < keys.length; i++) {
+            if (integerStamp.contains(keys[i])) {
+                newKeyDatas.add(new KeyData(keys[i], keyProbabilities[i], addNewSuccessor(keySuccessor(i), newSuccessors)));
+            }
+        }
+
+        if (newKeyDatas.size() == keys.length) {
+            /* All keys are reachable. */
+            return false;
+
+        } else if (newKeyDatas.size() == 0) {
+            tool.addToWorkList(defaultSuccessor());
+            graph().removeSplitPropagate(this, defaultSuccessor());
+            return true;
+
+        } else {
+            int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors);
+            double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1];
+            doReplace(tool, value(), newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability);
+            return true;
+        }
+    }
+
+    /**
+     * For switch statements on enum values, the Java compiler has to generate complicated code:
+     * because {@link Enum#ordinal()} can change when recompiling an enum, it cannot be used
+     * directly as the value that is switched on. An intermediate int[] array, which is initialized
+     * once at run time based on the actual {@link Enum#ordinal()} values, is used.
+     *
+     * The {@link ConstantFieldProvider} of Graal already detects the int[] arrays and marks them as
+     * {@link ConstantNode#isDefaultStable() stable}, i.e., the array elements are constant. The
+     * code in this method detects array loads from such a stable array and re-wires the switch to
+     * use the keys from the array elements, so that the array load is unnecessary.
+     */
+    private boolean tryOptimizeEnumSwitch(SimplifierTool tool) {
+        if (!(value() instanceof LoadIndexedNode)) {
+            /* Not the switch pattern we are looking for. */
+            return false;
+        }
+        LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
+        if (loadIndexed.usages().count() > 1) {
+            /*
+             * The array load is necessary for other reasons too, so there is no benefit optimizing
+             * the switch.
+             */
+            return false;
+        }
+        assert loadIndexed.usages().first() == this;
+
+        ValueNode newValue = loadIndexed.index();
+        JavaConstant arrayConstant = loadIndexed.array().asJavaConstant();
+        if (arrayConstant == null || ((ConstantNode) loadIndexed.array()).getStableDimension() != 1 || !((ConstantNode) loadIndexed.array()).isDefaultStable()) {
+            /*
+             * The array is a constant that we can optimize. We require the array elements to be
+             * constant too, since we put them as literal constants into the switch keys.
+             */
+            return false;
+        }
+
+        Integer optionalArrayLength = tool.getConstantReflection().readArrayLength(arrayConstant);
+        if (optionalArrayLength == null) {
+            /* Loading a constant value can be denied by the VM. */
+            return false;
+        }
+        int arrayLength = optionalArrayLength;
+
+        Map<Integer, List<Integer>> reverseArrayMapping = new HashMap<>();
+        for (int i = 0; i < arrayLength; i++) {
+            JavaConstant elementConstant = tool.getConstantReflection().readArrayElement(arrayConstant, i);
+            if (elementConstant == null || elementConstant.getJavaKind() != JavaKind.Int) {
+                /* Loading a constant value can be denied by the VM. */
+                return false;
+            }
+            int element = elementConstant.asInt();
+
+            /*
+             * The value loaded from the array is the old switch key, the index into the array is
+             * the new switch key. We build a mapping from the old switch key to new keys.
+             */
+            reverseArrayMapping.computeIfAbsent(element, e -> new ArrayList<>()).add(i);
+        }
+
+        /* Build high-level representation of new switch keys. */
+        List<KeyData> newKeyDatas = new ArrayList<>(arrayLength);
+        ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+        for (int i = 0; i < keys.length; i++) {
+            List<Integer> newKeys = reverseArrayMapping.get(keys[i]);
+            if (newKeys == null || newKeys.size() == 0) {
+                /* The switch case is unreachable, we can ignore it. */
+                continue;
+            }
+
+            /*
+             * We do not have detailed profiling information about the individual new keys, so we
+             * have to assume they split the probability of the old key.
+             */
+            double newKeyProbability = keyProbabilities[i] / newKeys.size();
+            int newKeySuccessor = addNewSuccessor(keySuccessor(i), newSuccessors);
+
+            for (int newKey : newKeys) {
+                newKeyDatas.add(new KeyData(newKey, newKeyProbability, newKeySuccessor));
+            }
+        }
+
+        int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors);
+        double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1];
+
+        /*
+         * We remove the array load, but we still need to preserve exception semantics by keeping
+         * the bounds check. Fortunately the array length is a constant.
+         */
+        LogicNode boundsCheck = graph().unique(new IntegerBelowNode(newValue, ConstantNode.forInt(arrayLength, graph())));
+        graph().addBeforeFixed(this, graph().add(new FixedGuardNode(boundsCheck, DeoptimizationReason.BoundsCheckException, DeoptimizationAction.InvalidateReprofile)));
+
+        /*
+         * Build the low-level representation of the new switch keys and replace ourself with a new
+         * node.
+         */
+        doReplace(tool, newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability);
+
+        /* The array load is now unnecessary. */
+        assert loadIndexed.hasNoUsages();
+        GraphUtil.removeFixedWithUnusedInputs(loadIndexed);
+
+        return true;
+    }
+
+    private static int addNewSuccessor(AbstractBeginNode newSuccessor, ArrayList<AbstractBeginNode> newSuccessors) {
+        int index = newSuccessors.indexOf(newSuccessor);
+        if (index == -1) {
+            index = newSuccessors.size();
+            newSuccessors.add(newSuccessor);
+        }
+        return index;
+    }
+
+    private void doReplace(SimplifierTool tool, ValueNode newValue, List<KeyData> newKeyDatas, ArrayList<AbstractBeginNode> newSuccessors, int newDefaultSuccessor, double newDefaultProbability) {
+        /* Sort the new keys (invariant of the IntegerSwitchNode). */
+        newKeyDatas.sort((k1, k2) -> k1.key - k2.key);
+
+        /* Create the final data arrays. */
+        int newKeyCount = newKeyDatas.size();
+        int[] newKeys = new int[newKeyCount];
+        double[] newKeyProbabilities = new double[newKeyCount + 1];
+        int[] newKeySuccessors = new int[newKeyCount + 1];
+
+        for (int i = 0; i < newKeyCount; i++) {
+            KeyData keyData = newKeyDatas.get(i);
+            newKeys[i] = keyData.key;
+            newKeyProbabilities[i] = keyData.keyProbability;
+            newKeySuccessors[i] = keyData.keySuccessor;
+        }
+
+        newKeySuccessors[newKeyCount] = newDefaultSuccessor;
+        newKeyProbabilities[newKeyCount] = newDefaultProbability;
+
+        /* Normalize new probabilities so that they sum up to 1. */
+        double totalProbability = 0;
+        for (double probability : newKeyProbabilities) {
+            totalProbability += probability;
+        }
+        if (totalProbability > 0) {
+            for (int i = 0; i < newKeyProbabilities.length; i++) {
+                newKeyProbabilities[i] /= totalProbability;
+            }
+        } else {
+            for (int i = 0; i < newKeyProbabilities.length; i++) {
+                newKeyProbabilities[i] = 1.0 / newKeyProbabilities.length;
+            }
+        }
+
+        /* Remove dead successors. */
+        for (int i = 0; i < blockSuccessorCount(); i++) {
+            AbstractBeginNode successor = blockSuccessor(i);
+            if (!newSuccessors.contains(successor)) {
+                tool.deleteBranch(successor);
+            }
+            setBlockSuccessor(i, null);
+        }
+
+        /* Create the new switch node and replace ourself with it. */
+        AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
+        SwitchNode newSwitch = graph().add(new IntegerSwitchNode(newValue, successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
+        ((FixedWithNextNode) predecessor()).setNext(newSwitch);
+        GraphUtil.killWithUnusedFloatingInputs(this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java
new file mode 100644
index 0000000..ebb05cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Read a raw memory location according to Java field or array read semantics. It will perform read
+ * barriers, implicit conversions and optionally oop uncompression.
+ */
+@NodeInfo(nameTemplate = "JavaRead#{p#location/s}", cycles = CYCLES_2, size = SIZE_1)
+public final class JavaReadNode extends FixedAccessNode implements Lowerable, GuardingNode, Canonicalizable {
+
+    public static final NodeClass<JavaReadNode> TYPE = NodeClass.create(JavaReadNode.class);
+    protected final JavaKind readKind;
+    protected final boolean compressible;
+
+    public JavaReadNode(JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) {
+        super(TYPE, address, location, StampFactory.forKind(readKind), barrierType);
+        this.readKind = readKind;
+        this.compressible = compressible;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return true;
+    }
+
+    public JavaKind getReadKind() {
+        return readKind;
+    }
+
+    public boolean isCompressible() {
+        return compressible;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return ReadNode.canonicalizeRead(this, getAddress(), getLocationIdentity(), tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java
new file mode 100644
index 0000000..da467c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractWriteNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Write a raw memory location according to Java field or array write semantics. It will perform
+ * write barriers, implicit conversions and optionally oop compression.
+ */
+@NodeInfo(nameTemplate = "JavaWrite#{p#location/s}")
+public final class JavaWriteNode extends AbstractWriteNode implements Lowerable, StateSplit, MemoryAccess, MemoryCheckpoint.Single {
+
+    public static final NodeClass<JavaWriteNode> TYPE = NodeClass.create(JavaWriteNode.class);
+    protected final JavaKind writeKind;
+    protected final boolean compressible;
+
+    public JavaWriteNode(JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, boolean compressible, boolean initialization) {
+        super(TYPE, address, location, value, barrierType, initialization);
+        this.writeKind = writeKind;
+        this.compressible = compressible;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return true;
+    }
+
+    public JavaKind getWriteKind() {
+        return writeKind;
+    }
+
+    public boolean isCompressible() {
+        return compressible;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java
new file mode 100644
index 0000000..366f8db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Loads an object's hub. The object is not null-checked by this operation.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class LoadHubNode extends FloatingNode implements Lowerable, Canonicalizable, Virtualizable {
+
+    public static final NodeClass<LoadHubNode> TYPE = NodeClass.create(LoadHubNode.class);
+    @Input ValueNode value;
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    private static Stamp hubStamp(StampProvider stampProvider, ValueNode value) {
+        assert value.stamp() instanceof ObjectStamp;
+        return stampProvider.createHubStamp(((ObjectStamp) value.stamp()));
+    }
+
+    public static ValueNode create(ValueNode value, StampProvider stampProvider, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        Stamp stamp = hubStamp(stampProvider, value);
+        ValueNode synonym = findSynonym(value, stamp, metaAccess, constantReflection);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new LoadHubNode(stamp, value);
+    }
+
+    public LoadHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode value) {
+        this(hubStamp(stampProvider, value), value);
+    }
+
+    public LoadHubNode(Stamp stamp, ValueNode value) {
+        super(TYPE, stamp);
+        this.value = value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (!GeneratePIC.getValue()) {
+            MetaAccessProvider metaAccess = tool.getMetaAccess();
+            ValueNode curValue = getValue();
+            ValueNode newNode = findSynonym(curValue, stamp(), metaAccess, tool.getConstantReflection());
+            if (newNode != null) {
+                return newNode;
+            }
+        }
+        return this;
+    }
+
+    public static ValueNode findSynonym(ValueNode curValue, Stamp stamp, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        if (!GeneratePIC.getValue()) {
+            TypeReference type = StampTool.typeReferenceOrNull(curValue);
+            if (type != null && type.isExact()) {
+                return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(type.getType()), metaAccess);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        if (!GeneratePIC.getValue()) {
+            ValueNode alias = tool.getAlias(getValue());
+            TypeReference type = StampTool.typeReferenceOrNull(alias);
+            if (type != null && type.isExact()) {
+                tool.replaceWithValue(ConstantNode.forConstant(stamp(), tool.getConstantReflectionProvider().asObjectHub(type.getType()), tool.getMetaAccessProvider(), graph()));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadMethodNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadMethodNode.java
new file mode 100644
index 0000000..28b464a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadMethodNode.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Loads a method from the virtual method table of a given hub.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
+
+    public static final NodeClass<LoadMethodNode> TYPE = NodeClass.create(LoadMethodNode.class);
+    @Input ValueNode hub;
+    protected final ResolvedJavaMethod method;
+    protected final ResolvedJavaType receiverType;
+
+    /**
+     * The caller or context type used to perform access checks when resolving {@link #method}.
+     */
+    protected final ResolvedJavaType callerType;
+
+    public ValueNode getHub() {
+        return hub;
+    }
+
+    public LoadMethodNode(@InjectedNodeParameter Stamp stamp, ResolvedJavaMethod method, ResolvedJavaType receiverType, ResolvedJavaType callerType, ValueNode hub) {
+        super(TYPE, stamp);
+        this.receiverType = receiverType;
+        this.callerType = callerType;
+        this.hub = hub;
+        this.method = method;
+        assert method.isConcrete() : "Cannot load abstract method from a hub";
+        assert method.hasReceiver() : "Cannot load a static method from a hub";
+        if (!method.isInVirtualMethodTable(receiverType)) {
+            throw new GraalError("%s does not have a vtable entry in type %s", method, receiverType);
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (hub instanceof LoadHubNode) {
+            ValueNode object = ((LoadHubNode) hub).getValue();
+            TypeReference type = StampTool.typeReferenceOrNull(object);
+            if (type != null) {
+                if (type.isExact()) {
+                    return resolveExactMethod(tool, type.getType());
+                }
+                Assumptions assumptions = graph().getAssumptions();
+                AssumptionResult<ResolvedJavaMethod> resolvedMethod = type.getType().findUniqueConcreteMethod(method);
+                if (resolvedMethod != null && resolvedMethod.canRecordTo(assumptions) && !type.getType().isInterface() && method.getDeclaringClass().isAssignableFrom(type.getType())) {
+                    resolvedMethod.recordTo(assumptions);
+                    return ConstantNode.forConstant(stamp(), resolvedMethod.getResult().getEncoding(), tool.getMetaAccess());
+                }
+            }
+        }
+        if (hub.isConstant()) {
+            return resolveExactMethod(tool, tool.getConstantReflection().asJavaType(hub.asConstant()));
+        }
+
+        return this;
+    }
+
+    /**
+     * Find the method which would be loaded.
+     *
+     * @param tool
+     * @param type the exact type of object being loaded from
+     * @return the method which would be invoked for {@code type} or null if it doesn't implement
+     *         the method
+     */
+    private Node resolveExactMethod(CanonicalizerTool tool, ResolvedJavaType type) {
+        ResolvedJavaMethod newMethod = type.resolveConcreteMethod(method, callerType);
+        if (newMethod == null) {
+            /*
+             * This really represent a misuse of LoadMethod since we're loading from a class which
+             * isn't known to implement the original method but for now at least fold it away.
+             */
+            return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, null);
+        } else {
+            return ConstantNode.forConstant(stamp(), newMethod.getEncoding(), tool.getMetaAccess());
+        }
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    public ResolvedJavaType getReceiverType() {
+        return receiverType;
+    }
+
+    public ResolvedJavaType getCallerType() {
+        return callerType;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java
new file mode 100644
index 0000000..c354a14
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Creates a memory barrier.
+ */
+@NodeInfo(nameTemplate = "Membar#{p#location/s}", allowedUsageTypes = Memory, cycles = CYCLES_20, size = SIZE_2)
+public final class MembarNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<MembarNode> TYPE = NodeClass.create(MembarNode.class);
+    protected final int barriers;
+    protected final LocationIdentity location;
+
+    public MembarNode(int barriers) {
+        this(barriers, LocationIdentity.any());
+    }
+
+    public MembarNode(int barriers, LocationIdentity location) {
+        super(TYPE, StampFactory.forVoid());
+        this.barriers = barriers;
+        this.location = location;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return location;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.getLIRGeneratorTool().emitMembar(barriers);
+    }
+
+    @NodeIntrinsic
+    public static native void memoryBarrier(@ConstantNodeParameter int barriers);
+
+    @NodeIntrinsic
+    public static native void memoryBarrier(@ConstantNodeParameter int barriers, @ConstantNodeParameter LocationIdentity location);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorEnter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorEnter.java
new file mode 100644
index 0000000..29d0517
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorEnter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+/**
+ * Denotes monitor locking transition.
+ */
+public interface MonitorEnter {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorExit.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorExit.java
new file mode 100644
index 0000000..70dc69d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MonitorExit.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+/**
+ * Denotes monitor unlocking transition.
+ */
+public interface MonitorExit extends MemoryCheckpoint {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/NullCheckNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/NullCheckNode.java
new file mode 100644
index 0000000..26dd993
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/NullCheckNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(allowedUsageTypes = Guard, cycles = CYCLES_2, size = SIZE_2)
+public final class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
+
+    public static final NodeClass<NullCheckNode> TYPE = NodeClass.create(NullCheckNode.class);
+    @Input ValueNode object;
+
+    public NullCheckNode(ValueNode object) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.getLIRGeneratorTool().emitNullCheck(generator.operand(object), generator.state(this));
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @NodeIntrinsic
+    public static native void nullCheck(Object object);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRLocalNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRLocalNode.java
new file mode 100644
index 0000000..ac68957
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRLocalNode.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractLocalNode;
+
+@NodeInfo(nameTemplate = "OSRLocal({p#index})")
+public final class OSRLocalNode extends AbstractLocalNode implements IterableNodeType {
+
+    public static final NodeClass<OSRLocalNode> TYPE = NodeClass.create(OSRLocalNode.class);
+
+    public OSRLocalNode(int index, Stamp stamp) {
+        super(TYPE, index, stamp);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRStartNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRStartNode.java
new file mode 100644
index 0000000..89dba58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OSRStartNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo
+public final class OSRStartNode extends StartNode implements Lowerable {
+    public static final NodeClass<OSRStartNode> TYPE = NodeClass.create(OSRStartNode.class);
+
+    public OSRStartNode() {
+        super(TYPE);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public NodeIterable<OSRLocalNode> getOSRLocals() {
+        return usages().filter(OSRLocalNode.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/StoreHubNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/StoreHubNode.java
new file mode 100644
index 0000000..2487364
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/StoreHubNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class StoreHubNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<StoreHubNode> TYPE = NodeClass.create(StoreHubNode.class);
+    @Input ValueNode value;
+    @Input ValueNode object;
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public StoreHubNode(ValueNode object, ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+        this.object = object;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static native void write(Object object, Object value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java
new file mode 100644
index 0000000..b7ee7ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSuccessorList;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.Constant;
+
+/**
+ * The {@code SwitchNode} class is the base of both lookup and table switches.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "We cannot estimate the runtime cost of a switch statement without knowing the number" +
+                            "of case statements and the involved keys.",
+          size = SIZE_UNKNOWN,
+          sizeRationale = "We cannot estimate the code size of a switch statement without knowing the number" +
+                          "of case statements.")
+// @formatter:on
+public abstract class SwitchNode extends ControlSplitNode {
+
+    public static final NodeClass<SwitchNode> TYPE = NodeClass.create(SwitchNode.class);
+    @Successor protected NodeSuccessorList<AbstractBeginNode> successors;
+    @Input protected ValueNode value;
+
+    // do not change the contents of these arrays:
+    protected final double[] keyProbabilities;
+    protected final int[] keySuccessors;
+
+    /**
+     * Constructs a new Switch.
+     *
+     * @param value the instruction that provides the value to be switched over
+     * @param successors the list of successors of this switch
+     */
+    protected SwitchNode(NodeClass<? extends SwitchNode> c, ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
+        super(c, StampFactory.forVoid());
+        assert value.stamp().getStackKind().isNumericInteger() || value.stamp() instanceof AbstractPointerStamp : value.stamp() + " key not supported by SwitchNode";
+        assert keySuccessors.length == keyProbabilities.length;
+        this.successors = new NodeSuccessorList<>(this, successors);
+        this.value = value;
+        this.keySuccessors = keySuccessors;
+        this.keyProbabilities = keyProbabilities;
+        assert assertProbabilities();
+    }
+
+    private boolean assertProbabilities() {
+        double total = 0;
+        for (double d : keyProbabilities) {
+            total += d;
+            assert d >= 0.0 : "Cannot have negative probabilities in switch node: " + d;
+        }
+        assert total > 0.999 && total < 1.001 : "Total " + total;
+        return true;
+    }
+
+    @Override
+    public double probability(AbstractBeginNode successor) {
+        double sum = 0;
+        for (int i = 0; i < keySuccessors.length; i++) {
+            if (successors.get(keySuccessors[i]) == successor) {
+                sum += keyProbabilities[i];
+            }
+        }
+        return sum;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public abstract boolean isSorted();
+
+    /**
+     * The number of distinct keys in this switch.
+     */
+    public abstract int keyCount();
+
+    /**
+     * The key at the specified position, encoded in a Constant.
+     */
+    public abstract Constant keyAt(int i);
+
+    public boolean structureEquals(SwitchNode switchNode) {
+        return Arrays.equals(keySuccessors, switchNode.keySuccessors) && equalKeys(switchNode);
+    }
+
+    /**
+     * Returns true if the switch has the same keys in the same order as this switch.
+     */
+    public abstract boolean equalKeys(SwitchNode switchNode);
+
+    /**
+     * Returns the index of the successor belonging to the key at the specified index.
+     */
+    public int keySuccessorIndex(int i) {
+        return keySuccessors[i];
+    }
+
+    /**
+     * Returns the successor for the key at the given index.
+     */
+    public AbstractBeginNode keySuccessor(int i) {
+        return successors.get(keySuccessors[i]);
+    }
+
+    /**
+     * Returns the probability of the key at the given index.
+     */
+    public double keyProbability(int i) {
+        return keyProbabilities[i];
+    }
+
+    /**
+     * Returns the index of the default (fall through) successor of this switch.
+     */
+    public int defaultSuccessorIndex() {
+        return keySuccessors[keySuccessors.length - 1];
+    }
+
+    public AbstractBeginNode blockSuccessor(int i) {
+        return successors.get(i);
+    }
+
+    public void setBlockSuccessor(int i, AbstractBeginNode s) {
+        successors.set(i, s);
+    }
+
+    public int blockSuccessorCount() {
+        return successors.count();
+    }
+
+    /**
+     * Gets the successor corresponding to the default (fall through) case.
+     *
+     * @return the default successor
+     */
+    public AbstractBeginNode defaultSuccessor() {
+        if (defaultSuccessorIndex() == -1) {
+            throw new GraalError("unexpected");
+        }
+        return successors.get(defaultSuccessorIndex());
+    }
+
+    @Override
+    public AbstractBeginNode getPrimarySuccessor() {
+        return this.defaultSuccessor();
+    }
+
+    /**
+     * Delete all other successors except for the one reached by {@code survivingEdge}.
+     *
+     * @param tool
+     * @param survivingEdge index of the edge in the {@link SwitchNode#successors} list
+     */
+    protected void killOtherSuccessors(SimplifierTool tool, int survivingEdge) {
+        for (Node successor : successors()) {
+            /*
+             * Deleting a branch change change the successors so reload the surviving successor each
+             * time.
+             */
+            if (successor != blockSuccessor(survivingEdge)) {
+                tool.deleteBranch(successor);
+            }
+        }
+        tool.addToWorkList(blockSuccessor(survivingEdge));
+        graph().removeSplit(this, blockSuccessor(survivingEdge));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java
new file mode 100644
index 0000000..deb5025
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(cycles = CYCLES_100, size = SIZE_50)
+public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> {
+
+    public static final NodeClass<UnboxNode> TYPE = NodeClass.create(UnboxNode.class);
+    @Input protected ValueNode value;
+    protected final JavaKind boxingKind;
+
+    @Override
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public UnboxNode(ValueNode value, JavaKind boxingKind) {
+        super(TYPE, StampFactory.forKind(boxingKind.getStackKind()));
+        this.value = value;
+        this.boxingKind = boxingKind;
+    }
+
+    public static ValueNode create(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode value, JavaKind boxingKind) {
+        ValueNode synonym = findSynonym(metaAccess, constantReflection, value, boxingKind);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new UnboxNode(value, boxingKind);
+    }
+
+    public JavaKind getBoxingKind() {
+        return boxingKind;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getValue());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ResolvedJavaType objectType = virtual.type();
+            ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass());
+            if (objectType.equals(expectedType)) {
+                tool.replaceWithValue(tool.getEntry(virtual, 0));
+            }
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (tool.allUsagesAvailable() && hasNoUsages() && StampTool.isPointerNonNull(forValue)) {
+            return null;
+        }
+        ValueNode synonym = findSynonym(tool.getMetaAccess(), tool.getConstantReflection(), forValue, boxingKind);
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    private static ValueNode findSynonym(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode forValue, JavaKind boxingKind) {
+        if (forValue.isConstant()) {
+            JavaConstant constant = forValue.asJavaConstant();
+            JavaConstant unboxed = constantReflection.unboxPrimitive(constant);
+            if (unboxed != null && unboxed.getJavaKind() == boxingKind) {
+                return ConstantNode.forConstant(unboxed, metaAccess);
+            }
+        } else if (forValue instanceof BoxNode) {
+            BoxNode box = (BoxNode) forValue;
+            if (boxingKind == box.getBoxingKind()) {
+                return box.getValue();
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
new file mode 100644
index 0000000..e29f8b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable {
+
+    public static final NodeClass<UnsafeAccessNode> TYPE = NodeClass.create(UnsafeAccessNode.class);
+    @Input ValueNode object;
+    @Input ValueNode offset;
+    protected final JavaKind accessKind;
+    protected final LocationIdentity locationIdentity;
+
+    protected UnsafeAccessNode(NodeClass<? extends UnsafeAccessNode> c, Stamp stamp, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
+        super(c, stamp);
+        assert accessKind != null;
+        assert locationIdentity != null;
+        this.object = object;
+        this.offset = offset;
+        this.accessKind = accessKind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode offset() {
+        return offset;
+    }
+
+    public JavaKind accessKind() {
+        return accessKind;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (this.getLocationIdentity().isAny() && offset().isConstant()) {
+            long constantOffset = offset().asJavaConstant().asLong();
+
+            // Try to canonicalize to a field access.
+            ResolvedJavaType receiverType = StampTool.typeOrNull(object());
+            if (receiverType != null) {
+                ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind());
+                // No need for checking that the receiver is non-null. The field access includes
+                // the null check and if a field is found, the offset is so small that this is
+                // never a valid access of an arbitrary address.
+                if (field != null && field.getJavaKind() == this.accessKind()) {
+                    assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase";
+                    return cloneAsFieldAccess(graph().getAssumptions(), field);
+                }
+            }
+        }
+        if (this.getLocationIdentity().isAny()) {
+            ResolvedJavaType receiverType = StampTool.typeOrNull(object());
+            // Try to build a better location identity.
+            if (receiverType != null && receiverType.isArray()) {
+                LocationIdentity identity = NamedLocationIdentity.getArrayLocation(receiverType.getComponentType().getJavaKind());
+                assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase";
+                return cloneAsArrayAccess(offset(), identity);
+            }
+        }
+
+        return this;
+    }
+
+    protected abstract ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field);
+
+    protected abstract ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java
new file mode 100644
index 0000000..b6500f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+
+/**
+ * Copy a value at a location specified as an offset relative to a source object to another location
+ * specified as an offset relative to destination object. No null checks are performed.
+ */
+public final class UnsafeCopyNode {
+
+    public static boolean intrinsify(GraphBuilderContext b, @SuppressWarnings("unused") ResolvedJavaMethod targetMethod, ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject,
+                    ValueNode destinationOffset, JavaKind accessKind, LocationIdentity locationIdentity) {
+        UnsafeLoadNode value = b.add(new UnsafeLoadNode(sourceObject, sourceOffset, accessKind, locationIdentity));
+        b.add(new UnsafeStoreNode(destinationObject, destinationOffset, value, accessKind, locationIdentity));
+        return true;
+    }
+
+    @NodeIntrinsic
+    public static native void copy(Object srcObject, long srcOffset, Object destObject, long destOffset, @ConstantNodeParameter JavaKind kind,
+                    @ConstantNodeParameter LocationIdentity locationIdentity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeLoadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeLoadNode.java
new file mode 100644
index 0000000..ff60485
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeLoadNode.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * Load of a value from a location specified as an offset relative to an object. No null check is
+ * performed before the load.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
+    public static final NodeClass<UnsafeLoadNode> TYPE = NodeClass.create(UnsafeLoadNode.class);
+
+    public UnsafeLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity);
+    }
+
+    public UnsafeLoadNode(NodeClass<? extends UnsafeLoadNode> c, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
+        super(c, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ValueNode offsetValue = tool.getAlias(offset());
+            if (offsetValue.isConstant()) {
+                long off = offsetValue.asJavaConstant().asLong();
+                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
+
+                if (entryIndex != -1) {
+                    ValueNode entry = tool.getEntry(virtual, entryIndex);
+                    JavaKind entryKind = virtual.entryKind(entryIndex);
+                    if (entry.getStackKind() == getStackKind() || entryKind == accessKind()) {
+                        tool.replaceWith(entry);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) {
+        return LoadFieldNode.create(assumptions, object(), field);
+    }
+
+    @Override
+    protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity) {
+        return new UnsafeLoadNode(object(), location, accessKind(), identity);
+    }
+
+    @NodeIntrinsic
+    public static native Object load(Object object, long offset, @ConstantNodeParameter JavaKind kind, @ConstantNodeParameter LocationIdentity locationIdentity);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java
new file mode 100644
index 0000000..73abaf3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Load of a value at a location specified as an absolute address.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public class UnsafeMemoryLoadNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<UnsafeMemoryLoadNode> TYPE = NodeClass.create(UnsafeMemoryLoadNode.class);
+
+    @Input protected ValueNode address;
+    protected final JavaKind kind;
+    protected final LocationIdentity locationIdentity;
+
+    public UnsafeMemoryLoadNode(ValueNode address, JavaKind kind, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forKind(kind.getStackKind()));
+        this.address = address;
+        this.kind = kind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode getAddress() {
+        return address;
+    }
+
+    public JavaKind getKind() {
+        return kind;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java
new file mode 100644
index 0000000..5faa33f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Store of a value at a location specified as an absolute address.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public class UnsafeMemoryStoreNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<UnsafeMemoryStoreNode> TYPE = NodeClass.create(UnsafeMemoryStoreNode.class);
+    @Input protected ValueNode value;
+    @Input protected ValueNode address;
+    protected final JavaKind kind;
+    protected final LocationIdentity locationIdentity;
+
+    public UnsafeMemoryStoreNode(ValueNode address, ValueNode value, JavaKind kind, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = address;
+        this.value = value;
+        this.kind = kind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public ValueNode getAddress() {
+        return address;
+    }
+
+    public JavaKind getKind() {
+        return kind;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeStoreNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeStoreNode.java
new file mode 100644
index 0000000..bc8b230
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeStoreNode.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * Store of a value at a location specified as an offset relative to an object. No null check is
+ * performed before the store.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<UnsafeStoreNode> TYPE = NodeClass.create(UnsafeStoreNode.class);
+    @Input ValueNode value;
+    @OptionalInput(State) FrameState stateAfter;
+
+    public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, JavaKind accessKind, LocationIdentity locationIdentity) {
+        this(object, offset, value, accessKind, locationIdentity, null);
+    }
+
+    public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, JavaKind accessKind, LocationIdentity locationIdentity, FrameState stateAfter) {
+        super(TYPE, StampFactory.forVoid(), object, offset, accessKind, locationIdentity);
+        this.value = value;
+        this.stateAfter = stateAfter;
+        assert accessKind != JavaKind.Void && accessKind != JavaKind.Illegal;
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            ValueNode indexValue = tool.getAlias(offset());
+            if (indexValue.isConstant()) {
+                long off = indexValue.asJavaConstant().asLong();
+                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
+                if (entryIndex != -1) {
+                    JavaKind entryKind = virtual.entryKind(entryIndex);
+                    ValueNode entry = tool.getEntry(virtual, entryIndex);
+                    if (entry.getStackKind() == value.getStackKind() || entryKind == accessKind()) {
+                        tool.setVirtualEntry(virtual, entryIndex, value(), true);
+                        tool.delete();
+                    } else {
+                        if ((accessKind() == JavaKind.Long || accessKind() == JavaKind.Double) && entryKind == JavaKind.Int) {
+                            int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind);
+                            if (nextIndex != -1) {
+                                JavaKind nextKind = virtual.entryKind(nextIndex);
+                                if (nextKind == JavaKind.Int) {
+                                    tool.setVirtualEntry(virtual, entryIndex, value(), true);
+                                    tool.setVirtualEntry(virtual, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true);
+                                    tool.delete();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) {
+        return new StoreFieldNode(object(), field, value(), stateAfter());
+    }
+
+    @Override
+    protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity) {
+        return new UnsafeStoreNode(object(), location, value, accessKind(), identity, stateAfter());
+    }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ValueAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ValueAnchorNode.java
new file mode 100644
index 0000000..6fb4d8d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ValueAnchorNode.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Anchor;
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
+ */
+@NodeInfo(allowedUsageTypes = {Anchor, Guard}, cycles = CYCLES_0, size = SIZE_0)
+public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, AnchoringNode, GuardingNode {
+
+    public static final NodeClass<ValueAnchorNode> TYPE = NodeClass.create(ValueAnchorNode.class);
+    @OptionalInput(Guard) ValueNode anchored;
+
+    public ValueAnchorNode(ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.anchored = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // Nothing to emit, since this node is used for structural purposes only.
+    }
+
+    public ValueNode getAnchoredNode() {
+        return anchored;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        while (next() instanceof ValueAnchorNode) {
+            ValueAnchorNode nextAnchor = (ValueAnchorNode) next();
+            if (nextAnchor.anchored == anchored || nextAnchor.anchored == null) {
+                // two anchors for the same anchored -> coalesce
+                // nothing anchored on the next anchor -> coalesce
+                nextAnchor.replaceAtUsages(this);
+                GraphUtil.removeFixedWithUnusedInputs(nextAnchor);
+            } else {
+                break;
+            }
+        }
+        if (tool.allUsagesAvailable() && hasNoUsages() && next() instanceof FixedAccessNode) {
+            FixedAccessNode currentNext = (FixedAccessNode) next();
+            if (currentNext.getGuard() == anchored) {
+                GraphUtil.removeFixedWithUnusedInputs(this);
+                return;
+            } else if (currentNext.getGuard() == null && anchored instanceof GuardNode && ((GuardNode) anchored).getCondition() instanceof IsNullNode) {
+                // coalesce null check guards into subsequent read/write
+                currentNext.setGuard((GuardingNode) anchored);
+                tool.addToWorkList(next());
+                return;
+            }
+        }
+
+        if (anchored != null && (anchored.isConstant() || anchored instanceof FixedNode)) {
+            // anchoring fixed nodes and constants is useless
+            removeAnchoredNode();
+        }
+
+        if (anchored == null && hasNoUsages()) {
+            // anchor is not necessary any more => remove.
+            GraphUtil.removeFixedWithUnusedInputs(this);
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        if (anchored == null || anchored instanceof AbstractBeginNode) {
+            tool.delete();
+        } else {
+            ValueNode alias = tool.getAlias(anchored);
+            if (alias instanceof VirtualObjectNode) {
+                tool.delete();
+            }
+        }
+    }
+
+    public void removeAnchoredNode() {
+        this.updateUsages(anchored, null);
+        this.anchored = null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java
new file mode 100644
index 0000000..9ea105a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public interface ClassInitializationPlugin extends GraphBuilderPlugin {
+    boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type);
+
+    ValueNode apply(GraphBuilderContext builder, ResolvedJavaType type, FrameState frameState);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ForeignCallPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ForeignCallPlugin.java
new file mode 100644
index 0000000..0340e43
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ForeignCallPlugin.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * {@link InvocationPlugin} for converting a method call directly to a foreign call.
+ */
+public final class ForeignCallPlugin implements InvocationPlugin {
+    private final ForeignCallsProvider foreignCalls;
+    private final ForeignCallDescriptor descriptor;
+
+    public ForeignCallPlugin(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor) {
+        this.foreignCalls = foreignCalls;
+        this.descriptor = descriptor;
+    }
+
+    @Override
+    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {
+        ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
+        foreignCall.setBci(b.bci());
+        b.addPush(targetMethod.getSignature().getReturnKind(), foreignCall);
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GeneratedInvocationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GeneratedInvocationPlugin.java
new file mode 100644
index 0000000..7a0c091
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GeneratedInvocationPlugin.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public abstract class GeneratedInvocationPlugin implements InvocationPlugin {
+
+    @Override
+    public abstract boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args);
+
+    @Override
+    public StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("execute")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new GraalError("could not find method named \"execute\" in " + c.getName());
+    }
+
+    protected boolean checkInjectedArgument(GraphBuilderContext b, ValueNode arg, ResolvedJavaMethod foldAnnotatedMethod) {
+        if (arg.isNullConstant()) {
+            return true;
+        }
+
+        MetaAccessProvider metaAccess = b.getMetaAccess();
+        ResolvedJavaMethod executeMethod = metaAccess.lookupJavaMethod(getExecuteMethod());
+        ResolvedJavaType thisClass = metaAccess.lookupJavaType(getClass());
+        ResolvedJavaMethod thisExecuteMethod = thisClass.resolveConcreteMethod(executeMethod, thisClass);
+        if (b.getMethod().equals(thisExecuteMethod)) {
+            // The "execute" method of this plugin is itself being compiled. In (only) this context,
+            // the injected argument of the call to the @Fold annotated method will be non-null.
+            return true;
+        }
+        throw new AssertionError("must pass null to injected argument of " + foldAnnotatedMethod.format("%H.%n(%p)"));
+    }
+
+    private static Method getExecuteMethod() {
+        try {
+            return GeneratedInvocationPlugin.class.getMethod("execute", GraphBuilderContext.class, ResolvedJavaMethod.class, InvocationPlugin.Receiver.class, ValueNode[].class);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalError(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java
new file mode 100644
index 0000000..f5e2669
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.type.StampPair;
+
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class GraphBuilderConfiguration {
+
+    public static class Plugins {
+        private final InvocationPlugins invocationPlugins;
+        private NodePlugin[] nodePlugins;
+        private ParameterPlugin[] parameterPlugins;
+        private TypePlugin[] typePlugins;
+        private InlineInvokePlugin[] inlineInvokePlugins;
+        private LoopExplosionPlugin loopExplosionPlugin;
+        private ClassInitializationPlugin classInitializationPlugin;
+        private ProfilingPlugin profilingPlugin;
+
+        /**
+         * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
+         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
+         * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
+         */
+        public Plugins(Plugins copyFrom) {
+            this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins);
+            this.nodePlugins = copyFrom.nodePlugins;
+            this.parameterPlugins = copyFrom.parameterPlugins;
+            this.typePlugins = copyFrom.typePlugins;
+            this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
+            this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
+            this.classInitializationPlugin = copyFrom.classInitializationPlugin;
+            this.profilingPlugin = copyFrom.profilingPlugin;
+        }
+
+        /**
+         * Creates a new set of plugins.
+         *
+         * @param invocationPlugins the {@linkplain #getInvocationPlugins() invocation plugins} in
+         *            this object
+         */
+        public Plugins(InvocationPlugins invocationPlugins) {
+            this.invocationPlugins = invocationPlugins;
+            this.nodePlugins = new NodePlugin[0];
+            this.parameterPlugins = new ParameterPlugin[0];
+            this.typePlugins = new TypePlugin[0];
+            this.inlineInvokePlugins = new InlineInvokePlugin[0];
+        }
+
+        public InvocationPlugins getInvocationPlugins() {
+            return invocationPlugins;
+        }
+
+        public NodePlugin[] getNodePlugins() {
+            return nodePlugins;
+        }
+
+        public void appendNodePlugin(NodePlugin plugin) {
+            nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1);
+            nodePlugins[nodePlugins.length - 1] = plugin;
+        }
+
+        public void prependNodePlugin(NodePlugin plugin) {
+            NodePlugin[] newPlugins = new NodePlugin[nodePlugins.length + 1];
+            System.arraycopy(nodePlugins, 0, newPlugins, 1, nodePlugins.length);
+            newPlugins[0] = plugin;
+            nodePlugins = newPlugins;
+        }
+
+        public void clearNodePlugin() {
+            nodePlugins = new NodePlugin[0];
+        }
+
+        public ParameterPlugin[] getParameterPlugins() {
+            return parameterPlugins;
+        }
+
+        public void appendParameterPlugin(ParameterPlugin plugin) {
+            parameterPlugins = Arrays.copyOf(parameterPlugins, parameterPlugins.length + 1);
+            parameterPlugins[parameterPlugins.length - 1] = plugin;
+        }
+
+        public void prependParameterPlugin(ParameterPlugin plugin) {
+            ParameterPlugin[] newPlugins = new ParameterPlugin[parameterPlugins.length + 1];
+            System.arraycopy(parameterPlugins, 0, newPlugins, 1, parameterPlugins.length);
+            newPlugins[0] = plugin;
+            parameterPlugins = newPlugins;
+        }
+
+        public TypePlugin[] getTypePlugins() {
+            return typePlugins;
+        }
+
+        public void appendTypePlugin(TypePlugin plugin) {
+            typePlugins = Arrays.copyOf(typePlugins, typePlugins.length + 1);
+            typePlugins[typePlugins.length - 1] = plugin;
+        }
+
+        public void prependTypePlugin(TypePlugin plugin) {
+            TypePlugin[] newPlugins = new TypePlugin[typePlugins.length + 1];
+            System.arraycopy(typePlugins, 0, newPlugins, 1, typePlugins.length);
+            newPlugins[0] = plugin;
+            typePlugins = newPlugins;
+        }
+
+        public void clearParameterPlugin() {
+            parameterPlugins = new ParameterPlugin[0];
+        }
+
+        public InlineInvokePlugin[] getInlineInvokePlugins() {
+            return inlineInvokePlugins;
+        }
+
+        public void appendInlineInvokePlugin(InlineInvokePlugin plugin) {
+            inlineInvokePlugins = Arrays.copyOf(inlineInvokePlugins, inlineInvokePlugins.length + 1);
+            inlineInvokePlugins[inlineInvokePlugins.length - 1] = plugin;
+        }
+
+        public void prependInlineInvokePlugin(InlineInvokePlugin plugin) {
+            InlineInvokePlugin[] newPlugins = new InlineInvokePlugin[inlineInvokePlugins.length + 1];
+            System.arraycopy(inlineInvokePlugins, 0, newPlugins, 1, inlineInvokePlugins.length);
+            newPlugins[0] = plugin;
+            inlineInvokePlugins = newPlugins;
+        }
+
+        public void clearInlineInvokePlugins() {
+            inlineInvokePlugins = new InlineInvokePlugin[0];
+        }
+
+        public LoopExplosionPlugin getLoopExplosionPlugin() {
+            return loopExplosionPlugin;
+        }
+
+        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
+            this.loopExplosionPlugin = plugin;
+        }
+
+        public ClassInitializationPlugin getClassInitializationPlugin() {
+            return classInitializationPlugin;
+        }
+
+        public void setClassInitializationPlugin(ClassInitializationPlugin plugin) {
+            this.classInitializationPlugin = plugin;
+        }
+
+        public ProfilingPlugin getProfilingPlugin() {
+            return profilingPlugin;
+        }
+
+        public void setProfilingPlugin(ProfilingPlugin plugin) {
+            this.profilingPlugin = plugin;
+        }
+
+        public StampPair getOverridingStamp(GraphBuilderTool b, JavaType type, boolean nonNull) {
+            for (TypePlugin plugin : getTypePlugins()) {
+                StampPair stamp = plugin.interceptType(b, type, nonNull);
+                if (stamp != null) {
+                    return stamp;
+                }
+            }
+            return null;
+        }
+    }
+
+    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
+
+    private final boolean eagerResolving;
+    private final BytecodeExceptionMode bytecodeExceptionMode;
+    private final boolean omitAssertions;
+    private final ResolvedJavaType[] skippedExceptionTypes;
+    private final boolean insertFullInfopoints;
+    private final boolean trackNodeSourcePosition;
+    private final boolean clearNonLiveLocals;
+    private final Plugins plugins;
+
+    public enum BytecodeExceptionMode {
+        /**
+         * This mode always explicitly checks for exceptions.
+         */
+        CheckAll,
+        /**
+         * This mode omits all explicit exception edges.
+         */
+        OmitAll,
+        /**
+         * This mode uses profiling information to decide whether to use explicit exception edges.
+         */
+        Profile
+    }
+
+    protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
+                    boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes,
+                    boolean clearNonLiveLocals, Plugins plugins) {
+        this.eagerResolving = eagerResolving;
+        this.bytecodeExceptionMode = bytecodeExceptionMode;
+        this.omitAssertions = omitAssertions;
+        this.insertFullInfopoints = insertFullInfopoints;
+        this.trackNodeSourcePosition = trackNodeSourcePosition;
+        this.skippedExceptionTypes = skippedExceptionTypes;
+        this.clearNonLiveLocals = clearNonLiveLocals;
+        this.plugins = plugins;
+    }
+
+    /**
+     * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
+     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
+     * {@link InvocationPlugins} in the copy.
+     */
+    public GraphBuilderConfiguration copy() {
+        Plugins newPlugins = new Plugins(plugins);
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+                        clearNonLiveLocals, newPlugins);
+        return result;
+    }
+
+    public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
+        return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
+        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) {
+        return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
+        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) {
+        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
+        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) {
+        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
+        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, clearNonLiveLocals,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) {
+        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, newClearNonLiveLocals,
+                        plugins);
+    }
+
+    public ResolvedJavaType[] getSkippedExceptionTypes() {
+        return skippedExceptionTypes;
+    }
+
+    public boolean eagerResolving() {
+        return eagerResolving;
+    }
+
+    public BytecodeExceptionMode getBytecodeExceptionMode() {
+        return bytecodeExceptionMode;
+    }
+
+    public boolean omitAssertions() {
+        return omitAssertions;
+    }
+
+    public boolean trackNodeSourcePosition() {
+        return trackNodeSourcePosition;
+    }
+
+    public boolean insertFullInfopoints() {
+        return insertFullInfopoints;
+    }
+
+    public boolean clearNonLiveLocals() {
+        return clearNonLiveLocals;
+    }
+
+    public static GraphBuilderConfiguration getDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    /**
+     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
+     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
+     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
+     */
+    public boolean unresolvedIsError() {
+        return eagerResolving;
+    }
+
+    public Plugins getPlugins() {
+        return plugins;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
new file mode 100644
index 0000000..cd52988
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
+ * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
+ */
+public interface GraphBuilderContext extends GraphBuilderTool {
+
+    /**
+     * Pushes a given value to the frame state stack using an explicit kind. This should be used
+     * when {@code value.getJavaKind()} is different from the kind that the bytecode instruction
+     * currently being parsed pushes to the stack.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to push to the stack. The value must already have been
+     *            {@linkplain #append(ValueNode) appended}.
+     */
+    void push(JavaKind kind, ValueNode value);
+
+    /**
+     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
+     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
+     *
+     * @param value the value to add to the graph and push to the stack. The
+     *            {@code value.getJavaKind()} kind is used when type checking this operation.
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T add(T value) {
+        if (value.graph() != null) {
+            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
+            return value;
+        }
+        T equivalentValue = append(value);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * frame state is initialized.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to add to the graph and push to the stack
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T addPush(JavaKind kind, T value) {
+        T equivalentValue = value.graph() != null ? value : append(value);
+        push(kind, equivalentValue);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
+     * one for which the plugin was applied). This applies all standard graph builder processing to
+     * the replaced invocation including applying any relevant plugins.
+     *
+     * @param invokeKind the kind of the replacement invocation
+     * @param targetMethod the target of the replacement invocation
+     * @param args the arguments to the replacement invocation
+     * @param forceInlineEverything specifies if all invocations encountered in the scope of
+     *            handling the replaced invoke are to be force inlined
+     */
+    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
+
+    /**
+     * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
+     * substitution method.
+     *
+     * @param bytecodeProvider used to get the bytecodes to parse for the substitution method
+     * @param targetMethod the method being intrinsified
+     * @param substitute the intrinsic implementation
+     * @param receiver the receiver, or null for static methods
+     * @param argsIncludingReceiver the arguments with which to inline the invocation
+     *
+     * @return whether the intrinsification was successful
+     */
+    boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver);
+
+    /**
+     * Creates a snap shot of the current frame state with the BCI of the instruction after the one
+     * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
+     * effect} node.
+     *
+     * @param sideEffect a side effect node just appended to the graph
+     */
+    void setStateAfter(StateSplit sideEffect);
+
+    /**
+     * Gets the parsing context for the method that inlines the method being parsed by this context.
+     */
+    GraphBuilderContext getParent();
+
+    /**
+     * Gets the first ancestor parsing context that is not parsing a {@linkplain #parsingIntrinsic()
+     * intrinsic}.
+     */
+    default GraphBuilderContext getNonIntrinsicAncestor() {
+        GraphBuilderContext ancestor = getParent();
+        while (ancestor != null && ancestor.parsingIntrinsic()) {
+            ancestor = ancestor.getParent();
+        }
+        return ancestor;
+    }
+
+    /**
+     * Gets the code being parsed.
+     */
+    Bytecode getCode();
+
+    /**
+     * Gets the method being parsed by this context.
+     */
+    ResolvedJavaMethod getMethod();
+
+    /**
+     * Gets the index of the bytecode instruction currently being parsed.
+     */
+    int bci();
+
+    /**
+     * Gets the kind of invocation currently being parsed.
+     */
+    InvokeKind getInvokeKind();
+
+    /**
+     * Gets the return type of the invocation currently being parsed.
+     */
+    JavaType getInvokeReturnType();
+
+    default StampPair getInvokeReturnStamp(Assumptions assumptions) {
+        JavaType returnType = getInvokeReturnType();
+        return StampFactory.forDeclaredType(assumptions, returnType, false);
+    }
+
+    /**
+     * Gets the inline depth of this context. A return value of 0 implies that this is the context
+     * for the parse root.
+     */
+    default int getDepth() {
+        GraphBuilderContext parent = getParent();
+        return parent == null ? 0 : 1 + parent.getDepth();
+    }
+
+    /**
+     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
+     * by an intrinsic.
+     */
+    @Override
+    default boolean parsingIntrinsic() {
+        return getIntrinsic() != null;
+    }
+
+    /**
+     * Gets the intrinsic of the current parsing context or {@code null} if not
+     * {@link #parsingIntrinsic() parsing an intrinsic}.
+     */
+    IntrinsicContext getIntrinsic();
+
+    BailoutException bailout(String string);
+
+    /**
+     * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
+     * non-null} stamp.
+     */
+    default ValueNode nullCheckedValue(ValueNode value) {
+        if (!StampTool.isPointerNonNull(value.stamp())) {
+            LogicNode condition = getGraph().unique(IsNullNode.create(value));
+            ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
+            Stamp stamp = receiverStamp.join(objectNonNull());
+            FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
+            PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp, fixedGuard));
+            // TODO: Propogating the non-null into the frame state would
+            // remove subsequent null-checks on the same value. However,
+            // it currently causes an assertion failure when merging states.
+            //
+            // frameState.replace(value, nonNullReceiver);
+            return nonNullReceiver;
+        }
+        return value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderPlugin.java
new file mode 100644
index 0000000..e5cceed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderPlugin.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+/**
+ * Marker interface for graph builder plugins.
+ */
+public interface GraphBuilderPlugin {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java
new file mode 100644
index 0000000..f2885e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Used by a {@link GraphBuilderPlugin} to interface with an object that builds a graph.
+ */
+public interface GraphBuilderTool {
+
+    /**
+     * Raw operation for adding a node to the graph.
+     *
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T append(T value);
+
+    /**
+     * Adds the given node to the graph and also adds recursively all referenced inputs.
+     *
+     * @param value the node to be added to the graph
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T recursiveAppend(T value);
+
+    StampProvider getStampProvider();
+
+    MetaAccessProvider getMetaAccess();
+
+    default Assumptions getAssumptions() {
+        return getGraph().getAssumptions();
+    }
+
+    ConstantReflectionProvider getConstantReflection();
+
+    ConstantFieldProvider getConstantFieldProvider();
+
+    /**
+     * Gets the graph being constructed.
+     */
+    StructuredGraph getGraph();
+
+    /**
+     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
+     * by an intrinsic.
+     */
+    boolean parsingIntrinsic();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java
new file mode 100644
index 0000000..73ac712
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Plugin for specifying what is inlined during graph parsing. This plugin is also notified
+ * {@link #notifyBeforeInline before} and {@link #notifyAfterInline} the inlining, as well as of
+ * {@link #notifyNotInlined non-inlined} invocations (i.e., those for which an {@link Invoke} node
+ * is created).
+ */
+public interface InlineInvokePlugin extends GraphBuilderPlugin {
+
+    /**
+     * Result of a {@link #shouldInlineInvoke inlining decision}.
+     */
+    final class InlineInfo {
+
+        /**
+         * Denotes a call site that must not be inlined and should be implemented by a node that
+         * does not speculate on the call not raising an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, null);
+
+        /**
+         * Denotes a call site must not be inlined and can be implemented by a node that speculates
+         * the call will not throw an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null);
+
+        private final ResolvedJavaMethod methodToInline;
+        private final BytecodeProvider intrinsicBytecodeProvider;
+
+        public static InlineInfo createStandardInlineInfo(ResolvedJavaMethod methodToInline) {
+            return new InlineInfo(methodToInline, null);
+        }
+
+        public static InlineInfo createIntrinsicInlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) {
+            return new InlineInfo(methodToInline, intrinsicBytecodeProvider);
+        }
+
+        private InlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) {
+            this.methodToInline = methodToInline;
+            this.intrinsicBytecodeProvider = intrinsicBytecodeProvider;
+        }
+
+        /**
+         * Returns the method to be inlined, or {@code null} if the call site must not be inlined.
+         */
+        public ResolvedJavaMethod getMethodToInline() {
+            return methodToInline;
+        }
+
+        /**
+         * Gets the provider of bytecode to be parsed for {@link #getMethodToInline()} if is is an
+         * intrinsic for the original method (i.e., the {@code method} passed to
+         * {@link InlineInvokePlugin#shouldInlineInvoke}). A {@code null} return value indicates
+         * that this is not an intrinsic inlining.
+         */
+        public BytecodeProvider getIntrinsicBytecodeProvider() {
+            return intrinsicBytecodeProvider;
+        }
+    }
+
+    /**
+     * Determines whether a call to a given method is to be inlined. The return value is a
+     * tri-state:
+     * <p>
+     * Non-null return value with a non-null {@link InlineInfo#getMethodToInline method}: That
+     * {@link InlineInfo#getMethodToInline method} is inlined. Note that it can be a different
+     * method than the one specified here as the parameter, which allows method substitutions.
+     * <p>
+     * Non-null return value with a null {@link InlineInfo#getMethodToInline method}, e.g.,
+     * {@link InlineInfo#DO_NOT_INLINE_WITH_EXCEPTION}: The method is not inlined, and other plugins
+     * with a lower priority cannot overwrite this decision.
+     * <p>
+     * Null return value: This plugin made no decision, other plugins with a lower priority are
+     * asked.
+     *
+     * @param b the context
+     * @param method the target method of an invoke
+     * @param args the arguments to the invoke
+     */
+    default InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return null;
+    }
+
+    /**
+     * Notification that a method is about to be inlined.
+     *
+     * @param methodToInline the inlined method
+     */
+    default void notifyBeforeInline(ResolvedJavaMethod methodToInline) {
+    }
+
+    /**
+     * Notification that a method was inlined.
+     *
+     * @param methodToInline the inlined method
+     */
+    default void notifyAfterInline(ResolvedJavaMethod methodToInline) {
+    }
+
+    /**
+     * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined per
+     * {@link #shouldInlineInvoke}.
+     *
+     * @param b the context
+     * @param method the method that was not inlined
+     * @param invoke the invoke node created for the call to {@code method}
+     */
+    default void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
new file mode 100644
index 0000000..caf4252
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
+ * snippets) that is itself implemented in Java. This interface provides information about the
+ * intrinsic currently being processed by the graph builder.
+ *
+ * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
+ * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
+ * machine words and pointers.
+ */
+public class IntrinsicContext {
+
+    /**
+     * Method being intrinsified.
+     */
+    final ResolvedJavaMethod method;
+
+    /**
+     * Method providing the intrinsic implementation.
+     */
+    final ResolvedJavaMethod intrinsic;
+
+    /**
+     * Provider of bytecode to be parsed for a method that is part of an intrinsic.
+     */
+    final BytecodeProvider bytecodeProvider;
+
+    /**
+     * Gets the method being intrinsified.
+     */
+    public ResolvedJavaMethod getOriginalMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the method providing the intrinsic implementation.
+     */
+    public ResolvedJavaMethod getIntrinsicMethod() {
+        return intrinsic;
+    }
+
+    /**
+     * Gets provider of bytecode to be parsed for a method that is part of an intrinsic.
+     */
+    public BytecodeProvider getBytecodeProvider() {
+        return bytecodeProvider;
+    }
+
+    /**
+     * Determines if a call within the compilation scope of this intrinsic represents a call to the
+     * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
+     * intrinsification falls back to the original method.
+     */
+    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
+        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
+    }
+
+    final CompilationContext compilationContext;
+
+    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
+        this.method = method;
+        this.intrinsic = intrinsic;
+        this.bytecodeProvider = bytecodeProvider;
+        assert bytecodeProvider != null;
+        this.compilationContext = compilationContext;
+        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+    }
+
+    public boolean isPostParseInlined() {
+        return compilationContext.equals(INLINE_AFTER_PARSING);
+    }
+
+    public boolean isCompilationRoot() {
+        return compilationContext.equals(ROOT_COMPILATION);
+    }
+
+    /**
+     * Denotes the compilation context in which an intrinsic is being parsed.
+     */
+    public enum CompilationContext {
+        /**
+         * An intrinsic is being processed when parsing an invoke bytecode that calls the
+         * intrinsified method.
+         */
+        INLINE_DURING_PARSING,
+
+        /**
+         * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
+         */
+        INLINE_AFTER_PARSING,
+
+        /**
+         * An intrinsic is the root of compilation.
+         */
+        ROOT_COMPILATION
+    }
+
+    /**
+     * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
+     * are control flow predecessors of the current point in a graph.
+     */
+    public interface SideEffectsState {
+
+        /**
+         * Determines if the current program point is preceded by one or more side effects.
+         */
+        boolean isAfterSideEffect();
+
+        /**
+         * Gets the side effects preceding the current program point.
+         */
+        Iterable<StateSplit> sideEffects();
+
+        /**
+         * Records a side effect for the current program point.
+         */
+        void addSideEffect(StateSplit sideEffect);
+    }
+
+    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
+        assert forStateSplit != graph.start();
+        if (forStateSplit.hasSideEffect()) {
+            if (sideEffects.isAfterSideEffect()) {
+                // Only the last side effect on any execution path in a replacement
+                // can inherit the stateAfter of the replaced node
+                FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
+                for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
+                    lastSideEffect.setStateAfter(invalid);
+                }
+            }
+            sideEffects.addSideEffect(forStateSplit);
+            return graph.add(new FrameState(AFTER_BCI));
+        } else {
+            if (forStateSplit instanceof AbstractMergeNode) {
+                // Merge nodes always need a frame state
+                if (sideEffects.isAfterSideEffect()) {
+                    // A merge after one or more side effects
+                    return graph.add(new FrameState(AFTER_BCI));
+                } else {
+                    // A merge before any side effects
+                    return graph.add(new FrameState(BEFORE_BCI));
+                }
+            } else {
+                // Other non-side-effects do not need a state
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java
new file mode 100644
index 0000000..b2f6910
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Plugin for handling a specific method invocation.
+ */
+public interface InvocationPlugin extends GraphBuilderPlugin {
+
+    /**
+     * The receiver in a non-static method. The class literal for this interface must be used with
+     * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, boolean, Class, String, Class...)}
+     * to denote the receiver argument for such a non-static method.
+     */
+    public interface Receiver {
+        /**
+         * Gets the receiver value, null checking it first if necessary.
+         *
+         * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode)
+         *         non-null} stamp
+         */
+        default ValueNode get() {
+            return get(true);
+        }
+
+        /**
+         * Gets the receiver value, optionally null checking it first if necessary.
+         */
+        ValueNode get(boolean performNullCheck);
+
+        /**
+         * Determines if the receiver is constant.
+         */
+        default boolean isConstant() {
+            return false;
+        }
+    }
+
+    /**
+     * Determines if this plugin is for a method with a polymorphic signature (e.g.
+     * {@link MethodHandle#invokeExact(Object...)}).
+     */
+    default boolean isSignaturePolymorphic() {
+        return false;
+    }
+
+    /**
+     * Determines if this plugin can only be used when inlining the method is it associated with.
+     * That is, this plugin cannot be used when the associated method is the compilation root.
+     */
+    default boolean inlineOnly() {
+        return isSignaturePolymorphic();
+    }
+
+    /**
+     * Handles invocation of a signature polymorphic method.
+     *
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
+     *            position 0 if {@code targetMethod} is not static
+     * @see #execute
+     */
+    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) {
+        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) {
+        return defaultHandler(b, targetMethod, receiver);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
+        return defaultHandler(b, targetMethod, receiver, arg);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /**
+     * Executes this plugin against a set of invocation arguments.
+     *
+     * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)}
+     * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin}
+     * is {@linkplain #isSignaturePolymorphic() signature polymorphic}.
+     *
+     * @param targetMethod the method for which this plugin is being applied
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
+     *            0 if {@code targetMethod} is not static
+     * @return {@code true} if this plugin handled the invocation of {@code targetMethod}
+     *         {@code false} if the graph builder should process the invoke further (e.g., by
+     *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
+     *         invocation must not modify the graph being constructed.
+     */
+    default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        if (isSignaturePolymorphic()) {
+            return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
+        } else if (receiver != null) {
+            assert !targetMethod.isStatic();
+            assert argsIncludingReceiver.length > 0;
+            if (argsIncludingReceiver.length == 1) {
+                return apply(b, targetMethod, receiver);
+            } else if (argsIncludingReceiver.length == 2) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
+            } else {
+                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+            }
+        } else {
+            assert targetMethod.isStatic();
+            if (argsIncludingReceiver.length == 0) {
+                return apply(b, targetMethod, null);
+            } else if (argsIncludingReceiver.length == 1) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0]);
+            } else if (argsIncludingReceiver.length == 2) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
+            } else {
+                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+            }
+
+        }
+    }
+
+    /**
+     * Handles an invocation when a specific {@code apply} method is not available.
+     */
+    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver,
+                    ValueNode... args) {
+        throw new GraalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
+    }
+
+    default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("apply")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            } else if (m.getName().equals("defaultHandler")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new GraalError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
new file mode 100644
index 0000000..74562c4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import static java.lang.String.format;
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.MetaUtil;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Manages a set of {@link InvocationPlugin}s.
+ */
+public class InvocationPlugins {
+
+    public static class InvocationPluginReceiver implements InvocationPlugin.Receiver {
+        private final GraphBuilderContext parser;
+        private ValueNode[] args;
+        private ValueNode value;
+
+        public InvocationPluginReceiver(GraphBuilderContext parser) {
+            this.parser = parser;
+        }
+
+        @Override
+        public ValueNode get(boolean performNullCheck) {
+            assert args != null : "Cannot get the receiver of a static method";
+            if (!performNullCheck) {
+                return args[0];
+            }
+            if (value == null) {
+                value = parser.nullCheckedValue(args[0]);
+                if (value != args[0]) {
+                    args[0] = value;
+                }
+            }
+            return value;
+        }
+
+        @Override
+        public boolean isConstant() {
+            return args[0].isConstant();
+        }
+
+        public InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) {
+            if (!targetMethod.isStatic()) {
+                this.args = newArgs;
+                this.value = null;
+                return this;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
+     */
+    static class OptionalLazySymbol implements Type {
+        private static final Class<?> MASK_NULL = OptionalLazySymbol.class;
+        private final String name;
+        private Class<?> resolved;
+
+        OptionalLazySymbol(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getTypeName() {
+            return name;
+        }
+
+        /**
+         * Gets the resolved {@link Class} corresponding to this symbol or {@code null} if
+         * resolution fails.
+         */
+        public Class<?> resolve() {
+            if (resolved == null) {
+                Class<?> resolvedOrNull = resolveClass(name, true);
+                resolved = resolvedOrNull == null ? MASK_NULL : resolvedOrNull;
+            }
+            return resolved == MASK_NULL ? null : resolved;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    /**
+     * Utility for {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
+     * registration} of invocation plugins.
+     */
+    public static class Registration implements MethodSubstitutionRegistry {
+
+        private final InvocationPlugins plugins;
+        private final Type declaringType;
+        private final BytecodeProvider methodSubstitutionBytecodeProvider;
+        private boolean allowOverwrite;
+
+        @Override
+        public Class<?> getReceiverType() {
+            return Receiver.class;
+        }
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringType the class declaring the methods for which plugins will be registered
+         *            via this object
+         */
+        public Registration(InvocationPlugins plugins, Type declaringType) {
+            this.plugins = plugins;
+            this.declaringType = declaringType;
+            this.methodSubstitutionBytecodeProvider = null;
+        }
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringType the class declaring the methods for which plugins will be registered
+         *            via this object
+         * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
+         *            method substitutions
+         */
+        public Registration(InvocationPlugins plugins, Type declaringType, BytecodeProvider methodSubstitutionBytecodeProvider) {
+            this.plugins = plugins;
+            this.declaringType = declaringType;
+            this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
+        }
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringClassName the name of the class class declaring the methods for which
+         *            plugins will be registered via this object
+         * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
+         *            method substitutions
+         */
+        public Registration(InvocationPlugins plugins, String declaringClassName, BytecodeProvider methodSubstitutionBytecodeProvider) {
+            this.plugins = plugins;
+            this.declaringType = new OptionalLazySymbol(declaringClassName);
+            this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
+        }
+
+        /**
+         * Configures this registration to allow or disallow overwriting of invocation plugins.
+         */
+        public Registration setAllowOverwrite(boolean allowOverwrite) {
+            this.allowOverwrite = allowOverwrite;
+            return this;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Type arg, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register2(String name, Type arg1, Type arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register3(String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3);
+        }
+
+        /**
+         * Registers a plugin for a method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Registers a plugin for a method with 5 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register5(String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
+        }
+
+        /**
+         * Registers a plugin for an optional method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional0(String name, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional1(String name, Type arg, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional2(String name, Type arg1, Type arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional3(String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2, arg3);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional4(String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method.
+         *
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original and substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        @Override
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
+            registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method.
+         *
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original method
+         * @param substituteName the name of the substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        @Override
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
+            assert methodSubstitutionBytecodeProvider != null : "Registration used for method substitutions requires a non-null methodSubstitutionBytecodeProvider";
+            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(methodSubstitutionBytecodeProvider, substituteDeclaringClass, substituteName, argumentTypes);
+            plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
+        }
+    }
+
+    /**
+     * Key for a {@linkplain ClassPlugins#entries resolved} plugin registration. Due to the
+     * possibility of class redefinition, we cannot directly use {@link ResolvedJavaMethod}s as
+     * keys. A {@link ResolvedJavaMethod} implementation might implement {@code equals()} and
+     * {@code hashCode()} based on internal representation subject to change by class redefinition.
+     */
+    static final class ResolvedJavaMethodKey {
+        private final ResolvedJavaMethod method;
+
+        ResolvedJavaMethodKey(ResolvedJavaMethod method) {
+            this.method = method;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ResolvedJavaMethodKey) {
+                ResolvedJavaMethodKey that = (ResolvedJavaMethodKey) obj;
+                if (this.method.isStatic() == that.method.isStatic()) {
+                    if (this.method.getDeclaringClass().equals(that.method.getDeclaringClass())) {
+                        if (this.method.getName().equals(that.method.getName())) {
+                            if (this.method.getSignature().equals(that.method.getSignature())) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.method.getName().hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "ResolvedJavaMethodKey<" + method + ">";
+        }
+    }
+
+    /**
+     * Key for {@linkplain ClassPlugins#registrations registering} an {@link InvocationPlugin} for a
+     * specific method.
+     */
+    static class MethodKey {
+        final boolean isStatic;
+
+        /**
+         * This method is optional. This is used for new API methods not present in previous JDK
+         * versions.
+         */
+        final boolean isOptional;
+
+        final String name;
+        final Type[] argumentTypes;
+        final InvocationPlugin value;
+
+        /**
+         * Used to lazily initialize {@link #resolved}.
+         */
+        private final MetaAccessProvider metaAccess;
+
+        private volatile ResolvedJavaMethod resolved;
+
+        MethodKey(MetaAccessProvider metaAccess, InvocationPlugin data, boolean isStatic, boolean isOptional, String name, Type... argumentTypes) {
+            this.metaAccess = metaAccess;
+            this.value = data;
+            this.isStatic = isStatic;
+            this.isOptional = isOptional;
+            this.name = name;
+            this.argumentTypes = argumentTypes;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MethodKey) {
+                MethodKey that = (MethodKey) obj;
+                boolean res = this.name.equals(that.name) && areEqual(this.argumentTypes, that.argumentTypes);
+                assert !res || this.isStatic == that.isStatic;
+                return res;
+            }
+            return false;
+        }
+
+        private static boolean areEqual(Type[] args1, Type[] args2) {
+            if (args1.length == args2.length) {
+                for (int i = 0; i < args1.length; i++) {
+                    if (!args1[i].getTypeName().equals(args2[i].getTypeName())) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public int getDeclaredParameterCount() {
+            return isStatic ? argumentTypes.length : argumentTypes.length - 1;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        private ResolvedJavaMethod resolve(Class<?> declaringClass) {
+            if (resolved == null) {
+                Executable method = resolveJava(declaringClass);
+                if (method == null) {
+                    return null;
+                }
+                resolved = metaAccess.lookupJavaMethod(method);
+            }
+            return resolved;
+        }
+
+        private Executable resolveJava(Class<?> declaringClass) {
+            try {
+                Executable res;
+                Class<?>[] parameterTypes = resolveTypes(argumentTypes, isStatic ? 0 : 1, argumentTypes.length);
+                if (name.equals("<init>")) {
+                    res = declaringClass.getDeclaredConstructor(parameterTypes);
+                } else {
+                    res = declaringClass.getDeclaredMethod(name, parameterTypes);
+                }
+                assert Modifier.isStatic(res.getModifiers()) == isStatic : res;
+                return res;
+            } catch (NoSuchMethodException | SecurityException e) {
+                if (isOptional) {
+                    return null;
+                }
+                throw new InternalError(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(name).append('(');
+            for (Type p : argumentTypes) {
+                if (sb.charAt(sb.length() - 1) != '(') {
+                    sb.append(", ");
+                }
+                sb.append(p.getTypeName());
+            }
+            return sb.append(')').toString();
+        }
+    }
+
+    private final MetaAccessProvider metaAccess;
+
+    private final Map<String, ClassPlugins> registrations = new HashMap<>();
+
+    /**
+     * Deferred registrations as well as guard for initialization. The guard uses double-checked
+     * locking which is why this field is {@code volatile}.
+     */
+    private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
+
+    /**
+     * Adds a {@link Runnable} for doing registration deferred until the first time
+     * {@link #get(ResolvedJavaMethod)} or {@link #closeRegistration()} is called on this object.
+     */
+    public void defer(Runnable deferrable) {
+        assert deferredRegistrations != null : "registration is closed";
+        deferredRegistrations.add(deferrable);
+    }
+
+    /**
+     * Per-class invocation plugins.
+     */
+    protected static class ClassPlugins {
+        private final Type declaringType;
+
+        private final List<MethodKey> registrations = new ArrayList<>();
+
+        public ClassPlugins(Type declaringClass) {
+            this.declaringType = declaringClass;
+        }
+
+        /**
+         * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
+         *
+         * Note: this must be volatile as threads may race to initialize it.
+         */
+        private volatile Map<ResolvedJavaMethodKey, InvocationPlugin> entries;
+
+        void initializeMap() {
+            if (!isClosed()) {
+                if (registrations.isEmpty()) {
+                    entries = Collections.emptyMap();
+                } else {
+                    Class<?> declaringClass = resolveType(declaringType, true);
+                    if (declaringClass == null) {
+                        // An optional type that could not be resolved
+                        entries = Collections.emptyMap();
+                    } else {
+                        Map<ResolvedJavaMethodKey, InvocationPlugin> newEntries = new HashMap<>();
+                        for (MethodKey methodKey : registrations) {
+                            ResolvedJavaMethod m = methodKey.resolve(declaringClass);
+                            if (m != null) {
+                                newEntries.put(new ResolvedJavaMethodKey(m), methodKey.value);
+                                if (entries != null) {
+                                    // Another thread finished initializing entries first
+                                    return;
+                                }
+                            }
+                        }
+                        entries = newEntries;
+                    }
+                }
+            }
+        }
+
+        public InvocationPlugin get(ResolvedJavaMethod method) {
+            if (!isClosed()) {
+                initializeMap();
+            }
+            return entries.get(new ResolvedJavaMethodKey(method));
+        }
+
+        public void register(MethodKey methodKey, boolean allowOverwrite) {
+            assert !isClosed() : "registration is closed: " + methodKey + " " + Arrays.toString(entries.keySet().toArray());
+            if (allowOverwrite) {
+                int index = registrations.indexOf(methodKey);
+                if (index >= 0) {
+                    registrations.set(index, methodKey);
+                    return;
+                }
+            } else {
+                assert !registrations.contains(methodKey) : "a value is already registered for " + declaringType + "." + methodKey;
+            }
+            registrations.add(methodKey);
+        }
+
+        public boolean isClosed() {
+            return entries != null;
+        }
+    }
+
+    /**
+     * Adds an entry to this map for a specified method.
+     *
+     * @param value value to be associated with the specified method
+     * @param isStatic specifies if the method is static
+     * @param isOptional specifies if the method is optional
+     * @param declaringClass the class declaring the method
+     * @param name the name of the method
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be
+     *            {@code declaringClass} iff the method is non-static.
+     * @return an object representing the method
+     */
+    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
+        assert isStatic || argumentTypes[0] == declaringClass;
+
+        String internalName = MetaUtil.toInternalName(declaringClass.getTypeName());
+        ClassPlugins classPlugins = registrations.get(internalName);
+        if (classPlugins == null) {
+            classPlugins = new ClassPlugins(declaringClass);
+            registrations.put(internalName, classPlugins);
+        }
+        assert isStatic || argumentTypes[0] == declaringClass;
+        MethodKey methodKey = new MethodKey(metaAccess, value, isStatic, isOptional, name, argumentTypes);
+        classPlugins.register(methodKey, allowOverwrite);
+        return methodKey;
+    }
+
+    /**
+     * Determines if a method denoted by a given {@link MethodKey} is in this map.
+     */
+    boolean containsKey(Type declaringType, MethodKey key) {
+        String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
+        ClassPlugins classPlugins = registrations.get(internalName);
+        return classPlugins != null && classPlugins.registrations.contains(key);
+    }
+
+    InvocationPlugin get(ResolvedJavaMethod method) {
+        flushDeferrables();
+        String internalName = method.getDeclaringClass().getName();
+        ClassPlugins classPlugins = registrations.get(internalName);
+        if (classPlugins != null) {
+            return classPlugins.get(method);
+        }
+        return null;
+    }
+
+    private void flushDeferrables() {
+        if (deferredRegistrations != null) {
+            synchronized (this) {
+                if (deferredRegistrations != null) {
+                    for (Runnable deferrable : deferredRegistrations) {
+                        deferrable.run();
+                    }
+                    deferredRegistrations = null;
+                }
+            }
+            for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
+                e.getValue().initializeMap();
+            }
+        }
+    }
+
+    /**
+     * Disallows new registrations of new plugins, and creates the internal tables for method
+     * lookup.
+     */
+    public void closeRegistration() {
+        flushDeferrables();
+        for (Map.Entry<String, ClassPlugins> e : registrations.entrySet()) {
+            e.getValue().initializeMap();
+        }
+    }
+
+    public int size() {
+        return registrations.size();
+    }
+
+    /**
+     * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
+     * this object.
+     */
+    protected final InvocationPlugins parent;
+
+    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+        InvocationPlugins p = parent;
+        this.parent = p;
+    }
+
+    /**
+     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
+     */
+    public InvocationPlugins(InvocationPlugins parent) {
+        this(parent, parent.getMetaAccess());
+    }
+
+    public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent, MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+        this.parent = parent;
+
+        this.deferredRegistrations = null;
+
+        for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
+            ResolvedJavaMethod method = entry.getKey();
+            InvocationPlugin plugin = entry.getValue();
+
+            String internalName = method.getDeclaringClass().getName();
+            ClassPlugins classPlugins = registrations.get(internalName);
+            if (classPlugins == null) {
+                classPlugins = new ClassPlugins(null);
+                registrations.put(internalName, classPlugins);
+                classPlugins.entries = new HashMap<>();
+            }
+
+            classPlugins.entries.put(new ResolvedJavaMethodKey(method), plugin);
+        }
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public InvocationPlugins(MetaAccessProvider metaAccess) {
+        this(null, metaAccess);
+    }
+
+    protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
+        boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
+        if (!isStatic) {
+            argumentTypes[0] = declaringClass;
+        }
+        MethodKey methodKey = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
+        assert Checker.check(this, declaringClass, methodKey, plugin);
+    }
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     *
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
+     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
+     *            non-static. Upon returning, element 0 will have been rewritten to
+     *            {@code declaringClass}
+     */
+    public void register(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
+        register(plugin, false, false, declaringClass, name, argumentTypes);
+    }
+
+    public void register(InvocationPlugin plugin, String declaringClass, String name, Type... argumentTypes) {
+        register(plugin, false, false, new OptionalLazySymbol(declaringClass), name, argumentTypes);
+    }
+
+    /**
+     * Registers an invocation plugin for a given, optional method. There must be no plugin
+     * currently registered for {@code method}.
+     *
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
+     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
+     *            non-static. Upon returning, element 0 will have been rewritten to
+     *            {@code declaringClass}
+     */
+    public void registerOptional(InvocationPlugin plugin, Type declaringClass, String name, Type... argumentTypes) {
+        register(plugin, true, false, declaringClass, name, argumentTypes);
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        if (parent != null) {
+            InvocationPlugin plugin = parent.lookupInvocation(method);
+            if (plugin != null) {
+                return plugin;
+            }
+        }
+        return get(method);
+    }
+
+    /**
+     * Gets the set of methods for which invocation plugins have been registered. Once this method
+     * is called, no further registrations can be made.
+     */
+    public Set<ResolvedJavaMethod> getMethods() {
+        Set<ResolvedJavaMethod> res = new HashSet<>();
+        if (parent != null) {
+            res.addAll(parent.getMethods());
+        }
+        flushDeferrables();
+        for (ClassPlugins cp : registrations.values()) {
+            for (ResolvedJavaMethodKey key : cp.entries.keySet()) {
+                res.add(key.method);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
+     * before searching in this object.
+     */
+    public InvocationPlugins getParent() {
+        return parent;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        registrations.forEach((name, cp) -> buf.append(name).append('.').append(cp).append(", "));
+        String s = buf.toString();
+        if (buf.length() != 0) {
+            s = s.substring(buf.length() - ", ".length());
+        }
+        return s + " / parent: " + this.parent;
+    }
+
+    private static class Checker {
+        private static final int MAX_ARITY = 5;
+        /**
+         * The set of all {@link InvocationPlugin#apply} method signatures.
+         */
+        static final Class<?>[][] SIGS;
+
+        static {
+            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
+            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
+                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
+                    Class<?>[] sig = method.getParameterTypes();
+                    assert sig[0] == GraphBuilderContext.class;
+                    assert sig[1] == ResolvedJavaMethod.class;
+                    assert sig[2] == InvocationPlugin.Receiver.class;
+                    assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length - 2) {
+                        sigs.add(null);
+                    }
+                    sigs.set(sig.length - 3, sig);
+                }
+            }
+            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
+                            ValueNode.class.getSimpleName());
+            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
+        }
+
+        public static boolean check(InvocationPlugins plugins, Type declaringType, MethodKey method, InvocationPlugin plugin) {
+            InvocationPlugins p = plugins.parent;
+            while (p != null) {
+                assert !p.containsKey(declaringType, method) : "a plugin is already registered for " + method;
+                p = p.parent;
+            }
+            if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
+                return true;
+            }
+            if (plugin instanceof MethodSubstitutionPlugin) {
+                MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
+                Method substitute = msplugin.getJavaSubstitute();
+                assert substitute.getAnnotation(MethodSubstitution.class) != null : format("Substitute method must be annotated with @%s: %s", MethodSubstitution.class.getSimpleName(), substitute);
+                return true;
+            }
+            int arguments = method.getDeclaredParameterCount();
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
+                        return true;
+                    }
+                }
+            }
+            throw new AssertionError(format("graph builder plugin for %s not found", method));
+        }
+    }
+
+    /**
+     * Checks a set of nodes added to the graph by an {@link InvocationPlugin}.
+     *
+     * @param b the graph builder that applied the plugin
+     * @param plugin a plugin that was just applied
+     * @param newNodes the nodes added to the graph by {@code plugin}
+     * @throws AssertionError if any check fail
+     */
+    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        if (parent != null) {
+            parent.checkNewNodes(b, plugin, newNodes);
+        }
+    }
+
+    /**
+     * Resolves a name to a class.
+     *
+     * @param className the name of the class to resolve
+     * @param optional if true, resolution failure returns null
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?> resolveClass(String className, boolean optional) {
+        try {
+            // Need to use the system class loader to handle classes
+            // loaded by the application class loader which is not
+            // delegated to by the JVMCI class loader.
+            ClassLoader cl = ClassLoader.getSystemClassLoader();
+            return Class.forName(className, false, cl);
+        } catch (ClassNotFoundException e) {
+            if (optional) {
+                return null;
+            }
+            throw new GraalError("Could not resolve type " + className);
+        }
+    }
+
+    /**
+     * Resolves a {@link Type} to a {@link Class}.
+     *
+     * @param type the type to resolve
+     * @param optional if true, resolution failure returns null
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?> resolveType(Type type, boolean optional) {
+        if (type instanceof Class) {
+            return (Class<?>) type;
+        }
+        if (optional && type instanceof OptionalLazySymbol) {
+            return ((OptionalLazySymbol) type).resolve();
+        }
+        return resolveClass(type.getTypeName(), optional);
+    }
+
+    private static final Class<?>[] NO_CLASSES = {};
+
+    /**
+     * Resolves an array of {@link Type}s to an array of {@link Class}es.
+     *
+     * @param types the types to resolve
+     * @param from the initial index of the range to be resolved, inclusive
+     * @param to the final index of the range to be resolved, exclusive
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?>[] resolveTypes(Type[] types, int from, int to) {
+        int length = to - from;
+        if (length <= 0) {
+            return NO_CLASSES;
+        }
+        Class<?>[] classes = new Class<?>[length];
+        for (int i = 0; i < length; i++) {
+            classes[i] = resolveType(types[i + from], false);
+        }
+        return classes;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java
new file mode 100644
index 0000000..55bf6e7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public interface LoopExplosionPlugin extends GraphBuilderPlugin {
+
+    enum LoopExplosionKind {
+        /**
+         * No loop explosion.
+         */
+        NONE,
+        /**
+         * Fully unroll all loops. The loops must have a known finite number of iterations. If a
+         * loop has multiple loop ends, they are merged so that the subsequent loop iteration is
+         * processed only once. For example, a loop with 4 iterations and 2 loop ends leads to
+         * 1+1+1+1 = 4 copies of the loop body.
+         */
+        FULL_UNROLL,
+        /**
+         * Fully explode all loops. The loops must have a known finite number of iterations. If a
+         * loop has multiple loop ends, they are not merged so that subsequent loop iterations are
+         * processed multiple times. For example, a loop with 4 iterations and 2 loop ends leads to
+         * 1+2+4+8 = 15 copies of the loop body.
+         */
+        FULL_EXPLODE,
+        /**
+         * Like {@link #FULL_EXPLODE}, but in addition explosion does not stop at loop exits. Code
+         * after the loop is duplicated for every loop exit of every loop iteration. For example, a
+         * loop with 4 iterations and 2 loop exits leads to 4 * 2 = 8 copies of the code after the
+         * loop.
+         */
+        FULL_EXPLODE_UNTIL_RETURN,
+        /**
+         * like {@link #FULL_EXPLODE}, but copies of the loop body that have the exact same state
+         * (all local variables have the same value) are merged. This reduces the number of copies
+         * necessary, but can introduce loops again. This kind is useful for bytecode interpreter
+         * loops.
+         */
+        MERGE_EXPLODE
+    }
+
+    LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java
new file mode 100644
index 0000000..3ae4194
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import static org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.resolveType;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a
+ * {@linkplain #getSubstitute(MetaAccessProvider) substitute} method. A substitute method must be
+ * static even if the substituted method is not.
+ *
+ * While performing intrinsification with method substitutions is simpler than writing an
+ * {@link InvocationPlugin} that does manual graph weaving, it has a higher compile time cost than
+ * the latter; parsing bytecodes to create nodes is slower than simply creating nodes. As such, the
+ * recommended practice is to use {@link MethodSubstitutionPlugin} only for complex
+ * intrinsifications which is typically those using non-straight-line control flow.
+ */
+public final class MethodSubstitutionPlugin implements InvocationPlugin {
+
+    private ResolvedJavaMethod cachedSubstitute;
+
+    /**
+     * The class in which the substitute method is declared.
+     */
+    private final Class<?> declaringClass;
+
+    /**
+     * The name of the original and substitute method.
+     */
+    private final String name;
+
+    /**
+     * The parameter types of the substitute method.
+     */
+    private final Type[] parameters;
+
+    private final boolean originalIsStatic;
+
+    private final BytecodeProvider bytecodeProvider;
+
+    /**
+     * Creates a method substitution plugin.
+     *
+     * @param bytecodeProvider used to get the bytecodes to parse for the substitute method
+     * @param declaringClass the class in which the substitute method is declared
+     * @param name the name of the substitute method
+     * @param parameters the parameter types of the substitute method. If the original method is not
+     *            static, then {@code parameters[0]} must be the {@link Class} value denoting
+     *            {@link InvocationPlugin.Receiver}
+     */
+    public MethodSubstitutionPlugin(BytecodeProvider bytecodeProvider, Class<?> declaringClass, String name, Type... parameters) {
+        this.bytecodeProvider = bytecodeProvider;
+        this.declaringClass = declaringClass;
+        this.name = name;
+        this.parameters = parameters;
+        this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class;
+    }
+
+    @Override
+    public boolean inlineOnly() {
+        // Conservatively assume MacroNodes may be used in a substitution
+        return true;
+    }
+
+    /**
+     * Gets the substitute method, resolving it first if necessary.
+     */
+    public ResolvedJavaMethod getSubstitute(MetaAccessProvider metaAccess) {
+        if (cachedSubstitute == null) {
+            cachedSubstitute = metaAccess.lookupJavaMethod(getJavaSubstitute());
+        }
+        return cachedSubstitute;
+    }
+
+    /**
+     * Gets the reflection API version of the substitution method.
+     */
+    Method getJavaSubstitute() throws GraalError {
+        Method substituteMethod = lookupSubstitute();
+        int modifiers = substituteMethod.getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            throw new GraalError("Substitution method must not be abstract or native: " + substituteMethod);
+        }
+        if (!Modifier.isStatic(modifiers)) {
+            throw new GraalError("Substitution method must be static: " + substituteMethod);
+        }
+        return substituteMethod;
+    }
+
+    /**
+     * Determines if a given method is the substitute method of this plugin.
+     */
+    private boolean isSubstitute(Method m) {
+        if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
+            if (parameters.length == m.getParameterCount()) {
+                Class<?>[] mparams = m.getParameterTypes();
+                int start = 0;
+                if (!originalIsStatic) {
+                    start = 1;
+                    if (!mparams[0].isAssignableFrom(resolveType(parameters[0], false))) {
+                        return false;
+                    }
+                }
+                for (int i = start; i < mparams.length; i++) {
+                    if (mparams[i] != resolveType(parameters[i], false)) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Gets the substitute method of this plugin.
+     */
+    private Method lookupSubstitute() {
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (isSubstitute(m)) {
+                return m;
+            }
+        }
+        throw new GraalError("No method found specified by %s", this);
+    }
+
+    @Override
+    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        ResolvedJavaMethod subst = getSubstitute(b.getMetaAccess());
+        return b.intrinsify(bytecodeProvider, targetMethod, subst, receiver, argsIncludingReceiver);
+    }
+
+    @Override
+    public StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("execute")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new GraalError("could not find method named \"execute\" in " + c.getName());
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
+                        Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", ")));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java
new file mode 100644
index 0000000..70aa64e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+
+public interface NodeIntrinsicPluginFactory {
+
+    public interface InjectionProvider {
+
+        <T> T getInjectedArgument(Class<T> type);
+
+        Stamp getReturnStamp(Class<?> type, boolean nonNull);
+    }
+
+    void registerPlugins(InvocationPlugins plugins, InjectionProvider injection);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java
new file mode 100644
index 0000000..199a53b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+public interface NodePlugin extends GraphBuilderPlugin {
+    /**
+     * Handle the parsing of a method invocation bytecode to a method that can be bound statically.
+     * If the method returns true, it must {@link GraphBuilderContext#push push} a value as the
+     * result of the method invocation using the {@link Signature#getReturnKind return kind} of the
+     * method.
+     *
+     * @param b the context
+     * @param method the statically bound, invoked method
+     * @param args the arguments of the method invocation
+     * @return true if the plugin handles the invocation, false otherwise
+     */
+    default boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a GETFIELD bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the
+     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
+     *
+     * @param b the context
+     * @param object the receiver object for the field access
+     * @param field the accessed field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a GETSTATIC bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the
+     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
+     *
+     * @param b the context
+     * @param field the accessed field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a PUTFIELD bytecode.
+     *
+     * @param b the context
+     * @param object the receiver object for the field access
+     * @param field the accessed field
+     * @param value the value to be stored into the field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a PUTSTATIC bytecode.
+     *
+     * @param b the context
+     * @param field the accessed field
+     * @param value the value to be stored into the field
+     * @return true if the plugin handles the field access, false otherwise.
+     */
+    default boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of an array load bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the provided elementKind.
+     *
+     * @param b the context
+     * @param array the accessed array
+     * @param index the index for the array access
+     * @param elementKind the element kind of the accessed array
+     * @return true if the plugin handles the array access, false otherwise.
+     */
+    default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of an array store bytecode.
+     *
+     * @param b the context
+     * @param array the accessed array
+     * @param index the index for the array access
+     * @param elementKind the element kind of the accessed array
+     * @param value the value to be stored into the array
+     * @return true if the plugin handles the array access, false otherwise.
+     */
+    default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a CHECKCAST bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the cast using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param object the object to be type checked
+     * @param type the type that the object is checked against
+     * @param profile the profiling information for the type check, or null if no profiling
+     *            information is available
+     * @return true if the plugin handles the cast, false otherwise
+     */
+    default boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a INSTANCEOF bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the instanceof using
+     * {@link JavaKind#Int}.
+     *
+     * @param b the context
+     * @param object the object to be type checked
+     * @param type the type that the object is checked against
+     * @param profile the profiling information for the type check, or null if no profiling
+     *            information is available
+     * @return true if the plugin handles the instanceof, false otherwise
+     */
+    default boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a NEW bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param type the type to be instantiated
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewInstance(GraphBuilderContext b, ResolvedJavaType type) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a NEWARRAY and ANEWARRAY bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param elementType the element type of the array to be instantiated
+     * @param length the length of the new array
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewArray(GraphBuilderContext b, ResolvedJavaType elementType, ValueNode length) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a MULTIANEWARRAY bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param type the type of the outermost array to be instantiated
+     * @param dimensions the array of lengths for all the dimensions to be instantiated
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewMultiArray(GraphBuilderContext b, ResolvedJavaType type, ValueNode[] dimensions) {
+        return false;
+    }
+
+    /**
+     * If the plugin {@link GraphBuilderContext#push pushes} a value with a different
+     * {@link JavaKind} than specified by the bytecode, it must override this method and return
+     * {@code true}. This disables assertion checking for value kinds.
+     *
+     * @param b the context
+     */
+    default boolean canChangeStackKind(GraphBuilderContext b) {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ParameterPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ParameterPlugin.java
new file mode 100644
index 0000000..3b205ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ParameterPlugin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+public interface ParameterPlugin extends GraphBuilderPlugin {
+
+    FloatingNode interceptParameter(GraphBuilderTool b, int index, StampPair stamp);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java
new file mode 100644
index 0000000..299d600
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LogicNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public interface ProfilingPlugin extends GraphBuilderPlugin {
+    boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method);
+
+    void profileInvoke(GraphBuilderContext builder, ResolvedJavaMethod method, FrameState frameState);
+
+    void profileGoto(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, int targetBci, FrameState frameState);
+
+    void profileIf(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, LogicNode condition, int trueBranchBci, int falseBranchBci, FrameState frameState);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/TypePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/TypePlugin.java
new file mode 100644
index 0000000..d459de7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/TypePlugin.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+
+import jdk.vm.ci.meta.JavaType;
+
+/**
+ * Plugin for overriding types in the bytecode parser. This can be used to modify the standard
+ * behavior of Java type resolution, e.g. to introduce trusted interface types with special
+ * semantics.
+ */
+public interface TypePlugin extends GraphBuilderPlugin {
+
+    /**
+     * Intercept the type of arguments or return values.
+     */
+    StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java
new file mode 100644
index 0000000..4c6f918
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+
+/**
+ * The {@code AbstractNewArrayNode} is used for all 1-dimensional array allocations.
+ */
+@NodeInfo
+public abstract class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider {
+
+    public static final NodeClass<AbstractNewArrayNode> TYPE = NodeClass.create(AbstractNewArrayNode.class);
+    @Input protected ValueNode length;
+
+    @Override
+    public ValueNode length() {
+        return length;
+    }
+
+    protected AbstractNewArrayNode(NodeClass<? extends AbstractNewArrayNode> c, Stamp stamp, ValueNode length, boolean fillContents, FrameState stateBefore) {
+        super(c, stamp, fillContents, stateBefore);
+        this.length = length;
+    }
+
+    /**
+     * The list of node which produce input for this instruction.
+     */
+    public ValueNode dimension(int index) {
+        assert index == 0;
+        return length();
+    }
+
+    /**
+     * The rank of the array allocated by this node, i.e. how many array dimensions.
+     */
+    public int dimensionCount() {
+        return 1;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewObjectNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewObjectNode.java
new file mode 100644
index 0000000..3682cf5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewObjectNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+/**
+ * The {@code AbstractNewObjectNode} is the base class for the new instance and new array nodes.
+ */
+@NodeInfo(cycles = CYCLES_20, size = SIZE_20)
+public abstract class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<AbstractNewObjectNode> TYPE = NodeClass.create(AbstractNewObjectNode.class);
+    protected final boolean fillContents;
+
+    protected AbstractNewObjectNode(NodeClass<? extends AbstractNewObjectNode> c, Stamp stamp, boolean fillContents, FrameState stateBefore) {
+        super(c, stamp, stateBefore);
+        this.fillContents = fillContents;
+    }
+
+    /**
+     * @return <code>true</code> if the object's contents should be initialized to zero/null.
+     */
+    public boolean fillContents() {
+        return fillContents;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessArrayNode.java
new file mode 100644
index 0000000..8e0b1fb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessArrayNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * This the base class of all array operations.
+ */
+@NodeInfo
+public abstract class AccessArrayNode extends FixedWithNextNode {
+
+    public static final NodeClass<AccessArrayNode> TYPE = NodeClass.create(AccessArrayNode.class);
+    @Input protected ValueNode array;
+
+    public ValueNode array() {
+        return array;
+    }
+
+    /**
+     * Creates a new AccessArrayNode.
+     *
+     * @param array the instruction that produces the array object value
+     */
+    public AccessArrayNode(NodeClass<? extends AccessArrayNode> c, Stamp stamp, ValueNode array) {
+        super(c, stamp);
+        this.array = array;
+    }
+
+    public void setArray(ValueNode array) {
+        updateUsages(this.array, array);
+        this.array = array;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessFieldNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessFieldNode.java
new file mode 100644
index 0000000..4856a00
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessFieldNode.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * The base class of all instructions that access fields.
+ */
+@NodeInfo(cycles = CYCLES_15, size = SIZE_10)
+public abstract class AccessFieldNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<AccessFieldNode> TYPE = NodeClass.create(AccessFieldNode.class);
+    @OptionalInput ValueNode object;
+
+    protected final ResolvedJavaField field;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    /**
+     * Constructs a new access field object.
+     *
+     * @param object the instruction producing the receiver object
+     * @param field the compiler interface representation of the field
+     */
+    public AccessFieldNode(NodeClass<? extends AccessFieldNode> c, Stamp stamp, ValueNode object, ResolvedJavaField field) {
+        super(c, stamp);
+        this.object = object;
+        this.field = field;
+        assert field.getDeclaringClass().isInitialized();
+    }
+
+    /**
+     * Gets the compiler interface field for this field access.
+     *
+     * @return the compiler interface field for this field access
+     */
+    public ResolvedJavaField field() {
+        return field;
+    }
+
+    /**
+     * Checks whether this field access is an access to a static field.
+     *
+     * @return {@code true} if this field access is to a static field
+     */
+    public boolean isStatic() {
+        return field.isStatic();
+    }
+
+    /**
+     * Checks whether this field is declared volatile.
+     *
+     * @return {@code true} if the field is resolved and declared volatile
+     */
+    public boolean isVolatile() {
+        return field.isVolatile();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + field.getName();
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue((object == null) == isStatic(), "static field must not have object, instance field must have object");
+        return super.verify();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessIndexedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessIndexedNode.java
new file mode 100644
index 0000000..97dfd0f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessIndexedNode.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {@code AccessIndexedNode} class is the base class of instructions that read or write elements
+ * of an array.
+ */
+@NodeInfo
+public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable {
+
+    public static final NodeClass<AccessIndexedNode> TYPE = NodeClass.create(AccessIndexedNode.class);
+    @Input protected ValueNode index;
+    protected final JavaKind elementKind;
+
+    public ValueNode index() {
+        return index;
+    }
+
+    /**
+     * Create an new AccessIndexedNode.
+     *
+     * @param stamp the result kind of the access
+     * @param array the instruction producing the array
+     * @param index the instruction producing the index
+     * @param elementKind the kind of the elements of the array
+     */
+    protected AccessIndexedNode(NodeClass<? extends AccessIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, JavaKind elementKind) {
+        super(c, stamp, array);
+        this.index = index;
+        this.elementKind = elementKind;
+    }
+
+    /**
+     * Gets the element type of the array.
+     *
+     * @return the element type
+     */
+    public JavaKind elementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessMonitorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessMonitorNode.java
new file mode 100644
index 0000000..3870a27
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessMonitorNode.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+import jdk.vm.ci.code.BailoutException;
+
+/**
+ * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release.
+ * <p>
+ * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
+ * throws a {@link BailoutException} instead during graph building.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode.DeoptBefore, DeoptimizingNode.DeoptAfter {
+
+    public static final NodeClass<AccessMonitorNode> TYPE = NodeClass.create(AccessMonitorNode.class);
+    @OptionalInput(InputType.State) FrameState stateBefore;
+    @Input ValueNode object;
+    @Input(InputType.Association) MonitorIdNode monitorId;
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public MonitorIdNode getMonitorId() {
+        return monitorId;
+    }
+
+    /**
+     * Creates a new AccessMonitor instruction.
+     *
+     * @param object the instruction producing the object
+     */
+    protected AccessMonitorNode(NodeClass<? extends AccessMonitorNode> c, ValueNode object, MonitorIdNode monitorId) {
+        super(c, StampFactory.forVoid());
+        this.object = object;
+        this.monitorId = monitorId;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ArrayLengthNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ArrayLengthNode.java
new file mode 100644
index 0000000..16346fe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ArrayLengthNode.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * The {@code ArrayLength} instruction gets the length of an array.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary<ValueNode>, Lowerable, Virtualizable {
+
+    public static final NodeClass<ArrayLengthNode> TYPE = NodeClass.create(ArrayLengthNode.class);
+    @Input ValueNode array;
+
+    public ValueNode array() {
+        return array;
+    }
+
+    @Override
+    public ValueNode getValue() {
+        return array;
+    }
+
+    public ArrayLengthNode(ValueNode array) {
+        super(TYPE, StampFactory.positiveInt());
+        this.array = array;
+    }
+
+    public static ValueNode create(ValueNode forValue, ConstantReflectionProvider constantReflection) {
+        if (forValue instanceof NewArrayNode) {
+            NewArrayNode newArray = (NewArrayNode) forValue;
+            return newArray.length();
+        }
+
+        ValueNode length = readArrayLengthConstant(forValue, constantReflection);
+        if (length != null) {
+            return length;
+        }
+        return new ArrayLengthNode(forValue);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode length = readArrayLength(forValue, tool.getConstantReflection());
+        if (length != null) {
+            return length;
+        }
+        return this;
+    }
+
+    /**
+     * Replicate the {@link ValueProxyNode}s from {@code originalValue} onto {@code value}.
+     *
+     * @param originalValue a possibly proxied value
+     * @param value a value needing proxies
+     * @return proxies wrapping {@code value}
+     */
+    private static ValueNode reproxyValue(ValueNode originalValue, ValueNode value) {
+        if (value.isConstant()) {
+            // No proxy needed
+            return value;
+        }
+        if (originalValue instanceof ValueProxyNode) {
+            ValueProxyNode proxy = (ValueProxyNode) originalValue;
+            return new ValueProxyNode(reproxyValue(proxy.getOriginalNode(), value), proxy.proxyPoint());
+        } else if (originalValue instanceof ValueProxy) {
+            ValueProxy proxy = (ValueProxy) originalValue;
+            return reproxyValue(proxy.getOriginalNode(), value);
+        } else {
+            return value;
+        }
+    }
+
+    /**
+     * Gets the length of an array if possible.
+     *
+     * @return a node representing the length of {@code array} or null if it is not available
+     */
+    public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
+        ValueNode length = GraphUtil.arrayLength(originalArray);
+        if (length != null) {
+            // Ensure that any proxies on the original value end up on the length value
+            return reproxyValue(originalArray, length);
+        }
+        return readArrayLengthConstant(originalArray, constantReflection);
+    }
+
+    private static ValueNode readArrayLengthConstant(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
+        ValueNode array = GraphUtil.unproxify(originalArray);
+        if (constantReflection != null && array.isConstant() && !array.isNullConstant()) {
+            JavaConstant constantValue = array.asJavaConstant();
+            if (constantValue != null && constantValue.isNonNull()) {
+                Integer constantLength = constantReflection.readArrayLength(constantValue);
+                if (constantLength != null) {
+                    return ConstantNode.forInt(constantLength);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static native int arrayLength(Object array);
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(array());
+        if (alias instanceof VirtualArrayNode) {
+            VirtualArrayNode virtualArray = (VirtualArrayNode) alias;
+            tool.replaceWithValue(ConstantNode.forInt(virtualArray.entryCount(), graph()));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java
new file mode 100644
index 0000000..62898b5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+import sun.misc.Unsafe;
+
+/**
+ * Represents an atomic read-and-add operation like {@link Unsafe#getAndAddInt(Object, long, int)}.
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_10, size = SIZE_3)
+public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<AtomicReadAndAddNode> TYPE = NodeClass.create(AtomicReadAndAddNode.class);
+    @Input(Association) AddressNode address;
+    @Input ValueNode delta;
+
+    protected final LocationIdentity locationIdentity;
+
+    public AtomicReadAndAddNode(AddressNode address, ValueNode delta, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forKind(delta.getStackKind()));
+        this.address = address;
+        this.delta = delta;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode delta() {
+        return delta;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndAdd(gen.operand(address), gen.operand(delta));
+        gen.setResult(this, result);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java
new file mode 100644
index 0000000..c30a56b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import sun.misc.Unsafe;
+
+/**
+ * Represents an atomic read-and-write operation like {@link Unsafe#getAndSetInt(Object, long, int)}
+ * .
+ */
+@NodeInfo(cycles = CYCLES_10, size = SIZE_4)
+public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<AtomicReadAndWriteNode> TYPE = NodeClass.create(AtomicReadAndWriteNode.class);
+    @Input ValueNode object;
+    @Input ValueNode offset;
+    @Input ValueNode newValue;
+
+    protected final JavaKind valueKind;
+    protected final LocationIdentity locationIdentity;
+
+    public AtomicReadAndWriteNode(ValueNode object, ValueNode offset, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forKind(newValue.getStackKind()));
+        this.object = object;
+        this.offset = offset;
+        this.newValue = newValue;
+        this.valueKind = valueKind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode offset() {
+        return offset;
+    }
+
+    public ValueNode newValue() {
+        return newValue;
+    }
+
+    public JavaKind getValueKind() {
+        return valueKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java
new file mode 100644
index 0000000..ca5ca87
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * The {@code ClassIsAssignableFromNode} represents a type check against {@link Class} instead of
+ * against instances. This is used, for instance, to intrinsify
+ * {@link Class#isAssignableFrom(Class)} .
+ */
+@NodeInfo(cycles = CYCLES_30, size = SIZE_30)
+public final class ClassIsAssignableFromNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
+
+    public static final NodeClass<ClassIsAssignableFromNode> TYPE = NodeClass.create(ClassIsAssignableFromNode.class);
+
+    public ClassIsAssignableFromNode(ValueNode thisClass, ValueNode otherClass) {
+        super(TYPE, thisClass, otherClass);
+    }
+
+    public Object getThisClass() {
+        return getX();
+    }
+
+    public Object getOtherClass() {
+        return getY();
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+            ResolvedJavaType thisType = constantReflection.asJavaType(forX.asJavaConstant());
+            ResolvedJavaType otherType = constantReflection.asJavaType(forY.asJavaConstant());
+            if (thisType != null && otherType != null) {
+                return LogicConstantNode.forBoolean(thisType.isAssignableFrom(otherType));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStamp, Stamp yStamp) {
+        return TriState.UNKNOWN;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/CompareAndSwapNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/CompareAndSwapNode.java
new file mode 100644
index 0000000..c889c07
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/CompareAndSwapNode.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
+ * value matched the expected value.
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_30, size = SIZE_8)
+public final class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<CompareAndSwapNode> TYPE = NodeClass.create(CompareAndSwapNode.class);
+    @Input ValueNode object;
+    @Input ValueNode offset;
+    @Input ValueNode expected;
+    @Input ValueNode newValue;
+
+    protected final JavaKind valueKind;
+    protected final LocationIdentity locationIdentity;
+
+    public CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forKind(JavaKind.Boolean.getStackKind()));
+        assert expected.stamp().isCompatible(newValue.stamp());
+        this.object = object;
+        this.offset = offset;
+        this.expected = expected;
+        this.newValue = newValue;
+        this.valueKind = valueKind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode offset() {
+        return offset;
+    }
+
+    public ValueNode expected() {
+        return expected;
+    }
+
+    public ValueNode newValue() {
+        return newValue;
+    }
+
+    public JavaKind getValueKind() {
+        return valueKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java
new file mode 100644
index 0000000..8c1038d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+//JaCoCo Exclude
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code DynamicNewArrayNode} is used for allocation of arrays when the type is not a
+ * compile-time constant.
+ */
+@NodeInfo
+public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonicalizable {
+    public static final NodeClass<DynamicNewArrayNode> TYPE = NodeClass.create(DynamicNewArrayNode.class);
+
+    @Input ValueNode elementType;
+
+    /**
+     * Class pointer to void.class needs to be exposed earlier than this node is lowered so that it
+     * can be replaced by the AOT machinery. If it's not needed for lowering this input can be
+     * ignored.
+     */
+    @OptionalInput ValueNode voidClass;
+
+    /**
+     * A non-null value indicating the worst case element type. Mainly useful for distinguishing
+     * Object arrays from primitive arrays.
+     */
+    protected final JavaKind knownElementKind;
+
+    public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
+        this(TYPE, elementType, length, fillContents, null, null, null);
+    }
+
+    public DynamicNewArrayNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode elementType, ValueNode length, boolean fillContents, JavaKind knownElementKind) {
+        this(TYPE, elementType, length, fillContents, knownElementKind, null, metaAccess);
+    }
+
+    private static Stamp computeStamp(JavaKind knownElementKind, MetaAccessProvider metaAccess) {
+        if (knownElementKind != null && metaAccess != null) {
+            ResolvedJavaType arrayType = metaAccess.lookupJavaType(knownElementKind == JavaKind.Object ? Object.class : knownElementKind.toJavaClass()).getArrayClass();
+            return StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(arrayType));
+        }
+        return StampFactory.objectNonNull();
+    }
+
+    protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, JavaKind knownElementKind, FrameState stateBefore,
+                    MetaAccessProvider metaAccess) {
+        super(c, computeStamp(knownElementKind, metaAccess), length, fillContents, stateBefore);
+        this.elementType = elementType;
+        this.knownElementKind = knownElementKind;
+        assert knownElementKind != JavaKind.Void && knownElementKind != JavaKind.Illegal;
+    }
+
+    public ValueNode getElementType() {
+        return elementType;
+    }
+
+    public JavaKind getKnownElementKind() {
+        return knownElementKind;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (elementType.isConstant()) {
+            ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant());
+            if (type != null && !throwsIllegalArgumentException(type)) {
+                return createNewArrayNode(type);
+            }
+        }
+        return this;
+    }
+
+    /** Hook for subclasses to instantiate a subclass of {@link NewArrayNode}. */
+    protected NewArrayNode createNewArrayNode(ResolvedJavaType type) {
+        return new NewArrayNode(type, length(), fillContents(), stateBefore());
+    }
+
+    public static boolean throwsIllegalArgumentException(Class<?> elementType, Class<?> voidClass) {
+        return elementType == voidClass;
+    }
+
+    public static boolean throwsIllegalArgumentException(ResolvedJavaType elementType) {
+        return elementType.getJavaKind() == JavaKind.Void;
+    }
+
+    @NodeIntrinsic
+    private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter JavaKind knownElementKind);
+
+    public static Object newArray(Class<?> componentType, int length, JavaKind knownElementKind) {
+        return newArray(componentType, length, true, knownElementKind);
+    }
+
+    public static Object newUninitializedArray(Class<?> componentType, int length, JavaKind knownElementKind) {
+        return newArray(componentType, length, false, knownElementKind);
+    }
+
+    public ValueNode getVoidClass() {
+        return voidClass;
+    }
+
+    public void setVoidClass(ValueNode newVoidClass) {
+        updateUsages(voidClass, newVoidClass);
+        voidClass = newVoidClass;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java
new file mode 100644
index 0000000..dd758f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import java.lang.reflect.Modifier;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo
+public class DynamicNewInstanceNode extends AbstractNewObjectNode implements Canonicalizable {
+    public static final NodeClass<DynamicNewInstanceNode> TYPE = NodeClass.create(DynamicNewInstanceNode.class);
+
+    @Input ValueNode clazz;
+
+    /**
+     * Class pointer to class.class needs to be exposed earlier than this node is lowered so that it
+     * can be replaced by the AOT machinery. If it's not needed for lowering this input can be
+     * ignored.
+     */
+    @OptionalInput ValueNode classClass;
+
+    public DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) {
+        this(TYPE, clazz, fillContents, null);
+    }
+
+    protected DynamicNewInstanceNode(NodeClass<? extends DynamicNewInstanceNode> c, ValueNode clazz, boolean fillContents, FrameState stateBefore) {
+        super(c, StampFactory.objectNonNull(), fillContents, stateBefore);
+        this.clazz = clazz;
+    }
+
+    public ValueNode getInstanceType() {
+        return clazz;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (clazz.isConstant()) {
+            ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant());
+            if (type != null && type.isInitialized() && !throwsInstantiationException(type, tool.getMetaAccess())) {
+                return createNewInstanceNode(type);
+            }
+        }
+        return this;
+    }
+
+    /** Hook for subclasses to instantiate a subclass of {@link NewInstanceNode}. */
+    protected NewInstanceNode createNewInstanceNode(ResolvedJavaType type) {
+        return new NewInstanceNode(type, fillContents(), stateBefore());
+    }
+
+    public static boolean throwsInstantiationException(Class<?> type, Class<?> classClass) {
+        return type.isPrimitive() || type.isArray() || type.isInterface() || Modifier.isAbstract(type.getModifiers()) || type == classClass;
+    }
+
+    public static boolean throwsInstantiationException(ResolvedJavaType type, MetaAccessProvider metaAccess) {
+        return type.isPrimitive() || type.isArray() || type.isInterface() || Modifier.isAbstract(type.getModifiers()) || type.equals(metaAccess.lookupJavaType(Class.class));
+    }
+
+    public ValueNode getClassClass() {
+        return classClass;
+    }
+
+    public void setClassClass(ValueNode newClassClass) {
+        updateUsages(classClass, newClassClass);
+        classClass = newClassClass;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java
new file mode 100644
index 0000000..033591a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginStateSplitNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.KillingBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * The entry to an exception handler with the exception coming from a call (as opposed to a local
+ * throw instruction or implicit exception).
+ */
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_10, size = SIZE_8)
+public final class ExceptionObjectNode extends BeginStateSplitNode implements Lowerable, MemoryCheckpoint.Single {
+    public static final NodeClass<ExceptionObjectNode> TYPE = NodeClass.create(ExceptionObjectNode.class);
+
+    public ExceptionObjectNode(MetaAccessProvider metaAccess) {
+        super(TYPE, StampFactory.objectNonNull(TypeReference.createTrustedWithoutAssumptions(metaAccess.lookupJavaType(Throwable.class))));
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            /*
+             * Now the lowering to BeginNode+LoadExceptionNode can be performed, since no more
+             * deopts can float in between the begin node and the load exception node.
+             */
+            LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) predecessor()).getLocationIdentity();
+            AbstractBeginNode entry = graph().add(new KillingBeginNode(locationsKilledByInvoke));
+            LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
+
+            loadException.setStateAfter(stateAfter());
+            replaceAtUsages(InputType.Value, loadException);
+            graph().replaceFixedWithFixed(this, entry);
+            entry.graph().addAfterFixed(entry, loadException);
+
+            loadException.lower(tool);
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(stateAfter() != null, "an exception handler needs a frame state");
+        return super.verify();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/FinalFieldBarrierNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/FinalFieldBarrierNode.java
new file mode 100644
index 0000000..e38a40e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/FinalFieldBarrierNode.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+@NodeInfo(cycles = CYCLES_20, size = SIZE_2)
+public class FinalFieldBarrierNode extends FixedWithNextNode implements Virtualizable, Lowerable {
+    public static final NodeClass<FinalFieldBarrierNode> TYPE = NodeClass.create(FinalFieldBarrierNode.class);
+
+    @Input private ValueNode value;
+
+    public FinalFieldBarrierNode(ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        if (tool.getAlias(value) instanceof VirtualObjectNode) {
+            tool.delete();
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        graph().replaceFixedWithFixed(this, graph().add(new MembarNode(LOAD_STORE | STORE_STORE)));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ForeignCallDescriptors.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ForeignCallDescriptors.java
new file mode 100644
index 0000000..a152e9a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ForeignCallDescriptors.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+
+/**
+ * The foreign call descriptors used by nodes in this package.
+ * <p>
+ * Using a separate class for such descriptors prevents an access from triggering unwanted class
+ * initialization during runtime initialization.
+ */
+public class ForeignCallDescriptors {
+
+    /**
+     * @see RegisterFinalizerNode
+     */
+    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java
new file mode 100644
index 0000000..e1a44ff
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * The {@code InstanceOfDynamicNode} represents a type check where the type being checked is not
+ * known at compile time. This is used, for instance, to intrinsify {@link Class#isInstance(Object)}
+ * .
+ */
+@NodeInfo(cycles = CYCLES_30, size = SIZE_30)
+public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
+    public static final NodeClass<InstanceOfDynamicNode> TYPE = NodeClass.create(InstanceOfDynamicNode.class);
+
+    private final boolean allowNull;
+
+    public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) {
+        LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new InstanceOfDynamicNode(mirror, object, allowNull);
+    }
+
+    protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull) {
+        super(TYPE, mirror, object);
+        this.allowNull = allowNull;
+        assert mirror.getStackKind() == JavaKind.Object || mirror.getStackKind() == JavaKind.Illegal : mirror.getStackKind();
+    }
+
+    public boolean isMirror() {
+        return getMirrorOrHub().getStackKind() == JavaKind.Object;
+    }
+
+    public boolean isHub() {
+        return !isMirror();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject,
+                    boolean allowNull) {
+        if (forMirror.isConstant()) {
+            ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant());
+            if (t != null) {
+                if (t.isPrimitive()) {
+                    if (allowNull) {
+                        return IsNullNode.create(forObject);
+                    } else {
+                        return LogicConstantNode.contradiction();
+                    }
+                } else {
+                    TypeReference type = TypeReference.createTrusted(assumptions, t);
+                    if (allowNull) {
+                        return InstanceOfNode.createAllowNull(type, forObject, null, null);
+                    } else {
+                        return InstanceOfNode.create(type, forObject);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public ValueNode getMirrorOrHub() {
+        return this.getX();
+    }
+
+    public ValueNode getObject() {
+        return this.getY();
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) {
+        LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull);
+        if (result != null) {
+            return result;
+        }
+        return this;
+    }
+
+    public void setMirror(ValueNode newObject) {
+        this.updateUsages(x, newObject);
+        this.x = newObject;
+    }
+
+    public boolean allowsNull() {
+        return allowNull;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForX(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public Stamp getSucceedingStampForY(boolean negated) {
+        return null;
+    }
+
+    @Override
+    public TriState tryFold(Stamp xStamp, Stamp yStamp) {
+        return TriState.UNKNOWN;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java
new file mode 100644
index 0000000..a3558ab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Anchor;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNegationNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.UnaryOpLogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * The {@code InstanceOfNode} represents an instanceof test.
+ */
+@NodeInfo(cycles = CYCLES_15, size = SIZE_15)
+public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
+    public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
+
+    protected final ObjectStamp checkedStamp;
+
+    private JavaTypeProfile profile;
+    @OptionalInput(Anchor) protected AnchoringNode anchor;
+
+    private InstanceOfNode(ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
+        this(TYPE, checkedStamp, object, profile, anchor);
+    }
+
+    protected InstanceOfNode(NodeClass<? extends InstanceOfNode> c, ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
+        super(c, object);
+        this.checkedStamp = checkedStamp;
+        this.profile = profile;
+        this.anchor = anchor;
+        assert (profile == null) || (anchor != null) : "profiles must be anchored";
+        assert checkedStamp != null;
+    }
+
+    public static LogicNode createAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
+        if (StampTool.isPointerNonNull(object)) {
+            return create(type, object, profile, anchor);
+        }
+        return createHelper(StampFactory.object(type), object, profile, anchor);
+    }
+
+    public static LogicNode create(TypeReference type, ValueNode object) {
+        return create(type, object, null, null);
+    }
+
+    public static LogicNode create(TypeReference type, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
+        return createHelper(StampFactory.objectNonNull(type), object, profile, anchor);
+    }
+
+    public static LogicNode createHelper(ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
+        LogicNode synonym = findSynonym(checkedStamp, object);
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new InstanceOfNode(checkedStamp, object, profile, anchor);
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        LogicNode synonym = findSynonym(checkedStamp, forValue);
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return this;
+        }
+    }
+
+    public static LogicNode findSynonym(ObjectStamp checkedStamp, ValueNode object) {
+        ObjectStamp inputStamp = (ObjectStamp) object.stamp();
+        ObjectStamp joinedStamp = (ObjectStamp) checkedStamp.join(inputStamp);
+
+        if (joinedStamp.isEmpty()) {
+            // The check can never succeed, the intersection of the two stamps is empty.
+            return LogicConstantNode.contradiction();
+        } else {
+            ObjectStamp meetStamp = (ObjectStamp) checkedStamp.meet(inputStamp);
+            if (checkedStamp.equals(meetStamp)) {
+                // The check will always succeed, the union of the two stamps is equal to the
+                // checked stamp.
+                return LogicConstantNode.tautology();
+            } else if (checkedStamp.type().equals(meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) {
+                assert checkedStamp.nonNull() != inputStamp.nonNull();
+                // The only difference makes the null-ness of the value => simplify the check.
+                if (checkedStamp.nonNull()) {
+                    return LogicNegationNode.create(IsNullNode.create(object));
+                } else {
+                    return IsNullNode.create(object);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the type being tested.
+     */
+    public TypeReference type() {
+        return StampTool.typeReferenceOrNull(checkedStamp);
+    }
+
+    public JavaTypeProfile profile() {
+        return profile;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getValue());
+        TriState fold = tryFold(alias.stamp());
+        if (fold != TriState.UNKNOWN) {
+            tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph()));
+        }
+    }
+
+    @Override
+    public Stamp getSucceedingStampForValue(boolean negated) {
+        if (negated) {
+            return null;
+        } else {
+            return checkedStamp;
+        }
+    }
+
+    @Override
+    public TriState tryFold(Stamp valueStamp) {
+        if (valueStamp instanceof ObjectStamp) {
+            ObjectStamp inputStamp = (ObjectStamp) valueStamp;
+            ObjectStamp joinedStamp = (ObjectStamp) checkedStamp.join(inputStamp);
+
+            if (joinedStamp.isEmpty()) {
+                // The check can never succeed, the intersection of the two stamps is empty.
+                return TriState.FALSE;
+            } else {
+                ObjectStamp meetStamp = (ObjectStamp) checkedStamp.meet(inputStamp);
+                if (checkedStamp.equals(meetStamp)) {
+                    // The check will always succeed, the union of the two stamps is equal to the
+                    // checked stamp.
+                    return TriState.TRUE;
+                }
+            }
+        }
+        return TriState.UNKNOWN;
+    }
+
+    public boolean allowsNull() {
+        return !checkedStamp.nonNull();
+    }
+
+    public void setProfile(JavaTypeProfile typeProfile, AnchoringNode anchor) {
+        this.profile = typeProfile;
+        updateUsagesInterface(this.anchor, anchor);
+        this.anchor = anchor;
+        assert (profile == null) || (anchor != null) : "profiles must be anchored";
+    }
+
+    public AnchoringNode getAnchor() {
+        return anchor;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java
new file mode 100644
index 0000000..e2f52ba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_10, size = SIZE_8)
+public final class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+
+    public static final NodeClass<LoadExceptionObjectNode> TYPE = NodeClass.create(LoadExceptionObjectNode.class);
+
+    public LoadExceptionObjectNode(Stamp stamp) {
+        super(TYPE, stamp);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java
new file mode 100644
index 0000000..c3c1472
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * The {@code LoadFieldNode} represents a read of a static or instance field.
+ */
+@NodeInfo(nameTemplate = "LoadField#{p#field/s}")
+public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary<ValueNode>, Virtualizable, UncheckedInterfaceProvider {
+
+    public static final NodeClass<LoadFieldNode> TYPE = NodeClass.create(LoadFieldNode.class);
+
+    private final Stamp uncheckedStamp;
+
+    protected LoadFieldNode(StampPair stamp, ValueNode object, ResolvedJavaField field) {
+        super(TYPE, stamp.getTrustedStamp(), object, field);
+        this.uncheckedStamp = stamp.getUncheckedStamp();
+    }
+
+    public static LoadFieldNode create(Assumptions assumptions, ValueNode object, ResolvedJavaField field) {
+        return new LoadFieldNode(StampFactory.forDeclaredType(assumptions, field.getType(), false), object, field);
+    }
+
+    public static LoadFieldNode createOverrideStamp(StampPair stamp, ValueNode object, ResolvedJavaField field) {
+        return new LoadFieldNode(stamp, object, field);
+    }
+
+    @Override
+    public ValueNode getValue() {
+        return object();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) {
+        if (tool.allUsagesAvailable() && hasNoUsages() && !isVolatile() && (isStatic() || StampTool.isPointerNonNull(forObject.stamp()))) {
+            return null;
+        }
+        MetaAccessProvider metaAccess = tool.getMetaAccess();
+        if (tool.canonicalizeReads() && metaAccess != null) {
+            ConstantNode constant = asConstant(tool, forObject);
+            if (constant != null) {
+                return constant;
+            }
+            if (tool.allUsagesAvailable()) {
+                PhiNode phi = asPhi(tool, forObject);
+                if (phi != null) {
+                    return phi;
+                }
+            }
+        }
+        if (!isStatic() && forObject.isNullConstant()) {
+            return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
+        }
+        return this;
+    }
+
+    /**
+     * Gets a constant value for this load if possible.
+     */
+    public ConstantNode asConstant(CanonicalizerTool tool, ValueNode forObject) {
+        if (isStatic()) {
+            return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), null);
+        } else if (forObject.isConstant() && !forObject.isNullConstant()) {
+            return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), forObject.asJavaConstant());
+        }
+        return null;
+    }
+
+    public ConstantNode asConstant(CanonicalizerTool tool, JavaConstant constant) {
+        return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant);
+    }
+
+    private PhiNode asPhi(CanonicalizerTool tool, ValueNode forObject) {
+        if (!isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
+            PhiNode phi = (PhiNode) forObject;
+            ConstantNode[] constantNodes = new ConstantNode[phi.valueCount()];
+            for (int i = 0; i < phi.valueCount(); i++) {
+                ConstantNode constant = ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), phi.valueAt(i).asJavaConstant());
+                if (constant == null) {
+                    return null;
+                }
+                constantNodes[i] = constant;
+            }
+            return new ValuePhiNode(stamp(), phi.merge(), constantNodes);
+        }
+        return null;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            int fieldIndex = ((VirtualInstanceNode) alias).fieldIndex(field());
+            if (fieldIndex != -1) {
+                tool.replaceWith(tool.getEntry((VirtualObjectNode) alias, fieldIndex));
+            }
+        }
+    }
+
+    @Override
+    public Stamp uncheckedStamp() {
+        return uncheckedStamp;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java
new file mode 100644
index 0000000..1899396
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code LoadIndexedNode} represents a read from an element of an array.
+ */
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
+public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable, Canonicalizable {
+
+    public static final NodeClass<LoadIndexedNode> TYPE = NodeClass.create(LoadIndexedNode.class);
+
+    /**
+     * Creates a new LoadIndexedNode.
+     *
+     * @param array the instruction producing the array
+     * @param index the instruction producing the index
+     * @param elementKind the element type
+     */
+    public LoadIndexedNode(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind) {
+        this(TYPE, createStamp(assumptions, array, elementKind), array, index, elementKind);
+    }
+
+    public static ValueNode create(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        ValueNode constant = tryConstantFold(array, index, metaAccess, constantReflection);
+        if (constant != null) {
+            return constant;
+        }
+        return new LoadIndexedNode(assumptions, array, index, elementKind);
+    }
+
+    protected LoadIndexedNode(NodeClass<? extends LoadIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, JavaKind elementKind) {
+        super(c, stamp, array, index, elementKind);
+    }
+
+    private static Stamp createStamp(Assumptions assumptions, ValueNode array, JavaKind kind) {
+        ResolvedJavaType type = StampTool.typeOrNull(array);
+        if (kind == JavaKind.Object && type != null && type.isArray()) {
+            return StampFactory.object(TypeReference.createTrusted(assumptions, type.getComponentType()));
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(createStamp(graph().getAssumptions(), array(), elementKind()));
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(array());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualArrayNode virtual = (VirtualArrayNode) alias;
+            ValueNode indexValue = tool.getAlias(index());
+            int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1;
+            if (idx >= 0 && idx < virtual.entryCount()) {
+                tool.replaceWith(tool.getEntry(virtual, idx));
+            }
+        }
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode constant = tryConstantFold(array(), index(), tool.getMetaAccess(), tool.getConstantReflection());
+        if (constant != null) {
+            return constant;
+        }
+        return this;
+    }
+
+    private static ValueNode tryConstantFold(ValueNode array, ValueNode index, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        if (array.isConstant() && !array.isNullConstant() && index.isConstant()) {
+            JavaConstant arrayConstant = array.asJavaConstant();
+            if (arrayConstant != null) {
+                int stableDimension = ((ConstantNode) array).getStableDimension();
+                if (stableDimension > 0) {
+                    JavaConstant constant = constantReflection.readArrayElement(arrayConstant, index.asJavaConstant().asInt());
+                    boolean isDefaultStable = ((ConstantNode) array).isDefaultStable();
+                    if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
+                        return ConstantNode.forConstant(constant, stableDimension - 1, isDefaultStable, metaAccess);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java
new file mode 100644
index 0000000..8c543cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+import sun.misc.Unsafe;
+
+/**
+ * Represents the lowered version of an atomic read-and-write operation like
+ * {@link Unsafe#getAndSetInt(Object, long, int)} .
+ */
+@NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_8, size = SIZE_2)
+public final class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<LoweredAtomicReadAndWriteNode> TYPE = NodeClass.create(LoweredAtomicReadAndWriteNode.class);
+    @Input ValueNode newValue;
+    @OptionalInput(State) FrameState stateAfter;
+
+    public LoweredAtomicReadAndWriteNode(AddressNode address, LocationIdentity location, ValueNode newValue, BarrierType barrierType) {
+        super(TYPE, address, location, newValue.stamp().unrestricted(), barrierType);
+        this.newValue = newValue;
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(gen.operand(getAddress()), gen.operand(getNewValue()));
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return false;
+    }
+
+    public ValueNode getNewValue() {
+        return newValue;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredCompareAndSwapNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredCompareAndSwapNode.java
new file mode 100644
index 0000000..c130ff2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredCompareAndSwapNode.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.InputType.Value;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
+ */
+@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_30, size = SIZE_8)
+public final class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+
+    public static final NodeClass<LoweredCompareAndSwapNode> TYPE = NodeClass.create(LoweredCompareAndSwapNode.class);
+    @Input ValueNode expectedValue;
+    @Input ValueNode newValue;
+    @OptionalInput(State) FrameState stateAfter;
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode getExpectedValue() {
+        return expectedValue;
+    }
+
+    public ValueNode getNewValue() {
+        return newValue;
+    }
+
+    public LoweredCompareAndSwapNode(AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) {
+        super(TYPE, address, location, StampFactory.forKind(JavaKind.Boolean.getStackKind()), barrierType);
+        assert expectedValue.getStackKind() == newValue.getStackKind();
+        this.expectedValue = expectedValue;
+        this.newValue = newValue;
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return false;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert getNewValue().stamp().isCompatible(getExpectedValue().stamp());
+        LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+
+        LIRKind resultKind = tool.getLIRKind(stamp());
+        Value trueResult = tool.emitConstant(resultKind, JavaConstant.TRUE);
+        Value falseResult = tool.emitConstant(resultKind, JavaConstant.FALSE);
+        Value result = tool.emitCompareAndSwap(gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue()), trueResult, falseResult);
+
+        gen.setResult(this, result);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java
new file mode 100644
index 0000000..3ab929c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo
+public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Simplifiable {
+    public static final NodeClass<MethodCallTargetNode> TYPE = NodeClass.create(MethodCallTargetNode.class);
+    protected JavaTypeProfile profile;
+
+    public MethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp, JavaTypeProfile profile) {
+        this(TYPE, invokeKind, targetMethod, arguments, returnStamp, profile);
+    }
+
+    protected MethodCallTargetNode(NodeClass<? extends MethodCallTargetNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp,
+                    JavaTypeProfile profile) {
+        super(c, arguments, targetMethod, invokeKind, returnStamp);
+        this.profile = profile;
+    }
+
+    /**
+     * Gets the instruction that produces the receiver object for this invocation, if any.
+     *
+     * @return the instruction that produces the receiver object for this invocation if any,
+     *         {@code null} if this invocation does not take a receiver object
+     */
+    public ValueNode receiver() {
+        return isStatic() ? null : arguments().get(0);
+    }
+
+    /**
+     * Checks whether this is an invocation of a static method.
+     *
+     * @return {@code true} if the invocation is a static invocation
+     */
+    public boolean isStatic() {
+        return invokeKind() == InvokeKind.Static;
+    }
+
+    public JavaKind returnKind() {
+        return targetMethod().getSignature().getReturnKind();
+    }
+
+    public Invoke invoke() {
+        return (Invoke) this.usages().first();
+    }
+
+    @Override
+    public boolean verify() {
+        assert getUsageCount() <= 1 : "call target may only be used by a single invoke";
+        for (Node n : usages()) {
+            assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n);
+        }
+        if (invokeKind().isDirect()) {
+            assertTrue(targetMethod().isConcrete(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod());
+        }
+        if (invokeKind() == InvokeKind.Static) {
+            assertTrue(targetMethod().isStatic(), "static calls are only allowed for static methods (%s)", targetMethod());
+        } else {
+            assertFalse(targetMethod().isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod());
+        }
+        return super.verify();
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Long) {
+            return super.toString(Verbosity.Short) + "(" + targetMethod() + ")";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    public static ResolvedJavaMethod findSpecialCallTarget(InvokeKind invokeKind, ValueNode receiver, ResolvedJavaMethod targetMethod, ResolvedJavaType contextType) {
+        if (invokeKind.isDirect()) {
+            return null;
+        }
+
+        // check for trivial cases (e.g. final methods, nonvirtual methods)
+        if (targetMethod.canBeStaticallyBound()) {
+            return targetMethod;
+        }
+
+        Assumptions assumptions = receiver.graph().getAssumptions();
+        TypeReference type = StampTool.typeReferenceOrNull(receiver);
+        if (type == null && invokeKind == InvokeKind.Virtual) {
+            // For virtual calls, we are guaranteed to receive a correct receiver type.
+            type = TypeReference.createTrusted(assumptions, targetMethod.getDeclaringClass());
+        }
+
+        if (type != null) {
+            /*
+             * either the holder class is exact, or the receiver object has an exact type, or it's
+             * an array type
+             */
+            ResolvedJavaMethod resolvedMethod = type.getType().resolveConcreteMethod(targetMethod, contextType);
+            if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || type.isExact() || type.getType().isArray())) {
+                return resolvedMethod;
+            }
+
+            AssumptionResult<ResolvedJavaMethod> uniqueConcreteMethod = type.getType().findUniqueConcreteMethod(targetMethod);
+            if (uniqueConcreteMethod != null && uniqueConcreteMethod.canRecordTo(assumptions)) {
+                uniqueConcreteMethod.recordTo(assumptions);
+                return uniqueConcreteMethod.getResult();
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        // attempt to devirtualize the call
+        if (invoke().getContextMethod() == null) {
+            // avoid invokes that have placeholder bcis: they do not have a valid contextType
+            assert (invoke().stateAfter() != null && BytecodeFrame.isPlaceholderBci(invoke().stateAfter().bci)) || BytecodeFrame.isPlaceholderBci(invoke().stateDuring().bci);
+            return;
+        }
+        ResolvedJavaType contextType = (invoke().stateAfter() == null && invoke().stateDuring() == null) ? null : invoke().getContextType();
+        ResolvedJavaMethod specialCallTarget = findSpecialCallTarget(invokeKind, receiver(), targetMethod, contextType);
+        if (specialCallTarget != null) {
+            this.setTargetMethod(specialCallTarget);
+            setInvokeKind(InvokeKind.Special);
+            return;
+        }
+
+        Assumptions assumptions = graph().getAssumptions();
+        /*
+         * Even though we are not registering an assumption (see comment below), the optimization is
+         * only valid when speculative optimizations are enabled.
+         */
+        if (invokeKind().isIndirect() && invokeKind().isInterface() && assumptions != null) {
+
+            // check if the type of the receiver can narrow the result
+            ValueNode receiver = receiver();
+
+            // try to turn a interface call into a virtual call
+            ResolvedJavaType declaredReceiverType = targetMethod().getDeclaringClass();
+
+            /*
+             * We need to check the invoke kind to avoid recursive simplification for virtual
+             * interface methods calls.
+             */
+            if (declaredReceiverType.isInterface()) {
+                ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
+                if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
+                    TypeReference speculatedType = TypeReference.createTrusted(assumptions, singleImplementor);
+                    if (tryCheckCastSingleImplementor(receiver, speculatedType)) {
+                        return;
+                    }
+                }
+            }
+
+            if (receiver instanceof UncheckedInterfaceProvider) {
+                UncheckedInterfaceProvider uncheckedInterfaceProvider = (UncheckedInterfaceProvider) receiver;
+                Stamp uncheckedStamp = uncheckedInterfaceProvider.uncheckedStamp();
+                if (uncheckedStamp != null) {
+                    TypeReference speculatedType = StampTool.typeReferenceOrNull(uncheckedStamp);
+                    if (speculatedType != null) {
+                        tryCheckCastSingleImplementor(receiver, speculatedType);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean tryCheckCastSingleImplementor(ValueNode receiver, TypeReference speculatedType) {
+        ResolvedJavaType singleImplementor = speculatedType.getType();
+        if (singleImplementor != null) {
+            ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveConcreteMethod(targetMethod(), invoke().getContextType());
+            if (singleImplementorMethod != null) {
+                /**
+                 * We have an invoke on an interface with a single implementor. We can replace this
+                 * with an invoke virtual.
+                 *
+                 * To do so we need to ensure two properties: 1) the receiver must implement the
+                 * interface (declaredReceiverType). The verifier does not prove this so we need a
+                 * dynamic check. 2) we need to ensure that there is still only one implementor of
+                 * this interface, i.e. that we are calling the right method. We could do this with
+                 * an assumption but as we need an instanceof check anyway we can verify both
+                 * properties by checking of the receiver is an instance of the single implementor.
+                 */
+                ValueAnchorNode anchor = new ValueAnchorNode(null);
+                if (anchor != null) {
+                    graph().add(anchor);
+                    graph().addBeforeFixed(invoke().asNode(), anchor);
+                }
+                LogicNode condition = graph().addOrUniqueWithInputs(InstanceOfNode.create(speculatedType, receiver, getProfile(), anchor));
+                FixedGuardNode guard = graph().add(new FixedGuardNode(condition, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, false));
+                graph().addBeforeFixed(invoke().asNode(), guard);
+                PiNode piNode = graph().unique(new PiNode(receiver, StampFactory.objectNonNull(speculatedType), guard));
+                arguments().set(0, piNode);
+                if (speculatedType.isExact()) {
+                    setInvokeKind(InvokeKind.Special);
+                } else {
+                    setInvokeKind(InvokeKind.Virtual);
+                }
+                setTargetMethod(singleImplementorMethod);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public JavaTypeProfile getProfile() {
+        return profile;
+    }
+
+    @Override
+    public String targetName() {
+        if (targetMethod() == null) {
+            return "??Invalid!";
+        }
+        return targetMethod().format("%h.%n");
+    }
+
+    public static MethodCallTargetNode find(StructuredGraph graph, ResolvedJavaMethod method) {
+        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            if (target.targetMethod().equals(method)) {
+                return target;
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java
new file mode 100644
index 0000000..d2b0149
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.MonitorEnter;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * The {@code MonitorEnterNode} represents the acquisition of a monitor.
+ */
+@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+public class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
+
+    public static final NodeClass<MonitorEnterNode> TYPE = NodeClass.create(MonitorEnterNode.class);
+
+    public MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
+        this(TYPE, object, monitorId);
+    }
+
+    public MonitorEnterNode(NodeClass<? extends MonitorEnterNode> c, ValueNode object, MonitorIdNode monitorId) {
+        super(c, object, monitorId);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                tool.addLock(virtual, getMonitorId());
+                tool.delete();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java
new file mode 100644
index 0000000..ca3f2db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.MonitorExit;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of
+ * a synchronized method, then the return value of the method will be referenced via the edge
+ * {@link #escapedReturnValue}, so that it will be materialized before releasing the monitor.
+ */
+@NodeInfo(cycles = CYCLES_50, size = SIZE_100)
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single {
+
+    public static final NodeClass<MonitorExitNode> TYPE = NodeClass.create(MonitorExitNode.class);
+
+    /**
+     * Non-null for the monitor exit introduced due to a synchronized root method and null in all
+     * other cases.
+     */
+    @OptionalInput ValueNode escapedReturnValue;
+
+    public MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
+        super(TYPE, object, monitorId);
+        this.escapedReturnValue = escapedReturnValue;
+    }
+
+    /**
+     * Return value is cleared when a synchronized method graph is inlined.
+     */
+    public void clearEscapedReturnValue() {
+        updateUsages(escapedReturnValue, null);
+        this.escapedReturnValue = null;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                MonitorIdNode removedLock = tool.removeLock(virtual);
+                assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
+                tool.delete();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java
new file mode 100644
index 0000000..daeb9ed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * This node describes one locking scope; it ties the monitor enter, monitor exit and the frame
+ * states together. It is thus referenced from the {@link MonitorEnterNode}, from the
+ * {@link MonitorExitNode} and from the {@link FrameState}.
+ */
+@NodeInfo(allowedUsageTypes = Association, cycles = CYCLES_0, size = SIZE_0)
+public class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable {
+
+    public static final NodeClass<MonitorIdNode> TYPE = NodeClass.create(MonitorIdNode.class);
+    protected int lockDepth;
+
+    public MonitorIdNode(int lockDepth) {
+        this(TYPE, lockDepth);
+    }
+
+    protected MonitorIdNode(NodeClass<? extends MonitorIdNode> c, int lockDepth) {
+        super(c, StampFactory.forVoid());
+        this.lockDepth = lockDepth;
+    }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // nothing to do
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java
new file mode 100644
index 0000000..c6bfed4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code NewArrayNode} is used for all array allocations where the element type is know at
+ * compile time.
+ */
+// JaCoCo Exclude
+@NodeInfo
+public class NewArrayNode extends AbstractNewArrayNode implements VirtualizableAllocation {
+
+    public static final NodeClass<NewArrayNode> TYPE = NodeClass.create(NewArrayNode.class);
+    private final ResolvedJavaType elementType;
+
+    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+        this(elementType, length, fillContents, null);
+    }
+
+    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents, FrameState stateBefore) {
+        this(TYPE, elementType, length, fillContents, stateBefore);
+    }
+
+    protected NewArrayNode(NodeClass<? extends NewArrayNode> c, ResolvedJavaType elementType, ValueNode length, boolean fillContents, FrameState stateBefore) {
+        super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(elementType.getArrayClass())), length, fillContents, stateBefore);
+        this.elementType = elementType;
+    }
+
+    @NodeIntrinsic
+    private static native Object newArray(@ConstantNodeParameter Class<?> elementType, int length, @ConstantNodeParameter boolean fillContents);
+
+    public static Object newUninitializedArray(Class<?> elementType, int length) {
+        return newArray(elementType, length, false);
+    }
+
+    /**
+     * Gets the element type of the array.
+     *
+     * @return the element type of the array
+     */
+    public ResolvedJavaType elementType() {
+        return elementType;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode lengthAlias = tool.getAlias(length());
+        if (lengthAlias.asConstant() != null) {
+            int constantLength = lengthAlias.asJavaConstant().asInt();
+            if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) {
+                ValueNode[] state = new ValueNode[constantLength];
+                ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue();
+                for (int i = 0; i < constantLength; i++) {
+                    state[i] = defaultForKind;
+                }
+                VirtualObjectNode virtualObject = createVirtualArrayNode(constantLength);
+                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
+                tool.replaceWithVirtual(virtualObject);
+            }
+        }
+    }
+
+    protected VirtualArrayNode createVirtualArrayNode(int constantLength) {
+        return new VirtualArrayNode(elementType(), constantLength);
+    }
+
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultElementValue() {
+        return ConstantNode.defaultForKind(elementType().getJavaKind(), graph());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java
new file mode 100644
index 0000000..c5fed6b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import java.lang.ref.Reference;
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code NewInstanceNode} represents the allocation of an instance class object.
+ */
+@NodeInfo(nameTemplate = "New {p#instanceClass/s}")
+public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
+
+    public static final NodeClass<NewInstanceNode> TYPE = NodeClass.create(NewInstanceNode.class);
+    protected final ResolvedJavaType instanceClass;
+
+    public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
+        this(TYPE, type, fillContents, null);
+    }
+
+    public NewInstanceNode(ResolvedJavaType type, boolean fillContents, FrameState stateBefore) {
+        this(TYPE, type, fillContents, stateBefore);
+    }
+
+    protected NewInstanceNode(NodeClass<? extends NewInstanceNode> c, ResolvedJavaType type, boolean fillContents, FrameState stateBefore) {
+        super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(type)), fillContents, stateBefore);
+        assert !type.isArray() && !type.isInterface() && !type.isPrimitive();
+        this.instanceClass = type;
+    }
+
+    /**
+     * Gets the instance class being allocated by this node.
+     *
+     * @return the instance class allocated
+     */
+    public ResolvedJavaType instanceClass() {
+        return instanceClass;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        /*
+         * Reference objects can escape into their ReferenceQueue at any safepoint, therefore
+         * they're excluded from escape analysis.
+         */
+        if (!tool.getMetaAccessProvider().lookupJavaType(Reference.class).isAssignableFrom(instanceClass)) {
+            VirtualInstanceNode virtualObject = createVirtualInstanceNode(true);
+            ResolvedJavaField[] fields = virtualObject.getFields();
+            ValueNode[] state = new ValueNode[fields.length];
+            for (int i = 0; i < state.length; i++) {
+                state[i] = defaultFieldValue(fields[i]);
+            }
+            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
+            tool.replaceWithVirtual(virtualObject);
+        }
+    }
+
+    protected VirtualInstanceNode createVirtualInstanceNode(boolean hasIdentity) {
+        return new VirtualInstanceNode(instanceClass(), hasIdentity);
+    }
+
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultFieldValue(ResolvedJavaField field) {
+        return ConstantNode.defaultForKind(field.getType().getJavaKind(), graph());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java
new file mode 100644
index 0000000..b1cc8d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array.
+ */
+@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
+
+    public static final NodeClass<NewMultiArrayNode> TYPE = NodeClass.create(NewMultiArrayNode.class);
+    @Input protected NodeInputList<ValueNode> dimensions;
+    protected final ResolvedJavaType type;
+
+    public ValueNode dimension(int index) {
+        return dimensions.get(index);
+    }
+
+    public int dimensionCount() {
+        return dimensions.size();
+    }
+
+    public NodeList<ValueNode> dimensions() {
+        return dimensions;
+    }
+
+    public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) {
+        this(TYPE, type, dimensions);
+    }
+
+    protected NewMultiArrayNode(NodeClass<? extends NewMultiArrayNode> c, ResolvedJavaType type, ValueNode[] dimensions) {
+        super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(type)));
+        this.type = type;
+        this.dimensions = new NodeInputList<>(this, dimensions);
+        assert dimensions.length > 0 && type.isArray();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public ValueNode length() {
+        return dimension(0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java
new file mode 100644
index 0000000..660b3bf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.MonitorEnter;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * The {@code RawMonitorEnterNode} represents the acquisition of a monitor. The object needs to
+ * already be non-null and the hub is an additional parameter to the node.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_80,
+          cyclesRationale = "Rough estimation of the enter operation",
+          size = SIZE_80)
+// @formatter:on
+public final class RawMonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
+
+    public static final NodeClass<RawMonitorEnterNode> TYPE = NodeClass.create(RawMonitorEnterNode.class);
+
+    @Input ValueNode hub;
+
+    public RawMonitorEnterNode(ValueNode object, ValueNode hub, MonitorIdNode monitorId) {
+        super(TYPE, object, monitorId);
+        assert ((ObjectStamp) object.stamp()).nonNull();
+        this.hub = hub;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual.hasIdentity()) {
+                tool.addLock(virtual, getMonitorId());
+                tool.delete();
+            }
+        }
+    }
+
+    public ValueNode getHub() {
+        return hub;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RegisterFinalizerNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RegisterFinalizerNode.java
new file mode 100644
index 0000000..30dd9db
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RegisterFinalizerNode.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+
+/**
+ * This node is used to perform the finalizer registration at the end of the java.lang.Object
+ * constructor.
+ */
+// @formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "We cannot estimate the time of a runtime call.",
+          size = SIZE_20,
+          sizeRationale = "Rough estimation for register handling & calling")
+// @formatter:on
+public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable.Unary<ValueNode>, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
+
+    public static final NodeClass<RegisterFinalizerNode> TYPE = NodeClass.create(RegisterFinalizerNode.class);
+    @OptionalInput(State) FrameState deoptState;
+    @Input ValueNode value;
+
+    public RegisterFinalizerNode(ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+    }
+
+    @Override
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // Note that an unconditional call to the runtime routine is made without
+        // checking that the object actually has a finalizer. This requires the
+        // runtime routine to do the check.
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue()));
+    }
+
+    /**
+     * Determines if the compiler should emit code to test whether a given object has a finalizer
+     * that must be registered with the runtime upon object initialization.
+     */
+    public static boolean mayHaveFinalizer(ValueNode object, Assumptions assumptions) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        if (objectStamp.isExactType()) {
+            return objectStamp.type().hasFinalizer();
+        } else if (objectStamp.type() != null) {
+            AssumptionResult<Boolean> result = objectStamp.type().hasFinalizableSubclass();
+            if (result.canRecordTo(assumptions)) {
+                result.recordTo(assumptions);
+                return result.getResult();
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (!(forValue.stamp() instanceof ObjectStamp)) {
+            return this;
+        }
+        if (!mayHaveFinalizer(forValue, graph().getAssumptions())) {
+            return null;
+        }
+
+        return this;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(getValue());
+        if (alias instanceof VirtualObjectNode && !((VirtualObjectNode) alias).type().hasFinalizer()) {
+            tool.delete();
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @NodeIntrinsic
+    public static native void register(Object thisObj);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java
new file mode 100644
index 0000000..3990a09
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+/**
+ * The {@code StoreFieldNode} represents a write to a static or instance field.
+ */
+@NodeInfo(nameTemplate = "StoreField#{p#field/s}")
+public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable {
+    public static final NodeClass<StoreFieldNode> TYPE = NodeClass.create(StoreFieldNode.class);
+
+    @Input ValueNode value;
+    @OptionalInput(InputType.State) FrameState stateAfter;
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value) {
+        super(TYPE, StampFactory.forVoid(), object, field);
+        this.value = value;
+    }
+
+    public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) {
+        super(TYPE, StampFactory.forVoid(), object, field);
+        this.value = value;
+        this.stateAfter = stateAfter;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object());
+        if (alias instanceof VirtualObjectNode) {
+            VirtualInstanceNode virtual = (VirtualInstanceNode) alias;
+            int fieldIndex = virtual.fieldIndex(field());
+            if (fieldIndex != -1) {
+                tool.setVirtualEntry(virtual, fieldIndex, value(), false);
+                tool.delete();
+            }
+        }
+    }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java
new file mode 100644
index 0000000..04e6fb4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code StoreIndexedNode} represents a write to an array element.
+ */
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
+public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable {
+
+    public static final NodeClass<StoreIndexedNode> TYPE = NodeClass.create(StoreIndexedNode.class);
+    @Input ValueNode value;
+    @OptionalInput(State) FrameState stateAfter;
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public StoreIndexedNode(ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        super(TYPE, StampFactory.forVoid(), array, index, elementKind);
+        this.value = value;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(array());
+        if (alias instanceof VirtualObjectNode) {
+            ValueNode indexValue = tool.getAlias(index());
+            int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1;
+            VirtualArrayNode virtual = (VirtualArrayNode) alias;
+            if (idx >= 0 && idx < virtual.entryCount()) {
+                ResolvedJavaType componentType = virtual.type().getComponentType();
+                if (componentType.isPrimitive() || StampTool.isPointerAlwaysNull(value) || componentType.getSuperclass() == null ||
+                                (StampTool.typeReferenceOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) {
+                    tool.setVirtualEntry(virtual, idx, value(), false);
+                    tool.delete();
+                }
+            }
+        }
+    }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/TypeSwitchNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/TypeSwitchNode.java
new file mode 100644
index 0000000..faca857
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/TypeSwitchNode.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.java;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * The {@code TypeSwitchNode} performs a lookup based on the type of the input value. The type
+ * comparison is an exact type comparison, not an instanceof.
+ */
+@NodeInfo
+public final class TypeSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+
+    public static final NodeClass<TypeSwitchNode> TYPE = NodeClass.create(TypeSwitchNode.class);
+    protected final ResolvedJavaType[] keys;
+    protected final Constant[] hubs;
+
+    public TypeSwitchNode(ValueNode value, AbstractBeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors, ConstantReflectionProvider constantReflection) {
+        super(TYPE, value, successors, keySuccessors, keyProbabilities);
+        assert successors.length <= keys.length + 1;
+        assert keySuccessors.length == keyProbabilities.length;
+        this.keys = keys;
+        assert value.stamp() instanceof AbstractPointerStamp;
+        assert assertKeys();
+
+        hubs = new Constant[keys.length];
+        for (int i = 0; i < hubs.length; i++) {
+            hubs[i] = constantReflection.asObjectHub(keys[i]);
+        }
+    }
+
+    /**
+     * Don't allow duplicate keys.
+     */
+    private boolean assertKeys() {
+        for (int i = 0; i < keys.length; i++) {
+            for (int j = 0; j < keys.length; j++) {
+                if (i == j) {
+                    continue;
+                }
+                assert !keys[i].equals(keys[j]);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isSorted() {
+        return false;
+    }
+
+    @Override
+    public int keyCount() {
+        return keys.length;
+    }
+
+    @Override
+    public Constant keyAt(int index) {
+        return hubs[index];
+    }
+
+    @Override
+    public boolean equalKeys(SwitchNode switchNode) {
+        if (!(switchNode instanceof TypeSwitchNode)) {
+            return false;
+        }
+        TypeSwitchNode other = (TypeSwitchNode) switchNode;
+        return Arrays.equals(keys, other.keys);
+    }
+
+    public ResolvedJavaType typeAt(int index) {
+        return keys[index];
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        gen.emitSwitch(this);
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (value() instanceof ConstantNode) {
+            Constant constant = value().asConstant();
+
+            int survivingEdge = keySuccessorIndex(keyCount());
+            for (int i = 0; i < keyCount(); i++) {
+                Constant typeHub = keyAt(i);
+                Boolean equal = tool.getConstantReflection().constantEquals(constant, typeHub);
+                if (equal == null) {
+                    /* We don't know if this key is a match or not, so we cannot simplify. */
+                    return;
+                } else if (equal.booleanValue()) {
+                    survivingEdge = keySuccessorIndex(i);
+                }
+            }
+            killOtherSuccessors(tool, survivingEdge);
+        }
+        if (value() instanceof LoadHubNode && ((LoadHubNode) value()).getValue().stamp() instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) ((LoadHubNode) value()).getValue().stamp();
+            if (objectStamp.type() != null) {
+                int validKeys = 0;
+                for (int i = 0; i < keyCount(); i++) {
+                    if (objectStamp.type().isAssignableFrom(keys[i])) {
+                        validKeys++;
+                    }
+                }
+                if (validKeys == 0) {
+                    tool.addToWorkList(defaultSuccessor());
+                    graph().removeSplitPropagate(this, defaultSuccessor());
+                } else if (validKeys != keys.length) {
+                    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+                    ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys];
+                    int[] newKeySuccessors = new int[validKeys + 1];
+                    double[] newKeyProbabilities = new double[validKeys + 1];
+                    double totalProbability = 0;
+                    int current = 0;
+                    for (int i = 0; i < keyCount() + 1; i++) {
+                        if (i == keyCount() || objectStamp.type().isAssignableFrom(keys[i])) {
+                            int index = newSuccessors.indexOf(keySuccessor(i));
+                            if (index == -1) {
+                                index = newSuccessors.size();
+                                newSuccessors.add(keySuccessor(i));
+                            }
+                            newKeySuccessors[current] = index;
+                            if (i < keyCount()) {
+                                newKeys[current] = keys[i];
+                            }
+                            newKeyProbabilities[current] = keyProbability(i);
+                            totalProbability += keyProbability(i);
+                            current++;
+                        }
+                    }
+                    if (totalProbability > 0) {
+                        for (int i = 0; i < current; i++) {
+                            newKeyProbabilities[i] /= totalProbability;
+                        }
+                    } else {
+                        for (int i = 0; i < current; i++) {
+                            newKeyProbabilities[i] = 1.0 / current;
+                        }
+                    }
+
+                    for (int i = 0; i < blockSuccessorCount(); i++) {
+                        AbstractBeginNode successor = blockSuccessor(i);
+                        if (!newSuccessors.contains(successor)) {
+                            tool.deleteBranch(successor);
+                        }
+                        setBlockSuccessor(i, null);
+                    }
+
+                    AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
+                    TypeSwitchNode newSwitch = graph().add(new TypeSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors, tool.getConstantReflection()));
+                    ((FixedWithNextNode) predecessor()).setNext(newSwitch);
+                    GraphUtil.killWithUnusedFloatingInputs(this);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractMemoryCheckpoint.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractMemoryCheckpoint.java
new file mode 100644
index 0000000..df3722a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractMemoryCheckpoint.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+@NodeInfo
+public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
+
+    public static final NodeClass<AbstractMemoryCheckpoint> TYPE = NodeClass.create(AbstractMemoryCheckpoint.class);
+
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp) {
+        this(c, stamp, null);
+    }
+
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp, FrameState stateAfter) {
+        super(c, stamp, stateAfter);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java
new file mode 100644
index 0000000..c7b8e80
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Guard}, cycles = CYCLES_3, size = SIZE_1)
+public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
+
+    public static final NodeClass<AbstractWriteNode> TYPE = NodeClass.create(AbstractWriteNode.class);
+    @Input ValueNode value;
+    @OptionalInput(InputType.State) FrameState stateAfter;
+    @OptionalInput(InputType.Memory) Node lastLocationAccess;
+
+    protected final boolean initialization;
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    /**
+     * Returns whether this write is the initialization of the written location. If it is true, the
+     * old value of the memory location is either uninitialized or zero. If it is false, the memory
+     * location is guaranteed to contain a valid value or zero.
+     */
+    public boolean isInitialization() {
+        return initialization;
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+        this(c, address, location, value, barrierType, false);
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, boolean initialization) {
+        super(c, address, location, StampFactory.forVoid(), barrierType);
+        this.value = value;
+        this.initialization = initialization;
+    }
+
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, GuardingNode guard,
+                    boolean initialization) {
+        super(c, address, location, StampFactory.forVoid(), guard, barrierType, false, null);
+        this.value = value;
+        this.initialization = initialization;
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type);
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return (MemoryNode) lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        Node newLla = ValueNodeUtil.asNode(lla);
+        updateUsages(lastLocationAccess, newLla);
+        lastLocationAccess = newLla;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java
new file mode 100644
index 0000000..488d10f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+public interface Access extends GuardedNode, HeapAccess {
+
+    AddressNode getAddress();
+
+    LocationIdentity getLocationIdentity();
+
+    boolean canNullCheck();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java
new file mode 100644
index 0000000..9adc78e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+/**
+ * Accesses a value at an memory address specified by an {@linkplain #address address}. The access
+ * does not include a null check on the object.
+ */
+@NodeInfo
+public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access {
+    public static final NodeClass<FixedAccessNode> TYPE = NodeClass.create(FixedAccessNode.class);
+
+    @OptionalInput(InputType.Guard) protected GuardingNode guard;
+
+    @Input(InputType.Association) AddressNode address;
+    protected final LocationIdentity location;
+
+    protected boolean nullCheck;
+    protected BarrierType barrierType;
+
+    @Override
+    public AddressNode getAddress() {
+        return address;
+    }
+
+    public void setAddress(AddressNode address) {
+        updateUsages(this.address, address);
+        this.address = address;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return location;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    public void setNullCheck(boolean check) {
+        this.nullCheck = check;
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp) {
+        this(c, address, location, stamp, BarrierType.NONE);
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
+        this(c, address, location, stamp, null, barrierType, false, null);
+    }
+
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, stamp, stateBefore);
+        this.address = address;
+        this.location = location;
+        this.guard = guard;
+        this.barrierType = barrierType;
+        this.nullCheck = nullCheck;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsagesInterface(this.guard, guard);
+        this.guard = guard;
+    }
+
+    @Override
+    public BarrierType getBarrierType() {
+        return barrierType;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java
new file mode 100644
index 0000000..79f9abc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+/**
+ * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}.
+ */
+@NodeInfo
+public abstract class FloatableAccessNode extends FixedAccessNode {
+    public static final NodeClass<FloatableAccessNode> TYPE = NodeClass.create(FloatableAccessNode.class);
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp) {
+        super(c, address, location, stamp);
+    }
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, address, location, stamp, guard, barrierType, false, null);
+    }
+
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType,
+                    boolean nullCheck, FrameState stateBefore) {
+        super(c, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
+    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
+
+    protected boolean forceFixed;
+
+    public void setForceFixed(boolean flag) {
+        this.forceFixed = flag;
+    }
+
+    /**
+     * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in
+     * case G1 is enabled any access (read) to the java.lang.ref.Reference.referent field which has
+     * an attached write barrier with pre-semantics can not also float.
+     */
+    public boolean canFloat() {
+        return !forceFixed && getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java
new file mode 100644
index 0000000..73f39a6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FloatingGuardedNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo
+public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess {
+    public static final NodeClass<FloatingAccessNode> TYPE = NodeClass.create(FloatingAccessNode.class);
+
+    @Input(InputType.Association) AddressNode address;
+    protected final LocationIdentity location;
+
+    protected BarrierType barrierType;
+
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp) {
+        super(c, stamp);
+        this.address = address;
+        this.location = location;
+    }
+
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, stamp, guard);
+        this.address = address;
+        this.location = location;
+        this.barrierType = barrierType;
+    }
+
+    @Override
+    public AddressNode getAddress() {
+        return address;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return location;
+    }
+
+    @Override
+    public BarrierType getBarrierType() {
+        return barrierType;
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return true;
+    }
+
+    public abstract FixedAccessNode asFixedNode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java
new file mode 100644
index 0000000..95be59c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * A floating read of a value from memory specified in terms of an object base and an object
+ * relative location. This node does not null check the object.
+ */
+@NodeInfo(nameTemplate = "Read#{p#location/s}", cycles = CYCLES_2, size = SIZE_1)
+public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable {
+    public static final NodeClass<FloatingReadNode> TYPE = NodeClass.create(FloatingReadNode.class);
+
+    @OptionalInput(Memory) MemoryNode lastLocationAccess;
+
+    public FloatingReadNode(AddressNode address, LocationIdentity location, MemoryNode lastLocationAccess, Stamp stamp) {
+        this(address, location, lastLocationAccess, stamp, null, BarrierType.NONE);
+    }
+
+    public FloatingReadNode(AddressNode address, LocationIdentity location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
+        this(address, location, lastLocationAccess, stamp, guard, BarrierType.NONE);
+    }
+
+    public FloatingReadNode(AddressNode address, LocationIdentity location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(TYPE, address, location, stamp, guard, barrierType);
+        this.lastLocationAccess = lastLocationAccess;
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode newlla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
+        lastLocationAccess = newlla;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitLoad(readKind, gen.operand(address), null));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getAddress() instanceof OffsetAddressNode) {
+            OffsetAddressNode objAddress = (OffsetAddressNode) getAddress();
+            if (objAddress.getBase() instanceof PiNode) {
+                PiNode piBase = (PiNode) objAddress.getBase();
+                /*
+                 * If the Pi and the read have the same guard or the read is unguarded, use the
+                 * guard of the Pi along with the original value. This encourages a canonical form
+                 * guarded reads.
+                 */
+                if (piBase.getGuard() == getGuard() || getGuard() == null) {
+                    OffsetAddressNode newAddress = new OffsetAddressNode(piBase.getOriginalNode(), objAddress.getOffset());
+                    return new FloatingReadNode(newAddress, getLocationIdentity(), getLastLocationAccess(), stamp(), getGuard() == null ? piBase.getGuard() : getGuard(), getBarrierType());
+                }
+            }
+        }
+        return ReadNode.canonicalizeRead(this, getAddress(), getLocationIdentity(), tool);
+    }
+
+    @SuppressWarnings("try")
+    @Override
+    public FixedAccessNode asFixedNode() {
+        try (DebugCloseable position = withNodeSourcePosition()) {
+            return graph().add(new ReadNode(getAddress(), getLocationIdentity(), stamp(), getGuard(), getBarrierType()));
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        MemoryNode lla = getLastLocationAccess();
+        assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity();
+        return super.verify();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java
new file mode 100644
index 0000000..46edaa3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+/**
+ * Encapsulates properties of a node describing how it accesses the heap.
+ */
+public interface HeapAccess {
+
+    /**
+     * The types of (write/read) barriers attached to stores.
+     */
+    enum BarrierType {
+        /**
+         * Primitive stores which do not necessitate barriers.
+         */
+        NONE,
+        /**
+         * Array object stores which necessitate precise barriers.
+         */
+        PRECISE,
+        /**
+         * Field object stores which necessitate imprecise barriers.
+         */
+        IMPRECISE
+    }
+
+    /**
+     * Gets the write barrier type for that particular access.
+     */
+    BarrierType getBarrierType();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java
new file mode 100644
index 0000000..73623dc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+/**
+ * This interface marks nodes that access some memory location, and that have an edge to the last
+ * node that kills this location.
+ */
+public interface MemoryAccess {
+
+    LocationIdentity getLocationIdentity();
+
+    MemoryNode getLastLocationAccess();
+
+    /**
+     * @param lla the {@link MemoryNode} that represents the last kill of the location
+     */
+    void setLastLocationAccess(MemoryNode lla);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAnchorNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAnchorNode.java
new file mode 100644
index 0000000..f6107f4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAnchorNode.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.StructuralInput.Memory;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_0, size = SIZE_0)
+public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
+
+    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
+
+    public MemoryAnchorNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // Nothing to emit, since this node is used for structural purposes only.
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return tool.allUsagesAvailable() && hasNoUsages() ? null : this;
+    }
+
+    @NodeIntrinsic
+    public static native Memory anchor();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java
new file mode 100644
index 0000000..f8f07e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedNodeInterface;
+
+/**
+ * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations
+ * represented by location identities (i.e. change a value at one or more locations that belong to
+ * these location identities).
+ */
+public interface MemoryCheckpoint extends MemoryNode, FixedNodeInterface {
+
+    interface Single extends MemoryCheckpoint {
+
+        /**
+         * This method is used to determine which memory location is killed by this node. Returning
+         * the special value {@link LocationIdentity#any()} will kill all memory locations.
+         *
+         * @return the identity of the location killed by this node.
+         */
+        LocationIdentity getLocationIdentity();
+
+    }
+
+    interface Multi extends MemoryCheckpoint {
+
+        /**
+         * This method is used to determine which set of memory locations is killed by this node.
+         * Returning the special value {@link LocationIdentity#any()} will kill all memory
+         * locations.
+         *
+         * @return the identities of all locations killed by this node.
+         */
+        LocationIdentity[] getLocationIdentities();
+
+    }
+
+    class TypeAssertion {
+
+        public static boolean correctType(Node node) {
+            return !(node instanceof MemoryCheckpoint) || (node instanceof MemoryCheckpoint.Single ^ node instanceof MemoryCheckpoint.Multi);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java
new file mode 100644
index 0000000..980e351
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import java.util.Collection;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+
+/**
+ * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the
+ * location.
+ */
+public interface MemoryMap {
+
+    /**
+     * Gets the last node that that (potentially) wrote to {@code locationIdentity}.
+     */
+    MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
+
+    /**
+     * Gets the location identities in the domain of this map.
+     */
+    Collection<LocationIdentity> getLocations();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java
new file mode 100644
index 0000000..a0e29cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+@NodeInfo(allowedUsageTypes = {Extension, Memory}, cycles = CYCLES_0, size = SIZE_0)
+public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable {
+
+    public static final NodeClass<MemoryMapNode> TYPE = NodeClass.create(MemoryMapNode.class);
+    protected final List<LocationIdentity> locationIdentities;
+    @Input(Memory) NodeInputList<ValueNode> nodes;
+
+    private boolean checkOrder(Map<LocationIdentity, MemoryNode> mmap) {
+        for (int i = 0; i < locationIdentities.size(); i++) {
+            LocationIdentity locationIdentity = locationIdentities.get(i);
+            ValueNode n = nodes.get(i);
+            assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map");
+        }
+        return true;
+    }
+
+    public MemoryMapNode(Map<LocationIdentity, MemoryNode> mmap) {
+        super(TYPE, StampFactory.forVoid());
+        locationIdentities = new ArrayList<>(mmap.keySet());
+        nodes = new NodeInputList<>(this, mmap.values());
+        assert checkOrder(mmap);
+    }
+
+    public boolean isEmpty() {
+        if (locationIdentities.isEmpty()) {
+            return true;
+        }
+        if (locationIdentities.size() == 1) {
+            if (nodes.get(0) instanceof StartNode) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+        if (locationIdentity.isImmutable()) {
+            return null;
+        } else {
+            int index = locationIdentities.indexOf(locationIdentity);
+            if (index == -1) {
+                index = locationIdentities.indexOf(any());
+            }
+            assert index != -1;
+            return (MemoryNode) nodes.get(index);
+        }
+    }
+
+    @Override
+    public Collection<LocationIdentity> getLocations() {
+        return locationIdentities;
+    }
+
+    public Map<LocationIdentity, MemoryNode> toMap() {
+        HashMap<LocationIdentity, MemoryNode> res = CollectionsFactory.newMap(locationIdentities.size());
+        for (int i = 0; i < nodes.size(); i++) {
+            res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i));
+        }
+        return res;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        // nothing to do...
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryNode.java
new file mode 100644
index 0000000..d958c78
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryNode.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+/**
+ * This interface marks nodes that are part of the memory graph.
+ */
+public interface MemoryNode extends ValueNodeInterface {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java
new file mode 100644
index 0000000..3a1513c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * Memory {@code PhiNode}s merge memory dependencies at control flow merges.
+ */
+@NodeInfo(nameTemplate = "Phi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
+public final class MemoryPhiNode extends PhiNode implements MemoryNode {
+
+    public static final NodeClass<MemoryPhiNode> TYPE = NodeClass.create(MemoryPhiNode.class);
+    @Input(InputType.Memory) NodeInputList<ValueNode> values;
+    protected final LocationIdentity locationIdentity;
+
+    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this);
+    }
+
+    public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) {
+        super(TYPE, StampFactory.forVoid(), merge);
+        this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java
new file mode 100644
index 0000000..5bb8a9e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CanonicalizableLocation;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Reads an {@linkplain FixedAccessNode accessed} value.
+ */
+@NodeInfo(nameTemplate = "Read#{p#location/s}", cycles = CYCLES_2, size = SIZE_1)
+public class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, Virtualizable, GuardingNode {
+
+    public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
+
+    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
+        super(TYPE, address, location, stamp, null, barrierType);
+    }
+
+    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(TYPE, address, location, stamp, guard, barrierType);
+    }
+
+    public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+        this(TYPE, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
+    protected ReadNode(NodeClass<? extends ReadNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    }
+
+    public ReadNode(AddressNode address, LocationIdentity location, ValueNode guard, BarrierType barrierType) {
+        /*
+         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
+         * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
+         * type LocationNode.
+         */
+        super(TYPE, address, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+        gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitLoad(readKind, gen.operand(address), gen.state(this)));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            if (getGuard() != null && !(getGuard() instanceof FixedNode)) {
+                // The guard is necessary even if the read goes away.
+                return new ValueAnchorNode((ValueNode) getGuard());
+            } else {
+                // Read without usages or guard can be safely removed.
+                return null;
+            }
+        }
+        if (getAddress() instanceof OffsetAddressNode) {
+            OffsetAddressNode objAddress = (OffsetAddressNode) getAddress();
+            if (objAddress.getBase() instanceof PiNode && ((PiNode) objAddress.getBase()).getGuard() == getGuard()) {
+                OffsetAddressNode newAddress = new OffsetAddressNode(((PiNode) objAddress.getBase()).getOriginalNode(), objAddress.getOffset());
+                return new ReadNode(newAddress, getLocationIdentity(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore());
+            }
+        }
+        if (!getNullCheck()) {
+            return canonicalizeRead(this, getAddress(), getLocationIdentity(), tool);
+        } else {
+            // if this read is a null check, then replacing it with the value is incorrect for
+            // guard-type usages
+            return this;
+        }
+    }
+
+    @SuppressWarnings("try")
+    @Override
+    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
+        try (DebugCloseable position = withNodeSourcePosition()) {
+            return graph().unique(new FloatingReadNode(getAddress(), getLocationIdentity(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
+        }
+    }
+
+    @Override
+    public boolean isAllowedUsageType(InputType type) {
+        return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
+    }
+
+    public static ValueNode canonicalizeRead(ValueNode read, AddressNode address, LocationIdentity locationIdentity, CanonicalizerTool tool) {
+        MetaAccessProvider metaAccess = tool.getMetaAccess();
+        if (tool.canonicalizeReads() && address instanceof OffsetAddressNode) {
+            OffsetAddressNode objAddress = (OffsetAddressNode) address;
+            ValueNode object = objAddress.getBase();
+            if (metaAccess != null && object.isConstant() && !object.isNullConstant() && objAddress.getOffset().isConstant()) {
+                long displacement = objAddress.getOffset().asJavaConstant().asLong();
+                int stableDimension = ((ConstantNode) object).getStableDimension();
+                if (locationIdentity.isImmutable() || stableDimension > 0) {
+                    Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement);
+                    boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable();
+                    if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
+                        return ConstantNode.forConstant(read.stamp(), constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess);
+                    }
+                }
+            }
+            if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) {
+                ValueNode length = GraphUtil.arrayLength(object);
+                if (length != null) {
+                    // TODO Does this need a PiCastNode to the positive range?
+                    return length;
+                }
+            }
+            if (locationIdentity instanceof CanonicalizableLocation) {
+                CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity;
+                ValueNode result = canonicalize.canonicalizeRead(read, address, object, tool);
+                assert result != null && result.stamp().isCompatible(read.stamp());
+                return result;
+            }
+
+        }
+        return read;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        throw GraalError.shouldNotReachHere("unexpected ReadNode before PEA");
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java
new file mode 100644
index 0000000..64abb54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+
+/**
+ * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
+ */
+@NodeInfo(nameTemplate = "Write#{p#location/s}")
+public class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
+
+    public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
+
+    @OptionalInput(Guard) protected GuardingNode storeCheckGuard;
+
+    protected WriteNode(ValueNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+        this((AddressNode) address, location, value, barrierType);
+    }
+
+    public WriteNode(AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+        super(TYPE, address, location, value, barrierType);
+    }
+
+    public WriteNode(AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, boolean initialization) {
+        super(TYPE, address, location, value, barrierType, initialization);
+    }
+
+    public WriteNode(AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        this(TYPE, address, location, value, barrierType, guard, initialization);
+    }
+
+    protected WriteNode(NodeClass<? extends WriteNode> c, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(c, address, location, value, barrierType, guard, initialization);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp());
+        gen.getLIRGeneratorTool().getArithmetic().emitStore(writeKind, gen.operand(address), gen.operand(value()), gen.state(this));
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (getAddress() instanceof OffsetAddressNode) {
+            OffsetAddressNode objAddress = (OffsetAddressNode) getAddress();
+            if (objAddress.getBase() instanceof PiNode && ((PiNode) objAddress.getBase()).getGuard() == getGuard()) {
+                OffsetAddressNode newAddress = graph().unique(new OffsetAddressNode(((PiNode) objAddress.getBase()).getOriginalNode(), objAddress.getOffset()));
+                setAddress(newAddress);
+                tool.addToWorkList(newAddress);
+            }
+        }
+    }
+
+    @NodeIntrinsic
+    public static native void writeMemory(Address address, @ConstantNodeParameter LocationIdentity location, Object value, @ConstantNodeParameter BarrierType barrierType);
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        throw GraalError.shouldNotReachHere("unexpected WriteNode before PEA");
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return true;
+    }
+
+    public void setStoreCheckGuard(GuardingNode newStoreCheckGuard) {
+        updateUsages((Node) this.storeCheckGuard, (Node) newStoreCheckGuard);
+        this.storeCheckGuard = newStoreCheckGuard;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/AddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/AddressNode.java
new file mode 100644
index 0000000..9c4e80a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/AddressNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory.address;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.StructuralInput;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+
+/**
+ * Base class for nodes that deal with addressing calculation.
+ */
+@NodeInfo(allowedUsageTypes = Association, size = SIZE_0, cycles = CYCLES_0)
+public abstract class AddressNode extends FloatingNode implements IndirectCanonicalization {
+    public static final NodeClass<AddressNode> TYPE = NodeClass.create(AddressNode.class);
+
+    protected AddressNode(NodeClass<? extends AddressNode> c) {
+        super(c, StampFactory.pointer());
+    }
+
+    public abstract static class Address extends StructuralInput.Association {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/OffsetAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/OffsetAddressNode.java
new file mode 100644
index 0000000..20008ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/OffsetAddressNode.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory.address;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.spi.PiPushable;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Represents an address that is composed of a base and an offset. The base can be either a
+ * {@link JavaKind#Object}, a word-sized integer or another pointer. The offset must be a word-sized
+ * integer.
+ */
+@NodeInfo(allowedUsageTypes = InputType.Association)
+public class OffsetAddressNode extends AddressNode implements Canonicalizable, PiPushable {
+    public static final NodeClass<OffsetAddressNode> TYPE = NodeClass.create(OffsetAddressNode.class);
+
+    @Input ValueNode base;
+    @Input ValueNode offset;
+
+    public OffsetAddressNode(ValueNode base, ValueNode offset) {
+        super(TYPE);
+        this.base = base;
+        this.offset = offset;
+    }
+
+    public ValueNode getBase() {
+        return base;
+    }
+
+    public void setBase(ValueNode base) {
+        updateUsages(this.base, base);
+        this.base = base;
+    }
+
+    public ValueNode getOffset() {
+        return offset;
+    }
+
+    public void setOffset(ValueNode offset) {
+        updateUsages(this.offset, offset);
+        this.offset = offset;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (base instanceof RawAddressNode) {
+            // The RawAddressNode is redundant, just directly use its input as base.
+            return new OffsetAddressNode(((RawAddressNode) base).getAddress(), offset);
+        } else if (base instanceof OffsetAddressNode) {
+            // Rewrite (&base[offset1])[offset2] to base[offset1 + offset2].
+            OffsetAddressNode b = (OffsetAddressNode) base;
+            return new OffsetAddressNode(b.getBase(), BinaryArithmeticNode.add(b.getOffset(), this.getOffset()));
+        } else {
+            return this;
+        }
+    }
+
+    @Override
+    public boolean push(PiNode parent) {
+        if (!(offset.isConstant() && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) {
+            return false;
+        }
+
+        ObjectStamp piStamp = (ObjectStamp) parent.stamp();
+        ResolvedJavaType receiverType = piStamp.type();
+        if (receiverType == null) {
+            return false;
+        }
+        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(offset.asJavaConstant().asLong(), JavaKind.Void);
+        if (field == null) {
+            // field was not declared by receiverType
+            return false;
+        }
+
+        ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp();
+        ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp);
+        if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) {
+            if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) {
+                replaceFirstInput(parent, parent.object());
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @NodeIntrinsic
+    public static native Address address(Object base, long offset);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/RawAddressNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/RawAddressNode.java
new file mode 100644
index 0000000..26359cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/RawAddressNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.memory.address;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * Convert a word-sized integer to a raw address.
+ */
+@NodeInfo(allowedUsageTypes = InputType.Association)
+public class RawAddressNode extends AddressNode {
+    public static final NodeClass<RawAddressNode> TYPE = NodeClass.create(RawAddressNode.class);
+
+    @Input ValueNode address;
+
+    public RawAddressNode(ValueNode address) {
+        super(TYPE);
+        this.address = address;
+    }
+
+    public ValueNode getAddress() {
+        return address;
+    }
+
+    public void setAddress(ValueNode address) {
+        updateUsages(this.address, address);
+        this.address = address;
+    }
+
+    @NodeIntrinsic
+    public static native Address address(long address);
+
+    @NodeIntrinsic
+    public static native Address address(Object address);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArithmeticLIRLowerable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArithmeticLIRLowerable.java
new file mode 100644
index 0000000..a279e49
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArithmeticLIRLowerable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+
+public interface ArithmeticLIRLowerable extends LIRLowerable {
+
+    @Override
+    default void generate(NodeLIRBuilderTool builder) {
+        generate(builder, builder.getLIRGeneratorTool().getArithmetic());
+    }
+
+    void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArrayLengthProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArrayLengthProvider.java
new file mode 100644
index 0000000..d472e20
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArrayLengthProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.nodes.ValueNode;
+
+public interface ArrayLengthProvider {
+
+    /**
+     * @return the length of the array described by this node, or null if it is not available
+     */
+    ValueNode length();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DefaultNodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DefaultNodeCostProvider.java
new file mode 100644
index 0000000..cb7b909
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DefaultNodeCostProvider.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.nodes.java.AccessFieldNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+
+/*
+ * Certain node costs can not, based on the meta information encoded in the node properties,
+ * be computed before a real node is instantiated. E.g. the type of a call in Java heavily
+ * influences the cost of an invocation and thus must be decided dynamically.
+ */
+public abstract class DefaultNodeCostProvider implements NodeCostProvider {
+
+    @Override
+    public final int getEstimatedCodeSize(Node n) {
+        return size(n).estimatedCodeSize;
+    }
+
+    @Override
+    public final int getEstimatedCPUCycles(Node n) {
+        return cycles(n).estimatedCPUCycles;
+    }
+
+    @Override
+    public NodeSize size(Node n) {
+        if (n instanceof Invoke) {
+            /*
+             * Code size for the invoke itself is a very weak approximation.
+             */
+            Invoke ivk = (Invoke) n;
+            CallTargetNode mct = ivk.callTarget();
+            switch (mct.invokeKind()) {
+                case Interface:
+                    return SIZE_50;
+                case Special:
+                case Static:
+                    return SIZE_2;
+                case Virtual:
+                    return SIZE_4;
+                default:
+                    break;
+            }
+        } else if (n instanceof CommitAllocationNode) {
+            CommitAllocationNode commit = (CommitAllocationNode) n;
+            /*
+             * very weak approximation, current problem is node size is an enum and we cannot
+             * dynamically instantiate a new case like nrOfAllocs*allocationCodeSize
+             */
+            int nrOfAllocs = commit.getVirtualObjects().size();
+            if (nrOfAllocs < 5) {
+                return SIZE_80;
+            } else if (nrOfAllocs < 10) {
+                return SIZE_100;
+            } else {
+                return SIZE_200;
+            }
+        } else if (n instanceof AccessFieldNode) {
+            if (((AccessFieldNode) n).field().isVolatile()) {
+                // membar size is added
+                return SIZE_10;
+            }
+        } else if (n instanceof LoopEndNode) {
+            if (((LoopEndNode) n).canSafepoint()) {
+                return SIZE_6;
+            }
+        } else if (n instanceof SwitchNode) {
+            SwitchNode x = (SwitchNode) n;
+            int keyCount = x.keyCount();
+            if (keyCount == 0) {
+                return SIZE_1;
+            } else {
+                if (keyCount == 1) {
+                    // if
+                    return SIZE_2;
+                } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
+                    // good heuristic
+                    return SIZE_15;
+                } else {
+                    // not so good
+                    return SIZE_30;
+                }
+            }
+        }
+
+        return n.getNodeClass().size();
+    }
+
+    @Override
+    public NodeCycles cycles(Node n) {
+        if (n instanceof Invoke) {
+            Invoke ivk = (Invoke) n;
+            CallTargetNode mct = ivk.callTarget();
+            switch (mct.invokeKind()) {
+                case Interface:
+                    return CYCLES_100;
+                case Special:
+                case Static:
+                    return CYCLES_2;
+                case Virtual:
+                    return CYCLES_4;
+                default:
+                    break;
+            }
+        } else if (n instanceof CommitAllocationNode) {
+            CommitAllocationNode commit = (CommitAllocationNode) n;
+            /*
+             * very weak approximation, current problem is node cycles is an enum and we cannot
+             * dynamically instantiate a new case like nrOfAllocs*allocationCost
+             */
+            int nrOfAllocs = commit.getVirtualObjects().size();
+            if (nrOfAllocs < 5) {
+                return CYCLES_20;
+            } else if (nrOfAllocs < 10) {
+                return CYCLES_40;
+            } else {
+                return CYCLES_80;
+            }
+        } else if (n instanceof AccessFieldNode) {
+            if (((AccessFieldNode) n).field().isVolatile()) {
+                // membar cycles is added
+                return CYCLES_30;
+            }
+        } else if (n instanceof SwitchNode) {
+            SwitchNode x = (SwitchNode) n;
+            int keyCount = x.keyCount();
+            if (keyCount == 0) {
+                return CYCLES_1;
+            } else {
+                if (keyCount == 1) {
+                    // if
+                    return CYCLES_2;
+                } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
+                    // good heuristic
+                    return CYCLES_15;
+                } else {
+                    // not so good
+                    return CYCLES_30;
+                }
+            }
+        }
+
+        return n.getNodeClass().cycles();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LIRLowerable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LIRLowerable.java
new file mode 100644
index 0000000..4ed47ce
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LIRLowerable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+public interface LIRLowerable {
+
+    void generate(NodeLIRBuilderTool generator);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LimitedValueProxy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LimitedValueProxy.java
new file mode 100644
index 0000000..263fd05
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LimitedValueProxy.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * This interface is like the derived {@link ValueProxy}. The difference is that only the graph
+ * builder should see through the proxy for doing some checks. Optimizations should not see through
+ * this proxy and therefore should only test for {@link ValueProxy}.
+ */
+public interface LimitedValueProxy extends Proxy {
+
+    @Override
+    ValueNode getOriginalNode();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Lowerable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Lowerable.java
new file mode 100644
index 0000000..1c01c62
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Lowerable.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.nodes.ValueNodeInterface;
+
+/**
+ * Interface implemented by nodes that can replace themselves with lower level nodes during a phase
+ * that transforms a graph to replace higher level nodes with lower level nodes.
+ */
+public interface Lowerable extends ValueNodeInterface {
+
+    /**
+     * Expand this node into lower level nodes expressing the same semantics. If the introduced
+     * nodes are themselves lowerable, they should be recursively lowered as part of this call.
+     */
+    void lower(LoweringTool tool);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java
new file mode 100644
index 0000000..87b708a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Provides a capability for replacing a higher node with one or more lower level nodes.
+ */
+public interface LoweringProvider {
+
+    void lower(Node n, LoweringTool tool);
+
+    /**
+     * Reconstructs the array index from an address node that was created as a lowering of an
+     * indexed access to an array.
+     *
+     * @param elementKind the {@link JavaKind} of the array elements
+     * @param address an {@link AddressNode} pointing to an element in an array
+     * @return a node that gives the index of the element
+     */
+    ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address);
+
+    /**
+     * Indicates whether the target platform supports comparison of integers of a particular bit
+     * width. This check is used by optimizations that might introduce subword compares.
+     */
+    default boolean supportSubwordCompare(int bits) {
+        // most platforms only support 32 and 64 bit compares
+        return bits >= 32;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java
new file mode 100644
index 0000000..f8e279f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public interface LoweringTool {
+
+    MetaAccessProvider getMetaAccess();
+
+    LoweringProvider getLowerer();
+
+    ConstantReflectionProvider getConstantReflection();
+
+    ConstantFieldProvider getConstantFieldProvider();
+
+    Replacements getReplacements();
+
+    StampProvider getStampProvider();
+
+    NodeCostProvider getNodeCostProvider();
+
+    GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
+
+    GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated);
+
+    /**
+     * Gets the closest fixed node preceding the node currently being lowered.
+     */
+    FixedWithNextNode lastFixedNode();
+
+    AnchoringNode getCurrentGuardAnchor();
+
+    /**
+     * Marker interface lowering stages.
+     */
+    interface LoweringStage {
+    }
+
+    /**
+     * The lowering stages used in a standard Graal phase plan. Lowering is called 3 times, during
+     * every tier of compilation.
+     */
+    enum StandardLoweringStage implements LoweringStage {
+        HIGH_TIER,
+        MID_TIER,
+        LOW_TIER
+    }
+
+    /**
+     * Returns current lowering stage.
+     */
+    LoweringStage getLoweringStage();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java
new file mode 100644
index 0000000..dc1e045
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+
+public interface MemoryProxy extends Proxy, MemoryNode {
+
+    LocationIdentity getLocationIdentity();
+
+    MemoryNode getOriginalMemoryNode();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeCostProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeCostProvider.java
new file mode 100644
index 0000000..918a416
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeCostProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+
+/**
+ * A provider that enables overriding and customization of the {@link NodeCycles} and
+ * {@link NodeSize} values for a {@linkplain Node node}.
+ */
+public interface NodeCostProvider {
+
+    /**
+     * Gets the estimated size of machine code generated for {@code n}.
+     */
+    int getEstimatedCodeSize(Node n);
+
+    /**
+     * Gets the estimated execution cost for {@code n} in terms of CPU cycles.
+     */
+    int getEstimatedCPUCycles(Node n);
+
+    /**
+     * @see NodeInfo#size()
+     */
+    NodeSize size(Node n);
+
+    /**
+     * @see NodeInfo#cycles()
+     */
+    NodeCycles cycles(Node n);
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java
new file mode 100644
index 0000000..649c2a9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.Value;
+
+public interface NodeLIRBuilderTool extends NodeValueMap {
+
+    // TODO (je) remove and move into the Node
+    LIRFrameState state(DeoptimizingNode deopt);
+
+    void emitIf(IfNode i);
+
+    void emitConditional(ConditionalNode i);
+
+    void emitSwitch(SwitchNode i);
+
+    void emitInvoke(Invoke i);
+
+    // Handling of block-end nodes still needs to be unified in the LIRGenerator.
+    void visitMerge(AbstractMergeNode i);
+
+    void visitEndNode(AbstractEndNode i);
+
+    void visitLoopEnd(LoopEndNode i);
+
+    // These methods define the contract a runtime specific backend must provide.
+
+    void visitSafepointNode(SafepointNode i);
+
+    void visitBreakpointNode(BreakpointNode i);
+
+    void visitFullInfopointNode(FullInfopointNode i);
+
+    void setSourcePosition(NodeSourcePosition position);
+
+    LIRGeneratorTool getLIRGeneratorTool();
+
+    void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp compareStamp, double probability);
+
+    Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
+
+    void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java
new file mode 100644
index 0000000..b07e01b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.Value;
+
+public interface NodeValueMap {
+
+    /**
+     * Returns the operand that has been previously initialized by
+     * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code
+     * generation error to ask for the operand of ValueNode that doesn't have one yet.
+     *
+     * @param node A node that produces a result value.
+     */
+    Value operand(Node node);
+
+    /**
+     * @return {@code true} if there is an {@link Value operand} associated with the {@code node} in
+     *         the current block.
+     */
+    boolean hasOperand(Node node);
+
+    /**
+     * Associates {@code operand} with the {@code node} in the current block.
+     *
+     * @return {@code operand}
+     */
+    Value setResult(ValueNode node, Value operand);
+
+    /**
+     * Gets the the {@link ValueNode} that produced a {@code value}. If the {@code value} is not
+     * associated with a {@link ValueNode} {@code null} is returned.
+     *
+     * This method is intended for debugging purposes only.
+     */
+    ValueNode valueForOperand(Value value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeWithState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeWithState.java
new file mode 100644
index 0000000..2e1ba19
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeWithState.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.FixedNodeInterface;
+import org.graalvm.compiler.nodes.FrameState;
+
+/**
+ * Interface for nodes which have {@link FrameState} nodes as input.
+ */
+public interface NodeWithState extends FixedNodeInterface {
+
+    default NodeIterable<FrameState> states() {
+        return asNode().inputs().filter(FrameState.class);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/PiPushable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/PiPushable.java
new file mode 100644
index 0000000..82686f7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/PiPushable.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.nodes.PiNode;
+
+/**
+ * This interface marks nodes, which are able to be pushed through a PiNode.
+ */
+public interface PiPushable {
+
+    /**
+     *
+     * @param parent PiNode
+     * @return true if node was moved
+     */
+    boolean push(PiNode parent);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java
new file mode 100644
index 0000000..3e400d5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInterface;
+
+/**
+ * This interface marks nodes whose result is the same as one of their inputs. Such nodes are used
+ * to add type information, to introduce scheduling restrictions, etc.
+ *
+ * For some algorithms it is necessary or advantageous to see through these proxies.
+ */
+public interface Proxy extends NodeInterface {
+
+    Node getOriginalNode();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java
new file mode 100644
index 0000000..9320448
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Interface for managing replacements.
+ */
+public interface Replacements {
+
+    /**
+     * Gets the snippet graph derived from a given method.
+     *
+     * @param args arguments to the snippet if available, otherwise {@code null}
+     * @return the snippet graph, if any, that is derived from {@code method}
+     */
+    StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args);
+
+    /**
+     * Gets the snippet graph derived from a given method.
+     *
+     * @param recursiveEntry if the snippet contains a call to this method, it's considered as
+     *            recursive call and won't be processed for {@linkplain MethodSubstitution
+     *            substitutions}.
+     * @param args arguments to the snippet if available, otherwise {@code null}
+     * @return the snippet graph, if any, that is derived from {@code method}
+     */
+    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args);
+
+    /**
+     * Registers a method as snippet.
+     */
+    void registerSnippet(ResolvedJavaMethod method);
+
+    /**
+     * Gets a graph that is a substitution for a given method.
+     *
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
+     * @return the graph, if any, that is a substitution for {@code method}
+     */
+    StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci);
+
+    /**
+     * Gets a method that is a substitution for a given method.
+     *
+     * @return the method, if any, whose bytecode are a substitution for {@code method}
+     */
+    ResolvedJavaMethod getSubstitutionMethod(ResolvedJavaMethod method);
+
+    /**
+     * Determines if there may be a {@linkplain #getSubstitution(ResolvedJavaMethod, int)
+     * substitution graph} for a given method.
+     *
+     * A call to {@link #getSubstitution} may still return {@code null} for {@code method} and
+     * {@code invokeBci}. A substitution may be based on an {@link InvocationPlugin} that returns
+     * {@code false} for {@link InvocationPlugin#execute} making it impossible to create a
+     * substitute graph.
+     *
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
+     * @return true iff there may be a substitution graph available for {@code method}
+     */
+    boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci);
+
+    /**
+     * Gets the provider for accessing the bytecode of a substitution method.
+     */
+    BytecodeProvider getReplacementBytecodeProvider();
+
+    /**
+     * Register snippet templates.
+     */
+    void registerSnippetTemplateCache(SnippetTemplateCache snippetTemplates);
+
+    /**
+     * Get snippet templates that were registered with
+     * {@link Replacements#registerSnippetTemplateCache(SnippetTemplateCache)}.
+     */
+    <T extends SnippetTemplateCache> T getSnippetTemplateCache(Class<T> templatesClass);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/StampProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/StampProvider.java
new file mode 100644
index 0000000..23d4897
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/StampProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+
+/**
+ * Provides a capability for creating platform dependent stamps.
+ */
+public interface StampProvider {
+
+    /**
+     * Create the stamp of the {@link LoadHubNode hub} of an object.
+     */
+    Stamp createHubStamp(ObjectStamp object);
+
+    /**
+     * Create the stamp of a pointer to a method.
+     */
+    Stamp createMethodStamp();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/UncheckedInterfaceProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/UncheckedInterfaceProvider.java
new file mode 100644
index 0000000..d6c728f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/UncheckedInterfaceProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+
+public interface UncheckedInterfaceProvider {
+    /**
+     * Returns a stamp containing information about interface types that has not been verified or
+     * null if no such stamp is available. A type check is needed before using informations from
+     * this stamp.
+     */
+    Stamp uncheckedStamp();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ValueProxy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ValueProxy.java
new file mode 100644
index 0000000..3dc0fc2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ValueProxy.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+/**
+ * This interface marks nodes whose result is the same as one of their inputs. Such nodes are used
+ * to add type information, to introduce scheduling restrictions, etc.
+ *
+ * For some algorithms it is necessary or advantageous to see through these proxies.
+ */
+public interface ValueProxy extends LimitedValueProxy {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Virtualizable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Virtualizable.java
new file mode 100644
index 0000000..f8a2f9d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Virtualizable.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+/**
+ * This interface allows a node to convey information about what its effect would be if some of its
+ * inputs were virtualized. The {@link #virtualize(VirtualizerTool)} method will only be called for
+ * nodes that have some interaction with virtualized nodes. However, the virtualized nodes might
+ * have been re-materialized in the meantime.
+ */
+public interface Virtualizable {
+
+    /**
+     * A node class can implement this method to convey information about what its effect would be
+     * if some of its inputs were virtualized. All modifications must be made through the supplied
+     * tool, and not directly on the node, because by the time this method is called the
+     * virtualized/non-virtualized state is still speculative and might not hold because of loops,
+     * etc.
+     *
+     * @param tool the tool used to describe the effects of this node
+     */
+    void virtualize(VirtualizerTool tool);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizableAllocation.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizableAllocation.java
new file mode 100644
index 0000000..34bb295
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizableAllocation.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+/**
+ * This interface allows a node to convey information about what its effect would be if some of its
+ * inputs were virtualized.
+ *
+ * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
+ * will be called regardless of whether this node had any interaction with virtualized nodes. This
+ * interface can therefore be used for object allocations, for which virtualization introduces new
+ * virtualized objects.
+ */
+public interface VirtualizableAllocation extends Virtualizable {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java
new file mode 100644
index 0000000..c5db63e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.spi;
+
+import java.util.List;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * This tool can be used to query the current state (normal/virtualized/re-materialized) of values
+ * and to describe the actions that would be taken for this state.
+ *
+ * See also {@link Virtualizable}.
+ */
+public interface VirtualizerTool {
+
+    /**
+     * @return the {@link MetaAccessProvider} associated with the current compilation.
+     */
+    MetaAccessProvider getMetaAccessProvider();
+
+    /**
+     * @return the {@link ConstantReflectionProvider} associated with the current compilation, which
+     *         can be used to access {@link JavaConstant}s.
+     */
+    ConstantReflectionProvider getConstantReflectionProvider();
+
+    /**
+     * This method should be used to query the maximum size of virtualized objects before attempting
+     * virtualization.
+     *
+     * @return the maximum number of entries for virtualized objects.
+     */
+    int getMaximumEntryCount();
+
+    // methods working on virtualized/materialized objects
+
+    /**
+     * Introduces a new virtual object to the current state.
+     *
+     * @param virtualObject the new virtual object.
+     * @param entryState the initial state of the virtual object's fields.
+     * @param locks the initial locking depths.
+     * @param ensureVirtualized true if this object needs to stay virtual
+     */
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized);
+
+    /**
+     * Returns a VirtualObjectNode if the given value is aliased with a virtual object that is still
+     * virtual, the materialized value of the given value is aliased with a virtual object that was
+     * materialized, the replacement if the give value was replaced, otherwise the given value.
+     *
+     * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This
+     * method can be used to determine if a value was replaced by another one (e.g., a load field by
+     * the loaded value).
+     */
+    ValueNode getAlias(ValueNode value);
+
+    /**
+     * Sets the entry (field or array element) with the given index in the virtualized object.
+     *
+     * @param index the index to be set.
+     * @param value the new value for the given index.
+     * @param unsafe if true, then mismatching value {@link JavaKind}s will be accepted.
+     */
+    void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, boolean unsafe);
+
+    ValueNode getEntry(VirtualObjectNode virtualObject, int index);
+
+    void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId);
+
+    MonitorIdNode removeLock(VirtualObjectNode virtualObject);
+
+    void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized);
+
+    boolean getEnsureVirtualized(VirtualObjectNode virtualObject);
+
+    // operations on the current node
+
+    /**
+     * Deletes the current node and replaces it with the given virtualized object.
+     *
+     * @param virtualObject the virtualized object that should replace the current node.
+     */
+    void replaceWithVirtual(VirtualObjectNode virtualObject);
+
+    /**
+     * Deletes the current node and replaces it with the given value.
+     *
+     * @param replacement the value that should replace the current node.
+     */
+    void replaceWithValue(ValueNode replacement);
+
+    /**
+     * Deletes the current node.
+     */
+    void delete();
+
+    /**
+     * Replaces an input of the current node.
+     *
+     * @param oldInput the old input value.
+     * @param replacement the new input value.
+     */
+    void replaceFirstInput(Node oldInput, Node replacement);
+
+    /**
+     * Adds the given node to the graph.This action will only be performed when, and if, the changes
+     * are committed.
+     *
+     * @param node the node to add.
+     */
+    void addNode(ValueNode node);
+
+    /**
+     * This method performs either {@link #replaceWithValue(ValueNode)} or
+     * {@link #replaceWithVirtual(VirtualObjectNode)}, depending on the given value.
+     *
+     * @param value the replacement value
+     */
+    void replaceWith(ValueNode value);
+
+    /**
+     *
+     * If state is virtual, materialization is performed for the given state.
+     *
+     * @return true if materialization happened, false if not.
+     */
+    boolean ensureMaterialized(VirtualObjectNode virtualObject);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java
new file mode 100644
index 0000000..cc6a6e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.type;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Helper class that is used to keep all stamp-related operations in one place.
+ */
+public class StampTool {
+
+    public static Stamp meet(Iterable<? extends ValueNode> values) {
+        Stamp stamp = meetOrNull(values, null);
+        if (stamp == null) {
+            return StampFactory.forVoid();
+        }
+        return stamp;
+    }
+
+    /**
+     * Meet a collection of {@link ValueNode}s optionally excluding {@code selfValue}. If no values
+     * are encountered then return {@code null}.
+     */
+    public static Stamp meetOrNull(Iterable<? extends ValueNode> values, ValueNode selfValue) {
+        Iterator<? extends ValueNode> iterator = values.iterator();
+        Stamp stamp = null;
+        while (iterator.hasNext()) {
+            ValueNode nextValue = iterator.next();
+            if (nextValue != selfValue) {
+                if (stamp == null) {
+                    stamp = nextValue.stamp();
+                } else {
+                    stamp = stamp.meet(nextValue.stamp());
+                }
+            }
+        }
+        return stamp;
+    }
+
+    /**
+     * Compute the stamp resulting from the unsigned comparison being true.
+     *
+     * @return null if it's can't be true or it nothing useful can be encoded.
+     */
+    public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) {
+        IntegerStamp x = (IntegerStamp) stamp;
+        IntegerStamp y = (IntegerStamp) stamp2;
+        if (x == x.unrestricted() && y == y.unrestricted()) {
+            // Don't know anything.
+            return null;
+        }
+        // c <| n, where c is a constant and n is known to be positive.
+        if (x.lowerBound() == x.upperBound()) {
+            if (y.isPositive()) {
+                if (x.lowerBound() == (1 << x.getBits()) - 1) {
+                    // Constant is MAX_VALUE which must fail.
+                    return null;
+                }
+                if (x.lowerBound() <= y.lowerBound()) {
+                    // Test will fail. Return illegalStamp instead?
+                    return null;
+                }
+                // If the test succeeds then this proves that n is at greater than c so the bounds
+                // are [c+1..-n.upperBound)].
+                return StampFactory.forInteger(x.getBits(), x.lowerBound() + 1, y.upperBound());
+            }
+            return null;
+        }
+        // n <| c, where c is a strictly positive constant
+        if (y.lowerBound() == y.upperBound() && y.isStrictlyPositive()) {
+            // The test proves that n is positive and less than c, [0..c-1]
+            return StampFactory.forInteger(y.getBits(), 0, y.lowerBound() - 1);
+        }
+        return null;
+    }
+
+    public static Stamp stampForLeadingZeros(IntegerStamp valueStamp) {
+        long mask = CodeUtil.mask(valueStamp.getBits());
+        // Don't count zeros from the mask in the result.
+        int adjust = Long.numberOfLeadingZeros(mask);
+        assert adjust == 0 || adjust == 32;
+        int min = Long.numberOfLeadingZeros(valueStamp.upMask() & mask) - adjust;
+        int max = Long.numberOfLeadingZeros(valueStamp.downMask() & mask) - adjust;
+        return StampFactory.forInteger(JavaKind.Int, min, max);
+    }
+
+    public static Stamp stampForTrailingZeros(IntegerStamp valueStamp) {
+        long mask = CodeUtil.mask(valueStamp.getBits());
+        int min = Long.numberOfTrailingZeros(valueStamp.upMask() & mask);
+        int max = Long.numberOfTrailingZeros(valueStamp.downMask() & mask);
+        return StampFactory.forInteger(JavaKind.Int, min, max);
+    }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
+     * pointer value which is known to be always null.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value which is known to be always null
+     */
+    public static boolean isPointerAlwaysNull(ValueNode node) {
+        return isPointerAlwaysNull(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer
+     * stamp whose values are known to be always null.
+     *
+     * @param stamp the stamp to check
+     * @return true if this stamp represents a legal object stamp whose values are known to be
+     *         always null
+     */
+    public static boolean isPointerAlwaysNull(Stamp stamp) {
+        if (stamp instanceof AbstractPointerStamp && stamp.hasValues()) {
+            return ((AbstractPointerStamp) stamp).alwaysNull();
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
+     * pointer value which is known to never be null.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value which is known to never be null
+     */
+    public static boolean isPointerNonNull(ValueNode node) {
+        return isPointerNonNull(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer
+     * stamp whose values are known to never be null.
+     *
+     * @param stamp the stamp to check
+     * @return true if this stamp represents a legal object stamp whose values are known to be
+     *         always null
+     */
+    public static boolean isPointerNonNull(Stamp stamp) {
+        if (stamp instanceof AbstractPointerStamp) {
+            return ((AbstractPointerStamp) stamp).nonNull();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
+     * a {@linkplain Stamp#hasValues() legal} Object value.
+     *
+     * @param node the node to check
+     * @return the Java type this value has if it is a legal Object type, null otherwise
+     */
+    public static TypeReference typeReferenceOrNull(ValueNode node) {
+        return typeReferenceOrNull(node.stamp());
+    }
+
+    public static ResolvedJavaType typeOrNull(ValueNode node) {
+        return typeOrNull(node.stamp());
+    }
+
+    public static ResolvedJavaType typeOrNull(Stamp stamp) {
+        TypeReference type = typeReferenceOrNull(stamp);
+        return type == null ? null : type.getType();
+    }
+
+    public static ResolvedJavaType typeOrNull(Stamp stamp, MetaAccessProvider metaAccess) {
+        if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) {
+            AbstractObjectStamp abstractObjectStamp = (AbstractObjectStamp) stamp;
+            ResolvedJavaType type = abstractObjectStamp.type();
+            if (type == null) {
+                return metaAccess.lookupJavaType(Object.class);
+            } else {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    public static ResolvedJavaType typeOrNull(ValueNode node, MetaAccessProvider metaAccess) {
+        return typeOrNull(node.stamp(), metaAccess);
+    }
+
+    /**
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
+     * {@linkplain Stamp#hasValues() legal} Object stamp.
+     *
+     * @param stamp the stamp to check
+     * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
+     */
+    public static TypeReference typeReferenceOrNull(Stamp stamp) {
+        if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) {
+            AbstractObjectStamp abstractObjectStamp = (AbstractObjectStamp) stamp;
+            if (abstractObjectStamp.isExactType()) {
+                return TypeReference.createExactTrusted(abstractObjectStamp.type());
+            } else {
+                return TypeReference.createTrustedWithoutAssumptions(abstractObjectStamp.type());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
+     * Object value whose Java type is known exactly. If this method returns true then the
+     * {@linkplain ResolvedJavaType Java type} returned by {@link #typeReferenceOrNull(ValueNode)}
+     * is the concrete dynamic/runtime Java type of this value.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value whose Java type is known exactly
+     */
+    public static boolean isExactType(ValueNode node) {
+        return isExactType(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} Object
+     * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
+     * true then the Java type returned by {@link #typeReferenceOrNull(Stamp)} is the only concrete
+     * dynamic/runtime Java type possible for values of this stamp.
+     *
+     * @param stamp the stamp to check
+     * @return true if this node represents a legal object stamp whose Java type is known exactly
+     */
+    public static boolean isExactType(Stamp stamp) {
+        if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) {
+            return ((AbstractObjectStamp) stamp).isExactType();
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java
new file mode 100644
index 0000000..3c27870
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/ConstantFoldUtil.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.util;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider.ConstantFieldTool;
+import org.graalvm.compiler.nodes.ConstantNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+
+public class ConstantFoldUtil {
+
+    public static ConstantNode tryConstantFold(ConstantFieldProvider fieldProvider, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, ResolvedJavaField field,
+                    JavaConstant receiver) {
+        if (!field.isStatic()) {
+            if (receiver == null || receiver.isNull()) {
+                return null;
+            }
+        }
+
+        return fieldProvider.readConstantField(field, new ConstantFieldTool<ConstantNode>() {
+
+            @Override
+            public JavaConstant readValue() {
+                return constantReflection.readFieldValue(field, receiver);
+            }
+
+            @Override
+            public JavaConstant getReceiver() {
+                return receiver;
+            }
+
+            @Override
+            public ConstantNode foldConstant(JavaConstant ret) {
+                if (ret != null) {
+                    return ConstantNode.forConstant(ret, metaAccess);
+                } else {
+                    return null;
+                }
+            }
+
+            @Override
+            public ConstantNode foldStableArray(JavaConstant ret, int stableDimensions, boolean isDefaultStable) {
+                if (ret != null) {
+                    return ConstantNode.forConstant(ret, stableDimensions, isDefaultStable, metaAccess);
+                } else {
+                    return null;
+                }
+            }
+        });
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
new file mode 100644
index 0000000..f942d8c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
@@ -0,0 +1,743 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.code.SourceStackTraceBailoutException;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class GraphUtil {
+
+    public static void killCFG(Node node, SimplifierTool tool) {
+        NodeWorkList worklist = killCFG(node, tool, null);
+        if (worklist != null) {
+            for (Node successor : worklist) {
+                killCFG(successor, tool, worklist);
+            }
+        }
+    }
+
+    private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) {
+        NodeWorkList newWorklist = worklist;
+        // DebugScope.forceDump(node.graph(), "kill CFG %s", node);
+        if (node instanceof FixedNode) {
+            newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool);
+        } else {
+            propagateKill(node);
+        }
+        return newWorklist;
+    }
+
+    private static NodeWorkList killCFGLinear(FixedNode in, NodeWorkList worklist, SimplifierTool tool) {
+        NodeWorkList newWorklist = worklist;
+        FixedNode current = in;
+        while (current != null) {
+            FixedNode next = null;
+            assert current.isAlive();
+            if (current instanceof AbstractEndNode) {
+                // We reached a control flow end.
+                AbstractEndNode end = (AbstractEndNode) current;
+                killEnd(end, tool);
+            } else if (current instanceof FixedWithNextNode) {
+                next = ((FixedWithNextNode) current).next();
+            } else {
+                // Normal control flow node.
+                /*
+                 * We do not take a successor snapshot because this iterator supports concurrent
+                 * modifications as long as they do not change the size of the successor list. Not
+                 * taking a snapshot allows us to see modifications to other branches that may
+                 * happen while processing one branch.
+                 */
+                // assert node.successors().count() > 1 || node.successors().count() == 0 :
+                // node.getClass();
+                Iterator<Node> successors = current.successors().iterator();
+                if (successors.hasNext()) {
+                    Node first = successors.next();
+                    if (!successors.hasNext()) {
+                        next = (FixedNode) first;
+                    } else {
+                        if (newWorklist == null) {
+                            newWorklist = in.graph().createNodeWorkList();
+                        }
+                        for (Node successor : current.successors()) {
+                            newWorklist.add(successor);
+                            if (successor instanceof LoopExitNode) {
+                                LoopExitNode exit = (LoopExitNode) successor;
+                                exit.replaceFirstInput(exit.loopBegin(), null);
+                            }
+                        }
+                    }
+                }
+            }
+            current.replaceAtPredecessor(null);
+            propagateKill(current);
+            current = next;
+        }
+        return newWorklist;
+    }
+
+    public static void killCFG(Node node) {
+        killCFG(node, null);
+    }
+
+    private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
+        AbstractMergeNode merge = end.merge();
+        if (merge != null) {
+            merge.removeEnd(end);
+            StructuredGraph graph = end.graph();
+            if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
+                // dead loop
+                for (PhiNode phi : merge.phis().snapshot()) {
+                    propagateKill(phi);
+                }
+                LoopBeginNode begin = (LoopBeginNode) merge;
+                // disconnect and delete loop ends & loop exits
+                for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
+                    loopend.predecessor().replaceFirstSuccessor(loopend, null);
+                    loopend.safeDelete();
+                }
+                begin.removeExits();
+                FixedNode loopBody = begin.next();
+                if (loopBody != null) { // for small infinite loops, the body may be killed while
+                                        // killing the loop ends
+                    killCFG(loopBody);
+                }
+                begin.safeDelete();
+            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
+                // not a loop anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+                }
+                graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
+            } else if (merge.phiPredecessorCount() == 1) {
+                // not a merge anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+                }
+                graph.reduceTrivialMerge(merge);
+            }
+        }
+    }
+
+    public static boolean isFloatingNode(Node n) {
+        return !(n instanceof FixedNode);
+    }
+
+    private static void propagateKill(Node node) {
+        if (node != null && node.isAlive()) {
+            node.markDeleted();
+
+            for (Node in : node.inputs()) {
+                if (in.isAlive()) {
+                    in.removeUsage(node);
+                    if (in.hasNoUsages() && !(in instanceof FixedNode)) {
+                        killWithUnusedFloatingInputs(in);
+                    }
+                }
+            }
+
+            ArrayList<Node> usageToKill = null;
+            for (Node usage : node.usages()) {
+                if (usage.isAlive() && !(usage instanceof FixedNode)) {
+                    if (usageToKill == null) {
+                        usageToKill = new ArrayList<>();
+                    }
+                    usageToKill.add(usage);
+                }
+            }
+            if (usageToKill != null) {
+                for (Node usage : usageToKill) {
+                    if (usage.isAlive()) {
+                        if (usage instanceof PhiNode) {
+                            PhiNode phiNode = (PhiNode) usage;
+                            usage.replaceFirstInput(node, null);
+                            if (phiNode.merge() == null || !phiNode.hasValidInput()) {
+                                propagateKill(usage);
+                            }
+                        } else {
+                            propagateKill(usage);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static void killWithUnusedFloatingInputs(Node node) {
+        node.markDeleted();
+        outer: for (Node in : node.inputs()) {
+            if (in.isAlive()) {
+                in.removeUsage(node);
+                if (in.hasNoUsages()) {
+                    node.maybeNotifyZeroUsages(in);
+                }
+                if (!(in instanceof FixedNode)) {
+                    if (in.hasNoUsages()) {
+                        killWithUnusedFloatingInputs(in);
+                    } else if (in instanceof PhiNode) {
+                        for (Node use : in.usages()) {
+                            if (use != in) {
+                                continue outer;
+                            }
+                        }
+                        in.replaceAtUsages(null);
+                        killWithUnusedFloatingInputs(in);
+                    }
+                }
+            }
+        }
+    }
+
+    public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
+        if (fixed instanceof StateSplit) {
+            FrameState stateAfter = ((StateSplit) fixed).stateAfter();
+            if (stateAfter != null) {
+                ((StateSplit) fixed).setStateAfter(null);
+                if (stateAfter.hasNoUsages()) {
+                    killWithUnusedFloatingInputs(stateAfter);
+                }
+            }
+        }
+        unlinkFixedNode(fixed);
+        killWithUnusedFloatingInputs(fixed);
+    }
+
+    public static void unlinkFixedNode(FixedWithNextNode fixed) {
+        assert fixed.next() != null && fixed.predecessor() != null && fixed.isAlive() : fixed;
+        FixedNode next = fixed.next();
+        fixed.setNext(null);
+        fixed.replaceAtPredecessor(next);
+    }
+
+    public static void checkRedundantPhi(PhiNode phiNode) {
+        if (phiNode.isDeleted() || phiNode.valueCount() == 1) {
+            return;
+        }
+
+        ValueNode singleValue = phiNode.singleValue();
+        if (singleValue != PhiNode.MULTIPLE_VALUES) {
+            Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
+            Collection<ProxyNode> proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot();
+            phiNode.replaceAtUsagesAndDelete(singleValue);
+            for (PhiNode phi : phiUsages) {
+                checkRedundantPhi(phi);
+            }
+            for (ProxyNode proxy : proxyUsages) {
+                checkRedundantProxy(proxy);
+            }
+        }
+    }
+
+    public static void checkRedundantProxy(ProxyNode vpn) {
+        if (vpn.isDeleted()) {
+            return;
+        }
+        AbstractBeginNode proxyPoint = vpn.proxyPoint();
+        if (proxyPoint instanceof LoopExitNode) {
+            LoopExitNode exit = (LoopExitNode) proxyPoint;
+            LoopBeginNode loopBegin = exit.loopBegin();
+            Node vpnValue = vpn.value();
+            for (ValueNode v : loopBegin.stateAfter().values()) {
+                ValueNode v2 = v;
+                if (loopBegin.isPhiAtMerge(v2)) {
+                    v2 = ((PhiNode) v2).valueAt(loopBegin.forwardEnd());
+                }
+                if (vpnValue == v2) {
+                    Collection<PhiNode> phiUsages = vpn.usages().filter(PhiNode.class).snapshot();
+                    Collection<ProxyNode> proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot();
+                    vpn.replaceAtUsagesAndDelete(vpnValue);
+                    for (PhiNode phi : phiUsages) {
+                        checkRedundantPhi(phi);
+                    }
+                    for (ProxyNode proxy : proxyUsages) {
+                        checkRedundantProxy(proxy);
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove loop header without loop ends. This can happen with degenerated loops like this one:
+     *
+     * <pre>
+     * for (;;) {
+     *     try {
+     *         break;
+     *     } catch (UnresolvedException iioe) {
+     *     }
+     * }
+     * </pre>
+     */
+    public static void normalizeLoops(StructuredGraph graph) {
+        boolean loopRemoved = false;
+        for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) {
+            if (begin.loopEnds().isEmpty()) {
+                assert begin.forwardEndCount() == 1;
+                graph.reduceDegenerateLoopBegin(begin);
+                loopRemoved = true;
+            } else {
+                normalizeLoopBegin(begin);
+            }
+        }
+
+        if (loopRemoved) {
+            /*
+             * Removing a degenerated loop can make non-loop phi functions unnecessary. Therefore,
+             * we re-check all phi functions and remove redundant ones.
+             */
+            for (Node node : graph.getNodes()) {
+                if (node instanceof PhiNode) {
+                    checkRedundantPhi((PhiNode) node);
+                }
+            }
+        }
+    }
+
+    private static void normalizeLoopBegin(LoopBeginNode begin) {
+        // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either
+        // the same or the phi itself.
+        for (PhiNode phi : begin.phis().snapshot()) {
+            GraphUtil.checkRedundantPhi(phi);
+        }
+        for (LoopExitNode exit : begin.loopExits()) {
+            for (ProxyNode vpn : exit.proxies().snapshot()) {
+                GraphUtil.checkRedundantProxy(vpn);
+            }
+        }
+    }
+
+    /**
+     * Gets an approximate source code location for a node if possible.
+     *
+     * @return the StackTraceElements if an approximate source location is found, null otherwise
+     */
+    public static StackTraceElement[] approxSourceStackTraceElement(Node node) {
+        ArrayList<StackTraceElement> elements = new ArrayList<>();
+        Node n = node;
+        while (n != null) {
+            if (n instanceof MethodCallTargetNode) {
+                elements.add(((MethodCallTargetNode) n).targetMethod().asStackTraceElement(-1));
+                n = ((MethodCallTargetNode) n).invoke().asNode();
+            }
+
+            if (n instanceof StateSplit) {
+                FrameState state = ((StateSplit) n).stateAfter();
+                elements.addAll(Arrays.asList(approxSourceStackTraceElement(state)));
+                break;
+            }
+            n = n.predecessor();
+        }
+        return elements.toArray(new StackTraceElement[elements.size()]);
+    }
+
+    /**
+     * Gets an approximate source code location for frame state.
+     *
+     * @return the StackTraceElements if an approximate source location is found, null otherwise
+     */
+    public static StackTraceElement[] approxSourceStackTraceElement(FrameState frameState) {
+        ArrayList<StackTraceElement> elements = new ArrayList<>();
+        FrameState state = frameState;
+        while (state != null) {
+            Bytecode code = state.getCode();
+            if (code != null) {
+                elements.add(code.asStackTraceElement(state.bci - 1));
+            }
+            state = state.outerFrameState();
+        }
+        return elements.toArray(new StackTraceElement[0]);
+    }
+
+    /**
+     * Gets approximate stack trace elements for a bytecode position.
+     */
+    public static StackTraceElement[] approxSourceStackTraceElement(BytecodePosition bytecodePosition) {
+        ArrayList<StackTraceElement> elements = new ArrayList<>();
+        BytecodePosition position = bytecodePosition;
+        while (position != null) {
+            ResolvedJavaMethod method = position.getMethod();
+            if (method != null) {
+                elements.add(method.asStackTraceElement(position.getBCI()));
+            }
+            position = position.getCaller();
+        }
+        return elements.toArray(new StackTraceElement[0]);
+    }
+
+    /**
+     * Gets an approximate source code location for a node, encoded as an exception, if possible.
+     *
+     * @return the exception with the location
+     */
+    public static RuntimeException approxSourceException(Node node, Throwable cause) {
+        final StackTraceElement[] elements = approxSourceStackTraceElement(node);
+        return createBailoutException(cause == null ? "" : cause.getMessage(), cause, elements);
+    }
+
+    /**
+     * Creates a bailout exception with the given stack trace elements and message.
+     *
+     * @param message the message of the exception
+     * @param elements the stack trace elements
+     * @return the exception
+     */
+    public static BailoutException createBailoutException(String message, Throwable cause, StackTraceElement[] elements) {
+        return SourceStackTraceBailoutException.create(cause, message, elements);
+    }
+
+    /**
+     * Gets an approximate source code location for a node if possible.
+     *
+     * @return a file name and source line number in stack trace format (e.g. "String.java:32") if
+     *         an approximate source location is found, null otherwise
+     */
+    public static String approxSourceLocation(Node node) {
+        StackTraceElement[] stackTraceElements = approxSourceStackTraceElement(node);
+        if (stackTraceElements != null && stackTraceElements.length > 0) {
+            StackTraceElement top = stackTraceElements[0];
+            if (top.getFileName() != null && top.getLineNumber() >= 0) {
+                return top.getFileName() + ":" + top.getLineNumber();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a string representation of the given collection of objects.
+     *
+     * @param objects The {@link Iterable} that will be used to iterate over the objects.
+     * @return A string of the format "[a, b, ...]".
+     */
+    public static String toString(Iterable<?> objects) {
+        StringBuilder str = new StringBuilder();
+        str.append("[");
+        for (Object o : objects) {
+            str.append(o).append(", ");
+        }
+        if (str.length() > 1) {
+            str.setLength(str.length() - 2);
+        }
+        str.append("]");
+        return str.toString();
+    }
+
+    /**
+     * Gets the original value by iterating through all {@link ValueProxy ValueProxies}.
+     *
+     * @param value The start value.
+     * @return The first non-proxy value encountered.
+     */
+    public static ValueNode unproxify(ValueNode value) {
+        ValueNode result = value;
+        while (result instanceof ValueProxy) {
+            result = ((ValueProxy) result).getOriginalNode();
+        }
+        return result;
+    }
+
+    /**
+     * Looks for an {@link ArrayLengthProvider} while iterating through all {@link ValueProxy
+     * ValueProxies}.
+     *
+     * @param value The start value.
+     * @return The array length if one was found, or null otherwise.
+     */
+    public static ValueNode arrayLength(ValueNode value) {
+        ValueNode current = value;
+        do {
+            if (current instanceof ArrayLengthProvider) {
+                ValueNode length = ((ArrayLengthProvider) current).length();
+                if (length != null) {
+                    return length;
+                }
+            }
+            if (current instanceof ValueProxy) {
+                current = ((ValueProxy) current).getOriginalNode();
+            } else {
+                break;
+            }
+        } while (true);
+        return null;
+    }
+
+    /**
+     * Tries to find an original value of the given node by traversing through proxies and
+     * unambiguous phis. Note that this method will perform an exhaustive search through phis. It is
+     * intended to be used during graph building, when phi nodes aren't yet canonicalized.
+     *
+     * @param proxy The node whose original value should be determined.
+     */
+    public static ValueNode originalValue(ValueNode proxy) {
+        ValueNode v = proxy;
+        do {
+            if (v instanceof LimitedValueProxy) {
+                v = ((LimitedValueProxy) v).getOriginalNode();
+            } else if (v instanceof PhiNode) {
+                v = ((PhiNode) v).singleValue();
+                if (v == PhiNode.MULTIPLE_VALUES) {
+                    v = null;
+                }
+            } else {
+                break;
+            }
+        } while (v != null);
+
+        if (v == null) {
+            v = new OriginalValueSearch(proxy).result;
+        }
+        return v;
+    }
+
+    public static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && isFloatingNode(node) && node.hasNoUsages()) {
+            killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
+     * This can happen in the presence of complicated phi/proxy/phi constructs.
+     */
+    static class OriginalValueSearch {
+        ValueNode result;
+
+        OriginalValueSearch(ValueNode proxy) {
+            NodeWorkList worklist = proxy.graph().createNodeWorkList();
+            worklist.add(proxy);
+            for (Node node : worklist) {
+                if (node instanceof LimitedValueProxy) {
+                    ValueNode originalValue = ((LimitedValueProxy) node).getOriginalNode();
+                    if (!process(originalValue, worklist)) {
+                        return;
+                    }
+                } else if (node instanceof PhiNode) {
+                    for (Node value : ((PhiNode) node).values()) {
+                        if (!process((ValueNode) value, worklist)) {
+                            return;
+                        }
+                    }
+                } else {
+                    if (!process((ValueNode) node, null)) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Process a node as part of this search.
+         *
+         * @param node the next node encountered in the search
+         * @param worklist if non-null, {@code node} will be added to this list. Otherwise,
+         *            {@code node} is treated as a candidate result.
+         * @return true if the search should continue, false if a definitive {@link #result} has
+         *         been found
+         */
+        private boolean process(ValueNode node, NodeWorkList worklist) {
+            if (node.isAlive()) {
+                if (worklist == null) {
+                    if (result == null) {
+                        // Initial candidate result: continue search
+                        result = node;
+                    } else if (result != node) {
+                        // Conflicts with existing candidate: stop search with null result
+                        result = null;
+                        return false;
+                    }
+                } else {
+                    worklist.add(node);
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Returns an iterator that will return the given node followed by all its predecessors, up
+     * until the point where {@link Node#predecessor()} returns null.
+     *
+     * @param start the node at which to start iterating
+     */
+    public static NodeIterable<FixedNode> predecessorIterable(final FixedNode start) {
+        return new NodeIterable<FixedNode>() {
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new Iterator<FixedNode>() {
+                    public FixedNode current = start;
+
+                    @Override
+                    public boolean hasNext() {
+                        return current != null;
+                    }
+
+                    @Override
+                    public FixedNode next() {
+                        try {
+                            return current;
+                        } finally {
+                            current = (FixedNode) current.predecessor();
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    private static final class DefaultSimplifierTool implements SimplifierTool {
+        private final MetaAccessProvider metaAccess;
+        private final ConstantReflectionProvider constantReflection;
+        private final ConstantFieldProvider constantFieldProvider;
+        private final boolean canonicalizeReads;
+        private final Assumptions assumptions;
+        private final LoweringProvider loweringProvider;
+
+        DefaultSimplifierTool(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, boolean canonicalizeReads,
+                        Assumptions assumptions, LoweringProvider loweringProvider) {
+            this.metaAccess = metaAccess;
+            this.constantReflection = constantReflection;
+            this.constantFieldProvider = constantFieldProvider;
+            this.canonicalizeReads = canonicalizeReads;
+            this.assumptions = assumptions;
+            this.loweringProvider = loweringProvider;
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return metaAccess;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return constantReflection;
+        }
+
+        @Override
+        public ConstantFieldProvider getConstantFieldProvider() {
+            return constantFieldProvider;
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return canonicalizeReads;
+        }
+
+        @Override
+        public boolean allUsagesAvailable() {
+            return true;
+        }
+
+        @Override
+        public void deleteBranch(Node branch) {
+            branch.predecessor().replaceFirstSuccessor(branch, null);
+            GraphUtil.killCFG(branch, this);
+        }
+
+        @Override
+        public void removeIfUnused(Node node) {
+            GraphUtil.tryKillUnused(node);
+        }
+
+        @Override
+        public void addToWorkList(Node node) {
+        }
+
+        @Override
+        public void addToWorkList(Iterable<? extends Node> nodes) {
+        }
+
+        @Override
+        public Assumptions getAssumptions() {
+            return assumptions;
+        }
+
+        @Override
+        public boolean supportSubwordCompare(int bits) {
+            if (loweringProvider != null) {
+                return loweringProvider.supportSubwordCompare(bits);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    public static SimplifierTool getDefaultSimplifier(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                    boolean canonicalizeReads, Assumptions assumptions) {
+        return getDefaultSimplifier(metaAccess, constantReflection, constantFieldProvider, canonicalizeReads, assumptions, null);
+    }
+
+    public static SimplifierTool getDefaultSimplifier(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                    boolean canonicalizeReads, Assumptions assumptions, LoweringProvider loweringProvider) {
+        return new DefaultSimplifierTool(metaAccess, constantReflection, constantFieldProvider, canonicalizeReads, assumptions, loweringProvider);
+    }
+
+    public static Constant foldIfConstantAndRemove(ValueNode node, ValueNode constant) {
+        assert node.inputs().contains(constant);
+        if (constant.isConstant()) {
+            node.replaceFirstInput(constant, null);
+            Constant result = constant.asConstant();
+            tryKillUnused(constant);
+            return result;
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java
new file mode 100644
index 0000000..fd2220f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+
+/**
+ * Selects one object from a {@link CommitAllocationNode}. The object is identified by its
+ * {@link VirtualObjectNode}.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class AllocatedObjectNode extends FloatingNode implements Virtualizable, ArrayLengthProvider {
+
+    public static final NodeClass<AllocatedObjectNode> TYPE = NodeClass.create(AllocatedObjectNode.class);
+    @Input VirtualObjectNode virtualObject;
+    @Input(Extension) CommitAllocationNode commit;
+
+    public AllocatedObjectNode(VirtualObjectNode virtualObject) {
+        super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(virtualObject.type())));
+        this.virtualObject = virtualObject;
+    }
+
+    public VirtualObjectNode getVirtualObject() {
+        return virtualObject;
+    }
+
+    public CommitAllocationNode getCommit() {
+        return commit;
+    }
+
+    public void setCommit(CommitAllocationNode x) {
+        updateUsages(commit, x);
+        commit = x;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        tool.replaceWithVirtual(getVirtualObject());
+    }
+
+    @Override
+    public ValueNode length() {
+        if (virtualObject instanceof ArrayLengthProvider) {
+            return ((ArrayLengthProvider) virtualObject).length();
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java
new file mode 100644
index 0000000..72362e9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Association;
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+
+// @formatter:off
+@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}",
+          allowedUsageTypes = Extension,
+          cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "We don't know statically how many, and which, allocations are done.",
+          size = SIZE_UNKNOWN,
+          sizeRationale = "We don't know statically how much code for which allocations has to be generated."
+)
+// @formatter:on
+public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
+
+    public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
+
+    @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
+    @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    @Input(Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
+    protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
+    protected ArrayList<Boolean> ensureVirtual = new ArrayList<>();
+
+    public CommitAllocationNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public List<VirtualObjectNode> getVirtualObjects() {
+        return virtualObjects;
+    }
+
+    public List<ValueNode> getValues() {
+        return values;
+    }
+
+    public List<MonitorIdNode> getLocks(int objIndex) {
+        return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
+    }
+
+    public List<Boolean> getEnsureVirtual() {
+        return ensureVirtual;
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match %s, %s", virtualObjects, lockIndexes);
+        assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match %s,%s", lockIndexes, locks);
+        int valueCount = 0;
+        for (VirtualObjectNode virtual : virtualObjects) {
+            valueCount += virtual.entryCount();
+        }
+        assertTrue(values.size() == valueCount, "values size doesn't match");
+        assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match");
+        return super.verify();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            if (ensureVirtual.get(i)) {
+                EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp());
+            }
+        }
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void afterClone(Node other) {
+        lockIndexes = new ArrayList<>(lockIndexes);
+    }
+
+    public void addLocks(List<MonitorIdNode> monitorIds) {
+        locks.addAll(monitorIds);
+        lockIndexes.add(locks.size());
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        int pos = 0;
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            VirtualObjectNode virtualObject = virtualObjects.get(i);
+            int entryCount = virtualObject.entryCount();
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i));
+            pos += entryCount;
+        }
+        tool.delete();
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> properties = super.getDebugProperties(map);
+        int valuePos = 0;
+        for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+            VirtualObjectNode virtual = virtualObjects.get(objIndex);
+            if (virtual == null) {
+                // Could occur in invalid graphs
+                properties.put("object(" + objIndex + ")", "null");
+                continue;
+            }
+            StringBuilder s = new StringBuilder();
+            s.append(virtual.type().toJavaName(false)).append("[");
+            for (int i = 0; i < virtual.entryCount(); i++) {
+                ValueNode value = values.get(valuePos++);
+                s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id));
+            }
+            s.append("]");
+            if (!getLocks(objIndex).isEmpty()) {
+                s.append(" locked(").append(getLocks(objIndex)).append(")");
+            }
+            properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
+        }
+        return properties;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        boolean[] used = new boolean[virtualObjects.size()];
+        int usedCount = 0;
+        for (Node usage : usages()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = virtualObjects.indexOf(addObject.getVirtualObject());
+            assert !used[index];
+            used[index] = true;
+            usedCount++;
+        }
+        if (usedCount == 0) {
+            List<Node> inputSnapshot = inputs().snapshot();
+            graph().removeFixed(this);
+            for (Node input : inputSnapshot) {
+                tool.removeIfUnused(input);
+            }
+            return;
+        }
+        boolean progress;
+        do {
+            progress = false;
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    for (int i = 0; i < virtualObject.entryCount(); i++) {
+                        int index = virtualObjects.indexOf(values.get(valuePos + i));
+                        if (index != -1 && !used[index]) {
+                            progress = true;
+                            used[index] = true;
+                            usedCount++;
+                        }
+                    }
+                }
+                valuePos += virtualObject.entryCount();
+            }
+
+        } while (progress);
+
+        if (usedCount < virtualObjects.size()) {
+            List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
+            List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
+            ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
+            ArrayList<Boolean> newEnsureVirtual = new ArrayList<>(usedCount);
+            newLockIndexes.add(0);
+            List<ValueNode> newValues = new ArrayList<>();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    newVirtualObjects.add(virtualObject);
+                    newLocks.addAll(getLocks(objIndex));
+                    newLockIndexes.add(newLocks.size());
+                    newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
+                    newEnsureVirtual.add(ensureVirtual.get(objIndex));
+                }
+                valuePos += virtualObject.entryCount();
+            }
+            virtualObjects.clear();
+            virtualObjects.addAll(newVirtualObjects);
+            locks.clear();
+            locks.addAll(newLocks);
+            values.clear();
+            values.addAll(newValues);
+            lockIndexes = newLockIndexes;
+            ensureVirtual = newEnsureVirtual;
+        }
+    }
+
+    /**
+     * For all the virtual object nodes that depends on commit allocation, this method maps the node
+     * with its values. For example, a commit allocation could depend on a {@link VirtualArrayNode}
+     * with many {@link ValueNode}s. The map will contain the corresponding {@link VirtualArrayNode}
+     * as a key with the array of {@link ValueNode}s.
+     */
+    public HashMap<VirtualObjectNode, Object[]> getVirtualObjectsArrays() {
+        HashMap<VirtualObjectNode, Object[]> arrayValues = new HashMap<>();
+        int pos = 0;
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            VirtualObjectNode virtualObject = virtualObjects.get(i);
+            int entryCount = virtualObject.entryCount();
+            ValueNode[] array = values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]);
+            arrayValues.put(virtualObject, array);
+            pos += entryCount;
+        }
+        return arrayValues;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java
new file mode 100644
index 0000000..a24ccf9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.VerificationError;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class EnsureVirtualizedNode extends FixedWithNextNode implements Virtualizable, Lowerable {
+
+    public static final NodeClass<EnsureVirtualizedNode> TYPE = NodeClass.create(EnsureVirtualizedNode.class);
+
+    @Input ValueNode object;
+    private final boolean localOnly;
+
+    public EnsureVirtualizedNode(ValueNode object, boolean localOnly) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.localOnly = localOnly;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias = tool.getAlias(object);
+        if (alias instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual = (VirtualObjectNode) alias;
+            if (virtual instanceof VirtualBoxingNode) {
+                Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName());
+                throw GraphUtil.approxSourceException(this, exception);
+            }
+            if (!localOnly) {
+                tool.setEnsureVirtualized(virtual, true);
+            }
+            tool.delete();
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        ensureVirtualFailure(this, object.stamp());
+    }
+
+    public static void ensureVirtualFailure(Node location, Stamp stamp) {
+        String additionalReason = "";
+        if (location instanceof FixedWithNextNode && !(location instanceof EnsureVirtualizedNode)) {
+            FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) location;
+            FixedNode next = fixedWithNextNode.next();
+            if (next instanceof StoreFieldNode) {
+                additionalReason = " (must not store virtual object into a field)";
+            } else if (next instanceof Invoke) {
+                additionalReason = " (must not pass virtual object into an invoke that cannot be inlined)";
+            } else {
+                additionalReason = " (must not let virtual object escape at node " + next + ")";
+            }
+        }
+        Throwable exception = new VerificationError("Object of type %s should not be materialized%s:", StampTool.typeOrNull(stamp).getName(), additionalReason);
+
+        Node pos;
+        if (location instanceof FixedWithNextNode) {
+            pos = ((FixedWithNextNode) location).next();
+        } else if (location instanceof AbstractEndNode) {
+            pos = ((AbstractEndNode) location).merge();
+        } else {
+            pos = location;
+        }
+        throw GraphUtil.approxSourceException(pos, exception);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EscapeObjectState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EscapeObjectState.java
new file mode 100644
index 0000000..3e48803
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EscapeObjectState.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.VirtualState;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public abstract class EscapeObjectState extends VirtualState implements ValueNumberable {
+    public static final NodeClass<EscapeObjectState> TYPE = NodeClass.create(EscapeObjectState.class);
+
+    @Input protected VirtualObjectNode object;
+
+    public VirtualObjectNode object() {
+        return object;
+    }
+
+    public EscapeObjectState(NodeClass<? extends EscapeObjectState> c, VirtualObjectNode object) {
+        super(c);
+        this.object = object;
+    }
+
+    @Override
+    public abstract EscapeObjectState duplicateWithVirtualState();
+
+    @Override
+    public boolean isPartOfThisState(VirtualState state) {
+        return this == state;
+    }
+
+    @Override
+    public void applyToVirtual(VirtualClosure closure) {
+        closure.apply(this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/LockState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/LockState.java
new file mode 100644
index 0000000..218000a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/LockState.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+
+/**
+ * The class implements a simple linked list of MonitorIdNodes, which can be used to describe the
+ * current lock state of an object.
+ */
+public final class LockState {
+
+    public final MonitorIdNode monitorId;
+    public final LockState next;
+
+    public LockState(MonitorIdNode monitorId, LockState next) {
+        this.monitorId = monitorId;
+        this.next = next;
+    }
+
+    @Override
+    public String toString() {
+        return monitorId.getLockDepth() + (next == null ? "" : "," + next);
+    }
+
+    public static List<MonitorIdNode> asList(LockState state) {
+        if (state == null) {
+            return Collections.emptyList();
+        } else {
+            ArrayList<MonitorIdNode> result = new ArrayList<>();
+            LockState a = state;
+            do {
+                result.add(a.monitorId);
+                a = a.next;
+            } while (a != null);
+            return result;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java
new file mode 100644
index 0000000..c0e4768
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import java.nio.ByteOrder;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import sun.misc.Unsafe;
+
+@NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
+public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
+
+    public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
+    protected final ResolvedJavaType componentType;
+    protected final int length;
+
+    public VirtualArrayNode(ResolvedJavaType componentType, int length) {
+        this(TYPE, componentType, length);
+    }
+
+    protected VirtualArrayNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType componentType, int length) {
+        super(c, componentType.getArrayClass(), true);
+        this.componentType = componentType;
+        this.length = length;
+    }
+
+    @Override
+    public ResolvedJavaType type() {
+        return componentType.getArrayClass();
+    }
+
+    public ResolvedJavaType componentType() {
+        return componentType;
+    }
+
+    @Override
+    public int entryCount() {
+        return length;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // nothing to do...
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + " " + componentType.getName() + "[" + length + "]";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public String entryName(int index) {
+        return "[" + index + "]";
+    }
+
+    @Override
+    public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) {
+        return entryIndexForOffset(constantOffset, expectedEntryKind, componentType, length);
+    }
+
+    public static int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) {
+        int baseOffset;
+        int indexScale;
+        switch (componentType.getJavaKind()) {
+            case Boolean:
+                baseOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
+                break;
+            case Byte:
+                baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE;
+                break;
+            case Short:
+                baseOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_SHORT_INDEX_SCALE;
+                break;
+            case Char:
+                baseOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_CHAR_INDEX_SCALE;
+                break;
+            case Int:
+                baseOffset = Unsafe.ARRAY_INT_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_INT_INDEX_SCALE;
+                break;
+            case Long:
+                baseOffset = Unsafe.ARRAY_LONG_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_LONG_INDEX_SCALE;
+                break;
+            case Float:
+                baseOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_FLOAT_INDEX_SCALE;
+                break;
+            case Double:
+                baseOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
+                break;
+            case Object:
+                baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET;
+                indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+                break;
+            default:
+                return -1;
+        }
+        long offset;
+        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) {
+            // On big endian, we do just get expect the type be right aligned in this memory slot
+            offset = constantOffset - (componentType.getJavaKind().getByteCount() - Math.min(componentType.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()));
+        } else {
+            offset = constantOffset;
+        }
+        long index = offset - baseOffset;
+        if (index % indexScale != 0) {
+            return -1;
+        }
+        long elementIndex = index / indexScale;
+        if (elementIndex < 0 || elementIndex >= length) {
+            return -1;
+        }
+        return (int) elementIndex;
+    }
+
+    @Override
+    public JavaKind entryKind(int index) {
+        assert index >= 0 && index < length;
+        return componentType.getJavaKind();
+    }
+
+    @Override
+    public VirtualArrayNode duplicate() {
+        return new VirtualArrayNode(componentType, length);
+    }
+
+    @Override
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
+        return new AllocatedObjectNode(this);
+    }
+
+    @Override
+    public ValueNode length() {
+        return ConstantNode.forInt(length);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualBoxingNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualBoxingNode.java
new file mode 100644
index 0000000..a309068
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualBoxingNode.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo
+public class VirtualBoxingNode extends VirtualInstanceNode {
+
+    public static final NodeClass<VirtualBoxingNode> TYPE = NodeClass.create(VirtualBoxingNode.class);
+    protected final JavaKind boxingKind;
+
+    public VirtualBoxingNode(ResolvedJavaType type, JavaKind boxingKind) {
+        this(TYPE, type, boxingKind);
+    }
+
+    public VirtualBoxingNode(NodeClass<? extends VirtualBoxingNode> c, ResolvedJavaType type, JavaKind boxingKind) {
+        super(c, type, false);
+        this.boxingKind = boxingKind;
+    }
+
+    public JavaKind getBoxingKind() {
+        return boxingKind;
+    }
+
+    @Override
+    public VirtualBoxingNode duplicate() {
+        return new VirtualBoxingNode(type(), boxingKind);
+    }
+
+    @Override
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
+        assert entries.length == 1;
+        assert locks == null;
+        return new BoxNode(entries[0], type(), boxingKind);
+    }
+
+    public ValueNode getBoxedValue(VirtualizerTool tool) {
+        return tool.getEntry(this, 0);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java
new file mode 100644
index 0000000..0591a2d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}")
+public class VirtualInstanceNode extends VirtualObjectNode {
+
+    public static final NodeClass<VirtualInstanceNode> TYPE = NodeClass.create(VirtualInstanceNode.class);
+    protected final ResolvedJavaType type;
+    protected final ResolvedJavaField[] fields;
+
+    public VirtualInstanceNode(ResolvedJavaType type, boolean hasIdentity) {
+        this(type, type.getInstanceFields(true), hasIdentity);
+    }
+
+    public VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields, boolean hasIdentity) {
+        this(TYPE, type, fields, hasIdentity);
+    }
+
+    protected VirtualInstanceNode(NodeClass<? extends VirtualInstanceNode> c, ResolvedJavaType type, boolean hasIdentity) {
+        this(c, type, type.getInstanceFields(true), hasIdentity);
+    }
+
+    protected VirtualInstanceNode(NodeClass<? extends VirtualInstanceNode> c, ResolvedJavaType type, ResolvedJavaField[] fields, boolean hasIdentity) {
+        super(c, type, hasIdentity);
+        this.type = type;
+        this.fields = fields;
+    }
+
+    @Override
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    @Override
+    public int entryCount() {
+        return fields.length;
+    }
+
+    public ResolvedJavaField field(int index) {
+        return fields[index];
+    }
+
+    public ResolvedJavaField[] getFields() {
+        return fields;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + " " + type.toJavaName(false);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public String entryName(int index) {
+        return fields[index].getName();
+    }
+
+    public int fieldIndex(ResolvedJavaField field) {
+        // on average fields.length == ~6, so a linear search is fast enough
+        for (int i = 0; i < fields.length; i++) {
+            if (fields[i].equals(field)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) {
+        return fieldIndex(type.findInstanceFieldWithOffset(constantOffset, expectedEntryKind));
+    }
+
+    @Override
+    public JavaKind entryKind(int index) {
+        assert index >= 0 && index < fields.length;
+        return fields[index].getJavaKind();
+    }
+
+    @Override
+    public VirtualInstanceNode duplicate() {
+        return new VirtualInstanceNode(type, fields, super.hasIdentity());
+    }
+
+    @Override
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
+        return new AllocatedObjectNode(this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java
new file mode 100644
index 0000000..2c512a2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.virtual;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.graph.IterableNodeType;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, IterableNodeType {
+
+    public static final NodeClass<VirtualObjectNode> TYPE = NodeClass.create(VirtualObjectNode.class);
+    protected boolean hasIdentity;
+    private int objectId = -1;
+
+    protected VirtualObjectNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType type, boolean hasIdentity) {
+        super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(type)));
+        this.hasIdentity = hasIdentity;
+    }
+
+    public final int getObjectId() {
+        return objectId;
+    }
+
+    public final void resetObjectId() {
+        this.objectId = -1;
+    }
+
+    public final void setObjectId(int objectId) {
+        assert objectId != -1;
+        this.objectId = objectId;
+    }
+
+    @Override
+    protected void afterClone(Node other) {
+        super.afterClone(other);
+        resetObjectId();
+    }
+
+    /**
+     * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is
+     * the array type (and not the component type).
+     */
+    public abstract ResolvedJavaType type();
+
+    /**
+     * The number of entries this virtual object has. Either the number of fields or the number of
+     * array elements.
+     */
+    public abstract int entryCount();
+
+    /**
+     * Returns the name of the entry at the given index. Only used for debugging purposes.
+     */
+    public abstract String entryName(int i);
+
+    /**
+     * If the given index denotes an entry in this virtual object, the index of this entry is
+     * returned. If no such entry can be found, this method returns -1.
+     *
+     * @param constantOffset offset, where the value is placed.
+     * @param expectedEntryKind Specifies which type is expected at this offset (Is important when
+     *            doing implicit casts, especially on big endian systems.
+     */
+    public abstract int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind);
+
+    /**
+     * Returns the {@link JavaKind} of the entry at the given index.
+     */
+    public abstract JavaKind entryKind(int index);
+
+    /**
+     * Returns an exact duplicate of this virtual object node, which has not been added to the graph
+     * yet.
+     */
+    public abstract VirtualObjectNode duplicate();
+
+    /**
+     * Specifies whether this virtual object has an object identity. If not, then the result of a
+     * comparison of two virtual objects is determined by comparing their contents.
+     */
+    public boolean hasIdentity() {
+        return hasIdentity;
+    }
+
+    public void setIdentity(boolean identity) {
+        this.hasIdentity = identity;
+    }
+
+    /**
+     * Returns a node that can be used to materialize this virtual object. If this returns an
+     * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode}
+     * , otherwise the node will just be added to the graph.
+     */
+    public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        // nothing to do...
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..f301f7e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.graalvm.compiler.options.processor.OptionProcessor
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java
new file mode 100644
index 0000000..2015650
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options.processor;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.JavaFileObject;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionValue;
+
+/**
+ * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors}
+ * implementation is generated for each top level class containing at least one such field. The name
+ * of the generated class for top level class {@code com.foo.Bar} is
+ * {@code com.foo.Bar_OptionDescriptors}.
+ */
+@SupportedAnnotationTypes({"org.graalvm.compiler.options.Option"})
+public class OptionProcessor extends AbstractProcessor {
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processed = new HashSet<>();
+
+    private void processElement(Element element, OptionsInfo info) {
+
+        if (!element.getModifiers().contains(Modifier.STATIC)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element);
+            return;
+        }
+        if (element.getModifiers().contains(Modifier.PRIVATE)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be private", element);
+            return;
+        }
+
+        Option annotation = element.getAnnotation(Option.class);
+        assert annotation != null;
+        assert element instanceof VariableElement;
+        assert element.getKind() == ElementKind.FIELD;
+        VariableElement field = (VariableElement) element;
+        String fieldName = field.getSimpleName().toString();
+
+        Elements elements = processingEnv.getElementUtils();
+        Types types = processingEnv.getTypeUtils();
+
+        TypeMirror fieldType = field.asType();
+        if (fieldType.getKind() != TypeKind.DECLARED) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element);
+            return;
+        }
+        DeclaredType declaredFieldType = (DeclaredType) fieldType;
+
+        TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType();
+        if (!types.isSubtype(fieldType, types.erasure(optionValueType))) {
+            String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType);
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+            return;
+        }
+
+        if (!field.getModifiers().contains(Modifier.STATIC)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element);
+            return;
+        }
+        if (field.getModifiers().contains(Modifier.PRIVATE)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be private", element);
+            return;
+        }
+
+        String help = annotation.help();
+        if (help.length() != 0) {
+            char firstChar = help.charAt(0);
+            if (!Character.isUpperCase(firstChar)) {
+                processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element);
+                return;
+            }
+        }
+
+        String optionName = annotation.name();
+        if (optionName.equals("")) {
+            optionName = fieldName;
+        }
+
+        if (!Character.isUpperCase(optionName.charAt(0))) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option name must start with capital letter", element);
+            return;
+        }
+
+        DeclaredType declaredOptionValueType = declaredFieldType;
+        while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) {
+            List<? extends TypeMirror> directSupertypes = types.directSupertypes(declaredFieldType);
+            assert !directSupertypes.isEmpty();
+            declaredOptionValueType = (DeclaredType) directSupertypes.get(0);
+        }
+
+        assert !declaredOptionValueType.getTypeArguments().isEmpty();
+        String optionType = declaredOptionValueType.getTypeArguments().get(0).toString();
+        if (optionType.startsWith("java.lang.")) {
+            optionType = optionType.substring("java.lang.".length());
+        }
+
+        Element enclosing = element.getEnclosingElement();
+        String declaringClass = "";
+        String separator = "";
+        Set<Element> originatingElementsList = info.originatingElements;
+        originatingElementsList.add(field);
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                    String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+                    return;
+                }
+                originatingElementsList.add(enclosing);
+                declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                separator = ".";
+            } else {
+                assert enclosing.getKind() == ElementKind.PACKAGE;
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+
+        info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field));
+    }
+
+    private void createFiles(OptionsInfo info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements);
+    }
+
+    private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) {
+        String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName();
+
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// CheckStyle: stop line length check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;");
+            out.println("");
+            out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {");
+
+            String desc = OptionDescriptor.class.getSimpleName();
+
+            int i = 0;
+            Collections.sort(info.options);
+
+            out.println("    @Override");
+            out.println("    public OptionDescriptor get(String value) {");
+            out.println("        // CheckStyle: stop line length check");
+            if (info.options.size() == 1) {
+                out.println("        if (value.equals(\"" + info.options.get(0).name + "\")) {");
+            } else {
+                out.println("        switch (value) {");
+            }
+            for (OptionInfo option : info.options) {
+                String name = option.name;
+                String optionValue;
+                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
+                    throw new InternalError();
+                } else {
+                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
+                }
+                String type = option.type;
+                String help = option.help;
+                String declaringClass = option.declaringClass;
+                Name fieldName = option.field.getSimpleName();
+                if (info.options.size() == 1) {
+                    out.printf("            return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue);
+                } else {
+                    out.printf("            case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName,
+                                    optionValue);
+                }
+            }
+            out.println("        }");
+            out.println("        // CheckStyle: resume line length check");
+            out.println("        return null;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public Iterator<" + desc + "> iterator() {");
+            out.println("        // CheckStyle: stop line length check");
+            out.println("        List<" + desc + "> options = Arrays.asList(");
+            for (OptionInfo option : info.options) {
+                String optionValue;
+                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
+                    throw new InternalError();
+                } else {
+                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
+                }
+                String name = option.name;
+                String type = option.type;
+                String help = option.help;
+                String declaringClass = option.declaringClass;
+                Name fieldName = option.field.getSimpleName();
+                String comma = i == info.options.size() - 1 ? "" : ",";
+                out.printf("            %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma);
+                i++;
+            }
+            out.println("        );");
+            out.println("        // CheckStyle: resume line length check");
+            out.println("        return options.iterator();");
+            out.println("    }");
+            out.println("}");
+        }
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static class OptionInfo implements Comparable<OptionInfo> {
+
+        final String name;
+        final String help;
+        final String type;
+        final String declaringClass;
+        final VariableElement field;
+
+        OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) {
+            this.name = name;
+            this.help = help;
+            this.type = type;
+            this.declaringClass = declaringClass;
+            this.field = field;
+        }
+
+        @Override
+        public int compareTo(OptionInfo other) {
+            return name.compareTo(other.name);
+        }
+
+        @Override
+        public String toString() {
+            return declaringClass + "." + field;
+        }
+    }
+
+    static class OptionsInfo {
+
+        final Element topDeclaringType;
+        final List<OptionInfo> options = new ArrayList<>();
+        final Set<Element> originatingElements = new HashSet<>();
+
+        OptionsInfo(Element topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static Element topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        Map<Element, OptionsInfo> map = new HashMap<>();
+        for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) {
+            if (!processed.contains(element)) {
+                processed.add(element);
+                Element topDeclaringType = topDeclaringType(element);
+                OptionsInfo options = map.get(topDeclaringType);
+                if (options == null) {
+                    options = new OptionsInfo(topDeclaringType);
+                    map.put(topDeclaringType, options);
+                }
+                processElement(element, options);
+            }
+        }
+
+        boolean ok = true;
+        Map<String, OptionInfo> uniqueness = new HashMap<>();
+        for (OptionsInfo info : map.values()) {
+            for (OptionInfo option : info.options) {
+                OptionInfo conflict = uniqueness.put(option.name, option);
+                if (conflict != null) {
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field);
+                    ok = false;
+                }
+            }
+        }
+
+        if (ok) {
+            for (OptionsInfo info : map.values()) {
+                createFiles(info);
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionValueTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionValueTest.java
new file mode 100644
index 0000000..ff842fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionValueTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run junit jdk.vm.ci.options.test.NestedBooleanOptionValueTest
+ */
+
+package org.graalvm.compiler.options.test;
+
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.Master0;
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.Master1;
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.Master2;
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.NestedOption0;
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.NestedOption1;
+import static org.graalvm.compiler.options.test.NestedBooleanOptionValueTest.Options.NestedOption2;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.options.NestedBooleanOptionValue;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+public class NestedBooleanOptionValueTest {
+
+    public static class Options {
+        public static final OptionValue<Boolean> Master0 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption0 = new NestedBooleanOptionValue(Master0, true);
+        public static final OptionValue<Boolean> Master1 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption1 = new NestedBooleanOptionValue(Master1, true);
+        public static final OptionValue<Boolean> Master2 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption2 = new NestedBooleanOptionValue(Master2, false);
+    }
+
+    static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0);
+    static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0);
+    static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1);
+    static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1);
+    static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2);
+    static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2);
+
+    @SuppressWarnings("try")
+    @Test
+    public void runOverrides() {
+        assertTrue(Master0.getValue());
+        assertTrue(NestedOption0.getValue());
+        try (OverrideScope s1 = OptionValue.override(Master0, false)) {
+            assertFalse(Master0.getValue());
+            assertFalse(NestedOption0.getValue());
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) {
+                assertFalse(NestedOption0.getValue());
+            }
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) {
+                assertTrue(NestedOption0.getValue());
+            }
+        }
+        assertTrue(Master0.getValue());
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) {
+            assertFalse(NestedOption0.getValue());
+        }
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) {
+            assertTrue(NestedOption0.getValue());
+        }
+    }
+
+    @Test
+    public void runDefaultTrue() {
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        // nested value unset
+        Master1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set false
+        Master1.setValue(false);
+        NestedOption1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set true
+        Master1.setValue(false);
+        NestedOption1.setValue(true);
+        assertFalse(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+    }
+
+    @Test
+    public void runDefaultFalse() {
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // nested value unset
+        Master2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set false
+        Master2.setValue(false);
+        NestedOption2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set true
+        Master2.setValue(false);
+        NestedOption2.setValue(true);
+        assertFalse(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionValue.java
new file mode 100644
index 0000000..b98fd55
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionValue.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run junit org.graalvm.compiler.options.test.TestOptionValue
+ */
+
+package org.graalvm.compiler.options.test;
+
+import static org.graalvm.compiler.options.test.TestOptionValue.Options.Mutable;
+import static org.graalvm.compiler.options.test.TestOptionValue.Options.SecondMutable;
+import static org.graalvm.compiler.options.test.TestOptionValue.Options.Stable;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+@SuppressWarnings("try")
+public class TestOptionValue {
+
+    public static class Options {
+        public static final OptionValue<Boolean> Stable = new StableOptionValue<>(true);
+        public static final OptionValue<String> Mutable = new OptionValue<>("original");
+        public static final OptionValue<String> SecondMutable = new OptionValue<>("second");
+    }
+
+    static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable);
+    static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable);
+    static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable);
+
+    @Test
+    public void testMutable() {
+        assertEquals("original", Mutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals("override1", Mutable.getValue());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals("override2", Mutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) {
+                assertEquals("override3", Mutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+        }
+        assertEquals("original", Mutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "original")) {
+            assertEquals("original", Mutable.getValue());
+        }
+    }
+
+    @Test
+    public void testMultiple() {
+        assertEquals("original", Mutable.getValue());
+        assertEquals("second", SecondMutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) {
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) {
+                assertEquals("override2", Mutable.getValue());
+                assertEquals("secondOverride2", SecondMutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+            try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) {
+                assertEquals("override3", Mutable.getValue());
+                assertEquals("secondOverride3", SecondMutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+        }
+        assertEquals("original", Mutable.getValue());
+        assertEquals("second", SecondMutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) {
+            assertEquals("original", Mutable.getValue());
+            assertEquals("second", SecondMutable.getValue());
+        }
+    }
+
+    @Test
+    public void testStable() {
+        assertTrue(Stable.getValue());
+        try (OverrideScope s = OptionValue.override(Stable, false)) {
+            fail("cannot override stable option");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void toStringTest() {
+        assertEquals("Mutable=original", Mutable.toString());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals("Mutable=override1", Mutable.toString());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals("Mutable=override2", Mutable.toString());
+            }
+        }
+    }
+
+    @Test
+    public void getValuesTest() {
+        assertEquals(Arrays.asList("original"), Mutable.getValues(null));
+        assertEquals(Arrays.asList(true), Stable.getValues(null));
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null));
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/DerivedOptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/DerivedOptionValue.java
new file mode 100644
index 0000000..3ab267f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/DerivedOptionValue.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+
+/**
+ * A cached value that needs to be recomputed when an option changes.
+ */
+public class DerivedOptionValue<T> {
+
+    public interface OptionSupplier<T> extends Supplier<T>, Serializable {
+    }
+
+    private T initialValue;
+    private final OptionSupplier<T> supplier;
+
+    public DerivedOptionValue(OptionSupplier<T> supplier) {
+        this.supplier = supplier;
+    }
+
+    public T getValue() {
+        OverrideScope overrideScope = OptionValue.getOverrideScope();
+        if (overrideScope != null) {
+            return overrideScope.getDerived(this);
+        } else {
+            if (initialValue == null) {
+                initialValue = createValue();
+            }
+            return initialValue;
+        }
+    }
+
+    T createValue() {
+        return supplier.get();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionValue.java
new file mode 100644
index 0000000..53e1ca4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionValue.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.util.EnumSet;
+
+public class EnumOptionValue<T extends Enum<T>> extends OptionValue<T> {
+    final Class<T> enumClass;
+
+    @SuppressWarnings("unchecked")
+    public EnumOptionValue(T value) {
+        super(value);
+        if (value == null) {
+            throw new IllegalArgumentException("Value must not be null");
+        }
+        this.enumClass = (Class<T>) value.getClass();
+    }
+
+    /**
+     *
+     * @return the set of possible values for this option.
+     */
+    public EnumSet<T> getOptionValues() {
+        return EnumSet.allOf(enumClass);
+    }
+
+    @Override
+    public void setValue(Object v) {
+        try {
+            super.setValue(Enum.valueOf(enumClass, (String) v));
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException("\"" + v + "\" is not a valid option for " + getName() + ".  Valid values are " + EnumSet.allOf(enumClass));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/NestedBooleanOptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/NestedBooleanOptionValue.java
new file mode 100644
index 0000000..67a922c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/NestedBooleanOptionValue.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+/**
+ * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master
+ * option}.
+ * <p>
+ * <li>If the option is present on the command line the specified value is used.
+ * <li>Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows:
+ * <ul>
+ * <li>If {@link #masterOption} is set, this value equals to {@link #initialValue}.
+ * <li>Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}.
+ */
+public class NestedBooleanOptionValue extends OptionValue<Boolean> {
+    private final OptionValue<Boolean> masterOption;
+    private final Boolean initialValue;
+
+    public NestedBooleanOptionValue(OptionValue<Boolean> masterOption, Boolean initialValue) {
+        super(null);
+        this.masterOption = masterOption;
+        this.initialValue = initialValue;
+    }
+
+    public OptionValue<Boolean> getMasterOption() {
+        return masterOption;
+    }
+
+    @Override
+    public Boolean getValue() {
+        Boolean v = super.getValue();
+        if (v == null) {
+            return initialValue && masterOption.getValue();
+        }
+        return v;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java
new file mode 100644
index 0000000..56283b6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Describes the attributes of an option whose {@link OptionValue value} is in a static field
+ * annotated by this annotation type.
+ *
+ * @see OptionDescriptor
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.FIELD)
+public @interface Option {
+
+    /**
+     * Gets a help message for the option. New lines can be embedded in the message with
+     * {@code "%n"}.
+     */
+    String help();
+
+    /**
+     * The name of the option. By default, the name of the annotated field should be used.
+     */
+    String name() default "";
+
+    /**
+     * Specifies the type of the option.
+     */
+    OptionType type() default OptionType.Debug;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java
new file mode 100644
index 0000000..d43512f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+/**
+ * Describes the attributes of a static field {@linkplain Option option} and provides access to its
+ * {@linkplain OptionValue value}.
+ */
+public final class OptionDescriptor {
+
+    protected final String name;
+    protected final Class<?> type;
+    protected final String help;
+    protected final OptionValue<?> option;
+    protected final Class<?> declaringClass;
+    protected final String fieldName;
+
+    public static OptionDescriptor create(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionValue<?> option) {
+        OptionDescriptor result = option.getDescriptor();
+        if (result == null) {
+            result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option);
+            option.setDescriptor(result);
+        }
+        assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option;
+        return result;
+    }
+
+    private OptionDescriptor(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionValue<?> option) {
+        this.name = name;
+        this.type = type;
+        this.help = help;
+        this.option = option;
+        this.declaringClass = declaringClass;
+        this.fieldName = fieldName;
+        assert !type.isPrimitive() : "must used boxed type instead of " + type;
+    }
+
+    /**
+     * Gets the type of values stored in the option. This will be the boxed type for a primitive
+     * option.
+     */
+    public Class<?> getType() {
+        return type;
+    }
+
+    /**
+     * Gets a descriptive help message for the option.
+     */
+    public String getHelp() {
+        return help;
+    }
+
+    /**
+     * Gets the name of the option. It's up to the client of this object how to use the name to get
+     * a user specified value for the option from the environment.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the boxed option value.
+     */
+    public OptionValue<?> getOptionValue() {
+        return option;
+    }
+
+    public Class<?> getDeclaringClass() {
+        return declaringClass;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    /**
+     * Gets a description of the location where this option is stored.
+     */
+    public String getLocation() {
+        return getDeclaringClass().getName() + "." + getFieldName();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptors.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptors.java
new file mode 100644
index 0000000..e210948
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptors.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+/**
+ * An interface to a set of {@link OptionDescriptor}s.
+ */
+public interface OptionDescriptors extends Iterable<OptionDescriptor> {
+    /**
+     * Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option
+     * descriptor set doesn't contain a matching option.
+     */
+    OptionDescriptor get(String value);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionType.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionType.java
new file mode 100644
index 0000000..9f30b7f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionType.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+/**
+ * Classifies Graal options in several categories depending on who this option is relevant for.
+ *
+ */
+public enum OptionType {
+    /**
+     * An option common for users to apply.
+     */
+    User,
+
+    /**
+     * An option only relevant in corner cases and for fine-tuning.
+     */
+    Expert,
+
+    /**
+     * An option only relevant when debugging the compiler.
+     */
+    Debug
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValue.java
new file mode 100644
index 0000000..c3c5aa8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValue.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.ServiceLoader;
+
+/**
+ * An option value.
+ */
+public class OptionValue<T> {
+    /**
+     * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of
+     * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the
+     * object returned by this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * try (OverrideScope s = OptionValue.override(myOption, myValue)) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     */
+    public static OverrideScope override(OptionValue<?> option, Object value) {
+        OverrideScope current = getOverrideScope();
+        if (current == null) {
+            if (!value.equals(option.getValue())) {
+                return new SingleOverrideScope(option, value);
+            }
+            Map<OptionValue<?>, Object> overrides = Collections.emptyMap();
+            return new MultipleOverridesScope(current, overrides);
+        }
+        return new MultipleOverridesScope(current, option, value);
+    }
+
+    /**
+     * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue()
+     * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value}
+     * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by
+     * this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * Map&lt;OptionValue, Object&gt; overrides = new HashMap&lt;&gt;();
+     * overrides.put(myOption1, myValue1);
+     * overrides.put(myOption2, myValue2);
+     * try (OverrideScope s = OptionValue.override(overrides)) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     */
+    public static OverrideScope override(Map<OptionValue<?>, Object> overrides) {
+        OverrideScope current = getOverrideScope();
+        if (current == null && overrides.size() == 1) {
+            Entry<OptionValue<?>, Object> single = overrides.entrySet().iterator().next();
+            OptionValue<?> option = single.getKey();
+            Object overrideValue = single.getValue();
+            return new SingleOverrideScope(option, overrideValue);
+        }
+        return new MultipleOverridesScope(current, overrides);
+    }
+
+    /**
+     * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue()
+     * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value}
+     * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by
+     * this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2)) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     *
+     * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]}
+     */
+    public static OverrideScope override(Object... overrides) {
+        OverrideScope current = getOverrideScope();
+        if (current == null && overrides.length == 2) {
+            OptionValue<?> option = (OptionValue<?>) overrides[0];
+            Object overrideValue = overrides[1];
+            if (!overrideValue.equals(option.getValue())) {
+                return new SingleOverrideScope(option, overrideValue);
+            }
+        }
+        Map<OptionValue<?>, Object> map = Collections.emptyMap();
+        for (int i = 0; i < overrides.length; i += 2) {
+            OptionValue<?> option = (OptionValue<?>) overrides[i];
+            Object overrideValue = overrides[i + 1];
+            if (!overrideValue.equals(option.getValue())) {
+                if (map.isEmpty()) {
+                    map = new HashMap<>();
+                }
+                map.put(option, overrideValue);
+            }
+        }
+        return new MultipleOverridesScope(current, map);
+    }
+
+    private static final ThreadLocal<OverrideScope> overrideScopeTL = new ThreadLocal<>();
+
+    protected static OverrideScope getOverrideScope() {
+        return overrideScopeTL.get();
+    }
+
+    protected static void setOverrideScope(OverrideScope overrideScope) {
+        overrideScopeTL.set(overrideScope);
+    }
+
+    private T defaultValue;
+
+    /**
+     * The raw option value.
+     */
+    protected T value;
+
+    private OptionDescriptor descriptor;
+
+    private long reads;
+    private OptionValue<?> next;
+    private static OptionValue<?> head;
+
+    /**
+     * Name of the boolean system property governing whether to profile the number of times
+     * {@link #getValue()} is called for each {@link OptionValue}.
+     */
+    public static final String PROFILE_OPTIONVALUE_PROPERTY_NAME = "graal.profileOptionValue";
+
+    private static final boolean ProfileOptionValue = Boolean.getBoolean(PROFILE_OPTIONVALUE_PROPERTY_NAME);
+
+    private static void addToHistogram(OptionValue<?> option) {
+        if (ProfileOptionValue) {
+            synchronized (OptionValue.class) {
+                option.next = head;
+                head = option;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public OptionValue(T value) {
+        this.defaultValue = value;
+        this.value = (T) DEFAULT;
+        addToHistogram(this);
+    }
+
+    private static final Object DEFAULT = "DEFAULT";
+    private static final Object UNINITIALIZED = "UNINITIALIZED";
+
+    /**
+     * Creates an uninitialized option value for a subclass that initializes itself
+     * {@link #defaultValue() lazily}.
+     */
+    @SuppressWarnings("unchecked")
+    protected OptionValue() {
+        this.defaultValue = (T) UNINITIALIZED;
+        this.value = (T) DEFAULT;
+        addToHistogram(this);
+    }
+
+    /**
+     * Lazy initialization of default value.
+     */
+    protected T defaultValue() {
+        throw new InternalError("Option without a default value value must override defaultValue()");
+    }
+
+    /**
+     * Sets the descriptor for this option.
+     */
+    public void setDescriptor(OptionDescriptor descriptor) {
+        assert this.descriptor == null : "Overwriting existing descriptor";
+        this.descriptor = descriptor;
+    }
+
+    /**
+     * Returns the descriptor for this option, if it has been set by
+     * {@link #setDescriptor(OptionDescriptor)}.
+     */
+    public OptionDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Mechanism for lazily loading all available options which has the side effect of assigning
+     * names to the options.
+     */
+    static class Lazy {
+        static void init() {
+            ServiceLoader<OptionDescriptors> loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader());
+            for (OptionDescriptors opts : loader) {
+                for (OptionDescriptor desc : opts) {
+                    desc.getName();
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the name of this option. The name for an option value with a null
+     * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of
+     * {@link Object#toString()}.
+     */
+    public String getName() {
+        if (descriptor == null) {
+            // Trigger initialization of OptionsLoader to ensure all option values have
+            // a descriptor which is required for them to have meaningful names.
+            Lazy.init();
+        }
+        return descriptor == null ? super.toString() : descriptor.getName();
+    }
+
+    @Override
+    public String toString() {
+        return getName() + "=" + getValue();
+    }
+
+    /**
+     * The initial value specified in source code. The returned value is not affected by calls to
+     * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not
+     * affected by options set on the command line.
+     */
+    public T getDefaultValue() {
+        if (defaultValue == UNINITIALIZED) {
+            defaultValue = defaultValue();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns true if the option has been set in any way. Note that this doesn't mean that the
+     * current value is different than the default.
+     */
+    public boolean hasBeenSet() {
+        if (!(this instanceof StableOptionValue)) {
+            getValue(); // ensure initialized
+
+            OverrideScope overrideScope = getOverrideScope();
+            if (overrideScope != null) {
+                T override = overrideScope.getOverride(this);
+                if (override != null) {
+                    return true;
+                }
+            }
+        }
+        return value != DEFAULT;
+    }
+
+    /**
+     * Gets the value of this option.
+     */
+    public T getValue() {
+        if (ProfileOptionValue) {
+            reads++;
+        }
+        if (!(this instanceof StableOptionValue)) {
+            OverrideScope overrideScope = getOverrideScope();
+            if (overrideScope != null) {
+                T override = overrideScope.getOverride(this);
+                if (override != null) {
+                    return override;
+                }
+            }
+        }
+        if (value != DEFAULT) {
+            return value;
+        } else {
+            return getDefaultValue();
+        }
+    }
+
+    /**
+     * Gets the values of this option including overridden values.
+     *
+     * @param c the collection to which the values are added. If null, one is allocated.
+     * @return the collection to which the values were added in order from most overridden to
+     *         current value
+     */
+    @SuppressWarnings("unchecked")
+    public Collection<T> getValues(Collection<T> c) {
+        Collection<T> values = c == null ? new ArrayList<>() : c;
+        if (!(this instanceof StableOptionValue)) {
+            OverrideScope overrideScope = getOverrideScope();
+            if (overrideScope != null) {
+                overrideScope.getOverrides(this, (Collection<Object>) values);
+            }
+        }
+        if (value != DEFAULT) {
+            values.add(value);
+        } else {
+            values.add(getDefaultValue());
+        }
+        return values;
+    }
+
+    /**
+     * Sets the value of this option.
+     */
+    @SuppressWarnings("unchecked")
+    public void setValue(Object v) {
+        this.value = (T) v;
+    }
+
+    /**
+     * An object whose {@link #close()} method reverts the option value overriding initiated by
+     * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}.
+     */
+    public abstract static class OverrideScope implements AutoCloseable {
+
+        private Map<DerivedOptionValue<?>, Object> derivedCache = null;
+
+        public <T> T getDerived(DerivedOptionValue<T> key) {
+            if (derivedCache == null) {
+                derivedCache = new HashMap<>();
+            }
+            @SuppressWarnings("unchecked")
+            T ret = (T) derivedCache.get(key);
+            if (ret == null) {
+                ret = key.createValue();
+                derivedCache.put(key, ret);
+            }
+            return ret;
+        }
+
+        abstract void addToInherited(Map<OptionValue<?>, Object> inherited);
+
+        abstract <T> T getOverride(OptionValue<T> option);
+
+        abstract void getOverrides(OptionValue<?> option, Collection<Object> c);
+
+        @Override
+        public abstract void close();
+    }
+
+    static class SingleOverrideScope extends OverrideScope {
+
+        private final OptionValue<?> option;
+        private final Object value;
+
+        SingleOverrideScope(OptionValue<?> option, Object value) {
+            if (option instanceof StableOptionValue) {
+                throw new IllegalArgumentException("Cannot override stable option " + option);
+            }
+            this.option = option;
+            this.value = value;
+            setOverrideScope(this);
+        }
+
+        @Override
+        void addToInherited(Map<OptionValue<?>, Object> inherited) {
+            inherited.put(option, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        <T> T getOverride(OptionValue<T> key) {
+            if (key == this.option) {
+                return (T) value;
+            }
+            return null;
+        }
+
+        @Override
+        void getOverrides(OptionValue<?> key, Collection<Object> c) {
+            if (key == this.option) {
+                c.add(value);
+            }
+        }
+
+        @Override
+        public void close() {
+            setOverrideScope(null);
+        }
+    }
+
+    static class MultipleOverridesScope extends OverrideScope {
+        final OverrideScope parent;
+        final Map<OptionValue<?>, Object> overrides;
+
+        MultipleOverridesScope(OverrideScope parent, OptionValue<?> option, Object value) {
+            this.parent = parent;
+            this.overrides = new HashMap<>();
+            if (parent != null) {
+                parent.addToInherited(overrides);
+            }
+            if (option instanceof StableOptionValue) {
+                throw new IllegalArgumentException("Cannot override stable option " + option);
+            }
+            if (!value.equals(option.getValue())) {
+                this.overrides.put(option, value);
+            }
+            if (!overrides.isEmpty()) {
+                setOverrideScope(this);
+            }
+        }
+
+        MultipleOverridesScope(OverrideScope parent, Map<OptionValue<?>, Object> overrides) {
+            this.parent = parent;
+            if (overrides.isEmpty() && parent == null) {
+                this.overrides = Collections.emptyMap();
+                return;
+            }
+            this.overrides = new HashMap<>();
+            if (parent != null) {
+                parent.addToInherited(this.overrides);
+            }
+            for (Map.Entry<OptionValue<?>, Object> e : overrides.entrySet()) {
+                OptionValue<?> option = e.getKey();
+                if (option instanceof StableOptionValue) {
+                    throw new IllegalArgumentException("Cannot override stable option " + option);
+                }
+                this.overrides.put(option, e.getValue());
+            }
+            if (!this.overrides.isEmpty()) {
+                setOverrideScope(this);
+            }
+        }
+
+        @Override
+        void addToInherited(Map<OptionValue<?>, Object> inherited) {
+            if (parent != null) {
+                parent.addToInherited(inherited);
+            }
+            inherited.putAll(overrides);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        <T> T getOverride(OptionValue<T> option) {
+            return (T) overrides.get(option);
+        }
+
+        @Override
+        void getOverrides(OptionValue<?> option, Collection<Object> c) {
+            Object v = overrides.get(option);
+            if (v != null) {
+                c.add(v);
+            }
+            if (parent != null) {
+                parent.getOverrides(option, c);
+            }
+        }
+
+        @Override
+        public void close() {
+            if (!overrides.isEmpty()) {
+                setOverrideScope(parent);
+            }
+        }
+    }
+
+    static {
+        if (ProfileOptionValue) {
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                @Override
+                public void run() {
+                    ArrayList<OptionValue<?>> options = new ArrayList<>();
+                    for (OptionValue<?> option = head; option != null; option = option.next) {
+                        options.add(option);
+                    }
+                    Collections.sort(options, new Comparator<OptionValue<?>>() {
+
+                        @Override
+                        public int compare(OptionValue<?> o1, OptionValue<?> o2) {
+                            if (o1.reads < o2.reads) {
+                                return -1;
+                            } else if (o1.reads > o2.reads) {
+                                return 1;
+                            } else {
+                                return o1.getName().compareTo(o2.getName());
+                            }
+                        }
+                    });
+                    PrintStream out = System.out;
+                    out.println("=== OptionValue reads histogram ===");
+                    for (OptionValue<?> option : options) {
+                        out.println(option.reads + "\t" + option);
+                    }
+                }
+            });
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java
new file mode 100644
index 0000000..552d786
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * This class contains methods for parsing Graal options and matching them against a set of
+ * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded via a {@link ServiceLoader}.
+ */
+public class OptionsParser {
+
+    public interface OptionConsumer {
+        void set(OptionDescriptor desc, Object value);
+    }
+
+    /**
+     * Parses a map representing assignments of values to options.
+     *
+     * @param optionSettings option settings (i.e., assignments of values to options)
+     * @param setter the object to notify of the parsed option and value
+     * @param loader the loader for {@linkplain #lookup(ServiceLoader, String) looking} up
+     *            {@link OptionDescriptor}s
+     * @throws IllegalArgumentException if there's a problem parsing {@code option}
+     */
+    public static void parseOptions(Map<String, String> optionSettings, OptionConsumer setter, ServiceLoader<OptionDescriptors> loader) {
+        if (optionSettings != null && !optionSettings.isEmpty()) {
+
+            for (Map.Entry<String, String> e : optionSettings.entrySet()) {
+                parseOption(e.getKey(), e.getValue(), setter, loader);
+            }
+        }
+    }
+
+    /**
+     * Parses a given option setting string to a map of settings.
+     *
+     * @param optionSetting a string matching the pattern {@code <name>=<value>}
+     */
+    public static void parseOptionSettingTo(String optionSetting, Map<String, String> dst) {
+        int eqIndex = optionSetting.indexOf('=');
+        if (eqIndex == -1) {
+            throw new InternalError("Option setting has does not match the pattern <name>=<value>: " + optionSetting);
+        }
+        dst.put(optionSetting.substring(0, eqIndex), optionSetting.substring(eqIndex + 1));
+    }
+
+    /**
+     * Looks up an {@link OptionDescriptor} based on a given name.
+     *
+     * @param loader provides the available {@link OptionDescriptor}s
+     * @param name the name of the option to look up
+     * @return the {@link OptionDescriptor} whose name equals {@code name} or null if not such
+     *         descriptor is available
+     */
+    private static OptionDescriptor lookup(ServiceLoader<OptionDescriptors> loader, String name) {
+        for (OptionDescriptors optionDescriptors : loader) {
+            OptionDescriptor desc = optionDescriptors.get(name);
+            if (desc != null) {
+                return desc;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parses a given option name and value.
+     *
+     * @param name the option name
+     * @param valueString the option value as a string
+     * @param setter the object to notify of the parsed option and value
+     * @param loader the loader for {@linkplain #lookup(ServiceLoader, String) looking} up
+     *            {@link OptionDescriptor}s
+     * @throws IllegalArgumentException if there's a problem parsing {@code option}
+     */
+    private static void parseOption(String name, String valueString, OptionConsumer setter, ServiceLoader<OptionDescriptors> loader) {
+
+        OptionDescriptor desc = lookup(loader, name);
+        if (desc == null) {
+            List<OptionDescriptor> matches = fuzzyMatch(loader, name);
+            Formatter msg = new Formatter();
+            msg.format("Could not find option %s", name);
+            if (!matches.isEmpty()) {
+                msg.format("%nDid you mean one of the following?");
+                for (OptionDescriptor match : matches) {
+                    msg.format("%n    %s=<value>", match.getName());
+                }
+            }
+            throw new IllegalArgumentException(msg.toString());
+        }
+
+        Class<?> optionType = desc.getType();
+        Object value;
+        if (optionType == Boolean.class) {
+            if ("true".equals(valueString)) {
+                value = Boolean.TRUE;
+            } else if ("false".equals(valueString)) {
+                value = Boolean.FALSE;
+            } else {
+                throw new IllegalArgumentException("Boolean option '" + name + "' must have value \"true\" or \"false\", not \"" + valueString + "\"");
+            }
+        } else if (optionType == String.class || Enum.class.isAssignableFrom(optionType)) {
+            value = valueString;
+        } else {
+            if (valueString.isEmpty()) {
+                throw new IllegalArgumentException("Non empty value required for option '" + name + "'");
+            }
+            try {
+                if (optionType == Float.class) {
+                    value = Float.parseFloat(valueString);
+                } else if (optionType == Double.class) {
+                    value = Double.parseDouble(valueString);
+                } else if (optionType == Integer.class) {
+                    value = Integer.valueOf((int) parseLong(valueString));
+                } else if (optionType == Long.class) {
+                    value = Long.valueOf(parseLong(valueString));
+                } else {
+                    throw new IllegalArgumentException("Wrong value for option '" + name + "'");
+                }
+            } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException("Value for option '" + name + "' has invalid number format: " + valueString);
+            }
+        }
+        if (setter == null) {
+            desc.getOptionValue().setValue(value);
+        } else {
+            setter.set(desc, value);
+        }
+    }
+
+    private static long parseLong(String v) {
+        String valueString = v.toLowerCase();
+        long scale = 1;
+        if (valueString.endsWith("k")) {
+            scale = 1024L;
+        } else if (valueString.endsWith("m")) {
+            scale = 1024L * 1024L;
+        } else if (valueString.endsWith("g")) {
+            scale = 1024L * 1024L * 1024L;
+        } else if (valueString.endsWith("t")) {
+            scale = 1024L * 1024L * 1024L * 1024L;
+        }
+
+        if (scale != 1) {
+            /* Remove trailing scale character. */
+            valueString = valueString.substring(0, valueString.length() - 1);
+        }
+
+        return Long.parseLong(valueString) * scale;
+    }
+
+    /**
+     * Wraps some given text to one or more lines of a given maximum width.
+     *
+     * @param text text to wrap
+     * @param width maximum width of an output line, exception for words in {@code text} longer than
+     *            this value
+     * @return {@code text} broken into lines
+     */
+    private static List<String> wrap(String text, int width) {
+        List<String> lines = Collections.singletonList(text);
+        if (text.length() > width) {
+            String[] chunks = text.split("\\s+");
+            lines = new ArrayList<>();
+            StringBuilder line = new StringBuilder();
+            for (String chunk : chunks) {
+                if (line.length() + chunk.length() > width) {
+                    lines.add(line.toString());
+                    line.setLength(0);
+                }
+                if (line.length() != 0) {
+                    line.append(' ');
+                }
+                String[] embeddedLines = chunk.split("%n", -2);
+                if (embeddedLines.length == 1) {
+                    line.append(chunk);
+                } else {
+                    for (int i = 0; i < embeddedLines.length; i++) {
+                        line.append(embeddedLines[i]);
+                        if (i < embeddedLines.length - 1) {
+                            lines.add(line.toString());
+                            line.setLength(0);
+                        }
+                    }
+                }
+            }
+            if (line.length() != 0) {
+                lines.add(line.toString());
+            }
+        }
+        return lines;
+    }
+
+    private static final int PROPERTY_LINE_WIDTH = 80;
+    private static final int PROPERTY_HELP_INDENT = 10;
+
+    public static void printFlags(ServiceLoader<OptionDescriptors> loader, PrintStream out, Set<String> explicitlyAssigned, String namePrefix) {
+        SortedMap<String, OptionDescriptor> sortedOptions = new TreeMap<>();
+        for (OptionDescriptors opts : loader) {
+            for (OptionDescriptor desc : opts) {
+                String name = desc.getName();
+                OptionDescriptor existing = sortedOptions.put(name, desc);
+                assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
+            }
+        }
+        for (Map.Entry<String, OptionDescriptor> e : sortedOptions.entrySet()) {
+            OptionDescriptor desc = e.getValue();
+            Object value = desc.getOptionValue().getValue();
+            if (value instanceof String) {
+                value = '"' + String.valueOf(value) + '"';
+            }
+            String help = desc.getHelp();
+            if (desc.getOptionValue() instanceof EnumOptionValue) {
+                EnumOptionValue<?> eoption = (EnumOptionValue<?>) desc.getOptionValue();
+                String evalues = eoption.getOptionValues().toString();
+                if (help.length() > 0 && !help.endsWith(".")) {
+                    help += ".";
+                }
+                help += " Valid values are: " + evalues.substring(1, evalues.length() - 1);
+            }
+            String name = namePrefix + e.getKey();
+            String assign = explicitlyAssigned.contains(name) ? ":=" : "=";
+            String typeName = desc.getOptionValue() instanceof EnumOptionValue ? "String" : desc.getType().getSimpleName();
+            String linePrefix = String.format("%s %s %s ", name, assign, value);
+            int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length();
+            int linePad = typeStartPos - linePrefix.length();
+            if (linePad > 0) {
+                out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName);
+            } else {
+                out.printf("%s[%s]%n", linePrefix, typeName);
+            }
+
+            if (help.length() != 0) {
+                List<String> helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT);
+                for (int i = 0; i < helpLines.size(); i++) {
+                    out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", helpLines.get(i));
+                }
+            }
+        }
+    }
+
+    /**
+     * Compute string similarity based on Dice's coefficient.
+     *
+     * Ported from str_similar() in globals.cpp.
+     */
+    static float stringSimiliarity(String str1, String str2) {
+        int hit = 0;
+        for (int i = 0; i < str1.length() - 1; ++i) {
+            for (int j = 0; j < str2.length() - 1; ++j) {
+                if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
+                    ++hit;
+                    break;
+                }
+            }
+        }
+        return 2.0f * hit / (str1.length() + str2.length());
+    }
+
+    private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
+
+    /**
+     * Returns the set of options that fuzzy match a given option name.
+     */
+    private static List<OptionDescriptor> fuzzyMatch(ServiceLoader<OptionDescriptors> loader, String optionName) {
+        List<OptionDescriptor> matches = new ArrayList<>();
+        for (OptionDescriptors options : loader) {
+            for (OptionDescriptor option : options) {
+                float score = stringSimiliarity(option.getName(), optionName);
+                if (score >= FUZZY_MATCH_THRESHOLD) {
+                    matches.add(option);
+                }
+            }
+        }
+        return matches;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/StableOptionValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/StableOptionValue.java
new file mode 100644
index 0000000..0a589a0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/StableOptionValue.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+/**
+ * An option that always returns the same {@linkplain #getValue() value}.
+ */
+public class StableOptionValue<T> extends OptionValue<T> {
+
+    /**
+     * Creates a stable option value.
+     */
+    public StableOptionValue(T value) {
+        super(value);
+    }
+
+    /**
+     * Used to assert the invariant for stability. Without using locks, this check is not safe
+     * against races and so it's only an assertion.
+     */
+    private boolean getValueCalled;
+
+    /**
+     * Creates an uninitialized stable option value for a subclass that initializes itself
+     * {@link #defaultValue() lazily}.
+     */
+    public StableOptionValue() {
+    }
+
+    /**
+     * Gets the value of this option.
+     */
+    @Override
+    public final T getValue() {
+        T result = super.getValue();
+        assert initGetValueCalled();
+        return result;
+    }
+
+    private boolean initGetValueCalled() {
+        getValueCalled = true;
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This must only be called if {@link #getValue()} has never been called.
+     */
+    @Override
+    public final void setValue(Object v) {
+        assert !getValueCalled;
+        super.setValue(v);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java
new file mode 100644
index 0000000..444d91d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.options;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class UniquePathUtilities {
+
+    private static final AtomicLong globalTimeStamp = new AtomicLong();
+    /**
+     * This generates a per thread persistent id to aid mapping related dump files with each other.
+     */
+    private static final ThreadLocal<Integer> threadDumpId = new ThreadLocal<>();
+    private static final AtomicInteger dumpId = new AtomicInteger();
+
+    private static int getThreadDumpId() {
+        Integer id = threadDumpId.get();
+        if (id == null) {
+            id = dumpId.incrementAndGet();
+            threadDumpId.set(id);
+        }
+        return id;
+    }
+
+    private static String formatExtension(String ext) {
+        if (ext == null || ext.length() == 0) {
+            return "";
+        }
+        return "." + ext;
+    }
+
+    public static long getGlobalTimeStamp() {
+        if (globalTimeStamp.get() == 0) {
+            globalTimeStamp.compareAndSet(0, System.currentTimeMillis());
+        }
+        return globalTimeStamp.get();
+    }
+
+    /**
+     * Generate a {@link Path} using the format "%s-%d_%d%s" with the {@link OptionValue#getValue()
+     * base filename}, a {@link #globalTimeStamp global timestamp}, {@link #getThreadDumpId a per
+     * thread unique id} and an optional {@code extension}.
+     *
+     * @return the output file path or null if the flag is null
+     */
+    public static Path getPath(OptionValue<String> option, OptionValue<String> defaultDirectory, String extension) {
+        return getPath(option, defaultDirectory, extension, true);
+    }
+
+    /**
+     * Generate a {@link Path} using the format "%s-%d_%s" with the {@link OptionValue#getValue()
+     * base filename}, a {@link #globalTimeStamp global timestamp} and an optional {@code extension}
+     * .
+     *
+     * @return the output file path or null if the flag is null
+     */
+    public static Path getPathGlobal(OptionValue<String> option, OptionValue<String> defaultDirectory, String extension) {
+        return getPath(option, defaultDirectory, extension, false);
+    }
+
+    private static Path getPath(OptionValue<String> option, OptionValue<String> defaultDirectory, String extension, boolean includeThreadId) {
+        if (option.getValue() == null) {
+            return null;
+        }
+        final String name = includeThreadId
+                        ? String.format("%s-%d_%d%s", option.getValue(), getGlobalTimeStamp(), getThreadDumpId(), formatExtension(extension))
+                        : String.format("%s-%d%s", option.getValue(), getGlobalTimeStamp(), formatExtension(extension));
+        Path result = Paths.get(name);
+        if (result.isAbsolute() || defaultDirectory == null) {
+            return result;
+        }
+        return Paths.get(defaultDirectory.getValue(), name);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common.test/src/org/graalvm/compiler/phases/common/test/StampFactoryTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common.test/src/org/graalvm/compiler/phases/common/test/StampFactoryTest.java
new file mode 100644
index 0000000..5199875
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common.test/src/org/graalvm/compiler/phases/common/test/StampFactoryTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.test;
+
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+public class StampFactoryTest {
+
+    @SuppressWarnings("unused")
+    public void test(int a, Object b, double c) {
+    }
+
+    @Test
+    public void testParameters() throws NoSuchMethodException, SecurityException {
+        Method method = StampFactoryTest.class.getMethod("test", Integer.TYPE, Object.class, Double.TYPE);
+        MetaAccessProvider metaAccess = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getMetaAccess();
+        Stamp[] parameterStamps = StampFactory.createParameterStamps(null, metaAccess.lookupJavaMethod(method));
+        Stamp[] expected = {StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(metaAccess.lookupJavaType(StampFactoryTest.class))), StampFactory.forKind(JavaKind.Int),
+                        StampFactory.object(TypeReference.createWithoutAssumptions(metaAccess.lookupJavaType(Object.class))), StampFactory.forKind(JavaKind.Double)};
+        Assert.assertArrayEquals(expected, parameterStamps);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java
new file mode 100644
index 0000000..51f90ef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+/**
+ * Common superclass for phases that perform inlining.
+ */
+public abstract class AbstractInliningPhase extends BasePhase<HighTierContext> {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java
new file mode 100644
index 0000000..dbdada7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+
+public class AddressLoweringPhase extends Phase {
+
+    public abstract static class AddressLowering {
+
+        public abstract AddressNode lower(ValueNode address);
+
+        public abstract AddressNode lower(ValueNode base, ValueNode offset);
+    }
+
+    private final AddressLowering lowering;
+
+    public AddressLoweringPhase(AddressLowering lowering) {
+        this.lowering = lowering;
+        assert lowering != null;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            AddressNode lowered;
+            if (node instanceof RawAddressNode) {
+                RawAddressNode address = (RawAddressNode) node;
+                lowered = lowering.lower(address.getAddress());
+            } else if (node instanceof OffsetAddressNode) {
+                OffsetAddressNode address = (OffsetAddressNode) node;
+                lowered = lowering.lower(address.getBase(), address.getOffset());
+            } else {
+                continue;
+            }
+            node.replaceAtUsages(lowered);
+            GraphUtil.killWithUnusedFloatingInputs(node);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
new file mode 100644
index 0000000..35c0a41
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class CanonicalizerPhase extends BasePhase<PhaseContext> {
+
+    private static final int MAX_ITERATION_PER_NODE = 10;
+    private static final DebugCounter COUNTER_CANONICALIZED_NODES = Debug.counter("CanonicalizedNodes");
+    private static final DebugCounter COUNTER_PROCESSED_NODES = Debug.counter("ProcessedNodes");
+    private static final DebugCounter COUNTER_CANONICALIZATION_CONSIDERED_NODES = Debug.counter("CanonicalizationConsideredNodes");
+    private static final DebugCounter COUNTER_INFER_STAMP_CALLED = Debug.counter("InferStampCalled");
+    private static final DebugCounter COUNTER_STAMP_CHANGED = Debug.counter("StampChanged");
+    private static final DebugCounter COUNTER_SIMPLIFICATION_CONSIDERED_NODES = Debug.counter("SimplificationConsideredNodes");
+    private static final DebugCounter COUNTER_GLOBAL_VALUE_NUMBERING_HITS = Debug.counter("GlobalValueNumberingHits");
+
+    private boolean canonicalizeReads = true;
+    private boolean simplify = true;
+    private final CustomCanonicalizer customCanonicalizer;
+
+    public abstract static class CustomCanonicalizer {
+
+        public Node canonicalize(Node node) {
+            return node;
+        }
+
+        @SuppressWarnings("unused")
+        public void simplify(Node node, SimplifierTool tool) {
+        }
+    }
+
+    public CanonicalizerPhase() {
+        this(null);
+    }
+
+    public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) {
+        this.customCanonicalizer = customCanonicalizer;
+    }
+
+    public void disableReadCanonicalization() {
+        canonicalizeReads = false;
+    }
+
+    public void disableSimplification() {
+        simplify = false;
+    }
+
+    @Override
+    public boolean checkContract() {
+        /*
+         * There are certain canonicalizations we make that heavily increase code size by e.g.
+         * replacing a merge followed by a return of the merge's phi with returns in each
+         * predecessor.
+         */
+        return false;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        new Instance(context).run(graph);
+    }
+
+    /**
+     * @param newNodesMark only the {@linkplain Graph#getNewNodes(Mark) new nodes} specified by this
+     *            mark are processed
+     */
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark) {
+        applyIncremental(graph, context, newNodesMark, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark, boolean dumpGraph) {
+        new Instance(context, newNodesMark).apply(graph, dumpGraph);
+    }
+
+    /**
+     * @param workingSet the initial working set of nodes on which the canonicalizer works, should
+     *            be an auto-grow node bitmap
+     */
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet) {
+        applyIncremental(graph, context, workingSet, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, boolean dumpGraph) {
+        new Instance(context, workingSet).apply(graph, dumpGraph);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
+        applyIncremental(graph, context, workingSet, newNodesMark, true);
+    }
+
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark, boolean dumpGraph) {
+        new Instance(context, workingSet, newNodesMark).apply(graph, dumpGraph);
+    }
+
+    private final class Instance extends Phase {
+
+        private final Mark newNodesMark;
+        private final PhaseContext context;
+        private final Iterable<? extends Node> initWorkingSet;
+
+        private NodeWorkList workList;
+        private Tool tool;
+
+        private Instance(PhaseContext context) {
+            this(context, null, null);
+        }
+
+        private Instance(PhaseContext context, Iterable<? extends Node> workingSet) {
+            this(context, workingSet, null);
+        }
+
+        private Instance(PhaseContext context, Mark newNodesMark) {
+            this(context, null, newNodesMark);
+        }
+
+        private Instance(PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
+            this.newNodesMark = newNodesMark;
+            this.context = context;
+            this.initWorkingSet = workingSet;
+        }
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            boolean wholeGraph = newNodesMark == null || newNodesMark.isStart();
+            if (initWorkingSet == null) {
+                workList = graph.createIterativeNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE);
+            } else {
+                workList = graph.createIterativeNodeWorkList(false, MAX_ITERATION_PER_NODE);
+                workList.addAll(initWorkingSet);
+            }
+            if (!wholeGraph) {
+                workList.addAll(graph.getNewNodes(newNodesMark));
+            }
+            tool = new Tool(graph.getAssumptions());
+            processWorkSet(graph);
+        }
+
+        @SuppressWarnings("try")
+        private void processWorkSet(StructuredGraph graph) {
+            NodeEventListener listener = new NodeEventListener() {
+
+                @Override
+                public void nodeAdded(Node node) {
+                    workList.add(node);
+                }
+
+                @Override
+                public void inputChanged(Node node) {
+                    workList.add(node);
+                    if (node instanceof IndirectCanonicalization) {
+                        for (Node usage : node.usages()) {
+                            workList.add(usage);
+                        }
+                    }
+                }
+
+                @Override
+                public void usagesDroppedToZero(Node node) {
+                    workList.add(node);
+                }
+
+            };
+            try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                for (Node n : workList) {
+                    boolean changed = processNode(n);
+                    if (changed && Debug.isDumpEnabled(Debug.DETAILED_LOG_LEVEL)) {
+                        Debug.dump(Debug.DETAILED_LOG_LEVEL, graph, "CanonicalizerPhase %s", n);
+                    }
+                }
+            }
+        }
+
+        /**
+         * @return true if the graph was changed.
+         */
+        private boolean processNode(Node node) {
+            if (!node.isAlive()) {
+                return false;
+            }
+            if (node instanceof FloatingNode && node.hasNoUsages()) {
+                // Dead but on the worklist so simply kill it
+                GraphUtil.killWithUnusedFloatingInputs(node);
+                return false;
+            }
+            COUNTER_PROCESSED_NODES.increment();
+
+            NodeClass<?> nodeClass = node.getNodeClass();
+            if (tryGlobalValueNumbering(node, nodeClass)) {
+                return true;
+            }
+            StructuredGraph graph = (StructuredGraph) node.graph();
+            if (GraphUtil.tryKillUnused(node)) {
+                return true;
+            }
+            if (tryCanonicalize(node, nodeClass)) {
+                return true;
+            }
+            if (node instanceof ValueNode) {
+                ValueNode valueNode = (ValueNode) node;
+                boolean improvedStamp = tryInferStamp(valueNode);
+                Constant constant = valueNode.stamp().asConstant();
+                if (constant != null && !(node instanceof ConstantNode)) {
+                    ConstantNode stampConstant = ConstantNode.forConstant(valueNode.stamp(), constant, context.getMetaAccess(), graph);
+                    Debug.log("Canonicalizer: constant stamp replaces %1s with %1s", valueNode, stampConstant);
+                    valueNode.replaceAtUsages(InputType.Value, stampConstant);
+                    GraphUtil.tryKillUnused(valueNode);
+                    return true;
+                } else if (improvedStamp) {
+                    // the improved stamp may enable additional canonicalization
+                    if (tryCanonicalize(valueNode, nodeClass)) {
+                        return true;
+                    }
+                    valueNode.usages().forEach(workList::add);
+                }
+            }
+            return false;
+        }
+
+        public boolean tryGlobalValueNumbering(Node node, NodeClass<?> nodeClass) {
+            if (nodeClass.valueNumberable()) {
+                Node newNode = node.graph().findDuplicate(node);
+                if (newNode != null) {
+                    assert !(node instanceof FixedNode || newNode instanceof FixedNode);
+                    node.replaceAtUsagesAndDelete(newNode);
+                    COUNTER_GLOBAL_VALUE_NUMBERING_HITS.increment();
+                    Debug.log("GVN applied and new node is %1s", newNode);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private AutoCloseable getCanonicalizeableContractAssertion(Node node) {
+            boolean needsAssertion = false;
+            assert (needsAssertion = true) == true;
+            if (needsAssertion) {
+                Mark mark = node.graph().getMark();
+                return () -> {
+                    assert mark.equals(node.graph().getMark()) : "new node created while canonicalizing " + node.getClass().getSimpleName() + " " + node + ": " +
+                                    node.graph().getNewNodes(mark).snapshot();
+                };
+            } else {
+                return null;
+            }
+        }
+
+        @SuppressWarnings("try")
+        public boolean tryCanonicalize(final Node node, NodeClass<?> nodeClass) {
+            try (DebugCloseable position = node.withNodeSourcePosition()) {
+                if (customCanonicalizer != null) {
+                    Node canonical = customCanonicalizer.canonicalize(node);
+                    if (performReplacement(node, canonical)) {
+                        return true;
+                    } else {
+                        customCanonicalizer.simplify(node, tool);
+                        if (node.isDeleted()) {
+                            return true;
+                        }
+                    }
+                }
+                if (nodeClass.isCanonicalizable()) {
+                    COUNTER_CANONICALIZATION_CONSIDERED_NODES.increment();
+                    Node canonical;
+                    try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
+                        canonical = ((Canonicalizable) node).canonical(tool);
+                        if (canonical == node && nodeClass.isCommutative()) {
+                            canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
+                        }
+                    } catch (Throwable e) {
+                        throw new RuntimeException(e);
+                    }
+                    if (performReplacement(node, canonical)) {
+                        return true;
+                    }
+                }
+
+                if (nodeClass.isSimplifiable() && simplify) {
+                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "Canonicalizer: simplifying %s", node);
+                    COUNTER_SIMPLIFICATION_CONSIDERED_NODES.increment();
+                    node.simplify(tool);
+                    return node.isDeleted();
+                }
+                return false;
+            }
+        }
+
+// @formatter:off
+//     cases:                                           original node:
+//                                         |Floating|Fixed-unconnected|Fixed-connected|
+//                                         --------------------------------------------
+//                                     null|   1    |        X        |       3       |
+//                                         --------------------------------------------
+//                                 Floating|   2    |        X        |       4       |
+//       canonical node:                   --------------------------------------------
+//                        Fixed-unconnected|   X    |        X        |       5       |
+//                                         --------------------------------------------
+//                          Fixed-connected|   2    |        X        |       6       |
+//                                         --------------------------------------------
+//                              ControlSink|   X    |        X        |       7       |
+//                                         --------------------------------------------
+//       X: must not happen (checked with assertions)
+// @formatter:on
+        private boolean performReplacement(final Node node, Node newCanonical) {
+            if (newCanonical == node) {
+                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Canonicalizer: work on %1s", node);
+                return false;
+            } else {
+                Node canonical = newCanonical;
+                Debug.log("Canonicalizer: replacing %1s with %1s", node, canonical);
+                COUNTER_CANONICALIZED_NODES.increment();
+                StructuredGraph graph = (StructuredGraph) node.graph();
+                if (canonical != null && !canonical.isAlive()) {
+                    assert !canonical.isDeleted();
+                    canonical = graph.addOrUniqueWithInputs(canonical);
+                }
+                if (node instanceof FloatingNode) {
+                    assert canonical == null || !(canonical instanceof FixedNode) ||
+                                    (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof AbstractMergeNode) : node +
+                                                    " -> " + canonical + " : replacement should be floating or fixed and connected";
+                    node.replaceAtUsages(canonical);
+                    GraphUtil.killWithUnusedFloatingInputs(node);
+                } else {
+                    assert node instanceof FixedNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
+                    FixedNode fixed = (FixedNode) node;
+                    if (canonical instanceof ControlSinkNode) {
+                        // case 7
+                        fixed.replaceAtPredecessor(canonical);
+                        GraphUtil.killCFG(fixed);
+                        return true;
+                    } else {
+                        assert fixed instanceof FixedWithNextNode;
+                        FixedWithNextNode fixedWithNext = (FixedWithNextNode) fixed;
+                        // When removing a fixed node, new canonicalization
+                        // opportunities for its successor may arise
+                        assert fixedWithNext.next() != null;
+                        tool.addToWorkList(fixedWithNext.next());
+                        if (canonical == null) {
+                            // case 3
+                            node.replaceAtUsages(null);
+                            GraphUtil.removeFixedWithUnusedInputs(fixedWithNext);
+                        } else if (canonical instanceof FloatingNode) {
+                            // case 4
+                            graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical);
+                        } else {
+                            assert canonical instanceof FixedNode;
+                            if (canonical.predecessor() == null) {
+                                assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
+                                // case 5
+                                graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical);
+                            } else {
+                                assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
+                                // case 6
+                                node.replaceAtUsages(canonical);
+                                GraphUtil.removeFixedWithUnusedInputs(fixedWithNext);
+                            }
+                        }
+                    }
+                }
+                return true;
+            }
+        }
+
+        /**
+         * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means
+         * that the stamp has changed), re-queues the node's usages. If the stamp has changed then
+         * this method also checks if the stamp now describes a constant integer value, in which
+         * case the node is replaced with a constant.
+         */
+        private boolean tryInferStamp(ValueNode node) {
+            if (node.isAlive()) {
+                COUNTER_INFER_STAMP_CALLED.increment();
+                if (node.inferStamp()) {
+                    COUNTER_STAMP_CHANGED.increment();
+                    for (Node usage : node.usages()) {
+                        workList.add(usage);
+                    }
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private final class Tool implements SimplifierTool {
+
+            private final Assumptions assumptions;
+
+            Tool(Assumptions assumptions) {
+                this.assumptions = assumptions;
+            }
+
+            @Override
+            public void deleteBranch(Node branch) {
+                branch.predecessor().replaceFirstSuccessor(branch, null);
+                GraphUtil.killCFG(branch, this);
+            }
+
+            @Override
+            public MetaAccessProvider getMetaAccess() {
+                return context.getMetaAccess();
+            }
+
+            @Override
+            public ConstantReflectionProvider getConstantReflection() {
+                return context.getConstantReflection();
+            }
+
+            @Override
+            public ConstantFieldProvider getConstantFieldProvider() {
+                return context.getConstantFieldProvider();
+            }
+
+            @Override
+            public void addToWorkList(Node node) {
+                workList.add(node);
+            }
+
+            @Override
+            public void addToWorkList(Iterable<? extends Node> nodes) {
+                workList.addAll(nodes);
+            }
+
+            @Override
+            public void removeIfUnused(Node node) {
+                GraphUtil.tryKillUnused(node);
+            }
+
+            @Override
+            public boolean canonicalizeReads() {
+                return canonicalizeReads;
+            }
+
+            @Override
+            public boolean allUsagesAvailable() {
+                return true;
+            }
+
+            @Override
+            public Assumptions getAssumptions() {
+                return assumptions;
+            }
+
+            @Override
+            public boolean supportSubwordCompare(int bits) {
+                return context.getLowerer().supportSubwordCompare(bits);
+            }
+        }
+    }
+
+    public boolean getCanonicalizeReads() {
+        return canonicalizeReads;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java
new file mode 100644
index 0000000..10f62f6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
+
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
+ * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
+ *
+ * This is useful because {@link FixedGuardNode FixedGuardNodes} will be lowered to {@link GuardNode
+ * GuardNodes} which can later be optimized more aggressively than control-flow constructs.
+ *
+ * This is currently only done for branches that start from a {@link IfNode}. If it encounters a
+ * branch starting at an other kind of {@link ControlSplitNode}, it will only bring the
+ * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
+ *
+ */
+public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
+    private static AbstractBeginNode findBeginNode(FixedNode startNode) {
+        return GraphUtil.predecessorIterable(startNode).filter(AbstractBeginNode.class).first();
+    }
+
+    @Override
+    protected void run(final StructuredGraph graph, PhaseContext context) {
+        assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
+        if (graph.getNodes(DeoptimizeNode.TYPE).isEmpty()) {
+            return;
+        }
+        for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
+            assert d.isAlive();
+            visitDeoptBegin(AbstractBeginNode.prevBegin(d), d.action(), d.reason(), d.getSpeculation(), graph, context != null ? context.getLowerer() : null);
+        }
+
+        if (context != null) {
+            for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
+                trySplitFixedGuard(fixedGuard, context);
+            }
+        }
+
+        new DeadCodeEliminationPhase(Optional).apply(graph);
+    }
+
+    private void trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context) {
+        LogicNode condition = fixedGuard.condition();
+        if (condition instanceof CompareNode) {
+            CompareNode compare = (CompareNode) condition;
+            ValueNode x = compare.getX();
+            ValuePhiNode xPhi = (x instanceof ValuePhiNode) ? (ValuePhiNode) x : null;
+            if (x instanceof ConstantNode || xPhi != null) {
+                ValueNode y = compare.getY();
+                ValuePhiNode yPhi = (y instanceof ValuePhiNode) ? (ValuePhiNode) y : null;
+                if (y instanceof ConstantNode || yPhi != null) {
+                    processFixedGuardAndPhis(fixedGuard, context, compare, x, xPhi, y, yPhi);
+                }
+            }
+        }
+    }
+
+    private void processFixedGuardAndPhis(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi) {
+        AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard);
+        if (pred instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) pred;
+            if (xPhi != null && xPhi.merge() != merge) {
+                return;
+            }
+            if (yPhi != null && yPhi.merge() != merge) {
+                return;
+            }
+
+            processFixedGuardAndMerge(fixedGuard, context, compare, x, xPhi, y, yPhi, merge);
+        }
+    }
+
+    private void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
+                    AbstractMergeNode merge) {
+        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        for (int i = 0; i < mergePredecessors.size(); ++i) {
+            AbstractEndNode mergePredecessor = mergePredecessors.get(i);
+            if (!mergePredecessor.isAlive()) {
+                break;
+            }
+            Constant xs;
+            if (xPhi == null) {
+                xs = x.asConstant();
+            } else {
+                xs = xPhi.valueAt(mergePredecessor).asConstant();
+            }
+            Constant ys;
+            if (yPhi == null) {
+                ys = y.asConstant();
+            } else {
+                ys = yPhi.valueAt(mergePredecessor).asConstant();
+            }
+            if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
+                visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph(), context.getLowerer());
+            }
+        }
+    }
+
+    private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph,
+                    LoweringProvider loweringProvider) {
+        if (deoptBegin.predecessor() instanceof AbstractBeginNode) {
+            /*
+             * Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization.
+             */
+            visitDeoptBegin((AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph, loweringProvider);
+            return;
+        }
+
+        if (deoptBegin instanceof AbstractMergeNode) {
+            AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin;
+            Debug.log("Visiting %s", mergeNode);
+            FixedNode next = mergeNode.next();
+            while (mergeNode.isAlive()) {
+                AbstractEndNode end = mergeNode.forwardEnds().first();
+                AbstractBeginNode newBeginNode = findBeginNode(end);
+                visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
+            }
+            assert next.isAlive();
+            AbstractBeginNode newBeginNode = findBeginNode(next);
+            visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
+            return;
+        } else if (deoptBegin.predecessor() instanceof IfNode) {
+            IfNode ifNode = (IfNode) deoptBegin.predecessor();
+            AbstractBeginNode otherBegin = ifNode.trueSuccessor();
+            LogicNode conditionNode = ifNode.condition();
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor()));
+            FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
+            AbstractBeginNode survivingSuccessor;
+            if (deoptBegin == ifNode.trueSuccessor()) {
+                survivingSuccessor = ifNode.falseSuccessor();
+            } else {
+                survivingSuccessor = ifNode.trueSuccessor();
+            }
+            graph.removeSplitPropagate(ifNode, survivingSuccessor);
+
+            Node newGuard = guard;
+            if (survivingSuccessor instanceof LoopExitNode) {
+                newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
+            }
+            survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
+
+            Debug.log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin);
+            FixedNode next = pred.next();
+            pred.setNext(guard);
+            guard.setNext(next);
+            SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), loweringProvider);
+            survivingSuccessor.simplify(simplifierTool);
+            return;
+        }
+
+        // We could not convert the control split - at least cut off control flow after the split.
+        FixedWithNextNode deoptPred = deoptBegin;
+        FixedNode next = deoptPred.next();
+
+        if (!(next instanceof DeoptimizeNode)) {
+            DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation));
+            deoptPred.setNext(newDeoptNode);
+            assert deoptPred == newDeoptNode.predecessor();
+            GraphUtil.killCFG(next);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeadCodeEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeadCodeEliminationPhase.java
new file mode 100644
index 0000000..599f2a7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeadCodeEliminationPhase.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeFlood;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.Phase;
+
+public class DeadCodeEliminationPhase extends Phase {
+
+    public static class Options {
+
+        // @formatter:off
+        @Option(help = "Disable optional dead code eliminations", type = OptionType.Debug)
+        public static final OptionValue<Boolean> ReduceDCE = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    private static final DebugCounter counterNodesRemoved = Debug.counter("NodesRemoved");
+
+    public enum Optionality {
+        Optional,
+        Required;
+    }
+
+    /**
+     * Creates a dead code elimination phase that will be run irrespective of
+     * {@link Options#ReduceDCE}.
+     */
+    public DeadCodeEliminationPhase() {
+        this(Optionality.Required);
+    }
+
+    /**
+     * Creates a dead code elimination phase that will be run only if it is
+     * {@linkplain Optionality#Required non-optional} or {@link Options#ReduceDCE} is false.
+     */
+    public DeadCodeEliminationPhase(Optionality optionality) {
+        this.optional = optionality == Optionality.Optional;
+    }
+
+    private final boolean optional;
+
+    @Override
+    public void run(StructuredGraph graph) {
+        if (optional && Options.ReduceDCE.getValue()) {
+            return;
+        }
+
+        NodeFlood flood = graph.createNodeFlood();
+        int totalNodeCount = graph.getNodeCount();
+        flood.add(graph.start());
+        iterateSuccessorsAndInputs(flood);
+        int totalMarkedCount = flood.getTotalMarkedCount();
+        if (totalNodeCount == totalMarkedCount) {
+            // All nodes are live => nothing more to do.
+            return;
+        } else {
+            // Some nodes are not marked alive and therefore dead => proceed.
+            assert totalNodeCount > totalMarkedCount;
+        }
+
+        deleteNodes(flood, graph);
+    }
+
+    private static void iterateSuccessorsAndInputs(NodeFlood flood) {
+        Node.EdgeVisitor consumer = new Node.EdgeVisitor() {
+            @Override
+            public Node apply(Node n, Node succOrInput) {
+                assert succOrInput.isAlive() : "dead successor or input " + succOrInput + " in " + n;
+                flood.add(succOrInput);
+                return succOrInput;
+            }
+        };
+        for (Node current : flood) {
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
+                flood.add(end.merge());
+            } else {
+                current.applySuccessors(consumer);
+                current.applyInputs(consumer);
+            }
+        }
+    }
+
+    private static void deleteNodes(NodeFlood flood, StructuredGraph graph) {
+        Node.EdgeVisitor consumer = new Node.EdgeVisitor() {
+            @Override
+            public Node apply(Node n, Node input) {
+                if (input.isAlive() && flood.isMarked(input)) {
+                    input.removeUsage(n);
+                }
+                return input;
+            }
+        };
+
+        for (Node node : graph.getNodes()) {
+            if (!flood.isMarked(node)) {
+                node.markDeleted();
+                node.applyInputs(consumer);
+                counterNodesRemoved.increment();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeoptimizationGroupingPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeoptimizationGroupingPhase.java
new file mode 100644
index 0000000..986af0c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeoptimizationGroupingPhase.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.DynamicDeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+/**
+ * This phase tries to find {@link AbstractDeoptimizeNode DeoptimizeNodes} which use the same
+ * {@link FrameState} and merges them together.
+ */
+public class DeoptimizationGroupingPhase extends BasePhase<MidTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        ControlFlowGraph cfg = null;
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            FixedNode target = null;
+            PhiNode reasonActionPhi = null;
+            PhiNode speculationPhi = null;
+            List<AbstractDeoptimizeNode> obsoletes = null;
+            for (AbstractDeoptimizeNode deopt : fs.usages().filter(AbstractDeoptimizeNode.class)) {
+                if (target == null) {
+                    target = deopt;
+                } else {
+                    if (cfg == null) {
+                        cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+                    }
+                    AbstractMergeNode merge;
+                    if (target instanceof AbstractDeoptimizeNode) {
+                        merge = graph.add(new MergeNode());
+                        EndNode firstEnd = graph.add(new EndNode());
+                        ValueNode actionAndReason = ((AbstractDeoptimizeNode) target).getActionAndReason(context.getMetaAccess());
+                        ValueNode speculation = ((AbstractDeoptimizeNode) target).getSpeculation(context.getMetaAccess());
+                        reasonActionPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(actionAndReason.getStackKind()), merge));
+                        speculationPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(speculation.getStackKind()), merge));
+                        merge.addForwardEnd(firstEnd);
+                        reasonActionPhi.addInput(actionAndReason);
+                        speculationPhi.addInput(speculation);
+                        target.replaceAtPredecessor(firstEnd);
+
+                        exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
+
+                        merge.setNext(graph.add(new DynamicDeoptimizeNode(reasonActionPhi, speculationPhi)));
+                        obsoletes = new LinkedList<>();
+                        obsoletes.add((AbstractDeoptimizeNode) target);
+                        target = merge;
+                    } else {
+                        merge = (AbstractMergeNode) target;
+                    }
+                    EndNode newEnd = graph.add(new EndNode());
+                    merge.addForwardEnd(newEnd);
+                    reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess()));
+                    speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess()));
+                    deopt.replaceAtPredecessor(newEnd);
+                    exitLoops(deopt, newEnd, cfg);
+                    obsoletes.add(deopt);
+                }
+            }
+            if (obsoletes != null) {
+                ((DynamicDeoptimizeNode) ((AbstractMergeNode) target).next()).setStateBefore(fs);
+                for (AbstractDeoptimizeNode obsolete : obsoletes) {
+                    obsolete.safeDelete();
+                }
+            }
+        }
+    }
+
+    private static void exitLoops(AbstractDeoptimizeNode deopt, EndNode end, ControlFlowGraph cfg) {
+        Block block = cfg.blockFor(deopt);
+        Loop<Block> loop = block.getLoop();
+        while (loop != null) {
+            end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode())));
+            loop = loop.getParent();
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 2.5f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java
new file mode 100644
index 0000000..738f0f3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java
@@ -0,0 +1,965 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.ConditionAnchorNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.DeoptimizingGuard;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.GuardProxyNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnaryOpLogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.calc.PointerEqualsNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.TypeSwitchNode;
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.LoweringPhase.Frame;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.TriState;
+
+public class DominatorConditionalEliminationPhase extends BasePhase<PhaseContext> {
+
+    private static final DebugCounter counterStampsRegistered = Debug.counter("StampsRegistered");
+    private static final DebugCounter counterStampsFound = Debug.counter("StampsFound");
+    private static final DebugCounter counterIfsKilled = Debug.counter("CE_KilledIfs");
+    private static final DebugCounter counterLFFolded = Debug.counter("ConstantLFFolded");
+    private final boolean fullSchedule;
+
+    public DominatorConditionalEliminationPhase(boolean fullSchedule) {
+        this.fullSchedule = fullSchedule;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        try (Debug.Scope s = Debug.scope("DominatorConditionalElimination")) {
+            Function<Block, Iterable<? extends Node>> blockToNodes;
+            Function<Node, Block> nodeToBlock;
+            Block startBlock;
+
+            if (fullSchedule) {
+                SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
+                schedule.apply(graph);
+                ControlFlowGraph cfg = graph.getLastSchedule().getCFG();
+                cfg.computePostdominators();
+                blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b);
+                nodeToBlock = n -> graph.getLastSchedule().getNodeToBlockMap().get(n);
+                startBlock = cfg.getStartBlock();
+            } else {
+                ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+                BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg);
+                for (Block b : cfg.getBlocks()) {
+                    ArrayList<FixedNode> curNodes = new ArrayList<>();
+                    for (FixedNode node : b.getNodes()) {
+                        if (node instanceof AbstractBeginNode || node instanceof FixedGuardNode || node instanceof ConditionAnchorNode || node instanceof IfNode) {
+                            curNodes.add(node);
+                        }
+                    }
+                    nodes.put(b, curNodes);
+                }
+                blockToNodes = b -> nodes.get(b);
+                nodeToBlock = n -> cfg.blockFor(n);
+                startBlock = cfg.getStartBlock();
+            }
+            new Instance(graph, blockToNodes, nodeToBlock, context).processBlock(startBlock);
+        }
+    }
+
+    public static class Instance {
+        protected NodeMap<Info> map;
+        protected Deque<LoopExitNode> loopExits;
+        protected final Function<Block, Iterable<? extends Node>> blockToNodes;
+        protected final Function<Node, Block> nodeToBlock;
+        protected final CanonicalizerTool tool;
+        /**
+         * Tests which may be eliminated because post dominating tests to prove a broader condition.
+         */
+        private Deque<PendingTest> pendingTests;
+
+        public Instance(StructuredGraph graph, Function<Block, Iterable<? extends Node>> blockToNodes,
+                        Function<Node, Block> nodeToBlock, PhaseContext context) {
+            map = graph.createNodeMap();
+            loopExits = new ArrayDeque<>();
+            this.blockToNodes = blockToNodes;
+            this.nodeToBlock = nodeToBlock;
+            pendingTests = new ArrayDeque<>();
+            tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), context.getLowerer());
+        }
+
+        public void processBlock(Block startBlock) {
+            LoweringPhase.processBlock(new InstanceFrame(startBlock, null));
+        }
+
+        public class InstanceFrame extends LoweringPhase.Frame<InstanceFrame> {
+            protected List<Runnable> undoOperations = new ArrayList<>();
+
+            public InstanceFrame(Block block, InstanceFrame parent) {
+                super(block, parent);
+            }
+
+            @Override
+            public Frame<?> enter(Block b) {
+                return new InstanceFrame(b, this);
+            }
+
+            @Override
+            public void postprocess() {
+                Debug.log("[Post Processing block %s]", block);
+                undoOperations.forEach(x -> x.run());
+            }
+
+            protected void processConditionAnchor(ConditionAnchorNode node) {
+                tryProveCondition(node.condition(), (guard, result) -> {
+                    if (result != node.isNegated()) {
+                        node.replaceAtUsages(guard);
+                        GraphUtil.unlinkFixedNode(node);
+                        GraphUtil.killWithUnusedFloatingInputs(node);
+                    } else {
+                        ValueAnchorNode valueAnchor = node.graph().add(new ValueAnchorNode(null));
+                        node.replaceAtUsages(valueAnchor);
+                        node.graph().replaceFixedWithFixed(node, valueAnchor);
+                    }
+                    return true;
+                });
+            }
+
+            protected void processGuard(GuardNode node) {
+                if (!tryProveGuardCondition(node, node.getCondition(), (guard, result) -> {
+                    if (result != node.isNegated()) {
+                        node.replaceAndDelete(guard);
+                    } else {
+                        DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
+                        AbstractBeginNode beginNode = (AbstractBeginNode) node.getAnchor();
+                        FixedNode next = beginNode.next();
+                        beginNode.setNext(deopt);
+                        GraphUtil.killCFG(next);
+                    }
+                    return true;
+                })) {
+                    registerNewCondition(node.getCondition(), node.isNegated(), node);
+                }
+            }
+
+            protected void processFixedGuard(FixedGuardNode node) {
+                if (!tryProveGuardCondition(node, node.condition(), (guard, result) -> {
+                    if (result != node.isNegated()) {
+                        node.replaceAtUsages(guard);
+                        GraphUtil.unlinkFixedNode(node);
+                        GraphUtil.killWithUnusedFloatingInputs(node);
+                    } else {
+                        DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
+                        deopt.setStateBefore(node.stateBefore());
+                        node.replaceAtPredecessor(deopt);
+                        GraphUtil.killCFG(node);
+                    }
+                    Debug.log("Kill fixed guard guard");
+                    return true;
+                })) {
+                    registerNewCondition(node.condition(), node.isNegated(), node);
+                }
+            }
+
+            protected void processIf(IfNode node) {
+                tryProveCondition(node.condition(), (guard, result) -> {
+                    AbstractBeginNode survivingSuccessor = node.getSuccessor(result);
+                    survivingSuccessor.replaceAtUsages(InputType.Guard, guard);
+                    survivingSuccessor.replaceAtPredecessor(null);
+                    node.replaceAtPredecessor(survivingSuccessor);
+                    GraphUtil.killCFG(node);
+                    if (survivingSuccessor instanceof BeginNode) {
+                        undoOperations.add(() -> {
+                            if (survivingSuccessor.isAlive()) {
+                                ((BeginNode) survivingSuccessor).trySimplify();
+                            }
+                        });
+                    }
+                    Debug.log("Kill if");
+                    counterIfsKilled.increment();
+                    return true;
+                });
+            }
+
+            @Override
+            public void preprocess() {
+                Debug.log("[Pre Processing block %s]", block);
+                AbstractBeginNode beginNode = block.getBeginNode();
+                if (beginNode instanceof LoopExitNode && beginNode.isAlive()) {
+                    LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+                    Instance.this.loopExits.push(loopExitNode);
+                    undoOperations.add(() -> loopExits.pop());
+                } else if (block.getDominator() != null && (block.getDominator().getLoopDepth() > block.getLoopDepth() ||
+                                (block.getDominator().getLoopDepth() == block.getLoopDepth() && block.getDominator().getLoop() != block.getLoop()))) {
+                    // We are exiting the loop, but there is not a single loop exit block along our
+                    // dominator tree (e.g., we are a merge of two loop exits).
+                    final NodeMap<Info> oldMap = map;
+                    final Deque<LoopExitNode> oldLoopExits = loopExits;
+                    map = map.graph().createNodeMap();
+                    loopExits = new ArrayDeque<>();
+                    undoOperations.add(() -> {
+                        map = oldMap;
+                        loopExits = oldLoopExits;
+                    });
+                }
+
+                // For now conservatively collect guards only within the same block.
+                pendingTests.clear();
+                for (Node n : blockToNodes.apply(block)) {
+                    if (n.isAlive()) {
+                        processNode(n);
+                    }
+                }
+            }
+
+            protected void processNode(Node node) {
+                if (node instanceof NodeWithState && !(node instanceof GuardingNode)) {
+                    pendingTests.clear();
+                }
+                if (node instanceof AbstractBeginNode) {
+                    processAbstractBegin((AbstractBeginNode) node);
+                } else if (node instanceof FixedGuardNode) {
+                    processFixedGuard((FixedGuardNode) node);
+                } else if (node instanceof GuardNode) {
+                    processGuard((GuardNode) node);
+                } else if (node instanceof ConditionAnchorNode) {
+                    processConditionAnchor((ConditionAnchorNode) node);
+                } else if (node instanceof IfNode) {
+                    processIf((IfNode) node);
+                } else {
+                    return;
+                }
+            }
+
+            protected void registerNewCondition(LogicNode condition, boolean negated, ValueNode guard) {
+                if (!negated && condition instanceof PointerEqualsNode) {
+                    PointerEqualsNode pe = (PointerEqualsNode) condition;
+                    ValueNode x = pe.getX();
+                    ValueNode y = pe.getY();
+                    if (y.isConstant()) {
+                        JavaConstant constant = y.asJavaConstant();
+                        Stamp succeeding = pe.getSucceedingStampForX(negated);
+                        if (succeeding == null && pe instanceof ObjectEqualsNode && guard instanceof FixedGuardNode) {
+                            succeeding = y.stamp();
+                        }
+                        if (succeeding != null) {
+                            if (y.stamp() instanceof ObjectStamp) {
+                                GuardedConstantStamp cos = new GuardedConstantStamp(constant, (ObjectStamp) succeeding);
+                                registerNewStamp(x, cos, guard);
+                                return;
+                            }
+                        }
+                    }
+                }
+                if (condition instanceof UnaryOpLogicNode) {
+                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
+                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
+                    registerNewStamp(unaryLogicNode.getValue(), newStamp, guard);
+                } else if (condition instanceof BinaryOpLogicNode) {
+                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
+                    ValueNode x = binaryOpLogicNode.getX();
+                    if (!x.isConstant()) {
+                        Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(negated);
+                        registerNewStamp(x, newStampX, guard);
+                    }
+
+                    ValueNode y = binaryOpLogicNode.getY();
+                    if (!y.isConstant()) {
+                        Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(negated);
+                        registerNewStamp(y, newStampY, guard);
+                    }
+                    if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
+                        if (y.isConstant() && x instanceof AndNode) {
+                            AndNode and = (AndNode) x;
+                            if (and.getY() == y) {
+                                /*
+                                 * This 'and' proves something about some of the bits in and.getX().
+                                 * It's equivalent to or'ing in the mask value since those values
+                                 * are known to be set.
+                                 */
+                                BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+                                IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp());
+                                registerNewStamp(and.getX(), newStampX, guard);
+                            }
+                        }
+                    }
+                }
+                if (guard instanceof DeoptimizingGuard) {
+                    pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
+                }
+                registerCondition(condition, negated, guard);
+            }
+
+            @SuppressWarnings("try")
+            protected Pair<InfoElement, Stamp> foldFromConstLoadField(LoadFieldNode loadFieldNode, InfoElementProvider info) {
+                ValueNode object = loadFieldNode.object();
+                if (!loadFieldNode.field().isStatic()) {
+                    // look if we got stamp info for the object and return the constant stamp
+                    Pair<InfoElement, Stamp> pair = getConstantObjectStamp(info, object);
+                    if (pair == null) {
+                        pair = recursiveFoldStamp(object, info);
+                    }
+                    if (pair != null) {
+                        Stamp s = pair.second;
+                        if (s instanceof GuardedConstantStamp) {
+                            ConstantNode c = tryFoldFromLoadField(loadFieldNode, pair.second);
+                            if (c != null) {
+                                counterLFFolded.increment();
+                                if (c.stamp() instanceof ObjectStamp) {
+                                    GuardedConstantStamp cos = new GuardedConstantStamp(c.asJavaConstant(), (ObjectStamp) c.stamp());
+                                    return new Pair<>(pair.first, cos);
+                                }
+                                return new Pair<>(pair.first, c.stamp());
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+
+            private ConstantNode tryFoldFromLoadField(LoadFieldNode lf, Stamp x) {
+                GuardedConstantStamp cos = (GuardedConstantStamp) x;
+                return lf.asConstant(tool, cos.objectConstant);
+            }
+
+            private Pair<InfoElement, Stamp> getConstantObjectStamp(InfoElementProvider infos, ValueNode n) {
+                for (InfoElement infoElement : infos.getInfoElements(n)) {
+                    Stamp s = infoElement.getStamp();
+                    if (s instanceof GuardedConstantStamp) {
+                        return new Pair<>(infoElement, s);
+                    }
+                }
+                return null;
+            }
+
+            Pair<InfoElement, Stamp> recursiveFoldStamp(Node node, InfoElementProvider info) {
+                if (node instanceof LoadFieldNode) {
+                    Pair<InfoElement, Stamp> pair = foldFromConstLoadField((LoadFieldNode) node, info);
+                    if (pair != null) {
+                        return pair;
+                    }
+                }
+                if (node instanceof UnaryNode) {
+                    UnaryNode unary = (UnaryNode) node;
+                    ValueNode value = unary.getValue();
+                    for (InfoElement infoElement : info.getInfoElements(value)) {
+                        Stamp result = unary.foldStamp(infoElement.getStamp());
+                        if (result != null) {
+                            return new Pair<>(infoElement, result);
+                        }
+                    }
+                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(value, info);
+                    if (foldResult != null) {
+                        Stamp result = unary.foldStamp(foldResult.second);
+                        if (result != null) {
+                            return new Pair<>(foldResult.first, result);
+                        }
+                    }
+                } else if (node instanceof BinaryNode) {
+                    BinaryNode binary = (BinaryNode) node;
+                    ValueNode y = binary.getY();
+                    ValueNode x = binary.getX();
+                    if (y.isConstant()) {
+                        for (InfoElement infoElement : info.getInfoElements(x)) {
+                            Stamp result = binary.foldStamp(infoElement.stamp, y.stamp());
+                            if (result != null) {
+                                return new Pair<>(infoElement, result);
+                            }
+                        }
+                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(x, info);
+                        if (foldResult != null) {
+                            Stamp result = binary.foldStamp(foldResult.second, y.stamp());
+                            if (result != null) {
+                                return new Pair<>(foldResult.first, result);
+                            }
+                        }
+                    } else if (x instanceof LoadFieldNode || y instanceof LoadFieldNode) {
+                        boolean useX = x instanceof LoadFieldNode;
+                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(useX ? x : y, info);
+                        if (foldResult != null) {
+                            Stamp result = binary.foldStamp(useX ? foldResult.second : x.stamp(), useX ? y.stamp() : foldResult.second);
+                            if (result != null) {
+                                return new Pair<>(foldResult.first, result);
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+
+            /**
+             * Recursively try to fold stamps within this expression using information from
+             * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
+             * {@link InfoElement} otherwise more than one guard would be required.
+             *
+             * @param node
+             * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
+             *         expression
+             */
+            Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
+                return recursiveFoldStamp(node, (value) -> getInfoElements(value));
+            }
+
+            /**
+             * Recursively try to fold stamps within this expression using {@code newStamp} if the
+             * node {@code original} is encountered in the expression. It's only safe to use
+             * constants and the passed in stamp otherwise more than one guard would be required.
+             *
+             * @param node
+             * @param original
+             * @param newStamp
+             * @return the improved stamp or null is nothing could be done
+             */
+            @SuppressWarnings("unchecked")
+            Stamp recursiveFoldStamp(Node node, ValueNode original, Stamp newStamp) {
+                Debug.log("Recursively fold stamp for node %s original %s stamp %s", node, original, newStamp);
+                InfoElement element = new InfoElement(newStamp, original);
+                Pair<InfoElement, Stamp> result = recursiveFoldStamp(node, (value) -> value == original ? Collections.singleton(element) : Collections.EMPTY_LIST);
+                if (result != null) {
+                    return result.second;
+                }
+                return null;
+            }
+
+            protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
+                for (PendingTest pending : pendingTests) {
+                    TriState result = TriState.UNKNOWN;
+                    if (pending.condition instanceof UnaryOpLogicNode) {
+                        UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
+                        if (unaryLogicNode.getValue() == original) {
+                            result = unaryLogicNode.tryFold(newStamp);
+                        }
+                        if (!result.isKnown()) {
+                            Stamp foldResult = recursiveFoldStamp(unaryLogicNode.getValue(), original, newStamp);
+                            if (foldResult != null) {
+                                result = unaryLogicNode.tryFold(foldResult);
+                            }
+                        }
+                    } else if (pending.condition instanceof BinaryOpLogicNode) {
+                        BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
+                        ValueNode x = binaryOpLogicNode.getX();
+                        ValueNode y = binaryOpLogicNode.getY();
+                        if (binaryOpLogicNode.getX() == original) {
+                            result = binaryOpLogicNode.tryFold(newStamp, binaryOpLogicNode.getY().stamp());
+                        } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
+                            AndNode and = (AndNode) x;
+                            if (and.getY() == y && and.getX() == original) {
+                                BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
+                                result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, y.stamp()), y.stamp());
+                            }
+                        }
+                        if (!result.isKnown() && y.isConstant()) {
+                            Stamp foldResult = recursiveFoldStamp(x, original, newStamp);
+                            if (foldResult != null) {
+                                result = binaryOpLogicNode.tryFold(foldResult, y.stamp());
+                            }
+                        }
+                    }
+                    if (result.isKnown()) {
+                        /*
+                         * The test case be folded using the information available but the test can
+                         * only be moved up if we're sure there's no schedule dependence. For now
+                         * limit it to the original node and constants.
+                         */
+                        InputFilter v = new InputFilter(original);
+                        thisGuard.getCondition().applyInputs(v);
+                        if (v.ok && foldGuard(thisGuard, pending.guard, rewireGuardFunction)) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, GuardRewirer rewireGuardFunction) {
+                if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getReason() == thisGuard.getReason() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
+                    LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
+                    GuardRewirer rewirer = (guard, result) -> {
+                        if (rewireGuardFunction.rewire(guard, result)) {
+                            otherGuard.setCondition(condition, thisGuard.isNegated());
+                            return true;
+                        }
+                        condition.safeDelete();
+                        return false;
+                    };
+                    // Move the later test up
+                    return rewireGuards(otherGuard.asNode(), !thisGuard.isNegated(), rewirer);
+                }
+                return false;
+            }
+
+            protected void registerCondition(LogicNode condition, boolean negated, ValueNode guard) {
+                registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
+            }
+
+            protected Iterable<InfoElement> getInfoElements(ValueNode proxiedValue) {
+                ValueNode value = GraphUtil.unproxify(proxiedValue);
+                if (value == null) {
+                    return Collections.emptyList();
+                }
+                Info info = map.get(value);
+                if (info == null) {
+                    return Collections.emptyList();
+                } else {
+                    return info.getElements();
+                }
+            }
+
+            protected boolean rewireGuards(ValueNode guard, boolean result, GuardRewirer rewireGuardFunction) {
+                assert guard instanceof GuardingNode;
+                counterStampsFound.increment();
+                ValueNode proxiedGuard = proxyGuard(guard);
+                return rewireGuardFunction.rewire(proxiedGuard, result);
+            }
+
+            protected ValueNode proxyGuard(ValueNode guard) {
+                ValueNode proxiedGuard = guard;
+                if (!Instance.this.loopExits.isEmpty()) {
+                    while (proxiedGuard instanceof GuardProxyNode) {
+                        proxiedGuard = ((GuardProxyNode) proxiedGuard).value();
+                    }
+                    Block guardBlock = nodeToBlock.apply(proxiedGuard);
+                    assert guardBlock != null;
+                    for (Iterator<LoopExitNode> iter = loopExits.descendingIterator(); iter.hasNext();) {
+                        LoopExitNode loopExitNode = iter.next();
+                        Block loopExitBlock = nodeToBlock.apply(loopExitNode);
+                        if (guardBlock != loopExitBlock && AbstractControlFlowGraph.dominates(guardBlock, loopExitBlock)) {
+                            Block loopBeginBlock = nodeToBlock.apply(loopExitNode.loopBegin());
+                            if (!AbstractControlFlowGraph.dominates(guardBlock, loopBeginBlock) || guardBlock == loopBeginBlock) {
+                                proxiedGuard = proxiedGuard.graph().unique(new GuardProxyNode((GuardingNode) proxiedGuard, loopExitNode));
+                            }
+                        }
+                    }
+                }
+                return proxiedGuard;
+            }
+
+            protected boolean tryProveCondition(LogicNode node, GuardRewirer rewireGuardFunction) {
+                return tryProveGuardCondition(null, node, rewireGuardFunction);
+            }
+
+            protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
+                for (InfoElement infoElement : getInfoElements(node)) {
+                    Stamp stamp = infoElement.getStamp();
+                    JavaConstant constant = (JavaConstant) stamp.asConstant();
+                    if (constant != null) {
+                        return rewireGuards(infoElement.getGuard(), constant.asBoolean(), rewireGuardFunction);
+                    }
+                }
+                if (node instanceof UnaryOpLogicNode) {
+                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
+                    ValueNode value = unaryLogicNode.getValue();
+                    for (InfoElement infoElement : getInfoElements(value)) {
+                        Stamp stamp = infoElement.getStamp();
+                        TriState result = unaryLogicNode.tryFold(stamp);
+                        if (result.isKnown()) {
+                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), rewireGuardFunction);
+                        }
+                    }
+                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(value);
+                    if (foldResult != null) {
+                        TriState result = unaryLogicNode.tryFold(foldResult.second);
+                        if (result.isKnown()) {
+                            return rewireGuards(foldResult.first.getGuard(), result.toBoolean(), rewireGuardFunction);
+                        }
+                    }
+                    if (thisGuard != null) {
+                        Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
+                        if (newStamp != null && foldPendingTest(thisGuard, value, newStamp, rewireGuardFunction)) {
+                            return true;
+                        }
+
+                    }
+                } else if (node instanceof BinaryOpLogicNode) {
+                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node;
+                    for (InfoElement infoElement : getInfoElements(binaryOpLogicNode)) {
+                        if (infoElement.getStamp().equals(StampFactory.contradiction())) {
+                            return rewireGuards(infoElement.getGuard(), false, rewireGuardFunction);
+                        } else if (infoElement.getStamp().equals(StampFactory.tautology())) {
+                            return rewireGuards(infoElement.getGuard(), true, rewireGuardFunction);
+                        }
+                    }
+
+                    ValueNode x = binaryOpLogicNode.getX();
+                    ValueNode y = binaryOpLogicNode.getY();
+                    for (InfoElement infoElement : getInfoElements(x)) {
+                        TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp());
+                        if (result.isKnown()) {
+                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), rewireGuardFunction);
+                        }
+                    }
+
+                    if (y.isConstant()) {
+                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(x);
+                        if (foldResult != null) {
+                            TriState result = binaryOpLogicNode.tryFold(foldResult.second, y.stamp());
+                            if (result.isKnown()) {
+                                return rewireGuards(foldResult.first.getGuard(), result.toBoolean(), rewireGuardFunction);
+                            }
+                        }
+                    } else {
+                        for (InfoElement infoElement : getInfoElements(y)) {
+                            TriState result = binaryOpLogicNode.tryFold(x.stamp(), infoElement.getStamp());
+                            if (result.isKnown()) {
+                                return rewireGuards(infoElement.getGuard(), result.toBoolean(), rewireGuardFunction);
+                            }
+                        }
+                    }
+
+                    /*
+                     * For complex expressions involving constants, see if it's possible to fold the
+                     * tests by using stamps one level up in the expression. For instance, (x + n <
+                     * y) might fold if something is known about x and all other values are
+                     * constants. The reason for the constant restriction is that if more than 1
+                     * real value is involved the code might need to adopt multiple guards to have
+                     * proper dependences.
+                     */
+                    if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
+                        BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
+                        if (binary.getY().isConstant()) {
+                            for (InfoElement infoElement : getInfoElements(binary.getX())) {
+                                Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp());
+                                TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp());
+                                if (result.isKnown()) {
+                                    return rewireGuards(infoElement.getGuard(), result.toBoolean(), rewireGuardFunction);
+                                }
+                            }
+                        }
+                    }
+                    if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
+                        if (y.isConstant() && x instanceof AndNode) {
+                            AndNode and = (AndNode) x;
+                            if (and.getY() == y) {
+                                /*
+                                 * This 'and' proves something about some of the bits in and.getX().
+                                 * It's equivalent to or'ing in the mask value since those values
+                                 * are known to be set.
+                                 */
+                                BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+                                IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp());
+                                if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                    if (thisGuard != null) {
+                        if (!x.isConstant()) {
+                            Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated());
+                            if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) {
+                                return true;
+                            }
+                        }
+                        if (!y.isConstant()) {
+                            Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated());
+                            if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) {
+                                return true;
+                            }
+                        }
+                    }
+                } else if (node instanceof ShortCircuitOrNode) {
+                    final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
+                    if (Instance.this.loopExits.isEmpty()) {
+                        return tryProveCondition(shortCircuitOrNode.getX(), (guard, result) -> {
+                            if (result == !shortCircuitOrNode.isXNegated()) {
+                                return rewireGuards(guard, true, rewireGuardFunction);
+                            } else {
+                                return tryProveCondition(shortCircuitOrNode.getY(), (innerGuard, innerResult) -> {
+                                    if (innerGuard == guard) {
+                                        return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), rewireGuardFunction);
+                                    }
+                                    return false;
+                                });
+                            }
+                        });
+                    }
+                }
+
+                return false;
+            }
+
+            protected void registerNewStamp(ValueNode proxiedValue, Stamp newStamp, ValueNode guard) {
+                assert proxiedValue != null;
+                assert guard != null;
+                if (newStamp != null) {
+                    ValueNode value = GraphUtil.unproxify(proxiedValue);
+                    Info info = map.get(value);
+                    if (info == null) {
+                        info = new Info();
+                        map.set(value, info);
+                    }
+                    counterStampsRegistered.increment();
+                    final Info finalInfo = info;
+                    Debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, newStamp, guard == null ? "null" : guard);
+                    finalInfo.pushElement(new InfoElement(newStamp, guard));
+                    undoOperations.add(() -> finalInfo.popElement());
+                }
+            }
+
+            protected void processAbstractBegin(AbstractBeginNode beginNode) {
+                Node predecessor = beginNode.predecessor();
+                if (predecessor instanceof IfNode) {
+                    IfNode ifNode = (IfNode) predecessor;
+                    boolean negated = (ifNode.falseSuccessor() == beginNode);
+                    LogicNode condition = ifNode.condition();
+                    registerNewCondition(condition, negated, beginNode);
+                } else if (predecessor instanceof TypeSwitchNode) {
+                    TypeSwitchNode typeSwitch = (TypeSwitchNode) predecessor;
+                    processTypeSwitch(beginNode, predecessor, typeSwitch);
+                } else if (predecessor instanceof IntegerSwitchNode) {
+                    IntegerSwitchNode integerSwitchNode = (IntegerSwitchNode) predecessor;
+                    processIntegerSwitch(beginNode, predecessor, integerSwitchNode);
+                }
+            }
+
+            protected void processIntegerSwitch(AbstractBeginNode beginNode, Node predecessor, IntegerSwitchNode integerSwitchNode) {
+                Stamp stamp = null;
+                for (int i = 0; i < integerSwitchNode.keyCount(); i++) {
+                    if (integerSwitchNode.keySuccessor(i) == predecessor) {
+                        if (stamp == null) {
+                            stamp = StampFactory.forConstant(integerSwitchNode.keyAt(i));
+                        } else {
+                            stamp = stamp.meet(StampFactory.forConstant(integerSwitchNode.keyAt(i)));
+                        }
+                    }
+                }
+
+                if (stamp != null) {
+                    registerNewStamp(integerSwitchNode.value(), stamp, beginNode);
+                }
+            }
+
+            protected void processTypeSwitch(AbstractBeginNode beginNode, Node predecessor, TypeSwitchNode typeSwitch) {
+                ValueNode hub = typeSwitch.value();
+                if (hub instanceof LoadHubNode) {
+                    LoadHubNode loadHub = (LoadHubNode) hub;
+                    Stamp stamp = null;
+                    for (int i = 0; i < typeSwitch.keyCount(); i++) {
+                        if (typeSwitch.keySuccessor(i) == predecessor) {
+                            if (stamp == null) {
+                                stamp = StampFactory.objectNonNull(TypeReference.createExactTrusted(typeSwitch.typeAt(i)));
+                            } else {
+                                stamp = stamp.meet(StampFactory.objectNonNull(TypeReference.createExactTrusted(typeSwitch.typeAt(i))));
+                            }
+                        }
+                    }
+                    if (stamp != null) {
+                        registerNewStamp(loadHub.getValue(), stamp, beginNode);
+                    }
+                }
+            }
+        }
+    }
+
+    protected static class Pair<F, S> {
+        public final F first;
+        public final S second;
+
+        Pair(F first, S second) {
+            this.first = first;
+            this.second = second;
+        }
+
+        @Override
+        public int hashCode() {
+            return first.hashCode() * 31 ^ second.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Pair<?, ?>) {
+                Pair<?, ?> other = (Pair<?, ?>) obj;
+                return this.first.equals(other.first) && this.second.equals(other.second);
+            }
+            return false;
+        }
+    }
+
+    @FunctionalInterface
+    protected interface InfoElementProvider {
+        Iterable<InfoElement> getInfoElements(ValueNode value);
+    }
+
+    /**
+     * Checks for safe nodes when moving pending tests up.
+     */
+    static class InputFilter extends Node.EdgeVisitor {
+        boolean ok;
+        private ValueNode value;
+
+        InputFilter(ValueNode value) {
+            this.value = value;
+            this.ok = true;
+        }
+
+        @Override
+        public Node apply(Node node, Node curNode) {
+            if (!(curNode instanceof ValueNode)) {
+                ok = false;
+                return curNode;
+            }
+            ValueNode curValue = (ValueNode) curNode;
+            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
+                return curNode;
+            }
+            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
+                curValue.applyInputs(this);
+            } else {
+                ok = false;
+            }
+            return curNode;
+        }
+    }
+
+    @FunctionalInterface
+    protected interface GuardRewirer {
+        /**
+         * Called if the condition could be proven to have a constant value ({@code result}) under
+         * {@code guard}.
+         *
+         * Return whether a transformation could be applied.
+         */
+        boolean rewire(ValueNode guard, boolean result);
+    }
+
+    protected static class PendingTest {
+        private final LogicNode condition;
+        private final DeoptimizingGuard guard;
+
+        public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
+            this.condition = condition;
+            this.guard = guard;
+        }
+    }
+
+    protected static final class InfoElement {
+        private final Stamp stamp;
+        private final ValueNode guard;
+
+        public InfoElement(Stamp stamp, ValueNode guard) {
+            this.stamp = stamp;
+            this.guard = guard;
+        }
+
+        public Stamp getStamp() {
+            return stamp;
+        }
+
+        public ValueNode getGuard() {
+            return guard;
+        }
+
+        @Override
+        public String toString() {
+            return stamp + " -> " + guard;
+        }
+    }
+
+    protected static final class Info {
+        private final ArrayList<InfoElement> infos;
+
+        public Info() {
+            infos = new ArrayList<>();
+        }
+
+        public Iterable<InfoElement> getElements() {
+            return infos;
+        }
+
+        public void pushElement(InfoElement element) {
+            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Pushing an info element:%s", element);
+            infos.add(element);
+        }
+
+        public void popElement() {
+            infos.remove(infos.size() - 1);
+        }
+    }
+
+    private static class GuardedConstantStamp extends ObjectStamp {
+        private final JavaConstant objectConstant;
+
+        GuardedConstantStamp(JavaConstant objectConstant, ObjectStamp succeedingStamp) {
+            super(succeedingStamp.type(), succeedingStamp.isExactType(), succeedingStamp.nonNull(), succeedingStamp.alwaysNull());
+            this.objectConstant = objectConstant;
+        }
+
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 1.5f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java
new file mode 100644
index 0000000..37df1d9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.phases.Phase;
+
+public class ExpandLogicPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ShortCircuitOrNode logic : graph.getNodes(ShortCircuitOrNode.TYPE)) {
+            processBinary(logic);
+        }
+        assert graph.getNodes(ShortCircuitOrNode.TYPE).isEmpty();
+    }
+
+    private static void processBinary(ShortCircuitOrNode binary) {
+        while (binary.usages().isNotEmpty()) {
+            Node usage = binary.usages().first();
+            if (usage instanceof ShortCircuitOrNode) {
+                processBinary((ShortCircuitOrNode) usage);
+            } else if (usage instanceof IfNode) {
+                processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability());
+            } else if (usage instanceof ConditionalNode) {
+                processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage);
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+        }
+        binary.safeDelete();
+    }
+
+    private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) {
+        AbstractBeginNode trueTarget = ifNode.trueSuccessor();
+        AbstractBeginNode falseTarget = ifNode.falseSuccessor();
+        double firstIfProbability = shortCircuitProbability;
+        /*
+         * P(Y | not(X)) = P(Y inter not(X)) / P(not(X)) = (P(X union Y) - P(X)) / (1 - P(X))
+         *
+         * P(X) = shortCircuitProbability
+         *
+         * P(X union Y) = ifNode.probability(trueTarget)
+         */
+        double secondIfProbability = (ifNode.probability(trueTarget) - shortCircuitProbability) / (1 - shortCircuitProbability);
+        secondIfProbability = Math.min(1.0, Math.max(0.0, secondIfProbability));
+        if (Double.isNaN(secondIfProbability)) {
+            secondIfProbability = 0.5;
+        }
+        ifNode.clearSuccessors();
+        Graph graph = ifNode.graph();
+        AbstractMergeNode trueTargetMerge = graph.add(new MergeNode());
+        trueTargetMerge.setNext(trueTarget);
+        EndNode firstTrueEnd = graph.add(new EndNode());
+        EndNode secondTrueEnd = graph.add(new EndNode());
+        trueTargetMerge.addForwardEnd(firstTrueEnd);
+        trueTargetMerge.addForwardEnd(secondTrueEnd);
+        AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd);
+        AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd);
+        AbstractBeginNode secondIf = BeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfProbability)));
+        IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfProbability));
+        ifNode.replaceAtPredecessor(firstIf);
+        ifNode.safeDelete();
+    }
+
+    private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional) {
+        ValueNode trueTarget = conditional.trueValue();
+        ValueNode falseTarget = conditional.falseValue();
+        Graph graph = conditional.graph();
+        ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget));
+        ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? secondConditional : trueTarget, xNegated ? trueTarget : secondConditional));
+        conditional.replaceAndDelete(firstConditional);
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java
new file mode 100644
index 0000000..707cb35
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.graph.Graph.NodeEvent.NODE_ADDED;
+import static org.graalvm.compiler.graph.Graph.NodeEvent.ZERO_USAGES;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.cfg.HIRLoop;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.memory.FloatableAccessNode;
+import org.graalvm.compiler.nodes.memory.FloatingAccessNode;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryAnchorNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryMap;
+import org.graalvm.compiler.nodes.memory.MemoryMapNode;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
+
+public class FloatingReadPhase extends Phase {
+
+    private boolean createFloatingReads;
+    private boolean createMemoryMapNodes;
+
+    public static class MemoryMapImpl implements MemoryMap {
+
+        private final Map<LocationIdentity, MemoryNode> lastMemorySnapshot;
+
+        public MemoryMapImpl(MemoryMapImpl memoryMap) {
+            lastMemorySnapshot = CollectionsFactory.newMap(memoryMap.lastMemorySnapshot);
+        }
+
+        public MemoryMapImpl(StartNode start) {
+            lastMemorySnapshot = CollectionsFactory.newMap();
+            lastMemorySnapshot.put(any(), start);
+        }
+
+        public MemoryMapImpl() {
+            lastMemorySnapshot = CollectionsFactory.newMap();
+        }
+
+        @Override
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+            MemoryNode lastLocationAccess;
+            if (locationIdentity.isImmutable()) {
+                return null;
+            } else {
+                lastLocationAccess = lastMemorySnapshot.get(locationIdentity);
+                if (lastLocationAccess == null) {
+                    lastLocationAccess = lastMemorySnapshot.get(any());
+                    assert lastLocationAccess != null;
+                }
+                return lastLocationAccess;
+            }
+        }
+
+        @Override
+        public Collection<LocationIdentity> getLocations() {
+            return lastMemorySnapshot.keySet();
+        }
+
+        public Map<LocationIdentity, MemoryNode> getMap() {
+            return lastMemorySnapshot;
+        }
+    }
+
+    public FloatingReadPhase() {
+        this(true, false);
+    }
+
+    /**
+     * @param createFloatingReads specifies whether {@link FloatableAccessNode}s like
+     *            {@link ReadNode} should be converted into floating nodes (e.g.,
+     *            {@link FloatingReadNode}s) where possible
+     * @param createMemoryMapNodes a {@link MemoryMapNode} will be created for each return if this
+     *            is true
+     */
+    public FloatingReadPhase(boolean createFloatingReads, boolean createMemoryMapNodes) {
+        this.createFloatingReads = createFloatingReads;
+        this.createMemoryMapNodes = createMemoryMapNodes;
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 1.25f;
+    }
+
+    /**
+     * Removes nodes from a given set that (transitively) have a usage outside the set.
+     */
+    private static Set<Node> removeExternallyUsedNodes(Set<Node> set) {
+        boolean change;
+        do {
+            change = false;
+            for (Iterator<Node> iter = set.iterator(); iter.hasNext();) {
+                Node node = iter.next();
+                for (Node usage : node.usages()) {
+                    if (!set.contains(usage)) {
+                        change = true;
+                        iter.remove();
+                        break;
+                    }
+                }
+            }
+        } while (change);
+        return set;
+    }
+
+    protected void processNode(FixedNode node, Set<LocationIdentity> currentState) {
+        if (node instanceof MemoryCheckpoint.Single) {
+            currentState.add(((MemoryCheckpoint.Single) node).getLocationIdentity());
+        } else if (node instanceof MemoryCheckpoint.Multi) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                currentState.add(identity);
+            }
+        }
+    }
+
+    protected void processBlock(Block b, Set<LocationIdentity> currentState) {
+        for (FixedNode n : b.getNodes()) {
+            processNode(n, currentState);
+        }
+    }
+
+    private Set<LocationIdentity> processLoop(HIRLoop loop, Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
+        LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
+        Set<LocationIdentity> result = modifiedInLoops.get(loopBegin);
+        if (result != null) {
+            return result;
+        }
+
+        result = CollectionsFactory.newSet();
+        for (Loop<Block> inner : loop.getChildren()) {
+            result.addAll(processLoop((HIRLoop) inner, modifiedInLoops));
+        }
+
+        for (Block b : loop.getBlocks()) {
+            if (b.getLoop() == loop) {
+                processBlock(b, result);
+            }
+        }
+
+        modifiedInLoops.put(loopBegin, result);
+        return result;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph) {
+        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = null;
+        if (graph.hasLoops()) {
+            modifiedInLoops = new HashMap<>();
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            for (Loop<?> l : cfg.getLoops()) {
+                HIRLoop loop = (HIRLoop) l;
+                processLoop(loop, modifiedInLoops);
+            }
+        }
+
+        HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES));
+        try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+            ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start()));
+        }
+
+        for (Node n : removeExternallyUsedNodes(listener.getNodes())) {
+            if (n.isAlive() && n instanceof FloatingNode) {
+                n.replaceAtUsages(null);
+                GraphUtil.killWithUnusedFloatingInputs(n);
+            }
+        }
+        if (createFloatingReads) {
+            assert !graph.isAfterFloatingReadPhase();
+            graph.setAfterFloatingReadPhase(true);
+        }
+    }
+
+    public static MemoryMapImpl mergeMemoryMaps(AbstractMergeNode merge, List<? extends MemoryMap> states) {
+        MemoryMapImpl newState = new MemoryMapImpl();
+
+        Set<LocationIdentity> keys = CollectionsFactory.newSet();
+        for (MemoryMap other : states) {
+            keys.addAll(other.getLocations());
+        }
+        assert checkNoImmutableLocations(keys);
+
+        for (LocationIdentity key : keys) {
+            int mergedStatesCount = 0;
+            boolean isPhi = false;
+            MemoryNode merged = null;
+            for (MemoryMap state : states) {
+                MemoryNode last = state.getLastLocationAccess(key);
+                if (isPhi) {
+                    ((MemoryPhiNode) merged).addInput(ValueNodeUtil.asNode(last));
+                } else {
+                    if (merged == last) {
+                        // nothing to do
+                    } else if (merged == null) {
+                        merged = last;
+                    } else {
+                        MemoryPhiNode phi = merge.graph().addWithoutUnique(new MemoryPhiNode(merge, key));
+                        for (int j = 0; j < mergedStatesCount; j++) {
+                            phi.addInput(ValueNodeUtil.asNode(merged));
+                        }
+                        phi.addInput(ValueNodeUtil.asNode(last));
+                        merged = phi;
+                        isPhi = true;
+                    }
+                }
+                mergedStatesCount++;
+            }
+            newState.lastMemorySnapshot.put(key, merged);
+        }
+        return newState;
+
+    }
+
+    private static boolean checkNoImmutableLocations(Set<LocationIdentity> keys) {
+        keys.forEach(t -> {
+            assert !t.isImmutable();
+        });
+        return true;
+    }
+
+    public static class FloatingReadClosure extends NodeIteratorClosure<MemoryMapImpl> {
+
+        private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
+        private boolean createFloatingReads;
+        private boolean createMemoryMapNodes;
+
+        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops, boolean createFloatingReads, boolean createMemoryMapNodes) {
+            this.modifiedInLoops = modifiedInLoops;
+            this.createFloatingReads = createFloatingReads;
+            this.createMemoryMapNodes = createMemoryMapNodes;
+        }
+
+        @Override
+        protected MemoryMapImpl processNode(FixedNode node, MemoryMapImpl state) {
+            if (node instanceof MemoryAnchorNode) {
+                processAnchor((MemoryAnchorNode) node, state);
+                return state;
+            }
+
+            if (node instanceof MemoryAccess) {
+                processAccess((MemoryAccess) node, state);
+            }
+
+            if (createFloatingReads & node instanceof FloatableAccessNode) {
+                processFloatable((FloatableAccessNode) node, state);
+            } else if (node instanceof MemoryCheckpoint.Single) {
+                processCheckpoint((MemoryCheckpoint.Single) node, state);
+            } else if (node instanceof MemoryCheckpoint.Multi) {
+                processCheckpoint((MemoryCheckpoint.Multi) node, state);
+            }
+            assert MemoryCheckpoint.TypeAssertion.correctType(node) : node;
+
+            if (createMemoryMapNodes && node instanceof ReturnNode) {
+                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapNode(state.lastMemorySnapshot)));
+            }
+            return state;
+        }
+
+        /**
+         * Improve the memory graph by re-wiring all usages of a {@link MemoryAnchorNode} to the
+         * real last access location.
+         */
+        private static void processAnchor(MemoryAnchorNode anchor, MemoryMapImpl state) {
+            for (Node node : anchor.usages().snapshot()) {
+                if (node instanceof MemoryAccess) {
+                    MemoryAccess access = (MemoryAccess) node;
+                    if (access.getLastLocationAccess() == anchor) {
+                        MemoryNode lastLocationAccess = state.getLastLocationAccess(access.getLocationIdentity());
+                        assert lastLocationAccess != null;
+                        access.setLastLocationAccess(lastLocationAccess);
+                    }
+                }
+            }
+
+            if (anchor.hasNoUsages()) {
+                anchor.graph().removeFixed(anchor);
+            }
+        }
+
+        private static void processAccess(MemoryAccess access, MemoryMapImpl state) {
+            LocationIdentity locationIdentity = access.getLocationIdentity();
+            if (!locationIdentity.equals(LocationIdentity.any())) {
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                access.setLastLocationAccess(lastLocationAccess);
+            }
+        }
+
+        private static void processCheckpoint(MemoryCheckpoint.Single checkpoint, MemoryMapImpl state) {
+            processIdentity(checkpoint.getLocationIdentity(), checkpoint, state);
+        }
+
+        private static void processCheckpoint(MemoryCheckpoint.Multi checkpoint, MemoryMapImpl state) {
+            for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
+                processIdentity(identity, checkpoint, state);
+            }
+        }
+
+        private static void processIdentity(LocationIdentity identity, MemoryCheckpoint checkpoint, MemoryMapImpl state) {
+            if (identity.isAny()) {
+                state.lastMemorySnapshot.clear();
+            }
+            state.lastMemorySnapshot.put(identity, checkpoint);
+        }
+
+        @SuppressWarnings("try")
+        private static void processFloatable(FloatableAccessNode accessNode, MemoryMapImpl state) {
+            StructuredGraph graph = accessNode.graph();
+            LocationIdentity locationIdentity = accessNode.getLocationIdentity();
+            if (accessNode.canFloat()) {
+                assert accessNode.getNullCheck() == false;
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                try (DebugCloseable position = accessNode.withNodeSourcePosition()) {
+                    FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
+                    ValueAnchorNode anchor = null;
+                    GuardingNode guard = accessNode.getGuard();
+                    if (guard != null) {
+                        anchor = graph.add(new ValueAnchorNode(guard.asNode()));
+                        graph.addAfterFixed(accessNode, anchor);
+                    }
+                    graph.replaceFixedWithFloating(accessNode, floatingNode);
+                }
+            }
+        }
+
+        @Override
+        protected MemoryMapImpl merge(AbstractMergeNode merge, List<MemoryMapImpl> states) {
+            return mergeMemoryMaps(merge, states);
+        }
+
+        @Override
+        protected MemoryMapImpl afterSplit(AbstractBeginNode node, MemoryMapImpl oldState) {
+            MemoryMapImpl result = new MemoryMapImpl(oldState);
+            if (node.predecessor() instanceof InvokeWithExceptionNode) {
+                /*
+                 * InvokeWithException cannot be the lastLocationAccess for a FloatingReadNode.
+                 * Since it is both the invoke and a control flow split, the scheduler cannot
+                 * schedule anything immediately after the invoke. It can only schedule in the
+                 * normal or exceptional successor - and we have to tell the scheduler here which
+                 * side it needs to choose by putting in the location identity on both successors.
+                 */
+                InvokeWithExceptionNode invoke = (InvokeWithExceptionNode) node.predecessor();
+                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), (MemoryCheckpoint) node);
+            }
+            return result;
+        }
+
+        @Override
+        protected Map<LoopExitNode, MemoryMapImpl> processLoop(LoopBeginNode loop, MemoryMapImpl initialState) {
+            Set<LocationIdentity> modifiedLocations = modifiedInLoops.get(loop);
+            Map<LocationIdentity, MemoryPhiNode> phis = CollectionsFactory.newMap();
+            if (modifiedLocations.contains(LocationIdentity.any())) {
+                // create phis for all locations if ANY is modified in the loop
+                modifiedLocations = CollectionsFactory.newSet(modifiedLocations);
+                modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet());
+            }
+
+            for (LocationIdentity location : modifiedLocations) {
+                createMemoryPhi(loop, initialState, phis, location);
+            }
+            for (Map.Entry<LocationIdentity, MemoryPhiNode> entry : phis.entrySet()) {
+                initialState.lastMemorySnapshot.put(entry.getKey(), entry.getValue());
+            }
+
+            LoopInfo<MemoryMapImpl> loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState);
+
+            for (Map.Entry<LoopEndNode, MemoryMapImpl> entry : loopInfo.endStates.entrySet()) {
+                int endIndex = loop.phiPredecessorIndex(entry.getKey());
+                for (Map.Entry<LocationIdentity, MemoryPhiNode> phiEntry : phis.entrySet()) {
+                    LocationIdentity key = phiEntry.getKey();
+                    PhiNode phi = phiEntry.getValue();
+                    phi.initializeValueAt(endIndex, ValueNodeUtil.asNode(entry.getValue().getLastLocationAccess(key)));
+                }
+            }
+            return loopInfo.exitStates;
+        }
+
+        private static void createMemoryPhi(LoopBeginNode loop, MemoryMapImpl initialState, Map<LocationIdentity, MemoryPhiNode> phis, LocationIdentity location) {
+            MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
+            phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
+            phis.put(location, phi);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java
new file mode 100644
index 0000000..ef92c5c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
+import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
+
+/**
+ * This phase transfers {@link FrameState} nodes from {@link StateSplit} nodes to
+ * {@link DeoptimizingNode DeoptimizingNodes}.
+ *
+ * This allow to enter the {@link GuardsStage#AFTER_FSA AFTER_FSA} stage of the graph where no new
+ * node that may cause deoptimization can be introduced anymore.
+ * <p>
+ * This Phase processes the graph in post order, assigning the {@link FrameState} from the last
+ * {@link StateSplit} node to {@link DeoptimizingNode DeoptimizingNodes}.
+ */
+public class FrameStateAssignmentPhase extends Phase {
+
+    private static class FrameStateAssignmentClosure extends NodeIteratorClosure<FrameState> {
+
+        @Override
+        protected FrameState processNode(FixedNode node, FrameState previousState) {
+            FrameState currentState = previousState;
+            if (node instanceof DeoptimizingNode.DeoptBefore) {
+                DeoptimizingNode.DeoptBefore deopt = (DeoptimizingNode.DeoptBefore) node;
+                if (deopt.canDeoptimize() && deopt.stateBefore() == null) {
+                    GraalError.guarantee(currentState != null, "no FrameState at DeoptimizingNode %s", deopt);
+                    deopt.setStateBefore(currentState);
+                }
+            }
+
+            if (node instanceof StateSplit) {
+                StateSplit stateSplit = (StateSplit) node;
+                FrameState stateAfter = stateSplit.stateAfter();
+                if (stateAfter != null) {
+                    currentState = stateAfter;
+                    stateSplit.setStateAfter(null);
+                }
+            }
+
+            if (node instanceof DeoptimizingNode.DeoptDuring) {
+                DeoptimizingNode.DeoptDuring deopt = (DeoptimizingNode.DeoptDuring) node;
+                if (deopt.canDeoptimize()) {
+                    GraalError.guarantee(currentState != null, "no FrameState at DeoptimizingNode %s", deopt);
+                    deopt.computeStateDuring(currentState);
+                }
+            }
+
+            if (node instanceof DeoptimizingNode.DeoptAfter) {
+                DeoptimizingNode.DeoptAfter deopt = (DeoptimizingNode.DeoptAfter) node;
+                if (deopt.canDeoptimize() && deopt.stateAfter() == null) {
+                    GraalError.guarantee(currentState != null, "no FrameState at DeoptimizingNode %s", deopt);
+                    deopt.setStateAfter(currentState);
+                }
+            }
+
+            return currentState;
+        }
+
+        @Override
+        protected FrameState merge(AbstractMergeNode merge, List<FrameState> states) {
+            FrameState singleFrameState = singleFrameState(states);
+            return singleFrameState == null ? merge.stateAfter() : singleFrameState;
+        }
+
+        @Override
+        protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) {
+            return oldState;
+        }
+
+        @Override
+        protected Map<LoopExitNode, FrameState> processLoop(LoopBeginNode loop, FrameState initialState) {
+            return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        assert !graph.getGuardsStage().allowsFloatingGuards() && !hasFloatingDeopts(graph);
+        if (graph.getGuardsStage().areFrameStatesAtSideEffects()) {
+            ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null);
+            graph.setGuardsStage(GuardsStage.AFTER_FSA);
+            graph.getNodes(FrameState.TYPE).filter(state -> state.hasNoUsages()).forEach(GraphUtil::killWithUnusedFloatingInputs);
+        }
+    }
+
+    private static boolean hasFloatingDeopts(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof DeoptimizingNode && GraphUtil.isFloatingNode(n)) {
+                DeoptimizingNode deoptimizingNode = (DeoptimizingNode) n;
+                if (deoptimizingNode.canDeoptimize()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static FrameState singleFrameState(List<FrameState> states) {
+        FrameState singleState = states.get(0);
+        for (int i = 1; i < states.size(); ++i) {
+            if (states.get(i) != singleState) {
+                return null;
+            }
+        }
+        return singleState;
+    }
+
+    @Override
+    public boolean checkContract() {
+        // TODO GR-1409
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java
new file mode 100644
index 0000000..3e4fe38
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.memory.Access;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.FloatingAccessNode;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.graph.ScheduledNodeIterator;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * This phase lowers {@link GuardNode GuardNodes} into corresponding control-flow structure and
+ * {@link DeoptimizeNode DeoptimizeNodes}.
+ *
+ * This allow to enter the {@link GuardsStage#FIXED_DEOPTS FIXED_DEOPTS} stage of the graph where
+ * all node that may cause deoptimization are fixed.
+ * <p>
+ * It first makes a schedule in order to know where the control flow should be placed. Then, for
+ * each block, it applies two passes. The first one tries to replace null-check guards with implicit
+ * null checks performed by access to the objects that need to be null checked. The second phase
+ * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}.
+ */
+public class GuardLoweringPhase extends BasePhase<MidTierContext> {
+
+    private static final DebugCounter counterImplicitNullCheck = Debug.counter("ImplicitNullCheck");
+
+    private static class UseImplicitNullChecks extends ScheduledNodeIterator {
+
+        private final Map<ValueNode, ValueNode> nullGuarded = Node.newIdentityMap();
+        private final int implicitNullCheckLimit;
+
+        UseImplicitNullChecks(int implicitNullCheckLimit) {
+            this.implicitNullCheckLimit = implicitNullCheckLimit;
+        }
+
+        @Override
+        protected void processNode(Node node) {
+            if (node instanceof GuardNode) {
+                processGuard(node);
+            } else if (node instanceof Access) {
+                processAccess((Access) node);
+            } else if (node instanceof PiNode) {
+                processPi((PiNode) node);
+            }
+            if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
+                nullGuarded.clear();
+            } else {
+                /*
+                 * The OffsetAddressNode itself never forces materialization of a null check, even
+                 * if its input is a PiNode. The null check will be folded into the first usage of
+                 * the OffsetAddressNode, so we need to keep it in the nullGuarded map.
+                 */
+                if (!(node instanceof OffsetAddressNode)) {
+                    Iterator<Entry<ValueNode, ValueNode>> it = nullGuarded.entrySet().iterator();
+                    while (it.hasNext()) {
+                        Entry<ValueNode, ValueNode> entry = it.next();
+                        ValueNode guard = entry.getValue();
+                        if (guard.usages().contains(node)) {
+                            it.remove();
+                        } else if (guard instanceof PiNode && guard != node) {
+                            PiNode piNode = (PiNode) guard;
+                            if (piNode.getGuard().asNode().usages().contains(node)) {
+                                it.remove();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private boolean processPi(PiNode node) {
+            ValueNode guardNode = nullGuarded.get(node.object());
+            if (guardNode != null && node.getGuard() == guardNode) {
+                nullGuarded.put(node, node);
+                return true;
+            }
+            return false;
+        }
+
+        private void processAccess(Access access) {
+            if (access.canNullCheck() && access.getAddress() instanceof OffsetAddressNode) {
+                OffsetAddressNode address = (OffsetAddressNode) access.getAddress();
+                check(access, address);
+            }
+        }
+
+        private void check(Access access, OffsetAddressNode address) {
+            ValueNode base = address.getBase();
+            ValueNode guard = nullGuarded.get(base);
+            if (guard != null && isImplicitNullCheck(address.getOffset())) {
+                if (guard instanceof PiNode) {
+                    PiNode piNode = (PiNode) guard;
+                    assert guard == address.getBase();
+                    assert piNode.getGuard() instanceof GuardNode : piNode;
+                    address.setBase(piNode.getOriginalNode());
+                } else {
+                    assert guard instanceof GuardNode;
+                }
+                counterImplicitNullCheck.increment();
+                access.setGuard(null);
+                FixedAccessNode fixedAccess;
+                if (access instanceof FloatingAccessNode) {
+                    FloatingAccessNode floatingAccessNode = (FloatingAccessNode) access;
+                    MemoryNode lastLocationAccess = floatingAccessNode.getLastLocationAccess();
+                    fixedAccess = floatingAccessNode.asFixedNode();
+                    replaceCurrent(fixedAccess);
+                    if (lastLocationAccess != null) {
+                        // fixed accesses are not currently part of the memory graph
+                        GraphUtil.tryKillUnused(lastLocationAccess.asNode());
+                    }
+                } else {
+                    fixedAccess = (FixedAccessNode) access;
+                }
+                fixedAccess.setNullCheck(true);
+                GuardNode guardNode = null;
+                if (guard instanceof GuardNode) {
+                    guardNode = (GuardNode) guard;
+                } else {
+                    PiNode piNode = (PiNode) guard;
+                    guardNode = (GuardNode) piNode.getGuard();
+                }
+                LogicNode condition = guardNode.getCondition();
+                guardNode.replaceAndDelete(fixedAccess);
+                if (condition.hasNoUsages()) {
+                    GraphUtil.killWithUnusedFloatingInputs(condition);
+                }
+                nullGuarded.remove(base);
+            }
+        }
+
+        private void processGuard(Node node) {
+            GuardNode guard = (GuardNode) node;
+            if (guard.isNegated() && guard.getCondition() instanceof IsNullNode && (guard.getSpeculation() == null || guard.getSpeculation().equals(JavaConstant.NULL_POINTER))) {
+                ValueNode obj = ((IsNullNode) guard.getCondition()).getValue();
+                nullGuarded.put(obj, guard);
+            }
+        }
+
+        private boolean isImplicitNullCheck(ValueNode offset) {
+            JavaConstant c = offset.asJavaConstant();
+            if (c != null) {
+                return c.asLong() < implicitNullCheckLimit;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    private static class LowerGuards extends ScheduledNodeIterator {
+
+        private final Block block;
+        private boolean useGuardIdAsDebugId;
+
+        LowerGuards(Block block, boolean useGuardIdAsDebugId) {
+            this.block = block;
+            this.useGuardIdAsDebugId = useGuardIdAsDebugId;
+        }
+
+        @Override
+        protected void processNode(Node node) {
+            if (node instanceof GuardNode) {
+                GuardNode guard = (GuardNode) node;
+                FixedWithNextNode lowered = guard.lowerGuard();
+                if (lowered != null) {
+                    replaceCurrent(lowered);
+                } else {
+                    lowerToIf(guard);
+                }
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void lowerToIf(GuardNode guard) {
+            try (DebugCloseable position = guard.withNodeSourcePosition()) {
+                StructuredGraph graph = guard.graph();
+                AbstractBeginNode fastPath = graph.add(new BeginNode());
+                @SuppressWarnings("deprecation")
+                int debugId = useGuardIdAsDebugId ? guard.getId() : DeoptimizeNode.DEFAULT_DEBUG_ID;
+                DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.getAction(), guard.getReason(), debugId, guard.getSpeculation(), null));
+                AbstractBeginNode deoptBranch = BeginNode.begin(deopt);
+                AbstractBeginNode trueSuccessor;
+                AbstractBeginNode falseSuccessor;
+                insertLoopExits(deopt);
+                if (guard.isNegated()) {
+                    trueSuccessor = deoptBranch;
+                    falseSuccessor = fastPath;
+                } else {
+                    trueSuccessor = fastPath;
+                    falseSuccessor = deoptBranch;
+                }
+                IfNode ifNode = graph.add(new IfNode(guard.getCondition(), trueSuccessor, falseSuccessor, trueSuccessor == fastPath ? 1 : 0));
+                guard.replaceAndDelete(fastPath);
+                insert(ifNode, fastPath);
+            }
+        }
+
+        private void insertLoopExits(DeoptimizeNode deopt) {
+            Loop<Block> loop = block.getLoop();
+            StructuredGraph graph = deopt.graph();
+            while (loop != null) {
+                LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode()));
+                graph.addBeforeFixed(deopt, exit);
+                loop = loop.getParent();
+            }
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        if (graph.getGuardsStage().allowsFloatingGuards()) {
+            SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+            schedulePhase.apply(graph);
+            ScheduleResult schedule = graph.getLastSchedule();
+
+            for (Block block : schedule.getCFG().getBlocks()) {
+                processBlock(block, schedule, context != null ? context.getTarget().implicitNullCheckLimit : 0);
+            }
+            graph.setGuardsStage(GuardsStage.FIXED_DEOPTS);
+        }
+
+        assert assertNoGuardsLeft(graph);
+    }
+
+    private static boolean assertNoGuardsLeft(StructuredGraph graph) {
+        assert graph.getNodes().filter(GuardNode.class).isEmpty();
+        return true;
+    }
+
+    private static void processBlock(Block block, ScheduleResult schedule, int implicitNullCheckLimit) {
+        if (OptImplicitNullChecks.getValue() && implicitNullCheckLimit > 0) {
+            new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(block, schedule);
+        }
+        new LowerGuards(block, Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()).processNodes(block, schedule);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java
new file mode 100644
index 0000000..cbd30d4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * A phase suite that applies {@linkplain CanonicalizerPhase canonicalization} to a graph after all
+ * phases in the suite have been applied if any of the phases changed the graph.
+ */
+public class IncrementalCanonicalizerPhase<C extends PhaseContext> extends PhaseSuite<C> {
+
+    private final CanonicalizerPhase canonicalizer;
+
+    public IncrementalCanonicalizerPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
+    public IncrementalCanonicalizerPhase(CanonicalizerPhase canonicalizer, BasePhase<? super C> phase) {
+        this.canonicalizer = canonicalizer;
+        appendPhase(phase);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, C context) {
+        HashSetNodeEventListener listener = new HashSetNodeEventListener();
+        try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+            super.run(graph, context);
+        }
+
+        if (!listener.getNodes().isEmpty()) {
+            canonicalizer.applyIncremental(graph, context, listener.getNodes(), null, false);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java
new file mode 100644
index 0000000..f2ee89d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.graph.Graph.NodeEvent.NODE_ADDED;
+import static org.graalvm.compiler.graph.Graph.NodeEvent.ZERO_USAGES;
+
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class IterativeConditionalEliminationPhase extends BasePhase<PhaseContext> {
+
+    private static final int MAX_ITERATIONS = 256;
+
+    private final CanonicalizerPhase canonicalizer;
+    private final boolean fullSchedule;
+
+    public IterativeConditionalEliminationPhase(CanonicalizerPhase canonicalizer, boolean fullSchedule) {
+        this.canonicalizer = canonicalizer;
+        this.fullSchedule = fullSchedule;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NODE_ADDED).exclude(ZERO_USAGES);
+        int count = 0;
+        while (true) {
+            try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                new DominatorConditionalEliminationPhase(fullSchedule).apply(graph, context);
+            }
+            if (listener.getNodes().isEmpty()) {
+                break;
+            }
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Simplifiable) {
+                    listener.getNodes().add(node);
+                }
+            }
+            canonicalizer.applyIncremental(graph, context, listener.getNodes());
+            listener.getNodes().clear();
+            if (++count > MAX_ITERATIONS) {
+                throw new RetryableBailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds %d", MAX_ITERATIONS);
+            }
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 2.0f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LazyValue.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LazyValue.java
new file mode 100644
index 0000000..b1e1c4f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LazyValue.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.function.Supplier;
+
+/**
+ * A {@link Supplier} which always returns the same value, computed from an other supplier on the
+ * first access.
+ *
+ * <p>
+ * This implementation is not thread-safe and assumes the underlying supplier does not return null.
+ * If the underlying supplier returns null it will be called on each access until it returns a
+ * non-null value.
+ * </p>
+ */
+public class LazyValue<T> implements Supplier<T> {
+    private final Supplier<T> supplier;
+    private T value;
+
+    public LazyValue(Supplier<T> supplier) {
+        this.supplier = supplier;
+    }
+
+    @Override
+    public T get() {
+        if (value == null) {
+            value = supplier.get();
+        }
+        return value;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java
new file mode 100644
index 0000000..8933be2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.AccessMonitorNode;
+import org.graalvm.compiler.nodes.java.MonitorEnterNode;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+
+public class LockEliminationPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (MonitorExitNode node : graph.getNodes(MonitorExitNode.TYPE)) {
+            FixedNode next = node.next();
+            if (next instanceof MonitorEnterNode || next instanceof RawMonitorEnterNode) {
+                AccessMonitorNode monitorEnterNode = (AccessMonitorNode) next;
+                if (GraphUtil.unproxify(monitorEnterNode.object()) == GraphUtil.unproxify(node.object())) {
+                    GraphUtil.removeFixedWithUnusedInputs(monitorEnterNode);
+                    GraphUtil.removeFixedWithUnusedInputs(node);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoopSafepointInsertionPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoopSafepointInsertionPhase.java
new file mode 100644
index 0000000..e8fbf58
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoopSafepointInsertionPhase.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GenLoopSafepoints;
+
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.Phase;
+
+/**
+ * Adds safepoints to loops.
+ */
+public class LoopSafepointInsertionPhase extends Phase {
+
+    @Override
+    public boolean checkContract() {
+        // the size / cost after is highly dynamic and dependent on the graph, thus we do not verify
+        // costs for this phase
+        return false;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (GenLoopSafepoints.getValue()) {
+            for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.TYPE)) {
+                if (loopEndNode.canSafepoint()) {
+                    SafepointNode safepointNode = graph.add(new SafepointNode());
+                    graph.addBeforeFixed(loopEndNode, safepointNode);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java
new file mode 100644
index 0000000..981c8da
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptEliminateGuards;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.graalvm.compiler.phases.common.LoweringPhase.ProcessBlockState.ST_ENTER;
+import static org.graalvm.compiler.phases.common.LoweringPhase.ProcessBlockState.ST_ENTER_ALWAYS_REACHED;
+import static org.graalvm.compiler.phases.common.LoweringPhase.ProcessBlockState.ST_LEAVE;
+import static org.graalvm.compiler.phases.common.LoweringPhase.ProcessBlockState.ST_PROCESS;
+import static org.graalvm.compiler.phases.common.LoweringPhase.ProcessBlockState.ST_PROCESS_ALWAYS_REACHED;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * Processes all {@link Lowerable} nodes to do their lowering.
+ */
+public class LoweringPhase extends BasePhase<PhaseContext> {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class DummyGuardHandle extends ValueNode implements GuardedNode {
+        public static final NodeClass<DummyGuardHandle> TYPE = NodeClass.create(DummyGuardHandle.class);
+        @Input(InputType.Guard) GuardingNode guard;
+
+        protected DummyGuardHandle(GuardingNode guard) {
+            super(TYPE, StampFactory.forVoid());
+            this.guard = guard;
+        }
+
+        @Override
+        public GuardingNode getGuard() {
+            return guard;
+        }
+
+        @Override
+        public void setGuard(GuardingNode guard) {
+            updateUsagesInterface(this.guard, guard);
+            this.guard = guard;
+        }
+
+        @Override
+        public ValueNode asNode() {
+            return this;
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    final class LoweringToolImpl implements LoweringTool {
+
+        private final PhaseContext context;
+        private final NodeBitMap activeGuards;
+        private AnchoringNode guardAnchor;
+        private FixedWithNextNode lastFixedNode;
+
+        LoweringToolImpl(PhaseContext context, AnchoringNode guardAnchor, NodeBitMap activeGuards, FixedWithNextNode lastFixedNode) {
+            this.context = context;
+            this.guardAnchor = guardAnchor;
+            this.activeGuards = activeGuards;
+            this.lastFixedNode = lastFixedNode;
+        }
+
+        @Override
+        public LoweringStage getLoweringStage() {
+            return loweringStage;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return context.getConstantReflection();
+        }
+
+        @Override
+        public ConstantFieldProvider getConstantFieldProvider() {
+            return context.getConstantFieldProvider();
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return context.getMetaAccess();
+        }
+
+        @Override
+        public LoweringProvider getLowerer() {
+            return context.getLowerer();
+        }
+
+        @Override
+        public Replacements getReplacements() {
+            return context.getReplacements();
+        }
+
+        @Override
+        public AnchoringNode getCurrentGuardAnchor() {
+            return guardAnchor;
+        }
+
+        @Override
+        public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
+            return createGuard(before, condition, deoptReason, action, JavaConstant.NULL_POINTER, false);
+        }
+
+        @Override
+        public StampProvider getStampProvider() {
+            return context.getStampProvider();
+        }
+
+        @Override
+        public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated) {
+            if (OptEliminateGuards.getValue()) {
+                for (Node usage : condition.usages()) {
+                    if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).isNegated() == negated) {
+                        return (GuardNode) usage;
+                    }
+                }
+            }
+            StructuredGraph graph = before.graph();
+            if (!condition.graph().getGuardsStage().allowsFloatingGuards()) {
+                FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, speculation, negated));
+                graph.addBeforeFixed(before, fixedGuard);
+                DummyGuardHandle handle = graph.add(new DummyGuardHandle(fixedGuard));
+                fixedGuard.lower(this);
+                GuardingNode result = handle.getGuard();
+                handle.safeDelete();
+                return result;
+            } else {
+                GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, speculation));
+                if (OptEliminateGuards.getValue()) {
+                    activeGuards.markAndGrow(newGuard);
+                }
+                return newGuard;
+            }
+        }
+
+        @Override
+        public FixedWithNextNode lastFixedNode() {
+            return lastFixedNode;
+        }
+
+        @Override
+        public NodeCostProvider getNodeCostProvider() {
+            return context.getNodeCostProvider();
+        }
+
+        private void setLastFixedNode(FixedWithNextNode n) {
+            assert n.isAlive() : n;
+            lastFixedNode = n;
+        }
+    }
+
+    private final CanonicalizerPhase canonicalizer;
+    private final LoweringTool.LoweringStage loweringStage;
+
+    public LoweringPhase(CanonicalizerPhase canonicalizer, LoweringTool.LoweringStage loweringStage) {
+        this.canonicalizer = canonicalizer;
+        this.loweringStage = loweringStage;
+    }
+
+    /**
+     * Checks that second lowering of a given graph did not introduce any new nodes.
+     *
+     * @param graph a graph that was just {@linkplain #lower lowered}
+     * @throws AssertionError if the check fails
+     */
+    private boolean checkPostLowering(StructuredGraph graph, PhaseContext context) {
+        Mark expectedMark = graph.getMark();
+        lower(graph, context, LoweringMode.VERIFY_LOWERING);
+        Mark mark = graph.getMark();
+        assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(expectedMark).snapshot();
+        return true;
+    }
+
+    @Override
+    protected void run(final StructuredGraph graph, PhaseContext context) {
+        lower(graph, context, LoweringMode.LOWERING);
+        assert checkPostLowering(graph, context);
+    }
+
+    private void lower(StructuredGraph graph, PhaseContext context, LoweringMode mode) {
+        IncrementalCanonicalizerPhase<PhaseContext> incrementalCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
+        incrementalCanonicalizer.appendPhase(new Round(context, mode));
+        incrementalCanonicalizer.apply(graph, context);
+        assert graph.verify();
+    }
+
+    /**
+     * Checks that lowering of a given node did not introduce any new {@link Lowerable} nodes that
+     * could be lowered in the current {@link LoweringPhase}. Such nodes must be recursively lowered
+     * as part of lowering {@code node}.
+     *
+     * @param node a node that was just lowered
+     * @param preLoweringMark the graph mark before {@code node} was lowered
+     * @param unscheduledUsages set of {@code node}'s usages that were unscheduled before it was
+     *            lowered
+     * @throws AssertionError if the check fails
+     */
+    private static boolean checkPostNodeLowering(Node node, LoweringToolImpl loweringTool, Mark preLoweringMark, Collection<Node> unscheduledUsages) {
+        StructuredGraph graph = (StructuredGraph) node.graph();
+        Mark postLoweringMark = graph.getMark();
+        NodeIterable<Node> newNodesAfterLowering = graph.getNewNodes(preLoweringMark);
+        if (node instanceof FloatingNode) {
+            if (!unscheduledUsages.isEmpty()) {
+                for (Node n : newNodesAfterLowering) {
+                    assert !(n instanceof FixedNode) : node.graph() + ": cannot lower floatable node " + node + " as it introduces fixed node(s) but has the following unscheduled usages: " +
+                                    unscheduledUsages;
+                }
+            }
+        }
+        for (Node n : newNodesAfterLowering) {
+            if (n instanceof Lowerable) {
+                ((Lowerable) n).lower(loweringTool);
+                Mark mark = graph.getMark();
+                assert postLoweringMark.equals(mark) : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " +
+                                graph.getNewNodes(postLoweringMark).snapshot();
+            }
+        }
+        return true;
+    }
+
+    private enum LoweringMode {
+        LOWERING,
+        VERIFY_LOWERING
+    }
+
+    private final class Round extends Phase {
+
+        private final PhaseContext context;
+        private final LoweringMode mode;
+        private ScheduleResult schedule;
+        private final SchedulePhase schedulePhase;
+
+        private Round(PhaseContext context, LoweringMode mode) {
+            this.context = context;
+            this.mode = mode;
+
+            /*
+             * In VERIFY_LOWERING, we want to verify whether the lowering itself changes the graph.
+             * Make sure we're not detecting spurious changes because the SchedulePhase modifies the
+             * graph.
+             */
+            boolean immutableSchedule = mode == LoweringMode.VERIFY_LOWERING;
+
+            this.schedulePhase = new SchedulePhase(immutableSchedule);
+        }
+
+        @Override
+        protected CharSequence getName() {
+            switch (mode) {
+                case LOWERING:
+                    return "LoweringRound";
+                case VERIFY_LOWERING:
+                    return "VerifyLoweringRound";
+                default:
+                    throw GraalError.shouldNotReachHere();
+            }
+        }
+
+        @Override
+        public boolean checkContract() {
+            /*
+             * lowering with snippets cannot be fully built in the node costs of all high level
+             * nodes
+             */
+            return false;
+        }
+
+        @Override
+        public void run(StructuredGraph graph) {
+            schedulePhase.apply(graph, false);
+            schedule = graph.getLastSchedule();
+            schedule.getCFG().computePostdominators();
+            Block startBlock = schedule.getCFG().getStartBlock();
+            ProcessFrame rootFrame = new ProcessFrame(startBlock, graph.createNodeBitMap(), startBlock.getBeginNode(), null);
+            LoweringPhase.processBlock(rootFrame);
+        }
+
+        private class ProcessFrame extends Frame<ProcessFrame> {
+            private final NodeBitMap activeGuards;
+            private AnchoringNode anchor;
+
+            ProcessFrame(Block block, NodeBitMap activeGuards, AnchoringNode anchor, ProcessFrame parent) {
+                super(block, parent);
+                this.activeGuards = activeGuards;
+                this.anchor = anchor;
+            }
+
+            @Override
+            public void preprocess() {
+                this.anchor = Round.this.process(block, activeGuards, anchor);
+            }
+
+            @Override
+            public ProcessFrame enter(Block b) {
+                return new ProcessFrame(b, activeGuards, b.getBeginNode(), this);
+            }
+
+            @Override
+            public Frame<?> enterAlwaysReached(Block b) {
+                AnchoringNode newAnchor = anchor;
+                if (parent != null && b.getLoop() != parent.block.getLoop() && !b.isLoopHeader()) {
+                    // We are exiting a loop => cannot reuse the anchor without inserting loop
+                    // proxies.
+                    newAnchor = b.getBeginNode();
+                }
+                return new ProcessFrame(b, activeGuards, newAnchor, this);
+            }
+
+            @Override
+            public void postprocess() {
+                if (anchor != null && OptEliminateGuards.getValue()) {
+                    for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) {
+                        if (activeGuards.isMarkedAndGrow(guard)) {
+                            activeGuards.clear(guard);
+                        }
+                    }
+                }
+            }
+
+        }
+
+        @SuppressWarnings("try")
+        private AnchoringNode process(final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) {
+
+            final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode());
+
+            // Lower the instructions of this block.
+            List<Node> nodes = schedule.nodesFor(b);
+            for (Node node : nodes) {
+
+                if (node.isDeleted()) {
+                    // This case can happen when previous lowerings deleted nodes.
+                    continue;
+                }
+
+                // Cache the next node to be able to reconstruct the previous of the next node
+                // after lowering.
+                FixedNode nextNode = null;
+                if (node instanceof FixedWithNextNode) {
+                    nextNode = ((FixedWithNextNode) node).next();
+                } else {
+                    nextNode = loweringTool.lastFixedNode().next();
+                }
+
+                if (node instanceof Lowerable) {
+                    Collection<Node> unscheduledUsages = null;
+                    assert (unscheduledUsages = getUnscheduledUsages(node)) != null;
+                    Mark preLoweringMark = node.graph().getMark();
+                    try (DebugCloseable s = node.graph().withNodeSourcePosition(node)) {
+                        ((Lowerable) node).lower(loweringTool);
+                    }
+                    if (loweringTool.guardAnchor.asNode().isDeleted()) {
+                        // TODO nextNode could be deleted but this is not currently supported
+                        assert nextNode.isAlive();
+                        loweringTool.guardAnchor = AbstractBeginNode.prevBegin(nextNode);
+                    }
+                    assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages);
+                }
+
+                if (!nextNode.isAlive()) {
+                    // can happen when the rest of the block is killed by lowering
+                    // (e.g. by an unconditional deopt)
+                    break;
+                } else {
+                    Node nextLastFixed = nextNode.predecessor();
+                    if (!(nextLastFixed instanceof FixedWithNextNode)) {
+                        // insert begin node, to have a valid last fixed for next lowerable node.
+                        // This is about lowering a FixedWithNextNode to a control split while this
+                        // FixedWithNextNode is followed by some kind of BeginNode.
+                        // For example the when a FixedGuard followed by a loop exit is lowered to a
+                        // control-split + deopt.
+                        AbstractBeginNode begin = node.graph().add(new BeginNode());
+                        nextLastFixed.replaceFirstSuccessor(nextNode, begin);
+                        begin.setNext(nextNode);
+                        nextLastFixed = begin;
+                    }
+                    loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed);
+                }
+            }
+            return loweringTool.getCurrentGuardAnchor();
+        }
+
+        /**
+         * Gets all usages of a floating, lowerable node that are unscheduled.
+         * <p>
+         * Given that the lowering of such nodes may introduce fixed nodes, they must be lowered in
+         * the context of a usage that dominates all other usages. The fixed nodes resulting from
+         * lowering are attached to the fixed node context of the dominating usage. This ensures the
+         * post-lowering graph still has a valid schedule.
+         *
+         * @param node a {@link Lowerable} node
+         */
+        private Collection<Node> getUnscheduledUsages(Node node) {
+            List<Node> unscheduledUsages = new ArrayList<>();
+            if (node instanceof FloatingNode) {
+                for (Node usage : node.usages()) {
+                    if (usage instanceof ValueNode) {
+                        if (schedule.getCFG().getNodeToBlock().isNew(usage) || schedule.getCFG().blockFor(usage) == null) {
+                            unscheduledUsages.add(usage);
+                        }
+                    }
+                }
+            }
+            return unscheduledUsages;
+        }
+    }
+
+    enum ProcessBlockState {
+        ST_ENTER,
+        ST_PROCESS,
+        ST_ENTER_ALWAYS_REACHED,
+        ST_LEAVE,
+        ST_PROCESS_ALWAYS_REACHED;
+    }
+
+    /**
+     * This state-machine resembles the following recursion:
+     *
+     * <pre>
+     * void processBlock(Block block) {
+     *     preprocess();
+     *     // Process always reached block first.
+     *     Block alwaysReachedBlock = block.getPostdominator();
+     *     if (alwaysReachedBlock != null &amp;&amp; alwaysReachedBlock.getDominator() == block) {
+     *         processBlock(alwaysReachedBlock);
+     *     }
+     *
+     *     // Now go for the other dominators.
+     *     for (Block dominated : block.getDominated()) {
+     *         if (dominated != alwaysReachedBlock) {
+     *             assert dominated.getDominator() == block;
+     *             processBlock(dominated);
+     *         }
+     *     }
+     *     postprocess();
+     * }
+     * </pre>
+     *
+     * This is necessary, as the recursive implementation quickly exceed the stack depth on SPARC.
+     *
+     * @param rootFrame contains the starting block.
+     */
+    public static void processBlock(final Frame<?> rootFrame) {
+        ProcessBlockState state = ST_PROCESS;
+        Frame<?> f = rootFrame;
+        while (f != null) {
+            ProcessBlockState nextState;
+            if (state == ST_PROCESS || state == ST_PROCESS_ALWAYS_REACHED) {
+                f.preprocess();
+                nextState = state == ST_PROCESS_ALWAYS_REACHED ? ST_ENTER : ST_ENTER_ALWAYS_REACHED;
+            } else if (state == ST_ENTER_ALWAYS_REACHED) {
+                if (f.alwaysReachedBlock != null && f.alwaysReachedBlock.getDominator() == f.block) {
+                    f = f.enterAlwaysReached(f.alwaysReachedBlock);
+                    nextState = ST_PROCESS;
+                } else {
+                    nextState = ST_ENTER;
+                }
+            } else if (state == ST_ENTER) {
+                if (f.dominated.hasNext()) {
+                    Block n = f.dominated.next();
+                    if (n == f.alwaysReachedBlock) {
+                        if (f.dominated.hasNext()) {
+                            n = f.dominated.next();
+                        } else {
+                            n = null;
+                        }
+                    }
+                    if (n == null) {
+                        nextState = ST_LEAVE;
+                    } else {
+                        f = f.enter(n);
+                        assert f.block.getDominator() == f.parent.block;
+                        nextState = ST_PROCESS;
+                    }
+                } else {
+                    nextState = ST_LEAVE;
+                }
+            } else if (state == ST_LEAVE) {
+                f.postprocess();
+                f = f.parent;
+                nextState = ST_ENTER;
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+            state = nextState;
+        }
+    }
+
+    public static void processBlockBounded(final Frame<?> rootFrame) {
+        ProcessBlockState state = ST_PROCESS;
+        Frame<?> f = rootFrame;
+        while (f != null) {
+            ProcessBlockState nextState;
+            if (state == ST_PROCESS || state == ST_PROCESS_ALWAYS_REACHED) {
+                f.preprocess();
+                nextState = state == ST_PROCESS_ALWAYS_REACHED ? ST_ENTER : ST_ENTER_ALWAYS_REACHED;
+            } else if (state == ST_ENTER_ALWAYS_REACHED) {
+                if (f.alwaysReachedBlock != null && f.alwaysReachedBlock.getDominator() == f.block) {
+                    Frame<?> continueRecur = f.enterAlwaysReached(f.alwaysReachedBlock);
+                    if (continueRecur == null) {
+                        // stop recursion here
+                        f.postprocess();
+                        f = f.parent;
+                        state = ST_ENTER;
+                        continue;
+                    }
+                    f = continueRecur;
+                    nextState = ST_PROCESS;
+                } else {
+                    nextState = ST_ENTER;
+                }
+            } else if (state == ST_ENTER) {
+                if (f.dominated.hasNext()) {
+                    Block n = f.dominated.next();
+                    if (n == f.alwaysReachedBlock) {
+                        if (f.dominated.hasNext()) {
+                            n = f.dominated.next();
+                        } else {
+                            n = null;
+                        }
+                    }
+                    if (n == null) {
+                        nextState = ST_LEAVE;
+                    } else {
+                        Frame<?> continueRecur = f.enter(n);
+                        if (continueRecur == null) {
+                            // stop recursion here
+                            f.postprocess();
+                            f = f.parent;
+                            state = ST_ENTER;
+                            continue;
+                        }
+                        f = continueRecur;
+                        nextState = ST_PROCESS;
+                    }
+                } else {
+                    nextState = ST_LEAVE;
+                }
+            } else if (state == ST_LEAVE) {
+                f.postprocess();
+                f = f.parent;
+                nextState = ST_ENTER;
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+            state = nextState;
+        }
+    }
+
+    public abstract static class Frame<T extends Frame<?>> {
+        protected final Block block;
+        final T parent;
+        Iterator<Block> dominated;
+        final Block alwaysReachedBlock;
+
+        public Frame(Block block, T parent) {
+            super();
+            this.block = block;
+            this.alwaysReachedBlock = block.getPostdominator();
+            this.dominated = block.getDominated().iterator();
+            this.parent = parent;
+        }
+
+        public Frame<?> enterAlwaysReached(Block b) {
+            return enter(b);
+        }
+
+        public abstract Frame<?> enter(Block b);
+
+        public abstract void preprocess();
+
+        public abstract void postprocess();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NonNullParametersPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NonNullParametersPhase.java
new file mode 100644
index 0000000..a25a2b8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NonNullParametersPhase.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.Phase;
+
+/**
+ * Modifies the stamp of all object {@linkplain ParameterNode parameters} in a graph to denote they
+ * are non-null. This can be used for graphs where the caller null checks all arguments.
+ */
+public class NonNullParametersPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        Stamp nonNull = StampFactory.objectNonNull();
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            if (param.stamp() instanceof ObjectStamp) {
+                ObjectStamp paramStamp = (ObjectStamp) param.stamp();
+                param.setStamp(paramStamp.join(nonNull));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/OptimizeGuardAnchorsPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/OptimizeGuardAnchorsPhase.java
new file mode 100644
index 0000000..23c0044
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/OptimizeGuardAnchorsPhase.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.AnchoringNode;
+import org.graalvm.compiler.phases.Phase;
+
+public class OptimizeGuardAnchorsPhase extends Phase {
+    private static final DebugCounter counterGuardsAnchorOptimized = Debug.counter("GuardsAnchorOptimized");
+    private static final DebugCounter counterGuardsOptimizedAtSplit = Debug.counter("GuardsOptimizedAtSplit");
+
+    public static class LazyCFG extends LazyValue<ControlFlowGraph> {
+        public LazyCFG(StructuredGraph graph) {
+            super(() -> ControlFlowGraph.compute(graph, true, false, true, true));
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (!graph.getGuardsStage().allowsFloatingGuards()) {
+            return;
+        }
+        LazyCFG cfg = new LazyCFG(graph);
+        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
+            if (!(begin instanceof StartNode || begin.predecessor() instanceof ControlSplitNode)) {
+                NodeIterable<GuardNode> guards = begin.guards();
+                if (guards.isNotEmpty()) {
+                    AbstractBeginNode newAnchor = computeOptimalAnchor(cfg.get(), begin);
+                    // newAnchor == begin is possible because postdominator computation assumes that
+                    // loops never end
+                    if (newAnchor != begin) {
+                        for (GuardNode guard : guards.snapshot()) {
+                            guard.setAnchor(newAnchor);
+                        }
+                        counterGuardsAnchorOptimized.increment();
+                    }
+                }
+            }
+        }
+        for (ControlSplitNode controlSplit : graph.getNodes(ControlSplitNode.TYPE)) {
+            optimizeAtControlSplit(controlSplit, cfg);
+        }
+    }
+
+    public static AbstractBeginNode getOptimalAnchor(LazyCFG cfg, AbstractBeginNode begin) {
+        if (begin instanceof StartNode || begin.predecessor() instanceof ControlSplitNode) {
+            return begin;
+        }
+        return computeOptimalAnchor(cfg.get(), begin);
+    }
+
+    private static AbstractBeginNode computeOptimalAnchor(ControlFlowGraph cfg, AbstractBeginNode begin) {
+        Block anchor = cfg.blockFor(begin);
+        while (anchor.getDominator() != null && anchor.getDominator().getPostdominator() == anchor) {
+            anchor = anchor.getDominator();
+        }
+        return anchor.getBeginNode();
+    }
+
+    private static void optimizeAtControlSplit(ControlSplitNode controlSplit, LazyCFG cfg) {
+        AbstractBeginNode successor = findMinimumUsagesSuccessor(controlSplit);
+        int successorCount = controlSplit.successors().count();
+        for (GuardNode guard : successor.guards().snapshot()) {
+            if (guard.isDeleted() || guard.getCondition().getUsageCount() < successorCount) {
+                continue;
+            }
+            List<GuardNode> otherGuards = new ArrayList<>(successorCount - 1);
+            HashSet<Node> successorsWithoutGuards = new HashSet<>(controlSplit.successors().count());
+            controlSplit.successors().snapshotTo(successorsWithoutGuards);
+            successorsWithoutGuards.remove(guard.getAnchor());
+            for (GuardNode conditonGuard : guard.getCondition().usages().filter(GuardNode.class)) {
+                if (conditonGuard != guard) {
+                    AnchoringNode conditionGuardAnchor = conditonGuard.getAnchor();
+                    if (conditionGuardAnchor.asNode().predecessor() == controlSplit && compatibleGuards(guard, conditonGuard)) {
+                        otherGuards.add(conditonGuard);
+                        successorsWithoutGuards.remove(conditionGuardAnchor);
+                    }
+                }
+            }
+
+            if (successorsWithoutGuards.isEmpty()) {
+                assert otherGuards.size() >= successorCount - 1;
+                AbstractBeginNode anchor = computeOptimalAnchor(cfg.get(), AbstractBeginNode.prevBegin(controlSplit));
+                GuardNode newGuard = controlSplit.graph().unique(new GuardNode(guard.getCondition(), anchor, guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation()));
+                for (GuardNode otherGuard : otherGuards) {
+                    otherGuard.replaceAndDelete(newGuard);
+                }
+                guard.replaceAndDelete(newGuard);
+                counterGuardsOptimizedAtSplit.increment();
+            }
+            otherGuards.clear();
+        }
+    }
+
+    private static boolean compatibleGuards(GuardNode guard, GuardNode conditonGuard) {
+        return conditonGuard.isNegated() == guard.isNegated() && conditonGuard.getAction() == guard.getAction() && conditonGuard.getReason() == guard.getReason() &&
+                        conditonGuard.getSpeculation().equals(guard.getSpeculation());
+    }
+
+    private static AbstractBeginNode findMinimumUsagesSuccessor(ControlSplitNode controlSplit) {
+        Iterator<Node> successors = controlSplit.successors().iterator();
+        AbstractBeginNode min = (AbstractBeginNode) successors.next();
+        int minUsages = min.getUsageCount();
+        while (successors.hasNext()) {
+            AbstractBeginNode successor = (AbstractBeginNode) successors.next();
+            int count = successor.getUsageCount();
+            if (count < minUsages) {
+                minUsages = count;
+                min = successor;
+            }
+        }
+        return min;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java
new file mode 100644
index 0000000..1f3606e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.ConvertNode;
+import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.NotNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.nodes.calc.RemNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
+import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.java.AccessMonitorNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.memory.Access;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+/**
+ * This phase add counters for the dynamically executed number of nodes. Incrementing the counter
+ * for each node would be too costly, so this phase takes the compromise that it trusts split
+ * probabilities, but not loop frequencies. This means that it will insert counters at the start of
+ * a method and at each loop header.
+ *
+ * A schedule is created so that floating nodes can also be taken into account. The weight of a node
+ * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(Node)}
+ * method.
+ *
+ * Additionally, there's a second counter that's only increased for code sections without invokes.
+ */
+public class ProfileCompiledMethodsPhase extends Phase {
+
+    private static final String GROUP_NAME = "~profiled weight";
+    private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+    private static final String GROUP_NAME_INVOKES = "~profiled invokes";
+
+    private static final boolean WITH_SECTION_HEADER = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_SECTION_HEADER", "false"));
+    private static final boolean WITH_INVOKE_FREE_SECTIONS = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_FREE_SECTIONS", "false"));
+    private static final boolean WITH_INVOKES = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_INVOKES", "true"));
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        SchedulePhase schedule = new SchedulePhase();
+        schedule.apply(graph, false);
+
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+        for (Loop<Block> loop : cfg.getLoops()) {
+            double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).probability();
+            if (loopProbability > (1D / Integer.MAX_VALUE)) {
+                addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), graph.getLastSchedule(), cfg);
+            }
+        }
+        // don't put the counter increase directly after the start (problems with OSR)
+        FixedWithNextNode current = graph.start();
+        while (current.next() instanceof FixedWithNextNode) {
+            current = (FixedWithNextNode) current.next();
+        }
+        addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), graph.getLastSchedule(), cfg);
+
+        if (WITH_INVOKES) {
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Invoke) {
+                    Invoke invoke = (Invoke) node;
+                    DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode());
+
+                }
+            }
+        }
+    }
+
+    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, ScheduleResult schedule, ControlFlowGraph cfg) {
+        HashSet<Block> blocks = new HashSet<>(sectionBlocks);
+        for (Loop<?> loop : childLoops) {
+            blocks.removeAll(loop.getBlocks());
+        }
+        double weight = getSectionWeight(schedule, blocks) / cfg.blockFor(start).probability();
+        DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
+        if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
+            DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
+        }
+    }
+
+    private static String sectionHead(Node node) {
+        if (WITH_SECTION_HEADER) {
+            return node.toString();
+        } else {
+            return "";
+        }
+    }
+
+    private static double getSectionWeight(ScheduleResult schedule, Collection<Block> blocks) {
+        double count = 0;
+        for (Block block : blocks) {
+            double blockProbability = block.probability();
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+                count += blockProbability * getNodeWeight(node);
+            }
+        }
+        return count;
+    }
+
+    private static double getNodeWeight(Node node) {
+        if (node instanceof AbstractMergeNode) {
+            return ((AbstractMergeNode) node).phiPredecessorCount();
+        } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode ||
+                        node instanceof CallTargetNode || node instanceof ValueProxy || node instanceof VirtualObjectNode || node instanceof ReinterpretNode) {
+            return 0;
+        } else if (node instanceof AccessMonitorNode) {
+            return 10;
+        } else if (node instanceof Access) {
+            return 2;
+        } else if (node instanceof LogicNode || node instanceof ConvertNode || node instanceof BinaryNode || node instanceof NotNode) {
+            return 1;
+        } else if (node instanceof IntegerDivRemNode || node instanceof DivNode || node instanceof RemNode) {
+            return 10;
+        } else if (node instanceof MulNode) {
+            return 3;
+        } else if (node instanceof Invoke) {
+            return 5;
+        } else if (node instanceof IfNode || node instanceof SafepointNode) {
+            return 1;
+        } else if (node instanceof SwitchNode) {
+            return node.successors().count();
+        } else if (node instanceof ReturnNode || node instanceof UnwindNode || node instanceof DeoptimizeNode) {
+            return node.successors().count();
+        } else if (node instanceof AbstractNewObjectNode) {
+            return 10;
+        } else if (node instanceof VirtualState) {
+            return 0;
+        }
+        return 2;
+    }
+
+    private static boolean hasInvoke(Collection<Block> blocks) {
+        boolean hasInvoke = false;
+        for (Block block : blocks) {
+            for (FixedNode fixed : block.getNodes()) {
+                if (fixed instanceof Invoke) {
+                    hasInvoke = true;
+                }
+            }
+        }
+        return hasInvoke;
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PushThroughPiPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PushThroughPiPhase.java
new file mode 100644
index 0000000..40d0a39
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PushThroughPiPhase.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.PiPushable;
+import org.graalvm.compiler.phases.Phase;
+
+public class PushThroughPiPhase extends Phase {
+
+    public static final DebugCounter PUSHED_NODES = Debug.counter("NodesPushedThroughPi");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (PiNode pi : graph.getNodes(PiNode.TYPE)) {
+            for (Node n : pi.usages().snapshot()) {
+                if (n instanceof PiPushable) {
+                    PiPushable pip = (PiPushable) n;
+                    if (pip.push(pi)) {
+                        PUSHED_NODES.add(1);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/RemoveValueProxyPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/RemoveValueProxyPhase.java
new file mode 100644
index 0000000..61c4eba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/RemoveValueProxyPhase.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+
+public class RemoveValueProxyPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ProxyNode vpn : graph.getNodes(ProxyNode.TYPE)) {
+            vpn.replaceAtUsagesAndDelete(vpn.value());
+        }
+        for (LoopExitNode exit : graph.getNodes(LoopExitNode.TYPE)) {
+            FrameState stateAfter = exit.stateAfter();
+            if (stateAfter != null) {
+                exit.setStateAfter(null);
+                if (stateAfter.hasNoUsages()) {
+                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                }
+            }
+        }
+        graph.setHasValueProxies(false);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java
new file mode 100644
index 0000000..3e3be72
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.DynamicDeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.extended.NullCheckNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class UseTrappingNullChecksPhase extends BasePhase<LowTierContext> {
+
+    private static final DebugCounter counterTrappingNullCheck = Debug.counter("TrappingNullCheck");
+    private static final DebugCounter counterTrappingNullCheckUnreached = Debug.counter("TrappingNullCheckUnreached");
+    private static final DebugCounter counterTrappingNullCheckDynamicDeoptimize = Debug.counter("TrappingNullCheckDynamicDeoptimize");
+
+    @Override
+    protected void run(StructuredGraph graph, LowTierContext context) {
+        if (context.getTarget().implicitNullCheckLimit <= 0) {
+            return;
+        }
+        assert graph.getGuardsStage().areFrameStatesAtDeopts();
+
+        for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.TYPE)) {
+            tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation());
+        }
+        for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.TYPE)) {
+            tryUseTrappingNullCheck(context.getMetaAccess(), deopt);
+        }
+    }
+
+    private static void tryUseTrappingNullCheck(MetaAccessProvider metaAccessProvider, DynamicDeoptimizeNode deopt) {
+        Node predecessor = deopt.predecessor();
+        if (predecessor instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) predecessor;
+
+            // Process each predecessor at the merge, unpacking the reasons and speculations as
+            // needed.
+            ValueNode reason = deopt.getActionAndReason();
+            ValuePhiNode reasonPhi = null;
+            List<ValueNode> reasons = null;
+            int expectedPhis = 0;
+
+            if (reason instanceof ValuePhiNode) {
+                reasonPhi = (ValuePhiNode) reason;
+                if (reasonPhi.merge() != merge) {
+                    return;
+                }
+                reasons = reasonPhi.values().snapshot();
+                expectedPhis++;
+            } else if (!reason.isConstant()) {
+                return;
+            }
+
+            ValueNode speculation = deopt.getSpeculation();
+            ValuePhiNode speculationPhi = null;
+            List<ValueNode> speculations = null;
+            if (speculation instanceof ValuePhiNode) {
+                speculationPhi = (ValuePhiNode) speculation;
+                if (speculationPhi.merge() != merge) {
+                    return;
+                }
+                speculations = speculationPhi.values().snapshot();
+                expectedPhis++;
+            }
+
+            if (merge.phis().count() != expectedPhis) {
+                return;
+            }
+
+            int index = 0;
+            for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+                ValueNode thisReason = reasons != null ? reasons.get(index) : reason;
+                ValueNode thisSpeculation = speculations != null ? speculations.get(index++) : speculation;
+                if (!thisReason.isConstant() || !thisSpeculation.isConstant() || !thisSpeculation.asConstant().equals(JavaConstant.NULL_POINTER)) {
+                    continue;
+                }
+                DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asJavaConstant());
+                tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, null);
+            }
+        }
+    }
+
+    private static void tryUseTrappingNullCheck(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, JavaConstant speculation) {
+        if (deoptimizationReason != DeoptimizationReason.NullCheckException && deoptimizationReason != DeoptimizationReason.UnreachedCode) {
+            return;
+        }
+        if (speculation != null && !speculation.equals(JavaConstant.NULL_POINTER)) {
+            return;
+        }
+        if (predecessor instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) predecessor;
+            if (merge.phis().isEmpty()) {
+                for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+                    checkPredecessor(deopt, end.predecessor(), deoptimizationReason);
+                }
+            }
+        } else if (predecessor instanceof AbstractBeginNode) {
+            checkPredecessor(deopt, predecessor, deoptimizationReason);
+        }
+    }
+
+    private static void checkPredecessor(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason) {
+        Node current = predecessor;
+        AbstractBeginNode branch = null;
+        while (current instanceof AbstractBeginNode) {
+            branch = (AbstractBeginNode) current;
+            if (branch.anchored().isNotEmpty()) {
+                // some input of the deopt framestate is anchored to this branch
+                return;
+            }
+            current = current.predecessor();
+        }
+        if (current instanceof IfNode) {
+            IfNode ifNode = (IfNode) current;
+            if (branch != ifNode.trueSuccessor()) {
+                return;
+            }
+            LogicNode condition = ifNode.condition();
+            if (condition instanceof IsNullNode) {
+                replaceWithTrappingNullCheck(deopt, ifNode, condition, deoptimizationReason);
+            }
+        }
+    }
+
+    private static void replaceWithTrappingNullCheck(AbstractDeoptimizeNode deopt, IfNode ifNode, LogicNode condition, DeoptimizationReason deoptimizationReason) {
+        counterTrappingNullCheck.increment();
+        if (deopt instanceof DynamicDeoptimizeNode) {
+            counterTrappingNullCheckDynamicDeoptimize.increment();
+        }
+        if (deoptimizationReason == DeoptimizationReason.UnreachedCode) {
+            counterTrappingNullCheckUnreached.increment();
+        }
+        IsNullNode isNullNode = (IsNullNode) condition;
+        AbstractBeginNode nonTrappingContinuation = ifNode.falseSuccessor();
+        AbstractBeginNode trappingContinuation = ifNode.trueSuccessor();
+        NullCheckNode trappingNullCheck = deopt.graph().add(new NullCheckNode(isNullNode.getValue()));
+        trappingNullCheck.setStateBefore(deopt.stateBefore());
+        deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
+
+        /*
+         * We now have the pattern NullCheck/BeginNode/... It's possible some node is using the
+         * BeginNode as a guard input, so replace guard users of the Begin with the NullCheck and
+         * then remove the Begin from the graph.
+         */
+        nonTrappingContinuation.replaceAtUsages(InputType.Guard, trappingNullCheck);
+        if (nonTrappingContinuation instanceof BeginNode) {
+            FixedNode next = nonTrappingContinuation.next();
+            nonTrappingContinuation.clearSuccessors();
+            trappingNullCheck.setNext(next);
+            nonTrappingContinuation.safeDelete();
+        } else {
+            trappingNullCheck.setNext(nonTrappingContinuation);
+        }
+
+        GraphUtil.killCFG(trappingContinuation);
+        GraphUtil.tryKillUnused(isNullNode);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ValueAnchorCleanupPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ValueAnchorCleanupPhase.java
new file mode 100644
index 0000000..255208e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ValueAnchorCleanupPhase.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.phases.Phase;
+import org.graalvm.compiler.phases.graph.MergeableState;
+import org.graalvm.compiler.phases.graph.SinglePassNodeIterator;
+
+/**
+ * This phase performs a bit of hygiene on {@link ValueAnchorNode} by removing inputs that have
+ * already been anchored in a dominating value anchor. Value anchors that lose their last input,
+ * have no usages and are not marked as permanent are removed.
+ */
+public class ValueAnchorCleanupPhase extends Phase {
+
+    private static class State extends MergeableState<State> implements Cloneable {
+
+        private final Set<Node> anchoredValues;
+
+        State() {
+            anchoredValues = Node.newSet();
+        }
+
+        State(State other) {
+            anchoredValues = Node.newSet(other.anchoredValues);
+        }
+
+        @Override
+        public boolean merge(AbstractMergeNode merge, List<State> withStates) {
+            for (State other : withStates) {
+                anchoredValues.retainAll(other.anchoredValues);
+            }
+            return true;
+        }
+
+        @Override
+        public State clone() {
+            return new State(this);
+        }
+    }
+
+    private static class CleanupValueAnchorsClosure extends SinglePassNodeIterator<State> {
+
+        CleanupValueAnchorsClosure(StartNode start) {
+            super(start, new State());
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof ValueAnchorNode) {
+                ValueAnchorNode anchor = (ValueAnchorNode) node;
+                ValueNode anchored = anchor.getAnchoredNode();
+                if (anchored != null) {
+                    if (state.anchoredValues.contains(anchored)) {
+                        anchor.removeAnchoredNode();
+                    } else {
+                        state.anchoredValues.add(anchored);
+                    }
+                }
+                if (anchor.getAnchoredNode() == null && anchor.hasNoUsages()) {
+                    node.graph().removeFixed(anchor);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        CleanupValueAnchorsClosure closure = new CleanupValueAnchorsClosure(graph.start());
+        closure.apply();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/VerifyHeapAtReturnPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/VerifyHeapAtReturnPhase.java
new file mode 100644
index 0000000..e7b0957
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/VerifyHeapAtReturnPhase.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
+import org.graalvm.compiler.phases.Phase;
+
+public class VerifyHeapAtReturnPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
+            VerifyHeapNode.addBefore(returnNode);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningPhase.java
new file mode 100644
index 0000000..7007752
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningPhase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining;
+
+import java.util.Map;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
+import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy;
+import org.graalvm.compiler.phases.common.inlining.walker.InliningData;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+public class InliningPhase extends AbstractInliningPhase {
+
+    public static class Options {
+
+        @Option(help = "Unconditionally inline intrinsics", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> AlwaysInlineIntrinsics = new OptionValue<>(false);
+
+        /**
+         * This is a defensive measure against known pathologies of the inliner where the breadth of
+         * the inlining call tree exploration can be wide enough to prevent inlining from completing
+         * in reasonable time.
+         */
+        @Option(help = "Per-compilation method inlining exploration limit before giving up (use 0 to disable)", type = OptionType.Debug)//
+        public static final OptionValue<Integer> MethodInlineBailoutLimit = new OptionValue<>(5000);
+    }
+
+    private final InliningPolicy inliningPolicy;
+    private final CanonicalizerPhase canonicalizer;
+
+    private int maxMethodPerInlining = Integer.MAX_VALUE;
+
+    public InliningPhase(CanonicalizerPhase canonicalizer) {
+        this(new GreedyInliningPolicy(null), canonicalizer);
+    }
+
+    public InliningPhase(Map<Invoke, Double> hints, CanonicalizerPhase canonicalizer) {
+        this(new GreedyInliningPolicy(hints), canonicalizer);
+    }
+
+    public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
+        this.inliningPolicy = policy;
+        this.canonicalizer = canonicalizer;
+    }
+
+    public CanonicalizerPhase getCanonicalizer() {
+        return canonicalizer;
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 10_000f;
+    }
+
+    public void setMaxMethodsPerInlining(int max) {
+        maxMethodPerInlining = max;
+    }
+
+    /**
+     *
+     * This method sets in motion the inlining machinery.
+     *
+     * @see InliningData
+     * @see InliningData#moveForward()
+     *
+     */
+    @Override
+    protected void run(final StructuredGraph graph, final HighTierContext context) {
+        final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy);
+
+        int count = 0;
+        assert data.repOK();
+        int limit = Options.MethodInlineBailoutLimit.getValue();
+        while (data.hasUnprocessedGraphs()) {
+            boolean wasInlined = data.moveForward();
+            assert data.repOK();
+            count++;
+            if (!wasInlined) {
+                if (limit > 0 && count == limit) {
+                    // Limit the amount of exploration which is done
+                    break;
+                }
+            }
+        }
+
+        assert data.inliningDepth() == 0 || count == limit;
+        assert data.graphCount() == 0 || count == limit;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java
new file mode 100644
index 0000000..2c8b96d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining;
+
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo;
+import org.graalvm.compiler.graph.GraalGraphError;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.GuardedValueNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.KillingBeginNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.MonitorExitNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class InliningUtil {
+
+    private static final String inliningDecisionsScopeString = "InliningDecisions";
+
+    /**
+     * Print a HotSpot-style inlining message to the console.
+     */
+    private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+        printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
+    }
+
+    private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+        Util.printInlining(method, invoke.bci(), inliningDepth, success, msg, args);
+    }
+
+    public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
+        logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
+    }
+
+    public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
+        logInliningDecision(info, inliningDepth, true, false, msg, args);
+    }
+
+    public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+        if (allowLogging) {
+            printInlining(info, inliningDepth, success, msg, args);
+            if (shouldLogInliningDecision()) {
+                logInliningDecision(methodName(info), success, msg, args);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    public static void logInliningDecision(final String msg, final Object... args) {
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            // Can't use log here since we are varargs
+            if (Debug.isLogEnabled()) {
+                Debug.logv(msg, args);
+            }
+        }
+    }
+
+    public static void logNotInlinedMethod(Invoke invoke, String msg) {
+        if (shouldLogInliningDecision()) {
+            String methodString = invoke.toString();
+            if (invoke.callTarget() == null) {
+                methodString += " callTarget=null";
+            } else {
+                String targetName = invoke.callTarget().targetName();
+                if (!methodString.endsWith(targetName)) {
+                    methodString += " " + targetName;
+                }
+            }
+            logInliningDecision(methodString, false, msg, new Object[0]);
+        }
+    }
+
+    public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
+        logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]);
+    }
+
+    public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
+        printInlining(method, invoke, inliningDepth, false, msg, args);
+        if (shouldLogInliningDecision()) {
+            String methodString = methodName(method, invoke);
+            logInliningDecision(methodString, false, msg, args);
+        }
+    }
+
+    private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
+        String inliningMsg = "inlining " + methodString + ": " + msg;
+        if (!success) {
+            inliningMsg = "not " + inliningMsg;
+        }
+        logInliningDecision(inliningMsg, args);
+    }
+
+    @SuppressWarnings("try")
+    public static boolean shouldLogInliningDecision() {
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            return Debug.isLogEnabled();
+        }
+    }
+
+    private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
+        if (invoke != null && invoke.stateAfter() != null) {
+            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
+        } else {
+            return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
+        }
+    }
+
+    private static String methodName(InlineInfo info) {
+        if (info == null) {
+            return "null";
+        } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
+            return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
+        } else {
+            return info.toString();
+        }
+    }
+
+    private static String methodName(FrameState frameState, int bci) {
+        StringBuilder sb = new StringBuilder();
+        if (frameState.outerFrameState() != null) {
+            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
+            sb.append("->");
+        }
+        sb.append(frameState.getMethod().format("%h.%n"));
+        sb.append("@").append(bci);
+        return sb.toString();
+    }
+
+    public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
+        MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
+        MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnStamp(),
+                        oldCallTarget.getProfile()));
+        invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
+    }
+
+    public static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+        return createAnchoredReceiver(graph, anchor, receiver,
+                        exact ? StampFactory.objectNonNull(TypeReference.createExactTrusted(commonType)) : StampFactory.objectNonNull(TypeReference.createTrusted(graph.getAssumptions(), commonType)));
+    }
+
+    private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) {
+        // to avoid that floating reads on receiver fields float above the type check
+        return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
+    }
+
+    /**
+     * @return null iff the check succeeds, otherwise a (non-null) descriptive message.
+     */
+    public static String checkInvokeConditions(Invoke invoke) {
+        if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
+            return "the invoke is dead code";
+        }
+        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+            return "the invoke has already been lowered, or has been created as a low-level node";
+        }
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (callTarget.targetMethod() == null) {
+            return "target method is null";
+        }
+        assert invoke.stateAfter() != null : invoke;
+        if (!invoke.useForInlining()) {
+            return "the invoke is marked to be not used for inlining";
+        }
+        ValueNode receiver = callTarget.receiver();
+        if (receiver != null && receiver.isConstant() && receiver.isNullConstant()) {
+            return "receiver is null";
+        }
+        return null;
+    }
+
+    /**
+     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     *
+     * @param invoke the invoke that will be replaced
+     * @param inlineGraph the graph that the invoke will be replaced with
+     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
+     *            false if no such check is required
+     * @param canonicalizedNodes if non-null then append to this list any nodes which should be
+     *            canonicalized after inlining
+     * @param inlineeMethod the actual method being inlined. Maybe be null for snippets.
+     */
+    @SuppressWarnings("try")
+    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, List<Node> canonicalizedNodes, ResolvedJavaMethod inlineeMethod) {
+        MethodMetricsInlineeScopeInfo m = MethodMetricsInlineeScopeInfo.create();
+        try (Debug.Scope s = Debug.methodMetricsScope("InlineEnhancement", m, false)) {
+            FixedNode invokeNode = invoke.asNode();
+            StructuredGraph graph = invokeNode.graph();
+            if (Fingerprint.ENABLED) {
+                Fingerprint.submit("inlining %s into %s: %s", formatGraph(inlineGraph), formatGraph(invoke.asNode().graph()), inlineGraph.getNodes().snapshot());
+            }
+            final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
+
+            assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
+            assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
+
+            if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
+                nonNullReceiver(invoke);
+            }
+
+            ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
+            ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
+            UnwindNode unwindNode = null;
+            final StartNode entryPointNode = inlineGraph.start();
+            FixedNode firstCFGNode = entryPointNode.next();
+            if (firstCFGNode == null) {
+                throw new IllegalStateException("Inlined graph is in invalid state: " + inlineGraph);
+            }
+            for (Node node : inlineGraph.getNodes()) {
+                if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.usages().count() == 1) || node instanceof ParameterNode) {
+                    // Do nothing.
+                } else {
+                    nodes.add(node);
+                    if (node instanceof ReturnNode) {
+                        returnNodes.add((ReturnNode) node);
+                    } else if (node instanceof UnwindNode) {
+                        assert unwindNode == null;
+                        unwindNode = (UnwindNode) node;
+                    }
+                }
+            }
+
+            final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invokeNode);
+            DuplicationReplacement localReplacement = new DuplicationReplacement() {
+
+                @Override
+                public Node replacement(Node node) {
+                    if (node instanceof ParameterNode) {
+                        return parameters.get(((ParameterNode) node).index());
+                    } else if (node == entryPointNode) {
+                        return prevBegin;
+                    }
+                    return node;
+                }
+            };
+
+            assert invokeNode.successors().first() != null : invoke;
+            assert invokeNode.predecessor() != null;
+
+            Map<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+
+            FrameState stateAfter = invoke.stateAfter();
+            assert stateAfter == null || stateAfter.isAlive();
+
+            FrameState stateAtExceptionEdge = null;
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+                if (unwindNode != null) {
+                    ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+                    stateAtExceptionEdge = obj.stateAfter();
+                }
+            }
+
+            updateSourcePositions(invoke, inlineGraph, duplicates);
+            if (stateAfter != null) {
+                processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
+                int callerLockDepth = stateAfter.nestedLockDepth();
+                if (callerLockDepth != 0) {
+                    for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) {
+                        MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
+                        processMonitorId(invoke.stateAfter(), monitor);
+                    }
+                }
+            } else {
+                assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
+            }
+
+            firstCFGNode = (FixedNode) duplicates.get(firstCFGNode);
+            for (int i = 0; i < returnNodes.size(); i++) {
+                returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i)));
+            }
+            if (unwindNode != null) {
+                unwindNode = (UnwindNode) duplicates.get(unwindNode);
+            }
+
+            if (UseGraalInstrumentation.getValue()) {
+                detachInstrumentation(invoke);
+            }
+            ValueNode returnValue = finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes);
+            if (canonicalizedNodes != null) {
+                if (returnValue != null) {
+                    for (Node usage : returnValue.usages()) {
+                        canonicalizedNodes.add(usage);
+                    }
+                }
+                for (ParameterNode parameter : inlineGraph.getNodes(ParameterNode.TYPE)) {
+                    for (Node usage : parameter.usages()) {
+                        Node duplicate = duplicates.get(usage);
+                        if (duplicate != null && duplicate.isAlive()) {
+                            canonicalizedNodes.add(duplicate);
+                        }
+                    }
+                }
+            }
+
+            GraphUtil.killCFG(invokeNode);
+
+            if (Debug.isMethodMeterEnabled() && m != null) {
+                MethodMetricsImpl.recordInlinee(m.getRootMethod(), invoke.asNode().graph().method(), inlineeMethod);
+            }
+            return duplicates;
+        }
+    }
+
+    public static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions,
+                    StructuredGraph inlineGraph, List<Node> canonicalizedNodes) {
+        FixedNode invokeNode = invoke.asNode();
+        FrameState stateAfter = invoke.stateAfter();
+        assert stateAfter == null || stateAfter.isAlive();
+
+        invokeNode.replaceAtPredecessor(firstNode);
+
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+            if (unwindNode != null && unwindNode.isAlive()) {
+                assert unwindNode.predecessor() != null;
+                assert invokeWithException.exceptionEdge().successors().count() == 1;
+                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+                obj.replaceAtUsages(unwindNode.exception());
+                Node n = obj.next();
+                obj.setNext(null);
+                unwindNode.replaceAndDelete(n);
+
+                obj.replaceAtPredecessor(null);
+                obj.safeDelete();
+            } else {
+                invokeWithException.killExceptionEdge();
+            }
+
+            // get rid of memory kill
+            AbstractBeginNode begin = invokeWithException.next();
+            if (begin instanceof KillingBeginNode) {
+                AbstractBeginNode newBegin = new BeginNode();
+                graph.addAfterFixed(begin, graph.add(newBegin));
+                begin.replaceAtUsages(newBegin);
+                graph.removeFixed(begin);
+            }
+        } else {
+            if (unwindNode != null && unwindNode.isAlive()) {
+                DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                unwindNode.replaceAndDelete(deoptimizeNode);
+            }
+        }
+
+        ValueNode returnValue;
+        if (!returnNodes.isEmpty()) {
+            FixedNode n = invoke.next();
+            invoke.setNext(null);
+            if (returnNodes.size() == 1) {
+                ReturnNode returnNode = returnNodes.get(0);
+                returnValue = returnNode.result();
+                invokeNode.replaceAtUsages(returnValue);
+                returnNode.replaceAndDelete(n);
+            } else {
+                AbstractMergeNode merge = graph.add(new MergeNode());
+                merge.setStateAfter(stateAfter);
+                returnValue = mergeReturns(merge, returnNodes, canonicalizedNodes);
+                invokeNode.replaceAtUsages(returnValue);
+                merge.setNext(n);
+            }
+        } else {
+            returnValue = null;
+            invokeNode.replaceAtUsages(null);
+            GraphUtil.killCFG(invoke.next());
+        }
+
+        // Copy assumptions from inlinee to caller
+        Assumptions assumptions = graph.getAssumptions();
+        if (assumptions != null) {
+            if (inlinedAssumptions != null) {
+                assumptions.record(inlinedAssumptions);
+            }
+        } else {
+            assert inlinedAssumptions == null : "cannot inline graph which makes assumptions into a graph that doesn't";
+        }
+
+        // Copy inlined methods from inlinee to caller
+        graph.updateMethods(inlineGraph);
+
+        // Update the set of accessed fields
+        graph.updateFields(inlineGraph);
+
+        if (inlineGraph.hasUnsafeAccess()) {
+            graph.markUnsafeAccess();
+        }
+        assert inlineGraph.getSpeculationLog() == null : "Only the root graph should have a speculation log";
+
+        return returnValue;
+    }
+
+    private static String formatGraph(StructuredGraph graph) {
+        if (graph.method() == null) {
+            return graph.name;
+        }
+        return graph.method().format("%H.%n(%p)");
+    }
+
+    @SuppressWarnings("try")
+    private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates) {
+        if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) {
+            if (invoke.asNode().getNodeSourcePosition() == null) {
+                // Temporarily ignore the assert below.
+                return;
+            }
+
+            JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() ? invoke.getReceiver().asJavaConstant() : null;
+            NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition();
+            assert invokePos != null : "missing source information";
+
+            Map<NodeSourcePosition, NodeSourcePosition> posMap = new HashMap<>();
+            for (Entry<Node, Node> entry : duplicates.entrySet()) {
+                NodeSourcePosition pos = entry.getKey().getNodeSourcePosition();
+                if (pos != null) {
+                    NodeSourcePosition callerPos = pos.addCaller(constantReceiver, invokePos);
+                    posMap.putIfAbsent(callerPos, callerPos);
+                    entry.getValue().setNodeSourcePosition(posMap.get(callerPos));
+                }
+            }
+        }
+    }
+
+    public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) {
+        if (stateAfter != null) {
+            int callerLockDepth = stateAfter.nestedLockDepth();
+            monitorIdNode.setLockDepth(monitorIdNode.getLockDepth() + callerLockDepth);
+        }
+    }
+
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge, boolean alwaysDuplicateStateAfter) {
+        FrameState stateAtReturn = invoke.stateAfter();
+        FrameState outerFrameState = null;
+        JavaKind invokeReturnKind = invoke.asNode().getStackKind();
+        for (FrameState original : inlineGraph.getNodes(FrameState.TYPE)) {
+            FrameState frameState = (FrameState) duplicates.get(original);
+            if (frameState != null && frameState.isAlive()) {
+                if (outerFrameState == null) {
+                    outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind);
+                }
+                processFrameState(frameState, invoke, inlineGraph.method(), stateAtExceptionEdge, outerFrameState, alwaysDuplicateStateAfter, invoke.callTarget().targetMethod(),
+                                invoke.callTarget().arguments());
+            }
+        }
+    }
+
+    public static FrameState processFrameState(FrameState frameState, Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState stateAtExceptionEdge, FrameState outerFrameState,
+                    boolean alwaysDuplicateStateAfter, ResolvedJavaMethod invokeTargetMethod, List<ValueNode> invokeArgsList) {
+
+        assert outerFrameState == null || !outerFrameState.isDeleted() : outerFrameState;
+        FrameState stateAtReturn = invoke.stateAfter();
+        JavaKind invokeReturnKind = invoke.asNode().getStackKind();
+
+        if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+            FrameState stateAfterReturn = stateAtReturn;
+            if (frameState.getCode() == null) {
+                // This is a frame state for a side effect within an intrinsic
+                // that was parsed for post-parse intrinsification
+                for (Node usage : frameState.usages()) {
+                    if (usage instanceof ForeignCallNode) {
+                        // A foreign call inside an intrinsic needs to have
+                        // the BCI of the invoke being intrinsified
+                        ForeignCallNode foreign = (ForeignCallNode) usage;
+                        foreign.setBci(invoke.bci());
+                    }
+                }
+            }
+
+            // pop return kind from invoke's stateAfter and replace with this frameState's return
+            // value (top of stack)
+            if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
+                stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, invokeReturnKind, frameState.stackAt(0));
+            }
+
+            // Return value does no longer need to be limited by the monitor exit.
+            for (MonitorExitNode n : frameState.usages().filter(MonitorExitNode.class)) {
+                n.clearEscapedReturnValue();
+            }
+
+            frameState.replaceAndDelete(stateAfterReturn);
+            return stateAfterReturn;
+        } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+            // pop exception object from invoke's stateAfter and replace with this frameState's
+            // exception object (top of stack)
+            FrameState stateAfterException = stateAtExceptionEdge;
+            if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+                stateAfterException = stateAtExceptionEdge.duplicateModified(JavaKind.Object, JavaKind.Object, frameState.stackAt(0));
+            }
+            frameState.replaceAndDelete(stateAfterException);
+            return stateAfterException;
+        } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+            return handleMissingAfterExceptionFrameState(frameState);
+        } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
+            // This is an intrinsic. Deoptimizing within an intrinsic
+            // must re-execute the intrinsified invocation
+            assert frameState.outerFrameState() == null;
+            ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]);
+            FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeTargetMethod.getSignature().toParameterKinds(!invokeTargetMethod.isStatic()),
+                            invokeArgs);
+            frameState.replaceAndDelete(stateBeforeCall);
+            return stateBeforeCall;
+        } else {
+            // only handle the outermost frame states
+            if (frameState.outerFrameState() == null) {
+                assert checkInlineeFrameState(invoke, inlinedMethod, frameState);
+                frameState.setOuterFrameState(outerFrameState);
+            }
+            return frameState;
+        }
+    }
+
+    static boolean checkInlineeFrameState(Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState frameState) {
+        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
+        if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            ResolvedJavaMethod method = frameState.getMethod();
+            if (method.equals(inlinedMethod)) {
+                // Normal inlining expects all outermost inlinee frame states to
+                // denote the inlinee method
+            } else if (method.equals(invoke.callTarget().targetMethod())) {
+                // This occurs when an intrinsic calls back to the original
+                // method to handle a slow path. During parsing of such a
+                // partial intrinsic, these calls are given frame states
+                // that exclude the outer frame state denoting a position
+                // in the intrinsic code.
+                assert inlinedMethod.getAnnotation(
+                                MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " +
+                                                frameState;
+            } else if (method.getName().equals(inlinedMethod.getName())) {
+                // This can happen for method substitutions.
+            } else {
+                throw new AssertionError(String.format("inlinedMethod=%s frameState.method=%s frameState=%s invoke.method=%s", inlinedMethod, method, frameState,
+                                invoke.callTarget().targetMethod()));
+            }
+        }
+        return true;
+    }
+
+    private static final ValueNode[] NO_ARGS = {};
+
+    private static boolean isStateAfterException(FrameState frameState) {
+        return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.getMethod().isSynchronized());
+    }
+
+    public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+        Graph graph = nonReplaceableFrameState.graph();
+        NodeWorkList workList = graph.createNodeWorkList();
+        workList.add(nonReplaceableFrameState);
+        for (Node node : workList) {
+            FrameState fs = (FrameState) node;
+            for (Node usage : fs.usages().snapshot()) {
+                if (!usage.isAlive()) {
+                    continue;
+                }
+                if (usage instanceof FrameState) {
+                    workList.add(usage);
+                } else {
+                    StateSplit stateSplit = (StateSplit) usage;
+                    FixedNode fixedStateSplit = stateSplit.asNode();
+                    if (fixedStateSplit instanceof AbstractMergeNode) {
+                        AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit;
+                        while (merge.isAlive()) {
+                            AbstractEndNode end = merge.forwardEnds().first();
+                            DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                            end.replaceAtPredecessor(deoptimizeNode);
+                            GraphUtil.killCFG(end);
+                        }
+                    } else {
+                        FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        if (fixedStateSplit instanceof AbstractBeginNode) {
+                            deoptimizeNode = BeginNode.begin(deoptimizeNode);
+                        }
+                        fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
+                        GraphUtil.killCFG(fixedStateSplit);
+                    }
+                }
+            }
+        }
+        return nonReplaceableFrameState;
+    }
+
+    public static ValueNode mergeReturns(AbstractMergeNode merge, List<? extends ReturnNode> returnNodes, List<Node> canonicalizedNodes) {
+        return mergeValueProducers(merge, returnNodes, canonicalizedNodes, returnNode -> returnNode.result());
+    }
+
+    public static <T extends ControlSinkNode> ValueNode mergeValueProducers(AbstractMergeNode merge, List<? extends T> valueProducers, List<Node> canonicalizedNodes,
+                    Function<T, ValueNode> valueFunction) {
+        ValueNode singleResult = null;
+        PhiNode phiResult = null;
+        for (T valueProducer : valueProducers) {
+            ValueNode result = valueFunction.apply(valueProducer);
+            if (result != null) {
+                if (phiResult == null && (singleResult == null || singleResult == result)) {
+                    /* Only one result value, so no need yet for a phi node. */
+                    singleResult = result;
+                } else if (phiResult == null) {
+                    /* Found a second result value, so create phi node. */
+                    phiResult = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge));
+                    if (canonicalizedNodes != null) {
+                        canonicalizedNodes.add(phiResult);
+                    }
+                    for (int i = 0; i < merge.forwardEndCount(); i++) {
+                        phiResult.addInput(singleResult);
+                    }
+                    phiResult.addInput(result);
+
+                } else {
+                    /* Multiple return values, just add to existing phi node. */
+                    phiResult.addInput(result);
+                }
+            }
+
+            // create and wire up a new EndNode
+            EndNode endNode = merge.graph().add(new EndNode());
+            merge.addForwardEnd(endNode);
+            valueProducer.replaceAndDelete(endNode);
+        }
+
+        if (phiResult != null) {
+            assert phiResult.verify();
+            phiResult.inferStamp();
+            return phiResult;
+        } else {
+            return singleResult;
+        }
+    }
+
+    private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map<Node, Node> duplicates) {
+        for (Node node : duplicates.values()) {
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                assert frameState.bci == BytecodeFrame.AFTER_BCI || frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null, and
+     * ensuring that the resulting type is compatible with the method being invoked.
+     */
+    public static ValueNode nonNullReceiver(Invoke invoke) {
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        assert !callTarget.isStatic() : callTarget.targetMethod();
+        StructuredGraph graph = callTarget.graph();
+        ValueNode firstParam = callTarget.arguments().get(0);
+        if (firstParam.getStackKind() == JavaKind.Object) {
+            Stamp paramStamp = firstParam.stamp();
+            Stamp stamp = paramStamp.join(StampFactory.objectNonNull(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass())));
+            if (!StampTool.isPointerNonNull(firstParam)) {
+                LogicNode condition = graph.unique(IsNullNode.create(firstParam));
+                FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
+                PiNode nonNullReceiver = graph.unique(new PiNode(firstParam, stamp, fixedGuard));
+                graph.addBeforeFixed(invoke.asNode(), fixedGuard);
+                callTarget.replaceFirstInput(firstParam, nonNullReceiver);
+                return nonNullReceiver;
+            }
+            if (!stamp.equals(paramStamp)) {
+                PiNode cast = graph.unique(new PiNode(firstParam, stamp));
+                callTarget.replaceFirstInput(firstParam, cast);
+                return cast;
+            }
+        }
+        return firstParam;
+    }
+
+    public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target, int invokeBci) {
+        return replacements.hasSubstitution(target, invokeBci);
+    }
+
+    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) {
+        return replacements.getSubstitution(target, invokeBci);
+    }
+
+    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalError {
+        StructuredGraph graph = invoke.asNode().graph();
+        if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
+            assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind().hasReceiver();
+            InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
+        }
+
+        FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
+
+        CallTargetNode callTarget = invoke.callTarget();
+        if (invoke instanceof InvokeNode) {
+            graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
+        } else {
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            invokeWithException.killExceptionEdge();
+            graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
+        }
+        GraphUtil.killWithUnusedFloatingInputs(callTarget);
+        return macroNode;
+    }
+
+    private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalError {
+        try {
+            Constructor<?> cons = macroNodeClass.getDeclaredConstructor(Invoke.class);
+            return (FixedWithNextNode) cons.newInstance(invoke);
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+            throw new GraalGraphError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+        }
+    }
+
+    /**
+     * This method exclude InstrumentationNode from inlining heuristics.
+     */
+    public static int getNodeCount(StructuredGraph graph) {
+        if (UseGraalInstrumentation.getValue()) {
+            return graph.getNodeCount() - graph.getNodes().filter(InstrumentationNode.class).count();
+        } else {
+            return graph.getNodeCount();
+        }
+    }
+
+    /**
+     * This method detach the instrumentation attached to the given Invoke. It is called when the
+     * given Invoke is inlined.
+     */
+    public static void detachInstrumentation(Invoke invoke) {
+        FixedNode invokeNode = invoke.asNode();
+        for (InstrumentationNode instrumentation : invokeNode.usages().filter(InstrumentationNode.class).snapshot()) {
+            if (instrumentation.getTarget() == invoke) {
+                instrumentation.replaceFirstInput(instrumentation.getTarget(), null);
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java
new file mode 100644
index 0000000..f421628
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class AbstractInlineInfo implements InlineInfo {
+
+    protected final Invoke invoke;
+
+    public AbstractInlineInfo(Invoke invoke) {
+        this.invoke = invoke;
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return invoke.asNode().graph();
+    }
+
+    @Override
+    public Invoke invoke() {
+        return invoke;
+    }
+
+    protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, boolean receiverNullCheck) {
+        List<Node> canonicalizeNodes = new ArrayList<>();
+        assert inlineable instanceof InlineableGraph;
+        StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
+        Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes, concrete);
+        getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
+        return canonicalizeNodes;
+    }
+
+    public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
+        for (ParameterNode parameter : calleeGraph.getNodes(ParameterNode.TYPE)) {
+            for (Node usage : parameter.usages()) {
+                Node node = duplicateMap.get(usage);
+                if (node != null && node.isAlive()) {
+                    parameterUsages.add(node);
+                }
+            }
+        }
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public final void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer) {
+        for (int i = 0; i < numberOfMethods(); i++) {
+            try (Debug.Scope s = Debug.methodMetricsScope("InlineEnhancement", MethodMetricsInlineeScopeInfo.create(), false)) {
+                Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer);
+                setInlinableElement(i, elem);
+            }
+        }
+    }
+
+    @Override
+    public final int determineNodeCount() {
+        int nodes = 0;
+        for (int i = 0; i < numberOfMethods(); i++) {
+            Inlineable elem = inlineableElementAt(i);
+            if (elem != null) {
+                nodes += elem.getNodeCount();
+            }
+        }
+        return nodes;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java
new file mode 100644
index 0000000..a44b2e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import java.util.Collection;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
+ * target method, but for which an assumption has to be registered because of non-final classes.
+ */
+public class AssumptionInlineInfo extends ExactInlineInfo {
+
+    private final AssumptionResult<?> takenAssumption;
+
+    public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, AssumptionResult<?> takenAssumption) {
+        super(invoke, concrete);
+        this.takenAssumption = takenAssumption;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers) {
+        takenAssumption.recordTo(invoke.asNode().graph().getAssumptions());
+        return super.inline(providers);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(Providers providers) {
+        takenAssumption.recordTo(invoke.asNode().graph().getAssumptions());
+        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+    }
+
+    @Override
+    public String toString() {
+        return "assumption " + concrete.format("%H.%n(%p):%r");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java
new file mode 100644
index 0000000..b690000
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import java.util.Collection;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Represents an inlining opportunity where the compiler can statically determine a monomorphic
+ * target method and therefore is able to determine the called method exactly.
+ */
+public class ExactInlineInfo extends AbstractInlineInfo {
+
+    protected final ResolvedJavaMethod concrete;
+    private Inlineable inlineableElement;
+    private boolean suppressNullCheck;
+
+    public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
+        super(invoke);
+        this.concrete = concrete;
+        assert concrete != null;
+    }
+
+    public void suppressNullCheck() {
+        suppressNullCheck = true;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers) {
+        return inline(invoke, concrete, inlineableElement, !suppressNullCheck);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(Providers providers) {
+        // nothing todo, can already be bound statically
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return 1;
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index == 0;
+        return concrete;
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public String toString() {
+        return "exact " + concrete.format("%H.%n(%p):%r");
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index == 0;
+        return inlineableElement;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index == 0;
+        this.inlineableElement = inlineableElement;
+    }
+
+    @Override
+    public boolean shouldInline() {
+        return concrete.shouldBeInlined();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java
new file mode 100644
index 0000000..8eb382b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import java.util.Collection;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Represents an opportunity for inlining at a given invoke, with the given weight and level. The
+ * weight is the amortized weight of the additional code - so smaller is better. The level is the
+ * number of nested inlinings that lead to this invoke.
+ */
+public interface InlineInfo {
+
+    /**
+     * The graph containing the {@link #invoke() invocation} that may be inlined.
+     */
+    StructuredGraph graph();
+
+    /**
+     * The invocation that may be inlined.
+     */
+    Invoke invoke();
+
+    /**
+     * Returns the number of methods that may be inlined by the {@link #invoke() invocation}. This
+     * may be more than one in the case of a invocation profile showing a number of "hot" concrete
+     * methods dispatched to by the invocation.
+     */
+    int numberOfMethods();
+
+    ResolvedJavaMethod methodAt(int index);
+
+    Inlineable inlineableElementAt(int index);
+
+    double probabilityAt(int index);
+
+    double relevanceAt(int index);
+
+    void setInlinableElement(int index, Inlineable inlineableElement);
+
+    /**
+     * Performs the inlining described by this object and returns the node that represents the
+     * return value of the inlined method (or null for void methods and methods that have no
+     * non-exceptional exit).
+     *
+     * @return a collection of nodes that need to be canonicalized after the inlining
+     */
+    Collection<Node> inline(Providers providers);
+
+    /**
+     * Try to make the call static bindable to avoid interface and virtual method calls.
+     */
+    void tryToDevirtualizeInvoke(Providers providers);
+
+    boolean shouldInline();
+
+    void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer);
+
+    int determineNodeCount();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java
new file mode 100644
index 0000000..13b3e4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.GuardedValueNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.TypeSwitchNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Polymorphic inlining of m methods with n type checks (n &ge; m) in case that the profiling
+ * information suggests a reasonable amount of different receiver types and different methods. If an
+ * unknown type is encountered a deoptimization is triggered.
+ */
+public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
+
+    private final List<ResolvedJavaMethod> concretes;
+    private final double[] methodProbabilities;
+    private final double maximumMethodProbability;
+    private final ArrayList<Integer> typesToConcretes;
+    private final ArrayList<ProfiledType> ptypes;
+    private final double notRecordedTypeProbability;
+    private final Inlineable[] inlineableElements;
+
+    public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<ProfiledType> ptypes, ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
+        super(invoke);
+        assert concretes.size() > 0 : "must have at least one method";
+        assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
+
+        this.concretes = concretes;
+        this.ptypes = ptypes;
+        this.typesToConcretes = typesToConcretes;
+        this.notRecordedTypeProbability = notRecordedTypeProbability;
+        this.inlineableElements = new Inlineable[concretes.size()];
+        this.methodProbabilities = computeMethodProbabilities();
+        this.maximumMethodProbability = maximumMethodProbability();
+        assert maximumMethodProbability > 0;
+        assert assertUniqueTypes(ptypes);
+    }
+
+    private static boolean assertUniqueTypes(ArrayList<ProfiledType> ptypes) {
+        Set<ResolvedJavaType> set = new HashSet<>();
+        for (ProfiledType ptype : ptypes) {
+            set.add(ptype.getType());
+        }
+        return set.size() == ptypes.size();
+    }
+
+    private double[] computeMethodProbabilities() {
+        double[] result = new double[concretes.size()];
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            int concrete = typesToConcretes.get(i);
+            double probability = ptypes.get(i).getProbability();
+            result[concrete] += probability;
+        }
+        return result;
+    }
+
+    private double maximumMethodProbability() {
+        double max = 0;
+        for (int i = 0; i < methodProbabilities.length; i++) {
+            max = Math.max(max, methodProbabilities[i]);
+        }
+        return max;
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return concretes.size();
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index >= 0 && index < concretes.size();
+        return concretes.get(index);
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index >= 0 && index < concretes.size();
+        return inlineableElements[index];
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        return methodProbabilities[index];
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        return probabilityAt(index) / maximumMethodProbability;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index >= 0 && index < concretes.size();
+        inlineableElements[index] = inlineableElement;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers) {
+        if (hasSingleMethod()) {
+            return inlineSingleMethod(graph(), providers.getStampProvider(), providers.getConstantReflection());
+        } else {
+            return inlineMultipleMethods(graph(), providers);
+        }
+    }
+
+    @Override
+    public boolean shouldInline() {
+        for (ResolvedJavaMethod method : concretes) {
+            if (method.shouldBeInlined()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasSingleMethod() {
+        return concretes.size() == 1 && !shouldFallbackToInvoke();
+    }
+
+    private boolean shouldFallbackToInvoke() {
+        return notRecordedTypeProbability > 0;
+    }
+
+    private Collection<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers) {
+        int numberOfMethods = concretes.size();
+        FixedNode continuation = invoke.next();
+
+        // setup merge and phi nodes for results and exceptions
+        AbstractMergeNode returnMerge = graph.add(new MergeNode());
+        returnMerge.setStateAfter(invoke.stateAfter());
+
+        PhiNode returnValuePhi = null;
+        if (invoke.asNode().getStackKind() != JavaKind.Void) {
+            returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
+        }
+
+        AbstractMergeNode exceptionMerge = null;
+        PhiNode exceptionObjectPhi = null;
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+
+            exceptionMerge = graph.add(new MergeNode());
+
+            FixedNode exceptionSux = exceptionEdge.next();
+            graph.addBeforeFixed(exceptionSux, exceptionMerge);
+            exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(JavaKind.Object), exceptionMerge));
+            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, JavaKind.Object, new JavaKind[]{JavaKind.Object},
+                            new ValueNode[]{exceptionObjectPhi}));
+        }
+
+        // create one separate block for each invoked method
+        AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1];
+        for (int i = 0; i < numberOfMethods; i++) {
+            successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
+        }
+
+        // create the successor for an unknown type
+        FixedNode unknownTypeSux;
+        if (shouldFallbackToInvoke()) {
+            unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
+        } else {
+            unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
+        }
+        successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+
+        // replace the invoke exception edge
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
+            exceptionEdge.replaceAtUsages(exceptionObjectPhi);
+            exceptionEdge.setNext(null);
+            GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+        }
+
+        assert invoke.asNode().isAlive();
+
+        // replace the invoke with a switch on the type of the actual receiver
+        boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getStampProvider(), providers.getConstantReflection());
+
+        assert invoke.next() == continuation;
+        invoke.setNext(null);
+        returnMerge.setNext(continuation);
+        if (UseGraalInstrumentation.getValue()) {
+            InliningUtil.detachInstrumentation(invoke);
+        }
+        if (returnValuePhi != null) {
+            invoke.asNode().replaceAtUsages(returnValuePhi);
+        }
+        invoke.asNode().safeDelete();
+
+        ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
+
+        // prepare the anchors for the invokes
+        for (int i = 0; i < numberOfMethods; i++) {
+            AbstractBeginNode node = successors[i];
+            Invoke invokeForInlining = (Invoke) node.next();
+
+            ResolvedJavaType commonType;
+            if (methodDispatch) {
+                commonType = concretes.get(i).getDeclaringClass();
+            } else {
+                commonType = getLeastCommonType(i);
+            }
+
+            ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
+            boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
+            GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
+            invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+            assert !anchoredReceiver.isDeleted() : anchoredReceiver;
+            replacementNodes.add(anchoredReceiver);
+        }
+        if (shouldFallbackToInvoke()) {
+            replacementNodes.add(null);
+        }
+
+        Collection<Node> canonicalizeNodes = new ArrayList<>();
+        // do the actual inlining for every invoke
+        for (int i = 0; i < numberOfMethods; i++) {
+            Invoke invokeForInlining = (Invoke) successors[i].next();
+            canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), false));
+        }
+        if (returnValuePhi != null) {
+            canonicalizeNodes.add(returnValuePhi);
+        }
+        return canonicalizeNodes;
+    }
+
+    private int getTypeCount(int concreteMethodIndex) {
+        int count = 0;
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            if (typesToConcretes.get(i) == concreteMethodIndex) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+        ResolvedJavaType commonType = null;
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            if (typesToConcretes.get(i) == concreteMethodIndex) {
+                if (commonType == null) {
+                    commonType = ptypes.get(i).getType();
+                } else {
+                    commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
+                }
+            }
+        }
+        assert commonType != null;
+        return commonType;
+    }
+
+    private ResolvedJavaType getLeastCommonType() {
+        ResolvedJavaType result = getLeastCommonType(0);
+        for (int i = 1; i < concretes.size(); i++) {
+            result = result.findLeastCommonAncestor(getLeastCommonType(i));
+        }
+        return result;
+    }
+
+    private Collection<Node> inlineSingleMethod(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection) {
+        assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+        AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
+
+        AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+        AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux};
+        createDispatchOnTypeBeforeInvoke(graph, successors, false, stampProvider, constantReflection);
+
+        calleeEntryNode.setNext(invoke.asNode());
+
+        return inline(invoke, methodAt(0), inlineableElementAt(0), false);
+    }
+
+    private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, StampProvider stampProvider,
+                    ConstantReflectionProvider constantReflection) {
+        assert ptypes.size() >= 1;
+        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+        LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
+
+        Debug.log("Type switch with %d types", concretes.size());
+
+        ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
+        double[] keyProbabilities = new double[ptypes.size() + 1];
+        int[] keySuccessors = new int[ptypes.size() + 1];
+        double totalProbability = notRecordedTypeProbability;
+        for (int i = 0; i < ptypes.size(); i++) {
+            keys[i] = ptypes.get(i).getType();
+            keyProbabilities[i] = ptypes.get(i).getProbability();
+            totalProbability += keyProbabilities[i];
+            keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
+            assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
+        }
+        keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
+        keySuccessors[keySuccessors.length - 1] = successors.length - 1;
+
+        // Normalize the probabilities.
+        for (int i = 0; i < keyProbabilities.length; i++) {
+            keyProbabilities[i] /= totalProbability;
+        }
+
+        TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors, constantReflection));
+        FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+        pred.setNext(typeSwitch);
+        return false;
+    }
+
+    private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, AbstractMergeNode returnMerge, PhiNode returnValuePhi, AbstractMergeNode exceptionMerge,
+                    PhiNode exceptionObjectPhi, boolean useForInlining) {
+        Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
+        AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
+        calleeEntryNode.setNext(duplicatedInvoke.asNode());
+
+        EndNode endNode = graph.add(new EndNode());
+        duplicatedInvoke.setNext(endNode);
+        returnMerge.addForwardEnd(endNode);
+
+        if (returnValuePhi != null) {
+            returnValuePhi.addInput(duplicatedInvoke.asNode());
+        }
+        return calleeEntryNode;
+    }
+
+    private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, AbstractMergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
+        Invoke result = (Invoke) invoke.asNode().copyWithInputs();
+        Node callTarget = result.callTarget().copyWithInputs();
+        result.asNode().replaceFirstInput(result.callTarget(), callTarget);
+        result.setUseForInlining(useForInlining);
+
+        JavaKind kind = invoke.asNode().getStackKind();
+        if (kind != JavaKind.Void) {
+            FrameState stateAfter = invoke.stateAfter();
+            stateAfter = stateAfter.duplicate(stateAfter.bci);
+            stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
+            result.setStateAfter(stateAfter);
+        }
+
+        if (invoke instanceof InvokeWithExceptionNode) {
+            assert exceptionMerge != null && exceptionObjectPhi != null;
+
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+            FrameState stateAfterException = exceptionEdge.stateAfter();
+
+            ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
+            // set new state (pop old exception object, push new one)
+            newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(JavaKind.Object, JavaKind.Object, newExceptionEdge));
+
+            EndNode endNode = graph.add(new EndNode());
+            newExceptionEdge.setNext(endNode);
+            exceptionMerge.addForwardEnd(endNode);
+            exceptionObjectPhi.addInput(newExceptionEdge);
+
+            ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+        }
+        return result;
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(Providers providers) {
+        if (hasSingleMethod()) {
+            devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), providers.getStampProvider(), providers.getConstantReflection());
+        } else {
+            tryToDevirtualizeMultipleMethods(graph(), providers.getStampProvider(), providers.getConstantReflection());
+        }
+    }
+
+    private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection) {
+        MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
+            ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
+            ResolvedJavaType leastCommonType = getLeastCommonType();
+            ResolvedJavaType contextType = invoke.getContextType();
+            // check if we have a common base type that implements the interface -> in that case
+            // we have a vtable entry for the interface method and can use a less expensive
+            // virtual call
+            if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
+                ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveConcreteMethod(targetMethod, contextType);
+                if (baseClassTargetMethod != null) {
+                    devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveConcreteMethod(targetMethod, contextType), stampProvider, constantReflection);
+                }
+            }
+        }
+    }
+
+    private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, StampProvider stampProvider, ConstantReflectionProvider constantReflection) {
+        AbstractBeginNode invocationEntry = graph.add(new BeginNode());
+        AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+        AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux};
+        createDispatchOnTypeBeforeInvoke(graph, successors, true, stampProvider, constantReflection);
+
+        invocationEntry.setNext(invoke.asNode());
+        ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+        GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
+        invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+        InliningUtil.replaceInvokeCallTarget(invoke, graph, kind, target);
+    }
+
+    private static AbstractBeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+        return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+        builder.append(", ");
+        builder.append(concretes.size());
+        builder.append(" methods [ ");
+        for (int i = 0; i < concretes.size(); i++) {
+            builder.append(concretes.get(i).format("  %H.%n(%p):%r"));
+        }
+        builder.append(" ], ");
+        builder.append(ptypes.size());
+        builder.append(" type checks [ ");
+        for (int i = 0; i < ptypes.size(); i++) {
+            builder.append("  ");
+            builder.append(ptypes.get(i).getType().getName());
+            builder.append(ptypes.get(i).getProbability());
+        }
+        builder.append(" ]");
+        return builder.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java
new file mode 100644
index 0000000..412ba70
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info;
+
+import java.util.Collection;
+
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Represents an inlining opportunity for which profiling information suggests a monomorphic
+ * receiver, but for which the receiver type cannot be proven. A type check guard will be generated
+ * if this inlining is performed.
+ */
+public class TypeGuardInlineInfo extends AbstractInlineInfo {
+
+    private final ResolvedJavaMethod concrete;
+    private final ResolvedJavaType type;
+    private Inlineable inlineableElement;
+
+    public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+        super(invoke);
+        this.concrete = concrete;
+        this.type = type;
+        assert type.isArray() || type.isConcrete() : type;
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return 1;
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index == 0;
+        return concrete;
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index == 0;
+        return inlineableElement;
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index == 0;
+        this.inlineableElement = inlineableElement;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers) {
+        createGuard(graph(), providers);
+        return inline(invoke, concrete, inlineableElement, false);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(Providers providers) {
+        createGuard(graph(), providers);
+        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+    }
+
+    private void createGuard(StructuredGraph graph, Providers providers) {
+        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+        LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver));
+        ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph);
+
+        LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection());
+        FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+        assert invoke.predecessor() != null;
+
+        ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
+        invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
+
+        graph.addBeforeFixed(invoke.asNode(), guard);
+    }
+
+    @Override
+    public String toString() {
+        return "type-checked with type " + type.getName() + " and method " + concrete.format("%H.%n(%p):%r");
+    }
+
+    @Override
+    public boolean shouldInline() {
+        return concrete.shouldBeInlined();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java
new file mode 100644
index 0000000..2bdeb86
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info.elem;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public interface Inlineable {
+
+    static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        assert method != null;
+        assert invoke != null;
+        return new InlineableGraph(method, invoke, context, canonicalizer);
+    }
+
+    int getNodeCount();
+
+    Iterable<Invoke> getInvokes();
+
+    double getProbability(Invoke invoke);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java
new file mode 100644
index 0000000..9496399
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.info.elem;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.instrumentation.ExtractInstrumentationPhase;
+import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * <p>
+ * Represents a feasible concrete target for inlining, whose graph has been copied already and thus
+ * can be modified without affecting the original (usually cached) version.
+ * </p>
+ *
+ * <p>
+ * Instances of this class don't make sense in isolation but as part of an
+ * {@link org.graalvm.compiler.phases.common.inlining.info.InlineInfo InlineInfo}.
+ * </p>
+ *
+ * @see org.graalvm.compiler.phases.common.inlining.walker.InliningData#moveForward()
+ * @see org.graalvm.compiler.phases.common.inlining.walker.CallsiteHolderExplorable
+ */
+public class InlineableGraph implements Inlineable {
+
+    private final StructuredGraph graph;
+
+    private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache();
+
+    public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci());
+        // TODO copying the graph is only necessary if it is modified or if it contains any invokes
+        this.graph = (StructuredGraph) original.copy();
+        specializeGraphToArguments(invoke, context, canonicalizer);
+    }
+
+    /**
+     * This method looks up in a cache the graph for the argument, if not found bytecode is parsed.
+     * The graph thus obtained is returned, ie the caller is responsible for cloning before
+     * modification.
+     */
+    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci) {
+        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci);
+        if (result != null) {
+            return result;
+        }
+        return parseBytecodes(method, context, canonicalizer, caller);
+    }
+
+    /**
+     * @return true iff one or more parameters <code>newGraph</code> were specialized to account for
+     *         a constant argument, or an argument with a more specific stamp.
+     */
+    @SuppressWarnings("try")
+    private boolean specializeGraphToArguments(final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+        try (Debug.Scope s = Debug.scope("InlineGraph", graph)) {
+
+            ArrayList<Node> parameterUsages = replaceParamsWithMoreInformativeArguments(invoke, context);
+            if (parameterUsages != null) {
+                assert !parameterUsages.isEmpty() : "The caller didn't have more information about arguments after all";
+                canonicalizer.applyIncremental(graph, context, parameterUsages);
+                return true;
+            } else {
+                // TODO (chaeubl): if args are not more concrete, inlining should be avoided
+                // in most cases or we could at least use the previous graph size + invoke
+                // probability to check the inlining
+                return false;
+            }
+
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private static boolean isArgMoreInformativeThanParam(ValueNode arg, ParameterNode param) {
+        return arg.isConstant() || canStampBeImproved(arg, param);
+    }
+
+    private static boolean canStampBeImproved(ValueNode arg, ParameterNode param) {
+        return improvedStamp(arg, param) != null;
+    }
+
+    private static Stamp improvedStamp(ValueNode arg, ParameterNode param) {
+        Stamp joinedStamp = param.stamp().join(arg.stamp());
+        if (joinedStamp == null || joinedStamp.equals(param.stamp())) {
+            return null;
+        }
+        return joinedStamp;
+    }
+
+    /**
+     * This method detects:
+     * <ul>
+     * <li>constants among the arguments to the <code>invoke</code></li>
+     * <li>arguments with more precise type than that declared by the corresponding parameter</li>
+     * </ul>
+     *
+     * <p>
+     * The corresponding parameters are updated to reflect the above information. Before doing so,
+     * their usages are added to <code>parameterUsages</code> for later incremental
+     * canonicalization.
+     * </p>
+     *
+     * @return null if no incremental canonicalization is need, a list of nodes for such
+     *         canonicalization otherwise.
+     */
+    private ArrayList<Node> replaceParamsWithMoreInformativeArguments(final Invoke invoke, final HighTierContext context) {
+        NodeInputList<ValueNode> args = invoke.callTarget().arguments();
+        ArrayList<Node> parameterUsages = null;
+        List<ParameterNode> params = graph.getNodes(ParameterNode.TYPE).snapshot();
+        assert params.size() <= args.size();
+        /*
+         * param-nodes that aren't used (eg, as a result of canonicalization) don't occur in
+         * `params`. Thus, in general, the sizes of `params` and `args` don't always match. Still,
+         * it's always possible to pair a param-node with its corresponding arg-node using
+         * param.index() as index into `args`.
+         */
+        for (ParameterNode param : params) {
+            if (param.usages().isNotEmpty()) {
+                ValueNode arg = args.get(param.index());
+                if (arg.isConstant()) {
+                    Constant constant = arg.asConstant();
+                    parameterUsages = trackParameterUsages(param, parameterUsages);
+                    // collect param usages before replacing the param
+                    param.replaceAtUsagesAndDelete(graph.unique(
+                                    ConstantNode.forConstant(arg.stamp(), constant, ((ConstantNode) arg).getStableDimension(), ((ConstantNode) arg).isDefaultStable(), context.getMetaAccess())));
+                    // param-node gone, leaving a gap in the sequence given by param.index()
+                } else {
+                    Stamp impro = improvedStamp(arg, param);
+                    if (impro != null) {
+                        param.setStamp(impro);
+                        parameterUsages = trackParameterUsages(param, parameterUsages);
+                    } else {
+                        assert !isArgMoreInformativeThanParam(arg, param);
+                    }
+                }
+            }
+        }
+        assert (parameterUsages == null) || (!parameterUsages.isEmpty());
+        return parameterUsages;
+    }
+
+    private static ArrayList<Node> trackParameterUsages(ParameterNode param, ArrayList<Node> parameterUsages) {
+        ArrayList<Node> result = (parameterUsages == null) ? new ArrayList<>() : parameterUsages;
+        param.usages().snapshotTo(result);
+        return result;
+    }
+
+    /**
+     * This method builds the IR nodes for the given <code>method</code> and canonicalizes them.
+     * Provided profiling info is mature, the resulting graph is cached. The caller is responsible
+     * for cloning before modification.
+     * </p>
+     */
+    @SuppressWarnings("try")
+    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
+        StructuredGraph newGraph = new StructuredGraph(method, AllowAssumptions.from(caller.getAssumptions() != null), INVALID_COMPILATION_ID);
+        try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) {
+            if (!caller.isUnsafeAccessTrackingEnabled()) {
+                newGraph.disableUnsafeAccessTracking();
+            }
+            if (context.getGraphBuilderSuite() != null) {
+                context.getGraphBuilderSuite().apply(newGraph, context);
+            }
+            assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined();
+
+            if (UseGraalInstrumentation.getValue()) {
+                new ExtractInstrumentationPhase().apply(newGraph, context);
+            }
+            new DeadCodeEliminationPhase(Optional).apply(newGraph);
+
+            canonicalizer.apply(newGraph, context);
+
+            return newGraph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    @Override
+    public int getNodeCount() {
+        return InliningUtil.getNodeCount(graph);
+    }
+
+    @Override
+    public Iterable<Invoke> getInvokes() {
+        return graph.getInvokes();
+    }
+
+    @Override
+    public double getProbability(Invoke invoke) {
+        return probabilites.applyAsDouble(invoke.asNode());
+    }
+
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java
new file mode 100644
index 0000000..cab7056
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.policy;
+
+import static org.graalvm.compiler.phases.common.inlining.InliningPhase.Options.AlwaysInlineIntrinsics;
+
+import java.util.Map;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class AbstractInliningPolicy implements InliningPolicy {
+    public static final float RelevanceCapForInlining = 1.0f;
+    public static final float CapInheritedRelevance = 1.0f;
+    protected final Map<Invoke, Double> hints;
+
+    public AbstractInliningPolicy(Map<Invoke, Double> hints) {
+        this.hints = hints;
+    }
+
+    protected double computeMaximumSize(double relevance, int configuredMaximum) {
+        double inlineRatio = Math.min(RelevanceCapForInlining, relevance);
+        return configuredMaximum * inlineRatio;
+    }
+
+    protected double getInliningBonus(InlineInfo info) {
+        if (hints != null && hints.containsKey(info.invoke())) {
+            return hints.get(info.invoke());
+        }
+        return 1;
+    }
+
+    protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
+        if (AlwaysInlineIntrinsics.getValue()) {
+            return onlyIntrinsics(replacements, info);
+        } else {
+            return onlyForcedIntrinsics(replacements, info);
+        }
+    }
+
+    private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static int previousLowLevelGraphSize(InlineInfo info) {
+        int size = 0;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            ResolvedJavaMethod m = info.methodAt(i);
+            ProfilingInfo profile = info.graph().getProfilingInfo(m);
+            int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
+            if (compiledGraphSize > 0) {
+                size += compiledGraphSize;
+            }
+        }
+        return size;
+    }
+
+    protected static double determineInvokeProbability(InlineInfo info) {
+        double invokeProbability = 0;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable callee = info.inlineableElementAt(i);
+            Iterable<Invoke> invokes = callee.getInvokes();
+            if (invokes.iterator().hasNext()) {
+                for (Invoke invoke : invokes) {
+                    invokeProbability += callee.getProbability(invoke);
+                }
+            }
+        }
+        return invokeProbability;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java
new file mode 100644
index 0000000..b8e56f5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.policy;
+
+import static org.graalvm.compiler.core.common.GraalOptions.InlineEverything;
+import static org.graalvm.compiler.core.common.GraalOptions.LimitInlinedInvokes;
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize;
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumInliningSize;
+import static org.graalvm.compiler.core.common.GraalOptions.SmallCompiledLowLevelGraphSize;
+import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize;
+
+import java.util.Map;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation;
+
+public class GreedyInliningPolicy extends AbstractInliningPolicy {
+
+    private static final DebugCounter inliningStoppedByMaxDesiredSizeCounter = Debug.counter("InliningStoppedByMaxDesiredSize");
+
+    public GreedyInliningPolicy(Map<Invoke, Double> hints) {
+        super(hints);
+    }
+
+    @Override
+    public boolean continueInlining(StructuredGraph currentGraph) {
+        if (InliningUtil.getNodeCount(currentGraph) >= MaximumDesiredSize.getValue()) {
+            InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
+            inliningStoppedByMaxDesiredSizeCounter.increment();
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+
+        final InlineInfo info = invocation.callee();
+        final double probability = invocation.probability();
+        final double relevance = invocation.relevance();
+
+        if (InlineEverything.getValue()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+            return true;
+        }
+
+        if (isIntrinsic(replacements, info)) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+            return true;
+        }
+
+        if (info.shouldInline()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+            return true;
+        }
+
+        double inliningBonus = getInliningBonus(info);
+        int nodes = info.determineNodeCount();
+        int lowLevelGraphSize = previousLowLevelGraphSize(info);
+
+        if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
+            InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize,
+                            relevance, probability, inliningBonus, nodes);
+            return false;
+        }
+
+        if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+            return true;
+        }
+
+        /*
+         * TODO (chaeubl): invoked methods that are on important paths but not yet compiled -> will
+         * be compiled anyways and it is likely that we are the only caller... might be useful to
+         * inline those methods but increases bootstrap time (maybe those methods are also getting
+         * queued in the compilation queue concurrently)
+         */
+        double invokes = determineInvokeProbability(info);
+        if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
+            InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance,
+                            probability, inliningBonus, nodes);
+            return false;
+        }
+
+        double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
+        if (nodes <= maximumNodes) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+                            nodes, maximumNodes);
+            return true;
+        }
+
+        InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java
new file mode 100644
index 0000000..c149a80
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.policy;
+
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation;
+
+public class InlineEverythingPolicy implements InliningPolicy {
+
+    @Override
+    public boolean continueInlining(StructuredGraph graph) {
+        if (InliningUtil.getNodeCount(graph) >= MaximumDesiredSize.getValue()) {
+            throw new PermanentBailoutException("Inline all calls failed. The resulting graph is too large.");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java
new file mode 100644
index 0000000..9b03288
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.policy;
+
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Inline every method which would be replaced by a substitution. Useful for testing purposes.
+ */
+public final class InlineMethodSubstitutionsPolicy extends InlineEverythingPolicy {
+
+    @Override
+    public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+        CallTargetNode callTarget = invocation.callee().invoke().callTarget();
+        if (callTarget instanceof MethodCallTargetNode) {
+            ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+            if (replacements.getSubstitution(calleeMethod, invocation.callee().invoke().bci()) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java
new file mode 100644
index 0000000..5ac832f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.policy;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation;
+
+public interface InliningPolicy {
+
+    boolean continueInlining(StructuredGraph graph);
+
+    boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolder.java
new file mode 100644
index 0000000..6d30808
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Information about a graph that will potentially be inlined. This includes tracking the
+ * invocations in graph that will subject to inlining themselves.
+ */
+public abstract class CallsiteHolder {
+
+    /**
+     * Gets the method associated with the {@linkplain #graph() graph} represented by this object.
+     */
+    public abstract ResolvedJavaMethod method();
+
+    /**
+     * The stack realized by {@link InliningData} grows upon {@link InliningData#moveForward()}
+     * deciding to explore (depth-first) a callsite of the graph associated to this
+     * {@link CallsiteHolder}. The list of not-yet-considered callsites is managed by
+     * {@link CallsiteHolderExplorable}, and this method reports whether any such candidates remain.
+     */
+    public abstract boolean hasRemainingInvokes();
+
+    /**
+     * The graph about which this object contains inlining information.
+     */
+    public abstract StructuredGraph graph();
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java
new file mode 100644
index 0000000..d54ec59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.function.ToDoubleFunction;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.phases.common.inlining.policy.AbstractInliningPolicy;
+import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * <p>
+ * A {@link CallsiteHolder} whose graph has been copied already and thus can be modified without
+ * affecting the original (usually cached) version.
+ * </p>
+ *
+ * <p>
+ * An instance of this class is derived from an
+ * {@link org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph InlineableGraph} and
+ * contains a subset of the information there: just the {@link Invoke} nodes from it. Such nodes are
+ * candidates for depth-first search of further inlining opportunities (thus the adjective
+ * "explorable" given to this class)
+ * </p>
+ *
+ * @see InliningData#moveForward()
+ */
+public final class CallsiteHolderExplorable extends CallsiteHolder {
+
+    /**
+     * Graph in which inlining may be performed at one or more of the callsites containined in
+     * {@link #remainingInvokes}.
+     */
+    private final StructuredGraph graph;
+
+    private final LinkedList<Invoke> remainingInvokes;
+    private final double probability;
+    private final double relevance;
+
+    /**
+     * @see #getFixedParams()
+     */
+    private final Set<ParameterNode> fixedParams;
+
+    private final ToDoubleFunction<FixedNode> probabilities;
+    private final ComputeInliningRelevance computeInliningRelevance;
+
+    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
+        assert graph != null;
+        this.graph = graph;
+        this.probability = probability;
+        this.relevance = relevance;
+        this.fixedParams = fixedParamsAt(freshlyInstantiatedArguments);
+        remainingInvokes = new InliningIterator(graph).apply();
+        if (remainingInvokes.isEmpty()) {
+            probabilities = null;
+            computeInliningRelevance = null;
+        } else {
+            probabilities = new FixedNodeProbabilityCache();
+            computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+            computeProbabilities();
+        }
+        assert repOK();
+    }
+
+    /**
+     * @see #getFixedParams()
+     */
+    @SuppressWarnings("unchecked")
+    private Set<ParameterNode> fixedParamsAt(BitSet freshlyInstantiatedArguments) {
+        if (freshlyInstantiatedArguments == null || freshlyInstantiatedArguments.isEmpty()) {
+            return Collections.EMPTY_SET;
+        }
+        Set<ParameterNode> result = Node.newSet();
+        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
+            if (freshlyInstantiatedArguments.get(p.index())) {
+                result.add(p);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Parameters for which the callsite targeting {@link #graph()} provides "fixed" arguments. That
+     * callsite isn't referenced by this instance. Instead, it belongs to the graph of the caller of
+     * this {@link CallsiteHolderExplorable}
+     * </p>
+     *
+     * <p>
+     * Constant arguments don't contribute to fixed-params: those params have been removed already,
+     * see {@link org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph}.
+     * </p>
+     *
+     * <p>
+     * Instead, fixed-params are those receiving freshly instantiated arguments (possibly
+     * instantiated several levels up in the call-hierarchy)
+     * </p>
+     */
+    public Set<ParameterNode> getFixedParams() {
+        return fixedParams;
+    }
+
+    public boolean repOK() {
+        for (Invoke invoke : remainingInvokes) {
+            if (!invoke.asNode().isAlive() || !containsInvoke(invoke)) {
+                assert false;
+                return false;
+            }
+            if (!allArgsNonNull(invoke)) {
+                assert false;
+                return false;
+            }
+        }
+        for (ParameterNode fixedParam : fixedParams) {
+            if (!containsParam(fixedParam)) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public ResolvedJavaMethod method() {
+        return graph == null ? null : graph.method();
+    }
+
+    @Override
+    public boolean hasRemainingInvokes() {
+        return !remainingInvokes.isEmpty();
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return graph;
+    }
+
+    public Invoke popInvoke() {
+        return remainingInvokes.removeFirst();
+    }
+
+    public void pushInvoke(Invoke invoke) {
+        remainingInvokes.push(invoke);
+    }
+
+    public static boolean allArgsNonNull(Invoke invoke) {
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            if (arg == null) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean containsInvoke(Invoke invoke) {
+        for (Invoke i : graph().getInvokes()) {
+            if (i == invoke) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean containsParam(ParameterNode param) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
+            if (p == param) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void computeProbabilities() {
+        computeInliningRelevance.compute();
+    }
+
+    public double invokeProbability(Invoke invoke) {
+        return probability * probabilities.applyAsDouble(invoke.asNode());
+    }
+
+    public double invokeRelevance(Invoke invoke) {
+        return Math.min(AbstractInliningPolicy.CapInheritedRelevance, relevance) * computeInliningRelevance.getRelevance(invoke);
+    }
+
+    @Override
+    public String toString() {
+        return (graph != null ? method().format("%H.%n(%p)") : "<null method>") + remainingInvokes;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java
new file mode 100644
index 0000000..42b48e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+
+public class ComputeInliningRelevance {
+
+    private static final double EPSILON = 1d / Integer.MAX_VALUE;
+    private static final double UNINITIALIZED = -1D;
+
+    private static final int EXPECTED_MIN_INVOKE_COUNT = 3;
+    private static final int EXPECTED_INVOKE_RATIO = 20;
+    private static final int EXPECTED_LOOP_COUNT = 3;
+
+    private final StructuredGraph graph;
+    private final ToDoubleFunction<FixedNode> nodeProbabilities;
+
+    /**
+     * Node relevances are pre-computed for all invokes if the graph contains loops. If there are no
+     * loops, the computation happens lazily based on {@link #rootScope}.
+     */
+    private Map<FixedNode, Double> nodeRelevances;
+    /**
+     * This scope is non-null if (and only if) there are no loops in the graph. In this case, the
+     * root scope is used to compute invoke relevances on the fly.
+     */
+    private Scope rootScope;
+
+    public ComputeInliningRelevance(StructuredGraph graph, ToDoubleFunction<FixedNode> nodeProbabilities) {
+        this.graph = graph;
+        this.nodeProbabilities = nodeProbabilities;
+    }
+
+    /**
+     * Initializes or updates the relevance computation. If there are no loops within the graph,
+     * most computation happens lazily.
+     */
+    public void compute() {
+        rootScope = null;
+        if (!graph.hasLoops()) {
+            // fast path for the frequent case of no loops
+            rootScope = new Scope(graph.start(), null);
+        } else {
+            if (nodeRelevances == null) {
+                nodeRelevances = Node.newIdentityMap(EXPECTED_MIN_INVOKE_COUNT + InliningUtil.getNodeCount(graph) / EXPECTED_INVOKE_RATIO);
+            }
+            NodeWorkList workList = graph.createNodeWorkList();
+            Map<LoopBeginNode, Scope> loops = Node.newIdentityMap(EXPECTED_LOOP_COUNT);
+
+            loops.put(null, new Scope(graph.start(), null));
+            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
+                createLoopScope(loopBegin, loops);
+            }
+
+            for (Scope scope : loops.values()) {
+                scope.process(workList);
+            }
+        }
+    }
+
+    public double getRelevance(Invoke invoke) {
+        if (rootScope != null) {
+            return rootScope.computeInvokeRelevance(invoke);
+        }
+        assert nodeRelevances != null : "uninitialized relevance";
+        return nodeRelevances.get(invoke);
+    }
+
+    /**
+     * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
+     * method will call itself recursively if no {@link Scope} for the parent loop exists.
+     */
+    private Scope createLoopScope(LoopBeginNode loopBegin, Map<LoopBeginNode, Scope> loops) {
+        Scope scope = loops.get(loopBegin);
+        if (scope == null) {
+            final Scope parent;
+            // look for the parent scope
+            FixedNode current = loopBegin.forwardEnd();
+            while (true) {
+                if (current.predecessor() == null) {
+                    if (current instanceof LoopBeginNode) {
+                        // if we reach a LoopBeginNode then we're within this loop
+                        parent = createLoopScope((LoopBeginNode) current, loops);
+                        break;
+                    } else if (current instanceof StartNode) {
+                        // we're within the outermost scope
+                        parent = loops.get(null);
+                        break;
+                    } else {
+                        assert current instanceof MergeNode : current;
+                        // follow any path upwards - it doesn't matter which one
+                        current = ((AbstractMergeNode) current).forwardEndAt(0);
+                    }
+                } else if (current instanceof LoopExitNode) {
+                    // if we reach a loop exit then we follow this loop and have the same parent
+                    parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops).parent;
+                    break;
+                } else {
+                    current = (FixedNode) current.predecessor();
+                }
+            }
+            scope = new Scope(loopBegin, parent);
+            loops.put(loopBegin, scope);
+        }
+        return scope;
+    }
+
+    /**
+     * A scope holds information for the contents of one loop or of the root of the method. It does
+     * not include child loops, i.e., the iteration in {@link #process(NodeWorkList)} explicitly
+     * excludes the nodes of child loops.
+     */
+    private class Scope {
+        public final FixedNode start;
+        public final Scope parent; // can be null for the outermost scope
+
+        /**
+         * The minimum probability along the most probable path in this scope. Computed lazily.
+         */
+        private double fastPathMinProbability = UNINITIALIZED;
+        /**
+         * A measure of how important this scope is within its parent scope. Computed lazily.
+         */
+        private double scopeRelevanceWithinParent = UNINITIALIZED;
+
+        Scope(FixedNode start, Scope parent) {
+            this.start = start;
+            this.parent = parent;
+        }
+
+        @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "comparing against -1D is accurate")
+        public double getFastPathMinProbability() {
+            if (fastPathMinProbability == UNINITIALIZED) {
+                fastPathMinProbability = Math.max(EPSILON, computeFastPathMinProbability(start));
+            }
+            return fastPathMinProbability;
+        }
+
+        /**
+         * Computes the ratio between the probabilities of the current scope's entry point and the
+         * parent scope's fastPathMinProbability.
+         */
+        @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "comparing against -1D is accurate")
+        public double getScopeRelevanceWithinParent() {
+            if (scopeRelevanceWithinParent == UNINITIALIZED) {
+                if (start instanceof LoopBeginNode) {
+                    assert parent != null;
+                    double scopeEntryProbability = nodeProbabilities.applyAsDouble(((LoopBeginNode) start).forwardEnd());
+
+                    scopeRelevanceWithinParent = scopeEntryProbability / parent.getFastPathMinProbability();
+                } else {
+                    scopeRelevanceWithinParent = 1D;
+                }
+            }
+            return scopeRelevanceWithinParent;
+        }
+
+        /**
+         * Processes all invokes in this scope by starting at the scope's start node and iterating
+         * all fixed nodes. Child loops are skipped by going from loop entries directly to the loop
+         * exits. Processing stops at loop exits of the current loop.
+         */
+        public void process(NodeWorkList workList) {
+            assert !(start instanceof Invoke);
+            workList.addAll(start.successors());
+
+            for (Node current : workList) {
+                assert current.isAlive();
+
+                if (current instanceof Invoke) {
+                    // process the invoke and queue its successors
+                    nodeRelevances.put((FixedNode) current, computeInvokeRelevance((Invoke) current));
+                    workList.addAll(current.successors());
+                } else if (current instanceof LoopBeginNode) {
+                    // skip child loops by advancing over the loop exits
+                    ((LoopBeginNode) current).loopExits().forEach(exit -> workList.add(exit.next()));
+                } else if (current instanceof LoopEndNode) {
+                    // nothing to do
+                } else if (current instanceof LoopExitNode) {
+                    // nothing to do
+                } else if (current instanceof FixedWithNextNode) {
+                    workList.add(((FixedWithNextNode) current).next());
+                } else if (current instanceof EndNode) {
+                    workList.add(((EndNode) current).merge());
+                } else if (current instanceof ControlSinkNode) {
+                    // nothing to do
+                } else if (current instanceof ControlSplitNode) {
+                    workList.addAll(current.successors());
+                } else {
+                    assert false : current;
+                }
+            }
+        }
+
+        /**
+         * The relevance of an invoke is the ratio between the invoke's probability and the current
+         * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent.
+         */
+        public double computeInvokeRelevance(Invoke invoke) {
+            double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode());
+            assert !Double.isNaN(invokeProbability);
+
+            double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent());
+            assert !Double.isNaN(relevance) : invoke + ": " + relevance + " / " + invokeProbability + " / " + getFastPathMinProbability() + " / " + getScopeRelevanceWithinParent();
+            return relevance;
+        }
+    }
+
+    /**
+     * Computes the minimum probability along the most probable path within the scope. During
+     * iteration, the method returns immediately once a loop exit is discovered.
+     */
+    private double computeFastPathMinProbability(FixedNode scopeStart) {
+        ArrayList<FixedNode> pathBeginNodes = new ArrayList<>();
+        pathBeginNodes.add(scopeStart);
+        double minPathProbability = nodeProbabilities.applyAsDouble(scopeStart);
+        boolean isLoopScope = scopeStart instanceof LoopBeginNode;
+
+        do {
+            Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
+            do {
+                if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
+                    return minPathProbability;
+                } else if (current instanceof LoopBeginNode && current != scopeStart) {
+                    current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
+                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                } else if (current instanceof ControlSplitNode) {
+                    current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
+                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                } else {
+                    assert current.successors().count() <= 1;
+                    current = current.successors().first();
+                }
+            } while (current != null);
+        } while (!pathBeginNodes.isEmpty());
+
+        return minPathProbability;
+    }
+
+    private double getMinPathProbability(FixedNode current, double minPathProbability) {
+        return current == null ? minPathProbability : Math.min(minPathProbability, nodeProbabilities.applyAsDouble(current));
+    }
+
+    /**
+     * Returns the most probable successor. If multiple successors share the maximum probability,
+     * one is returned and the others are enqueued in pathBeginNodes.
+     */
+    private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList<FixedNode> pathBeginNodes) {
+        Node maxSux = null;
+        double maxProbability = 0.0;
+        int pathBeginCount = pathBeginNodes.size();
+
+        for (Node sux : controlSplit.successors()) {
+            double probability = controlSplit.probability((AbstractBeginNode) sux);
+            if (probability > maxProbability) {
+                maxProbability = probability;
+                maxSux = sux;
+                truncate(pathBeginNodes, pathBeginCount);
+            } else if (probability == maxProbability) {
+                pathBeginNodes.add((FixedNode) sux);
+            }
+        }
+
+        return maxSux;
+    }
+
+    /**
+     * Returns the most probable loop exit. If multiple successors share the maximum probability,
+     * one is returned and the others are enqueued in pathBeginNodes.
+     */
+    private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList<FixedNode> pathBeginNodes) {
+        Node maxSux = null;
+        double maxProbability = 0.0;
+        int pathBeginCount = pathBeginNodes.size();
+
+        for (LoopExitNode sux : loopBegin.loopExits()) {
+            double probability = nodeProbabilities.applyAsDouble(sux);
+            if (probability > maxProbability) {
+                maxProbability = probability;
+                maxSux = sux;
+                truncate(pathBeginNodes, pathBeginCount);
+            } else if (probability == maxProbability) {
+                pathBeginNodes.add(sux);
+            }
+        }
+
+        return maxSux;
+    }
+
+    private static void truncate(ArrayList<FixedNode> pathBeginNodes, int pathBeginCount) {
+        for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
+            pathBeginNodes.remove(pathBeginNodes.size() - 1);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java
new file mode 100644
index 0000000..863e02f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import static org.graalvm.compiler.core.common.GraalOptions.Intrinsify;
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumRecursiveInlining;
+import static org.graalvm.compiler.core.common.GraalOptions.MegamorphicInliningMinMethodProbability;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.common.inlining.info.AssumptionInlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.ExactInlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.MultiTypeGuardInlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.TypeGuardInlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph;
+import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * <p>
+ * The space of inlining decisions is explored depth-first with the help of a stack realized by
+ * {@link InliningData}. At any point in time, the topmost element of that stack consists of:
+ * <ul>
+ * <li>the callsite under consideration is tracked as a {@link MethodInvocation}.</li>
+ * <li>one or more {@link CallsiteHolder}s, all of them associated to the callsite above. Why more
+ * than one? Depending on the type-profile for the receiver more than one concrete method may be
+ * feasible target.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * The bottom element in the stack consists of:
+ * <ul>
+ * <li>a single {@link MethodInvocation} (the
+ * {@link org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation#isRoot root} one, ie
+ * the unknown caller of the root graph)</li>
+ * <li>a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @see #moveForward()
+ */
+public class InliningData {
+
+    // Counters
+    private static final DebugCounter counterInliningPerformed = Debug.counter("InliningPerformed");
+    private static final DebugCounter counterInliningRuns = Debug.counter("InliningRuns");
+    private static final DebugCounter counterInliningConsidered = Debug.counter("InliningConsidered");
+
+    /**
+     * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
+     */
+    private final ArrayDeque<CallsiteHolder> graphQueue = new ArrayDeque<>();
+    private final ArrayDeque<MethodInvocation> invocationQueue = new ArrayDeque<>();
+
+    private final HighTierContext context;
+    private final int maxMethodPerInlining;
+    private final CanonicalizerPhase canonicalizer;
+    private final InliningPolicy inliningPolicy;
+    private final StructuredGraph rootGraph;
+
+    private int maxGraphs;
+
+    public InliningData(StructuredGraph rootGraph, HighTierContext context, int maxMethodPerInlining, CanonicalizerPhase canonicalizer, InliningPolicy inliningPolicy) {
+        assert rootGraph != null;
+        this.context = context;
+        this.maxMethodPerInlining = maxMethodPerInlining;
+        this.canonicalizer = canonicalizer;
+        this.inliningPolicy = inliningPolicy;
+        this.maxGraphs = 1;
+        this.rootGraph = rootGraph;
+
+        invocationQueue.push(new MethodInvocation(null, 1.0, 1.0, null));
+        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0, null));
+    }
+
+    public static boolean isFreshInstantiation(ValueNode arg) {
+        return (arg instanceof AbstractNewObjectNode) || (arg instanceof AllocatedObjectNode) || (arg instanceof VirtualObjectNode);
+    }
+
+    private String checkTargetConditionsHelper(ResolvedJavaMethod method, int invokeBci) {
+        if (method == null) {
+            return "the method is not resolved";
+        } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method, invokeBci))) {
+            return "it is a non-intrinsic native method";
+        } else if (method.isAbstract()) {
+            return "it is an abstract method";
+        } else if (!method.getDeclaringClass().isInitialized()) {
+            return "the method's class is not initialized";
+        } else if (!method.canBeInlined()) {
+            return "it is marked non-inlinable";
+        } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
+            return "it exceeds the maximum recursive inlining depth";
+        } else if (new OptimisticOptimizations(rootGraph.getProfilingInfo(method)).lessOptimisticThan(context.getOptimisticOptimizations())) {
+            return "the callee uses less optimistic optimizations than caller";
+        } else {
+            return null;
+        }
+    }
+
+    private boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method) {
+        final String failureMessage = checkTargetConditionsHelper(method, invoke.bci());
+        if (failureMessage == null) {
+            return true;
+        } else {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), method, failureMessage);
+            return false;
+        }
+    }
+
+    /**
+     * Determines if inlining is possible at the given invoke node.
+     *
+     * @param invoke the invoke that should be inlined
+     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+     */
+    private InlineInfo getInlineInfo(Invoke invoke) {
+        final String failureMessage = InliningUtil.checkInvokeConditions(invoke);
+        if (failureMessage != null) {
+            InliningUtil.logNotInlinedMethod(invoke, failureMessage);
+            return null;
+        }
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+
+        if (callTarget.invokeKind() == CallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+            return getExactInlineInfo(invoke, targetMethod);
+        }
+
+        assert callTarget.invokeKind().isIndirect();
+
+        ResolvedJavaType holder = targetMethod.getDeclaringClass();
+        if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
+            return null;
+        }
+        ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
+        if (receiverStamp.alwaysNull()) {
+            // Don't inline if receiver is known to be null
+            return null;
+        }
+        ResolvedJavaType contextType = invoke.getContextType();
+        if (receiverStamp.type() != null) {
+            // the invoke target might be more specific than the holder (happens after inlining:
+            // parameters lose their declared type...)
+            ResolvedJavaType receiverType = receiverStamp.type();
+            if (receiverType != null && holder.isAssignableFrom(receiverType)) {
+                holder = receiverType;
+                if (receiverStamp.isExactType()) {
+                    assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+                    ResolvedJavaMethod resolvedMethod = holder.resolveConcreteMethod(targetMethod, contextType);
+                    if (resolvedMethod != null) {
+                        return getExactInlineInfo(invoke, resolvedMethod);
+                    }
+                }
+            }
+        }
+
+        if (holder.isArray()) {
+            // arrays can be treated as Objects
+            ResolvedJavaMethod resolvedMethod = holder.resolveConcreteMethod(targetMethod, contextType);
+            if (resolvedMethod != null) {
+                return getExactInlineInfo(invoke, resolvedMethod);
+            }
+        }
+
+        AssumptionResult<ResolvedJavaType> leafConcreteSubtype = holder.findLeafConcreteSubtype();
+        if (leafConcreteSubtype != null) {
+            ResolvedJavaMethod resolvedMethod = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType);
+            if (resolvedMethod != null) {
+                if (leafConcreteSubtype.canRecordTo(callTarget.graph().getAssumptions())) {
+                    return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype);
+                } else {
+                    return getTypeCheckedAssumptionInfo(invoke, resolvedMethod, leafConcreteSubtype.getResult());
+                }
+            }
+        }
+
+        AssumptionResult<ResolvedJavaMethod> concrete = holder.findUniqueConcreteMethod(targetMethod);
+        if (concrete != null && concrete.canRecordTo(callTarget.graph().getAssumptions())) {
+            return getAssumptionInlineInfo(invoke, concrete.getResult(), concrete);
+        }
+
+        // type check based inlining
+        return getTypeCheckedInlineInfo(invoke, targetMethod);
+    }
+
+    private InlineInfo getTypeCheckedAssumptionInfo(Invoke invoke, ResolvedJavaMethod method, ResolvedJavaType type) {
+        if (!checkTargetConditions(invoke, method)) {
+            return null;
+        }
+        return new TypeGuardInlineInfo(invoke, method, type);
+    }
+
+    private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+        JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile();
+        if (typeProfile == null) {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists");
+            return null;
+        }
+
+        JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes();
+        if (ptypes == null || ptypes.length <= 0) {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile");
+            return null;
+        }
+        ResolvedJavaType contextType = invoke.getContextType();
+        double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+        final OptimisticOptimizations optimisticOpts = context.getOptimisticOptimizations();
+        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+            if (!optimisticOpts.inlineMonomorphicCalls()) {
+                InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
+                return null;
+            }
+
+            ResolvedJavaType type = ptypes[0].getType();
+            assert type.isArray() || type.isConcrete();
+            ResolvedJavaMethod concrete = type.resolveConcreteMethod(targetMethod, contextType);
+            if (!checkTargetConditions(invoke, concrete)) {
+                return null;
+            }
+            return new TypeGuardInlineInfo(invoke, concrete, type);
+        } else {
+            invoke.setPolymorphic(true);
+
+            if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+                return null;
+            }
+            if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+                // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
+                // the number of types is lower than what can be recorded in a type profile
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
+                                notRecordedTypeProbability * 100);
+                return null;
+            }
+
+            // Find unique methods and their probabilities.
+            ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
+            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
+            for (int i = 0; i < ptypes.length; i++) {
+                ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType);
+                if (concrete == null) {
+                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method");
+                    return null;
+                }
+                int index = concreteMethods.indexOf(concrete);
+                double curProbability = ptypes[i].getProbability();
+                if (index < 0) {
+                    index = concreteMethods.size();
+                    concreteMethods.add(concrete);
+                    concreteMethodsProbabilities.add(curProbability);
+                } else {
+                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
+                }
+            }
+
+            // Clear methods that fall below the threshold.
+            if (notRecordedTypeProbability > 0) {
+                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
+                ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
+                for (int i = 0; i < concreteMethods.size(); ++i) {
+                    if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
+                        newConcreteMethods.add(concreteMethods.get(i));
+                        newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+                    }
+                }
+
+                if (newConcreteMethods.isEmpty()) {
+                    // No method left that is worth inlining.
+                    InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
+                                    concreteMethods.size());
+                    return null;
+                }
+
+                concreteMethods = newConcreteMethods;
+                concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+            }
+
+            if (concreteMethods.size() > maxMethodPerInlining) {
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
+                return null;
+            }
+
+            // Clean out types whose methods are no longer available.
+            ArrayList<JavaTypeProfile.ProfiledType> usedTypes = new ArrayList<>();
+            ArrayList<Integer> typesToConcretes = new ArrayList<>();
+            for (JavaTypeProfile.ProfiledType type : ptypes) {
+                ResolvedJavaMethod concrete = type.getType().resolveConcreteMethod(targetMethod, contextType);
+                int index = concreteMethods.indexOf(concrete);
+                if (index == -1) {
+                    notRecordedTypeProbability += type.getProbability();
+                } else {
+                    assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
+                    usedTypes.add(type);
+                    typesToConcretes.add(index);
+                }
+            }
+
+            if (usedTypes.isEmpty()) {
+                // No type left that is worth checking for.
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+                return null;
+            }
+
+            for (ResolvedJavaMethod concrete : concreteMethods) {
+                if (!checkTargetConditions(invoke, concrete)) {
+                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+                    return null;
+                }
+            }
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, usedTypes, typesToConcretes, notRecordedTypeProbability);
+        }
+    }
+
+    private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, AssumptionResult<?> takenAssumption) {
+        assert concrete.isConcrete();
+        if (checkTargetConditions(invoke, concrete)) {
+            return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
+        }
+        return null;
+    }
+
+    private InlineInfo getExactInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+        assert targetMethod.isConcrete();
+        if (checkTargetConditions(invoke, targetMethod)) {
+            return new ExactInlineInfo(invoke, targetMethod);
+        }
+        return null;
+    }
+
+    @SuppressWarnings("try")
+    private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation) {
+        StructuredGraph callerGraph = callerCallsiteHolder.graph();
+        InlineInfo calleeInfo = calleeInvocation.callee();
+        try {
+            try (Debug.Scope scope = Debug.scope("doInline", callerGraph); Debug.Scope s = Debug.methodMetricsScope("InlineEnhancement", MethodMetricsInlineeScopeInfo.create(), false)) {
+                Set<Node> canonicalizedNodes = Node.newSet();
+                calleeInfo.invoke().asNode().usages().snapshotTo(canonicalizedNodes);
+                Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context));
+                canonicalizedNodes.addAll(parameterUsages);
+                counterInliningRuns.increment();
+                Debug.dump(Debug.INFO_LOG_LEVEL, callerGraph, "after %s", calleeInfo);
+
+                Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
+
+                canonicalizer.applyIncremental(callerGraph, context, canonicalizedNodes);
+
+                // process invokes that are possibly created during canonicalization
+                for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+                    if (newNode instanceof Invoke) {
+                        callerCallsiteHolder.pushInvoke((Invoke) newNode);
+                    }
+                }
+
+                callerCallsiteHolder.computeProbabilities();
+
+                counterInliningPerformed.increment();
+            }
+        } catch (BailoutException bailout) {
+            throw bailout;
+        } catch (AssertionError | RuntimeException e) {
+            throw new GraalError(e).addContext(calleeInfo.toString());
+        } catch (GraalError e) {
+            throw e.addContext(calleeInfo.toString());
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     *
+     * This method attempts:
+     * <ol>
+     * <li>to inline at the callsite given by <code>calleeInvocation</code>, where that callsite
+     * belongs to the {@link CallsiteHolderExplorable} at the top of the {@link #graphQueue}
+     * maintained in this class.</li>
+     * <li>otherwise, to devirtualize the callsite in question.</li>
+     * </ol>
+     *
+     * @return true iff inlining was actually performed
+     */
+    private boolean tryToInline(MethodInvocation calleeInvocation, int inliningDepth) {
+        CallsiteHolderExplorable callerCallsiteHolder = (CallsiteHolderExplorable) currentGraph();
+        InlineInfo calleeInfo = calleeInvocation.callee();
+        assert callerCallsiteHolder.containsInvoke(calleeInfo.invoke());
+        counterInliningConsidered.increment();
+
+        if (inliningPolicy.isWorthInlining(context.getReplacements(), calleeInvocation, inliningDepth, true)) {
+            doInline(callerCallsiteHolder, calleeInvocation);
+            return true;
+        }
+
+        if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+            calleeInfo.tryToDevirtualizeInvoke(new Providers(context));
+        }
+
+        return false;
+    }
+
+    /**
+     * This method picks one of the callsites belonging to the current
+     * {@link CallsiteHolderExplorable}. Provided the callsite qualifies to be analyzed for
+     * inlining, this method prepares a new stack top in {@link InliningData} for such callsite,
+     * which comprises:
+     * <ul>
+     * <li>preparing a summary of feasible targets, ie preparing an {@link InlineInfo}</li>
+     * <li>based on it, preparing the stack top proper which consists of:</li>
+     * <ul>
+     * <li>one {@link MethodInvocation}</li>
+     * <li>a {@link CallsiteHolder} for each feasible target</li>
+     * </ul>
+     * </ul>
+     *
+     * <p>
+     * The thus prepared "stack top" is needed by {@link #moveForward()} to explore the space of
+     * inlining decisions (each decision one of: backtracking, delving, inlining).
+     * </p>
+     *
+     * <p>
+     * The {@link InlineInfo} used to get things rolling is kept around in the
+     * {@link MethodInvocation}, it will be needed in case of inlining, see
+     * {@link InlineInfo#inline(Providers)}
+     * </p>
+     */
+    private void processNextInvoke() {
+        CallsiteHolderExplorable callsiteHolder = (CallsiteHolderExplorable) currentGraph();
+        Invoke invoke = callsiteHolder.popInvoke();
+        InlineInfo info = getInlineInfo(invoke);
+
+        if (info != null) {
+            info.populateInlinableElements(context, currentGraph().graph(), canonicalizer);
+            double invokeProbability = callsiteHolder.invokeProbability(invoke);
+            double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
+            MethodInvocation methodInvocation = new MethodInvocation(info, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
+            pushInvocationAndGraphs(methodInvocation);
+        }
+    }
+
+    /**
+     * Gets the freshly instantiated arguments.
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(org.graalvm.compiler.nodes.ValueNode)}</li>
+     * <li>a fixed-param, ie a {@link ParameterNode} receiving a freshly instantiated argument</li>
+     * </uL>
+     * </p>
+     *
+     * @return the positions of freshly instantiated arguments in the argument list of the
+     *         <code>invoke</code>, or null if no such positions exist.
+     */
+    public static BitSet freshlyInstantiatedArguments(Invoke invoke, Set<ParameterNode> fixedParams) {
+        assert fixedParams != null;
+        assert paramsAndInvokeAreInSameGraph(invoke, fixedParams);
+        BitSet result = null;
+        int argIdx = 0;
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            assert arg != null;
+            if (isFreshInstantiation(arg) || fixedParams.contains(arg)) {
+                if (result == null) {
+                    result = new BitSet();
+                }
+                result.set(argIdx);
+            }
+            argIdx++;
+        }
+        return result;
+    }
+
+    private static boolean paramsAndInvokeAreInSameGraph(Invoke invoke, Set<ParameterNode> fixedParams) {
+        if (fixedParams.isEmpty()) {
+            return true;
+        }
+        for (ParameterNode p : fixedParams) {
+            if (p.graph() != invoke.asNode().graph()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int graphCount() {
+        return graphQueue.size();
+    }
+
+    public boolean hasUnprocessedGraphs() {
+        return !graphQueue.isEmpty();
+    }
+
+    private CallsiteHolder currentGraph() {
+        return graphQueue.peek();
+    }
+
+    private void popGraph() {
+        graphQueue.pop();
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    private void popGraphs(int count) {
+        assert count >= 0;
+        for (int i = 0; i < count; i++) {
+            graphQueue.pop();
+        }
+    }
+
+    private static final Object[] NO_CONTEXT = {};
+
+    /**
+     * Gets the call hierarchy of this inlining from outer most call to inner most callee.
+     */
+    private Object[] inliningContext() {
+        if (!Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            return NO_CONTEXT;
+        }
+        Object[] result = new Object[graphQueue.size()];
+        int i = 0;
+        for (CallsiteHolder g : graphQueue) {
+            result[i++] = g.method();
+        }
+        return result;
+    }
+
+    private MethodInvocation currentInvocation() {
+        return invocationQueue.peekFirst();
+    }
+
+    private void pushInvocationAndGraphs(MethodInvocation methodInvocation) {
+        invocationQueue.addFirst(methodInvocation);
+        InlineInfo info = methodInvocation.callee();
+        maxGraphs += info.numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            CallsiteHolder ch = methodInvocation.buildCallsiteHolderForElement(i);
+            assert !contains(ch.graph());
+            graphQueue.push(ch);
+            assert graphQueue.size() <= maxGraphs;
+        }
+    }
+
+    private void popInvocation() {
+        maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        invocationQueue.removeFirst();
+    }
+
+    public int countRecursiveInlining(ResolvedJavaMethod method) {
+        int count = 0;
+        for (CallsiteHolder callsiteHolder : graphQueue) {
+            if (method.equals(callsiteHolder.method())) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int inliningDepth() {
+        assert invocationQueue.size() > 0;
+        return invocationQueue.size() - 1;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder("Invocations: ");
+
+        for (MethodInvocation invocation : invocationQueue) {
+            if (invocation.callee() != null) {
+                result.append(invocation.callee().numberOfMethods());
+                result.append("x ");
+                result.append(invocation.callee().invoke());
+                result.append("; ");
+            }
+        }
+
+        result.append("\nGraphs: ");
+        for (CallsiteHolder graph : graphQueue) {
+            result.append(graph.graph());
+            result.append("; ");
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Gets a stack trace representing the current inlining stack represented by this object.
+     */
+    public Collection<StackTraceElement> getInvocationStackTrace() {
+        List<StackTraceElement> result = new ArrayList<>();
+        for (CallsiteHolder graph : graphQueue) {
+            result.add(graph.method().asStackTraceElement(0));
+        }
+
+        return result;
+    }
+
+    private boolean contains(StructuredGraph graph) {
+        assert graph != null;
+        for (CallsiteHolder info : graphQueue) {
+            if (info.graph() == graph) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * <p>
+     * The stack realized by {@link InliningData} grows and shrinks as choices are made among the
+     * alternatives below:
+     * <ol>
+     * <li>not worth inlining: pop stack top, which comprises:
+     * <ul>
+     * <li>pop any remaining graphs not yet delved into</li>
+     * <li>pop the current invocation</li>
+     * </ul>
+     * </li>
+     * <li>{@link #processNextInvoke() delve} into one of the callsites hosted in the current graph,
+     * such callsite is explored next by {@link #moveForward()}</li>
+     * <li>{@link #tryToInline(MethodInvocation, int) try to inline}: move past the current graph
+     * (remove it from the topmost element).
+     * <ul>
+     * <li>If that was the last one then {@link #tryToInline(MethodInvocation, int) try to inline}
+     * the callsite under consideration (ie, the "current invocation").</li>
+     * <li>Whether inlining occurs or not, that callsite is removed from the top of
+     * {@link InliningData} .</li>
+     * </ul>
+     * </li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * Some facts about the alternatives above:
+     * <ul>
+     * <li>the first step amounts to backtracking, the 2nd one to depth-search, and the 3rd one also
+     * involves backtracking (however possibly after inlining).</li>
+     * <li>the choice of abandon-and-backtrack or delve-into depends on
+     * {@link InliningPolicy#isWorthInlining} and {@link InliningPolicy#continueInlining}.</li>
+     * <li>the 3rd choice is picked whenever none of the previous choices are made</li>
+     * </ul>
+     * </p>
+     *
+     * @return true iff inlining was actually performed
+     */
+    @SuppressWarnings("try")
+    public boolean moveForward() {
+
+        final MethodInvocation currentInvocation = currentInvocation();
+
+        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation, inliningDepth(), false));
+        if (backtrack) {
+            int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
+            assert remainingGraphs > 0;
+            popGraphs(remainingGraphs);
+            popInvocation();
+            return false;
+        }
+
+        final boolean delve = currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(currentGraph().graph());
+        if (delve) {
+            processNextInvoke();
+            return false;
+        }
+
+        popGraph();
+        if (currentInvocation.isRoot()) {
+            return false;
+        }
+
+        // try to inline
+        assert currentInvocation.callee().invoke().asNode().isAlive();
+        currentInvocation.incrementProcessedGraphs();
+        if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
+            /*
+             * "all of currentInvocation's graphs processed" amounts to
+             * "all concrete methods that come into question already had the callees they contain analyzed for inlining"
+             */
+            popInvocation();
+            try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
+                if (tryToInline(currentInvocation, inliningDepth() + 1)) {
+                    // Report real progress only if we inline into the root graph
+                    return currentGraph().graph() == rootGraph;
+                }
+                return false;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks an invariant that {@link #moveForward()} must maintain: "the top invocation records
+     * how many concrete target methods (for it) remain on the {@link #graphQueue}; those targets
+     * 'belong' to the current invocation in question.
+     */
+    private boolean topGraphsForTopInvocation() {
+        if (invocationQueue.isEmpty()) {
+            assert graphQueue.isEmpty();
+            return true;
+        }
+        if (currentInvocation().isRoot()) {
+            if (!graphQueue.isEmpty()) {
+                assert graphQueue.size() == 1;
+            }
+            return true;
+        }
+        final int remainingGraphs = currentInvocation().totalGraphs() - currentInvocation().processedGraphs();
+        final Iterator<CallsiteHolder> iter = graphQueue.iterator();
+        for (int i = (remainingGraphs - 1); i >= 0; i--) {
+            if (!iter.hasNext()) {
+                assert false;
+                return false;
+            }
+            CallsiteHolder queuedTargetCH = iter.next();
+            Inlineable targetIE = currentInvocation().callee().inlineableElementAt(i);
+            InlineableGraph targetIG = (InlineableGraph) targetIE;
+            assert queuedTargetCH.method().equals(targetIG.getGraph().method());
+        }
+        return true;
+    }
+
+    /**
+     * This method checks invariants for this class. Named after shorthand for "internal
+     * representation is ok".
+     */
+    public boolean repOK() {
+        assert topGraphsForTopInvocation();
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningIterator.java
new file mode 100644
index 0000000..dee9ca5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningIterator.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+
+/**
+ * Given a graph, visit all fixed nodes in dominator-based order, collecting in the process the
+ * {@link Invoke} nodes with {@link MethodCallTargetNode}. Such list of callsites is returned by
+ * {@link #apply()}
+ */
+public class InliningIterator {
+
+    private final StartNode start;
+    private final Deque<FixedNode> nodeQueue;
+    private final NodeBitMap queuedNodes;
+
+    public InliningIterator(StructuredGraph graph) {
+        this.start = graph.start();
+        this.nodeQueue = new ArrayDeque<>();
+        this.queuedNodes = graph.createNodeBitMap();
+        assert start.isAlive();
+    }
+
+    public LinkedList<Invoke> apply() {
+        LinkedList<Invoke> invokes = new LinkedList<>();
+        FixedNode current;
+        forcedQueue(start);
+
+        while ((current = nextQueuedNode()) != null) {
+            assert current.isAlive();
+
+            if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
+                if (current != start) {
+                    invokes.addLast((Invoke) current);
+                }
+                queueSuccessors(current);
+            } else if (current instanceof LoopBeginNode) {
+                queueSuccessors(current);
+            } else if (current instanceof LoopEndNode) {
+                // nothing to do
+            } else if (current instanceof AbstractMergeNode) {
+                queueSuccessors(current);
+            } else if (current instanceof FixedWithNextNode) {
+                queueSuccessors(current);
+            } else if (current instanceof EndNode) {
+                queueMerge((EndNode) current);
+            } else if (current instanceof ControlSinkNode) {
+                // nothing to do
+            } else if (current instanceof ControlSplitNode) {
+                queueSuccessors(current);
+            } else {
+                assert false : current;
+            }
+        }
+
+        assert invokes.size() == count(start.graph().getInvokes());
+        return invokes;
+    }
+
+    private void queueSuccessors(FixedNode x) {
+        for (Node node : x.successors()) {
+            queue(node);
+        }
+    }
+
+    private void queue(Node node) {
+        if (node != null && !queuedNodes.isMarked(node)) {
+            forcedQueue(node);
+        }
+    }
+
+    private void forcedQueue(Node node) {
+        queuedNodes.mark(node);
+        nodeQueue.addFirst((FixedNode) node);
+    }
+
+    private FixedNode nextQueuedNode() {
+        if (nodeQueue.isEmpty()) {
+            return null;
+        }
+
+        FixedNode result = nodeQueue.removeFirst();
+        assert queuedNodes.isMarked(result);
+        return result;
+    }
+
+    private void queueMerge(AbstractEndNode end) {
+        AbstractMergeNode merge = end.merge();
+        if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
+            queuedNodes.mark(merge);
+            nodeQueue.add(merge);
+        }
+    }
+
+    private boolean visitedAllEnds(AbstractMergeNode merge) {
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static int count(Iterable<Invoke> invokes) {
+        int count = 0;
+        Iterator<Invoke> iterator = invokes.iterator();
+        while (iterator.hasNext()) {
+            iterator.next();
+            count++;
+        }
+        return count;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/MethodInvocation.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/MethodInvocation.java
new file mode 100644
index 0000000..ab6b2ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/MethodInvocation.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.inlining.walker;
+
+import java.util.BitSet;
+
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
+import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
+import org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * <p>
+ * An instance of this class denotes a callsite being analyzed for inlining.
+ * </p>
+ * <p>
+ * Each element of the {@link InliningData} stack contains one such instance, the accompanying
+ * {@link CallsiteHolder}s in that element represent feasible targets for the callsite in question.
+ * </p>
+ *
+ * @see InliningData#moveForward()
+ */
+public class MethodInvocation {
+
+    private final InlineInfo callee;
+    private final double probability;
+    private final double relevance;
+
+    private int processedGraphs;
+
+    /**
+     * <p>
+     * The immutable positions of freshly instantiated arguments (ie, positions in
+     * <code>callee.invoke.callTarget.arguments</code>).
+     * </p>
+     *
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(org.graalvm.compiler.nodes.ValueNode)}</li>
+     * <li>a fixed-param of the graph containing the callsite (ie, of <code>callee.graph()</code>
+     * that contains <code>callee.invoke</code>)</li>
+     * </uL>
+     * </p>
+     *
+     * <p>
+     * Given those positions, the
+     * {@link org.graalvm.compiler.phases.common.inlining.walker.CallsiteHolderExplorable}
+     * instantiated in {@link #buildCallsiteHolderForElement(int)} can determine which of <i>its</i>
+     * parameters are fixed.
+     * </p>
+     */
+    private final BitSet freshlyInstantiatedArguments;
+
+    private final int sizeFreshArgs;
+
+    public MethodInvocation(InlineInfo info, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
+        this.callee = info;
+        this.probability = probability;
+        this.relevance = relevance;
+        this.freshlyInstantiatedArguments = freshlyInstantiatedArguments;
+        this.sizeFreshArgs = freshlyInstantiatedArguments == null ? 0 : freshlyInstantiatedArguments.cardinality();
+    }
+
+    public void incrementProcessedGraphs() {
+        processedGraphs++;
+        assert processedGraphs <= callee.numberOfMethods();
+    }
+
+    public int processedGraphs() {
+        assert processedGraphs <= callee.numberOfMethods();
+        return processedGraphs;
+    }
+
+    public int totalGraphs() {
+        return callee.numberOfMethods();
+    }
+
+    public InlineInfo callee() {
+        return callee;
+    }
+
+    public double probability() {
+        return probability;
+    }
+
+    public double relevance() {
+        return relevance;
+    }
+
+    public boolean isRoot() {
+        return callee == null;
+    }
+
+    public BitSet getFreshlyInstantiatedArguments() {
+        return freshlyInstantiatedArguments;
+    }
+
+    public int getSizeFreshArgs() {
+        return sizeFreshArgs;
+    }
+
+    public CallsiteHolder buildCallsiteHolderForElement(int index) {
+        Inlineable elem = callee.inlineableElementAt(index);
+        assert elem instanceof InlineableGraph;
+        InlineableGraph ig = (InlineableGraph) elem;
+        final double invokeProbability = probability * callee.probabilityAt(index);
+        final double invokeRelevance = relevance * callee.relevanceAt(index);
+        return new CallsiteHolderExplorable(ig.getGraph(), invokeProbability, invokeRelevance, freshlyInstantiatedArguments);
+    }
+
+    @Override
+    public String toString() {
+        if (isRoot()) {
+            return "<root>";
+        }
+        CallTargetNode callTarget = callee.invoke().callTarget();
+        if (callTarget instanceof MethodCallTargetNode) {
+            ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+            return calleeMethod.format("Invoke#%H.%n(%p)");
+        } else {
+            return "Invoke#" + callTarget.targetName();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/ExtractInstrumentationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/ExtractInstrumentationPhase.java
new file mode 100644
index 0000000..a6cc338
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/ExtractInstrumentationPhase.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.instrumentation;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeFlood;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractLocalNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationBeginNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationEndNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+/**
+ * The {@code ExtractInstrumentationPhase} extracts the instrumentation (whose boundary are
+ * indicated by instrumentationBegin and instrumentationEnd), and insert an
+ * {@link InstrumentationNode} in the graph to take place of the instrumentation.
+ */
+public class ExtractInstrumentationPhase extends BasePhase<HighTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, HighTierContext context) {
+        for (InstrumentationBeginNode begin : graph.getNodes().filter(InstrumentationBeginNode.class)) {
+            Instrumentation instrumentation = new Instrumentation(begin);
+            if (begin.isAnchored() || begin.getTarget() != null) {
+                // we create InstrumentationNode when the instrumentation is anchored (when 0 is
+                // passed to instrumentationBegin), or when the instrumentation is associated with
+                // some target.
+                InstrumentationNode instrumentationNode = graph.addWithoutUnique(new InstrumentationNode(begin.getTarget(), begin.isAnchored()));
+                graph.addBeforeFixed(begin, instrumentationNode);
+                FrameState currentState = begin.stateAfter();
+                FrameState newState = graph.addWithoutUnique(new FrameState(currentState.outerFrameState(), currentState.getCode(), currentState.bci, 0, 0,
+                                0, currentState.rethrowException(), currentState.duringCall(), null,
+                                Collections.<EscapeObjectState> emptyList()));
+                instrumentationNode.setStateBefore(newState);
+
+                StructuredGraph instrumentationGraph = instrumentation.genInstrumentationGraph(graph, instrumentationNode);
+                new DeadCodeEliminationPhase().apply(instrumentationGraph, false);
+                instrumentationNode.setInstrumentationGraph(instrumentationGraph);
+                Debug.dump(Debug.INFO_LOG_LEVEL, instrumentationGraph, "After extracted instrumentation at %s", instrumentation);
+            }
+            instrumentation.unlink();
+        }
+    }
+
+    /**
+     * This class denotes the instrumentation code being detached from the graph.
+     */
+    private static class Instrumentation {
+
+        private InstrumentationBeginNode begin;
+        private InstrumentationEndNode end;
+        private NodeBitMap nodes;
+
+        Instrumentation(InstrumentationBeginNode begin) {
+            this.begin = begin;
+
+            // travel along the control flow for the paired InstrumentationEndNode
+            NodeFlood cfgFlood = begin.graph().createNodeFlood();
+            cfgFlood.add(begin.next());
+            for (Node current : cfgFlood) {
+                if (current instanceof InstrumentationEndNode) {
+                    this.end = (InstrumentationEndNode) current;
+                } else if (current instanceof LoopEndNode) {
+                    // do nothing
+                } else if (current instanceof AbstractEndNode) {
+                    cfgFlood.add(((AbstractEndNode) current).merge());
+                } else {
+                    cfgFlood.addAll(current.successors());
+                }
+            }
+
+            if (this.end == null) {
+                // this may be caused by DeoptimizationReason.Unresolved
+                throw GraalError.shouldNotReachHere("could not find invocation to instrumentationEnd()");
+            }
+
+            // all FloatingNodes (except AbstractLocalNodes), which the FixedNodes in the
+            // instrumentation depend on, are included in the instrumentation if they are not used
+            // by other nodes in the graph
+            NodeBitMap cfgNodes = cfgFlood.getVisited();
+            NodeFlood dfgFlood = begin.graph().createNodeFlood();
+            dfgFlood.addAll(cfgNodes);
+            dfgFlood.add(begin.stateAfter());
+            for (Node current : dfgFlood) {
+                for (Position pos : current.inputPositions()) {
+                    Node input = pos.get(current);
+                    if (pos.getInputType() == InputType.Value) {
+                        if (current instanceof FrameState) {
+                            // don't include value input for the FrameState
+                            continue;
+                        }
+                        if (!(input instanceof FloatingNode)) {
+                            // we only consider FloatingNode for this input type
+                            continue;
+                        }
+                        if (input instanceof AbstractLocalNode) {
+                            // AbstractLocalNode is invalid in the instrumentation sub-graph
+                            continue;
+                        }
+                        if (shouldIncludeValueInput((FloatingNode) input, cfgNodes)) {
+                            dfgFlood.add(input);
+                        }
+                    } else {
+                        dfgFlood.add(input);
+                    }
+                }
+            }
+            this.nodes = dfgFlood.getVisited();
+        }
+
+        /**
+         * Copy the instrumentation nodes into a separate graph. During the copying, this method
+         * updates the input of the given InstrumentationNode. Hence, it is essential that the given
+         * InstrumentationNode is alive.
+         */
+        StructuredGraph genInstrumentationGraph(StructuredGraph oldGraph, InstrumentationNode instrumentationNode) {
+            StructuredGraph instrumentationGraph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID);
+            Map<Node, Node> replacements = Node.newMap();
+            int index = 0; // for ParameterNode index
+            for (Node current : nodes) {
+                // mark any input that is not included in the instrumentation a weak dependency
+                for (Node input : current.inputs()) {
+                    if (input instanceof ValueNode) {
+                        ValueNode valueNode = (ValueNode) input;
+                        if (!nodes.isMarked(input) && !replacements.containsKey(input)) {
+                            // create a ParameterNode in case the input is not within the
+                            // instrumentation
+                            ParameterNode parameter = new ParameterNode(index++, StampPair.createSingle(valueNode.stamp()));
+                            instrumentationGraph.addWithoutUnique(parameter);
+                            instrumentationNode.addWeakDependency(valueNode);
+                            replacements.put(input, parameter);
+                        }
+                    }
+                }
+            }
+            replacements = instrumentationGraph.addDuplicates(nodes, oldGraph, nodes.count(), replacements);
+            instrumentationGraph.start().setNext((FixedNode) replacements.get(begin.next()));
+            instrumentationGraph.start().setStateAfter((FrameState) replacements.get(begin.stateAfter()));
+            replacements.get(end).replaceAtPredecessor(instrumentationGraph.addWithoutUnique(new ReturnNode(null)));
+            return instrumentationGraph;
+        }
+
+        /**
+         * @return true if the given FloatingNode does not contain any FixedNode input of types
+         *         other than InputType.Value.
+         */
+        private static boolean shouldIncludeValueInput(FloatingNode node, NodeBitMap cfgNodes) {
+            for (Position pos : node.inputPositions()) {
+                if (pos.getInputType() == InputType.Value) {
+                    continue;
+                }
+                Node input = pos.get(node);
+                if (input instanceof FixedNode && !cfgNodes.isMarked(input)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        void unlink() {
+            FixedNode next = end.next();
+            end.setNext(null);
+            begin.replaceAtPredecessor(next);
+            GraphUtil.killCFG(begin);
+        }
+
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/HighTierReconcileInstrumentationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/HighTierReconcileInstrumentationPhase.java
new file mode 100644
index 0000000..6663f2b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/HighTierReconcileInstrumentationPhase.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.instrumentation;
+
+import java.util.HashMap;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeFlood;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.MonitorProxyNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.Phase;
+
+/**
+ * The {@code HighTierReconcileInstrumentationPhase} reconciles the InstrumentationNodes according
+ * to the optimizations at the high tier, e.g., the partial escape analysis. It clones the
+ * InstrumentationNode and inserts at the CommitAllocationNode that includes the allocation/lock
+ * targeted by the InstrumentationNode.
+ */
+public class HighTierReconcileInstrumentationPhase extends Phase {
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        // iterate through all CommitAllocationNodes, and clone the InstrumentationNodes targeting
+        // allocation/lock held by this CommitAllocationNode
+        for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) {
+            InstrumentationAggregation aggr = new InstrumentationAggregation(graph, commit);
+            // iterate through all VirtualObjectNodes held by the CommitAllocationNode, clone if any
+            // InstrumentationNode targets one of these VirtualObjectNodes
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+                    if (isCFGAccessible(instrumentationNode, commit) && instrumentationNode.getTarget() == virtual) {
+                        // clone InstrumentationNode when the CommitAllocationNode is accessible
+                        // from the InstrumentationNode, and the InstrumentationNode's target
+                        // matches the given VirtualObjectNode
+                        aggr.insertClone(instrumentationNode, getAllocatedObject(graph, commit, virtual));
+                    }
+                }
+            }
+            // iterate through all MonitorIdNodes held by the CommitAllocationNode, clone if any
+            // InstrumentationNode targets one of these MonitorIdNodes (via MonitorProxyNode)
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                    for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+                        if (isCFGAccessible(instrumentationNode, commit) && instrumentationNode.getTarget() instanceof MonitorProxyNode &&
+                                        ((MonitorProxyNode) instrumentationNode.getTarget()).getMonitorId() == monitorId) {
+                            // clone InstrumentationNode when the CommitAllocationNode is accessible
+                            // from the InstrumentationNode, and the InstrumentationNode's target is
+                            // a MonitorProxyNode that matches the MonitorIdNode
+                            aggr.insertClone(instrumentationNode, graph.addWithoutUnique(new MonitorProxyNode(getAllocatedObject(graph, commit, virtual), monitorId)));
+                        }
+                    }
+                }
+            }
+        }
+        // remove InstrumentationNodes that still target virtual nodes
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            ValueNode target = instrumentationNode.getTarget();
+            if (target instanceof VirtualObjectNode) {
+                graph.removeFixed(instrumentationNode);
+            } else if (target instanceof MonitorProxyNode) {
+                MonitorProxyNode proxy = (MonitorProxyNode) target;
+                if (proxy.object() == null) {
+                    graph.removeFixed(instrumentationNode);
+                }
+            }
+        }
+    }
+
+    /**
+     * The {@code InstrumentationAggregation} maintains an inserting location after
+     * CommitAllocationNode such that the cloned InstrumentationNodes would appear in the order of
+     * the allocations.
+     */
+    class InstrumentationAggregation {
+
+        private StructuredGraph graph;
+        private CommitAllocationNode commit;
+        private FixedWithNextNode insertAfter;
+
+        InstrumentationAggregation(StructuredGraph graph, CommitAllocationNode commit) {
+            this.graph = graph;
+            this.commit = commit;
+            this.insertAfter = commit;
+        }
+
+        void insertClone(InstrumentationNode instrumentationNode, ValueNode newTarget) {
+            InstrumentationNode clone = (InstrumentationNode) instrumentationNode.copyWithInputs();
+            // update the clone instrumentation node with the new target
+            clone.replaceFirstInput(clone.getTarget(), newTarget);
+            // update weak dependencies of the clone instrumentation node where the dependency
+            // is also a VirtualObjectNode. This is common when one allocation in the
+            // CommitAllocationNode depends on another allocation.
+            for (ValueNode input : clone.getWeakDependencies()) {
+                if ((input instanceof VirtualObjectNode) && (commit.getVirtualObjects().contains(input))) {
+                    clone.replaceFirstInput(input, getAllocatedObject(graph, commit, (VirtualObjectNode) input));
+                }
+            }
+            graph.addAfterFixed(insertAfter, clone);
+            insertAfter = clone;
+        }
+
+    }
+
+    private final HashMap<FixedWithNextNode, NodeFlood> cachedNodeFloods = new HashMap<>();
+
+    /**
+     * @return true if there is a control flow path between {@code from} and {@code to}.
+     */
+    private boolean isCFGAccessible(FixedWithNextNode from, FixedNode to) {
+        NodeFlood flood = cachedNodeFloods.get(from);
+        if (flood == null) {
+            flood = from.graph().createNodeFlood();
+            flood.add(from);
+            for (Node current : flood) {
+                if (current instanceof LoopEndNode) {
+                    continue;
+                } else if (current instanceof AbstractEndNode) {
+                    flood.add(((AbstractEndNode) current).merge());
+                } else {
+                    flood.addAll(current.successors());
+                }
+            }
+            cachedNodeFloods.put(from, flood);
+        }
+        return flood.isMarked(to);
+    }
+
+    /**
+     * Get/generate the AllocatedObjectNode for the given VirtualObjectNode in the given
+     * CommitAllocationNode.
+     */
+    private static AllocatedObjectNode getAllocatedObject(StructuredGraph graph, CommitAllocationNode commit, VirtualObjectNode virtual) {
+        // search if the AllocatedObjectNode already exists
+        for (AllocatedObjectNode allocatedObject : graph.getNodes().filter(AllocatedObjectNode.class)) {
+            if (allocatedObject.getCommit() == commit && allocatedObject.getVirtualObject() == virtual) {
+                return allocatedObject;
+            }
+        }
+        // create one if the AllocatedObjectNode does not exist
+        AllocatedObjectNode allocatedObject = graph.addWithoutUnique(new AllocatedObjectNode(virtual));
+        allocatedObject.setCommit(commit);
+        return allocatedObject;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/InlineInstrumentationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/InlineInstrumentationPhase.java
new file mode 100644
index 0000000..e8fb603
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/InlineInstrumentationPhase.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.instrumentation;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationInliningCallback;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.memory.MemoryAnchorNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.LowTierContext;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * The {code InlineInstrumentationPhase} inlines the instrumentation graph back into the graph to
+ * take place of the InstrumentationNode. Before inlining, the instrumentation graph will be passed
+ * to GuardLoweringPhase, FrameStateAssignmentPhase, LoweringPhase, and FloatingReadPhase.
+ */
+public class InlineInstrumentationPhase extends BasePhase<LowTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, LowTierContext context) {
+        Set<StructuredGraph> visited = new HashSet<>();
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            // if the target of the instrumentationNode is null while the offset is non-zero, the
+            // instrumentation is invalid.
+            if (!(instrumentationNode.isAnchored() || instrumentationNode.getTarget() != null)) {
+                graph.removeFixed(instrumentationNode);
+                continue;
+            }
+            // Clone the instrumentation in case it is shared amongst multiple InstrumentationNodes.
+            StructuredGraph instrumentationGraph = instrumentationNode.getInstrumentationGraph();
+            if (visited.contains(instrumentationGraph)) {
+                instrumentationGraph = (StructuredGraph) instrumentationGraph.copy();
+                instrumentationNode.setInstrumentationGraph(instrumentationGraph);
+            }
+            visited.add(instrumentationGraph);
+        }
+        // at this point, instrumentation graphs are not shared and can apply changes according to
+        // the context of the InstrumentationNode
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            StructuredGraph instrumentationGraph = instrumentationNode.getInstrumentationGraph();
+            // notify instrumentation nodes of the preInlineInstrumentation event
+            for (Node node : instrumentationGraph.getNodes()) {
+                if (node instanceof InstrumentationInliningCallback) {
+                    ((InstrumentationInliningCallback) node).preInlineInstrumentation(instrumentationNode);
+                }
+            }
+            // pre-process the instrumentation graph
+            new GuardLoweringPhase().apply(instrumentationGraph, null);
+            new FrameStateAssignmentPhase().apply(instrumentationGraph, false);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.LOW_TIER).apply(instrumentationGraph, context);
+            new FloatingReadPhase(true, true).apply(instrumentationGraph, false);
+
+            final StartNode entryPointNode = instrumentationGraph.start();
+            MemoryAnchorNode anchor = instrumentationGraph.add(new MemoryAnchorNode());
+            instrumentationGraph.start().replaceAtUsages(InputType.Memory, anchor);
+            if (anchor.hasNoUsages()) {
+                anchor.safeDelete();
+            } else {
+                instrumentationGraph.addAfterFixed(entryPointNode, anchor);
+            }
+
+            ArrayList<Node> nodes = new ArrayList<>(instrumentationGraph.getNodes().count());
+            FixedNode firstCFGNode = entryPointNode.next();
+            // locate return nodes
+            ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
+            for (Node node : instrumentationGraph.getNodes()) {
+                if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof ParameterNode) {
+                    // Do nothing.
+                } else {
+                    nodes.add(node);
+                    if (node instanceof ReturnNode) {
+                        returnNodes.add((ReturnNode) node);
+                    }
+                }
+            }
+
+            final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(instrumentationNode);
+            DuplicationReplacement localReplacement = new DuplicationReplacement() {
+                @Override
+                public Node replacement(Node replacement) {
+                    if (replacement instanceof ParameterNode) {
+                        // rewire weak dependencies. In case of invalid input, we replace it with a
+                        // constant null
+                        ValueNode value = instrumentationNode.getWeakDependency(((ParameterNode) replacement).index());
+                        if (value == null || value.isDeleted() || value instanceof VirtualObjectNode || value.stamp().getStackKind() != JavaKind.Object) {
+                            return graph.unique(new ConstantNode(JavaConstant.NULL_POINTER, ((ParameterNode) replacement).stamp()));
+                        } else {
+                            return value;
+                        }
+                    } else if (replacement == entryPointNode) {
+                        return prevBegin;
+                    }
+                    return replacement;
+                }
+            };
+            // clone instrumentation nodes into the graph and replace the InstrumentationNode
+            Map<Node, Node> duplicates = graph.addDuplicates(nodes, instrumentationGraph, instrumentationGraph.getNodeCount(), localReplacement);
+            FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+            instrumentationNode.replaceAtPredecessor(firstCFGNodeDuplicate);
+
+            if (!returnNodes.isEmpty()) {
+                if (returnNodes.size() == 1) {
+                    ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
+                    returnNode.replaceAndDelete(instrumentationNode);
+                } else {
+                    ArrayList<ReturnNode> returnDuplicates = new ArrayList<>(returnNodes.size());
+                    for (ReturnNode returnNode : returnNodes) {
+                        returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
+                    }
+                    AbstractMergeNode merge = graph.add(new MergeNode());
+
+                    for (ReturnNode returnNode : returnDuplicates) {
+                        EndNode endNode = graph.add(new EndNode());
+                        merge.addForwardEnd(endNode);
+                        returnNode.replaceAndDelete(endNode);
+                    }
+
+                    merge.setNext(instrumentationNode);
+                }
+            }
+
+            // The InstrumentationNode may be inlined. In such case, update the outerFrameState of
+            // the FrameStates in the instrumentation
+            FrameState currentState = instrumentationNode.stateBefore();
+            FrameState outerFrameState = currentState.outerFrameState();
+            if (outerFrameState != null) {
+                for (Node replacee : duplicates.values()) {
+                    if (replacee instanceof FrameState) {
+                        FrameState innerFrameState = (FrameState) replacee;
+                        if (innerFrameState.outerFrameState() == null) {
+                            innerFrameState.setOuterFrameState(outerFrameState);
+                        }
+                    }
+                }
+            }
+
+            // assign FrameStates for DeoptimizingNodes
+            for (Node replacee : duplicates.values()) {
+                if (replacee instanceof DeoptimizingNode && !(replacee instanceof Invoke)) {
+                    DeoptimizingNode deoptDup = (DeoptimizingNode) replacee;
+                    if (deoptDup.canDeoptimize()) {
+                        if (deoptDup instanceof DeoptimizingNode.DeoptBefore) {
+                            ((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(currentState);
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptDuring) {
+                            DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup;
+                            assert !deoptDupDuring.hasSideEffect() : "can't use stateBefore as stateDuring for state split " + deoptDupDuring;
+                            deoptDupDuring.setStateDuring(currentState);
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptAfter) {
+                            DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup;
+                            assert !deoptDupAfter.hasSideEffect() : "can't use stateBefore as stateAfter for state split " + deoptDupAfter;
+                            deoptDupAfter.setStateAfter(currentState);
+                        }
+                    }
+                }
+            }
+
+            // notify instrumentation nodes of the postInlineInstrumentation event
+            for (Node replacee : duplicates.values()) {
+                if (replacee instanceof InstrumentationInliningCallback) {
+                    ((InstrumentationInliningCallback) replacee).postInlineInstrumentation(instrumentationNode);
+                }
+            }
+
+            graph.removeFixed(instrumentationNode);
+        }
+
+        new CanonicalizerPhase().apply(graph, context);
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/MidTierReconcileInstrumentationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/MidTierReconcileInstrumentationPhase.java
new file mode 100644
index 0000000..faf2438
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/instrumentation/MidTierReconcileInstrumentationPhase.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.instrumentation;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.MonitorProxyNode;
+import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.Phase;
+
+/**
+ * The {@code MidTierReconcileInstrumentationPhase} reconciles the InstrumentationNodes right after
+ * lowering in the mid tier. Concretely, it attempts to unproxify the targets of the
+ * InstrumentationNodes.
+ */
+public class MidTierReconcileInstrumentationPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            ValueNode target = instrumentationNode.getTarget();
+            if (target instanceof MonitorProxyNode) {
+                RawMonitorEnterNode monitorEnter = ((MonitorProxyNode) target).findFirstMatch();
+                if (monitorEnter != null) {
+                    instrumentationNode.replaceFirstInput(target, monitorEnter);
+                } else {
+                    // we cannot find valid AccessMonitorNode for the proxy, detach the
+                    // instrumentation
+                    graph.removeFixed(instrumentationNode);
+                }
+            } else if (target instanceof FixedValueAnchorNode) {
+                instrumentationNode.replaceFirstInput(target, GraphUtil.unproxify(target));
+            }
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java
new file mode 100644
index 0000000..141f4c5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common.util;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
+
+/**
+ * A simple {@link NodeEventListener} implementation that accumulates event nodes in a
+ * {@link HashSet}.
+ */
+public class HashSetNodeEventListener implements NodeEventListener {
+
+    private final Set<Node> nodes;
+    private final Set<NodeEvent> filter;
+
+    /**
+     * Creates a {@link NodeEventListener} that collects nodes from all events.
+     */
+    public HashSetNodeEventListener() {
+        this.nodes = Node.newSet();
+        this.filter = EnumSet.allOf(NodeEvent.class);
+    }
+
+    /**
+     * Creates a {@link NodeEventListener} that collects nodes from all events that match a given
+     * filter.
+     */
+    public HashSetNodeEventListener(Set<NodeEvent> filter) {
+        this.nodes = Node.newSet();
+        this.filter = filter;
+    }
+
+    /**
+     * Excludes a given event from those for which nodes are collected.
+     */
+    public HashSetNodeEventListener exclude(NodeEvent e) {
+        filter.remove(e);
+        return this;
+    }
+
+    @Override
+    public void event(NodeEvent e, Node node) {
+        if (filter.contains(e)) {
+            nodes.add(node);
+            if (node instanceof IndirectCanonicalization) {
+                for (Node usage : node.usages()) {
+                    nodes.add(usage);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the set being used to accumulate the nodes communicated to this listener.
+     */
+    public Set<Node> getNodes() {
+        return nodes;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java
new file mode 100644
index 0000000..be1e219
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugMemUseTracker;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.StableOptionValue;
+import org.graalvm.compiler.phases.contract.NodeCostUtil;
+import org.graalvm.compiler.phases.contract.PhaseSizeContract;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+/**
+ * Base class for all compiler phases. Subclasses should be stateless. There will be one global
+ * instance for each compiler phase that is shared for all compilations. VM-, target- and
+ * compilation-specific data can be passed with a context object.
+ */
+public abstract class BasePhase<C> implements PhaseSizeContract {
+
+    public static class PhaseOptions {
+        // @formatter:off
+        @Option(help = "Verify before - after relation of the relative, computed, code size of a graph", type = OptionType.Debug)
+        public static final OptionValue<Boolean> VerifyGraalPhasesSize = new StableOptionValue<>(false);
+        // @formatter:on
+    }
+
+    /**
+     * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugCounter executionCount;
+
+    /**
+     * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
+     * {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugCounter inputNodesCount;
+
+    /**
+     * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugMemUseTracker memUseTracker;
+
+    /** Lazy initialization to create pattern only when assertions are enabled. */
+    static class NamePatternHolder {
+        static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
+    }
+
+    private static class BasePhaseStatistics {
+        /**
+         * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
+         */
+        private final DebugTimer timer;
+
+        /**
+         * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
+         */
+        private final DebugCounter executionCount;
+
+        /**
+         * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
+         * {@link #apply(StructuredGraph, Object, boolean)}.
+         */
+        private final DebugCounter inputNodesCount;
+
+        /**
+         * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
+         */
+        private final DebugMemUseTracker memUseTracker;
+
+        BasePhaseStatistics(Class<?> clazz) {
+            timer = Debug.timer("PhaseTime_%s", clazz);
+            executionCount = Debug.counter("PhaseCount_%s", clazz);
+            memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", clazz);
+            inputNodesCount = Debug.counter("PhaseNodes_%s", clazz);
+        }
+    }
+
+    private static final ClassValue<BasePhaseStatistics> statisticsClassValue = new ClassValue<BasePhaseStatistics>() {
+        @Override
+        protected BasePhaseStatistics computeValue(Class<?> c) {
+            return new BasePhaseStatistics(c);
+        }
+    };
+
+    protected BasePhase() {
+        BasePhaseStatistics statistics = statisticsClassValue.get(getClass());
+        timer = statistics.timer;
+        executionCount = statistics.executionCount;
+        memUseTracker = statistics.memUseTracker;
+        inputNodesCount = statistics.inputNodesCount;
+    }
+
+    public final void apply(final StructuredGraph graph, final C context) {
+        apply(graph, context, true);
+    }
+
+    @SuppressWarnings("try")
+    protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
+        try (DebugCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); DebugCloseable c = memUseTracker.start()) {
+            int sizeBefore = 0;
+            Mark before = null;
+            if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) {
+                if (context instanceof PhaseContext) {
+                    sizeBefore = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
+                    before = graph.getMark();
+                }
+            }
+            if (dumpGraph && Debug.isDumpEnabled(Debug.VERBOSE_LOG_LEVEL)) {
+                Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "Before phase %s", getName());
+            }
+            inputNodesCount.add(graph.getNodeCount());
+            this.run(graph, context);
+            executionCount.increment();
+            if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) {
+                if (context instanceof PhaseContext) {
+                    if (!before.isCurrent()) {
+                        int sizeAfter = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
+                        NodeCostUtil.phaseFulfillsSizeContract(graph, sizeBefore, sizeAfter, this);
+                    }
+                }
+            }
+            if (dumpGraph && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", getName());
+            }
+            if (Fingerprint.ENABLED) {
+                String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)");
+                Fingerprint.submit("After phase %s nodes in %s are %s", getName(), graphDesc, graph.getNodes().snapshot());
+            }
+            if (Debug.isVerifyEnabled()) {
+                Debug.verify(graph, "%s", getName());
+            }
+            assert graph.verify();
+        } catch (Throwable t) {
+            throw Debug.handle(t);
+        }
+    }
+
+    protected CharSequence getName() {
+        String className = BasePhase.this.getClass().getName();
+        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
+        int innerClassPos = s.indexOf('$');
+        if (innerClassPos > 0) {
+            /* Remove inner class name. */
+            s = s.substring(0, innerClassPos);
+        }
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
+    protected abstract void run(StructuredGraph graph, C context);
+
+    @Override
+    public String contractorName() {
+        return (String) getName();
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 1.25f;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/LazyName.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/LazyName.java
new file mode 100644
index 0000000..e742059
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/LazyName.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import org.graalvm.compiler.debug.Debug;
+
+/**
+ * A name whose {@link String} value is computed only when it is needed. This is useful in
+ * combination with debugging facilities such as {@link Debug#scope(Object)} where the
+ * {@link String} value of a name is only needed if debugging is enabled.
+ */
+public abstract class LazyName implements CharSequence {
+
+    private String value;
+
+    @Override
+    public int length() {
+        return toString().length();
+    }
+
+    @Override
+    public char charAt(int index) {
+        return toString().charAt(index);
+    }
+
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return toString().subSequence(start, end);
+    }
+
+    @Override
+    public final String toString() {
+        if (value == null) {
+            value = createString();
+        }
+        return value;
+    }
+
+    /**
+     * Creates the {@link String} value of this name.
+     */
+    protected abstract String createString();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/OptimisticOptimizations.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/OptimisticOptimizations.java
new file mode 100644
index 0000000..bbe304a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/OptimisticOptimizations.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.ProfilingInfo;
+
+public final class OptimisticOptimizations {
+
+    public static final OptimisticOptimizations ALL = new OptimisticOptimizations(EnumSet.allOf(Optimization.class));
+    public static final OptimisticOptimizations NONE = new OptimisticOptimizations(EnumSet.noneOf(Optimization.class));
+    private static final DebugCounter disabledOptimisticOptsCounter = Debug.counter("DisabledOptimisticOpts");
+
+    public enum Optimization {
+        RemoveNeverExecutedCode,
+        UseTypeCheckedInlining,
+        UseTypeCheckHints,
+        UseExceptionProbabilityForOperations,
+        UseExceptionProbability,
+        UseLoopLimitChecks
+    }
+
+    private final Set<Optimization> enabledOpts;
+
+    public OptimisticOptimizations(ProfilingInfo info) {
+        this.enabledOpts = EnumSet.noneOf(Optimization.class);
+
+        enabledOpts.add(Optimization.UseExceptionProbabilityForOperations);
+        addOptimization(info, DeoptimizationReason.UnreachedCode, Optimization.RemoveNeverExecutedCode);
+        addOptimization(info, DeoptimizationReason.TypeCheckedInliningViolated, Optimization.UseTypeCheckedInlining);
+        addOptimization(info, DeoptimizationReason.OptimizedTypeCheckViolated, Optimization.UseTypeCheckHints);
+        addOptimization(info, DeoptimizationReason.NotCompiledExceptionHandler, Optimization.UseExceptionProbability);
+        addOptimization(info, DeoptimizationReason.LoopLimitCheck, Optimization.UseLoopLimitChecks);
+    }
+
+    private void addOptimization(ProfilingInfo info, DeoptimizationReason deoptReason, Optimization optimization) {
+        if (checkDeoptimizations(info, deoptReason)) {
+            enabledOpts.add(optimization);
+        } else {
+            disabledOptimisticOptsCounter.increment();
+        }
+    }
+
+    public OptimisticOptimizations remove(Optimization... optimizations) {
+        Set<Optimization> newOptimizations = EnumSet.copyOf(enabledOpts);
+        for (Optimization o : optimizations) {
+            newOptimizations.remove(o);
+        }
+        return new OptimisticOptimizations(newOptimizations);
+    }
+
+    public OptimisticOptimizations add(Optimization... optimizations) {
+        Set<Optimization> newOptimizations = EnumSet.copyOf(enabledOpts);
+        for (Optimization o : optimizations) {
+            newOptimizations.add(o);
+        }
+        return new OptimisticOptimizations(newOptimizations);
+    }
+
+    private OptimisticOptimizations(Set<Optimization> enabledOpts) {
+        this.enabledOpts = enabledOpts;
+    }
+
+    public boolean removeNeverExecutedCode() {
+        return GraalOptions.RemoveNeverExecutedCode.getValue() && enabledOpts.contains(Optimization.RemoveNeverExecutedCode);
+    }
+
+    public boolean useTypeCheckHints() {
+        return GraalOptions.UseTypeCheckHints.getValue() && enabledOpts.contains(Optimization.UseTypeCheckHints);
+    }
+
+    public boolean inlineMonomorphicCalls() {
+        return GraalOptions.InlineMonomorphicCalls.getValue() && enabledOpts.contains(Optimization.UseTypeCheckedInlining);
+    }
+
+    public boolean inlinePolymorphicCalls() {
+        return GraalOptions.InlinePolymorphicCalls.getValue() && enabledOpts.contains(Optimization.UseTypeCheckedInlining);
+    }
+
+    public boolean inlineMegamorphicCalls() {
+        return GraalOptions.InlineMegamorphicCalls.getValue() && enabledOpts.contains(Optimization.UseTypeCheckedInlining);
+    }
+
+    public boolean devirtualizeInvokes() {
+        return GraalOptions.OptDevirtualizeInvokesOptimistically.getValue() && enabledOpts.contains(Optimization.UseTypeCheckedInlining);
+    }
+
+    public boolean useExceptionProbability() {
+        return GraalOptions.UseExceptionProbability.getValue() && enabledOpts.contains(Optimization.UseExceptionProbability);
+    }
+
+    public boolean useExceptionProbabilityForOperations() {
+        return GraalOptions.UseExceptionProbabilityForOperations.getValue() && enabledOpts.contains(Optimization.UseExceptionProbabilityForOperations);
+    }
+
+    public boolean useLoopLimitChecks() {
+        return GraalOptions.UseLoopLimitChecks.getValue() && enabledOpts.contains(Optimization.UseLoopLimitChecks);
+    }
+
+    public boolean lessOptimisticThan(OptimisticOptimizations other) {
+        for (Optimization opt : Optimization.values()) {
+            if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean checkDeoptimizations(ProfilingInfo profilingInfo, DeoptimizationReason reason) {
+        return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization.getValue();
+    }
+
+    @Override
+    public String toString() {
+        return enabledOpts.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/Phase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/Phase.java
new file mode 100644
index 0000000..a40aef7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/Phase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * Base class for compiler phases that don't need a context object.
+ */
+public abstract class Phase extends BasePhase<Object> {
+
+    protected Phase() {
+    }
+
+    public final void apply(final StructuredGraph graph) {
+        apply(graph, true);
+    }
+
+    public final void apply(final StructuredGraph graph, final boolean dumpGraph) {
+        apply(graph, null, dumpGraph);
+    }
+
+    protected abstract void run(StructuredGraph graph);
+
+    @Override
+    protected final void run(StructuredGraph graph, Object context) {
+        run(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java
new file mode 100644
index 0000000..61f11b4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * A compiler phase that can apply an ordered collection of phases to a graph.
+ */
+public class PhaseSuite<C> extends BasePhase<C> {
+
+    private List<BasePhase<? super C>> phases;
+    private boolean immutable;
+
+    public PhaseSuite() {
+        this.phases = new ArrayList<>();
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    public synchronized void setImmutable() {
+        if (!immutable) {
+            phases = Collections.unmodifiableList(phases);
+            immutable = true;
+        }
+    }
+
+    /**
+     * Add a new phase at the beginning of this suite.
+     */
+    public final void prependPhase(BasePhase<? super C> phase) {
+        phases.add(0, phase);
+    }
+
+    /**
+     * Add a new phase at the end of this suite.
+     */
+    public final void appendPhase(BasePhase<? super C> phase) {
+        phases.add(phase);
+    }
+
+    /**
+     * Returns a {@link ListIterator} at the position of the first phase which is an instance of
+     * {@code phaseClass} or null if no such phase can be found.
+     *
+     * Calling {@link ListIterator#previous()} would return the phase that was found.
+     *
+     * @param phaseClass the type of phase to look for.
+     */
+    public final ListIterator<BasePhase<? super C>> findPhase(Class<? extends BasePhase<? super C>> phaseClass) {
+        return findPhase(phaseClass, false);
+    }
+
+    /**
+     * Returns a {@link ListIterator} at the position of the first phase which is an instance of
+     * {@code phaseClass} or, if {@code recursive} is true, is a {@link PhaseSuite} containing a
+     * phase which is an instance of {@code phaseClass}. This method returns null if no such phase
+     * can be found.
+     *
+     * Calling {@link ListIterator#previous()} would return the phase or phase suite that was found.
+     *
+     * @param phaseClass the type of phase to look for
+     * @param recursive whether to recursively look into phase suites.
+     */
+    public final ListIterator<BasePhase<? super C>> findPhase(Class<? extends BasePhase<? super C>> phaseClass, boolean recursive) {
+        ListIterator<BasePhase<? super C>> it = phases.listIterator();
+        if (findNextPhase(it, phaseClass, recursive)) {
+            return it;
+        } else {
+            return null;
+        }
+    }
+
+    public static <C> boolean findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass) {
+        return findNextPhase(it, phaseClass, false);
+    }
+
+    public static <C> boolean findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass, boolean recursive) {
+        while (it.hasNext()) {
+            BasePhase<? super C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                return true;
+            } else if (recursive && phase instanceof PhaseSuite) {
+                @SuppressWarnings("unchecked")
+                PhaseSuite<C> suite = (PhaseSuite<C>) phase;
+                if (suite.findPhase(phaseClass, true) != null) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the first instance of the given phase class, looking recursively into inner phase
+     * suites.
+     */
+    public boolean removePhase(Class<? extends BasePhase<? super C>> phaseClass) {
+        ListIterator<BasePhase<? super C>> it = phases.listIterator();
+        while (it.hasNext()) {
+            BasePhase<? super C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                it.remove();
+                return true;
+            } else if (phase instanceof PhaseSuite) {
+                @SuppressWarnings("unchecked")
+                PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
+                if (innerSuite.removePhase(phaseClass)) {
+                    if (innerSuite.phases.isEmpty()) {
+                        it.remove();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, C context) {
+        for (BasePhase<? super C> phase : phases) {
+            phase.apply(graph, context);
+        }
+    }
+
+    public PhaseSuite<C> copy() {
+        PhaseSuite<C> suite = new PhaseSuite<>();
+        suite.phases.addAll(phases);
+        return suite;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java
new file mode 100644
index 0000000..3f37012
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/***
+ * This phase serves as a verification, in order to check the graph for certain properties. The
+ * {@link #verify(StructuredGraph, Object)} method will be used as an assertion, and implements the
+ * actual check. Instead of returning false, it is also valid to throw an {@link VerificationError}
+ * in the implemented {@link #verify(StructuredGraph, Object)} method.
+ */
+public abstract class VerifyPhase<C> extends BasePhase<C> {
+
+    /**
+     * Thrown when verification performed by a {@link VerifyPhase} fails.
+     */
+    @SuppressWarnings("serial")
+    public static class VerificationError extends AssertionError {
+
+        public VerificationError(String message) {
+            super(message);
+        }
+
+        public VerificationError(String format, Object... args) {
+            super(String.format(format, args));
+        }
+
+        public VerificationError(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    @Override
+    protected final void run(StructuredGraph graph, C context) {
+        assert verify(graph, context);
+    }
+
+    /**
+     * Performs the actual verification.
+     *
+     * @throws VerificationError if the verification fails
+     */
+    protected abstract boolean verify(StructuredGraph graph, C context);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java
new file mode 100644
index 0000000..907f927
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.contract;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.VerificationError;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class NodeCostUtil {
+
+    private static final DebugCounter sizeComputationCount = Debug.counter("GraphCostComputationCount_Size");
+    private static final DebugCounter sizeVerificationCount = Debug.counter("GraphCostVerificationCount_Size");
+
+    @SuppressWarnings("try")
+    public static int computeGraphSize(StructuredGraph graph, NodeCostProvider nodeCostProvider) {
+        sizeComputationCount.increment();
+        int size = 0;
+        for (Node n : graph.getNodes()) {
+            size += nodeCostProvider.getEstimatedCodeSize(n);
+        }
+        assert size >= 0;
+        return size;
+    }
+
+    @SuppressWarnings("try")
+    public static double computeGraphCycles(StructuredGraph graph, NodeCostProvider nodeCostProvider, boolean fullSchedule) {
+        Function<Block, Iterable<? extends Node>> blockToNodes;
+        ControlFlowGraph cfg;
+        if (fullSchedule) {
+            SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true);
+            schedule.apply(graph);
+            cfg = graph.getLastSchedule().getCFG();
+            blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b);
+        } else {
+            cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg);
+            for (Block b : cfg.getBlocks()) {
+                ArrayList<FixedNode> curNodes = new ArrayList<>();
+                for (FixedNode node : b.getNodes()) {
+                    curNodes.add(node);
+                }
+                nodes.put(b, curNodes);
+            }
+            blockToNodes = b -> nodes.get(b);
+        }
+        double weightedCycles = 0D;
+        try (Debug.Scope s = Debug.scope("NodeCostSummary")) {
+            for (Block block : cfg.getBlocks()) {
+                for (Node n : blockToNodes.apply(block)) {
+                    double probWeighted = nodeCostProvider.getEstimatedCPUCycles(n) * block.probability();
+                    assert Double.isFinite(probWeighted);
+                    weightedCycles += probWeighted;
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, nodeCostProvider.getEstimatedCPUCycles(n) * block.probability(),
+                                        nodeCostProvider.getEstimatedCodeSize(n), graph, block.probability());
+                    }
+                }
+            }
+        }
+        assert weightedCycles >= 0D;
+        assert Double.isFinite(weightedCycles);
+        return weightedCycles;
+    }
+
+    private static int deltaCompare(double a, double b, double delta) {
+        if (Math.abs(a - b) <= delta) {
+            return 0;
+        }
+        return Double.compare(a, b);
+    }
+
+    /**
+     * Factor to control the "imprecision" of the before - after relation when verifying phase
+     * effects. If the cost model is perfect the best theoretical value is 0.0D (Ignoring the fact
+     * that profiling information is not reliable and thus the, probability based, profiling view on
+     * a graph is different than the reality).
+     */
+    private static final double DELTA = 0.001D;
+
+    public static void phaseFulfillsSizeContract(StructuredGraph graph, int codeSizeBefore, int codeSizeAfter, PhaseSizeContract contract) {
+        sizeVerificationCount.increment();
+        final double codeSizeIncrease = contract.codeSizeIncrease();
+        final double graphSizeDelta = codeSizeBefore * DELTA;
+        if (deltaCompare(codeSizeAfter, codeSizeBefore * codeSizeIncrease, graphSizeDelta) > 0) {
+            ResolvedJavaMethod method = graph.method();
+            double increase = (double) codeSizeAfter / (double) codeSizeBefore;
+            throw new VerificationError("Phase %s expects to increase code size by at most a factor of %.2f but an increase of %.2f was seen (code size before: %d, after: %d)%s",
+                            contract.contractorName(), codeSizeIncrease, increase, codeSizeBefore, codeSizeAfter,
+                            method != null ? " when compiling method " + method.format("%H.%n(%p)") + "." : ".");
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/PhaseSizeContract.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/PhaseSizeContract.java
new file mode 100644
index 0000000..4c86fa8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/PhaseSizeContract.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.contract;
+
+import org.graalvm.compiler.nodeinfo.NodeSize;
+
+public interface PhaseSizeContract {
+
+    /**
+     * Returns a factor {@code >=1} that determines what the final code size in terms of the sum of
+     * the node code sizes {@link NodeSize} of all nodes is.
+     *
+     * @return a factor that determines how much the code size can be increased by this phase
+     */
+    float codeSizeIncrease();
+
+    default boolean checkContract() {
+        return true;
+    }
+
+    String contractorName();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java
new file mode 100644
index 0000000..2d0314b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StartNode;
+
+/**
+ * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s.
+ */
+public class FixedNodeProbabilityCache implements ToDoubleFunction<FixedNode> {
+
+    private static final DebugCounter computeNodeProbabilityCounter = Debug.counter("ComputeNodeProbability");
+
+    private final Map<FixedNode, Double> cache = Node.newIdentityMap();
+
+    /**
+     * <p>
+     * Given a {@link FixedNode} this method finds the most immediate {@link AbstractBeginNode}
+     * preceding it that either:
+     * <ul>
+     * <li>has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the
+     * start-node)</li>
+     * <li>has a control-split predecessor</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * The thus found {@link AbstractBeginNode} is equi-probable with the {@link FixedNode} it was
+     * obtained from. When computed for the first time (afterwards a cache lookup returns it) that
+     * probability is computed as follows, again depending on the begin-node's predecessor:
+     * <ul>
+     * <li>No predecessor. In this case the begin-node is either:</li>
+     * <ul>
+     * <li>a merge-node, whose probability adds up those of its forward-ends</li>
+     * <li>a loop-begin, with probability as above multiplied by the loop-frequency</li>
+     * </ul>
+     * <li>Control-split predecessor: probability of the branch times that of the control-split</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * As an exception to all the above, a probability of 1 is assumed for a {@link FixedNode} that
+     * appears to be dead-code (ie, lacks a predecessor).
+     * </p>
+     *
+     */
+    @Override
+    public double applyAsDouble(FixedNode node) {
+        assert node != null;
+        computeNodeProbabilityCounter.increment();
+
+        FixedNode current = findBegin(node);
+        if (current == null) {
+            // this should only appear for dead code
+            return 1D;
+        }
+
+        assert current instanceof AbstractBeginNode;
+        Double cachedValue = cache.get(current);
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        double probability = 0.0;
+        if (current.predecessor() == null) {
+            if (current instanceof AbstractMergeNode) {
+                probability = handleMerge(current, probability);
+            } else {
+                assert current instanceof StartNode;
+                probability = 1D;
+            }
+        } else {
+            ControlSplitNode split = (ControlSplitNode) current.predecessor();
+            probability = split.probability((AbstractBeginNode) current) * applyAsDouble(split);
+        }
+        assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability;
+        cache.put(current, probability);
+        return probability;
+    }
+
+    private double handleMerge(FixedNode current, double probability) {
+        double result = probability;
+        AbstractMergeNode currentMerge = (AbstractMergeNode) current;
+        NodeInputList<EndNode> currentForwardEnds = currentMerge.forwardEnds();
+        /*
+         * Use simple iteration instead of streams, since the stream infrastructure adds many frames
+         * which causes the recursion to overflow the stack earlier than it would otherwise.
+         */
+        for (AbstractEndNode endNode : currentForwardEnds) {
+            result += applyAsDouble(endNode);
+        }
+        if (current instanceof LoopBeginNode) {
+            result *= ((LoopBeginNode) current).loopFrequency();
+        }
+        return result;
+    }
+
+    private static FixedNode findBegin(FixedNode node) {
+        FixedNode current = node;
+        while (true) {
+            assert current != null;
+            Node predecessor = current.predecessor();
+            if (current instanceof AbstractBeginNode) {
+                if (predecessor == null) {
+                    break;
+                } else if (predecessor.successors().count() != 1) {
+                    assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor;
+                    break;
+                }
+            } else if (predecessor == null) {
+                current = null;
+                break;
+            }
+            current = (FixedNode) predecessor;
+        }
+        return current;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/InferStamps.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/InferStamps.java
new file mode 100644
index 0000000..1bd1ad5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/InferStamps.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+
+public class InferStamps {
+
+    /**
+     * Infer the stamps for all Object nodes in the graph, to make the stamps as precise as
+     * possible. For example, this propagates the word-type through phi functions. To handle phi
+     * functions at loop headers, the stamp inference is called until a fix point is reached.
+     * <p>
+     * This method can be used when it is needed that stamps are inferred before the first run of
+     * the canonicalizer. For example, word type rewriting must run before the first run of the
+     * canonicalizer because many nodes are not prepared to see the word type during
+     * canonicalization.
+     */
+    public static void inferStamps(StructuredGraph graph) {
+        /*
+         * We want to make the stamps more precise. For cyclic phi functions, this means we have to
+         * ignore the initial stamp because the imprecise stamp would always propagate around the
+         * cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored
+         * when the phi function performs the "meet" operator on its input stamps.
+         */
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValuePhiNode) {
+                ValueNode node = (ValueNode) n;
+                if (node.stamp() instanceof ObjectStamp) {
+                    assert node.stamp().hasValues() : "We assume all Phi and Proxy stamps are legal before the analysis";
+                    node.setStamp(node.stamp().empty());
+                }
+            }
+        }
+
+        boolean stampChanged;
+        // The algorithm is not guaranteed to reach a stable state.
+        int z = 0;
+        do {
+            stampChanged = false;
+            /*
+             * We could use GraphOrder.forwardGraph() to process the nodes in a defined order and
+             * propagate long def-use chains in fewer iterations. However, measurements showed that
+             * we have few iterations anyway, and the overhead of computing the order is much higher
+             * than the benefit.
+             */
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ValueNode) {
+                    ValueNode node = (ValueNode) n;
+                    if (node.stamp() instanceof ObjectStamp) {
+                        stampChanged |= node.inferStamp();
+                    }
+                }
+            }
+            ++z;
+        } while (stampChanged && z < 10000);
+
+        /*
+         * Check that all the illegal stamps we introduced above are correctly replaced with real
+         * stamps again.
+         */
+        assert checkNoEmptyStamp(graph);
+    }
+
+    private static boolean checkNoEmptyStamp(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValuePhiNode) {
+                ValueNode node = (ValueNode) n;
+                assert node.stamp().hasValues() : "Stamp is empty after analysis. This is not necessarily an error, but a condition that we want to investigate (and then maybe relax or remove the assertion).";
+            }
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java
new file mode 100644
index 0000000..eff02f9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.List;
+
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+
+public abstract class MergeableState<T> {
+
+    @Override
+    public abstract T clone();
+
+    /**
+     * This method is called on merge on the state of the first branch. The {@code withStates} list
+     * contains the states of the of the other branches in the order of the merge's end nodes.
+     *
+     * @param merge the merge node
+     * @param withStates the state at the the merge's end node except the first one.
+     */
+    public abstract boolean merge(AbstractMergeNode merge, List<T> withStates);
+
+    /**
+     * This method is called before a loop is entered (before the {@link LoopBeginNode} is visited).
+     *
+     * @param loopBegin the begin node of the loop
+     */
+    public void loopBegin(LoopBeginNode loopBegin) {
+        // empty default implementation
+    }
+
+    /**
+     * This method is called after all {@link LoopEndNode}s belonging to a loop have been visited.
+     *
+     * @param loopBegin the begin node of the loop
+     * @param loopEndStates the states at the loop ends, sorted according to
+     *            {@link LoopBeginNode#orderedLoopEnds()}
+     */
+    public void loopEnds(LoopBeginNode loopBegin, List<T> loopEndStates) {
+        // empty default implementation
+    }
+
+    /**
+     * This method is called before the successors of a {@link ControlSplitNode} are visited.
+     *
+     * @param node the successor of the control split that is about to be visited
+     */
+    public void afterSplit(AbstractBeginNode node) {
+        // empty default implementation
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java
new file mode 100644
index 0000000..a5abb81
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a
+ * specified fixed node.
+ * <p>
+ * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode},
+ * {@link AbstractMergeNode}...) and the {@link FixedWithNextNode#next() next} pointers of
+ * {@link FixedWithNextNode}.
+ * <p>
+ * While iterating it maintains a user-defined state by calling the methods available in
+ * {@link MergeableState}.
+ *
+ * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator
+ */
+public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
+
+    private final NodeBitMap visitedEnds;
+    private final Deque<AbstractBeginNode> nodeQueue;
+    private final Map<FixedNode, T> nodeStates;
+    private final FixedNode start;
+
+    protected T state;
+
+    public PostOrderNodeIterator(FixedNode start, T initialState) {
+        StructuredGraph graph = start.graph();
+        visitedEnds = graph.createNodeBitMap();
+        nodeQueue = new ArrayDeque<>();
+        nodeStates = Node.newIdentityMap();
+        this.start = start;
+        this.state = initialState;
+    }
+
+    public void apply() {
+        FixedNode current = start;
+
+        do {
+            if (current instanceof InvokeWithExceptionNode) {
+                invoke((Invoke) current);
+                queueSuccessors(current, null);
+                current = nextQueuedNode();
+            } else if (current instanceof LoopBeginNode) {
+                state.loopBegin((LoopBeginNode) current);
+                nodeStates.put(current, state);
+                state = state.clone();
+                loopBegin((LoopBeginNode) current);
+                current = ((LoopBeginNode) current).next();
+                assert current != null;
+            } else if (current instanceof LoopEndNode) {
+                loopEnd((LoopEndNode) current);
+                finishLoopEnds((LoopEndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof AbstractMergeNode) {
+                merge((AbstractMergeNode) current);
+                current = ((AbstractMergeNode) current).next();
+                assert current != null;
+            } else if (current instanceof FixedWithNextNode) {
+                FixedNode next = ((FixedWithNextNode) current).next();
+                assert next != null : current;
+                node(current);
+                current = next;
+            } else if (current instanceof EndNode) {
+                end((EndNode) current);
+                queueMerge((EndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSinkNode) {
+                node(current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSplitNode) {
+                Set<Node> successors = controlSplit((ControlSplitNode) current);
+                queueSuccessors(current, successors);
+                current = nextQueuedNode();
+            } else {
+                assert false : current;
+            }
+        } while (current != null);
+        finished();
+    }
+
+    private void queueSuccessors(FixedNode x, Set<Node> successors) {
+        nodeStates.put(x, state);
+        if (successors != null) {
+            for (Node node : successors) {
+                if (node != null) {
+                    nodeStates.put((FixedNode) node.predecessor(), state);
+                    nodeQueue.addFirst((AbstractBeginNode) node);
+                }
+            }
+        } else {
+            for (Node node : x.successors()) {
+                if (node != null) {
+                    nodeQueue.addFirst((AbstractBeginNode) node);
+                }
+            }
+        }
+    }
+
+    private FixedNode nextQueuedNode() {
+        int maxIterations = nodeQueue.size();
+        while (maxIterations-- > 0) {
+            AbstractBeginNode node = nodeQueue.removeFirst();
+            if (node instanceof AbstractMergeNode) {
+                AbstractMergeNode merge = (AbstractMergeNode) node;
+                state = nodeStates.get(merge.forwardEndAt(0)).clone();
+                ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1);
+                for (int i = 1; i < merge.forwardEndCount(); i++) {
+                    T other = nodeStates.get(merge.forwardEndAt(i));
+                    assert other != null;
+                    states.add(other);
+                }
+                boolean ready = state.merge(merge, states);
+                if (ready) {
+                    return merge;
+                } else {
+                    nodeQueue.addLast(merge);
+                }
+            } else {
+                assert node.predecessor() != null;
+                state = nodeStates.get(node.predecessor()).clone();
+                state.afterSplit(node);
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private void finishLoopEnds(LoopEndNode end) {
+        assert !visitedEnds.isMarked(end);
+        assert !nodeStates.containsKey(end);
+        nodeStates.put(end, state);
+        visitedEnds.mark(end);
+        LoopBeginNode begin = end.loopBegin();
+        boolean endsVisited = true;
+        for (LoopEndNode le : begin.loopEnds()) {
+            if (!visitedEnds.isMarked(le)) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
+            for (LoopEndNode le : begin.orderedLoopEnds()) {
+                states.add(nodeStates.get(le));
+            }
+            T loopBeginState = nodeStates.get(begin);
+            if (loopBeginState != null) {
+                loopBeginState.loopEnds(begin, states);
+            }
+        }
+    }
+
+    private void queueMerge(EndNode end) {
+        assert !visitedEnds.isMarked(end);
+        assert !nodeStates.containsKey(end);
+        nodeStates.put(end, state);
+        visitedEnds.mark(end);
+        AbstractMergeNode merge = end.merge();
+        boolean endsVisited = true;
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            nodeQueue.add(merge);
+        }
+    }
+
+    protected abstract void node(FixedNode node);
+
+    protected void end(EndNode endNode) {
+        node(endNode);
+    }
+
+    protected void merge(AbstractMergeNode merge) {
+        node(merge);
+    }
+
+    protected void loopBegin(LoopBeginNode loopBegin) {
+        node(loopBegin);
+    }
+
+    protected void loopEnd(LoopEndNode loopEnd) {
+        node(loopEnd);
+    }
+
+    protected Set<Node> controlSplit(ControlSplitNode controlSplit) {
+        node(controlSplit);
+        return null;
+    }
+
+    protected void invoke(Invoke invoke) {
+        node(invoke.asNode());
+    }
+
+    protected void finished() {
+        // nothing to do
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java
new file mode 100644
index 0000000..6e306bb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.util.CompilationAlarm;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+
+public final class ReentrantBlockIterator {
+
+    public static class LoopInfo<StateT> {
+
+        public final List<StateT> endStates;
+        public final List<StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = new ArrayList<>(endCount);
+            exitStates = new ArrayList<>(exitCount);
+        }
+    }
+
+    public abstract static class BlockIteratorClosure<StateT> {
+
+        protected abstract StateT getInitialState();
+
+        protected abstract StateT processBlock(Block block, StateT currentState);
+
+        protected abstract StateT merge(Block merge, List<StateT> states);
+
+        protected abstract StateT cloneState(StateT oldState);
+
+        protected abstract List<StateT> processLoop(Loop<Block> loop, StateT initialState);
+    }
+
+    private ReentrantBlockIterator() {
+        // no instances allowed
+    }
+
+    public static <StateT> LoopInfo<StateT> processLoop(BlockIteratorClosure<StateT> closure, Loop<Block> loop, StateT initialState) {
+        Map<FixedNode, StateT> blockEndStates = apply(closure, loop.getHeader(), initialState, block -> !(block.getLoop() == loop || block.isLoopHeader()));
+
+        Block[] predecessors = loop.getHeader().getPredecessors();
+        LoopInfo<StateT> info = new LoopInfo<>(predecessors.length - 1, loop.getExits().size());
+        for (int i = 1; i < predecessors.length; i++) {
+            StateT endState = blockEndStates.get(predecessors[i].getEndNode());
+            // make sure all end states are unique objects
+            info.endStates.add(closure.cloneState(endState));
+        }
+        for (Block loopExit : loop.getExits()) {
+            assert loopExit.getPredecessorCount() == 1;
+            assert blockEndStates.containsKey(loopExit.getBeginNode()) : loopExit.getBeginNode() + " " + blockEndStates;
+            StateT exitState = blockEndStates.get(loopExit.getBeginNode());
+            // make sure all exit states are unique objects
+            info.exitStates.add(closure.cloneState(exitState));
+        }
+        return info;
+    }
+
+    public static <StateT> void apply(BlockIteratorClosure<StateT> closure, Block start) {
+        apply(closure, start, closure.getInitialState(), null);
+    }
+
+    public static <StateT> Map<FixedNode, StateT> apply(BlockIteratorClosure<StateT> closure, Block start, StateT initialState, Predicate<Block> stopAtBlock) {
+        Deque<Block> blockQueue = new ArrayDeque<>();
+        /*
+         * States are stored on EndNodes before merges, and on BeginNodes after ControlSplitNodes.
+         */
+        Map<FixedNode, StateT> states = Node.newIdentityMap();
+
+        StateT state = initialState;
+        Block current = start;
+
+        while (true) {
+            if (CompilationAlarm.hasExpired()) {
+                throw new RetryableBailoutException("Compilation exceeded %d seconds during CFG traversal", CompilationAlarm.Options.CompilationExpirationPeriod.getValue());
+            }
+            Block next = null;
+            if (stopAtBlock != null && stopAtBlock.test(current)) {
+                states.put(current.getBeginNode(), state);
+            } else {
+                state = closure.processBlock(current, state);
+
+                Block[] successors = current.getSuccessors();
+                if (successors.length == 0) {
+                    // nothing to do...
+                } else if (successors.length == 1) {
+                    Block successor = successors[0];
+                    if (successor.isLoopHeader()) {
+                        if (current.isLoopEnd()) {
+                            // nothing to do... loop ends only lead to loop begins we've already
+                            // visited
+                            states.put(current.getEndNode(), state);
+                        } else {
+                            recurseIntoLoop(closure, blockQueue, states, state, successor);
+                        }
+                    } else if (current.getEndNode() instanceof AbstractEndNode) {
+                        AbstractEndNode end = (AbstractEndNode) current.getEndNode();
+
+                        // add the end node and see if the merge is ready for processing
+                        AbstractMergeNode merge = end.merge();
+                        if (allEndsVisited(states, current, merge)) {
+                            ArrayList<StateT> mergedStates = mergeStates(states, state, current, successor, merge);
+                            state = closure.merge(successor, mergedStates);
+                            next = successor;
+                        } else {
+                            assert !states.containsKey(end);
+                            states.put(end, state);
+                        }
+                    } else {
+                        next = successor;
+                    }
+                } else {
+                    next = processMultipleSuccessors(closure, blockQueue, states, state, successors);
+                }
+            }
+
+            // get next queued block
+            if (next != null) {
+                current = next;
+            } else if (blockQueue.isEmpty()) {
+                return states;
+            } else {
+                current = blockQueue.removeFirst();
+                assert current.getPredecessorCount() == 1;
+                assert states.containsKey(current.getBeginNode());
+                state = states.remove(current.getBeginNode());
+            }
+        }
+    }
+
+    private static <StateT> boolean allEndsVisited(Map<FixedNode, StateT> states, Block current, AbstractMergeNode merge) {
+        for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
+            if (forwardEnd != current.getEndNode() && !states.containsKey(forwardEnd)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static <StateT> Block processMultipleSuccessors(BlockIteratorClosure<StateT> closure, Deque<Block> blockQueue, Map<FixedNode, StateT> states, StateT state, Block[] successors) {
+        assert successors.length > 1;
+        for (int i = 1; i < successors.length; i++) {
+            Block successor = successors[i];
+            blockQueue.addFirst(successor);
+            states.put(successor.getBeginNode(), closure.cloneState(state));
+        }
+        return successors[0];
+    }
+
+    private static <StateT> ArrayList<StateT> mergeStates(Map<FixedNode, StateT> states, StateT state, Block current, Block successor, AbstractMergeNode merge) {
+        ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
+        for (Block predecessor : successor.getPredecessors()) {
+            assert predecessor == current || states.containsKey(predecessor.getEndNode());
+            StateT endState = predecessor == current ? state : states.remove(predecessor.getEndNode());
+            mergedStates.add(endState);
+        }
+        return mergedStates;
+    }
+
+    private static <StateT> void recurseIntoLoop(BlockIteratorClosure<StateT> closure, Deque<Block> blockQueue, Map<FixedNode, StateT> states, StateT state, Block successor) {
+        // recurse into the loop
+        Loop<Block> loop = successor.getLoop();
+        LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
+        assert successor.getBeginNode() == loopBegin;
+
+        List<StateT> exitStates = closure.processLoop(loop, state);
+
+        int i = 0;
+        assert loop.getExits().size() == exitStates.size();
+        for (Block exit : loop.getExits()) {
+            states.put(exit.getBeginNode(), exitStates.get(i++));
+            blockQueue.addFirst(exit);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java
new file mode 100644
index 0000000..c64d020
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+
+public final class ReentrantNodeIterator {
+
+    public static class LoopInfo<StateT> {
+
+        public final Map<LoopEndNode, StateT> endStates;
+        public final Map<LoopExitNode, StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = Node.newIdentityMap(endCount);
+            exitStates = Node.newIdentityMap(exitCount);
+        }
+    }
+
+    public abstract static class NodeIteratorClosure<StateT> {
+
+        protected abstract StateT processNode(FixedNode node, StateT currentState);
+
+        protected abstract StateT merge(AbstractMergeNode merge, List<StateT> states);
+
+        protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState);
+
+        protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
+
+        /**
+         * Determine whether iteration should continue in the current state.
+         *
+         * @param currentState
+         */
+        protected boolean continueIteration(StateT currentState) {
+            return true;
+        }
+    }
+
+    private ReentrantNodeIterator() {
+        // no instances allowed
+    }
+
+    public static <StateT> LoopInfo<StateT> processLoop(NodeIteratorClosure<StateT> closure, LoopBeginNode loop, StateT initialState) {
+        Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, loop);
+
+        LoopInfo<StateT> info = new LoopInfo<>(loop.loopEnds().count(), loop.loopExits().count());
+        for (LoopEndNode end : loop.loopEnds()) {
+            if (blockEndStates.containsKey(end)) {
+                info.endStates.put(end, blockEndStates.get(end));
+            }
+        }
+        for (LoopExitNode exit : loop.loopExits()) {
+            if (blockEndStates.containsKey(exit)) {
+                info.exitStates.put(exit, blockEndStates.get(exit));
+            }
+        }
+        return info;
+    }
+
+    public static <StateT> void apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState) {
+        apply(closure, start, initialState, null);
+    }
+
+    private static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, LoopBeginNode boundary) {
+        assert start != null;
+        Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
+        Map<FixedNode, StateT> blockEndStates = Node.newIdentityMap();
+
+        StateT state = initialState;
+        FixedNode current = start;
+        do {
+            while (current instanceof FixedWithNextNode) {
+                if (boundary != null && current instanceof LoopExitNode && ((LoopExitNode) current).loopBegin() == boundary) {
+                    blockEndStates.put(current, state);
+                    current = null;
+                } else {
+                    FixedNode next = ((FixedWithNextNode) current).next();
+                    state = closure.processNode(current, state);
+                    current = closure.continueIteration(state) ? next : null;
+                }
+            }
+
+            if (current != null) {
+                state = closure.processNode(current, state);
+
+                if (closure.continueIteration(state)) {
+                    Iterator<Node> successors = current.successors().iterator();
+                    if (!successors.hasNext()) {
+                        if (current instanceof LoopEndNode) {
+                            blockEndStates.put(current, state);
+                        } else if (current instanceof EndNode) {
+                            // add the end node and see if the merge is ready for processing
+                            AbstractMergeNode merge = ((EndNode) current).merge();
+                            if (merge instanceof LoopBeginNode) {
+                                Map<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
+                                for (Map.Entry<LoopExitNode, StateT> entry : loopExitState.entrySet()) {
+                                    blockEndStates.put(entry.getKey(), entry.getValue());
+                                    nodeQueue.add(entry.getKey());
+                                }
+                            } else {
+                                boolean endsVisited = true;
+                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
+                                    if (forwardEnd != current && !blockEndStates.containsKey(forwardEnd)) {
+                                        endsVisited = false;
+                                        break;
+                                    }
+                                }
+                                if (endsVisited) {
+                                    ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
+                                    for (int i = 0; i < merge.forwardEndCount(); i++) {
+                                        AbstractEndNode forwardEnd = merge.forwardEndAt(i);
+                                        assert forwardEnd == current || blockEndStates.containsKey(forwardEnd);
+                                        StateT other = forwardEnd == current ? state : blockEndStates.remove(forwardEnd);
+                                        states.add(other);
+                                    }
+                                    state = closure.merge(merge, states);
+                                    current = closure.continueIteration(state) ? merge : null;
+                                    continue;
+                                } else {
+                                    assert !blockEndStates.containsKey(current);
+                                    blockEndStates.put(current, state);
+                                }
+                            }
+                        }
+                    } else {
+                        FixedNode firstSuccessor = (FixedNode) successors.next();
+                        if (!successors.hasNext()) {
+                            current = firstSuccessor;
+                            continue;
+                        } else {
+                            do {
+                                AbstractBeginNode successor = (AbstractBeginNode) successors.next();
+                                StateT successorState = closure.afterSplit(successor, state);
+                                if (closure.continueIteration(successorState)) {
+                                    blockEndStates.put(successor, successorState);
+                                    nodeQueue.add(successor);
+                                }
+                            } while (successors.hasNext());
+
+                            state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
+                            current = closure.continueIteration(state) ? firstSuccessor : null;
+                            continue;
+                        }
+                    }
+                }
+            }
+
+            // get next queued block
+            if (nodeQueue.isEmpty()) {
+                return blockEndStates;
+            } else {
+                current = nodeQueue.removeFirst();
+                assert blockEndStates.containsKey(current);
+                state = blockEndStates.remove(current);
+                assert !(current instanceof AbstractMergeNode) && current instanceof AbstractBeginNode;
+            }
+        } while (true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScheduledNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScheduledNodeIterator.java
new file mode 100644
index 0000000..3573d74
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScheduledNodeIterator.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ListIterator;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+
+/**
+ * Iterates over a list of nodes, which usually comes from
+ * {@link ScheduleResult#getBlockToNodesMap()}.
+ *
+ * While iterating, it is possible to {@link #insert(FixedNode, FixedWithNextNode) insert} and
+ * {@link #replaceCurrent(FixedWithNextNode) replace} nodes.
+ */
+public abstract class ScheduledNodeIterator {
+
+    private FixedWithNextNode lastFixed;
+    private FixedWithNextNode reconnect;
+    private ListIterator<Node> iterator;
+
+    public void processNodes(Block block, ScheduleResult schedule) {
+        lastFixed = block.getBeginNode();
+        assert lastFixed != null;
+        reconnect = null;
+        iterator = schedule.nodesFor(block).listIterator();
+
+        while (iterator.hasNext()) {
+            Node node = iterator.next();
+            if (!node.isAlive()) {
+                continue;
+            }
+            if (reconnect != null && node instanceof FixedNode) {
+                reconnect.setNext((FixedNode) node);
+                reconnect = null;
+            }
+            if (node instanceof FixedWithNextNode) {
+                lastFixed = (FixedWithNextNode) node;
+            }
+            processNode(node);
+        }
+        if (reconnect != null) {
+            assert block.getSuccessorCount() == 1;
+            reconnect.setNext(block.getFirstSuccessor().getBeginNode());
+        }
+    }
+
+    protected void insert(FixedNode start, FixedWithNextNode end) {
+        this.lastFixed.setNext(start);
+        this.lastFixed = end;
+        this.reconnect = end;
+    }
+
+    protected void replaceCurrent(FixedWithNextNode newNode) {
+        Node current = iterator.previous();
+        iterator.next(); // needed because of the previous() call
+        current.replaceAndDelete(newNode);
+        insert(newNode, newNode);
+        iterator.set(newNode);
+    }
+
+    protected abstract void processNode(Node node);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScopedPostOrderNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScopedPostOrderNodeIterator.java
new file mode 100644
index 0000000..3cd71b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ScopedPostOrderNodeIterator.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+public abstract class ScopedPostOrderNodeIterator {
+
+    private final Deque<FixedNode> nodeQueue;
+    private final NodeBitMap queuedNodes;
+    private final Deque<FixedNode> scopes;
+
+    protected FixedNode currentScopeStart;
+
+    public ScopedPostOrderNodeIterator(StructuredGraph graph) {
+        this.queuedNodes = graph.createNodeBitMap();
+        this.nodeQueue = new ArrayDeque<>();
+        this.scopes = getScopes(graph);
+    }
+
+    public void apply() {
+        while (!scopes.isEmpty()) {
+            queuedNodes.clearAll();
+            this.currentScopeStart = scopes.pop();
+            initializeScope();
+            processScope();
+        }
+    }
+
+    public void processScope() {
+        FixedNode current;
+        queue(currentScopeStart);
+
+        while ((current = nextQueuedNode()) != null) {
+            assert current.isAlive();
+
+            if (current instanceof Invoke) {
+                invoke((Invoke) current);
+                queueSuccessors(current);
+            } else if (current instanceof LoopBeginNode) {
+                queueLoopBeginSuccessors((LoopBeginNode) current);
+            } else if (current instanceof LoopExitNode) {
+                queueLoopExitSuccessors((LoopExitNode) current);
+            } else if (current instanceof LoopEndNode) {
+                // nothing todo
+            } else if (current instanceof AbstractMergeNode) {
+                queueSuccessors(current);
+            } else if (current instanceof FixedWithNextNode) {
+                queueSuccessors(current);
+            } else if (current instanceof EndNode) {
+                queueMerge((EndNode) current);
+            } else if (current instanceof ControlSinkNode) {
+                // nothing todo
+            } else if (current instanceof ControlSplitNode) {
+                queueSuccessors(current);
+            } else {
+                assert false : current;
+            }
+        }
+    }
+
+    protected void queueLoopBeginSuccessors(LoopBeginNode node) {
+        if (currentScopeStart == node) {
+            queue(node.next());
+        } else if (currentScopeStart instanceof LoopBeginNode) {
+            // so we are currently processing loop A and found another loop B
+            // -> queue all loop exits of B except those that also exit loop A
+            for (LoopExitNode loopExit : node.loopExits()) {
+                if (!((LoopBeginNode) currentScopeStart).loopExits().contains(loopExit)) {
+                    queue(loopExit);
+                }
+            }
+        } else {
+            queue(node.loopExits());
+        }
+    }
+
+    protected void queueLoopExitSuccessors(LoopExitNode node) {
+        if (!(currentScopeStart instanceof LoopBeginNode) || !((LoopBeginNode) currentScopeStart).loopExits().contains(node)) {
+            queueSuccessors(node);
+        }
+    }
+
+    protected Deque<FixedNode> getScopes(StructuredGraph graph) {
+        Deque<FixedNode> result = new ArrayDeque<>();
+        result.push(graph.start());
+        for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
+            result.push(loopBegin);
+        }
+        return result;
+    }
+
+    private void queueSuccessors(FixedNode x) {
+        queue(x.successors());
+    }
+
+    private void queue(NodeIterable<? extends Node> iter) {
+        for (Node node : iter) {
+            queue(node);
+        }
+    }
+
+    private void queue(Node node) {
+        if (node != null && !queuedNodes.isMarked(node)) {
+            queuedNodes.mark(node);
+            nodeQueue.addFirst((FixedNode) node);
+        }
+    }
+
+    private FixedNode nextQueuedNode() {
+        if (nodeQueue.isEmpty()) {
+            return null;
+        }
+
+        FixedNode result = nodeQueue.removeFirst();
+        assert queuedNodes.isMarked(result);
+        return result;
+    }
+
+    private void queueMerge(AbstractEndNode end) {
+        AbstractMergeNode merge = end.merge();
+        if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
+            queue(merge);
+        }
+    }
+
+    private boolean visitedAllEnds(AbstractMergeNode merge) {
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected abstract void initializeScope();
+
+    protected abstract void invoke(Invoke invoke);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java
new file mode 100644
index 0000000..746be12
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * A SinglePassNodeIterator iterates the fixed nodes of the graph in post order starting from its
+ * start node. Unlike in iterative dataflow analysis, a single pass is performed, which allows
+ * keeping a smaller working set of pending {@link MergeableState}. This iteration scheme requires:
+ * <ul>
+ * <li>{@link MergeableState#merge(AbstractMergeNode, List)} to always return <code>true</code> (an
+ * assertion checks this)</li>
+ * <li>{@link #controlSplit(ControlSplitNode)} to always return all successors (otherwise, not all
+ * associated {@link EndNode} will be visited. In turn, visiting all the end nodes for a given
+ * {@link AbstractMergeNode} is a precondition before that merge node can be visited)</li>
+ * </ul>
+ *
+ * <p>
+ * For this iterator the CFG is defined by the classical CFG nodes (
+ * {@link org.graalvm.compiler.nodes.ControlSplitNode},
+ * {@link org.graalvm.compiler.nodes.AbstractMergeNode} ...) and the
+ * {@link org.graalvm.compiler.nodes.FixedWithNextNode#next() next} pointers of
+ * {@link org.graalvm.compiler.nodes.FixedWithNextNode}.
+ * </p>
+ *
+ * <p>
+ * The lifecycle that single-pass node iterators go through is described in {@link #apply()}
+ * </p>
+ *
+ * @param <T> the type of {@link MergeableState} handled by this SinglePassNodeIterator
+ */
+public abstract class SinglePassNodeIterator<T extends MergeableState<T>> {
+
+    private final NodeBitMap visitedEnds;
+
+    /**
+     * @see SinglePassNodeIterator.PathStart
+     */
+    private final Deque<PathStart<T>> nodeQueue;
+
+    /**
+     * The keys in this map may be:
+     * <ul>
+     * <li>loop-begins and loop-ends, see {@link #finishLoopEnds(LoopEndNode)}</li>
+     * <li>forward-ends of merge-nodes, see {@link #queueMerge(EndNode)}</li>
+     * </ul>
+     *
+     * <p>
+     * It's tricky to answer whether the state an entry contains is the pre-state or the post-state
+     * for the key in question, because states are mutable. Thus an entry may be created to contain
+     * a pre-state (at the time, as done for a loop-begin in {@link #apply()}) only to make it a
+     * post-state soon after (continuing with the loop-begin example, also in {@link #apply()}). In
+     * any case, given that keys are limited to the nodes mentioned in the previous paragraph, in
+     * all cases an entry can be considered to hold a post-state by the time such entry is
+     * retrieved.
+     * </p>
+     *
+     * <p>
+     * The only method that makes this map grow is {@link #keepForLater(FixedNode, MergeableState)}
+     * and the only one that shrinks it is {@link #pruneEntry(FixedNode)}. To make sure no entry is
+     * left behind inadvertently, asserts in {@link #finished()} are in place.
+     * </p>
+     */
+    private final Map<FixedNode, T> nodeStates;
+
+    private final StartNode start;
+
+    protected T state;
+
+    /**
+     * An item queued in {@link #nodeQueue} can be used to continue with the single-pass visit after
+     * the previous path can't be followed anymore. Such items are:
+     * <ul>
+     * <li>de-queued via {@link #nextQueuedNode()}</li>
+     * <li>en-queued via {@link #queueMerge(EndNode)} and {@link #queueSuccessors(FixedNode)}</li>
+     * </ul>
+     *
+     * <p>
+     * Correspondingly each item may stand for:
+     * <ul>
+     * <li>a {@link AbstractMergeNode} whose pre-state results from merging those of its
+     * forward-ends, see {@link #nextQueuedNode()}</li>
+     * <li>a successor of a control-split node, in which case the state on entry to it (the
+     * successor) is also stored in the item, see {@link #nextQueuedNode()}</li>
+     * </ul>
+     * </p>
+     */
+    private static final class PathStart<U> {
+        private final AbstractBeginNode node;
+        private final U stateOnEntry;
+
+        private PathStart(AbstractBeginNode node, U stateOnEntry) {
+            this.node = node;
+            this.stateOnEntry = stateOnEntry;
+            assert repOK();
+        }
+
+        /**
+         * @return true iff this instance is internally consistent (ie, its "representation is OK")
+         */
+        private boolean repOK() {
+            if (node == null) {
+                return false;
+            }
+            if (node instanceof AbstractMergeNode) {
+                return stateOnEntry == null;
+            }
+            return (stateOnEntry != null);
+        }
+    }
+
+    public SinglePassNodeIterator(StartNode start, T initialState) {
+        StructuredGraph graph = start.graph();
+        visitedEnds = graph.createNodeBitMap();
+        nodeQueue = new ArrayDeque<>();
+        nodeStates = Node.newIdentityMap();
+        this.start = start;
+        this.state = initialState;
+    }
+
+    /**
+     * Performs a single-pass iteration.
+     *
+     * <p>
+     * After this method has been invoked, the {@link SinglePassNodeIterator} instance can't be used
+     * again. This saves clearing up fields in {@link #finished()}, the assumption being that this
+     * instance will be garbage-collected soon afterwards.
+     * </p>
+     */
+    public void apply() {
+        FixedNode current = start;
+
+        do {
+            if (current instanceof InvokeWithExceptionNode) {
+                invoke((Invoke) current);
+                queueSuccessors(current);
+                current = nextQueuedNode();
+            } else if (current instanceof LoopBeginNode) {
+                state.loopBegin((LoopBeginNode) current);
+                keepForLater(current, state);
+                state = state.clone();
+                loopBegin((LoopBeginNode) current);
+                current = ((LoopBeginNode) current).next();
+                assert current != null;
+            } else if (current instanceof LoopEndNode) {
+                loopEnd((LoopEndNode) current);
+                finishLoopEnds((LoopEndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof AbstractMergeNode) {
+                merge((AbstractMergeNode) current);
+                current = ((AbstractMergeNode) current).next();
+                assert current != null;
+            } else if (current instanceof FixedWithNextNode) {
+                FixedNode next = ((FixedWithNextNode) current).next();
+                assert next != null : current;
+                node(current);
+                current = next;
+            } else if (current instanceof EndNode) {
+                end((EndNode) current);
+                queueMerge((EndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSinkNode) {
+                node(current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSplitNode) {
+                controlSplit((ControlSplitNode) current);
+                queueSuccessors(current);
+                current = nextQueuedNode();
+            } else {
+                assert false : current;
+            }
+        } while (current != null);
+        finished();
+    }
+
+    /**
+     * Two methods enqueue items in {@link #nodeQueue}. Of them, only this method enqueues items
+     * with non-null state (the other method being {@link #queueMerge(EndNode)}).
+     *
+     * <p>
+     * A space optimization is made: the state is cloned for all successors except the first. Given
+     * that right after invoking this method, {@link #nextQueuedNode()} is invoked, that single
+     * non-cloned state instance is in effect "handed over" to its next owner (thus realizing an
+     * owner-is-mutator access protocol).
+     * </p>
+     */
+    private void queueSuccessors(FixedNode x) {
+        T startState = state;
+        T curState = startState;
+        for (Node succ : x.successors()) {
+            if (succ != null) {
+                if (curState == null) {
+                    // the current state isn't cloned for the first successor
+                    // conceptually, the state is handed over to it
+                    curState = startState.clone();
+                }
+                AbstractBeginNode begin = (AbstractBeginNode) succ;
+                nodeQueue.addFirst(new PathStart<>(begin, curState));
+            }
+        }
+    }
+
+    /**
+     * This method is invoked upon not having a (single) next {@link FixedNode} to visit. This
+     * method picks such next-node-to-visit from {@link #nodeQueue} and updates {@link #state} with
+     * the pre-state for that node.
+     *
+     * <p>
+     * Upon reaching a {@link AbstractMergeNode}, some entries are pruned from {@link #nodeStates}
+     * (ie, the entries associated to forward-ends for that merge-node).
+     * </p>
+     */
+    private FixedNode nextQueuedNode() {
+        if (nodeQueue.isEmpty()) {
+            return null;
+        }
+        PathStart<T> elem = nodeQueue.removeFirst();
+        if (elem.node instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) elem.node;
+            state = pruneEntry(merge.forwardEndAt(0));
+            ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1);
+            for (int i = 1; i < merge.forwardEndCount(); i++) {
+                T other = pruneEntry(merge.forwardEndAt(i));
+                states.add(other);
+            }
+            boolean ready = state.merge(merge, states);
+            assert ready : "Not a single-pass iterator after all";
+            return merge;
+        } else {
+            AbstractBeginNode begin = elem.node;
+            assert begin.predecessor() != null;
+            state = elem.stateOnEntry;
+            state.afterSplit(begin);
+            return begin;
+        }
+    }
+
+    /**
+     * Once all loop-end-nodes for a given loop-node have been visited.
+     * <ul>
+     * <li>the state for that loop-node is updated based on the states of the loop-end-nodes</li>
+     * <li>entries in {@link #nodeStates} are pruned for the loop (they aren't going to be looked up
+     * again, anyway)</li>
+     * </ul>
+     *
+     * <p>
+     * The entries removed by this method were inserted:
+     * <ul>
+     * <li>for the loop-begin, by {@link #apply()}</li>
+     * <li>for loop-ends, by (previous) invocations of this method</li>
+     * </ul>
+     * </p>
+     */
+    private void finishLoopEnds(LoopEndNode end) {
+        assert !visitedEnds.isMarked(end);
+        visitedEnds.mark(end);
+        keepForLater(end, state);
+        LoopBeginNode begin = end.loopBegin();
+        boolean endsVisited = true;
+        for (LoopEndNode le : begin.loopEnds()) {
+            if (!visitedEnds.isMarked(le)) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
+            for (LoopEndNode le : begin.orderedLoopEnds()) {
+                T leState = pruneEntry(le);
+                states.add(leState);
+            }
+            T loopBeginState = pruneEntry(begin);
+            loopBeginState.loopEnds(begin, states);
+        }
+    }
+
+    /**
+     * Once all end-nodes for a given merge-node have been visited, that merge-node is added to the
+     * {@link #nodeQueue}
+     *
+     * <p>
+     * {@link #nextQueuedNode()} is in charge of pruning entries (held by {@link #nodeStates}) for
+     * the forward-ends inserted by this method.
+     * </p>
+     */
+    private void queueMerge(EndNode end) {
+        assert !visitedEnds.isMarked(end);
+        visitedEnds.mark(end);
+        keepForLater(end, state);
+        AbstractMergeNode merge = end.merge();
+        boolean endsVisited = true;
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            nodeQueue.add(new PathStart<>(merge, null));
+        }
+    }
+
+    protected abstract void node(FixedNode node);
+
+    protected void end(EndNode endNode) {
+        node(endNode);
+    }
+
+    protected void merge(AbstractMergeNode merge) {
+        node(merge);
+    }
+
+    protected void loopBegin(LoopBeginNode loopBegin) {
+        node(loopBegin);
+    }
+
+    protected void loopEnd(LoopEndNode loopEnd) {
+        node(loopEnd);
+    }
+
+    protected void controlSplit(ControlSplitNode controlSplit) {
+        node(controlSplit);
+    }
+
+    protected void invoke(Invoke invoke) {
+        node(invoke.asNode());
+    }
+
+    /**
+     * The lifecycle that single-pass node iterators go through is described in {@link #apply()}
+     *
+     * <p>
+     * When overriding this method don't forget to invoke this implementation, otherwise the
+     * assertions will be skipped.
+     * </p>
+     */
+    protected void finished() {
+        assert nodeQueue.isEmpty();
+        assert nodeStates.isEmpty();
+    }
+
+    private void keepForLater(FixedNode x, T s) {
+        assert !nodeStates.containsKey(x);
+        assert (x instanceof LoopBeginNode) || (x instanceof LoopEndNode) || (x instanceof EndNode);
+        assert s != null;
+        nodeStates.put(x, s);
+    }
+
+    private T pruneEntry(FixedNode x) {
+        T result = nodeStates.remove(x);
+        assert result != null;
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/StatelessPostOrderNodeIterator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/StatelessPostOrderNodeIterator.java
new file mode 100644
index 0000000..89ee530
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/StatelessPostOrderNodeIterator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.graph;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopEndNode;
+
+/**
+ * This iterator implements a reverse post order iteration over the fixed nodes in the graph,
+ * starting at the given fixed node.
+ *
+ * No changes to the fixed nodes are expected during the iteration, they cause undefined behavior.
+ */
+public abstract class StatelessPostOrderNodeIterator {
+
+    private final NodeBitMap visitedEnds;
+    private final Deque<AbstractBeginNode> nodeQueue;
+    private final FixedNode start;
+
+    public StatelessPostOrderNodeIterator(FixedNode start) {
+        visitedEnds = start.graph().createNodeBitMap();
+        nodeQueue = new ArrayDeque<>();
+        this.start = start;
+    }
+
+    public void apply() {
+        FixedNode current = start;
+
+        do {
+            if (current instanceof LoopBeginNode) {
+                loopBegin((LoopBeginNode) current);
+                current = ((LoopBeginNode) current).next();
+                assert current != null;
+            } else if (current instanceof LoopEndNode) {
+                loopEnd((LoopEndNode) current);
+                assert !visitedEnds.isMarked(current);
+                visitedEnds.mark(current);
+                current = nodeQueue.pollFirst();
+            } else if (current instanceof AbstractMergeNode) {
+                merge((AbstractMergeNode) current);
+                current = ((AbstractMergeNode) current).next();
+                assert current != null;
+            } else if (current instanceof FixedWithNextNode) {
+                node(current);
+                current = ((FixedWithNextNode) current).next();
+            } else if (current instanceof EndNode) {
+                end((EndNode) current);
+                queueMerge((EndNode) current);
+                current = nodeQueue.pollFirst();
+            } else if (current instanceof ControlSinkNode) {
+                node(current);
+                current = nodeQueue.pollFirst();
+            } else if (current instanceof ControlSplitNode) {
+                controlSplit((ControlSplitNode) current);
+                for (Node node : current.successors()) {
+                    nodeQueue.addFirst((AbstractBeginNode) node);
+                }
+                current = nodeQueue.pollFirst();
+            } else {
+                assert false : current;
+            }
+        } while (current != null);
+        finished();
+    }
+
+    private void queueMerge(EndNode end) {
+        assert !visitedEnds.isMarked(end);
+        visitedEnds.mark(end);
+        AbstractMergeNode merge = end.merge();
+        boolean endsVisited = true;
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            nodeQueue.add(merge);
+        }
+    }
+
+    protected void node(@SuppressWarnings("unused") FixedNode node) {
+        // empty default implementation
+    }
+
+    protected void end(EndNode endNode) {
+        node(endNode);
+    }
+
+    protected void merge(AbstractMergeNode merge) {
+        node(merge);
+    }
+
+    protected void loopBegin(LoopBeginNode loopBegin) {
+        node(loopBegin);
+    }
+
+    protected void loopEnd(LoopEndNode loopEnd) {
+        node(loopEnd);
+    }
+
+    protected void controlSplit(ControlSplitNode controlSplit) {
+        node(controlSplit);
+    }
+
+    protected void finished() {
+        // nothing to do
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/package-info.java
new file mode 100644
index 0000000..da0d328
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ *
+ */
+package org.graalvm.compiler.phases.graph;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/package-info.java
new file mode 100644
index 0000000..1563476
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * The top-level package in Graal containing options, counters and timers.
+ *
+ * Graal is intended to be used with multiple JVM's so makes no use of or reference to classes for a
+ * specific JVM.
+ */
+package org.graalvm.compiler.phases;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/BlockClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/BlockClosure.java
new file mode 100644
index 0000000..ebf2067
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/BlockClosure.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.schedule;
+
+import org.graalvm.compiler.nodes.cfg.Block;
+
+/**
+ * The {@code BlockClosure} interface represents a closure for iterating over blocks.
+ */
+public interface BlockClosure {
+
+    void apply(Block block);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java
new file mode 100644
index 0000000..4ddfd57
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.schedule;
+
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.HIRLoop;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+
+public final class MemoryScheduleVerification extends BlockIteratorClosure<Set<FloatingReadNode>> {
+
+    private final BlockMap<List<Node>> blockToNodesMap;
+
+    public static boolean check(Block startBlock, BlockMap<List<Node>> blockToNodesMap) {
+        ReentrantBlockIterator.apply(new MemoryScheduleVerification(blockToNodesMap), startBlock);
+        return true;
+    }
+
+    private MemoryScheduleVerification(BlockMap<List<Node>> blockToNodesMap) {
+        this.blockToNodesMap = blockToNodesMap;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> getInitialState() {
+        return CollectionsFactory.newSet();
+    }
+
+    @Override
+    protected Set<FloatingReadNode> processBlock(Block block, Set<FloatingReadNode> currentState) {
+        AbstractBeginNode beginNode = block.getBeginNode();
+        if (beginNode instanceof AbstractMergeNode) {
+            AbstractMergeNode abstractMergeNode = (AbstractMergeNode) beginNode;
+            for (PhiNode phi : abstractMergeNode.phis()) {
+                if (phi instanceof MemoryPhiNode) {
+                    MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
+                    addFloatingReadUsages(currentState, memoryPhiNode);
+                }
+            }
+        }
+        for (Node n : blockToNodesMap.get(block)) {
+            if (n instanceof MemoryCheckpoint) {
+                if (n instanceof MemoryCheckpoint.Single) {
+                    MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
+                    processLocation(n, single.getLocationIdentity(), currentState);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
+                    for (LocationIdentity location : multi.getLocationIdentities()) {
+                        processLocation(n, location, currentState);
+                    }
+                }
+
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof MemoryNode) {
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) {
+                    if (currentState.contains(floatingReadNode)) {
+                        // Floating read was found in the state.
+                        currentState.remove(floatingReadNode);
+                    } else {
+                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule. Block=" +
+                                        block + ", block begin: " + block.getBeginNode() + " block loop: " + block.getLoop() + ", " + blockToNodesMap.get(block).get(0));
+                    }
+                }
+
+            }
+        }
+        return currentState;
+    }
+
+    private static void addFloatingReadUsages(Set<FloatingReadNode> currentState, Node n) {
+        for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) {
+            if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) {
+                currentState.add(read);
+            }
+        }
+    }
+
+    private void processLocation(Node n, LocationIdentity location, Set<FloatingReadNode> currentState) {
+        assert n != null;
+        if (location.isImmutable()) {
+            return;
+        }
+
+        for (FloatingReadNode r : cloneState(currentState)) {
+            if (r.getLocationIdentity().overlaps(location)) {
+                // This read is killed by this location.
+                currentState.remove(r);
+            }
+        }
+    }
+
+    @Override
+    protected Set<FloatingReadNode> merge(Block merge, List<Set<FloatingReadNode>> states) {
+        Set<FloatingReadNode> result = states.get(0);
+        for (int i = 1; i < states.size(); ++i) {
+            result.retainAll(states.get(i));
+        }
+        return result;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> cloneState(Set<FloatingReadNode> oldState) {
+        Set<FloatingReadNode> result = CollectionsFactory.newSet();
+        if (oldState != null) {
+            result.addAll(oldState);
+        }
+        return result;
+    }
+
+    @Override
+    protected List<Set<FloatingReadNode>> processLoop(Loop<Block> loop, Set<FloatingReadNode> initialState) {
+        HIRLoop l = (HIRLoop) loop;
+        for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).phis().filter(MemoryPhiNode.class)) {
+            for (FloatingReadNode r : cloneState(initialState)) {
+                if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) {
+                    initialState.remove(r);
+                }
+            }
+        }
+        return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java
new file mode 100644
index 0000000..0ee470d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.schedule;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Formatter;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.NodeStack;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.cfg.HIRLoop;
+import org.graalvm.compiler.nodes.cfg.LocationSet;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.phases.Phase;
+
+public final class SchedulePhase extends Phase {
+
+    public enum SchedulingStrategy {
+        EARLIEST,
+        LATEST,
+        LATEST_OUT_OF_LOOPS,
+        FINAL_SCHEDULE
+    }
+
+    private final SchedulingStrategy selectedStrategy;
+
+    private final boolean immutableGraph;
+
+    public SchedulePhase() {
+        this(false);
+    }
+
+    public SchedulePhase(boolean immutableGraph) {
+        this(OptScheduleOutOfLoops.getValue() ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST, immutableGraph);
+    }
+
+    public SchedulePhase(SchedulingStrategy strategy) {
+        this(strategy, false);
+    }
+
+    public SchedulePhase(SchedulingStrategy strategy, boolean immutableGraph) {
+        this.selectedStrategy = strategy;
+        this.immutableGraph = immutableGraph;
+    }
+
+    private NodeEventScope verifyImmutableGraph(StructuredGraph graph) {
+        boolean assertionsEnabled = false;
+        assert (assertionsEnabled = true) == true;
+        if (immutableGraph && assertionsEnabled) {
+            return graph.trackNodeEvents(new NodeEventListener() {
+                @Override
+                public void event(NodeEvent e, Node node) {
+                    assert false : "graph changed: " + e + " on node " + node;
+                }
+            });
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph) {
+        try (NodeEventScope scope = verifyImmutableGraph(graph)) {
+            Instance inst = new Instance();
+            inst.run(graph, selectedStrategy, immutableGraph);
+        }
+    }
+
+    public static class Instance {
+
+        /**
+         * Map from blocks to the nodes in each block.
+         */
+        protected ControlFlowGraph cfg;
+        protected BlockMap<List<Node>> blockToNodesMap;
+        protected NodeMap<Block> nodeToBlockMap;
+
+        @SuppressWarnings("try")
+        public void run(StructuredGraph graph, SchedulingStrategy selectedStrategy, boolean immutableGraph) {
+            // assert GraphOrder.assertNonCyclicGraph(graph);
+            cfg = ControlFlowGraph.compute(graph, true, true, true, false);
+
+            NodeMap<Block> currentNodeMap = graph.createNodeMap();
+            NodeBitMap visited = graph.createNodeBitMap();
+            BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
+            this.nodeToBlockMap = currentNodeMap;
+            this.blockToNodesMap = earliestBlockToNodesMap;
+
+            scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph);
+
+            if (selectedStrategy != SchedulingStrategy.EARLIEST) {
+                // For non-earliest schedules, we need to do a second pass.
+                BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
+                for (Block b : cfg.getBlocks()) {
+                    latestBlockToNodesMap.put(b, new ArrayList<Node>());
+                }
+
+                BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph);
+                sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+
+                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
+                assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
+
+                this.blockToNodesMap = latestBlockToNodesMap;
+
+                cfg.setNodeToBlock(currentNodeMap);
+            }
+
+            graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap));
+        }
+
+        @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
+        private BlockMap<ArrayList<FloatingReadNode>> calcLatestBlocks(SchedulingStrategy strategy, NodeMap<Block> currentNodeMap, BlockMap<List<Node>> earliestBlockToNodesMap, NodeBitMap visited,
+                        BlockMap<List<Node>> latestBlockToNodesMap, boolean immutableGraph) {
+            BlockMap<ArrayList<FloatingReadNode>> watchListMap = new BlockMap<>(cfg);
+            Block[] reversePostOrder = cfg.reversePostOrder();
+            for (int j = reversePostOrder.length - 1; j >= 0; --j) {
+                Block currentBlock = reversePostOrder[j];
+                List<Node> blockToNodes = earliestBlockToNodesMap.get(currentBlock);
+                LocationSet killed = null;
+                int previousIndex = blockToNodes.size();
+                for (int i = blockToNodes.size() - 1; i >= 0; --i) {
+                    Node currentNode = blockToNodes.get(i);
+                    assert currentNodeMap.get(currentNode) == currentBlock;
+                    assert !(currentNode instanceof PhiNode) && !(currentNode instanceof ProxyNode);
+                    assert visited.isMarked(currentNode);
+                    if (currentNode instanceof FixedNode) {
+                        // For these nodes, the earliest is at the same time the latest block.
+                    } else {
+                        Block latestBlock = null;
+
+                        LocationIdentity constrainingLocation = null;
+                        if (currentNode instanceof FloatingReadNode) {
+                            // We are scheduling a floating read node => check memory
+                            // anti-dependencies.
+                            FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
+                            LocationIdentity location = floatingReadNode.getLocationIdentity();
+                            if (location.isMutable()) {
+                                // Location can be killed.
+                                constrainingLocation = location;
+                                if (currentBlock.canKill(location)) {
+                                    if (killed == null) {
+                                        killed = new LocationSet();
+                                    }
+                                    fillKillSet(killed, blockToNodes.subList(i + 1, previousIndex));
+                                    previousIndex = i;
+                                    if (killed.contains(location)) {
+                                        // Earliest block kills location => we need to stay within
+                                        // earliest block.
+                                        latestBlock = currentBlock;
+                                    }
+                                }
+                            }
+                        }
+
+                        if (latestBlock == null) {
+                            // We are not constraint within earliest block => calculate optimized
+                            // schedule.
+                            calcLatestBlock(currentBlock, strategy, currentNode, currentNodeMap, constrainingLocation, watchListMap, latestBlockToNodesMap, visited, immutableGraph);
+                        } else {
+                            selectLatestBlock(currentNode, currentBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap);
+                        }
+                    }
+                }
+            }
+            return watchListMap;
+        }
+
+        protected static void selectLatestBlock(Node currentNode, Block currentBlock, Block latestBlock, NodeMap<Block> currentNodeMap, BlockMap<ArrayList<FloatingReadNode>> watchListMap,
+                        LocationIdentity constrainingLocation, BlockMap<List<Node>> latestBlockToNodesMap) {
+
+            assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock);
+            if (currentBlock != latestBlock) {
+                currentNodeMap.setAndGrow(currentNode, latestBlock);
+
+                if (constrainingLocation != null && latestBlock.canKill(constrainingLocation)) {
+                    if (watchListMap.get(latestBlock) == null) {
+                        watchListMap.put(latestBlock, new ArrayList<>());
+                    }
+                    watchListMap.get(latestBlock).add((FloatingReadNode) currentNode);
+                }
+            }
+
+            latestBlockToNodesMap.get(latestBlock).add(currentNode);
+        }
+
+        private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) {
+            assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format(
+                            "%s %s (%s) %s (%s)", currentNode, earliestBlock, earliestBlock.getBeginNode(), latestBlock, latestBlock.getBeginNode());
+            return true;
+        }
+
+        private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
+            for (Block b : cfg.getBlocks()) {
+                List<Node> nodes = blockToNodesMap.get(b);
+                for (Node n : nodes) {
+                    assert n.isAlive();
+                    assert nodeMap.get(n) == b;
+                    StructuredGraph g = (StructuredGraph) n.graph();
+                    if (g.hasLoops() && g.getGuardsStage() == GuardsStage.AFTER_FSA && n instanceof DeoptimizeNode) {
+                        assert b.getLoopDepth() == 0 : n;
+                    }
+                }
+            }
+            return true;
+        }
+
+        public static Block checkKillsBetween(Block earliestBlock, Block latestBlock, LocationIdentity location) {
+            assert strictlyDominates(earliestBlock, latestBlock);
+            Block current = latestBlock.getDominator();
+
+            // Collect dominator chain that needs checking.
+            List<Block> dominatorChain = new ArrayList<>();
+            dominatorChain.add(latestBlock);
+            while (current != earliestBlock) {
+                // Current is an intermediate dominator between earliestBlock and latestBlock.
+                assert strictlyDominates(earliestBlock, current) && strictlyDominates(current, latestBlock);
+                if (current.canKill(location)) {
+                    dominatorChain.clear();
+                }
+                dominatorChain.add(current);
+                current = current.getDominator();
+            }
+
+            // The first element of dominatorChain now contains the latest possible block.
+            assert dominatorChain.size() >= 1;
+            assert dominatorChain.get(dominatorChain.size() - 1).getDominator() == earliestBlock;
+
+            Block lastBlock = earliestBlock;
+            for (int i = dominatorChain.size() - 1; i >= 0; --i) {
+                Block currentBlock = dominatorChain.get(i);
+                if (currentBlock.getLoopDepth() > lastBlock.getLoopDepth()) {
+                    // We are entering a loop boundary. The new loops must not kill the location for
+                    // the crossing to be safe.
+                    if (currentBlock.getLoop() != null && ((HIRLoop) currentBlock.getLoop()).canKill(location)) {
+                        break;
+                    }
+                }
+
+                if (currentBlock.canKillBetweenThisAndDominator(location)) {
+                    break;
+                }
+                lastBlock = currentBlock;
+            }
+
+            return lastBlock;
+        }
+
+        private static void fillKillSet(LocationSet killed, List<Node> subList) {
+            if (!killed.isAny()) {
+                for (Node n : subList) {
+                    // Check if this node kills a node in the watch list.
+                    if (n instanceof MemoryCheckpoint.Single) {
+                        LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                        killed.add(identity);
+                        if (killed.isAny()) {
+                            return;
+                        }
+                    } else if (n instanceof MemoryCheckpoint.Multi) {
+                        for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                            killed.add(identity);
+                            if (killed.isAny()) {
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> currentNodeMap,
+                        BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap visited) {
+            for (Block b : cfg.getBlocks()) {
+                sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+            }
+        }
+
+        private static void sortNodesLatestWithinBlock(Block b, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> nodeMap,
+                        BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap unprocessed) {
+            List<Node> earliestSorting = earliestBlockToNodesMap.get(b);
+            ArrayList<Node> result = new ArrayList<>(earliestSorting.size());
+            ArrayList<FloatingReadNode> watchList = null;
+            if (watchListMap != null) {
+                watchList = watchListMap.get(b);
+                assert watchList == null || !b.getKillLocations().isEmpty();
+            }
+            AbstractBeginNode beginNode = b.getBeginNode();
+            if (beginNode instanceof LoopExitNode) {
+                LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+                for (ProxyNode proxy : loopExitNode.proxies()) {
+                    unprocessed.clear(proxy);
+                    ValueNode value = proxy.value();
+                    // if multiple proxies reference the same value, schedule the value of a
+                    // proxy once
+                    if (value != null && nodeMap.get(value) == b && unprocessed.isMarked(value)) {
+                        sortIntoList(value, b, result, nodeMap, unprocessed, null);
+                    }
+                }
+            }
+            FixedNode endNode = b.getEndNode();
+            FixedNode fixedEndNode = null;
+            if (isFixedEnd(endNode)) {
+                // Only if the end node is either a control split or an end node, we need to force
+                // it to be the last node in the schedule.
+                fixedEndNode = endNode;
+            }
+            for (Node n : earliestSorting) {
+                if (n != fixedEndNode) {
+                    if (n instanceof FixedNode) {
+                        assert nodeMap.get(n) == b;
+                        checkWatchList(b, nodeMap, unprocessed, result, watchList, n);
+                        sortIntoList(n, b, result, nodeMap, unprocessed, null);
+                    } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) {
+                        FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                        LocationIdentity location = floatingReadNode.getLocationIdentity();
+                        if (b.canKill(location)) {
+                            // This read can be killed in this block, add to watch list.
+                            if (watchList == null) {
+                                watchList = new ArrayList<>();
+                            }
+                            watchList.add(floatingReadNode);
+                        }
+                    }
+                }
+            }
+
+            for (Node n : latestBlockToNodesMap.get(b)) {
+                assert nodeMap.get(n) == b : n;
+                assert !(n instanceof FixedNode);
+                if (unprocessed.isMarked(n)) {
+                    sortIntoList(n, b, result, nodeMap, unprocessed, fixedEndNode);
+                }
+            }
+
+            if (endNode != null && unprocessed.isMarked(endNode)) {
+                sortIntoList(endNode, b, result, nodeMap, unprocessed, null);
+            }
+
+            latestBlockToNodesMap.put(b, result);
+        }
+
+        private static void checkWatchList(Block b, NodeMap<Block> nodeMap, NodeBitMap unprocessed, ArrayList<Node> result, ArrayList<FloatingReadNode> watchList, Node n) {
+            if (watchList != null && !watchList.isEmpty()) {
+                // Check if this node kills a node in the watch list.
+                if (n instanceof MemoryCheckpoint.Single) {
+                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                    checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                        checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
+                    }
+                }
+            }
+        }
+
+        private static void checkWatchList(ArrayList<FloatingReadNode> watchList, LocationIdentity identity, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed) {
+            assert identity.isMutable();
+            if (identity.isAny()) {
+                for (FloatingReadNode r : watchList) {
+                    if (unprocessed.isMarked(r)) {
+                        sortIntoList(r, b, result, nodeMap, unprocessed, null);
+                    }
+                }
+                watchList.clear();
+            } else {
+                int index = 0;
+                while (index < watchList.size()) {
+                    FloatingReadNode r = watchList.get(index);
+                    LocationIdentity locationIdentity = r.getLocationIdentity();
+                    assert locationIdentity.isMutable();
+                    if (unprocessed.isMarked(r)) {
+                        if (identity.overlaps(locationIdentity)) {
+                            sortIntoList(r, b, result, nodeMap, unprocessed, null);
+                        } else {
+                            ++index;
+                            continue;
+                        }
+                    }
+                    int lastIndex = watchList.size() - 1;
+                    watchList.set(index, watchList.get(lastIndex));
+                    watchList.remove(lastIndex);
+                }
+            }
+        }
+
+        private static void sortIntoList(Node n, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed, Node excludeNode) {
+            assert unprocessed.isMarked(n) : n;
+            assert nodeMap.get(n) == b;
+
+            if (n instanceof PhiNode) {
+                return;
+            }
+
+            unprocessed.clear(n);
+
+            for (Node input : n.inputs()) {
+                if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) {
+                    sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode);
+                }
+            }
+
+            if (n instanceof ProxyNode) {
+                // Skip proxy nodes.
+            } else {
+                result.add(n);
+            }
+
+        }
+
+        protected void calcLatestBlock(Block earliestBlock, SchedulingStrategy strategy, Node currentNode, NodeMap<Block> currentNodeMap, LocationIdentity constrainingLocation,
+                        BlockMap<ArrayList<FloatingReadNode>> watchListMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeBitMap visited, boolean immutableGraph) {
+            Block latestBlock = null;
+            assert currentNode.hasUsages();
+            for (Node usage : currentNode.usages()) {
+                if (immutableGraph && !visited.contains(usage)) {
+                    /*
+                     * Normally, dead nodes are deleted by the scheduler before we reach this point.
+                     * Only when the scheduler is asked to not modify a graph, we can see dead nodes
+                     * here.
+                     */
+                    continue;
+                }
+                latestBlock = calcBlockForUsage(currentNode, usage, latestBlock, currentNodeMap);
+            }
+
+            if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
+                assert latestBlock != null;
+                while (latestBlock.getLoopDepth() > earliestBlock.getLoopDepth() && latestBlock != earliestBlock.getDominator()) {
+                    latestBlock = latestBlock.getDominator();
+                }
+            }
+
+            if (latestBlock != earliestBlock && latestBlock != earliestBlock.getDominator() && constrainingLocation != null) {
+                latestBlock = checkKillsBetween(earliestBlock, latestBlock, constrainingLocation);
+            }
+
+            selectLatestBlock(currentNode, earliestBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap);
+        }
+
+        private static Block calcBlockForUsage(Node node, Node usage, Block startBlock, NodeMap<Block> currentNodeMap) {
+            assert !(node instanceof PhiNode);
+            Block currentBlock = startBlock;
+            if (usage instanceof PhiNode) {
+                // An input to a PhiNode is used at the end of the predecessor block that
+                // corresponds to the PhiNode input. One PhiNode can use an input multiple times.
+                PhiNode phi = (PhiNode) usage;
+                AbstractMergeNode merge = phi.merge();
+                Block mergeBlock = currentNodeMap.get(merge);
+                for (int i = 0; i < phi.valueCount(); ++i) {
+                    if (phi.valueAt(i) == node) {
+                        Block otherBlock = mergeBlock.getPredecessors()[i];
+                        currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+                    }
+                }
+            } else if (usage instanceof AbstractBeginNode) {
+                AbstractBeginNode abstractBeginNode = (AbstractBeginNode) usage;
+                if (abstractBeginNode instanceof StartNode) {
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(abstractBeginNode));
+                } else {
+                    Block otherBlock = currentNodeMap.get(abstractBeginNode).getDominator();
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+                }
+            } else {
+                // All other types of usages: Put the input into the same block as the usage.
+                Block otherBlock = currentNodeMap.get(usage);
+                currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+            }
+            return currentBlock;
+        }
+
+        private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph) {
+
+            BitSet floatingReads = new BitSet(cfg.getBlocks().length);
+
+            // Add begin nodes as the first entry and set the block for phi nodes.
+            for (Block b : cfg.getBlocks()) {
+                AbstractBeginNode beginNode = b.getBeginNode();
+                ArrayList<Node> nodes = new ArrayList<>();
+                nodeToBlock.set(beginNode, b);
+                nodes.add(beginNode);
+                blockToNodes.put(b, nodes);
+
+                if (beginNode instanceof AbstractMergeNode) {
+                    AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
+                    for (PhiNode phi : mergeNode.phis()) {
+                        nodeToBlock.set(phi, b);
+                    }
+                } else if (beginNode instanceof LoopExitNode) {
+                    LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+                    for (ProxyNode proxy : loopExitNode.proxies()) {
+                        nodeToBlock.set(proxy, b);
+                    }
+                }
+            }
+
+            NodeStack stack = new NodeStack();
+
+            // Start analysis with control flow ends.
+            Block[] reversePostOrder = cfg.reversePostOrder();
+            for (int j = reversePostOrder.length - 1; j >= 0; --j) {
+                Block b = reversePostOrder[j];
+                FixedNode endNode = b.getEndNode();
+                if (isFixedEnd(endNode)) {
+                    stack.push(endNode);
+                    nodeToBlock.set(endNode, b);
+                }
+            }
+
+            processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+
+            // Visit back input edges of loop phis.
+            boolean changed;
+            boolean unmarkedPhi;
+            do {
+                changed = false;
+                unmarkedPhi = false;
+                for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
+                    for (PhiNode phi : loopBegin.phis()) {
+                        if (visited.isMarked(phi)) {
+                            for (int i = 0; i < loopBegin.getLoopEndCount(); ++i) {
+                                Node node = phi.valueAt(i + loopBegin.forwardEndCount());
+                                if (node != null && !visited.isMarked(node)) {
+                                    changed = true;
+                                    stack.push(node);
+                                    processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+                                }
+                            }
+                        } else {
+                            unmarkedPhi = true;
+                        }
+                    }
+                }
+
+                /*
+                 * the processing of one loop phi could have marked a previously checked loop phi,
+                 * therefore this needs to be iterative.
+                 */
+            } while (unmarkedPhi && changed);
+
+            // Check for dead nodes.
+            if (!immutableGraph && visited.getCounter() < graph.getNodeCount()) {
+                for (Node n : graph.getNodes()) {
+                    if (!visited.isMarked(n)) {
+                        n.clearInputs();
+                        n.markDeleted();
+                    }
+                }
+            }
+
+            // Add end nodes as the last nodes in each block.
+            for (Block b : cfg.getBlocks()) {
+                FixedNode endNode = b.getEndNode();
+                if (isFixedEnd(endNode)) {
+                    if (endNode != b.getBeginNode()) {
+                        addNode(blockToNodes, b, endNode);
+                    }
+                }
+            }
+
+            if (!floatingReads.isEmpty()) {
+                for (Block b : cfg.getBlocks()) {
+                    if (floatingReads.get(b.getId())) {
+                        resortEarliestWithinBlock(b, blockToNodes, nodeToBlock, visited);
+                    }
+                }
+            }
+
+            assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
+        }
+
+        private static boolean isFixedEnd(FixedNode endNode) {
+            return endNode instanceof ControlSplitNode || endNode instanceof ControlSinkNode || endNode instanceof AbstractEndNode;
+        }
+
+        private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
+            ArrayList<FloatingReadNode> watchList = new ArrayList<>();
+            List<Node> oldList = blockToNodes.get(b);
+            AbstractBeginNode beginNode = b.getBeginNode();
+            for (Node n : oldList) {
+                if (n instanceof FloatingReadNode) {
+                    FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                    LocationIdentity locationIdentity = floatingReadNode.getLocationIdentity();
+                    MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
+                    if (locationIdentity.isMutable() && lastLocationAccess != null) {
+                        ValueNode lastAccessLocation = lastLocationAccess.asNode();
+                        if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) {
+                            // This node's last access location is within this block. Add to watch
+                            // list when processing the last access location.
+                        } else {
+                            watchList.add(floatingReadNode);
+                        }
+                    }
+                }
+            }
+
+            ArrayList<Node> newList = new ArrayList<>(oldList.size());
+            assert oldList.get(0) == beginNode;
+            unprocessed.clear(beginNode);
+            newList.add(beginNode);
+            for (int i = 1; i < oldList.size(); ++i) {
+                Node n = oldList.get(i);
+                if (unprocessed.isMarked(n)) {
+                    if (n instanceof MemoryNode) {
+                        if (n instanceof MemoryCheckpoint) {
+                            assert n instanceof FixedNode;
+                            if (watchList.size() > 0) {
+                                // Check whether we need to commit reads from the watch list.
+                                checkWatchList(b, nodeToBlock, unprocessed, newList, watchList, n);
+                            }
+                        }
+                        // Add potential dependent reads to the watch list.
+                        for (Node usage : n.usages()) {
+                            if (usage instanceof FloatingReadNode) {
+                                FloatingReadNode floatingReadNode = (FloatingReadNode) usage;
+                                if (nodeToBlock.get(floatingReadNode) == b && floatingReadNode.getLastLocationAccess() == n && !(n instanceof MemoryPhiNode)) {
+                                    watchList.add(floatingReadNode);
+                                }
+                            }
+                        }
+                    }
+                    assert unprocessed.isMarked(n);
+                    unprocessed.clear(n);
+                    newList.add(n);
+                } else {
+                    // This node was pulled up.
+                    assert !(n instanceof FixedNode) : n;
+                }
+            }
+
+            for (Node n : newList) {
+                unprocessed.mark(n);
+            }
+
+            assert newList.size() == oldList.size();
+            blockToNodes.put(b, newList);
+        }
+
+        private static void addNode(BlockMap<List<Node>> blockToNodes, Block b, Node endNode) {
+            assert !blockToNodes.get(b).contains(endNode) : endNode;
+            blockToNodes.get(b).add(endNode);
+        }
+
+        private static void processStack(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, BitSet floatingReads, NodeStack stack) {
+            Block startBlock = cfg.getStartBlock();
+            while (!stack.isEmpty()) {
+                Node current = stack.peek();
+                if (visited.checkAndMarkInc(current)) {
+
+                    // Push inputs and predecessor.
+                    Node predecessor = current.predecessor();
+                    if (predecessor != null) {
+                        stack.push(predecessor);
+                    }
+
+                    if (current instanceof PhiNode) {
+                        processStackPhi(stack, (PhiNode) current);
+                    } else if (current instanceof ProxyNode) {
+                        processStackProxy(stack, (ProxyNode) current);
+                    } else if (current instanceof FrameState) {
+                        processStackFrameState(stack, current);
+                    } else {
+                        current.pushInputs(stack);
+                    }
+                } else {
+                    stack.pop();
+                    if (nodeToBlock.get(current) == null) {
+                        Block curBlock = cfg.blockFor(current);
+                        if (curBlock == null) {
+                            assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
+                            Block earliest = startBlock;
+                            for (Node input : current.inputs()) {
+                                Block inputEarliest = nodeToBlock.get(input);
+                                if (inputEarliest == null) {
+                                    assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current : current;
+                                } else {
+                                    assert inputEarliest != null;
+                                    if (inputEarliest.getEndNode() == input) {
+                                        // This is the last node of the block.
+                                        if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                            // Keep regular inputEarliest.
+                                        } else if (input instanceof ControlSplitNode) {
+                                            inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
+                                        } else {
+                                            assert inputEarliest.getSuccessorCount() == 1;
+                                            assert !(input instanceof AbstractEndNode);
+                                            // Keep regular inputEarliest
+                                        }
+                                    }
+                                    if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
+                                        earliest = inputEarliest;
+                                    }
+                                }
+                            }
+                            curBlock = earliest;
+                        }
+                        assert curBlock != null;
+                        addNode(blockToNodes, curBlock, current);
+                        nodeToBlock.set(current, curBlock);
+                        if (current instanceof FloatingReadNode) {
+                            FloatingReadNode floatingReadNode = (FloatingReadNode) current;
+                            if (curBlock.canKill(floatingReadNode.getLocationIdentity())) {
+                                floatingReads.set(curBlock.getId());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private static void processStackFrameState(NodeStack stack, Node current) {
+            for (Node input : current.inputs()) {
+                if (input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                    // Ignore the cycle.
+                } else {
+                    stack.push(input);
+                }
+            }
+        }
+
+        private static void processStackProxy(NodeStack stack, ProxyNode proxyNode) {
+            LoopExitNode proxyPoint = proxyNode.proxyPoint();
+            for (Node input : proxyNode.inputs()) {
+                if (input != proxyPoint) {
+                    stack.push(input);
+                }
+            }
+        }
+
+        private static void processStackPhi(NodeStack stack, PhiNode phiNode) {
+            AbstractMergeNode merge = phiNode.merge();
+            for (int i = 0; i < merge.forwardEndCount(); ++i) {
+                Node input = phiNode.valueAt(i);
+                if (input != null) {
+                    stack.push(input);
+                }
+            }
+        }
+
+        public String printScheduleHelper(String desc) {
+            Formatter buf = new Formatter();
+            buf.format("=== %s / %s ===%n", getCFG().getStartBlock().getBeginNode().graph(), desc);
+            for (Block b : getCFG().getBlocks()) {
+                buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
+                buf.format("dom: %s. ", b.getDominator());
+                buf.format("preds: %s. ", Arrays.toString(b.getPredecessors()));
+                buf.format("succs: %s ====%n", Arrays.toString(b.getSuccessors()));
+
+                if (blockToNodesMap.get(b) != null) {
+                    for (Node n : nodesFor(b)) {
+                        printNode(n);
+                    }
+                } else {
+                    for (Node n : b.getNodes()) {
+                        printNode(n);
+                    }
+                }
+            }
+            buf.format("%n");
+            return buf.toString();
+        }
+
+        private static void printNode(Node n) {
+            Formatter buf = new Formatter();
+            buf.format("%s", n);
+            if (n instanceof MemoryCheckpoint.Single) {
+                buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
+            } else if (n instanceof MemoryCheckpoint.Multi) {
+                buf.format(" // kills ");
+                for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                    buf.format("%s, ", locid);
+                }
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode frn = (FloatingReadNode) n;
+                buf.format(" // from %s", frn.getLocationIdentity());
+                buf.format(", lastAccess: %s", frn.getLastLocationAccess());
+                buf.format(", address: %s", frn.getAddress());
+            } else if (n instanceof GuardNode) {
+                buf.format(", anchor: %s", ((GuardNode) n).getAnchor());
+            }
+            Debug.log("%s", buf);
+        }
+
+        public ControlFlowGraph getCFG() {
+            return cfg;
+        }
+
+        /**
+         * Gets the nodes in a given block.
+         */
+        public List<Node> nodesFor(Block block) {
+            return blockToNodesMap.get(block);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/CompilerConfiguration.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/CompilerConfiguration.java
new file mode 100644
index 0000000..a63d3b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/CompilerConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import org.graalvm.compiler.phases.PhaseSuite;
+
+public interface CompilerConfiguration {
+
+    PhaseSuite<HighTierContext> createHighTier();
+
+    PhaseSuite<MidTierContext> createMidTier();
+
+    PhaseSuite<LowTierContext> createLowTier();
+
+    LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage();
+
+    LIRPhaseSuite<AllocationContext> createAllocationStage();
+
+    LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/HighTierContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/HighTierContext.java
new file mode 100644
index 0000000..351e6fd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/HighTierContext.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.util.Providers;
+
+public class HighTierContext extends PhaseContext {
+
+    private final PhaseSuite<HighTierContext> graphBuilderSuite;
+
+    private final OptimisticOptimizations optimisticOpts;
+
+    public HighTierContext(Providers providers, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts) {
+        super(providers);
+        this.graphBuilderSuite = graphBuilderSuite;
+        this.optimisticOpts = optimisticOpts;
+    }
+
+    public PhaseSuite<HighTierContext> getGraphBuilderSuite() {
+        return graphBuilderSuite;
+    }
+
+    public OptimisticOptimizations getOptimisticOptimizations() {
+        return optimisticOpts;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/LowTierContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/LowTierContext.java
new file mode 100644
index 0000000..26fc833
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/LowTierContext.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class LowTierContext extends PhaseContext {
+
+    private final TargetProvider target;
+
+    public LowTierContext(Providers copyFrom, TargetProvider target) {
+        super(copyFrom);
+        this.target = target;
+    }
+
+    public TargetDescription getTarget() {
+        return target.getTarget();
+    }
+
+    public TargetProvider getTargetProvider() {
+        return target;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/MidTierContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/MidTierContext.java
new file mode 100644
index 0000000..d0d6dab
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/MidTierContext.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ProfilingInfo;
+
+public class MidTierContext extends PhaseContext {
+
+    private final TargetProvider target;
+    private final OptimisticOptimizations optimisticOpts;
+    private final ProfilingInfo profilingInfo;
+
+    public MidTierContext(Providers copyFrom, TargetProvider target, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo) {
+        super(copyFrom);
+        this.target = target;
+        this.optimisticOpts = optimisticOpts;
+        this.profilingInfo = profilingInfo;
+    }
+
+    public TargetDescription getTarget() {
+        return target.getTarget();
+    }
+
+    public TargetProvider getTargetProvider() {
+        return target;
+    }
+
+    public OptimisticOptimizations getOptimisticOptimizations() {
+        return optimisticOpts;
+    }
+
+    public ProfilingInfo getProfilingInfo() {
+        return profilingInfo;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java
new file mode 100644
index 0000000..9a6e307
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class PhaseContext {
+
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+    private final ConstantFieldProvider constantFieldProvider;
+    private final LoweringProvider lowerer;
+    private final Replacements replacements;
+    private final StampProvider stampProvider;
+    private final NodeCostProvider nodeCostProvider;
+
+    public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer, Replacements replacements,
+                    StampProvider stampProvider, NodeCostProvider nodeCostProvider) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.lowerer = lowerer;
+        this.replacements = replacements;
+        this.stampProvider = stampProvider;
+        this.nodeCostProvider = nodeCostProvider;
+    }
+
+    public PhaseContext(Providers providers) {
+        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getLowerer(), providers.getReplacements(), providers.getStampProvider(),
+                        providers.getNodeCostProvider());
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    public LoweringProvider getLowerer() {
+        return lowerer;
+    }
+
+    public Replacements getReplacements() {
+        return replacements;
+    }
+
+    public StampProvider getStampProvider() {
+        return stampProvider;
+    }
+
+    public NodeCostProvider getNodeCostProvider() {
+        return nodeCostProvider;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java
new file mode 100644
index 0000000..59a30c9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.phases.PhaseSuite;
+
+public final class Suites {
+
+    private final PhaseSuite<HighTierContext> highTier;
+    private final PhaseSuite<MidTierContext> midTier;
+    private final PhaseSuite<LowTierContext> lowTier;
+    private boolean immutable;
+
+    public PhaseSuite<HighTierContext> getHighTier() {
+        return highTier;
+    }
+
+    public PhaseSuite<MidTierContext> getMidTier() {
+        return midTier;
+    }
+
+    public PhaseSuite<LowTierContext> getLowTier() {
+        return lowTier;
+    }
+
+    public Suites(PhaseSuite<HighTierContext> highTier, PhaseSuite<MidTierContext> midTier, PhaseSuite<LowTierContext> lowTier) {
+        this.highTier = highTier;
+        this.midTier = midTier;
+        this.lowTier = lowTier;
+    }
+
+    public static Suites createSuites(CompilerConfiguration config) {
+        return new Suites(config.createHighTier(), config.createMidTier(), config.createLowTier());
+    }
+
+    public static LIRSuites createLIRSuites(CompilerConfiguration config) {
+        return new LIRSuites(config.createPreAllocationOptimizationStage(), config.createAllocationStage(), config.createPostAllocationOptimizationStage());
+    }
+
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    public synchronized void setImmutable() {
+        if (!immutable) {
+            highTier.setImmutable();
+            midTier.setImmutable();
+            lowTier.setImmutable();
+            immutable = true;
+        }
+    }
+
+    public Suites copy() {
+        return new Suites(highTier.copy(), midTier.copy(), lowTier.copy());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesCreator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesCreator.java
new file mode 100644
index 0000000..39dfc83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesCreator.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.lir.phases.LIRSuites;
+
+/**
+ * Interface used for composing {@link SuitesProvider}s.
+ */
+public interface SuitesCreator extends SuitesProvider {
+    /**
+     * Create a new set of phase suites based on the current option settings.
+     */
+    Suites createSuites();
+
+    /**
+     * Create a new set of low-level phase suites based on the current option settings.
+     */
+    LIRSuites createLIRSuites();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesProvider.java
new file mode 100644
index 0000000..43762c0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/SuitesProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.phases.PhaseSuite;
+
+/**
+ * Main interface providing access to suites used for compilation.
+ */
+
+public interface SuitesProvider {
+
+    /**
+     * Get the default phase suites of this compiler. This will take in account any options enabled
+     * at the time of call, returning an appropriately constructed suite. The returned suite is
+     * immutable by default but {@link Suites#copy} can be used to create a customized version.
+     */
+    Suites getDefaultSuites();
+
+    /**
+     * Get the default phase suite for creating new graphs.
+     */
+    PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite();
+
+    /**
+     * Get the default LIR phase suites of this compiler. This will take in account any options
+     * enabled at the time of call, returning an appropriately constructed suite. The returned suite
+     * is immutable by default but {@link LIRSuites#copy} can be used to create a customized
+     * version.
+     */
+    LIRSuites getDefaultLIRSuites();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/TargetProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/TargetProvider.java
new file mode 100644
index 0000000..daf3655
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/TargetProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.tiers;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public interface TargetProvider {
+
+    TargetDescription getTarget();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/BlockWorkList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/BlockWorkList.java
new file mode 100644
index 0000000..a78c4e5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/BlockWorkList.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.util;
+
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+
+/**
+ * This class implements a worklist for dealing with blocks. The worklist can operate either as a
+ * stack (i.e. first-in / last-out), or as a sorted list, where blocks can be sorted by a supplied
+ * number. The latter usage lends itself naturally to iterative dataflow analysis problems.
+ */
+public class BlockWorkList {
+
+    AbstractMergeNode[] workList;
+    int[] workListNumbers;
+    int workListIndex;
+
+    /**
+     * Adds a block to this list in an unsorted fashion, like a stack.
+     *
+     * @param block the block to add
+     */
+    public void add(AbstractMergeNode block) {
+        if (workList == null) {
+            // worklist not allocated yet
+            allocate();
+        } else if (workListIndex == workList.length) {
+            // need to grow the worklist
+            grow();
+        }
+        // put the block at the end of the array
+        workList[workListIndex++] = block;
+    }
+
+    /**
+     * Adds a block to this list, sorted by the supplied number. The block with the lowest number is
+     * returned upon subsequent removes.
+     *
+     * @param block the block to add
+     * @param number the number used to sort the block
+     */
+    public void addSorted(AbstractMergeNode block, int number) {
+        if (workList == null) {
+            // worklist not allocated yet
+            allocate();
+        } else if (workListIndex == workList.length) {
+            // need to grow the worklist
+            grow();
+        }
+        // put the block at the end of the array
+        workList[workListIndex] = block;
+        workListNumbers[workListIndex] = number;
+        workListIndex++;
+        int i = workListIndex - 2;
+        // push block towards the beginning of the array
+        for (; i >= 0; i--) {
+            int n = workListNumbers[i];
+            if (n >= number) {
+                break; // already in the right position
+            }
+            workList[i + 1] = workList[i]; // bubble b down by one
+            workList[i] = block;           // and overwrite its place with block
+            workListNumbers[i + 1] = n;    // bubble n down by one
+            workListNumbers[i] = number;   // and overwrite its place with number
+        }
+    }
+
+    /**
+     * Removes the next block from this work list. If the blocks have been added in a sorted order,
+     * then the block with the lowest number is returned. Otherwise, the last block added is
+     * returned.
+     *
+     * @return the next block in the list
+     */
+    public AbstractMergeNode removeFromWorkList() {
+        if (workListIndex != 0) {
+            return workList[--workListIndex];
+        }
+        return null;
+    }
+
+    /**
+     * Checks whether the list is empty.
+     *
+     * @return {@code true} if this list is empty
+     */
+    public boolean isEmpty() {
+        return workListIndex == 0;
+    }
+
+    private void allocate() {
+        workList = new AbstractMergeNode[5];
+        workListNumbers = new int[5];
+    }
+
+    private void grow() {
+        int prevLength = workList.length;
+        AbstractMergeNode[] nworkList = new AbstractMergeNode[prevLength * 3];
+        System.arraycopy(workList, 0, nworkList, 0, prevLength);
+        workList = nworkList;
+
+        int[] nworkListNumbers = new int[prevLength * 3];
+        System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength);
+        workListNumbers = nworkListNumbers;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java
new file mode 100644
index 0000000..9191580
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.GraalGraphError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.VirtualState.NodeClosure;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import org.graalvm.compiler.phases.graph.StatelessPostOrderNodeIterator;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+
+public final class GraphOrder {
+
+    private GraphOrder() {
+    }
+
+    /**
+     * Quick (and imprecise) assertion that there are no (invalid) cycles in the given graph. First,
+     * an ordered list of all nodes in the graph (a total ordering) is created. A second run over
+     * this list checks whether inputs are scheduled before their usages.
+     *
+     * @param graph the graph to be checked.
+     * @throws AssertionError if a cycle was detected.
+     */
+    public static boolean assertNonCyclicGraph(StructuredGraph graph) {
+        List<Node> order = createOrder(graph);
+        NodeBitMap visited = graph.createNodeBitMap();
+        visited.clearAll();
+        for (Node node : order) {
+            if (node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode) {
+                assert visited.isMarked(((PhiNode) node).valueAt(0));
+                // nothing to do
+            } else {
+                for (Node input : node.inputs()) {
+                    if (!visited.isMarked(input)) {
+                        if (input instanceof FrameState) {
+                            // nothing to do - frame states are known, allowed cycles
+                        } else {
+                            assert false : "unexpected cycle detected at input " + node + " -> " + input;
+                        }
+                    }
+                }
+            }
+            visited.mark(node);
+        }
+        return true;
+    }
+
+    private static List<Node> createOrder(StructuredGraph graph) {
+        final ArrayList<Node> nodes = new ArrayList<>();
+        final NodeBitMap visited = graph.createNodeBitMap();
+
+        new StatelessPostOrderNodeIterator(graph.start()) {
+            @Override
+            protected void node(FixedNode node) {
+                visitForward(nodes, visited, node, false);
+            }
+        }.apply();
+        return nodes;
+    }
+
+    private static void visitForward(ArrayList<Node> nodes, NodeBitMap visited, Node node, boolean floatingOnly) {
+        try {
+            assert node == null || node.isAlive() : node + " not alive";
+            if (node != null && !visited.isMarked(node)) {
+                if (floatingOnly && node instanceof FixedNode) {
+                    throw new GraalError("unexpected reference to fixed node: %s (this indicates an unexpected cycle)", node);
+                }
+                visited.mark(node);
+                FrameState stateAfter = null;
+                if (node instanceof StateSplit) {
+                    stateAfter = ((StateSplit) node).stateAfter();
+                }
+                for (Node input : node.inputs()) {
+                    if (input != stateAfter) {
+                        visitForward(nodes, visited, input, true);
+                    }
+                }
+                if (node instanceof EndNode) {
+                    EndNode end = (EndNode) node;
+                    for (PhiNode phi : end.merge().phis()) {
+                        visitForward(nodes, visited, phi.valueAt(end), true);
+                    }
+                }
+                nodes.add(node);
+                if (node instanceof AbstractMergeNode) {
+                    for (PhiNode phi : ((AbstractMergeNode) node).phis()) {
+                        visited.mark(phi);
+                        nodes.add(phi);
+                    }
+                }
+                if (stateAfter != null) {
+                    visitForward(nodes, visited, stateAfter, true);
+                }
+            }
+        } catch (GraalError e) {
+            throw GraalGraphError.transformAndAddContext(e, node);
+        }
+    }
+
+    /**
+     * This method schedules the graph and makes sure that, for every node, all inputs are available
+     * at the position where it is scheduled. This is a very expensive assertion.
+     */
+    public static boolean assertSchedulableGraph(final StructuredGraph graph) {
+        assert graph.getGuardsStage() != GuardsStage.AFTER_FSA : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid.";
+        try {
+            final SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS);
+            final Map<LoopBeginNode, NodeBitMap> loopEntryStates = Node.newIdentityMap();
+            schedulePhase.apply(graph, false);
+            final ScheduleResult schedule = graph.getLastSchedule();
+
+            BlockIteratorClosure<NodeBitMap> closure = new BlockIteratorClosure<NodeBitMap>() {
+
+                @Override
+                protected List<NodeBitMap> processLoop(Loop<Block> loop, NodeBitMap initialState) {
+                    return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+                }
+
+                @Override
+                protected NodeBitMap processBlock(final Block block, final NodeBitMap currentState) {
+                    final List<Node> list = graph.getLastSchedule().getBlockToNodesMap().get(block);
+
+                    /*
+                     * A stateAfter is not valid directly after its associated state split, but
+                     * right before the next fixed node. Therefore a pending stateAfter is kept that
+                     * will be checked at the correct position.
+                     */
+                    FrameState pendingStateAfter = null;
+                    for (final Node node : list) {
+                        if (node instanceof ValueNode) {
+                            FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null;
+                            if (node instanceof FullInfopointNode) {
+                                stateAfter = ((FullInfopointNode) node).getState();
+                            }
+
+                            if (pendingStateAfter != null && node instanceof FixedNode) {
+                                pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
+                                    @Override
+                                    public void apply(Node usage, Node nonVirtualNode) {
+                                        assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
+                                                        " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
+                                    }
+                                });
+                                pendingStateAfter = null;
+                            }
+
+                            if (node instanceof AbstractMergeNode) {
+                                // phis aren't scheduled, so they need to be added explicitly
+                                currentState.markAll(((AbstractMergeNode) node).phis());
+                                if (node instanceof LoopBeginNode) {
+                                    // remember the state at the loop entry, it's restored at exits
+                                    loopEntryStates.put((LoopBeginNode) node, currentState.copy());
+                                }
+                            } else if (node instanceof ProxyNode) {
+                                assert false : "proxy nodes should not be in the schedule";
+                            } else if (node instanceof LoopExitNode) {
+                                if (graph.hasValueProxies()) {
+                                    for (ProxyNode proxy : ((LoopExitNode) node).proxies()) {
+                                        for (Node input : proxy.inputs()) {
+                                            if (input != proxy.proxyPoint()) {
+                                                assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list;
+                                            }
+                                        }
+                                    }
+
+                                    // loop contents are only accessible via proxies at the exit
+                                    currentState.clearAll();
+                                    currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin()));
+                                }
+                                // Loop proxies aren't scheduled, so they need to be added
+                                // explicitly
+                                currentState.markAll(((LoopExitNode) node).proxies());
+                            } else {
+                                for (Node input : node.inputs()) {
+                                    if (input != stateAfter) {
+                                        if (input instanceof FrameState) {
+                                            ((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure<Node>() {
+                                                @Override
+                                                public void apply(Node usage, Node nonVirtual) {
+                                                    assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
+                                                }
+                                            });
+                                        } else {
+                                            assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node +
+                                                            " in block " + block + "\n" + list;
+                                        }
+                                    }
+                                }
+                            }
+                            if (node instanceof AbstractEndNode) {
+                                AbstractMergeNode merge = ((AbstractEndNode) node).merge();
+                                for (PhiNode phi : merge.phis()) {
+                                    ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
+                                    assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node +
+                                                    " in block " + block;
+                                }
+                            }
+                            if (stateAfter != null) {
+                                assert pendingStateAfter == null;
+                                pendingStateAfter = stateAfter;
+                            }
+                            currentState.mark(node);
+                        }
+                    }
+                    if (pendingStateAfter != null) {
+                        pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
+                            @Override
+                            public void apply(Node usage, Node nonVirtualNode) {
+                                assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
+                                                " not available at virtualstate " + usage + " at end of block " + block + " \n" + list;
+                            }
+                        });
+                    }
+                    return currentState;
+                }
+
+                @Override
+                protected NodeBitMap merge(Block merge, List<NodeBitMap> states) {
+                    NodeBitMap result = states.get(0);
+                    for (int i = 1; i < states.size(); i++) {
+                        result.intersect(states.get(i));
+                    }
+                    return result;
+                }
+
+                @Override
+                protected NodeBitMap getInitialState() {
+                    NodeBitMap ret = graph.createNodeBitMap();
+                    ret.markAll(graph.getNodes().filter(ConstantNode.class));
+                    return ret;
+                }
+
+                @Override
+                protected NodeBitMap cloneState(NodeBitMap oldState) {
+                    return oldState.copy();
+                }
+            };
+
+            ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+
+        } catch (Throwable t) {
+            Debug.handle(t);
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/MethodDebugValueName.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/MethodDebugValueName.java
new file mode 100644
index 0000000..deb08d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/MethodDebugValueName.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.util;
+
+import org.graalvm.compiler.phases.LazyName;
+
+import jdk.vm.ci.meta.JavaMethod;
+
+/**
+ * Lazily computed debug value name composed of a prefix and a {@linkplain JavaMethod#getName()
+ * method name}.
+ */
+public class MethodDebugValueName extends LazyName {
+    final String prefix;
+    final JavaMethod method;
+
+    public MethodDebugValueName(String prefix, JavaMethod method) {
+        this.prefix = prefix;
+        this.method = method;
+    }
+
+    @Override
+    public String createString() {
+        return prefix + "[" + method.getName() + "]";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java
new file mode 100644
index 0000000..27244d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.util;
+
+import org.graalvm.compiler.core.common.spi.CodeGenProviders;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeCostProvider;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * A set of providers, some of which may not be present (i.e., null).
+ */
+public class Providers implements CodeGenProviders {
+
+    private final MetaAccessProvider metaAccess;
+    private final CodeCacheProvider codeCache;
+    private final LoweringProvider lowerer;
+    private final ConstantReflectionProvider constantReflection;
+    private final ConstantFieldProvider constantFieldProvider;
+    private final ForeignCallsProvider foreignCalls;
+    private final Replacements replacements;
+    private final StampProvider stampProvider;
+    private final NodeCostProvider nodeCostProvider;
+
+    public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                    ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider, NodeCostProvider nodeCostProvider) {
+        this.metaAccess = metaAccess;
+        this.codeCache = codeCache;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.foreignCalls = foreignCalls;
+        this.lowerer = lowerer;
+        this.replacements = replacements;
+        this.stampProvider = stampProvider;
+        this.nodeCostProvider = nodeCostProvider;
+    }
+
+    public Providers(Providers copyFrom) {
+        this(copyFrom.getMetaAccess(), copyFrom.getCodeCache(), copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), copyFrom.getForeignCalls(), copyFrom.getLowerer(),
+                        copyFrom.getReplacements(), copyFrom.getStampProvider(), copyFrom.getNodeCostProvider());
+    }
+
+    public Providers(PhaseContext copyFrom) {
+        this(copyFrom.getMetaAccess(), null, copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), null, copyFrom.getLowerer(), copyFrom.getReplacements(),
+                        copyFrom.getStampProvider(), copyFrom.getNodeCostProvider());
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @Override
+    public CodeCacheProvider getCodeCache() {
+        return codeCache;
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return foreignCalls;
+    }
+
+    public LoweringProvider getLowerer() {
+        return lowerer;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    public Replacements getReplacements() {
+        return replacements;
+    }
+
+    public StampProvider getStampProvider() {
+        return stampProvider;
+    }
+
+    public NodeCostProvider getNodeCostProvider() {
+        return nodeCostProvider;
+    }
+
+    public Providers copyWith(MetaAccessProvider substitution) {
+        return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(CodeCacheProvider substitution) {
+        return new Providers(metaAccess, substitution, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(ConstantReflectionProvider substitution) {
+        return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(ConstantFieldProvider substitution) {
+        return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(ForeignCallsProvider substitution) {
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, substitution, lowerer, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(LoweringProvider substitution) {
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, substitution, replacements, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(Replacements substitution) {
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider, nodeCostProvider);
+    }
+
+    public Providers copyWith(StampProvider substitution) {
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, substitution, nodeCostProvider);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java
new file mode 100644
index 0000000..787022b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.common.RetryableBailoutException;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class VerifyBailoutUsage extends VerifyPhase<PhaseContext> {
+
+    private static final String[] AllowedPackagePrefixes;
+
+    private static String getPackageName(Class<?> c) {
+        String classNameWithPackage = c.getName();
+        String simpleName = c.getSimpleName();
+        return classNameWithPackage.substring(0, classNameWithPackage.length() - simpleName.length() - 1);
+    }
+
+    static {
+        try {
+            AllowedPackagePrefixes = new String[]{getPackageName(PermanentBailoutException.class), "jdk.vm.ci"};
+        } catch (Throwable t) {
+            throw new GraalError(t);
+        }
+    }
+
+    private static boolean matchesPrefix(String packageName) {
+        for (String allowedPackagePrefix : AllowedPackagePrefixes) {
+            if (packageName.startsWith(allowedPackagePrefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        final ResolvedJavaType bailoutType = context.getMetaAccess().lookupJavaType(BailoutException.class);
+        ResolvedJavaMethod caller = graph.method();
+        String holderQualified = caller.format("%H");
+        String holderUnqualified = caller.format("%h");
+        String packageName = holderQualified.substring(0, holderQualified.length() - holderUnqualified.length() - 1);
+        if (!matchesPrefix(packageName)) {
+            for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+                ResolvedJavaMethod callee = t.targetMethod();
+                if (callee.getDeclaringClass().equals(bailoutType)) {
+                    // we only allow the getter
+                    if (!callee.getName().equals("isPermanent")) {
+                        throw new VerificationError("Call to %s at callsite %s is prohibited. Consider using %s for permanent bailouts or %s for retryables.", callee.format("%H.%n(%p)"),
+                                        caller.format("%H.%n(%p)"), PermanentBailoutException.class.getName(),
+                                        RetryableBailoutException.class.getName());
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java
new file mode 100644
index 0000000..474d0cf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+
+import java.lang.annotation.Annotation;
+
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Verifies a method is annotated with CallerSensitive iff it calls Reflection#getCallerClass().
+ */
+public class VerifyCallerSensitiveMethods extends VerifyPhase<PhaseContext> {
+
+    Class<? extends Annotation> callerSensitiveClass;
+    Class<?> reflectionClass;
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    public VerifyCallerSensitiveMethods() {
+        try {
+            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+            if (Java8OrEarlier) {
+                reflectionClass = classLoader.loadClass("sun.reflect.Reflection");
+                callerSensitiveClass = (Class<? extends Annotation>) classLoader.loadClass("sun.reflect.ConstantPool");
+            } else {
+                reflectionClass = classLoader.loadClass("jdk.internal.reflect.Reflection");
+                callerSensitiveClass = (Class<? extends Annotation>) classLoader.loadClass("jdk.internal.reflect.ConstantPool");
+            }
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        Invoke invoke = callsReflectionGetCallerClass(graph, context);
+        Annotation annotation = graph.method().getAnnotation(callerSensitiveClass);
+        if (invoke != null) {
+            if (annotation == null) {
+                StackTraceElement e = graph.method().asStackTraceElement(invoke.bci());
+                throw new VerificationError(String.format("%s: method that calls Reflection.getCallerClass() must be annotated with @CallerSensitive", e));
+            }
+
+        } else if (annotation != null) {
+            throw new VerificationError(String.format("%s: method annotated with @CallerSensitive does not call Reflection.getCallerClass()", graph.method().format("%H.%n(%p)")));
+        }
+        return true;
+    }
+
+    private Invoke callsReflectionGetCallerClass(StructuredGraph graph, PhaseContext context) {
+        ResolvedJavaType reflectionType = context.getMetaAccess().lookupJavaType(reflectionClass);
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            if (callee.getDeclaringClass().equals(reflectionType)) {
+                if (callee.getName().equals("getCallerClass")) {
+                    return t.invoke();
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java
new file mode 100644
index 0000000..03aac26
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugMethodMetrics;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ *
+ * Verifies that call sites calling one of the methods in {@link Debug} use them correctly. Correct
+ * usage of the methods in {@link Debug} requires call sites to not eagerly evaluate their
+ * arguments. Additionally this phase verifies that no argument is the result of a call to
+ * {@link StringBuilder#toString()} or {@link StringBuffer#toString()}. Ideally the parameters at
+ * call sites of {@link Debug} are eliminated, and do not produce additional allocations, if
+ * {@link Debug#isDumpEnabled(int)} (or {@link Debug#isLogEnabled(int)}, ...) is {@code false}.
+ *
+ * Methods in {@link Debug} checked by this phase are various different versions of
+ * {@link Debug#log(String)} , {@link Debug#dump(int, Object, String)},
+ * {@link Debug#logAndIndent(String)} and {@link Debug#verify(Object, String)}.
+ */
+public class VerifyDebugUsage extends VerifyPhase<PhaseContext> {
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        ResolvedJavaType debugType = context.getMetaAccess().lookupJavaType(Debug.class);
+        ResolvedJavaType nodeType = context.getMetaAccess().lookupJavaType(Node.class);
+        ResolvedJavaType stringType = context.getMetaAccess().lookupJavaType(String.class);
+        ResolvedJavaType debugMethodMetricsType = context.getMetaAccess().lookupJavaType(DebugMethodMetrics.class);
+        ResolvedJavaType graalErrorType = context.getMetaAccess().lookupJavaType(GraalError.class);
+
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            String calleeName = callee.getName();
+            if (callee.getDeclaringClass().equals(debugType)) {
+                if (calleeName.equals("log") || calleeName.equals("logAndIndent") || calleeName.equals("verify") || calleeName.equals("dump")) {
+                    verifyParameters(t, graph, t.arguments(), stringType, calleeName.equals("dump") ? 2 : 1);
+                }
+            }
+            if (callee.getDeclaringClass().isAssignableFrom(nodeType)) {
+                if (calleeName.equals("assertTrue") || calleeName.equals("assertFalse")) {
+                    verifyParameters(t, graph, t.arguments(), stringType, 1);
+                }
+            }
+            if (callee.getDeclaringClass().equals(debugMethodMetricsType)) {
+                if (calleeName.equals("addToMetric") || calleeName.equals("getCurrentMetricValue") || calleeName.equals("incrementMetric")) {
+                    verifyParameters(t, graph, t.arguments(), stringType, 1);
+                }
+            }
+            if (callee.getDeclaringClass().isAssignableFrom(graalErrorType) && !graph.method().getDeclaringClass().isAssignableFrom(graalErrorType)) {
+                if (calleeName.equals("guarantee")) {
+                    verifyParameters(t, graph, t.arguments(), stringType, 0);
+                }
+                if (calleeName.equals("<init>") && callee.getSignature().getParameterCount(false) == 2) {
+                    verifyParameters(t, graph, t.arguments(), stringType, 1);
+                }
+            }
+        }
+        return true;
+    }
+
+    private static void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList<? extends Node> args, ResolvedJavaType stringType, int startArgIdx) {
+        if (callTarget.targetMethod().isVarArgs() && args.get(args.count() - 1) instanceof NewArrayNode) {
+            // unpack the arguments to the var args
+            List<Node> unpacked = new ArrayList<>(args.snapshot());
+            NewArrayNode varArgParameter = (NewArrayNode) unpacked.remove(unpacked.size() - 1);
+            int firstVarArg = unpacked.size();
+            for (Node usage : varArgParameter.usages()) {
+                if (usage instanceof StoreIndexedNode) {
+                    StoreIndexedNode si = (StoreIndexedNode) usage;
+                    unpacked.add(si.value());
+                }
+            }
+            verifyParameters(callerGraph, callTarget.targetMethod(), unpacked, stringType, startArgIdx, firstVarArg);
+        } else {
+            verifyParameters(callerGraph, callTarget.targetMethod(), args, stringType, startArgIdx, -1);
+        }
+    }
+
+    private static void verifyParameters(StructuredGraph callerGraph, ResolvedJavaMethod verifiedCallee, List<? extends Node> args, ResolvedJavaType stringType, int startArgIdx, int varArgsIndex) {
+        int argIdx = startArgIdx;
+        int varArgsElementIndex = 0;
+        boolean reportVarArgs = false;
+        for (int i = 0; i < args.size(); i++) {
+            Node arg = args.get(i);
+            if (arg instanceof Invoke) {
+                reportVarArgs = varArgsIndex >= 0 && argIdx >= varArgsIndex;
+                Invoke invoke = (Invoke) arg;
+                CallTargetNode callTarget = invoke.callTarget();
+                if (callTarget instanceof MethodCallTargetNode) {
+                    ResolvedJavaMethod m = ((MethodCallTargetNode) callTarget).targetMethod();
+                    if (m.getName().equals("toString")) {
+                        int bci = invoke.bci();
+                        int nonVarArgIdx = reportVarArgs ? argIdx - varArgsElementIndex : argIdx;
+                        verifyStringConcat(callerGraph, verifiedCallee, bci, nonVarArgIdx, reportVarArgs ? varArgsElementIndex : -1, m);
+                        verifyToStringCall(callerGraph, verifiedCallee, stringType, m, bci, nonVarArgIdx, reportVarArgs ? varArgsElementIndex : -1);
+                    } else if (m.getName().equals("format")) {
+                        int bci = invoke.bci();
+                        int nonVarArgIdx = reportVarArgs ? argIdx - varArgsElementIndex : argIdx;
+                        verifyFormatCall(callerGraph, verifiedCallee, stringType, m, bci, nonVarArgIdx, reportVarArgs ? varArgsElementIndex : -1);
+
+                    }
+                }
+            }
+            if (varArgsIndex >= 0 && i >= varArgsIndex) {
+                varArgsElementIndex++;
+            }
+            argIdx++;
+        }
+    }
+
+    /**
+     * Checks that a given call is not to {@link StringBuffer#toString()} or
+     * {@link StringBuilder#toString()}.
+     */
+    private static void verifyStringConcat(StructuredGraph callerGraph, ResolvedJavaMethod verifiedCallee, int bci, int argIdx, int varArgsElementIndex, ResolvedJavaMethod callee) {
+        if (callee.getDeclaringClass().getName().equals("Ljava/lang/StringBuilder;") || callee.getDeclaringClass().getName().equals("Ljava/lang/StringBuffer;")) {
+            StackTraceElement e = callerGraph.method().asStackTraceElement(bci);
+            if (varArgsElementIndex >= 0) {
+                throw new VerificationError(
+                                "In %s: element %d of parameter %d of call to %s appears to be a String concatenation expression.%n", e, varArgsElementIndex, argIdx,
+                                verifiedCallee.format("%H.%n(%p)"));
+            } else {
+                throw new VerificationError(
+                                "In %s: parameter %d of call to %s appears to be a String concatenation expression.%n", e, argIdx, verifiedCallee.format("%H.%n(%p)"));
+            }
+        }
+    }
+
+    /**
+     * Checks that a given call is not to {@link Object#toString()}.
+     */
+    private static void verifyToStringCall(StructuredGraph callerGraph, ResolvedJavaMethod verifiedCallee, ResolvedJavaType stringType, ResolvedJavaMethod callee, int bci, int argIdx,
+                    int varArgsElementIndex) {
+        if (callee.getSignature().getParameterCount(false) == 0 && callee.getSignature().getReturnType(callee.getDeclaringClass()).equals(stringType)) {
+            StackTraceElement e = callerGraph.method().asStackTraceElement(bci);
+            if (varArgsElementIndex >= 0) {
+                throw new VerificationError(
+                                "In %s: element %d of parameter %d of call to %s is a call to toString() which is redundant (the callee will do it) and forces unnecessary eager evaluation.",
+                                e, varArgsElementIndex, argIdx, verifiedCallee.format("%H.%n(%p)"));
+            } else {
+                throw new VerificationError("In %s: parameter %d of call to %s is a call to toString() which is redundant (the callee will do it) and forces unnecessary eager evaluation.", e, argIdx,
+                                verifiedCallee.format("%H.%n(%p)"));
+            }
+        }
+    }
+
+    /**
+     * Checks that a given call is not to {@link String#format(String, Object...)} or
+     * {@link String#format(java.util.Locale, String, Object...)}.
+     */
+    private static void verifyFormatCall(StructuredGraph callerGraph, ResolvedJavaMethod verifiedCallee, ResolvedJavaType stringType, ResolvedJavaMethod callee, int bci, int argIdx,
+                    int varArgsElementIndex) {
+        if (callee.getDeclaringClass().equals(stringType) && callee.getSignature().getReturnType(callee.getDeclaringClass()).equals(stringType)) {
+            StackTraceElement e = callerGraph.method().asStackTraceElement(bci);
+            if (varArgsElementIndex >= 0) {
+                throw new VerificationError(
+                                "In %s: element %d of parameter %d of call to %s is a call to String.format() which is redundant (%s does formatting) and forces unnecessary eager evaluation.",
+                                e, varArgsElementIndex, argIdx, verifiedCallee.format("%H.%n(%p)"), verifiedCallee.format("%h.%n"));
+            } else {
+                throw new VerificationError("In %s: parameter %d of call to %s is a call to String.format() which is redundant (%s does formatting) and forces unnecessary eager evaluation.", e,
+                                argIdx,
+                                verifiedCallee.format("%H.%n(%p)"), verifiedCallee.format("%h.%n"));
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUpdateUsages.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUpdateUsages.java
new file mode 100644
index 0000000..ac68f5a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUpdateUsages.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import java.util.List;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.Input;
+import org.graalvm.compiler.graph.Node.OptionalInput;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Try to ensure that methods which update {@link Input} or {@link OptionalInput} fields also
+ * include a call to {@link Node#updateUsages} or {@link Node#updateUsagesInterface}.
+ */
+public class VerifyUpdateUsages extends VerifyPhase<PhaseContext> {
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    public VerifyUpdateUsages() {
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        if (graph.method().isConstructor()) {
+            return true;
+        }
+        /*
+         * There are only two acceptable patterns for methods which update Node inputs, either a
+         * single StoreField node and invoke of updateUsages or updateUsagesInterface, or 2
+         * StoreFields that come from LoadFields on the same object. Other patterns can be added as
+         * needed but it would be best to keep things simple so that verification can be simple.
+         */
+        List<StoreFieldNode> stores = graph.getNodes().filter(StoreFieldNode.class).snapshot();
+        ResolvedJavaType declaringClass = graph.method().getDeclaringClass();
+        ResolvedJavaType nodeInputList = context.getMetaAccess().lookupJavaType(NodeInputList.class);
+        StoreFieldNode storeField1 = null;
+        StoreFieldNode storeField2 = null;
+        for (StoreFieldNode store : stores) {
+            if (isNodeInput(store.field(), declaringClass, nodeInputList)) {
+                if (storeField1 == null) {
+                    storeField1 = store;
+                } else if (storeField2 == null) {
+                    storeField2 = store;
+                } else {
+                    return false;
+                }
+            }
+        }
+        if (storeField1 == null) {
+            return true;
+        }
+        if (storeField2 == null) {
+            // Single input field update so just check for updateUsages or updateUsagesInterface
+            // call
+            ResolvedJavaType node = context.getMetaAccess().lookupJavaType(Node.class);
+            for (MethodCallTargetNode call : graph.getNodes().filter(MethodCallTargetNode.class)) {
+                ResolvedJavaMethod callee = call.targetMethod();
+                if (callee.getDeclaringClass().equals(node) && (callee.getName().equals("updateUsages") || callee.getName().equals("updateUsagesInterface"))) {
+                    return true;
+                }
+            }
+        } else {
+            if (storeField1.value() instanceof LoadFieldNode && storeField2.value() instanceof LoadFieldNode) {
+                LoadFieldNode load1 = (LoadFieldNode) storeField1.value();
+                LoadFieldNode load2 = (LoadFieldNode) storeField2.value();
+                // Check for swapping values within the same object
+                if (load1.object() == storeField1.object() && load2.object() == storeField2.object() && storeField1.object() == storeField2.object() &&
+                                load1.field().equals(storeField2.field()) && load2.field().equals(storeField1.field())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    boolean isNodeInput(ResolvedJavaField field, ResolvedJavaType declaringClass, ResolvedJavaType nodeInputList) {
+        return declaringClass.isAssignableFrom(field.getDeclaringClass()) && (field.getAnnotation(Input.class) != null || field.getAnnotation(OptionalInput.class) != null) &&
+                        !field.getType().equals(nodeInputList);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUsageWithEquals.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUsageWithEquals.java
new file mode 100644
index 0000000..f89cbf5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyUsageWithEquals.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * For certain types, object identity should not be used for object equality check. This phase
+ * checks the correct usage of the given type. Equality checks with == or != (except null checks)
+ * results in an {@link AssertionError}.
+ */
+public class VerifyUsageWithEquals extends VerifyPhase<PhaseContext> {
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    /**
+     * The type of values that must not use identity for testing object equality.
+     */
+    private final Class<?> restrictedClass;
+
+    public VerifyUsageWithEquals(Class<?> restrictedClass) {
+        this.restrictedClass = restrictedClass;
+        assert !restrictedClass.isInterface() || isTrustedInterface(restrictedClass);
+    }
+
+    private static final Class<?>[] trustedInterfaceTypes = {JavaType.class, JavaField.class, JavaMethod.class};
+
+    private static boolean isTrustedInterface(Class<?> cls) {
+        for (Class<?> trusted : trustedInterfaceTypes) {
+            if (trusted.isAssignableFrom(cls)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines whether the type of {@code node} is assignable to the {@link #restrictedClass}.
+     */
+    private boolean isAssignableToRestrictedType(ValueNode node, MetaAccessProvider metaAccess) {
+        if (node.stamp() instanceof ObjectStamp) {
+            ResolvedJavaType restrictedType = metaAccess.lookupJavaType(restrictedClass);
+            ResolvedJavaType nodeType = StampTool.typeOrNull(node);
+
+            if (nodeType != null && restrictedType.isAssignableFrom(nodeType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isNullConstant(ValueNode node) {
+        return node.isConstant() && node.isNullConstant();
+    }
+
+    private static boolean isEqualsMethod(ResolvedJavaMethod method) {
+        if (method.getName().equals("equals")) {
+            Signature sig = method.getSignature();
+            if (sig.getReturnKind() == JavaKind.Boolean) {
+                if (sig.getParameterCount(false) == 1) {
+                    ResolvedJavaType ptype = (ResolvedJavaType) sig.getParameterType(0, method.getDeclaringClass());
+                    if (ptype.isJavaLangObject()) {
+                        return true;
+                    }
+
+                }
+            }
+        }
+        return false;
+    }
+
+    private static boolean isThisParameter(ValueNode node) {
+        return node instanceof ParameterNode && ((ParameterNode) node).index() == 0;
+    }
+
+    /**
+     * Checks whether the type of {@code x} is assignable to the restricted type and that {@code y}
+     * is not a null constant.
+     */
+    private boolean isIllegalUsage(ResolvedJavaMethod method, ValueNode x, ValueNode y, MetaAccessProvider metaAccess) {
+        if (isAssignableToRestrictedType(x, metaAccess) && !isNullConstant(y)) {
+            if (isEqualsMethod(method) && isThisParameter(x) || isThisParameter(y)) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
+            // bail out if we compare an object of type klass with == or != (except null checks)
+            ResolvedJavaMethod method = graph.method();
+            ResolvedJavaType restrictedType = context.getMetaAccess().lookupJavaType(restrictedClass);
+
+            if (method.getDeclaringClass().equals(restrictedType)) {
+                // Allow violation in methods of the restricted type itself.
+            } else if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) {
+                throw new VerificationError("Verification of " + restrictedClass.getName() + " usage failed: Comparing " + cn.getX() + " and " + cn.getY() + " in " + method +
+                                " must use .equals() for object equality, not '==' or '!='");
+            }
+        }
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyVirtualizableUsage.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyVirtualizableUsage.java
new file mode 100644
index 0000000..ace1303
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyVirtualizableUsage.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.verify;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ *
+ * Verifies that node types implementing the {@link Virtualizable} interface use it correctly.
+ * Implementors of {@link Virtualizable#virtualize(org.graalvm.compiler.nodes.spi.VirtualizerTool)}
+ * must not apply effects on their {@link Graph graph} that cannot be easily undone.
+ */
+public class VerifyVirtualizableUsage extends VerifyPhase<PhaseContext> {
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        final ResolvedJavaType graphType = context.getMetaAccess().lookupJavaType(Graph.class);
+        final ResolvedJavaType virtualizableType = context.getMetaAccess().lookupJavaType(Virtualizable.class);
+        final ResolvedJavaType constantNodeType = context.getMetaAccess().lookupJavaType(ConstantNode.class);
+        if (virtualizableType.isAssignableFrom(graph.method().getDeclaringClass()) && graph.method().getName().equals("virtualize")) {
+            for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+                int bci = t.invoke().bci();
+                ResolvedJavaMethod callee = t.targetMethod();
+                String calleeName = callee.getName();
+                if (callee.getDeclaringClass().equals(graphType)) {
+                    if (calleeName.equals("add") || calleeName.equals("addWithoutUnique") || calleeName.equals("addOrUnique") || calleeName.equals("addWithoutUniqueWithInputs") ||
+                                    calleeName.equals("addOrUniqueWithInputs")) {
+                        verifyVirtualizableEffectArguments(constantNodeType, graph.method(), callee, bci, t.arguments(), 1);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private static void verifyVirtualizableEffectArguments(ResolvedJavaType constantNodeType, ResolvedJavaMethod caller, ResolvedJavaMethod callee, int bciCaller,
+                    NodeInputList<? extends Node> arguments, int startIdx) {
+        /*
+         * Virtualizable.virtualize should never apply effects on the graph during the execution of
+         * the call as the handling of loops during pea might be speculative and does not hold. We
+         * should only allow nodes changing the graph that do no harm like constants.
+         */
+        int i = 0;
+        for (Node arg : arguments) {
+            if (i >= startIdx) {
+                Stamp argStamp = ((ValueNode) arg).stamp();
+                if (argStamp instanceof ObjectStamp) {
+                    ObjectStamp objectStamp = (ObjectStamp) argStamp;
+                    ResolvedJavaType argStampType = objectStamp.type();
+                    if (!(argStampType.equals(constantNodeType))) {
+                        StackTraceElement e = caller.asStackTraceElement(bciCaller);
+                        throw new VerificationError("%s:Parameter %d in call to %s (which has effects on the graph) is not a " +
+                                        "constant and thus not safe to apply during speculative virtualization.", e, i, callee.format("%H.%n(%p)"));
+                    }
+                }
+            }
+            i++;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BasicIdealGraphPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BasicIdealGraphPrinter.java
new file mode 100644
index 0000000..1e853df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BasicIdealGraphPrinter.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.io.BufferedOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific
+ * data structures.
+ */
+class BasicIdealGraphPrinter {
+
+    /**
+     * Edge between two nodes.
+     */
+    protected static class Edge {
+
+        final String from;
+        final int fromIndex;
+        final String to;
+        final int toIndex;
+        final String label;
+
+        public Edge(String from, int fromIndex, String to, int toIndex, String label) {
+            assert (from != null && to != null);
+            this.from = from;
+            this.fromIndex = fromIndex;
+            this.to = to;
+            this.toIndex = toIndex;
+            this.label = label;
+        }
+
+        @Override
+        public int hashCode() {
+            int h = from.hashCode() ^ to.hashCode();
+            h = 3 * h + fromIndex;
+            h = 5 * h + toIndex;
+            if (label != null) {
+                h ^= label.hashCode();
+            }
+            return h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof Edge) {
+                Edge other = (Edge) obj;
+                return from.equals(other.from) && fromIndex == other.fromIndex && to.equals(other.to) && toIndex == other.toIndex &&
+                                (label == other.label || (label != null && label.equals(other.label)));
+            }
+            return false;
+        }
+    }
+
+    private final PrintStream stream;
+
+    /**
+     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     */
+    protected BasicIdealGraphPrinter(OutputStream stream) {
+        try {
+            OutputStream buffered;
+            if (stream instanceof BufferedOutputStream) {
+                buffered = stream;
+            } else {
+                buffered = new BufferedOutputStream(stream, 256 * 1024);
+            }
+            this.stream = new PrintStream(buffered, false, Charset.defaultCharset().name());
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Flushes any buffered output.
+     */
+    protected void flush() {
+        stream.flush();
+    }
+
+    /**
+     * Starts a new graph document.
+     */
+    protected void begin() {
+        stream.println("<graphDocument>");
+    }
+
+    protected void beginGroup() {
+        stream.println("<group>");
+    }
+
+    protected void beginMethod(String name, String shortName, int bci) {
+        stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci);
+    }
+
+    protected void beginBytecodes() {
+        stream.println("  <bytecodes>\n<![CDATA[");
+    }
+
+    protected void printBytecode(int bci, String mnemonic, int[] extra) {
+        stream.print(bci);
+        stream.print(' ');
+        stream.print(mnemonic);
+        if (extra != null) {
+            for (int b : extra) {
+                stream.print(' ');
+                stream.print(b);
+            }
+        }
+        stream.println();
+    }
+
+    protected void endBytecodes() {
+        stream.println("  ]]></bytecodes>");
+    }
+
+    protected void printBytecodes(String disassembly) {
+        beginBytecodes();
+        stream.println(disassembly);
+        endBytecodes();
+    }
+
+    protected void endMethod() {
+        stream.println(" </method>");
+    }
+
+    protected void beginGraph(String title) {
+        stream.printf(" <graph name='%s'>%n", escape(title));
+    }
+
+    protected void beginProperties() {
+        stream.print("<properties>");
+    }
+
+    protected void printProperty(String name, String value) {
+        stream.printf("<p name='%s'>%s</p>", escape(name), escape(value));
+    }
+
+    protected void endProperties() {
+        stream.print("</properties>");
+    }
+
+    protected void printProperties(Map<String, String> properties) {
+        beginProperties();
+        for (Entry<String, String> entry : properties.entrySet()) {
+            printProperty(entry.getKey(), entry.getValue());
+        }
+        endProperties();
+    }
+
+    protected void beginNodes() {
+        stream.println("  <nodes>");
+    }
+
+    protected void beginNode(String id) {
+        stream.printf("   <node id='%s'>", escape(id));
+    }
+
+    protected void endNode() {
+        stream.println("   </node>");
+    }
+
+    protected void printNode(String id, Map<String, String> properties) {
+        beginNode(id);
+        if (properties != null) {
+            printProperties(properties);
+        }
+        endNode();
+    }
+
+    protected void endNodes() {
+        stream.println("  </nodes>");
+    }
+
+    protected void beginEdges() {
+        stream.println("  <edges>");
+    }
+
+    protected void printEdge(Edge edge) {
+        stream.printf("   <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label));
+    }
+
+    protected void endEdges() {
+        stream.println("  </edges>");
+    }
+
+    protected void beginControlFlow() {
+        stream.println("  <controlFlow>");
+    }
+
+    protected void beginBlock(String name) {
+        stream.printf("   <block name='%s'>%n", escape(name));
+    }
+
+    protected void beginSuccessors() {
+        stream.println("    <successors>");
+    }
+
+    protected void printSuccessor(String name) {
+        stream.printf("     <successor name='%s'/>%n", escape(name));
+    }
+
+    protected void endSuccessors() {
+        stream.println("    </successors>");
+    }
+
+    protected void beginBlockNodes() {
+        stream.println("    <nodes>");
+    }
+
+    protected void printBlockNode(String nodeId) {
+        stream.printf("     <node id='%s'/>%n", escape(nodeId));
+    }
+
+    protected void endBlockNodes() {
+        stream.println("    </nodes>");
+    }
+
+    protected void endBlock() {
+        stream.println("   </block>");
+    }
+
+    protected void endControlFlow() {
+        stream.println("  </controlFlow>");
+    }
+
+    protected void endGraph() {
+        stream.println(" </graph>");
+    }
+
+    /**
+     * Ends the current group.
+     */
+    public void endGroup() {
+        stream.println("</group>");
+    }
+
+    /**
+     * Finishes the graph document and flushes the output stream.
+     */
+    protected void end() {
+        stream.println("</graphDocument>");
+        flush();
+    }
+
+    public void close() {
+        end();
+        stream.close();
+    }
+
+    public boolean isValid() {
+        return !stream.checkError();
+    }
+
+    private static String escape(String s) {
+        StringBuilder str = null;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '&':
+                case '<':
+                case '>':
+                case '"':
+                case '\'':
+                    if (str == null) {
+                        str = new StringBuilder();
+                        str.append(s, 0, i);
+                    }
+                    switch (c) {
+                        case '&':
+                            str.append("&amp;");
+                            break;
+                        case '<':
+                            str.append("&lt;");
+                            break;
+                        case '>':
+                            str.append("&gt;");
+                            break;
+                        case '"':
+                            str.append("&quot;");
+                            break;
+                        case '\'':
+                            str.append("&apos;");
+                            break;
+                        default:
+                            assert false;
+                    }
+                    break;
+                case '\u0000':
+                case '\u0001':
+                case '\u0002':
+                case '\u0003':
+                case '\u0004':
+                case '\u0005':
+                case '\u0006':
+                case '\u0007':
+                case '\u0008':
+                case '\u000b':
+                case '\u000c':
+                case '\u000e':
+                case '\u000f':
+                case '\u0010':
+                case '\u0011':
+                case '\u0012':
+                case '\u0013':
+                case '\u0014':
+                case '\u0015':
+                case '\u0016':
+                case '\u0017':
+                case '\u0018':
+                case '\u0019':
+                case '\u001a':
+                case '\u001b':
+                case '\u001c':
+                case '\u001d':
+                case '\u001e':
+                case '\u001f':
+                    if (str == null) {
+                        str = new StringBuilder();
+                        str.append(s, 0, i);
+                    }
+                    str.append("'0x").append(Integer.toHexString(c));
+                    break;
+                default:
+                    if (str != null) {
+                        str.append(c);
+                    }
+                    break;
+            }
+        }
+        if (str == null) {
+            return s;
+        } else {
+            return str.toString();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java
new file mode 100644
index 0000000..c38eed2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import static org.graalvm.compiler.graph.Edges.Type.Inputs;
+import static org.graalvm.compiler.graph.Edges.Type.Successors;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.graph.CachedGraph;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.InputEdges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Signature;
+
+public class BinaryGraphPrinter implements GraphPrinter {
+
+    private static final int CONSTANT_POOL_MAX_SIZE = 8000;
+
+    private static final int BEGIN_GROUP = 0x00;
+    private static final int BEGIN_GRAPH = 0x01;
+    private static final int CLOSE_GROUP = 0x02;
+
+    private static final int POOL_NEW = 0x00;
+    private static final int POOL_STRING = 0x01;
+    private static final int POOL_ENUM = 0x02;
+    private static final int POOL_CLASS = 0x03;
+    private static final int POOL_METHOD = 0x04;
+    private static final int POOL_NULL = 0x05;
+    private static final int POOL_NODE_CLASS = 0x06;
+    private static final int POOL_FIELD = 0x07;
+    private static final int POOL_SIGNATURE = 0x08;
+
+    private static final int PROPERTY_POOL = 0x00;
+    private static final int PROPERTY_INT = 0x01;
+    private static final int PROPERTY_LONG = 0x02;
+    private static final int PROPERTY_DOUBLE = 0x03;
+    private static final int PROPERTY_FLOAT = 0x04;
+    private static final int PROPERTY_TRUE = 0x05;
+    private static final int PROPERTY_FALSE = 0x06;
+    private static final int PROPERTY_ARRAY = 0x07;
+    private static final int PROPERTY_SUBGRAPH = 0x08;
+
+    private static final int KLASS = 0x00;
+    private static final int ENUM_KLASS = 0x01;
+
+    static final int CURRENT_MAJOR_VERSION = 1;
+    static final int CURRENT_MINOR_VERSION = 0;
+
+    static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'};
+
+    private void writeVersion() throws IOException {
+        writeBytesRaw(MAGIC_BYTES);
+        writeByte(CURRENT_MAJOR_VERSION);
+        writeByte(CURRENT_MINOR_VERSION);
+    }
+
+    private static final class ConstantPool extends LinkedHashMap<Object, Character> {
+
+        private final LinkedList<Character> availableIds;
+        private char nextId;
+        private static final long serialVersionUID = -2676889957907285681L;
+
+        ConstantPool() {
+            super(50, 0.65f);
+            availableIds = new LinkedList<>();
+        }
+
+        @Override
+        protected boolean removeEldestEntry(java.util.Map.Entry<Object, Character> eldest) {
+            if (size() > CONSTANT_POOL_MAX_SIZE) {
+                availableIds.addFirst(eldest.getValue());
+                return true;
+            }
+            return false;
+        }
+
+        private Character nextAvailableId() {
+            if (!availableIds.isEmpty()) {
+                return availableIds.removeFirst();
+            }
+            return nextId++;
+        }
+
+        public char add(Object obj) {
+            Character id = nextAvailableId();
+            put(obj, id);
+            return id;
+        }
+    }
+
+    private final ConstantPool constantPool;
+    private final ByteBuffer buffer;
+    private final WritableByteChannel channel;
+    private final SnippetReflectionProvider snippetReflection;
+
+    private static final Charset utf8 = Charset.forName("UTF-8");
+
+    public BinaryGraphPrinter(WritableByteChannel channel, SnippetReflectionProvider snippetReflection) throws IOException {
+        constantPool = new ConstantPool();
+        buffer = ByteBuffer.allocateDirect(256 * 1024);
+        this.snippetReflection = snippetReflection;
+        this.channel = channel;
+        writeVersion();
+    }
+
+    @Override
+    public SnippetReflectionProvider getSnippetReflectionProvider() {
+        return snippetReflection;
+    }
+
+    @Override
+    public void print(Graph graph, String title, Map<Object, Object> properties) throws IOException {
+        writeByte(BEGIN_GRAPH);
+        writePoolObject(title);
+        writeGraph(graph, properties);
+        flush();
+    }
+
+    private void writeGraph(Graph graph, Map<Object, Object> properties) throws IOException {
+        ScheduleResult scheduleResult = null;
+        if (graph instanceof StructuredGraph) {
+
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            scheduleResult = structuredGraph.getLastSchedule();
+            if (scheduleResult == null) {
+
+                // Also provide a schedule when an error occurs
+                if (Options.PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
+                    try {
+                        SchedulePhase schedule = new SchedulePhase();
+                        schedule.apply(structuredGraph);
+                        scheduleResult = structuredGraph.getLastSchedule();
+                    } catch (Throwable t) {
+                    }
+                }
+
+            }
+        }
+        ControlFlowGraph cfg = scheduleResult == null ? Debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG();
+        BlockMap<List<Node>> blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap();
+        List<Block> blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks());
+        writeProperties(properties);
+        writeNodes(graph, nodeToBlocks, cfg);
+        writeBlocks(blocks, blockToNodes);
+    }
+
+    private void flush() throws IOException {
+        buffer.flip();
+        channel.write(buffer);
+        buffer.compact();
+    }
+
+    private void ensureAvailable(int i) throws IOException {
+        assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small";
+        while (buffer.remaining() < i) {
+            flush();
+        }
+    }
+
+    private void writeByte(int b) throws IOException {
+        ensureAvailable(1);
+        buffer.put((byte) b);
+    }
+
+    private void writeInt(int b) throws IOException {
+        ensureAvailable(4);
+        buffer.putInt(b);
+    }
+
+    private void writeLong(long b) throws IOException {
+        ensureAvailable(8);
+        buffer.putLong(b);
+    }
+
+    private void writeDouble(double b) throws IOException {
+        ensureAvailable(8);
+        buffer.putDouble(b);
+    }
+
+    private void writeFloat(float b) throws IOException {
+        ensureAvailable(4);
+        buffer.putFloat(b);
+    }
+
+    private void writeShort(char b) throws IOException {
+        ensureAvailable(2);
+        buffer.putChar(b);
+    }
+
+    private void writeString(String str) throws IOException {
+        byte[] bytes = str.getBytes(utf8);
+        writeBytes(bytes);
+    }
+
+    private void writeBytes(byte[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            writeBytesRaw(b);
+        }
+    }
+
+    private void writeBytesRaw(byte[] b) throws IOException {
+        int bytesWritten = 0;
+        while (bytesWritten < b.length) {
+            int toWrite = Math.min(b.length - bytesWritten, buffer.capacity());
+            ensureAvailable(toWrite);
+            buffer.put(b, bytesWritten, toWrite);
+            bytesWritten += toWrite;
+        }
+    }
+
+    private void writeInts(int[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            int sizeInBytes = b.length * 4;
+            ensureAvailable(sizeInBytes);
+            buffer.asIntBuffer().put(b);
+            buffer.position(buffer.position() + sizeInBytes);
+        }
+    }
+
+    private void writeDoubles(double[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            int sizeInBytes = b.length * 8;
+            ensureAvailable(sizeInBytes);
+            buffer.asDoubleBuffer().put(b);
+            buffer.position(buffer.position() + sizeInBytes);
+        }
+    }
+
+    private void writePoolObject(Object object) throws IOException {
+        if (object == null) {
+            writeByte(POOL_NULL);
+            return;
+        }
+        Character id = constantPool.get(object);
+        if (id == null) {
+            addPoolEntry(object);
+        } else {
+            if (object instanceof Enum<?>) {
+                writeByte(POOL_ENUM);
+            } else if (object instanceof Class<?> || object instanceof JavaType) {
+                writeByte(POOL_CLASS);
+            } else if (object instanceof NodeClass) {
+                writeByte(POOL_NODE_CLASS);
+            } else if (object instanceof ResolvedJavaMethod) {
+                writeByte(POOL_METHOD);
+            } else if (object instanceof ResolvedJavaField) {
+                writeByte(POOL_FIELD);
+            } else if (object instanceof Signature) {
+                writeByte(POOL_SIGNATURE);
+            } else {
+                writeByte(POOL_STRING);
+            }
+            writeShort(id.charValue());
+        }
+    }
+
+    private static String getClassName(Class<?> klass) {
+        if (!klass.isArray()) {
+            return klass.getName();
+        }
+        return getClassName(klass.getComponentType()) + "[]";
+    }
+
+    private void addPoolEntry(Object object) throws IOException {
+        char index = constantPool.add(object);
+        writeByte(POOL_NEW);
+        writeShort(index);
+        if (object instanceof Class<?>) {
+            Class<?> klass = (Class<?>) object;
+            writeByte(POOL_CLASS);
+            writeString(getClassName(klass));
+            if (klass.isEnum()) {
+                writeByte(ENUM_KLASS);
+                Object[] enumConstants = klass.getEnumConstants();
+                writeInt(enumConstants.length);
+                for (Object o : enumConstants) {
+                    writePoolObject(((Enum<?>) o).name());
+                }
+            } else {
+                writeByte(KLASS);
+            }
+        } else if (object instanceof Enum<?>) {
+            writeByte(POOL_ENUM);
+            writePoolObject(object.getClass());
+            writeInt(((Enum<?>) object).ordinal());
+        } else if (object instanceof JavaType) {
+            JavaType type = (JavaType) object;
+            writeByte(POOL_CLASS);
+            writeString(type.toJavaName());
+            writeByte(KLASS);
+        } else if (object instanceof NodeClass) {
+            NodeClass<?> nodeClass = (NodeClass<?>) object;
+            writeByte(POOL_NODE_CLASS);
+            writeString(nodeClass.getJavaClass().getSimpleName());
+            writeString(nodeClass.getNameTemplate());
+            writeEdgesInfo(nodeClass, Inputs);
+            writeEdgesInfo(nodeClass, Successors);
+        } else if (object instanceof ResolvedJavaMethod) {
+            writeByte(POOL_METHOD);
+            ResolvedJavaMethod method = ((ResolvedJavaMethod) object);
+            writePoolObject(method.getDeclaringClass());
+            writePoolObject(method.getName());
+            writePoolObject(method.getSignature());
+            writeInt(method.getModifiers());
+            writeBytes(method.getCode());
+        } else if (object instanceof ResolvedJavaField) {
+            writeByte(POOL_FIELD);
+            ResolvedJavaField field = ((ResolvedJavaField) object);
+            writePoolObject(field.getDeclaringClass());
+            writePoolObject(field.getName());
+            writePoolObject(field.getType().getName());
+            writeInt(field.getModifiers());
+        } else if (object instanceof Signature) {
+            writeByte(POOL_SIGNATURE);
+            Signature signature = ((Signature) object);
+            int args = signature.getParameterCount(false);
+            writeShort((char) args);
+            for (int i = 0; i < args; i++) {
+                writePoolObject(signature.getParameterType(i, null).getName());
+            }
+            writePoolObject(signature.getReturnType(null).getName());
+        } else {
+            writeByte(POOL_STRING);
+            writeString(object.toString());
+        }
+    }
+
+    private void writeEdgesInfo(NodeClass<?> nodeClass, Edges.Type type) throws IOException {
+        Edges edges = nodeClass.getEdges(type);
+        writeShort((char) edges.getCount());
+        for (int i = 0; i < edges.getCount(); i++) {
+            writeByte(i < edges.getDirectCount() ? 0 : 1);
+            writePoolObject(edges.getName(i));
+            if (type == Inputs) {
+                writePoolObject(((InputEdges) edges).getInputType(i));
+            }
+        }
+    }
+
+    private void writePropertyObject(Object obj) throws IOException {
+        if (obj instanceof Integer) {
+            writeByte(PROPERTY_INT);
+            writeInt(((Integer) obj).intValue());
+        } else if (obj instanceof Long) {
+            writeByte(PROPERTY_LONG);
+            writeLong(((Long) obj).longValue());
+        } else if (obj instanceof Double) {
+            writeByte(PROPERTY_DOUBLE);
+            writeDouble(((Double) obj).doubleValue());
+        } else if (obj instanceof Float) {
+            writeByte(PROPERTY_FLOAT);
+            writeFloat(((Float) obj).floatValue());
+        } else if (obj instanceof Boolean) {
+            if (((Boolean) obj).booleanValue()) {
+                writeByte(PROPERTY_TRUE);
+            } else {
+                writeByte(PROPERTY_FALSE);
+            }
+        } else if (obj instanceof Graph) {
+            writeByte(PROPERTY_SUBGRAPH);
+            writeGraph((Graph) obj, null);
+        } else if (obj instanceof CachedGraph) {
+            writeByte(PROPERTY_SUBGRAPH);
+            writeGraph(((CachedGraph<?>) obj).getReadonlyCopy(), null);
+        } else if (obj != null && obj.getClass().isArray()) {
+            Class<?> componentType = obj.getClass().getComponentType();
+            if (componentType.isPrimitive()) {
+                if (componentType == Double.TYPE) {
+                    writeByte(PROPERTY_ARRAY);
+                    writeByte(PROPERTY_DOUBLE);
+                    writeDoubles((double[]) obj);
+                } else if (componentType == Integer.TYPE) {
+                    writeByte(PROPERTY_ARRAY);
+                    writeByte(PROPERTY_INT);
+                    writeInts((int[]) obj);
+                } else {
+                    writeByte(PROPERTY_POOL);
+                    writePoolObject(obj);
+                }
+            } else {
+                writeByte(PROPERTY_ARRAY);
+                writeByte(PROPERTY_POOL);
+                Object[] array = (Object[]) obj;
+                writeInt(array.length);
+                for (Object o : array) {
+                    writePoolObject(o);
+                }
+            }
+        } else {
+            writeByte(PROPERTY_POOL);
+            writePoolObject(obj);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private static int getNodeId(Node node) {
+        return node.getId();
+    }
+
+    private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
+        if (nodeToBlocks.isNew(node)) {
+            return "NEW (not in schedule)";
+        } else {
+            Block block = nodeToBlocks.get(node);
+            if (block != null) {
+                return block.getId();
+            } else if (node instanceof PhiNode) {
+                return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks);
+            }
+        }
+        return null;
+    }
+
+    private void writeNodes(Graph graph, NodeMap<Block> nodeToBlocks, ControlFlowGraph cfg) throws IOException {
+        Map<Object, Object> props = new HashMap<>();
+
+        writeInt(graph.getNodeCount());
+
+        for (Node node : graph.getNodes()) {
+            NodeClass<?> nodeClass = node.getNodeClass();
+            node.getDebugProperties(props);
+            if (cfg != null && Options.PrintGraphProbabilities.getValue() && node instanceof FixedNode) {
+                try {
+                    props.put("probability", cfg.blockFor(node).probability());
+                } catch (Throwable t) {
+                    props.put("probability", 0.0);
+                    props.put("probability-exception", t);
+                }
+            }
+            if (nodeToBlocks != null) {
+                Object block = getBlockForNode(node, nodeToBlocks);
+                if (block != null) {
+                    props.put("node-to-block", block);
+                }
+            }
+
+            if (node instanceof ControlSinkNode) {
+                props.put("category", "controlSink");
+            } else if (node instanceof ControlSplitNode) {
+                props.put("category", "controlSplit");
+            } else if (node instanceof AbstractMergeNode) {
+                props.put("category", "merge");
+            } else if (node instanceof AbstractBeginNode) {
+                props.put("category", "begin");
+            } else if (node instanceof AbstractEndNode) {
+                props.put("category", "end");
+            } else if (node instanceof FixedNode) {
+                props.put("category", "fixed");
+            } else if (node instanceof VirtualState) {
+                props.put("category", "state");
+            } else if (node instanceof PhiNode) {
+                props.put("category", "phi");
+            } else if (node instanceof ProxyNode) {
+                props.put("category", "proxy");
+            } else {
+                if (node instanceof ConstantNode) {
+                    ConstantNode cn = (ConstantNode) node;
+                    updateStringPropertiesForConstant(props, cn);
+                }
+                props.put("category", "floating");
+            }
+
+            writeInt(getNodeId(node));
+            writePoolObject(nodeClass);
+            writeByte(node.predecessor() == null ? 0 : 1);
+            writeProperties(props);
+            writeEdges(node, Inputs);
+            writeEdges(node, Successors);
+
+            props.clear();
+        }
+    }
+
+    private void writeProperties(Map<Object, Object> props) throws IOException {
+        if (props == null) {
+            writeShort((char) 0);
+            return;
+        }
+        // properties
+        writeShort((char) props.size());
+        for (Entry<Object, Object> entry : props.entrySet()) {
+            String key = entry.getKey().toString();
+            writePoolObject(key);
+            writePropertyObject(entry.getValue());
+        }
+    }
+
+    private void writeEdges(Node node, Edges.Type type) throws IOException {
+        NodeClass<?> nodeClass = node.getNodeClass();
+        Edges edges = nodeClass.getEdges(type);
+        final long[] curOffsets = edges.getOffsets();
+        for (int i = 0; i < edges.getDirectCount(); i++) {
+            writeNodeRef(Edges.getNode(node, curOffsets, i));
+        }
+        for (int i = edges.getDirectCount(); i < edges.getCount(); i++) {
+            NodeList<Node> list = Edges.getNodeList(node, curOffsets, i);
+            if (list == null) {
+                writeShort((char) 0);
+            } else {
+                int listSize = list.count();
+                assert listSize == ((char) listSize);
+                writeShort((char) listSize);
+                for (Node edge : list) {
+                    writeNodeRef(edge);
+                }
+            }
+        }
+    }
+
+    private void writeNodeRef(Node edge) throws IOException {
+        if (edge != null) {
+            writeInt(getNodeId(edge));
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    private void writeBlocks(List<Block> blocks, BlockMap<List<Node>> blockToNodes) throws IOException {
+        if (blocks != null && blockToNodes != null) {
+            for (Block block : blocks) {
+                List<Node> nodes = blockToNodes.get(block);
+                if (nodes == null) {
+                    writeInt(0);
+                    return;
+                }
+            }
+            writeInt(blocks.size());
+            for (Block block : blocks) {
+                List<Node> nodes = blockToNodes.get(block);
+                List<Node> extraNodes = new LinkedList<>();
+                writeInt(block.getId());
+                for (Node node : nodes) {
+                    if (node instanceof AbstractMergeNode) {
+                        AbstractMergeNode merge = (AbstractMergeNode) node;
+                        for (PhiNode phi : merge.phis()) {
+                            if (!nodes.contains(phi)) {
+                                extraNodes.add(phi);
+                            }
+                        }
+                    }
+                }
+                writeInt(nodes.size() + extraNodes.size());
+                for (Node node : nodes) {
+                    writeInt(getNodeId(node));
+                }
+                for (Node node : extraNodes) {
+                    writeInt(getNodeId(node));
+                }
+                writeInt(block.getSuccessors().length);
+                for (Block sux : block.getSuccessors()) {
+                    writeInt(sux.getId());
+                }
+            }
+        } else {
+            writeInt(0);
+        }
+    }
+
+    @Override
+    public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
+        writeByte(BEGIN_GROUP);
+        writePoolObject(name);
+        writePoolObject(shortName);
+        writePoolObject(method);
+        writeInt(bci);
+        writeProperties(properties);
+    }
+
+    @Override
+    public void endGroup() throws IOException {
+        writeByte(CLOSE_GROUP);
+    }
+
+    @Override
+    public void close() {
+        try {
+            flush();
+            channel.close();
+        } catch (IOException ex) {
+            throw new Error(ex);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java
new file mode 100644
index 0000000..61589ca
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import static java.lang.Character.toLowerCase;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.java.BciBlockMapping;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.debug.IntervalDumper;
+import org.graalvm.compiler.lir.debug.IntervalDumper.IntervalVisitor;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Utility for printing Graal IR at various compilation phases.
+ */
+class CFGPrinter extends CompilationPrinter {
+
+    protected TargetDescription target;
+    protected LIR lir;
+    protected NodeLIRBuilder nodeLirGenerator;
+    protected ControlFlowGraph cfg;
+    protected ScheduleResult schedule;
+    protected ResolvedJavaMethod method;
+
+    /**
+     * Creates a control flow graph printer.
+     *
+     * @param out where the output generated via this printer shown be written
+     */
+    CFGPrinter(OutputStream out) {
+        super(out);
+    }
+
+    /**
+     * Prints the control flow graph denoted by a given block map.
+     *
+     * @param label A label describing the compilation phase that produced the control flow graph.
+     * @param blockMap A data structure describing the blocks in a method and how they are
+     *            connected.
+     */
+    public void printCFG(String label, BciBlockMapping blockMap) {
+        begin("cfg");
+        out.print("name \"").print(label).println('"');
+        for (BciBlockMapping.BciBlock block : blockMap.getBlocks()) {
+            begin("block");
+            printBlock(block);
+            end("block");
+        }
+        end("cfg");
+    }
+
+    private void printBlock(BciBlockMapping.BciBlock block) {
+        out.print("name \"B").print(block.startBci).println('"');
+        out.print("from_bci ").println(block.startBci);
+        out.print("to_bci ").println(block.endBci);
+
+        out.println("predecessors ");
+
+        out.print("successors ");
+        for (BciBlockMapping.BciBlock succ : block.getSuccessors()) {
+            if (!succ.isExceptionEntry) {
+                out.print("\"B").print(succ.startBci).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("xhandlers");
+        for (BciBlockMapping.BciBlock succ : block.getSuccessors()) {
+            if (succ.isExceptionEntry) {
+                out.print("\"B").print(succ.startBci).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("flags ");
+        if (block.isExceptionEntry) {
+            out.print("\"ex\" ");
+        }
+        if (block.isLoopHeader) {
+            out.print("\"plh\" ");
+        }
+        out.println();
+
+        out.print("loop_depth ").println(Long.bitCount(block.loops));
+    }
+
+    private NodeMap<Block> latestScheduling;
+    private NodeBitMap printedNodes;
+
+    private boolean inFixedSchedule(Node node) {
+        return lir != null || schedule != null || node.isDeleted() || cfg.getNodeToBlock().get(node) != null;
+    }
+
+    /**
+     * Prints the specified list of blocks.
+     *
+     * @param label A label describing the compilation phase that produced the control flow graph.
+     * @param blocks The list of blocks to be printed.
+     */
+    public void printCFG(String label, AbstractBlockBase<?>[] blocks, boolean printNodes) {
+        if (lir == null) {
+            latestScheduling = new NodeMap<>(cfg.getNodeToBlock());
+            for (AbstractBlockBase<?> abstractBlock : blocks) {
+                if (abstractBlock == null) {
+                    continue;
+                }
+                Block block = (Block) abstractBlock;
+                Node cur = block.getBeginNode();
+                while (true) {
+                    assert inFixedSchedule(cur) && latestScheduling.get(cur) == block;
+                    scheduleInputs(cur, block);
+
+                    if (cur == block.getEndNode()) {
+                        break;
+                    }
+                    assert cur.successors().count() == 1;
+                    cur = cur.successors().first();
+                }
+            }
+        }
+
+        begin("cfg");
+        out.print("name \"").print(label).println('"');
+        for (AbstractBlockBase<?> block : blocks) {
+            printBlock(block, printNodes);
+        }
+        end("cfg");
+        // NOTE: we do this only because the c1visualizer does not recognize the bytecode block if
+        // it is proceeding the cfg blocks. Currently we have no direct influence on the emit order.
+        // As a workaround we dump the bytecode after every cfg.
+        if (method != null) {
+            printBytecodes(new BytecodeDisassembler(false).disassemble(method));
+        }
+
+        latestScheduling = null;
+    }
+
+    private void scheduleInputs(Node node, Block nodeBlock) {
+        if (node instanceof ValuePhiNode) {
+            PhiNode phi = (PhiNode) node;
+            Block phiBlock = latestScheduling.get(phi.merge());
+            assert phiBlock != null;
+            for (Block pred : phiBlock.getPredecessors()) {
+                schedule(phi.valueAt((AbstractEndNode) pred.getEndNode()), pred);
+            }
+
+        } else {
+            for (Node input : node.inputs()) {
+                schedule(input, nodeBlock);
+            }
+        }
+    }
+
+    private void schedule(Node input, Block block) {
+        if (!inFixedSchedule(input)) {
+            Block inputBlock = block;
+            if (latestScheduling.get(input) != null) {
+                inputBlock = AbstractControlFlowGraph.commonDominatorTyped(inputBlock, latestScheduling.get(input));
+            }
+            if (inputBlock != latestScheduling.get(input)) {
+                latestScheduling.set(input, inputBlock);
+                scheduleInputs(input, inputBlock);
+            }
+        }
+    }
+
+    private void printBlock(AbstractBlockBase<?> block, boolean printNodes) {
+        if (block == null) {
+            return;
+        }
+        printBlockProlog(block);
+        if (printNodes) {
+            assert block instanceof Block;
+            printNodes((Block) block);
+        }
+        printBlockEpilog(block);
+    }
+
+    private void printBlockEpilog(AbstractBlockBase<?> block) {
+        printLIR(block);
+        end("block");
+    }
+
+    private void printBlockProlog(AbstractBlockBase<?> block) {
+        begin("block");
+
+        out.print("name \"").print(blockToString(block)).println('"');
+        out.println("from_bci -1");
+        out.println("to_bci -1");
+
+        out.print("predecessors ");
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            out.print("\"").print(blockToString(pred)).print("\" ");
+        }
+        out.println();
+
+        out.print("successors ");
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            if (!succ.isExceptionEntry()) {
+                out.print("\"").print(blockToString(succ)).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("xhandlers");
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+            if (succ.isExceptionEntry()) {
+                out.print("\"").print(blockToString(succ)).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("flags ");
+        if (block.isLoopHeader()) {
+            out.print("\"llh\" ");
+        }
+        if (block.isLoopEnd()) {
+            out.print("\"lle\" ");
+        }
+        if (block.isExceptionEntry()) {
+            out.print("\"ex\" ");
+        }
+        out.println();
+
+        if (block.getLoop() != null) {
+            out.print("loop_index ").println(block.getLoop().getIndex());
+            out.print("loop_depth ").println(block.getLoop().getDepth());
+        }
+
+        out.print("probability ").println(Double.doubleToRawLongBits(block.probability()));
+    }
+
+    private void printNodes(Block block) {
+        printedNodes = new NodeBitMap(cfg.graph);
+        begin("IR");
+        out.println("HIR");
+        out.disableIndentation();
+
+        if (block.getBeginNode() instanceof AbstractMergeNode) {
+            // Currently phi functions are not in the schedule, so print them separately here.
+            for (ValueNode phi : ((AbstractMergeNode) block.getBeginNode()).phis()) {
+                printNode(phi, false);
+            }
+        }
+
+        Node cur = block.getBeginNode();
+        while (true) {
+            printNode(cur, false);
+
+            if (cur == block.getEndNode()) {
+                for (Map.Entry<Node, Block> entry : latestScheduling.entries()) {
+                    if (entry.getValue() == block && !inFixedSchedule(entry.getKey()) && !printedNodes.isMarked(entry.getKey())) {
+                        printNode(entry.getKey(), true);
+                    }
+                }
+                break;
+            }
+            assert cur.successors().count() == 1;
+            cur = cur.successors().first();
+        }
+
+        out.enableIndentation();
+        end("IR");
+        printedNodes = null;
+    }
+
+    private void printNode(Node node, boolean unscheduled) {
+        assert !printedNodes.isMarked(node);
+        printedNodes.mark(node);
+
+        if (!(node instanceof ValuePhiNode)) {
+            for (Node input : node.inputs()) {
+                if (!inFixedSchedule(input) && !printedNodes.isMarked(input)) {
+                    printNode(input, true);
+                }
+            }
+        }
+
+        if (unscheduled) {
+            assert lir == null && schedule == null : "unscheduled nodes can only be present before LIR generation";
+            out.print("f ").print(HOVER_START).print("u").print(HOVER_SEP).print("unscheduled").print(HOVER_END).println(COLUMN_END);
+        } else if (node instanceof FixedWithNextNode) {
+            out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END);
+        } else if (node instanceof FixedNode) {
+            out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END);
+        } else if (node instanceof FloatingNode) {
+            out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END);
+        }
+        out.print("tid ").print(nodeToString(node)).println(COLUMN_END);
+
+        if (nodeLirGenerator != null) {
+            Value operand = nodeLirGenerator.hasOperand(node) ? nodeLirGenerator.operand(node) : null;
+            if (operand != null) {
+                out.print("result ").print(operand.toString()).println(COLUMN_END);
+            }
+        }
+
+        if (node instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) node;
+            if (stateSplit.stateAfter() != null) {
+                String state = stateToString(stateSplit.stateAfter());
+                out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END);
+            }
+        }
+
+        Map<Object, Object> props = new TreeMap<>(node.getDebugProperties());
+        out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP);
+        out.println("=== Debug Properties ===");
+        for (Map.Entry<Object, Object> entry : props.entrySet()) {
+            out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println();
+        }
+        out.println("=== Inputs ===");
+        printNamedNodes(node, node.inputPositions().iterator(), "", "\n", null);
+        out.println("=== Succesors ===");
+        printNamedNodes(node, node.successorPositions().iterator(), "", "\n", null);
+        out.println("=== Usages ===");
+        if (!node.hasNoUsages()) {
+            for (Node usage : node.usages()) {
+                out.print(nodeToString(usage)).print(" ");
+            }
+            out.println();
+        }
+        out.println("=== Predecessor ===");
+        out.print(nodeToString(node.predecessor())).print(" ");
+        out.print(HOVER_END).println(COLUMN_END);
+
+        out.print("instruction ");
+        out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" ");
+        printNamedNodes(node, node.inputPositions().iterator(), "", "", "#NDF");
+        printNamedNodes(node, node.successorPositions().iterator(), "#", "", "#NDF");
+        for (Map.Entry<Object, Object> entry : props.entrySet()) {
+            String key = entry.getKey().toString();
+            if (key.startsWith("data.") && !key.equals("data.stamp")) {
+                out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" ");
+            }
+        }
+        out.print(COLUMN_END).print(' ').println(COLUMN_END);
+    }
+
+    private void printNamedNodes(Node node, Iterator<Position> iter, String prefix, String suffix, String hideSuffix) {
+        int lastIndex = -1;
+        while (iter.hasNext()) {
+            Position pos = iter.next();
+            if (hideSuffix != null && pos.getName().endsWith(hideSuffix)) {
+                continue;
+            }
+
+            if (pos.getIndex() != lastIndex) {
+                if (lastIndex != -1) {
+                    out.print(suffix);
+                }
+                out.print(prefix).print(pos.getName()).print(": ");
+                lastIndex = pos.getIndex();
+            }
+            out.print(nodeToString(pos.get(node))).print(" ");
+        }
+        if (lastIndex != -1) {
+            out.print(suffix);
+        }
+    }
+
+    private String stateToString(FrameState state) {
+        StringBuilder buf = new StringBuilder();
+        FrameState curState = state;
+        do {
+            buf.append(Bytecode.toLocation(curState.getCode(), curState.bci)).append('\n');
+
+            if (curState.stackSize() > 0) {
+                buf.append("stack: ");
+                for (int i = 0; i < curState.stackSize(); i++) {
+                    buf.append(stateValueToString(curState.stackAt(i))).append(' ');
+                }
+                buf.append("\n");
+            }
+
+            buf.append("locals: ");
+            for (int i = 0; i < curState.localsSize(); i++) {
+                buf.append(stateValueToString(curState.localAt(i))).append(' ');
+            }
+            buf.append("\n");
+
+            buf.append("locks: ");
+            for (int i = 0; i < curState.locksSize(); i++) {
+                buf.append(stateValueToString(curState.lockAt(i))).append(' ');
+            }
+            buf.append("\n");
+
+            curState = curState.outerFrameState();
+        } while (curState != null);
+
+        return buf.toString();
+    }
+
+    private String stateValueToString(ValueNode value) {
+        String result = nodeToString(value);
+        if (nodeLirGenerator != null && value != null && nodeLirGenerator.hasOperand(value)) {
+            Value operand = nodeLirGenerator.operand(value);
+            assert operand != null;
+            result += ": " + operand;
+        }
+        return result;
+    }
+
+    /**
+     * Prints the LIR for each instruction in a given block.
+     *
+     * @param block the block to print
+     */
+    private void printLIR(AbstractBlockBase<?> block) {
+        if (lir == null) {
+            return;
+        }
+        List<LIRInstruction> lirInstructions = lir.getLIRforBlock(block);
+        if (lirInstructions == null) {
+            return;
+        }
+
+        begin("IR");
+        out.println("LIR");
+
+        for (int i = 0; i < lirInstructions.size(); i++) {
+            LIRInstruction inst = lirInstructions.get(i);
+            printLIRInstruction(inst);
+        }
+        end("IR");
+    }
+
+    private void printLIRInstruction(LIRInstruction inst) {
+        if (inst == null) {
+            out.print("nr   -1 ").print(COLUMN_END).print(" instruction ").print("<deleted>").print(COLUMN_END);
+            out.println(COLUMN_END);
+        } else {
+            out.printf("nr %4d ", inst.id()).print(COLUMN_END);
+
+            final StringBuilder stateString = new StringBuilder();
+            inst.forEachState(state -> {
+                if (state.hasDebugInfo()) {
+                    DebugInfo di = state.debugInfo();
+                    stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), state.getLiveBasePointers(), di.getCalleeSaveInfo()));
+                } else {
+                    stateString.append(debugInfoToString(state.topFrame, null, state.getLiveBasePointers(), null));
+                }
+            });
+            if (stateString.length() > 0) {
+                int level = out.indentationLevel();
+                out.adjustIndentation(-level);
+                out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(stateString.toString()).print(HOVER_END).print(COLUMN_END);
+                out.adjustIndentation(level);
+            }
+
+            out.print(" instruction ").print(inst.toString()).print(COLUMN_END);
+            out.println(COLUMN_END);
+        }
+    }
+
+    private String nodeToString(Node node) {
+        if (node == null) {
+            return "-";
+        }
+        String prefix;
+        if (node instanceof AbstractBeginNode && (lir == null && schedule == null)) {
+            prefix = "B";
+        } else if (node instanceof ValueNode) {
+            ValueNode value = (ValueNode) node;
+            if (value.getStackKind() == JavaKind.Illegal) {
+                prefix = "v";
+            } else {
+                prefix = String.valueOf(toLowerCase(value.getStackKind().getTypeChar()));
+            }
+        } else {
+            prefix = "?";
+        }
+        return prefix + node.toString(Verbosity.Id);
+    }
+
+    private String blockToString(AbstractBlockBase<?> block) {
+        if (lir == null && schedule == null && block instanceof Block) {
+            // During all the front-end phases, the block schedule is built only for the debug
+            // output.
+            // Therefore, the block numbers would be different for every CFG printed -> use the id
+            // of the first instruction.
+            return "B" + ((Block) block).getBeginNode().toString(Verbosity.Id);
+        } else {
+            // LIR instructions contain references to blocks and these blocks are printed as the
+            // blockID -> use the blockID.
+            return "B" + block.getId();
+        }
+    }
+
+    IntervalVisitor intervalVisitor = new IntervalVisitor() {
+
+        /**
+         * @return a formatted description of the operand that the C1Visualizer can handle.
+         */
+        String getFormattedOperand(Value operand) {
+            String s = operand.toString();
+            int last = s.lastIndexOf('|');
+            if (last != -1) {
+                return s.substring(0, last) + "|" + operand.getPlatformKind().getTypeChar();
+            }
+            return s;
+        }
+
+        @Override
+        public void visitIntervalStart(Value parentOperand, Value splitOperand, Value location, Value hint, String typeName) {
+            out.printf("%s %s ", getFormattedOperand(splitOperand), typeName);
+            if (location != null) {
+                out.printf("\"[%s]\"", getFormattedOperand(location));
+            } else {
+                out.printf("\"[%s]\"", getFormattedOperand(splitOperand));
+            }
+            out.printf(" %s %s ", getFormattedOperand(parentOperand), hint != null ? getFormattedOperand(hint) : -1);
+        }
+
+        @Override
+        public void visitRange(int from, int to) {
+            out.printf("[%d, %d[", from, to);
+        }
+
+        @Override
+        public void visitUsePos(int usePos, Object registerPriority) {
+            out.printf("%d %s ", usePos, registerPriority);
+        }
+
+        @Override
+        public void visitIntervalEnd(Object spillState) {
+            out.printf(" \"%s\"", spillState);
+            out.println();
+        }
+
+    };
+
+    public void printIntervals(String label, IntervalDumper intervals) {
+        begin("intervals");
+        out.println(String.format("name \"%s\"", label));
+
+        intervals.visitIntervals(intervalVisitor);
+
+        end("intervals");
+    }
+
+    public void printSchedule(String message, ScheduleResult theSchedule) {
+        schedule = theSchedule;
+        cfg = schedule.getCFG();
+        printedNodes = new NodeBitMap(cfg.graph);
+
+        begin("cfg");
+        out.print("name \"").print(message).println('"');
+        for (Block b : schedule.getCFG().getBlocks()) {
+            if (schedule.nodesFor(b) != null) {
+                printScheduledBlock(b, schedule.nodesFor(b));
+            }
+        }
+        end("cfg");
+
+        schedule = null;
+        cfg = null;
+        printedNodes = null;
+    }
+
+    private void printScheduledBlock(Block block, List<Node> nodesFor) {
+        printBlockProlog(block);
+        begin("IR");
+        out.println("HIR");
+        out.disableIndentation();
+
+        if (block.getBeginNode() instanceof AbstractMergeNode) {
+            // Currently phi functions are not in the schedule, so print them separately here.
+            for (ValueNode phi : ((AbstractMergeNode) block.getBeginNode()).phis()) {
+                printNode(phi, false);
+            }
+        }
+
+        for (Node n : nodesFor) {
+            printNode(n, false);
+        }
+
+        out.enableIndentation();
+        end("IR");
+
+        printBlockEpilog(block);
+    }
+
+    public void printTraces(String label, TraceBuilderResult traces) {
+        begin("cfg");
+        out.print("name \"").print(label).println('"');
+
+        for (Trace trace : traces.getTraces()) {
+            printTrace(trace, traces);
+        }
+
+        end("cfg");
+    }
+
+    private void printTrace(Trace trace, TraceBuilderResult traceBuilderResult) {
+        printTraceProlog(trace, traceBuilderResult);
+        printTraceInstructions(trace, traceBuilderResult);
+        printTraceEpilog();
+    }
+
+    private void printTraceProlog(Trace trace, TraceBuilderResult traceBuilderResult) {
+        begin("block");
+
+        out.print("name \"").print(traceToString(trace)).println('"');
+        out.println("from_bci -1");
+        out.println("to_bci -1");
+
+        out.print("predecessors ");
+        for (Trace pred : getPredecessors(trace, traceBuilderResult)) {
+            out.print("\"").print(traceToString(pred)).print("\" ");
+        }
+        out.println();
+
+        out.print("successors ");
+        for (Trace succ : getSuccessors(trace, traceBuilderResult)) {
+            // if (!succ.isExceptionEntry()) {
+            out.print("\"").print(traceToString(succ)).print("\" ");
+            // }
+        }
+        out.println();
+
+        out.print("xhandlers");
+        // TODO(je) add support for exception handler
+        out.println();
+
+        out.print("flags ");
+        // TODO(je) add support for flags
+        out.println();
+        // TODO(je) add support for loop infos
+    }
+
+    private void printTraceInstructions(Trace trace, TraceBuilderResult traceBuilderResult) {
+        if (lir == null) {
+            return;
+        }
+        begin("IR");
+        out.println("LIR");
+
+        for (AbstractBlockBase<?> block : trace.getBlocks()) {
+            List<LIRInstruction> lirInstructions = lir.getLIRforBlock(block);
+            if (lirInstructions == null) {
+                continue;
+            }
+            printBlockInstruction(block, traceBuilderResult);
+            for (int i = 0; i < lirInstructions.size(); i++) {
+                LIRInstruction inst = lirInstructions.get(i);
+                printLIRInstruction(inst);
+            }
+        }
+        end("IR");
+    }
+
+    private void printBlockInstruction(AbstractBlockBase<?> block, TraceBuilderResult traceBuilderResult) {
+        out.print("nr ").print(block.toString()).print(COLUMN_END).print(" instruction ");
+
+        if (block.getPredecessorCount() > 0) {
+            out.print("<- ");
+            printBlockListWithTrace(Arrays.asList(block.getPredecessors()), traceBuilderResult);
+            out.print(" ");
+        }
+        if (block.getSuccessorCount() > 0) {
+            out.print("-> ");
+            printBlockListWithTrace(Arrays.asList(block.getSuccessors()), traceBuilderResult);
+        }
+
+        out.print(COLUMN_END);
+        out.println(COLUMN_END);
+    }
+
+    private void printBlockListWithTrace(List<? extends AbstractBlockBase<?>> blocks, TraceBuilderResult traceBuilderResult) {
+        Iterator<? extends AbstractBlockBase<?>> it = blocks.iterator();
+        printBlockWithTrace(it.next(), traceBuilderResult);
+        while (it.hasNext()) {
+            out.print(",");
+            printBlockWithTrace(it.next(), traceBuilderResult);
+        }
+    }
+
+    private void printBlockWithTrace(AbstractBlockBase<?> block, TraceBuilderResult traceBuilderResult) {
+        out.print(block.toString());
+        out.print("[T").print(traceBuilderResult.getTraceForBlock(block).getId()).print("]");
+    }
+
+    private void printTraceEpilog() {
+        end("block");
+    }
+
+    private static boolean isLoopBackEdge(AbstractBlockBase<?> src, AbstractBlockBase<?> dst) {
+        return dst.isLoopHeader() && dst.getLoop().equals(src.getLoop());
+    }
+
+    private static List<Trace> getSuccessors(Trace trace, TraceBuilderResult traceBuilderResult) {
+        BitSet bs = new BitSet(traceBuilderResult.getTraces().size());
+        for (AbstractBlockBase<?> block : trace.getBlocks()) {
+            for (AbstractBlockBase<?> s : block.getSuccessors()) {
+                Trace otherTrace = traceBuilderResult.getTraceForBlock(s);
+                int otherTraceId = otherTrace.getId();
+                if (trace.getId() != otherTraceId || isLoopBackEdge(block, s)) {
+                    bs.set(otherTraceId);
+                }
+            }
+        }
+        List<Trace> succ = new ArrayList<>();
+        for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
+            succ.add(traceBuilderResult.getTraces().get(i));
+        }
+        return succ;
+    }
+
+    private static List<Trace> getPredecessors(Trace trace, TraceBuilderResult traceBuilderResult) {
+        BitSet bs = new BitSet(traceBuilderResult.getTraces().size());
+        for (AbstractBlockBase<?> block : trace.getBlocks()) {
+            for (AbstractBlockBase<?> p : block.getPredecessors()) {
+                Trace otherTrace = traceBuilderResult.getTraceForBlock(p);
+                int otherTraceId = otherTrace.getId();
+                if (trace.getId() != otherTraceId || isLoopBackEdge(p, block)) {
+                    bs.set(traceBuilderResult.getTraceForBlock(p).getId());
+                }
+            }
+        }
+        List<Trace> pred = new ArrayList<>();
+        for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
+            pred.add(traceBuilderResult.getTraces().get(i));
+        }
+        return pred;
+    }
+
+    private static String traceToString(Trace trace) {
+        return new StringBuilder("T").append(trace.getId()).toString();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java
new file mode 100644
index 0000000..659d252
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.gen.NodeLIRBuilder;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.java.BciBlockMapping;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.debug.IntervalDumper;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.options.UniquePathUtilities;
+import org.graalvm.compiler.serviceprovider.GraalServices;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the
+ * <a href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>.
+ */
+public class CFGPrinterObserver implements DebugDumpHandler {
+
+    private CFGPrinter cfgPrinter;
+    private File cfgFile;
+    private JavaMethod curMethod;
+    private List<String> curDecorators = Collections.emptyList();
+    private final boolean dumpFrontend;
+
+    public CFGPrinterObserver(boolean dumpFrontend) {
+        this.dumpFrontend = dumpFrontend;
+    }
+
+    @Override
+    public void dump(Object object, String message) {
+        try {
+            dumpSandboxed(object, message);
+        } catch (Throwable ex) {
+            TTY.println("CFGPrinter: Exception during output of " + message + ": " + ex);
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Looks for the outer most method and its {@link DebugDumpScope#decorator}s in the current
+     * debug scope and opens a new compilation scope if this pair does not match the current method
+     * and decorator pair.
+     */
+    private boolean checkMethodScope() {
+        JavaMethod method = null;
+        ArrayList<String> decorators = new ArrayList<>();
+        for (Object o : Debug.context()) {
+            if (o instanceof JavaMethod) {
+                method = (JavaMethod) o;
+                decorators.clear();
+            } else if (o instanceof StructuredGraph) {
+                StructuredGraph graph = (StructuredGraph) o;
+                if (graph.method() != null) {
+                    method = graph.method();
+                    decorators.clear();
+                }
+            } else if (o instanceof DebugDumpScope) {
+                DebugDumpScope debugDumpScope = (DebugDumpScope) o;
+                if (debugDumpScope.decorator) {
+                    decorators.add(debugDumpScope.name);
+                }
+            }
+        }
+
+        if (method == null) {
+            return false;
+        }
+
+        if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
+            cfgPrinter.printCompilation(method);
+            TTY.println("CFGPrinter: Dumping method %s to %s", method, cfgFile.getAbsolutePath());
+        }
+        curMethod = method;
+        curDecorators = decorators;
+        return true;
+    }
+
+    private static boolean isFrontendObject(Object object) {
+        return object instanceof Graph || object instanceof BciBlockMapping;
+    }
+
+    private LIR lastLIR = null;
+    private IntervalDumper delayedIntervals = null;
+
+    public void dumpSandboxed(Object object, String message) {
+        if (!dumpFrontend && isFrontendObject(object)) {
+            return;
+        }
+
+        if (cfgPrinter == null) {
+            cfgFile = getCFGPath().toFile();
+            try {
+                /*
+                 * Initializing a debug environment multiple times by calling
+                 * DebugEnvironment#initialize will create new CFGPrinterObserver objects that refer
+                 * to the same file path. This means the CFG file may be overridden by another
+                 * instance. Appending to an existing CFG file is not an option as the writing
+                 * happens buffered.
+                 */
+                OutputStream out = new BufferedOutputStream(new FileOutputStream(cfgFile));
+                cfgPrinter = new CFGPrinter(out);
+            } catch (FileNotFoundException e) {
+                throw new GraalError("Could not open " + cfgFile.getAbsolutePath());
+            }
+            TTY.println("CFGPrinter: Output to file %s", cfgFile.getAbsolutePath());
+        }
+
+        if (!checkMethodScope()) {
+            return;
+        }
+        try {
+            if (curMethod instanceof ResolvedJavaMethod) {
+                cfgPrinter.method = (ResolvedJavaMethod) curMethod;
+            }
+
+            if (object instanceof LIR) {
+                cfgPrinter.lir = (LIR) object;
+            } else {
+                cfgPrinter.lir = Debug.contextLookup(LIR.class);
+            }
+            cfgPrinter.nodeLirGenerator = Debug.contextLookup(NodeLIRBuilder.class);
+            if (cfgPrinter.nodeLirGenerator != null) {
+                cfgPrinter.target = cfgPrinter.nodeLirGenerator.getLIRGeneratorTool().target();
+            }
+            if (cfgPrinter.lir != null && cfgPrinter.lir.getControlFlowGraph() instanceof ControlFlowGraph) {
+                cfgPrinter.cfg = (ControlFlowGraph) cfgPrinter.lir.getControlFlowGraph();
+            }
+
+            CodeCacheProvider codeCache = Debug.contextLookup(CodeCacheProvider.class);
+            if (codeCache != null) {
+                cfgPrinter.target = codeCache.getTarget();
+            }
+
+            if (object instanceof BciBlockMapping) {
+                BciBlockMapping blockMap = (BciBlockMapping) object;
+                cfgPrinter.printCFG(message, blockMap);
+                if (blockMap.code.getCode() != null) {
+                    cfgPrinter.printBytecodes(new BytecodeDisassembler(false).disassemble(blockMap.code));
+                }
+
+            } else if (object instanceof LIR) {
+                // Currently no node printing for lir
+                cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), false);
+                lastLIR = (LIR) object;
+                if (delayedIntervals != null) {
+                    cfgPrinter.printIntervals(message, delayedIntervals);
+                    delayedIntervals = null;
+                }
+            } else if (object instanceof ScheduleResult) {
+                cfgPrinter.printSchedule(message, (ScheduleResult) object);
+            } else if (object instanceof StructuredGraph) {
+                if (cfgPrinter.cfg == null) {
+                    StructuredGraph graph = (StructuredGraph) object;
+                    cfgPrinter.cfg = ControlFlowGraph.compute(graph, true, true, true, false);
+                    cfgPrinter.printCFG(message, cfgPrinter.cfg.getBlocks(), true);
+                } else {
+                    cfgPrinter.printCFG(message, cfgPrinter.cfg.getBlocks(), true);
+                }
+
+            } else if (object instanceof CompilationResult) {
+                final CompilationResult compResult = (CompilationResult) object;
+                cfgPrinter.printMachineCode(disassemble(codeCache, compResult, null), message);
+            } else if (object instanceof InstalledCode) {
+                CompilationResult compResult = Debug.contextLookup(CompilationResult.class);
+                if (compResult != null) {
+                    cfgPrinter.printMachineCode(disassemble(codeCache, compResult, (InstalledCode) object), message);
+                }
+            } else if (object instanceof IntervalDumper) {
+                if (lastLIR == cfgPrinter.lir) {
+                    cfgPrinter.printIntervals(message, (IntervalDumper) object);
+                } else {
+                    if (delayedIntervals != null) {
+                        Debug.log("Some delayed intervals were dropped (%s)", delayedIntervals);
+                    }
+                    delayedIntervals = (IntervalDumper) object;
+                }
+            } else if (object instanceof AbstractBlockBase<?>[]) {
+                cfgPrinter.printCFG(message, (AbstractBlockBase<?>[]) object, false);
+            } else if (object instanceof Trace) {
+                cfgPrinter.printCFG(message, ((Trace) object).getBlocks(), false);
+            } else if (object instanceof TraceBuilderResult) {
+                cfgPrinter.printTraces(message, (TraceBuilderResult) object);
+            }
+        } finally {
+            cfgPrinter.target = null;
+            cfgPrinter.lir = null;
+            cfgPrinter.nodeLirGenerator = null;
+            cfgPrinter.cfg = null;
+            cfgPrinter.flush();
+        }
+    }
+
+    public static Path getCFGPath() {
+        return UniquePathUtilities.getPath(Options.PrintCFGFileName, Options.DumpPath, "cfg");
+    }
+
+    /** Lazy initialization to delay service lookup until disassembler is actually needed. */
+    static class DisassemblerHolder {
+        private static final DisassemblerProvider disassembler;
+
+        static {
+            DisassemblerProvider selected = null;
+            for (DisassemblerProvider d : GraalServices.load(DisassemblerProvider.class)) {
+                String name = d.getName().toLowerCase();
+                if (name.contains("hcf") || name.contains("hexcodefile")) {
+                    selected = d;
+                    break;
+                }
+            }
+            if (selected == null) {
+                selected = new DisassemblerProvider() {
+                    @Override
+                    public String getName() {
+                        return "nop";
+                    }
+                };
+            }
+            disassembler = selected;
+        }
+    }
+
+    private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) {
+        DisassemblerProvider dis = DisassemblerHolder.disassembler;
+        if (installedCode != null) {
+            return dis.disassembleInstalledCode(codeCache, compResult, installedCode);
+        }
+        return dis.disassembleCompiledCode(codeCache, compResult);
+    }
+
+    @Override
+    public void close() {
+        if (cfgPrinter != null) {
+            cfgPrinter.close();
+            cfgPrinter = null;
+            curDecorators = Collections.emptyList();
+            curMethod = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java
new file mode 100644
index 0000000..c8d0f39
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.CanonicalGraphStringsCheckConstants;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.CanonicalGraphStringsExcludeVirtuals;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.CanonicalGraphStringsRemoveIdentities;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCanonicalGraphStringFlavor;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.FullInfopointNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class CanonicalStringGraphPrinter implements GraphPrinter {
+    private static final Pattern IDENTITY_PATTERN = Pattern.compile("([A-Za-z0-9$_]+)@[0-9a-f]+");
+    private Path currentDirectory;
+    private Path root;
+    private final SnippetReflectionProvider snippetReflection;
+
+    public CanonicalStringGraphPrinter(Path directory, SnippetReflectionProvider snippetReflection) {
+        this.currentDirectory = directory;
+        this.root = directory;
+        this.snippetReflection = snippetReflection;
+    }
+
+    @Override
+    public SnippetReflectionProvider getSnippetReflectionProvider() {
+        return snippetReflection;
+    }
+
+    protected static String escapeFileName(String name) {
+        byte[] bytes = name.getBytes();
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            if ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '.' || b == '-' || b == '_') {
+                sb.append((char) b);
+            } else {
+                sb.append('%');
+                sb.append(Integer.toHexString(b));
+            }
+        }
+        return sb.toString();
+    }
+
+    private static String removeIdentities(String str) {
+        return IDENTITY_PATTERN.matcher(str).replaceAll("$1");
+    }
+
+    protected static void writeCanonicalGraphExpressionString(ValueNode node, boolean checkConstants, boolean removeIdentities, PrintWriter writer) {
+        writer.print(node.getClass().getSimpleName());
+        writer.print("(");
+        Fields properties = node.getNodeClass().getData();
+        for (int i = 0; i < properties.getCount(); i++) {
+            String dataStr = String.valueOf(properties.get(node, i));
+            if (removeIdentities) {
+                dataStr = removeIdentities(dataStr);
+            }
+            writer.print(dataStr);
+            if (i + 1 < properties.getCount() || node.inputPositions().iterator().hasNext()) {
+                writer.print(", ");
+            }
+        }
+        Iterator<Position> iterator = node.inputPositions().iterator();
+        while (iterator.hasNext()) {
+            Position position = iterator.next();
+            Node input = position.get(node);
+            if (checkConstants && input instanceof ConstantNode) {
+                ConstantNode constantNode = (ConstantNode) input;
+                String valueString = constantNode.getValue().toValueString();
+                if (removeIdentities) {
+                    valueString = removeIdentities(valueString);
+                }
+                writer.print(valueString);
+            } else if (input instanceof ValueNode && !(input instanceof PhiNode) && !(input instanceof FixedNode)) {
+                writeCanonicalGraphExpressionString((ValueNode) input, checkConstants, removeIdentities, writer);
+            } else if (input == null) {
+                writer.print("null");
+            } else {
+                writer.print(input.getClass().getSimpleName());
+            }
+            if (iterator.hasNext()) {
+                writer.print(", ");
+            }
+        }
+        writer.print(")");
+    }
+
+    protected static void writeCanonicalExpressionCFGString(StructuredGraph graph, boolean checkConstants, boolean removeIdentities, PrintWriter writer) {
+        ControlFlowGraph controlFlowGraph = ControlFlowGraph.compute(graph, true, true, false, false);
+        for (Block block : controlFlowGraph.getBlocks()) {
+            writer.print("Block ");
+            writer.print(block);
+            writer.print(" ");
+            if (block == controlFlowGraph.getStartBlock()) {
+                writer.print("* ");
+            }
+            writer.print("-> ");
+            for (Block successor : block.getSuccessors()) {
+                writer.print(successor);
+                writer.print(" ");
+            }
+            writer.println();
+            FixedNode node = block.getBeginNode();
+            while (node != null) {
+                writeCanonicalGraphExpressionString(node, checkConstants, removeIdentities, writer);
+                writer.println();
+                if (node instanceof FixedWithNextNode) {
+                    node = ((FixedWithNextNode) node).next();
+                } else {
+                    node = null;
+                }
+            }
+        }
+    }
+
+    protected static void writeCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants, PrintWriter writer) {
+        SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        StructuredGraph.ScheduleResult scheduleResult = graph.getLastSchedule();
+
+        NodeMap<Integer> canonicalId = graph.createNodeMap();
+        int nextId = 0;
+
+        List<String> constantsLines = null;
+        if (checkConstants) {
+            constantsLines = new ArrayList<>();
+        }
+
+        for (Block block : scheduleResult.getCFG().getBlocks()) {
+            writer.print("Block ");
+            writer.print(block);
+            writer.print(" ");
+            if (block == scheduleResult.getCFG().getStartBlock()) {
+                writer.print("* ");
+            }
+            writer.print("-> ");
+            for (Block successor : block.getSuccessors()) {
+                writer.print(successor);
+                writer.print(" ");
+            }
+            writer.println();
+            for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
+                if (node instanceof ValueNode && node.isAlive()) {
+                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) {
+                        if (node instanceof ConstantNode) {
+                            if (constantsLines != null) {
+                                String name = node.toString(Verbosity.Name);
+                                String str = name + (excludeVirtual ? "" : "    (" + filteredUsageCount(node) + ")");
+                                constantsLines.add(str);
+                            }
+                        } else {
+                            int id;
+                            if (canonicalId.get(node) != null) {
+                                id = canonicalId.get(node);
+                            } else {
+                                id = nextId++;
+                                canonicalId.set(node, id);
+                            }
+                            String name = node.getClass().getSimpleName();
+                            writer.print("  ");
+                            writer.print(id);
+                            writer.print("|");
+                            writer.print(name);
+                            if (!excludeVirtual) {
+                                writer.print("    (");
+                                writer.print(filteredUsageCount(node));
+                                writer.print(")");
+                            }
+                            writer.println();
+                        }
+                    }
+                }
+            }
+        }
+        if (constantsLines != null) {
+            writer.print(constantsLines.size());
+            writer.println(" constants:");
+            Collections.sort(constantsLines);
+            for (String s : constantsLines) {
+                writer.println(s);
+            }
+        }
+    }
+
+    public static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(stringWriter);
+        writeCanonicalGraphString(graph, excludeVirtual, checkConstants, writer);
+        writer.flush();
+        return stringWriter.toString();
+    }
+
+    private static int filteredUsageCount(Node node) {
+        return node.usages().filter(n -> !(n instanceof FrameState)).count();
+    }
+
+    @Override
+    public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
+        currentDirectory = currentDirectory.resolve(escapeFileName(name));
+    }
+
+    @Override
+    public void print(Graph graph, String title, Map<Object, Object> properties) throws IOException {
+        if (graph instanceof StructuredGraph) {
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            currentDirectory.toFile().mkdirs();
+            if (this.root != null) {
+                TTY.println("Dumping string graphs in %s", this.root);
+                this.root = null;
+            }
+            Path filePath = currentDirectory.resolve(escapeFileName(title));
+            try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filePath.toFile())))) {
+                switch (PrintCanonicalGraphStringFlavor.getValue()) {
+                    case 1:
+                        writeCanonicalExpressionCFGString(structuredGraph, CanonicalGraphStringsCheckConstants.getValue(), CanonicalGraphStringsRemoveIdentities.getValue(), writer);
+                        break;
+                    case 0:
+                    default:
+                        writeCanonicalGraphString(structuredGraph, CanonicalGraphStringsExcludeVirtuals.getValue(), CanonicalGraphStringsCheckConstants.getValue(), writer);
+                        break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void endGroup() throws IOException {
+        currentDirectory = currentDirectory.getParent();
+        assert currentDirectory != null;
+    }
+
+    @Override
+    public void close() {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java
new file mode 100644
index 0000000..6b5e735
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.LogStream;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.lir.util.IndexedValueMap;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.ReferenceMap;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.MetaUtil;
+
+/**
+ * Utility for printing compilation related data structures at various compilation phases. The
+ * output format is such that it can then be fed to the
+ * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>.
+ */
+public class CompilationPrinter implements Closeable {
+
+    public static final String COLUMN_END = " <|@";
+    public static final String HOVER_START = "<@";
+    public static final String HOVER_SEP = "|@";
+    public static final String HOVER_END = ">@";
+
+    private static OutputStream globalOut;
+
+    /**
+     * Gets a global output stream on a file in the current working directory. This stream is first
+     * opened if necessary. The name of the file is
+     * {@code "compilations-" + System.currentTimeMillis() + ".cfg"}.
+     *
+     * @return the global output stream or {@code null} if there was an error opening the file for
+     *         writing
+     */
+    public static synchronized OutputStream globalOut() {
+        if (globalOut == null) {
+            File file = new File("compilations-" + System.currentTimeMillis() + ".cfg");
+            try {
+                globalOut = new FileOutputStream(file);
+            } catch (FileNotFoundException e) {
+                TTY.println("WARNING: Could not open " + file.getAbsolutePath());
+            }
+        }
+        return globalOut;
+    }
+
+    protected final LogStream out;
+
+    /**
+     * Creates a control flow graph printer.
+     *
+     * @param os where the output generated via this printer will be sent
+     */
+    public CompilationPrinter(OutputStream os) {
+        out = new LogStream(os);
+    }
+
+    /**
+     * Flushes all buffered output to the underlying output stream.
+     */
+    public void flush() {
+        out.flush();
+    }
+
+    @Override
+    public void close() {
+        out.out().close();
+    }
+
+    protected void begin(String string) {
+        out.println("begin_" + string);
+        out.adjustIndentation(2);
+    }
+
+    protected void end(String string) {
+        out.adjustIndentation(-2);
+        out.println("end_" + string);
+    }
+
+    /**
+     * Prints a compilation timestamp for a given method.
+     *
+     * @param method the method for which a timestamp will be printed
+     */
+    public void printCompilation(JavaMethod method) {
+        begin("compilation");
+        out.print("name \" ").print(method.format("%H::%n")).println('"');
+        out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
+        out.print("date ").println(System.currentTimeMillis());
+        end("compilation");
+    }
+
+    /**
+     * Formats given debug info as a multi line string.
+     */
+    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
+        StringBuilder sb = new StringBuilder();
+        if (refMap != null) {
+            sb.append("reference-map: ");
+            sb.append(refMap.toString());
+            sb.append("\n");
+        }
+        if (liveBasePointers != null) {
+            sb.append("live-base-pointers: ");
+            sb.append(liveBasePointers);
+            sb.append("\n");
+        }
+
+        if (calleeSaveInfo != null) {
+            sb.append("callee-save-info:");
+            for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
+                sb.append(" " + e.getKey() + " -> s" + e.getValue());
+            }
+            sb.append("\n");
+        }
+
+        if (codePos != null) {
+            BytecodePosition curCodePos = codePos;
+            List<VirtualObject> virtualObjects = new ArrayList<>();
+            do {
+                sb.append(MetaUtil.toLocation(curCodePos.getMethod(), curCodePos.getBCI()));
+                sb.append('\n');
+                if (curCodePos instanceof BytecodeFrame) {
+                    BytecodeFrame frame = (BytecodeFrame) curCodePos;
+                    if (frame.numStack > 0) {
+                        sb.append("stack: ");
+                        for (int i = 0; i < frame.numStack; i++) {
+                            sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' ');
+                        }
+                        sb.append("\n");
+                    }
+                    sb.append("locals: ");
+                    for (int i = 0; i < frame.numLocals; i++) {
+                        sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).append(' ');
+                    }
+                    sb.append("\n");
+                    if (frame.numLocks > 0) {
+                        sb.append("locks: ");
+                        for (int i = 0; i < frame.numLocks; ++i) {
+                            sb.append(valueToString(frame.getLockValue(i), virtualObjects)).append(' ');
+                        }
+                        sb.append("\n");
+                    }
+
+                }
+                curCodePos = curCodePos.getCaller();
+            } while (curCodePos != null);
+
+            for (int i = 0; i < virtualObjects.size(); i++) {
+                VirtualObject obj = virtualObjects.get(i);
+                sb.append(obj).append(" ").append(obj.getType().getName()).append(" ");
+                for (int j = 0; j < obj.getValues().length; j++) {
+                    sb.append(valueToString(obj.getValues()[j], virtualObjects)).append(' ');
+                }
+                sb.append("\n");
+
+            }
+        }
+        return sb.toString();
+    }
+
+    protected String valueToString(JavaValue value, List<VirtualObject> virtualObjects) {
+        if (value == null) {
+            return "-";
+        }
+        if (value instanceof VirtualObject && !virtualObjects.contains(value)) {
+            virtualObjects.add((VirtualObject) value);
+        }
+        return value.toString();
+    }
+
+    public void printMachineCode(String code, String label) {
+        if (code == null || code.length() == 0) {
+            return;
+        }
+        if (label != null) {
+            begin("cfg");
+            out.print("name \"").print(label).println('"');
+            end("cfg");
+        }
+        begin("nmethod");
+        out.print(code);
+        out.println(" <|@");
+        end("nmethod");
+    }
+
+    public void printBytecodes(String code) {
+        if (code == null || code.length() == 0) {
+            return;
+        }
+        begin("bytecodes");
+        out.print(code);
+        out.println(" <|@");
+        end("bytecodes");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugConfigCustomizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugConfigCustomizer.java
new file mode 100644
index 0000000..fdd1393
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugConfigCustomizer.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugConfigCustomizer;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.UniquePathUtilities;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+@ServiceProvider(DebugConfigCustomizer.class)
+public class GraalDebugConfigCustomizer implements DebugConfigCustomizer {
+
+    private SnippetReflectionProvider snippetReflection;
+
+    @Override
+    public void customize(DebugConfig config, Object... extraArgs) {
+        snippetReflection = DebugConfigCustomizer.lookupArg(SnippetReflectionProvider.class, extraArgs);
+        if (Options.PrintIdealGraphFile.getValue()) {
+            config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createFilePrinter));
+        } else {
+            config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createNetworkPrinter));
+        }
+        if (Options.PrintCanonicalGraphStrings.getValue()) {
+            config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createStringPrinter));
+        }
+        config.dumpHandlers().add(new NodeDumper());
+        if (Options.PrintCFG.getValue() || Options.PrintBackendCFG.getValue()) {
+            if (Options.PrintBinaryGraphs.getValue() && Options.PrintCFG.getValue()) {
+                TTY.out.println("Complete C1Visualizer dumping slows down PrintBinaryGraphs: use -Dgraal.PrintCFG=false to disable it");
+            }
+            config.dumpHandlers().add(new CFGPrinterObserver(Options.PrintCFG.getValue()));
+        }
+        config.verifyHandlers().add(new NoDeadCodeVerifyHandler());
+    }
+
+    private static class NodeDumper implements DebugDumpHandler {
+        @Override
+        public void dump(Object object, String message) {
+            if (object instanceof Node) {
+                String location = GraphUtil.approxSourceLocation((Node) object);
+                String node = ((Node) object).toString(Verbosity.Debugger);
+                if (location != null) {
+                    Debug.log("Context obj %s (approx. location: %s)", node, location);
+                } else {
+                    Debug.log("Context obj %s", node);
+                }
+            }
+        }
+
+        @Override
+        public void close() {
+        }
+    }
+
+    private CanonicalStringGraphPrinter createStringPrinter() {
+        // Construct the path to the directory.
+        Path path = UniquePathUtilities.getPath(Options.PrintCanonicalGraphStringsDirectory, Options.DumpPath, "");
+        return new CanonicalStringGraphPrinter(path, snippetReflection);
+    }
+
+    private GraphPrinter createNetworkPrinter() throws IOException {
+        String host = Options.PrintIdealGraphAddress.getValue();
+        int port = Options.PrintBinaryGraphs.getValue() ? Options.PrintBinaryGraphPort.getValue() : Options.PrintIdealGraphPort.getValue();
+        try {
+            GraphPrinter printer;
+            if (Options.PrintBinaryGraphs.getValue()) {
+                printer = new BinaryGraphPrinter(SocketChannel.open(new InetSocketAddress(host, port)), snippetReflection);
+            } else {
+                printer = new IdealGraphPrinter(new Socket(host, port).getOutputStream(), true, snippetReflection);
+            }
+            TTY.println("Connected to the IGV on %s:%d", host, port);
+            return printer;
+        } catch (ClosedByInterruptException | InterruptedIOException e) {
+            /*
+             * Interrupts should not count as errors because they may be caused by a cancelled Graal
+             * compilation. ClosedByInterruptException occurs if the SocketChannel could not be
+             * opened. InterruptedIOException occurs if new Socket(..) was interrupted.
+             */
+            return null;
+        } catch (IOException e) {
+            throw new IOException(String.format("Could not connect to the IGV on %s:%d", host, port), e);
+        }
+    }
+
+    private static Path getFilePrinterPath() {
+        // Construct the path to the file.
+        return UniquePathUtilities.getPath(Options.PrintIdealGraphFileName, Options.DumpPath, Options.PrintBinaryGraphs.getValue() ? "bgv" : "gv.xml");
+    }
+
+    private GraphPrinter createFilePrinter() throws IOException {
+        Path path = getFilePrinterPath();
+        try {
+            GraphPrinter printer;
+            if (Options.PrintBinaryGraphs.getValue()) {
+                printer = new BinaryGraphPrinter(FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW), snippetReflection);
+            } else {
+                printer = new IdealGraphPrinter(Files.newOutputStream(path), true, snippetReflection);
+            }
+            TTY.println("Dumping IGV graphs to %s", path.toString());
+            return printer;
+        } catch (IOException e) {
+            throw new IOException(String.format("Failed to open %s to dump IGV graphs", path), e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java
new file mode 100644
index 0000000..6ef7a61
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.util.ModuleAPI;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.nodes.ConstantNode;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaUtil;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.services.Services;
+
+interface GraphPrinter extends Closeable {
+
+    /**
+     * Starts a new group of graphs with the given name, short name and method byte code index (BCI)
+     * as properties.
+     */
+    void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException;
+
+    /**
+     * Prints an entire {@link Graph} with the specified title, optionally using short names for
+     * nodes.
+     */
+    void print(Graph graph, String title, Map<Object, Object> properties) throws IOException;
+
+    SnippetReflectionProvider getSnippetReflectionProvider();
+
+    /**
+     * Ends the current group.
+     */
+    void endGroup() throws IOException;
+
+    @Override
+    void close();
+
+    /**
+     * A JVMCI package {@linkplain Services#exportJVMCITo(Class) dynamically exported} to trusted
+     * modules.
+     */
+    String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName();
+
+    /**
+     * {@code jdk.vm.ci} module.
+     */
+    Object JVMCI_MODULE = JAVA_SPECIFICATION_VERSION < 9 ? null : ModuleAPI.getModule.invoke(Services.class);
+
+    /**
+     * Classes whose {@link #toString()} method does not run any untrusted code.
+     */
+    Set<Class<?>> TRUSTED_CLASSES = new HashSet<>(Arrays.asList(
+                    String.class,
+                    Class.class,
+                    Boolean.class,
+                    Byte.class,
+                    Character.class,
+                    Short.class,
+                    Integer.class,
+                    Float.class,
+                    Long.class,
+                    Double.class));
+    int MAX_CONSTANT_TO_STRING_LENGTH = 50;
+
+    /**
+     * Determines if invoking {@link Object#toString()} on an instance of {@code c} will only run
+     * trusted code.
+     */
+    static boolean isToStringTrusted(Class<?> c) {
+        if (TRUSTED_CLASSES.contains(c)) {
+            return true;
+        }
+        if (JAVA_SPECIFICATION_VERSION < 9) {
+            if (c.getClassLoader() == Services.class.getClassLoader()) {
+                // Loaded by the JVMCI class loader
+                return true;
+            }
+        } else {
+            Object module = ModuleAPI.getModule.invoke(c);
+            if (JVMCI_MODULE == module || (Boolean) ModuleAPI.isExportedTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
+                // Can access non-statically-exported package in JVMCI
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets or updates the {@code "rawvalue"} and {@code "toString"} properties in {@code props} for
+     * {@code cn} if it's a boxed Object value and {@code snippetReflection} can access the raw
+     * value.
+     */
+    default void updateStringPropertiesForConstant(Map<Object, Object> props, ConstantNode cn) {
+        SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider();
+        if (snippetReflection != null && cn.getValue() instanceof JavaConstant) {
+            JavaConstant constant = (JavaConstant) cn.getValue();
+            if (constant.getJavaKind() == JavaKind.Object) {
+                Object obj = snippetReflection.asObject(Object.class, constant);
+                if (obj != null) {
+                    String toString = GraphPrinter.constantToString(obj);
+                    String rawvalue = GraphPrinter.truncate(toString);
+                    // Overwrite the value inserted by
+                    // ConstantNode.getDebugProperties()
+                    props.put("rawvalue", rawvalue);
+                    if (!rawvalue.equals(toString)) {
+                        props.put("toString", toString);
+                    }
+                }
+            }
+        }
+    }
+
+    static String truncate(String s) {
+        if (s.length() > MAX_CONSTANT_TO_STRING_LENGTH) {
+            return s.substring(0, MAX_CONSTANT_TO_STRING_LENGTH - 3) + "...";
+        }
+        return s;
+    }
+
+    static String constantToString(Object value) {
+        Class<?> c = value.getClass();
+        if (c.isArray()) {
+            return constantArrayToString(value);
+        } else if (value instanceof Enum) {
+            return ((Enum<?>) value).name();
+        } else if (isToStringTrusted(c)) {
+            return value.toString();
+        }
+        return MetaUtil.getSimpleName(c, true) + "@" + System.identityHashCode(value);
+
+    }
+
+    static String constantArrayToString(Object array) {
+        Class<?> componentType = array.getClass().getComponentType();
+        assert componentType != null;
+        int arrayLength = Array.getLength(array);
+        StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{");
+        int length = arrayLength;
+        boolean primitive = componentType.isPrimitive();
+        for (int i = 0; i < length; i++) {
+            if (primitive) {
+                buf.append(Array.get(array, i));
+            } else {
+                Object o = ((Object[]) array)[i];
+                buf.append(o == null ? "null" : constantToString(o));
+            }
+            if (i != length - 1) {
+                buf.append(", ");
+            }
+        }
+        return buf.append('}').toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java
new file mode 100644
index 0000000..6d1e6df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.asJavaMethod;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+//JaCoCo Exclude
+
+/**
+ * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation
+ * that can be inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>
+ * .
+ */
+public class GraphPrinterDumpHandler implements DebugDumpHandler {
+
+    private final GraphPrinterSupplier printerSupplier;
+    protected GraphPrinter printer;
+    private List<String> previousInlineContext;
+    private int[] dumpIds = {};
+    private int failuresCount;
+    private Map<Graph, List<String>> inlineContextMap;
+    private final String jvmArguments;
+    private final String sunJavaCommand;
+
+    @FunctionalInterface
+    public interface GraphPrinterSupplier {
+        GraphPrinter get() throws IOException;
+    }
+
+    /**
+     * Creates a new {@link GraphPrinterDumpHandler}.
+     *
+     * @param printerSupplier Supplier used to create the GraphPrinter. Should supply an optional or
+     *            null in case of failure.
+     */
+    public GraphPrinterDumpHandler(GraphPrinterSupplier printerSupplier) {
+        this.printerSupplier = printerSupplier;
+        /* Add the JVM and Java arguments to the graph properties to help identify it. */
+        this.jvmArguments = String.join(" ", ManagementFactory.getRuntimeMXBean().getInputArguments());
+        this.sunJavaCommand = System.getProperty("sun.java.command");
+    }
+
+    private void ensureInitialized() {
+        if (printer == null) {
+            if (failuresCount > 8) {
+                return;
+            }
+            previousInlineContext = new ArrayList<>();
+            inlineContextMap = new WeakHashMap<>();
+            try {
+                printer = printerSupplier.get();
+            } catch (IOException e) {
+                TTY.println(e.getMessage());
+                failuresCount++;
+            }
+        }
+    }
+
+    private int nextDumpId() {
+        int depth = previousInlineContext.size();
+        if (dumpIds.length < depth) {
+            dumpIds = Arrays.copyOf(dumpIds, depth);
+        }
+        return dumpIds[depth - 1]++;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public void dump(Object object, final String message) {
+        if (object instanceof Graph && Options.PrintIdealGraph.getValue()) {
+            ensureInitialized();
+            if (printer == null) {
+                return;
+            }
+            final Graph graph = (Graph) object;
+
+            // Get all current JavaMethod instances in the context.
+            List<String> inlineContext = getInlineContext(graph);
+
+            if (inlineContext != previousInlineContext) {
+                Map<Object, Object> properties = new HashMap<>();
+                properties.put("graph", graph.toString());
+                addCompilationId(properties, graph);
+                addCFGFileName(properties);
+                if (inlineContext.equals(previousInlineContext)) {
+                    /*
+                     * two different graphs have the same inline context, so make sure they appear
+                     * in different folders by closing and reopening the top scope.
+                     */
+                    int inlineDepth = previousInlineContext.size() - 1;
+                    closeScope(inlineDepth);
+                    openScope(inlineContext.get(inlineDepth), inlineDepth, properties);
+                } else {
+                    // Check for method scopes that must be closed since the previous dump.
+                    for (int i = 0; i < previousInlineContext.size(); ++i) {
+                        if (i >= inlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
+                            for (int inlineDepth = previousInlineContext.size() - 1; inlineDepth >= i; --inlineDepth) {
+                                closeScope(inlineDepth);
+                            }
+                            break;
+                        }
+                    }
+                    // Check for method scopes that must be opened since the previous dump.
+                    for (int i = 0; i < inlineContext.size(); ++i) {
+                        if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
+                            for (int inlineDepth = i; inlineDepth < inlineContext.size(); ++inlineDepth) {
+                                openScope(inlineContext.get(inlineDepth), inlineDepth, inlineDepth == inlineContext.size() - 1 ? properties : null);
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // Save inline context for next dump.
+            previousInlineContext = inlineContext;
+
+            try (Scope s = Debug.sandbox("PrintingGraph", null)) {
+                // Finally, output the graph.
+                Map<Object, Object> properties = new HashMap<>();
+                properties.put("graph", graph.toString());
+                properties.put("scope", Debug.currentScope());
+                addCFGFileName(properties);
+                printer.print(graph, nextDumpId() + ":" + message, properties);
+            } catch (IOException e) {
+                failuresCount++;
+                printer = null;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+    }
+
+    private static void addCompilationId(Map<Object, Object> properties, final Graph graph) {
+        if (graph instanceof StructuredGraph) {
+            properties.put("compilationId", ((StructuredGraph) graph).compilationId());
+        }
+    }
+
+    private static void addCFGFileName(Map<Object, Object> properties) {
+        if (Options.PrintCFG.getValue() || Options.PrintBackendCFG.getValue()) {
+            properties.put("PrintCFGFileName", CFGPrinterObserver.getCFGPath().toAbsolutePath().toString());
+        }
+    }
+
+    private List<String> getInlineContext(Graph graph) {
+        List<String> result = inlineContextMap.get(graph);
+        if (result == null) {
+            result = new ArrayList<>();
+            Object lastMethodOrGraph = null;
+            boolean graphSeen = false;
+            for (Object o : Debug.context()) {
+                if (o == graph) {
+                    graphSeen = true;
+                }
+
+                if (o instanceof DebugDumpScope) {
+                    DebugDumpScope debugDumpScope = (DebugDumpScope) o;
+                    if (debugDumpScope.decorator && !result.isEmpty()) {
+                        result.set(result.size() - 1, debugDumpScope.name + ":" + result.get(result.size() - 1));
+                    } else {
+                        result.add(debugDumpScope.name);
+                    }
+                } else {
+                    addMethodContext(result, o, lastMethodOrGraph);
+                }
+                if (o instanceof JavaMethod || o instanceof Graph) {
+                    lastMethodOrGraph = o;
+                }
+            }
+
+            if (result.isEmpty()) {
+                result.add(graph.toString());
+                graphSeen = true;
+            }
+            // Reverse list such that inner method comes after outer method.
+            Collections.reverse(result);
+            if (!graphSeen) {
+                /*
+                 * The graph isn't in any context but is being processed within another graph so add
+                 * it to the end of the scopes.
+                 */
+                if (asJavaMethod(graph) != null) {
+                    addMethodContext(result, graph, lastMethodOrGraph);
+                } else {
+                    result.add(graph.toString());
+                }
+            }
+            inlineContextMap.put(graph, result);
+        }
+        return result;
+    }
+
+    private static void addMethodContext(List<String> result, Object o, Object lastMethodOrGraph) {
+        JavaMethod method = asJavaMethod(o);
+        if (method != null) {
+            /*
+             * Include the current method in the context if there was no previous JavaMethod or
+             * JavaMethodContext or if the method is different or if the method is the same but it
+             * comes from two different graphs. This ensures that recursive call patterns are
+             * handled properly.
+             */
+            if (lastMethodOrGraph == null || asJavaMethod(lastMethodOrGraph) == null || !asJavaMethod(lastMethodOrGraph).equals(method) ||
+                            (lastMethodOrGraph != o && lastMethodOrGraph instanceof Graph && o instanceof Graph)) {
+                result.add(method.format("%H::%n(%p)"));
+            } else {
+                /*
+                 * This prevents multiple adjacent method context objects for the same method from
+                 * resulting in multiple IGV tree levels. This works on the assumption that real
+                 * inlining debug scopes will have a graph context object between the inliner and
+                 * inlinee context objects.
+                 */
+            }
+        }
+    }
+
+    private void openScope(String name, int inlineDepth, Map<Object, Object> properties) {
+        String prefix = inlineDepth == 0 ? Thread.currentThread().getName() + ":" : "";
+        try {
+            Map<Object, Object> props = properties;
+            if (inlineDepth == 0) {
+                /* Include some VM specific properties at the root. */
+                if (props == null) {
+                    props = new HashMap<>();
+                }
+                props.put("jvmArguments", jvmArguments);
+                if (sunJavaCommand != null) {
+                    props.put("sun.java.command", sunJavaCommand);
+                }
+                props.put("date", new Date().toString());
+            }
+            printer.beginGroup(prefix + name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1, props);
+        } catch (IOException e) {
+            failuresCount++;
+            printer = null;
+        }
+    }
+
+    private void closeScope(int inlineDepth) {
+        dumpIds[inlineDepth] = 0;
+        try {
+            printer.endGroup();
+        } catch (IOException e) {
+            failuresCount++;
+            printer = null;
+        }
+    }
+
+    @Override
+    public void close() {
+        if (previousInlineContext != null) {
+            for (int inlineDepth = 0; inlineDepth < previousInlineContext.size(); inlineDepth++) {
+                closeScope(inlineDepth);
+            }
+        }
+        if (printer != null) {
+            printer.close();
+            printer = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java
new file mode 100644
index 0000000..e6548a2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the
+ * <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
+ */
+public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter {
+
+    private final boolean tryToSchedule;
+    private final SnippetReflectionProvider snippetReflection;
+
+    /**
+     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     *
+     * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for
+     *            non-schedulable graphs.
+     */
+    public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule, SnippetReflectionProvider snippetReflection) {
+        super(stream);
+        this.begin();
+        this.tryToSchedule = tryToSchedule;
+        this.snippetReflection = snippetReflection;
+    }
+
+    @Override
+    public SnippetReflectionProvider getSnippetReflectionProvider() {
+        return snippetReflection;
+    }
+
+    /**
+     * Starts a new group of graphs with the given name, short name and method byte code index (BCI)
+     * as properties.
+     */
+    @Override
+    public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) {
+        beginGroup();
+        beginProperties();
+        printProperty("name", name);
+        if (properties != null) {
+            for (Entry<Object, Object> entry : properties.entrySet()) {
+                printProperty(entry.getKey().toString(), entry.getValue().toString());
+            }
+        }
+        endProperties();
+        beginMethod(name, shortName, bci);
+        if (method != null && method.getCode() != null) {
+            printBytecodes(new BytecodeDisassembler(false).disassemble(method));
+        }
+        endMethod();
+    }
+
+    /**
+     * Prints an entire {@link Graph} with the specified title, optionally using short names for
+     * nodes.
+     */
+    @Override
+    public void print(Graph graph, String title, Map<Object, Object> properties) {
+        beginGraph(title);
+        Set<Node> noBlockNodes = Node.newSet();
+        ScheduleResult schedule = null;
+        if (graph instanceof StructuredGraph) {
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            schedule = structuredGraph.getLastSchedule();
+            if (schedule == null && tryToSchedule) {
+                if (Options.PrintIdealGraphSchedule.getValue()) {
+                    try {
+                        SchedulePhase schedulePhase = new SchedulePhase();
+                        schedulePhase.apply(structuredGraph);
+                        schedule = structuredGraph.getLastSchedule();
+                    } catch (Throwable t) {
+                    }
+                }
+            }
+        }
+        ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
+
+        if (properties != null) {
+            beginProperties();
+            for (Entry<Object, Object> entry : properties.entrySet()) {
+                printProperty(entry.getKey().toString(), entry.getValue().toString());
+            }
+            endProperties();
+        }
+
+        beginNodes();
+        List<Edge> edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes);
+        endNodes();
+
+        beginEdges();
+        for (Edge edge : edges) {
+            printEdge(edge);
+        }
+        endEdges();
+
+        if (cfg != null && cfg.getBlocks() != null) {
+            beginControlFlow();
+            for (Block block : cfg.getBlocks()) {
+                printBlock(graph, block, cfg.getNodeToBlock());
+            }
+            printNoBlock(noBlockNodes);
+            endControlFlow();
+        }
+
+        endGraph();
+        flush();
+    }
+
+    private List<Edge> printNodes(Graph graph, NodeMap<Block> nodeToBlock, Set<Node> noBlockNodes) {
+        ArrayList<Edge> edges = new ArrayList<>();
+
+        NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap();
+        NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap();
+        NodeMap<Set<String>> bits = graph.createNodeMap();
+
+        for (Node node : graph.getNodes()) {
+
+            beginNode(node.toString(Verbosity.Id));
+            beginProperties();
+            printProperty("idx", node.toString(Verbosity.Id));
+
+            Map<Object, Object> props = node.getDebugProperties();
+            if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) {
+                String name = node.toString(Verbosity.Name);
+                printProperty("name", name);
+            }
+            printProperty("class", node.getClass().getSimpleName());
+
+            Block block = nodeToBlock == null || nodeToBlock.isNew(node) ? null : nodeToBlock.get(node);
+            if (block != null) {
+                printProperty("block", Integer.toString(block.getId()));
+                // if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof
+                // ParameterNode) && !block.nodes().contains(node)) {
+                // printProperty("notInOwnBlock", "true");
+                // }
+            } else {
+                printProperty("block", "noBlock");
+                noBlockNodes.add(node);
+            }
+
+            Set<Entry<String, Integer>> nodeColors = colors.get(node);
+            if (nodeColors != null) {
+                for (Entry<String, Integer> color : nodeColors) {
+                    String name = color.getKey();
+                    Integer value = color.getValue();
+                    printProperty(name, Integer.toString(value));
+                }
+            }
+            Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
+            if (nodeColorStrings != null) {
+                for (Entry<String, String> color : nodeColorStrings) {
+                    String name = color.getKey();
+                    String value = color.getValue();
+                    printProperty(name, value);
+                }
+            }
+            Set<String> nodeBits = bits.get(node);
+            if (nodeBits != null) {
+                for (String bit : nodeBits) {
+                    printProperty(bit, "true");
+                }
+            }
+            if (node instanceof BeginNode) {
+                printProperty("shortName", "B");
+            } else if (node.getClass() == EndNode.class) {
+                printProperty("shortName", "E");
+            } else if (node instanceof ConstantNode) {
+                ConstantNode cn = (ConstantNode) node;
+                updateStringPropertiesForConstant(props, cn);
+            }
+            if (node.predecessor() != null) {
+                printProperty("hasPredecessor", "true");
+            }
+
+            for (Entry<Object, Object> entry : props.entrySet()) {
+                String key = entry.getKey().toString();
+                Object value = entry.getValue();
+                String valueString;
+                if (value == null) {
+                    valueString = "null";
+                } else {
+                    Class<?> type = value.getClass();
+                    if (type.isArray()) {
+                        if (!type.getComponentType().isPrimitive()) {
+                            valueString = Arrays.toString((Object[]) value);
+                        } else if (type.getComponentType() == Integer.TYPE) {
+                            valueString = Arrays.toString((int[]) value);
+                        } else if (type.getComponentType() == Double.TYPE) {
+                            valueString = Arrays.toString((double[]) value);
+                        } else {
+                            valueString = toString();
+                        }
+                    } else {
+                        valueString = value.toString();
+                    }
+                }
+                printProperty(key, valueString);
+            }
+
+            endProperties();
+            endNode();
+
+            // successors
+            int fromIndex = 0;
+            for (Position position : node.successorPositions()) {
+                Node successor = position.get(node);
+                if (successor != null) {
+                    edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, position.getName()));
+                }
+                fromIndex++;
+            }
+
+            // inputs
+            int toIndex = 1;
+            for (Position position : node.inputPositions()) {
+                Node input = position.get(node);
+                if (input != null) {
+                    edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, position.getName()));
+                }
+                toIndex++;
+            }
+        }
+
+        return edges;
+    }
+
+    private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) {
+        beginBlock(Integer.toString(block.getId()));
+        beginSuccessors();
+        for (Block sux : block.getSuccessors()) {
+            if (sux != null) {
+                printSuccessor(Integer.toString(sux.getId()));
+            }
+        }
+        endSuccessors();
+        beginBlockNodes();
+
+        Set<Node> nodes = Node.newSet();
+
+        if (nodeToBlock != null) {
+            for (Node n : graph.getNodes()) {
+                Block blk = nodeToBlock.isNew(n) ? null : nodeToBlock.get(n);
+                if (blk == block) {
+                    nodes.add(n);
+                }
+            }
+        }
+
+        if (nodes.size() > 0) {
+            // if this is the first block: add all locals to this block
+            if (block.getBeginNode() == ((StructuredGraph) graph).start()) {
+                for (Node node : graph.getNodes()) {
+                    if (node instanceof ParameterNode) {
+                        nodes.add(node);
+                    }
+                }
+            }
+
+            Set<Node> snapshot = Node.newSet(nodes);
+            // add all framestates and phis to their blocks
+            for (Node node : snapshot) {
+                if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
+                    nodes.add(((StateSplit) node).stateAfter());
+                }
+                if (node instanceof AbstractMergeNode) {
+                    for (PhiNode phi : ((AbstractMergeNode) node).phis()) {
+                        nodes.add(phi);
+                    }
+                }
+            }
+
+            for (Node node : nodes) {
+                printBlockNode(node.toString(Verbosity.Id));
+            }
+        }
+        endBlockNodes();
+        endBlock();
+    }
+
+    private void printNoBlock(Set<Node> noBlockNodes) {
+        if (!noBlockNodes.isEmpty()) {
+            beginBlock("noBlock");
+            beginBlockNodes();
+            for (Node node : noBlockNodes) {
+                printBlockNode(node.toString(Verbosity.Id));
+            }
+            endBlockNodes();
+            endBlock();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/NoDeadCodeVerifyHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/NoDeadCodeVerifyHandler.java
new file mode 100644
index 0000000..bae951e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/NoDeadCodeVerifyHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.printer;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.graalvm.compiler.debug.DebugVerifyHandler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+
+/**
+ * Verifies that graphs have no dead code.
+ */
+public class NoDeadCodeVerifyHandler implements DebugVerifyHandler {
+
+    // The options below will be removed once all phases clean up their own dead code.
+
+    private static final int OFF = 0;
+    private static final int INFO = 1;
+    private static final int VERBOSE = 2;
+    private static final int FATAL = 3;
+
+    static class Options {
+        // @formatter:off
+        @Option(help = "Run level for NoDeadCodeVerifyHandler (0 = off, 1 = info, 2 = verbose, 3 = fatal)", type = OptionType.Debug)
+        public static final OptionValue<Integer> NDCV = new OptionValue<>(0);
+        // @formatter:on
+    }
+
+    /**
+     * Only the first instance of failure at any point is shown. This will also be removed once all
+     * phases clean up their own dead code.
+     */
+    private static final Map<String, Boolean> discovered = new ConcurrentHashMap<>();
+
+    @Override
+    public void verify(Object object, String message) {
+        if (Options.NDCV.getValue() != OFF && object instanceof StructuredGraph) {
+            StructuredGraph graph = (StructuredGraph) object;
+            List<Node> before = graph.getNodes().snapshot();
+            new DeadCodeEliminationPhase().run(graph);
+            List<Node> after = graph.getNodes().snapshot();
+            assert after.size() <= before.size();
+            if (before.size() != after.size()) {
+                if (discovered.put(message, Boolean.TRUE) == null) {
+                    before.removeAll(after);
+                    String prefix = message == null ? "" : message + ": ";
+                    GraalError error = new GraalError("%sfound dead nodes in %s: %s", prefix, graph, before);
+                    if (Options.NDCV.getValue() == INFO) {
+                        System.out.println(error.getMessage());
+                    } else if (Options.NDCV.getValue() == VERBOSE) {
+                        error.printStackTrace(System.out);
+                    } else {
+                        assert Options.NDCV.getValue() == FATAL;
+                        throw error;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountLeadingZerosNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountLeadingZerosNode.java
new file mode 100644
index 0000000..aaedbb9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountLeadingZerosNode.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.aarch64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_6;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(cycles = CYCLES_6, size = SIZE_1)
+public final class AArch64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<AArch64CountLeadingZerosNode> TYPE = NodeClass.create(AArch64CountLeadingZerosNode.class);
+
+    public AArch64CountLeadingZerosNode(ValueNode value) {
+        super(TYPE, computeStamp(value.stamp(), value), value);
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        return computeStamp(newStamp, getValue());
+    }
+
+    private static Stamp computeStamp(Stamp newStamp, ValueNode theValue) {
+        assert newStamp.isCompatible(theValue.stamp());
+        assert theValue.getStackKind() == JavaKind.Int || theValue.getStackKind() == JavaKind.Long;
+        return StampTool.stampForLeadingZeros((IntegerStamp) newStamp);
+    }
+
+    public static ValueNode tryFold(ValueNode value) {
+        if (value.isConstant()) {
+            JavaConstant c = value.asJavaConstant();
+            if (value.getStackKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Integer.numberOfLeadingZeros(c.asInt()));
+            } else {
+                return ConstantNode.forInt(Long.numberOfLeadingZeros(c.asLong()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, ((AArch64ArithmeticLIRGeneratorTool) gen).emitCountLeadingZeros(builder.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java
new file mode 100644
index 0000000..f52f116
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.replacements.aarch64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.RemNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * AArch64 does not have a remainder operation. We use <code>n % d == n - Truncate(n / d) * d</code>
+ * for it instead. This is not correct for some edge cases, so we have to fix it up using these
+ * snippets.
+ */
+public class AArch64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemplates implements Snippets {
+
+    private final SnippetTemplate.SnippetInfo drem;
+    private final SnippetTemplate.SnippetInfo frem;
+
+    public AArch64FloatArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+        super(providers, snippetReflection, target);
+        drem = snippet(AArch64FloatArithmeticSnippets.class, "dremSnippet");
+        frem = snippet(AArch64FloatArithmeticSnippets.class, "fremSnippet");
+    }
+
+    public void lower(RemNode node, LoweringTool tool) {
+        JavaKind kind = node.stamp().getStackKind();
+        assert kind == JavaKind.Float || kind == JavaKind.Double;
+        if (node instanceof SafeNode) {
+            // We already introduced the necessary checks, nothing to do.
+            return;
+        }
+        SnippetTemplate.SnippetInfo snippet = kind == JavaKind.Float ? frem : drem;
+        StructuredGraph graph = node.graph();
+        Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+        args.add("x", node.getX());
+        args.add("y", node.getY());
+        template(args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args);
+    }
+
+    @Snippet
+    public static float fremSnippet(float x, float y) {
+        // JVMS: If either value1' or value2' is NaN, the result is NaN.
+        // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN.
+        if (Float.isInfinite(x) || y == 0.0f || Float.isNaN(y)) {
+            return Float.NaN;
+        }
+        // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the
+        // dividend.
+        // JVMS: If the dividend is a zero and the divisor is finite, the result equals the
+        // dividend.
+        if (x == 0.0f || Float.isInfinite(y)) {
+            return x;
+        }
+
+        float result = safeRem(x, y);
+
+        // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of
+        // the dividend.
+        if (result == 0.0f && x < 0.0f) {
+            return -result;
+        }
+        return result;
+    }
+
+    @Snippet
+    public static double dremSnippet(double x, double y) {
+        // JVMS: If either value1' or value2' is NaN, the result is NaN.
+        // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN.
+        if (Double.isInfinite(x) || y == 0.0 || Double.isNaN(y)) {
+            return Double.NaN;
+        }
+        // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the
+        // dividend.
+        // JVMS: If the dividend is a zero and the divisor is finite, the result equals the
+        // dividend.
+        if (x == 0.0 || Double.isInfinite(y)) {
+            return x;
+        }
+
+        double result = safeRem(x, y);
+
+        // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of
+        // the dividend.
+        if (result == 0.0 && x < 0.0) {
+            return -result;
+        }
+        return result;
+    }
+
+    @NodeIntrinsic(SafeFloatRemNode.class)
+    private static native float safeRem(float x, float y);
+
+    @NodeIntrinsic(SafeFloatRemNode.class)
+    private static native double safeRem(double x, double y);
+
+    /**
+     * Marker interface to distinguish untreated nodes from ones where we have installed the
+     * additional checks.
+     */
+    private interface SafeNode {
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    // static class SafeFloatRemNode extends FloatRemNode implements SafeNode {
+    static class SafeFloatRemNode extends RemNode implements SafeNode {
+        public static final NodeClass<SafeFloatRemNode> TYPE = NodeClass.create(SafeFloatRemNode.class);
+
+        protected SafeFloatRemNode(ValueNode x, ValueNode y) {
+            super(TYPE, x, y);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java
new file mode 100644
index 0000000..5a1a90a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.aarch64;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class AArch64GraphBuilderPlugins {
+
+    public static void register(Plugins plugins, ForeignCallsProvider foreignCalls, BytecodeProvider bytecodeProvider) {
+        InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
+        invocationPlugins.defer(new Runnable() {
+            @Override
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, AArch64IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider);
+                registerIntegerLongPlugins(invocationPlugins, AArch64LongSubstitutions.class, JavaKind.Long, bytecodeProvider);
+                registerMathPlugins(invocationPlugins, foreignCalls);
+            }
+        });
+    }
+
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, BytecodeProvider bytecodeProvider) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
+        r.register1("numberOfLeadingZeros", type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                ValueNode folded = AArch64CountLeadingZerosNode.tryFold(value);
+                if (folded != null) {
+                    b.addPush(JavaKind.Int, folded);
+                } else {
+                    b.addPush(JavaKind.Int, new AArch64CountLeadingZerosNode(value));
+                }
+                return true;
+            }
+        });
+        r.register1("numberOfTrailingZeros", type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                ValueNode folded = BitScanForwardNode.tryFold(value);
+                if (folded != null) {
+                    b.addPush(JavaKind.Int, folded);
+                } else {
+                    b.addPush(JavaKind.Int, new BitScanForwardNode(value));
+                }
+                return true;
+            }
+        });
+        r.registerMethodSubstitution(substituteDeclaringClass, "bitCount", type);
+    }
+
+    @SuppressWarnings("unused")
+    private static void registerMathPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
+        // Registration r = new Registration(plugins, Math.class);
+        // r.register1("sin", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_SIN));
+        // r.register1("cos", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_COS));
+        // r.register1("tan", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_TAN));
+        // r.register1("exp", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_EXP));
+        // r.register1("log", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_LOG));
+        // r.register1("log10", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_LOG10));
+        // r.register2("pow", Double.TYPE, Double.TYPE, new ForeignCallPlugin(foreignCalls,
+        // ARITHMETIC_POW));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java
new file mode 100644
index 0000000..ed82950
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.replacements.aarch64;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
+import org.graalvm.compiler.nodes.calc.SignedDivNode;
+import org.graalvm.compiler.nodes.calc.SignedRemNode;
+import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
+ * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
+ * forward to the LIRGenerator.
+ */
+public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {
+
+    private final SnippetTemplate.SnippetInfo idiv;
+    private final SnippetTemplate.SnippetInfo ldiv;
+    private final SnippetTemplate.SnippetInfo irem;
+    private final SnippetTemplate.SnippetInfo lrem;
+
+    private final SnippetTemplate.SnippetInfo uidiv;
+    private final SnippetTemplate.SnippetInfo uldiv;
+    private final SnippetTemplate.SnippetInfo uirem;
+    private final SnippetTemplate.SnippetInfo ulrem;
+
+    public AArch64IntegerArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+        super(providers, snippetReflection, target);
+        idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
+        ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
+        irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
+        lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");
+
+        uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
+        uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
+        uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
+        ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
+    }
+
+    public void lower(FixedBinaryNode node, LoweringTool tool) {
+        JavaKind kind = node.stamp().getStackKind();
+        assert kind == JavaKind.Int || kind == JavaKind.Long;
+        SnippetTemplate.SnippetInfo snippet;
+        if (node instanceof SafeNode) {
+            // We already introduced the zero division check, nothing to do.
+            return;
+        } else if (node instanceof SignedDivNode) {
+            snippet = kind == JavaKind.Int ? idiv : ldiv;
+        } else if (node instanceof SignedRemNode) {
+            snippet = kind == JavaKind.Int ? irem : lrem;
+        } else if (node instanceof UnsignedDivNode) {
+            snippet = kind == JavaKind.Int ? uidiv : uldiv;
+        } else if (node instanceof UnsignedRemNode) {
+            snippet = kind == JavaKind.Int ? uirem : ulrem;
+        } else {
+            throw GraalError.shouldNotReachHere();
+        }
+        StructuredGraph graph = node.graph();
+        Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+        args.add("x", node.getX());
+        args.add("y", node.getY());
+        template(args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
+    }
+
+    @Snippet
+    public static int idivSnippet(int x, int y) {
+        checkForZero(y);
+        return safeDiv(x, y);
+    }
+
+    @Snippet
+    public static long ldivSnippet(long x, long y) {
+        checkForZero(y);
+        return safeDiv(x, y);
+    }
+
+    @Snippet
+    public static int iremSnippet(int x, int y) {
+        checkForZero(y);
+        return safeRem(x, y);
+    }
+
+    @Snippet
+    public static long lremSnippet(long x, long y) {
+        checkForZero(y);
+        return safeRem(x, y);
+    }
+
+    @Snippet
+    public static int uidivSnippet(int x, int y) {
+        checkForZero(y);
+        return safeUDiv(x, y);
+    }
+
+    @Snippet
+    public static long uldivSnippet(long x, long y) {
+        checkForZero(y);
+        return safeUDiv(x, y);
+    }
+
+    @Snippet
+    public static int uiremSnippet(int x, int y) {
+        checkForZero(y);
+        return safeURem(x, y);
+    }
+
+    @Snippet
+    public static long ulremSnippet(long x, long y) {
+        checkForZero(y);
+        return safeURem(x, y);
+    }
+
+    private static void checkForZero(int y) {
+        if (y == 0) {
+            // "/ by zero"
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
+        }
+    }
+
+    private static void checkForZero(long y) {
+        if (y == 0) {
+            // "/ by zero"
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
+        }
+    }
+
+    @NodeIntrinsic(SafeSignedDivNode.class)
+    private static native int safeDiv(int x, int y);
+
+    @NodeIntrinsic(SafeSignedDivNode.class)
+    private static native long safeDiv(long x, long y);
+
+    @NodeIntrinsic(SafeSignedRemNode.class)
+    private static native int safeRem(int x, int y);
+
+    @NodeIntrinsic(SafeSignedRemNode.class)
+    private static native long safeRem(long x, long y);
+
+    @NodeIntrinsic(SafeUnsignedDivNode.class)
+    private static native int safeUDiv(int x, int y);
+
+    @NodeIntrinsic(SafeUnsignedDivNode.class)
+    private static native long safeUDiv(long x, long y);
+
+    @NodeIntrinsic(SafeUnsignedRemNode.class)
+    private static native int safeURem(int x, int y);
+
+    @NodeIntrinsic(SafeUnsignedRemNode.class)
+    private static native long safeURem(long x, long y);
+
+    /**
+     * Marker interface to distinguish untreated nodes from ones where we have installed the
+     * additional checks.
+     */
+    private interface SafeNode {
+    }
+
+    @NodeInfo
+    static class SafeSignedDivNode extends SignedDivNode implements SafeNode {
+        public static final NodeClass<SafeSignedDivNode> TYPE = NodeClass.create(SafeSignedDivNode.class);
+
+        protected SafeSignedDivNode(ValueNode x, ValueNode y) {
+            super(TYPE, x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeSignedRemNode extends SignedRemNode implements SafeNode {
+        public static final NodeClass<SafeSignedRemNode> TYPE = NodeClass.create(SafeSignedRemNode.class);
+
+        protected SafeSignedRemNode(ValueNode x, ValueNode y) {
+            super(TYPE, x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
+        public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
+
+        protected SafeUnsignedDivNode(ValueNode x, ValueNode y) {
+            super(TYPE, x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
+        public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
+
+        protected SafeUnsignedRemNode(ValueNode x, ValueNode y) {
+            super(TYPE, x, y);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerSubstitutions.java
new file mode 100644
index 0000000..28c753a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerSubstitutions.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.aarch64;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+
+/**
+ * AArch64 ISA offers a count leading zeros instruction which can be used to implement
+ * numberOfLeadingZeros more efficiently than using BitScanReverse.
+ */
+@ClassSubstitution(Integer.class)
+public class AArch64IntegerSubstitutions {
+
+    @MethodSubstitution
+    public static int bitCount(int value) {
+        // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift
+        // instruction.
+        // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction
+        // this takes 10 instructions.
+        int x = value;
+        x = x - ((x & 0xaaaaaaaa) >>> 1);
+        x = (x & 0x33333333) + ((x & 0xcccccccc) >>> 2);
+        x = (x + (x >>> 4)) & 0x0f0f0f0f;
+        x = x + (x >>> 8);
+        x = x + (x >>> 16);
+        return x & 0x3f;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64LongSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64LongSubstitutions.java
new file mode 100644
index 0000000..dc1afb3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64LongSubstitutions.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.aarch64;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+
+/**
+ * Aarch64 ISA offers a count leading zeros instruction which can be used to implement
+ * numberOfLeadingZeros more efficiently than using BitScanReverse.
+ */
+@ClassSubstitution(Long.class)
+public class AArch64LongSubstitutions {
+
+    @MethodSubstitution
+    public static int bitCount(long value) {
+        // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift
+        // instruction.
+        // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction
+        // this takes 11 instructions.
+        long x = value;
+        x = x - ((x & 0xaaaaaaaaaaaaaaaaL) >>> 1);
+        x = (x & 0x3333333333333333L) + ((x & 0xccccccccccccccccL) >>> 2);
+        x = (x + (x >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
+        x = x + (x >>> 8);
+        x = x + (x >>> 16);
+        x = x + (x >>> 32);
+        return (int) x & 0x7f;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java
new file mode 100644
index 0000000..f3435ee
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match
+ * the semantics of the JVM specification.
+ */
+public class AMD64ConvertSnippets implements Snippets {
+
+    /**
+     * Converts a float to an int.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the
+     * conversion. If the float value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and
+     * extra tests are required on the float value to return the correct int value.
+     *
+     * @param input the float being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static int f2i(float input, int result) {
+        if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) {
+            if (Float.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0f) {
+                // input is > 0 -> return max int
+                return Integer.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a float to a long.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the
+     * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns
+     * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct
+     * long value.
+     *
+     * @param input the float being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static long f2l(float input, long result) {
+        if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) {
+            if (Float.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0f) {
+                // input is > 0 -> return max int
+                return Long.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a double to an int.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the
+     * conversion. If the double value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and
+     * extra tests are required on the double value to return the correct int value.
+     *
+     * @param input the double being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static int d2i(double input, int result) {
+        if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) {
+            if (Double.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0d) {
+                // input is positive -> return maxInt
+                return Integer.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a double to a long.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the
+     * conversion. If the double value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra
+     * tests are required on the double value to return the correct long value.
+     *
+     * @param input the double being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static long d2l(double input, long result) {
+        if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) {
+            if (Double.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0d) {
+                // input is positive -> return maxInt
+                return Long.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo f2i;
+        private final SnippetInfo f2l;
+        private final SnippetInfo d2i;
+        private final SnippetInfo d2l;
+
+        public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+            super(providers, snippetReflection, target);
+
+            f2i = snippet(AMD64ConvertSnippets.class, "f2i");
+            f2l = snippet(AMD64ConvertSnippets.class, "f2l");
+            d2i = snippet(AMD64ConvertSnippets.class, "d2i");
+            d2l = snippet(AMD64ConvertSnippets.class, "d2l");
+        }
+
+        public void lower(FloatConvertNode convert, LoweringTool tool) {
+            SnippetInfo key;
+            switch (convert.getFloatConvert()) {
+                case F2I:
+                    key = f2i;
+                    break;
+                case F2L:
+                    key = f2l;
+                    break;
+                case D2I:
+                    key = d2i;
+                    break;
+                case D2L:
+                    key = d2l;
+                    break;
+                default:
+                    return;
+            }
+
+            StructuredGraph graph = convert.graph();
+
+            Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("input", convert.getValue());
+            args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue())));
+
+            SnippetTemplate template = template(args);
+            Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args);
+            template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args);
+            convert.safeDelete();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java
new file mode 100644
index 0000000..47d1ed4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Count the number of leading zeros using the {@code lzcntq} or {@code lzcntl} instructions.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class AMD64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
+    public static final NodeClass<AMD64CountLeadingZerosNode> TYPE = NodeClass.create(AMD64CountLeadingZerosNode.class);
+
+    public AMD64CountLeadingZerosNode(ValueNode value) {
+        super(TYPE, computeStamp(value.stamp(), value), value);
+        assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        return computeStamp(newStamp, getValue());
+    }
+
+    private static Stamp computeStamp(Stamp newStamp, ValueNode theValue) {
+        assert newStamp.isCompatible(theValue.stamp());
+        assert theValue.getStackKind() == JavaKind.Int || theValue.getStackKind() == JavaKind.Long;
+        return StampTool.stampForLeadingZeros((IntegerStamp) newStamp);
+    }
+
+    public static ValueNode tryFold(ValueNode value) {
+        if (value.isConstant()) {
+            JavaConstant c = value.asJavaConstant();
+            if (value.getStackKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Integer.numberOfLeadingZeros(c.asInt()));
+            } else {
+                return ConstantNode.forInt(Long.numberOfLeadingZeros(c.asLong()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, ((AMD64ArithmeticLIRGeneratorTool) gen).emitCountLeadingZeros(builder.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java
new file mode 100644
index 0000000..dc4f62c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Count the number of trailing zeros using the {@code tzcntq} or {@code tzcntl} instructions.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class AMD64CountTrailingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
+    public static final NodeClass<AMD64CountTrailingZerosNode> TYPE = NodeClass.create(AMD64CountTrailingZerosNode.class);
+
+    public AMD64CountTrailingZerosNode(ValueNode value) {
+        super(TYPE, computeStamp(value.stamp(), value), value);
+        assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        return computeStamp(newStamp, getValue());
+    }
+
+    static Stamp computeStamp(Stamp newStamp, ValueNode value) {
+        assert newStamp.isCompatible(value.stamp());
+        IntegerStamp valueStamp = (IntegerStamp) newStamp;
+        return StampTool.stampForTrailingZeros(valueStamp);
+    }
+
+    public static ValueNode tryFold(ValueNode value) {
+        if (value.isConstant()) {
+            JavaConstant c = value.asJavaConstant();
+            if (value.getStackKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Integer.numberOfTrailingZeros(c.asInt()));
+            } else {
+                return ConstantNode.forInt(Long.numberOfTrailingZeros(c.asLong()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, ((AMD64ArithmeticLIRGeneratorTool) gen).emitCountTrailingZeros(builder.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64FloatConvertNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64FloatConvertNode.java
new file mode 100644
index 0000000..039326d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64FloatConvertNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_5;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.UnaryArithmeticNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * This node has the semantics of the AMD64 floating point conversions. It is used in the lowering
+ * of the {@link FloatConvertNode} which, on AMD64 needs a {@link AMD64FloatConvertNode} plus some
+ * fixup code that handles the corner cases that differ between AMD64 and Java.
+ */
+@NodeInfo(cycles = CYCLES_5, size = SIZE_1)
+public final class AMD64FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ArithmeticLIRLowerable {
+    public static final NodeClass<AMD64FloatConvertNode> TYPE = NodeClass.create(AMD64FloatConvertNode.class);
+
+    protected final FloatConvert op;
+
+    public AMD64FloatConvertNode(FloatConvert op, ValueNode value) {
+        super(TYPE, table -> table.getFloatConvert(op), value);
+        this.op = op;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        // nothing to do
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        nodeValueMap.setResult(this, gen.emitFloatConvert(op, nodeValueMap.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java
new file mode 100644
index 0000000..f7919d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.java.AtomicReadAndAddNode;
+import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.replacements.IntegerSubstitutions;
+import org.graalvm.compiler.replacements.LongSubstitutions;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeGetPlugin;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafePutPlugin;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
+import org.graalvm.compiler.replacements.nodes.BitCountNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+public class AMD64GraphBuilderPlugins {
+
+    public static void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, AMD64 arch, boolean arithmeticStubs) {
+        InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
+        invocationPlugins.defer(new Runnable() {
+            @Override
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch, replacementsBytecodeProvider);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider);
+                registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider);
+                registerMathPlugins(invocationPlugins, arch, arithmeticStubs, replacementsBytecodeProvider);
+            }
+        });
+    }
+
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch, BytecodeProvider bytecodeProvider) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
+        if (arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction)) {
+            r.register1("numberOfLeadingZeros", type, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    ValueNode folded = AMD64CountLeadingZerosNode.tryFold(value);
+                    if (folded != null) {
+                        b.addPush(JavaKind.Int, folded);
+                    } else {
+                        b.addPush(JavaKind.Int, new AMD64CountLeadingZerosNode(value));
+                    }
+                    return true;
+                }
+            });
+        } else {
+            r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type);
+        }
+        if (arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction)) {
+            r.register1("numberOfTrailingZeros", type, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    ValueNode folded = AMD64CountTrailingZerosNode.tryFold(value);
+                    if (folded != null) {
+                        b.addPush(JavaKind.Int, folded);
+                    } else {
+                        b.addPush(JavaKind.Int, new AMD64CountTrailingZerosNode(value));
+                    }
+                    return true;
+                }
+            });
+        } else {
+            r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
+        }
+
+        if (arch.getFeatures().contains(AMD64.CPUFeature.POPCNT)) {
+            r.register1("bitCount", type, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    b.push(JavaKind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null)));
+                    return true;
+                }
+            });
+        }
+    }
+
+    private static void registerMathPlugins(InvocationPlugins plugins, AMD64 arch, boolean arithmeticStubs, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Math.class, bytecodeProvider);
+        registerUnaryMath(r, "log", LOG);
+        registerUnaryMath(r, "log10", LOG10);
+        registerUnaryMath(r, "exp", EXP);
+        registerBinaryMath(r, "pow", POW);
+        if (arithmeticStubs) {
+            registerUnaryMath(r, "sin", SIN);
+            registerUnaryMath(r, "cos", COS);
+            registerUnaryMath(r, "tan", TAN);
+        } else {
+            r.registerMethodSubstitution(AMD64MathSubstitutions.class, "sin", double.class);
+            r.registerMethodSubstitution(AMD64MathSubstitutions.class, "cos", double.class);
+            r.registerMethodSubstitution(AMD64MathSubstitutions.class, "tan", double.class);
+        }
+
+        if (arch.getFeatures().contains(CPUFeature.SSE4_1)) {
+            registerRound(r, "rint", RoundingMode.NEAREST);
+            registerRound(r, "ceil", RoundingMode.UP);
+            registerRound(r, "floor", RoundingMode.DOWN);
+        }
+    }
+
+    private static void registerUnaryMath(Registration r, String name, UnaryOperation operation) {
+        r.register1(name, Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Double, b.recursiveAppend(UnaryMathIntrinsicNode.create(value, operation)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerBinaryMath(Registration r, String name, BinaryOperation operation) {
+        r.register2(name, Double.TYPE, Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(JavaKind.Double, b.recursiveAppend(BinaryMathIntrinsicNode.create(x, y, operation)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerRound(Registration r, String name, RoundingMode mode) {
+        r.register1(name, Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                b.push(JavaKind.Double, b.append(new AMD64RoundNode(arg, mode)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+        Registration r;
+        if (Java8OrEarlier) {
+            r = new Registration(plugins, Unsafe.class);
+        } else {
+            r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider);
+        }
+        for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
+            Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+
+            r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
+                    // Emits a null-check for the otherwise unused receiver
+                    unsafe.get();
+                    b.addPush(kind, new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()));
+                    b.getGraph().markUnsafeAccess();
+                    return true;
+                }
+            });
+            if (kind != JavaKind.Object) {
+                r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
+                        // Emits a null-check for the otherwise unused receiver
+                        unsafe.get();
+                        AddressNode address = b.add(new OffsetAddressNode(object, offset));
+                        b.addPush(kind, new AtomicReadAndAddNode(address, delta, LocationIdentity.any()));
+                        b.getGraph().markUnsafeAccess();
+                        return true;
+                    }
+                });
+            }
+        }
+
+        for (JavaKind kind : new JavaKind[]{JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long}) {
+            Class<?> javaClass = kind.toJavaClass();
+            r.registerOptional3("get" + kind.name() + "Unaligned", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, false));
+            r.registerOptional4("put" + kind.name() + "Unaligned", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64MathSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64MathSubstitutions.java
new file mode 100644
index 0000000..4a15b93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64MathSubstitutions.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for some {@link java.lang.Math} methods that leverage AMD64 instructions for
+ * selected input values.
+ */
+@ClassSubstitution(Math.class)
+public class AMD64MathSubstitutions {
+
+    private static final double PI_4 = Math.PI / 4;
+
+    // NOTE on snippets below:
+    // Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the
+    // exact result, but x87 trigonometric FPU instructions are only that
+    // accurate within [-pi/4, pi/4]. Examine the passed value and provide
+    // a slow path for inputs outside of that interval.
+
+    @MethodSubstitution
+    public static double sin(double x) {
+        if (Math.abs(x) < PI_4) {
+            return UnaryMathIntrinsicNode.compute(x, UnaryOperation.SIN);
+        } else {
+            return callDouble1(UnaryOperation.SIN.foreignCallDescriptor, x);
+        }
+    }
+
+    @MethodSubstitution
+    public static double cos(double x) {
+        if (Math.abs(x) < PI_4) {
+            return UnaryMathIntrinsicNode.compute(x, UnaryOperation.COS);
+        } else {
+            return callDouble1(UnaryOperation.COS.foreignCallDescriptor, x);
+        }
+    }
+
+    @MethodSubstitution
+    public static double tan(double x) {
+        if (Math.abs(x) < PI_4) {
+            return UnaryMathIntrinsicNode.compute(x, UnaryOperation.TAN);
+        } else {
+            return callDouble1(UnaryOperation.TAN.foreignCallDescriptor, x);
+        }
+    }
+
+    @NodeIntrinsic(value = ForeignCallNode.class)
+    private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
+
+    @NodeIntrinsic(value = ForeignCallNode.class)
+    private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64RoundNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64RoundNode.java
new file mode 100644
index 0000000..4a980b0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64RoundNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Round floating-point value.
+ */
+@NodeInfo(cycles = CYCLES_1)
+public final class AMD64RoundNode extends UnaryNode implements ArithmeticLIRLowerable {
+    public static final NodeClass<AMD64RoundNode> TYPE = NodeClass.create(AMD64RoundNode.class);
+
+    private final RoundingMode mode;
+
+    public AMD64RoundNode(ValueNode value, RoundingMode mode) {
+        super(TYPE, roundStamp((FloatStamp) value.stamp(), mode), value);
+        this.mode = mode;
+    }
+
+    private static double round(RoundingMode mode, double input) {
+        switch (mode) {
+            case DOWN:
+                return Math.floor(input);
+            case NEAREST:
+                return Math.rint(input);
+            case UP:
+                return Math.ceil(input);
+            case TRUNCATE:
+                return (long) input;
+            default:
+                throw GraalError.unimplemented("unimplemented RoundingMode " + mode);
+        }
+    }
+
+    private static FloatStamp roundStamp(FloatStamp stamp, RoundingMode mode) {
+        double min = stamp.lowerBound();
+        min = Math.min(min, round(mode, min));
+
+        double max = stamp.upperBound();
+        max = Math.max(max, round(mode, max));
+
+        return new FloatStamp(stamp.getBits(), min, max, stamp.isNonNaN());
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        return roundStamp((FloatStamp) newStamp, mode);
+    }
+
+    public ValueNode tryFold(ValueNode input) {
+        if (input.isConstant()) {
+            JavaConstant c = input.asJavaConstant();
+            if (c.getJavaKind() == JavaKind.Double) {
+                return ConstantNode.forDouble(round(mode, c.asDouble()));
+            } else if (c.getJavaKind() == JavaKind.Float) {
+                return ConstantNode.forFloat((float) round(mode, c.asFloat()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, ((AMD64ArithmeticLIRGeneratorTool) gen).emitRound(builder.operand(getValue()), mode));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java
new file mode 100644
index 0000000..2a3bb47
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.sparc;
+
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
+import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.replacements.IntegerSubstitutions;
+import org.graalvm.compiler.replacements.LongSubstitutions;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.BitCountNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class SPARCGraphBuilderPlugins {
+
+    public static void register(Plugins plugins, BytecodeProvider bytecodeProvider) {
+        InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
+        invocationPlugins.defer(new Runnable() {
+            @Override
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, bytecodeProvider);
+                registerMathPlugins(invocationPlugins);
+            }
+        });
+    }
+
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, BytecodeProvider bytecodeProvider) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
+        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type);
+        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
+
+        r.register1("bitCount", type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerMathPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Math.class);
+        registerUnaryMath(r, "sin", SIN);
+        registerUnaryMath(r, "cos", COS);
+        registerUnaryMath(r, "tan", TAN);
+        registerUnaryMath(r, "exp", EXP);
+        registerUnaryMath(r, "log", LOG);
+        registerUnaryMath(r, "log10", LOG10);
+        r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(JavaKind.Double, b.recursiveAppend(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerUnaryMath(Registration r, String name, UnaryOperation operation) {
+        r.register1(name, Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Double, b.recursiveAppend(UnaryMathIntrinsicNode.create(value, operation)));
+                return true;
+            }
+        });
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java
new file mode 100644
index 0000000..1aceedf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@RunWith(Parameterized.class)
+public class ArrayStoreBytecodeExceptionTest extends BytecodeExceptionTest {
+
+    private static class Exceptions {
+
+        private static Object[] array = new Exceptions[1];
+
+        public static void throwArrayStore(Object obj) {
+            array[0] = obj;
+        }
+    }
+
+    @Override
+    protected void registerPlugin(InvocationPlugins plugins) {
+        plugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj) {
+                return throwBytecodeException(b, ArrayStoreException.class, obj);
+            }
+        }, Exceptions.class, "throwArrayStore", Object.class);
+    }
+
+    public static void arrayStoreSnippet(Object obj) {
+        Exceptions.throwArrayStore(obj);
+    }
+
+    @Parameter(0) public Object object;
+    @Parameter(1) public Class<?> cls;
+
+    @Parameters(name = "{1}")
+    public static Collection<Object[]> data() {
+        Object[] objects = {"string", 42, new int[0], new String[0], new double[0][]};
+
+        ArrayList<Object[]> ret = new ArrayList<>(objects.length);
+        for (Object o : objects) {
+            ret.add(new Object[]{o, o.getClass()});
+        }
+        return ret;
+    }
+
+    @Test
+    public void testArrayStoreException() {
+        test("arrayStoreSnippet", object);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java
new file mode 100644
index 0000000..bc6fdb1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.replacements.ArraysSubstitutions;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+/**
+ * Tests {@link ArraysSubstitutions}.
+ */
+public class ArraysSubstitutionsTest extends MethodSubstitutionTest {
+
+    private static final int N = 10;
+
+    @Test
+    public void testEqualsBoolean() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new boolean[i];
+            args2[n] = new boolean[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            boolean[] a2 = new boolean[i];
+            if (i > 0) {
+                a2[i - 1] = true;
+            }
+            args1[n] = new boolean[i];
+            args2[n] = a2;
+        }
+        Class<?>[] parameterTypes = new Class<?>[]{boolean[].class, boolean[].class};
+        testSubstitution("arraysEqualsBoolean", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsByte() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new byte[i];
+            args2[n] = new byte[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            byte[] a2 = new byte[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new byte[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{byte[].class, byte[].class};
+        testSubstitution("arraysEqualsByte", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsByte(byte[] a, byte[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsChar() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new char[i];
+            args2[n] = new char[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            char[] a2 = new char[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new char[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{char[].class, char[].class};
+        testSubstitution("arraysEqualsChar", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsChar(char[] a, char[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsShort() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new short[i];
+            args2[n] = new short[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            short[] a2 = new short[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new short[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{short[].class, short[].class};
+        testSubstitution("arraysEqualsShort", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsShort(short[] a, short[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsInt() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new int[i];
+            args2[n] = new int[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            int[] a2 = new int[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new int[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{int[].class, int[].class};
+        testSubstitution("arraysEqualsInt", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsInt(int[] a, int[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsLong() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new long[i];
+            args2[n] = new long[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            long[] a2 = new long[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new long[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{long[].class, long[].class};
+        testSubstitution("arraysEqualsLong", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsLong(long[] a, long[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsFloat() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new float[i];
+            args2[n] = new float[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            float[] a2 = new float[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new float[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{float[].class, float[].class};
+        testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsFloat(float[] a, float[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsDouble() {
+        Object[] args1 = new Object[N];
+        Object[] args2 = new Object[N];
+        int n = 0;
+
+        // equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            args1[n] = new double[i];
+            args2[n] = new double[i];
+        }
+
+        // non-equal arrays
+        for (int i = 0; i < N / 2; i++, n++) {
+            double[] a2 = new double[i];
+            if (i > 0) {
+                a2[i - 1] = 1;
+            }
+            args1[n] = new double[i];
+            args2[n] = a2;
+        }
+
+        Class<?>[] parameterTypes = new Class<?>[]{double[].class, double[].class};
+        testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean arraysEqualsDouble(double[] a, double[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    @Test
+    public void testEqualsNodeGVN() {
+        test("testEqualsNodeGVNSnippet", true);
+    }
+
+    public static int[] intArrayCompare = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+    public static int[] intArray;
+
+    public static boolean testEqualsNodeGVNSnippet(boolean b) {
+        int[] newIntArray = new int[]{0, 2, 3, 4, 5, 6, 7, 8, 9};
+        intArray = newIntArray;
+
+        if (b) {
+            newIntArray[0] = 1;
+            return Arrays.equals(newIntArray, intArrayCompare);
+        } else {
+            newIntArray[0] = 1;
+            return Arrays.equals(newIntArray, intArrayCompare);
+        }
+    }
+
+    @Test
+    public void testConstants() {
+        testGraph("testConstantsSnippet");
+    }
+
+    public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+    public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+    public static boolean testConstantsSnippet() {
+        constantArray2[0] = 10;
+        try {
+            return Arrays.equals(constantArray1, constantArray2);
+        } finally {
+            constantArray2[0] = 1;
+        }
+    }
+
+    @Test
+    public void testCanonicalLength() {
+        StructuredGraph graph = parseEager("testCanonicalLengthSnippet", AllowAssumptions.NO);
+        HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
+    }
+
+    public static final int[] constantArray3 = new int[]{1, 2, 3};
+
+    public static boolean testCanonicalLengthSnippet() {
+        return Arrays.equals(constantArray1, constantArray3);
+    }
+
+    @Test
+    public void testCanonicalEqual() {
+        StructuredGraph graph = parseEager("testCanonicalEqualSnippet", AllowAssumptions.NO);
+        HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
+    }
+
+    public static boolean testCanonicalEqualSnippet() {
+        return Arrays.equals(constantArray1, constantArray1);
+    }
+
+    @Test
+    public void testVirtualEqual() {
+        StructuredGraph graph = parseEager("testVirtualEqualSnippet", AllowAssumptions.NO);
+        HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
+    }
+
+    public static boolean testVirtualEqualSnippet() {
+        int[] array1 = new int[]{1, 2, 3, 4};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
+
+    @Test
+    public void testVirtualNotEqual() {
+        StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
+    }
+
+    public static boolean testVirtualNotEqualSnippet(int x) {
+        int[] array1 = new int[]{1, 2, 100, x};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java
new file mode 100644
index 0000000..2dd8252
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.sparc.SPARC;
+
+public class BitOpNodesTest extends GraalCompilerTest {
+
+    private static final int INT_CONSTANT_1 = 0x80100010;
+    private static final int INT_CONSTANT_2 = 0x00011110;
+    private static final int INT_CONSTANT_3 = 0x00000000;
+
+    private static final long LONG_CONSTANT_1 = 0x8000000000100010L;
+    private static final long LONG_CONSTANT_2 = 0x0000000000011110L;
+    private static final long LONG_CONSTANT_3 = 0x0000000000000000L;
+
+    public static long dummyField;
+
+    /*
+     * Tests for BitCountNode canonicalizations.
+     */
+
+    public static int bitCountIntConstantSnippet() {
+        return Integer.bitCount(INT_CONSTANT_1) + Integer.bitCount(INT_CONSTANT_2) + Integer.bitCount(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testBitCountIntConstant() {
+        ValueNode result = parseAndInline("bitCountIntConstantSnippet");
+        Assert.assertEquals(7, result.asJavaConstant().asInt());
+    }
+
+    public static int bitCountLongConstantSnippet() {
+        return Long.bitCount(LONG_CONSTANT_1) + Long.bitCount(LONG_CONSTANT_2) + Long.bitCount(LONG_CONSTANT_3);
+    }
+
+    public static int bitCountIntSnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF | 0xFF);
+    }
+
+    @Test
+    public void testBitCountInt() {
+        Architecture arch = getBackend().getTarget().arch;
+        boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT);
+        boolean isSparc = arch instanceof SPARC;
+        Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc);
+        ValueNode result = parseAndInline("bitCountIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 24), result.stamp());
+    }
+
+    public static int bitCountIntEmptySnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF);
+    }
+
+    @Test
+    public void testBitCountIntEmpty() {
+        Architecture arch = getBackend().getTarget().arch;
+        boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT);
+        boolean isSparc = arch instanceof SPARC;
+        Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc);
+        ValueNode result = parseAndInline("bitCountIntEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 24), result.stamp());
+    }
+
+    @Test
+    public void testBitCountLongConstant() {
+        ValueNode result = parseAndInline("bitCountLongConstantSnippet");
+        Assert.assertEquals(7, result.asJavaConstant().asInt());
+    }
+
+    public static int bitCountLongSnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL | 0xFFL);
+    }
+
+    @Test
+    public void testBitCountLong() {
+        Architecture arch = getBackend().getTarget().arch;
+        boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT);
+        boolean isSparc = arch instanceof SPARC;
+        Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc);
+        ValueNode result = parseAndInline("bitCountLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 40), result.stamp());
+    }
+
+    public static int bitCountLongEmptySnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL);
+    }
+
+    @Test
+    public void testBitCountLongEmpty() {
+        Architecture arch = getBackend().getTarget().arch;
+        boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT);
+        boolean isSparc = arch instanceof SPARC;
+        Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc);
+        ValueNode result = parseAndInline("bitCountLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 40), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanForwardNode
+     */
+
+    public static int scanForwardIntConstantSnippet() {
+        return Integer.numberOfTrailingZeros(INT_CONSTANT_1) + Integer.numberOfTrailingZeros(INT_CONSTANT_2) + Integer.numberOfTrailingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardIntConstant() {
+        ValueNode result = parseAndInline("scanForwardIntConstantSnippet");
+        Assert.assertEquals(40, result.asJavaConstant().asInt());
+    }
+
+    public static int scanForwardIntSnippet(int v) {
+        return Integer.numberOfTrailingZeros(v & 0xFFF0 | 0xFF00);
+    }
+
+    @Test
+    public void testScanForwardInt() {
+        ValueNode result = parseAndInline("scanForwardIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 4, 8), result.stamp());
+    }
+
+    public static int scanForwardLongConstantSnippet() {
+        return Long.numberOfTrailingZeros(LONG_CONSTANT_1) + Long.numberOfTrailingZeros(LONG_CONSTANT_2) + Long.numberOfTrailingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardLongConstant() {
+        ValueNode result = parseAndInline("scanForwardLongConstantSnippet");
+        Assert.assertEquals(72, result.asJavaConstant().asInt());
+    }
+
+    public static int scanForwardLongSnippet(long v) {
+        return Long.numberOfTrailingZeros(v & 0xFFFF000000L | 0xFF00000000L);
+    }
+
+    @Test
+    public void testScanForwardLong() {
+        ValueNode result = parseAndInline("scanForwardLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 32), result.stamp());
+    }
+
+    public static int scanForwardLongEmptySnippet(long v) {
+        int result = Long.numberOfTrailingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanForwardLongEmpty() {
+        ValueNode result = parseAndInline("scanForwardLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanReverseNode
+     */
+
+    public static int scanReverseIntConstantSnippet() {
+        return Integer.numberOfLeadingZeros(INT_CONSTANT_1) + Integer.numberOfLeadingZeros(INT_CONSTANT_2) + Integer.numberOfLeadingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseIntConstant() {
+        ValueNode result = parseAndInline("scanReverseIntConstantSnippet");
+        Assert.assertEquals(47, result.asJavaConstant().asInt());
+    }
+
+    public static int scanReverseIntSnippet(int v) {
+        return Integer.numberOfLeadingZeros(v & 0xFFF0 | 0xFF0);
+    }
+
+    @Test
+    public void testScanReverseInt() {
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseIntSnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 16, 20), result.stamp());
+        }
+    }
+
+    public static int scanReverseLongConstantSnippet() {
+        return Long.numberOfLeadingZeros(LONG_CONSTANT_1) + Long.numberOfLeadingZeros(LONG_CONSTANT_2) + Long.numberOfLeadingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseLongConstant() {
+        ValueNode result = parseAndInline("scanReverseLongConstantSnippet");
+        Assert.assertEquals(111, result.asJavaConstant().asInt());
+    }
+
+    public static int scanReverseLongSnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFF0);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLong() {
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseLongSnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 48, 64), result.stamp());
+        }
+    }
+
+    public static int scanReverseLongEmptySnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLongEmpty() {
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseLongEmptySnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp());
+        }
+    }
+
+    private ValueNode parseAndInline(String name) {
+        return parseAndInline(name, null);
+    }
+
+    /**
+     * Parse and optimize {@code name}. If {@code expectedClass} is non-null and a node of that type
+     * isn't found simply return null. Otherwise return the node returned by the graph.
+     *
+     * @param name
+     * @param expectedClass
+     * @return the returned value or null if {@code expectedClass} is not found in the graph.
+     */
+    private ValueNode parseAndInline(String name, Class<? extends ValueNode> expectedClass) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+        HighTierContext context = getDefaultHighTierContext();
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, context);
+        new InliningPhase(canonicalizer).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        Assert.assertEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        if (expectedClass != null) {
+            if (graph.getNodes().filter(expectedClass).count() == 0) {
+                return null;
+            }
+        }
+        return graph.getNodes(ReturnNode.TYPE).first().result();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java
new file mode 100644
index 0000000..f377021
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+public abstract class BytecodeExceptionTest extends GraalCompilerTest {
+
+    protected boolean throwBytecodeException(GraphBuilderContext b, Class<? extends Throwable> exception, ValueNode... arguments) {
+        BytecodeExceptionNode exceptionNode = b.add(new BytecodeExceptionNode(b.getMetaAccess(), exception, arguments));
+        b.add(new UnwindNode(exceptionNode));
+        return true;
+    }
+
+    protected abstract void registerPlugin(InvocationPlugins plugins);
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        GraphBuilderConfiguration ret = super.editGraphBuilderConfiguration(conf);
+        registerPlugin(ret.getPlugins().getInvocationPlugins());
+        return ret;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java
new file mode 100644
index 0000000..c6203e4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@RunWith(Parameterized.class)
+public class ClassCastBytecodeExceptionTest extends BytecodeExceptionTest {
+
+    private static class Exceptions {
+
+        public static void throwClassCast(Object obj, Class<?> cls) {
+            /*
+             * We don't use cls.cast(obj) here because that gives a different exception message than
+             * the checkcast bytecode.
+             */
+            if (cls == Double.class) {
+                Double cast = (Double) obj;
+                GraalDirectives.blackhole(cast);
+            } else if (cls == byte[].class) {
+                byte[] cast = (byte[]) obj;
+                GraalDirectives.blackhole(cast);
+            } else if (cls == String[].class) {
+                String[] cast = (String[]) obj;
+                GraalDirectives.blackhole(cast);
+            } else if (cls == Object[][].class) {
+                Object[][] cast = (Object[][]) obj;
+                GraalDirectives.blackhole(cast);
+            } else {
+                Assert.fail("unexpected class argument");
+            }
+        }
+    }
+
+    @Override
+    protected void registerPlugin(InvocationPlugins plugins) {
+        plugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj, ValueNode classNode) {
+                ResolvedJavaType type = b.getConstantReflection().asJavaType(classNode.asConstant());
+                Constant hub = b.getConstantReflection().asObjectHub(type);
+                Stamp hubStamp = b.getStampProvider().createHubStamp(StampFactory.object(TypeReference.createExactTrusted(type)));
+                ConstantNode hubConst = b.add(ConstantNode.forConstant(hubStamp, hub, b.getMetaAccess()));
+                return throwBytecodeException(b, ClassCastException.class, obj, hubConst);
+            }
+        }, Exceptions.class, "throwClassCast", Object.class, Class.class);
+    }
+
+    @Parameter(0) public Object object;
+    @Parameter(1) public Class<?> cls;
+
+    @Parameters(name = "{1}")
+    public static Collection<Object[]> data() {
+        Object[] objects = {"string", 42, new int[0], new Object[0], new double[0][]};
+
+        ArrayList<Object[]> ret = new ArrayList<>(objects.length);
+        for (Object o : objects) {
+            ret.add(new Object[]{o, o.getClass()});
+        }
+        return ret;
+    }
+
+    public static void castToDouble(Object obj) {
+        Exceptions.throwClassCast(obj, Double.class);
+    }
+
+    @Test
+    public void testCastToDouble() {
+        test("castToDouble", object);
+    }
+
+    public static void castToByteArray(Object obj) {
+        Exceptions.throwClassCast(obj, byte[].class);
+    }
+
+    @Test
+    public void testCastToByteArray() {
+        test("castToByteArray", object);
+    }
+
+    public static void castToStringArray(Object obj) {
+        Exceptions.throwClassCast(obj, String[].class);
+    }
+
+    @Test
+    public void testCastToStringArray() {
+        test("castToStringArray", object);
+    }
+
+    public static void castToArrayArray(Object obj) {
+        Exceptions.throwClassCast(obj, Object[][].class);
+    }
+
+    @Test
+    public void testCastToArrayArray() {
+        test("castToArrayArray", object);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledExceptionHandlerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledExceptionHandlerTest.java
new file mode 100644
index 0000000..3393a3de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledExceptionHandlerTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests compilation of a hot exception handler.
+ */
+public class CompiledExceptionHandlerTest extends GraalCompilerTest {
+
+    @Override
+    @SuppressWarnings("try")
+    protected Suites createSuites() {
+        try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) {
+            return super.createSuites();
+        }
+    }
+
+    @Override
+    protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        /*
+         * We don't care whether other invokes are inlined or not, but we definitely don't want
+         * another explicit exception handler in the graph.
+         */
+        return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId);
+        int handlers = graph.getNodes().filter(ExceptionObjectNode.class).count();
+        Assert.assertEquals(1, handlers);
+        return graph;
+    }
+
+    @BytecodeParserNeverInline(invokeWithException = true)
+    private static void raiseExceptionSimple(String s) {
+        throw new RuntimeException("Raising exception with message \"" + s + "\"");
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "a string");
+        test("test1Snippet", (String) null);
+    }
+
+    public static String test1Snippet(String message) {
+        if (message != null) {
+            try {
+                raiseExceptionSimple(message);
+            } catch (Exception e) {
+                return message + e.getMessage();
+            }
+        }
+        return null;
+    }
+
+    @BytecodeParserNeverInline(invokeWithException = true)
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", "m1", "m2", "m3", "m4", "m5");
+        test("test2Snippet", null, "m2", "m3", "m4", "m5");
+    }
+
+    public static String test2Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            try {
+                raiseException(m1, m2, m3, m4, m5);
+            } catch (Exception e) {
+                return m5 + m4 + m3 + m2 + m1;
+            }
+        }
+        return m4 + m3;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledNullPointerExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledNullPointerExceptionTest.java
new file mode 100644
index 0000000..1fa8dcb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/CompiledNullPointerExceptionTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import static org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode.CheckAll;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.tiers.Suites;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests compilation of a hot exception handler.
+ */
+public class CompiledNullPointerExceptionTest extends GraalCompilerTest {
+
+    @Override
+    @SuppressWarnings("try")
+    protected Suites createSuites() {
+        try (OverrideScope scope = OptionValue.override(HighTier.Options.Inline, false)) {
+            return super.createSuites();
+        }
+    }
+
+    @Override
+    protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        return super.editGraphBuilderConfiguration(conf).withBytecodeExceptionMode(CheckAll);
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions, compilationId);
+        int handlers = graph.getNodes().filter(BytecodeExceptionNode.class).count();
+        Assert.assertEquals(1, handlers);
+        return graph;
+    }
+
+    private class TestClass {
+
+        @Override
+        public String toString() {
+            return "TestClass";
+        }
+    }
+
+    @Test
+    public void test() {
+        test("testSnippet", (TestClass) null, "object2");
+        test("testSnippet", new TestClass(), "object2");
+    }
+
+    public static String testSnippet(TestClass o, Object o2) {
+        try {
+            return o.toString();
+        } catch (NullPointerException e) {
+            return String.valueOf(o2);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java
new file mode 100644
index 0000000..783c276
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.Random;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+import org.graalvm.compiler.test.ExportingClassLoader;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests that deoptimization upon exception handling works.
+ */
+public class DeoptimizeOnExceptionTest extends GraalCompilerTest {
+
+    public DeoptimizeOnExceptionTest() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+    }
+
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "m1", "m2", "m3", "m4", "m5");
+    }
+
+    // no local exception handler - will deopt
+    public static String test1Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            raiseException(m1, m2, m3, m4, m5);
+        }
+        return m1 + m2 + m3 + m4 + m5;
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet");
+    }
+
+    public String test2Snippet() throws Exception {
+        try {
+            ClassLoader testCl = new MyClassLoader();
+            @SuppressWarnings("unchecked")
+            Class<Runnable> c = (Class<Runnable>) testCl.loadClass(name);
+            Runnable r = c.newInstance();
+            ct = Long.MAX_VALUE;
+            // warmup
+            for (int i = 0; i < 100; i++) {
+                r.run();
+            }
+            // compile
+            ResolvedJavaMethod method = getResolvedJavaMethod(c, "run");
+            getCode(method);
+            ct = 0;
+            r.run();
+        } catch (Throwable e) {
+            e.printStackTrace(System.out);
+            Assert.fail();
+        }
+        return "SUCCESS";
+    }
+
+    public static class MyClassLoader extends ExportingClassLoader {
+        @Override
+        protected Class<?> findClass(String className) throws ClassNotFoundException {
+            return defineClass(name.replace('/', '.'), clazz, 0, clazz.length);
+        }
+    }
+
+    public static void methodB() {
+        Random r = new Random(System.currentTimeMillis());
+        while (r.nextFloat() > .03f) {
+            // Empty
+        }
+
+        return;
+    }
+
+    public static void methodA() {
+        Random r = new Random(System.currentTimeMillis());
+        while (r.nextDouble() > .05) {
+            // Empty
+        }
+        return;
+    }
+
+    private static Object m = new Object();
+    static long ct = Long.MAX_VALUE;
+
+    public static Object getM() {
+        if (ct-- > 0) {
+            return m;
+        } else {
+            return null;
+        }
+    }
+
+    private static String name = "t/TestJSR";
+
+    private static final byte[] clazz = makeClazz();
+
+    private static byte[] makeClazz() {
+        // Code generated the class below using asm.
+        String clazzName = DeoptimizeOnExceptionTest.class.getName().replace('.', '/');
+        final ClassWriter w = new ClassWriter(0);
+        w.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC,
+                        "t/TestJSR", null, "java/lang/Object",
+                        new String[]{"java/lang/Runnable"});
+        MethodVisitor mv = w.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, new String[]{});
+        mv.visitCode();
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(Opcodes.RETURN);
+        mv.visitMaxs(10, 10);
+        mv.visitEnd();
+
+        mv = w.visitMethod(Opcodes.ACC_PUBLIC, "run", "()V", null, null);
+        mv.visitCode();
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false);
+        Label l1 = new Label();
+        mv.visitJumpInsn(Opcodes.JSR, l1);
+        mv.visitInsn(Opcodes.RETURN);
+
+        mv.visitLabel(l1);
+        mv.visitVarInsn(Opcodes.ASTORE, 1);
+
+        Label lElse = new Label();
+        Label lEnd = new Label();
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
+        mv.visitInsn(Opcodes.POP2);
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false);
+        mv.visitInsn(Opcodes.DUP);
+        mv.visitJumpInsn(Opcodes.IFNULL, lElse);
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodA", "()V", false);
+        mv.visitJumpInsn(Opcodes.GOTO, lEnd);
+        mv.visitLabel(lElse);
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodB", "()V", false);
+        mv.visitLabel(lEnd);
+
+        mv.visitVarInsn(Opcodes.RET, 1);
+        mv.visitMaxs(10, 10);
+        mv.visitEnd();
+        return w.toByteArray();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java
new file mode 100644
index 0000000..878f59e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.Objects;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.nodes.WordCastNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests for derived oops in reference maps.
+ */
+public class DerivedOopTest extends GraalCompilerTest implements Snippets {
+
+    private static class Pointers {
+        public long basePointer;
+        public long internalPointer;
+
+        public long delta() {
+            return internalPointer - basePointer;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Pointers)) {
+                return false;
+            }
+
+            Pointers other = (Pointers) obj;
+            return this.delta() == other.delta();
+        }
+
+        @Override
+        public int hashCode() {
+            return (int) delta();
+        }
+    }
+
+    private static class Result {
+        public Pointers beforeGC;
+        public Pointers afterGC;
+
+        Result() {
+            beforeGC = new Pointers();
+            afterGC = new Pointers();
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((afterGC == null) ? 0 : afterGC.hashCode());
+            result = prime * result + ((beforeGC == null) ? 0 : beforeGC.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Result)) {
+                return false;
+            }
+            Result other = (Result) obj;
+            return Objects.equals(this.beforeGC, other.beforeGC) && Objects.equals(this.afterGC, other.afterGC);
+        }
+    }
+
+    @Test
+    public void testFieldOffset() {
+        // Run a couple times to encourage objects to move
+        for (int i = 0; i < 4; i++) {
+            Result r = new Result();
+            test("fieldOffsetSnippet", r, 16L);
+
+            Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
+        }
+    }
+
+    static long getRawPointer(Object obj) {
+        // fake implementation for interpreter
+        return obj.hashCode();
+    }
+
+    static long getRawPointerIntrinsic(Object obj) {
+        return Word.objectToTrackedPointer(obj).rawValue();
+    }
+
+    public static Result fieldOffsetSnippet(Result obj, long offset) {
+        long internalPointer = getRawPointer(obj) + offset;
+
+        // make sure the internal pointer is computed before the safepoint
+        GraalDirectives.blackhole(internalPointer);
+
+        obj.beforeGC.basePointer = getRawPointer(obj);
+        obj.beforeGC.internalPointer = internalPointer;
+
+        System.gc();
+
+        obj.afterGC.basePointer = getRawPointer(obj);
+        obj.afterGC.internalPointer = internalPointer;
+
+        return obj;
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class);
+
+        ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic");
+        r.register1("getRawPointer", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                return b.intrinsify(getReplacements().getReplacementBytecodeProvider(), targetMethod, intrinsic, receiver, new ValueNode[]{arg});
+            }
+        });
+
+        return plugins;
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified";
+        return super.checkHighTierGraph(graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DynamicNewArrayTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DynamicNewArrayTest.java
new file mode 100644
index 0000000..1e20594
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DynamicNewArrayTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.lang.reflect.Array;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests the implementation of Array.createInstance.
+ */
+public class DynamicNewArrayTest extends GraalCompilerTest {
+
+    private class Element {
+    }
+
+    @Test
+    public void test1() {
+        test("test1snippet");
+    }
+
+    @Test
+    public void test2() {
+        test("test2snippet");
+    }
+
+    @Test
+    public void test3() {
+        test("dynamic", Long.class, 7);
+    }
+
+    @Test
+    public void test4() {
+        test("dynamic", Boolean.class, -7);
+        test("dynamicSynchronized", Boolean.class, -7);
+    }
+
+    @Test
+    public void test5() {
+        test("dynamic", byte.class, 7);
+    }
+
+    @Test
+    public void test6() {
+        test("dynamic", null, 5);
+    }
+
+    @Test
+    public void test7() {
+        test("dynamic", void.class, 5);
+    }
+
+    @Test
+    public void testStub() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("dynamic");
+        // this will use the stub call because Element[] is not loaded
+        Result actual1 = executeActual(method, null, Element.class, 7);
+        // this call will use the fast path
+        Result actual2 = executeActual(method, null, Element.class, 7);
+        Result expected = executeExpected(method, null, Element.class, 7);
+        assertEquals(actual1, expected);
+        assertEquals(actual2, expected);
+    }
+
+    public static Object test1snippet() {
+        return Array.newInstance(Integer.class, 7);
+    }
+
+    public static Object test2snippet() {
+        return Array.newInstance(char.class, 7);
+    }
+
+    public static Object dynamic(Class<?> elementType, int length) {
+        return Array.newInstance(elementType, length);
+    }
+
+    public static synchronized Object dynamicSynchronized(Class<?> elementType, int length) {
+        return Array.newInstance(elementType, length);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java
new file mode 100644
index 0000000..3966f83
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import java.lang.reflect.Method;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.common.inlining.policy.InlineMethodSubstitutionsPolicy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class EdgesTest extends GraalCompilerTest {
+
+    @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+        @Input NodeInputList<ValueNode> itail;
+        @Input ConstantNode i1;
+        @Input FloatingNode i2;
+
+        protected TestNode() {
+            super(TYPE);
+        }
+
+    }
+
+    StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO, INVALID_COMPILATION_ID);
+    TestNode node;
+    ConstantNode i1;
+    ConstantNode i2;
+    ConstantNode i3;
+    ConstantNode i4;
+    Edges inputs;
+
+    public EdgesTest() {
+        node = new TestNode();
+        i1 = ConstantNode.forInt(1, graph);
+        i2 = ConstantNode.forDouble(1.0d, graph);
+        i3 = ConstantNode.forInt(4, graph);
+        i4 = ConstantNode.forInt(14, graph);
+        node.itail = new NodeInputList<>(node, new ValueNode[]{i3, i4});
+        node.i1 = i1;
+        node.i2 = i2;
+        graph.add(node);
+        inputs = node.getNodeClass().getInputEdges();
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#getNode(Node, long[], int)}.
+     */
+    @Test
+    public void test0() {
+        testMethod(getMethod("getNode", Node.class, long[].class, int.class), null, node, inputs.getOffsets(), 0);
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#getNodeList(Node, long[], int)}.
+     */
+    @Test
+    public void test1() {
+        testMethod(getMethod("getNodeList", Node.class, long[].class, int.class), null, node, inputs.getOffsets(), 2);
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#setNode(Node, int, Node)}.
+     */
+    @Test
+    public void test2() {
+        testMethod(getMethod("setNode", Node.class, int.class, Node.class), inputs, node, 1, i2);
+    }
+
+    private void testMethod(Method method, Object receiver, Object... args) {
+        try {
+            // Invoke the method to ensure it has a type profile
+            for (int i = 0; i < 5000; i++) {
+                method.invoke(receiver, args);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
+        StructuredGraph g = parseProfiled(javaMethod, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new InlineMethodSubstitutionsPolicy(), new CanonicalizerPhase()).apply(g, context);
+        new CanonicalizerPhase().apply(g, context);
+        Assert.assertTrue(g.getNodes().filter(InstanceOfNode.class).isEmpty());
+    }
+
+    private static Method getMethod(final String name, Class<?>... parameters) {
+        try {
+            return Edges.class.getDeclaredMethod(name, parameters);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java
new file mode 100644
index 0000000..a320786
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
+import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
+
+public class FoldTest extends GraalCompilerTest {
+
+    private static class TestMethod {
+
+        public static int test() {
+            return 42;
+        }
+    }
+
+    static class FoldUtils {
+
+        private int number;
+
+        FoldUtils(int number) {
+            this.number = number;
+        }
+
+        @Fold
+        static int multiply(int a, int b) {
+            // we want to test whether @Fold works, so prevent automatic constant folding
+            return a * GraalDirectives.opaque(b);
+        }
+
+        @Fold
+        int getNumber() {
+            // we want to test whether @Fold works, so prevent automatic constant folding
+            return GraalDirectives.opaque(number);
+        }
+    }
+
+    @ClassSubstitution(TestMethod.class)
+    private static class TestMethodSubstitution {
+
+        private static final FoldUtils utils = new FoldUtils(21);
+
+        @MethodSubstitution
+        public static int test() {
+            return FoldUtils.multiply(utils.getNumber(), 2);
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        BytecodeProvider replacementBytecodeProvider = getReplacements().getReplacementBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider);
+        r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    public static int callTest() {
+        return TestMethod.test();
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factories, jvmci service providers don't work from unit tests
+        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
+        new PluginFactory_FoldTest().registerPlugins(ret.getInvocationPlugins(), injection);
+        return ret;
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        // check that folding happened correctly
+        StartNode start = graph.start();
+        assert start.next() instanceof ReturnNode : "expected ReturnNode, got " + start.next();
+
+        ReturnNode ret = (ReturnNode) start.next();
+        assert ret.result().isConstant() : "expected ConstantNode, got " + ret.result();
+        return true;
+    }
+
+    @Test
+    public void snippetTest() {
+        test("callTest");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java
new file mode 100644
index 0000000..64af2b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@RunWith(Parameterized.class)
+public class IndexOobBytecodeExceptionTest extends BytecodeExceptionTest {
+
+    private static class Exceptions {
+
+        private static Object[] empty = new Object[0];
+
+        public static void throwOutOfBounds(int idx) {
+            GraalDirectives.blackhole(empty[idx]);
+        }
+    }
+
+    @Override
+    protected void registerPlugin(InvocationPlugins plugins) {
+        plugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode idx) {
+                return throwBytecodeException(b, ArrayIndexOutOfBoundsException.class, idx);
+            }
+        }, Exceptions.class, "throwOutOfBounds", int.class);
+    }
+
+    public static void oobSnippet(int idx) {
+        Exceptions.throwOutOfBounds(idx);
+    }
+
+    @Parameter public int index;
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        int[] values = {Integer.MIN_VALUE, -42, -1, 0, 1, 42, Integer.MAX_VALUE};
+
+        ArrayList<Object[]> ret = new ArrayList<>(values.length);
+        for (int i : values) {
+            ret.add(new Object[]{i});
+        }
+        return ret;
+    }
+
+    @Test
+    public void testOutOfBoundsException() {
+        test("oobSnippet", index);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfDynamicTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfDynamicTest.java
new file mode 100644
index 0000000..5495e02
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfDynamicTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+
+/**
+ * Tests for {@link InstanceOfDynamicNode}.
+ */
+public class InstanceOfDynamicTest extends GraalCompilerTest {
+
+    public static int id(int value) {
+        return value;
+    }
+
+    @Test
+    public void test100() {
+        final Object nul = null;
+        test("isStringDynamic", nul);
+        test("isStringDynamic", "object");
+        test("isStringDynamic", Object.class);
+    }
+
+    @Test
+    public void test101() {
+        final Object nul = null;
+        test("isStringIntDynamic", nul);
+        test("isStringIntDynamic", "object");
+        test("isStringIntDynamic", Object.class);
+    }
+
+    @Test
+    public void test103() {
+        test("isInstanceDynamic", String.class, null);
+        test("isInstanceDynamic", String.class, "object");
+        test("isInstanceDynamic", String.class, Object.class);
+        test("isInstanceDynamic", int.class, null);
+        test("isInstanceDynamic", int.class, "Object");
+        test("isInstanceDynamic", int.class, Object.class);
+    }
+
+    @Test
+    public void test104() {
+        test("isInstanceIntDynamic", String.class, null);
+        test("isInstanceIntDynamic", String.class, "object");
+        test("isInstanceIntDynamic", String.class, Object.class);
+        test("isInstanceIntDynamic", int.class, null);
+        test("isInstanceIntDynamic", int.class, "Object");
+        test("isInstanceIntDynamic", int.class, Object.class);
+    }
+
+    public static boolean isStringDynamic(Object o) {
+        return String.class.isInstance(o);
+    }
+
+    public static int isStringIntDynamic(Object o) {
+        if (String.class.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+
+    public static boolean isInstanceDynamic(Class<?> c, Object o) {
+        return c.isInstance(o);
+    }
+
+    public static int isInstanceIntDynamic(Class<?> c, Object o) {
+        if (c.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java
new file mode 100644
index 0000000..f761931
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.code.site.Site;
+import jdk.vm.ci.meta.JavaTypeProfile;
+
+/**
+ * Tests the implementation of instanceof, allowing profiling information to be manually specified.
+ */
+public class InstanceOfTest extends TypeCheckTest {
+
+    public InstanceOfTest() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+    }
+
+    @Override
+    protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
+        InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first();
+        if (ion != null) {
+            ion.setProfile(profile, graph.start());
+        }
+    }
+
+    @Test
+    public void test1() {
+        test("isString", profile(), "object");
+        test("isString", profile(String.class), "object");
+
+        test("isString", profile(), Object.class);
+        test("isString", profile(String.class), Object.class);
+    }
+
+    @Test
+    public void test2() {
+        test("isStringInt", profile(), "object");
+        test("isStringInt", profile(String.class), "object");
+
+        test("isStringInt", profile(), Object.class);
+        test("isStringInt", profile(String.class), Object.class);
+    }
+
+    @Test
+    public void test201() {
+        test("isStringIntComplex", profile(), "object");
+        test("isStringIntComplex", profile(String.class), "object");
+
+        test("isStringIntComplex", profile(), Object.class);
+        test("isStringIntComplex", profile(String.class), Object.class);
+    }
+
+    @Test
+    public void test3() {
+        Throwable throwable = new Exception();
+        test("isThrowable", profile(), throwable);
+        test("isThrowable", profile(Throwable.class), throwable);
+        test("isThrowable", profile(Exception.class, Error.class), throwable);
+
+        test("isThrowable", profile(), Object.class);
+        test("isThrowable", profile(Throwable.class), Object.class);
+        test("isThrowable", profile(Exception.class, Error.class), Object.class);
+    }
+
+    @Test
+    public void test301() {
+        onlyFirstIsException(new Exception(), new Error());
+        test("onlyFirstIsException", profile(), new Exception(), new Error());
+        test("onlyFirstIsException", profile(), new Error(), new Exception());
+        test("onlyFirstIsException", profile(), new Exception(), new Exception());
+        test("onlyFirstIsException", profile(), new Error(), new Error());
+    }
+
+    @Test
+    public void test4() {
+        Throwable throwable = new Exception();
+        test("isThrowableInt", profile(), throwable);
+        test("isThrowableInt", profile(Throwable.class), throwable);
+        test("isThrowableInt", profile(Exception.class, Error.class), throwable);
+
+        test("isThrowableInt", profile(), Object.class);
+        test("isThrowableInt", profile(Throwable.class), Object.class);
+        test("isThrowableInt", profile(Exception.class, Error.class), Object.class);
+    }
+
+    @Test
+    public void test5() {
+        Map<?, ?> map = new HashMap<>();
+        test("isMap", profile(), map);
+        test("isMap", profile(HashMap.class), map);
+        test("isMap", profile(TreeMap.class, HashMap.class), map);
+
+        test("isMap", profile(), Object.class);
+        test("isMap", profile(HashMap.class), Object.class);
+        test("isMap", profile(TreeMap.class, HashMap.class), Object.class);
+        test("isMap", profile(String.class, HashMap.class), Object.class);
+    }
+
+    @Test
+    public void test6() {
+        Map<?, ?> map = new HashMap<>();
+        test("isMapInt", profile(), map);
+        test("isMapInt", profile(HashMap.class), map);
+        test("isMapInt", profile(TreeMap.class, HashMap.class), map);
+
+        test("isMapInt", profile(), Object.class);
+        test("isMapInt", profile(HashMap.class), Object.class);
+        test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class);
+    }
+
+    @Test
+    public void test7() {
+        Object o = new Depth13();
+        test("isDepth12", profile(), o);
+        test("isDepth12", profile(Depth13.class), o);
+        test("isDepth12", profile(Depth13.class, Depth14.class), o);
+
+        o = "not a depth";
+        test("isDepth12", profile(), o);
+        test("isDepth12", profile(Depth13.class), o);
+        test("isDepth12", profile(Depth13.class, Depth14.class), o);
+        test("isDepth12", profile(String.class, HashMap.class), o);
+    }
+
+    @Test
+    public void test8() {
+        Object o = new Depth13();
+        test("isDepth12Int", profile(), o);
+        test("isDepth12Int", profile(Depth13.class), o);
+        test("isDepth12Int", profile(Depth13.class, Depth14.class), o);
+
+        o = "not a depth";
+        test("isDepth12Int", profile(), o);
+        test("isDepth12Int", profile(Depth13.class), o);
+        test("isDepth12Int", profile(Depth13.class, Depth14.class), o);
+    }
+
+    public static boolean isString(Object o) {
+        return o instanceof String;
+    }
+
+    public static int isStringInt(Object o) {
+        if (o instanceof String) {
+            return id(1);
+        }
+        return id(0);
+    }
+
+    public static int isStringIntComplex(Object o) {
+        if (o instanceof String || o instanceof Integer) {
+            return id(o instanceof String ? 1 : 0);
+        }
+        return id(0);
+    }
+
+    public static int id(int value) {
+        return value;
+    }
+
+    public static boolean isThrowable(Object o) {
+        return ((Throwable) o) instanceof Exception;
+    }
+
+    public static int onlyFirstIsException(Throwable t1, Throwable t2) {
+        if (t1 instanceof Exception ^ t2 instanceof Exception) {
+            return t1 instanceof Exception ? 1 : -1;
+        }
+        return -1;
+    }
+
+    public static int isThrowableInt(Object o) {
+        int result = o instanceof Throwable ? 4 : 5;
+        if (o instanceof Throwable) {
+            return id(4);
+        }
+        return result;
+    }
+
+    public static boolean isMap(Object o) {
+        return o instanceof Map;
+    }
+
+    public static int isMapInt(Object o) {
+        if (o instanceof Map) {
+            return id(1);
+        }
+        return id(0);
+    }
+
+    public static boolean isDepth12(Object o) {
+        return o instanceof Depth12;
+    }
+
+    public static int isDepth12Int(Object o) {
+        if (o instanceof Depth12) {
+            return id(0);
+        }
+        return id(0);
+    }
+
+    abstract static class MySite {
+
+        final int offset;
+
+        MySite(int offset) {
+            this.offset = offset;
+        }
+    }
+
+    static class MyMark extends MySite {
+
+        MyMark(int offset) {
+            super(offset);
+        }
+    }
+
+    abstract static class MySafepoint extends MySite {
+
+        MySafepoint(int offset) {
+            super(offset);
+        }
+    }
+
+    static class MyCall extends MySafepoint {
+
+        MyCall(int offset) {
+            super(offset);
+        }
+    }
+
+    @Test
+    public void test9() {
+        MyCall callAt63 = new MyCall(63);
+        MyMark markAt63 = new MyMark(63);
+        test("compareMySites", callAt63, callAt63);
+        test("compareMySites", callAt63, markAt63);
+        test("compareMySites", markAt63, callAt63);
+        test("compareMySites", markAt63, markAt63);
+    }
+
+    public static int compareMySites(MySite s1, MySite s2) {
+        if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) {
+            return s1 instanceof MyMark ? -1 : 1;
+        }
+        return s1.offset - s2.offset;
+    }
+
+    @Test
+    public void test10() {
+        Call callAt63 = new Call(null, 63, 5, true, null);
+        Mark markAt63 = new Mark(63, "1");
+        test("compareSites", callAt63, callAt63);
+        test("compareSites", callAt63, markAt63);
+        test("compareSites", markAt63, callAt63);
+        test("compareSites", markAt63, markAt63);
+    }
+
+    public static int compareSites(Site s1, Site s2) {
+        if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) {
+            return s1 instanceof Mark ? -1 : 1;
+        }
+        return s1.pcOffset - s2.pcOffset;
+    }
+
+    /**
+     * This test exists to show the kind of pattern that is be optimizable by
+     * {@code removeIntermediateMaterialization()} in {@link IfNode}.
+     * <p>
+     * The test exists in this source file as the transformation was originally motivated by the
+     * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}.
+     */
+    @Test
+    public void testRemoveIntermediateMaterialization() {
+        List<String> list = Arrays.asList("1", "2", "3", "4");
+        test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no");
+        test("removeIntermediateMaterialization", profile(), list, null, "yes", "no");
+        test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no");
+    }
+
+    public static String removeIntermediateMaterialization(List<Object> list, Object e, String a, String b) {
+        boolean test;
+        if (list == null || e == null) {
+            test = false;
+        } else {
+            test = false;
+            for (Object i : list) {
+                if (i.equals(e)) {
+                    test = true;
+                    break;
+                }
+            }
+        }
+        if (test) {
+            return a;
+        }
+        return b;
+    }
+
+    abstract static class A {
+    }
+
+    static class B extends A {
+    }
+
+    static class C extends B {
+    }
+
+    abstract static class D extends C {
+    }
+
+    public static boolean isArrayOfA(Object o) {
+        return o instanceof A[];
+    }
+
+    public static boolean isArrayOfB(Object o) {
+        return o instanceof B[];
+    }
+
+    public static boolean isArrayOfC(Object o) {
+        return o instanceof C[];
+    }
+
+    public static boolean isArrayOfD(Object o) {
+        return o instanceof D[];
+    }
+
+    @Test
+    public void testArray() {
+        Object aArray = new A[10];
+        test("isArrayOfA", aArray);
+
+        Object bArray = new B[10];
+        test("isArrayOfA", aArray);
+        test("isArrayOfA", bArray);
+        test("isArrayOfB", aArray);
+        test("isArrayOfB", bArray);
+
+        Object cArray = new C[10];
+        test("isArrayOfA", aArray);
+        test("isArrayOfA", bArray);
+        test("isArrayOfA", cArray);
+        test("isArrayOfB", aArray);
+        test("isArrayOfB", bArray);
+        test("isArrayOfB", cArray);
+        test("isArrayOfC", aArray);
+        test("isArrayOfC", bArray);
+        test("isArrayOfC", cArray);
+
+        Object dArray = new D[10];
+        test("isArrayOfA", aArray);
+        test("isArrayOfA", bArray);
+        test("isArrayOfA", cArray);
+        test("isArrayOfA", dArray);
+        test("isArrayOfB", aArray);
+        test("isArrayOfB", bArray);
+        test("isArrayOfB", cArray);
+        test("isArrayOfB", dArray);
+        test("isArrayOfC", aArray);
+        test("isArrayOfC", bArray);
+        test("isArrayOfC", cArray);
+        test("isArrayOfC", dArray);
+        test("isArrayOfD", aArray);
+        test("isArrayOfD", bArray);
+        test("isArrayOfD", cArray);
+        test("isArrayOfD", dArray);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> String arrayCopyTypeName(T[] original) {
+        Class<? extends T[]> newType = (Class<? extends T[]>) original.getClass();
+        if (newType == (Object) Object[].class) {
+            return Object[].class.getName();
+        } else {
+            return newType.getName();
+        }
+    }
+
+    @Test
+    public void testArrayCopy() {
+        test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"});
+        test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"});
+    }
+
+    public int conditionalInstantiation(Object o) {
+        int total = 0;
+        if (o instanceof CharSequence) {
+            if (o instanceof StringBuilder || o instanceof String) {
+                total = 9;
+            }
+            total += (o instanceof String ? 2 : 1);
+        }
+
+        return total;
+    }
+
+    @Test
+    public void testInstantiation() {
+        test("conditionalInstantiation", "foo");
+        test("conditionalInstantiation", new StringBuilder());
+        test("conditionalInstantiation", 1);
+    }
+
+    public boolean exactlyObject(Thread thread) {
+        return thread != null && ((Object) thread).getClass() == Object.class;
+    }
+
+    public boolean exactlyObjectArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads).getClass() == Object[].class;
+    }
+
+    public boolean exactlyString(Thread thread) {
+        return thread != null && ((Object) thread).getClass() == String.class;
+    }
+
+    public boolean exactlyStringArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads).getClass() == String[].class;
+    }
+
+    @SuppressWarnings("cast")
+    public boolean instanceofStringArray(Thread[] threads) {
+        return threads != null && ((Object[]) threads) instanceof String[];
+    }
+
+    @SuppressWarnings("cast")
+    public boolean instanceofString(Thread thread) {
+        return thread != null && ((Object) thread) instanceof String;
+    }
+
+    @Test
+    public void testTypeCheck() {
+        testConstantReturn("exactlyObject", 0);
+        testConstantReturn("exactlyObjectArray", 0);
+        testConstantReturn("exactlyString", 0);
+        testConstantReturn("exactlyStringArray", 0);
+        testConstantReturn("instanceofString", 0);
+        testConstantReturn("instanceofStringArray", 0);
+    }
+
+    private void testConstantReturn(String name, Object value) {
+        StructuredGraph result = buildGraph(name);
+        ReturnNode ret = result.getNodes(ReturnNode.TYPE).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count());
+
+        assertDeepEquals(true, ret.result().isConstant());
+        assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
+    }
+
+    @SuppressWarnings("try")
+    protected StructuredGraph buildGraph(final String snippet) {
+        try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    static class Depth1 implements Cloneable {
+    }
+
+    static class Depth2 extends Depth1 {
+    }
+
+    static class Depth3 extends Depth2 {
+    }
+
+    static class Depth4 extends Depth3 {
+    }
+
+    static class Depth5 extends Depth4 {
+    }
+
+    static class Depth6 extends Depth5 {
+    }
+
+    static class Depth7 extends Depth6 {
+    }
+
+    static class Depth8 extends Depth7 {
+    }
+
+    static class Depth9 extends Depth8 {
+    }
+
+    static class Depth10 extends Depth9 {
+    }
+
+    static class Depth11 extends Depth10 {
+    }
+
+    static class Depth12 extends Depth11 {
+    }
+
+    static class Depth13 extends Depth12 {
+    }
+
+    static class Depth14 extends Depth12 {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerMulExactFoldTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerMulExactFoldTest.java
new file mode 100644
index 0000000..4cd8f3c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerMulExactFoldTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode;
+
+@RunWith(Parameterized.class)
+public class IntegerMulExactFoldTest extends GraalCompilerTest {
+
+    public static int SideEffectI;
+    public static long SideEffectL;
+
+    public static void snippetInt(int a, int b) {
+        SideEffectI = Math.multiplyExact(a, b);
+    }
+
+    public static void snippetLong(long a, long b) {
+        SideEffectL = Math.multiplyExact(a, b);
+    }
+
+    private StructuredGraph prepareGraph(String snippet) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new CanonicalizerPhase().apply(graph, context);
+        return graph;
+    }
+
+    @Parameter(0) public long lowerBound1;
+    @Parameter(1) public long upperBound1;
+    @Parameter(2) public long lowerBound2;
+    @Parameter(3) public long upperBound2;
+    @Parameter(4) public int bits;
+
+    @Test
+    public void tryFold() {
+        assert bits == 32 || bits == 64;
+
+        IntegerStamp a = StampFactory.forInteger(bits, lowerBound1, upperBound1);
+        IntegerStamp b = StampFactory.forInteger(bits, lowerBound2, upperBound2);
+
+        // prepare the graph once for the given stamps, if the canonicalize method thinks it does
+        // not overflow it will replace the exact mul with a normal mul
+        StructuredGraph g = prepareGraph(bits == 32 ? "snippetInt" : "snippetLong");
+        List<ParameterNode> params = g.getNodes(ParameterNode.TYPE).snapshot();
+        params.get(0).replaceAtMatchingUsages((g.addOrUnique(new PiNode(params.get(0), a))), x -> x instanceof IntegerMulExactNode);
+        params.get(1).replaceAtMatchingUsages((g.addOrUnique(new PiNode(params.get(1), b))), x -> x instanceof IntegerMulExactNode);
+        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        boolean optimized = g.getNodes().filter(IntegerMulExactNode.class).count() == 0;
+        ValueNode leftOverMull = optimized ? g.getNodes().filter(MulNode.class).first() : g.getNodes().filter(IntegerMulExactNode.class).first();
+        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        if (leftOverMull == null) {
+            // result may be constant if there is no mul exact or mul node left
+            leftOverMull = g.getNodes().filter(StoreFieldNode.class).first().inputs().filter(ConstantNode.class).first();
+        }
+        if (leftOverMull == null) {
+            // even mul got canonicalized so we may end up with one of the original nodes
+            leftOverMull = g.getNodes().filter(PiNode.class).first();
+        }
+        IntegerStamp resultStamp = (IntegerStamp) leftOverMull.stamp();
+
+        // now check for all values in the stamp whether their products overflow overflow
+        for (long l1 = lowerBound1; l1 <= upperBound1; l1++) {
+            for (long l2 = lowerBound2; l2 <= upperBound2; l2++) {
+                try {
+                    long res = mulExact(l1, l2, bits);
+                    Assert.assertTrue(resultStamp.contains(res));
+                } catch (ArithmeticException e) {
+                    Assert.assertFalse(optimized);
+                }
+                if (l2 == Long.MAX_VALUE) {
+                    // do not want to overflow the check loop
+                    break;
+                }
+            }
+            if (l1 == Long.MAX_VALUE) {
+                // do not want to overflow the check loop
+                break;
+            }
+        }
+
+    }
+
+    private static long mulExact(long x, long y, int bits) {
+        long r = x * y;
+        if (bits == 8) {
+            if ((byte) r != r) {
+                throw new ArithmeticException("overflow");
+            }
+        } else if (bits == 16) {
+            if ((short) r != r) {
+                throw new ArithmeticException("overflow");
+            }
+        } else if (bits == 32) {
+            return Math.multiplyExact((int) x, (int) y);
+        } else {
+            return Math.multiplyExact(x, y);
+        }
+        return r;
+    }
+
+    @Parameters(name = "a[{0} - {1}] b[{2} - {3}] bits=32")
+    public static Collection<Object[]> data() {
+        ArrayList<Object[]> tests = new ArrayList<>();
+
+        // zero related
+        addTest(tests, -2, 2, 3, 3, 32);
+        addTest(tests, 0, 0, 1, 1, 32);
+        addTest(tests, 1, 1, 0, 0, 32);
+        addTest(tests, -1, 1, 0, 1, 32);
+        addTest(tests, -1, 1, 1, 1, 32);
+        addTest(tests, -1, 1, -1, 1, 32);
+
+        addTest(tests, -2, 2, 3, 3, 64);
+        addTest(tests, 0, 0, 1, 1, 64);
+        addTest(tests, 1, 1, 0, 0, 64);
+        addTest(tests, -1, 1, 0, 1, 64);
+        addTest(tests, -1, 1, 1, 1, 64);
+        addTest(tests, -1, 1, -1, 1, 64);
+
+        addTest(tests, -2, 2, 3, 3, 32);
+        addTest(tests, 0, 0, 1, 1, 32);
+        addTest(tests, 1, 1, 0, 0, 32);
+        addTest(tests, -1, 1, 0, 1, 32);
+        addTest(tests, -1, 1, 1, 1, 32);
+        addTest(tests, -1, 1, -1, 1, 32);
+
+        addTest(tests, 0, 0, 1, 1, 64);
+        addTest(tests, 1, 1, 0, 0, 64);
+        addTest(tests, -1, 1, 0, 1, 64);
+        addTest(tests, -1, 1, 1, 1, 64);
+        addTest(tests, -1, 1, -1, 1, 64);
+
+        // bounds
+        addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF,
+                        Integer.MAX_VALUE, 32);
+        addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 32);
+        addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFF, Integer.MAX_VALUE - 0xFF,
+                        Integer.MAX_VALUE, 64);
+        addTest(tests, Integer.MIN_VALUE, Integer.MIN_VALUE + 0xFFF, -1, -1, 64);
+        addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE + 0xFFF, -1, -1, 64);
+
+        // constants
+        addTest(tests, 2, 2, 2, 2, 32);
+        addTest(tests, 1, 1, 2, 2, 32);
+        addTest(tests, 2, 2, 4, 4, 32);
+        addTest(tests, 3, 3, 3, 3, 32);
+        addTest(tests, -4, -4, 3, 3, 32);
+        addTest(tests, -4, -4, -3, -3, 32);
+        addTest(tests, 4, 4, -3, -3, 32);
+
+        addTest(tests, 2, 2, 2, 2, 64);
+        addTest(tests, 1, 1, 2, 2, 64);
+        addTest(tests, 3, 3, 3, 3, 64);
+
+        addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, 1, 1, 64);
+        addTest(tests, Long.MAX_VALUE, Long.MAX_VALUE, -1, -1, 64);
+        addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, -1, -1, 64);
+        addTest(tests, Long.MIN_VALUE, Long.MIN_VALUE, 1, 1, 64);
+
+        return tests;
+    }
+
+    private static void addTest(ArrayList<Object[]> tests, long lowerBound1, long upperBound1, long lowerBound2, long upperBound2, int bits) {
+        tests.add(new Object[]{lowerBound1, upperBound1, lowerBound2, upperBound2, bits});
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerSubOverflowsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerSubOverflowsTest.java
new file mode 100644
index 0000000..5b14c64
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerSubOverflowsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+
+public class IntegerSubOverflowsTest {
+
+    @Test
+    public void testOverflowCheck() {
+        long a = Integer.MIN_VALUE;
+        long b = -1;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck01() {
+        long a = Integer.MAX_VALUE;
+        long b = Integer.MAX_VALUE;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck02() {
+        long a = Integer.MIN_VALUE;
+        long b = Integer.MIN_VALUE;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck03() {
+        long a = Integer.MIN_VALUE;
+        long b = 1;
+        Assert.assertTrue(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck04() {
+        long a = Integer.MAX_VALUE;
+        long b = 1;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck05() {
+        long a = Integer.MAX_VALUE;
+        long b = Integer.MIN_VALUE;
+        Assert.assertTrue(IntegerStamp.subtractionOverflows(a, b, 32));
+    }
+
+    @Test
+    public void testOverflowCheck06() {
+        long a = Integer.MAX_VALUE;
+        long b = Integer.MAX_VALUE;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheck07() {
+        long a = Long.MAX_VALUE;
+        long b = 2;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheck08() {
+        long a = Long.MAX_VALUE;
+        long b = Long.MAX_VALUE;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheck09() {
+        long a = -Long.MAX_VALUE;
+        long b = Long.MAX_VALUE;
+        Assert.assertTrue(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheck10() {
+        long a = -Long.MAX_VALUE;
+        long b = -Long.MAX_VALUE;
+        Assert.assertFalse(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheck11() {
+        long a = Long.MAX_VALUE;
+        long b = -Long.MAX_VALUE;
+        Assert.assertTrue(IntegerStamp.subtractionOverflows(a, b, 64));
+    }
+
+    @Test
+    public void testOverflowCheckStamp() {
+        IntegerStamp s1 = StampFactory.forInteger(32, Integer.MIN_VALUE, Integer.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(32, -1, -1);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp01() {
+        IntegerStamp s1 = StampFactory.forInteger(32, Integer.MAX_VALUE, Integer.MAX_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(32, Integer.MAX_VALUE, Integer.MAX_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp02() {
+        IntegerStamp s1 = StampFactory.forInteger(32, Integer.MIN_VALUE, Integer.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(32, Integer.MIN_VALUE, Integer.MIN_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp03() {
+        IntegerStamp s1 = StampFactory.forInteger(32, Integer.MIN_VALUE, Integer.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(32, 1, 1);
+        Assert.assertTrue(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp04() {
+        IntegerStamp s1 = StampFactory.forInteger(8, Byte.MIN_VALUE, Byte.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(8, -1, -1);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp05() {
+        IntegerStamp s1 = StampFactory.forInteger(8, Byte.MAX_VALUE, Byte.MAX_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(8, Byte.MAX_VALUE, Byte.MAX_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp06() {
+        IntegerStamp s1 = StampFactory.forInteger(8, Byte.MIN_VALUE, Byte.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(8, Byte.MIN_VALUE, Byte.MIN_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp07() {
+        IntegerStamp s1 = StampFactory.forInteger(8, Byte.MIN_VALUE, Byte.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(8, 1, 1);
+        Assert.assertTrue(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp08() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, -1, -1);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp09() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MAX_VALUE, Long.MAX_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, Long.MAX_VALUE, Long.MAX_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp10() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MIN_VALUE);
+        Assert.assertFalse(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowCheckStamp11() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MIN_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, 1, 1);
+        Assert.assertTrue(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowBIgStamps01() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MAX_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MAX_VALUE);
+        Assert.assertTrue(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+
+    @Test
+    public void testOverflowBIgStamps02() {
+        IntegerStamp s1 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MAX_VALUE);
+        IntegerStamp s2 = StampFactory.forInteger(64, Long.MIN_VALUE, Long.MIN_VALUE);
+        Assert.assertTrue(IntegerStamp.subtractionCanOverflow(s1, s2));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InvokeTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InvokeTest.java
new file mode 100644
index 0000000..155540b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InvokeTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+
+/**
+ * Tests the implementation of the snippets for lowering the INVOKE* instructions.
+ */
+public class InvokeTest extends GraalCompilerTest {
+
+    public InvokeTest() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+    }
+
+    public interface I {
+
+        String virtualMethod(String s);
+    }
+
+    public static class A implements I {
+
+        final String name = "A";
+
+        @Override
+        public String virtualMethod(String s) {
+            return name + s;
+        }
+    }
+
+    @SuppressWarnings("static-method")
+    private String privateMethod(String s) {
+        return s;
+    }
+
+    @Test
+    public void test1() {
+        test("invokestatic", "a string");
+        test("invokespecialConstructor", "a string");
+        test("invokespecial", this, "a string");
+        test("invokevirtual", new A(), "a string");
+        test("invokevirtual2", new A(), "a string");
+        test("invokeinterface", new A(), "a string");
+        Object[] args = {null};
+        test("invokestatic", args);
+        test("invokespecialConstructor", args);
+        test("invokespecial", null, null);
+        test("invokevirtual", null, null);
+        test("invokevirtual2", null, null);
+        test("invokeinterface", null, null);
+    }
+
+    public static String invokestatic(String s) {
+        return staticMethod(s);
+    }
+
+    public static String staticMethod(String s) {
+        return s;
+    }
+
+    public static String invokespecialConstructor(String s) {
+        return new A().virtualMethod(s);
+    }
+
+    public static String invokespecial(InvokeTest a, String s) {
+        return a.privateMethod(s);
+    }
+
+    public static String invokevirtual(A a, String s) {
+        return a.virtualMethod(s);
+    }
+
+    public static String invokevirtual2(A a, String s) {
+        a.virtualMethod(s);
+        return a.virtualMethod(s);
+    }
+
+    public static String invokeinterface(I i, String s) {
+        return i.virtualMethod(s);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java
new file mode 100644
index 0000000..6300eaa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.replacements.nodes.MacroNode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that
+ * there are no remaining invocations in the graph. This is sufficient if the method that is being
+ * substituted is a native method. For Java methods, additional checks are necessary.
+ */
+public abstract class MethodSubstitutionTest extends GraalCompilerTest {
+
+    @SuppressWarnings("try")
+    protected StructuredGraph testGraph(final String snippet) {
+        try (Scope s = Debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            HighTierContext context = getDefaultHighTierContext();
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+            new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+            new CanonicalizerPhase().apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
+            // Try to ensure any macro nodes are lowered to expose any resulting invokes
+            if (graph.getNodes().filter(MacroNode.class).isNotEmpty()) {
+                new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            }
+            if (graph.getNodes().filter(MacroNode.class).isNotEmpty()) {
+                new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+            }
+            assertNotInGraph(graph, MacroNode.class);
+            assertNotInGraph(graph, Invoke.class);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    protected void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, Class<?>[] parameterTypes, boolean optional, Object[] args1, Object[] args2) {
+        ResolvedJavaMethod realMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
+
+        // Check to see if the resulting graph contains the expected node
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
+        if (replacement == null && !optional) {
+            assertInGraph(graph, intrinsicClass);
+        }
+
+        // Force compilation
+        InstalledCode code = getCode(testMethod);
+        assert optional || code != null;
+
+        for (int i = 0; i < args1.length; i++) {
+            Object arg1 = args1[i];
+            Object arg2 = args2[i];
+            Object expected = invokeSafe(realMethod, null, arg1, arg2);
+            // Verify that the original method and the substitution produce the same value
+            assertDeepEquals(expected, invokeSafe(testMethod, null, arg1, arg2));
+            // Verify that the generated code and the original produce the same value
+            assertDeepEquals(expected, executeVarargsSafe(code, arg1, arg2));
+        }
+    }
+
+    protected static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                return graph;
+            }
+        }
+        fail("Graph does not contain a node of class " + clazz.getName());
+        return graph;
+    }
+
+    protected static Object executeVarargsSafe(InstalledCode code, Object... args) {
+        try {
+            return code.executeVarargs(args);
+        } catch (InvalidInstalledCodeException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected Object invokeSafe(ResolvedJavaMethod method, Object receiver, Object... args) {
+        try {
+            return invoke(method, receiver, args);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java
new file mode 100644
index 0000000..8b8659a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.replacements.BoxingSnippets;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+
+public class MonitorTest extends GraalCompilerTest {
+
+    @Test
+    public void test0() {
+        test("lockObjectSimple", new Object(), new Object());
+        test("lockObjectSimple", new Object(), null);
+        test("lockObjectSimple", null, null);
+    }
+
+    @Test
+    public void test01() {
+        test("lockThisSimple", "test1", new Object());
+        test("lockThisSimple", "test1", null);
+    }
+
+    @Test
+    public void test02() {
+        test("lockObjectSimple", null, "test1");
+    }
+
+    @Test
+    public void test101() {
+        test("lockObject", new Object(), "test1", new String[1]);
+    }
+
+    @Test
+    public void test102() {
+        test("lockObject", null, "test1_1", new String[1]);
+    }
+
+    @Test
+    public void test2() {
+        test("lockThis", "test2", new String[1]);
+    }
+
+    /**
+     * Tests monitor operations on {@link PartialEscapePhase virtual objects}.
+     */
+    @Test
+    public void test3() {
+        test("lockLocalObject", "test3", new String[1]);
+    }
+
+    /**
+     * Tests recursive locking of objects which should be biasable.
+     */
+    @Test
+    public void test4() {
+        Chars src = new Chars("1234567890".toCharArray());
+        Chars dst = new Chars(src.data.length);
+        test("copyObj", src, dst, 100);
+    }
+
+    /**
+     * Tests recursive locking of objects which do not appear to be biasable.
+     */
+    @Test
+    public void test5() {
+        char[] src = "1234567890".toCharArray();
+        char[] dst = new char[src.length];
+        test("copyArr", src, dst, 100);
+    }
+
+    /**
+     * Extends {@link #test4()} with contention.
+     */
+    @Test
+    public void test6() {
+        Chars src = new Chars("1234567890".toCharArray());
+        Chars dst = new Chars(src.data.length);
+        int n = Runtime.getRuntime().availableProcessors();
+        testN(n, "copyObj", src, dst, 100);
+    }
+
+    /**
+     * Extends {@link #test5()} with contention.
+     */
+    @Test
+    public void test7() {
+        char[] src = "1234567890".toCharArray();
+        char[] dst = new char[src.length];
+        int n = Math.min(32, Runtime.getRuntime().availableProcessors());
+        testN(n, "copyArr", src, dst, 100);
+    }
+
+    private static String setAndGet(String[] box, String value) {
+        synchronized (box) {
+            box[0] = null;
+        }
+
+        // Do a GC while a object is locked (by the caller)
+        System.gc();
+
+        synchronized (box) {
+            box[0] = value;
+        }
+        return box[0];
+    }
+
+    public static Object lockObjectSimple(Object o, Object value) {
+        synchronized (o) {
+            value.hashCode();
+            return value;
+        }
+    }
+
+    public String lockThisSimple(String value, Object o) {
+        synchronized (this) {
+            synchronized (value) {
+                o.hashCode();
+                return value;
+            }
+        }
+    }
+
+    public static String lockObject(Object o, String value, String[] box) {
+        synchronized (o) {
+            return setAndGet(box, value);
+        }
+    }
+
+    public String lockThis(String value, String[] box) {
+        synchronized (this) {
+            return setAndGet(box, value);
+        }
+    }
+
+    public static String lockLocalObject(String value, String[] box) {
+        Object o = new Object();
+        synchronized (o) {
+            return setAndGet(box, value);
+        }
+    }
+
+    static class Chars {
+
+        final char[] data;
+
+        Chars(int size) {
+            this.data = new char[size];
+        }
+
+        Chars(char[] data) {
+            this.data = data;
+        }
+    }
+
+    public static String copyObj(Chars src, Chars dst, int n) {
+        for (int j = 0; j < n; j++) {
+            for (int i = 0; i < src.data.length; i++) {
+                synchronized (src) {
+                    synchronized (dst) {
+                        synchronized (src) {
+                            synchronized (dst) {
+                                dst.data[i] = src.data[i];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return new String(dst.data);
+    }
+
+    public static String copyArr(char[] src, char[] dst, int n) {
+        for (int j = 0; j < n; j++) {
+            for (int i = 0; i < src.length; i++) {
+                synchronized (src) {
+                    synchronized (dst) {
+                        synchronized (src) {
+                            synchronized (dst) {
+                                dst[i] = src[i];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return new String(dst);
+    }
+
+    public static String lockBoxedLong(long value) {
+        Long lock = value;
+        synchronized (lock) {
+            return lock.toString();
+        }
+    }
+
+    /**
+     * Reproduces issue reported in https://github.com/graalvm/graal-core/issues/201. The stamp in
+     * the PiNode returned by {@link BoxingSnippets#longValueOf(long)} was overwritten when the node
+     * was subsequently canonicalized because {@code PiNode.computeValue()} ignored the
+     * {@link ValueNode#stamp()} field and used the {@code PiNode.piStamp} field.
+     */
+    @Test
+    public void test8() {
+        test("lockBoxedLong", 5L);
+        test("lockBoxedLong", Long.MAX_VALUE - 1);
+        test("lockBoxedLong", Long.MIN_VALUE + 1);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewArrayTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewArrayTest.java
new file mode 100644
index 0000000..18db0dd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewArrayTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests the implementation of {@code [A]NEWARRAY}.
+ */
+public class NewArrayTest extends GraalCompilerTest {
+
+    @Override
+    protected void assertDeepEquals(Object expected, Object actual) {
+        Assert.assertTrue(expected != null);
+        Assert.assertTrue(actual != null);
+        super.assertDeepEquals(expected.getClass(), actual.getClass());
+        if (expected instanceof int[]) {
+            Assert.assertArrayEquals((int[]) expected, (int[]) actual);
+        } else if (expected instanceof byte[]) {
+            Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
+        } else if (expected instanceof char[]) {
+            Assert.assertArrayEquals((char[]) expected, (char[]) actual);
+        } else if (expected instanceof short[]) {
+            Assert.assertArrayEquals((short[]) expected, (short[]) actual);
+        } else if (expected instanceof float[]) {
+            Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
+        } else if (expected instanceof long[]) {
+            Assert.assertArrayEquals((long[]) expected, (long[]) actual);
+        } else if (expected instanceof double[]) {
+            Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
+        } else if (expected instanceof Object[]) {
+            Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
+        } else {
+            Assert.fail("non-array value encountered: " + expected);
+        }
+    }
+
+    @Test
+    public void test1() {
+        for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) {
+            test("new" + type + "Array7");
+            test("new" + type + "ArrayMinus7");
+            test("new" + type + "Array", 7);
+            test("new" + type + "Array", -7);
+            test("new" + type + "Array", Integer.MAX_VALUE);
+            test("new" + type + "Array", Integer.MIN_VALUE);
+        }
+    }
+
+    public static Object newCharArray7() {
+        return new char[7];
+    }
+
+    public static Object newCharArrayMinus7() {
+        return new char[-7];
+    }
+
+    public static Object newCharArray(int length) {
+        return new char[length];
+    }
+
+    public static Object newShortArray7() {
+        return new short[7];
+    }
+
+    public static Object newShortArrayMinus7() {
+        return new short[-7];
+    }
+
+    public static Object newShortArray(int length) {
+        return new short[length];
+    }
+
+    public static Object newFloatArray7() {
+        return new float[7];
+    }
+
+    public static Object newFloatArrayMinus7() {
+        return new float[-7];
+    }
+
+    public static Object newFloatArray(int length) {
+        return new float[length];
+    }
+
+    public static Object newLongArray7() {
+        return new long[7];
+    }
+
+    public static Object newLongArrayMinus7() {
+        return new long[-7];
+    }
+
+    public static Object newLongArray(int length) {
+        return new long[length];
+    }
+
+    public static Object newDoubleArray7() {
+        return new double[7];
+    }
+
+    public static Object newDoubleArrayMinus7() {
+        return new double[-7];
+    }
+
+    public static Object newDoubleArray(int length) {
+        return new double[length];
+    }
+
+    public static Object newIntArray7() {
+        return new int[7];
+    }
+
+    public static Object newIntArrayMinus7() {
+        return new int[-7];
+    }
+
+    public static Object newIntArray(int length) {
+        return new int[length];
+    }
+
+    public static Object newByteArray7() {
+        return new byte[7];
+    }
+
+    public static Object newByteArrayMinus7() {
+        return new byte[-7];
+    }
+
+    public static Object newByteArray(int length) {
+        return new byte[length];
+    }
+
+    public static Object newStringArray7() {
+        return new String[7];
+    }
+
+    public static Object newStringArrayMinus7() {
+        return new String[-7];
+    }
+
+    public static Object newStringArray(int length) {
+        return new String[length];
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewInstanceTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewInstanceTest.java
new file mode 100644
index 0000000..93186de
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewInstanceTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.HashMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests the implementation of {@code NEW}.
+ */
+public class NewInstanceTest extends GraalCompilerTest {
+
+    @Override
+    protected void assertDeepEquals(Object expected, Object actual) {
+        Assert.assertTrue(expected != null);
+        Assert.assertTrue(actual != null);
+        super.assertDeepEquals(expected.getClass(), actual.getClass());
+
+        if (expected instanceof Object[]) {
+            Assert.assertTrue(actual instanceof Object[]);
+            Object[] eArr = (Object[]) expected;
+            Object[] aArr = (Object[]) actual;
+            Assert.assertTrue(eArr.length == aArr.length);
+            for (int i = 0; i < eArr.length; i++) {
+                assertDeepEquals(eArr[i], aArr[i]);
+            }
+        } else if (expected.getClass() != Object.class) {
+            try {
+                expected.getClass().getDeclaredMethod("equals", Object.class);
+                super.assertDeepEquals(expected, actual);
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    @Test
+    public void test1() {
+        test("newObject");
+    }
+
+    @Test
+    public void test2() {
+        test("newObjectTwice");
+    }
+
+    public static Object newObject() {
+        return new Object();
+    }
+
+    @Test
+    public void test3() {
+        test("newObjectLoop", 100);
+    }
+
+    @Test
+    public void test4() {
+        test("newBigObject");
+    }
+
+    @Test
+    public void test5() {
+        test("newSomeObject");
+    }
+
+    @Test
+    public void test6() {
+        test("newEmptyString");
+    }
+
+    @Test
+    public void test7() {
+        test("newString", "value");
+    }
+
+    @Test
+    public void test8() {
+        test("newHashMap", 31);
+    }
+
+    @Test
+    public void test9() {
+        test("newRegression", true);
+    }
+
+    public static Object[] newObjectTwice() {
+        Object[] res = {new Object(), new Object()};
+        return res;
+    }
+
+    public static Object[] newObjectLoop(int n) {
+        Object[] res = new Object[n];
+        for (int i = 0; i < n; i++) {
+            res[i] = new Object();
+        }
+        return res;
+    }
+
+    public static BigObject newBigObject() {
+        return new BigObject();
+    }
+
+    public static SomeObject newSomeObject() {
+        return new SomeObject();
+    }
+
+    public static String newEmptyString() {
+        return new String();
+    }
+
+    public static String newString(String value) {
+        return new String(value);
+    }
+
+    public static HashMap<?, ?> newHashMap(int initialCapacity) {
+        return new HashMap<>(initialCapacity);
+    }
+
+    static class SomeObject {
+
+        String name = "o1";
+        HashMap<String, Object> map = new HashMap<>();
+
+        SomeObject() {
+            map.put(name, this.getClass());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof SomeObject) {
+                SomeObject so = (SomeObject) obj;
+                return so.name.equals(name) && so.map.equals(map);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+    }
+
+    static class BigObject {
+
+        Object f01;
+        Object f02;
+        Object f03;
+        Object f04;
+        Object f05;
+        Object f06;
+        Object f07;
+        Object f08;
+        Object f09;
+        Object f10;
+        Object f12;
+        Object f13;
+        Object f14;
+        Object f15;
+        Object f16;
+        Object f17;
+        Object f18;
+        Object f19;
+        Object f20;
+        Object f21;
+        Object f22;
+        Object f23;
+        Object f24;
+        Object f25;
+        Object f26;
+        Object f27;
+        Object f28;
+        Object f29;
+        Object f30;
+        Object f31;
+        Object f32;
+        Object f33;
+        Object f34;
+        Object f35;
+        Object f36;
+        Object f37;
+        Object f38;
+        Object f39;
+        Object f40;
+        Object f41;
+        Object f42;
+        Object f43;
+        Object f44;
+        Object f45;
+    }
+
+    /**
+     * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top'
+     * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the
+     * allocated B object in the true branch overwrote the allocated array. The cause is that
+     * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also
+     * floating. The fix was to make RegisterNode a fixed node (which it should have been in the
+     * first place).
+     */
+    public static Object newRegression(boolean condition) {
+        Object result;
+        if (condition) {
+            Object[] arr = {0, 1, 2, 3, 4, 5};
+            result = new B();
+            for (int i = 0; i < arr.length; ++i) {
+                // If the bug exists, the values of arr will now be deadbeef values
+                // and the virtual dispatch will cause a segfault. This can result in
+                // either a VM crash or a spurious NullPointerException.
+                if (arr[i].equals(Integer.valueOf(i))) {
+                    return false;
+                }
+            }
+        } else {
+            result = new B();
+        }
+        return result;
+    }
+
+    static class B {
+
+        long f1 = 0xdeadbeefdeadbe01L;
+        long f2 = 0xdeadbeefdeadbe02L;
+        long f3 = 0xdeadbeefdeadbe03L;
+        long f4 = 0xdeadbeefdeadbe04L;
+        long f5 = 0xdeadbeefdeadbe05L;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewMultiArrayTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewMultiArrayTest.java
new file mode 100644
index 0000000..591a3af
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NewMultiArrayTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Tests the lowering of the MULTIANEWARRAY instruction.
+ */
+public class NewMultiArrayTest extends GraalCompilerTest {
+
+    private static int rank(ResolvedJavaType type) {
+        String name = type.getName();
+        int dims = 0;
+        while (dims < name.length() && name.charAt(dims) == '[') {
+            dims++;
+        }
+        return dims;
+    }
+
+    @Override
+    protected InstalledCode getCode(final ResolvedJavaMethod method, StructuredGraph g) {
+        StructuredGraph graph = g == null ? parseForCompile(method) : g;
+        boolean forceCompile = false;
+        if (bottomType != null) {
+            List<NewMultiArrayNode> snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot();
+            assert snapshot != null;
+            assert snapshot.size() == 1;
+
+            NewMultiArrayNode node = snapshot.get(0);
+            assert rank(arrayType) == dimensions.length;
+            int rank = dimensions.length;
+            ValueNode[] dimensionNodes = new ValueNode[rank];
+            for (int i = 0; i < rank; i++) {
+                dimensionNodes[i] = ConstantNode.forInt(dimensions[i], graph);
+            }
+
+            NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes));
+            graph.replaceFixedWithFixed(node, repl);
+            forceCompile = true;
+        }
+        return super.getCode(method, graph, forceCompile);
+    }
+
+    @Override
+    protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        if (bottomType != null) {
+            try {
+                return Array.newInstance(bottomClass, dimensions);
+            } catch (Exception e) {
+                throw new InvocationTargetException(e);
+            }
+        }
+        return super.referenceInvoke(method, receiver, args);
+    }
+
+    ResolvedJavaType arrayType;
+    ResolvedJavaType bottomType;
+    Class<?> bottomClass;
+    int[] dimensions;
+
+    @Test
+    public void test1() {
+        for (Class<?> clazz : new Class<?>[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
+            bottomClass = clazz;
+            bottomType = getMetaAccess().lookupJavaType(clazz);
+            arrayType = bottomType;
+            for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) {
+                while (rank(arrayType) != rank) {
+                    arrayType = arrayType.getArrayClass();
+                }
+
+                dimensions = new int[rank];
+                for (int i = 0; i < rank; i++) {
+                    dimensions[i] = 1;
+                }
+
+                test("newMultiArray");
+            }
+        }
+        bottomType = null;
+        arrayType = null;
+    }
+
+    public static Object newMultiArray() {
+        // This is merely a template - the NewMultiArrayNode is replaced in getCode() above.
+        // This also means we need a separate test for correct handling of negative dimensions
+        // as deoptimization won't do what we want for a graph modified to be different from the
+        // source bytecode.
+        return new Object[10][9][8];
+    }
+
+    @Test
+    public void test2() {
+        test("newMultiArrayException");
+    }
+
+    public static Object newMultiArrayException() {
+        return new Object[10][9][-8];
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java
new file mode 100644
index 0000000..3e78c3e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class NullBytecodeExceptionTest extends BytecodeExceptionTest {
+
+    private static class Exceptions {
+
+        private static Object obj = null;
+
+        public static void throwNull() {
+            obj.toString();
+        }
+    }
+
+    @Override
+    protected void registerPlugin(InvocationPlugins plugins) {
+        plugins.register(new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                return throwBytecodeException(b, NullPointerException.class);
+            }
+        }, Exceptions.class, "throwNull");
+    }
+
+    public static void nullSnippet() {
+        Exceptions.throwNull();
+    }
+
+    @Test
+    public void testNullPointerException() {
+        test("nullSnippet");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java
new file mode 100644
index 0000000..27e6513
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.extended.JavaReadNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.ObjectAccess;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests for the {@link Pointer} read and write operations.
+ */
+public class ObjectAccessTest extends GraalCompilerTest implements Snippets {
+
+    private static final LocationIdentity ID = NamedLocationIdentity.mutable("ObjectAccessTestID");
+    private static final JavaKind[] KINDS = new JavaKind[]{JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Float, JavaKind.Double, JavaKind.Object};
+    private final ReplacementsImpl installer;
+
+    public ObjectAccessTest() {
+        installer = (ReplacementsImpl) getReplacements();
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        return installer.makeGraph(m, null, null);
+    }
+
+    @Test
+    public void testRead1() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead2() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead3() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
+        }
+    }
+
+    @Test
+    public void testWrite1() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "1", AllowAssumptions.YES), true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite2() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "2", AllowAssumptions.YES), true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite3() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any());
+        }
+    }
+
+    private static void assertRead(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        JavaReadNode read = (JavaReadNode) graph.start().next();
+        Assert.assertEquals(kind.getStackKind(), read.stamp().getStackKind());
+
+        OffsetAddressNode address = (OffsetAddressNode) read.getAddress();
+        Assert.assertEquals(graph.getParameter(0), address.getBase());
+        Assert.assertEquals(locationIdentity, read.getLocationIdentity());
+
+        if (indexConvert) {
+            SignExtendNode convert = (SignExtendNode) address.getOffset();
+            Assert.assertEquals(convert.getInputBits(), 32);
+            Assert.assertEquals(convert.getResultBits(), 64);
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
+        } else {
+            Assert.assertEquals(graph.getParameter(1), address.getOffset());
+        }
+
+        ReturnNode ret = (ReturnNode) read.next();
+        Assert.assertEquals(read, ret.result());
+    }
+
+    private static void assertWrite(StructuredGraph graph, boolean indexConvert, LocationIdentity locationIdentity) {
+        JavaWriteNode write = (JavaWriteNode) graph.start().next();
+        Assert.assertEquals(graph.getParameter(2), write.value());
+
+        OffsetAddressNode address = (OffsetAddressNode) write.getAddress();
+        Assert.assertEquals(graph.getParameter(0), address.getBase());
+        Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
+
+        Assert.assertEquals(locationIdentity, write.getLocationIdentity());
+
+        if (indexConvert) {
+            SignExtendNode convert = (SignExtendNode) address.getOffset();
+            Assert.assertEquals(convert.getInputBits(), 32);
+            Assert.assertEquals(convert.getResultBits(), 64);
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
+        } else {
+            Assert.assertEquals(graph.getParameter(1), address.getOffset());
+        }
+
+        ReturnNode ret = (ReturnNode) write.next();
+        Assert.assertEquals(null, ret.result());
+    }
+
+    @Snippet
+    public static byte readByte1(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset, ID);
+    }
+
+    @Snippet
+    public static byte readByte2(Object o, int offset) {
+        return ObjectAccess.readByte(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static byte readByte3(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset);
+    }
+
+    @Snippet
+    public static void writeByte1(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeByte2(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeByte3(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value);
+    }
+
+    @Snippet
+    public static char readChar1(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset, ID);
+    }
+
+    @Snippet
+    public static char readChar2(Object o, int offset) {
+        return ObjectAccess.readChar(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static char readChar3(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset);
+    }
+
+    @Snippet
+    public static void writeChar1(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeChar2(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeChar3(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value);
+    }
+
+    @Snippet
+    public static short readShort1(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset, ID);
+    }
+
+    @Snippet
+    public static short readShort2(Object o, int offset) {
+        return ObjectAccess.readShort(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static short readShort3(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset);
+    }
+
+    @Snippet
+    public static void writeShort1(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeShort2(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeShort3(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value);
+    }
+
+    @Snippet
+    public static int readInt1(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset, ID);
+    }
+
+    @Snippet
+    public static int readInt2(Object o, int offset) {
+        return ObjectAccess.readInt(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static int readInt3(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset);
+    }
+
+    @Snippet
+    public static void writeInt1(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeInt2(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeInt3(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value);
+    }
+
+    @Snippet
+    public static long readLong1(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset, ID);
+    }
+
+    @Snippet
+    public static long readLong2(Object o, int offset) {
+        return ObjectAccess.readLong(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static long readLong3(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset);
+    }
+
+    @Snippet
+    public static void writeLong1(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeLong2(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeLong3(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value);
+    }
+
+    @Snippet
+    public static float readFloat1(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset, ID);
+    }
+
+    @Snippet
+    public static float readFloat2(Object o, int offset) {
+        return ObjectAccess.readFloat(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static float readFloat3(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset);
+    }
+
+    @Snippet
+    public static void writeFloat1(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat2(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat3(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value);
+    }
+
+    @Snippet
+    public static double readDouble1(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset, ID);
+    }
+
+    @Snippet
+    public static double readDouble2(Object o, int offset) {
+        return ObjectAccess.readDouble(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static double readDouble3(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset);
+    }
+
+    @Snippet
+    public static void writeDouble1(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble2(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble3(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value);
+    }
+
+    @Snippet
+    public static Object readObject1(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset, ID);
+    }
+
+    @Snippet
+    public static Object readObject2(Object o, int offset) {
+        return ObjectAccess.readObject(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static Object readObject3(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset);
+    }
+
+    @Snippet
+    public static void writeObject1(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeObject2(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeObject3(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java
new file mode 100644
index 0000000..a54d047
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.replacements.CachingPEGraphDecoder;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class PEGraphDecoderTest extends GraalCompilerTest {
+
+    /**
+     * This method is intrinsified to a node with a guard dependency on the block it is in. The
+     * various tests ensure that this guard is correctly updated when blocks are merged during
+     * inlining.
+     */
+    private static native int readInt(Object obj, long offset);
+
+    private static boolean flag;
+    private static int value;
+
+    private static void invokeSimple() {
+        value = 111;
+    }
+
+    private static void invokeComplicated() {
+        if (flag) {
+            value = 0;
+        } else {
+            value = 42;
+        }
+    }
+
+    private static int readInt1(Object obj) {
+        return readInt(obj, 16);
+    }
+
+    private static int readInt2(Object obj) {
+        invokeSimple();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt3(Object obj) {
+        invokeComplicated();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt4(Object obj, int n) {
+        if (n > 0) {
+            invokeComplicated();
+        }
+        return readInt(obj, 16);
+    }
+
+    public static int doTest(Object obj) {
+        int result = 0;
+        result += readInt1(obj);
+        result += readInt2(obj);
+        result += readInt3(obj);
+        result += readInt4(obj, 2);
+        return result;
+    }
+
+    private static void registerPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, PEGraphDecoderTest.class);
+        r.register2("readInt", Object.class, long.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode obj, ValueNode offset) {
+                AddressNode address = b.add(new OffsetAddressNode(obj, offset));
+                ReadNode read = b.addPush(JavaKind.Int, new ReadNode(address, LocationIdentity.any(), StampFactory.forKind(JavaKind.Int), BarrierType.NONE));
+                read.setGuard(AbstractBeginNode.prevBegin(read));
+                return true;
+            }
+        });
+    }
+
+    class InlineAll implements InlineInvokePlugin {
+        @Override
+        public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+            return createStandardInlineInfo(method);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test() {
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(PEGraphDecoderTest.class, "doTest", Object.class);
+        StructuredGraph targetGraph = null;
+        try (Debug.Scope scope = Debug.scope("GraphPETest", testMethod)) {
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true);
+            registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
+            CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, getTarget().arch);
+
+            targetGraph = new StructuredGraph(testMethod, AllowAssumptions.YES, INVALID_COMPILATION_ID);
+            decoder.decode(targetGraph, testMethod, null, null, new InlineInvokePlugin[]{new InlineAll()}, null);
+            Debug.dump(Debug.BASIC_LOG_LEVEL, targetGraph, "Target Graph");
+            targetGraph.verify();
+
+            PhaseContext context = new PhaseContext(getProviders());
+            new CanonicalizerPhase().apply(targetGraph, context);
+            targetGraph.verify();
+
+        } catch (Throwable ex) {
+            if (targetGraph != null) {
+                Debug.dump(Debug.BASIC_LOG_LEVEL, targetGraph, ex.toString());
+            }
+            Debug.handle(ex);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java
new file mode 100644
index 0000000..a4c756b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.extended.JavaReadNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.nodes.WordCastNode;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests for the {@link Pointer} read and write operations.
+ */
+public class PointerTest extends GraalCompilerTest implements Snippets {
+
+    private static final LocationIdentity ID = NamedLocationIdentity.mutable("ID");
+    private static final JavaKind[] KINDS = new JavaKind[]{JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Float, JavaKind.Double, JavaKind.Object};
+    private final TargetDescription target;
+    private final ReplacementsImpl installer;
+
+    public PointerTest() {
+        target = getCodeCache().getTarget();
+        installer = (ReplacementsImpl) getProviders().getReplacements();
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        return installer.makeGraph(m, null, null);
+    }
+
+    @Test
+    public void testRead1() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead2() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead3() {
+        for (JavaKind kind : KINDS) {
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
+        }
+    }
+
+    @Test
+    public void testWrite1() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "1", AllowAssumptions.YES), true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite2() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "2", AllowAssumptions.YES), true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite3() {
+        for (JavaKind kind : KINDS) {
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any());
+        }
+    }
+
+    private void assertRead(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        JavaReadNode read = (JavaReadNode) cast.next();
+        Assert.assertEquals(kind.getStackKind(), read.stamp().getStackKind());
+
+        OffsetAddressNode address = (OffsetAddressNode) read.getAddress();
+        Assert.assertEquals(cast, address.getBase());
+        Assert.assertEquals(graph.getParameter(0), cast.getInput());
+        Assert.assertEquals(target.wordJavaKind, cast.stamp().getStackKind());
+
+        Assert.assertEquals(locationIdentity, read.getLocationIdentity());
+
+        if (indexConvert) {
+            SignExtendNode convert = (SignExtendNode) address.getOffset();
+            Assert.assertEquals(convert.getInputBits(), 32);
+            Assert.assertEquals(convert.getResultBits(), 64);
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
+        } else {
+            Assert.assertEquals(graph.getParameter(1), address.getOffset());
+        }
+
+        ReturnNode ret = (ReturnNode) read.next();
+        Assert.assertEquals(read, ret.result());
+    }
+
+    private void assertWrite(StructuredGraph graph, boolean indexConvert, LocationIdentity locationIdentity) {
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        JavaWriteNode write = (JavaWriteNode) cast.next();
+        Assert.assertEquals(graph.getParameter(2), write.value());
+        Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
+
+        OffsetAddressNode address = (OffsetAddressNode) write.getAddress();
+        Assert.assertEquals(cast, address.getBase());
+        Assert.assertEquals(graph.getParameter(0), cast.getInput());
+        Assert.assertEquals(target.wordJavaKind, cast.stamp().getStackKind());
+
+        Assert.assertEquals(locationIdentity, write.getLocationIdentity());
+
+        if (indexConvert) {
+            SignExtendNode convert = (SignExtendNode) address.getOffset();
+            Assert.assertEquals(convert.getInputBits(), 32);
+            Assert.assertEquals(convert.getResultBits(), 64);
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
+        } else {
+            Assert.assertEquals(graph.getParameter(1), address.getOffset());
+        }
+
+        ReturnNode ret = (ReturnNode) write.next();
+        Assert.assertEquals(null, ret.result());
+    }
+
+    @Snippet
+    public static byte readByte1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readByte(offset, ID);
+    }
+
+    @Snippet
+    public static byte readByte2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readByte(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static byte readByte3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readByte(offset);
+    }
+
+    @Snippet
+    public static void writeByte1(Object o, int offset, byte value) {
+        Word.objectToTrackedPointer(o).writeByte(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeByte2(Object o, int offset, byte value) {
+        Word.objectToTrackedPointer(o).writeByte(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeByte3(Object o, int offset, byte value) {
+        Word.objectToTrackedPointer(o).writeByte(offset, value);
+    }
+
+    @Snippet
+    public static char readChar1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readChar(offset, ID);
+    }
+
+    @Snippet
+    public static char readChar2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readChar(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static char readChar3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readChar(offset);
+    }
+
+    @Snippet
+    public static void writeChar1(Object o, int offset, char value) {
+        Word.objectToTrackedPointer(o).writeChar(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeChar2(Object o, int offset, char value) {
+        Word.objectToTrackedPointer(o).writeChar(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeChar3(Object o, int offset, char value) {
+        Word.objectToTrackedPointer(o).writeChar(offset, value);
+    }
+
+    @Snippet
+    public static short readShort1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readShort(offset, ID);
+    }
+
+    @Snippet
+    public static short readShort2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readShort(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static short readShort3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readShort(offset);
+    }
+
+    @Snippet
+    public static void writeShort1(Object o, int offset, short value) {
+        Word.objectToTrackedPointer(o).writeShort(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeShort2(Object o, int offset, short value) {
+        Word.objectToTrackedPointer(o).writeShort(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeShort3(Object o, int offset, short value) {
+        Word.objectToTrackedPointer(o).writeShort(offset, value);
+    }
+
+    @Snippet
+    public static int readInt1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readInt(offset, ID);
+    }
+
+    @Snippet
+    public static int readInt2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readInt(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static int readInt3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readInt(offset);
+    }
+
+    @Snippet
+    public static void writeInt1(Object o, int offset, int value) {
+        Word.objectToTrackedPointer(o).writeInt(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeInt2(Object o, int offset, int value) {
+        Word.objectToTrackedPointer(o).writeInt(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeInt3(Object o, int offset, int value) {
+        Word.objectToTrackedPointer(o).writeInt(offset, value);
+    }
+
+    @Snippet
+    public static long readLong1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readLong(offset, ID);
+    }
+
+    @Snippet
+    public static long readLong2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readLong(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static long readLong3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readLong(offset);
+    }
+
+    @Snippet
+    public static void writeLong1(Object o, int offset, long value) {
+        Word.objectToTrackedPointer(o).writeLong(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeLong2(Object o, int offset, long value) {
+        Word.objectToTrackedPointer(o).writeLong(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeLong3(Object o, int offset, long value) {
+        Word.objectToTrackedPointer(o).writeLong(offset, value);
+    }
+
+    @Snippet
+    public static float readFloat1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readFloat(offset, ID);
+    }
+
+    @Snippet
+    public static float readFloat2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readFloat(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static float readFloat3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readFloat(offset);
+    }
+
+    @Snippet
+    public static void writeFloat1(Object o, int offset, float value) {
+        Word.objectToTrackedPointer(o).writeFloat(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat2(Object o, int offset, float value) {
+        Word.objectToTrackedPointer(o).writeFloat(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat3(Object o, int offset, float value) {
+        Word.objectToTrackedPointer(o).writeFloat(offset, value);
+    }
+
+    @Snippet
+    public static double readDouble1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readDouble(offset, ID);
+    }
+
+    @Snippet
+    public static double readDouble2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readDouble(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static double readDouble3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readDouble(offset);
+    }
+
+    @Snippet
+    public static void writeDouble1(Object o, int offset, double value) {
+        Word.objectToTrackedPointer(o).writeDouble(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble2(Object o, int offset, double value) {
+        Word.objectToTrackedPointer(o).writeDouble(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble3(Object o, int offset, double value) {
+        Word.objectToTrackedPointer(o).writeDouble(offset, value);
+    }
+
+    @Snippet
+    public static Object readObject1(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readObject(offset, ID);
+    }
+
+    @Snippet
+    public static Object readObject2(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readObject(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static Object readObject3(Object o, int offset) {
+        return Word.objectToTrackedPointer(o).readObject(offset);
+    }
+
+    @Snippet
+    public static void writeObject1(Object o, int offset, Object value) {
+        Word.objectToTrackedPointer(o).writeObject(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeObject2(Object o, int offset, Object value) {
+        Word.objectToTrackedPointer(o).writeObject(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeObject3(Object o, int offset, Object value) {
+        Word.objectToTrackedPointer(o).writeObject(offset, value);
+    }
+
+    private void assertNumWordCasts(String snippetName, int expectedWordCasts) {
+        HighTierContext context = new HighTierContext(getProviders(), null, OptimisticOptimizations.ALL);
+
+        StructuredGraph graph = parseEager(snippetName, AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, context);
+        Assert.assertEquals(expectedWordCasts, graph.getNodes().filter(WordCastNode.class).count());
+    }
+
+    @Test
+    public void testUnusedFromObject() {
+        assertNumWordCasts("unusedFromObject", 0);
+    }
+
+    @Snippet
+    public static void unusedFromObject(Object o) {
+        Word.objectToTrackedPointer(o);
+    }
+
+    @Test
+    public void testUnusedRawValue() {
+        assertNumWordCasts("unusedRawValue", 0);
+    }
+
+    @Snippet
+    public static void unusedRawValue(Object o) {
+        Word.objectToTrackedPointer(o).rawValue();
+    }
+
+    @Test
+    public void testUsedRawValue() {
+        assertNumWordCasts("usedRawValue", 1);
+    }
+
+    @Snippet
+    public static long usedRawValue(Object o) {
+        return Word.objectToTrackedPointer(o).rawValue();
+    }
+
+    @Test
+    public void testUnusedToObject() {
+        assertNumWordCasts("unusedToObject", 0);
+    }
+
+    @Snippet
+    public static void unusedToObject(Word w) {
+        w.toObject();
+    }
+
+    @Test
+    public void testUsedToObject() {
+        assertNumWordCasts("usedToObject", 1);
+    }
+
+    @Snippet
+    public static Object usedToObject(Word w) {
+        return w.toObject();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java
new file mode 100644
index 0000000..afe45a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class PointerTrackingTest extends GraalCompilerTest implements Snippets {
+
+    @Test
+    public void testTracking() {
+        Result result = executeActual(getResolvedJavaMethod("trackingSnippet"), null, new Object());
+        assertEquals(new Result("OK", null), result);
+    }
+
+    public static String trackingSnippet(Object obj) {
+        long trackedBeforeGC = getTrackedPointer(obj);
+        long untrackedBeforeGC = getUntrackedPointer(obj);
+
+        int i = 0;
+        while (untrackedBeforeGC == getTrackedPointer(obj)) {
+            System.gc();
+            if (i++ > 100) {
+                return "Timeout! Object didn't move after 100 GCs.";
+            }
+        }
+
+        long trackedAfterGC = getTrackedPointer(obj);
+        long untrackedAfterGC = getUntrackedPointer(obj);
+
+        if (untrackedBeforeGC == untrackedAfterGC) {
+            /*
+             * The untracked pointer isn't supposed to be updated, so it should be different before
+             * and after GC.
+             */
+            return "untrackedBeforeGC == untrackedAfterGC";
+        }
+        if (trackedBeforeGC != trackedAfterGC) {
+            /*
+             * The trackedBeforeGC variable should be updated to the new location by the GC, so it
+             * should be equal to trackedAfterGC.
+             */
+            return "trackedBeforeGC != trackedAfterGC";
+        }
+
+        return "OK";
+    }
+
+    @Test(expected = GraalError.class)
+    @SuppressWarnings("try")
+    public void testVerification() {
+        try (DebugConfigScope scope = Debug.disableIntercept()) {
+            compile(getResolvedJavaMethod("verificationSnippet"), null);
+        }
+    }
+
+    public static long verificationSnippet(Object obj) {
+        long value = getTrackedPointer(obj) * 7 + 3;
+
+        /*
+         * Ensure usage before and after GC to force the value to be alive across the safepoint.
+         * This should lead to a compiler error, since value can not be tracked in the reference
+         * map.
+         */
+        GraalDirectives.blackhole(value);
+        System.gc();
+        return value;
+    }
+
+    static long getTrackedPointer(@SuppressWarnings("unused") Object obj) {
+        throw GraalError.shouldNotReachHere("should be intrinsified");
+    }
+
+    static long getUntrackedPointer(@SuppressWarnings("unused") Object obj) {
+        throw GraalError.shouldNotReachHere("should be intrinsified");
+    }
+
+    static long getTrackedPointerIntrinsic(Object obj) {
+        return Word.objectToTrackedPointer(obj).rawValue();
+    }
+
+    static long getUntrackedPointerIntrinsic(Object obj) {
+        return Word.objectToUntrackedPointer(obj).rawValue();
+    }
+
+    private void register(Registration r, String fnName) {
+        ResolvedJavaMethod intrinsic = getResolvedJavaMethod(fnName + "Intrinsic");
+        r.register1(fnName, Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                return b.intrinsify(getReplacements().getReplacementBytecodeProvider(), targetMethod, intrinsic, receiver, new ValueNode[]{arg});
+            }
+        });
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), PointerTrackingTest.class);
+
+        register(r, "getTrackedPointer");
+        register(r, "getUntrackedPointer");
+
+        return plugins;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java
new file mode 100644
index 0000000..5bd0bd4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.function.Function;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests for expected behavior when parsing snippets and intrinsics.
+ */
+public class ReplacementsParseTest extends GraalCompilerTest {
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factory, jvmci service providers don't work from unit tests
+        new PluginFactory_ReplacementsParseTest().registerPlugins(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
+    private static final Object THROW_EXCEPTION_MARKER = new Object() {
+        @Override
+        public String toString() {
+            return "THROW_EXCEPTION_MARKER";
+        }
+    };
+
+    static class TestMethods {
+        static double next(double v) {
+            return Math.nextAfter(v, 1.0);
+        }
+
+        static double next2(double v) {
+            return Math.nextAfter(v, 1.0);
+        }
+
+        static double nextAfter(double x, double d) {
+            return Math.nextAfter(x, d);
+        }
+
+        static String stringize(Object obj) {
+            String res = String.valueOf(obj);
+            if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
+                // Tests exception throwing from partial intrinsification
+                throw new RuntimeException("ex: " + obj);
+            }
+            return res;
+        }
+
+        static String identity(String s) {
+            return s;
+        }
+    }
+
+    @ClassSubstitution(TestMethods.class)
+    static class TestMethodsSubstitutions {
+
+        @MethodSubstitution(isStatic = true)
+        static double nextAfter(double x, double d) {
+            double xx = (x == -0.0 ? 0.0 : x);
+            return Math.nextAfter(xx, d);
+        }
+
+        /**
+         * Tests partial intrinsification.
+         */
+        @MethodSubstitution
+        static String stringize(Object obj) {
+            if (obj != null && obj.getClass() == String.class) {
+                return asNonNullString(obj);
+            } else {
+                // A recursive call denotes exiting/deoptimizing
+                // out of the partial intrinsification to the
+                // slow/uncommon case.
+                return stringize(obj);
+            }
+        }
+
+        public static String asNonNullString(Object object) {
+            return asNonNullStringIntrinsic(object, String.class, true, true);
+        }
+
+        @NodeIntrinsic(PiNode.class)
+        private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
+
+        /**
+         * Tests that non-capturing lambdas are folded away.
+         */
+        @MethodSubstitution
+        static String identity(String value) {
+            return apply(s -> s, value);
+        }
+
+        private static String apply(Function<String, String> f, String value) {
+            return f.apply(value);
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        BytecodeProvider replacementBytecodeProvider = getReplacements().getReplacementBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, TestMethods.class, replacementBytecodeProvider);
+        r.registerMethodSubstitution(TestMethodsSubstitutions.class, "nextAfter", double.class, double.class);
+        r.registerMethodSubstitution(TestMethodsSubstitutions.class, "stringize", Object.class);
+        if (replacementBytecodeProvider.supportsInvokedynamic()) {
+            r.registerMethodSubstitution(TestMethodsSubstitutions.class, "identity", String.class);
+        }
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    /**
+     * Ensure that calling the original method from the substitution binds correctly.
+     */
+    @Test
+    public void test1() {
+        test("test1Snippet", 1.0);
+    }
+
+    public double test1Snippet(double d) {
+        return TestMethods.next(d);
+    }
+
+    /**
+     * Ensure that calling the substitution method binds to the original method properly.
+     */
+    @Test
+    public void test2() {
+        test("test2Snippet", 1.0);
+    }
+
+    public double test2Snippet(double d) {
+        return TestMethods.next2(d);
+    }
+
+    /**
+     * Ensure that substitution methods with assertions in them don't complain when the exception
+     * constructor is deleted.
+     */
+
+    @Test
+    public void testNextAfter() {
+        double[] inArray = new double[1024];
+        double[] outArray = new double[1024];
+        for (int i = 0; i < inArray.length; i++) {
+            inArray[i] = -0.0;
+        }
+        test("doNextAfter", inArray, outArray);
+    }
+
+    public void doNextAfter(double[] outArray, double[] inArray) {
+        for (int i = 0; i < inArray.length; i++) {
+            double direction = (i & 1) == 0 ? Double.POSITIVE_INFINITY : -Double.NEGATIVE_INFINITY;
+            outArray[i] = TestMethods.nextAfter(inArray[i], direction);
+        }
+    }
+
+    @Test
+    public void testCallStringize() {
+        test("callStringize", "a string");
+        test("callStringize", THROW_EXCEPTION_MARKER);
+        test("callStringize", Boolean.TRUE);
+    }
+
+    public static Object callStringize(Object obj) {
+        return TestMethods.stringize(obj);
+    }
+
+    @Test
+    public void testRootCompileStringize() {
+        ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize");
+        test(method, null, "a string");
+        test(method, null, Boolean.TRUE);
+        test(method, null, THROW_EXCEPTION_MARKER);
+    }
+
+    @Test
+    public void testLambda() {
+        test("callLambda", (String) null);
+        test("callLambda", "a string");
+    }
+
+    public static String callLambda(String value) {
+        return TestMethods.identity(value);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java
new file mode 100644
index 0000000..3decde1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.HashMap;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.AbsNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.replacements.nodes.BitCountNode;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+import org.graalvm.compiler.replacements.nodes.ReverseBytesNode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests the VM independent {@link MethodSubstitution}s.
+ */
+public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest {
+
+    @Test
+    public void testMathSubstitutions() {
+        assertInGraph(assertNotInGraph(testGraph("mathAbs"), IfNode.class), AbsNode.class);     // Java
+        double value = 34567.891D;
+        testGraph("mathCos");
+        testGraph("mathLog");
+        testGraph("mathLog10");
+        testGraph("mathSin");
+        testGraph("mathSqrt");
+        testGraph("mathTan");
+        testGraph("mathAll");
+
+        test("mathCos", value);
+        test("mathLog", value);
+        test("mathLog10", value);
+        test("mathSin", value);
+        test("mathSqrt", value);
+        test("mathTan", value);
+        test("mathAll", value);
+    }
+
+    @Test
+    public void testMathPow() {
+        double a = 34567.891D;
+        double b = 4.6D;
+        test("mathPow", a, b);
+
+        // Test the values directly handled by the substitution
+
+        // If the second argument is positive or negative zero, then the result is 1.0.
+        test("mathPow", a, 0.0D);
+        test("mathPow", a, -0.0D);
+        // If the second argument is 1.0, then the result is the same as the first argument.
+        test("mathPow", a, 1.0D);
+        // If the second argument is NaN, then the result is NaN.
+        test("mathPow", a, Double.NaN);
+        // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
+        test("mathPow", Double.NaN, b);
+        test("mathPow", Double.NaN, 0.0D);
+        // x**-1 = 1/x
+        test("mathPow", a, -1.0D);
+        // x**2 = x*x
+        test("mathPow", a, 2.0D);
+        // x**0.5 = sqrt(x)
+        test("mathPow", a, 0.5D);
+    }
+
+    public static double mathPow(double a, double b) {
+        return mathPow0(a, b);
+    }
+
+    public static double mathPow0(double a, double b) {
+        return Math.pow(a, b);
+    }
+
+    public static double mathAbs(double value) {
+        return Math.abs(value);
+    }
+
+    public static double mathSqrt(double value) {
+        return Math.sqrt(value);
+    }
+
+    public static double mathLog(double value) {
+        return Math.log(value);
+    }
+
+    public static double mathLog10(double value) {
+        return Math.log10(value);
+    }
+
+    public static double mathSin(double value) {
+        return Math.sin(value);
+    }
+
+    public static double mathCos(double value) {
+        return Math.cos(value);
+    }
+
+    public static double mathTan(double value) {
+        return Math.tan(value);
+    }
+
+    public static double mathAll(double value) {
+        return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
+    }
+
+    public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object... args) {
+        ResolvedJavaMethod realJavaMethod = getResolvedJavaMethod(holder, methodName);
+        ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
+
+        // Check to see if the resulting graph contains the expected node
+        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1);
+        if (replacement == null && !optional) {
+            assertInGraph(graph, intrinsicClass);
+        }
+
+        for (Object l : args) {
+            // Force compilation
+            InstalledCode code = getCode(testJavaMethod);
+            assert optional || code != null;
+            // Verify that the original method and the substitution produce the same value
+            Object expected = invokeSafe(realJavaMethod, null, l);
+            assertDeepEquals(expected, invokeSafe(testJavaMethod, null, l));
+            // Verify that the generated code and the original produce the same value
+            assertDeepEquals(expected, executeVarargsSafe(code, l));
+        }
+    }
+
+    @Test
+    public void testCharSubstitutions() {
+        Object[] args = new Character[]{Character.MIN_VALUE, (char) -1, (char) 0, (char) 1, Character.MAX_VALUE};
+
+        testSubstitution("charReverseBytes", ReverseBytesNode.class, Character.class, "reverseBytes", false, args);
+    }
+
+    public static char charReverseBytes(char value) {
+        return Character.reverseBytes(value);
+    }
+
+    @Test
+    public void testCharSubstitutionsNarrowing() {
+        Object[] args = new Integer[]{(int) Character.MIN_VALUE, -1, 0, 1, (int) Character.MAX_VALUE};
+
+        for (Object arg : args) {
+            test("charReverseBytesNarrowing", arg);
+        }
+    }
+
+    public static char charReverseBytesNarrowing(int value) {
+        return Character.reverseBytes((char) value);
+    }
+
+    @Test
+    public void testShortSubstitutions() {
+        Object[] args = new Short[]{Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE};
+
+        testSubstitution("shortReverseBytes", ReverseBytesNode.class, Short.class, "reverseBytes", false, args);
+    }
+
+    public static short shortReverseBytes(short value) {
+        return Short.reverseBytes(value);
+    }
+
+    @Test
+    public void testShortSubstitutionsNarrowing() {
+        Object[] args = new Integer[]{(int) Short.MIN_VALUE, -1, 0, 1, (int) Short.MAX_VALUE};
+
+        for (Object arg : args) {
+            test("shortReverseBytesNarrowing", arg);
+        }
+    }
+
+    public static short shortReverseBytesNarrowing(int value) {
+        return Short.reverseBytes((short) value);
+    }
+
+    @Test
+    public void testIntegerSubstitutions() {
+        Object[] args = new Object[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE};
+
+        testSubstitution("integerReverseBytes", ReverseBytesNode.class, Integer.class, "reverseBytes", false, args);
+        testSubstitution("integerNumberOfLeadingZeros", BitScanReverseNode.class, Integer.class, "numberOfLeadingZeros", true, args);
+        testSubstitution("integerNumberOfTrailingZeros", BitScanForwardNode.class, Integer.class, "numberOfTrailingZeros", false, args);
+        testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args);
+    }
+
+    public static int integerReverseBytes(int value) {
+        return Integer.reverseBytes(value);
+    }
+
+    public static int integerNumberOfLeadingZeros(int value) {
+        return Integer.numberOfLeadingZeros(value);
+    }
+
+    public static int integerNumberOfTrailingZeros(int value) {
+        return Integer.numberOfTrailingZeros(value);
+    }
+
+    public static int integerBitCount(int value) {
+        return Integer.bitCount(value);
+    }
+
+    @Test
+    public void testLongSubstitutions() {
+        Object[] args = new Object[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE};
+
+        testSubstitution("longReverseBytes", ReverseBytesNode.class, Long.class, "reverseBytes", false, args);
+        testSubstitution("longNumberOfLeadingZeros", BitScanReverseNode.class, Long.class, "numberOfLeadingZeros", true, args);
+        testSubstitution("longNumberOfTrailingZeros", BitScanForwardNode.class, Long.class, "numberOfTrailingZeros", false, args);
+        testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args);
+    }
+
+    public static long longReverseBytes(long value) {
+        return Long.reverseBytes(value);
+    }
+
+    public static int longNumberOfLeadingZeros(long value) {
+        return Long.numberOfLeadingZeros(value);
+    }
+
+    public static int longNumberOfTrailingZeros(long value) {
+        return Long.numberOfTrailingZeros(value);
+    }
+
+    public static int longBitCount(long value) {
+        return Long.bitCount(value);
+    }
+
+    @Test
+    public void testFloatSubstitutions() {
+        assertInGraph(testGraph("floatToIntBits"), ReinterpretNode.class); // Java
+        testGraph("intBitsToFloat");
+    }
+
+    public static int floatToIntBits(float value) {
+        return Float.floatToIntBits(value);
+    }
+
+    public static float intBitsToFloat(int value) {
+        return Float.intBitsToFloat(value);
+    }
+
+    @Test
+    public void testDoubleSubstitutions() {
+        assertInGraph(testGraph("doubleToLongBits"), ReinterpretNode.class); // Java
+        testGraph("longBitsToDouble");
+    }
+
+    public static long doubleToLongBits(double value) {
+        return Double.doubleToLongBits(value);
+    }
+
+    public static double longBitsToDouble(long value) {
+        return Double.longBitsToDouble(value);
+    }
+
+    public static boolean isInstance(Class<?> clazz, Object object) {
+        return clazz.isInstance(object);
+    }
+
+    public static boolean isInstance2(boolean cond, Object object) {
+        Class<?> clazz;
+        if (cond) {
+            clazz = String.class;
+        } else {
+            clazz = java.util.HashMap.class;
+        }
+        return clazz.isInstance(object);
+    }
+
+    public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
+        return clazz.isAssignableFrom(other);
+    }
+
+    @Test
+    public void testClassSubstitutions() {
+        testGraph("isInstance");
+        testGraph("isInstance2");
+        testGraph("isAssignableFrom");
+        for (Class<?> c : new Class<?>[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
+            for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
+                test("isInstance", c, o);
+                test("isAssignableFrom", c, o.getClass());
+            }
+        }
+
+        test("isInstance2", true, null);
+        test("isInstance2", false, null);
+        test("isInstance2", true, "string");
+        test("isInstance2", false, "string");
+        test("isInstance2", true, new HashMap<>());
+        test("isInstance2", false, new HashMap<>());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringEqualsConstantTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringEqualsConstantTest.java
new file mode 100644
index 0000000..6cd58b9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringEqualsConstantTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import jdk.vm.ci.meta.JavaConstant;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import org.junit.Assert;
+
+/**
+ * Tests constant folding of string equality.
+ */
+public class StringEqualsConstantTest extends GraalCompilerTest {
+
+    private ValueNode asConstant(StructuredGraph graph, String str) {
+        return ConstantNode.forConstant(getSnippetReflection().forObject(str), getMetaAccess(), graph);
+    }
+
+    private void testStringEquals(String s0, String s1) {
+        ResolvedJavaMethod method = getResolvedJavaMethod("stringEquals");
+        StructuredGraph graph = parseForCompile(method);
+
+        graph.getParameter(0).replaceAndDelete(asConstant(graph, s0));
+        graph.getParameter(1).replaceAndDelete(asConstant(graph, s1));
+
+        compile(method, graph);
+
+        FixedNode firstFixed = graph.start().next();
+        Assert.assertThat(firstFixed, instanceOf(ReturnNode.class));
+
+        ReturnNode ret = (ReturnNode) firstFixed;
+        JavaConstant result = ret.result().asJavaConstant();
+        if (result == null) {
+            Assert.fail("result not constant: " + ret.result());
+        } else {
+            int expected = s0.equals(s1) ? 1 : 0;
+            Assert.assertEquals("result", expected, result.asInt());
+        }
+    }
+
+    @Test
+    public void testSameString() {
+        String s = "equal-string";
+        testStringEquals(s, s);
+    }
+
+    @Test
+    public void testEqualString() {
+        String s = "equal-string";
+        testStringEquals(s, new String(s.toCharArray()));
+    }
+
+    @Test
+    public void testDifferentString() {
+        testStringEquals("some-string", "different-string");
+    }
+
+    @Test
+    public void testSameLengthString() {
+        testStringEquals("string-1", "string-2");
+    }
+
+    public static boolean stringEquals(String a, String b) {
+        return a.equals(b);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringHashConstantTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringHashConstantTest.java
new file mode 100644
index 0000000..b2156ec
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringHashConstantTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import jdk.vm.ci.meta.JavaConstant;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import org.junit.Assert;
+
+/**
+ * Tests constant folding of {@link String#hashCode()}.
+ */
+public class StringHashConstantTest extends GraalCompilerTest {
+
+    private static final String A_CONSTANT_STRING = "a constant string";
+
+    private ValueNode asConstant(StructuredGraph graph, String str) {
+        return ConstantNode.forConstant(getSnippetReflection().forObject(str), getMetaAccess(), graph);
+    }
+
+    @Test
+    public void test1() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("parameterizedHashCode");
+        StructuredGraph graph = parseForCompile(method);
+
+        String s = "some string";
+        int expected = s.hashCode();
+        graph.getParameter(0).replaceAndDelete(asConstant(graph, s));
+
+        compile(method, graph);
+
+        FixedNode firstFixed = graph.start().next();
+        Assert.assertThat(firstFixed, instanceOf(ReturnNode.class));
+
+        ReturnNode ret = (ReturnNode) firstFixed;
+        JavaConstant result = ret.result().asJavaConstant();
+        if (result == null) {
+            Assert.fail("result not constant: " + ret.result());
+        } else {
+            Assert.assertEquals("result", expected, result.asInt());
+        }
+    }
+
+    public static int parameterizedHashCode(String value) {
+        return value.hashCode();
+    }
+
+    @Test
+    public void test2() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("constantHashCode");
+        StructuredGraph graph = parseForCompile(method);
+
+        FixedNode firstFixed = graph.start().next();
+        Assert.assertThat(firstFixed, instanceOf(ReturnNode.class));
+
+        ReturnNode ret = (ReturnNode) firstFixed;
+        JavaConstant result = ret.result().asJavaConstant();
+        if (result == null) {
+            Assert.fail("result not constant: " + ret.result());
+        } else {
+            int expected = A_CONSTANT_STRING.hashCode();
+            Assert.assertEquals("result", expected, result.asInt());
+        }
+    }
+
+    public static int constantHashCode() {
+        return A_CONSTANT_STRING.hashCode();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java
new file mode 100644
index 0000000..7c870fa
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.replacements.StringSubstitutions;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests {@link StringSubstitutions}.
+ */
+public class StringSubstitutionsTest extends MethodSubstitutionTest {
+
+    public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object[] args1, Object[] args2) {
+        ResolvedJavaMethod realMethod = getResolvedJavaMethod(holder, methodName);
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
+
+        // Check to see if the resulting graph contains the expected node
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
+        if (replacement == null && !optional) {
+            assertInGraph(graph, intrinsicClass);
+        }
+
+        // Force compilation
+        InstalledCode code = getCode(testMethod);
+        assert optional || code != null;
+
+        for (int i = 0; i < args1.length; i++) {
+            Object arg1 = args1[i];
+            Object arg2 = args2[i];
+            Object expected = invokeSafe(realMethod, arg1, arg2);
+            // Verify that the original method and the substitution produce the same value
+            assertDeepEquals(expected, invokeSafe(testMethod, null, arg1, arg2));
+            // Verify that the generated code and the original produce the same value
+            assertDeepEquals(expected, executeVarargsSafe(code, arg1, arg2));
+        }
+    }
+
+    @Test
+    public void testEquals() {
+        if (!Java8OrEarlier) {
+            // StringSubstitutions are disabled in 1.9
+            return;
+        }
+
+        final int n = 1000;
+        Object[] args1 = new Object[n];
+        Object[] args2 = new Object[n];
+
+        // equal strings
+        String s1 = "";
+        String s2 = "";
+        for (int i = 0; i < n / 2; i++) {
+            args1[i] = s1;
+            args2[i] = s2;
+            s1 = s1 + "0";
+            s2 = s2 + "0";
+        }
+
+        // non-equal strings
+        s1 = "";
+        s2 = "";
+        for (int i = n / 2; i < n; i++) {
+            args1[i] = s1;
+            args2[i] = s2;
+            s2 = s1 + "1";
+            s1 = s1 + "0";
+        }
+
+        testSubstitution("stringEquals", ArrayEqualsNode.class, String.class, "equals", false, args1, args2);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean stringEquals(String a, String b) {
+        return a.equals(b);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java
new file mode 100644
index 0000000..a542fa8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.hamcrest.CoreMatchers.instanceOf;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.StructuralInput.Guard;
+import org.graalvm.compiler.nodeinfo.StructuralInput.Memory;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class SubstitutionsTest extends GraalCompilerTest {
+
+    @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class TestMemory extends FixedWithNextNode implements MemoryNode {
+        private static final NodeClass<TestMemory> TYPE = NodeClass.create(TestMemory.class);
+
+        protected TestMemory() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @NodeIntrinsic
+        public static native Memory memory();
+    }
+
+    @NodeInfo(allowedUsageTypes = {Guard}, cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class TestGuard extends FloatingNode implements GuardingNode {
+        private static final NodeClass<TestGuard> TYPE = NodeClass.create(TestGuard.class);
+
+        @Input(Memory) MemoryNode memory;
+
+        protected TestGuard(ValueNode memory) {
+            super(TYPE, StampFactory.forVoid());
+            this.memory = (MemoryNode) memory;
+        }
+
+        @NodeIntrinsic
+        public static native Guard guard(Memory memory);
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class TestValue extends FloatingNode {
+        private static final NodeClass<TestValue> TYPE = NodeClass.create(TestValue.class);
+
+        @Input(Guard) GuardingNode guard;
+
+        protected TestValue(ValueNode guard) {
+            super(TYPE, StampFactory.forKind(JavaKind.Int));
+            this.guard = (GuardingNode) guard;
+        }
+
+        @NodeIntrinsic
+        public static native int value(Guard guard);
+    }
+
+    private static class TestMethod {
+
+        public static int test() {
+            return 42;
+        }
+    }
+
+    @ClassSubstitution(TestMethod.class)
+    private static class TestMethodSubstitution {
+
+        @MethodSubstitution
+        public static int test() {
+            Memory memory = TestMemory.memory();
+            Guard guard = TestGuard.guard(memory);
+            return TestValue.value(guard);
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        BytecodeProvider replacementBytecodeProvider = getReplacements().getReplacementBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider);
+        r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    public static int callTest() {
+        return TestMethod.test();
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factories, jvmci service providers don't work from unit tests
+        new PluginFactory_SubstitutionsTest().registerPlugins(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        // Check that the graph contains the expected test nodes.
+        NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
+        Assert.assertTrue("expected exactly one ReturnNode", retNodes.count() == 1);
+        ReturnNode ret = retNodes.first();
+
+        Assert.assertThat(ret.result(), instanceOf(TestValue.class));
+        TestValue value = (TestValue) ret.result();
+
+        Assert.assertThat(value.guard, instanceOf(TestGuard.class));
+        TestGuard guard = (TestGuard) value.guard;
+
+        Assert.assertThat(guard.memory, instanceOf(TestMemory.class));
+        TestMemory memory = (TestMemory) guard.memory;
+
+        // Remove the test nodes, replacing them by the constant 42.
+        // This implicitly makes sure that the rest of the graph is valid.
+        ret.replaceFirstInput(value, graph.unique(ConstantNode.forInt(42)));
+        value.safeDelete();
+        guard.safeDelete();
+        graph.removeFixed(memory);
+
+        return true;
+    }
+
+    @Test
+    public void snippetTest() {
+        test("callTest");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/TypeCheckTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/TypeCheckTest.java
new file mode 100644
index 0000000..0767899
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/TypeCheckTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * Base class for instanceof test classes.
+ */
+public abstract class TypeCheckTest extends GraalCompilerTest {
+
+    protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile);
+
+    protected JavaTypeProfile currentProfile;
+
+    @Override
+    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) {
+        StructuredGraph graph = super.parseForCompile(method, compilationId);
+        if (currentProfile != null) {
+            replaceProfile(graph, currentProfile);
+        }
+        return graph;
+    }
+
+    @Override
+    protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) {
+        return getCode(method, graph, currentProfile != null);
+    }
+
+    protected JavaTypeProfile profile(Class<?>... types) {
+        return profile(TriState.FALSE, types);
+    }
+
+    protected JavaTypeProfile profile(TriState nullSeen, Class<?>... types) {
+        if (types.length == 0) {
+            return null;
+        }
+        ProfiledType[] ptypes = new ProfiledType[types.length];
+        for (int i = 0; i < types.length; i++) {
+            ptypes[i] = new ProfiledType(getMetaAccess().lookupJavaType(types[i]), 1.0D / types.length);
+        }
+        return new JavaTypeProfile(nullSeen, 0.0D, ptypes);
+    }
+
+    protected void test(String name, JavaTypeProfile profile, Object... args) {
+        assert currentProfile == null;
+        currentProfile = profile;
+        try {
+            super.test(name, args);
+        } finally {
+            currentProfile = null;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeSubstitutionsTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeSubstitutionsTest.java
new file mode 100644
index 0000000..45cad33
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeSubstitutionsTest.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * Tests the VM independent intrinsification of {@link Unsafe} methods.
+ */
+public class UnsafeSubstitutionsTest extends MethodSubstitutionTest {
+
+    public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
+        ResolvedJavaMethod originalMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
+
+        // Force compilation
+        InstalledCode code = getCode(testMethod);
+        assert code != null;
+
+        // Verify that the original method and the substitution produce the same value
+        Object expected = invokeSafe(originalMethod, receiver, args1);
+        Object actual = invokeSafe(testMethod, null, args2);
+        assertDeepEquals(expected, actual);
+
+        // Verify that the generated code and the original produce the same value
+        expected = invokeSafe(originalMethod, receiver, args1);
+        actual = executeVarargsSafe(code, args2);
+        assertDeepEquals(expected, actual);
+
+    }
+
+    static long off(Object o, String name) {
+        try {
+            return UNSAFE.objectFieldOffset(o.getClass().getDeclaredField(name));
+        } catch (Exception e) {
+            Assert.fail(e.toString());
+            return 0L;
+        }
+    }
+
+    static class Foo {
+        boolean z;
+        byte b;
+        short s;
+        char c;
+        int i;
+        long l;
+        float f;
+        double d;
+        Object o;
+    }
+
+    @Test
+    public void testUnsafeSubstitutions() throws Exception {
+        test("unsafeCompareAndSwapInt", UNSAFE, supply(() -> new Foo()), fooOffset("i"));
+
+        testGraph("unsafeCompareAndSwapInt");
+        testGraph("unsafeCompareAndSwapLong");
+        testGraph("unsafeCompareAndSwapObject");
+
+        testGraph("unsafeGetBoolean");
+        testGraph("unsafeGetByte");
+        testGraph("unsafeGetShort");
+        testGraph("unsafeGetChar");
+        testGraph("unsafeGetInt");
+        testGraph("unsafeGetLong");
+        testGraph("unsafeGetFloat");
+        testGraph("unsafeGetDouble");
+        testGraph("unsafeGetObject");
+
+        testGraph("unsafePutBoolean");
+        testGraph("unsafePutByte");
+        testGraph("unsafePutShort");
+        testGraph("unsafePutChar");
+        testGraph("unsafePutInt");
+        testGraph("unsafePutLong");
+        testGraph("unsafePutFloat");
+        testGraph("unsafePutDouble");
+        testGraph("unsafePutObject");
+
+        testGraph("unsafeGetAddress");
+        testGraph("unsafePutAddress");
+
+        testGraph("unsafeDirectMemoryRead");
+        testGraph("unsafeDirectMemoryWrite");
+
+        long address = UNSAFE.allocateMemory(8 * JavaKind.values().length);
+        for (Unsafe unsafeArg : new Unsafe[]{UNSAFE, null}) {
+            test("unsafeCompareAndSwapInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"));
+            test("unsafeCompareAndSwapLong", unsafeArg, supply(() -> new Foo()), fooOffset("l"));
+            test("unsafeCompareAndSwapObject", unsafeArg, supply(() -> new Foo()), fooOffset("o"));
+
+            test("unsafeGetBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"));
+            test("unsafeGetByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"));
+            test("unsafeGetShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"));
+            test("unsafeGetChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"));
+            test("unsafeGetInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"));
+            test("unsafeGetLong", unsafeArg, supply(() -> new Foo()), fooOffset("l"));
+            test("unsafeGetFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"));
+            test("unsafeGetDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"));
+            test("unsafeGetObject", unsafeArg, supply(() -> new Foo()), fooOffset("o"));
+
+            test("unsafePutBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"), true);
+            test("unsafePutByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"), (byte) 87);
+            test("unsafePutShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"), (short) -93);
+            test("unsafePutChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"), 'A');
+            test("unsafePutInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"), 42);
+            test("unsafePutLong", unsafeArg, supply(() -> new Foo()), fooOffset("l"), 4711L);
+            test("unsafePutFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"), 58.0F);
+            test("unsafePutDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"), -28736.243465D);
+            test("unsafePutObject", unsafeArg, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3");
+
+            test("unsafeGetAddress", unsafeArg, address);
+            test("unsafePutAddress", unsafeArg, address, 0xDEAD_BEEF_DEAD_BABEL);
+
+            test("unsafeDirectMemoryRead", unsafeArg, address);
+            test("unsafeDirectMemoryWrite", unsafeArg, address, 0xCAFE_BABE_DEAD_BABEL);
+        }
+        UNSAFE.freeMemory(address);
+    }
+
+    private static long fooOffset(String name) {
+        try {
+            return UNSAFE.objectFieldOffset(Foo.class.getDeclaredField(name));
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapInt(obj, offset, 0, 1);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapLong(obj, offset, 0, 1);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapObject(obj, offset, null, new Object());
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) {
+        int res = 1;
+        unsafe.putBoolean(obj, offset, value);
+        res += unsafe.getBoolean(obj, offset) ? 3 : 5;
+        unsafe.putBooleanVolatile(obj, offset, value);
+        res += unsafe.getBoolean(obj, offset) ? 7 : 11;
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) {
+        int res = 1;
+        unsafe.putByte(obj, offset, (byte) (value + 1));
+        res += unsafe.getByte(obj, offset);
+        unsafe.putByteVolatile(obj, offset, (byte) (value + 2));
+        res += unsafe.getByte(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) {
+        int res = 1;
+        unsafe.putShort(obj, offset, (short) (value + 1));
+        res += unsafe.getShort(obj, offset);
+        unsafe.putShortVolatile(obj, offset, (short) (value + 2));
+        res += unsafe.getShort(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) {
+        int res = 1;
+        unsafe.putChar(obj, offset, (char) (value + 1));
+        res += unsafe.getChar(obj, offset);
+        unsafe.putCharVolatile(obj, offset, (char) (value + 2));
+        res += unsafe.getChar(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) {
+        int res = 1;
+        unsafe.putInt(obj, offset, value);
+        res += unsafe.getInt(obj, offset);
+        unsafe.putIntVolatile(obj, offset, value + 1);
+        res += unsafe.getInt(obj, offset);
+        unsafe.putOrderedInt(obj, offset, value + 2);
+        res += unsafe.getInt(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static long unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) {
+        long res = 1;
+        unsafe.putLong(obj, offset, value + 1);
+        res += unsafe.getLong(obj, offset);
+        unsafe.putLongVolatile(obj, offset, value + 2);
+        res += unsafe.getLong(obj, offset);
+        unsafe.putOrderedLong(obj, offset, value + 3);
+        res += unsafe.getLong(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static float unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) {
+        float res = 1;
+        unsafe.putFloat(obj, offset, value + 1.0F);
+        res += unsafe.getFloat(obj, offset);
+        unsafe.putFloatVolatile(obj, offset, value + 2.0F);
+        res += unsafe.getFloat(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) {
+        double res = 1;
+        unsafe.putDouble(obj, offset, value);
+        res += unsafe.getDouble(obj, offset);
+        unsafe.putDoubleVolatile(obj, offset, value);
+        res += unsafe.getDouble(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static Object[] unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value1, Object value2, Object value3) {
+        Object[] res = new Object[3];
+        unsafe.putObject(obj, offset, value1);
+        res[0] = unsafe.getObject(obj, offset);
+        unsafe.putObjectVolatile(obj, offset, value2);
+        res[1] = unsafe.getObject(obj, offset);
+        unsafe.putOrderedObject(obj, offset, value3);
+        res[2] = unsafe.getObject(obj, offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static long unsafeGetAddress(Unsafe unsafe, long offset) {
+        return unsafe.getAddress(offset);
+    }
+
+    @SuppressWarnings("all")
+    public static long unsafePutAddress(Unsafe unsafe, long offset, long value) {
+        long res = 1;
+        unsafe.putAddress(offset, value);
+        res += unsafe.getAddress(offset);
+        return res;
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) {
+        // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist
+        // @formatter:off
+        return unsafe.getByte(address) +
+               unsafe.getShort(address + 8) +
+               unsafe.getChar(address + 16) +
+               unsafe.getInt(address + 24) +
+               unsafe.getLong(address + 32) +
+               unsafe.getFloat(address + 40) +
+               unsafe.getDouble(address + 48);
+        // @formatter:on
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafeDirectMemoryWrite(Unsafe unsafe, long address, long value) {
+        // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist
+        unsafe.putByte(address + 0, (byte) value);
+        unsafe.putShort(address + 8, (short) value);
+        unsafe.putChar(address + 16, (char) value);
+        unsafe.putInt(address + 24, (int) value);
+        unsafe.putLong(address + 32, value);
+        unsafe.putFloat(address + 40, value);
+        unsafe.putDouble(address + 48, value);
+        return unsafeDirectMemoryRead(unsafe, address);
+    }
+
+    static class MyObject {
+        int i = 42;
+        final int j = 24;
+        final String a = "a";
+        final String b;
+
+        MyObject(String b) {
+            this.b = b;
+            Thread.dumpStack();
+        }
+
+        @Override
+        public String toString() {
+            return j + a + b + i;
+        }
+    }
+
+    @SuppressWarnings("all")
+    public static String unsafeAllocateInstance(Unsafe unsafe) throws InstantiationException {
+        return unsafe.allocateInstance(MyObject.class).toString();
+    }
+
+    @Test
+    public void testAllocateInstance() throws Exception {
+        unsafeAllocateInstance(UNSAFE);
+        test("unsafeAllocateInstance", UNSAFE);
+        test("unsafeAllocateInstance", (Object) null);
+    }
+
+    @Test
+    public void testGetAndAddInt() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "i");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, int.class};
+        for (int delta = Integer.MAX_VALUE - 10; delta < Integer.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndAddInt", Unsafe.class, "getAndAddInt", parameterTypes, UNSAFE, args1, args2);
+        }
+    }
+
+    public static int getAndAddInt(Object obj, long offset, int delta) {
+        return UNSAFE.getAndAddInt(obj, offset, delta);
+    }
+
+    @Test
+    public void testGetAndAddLong() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "l");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, long.class};
+        for (long delta = Long.MAX_VALUE - 10; delta < Long.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndAddLong", Unsafe.class, "getAndAddLong", parameterTypes, UNSAFE, args1, args2);
+        }
+    }
+
+    public static long getAndAddLong(Object obj, long offset, long delta) {
+        return UNSAFE.getAndAddLong(obj, offset, delta);
+    }
+
+    @Test
+    public void testGetAndSetInt() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "i");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, int.class};
+        for (int delta = Integer.MAX_VALUE - 10; delta < Integer.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndSetInt", Unsafe.class, "getAndSetInt", parameterTypes, UNSAFE, args1, args2);
+        }
+    }
+
+    public static int getAndSetInt(Object obj, long offset, int newValue) {
+        return UNSAFE.getAndSetInt(obj, offset, newValue);
+    }
+
+    @Test
+    public void testGetAndSetLong() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "l");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, long.class};
+        for (long newValue = Long.MAX_VALUE - 10; newValue < Long.MAX_VALUE; newValue++) {
+            Object[] args1 = new Object[]{f1, offset, newValue};
+            Object[] args2 = new Object[]{f2, offset, newValue};
+            testSubstitution("getAndSetLong", Unsafe.class, "getAndSetLong", parameterTypes, UNSAFE, args1, args2);
+        }
+    }
+
+    public static long getAndSetLong(Object obj, long offset, long newValue) {
+        return UNSAFE.getAndSetLong(obj, offset, newValue);
+    }
+
+    @Test
+    public void testGetAndSetObject() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "o");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, Object.class};
+        for (long i = 0; i < 10; i++) {
+            Object o = new Object();
+            Object[] args1 = new Object[]{f1, offset, o};
+            Object[] args2 = new Object[]{f2, offset, o};
+            testSubstitution("getAndSetObject", Unsafe.class, "getAndSetObject", parameterTypes, UNSAFE, args1, args2);
+            System.gc();
+        }
+    }
+
+    public static Object getAndSetObject(Object obj, long offset, Object newValue) {
+        return UNSAFE.getAndSetObject(obj, offset, newValue);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedIntegerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedIntegerTest.java
new file mode 100644
index 0000000..fcd0de7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedIntegerTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests the unsigned operations on {@link Integer} and {@link Long}.
+ */
+public class UnsignedIntegerTest extends GraalCompilerTest {
+
+    public static int compareInteger(int a, int b) {
+        return Integer.compareUnsigned(a, b);
+    }
+
+    public static int divideInteger(int a, int b) {
+        return Integer.divideUnsigned(a, b);
+    }
+
+    public static int remainderInteger(int a, int b) {
+        return Integer.remainderUnsigned(a, b);
+    }
+
+    public static long compareLong(long a, long b) {
+        return Long.compareUnsigned(a, b);
+    }
+
+    public static long divideLong(long a, long b) {
+        return Long.divideUnsigned(a, b);
+    }
+
+    public static long remainderLong(long a, long b) {
+        return Long.remainderUnsigned(a, b);
+    }
+
+    private void testInteger(int a, int b) {
+        test("compareInteger", a, b);
+        test("divideInteger", a, b);
+        test("remainderInteger", a, b);
+    }
+
+    private void testLong(long a, long b) {
+        test("compareLong", a, b);
+        test("divideLong", a, b);
+        test("remainderLong", a, b);
+    }
+
+    @Test
+    public void testInteger() {
+        testInteger(5, 7);
+        testInteger(-3, -7);
+        testInteger(-3, 7);
+        testInteger(42, -5);
+    }
+
+    @Test
+    public void testLong() {
+        testLong(5, 7);
+        testLong(-3, -7);
+        testLong(-3, 7);
+        testLong(42, -5);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedMathTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedMathTest.java
new file mode 100644
index 0000000..593d960
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsignedMathTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.common.calc.UnsignedMath;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests the substitutions for the {@link UnsignedMath} class.
+ */
+public class UnsignedMathTest extends GraalCompilerTest {
+
+    public static boolean aboveThanInt(int a, int b) {
+        return UnsignedMath.aboveThan(a, b);
+    }
+
+    public static boolean aboveOrEqualInt(int a, int b) {
+        return UnsignedMath.aboveOrEqual(a, b);
+    }
+
+    public static boolean belowThanInt(int a, int b) {
+        return UnsignedMath.belowThan(a, b);
+    }
+
+    public static boolean belowOrEqualInt(int a, int b) {
+        return UnsignedMath.belowOrEqual(a, b);
+    }
+
+    public static int divideInt(int a, int b) {
+        return Integer.divideUnsigned(a, b);
+    }
+
+    public static int remainderInt(int a, int b) {
+        return Integer.remainderUnsigned(a, b);
+    }
+
+    public static boolean aboveThanLong(long a, long b) {
+        return UnsignedMath.aboveThan(a, b);
+    }
+
+    public static boolean aboveOrEqualLong(long a, long b) {
+        return UnsignedMath.aboveOrEqual(a, b);
+    }
+
+    public static boolean belowThanLong(long a, long b) {
+        return UnsignedMath.belowThan(a, b);
+    }
+
+    public static boolean belowOrEqualLong(long a, long b) {
+        return UnsignedMath.belowOrEqual(a, b);
+    }
+
+    public static long divideLong(long a, long b) {
+        return Long.divideUnsigned(a, b);
+    }
+
+    public static long remainderLong(long a, long b) {
+        return Long.remainderUnsigned(a, b);
+    }
+
+    private void testInt(int a, int b) {
+        test("aboveThanInt", a, b);
+        test("aboveOrEqualInt", a, b);
+        test("belowThanInt", a, b);
+        test("belowOrEqualInt", a, b);
+        test("divideInt", a, b);
+        test("remainderInt", a, b);
+    }
+
+    private void testLong(long a, long b) {
+        test("aboveThanLong", a, b);
+        test("aboveOrEqualLong", a, b);
+        test("belowThanLong", a, b);
+        test("belowOrEqualLong", a, b);
+        test("divideLong", a, b);
+        test("remainderLong", a, b);
+    }
+
+    @Test
+    public void testInt() {
+        testInt(5, 7);
+        testInt(-3, -7);
+        testInt(-3, 7);
+        testInt(42, -5);
+    }
+
+    @Test
+    public void testLong() {
+        testLong(5, 7);
+        testLong(-3, -7);
+        testLong(-3, 7);
+        testLong(42, -5);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnwindExceptionToCallerTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnwindExceptionToCallerTest.java
new file mode 100644
index 0000000..2eb284c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnwindExceptionToCallerTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+
+/**
+ * Tests exception throwing from Graal compiled code.
+ */
+public class UnwindExceptionToCallerTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        NullPointerException npe = new NullPointerException();
+        test("test1Snippet", "a string", npe);
+        test("test1Snippet", (String) null, npe);
+    }
+
+    public static String test1Snippet(String message, NullPointerException npe) {
+        if (message == null) {
+            throw npe;
+        }
+        return message;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java
new file mode 100644
index 0000000..cbe0856
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.word.Pointer;
+import org.graalvm.compiler.word.Unsigned;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordBase;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests for the {@link Word} type.
+ */
+public class WordTest extends GraalCompilerTest implements Snippets {
+
+    private final ReplacementsImpl installer;
+
+    public WordTest() {
+        installer = (ReplacementsImpl) getReplacements();
+    }
+
+    @Override
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) {
+        // create a copy to assign a valid compilation id
+        return installer.makeGraph(m, null, null).copyWithIdentifier(compilationId);
+    }
+
+    @Test
+    public void construction() {
+        long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
+                        Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
+        for (long word : words) {
+            test("unsignedLong", word);
+            test("unsignedInt", (int) word);
+            test("signedLong", word);
+            test("signedInt", (int) word);
+        }
+    }
+
+    @Test
+    public void testArithmetic() {
+        long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
+                        Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
+        for (long word : words) {
+            test("unsignedNot", word);
+            test("signedNot", word);
+            for (long addend : words) {
+                test("unsignedPlusInt", word, (int) addend);
+                test("unsignedMinusInt", word, (int) addend);
+                test("unsignedPlusInt", word, -((int) addend));
+                test("unsignedMinusInt", word, -((int) addend));
+                test("unsignedPlusLong", word, addend);
+                test("unsignedMinusLong", word, addend);
+                test("unsignedPlusLong", word, -addend);
+                test("unsignedMinusLong", word, -addend);
+                test("signedPlusInt", word, (int) addend);
+                test("signedMinusInt", word, (int) addend);
+                test("signedPlusInt", word, -((int) addend));
+                test("signedMinusInt", word, -((int) addend));
+                test("signedPlusLong", word, addend);
+                test("signedMinusLong", word, addend);
+                test("signedPlusLong", word, -addend);
+                test("signedMinusLong", word, -addend);
+
+                test("andInt", word, (int) addend);
+                test("orInt", word, (int) addend);
+                test("andInt", word, -((int) addend));
+                test("orInt", word, -((int) addend));
+                test("andLong", word, addend);
+                test("orLong", word, addend);
+                test("andLong", word, -addend);
+                test("orLong", word, -addend);
+            }
+        }
+    }
+
+    @Test
+    public void testCompare() {
+        long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
+        for (long word1 : words) {
+            for (long word2 : words) {
+                for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) {
+                    test(method, word1, word2);
+                    test(method, word2, word1);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testCast() {
+        test("cast", 1234L);
+    }
+
+    @Snippet
+    public static long cast(long input) {
+        WordBase base = Word.signed(input);
+        Unsigned unsigned = (Unsigned) base;
+        Pointer pointer = (Pointer) unsigned;
+        Word word = (Word) pointer;
+        return word.rawValue();
+    }
+
+    @Snippet
+    public static long unsignedLong(long word) {
+        return Word.unsigned(word).rawValue();
+    }
+
+    @Snippet
+    public static long unsignedInt(int word) {
+        return Word.unsigned(word).rawValue();
+    }
+
+    @Snippet
+    public static long signedLong(long word) {
+        return Word.signed(word).rawValue();
+    }
+
+    @Snippet
+    public static long signedInt(int word) {
+        return Word.signed(word).rawValue();
+    }
+
+    @Snippet
+    public static long unsignedPlusInt(long word, int addend) {
+        return Word.unsigned(word).add(addend).rawValue();
+    }
+
+    @Snippet
+    public static long unsignedMinusInt(long word, int addend) {
+        return Word.unsigned(word).subtract(addend).rawValue();
+    }
+
+    @Snippet
+    public static long unsignedPlusLong(long word, long addend) {
+        return Word.unsigned(word).add(Word.unsigned(addend)).rawValue();
+    }
+
+    @Snippet
+    public static long unsignedMinusLong(long word, long addend) {
+        return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue();
+    }
+
+    @Snippet
+    public static long signedPlusInt(long word, int addend) {
+        return Word.signed(word).add(addend).rawValue();
+    }
+
+    @Snippet
+    public static long signedMinusInt(long word, int addend) {
+        return Word.signed(word).subtract(addend).rawValue();
+    }
+
+    @Snippet
+    public static long signedPlusLong(long word, long addend) {
+        return Word.signed(word).add(Word.signed(addend)).rawValue();
+    }
+
+    @Snippet
+    public static long signedMinusLong(long word, long addend) {
+        return Word.signed(word).subtract(Word.signed(addend)).rawValue();
+    }
+
+    @Snippet
+    public static long signedNot(long word) {
+        return Word.signed(word).not().rawValue();
+    }
+
+    @Snippet
+    public static long unsignedNot(long word) {
+        return Word.unsigned(word).not().rawValue();
+    }
+
+    @Snippet
+    public static boolean aboveOrEqual(long word1, long word2) {
+        return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2));
+    }
+
+    @Snippet
+    public static boolean above(long word1, long word2) {
+        return Word.unsigned(word1).aboveThan(Word.unsigned(word2));
+    }
+
+    @Snippet
+    public static boolean belowOrEqual(long word1, long word2) {
+        return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2));
+    }
+
+    @Snippet
+    public static boolean below(long word1, long word2) {
+        return Word.unsigned(word1).belowThan(Word.unsigned(word2));
+    }
+
+    @Snippet
+    public static long andInt(long word, int addend) {
+        return Word.unsigned(word).and(addend).rawValue();
+    }
+
+    @Snippet
+    public static long orInt(long word, int addend) {
+        return Word.unsigned(word).or(addend).rawValue();
+    }
+
+    @Snippet
+    public static long andLong(long word, long addend) {
+        return Word.unsigned(word).and(Word.unsigned(addend)).rawValue();
+    }
+
+    @Snippet
+    public static long orLong(long word, long addend) {
+        return Word.unsigned(word).or(Word.unsigned(addend)).rawValue();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java
new file mode 100644
index 0000000..4c4c267
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test.classfile;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST;
+import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO;
+import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT;
+import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE;
+import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.INSTANCEOF;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
+import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W;
+import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD;
+import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEW;
+import static org.graalvm.compiler.bytecode.Bytecodes.NEWARRAY;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.RET;
+import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH;
+import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Formatter;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
+import org.graalvm.compiler.bytecode.BytecodeStream;
+import org.graalvm.compiler.bytecode.BytecodeSwitch;
+import org.graalvm.compiler.bytecode.BytecodeTableSwitch;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecode;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaMethodProfile.ProfiledMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Tests that bytecode exposed via {@link ClassfileBytecode} objects is the same as the bytecode
+ * (modulo minor differences in constant pool resolution) obtained directly from
+ * {@link ResolvedJavaMethod} objects.
+ */
+public class ClassfileBytecodeProviderTest extends GraalCompilerTest {
+
+    private static boolean shouldProcess(String classpathEntry) {
+        if (classpathEntry.endsWith(".jar")) {
+            String name = new File(classpathEntry).getName();
+            return name.contains("jvmci") || name.contains("graal");
+        }
+        return false;
+    }
+
+    @Test
+    public void test() {
+        RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
+        Providers providers = rt.getHostBackend().getProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+
+        Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
+
+        String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path";
+        String bootclasspath = System.getProperty(propertyName);
+        Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath);
+
+        for (String path : bootclasspath.split(File.pathSeparator)) {
+            if (shouldProcess(path)) {
+                try {
+                    final ZipFile zipFile = new ZipFile(new File(path));
+                    for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) {
+                        final ZipEntry zipEntry = entry.nextElement();
+                        String name = zipEntry.getName();
+                        if (name.endsWith(".class") && !name.equals("module-info.class")) {
+                            String className = name.substring(0, name.length() - ".class".length()).replace('/', '.');
+                            try {
+                                checkClass(metaAccess, getSnippetReflection(), className);
+                            } catch (ClassNotFoundException e) {
+                                throw new AssertionError(e);
+                            }
+                        }
+                    }
+                } catch (IOException ex) {
+                    Assert.fail(ex.toString());
+                }
+            }
+        }
+    }
+
+    protected void checkClass(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, String className) throws ClassNotFoundException {
+        Class<?> c = Class.forName(className, true, getClass().getClassLoader());
+        ClassfileBytecodeProvider cbp = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+        for (Method method : c.getDeclaredMethods()) {
+            checkMethod(cbp, metaAccess, method);
+        }
+    }
+
+    private static void checkMethod(ClassfileBytecodeProvider cbp, MetaAccessProvider metaAccess, Executable executable) {
+        ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable);
+        if (method.hasBytecodes()) {
+            ResolvedJavaMethodBytecode expected = new ResolvedJavaMethodBytecode(method);
+            Bytecode actual = getBytecode(cbp, method);
+            new BytecodeComparer(expected, actual).compare();
+        }
+    }
+
+    protected static Bytecode getBytecode(ClassfileBytecodeProvider cbp, ResolvedJavaMethod method) {
+        try {
+            return cbp.getBytecode(method);
+        } catch (Throwable e) {
+            throw new AssertionError(String.format("Error getting bytecode for %s", method.format("%H.%n(%p)")), e);
+        }
+    }
+
+    static class BytecodeComparer {
+
+        private Bytecode expected;
+        private Bytecode actual;
+        private ConstantPool eCp;
+        private ConstantPool aCp;
+        BytecodeStream eStream;
+        BytecodeStream aStream;
+        int bci = -1;
+
+        BytecodeComparer(Bytecode expected, Bytecode actual) {
+            this.expected = expected;
+            this.actual = actual;
+            this.eCp = expected.getConstantPool();
+            this.aCp = actual.getConstantPool();
+            Assert.assertEquals(expected.getMethod().toString(), expected.getCodeSize(), actual.getCodeSize());
+            this.eStream = new BytecodeStream(expected.getCode());
+            this.aStream = new BytecodeStream(actual.getCode());
+        }
+
+        public void compare() {
+            try {
+                compare0();
+            } catch (Throwable e) {
+                BytecodeDisassembler dis = new BytecodeDisassembler(true, false);
+                Formatter msg = new Formatter();
+                msg.format("Error comparing bytecode for %s", expected.getMethod().format("%H.%n(%p)"));
+                if (bci >= 0) {
+                    msg.format("%nexpected: %s", dis.disassemble(expected, bci, eStream.nextBCI() - 1));
+                    msg.format("%nactual:   %s", dis.disassemble(actual, bci, aStream.nextBCI() - 1));
+                }
+                throw new AssertionError(msg.toString(), e);
+            }
+        }
+
+        public void compare0() {
+            int opcode = eStream.currentBC();
+            ResolvedJavaMethod method = expected.getMethod();
+            while (opcode != Bytecodes.END) {
+                bci = eStream.currentBCI();
+                int actualOpcode = aStream.currentBC();
+                if (opcode != actualOpcode) {
+                    Assert.assertEquals(opcode, actualOpcode);
+                }
+                if (eStream.nextBCI() > bci + 1) {
+                    switch (opcode) {
+                        case BIPUSH:
+                            Assert.assertEquals(eStream.readByte(), aStream.readByte());
+                            break;
+                        case SIPUSH:
+                            Assert.assertEquals(eStream.readShort(), aStream.readShort());
+                            break;
+                        case NEW:
+                        case CHECKCAST:
+                        case INSTANCEOF:
+                        case ANEWARRAY: {
+                            ResolvedJavaType e = lookupType(eCp, eStream.readCPI(), opcode);
+                            ResolvedJavaType a = lookupType(aCp, aStream.readCPI(), opcode);
+                            assertEqualTypes(e, a);
+                            break;
+                        }
+                        case GETSTATIC:
+                        case PUTSTATIC:
+                        case GETFIELD:
+                        case PUTFIELD: {
+                            ResolvedJavaField e = lookupField(eCp, eStream.readCPI(), method, opcode);
+                            ResolvedJavaField a = lookupField(aCp, aStream.readCPI(), method, opcode);
+                            assertEqualFields(e, a);
+                            break;
+                        }
+                        case INVOKEVIRTUAL:
+                        case INVOKESPECIAL:
+                        case INVOKESTATIC: {
+                            ResolvedJavaMethod e = lookupMethod(eCp, eStream.readCPI(), opcode);
+                            ResolvedJavaMethod a = lookupMethodOrNull(aCp, aStream.readCPI(), opcode);
+                            assertEqualMethods(e, a);
+                            break;
+                        }
+                        case INVOKEINTERFACE: {
+                            ResolvedJavaMethod e = lookupMethod(eCp, eStream.readCPI(), opcode);
+                            ResolvedJavaMethod a = lookupMethod(aCp, aStream.readCPI(), opcode);
+                            assertEqualMethods(e, a);
+                            break;
+                        }
+                        case INVOKEDYNAMIC: {
+                            // INVOKEDYNAMIC is not supported by ClassfileBytecodeProvider
+                            return;
+                        }
+                        case LDC:
+                        case LDC_W:
+                        case LDC2_W: {
+                            Object e = lookupConstant(eCp, eStream.readCPI(), opcode);
+                            Object a = lookupConstant(aCp, aStream.readCPI(), opcode);
+                            assertEqualsConstants(e, a);
+                            break;
+                        }
+                        case RET:
+                        case ILOAD:
+                        case LLOAD:
+                        case FLOAD:
+                        case DLOAD:
+                        case ALOAD:
+                        case ISTORE:
+                        case LSTORE:
+                        case FSTORE:
+                        case DSTORE:
+                        case ASTORE: {
+                            Assert.assertEquals(eStream.readLocalIndex(), aStream.readLocalIndex());
+                            break;
+                        }
+                        case IFEQ:
+                        case IFNE:
+                        case IFLT:
+                        case IFGE:
+                        case IFGT:
+                        case IFLE:
+                        case IF_ICMPEQ:
+                        case IF_ICMPNE:
+                        case IF_ICMPLT:
+                        case IF_ICMPGE:
+                        case IF_ICMPGT:
+                        case IF_ICMPLE:
+                        case IF_ACMPEQ:
+                        case IF_ACMPNE:
+                        case GOTO:
+                        case JSR:
+                        case IFNULL:
+                        case IFNONNULL:
+                        case GOTO_W:
+                        case JSR_W: {
+                            Assert.assertEquals(eStream.readBranchDest(), aStream.readBranchDest());
+                            break;
+                        }
+                        case LOOKUPSWITCH:
+                        case TABLESWITCH: {
+                            BytecodeSwitch e = opcode == LOOKUPSWITCH ? new BytecodeLookupSwitch(eStream, bci) : new BytecodeTableSwitch(eStream, bci);
+                            BytecodeSwitch a = opcode == LOOKUPSWITCH ? new BytecodeLookupSwitch(aStream, bci) : new BytecodeTableSwitch(aStream, bci);
+                            Assert.assertEquals(e.numberOfCases(), a.numberOfCases());
+                            for (int i = 0; i < e.numberOfCases(); i++) {
+                                Assert.assertEquals(e.keyAt(i), a.keyAt(i));
+                                Assert.assertEquals(e.targetAt(i), a.targetAt(i));
+                            }
+                            Assert.assertEquals(e.defaultTarget(), a.defaultTarget());
+                            Assert.assertEquals(e.defaultOffset(), a.defaultOffset());
+                            break;
+                        }
+                        case NEWARRAY: {
+                            Assert.assertEquals(eStream.readLocalIndex(), aStream.readLocalIndex());
+                            break;
+                        }
+                        case MULTIANEWARRAY: {
+                            ResolvedJavaType e = lookupType(eCp, eStream.readCPI(), opcode);
+                            ResolvedJavaType a = lookupType(aCp, aStream.readCPI(), opcode);
+                            Assert.assertEquals(e, a);
+                            break;
+                        }
+                    }
+                }
+                eStream.next();
+                aStream.next();
+                opcode = eStream.currentBC();
+            }
+        }
+
+        static Object lookupConstant(ConstantPool cp, int cpi, int opcode) {
+            cp.loadReferencedType(cpi, opcode);
+            return cp.lookupConstant(cpi);
+        }
+
+        static ResolvedJavaField lookupField(ConstantPool cp, int cpi, ResolvedJavaMethod method, int opcode) {
+            cp.loadReferencedType(cpi, opcode);
+            return (ResolvedJavaField) cp.lookupField(cpi, method, opcode);
+        }
+
+        static ResolvedJavaMethod lookupMethod(ConstantPool cp, int cpi, int opcode) {
+            cp.loadReferencedType(cpi, opcode);
+            return (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode);
+        }
+
+        static ResolvedJavaMethod lookupMethodOrNull(ConstantPool cp, int cpi, int opcode) {
+            try {
+                return lookupMethod(cp, cpi, opcode);
+            } catch (NoSuchMethodError e) {
+                // A method hidden to reflection
+                return null;
+            }
+        }
+
+        static ResolvedJavaType lookupType(ConstantPool cp, int cpi, int opcode) {
+            cp.loadReferencedType(cpi, opcode);
+            return (ResolvedJavaType) cp.lookupType(cpi, opcode);
+        }
+
+        static void assertEqualsConstants(Object e, Object a) {
+            if (!e.equals(a)) {
+                Assert.assertEquals(String.valueOf(e), String.valueOf(a));
+            }
+        }
+
+        static void assertEqualFields(JavaField e, JavaField a) {
+            if (!e.equals(a)) {
+                Assert.assertEquals(e.format("%H.%n %T"), a.format("%H.%n %T"));
+            }
+        }
+
+        static void assertEqualTypes(JavaType e, JavaType a) {
+            if (!e.equals(a)) {
+                Assert.assertEquals(e.toJavaName(), a.toJavaName());
+            }
+        }
+
+        static void assertEqualMethods(ResolvedJavaMethod e, ResolvedJavaMethod a) {
+            if (a != null) {
+                if (!e.equals(a)) {
+                    if (!e.equals(a)) {
+                        if (!e.getDeclaringClass().equals(a.getDeclaringClass())) {
+
+                            if (!typesAreRelated(e, a)) {
+                                throw new AssertionError(String.format("%s and %s are unrelated", a.getDeclaringClass().toJavaName(), e.getDeclaringClass().toJavaName()));
+                            }
+                        }
+                        Assert.assertEquals(e.getName(), a.getName());
+                        Assert.assertEquals(e.getSignature(), a.getSignature());
+                    } else {
+                        Assert.assertEquals(e, a);
+                    }
+                }
+            }
+        }
+
+        /**
+         * The VM can resolve references to methods not available via reflection. For example, the
+         * javap output for {@link ProfiledMethod#toString()} includes:
+         *
+         * <pre>
+         *     16: invokeinterface #40, 1 // InterfaceMethod jdk/vm/ci/meta/ResolvedJavaMethod.getName:()Ljava/lang/String;
+         * </pre>
+         *
+         * When resolving via {@code HotSpotConstantPool}, we get:
+         *
+         * <pre>
+         *     16: invokeinterface#4, 1   // jdk.vm.ci.meta.ResolvedJavaMethod.getName:()java.lang.String
+         * </pre>
+         *
+         * However resolving via {@code ClassfileConstantPool}, we get:
+         *
+         * <pre>
+         *     16: invokeinterface#40, 1  // jdk.vm.ci.meta.JavaMethod.getName:()java.lang.String
+         * </pre>
+         *
+         * since the latter relies on {@link ResolvedJavaType#getDeclaredMethods()} which only
+         * returns methods originating from class files.
+         *
+         * We accept such differences for the purpose of this test if the declaring class of two
+         * otherwise similar methods are related (i.e. one is a subclass of the other).
+         */
+        protected static boolean typesAreRelated(ResolvedJavaMethod e, ResolvedJavaMethod a) {
+            return a.getDeclaringClass().isAssignableFrom(e.getDeclaringClass()) || e.getDeclaringClass().isAssignableFrom(a.getDeclaringClass());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java
new file mode 100644
index 0000000..90f0b54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test.classfile;
+
+import static org.junit.Assume.assumeTrue;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.ProtectionDomain;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import javax.tools.ToolProvider;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests that intrinsics (and snippets) are isolated from bytecode instrumentation.
+ */
+public class RedefineIntrinsicTest extends GraalCompilerTest {
+
+    public static class Original {
+
+        // Intrinsified by Intrinsic.getValue
+        public static String getValue() {
+            return "original";
+        }
+    }
+
+    @ClassSubstitution(Original.class)
+    private static class Intrinsic {
+
+        @MethodSubstitution
+        public static String getValue() {
+            return "intrinsic";
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+        BytecodeProvider replacementBytecodeProvider = getReplacements().getReplacementBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, Original.class, replacementBytecodeProvider);
+        r.registerMethodSubstitution(Intrinsic.class, "getValue");
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    public static String callOriginalGetValue() {
+        // This call will be intrinsified when compiled by Graal
+        return Original.getValue();
+    }
+
+    public static String callIntrinsicGetValue() {
+        // This call will *not* be intrinsified when compiled by Graal
+        return Intrinsic.getValue();
+    }
+
+    @Test
+    public void test() throws Throwable {
+        Object receiver = null;
+        Object[] args = {};
+
+        // Prior to redefinition, both Original and Intrinsic
+        // should behave as per their Java source code
+        Assert.assertEquals("original", Original.getValue());
+        Assert.assertEquals("intrinsic", Intrinsic.getValue());
+
+        ResolvedJavaMethod callOriginalGetValue = getResolvedJavaMethod("callOriginalGetValue");
+        ResolvedJavaMethod callIntrinsicGetValue = getResolvedJavaMethod("callIntrinsicGetValue");
+
+        // Expect intrinsification to change "original" to "intrinsic"
+        testAgainstExpected(callOriginalGetValue, new Result("intrinsic", null), receiver, args);
+
+        // Expect no intrinsification
+        testAgainstExpected(callIntrinsicGetValue, new Result("intrinsic", null), receiver, args);
+
+        // Apply redefinition of intrinsic bytecode
+        redefineIntrinsic();
+
+        // Expect redefinition to have no effect
+        Assert.assertEquals("original", Original.getValue());
+
+        // Expect redefinition to change "intrinsic" to "redefined"
+        Assert.assertEquals("redefined", Intrinsic.getValue());
+
+        // Expect redefinition to have no effect on intrinsification (i.e.,
+        // "original" is still changed to "intrinsic", not "redefined"
+        testAgainstExpected(callOriginalGetValue, new Result("intrinsic", null), receiver, args);
+    }
+
+    /**
+     * Adds the class file bytes for a given class to a JAR stream.
+     */
+    static void add(JarOutputStream jar, Class<?> c) throws IOException {
+        String name = c.getName();
+        String classAsPath = name.replace('.', '/') + ".class";
+        jar.putNextEntry(new JarEntry(classAsPath));
+
+        InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath);
+
+        int nRead;
+        byte[] buf = new byte[1024];
+        while ((nRead = stream.read(buf, 0, buf.length)) != -1) {
+            jar.write(buf, 0, nRead);
+        }
+
+        jar.closeEntry();
+    }
+
+    static void redefineIntrinsic() throws Exception {
+        Manifest manifest = new Manifest();
+        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        Attributes mainAttrs = manifest.getMainAttributes();
+        mainAttrs.putValue("Agent-Class", RedefinerAgent.class.getName());
+        mainAttrs.putValue("Can-Redefine-Classes", "true");
+        mainAttrs.putValue("Can-Retransform-Classes", "true");
+
+        Path jar = Files.createTempFile("myagent", ".jar");
+        try {
+            JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest);
+            add(jarStream, RedefinerAgent.class);
+            add(jarStream, Redefiner.class);
+            jarStream.close();
+
+            loadAgent(jar);
+        } finally {
+            Files.deleteIfExists(jar);
+        }
+    }
+
+    public static void loadAgent(Path agent) throws Exception {
+        String vmName = ManagementFactory.getRuntimeMXBean().getName();
+        int p = vmName.indexOf('@');
+        assumeTrue("VM name not in <pid>@<host> format: " + vmName, p != -1);
+        String pid = vmName.substring(0, p);
+        ClassLoader cl = ToolProvider.getSystemToolClassLoader();
+        Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl);
+        Method attach = c.getDeclaredMethod("attach", String.class);
+        Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class);
+        Method detach = c.getDeclaredMethod("detach");
+        Object vm = attach.invoke(null, pid);
+        loadAgent.invoke(vm, agent.toString(), "");
+        detach.invoke(vm);
+    }
+
+    public static class RedefinerAgent {
+
+        public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception {
+            if (inst.isRedefineClassesSupported() && inst.isRetransformClassesSupported()) {
+                inst.addTransformer(new Redefiner(), true);
+                Class<?>[] allClasses = inst.getAllLoadedClasses();
+                for (int i = 0; i < allClasses.length; i++) {
+                    Class<?> c = allClasses[i];
+                    if (c == Intrinsic.class) {
+                        inst.retransformClasses(new Class<?>[]{c});
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This transformer replaces the first instance of the constant "intrinsic" in the class file
+     * for {@link Intrinsic} with "redefined".
+     */
+    static class Redefiner implements ClassFileTransformer {
+
+        @Override
+        public byte[] transform(ClassLoader cl, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
+            if (Intrinsic.class.equals(classBeingRedefined)) {
+                String cf = new String(classfileBuffer);
+                int i = cf.indexOf("intrinsic");
+                Assert.assertTrue("cannot find \"intrinsic\" constant in " + Intrinsic.class.getSimpleName() + "'s class file", i > 0);
+                System.arraycopy("redefined".getBytes(), 0, classfileBuffer, i, "redefined".length());
+            }
+            return classfileBuffer;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..1d3cd49
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.graalvm.compiler.replacements.verifier.VerifierAnnotationProcessor
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/APHotSpotSignature.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/APHotSpotSignature.java
new file mode 100644
index 0000000..48cf4d7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/APHotSpotSignature.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+/**
+ * Pretty much copied from HotSpotSignature but using a different method for resolving types. This
+ * class should be rewritten, its just a quick hack to get signatures working.
+ */
+final class APHotSpotSignature {
+
+    private final List<String> arguments = new ArrayList<>();
+    private final String returnType;
+    private final String originalString;
+    private TypeMirror[] argumentTypes;
+    private TypeMirror returnTypeCache;
+
+    APHotSpotSignature(String signature) {
+        assert signature.length() > 0;
+        this.originalString = signature;
+
+        if (signature.charAt(0) == '(') {
+            int cur = 1;
+            while (cur < signature.length() && signature.charAt(cur) != ')') {
+                int nextCur = parseSignature(signature, cur);
+                arguments.add(signature.substring(cur, nextCur));
+                cur = nextCur;
+            }
+
+            cur++;
+            int nextCur = parseSignature(signature, cur);
+            returnType = signature.substring(cur, nextCur);
+            if (nextCur != signature.length()) {
+                throw new RuntimeException("Invalid trailing characters.");
+            }
+        } else {
+            returnType = null;
+        }
+    }
+
+    private static int parseSignature(String signature, int start) {
+        int cur = start;
+        char first;
+        do {
+            first = signature.charAt(cur++);
+        } while (first == '[');
+
+        switch (first) {
+            case 'L':
+                while (signature.charAt(cur) != ';') {
+                    cur++;
+                }
+                cur++;
+                break;
+            case 'V':
+            case 'I':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'J':
+            case 'S':
+            case 'Z':
+                break;
+            default:
+                throw new RuntimeException("Invalid character at index " + cur + " in signature: " + signature);
+        }
+        return cur;
+    }
+
+    public int getParameterCount(boolean withReceiver) {
+        return arguments.size() + (withReceiver ? 1 : 0);
+    }
+
+    public TypeMirror getParameterType(ProcessingEnvironment env, int index) {
+        if (argumentTypes == null) {
+            argumentTypes = new TypeMirror[arguments.size()];
+        }
+        TypeMirror type = argumentTypes[index];
+        if (arguments.get(index) == null) {
+            throw new RuntimeException(String.format("Invalid argument at index %s.", index));
+        }
+
+        if (type == null) {
+            argumentTypes[index] = lookupType(env, arguments.get(index));
+        }
+        return argumentTypes[index];
+    }
+
+    private static TypeMirror lookupType(ProcessingEnvironment env, String binaryName) {
+        if (binaryName.length() == 1) {
+            TypeKind kind = fromPrimitiveOrVoidTypeChar(binaryName.charAt(0));
+            if (kind.isPrimitive()) {
+                return env.getTypeUtils().getPrimitiveType(kind);
+            } else if (kind == TypeKind.VOID) {
+                return env.getTypeUtils().getNoType(kind);
+            }
+        }
+
+        String canonicalName = binaryName;
+        if (canonicalName.startsWith("L") && canonicalName.endsWith(";")) {
+            canonicalName = canonicalName.substring(1, canonicalName.length() - 1);
+        }
+        env.getMessager().printMessage(Kind.ERROR, canonicalName);
+
+        int arrayDims = 0;
+        while (canonicalName.startsWith("[")) {
+            canonicalName = canonicalName.substring(1, canonicalName.length());
+            arrayDims++;
+        }
+
+        canonicalName = canonicalName.replaceAll("/", ".");
+        TypeElement typeElement = env.getElementUtils().getTypeElement(canonicalName);
+        if (typeElement == null) {
+            throw new RuntimeException(String.format("Type with name %s not found.", canonicalName));
+        }
+        TypeMirror mirror = typeElement.asType();
+        for (int i = 0; i < arrayDims; i++) {
+            mirror = env.getTypeUtils().getArrayType(mirror);
+        }
+        return mirror;
+    }
+
+    /**
+     * Returns the kind from the character describing a primitive or void.
+     *
+     * @param ch the character
+     * @return the kind
+     */
+    public static TypeKind fromPrimitiveOrVoidTypeChar(char ch) {
+        switch (ch) {
+            case 'Z':
+                return TypeKind.BOOLEAN;
+            case 'C':
+                return TypeKind.CHAR;
+            case 'F':
+                return TypeKind.FLOAT;
+            case 'D':
+                return TypeKind.DOUBLE;
+            case 'B':
+                return TypeKind.BYTE;
+            case 'S':
+                return TypeKind.SHORT;
+            case 'I':
+                return TypeKind.INT;
+            case 'J':
+                return TypeKind.LONG;
+            case 'V':
+                return TypeKind.VOID;
+        }
+        throw new IllegalArgumentException("unknown primitive or void type character: " + ch);
+    }
+
+    public TypeMirror getReturnType(ProcessingEnvironment env) {
+        if (returnTypeCache == null) {
+            if (returnType == null) {
+                throw new RuntimeException("Invalid return type.");
+            }
+            returnTypeCache = lookupType(env, returnType);
+        }
+        return returnTypeCache;
+    }
+
+    @Override
+    public String toString() {
+        return "Signature<" + originalString + ">";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/AbstractVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/AbstractVerifier.java
new file mode 100644
index 0000000..db1d2b3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/AbstractVerifier.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+
+public abstract class AbstractVerifier {
+
+    protected final ProcessingEnvironment env;
+
+    public AbstractVerifier(ProcessingEnvironment env) {
+        this.env = env;
+    }
+
+    public abstract void verify(Element element, AnnotationMirror annotation, PluginGenerator generator);
+
+    public abstract Class<? extends Annotation> getAnnotationClass();
+
+    @SuppressWarnings("unchecked")
+    protected static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        if (value == null) {
+            return null;
+        }
+        if (expectedType.isArray()) {
+            ArrayList<Object> result = new ArrayList<>();
+            List<AnnotationValue> l = (List<AnnotationValue>) value.getValue();
+            for (AnnotationValue el : l) {
+                result.add(resolveAnnotationValue(expectedType.getComponentType(), el));
+            }
+            return (T) result.toArray((Object[]) Array.newInstance(expectedType.getComponentType(), result.size()));
+        }
+        Object unboxedValue = value.getValue();
+        if (unboxedValue != null) {
+            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
+                /*
+                 * Happens if type is invalid when using the ECJ compiler. The ECJ does not match
+                 * AP-API specification here.
+                 */
+                return null;
+            }
+            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
+                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
+            }
+        }
+        return (T) unboxedValue;
+    }
+
+    protected static AnnotationValue findAnnotationValue(AnnotationMirror mirror, String name) {
+        ExecutableElement valueMethod = null;
+        for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
+            if (method.getSimpleName().toString().equals(name)) {
+                valueMethod = method;
+                break;
+            }
+        }
+
+        if (valueMethod == null) {
+            return null;
+        }
+
+        AnnotationValue value = mirror.getElementValues().get(valueMethod);
+        if (value == null) {
+            value = valueMethod.getDefaultValue();
+        }
+
+        return value;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java
new file mode 100644
index 0000000..afcd6f1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+
+public final class ClassSubstitutionVerifier extends AbstractVerifier {
+
+    private static final String TYPE_VALUE = "value";
+    private static final String STRING_VALUE = "className";
+    private static final String OPTIONAL = "optional";
+
+    public ClassSubstitutionVerifier(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationClass() {
+        return ClassSubstitution.class;
+    }
+
+    @Override
+    public void verify(Element element, AnnotationMirror classSubstitution, PluginGenerator generator) {
+        if (!element.getKind().isClass()) {
+            assert false : "Element is guaranteed to be a class.";
+            return;
+        }
+        TypeElement type = (TypeElement) element;
+
+        TypeElement substitutionType = resolveOriginalType(env, type, classSubstitution);
+        if (substitutionType == null) {
+            return;
+        }
+    }
+
+    static TypeElement resolveOriginalType(ProcessingEnvironment env, Element sourceElement, AnnotationMirror classSubstition) {
+        AnnotationValue typeValue = findAnnotationValue(classSubstition, TYPE_VALUE);
+        AnnotationValue stringValue = findAnnotationValue(classSubstition, STRING_VALUE);
+        AnnotationValue optionalValue = findAnnotationValue(classSubstition, OPTIONAL);
+
+        assert typeValue != null && stringValue != null && optionalValue != null;
+
+        TypeMirror type = resolveAnnotationValue(TypeMirror.class, typeValue);
+        String[] classNames = resolveAnnotationValue(String[].class, stringValue);
+        boolean optional = resolveAnnotationValue(Boolean.class, optionalValue);
+
+        if (type.getKind() != TypeKind.DECLARED) {
+            env.getMessager().printMessage(Kind.ERROR, "The provided class must be a declared type.", sourceElement, classSubstition, typeValue);
+            return null;
+        }
+
+        if (!classSubstition.getAnnotationType().asElement().equals(((DeclaredType) type).asElement())) {
+            if (classNames.length != 0) {
+                String msg = "The usage of value and className is exclusive.";
+                env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, stringValue);
+                env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, typeValue);
+            }
+
+            return (TypeElement) ((DeclaredType) type).asElement();
+        }
+
+        if (classNames.length != 0) {
+            TypeElement typeElement = null;
+            for (String className : classNames) {
+                typeElement = env.getElementUtils().getTypeElement(className);
+                if (typeElement == null && !optional) {
+                    env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+                }
+            }
+
+            return typeElement;
+        }
+
+        if (!optional) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("No value for '%s' or '%s' provided but required.", TYPE_VALUE, STRING_VALUE), sourceElement, classSubstition);
+        }
+
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/FoldVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/FoldVerifier.java
new file mode 100644
index 0000000..6952143
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/FoldVerifier.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.api.replacements.Fold;
+
+public final class FoldVerifier extends AbstractVerifier {
+
+    public FoldVerifier(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationClass() {
+        return Fold.class;
+    }
+
+    @Override
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+        if (element.getKind() != ElementKind.METHOD) {
+            assert false : "Element is guaranteed to be a method.";
+            return;
+        }
+
+        ExecutableElement foldMethod = (ExecutableElement) element;
+        if (foldMethod.getModifiers().contains(Modifier.PRIVATE)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be private.", Fold.class.getSimpleName()), element, annotation);
+        } else {
+            generator.addPlugin(new GeneratedFoldPlugin(foldMethod));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedFoldPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedFoldPlugin.java
new file mode 100644
index 0000000..416b846
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedFoldPlugin.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link Fold} methods.
+ */
+public class GeneratedFoldPlugin extends GeneratedPlugin {
+
+    public GeneratedFoldPlugin(ExecutableElement intrinsicMethod) {
+        super(intrinsicMethod);
+    }
+
+    private static TypeMirror stringType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("java.lang.String").asType();
+    }
+
+    @Override
+    public void extraImports(Set<String> imports) {
+        imports.add("jdk.vm.ci.meta.JavaConstant");
+        imports.add("jdk.vm.ci.meta.JavaKind");
+        imports.add("org.graalvm.compiler.nodes.ConstantNode");
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
+        InjectedDependencies deps = new InjectedDependencies();
+        List<? extends VariableElement> params = intrinsicMethod.getParameters();
+
+        int argCount = 0;
+        Object receiver;
+        if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            receiver = intrinsicMethod.getEnclosingElement();
+        } else {
+            receiver = "arg0";
+            TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
+            constantArgument(env, out, deps, argCount, type.asType(), argCount);
+            argCount++;
+        }
+
+        int firstArg = argCount;
+        for (VariableElement param : params) {
+            if (param.getAnnotation(InjectedParameter.class) == null) {
+                constantArgument(env, out, deps, argCount, param.asType(), argCount);
+            } else {
+                out.printf("            assert checkInjectedArgument(b, args[%d], targetMethod);\n", argCount);
+                out.printf("            %s arg%d = %s;\n", param.asType(), argCount, deps.use(env, (DeclaredType) param.asType()));
+            }
+            argCount++;
+        }
+
+        Set<String> suppressWarnings = new TreeSet<>();
+        if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
+            suppressWarnings.add("deprecation");
+        }
+        if (hasRawtypeWarning(intrinsicMethod.getReturnType())) {
+            suppressWarnings.add("rawtypes");
+        }
+        for (VariableElement param : params) {
+            if (hasUncheckedWarning(param.asType())) {
+                suppressWarnings.add("unchecked");
+            }
+        }
+        if (suppressWarnings.size() > 0) {
+            out.printf("            @SuppressWarnings({");
+            String sep = "";
+            for (String suppressWarning : suppressWarnings) {
+                out.printf("%s\"%s\"", sep, suppressWarning);
+                sep = ", ";
+            }
+            out.printf("})\n");
+        }
+
+        out.printf("            %s result = %s.%s(", getErasedType(intrinsicMethod.getReturnType()), receiver, intrinsicMethod.getSimpleName());
+        if (argCount > firstArg) {
+            out.printf("arg%d", firstArg);
+            for (int i = firstArg + 1; i < argCount; i++) {
+                out.printf(", arg%d", i);
+            }
+        }
+        out.printf(");\n");
+
+        TypeMirror returnType = intrinsicMethod.getReturnType();
+        switch (returnType.getKind()) {
+            case BOOLEAN:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n");
+                break;
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result);\n");
+                break;
+            case LONG:
+                out.printf("            JavaConstant constant = JavaConstant.forLong(result);\n");
+                break;
+            case FLOAT:
+                out.printf("            JavaConstant constant = JavaConstant.forFloat(result);\n");
+                break;
+            case DOUBLE:
+                out.printf("            JavaConstant constant = JavaConstant.forDouble(result);\n");
+                break;
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                if (returnType.equals(stringType(env))) {
+                    out.printf("            JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION));
+                } else {
+                    out.printf("            JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION));
+                }
+                break;
+            default:
+                throw new IllegalArgumentException(returnType.toString());
+        }
+
+        out.printf("            ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH));
+        out.printf("            b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
+        out.printf("            return true;\n");
+
+        return deps;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java
new file mode 100644
index 0000000..2cfce1c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.InjectedNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link NodeIntrinsic} methods.
+ */
+public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin {
+
+    private final TypeMirror[] signature;
+
+    public GeneratedNodeIntrinsicPlugin(ExecutableElement intrinsicMethod, TypeMirror[] signature) {
+        super(intrinsicMethod);
+        this.signature = signature;
+    }
+
+    private static TypeMirror valueNodeType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType();
+    }
+
+    protected abstract List<? extends VariableElement> getParameters();
+
+    protected abstract void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount);
+
+    @Override
+    protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
+        InjectedDependencies deps = new InjectedDependencies();
+
+        List<? extends VariableElement> params = getParameters();
+
+        int idx = 0;
+        for (; idx < params.size(); idx++) {
+            VariableElement param = params.get(idx);
+            if (param.getAnnotation(InjectedNodeParameter.class) == null) {
+                break;
+            }
+
+            out.printf("            %s arg%d = %s;\n", param.asType(), idx, deps.use(env, (DeclaredType) param.asType()));
+        }
+
+        for (int i = 0; i < signature.length; i++, idx++) {
+            if (intrinsicMethod.getParameters().get(i).getAnnotation(ConstantNodeParameter.class) != null) {
+                constantArgument(env, out, deps, idx, signature[i], i);
+            } else {
+                if (signature[i].equals(valueNodeType(env))) {
+                    out.printf("            ValueNode arg%d = args[%d];\n", idx, i);
+                } else {
+                    out.printf("            %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
+                }
+            }
+        }
+
+        factoryCall(env, out, deps, idx);
+
+        return deps;
+    }
+
+    public static class ConstructorPlugin extends GeneratedNodeIntrinsicPlugin {
+
+        private final ExecutableElement constructor;
+
+        public ConstructorPlugin(ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+            super(intrinsicMethod, signature);
+            this.constructor = constructor;
+        }
+
+        @Override
+        public void extraImports(Set<String> imports) {
+            if (intrinsicMethod.getReturnType().getKind() != TypeKind.VOID) {
+                imports.add("jdk.vm.ci.meta.JavaKind");
+            }
+        }
+
+        @Override
+        protected List<? extends VariableElement> getParameters() {
+            return constructor.getParameters();
+        }
+
+        @Override
+        protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
+            out.printf("            %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
+            if (argCount > 0) {
+                out.printf("arg0");
+                for (int i = 1; i < argCount; i++) {
+                    out.printf(", arg%d", i);
+                }
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                out.printf("            node.setStamp(%s);\n", deps.use(WellKnownDependency.RETURN_STAMP));
+            }
+
+            if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) {
+                out.printf("            b.add(node);\n");
+            } else {
+                out.printf("            b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
+            }
+            out.printf("            return true;\n");
+        }
+    }
+
+    public static class CustomFactoryPlugin extends GeneratedNodeIntrinsicPlugin {
+
+        private final ExecutableElement customFactory;
+
+        public CustomFactoryPlugin(ExecutableElement intrinsicMethod, ExecutableElement customFactory, TypeMirror[] signature) {
+            super(intrinsicMethod, signature);
+            this.customFactory = customFactory;
+        }
+
+        @Override
+        public void extraImports(Set<String> imports) {
+        }
+
+        @Override
+        protected List<? extends VariableElement> getParameters() {
+            List<? extends VariableElement> ret = customFactory.getParameters();
+            // remove initial GraphBuilderContext and ResolvedJavaMethod parameters
+            return ret.subList(2, ret.size());
+        }
+
+        @Override
+        protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
+            out.printf("            return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName());
+            for (int i = 0; i < argCount; i++) {
+                out.printf(", arg%d", i);
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                env.getMessager().printMessage(Kind.WARNING, "Ignoring setStampFromReturnType because a custom 'intrinsify' method is used.", intrinsicMethod);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedPlugin.java
new file mode 100644
index 0000000..986b6cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedPlugin.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+
+import org.graalvm.compiler.replacements.verifier.InjectedDependencies.Dependency;
+import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+public abstract class GeneratedPlugin {
+
+    protected final ExecutableElement intrinsicMethod;
+    private boolean needInjectionProvider;
+
+    private String pluginName;
+
+    public GeneratedPlugin(ExecutableElement intrinsicMethod) {
+        this.intrinsicMethod = intrinsicMethod;
+        this.needInjectionProvider = false;
+        this.pluginName = intrinsicMethod.getEnclosingElement().getSimpleName() + "_" + intrinsicMethod.getSimpleName();
+    }
+
+    public String getPluginName() {
+        return pluginName;
+    }
+
+    public void setPluginName(String pluginName) {
+        this.pluginName = pluginName;
+    }
+
+    public void generate(ProcessingEnvironment env, PrintWriter out) {
+        out.printf("    //        class: %s\n", intrinsicMethod.getEnclosingElement());
+        out.printf("    //       method: %s\n", intrinsicMethod);
+        out.printf("    // generated-by: %s\n", getClass().getName());
+        out.printf("    private static final class %s extends GeneratedInvocationPlugin {\n", pluginName);
+        out.printf("\n");
+        out.printf("        @Override\n");
+        out.printf("        public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n");
+        InjectedDependencies deps = createExecute(env, out);
+        out.printf("        }\n");
+
+        createPrivateMembers(out, deps);
+
+        out.printf("    }\n");
+    }
+
+    public void register(PrintWriter out) {
+        out.printf("        plugins.register(new %s(", pluginName);
+        if (needInjectionProvider) {
+            out.printf("injection");
+        }
+        out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+        if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            out.printf(", InvocationPlugin.Receiver.class");
+        }
+        for (VariableElement arg : intrinsicMethod.getParameters()) {
+            out.printf(", %s.class", getErasedType(arg.asType()));
+        }
+        out.printf(");\n");
+    }
+
+    public abstract void extraImports(Set<String> imports);
+
+    protected abstract InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out);
+
+    private static TypeMirror resolvedJavaTypeType(ProcessingEnvironment env) {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    }
+
+    static String getErasedType(TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                TypeElement element = (TypeElement) declared.asElement();
+                return element.getQualifiedName().toString();
+            case TYPEVAR:
+                return getErasedType(((TypeVariable) type).getUpperBound());
+            case WILDCARD:
+                return getErasedType(((WildcardType) type).getExtendsBound());
+            case ARRAY:
+                return getErasedType(((ArrayType) type).getComponentType()) + "[]";
+            default:
+                return type.toString();
+        }
+    }
+
+    static boolean hasRawtypeWarning(TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                return declared.getTypeArguments().size() > 0;
+            case TYPEVAR:
+                return false;
+            case WILDCARD:
+                return false;
+            case ARRAY:
+                return hasRawtypeWarning(((ArrayType) type).getComponentType());
+            default:
+                return false;
+        }
+    }
+
+    static boolean hasUncheckedWarning(TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                for (TypeMirror typeParam : declared.getTypeArguments()) {
+                    if (hasUncheckedWarning(typeParam)) {
+                        return true;
+                    }
+                }
+                return false;
+            case TYPEVAR:
+                return true;
+            case WILDCARD:
+                return ((WildcardType) type).getExtendsBound() != null;
+            case ARRAY:
+                return hasUncheckedWarning(((ArrayType) type).getComponentType());
+            default:
+                return false;
+        }
+    }
+
+    private void createPrivateMembers(PrintWriter out, InjectedDependencies deps) {
+        if (!deps.isEmpty()) {
+            out.printf("\n");
+            for (Dependency dep : deps) {
+                out.printf("        private final %s %s;\n", dep.type, dep.name);
+            }
+
+            out.printf("\n");
+            out.printf("        private %s(InjectionProvider injection) {\n", pluginName);
+            for (Dependency dep : deps) {
+                out.printf("            this.%s = %s;\n", dep.name, dep.inject(intrinsicMethod));
+            }
+            out.printf("        }\n");
+
+            needInjectionProvider = true;
+        }
+    }
+
+    protected static String getReturnKind(ExecutableElement method) {
+        switch (method.getReturnType().getKind()) {
+            case BOOLEAN:
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                return "Int";
+            case LONG:
+                return "Long";
+            case FLOAT:
+                return "Float";
+            case DOUBLE:
+                return "Double";
+            case VOID:
+                return "Void";
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                return "Object";
+            default:
+                throw new IllegalArgumentException(method.getReturnType().toString());
+        }
+    }
+
+    protected static void constantArgument(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) {
+        if (hasRawtypeWarning(type)) {
+            out.printf("            @SuppressWarnings({\"rawtypes\"})\n");
+        }
+        out.printf("            %s arg%d;\n", getErasedType(type), argIdx);
+        out.printf("            if (args[%d].isConstant()) {\n", nodeIdx);
+        if (type.equals(resolvedJavaTypeType(env))) {
+            out.printf("                arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx);
+        } else {
+            switch (type.getKind()) {
+                case BOOLEAN:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx);
+                    break;
+                case BYTE:
+                    out.printf("                arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case CHAR:
+                    out.printf("                arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case SHORT:
+                    out.printf("                arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case INT:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case LONG:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx);
+                    break;
+                case FLOAT:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx);
+                    break;
+                case DOUBLE:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx);
+                    break;
+                case DECLARED:
+                    out.printf("                arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx);
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        out.printf("            } else {\n");
+        out.printf("                return false;\n");
+        out.printf("            }\n");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java
new file mode 100644
index 0000000..9342320
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.replacements.verifier.InjectedDependencies.Dependency;
+
+public class InjectedDependencies implements Iterable<Dependency> {
+
+    public abstract static class Dependency {
+
+        public final String name;
+        public final String type;
+
+        private Dependency(String name, String type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        public abstract String inject(ExecutableElement inject);
+    }
+
+    private static final class InjectedDependency extends Dependency {
+
+        private InjectedDependency(String name, String type) {
+            super(name, type);
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            return String.format("injection.getInjectedArgument(%s.class)", type);
+        }
+    }
+
+    private static final class StampDependency extends Dependency {
+
+        private StampDependency() {
+            super("returnStamp", "org.graalvm.compiler.core.common.type.Stamp");
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            NodeIntrinsic nodeIntrinsic = inject.getAnnotation(NodeIntrinsic.class);
+            return String.format("injection.getReturnStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nodeIntrinsic != null && nodeIntrinsic.returnStampIsNonNull());
+        }
+    }
+
+    public enum WellKnownDependency {
+        CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
+        META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
+        RETURN_STAMP(new StampDependency()),
+        SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "org.graalvm.compiler.api.replacements.SnippetReflectionProvider")),
+        STAMP_PROVIDER("b.getStampProvider()", "org.graalvm.compiler.nodes.spi.StampProvider"),
+        STRUCTURED_GRAPH("b.getGraph()", "org.graalvm.compiler.nodes.StructuredGraph");
+
+        private final String expr;
+        private final String type;
+        private final Dependency generateMember;
+
+        WellKnownDependency(String expr, String type) {
+            this.expr = expr;
+            this.type = type;
+            this.generateMember = null;
+        }
+
+        WellKnownDependency(Dependency generateMember) {
+            this.expr = generateMember.name;
+            this.type = generateMember.type;
+            this.generateMember = generateMember;
+        }
+
+        private TypeMirror getType(ProcessingEnvironment env) {
+            return env.getElementUtils().getTypeElement(type).asType();
+        }
+    }
+
+    private final HashMap<String, Dependency> deps;
+
+    public InjectedDependencies() {
+        deps = new HashMap<>();
+    }
+
+    public String use(WellKnownDependency wellKnown) {
+        if (wellKnown.generateMember != null) {
+            deps.put(wellKnown.type, wellKnown.generateMember);
+        }
+        return wellKnown.expr;
+    }
+
+    public String use(ProcessingEnvironment env, DeclaredType type) {
+        for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
+            if (env.getTypeUtils().isAssignable(wellKnown.getType(env), type)) {
+                return use(wellKnown);
+            }
+        }
+
+        String typeName = type.toString();
+        Dependency ret = deps.get(typeName);
+        if (ret == null) {
+            ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
+            deps.put(typeName, ret);
+        }
+        return ret.name;
+    }
+
+    @Override
+    public Iterator<Dependency> iterator() {
+        return deps.values().iterator();
+    }
+
+    public boolean isEmpty() {
+        return deps.isEmpty();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/MethodSubstitutionVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/MethodSubstitutionVerifier.java
new file mode 100644
index 0000000..141e3d8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/MethodSubstitutionVerifier.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+
+public final class MethodSubstitutionVerifier extends AbstractVerifier {
+
+    private static final boolean DEBUG = false;
+
+    private static final String ORIGINAL_METHOD_NAME = "value";
+    private static final String ORIGINAL_IS_STATIC = "isStatic";
+    private static final String ORIGINAL_SIGNATURE = "signature";
+
+    private static final String ORIGINAL_METHOD_NAME_DEFAULT = "";
+    private static final String ORIGINAL_SIGNATURE_DEFAULT = "";
+
+    public MethodSubstitutionVerifier(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationClass() {
+        return MethodSubstitution.class;
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+        if (element.getKind() != ElementKind.METHOD) {
+            assert false : "Element is guaranteed to be a method.";
+            return;
+        }
+        ExecutableElement substitutionMethod = (ExecutableElement) element;
+        TypeElement substitutionType = findEnclosingClass(substitutionMethod);
+        assert substitutionType != null;
+
+        AnnotationMirror substitutionClassAnnotation = VerifierAnnotationProcessor.findAnnotationMirror(env, substitutionType.getAnnotationMirrors(), ClassSubstitution.class);
+        if (substitutionClassAnnotation == null) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s annotation is required on the enclosing class.", ClassSubstitution.class.getSimpleName()), element, annotation);
+            return;
+        }
+        boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionClassAnnotation, "optional"));
+        if (optional) {
+            return;
+        }
+
+        TypeElement originalType = ClassSubstitutionVerifier.resolveOriginalType(env, substitutionType, substitutionClassAnnotation);
+        if (originalType == null) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("The @%s annotation is invalid on the enclosing class.", ClassSubstitution.class.getSimpleName()), element, annotation);
+            return;
+        }
+
+        if (!substitutionMethod.getModifiers().contains(Modifier.STATIC)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be static.", MethodSubstitution.class.getSimpleName()), element, annotation);
+        }
+
+        if (substitutionMethod.getModifiers().contains(Modifier.ABSTRACT) || substitutionMethod.getModifiers().contains(Modifier.NATIVE)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be native or abstract.", MethodSubstitution.class.getSimpleName()), element, annotation);
+        }
+
+        String originalName = originalName(substitutionMethod, annotation);
+        boolean isStatic = resolveAnnotationValue(Boolean.class, findAnnotationValue(annotation, ORIGINAL_IS_STATIC));
+        TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation, isStatic);
+        if (originalSignature == null) {
+            return;
+        }
+        ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature, isStatic);
+        if (DEBUG && originalMethod != null) {
+            env.getMessager().printMessage(Kind.NOTE, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
+        }
+    }
+
+    private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation, boolean isStatic) {
+        AnnotationValue signatureValue = findAnnotationValue(annotation, ORIGINAL_SIGNATURE);
+        String signatureString = resolveAnnotationValue(String.class, signatureValue);
+        List<TypeMirror> parameters = new ArrayList<>();
+        if (signatureString.equals(ORIGINAL_SIGNATURE_DEFAULT)) {
+            for (int i = 0; i < method.getParameters().size(); i++) {
+                parameters.add(method.getParameters().get(i).asType());
+            }
+            if (!isStatic) {
+                if (parameters.isEmpty()) {
+                    env.getMessager().printMessage(Kind.ERROR, "Method signature must be a static method with the 'this' object as its first parameter", method, annotation);
+                    return null;
+                } else {
+                    TypeMirror thisParam = parameters.remove(0);
+                    if (!isSubtype(originalType.asType(), thisParam)) {
+                        Name thisName = method.getParameters().get(0).getSimpleName();
+                        env.getMessager().printMessage(Kind.ERROR, String.format("The type of %s must assignable from %s", thisName, originalType), method, annotation);
+                    }
+                }
+            }
+            parameters.add(0, method.getReturnType());
+        } else {
+            try {
+                APHotSpotSignature signature = new APHotSpotSignature(signatureString);
+                parameters.add(signature.getReturnType(env));
+                for (int i = 0; i < signature.getParameterCount(false); i++) {
+                    parameters.add(signature.getParameterType(env, i));
+                }
+            } catch (Exception e) {
+                /*
+                 * That's not good practice and should be changed after APHotSpotSignature has
+                 * received a cleanup.
+                 */
+                env.getMessager().printMessage(Kind.ERROR, String.format("Parsing the signature failed: %s", e.getMessage() != null ? e.getMessage() : e.toString()), method, annotation,
+                                signatureValue);
+                return null;
+            }
+        }
+        return parameters.toArray(new TypeMirror[parameters.size()]);
+    }
+
+    private static String originalName(ExecutableElement substituteMethod, AnnotationMirror substitution) {
+        String originalMethodName = resolveAnnotationValue(String.class, findAnnotationValue(substitution, ORIGINAL_METHOD_NAME));
+        if (originalMethodName.equals(ORIGINAL_METHOD_NAME_DEFAULT)) {
+            originalMethodName = substituteMethod.getSimpleName().toString();
+        }
+        return originalMethodName;
+    }
+
+    private ExecutableElement originalMethod(ExecutableElement substitutionMethod, AnnotationMirror substitutionAnnotation, TypeElement originalType, String originalName,
+                    TypeMirror[] originalSignature, boolean isStatic) {
+        TypeMirror signatureReturnType = originalSignature[0];
+        TypeMirror[] signatureParameters = Arrays.copyOfRange(originalSignature, 1, originalSignature.length);
+        List<ExecutableElement> searchElements;
+        if (originalName.equals("<init>")) {
+            searchElements = ElementFilter.constructorsIn(originalType.getEnclosedElements());
+        } else {
+            searchElements = ElementFilter.methodsIn(originalType.getEnclosedElements());
+        }
+
+        ExecutableElement originalMethod = null;
+        outer: for (ExecutableElement searchElement : searchElements) {
+            if (searchElement.getSimpleName().toString().equals(originalName) && searchElement.getParameters().size() == signatureParameters.length) {
+                for (int i = 0; i < signatureParameters.length; i++) {
+                    VariableElement parameter = searchElement.getParameters().get(i);
+                    if (!isTypeCompatible(parameter.asType(), signatureParameters[i])) {
+                        continue outer;
+                    }
+                }
+                originalMethod = searchElement;
+                break;
+            }
+        }
+        if (originalMethod == null) {
+            boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionAnnotation, "optional"));
+            if (!optional) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("Could not find the original method with name '%s' and parameters '%s'.", originalName, Arrays.toString(signatureParameters)),
+                                substitutionMethod, substitutionAnnotation);
+            }
+            return null;
+        }
+
+        if (originalMethod.getModifiers().contains(Modifier.STATIC) != isStatic) {
+            boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionAnnotation, "optional"));
+            if (!optional) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("The %s element must be set to %s.", ORIGINAL_IS_STATIC, !isStatic), substitutionMethod, substitutionAnnotation);
+            }
+            return null;
+        }
+
+        if (!isTypeCompatible(originalMethod.getReturnType(), signatureReturnType)) {
+            env.getMessager().printMessage(
+                            Kind.ERROR,
+                            String.format("The return type of the substitution method '%s' must match with the return type of the original method '%s'.", signatureReturnType,
+                                            originalMethod.getReturnType()),
+                            substitutionMethod, substitutionAnnotation);
+            return null;
+        }
+
+        return originalMethod;
+    }
+
+    private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
+        TypeMirror original = originalType;
+        TypeMirror substitution = substitutionType;
+        if (needsErasure(original)) {
+            original = env.getTypeUtils().erasure(original);
+        }
+        if (needsErasure(substitution)) {
+            substitution = env.getTypeUtils().erasure(substitution);
+        }
+        return env.getTypeUtils().isSameType(original, substitution);
+    }
+
+    /**
+     * Tests whether one type is a subtype of another. Any type is considered to be a subtype of
+     * itself.
+     *
+     * @param t1 the first type
+     * @param t2 the second type
+     * @return {@code true} if and only if the first type is a subtype of the second
+     */
+    private boolean isSubtype(TypeMirror t1, TypeMirror t2) {
+        TypeMirror t1Erased = t1;
+        TypeMirror t2Erased = t2;
+        if (needsErasure(t1Erased)) {
+            t1Erased = env.getTypeUtils().erasure(t1Erased);
+        }
+        if (needsErasure(t2Erased)) {
+            t2Erased = env.getTypeUtils().erasure(t2Erased);
+        }
+        return env.getTypeUtils().isSubtype(t1Erased, t2Erased);
+    }
+
+    private static boolean needsErasure(TypeMirror typeMirror) {
+        return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
+                        typeMirror.getKind() != TypeKind.NULL;
+    }
+
+    private static TypeElement findEnclosingClass(Element element) {
+        if (element.getKind().isClass()) {
+            return (TypeElement) element;
+        }
+
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            if (enclosing.getKind().isClass()) {
+                return (TypeElement) enclosing;
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java
new file mode 100644
index 0000000..4145eb5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.InjectedNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.StructuralInput.MarkerType;
+
+public final class NodeIntrinsicVerifier extends AbstractVerifier {
+
+    private static final String NODE_CLASS_NAME = "value";
+
+    private TypeMirror nodeType() {
+        return env.getElementUtils().getTypeElement("org.graalvm.compiler.graph.Node").asType();
+    }
+
+    private TypeMirror valueNodeType() {
+        return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType();
+    }
+
+    private TypeMirror classType() {
+        return env.getElementUtils().getTypeElement("java.lang.Class").asType();
+    }
+
+    private TypeMirror resolvedJavaTypeType() {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    }
+
+    private TypeMirror resolvedJavaMethodType() {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaMethod").asType();
+    }
+
+    private TypeMirror structuralInputType() {
+        return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodeinfo.StructuralInput").asType();
+    }
+
+    private TypeMirror graphBuilderContextType() {
+        return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext").asType();
+    }
+
+    public NodeIntrinsicVerifier(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationClass() {
+        return NodeIntrinsic.class;
+    }
+
+    @Override
+    public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+        if (element.getKind() != ElementKind.METHOD) {
+            assert false : "Element is guaranteed to be a method.";
+            return;
+        }
+
+        ExecutableElement intrinsicMethod = (ExecutableElement) element;
+        if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be static.", NodeIntrinsic.class.getSimpleName()), element, annotation);
+        }
+        if (!intrinsicMethod.getModifiers().contains(Modifier.NATIVE)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be native.", NodeIntrinsic.class.getSimpleName()), element, annotation);
+        }
+
+        TypeMirror nodeClassMirror = resolveAnnotationValue(TypeMirror.class, findAnnotationValue(annotation, NODE_CLASS_NAME));
+        TypeElement nodeClass = (TypeElement) env.getTypeUtils().asElement(nodeClassMirror);
+        if (nodeClass.getSimpleName().contentEquals(NodeIntrinsic.class.getSimpleName())) {
+            // default value
+            Element enclosingElement = intrinsicMethod.getEnclosingElement();
+            while (enclosingElement != null && enclosingElement.getKind() != ElementKind.CLASS) {
+                enclosingElement = enclosingElement.getEnclosingElement();
+            }
+            if (enclosingElement != null) {
+                nodeClass = (TypeElement) enclosingElement;
+            }
+        }
+
+        if (intrinsicMethod.getReturnType() instanceof TypeVariable) {
+            env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
+        }
+
+        TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
+        ExecutableElement custom = findCustomIntrinsifyMethod(nodeClass, constructorSignature);
+        if (custom != null) {
+            generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, custom, constructorSignature));
+        } else {
+            if (isNodeType(nodeClass)) {
+                if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
+                    env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
+                } else {
+                    TypeMirror ret = intrinsicMethod.getReturnType();
+                    if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
+                        checkInputType(nodeClass, ret, element, annotation);
+                    }
+
+                    ExecutableElement constructor = findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
+                    if (constructor != null) {
+                        generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructor, constructorSignature));
+                    }
+                }
+            } else {
+                env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation);
+            }
+        }
+    }
+
+    private void checkInputType(TypeElement nodeClass, TypeMirror returnType, Element element, AnnotationMirror annotation) {
+        InputType inputType = getInputType(returnType, element, annotation);
+        if (inputType != InputType.Value) {
+            boolean allowed = false;
+            InputType[] allowedTypes = nodeClass.getAnnotation(NodeInfo.class).allowedUsageTypes();
+            for (InputType allowedType : allowedTypes) {
+                if (inputType == allowedType) {
+                    allowed = true;
+                    break;
+                }
+            }
+            if (!allowed) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("@NodeIntrinsic returns input type %s, but only %s is allowed.", inputType, Arrays.toString(allowedTypes)), element,
+                                annotation);
+            }
+        }
+    }
+
+    private InputType getInputType(TypeMirror type, Element element, AnnotationMirror annotation) {
+        TypeElement current = (TypeElement) env.getTypeUtils().asElement(type);
+        while (current != null) {
+            MarkerType markerType = current.getAnnotation(MarkerType.class);
+            if (markerType != null) {
+                return markerType.value();
+            }
+
+            current = (TypeElement) env.getTypeUtils().asElement(current.getSuperclass());
+        }
+
+        env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is a subclass of StructuralInput, but isn't annotated with @MarkerType.", type), element, annotation);
+        return InputType.Value;
+    }
+
+    private boolean isNodeType(TypeElement nodeClass) {
+        return env.getTypeUtils().isSubtype(nodeClass.asType(), nodeType());
+    }
+
+    private TypeMirror[] constructorSignature(ExecutableElement method) {
+        TypeMirror[] parameters = new TypeMirror[method.getParameters().size()];
+        for (int i = 0; i < method.getParameters().size(); i++) {
+            VariableElement parameter = method.getParameters().get(i);
+            if (parameter.getAnnotation(ConstantNodeParameter.class) == null) {
+                parameters[i] = valueNodeType();
+            } else {
+                TypeMirror type = parameter.asType();
+                if (isTypeCompatible(type, classType())) {
+                    type = resolvedJavaTypeType();
+                }
+                parameters[i] = type;
+            }
+        }
+        return parameters;
+    }
+
+    private ExecutableElement findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
+        List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
+        List<String> failureReasons = new ArrayList<>();
+
+        for (ExecutableElement constructor : constructors) {
+            String failureReason = matchSignature(0, constructor, signature);
+            if (failureReason == null) {
+                // found
+                return constructor;
+            }
+
+            failureReasons.add(failureReason);
+        }
+
+        // not found
+        if (failureReasons.isEmpty()) {
+            env.getMessager().printMessage(Kind.ERROR, "Could not find matching constructor for node intrinsic.", intrinsicMethod, intrinsicAnnotation);
+        } else {
+            for (String reason : failureReasons) {
+                env.getMessager().printMessage(Kind.ERROR, reason, intrinsicMethod, intrinsicAnnotation);
+            }
+        }
+
+        return null;
+    }
+
+    private ExecutableElement findCustomIntrinsifyMethod(TypeElement nodeClass, TypeMirror[] signature) {
+        List<ExecutableElement> methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements());
+        for (ExecutableElement method : methods) {
+            if (!method.getSimpleName().toString().equals("intrinsify")) {
+                continue;
+            }
+
+            if (method.getParameters().size() < 2) {
+                continue;
+            }
+
+            VariableElement firstArg = method.getParameters().get(0);
+            if (!isTypeCompatible(firstArg.asType(), graphBuilderContextType())) {
+                continue;
+            }
+
+            VariableElement secondArg = method.getParameters().get(1);
+            if (!isTypeCompatible(secondArg.asType(), resolvedJavaMethodType())) {
+                continue;
+            }
+
+            String failureReason = matchSignature(2, method, signature);
+            if (failureReason == null) {
+                // found
+                return method;
+            }
+        }
+
+        return null;
+    }
+
+    private String matchSignature(int numSkippedParameters, ExecutableElement method, TypeMirror[] signature) {
+        int sIdx = 0;
+        int cIdx = numSkippedParameters;
+        while (cIdx < method.getParameters().size()) {
+            VariableElement parameter = method.getParameters().get(cIdx++);
+            if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
+                // skip injected parameters
+                continue;
+            }
+
+            TypeMirror paramType = parameter.asType();
+            if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
+                // last argument of constructor is varargs, match remaining intrinsic arguments
+                TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
+                while (sIdx < signature.length) {
+                    if (!isTypeCompatible(varargsType, signature[sIdx++])) {
+                        return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, varargsType, signature[sIdx - 1]);
+                    }
+                }
+            } else if (sIdx >= signature.length) {
+                // too many arguments in intrinsic method
+                return String.format("Too many arguments for %s", method);
+            } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
+                return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, paramType, signature[sIdx - 1]);
+            }
+        }
+
+        if (sIdx == signature.length) {
+            // found
+            return null;
+        }
+
+        // too many arguments in constructor
+        return String.format("Not enough arguments for %s", method);
+    }
+
+    private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
+        TypeMirror original = originalType;
+        TypeMirror substitution = substitutionType;
+        if (needsErasure(original)) {
+            original = env.getTypeUtils().erasure(original);
+        }
+        if (needsErasure(substitution)) {
+            substitution = env.getTypeUtils().erasure(substitution);
+        }
+        return env.getTypeUtils().isSameType(original, substitution);
+    }
+
+    private static boolean needsErasure(TypeMirror typeMirror) {
+        return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
+                        typeMirror.getKind() != TypeKind.NULL;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/PluginGenerator.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/PluginGenerator.java
new file mode 100644
index 0000000..70228b2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/PluginGenerator.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+public class PluginGenerator {
+
+    private final Map<Element, List<GeneratedPlugin>> plugins;
+
+    public PluginGenerator() {
+        this.plugins = new HashMap<>();
+    }
+
+    public void addPlugin(GeneratedPlugin plugin) {
+        Element topLevel = getTopLevelClass(plugin.intrinsicMethod);
+        List<GeneratedPlugin> list = plugins.get(topLevel);
+        if (list == null) {
+            list = new ArrayList<>();
+            plugins.put(topLevel, list);
+        }
+        list.add(plugin);
+    }
+
+    public void generateAll(ProcessingEnvironment env) {
+        for (Entry<Element, List<GeneratedPlugin>> entry : plugins.entrySet()) {
+            disambiguateNames(entry.getValue());
+            createPluginFactory(env, entry.getKey(), entry.getValue());
+        }
+    }
+
+    private static Element getTopLevelClass(Element element) {
+        Element prev = element;
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            prev = enclosing;
+            enclosing = enclosing.getEnclosingElement();
+        }
+        return prev;
+    }
+
+    private static void disambiguateWith(List<GeneratedPlugin> plugins, Function<GeneratedPlugin, String> genName) {
+        plugins.sort(Comparator.comparing(GeneratedPlugin::getPluginName));
+
+        GeneratedPlugin current = plugins.get(0);
+        String currentName = current.getPluginName();
+
+        for (int i = 1; i < plugins.size(); i++) {
+            GeneratedPlugin next = plugins.get(i);
+            if (currentName.equals(next.getPluginName())) {
+                if (current != null) {
+                    current.setPluginName(genName.apply(current));
+                    current = null;
+                }
+                next.setPluginName(genName.apply(next));
+            } else {
+                current = next;
+                currentName = current.getPluginName();
+            }
+        }
+    }
+
+    private static void appendSimpleTypeName(StringBuilder ret, TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                TypeElement element = (TypeElement) declared.asElement();
+                ret.append(element.getSimpleName());
+                break;
+            case TYPEVAR:
+                appendSimpleTypeName(ret, ((TypeVariable) type).getUpperBound());
+                break;
+            case WILDCARD:
+                appendSimpleTypeName(ret, ((WildcardType) type).getExtendsBound());
+                break;
+            case ARRAY:
+                appendSimpleTypeName(ret, ((ArrayType) type).getComponentType());
+                ret.append("Array");
+                break;
+            default:
+                ret.append(type);
+        }
+    }
+
+    private static void disambiguateNames(List<GeneratedPlugin> plugins) {
+        // if we have more than one method with the same name, disambiguate with the argument types
+        disambiguateWith(plugins, plugin -> {
+            StringBuilder ret = new StringBuilder(plugin.getPluginName());
+            for (VariableElement param : plugin.intrinsicMethod.getParameters()) {
+                ret.append('_');
+                appendSimpleTypeName(ret, param.asType());
+            }
+            return ret.toString();
+        });
+
+        // since we're using simple names for argument types, we could still have a collision
+        disambiguateWith(plugins, new Function<GeneratedPlugin, String>() {
+
+            private int idx = 0;
+
+            @Override
+            public String apply(GeneratedPlugin plugin) {
+                return plugin.getPluginName() + "_" + (idx++);
+            }
+        });
+    }
+
+    private static void createPluginFactory(ProcessingEnvironment env, Element topLevelClass, List<GeneratedPlugin> plugins) {
+        PackageElement pkg = (PackageElement) topLevelClass.getEnclosingElement();
+
+        String genClassName = "PluginFactory_" + topLevelClass.getSimpleName();
+
+        try {
+            JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, topLevelClass);
+            try (PrintWriter out = new PrintWriter(factory.openWriter())) {
+                out.printf("// CheckStyle: stop header check\n");
+                out.printf("// CheckStyle: stop line length check\n");
+                out.printf("// GENERATED CONTENT - DO NOT EDIT\n");
+                out.printf("// GENERATORS: %s, %s\n", VerifierAnnotationProcessor.class.getName(), PluginGenerator.class.getName());
+                out.printf("package %s;\n", pkg.getQualifiedName());
+                out.printf("\n");
+                createImports(out, plugins);
+                out.printf("\n");
+                out.printf("@ServiceProvider(NodeIntrinsicPluginFactory.class)\n");
+                out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName);
+                for (GeneratedPlugin plugin : plugins) {
+                    out.printf("\n");
+                    plugin.generate(env, out);
+                }
+                out.printf("\n");
+                createPluginFactoryMethod(out, plugins);
+                out.printf("}\n");
+            }
+        } catch (IOException e) {
+            env.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
+        }
+    }
+
+    protected static void createImports(PrintWriter out, List<GeneratedPlugin> plugins) {
+        out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
+        out.printf("import org.graalvm.compiler.serviceprovider.ServiceProvider;\n");
+        out.printf("\n");
+        out.printf("import org.graalvm.compiler.nodes.ValueNode;\n");
+        out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;\n");
+        out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;\n");
+        out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;\n");
+        out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;\n");
+        out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;\n");
+
+        HashSet<String> extra = new HashSet<>();
+        for (GeneratedPlugin plugin : plugins) {
+            plugin.extraImports(extra);
+        }
+        if (!extra.isEmpty()) {
+            out.printf("\n");
+            for (String i : extra) {
+                out.printf("import %s;\n", i);
+            }
+        }
+    }
+
+    private static void createPluginFactoryMethod(PrintWriter out, List<GeneratedPlugin> plugins) {
+        out.printf("    @Override\n");
+        out.printf("    public void registerPlugins(InvocationPlugins plugins, InjectionProvider injection) {\n");
+        for (GeneratedPlugin plugin : plugins) {
+            plugin.register(out);
+        }
+        out.printf("    }\n");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/VerifierAnnotationProcessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/VerifierAnnotationProcessor.java
new file mode 100644
index 0000000..9d96e93
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/VerifierAnnotationProcessor.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.verifier;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+
+public class VerifierAnnotationProcessor extends AbstractProcessor {
+
+    private List<AbstractVerifier> verifiers;
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (!roundEnv.processingOver()) {
+            PluginGenerator generator = new PluginGenerator();
+            for (AbstractVerifier verifier : getVerifiers()) {
+                Class<? extends Annotation> annotationClass = verifier.getAnnotationClass();
+                for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) {
+                    AnnotationMirror annotationMirror = findAnnotationMirror(processingEnv, e.getAnnotationMirrors(), annotationClass);
+                    if (annotationMirror == null) {
+                        assert false : "Annotation mirror always expected.";
+                        continue;
+                    }
+                    verifier.verify(e, annotationMirror, generator);
+                }
+            }
+
+            generator.generateAll(processingEnv);
+        }
+        return false;
+    }
+
+    public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List<? extends AnnotationMirror> mirrors, Class<?> annotationClass) {
+        TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName());
+        for (AnnotationMirror mirror : mirrors) {
+            DeclaredType annotationType = mirror.getAnnotationType();
+            TypeElement actualAnnotationType = (TypeElement) annotationType.asElement();
+            if (actualAnnotationType.equals(expectedAnnotationType)) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
+    public List<AbstractVerifier> getVerifiers() {
+        /*
+         * Initialized lazily to fail(CNE) when the processor is invoked and not when it is created.
+         */
+        if (verifiers == null) {
+            assert this.processingEnv != null : "ProcessingEnv must be initialized before calling getVerifiers.";
+            verifiers = new ArrayList<>();
+            verifiers.add(new ClassSubstitutionVerifier(this.processingEnv));
+            verifiers.add(new MethodSubstitutionVerifier(this.processingEnv));
+            verifiers.add(new NodeIntrinsicVerifier(this.processingEnv));
+            verifiers.add(new FoldVerifier(this.processingEnv));
+        }
+        return verifiers;
+    }
+
+    @Override
+    public Set<String> getSupportedAnnotationTypes() {
+        Set<String> annotationTypes = new HashSet<>();
+        for (AbstractVerifier verifier : getVerifiers()) {
+            annotationTypes.add(verifier.getAnnotationClass().getCanonicalName());
+        }
+        return annotationTypes;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraySubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraySubstitutions.java
new file mode 100644
index 0000000..2fbd74f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraySubstitutions.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import java.lang.reflect.Array;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link java.lang.reflect.Array} methods.
+ */
+@ClassSubstitution(Array.class)
+public class ArraySubstitutions {
+
+    @MethodSubstitution
+    public static int getLength(Object array) {
+        if (!array.getClass().isArray()) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        return ArrayLengthNode.arrayLength(array);
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraysSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraysSubstitutions.java
new file mode 100644
index 0000000..a47f247
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ArraysSubstitutions.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link java.util.Arrays} methods.
+ */
+@ClassSubstitution(Arrays.class)
+public class ArraysSubstitutions {
+
+    @MethodSubstitution
+    public static boolean equals(boolean[] a, boolean[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(byte[] a, byte[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(char[] a, char[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(short[] a, short[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(int[] a, int[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(long[] a, long[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(float[] a, float[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+
+    @MethodSubstitution
+    public static boolean equals(double[] a, double[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null || a.length != a2.length) {
+            return false;
+        }
+        return ArrayEqualsNode.equals(a, a2, a.length);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java
new file mode 100644
index 0000000..3fc0699
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import java.util.EnumMap;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class BoxingSnippets implements Snippets {
+
+    @Snippet
+    public static Object booleanValueOf(boolean value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object byteValueOf(byte value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object charValueOf(char value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object doubleValueOf(double value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object floatValueOf(float value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object intValueOf(int value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object longValueOf(long value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static Object shortValueOf(short value) {
+        valueOfCounter.inc();
+        return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet
+    public static boolean booleanValue(Boolean value) {
+        valueOfCounter.inc();
+        return value.booleanValue();
+    }
+
+    @Snippet
+    public static byte byteValue(Byte value) {
+        valueOfCounter.inc();
+        return value.byteValue();
+    }
+
+    @Snippet
+    public static char charValue(Character value) {
+        valueOfCounter.inc();
+        return value.charValue();
+    }
+
+    @Snippet
+    public static double doubleValue(Double value) {
+        valueOfCounter.inc();
+        return value.doubleValue();
+    }
+
+    @Snippet
+    public static float floatValue(Float value) {
+        valueOfCounter.inc();
+        return value.floatValue();
+    }
+
+    @Snippet
+    public static int intValue(Integer value) {
+        valueOfCounter.inc();
+        return value.intValue();
+    }
+
+    @Snippet
+    public static long longValue(Long value) {
+        valueOfCounter.inc();
+        return value.longValue();
+    }
+
+    @Snippet
+    public static short shortValue(Short value) {
+        valueOfCounter.inc();
+        return value.shortValue();
+    }
+
+    public static FloatingNode canonicalizeBoxing(BoxNode box, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        ValueNode value = box.getValue();
+        if (value.isConstant()) {
+            JavaConstant sourceConstant = value.asJavaConstant();
+            if (sourceConstant.getJavaKind() != box.getBoxingKind() && sourceConstant.getJavaKind().isNumericInteger()) {
+                switch (box.getBoxingKind()) {
+                    case Boolean:
+                        sourceConstant = JavaConstant.forBoolean(sourceConstant.asLong() != 0L);
+                        break;
+                    case Byte:
+                        sourceConstant = JavaConstant.forByte((byte) sourceConstant.asLong());
+                        break;
+                    case Char:
+                        sourceConstant = JavaConstant.forChar((char) sourceConstant.asLong());
+                        break;
+                    case Short:
+                        sourceConstant = JavaConstant.forShort((short) sourceConstant.asLong());
+                        break;
+                }
+            }
+            JavaConstant boxedConstant = constantReflection.boxPrimitive(sourceConstant);
+            if (boxedConstant != null && sourceConstant.getJavaKind() == box.getBoxingKind()) {
+                return ConstantNode.forConstant(boxedConstant, metaAccess, box.graph());
+            }
+        }
+        return null;
+    }
+
+    public static class Templates extends AbstractTemplates {
+
+        private final EnumMap<JavaKind, SnippetInfo> boxSnippets = new EnumMap<>(JavaKind.class);
+        private final EnumMap<JavaKind, SnippetInfo> unboxSnippets = new EnumMap<>(JavaKind.class);
+
+        public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+            super(providers, snippetReflection, target);
+            for (JavaKind kind : new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Double, JavaKind.Float, JavaKind.Int, JavaKind.Long, JavaKind.Short}) {
+                boxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "ValueOf"));
+                unboxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "Value"));
+            }
+        }
+
+        public void lower(BoxNode box, LoweringTool tool) {
+            FloatingNode canonical = canonicalizeBoxing(box, providers.getMetaAccess(), providers.getConstantReflection());
+            // if in AOT mode, we don't want to embed boxed constants.
+            if (canonical != null && !ImmutableCode.getValue()) {
+                box.graph().replaceFixedWithFloating(box, canonical);
+            } else {
+                Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind()), box.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("value", box.getValue());
+
+                SnippetTemplate template = template(args);
+                Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", box.graph(), box, template, args);
+                template.instantiate(providers.getMetaAccess(), box, DEFAULT_REPLACER, args);
+            }
+        }
+
+        public void lower(UnboxNode unbox, LoweringTool tool) {
+            Arguments args = new Arguments(unboxSnippets.get(unbox.getBoxingKind()), unbox.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("value", unbox.getValue());
+
+            SnippetTemplate template = template(args);
+            Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args);
+            template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args);
+        }
+    }
+
+    private static final SnippetCounter.Group integerCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Integer intrinsifications") : null;
+    private static final SnippetCounter valueOfCounter = new SnippetCounter(integerCounters, "valueOf", "valueOf intrinsification");
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java
new file mode 100644
index 0000000..d54e1e1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.EncodedGraph;
+import org.graalvm.compiler.nodes.GraphEncoder;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.util.Providers;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and
+ * encoding the graphs).
+ */
+public class CachingPEGraphDecoder extends PEGraphDecoder {
+
+    protected final Providers providers;
+    protected final GraphBuilderConfiguration graphBuilderConfig;
+    protected final OptimisticOptimizations optimisticOpts;
+    private final AllowAssumptions allowAssumptions;
+    private final Map<ResolvedJavaMethod, EncodedGraph> graphCache;
+
+    public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions,
+                    Architecture architecture) {
+        super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), architecture);
+
+        this.providers = providers;
+        this.graphBuilderConfig = graphBuilderConfig;
+        this.optimisticOpts = optimisticOpts;
+        this.allowAssumptions = allowAssumptions;
+        this.graphCache = new HashMap<>();
+    }
+
+    protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(IntrinsicContext initialIntrinsicContext) {
+        return new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), graphBuilderConfig,
+                        optimisticOpts, initialIntrinsicContext);
+    }
+
+    @SuppressWarnings("try")
+    private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
+        StructuredGraph graph = new StructuredGraph(method, allowAssumptions, INVALID_COMPILATION_ID);
+        try (Debug.Scope scope = Debug.scope("createGraph", graph)) {
+            IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(method, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null;
+            GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext);
+            graphBuilderPhaseInstance.apply(graph);
+
+            PhaseContext context = new PhaseContext(providers);
+            new CanonicalizerPhase().apply(graph, context);
+            /*
+             * ConvertDeoptimizeToGuardPhase reduces the number of merges in the graph, so that
+             * fewer frame states will be created. This significantly reduces the number of nodes in
+             * the initial graph.
+             */
+            new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+
+            EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture);
+            graphCache.put(method, encodedGraph);
+            return encodedGraph;
+
+        } catch (Throwable ex) {
+            throw Debug.handle(ex);
+        }
+    }
+
+    @Override
+    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
+        EncodedGraph result = graphCache.get(method);
+        if (result == null && method.hasBytecodes()) {
+            result = createGraph(method, intrinsicBytecodeProvider);
+        }
+        return result;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java
new file mode 100644
index 0000000..deb7fba
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+/**
+ * A {@link ParameterPlugin} that binds constant values to some parameters.
+ */
+public class ConstantBindingParameterPlugin implements ParameterPlugin {
+    private final Object[] constantArgs;
+    private final MetaAccessProvider metaAccess;
+    private final SnippetReflectionProvider snippetReflection;
+
+    /**
+     * Creates a plugin that will create {@link ConstantNode}s for each parameter with an index
+     * equal to that of a non-null object in {@code constantArgs} (from which the
+     * {@link ConstantNode} is created if it isn't already a {@link ConstantNode}).
+     */
+    public ConstantBindingParameterPlugin(Object[] constantArgs, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection) {
+        this.constantArgs = constantArgs;
+        this.metaAccess = metaAccess;
+        this.snippetReflection = snippetReflection;
+    }
+
+    @Override
+    public FloatingNode interceptParameter(GraphBuilderTool b, int index, StampPair stamp) {
+        Object arg = constantArgs[index];
+        if (arg != null) {
+            ConstantNode constantNode;
+            if (arg instanceof ConstantNode) {
+                constantNode = (ConstantNode) arg;
+            } else if (arg instanceof Constant) {
+                constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), (Constant) arg, metaAccess);
+            } else {
+                constantNode = ConstantNode.forConstant(snippetReflection.forBoxed(stamp.getTrustedStamp().getStackKind(), arg), metaAccess);
+            }
+            return constantNode;
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
new file mode 100644
index 0000000..682e99d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
@@ -0,0 +1,986 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
+import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.RightShiftNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.JavaReadNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.java.AbstractNewArrayNode;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.java.AccessIndexedNode;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.java.CompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.java.LoweredCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.MonitorEnterNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
+import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.MemoryBarriers;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
+ * implemented by VM-specific subclasses.
+ */
+public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final ForeignCallsProvider foreignCalls;
+    protected final TargetDescription target;
+
+    private BoxingSnippets.Templates boxingSnippets;
+
+    public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target) {
+        this.metaAccess = metaAccess;
+        this.foreignCalls = foreignCalls;
+        this.target = target;
+    }
+
+    public void initialize(Providers providers, SnippetReflectionProvider snippetReflection) {
+        boxingSnippets = new BoxingSnippets.Templates(providers, snippetReflection, target);
+        providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(providers, snippetReflection, target));
+    }
+
+    public final TargetDescription getTarget() {
+        return target;
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        assert n instanceof Lowerable;
+        StructuredGraph graph = (StructuredGraph) n.graph();
+        if (n instanceof LoadFieldNode) {
+            lowerLoadFieldNode((LoadFieldNode) n, tool);
+        } else if (n instanceof StoreFieldNode) {
+            lowerStoreFieldNode((StoreFieldNode) n, tool);
+        } else if (n instanceof LoadIndexedNode) {
+            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
+        } else if (n instanceof StoreIndexedNode) {
+            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
+        } else if (n instanceof ArrayLengthNode) {
+            lowerArrayLengthNode((ArrayLengthNode) n, tool);
+        } else if (n instanceof LoadHubNode) {
+            lowerLoadHubNode((LoadHubNode) n, tool);
+        } else if (n instanceof MonitorEnterNode) {
+            lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
+        } else if (n instanceof CompareAndSwapNode) {
+            lowerCompareAndSwapNode((CompareAndSwapNode) n);
+        } else if (n instanceof AtomicReadAndWriteNode) {
+            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
+        } else if (n instanceof UnsafeLoadNode) {
+            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
+        } else if (n instanceof UnsafeMemoryLoadNode) {
+            lowerUnsafeMemoryLoadNode((UnsafeMemoryLoadNode) n);
+        } else if (n instanceof UnsafeStoreNode) {
+            lowerUnsafeStoreNode((UnsafeStoreNode) n);
+        } else if (n instanceof UnsafeMemoryStoreNode) {
+            lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
+        } else if (n instanceof JavaReadNode) {
+            lowerJavaReadNode((JavaReadNode) n);
+        } else if (n instanceof JavaWriteNode) {
+            lowerJavaWriteNode((JavaWriteNode) n);
+        } else if (n instanceof CommitAllocationNode) {
+            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n, tool);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n, tool);
+        } else if (n instanceof VerifyHeapNode) {
+            lowerVerifyHeap((VerifyHeapNode) n);
+        } else if (n instanceof UnaryMathIntrinsicNode) {
+            lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
+        } else if (n instanceof BinaryMathIntrinsicNode) {
+            lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
+        } else {
+            throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+        }
+    }
+
+    private void lowerBinaryMath(BinaryMathIntrinsicNode math, LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+        ResolvedJavaMethod method = math.graph().method();
+        if (method != null) {
+            if (method.getAnnotation(Snippet.class) != null) {
+                /*
+                 * In the context of the snippet use the LIR lowering instead of the Node lowering.
+                 */
+                return;
+            }
+            if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
+                /*
+                 * A root compilation of the intrinsic method should emit the full assembly
+                 * implementation.
+                 */
+                return;
+            }
+
+        }
+        ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
+        if (foreignCall != null) {
+            StructuredGraph graph = math.graph();
+            ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, toForeignCall(math.getOperation()), math.getX(), math.getY()));
+            graph.addAfterFixed(tool.lastFixedNode(), call);
+            math.replaceAtUsages(call);
+        }
+    }
+
+    private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) {
+        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
+            return;
+        }
+        ResolvedJavaMethod method = math.graph().method();
+        if (method != null) {
+            if (method.getAnnotation(Snippet.class) != null) {
+                /*
+                 * In the context of the snippet use the LIR lowering instead of the Node lowering.
+                 */
+                return;
+            }
+            if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
+                /*
+                 * A root compilation of the intrinsic method should emit the full assembly
+                 * implementation.
+                 */
+                return;
+            }
+
+        }
+        ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
+        if (foreignCall != null) {
+            StructuredGraph graph = math.graph();
+            ForeignCallNode call = math.graph().add(new ForeignCallNode(foreignCalls, foreignCall, math.getValue()));
+            graph.addAfterFixed(tool.lastFixedNode(), call);
+            math.replaceAtUsages(call);
+        }
+    }
+
+    protected ForeignCallDescriptor toForeignCall(UnaryOperation operation) {
+        return operation.foreignCallDescriptor;
+    }
+
+    protected ForeignCallDescriptor toForeignCall(BinaryOperation operation) {
+        return operation.foreignCallDescriptor;
+    }
+
+    protected void lowerVerifyHeap(VerifyHeapNode n) {
+        GraphUtil.removeFixedWithUnusedInputs(n);
+    }
+
+    protected AddressNode createOffsetAddress(StructuredGraph graph, ValueNode object, long offset) {
+        ValueNode o = ConstantNode.forIntegerKind(target.wordJavaKind, offset, graph);
+        return graph.unique(new OffsetAddressNode(object, o));
+    }
+
+    protected AddressNode createFieldAddress(StructuredGraph graph, ValueNode object, ResolvedJavaField field) {
+        int offset = fieldOffset(field);
+        if (offset >= 0) {
+            return createOffsetAddress(graph, object, offset);
+        } else {
+            return null;
+        }
+    }
+
+    protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
+        assert loadField.getStackKind() != JavaKind.Illegal;
+        StructuredGraph graph = loadField.graph();
+        ResolvedJavaField field = loadField.field();
+        ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getJavaKind());
+
+        AddressNode address = createFieldAddress(graph, object, field);
+        assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
+
+        ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
+        ValueNode readValue = implicitLoadConvert(graph, field.getJavaKind(), memoryRead);
+        loadField.replaceAtUsages(readValue);
+        graph.replaceFixed(loadField, memoryRead);
+
+        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
+
+        if (loadField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            graph.addBeforeFixed(memoryRead, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            graph.addAfterFixed(memoryRead, postMembar);
+        }
+    }
+
+    protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
+        StructuredGraph graph = storeField.graph();
+        ResolvedJavaField field = storeField.field();
+        ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
+        ValueNode value = implicitStoreConvert(graph, storeField.field().getJavaKind(), storeField.value());
+        AddressNode address = createFieldAddress(graph, object, field);
+        assert address != null;
+
+        WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field())));
+        memoryWrite.setStateAfter(storeField.stateAfter());
+        graph.replaceFixedWithFixed(storeField, memoryWrite);
+        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
+
+        if (storeField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            graph.addBeforeFixed(memoryWrite, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            graph.addAfterFixed(memoryWrite, postMembar);
+        }
+    }
+
+    public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index) {
+        ValueNode wordIndex;
+        if (target.wordSize > 4) {
+            wordIndex = graph.unique(new SignExtendNode(index, target.wordSize * 8));
+        } else {
+            assert target.wordSize == 4 : "unsupported word size";
+            wordIndex = index;
+        }
+
+        int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
+        ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph)));
+
+        int base = arrayBaseOffset(elementKind);
+        ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordJavaKind, base, graph)));
+
+        return graph.unique(new OffsetAddressNode(array, offset));
+    }
+
+    protected void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
+        StructuredGraph graph = loadIndexed.graph();
+        JavaKind elementKind = loadIndexed.elementKind();
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
+
+        PiNode pi = getBoundsCheckedIndex(loadIndexed, tool, null);
+        ValueNode checkedIndex = pi;
+        if (checkedIndex == null) {
+            checkedIndex = loadIndexed.index();
+        }
+
+        AddressNode address = createArrayAddress(graph, loadIndexed.array(), elementKind, checkedIndex);
+        ReadNode memoryRead = graph.add(new ReadNode(address, NamedLocationIdentity.getArrayLocation(elementKind), loadStamp, BarrierType.NONE));
+        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
+
+        if (pi != null) {
+            memoryRead.setGuard(pi.getGuard());
+        }
+
+        loadIndexed.replaceAtUsages(readValue);
+        graph.replaceFixed(loadIndexed, memoryRead);
+    }
+
+    protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
+        StructuredGraph graph = storeIndexed.graph();
+
+        GuardingNode[] nullCheckReturn = new GuardingNode[1];
+        PiNode pi = getBoundsCheckedIndex(storeIndexed, tool, nullCheckReturn);
+        ValueNode checkedIndex;
+        GuardingNode boundsCheck;
+        if (pi == null) {
+            checkedIndex = storeIndexed.index();
+            boundsCheck = null;
+        } else {
+            checkedIndex = pi;
+            boundsCheck = pi.getGuard();
+        }
+
+        JavaKind elementKind = storeIndexed.elementKind();
+
+        ValueNode value = storeIndexed.value();
+        ValueNode array = storeIndexed.array();
+        LogicNode condition = null;
+        if (elementKind == JavaKind.Object && !StampTool.isPointerAlwaysNull(value)) {
+            /* Array store check. */
+            TypeReference arrayType = StampTool.typeReferenceOrNull(array);
+            if (arrayType != null && arrayType.isExact()) {
+                ResolvedJavaType elementType = arrayType.getType().getComponentType();
+                if (!elementType.isJavaLangObject()) {
+                    TypeReference typeReference = TypeReference.createTrusted(storeIndexed.graph().getAssumptions(), elementType);
+                    LogicNode typeTest = graph.addOrUniqueWithInputs(InstanceOfNode.create(typeReference, value));
+                    condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
+                }
+            } else {
+                /*
+                 * The guard on the read hub should be the null check of the array that was
+                 * introduced earlier.
+                 */
+                GuardingNode nullCheck = nullCheckReturn[0];
+                assert nullCheckReturn[0] != null || createNullCheck(array, storeIndexed, tool) == null;
+                ValueNode arrayClass = createReadHub(graph, graph.unique(new PiNode(array, (ValueNode) nullCheck)), tool);
+                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
+                LogicNode typeTest = graph.unique(InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), componentHub, value, false));
+                condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
+            }
+        }
+
+        AddressNode address = createArrayAddress(graph, array, elementKind, checkedIndex);
+        WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
+                        arrayStoreBarrierType(storeIndexed.elementKind())));
+        memoryWrite.setGuard(boundsCheck);
+        if (condition != null) {
+            GuardingNode storeCheckGuard = tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile);
+            memoryWrite.setStoreCheckGuard(storeCheckGuard);
+        }
+        memoryWrite.setStateAfter(storeIndexed.stateAfter());
+        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+    }
+
+    protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
+        StructuredGraph graph = arrayLengthNode.graph();
+        ValueNode array = arrayLengthNode.array();
+
+        AddressNode address = createOffsetAddress(graph, array, arrayLengthOffset());
+        ReadNode arrayLengthRead = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, StampFactory.positiveInt(), BarrierType.NONE));
+        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
+        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+    }
+
+    protected void lowerLoadHubNode(LoadHubNode loadHub, LoweringTool tool) {
+        StructuredGraph graph = loadHub.graph();
+        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
+            return;
+        }
+        if (graph.getGuardsStage().allowsFloatingGuards()) {
+            return;
+        }
+        ValueNode hub = createReadHub(graph, loadHub.getValue(), tool);
+        loadHub.replaceAtUsagesAndDelete(hub);
+    }
+
+    protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
+        ValueNode object = monitorEnter.object();
+        GuardingNode nullCheck = createNullCheck(object, monitorEnter, tool);
+        if (nullCheck != null) {
+            object = graph.unique(new PiNode(object, ((ObjectStamp) object.stamp()).improveWith(StampFactory.objectNonNull()), (ValueNode) nullCheck));
+        }
+        ValueNode hub = graph.addOrUnique(LoadHubNode.create(object, tool.getStampProvider(), tool.getMetaAccess(), tool.getConstantReflection()));
+        RawMonitorEnterNode rawMonitorEnter = graph.add(new RawMonitorEnterNode(object, hub, monitorEnter.getMonitorId()));
+        rawMonitorEnter.setStateBefore(monitorEnter.stateBefore());
+        rawMonitorEnter.setStateAfter(monitorEnter.stateAfter());
+        graph.replaceFixedWithFixed(monitorEnter, rawMonitorEnter);
+    }
+
+    protected void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
+        StructuredGraph graph = cas.graph();
+        JavaKind valueKind = cas.getValueKind();
+
+        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
+
+        AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
+        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, compareAndSwapBarrierType(cas)));
+        atomicNode.setStateAfter(cas.stateAfter());
+        graph.replaceFixedWithFixed(cas, atomicNode);
+    }
+
+    protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
+        StructuredGraph graph = n.graph();
+        JavaKind valueKind = n.getValueKind();
+
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
+
+        AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
+        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, atomicReadAndWriteBarrierType(n)));
+        memoryRead.setStateAfter(n.stateAfter());
+
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
+        n.stateAfter().replaceFirstInput(n, memoryRead);
+        n.replaceAtUsages(readValue);
+        graph.replaceFixedWithFixed(n, memoryRead);
+    }
+
+    /**
+     * @param tool utility for performing the lowering
+     */
+    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load instanceof GuardedUnsafeLoadNode) {
+            GuardedUnsafeLoadNode guardedLoad = (GuardedUnsafeLoadNode) load;
+            GuardingNode guard = guardedLoad.getGuard();
+            if (guard == null) {
+                // can float freely if the guard folded away
+                ReadNode memoryRead = createUnsafeRead(graph, load, null);
+                memoryRead.setForceFixed(false);
+                graph.replaceFixedWithFixed(load, memoryRead);
+            } else {
+                // must be guarded, but flows below the guard
+                ReadNode memoryRead = createUnsafeRead(graph, load, guard);
+                graph.replaceFixedWithFixed(load, memoryRead);
+            }
+        } else {
+            // never had a guarding condition so it must be fixed, creation of the read will force
+            // it to be fixed
+            ReadNode memoryRead = createUnsafeRead(graph, load, null);
+            graph.replaceFixedWithFixed(load, memoryRead);
+        }
+    }
+
+    protected AddressNode createUnsafeAddress(StructuredGraph graph, ValueNode object, ValueNode offset) {
+        if (object.isConstant() && object.asConstant().isDefaultForKind()) {
+            return graph.unique(new RawAddressNode(offset));
+        } else {
+            return graph.unique(new OffsetAddressNode(object, offset));
+        }
+    }
+
+    protected ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
+        boolean compressible = load.accessKind() == JavaKind.Object;
+        JavaKind readKind = load.accessKind();
+        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
+        AddressNode address = createUnsafeAddress(graph, load.object(), load.offset());
+        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, guard, BarrierType.NONE));
+        if (guard == null) {
+            // An unsafe read must not float otherwise it may float above
+            // a test guaranteeing the read is safe.
+            memoryRead.setForceFixed(true);
+        }
+        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
+        load.replaceAtUsages(readValue);
+        return memoryRead;
+    }
+
+    protected void lowerUnsafeMemoryLoadNode(UnsafeMemoryLoadNode load) {
+        StructuredGraph graph = load.graph();
+        JavaKind readKind = load.getKind();
+        assert readKind != JavaKind.Object;
+        Stamp loadStamp = loadStamp(load.stamp(), readKind, false);
+        AddressNode address = graph.unique(new RawAddressNode(load.getAddress()));
+        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
+        // An unsafe read must not float otherwise it may float above
+        // a test guaranteeing the read is safe.
+        memoryRead.setForceFixed(true);
+        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, false);
+        load.replaceAtUsages(readValue);
+        graph.replaceFixedWithFixed(load, memoryRead);
+    }
+
+    protected void lowerUnsafeStoreNode(UnsafeStoreNode store) {
+        StructuredGraph graph = store.graph();
+        boolean compressible = store.value().getStackKind() == JavaKind.Object;
+        JavaKind valueKind = store.accessKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
+        AddressNode address = createUnsafeAddress(graph, store.object(), store.offset());
+        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, unsafeStoreBarrierType(store)));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    protected void lowerUnsafeMemoryStoreNode(UnsafeMemoryStoreNode store) {
+        StructuredGraph graph = store.graph();
+        assert store.getValue().getStackKind() != JavaKind.Object;
+        JavaKind valueKind = store.getKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, store.getValue(), false);
+        AddressNode address = graph.unique(new RawAddressNode(store.getAddress()));
+        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, BarrierType.NONE));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    protected void lowerJavaReadNode(JavaReadNode read) {
+        StructuredGraph graph = read.graph();
+        JavaKind valueKind = read.getReadKind();
+        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
+
+        ReadNode memoryRead = graph.add(new ReadNode(read.getAddress(), read.getLocationIdentity(), loadStamp, read.getBarrierType()));
+        GuardingNode guard = read.getGuard();
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
+        if (guard == null) {
+            // An unsafe read must not float otherwise it may float above
+            // a test guaranteeing the read is safe.
+            memoryRead.setForceFixed(true);
+        } else {
+            memoryRead.setGuard(guard);
+        }
+        read.replaceAtUsages(readValue);
+        graph.replaceFixed(read, memoryRead);
+    }
+
+    protected void lowerJavaWriteNode(JavaWriteNode write) {
+        StructuredGraph graph = write.graph();
+        JavaKind valueKind = write.getWriteKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
+
+        WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType(), write.isInitialization()));
+        memoryWrite.setStateAfter(write.stateAfter());
+        graph.replaceFixedWithFixed(write, memoryWrite);
+        memoryWrite.setGuard(write.getGuard());
+    }
+
+    protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
+        StructuredGraph graph = commit.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
+
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            BitSet omittedValues = new BitSet();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                AbstractNewObjectNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(createNewInstanceFromVirtual(virtual));
+                } else {
+                    newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph)));
+                }
+                recursiveLowerings.add(newObject);
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode value = commit.getValues().get(valuePos);
+                    if (value instanceof VirtualObjectNode) {
+                        value = allocations[commit.getVirtualObjects().indexOf(value)];
+                    }
+                    if (value == null) {
+                        omittedValues.set(valuePos);
+                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                        // Constant.illegal is always the defaultForKind, so it is skipped
+                        JavaKind valueKind = value.getStackKind();
+                        JavaKind entryKind = virtual.entryKind(i);
+
+                        // Truffle requires some leniency in terms of what can be put where:
+                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                        (valueKind == JavaKind.Long || valueKind == JavaKind.Double || (valueKind == JavaKind.Int && virtual instanceof VirtualArrayNode));
+                        AddressNode address = null;
+                        BarrierType barrierType = null;
+                        if (virtual instanceof VirtualInstanceNode) {
+                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                            long offset = fieldOffset(field);
+                            if (offset >= 0) {
+                                address = createOffsetAddress(graph, newObject, offset);
+                                barrierType = fieldInitializationBarrier(entryKind);
+                            }
+                        } else {
+                            address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
+                            barrierType = arrayInitializationBarrier(entryKind);
+                        }
+                        if (address != null) {
+                            WriteNode write = new WriteNode(address, initLocationIdentity(), implicitStoreConvert(graph, entryKind, value), barrierType);
+                            graph.addAfterFixed(newObject, graph.add(write));
+                        }
+                    }
+                    valuePos++;
+
+                }
+            }
+            valuePos = 0;
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                ValueNode newObject = allocations[objIndex];
+                for (int i = 0; i < entryCount; i++) {
+                    if (omittedValues.get(valuePos)) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        assert value instanceof VirtualObjectNode;
+                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                            assert virtual.entryKind(i) == JavaKind.Object && allocValue.getStackKind() == JavaKind.Object;
+                            AddressNode address;
+                            BarrierType barrierType;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                address = createFieldAddress(graph, newObject, virtualInstance.field(i));
+                                barrierType = BarrierType.IMPRECISE;
+                            } else {
+                                address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
+                                barrierType = BarrierType.PRECISE;
+                            }
+                            if (address != null) {
+                                WriteNode write = new WriteNode(address, initLocationIdentity(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
+                                graph.addBeforeFixed(commit, graph.add(write));
+                            }
+                        }
+                    }
+                    valuePos++;
+                }
+            }
+
+            finishAllocatedObjects(tool, commit, allocations);
+            graph.removeFixed(commit);
+
+            for (AbstractNewObjectNode recursiveLowering : recursiveLowerings) {
+                recursiveLowering.lower(tool);
+            }
+        }
+    }
+
+    public NewInstanceNode createNewInstanceFromVirtual(VirtualObjectNode virtual) {
+        return new NewInstanceNode(virtual.type(), true);
+    }
+
+    protected NewArrayNode createNewArrayFromVirtual(VirtualObjectNode virtual, ValueNode length) {
+        return new NewArrayNode(((VirtualArrayNode) virtual).componentType(), length, true);
+    }
+
+    public void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
+        StructuredGraph graph = commit.graph();
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+            allocations[objIndex] = anchor;
+            graph.addBeforeFixed(commit, anchor);
+        }
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
+                graph.addBeforeFixed(commit, enter);
+                enter.lower(tool);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+            addObject.replaceAtUsagesAndDelete(allocations[index]);
+        }
+        insertAllocationBarrier(commit, graph);
+    }
+
+    /**
+     * Insert the required {@link MemoryBarriers#STORE_STORE} barrier for an allocation and also
+     * include the {@link MemoryBarriers#LOAD_STORE} required for final fields if any final fields
+     * are being written, as if {@link FinalFieldBarrierNode} were emitted.
+     */
+    private void insertAllocationBarrier(CommitAllocationNode commit, StructuredGraph graph) {
+        int barrier = MemoryBarriers.STORE_STORE;
+        outer: for (VirtualObjectNode vobj : commit.getVirtualObjects()) {
+            for (ResolvedJavaField field : vobj.type().getInstanceFields(true)) {
+                if (field.isFinal()) {
+                    barrier = barrier | MemoryBarriers.LOAD_STORE;
+                    break outer;
+                }
+            }
+        }
+        graph.addAfterFixed(commit, graph.add(new MembarNode(barrier, initLocationIdentity())));
+    }
+
+    /**
+     * @param field the field whose barrier type should be returned
+     */
+    protected BarrierType fieldLoadBarrierType(ResolvedJavaField field) {
+        return BarrierType.NONE;
+    }
+
+    protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
+        if (field.getJavaKind() == JavaKind.Object) {
+            return BarrierType.IMPRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    protected BarrierType arrayStoreBarrierType(JavaKind elementKind) {
+        if (elementKind == JavaKind.Object) {
+            return BarrierType.PRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    public BarrierType fieldInitializationBarrier(JavaKind entryKind) {
+        return entryKind == JavaKind.Object ? BarrierType.IMPRECISE : BarrierType.NONE;
+    }
+
+    public BarrierType arrayInitializationBarrier(JavaKind entryKind) {
+        return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE;
+    }
+
+    protected BarrierType unsafeStoreBarrierType(UnsafeStoreNode store) {
+        return storeBarrierType(store.object(), store.value());
+    }
+
+    protected BarrierType compareAndSwapBarrierType(CompareAndSwapNode cas) {
+        return storeBarrierType(cas.object(), cas.expected());
+    }
+
+    protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
+        return storeBarrierType(n.object(), n.newValue());
+    }
+
+    protected BarrierType storeBarrierType(ValueNode object, ValueNode value) {
+        if (value.getStackKind() == JavaKind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(object);
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    public abstract int fieldOffset(ResolvedJavaField field);
+
+    public FieldLocationIdentity fieldLocationIdentity(ResolvedJavaField field) {
+        return new FieldLocationIdentity(field);
+    }
+
+    public abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
+
+    public abstract int arrayLengthOffset();
+
+    public abstract int arrayBaseOffset(JavaKind elementKind);
+
+    public int arrayScalingFactor(JavaKind elementKind) {
+        return target.arch.getPlatformKind(elementKind).getSizeInBytes();
+    }
+
+    public abstract LocationIdentity initLocationIdentity();
+
+    public Stamp loadStamp(Stamp stamp, JavaKind kind) {
+        return loadStamp(stamp, kind, true);
+    }
+
+    /**
+     * @param compressible whether the stamp should be compressible
+     */
+    protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return IntegerStamp.OPS.getNarrow().foldStamp(32, 8, stamp);
+            case Char:
+            case Short:
+                return IntegerStamp.OPS.getNarrow().foldStamp(32, 16, stamp);
+        }
+        return stamp;
+    }
+
+    public final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
+        return implicitLoadConvert(graph, kind, value, true);
+    }
+
+    public ValueNode implicitLoadConvert(JavaKind kind, ValueNode value) {
+        return implicitLoadConvert(kind, value, true);
+    }
+
+    protected final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+        ValueNode ret = implicitLoadConvert(kind, value, compressible);
+        if (!ret.isAlive()) {
+            ret = graph.addOrUnique(ret);
+        }
+        return ret;
+    }
+
+    /**
+     * @param compressible whether the covert should be compressible
+     */
+    protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Byte:
+            case Short:
+                return new SignExtendNode(value, 32);
+            case Boolean:
+            case Char:
+                return new ZeroExtendNode(value, 32);
+        }
+        return value;
+    }
+
+    public final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
+        return implicitStoreConvert(graph, kind, value, true);
+    }
+
+    public ValueNode implicitStoreConvert(JavaKind kind, ValueNode value) {
+        return implicitStoreConvert(kind, value, true);
+    }
+
+    protected final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+        ValueNode ret = implicitStoreConvert(kind, value, compressible);
+        if (!ret.isAlive()) {
+            ret = graph.addOrUnique(ret);
+        }
+        return ret;
+    }
+
+    /**
+     * @param compressible whether the covert should be compressible
+     */
+    protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return new NarrowNode(value, 8);
+            case Char:
+            case Short:
+                return new NarrowNode(value, 16);
+        }
+        return value;
+    }
+
+    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool);
+
+    protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
+
+    protected PiNode getBoundsCheckedIndex(AccessIndexedNode n, LoweringTool tool, GuardingNode[] nullCheckReturn) {
+        StructuredGraph graph = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            AddressNode address = createOffsetAddress(graph, array, arrayLengthOffset());
+            ReadNode readArrayLength = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, stamp, BarrierType.NONE));
+            graph.addBeforeFixed(n, readArrayLength);
+            GuardingNode nullCheck = createNullCheck(array, readArrayLength, tool);
+            if (nullCheckReturn != null) {
+                nullCheckReturn[0] = nullCheck;
+            }
+            readArrayLength.setGuard(nullCheck);
+            arrayLength = readArrayLength;
+        } else {
+            if (array instanceof AbstractNewArrayNode) {
+                arrayLength = n.graph().addOrUnique(new PiNode(arrayLength, StampFactory.positiveInt()));
+            }
+            arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
+        }
+
+        if (arrayLength.isConstant() && n.index().isConstant()) {
+            int l = arrayLength.asJavaConstant().asInt();
+            int i = n.index().asJavaConstant().asInt();
+            if (i >= 0 && i < l) {
+                // unneeded range check
+                return null;
+            }
+        }
+
+        GuardingNode guard = tool.createGuard(n, graph.unique(new IntegerBelowNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+        IntegerStamp lengthStamp = (IntegerStamp) arrayLength.stamp();
+        IntegerStamp indexStamp = StampFactory.forInteger(32, 0, lengthStamp.upperBound() - 1);
+        return graph.unique(new PiNode(n.index(), indexStamp, guard.asNode()));
+    }
+
+    protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
+        if (StampTool.isPointerNonNull(object)) {
+            return null;
+        }
+        return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true);
+    }
+
+    @Override
+    public ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address) {
+        StructuredGraph graph = address.graph();
+        ValueNode offset = ((OffsetAddressNode) address).getOffset();
+
+        int base = arrayBaseOffset(elementKind);
+        ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), base, graph)));
+
+        int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
+        ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph)));
+        return IntegerConvertNode.convert(ret, StampFactory.forKind(JavaKind.Int), graph);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java
new file mode 100644
index 0000000..37ae9c1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.java.FrameStateBuilder;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * A utility for manually creating a graph. This will be expanded as necessary to support all
+ * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase
+ * bytecode parsing} based graph creation).
+ */
+public class GraphKit implements GraphBuilderTool {
+
+    protected final Providers providers;
+    protected final StructuredGraph graph;
+    protected final WordTypes wordTypes;
+    protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins;
+    protected FixedWithNextNode lastFixedNode;
+
+    private final List<Structure> structures;
+
+    abstract static class Structure {
+    }
+
+    public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) {
+        this.providers = providers;
+        this.graph = graph;
+        this.wordTypes = wordTypes;
+        this.graphBuilderPlugins = graphBuilderPlugins;
+        this.lastFixedNode = graph.start();
+
+        structures = new ArrayList<>();
+        /*
+         * Add a dummy element, so that the access of the last element never leads to an exception.
+         */
+        structures.add(new Structure() {
+        });
+    }
+
+    @Override
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return providers.getConstantReflection();
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return providers.getConstantFieldProvider();
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public StampProvider getStampProvider() {
+        return providers.getStampProvider();
+    }
+
+    @Override
+    public boolean parsingIntrinsic() {
+        return true;
+    }
+
+    /**
+     * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}.
+     *
+     * @return a node similar to {@code node} if one exists, otherwise {@code node}
+     */
+    public <T extends FloatingNode & ValueNumberable> T unique(T node) {
+        return graph.unique(changeToWord(node));
+    }
+
+    public <T extends ValueNode> T add(T node) {
+        return graph.add(changeToWord(node));
+    }
+
+    public <T extends ValueNode> T changeToWord(T node) {
+        if (wordTypes != null && wordTypes.isWord(node)) {
+            node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node)));
+        }
+        return node;
+    }
+
+    @Override
+    public <T extends ValueNode> T append(T node) {
+        T result = graph.addOrUnique(changeToWord(node));
+        if (result instanceof FixedNode) {
+            updateLastFixed((FixedNode) result);
+        }
+        return result;
+    }
+
+    @Override
+    public <T extends ValueNode> T recursiveAppend(T node) {
+        T result = graph.addOrUniqueWithInputs(node);
+        if (result instanceof FixedNode) {
+            updateLastFixed((FixedNode) result);
+        }
+        return result;
+    }
+
+    private void updateLastFixed(FixedNode result) {
+        assert lastFixedNode != null;
+        assert result.predecessor() == null;
+        graph.addAfterFixed(lastFixedNode, result);
+        if (result instanceof FixedWithNextNode) {
+            lastFixedNode = (FixedWithNextNode) result;
+        } else {
+            lastFixedNode = null;
+        }
+    }
+
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
+        return createInvoke(declaringClass, name, InvokeKind.Static, null, BytecodeFrame.UNKNOWN_BCI, args);
+    }
+
+    /**
+     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
+     * arguments. The method is looked up via reflection based on the declaring class and name.
+     *
+     * @param declaringClass the class declaring the invoked method
+     * @param name the name of the invoked method
+     * @param args the arguments to the invocation
+     */
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        boolean isStatic = invokeKind == InvokeKind.Static;
+        ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic);
+        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+    }
+
+    public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, boolean isStatic) {
+        ResolvedJavaMethod method = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) {
+                assert method == null : "found more than one method in " + declaringClass + " named " + name;
+                method = providers.getMetaAccess().lookupJavaMethod(m);
+            }
+        }
+        assert method != null : "did not find method in " + declaringClass + " named " + name;
+        return method;
+    }
+
+    public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        try {
+            Method m = declaringClass.getDeclaredMethod(name, parameterTypes);
+            return providers.getMetaAccess().lookupJavaMethod(m);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
+     * arguments.
+     */
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        assert method.isStatic() == (invokeKind == InvokeKind.Static);
+        Signature signature = method.getSignature();
+        JavaType returnType = signature.getReturnType(null);
+        assert checkArgs(method, args);
+        StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false);
+        if (returnStamp == null) {
+            returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+        }
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci));
+        InvokeNode invoke = append(new InvokeNode(callTarget, bci));
+
+        if (frameStateBuilder != null) {
+            if (invoke.getStackKind() != JavaKind.Void) {
+                frameStateBuilder.push(returnType.getJavaKind(), invoke);
+            }
+            invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
+            if (invoke.getStackKind() != JavaKind.Void) {
+                frameStateBuilder.pop(returnType.getJavaKind());
+            }
+        }
+        return invoke;
+    }
+
+    protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, @SuppressWarnings("unused") int bci) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, null);
+    }
+
+    /**
+     * Determines if a given set of arguments is compatible with the signature of a given method.
+     *
+     * @return true if {@code args} are compatible with the signature if {@code method}
+     * @throws AssertionError if {@code args} are not compatible with the signature if
+     *             {@code method}
+     */
+    public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
+        Signature signature = method.getSignature();
+        boolean isStatic = method.isStatic();
+        if (signature.getParameterCount(!isStatic) != args.length) {
+            throw new AssertionError(graph + ": wrong number of arguments to " + method);
+        }
+        int argIndex = 0;
+        if (!isStatic) {
+            ResolvedJavaType expectedType = method.getDeclaringClass();
+            JavaKind expected = wordTypes == null ? expectedType.getJavaKind() : wordTypes.asKind(expectedType);
+            JavaKind actual = args[argIndex++].stamp().getStackKind();
+            assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]";
+        }
+        for (int i = 0; i != signature.getParameterCount(false); i++) {
+            JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass());
+            JavaKind expected = wordTypes == null ? expectedType.getJavaKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind();
+            JavaKind actual = args[argIndex++].stamp().getStackKind();
+            if (expected != actual) {
+                throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Recursively {@linkplain #inline inlines} all invocations currently in the graph.
+     */
+    public void inlineInvokes() {
+        while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
+            for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
+                inline(invoke);
+            }
+        }
+
+        // Clean up all code that is now dead after inlining.
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+
+    /**
+     * Inlines a given invocation to a method. The graph of the inlined method is processed in the
+     * same manner as for snippets and method substitutions.
+     */
+    public void inline(InvokeNode invoke) {
+        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
+
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Plugins plugins = new Plugins(graphBuilderPlugins);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+
+        StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO, NO_PROFILING_INFO, INVALID_COMPILATION_ID);
+        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
+        GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
+                        OptimisticOptimizations.NONE,
+                        initialReplacementContext);
+        instance.apply(calleeGraph);
+
+        // Remove all frame states from inlinee
+        calleeGraph.clearAllStateAfter();
+        new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph);
+
+        InliningUtil.inline(invoke, calleeGraph, false, null, method);
+    }
+
+    protected void pushStructure(Structure structure) {
+        structures.add(structure);
+    }
+
+    protected <T extends Structure> T getTopStructure(Class<T> expectedClass) {
+        return expectedClass.cast(structures.get(structures.size() - 1));
+    }
+
+    protected void popStructure() {
+        structures.remove(structures.size() - 1);
+    }
+
+    protected enum IfState {
+        CONDITION,
+        THEN_PART,
+        ELSE_PART,
+        FINISHED
+    }
+
+    static class IfStructure extends Structure {
+        protected IfState state;
+        protected FixedNode thenPart;
+        protected FixedNode elsePart;
+    }
+
+    /**
+     * Starts an if-block. This call can be followed by a call to {@link #thenPart} to start
+     * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start
+     * emititng the code when the condition does not hold. It must be followed by a call to
+     * {@link #endIf} to close the if-block.
+     *
+     * @param condition The condition for the if-block
+     * @param trueProbability The estimated probability the the condition is true
+     */
+    public void startIf(LogicNode condition, double trueProbability) {
+        AbstractBeginNode thenSuccessor = graph.add(new BeginNode());
+        AbstractBeginNode elseSuccessor = graph.add(new BeginNode());
+        append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability));
+        lastFixedNode = null;
+
+        IfStructure s = new IfStructure();
+        s.state = IfState.CONDITION;
+        s.thenPart = thenSuccessor;
+        s.elsePart = elseSuccessor;
+        pushStructure(s);
+    }
+
+    private IfStructure saveLastNode() {
+        IfStructure s = getTopStructure(IfStructure.class);
+        switch (s.state) {
+            case CONDITION:
+                assert lastFixedNode == null;
+                break;
+            case THEN_PART:
+                s.thenPart = lastFixedNode;
+                break;
+            case ELSE_PART:
+                s.elsePart = lastFixedNode;
+                break;
+            case FINISHED:
+                assert false;
+                break;
+        }
+        lastFixedNode = null;
+        return s;
+    }
+
+    public void thenPart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.thenPart;
+        s.state = IfState.THEN_PART;
+    }
+
+    public void elsePart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.elsePart;
+        s.state = IfState.ELSE_PART;
+    }
+
+    public void endIf() {
+        IfStructure s = saveLastNode();
+
+        FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
+        FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
+
+        if (thenPart != null && elsePart != null) {
+            /* Both parts are alive, we need a real merge. */
+            EndNode thenEnd = graph.add(new EndNode());
+            graph.addAfterFixed(thenPart, thenEnd);
+            EndNode elseEnd = graph.add(new EndNode());
+            graph.addAfterFixed(elsePart, elseEnd);
+
+            AbstractMergeNode merge = graph.add(new MergeNode());
+            merge.addForwardEnd(thenEnd);
+            merge.addForwardEnd(elseEnd);
+
+            lastFixedNode = merge;
+
+        } else if (thenPart != null) {
+            /* elsePart ended with a control sink, so we can continue with thenPart. */
+            lastFixedNode = thenPart;
+
+        } else if (elsePart != null) {
+            /* thenPart ended with a control sink, so we can continue with elsePart. */
+            lastFixedNode = elsePart;
+
+        } else {
+            /* Both parts ended with a control sink, so no nodes can be added after the if. */
+            assert lastFixedNode == null;
+        }
+        s.state = IfState.FINISHED;
+        popStructure();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java
new file mode 100644
index 0000000..533edbf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize;
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsingMaxDepth;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo;
+
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public final class InlineDuringParsingPlugin implements InlineInvokePlugin {
+
+    @Override
+    public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        // @formatter:off
+        if (method.hasBytecodes() &&
+            method.getDeclaringClass().isLinked() &&
+            method.canBeInlined()) {
+
+            // Test force inlining first
+            if (method.shouldBeInlined()) {
+                return createStandardInlineInfo(method);
+            }
+
+            if (!method.isSynchronized() &&
+                checkSize(method, args) &&
+                b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+                return createStandardInlineInfo(method);
+            }
+        }
+        // @formatter:on
+        return null;
+    }
+
+    private static boolean checkSize(ResolvedJavaMethod method, ValueNode[] args) {
+        int bonus = 1;
+        for (ValueNode v : args) {
+            if (v.isConstant()) {
+                bonus++;
+            }
+        }
+        return method.getCode().length <= TrivialInliningSize.getValue() * bonus;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineGraalDirectivesPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineGraalDirectivesPlugin.java
new file mode 100644
index 0000000..f4b4af1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineGraalDirectivesPlugin.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo;
+
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public final class InlineGraalDirectivesPlugin implements InlineInvokePlugin {
+
+    private static final Method ROOTNAME;
+
+    static {
+        try {
+            ROOTNAME = GraalDirectives.class.getDeclaredMethod("rootName");
+        } catch (Exception e) {
+            throw new GraalError("unable to find GraalDirectives.rootName()", e);
+        }
+    }
+
+    @Override
+    public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (method.equals(b.getMetaAccess().lookupJavaMethod(ROOTNAME))) {
+            return createStandardInlineInfo(method);
+        }
+        return null;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java
new file mode 100644
index 0000000..5d7d31c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode;
+
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConditionAnchorNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.UsageReplacer;
+
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity
+ * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A
+ * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and
+ * replacing a floating node with control flow is not trivial.
+ * <p>
+ * The mechanism implemented in this class ensures that the graph for an instanceof snippet is
+ * instantiated once per {@link InstanceOfNode} being lowered. The result produced is then re-used
+ * by all usages of the node. Additionally, if there is a single usage that is an {@link IfNode},
+ * the control flow in the snippet is connected directly to the true and false successors of the
+ * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested
+ * by the {@link IfNode}.
+ */
+public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates {
+
+    public InstanceOfSnippetsTemplates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+        super(providers, snippetReflection, target);
+    }
+
+    /**
+     * Gets the arguments used to retrieve and instantiate an instanceof snippet template.
+     */
+    protected abstract Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool);
+
+    public void lower(FloatingNode instanceOf, LoweringTool tool) {
+        assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
+        List<Node> usages = instanceOf.usages().snapshot();
+
+        Instantiation instantiation = new Instantiation();
+        for (Node usage : usages) {
+            final StructuredGraph graph = (StructuredGraph) usage.graph();
+
+            InstanceOfUsageReplacer replacer = createReplacer(instanceOf, instantiation, usage, graph);
+
+            if (instantiation.isInitialized()) {
+                // No need to re-instantiate the snippet - just re-use its result
+                replacer.replaceUsingInstantiation();
+            } else {
+                Arguments args = makeArguments(replacer, tool);
+                template(args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args);
+            }
+        }
+
+        assert instanceOf.hasNoUsages();
+        if (!instanceOf.isDeleted()) {
+            GraphUtil.killWithUnusedFloatingInputs(instanceOf);
+        }
+    }
+
+    /**
+     * Gets the specific replacer object used to replace the usage of an instanceof node with the
+     * result of an instantiated instanceof snippet.
+     */
+    protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
+        InstanceOfUsageReplacer replacer;
+        if (!canMaterialize(usage)) {
+            ValueNode trueValue = ConstantNode.forInt(1, graph);
+            ValueNode falseValue = ConstantNode.forInt(0, graph);
+            if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) {
+                /*
+                 * This code doesn't really care what values are used so adopt the values from the
+                 * previous instantiation.
+                 */
+                trueValue = instantiation.trueValue;
+                falseValue = instantiation.falseValue;
+            }
+            replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage);
+        } else {
+            assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
+            ConditionalNode c = (ConditionalNode) usage;
+            replacer = new MaterializationUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c);
+        }
+        return replacer;
+    }
+
+    /**
+     * Determines if an {@code instanceof} usage can be materialized.
+     */
+    protected boolean canMaterialize(Node usage) {
+        if (usage instanceof ConditionalNode) {
+            ConditionalNode cn = (ConditionalNode) usage;
+            return cn.trueValue().isConstant() && cn.falseValue().isConstant();
+        }
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof ConditionAnchorNode) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * The result of instantiating an instanceof snippet. This enables a snippet instantiation to be
+     * re-used which reduces compile time and produces better code.
+     */
+    public static final class Instantiation {
+
+        private ValueNode result;
+        private LogicNode condition;
+        private ValueNode trueValue;
+        private ValueNode falseValue;
+
+        /**
+         * Determines if the instantiation has occurred.
+         */
+        boolean isInitialized() {
+            return result != null;
+        }
+
+        void initialize(ValueNode r, ValueNode t, ValueNode f) {
+            assert !isInitialized();
+            this.result = r;
+            this.trueValue = t;
+            this.falseValue = f;
+        }
+
+        /**
+         * Gets the result of this instantiation as a condition.
+         *
+         * @param testValue the returned condition is true if the result is equal to this value
+         */
+        LogicNode asCondition(ValueNode testValue) {
+            assert isInitialized();
+            if (result.isConstant()) {
+                assert testValue.isConstant();
+                return LogicConstantNode.forBoolean(result.asConstant().equals(testValue.asConstant()), result.graph());
+            }
+            if (condition == null || (!(condition instanceof CompareNode)) || ((CompareNode) condition).getY() != testValue) {
+                // Re-use previously generated condition if the trueValue for the test is the same
+                condition = createCompareNode(result.graph(), Condition.EQ, result, testValue, null);
+            }
+            return condition;
+        }
+
+        /**
+         * Gets the result of the instantiation as a materialized value.
+         *
+         * @param t the true value for the materialization
+         * @param f the false value for the materialization
+         */
+        ValueNode asMaterialization(StructuredGraph graph, ValueNode t, ValueNode f) {
+            assert isInitialized();
+            if (t == this.trueValue && f == this.falseValue) {
+                // Can simply use the phi result if the same materialized values are expected.
+                return result;
+            } else {
+                return graph.unique(new ConditionalNode(asCondition(trueValue), t, f));
+            }
+        }
+    }
+
+    /**
+     * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
+     */
+    public abstract static class InstanceOfUsageReplacer implements UsageReplacer {
+
+        public final Instantiation instantiation;
+        public final FloatingNode instanceOf;
+        public final ValueNode trueValue;
+        public final ValueNode falseValue;
+
+        public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+            assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
+            this.instantiation = instantiation;
+            this.instanceOf = instanceOf;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+        }
+
+        /**
+         * Does the replacement based on a previously snippet instantiation.
+         */
+        public abstract void replaceUsingInstantiation();
+    }
+
+    /**
+     * Replaces the usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode} that does
+     * not materialize the result of the type test.
+     */
+    public static class NonMaterializationUsageReplacer extends InstanceOfUsageReplacer {
+
+        private final Node usage;
+
+        public NonMaterializationUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, Node usage) {
+            super(instantiation, instanceOf, trueValue, falseValue);
+            this.usage = usage;
+        }
+
+        @Override
+        public void replaceUsingInstantiation() {
+            usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue));
+        }
+
+        @Override
+        public void replace(ValueNode oldNode, ValueNode newNode) {
+            assert newNode instanceof PhiNode;
+            assert oldNode == instanceOf;
+            newNode.inferStamp();
+            instantiation.initialize(newNode, trueValue, falseValue);
+            usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue));
+        }
+    }
+
+    /**
+     * Replaces the usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode} that does
+     * materializes the result of the type test.
+     */
+    public static class MaterializationUsageReplacer extends InstanceOfUsageReplacer {
+
+        public final ConditionalNode usage;
+
+        public MaterializationUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) {
+            super(instantiation, instanceOf, trueValue, falseValue);
+            this.usage = usage;
+        }
+
+        @Override
+        public void replaceUsingInstantiation() {
+            ValueNode newValue = instantiation.asMaterialization(usage.graph(), trueValue, falseValue);
+            usage.replaceAtUsages(newValue);
+            assert usage.hasNoUsages();
+            GraphUtil.killWithUnusedFloatingInputs(usage);
+        }
+
+        @Override
+        public void replace(ValueNode oldNode, ValueNode newNode) {
+            assert newNode instanceof PhiNode;
+            assert oldNode == instanceOf;
+            newNode.inferStamp();
+            instantiation.initialize(newNode, trueValue, falseValue);
+            usage.replaceAtUsages(newNode);
+            assert usage.hasNoUsages();
+            GraphUtil.killWithUnusedFloatingInputs(usage);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java
new file mode 100644
index 0000000..aa3eef0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+
+@ClassSubstitution(Integer.class)
+public class IntegerSubstitutions {
+
+    @MethodSubstitution
+    public static int numberOfLeadingZeros(int i) {
+        if (i == 0) {
+            return 32;
+        }
+        return 31 - BitScanReverseNode.unsafeScan(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(int i) {
+        if (i == 0) {
+            return 32;
+        }
+        return BitScanForwardNode.unsafeScan(i);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java
new file mode 100644
index 0000000..6291dbe
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
+ * {@link InvocationPlugin} for the method.
+ */
+public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final ConstantReflectionProvider constantReflection;
+    protected final ConstantFieldProvider constantFieldProvider;
+    protected final StampProvider stampProvider;
+    protected final StructuredGraph graph;
+    protected final Bytecode code;
+    protected final ResolvedJavaMethod method;
+    protected final int invokeBci;
+    protected FixedWithNextNode lastInstr;
+    protected ValueNode[] arguments;
+    protected ValueNode returnValue;
+
+    public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
+                    Bytecode code, int invokeBci) {
+        this(metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci, AllowAssumptions.YES);
+    }
+
+    protected IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
+                    Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.stampProvider = stampProvider;
+        this.code = code;
+        this.method = code.getMethod();
+        this.graph = new StructuredGraph(method, allowAssumptions, INVALID_COMPILATION_ID);
+        this.invokeBci = invokeBci;
+        this.lastInstr = graph.start();
+
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // add the receiver
+            Stamp receiverStamp = StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(method.getDeclaringClass()));
+            ValueNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, StampPair.createSingle(receiverStamp)));
+            arguments[index] = receiver;
+            javaIndex = 1;
+            index = 1;
+        }
+        ResolvedJavaType accessingClass = method.getDeclaringClass();
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
+            JavaKind kind = type.getJavaKind();
+            Stamp stamp;
+            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.object(TypeReference.createWithoutAssumptions((ResolvedJavaType) type));
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            ValueNode param = graph.addWithoutUnique(new ParameterNode(index, StampPair.createSingle(stamp)));
+            arguments[index] = param;
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    private <T extends ValueNode> void updateLastInstruction(T v) {
+        if (v instanceof FixedNode) {
+            FixedNode fixedNode = (FixedNode) v;
+            lastInstr.setNext(fixedNode);
+            if (fixedNode instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                lastInstr = fixedWithNextNode;
+            } else {
+                lastInstr = null;
+            }
+        }
+    }
+
+    @Override
+    public <T extends ValueNode> T append(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUnique(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    @Override
+    public <T extends ValueNode> T recursiveAppend(T v) {
+        if (v.graph() != null) {
+            return v;
+        }
+        T added = graph.addOrUniqueWithInputs(v);
+        if (added == v) {
+            updateLastInstruction(v);
+        }
+        return added;
+    }
+
+    @Override
+    public void push(JavaKind kind, ValueNode value) {
+        assert kind != JavaKind.Void;
+        assert returnValue == null;
+        returnValue = value;
+    }
+
+    @Override
+    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public StampProvider getStampProvider() {
+        return stampProvider;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    @Override
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+
+    @Override
+    public void setStateAfter(StateSplit sideEffect) {
+        assert sideEffect.hasSideEffect();
+        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+        sideEffect.setStateAfter(stateAfter);
+    }
+
+    @Override
+    public GraphBuilderContext getParent() {
+        return null;
+    }
+
+    @Override
+    public Bytecode getCode() {
+        return code;
+    }
+
+    @Override
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    @Override
+    public int bci() {
+        return invokeBci;
+    }
+
+    @Override
+    public InvokeKind getInvokeKind() {
+        return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
+    }
+
+    @Override
+    public JavaType getInvokeReturnType() {
+        return method.getSignature().getReturnType(method.getDeclaringClass());
+    }
+
+    @Override
+    public int getDepth() {
+        return 0;
+    }
+
+    @Override
+    public boolean parsingIntrinsic() {
+        return true;
+    }
+
+    @Override
+    public IntrinsicContext getIntrinsic() {
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public BailoutException bailout(String string) {
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public ValueNode get(boolean performNullCheck) {
+        return arguments[0];
+    }
+
+    public StructuredGraph buildGraph(InvocationPlugin plugin) {
+        Receiver receiver = method.isStatic() ? null : this;
+        if (plugin.execute(this, method, receiver, arguments)) {
+            assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
+            append(new ReturnNode(returnValue));
+            return graph;
+        }
+        return null;
+    }
+
+    @Override
+    public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s:intrinsic", method.format("%H.%n(%p)"));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JavacBug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JavacBug.java
new file mode 100644
index 0000000..9d9df65
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JavacBug.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+/**
+ * Used to indicate that an otherwise strange looking code pattern is required to work around a bug
+ * in javac.
+ */
+public @interface JavacBug {
+
+    /**
+     * A description of the bug. Only really useful if there is no existing entry for the bug in the
+     * <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>.
+     */
+    String value() default "";
+
+    /**
+     * An identifier in the <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>.
+     */
+    int id() default 0;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Log.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Log.java
new file mode 100644
index 0000000..ad3e223
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Log.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import java.io.PrintStream;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+//JaCoCo Exclude
+
+/**
+ * Provides {@link PrintStream}-like logging facility.
+ */
+public final class Log {
+
+    public static final ForeignCallDescriptor LOG_PRIMITIVE = new ForeignCallDescriptor("logPrimitive", void.class, int.class, long.class, boolean.class);
+    public static final ForeignCallDescriptor LOG_OBJECT = new ForeignCallDescriptor("logObject", void.class, Object.class, boolean.class, boolean.class);
+    public static final ForeignCallDescriptor LOG_PRINTF = new ForeignCallDescriptor("logPrintf", void.class, Object.class, long.class, long.class, long.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logObject, Object object, boolean asString, boolean newline);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logPrimitive, int typeChar, long value, boolean newline);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, String format, long v1, long v2, long v3);
+
+    public static void print(boolean value) {
+        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, false);
+    }
+
+    public static void print(byte value) {
+        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, false);
+    }
+
+    public static void print(char value) {
+        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, false);
+    }
+
+    public static void print(short value) {
+        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, false);
+    }
+
+    public static void print(int value) {
+        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, false);
+    }
+
+    public static void print(long value) {
+        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, false);
+    }
+
+    /**
+     * Prints a formatted string to the log stream.
+     *
+     * @param format a C style printf format value that can contain at most one conversion specifier
+     *            (i.e., a sequence of characters starting with '%').
+     * @param value the value associated with the conversion specifier
+     */
+    public static void printf(String format, long value) {
+        printf(LOG_PRINTF, format, value, 0L, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2) {
+        printf(LOG_PRINTF, format, v1, v2, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2, long v3) {
+        printf(LOG_PRINTF, format, v1, v2, v3);
+    }
+
+    public static void print(float value) {
+        if (Float.isNaN(value)) {
+            print("NaN");
+        } else if (value == Float.POSITIVE_INFINITY) {
+            print("Infinity");
+        } else if (value == Float.NEGATIVE_INFINITY) {
+            print("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), false);
+        }
+    }
+
+    public static void print(double value) {
+        if (Double.isNaN(value)) {
+            print("NaN");
+        } else if (value == Double.POSITIVE_INFINITY) {
+            print("Infinity");
+        } else if (value == Double.NEGATIVE_INFINITY) {
+            print("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false);
+        }
+    }
+
+    public static void print(String value) {
+        log(LOG_OBJECT, value, true, false);
+    }
+
+    public static void printObject(Object o) {
+        log(LOG_OBJECT, o, false, false);
+    }
+
+    public static void println(boolean value) {
+        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, true);
+    }
+
+    public static void println(byte value) {
+        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, true);
+    }
+
+    public static void println(char value) {
+        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, true);
+    }
+
+    public static void println(short value) {
+        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, true);
+    }
+
+    public static void println(int value) {
+        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, true);
+    }
+
+    public static void println(long value) {
+        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, true);
+    }
+
+    public static void println(float value) {
+        if (Float.isNaN(value)) {
+            println("NaN");
+        } else if (value == Float.POSITIVE_INFINITY) {
+            println("Infinity");
+        } else if (value == Float.NEGATIVE_INFINITY) {
+            println("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), true);
+        }
+    }
+
+    public static void println(double value) {
+        if (Double.isNaN(value)) {
+            println("NaN");
+        } else if (value == Double.POSITIVE_INFINITY) {
+            println("Infinity");
+        } else if (value == Double.NEGATIVE_INFINITY) {
+            println("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true);
+        }
+    }
+
+    public static void println(String value) {
+        log(LOG_OBJECT, value, true, true);
+    }
+
+    public static void printlnObject(Object o) {
+        log(LOG_OBJECT, o, false, true);
+    }
+
+    public static void println() {
+        println("");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java
new file mode 100644
index 0000000..20adf97
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+
+// JaCoCo Exclude
+
+@ClassSubstitution(Long.class)
+public class LongSubstitutions {
+
+    @MethodSubstitution
+    public static int numberOfLeadingZeros(long i) {
+        if (i == 0) {
+            return 64;
+        }
+        return 63 - BitScanReverseNode.unsafeScan(i);
+    }
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(long i) {
+        if (i == 0) {
+            return 64;
+        }
+        return BitScanForwardNode.unsafeScan(i);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java
new file mode 100644
index 0000000..0441681
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.replacements.nodes.MethodHandleNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MethodHandleAccessProvider;
+import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodHandlePlugin implements NodePlugin {
+    private final MethodHandleAccessProvider methodHandleAccess;
+    private final boolean safeForDeoptimization;
+
+    public MethodHandlePlugin(MethodHandleAccessProvider methodHandleAccess, boolean safeForDeoptimization) {
+        this.methodHandleAccess = methodHandleAccess;
+        this.safeForDeoptimization = safeForDeoptimization;
+    }
+
+    @Override
+    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method);
+        if (intrinsicMethod != null) {
+            InvokeKind invokeKind = b.getInvokeKind();
+            if (invokeKind != InvokeKind.Static) {
+                args[0] = b.nullCheckedValue(args[0]);
+            }
+            StampPair invokeReturnStamp = b.getInvokeReturnStamp(b.getAssumptions());
+            InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnStamp,
+                            args);
+            if (invoke == null) {
+                MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnStamp, args);
+                if (invokeReturnStamp.getTrustedStamp().getStackKind() == JavaKind.Void) {
+                    b.add(methodHandleNode);
+                } else {
+                    b.addPush(invokeReturnStamp.getTrustedStamp().getStackKind(), methodHandleNode);
+                }
+            } else {
+                CallTargetNode callTarget = invoke.callTarget();
+                NodeInputList<ValueNode> argumentsList = callTarget.arguments();
+                for (int i = 0; i < argumentsList.size(); ++i) {
+                    argumentsList.initialize(i, b.recursiveAppend(argumentsList.get(i)));
+                }
+
+                boolean inlineEverything = false;
+                if (safeForDeoptimization) {
+                    // If a MemberName suffix argument is dropped, the replaced call cannot
+                    // deoptimized since the necessary frame state cannot be reconstructed.
+                    // As such, it needs to recursively inline everything.
+                    inlineEverything = args.length != argumentsList.size();
+                }
+                b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), argumentsList.toArray(new ValueNode[argumentsList.size()]), inlineEverything);
+            }
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java
new file mode 100644
index 0000000..736adcb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
+import org.graalvm.compiler.word.WordTypes;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class NodeIntrinsificationProvider implements InjectionProvider {
+
+    private final MetaAccessProvider metaAccess;
+    private final SnippetReflectionProvider snippetReflection;
+    private final ForeignCallsProvider foreignCalls;
+    private final WordTypes wordTypes;
+
+    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) {
+        this.metaAccess = metaAccess;
+        this.snippetReflection = snippetReflection;
+        this.foreignCalls = foreignCalls;
+        this.wordTypes = wordTypes;
+    }
+
+    @Override
+    public Stamp getReturnStamp(Class<?> type, boolean nonNull) {
+        JavaKind kind = JavaKind.fromJavaClass(type);
+        if (kind == JavaKind.Object) {
+            ResolvedJavaType returnType = metaAccess.lookupJavaType(type);
+            if (wordTypes.isWord(returnType)) {
+                return wordTypes.getWordStamp(returnType);
+            } else {
+                return StampFactory.object(TypeReference.createWithoutAssumptions(returnType), nonNull);
+            }
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public <T> T getInjectedArgument(Class<T> type) {
+        T injected = snippetReflection.getInjectedNodeIntrinsicParameter(type);
+        if (injected != null) {
+            return injected;
+        } else if (type.equals(ForeignCallsProvider.class)) {
+            return type.cast(foreignCalls);
+        } else if (type.equals(SnippetReflectionProvider.class)) {
+            return type.cast(snippetReflection);
+        } else {
+            throw new GraalError("Cannot handle injected argument of type %s.", type.getName());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java
new file mode 100644
index 0000000..7c4b44b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java
@@ -0,0 +1,901 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.debug.GraalError.unimplemented;
+import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.cfg.CFGVerifier;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EncodedGraph;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.SimplifyingGraphDecoder;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
+import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
+ * canonicalization/simplification of nodes during decoding.
+ *
+ * Inlining and loop explosion are configured via the plugin mechanism also used by the
+ * {@link GraphBuilderPhase}. However, not all callback methods defined in
+ * {@link GraphBuilderContext} are available since decoding is more limited than graph building.
+ *
+ * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to
+ * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and
+ * {@link IntegerSwitchNode switches} with constant conditions are simplified.
+ */
+public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
+
+    public static class Options {
+        @Option(help = "Maximum inlining depth during partial evaluation before reporting an infinite recursion")//
+        public static final OptionValue<Integer> InliningDepthError = new OptionValue<>(1000);
+
+        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)//
+        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
+
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) //
+        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+    }
+
+    protected class PEMethodScope extends MethodScope {
+        /** The state of the caller method. Only non-null during method inlining. */
+        protected final PEMethodScope caller;
+        protected final ResolvedJavaMethod method;
+        protected final InvokeData invokeData;
+        protected final int inliningDepth;
+
+        protected final LoopExplosionPlugin loopExplosionPlugin;
+        protected final InvocationPlugins invocationPlugins;
+        protected final InlineInvokePlugin[] inlineInvokePlugins;
+        protected final ParameterPlugin parameterPlugin;
+        protected final ValueNode[] arguments;
+
+        protected FrameState outerState;
+        protected FrameState exceptionState;
+        protected ExceptionPlaceholderNode exceptionPlaceholderNode;
+        protected NodeSourcePosition callerBytecodePosition;
+
+        protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData,
+                        int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin,
+                        ValueNode[] arguments) {
+            super(callerLoopScope, targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin));
+
+            this.caller = caller;
+            this.method = method;
+            this.invokeData = invokeData;
+            this.inliningDepth = inliningDepth;
+            this.loopExplosionPlugin = loopExplosionPlugin;
+            this.invocationPlugins = invocationPlugins;
+            this.inlineInvokePlugins = inlineInvokePlugins;
+            this.parameterPlugin = parameterPlugin;
+            this.arguments = arguments;
+        }
+
+        public boolean isInlinedMethod() {
+            return caller != null;
+        }
+
+        public NodeSourcePosition getCallerBytecodePosition() {
+            if (caller == null) {
+                return null;
+            }
+            if (callerBytecodePosition == null) {
+                JavaConstant constantReceiver = caller.invokeData == null ? null : caller.invokeData.constantReceiver;
+                NodeSourcePosition callerPosition = caller.getCallerBytecodePosition();
+                NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition();
+                callerBytecodePosition = invokePosition != null ? invokePosition.addCaller(constantReceiver, callerPosition) : callerPosition;
+            }
+            return callerBytecodePosition;
+        }
+    }
+
+    protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
+        protected final PEMethodScope methodScope;
+        protected final Invoke invoke;
+
+        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
+            this.methodScope = methodScope;
+            this.invoke = invoke;
+        }
+
+        @Override
+        public BailoutException bailout(String string) {
+            BailoutException bailout = new PermanentBailoutException(string);
+            throw GraphUtil.createBailoutException(string, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition()));
+        }
+
+        @Override
+        public StampProvider getStampProvider() {
+            return stampProvider;
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return metaAccess;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return constantReflection;
+        }
+
+        @Override
+        public ConstantFieldProvider getConstantFieldProvider() {
+            return constantFieldProvider;
+        }
+
+        @Override
+        public StructuredGraph getGraph() {
+            return methodScope.graph;
+        }
+
+        @Override
+        public int getDepth() {
+            return methodScope.inliningDepth;
+        }
+
+        @Override
+        public IntrinsicContext getIntrinsic() {
+            return null;
+        }
+
+        @Override
+        public <T extends ValueNode> T append(T value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public <T extends ValueNode> T recursiveAppend(T value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public void push(JavaKind kind, ValueNode value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) {
+            throw unimplemented();
+        }
+
+        @Override
+        public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
+            return false;
+        }
+
+        @Override
+        public void setStateAfter(StateSplit stateSplit) {
+            throw unimplemented();
+        }
+
+        @Override
+        public GraphBuilderContext getParent() {
+            throw unimplemented();
+        }
+
+        @Override
+        public Bytecode getCode() {
+            throw unimplemented();
+        }
+
+        @Override
+        public ResolvedJavaMethod getMethod() {
+            throw unimplemented();
+        }
+
+        @Override
+        public int bci() {
+            return invoke.bci();
+        }
+
+        @Override
+        public InvokeKind getInvokeKind() {
+            throw unimplemented();
+        }
+
+        @Override
+        public JavaType getInvokeReturnType() {
+            throw unimplemented();
+        }
+    }
+
+    protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext {
+        protected FixedWithNextNode lastInstr;
+        protected ValueNode pushedNode;
+
+        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
+            super(inlineScope, inlineScope.invokeData.invoke);
+            this.lastInstr = lastInstr;
+        }
+
+        @Override
+        public void push(JavaKind kind, ValueNode value) {
+            if (pushedNode != null) {
+                throw unimplemented("Only one push is supported");
+            }
+            pushedNode = value;
+        }
+
+        @Override
+        public void setStateAfter(StateSplit stateSplit) {
+            Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
+            getGraph().add(stateAfter);
+            FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+            stateSplit.setStateAfter(fs);
+        }
+
+        @SuppressWarnings("try")
+        @Override
+        public <T extends ValueNode> T append(T v) {
+            if (v.graph() != null) {
+                return v;
+            }
+            try (DebugCloseable position = withNodeSoucePosition()) {
+                T added = getGraph().addOrUnique(v);
+                if (added == v) {
+                    updateLastInstruction(v);
+                }
+                return added;
+            }
+        }
+
+        private DebugCloseable withNodeSoucePosition() {
+            if (getGraph().mayHaveNodeSourcePosition()) {
+                return getGraph().withNodeSourcePosition(methodScope.getCallerBytecodePosition());
+            }
+            return null;
+        }
+
+        @SuppressWarnings("try")
+        @Override
+        public <T extends ValueNode> T recursiveAppend(T v) {
+            if (v.graph() != null) {
+                return v;
+            }
+            try (DebugCloseable position = withNodeSoucePosition()) {
+                T added = getGraph().addOrUniqueWithInputs(v);
+                if (added == v) {
+                    updateLastInstruction(v);
+                }
+                return added;
+            }
+        }
+
+        private <T extends ValueNode> void updateLastInstruction(T v) {
+            if (v instanceof FixedNode) {
+                FixedNode fixedNode = (FixedNode) v;
+                lastInstr.setNext(fixedNode);
+                if (fixedNode instanceof FixedWithNextNode) {
+                    FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                    assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                    lastInstr = fixedWithNextNode;
+                } else {
+                    lastInstr = null;
+                }
+            }
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static class ExceptionPlaceholderNode extends ValueNode {
+        public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
+
+        protected ExceptionPlaceholderNode() {
+            super(TYPE, StampFactory.object());
+        }
+    }
+
+    public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
+                    Architecture architecture) {
+        super(metaAccess, constantReflection, constantFieldProvider, stampProvider, true, architecture);
+    }
+
+    protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
+        if (loopExplosionPlugin == null) {
+            return LoopExplosionKind.NONE;
+        } else {
+            return loopExplosionPlugin.loopExplosionKind(method);
+        }
+    }
+
+    public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
+                    ParameterPlugin parameterPlugin) {
+        PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugins,
+                        parameterPlugin, null);
+        decode(createInitialLoopScope(methodScope, null));
+        cleanupGraph(methodScope);
+
+        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After graph cleanup");
+        assert methodScope.graph.verify();
+
+        try {
+            /* Check that the control flow graph can be computed, to catch problems early. */
+            assert CFGVerifier.verify(ControlFlowGraph.compute(methodScope.graph, true, true, true, true));
+        } catch (Throwable ex) {
+            throw GraalError.shouldNotReachHere("Control flow graph not valid after partial evaluation");
+        }
+    }
+
+    @Override
+    protected void cleanupGraph(MethodScope methodScope) {
+        super.cleanupGraph(methodScope);
+
+        for (FrameState frameState : methodScope.graph.getNodes(FrameState.TYPE)) {
+            if (frameState.bci == BytecodeFrame.UNWIND_BCI) {
+                /*
+                 * handleMissingAfterExceptionFrameState is called during graph decoding from
+                 * InliningUtil.processFrameState - but during graph decoding it does not do
+                 * anything because the usages of the frameState are not available yet. So we need
+                 * to call it again.
+                 */
+                InliningUtil.handleMissingAfterExceptionFrameState(frameState);
+
+                /*
+                 * The frameState must be gone now, because it is not a valid deoptimization point.
+                 */
+                assert frameState.isDeleted();
+            }
+        }
+    }
+
+    @Override
+    protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (loopScope.loopIteration > Options.MaximumLoopExplosionCount.getValue()) {
+            throw tooManyLoopExplosionIterations(methodScope);
+        }
+    }
+
+    private static RuntimeException tooManyLoopExplosionIterations(PEMethodScope methodScope) {
+        String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?";
+        RuntimeException bailout = Options.FailedLoopExplosionIsFatal.getValue() ? new RuntimeException(message) : new PermanentBailoutException(message);
+        throw GraphUtil.createBailoutException(message, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition()));
+    }
+
+    @Override
+    protected LoopScope handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        /*
+         * Decode the call target, but do not add it to the graph yet. This avoids adding usages for
+         * all the arguments, which are expensive to remove again when we can inline the method.
+         */
+        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
+        CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId);
+        if (callTarget instanceof MethodCallTargetNode) {
+            MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget;
+            if (methodCall.invokeKind().hasReceiver()) {
+                invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant();
+            }
+            LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget);
+            if (inlineLoopScope != null) {
+                return inlineLoopScope;
+            }
+        }
+
+        /* We know that we need an invoke, so now we can add the call target to the graph. */
+        methodScope.graph.add(callTarget);
+        registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false);
+        return super.handleInvoke(methodScope, loopScope, invokeData);
+    }
+
+    protected LoopScope trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        // attempt to devirtualize the call
+        ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
+        if (specialCallTarget != null) {
+            callTarget.setTargetMethod(specialCallTarget);
+            callTarget.setInvokeKind(InvokeKind.Special);
+        }
+
+        if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) {
+            /*
+             * The invocation plugin handled the call, so decoding continues in the calling method.
+             */
+            return loopScope;
+        }
+        LoopScope inlineLoopScope = tryInline(methodScope, loopScope, invokeData, callTarget);
+        if (inlineLoopScope != null) {
+            /*
+             * We can inline the call, so decoding continues in the inlined method.
+             */
+            return inlineLoopScope;
+        }
+
+        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
+            plugin.notifyNotInlined(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
+        }
+        return null;
+    }
+
+    protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        if (methodScope.invocationPlugins == null) {
+            return false;
+        }
+
+        Invoke invoke = invokeData.invoke;
+
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod);
+        if (invocationPlugin == null) {
+            return false;
+        }
+
+        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
+        FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor();
+
+        /*
+         * Remove invoke from graph so that invocation plugin can append nodes to the predecessor.
+         */
+        invoke.asNode().replaceAtPredecessor(null);
+
+        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin,
+                        methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
+        PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor);
+        InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext);
+
+        if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) {
+
+            if (graphBuilderContext.lastInstr != null) {
+                registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
+                invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
+                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr)));
+            } else {
+                assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
+                invoke.asNode().replaceAtUsages(null);
+            }
+
+            deleteInvoke(invoke);
+            return true;
+
+        } else {
+            /* Intrinsification failed, restore original state: invoke is in Graph. */
+            invokePredecessor.setNext(invoke.asNode());
+            return false;
+        }
+    }
+
+    protected LoopScope tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        if (!callTarget.invokeKind().isDirect()) {
+            return null;
+        }
+
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        if (!targetMethod.canBeInlined()) {
+            return null;
+        }
+
+        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
+        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
+
+        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
+            InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments);
+            if (inlineInfo != null) {
+                if (inlineInfo.getMethodToInline() == null) {
+                    return null;
+                } else {
+                    return doInline(methodScope, loopScope, invokeData, inlineInfo, arguments);
+                }
+            }
+        }
+        return null;
+    }
+
+    protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) {
+        ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline();
+        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getIntrinsicBytecodeProvider());
+        if (graphToInline == null) {
+            return null;
+        }
+
+        if (methodScope.inliningDepth > Options.InliningDepthError.getValue()) {
+            throw tooDeepInlining(methodScope);
+        }
+
+        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
+            plugin.notifyBeforeInline(inlineMethod);
+        }
+
+        Invoke invoke = invokeData.invoke;
+        FixedNode invokeNode = invoke.asNode();
+        FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor();
+        invokeNode.replaceAtPredecessor(null);
+
+        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
+                        methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
+
+        /*
+         * After decoding all the nodes of the inlined method, we need to re-wire the return and
+         * unwind nodes. Since inlining is non-recursive, this cannot be done at the end of this
+         * method, but must be registered as a cleanup task that runs when all nodes of the inlined
+         * methods have been decoded.
+         */
+        inlineScope.cleanupTasks.add(() -> finishInlining(methodScope, loopScope, invokeData, inlineMethod, inlineScope));
+
+        /*
+         * Do the actual inlining by returning the initial loop scope for the inlined method scope.
+         */
+        return createInitialLoopScope(inlineScope, predecessor);
+    }
+
+    protected void finishInlining(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, ResolvedJavaMethod inlineMethod, PEMethodScope inlineScope) {
+        Invoke invoke = invokeData.invoke;
+        FixedNode invokeNode = invoke.asNode();
+
+        ValueNode exceptionValue = null;
+        List<UnwindNode> unwindNodes = inlineScope.unwindNodes;
+        Iterator<UnwindNode> iter = unwindNodes.iterator();
+        while (iter.hasNext()) {
+            if (iter.next().isDeleted()) {
+                iter.remove();
+            }
+        }
+
+        if (!unwindNodes.isEmpty()) {
+            FixedNode unwindReplacement;
+            if (invoke instanceof InvokeWithExceptionNode) {
+                /* Decoding continues for the exception handler. */
+                unwindReplacement = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
+            } else {
+                /* No exception handler available, so the only thing we can do is deoptimize. */
+                unwindReplacement = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+            }
+
+            if (unwindNodes.size() == 1) {
+                /* Only one UnwindNode, we can use the exception directly. */
+                UnwindNode unwindNode = unwindNodes.get(0);
+                exceptionValue = unwindNode.exception();
+                unwindNode.replaceAndDelete(unwindReplacement);
+
+            } else {
+                /*
+                 * More than one UnwindNode. This can happen with the loop explosion strategy
+                 * FULL_EXPLODE_UNTIL_RETURN, where we keep exploding after the loop and therefore
+                 * also explode exception paths. Merge the exception in a similar way as multiple
+                 * return values.
+                 */
+                MergeNode unwindMergeNode = methodScope.graph.add(new MergeNode());
+                exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, unwindNodes, null, unwindNode -> unwindNode.exception());
+                unwindMergeNode.setNext(unwindReplacement);
+
+                ensureExceptionStateDecoded(inlineScope);
+                unwindMergeNode.setStateAfter(inlineScope.exceptionState.duplicateModified(JavaKind.Object, JavaKind.Object, exceptionValue));
+            }
+        }
+
+        assert invoke.next() == null;
+        assert !(invoke instanceof InvokeWithExceptionNode) || ((InvokeWithExceptionNode) invoke).exceptionEdge() == null;
+
+        ValueNode returnValue;
+        List<ReturnNode> returnNodes = inlineScope.returnNodes;
+        if (!returnNodes.isEmpty()) {
+            if (returnNodes.size() == 1) {
+                ReturnNode returnNode = returnNodes.get(0);
+                returnValue = returnNode.result();
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
+                returnNode.replaceAndDelete(n);
+            } else {
+                AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
+                merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
+                returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
+                merge.setNext(n);
+            }
+        } else {
+            returnValue = null;
+        }
+        invokeNode.replaceAtUsages(returnValue);
+
+        /*
+         * Usage the handles that we have on the return value and the exception to update the
+         * orderId->Node table.
+         */
+        registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
+        if (invoke instanceof InvokeWithExceptionNode) {
+            registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
+        }
+        if (inlineScope.exceptionPlaceholderNode != null) {
+            inlineScope.exceptionPlaceholderNode.replaceAtUsagesAndDelete(exceptionValue);
+        }
+        deleteInvoke(invoke);
+
+        for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
+            plugin.notifyAfterInline(inlineMethod);
+        }
+
+        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue()) {
+            Debug.dump(Debug.INFO_LOG_LEVEL, methodScope.graph, "Inline finished: %s.%s", inlineMethod.getDeclaringClass().getUnqualifiedName(), inlineMethod.getName());
+        }
+    }
+
+    private static RuntimeException tooDeepInlining(PEMethodScope methodScope) {
+        HashMap<ResolvedJavaMethod, Integer> methodCounts = new HashMap<>();
+        for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {
+            Integer oldCount = methodCounts.get(cur.method);
+            methodCounts.put(cur.method, oldCount == null ? 1 : oldCount + 1);
+        }
+
+        List<Map.Entry<ResolvedJavaMethod, Integer>> methods = new ArrayList<>(methodCounts.entrySet());
+        methods.sort((e1, e2) -> -Integer.compare(e1.getValue(), e2.getValue()));
+
+        StringBuilder msg = new StringBuilder("Too deep inlining, probably caused by recursive inlining.").append(System.lineSeparator()).append("== Inlined methods ordered by inlining frequency:");
+        for (Map.Entry<ResolvedJavaMethod, Integer> entry : methods) {
+            msg.append(System.lineSeparator()).append(entry.getKey().format("%H.%n(%p) [")).append(entry.getValue()).append("]");
+        }
+        msg.append(System.lineSeparator()).append("== Complete stack trace of inlined methods:");
+        int lastBci = 0;
+        for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {
+            msg.append(System.lineSeparator()).append(cur.method.asStackTraceElement(lastBci));
+            if (cur.invokeData != null) {
+                lastBci = cur.invokeData.invoke.bci();
+            } else {
+                lastBci = 0;
+            }
+        }
+
+        throw new PermanentBailoutException(msg.toString());
+    }
+
+    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) {
+        assert lastBlock.isAlive();
+        FixedNode n;
+        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false);
+            n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
+        } else {
+            n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
+        }
+        return n;
+    }
+
+    private static void deleteInvoke(Invoke invoke) {
+        /*
+         * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can
+         * kill too much: nodes that are decoded later can use values that appear unused by now.
+         */
+        FrameState frameState = invoke.stateAfter();
+        invoke.asNode().safeDelete();
+        assert invoke.callTarget() == null : "must not have been added to the graph yet";
+        if (frameState != null && frameState.hasNoUsages()) {
+            frameState.safeDelete();
+        }
+    }
+
+    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider);
+
+    @SuppressWarnings("try")
+    @Override
+    protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+        if (node instanceof ForeignCallNode) {
+            ForeignCallNode foreignCall = (ForeignCallNode) node;
+            if (foreignCall.getBci() == BytecodeFrame.UNKNOWN_BCI && methodScope.invokeData != null) {
+                foreignCall.setBci(methodScope.invokeData.invoke.bci());
+            }
+        }
+
+        NodeSourcePosition pos = node.getNodeSourcePosition();
+        if (pos != null && methodScope.isInlinedMethod()) {
+            NodeSourcePosition newPosition = pos.addCaller(methodScope.getCallerBytecodePosition());
+            try (DebugCloseable scope = node.graph().withoutNodeSourcePosition()) {
+                super.handleFixedNode(s, loopScope, nodeOrderId, node);
+            }
+            if (node.isAlive()) {
+                node.setNodeSourcePosition(newPosition);
+            }
+        } else {
+            super.handleFixedNode(s, loopScope, nodeOrderId, node);
+        }
+
+    }
+
+    @Override
+    protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (node instanceof ParameterNode) {
+            ParameterNode param = (ParameterNode) node;
+            if (methodScope.arguments != null) {
+                Node result = methodScope.arguments[param.index()];
+                assert result != null;
+                return result;
+
+            } else if (methodScope.parameterPlugin != null) {
+                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
+                Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, param.index(),
+                                StampPair.create(param.stamp(), param.uncheckedStamp()));
+                if (result != null) {
+                    return result;
+                }
+            }
+
+        }
+
+        return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
+    }
+
+    protected void ensureOuterStateDecoded(PEMethodScope methodScope) {
+        if (methodScope.outerState == null && methodScope.caller != null) {
+            FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter();
+            if (stateAtReturn == null) {
+                stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
+            }
+
+            JavaKind invokeReturnKind = methodScope.invokeData.invoke.asNode().getStackKind();
+            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null);
+
+            /*
+             * When the encoded graph has methods inlining, we can already have a proper caller
+             * state. If not, we set the caller state here.
+             */
+            if (outerState.outerFrameState() == null && methodScope.caller != null) {
+                ensureOuterStateDecoded(methodScope.caller);
+                outerState.setOuterFrameState(methodScope.caller.outerState);
+            }
+            methodScope.outerState = outerState;
+        }
+    }
+
+    protected void ensureStateAfterDecoded(PEMethodScope methodScope) {
+        if (methodScope.invokeData.invoke.stateAfter() == null) {
+            methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId));
+        }
+    }
+
+    protected void ensureExceptionStateDecoded(PEMethodScope methodScope) {
+        if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) {
+            ensureStateAfterDecoded(methodScope);
+
+            assert methodScope.exceptionPlaceholderNode == null;
+            methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode());
+            registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
+            FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
+
+            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
+                ensureOuterStateDecoded(methodScope.caller);
+                exceptionState.setOuterFrameState(methodScope.caller.outerState);
+            }
+            methodScope.exceptionState = exceptionState;
+        }
+    }
+
+    @Override
+    protected Node addFloatingNode(MethodScope s, Node node) {
+        Node addedNode = super.addFloatingNode(s, node);
+        PEMethodScope methodScope = (PEMethodScope) s;
+        NodeSourcePosition pos = node.getNodeSourcePosition();
+        if (methodScope.isInlinedMethod()) {
+            if (pos != null) {
+                NodeSourcePosition bytecodePosition = methodScope.getCallerBytecodePosition();
+                node.setNodeSourcePosition(pos.addCaller(bytecodePosition));
+            }
+        }
+        return addedNode;
+    }
+
+    @Override
+    protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (methodScope.isInlinedMethod()) {
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+
+                ensureOuterStateDecoded(methodScope);
+                if (frameState.bci < 0) {
+                    ensureExceptionStateDecoded(methodScope);
+                }
+                List<ValueNode> invokeArgsList = null;
+                if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
+                    /*
+                     * We know that the argument list is only used in this case, so avoid the List
+                     * allocation for "normal" bcis.
+                     */
+                    invokeArgsList = Arrays.asList(methodScope.arguments);
+                }
+                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true, methodScope.method,
+                                invokeArgsList);
+
+            } else if (node instanceof MonitorIdNode) {
+                ensureOuterStateDecoded(methodScope);
+                InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node);
+                return node;
+            }
+        }
+
+        return node;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java
new file mode 100644
index 0000000..3cd90df
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.core.common.GraalOptions.DeoptALot;
+import static org.graalvm.compiler.core.common.GraalOptions.UseSnippetGraphCache;
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlineIntrinsicsDuringParsing;
+import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createIntrinsicInlineInfo;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.java.GraphBuilderPhase.Instance;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.options.OptionValue.OverrideScope;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class ReplacementsImpl implements Replacements, InlineInvokePlugin {
+
+    public final Providers providers;
+    public final SnippetReflectionProvider snippetReflection;
+    public final TargetDescription target;
+    private GraphBuilderConfiguration.Plugins graphBuilderPlugins;
+
+    /**
+     * The preprocessed replacement graphs.
+     */
+    protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
+
+    protected final BytecodeProvider bytecodeProvider;
+
+    public void setGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
+        assert this.graphBuilderPlugins == null;
+        this.graphBuilderPlugins = plugins;
+    }
+
+    public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() {
+        return graphBuilderPlugins;
+    }
+
+    protected boolean hasGeneratedInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Fold.class) != null;
+    }
+
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(Word.Operation.class) != null;
+    }
+
+    private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
+
+    /**
+     * Determines whether a given method should be inlined based on whether it has a substitution or
+     * whether the inlining context is already within a substitution.
+     *
+     * @return an object specifying how {@code method} is to be inlined or null if it should not be
+     *         inlined based on substitution related criteria
+     */
+    @Override
+    public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        ResolvedJavaMethod subst = getSubstitutionMethod(method);
+        if (subst != null) {
+            if (b.parsingIntrinsic() || InlineDuringParsing.getValue() || InlineIntrinsicsDuringParsing.getValue()) {
+                // Forced inlining of intrinsics
+                return createIntrinsicInlineInfo(subst, bytecodeProvider);
+            }
+            return null;
+        }
+        if (b.parsingIntrinsic()) {
+            if (hasGeneratedInvocationPluginAnnotation(method)) {
+                throw new GraalError("%s should have been handled by a %s", method.format("%H.%n(%p)"), GeneratedInvocationPlugin.class.getSimpleName());
+            }
+            if (hasGenericInvocationPluginAnnotation(method)) {
+                throw new GraalError("%s should have been handled by %s", method.format("%H.%n(%p)"), WordOperationPlugin.class.getSimpleName());
+            }
+
+            assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
+
+            if (method.getName().startsWith("$jacoco")) {
+                throw new GraalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this.");
+            }
+
+            // Force inlining when parsing replacements
+            return createIntrinsicInlineInfo(method, bytecodeProvider);
+        } else {
+            assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
+                            method.format("%h.%n"), b);
+        }
+        return null;
+    }
+
+    @Override
+    public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (b.parsingIntrinsic()) {
+            IntrinsicContext intrinsic = b.getIntrinsic();
+            if (!intrinsic.isCallToOriginal(method)) {
+                throw new GraalError("All non-recursive calls in the intrinsic %s must be inlined or intrinsified: found call to %s",
+                                intrinsic.getIntrinsicMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
+            }
+        }
+    }
+
+    // This map is key'ed by a class name instead of a Class object so that
+    // it is stable across VM executions (in support of replay compilation).
+    private final Map<String, SnippetTemplateCache> snippetTemplateCache;
+
+    public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) {
+        this.providers = providers.copyWith(this);
+        this.snippetReflection = snippetReflection;
+        this.target = target;
+        this.graphs = new ConcurrentHashMap<>();
+        this.snippetTemplateCache = CollectionsFactory.newMap();
+        this.bytecodeProvider = bytecodeProvider;
+    }
+
+    private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
+
+    @Override
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) {
+        return getSnippet(method, null, args);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args) {
+        assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
+        assert method.hasBytecodes() : "Snippet must not be abstract or native";
+
+        StructuredGraph graph = UseSnippetGraphCache.getValue() ? graphs.get(method) : null;
+        if (graph == null) {
+            try (DebugCloseable a = SnippetPreparationTime.start()) {
+                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry);
+                Debug.counter("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
+                if (!UseSnippetGraphCache.getValue() || args != null) {
+                    return newGraph;
+                }
+                graphs.putIfAbsent(method, newGraph);
+                graph = graphs.get(method);
+            }
+        }
+        return graph;
+    }
+
+    @Override
+    public void registerSnippet(ResolvedJavaMethod method) {
+        // No initialization needed as snippet graphs are created on demand in getSnippet
+    }
+
+    @Override
+    public boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) {
+        InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
+        return plugin != null && (!plugin.inlineOnly() || invokeBci >= 0);
+    }
+
+    @Override
+    public BytecodeProvider getReplacementBytecodeProvider() {
+        return bytecodeProvider;
+    }
+
+    @Override
+    public ResolvedJavaMethod getSubstitutionMethod(ResolvedJavaMethod method) {
+        InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
+        if (plugin instanceof MethodSubstitutionPlugin) {
+            MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
+            return msPlugin.getSubstitute(providers.getMetaAccess());
+        }
+        return null;
+    }
+
+    @Override
+    public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci) {
+        StructuredGraph result;
+        InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
+        if (plugin != null && (!plugin.inlineOnly() || invokeBci >= 0)) {
+            MetaAccessProvider metaAccess = providers.getMetaAccess();
+            if (plugin instanceof MethodSubstitutionPlugin) {
+                MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
+                ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess);
+                StructuredGraph graph = graphs.get(substitute);
+                if (graph == null) {
+                    graph = makeGraph(substitute, null, method);
+                    graph.freeze();
+                    graphs.putIfAbsent(substitute, graph);
+                    graph = graphs.get(substitute);
+                }
+                assert graph.isFrozen();
+                result = graph;
+            } else {
+                ResolvedJavaMethodBytecode code = new ResolvedJavaMethodBytecode(method);
+                ConstantReflectionProvider constantReflection = providers.getConstantReflection();
+                ConstantFieldProvider constantFieldProvider = providers.getConstantFieldProvider();
+                StampProvider stampProvider = providers.getStampProvider();
+                result = new IntrinsicGraphBuilder(metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci).buildGraph(plugin);
+            }
+        } else {
+            result = null;
+        }
+        return result;
+    }
+
+    /**
+     * Creates a preprocessed graph for a snippet or method substitution.
+     *
+     * @param method the snippet or method substitution for which a graph will be created
+     * @param args
+     * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
+     *            substitution} otherwise null
+     */
+    @SuppressWarnings("try")
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
+        try (OverrideScope s = OptionValue.override(DeoptALot, false)) {
+            return createGraphMaker(method, original).makeGraph(args);
+        }
+    }
+
+    /**
+     * Can be overridden to return an object that specializes various parts of graph preprocessing.
+     */
+    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
+        return new GraphMaker(this, substitute, original);
+    }
+
+    /**
+     * Creates and preprocesses a graph for a replacement.
+     */
+    public static class GraphMaker {
+
+        /** The replacements object that the graphs are created for. */
+        protected final ReplacementsImpl replacements;
+
+        /**
+         * The method for which a graph is being created.
+         */
+        protected final ResolvedJavaMethod method;
+
+        /**
+         * The original method which {@link #method} is substituting. Calls to {@link #method} or
+         * {@link #substitutedMethod} will be replaced with a forced inline of
+         * {@link #substitutedMethod}.
+         */
+        protected final ResolvedJavaMethod substitutedMethod;
+
+        protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) {
+            this.replacements = replacements;
+            this.method = substitute;
+            this.substitutedMethod = substitutedMethod;
+        }
+
+        @SuppressWarnings("try")
+        public StructuredGraph makeGraph(Object[] args) {
+            try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
+                assert method.hasBytecodes() : method;
+                StructuredGraph graph = buildInitialGraph(method, args);
+
+                finalizeGraph(graph);
+
+                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "%s: Final", method.getName());
+
+                return graph;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        /**
+         * Does final processing of a snippet graph.
+         */
+        protected void finalizeGraph(StructuredGraph graph) {
+            if (!GraalOptions.SnippetCounters.getValue() || graph.getNodes().filter(SnippetCounterNode.class).isEmpty()) {
+                int sideEffectCount = 0;
+                assert (sideEffectCount = graph.getNodes().filter(e -> hasSideEffect(e)).count()) >= 0;
+                new ConvertDeoptimizeToGuardPhase().apply(graph, null);
+                assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node";
+
+                new DeadCodeEliminationPhase(Required).apply(graph);
+            } else {
+                // ConvertDeoptimizeToGuardPhase will eliminate snippet counters on paths
+                // that terminate in a deopt so we disable it if the graph contains
+                // snippet counters. The trade off is that we miss out on guard
+                // coalescing opportunities.
+            }
+        }
+
+        /**
+         * Filter nodes which have side effects and shouldn't be deleted from snippets when
+         * converting deoptimizations to guards. Currently this only allows exception constructors
+         * to be eliminated to cover the case when Java assertions are in the inlined code.
+         *
+         * @param node
+         * @return true for nodes that have side effects and are unsafe to delete
+         */
+        private boolean hasSideEffect(Node node) {
+            if (node instanceof StateSplit) {
+                if (((StateSplit) node).hasSideEffect()) {
+                    if (node instanceof Invoke) {
+                        CallTargetNode callTarget = ((Invoke) node).callTarget();
+                        if (callTarget instanceof MethodCallTargetNode) {
+                            ResolvedJavaMethod targetMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+                            if (targetMethod.isConstructor()) {
+                                ResolvedJavaType throwableType = replacements.providers.getMetaAccess().lookupJavaType(Throwable.class);
+                                return !throwableType.isAssignableFrom(targetMethod.getDeclaringClass());
+                            }
+                        }
+                    }
+                    // Not an exception constructor call
+                    return true;
+                }
+            }
+            // Not a StateSplit
+            return false;
+        }
+
+        /**
+         * Builds the initial graph for a snippet.
+         */
+        @SuppressWarnings("try")
+        protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
+            // Replacements cannot have optimistic assumptions since they have
+            // to be valid for the entire run of the VM.
+
+            final StructuredGraph graph = new StructuredGraph(methodToParse, AllowAssumptions.NO, NO_PROFILING_INFO, INVALID_COMPILATION_ID);
+
+            // They are not user code so they do not participate in unsafe access tracking
+            graph.disableUnsafeAccessTracking();
+
+            try (Scope s = Debug.scope("buildInitialGraph", graph)) {
+                MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
+
+                Plugins plugins = new Plugins(replacements.graphBuilderPlugins);
+                GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+                if (args != null) {
+                    plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(args, metaAccess, replacements.snippetReflection));
+                }
+
+                IntrinsicContext initialIntrinsicContext = null;
+                if (method.getAnnotation(Snippet.class) == null) {
+                    // Post-parse inlined intrinsic
+                    initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, replacements.bytecodeProvider, INLINE_AFTER_PARSING);
+                } else {
+                    // Snippet
+                    ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
+                    initialIntrinsicContext = new IntrinsicContext(original, method, replacements.bytecodeProvider, INLINE_AFTER_PARSING);
+                }
+
+                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), replacements.providers.getConstantFieldProvider(), config,
+                                OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
+
+                new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            return graph;
+        }
+
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts,
+                            initialIntrinsicContext);
+        }
+    }
+
+    @Override
+    public void registerSnippetTemplateCache(SnippetTemplateCache templates) {
+        assert snippetTemplateCache.get(templates.getClass().getName()) == null;
+        snippetTemplateCache.put(templates.getClass().getName(), templates);
+    }
+
+    @Override
+    public <T extends SnippetTemplateCache> T getSnippetTemplateCache(Class<T> templatesClass) {
+        SnippetTemplateCache ret = snippetTemplateCache.get(templatesClass.getName());
+        return templatesClass.cast(ret);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java
new file mode 100644
index 0000000..db07dcb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsUtil.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+
+// JaCoCo Exclude
+public final class ReplacementsUtil {
+    private ReplacementsUtil() {
+        // empty
+    }
+
+    public static final boolean REPLACEMENTS_ASSERTIONS_ENABLED;
+
+    static {
+        boolean assertionsEnabled = false;
+        assert (assertionsEnabled = true) != false;
+        REPLACEMENTS_ASSERTIONS_ENABLED = assertionsEnabled && GraalOptions.ImmutableCode.getValue() == false;
+    }
+
+    /**
+     * Asserts that condition evaluates to true by the time compilation is finished. This is
+     * intended to be used within snippets or stubs, and will lead to a compile error if the
+     * assertion fails.
+     */
+    public static void staticAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(true, condition, message);
+        }
+    }
+
+    /**
+     * Asserts that condition evaluates to true at runtime. This is intended to be used within
+     * snippets or stubs, and will lead to a VM error if it fails.
+     */
+    public static void runtimeAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(false, condition, message);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounter.java
new file mode 100644
index 0000000..cfb90d2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounter.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+//JaCoCo Exclude
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
+ * snippet specific metrics.
+ */
+public class SnippetCounter implements Comparable<SnippetCounter> {
+    /**
+     * A group of related counters.
+     */
+    public static class Group {
+
+        final String name;
+        final List<SnippetCounter> counters;
+
+        public Group(String name) {
+            this.name = name;
+            this.counters = new ArrayList<>();
+        }
+
+        @Override
+        public synchronized String toString() {
+            Collections.sort(counters);
+
+            long total = 0;
+            int maxNameLen = 0;
+            for (SnippetCounter c : counters) {
+                total += c.value;
+                maxNameLen = Math.max(c.name.length(), maxNameLen);
+            }
+
+            StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name));
+
+            String formatString = "  %" + maxNameLen + "s: %6.2f%%%," + (String.format("%,d", total).length() + 2) + "d  // %s%n";
+            for (SnippetCounter c : counters) {
+                double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total;
+                buf.append(String.format(formatString, c.name, percent, c.value, c.description));
+            }
+            buf.append(String.format(formatString, "TOTAL", 100.0D, total, ""));
+
+            return buf.toString();
+        }
+    }
+
+    /**
+     * Sorts counters in descending order of their {@linkplain #value() values}.
+     */
+    @Override
+    public int compareTo(SnippetCounter o) {
+        if (value > o.value) {
+            return -1;
+        } else if (o.value < value) {
+            return 1;
+        }
+        return 0;
+    }
+
+    private static final List<Group> groups = new ArrayList<>();
+
+    private final Group group;
+    private final int index;
+    private final String name;
+    private final String description;
+    private long value;
+
+    /**
+     * Creates a counter.
+     *
+     * @param group the group to which the counter belongs. If this is null, the newly created
+     *            counter is disabled and {@linkplain #inc() incrementing} is a no-op.
+     * @param name the name of the counter
+     * @param description a brief comment describing the metric represented by the counter
+     */
+    public SnippetCounter(Group group, String name, String description) {
+        this.group = group;
+        this.name = name;
+        this.description = description;
+        if (group != null) {
+            List<SnippetCounter> counters = group.counters;
+            this.index = counters.size();
+            counters.add(this);
+            if (index == 0) {
+                groups.add(group);
+            }
+        } else {
+            this.index = -1;
+        }
+    }
+
+    /**
+     * Increments the value of this counter. This method can only be used in a snippet on a
+     * compile-time constant {@link SnippetCounter} object.
+     */
+    public void inc() {
+        if (group != null) {
+            SnippetCounterNode.increment(this);
+        }
+    }
+
+    /**
+     * Increments the value of this counter. This method can only be used in a snippet on a
+     * compile-time constant {@link SnippetCounter} object.
+     */
+    public void add(int increment) {
+        if (group != null) {
+            SnippetCounterNode.add(this, increment);
+        }
+    }
+
+    /**
+     * Gets the value of this counter.
+     */
+    public long value() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        if (group != null) {
+            return "SnippetCounter-" + group.name + ":" + name;
+        }
+        return super.toString();
+    }
+
+    /**
+     * Prints all the counter groups to a given stream.
+     */
+    public static void printGroups(PrintStream out) {
+        for (Group group : groups) {
+            out.println(group);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java
new file mode 100644
index 0000000..a7b998f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.word.ObjectAccess;
+
+import jdk.vm.ci.code.TargetDescription;
+import sun.misc.Unsafe;
+
+/**
+ * This node can be used to add a counter to the code that will estimate the dynamic number of calls
+ * by adding an increment to the compiled code. This should of course only be used for
+ * debugging/testing purposes.
+ *
+ * A unique counter will be created for each unique name passed to the constructor. Depending on the
+ * value of withContext, the name of the root method is added to the counter's name.
+ */
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+public class SnippetCounterNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<SnippetCounterNode> TYPE = NodeClass.create(SnippetCounterNode.class);
+
+    @Input protected ValueNode increment;
+
+    protected final SnippetCounter counter;
+
+    public SnippetCounterNode(SnippetCounter counter, ValueNode increment) {
+        super(TYPE, StampFactory.forVoid());
+        this.counter = counter;
+        this.increment = increment;
+    }
+
+    public SnippetCounter getCounter() {
+        return counter;
+    }
+
+    public ValueNode getIncrement() {
+        return increment;
+    }
+
+    @NodeIntrinsic
+    public static native void add(@ConstantNodeParameter SnippetCounter counter, int increment);
+
+    public static void increment(@ConstantNodeParameter SnippetCounter counter) {
+        add(counter, 1);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
+            SnippetCounterSnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(SnippetCounterSnippets.Templates.class);
+            templates.lower(this, tool);
+        }
+    }
+
+    /**
+     * When {@link #SnippetCounters} are enabled make sure {@link #SNIPPET_COUNTER_LOCATION} is part
+     * of the private locations.
+     *
+     * @param privateLocations
+     * @return a copy of privateLocations with any needed locations added
+     */
+    public static LocationIdentity[] addSnippetCounters(LocationIdentity[] privateLocations) {
+        if (SnippetCounters.getValue()) {
+            for (LocationIdentity location : privateLocations) {
+                if (location.equals(SNIPPET_COUNTER_LOCATION)) {
+                    return privateLocations;
+                }
+            }
+            LocationIdentity[] result = Arrays.copyOf(privateLocations, privateLocations.length + 1);
+            result[result.length - 1] = SnippetCounterNode.SNIPPET_COUNTER_LOCATION;
+            return result;
+        }
+        return privateLocations;
+    }
+
+    /**
+     * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value} field,
+     * so that the usage in snippets is always possible. If a method accesses the counter via the
+     * field and the snippet, the result might not be correct though.
+     */
+    public static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter");
+
+    static class SnippetCounterSnippets implements Snippets {
+
+        @Fold
+        static int countOffset() {
+            try {
+                return (int) UNSAFE.objectFieldOffset(SnippetCounter.class.getDeclaredField("value"));
+            } catch (Exception e) {
+                throw new GraalError(e);
+            }
+        }
+
+        @Snippet
+        public static void add(@ConstantParameter SnippetCounter counter, int increment) {
+            long loadedValue = ObjectAccess.readLong(counter, countOffset(), SNIPPET_COUNTER_LOCATION);
+            ObjectAccess.writeLong(counter, countOffset(), loadedValue + increment, SNIPPET_COUNTER_LOCATION);
+        }
+
+        public static class Templates extends AbstractTemplates {
+
+            private final SnippetInfo add = snippet(SnippetCounterSnippets.class, "add", SNIPPET_COUNTER_LOCATION);
+
+            Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+                super(providers, snippetReflection, target);
+            }
+
+            public void lower(SnippetCounterNode counter, LoweringTool tool) {
+                StructuredGraph graph = counter.graph();
+                Arguments args = new Arguments(add, graph.getGuardsStage(), tool.getLoweringStage());
+                args.addConst("counter", counter.getCounter());
+                args.add("increment", counter.getIncrement());
+
+                template(args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args);
+            }
+        }
+    }
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java
new file mode 100644
index 0000000..ef75016
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java
@@ -0,0 +1,1624 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation;
+import static org.graalvm.compiler.core.common.LocationIdentity.ANY_LOCATION;
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.debug.Debug.applyFormattingFlagsAndWidth;
+import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+import static java.util.FormattableFlags.ALTERNATE;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Formattable;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugTimer;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.loop.phases.LoopTransformations;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryAnchorNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryMap;
+import org.graalvm.compiler.nodes.memory.MemoryMapNode;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.MemoryProxy;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
+import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode;
+import org.graalvm.compiler.word.WordBase;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Local;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * A snippet template is a graph created by parsing a snippet method and then specialized by binding
+ * constants to the snippet's {@link ConstantParameter} parameters.
+ *
+ * Snippet templates can be managed in a cache maintained by {@link AbstractTemplates}.
+ */
+public class SnippetTemplate {
+
+    private boolean mayRemoveLocation = false;
+
+    /**
+     * Holds the {@link ResolvedJavaMethod} of the snippet, together with some information about the
+     * method that needs to be computed only once. The {@link SnippetInfo} should be created once
+     * per snippet and then cached.
+     */
+    public abstract static class SnippetInfo {
+
+        protected final ResolvedJavaMethod method;
+        protected ResolvedJavaMethod original;
+        protected final LocationIdentity[] privateLocations;
+
+        /**
+         * Lazily constructed parts of {@link SnippetInfo}.
+         */
+        static class Lazy {
+            Lazy(ResolvedJavaMethod method) {
+                int count = method.getSignature().getParameterCount(false);
+                constantParameters = new boolean[count];
+                varargsParameters = new boolean[count];
+                for (int i = 0; i < count; i++) {
+                    constantParameters[i] = method.getParameterAnnotation(ConstantParameter.class, i) != null;
+                    varargsParameters[i] = method.getParameterAnnotation(VarargsParameter.class, i) != null;
+
+                    assert !constantParameters[i] || !varargsParameters[i] : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" +
+                                    VarargsParameter.class.getSimpleName();
+                }
+
+                // Retrieve the names only when assertions are turned on.
+                assert initNames(method, count);
+            }
+
+            final boolean[] constantParameters;
+            final boolean[] varargsParameters;
+
+            /**
+             * The parameter names, taken from the local variables table. Only used for assertion
+             * checking, so use only within an assert statement.
+             */
+            String[] names;
+
+            private boolean initNames(ResolvedJavaMethod method, int parameterCount) {
+                names = new String[parameterCount];
+                int slotIdx = 0;
+                LocalVariableTable localVariableTable = method.getLocalVariableTable();
+                if (localVariableTable != null) {
+                    for (int i = 0; i < names.length; i++) {
+                        Local local = localVariableTable.getLocal(slotIdx, 0);
+                        if (local != null) {
+                            names[i] = local.getName();
+                        }
+                        JavaKind kind = method.getSignature().getParameterKind(i);
+                        slotIdx += kind.getSlotCount();
+                    }
+                }
+                return true;
+            }
+
+        }
+
+        /**
+         * Times instantiations of all templates derived form this snippet.
+         *
+         * @see SnippetTemplate#instantiationTimer
+         */
+        private final DebugTimer instantiationTimer;
+
+        /**
+         * Counts instantiations of all templates derived from this snippet.
+         *
+         * @see SnippetTemplate#instantiationCounter
+         */
+        private final DebugCounter instantiationCounter;
+
+        protected abstract Lazy lazy();
+
+        protected SnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations) {
+            this.method = method;
+            this.privateLocations = SnippetCounterNode.addSnippetCounters(privateLocations);
+            instantiationCounter = Debug.counter("SnippetInstantiationCount[%s]", method.getName());
+            instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method.getName());
+            assert method.isStatic() : "snippet method must be static: " + method.format("%H.%n");
+        }
+
+        public ResolvedJavaMethod getMethod() {
+            return method;
+        }
+
+        public int getParameterCount() {
+            return lazy().constantParameters.length;
+        }
+
+        public void setOriginalMethod(ResolvedJavaMethod original) {
+            this.original = original;
+        }
+
+        public boolean isConstantParameter(int paramIdx) {
+            return lazy().constantParameters[paramIdx];
+        }
+
+        public boolean isVarargsParameter(int paramIdx) {
+            return lazy().varargsParameters[paramIdx];
+        }
+
+        public String getParameterName(int paramIdx) {
+            String[] names = lazy().names;
+            if (names != null) {
+                return names[paramIdx];
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + ":" + method.format("%h.%n");
+        }
+    }
+
+    protected static class LazySnippetInfo extends SnippetInfo {
+        protected final AtomicReference<Lazy> lazy = new AtomicReference<>(null);
+
+        protected LazySnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations) {
+            super(method, privateLocations);
+        }
+
+        @Override
+        protected Lazy lazy() {
+            if (lazy.get() == null) {
+                lazy.compareAndSet(null, new Lazy(method));
+            }
+            return lazy.get();
+        }
+    }
+
+    protected static class EagerSnippetInfo extends SnippetInfo {
+        protected final Lazy lazy;
+
+        protected EagerSnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations) {
+            super(method, privateLocations);
+            lazy = new Lazy(method);
+        }
+
+        @Override
+        protected Lazy lazy() {
+            return lazy;
+        }
+    }
+
+    /**
+     * Values that are bound to the snippet method parameters. The methods {@link #add},
+     * {@link #addConst}, and {@link #addVarargs} must be called in the same order as in the
+     * signature of the snippet method. The parameter name is passed to the add methods for
+     * assertion checking, i.e., to enforce that the order matches. Which method needs to be called
+     * depends on the annotation of the snippet method parameter:
+     * <ul>
+     * <li>Use {@link #add} for a parameter without an annotation. The value is bound when the
+     * {@link SnippetTemplate} is {@link SnippetTemplate#instantiate instantiated}.
+     * <li>Use {@link #addConst} for a parameter annotated with {@link ConstantParameter}. The value
+     * is bound when the {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created}.
+     * <li>Use {@link #addVarargs} for an array parameter annotated with {@link VarargsParameter}. A
+     * separate {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created} for every
+     * distinct array length. The actual values are bound when the {@link SnippetTemplate} is
+     * {@link SnippetTemplate#instantiate instantiated}
+     * </ul>
+     */
+    public static class Arguments implements Formattable {
+
+        protected final SnippetInfo info;
+        protected final CacheKey cacheKey;
+        protected final Object[] values;
+        protected final Stamp[] constStamps;
+        protected boolean cacheable;
+
+        protected int nextParamIdx;
+
+        public Arguments(SnippetInfo info, GuardsStage guardsStage, LoweringTool.LoweringStage loweringStage) {
+            this.info = info;
+            this.cacheKey = new CacheKey(info, guardsStage, loweringStage);
+            this.values = new Object[info.getParameterCount()];
+            this.constStamps = new Stamp[info.getParameterCount()];
+            this.cacheable = true;
+        }
+
+        public Arguments add(String name, Object value) {
+            assert check(name, false, false);
+            values[nextParamIdx] = value;
+            nextParamIdx++;
+            return this;
+        }
+
+        public Arguments addConst(String name, Object value) {
+            assert value != null;
+            return addConst(name, value, null);
+        }
+
+        public Arguments addConst(String name, Object value, Stamp stamp) {
+            assert check(name, true, false);
+            values[nextParamIdx] = value;
+            constStamps[nextParamIdx] = stamp;
+            cacheKey.setParam(nextParamIdx, value);
+            nextParamIdx++;
+            return this;
+        }
+
+        public Arguments addVarargs(String name, Class<?> componentType, Stamp argStamp, Object value) {
+            assert check(name, false, true);
+            Varargs varargs = new Varargs(componentType, argStamp, value);
+            values[nextParamIdx] = varargs;
+            // A separate template is necessary for every distinct array length
+            cacheKey.setParam(nextParamIdx, varargs.length);
+            nextParamIdx++;
+            return this;
+        }
+
+        public void setCacheable(boolean cacheable) {
+            this.cacheable = cacheable;
+        }
+
+        private boolean check(String name, boolean constParam, boolean varargsParam) {
+            assert nextParamIdx < info.getParameterCount() : "too many parameters: " + name + "  " + this;
+            assert info.getParameterName(nextParamIdx) == null || info.getParameterName(nextParamIdx).equals(name) : "wrong parameter name: " + name + "  " + this;
+            assert constParam == info.isConstantParameter(nextParamIdx) : "Parameter " + (constParam ? "not " : "") + "annotated with @" + ConstantParameter.class.getSimpleName() + ": " + name +
+                            "  " + this;
+            assert varargsParam == info.isVarargsParameter(nextParamIdx) : "Parameter " + (varargsParam ? "not " : "") + "annotated with @" + VarargsParameter.class.getSimpleName() + ": " + name +
+                            "  " + this;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder result = new StringBuilder();
+            result.append("Parameters<").append(info.method.format("%h.%n")).append(" [");
+            String sep = "";
+            for (int i = 0; i < info.getParameterCount(); i++) {
+                result.append(sep);
+                if (info.isConstantParameter(i)) {
+                    result.append("const ");
+                } else if (info.isVarargsParameter(i)) {
+                    result.append("varargs ");
+                }
+                result.append(info.getParameterName(i)).append(" = ").append(values[i]);
+                sep = ", ";
+            }
+            result.append(">");
+            return result.toString();
+        }
+
+        @Override
+        public void formatTo(Formatter formatter, int flags, int width, int precision) {
+            if ((flags & ALTERNATE) == 0) {
+                formatter.format(applyFormattingFlagsAndWidth(toString(), flags, width));
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append(info.method.getName()).append('(');
+                String sep = "";
+                for (int i = 0; i < info.getParameterCount(); i++) {
+                    if (info.isConstantParameter(i)) {
+                        sb.append(sep);
+                        if (info.getParameterName(i) != null) {
+                            sb.append(info.getParameterName(i));
+                        } else {
+                            sb.append(i);
+                        }
+                        sb.append('=').append(values[i]);
+                        sep = ", ";
+                    }
+                }
+                sb.append(")");
+                String string = sb.toString();
+                if (string.indexOf('%') != -1) {
+                    // Quote any % signs
+                    string = string.replace("%", "%%");
+                }
+                formatter.format(applyFormattingFlagsAndWidth(string, flags & ~ALTERNATE, width));
+            }
+        }
+    }
+
+    /**
+     * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter.
+     */
+    static class Varargs {
+
+        protected final Class<?> componentType;
+        protected final Stamp stamp;
+        protected final Object value;
+        protected final int length;
+
+        protected Varargs(Class<?> componentType, Stamp stamp, Object value) {
+            this.componentType = componentType;
+            this.stamp = stamp;
+            this.value = value;
+            if (value instanceof List) {
+                this.length = ((List<?>) value).size();
+            } else {
+                this.length = Array.getLength(value);
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (value instanceof boolean[]) {
+                return Arrays.toString((boolean[]) value);
+            }
+            if (value instanceof byte[]) {
+                return Arrays.toString((byte[]) value);
+            }
+            if (value instanceof char[]) {
+                return Arrays.toString((char[]) value);
+            }
+            if (value instanceof short[]) {
+                return Arrays.toString((short[]) value);
+            }
+            if (value instanceof int[]) {
+                return Arrays.toString((int[]) value);
+            }
+            if (value instanceof long[]) {
+                return Arrays.toString((long[]) value);
+            }
+            if (value instanceof float[]) {
+                return Arrays.toString((float[]) value);
+            }
+            if (value instanceof double[]) {
+                return Arrays.toString((double[]) value);
+            }
+            if (value instanceof Object[]) {
+                return Arrays.toString((Object[]) value);
+            }
+            return String.valueOf(value);
+        }
+    }
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class VarargsPlaceholderNode extends FloatingNode implements ArrayLengthProvider {
+
+        public static final NodeClass<VarargsPlaceholderNode> TYPE = NodeClass.create(VarargsPlaceholderNode.class);
+        protected final Varargs varargs;
+
+        protected VarargsPlaceholderNode(Varargs varargs, MetaAccessProvider metaAccess) {
+            super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(varargs.componentType).getArrayClass())));
+            this.varargs = varargs;
+        }
+
+        @Override
+        public ValueNode length() {
+            return ConstantNode.forInt(varargs.length);
+        }
+    }
+
+    static class CacheKey {
+
+        private final ResolvedJavaMethod method;
+        private final Object[] values;
+        private final GuardsStage guardsStage;
+        private final LoweringTool.LoweringStage loweringStage;
+        private int hash;
+
+        protected CacheKey(SnippetInfo info, GuardsStage guardsStage, LoweringTool.LoweringStage loweringStage) {
+            this.method = info.method;
+            this.guardsStage = guardsStage;
+            this.loweringStage = loweringStage;
+            this.values = new Object[info.getParameterCount()];
+            this.hash = info.method.hashCode() + 31 * guardsStage.ordinal();
+        }
+
+        protected void setParam(int paramIdx, Object value) {
+            values[paramIdx] = value;
+            hash = (hash * 31) ^ (value == null ? 0 : value.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof CacheKey)) {
+                return false;
+            }
+            CacheKey other = (CacheKey) obj;
+            if (!method.equals(other.method)) {
+                return false;
+            }
+            if (guardsStage != other.guardsStage || loweringStage != other.loweringStage) {
+                return false;
+            }
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] != null && !values[i].equals(other.values[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+    private static final DebugTimer SnippetTemplateCreationTime = Debug.timer("SnippetTemplateCreationTime");
+    private static final DebugCounter SnippetTemplates = Debug.counter("SnippetTemplateCount");
+
+    static class Options {
+        @Option(help = "Use a LRU cache for snippet templates.")//
+        static final OptionValue<Boolean> UseSnippetTemplateCache = new OptionValue<>(true);
+
+        @Option(help = "")//
+        static final OptionValue<Integer> MaxTemplatesPerSnippet = new OptionValue<>(50);
+    }
+
+    /**
+     * Base class for snippet classes. It provides a cache for {@link SnippetTemplate}s.
+     */
+    public abstract static class AbstractTemplates implements org.graalvm.compiler.api.replacements.SnippetTemplateCache {
+
+        protected final Providers providers;
+        protected final SnippetReflectionProvider snippetReflection;
+        protected final TargetDescription target;
+        private final Map<CacheKey, SnippetTemplate> templates;
+
+        protected AbstractTemplates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+            this.providers = providers;
+            this.snippetReflection = snippetReflection;
+            this.target = target;
+            if (Options.UseSnippetTemplateCache.getValue()) {
+                int size = Options.MaxTemplatesPerSnippet.getValue();
+                this.templates = Collections.synchronizedMap(new LRUCache<>(size, size));
+            } else {
+                this.templates = null;
+            }
+        }
+
+        public static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
+            for (Method m : declaringClass.getDeclaredMethods()) {
+                if (m.getName().equals(methodName) && !m.equals(except)) {
+                    return m;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Finds the unique method in {@code declaringClass} named {@code methodName} annotated by
+         * {@link Snippet} and returns a {@link SnippetInfo} value describing it. There must be
+         * exactly one snippet method in {@code declaringClass}.
+         */
+        protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName, LocationIdentity... privateLocations) {
+            assert methodName != null;
+            Method method = findMethod(declaringClass, methodName, null);
+            assert method != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName;
+            assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
+            assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass;
+            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method);
+            providers.getReplacements().registerSnippet(javaMethod);
+            if (GraalOptions.EagerSnippets.getValue()) {
+                return new EagerSnippetInfo(javaMethod, privateLocations);
+            } else {
+                return new LazySnippetInfo(javaMethod, privateLocations);
+            }
+        }
+
+        /**
+         * Gets a template for a given key, creating it first if necessary.
+         */
+        @SuppressWarnings("try")
+        protected SnippetTemplate template(final Arguments args) {
+            SnippetTemplate template = Options.UseSnippetTemplateCache.getValue() && args.cacheable ? templates.get(args.cacheKey) : null;
+            if (template == null) {
+                SnippetTemplates.increment();
+                try (DebugCloseable a = SnippetTemplateCreationTime.start(); Scope s = Debug.scope("SnippetSpecialization", args.info.method)) {
+                    template = new SnippetTemplate(providers, snippetReflection, args);
+                    if (Options.UseSnippetTemplateCache.getValue() && args.cacheable) {
+                        templates.put(args.cacheKey, template);
+                    }
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+            return template;
+        }
+    }
+
+    private static final class LRUCache<K, V> extends LinkedHashMap<K, V> {
+        private static final long serialVersionUID = 1L;
+        private final int maxCacheSize;
+
+        LRUCache(int initialCapacity, int maxCacheSize) {
+            super(initialCapacity, 0.75F, true);
+            this.maxCacheSize = maxCacheSize;
+        }
+
+        @Override
+        protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
+            return size() > maxCacheSize;
+        }
+    }
+
+    // These values must be compared with equals() not '==' to support replay compilation.
+    private static final Object UNUSED_PARAMETER = "UNUSED_PARAMETER";
+    private static final Object CONSTANT_PARAMETER = "CONSTANT_PARAMETER";
+
+    /**
+     * Determines if any parameter of a given method is annotated with {@link ConstantParameter}.
+     */
+    public static boolean hasConstantParameter(ResolvedJavaMethod method) {
+        for (ConstantParameter p : method.getParameterAnnotations(ConstantParameter.class)) {
+            if (p != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private final SnippetReflectionProvider snippetReflection;
+
+    /**
+     * Creates a snippet template.
+     */
+    @SuppressWarnings("try")
+    protected SnippetTemplate(final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args) {
+        this.snippetReflection = snippetReflection;
+        this.info = args.info;
+
+        Object[] constantArgs = getConstantArgs(args);
+        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs);
+        instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args);
+        instantiationCounter = Debug.counter("SnippetTemplateInstantiationCount[%#s]", args);
+
+        ResolvedJavaMethod method = snippetGraph.method();
+        Signature signature = method.getSignature();
+
+        PhaseContext phaseContext = new PhaseContext(providers);
+
+        // Copy snippet graph, replacing constant parameters with given arguments
+        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method(), AllowAssumptions.NO, INVALID_COMPILATION_ID);
+
+        try (Debug.Scope scope = Debug.scope("SpecializeSnippet", snippetCopy)) {
+            if (!snippetGraph.isUnsafeAccessTrackingEnabled()) {
+                snippetCopy.disableUnsafeAccessTracking();
+            }
+
+            Map<Node, Node> nodeReplacements = Node.newIdentityMap();
+            nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
+
+            MetaAccessProvider metaAccess = providers.getMetaAccess();
+            assert checkTemplate(metaAccess, args, method, signature);
+
+            int parameterCount = args.info.getParameterCount();
+            VarargsPlaceholderNode[] placeholders = new VarargsPlaceholderNode[parameterCount];
+
+            for (int i = 0; i < parameterCount; i++) {
+                if (args.info.isConstantParameter(i)) {
+                    Object arg = args.values[i];
+                    JavaKind kind = signature.getParameterKind(i);
+                    ConstantNode constantNode;
+                    if (arg instanceof Constant) {
+                        Stamp stamp = args.constStamps[i];
+                        if (stamp == null) {
+                            assert arg instanceof JavaConstant : "could not determine type of constant " + arg;
+                            constantNode = ConstantNode.forConstant((JavaConstant) arg, metaAccess, snippetCopy);
+                        } else {
+                            constantNode = ConstantNode.forConstant(stamp, (Constant) arg, metaAccess, snippetCopy);
+                        }
+                    } else {
+                        constantNode = ConstantNode.forConstant(snippetReflection.forBoxed(kind, arg), metaAccess, snippetCopy);
+                    }
+                    nodeReplacements.put(snippetGraph.getParameter(i), constantNode);
+                } else if (args.info.isVarargsParameter(i)) {
+                    Varargs varargs = (Varargs) args.values[i];
+                    VarargsPlaceholderNode placeholder = snippetCopy.unique(new VarargsPlaceholderNode(varargs, providers.getMetaAccess()));
+                    nodeReplacements.put(snippetGraph.getParameter(i), placeholder);
+                    placeholders[i] = placeholder;
+                }
+            }
+            snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements);
+
+            Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "Before specialization");
+
+            // Gather the template parameters
+            parameters = new Object[parameterCount];
+            for (int i = 0; i < parameterCount; i++) {
+                if (args.info.isConstantParameter(i)) {
+                    parameters[i] = CONSTANT_PARAMETER;
+                } else if (args.info.isVarargsParameter(i)) {
+                    assert snippetCopy.getParameter(i) == null;
+                    Varargs varargs = (Varargs) args.values[i];
+                    int length = varargs.length;
+                    ParameterNode[] params = new ParameterNode[length];
+                    Stamp stamp = varargs.stamp;
+                    for (int j = 0; j < length; j++) {
+                        // Use a decimal friendly numbering make it more obvious how values map
+                        assert parameterCount < 10000;
+                        int idx = (i + 1) * 10000 + j;
+                        assert idx >= parameterCount : "collision in parameter numbering";
+                        ParameterNode local = snippetCopy.addOrUnique(new ParameterNode(idx, StampPair.createSingle(stamp)));
+                        params[j] = local;
+                    }
+                    parameters[i] = params;
+
+                    VarargsPlaceholderNode placeholder = placeholders[i];
+                    assert placeholder != null;
+                    for (Node usage : placeholder.usages().snapshot()) {
+                        if (usage instanceof LoadIndexedNode) {
+                            LoadIndexedNode loadIndexed = (LoadIndexedNode) usage;
+                            Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "Before replacing %s", loadIndexed);
+                            LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(params, loadIndexed.index(), loadIndexed.stamp()));
+                            snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter);
+                            Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "After replacing %s", loadIndexed);
+                        } else if (usage instanceof StoreIndexedNode) {
+                            /*
+                             * The template lowering doesn't really treat this as an array so you
+                             * can't store back into the varargs. Allocate your own array if you
+                             * really need this and EA should eliminate it.
+                             */
+                            throw new GraalError("Can't store into VarargsParameter array");
+                        }
+                    }
+                } else {
+                    ParameterNode local = snippetCopy.getParameter(i);
+                    if (local == null) {
+                        // Parameter value was eliminated
+                        parameters[i] = UNUSED_PARAMETER;
+                    } else {
+                        parameters[i] = local;
+                    }
+                }
+            }
+
+            // Do any required loop explosion
+            boolean exploded = false;
+            do {
+                exploded = false;
+                ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first();
+                if (explodeLoop != null) { // Earlier canonicalization may have removed the loop
+                    // altogether
+                    LoopBeginNode loopBegin = explodeLoop.findLoopBegin();
+                    if (loopBegin != null) {
+                        LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
+                        Mark mark = snippetCopy.getMark();
+                        LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase());
+                        new CanonicalizerPhase().applyIncremental(snippetCopy, phaseContext, mark);
+                        loop.deleteUnusedNodes();
+                    }
+                    GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
+                    exploded = true;
+                }
+            } while (exploded);
+
+            GuardsStage guardsStage = args.cacheKey.guardsStage;
+            // Perform lowering on the snippet
+            if (!guardsStage.allowsFloatingGuards()) {
+                new GuardLoweringPhase().apply(snippetCopy, null);
+            }
+            snippetCopy.setGuardsStage(guardsStage);
+            try (Scope s = Debug.scope("LoweringSnippetTemplate", snippetCopy)) {
+                new LoweringPhase(new CanonicalizerPhase(), args.cacheKey.loweringStage).apply(snippetCopy, phaseContext);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
+            ArrayList<StateSplit> curSideEffectNodes = new ArrayList<>();
+            ArrayList<DeoptimizingNode> curDeoptNodes = new ArrayList<>();
+            ArrayList<ValueNode> curStampNodes = new ArrayList<>();
+            for (Node node : snippetCopy.getNodes()) {
+                if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) {
+                    curStampNodes.add((ValueNode) node);
+                }
+                if (node instanceof StateSplit) {
+                    StateSplit stateSplit = (StateSplit) node;
+                    FrameState frameState = stateSplit.stateAfter();
+                    if (stateSplit.hasSideEffect()) {
+                        curSideEffectNodes.add((StateSplit) node);
+                    }
+                    if (frameState != null) {
+                        stateSplit.setStateAfter(null);
+                    }
+                }
+                if (node instanceof DeoptimizingNode) {
+                    DeoptimizingNode deoptNode = (DeoptimizingNode) node;
+                    if (deoptNode.canDeoptimize()) {
+                        curDeoptNodes.add(deoptNode);
+                    }
+                }
+            }
+
+            new DeadCodeEliminationPhase(Required).apply(snippetCopy);
+
+            assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders);
+
+            new FloatingReadPhase(true, true).apply(snippetCopy);
+
+            MemoryAnchorNode anchor = snippetCopy.add(new MemoryAnchorNode());
+            snippetCopy.start().replaceAtUsages(InputType.Memory, anchor);
+
+            this.snippet = snippetCopy;
+
+            StartNode entryPointNode = snippet.start();
+            if (anchor.hasNoUsages()) {
+                anchor.safeDelete();
+                this.memoryAnchor = null;
+            } else {
+                // Find out if all the return memory maps point to the anchor (i.e., there's no kill
+                // anywhere)
+                boolean needsMemoryMaps = false;
+                for (ReturnNode retNode : snippet.getNodes(ReturnNode.TYPE)) {
+                    MemoryMapNode memoryMap = retNode.getMemoryMap();
+                    if (memoryMap.getLocations().size() > 1 || memoryMap.getLastLocationAccess(ANY_LOCATION) != anchor) {
+                        needsMemoryMaps = true;
+                        break;
+                    }
+                }
+                boolean needsAnchor;
+                if (needsMemoryMaps) {
+                    needsAnchor = true;
+                } else {
+                    // Check that all those memory maps where the only usages of the anchor
+                    needsAnchor = anchor.usages().filter(isNotA(MemoryMapNode.class)).isNotEmpty();
+                    // Remove the useless memory map
+                    MemoryMapNode memoryMap = null;
+                    for (ReturnNode retNode : snippet.getNodes(ReturnNode.TYPE)) {
+                        if (memoryMap == null) {
+                            memoryMap = retNode.getMemoryMap();
+                        } else {
+                            assert memoryMap == retNode.getMemoryMap();
+                        }
+                        retNode.setMemoryMap(null);
+                    }
+                    memoryMap.safeDelete();
+                }
+                if (needsAnchor) {
+                    snippetCopy.addAfterFixed(snippetCopy.start(), anchor);
+                    this.memoryAnchor = anchor;
+                } else {
+                    anchor.safeDelete();
+                    this.memoryAnchor = null;
+                }
+            }
+            Debug.dump(Debug.INFO_LOG_LEVEL, snippet, "SnippetTemplate after fixing memory anchoring");
+
+            List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot();
+            if (returnNodes.isEmpty()) {
+                this.returnNode = null;
+            } else if (returnNodes.size() == 1) {
+                this.returnNode = returnNodes.get(0);
+            } else {
+                AbstractMergeNode merge = snippet.add(new MergeNode());
+                List<MemoryMapNode> memMaps = returnNodes.stream().map(ReturnNode::getMemoryMap).filter(Objects::nonNull).collect(Collectors.toList());
+                ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
+                this.returnNode = snippet.add(new ReturnNode(returnValue));
+                if (!memMaps.isEmpty()) {
+                    MemoryMapImpl mmap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
+                    MemoryMapNode memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap()));
+                    this.returnNode.setMemoryMap(memoryMap);
+                    for (MemoryMapNode mm : memMaps) {
+                        if (mm != memoryMap && mm.isAlive()) {
+                            assert mm.hasNoUsages();
+                            GraphUtil.killWithUnusedFloatingInputs(mm);
+                        }
+                    }
+                }
+                merge.setNext(this.returnNode);
+            }
+
+            this.sideEffectNodes = curSideEffectNodes;
+            this.deoptNodes = curDeoptNodes;
+            this.stampNodes = curStampNodes;
+
+            nodes = new ArrayList<>(snippet.getNodeCount());
+            for (Node node : snippet.getNodes()) {
+                if (node != entryPointNode && node != entryPointNode.stateAfter()) {
+                    nodes.add(node);
+                }
+            }
+
+            Debug.counter("SnippetTemplateNodeCount[%#s]", args).add(nodes.size());
+            Debug.dump(Debug.INFO_LOG_LEVEL, snippet, "SnippetTemplate final state");
+
+        } catch (Throwable ex) {
+            throw Debug.handle(ex);
+        }
+    }
+
+    protected Object[] getConstantArgs(Arguments args) {
+        Object[] constantArgs = args.values.clone();
+        for (int i = 0; i < args.info.getParameterCount(); i++) {
+            if (!args.info.isConstantParameter(i)) {
+                constantArgs[i] = null;
+            } else {
+                assert constantArgs[i] != null : "Can't pass raw null through as argument";
+            }
+        }
+        return constantArgs;
+    }
+
+    private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, VarargsPlaceholderNode[] placeholders) {
+        for (int i = 0; i < parameterCount; i++) {
+            if (placeholders[i] != null) {
+                assert placeholders[i].isDeleted() : placeholders[i];
+            }
+        }
+        return true;
+    }
+
+    private static boolean checkConstantArgument(MetaAccessProvider metaAccess, final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, JavaKind kind) {
+        ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass());
+        if (metaAccess.lookupJavaType(WordBase.class).isAssignableFrom(type)) {
+            assert arg instanceof JavaConstant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg;
+            return true;
+        }
+        if (kind != JavaKind.Object) {
+            assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : method + ": wrong value kind for " + name + ": expected " + kind + ", got " +
+                            (arg == null ? "null" : arg.getClass().getSimpleName());
+        }
+        return true;
+    }
+
+    private static boolean checkVarargs(MetaAccessProvider metaAccess, final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) {
+        ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
+        assert type.isArray() : "varargs parameter must be an array type";
+        assert type.getComponentType().isAssignableFrom(metaAccess.lookupJavaType(varargs.componentType)) : "componentType for " + name + " not matching " + type.toJavaName() + " instance: " +
+                        varargs.componentType;
+        return true;
+    }
+
+    /**
+     * The graph built from the snippet method.
+     */
+    private final StructuredGraph snippet;
+
+    private final SnippetInfo info;
+
+    /**
+     * The named parameters of this template that must be bound to values during instantiation. For
+     * a parameter that is still live after specialization, the value in this map is either a
+     * {@link ParameterNode} instance or a {@link ParameterNode} array. For an eliminated parameter,
+     * the value is identical to the key.
+     */
+    private final Object[] parameters;
+
+    /**
+     * The return node (if any) of the snippet.
+     */
+    private final ReturnNode returnNode;
+
+    /**
+     * The memory anchor (if any) of the snippet.
+     */
+    private final MemoryAnchorNode memoryAnchor;
+
+    /**
+     * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during
+     * instantiation.
+     */
+    private final ArrayList<StateSplit> sideEffectNodes;
+
+    /**
+     * Nodes that inherit a deoptimization {@link FrameState} from the replacee during
+     * instantiation.
+     */
+    private final ArrayList<DeoptimizingNode> deoptNodes;
+
+    /**
+     * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation.
+     */
+    private final ArrayList<ValueNode> stampNodes;
+
+    /**
+     * The nodes to be inlined when this specialization is instantiated.
+     */
+    private final ArrayList<Node> nodes;
+
+    /**
+     * Times instantiations of this template.
+     *
+     * @see SnippetInfo#instantiationTimer
+     */
+    private final DebugTimer instantiationTimer;
+
+    /**
+     * Counts instantiations of this template.
+     *
+     * @see SnippetInfo#instantiationCounter
+     */
+    private final DebugCounter instantiationCounter;
+
+    /**
+     * Gets the instantiation-time bindings to this template's parameters.
+     *
+     * @return the map that will be used to bind arguments to parameters when inlining this template
+     */
+    private Map<Node, Node> bind(StructuredGraph replaceeGraph, MetaAccessProvider metaAccess, Arguments args) {
+        Map<Node, Node> replacements = Node.newIdentityMap();
+        assert args.info.getParameterCount() == parameters.length : "number of args (" + args.info.getParameterCount() + ") != number of parameters (" + parameters.length + ")";
+        for (int i = 0; i < parameters.length; i++) {
+            Object parameter = parameters[i];
+            assert parameter != null : this + " has no parameter named " + args.info.getParameterName(i);
+            Object argument = args.values[i];
+            if (parameter instanceof ParameterNode) {
+                if (argument instanceof ValueNode) {
+                    replacements.put((ParameterNode) parameter, (ValueNode) argument);
+                } else {
+                    JavaKind kind = ((ParameterNode) parameter).getStackKind();
+                    assert argument != null || kind == JavaKind.Object : this + " cannot accept null for non-object parameter named " + args.info.getParameterName(i);
+                    JavaConstant constant = forBoxed(argument, kind);
+                    replacements.put((ParameterNode) parameter, ConstantNode.forConstant(constant, metaAccess, replaceeGraph));
+                }
+            } else if (parameter instanceof ParameterNode[]) {
+                ParameterNode[] params = (ParameterNode[]) parameter;
+                Varargs varargs = (Varargs) argument;
+                int length = params.length;
+                List<?> list = null;
+                Object array = null;
+                if (varargs.value instanceof List) {
+                    list = (List<?>) varargs.value;
+                    assert list.size() == length : length + " != " + list.size();
+                } else {
+                    array = varargs.value;
+                    assert array != null && array.getClass().isArray();
+                    assert Array.getLength(array) == length : length + " != " + Array.getLength(array);
+                }
+
+                for (int j = 0; j < length; j++) {
+                    ParameterNode param = params[j];
+                    assert param != null;
+                    Object value = list != null ? list.get(j) : Array.get(array, j);
+                    if (value instanceof ValueNode) {
+                        replacements.put(param, (ValueNode) value);
+                    } else {
+                        JavaConstant constant = forBoxed(value, param.getStackKind());
+                        ConstantNode element = ConstantNode.forConstant(constant, metaAccess, replaceeGraph);
+                        replacements.put(param, element);
+                    }
+                }
+            } else {
+                assert parameter.equals(CONSTANT_PARAMETER) || parameter.equals(UNUSED_PARAMETER) : "unexpected entry for parameter: " + args.info.getParameterName(i) + " -> " + parameter;
+            }
+        }
+        return replacements;
+    }
+
+    /**
+     * Converts a Java boxed value to a {@link JavaConstant} of the right kind. This adjusts for the
+     * limitation that a {@link Local}'s kind is a {@linkplain JavaKind#getStackKind() stack kind}
+     * and so cannot be used for re-boxing primitives smaller than an int.
+     *
+     * @param argument a Java boxed value
+     * @param localKind the kind of the {@link Local} to which {@code argument} will be bound
+     */
+    protected JavaConstant forBoxed(Object argument, JavaKind localKind) {
+        assert localKind == localKind.getStackKind();
+        if (localKind == JavaKind.Int) {
+            return JavaConstant.forBoxedPrimitive(argument);
+        }
+        return snippetReflection.forBoxed(localKind, argument);
+    }
+
+    /**
+     * Logic for replacing a snippet-lowered node at its usages with the return value of the
+     * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default}
+     * replacement logic can be used to handle mismatches between the stamp of the node being
+     * lowered and the stamp of the snippet's return value.
+     */
+    public interface UsageReplacer {
+        /**
+         * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}.
+         */
+        void replace(ValueNode oldNode, ValueNode newNode);
+    }
+
+    /**
+     * Represents the default {@link UsageReplacer usage replacer} logic which simply delegates to
+     * {@link Node#replaceAtUsages(Node)}.
+     */
+    public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() {
+
+        @Override
+        public void replace(ValueNode oldNode, ValueNode newNode) {
+            if (newNode == null) {
+                assert oldNode.hasNoUsages();
+            } else {
+                oldNode.replaceAtUsages(newNode);
+            }
+        }
+    };
+
+    private boolean assertSnippetKills(ValueNode replacee) {
+        if (!replacee.graph().isAfterFloatingReadPhase()) {
+            // no floating reads yet, ignore locations created while lowering
+            return true;
+        }
+        if (returnNode == null) {
+            // The snippet terminates control flow
+            return true;
+        }
+        MemoryMapNode memoryMap = returnNode.getMemoryMap();
+        if (memoryMap == null || memoryMap.isEmpty()) {
+            // there are no kills in the snippet graph
+            return true;
+        }
+
+        Set<LocationIdentity> kills = new HashSet<>(memoryMap.getLocations());
+
+        if (replacee instanceof MemoryCheckpoint.Single) {
+            // check if some node in snippet graph also kills the same location
+            LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity();
+            if (locationIdentity.isAny()) {
+                assert !(memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not";
+                // if the replacee kills ANY_LOCATION, the snippet can kill arbitrary locations
+                return true;
+            }
+            assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location";
+            kills.remove(locationIdentity);
+        }
+        assert !(replacee instanceof MemoryCheckpoint.Multi) : replacee + " multi not supported (yet)";
+
+        // remove ANY_LOCATION if it's just a kill by the start node
+        if (memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) {
+            kills.remove(any());
+        }
+
+        // node can only lower to a ANY_LOCATION kill if the replacee also kills ANY_LOCATION
+        assert !kills.contains(any()) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION.  kills: " + kills;
+
+        /*
+         * Kills to private locations are safe, since there can be no floating read to these
+         * locations except reads that are introduced by the snippet itself or related snippets in
+         * the same lowering round. These reads are anchored to a MemoryAnchor at the beginning of
+         * their snippet, so they can not float above a kill in another instance of the same
+         * snippet.
+         */
+        for (LocationIdentity p : this.info.privateLocations) {
+            kills.remove(p);
+        }
+
+        assert kills.isEmpty() : "snippet graph kills non-private locations " + Arrays.toString(kills.toArray()) + " that replacee (" + replacee + ") doesn't kill";
+        return true;
+    }
+
+    private static class MemoryInputMap implements MemoryMap {
+
+        private final LocationIdentity locationIdentity;
+        private final MemoryNode lastLocationAccess;
+
+        MemoryInputMap(ValueNode replacee) {
+            if (replacee instanceof MemoryAccess) {
+                MemoryAccess access = (MemoryAccess) replacee;
+                locationIdentity = access.getLocationIdentity();
+                lastLocationAccess = access.getLastLocationAccess();
+            } else {
+                locationIdentity = null;
+                lastLocationAccess = null;
+            }
+        }
+
+        @Override
+        public MemoryNode getLastLocationAccess(LocationIdentity location) {
+            if (locationIdentity != null && locationIdentity.equals(location)) {
+                return lastLocationAccess;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public Collection<LocationIdentity> getLocations() {
+            if (locationIdentity == null) {
+                return Collections.emptySet();
+            } else {
+                return Collections.singleton(locationIdentity);
+            }
+        }
+    }
+
+    private class MemoryOutputMap extends MemoryInputMap {
+
+        private final Map<Node, Node> duplicates;
+
+        MemoryOutputMap(ValueNode replacee, Map<Node, Node> duplicates) {
+            super(replacee);
+            this.duplicates = duplicates;
+        }
+
+        @Override
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+            MemoryMapNode memoryMap = returnNode.getMemoryMap();
+            assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
+            MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
+            assert lastLocationAccess != null : locationIdentity;
+            if (lastLocationAccess == memoryAnchor) {
+                return super.getLastLocationAccess(locationIdentity);
+            } else {
+                return (MemoryNode) duplicates.get(ValueNodeUtil.asNode(lastLocationAccess));
+            }
+        }
+
+        @Override
+        public Collection<LocationIdentity> getLocations() {
+            return returnNode.getMemoryMap().getLocations();
+        }
+    }
+
+    private void rewireMemoryGraph(ValueNode replacee, Map<Node, Node> duplicates) {
+        if (replacee.graph().isAfterFloatingReadPhase()) {
+            // rewire outgoing memory edges
+            replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates));
+
+            if (returnNode != null) {
+                ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
+                if (ret != null) {
+                    MemoryMapNode memoryMap = ret.getMemoryMap();
+                    if (memoryMap != null) {
+                        ret.setMemoryMap(null);
+                        memoryMap.safeDelete();
+                    }
+                }
+            }
+            if (memoryAnchor != null) {
+                // rewire incoming memory edges
+                MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor);
+                replaceMemoryUsages(memoryDuplicate, new MemoryInputMap(replacee));
+
+                if (memoryDuplicate.hasNoUsages()) {
+                    if (memoryDuplicate.next() != null) {
+                        memoryDuplicate.graph().removeFixed(memoryDuplicate);
+                    } else {
+                        // this was a dummy memory node used when instantiating pure data-flow
+                        // snippets: it was not attached to the control flow.
+                        memoryDuplicate.safeDelete();
+                    }
+                }
+            }
+        }
+    }
+
+    private static LocationIdentity getLocationIdentity(Node node) {
+        if (node instanceof MemoryAccess) {
+            return ((MemoryAccess) node).getLocationIdentity();
+        } else if (node instanceof MemoryProxy) {
+            return ((MemoryProxy) node).getLocationIdentity();
+        } else if (node instanceof MemoryPhiNode) {
+            return ((MemoryPhiNode) node).getLocationIdentity();
+        } else {
+            return null;
+        }
+    }
+
+    private void replaceMemoryUsages(ValueNode node, MemoryMap map) {
+        for (Node usage : node.usages().snapshot()) {
+            if (usage instanceof MemoryMapNode) {
+                continue;
+            }
+
+            LocationIdentity location = getLocationIdentity(usage);
+            if (location != null) {
+                for (Position pos : usage.inputPositions()) {
+                    if (pos.getInputType() == InputType.Memory && pos.get(usage) == node) {
+                        MemoryNode replacement = map.getLastLocationAccess(location);
+                        if (replacement == null) {
+                            assert mayRemoveLocation || LocationIdentity.any().equals(location) || Arrays.stream(info.privateLocations).anyMatch(Predicate.isEqual(location)) : "Snippet " +
+                                            info.method.format("%h.%n") + " contains access to the non-private location " + location + ", but replacee doesn't access this location." +
+                                            map.getLocations();
+                        } else {
+                            pos.set(usage, replacement.asNode());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Replaces a given fixed node with this specialized snippet.
+     *
+     * @param metaAccess
+     * @param replacee the node that will be replaced
+     * @param replacer object that replaces the usages of {@code replacee}
+     * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     * @return the map of duplicated nodes (original -&gt; duplicate)
+     */
+    @SuppressWarnings("try")
+    public Map<Node, Node> instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args) {
+        assert assertSnippetKills(replacee);
+        try (DebugCloseable a = args.info.instantiationTimer.start(); DebugCloseable b = instantiationTimer.start()) {
+            args.info.instantiationCounter.increment();
+            instantiationCounter.increment();
+            // Inline the snippet nodes, replacing parameters with the given args in the process
+            StartNode entryPointNode = snippet.start();
+            FixedNode firstCFGNode = entryPointNode.next();
+            StructuredGraph replaceeGraph = replacee.graph();
+            Map<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
+            replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee));
+            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+
+            // Re-wire the control flow graph around the replacee
+            FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+            replacee.replaceAtPredecessor(firstCFGNodeDuplicate);
+
+            rewireFrameStates(replacee, duplicates);
+
+            if (replacee instanceof DeoptimizingNode) {
+                DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee;
+
+                FrameState stateBefore = null;
+                FrameState stateDuring = null;
+                FrameState stateAfter = null;
+                if (replaceeDeopt.canDeoptimize()) {
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptBefore) {
+                        stateBefore = ((DeoptimizingNode.DeoptBefore) replaceeDeopt).stateBefore();
+                    }
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptDuring) {
+                        stateDuring = ((DeoptimizingNode.DeoptDuring) replaceeDeopt).stateDuring();
+                    }
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptAfter) {
+                        stateAfter = ((DeoptimizingNode.DeoptAfter) replaceeDeopt).stateAfter();
+                    }
+                }
+
+                for (DeoptimizingNode deoptNode : deoptNodes) {
+                    DeoptimizingNode deoptDup = (DeoptimizingNode) duplicates.get(deoptNode);
+                    if (deoptDup.canDeoptimize()) {
+                        if (deoptDup instanceof DeoptimizingNode.DeoptBefore) {
+                            ((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(stateBefore);
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptDuring) {
+                            DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup;
+                            if (stateDuring != null) {
+                                deoptDupDuring.setStateDuring(stateDuring);
+                            } else if (stateAfter != null) {
+                                deoptDupDuring.computeStateDuring(stateAfter);
+                            } else if (stateBefore != null) {
+                                assert !deoptDupDuring.hasSideEffect() : "can't use stateBefore as stateDuring for state split " + deoptDupDuring;
+                                deoptDupDuring.setStateDuring(stateBefore);
+                            }
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptAfter) {
+                            DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup;
+                            if (stateAfter != null) {
+                                deoptDupAfter.setStateAfter(stateAfter);
+                            } else {
+                                assert !deoptDupAfter.hasSideEffect() : "can't use stateBefore as stateAfter for state split " + deoptDupAfter;
+                                deoptDupAfter.setStateAfter(stateBefore);
+                            }
+
+                        }
+                    }
+                }
+            }
+
+            updateStamps(replacee, duplicates);
+
+            if (UseGraalInstrumentation.getValue()) {
+                for (InstrumentationNode instrumentation : replaceeGraph.getNodes().filter(InstrumentationNode.class)) {
+                    if (instrumentation.getTarget() == replacee) {
+                        instrumentation.replaceFirstInput(replacee, firstCFGNodeDuplicate);
+                    }
+                }
+            }
+
+            rewireMemoryGraph(replacee, duplicates);
+
+            // Replace all usages of the replacee with the value returned by the snippet
+            ValueNode returnValue = null;
+            if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
+                ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
+                returnValue = returnDuplicate.result();
+                if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) {
+                    replacer.replace(replacee, null);
+                } else {
+                    assert returnValue != null || replacee.hasNoUsages();
+                    replacer.replace(replacee, returnValue);
+                }
+                if (returnDuplicate.isAlive()) {
+                    FixedNode next = null;
+                    if (replacee instanceof FixedWithNextNode) {
+                        FixedWithNextNode fwn = (FixedWithNextNode) replacee;
+                        next = fwn.next();
+                        fwn.setNext(null);
+                    }
+                    returnDuplicate.replaceAndDelete(next);
+                }
+            }
+
+            // Remove the replacee from its graph
+            GraphUtil.killCFG(replacee);
+
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
+            return duplicates;
+        }
+    }
+
+    private void propagateStamp(Node node) {
+        if (node instanceof PhiNode) {
+            PhiNode phi = (PhiNode) node;
+            if (phi.inferStamp()) {
+                for (Node usage : node.usages()) {
+                    propagateStamp(usage);
+                }
+            }
+        }
+    }
+
+    private void updateStamps(ValueNode replacee, Map<Node, Node> duplicates) {
+        for (ValueNode stampNode : stampNodes) {
+            Node stampDup = duplicates.get(stampNode);
+            ((ValueNode) stampDup).setStamp(replacee.stamp());
+        }
+        for (ParameterNode paramNode : snippet.getNodes(ParameterNode.TYPE)) {
+            for (Node usage : paramNode.usages()) {
+                Node usageDup = duplicates.get(usage);
+                propagateStamp(usageDup);
+            }
+        }
+    }
+
+    /**
+     * Gets a copy of the specialized graph.
+     */
+    public StructuredGraph copySpecializedGraph() {
+        return (StructuredGraph) snippet.copy();
+    }
+
+    /**
+     * Replaces a given floating node with this specialized snippet.
+     *
+     * @param metaAccess
+     * @param replacee the node that will be replaced
+     * @param replacer object that replaces the usages of {@code replacee}
+     * @param tool lowering tool used to insert the snippet into the control-flow
+     * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     */
+    @SuppressWarnings("try")
+    public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) {
+        assert assertSnippetKills(replacee);
+        try (DebugCloseable a = args.info.instantiationTimer.start()) {
+            args.info.instantiationCounter.increment();
+            instantiationCounter.increment();
+
+            // Inline the snippet nodes, replacing parameters with the given args in the process
+            StartNode entryPointNode = snippet.start();
+            FixedNode firstCFGNode = entryPointNode.next();
+            StructuredGraph replaceeGraph = replacee.graph();
+            Map<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
+            replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode());
+            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+
+            FixedWithNextNode lastFixedNode = tool.lastFixedNode();
+            assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph + " lastFixed=" + lastFixedNode;
+            FixedNode next = lastFixedNode.next();
+            lastFixedNode.setNext(null);
+            FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+            replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate);
+
+            rewireFrameStates(replacee, duplicates);
+            updateStamps(replacee, duplicates);
+
+            rewireMemoryGraph(replacee, duplicates);
+
+            // Replace all usages of the replacee with the value returned by the snippet
+            ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
+            ValueNode returnValue = returnDuplicate.result();
+            assert returnValue != null || replacee.hasNoUsages();
+            replacer.replace(replacee, returnValue);
+
+            if (returnDuplicate.isAlive()) {
+                returnDuplicate.replaceAndDelete(next);
+            }
+
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
+        }
+    }
+
+    /**
+     * Replaces a given floating node with this specialized snippet.
+     *
+     * This snippet must be pure data-flow
+     *
+     * @param metaAccess
+     * @param replacee the node that will be replaced
+     * @param replacer object that replaces the usages of {@code replacee}
+     * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     */
+    @SuppressWarnings("try")
+    public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, Arguments args) {
+        assert assertSnippetKills(replacee);
+        try (DebugCloseable a = args.info.instantiationTimer.start()) {
+            args.info.instantiationCounter.increment();
+            instantiationCounter.increment();
+
+            // Inline the snippet nodes, replacing parameters with the given args in the process
+            StartNode entryPointNode = snippet.start();
+            assert entryPointNode.next() == (memoryAnchor == null ? returnNode : memoryAnchor) : entryPointNode.next();
+            StructuredGraph replaceeGraph = replacee.graph();
+            Map<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
+            MemoryAnchorNode anchorDuplicate = null;
+            if (memoryAnchor != null) {
+                anchorDuplicate = replaceeGraph.add(new MemoryAnchorNode());
+                replacements.put(memoryAnchor, anchorDuplicate);
+            }
+            List<Node> floatingNodes = new ArrayList<>(nodes.size() - 2);
+            for (Node n : nodes) {
+                if (n != entryPointNode && n != returnNode) {
+                    floatingNodes.add(n);
+                }
+            }
+            Map<Node, Node> duplicates = replaceeGraph.addDuplicates(floatingNodes, snippet, floatingNodes.size(), replacements);
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+
+            rewireFrameStates(replacee, duplicates);
+            updateStamps(replacee, duplicates);
+
+            rewireMemoryGraph(replacee, duplicates);
+            assert anchorDuplicate == null || anchorDuplicate.isDeleted();
+
+            // Replace all usages of the replacee with the value returned by the snippet
+            ValueNode returnValue = (ValueNode) duplicates.get(returnNode.result());
+            replacer.replace(replacee, returnValue);
+
+            Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
+        }
+    }
+
+    protected void rewireFrameStates(ValueNode replacee, Map<Node, Node> duplicates) {
+        if (replacee instanceof StateSplit) {
+            for (StateSplit sideEffectNode : sideEffectNodes) {
+                assert ((StateSplit) replacee).hasSideEffect();
+                Node sideEffectDup = duplicates.get(sideEffectNode);
+                ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter());
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(snippet.toString()).append('(');
+        String sep = "";
+        for (int i = 0; i < parameters.length; i++) {
+            String name = "[" + i + "]";
+            Object value = parameters[i];
+            buf.append(sep);
+            sep = ", ";
+            if (value == null) {
+                buf.append("<null> ").append(name);
+            } else if (value.equals(UNUSED_PARAMETER)) {
+                buf.append("<unused> ").append(name);
+            } else if (value.equals(CONSTANT_PARAMETER)) {
+                buf.append("<constant> ").append(name);
+            } else if (value instanceof ParameterNode) {
+                ParameterNode param = (ParameterNode) value;
+                buf.append(param.getStackKind().getJavaName()).append(' ').append(name);
+            } else {
+                ParameterNode[] params = (ParameterNode[]) value;
+                String kind = params.length == 0 ? "?" : params[0].getStackKind().getJavaName();
+                buf.append(kind).append('[').append(params.length).append("] ").append(name);
+            }
+        }
+        return buf.append(')').toString();
+    }
+
+    private static boolean checkTemplate(MetaAccessProvider metaAccess, Arguments args, ResolvedJavaMethod method, Signature signature) {
+        for (int i = 0; i < args.info.getParameterCount(); i++) {
+            if (args.info.isConstantParameter(i)) {
+                JavaKind kind = signature.getParameterKind(i);
+                assert checkConstantArgument(metaAccess, method, signature, i, args.info.getParameterName(i), args.values[i], kind);
+
+            } else if (args.info.isVarargsParameter(i)) {
+                assert args.values[i] instanceof Varargs;
+                Varargs varargs = (Varargs) args.values[i];
+                assert checkVarargs(metaAccess, method, signature, i, args.info.getParameterName(i), varargs);
+            }
+        }
+        return true;
+    }
+
+    public void setMayRemoveLocation(boolean mayRemoveLocation) {
+        this.mayRemoveLocation = mayRemoveLocation;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Snippets.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Snippets.java
new file mode 100644
index 0000000..445a96a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Snippets.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+
+/**
+ * Marker interface for a class that defines one or more {@link Snippet}s.
+ */
+public interface Snippets {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
new file mode 100644
index 0000000..8a45e45
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
+import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD;
+import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.UnsignedMath;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AbsNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.nodes.calc.RightShiftNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.SqrtNode;
+import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.debug.BindToRegisterNode;
+import org.graalvm.compiler.nodes.debug.BlackholeNode;
+import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
+import org.graalvm.compiler.nodes.debug.OpaqueNode;
+import org.graalvm.compiler.nodes.debug.SpillRegistersNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationBeginNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationEndNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.IsMethodInlinedNode;
+import org.graalvm.compiler.nodes.debug.instrumentation.RootNameNode;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
+import org.graalvm.compiler.nodes.extended.GetClassNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
+import org.graalvm.compiler.nodes.java.CompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
+import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode;
+import org.graalvm.compiler.replacements.nodes.ReverseBytesNode;
+import org.graalvm.compiler.replacements.nodes.VirtualizableInvokeMacroNode;
+import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactNode;
+import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode;
+import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import sun.misc.Unsafe;
+
+/**
+ * Provides non-runtime specific {@link InvocationPlugin}s.
+ */
+public class StandardGraphBuilderPlugins {
+
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider,
+                    boolean allowDeoptimization) {
+        registerObjectPlugins(plugins);
+        registerClassPlugins(plugins);
+        registerMathPlugins(plugins, allowDeoptimization);
+        registerUnsignedMathPlugins(plugins);
+        registerStringPlugins(plugins, bytecodeProvider, snippetReflection);
+        registerCharacterPlugins(plugins);
+        registerShortPlugins(plugins);
+        registerIntegerLongPlugins(plugins, JavaKind.Int);
+        registerIntegerLongPlugins(plugins, JavaKind.Long);
+        registerFloatPlugins(plugins);
+        registerDoublePlugins(plugins);
+        registerArraysPlugins(plugins, bytecodeProvider);
+        registerArrayPlugins(plugins, bytecodeProvider);
+        registerUnsafePlugins(plugins, bytecodeProvider);
+        registerEdgesPlugins(metaAccess, plugins);
+        registerGraalDirectivesPlugins(plugins);
+        registerBoxingPlugins(plugins);
+        registerJMHBlackholePlugins(plugins, bytecodeProvider);
+        registerJFRThrowablePlugins(plugins, bytecodeProvider);
+        registerMethodHandleImplPlugins(plugins, snippetReflection, bytecodeProvider);
+    }
+
+    private static final Field STRING_VALUE_FIELD;
+
+    static {
+        try {
+            STRING_VALUE_FIELD = String.class.getDeclaredField("value");
+        } catch (NoSuchFieldException e) {
+            throw new GraalError(e);
+        }
+    }
+
+    private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection) {
+        Registration r = new Registration(plugins, String.class, bytecodeProvider);
+        r.register1("hashCode", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                if (receiver.isConstant()) {
+                    String s = snippetReflection.asObject(String.class, (JavaConstant) receiver.get().asConstant());
+                    b.addPush(JavaKind.Int, b.add(ConstantNode.forInt(s.hashCode())));
+                    return true;
+                }
+                return false;
+            }
+        });
+        if (Java8OrEarlier) {
+            r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
+
+            r = new Registration(plugins, StringSubstitutions.class);
+            r.register1("getValue", String.class, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
+                    b.addPush(JavaKind.Object, LoadFieldNode.create(b.getAssumptions(), value, field));
+                    return true;
+                }
+            });
+        }
+    }
+
+    private static void registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Arrays.class, bytecodeProvider);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", boolean[].class, boolean[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", byte[].class, byte[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class);
+    }
+
+    private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Array.class, bytecodeProvider);
+        r.register2("newInstance", Class.class, int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) {
+                b.addPush(JavaKind.Object, new DynamicNewArrayNode(componentType, length, true));
+                return true;
+            }
+        });
+        r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class);
+    }
+
+    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r;
+        if (Java8OrEarlier) {
+            r = new Registration(plugins, Unsafe.class);
+        } else {
+            r = new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider);
+        }
+
+        for (JavaKind kind : JavaKind.values()) {
+            if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
+                Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+                String kindName = kind.name();
+                String getName = "get" + kindName;
+                String putName = "put" + kindName;
+                // Object-based accesses
+                r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, false));
+                r.register4(putName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false));
+                // Volatile object-based accesses
+                r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, true));
+                r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true));
+                // Ordered object-based accesses
+                if (Java8OrEarlier) {
+                    if (kind == JavaKind.Int || kind == JavaKind.Long || kind == JavaKind.Object) {
+                        r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true));
+                    }
+                } else {
+                    r.register4("put" + kindName + "Release", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true));
+                }
+                if (kind != JavaKind.Boolean && kind != JavaKind.Object) {
+                    // Raw accesses to memory addresses
+                    r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, false));
+                    r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, false));
+                }
+            }
+        }
+
+        // Accesses to native memory addresses.
+        r.register2("getAddress", Receiver.class, long.class, new UnsafeGetPlugin(JavaKind.Long, false));
+        r.register3("putAddress", Receiver.class, long.class, long.class, new UnsafePutPlugin(JavaKind.Long, false));
+
+        for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
+            Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+            r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
+                    // Emits a null-check for the otherwise unused receiver
+                    unsafe.get();
+                    b.addPush(JavaKind.Int, new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()));
+                    b.getGraph().markUnsafeAccess();
+                    return true;
+                }
+            });
+        }
+
+        r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode clazz) {
+                // Emits a null-check for the otherwise unused receiver
+                unsafe.get();
+                b.addPush(JavaKind.Object, new DynamicNewInstanceNode(clazz, true));
+                return true;
+            }
+
+        });
+
+        r.register1("loadFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | LOAD_STORE));
+        r.register1("storeFence", Receiver.class, new UnsafeFencePlugin(STORE_STORE | LOAD_STORE));
+        r.register1("fullFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | STORE_STORE | LOAD_STORE | STORE_LOAD));
+    }
+
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass);
+        r.register1("reverseBytes", type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null)));
+                return true;
+            }
+        });
+        r.register2("divideUnsigned", type, type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null)));
+                return true;
+            }
+        });
+        r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.recursiveAppend(new UnsignedRemNode(dividend, divisor).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerCharacterPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Character.class);
+        r.register1("reverseBytes", char.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                // return (char) (Integer.reverse(i) >> 16);
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
+                b.push(JavaKind.Char, b.recursiveAppend(charCast.canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerShortPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Short.class);
+        r.register1("reverseBytes", short.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                // return (short) (Integer.reverse(i) >> 16);
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
+                b.push(JavaKind.Short, b.recursiveAppend(charCast.canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerFloatPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Float.class);
+        r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Int, b.recursiveAppend(new ReinterpretNode(JavaKind.Int, value).canonical(null)));
+                return true;
+            }
+        });
+        r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Float, b.recursiveAppend(new ReinterpretNode(JavaKind.Float, value).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerDoublePlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Double.class);
+        r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Long, b.recursiveAppend(new ReinterpretNode(JavaKind.Long, value).canonical(null)));
+                return true;
+            }
+        });
+        r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Double, b.recursiveAppend(new ReinterpretNode(JavaKind.Double, value).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization) {
+        Registration r = new Registration(plugins, Math.class);
+        if (allowDeoptimization) {
+            for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) {
+                Class<?> type = kind.toJavaClass();
+                r.register2("addExact", type, type, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                        b.addPush(kind, new IntegerAddExactNode(x, y));
+                        return true;
+                    }
+                });
+                r.register2("subtractExact", type, type, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                        b.addPush(kind, new IntegerSubExactNode(x, y));
+                        return true;
+                    }
+                });
+                r.register2("multiplyExact", type, type, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                        b.addPush(kind, new IntegerMulExactNode(x, y));
+                        return true;
+                    }
+                });
+            }
+        }
+        r.register1("abs", Float.TYPE, new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Float, b.recursiveAppend(new AbsNode(value).canonical(null)));
+                return true;
+            }
+        });
+        r.register1("abs", Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Double, b.recursiveAppend(new AbsNode(value).canonical(null)));
+                return true;
+            }
+        });
+        r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(JavaKind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    public static class UnsignedMathPlugin implements InvocationPlugin {
+        private final Condition condition;
+
+        public UnsignedMathPlugin(Condition condition) {
+            this.condition = condition;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+            // the mirroring and negation operations get the condition into canonical form
+            boolean mirror = condition.canonicalMirror();
+            boolean negate = condition.canonicalNegate();
+            StructuredGraph graph = b.getGraph();
+
+            ValueNode lhs = mirror ? y : x;
+            ValueNode rhs = mirror ? x : y;
+
+            ValueNode trueValue = ConstantNode.forBoolean(!negate, graph);
+            ValueNode falseValue = ConstantNode.forBoolean(negate, graph);
+
+            Condition cond = mirror ? condition.mirror() : condition;
+            if (negate) {
+                cond = cond.negate();
+            }
+
+            LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection());
+            b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue));
+            return true;
+        }
+    }
+
+    private static void registerUnsignedMathPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, UnsignedMath.class);
+        r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT));
+        r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT));
+        r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT));
+        r.register2("belowThan", long.class, long.class, new UnsignedMathPlugin(Condition.BT));
+        r.register2("aboveOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.AE));
+        r.register2("aboveOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.AE));
+        r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE));
+        r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE));
+    }
+
+    protected static void registerBoxingPlugins(InvocationPlugins plugins) {
+        for (JavaKind kind : JavaKind.values()) {
+            if (kind.isPrimitive() && kind != JavaKind.Void) {
+                new BoxPlugin(kind).register(plugins);
+                new UnboxPlugin(kind).register(plugins);
+            }
+        }
+    }
+
+    private static void registerObjectPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                /*
+                 * Object.<init> is a common instrumentation point so only perform this rewrite if
+                 * the current definition is the normal empty method with a single return bytecode.
+                 * The finalizer registration will instead be performed by the BytecodeParser.
+                 */
+                if (targetMethod.getCodeSize() == 1) {
+                    ValueNode object = receiver.get();
+                    if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
+                        b.add(new RegisterFinalizerNode(object));
+                    }
+                    return true;
+                }
+                return false;
+            }
+        });
+        r.register1("getClass", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode object = receiver.get();
+                ValueNode folded = GetClassNode.tryFold(b.getMetaAccess(), b.getConstantReflection(), GraphUtil.originalValue(object));
+                if (folded != null) {
+                    b.addPush(JavaKind.Object, folded);
+                } else {
+                    Stamp stamp = StampFactory.objectNonNull(TypeReference.createTrusted(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Class.class)));
+                    b.addPush(JavaKind.Object, new GetClassNode(stamp, object));
+                }
+                return true;
+            }
+        });
+    }
+
+    private static void registerClassPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Class.class);
+        r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
+                LogicNode condition = b.recursiveAppend(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), type.get(), object, false));
+                b.push(JavaKind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                return true;
+            }
+        });
+        r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) {
+                ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType));
+                b.push(JavaKind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Substitutions for improving the performance of some critical methods in {@link Edges}. These
+     * substitutions improve the performance by forcing the relevant methods to be inlined
+     * (intrinsification being a special form of inlining) and removing a checked cast.
+     */
+    private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Edges.class);
+        for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
+            r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) {
+                    UnsafeLoadNode value = b.add(new UnsafeLoadNode(node, offset, JavaKind.Object, LocationIdentity.any()));
+                    value.setStamp(StampFactory.object(TypeReference.createTrusted(b.getAssumptions(), metaAccess.lookupJavaType(c))));
+                    b.addPush(JavaKind.Object, value);
+                    return true;
+                }
+            });
+            r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) {
+                    b.add(new UnsafeStoreNode(node, offset, value, JavaKind.Object, LocationIdentity.any()));
+                    return true;
+                }
+            });
+        }
+    }
+
+    public static class BoxPlugin implements InvocationPlugin {
+
+        private final JavaKind kind;
+
+        BoxPlugin(JavaKind kind) {
+            this.kind = kind;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+            if (b.parsingIntrinsic()) {
+                ResolvedJavaMethod rootMethod = b.getGraph().method();
+                if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
+                    // Disable invocation plugins for boxing snippets so that the
+                    // original JDK methods are inlined
+                    return false;
+                }
+            }
+            ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            b.addPush(JavaKind.Object, new BoxNode(value, resultType, kind));
+            return true;
+        }
+
+        void register(InvocationPlugins plugins) {
+            plugins.register(this, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+        }
+    }
+
+    public static class UnboxPlugin implements InvocationPlugin {
+
+        private final JavaKind kind;
+
+        UnboxPlugin(JavaKind kind) {
+            this.kind = kind;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+            if (b.parsingIntrinsic()) {
+                ResolvedJavaMethod rootMethod = b.getGraph().method();
+                if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
+                    // Disable invocation plugins for unboxing snippets so that the
+                    // original JDK methods are inlined
+                    return false;
+                }
+            }
+            ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind);
+            b.addPush(kind, valueNode);
+            return true;
+        }
+
+        void register(InvocationPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            plugins.register(this, kind.toBoxedJavaClass(), name, Receiver.class);
+        }
+    }
+
+    public static class UnsafeGetPlugin implements InvocationPlugin {
+
+        private final JavaKind returnKind;
+        private final boolean isVolatile;
+
+        public UnsafeGetPlugin(JavaKind returnKind, boolean isVolatile) {
+            this.returnKind = returnKind;
+            this.isVolatile = isVolatile;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
+            b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, LocationIdentity.any()));
+            b.getGraph().markUnsafeAccess();
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
+            if (isVolatile) {
+                b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            }
+            b.addPush(returnKind, new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()));
+            if (isVolatile) {
+                b.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            }
+            b.getGraph().markUnsafeAccess();
+            return true;
+        }
+    }
+
+    public static class UnsafePutPlugin implements InvocationPlugin {
+
+        private final JavaKind kind;
+        private final boolean isVolatile;
+
+        public UnsafePutPlugin(JavaKind kind, boolean isVolatile) {
+            this.kind = kind;
+            this.isVolatile = isVolatile;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
+            b.add(new UnsafeMemoryStoreNode(address, value, kind, LocationIdentity.any()));
+            b.getGraph().markUnsafeAccess();
+            return true;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
+            if (isVolatile) {
+                b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            }
+            b.add(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any()));
+            if (isVolatile) {
+                b.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            }
+            b.getGraph().markUnsafeAccess();
+            return true;
+        }
+    }
+
+    public static class UnsafeFencePlugin implements InvocationPlugin {
+
+        private final int barriers;
+
+        public UnsafeFencePlugin(int barriers) {
+            this.barriers = barriers;
+        }
+
+        @Override
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
+            b.add(new MembarNode(barriers));
+            return true;
+        }
+    }
+
+    private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, GraalDirectives.class);
+        r.register0("deoptimize", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
+                return true;
+            }
+        });
+
+        r.register0("controlFlowAnchor", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new ControlFlowAnchorNode());
+                return true;
+            }
+        });
+
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
+                b.addPush(JavaKind.Boolean, new BranchProbabilityNode(probability, condition));
+                return true;
+            }
+        });
+
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.add(new BlackholeNode(value));
+                return true;
+            }
+        };
+
+        InvocationPlugin bindToRegisterPlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.add(new BindToRegisterNode(value));
+                return true;
+            }
+        };
+        for (JavaKind kind : JavaKind.values()) {
+            if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
+                Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+                r.register1("blackhole", javaClass, blackholePlugin);
+                r.register1("bindToRegister", javaClass, bindToRegisterPlugin);
+
+                r.register1("opaque", javaClass, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                        b.addPush(kind, new OpaqueNode(value));
+                        return true;
+                    }
+                });
+            }
+        }
+
+        InvocationPlugin spillPlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new SpillRegistersNode());
+                return true;
+            }
+        };
+        r.register0("spillRegisters", spillPlugin);
+
+        r.register1("guardingNonNull", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                ObjectStamp objectStamp = (ObjectStamp) value.stamp();
+                if (objectStamp.nonNull()) {
+                    b.addPush(value.getStackKind(), value);
+                    return true;
+                } else if (objectStamp.alwaysNull()) {
+                    b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.NullCheckException));
+                    return true;
+                }
+                LogicNode isNull = b.add(IsNullNode.create(value));
+                FixedGuardNode fixedGuard = b.add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true));
+                Stamp newStamp = objectStamp.improveWith(StampFactory.objectNonNull());
+                b.addPush(value.getStackKind(), new PiNode(value, newStamp, fixedGuard));
+                return true;
+            }
+        });
+
+        r.register1("ensureVirtualized", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, false));
+                return true;
+            }
+        });
+        r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, true));
+                return true;
+            }
+        });
+        r.register0("isMethodInlined", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(JavaKind.Boolean, new IsMethodInlinedNode(b.getDepth()));
+                return true;
+            }
+        });
+        r.register0("rawRootName", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(JavaKind.Object, new RootNameNode(b.getInvokeReturnStamp(b.getAssumptions()).getTrustedStamp()));
+                return true;
+            }
+        });
+        r.register0("instrumentationBegin", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new InstrumentationBeginNode(true));
+                return true;
+            }
+        });
+        r.register0("instrumentationBeginForPredecessor", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new InstrumentationBeginNode(false));
+                return true;
+            }
+        });
+        r.register0("instrumentationEnd", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new InstrumentationEndNode());
+                return true;
+            }
+        });
+    }
+
+    private static void registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
+                blackhole.get();
+                b.add(new BlackholeNode(value));
+                return true;
+            }
+        };
+        String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
+        for (String name : names) {
+            Registration r = new Registration(plugins, name, bytecodeProvider);
+            for (JavaKind kind : JavaKind.values()) {
+                if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
+                    Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+                    r.register2("consume", Receiver.class, javaClass, blackholePlugin);
+                }
+            }
+            r.register2("consume", Receiver.class, Object[].class, blackholePlugin);
+        }
+    }
+
+    private static void registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer", bytecodeProvider);
+        r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
+                b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), throwable, message));
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
+    }
+
+    private static void registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, "java.lang.invoke.MethodHandleImpl", bytecodeProvider);
+        r.register2("profileBoolean", boolean.class, int[].class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode result, ValueNode counters) {
+                if (result.isConstant()) {
+                    b.push(JavaKind.Boolean, result);
+                    return true;
+                }
+                if (counters.isConstant()) {
+                    ValueNode newResult = result;
+                    int[] ctrs = snippetReflection.asObject(int[].class, (JavaConstant) counters.asConstant());
+                    if (ctrs != null && ctrs.length == 2) {
+                        int falseCount = ctrs[0];
+                        int trueCount = ctrs[1];
+                        int totalCount = trueCount + falseCount;
+
+                        if (totalCount == 0) {
+                            b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                        } else if (falseCount == 0 || trueCount == 0) {
+                            boolean expected = falseCount == 0 ? true : false;
+                            LogicNode condition = b.add(IntegerEqualsNode.create(result, b.add(ConstantNode.forBoolean(!expected)), /* constantReflection */ null));
+                            b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true));
+                            newResult = b.add(ConstantNode.forBoolean(expected));
+                        } else {
+                            // We cannot use BranchProbabilityNode here since there's no guarantee
+                            // the result of MethodHandleImpl.profileBoolean() is used as the
+                            // test in an `if` statement (as required by BranchProbabilityNode).
+                        }
+                    }
+                    b.addPush(JavaKind.Boolean, newResult);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java
new file mode 100644
index 0000000..b0d8b1a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link java.lang.String} methods.
+ */
+@ClassSubstitution(String.class)
+public class StringSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    @SuppressFBWarnings(value = "ES_COMPARING_PARAMETER_STRING_WITH_EQ", justification = "reference equality on the receiver is what we want")
+    public static boolean equals(final String thisString, Object obj) {
+        if (thisString == obj) {
+            return true;
+        }
+        if (!(obj instanceof String)) {
+            return false;
+        }
+        String thatString = (String) obj;
+        if (thisString.length() != thatString.length()) {
+            return false;
+        }
+        if (thisString.length() == 0) {
+            return true;
+        }
+
+        final char[] array1 = getValue(thisString);
+        final char[] array2 = getValue(thatString);
+
+        return ArrayEqualsNode.equals(array1, array2, array1.length);
+    }
+
+    /**
+     * Will be intrinsified with an {@link InvocationPlugin} to a {@link LoadFieldNode}.
+     */
+    private static native char[] getValue(String s);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/WordOperationPlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/WordOperationPlugin.java
new file mode 100644
index 0000000..43aa1cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/WordOperationPlugin.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.nodes.ConstantNode.forInt;
+import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind;
+
+import java.lang.reflect.Constructor;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.XorNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.extended.JavaReadNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+import org.graalvm.compiler.word.WordTypes;
+import org.graalvm.compiler.word.nodes.WordCastNode;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that
+ * need special handling for {@link Word} types.
+ */
+public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvokePlugin {
+    protected final WordTypes wordTypes;
+    protected final JavaKind wordKind;
+    protected final SnippetReflectionProvider snippetReflection;
+
+    public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+        this.snippetReflection = snippetReflection;
+        this.wordTypes = wordTypes;
+        this.wordKind = wordTypes.getWordKind();
+    }
+
+    @Override
+    public boolean canChangeStackKind(GraphBuilderContext b) {
+        return true;
+    }
+
+    /**
+     * Processes a call to a method if it is annotated with {@link Operation} by adding nodes to the
+     * graph being built that implement the denoted operation.
+     *
+     * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus
+     *         processed by this method)
+     */
+    @Override
+    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (!wordTypes.isWordOperation(method)) {
+            return false;
+        }
+        processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
+        return true;
+    }
+
+    @Override
+    public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
+        Stamp wordStamp = null;
+        if (declaredType instanceof ResolvedJavaType) {
+            ResolvedJavaType resolved = (ResolvedJavaType) declaredType;
+            if (wordTypes.isWord(resolved)) {
+                wordStamp = wordTypes.getWordStamp(resolved);
+            } else if (resolved.isArray() && wordTypes.isWord(resolved.getElementalType())) {
+                TypeReference trusted = TypeReference.createTrustedWithoutAssumptions(resolved);
+                wordStamp = StampFactory.object(trusted, nonNull);
+            }
+        }
+        if (wordStamp != null) {
+            return StampPair.createSingle(wordStamp);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (wordTypes.isWord(invoke.asNode())) {
+            invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode())));
+        }
+    }
+
+    @Override
+    public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
+        StampPair wordStamp = interceptType(b, field.getType(), false);
+        if (wordStamp != null) {
+            LoadFieldNode loadFieldNode = LoadFieldNode.createOverrideStamp(wordStamp, receiver, field);
+            b.addPush(field.getJavaKind(), loadFieldNode);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) {
+        return handleLoadField(b, null, staticField);
+    }
+
+    @Override
+    public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+        /*
+         * There are cases where the array does not have a known type yet, i.e., the type is null.
+         * In that case we assume it is not a word type.
+         */
+        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
+            assert elementKind == JavaKind.Object;
+            b.addPush(elementKind, createLoadIndexedNode(array, index));
+            return true;
+        }
+        return false;
+    }
+
+    protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
+        return new LoadIndexedNode(null, array, index, wordTypes.getWordKind());
+    }
+
+    @Override
+    public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
+        if (field.getJavaKind() == JavaKind.Object) {
+            boolean isWordField = wordTypes.isWord(field.getType());
+            boolean isWordValue = value.getStackKind() == wordTypes.getWordKind();
+
+            if (isWordField && !isWordValue) {
+                throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n"));
+            } else if (!isWordField && isWordValue) {
+                throw bailout(b, "Cannot store a word value into a non-word field: " + field.format("%H.%n"));
+            }
+        }
+
+        /* We never need to intercept the field store. */
+        return false;
+    }
+
+    @Override
+    public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
+        return handleStoreField(b, null, field, value);
+    }
+
+    @Override
+    public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
+            assert elementKind == JavaKind.Object;
+            if (value.getStackKind() != wordTypes.getWordKind()) {
+                throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true));
+            }
+            b.add(createStoreIndexedNode(array, index, value));
+            return true;
+        }
+        if (elementKind == JavaKind.Object && value.getStackKind() == wordTypes.getWordKind()) {
+            throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true));
+        }
+        return false;
+    }
+
+    protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) {
+        return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value);
+    }
+
+    @Override
+    public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (!wordTypes.isWord(type)) {
+            if (object.getStackKind() != JavaKind.Object) {
+                throw bailout(b, "Cannot cast a word value to a non-word type: " + type.toJavaName(true));
+            }
+            return false;
+        }
+
+        if (object.getStackKind() != wordTypes.getWordKind()) {
+            throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true));
+        }
+        b.push(JavaKind.Object, object);
+        return true;
+    }
+
+    @Override
+    public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (wordTypes.isWord(type)) {
+            throw bailout(b, "Cannot use instanceof for word a type: " + type.toJavaName(true));
+        } else if (object.getStackKind() != JavaKind.Object) {
+            throw bailout(b, "Cannot use instanceof on a word value: " + type.toJavaName(true));
+        }
+        return false;
+    }
+
+    protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError {
+        Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
+        JavaKind returnKind = wordMethod.getSignature().getReturnKind();
+        switch (operation.opcode()) {
+            case NODE_CLASS:
+                assert args.length == 2;
+                ValueNode left = args[0];
+                ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]);
+
+                b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
+                break;
+
+            case COMPARISON:
+                assert args.length == 2;
+                b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
+                break;
+
+            case NOT:
+                assert args.length == 1;
+                b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
+                break;
+
+            case READ_POINTER:
+            case READ_OBJECT:
+            case READ_BARRIERED: {
+                assert args.length == 2 || args.length == 3;
+                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                LocationIdentity location;
+                if (args.length == 2) {
+                    location = any();
+                } else {
+                    assert args[2].isConstant();
+                    location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant());
+                }
+                b.push(returnKind, readOp(b, readKind, address, location, operation.opcode()));
+                break;
+            }
+            case READ_HEAP: {
+                assert args.length == 3;
+                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
+                b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true));
+                break;
+            }
+            case WRITE_POINTER:
+            case WRITE_OBJECT:
+            case WRITE_BARRIERED:
+            case INITIALIZE: {
+                assert args.length == 3 || args.length == 4;
+                JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                LocationIdentity location;
+                if (args.length == 3) {
+                    location = any();
+                } else {
+                    assert args[3].isConstant();
+                    location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant());
+                }
+                writeOp(b, writeKind, address, location, args[2], operation.opcode());
+                break;
+            }
+            case ZERO:
+                assert args.length == 0;
+                b.addPush(returnKind, forIntegerKind(wordKind, 0L));
+                break;
+
+            case FROM_UNSIGNED:
+                assert args.length == 1;
+                b.push(returnKind, fromUnsigned(b, args[0]));
+                break;
+
+            case FROM_SIGNED:
+                assert args.length == 1;
+                b.push(returnKind, fromSigned(b, args[0]));
+                break;
+
+            case TO_RAW_VALUE:
+                assert args.length == 1;
+                b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long));
+                break;
+
+            case OBJECT_TO_TRACKED:
+                assert args.length == 1;
+                WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind));
+                b.push(returnKind, objectToTracked);
+                break;
+
+            case OBJECT_TO_UNTRACKED:
+                assert args.length == 1;
+                WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind));
+                b.push(returnKind, objectToUntracked);
+                break;
+
+            case FROM_ADDRESS:
+                assert args.length == 1;
+                WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind));
+                b.push(returnKind, addressToWord);
+                break;
+
+            case TO_OBJECT:
+                assert args.length == 1;
+                WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
+                b.push(returnKind, wordToObject);
+                break;
+
+            default:
+                throw new GraalError("Unknown opcode: %s", operation.opcode());
+        }
+    }
+
+    /**
+     * Create an instance of a binary node which is used to lower {@link Word} operations. This
+     * method is called for all {@link Word} operations which are annotated with @Operation(node =
+     * ...) and encapsulates the reflective allocation of the node.
+     */
+    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
+        try {
+            Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
+            return (ValueNode) cons.newInstance(left, right);
+        } catch (Throwable ex) {
+            throw new GraalError(ex).addContext(nodeClass.getName());
+        }
+    }
+
+    private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
+        assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
+
+        // mirroring gets the condition into canonical form
+        boolean mirror = condition.canonicalMirror();
+
+        ValueNode a = mirror ? right : left;
+        ValueNode b = mirror ? left : right;
+
+        CompareNode comparison;
+        if (condition == Condition.EQ || condition == Condition.NE) {
+            comparison = new IntegerEqualsNode(a, b);
+        } else if (condition.isUnsigned()) {
+            comparison = new IntegerBelowNode(a, b);
+        } else {
+            comparison = new IntegerLessThanNode(a, b);
+        }
+
+        ConstantNode trueValue = graph.add(forInt(1));
+        ConstantNode falseValue = graph.add(forInt(0));
+
+        if (condition.canonicalNegate()) {
+            ConstantNode temp = trueValue;
+            trueValue = falseValue;
+            falseValue = temp;
+        }
+        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
+        return materialize;
+    }
+
+    protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) {
+        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
+        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
+
+        return readOp(b, readKind, address, location, barrier, compressible);
+    }
+
+    public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) {
+        /*
+         * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float
+         * above an explicit zero check on its base address or any other test that ensures the read
+         * is safe.
+         */
+        JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible));
+        return read;
+    }
+
+    protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) {
+        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
+        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
+        final boolean initialize = (op == Opcode.INITIALIZE);
+        b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible, initialize));
+    }
+
+    public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) {
+        return b.add(new OffsetAddressNode(base, fromSigned(b, offset)));
+    }
+
+    public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, true);
+    }
+
+    public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, false);
+    }
+
+    public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) {
+        return convert(b, value, toKind, true);
+    }
+
+    public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) {
+        if (value.getStackKind() == toKind) {
+            return value;
+        }
+
+        if (toKind == JavaKind.Int) {
+            assert value.getStackKind() == JavaKind.Long;
+            return b.add(new NarrowNode(value, 32));
+        } else {
+            assert toKind == JavaKind.Long;
+            assert value.getStackKind() == JavaKind.Int;
+            if (unsigned) {
+                return b.add(new ZeroExtendNode(value, 64));
+            } else {
+                return b.add(new SignExtendNode(value, 64));
+            }
+        }
+    }
+
+    public WordTypes getWordTypes() {
+        return wordTypes;
+    }
+
+    private static BailoutException bailout(GraphBuilderContext b, String msg) {
+        throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java
new file mode 100644
index 0000000..ccccdbf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.classfile;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Container for objects representing the {@code Code} attributes parsed from a class file.
+ *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3">Code
+ *      attributes</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4">Constant
+ *      Pool</a>
+ */
+public class Classfile {
+
+    private final ResolvedJavaType type;
+    private final List<ClassfileBytecode> codeAttributes;
+
+    private static final int MAJOR_VERSION_JAVA7 = 51;
+    private static final int MAJOR_VERSION_JAVA9 = 53;
+
+    /**
+     * Creates a {@link Classfile} by parsing the class file bytes for {@code type} loadable from
+     * {@code context}.
+     *
+     * @throws NoClassDefFoundError if there is an IO error while parsing the class file
+     */
+    public Classfile(ResolvedJavaType type, DataInputStream stream, ClassfileBytecodeProvider context) throws IOException {
+        this.type = type;
+
+        // magic
+        int magic = stream.readInt();
+        assert magic == 0xCAFEBABE;
+
+        int minor = stream.readUnsignedShort();
+        int major = stream.readUnsignedShort();
+        if (major < MAJOR_VERSION_JAVA7 || major > MAJOR_VERSION_JAVA9) {
+            throw new UnsupportedClassVersionError("Unsupported class file version: " + major + "." + minor);
+        }
+
+        ClassfileConstantPool cp = new ClassfileConstantPool(stream, context);
+
+        // access_flags, this_class, super_class
+        skipFully(stream, 6);
+
+        // interfaces
+        skipFully(stream, stream.readUnsignedShort() * 2);
+
+        // fields
+        skipFields(stream);
+
+        // methods
+        codeAttributes = readMethods(stream, cp);
+
+        // attributes
+        skipAttributes(stream);
+    }
+
+    public ClassfileBytecode getCode(String name, String descriptor) {
+        for (ClassfileBytecode code : codeAttributes) {
+            ResolvedJavaMethod method = code.getMethod();
+            if (method.getName().equals(name) && method.getSignature().toMethodDescriptor().equals(descriptor)) {
+                return code;
+            }
+        }
+        throw new NoSuchMethodError(type.toJavaName() + "." + name + descriptor);
+    }
+
+    private static void skipAttributes(DataInputStream stream) throws IOException {
+        int attributesCount;
+        attributesCount = stream.readUnsignedShort();
+        for (int i = 0; i < attributesCount; i++) {
+            skipFully(stream, 2); // name_index
+            int attributeLength = stream.readInt();
+            skipFully(stream, attributeLength);
+        }
+    }
+
+    static void skipFully(DataInputStream stream, int n) throws IOException {
+        long skipped = 0;
+        do {
+            long s = stream.skip(n - skipped);
+            skipped += s;
+            if (s == 0 && skipped != n) {
+                // Check for EOF (i.e., truncated class file)
+                if (stream.read() == -1) {
+                    throw new IOException("truncated stream");
+                }
+                skipped++;
+            }
+        } while (skipped != n);
+    }
+
+    private ClassfileBytecode findCodeAttribute(DataInputStream stream, ClassfileConstantPool cp, String name, String descriptor, boolean isStatic) throws IOException {
+        int attributesCount;
+        attributesCount = stream.readUnsignedShort();
+        ClassfileBytecode code = null;
+        for (int i = 0; i < attributesCount; i++) {
+            String attributeName = cp.get(Utf8.class, stream.readUnsignedShort()).value;
+            int attributeLength = stream.readInt();
+            if (code == null && attributeName.equals("Code")) {
+                ResolvedJavaMethod method = ClassfileBytecodeProvider.findMethod(type, name, descriptor, isStatic);
+                // Even if we will discard the Code attribute (see below), we still
+                // need to parse it to reach the following class file content.
+                code = new ClassfileBytecode(method, stream, cp);
+                if (method == null) {
+                    // This is a method hidden from reflection
+                    // (see sun.reflect.Reflection.filterMethods)
+                    code = null;
+                }
+            } else {
+                skipFully(stream, attributeLength);
+            }
+        }
+        return code;
+    }
+
+    private static void skipFields(DataInputStream stream) throws IOException {
+        int count = stream.readUnsignedShort();
+        for (int i = 0; i < count; i++) {
+            skipFully(stream, 6); // access_flags, name_index, descriptor_index
+            skipAttributes(stream);
+        }
+    }
+
+    private List<ClassfileBytecode> readMethods(DataInputStream stream, ClassfileConstantPool cp) throws IOException {
+        int count = stream.readUnsignedShort();
+        List<ClassfileBytecode> result = new ArrayList<>(count);
+        for (int i = 0; i < count; i++) {
+            int accessFlags = stream.readUnsignedShort();
+            boolean isStatic = Modifier.isStatic(accessFlags);
+            String name = cp.get(Utf8.class, stream.readUnsignedShort()).value;
+            String descriptor = cp.get(Utf8.class, stream.readUnsignedShort()).value;
+            ClassfileBytecode code = findCodeAttribute(stream, cp, name, descriptor, isStatic);
+            if (code != null) {
+                result.add(code);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "<" + type.toJavaName() + ">";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java
new file mode 100644
index 0000000..402f885
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.classfile;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.instrument.Instrumentation;
+
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.ExceptionHandler;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.LineNumberTable;
+import jdk.vm.ci.meta.Local;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.ProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+/**
+ * The bytecode properties of a method as parsed directly from a class file without any
+ * {@linkplain Instrumentation instrumentation} or other rewriting performed on the bytecode.
+ */
+public class ClassfileBytecode implements Bytecode {
+
+    private static final int EXCEPTION_HANDLER_TABLE_SIZE_IN_BYTES = 8;
+    private static final int LINE_NUMBER_TABLE_ENTRY_SIZE_IN_BYTES = 4;
+    private static final int LOCAL_VARIABLE_TABLE_SIZE_IN_BYTES = 10;
+
+    private final ResolvedJavaMethod method;
+
+    private final ClassfileConstantPool constantPool;
+
+    private byte[] code;
+    private int maxLocals;
+    private int maxStack;
+
+    private byte[] exceptionTableBytes;
+    private byte[] lineNumberTableBytes;
+    private byte[] localVariableTableBytes;
+
+    public ClassfileBytecode(ResolvedJavaMethod method, DataInputStream stream, ClassfileConstantPool constantPool) throws IOException {
+        this.method = method;
+        this.constantPool = constantPool;
+        maxStack = stream.readUnsignedShort();
+        maxLocals = stream.readUnsignedShort();
+        int codeLength = stream.readInt();
+        code = new byte[codeLength];
+        stream.readFully(code);
+        int exceptionTableLength = stream.readUnsignedShort();
+        exceptionTableBytes = new byte[exceptionTableLength * EXCEPTION_HANDLER_TABLE_SIZE_IN_BYTES];
+        stream.readFully(exceptionTableBytes);
+        readCodeAttributes(stream);
+    }
+
+    private void readCodeAttributes(DataInputStream stream) throws IOException {
+        int count = stream.readUnsignedShort();
+        for (int i = 0; i < count; i++) {
+            String attributeName = constantPool.get(Utf8.class, stream.readUnsignedShort()).value;
+            int attributeLength = stream.readInt();
+            switch (attributeName) {
+                case "LocalVariableTable": {
+                    int length = stream.readUnsignedShort();
+                    localVariableTableBytes = new byte[length * LOCAL_VARIABLE_TABLE_SIZE_IN_BYTES];
+                    stream.readFully(localVariableTableBytes);
+                    break;
+                }
+                case "LineNumberTable": {
+                    int length = stream.readUnsignedShort();
+                    lineNumberTableBytes = new byte[length * LINE_NUMBER_TABLE_ENTRY_SIZE_IN_BYTES];
+                    stream.readFully(lineNumberTableBytes);
+                    break;
+                }
+                default: {
+                    Classfile.skipFully(stream, attributeLength);
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public byte[] getCode() {
+        return code;
+    }
+
+    @Override
+    public int getCodeSize() {
+        return code.length;
+    }
+
+    @Override
+    public int getMaxLocals() {
+        return maxLocals;
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return maxStack;
+    }
+
+    @Override
+    public ExceptionHandler[] getExceptionHandlers() {
+        if (exceptionTableBytes == null) {
+            return new ExceptionHandler[0];
+        }
+
+        final int exceptionTableLength = exceptionTableBytes.length / EXCEPTION_HANDLER_TABLE_SIZE_IN_BYTES;
+        ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength];
+        DataInputStream stream = new DataInputStream(new ByteArrayInputStream(exceptionTableBytes));
+
+        for (int i = 0; i < exceptionTableLength; i++) {
+            try {
+                final int startPc = stream.readUnsignedShort();
+                final int endPc = stream.readUnsignedShort();
+                final int handlerPc = stream.readUnsignedShort();
+                int catchTypeIndex = stream.readUnsignedShort();
+
+                JavaType catchType;
+                if (catchTypeIndex == 0) {
+                    catchType = null;
+                } else {
+                    final int opcode = -1;  // opcode is not used
+                    catchType = constantPool.lookupType(catchTypeIndex, opcode);
+
+                    // Check for Throwable which catches everything.
+                    if (catchType.toJavaName().equals("java.lang.Throwable")) {
+                        catchTypeIndex = 0;
+                        catchType = null;
+                    }
+                }
+                handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType);
+            } catch (IOException e) {
+                throw new GraalError(e);
+            }
+        }
+
+        return handlers;
+    }
+
+    @Override
+    public StackTraceElement asStackTraceElement(int bci) {
+        int line = getLineNumberTable().getLineNumber(bci);
+        return new StackTraceElement(method.getDeclaringClass().toJavaName(), method.getName(), method.getDeclaringClass().getSourceFileName(), line);
+    }
+
+    @Override
+    public ConstantPool getConstantPool() {
+        return constantPool;
+    }
+
+    @Override
+    public LineNumberTable getLineNumberTable() {
+        if (lineNumberTableBytes == null) {
+            return null;
+        }
+
+        final int lineNumberTableLength = lineNumberTableBytes.length / LINE_NUMBER_TABLE_ENTRY_SIZE_IN_BYTES;
+        DataInputStream stream = new DataInputStream(new ByteArrayInputStream(lineNumberTableBytes));
+        int[] bci = new int[lineNumberTableLength];
+        int[] line = new int[lineNumberTableLength];
+
+        for (int i = 0; i < lineNumberTableLength; i++) {
+            try {
+                bci[i] = stream.readUnsignedShort();
+                line[i] = stream.readUnsignedShort();
+            } catch (IOException e) {
+                throw new GraalError(e);
+            }
+        }
+
+        return new LineNumberTable(line, bci);
+    }
+
+    @Override
+    public LocalVariableTable getLocalVariableTable() {
+        if (localVariableTableBytes == null) {
+            return null;
+        }
+
+        final int localVariableTableLength = localVariableTableBytes.length / LOCAL_VARIABLE_TABLE_SIZE_IN_BYTES;
+        DataInputStream stream = new DataInputStream(new ByteArrayInputStream(localVariableTableBytes));
+        Local[] locals = new Local[localVariableTableLength];
+
+        for (int i = 0; i < localVariableTableLength; i++) {
+            try {
+                final int startBci = stream.readUnsignedShort();
+                final int endBci = startBci + stream.readUnsignedShort();
+                final int nameCpIndex = stream.readUnsignedShort();
+                final int typeCpIndex = stream.readUnsignedShort();
+                final int slot = stream.readUnsignedShort();
+
+                String localName = constantPool.lookupUtf8(nameCpIndex);
+                String localType = constantPool.lookupUtf8(typeCpIndex);
+
+                ClassfileBytecodeProvider context = constantPool.context;
+                Class<?> c = context.resolveToClass(localType);
+                locals[i] = new Local(localName, context.metaAccess.lookupJavaType(c), startBci, endBci, slot);
+            } catch (IOException e) {
+                throw new GraalError(e);
+            }
+        }
+
+        return new LocalVariableTable(locals);
+    }
+
+    @Override
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
+    @Override
+    public ProfilingInfo getProfilingInfo() {
+        return DefaultProfilingInfo.get(TriState.FALSE);
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + method.format("<%H.%n(%p)>");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
new file mode 100644
index 0000000..bbbc2ac
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.classfile;
+
+import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
+import static org.graalvm.compiler.core.common.util.ModuleAPI.getResourceAsStream;
+import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.instrument.Instrumentation;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A {@link BytecodeProvider} that provides bytecode properties of a {@link ResolvedJavaMethod} as
+ * parsed from a class file. This avoids all {@linkplain Instrumentation instrumentation} and any
+ * bytecode rewriting performed by the VM.
+ *
+ * This mechanism retrieves class files based on the name and {@link ClassLoader} of existing
+ * {@link Class} instances. It bypasses all VM parsing and verification of the class file and
+ * assumes the class files are well formed. As such, it should only be used for classes from a
+ * trusted source such as the boot class (or module) path.
+ *
+ * A combination of {@link Class#forName(String)} and an existing {@link MetaAccessProvider} is used
+ * to resolve constant pool references. This opens up the opportunity for linkage errors if the
+ * referee is structurally changed through redefinition (e.g., a referred to method is renamed or
+ * deleted). This will result in an appropriate {@link LinkageError} being thrown. The only way to
+ * avoid this is to have a completely isolated {@code jdk.vm.ci.meta} implementation for parsing
+ * snippet/intrinsic bytecodes.
+ */
+public final class ClassfileBytecodeProvider implements BytecodeProvider {
+
+    private final ClassLoader loader;
+    private final Map<Class<?>, Classfile> classfiles = new HashMap<>();
+    private final Map<String, Class<?>> classes = new HashMap<>();
+    final MetaAccessProvider metaAccess;
+    final SnippetReflectionProvider snippetReflection;
+
+    public ClassfileBytecodeProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection) {
+        this.metaAccess = metaAccess;
+        this.snippetReflection = snippetReflection;
+        ClassLoader cl = getClass().getClassLoader();
+        this.loader = cl == null ? ClassLoader.getSystemClassLoader() : cl;
+    }
+
+    @Override
+    public Bytecode getBytecode(ResolvedJavaMethod method) {
+        Classfile classfile = getClassfile(resolveToClass(method.getDeclaringClass().getName()));
+        return classfile.getCode(method.getName(), method.getSignature().toMethodDescriptor());
+    }
+
+    @Override
+    public boolean supportsInvokedynamic() {
+        return false;
+    }
+
+    @Override
+    public boolean shouldRecordMethodDependencies() {
+        return false;
+    }
+
+    private static InputStream getClassfileAsStream(Class<?> c) {
+        String classfilePath = c.getName().replace('.', '/') + ".class";
+        if (JAVA_SPECIFICATION_VERSION >= 9) {
+            Object module = getModule.invoke(c);
+            return getResourceAsStream.invoke(module, classfilePath);
+        } else {
+            ClassLoader cl = c.getClassLoader();
+            if (cl == null) {
+                return ClassLoader.getSystemResourceAsStream(classfilePath);
+            }
+            return cl.getResourceAsStream(classfilePath);
+        }
+    }
+
+    /**
+     * Gets a {@link Classfile} created by parsing the class file bytes for {@code c}.
+     *
+     * @throws NoClassDefFoundError if the class file cannot be found
+     */
+    private synchronized Classfile getClassfile(Class<?> c) {
+        assert !c.isPrimitive() && !c.isArray() : c;
+        Classfile classfile = classfiles.get(c);
+        if (classfile == null) {
+            try {
+                ResolvedJavaType type = metaAccess.lookupJavaType(c);
+                InputStream in = getClassfileAsStream(c);
+                if (in != null) {
+                    DataInputStream stream = new DataInputStream(in);
+                    classfile = new Classfile(type, stream, this);
+                    classfiles.put(c, classfile);
+                    return classfile;
+                }
+                throw new NoClassDefFoundError(c.getName());
+            } catch (IOException e) {
+                throw (NoClassDefFoundError) new NoClassDefFoundError(c.getName()).initCause(e);
+            }
+        }
+        return classfile;
+    }
+
+    synchronized Class<?> resolveToClass(String descriptor) {
+        Class<?> c = classes.get(descriptor);
+        if (c == null) {
+            if (descriptor.length() == 1) {
+                c = JavaKind.fromPrimitiveOrVoidTypeChar(descriptor.charAt(0)).toJavaClass();
+            } else {
+                int dimensions = 0;
+                while (descriptor.charAt(dimensions) == '[') {
+                    dimensions++;
+                }
+                String name;
+                if (dimensions == 0 && descriptor.startsWith("L") && descriptor.endsWith(";")) {
+                    name = descriptor.substring(1, descriptor.length() - 1).replace('/', '.');
+                } else {
+                    name = descriptor.replace('/', '.');
+                }
+                try {
+                    c = Class.forName(name, true, loader);
+                    classes.put(descriptor, c);
+                } catch (ClassNotFoundException e) {
+                    throw new NoClassDefFoundError(descriptor);
+                }
+            }
+        }
+        return c;
+    }
+
+    static ResolvedJavaMethod findMethod(ResolvedJavaType type, String name, String descriptor, boolean isStatic) {
+        if (isStatic && name.equals("<clinit>")) {
+            ResolvedJavaMethod method = type.getClassInitializer();
+            if (method != null) {
+                return method;
+            }
+        }
+        ResolvedJavaMethod[] methodsToSearch = name.equals("<init>") ? type.getDeclaredConstructors() : type.getDeclaredMethods();
+        for (ResolvedJavaMethod method : methodsToSearch) {
+            if (method.isStatic() == isStatic && method.getName().equals(name) && method.getSignature().toMethodDescriptor().equals(descriptor)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    static ResolvedJavaField findField(ResolvedJavaType type, String name, String fieldType, boolean isStatic) {
+        ResolvedJavaField[] fields = isStatic ? type.getStaticFields() : type.getInstanceFields(false);
+        for (ResolvedJavaField field : fields) {
+            if (field.getName().equals(name) && field.getType().getName().equals(fieldType)) {
+                return field;
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java
new file mode 100644
index 0000000..24da070
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.classfile;
+
+import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
+import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+abstract class ClassfileConstant {
+
+    // @formatter:off
+    public static final byte CONSTANT_Utf8               = 1;
+    public static final byte CONSTANT_Integer            = 3;
+    public static final byte CONSTANT_Float              = 4;
+    public static final byte CONSTANT_Long               = 5;
+    public static final byte CONSTANT_Double             = 6;
+    public static final byte CONSTANT_Class              = 7;
+    public static final byte CONSTANT_Fieldref           = 9;
+    public static final byte CONSTANT_String             = 8;
+    public static final byte CONSTANT_Methodref          = 10;
+    public static final byte CONSTANT_InterfaceMethodref = 11;
+    public static final byte CONSTANT_NameAndType        = 12;
+    public static final byte CONSTANT_MethodHandle       = 15;
+    public static final byte CONSTANT_MethodType         = 16;
+    public static final byte CONSTANT_InvokeDynamic      = 18;
+    // @formatter:on
+
+    final byte tag;
+
+    ClassfileConstant(byte tag) {
+        this.tag = tag;
+    }
+
+    /**
+     * Loads the type, if any, referenced at a specified entry.
+     *
+     * @param cp
+     * @param index
+     * @param opcode
+     */
+    public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    static class ClassRef extends ClassfileConstant {
+
+        final int nameIndex;
+        private ResolvedJavaType type;
+
+        ClassRef(DataInputStream stream) throws IOException {
+            super(CONSTANT_Class);
+            this.nameIndex = stream.readUnsignedShort();
+        }
+
+        @Override
+        public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
+            resolve(cp);
+        }
+
+        public ResolvedJavaType resolve(ClassfileConstantPool cp) throws GraalError {
+            if (type == null) {
+                String typeDescriptor = cp.get(Utf8.class, nameIndex).value;
+                ClassfileBytecodeProvider context = cp.context;
+                type = context.metaAccess.lookupJavaType(context.resolveToClass(typeDescriptor));
+            }
+            return type;
+        }
+    }
+
+    static class MemberRef extends ClassfileConstant {
+
+        final int classIndex;
+        final int nameAndTypeIndex;
+
+        MemberRef(byte tag, DataInputStream stream) throws IOException {
+            super(tag);
+            this.classIndex = stream.readUnsignedShort();
+            this.nameAndTypeIndex = stream.readUnsignedShort();
+        }
+
+        @Override
+        public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
+            cp.get(ClassRef.class, classIndex).loadReferencedType(cp, classIndex, opcode);
+        }
+    }
+
+    static class ExecutableRef extends MemberRef {
+        private ResolvedJavaMethod method;
+
+        ExecutableRef(byte tag, DataInputStream stream) throws IOException {
+            super(tag, stream);
+        }
+
+        ResolvedJavaMethod resolve(ClassfileConstantPool cp, int opcode) {
+            if (method == null) {
+                ResolvedJavaType cls = cp.get(ClassRef.class, classIndex).resolve(cp);
+                NameAndType nameAndType = cp.get(NameAndType.class, nameAndTypeIndex);
+                String name = nameAndType.getName(cp);
+                String type = nameAndType.getType(cp);
+
+                if (opcode == Bytecodes.INVOKEINTERFACE) {
+                    method = resolveMethod(cls, name, type, false);
+                    if (method == null) {
+                        throw new NoSuchMethodError(cls.toJavaName() + "." + name + type);
+                    }
+                    if (!method.isPublic() || !(method.getDeclaringClass().isInterface() || method.getDeclaringClass().isJavaLangObject())) {
+                        throw new IncompatibleClassChangeError("cannot invokeinterface " + method.format("%H.%n(%P)%R"));
+                    }
+                } else if (opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL) {
+                    method = resolveMethod(cls, name, type, false);
+                    if (method == null) {
+                        throw new NoSuchMethodError(cls.toJavaName() + "." + name + type);
+                    }
+                } else {
+                    assert opcode == Bytecodes.INVOKESTATIC;
+                    method = resolveMethod(cls, name, type, true);
+                    if (method == null) {
+                        throw new NoSuchMethodError(cls.toJavaName() + "." + name + type);
+                    }
+                }
+            }
+            return method;
+        }
+    }
+
+    static class MethodRef extends ExecutableRef {
+
+        MethodRef(DataInputStream stream) throws IOException {
+            super(CONSTANT_Methodref, stream);
+        }
+    }
+
+    static class InterfaceMethodRef extends ExecutableRef {
+        InterfaceMethodRef(DataInputStream stream) throws IOException {
+            super(CONSTANT_InterfaceMethodref, stream);
+        }
+    }
+
+    static class FieldRef extends MemberRef {
+        private ResolvedJavaField field;
+
+        FieldRef(DataInputStream stream) throws IOException {
+            super(CONSTANT_Fieldref, stream);
+        }
+
+        ResolvedJavaField resolve(ClassfileConstantPool cp, int opcode) {
+            if (field == null) {
+                ResolvedJavaType cls = cp.get(ClassRef.class, classIndex).resolve(cp);
+                NameAndType nameAndType = cp.get(NameAndType.class, nameAndTypeIndex);
+                String name = nameAndType.getName(cp);
+                String type = nameAndType.getType(cp);
+                assert opcode == GETFIELD || opcode == GETSTATIC || opcode == PUTFIELD || opcode == PUTSTATIC : opcode;
+                field = resolveField(cls, name, type, opcode == GETSTATIC || opcode == PUTSTATIC);
+                if (field == null) {
+                    throw new NoSuchFieldError(cls.toJavaName() + "." + name + " " + type);
+                }
+            }
+            return field;
+        }
+    }
+
+    static class Primitive extends ClassfileConstant {
+        final JavaConstant value;
+
+        Primitive(byte tag, JavaConstant value) {
+            super(tag);
+            this.value = value;
+        }
+    }
+
+    static class StringRef extends ClassfileConstant {
+
+        final int stringIndex;
+        JavaConstant value;
+
+        StringRef(DataInputStream stream) throws IOException {
+            super(ClassfileConstant.CONSTANT_String);
+            this.stringIndex = stream.readUnsignedShort();
+        }
+
+        JavaConstant getValue(ClassfileConstantPool pool) {
+            if (value == null) {
+                value = pool.context.snippetReflection.forObject(pool.lookupUtf8(stringIndex));
+            }
+            return value;
+        }
+    }
+
+    static class NameAndType extends ClassfileConstant {
+
+        final int nameIndex;
+        final int typeIndex;
+        private String name;
+        private String type;
+
+        NameAndType(DataInputStream stream) throws IOException {
+            super(ClassfileConstant.CONSTANT_NameAndType);
+            this.nameIndex = stream.readUnsignedShort();
+            this.typeIndex = stream.readUnsignedShort();
+        }
+
+        public String getName(ClassfileConstantPool cp) {
+            if (name == null) {
+                name = cp.get(Utf8.class, nameIndex).value;
+            }
+            return name;
+        }
+
+        public String getType(ClassfileConstantPool cp) {
+            if (type == null) {
+                type = cp.get(Utf8.class, typeIndex).value;
+            }
+            return type;
+        }
+    }
+
+    static class Utf8 extends ClassfileConstant {
+        final String value;
+
+        Utf8(String value) {
+            super(CONSTANT_Utf8);
+            this.value = value;
+        }
+    }
+
+    static class Unsupported extends ClassfileConstant {
+        final String name;
+
+        Unsupported(byte tag, String name) {
+            super(tag);
+            this.name = name;
+        }
+
+        @Override
+        public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
+            throw new GraalError("Resolution of " + name + " constant pool entries not supported by " + ClassfileBytecodeProvider.class.getSimpleName());
+        }
+    }
+
+    static ResolvedJavaMethod resolveMethod(ResolvedJavaType c, String name, String descriptor, boolean isStatic) {
+        ResolvedJavaMethod method = ClassfileBytecodeProvider.findMethod(c, name, descriptor, isStatic);
+        if (method != null) {
+            return method;
+        }
+        if (!c.isJavaLangObject() && !c.isInterface()) {
+            method = resolveMethod(c.getSuperclass(), name, descriptor, isStatic);
+            if (method != null) {
+                return method;
+            }
+        }
+        for (ResolvedJavaType i : c.getInterfaces()) {
+            method = resolveMethod(i, name, descriptor, isStatic);
+            if (method != null) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    static ResolvedJavaField resolveField(ResolvedJavaType c, String name, String fieldType, boolean isStatic) {
+        ResolvedJavaField field = ClassfileBytecodeProvider.findField(c, name, fieldType, isStatic);
+        if (field != null) {
+            return field;
+        }
+        if (!c.isJavaLangObject() && !c.isInterface()) {
+            field = resolveField(c.getSuperclass(), name, fieldType, isStatic);
+            if (field != null) {
+                return field;
+            }
+        }
+        for (ResolvedJavaType i : c.getInterfaces()) {
+            field = resolveField(i, name, fieldType, isStatic);
+            if (field != null) {
+                return field;
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java
new file mode 100644
index 0000000..aac1de4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.classfile;
+
+import static org.graalvm.compiler.replacements.classfile.Classfile.skipFully;
+import static org.graalvm.compiler.replacements.classfile.ClassfileConstant.CONSTANT_Class;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ClassRef;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ExecutableRef;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.FieldRef;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Primitive;
+import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8;
+
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaField;
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Signature;
+
+class ClassfileConstantPool implements ConstantPool {
+
+    final ClassfileConstant[] entries;
+    final ClassfileBytecodeProvider context;
+
+    public static class Bytecodes {
+        public static final int GETSTATIC = 178; // 0xB2
+        public static final int PUTSTATIC = 179; // 0xB3
+        public static final int GETFIELD = 180; // 0xB4
+        public static final int PUTFIELD = 181; // 0xB5
+        public static final int INVOKEVIRTUAL = 182; // 0xB6
+        public static final int INVOKESPECIAL = 183; // 0xB7
+        public static final int INVOKESTATIC = 184; // 0xB8
+        public static final int INVOKEINTERFACE = 185; // 0xB9
+        public static final int INVOKEDYNAMIC = 186; // 0xBA
+    }
+
+    ClassfileConstantPool(DataInputStream stream, ClassfileBytecodeProvider context) throws IOException {
+        this.context = context;
+        byte tag;
+
+        int count = stream.readUnsignedShort();
+        entries = new ClassfileConstant[count];
+
+        int i = 1;
+        while (i < count) {
+            entries[i] = readConstant(stream);
+            tag = entries[i].tag;
+
+            if ((tag == ClassfileConstant.CONSTANT_Double) || (tag == ClassfileConstant.CONSTANT_Long)) {
+                i += 2;
+            } else {
+                i += 1;
+            }
+        }
+    }
+
+    static final ClassfileConstant readConstant(DataInputStream stream) throws IOException {
+        byte tag = stream.readByte();
+
+        switch (tag) {
+            case ClassfileConstant.CONSTANT_Class:
+                return new ClassfileConstant.ClassRef(stream);
+            case ClassfileConstant.CONSTANT_Fieldref:
+                return new ClassfileConstant.FieldRef(stream);
+            case ClassfileConstant.CONSTANT_Methodref:
+                return new ClassfileConstant.MethodRef(stream);
+            case ClassfileConstant.CONSTANT_InterfaceMethodref:
+                return new ClassfileConstant.InterfaceMethodRef(stream);
+            case ClassfileConstant.CONSTANT_String:
+                return new ClassfileConstant.StringRef(stream);
+            case ClassfileConstant.CONSTANT_Integer:
+                return new ClassfileConstant.Primitive(tag, JavaConstant.forInt(stream.readInt()));
+            case ClassfileConstant.CONSTANT_Float:
+                return new ClassfileConstant.Primitive(tag, JavaConstant.forFloat(stream.readFloat()));
+            case ClassfileConstant.CONSTANT_Long:
+                return new ClassfileConstant.Primitive(tag, JavaConstant.forLong(stream.readLong()));
+            case ClassfileConstant.CONSTANT_Double:
+                return new ClassfileConstant.Primitive(tag, JavaConstant.forDouble(stream.readDouble()));
+            case ClassfileConstant.CONSTANT_NameAndType:
+                return new ClassfileConstant.NameAndType(stream);
+            case ClassfileConstant.CONSTANT_Utf8:
+                return new ClassfileConstant.Utf8(stream.readUTF());
+            case ClassfileConstant.CONSTANT_MethodHandle:
+                skipFully(stream, 3); // reference_kind, reference_index
+                return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodHandle_info");
+            case ClassfileConstant.CONSTANT_MethodType:
+                skipFully(stream, 2); // descriptor_index
+                return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodType_info");
+            case ClassfileConstant.CONSTANT_InvokeDynamic:
+                skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index
+                return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info");
+            default:
+                throw new GraalError("Invalid constant pool tag: " + tag);
+        }
+    }
+
+    @Override
+    public int length() {
+        return entries.length;
+    }
+
+    <T extends ClassfileConstant> T get(Class<T> c, int index) {
+        return c.cast(entries[index]);
+    }
+
+    @Override
+    public void loadReferencedType(int index, int opcode) {
+        if (opcode == Bytecodes.INVOKEDYNAMIC) {
+            throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName());
+        }
+        entries[index].loadReferencedType(this, index, opcode);
+    }
+
+    @Override
+    public JavaField lookupField(int index, ResolvedJavaMethod method, int opcode) {
+        return get(FieldRef.class, index).resolve(this, opcode);
+    }
+
+    @Override
+    public JavaMethod lookupMethod(int index, int opcode) {
+        if (opcode == Bytecodes.INVOKEDYNAMIC) {
+            throw new GraalError("INVOKEDYNAMIC not supported by" + ClassfileBytecodeProvider.class.getSimpleName());
+        }
+        return get(ExecutableRef.class, index).resolve(this, opcode);
+    }
+
+    @Override
+    public JavaType lookupType(int index, int opcode) {
+        return get(ClassRef.class, index).resolve(this);
+    }
+
+    @Override
+    public String lookupUtf8(int index) {
+        return ((Utf8) entries[index]).value;
+    }
+
+    @Override
+    public Signature lookupSignature(int index) {
+        throw GraalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Object lookupConstant(int index) {
+        ClassfileConstant c = entries[index];
+        if (c instanceof Primitive) {
+            Primitive p = (Primitive) c;
+            return p.value;
+        }
+        switch (c.tag) {
+            case CONSTANT_Class:
+                final int opcode = -1;
+                return lookupType(index, opcode);
+            case ClassfileConstant.CONSTANT_String:
+                return ((ClassfileConstant.StringRef) c).getValue(this);
+            default:
+                throw new GraalError("Unexpected constant pool tag %s", c.tag);
+        }
+    }
+
+    @Override
+    public JavaConstant lookupAppendix(int index, int opcode) {
+        if (opcode == Bytecodes.INVOKEVIRTUAL) {
+            return null;
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java
new file mode 100644
index 0000000..ef2d943
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+// JaCoCo Exclude
+
+/**
+ * Compares two arrays with the same length.
+ */
+@NodeInfo(cycles = CYCLES_100, size = SIZE_50)
+public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
+
+    public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
+    /** {@link JavaKind} of the arrays to compare. */
+    protected final JavaKind kind;
+
+    /** One array to be tested for equality. */
+    @Input ValueNode array1;
+
+    /** The other array to be tested for equality. */
+    @Input ValueNode array2;
+
+    /** Length of both arrays. */
+    @Input ValueNode length;
+
+    @OptionalInput(Memory) MemoryNode lastLocationAccess;
+
+    public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter JavaKind kind) {
+        super(TYPE, StampFactory.forKind(JavaKind.Boolean));
+        this.kind = kind;
+        this.array1 = array1;
+        this.array2 = array2;
+        this.length = length;
+    }
+
+    public ValueNode getArray1() {
+        return array1;
+    }
+
+    public ValueNode getArray2() {
+        return array2;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
+    private static boolean arrayEquals(ConstantReflectionProvider constantReflection, JavaConstant a, JavaConstant b, int len) {
+        for (int i = 0; i < len; i++) {
+            JavaConstant aElem = constantReflection.readArrayElement(a, i);
+            JavaConstant bElem = constantReflection.readArrayElement(b, i);
+            if (!constantReflection.constantEquals(aElem, bElem)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        }
+        ValueNode a1 = GraphUtil.unproxify(array1);
+        ValueNode a2 = GraphUtil.unproxify(array2);
+        if (a1 == a2) {
+            return ConstantNode.forBoolean(true);
+        }
+        if (a1.isConstant() && a2.isConstant() && length.isConstant()) {
+            ConstantNode c1 = (ConstantNode) a1;
+            ConstantNode c2 = (ConstantNode) a2;
+            if (c1.getStableDimension() >= 1 && c2.getStableDimension() >= 1) {
+                boolean ret = arrayEquals(tool.getConstantReflection(), c1.asJavaConstant(), c2.asJavaConstant(), length.asJavaConstant().asInt());
+                return ConstantNode.forBoolean(ret);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias1 = tool.getAlias(array1);
+        ValueNode alias2 = tool.getAlias(array2);
+        if (alias1 == alias2) {
+            // the same virtual objects will always have the same contents
+            tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+        } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) {
+            VirtualObjectNode virtual1 = (VirtualObjectNode) alias1;
+            VirtualObjectNode virtual2 = (VirtualObjectNode) alias2;
+
+            if (virtual1.entryCount() == virtual2.entryCount()) {
+                int entryCount = virtual1.entryCount();
+                boolean allEqual = true;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode entry1 = tool.getEntry(virtual1, i);
+                    ValueNode entry2 = tool.getEntry(virtual2, i);
+                    if (entry1 != entry2) {
+                        // the contents might be different
+                        allEqual = false;
+                    }
+                    if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
+                        // the contents are different
+                        tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
+                        return;
+                    }
+                }
+                if (allEqual) {
+                    tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+                }
+            }
+        }
+    }
+
+    @NodeIntrinsic
+    public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter JavaKind kind);
+
+    public static boolean equals(boolean[] array1, boolean[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Boolean);
+    }
+
+    public static boolean equals(byte[] array1, byte[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Byte);
+    }
+
+    public static boolean equals(char[] array1, char[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Char);
+    }
+
+    public static boolean equals(short[] array1, short[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Short);
+    }
+
+    public static boolean equals(int[] array1, int[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Int);
+    }
+
+    public static boolean equals(long[] array1, long[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Long);
+    }
+
+    public static boolean equals(float[] array1, float[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Float);
+    }
+
+    public static boolean equals(double[] array1, double[] array2, int length) {
+        return equals(array1, array2, length, JavaKind.Double);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length));
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return NamedLocationIdentity.getArrayLocation(kind);
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
+        lastLocationAccess = lla;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java
new file mode 100644
index 0000000..2a70ba9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Assertion nodes will go away as soon as the value evaluates to true. Compile-time assertions will
+ * fail if this has not happened by the time the node is lowered to LIR, while runtime assertions
+ * may need to insert a check.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class AssertionNode extends FixedWithNextNode implements Lowerable, Canonicalizable, LIRLowerable {
+
+    public static final NodeClass<AssertionNode> TYPE = NodeClass.create(AssertionNode.class);
+    @Input ValueNode value;
+
+    protected final boolean compileTimeAssertion;
+    protected final String message;
+
+    public AssertionNode(boolean compileTimeAssertion, ValueNode value, String message) {
+        super(TYPE, StampFactory.forVoid());
+        this.value = value;
+        this.compileTimeAssertion = compileTimeAssertion;
+        this.message = message;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value.isConstant() && value.asJavaConstant().asInt() != 0) {
+            return null;
+        }
+        /*
+         * Assertions with a constant "false" value do not immediately cause an error, since they
+         * may be unreachable and could thus be removed by later optimizations.
+         */
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (!compileTimeAssertion) {
+            tool.getLowerer().lower(this, tool);
+        }
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        assert compileTimeAssertion;
+        if (value.isConstant()) {
+            if (value.asJavaConstant().asInt() == 0) {
+                throw new GraalError("%s: failed compile-time assertion: %s", this, message);
+            }
+        } else {
+            throw new GraalError("%s: failed compile-time assertion (value %s): %s", this, value, message);
+        }
+    }
+
+    @NodeIntrinsic
+    public static native void assertion(@ConstantNodeParameter boolean compileTimeAssertion, boolean value, @ConstantNodeParameter String message);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java
new file mode 100644
index 0000000..7acefef
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_200;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo(cycles = CYCLES_200, size = SIZE_100)
+public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring {
+
+    public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
+
+    static final int SRC_ARG = 0;
+    static final int SRC_POS_ARG = 1;
+    static final int DEST_ARG = 2;
+    static final int DEST_POS_ARG = 3;
+    static final int LENGTH_ARG = 4;
+
+    @Input NodeInputList<ValueNode> args;
+
+    @OptionalInput(State) FrameState stateDuring;
+
+    @OptionalInput(Memory) protected MemoryNode lastLocationAccess;
+
+    protected JavaKind elementKind;
+
+    protected int bci;
+
+    public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) {
+        super(type, StampFactory.forKind(JavaKind.Void));
+        this.bci = bci;
+        args = new NodeInputList<>(this, new ValueNode[]{src, srcPos, dest, destPos, length});
+        this.elementKind = elementKind != JavaKind.Illegal ? elementKind : null;
+    }
+
+    public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
+        super(type, StampFactory.forKind(JavaKind.Void));
+        this.bci = -6;
+        args = new NodeInputList<>(this, new ValueNode[]{src, srcPos, dest, destPos, length});
+        this.elementKind = elementKind != JavaKind.Illegal ? elementKind : null;
+    }
+
+    public ValueNode getSource() {
+        return args.get(SRC_ARG);
+    }
+
+    public ValueNode getSourcePosition() {
+        return args.get(SRC_POS_ARG);
+    }
+
+    public ValueNode getDestination() {
+        return args.get(DEST_ARG);
+    }
+
+    public ValueNode getDestinationPosition() {
+        return args.get(DEST_POS_ARG);
+    }
+
+    public ValueNode getLength() {
+        return args.get(LENGTH_ARG);
+    }
+
+    public int getBci() {
+        return bci;
+    }
+
+    public JavaKind getElementKind() {
+        return elementKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (elementKind != null) {
+            return NamedLocationIdentity.getArrayLocation(elementKind);
+        }
+        return any();
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsagesInterface(lastLocationAccess, lla);
+        lastLocationAccess = lla;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) {
+        return position >= 0 && position + length <= virtualObject.entryCount();
+    }
+
+    private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) {
+        if (destComponentType.getJavaKind() == JavaKind.Object && !destComponentType.isJavaLangObject()) {
+            for (int i = 0; i < length; i++) {
+                ValueNode entry = tool.getEntry(src, srcPos + i);
+                ResolvedJavaType type = StampTool.typeOrNull(entry);
+                if (type == null || !destComponentType.isAssignableFrom(type)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays.
+     */
+    public boolean isExact() {
+        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
+        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
+        if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+            return false;
+        }
+        if ((srcType.getComponentType().getJavaKind().isPrimitive() && destType.getComponentType().equals(srcType.getComponentType())) || getSource() == getDestination()) {
+            return true;
+        }
+
+        if (StampTool.isExactType(getDestination().stamp())) {
+            if (destType != null && destType.isAssignableFrom(srcType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode sourcePosition = tool.getAlias(getSourcePosition());
+        ValueNode destinationPosition = tool.getAlias(getDestinationPosition());
+        ValueNode replacedLength = tool.getAlias(getLength());
+
+        if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) {
+            int srcPosInt = sourcePosition.asJavaConstant().asInt();
+            int destPosInt = destinationPosition.asJavaConstant().asInt();
+            int len = replacedLength.asJavaConstant().asInt();
+            ValueNode destAlias = tool.getAlias(getDestination());
+
+            if (destAlias instanceof VirtualArrayNode) {
+                VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias;
+                if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) {
+                    return;
+                }
+                ValueNode srcAlias = tool.getAlias(getSource());
+
+                if (srcAlias instanceof VirtualObjectNode) {
+                    if (!(srcAlias instanceof VirtualArrayNode)) {
+                        return;
+                    }
+                    VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias;
+                    if (destVirtual.componentType().getJavaKind() != JavaKind.Object) {
+                        return;
+                    }
+                    if (srcVirtual.componentType().getJavaKind() != JavaKind.Object) {
+                        return;
+                    }
+                    if (!checkBounds(srcPosInt, len, srcVirtual)) {
+                        return;
+                    }
+                    if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) {
+                        return;
+                    }
+                    for (int i = 0; i < len; i++) {
+                        tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false);
+                    }
+                    tool.delete();
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len);
+                    }
+                } else {
+                    ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias);
+                    if (sourceType == null || !sourceType.isArray()) {
+                        return;
+                    }
+                    ResolvedJavaType sourceComponentType = sourceType.getComponentType();
+                    ResolvedJavaType destComponentType = destVirtual.type().getComponentType();
+                    if (!sourceComponentType.equals(destComponentType)) {
+                        return;
+                    }
+                    for (int i = 0; i < len; i++) {
+                        LoadIndexedNode load = new LoadIndexedNode(graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getJavaKind());
+                        tool.addNode(load);
+                        tool.setVirtualEntry(destVirtual, destPosInt + i, load, false);
+                    }
+                    tool.delete();
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    @Override
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public void computeStateDuring(FrameState currentStateAfter) {
+        FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getStackKind());
+        setStateDuring(newStateDuring);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java
new file mode 100644
index 0000000..3d0314b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import java.util.Collections;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+@NodeInfo
+public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
+
+    public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
+
+    public BasicObjectCloneNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnStamp, arguments);
+        updateStamp(computeStamp(getObject()));
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(computeStamp(getObject()));
+    }
+
+    private static Stamp computeStamp(ValueNode object) {
+        Stamp objectStamp = object.stamp();
+        if (objectStamp instanceof ObjectStamp) {
+            objectStamp = objectStamp.join(StampFactory.objectNonNull());
+        }
+        return objectStamp;
+    }
+
+    public ValueNode getObject() {
+        return arguments.get(0);
+    }
+
+    /*
+     * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
+     * exact type) and if it is a cloneable type.
+     *
+     * If yes, then the exact type is returned, otherwise it returns null.
+     */
+    protected static ResolvedJavaType getConcreteType(Stamp stamp) {
+        if (!(stamp instanceof ObjectStamp)) {
+            return null;
+        }
+        ObjectStamp objectStamp = (ObjectStamp) stamp;
+        if (objectStamp.type() == null) {
+            return null;
+        } else if (objectStamp.isExactType()) {
+            return objectStamp.type().isCloneableWithAllocation() ? objectStamp.type() : null;
+        }
+        return null;
+    }
+
+    protected LoadFieldNode genLoadFieldNode(Assumptions assumptions, ValueNode originalAlias, ResolvedJavaField field) {
+        return LoadFieldNode.create(assumptions, originalAlias, field);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode originalAlias = tool.getAlias(getObject());
+        if (originalAlias instanceof VirtualObjectNode) {
+            VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias;
+            if (originalVirtual.type().isCloneableWithAllocation()) {
+                ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()];
+                for (int i = 0; i < newEntryState.length; i++) {
+                    newEntryState[i] = tool.getEntry(originalVirtual, i);
+                }
+                VirtualObjectNode newVirtual = originalVirtual.duplicate();
+                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false);
+                tool.replaceWithVirtual(newVirtual);
+            }
+        } else {
+            ResolvedJavaType type = getConcreteType(originalAlias.stamp());
+            if (type != null && !type.isArray()) {
+                VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true);
+                ResolvedJavaField[] fields = newVirtual.getFields();
+
+                ValueNode[] state = new ValueNode[fields.length];
+                final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
+                for (int i = 0; i < fields.length; i++) {
+                    state[i] = loads[i] = genLoadFieldNode(graph().getAssumptions(), originalAlias, fields[i]);
+                    tool.addNode(loads[i]);
+                }
+                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false);
+                tool.replaceWithVirtual(newVirtual);
+            }
+        }
+    }
+
+    protected VirtualInstanceNode createVirtualInstanceNode(ResolvedJavaType type, boolean hasIdentity) {
+        return new VirtualInstanceNode(type, hasIdentity);
+    }
+
+    @Override
+    public ValueNode length() {
+        return GraphUtil.arrayLength(getObject());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BinaryMathIntrinsicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BinaryMathIntrinsicNode.java
new file mode 100644
index 0000000..bff7c32
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BinaryMathIntrinsicNode.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.SqrtNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(nameTemplate = "MathIntrinsic#{p#operation/s}", cycles = CYCLES_UNKNOWN, size = SIZE_1)
+public final class BinaryMathIntrinsicNode extends BinaryNode implements ArithmeticLIRLowerable, Lowerable {
+
+    public static final NodeClass<BinaryMathIntrinsicNode> TYPE = NodeClass.create(BinaryMathIntrinsicNode.class);
+    protected final BinaryOperation operation;
+
+    public enum BinaryOperation {
+        POW(new ForeignCallDescriptor("arithmeticPow", double.class, double.class, double.class));
+
+        public final ForeignCallDescriptor foreignCallDescriptor;
+
+        BinaryOperation(ForeignCallDescriptor foreignCallDescriptor) {
+            this.foreignCallDescriptor = foreignCallDescriptor;
+        }
+    }
+
+    public BinaryOperation getOperation() {
+        return operation;
+    }
+
+    public static ValueNode create(ValueNode forX, ValueNode forY, BinaryOperation op) {
+        ValueNode c = tryConstantFold(forX, forY, op);
+        if (c != null) {
+            return c;
+        }
+        return new BinaryMathIntrinsicNode(forX, forY, op);
+    }
+
+    protected static ValueNode tryConstantFold(ValueNode forX, ValueNode forY, BinaryOperation op) {
+        if (forX.isConstant() && forY.isConstant()) {
+            double ret = doCompute(forX.asJavaConstant().asDouble(), forY.asJavaConstant().asDouble(), op);
+            return ConstantNode.forDouble(ret);
+        }
+        return null;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        return stamp();
+    }
+
+    protected BinaryMathIntrinsicNode(ValueNode forX, ValueNode forY, BinaryOperation op) {
+        super(TYPE, StampFactory.forKind(JavaKind.Double), forX, forY);
+        assert forX.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(forX.stamp()) == 64;
+        assert forY.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(forY.stamp()) == 64;
+        this.operation = op;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value xValue = nodeValueMap.operand(getX());
+        Value yValue = nodeValueMap.operand(getY());
+        Value result;
+        switch (getOperation()) {
+            case POW:
+                result = gen.emitMathPow(xValue, yValue);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        nodeValueMap.setResult(this, result);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode c = tryConstantFold(forX, forY, getOperation());
+        if (c != null) {
+            return c;
+        }
+        if (forY.isConstant()) {
+            double yValue = forY.asJavaConstant().asDouble();
+            // If the second argument is positive or negative zero, then the result is 1.0.
+            if (yValue == 0.0D) {
+                return ConstantNode.forDouble(1);
+            }
+
+            // If the second argument is 1.0, then the result is the same as the first argument.
+            if (yValue == 1.0D) {
+                return x;
+            }
+
+            // If the second argument is NaN, then the result is NaN.
+            if (Double.isNaN(yValue)) {
+                return ConstantNode.forDouble(Double.NaN);
+            }
+
+            // x**-1 = 1/x
+            if (yValue == -1.0D) {
+                return new DivNode(ConstantNode.forDouble(1), x);
+            }
+
+            // x**2 = x*x
+            if (yValue == 2.0D) {
+                return new MulNode(x, x);
+            }
+
+            // x**0.5 = sqrt(x)
+            if (yValue == 0.5D && x.stamp() instanceof FloatStamp && ((FloatStamp) x.stamp()).lowerBound() >= 0.0D) {
+                return new SqrtNode(x);
+            }
+        }
+        return this;
+    }
+
+    @NodeIntrinsic
+    public static native double compute(double x, double y, @ConstantNodeParameter BinaryOperation op);
+
+    private static double doCompute(double x, double y, BinaryOperation op) {
+        switch (op) {
+            case POW:
+                return Math.pow(x, y);
+            default:
+                throw new GraalError("unknown op %s", op);
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitCountNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitCountNode.java
new file mode 100644
index 0000000..da7fb4e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitCountNode.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class BitCountNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<BitCountNode> TYPE = NodeClass.create(BitCountNode.class);
+
+    public BitCountNode(ValueNode value) {
+        super(TYPE, computeStamp(value.stamp(), value), value);
+        assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        ValueNode theValue = getValue();
+        return computeStamp(newStamp, theValue);
+    }
+
+    static Stamp computeStamp(Stamp newStamp, ValueNode theValue) {
+        assert newStamp.isCompatible(theValue.stamp());
+        IntegerStamp valueStamp = (IntegerStamp) newStamp;
+        assert (valueStamp.downMask() & CodeUtil.mask(valueStamp.getBits())) == valueStamp.downMask();
+        assert (valueStamp.upMask() & CodeUtil.mask(valueStamp.getBits())) == valueStamp.upMask();
+        return StampFactory.forInteger(JavaKind.Int, Long.bitCount(valueStamp.downMask()), Long.bitCount(valueStamp.upMask()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            JavaConstant c = forValue.asJavaConstant();
+            return ConstantNode.forInt(forValue.getStackKind() == JavaKind.Int ? Integer.bitCount(c.asInt()) : Long.bitCount(c.asLong()));
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, gen.emitBitCount(builder.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java
new file mode 100644
index 0000000..5ed9fd4
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Determines the index of the least significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class BitScanForwardNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<BitScanForwardNode> TYPE = NodeClass.create(BitScanForwardNode.class);
+
+    public BitScanForwardNode(ValueNode value) {
+        super(TYPE, StampFactory.forInteger(JavaKind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        IntegerStamp valueStamp = (IntegerStamp) newStamp;
+        int min;
+        int max;
+        long mask = CodeUtil.mask(valueStamp.getBits());
+        int firstAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        int firstMaybeSetBit = scan(valueStamp.upMask() & mask);
+        if (firstAlwaysSetBit == -1) {
+            int lastMaybeSetBit = BitScanReverseNode.scan(valueStamp.upMask() & mask);
+            min = firstMaybeSetBit;
+            max = lastMaybeSetBit;
+        } else {
+            min = firstMaybeSetBit;
+            max = firstAlwaysSetBit;
+        }
+        return StampFactory.forInteger(JavaKind.Int, min, max);
+    }
+
+    public static ValueNode tryFold(ValueNode value) {
+        if (value.isConstant()) {
+            JavaConstant c = value.asJavaConstant();
+            if (c.asLong() != 0) {
+                return ConstantNode.forInt(value.getStackKind() == JavaKind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return number of trailing zeros or -1 if {@code v} == 0.
+     */
+    public static int scan(long v) {
+        if (v == 0) {
+            return -1;
+        }
+        return Long.numberOfTrailingZeros(v);
+    }
+
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return number of trailing zeros or -1 if {@code v} == 0.
+     */
+    public static int scan(int v) {
+        return scan(0xffffffffL & v);
+    }
+
+    /**
+     * Raw intrinsic for bsf instruction.
+     *
+     * @param v
+     * @return number of trailing zeros or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(long v);
+
+    /**
+     * Raw intrinsic for bsf instruction.
+     *
+     * @param v
+     * @return number of trailing zeros or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(int v);
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, gen.emitBitScanForward(builder.operand(getValue())));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java
new file mode 100644
index 0000000..b54aecb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Determines the index of the most significant "1" bit. Note that the result is undefined if the
+ * input is zero.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class BitScanReverseNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<BitScanReverseNode> TYPE = NodeClass.create(BitScanReverseNode.class);
+
+    public BitScanReverseNode(ValueNode value) {
+        super(TYPE, StampFactory.forInteger(JavaKind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getStackKind() == JavaKind.Int || value.getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        IntegerStamp valueStamp = (IntegerStamp) newStamp;
+        int min;
+        int max;
+        long mask = CodeUtil.mask(valueStamp.getBits());
+        int lastAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        if (lastAlwaysSetBit == -1) {
+            int firstMaybeSetBit = BitScanForwardNode.scan(valueStamp.upMask() & mask);
+            min = firstMaybeSetBit;
+        } else {
+            min = lastAlwaysSetBit;
+        }
+        int lastMaybeSetBit = scan(valueStamp.upMask() & mask);
+        max = lastMaybeSetBit;
+        return StampFactory.forInteger(JavaKind.Int, min, max);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            JavaConstant c = forValue.asJavaConstant();
+            if (c.asLong() != 0) {
+                return ConstantNode.forInt(forValue.getStackKind() == JavaKind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return index of first set bit or -1 if {@code v} == 0.
+     */
+    public static int scan(long v) {
+        return 63 - Long.numberOfLeadingZeros(v);
+    }
+
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return index of first set bit or -1 if {@code v} == 0.
+     */
+    public static int scan(int v) {
+        return 31 - Integer.numberOfLeadingZeros(v);
+    }
+
+    /**
+     * Raw intrinsic for bsr instruction.
+     *
+     * @param v
+     * @return index of first set bit or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(int v);
+
+    /**
+     * Raw intrinsic for bsr instruction.
+     *
+     * @param v
+     * @return index of first set bit or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(long v);
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, gen.emitBitScanReverse(builder.operand(getValue())));
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/CStringConstant.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/CStringConstant.java
new file mode 100644
index 0000000..7735d06
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/CStringConstant.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+import org.graalvm.compiler.core.common.type.DataPointerConstant;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Represents a compile-time constant zero-terminated UTF-8 string installed with the generated
+ * code.
+ */
+public final class CStringConstant extends DataPointerConstant {
+
+    private static final Charset UTF8 = Charset.forName("utf8");
+
+    private final String string;
+
+    public CStringConstant(String string) {
+        super(1);
+        assert string != null;
+        this.string = string;
+    }
+
+    @Override
+    public int getSerializedSize() {
+        return string.getBytes(UTF8).length + 1;
+    }
+
+    @Override
+    public void serialize(ByteBuffer buffer) {
+        byte[] bytes = string.getBytes(UTF8);
+        buffer.put(bytes);
+        buffer.put((byte) 0);
+    }
+
+    @Override
+    public String toValueString() {
+        return "c\"" + string + "\"";
+    }
+
+    public static boolean intrinsify(GraphBuilderContext b, @SuppressWarnings("unused") ResolvedJavaMethod targetMethod, String string) {
+        b.addPush(JavaKind.Object, new ConstantNode(new CStringConstant(string), StampFactory.pointer()));
+        return true;
+    }
+
+    @NodeIntrinsic
+    public static native Word cstring(@ConstantNodeParameter String string);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectObjectStoreNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectObjectStoreNode.java
new file mode 100644
index 0000000..87f117c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectObjectStoreNode.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a
+ * {@link StateSplit} and does not include a write barrier. Note that contrary to the sound of the
+ * name this node can be used for storing any kind.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<DirectObjectStoreNode> TYPE = NodeClass.create(DirectObjectStoreNode.class);
+    @Input ValueNode object;
+    @Input ValueNode value;
+    @Input ValueNode offset;
+    protected final int displacement;
+    protected final LocationIdentity locationIdentity;
+    protected final JavaKind storeKind;
+
+    public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value, LocationIdentity locationIdentity, JavaKind storeKind) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.value = value;
+        this.offset = offset;
+        this.displacement = displacement;
+        this.locationIdentity = locationIdentity;
+        this.storeKind = storeKind;
+    }
+
+    @NodeIntrinsic
+    public static native void storeObject(Object obj, @ConstantNodeParameter int displacement, long offset, Object value, @ConstantNodeParameter LocationIdentity locationIdentity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeBoolean(Object obj, @ConstantNodeParameter int displacement, long offset, boolean value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeByte(Object obj, @ConstantNodeParameter int displacement, long offset, byte value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeChar(Object obj, @ConstantNodeParameter int displacement, long offset, char value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeShort(Object obj, @ConstantNodeParameter int displacement, long offset, short value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeLong(Object obj, @ConstantNodeParameter int displacement, long offset, long value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeFloat(Object obj, @ConstantNodeParameter int displacement, long offset, float value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @NodeIntrinsic
+    public static native void storeDouble(Object obj, @ConstantNodeParameter int displacement, long offset, double value, @ConstantNodeParameter LocationIdentity locationIdenity,
+                    @ConstantNodeParameter JavaKind storeKind);
+
+    @Override
+    public void lower(LoweringTool tool) {
+        ValueNode off = graph().unique(new AddNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), displacement, graph())));
+        AddressNode address = graph().unique(new OffsetAddressNode(object, off));
+        JavaWriteNode write = graph().add(new JavaWriteNode(storeKind, address, locationIdentity, value, BarrierType.NONE, storeKind == JavaKind.Object, false));
+        graph().replaceFixedWithFixed(this, write);
+
+        tool.getLowerer().lower(write, tool);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java
new file mode 100644
index 0000000..bbdae1b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a
+ * {@link StateSplit} and takes a computed address instead of an object.
+ */
+@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+public final class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<DirectStoreNode> TYPE = NodeClass.create(DirectStoreNode.class);
+    @Input protected ValueNode address;
+    @Input protected ValueNode value;
+    protected final JavaKind kind;
+
+    public DirectStoreNode(ValueNode address, ValueNode value, JavaKind kind) {
+        super(TYPE, StampFactory.forVoid());
+        this.address = address;
+        this.value = value;
+        this.kind = kind;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value v = gen.operand(value);
+        LIRKind lirKind = LIRKind.fromJavaKind(gen.getLIRGeneratorTool().target().arch, kind);
+        gen.getLIRGeneratorTool().getArithmetic().emitStore(lirKind, gen.operand(address), v, null);
+    }
+
+    public ValueNode getAddress() {
+        return address;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @NodeIntrinsic
+    public static native void storeBoolean(long address, boolean value, @ConstantNodeParameter JavaKind kind);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java
new file mode 100644
index 0000000..281d135
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+
+/**
+ * Placeholder node to denote to snippet preparation that the following loop must be completely
+ * unrolled.
+ *
+ * @see VarargsParameter
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class ExplodeLoopNode extends FixedWithNextNode {
+    public static final NodeClass<ExplodeLoopNode> TYPE = NodeClass.create(ExplodeLoopNode.class);
+
+    public ExplodeLoopNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public LoopBeginNode findLoopBegin() {
+        Node currentNext = next();
+        ArrayList<Node> succs = new ArrayList<>();
+        while (!(currentNext instanceof LoopBeginNode)) {
+            assert currentNext != null : "cannot find loop after " + this;
+            for (Node n : currentNext.cfgSuccessors()) {
+                succs.add(n);
+            }
+            if (succs.size() == 1) {
+                currentNext = succs.get(0);
+            } else {
+                return null;
+            }
+        }
+        return (LoopBeginNode) currentNext;
+    }
+
+    /**
+     * A call to this method must be placed immediately prior to the loop that is to be exploded.
+     */
+    @NodeIntrinsic
+    public static native void explodeLoop();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/LoadSnippetVarargParameterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/LoadSnippetVarargParameterNode.java
new file mode 100644
index 0000000..95d4c2c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/LoadSnippetVarargParameterNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+/**
+ * Implements the semantics of {@link VarargsParameter}.
+ */
+@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable {
+
+    public static final NodeClass<LoadSnippetVarargParameterNode> TYPE = NodeClass.create(LoadSnippetVarargParameterNode.class);
+    @Input ValueNode index;
+
+    @Input NodeInputList<ParameterNode> parameters;
+
+    public LoadSnippetVarargParameterNode(ParameterNode[] locals, ValueNode index, Stamp stamp) {
+        super(TYPE, stamp);
+        this.index = index;
+        this.parameters = new NodeInputList<>(this, locals);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (index.isConstant()) {
+            int indexValue = index.asJavaConstant().asInt();
+            if (indexValue < parameters.size()) {
+                return parameters.get(indexValue);
+            }
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java
new file mode 100644
index 0000000..a54e2bd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Macro nodes can be used to temporarily replace an invoke. They can, for example, be used to
+ * implement constant folding for known JDK functions like {@link Class#isInterface()}.<br/>
+ * <br/>
+ * During lowering, multiple sources are queried in order to look for a replacement:
+ * <ul>
+ * <li>If {@link #getLoweredSnippetGraph(LoweringTool)} returns a non-null result, this graph is
+ * used as a replacement.</li>
+ * <li>If a {@link MethodSubstitution} for the target method is found, this substitution is used as
+ * a replacement.</li>
+ * <li>Otherwise, the macro node is replaced with an {@link InvokeNode}. Note that this is only
+ * possible if the macro node is a {@link MacroStateSplitNode}.</li>
+ * </ul>
+ */
+//@formatter:off
+@NodeInfo(cycles = CYCLES_UNKNOWN,
+          cyclesRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate",
+          size = SIZE_UNKNOWN,
+          sizeRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate")
+//@formatter:on
+public abstract class MacroNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<MacroNode> TYPE = NodeClass.create(MacroNode.class);
+    @Input protected NodeInputList<ValueNode> arguments;
+
+    protected final int bci;
+    protected final ResolvedJavaMethod targetMethod;
+    protected final StampPair returnStamp;
+    protected final InvokeKind invokeKind;
+
+    protected MacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(c, returnStamp.getTrustedStamp());
+        assert targetMethod.getSignature().getParameterCount(!targetMethod.isStatic()) == arguments.length;
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.bci = bci;
+        this.targetMethod = targetMethod;
+        this.returnStamp = returnStamp;
+        this.invokeKind = invokeKind;
+        assert !isPlaceholderBci(bci);
+    }
+
+    public int getBci() {
+        return bci;
+    }
+
+    public ResolvedJavaMethod getTargetMethod() {
+        return targetMethod;
+    }
+
+    protected FrameState stateAfter() {
+        return null;
+    }
+
+    /**
+     * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must
+     * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}.
+     */
+    @SuppressWarnings("unused")
+    protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) {
+        return null;
+    }
+
+    /**
+     * Applies {@linkplain LoweringPhase lowering} to a replacement graph.
+     *
+     * @param replacementGraph a replacement (i.e., snippet or method substitution) graph
+     */
+    @SuppressWarnings("try")
+    protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
+        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getConstantFieldProvider(), tool.getLowerer(), tool.getReplacements(),
+                        tool.getStampProvider(), tool.getNodeCostProvider());
+        if (!graph().hasValueProxies()) {
+            new RemoveValueProxyPhase().apply(replacementGraph);
+        }
+        GuardsStage guardsStage = graph().getGuardsStage();
+        if (!guardsStage.allowsFloatingGuards()) {
+            new GuardLoweringPhase().apply(replacementGraph, null);
+            if (guardsStage.areFrameStatesAtDeopts()) {
+                new FrameStateAssignmentPhase().apply(replacementGraph);
+            }
+        }
+        try (Scope s = Debug.scope("LoweringSnippetTemplate", replacementGraph)) {
+            new LoweringPhase(new CanonicalizerPhase(), tool.getLoweringStage()).apply(replacementGraph, c);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return replacementGraph;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        StructuredGraph replacementGraph = getLoweredSnippetGraph(tool);
+
+        InvokeNode invoke = replaceWithInvoke();
+        assert invoke.verify();
+
+        if (replacementGraph != null) {
+            // Pull out the receiver null check so that a replaced
+            // receiver can be lowered if necessary
+            if (!targetMethod.isStatic()) {
+                ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+                if (nonNullReceiver instanceof Lowerable) {
+                    ((Lowerable) nonNullReceiver).lower(tool);
+                }
+            }
+            InliningUtil.inline(invoke, replacementGraph, false, null, targetMethod);
+            Debug.dump(Debug.INFO_LOG_LEVEL, graph(), "After inlining replacement %s", replacementGraph);
+        } else {
+            if (isPlaceholderBci(invoke.bci())) {
+                throw new GraalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this);
+            }
+
+            if (invoke.stateAfter() == null) {
+                ResolvedJavaMethod method = graph().method();
+                if (method.getAnnotation(MethodSubstitution.class) != null || method.getAnnotation(Snippet.class) != null) {
+                    // One cause for this is that a MacroNode is created for a method that
+                    // no longer needs a MacroNode. For example, Class.getComponentType()
+                    // only needs a MacroNode prior to JDK9 as it was given a non-native
+                    // implementation in JDK9.
+                    throw new GraalError("%s macro created for call to %s in %s must be lowerable to a snippet or intrinsic graph. " +
+                                    "Maybe a macro node is not needed for this method in the current JDK?", getClass().getSimpleName(), targetMethod.format("%h.%n(%p)"), graph());
+                }
+                throw new GraalError("%s: cannot lower to invoke without state: %s", graph(), this);
+            }
+            invoke.lower(tool);
+        }
+    }
+
+    protected InvokeNode replaceWithInvoke() {
+        InvokeNode invoke = createInvoke();
+        graph().replaceFixedWithFixed(this, invoke);
+        return invoke;
+    }
+
+    protected InvokeNode createInvoke() {
+        MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnStamp, null));
+        InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci));
+        if (stateAfter() != null) {
+            invoke.setStateAfter(stateAfter().duplicate());
+            if (getStackKind() != JavaKind.Void) {
+                invoke.stateAfter().replaceFirstInput(this, invoke);
+            }
+        }
+        return invoke;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java
new file mode 100644
index 0000000..fc50ca9
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.StateSplit;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a
+ * {@link MemoryCheckpoint}.
+ */
+@NodeInfo
+public abstract class MacroStateSplitNode extends MacroNode implements StateSplit, MemoryCheckpoint.Single {
+
+    public static final NodeClass<MacroStateSplitNode> TYPE = NodeClass.create(MacroStateSplitNode.class);
+    @OptionalInput(InputType.State) protected FrameState stateAfter;
+
+    protected MacroStateSplitNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnStamp, arguments);
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    @Override
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
+        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.TYPE)) {
+            Invoke invoke = call.invoke();
+            if (!call.targetMethod().equals(getTargetMethod())) {
+                throw new GraalError("unexpected invoke %s in snippet", getClass().getSimpleName());
+            }
+            assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
+            // Here we need to fix the bci of the invoke
+            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
+            newInvoke.setStateAfter(invoke.stateAfter());
+            snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java
new file mode 100644
index 0000000..b8bb2c5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import java.lang.invoke.MethodHandle;
+import java.util.Arrays;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Assumptions.AssumptionResult;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MethodHandleAccessProvider;
+import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
+    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
+
+    protected final IntrinsicMethod intrinsicMethod;
+
+    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments);
+        this.intrinsicMethod = intrinsicMethod;
+    }
+
+    /**
+     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
+     * invocation on another method with possibly transformed arguments.
+     *
+     * @param assumptions object for recording any speculations made during the transformation
+     * @param methodHandleAccess objects for accessing the implementation internals of a
+     *            {@link MethodHandle}
+     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
+     * @param bci the BCI of the original {@link MethodHandle} call
+     * @param returnStamp return stamp of the original {@link MethodHandle} call
+     * @param arguments arguments to the original {@link MethodHandle} call
+     * @return a more direct invocation derived from the {@link MethodHandle} call or null
+     */
+    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
+                    StampPair returnStamp, ValueNode... arguments) {
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnStamp, arguments);
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnStamp, arguments);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
+        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
+        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnStamp, argumentsArray);
+        if (invoke != null) {
+            assert invoke.graph() == null;
+            invoke = graph().addOrUniqueWithInputs(invoke);
+            invoke.setStateAfter(stateAfter());
+            FixedNode currentNext = next();
+            replaceAtUsages(invoke);
+            GraphUtil.removeFixedWithUnusedInputs(this);
+            graph().addBeforeFixed(currentNext, invoke);
+        }
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     *
+     * @return the receiver argument node
+     */
+    private static ValueNode getReceiver(ValueNode[] arguments) {
+        return arguments[0];
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     *
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private static ValueNode getMemberName(ValueNode[] arguments) {
+        return arguments[arguments.length - 1];
+    }
+
+    /**
+     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+     *
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    StampPair returnStamp, ValueNode[] arguments) {
+        ValueNode methodHandleNode = getReceiver(arguments);
+        if (methodHandleNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
+        }
+        return null;
+    }
+
+    /**
+     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+     * the member name argument is constant.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    StampPair returnStamp, ValueNode[] arguments) {
+        ValueNode memberNameNode = getMemberName(arguments);
+        if (memberNameNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the targetMethod of a
+     * java.lang.invoke.MemberName.
+     *
+     * @param target the target, already loaded from the member name node
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, StampPair returnStamp, ValueNode[] originalArguments, ResolvedJavaMethod target,
+                    ResolvedJavaMethod original) {
+        if (target == null) {
+            return null;
+        }
+
+        // In lambda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        Signature signature = target.getSignature();
+        final boolean isStatic = target.isStatic();
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Don't mutate the passed in arguments
+        ValueNode[] arguments = originalArguments.clone();
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = target.getDeclaringClass();
+            maybeCastArgument(assumptions, arguments, 0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
+            maybeCastArgument(assumptions, arguments, receiverSkip + index, parameterType);
+        }
+
+        if (target.canBeStaticallyBound()) {
+            return createTargetInvokeNode(assumptions, intrinsicMethod, target, original, bci, returnStamp, arguments);
+        }
+
+        // Try to get the most accurate receiver type
+        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+            ValueNode receiver = getReceiver(arguments);
+            TypeReference receiverType = StampTool.typeReferenceOrNull(receiver.stamp());
+            if (receiverType != null) {
+                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.getType().findUniqueConcreteMethod(target);
+                if (concreteMethod != null && concreteMethod.canRecordTo(assumptions)) {
+                    concreteMethod.recordTo(assumptions);
+                    return createTargetInvokeNode(assumptions, intrinsicMethod, concreteMethod.getResult(), original, bci, returnStamp, arguments);
+                }
+            }
+        } else {
+            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
+            if (concreteMethod != null && concreteMethod.canRecordTo(assumptions)) {
+                concreteMethod.recordTo(assumptions);
+                return createTargetInvokeNode(assumptions, intrinsicMethod, concreteMethod.getResult(), original, bci, returnStamp, arguments);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     *
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private static void maybeCastArgument(Assumptions assumptions, ValueNode[] arguments, int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            TypeReference targetType = TypeReference.create(assumptions, (ResolvedJavaType) type);
+            ValueNode argument = arguments[index];
+            /*
+             * When an argument is a Word type, we can have a mismatch of primitive/object types
+             * here. Not inserting a PiNode is a safe fallback, and Word types need no additional
+             * type information anyway.
+             */
+            if (targetType != null && !targetType.getType().isPrimitive() && !argument.getStackKind().isPrimitive()) {
+                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType.getType()) && !argumentType.equals(targetType.getType()))) {
+                    PiNode piNode = new PiNode(argument, StampFactory.object(targetType));
+                    arguments[index] = piNode;
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode createTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, StampPair returnStamp,
+                    ValueNode[] arguments) {
+        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType targetReturnType = target.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] targetArguments;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                targetArguments = arguments;
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        StampPair targetReturnStamp = StampFactory.forDeclaredType(assumptions, targetReturnType, false);
+
+        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnStamp, original, arguments, returnStamp);
+
+        // The call target can have a different return type than the invoker,
+        // e.g. the target returns an Object but the invoker void. In this case
+        // we need to use the stamp of the invoker. Note: always using the
+        // invoker's stamp would be wrong because it's a less concrete type
+        // (usually java.lang.Object).
+        if (returnStamp.getTrustedStamp().getStackKind() == JavaKind.Void) {
+            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
+        } else {
+            return new InvokeNode(callTarget, bci);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java
new file mode 100644
index 0000000..1ba07e2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * This node class can be used to create {@link MacroNode}s for simple pure functions like
+ * {@link System#identityHashCode(Object)}.
+ */
+@NodeInfo
+public abstract class PureFunctionMacroNode extends MacroStateSplitNode implements Canonicalizable {
+
+    public static final NodeClass<PureFunctionMacroNode> TYPE = NodeClass.create(PureFunctionMacroNode.class);
+
+    public PureFunctionMacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnStamp, arguments);
+    }
+
+    /**
+     * This method should return either a constant that represents the result of the function, or
+     * null if no such result could be determined.
+     */
+    protected abstract JavaConstant evaluate(JavaConstant param, MetaAccessProvider metaAccess);
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        } else {
+            ValueNode param = arguments.get(0);
+            if (param.isConstant()) {
+                JavaConstant constant = evaluate(param.asJavaConstant(), tool.getMetaAccess());
+                if (constant != null) {
+                    return ConstantNode.forConstant(constant, tool.getMetaAccess());
+                }
+            }
+        }
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java
new file mode 100644
index 0000000..e4124bc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Access the value of a specific register.
+ */
+@NodeInfo(nameTemplate = "ReadRegister %{p#register}", cycles = CYCLES_1, size = SIZE_1)
+public final class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<ReadRegisterNode> TYPE = NodeClass.create(ReadRegisterNode.class);
+    /**
+     * The fixed register to access.
+     */
+    protected final Register register;
+
+    /**
+     * When true, subsequent uses of this node use the fixed register; when false, the value is
+     * moved into a new virtual register so that the fixed register is not seen by uses.
+     */
+    protected final boolean directUse;
+
+    /**
+     * When true, this node is also an implicit definition of the value for the register allocator,
+     * i.e., the register is an implicit incoming value; when false, the register must be defined in
+     * the same method or must be an register excluded from register allocation.
+     */
+    protected final boolean incoming;
+
+    public ReadRegisterNode(Register register, JavaKind kind, boolean directUse, boolean incoming) {
+        super(TYPE, StampFactory.forKind(kind));
+        assert register != null;
+        this.register = register;
+        this.directUse = directUse;
+        this.incoming = incoming;
+    }
+
+    public ReadRegisterNode(Register register, boolean directUse, boolean incoming) {
+        super(TYPE, StampFactory.forNodeIntrinsic());
+        assert register != null;
+        this.register = register;
+        this.directUse = directUse;
+        this.incoming = incoming;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+        Value result = register.asValue(kind);
+        if (incoming) {
+            generator.getLIRGeneratorTool().emitIncomingValues(new Value[]{result});
+        }
+        if (!directUse) {
+            result = generator.getLIRGeneratorTool().emitMove(result);
+        }
+        generator.setResult(this, result);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "%" + register;
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java
new file mode 100644
index 0000000..b71dfc7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ResolvedMethodHandleCallTargetNode.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import java.lang.invoke.MethodHandle;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A call target that replaces itself in the graph when being lowered by restoring the original
+ * {@link MethodHandle} invocation target. Prior to
+ * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
+ * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
+ * that case, the original invocation must be restored with all of its original arguments. Why?
+ * HotSpot linkage for {@link MethodHandle} intrinsics (see
+ * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
+ * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
+ * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
+ * invocation drops these arguments which means the interpreter won't find them.
+ */
+@NodeInfo
+public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
+
+    /**
+     * Creates a call target for an invocation on a direct target derived by resolving a constant
+     * {@link MethodHandle}.
+     */
+    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp,
+                    ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, StampPair originalReturnStamp) {
+        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnStamp, originalTargetMethod, originalArguments, originalReturnStamp);
+    }
+
+    protected final ResolvedJavaMethod originalTargetMethod;
+    protected final StampPair originalReturnStamp;
+    @Input NodeInputList<ValueNode> originalArguments;
+
+    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, StampPair returnStamp,
+                    ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, StampPair originalReturnStamp) {
+        super(TYPE, invokeKind, targetMethod, arguments, returnStamp, null);
+        this.originalTargetMethod = originalTargetMethod;
+        this.originalReturnStamp = originalReturnStamp;
+        this.originalArguments = new NodeInputList<>(this, originalArguments);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnStamp, null));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw GraalError.shouldNotReachHere("should have replaced itself");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReverseBytesNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReverseBytesNode.java
new file mode 100644
index 0000000..414a763
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReverseBytesNode.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public final class ReverseBytesNode extends UnaryNode implements LIRLowerable {
+
+    public static final NodeClass<ReverseBytesNode> TYPE = NodeClass.create(ReverseBytesNode.class);
+
+    public ReverseBytesNode(ValueNode value) {
+        super(TYPE, StampFactory.forKind(value.getStackKind()), value);
+        assert getStackKind() == JavaKind.Int || getStackKind() == JavaKind.Long;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        IntegerStamp valueStamp = (IntegerStamp) newStamp;
+        if (getStackKind() == JavaKind.Int) {
+            long mask = CodeUtil.mask(JavaKind.Int.getBitCount());
+            return IntegerStamp.stampForMask(valueStamp.getBits(), Integer.reverse((int) valueStamp.downMask()) & mask, Integer.reverse((int) valueStamp.upMask()) & mask);
+        } else if (getStackKind() == JavaKind.Long) {
+            return IntegerStamp.stampForMask(valueStamp.getBits(), Long.reverse(valueStamp.downMask()), Long.reverse(valueStamp.upMask()));
+        } else {
+            return stamp();
+        }
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            JavaConstant c = forValue.asJavaConstant();
+            long reversed = getStackKind() == JavaKind.Int ? Integer.reverseBytes(c.asInt()) : Long.reverseBytes(c.asLong());
+            return ConstantNode.forIntegerKind(getStackKind(), reversed);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = gen.getLIRGeneratorTool().emitByteSwap(gen.operand(getValue()));
+        gen.setResult(this, result);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/UnaryMathIntrinsicNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/UnaryMathIntrinsicNode.java
new file mode 100644
index 0000000..76bfc73
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/UnaryMathIntrinsicNode.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(nameTemplate = "MathIntrinsic#{p#operation/s}", cycles = CYCLES_UNKNOWN, size = SIZE_1)
+public final class UnaryMathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable, Lowerable {
+
+    public static final NodeClass<UnaryMathIntrinsicNode> TYPE = NodeClass.create(UnaryMathIntrinsicNode.class);
+    protected final UnaryOperation operation;
+
+    public enum UnaryOperation {
+        LOG(new ForeignCallDescriptor("arithmeticLog", double.class, double.class)),
+        LOG10(new ForeignCallDescriptor("arithmeticLog10", double.class, double.class)),
+        SIN(new ForeignCallDescriptor("arithmeticSin", double.class, double.class)),
+        COS(new ForeignCallDescriptor("arithmeticCos", double.class, double.class)),
+        TAN(new ForeignCallDescriptor("arithmeticTan", double.class, double.class)),
+        EXP(new ForeignCallDescriptor("arithmeticExp", double.class, double.class));
+
+        public final ForeignCallDescriptor foreignCallDescriptor;
+
+        UnaryOperation(ForeignCallDescriptor foreignCallDescriptor) {
+            this.foreignCallDescriptor = foreignCallDescriptor;
+        }
+
+        public double compute(double value) {
+            switch (this) {
+                case LOG:
+                    return Math.log(value);
+                case LOG10:
+                    return Math.log10(value);
+                case EXP:
+                    return Math.exp(value);
+                case SIN:
+                    return Math.sin(value);
+                case COS:
+                    return Math.cos(value);
+                case TAN:
+                    return Math.tan(value);
+                default:
+                    throw new GraalError("unknown op %s", this);
+            }
+        }
+    }
+
+    public UnaryOperation getOperation() {
+        return operation;
+    }
+
+    public static ValueNode create(ValueNode value, UnaryOperation op) {
+        ValueNode c = tryConstantFold(value, op);
+        if (c != null) {
+            return c;
+        }
+        return new UnaryMathIntrinsicNode(value, op);
+    }
+
+    protected static ValueNode tryConstantFold(ValueNode value, UnaryOperation op) {
+        if (value.isConstant()) {
+            return ConstantNode.forDouble(op.compute(value.asJavaConstant().asDouble()));
+        }
+        return null;
+    }
+
+    protected UnaryMathIntrinsicNode(ValueNode value, UnaryOperation op) {
+        super(TYPE, computeStamp(value.stamp(), op), value);
+        assert value.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(value.stamp()) == 64;
+        this.operation = op;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp valueStamp) {
+        return computeStamp(valueStamp, getOperation());
+    }
+
+    static Stamp computeStamp(Stamp valueStamp, UnaryOperation op) {
+        if (valueStamp instanceof FloatStamp) {
+            FloatStamp floatStamp = (FloatStamp) valueStamp;
+            switch (op) {
+                case COS:
+                case SIN: {
+                    boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY && floatStamp.isNonNaN();
+                    return StampFactory.forFloat(JavaKind.Double, -1.0, 1.0, nonNaN);
+                }
+                case TAN: {
+                    boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY && floatStamp.isNonNaN();
+                    return StampFactory.forFloat(JavaKind.Double, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, nonNaN);
+                }
+                case LOG:
+                case LOG10: {
+                    double lowerBound = op.compute(floatStamp.lowerBound());
+                    double upperBound = op.compute(floatStamp.upperBound());
+                    if (floatStamp.contains(0.0)) {
+                        // 0.0 and -0.0 infinity produces -Inf
+                        lowerBound = Double.NEGATIVE_INFINITY;
+                    }
+                    boolean nonNaN = floatStamp.lowerBound() >= 0.0 && floatStamp.isNonNaN();
+                    return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, nonNaN);
+                }
+                case EXP: {
+                    double lowerBound = Math.exp(floatStamp.lowerBound());
+                    double upperBound = Math.exp(floatStamp.upperBound());
+                    boolean nonNaN = floatStamp.isNonNaN();
+                    return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, nonNaN);
+                }
+
+            }
+        }
+        return StampFactory.forKind(JavaKind.Double);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value input = nodeValueMap.operand(getValue());
+        Value result;
+        switch (getOperation()) {
+            case LOG:
+                result = gen.emitMathLog(input, false);
+                break;
+            case LOG10:
+                result = gen.emitMathLog(input, true);
+                break;
+            case EXP:
+                result = gen.emitMathExp(input);
+                break;
+            case SIN:
+                result = gen.emitMathSin(input);
+                break;
+            case COS:
+                result = gen.emitMathCos(input);
+                break;
+            case TAN:
+                result = gen.emitMathTan(input);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+        nodeValueMap.setResult(this, result);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode c = tryConstantFold(forValue, getOperation());
+        if (c != null) {
+            return c;
+        }
+        return this;
+    }
+
+    @NodeIntrinsic
+    public static native double compute(double value, @ConstantNodeParameter UnaryOperation op);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java
new file mode 100644
index 0000000..5d09414
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * A helper class to allow elimination of byte code instrumentation that could interfere with escape
+ * analysis.
+ */
+@NodeInfo
+public class VirtualizableInvokeMacroNode extends MacroStateSplitNode implements Virtualizable {
+
+    public static final NodeClass<VirtualizableInvokeMacroNode> TYPE = NodeClass.create(VirtualizableInvokeMacroNode.class);
+
+    public VirtualizableInvokeMacroNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments);
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        for (ValueNode arg : arguments) {
+            ValueNode alias = tool.getAlias(arg);
+            if (alias instanceof VirtualObjectNode) {
+                tool.delete();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/WriteRegisterNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/WriteRegisterNode.java
new file mode 100644
index 0000000..5cffadc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/WriteRegisterNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Changes the value of a specific register.
+ */
+@NodeInfo(nameTemplate = "WriteRegister %{p#register}")
+public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<WriteRegisterNode> TYPE = NodeClass.create(WriteRegisterNode.class);
+    /**
+     * The fixed register to access.
+     */
+    protected final Register register;
+
+    /**
+     * The new value assigned to the register.
+     */
+    @Input ValueNode value;
+
+    public WriteRegisterNode(Register register, ValueNode value) {
+        super(TYPE, StampFactory.forVoid());
+        this.register = register;
+        this.value = value;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        Value val = generator.operand(value);
+        generator.getLIRGeneratorTool().emitMove(register.asValue(val.getValueKind()), val);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "%" + register;
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java
new file mode 100644
index 0000000..cb396b2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsNegatively;
+import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsPositively;
+import static org.graalvm.compiler.core.common.type.IntegerStamp.carryBits;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
+ * case the addition would overflow the 32 bit range.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
+public final class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class);
+
+    public IntegerAddExactNode(ValueNode x, ValueNode y) {
+        super(TYPE, x, y);
+        setStamp(x.stamp().unrestricted());
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        /*
+         * Note: it is not allowed to use the foldStamp method of the regular add node as we do not
+         * know the result stamp of this node if we do not know whether we may deopt. If we know we
+         * can never overflow we will replace this node with its non overflow checking counterpart
+         * anyway.
+         */
+        return false;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        IntegerStamp a = (IntegerStamp) stampX;
+        IntegerStamp b = (IntegerStamp) stampY;
+
+        int bits = a.getBits();
+        assert bits == b.getBits();
+
+        long defaultMask = CodeUtil.mask(bits);
+        long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+        long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
+        long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
+        long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
+
+        newDownMask &= defaultMask;
+        newUpMask &= defaultMask;
+
+        long newLowerBound;
+        long newUpperBound;
+        boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
+        boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
+        boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
+        boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
+        if (lowerOverflowsPositively) {
+            newLowerBound = CodeUtil.maxValue(bits);
+        } else if (lowerOverflowsNegatively) {
+            newLowerBound = CodeUtil.minValue(bits);
+        } else {
+            newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
+        }
+
+        if (upperOverflowsPositively) {
+            newUpperBound = CodeUtil.maxValue(bits);
+        } else if (upperOverflowsNegatively) {
+            newUpperBound = CodeUtil.minValue(bits);
+        } else {
+            newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
+        }
+
+        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+        newUpMask &= limit.upMask();
+        newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
+        newDownMask |= limit.downMask();
+        newLowerBound |= newDownMask;
+        return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = findSynonym(forX, forY);
+        if (result == null) {
+            return this;
+        } else {
+            return result;
+        }
+    }
+
+    private static ValueNode findSynonym(ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerAddExactNode(forY, forX);
+        }
+        if (forX.isConstant()) {
+            ConstantNode constantNode = canonicalXconstant(forX, forY);
+            if (constantNode != null) {
+                return constantNode;
+            }
+        } else if (forY.isConstant()) {
+            long c = forY.asJavaConstant().asLong();
+            if (c == 0) {
+                return forX;
+            }
+        }
+        return null;
+    }
+
+    private static ConstantNode canonicalXconstant(ValueNode forX, ValueNode forY) {
+        JavaConstant xConst = forX.asJavaConstant();
+        JavaConstant yConst = forY.asJavaConstant();
+        if (xConst != null && yConst != null) {
+            assert xConst.getJavaKind() == yConst.getJavaKind();
+            try {
+                if (xConst.getJavaKind() == JavaKind.Int) {
+                    return ConstantNode.forInt(Math.addExact(xConst.asInt(), yConst.asInt()));
+                } else {
+                    assert xConst.getJavaKind() == JavaKind.Long;
+                    return ConstantNode.forLong(Math.addExact(xConst.asLong(), yConst.asLong()));
+                }
+            } catch (ArithmeticException ex) {
+                // The operation will result in an overflow exception, so do not canonicalize.
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) {
+        return graph().add(new IntegerAddExactSplitNode(stamp(), getX(), getY(), next, deopt));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        IntegerExactArithmeticSplitNode.lower(tool, this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactSplitNode.java
new file mode 100644
index 0000000..22ec85f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactSplitNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo
+public final class IntegerAddExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerAddExactSplitNode> TYPE = NodeClass.create(IntegerAddExactSplitNode.class);
+
+    public IntegerAddExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
+    }
+
+    @Override
+    protected Value generateArithmetic(NodeLIRBuilderTool gen) {
+        return gen.getLIRGeneratorTool().getArithmetic().emitAdd(gen.operand(getX()), gen.operand(getY()), true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticNode.java
new file mode 100644
index 0000000..34ca06f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticNode.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+
+interface IntegerExactArithmeticNode extends Lowerable {
+
+    IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticSplitNode.java
new file mode 100644
index 0000000..7ecff52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerExactArithmeticSplitNode.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(cycles = CYCLES_2, cyclesRationale = "add+cmp", size = SIZE_2)
+public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRLowerable {
+    public static final NodeClass<IntegerExactArithmeticSplitNode> TYPE = NodeClass.create(IntegerExactArithmeticSplitNode.class);
+
+    @Successor AbstractBeginNode next;
+    @Successor AbstractBeginNode overflowSuccessor;
+    @Input ValueNode x;
+    @Input ValueNode y;
+
+    protected IntegerExactArithmeticSplitNode(NodeClass<? extends IntegerExactArithmeticSplitNode> c, Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next,
+                    AbstractBeginNode overflowSuccessor) {
+        super(c, stamp);
+        this.x = x;
+        this.y = y;
+        this.overflowSuccessor = overflowSuccessor;
+        this.next = next;
+    }
+
+    @Override
+    public AbstractBeginNode getPrimarySuccessor() {
+        return next;
+    }
+
+    @Override
+    public double probability(AbstractBeginNode successor) {
+        return successor == next ? 1 : 0;
+    }
+
+    public AbstractBeginNode getNext() {
+        return next;
+    }
+
+    public AbstractBeginNode getOverflowSuccessor() {
+        return overflowSuccessor;
+    }
+
+    public ValueNode getX() {
+        return x;
+    }
+
+    public ValueNode getY() {
+        return y;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.setResult(this, generateArithmetic(generator));
+        generator.emitOverflowCheckBranch(getOverflowSuccessor(), getNext(), stamp, probability(getOverflowSuccessor()));
+    }
+
+    protected abstract Value generateArithmetic(NodeLIRBuilderTool generator);
+
+    static void lower(LoweringTool tool, IntegerExactArithmeticNode node) {
+        if (node.asNode().graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            FloatingNode floatingNode = (FloatingNode) node;
+            FixedWithNextNode previous = tool.lastFixedNode();
+            FixedNode next = previous.next();
+            previous.setNext(null);
+            DeoptimizeNode deopt = floatingNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException));
+            AbstractBeginNode normalBegin = floatingNode.graph().add(new BeginNode());
+            normalBegin.setNext(next);
+            IntegerExactArithmeticSplitNode split = node.createSplit(normalBegin, BeginNode.begin(deopt));
+            previous.setNext(split);
+            floatingNode.replaceAndDelete(split);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactNode.java
new file mode 100644
index 0000000..99375cb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactNode.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Node representing an exact integer multiplication that will throw an {@link ArithmeticException}
+ * in case the addition would overflow the 32 bit range.
+ */
+@NodeInfo(cycles = CYCLES_4, cyclesRationale = "mul+cmp", size = SIZE_2)
+public final class IntegerMulExactNode extends MulNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerMulExactNode> TYPE = NodeClass.create(IntegerMulExactNode.class);
+
+    public IntegerMulExactNode(ValueNode x, ValueNode y) {
+        super(TYPE, x, y);
+        setStamp(x.stamp().unrestricted());
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        /*
+         * Note: it is not allowed to use the foldStamp method of the regular mul node as we do not
+         * know the result stamp of this node if we do not know whether we may deopt. If we know we
+         * can never overflow we will replace this node with its non overflow checking counterpart
+         * anyway.
+         */
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && !forY.isConstant()) {
+            return new IntegerMulExactNode(forY, forX);
+        }
+        if (forX.isConstant()) {
+            return canonicalXconstant(forX, forY);
+        } else if (forY.isConstant()) {
+            long c = forY.asJavaConstant().asLong();
+            if (c == 1) {
+                return forX;
+            }
+            if (c == 0) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            }
+        }
+        if (!mayOverFlow((IntegerStamp) x.stamp(), (IntegerStamp) y.stamp())) {
+            return new MulNode(x, y).canonical(tool);
+        }
+        return this;
+    }
+
+    private static boolean mayOverFlow(IntegerStamp a, IntegerStamp b) {
+        // see IntegerStamp#foldStamp for details
+        assert a.getBits() == b.getBits();
+        if (a.upMask() == 0) {
+            return false;
+        } else if (b.upMask() == 0) {
+            return false;
+        }
+        if (a.isUnrestricted()) {
+            return true;
+        }
+        if (b.isUnrestricted()) {
+            return true;
+        }
+        int bits = a.getBits();
+        // Checkstyle: stop
+        long minN_a = a.lowerBound();
+        long maxN_a = Math.min(0, a.upperBound());
+        long minP_a = Math.max(0, a.lowerBound());
+        long maxP_a = a.upperBound();
+
+        long minN_b = b.lowerBound();
+        long maxN_b = Math.min(0, b.upperBound());
+        long minP_b = Math.max(0, b.lowerBound());
+        long maxP_b = b.upperBound();
+        // Checkstyle: resume
+
+        boolean mayOverflow = false;
+        if (a.canBePositive()) {
+            if (b.canBePositive()) {
+                mayOverflow |= IntegerStamp.multiplicationOverflows(maxP_a, maxP_b, bits);
+                mayOverflow |= IntegerStamp.multiplicationOverflows(minP_a, minP_b, bits);
+            }
+            if (b.canBeNegative()) {
+                mayOverflow |= IntegerStamp.multiplicationOverflows(minP_a, maxN_b, bits);
+                mayOverflow |= IntegerStamp.multiplicationOverflows(maxP_a, minN_b, bits);
+
+            }
+        }
+        if (a.canBeNegative()) {
+            if (b.canBePositive()) {
+                mayOverflow |= IntegerStamp.multiplicationOverflows(maxN_a, minP_b, bits);
+                mayOverflow |= IntegerStamp.multiplicationOverflows(minN_a, maxP_b, bits);
+            }
+            if (b.canBeNegative()) {
+                mayOverflow |= IntegerStamp.multiplicationOverflows(minN_a, minN_b, bits);
+                mayOverflow |= IntegerStamp.multiplicationOverflows(maxN_a, maxN_b, bits);
+            }
+        }
+        return mayOverflow;
+    }
+
+    private ValueNode canonicalXconstant(ValueNode forX, ValueNode forY) {
+        JavaConstant xConst = forX.asJavaConstant();
+        JavaConstant yConst = forY.asJavaConstant();
+        assert xConst.getJavaKind() == yConst.getJavaKind();
+        try {
+            if (xConst.getJavaKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Math.multiplyExact(xConst.asInt(), yConst.asInt()));
+            } else {
+                assert xConst.getJavaKind() == JavaKind.Long;
+                return ConstantNode.forLong(Math.multiplyExact(xConst.asLong(), yConst.asLong()));
+            }
+        } catch (ArithmeticException ex) {
+            // The operation will result in an overflow exception, so do not canonicalize.
+        }
+        return this;
+    }
+
+    @Override
+    public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) {
+        return graph().add(new IntegerMulExactSplitNode(stamp(), getX(), getY(), next, deopt));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        IntegerExactArithmeticSplitNode.lower(tool, this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactSplitNode.java
new file mode 100644
index 0000000..282253d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactSplitNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo
+public final class IntegerMulExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerMulExactSplitNode> TYPE = NodeClass.create(IntegerMulExactSplitNode.class);
+
+    public IntegerMulExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
+    }
+
+    @Override
+    protected Value generateArithmetic(NodeLIRBuilderTool gen) {
+        return gen.getLIRGeneratorTool().getArithmetic().emitMul(gen.operand(getX()), gen.operand(getY()), true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java
new file mode 100644
index 0000000..bd130d1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import java.util.function.BiFunction;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(shortName = "*H", cycles = CYCLES_2, size = SIZE_2)
+public final class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+    public static final NodeClass<IntegerMulHighNode> TYPE = NodeClass.create(IntegerMulHighNode.class);
+
+    public IntegerMulHighNode(ValueNode x, ValueNode y) {
+        this((IntegerStamp) x.stamp().unrestricted(), x, y);
+    }
+
+    public IntegerMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
+        super(TYPE, stamp, x, y);
+    }
+
+    /**
+     * Determines the minimum and maximum result of this node for the given inputs and returns the
+     * result of the given BiFunction on the minimum and maximum values.
+     */
+    private <T> T processExtremes(Stamp forX, Stamp forY, BiFunction<Long, Long, T> op) {
+        IntegerStamp xStamp = (IntegerStamp) forX;
+        IntegerStamp yStamp = (IntegerStamp) forY;
+
+        JavaKind kind = getStackKind();
+        assert kind == JavaKind.Int || kind == JavaKind.Long;
+        long[] xExtremes = {xStamp.lowerBound(), xStamp.upperBound()};
+        long[] yExtremes = {yStamp.lowerBound(), yStamp.upperBound()};
+        long min = Long.MAX_VALUE;
+        long max = Long.MIN_VALUE;
+        for (long a : xExtremes) {
+            for (long b : yExtremes) {
+                long result = kind == JavaKind.Int ? multiplyHigh((int) a, (int) b) : multiplyHigh(a, b);
+                min = Math.min(min, result);
+                max = Math.max(max, result);
+            }
+        }
+        return op.apply(min, max);
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        return processExtremes(stampX, stampY, (min, max) -> StampFactory.forInteger(getStackKind(), min, max));
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value a = nodeValueMap.operand(getX());
+        Value b = nodeValueMap.operand(getY());
+        nodeValueMap.setResult(this, gen.emitMulHigh(a, b));
+    }
+
+    public static int multiplyHigh(int x, int y) {
+        long r = (long) x * (long) y;
+        return (int) (r >> 32);
+    }
+
+    public static long multiplyHigh(long x, long y) {
+        // Checkstyle: stop
+        long x0, y0, z0;
+        long x1, y1, z1, z2, t;
+        // Checkstyle: resume
+
+        x0 = x & 0xFFFFFFFFL;
+        x1 = x >> 32;
+
+        y0 = y & 0xFFFFFFFFL;
+        y1 = y >> 32;
+
+        z0 = x0 * y0;
+        t = x1 * y0 + (z0 >>> 32);
+        z1 = t & 0xFFFFFFFFL;
+        z2 = t >> 32;
+        z1 += x0 * y1;
+
+        return x1 * y1 + z2 + (z1 >> 32);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactNode.java
new file mode 100644
index 0000000..625dbf6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactNode.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Node representing an exact integer substraction that will throw an {@link ArithmeticException} in
+ * case the addition would overflow the 32 bit range.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
+public final class IntegerSubExactNode extends SubNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerSubExactNode> TYPE = NodeClass.create(IntegerSubExactNode.class);
+
+    public IntegerSubExactNode(ValueNode x, ValueNode y) {
+        super(TYPE, x, y);
+        setStamp(x.stamp().unrestricted());
+        assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        /*
+         * Note: it is not allowed to use the foldStamp method of the regular sub node as we do not
+         * know the result stamp of this node if we do not know whether we may deopt. If we know we
+         * can never overflow we will replace this node with its non overflow checking counterpart
+         * anyway.
+         */
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return ConstantNode.forIntegerStamp(stamp(), 0);
+        }
+        if (forX.isConstant() && forY.isConstant()) {
+            return canonicalXYconstant(forX, forY);
+        } else if (forY.isConstant()) {
+            long c = forY.asJavaConstant().asLong();
+            if (c == 0) {
+                return forX;
+            }
+        }
+        if (!IntegerStamp.subtractionCanOverflow((IntegerStamp) x.stamp(), (IntegerStamp) y.stamp())) {
+            return new SubNode(x, y).canonical(tool);
+        }
+        return this;
+    }
+
+    private ValueNode canonicalXYconstant(ValueNode forX, ValueNode forY) {
+        JavaConstant xConst = forX.asJavaConstant();
+        JavaConstant yConst = forY.asJavaConstant();
+        assert xConst.getJavaKind() == yConst.getJavaKind();
+        try {
+            if (xConst.getJavaKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Math.subtractExact(xConst.asInt(), yConst.asInt()));
+            } else {
+                assert xConst.getJavaKind() == JavaKind.Long;
+                return ConstantNode.forLong(Math.subtractExact(xConst.asLong(), yConst.asLong()));
+            }
+        } catch (ArithmeticException ex) {
+            // The operation will result in an overflow exception, so do not canonicalize.
+        }
+        return this;
+    }
+
+    @Override
+    public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) {
+        return graph().add(new IntegerSubExactSplitNode(stamp(), getX(), getY(), next, deopt));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        IntegerExactArithmeticSplitNode.lower(tool, this);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactSplitNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactSplitNode.java
new file mode 100644
index 0000000..6e53aed
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerSubExactSplitNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo
+public final class IntegerSubExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerSubExactSplitNode> TYPE = NodeClass.create(IntegerSubExactSplitNode.class);
+
+    public IntegerSubExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
+    }
+
+    @Override
+    protected Value generateArithmetic(NodeLIRBuilderTool gen) {
+        return gen.getLIRGeneratorTool().getArithmetic().emitSub(gen.operand(getX()), gen.operand(getY()), true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java
new file mode 100644
index 0000000..845b1cd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes.arithmetic;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+
+import java.util.function.BiFunction;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+@NodeInfo(shortName = "|*H|", cycles = CYCLES_4, cyclesRationale = "mul + mov", size = SIZE_4)
+public final class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<UnsignedMulHighNode> TYPE = NodeClass.create(UnsignedMulHighNode.class);
+
+    public UnsignedMulHighNode(ValueNode x, ValueNode y) {
+        this((IntegerStamp) x.stamp().unrestricted(), x, y);
+    }
+
+    public UnsignedMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
+        super(TYPE, stamp, x, y);
+    }
+
+    private static long[] getUnsignedExtremes(IntegerStamp stamp) {
+        if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
+            /*
+             * If -1 and 0 are both in the signed range, then we can't say anything about the
+             * unsigned range, so we have to return [0, MAX_UNSIGNED].
+             */
+            return new long[]{0, -1L};
+        } else {
+            return new long[]{stamp.lowerBound(), stamp.upperBound()};
+        }
+    }
+
+    /**
+     * Determines the minimum and maximum result of this node for the given inputs and returns the
+     * result of the given BiFunction on the minimum and maximum values. Note that the minima and
+     * maxima are calculated using signed min/max functions, while the values themselves are
+     * unsigned.
+     */
+    private <T> T processExtremes(Stamp forX, Stamp forY, BiFunction<Long, Long, T> op) {
+        IntegerStamp xStamp = (IntegerStamp) forX;
+        IntegerStamp yStamp = (IntegerStamp) forY;
+
+        JavaKind kind = getStackKind();
+        assert kind == JavaKind.Int || kind == JavaKind.Long;
+        long[] xExtremes = getUnsignedExtremes(xStamp);
+        long[] yExtremes = getUnsignedExtremes(yStamp);
+        long min = Long.MAX_VALUE;
+        long max = Long.MIN_VALUE;
+        for (long a : xExtremes) {
+            for (long b : yExtremes) {
+                long result = kind == JavaKind.Int ? multiplyHighUnsigned((int) a, (int) b) : multiplyHighUnsigned(a, b);
+                min = Math.min(min, result);
+                max = Math.max(max, result);
+            }
+        }
+        return op.apply(min, max);
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
+        // if min is negative, then the value can reach into the unsigned range
+        return processExtremes(stampX, stampY, (min, max) -> (min == (long) max || min >= 0) ? StampFactory.forInteger(getStackKind(), min, max) : StampFactory.forKind(getStackKind()));
+    }
+
+    @SuppressWarnings("cast")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+        Value a = nodeValueMap.operand(getX());
+        Value b = nodeValueMap.operand(getY());
+        nodeValueMap.setResult(this, gen.emitUMulHigh(a, b));
+    }
+
+    public static int multiplyHighUnsigned(int x, int y) {
+        long xl = x & 0xFFFFFFFFL;
+        long yl = y & 0xFFFFFFFFL;
+        long r = xl * yl;
+        return (int) (r >> 32);
+    }
+
+    public static long multiplyHighUnsigned(long x, long y) {
+        // Checkstyle: stop
+        long x0, y0, z0;
+        long x1, y1, z1, z2, t;
+        // Checkstyle: resume
+
+        x0 = x & 0xFFFFFFFFL;
+        x1 = x >>> 32;
+
+        y0 = y & 0xFFFFFFFFL;
+        y1 = y >>> 32;
+
+        z0 = x0 * y0;
+        t = x1 * y0 + (z0 >>> 32);
+        z1 = t & 0xFFFFFFFFL;
+        z2 = t >>> 32;
+        z1 += x0 * y1;
+
+        return x1 * y1 + z2 + (z1 >>> 32);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.runtime/src/org/graalvm/compiler/runtime/RuntimeProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.runtime/src/org/graalvm/compiler/runtime/RuntimeProvider.java
new file mode 100644
index 0000000..e5af514
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.runtime/src/org/graalvm/compiler/runtime/RuntimeProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.runtime;
+
+import jdk.vm.ci.code.Architecture;
+
+import org.graalvm.compiler.core.target.Backend;
+
+/**
+ * A runtime supporting a host backend as well, zero or more additional backends.
+ */
+public interface RuntimeProvider {
+
+    /**
+     * Gets the host backend.
+     */
+    Backend getHostBackend();
+
+    /**
+     * Gets the backend for a given architecture.
+     *
+     * @param arch a specific architecture class
+     */
+    <T extends Architecture> Backend getBackend(Class<T> arch);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/Salver.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/Salver.java
new file mode 100644
index 0000000..79a343f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/Salver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver;
+
+import static org.graalvm.compiler.salver.SalverOptions.SalverAddress;
+import static org.graalvm.compiler.salver.SalverOptions.SalverPort;
+
+import java.net.InetSocketAddress;
+
+import org.graalvm.compiler.salver.util.ECIDUtil;
+
+public final class Salver {
+
+    /**
+     * The Execution Context Identifier is a unique identifier that simplifies the grouping of
+     * events created in different DumpHandlers or Threads. It should be added as a special property
+     * to all :begin trace events.
+     */
+    public static final String ECID = ECIDUtil.random();
+
+    private Salver() {
+    }
+
+    public static InetSocketAddress getSocketAddress() {
+        return new InetSocketAddress(SalverAddress.getValue(), SalverPort.getValue());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverDebugConfigCustomizer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverDebugConfigCustomizer.java
new file mode 100644
index 0000000..d43cabf
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverDebugConfigCustomizer.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver;
+
+import static org.graalvm.compiler.salver.SalverOptions.Salver;
+
+import org.graalvm.compiler.debug.DebugConfig;
+import org.graalvm.compiler.debug.DebugConfigCustomizer;
+import org.graalvm.compiler.salver.handler.GraphDumpHandler;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+@ServiceProvider(DebugConfigCustomizer.class)
+public class SalverDebugConfigCustomizer implements DebugConfigCustomizer {
+
+    @Override
+    public void customize(DebugConfig config, Object... extraArgs) {
+        if (Salver.getValue()) {
+            config.dumpHandlers().add(new GraphDumpHandler());
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverOptions.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverOptions.java
new file mode 100644
index 0000000..6617620
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/SalverOptions.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+
+public final class SalverOptions {
+
+    //@formatter:off
+    @Option(help = "Enable dumps via Salver trace events.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> Salver = new OptionValue<>(false);
+
+    @Option(help = "Network address (Salver).", type = OptionType.Debug)
+    public static final OptionValue<String> SalverAddress = new OptionValue<>("127.0.0.1");
+
+    @Option(help = "Network port (Salver).", type = OptionType.Debug)
+    public static final OptionValue<Integer> SalverPort = new OptionValue<>(2343);
+
+    @Option(help = "Dump to files as opposed to sending them over the network (Salver).", type = OptionType.Debug)
+    public static final OptionValue<Boolean> SalverToFile = new OptionValue<>(false);
+
+    //@Option(help = "Use binary format for dumps (Salver).", type = OptionType.Debug)
+    //public static final OptionValue<Boolean> SalverDumpBinary = new OptionValue<>(false);
+    //@formatter:on
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataDict.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataDict.java
new file mode 100644
index 0000000..f3caa59
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataDict.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.data;
+
+import java.util.LinkedHashMap;
+
+public class DataDict extends LinkedHashMap<Object, Object> {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataList.java
new file mode 100644
index 0000000..1f5a965
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/data/DataList.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.data;
+
+import java.util.ArrayList;
+
+public class DataList extends ArrayList<Object> {
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractGraalDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractGraalDumper.java
new file mode 100644
index 0000000..8f11ca7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractGraalDumper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.dumper;
+
+import java.io.IOException;
+
+import org.graalvm.compiler.salver.Salver;
+import org.graalvm.compiler.salver.data.DataDict;
+
+public class AbstractGraalDumper extends AbstractSerializerDumper {
+
+    public static final String EVENT_NAMESPACE = "graal";
+
+    private int eventCounter;
+
+    public void beginDump() throws IOException {
+        beginDump(EVENT_NAMESPACE);
+    }
+
+    protected void beginDump(String namespace) throws IOException {
+        beginDump(namespace, getBeginDumpDataDict());
+    }
+
+    protected void beginDump(String namespace, DataDict dataDict) throws IOException {
+        DataDict eventDict = createEventDict(":begin");
+        eventDict.put("@time", System.currentTimeMillis());
+        eventDict.put("@ecid", Salver.ECID);
+        if (namespace != null) {
+            eventDict.put("@namespace", namespace);
+        }
+        if (dataDict != null) {
+            eventDict.put("@data", dataDict);
+        }
+        serializeAndFlush(eventDict);
+    }
+
+    protected DataDict getBeginDumpDataDict() {
+        DataDict dataDict = new DataDict();
+        dataDict.put("dumper", getClass().getSimpleName());
+        dataDict.put("thread", Thread.currentThread().getName());
+        return dataDict;
+    }
+
+    public void endDump() throws IOException {
+        DataDict eventDict = createEventDict(":end");
+        eventDict.put("@time", System.currentTimeMillis());
+        serializeAndFlush(eventDict);
+    }
+
+    @Override
+    public void close() throws IOException {
+        endDump();
+    }
+
+    protected DataDict createEventDict(String name) {
+        DataDict eventDict = new DataDict();
+        eventDict.put("@event", name);
+        eventDict.put("@n", eventCounter++);
+        return eventDict;
+    }
+
+    protected DataDict createEventDict(String name, DataDict data) {
+        DataDict eventDict = createEventDict(name);
+        eventDict.put("@data", data);
+        return eventDict;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractMethodScopeDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractMethodScopeDumper.java
new file mode 100644
index 0000000..eb7f665
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractMethodScopeDumper.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.dumper;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.salver.data.DataDict;
+import org.graalvm.compiler.salver.data.DataList;
+import org.graalvm.compiler.salver.util.MethodContext;
+
+import jdk.vm.ci.meta.JavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class AbstractMethodScopeDumper extends AbstractGraalDumper {
+
+    protected MethodContext previousMethodContext;
+
+    protected final Deque<Integer> pathStack = new ArrayDeque<>();
+    protected int pathCounter;
+    protected final Deque<Integer> itemIdStack = new ArrayDeque<>();
+    protected int itemIdCounter;
+
+    protected void resolveMethodContext() throws IOException {
+        // Get all current JavaMethod instances in the context.
+        MethodContext methodContext = new MethodContext();
+        // Reverse list such that inner method comes after outer method.
+        Collections.reverse(methodContext);
+
+        int size = methodContext.size();
+        int previousSize = previousMethodContext != null ? previousMethodContext.size() : 0;
+        // Check for method scopes that must be closed since the previous dump.
+        for (int i = 0; i < previousSize; ++i) {
+            if (i >= size || !methodContext.itemEquals(i, previousMethodContext)) {
+                for (int inlineDepth = previousSize - 1; inlineDepth >= i; --inlineDepth) {
+                    closeScope();
+                }
+                break;
+            }
+        }
+        // Check for method scopes that must be opened since the previous dump.
+        for (int i = 0; i < size; ++i) {
+            if (i >= previousSize || !methodContext.itemEquals(i, previousMethodContext)) {
+                for (int inlineDepth = i; inlineDepth < size; ++inlineDepth) {
+                    openScope(methodContext.get(inlineDepth));
+                }
+                break;
+            }
+        }
+        // Save inline context for next dump.
+        previousMethodContext = methodContext;
+    }
+
+    protected void openScope(MethodContext.Item item) throws IOException {
+        int debugId = item.getDebugId();
+        int id = debugId != -1 ? debugId : pathCounter;
+
+        pathStack.push(id);
+        itemIdStack.push(itemIdCounter);
+        pathCounter = 0;
+        itemIdCounter = 0;
+
+        processMethod(item.getMethod(), id, item.getName());
+    }
+
+    @SuppressWarnings("unused")
+    protected void closeScope() throws IOException {
+        if (!pathStack.isEmpty()) {
+            pathCounter = pathStack.pop();
+            pathCounter++;
+        }
+        if (!itemIdStack.isEmpty()) {
+            itemIdCounter = itemIdStack.pop();
+        }
+    }
+
+    protected void processMethod(JavaMethod method, int id, String name) throws IOException {
+        DataDict dataDict = new DataDict();
+        dataDict.put("id", id);
+        dataDict.put("name", name);
+
+        if (method instanceof ResolvedJavaMethod) {
+            DataDict methodDict = new DataDict();
+            dataDict.put("method", methodDict);
+
+            ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method;
+
+            methodDict.put("modifiers", Modifier.toString(resolvedMethod.getModifiers()));
+            methodDict.put("code", new BytecodeDisassembler(false).disassemble(resolvedMethod));
+        }
+        serializeAndFlush(createEventDictWithId("method", dataDict, false));
+    }
+
+    protected int nextItemId() {
+        return itemIdCounter++;
+    }
+
+    protected DataDict createEventDictWithId(String name, boolean isItem) {
+        DataDict eventDict = createEventDict(name);
+
+        DataDict idDict = new DataDict();
+        eventDict.put("@id", idDict);
+
+        DataList pathList = new DataList();
+        idDict.put("path", pathList);
+
+        Iterator<Integer> i = pathStack.descendingIterator();
+        while (i.hasNext()) {
+            pathList.add(i.next());
+        }
+        if (isItem) {
+            pathList.add(pathCounter++);
+        }
+        return eventDict;
+    }
+
+    protected DataDict createEventDictWithId(String name, DataDict dataDict, boolean isItem) {
+        DataDict eventDict = createEventDictWithId(name, isItem);
+        eventDict.put("@data", dataDict);
+        return eventDict;
+    }
+
+    protected DataDict createEventDictWithId(String name) {
+        return createEventDictWithId(name, true);
+    }
+
+    protected DataDict createEventDictWithId(String name, DataDict dataDict) {
+        return createEventDictWithId(name, dataDict, true);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractSerializerDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractSerializerDumper.java
new file mode 100644
index 0000000..987f310
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/AbstractSerializerDumper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.dumper;
+
+import java.io.IOException;
+
+import org.graalvm.compiler.salver.serialize.Serializer;
+
+public abstract class AbstractSerializerDumper implements Dumper {
+
+    protected Serializer serializer;
+
+    public AbstractSerializerDumper() {
+    }
+
+    public AbstractSerializerDumper(Serializer serializer) {
+        this.serializer = serializer;
+    }
+
+    public Serializer getSerializer() {
+        return serializer;
+    }
+
+    public void setSerializer(Serializer serializer) {
+        this.serializer = serializer;
+    }
+
+    protected void serialize(Object obj) throws IOException {
+        if (serializer != null) {
+            serializer.serialize(obj);
+        }
+    }
+
+    protected void serializeAndFlush(Object obj) throws IOException {
+        if (serializer != null) {
+            serializer.serialize(obj);
+            serializer.flush();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/Dumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/Dumper.java
new file mode 100644
index 0000000..108addd
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/Dumper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.dumper;
+
+import java.io.Closeable;
+
+public interface Dumper extends Closeable, AutoCloseable {
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/GraphDumper.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/GraphDumper.java
new file mode 100644
index 0000000..79e7382
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/dumper/GraphDumper.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.dumper;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.GraalDebugConfig.Options;
+import org.graalvm.compiler.graph.Edges;
+import org.graalvm.compiler.graph.Edges.Type;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.InputEdges;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeList;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.salver.data.DataDict;
+import org.graalvm.compiler.salver.data.DataList;
+
+public class GraphDumper extends AbstractMethodScopeDumper {
+
+    public static final String EVENT_NAMESPACE = "graal/graph";
+
+    private static final Map<Class<?>, String> nodeClassCategoryMap;
+
+    static {
+        nodeClassCategoryMap = new LinkedHashMap<>();
+        nodeClassCategoryMap.put(ControlSinkNode.class, "ControlSink");
+        nodeClassCategoryMap.put(ControlSplitNode.class, "ControlSplit");
+        nodeClassCategoryMap.put(AbstractMergeNode.class, "Merge");
+        nodeClassCategoryMap.put(AbstractBeginNode.class, "Begin");
+        nodeClassCategoryMap.put(AbstractEndNode.class, "End");
+        nodeClassCategoryMap.put(FixedNode.class, "Fixed");
+        nodeClassCategoryMap.put(VirtualState.class, "State");
+        nodeClassCategoryMap.put(PhiNode.class, "Phi");
+        nodeClassCategoryMap.put(ProxyNode.class, "Proxy");
+        // nodeClassCategoryMap.put(Node.class, "Floating");
+    }
+
+    @Override
+    public void beginDump() throws IOException {
+        beginDump(EVENT_NAMESPACE);
+    }
+
+    @SuppressWarnings("try")
+    public void dump(Graph graph, String msg) throws IOException {
+        resolveMethodContext();
+
+        try (Scope s = Debug.sandbox(getClass().getSimpleName(), null)) {
+            processGraph(graph, msg);
+        } catch (IOException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private void processGraph(Graph graph, String name) throws IOException {
+
+        ScheduleResult scheduleResult = null;
+        if (graph instanceof StructuredGraph) {
+
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            scheduleResult = structuredGraph.getLastSchedule();
+            if (scheduleResult == null) {
+
+                // Also provide a schedule when an error occurs
+                if (Options.PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
+                    try {
+                        SchedulePhase schedule = new SchedulePhase();
+                        schedule.apply(structuredGraph);
+                    } catch (Throwable t) {
+                    }
+                }
+
+            }
+        }
+
+        DataDict dataDict = new DataDict();
+        dataDict.put("id", nextItemId());
+        dataDict.put("name", name);
+
+        DataDict graphDict = new DataDict();
+        dataDict.put("graph", graphDict);
+
+        processNodes(graphDict, graph.getNodes(), scheduleResult);
+
+        if (scheduleResult != null) {
+            ControlFlowGraph cfg = scheduleResult.getCFG();
+            if (cfg != null) {
+                List<Block> blocks = Arrays.asList(cfg.getBlocks());
+                processBlocks(graphDict, blocks, scheduleResult);
+            }
+        }
+        serializeAndFlush(createEventDictWithId("graph", dataDict));
+    }
+
+    private static void processNodes(DataDict graphDict, NodeIterable<Node> nodes, ScheduleResult schedule) {
+        Map<NodeClass<?>, Integer> classMap = new HashMap<>();
+
+        DataList classList = new DataList();
+        graphDict.put("classes", classList);
+
+        DataList nodeList = new DataList();
+        graphDict.put("nodes", nodeList);
+
+        DataList edgeList = new DataList();
+        graphDict.put("edges", edgeList);
+
+        for (Node node : nodes) {
+            NodeClass<?> nodeClass = node.getNodeClass();
+
+            DataDict nodeDict = new DataDict();
+            nodeList.add(nodeDict);
+
+            nodeDict.put("id", getNodeId(node));
+            nodeDict.put("class", getNodeClassId(classMap, classList, nodeClass));
+
+            if (schedule != null) {
+                processNodeSchedule(nodeDict, node, schedule);
+            }
+
+            DataDict propertyDict = new DataDict();
+            node.getDebugProperties(propertyDict);
+
+            if (!propertyDict.isEmpty()) {
+                nodeDict.put("properties", propertyDict);
+            }
+
+            appendEdges(edgeList, node, Type.Inputs);
+            appendEdges(edgeList, node, Type.Successors);
+        }
+    }
+
+    private static void processNodeSchedule(DataDict nodeDict, Node node, ScheduleResult schedule) {
+        NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+        if (nodeToBlock != null) {
+            if (nodeToBlock.isNew(node)) {
+                nodeDict.put("block", -1);
+            } else {
+                Block block = nodeToBlock.get(node);
+                if (block != null) {
+                    nodeDict.put("block", block.getId());
+                }
+            }
+        }
+
+        ControlFlowGraph cfg = schedule.getCFG();
+        if (cfg != null && Options.PrintGraphProbabilities.getValue() && node instanceof FixedNode) {
+            try {
+                nodeDict.put("probability", cfg.blockFor(node).probability());
+            } catch (Throwable t) {
+                nodeDict.put("probability", t);
+            }
+        }
+    }
+
+    private static void processBlocks(DataDict graphDict, List<Block> blocks, ScheduleResult schedule) {
+        BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
+        DataList blockList = new DataList();
+        graphDict.put("blocks", blockList);
+
+        for (Block block : blocks) {
+            List<Node> nodes = blockToNodes.get(block);
+            if (nodes != null) {
+                DataDict blockDict = new DataDict();
+                blockList.add(blockDict);
+
+                blockDict.put("id", block.getId());
+
+                DataList nodeList = new DataList();
+                blockDict.put("nodes", nodeList);
+
+                for (Node node : nodes) {
+                    nodeList.add(getNodeId(node));
+                }
+
+                Block[] successors = block.getSuccessors();
+                if (successors != null && successors.length > 0) {
+                    DataList successorList = new DataList();
+                    blockDict.put("successors", successorList);
+                    for (Block successor : successors) {
+                        successorList.add(successor.getId());
+                    }
+                }
+            }
+        }
+    }
+
+    private static void appendEdges(DataList edgeList, Node node, Edges.Type type) {
+        NodeClass<?> nodeClass = node.getNodeClass();
+
+        Edges edges = nodeClass.getEdges(type);
+        final long[] curOffsets = edges.getOffsets();
+
+        for (int i = 0; i < edges.getDirectCount(); i++) {
+            Node other = Edges.getNode(node, curOffsets, i);
+            if (other != null) {
+                DataDict edgeDict = new DataDict();
+
+                DataDict nodeDict = new DataDict();
+                nodeDict.put("node", getNodeId(node));
+                nodeDict.put("field", edges.getName(i));
+
+                edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict);
+                edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other));
+                edgeList.add(edgeDict);
+            }
+        }
+        for (int i = edges.getDirectCount(); i < edges.getCount(); i++) {
+            NodeList<Node> list = Edges.getNodeList(node, curOffsets, i);
+            if (list != null) {
+                for (int index = 0; index < list.size(); index++) {
+                    Node other = list.get(index);
+                    if (other != null) {
+                        DataDict edgeDict = new DataDict();
+
+                        DataDict nodeDict = new DataDict();
+                        nodeDict.put("node", getNodeId(node));
+                        nodeDict.put("field", edges.getName(i));
+                        nodeDict.put("index", index);
+
+                        edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict);
+                        edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other));
+                        edgeList.add(edgeDict);
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private static int getNodeId(Node node) {
+        return node != null ? node.getId() : -1;
+    }
+
+    private static int getNodeClassId(Map<NodeClass<?>, Integer> classMap, DataList classList, NodeClass<?> nodeClass) {
+        if (classMap.containsKey(nodeClass)) {
+            return classMap.get(nodeClass);
+        }
+        int classId = classMap.size();
+        classMap.put(nodeClass, classId);
+
+        Class<?> javaClass = nodeClass.getJavaClass();
+
+        DataDict classDict = new DataDict();
+        classList.add(classDict);
+
+        classDict.put("id", classId);
+        classDict.put("name", nodeClass.getNameTemplate());
+        classDict.put("jtype", javaClass.getName());
+
+        String category = getNodeClassCategory(javaClass);
+        if (category != null) {
+            classDict.put("category", category);
+        }
+
+        Object propertyInfo = getPropertyInfo(nodeClass);
+        if (propertyInfo != null) {
+            classDict.put("properties", propertyInfo);
+        }
+
+        Object inputInfo = getEdgeInfo(nodeClass, Type.Inputs);
+        if (inputInfo != null) {
+            classDict.put("inputs", inputInfo);
+        }
+        Object successorInfo = getEdgeInfo(nodeClass, Type.Successors);
+        if (successorInfo != null) {
+            classDict.put("successors", successorInfo);
+        }
+        return classId;
+    }
+
+    private static DataDict getPropertyInfo(NodeClass<?> nodeClass) {
+        Fields properties = nodeClass.getData();
+        if (properties.getCount() > 0) {
+            DataDict propertyInfoDict = new DataDict();
+            for (int i = 0; i < properties.getCount(); i++) {
+                DataDict propertyDict = new DataDict();
+                String name = properties.getName(i);
+                propertyDict.put("name", name);
+                propertyDict.put("jtype", properties.getType(i).getName());
+                propertyInfoDict.put(name, propertyDict);
+            }
+            return propertyInfoDict;
+        }
+        return null;
+    }
+
+    private static DataDict getEdgeInfo(NodeClass<?> nodeClass, Edges.Type type) {
+        DataDict edgeInfoDict = new DataDict();
+        Edges edges = nodeClass.getEdges(type);
+        for (int i = 0; i < edges.getCount(); i++) {
+            DataDict edgeDict = new DataDict();
+            String name = edges.getName(i);
+            Class<?> fieldClass = edges.getType(i);
+            edgeDict.put("name", name);
+            edgeDict.put("jtype", fieldClass.getName());
+            if (NodeList.class.isAssignableFrom(fieldClass)) {
+                edgeDict.put("isList", true);
+            }
+            if (type == Type.Inputs) {
+                InputEdges inputEdges = ((InputEdges) edges);
+                edgeDict.put("type", inputEdges.getInputType(i));
+                if (inputEdges.isOptional(i)) {
+                    edgeDict.put("isOptional", true);
+                }
+            }
+            edgeInfoDict.put(name, edgeDict);
+        }
+        return edgeInfoDict.isEmpty() ? null : edgeInfoDict;
+    }
+
+    private static String getNodeClassCategory(Class<?> clazz) {
+        for (Map.Entry<Class<?>, String> entry : nodeClassCategoryMap.entrySet()) {
+            if (entry.getKey().isAssignableFrom(clazz)) {
+                return entry.getValue();
+            }
+        }
+        return null;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractDumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractDumpHandler.java
new file mode 100644
index 0000000..6dd8e3a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractDumpHandler.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.handler;
+
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+
+import org.graalvm.compiler.salver.dumper.Dumper;
+import org.graalvm.compiler.salver.writer.ChannelDumpWriter;
+import org.graalvm.compiler.salver.writer.DumpWriter;
+
+public abstract class AbstractDumpHandler<D extends Dumper> implements DumpHandler {
+
+    protected String label;
+
+    protected DumpWriter writer;
+    protected D dumper;
+
+    public AbstractDumpHandler() {
+        setLabel(getClass().getSimpleName() + ":" + Thread.currentThread().getName());
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    protected void setLabel(String label) {
+        this.label = label;
+    }
+
+    public DumpWriter getWriter() {
+        return writer;
+    }
+
+    protected void setWriter(DumpWriter writer) {
+        this.writer = writer;
+    }
+
+    protected void setWriter(WritableByteChannel channel) {
+        setWriter(new ChannelDumpWriter(channel));
+    }
+
+    protected void setWriter(SocketAddress remote) throws IOException {
+        setWriter(SocketChannel.open(remote));
+    }
+
+    protected void setWriter(Path path) throws IOException {
+        setWriter(path, WRITE, TRUNCATE_EXISTING, CREATE);
+    }
+
+    protected void setWriter(Path path, OpenOption... options) throws IOException {
+        setWriter(FileChannel.open(path, options));
+    }
+
+    public D getDumper() {
+        return dumper;
+    }
+
+    protected void setDumper(D dumper) {
+        this.dumper = dumper;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (dumper != null) {
+            try {
+                dumper.close();
+            } finally {
+                dumper = null;
+            }
+        }
+        if (writer != null) {
+            try {
+                writer.close();
+            } finally {
+                writer = null;
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractGraalDumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractGraalDumpHandler.java
new file mode 100644
index 0000000..c3a6302
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/AbstractGraalDumpHandler.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.handler;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.ClosedByInterruptException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.salver.Salver;
+import org.graalvm.compiler.salver.SalverOptions;
+import org.graalvm.compiler.salver.dumper.AbstractGraalDumper;
+import org.graalvm.compiler.salver.serialize.JSONSerializer;
+import org.graalvm.compiler.salver.serialize.Serializer;
+
+public abstract class AbstractGraalDumpHandler<D extends AbstractGraalDumper> extends AbstractDumpHandler<D> implements DebugDumpHandler {
+
+    private Serializer serializer;
+
+    private static final int MAX_FAILURES = 7;
+    private int failures;
+
+    public static final class NotInitializedException extends IOException {
+
+        private static final long serialVersionUID = 1L;
+    }
+
+    protected void ensureInitialized() throws IOException {
+        if (writer == null) {
+            if (failures < MAX_FAILURES) {
+                if (SalverOptions.SalverToFile.getValue()) {
+                    initializeFileChannelWriter();
+                } else {
+                    initializeSocketChannelWriter();
+                }
+            }
+            if (writer == null) {
+                throw new NotInitializedException();
+            }
+        }
+        if (dumper == null) {
+            dumper = createDumper();
+            if (dumper == null) {
+                throw new NotInitializedException();
+            }
+            if (serializer == null) {
+                serializer = createSerializer();
+            }
+            if (serializer.getWriter() != writer) {
+                serializer.setWriter(writer);
+            }
+            dumper.setSerializer(serializer);
+            dumper.beginDump();
+        }
+    }
+
+    protected abstract D createDumper();
+
+    protected Serializer createSerializer() {
+        return new JSONSerializer();
+    }
+
+    protected abstract void handle(Object obj, String msg) throws IOException;
+
+    protected void initializeSocketChannelWriter() {
+        InetSocketAddress socketAddress = Salver.getSocketAddress();
+        try {
+            setWriter(socketAddress);
+            printlnTTY("Connected to %s:%d (ECID = %s)", socketAddress.getHostName(), socketAddress.getPort(), Salver.ECID);
+        } catch (ClosedByInterruptException e) {
+            // May be caused by a cancelled Graal compilation
+        } catch (IOException e) {
+            printlnTTY("Couldn't connect to %s:%d (%s)", socketAddress.getHostName(), socketAddress.getPort(), e);
+            failures++;
+        }
+    }
+
+    private static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+            return new SimpleDateFormat("YYYY-MM-dd_HH-mm");
+        }
+    };
+
+    protected void initializeFileChannelWriter() {
+        String filename = sdf.get().format(new Date());
+        if (label != null) {
+            filename += "_" + Salver.ECID + "_" + label.replaceAll("(?i)[^a-z0-9-]", "-");
+        }
+        String fileExt = JSONSerializer.getFileExtension();
+        File file = new File(filename + "." + fileExt);
+        try {
+            for (int i = 1; file.exists(); i++) {
+                if (i < 1 << 7) {
+                    file = new File(filename + "_" + i + "." + fileExt);
+                } else {
+                    throw new IOException();
+                }
+            }
+            setWriter(file.toPath());
+            printlnTTY("Dumping to \"%s\"", file.getName());
+        } catch (ClosedByInterruptException e) {
+            // May be caused by a cancelled Graal compilation
+        } catch (IOException e) {
+            printlnTTY("Failed to open %s for dumping (%s)", file.getName(), e);
+            failures++;
+        }
+    }
+
+    public void dump(Object obj) {
+        dump(obj, null);
+    }
+
+    @Override
+    public void dump(Object obj, String msg) {
+        try {
+            handle(obj, msg);
+        } catch (NotInitializedException e) {
+            // Ignore
+        } catch (IOException e) {
+            printlnTTY("%s", e);
+            if (failures < MAX_FAILURES) {
+                failures++;
+            } else {
+                close();
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        try {
+            super.close();
+        } catch (IOException e) {
+            printlnTTY("%s", e);
+        } finally {
+            failures = 0;
+        }
+    }
+
+    protected void printlnTTY(String format, Object... args) {
+        if (label != null) {
+            TTY.println("[" + label + "] " + format, args);
+        } else {
+            TTY.println(format, args);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/DumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/DumpHandler.java
new file mode 100644
index 0000000..2ef16a8
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/DumpHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.handler;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public interface DumpHandler extends Closeable, AutoCloseable {
+
+    void dump(Object obj, String msg) throws IOException;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/GraphDumpHandler.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/GraphDumpHandler.java
new file mode 100644
index 0000000..4862d4c
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/handler/GraphDumpHandler.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.handler;
+
+import java.io.IOException;
+
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.salver.dumper.GraphDumper;
+
+public class GraphDumpHandler extends AbstractGraalDumpHandler<GraphDumper> {
+
+    @Override
+    protected GraphDumper createDumper() {
+        return new GraphDumper();
+    }
+
+    @Override
+    public void handle(Object obj, String msg) throws IOException {
+        if (obj instanceof Graph) {
+            ensureInitialized();
+            dumper.dump((Graph) obj, msg);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/package-info.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/package-info.java
new file mode 100644
index 0000000..02d5cb5
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/package-info.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/**
+ * <p>
+ * This package provides the basic functionality to send debug dumps to a server that is able to
+ * process Salver trace events.
+ * </p>
+ *
+ * <p>
+ * Salver is a Web Application Framework for Trace Visualization which defines an interface for
+ * sending trace information via serializable events, e.g. as JSON text representation. Events are
+ * grouped into separate namespaces to simplify event processing. Listeners can register for a
+ * certain namespace and will receive all relevant events.
+ * </p>
+ *
+ * <p>
+ * In order to process trace events of this package the server needs to listen for the "graal/graph"
+ * namespace.
+ * </p>
+ *
+ * <p>
+ * See {@link org.graalvm.compiler.salver.SalverOptions SalverOptions} for all available options.
+ * <p>
+ *
+ * <p>
+ * Basic components of this package:
+ * <ul>
+ * <li>DumpHandler:<br/>
+ * Initialization of the corresponding Dumper in case a given object can be processed.</li>
+ * <li>Dumper:<br/>
+ * Processing the object about to be dumped and extract all necessary information in order to
+ * produce a serializable data object.</li>
+ * <li>Serializer:<br/>
+ * Serializing a given data object, e.g. to a JSON text representation.</li>
+ * <li>Writer:<br/>
+ * Writing the actual data, e.g. to a WritableByteChannel.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Currently available {@link org.graalvm.compiler.debug.DebugDumpHandler DebugDumpHandlers}:
+ * <ul>
+ * <li>{@link org.graalvm.compiler.salver.handler.GraphDumpHandler GraphDumpHandler}:<br>
+ * Dumps {@link org.graalvm.compiler.graph.Graph Graphs} (extracts almost the same information as
+ * IGV's dump handler).</li>
+ * </ul>
+ * </p>
+ */
+package org.graalvm.compiler.salver;
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/AbstractSerializer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/AbstractSerializer.java
new file mode 100644
index 0000000..1ed9f8f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/AbstractSerializer.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.serialize;
+
+import java.io.IOException;
+
+import org.graalvm.compiler.salver.writer.DumpWriter;
+
+public abstract class AbstractSerializer implements Serializer {
+
+    protected DumpWriter writer;
+
+    public AbstractSerializer() {
+    }
+
+    public AbstractSerializer(DumpWriter writer) {
+        if (writer != null) {
+            setWriter(writer);
+        }
+    }
+
+    @Override
+    public DumpWriter getWriter() {
+        return writer;
+    }
+
+    @Override
+    public void setWriter(DumpWriter writer) {
+        this.writer = writer;
+    }
+
+    @Override
+    public void reset() throws IOException {
+    }
+
+    @Override
+    public void flush() throws IOException {
+        if (writer != null) {
+            writer.flush();
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/JSONSerializer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/JSONSerializer.java
new file mode 100644
index 0000000..6bdae2f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/JSONSerializer.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.serialize;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.salver.writer.DumpWriter;
+
+public class JSONSerializer extends AbstractSerializer {
+
+    public static final String MEDIA_TYPE = "application/json";
+    public static final String FILE_EXTENSION = "json";
+
+    public JSONSerializer() {
+    }
+
+    public JSONSerializer(DumpWriter writer) {
+        super(writer);
+    }
+
+    @Override
+    public JSONSerializer serialize(Object obj) throws IOException {
+        if (writer != null) {
+            writer.write(appendValue(new StringBuilder(), obj).append('\n'));
+        }
+        return this;
+    }
+
+    public static StringBuilder stringify(StringBuilder sb, Object obj) {
+        return appendValue(sb, obj);
+    }
+
+    public static String stringify(Object obj) {
+        return appendValue(new StringBuilder(), obj).toString();
+    }
+
+    public static String getMediaType() {
+        return MEDIA_TYPE;
+    }
+
+    public static String getFileExtension() {
+        return FILE_EXTENSION;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static StringBuilder appendValue(StringBuilder sb, Object val) {
+        if (val instanceof Map<?, ?>) {
+            return appendDict(sb, (Map<Object, Object>) val);
+        }
+        if (val instanceof List<?>) {
+            return appendList(sb, (List<Object>) val);
+        }
+        if (val instanceof byte[]) {
+            return appendByteArray(sb, (byte[]) val);
+        }
+        if (val instanceof Number) {
+            return sb.append(val);
+        }
+        if (val instanceof Boolean) {
+            return sb.append(val);
+        }
+        if (val == null) {
+            return sb.append("null");
+        }
+        return appendString(sb, String.valueOf(val));
+    }
+
+    private static StringBuilder appendDict(StringBuilder sb, Map<Object, Object> dict) {
+        sb.append('{');
+        boolean comma = false;
+        for (Map.Entry<Object, Object> entry : dict.entrySet()) {
+            if (comma) {
+                sb.append(',');
+            } else {
+                comma = true;
+            }
+            appendString(sb, String.valueOf(entry.getKey()));
+            sb.append(':');
+            appendValue(sb, entry.getValue());
+        }
+        return sb.append('}');
+    }
+
+    private static StringBuilder appendList(StringBuilder sb, List<Object> list) {
+        sb.append('[');
+        boolean comma = false;
+        for (Object val : list) {
+            if (comma) {
+                sb.append(',');
+            } else {
+                comma = true;
+            }
+            appendValue(sb, val);
+        }
+        return sb.append(']');
+    }
+
+    private static StringBuilder appendString(StringBuilder sb, String str) {
+        sb.append('"');
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            switch (c) {
+                case '"':
+                    sb.append("\\\"");
+                    break;
+                case '\\':
+                    sb.append("\\\\");
+                    break;
+                case '\b':
+                    sb.append("\\b");
+                    break;
+                case '\f':
+                    sb.append("\\f");
+                    break;
+                case '\n':
+                    sb.append("\\n");
+                    break;
+                case '\r':
+                    sb.append("\\r");
+                    break;
+                case '\t':
+                    sb.append("\\t");
+                    break;
+                default: {
+                    if (Character.isISOControl(c)) {
+                        sb.append("\\u00");
+                        sb.append(Character.forDigit((c >> 4) & 0xF, 16));
+                        sb.append(Character.forDigit(c & 0xF, 16));
+                    } else {
+                        sb.append(c);
+                    }
+                }
+            }
+        }
+        return sb.append('"');
+    }
+
+    private static StringBuilder appendByteArray(StringBuilder sb, byte[] arr) {
+        if (arr.length > 0) {
+            sb.append("0x");
+            for (byte b : arr) {
+                sb.append(String.format("%02x", b));
+            }
+            return sb;
+        }
+        return sb.append("null");
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/Serializer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/Serializer.java
new file mode 100644
index 0000000..e921aed6
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/serialize/Serializer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.serialize;
+
+import java.io.Flushable;
+import java.io.IOException;
+
+import org.graalvm.compiler.salver.writer.DumpWriter;
+
+public interface Serializer extends Flushable {
+
+    DumpWriter getWriter();
+
+    void setWriter(DumpWriter writer);
+
+    Serializer serialize(Object obj) throws IOException;
+
+    void reset() throws IOException;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/ECIDUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/ECIDUtil.java
new file mode 100644
index 0000000..3b9428f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/ECIDUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.util;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+public class ECIDUtil {
+
+    private static final Random RANDOM = new SecureRandom();
+
+    private static final String BASE58_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789";
+
+    public static String random() {
+        return random(8);
+    }
+
+    public static String random(int length) {
+        StringBuilder sb = new StringBuilder();
+        byte[] bytes = new byte[length];
+        RANDOM.nextBytes(bytes);
+        for (byte b : bytes) {
+            sb.append(BASE58_ALPHABET.charAt((b & 0xff) % 58));
+        }
+        return sb.toString();
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/MethodContext.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/MethodContext.java
new file mode 100644
index 0000000..275bd09
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/util/MethodContext.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.util;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.asJavaMethod;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.salver.util.MethodContext.Item;
+
+import jdk.vm.ci.meta.JavaMethod;
+
+public class MethodContext extends ArrayList<Item> {
+
+    private static final long serialVersionUID = 1L;
+
+    public static final class Item {
+
+        private String name;
+        private JavaMethod method;
+        private int debugId;
+
+        private Item(String name, JavaMethod method, int debugId) {
+            this.name = name;
+            this.method = method;
+            this.debugId = debugId;
+        }
+
+        private Item(JavaMethod method) {
+            this(method.format("%H::%n(%p)"), method, -1);
+        }
+
+        private Item(String name) {
+            this(name, null, -1);
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public JavaMethod getMethod() {
+            return method;
+        }
+
+        public int getDebugId() {
+            return debugId;
+        }
+    }
+
+    public MethodContext() {
+        Object lastMethodOrGraph = null;
+        for (Object obj : Debug.context()) {
+            JavaMethod method = asJavaMethod(obj);
+            if (method != null) {
+                JavaMethod lastAsMethod = asJavaMethod(lastMethodOrGraph);
+                if (lastAsMethod == null || !lastAsMethod.equals(method)) {
+                    add(new Item(method));
+                } else {
+                    /*
+                     * This prevents multiple adjacent method context objects for the same method
+                     * from resulting in multiple IGV tree levels. This works on the assumption that
+                     * real inlining debug scopes will have a graph context object between the
+                     * inliner and inlinee context objects.
+                     */
+                }
+            } else if (obj instanceof DebugDumpScope) {
+                DebugDumpScope debugDumpScope = (DebugDumpScope) obj;
+                if (debugDumpScope.decorator && !isEmpty()) {
+                    try {
+                        get(size() - 1).debugId = Integer.parseInt(debugDumpScope.name);
+                    } catch (NumberFormatException e) {
+                        // Ignore
+                    }
+                } else {
+                    add(new Item(debugDumpScope.name));
+                }
+            }
+            if (obj instanceof JavaMethod || obj instanceof Graph) {
+                lastMethodOrGraph = obj;
+            }
+        }
+        if (isEmpty()) {
+            add(new Item("Top Scope"));
+        }
+    }
+
+    public boolean itemEquals(int index, MethodContext context) {
+        Item i1 = get(index);
+        Item i2 = context != null ? context.get(index) : null;
+        if (i1 != null && i2 != null && i1.name != null && i2.name != null) {
+            return i1.name.equals(i2.name) && i1.debugId == i2.debugId;
+        }
+        return false;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/ChannelDumpWriter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/ChannelDumpWriter.java
new file mode 100644
index 0000000..5cfa4a1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/ChannelDumpWriter.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.writer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.nio.channels.WritableByteChannel;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.StandardCharsets;
+
+public class ChannelDumpWriter implements DumpWriter {
+
+    private static final int BUFFER_CAPACITY = 256 * 1024;
+
+    protected final WritableByteChannel channel;
+    protected final ByteBuffer buffer;
+
+    public ChannelDumpWriter(WritableByteChannel channel) {
+        this(channel, ByteBuffer.allocateDirect(BUFFER_CAPACITY));
+    }
+
+    public ChannelDumpWriter(WritableByteChannel channel, ByteBuffer buffer) {
+        this.channel = channel;
+        this.buffer = buffer;
+    }
+
+    private void ensureAvailable(int len) throws IOException {
+        if (buffer.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        if (buffer.capacity() < len) {
+            throw new IllegalArgumentException();
+        }
+        while (buffer.remaining() < len) {
+            flush();
+        }
+    }
+
+    @Override
+    public ChannelDumpWriter write(byte b) throws IOException {
+        ensureAvailable(1);
+        buffer.put(b);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter write(byte[] arr) throws IOException {
+        if (buffer.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        int offset = 0;
+        while (offset < arr.length) {
+            int available = buffer.remaining();
+            int length = Math.min(available, arr.length - offset);
+            buffer.put(arr, offset, length);
+            if (!buffer.hasRemaining()) {
+                flush();
+            }
+            offset += length;
+        }
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter write(ByteBuffer buf) throws IOException {
+        if (buf == buffer) {
+            throw new IllegalArgumentException();
+        }
+        if (buffer.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        while (buf.hasRemaining()) {
+            int available = buffer.remaining();
+            int remaining = buf.remaining();
+            for (int i = 0, n = Math.min(available, remaining); i < n; i++) {
+                buffer.put(buf.get());
+            }
+            if (!buffer.hasRemaining()) {
+                flush();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter write(CharSequence csq) throws IOException {
+        if (buffer.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
+        CharBuffer buf = CharBuffer.wrap(csq);
+        while (true) {
+            CoderResult result = encoder.encode(buf, buffer, true);
+            if (result.isError()) {
+                throw new IOException(result.toString());
+            }
+            if (!buffer.hasRemaining()) {
+                flush();
+            }
+            if (result.isOverflow()) {
+                continue;
+            }
+            break;
+        }
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeChar(char v) throws IOException {
+        ensureAvailable(1 << 1);
+        buffer.putChar(v);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeShort(short v) throws IOException {
+        ensureAvailable(1 << 1);
+        buffer.putShort(v);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeInt(int v) throws IOException {
+        ensureAvailable(1 << 2);
+        buffer.putInt(v);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeLong(long v) throws IOException {
+        ensureAvailable(1 << 3);
+        buffer.putLong(v);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeFloat(float v) throws IOException {
+        ensureAvailable(1 << 2);
+        buffer.putFloat(v);
+        return this;
+    }
+
+    @Override
+    public ChannelDumpWriter writeDouble(double v) throws IOException {
+        ensureAvailable(1 << 3);
+        buffer.putDouble(v);
+        return this;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        if (buffer != null && channel != null) {
+            buffer.flip();
+            channel.write(buffer);
+            buffer.compact();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (channel != null) {
+            try {
+                flush();
+            } finally {
+                channel.close();
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/DumpWriter.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/DumpWriter.java
new file mode 100644
index 0000000..47a7ca3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.salver/src/org/graalvm/compiler/salver/writer/DumpWriter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.salver.writer;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public interface DumpWriter extends Closeable, Flushable, AutoCloseable {
+
+    DumpWriter write(byte b) throws IOException;
+
+    DumpWriter write(byte[] arr) throws IOException;
+
+    DumpWriter write(ByteBuffer buf) throws IOException;
+
+    DumpWriter write(CharSequence csq) throws IOException;
+
+    DumpWriter writeChar(char v) throws IOException;
+
+    DumpWriter writeShort(short v) throws IOException;
+
+    DumpWriter writeInt(int v) throws IOException;
+
+    DumpWriter writeLong(long v) throws IOException;
+
+    DumpWriter writeFloat(float v) throws IOException;
+
+    DumpWriter writeDouble(double v) throws IOException;
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..cb8c81d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.graalvm.compiler.serviceprovider.processor.ServiceProviderProcessor
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java
new file mode 100644
index 0000000..d21e862
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.serviceprovider.processor;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+/**
+ * Processes classes annotated with {@link ServiceProvider}. For a service defined by {@code S} and
+ * a class {@code P} implementing the service, this processor generates the file
+ * {@code META-INF/providers/P} whose contents are a single line containing the fully qualified name
+ * of {@code S}.
+ */
+@SupportedAnnotationTypes("org.graalvm.compiler.serviceprovider.ServiceProvider")
+public class ServiceProviderProcessor extends AbstractProcessor {
+
+    private final Set<TypeElement> processed = new HashSet<>();
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) {
+        if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) {
+            String msg = String.format("Service provider class %s must implement service interface %s", serviceProvider.getSimpleName(), serviceInterface);
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+            return false;
+        }
+
+        return true;
+    }
+
+    private void processElement(TypeElement serviceProvider) {
+        if (processed.contains(serviceProvider)) {
+            return;
+        }
+
+        processed.add(serviceProvider);
+        ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class);
+        if (annotation != null) {
+            try {
+                annotation.value();
+            } catch (MirroredTypeException ex) {
+                TypeMirror serviceInterface = ex.getTypeMirror();
+                if (verifyAnnotation(serviceInterface, serviceProvider)) {
+                    String interfaceName = ex.getTypeMirror().toString();
+                    createProviderFile(serviceProvider, interfaceName);
+                }
+            }
+        }
+    }
+
+    private void createProviderFile(TypeElement serviceProvider, String interfaceName) {
+        if (serviceProvider.getNestingKind().isNested()) {
+            // This is a simplifying constraint that means we don't have to
+            // processed the qualified name to insert '$' characters at
+            // the relevant positions.
+            String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+            return;
+        }
+
+        String filename = "META-INF/providers/" + serviceProvider.getQualifiedName();
+        try {
+            FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider);
+            PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+            writer.println(interfaceName);
+            writer.close();
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(isBug367599(e) ? Kind.NOTE : Kind.ERROR, e.getMessage(), serviceProvider);
+        }
+    }
+
+    /**
+     * Determines if a given exception is (most likely) caused by
+     * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
+     */
+    public static boolean isBug367599(Throwable t) {
+        if (t instanceof FilerException) {
+            for (StackTraceElement ste : t.getStackTrace()) {
+                if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
+                    // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
+                    return true;
+                }
+            }
+        }
+        if (t.getCause() != null) {
+            return isBug367599(t.getCause());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
+            assert element.getKind().isClass();
+            processElement((TypeElement) element);
+        }
+
+        return true;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
new file mode 100644
index 0000000..483cf77
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.serviceprovider;
+
+import java.util.Iterator;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+
+import jdk.vm.ci.services.JVMCIPermission;
+import jdk.vm.ci.services.Services;
+
+/**
+ * A mechanism for accessing service providers that abstracts over whether Graal is running on
+ * JVMCI-8 or JVMCI-9. In JVMCI-8, a JVMCI specific mechanism is used to lookup services via the
+ * hidden JVMCI class loader. in JVMCI-9, the standard {@link ServiceLoader} mechanism is used.
+ */
+public final class GraalServices {
+
+    private GraalServices() {
+    }
+
+    public static final boolean Java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+
+    /**
+     * Gets an {@link Iterable} of the providers available for a given service.
+     *
+     * @throws SecurityException if on JDK8 and a security manager is present and it denies
+     *             {@link JVMCIPermission}
+     */
+    public static <S> Iterable<S> load(Class<S> service) {
+        assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
+        if (Java8OrEarlier) {
+            return Services.load(service);
+        }
+        ServiceLoader<S> iterable = ServiceLoader.load(service);
+        return new Iterable<S>() {
+            @Override
+            public Iterator<S> iterator() {
+                Iterator<S> iterator = iterable.iterator();
+                return new Iterator<S>() {
+                    @Override
+                    public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    @Override
+                    public S next() {
+                        S provider = iterator.next();
+                        // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission
+                        Services.exportJVMCITo(provider.getClass());
+                        return provider;
+                    }
+
+                    @Override
+                    public void remove() {
+                        iterator.remove();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Gets the provider for a given service for which at most one provider must be available.
+     *
+     * @param service the service whose provider is being requested
+     * @param required specifies if an {@link InternalError} should be thrown if no provider of
+     *            {@code service} is available
+     * @return the requested provider if available else {@code null}
+     * @throws SecurityException if on JDK8 and a security manager is present and it denies
+     *             {@link JVMCIPermission}
+     */
+    public static <S> S loadSingle(Class<S> service, boolean required) {
+        assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
+        if (Java8OrEarlier) {
+            return Services.loadSingle(service, required);
+        }
+        Iterable<S> providers = ServiceLoader.load(service);
+        S singleProvider = null;
+        try {
+            for (Iterator<S> it = providers.iterator(); it.hasNext();) {
+                singleProvider = it.next();
+                if (it.hasNext()) {
+                    throw new InternalError(String.format("Multiple %s providers found", service.getName()));
+                }
+            }
+        } catch (ServiceConfigurationError e) {
+            // If the service is required we will bail out below.
+        }
+        if (singleProvider == null) {
+            if (required) {
+                throw new InternalError(String.format("No provider for %s found", service.getName()));
+            }
+        } else {
+            // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission
+            Services.exportJVMCITo(singleProvider.getClass());
+        }
+        return singleProvider;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/ServiceProvider.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/ServiceProvider.java
new file mode 100644
index 0000000..24810e2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/ServiceProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.serviceprovider;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a service provider that will have a provider file generated by an annotation processor.
+ * For a service defined by {@code S} and a class {@code P} implementing the service, the processor
+ * generates the file {@code META-INF/providers/P} whose contents are a single line containing the
+ * fully qualified name of {@code S}.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ServiceProvider {
+
+    /**
+     * The interface or class defining the service implemented by the annotated class.
+     */
+    Class<?> value();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java
new file mode 100644
index 0000000..e139b19
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.test;
+
+/**
+ * A class loader that exports all packages in the module defining the class loader to all classes
+ * in the unnamed module associated with the loader.
+ */
+public class ExportingClassLoader extends ClassLoader {
+    public ExportingClassLoader() {
+        if (!GraalTest.Java8OrEarlier) {
+            JLRModule.fromClass(getClass()).exportAllPackagesTo(JLRModule.getUnnamedModuleFor(this));
+        }
+    }
+
+    public ExportingClassLoader(ClassLoader parent) {
+        super(parent);
+        if (!GraalTest.Java8OrEarlier) {
+            JLRModule.fromClass(getClass()).exportAllPackagesTo(JLRModule.getUnnamedModuleFor(this));
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java
new file mode 100644
index 0000000..a285c66
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.test;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.internal.ComparisonCriteria;
+import org.junit.internal.ExactComparisonCriteria;
+
+import sun.misc.Unsafe;
+
+/**
+ * Base class that contains common utility methods and classes useful in unit tests.
+ */
+public class GraalTest {
+
+    public static final Unsafe UNSAFE;
+    static {
+        try {
+            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafe.setAccessible(true);
+            UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("exception while trying to get Unsafe", e);
+        }
+    }
+
+    public static final boolean Java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+
+    protected Method getMethod(String methodName) {
+        return getMethod(getClass(), methodName);
+    }
+
+    protected Method getMethod(Class<?> clazz, String methodName) {
+        Method found = null;
+        for (Method m : clazz.getMethods()) {
+            if (m.getName().equals(methodName)) {
+                Assert.assertNull(found);
+                found = m;
+            }
+        }
+        if (found == null) {
+            /* Now look for non-public methods (but this does not look in superclasses). */
+            for (Method m : clazz.getDeclaredMethods()) {
+                if (m.getName().equals(methodName)) {
+                    Assert.assertNull(found);
+                    found = m;
+                }
+            }
+        }
+        if (found != null) {
+            return found;
+        } else {
+            throw new RuntimeException("method not found: " + methodName);
+        }
+    }
+
+    protected Method getMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
+        try {
+            return clazz.getMethod(methodName, parameterTypes);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes));
+        }
+    }
+
+    /**
+     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+     * Does a deep copy equality comparison if {@code expected} is an array.
+     */
+    protected void assertDeepEquals(Object expected, Object actual) {
+        assertDeepEquals(null, expected, actual);
+    }
+
+    /**
+     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+     * Does a deep copy equality comparison if {@code expected} is an array.
+     *
+     * @param message the identifying message for the {@link AssertionError}
+     */
+    protected void assertDeepEquals(String message, Object expected, Object actual) {
+        if (ulpsDelta() > 0) {
+            assertDeepEquals(message, expected, actual, ulpsDelta());
+        } else {
+            assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
+        }
+    }
+
+    /**
+     * Compares two given values for equality, doing a recursive test if both values are arrays of
+     * the same type.
+     *
+     * @param message the identifying message for the {@link AssertionError}
+     * @param delta the maximum delta between two doubles or floats for which both numbers are still
+     *            considered equal.
+     */
+    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+        if (expected != null && actual != null) {
+            Class<?> expectedClass = expected.getClass();
+            Class<?> actualClass = actual.getClass();
+            if (expectedClass.isArray()) {
+                Assert.assertTrue(message, expected != null);
+                Assert.assertTrue(message, actual != null);
+                Assert.assertEquals(message, expectedClass, actual.getClass());
+                if (expected instanceof int[]) {
+                    Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual);
+                } else if (expected instanceof byte[]) {
+                    Assert.assertArrayEquals(message, (byte[]) expected, (byte[]) actual);
+                } else if (expected instanceof char[]) {
+                    Assert.assertArrayEquals(message, (char[]) expected, (char[]) actual);
+                } else if (expected instanceof short[]) {
+                    Assert.assertArrayEquals(message, (short[]) expected, (short[]) actual);
+                } else if (expected instanceof float[]) {
+                    Assert.assertArrayEquals(message, (float[]) expected, (float[]) actual, (float) delta);
+                } else if (expected instanceof long[]) {
+                    Assert.assertArrayEquals(message, (long[]) expected, (long[]) actual);
+                } else if (expected instanceof double[]) {
+                    Assert.assertArrayEquals(message, (double[]) expected, (double[]) actual, delta);
+                } else if (expected instanceof boolean[]) {
+                    new ExactComparisonCriteria().arrayEquals(message, expected, actual);
+                } else if (expected instanceof Object[]) {
+                    new ComparisonCriteria() {
+                        @Override
+                        protected void assertElementsEqual(Object e, Object a) {
+                            assertDeepEquals(message, e, a, delta);
+                        }
+                    }.arrayEquals(message, expected, actual);
+                } else {
+                    Assert.fail((message == null ? "" : message) + "non-array value encountered: " + expected);
+                }
+            } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
+                Assert.assertEquals((double) expected, (double) actual, delta);
+            } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
+                Assert.assertEquals((float) expected, (float) actual, delta);
+            } else {
+                Assert.assertEquals(message, expected, actual);
+            }
+        } else {
+            Assert.assertEquals(message, expected, actual);
+        }
+    }
+
+    /**
+     * Compares two given values for equality, doing a recursive test if both values are arrays of
+     * the same type. Uses {@linkplain StrictMath#ulp(float) ULP}s for comparison of floats.
+     *
+     * @param message the identifying message for the {@link AssertionError}
+     * @param ulpsDelta the maximum allowed ulps difference between two doubles or floats for which
+     *            both numbers are still considered equal.
+     */
+    protected void assertDeepEquals(String message, Object expected, Object actual, int ulpsDelta) {
+        ComparisonCriteria doubleUlpsDeltaCriteria = new ComparisonCriteria() {
+            @Override
+            protected void assertElementsEqual(Object e, Object a) {
+                assertTrue(message, e instanceof Double && a instanceof Double);
+                // determine acceptable error based on whether it is a normal number or a NaN/Inf
+                double de = (Double) e;
+                double epsilon = (!Double.isNaN(de) && Double.isFinite(de) ? ulpsDelta * Math.ulp(de) : 0);
+                Assert.assertEquals(message, (Double) e, (Double) a, epsilon);
+            }
+        };
+
+        ComparisonCriteria floatUlpsDeltaCriteria = new ComparisonCriteria() {
+            @Override
+            protected void assertElementsEqual(Object e, Object a) {
+                assertTrue(message, e instanceof Float && a instanceof Float);
+                // determine acceptable error based on whether it is a normal number or a NaN/Inf
+                float fe = (Float) e;
+                float epsilon = (!Float.isNaN(fe) && Float.isFinite(fe) ? ulpsDelta * Math.ulp(fe) : 0);
+                Assert.assertEquals(message, (Float) e, (Float) a, epsilon);
+            }
+        };
+
+        if (expected != null && actual != null) {
+            Class<?> expectedClass = expected.getClass();
+            Class<?> actualClass = actual.getClass();
+            if (expectedClass.isArray()) {
+                Assert.assertEquals(message, expectedClass, actualClass);
+                if (expected instanceof double[] || expected instanceof Object[]) {
+                    doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual);
+                    return;
+                } else if (expected instanceof float[] || expected instanceof Object[]) {
+                    floatUlpsDeltaCriteria.arrayEquals(message, expected, actual);
+                    return;
+                }
+            } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
+                doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual);
+                return;
+            } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
+                floatUlpsDeltaCriteria.arrayEquals(message, expected, actual);
+                return;
+            }
+        }
+        // anything else just use the non-ulps version
+        assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
+    }
+
+    /**
+     * Gets the value used by {@link #assertDeepEquals(Object, Object)} and
+     * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles
+     * or floats for which both numbers are still considered equal.
+     */
+    protected double equalFloatsOrDoublesDelta() {
+        return 0.0D;
+    }
+
+    // unless overridden ulpsDelta is not used
+    protected int ulpsDelta() {
+        return 0;
+    }
+
+    @SuppressWarnings("serial")
+    public static class MultiCauseAssertionError extends AssertionError {
+
+        private Throwable[] causes;
+
+        public MultiCauseAssertionError(String message, Throwable... causes) {
+            super(message);
+            this.causes = causes;
+        }
+
+        @Override
+        public void printStackTrace(PrintStream out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++));
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+
+        @Override
+        public void printStackTrace(PrintWriter out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++) + ": ");
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+    }
+
+    /*
+     * Overrides to the normal JUnit {@link Assert} routines that provide varargs style formatting
+     * and produce an exception stack trace with the assertion frames trimmed out.
+     */
+
+    /**
+     * Fails a test with the given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     *            okay)
+     * @see AssertionError
+     */
+    public static void fail(String message, Object... objects) {
+        AssertionError e;
+        if (message == null) {
+            e = new AssertionError();
+        } else {
+            e = new AssertionError(String.format(message, objects));
+        }
+        // Trim the assert frames from the stack trace
+        StackTraceElement[] trace = e.getStackTrace();
+        int start = 1; // Skip this frame
+        String thisClassName = GraalTest.class.getName();
+        while (start < trace.length && trace[start].getClassName().equals(thisClassName) && (trace[start].getMethodName().equals("assertTrue") || trace[start].getMethodName().equals("assertFalse"))) {
+            start++;
+        }
+        e.setStackTrace(Arrays.copyOfRange(trace, start, trace.length));
+        throw e;
+    }
+
+    /**
+     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the
+     * given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     *            okay)
+     * @param condition condition to be checked
+     */
+    public static void assertTrue(String message, boolean condition) {
+        assertTrue(condition, message);
+    }
+
+    /**
+     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} without a
+     * message.
+     *
+     * @param condition condition to be checked
+     */
+    public static void assertTrue(boolean condition) {
+        assertTrue(condition, null);
+    }
+
+    /**
+     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the
+     * given message.
+     *
+     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
+     *            okay)
+     * @param condition condition to be checked
+     */
+    public static void assertFalse(String message, boolean condition) {
+        assertTrue(!condition, message);
+    }
+
+    /**
+     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} without a
+     * message.
+     *
+     * @param condition condition to be checked
+     */
+    public static void assertFalse(boolean condition) {
+        assertTrue(!condition, null);
+    }
+
+    /**
+     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the
+     * given message.
+     *
+     * @param condition condition to be checked
+     * @param message the identifying message for the {@link AssertionError}
+     * @param objects arguments to the format string
+     */
+    public static void assertTrue(boolean condition, String message, Object... objects) {
+        if (!condition) {
+            fail(message, objects);
+        }
+    }
+
+    /**
+     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the
+     * given message produced by {@link String#format}.
+     *
+     * @param condition condition to be checked
+     * @param message the identifying message for the {@link AssertionError}
+     * @param objects arguments to the format string
+     */
+    public static void assertFalse(boolean condition, String message, Object... objects) {
+        assertTrue(!condition, message, objects);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLRModule.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLRModule.java
new file mode 100644
index 0000000..caa3223
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLRModule.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.test;
+
+import java.lang.reflect.Method;
+
+/**
+ * Facade for the {@code java.lang.reflect.Module} class introduced in JDK9 that allows tests to be
+ * developed against JDK8 but use module logic if deployed on JDK9.
+ */
+public class JLRModule {
+
+    static {
+        if (GraalTest.Java8OrEarlier) {
+            throw new AssertionError("Use of " + JLRModule.class + " only allowed if " + GraalTest.class.getName() + ".JDK8OrEarlier is false");
+        }
+    }
+
+    private final Object realModule;
+
+    public JLRModule(Object module) {
+        this.realModule = module;
+    }
+
+    private static final Class<?> moduleClass;
+    private static final Method getModuleMethod;
+    private static final Method getUnnamedModuleMethod;
+    private static final Method getPackagesMethod;
+    private static final Method isExportedMethod;
+    private static final Method isExported2Method;
+    private static final Method addExportsMethod;
+    static {
+        try {
+            moduleClass = Class.forName("java.lang.reflect.Module");
+            getModuleMethod = Class.class.getMethod("getModule");
+            getUnnamedModuleMethod = ClassLoader.class.getMethod("getUnnamedModule");
+            getPackagesMethod = moduleClass.getMethod("getPackages");
+            isExportedMethod = moduleClass.getMethod("isExported", String.class);
+            isExported2Method = moduleClass.getMethod("isExported", String.class, moduleClass);
+            addExportsMethod = moduleClass.getMethod("addExports", String.class, moduleClass);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static JLRModule fromClass(Class<?> cls) {
+        try {
+            return new JLRModule(getModuleMethod.invoke(cls));
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static JLRModule getUnnamedModuleFor(ClassLoader cl) {
+        try {
+            return new JLRModule(getUnnamedModuleMethod.invoke(cl));
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Exports all packages in this module to a given module.
+     */
+    public void exportAllPackagesTo(JLRModule module) {
+        if (this != module) {
+            for (String pkg : getPackages()) {
+                // Export all JVMCI packages dynamically instead
+                // of requiring a long list of -XaddExports
+                // options on the JVM command line.
+                if (!isExported(pkg, module)) {
+                    addExports(pkg, module);
+                }
+            }
+        }
+    }
+
+    public String[] getPackages() {
+        try {
+            return (String[]) getPackagesMethod.invoke(realModule);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public boolean isExported(String pn) {
+        try {
+            return (Boolean) isExportedMethod.invoke(realModule, pn);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public boolean isExported(String pn, JLRModule other) {
+        try {
+            return (Boolean) isExported2Method.invoke(realModule, pn, other.realModule);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public void addExports(String pn, JLRModule other) {
+        try {
+            addExportsMethod.invoke(realModule, pn, other.realModule);
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java
new file mode 100644
index 0000000..bf1ca3d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Utility methods for spawning a VM in a subprocess during unit tests.
+ */
+public final class SubprocessUtil {
+
+    private SubprocessUtil() {
+    }
+
+    /**
+     * Gets the command line for the current process.
+     *
+     * @return the command line arguments for the current process or {@code null} if they are not
+     *         available
+     */
+    public static List<String> getProcessCommandLine() {
+        String processArgsFile = System.getenv().get("MX_SUBPROCESS_COMMAND_FILE");
+        if (processArgsFile != null) {
+            try {
+                return Files.readAllLines(new File(processArgsFile).toPath());
+            } catch (IOException e) {
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the command line used to start the current Java VM, including all VM arguments, but not
+     * including the main class or any Java arguments. This can be used to spawn an identical VM,
+     * but running different Java code.
+     */
+    public static List<String> getVMCommandLine() {
+        List<String> args = getProcessCommandLine();
+        if (args == null) {
+            return null;
+        } else {
+            int index = findMainClassIndex(args);
+            return args.subList(0, index);
+        }
+    }
+
+    public static final List<String> JVM_OPTIONS_WITH_ONE_ARG = System.getProperty("java.specification.version").compareTo("1.9") < 0 ? //
+                    Arrays.asList("-cp", "-classpath") : //
+                    Arrays.asList("-cp", "-classpath", "-mp", "-modulepath", "-upgrademodulepath", "-addmods", "-m", "-limitmods");
+
+    private static int findMainClassIndex(List<String> commandLine) {
+        int i = 1; // Skip the java executable
+
+        while (i < commandLine.size()) {
+            String s = commandLine.get(i);
+            if (s.charAt(0) != '-') {
+                return i;
+            } else if (JVM_OPTIONS_WITH_ONE_ARG.contains(s)) {
+                i += 2;
+            } else {
+                i++;
+            }
+        }
+        throw new InternalError();
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude
new file mode 100644
index 0000000..2ba4881
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude
@@ -0,0 +1 @@
+src_gen
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/src/org/graalvm/compiler/virtual/bench/PartialEscapeBench.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/src/org/graalvm/compiler/virtual/bench/PartialEscapeBench.java
new file mode 100644
index 0000000..621372b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/src/org/graalvm/compiler/virtual/bench/PartialEscapeBench.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.bench;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
+
+public class PartialEscapeBench extends GraalBenchmark {
+
+    private static class Thing {
+        final int id;
+        final String name;
+
+        Thing(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+    }
+
+    @State(Scope.Thread)
+    public static class ThingsCache {
+
+        private Thing[] cache = new Thing[100];
+
+        public Thing getOrAdd(Thing input) {
+            if (cache[input.id] == null) {
+                cache[input.id] = input;
+            }
+            return cache[input.id];
+        }
+    }
+
+    @Benchmark
+    @Warmup(iterations = 30)
+    public String benchPartialEscape(ThingsCache cache) {
+        Thing thing = cache.getOrAdd(new Thing(42, "the answer!"));
+        return thing.name;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/MaterializedObjectState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/MaterializedObjectState.java
new file mode 100644
index 0000000..c08d4e3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/MaterializedObjectState.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.nodes;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * This class encapsulated the materialized state of an escape analyzed object.
+ */
+@NodeInfo
+public final class MaterializedObjectState extends EscapeObjectState implements Node.ValueNumberable {
+
+    public static final NodeClass<MaterializedObjectState> TYPE = NodeClass.create(MaterializedObjectState.class);
+    @Input ValueNode materializedValue;
+
+    public ValueNode materializedValue() {
+        return materializedValue;
+    }
+
+    public MaterializedObjectState(VirtualObjectNode object, ValueNode materializedValue) {
+        super(TYPE, object);
+        this.materializedValue = materializedValue;
+    }
+
+    @Override
+    public MaterializedObjectState duplicateWithVirtualState() {
+        return graph().addWithoutUnique(new MaterializedObjectState(object(), materializedValue));
+    }
+
+    @Override
+    public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) {
+        closure.apply(this, materializedValue);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/VirtualObjectState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/VirtualObjectState.java
new file mode 100644
index 0000000..6b8d241
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/nodes/VirtualObjectState.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.nodes;
+
+import java.util.List;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+/**
+ * This class encapsulated the virtual state of an escape analyzed object.
+ */
+@NodeInfo
+public final class VirtualObjectState extends EscapeObjectState implements Node.ValueNumberable {
+
+    public static final NodeClass<VirtualObjectState> TYPE = NodeClass.create(VirtualObjectState.class);
+    @Input NodeInputList<ValueNode> values;
+
+    public NodeInputList<ValueNode> values() {
+        return values;
+    }
+
+    public VirtualObjectState(VirtualObjectNode object, ValueNode[] values) {
+        super(TYPE, object);
+        assert object.entryCount() == values.length;
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    public VirtualObjectState(VirtualObjectNode object, List<ValueNode> values) {
+        super(TYPE, object);
+        assert object.entryCount() == values.size();
+        this.values = new NodeInputList<>(this, values);
+    }
+
+    @Override
+    public VirtualObjectState duplicateWithVirtualState() {
+        return graph().addWithoutUnique(new VirtualObjectState(object(), values));
+    }
+
+    @Override
+    public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) {
+        for (ValueNode value : values) {
+            closure.apply(this, value);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EarlyReadEliminationPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EarlyReadEliminationPhase.java
new file mode 100644
index 0000000..750508d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EarlyReadEliminationPhase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalyzeOnly;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
+
+    public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
+        super(1, canonicalizer, true);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
+            runAnalysis(graph, context);
+        }
+    }
+
+    @Override
+    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
+        assert schedule == null;
+        return new ReadEliminationClosure(cfg);
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java
new file mode 100644
index 0000000..3b35e13
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+/**
+ * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a
+ * previous state by truncating the list.
+ */
+public class EffectList implements Iterable<EffectList.Effect> {
+
+    public interface Effect {
+        default boolean isVisible() {
+            return true;
+        }
+
+        default boolean isCfgKill() {
+            return false;
+        }
+
+        void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes);
+    }
+
+    public interface SimpleEffect extends Effect {
+        @Override
+        default void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+            apply(graph);
+        }
+
+        void apply(StructuredGraph graph);
+    }
+
+    private static final Effect[] EMPTY_ARRAY = new Effect[0];
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    private Effect[] effects = EMPTY_ARRAY;
+    private String[] names = EMPTY_STRING_ARRAY;
+    private int size;
+
+    private void enlarge(int elements) {
+        int length = effects.length;
+        if (size + elements > length) {
+            while (size + elements > length) {
+                length = Math.max(length * 2, 4);
+            }
+            effects = Arrays.copyOf(effects, length);
+            if (Debug.isEnabled()) {
+                names = Arrays.copyOf(names, length);
+            }
+        }
+    }
+
+    public void add(String name, SimpleEffect effect) {
+        add(name, (Effect) effect);
+    }
+
+    public void add(String name, Effect effect) {
+        assert effect != null;
+        enlarge(1);
+        if (Debug.isEnabled()) {
+            names[size] = name;
+        }
+        effects[size++] = effect;
+    }
+
+    public void addAll(EffectList list) {
+        enlarge(list.size);
+        System.arraycopy(list.effects, 0, effects, size, list.size);
+        if (Debug.isEnabled()) {
+            System.arraycopy(list.names, 0, names, size, list.size);
+        }
+        size += list.size;
+    }
+
+    public void insertAll(EffectList list, int position) {
+        assert position >= 0 && position <= size;
+        enlarge(list.size);
+        System.arraycopy(effects, position, effects, position + list.size, size - position);
+        System.arraycopy(list.effects, 0, effects, position, list.size);
+        if (Debug.isEnabled()) {
+            System.arraycopy(names, position, names, position + list.size, size - position);
+            System.arraycopy(list.names, 0, names, position, list.size);
+        }
+        size += list.size;
+    }
+
+    public int checkpoint() {
+        return size;
+    }
+
+    public int size() {
+        return size;
+    }
+
+    public void backtrack(int checkpoint) {
+        assert checkpoint <= size;
+        size = checkpoint;
+    }
+
+    @Override
+    public Iterator<Effect> iterator() {
+        return new Iterator<Effect>() {
+
+            int index;
+            final int listSize = EffectList.this.size;
+
+            @Override
+            public boolean hasNext() {
+                return index < listSize;
+            }
+
+            @Override
+            public Effect next() {
+                return effects[index++];
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Effect get(int index) {
+        if (index >= size) {
+            throw new IndexOutOfBoundsException();
+        }
+        return effects[index];
+    }
+
+    public void clear() {
+        size = 0;
+    }
+
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes, boolean cfgKills) {
+        for (int i = 0; i < size(); i++) {
+            Effect effect = effects[i];
+            if (effect.isCfgKill() == cfgKills) {
+                try {
+                    effect.apply(graph, obsoleteNodes);
+                } catch (Throwable t) {
+                    StringBuilder str = new StringBuilder();
+                    toString(str, i);
+                    throw new GraalError(t).addContext("effect", str);
+                }
+                if (effect.isVisible() && Debug.isLogEnabled()) {
+                    StringBuilder str = new StringBuilder();
+                    toString(str, i);
+                    Debug.log("    %s", str);
+                }
+            }
+        }
+    }
+
+    private void toString(StringBuilder str, int i) {
+        Effect effect = effects[i];
+        str.append(getName(i)).append(" [");
+        boolean first = true;
+        for (Field field : effect.getClass().getDeclaredFields()) {
+            try {
+                field.setAccessible(true);
+                Object object = field.get(effect);
+                if (object == this) {
+                    // Inner classes could capture the EffectList itself.
+                    continue;
+                }
+                str.append(first ? "" : ", ").append(format(object));
+                first = false;
+            } catch (SecurityException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        str.append(']');
+    }
+
+    private static String format(Object object) {
+        if (object != null && Object[].class.isAssignableFrom(object.getClass())) {
+            return Arrays.toString((Object[]) object);
+        }
+        return "" + object;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        for (int i = 0; i < size(); i++) {
+            Effect effect = get(i);
+            if (effect.isVisible()) {
+                toString(str, i);
+                str.append('\n');
+            }
+        }
+        return str.toString();
+    }
+
+    private String getName(int i) {
+        if (Debug.isEnabled()) {
+            return names[i];
+        } else {
+            return "";
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java
new file mode 100644
index 0000000..ac1ebe7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.Iterator;
+import java.util.Map;
+
+public abstract class EffectsBlockState<T extends EffectsBlockState<T>> {
+
+    /*
+     * This flag specifies whether this path that leads to this block is unreachable.
+     */
+    private boolean dead;
+
+    public EffectsBlockState() {
+        // emtpy
+    }
+
+    public EffectsBlockState(EffectsBlockState<T> other) {
+        this.dead = other.dead;
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+
+    protected abstract boolean equivalentTo(T other);
+
+    public boolean isDead() {
+        return dead;
+    }
+
+    public void markAsDead() {
+        this.dead = true;
+    }
+
+    protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
+        if (left.size() != right.size()) {
+            return false;
+        }
+        return compareMapsNoSize(left, right);
+    }
+
+    protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
+        if (left == right) {
+            return true;
+        }
+        for (Map.Entry<K, V> entry : right.entrySet()) {
+            K key = entry.getKey();
+            V value = entry.getValue();
+            assert value != null;
+            V otherValue = left.get(key);
+            if (otherValue != value && !value.equals(otherValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
+        Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<U, V> entry = iter.next();
+            if (source.containsKey(entry.getKey())) {
+                assert source.get(entry.getKey()) == entry.getValue();
+            } else {
+                iter.remove();
+            }
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java
new file mode 100644
index 0000000..c6080b7
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.Indent;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.BoxNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.LoopInfo;
+
+public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
+
+    protected final ControlFlowGraph cfg;
+    protected final ScheduleResult schedule;
+
+    protected final NodeMap<ValueNode> aliases;
+    protected final BlockMap<GraphEffectList> blockEffects;
+    private final Map<Loop<Block>, GraphEffectList> loopMergeEffects = CollectionsFactory.newIdentityMap();
+    // Intended to be used by read-eliminating phases based on the effects phase.
+    protected final Map<Loop<Block>, LoopKillCache> loopLocationKillCache = CollectionsFactory.newIdentityMap();
+    private final Map<LoopBeginNode, BlockT> loopEntryStates = Node.newIdentityMap();
+    private final NodeBitMap hasScalarReplacedInputs;
+
+    protected boolean changed;
+
+    public EffectsClosure(ScheduleResult schedule, ControlFlowGraph cfg) {
+        this.schedule = schedule;
+        this.cfg = cfg;
+        this.aliases = cfg.graph.createNodeMap();
+        this.hasScalarReplacedInputs = cfg.graph.createNodeBitMap();
+        this.blockEffects = new BlockMap<>(cfg);
+        for (Block block : cfg.getBlocks()) {
+            blockEffects.put(block, new GraphEffectList());
+        }
+    }
+
+    @Override
+    public boolean hasChanged() {
+        return changed;
+    }
+
+    @Override
+    public void applyEffects() {
+        final StructuredGraph graph = cfg.graph;
+        final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
+        final ArrayList<GraphEffectList> effectList = new ArrayList<>();
+        BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
+
+            @Override
+            protected Void getInitialState() {
+                return null;
+            }
+
+            private void apply(GraphEffectList effects) {
+                if (effects != null && !effects.isEmpty()) {
+                    effectList.add(effects);
+                }
+            }
+
+            @Override
+            protected Void processBlock(Block block, Void currentState) {
+                apply(blockEffects.get(block));
+                return currentState;
+            }
+
+            @Override
+            protected Void merge(Block merge, List<Void> states) {
+                return null;
+            }
+
+            @Override
+            protected Void cloneState(Void oldState) {
+                return oldState;
+            }
+
+            @Override
+            protected List<Void> processLoop(Loop<Block> loop, Void initialState) {
+                LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
+                apply(loopMergeEffects.get(loop));
+                return info.exitStates;
+            }
+        };
+        ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
+        for (GraphEffectList effects : effectList) {
+            Debug.log(" ==== effects");
+            effects.apply(graph, obsoleteNodes, false);
+        }
+        for (GraphEffectList effects : effectList) {
+            Debug.log(" ==== cfg kill effects");
+            effects.apply(graph, obsoleteNodes, true);
+        }
+        Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "After applying effects");
+        assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
+        for (Node node : obsoleteNodes) {
+            if (node.isAlive()) {
+                node.replaceAtUsages(null);
+                GraphUtil.killWithUnusedFloatingInputs(node);
+            }
+        }
+    }
+
+    @Override
+    protected BlockT processBlock(Block block, BlockT state) {
+        if (!state.isDead()) {
+            GraphEffectList effects = blockEffects.get(block);
+
+            if (block.getBeginNode().predecessor() instanceof IfNode) {
+                IfNode ifNode = (IfNode) block.getBeginNode().predecessor();
+                LogicNode condition = ifNode.condition();
+                Node alias = getScalarAlias(condition);
+                if (alias instanceof LogicConstantNode) {
+                    LogicConstantNode constant = (LogicConstantNode) alias;
+                    boolean deadBranch = constant.getValue() != (block.getBeginNode() == ifNode.trueSuccessor());
+
+                    if (deadBranch) {
+                        state.markAsDead();
+                        effects.killIfBranch(ifNode, constant.getValue());
+                        return state;
+                    }
+                }
+            }
+
+            VirtualUtil.trace("\nBlock: %s, preds: %s, succ: %s (", block, block.getPredecessors(), block.getSuccessors());
+
+            FixedWithNextNode lastFixedNode = block.getBeginNode().predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) block.getBeginNode().predecessor() : null;
+            Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
+            for (Node node : nodes) {
+                aliases.set(node, null);
+                if (node instanceof LoopExitNode) {
+                    LoopExitNode loopExit = (LoopExitNode) node;
+                    for (ProxyNode proxy : loopExit.proxies()) {
+                        aliases.set(proxy, null);
+                        changed |= processNode(proxy, state, effects, lastFixedNode) && isSignificantNode(node);
+                    }
+                    processLoopExit(loopExit, loopEntryStates.get(loopExit.loopBegin()), state, blockEffects.get(block));
+                }
+                changed |= processNode(node, state, effects, lastFixedNode) && isSignificantNode(node);
+                if (node instanceof FixedWithNextNode) {
+                    lastFixedNode = (FixedWithNextNode) node;
+                }
+                if (state.isDead()) {
+                    break;
+                }
+            }
+            VirtualUtil.trace(")\n    end state: %s\n", state);
+        }
+        return state;
+    }
+
+    private static boolean isSignificantNode(Node node) {
+        return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode || node instanceof BoxNode);
+    }
+
+    /**
+     * Collects the effects of virtualizing the given node.
+     *
+     * @return {@code true} if the effects include removing the node, {@code false} otherwise.
+     */
+    protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode);
+
+    @Override
+    protected BlockT merge(Block merge, List<BlockT> states) {
+        assert blockEffects.get(merge).isEmpty();
+        MergeProcessor processor = createMergeProcessor(merge);
+        doMergeWithoutDead(processor, states);
+        processor.commitEnds(states);
+        blockEffects.get(merge).addAll(processor.mergeEffects);
+        blockEffects.get(merge).addAll(processor.afterMergeEffects);
+        return processor.newState;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected final List<BlockT> processLoop(Loop<Block> loop, BlockT initialState) {
+        if (initialState.isDead()) {
+            ArrayList<BlockT> states = new ArrayList<>();
+            for (int i = 0; i < loop.getExits().size(); i++) {
+                states.add(initialState);
+            }
+            return states;
+        }
+        /*
+         * Special case nested loops: To avoid an exponential runtime for nested loops we try to
+         * only process them as little times as possible.
+         *
+         * In the first iteration of an outer most loop we go into the inner most loop(s). We run
+         * the first iteration of the inner most loop and then, if necessary, a second iteration.
+         *
+         * We return from the recursion and finish the first iteration of the outermost loop. If we
+         * have to do a second iteration in the outer most loop we go again into the inner most
+         * loop(s) but this time we already know all states that are killed by the loop so inside
+         * the loop we will only have those changes that propagate from the first iteration of the
+         * outer most loop into the current loop. We strip the initial loop state for the inner most
+         * loops and do the first iteration with the (possible) changes from outer loops. If there
+         * are no changes we only have to do 1 iteration and are done.
+         *
+         */
+        BlockT initialStateRemovedKilledLocations = stripKilledLoopLocations(loop, cloneState(initialState));
+        BlockT loopEntryState = initialStateRemovedKilledLocations;
+        BlockT lastMergedState = cloneState(initialStateRemovedKilledLocations);
+        processInitialLoopState(loop, lastMergedState);
+        MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader());
+        for (int iteration = 0; iteration < 10; iteration++) {
+            try (Indent i = Debug.logAndIndent("================== Process Loop Effects Closure: block:%s begin node:%s", loop.getHeader(), loop.getHeader().getBeginNode())) {
+                LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
+
+                List<BlockT> states = new ArrayList<>();
+                states.add(initialStateRemovedKilledLocations);
+                states.addAll(info.endStates);
+                doMergeWithoutDead(mergeProcessor, states);
+
+                Debug.log("MergeProcessor New State: %s", mergeProcessor.newState);
+                Debug.log("===== vs.");
+                Debug.log("Last Merged State: %s", lastMergedState);
+
+                if (mergeProcessor.newState.equivalentTo(lastMergedState)) {
+                    mergeProcessor.commitEnds(states);
+
+                    blockEffects.get(loop.getHeader()).insertAll(mergeProcessor.mergeEffects, 0);
+                    loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects);
+
+                    assert info.exitStates.size() == loop.getExits().size();
+                    loopEntryStates.put((LoopBeginNode) loop.getHeader().getBeginNode(), loopEntryState);
+                    assert assertExitStatesNonEmpty(loop, info);
+
+                    processKilledLoopLocations(loop, initialStateRemovedKilledLocations, mergeProcessor.newState);
+                    return info.exitStates;
+                } else {
+                    lastMergedState = mergeProcessor.newState;
+                    for (Block block : loop.getBlocks()) {
+                        blockEffects.get(block).clear();
+                    }
+                }
+            }
+        }
+        throw new GraalError("too many iterations at %s", loop);
+    }
+
+    @SuppressWarnings("unused")
+    protected BlockT stripKilledLoopLocations(Loop<Block> loop, BlockT initialState) {
+        return initialState;
+    }
+
+    @SuppressWarnings("unused")
+    protected void processKilledLoopLocations(Loop<Block> loop, BlockT initialState, BlockT mergedStates) {
+        // nothing to do
+    }
+
+    @SuppressWarnings("unused")
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        // nothing to do
+    }
+
+    private void doMergeWithoutDead(MergeProcessor mergeProcessor, List<BlockT> states) {
+        int alive = 0;
+        for (BlockT state : states) {
+            if (!state.isDead()) {
+                alive++;
+            }
+        }
+        if (alive == 0) {
+            mergeProcessor.setNewState(states.get(0));
+        } else if (alive == states.size()) {
+            int[] stateIndexes = new int[states.size()];
+            for (int i = 0; i < stateIndexes.length; i++) {
+                stateIndexes[i] = i;
+            }
+            mergeProcessor.setStateIndexes(stateIndexes);
+            mergeProcessor.merge(states);
+        } else {
+            ArrayList<BlockT> aliveStates = new ArrayList<>(alive);
+            int[] stateIndexes = new int[alive];
+            for (int i = 0; i < states.size(); i++) {
+                if (!states.get(i).isDead()) {
+                    stateIndexes[aliveStates.size()] = i;
+                    aliveStates.add(states.get(i));
+                }
+            }
+            mergeProcessor.setStateIndexes(stateIndexes);
+            mergeProcessor.merge(aliveStates);
+        }
+    }
+
+    private boolean assertExitStatesNonEmpty(Loop<Block> loop, LoopInfo<BlockT> info) {
+        for (int i = 0; i < loop.getExits().size(); i++) {
+            assert info.exitStates.get(i) != null : "no loop exit state at " + loop.getExits().get(i) + " / " + loop.getHeader();
+        }
+        return true;
+    }
+
+    protected abstract void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects);
+
+    protected abstract MergeProcessor createMergeProcessor(Block merge);
+
+    protected class MergeProcessor {
+
+        private final Block mergeBlock;
+        private final AbstractMergeNode merge;
+
+        protected final GraphEffectList mergeEffects;
+        protected final GraphEffectList afterMergeEffects;
+
+        private int[] stateIndexes;
+        protected BlockT newState;
+
+        public MergeProcessor(Block mergeBlock) {
+            this.mergeBlock = mergeBlock;
+            this.merge = (AbstractMergeNode) mergeBlock.getBeginNode();
+            this.mergeEffects = new GraphEffectList();
+            this.afterMergeEffects = new GraphEffectList();
+        }
+
+        /**
+         * @param states the states that should be merged.
+         */
+        protected void merge(List<BlockT> states) {
+            setNewState(getInitialState());
+        }
+
+        private void setNewState(BlockT state) {
+            newState = state;
+            mergeEffects.clear();
+            afterMergeEffects.clear();
+        }
+
+        private void setStateIndexes(int[] stateIndexes) {
+            this.stateIndexes = stateIndexes;
+        }
+
+        @SuppressWarnings("unused")
+        protected void commitEnds(List<BlockT> states) {
+        }
+
+        protected final Block getPredecessor(int index) {
+            return mergeBlock.getPredecessors()[stateIndexes[index]];
+        }
+
+        protected final NodeIterable<PhiNode> getPhis() {
+            return merge.phis();
+        }
+
+        protected final ValueNode getPhiValueAt(PhiNode phi, int index) {
+            return phi.valueAt(stateIndexes[index]);
+        }
+
+        protected final ValuePhiNode createValuePhi(Stamp stamp) {
+            return new ValuePhiNode(stamp, merge, new ValueNode[mergeBlock.getPredecessorCount()]);
+        }
+
+        protected final void setPhiInput(PhiNode phi, int index, ValueNode value) {
+            afterMergeEffects.initializePhiInput(phi, stateIndexes[index], value);
+        }
+
+        protected final int getStateIndex(int i) {
+            return stateIndexes[i];
+        }
+
+        protected final StructuredGraph graph() {
+            return merge.graph();
+        }
+
+        @Override
+        public String toString() {
+            return "MergeProcessor@" + merge;
+        }
+    }
+
+    public void addScalarAlias(ValueNode node, ValueNode alias) {
+        assert !(alias instanceof VirtualObjectNode);
+        aliases.set(node, alias);
+        for (Node usage : node.usages()) {
+            if (!hasScalarReplacedInputs.isNew(usage)) {
+                hasScalarReplacedInputs.mark(usage);
+            }
+        }
+    }
+
+    protected final boolean hasScalarReplacedInputs(Node node) {
+        return hasScalarReplacedInputs.isMarked(node);
+    }
+
+    public ValueNode getScalarAlias(ValueNode node) {
+        assert !(node instanceof VirtualObjectNode);
+        if (node == null || !node.isAlive() || aliases.isNew(node)) {
+            return node;
+        }
+        ValueNode result = aliases.get(node);
+        return (result == null || result instanceof VirtualObjectNode) ? node : result;
+    }
+
+    protected static class LoopKillCache {
+        private int visits;
+        private LocationIdentity firstLocation;
+        private Set<LocationIdentity> killedLocations;
+        private boolean killsAll;
+
+        protected LoopKillCache(int visits) {
+            this.visits = visits;
+        }
+
+        protected void visited() {
+            visits++;
+        }
+
+        protected int visits() {
+            return visits;
+        }
+
+        protected void setKillsAll() {
+            killsAll = true;
+            firstLocation = null;
+            killedLocations = null;
+        }
+
+        protected boolean containsLocation(LocationIdentity locationIdentity) {
+            if (killsAll) {
+                return true;
+            }
+            if (firstLocation == null) {
+                return false;
+            }
+            if (!firstLocation.equals(locationIdentity)) {
+                return killedLocations != null ? killedLocations.contains(locationIdentity) : false;
+            }
+            return true;
+        }
+
+        protected void rememberLoopKilledLocation(LocationIdentity locationIdentity) {
+            if (killsAll) {
+                return;
+            }
+            if (firstLocation == null || firstLocation.equals(locationIdentity)) {
+                firstLocation = locationIdentity;
+            } else {
+                if (killedLocations == null) {
+                    killedLocations = new HashSet<>();
+                }
+                killedLocations.add(locationIdentity);
+            }
+        }
+
+        protected boolean loopKillsLocations() {
+            if (killsAll) {
+                return true;
+            }
+            return firstLocation != null;
+        }
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java
new file mode 100644
index 0000000..c5873cc
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.debug.Debug.isEnabled;
+import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.util.CompilationAlarm;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public abstract class EffectsPhase<PhaseContextT extends PhaseContext> extends BasePhase<PhaseContextT> {
+
+    public abstract static class Closure<T> extends ReentrantBlockIterator.BlockIteratorClosure<T> {
+
+        public abstract boolean hasChanged();
+
+        public abstract void applyEffects();
+    }
+
+    private final int maxIterations;
+    protected final CanonicalizerPhase canonicalizer;
+    private final boolean unscheduled;
+
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+        this(maxIterations, canonicalizer, false);
+    }
+
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer, boolean unscheduled) {
+        this.maxIterations = maxIterations;
+        this.canonicalizer = canonicalizer;
+        this.unscheduled = unscheduled;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContextT context) {
+        runAnalysis(graph, context);
+    }
+
+    @SuppressWarnings("try")
+    public boolean runAnalysis(final StructuredGraph graph, final PhaseContextT context) {
+        boolean changed = false;
+        boolean stop = false;
+        for (int iteration = 0; !stop && iteration < maxIterations && !CompilationAlarm.hasExpired(); iteration++) {
+            try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
+                ScheduleResult schedule;
+                ControlFlowGraph cfg;
+                if (unscheduled) {
+                    schedule = null;
+                    cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+                } else {
+                    new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST).apply(graph, false);
+                    schedule = graph.getLastSchedule();
+                    cfg = schedule.getCFG();
+                }
+                try (Scope scheduleScope = Debug.scope("EffectsPhaseWithSchedule", schedule)) {
+                    Closure<?> closure = createEffectsClosure(context, schedule, cfg);
+                    ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
+
+                    if (closure.hasChanged()) {
+                        changed = true;
+                    } else {
+                        stop = true;
+                    }
+
+                    // apply the effects collected during this iteration
+                    HashSetNodeEventListener listener = new HashSetNodeEventListener();
+                    try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                        closure.applyEffects();
+                    }
+
+                    if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+                        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "%s iteration", getName());
+                    }
+
+                    new DeadCodeEliminationPhase(Required).apply(graph);
+
+                    Set<Node> changedNodes = listener.getNodes();
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof Simplifiable) {
+                            changedNodes.add(node);
+                        }
+                    }
+                    postIteration(graph, context, changedNodes);
+                } catch (Throwable t) {
+                    throw Debug.handle(t);
+                }
+            }
+        }
+        return changed;
+    }
+
+    protected void postIteration(final StructuredGraph graph, final PhaseContextT context, Set<Node> changedNodes) {
+        if (canonicalizer != null) {
+            canonicalizer.applyIncremental(graph, context, changedNodes);
+        }
+    }
+
+    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, ScheduleResult schedule, ControlFlowGraph cfg);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/GraphEffectList.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/GraphEffectList.java
new file mode 100644
index 0000000..9cef9eb
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/GraphEffectList.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
+import org.graalvm.compiler.nodes.debug.WeakCounterNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+
+public class GraphEffectList extends EffectList {
+
+    public void addCounterBefore(String group, String name, int increment, boolean addContext, FixedNode position) {
+        add("add counter", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, position));
+    }
+
+    public void addCounterAfter(String group, String name, int increment, boolean addContext, FixedWithNextNode position) {
+        FixedNode nextPosition = position.next();
+        add("add counter after", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, nextPosition));
+    }
+
+    public void addWeakCounterCounterBefore(String group, String name, int increment, boolean addContext, ValueNode checkedValue, FixedNode position) {
+        add("add weak counter", graph -> WeakCounterNode.addCounterBefore(group, name, increment, addContext, checkedValue, position));
+    }
+
+    /**
+     * Adds the given fixed node to the graph's control flow, before position (so that the original
+     * predecessor of position will then be node's predecessor).
+     *
+     * @param node The fixed node to be added to the graph.
+     * @param position The fixed node before which the node should be added.
+     */
+    public void addFixedNodeBefore(FixedWithNextNode node, FixedNode position) {
+        add("add fixed node", graph -> {
+            assert !node.isAlive() && !node.isDeleted() && position.isAlive();
+            graph.addBeforeFixed(position, graph.add(node));
+        });
+    }
+
+    public void ensureAdded(ValueNode node, FixedNode position) {
+        add("ensure added", graph -> {
+            assert position.isAlive();
+            if (!node.isAlive()) {
+                graph.addWithoutUniqueWithInputs(node);
+                if (node instanceof FixedWithNextNode) {
+                    graph.addBeforeFixed(position, (FixedWithNextNode) node);
+                }
+            }
+        });
+    }
+
+    /**
+     * Add the given floating node to the graph.
+     *
+     * @param node The floating node to be added.
+     */
+    public void addFloatingNode(ValueNode node, @SuppressWarnings("unused") String cause) {
+        add("add floating node", graph -> graph.addWithoutUnique(node));
+    }
+
+    /**
+     * Sets the phi node's input at the given index to the given value, adding new phi inputs as
+     * needed.
+     *
+     * @param node The phi node whose input should be changed.
+     * @param index The index of the phi input to be changed.
+     * @param value The new value for the phi input.
+     */
+    public void initializePhiInput(PhiNode node, int index, ValueNode value) {
+        add("set phi input", (graph, obsoleteNodes) -> {
+            assert node.isAlive() && value.isAlive() && index >= 0;
+            node.initializeValueAt(index, value);
+        });
+    }
+
+    /**
+     * Adds a virtual object's state to the given frame state. If the given reusedVirtualObjects set
+     * contains the virtual object then old states for this object will be removed.
+     *
+     * @param node The frame state to which the state should be added.
+     * @param state The virtual object state to add.
+     */
+    public void addVirtualMapping(FrameState node, EscapeObjectState state) {
+        add("add virtual mapping", new Effect() {
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                if (node.isAlive()) {
+                    assert !state.isDeleted();
+                    FrameState stateAfter = node;
+                    for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) {
+                        if (stateAfter.virtualObjectMappingAt(i).object() == state.object()) {
+                            stateAfter.virtualObjectMappings().remove(i);
+                        }
+                    }
+                    stateAfter.addVirtualObjectMapping(state.isAlive() ? state : graph.unique(state));
+                }
+            }
+
+            @Override
+            public boolean isVisible() {
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Removes the given fixed node from the control flow and deletes it.
+     *
+     * @param node The fixed node that should be deleted.
+     */
+    public void deleteNode(Node node) {
+        add("delete fixed node", (graph, obsoleteNodes) -> {
+            if (node instanceof FixedWithNextNode) {
+                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+            }
+            obsoleteNodes.add(node);
+        });
+    }
+
+    public void killIfBranch(IfNode ifNode, boolean constantCondition) {
+        add("kill if branch", new Effect() {
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                graph.removeSplitPropagate(ifNode, ifNode.getSuccessor(constantCondition));
+            }
+
+            @Override
+            public boolean isCfgKill() {
+                return true;
+            }
+        });
+    }
+
+    public void replaceWithSink(FixedWithNextNode node, ControlSinkNode sink) {
+        add("kill if branch", new Effect() {
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                node.replaceAtPredecessor(sink);
+                GraphUtil.killCFG(node);
+            }
+
+            @Override
+            public boolean isCfgKill() {
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Replaces the given node at its usages without deleting it. If the current node is a fixed
+     * node it will be disconnected from the control flow, so that it will be deleted by a
+     * subsequent {@link DeadCodeEliminationPhase}
+     *
+     * @param node The node to be replaced.
+     * @param replacement The node that should replace the original value. If the replacement is a
+     *            non-connected {@link FixedWithNextNode} it will be added to the control flow.
+     *
+     */
+    public void replaceAtUsages(ValueNode node, ValueNode replacement) {
+        assert node != null && replacement != null : node + " " + replacement;
+        add("replace at usages", (graph, obsoleteNodes) -> {
+            assert node.isAlive() && replacement.isAlive() : node + " " + replacement;
+            if (replacement instanceof FixedWithNextNode && ((FixedWithNextNode) replacement).next() == null) {
+                assert node instanceof FixedNode;
+                graph.addBeforeFixed((FixedNode) node, (FixedWithNextNode) replacement);
+            }
+            node.replaceAtUsages(replacement);
+            if (node instanceof FixedWithNextNode) {
+                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+            }
+            obsoleteNodes.add(node);
+        });
+    }
+
+    /**
+     * Replaces the first occurrence of oldInput in node with newInput.
+     *
+     * @param node The node whose input should be changed.
+     * @param oldInput The value to look for.
+     * @param newInput The value to replace with.
+     */
+    public void replaceFirstInput(Node node, Node oldInput, Node newInput) {
+        assert node.isAlive() && oldInput.isAlive() && !newInput.isDeleted();
+        add("replace first input", new Effect() {
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                if (node.isAlive()) {
+                    assert oldInput.isAlive() && newInput.isAlive();
+                    node.replaceFirstInput(oldInput, newInput);
+                }
+            }
+
+            @Override
+            public boolean isVisible() {
+                return !(node instanceof FrameState);
+            }
+        });
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ObjectState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ObjectState.java
new file mode 100644
index 0000000..f05e6d0
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ObjectState.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
+import org.graalvm.compiler.nodes.virtual.LockState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
+import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
+
+/**
+ * This class describes the state of a virtual object while iterating over the graph. It describes
+ * the fields or array elements (called "entries") and the lock count if the object is still
+ * virtual. If the object was materialized, it contains the current materialized value.
+ */
+public class ObjectState {
+
+    public static final DebugCounter CREATE_ESCAPED_OBJECT_STATE = Debug.counter("CreateEscapeObjectState");
+    public static final DebugCounter GET_ESCAPED_OBJECT_STATE = Debug.counter("GetEscapeObjectState");
+
+    private ValueNode[] entries;
+    private ValueNode materializedValue;
+    private LockState locks;
+    private boolean ensureVirtualized;
+
+    private EscapeObjectState cachedState;
+
+    boolean copyOnWrite;
+
+    public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) {
+        this(entries, (LockState) null, ensureVirtualized);
+        for (int i = locks.size() - 1; i >= 0; i--) {
+            this.locks = new LockState(locks.get(i), this.locks);
+        }
+    }
+
+    public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) {
+        this.entries = entries;
+        this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
+    }
+
+    public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) {
+        assert materializedValue != null;
+        this.materializedValue = materializedValue;
+        this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
+    }
+
+    private ObjectState(ObjectState other) {
+        entries = other.entries == null ? null : other.entries.clone();
+        materializedValue = other.materializedValue;
+        locks = other.locks;
+        cachedState = other.cachedState;
+        ensureVirtualized = other.ensureVirtualized;
+    }
+
+    public ObjectState cloneState() {
+        return new ObjectState(this);
+    }
+
+    public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) {
+        GET_ESCAPED_OBJECT_STATE.increment();
+        if (cachedState == null) {
+            CREATE_ESCAPED_OBJECT_STATE.increment();
+            cachedState = isVirtual() ? new VirtualObjectState(virtual, entries) : new MaterializedObjectState(virtual, materializedValue);
+        }
+        return cachedState;
+
+    }
+
+    public boolean isVirtual() {
+        assert materializedValue == null ^ entries == null;
+        return materializedValue == null;
+    }
+
+    /**
+     * Users of this method are not allowed to change the entries of the returned array.
+     */
+    public ValueNode[] getEntries() {
+        assert isVirtual();
+        return entries;
+    }
+
+    public ValueNode getEntry(int index) {
+        assert isVirtual();
+        return entries[index];
+    }
+
+    public ValueNode getMaterializedValue() {
+        assert !isVirtual();
+        return materializedValue;
+    }
+
+    public void setEntry(int index, ValueNode value) {
+        assert isVirtual();
+        cachedState = null;
+        entries[index] = value;
+    }
+
+    public void escape(ValueNode materialized) {
+        assert isVirtual();
+        assert materialized != null;
+        materializedValue = materialized;
+        entries = null;
+        cachedState = null;
+        assert !isVirtual();
+    }
+
+    public void updateMaterializedValue(ValueNode value) {
+        assert !isVirtual();
+        assert value != null;
+        cachedState = null;
+        materializedValue = value;
+    }
+
+    public void addLock(MonitorIdNode monitorId) {
+        locks = new LockState(monitorId, locks);
+    }
+
+    public MonitorIdNode removeLock() {
+        try {
+            return locks.monitorId;
+        } finally {
+            locks = locks.next;
+        }
+    }
+
+    public LockState getLocks() {
+        return locks;
+    }
+
+    public boolean hasLocks() {
+        return locks != null;
+    }
+
+    public boolean locksEqual(ObjectState other) {
+        LockState a = locks;
+        LockState b = other.locks;
+        while (a != null && b != null && a.monitorId == b.monitorId) {
+            a = a.next;
+            b = b.next;
+        }
+        return a == null && b == null;
+    }
+
+    public void setEnsureVirtualized(boolean ensureVirtualized) {
+        this.ensureVirtualized = ensureVirtualized;
+    }
+
+    public boolean getEnsureVirtualized() {
+        return ensureVirtualized;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder().append('{');
+        if (locks != null) {
+            str.append('l').append(locks).append(' ');
+        }
+        if (entries != null) {
+            for (int i = 0; i < entries.length; i++) {
+                str.append("entry").append(i).append('=').append(entries[i]).append(' ');
+            }
+        }
+        if (materializedValue != null) {
+            str.append("mat=").append(materializedValue);
+        }
+
+        return str.append('}').toString();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(entries);
+        result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0);
+        result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        ObjectState other = (ObjectState) obj;
+        if (!Arrays.equals(entries, other.entries)) {
+            return false;
+        }
+        if (!locksEqual(other)) {
+            return false;
+        }
+        if (materializedValue == null) {
+            if (other.materializedValue != null) {
+                return false;
+            }
+        } else if (!materializedValue.equals(other.materializedValue)) {
+            return false;
+        }
+        return true;
+    }
+
+    public ObjectState share() {
+        copyOnWrite = true;
+        return this;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java
new file mode 100644
index 0000000..2902480
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+public class PEReadEliminationBlockState extends PartialEscapeBlockState<PEReadEliminationBlockState> {
+
+    final HashMap<ReadCacheEntry, ValueNode> readCache;
+
+    static final class ReadCacheEntry {
+
+        public final LocationIdentity identity;
+        public final ValueNode object;
+        public final int index;
+
+        ReadCacheEntry(LocationIdentity identity, ValueNode object, int index) {
+            this.identity = identity;
+            this.object = object;
+            this.index = index;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
+            result = 31 * result + ((object == null) ? 0 : object.hashCode());
+            return result * 31 + index;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof ReadCacheEntry)) {
+                return false;
+            }
+            ReadCacheEntry other = (ReadCacheEntry) obj;
+            return identity.equals(other.identity) && object == other.object;
+        }
+
+        @Override
+        public String toString() {
+            return index == -1 ? (object + ":" + identity) : (object + "[" + index + "]:" + identity);
+        }
+    }
+
+    public PEReadEliminationBlockState() {
+        readCache = CollectionsFactory.newMap();
+    }
+
+    public PEReadEliminationBlockState(PEReadEliminationBlockState other) {
+        super(other);
+        readCache = CollectionsFactory.newMap(other.readCache);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " " + readCache;
+    }
+
+    @Override
+    protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
+        if (virtual instanceof VirtualInstanceNode) {
+            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+            for (int i = 0; i < instance.entryCount(); i++) {
+                readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1), values.get(i));
+            }
+        }
+    }
+
+    @Override
+    public boolean equivalentTo(PEReadEliminationBlockState other) {
+        if (!compareMapsNoSize(readCache, other.readCache)) {
+            return false;
+        }
+        return super.equivalentTo(other);
+    }
+
+    public void addReadCache(ValueNode object, LocationIdentity identity, int index, ValueNode value, PartialEscapeClosure<?> closure) {
+        ValueNode cacheObject;
+        ObjectState obj = closure.getObjectState(this, object);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
+        }
+        readCache.put(new ReadCacheEntry(identity, cacheObject, index), value);
+    }
+
+    public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, PartialEscapeClosure<?> closure) {
+        ValueNode cacheObject;
+        ObjectState obj = closure.getObjectState(this, object);
+        if (obj != null) {
+            assert !obj.isVirtual() : object;
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
+        }
+        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index));
+        obj = closure.getObjectState(this, cacheValue);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheValue = obj.getMaterializedValue();
+        } else {
+            // assert !scalarAliases.containsKey(cacheValue);
+            cacheValue = closure.getScalarAlias(cacheValue);
+        }
+        return cacheValue;
+    }
+
+    public void killReadCache() {
+        readCache.clear();
+    }
+
+    public void killReadCache(LocationIdentity identity, int index) {
+        Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
+        while (iter.hasNext()) {
+            ReadCacheEntry entry = iter.next().getKey();
+            if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) {
+                iter.remove();
+            }
+        }
+    }
+
+    public Map<ReadCacheEntry, ValueNode> getReadCache() {
+        return readCache;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java
new file mode 100644
index 0000000..0ed0479
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
+
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
+import org.graalvm.compiler.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class PEReadEliminationClosure extends PartialEscapeClosure<PEReadEliminationBlockState> {
+
+    private static final EnumMap<JavaKind, LocationIdentity> UNBOX_LOCATIONS;
+
+    static {
+        UNBOX_LOCATIONS = new EnumMap<>(JavaKind.class);
+        for (JavaKind kind : JavaKind.values()) {
+            UNBOX_LOCATIONS.put(kind, NamedLocationIdentity.immutable("PEA unbox " + kind.getJavaName()));
+        }
+    }
+
+    public PEReadEliminationClosure(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                    LoweringProvider loweringProvider) {
+        super(schedule, metaAccess, constantReflection, constantFieldProvider, loweringProvider);
+    }
+
+    @Override
+    protected PEReadEliminationBlockState getInitialState() {
+        return new PEReadEliminationBlockState();
+    }
+
+    @Override
+    protected boolean processNode(Node node, PEReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        if (super.processNode(node, state, effects, lastFixedNode)) {
+            return true;
+        }
+
+        if (node instanceof LoadFieldNode) {
+            return processLoadField((LoadFieldNode) node, state, effects);
+        } else if (node instanceof StoreFieldNode) {
+            return processStoreField((StoreFieldNode) node, state, effects);
+        } else if (node instanceof LoadIndexedNode) {
+            return processLoadIndexed((LoadIndexedNode) node, state, effects);
+        } else if (node instanceof StoreIndexedNode) {
+            return processStoreIndexed((StoreIndexedNode) node, state, effects);
+        } else if (node instanceof ArrayLengthNode) {
+            return processArrayLength((ArrayLengthNode) node, state, effects);
+        } else if (node instanceof UnboxNode) {
+            return processUnbox((UnboxNode) node, state, effects);
+        } else if (node instanceof UnsafeLoadNode) {
+            return processUnsafeLoad((UnsafeLoadNode) node, state, effects);
+        } else if (node instanceof UnsafeStoreNode) {
+            return processUnsafeStore((UnsafeStoreNode) node, state, effects);
+        } else if (node instanceof MemoryCheckpoint.Single) {
+            COUNTER_MEMORYCHECKPOINT.increment();
+            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+            processIdentity(state, identity);
+        } else if (node instanceof MemoryCheckpoint.Multi) {
+            COUNTER_MEMORYCHECKPOINT.increment();
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                processIdentity(state, identity);
+            }
+        }
+
+        return false;
+    }
+
+    private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
+        ValueNode unproxiedObject = GraphUtil.unproxify(object);
+        ValueNode cachedValue = state.getReadCache(object, identity, index, this);
+
+        ValueNode finalValue = getScalarAlias(value);
+        boolean result = false;
+        if (GraphUtil.unproxify(finalValue) == GraphUtil.unproxify(cachedValue)) {
+            effects.deleteNode(store);
+            result = true;
+        }
+        state.killReadCache(identity, index);
+        state.addReadCache(unproxiedObject, identity, index, finalValue, this);
+        return result;
+    }
+
+    private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, PEReadEliminationBlockState state, GraphEffectList effects) {
+        ValueNode unproxiedObject = GraphUtil.unproxify(object);
+        ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, this);
+        if (cachedValue != null) {
+            effects.replaceAtUsages(load, cachedValue);
+            addScalarAlias(load, cachedValue);
+            return true;
+        } else {
+            state.addReadCache(unproxiedObject, identity, index, load, this);
+            return false;
+        }
+    }
+
+    private boolean processUnsafeLoad(UnsafeLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
+        if (load.offset().isConstant()) {
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && type.isArray()) {
+                long offset = load.offset().asJavaConstant().asLong();
+                int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
+                ValueNode object = GraphUtil.unproxify(load.object());
+                LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
+                ValueNode cachedValue = state.getReadCache(object, location, index, this);
+                if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
+                    effects.replaceAtUsages(load, cachedValue);
+                    addScalarAlias(load, cachedValue);
+                    return true;
+                } else {
+                    state.addReadCache(object, location, index, load, this);
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean processUnsafeStore(UnsafeStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
+        ResolvedJavaType type = StampTool.typeOrNull(store.object());
+        if (type != null && type.isArray()) {
+            LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
+            if (store.offset().isConstant()) {
+                long offset = store.offset().asJavaConstant().asLong();
+                int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
+                return processStore(store, store.object(), location, index, store.value(), state, effects);
+            } else {
+                processIdentity(state, location);
+            }
+        } else {
+            state.killReadCache();
+        }
+        return false;
+    }
+
+    private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) {
+        return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, state, effects);
+    }
+
+    private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
+        if (store.isVolatile()) {
+            state.killReadCache();
+            return false;
+        }
+        return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.value(), state, effects);
+    }
+
+    private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
+        if (load.isVolatile()) {
+            state.killReadCache();
+            return false;
+        }
+        return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, state, effects);
+    }
+
+    private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
+        LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind());
+        if (store.index().isConstant()) {
+            int index = ((JavaConstant) store.index().asConstant()).asInt();
+            return processStore(store, store.array(), arrayLocation, index, store.value(), state, effects);
+        } else {
+            state.killReadCache(arrayLocation, -1);
+        }
+        return false;
+    }
+
+    private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
+        if (load.index().isConstant()) {
+            int index = ((JavaConstant) load.index().asConstant()).asInt();
+            LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
+            return processLoad(load, load.array(), arrayLocation, index, state, effects);
+        }
+        return false;
+    }
+
+    private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) {
+        return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, state, effects);
+    }
+
+    private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {
+        if (identity.isAny()) {
+            state.killReadCache();
+        } else {
+            state.killReadCache(identity, -1);
+        }
+    }
+
+    @Override
+    protected void processInitialLoopState(Loop<Block> loop, PEReadEliminationBlockState initialState) {
+        super.processInitialLoopState(loop, initialState);
+
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            ValueNode firstValue = phi.valueAt(0);
+            if (firstValue != null) {
+                firstValue = GraphUtil.unproxify(firstValue);
+                for (Map.Entry<ReadCacheEntry, ValueNode> entry : new ArrayList<>(initialState.getReadCache().entrySet())) {
+                    if (entry.getKey().object == firstValue) {
+                        initialState.addReadCache(phi, entry.getKey().identity, entry.getKey().index, entry.getValue(), this);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
+        super.processLoopExit(exitNode, initialState, exitState, effects);
+
+        if (exitNode.graph().hasValueProxies()) {
+            for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
+                if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                    ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this);
+                    assert value != null : "Got null from read cache, entry's value:" + entry.getValue();
+                    if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
+                        ProxyNode proxy = new ValueProxyNode(value, exitNode);
+                        effects.addFloatingNode(proxy, "readCacheProxy");
+                        entry.setValue(proxy);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected PEReadEliminationBlockState cloneState(PEReadEliminationBlockState other) {
+        return new PEReadEliminationBlockState(other);
+    }
+
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new ReadEliminationMergeProcessor(merge);
+    }
+
+    private class ReadEliminationMergeProcessor extends MergeProcessor {
+
+        ReadEliminationMergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
+        }
+
+        @Override
+        protected void merge(List<PEReadEliminationBlockState> states) {
+            super.merge(states);
+
+            mergeReadCache(states);
+        }
+
+        private void mergeReadCache(List<PEReadEliminationBlockState> states) {
+            for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                ReadCacheEntry key = entry.getKey();
+                ValueNode value = entry.getValue();
+                boolean phi = false;
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode otherValue = states.get(i).readCache.get(key);
+                    // e.g. unsafe loads / stores with different access kinds have different stamps
+                    // although location, object and offset are the same, in this case we cannot
+                    // create a phi nor can we set a common value
+                    if (otherValue == null || !value.stamp().isCompatible(otherValue.stamp())) {
+                        value = null;
+                        phi = false;
+                        break;
+                    }
+                    if (!phi && otherValue != value) {
+                        phi = true;
+                    }
+                }
+                if (phi) {
+                    PhiNode phiNode = getPhi(entry, value.stamp().unrestricted());
+                    mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
+                    for (int i = 0; i < states.size(); i++) {
+                        ValueNode v = states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this);
+                        assert phiNode.stamp().isCompatible(v.stamp()) : "Cannot create read elimination phi for inputs with incompatible stamps.";
+                        setPhiInput(phiNode, i, v);
+                    }
+                    newState.readCache.put(key, phiNode);
+                } else if (value != null) {
+                    newState.readCache.put(key, value);
+                }
+            }
+            for (PhiNode phi : getPhis()) {
+                if (phi.getStackKind() == JavaKind.Object) {
+                    for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                        if (entry.getKey().object == getPhiValueAt(phi, 0)) {
+                            mergeReadCachePhi(phi, entry.getKey().identity, entry.getKey().index, states);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, List<PEReadEliminationBlockState> states) {
+            ValueNode[] values = new ValueNode[states.size()];
+            values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, PEReadEliminationClosure.this);
+            if (values[0] != null) {
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode value = states.get(i).getReadCache(getPhiValueAt(phi, i), identity, index, PEReadEliminationClosure.this);
+                    // e.g. unsafe loads / stores with same identity and different access kinds see
+                    // mergeReadCache(states)
+                    if (value == null || !values[i - 1].stamp().isCompatible(value.stamp())) {
+                        return;
+                    }
+                    values[i] = value;
+                }
+
+                PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted());
+                mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
+                for (int i = 0; i < values.length; i++) {
+                    setPhiInput(phiNode, i, values[i]);
+                }
+                newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode);
+            }
+        }
+    }
+
+    @Override
+    protected void processKilledLoopLocations(Loop<Block> loop, PEReadEliminationBlockState initialState, PEReadEliminationBlockState mergedStates) {
+        assert initialState != null;
+        assert mergedStates != null;
+        if (initialState.readCache.size() > 0) {
+            LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
+            // we have fully processed this loop the first time, remember to cache it the next time
+            // it is visited
+            if (loopKilledLocations == null) {
+                loopKilledLocations = new LoopKillCache(1/* 1.visit */);
+                loopLocationKillCache.put(loop, loopKilledLocations);
+            } else {
+                if (loopKilledLocations.visits() > ReadEliminationMaxLoopVisits.getValue()) {
+                    // we have processed the loop too many times, kill all locations so the inner
+                    // loop will never be processed more than once again on visit
+                    loopKilledLocations.setKillsAll();
+                } else {
+                    // we have fully processed this loop >1 times, update the killed locations
+                    Set<LocationIdentity> forwardEndLiveLocations = new HashSet<>();
+                    for (ReadCacheEntry entry : initialState.readCache.keySet()) {
+                        forwardEndLiveLocations.add(entry.identity);
+                    }
+                    for (ReadCacheEntry entry : mergedStates.readCache.keySet()) {
+                        forwardEndLiveLocations.remove(entry.identity);
+                    }
+                    // every location that is alive before the loop but not after is killed by the
+                    // loop
+                    for (LocationIdentity location : forwardEndLiveLocations) {
+                        loopKilledLocations.rememberLoopKilledLocation(location);
+                    }
+                    if (Debug.isLogEnabled() && loopKilledLocations != null) {
+                        Debug.log("[Early Read Elimination] Setting loop killed locations of loop at node %s with %s",
+                                        loop.getHeader().getBeginNode(), forwardEndLiveLocations);
+                    }
+                }
+                // remember the loop visit
+                loopKilledLocations.visited();
+            }
+        }
+    }
+
+    @Override
+    protected PEReadEliminationBlockState stripKilledLoopLocations(Loop<Block> loop, PEReadEliminationBlockState originalInitialState) {
+        PEReadEliminationBlockState initialState = super.stripKilledLoopLocations(loop, originalInitialState);
+        LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
+        if (loopKilledLocations != null && loopKilledLocations.loopKillsLocations()) {
+            Set<ReadCacheEntry> forwardEndLiveLocations = initialState.readCache.keySet();
+            Iterator<ReadCacheEntry> it = forwardEndLiveLocations.iterator();
+            while (it.hasNext()) {
+                ReadCacheEntry entry = it.next();
+                if (loopKilledLocations.containsLocation(entry.identity)) {
+                    it.remove();
+                }
+            }
+        }
+        return initialState;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java
new file mode 100644
index 0000000..a338e54
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.nodes.virtual.LockState;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> {
+
+    private static final ObjectState[] EMPTY_ARRAY = new ObjectState[0];
+
+    private ObjectState[] objectStates;
+
+    private static class RefCount {
+        private int refCount = 1;
+    }
+
+    private RefCount arrayRefCount;
+
+    /**
+     * Final subclass of PartialEscapeBlockState, for performance and to make everything behave
+     * nicely with generics.
+     */
+    public static final class Final extends PartialEscapeBlockState<Final> {
+
+        public Final() {
+        }
+
+        public Final(Final other) {
+            super(other);
+        }
+    }
+
+    protected PartialEscapeBlockState() {
+        objectStates = EMPTY_ARRAY;
+        arrayRefCount = new RefCount();
+    }
+
+    protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) {
+        super(other);
+        adoptAddObjectStates(other);
+    }
+
+    public ObjectState getObjectState(int object) {
+        ObjectState state = objectStates[object];
+        assert state != null;
+        return state;
+    }
+
+    public ObjectState getObjectStateOptional(int object) {
+        return object >= objectStates.length ? null : objectStates[object];
+    }
+
+    public ObjectState getObjectState(VirtualObjectNode object) {
+        ObjectState state = objectStates[object.getObjectId()];
+        assert state != null;
+        return state;
+    }
+
+    public ObjectState getObjectStateOptional(VirtualObjectNode object) {
+        int id = object.getObjectId();
+        return id >= objectStates.length ? null : objectStates[id];
+    }
+
+    private ObjectState[] getObjectStateArrayForModification() {
+        if (arrayRefCount.refCount > 1) {
+            objectStates = objectStates.clone();
+            arrayRefCount = new RefCount();
+        }
+        return objectStates;
+    }
+
+    private ObjectState getObjectStateForModification(int object) {
+        ObjectState[] array = getObjectStateArrayForModification();
+        ObjectState objectState = array[object];
+        if (objectState.copyOnWrite) {
+            array[object] = objectState = objectState.cloneState();
+        }
+        return objectState;
+    }
+
+    public void setEntry(int object, int entryIndex, ValueNode value) {
+        if (objectStates[object].getEntry(entryIndex) != value) {
+            getObjectStateForModification(object).setEntry(entryIndex, value);
+        }
+    }
+
+    public void escape(int object, ValueNode materialized) {
+        getObjectStateForModification(object).escape(materialized);
+    }
+
+    public void addLock(int object, MonitorIdNode monitorId) {
+        getObjectStateForModification(object).addLock(monitorId);
+    }
+
+    public MonitorIdNode removeLock(int object) {
+        return getObjectStateForModification(object).removeLock();
+    }
+
+    public void setEnsureVirtualized(int object, boolean ensureVirtualized) {
+        if (objectStates[object].getEnsureVirtualized() != ensureVirtualized) {
+            getObjectStateForModification(object).setEnsureVirtualized(ensureVirtualized);
+        }
+    }
+
+    public void updateMaterializedValue(int object, ValueNode value) {
+        if (objectStates[object].getMaterializedValue() != value) {
+            getObjectStateForModification(object).updateMaterializedValue(value);
+        }
+    }
+
+    public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) {
+        PartialEscapeClosure.COUNTER_MATERIALIZATIONS.increment();
+        List<AllocatedObjectNode> objects = new ArrayList<>(2);
+        List<ValueNode> values = new ArrayList<>(8);
+        List<List<MonitorIdNode>> locks = new ArrayList<>(2);
+        List<ValueNode> otherAllocations = new ArrayList<>(2);
+        List<Boolean> ensureVirtual = new ArrayList<>(2);
+        materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations);
+        assert fixed != null;
+
+        materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> {
+            for (ValueNode otherAllocation : otherAllocations) {
+                graph.addWithoutUnique(otherAllocation);
+                if (otherAllocation instanceof FixedWithNextNode) {
+                    graph.addBeforeFixed(fixed, (FixedWithNextNode) otherAllocation);
+                } else {
+                    assert otherAllocation instanceof FloatingNode;
+                }
+            }
+            if (!objects.isEmpty()) {
+                CommitAllocationNode commit;
+                if (fixed.predecessor() instanceof CommitAllocationNode) {
+                    commit = (CommitAllocationNode) fixed.predecessor();
+                } else {
+                    commit = graph.add(new CommitAllocationNode());
+                    graph.addBeforeFixed(fixed, commit);
+                }
+                for (AllocatedObjectNode obj : objects) {
+                    graph.addWithoutUnique(obj);
+                    commit.getVirtualObjects().add(obj.getVirtualObject());
+                    obj.setCommit(commit);
+                }
+                commit.getValues().addAll(values);
+                for (List<MonitorIdNode> monitorIds : locks) {
+                    commit.addLocks(monitorIds);
+                }
+                commit.getEnsureVirtual().addAll(ensureVirtual);
+
+                assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount();
+                List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
+                for (int i = 0; i < commit.getValues().size(); i++) {
+                    if (materializedValues.contains(commit.getValues().get(i))) {
+                        commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject());
+                    }
+                }
+            }
+        });
+    }
+
+    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
+                    List<Boolean> ensureVirtual, List<ValueNode> otherAllocations) {
+        ObjectState obj = getObjectState(virtual);
+
+        ValueNode[] entries = obj.getEntries();
+        ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
+        escape(virtual.getObjectId(), representation);
+        obj = getObjectState(virtual);
+        PartialEscapeClosure.updateStatesForMaterialized(this, virtual, obj.getMaterializedValue());
+        if (representation instanceof AllocatedObjectNode) {
+            objects.add((AllocatedObjectNode) representation);
+            locks.add(LockState.asList(obj.getLocks()));
+            ensureVirtual.add(obj.getEnsureVirtualized());
+            int pos = values.size();
+            while (values.size() < pos + entries.length) {
+                values.add(null);
+            }
+            for (int i = 0; i < entries.length; i++) {
+                if (entries[i] instanceof VirtualObjectNode) {
+                    VirtualObjectNode entryVirtual = (VirtualObjectNode) entries[i];
+                    ObjectState entryObj = getObjectState(entryVirtual);
+                    if (entryObj.isVirtual()) {
+                        materializeWithCommit(fixed, entryVirtual, objects, locks, values, ensureVirtual, otherAllocations);
+                        entryObj = getObjectState(entryVirtual);
+                    }
+                    values.set(pos + i, entryObj.getMaterializedValue());
+                } else {
+                    values.set(pos + i, entries[i]);
+                }
+            }
+            objectMaterialized(virtual, (AllocatedObjectNode) representation, values.subList(pos, pos + entries.length));
+        } else {
+            VirtualUtil.trace("materialized %s as %s", virtual, representation);
+            otherAllocations.add(representation);
+            assert obj.getLocks() == null;
+        }
+    }
+
+    protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
+        VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values);
+    }
+
+    public void addObject(int virtual, ObjectState state) {
+        ensureSize(virtual)[virtual] = state;
+    }
+
+    private ObjectState[] ensureSize(int objectId) {
+        if (objectStates.length <= objectId) {
+            objectStates = Arrays.copyOf(objectStates, Math.max(objectId * 2, 4));
+            arrayRefCount.refCount--;
+            arrayRefCount = new RefCount();
+            return objectStates;
+        } else {
+            return getObjectStateArrayForModification();
+        }
+    }
+
+    public int getStateCount() {
+        return objectStates.length;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + ", Object States: " + Arrays.toString(objectStates);
+    }
+
+    @Override
+    public boolean equivalentTo(T other) {
+        int length = Math.max(objectStates.length, other.getStateCount());
+        for (int i = 0; i < length; i++) {
+            ObjectState left = getObjectStateOptional(i);
+            ObjectState right = other.getObjectStateOptional(i);
+            if (left != right) {
+                if (left == null || right == null) {
+                    return false;
+                }
+                if (!left.equals(right)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
+        if (left.size() != right.size()) {
+            return false;
+        }
+        return compareMapsNoSize(left, right);
+    }
+
+    protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
+        if (left == right) {
+            return true;
+        }
+        for (Map.Entry<K, V> entry : right.entrySet()) {
+            K key = entry.getKey();
+            V value = entry.getValue();
+            assert value != null;
+            V otherValue = left.get(key);
+            if (otherValue != value && !value.equals(otherValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
+        Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<U, V> entry = iter.next();
+            if (source.containsKey(entry.getKey())) {
+                assert source.get(entry.getKey()) == entry.getValue();
+            } else {
+                iter.remove();
+            }
+        }
+    }
+
+    public void resetObjectStates(int size) {
+        objectStates = new ObjectState[size];
+    }
+
+    public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states) {
+        for (int i = 1; i < states.length; i++) {
+            if (states[0].objectStates != states[i].objectStates) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states, int object) {
+        for (int i = 1; i < states.length; i++) {
+            if (states[0].objectStates[object] != states[i].objectStates[object]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void adoptAddObjectStates(PartialEscapeBlockState<?> other) {
+        if (objectStates != null) {
+            arrayRefCount.refCount--;
+        }
+        objectStates = other.objectStates;
+        arrayRefCount = other.arrayRefCount;
+
+        if (arrayRefCount.refCount == 1) {
+            for (ObjectState state : objectStates) {
+                if (state != null) {
+                    state.share();
+                }
+            }
+        }
+        arrayRefCount.refCount++;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java
new file mode 100644
index 0000000..8f09e52
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java
@@ -0,0 +1,1074 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.IntFunction;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.util.ArraySet;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.VirtualState.NodeClosure;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockState<BlockT>> extends EffectsClosure<BlockT> {
+
+    public static final DebugCounter COUNTER_MATERIALIZATIONS = Debug.counter("Materializations");
+    public static final DebugCounter COUNTER_MATERIALIZATIONS_PHI = Debug.counter("MaterializationsPhi");
+    public static final DebugCounter COUNTER_MATERIALIZATIONS_MERGE = Debug.counter("MaterializationsMerge");
+    public static final DebugCounter COUNTER_MATERIALIZATIONS_UNHANDLED = Debug.counter("MaterializationsUnhandled");
+    public static final DebugCounter COUNTER_MATERIALIZATIONS_LOOP_REITERATION = Debug.counter("MaterializationsLoopReiteration");
+    public static final DebugCounter COUNTER_MATERIALIZATIONS_LOOP_END = Debug.counter("MaterializationsLoopEnd");
+    public static final DebugCounter COUNTER_ALLOCATION_REMOVED = Debug.counter("AllocationsRemoved");
+    public static final DebugCounter COUNTER_MEMORYCHECKPOINT = Debug.counter("MemoryCheckpoint");
+
+    private final NodeBitMap hasVirtualInputs;
+    private final VirtualizerToolImpl tool;
+
+    public final ArrayList<VirtualObjectNode> virtualObjects = new ArrayList<>();
+
+    private final class CollectVirtualObjectsClosure extends NodeClosure<ValueNode> {
+        private final Set<VirtualObjectNode> virtual;
+        private final GraphEffectList effects;
+        private final BlockT state;
+
+        private CollectVirtualObjectsClosure(Set<VirtualObjectNode> virtual, GraphEffectList effects, BlockT state) {
+            this.virtual = virtual;
+            this.effects = effects;
+            this.state = state;
+        }
+
+        @Override
+        public void apply(Node usage, ValueNode value) {
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode object = (VirtualObjectNode) value;
+                if (object.getObjectId() != -1 && state.getObjectStateOptional(object) != null) {
+                    virtual.add(object);
+                }
+            } else {
+                ValueNode alias = getAlias(value);
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode object = (VirtualObjectNode) alias;
+                    virtual.add(object);
+                    effects.replaceFirstInput(usage, value, object);
+                }
+            }
+        }
+    }
+
+    /**
+     * Final subclass of PartialEscapeClosure, for performance and to make everything behave nicely
+     * with generics.
+     */
+    public static final class Final extends PartialEscapeClosure<PartialEscapeBlockState.Final> {
+
+        public Final(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                        LoweringProvider loweringProvider) {
+            super(schedule, metaAccess, constantReflection, constantFieldProvider, loweringProvider);
+        }
+
+        @Override
+        protected PartialEscapeBlockState.Final getInitialState() {
+            return new PartialEscapeBlockState.Final();
+        }
+
+        @Override
+        protected PartialEscapeBlockState.Final cloneState(PartialEscapeBlockState.Final oldState) {
+            return new PartialEscapeBlockState.Final(oldState);
+        }
+    }
+
+    public PartialEscapeClosure(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider) {
+        this(schedule, metaAccess, constantReflection, constantFieldProvider, null);
+    }
+
+    public PartialEscapeClosure(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
+                    LoweringProvider loweringProvider) {
+        super(schedule, schedule.getCFG());
+        StructuredGraph graph = schedule.getCFG().graph;
+        this.hasVirtualInputs = graph.createNodeBitMap();
+        this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, constantFieldProvider, this, graph.getAssumptions(), loweringProvider);
+    }
+
+    /**
+     * @return true if the node was deleted, false otherwise
+     */
+    @Override
+    protected boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        /*
+         * These checks make up for the fact that an earliest schedule moves CallTargetNodes upwards
+         * and thus materializes virtual objects needlessly. Also, FrameStates and ConstantNodes are
+         * scheduled, but can safely be ignored.
+         */
+        if (node instanceof CallTargetNode || node instanceof FrameState || node instanceof ConstantNode) {
+            return false;
+        } else if (node instanceof Invoke) {
+            processNodeInternal(((Invoke) node).callTarget(), state, effects, lastFixedNode);
+        }
+        return processNodeInternal(node, state, effects, lastFixedNode);
+    }
+
+    private boolean processNodeInternal(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
+        VirtualUtil.trace("%s", node);
+
+        if (requiresProcessing(node)) {
+            if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) {
+                return false;
+            }
+            if (tool.isDeleted()) {
+                VirtualUtil.trace("deleted virtualizable allocation %s", node);
+                return true;
+            }
+        }
+        if (hasVirtualInputs.isMarked(node) && node instanceof ValueNode) {
+            if (node instanceof Virtualizable) {
+                if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) {
+                    return false;
+                }
+                if (tool.isDeleted()) {
+                    VirtualUtil.trace("deleted virtualizable node %s", node);
+                    return true;
+                }
+            }
+            processNodeInputs((ValueNode) node, nextFixedNode, state, effects);
+        }
+
+        if (hasScalarReplacedInputs(node) && node instanceof ValueNode) {
+            if (processNodeWithScalarReplacedInputs((ValueNode) node, nextFixedNode, state, effects)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected boolean requiresProcessing(Node node) {
+        return node instanceof VirtualizableAllocation;
+    }
+
+    private boolean processNodeWithScalarReplacedInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
+        ValueNode canonicalizedValue = node;
+        if (node instanceof Canonicalizable.Unary<?>) {
+            @SuppressWarnings("unchecked")
+            Canonicalizable.Unary<ValueNode> canonicalizable = (Canonicalizable.Unary<ValueNode>) node;
+            ObjectState valueObj = getObjectState(state, canonicalizable.getValue());
+            ValueNode valueAlias = valueObj != null ? valueObj.getMaterializedValue() : getScalarAlias(canonicalizable.getValue());
+            if (valueAlias != canonicalizable.getValue()) {
+                canonicalizedValue = (ValueNode) canonicalizable.canonical(tool, valueAlias);
+            }
+        } else if (node instanceof Canonicalizable.Binary<?>) {
+            @SuppressWarnings("unchecked")
+            Canonicalizable.Binary<ValueNode> canonicalizable = (Canonicalizable.Binary<ValueNode>) node;
+            ObjectState xObj = getObjectState(state, canonicalizable.getX());
+            ValueNode xAlias = xObj != null ? xObj.getMaterializedValue() : getScalarAlias(canonicalizable.getX());
+            ObjectState yObj = getObjectState(state, canonicalizable.getY());
+            ValueNode yAlias = yObj != null ? yObj.getMaterializedValue() : getScalarAlias(canonicalizable.getY());
+            if (xAlias != canonicalizable.getX() || yAlias != canonicalizable.getY()) {
+                canonicalizedValue = (ValueNode) canonicalizable.canonical(tool, xAlias, yAlias);
+            }
+        } else {
+            return false;
+        }
+        if (canonicalizedValue != node && canonicalizedValue != null) {
+            if (canonicalizedValue.isAlive()) {
+                ValueNode alias = getAliasAndResolve(state, canonicalizedValue);
+                if (alias instanceof VirtualObjectNode) {
+                    addAndMarkAlias((VirtualObjectNode) alias, node);
+                    effects.deleteNode(node);
+                } else {
+                    effects.replaceAtUsages(node, alias);
+                    addScalarAlias(node, alias);
+                }
+            } else {
+                if (!prepareCanonicalNode(canonicalizedValue, state, effects)) {
+                    VirtualUtil.trace("replacement via canonicalization too complex: %s -> %s", node, canonicalizedValue);
+                    return false;
+                }
+                effects.ensureAdded(canonicalizedValue, insertBefore);
+                if (canonicalizedValue instanceof ControlSinkNode) {
+                    effects.replaceWithSink((FixedWithNextNode) node, (ControlSinkNode) canonicalizedValue);
+                    state.markAsDead();
+                } else {
+                    effects.replaceAtUsages(node, canonicalizedValue);
+                    addScalarAlias(node, canonicalizedValue);
+                }
+            }
+            VirtualUtil.trace("replaced via canonicalization: %s -> %s", node, canonicalizedValue);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean prepareCanonicalNode(ValueNode node, BlockT state, GraphEffectList effects) {
+        assert !node.isAlive();
+        for (Position pos : node.inputPositions()) {
+            Node input = pos.get(node);
+            if (input instanceof ValueNode) {
+                if (input.isAlive()) {
+                    ObjectState obj = getObjectState(state, (ValueNode) input);
+                    if (obj != null) {
+                        if (obj.isVirtual()) {
+                            return false;
+                        } else {
+                            pos.initialize(node, obj.getMaterializedValue());
+                        }
+                    } else {
+                        pos.initialize(node, getScalarAlias((ValueNode) input));
+                    }
+                } else {
+                    if (!prepareCanonicalNode((ValueNode) input, state, effects)) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private void processNodeInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
+        VirtualUtil.trace("processing nodewithstate: %s", node);
+        for (Node input : node.inputs()) {
+            if (input instanceof ValueNode) {
+                ValueNode alias = getAlias((ValueNode) input);
+                if (alias instanceof VirtualObjectNode) {
+                    int id = ((VirtualObjectNode) alias).getObjectId();
+                    ensureMaterialized(state, id, insertBefore, effects, COUNTER_MATERIALIZATIONS_UNHANDLED);
+                    effects.replaceFirstInput(node, input, state.getObjectState(id).getMaterializedValue());
+                    VirtualUtil.trace("replacing input %s at %s", input, node);
+                }
+            }
+        }
+        if (node instanceof NodeWithState) {
+            processNodeWithState((NodeWithState) node, state, effects);
+        }
+    }
+
+    private boolean processVirtualizable(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
+        tool.reset(state, node, insertBefore, effects);
+        return virtualize(node, tool);
+    }
+
+    protected boolean virtualize(ValueNode node, VirtualizerTool vt) {
+        ((Virtualizable) node).virtualize(vt);
+        return true; // request further processing
+    }
+
+    private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) {
+        for (FrameState fs : nodeWithState.states()) {
+            FrameState frameState = getUniqueFramestate(nodeWithState, fs);
+            Set<VirtualObjectNode> virtual = new ArraySet<>();
+            frameState.applyToNonVirtual(new CollectVirtualObjectsClosure(virtual, effects, state));
+            collectLockedVirtualObjects(state, virtual);
+            collectReferencedVirtualObjects(state, virtual);
+            addVirtualMappings(frameState, virtual, state, effects);
+        }
+    }
+
+    private static FrameState getUniqueFramestate(NodeWithState nodeWithState, FrameState frameState) {
+        if (frameState.getUsageCount() > 1) {
+            // Can happen for example from inlined snippets with multiple state split nodes.
+            FrameState copy = (FrameState) frameState.copyWithInputs();
+            nodeWithState.asNode().replaceFirstInput(frameState, copy);
+            return copy;
+        }
+        return frameState;
+    }
+
+    private void addVirtualMappings(FrameState frameState, Set<VirtualObjectNode> virtual, BlockT state, GraphEffectList effects) {
+        for (VirtualObjectNode obj : virtual) {
+            effects.addVirtualMapping(frameState, state.getObjectState(obj).createEscapeObjectState(obj));
+        }
+    }
+
+    private void collectReferencedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) {
+        ArrayDeque<VirtualObjectNode> queue = new ArrayDeque<>(virtual);
+        while (!queue.isEmpty()) {
+            VirtualObjectNode object = queue.removeLast();
+            int id = object.getObjectId();
+            if (id != -1) {
+                ObjectState objState = state.getObjectStateOptional(id);
+                if (objState != null && objState.isVirtual()) {
+                    for (ValueNode entry : objState.getEntries()) {
+                        if (entry instanceof VirtualObjectNode) {
+                            VirtualObjectNode entryVirtual = (VirtualObjectNode) entry;
+                            if (!virtual.contains(entryVirtual)) {
+                                virtual.add(entryVirtual);
+                                queue.addLast(entryVirtual);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void collectLockedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) {
+        for (int i = 0; i < state.getStateCount(); i++) {
+            ObjectState objState = state.getObjectStateOptional(i);
+            if (objState != null && objState.isVirtual() && objState.hasLocks()) {
+                virtual.add(virtualObjects.get(i));
+            }
+        }
+    }
+
+    /**
+     * @return true if materialization happened, false if not.
+     */
+    protected boolean ensureMaterialized(PartialEscapeBlockState<?> state, int object, FixedNode materializeBefore, GraphEffectList effects, DebugCounter counter) {
+        if (state.getObjectState(object).isVirtual()) {
+            counter.increment();
+            VirtualObjectNode virtual = virtualObjects.get(object);
+            state.materializeBefore(materializeBefore, virtual, effects);
+            updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, VirtualObjectNode virtual, ValueNode materializedValue) {
+        // update all existing states with the newly materialized object
+        for (int i = 0; i < state.getStateCount(); i++) {
+            ObjectState objState = state.getObjectStateOptional(i);
+            if (objState != null && objState.isVirtual()) {
+                ValueNode[] entries = objState.getEntries();
+                for (int i2 = 0; i2 < entries.length; i2++) {
+                    if (entries[i2] == virtual) {
+                        state.setEntry(i, i2, materializedValue);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    protected BlockT stripKilledLoopLocations(Loop<Block> loop, BlockT originalInitialState) {
+        BlockT initialState = super.stripKilledLoopLocations(loop, originalInitialState);
+        if (loop.getDepth() > GraalOptions.EscapeAnalysisLoopCutoff.getValue()) {
+            /*
+             * After we've reached the maximum loop nesting, we'll simply materialize everything we
+             * can to make sure that the loops only need to be iterated one time. Care is taken here
+             * to not materialize virtual objects that have the "ensureVirtualized" flag set.
+             */
+            LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
+            AbstractEndNode end = loopBegin.forwardEnd();
+            Block loopPredecessor = loop.getHeader().getFirstPredecessor();
+            assert loopPredecessor.getEndNode() == end;
+            int length = initialState.getStateCount();
+
+            boolean change;
+            boolean[] ensureVirtualized = new boolean[length];
+            for (int i = 0; i < length; i++) {
+                ObjectState state = initialState.getObjectStateOptional(i);
+                if (state != null && state.isVirtual() && state.getEnsureVirtualized()) {
+                    ensureVirtualized[i] = true;
+                }
+            }
+            do {
+                // propagate "ensureVirtualized" flag
+                change = false;
+                for (int i = 0; i < length; i++) {
+                    if (!ensureVirtualized[i]) {
+                        ObjectState state = initialState.getObjectStateOptional(i);
+                        if (state != null && state.isVirtual()) {
+                            for (ValueNode entry : state.getEntries()) {
+                                if (entry instanceof VirtualObjectNode) {
+                                    if (ensureVirtualized[((VirtualObjectNode) entry).getObjectId()]) {
+                                        change = true;
+                                        ensureVirtualized[i] = true;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } while (change);
+
+            for (int i = 0; i < length; i++) {
+                ObjectState state = initialState.getObjectStateOptional(i);
+                if (state != null && state.isVirtual() && !ensureVirtualized[i]) {
+                    initialState.materializeBefore(end, virtualObjects.get(i), blockEffects.get(loopPredecessor));
+                }
+            }
+        }
+        return initialState;
+    }
+
+    @Override
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            if (phi.valueAt(0) != null) {
+                ValueNode alias = getAliasAndResolve(initialState, phi.valueAt(0));
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    addAndMarkAlias(virtual, phi);
+                } else {
+                    aliases.set(phi, null);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) {
+        if (exitNode.graph().hasValueProxies()) {
+            Map<Integer, ProxyNode> proxies = new IdentityHashMap<>();
+            for (ProxyNode proxy : exitNode.proxies()) {
+                ValueNode alias = getAlias(proxy.value());
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    proxies.put(virtual.getObjectId(), proxy);
+                }
+            }
+            for (int i = 0; i < exitState.getStateCount(); i++) {
+                ObjectState exitObjState = exitState.getObjectStateOptional(i);
+                if (exitObjState != null) {
+                    ObjectState initialObjState = initialState.getObjectStateOptional(i);
+
+                    if (exitObjState.isVirtual()) {
+                        processVirtualAtLoopExit(exitNode, effects, i, exitObjState, initialObjState, exitState);
+                    } else {
+                        processMaterializedAtLoopExit(exitNode, effects, proxies, i, exitObjState, initialObjState, exitState);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map<Integer, ProxyNode> proxies, int object, ObjectState exitObjState,
+                    ObjectState initialObjState, PartialEscapeBlockState<?> exitState) {
+        if (initialObjState == null || initialObjState.isVirtual()) {
+            ProxyNode proxy = proxies.get(object);
+            if (proxy == null) {
+                proxy = new ValueProxyNode(exitObjState.getMaterializedValue(), exitNode);
+                effects.addFloatingNode(proxy, "proxy");
+            } else {
+                effects.replaceFirstInput(proxy, proxy.value(), exitObjState.getMaterializedValue());
+                // nothing to do - will be handled in processNode
+            }
+            exitState.updateMaterializedValue(object, proxy);
+        } else {
+            if (initialObjState.getMaterializedValue() != exitObjState.getMaterializedValue()) {
+                Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObjState.getMaterializedValue(), exitObjState.getMaterializedValue(), exitNode);
+            }
+        }
+    }
+
+    private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, int object, ObjectState exitObjState, ObjectState initialObjState,
+                    PartialEscapeBlockState<?> exitState) {
+        for (int i = 0; i < exitObjState.getEntries().length; i++) {
+            ValueNode value = exitState.getObjectState(object).getEntry(i);
+            if (!(value instanceof VirtualObjectNode || value.isConstant())) {
+                if (exitNode.loopBegin().isPhiAtMerge(value) || initialObjState == null || !initialObjState.isVirtual() || initialObjState.getEntry(i) != value) {
+                    ProxyNode proxy = new ValueProxyNode(value, exitNode);
+                    exitState.setEntry(object, i, proxy);
+                    effects.addFloatingNode(proxy, "virtualProxy");
+                }
+            }
+        }
+    }
+
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new MergeProcessor(merge);
+    }
+
+    protected class MergeProcessor extends EffectsClosure<BlockT>.MergeProcessor {
+
+        private HashMap<Object, ValuePhiNode> materializedPhis;
+        private Map<ValueNode, ValuePhiNode[]> valuePhis;
+        private Map<ValuePhiNode, VirtualObjectNode> valueObjectVirtuals;
+        private final boolean needsCaching;
+
+        public MergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
+            needsCaching = mergeBlock.isLoopHeader();
+        }
+
+        protected <T> PhiNode getPhi(T virtual, Stamp stamp) {
+            if (needsCaching) {
+                return getPhiCached(virtual, stamp);
+            } else {
+                return createValuePhi(stamp);
+            }
+        }
+
+        private <T> PhiNode getPhiCached(T virtual, Stamp stamp) {
+            if (materializedPhis == null) {
+                materializedPhis = CollectionsFactory.newMap();
+            }
+            ValuePhiNode result = materializedPhis.get(virtual);
+            if (result == null) {
+                result = createValuePhi(stamp);
+                materializedPhis.put(virtual, result);
+            }
+            return result;
+        }
+
+        private PhiNode[] getValuePhis(ValueNode key, int entryCount) {
+            if (needsCaching) {
+                return getValuePhisCached(key, entryCount);
+            } else {
+                return new ValuePhiNode[entryCount];
+            }
+        }
+
+        private PhiNode[] getValuePhisCached(ValueNode key, int entryCount) {
+            if (valuePhis == null) {
+                valuePhis = Node.newIdentityMap();
+            }
+            ValuePhiNode[] result = valuePhis.get(key);
+            if (result == null) {
+                result = new ValuePhiNode[entryCount];
+                valuePhis.put(key, result);
+            }
+            assert result.length == entryCount;
+            return result;
+        }
+
+        private VirtualObjectNode getValueObjectVirtual(ValuePhiNode phi, VirtualObjectNode virtual) {
+            if (needsCaching) {
+                return getValueObjectVirtualCached(phi, virtual);
+            } else {
+                return virtual.duplicate();
+            }
+        }
+
+        private VirtualObjectNode getValueObjectVirtualCached(ValuePhiNode phi, VirtualObjectNode virtual) {
+            if (valueObjectVirtuals == null) {
+                valueObjectVirtuals = Node.newIdentityMap();
+            }
+            VirtualObjectNode result = valueObjectVirtuals.get(phi);
+            if (result == null) {
+                result = virtual.duplicate();
+                valueObjectVirtuals.put(phi, result);
+            }
+            return result;
+        }
+
+        /**
+         * Merge all predecessor block states into one block state. This is an iterative process,
+         * because merging states can lead to materializations which make previous parts of the
+         * merging operation invalid. The merging process is executed until a stable state has been
+         * reached. This method needs to be careful to place the effects of the merging operation
+         * into the correct blocks.
+         *
+         * @param statesList the predecessor block states of the merge
+         */
+        @Override
+        protected void merge(List<BlockT> statesList) {
+            super.merge(statesList);
+
+            PartialEscapeBlockState<?>[] states = new PartialEscapeBlockState<?>[statesList.size()];
+            for (int i = 0; i < statesList.size(); i++) {
+                states[i] = statesList.get(i);
+            }
+
+            // calculate the set of virtual objects that exist in all predecessors
+            int[] virtualObjTemp = intersectVirtualObjects(states);
+
+            boolean materialized;
+            do {
+                materialized = false;
+
+                if (PartialEscapeBlockState.identicalObjectStates(states)) {
+                    newState.adoptAddObjectStates(states[0]);
+                } else {
+
+                    for (int object : virtualObjTemp) {
+
+                        if (PartialEscapeBlockState.identicalObjectStates(states, object)) {
+                            newState.addObject(object, states[0].getObjectState(object).share());
+                            continue;
+                        }
+
+                        // determine if all inputs are virtual or the same materialized value
+                        int virtualCount = 0;
+                        ObjectState startObj = states[0].getObjectState(object);
+                        boolean locksMatch = true;
+                        boolean ensureVirtual = true;
+                        ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue();
+                        for (int i = 0; i < states.length; i++) {
+                            ObjectState obj = states[i].getObjectState(object);
+                            ensureVirtual &= obj.getEnsureVirtualized();
+                            if (obj.isVirtual()) {
+                                virtualCount++;
+                                uniqueMaterializedValue = null;
+                                locksMatch &= obj.locksEqual(startObj);
+                            } else if (obj.getMaterializedValue() != uniqueMaterializedValue) {
+                                uniqueMaterializedValue = null;
+                            }
+                        }
+
+                        if (virtualCount == states.length && locksMatch) {
+                            materialized |= mergeObjectStates(object, null, states);
+                        } else {
+                            if (uniqueMaterializedValue != null) {
+                                newState.addObject(object, new ObjectState(uniqueMaterializedValue, null, ensureVirtual));
+                            } else {
+                                PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(JavaKind.Object));
+                                mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
+                                for (int i = 0; i < states.length; i++) {
+                                    ObjectState obj = states[i].getObjectState(object);
+                                    if (obj.isVirtual()) {
+                                        Block predecessor = getPredecessor(i);
+                                        if (!ensureVirtual && obj.isVirtual()) {
+                                            // we can materialize if not all inputs are
+                                            // "ensureVirtualized"
+                                            obj.setEnsureVirtualized(false);
+                                        }
+                                        materialized |= ensureMaterialized(states[i], object, predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_MERGE);
+                                        obj = states[i].getObjectState(object);
+                                    }
+                                    setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
+                                }
+                                newState.addObject(object, new ObjectState(materializedValuePhi, null, false));
+                            }
+                        }
+                    }
+                }
+
+                for (PhiNode phi : getPhis()) {
+                    aliases.set(phi, null);
+                    if (hasVirtualInputs.isMarked(phi) && phi instanceof ValuePhiNode) {
+                        materialized |= processPhi((ValuePhiNode) phi, states, virtualObjTemp);
+                    }
+                }
+                if (materialized) {
+                    newState.resetObjectStates(virtualObjects.size());
+                    mergeEffects.clear();
+                    afterMergeEffects.clear();
+                }
+            } while (materialized);
+        }
+
+        private int[] intersectVirtualObjects(PartialEscapeBlockState<?>[] states) {
+            int length = states[0].getStateCount();
+            for (int i = 1; i < states.length; i++) {
+                length = Math.min(length, states[i].getStateCount());
+            }
+            boolean[] result = new boolean[length];
+            Arrays.fill(result, true);
+            int count = length;
+            for (int i = 0; i < states.length; i++) {
+                PartialEscapeBlockState<?> state = states[i];
+                for (int i2 = 0; i2 < length; i2++) {
+                    if (result[i2]) {
+                        if (state.getObjectStateOptional(i2) == null) {
+                            result[i2] = false;
+                            count--;
+                        }
+                    }
+                }
+            }
+            int[] resultInts = new int[count];
+            int index = 0;
+            for (int i = 0; i < length; i++) {
+                if (result[i]) {
+                    resultInts[index++] = i;
+                }
+            }
+            assert index == count;
+            return resultInts;
+        }
+
+        /**
+         * Try to merge multiple virtual object states into a single object state. If the incoming
+         * object states are compatible, then this method will create PhiNodes for the object's
+         * entries where needed. If they are incompatible, then all incoming virtual objects will be
+         * materialized, and a PhiNode for the materialized values will be created. Object states
+         * can be incompatible if they contain {@code long} or {@code double} values occupying two
+         * {@code int} slots in such a way that that their values cannot be merged using PhiNodes.
+         *
+         * @param states the predecessor block states of the merge
+         * @return true if materialization happened during the merge, false otherwise
+         */
+        private boolean mergeObjectStates(int resultObject, int[] sourceObjects, PartialEscapeBlockState<?>[] states) {
+            boolean compatible = true;
+            boolean ensureVirtual = true;
+            IntFunction<Integer> getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index];
+
+            VirtualObjectNode virtual = virtualObjects.get(resultObject);
+            int entryCount = virtual.entryCount();
+
+            // determine all entries that have a two-slot value
+            JavaKind[] twoSlotKinds = null;
+            outer: for (int i = 0; i < states.length; i++) {
+                ObjectState objectState = states[i].getObjectState(getObject.apply(i));
+                ValueNode[] entries = objectState.getEntries();
+                int valueIndex = 0;
+                ensureVirtual &= objectState.getEnsureVirtualized();
+                while (valueIndex < entryCount) {
+                    JavaKind otherKind = entries[valueIndex].getStackKind();
+                    JavaKind entryKind = virtual.entryKind(valueIndex);
+                    if (entryKind == JavaKind.Int && otherKind.needsTwoSlots()) {
+                        if (twoSlotKinds == null) {
+                            twoSlotKinds = new JavaKind[entryCount];
+                        }
+                        if (twoSlotKinds[valueIndex] != null && twoSlotKinds[valueIndex] != otherKind) {
+                            compatible = false;
+                            break outer;
+                        }
+                        twoSlotKinds[valueIndex] = otherKind;
+                        // skip the next entry
+                        valueIndex++;
+                    } else {
+                        assert entryKind.getStackKind() == otherKind.getStackKind() || (entryKind == JavaKind.Int && otherKind == JavaKind.Illegal) ||
+                                        entryKind.getBitCount() >= otherKind.getBitCount() : entryKind + " vs " + otherKind;
+                    }
+                    valueIndex++;
+                }
+            }
+            if (compatible && twoSlotKinds != null) {
+                // if there are two-slot values then make sure the incoming states can be merged
+                outer: for (int valueIndex = 0; valueIndex < entryCount; valueIndex++) {
+                    if (twoSlotKinds[valueIndex] != null) {
+                        assert valueIndex < virtual.entryCount() - 1 && virtual.entryKind(valueIndex) == JavaKind.Int && virtual.entryKind(valueIndex + 1) == JavaKind.Int;
+                        for (int i = 0; i < states.length; i++) {
+                            int object = getObject.apply(i);
+                            ObjectState objectState = states[i].getObjectState(object);
+                            ValueNode value = objectState.getEntry(valueIndex);
+                            JavaKind valueKind = value.getStackKind();
+                            if (valueKind != twoSlotKinds[valueIndex]) {
+                                ValueNode nextValue = objectState.getEntry(valueIndex + 1);
+                                if (value.isConstant() && value.asConstant().equals(JavaConstant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(JavaConstant.INT_0)) {
+                                    // rewrite to a zero constant of the larger kind
+                                    states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph()));
+                                    states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()));
+                                } else {
+                                    compatible = false;
+                                    break outer;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (compatible) {
+                // virtual objects are compatible: create phis for all entries that need them
+                ValueNode[] values = states[0].getObjectState(getObject.apply(0)).getEntries().clone();
+                PhiNode[] phis = getValuePhis(virtual, virtual.entryCount());
+                int valueIndex = 0;
+                while (valueIndex < values.length) {
+                    for (int i = 1; i < states.length; i++) {
+                        if (phis[valueIndex] == null) {
+                            ValueNode field = states[i].getObjectState(getObject.apply(i)).getEntry(valueIndex);
+                            if (values[valueIndex] != field) {
+                                phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted());
+                            }
+                        }
+                    }
+                    if (phis[valueIndex] != null && !phis[valueIndex].stamp().isCompatible(values[valueIndex].stamp())) {
+                        phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted());
+                    }
+                    if (twoSlotKinds != null && twoSlotKinds[valueIndex] != null) {
+                        // skip an entry after a long/double value that occupies two int slots
+                        valueIndex++;
+                        phis[valueIndex] = null;
+                        values[valueIndex] = ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph());
+                    }
+                    valueIndex++;
+                }
+
+                boolean materialized = false;
+                for (int i = 0; i < values.length; i++) {
+                    PhiNode phi = phis[i];
+                    if (phi != null) {
+                        mergeEffects.addFloatingNode(phi, "virtualMergePhi");
+                        if (virtual.entryKind(i) == JavaKind.Object) {
+                            materialized |= mergeObjectEntry(getObject, states, phi, i);
+                        } else {
+                            for (int i2 = 0; i2 < states.length; i2++) {
+                                ObjectState state = states[i2].getObjectState(getObject.apply(i2));
+                                if (!state.isVirtual()) {
+                                    break;
+                                }
+                                setPhiInput(phi, i2, state.getEntry(i));
+                            }
+                        }
+                        values[i] = phi;
+                    }
+                }
+                newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.apply(0)).getLocks(), ensureVirtual));
+                return materialized;
+            } else {
+                // not compatible: materialize in all predecessors
+                PhiNode materializedValuePhi = getPhi(resultObject, StampFactory.forKind(JavaKind.Object));
+                for (int i = 0; i < states.length; i++) {
+                    Block predecessor = getPredecessor(i);
+                    if (!ensureVirtual && states[i].getObjectState(virtual).isVirtual()) {
+                        // we can materialize if not all inputs are "ensureVirtualized"
+                        states[i].getObjectState(virtual).setEnsureVirtualized(false);
+                    }
+                    ensureMaterialized(states[i], getObject.apply(i), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_MERGE);
+                    setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.apply(i)).getMaterializedValue());
+                }
+                newState.addObject(resultObject, new ObjectState(materializedValuePhi, null, ensureVirtual));
+                return true;
+            }
+        }
+
+        /**
+         * Fill the inputs of the PhiNode corresponding to one {@link JavaKind#Object} entry in the
+         * virtual object.
+         *
+         * @return true if materialization happened during the merge, false otherwise
+         */
+        private boolean mergeObjectEntry(IntFunction<Integer> objectIdFunc, PartialEscapeBlockState<?>[] states, PhiNode phi, int entryIndex) {
+            boolean materialized = false;
+            for (int i = 0; i < states.length; i++) {
+                int object = objectIdFunc.apply(i);
+                ObjectState objectState = states[i].getObjectState(object);
+                if (!objectState.isVirtual()) {
+                    break;
+                }
+                ValueNode entry = objectState.getEntry(entryIndex);
+                if (entry instanceof VirtualObjectNode) {
+                    VirtualObjectNode entryVirtual = (VirtualObjectNode) entry;
+                    Block predecessor = getPredecessor(i);
+                    materialized |= ensureMaterialized(states[i], entryVirtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_MERGE);
+                    objectState = states[i].getObjectState(object);
+                    if (objectState.isVirtual()) {
+                        states[i].setEntry(object, entryIndex, entry = states[i].getObjectState(entryVirtual.getObjectId()).getMaterializedValue());
+                    }
+                }
+                setPhiInput(phi, i, entry);
+            }
+            return materialized;
+        }
+
+        /**
+         * Examine a PhiNode and try to replace it with merging of virtual objects if all its inputs
+         * refer to virtual object states. In order for the merging to happen, all incoming object
+         * states need to be compatible and without object identity (meaning that their object
+         * identity if not used later on).
+         *
+         * @param phi the PhiNode that should be processed
+         * @param states the predecessor block states of the merge
+         * @param mergedVirtualObjects the set of virtual objects that exist in all incoming states,
+         *            and therefore also exist in the merged state
+         * @return true if materialization happened during the merge, false otherwise
+         */
+        private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState<?>[] states, int[] mergedVirtualObjects) {
+
+            // determine how many inputs are virtual and if they're all the same virtual object
+            int virtualInputs = 0;
+            boolean uniqueVirtualObject = true;
+            boolean ensureVirtual = true;
+            VirtualObjectNode[] virtualObjs = new VirtualObjectNode[states.length];
+            for (int i = 0; i < states.length; i++) {
+                ValueNode alias = getAlias(getPhiValueAt(phi, i));
+                if (alias instanceof VirtualObjectNode) {
+                    VirtualObjectNode virtual = (VirtualObjectNode) alias;
+                    virtualObjs[i] = virtual;
+                    ObjectState objectState = states[i].getObjectStateOptional(virtual);
+                    if (objectState == null) {
+                        assert getPhiValueAt(phi, i) instanceof PhiNode : "this should only happen for phi nodes";
+                        return false;
+                    }
+                    if (objectState.isVirtual()) {
+                        if (virtualObjs[0] != alias) {
+                            uniqueVirtualObject = false;
+                        }
+                        ensureVirtual &= objectState.getEnsureVirtualized();
+                        virtualInputs++;
+                    }
+                }
+            }
+            if (virtualInputs == states.length) {
+                if (uniqueVirtualObject) {
+                    // all inputs refer to the same object: just make the phi node an alias
+                    addAndMarkAlias(virtualObjs[0], phi);
+                    mergeEffects.deleteNode(phi);
+                    return false;
+                } else {
+                    // all inputs are virtual: check if they're compatible and without identity
+                    boolean compatible = true;
+                    boolean hasIdentity = false;
+                    VirtualObjectNode firstVirtual = virtualObjs[0];
+                    for (int i = 0; i < states.length; i++) {
+                        VirtualObjectNode virtual = virtualObjs[i];
+                        hasIdentity |= virtual.hasIdentity();
+                        boolean identitySurvives = virtual.hasIdentity() && Arrays.asList(mergedVirtualObjects).contains(virtual.getObjectId());
+                        if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) {
+                            compatible = false;
+                            break;
+                        }
+                        if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) {
+                            compatible = false;
+                            break;
+                        }
+                    }
+                    if (compatible && !hasIdentity) {
+                        VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]);
+                        mergeEffects.addFloatingNode(virtual, "valueObjectNode");
+                        mergeEffects.deleteNode(phi);
+                        if (virtual.getObjectId() == -1) {
+                            int id = virtualObjects.size();
+                            virtualObjects.add(virtual);
+                            virtual.setObjectId(id);
+                        }
+
+                        int[] virtualObjectIds = new int[states.length];
+                        for (int i = 0; i < states.length; i++) {
+                            virtualObjectIds[i] = virtualObjs[i].getObjectId();
+                        }
+                        boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states);
+                        addAndMarkAlias(virtual, virtual);
+                        addAndMarkAlias(virtual, phi);
+                        return materialized;
+                    }
+                }
+            }
+
+            // otherwise: materialize all phi inputs
+            boolean materialized = false;
+            if (virtualInputs > 0) {
+                for (int i = 0; i < states.length; i++) {
+                    VirtualObjectNode virtual = virtualObjs[i];
+                    if (virtual != null) {
+                        Block predecessor = getPredecessor(i);
+                        if (!ensureVirtual && states[i].getObjectState(virtual).isVirtual()) {
+                            // we can materialize if not all inputs are "ensureVirtualized"
+                            states[i].getObjectState(virtual).setEnsureVirtualized(false);
+                        }
+                        materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_PHI);
+                    }
+                }
+            }
+            for (int i = 0; i < states.length; i++) {
+                VirtualObjectNode virtual = virtualObjs[i];
+                if (virtual != null) {
+                    setPhiInput(phi, i, getAliasAndResolve(states[i], virtual));
+                }
+            }
+            return materialized;
+        }
+    }
+
+    public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) {
+        if (value == null) {
+            return null;
+        }
+        if (value.isAlive() && !aliases.isNew(value)) {
+            ValueNode object = aliases.get(value);
+            return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null;
+        } else {
+            if (value instanceof VirtualObjectNode) {
+                return state.getObjectStateOptional((VirtualObjectNode) value);
+            }
+            return null;
+        }
+    }
+
+    public ValueNode getAlias(ValueNode value) {
+        if (value != null && !(value instanceof VirtualObjectNode)) {
+            if (value.isAlive() && !aliases.isNew(value)) {
+                ValueNode result = aliases.get(value);
+                if (result != null) {
+                    return result;
+                }
+            }
+        }
+        return value;
+    }
+
+    public ValueNode getAliasAndResolve(PartialEscapeBlockState<?> state, ValueNode value) {
+        ValueNode result = getAlias(value);
+        if (result instanceof VirtualObjectNode) {
+            int id = ((VirtualObjectNode) result).getObjectId();
+            if (id != -1 && !state.getObjectState(id).isVirtual()) {
+                result = state.getObjectState(id).getMaterializedValue();
+            }
+        }
+        return result;
+    }
+
+    void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) {
+        if (node.isAlive()) {
+            aliases.set(node, virtual);
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage);
+            }
+        }
+    }
+
+    private void markVirtualUsages(Node node) {
+        if (!hasVirtualInputs.isNew(node) && !hasVirtualInputs.isMarked(node)) {
+            hasVirtualInputs.mark(node);
+            if (node instanceof VirtualState) {
+                for (Node usage : node.usages()) {
+                    markVirtualUsages(usage);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java
new file mode 100644
index 0000000..28c7d94
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalysisIterations;
+import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalyzeOnly;
+
+import java.util.Set;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
+
+    static class Options {
+        //@formatter:off
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> OptEarlyReadElimination = new OptionValue<>(true);
+        //@formatter:on
+    }
+
+    private final boolean readElimination;
+    private final BasePhase<PhaseContext> cleanupPhase;
+
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
+        this(iterative, Options.OptEarlyReadElimination.getValue(), canonicalizer, null);
+    }
+
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase) {
+        this(iterative, Options.OptEarlyReadElimination.getValue(), canonicalizer, cleanupPhase);
+    }
+
+    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase) {
+        super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
+        this.readElimination = readElimination;
+        this.cleanupPhase = cleanupPhase;
+    }
+
+    @Override
+    protected void postIteration(StructuredGraph graph, PhaseContext context, Set<Node> changedNodes) {
+        super.postIteration(graph, context, changedNodes);
+        if (cleanupPhase != null) {
+            cleanupPhase.apply(graph, context);
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
+            if (readElimination || graph.hasVirtualizableAllocation()) {
+                runAnalysis(graph, context);
+            }
+        }
+    }
+
+    @Override
+    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
+        for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) {
+            virtual.resetObjectId();
+        }
+        assert schedule != null;
+        if (readElimination) {
+            return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), context.getLowerer());
+        } else {
+            return new PartialEscapeClosure.Final(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), context.getLowerer());
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java
new file mode 100644
index 0000000..f566e2a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+
+public class ReadEliminationBlockState extends EffectsBlockState<ReadEliminationBlockState> {
+
+    final HashMap<CacheEntry<?>, ValueNode> readCache;
+
+    abstract static class CacheEntry<T> {
+
+        public final ValueNode object;
+        public final T identity;
+
+        CacheEntry(ValueNode object, T identity) {
+            this.object = object;
+            this.identity = identity;
+        }
+
+        public abstract CacheEntry<T> duplicateWithObject(ValueNode newObject);
+
+        @Override
+        public int hashCode() {
+            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
+            return 31 * result + ((object == null) ? 0 : object.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof CacheEntry<?>)) {
+                return false;
+            }
+            CacheEntry<?> other = (CacheEntry<?>) obj;
+            return identity.equals(other.identity) && object == other.object;
+        }
+
+        @Override
+        public String toString() {
+            return object + ":" + identity;
+        }
+
+        public abstract boolean conflicts(LocationIdentity other);
+
+        public abstract LocationIdentity getIdentity();
+    }
+
+    static class LoadCacheEntry extends CacheEntry<LocationIdentity> {
+
+        LoadCacheEntry(ValueNode object, LocationIdentity identity) {
+            super(object, identity);
+        }
+
+        @Override
+        public CacheEntry<LocationIdentity> duplicateWithObject(ValueNode newObject) {
+            return new LoadCacheEntry(newObject, identity);
+        }
+
+        @Override
+        public boolean conflicts(LocationIdentity other) {
+            return identity.equals(other);
+        }
+
+        @Override
+        public LocationIdentity getIdentity() {
+            return identity;
+        }
+    }
+
+    /**
+     * CacheEntry describing an Unsafe memory reference. The memory location and the location
+     * identity are separate so both must be considered when looking for optimizable memory
+     * accesses.
+     */
+    static class UnsafeLoadCacheEntry extends CacheEntry<ValueNode> {
+
+        private final LocationIdentity locationIdentity;
+
+        UnsafeLoadCacheEntry(ValueNode object, ValueNode location, LocationIdentity locationIdentity) {
+            super(object, location);
+            assert locationIdentity != null;
+            this.locationIdentity = locationIdentity;
+        }
+
+        @Override
+        public CacheEntry<ValueNode> duplicateWithObject(ValueNode newObject) {
+            return new UnsafeLoadCacheEntry(newObject, identity, locationIdentity);
+        }
+
+        @Override
+        public boolean conflicts(LocationIdentity other) {
+            return locationIdentity.equals(other);
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * super.hashCode() + locationIdentity.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof UnsafeLoadCacheEntry) {
+                UnsafeLoadCacheEntry other = (UnsafeLoadCacheEntry) obj;
+                return super.equals(other) && locationIdentity.equals(other.locationIdentity);
+            }
+            return false;
+        }
+
+        @Override
+        public LocationIdentity getIdentity() {
+            return locationIdentity;
+        }
+
+        @Override
+        public String toString() {
+            return "UNSAFE:" + super.toString() + " location:" + locationIdentity;
+        }
+    }
+
+    public ReadEliminationBlockState() {
+        readCache = CollectionsFactory.newMap();
+    }
+
+    public ReadEliminationBlockState(ReadEliminationBlockState other) {
+        readCache = CollectionsFactory.newMap(other.readCache);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " " + readCache;
+    }
+
+    @Override
+    public boolean equivalentTo(ReadEliminationBlockState other) {
+        return compareMapsNoSize(readCache, other.readCache);
+    }
+
+    public void addCacheEntry(CacheEntry<?> identifier, ValueNode value) {
+        readCache.put(identifier, value);
+    }
+
+    public ValueNode getCacheEntry(CacheEntry<?> identifier) {
+        return readCache.get(identifier);
+    }
+
+    public void killReadCache() {
+        readCache.clear();
+    }
+
+    public void killReadCache(LocationIdentity identity) {
+        readCache.entrySet().removeIf(entry -> entry.getKey().conflicts(identity));
+    }
+
+    public Map<CacheEntry<?>, ValueNode> getReadCache() {
+        return readCache;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java
new file mode 100644
index 0000000..a4562a3
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits;
+import static org.graalvm.compiler.core.common.LocationIdentity.any;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.CollectionsFactory;
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
+import org.graalvm.compiler.nodes.extended.UnsafeLoadNode;
+import org.graalvm.compiler.nodes.extended.UnsafeStoreNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.java.AccessFieldNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
+import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
+import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.UnsafeLoadCacheEntry;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class ReadEliminationClosure extends EffectsClosure<ReadEliminationBlockState> {
+
+    public ReadEliminationClosure(ControlFlowGraph cfg) {
+        super(null, cfg);
+    }
+
+    @Override
+    protected ReadEliminationBlockState getInitialState() {
+        return new ReadEliminationBlockState();
+    }
+
+    @Override
+    protected boolean processNode(Node node, ReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        boolean deleted = false;
+        if (node instanceof AccessFieldNode) {
+            AccessFieldNode access = (AccessFieldNode) node;
+            if (access.isVolatile()) {
+                processIdentity(state, any());
+            } else {
+                ValueNode object = GraphUtil.unproxify(access.object());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, new FieldLocationIdentity(access.field()));
+                ValueNode cachedValue = state.getCacheEntry(identifier);
+                if (node instanceof LoadFieldNode) {
+                    if (cachedValue != null && access.stamp().isCompatible(cachedValue.stamp())) {
+                        effects.replaceAtUsages(access, cachedValue);
+                        addScalarAlias(access, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, access);
+                    }
+                } else {
+                    assert node instanceof StoreFieldNode;
+                    StoreFieldNode store = (StoreFieldNode) node;
+                    ValueNode value = getScalarAlias(store.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteNode(store);
+                        deleted = true;
+                    }
+                    state.killReadCache(identifier.identity);
+                    state.addCacheEntry(identifier, value);
+                }
+            }
+        } else if (node instanceof ReadNode) {
+            ReadNode read = (ReadNode) node;
+            if (read.getLocationIdentity().isSingle()) {
+                ValueNode object = GraphUtil.unproxify(read.getAddress());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, read.getLocationIdentity());
+                ValueNode cachedValue = state.getCacheEntry(identifier);
+                if (cachedValue != null && read.stamp().isCompatible(cachedValue.stamp())) {
+                    // Anchor guard if it is not fixed and different from cachedValue's guard such
+                    // that it gets preserved.
+                    if (read.getGuard() != null && !(read.getGuard() instanceof FixedNode)) {
+                        if (!(cachedValue instanceof GuardedNode) || ((GuardedNode) cachedValue).getGuard() != read.getGuard()) {
+                            effects.addFixedNodeBefore(new ValueAnchorNode((ValueNode) read.getGuard()), read);
+                        }
+                    }
+                    effects.replaceAtUsages(read, cachedValue);
+                    addScalarAlias(read, cachedValue);
+                    deleted = true;
+                } else {
+                    state.addCacheEntry(identifier, read);
+                }
+            }
+        } else if (node instanceof WriteNode) {
+            WriteNode write = (WriteNode) node;
+            if (write.getLocationIdentity().isSingle()) {
+                ValueNode object = GraphUtil.unproxify(write.getAddress());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
+                ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                ValueNode value = getScalarAlias(write.value());
+                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                    effects.deleteNode(write);
+                    deleted = true;
+                }
+                processIdentity(state, write.getLocationIdentity());
+                state.addCacheEntry(identifier, value);
+            } else {
+                processIdentity(state, write.getLocationIdentity());
+            }
+        } else if (node instanceof UnsafeAccessNode) {
+            if (node instanceof UnsafeLoadNode) {
+                UnsafeLoadNode load = (UnsafeLoadNode) node;
+                if (load.getLocationIdentity().isSingle()) {
+                    ValueNode object = GraphUtil.unproxify(load.object());
+                    UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+                    if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
+                        effects.replaceAtUsages(load, cachedValue);
+                        addScalarAlias(load, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, load);
+                    }
+                }
+            } else {
+                assert node instanceof UnsafeStoreNode;
+                UnsafeStoreNode write = (UnsafeStoreNode) node;
+                if (write.getLocationIdentity().isSingle()) {
+                    ValueNode object = GraphUtil.unproxify(write.object());
+                    UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                    ValueNode value = getScalarAlias(write.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteNode(write);
+                        deleted = true;
+                    }
+                    processIdentity(state, write.getLocationIdentity());
+                    state.addCacheEntry(identifier, value);
+                } else {
+                    processIdentity(state, write.getLocationIdentity());
+                }
+            }
+        } else if (node instanceof MemoryCheckpoint.Single) {
+            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+            processIdentity(state, identity);
+        } else if (node instanceof MemoryCheckpoint.Multi) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                processIdentity(state, identity);
+            }
+        }
+        return deleted;
+    }
+
+    private static void processIdentity(ReadEliminationBlockState state, LocationIdentity identity) {
+        if (identity.isAny()) {
+            state.killReadCache();
+            return;
+        }
+        state.killReadCache(identity);
+    }
+
+    @Override
+    protected void processLoopExit(LoopExitNode exitNode, ReadEliminationBlockState initialState, ReadEliminationBlockState exitState, GraphEffectList effects) {
+        if (exitNode.graph().hasValueProxies()) {
+            for (Map.Entry<CacheEntry<?>, ValueNode> entry : exitState.getReadCache().entrySet()) {
+                if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                    ProxyNode proxy = new ValueProxyNode(exitState.getCacheEntry(entry.getKey()), exitNode);
+                    effects.addFloatingNode(proxy, "readCacheProxy");
+                    entry.setValue(proxy);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected ReadEliminationBlockState cloneState(ReadEliminationBlockState other) {
+        return new ReadEliminationBlockState(other);
+    }
+
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new ReadEliminationMergeProcessor(merge);
+    }
+
+    private class ReadEliminationMergeProcessor extends EffectsClosure<ReadEliminationBlockState>.MergeProcessor {
+
+        private final HashMap<Object, ValuePhiNode> materializedPhis = CollectionsFactory.newMap();
+
+        ReadEliminationMergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
+        }
+
+        protected <T> PhiNode getCachedPhi(T virtual, Stamp stamp) {
+            ValuePhiNode result = materializedPhis.get(virtual);
+            if (result == null) {
+                result = createValuePhi(stamp);
+                materializedPhis.put(virtual, result);
+            }
+            return result;
+        }
+
+        @Override
+        protected void merge(List<ReadEliminationBlockState> states) {
+            super.merge(states);
+
+            mergeReadCache(states);
+        }
+
+        private void mergeReadCache(List<ReadEliminationBlockState> states) {
+            for (Map.Entry<CacheEntry<?>, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                CacheEntry<?> key = entry.getKey();
+                ValueNode value = entry.getValue();
+                boolean phi = false;
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode otherValue = states.get(i).readCache.get(key);
+                    // e.g. unsafe loads / stores with different access kinds have different stamps
+                    // although location, object and offset are the same, in this case we cannot
+                    // create a phi nor can we set a common value
+                    if (otherValue == null || !value.stamp().isCompatible(otherValue.stamp())) {
+                        value = null;
+                        phi = false;
+                        break;
+                    }
+                    if (!phi && otherValue != value) {
+                        phi = true;
+                    }
+                }
+                if (phi) {
+                    PhiNode phiNode = getCachedPhi(entry, value.stamp().unrestricted());
+                    mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
+                    for (int i = 0; i < states.size(); i++) {
+                        ValueNode v = states.get(i).getCacheEntry(key);
+                        assert phiNode.stamp().isCompatible(v.stamp()) : "Cannot create read elimination phi for inputs with incompatible stamps.";
+                        setPhiInput(phiNode, i, v);
+                    }
+                    newState.addCacheEntry(key, phiNode);
+                } else if (value != null) {
+                    // case that there is the same value on all branches
+                    newState.addCacheEntry(key, value);
+                }
+            }
+            for (PhiNode phi : getPhis()) {
+                if (phi.getStackKind() == JavaKind.Object) {
+                    for (Map.Entry<CacheEntry<?>, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                        if (entry.getKey().object == getPhiValueAt(phi, 0)) {
+                            mergeReadCachePhi(phi, entry.getKey(), states);
+                        }
+                    }
+
+                }
+            }
+        }
+
+        private void mergeReadCachePhi(PhiNode phi, CacheEntry<?> identifier, List<ReadEliminationBlockState> states) {
+            ValueNode[] values = new ValueNode[states.size()];
+            values[0] = states.get(0).getCacheEntry(identifier.duplicateWithObject(getPhiValueAt(phi, 0)));
+            if (values[0] != null) {
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode value = states.get(i).getCacheEntry(identifier.duplicateWithObject(getPhiValueAt(phi, i)));
+                    // e.g. unsafe loads / stores with same identity and different access kinds see
+                    // mergeReadCache(states)
+                    if (value == null || !values[i - 1].stamp().isCompatible(value.stamp())) {
+                        return;
+                    }
+                    values[i] = value;
+                }
+
+                CacheEntry<?> newIdentifier = identifier.duplicateWithObject(phi);
+                PhiNode phiNode = getCachedPhi(newIdentifier, values[0].stamp().unrestricted());
+                mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
+                for (int i = 0; i < values.length; i++) {
+                    setPhiInput(phiNode, i, values[i]);
+                }
+                newState.addCacheEntry(newIdentifier, phiNode);
+            }
+        }
+    }
+
+    @Override
+    protected void processKilledLoopLocations(Loop<Block> loop, ReadEliminationBlockState initialState, ReadEliminationBlockState mergedStates) {
+        assert initialState != null;
+        assert mergedStates != null;
+        if (initialState.readCache.size() > 0) {
+            LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
+            // we have fully processed this loop the first time, remember to cache it the next time
+            // it is visited
+            if (loopKilledLocations == null) {
+                loopKilledLocations = new LoopKillCache(1/* 1.visit */);
+                loopLocationKillCache.put(loop, loopKilledLocations);
+            } else {
+                if (loopKilledLocations.visits() > ReadEliminationMaxLoopVisits.getValue()) {
+                    // we have processed the loop too many times, kill all locations so the inner
+                    // loop will never be processed more than once again on visit
+                    loopKilledLocations.setKillsAll();
+                } else {
+                    // we have fully processed this loop >1 times, update the killed locations
+                    Set<LocationIdentity> forwardEndLiveLocations = new HashSet<>();
+                    for (CacheEntry<?> entry : initialState.readCache.keySet()) {
+                        forwardEndLiveLocations.add(entry.getIdentity());
+                    }
+                    for (CacheEntry<?> entry : mergedStates.readCache.keySet()) {
+                        forwardEndLiveLocations.remove(entry.getIdentity());
+                    }
+                    // every location that is alive before the loop but not after is killed by the
+                    // loop
+                    for (LocationIdentity location : forwardEndLiveLocations) {
+                        loopKilledLocations.rememberLoopKilledLocation(location);
+                    }
+                    if (Debug.isLogEnabled() && loopKilledLocations != null) {
+                        Debug.log("[Early Read Elimination] Setting loop killed locations of loop at node %s with %s",
+                                        loop.getHeader().getBeginNode(), forwardEndLiveLocations);
+                    }
+                }
+                // remember the loop visit
+                loopKilledLocations.visited();
+            }
+        }
+    }
+
+    @Override
+    protected ReadEliminationBlockState stripKilledLoopLocations(Loop<Block> loop, ReadEliminationBlockState originalInitialState) {
+        ReadEliminationBlockState initialState = super.stripKilledLoopLocations(loop, originalInitialState);
+        LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
+        if (loopKilledLocations != null && loopKilledLocations.loopKillsLocations()) {
+            Set<CacheEntry<?>> forwardEndLiveLocations = initialState.readCache.keySet();
+            Iterator<CacheEntry<?>> it = forwardEndLiveLocations.iterator();
+            while (it.hasNext()) {
+                CacheEntry<?> entry = it.next();
+                if (loopKilledLocations.containsLocation(entry.getIdentity())) {
+                    it.remove();
+                }
+            }
+        }
+        return initialState;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java
new file mode 100644
index 0000000..fdee390
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.TraceEscapeAnalysis;
+
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeFlood;
+import org.graalvm.compiler.nodes.AbstractEndNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public final class VirtualUtil {
+
+    private VirtualUtil() {
+        GraalError.shouldNotReachHere();
+    }
+
+    public static boolean assertNonReachable(StructuredGraph graph, List<Node> obsoleteNodes) {
+        // helper code that determines the paths that keep obsolete nodes alive:
+
+        NodeFlood flood = graph.createNodeFlood();
+        Map<Node, Node> path = Node.newIdentityMap();
+        flood.add(graph.start());
+        for (Node current : flood) {
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
+                flood.add(end.merge());
+                if (!path.containsKey(end.merge())) {
+                    path.put(end.merge(), end);
+                }
+            } else {
+                for (Node successor : current.successors()) {
+                    flood.add(successor);
+                    if (!path.containsKey(successor)) {
+                        path.put(successor, current);
+                    }
+                }
+            }
+        }
+
+        for (Node node : obsoleteNodes) {
+            if (node instanceof FixedNode && !node.isDeleted()) {
+                assert !flood.isMarked(node) : node;
+            }
+        }
+
+        for (Node node : graph.getNodes()) {
+            if (flood.isMarked(node)) {
+                for (Node input : node.inputs()) {
+                    flood.add(input);
+                    if (!path.containsKey(input)) {
+                        path.put(input, node);
+                    }
+                }
+            }
+        }
+        for (Node current : flood) {
+            for (Node input : current.inputs()) {
+                flood.add(input);
+                if (!path.containsKey(input)) {
+                    path.put(input, current);
+                }
+            }
+        }
+        boolean success = true;
+        for (Node node : obsoleteNodes) {
+            if (!node.isDeleted() && flood.isMarked(node)) {
+                TTY.println("offending node path:");
+                Node current = node;
+                TTY.print(current.toString());
+                while (true) {
+                    current = path.get(current);
+                    if (current != null) {
+                        TTY.print(" -> " + current.toString());
+                        if (current instanceof FixedNode && !obsoleteNodes.contains(current)) {
+                            break;
+                        }
+                    }
+                }
+                success = false;
+            }
+        }
+        if (!success) {
+            TTY.println();
+            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "assertNonReachable");
+        }
+        return success;
+    }
+
+    public static void trace(String format) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format);
+        }
+    }
+
+    public static void trace(String format, Object obj) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj);
+        }
+    }
+
+    public static void trace(String format, Object obj, Object obj2) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2);
+        }
+    }
+
+    public static void trace(String format, Object obj, Object obj2, Object obj3) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2, obj3);
+        }
+    }
+
+    public static void trace(String format, Object obj, Object obj2, Object obj3, Object obj4) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2, obj3, obj4);
+        }
+    }
+
+    public static boolean matches(StructuredGraph graph, String filter) {
+        if (filter != null) {
+            return matchesHelper(graph, filter);
+        }
+        return true;
+    }
+
+    private static boolean matchesHelper(StructuredGraph graph, String filter) {
+        if (filter.startsWith("~")) {
+            ResolvedJavaMethod method = graph.method();
+            return method == null || !method.format("%H.%n").contains(filter.substring(1));
+        } else {
+            ResolvedJavaMethod method = graph.method();
+            return method != null && method.format("%H.%n").contains(filter);
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java
new file mode 100644
index 0000000..f5b1e44
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.virtual.phases.ea;
+
+import static org.graalvm.compiler.core.common.GraalOptions.MaximumEscapeAnalysisArrayLength;
+
+import java.util.List;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+class VirtualizerToolImpl implements VirtualizerTool, CanonicalizerTool {
+
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+    private final ConstantFieldProvider constantFieldProvider;
+    private final PartialEscapeClosure<?> closure;
+    private final Assumptions assumptions;
+    private final LoweringProvider loweringProvider;
+
+    VirtualizerToolImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, PartialEscapeClosure<?> closure,
+                    Assumptions assumptions, LoweringProvider loweringProvider) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.closure = closure;
+        this.assumptions = assumptions;
+        this.loweringProvider = loweringProvider;
+    }
+
+    private boolean deleted;
+    private PartialEscapeBlockState<?> state;
+    private ValueNode current;
+    private FixedNode position;
+    private GraphEffectList effects;
+
+    @Override
+    public MetaAccessProvider getMetaAccessProvider() {
+        return metaAccess;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflectionProvider() {
+        return constantReflection;
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    public void reset(PartialEscapeBlockState<?> newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) {
+        deleted = false;
+        state = newState;
+        current = newCurrent;
+        position = newPosition;
+        effects = newEffects;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
+
+    @Override
+    public ValueNode getAlias(ValueNode value) {
+        return closure.getAliasAndResolve(state, value);
+    }
+
+    @Override
+    public ValueNode getEntry(VirtualObjectNode virtualObject, int index) {
+        return state.getObjectState(virtualObject).getEntry(index);
+    }
+
+    @Override
+    public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) {
+        ObjectState obj = state.getObjectState(virtual);
+        assert obj.isVirtual() : "not virtual: " + obj;
+        ValueNode newValue;
+        if (value == null) {
+            newValue = null;
+        } else {
+            newValue = closure.getAliasAndResolve(state, value);
+            assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getStackKind() == newValue.getStackKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
+        }
+        state.setEntry(virtual.getObjectId(), index, newValue);
+    }
+
+    @Override
+    public void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized) {
+        int id = virtualObject.getObjectId();
+        state.setEnsureVirtualized(id, ensureVirtualized);
+    }
+
+    @Override
+    public boolean getEnsureVirtualized(VirtualObjectNode virtualObject) {
+        return state.getObjectState(virtualObject).getEnsureVirtualized();
+    }
+
+    private static boolean isObjectEntry(ValueNode value) {
+        return value.getStackKind() == JavaKind.Object || value instanceof VirtualObjectNode;
+    }
+
+    @Override
+    public void replaceWithVirtual(VirtualObjectNode virtual) {
+        closure.addAndMarkAlias(virtual, current);
+        effects.deleteNode(current);
+        deleted = true;
+    }
+
+    @Override
+    public void replaceWithValue(ValueNode replacement) {
+        effects.replaceAtUsages(current, closure.getScalarAlias(replacement));
+        closure.addScalarAlias(current, replacement);
+        deleted = true;
+    }
+
+    @Override
+    public void delete() {
+        effects.deleteNode(current);
+        deleted = true;
+    }
+
+    @Override
+    public void replaceFirstInput(Node oldInput, Node replacement) {
+        effects.replaceFirstInput(current, oldInput, replacement);
+    }
+
+    @Override
+    public void addNode(ValueNode node) {
+        if (node instanceof FloatingNode) {
+            effects.addFloatingNode(node, "VirtualizerTool");
+        } else {
+            effects.addFixedNodeBefore((FixedWithNextNode) node, position);
+        }
+    }
+
+    @Override
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized) {
+        VirtualUtil.trace("{{%s}} ", current);
+        if (!virtualObject.isAlive()) {
+            effects.addFloatingNode(virtualObject, "newVirtualObject");
+        }
+        for (int i = 0; i < entryState.length; i++) {
+            ValueNode entry = entryState[i];
+            entryState[i] = entry instanceof VirtualObjectNode ? entry : closure.getAliasAndResolve(state, entry);
+        }
+        int id = virtualObject.getObjectId();
+        if (id == -1) {
+            id = closure.virtualObjects.size();
+            closure.virtualObjects.add(virtualObject);
+            virtualObject.setObjectId(id);
+        }
+        state.addObject(id, new ObjectState(entryState, locks, ensureVirtualized));
+        closure.addAndMarkAlias(virtualObject, virtualObject);
+        PartialEscapeClosure.COUNTER_ALLOCATION_REMOVED.increment();
+    }
+
+    @Override
+    public int getMaximumEntryCount() {
+        return MaximumEscapeAnalysisArrayLength.getValue();
+    }
+
+    @Override
+    public void replaceWith(ValueNode node) {
+        if (node instanceof VirtualObjectNode) {
+            replaceWithVirtual((VirtualObjectNode) node);
+        } else {
+            replaceWithValue(node);
+        }
+    }
+
+    @Override
+    public boolean ensureMaterialized(VirtualObjectNode virtualObject) {
+        return closure.ensureMaterialized(state, virtualObject.getObjectId(), position, effects, PartialEscapeClosure.COUNTER_MATERIALIZATIONS_UNHANDLED);
+    }
+
+    @Override
+    public void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId) {
+        int id = virtualObject.getObjectId();
+        state.addLock(id, monitorId);
+    }
+
+    @Override
+    public MonitorIdNode removeLock(VirtualObjectNode virtualObject) {
+        int id = virtualObject.getObjectId();
+        return state.removeLock(id);
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    @Override
+    public boolean canonicalizeReads() {
+        return false;
+    }
+
+    @Override
+    public boolean allUsagesAvailable() {
+        return true;
+    }
+
+    @Override
+    public Assumptions getAssumptions() {
+        return assumptions;
+    }
+
+    @Override
+    public boolean supportSubwordCompare(int bits) {
+        if (loweringProvider != null) {
+            return loweringProvider.supportSubwordCompare(bits);
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicUnsigned.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicUnsigned.java
new file mode 100644
index 0000000..d88272d
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicUnsigned.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+/**
+ * A {@link Unsigned} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for description of the properties of
+ * atomic variables.
+ */
+public class AtomicUnsigned extends AtomicWord<Unsigned> {
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final Unsigned getAndAdd(Unsigned delta) {
+        return Word.unsigned(value.getAndAdd(delta.rawValue()));
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final Unsigned addAndGet(Unsigned delta) {
+        return Word.unsigned(value.addAndGet(delta.rawValue()));
+    }
+
+    /**
+     * Atomically subtracts the given value from the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final Unsigned getAndSubtract(Unsigned delta) {
+        return Word.unsigned(value.getAndAdd(-delta.rawValue()));
+    }
+
+    /**
+     * Atomically subtracts the given value from the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final Unsigned subtractAndGet(Unsigned delta) {
+        return Word.unsigned(value.addAndGet(-delta.rawValue()));
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicWord.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicWord.java
new file mode 100644
index 0000000..7e72680
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicWord.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A {@link WordBase word} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for description of the properties of
+ * atomic variables.
+ *
+ * Similar to {@link AtomicReference}, but for {@link WordBase word} types. A dedicated
+ * implementation is necessary because Object and word types cannot be mixed.
+ */
+public class AtomicWord<T extends WordBase> {
+
+    /**
+     * For simplicity, we convert the word value to a long and delegate to existing atomic
+     * operations.
+     */
+    protected final AtomicLong value;
+
+    /**
+     * Creates a new AtomicLong with initial value {@link Word#zero}.
+     */
+    public AtomicWord() {
+        value = new AtomicLong();
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    @SuppressWarnings("unchecked")
+    public final T get() {
+        return (T) Word.unsigned(value.get());
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(T newValue) {
+        value.set(newValue.rawValue());
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final T getAndSet(T newValue) {
+        return (T) Word.unsigned(value.getAndSet(newValue.rawValue()));
+    }
+
+    /**
+     * Atomically sets the value to the given updated value if the current value {@code ==} the
+     * expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual value was not
+     *         equal to the expected value.
+     */
+    public final boolean compareAndSet(T expect, T update) {
+        return value.compareAndSet(expect.rawValue(), update.rawValue());
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java
new file mode 100644
index 0000000..22a4409
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+
+/**
+ * Medium-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
+ * {@link Pointer} and {@link ObjectAccess}, these methods access the memory without any null
+ * checks. However, these methods use read- or write barriers. When the VM uses compressed pointers,
+ * then readObject and writeObject methods access compressed pointers.
+ */
+public final class BarrieredAccess {
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, int offset);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, int offset, Object val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ComparableWord.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ComparableWord.java
new file mode 100644
index 0000000..bc3064e
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ComparableWord.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+public interface ComparableWord extends WordBase {
+
+    /**
+     * Compares this word with the specified value.
+     *
+     * @param val value to which this word is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(ComparableWord val);
+
+    /**
+     * Compares this word with the specified value.
+     *
+     * @param val value to which this word is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(ComparableWord val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java
new file mode 100644
index 0000000..0b331ea
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+
+/**
+ * Low-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
+ * {@link Pointer}, these methods access the raw memory without any null checks, read- or write
+ * barriers. When the VM uses compressed pointers, then readObject and writeObject methods access
+ * compressed pointers.
+ */
+public final class ObjectAccess {
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native byte readByte(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native char readChar(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native short readShort(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native int readInt(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native long readLong(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native float readFloat(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native double readDouble(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Word readWord(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Object readObject(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native byte readByte(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native char readChar(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native short readShort(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native int readInt(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native long readLong(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native float readFloat(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native double readDouble(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Word readWord(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_OBJECT)
+    public static native Object readObject(Object object, int offset);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeByte(Object object, WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeChar(Object object, WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeShort(Object object, WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeInt(Object object, WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeLong(Object object, WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeFloat(Object object, WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeDouble(Object object, WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeWord(Object object, WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeObject(Object object, WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeByte(Object object, int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeChar(Object object, int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeShort(Object object, int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeInt(Object object, int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeLong(Object object, int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeFloat(Object object, int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeDouble(Object object, int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeWord(Object object, int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_OBJECT)
+    public static native void writeObject(Object object, int offset, Object val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Pointer.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Pointer.java
new file mode 100644
index 0000000..7093c2b
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Pointer.java
@@ -0,0 +1,953 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+
+/**
+ * Lowest-level memory access of native C memory. These methods access the raw memory without any
+ * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject
+ * and writeObject methods access uncompressed pointers.
+ * <p>
+ * Do not use these methods to access Java objects, i.e., do not use
+ * {@code Word.fromObject(obj).readXxx()}. Instead, use {@link ObjectAccess} or
+ * {@link BarrieredAccess} to access Java objects.
+ */
+public interface Pointer extends Unsigned, PointerBase {
+
+    /**
+     * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
+     * checks are performed. The caller must ensure that the Pointer contains a valid Java object
+     * that can i.e., processed by the garbage collector.
+     *
+     * @return this Pointer cast to Object.
+     */
+    Object toObject();
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    byte readByte(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    char readChar(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    short readShort(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    int readInt(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    long readLong(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    float readFloat(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    double readDouble(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Word readWord(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    byte readByte(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    char readChar(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    short readShort(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    int readInt(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    long readLong(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    float readFloat(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    double readDouble(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Word readWord(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Object readObject(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeByte(int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeChar(int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeShort(int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeInt(int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeFloat(int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeDouble(int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void initializeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeObject(int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    byte readByte(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    char readChar(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    short readShort(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    int readInt(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    long readLong(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    float readFloat(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    double readDouble(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Word readWord(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
+     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
+     * field).
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param barrierType the type of the read barrier to be added
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset, BarrierType barrierType);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    byte readByte(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    char readChar(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    short readShort(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    int readInt(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    long readLong(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    float readFloat(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    double readDouble(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Word readWord(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Object readObject(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
+     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
+     * field).
+     *
+     * @param offset the signed offset for the memory access
+     * @param barrierType the type of the read barrier to be added
+     * @return the result of the memory access
+     */
+    Object readObject(int offset, BarrierType barrierType);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeByte(WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeChar(WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeShort(WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeInt(WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeLong(WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeFloat(WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeDouble(WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeWord(WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeObject(WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeByte(int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeChar(int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeShort(int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeInt(int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeLong(int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeFloat(int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeDouble(int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeWord(int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeObject(int offset, Object val);
+
+    // Math functions that are defined in Unsigned, but known to preserve the
+    // pointer-characteristics.
+    // It is therefore safe that they return a static type of Pointer instead of Unsigned.
+
+    @Override
+    Pointer add(Unsigned val);
+
+    @Override
+    Pointer add(int val);
+
+    @Override
+    Pointer subtract(Unsigned val);
+
+    @Override
+    Pointer subtract(int val);
+
+    @Override
+    Pointer and(Unsigned val);
+
+    @Override
+    Pointer and(int val);
+
+    @Override
+    Pointer or(Unsigned val);
+
+    @Override
+    Pointer or(int val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerBase.java
new file mode 100644
index 0000000..2aa657f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerBase.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+/**
+ * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
+ * necessarily all the memory access methods defined in {@link Pointer}).
+ */
+public interface PointerBase extends ComparableWord {
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerUtils.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerUtils.java
new file mode 100644
index 0000000..efafbda
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerUtils.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+/**
+ * Utility methods on Pointers.
+ */
+public final class PointerUtils {
+
+    private PointerUtils() {
+        // This is a class of static methods, so no need for any instances.
+    }
+
+    /**
+     * The value of a null Pointer.
+     *
+     * @return A null Pointer value.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends PointerBase> T nullPointer() {
+        return (T) Word.zero();
+    }
+
+    /**
+     * Predicate to check for the null Pointer value.
+     *
+     * @return Whether that Pointer is the null Pointer.
+     */
+    public static boolean isNull(ComparableWord that) {
+        return that.equal(nullPointer());
+    }
+
+    /**
+     * Predicate to check for a non-null Pointer value.
+     *
+     * @return Whether that Pointer is not the null Pointer.
+     */
+    public static boolean isNonNull(ComparableWord that) {
+        return that.notEqual(nullPointer());
+    }
+
+    /**
+     * Round a Pointer down to the nearest smaller multiple.
+     *
+     * @param that The Pointer to be rounded up.
+     * @param multiple The multiple to which that Pointer should be decreased.
+     * @return That Pointer, but rounded down.
+     */
+    public static Pointer roundDown(PointerBase that, Unsigned multiple) {
+        return (Pointer) UnsignedUtils.roundDown((Unsigned) that, multiple);
+    }
+
+    /**
+     * Round a Pointer up to the nearest larger multiple.
+     *
+     * @param that The Pointer to be rounded up.
+     * @param multiple The multiple to which that Pointer should be increased.
+     * @return That Pointer, but rounded up.
+     */
+    public static Pointer roundUp(PointerBase that, Unsigned multiple) {
+        return (Pointer) UnsignedUtils.roundUp((Unsigned) that, multiple);
+    }
+
+    /**
+     * Check that a Pointer is an even multiple.
+     *
+     * @param that The Pointer to be verified as a multiple.
+     * @param multiple The multiple against which the Pointer should be verified.
+     * @return true if that Pointer is a multiple, false otherwise.
+     */
+    public static boolean isAMultiple(PointerBase that, Unsigned multiple) {
+        return that.equal(PointerUtils.roundDown(that, multiple));
+    }
+
+    /**
+     * Return the distance between two Pointers.
+     *
+     * @param pointer1 A first Pointer.
+     * @param pointer2 A second Pointer.
+     * @return The distance in bytes between the two Pointers.
+     */
+    public static Unsigned absoluteDifference(PointerBase pointer1, PointerBase pointer2) {
+        Pointer p1 = (Pointer) pointer1;
+        Pointer p2 = (Pointer) pointer2;
+        final Unsigned result;
+        if (p1.aboveOrEqual(p2)) {
+            result = p1.subtract(p2);
+        } else {
+            result = p2.subtract(p1);
+        }
+        return result;
+    }
+
+    /**
+     * The minimum of two Pointers.
+     *
+     * @param x A Pointer.
+     * @param y Another Pointer.
+     * @return The whichever Pointer is smaller.
+     */
+    public static <T extends PointerBase> T min(T x, T y) {
+        return (((Pointer) x).belowOrEqual((Pointer) y)) ? x : y;
+    }
+
+    /**
+     * The maximum of two Pointers.
+     *
+     * @param x A Pointer.
+     * @param y Another Pointer.
+     * @return The whichever Pointer is larger.
+     */
+    public static <T extends PointerBase> T max(T x, T y) {
+        return (((Pointer) x).aboveOrEqual((Pointer) y)) ? x : y;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Signed.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Signed.java
new file mode 100644
index 0000000..719860f
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Signed.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+public interface Signed extends ComparableWord {
+
+    /**
+     * Returns a Signed whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Signed.
+     * @return {@code this + val}
+     */
+    Signed add(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Signed.
+     * @return {@code this - val}
+     */
+    Signed subtract(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Signed.
+     * @return {@code this * val}
+     */
+    Signed multiply(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Signed is to be divided.
+     * @return {@code this / val}
+     */
+    Signed signedDivide(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Signed is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Signed signedRemainder(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Signed shiftLeft(Unsigned n);
+
+    /**
+     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Signed signedShiftRight(Unsigned n);
+
+    /**
+     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
+     * if and only if this and val are both negative.)
+     *
+     * @param val value to be AND'ed with this Signed.
+     * @return {@code this & val}
+     */
+    Signed and(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
+     * if and only if either this or val is negative.)
+     *
+     * @param val value to be OR'ed with this Signed.
+     * @return {@code this | val}
+     */
+    Signed or(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
+     * if and only if exactly one of this and val are negative.)
+     *
+     * @param val value to be XOR'ed with this Signed.
+     * @return {@code this ^ val}
+     */
+    Signed xor(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (~this)}. (This method returns a negative value if and
+     * only if this Signed is non-negative.)
+     *
+     * @return {@code ~this}
+     */
+    Signed not();
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this < val}
+     */
+    boolean lessThan(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean lessOrEqual(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this > val}
+     */
+    boolean greaterThan(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean greaterOrEqual(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Signed.
+     * @return {@code this + val}
+     */
+    Signed add(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Signed.
+     * @return {@code this - val}
+     */
+    Signed subtract(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Signed.
+     * @return {@code this * val}
+     */
+    Signed multiply(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Signed is to be divided.
+     * @return {@code this / val}
+     */
+    Signed signedDivide(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Signed is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Signed signedRemainder(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Signed shiftLeft(int n);
+
+    /**
+     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Signed signedShiftRight(int n);
+
+    /**
+     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
+     * if and only if this and val are both negative.)
+     *
+     * @param val value to be AND'ed with this Signed.
+     * @return {@code this & val}
+     */
+    Signed and(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
+     * if and only if either this or val is negative.)
+     *
+     * @param val value to be OR'ed with this Signed.
+     * @return {@code this | val}
+     */
+    Signed or(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
+     * if and only if exactly one of this and val are negative.)
+     *
+     * @param val value to be XOR'ed with this Signed.
+     * @return {@code this ^ val}
+     */
+    Signed xor(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this < val}
+     */
+    boolean lessThan(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean lessOrEqual(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this > val}
+     */
+    boolean greaterThan(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean greaterOrEqual(int val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsafeAccess.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsafeAccess.java
new file mode 100644
index 0000000..05021f2
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsafeAccess.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Package private access to the {@link Unsafe} capability.
+ */
+class UnsafeAccess {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Unsigned.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Unsigned.java
new file mode 100644
index 0000000..1da7598
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Unsigned.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+public interface Unsigned extends ComparableWord {
+
+    /**
+     * Returns a Unsigned whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Unsigned.
+     * @return {@code this + val}
+     */
+    Unsigned add(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Unsigned.
+     * @return {@code this - val}
+     */
+    Unsigned subtract(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Unsigned.
+     * @return {@code this * val}
+     */
+    Unsigned multiply(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Unsigned is to be divided.
+     * @return {@code this / val}
+     */
+    Unsigned unsignedDivide(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Unsigned is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Unsigned unsignedRemainder(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Unsigned shiftLeft(Unsigned n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Unsigned unsignedShiftRight(Unsigned n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this & val)}.
+     *
+     * @param val value to be AND'ed with this Unsigned.
+     * @return {@code this & val}
+     */
+    Unsigned and(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this | val)}.
+     *
+     * @param val value to be OR'ed with this Unsigned.
+     * @return {@code this | val}
+     */
+    Unsigned or(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this ^ val)}.
+     *
+     * @param val value to be XOR'ed with this Unsigned.
+     * @return {@code this ^ val}
+     */
+    Unsigned xor(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (~this)}.
+     *
+     * @return {@code ~this}
+     */
+    Unsigned not();
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this < val}
+     */
+    boolean belowThan(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean belowOrEqual(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this > val}
+     */
+    boolean aboveThan(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean aboveOrEqual(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this + val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be added to this Unsigned.
+     * @return {@code this + val}
+     */
+    Unsigned add(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this - val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be subtracted from this Unsigned.
+     * @return {@code this - val}
+     */
+    Unsigned subtract(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this * val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be multiplied by this Unsigned.
+     * @return {@code this * val}
+     */
+    Unsigned multiply(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this / val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value by which this Unsigned is to be divided.
+     * @return {@code this / val}
+     */
+    Unsigned unsignedDivide(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this % val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value by which this Unsigned is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Unsigned unsignedRemainder(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this << n)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Unsigned shiftLeft(int n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Unsigned unsignedShiftRight(int n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this & val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be AND'ed with this Unsigned.
+     * @return {@code this & val}
+     */
+    Unsigned and(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this | val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be OR'ed with this Unsigned.
+     * @return {@code this | val}
+     */
+    Unsigned or(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this ^ val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be XOR'ed with this Unsigned.
+     * @return {@code this ^ val}
+     */
+    Unsigned xor(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this < val}
+     */
+    boolean belowThan(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean belowOrEqual(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this > val}
+     */
+    boolean aboveThan(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean aboveOrEqual(int val);
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsignedUtils.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsignedUtils.java
new file mode 100644
index 0000000..5f6a404
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsignedUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+/**
+ * Utility methods on Unsigned values.
+ */
+public final class UnsignedUtils {
+
+    private UnsignedUtils() {
+        // This is a class of static methods, so no need for any instances.
+    }
+
+    /**
+     * Round an Unsigned down to the nearest smaller multiple.
+     *
+     * @param that The Unsigned to be rounded down.
+     * @param multiple The multiple to which that Unsigned should be decreased.
+     * @return That Unsigned, but rounded down.
+     */
+    public static Unsigned roundDown(Unsigned that, Unsigned multiple) {
+        return that.unsignedDivide(multiple).multiply(multiple);
+    }
+
+    /**
+     * Round an Unsigned up to the nearest larger multiple.
+     *
+     * @param that The Unsigned to be rounded up.
+     * @param multiple The multiple to which that Unsigned should be increased.
+     * @return That Unsigned, but rounded up.
+     */
+    public static Unsigned roundUp(Unsigned that, Unsigned multiple) {
+        return UnsignedUtils.roundDown(that.add(multiple.subtract(1)), multiple);
+    }
+
+    /**
+     * Check that an Unsigned is an even multiple.
+     *
+     * @param that The Unsigned to be verified as a multiple.
+     * @param multiple The multiple against which the Unsigned should be verified.
+     * @return true if that Unsigned is a multiple, false otherwise.
+     */
+    public static boolean isAMultiple(Unsigned that, Unsigned multiple) {
+        return that.equal(UnsignedUtils.roundDown(that, multiple));
+    }
+
+    /**
+     * The minimum of two Unsigneds.
+     *
+     * @param x An Unsigned.
+     * @param y Another Unsigned.
+     * @return The whichever Unsigned is smaller.
+     */
+    public static Unsigned min(Unsigned x, Unsigned y) {
+        return (x.belowOrEqual(y)) ? x : y;
+    }
+
+    /**
+     * The maximum of two Unsigneds.
+     *
+     * @param x An Unsigned.
+     * @param y Another Unsigned.
+     * @return The whichever Unsigned is larger.
+     */
+    public static Unsigned max(Unsigned x, Unsigned y) {
+        return (x.aboveOrEqual(y)) ? x : y;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java
new file mode 100644
index 0000000..9f3e538
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import static org.graalvm.compiler.word.UnsafeAccess.UNSAFE;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.UnsignedMath;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
+import org.graalvm.compiler.nodes.calc.OrNode;
+import org.graalvm.compiler.nodes.calc.RightShiftNode;
+import org.graalvm.compiler.nodes.calc.SignedDivNode;
+import org.graalvm.compiler.nodes.calc.SignedRemNode;
+import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
+import org.graalvm.compiler.nodes.calc.XorNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+
+public abstract class Word implements Signed, Unsigned, Pointer {
+
+    /**
+     * Links a method to a canonical operation represented by an {@link Opcode} val.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface Operation {
+
+        Class<? extends ValueNode> node() default ValueNode.class;
+
+        boolean rightOperandIsInt() default false;
+
+        Opcode opcode() default Opcode.NODE_CLASS;
+
+        Condition condition() default Condition.EQ;
+    }
+
+    /**
+     * The canonical {@link Operation} represented by a method in the {@link Word} class.
+     */
+    // @formatter:off
+     public enum Opcode {
+         NODE_CLASS,
+         COMPARISON,
+         NOT,
+         READ_POINTER,
+         READ_OBJECT,
+         READ_BARRIERED,
+         READ_HEAP,
+         WRITE_POINTER,
+         WRITE_OBJECT,
+         WRITE_BARRIERED,
+         INITIALIZE,
+         ZERO,
+         FROM_UNSIGNED,
+         FROM_SIGNED,
+         FROM_ADDRESS,
+         OBJECT_TO_TRACKED,
+         OBJECT_TO_UNTRACKED,
+         TO_OBJECT,
+         TO_RAW_VALUE,
+    }
+     // @formatter:on
+
+    /*
+     * Outside users should use the different signed() and unsigned() methods to ensure proper
+     * expansion of 32-bit values on 64-bit systems.
+     */
+    private static Word box(long val) {
+        return HostedWord.boxLong(val);
+    }
+
+    protected abstract long unbox();
+
+    private static Word intParam(int val) {
+        return box(val);
+    }
+
+    /**
+     * The constant 0, i.e., the word with no bits set. There is no difference between a signed and
+     * unsigned zero.
+     *
+     * @return the constant 0.
+     */
+    @Operation(opcode = Opcode.ZERO)
+    public static Word zero() {
+        return box(0L);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a Word. The parameter is treated as an unsigned
+     * 64-bit value (in contrast to the semantics of a Java long).
+     *
+     * @param val a 64 bit unsigned value
+     * @return the value cast to Word
+     */
+    @Operation(opcode = Opcode.FROM_UNSIGNED)
+    public static Word unsigned(long val) {
+        return box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a {@link PointerBase pointer}. The parameter is
+     * treated as an unsigned 64-bit value (in contrast to the semantics of a Java long).
+     *
+     * @param val a 64 bit unsigned value
+     * @return the value cast to PointerBase
+     */
+    @Operation(opcode = Opcode.FROM_UNSIGNED)
+    @SuppressWarnings("unchecked")
+    public static <T extends PointerBase> T pointer(long val) {
+        return (T) box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java int value to a Word. The parameter is treated as an unsigned
+     * 32-bit value (in contrast to the semantics of a Java int).
+     *
+     * @param val a 32 bit unsigned value
+     * @return the value cast to Word
+     */
+    @Operation(opcode = Opcode.FROM_UNSIGNED)
+    public static Word unsigned(int val) {
+        return box(val & 0xffffffffL);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a Word. The parameter is treated as a signed
+     * 64-bit value (unchanged semantics of a Java long).
+     *
+     * @param val a 64 bit signed value
+     * @return the value cast to Word
+     */
+    @Operation(opcode = Opcode.FROM_SIGNED)
+    public static Word signed(long val) {
+        return box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java int value to a Word. The parameter is treated as a signed
+     * 32-bit value (unchanged semantics of a Java int).
+     *
+     * @param val a 32 bit signed value
+     * @return the value cast to Word
+     */
+    @Operation(opcode = Opcode.FROM_SIGNED)
+    public static Word signed(int val) {
+        return box(val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.TO_RAW_VALUE)
+    public long rawValue() {
+        return unbox();
+    }
+
+    /**
+     * Convert an {@link Object} to a {@link Pointer}, keeping the reference information. If the
+     * returned pointer or any value derived from it is alive across a safepoint, it will be
+     * tracked. Depending on the arithmetic on the pointer and the capabilities of the backend to
+     * deal with derived references, this may work correctly, or result in a compiler error.
+     */
+    @Operation(opcode = Opcode.OBJECT_TO_TRACKED)
+    public static native Pointer objectToTrackedPointer(Object val);
+
+    /**
+     * Convert an {@link Object} to a {@link Pointer}, dropping the reference information. If the
+     * returned pointer or any value derived from it is alive across a safepoint, it will be treated
+     * as a simple integer and not tracked by the garbage collector.
+     * <p>
+     * This is a dangerous operation, the GC could move the object without updating the pointer! Use
+     * only in combination with some mechanism to prevent the GC from moving or freeing the object
+     * as long as the pointer is in use.
+     * <p>
+     * If the result value should not be alive across a safepoint, it's better to use
+     * {@link #objectToTrackedPointer(Object)} instead.
+     */
+    @Operation(opcode = Opcode.OBJECT_TO_UNTRACKED)
+    public static native Pointer objectToUntrackedPointer(Object val);
+
+    @Operation(opcode = Opcode.FROM_ADDRESS)
+    public static native Pointer fromAddress(Address address);
+
+    @Override
+    @Operation(opcode = Opcode.TO_OBJECT)
+    public native Object toObject();
+
+    @Override
+    @Operation(node = AddNode.class)
+    public Word add(Signed val) {
+        return add((Word) val);
+    }
+
+    @Override
+    @Operation(node = AddNode.class)
+    public Word add(Unsigned val) {
+        return add((Word) val);
+    }
+
+    @Override
+    @Operation(node = AddNode.class)
+    public Word add(int val) {
+        return add(intParam(val));
+    }
+
+    @Operation(node = AddNode.class)
+    public Word add(Word val) {
+        return box(unbox() + val.unbox());
+    }
+
+    @Override
+    @Operation(node = SubNode.class)
+    public Word subtract(Signed val) {
+        return subtract((Word) val);
+    }
+
+    @Override
+    @Operation(node = SubNode.class)
+    public Word subtract(Unsigned val) {
+        return subtract((Word) val);
+    }
+
+    @Override
+    @Operation(node = SubNode.class)
+    public Word subtract(int val) {
+        return subtract(intParam(val));
+    }
+
+    @Operation(node = SubNode.class)
+    public Word subtract(Word val) {
+        return box(unbox() - val.unbox());
+    }
+
+    @Override
+    @Operation(node = MulNode.class)
+    public Word multiply(Signed val) {
+        return multiply((Word) val);
+    }
+
+    @Override
+    @Operation(node = MulNode.class)
+    public Word multiply(Unsigned val) {
+        return multiply((Word) val);
+    }
+
+    @Override
+    @Operation(node = MulNode.class)
+    public Word multiply(int val) {
+        return multiply(intParam(val));
+    }
+
+    @Operation(node = MulNode.class)
+    public Word multiply(Word val) {
+        return box(unbox() * val.unbox());
+    }
+
+    @Override
+    @Operation(node = SignedDivNode.class)
+    public Word signedDivide(Signed val) {
+        return signedDivide((Word) val);
+    }
+
+    @Override
+    @Operation(node = SignedDivNode.class)
+    public Word signedDivide(int val) {
+        return signedDivide(intParam(val));
+    }
+
+    @Operation(node = SignedDivNode.class)
+    public Word signedDivide(Word val) {
+        return box(unbox() / val.unbox());
+    }
+
+    @Override
+    @Operation(node = UnsignedDivNode.class)
+    public Word unsignedDivide(Unsigned val) {
+        return unsignedDivide((Word) val);
+    }
+
+    @Override
+    @Operation(node = UnsignedDivNode.class)
+    public Word unsignedDivide(int val) {
+        return signedDivide(intParam(val));
+    }
+
+    @Operation(node = UnsignedDivNode.class)
+    public Word unsignedDivide(Word val) {
+        return box(Long.divideUnsigned(unbox(), val.unbox()));
+    }
+
+    @Override
+    @Operation(node = SignedRemNode.class)
+    public Word signedRemainder(Signed val) {
+        return signedRemainder((Word) val);
+    }
+
+    @Override
+    @Operation(node = SignedRemNode.class)
+    public Word signedRemainder(int val) {
+        return signedRemainder(intParam(val));
+    }
+
+    @Operation(node = SignedRemNode.class)
+    public Word signedRemainder(Word val) {
+        return box(unbox() % val.unbox());
+    }
+
+    @Override
+    @Operation(node = UnsignedRemNode.class)
+    public Word unsignedRemainder(Unsigned val) {
+        return unsignedRemainder((Word) val);
+    }
+
+    @Override
+    @Operation(node = UnsignedRemNode.class)
+    public Word unsignedRemainder(int val) {
+        return signedRemainder(intParam(val));
+    }
+
+    @Operation(node = UnsignedRemNode.class)
+    public Word unsignedRemainder(Word val) {
+        return box(Long.remainderUnsigned(unbox(), val.unbox()));
+    }
+
+    @Override
+    @Operation(node = LeftShiftNode.class, rightOperandIsInt = true)
+    public Word shiftLeft(Unsigned val) {
+        return shiftLeft((Word) val);
+    }
+
+    @Override
+    @Operation(node = LeftShiftNode.class, rightOperandIsInt = true)
+    public Word shiftLeft(int val) {
+        return shiftLeft(intParam(val));
+    }
+
+    @Operation(node = LeftShiftNode.class, rightOperandIsInt = true)
+    public Word shiftLeft(Word val) {
+        return box(unbox() << val.unbox());
+    }
+
+    @Override
+    @Operation(node = RightShiftNode.class, rightOperandIsInt = true)
+    public Word signedShiftRight(Unsigned val) {
+        return signedShiftRight((Word) val);
+    }
+
+    @Override
+    @Operation(node = RightShiftNode.class, rightOperandIsInt = true)
+    public Word signedShiftRight(int val) {
+        return signedShiftRight(intParam(val));
+    }
+
+    @Operation(node = RightShiftNode.class, rightOperandIsInt = true)
+    public Word signedShiftRight(Word val) {
+        return box(unbox() >> val.unbox());
+    }
+
+    @Override
+    @Operation(node = UnsignedRightShiftNode.class, rightOperandIsInt = true)
+    public Word unsignedShiftRight(Unsigned val) {
+        return unsignedShiftRight((Word) val);
+    }
+
+    @Override
+    @Operation(node = UnsignedRightShiftNode.class, rightOperandIsInt = true)
+    public Word unsignedShiftRight(int val) {
+        return unsignedShiftRight(intParam(val));
+    }
+
+    @Operation(node = UnsignedRightShiftNode.class, rightOperandIsInt = true)
+    public Word unsignedShiftRight(Word val) {
+        return box(unbox() >>> val.unbox());
+    }
+
+    @Override
+    @Operation(node = AndNode.class)
+    public Word and(Signed val) {
+        return and((Word) val);
+    }
+
+    @Override
+    @Operation(node = AndNode.class)
+    public Word and(Unsigned val) {
+        return and((Word) val);
+    }
+
+    @Override
+    @Operation(node = AndNode.class)
+    public Word and(int val) {
+        return and(intParam(val));
+    }
+
+    @Operation(node = AndNode.class)
+    public Word and(Word val) {
+        return box(unbox() & val.unbox());
+    }
+
+    @Override
+    @Operation(node = OrNode.class)
+    public Word or(Signed val) {
+        return or((Word) val);
+    }
+
+    @Override
+    @Operation(node = OrNode.class)
+    public Word or(Unsigned val) {
+        return or((Word) val);
+    }
+
+    @Override
+    @Operation(node = OrNode.class)
+    public Word or(int val) {
+        return or(intParam(val));
+    }
+
+    @Operation(node = OrNode.class)
+    public Word or(Word val) {
+        return box(unbox() | val.unbox());
+    }
+
+    @Override
+    @Operation(node = XorNode.class)
+    public Word xor(Signed val) {
+        return xor((Word) val);
+    }
+
+    @Override
+    @Operation(node = XorNode.class)
+    public Word xor(Unsigned val) {
+        return xor((Word) val);
+    }
+
+    @Override
+    @Operation(node = XorNode.class)
+    public Word xor(int val) {
+        return xor(intParam(val));
+    }
+
+    @Operation(node = XorNode.class)
+    public Word xor(Word val) {
+        return box(unbox() ^ val.unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.NOT)
+    public Word not() {
+        return box(~unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(ComparableWord val) {
+        return equal((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(Signed val) {
+        return equal((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(Unsigned val) {
+        return equal((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(int val) {
+        return equal(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(Word val) {
+        return unbox() == val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(ComparableWord val) {
+        return notEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(Signed val) {
+        return notEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(Unsigned val) {
+        return notEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(int val) {
+        return notEqual(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(Word val) {
+        return unbox() != val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LT)
+    public boolean lessThan(Signed val) {
+        return lessThan((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LT)
+    public boolean lessThan(int val) {
+        return lessThan(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LT)
+    public boolean lessThan(Word val) {
+        return unbox() < val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LE)
+    public boolean lessOrEqual(Signed val) {
+        return lessOrEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LE)
+    public boolean lessOrEqual(int val) {
+        return lessOrEqual(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.LE)
+    public boolean lessOrEqual(Word val) {
+        return unbox() <= val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GT)
+    public boolean greaterThan(Signed val) {
+        return greaterThan((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GT)
+    public boolean greaterThan(int val) {
+        return greaterThan(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GT)
+    public boolean greaterThan(Word val) {
+        return unbox() > val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GE)
+    public boolean greaterOrEqual(Signed val) {
+        return greaterOrEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GE)
+    public boolean greaterOrEqual(int val) {
+        return greaterOrEqual(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.GE)
+    public boolean greaterOrEqual(Word val) {
+        return unbox() >= val.unbox();
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BT)
+    public boolean belowThan(Unsigned val) {
+        return belowThan((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BT)
+    public boolean belowThan(int val) {
+        return belowThan(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BT)
+    public boolean belowThan(Word val) {
+        return UnsignedMath.belowThan(unbox(), val.unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BE)
+    public boolean belowOrEqual(Unsigned val) {
+        return belowOrEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BE)
+    public boolean belowOrEqual(int val) {
+        return belowOrEqual(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.BE)
+    public boolean belowOrEqual(Word val) {
+        return UnsignedMath.belowOrEqual(unbox(), val.unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AT)
+    public boolean aboveThan(Unsigned val) {
+        return aboveThan((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AT)
+    public boolean aboveThan(int val) {
+        return aboveThan(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AT)
+    public boolean aboveThan(Word val) {
+        return UnsignedMath.aboveThan(unbox(), val.unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AE)
+    public boolean aboveOrEqual(Unsigned val) {
+        return aboveOrEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AE)
+    public boolean aboveOrEqual(int val) {
+        return aboveOrEqual(intParam(val));
+    }
+
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.AE)
+    public boolean aboveOrEqual(Word val) {
+        return UnsignedMath.aboveOrEqual(unbox(), val.unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public byte readByte(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getByte(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public char readChar(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getChar(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public short readShort(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getShort(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public int readInt(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getInt(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public long readLong(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getLong(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public float readFloat(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getFloat(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public double readDouble(WordBase offset, LocationIdentity locationIdentity) {
+        return UNSAFE.getDouble(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Word readWord(WordBase offset, LocationIdentity locationIdentity) {
+        return box(UNSAFE.getAddress(add((Word) offset).unbox()));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public native Object readObject(WordBase offset, LocationIdentity locationIdentity);
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public byte readByte(int offset, LocationIdentity locationIdentity) {
+        return readByte(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public char readChar(int offset, LocationIdentity locationIdentity) {
+        return readChar(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public short readShort(int offset, LocationIdentity locationIdentity) {
+        return readShort(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public int readInt(int offset, LocationIdentity locationIdentity) {
+        return readInt(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public long readLong(int offset, LocationIdentity locationIdentity) {
+        return readLong(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public float readFloat(int offset, LocationIdentity locationIdentity) {
+        return readFloat(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public double readDouble(int offset, LocationIdentity locationIdentity) {
+        return readDouble(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Word readWord(int offset, LocationIdentity locationIdentity) {
+        return readWord(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Object readObject(int offset, LocationIdentity locationIdentity) {
+        return readObject(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity) {
+        UNSAFE.putByte(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeChar(WordBase offset, char val, LocationIdentity locationIdentity) {
+        UNSAFE.putChar(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeShort(WordBase offset, short val, LocationIdentity locationIdentity) {
+        UNSAFE.putShort(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeInt(WordBase offset, int val, LocationIdentity locationIdentity) {
+        UNSAFE.putInt(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeLong(WordBase offset, long val, LocationIdentity locationIdentity) {
+        UNSAFE.putLong(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity) {
+        UNSAFE.putFloat(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity) {
+        UNSAFE.putDouble(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) {
+        UNSAFE.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.INITIALIZE)
+    public void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity) {
+        UNSAFE.putLong(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeByte(int offset, byte val, LocationIdentity locationIdentity) {
+        writeByte(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeChar(int offset, char val, LocationIdentity locationIdentity) {
+        writeChar(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeShort(int offset, short val, LocationIdentity locationIdentity) {
+        writeShort(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeInt(int offset, int val, LocationIdentity locationIdentity) {
+        writeInt(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeLong(int offset, long val, LocationIdentity locationIdentity) {
+        writeLong(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeFloat(int offset, float val, LocationIdentity locationIdentity) {
+        writeFloat(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeDouble(int offset, double val, LocationIdentity locationIdentity) {
+        writeDouble(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeWord(int offset, WordBase val, LocationIdentity locationIdentity) {
+        writeWord(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.INITIALIZE)
+    public void initializeLong(int offset, long val, LocationIdentity locationIdentity) {
+        initializeLong(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeObject(int offset, Object val, LocationIdentity locationIdentity) {
+        writeObject(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public byte readByte(WordBase offset) {
+        return UNSAFE.getByte(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public char readChar(WordBase offset) {
+        return UNSAFE.getChar(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public short readShort(WordBase offset) {
+        return UNSAFE.getShort(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public int readInt(WordBase offset) {
+        return UNSAFE.getInt(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public long readLong(WordBase offset) {
+        return UNSAFE.getLong(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public float readFloat(WordBase offset) {
+        return UNSAFE.getFloat(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public double readDouble(WordBase offset) {
+        return UNSAFE.getDouble(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Word readWord(WordBase offset) {
+        return box(UNSAFE.getAddress(add((Word) offset).unbox()));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public native Object readObject(WordBase offset);
+
+    @Override
+    @Operation(opcode = Opcode.READ_HEAP)
+    public native Object readObject(WordBase offset, BarrierType barrierType);
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public byte readByte(int offset) {
+        return readByte(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public char readChar(int offset) {
+        return readChar(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public short readShort(int offset) {
+        return readShort(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public int readInt(int offset) {
+        return readInt(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public long readLong(int offset) {
+        return readLong(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public float readFloat(int offset) {
+        return readFloat(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public double readDouble(int offset) {
+        return readDouble(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Word readWord(int offset) {
+        return readWord(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_POINTER)
+    public Object readObject(int offset) {
+        return readObject(signed(offset));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ_HEAP)
+    public Object readObject(int offset, BarrierType barrierType) {
+        return readObject(signed(offset), barrierType);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeByte(WordBase offset, byte val) {
+        UNSAFE.putByte(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeChar(WordBase offset, char val) {
+        UNSAFE.putChar(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeShort(WordBase offset, short val) {
+        UNSAFE.putShort(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeInt(WordBase offset, int val) {
+        UNSAFE.putInt(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeLong(WordBase offset, long val) {
+        UNSAFE.putLong(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeFloat(WordBase offset, float val) {
+        UNSAFE.putFloat(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeDouble(WordBase offset, double val) {
+        UNSAFE.putDouble(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeWord(WordBase offset, WordBase val) {
+        UNSAFE.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public native void writeObject(WordBase offset, Object val);
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeByte(int offset, byte val) {
+        writeByte(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeChar(int offset, char val) {
+        writeChar(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeShort(int offset, short val) {
+        writeShort(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeInt(int offset, int val) {
+        writeInt(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeLong(int offset, long val) {
+        writeLong(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeFloat(int offset, float val) {
+        writeFloat(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeDouble(int offset, double val) {
+        writeDouble(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeWord(int offset, WordBase val) {
+        writeWord(signed(offset), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE_POINTER)
+    public void writeObject(int offset, Object val) {
+        writeObject(signed(offset), val);
+    }
+
+    @Override
+    public final boolean equals(Object obj) {
+        throw GraalError.shouldNotReachHere("equals must not be called on words");
+    }
+
+    @Override
+    public final int hashCode() {
+        throw GraalError.shouldNotReachHere("hashCode must not be called on words");
+    }
+
+    @Override
+    public String toString() {
+        throw GraalError.shouldNotReachHere("toString must not be called on words");
+    }
+}
+
+final class HostedWord extends Word {
+
+    private static final int SMALL_FROM = -1;
+    private static final int SMALL_TO = 100;
+
+    private static final HostedWord[] smallCache = new HostedWord[SMALL_TO - SMALL_FROM + 1];
+
+    static {
+        for (int i = SMALL_FROM; i <= SMALL_TO; i++) {
+            smallCache[i - SMALL_FROM] = new HostedWord(i);
+        }
+    }
+
+    private final long rawValue;
+
+    private HostedWord(long rawValue) {
+        this.rawValue = rawValue;
+    }
+
+    protected static Word boxLong(long val) {
+        if (val >= SMALL_FROM && val <= SMALL_TO) {
+            return smallCache[(int) val - SMALL_FROM];
+        }
+        return new HostedWord(val);
+    }
+
+    @Override
+    protected long unbox() {
+        return rawValue;
+    }
+
+    @Override
+    public String toString() {
+        return "Word<" + rawValue + ">";
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordBase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordBase.java
new file mode 100644
index 0000000..006caa1
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordBase.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+public interface WordBase {
+
+    long rawValue();
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java
new file mode 100644
index 0000000..e6f2609
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.word.Word.Operation;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Encapsulates information for Java types representing raw words (as opposed to Objects).
+ */
+public class WordTypes {
+
+    /**
+     * Resolved type for {@link WordBase}.
+     */
+    private final ResolvedJavaType wordBaseType;
+
+    /**
+     * Resolved type for {@link Word}.
+     */
+    private final ResolvedJavaType wordImplType;
+
+    /**
+     * Resolved type for {@link ObjectAccess}.
+     */
+    private final ResolvedJavaType objectAccessType;
+
+    /**
+     * Resolved type for {@link BarrieredAccess}.
+     */
+    private final ResolvedJavaType barrieredAccessType;
+
+    private final JavaKind wordKind;
+
+    public WordTypes(MetaAccessProvider metaAccess, JavaKind wordKind) {
+        this.wordKind = wordKind;
+        this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
+        this.wordImplType = metaAccess.lookupJavaType(Word.class);
+        this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
+        this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class);
+    }
+
+    /**
+     * Determines if a given method denotes a word operation.
+     */
+    public boolean isWordOperation(ResolvedJavaMethod targetMethod) {
+        final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass());
+        final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass());
+        if (isObjectAccess || isBarrieredAccess) {
+            assert targetMethod.getAnnotation(Operation.class) != null : targetMethod + " should be annotated with @" + Operation.class.getSimpleName();
+            return true;
+        }
+        return isWord(targetMethod.getDeclaringClass());
+    }
+
+    /**
+     * Gets the method annotated with {@link Operation} based on a given method that represents a
+     * word operation (but may not necessarily have the annotation).
+     *
+     * @param callingContextType the {@linkplain ResolvedJavaType type} from which
+     *            {@code targetMethod} is invoked
+     * @return the {@link Operation} method resolved for {@code targetMethod} if any
+     */
+    public ResolvedJavaMethod getWordOperation(ResolvedJavaMethod targetMethod, ResolvedJavaType callingContextType) {
+        final boolean isWordBase = wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass());
+        ResolvedJavaMethod wordMethod = targetMethod;
+        if (isWordBase && !targetMethod.isStatic()) {
+            assert wordImplType.isLinked();
+            wordMethod = wordImplType.resolveConcreteMethod(targetMethod, callingContextType);
+        }
+        assert wordMethod != null : targetMethod;
+        assert BridgeMethodUtils.getAnnotation(Operation.class, wordMethod) != null;
+        return wordMethod;
+    }
+
+    /**
+     * Determines if a given node has a word type.
+     */
+    public boolean isWord(ValueNode node) {
+        return isWord(StampTool.typeOrNull(node));
+    }
+
+    /**
+     * Determines if a given type is a word type.
+     */
+    public boolean isWord(JavaType type) {
+        return type instanceof ResolvedJavaType && wordBaseType.isAssignableFrom((ResolvedJavaType) type);
+    }
+
+    /**
+     * Gets the kind for a given type, returning the {@linkplain #getWordKind() word kind} if
+     * {@code type} is a {@linkplain #isWord(JavaType) word type}.
+     */
+    public JavaKind asKind(JavaType type) {
+        if (isWord(type)) {
+            return wordKind;
+        } else {
+            return type.getJavaKind();
+        }
+    }
+
+    public JavaKind getWordKind() {
+        return wordKind;
+    }
+
+    /**
+     * Gets the stamp for a given {@linkplain #isWord(JavaType) word type}.
+     */
+    public Stamp getWordStamp(ResolvedJavaType type) {
+        assert isWord(type);
+        return StampFactory.forKind(wordKind);
+    }
+
+    public ResolvedJavaType getWordImplType() {
+        return wordImplType;
+    }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/nodes/WordCastNode.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/nodes/WordCastNode.java
new file mode 100644
index 0000000..7e7e51a
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/nodes/WordCastNode.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.word.Word.Opcode;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Casts between Word and Object exposed by the {@link Opcode#FROM_ADDRESS},
+ * {@link Opcode#OBJECT_TO_TRACKED}, {@link Opcode#OBJECT_TO_UNTRACKED} and {@link Opcode#TO_OBJECT}
+ * operations. It has an impact on the pointer maps for the GC, so it must not be scheduled or
+ * optimized away.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
+
+    public static final NodeClass<WordCastNode> TYPE = NodeClass.create(WordCastNode.class);
+
+    @Input ValueNode input;
+    public final boolean trackedPointer;
+
+    public static WordCastNode wordToObject(ValueNode input, JavaKind wordKind) {
+        assert input.getStackKind() == wordKind;
+        return new WordCastNode(StampFactory.object(), input);
+    }
+
+    public static WordCastNode addressToWord(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof AbstractPointerStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input);
+    }
+
+    public static WordCastNode objectToTrackedPointer(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof ObjectStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input, true);
+    }
+
+    public static WordCastNode objectToUntrackedPointer(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof ObjectStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input, false);
+    }
+
+    protected WordCastNode(Stamp stamp, ValueNode input) {
+        this(stamp, input, true);
+    }
+
+    protected WordCastNode(Stamp stamp, ValueNode input, boolean trackedPointer) {
+        super(TYPE, stamp);
+        this.input = input;
+        this.trackedPointer = trackedPointer;
+    }
+
+    public ValueNode getInput() {
+        return input;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            /* If the cast is unused, it can be eliminated. */
+            return input;
+        }
+
+        assert !stamp().isCompatible(input.stamp());
+        if (input.isConstant()) {
+            /* Null pointers are uncritical for GC, so they can be constant folded. */
+            if (input.asJavaConstant().isNull()) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (input.asJavaConstant().getJavaKind().isNumericInteger() && input.asJavaConstant().asLong() == 0) {
+                return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, tool.getMetaAccess());
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        Value value = generator.operand(input);
+        ValueKind<?> kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+        assert kind.getPlatformKind().getSizeInBytes() == value.getPlatformKind().getSizeInBytes();
+
+        if (trackedPointer && LIRKind.isValue(kind) && !LIRKind.isValue(value)) {
+            // just change the PlatformKind, but don't drop reference information
+            kind = value.getValueKind().changeType(kind.getPlatformKind());
+        }
+
+        if (kind.equals(value.getValueKind())) {
+            generator.setResult(this, value);
+        } else {
+            AllocatableValue result = generator.getLIRGeneratorTool().newVariable(kind);
+            generator.getLIRGeneratorTool().emitMove(result, value);
+            generator.setResult(this, result);
+        }
+    }
+}
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index a87885e..f2a3b69 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -547,11 +547,7 @@
     if (pslash != NULL) {
       pslash = strrchr(buf, '/');
       if (pslash != NULL) {
-        *pslash = '\0';          // Get rid of /<arch>.
-        pslash = strrchr(buf, '/');
-        if (pslash != NULL) {
-          *pslash = '\0';        // Get rid of /lib.
-        }
+        *pslash = '\0';        // Get rid of /lib.
       }
     }
     Arguments::set_java_home(buf);
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index a59f520..3b6122f 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -218,9 +218,6 @@
   #endif
 #endif
 
-// Cpu architecture string
-static char cpu_arch[] = HOTSPOT_LIB_ARCH;
-
 
 // pid_t gettid()
 //
@@ -263,7 +260,7 @@
   //
   // Obtain the JAVA_HOME value from the location of libjvm.so.
   // This library should be located at:
-  // <JAVA_HOME>/jre/lib/<arch>/{client|server}/libjvm.so.
+  // <JAVA_HOME>/lib/{client|server}/libjvm.so.
   //
   // If "/jre/lib/" appears at the right place in the path, then we
   // assume libjvm.so is installed in a JDK and we use this path.
@@ -329,11 +326,7 @@
     if (pslash != NULL) {
       pslash = strrchr(buf, '/');
       if (pslash != NULL) {
-        *pslash = '\0';          // Get rid of /<arch>.
-        pslash = strrchr(buf, '/');
-        if (pslash != NULL) {
-          *pslash = '\0';        // Get rid of /lib.
-        }
+        *pslash = '\0';        // Get rid of /lib.
       }
     }
     Arguments::set_java_home(buf);
@@ -360,9 +353,9 @@
     // That's +1 for the colon and +1 for the trailing '\0'.
     char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char,
                                                      strlen(v) + 1 +
-                                                     sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1,
+                                                     sizeof(SYS_EXT_DIR) + sizeof("/lib/") + sizeof(DEFAULT_LIBPATH) + 1,
                                                      mtInternal);
-    sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch);
+    sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib:" DEFAULT_LIBPATH, v, v_colon);
     Arguments::set_library_path(ld_library_path);
     FREE_C_HEAP_ARRAY(char, ld_library_path);
   }
@@ -2310,7 +2303,7 @@
 
   if (Arguments::sun_java_launcher_is_altjvm()) {
     // Support for the java launcher's '-XXaltjvm=<path>' option. Typical
-    // value for buf is "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so".
+    // value for buf is "<JAVA_HOME>/jre/lib/<vmtype>/libjvm.so".
     // If "/jre/lib/" appears at the right place in the string, then
     // assume we are installed in a JDK and we're done. Otherwise, check
     // for a JAVA_HOME environment variable and fix up the path so it
@@ -2346,9 +2339,9 @@
         len = strlen(buf);
         assert(len < buflen, "Ran out of buffer room");
         jrelib_p = buf + len;
-        snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch);
+        snprintf(jrelib_p, buflen-len, "/jre/lib");
         if (0 != access(buf, F_OK)) {
-          snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch);
+          snprintf(jrelib_p, buflen-len, "/lib");
         }
 
         if (0 == access(buf, F_OK)) {
diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp
index 1c11823..527246d 100644
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp
@@ -534,13 +534,12 @@
 #define SYS_EXT_DIR     "/usr/jdk/packages"
 #define EXTENSIONS_DIR  "/lib/ext"
 
-  char cpu_arch[12];
   // Buffer that fits several sprintfs.
   // Note that the space for the colon and the trailing null are provided
   // by the nulls included by the sizeof operator.
   const size_t bufsize =
     MAX3((size_t)MAXPATHLEN,  // For dll_dir & friends.
-         sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch), // invariant ld_library_path
+         sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path
          (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir
   char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
 
@@ -561,11 +560,7 @@
     if (pslash != NULL) {
       pslash = strrchr(buf, '/');
       if (pslash != NULL) {
-        *pslash = '\0';          // Get rid of /<arch>.
-        pslash = strrchr(buf, '/');
-        if (pslash != NULL) {
-          *pslash = '\0';        // Get rid of /lib.
-        }
+        *pslash = '\0';        // Get rid of /lib.
       }
     }
     Arguments::set_java_home(buf);
@@ -623,21 +618,8 @@
     // However, to prevent the proliferation of improperly built native
     // libraries, the new path component /usr/jdk/packages is added here.
 
-    // Determine the actual CPU architecture.
-    sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
-#ifdef _LP64
-    // If we are a 64-bit vm, perform the following translations:
-    //   sparc   -> sparcv9
-    //   i386    -> amd64
-    if (strcmp(cpu_arch, "sparc") == 0) {
-      strcat(cpu_arch, "v9");
-    } else if (strcmp(cpu_arch, "i386") == 0) {
-      strcpy(cpu_arch, "amd64");
-    }
-#endif
-
     // Construct the invariant part of ld_library_path.
-    sprintf(common_path, SYS_EXT_DIR "/lib/%s", cpu_arch);
+    sprintf(common_path, SYS_EXT_DIR "/lib");
 
     // Struct size is more than sufficient for the path components obtained
     // through the dlinfo() call, so only add additional space for the path
@@ -2076,18 +2058,9 @@
       // Look for JAVA_HOME in the environment.
       char* java_home_var = ::getenv("JAVA_HOME");
       if (java_home_var != NULL && java_home_var[0] != 0) {
-        char cpu_arch[12];
         char* jrelib_p;
         int   len;
-        sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
-#ifdef _LP64
-        // If we are on sparc running a 64-bit vm, look in jre/lib/sparcv9.
-        if (strcmp(cpu_arch, "sparc") == 0) {
-          strcat(cpu_arch, "v9");
-        } else if (strcmp(cpu_arch, "i386") == 0) {
-          strcpy(cpu_arch, "amd64");
-        }
-#endif
+
         // Check the current module name "libjvm.so".
         p = strrchr(buf, '/');
         assert(strstr(p, "/libjvm") == p, "invalid library name");
@@ -2098,9 +2071,9 @@
         len = strlen(buf);
         assert(len < buflen, "Ran out of buffer space");
         jrelib_p = buf + len;
-        snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch);
+        snprintf(jrelib_p, buflen-len, "/jre/lib");
         if (0 != access(buf, F_OK)) {
-          snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch);
+          snprintf(jrelib_p, buflen-len, "/lib");
         }
 
         if (0 == access(buf, F_OK)) {
diff --git a/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp b/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp
new file mode 100644
index 0000000..a53df4b
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP
+
+#include "runtime/os.hpp"
+#include "vm_version_arm.hpp"
+
+// Implementation of class atomic
+
+/*
+ * Atomic long operations on 32-bit ARM
+ * ARM v7 supports LDREXD/STREXD synchronization instructions so no problem.
+ * ARM < v7 does not have explicit 64 atomic load/store capability.
+ * However, gcc emits LDRD/STRD instructions on v5te and LDM/STM on v5t
+ * when loading/storing 64 bits.
+ * For non-MP machines (which is all we support for ARM < v7)
+ * under current Linux distros these instructions appear atomic.
+ * See section A3.5.3 of ARM Architecture Reference Manual for ARM v7.
+ * Also, for cmpxchg64, if ARM < v7 we check for cmpxchg64 support in the
+ * Linux kernel using _kuser_helper_version. See entry-armv.S in the Linux
+ * kernel source or kernel_user_helpers.txt in Linux Doc.
+ */
+
+inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
+inline void Atomic::store    (jshort   store_value, jshort*   dest) { *dest = store_value; }
+inline void Atomic::store    (jint     store_value, jint*     dest) { *dest = store_value; }
+inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
+inline void Atomic::store_ptr(void*    store_value, void*     dest) { *(void**)dest = store_value; }
+
+inline void Atomic::store    (jbyte    store_value, volatile jbyte*    dest) { *dest = store_value; }
+inline void Atomic::store    (jshort   store_value, volatile jshort*   dest) { *dest = store_value; }
+inline void Atomic::store    (jint     store_value, volatile jint*     dest) { *dest = store_value; }
+inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
+inline void Atomic::store_ptr(void*    store_value, volatile void*     dest) { *(void* volatile *)dest = store_value; }
+
+inline jlong Atomic::load (volatile jlong* src) {
+  assert(((intx)src & (sizeof(jlong)-1)) == 0, "Atomic load jlong mis-aligned");
+#ifdef AARCH64
+  return *src;
+#else
+  return (*os::atomic_load_long_func)(src);
+#endif
+}
+
+inline void Atomic::store (jlong value, volatile jlong* dest) {
+  assert(((intx)dest & (sizeof(jlong)-1)) == 0, "Atomic store jlong mis-aligned");
+#ifdef AARCH64
+  *dest = value;
+#else
+  (*os::atomic_store_long_func)(value, dest);
+#endif
+}
+
+inline void Atomic::store (jlong value, jlong* dest) {
+  store(value, (volatile jlong*)dest);
+}
+
+// As per atomic.hpp all read-modify-write operations have to provide two-way
+// barriers semantics. For AARCH64 we are using load-acquire-with-reservation and
+// store-release-with-reservation. While load-acquire combined with store-release
+// do not generally form two-way barriers, their use with reservations does - the
+// ARMv8 architecture manual Section F "Barrier Litmus Tests" indicates they
+// provide sequentially consistent semantics. All we need to add is an explicit
+// barrier in the failure path of the cmpxchg operations (as these don't execute
+// the store) - arguably this may be overly cautious as there is a very low
+// likelihood that the hardware would pull loads/stores into the region guarded
+// by the reservation.
+//
+// For ARMv7 we add explicit barriers in the stubs.
+
+inline jint Atomic::add(jint add_value, volatile jint* dest) {
+#ifdef AARCH64
+  jint val;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %w[val], [%[dest]]\n\t"
+    " add %w[val], %w[val], %w[add_val]\n\t"
+    " stlxr %w[tmp], %w[val], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    : [val] "=&r" (val), [tmp] "=&r" (tmp)
+    : [add_val] "r" (add_value), [dest] "r" (dest)
+    : "memory");
+  return val;
+#else
+  return (*os::atomic_add_func)(add_value, dest);
+#endif
+}
+
+inline void Atomic::inc(volatile jint* dest) {
+  Atomic::add(1, (volatile jint *)dest);
+}
+
+inline void Atomic::dec(volatile jint* dest) {
+  Atomic::add(-1, (volatile jint *)dest);
+}
+
+inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
+#ifdef AARCH64
+  intptr_t val;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %[val], [%[dest]]\n\t"
+    " add %[val], %[val], %[add_val]\n\t"
+    " stlxr %w[tmp], %[val], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    : [val] "=&r" (val), [tmp] "=&r" (tmp)
+    : [add_val] "r" (add_value), [dest] "r" (dest)
+    : "memory");
+  return val;
+#else
+  return (intptr_t)Atomic::add((jint)add_value, (volatile jint*)dest);
+#endif
+}
+
+inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) {
+  return (void*)add_ptr(add_value, (volatile intptr_t*)dest);
+}
+
+inline void Atomic::inc_ptr(volatile intptr_t* dest) {
+  Atomic::add_ptr(1, dest);
+}
+
+inline void Atomic::dec_ptr(volatile intptr_t* dest) {
+  Atomic::add_ptr(-1, dest);
+}
+
+inline void Atomic::inc_ptr(volatile void* dest) {
+  inc_ptr((volatile intptr_t*)dest);
+}
+
+inline void Atomic::dec_ptr(volatile void* dest) {
+  dec_ptr((volatile intptr_t*)dest);
+}
+
+
+inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+#ifdef AARCH64
+  jint old_val;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %w[old_val], [%[dest]]\n\t"
+    " stlxr %w[tmp], %w[new_val], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    : [old_val] "=&r" (old_val), [tmp] "=&r" (tmp)
+    : [new_val] "r" (exchange_value), [dest] "r" (dest)
+    : "memory");
+  return old_val;
+#else
+  return (*os::atomic_xchg_func)(exchange_value, dest);
+#endif
+}
+
+inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+#ifdef AARCH64
+  intptr_t old_val;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %[old_val], [%[dest]]\n\t"
+    " stlxr %w[tmp], %[new_val], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    : [old_val] "=&r" (old_val), [tmp] "=&r" (tmp)
+    : [new_val] "r" (exchange_value), [dest] "r" (dest)
+    : "memory");
+  return old_val;
+#else
+  return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
+#endif
+}
+
+inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
+  return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+}
+
+// The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering
+
+inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
+#ifdef AARCH64
+  jint rv;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %w[rv], [%[dest]]\n\t"
+    " cmp %w[rv], %w[cv]\n\t"
+    " b.ne 2f\n\t"
+    " stlxr %w[tmp], %w[ev], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    " b 3f\n\t"
+    "2:\n\t"
+    " dmb sy\n\t"
+    "3:\n\t"
+    : [rv] "=&r" (rv), [tmp] "=&r" (tmp)
+    : [ev] "r" (exchange_value), [dest] "r" (dest), [cv] "r" (compare_value)
+    : "memory");
+  return rv;
+#else
+  // Warning:  Arguments are swapped to avoid moving them for kernel call
+  return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest);
+#endif
+}
+
+inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
+#ifdef AARCH64
+  jlong rv;
+  int tmp;
+  __asm__ volatile(
+    "1:\n\t"
+    " ldaxr %[rv], [%[dest]]\n\t"
+    " cmp %[rv], %[cv]\n\t"
+    " b.ne 2f\n\t"
+    " stlxr %w[tmp], %[ev], [%[dest]]\n\t"
+    " cbnz %w[tmp], 1b\n\t"
+    " b 3f\n\t"
+    "2:\n\t"
+    " dmb sy\n\t"
+    "3:\n\t"
+    : [rv] "=&r" (rv), [tmp] "=&r" (tmp)
+    : [ev] "r" (exchange_value), [dest] "r" (dest), [cv] "r" (compare_value)
+    : "memory");
+  return rv;
+#else
+  assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!");
+  return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest);
+#endif
+}
+
+inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
+#ifdef AARCH64
+  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
+#else
+  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
+#endif
+}
+
+inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) {
+  return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order);
+}
+
+#endif // OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/bytes_linux_arm.inline.hpp b/hotspot/src/os_cpu/linux_arm/vm/bytes_linux_arm.inline.hpp
new file mode 100644
index 0000000..df0f0b8
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/bytes_linux_arm.inline.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_BYTES_LINUX_ARM_INLINE_HPP
+#define OS_CPU_LINUX_ARM_VM_BYTES_LINUX_ARM_INLINE_HPP
+
+#include <byteswap.h>
+
+// Efficient swapping of data bytes from Java byte
+// ordering to native byte ordering and vice versa.
+inline u2 Bytes::swap_u2(u2 x) {
+  // TODO: ARM - optimize
+  return bswap_16(x);
+}
+
+inline u4 Bytes::swap_u4(u4 x) {
+  // TODO: ARM - optimize
+  return bswap_32(x);
+}
+
+inline u8 Bytes::swap_u8(u8 x) {
+  // TODO: ARM - optimize
+  return bswap_64(x);
+}
+
+#endif // OS_CPU_LINUX_ARM_VM_BYTES_LINUX_ARM_INLINE_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/copy_linux_arm.inline.hpp b/hotspot/src/os_cpu/linux_arm/vm/copy_linux_arm.inline.hpp
new file mode 100644
index 0000000..b52aba2
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/copy_linux_arm.inline.hpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_COPY_LINUX_ARM_INLINE_HPP
+#define OS_CPU_LINUX_ARM_VM_COPY_LINUX_ARM_INLINE_HPP
+
+static void pd_conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+#ifdef AARCH64
+  _Copy_conjoint_words(from, to, count * HeapWordSize);
+#else
+   // NOTE: _Copy_* functions on 32-bit ARM expect "to" and "from" arguments in reversed order
+  _Copy_conjoint_words(to, from, count * HeapWordSize);
+#endif
+}
+
+static void pd_disjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+#ifdef AARCH64
+  _Copy_disjoint_words(from, to, count * HeapWordSize);
+#else
+  _Copy_disjoint_words(to, from, count * HeapWordSize);
+#endif // AARCH64
+}
+
+static void pd_disjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count) {
+  pd_disjoint_words(from, to, count);
+}
+
+static void pd_aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_words(from, to, count);
+}
+
+static void pd_aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count) {
+  pd_disjoint_words(from, to, count);
+}
+
+static void pd_conjoint_bytes(void* from, void* to, size_t count) {
+  memmove(to, from, count);
+}
+
+static void pd_conjoint_bytes_atomic(void* from, void* to, size_t count) {
+  pd_conjoint_bytes(from, to, count);
+}
+
+static void pd_conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count) {
+#ifdef AARCH64
+  _Copy_conjoint_jshorts_atomic(from, to, count * BytesPerShort);
+#else
+  _Copy_conjoint_jshorts_atomic(to, from, count * BytesPerShort);
+#endif
+}
+
+static void pd_conjoint_jints_atomic(jint* from, jint* to, size_t count) {
+#ifdef AARCH64
+  _Copy_conjoint_jints_atomic(from, to, count * BytesPerInt);
+#else
+  assert(HeapWordSize == BytesPerInt, "heapwords and jints must be the same size");
+  // pd_conjoint_words is word-atomic in this implementation.
+  pd_conjoint_words((HeapWord*)from, (HeapWord*)to, count);
+#endif
+}
+
+static void pd_conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count) {
+#ifdef AARCH64
+  assert(HeapWordSize == BytesPerLong, "64-bit architecture");
+  pd_conjoint_words((HeapWord*)from, (HeapWord*)to, count);
+#else
+  _Copy_conjoint_jlongs_atomic(to, from, count * BytesPerLong);
+#endif
+}
+
+static void pd_conjoint_oops_atomic(oop* from, oop* to, size_t count) {
+#ifdef AARCH64
+  if (UseCompressedOops) {
+    assert(BytesPerHeapOop == BytesPerInt, "compressed oops");
+    pd_conjoint_jints_atomic((jint*)from, (jint*)to, count);
+  } else {
+    assert(BytesPerHeapOop == BytesPerLong, "64-bit architecture");
+    pd_conjoint_jlongs_atomic((jlong*)from, (jlong*)to, count);
+  }
+#else
+  assert(BytesPerHeapOop == BytesPerInt, "32-bit architecture");
+  pd_conjoint_jints_atomic((jint*)from, (jint*)to, count);
+#endif
+}
+
+static void pd_arrayof_conjoint_bytes(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_bytes_atomic((void*)from, (void*)to, count);
+}
+
+static void pd_arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_jshorts_atomic((jshort*)from, (jshort*)to, count);
+}
+
+static void pd_arrayof_conjoint_jints(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_jints_atomic((jint*)from, (jint*)to, count);
+}
+
+static void pd_arrayof_conjoint_jlongs(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_jlongs_atomic((jlong*)from, (jlong*)to, count);
+}
+
+static void pd_arrayof_conjoint_oops(HeapWord* from, HeapWord* to, size_t count) {
+  pd_conjoint_oops_atomic((oop*)from, (oop*)to, count);
+}
+
+#endif // OS_CPU_LINUX_ARM_VM_COPY_LINUX_ARM_INLINE_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/globals_linux_arm.hpp b/hotspot/src/os_cpu/linux_arm/vm/globals_linux_arm.hpp
new file mode 100644
index 0000000..78a713a
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/globals_linux_arm.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_GLOBALS_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_VM_GLOBALS_LINUX_ARM_HPP
+
+//
+// Sets the default values for platform dependent flags used by the runtime system.
+// (see globals.hpp)
+//
+define_pd_global(bool, DontYieldALot,            false);
+#ifdef AARCH64
+define_pd_global(intx, CompilerThreadStackSize,  1024);
+define_pd_global(intx, ThreadStackSize,          1024);
+define_pd_global(intx, VMThreadStackSize,        1024);
+#else
+define_pd_global(intx, CompilerThreadStackSize,  512);
+// System default ThreadStackSize appears to be 512 which is too big.
+define_pd_global(intx, ThreadStackSize,          320);
+define_pd_global(intx, VMThreadStackSize,        512);
+#endif // AARCH64
+
+define_pd_global(size_t, JVMInvokeMethodSlack,   8192);
+
+// Used on 64 bit platforms for UseCompressedOops base address or CDS
+define_pd_global(size_t, HeapBaseMinAddress,     2*G);
+
+#endif // OS_CPU_LINUX_ARM_VM_GLOBALS_LINUX_ARM_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/linux_arm_32.s b/hotspot/src/os_cpu/linux_arm/vm/linux_arm_32.s
new file mode 100644
index 0000000..fd0c822
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/linux_arm_32.s
@@ -0,0 +1,513 @@
+# 
+# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+# 
+
+	
+        # NOTE WELL!  The _Copy functions are called directly
+	# from server-compiler-generated code via CallLeafNoFP,
+	# which means that they *must* either not use floating
+	# point or use it in the same manner as does the server
+	# compiler.
+	
+        .globl _Copy_conjoint_bytes
+	.type _Copy_conjoint_bytes, %function
+        .globl _Copy_arrayof_conjoint_bytes
+	.type _Copy_arrayof_conjoint_bytes, %function
+	.globl _Copy_disjoint_words
+	.type _Copy_disjoint_words, %function
+	.globl _Copy_conjoint_words
+	.type _Copy_conjoint_words, %function
+        .globl _Copy_conjoint_jshorts_atomic
+	.type _Copy_conjoint_jshorts_atomic, %function
+	.globl _Copy_arrayof_conjoint_jshorts
+	.type _Copy_arrayof_conjoint_jshorts, %function
+        .globl _Copy_conjoint_jints_atomic
+	.type _Copy_conjoint_jints_atomic, %function
+        .globl _Copy_arrayof_conjoint_jints
+	.type _Copy_arrayof_conjoint_jints, %function
+	.globl _Copy_conjoint_jlongs_atomic
+	.type _Copy_conjoint_jlongs_atomic, %function
+	.globl _Copy_arrayof_conjoint_jlongs
+	.type _Copy_arrayof_conjoint_jlongs, %function
+
+	.text
+        .globl  SpinPause
+        .type SpinPause, %function
+SpinPause:
+        bx      LR
+
+        # Support for void Copy::conjoint_bytes(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_conjoint_bytes:
+        swi     0x9f0001
+
+        # Support for void Copy::arrayof_conjoint_bytes(void* from,
+        #                                               void* to,
+        #                                               size_t count)
+_Copy_arrayof_conjoint_bytes:
+        swi     0x9f0001
+
+
+        # Support for void Copy::disjoint_words(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_disjoint_words:
+        stmdb    sp!, {r3 - r9, ip}
+ 
+        cmp     r2, #0
+        beq     disjoint_words_finish
+
+        pld     [r1, #0]
+        cmp     r2, #12
+        ble disjoint_words_small
+
+        .align 3
+dw_f2b_loop_32:
+        subs    r2, #32
+	blt	dw_f2b_loop_32_finish
+        ldmia r1!, {r3 - r9, ip}
+        nop
+	pld     [r1]
+        stmia r0!, {r3 - r9, ip}
+        bgt     dw_f2b_loop_32
+dw_f2b_loop_32_finish:
+        addlts  r2, #32
+        beq     disjoint_words_finish
+        cmp     r2, #16
+	blt	disjoint_words_small
+        ldmia r1!, {r3 - r6}
+        subge   r2, r2, #16
+        stmia r0!, {r3 - r6}
+        beq     disjoint_words_finish
+disjoint_words_small:
+        cmp     r2, #8
+        ldr     r7, [r1], #4
+        ldrge   r8, [r1], #4
+        ldrgt   r9, [r1], #4
+        str     r7, [r0], #4
+        strge   r8, [r0], #4
+        strgt   r9, [r0], #4
+
+disjoint_words_finish:
+        ldmia   sp!, {r3 - r9, ip}
+        bx      lr
+
+
+        # Support for void Copy::conjoint_words(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_conjoint_words:
+        stmdb    sp!, {r3 - r9, ip}
+
+	cmp	r2, #0
+	beq	conjoint_words_finish
+
+        pld     [r1, #0]
+        cmp     r2, #12
+        ble conjoint_words_small
+
+        subs    r3, r0, r1
+        cmphi   r2, r3
+        bhi     cw_b2f_copy
+        .align 3
+cw_f2b_loop_32:
+        subs    r2, #32
+	blt	cw_f2b_loop_32_finish
+        ldmia r1!, {r3 - r9, ip}
+        nop
+	pld     [r1]
+        stmia r0!, {r3 - r9, ip}
+        bgt     cw_f2b_loop_32
+cw_f2b_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_words_finish
+        cmp     r2, #16
+	blt	conjoint_words_small
+        ldmia r1!, {r3 - r6}
+        subge   r2, r2, #16
+        stmia r0!, {r3 - r6}
+        beq     conjoint_words_finish
+conjoint_words_small:
+        cmp     r2, #8
+        ldr     r7, [r1], #4
+        ldrge   r8, [r1], #4
+        ldrgt   r9, [r1], #4
+        str     r7, [r0], #4
+        strge   r8, [r0], #4
+        strgt   r9, [r0], #4
+        b       conjoint_words_finish
+
+	# Src and dest overlap, copy in a descending order
+cw_b2f_copy:
+        add     r1, r2
+        pld     [r1, #-32]
+        add     r0, r2
+        .align 3
+cw_b2f_loop_32:
+        subs    r2, #32
+	blt	cw_b2f_loop_32_finish
+        ldmdb r1!, {r3-r9,ip}
+        nop
+	pld     [r1, #-32]
+        stmdb r0!, {r3-r9,ip}
+        bgt     cw_b2f_loop_32
+cw_b2f_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_words_finish
+        cmp     r2, #16
+	blt	cw_b2f_copy_small
+        ldmdb r1!, {r3 - r6}
+        subge   r2, r2, #16
+        stmdb r0!, {r3 - r6}
+        beq     conjoint_words_finish
+cw_b2f_copy_small:
+        cmp     r2, #8
+        ldr     r7, [r1, #-4]!
+        ldrge   r8, [r1, #-4]!
+        ldrgt   r9, [r1, #-4]!
+        str     r7, [r0, #-4]!
+        strge   r8, [r0, #-4]!
+        strgt   r9, [r0, #-4]!
+
+conjoint_words_finish:
+        ldmia   sp!, {r3 - r9, ip}
+        bx      lr
+
+        # Support for void Copy::conjoint_jshorts_atomic(void* from,
+        #                                                void* to,
+        #                                                size_t count)
+_Copy_conjoint_jshorts_atomic:
+        stmdb   sp!, {r3 - r9, ip}
+
+	cmp	r2, #0
+	beq	conjoint_shorts_finish	
+
+        subs    r3, r0, r1
+        cmphi   r2, r3
+        bhi     cs_b2f_copy
+
+        pld     [r1]
+
+        ands    r3, r0, #3
+        bne     cs_f2b_dest_u
+        ands    r3, r1, #3
+        bne     cs_f2b_src_u
+
+	# Aligned source address
+        .align 3
+cs_f2b_loop_32:
+        subs    r2, #32
+	blt	cs_f2b_loop_32_finish
+        ldmia r1!, {r3 - r9, ip}
+        nop
+        pld     [r1]
+        stmia r0!, {r3 - r9, ip}
+        bgt     cs_f2b_loop_32
+cs_f2b_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_shorts_finish
+        movs    r6, r2, lsr #3
+        .align 3
+cs_f2b_8_loop:
+        beq     cs_f2b_4
+        ldmia   r1!, {r4-r5}
+        subs    r6, #1
+        stmia   r0!, {r4-r5}
+        bgt     cs_f2b_8_loop
+
+cs_f2b_4:
+        ands    r2, #7
+        beq     conjoint_shorts_finish
+        cmp     r2, #4
+        ldrh    r3, [r1], #2
+        ldrgeh  r4, [r1], #2
+        ldrgth  r5, [r1], #2
+        strh    r3, [r0], #2
+        strgeh  r4, [r0], #2
+        strgth  r5, [r0], #2
+        b       conjoint_shorts_finish
+
+	# Destination not aligned
+cs_f2b_dest_u:
+        ldrh    r3, [r1], #2
+        subs    r2, #2
+        strh    r3, [r0], #2
+        beq     conjoint_shorts_finish
+
+	# Check to see if source is not aligned ether
+        ands    r3, r1, #3
+        beq     cs_f2b_loop_32
+
+cs_f2b_src_u:
+        cmp     r2, #16
+        blt     cs_f2b_8_u
+
+	# Load 2 first bytes to r7 and make src ptr word aligned
+        bic     r1, #3
+        ldr     r7, [r1], #4
+
+	# Destination aligned, source not
+        mov     r8, r2, lsr #4
+        .align 3
+cs_f2b_16_u_loop:
+        mov     r3, r7, lsr #16
+        ldmia   r1!, {r4 - r7}
+        orr     r3, r3, r4, lsl #16
+        mov     r4, r4, lsr #16
+        pld     [r1]
+        orr     r4, r4, r5, lsl #16
+        mov     r5, r5, lsr #16
+        orr     r5, r5, r6, lsl #16
+        mov     r6, r6, lsr #16
+        orr     r6, r6, r7, lsl #16
+        stmia   r0!, {r3 - r6}
+        subs    r8, #1
+        bgt     cs_f2b_16_u_loop
+        ands    r2, #0xf
+        beq     conjoint_shorts_finish
+        sub     r1, #2
+
+cs_f2b_8_u:
+        cmp     r2, #8
+        blt     cs_f2b_4_u
+        ldrh    r4, [r1], #2
+        ldr     r5, [r1], #4
+        ldrh    r6, [r1], #2
+        orr     r4, r4, r5, lsl #16
+        mov     r5, r5, lsr #16
+        orr     r5, r5, r6, lsl #16
+        subs    r2, #8
+        stmia	r0!, {r4 - r5}
+cs_f2b_4_u:
+        beq     conjoint_shorts_finish
+        cmp     r2, #4
+        ldrh    r3, [r1], #2
+        ldrgeh  r4, [r1], #2
+        ldrgth  r5, [r1], #2
+        strh    r3, [r0], #2
+        strgeh  r4, [r0], #2
+        strgth  r5, [r0], #2
+        b       conjoint_shorts_finish
+
+	# Src and dest overlap, copy in a descending order
+cs_b2f_copy:
+        add     r1, r2
+        pld     [r1, #-32]
+        add     r0, r2
+
+        ands    r3, r0, #3
+        bne     cs_b2f_dest_u
+        ands    r3, r1, #3
+        bne     cs_b2f_src_u
+        .align 3
+cs_b2f_loop_32:
+        subs    r2, #32
+	blt	cs_b2f_loop_32_finish
+        ldmdb r1!, {r3-r9,ip}
+        nop
+        pld     [r1, #-32]
+        stmdb r0!, {r3-r9,ip}
+        bgt     cs_b2f_loop_32
+cs_b2f_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_shorts_finish
+        cmp     r2, #24
+        blt     cs_b2f_16
+        ldmdb   r1!, {r3-r8}
+        sub     r2, #24
+        stmdb   r0!, {r3-r8}
+        beq     conjoint_shorts_finish
+cs_b2f_16:
+        cmp     r2, #16
+        blt     cs_b2f_8
+        ldmdb   r1!, {r3-r6}
+        sub     r2, #16
+        stmdb   r0!, {r3-r6}
+        beq     conjoint_shorts_finish
+cs_b2f_8:
+        cmp     r2, #8
+        blt     cs_b2f_all_copy
+        ldmdb   r1!, {r3-r4}
+        sub     r2, #8
+        stmdb   r0!, {r3-r4}
+        beq     conjoint_shorts_finish
+
+cs_b2f_all_copy:
+        cmp     r2, #4
+        ldrh    r3, [r1, #-2]!
+        ldrgeh  r4, [r1, #-2]!
+        ldrgth  r5, [r1, #-2]!
+        strh    r3, [r0, #-2]!
+        strgeh  r4, [r0, #-2]!
+        strgth  r5, [r0, #-2]!
+        b       conjoint_shorts_finish
+
+	# Destination not aligned
+cs_b2f_dest_u:
+        ldrh    r3, [r1, #-2]!
+        strh    r3, [r0, #-2]!
+        sub     r2, #2
+	# Check source alignment as well
+        ands    r3, r1, #3
+        beq     cs_b2f_loop_32
+
+	# Source not aligned
+cs_b2f_src_u:
+        bic     r1, #3
+        .align 3
+cs_b2f_16_loop_u:
+        subs    r2, #16
+        blt     cs_b2f_16_loop_u_finished
+        ldr     r7, [r1]
+        mov     r3, r7
+        ldmdb   r1!, {r4 - r7}
+        mov     r4, r4, lsr #16
+        orr     r4, r4, r5, lsl #16
+        pld     [r1, #-32]
+        mov     r5, r5, lsr #16
+        orr     r5, r5, r6, lsl #16
+        mov     r6, r6, lsr #16
+        orr     r6, r6, r7, lsl #16
+        mov     r7, r7, lsr #16
+        orr     r7, r7, r3, lsl #16
+        stmdb   r0!, {r4 - r7}
+        bgt     cs_b2f_16_loop_u
+        beq     conjoint_shorts_finish
+cs_b2f_16_loop_u_finished:
+        addlts  r2, #16
+        ldr     r3, [r1]
+	cmp     r2, #10
+        blt     cs_b2f_2_u_loop
+        ldmdb   r1!, {r4 - r5}
+        mov     r6, r4, lsr #16
+        orr     r6, r6, r5, lsl #16
+        mov     r7, r5, lsr #16
+        orr     r7, r7, r3, lsl #16
+        stmdb   r0!, {r6-r7}
+        sub     r2, #8
+	.align 3
+cs_b2f_2_u_loop:
+        subs    r2, #2
+        ldrh    r3, [r1], #-2
+        strh    r3, [r0, #-2]!
+        bgt     cs_b2f_2_u_loop
+
+conjoint_shorts_finish:
+        ldmia   sp!, {r3 - r9, ip}
+        bx      lr
+
+
+        # Support for void Copy::arrayof_conjoint_jshorts(void* from,
+        #                                                 void* to,
+        #                                                 size_t count)
+_Copy_arrayof_conjoint_jshorts:
+        swi     0x9f0001
+
+        # Support for void Copy::conjoint_jints_atomic(void* from,
+        #                                              void* to,
+        #                                              size_t count)
+_Copy_conjoint_jints_atomic:
+_Copy_arrayof_conjoint_jints:
+        swi     0x9f0001
+	
+        # Support for void Copy::conjoint_jlongs_atomic(jlong* from,
+        #                                               jlong* to,
+        #                                               size_t count)
+_Copy_conjoint_jlongs_atomic:
+_Copy_arrayof_conjoint_jlongs:
+        stmdb    sp!, {r3 - r9, ip}
+
+	cmp	r2, #0
+	beq	conjoint_longs_finish
+
+        pld     [r1, #0]
+        cmp     r2, #24
+        ble conjoint_longs_small
+
+        subs    r3, r0, r1
+        cmphi   r2, r3
+        bhi     cl_b2f_copy
+        .align 3
+cl_f2b_loop_32:
+        subs    r2, #32
+	blt	cl_f2b_loop_32_finish
+        ldmia r1!, {r3 - r9, ip}
+        nop
+	pld     [r1]
+        stmia r0!, {r3 - r9, ip}
+        bgt     cl_f2b_loop_32
+cl_f2b_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_longs_finish
+conjoint_longs_small:
+        cmp     r2, #16
+	blt	cl_f2b_copy_8
+	bgt	cl_f2b_copy_24
+        ldmia 	r1!, {r3 - r6}
+        stmia 	r0!, {r3 - r6}
+	b	conjoint_longs_finish
+cl_f2b_copy_8:
+        ldmia   r1!, {r3 - r4}
+        stmia   r0!, {r3 - r4}
+        b       conjoint_longs_finish
+cl_f2b_copy_24:
+	ldmia   r1!, {r3 - r8}
+        stmia   r0!, {r3 - r8}
+        b       conjoint_longs_finish
+
+	# Src and dest overlap, copy in a descending order
+cl_b2f_copy:
+        add     r1, r2
+        pld     [r1, #-32]
+        add     r0, r2
+        .align 3
+cl_b2f_loop_32:
+        subs    r2, #32
+	blt	cl_b2f_loop_32_finish
+        ldmdb 	r1!, {r3 - r9, ip}
+        nop
+	pld     [r1]
+        stmdb 	r0!, {r3 - r9, ip}
+        bgt     cl_b2f_loop_32
+cl_b2f_loop_32_finish:
+        addlts  r2, #32
+        beq     conjoint_longs_finish
+        cmp     r2, #16
+	blt	cl_b2f_copy_8
+	bgt	cl_b2f_copy_24
+        ldmdb   r1!, {r3 - r6}
+        stmdb   r0!, {r3 - r6}
+        b       conjoint_longs_finish
+cl_b2f_copy_8:
+	ldmdb   r1!, {r3 - r4}
+        stmdb   r0!, {r3 - r4}
+        b       conjoint_longs_finish
+cl_b2f_copy_24:
+	ldmdb   r1!, {r3 - r8}
+        stmdb   r0!, {r3 - r8}
+
+conjoint_longs_finish:
+        ldmia   sp!, {r3 - r9, ip}
+        bx      lr
+
+
diff --git a/hotspot/src/os_cpu/linux_arm/vm/linux_arm_64.s b/hotspot/src/os_cpu/linux_arm/vm/linux_arm_64.s
new file mode 100644
index 0000000..ab86129
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/linux_arm_64.s
@@ -0,0 +1,542 @@
+# 
+# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+# 
+
+        # TODO-AARCH64
+        
+        # NOTE WELL!  The _Copy functions are called directly
+        # from server-compiler-generated code via CallLeafNoFP,
+        # which means that they *must* either not use floating
+        # point or use it in the same manner as does the server
+        # compiler.
+        
+        .globl _Copy_conjoint_bytes
+        .type _Copy_conjoint_bytes, %function
+        .globl _Copy_arrayof_conjoint_bytes
+        .type _Copy_arrayof_conjoint_bytes, %function
+        .globl _Copy_disjoint_words
+        .type _Copy_disjoint_words, %function
+        .globl _Copy_conjoint_words
+        .type _Copy_conjoint_words, %function
+        .globl _Copy_conjoint_jshorts_atomic
+        .type _Copy_conjoint_jshorts_atomic, %function
+        .globl _Copy_arrayof_conjoint_jshorts
+        .type _Copy_arrayof_conjoint_jshorts, %function
+        .globl _Copy_conjoint_jints_atomic
+        .type _Copy_conjoint_jints_atomic, %function
+        .globl _Copy_arrayof_conjoint_jints
+        .type _Copy_arrayof_conjoint_jints, %function
+        .globl _Copy_conjoint_jlongs_atomic
+        .type _Copy_conjoint_jlongs_atomic, %function
+        .globl _Copy_arrayof_conjoint_jlongs
+        .type _Copy_arrayof_conjoint_jlongs, %function
+
+        .text
+        .globl  SpinPause
+        .type SpinPause, %function
+SpinPause:
+        yield
+        ret
+
+        # Support for void Copy::conjoint_bytes(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_conjoint_bytes:
+        hlt 1002
+
+        # Support for void Copy::arrayof_conjoint_bytes(void* from,
+        #                                               void* to,
+        #                                               size_t count)
+_Copy_arrayof_conjoint_bytes:
+        hlt 1003
+
+
+        # Support for void Copy::disjoint_words(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_disjoint_words:
+        # These and further memory prefetches may hit out of array ranges.
+        # Experiments showed that prefetching of inaccessible memory doesn't result in exceptions.
+        prfm    pldl1keep,  [x0, #0]
+        prfm    pstl1keep,  [x1, #0]
+        prfm    pldl1keep,  [x0, #64]
+        prfm    pstl1keep,  [x1, #64]
+
+        subs    x18, x2,  #128
+        b.ge    dw_large
+
+dw_lt_128:
+        # Copy [x0, x0 + x2) to [x1, x1 + x2)
+        
+        adr     x15,  dw_tail_table_base
+        and     x16,  x2,  #~8
+
+        # Calculate address to jump and store it to x15:
+        #   Each pair of instructions before dw_tail_table_base copies 16 bytes.
+        #   x16 is count of bytes to copy aligned down by 16.
+        #   So x16/16 pairs of instructions should be executed. 
+        #   Each pair takes 8 bytes, so x15 = dw_tail_table_base - (x16/16)*8 = x15 - x16/2
+        sub     x15,  x15, x16, lsr #1
+        prfm    plil1keep, [x15]
+    
+        add     x17,  x0,  x2
+        add     x18,  x1,  x2
+
+        # If x2 = x16 + 8, then copy 8 bytes and x16 bytes after that.
+        # Otherwise x2 = x16, so proceed to copy x16 bytes.
+        tbz     x2, #3, dw_lt_128_even
+        ldr     x3, [x0]
+        str     x3, [x1]
+dw_lt_128_even:
+        # Copy [x17 - x16, x17) to [x18 - x16, x18)
+        # x16 is aligned by 16 and less than 128
+
+        # Execute (x16/16) ldp-stp pairs; each pair copies 16 bytes
+        br      x15
+
+        ldp     x3,  x4,  [x17, #-112]
+        stp     x3,  x4,  [x18, #-112]
+        ldp     x5,  x6,  [x17, #-96]
+        stp     x5,  x6,  [x18, #-96]
+        ldp     x7,  x8,  [x17, #-80]
+        stp     x7,  x8,  [x18, #-80]
+        ldp     x9,  x10, [x17, #-64]
+        stp     x9,  x10, [x18, #-64]
+        ldp     x11, x12, [x17, #-48]
+        stp     x11, x12, [x18, #-48]
+        ldp     x13, x14, [x17, #-32]
+        stp     x13, x14, [x18, #-32]
+        ldp     x15, x16, [x17, #-16]
+        stp     x15, x16, [x18, #-16]
+dw_tail_table_base:
+        ret
+
+.p2align  6
+.rept   12
+        nop
+.endr
+dw_large:
+        # x18 >= 0;
+        # Copy [x0, x0 + x18 + 128) to [x1, x1 + x18 + 128)
+
+        ldp     x3,  x4,  [x0], #64
+        ldp     x5,  x6,  [x0, #-48]
+        ldp     x7,  x8,  [x0, #-32]
+        ldp     x9,  x10, [x0, #-16]
+
+        # Before and after each iteration of loop registers x3-x10 contain [x0 - 64, x0),
+        # and x1 is a place to copy this data;
+        # x18 contains number of bytes to be stored minus 128
+
+        # Exactly 16 instructions from p2align, so dw_loop starts from cache line boundary
+        # Checking it explictly by aligning with "hlt 1000" instructions 
+.p2alignl  6, 0xd4407d00
+dw_loop:
+        prfm    pldl1keep,  [x0, #64]
+        # Next line actually hurted memory copy performance (for interpreter) - JDK-8078120
+        # prfm    pstl1keep,  [x1, #64]
+
+        subs    x18, x18, #64
+
+        stp     x3,  x4,  [x1, #0]
+        ldp     x3,  x4,  [x0, #0]
+        stp     x5,  x6,  [x1, #16]
+        ldp     x5,  x6,  [x0, #16]
+        stp     x7,  x8,  [x1, #32]
+        ldp     x7,  x8,  [x0, #32]
+        stp     x9,  x10, [x1, #48]
+        ldp     x9,  x10, [x0, #48]
+        
+        add     x1,  x1,  #64
+        add     x0,  x0,  #64
+
+        b.ge    dw_loop
+
+        # 13 instructions from dw_loop, so the loop body hits into one cache line
+
+dw_loop_end:
+        adds    x2,  x18, #64
+
+        stp     x3,  x4,  [x1], #64
+        stp     x5,  x6,  [x1, #-48]
+        stp     x7,  x8,  [x1, #-32]
+        stp     x9,  x10, [x1, #-16]
+
+        # Increased x18 by 64, but stored 64 bytes, so x2 contains exact number of bytes to be stored
+
+        # If this number is not zero, also copy remaining bytes
+        b.ne    dw_lt_128
+        ret
+
+
+        # Support for void Copy::conjoint_words(void* from,
+        #                                       void* to,
+        #                                       size_t count)
+_Copy_conjoint_words:
+        subs    x3, x1, x0
+        # hi condition is met <=> from < to
+        ccmp    x2, x3, #0, hi
+        # hi condition is met <=> (from < to) and (to - from < count)
+        # otherwise _Copy_disjoint_words may be used, because it performs forward copying,
+        # so it also works when ranges overlap but to <= from
+        b.ls    _Copy_disjoint_words
+
+        # Overlapping case should be the rare one, it does not worth optimizing
+
+        ands    x3,  x2,  #~8
+        # x3 is count aligned down by 2*wordSize
+        add     x0,  x0,  x2
+        add     x1,  x1,  x2
+        sub     x3,  x3,  #16
+        # Skip loop if 0 or 1 words
+        b.eq    cw_backward_loop_end
+
+        # x3 >= 0
+        # Copy [x0 - x3 - 16, x0) to [x1 - x3 - 16, x1) backward
+cw_backward_loop:
+        subs    x3,  x3,  #16
+        ldp     x4,  x5,  [x0, #-16]!
+        stp     x4,  x5,  [x1, #-16]!
+        b.ge    cw_backward_loop
+
+cw_backward_loop_end:
+        # Copy remaining 0 or 1 words
+        tbz     x2,  #3,  cw_finish
+        ldr     x3, [x0, #-8]
+        str     x3, [x1, #-8]
+
+cw_finish:
+        ret
+
+
+        # Support for void Copy::conjoint_jshorts_atomic(void* from,
+        #                                                void* to,
+        #                                                size_t count)
+_Copy_conjoint_jshorts_atomic:
+        add     x17, x0, x2
+        add     x18, x1, x2
+
+        subs    x3, x1, x0
+        # hi is met <=> (from < to) and (to - from < count)
+        ccmp    x2, x3, #0, hi
+        b.hi    cs_backward
+        
+        subs    x3, x2, #14
+        b.ge    cs_forward_loop
+
+        # Copy x2 < 14 bytes from x0 to x1
+cs_forward_lt14:
+        ands    x7, x2, #7
+        tbz     x2, #3, cs_forward_lt8
+        ldrh    w3, [x0, #0]
+        ldrh    w4, [x0, #2]
+        ldrh    w5, [x0, #4]
+        ldrh    w6, [x0, #6]
+
+        strh    w3, [x1, #0]
+        strh    w4, [x1, #2]
+        strh    w5, [x1, #4]
+        strh    w6, [x1, #6]
+
+        # Copy x7 < 8 bytes from x17 - x7 to x18 - x7
+cs_forward_lt8:
+        b.eq    cs_forward_0
+        cmp     x7, #4
+        b.lt    cs_forward_2
+        b.eq    cs_forward_4
+
+cs_forward_6:
+        ldrh    w3, [x17, #-6]
+        strh    w3, [x18, #-6]
+cs_forward_4:
+        ldrh    w4, [x17, #-4]
+        strh    w4, [x18, #-4]
+cs_forward_2:
+        ldrh    w5, [x17, #-2]
+        strh    w5, [x18, #-2]
+cs_forward_0:
+        ret
+
+
+        # Copy [x0, x0 + x3 + 14) to [x1, x1 + x3 + 14)
+        # x3 >= 0
+.p2align 6
+cs_forward_loop:
+        subs    x3, x3, #14
+        
+        ldrh    w4, [x0], #14
+        ldrh    w5, [x0, #-12]
+        ldrh    w6, [x0, #-10]
+        ldrh    w7, [x0, #-8]
+        ldrh    w8, [x0, #-6]
+        ldrh    w9, [x0, #-4]
+        ldrh    w10, [x0, #-2]
+
+        strh    w4, [x1], #14
+        strh    w5, [x1, #-12]
+        strh    w6, [x1, #-10]
+        strh    w7, [x1, #-8]
+        strh    w8, [x1, #-6]
+        strh    w9, [x1, #-4]
+        strh    w10, [x1, #-2]
+
+        b.ge    cs_forward_loop
+        # Exactly 16 instruction from cs_forward_loop, so loop fits into one cache line
+
+        adds    x2, x3, #14
+        # x2 bytes should be copied from x0 to x1
+        b.ne    cs_forward_lt14
+        ret
+        
+        # Very similar to forward copying
+cs_backward:
+        subs    x3, x2, #14
+        b.ge    cs_backward_loop
+
+cs_backward_lt14:
+        ands    x7, x2, #7
+        tbz     x2, #3, cs_backward_lt8
+
+        ldrh    w3, [x17, #-8]
+        ldrh    w4, [x17, #-6]
+        ldrh    w5, [x17, #-4]
+        ldrh    w6, [x17, #-2]
+        
+        strh    w3, [x18, #-8]
+        strh    w4, [x18, #-6]
+        strh    w5, [x18, #-4]
+        strh    w6, [x18, #-2]
+
+cs_backward_lt8:
+        b.eq    cs_backward_0
+        cmp     x7, #4
+        b.lt    cs_backward_2
+        b.eq    cs_backward_4
+
+cs_backward_6:
+        ldrh    w3, [x0, #4]
+        strh    w3, [x1, #4]
+
+cs_backward_4:
+        ldrh    w4, [x0, #2]
+        strh    w4, [x1, #2]
+
+cs_backward_2:
+        ldrh    w5, [x0, #0]
+        strh    w5, [x1, #0]
+
+cs_backward_0:
+        ret
+
+
+.p2align 6
+cs_backward_loop:
+        subs    x3, x3, #14
+
+        ldrh    w4, [x17, #-14]!
+        ldrh    w5, [x17, #2]
+        ldrh    w6, [x17, #4]
+        ldrh    w7, [x17, #6]
+        ldrh    w8, [x17, #8]
+        ldrh    w9, [x17, #10]
+        ldrh    w10, [x17, #12]
+
+        strh    w4, [x18, #-14]!
+        strh    w5, [x18, #2]
+        strh    w6, [x18, #4]
+        strh    w7, [x18, #6]
+        strh    w8, [x18, #8]
+        strh    w9, [x18, #10]
+        strh    w10, [x18, #12]
+
+        b.ge    cs_backward_loop
+        adds    x2, x3, #14
+        b.ne    cs_backward_lt14
+        ret
+
+
+        # Support for void Copy::arrayof_conjoint_jshorts(void* from,
+        #                                                 void* to,
+        #                                                 size_t count)
+_Copy_arrayof_conjoint_jshorts:
+        hlt 1007
+
+
+        # Support for void Copy::conjoint_jlongs_atomic(jlong* from,
+        #                                               jlong* to,
+        #                                               size_t count)
+_Copy_conjoint_jlongs_atomic:
+_Copy_arrayof_conjoint_jlongs:
+        hlt 1009
+
+
+        # Support for void Copy::conjoint_jints_atomic(void* from,
+        #                                              void* to,
+        #                                              size_t count)
+_Copy_conjoint_jints_atomic:
+_Copy_arrayof_conjoint_jints:
+        # These and further memory prefetches may hit out of array ranges.
+        # Experiments showed that prefetching of inaccessible memory doesn't result in exceptions.
+        prfm    pldl1keep,  [x0, #0]
+        prfm    pstl1keep,  [x1, #0]
+        prfm    pldl1keep,  [x0, #32]
+        prfm    pstl1keep,  [x1, #32]
+
+        subs    x3, x1, x0
+        # hi condition is met <=> from < to
+        ccmp    x2, x3, #0, hi
+        # hi condition is met <=> (from < to) and (to - from < count)
+        b.hi    ci_backward
+
+        subs    x18, x2,  #64
+        b.ge    ci_forward_large
+
+ci_forward_lt_64:
+        # Copy [x0, x0 + x2) to [x1, x1 + x2)
+        
+        adr     x15,  ci_forward_tail_table_base
+        and     x16,  x2,  #~4
+
+        # Calculate address to jump and store it to x15:
+        #   Each pair of instructions before ci_forward_tail_table_base copies 8 bytes.
+        #   x16 is count of bytes to copy aligned down by 8.
+        #   So x16/8 pairs of instructions should be executed. 
+        #   Each pair takes 8 bytes, so x15 = ci_forward_tail_table_base - (x16/8)*8 = x15 - x16
+        sub     x15,  x15, x16
+        prfm    plil1keep, [x15]
+    
+        add     x17,  x0,  x2
+        add     x18,  x1,  x2
+
+        # If x2 = x16 + 4, then copy 4 bytes and x16 bytes after that.
+        # Otherwise x2 = x16, so proceed to copy x16 bytes.
+        tbz     x2, #2, ci_forward_lt_64_even
+        ldr     w3, [x0]
+        str     w3, [x1]
+ci_forward_lt_64_even:
+        # Copy [x17 - x16, x17) to [x18 - x16, x18)
+        # x16 is aligned by 8 and less than 64
+
+        # Execute (x16/8) ldp-stp pairs; each pair copies 8 bytes
+        br      x15
+
+        ldp     w3,  w4,  [x17, #-56]
+        stp     w3,  w4,  [x18, #-56]
+        ldp     w5,  w6,  [x17, #-48]
+        stp     w5,  w6,  [x18, #-48]
+        ldp     w7,  w8,  [x17, #-40]
+        stp     w7,  w8,  [x18, #-40]
+        ldp     w9,  w10, [x17, #-32]
+        stp     w9,  w10, [x18, #-32]
+        ldp     w11, w12, [x17, #-24]
+        stp     w11, w12, [x18, #-24]
+        ldp     w13, w14, [x17, #-16]
+        stp     w13, w14, [x18, #-16]
+        ldp     w15, w16, [x17, #-8]
+        stp     w15, w16, [x18, #-8]
+ci_forward_tail_table_base:
+        ret
+
+.p2align  6
+.rept   12
+        nop
+.endr
+ci_forward_large:
+        # x18 >= 0;
+        # Copy [x0, x0 + x18 + 64) to [x1, x1 + x18 + 64)
+
+        ldp     w3,  w4,  [x0], #32
+        ldp     w5,  w6,  [x0, #-24]
+        ldp     w7,  w8,  [x0, #-16]
+        ldp     w9,  w10, [x0, #-8]
+
+        # Before and after each iteration of loop registers w3-w10 contain [x0 - 32, x0),
+        # and x1 is a place to copy this data;
+        # x18 contains number of bytes to be stored minus 64
+
+        # Exactly 16 instructions from p2align, so ci_forward_loop starts from cache line boundary
+        # Checking it explictly by aligning with "hlt 1000" instructions 
+.p2alignl  6, 0xd4407d00
+ci_forward_loop:
+        prfm    pldl1keep,  [x0, #32]
+        prfm    pstl1keep,  [x1, #32]
+
+        subs    x18, x18, #32
+
+        stp     w3,  w4,  [x1, #0]
+        ldp     w3,  w4,  [x0, #0]
+        stp     w5,  w6,  [x1, #8]
+        ldp     w5,  w6,  [x0, #8]
+        stp     w7,  w8,  [x1, #16]
+        ldp     w7,  w8,  [x0, #16]
+        stp     w9,  w10, [x1, #24]
+        ldp     w9,  w10, [x0, #24]
+        
+        add     x1,  x1,  #32
+        add     x0,  x0,  #32
+
+        b.ge    ci_forward_loop
+
+        # 14 instructions from ci_forward_loop, so the loop body hits into one cache line
+
+ci_forward_loop_end:
+        adds    x2,  x18, #32
+
+        stp     w3,  w4,  [x1], #32
+        stp     w5,  w6,  [x1, #-24]
+        stp     w7,  w8,  [x1, #-16]
+        stp     w9,  w10, [x1, #-8]
+
+        # Increased x18 by 32, but stored 32 bytes, so x2 contains exact number of bytes to be stored
+
+        # If this number is not zero, also copy remaining bytes
+        b.ne    ci_forward_lt_64
+        ret
+
+ci_backward:
+
+        # Overlapping case should be the rare one, it does not worth optimizing
+
+        ands    x3,  x2,  #~4
+        # x3 is count aligned down by 2*jintSize
+        add     x0,  x0,  x2
+        add     x1,  x1,  x2
+        sub     x3,  x3,  #8
+        # Skip loop if 0 or 1 jints
+        b.eq    ci_backward_loop_end
+
+        # x3 >= 0
+        # Copy [x0 - x3 - 8, x0) to [x1 - x3 - 8, x1) backward
+ci_backward_loop:
+        subs    x3,  x3,  #8
+        ldp     w4,  w5,  [x0, #-8]!
+        stp     w4,  w5,  [x1, #-8]!
+        b.ge    ci_backward_loop
+
+ci_backward_loop_end:
+        # Copy remaining 0 or 1 jints
+        tbz     x2,  #2,  ci_backward_finish
+        ldr     w3, [x0, #-4]
+        str     w3, [x1, #-4]
+
+ci_backward_finish:
+        ret
diff --git a/hotspot/src/os_cpu/linux_arm/vm/macroAssembler_linux_arm_32.cpp b/hotspot/src/os_cpu/linux_arm/vm/macroAssembler_linux_arm_32.cpp
new file mode 100644
index 0000000..f29096f
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/macroAssembler_linux_arm_32.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "runtime/os.hpp"
+
+void MacroAssembler::breakpoint(AsmCondition cond) {
+  if (cond == al) {
+    emit_int32(0xe7f001f0);
+  } else {
+    call(CAST_FROM_FN_PTR(address, os::breakpoint), relocInfo::runtime_call_type, cond);
+  }
+}
+
+// atomic_cas_bool
+//
+// Perform an atomic compare and exchange and return bool result
+//
+// inputs:
+//         oldval value to compare to
+//         newval value to store if *(base+offset) == oldval
+//         base   base address of storage location
+//         offset offset added to base to form dest address
+// output:
+//         Z flag is set in success
+
+void MacroAssembler::atomic_cas_bool(Register oldval, Register newval, Register base, int offset, Register tmpreg) {
+  if (VM_Version::supports_ldrex()) {
+    Register tmp_reg;
+    if (tmpreg == noreg) {
+      push(LR);
+      tmp_reg = LR;
+    } else {
+      tmp_reg = tmpreg;
+    }
+    assert_different_registers(tmp_reg, oldval, newval, base);
+    Label loop;
+    bind(loop);
+    ldrex(tmp_reg, Address(base, offset));
+    subs(tmp_reg, tmp_reg, oldval);
+    strex(tmp_reg, newval, Address(base, offset), eq);
+    cmp(tmp_reg, 1, eq);
+    b(loop, eq);
+    cmp(tmp_reg, 0);
+    if (tmpreg == noreg) {
+      pop(tmp_reg);
+    }
+  } else if (VM_Version::supports_kuser_cmpxchg32()) {
+    // On armv5 platforms we must use the Linux kernel helper
+    // function for atomic cas operations since ldrex/strex is
+    // not supported.
+    //
+    // This is a special routine at a fixed address 0xffff0fc0 with
+    // with these arguments and results
+    //
+    // input:
+    //  r0 = oldval, r1 = newval, r2 = ptr, lr = return adress
+    // output:
+    //  r0 = 0 carry set on success
+    //  r0 != 0 carry clear on failure
+    //
+    // r3, ip and flags are clobbered
+    //
+
+    Label loop;
+
+    push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR));
+
+    Register tmp_reg = LR; // ignore the argument
+
+    assert_different_registers(tmp_reg, oldval, newval, base);
+
+    // Shuffle registers for kernel call
+    if (oldval != R0) {
+      if (newval == R0) {
+        mov(tmp_reg, newval);
+        newval = tmp_reg;
+      }
+      if (base == R0) {
+        mov(tmp_reg, base);
+        base = tmp_reg;
+      }
+      mov(R0, oldval);
+    }
+    if(newval != R1) {
+      if(base == R1) {
+        if(newval == R2) {
+          mov(tmp_reg, base);
+          base = tmp_reg;
+        }
+        else {
+          mov(R2, base);
+          base = R2;
+        }
+      }
+      mov(R1, newval);
+    }
+    if (base != R2)
+      mov(R2, base);
+
+    if (offset != 0)
+      add(R2, R2, offset);
+
+    mvn(R3, 0xf000);
+    mov(LR, PC);
+    sub(PC, R3, 0x3f);
+    cmp (R0, 0);
+
+    pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(LR));
+  } else {
+    // Should never run on a platform so old that it does not have kernel helper
+    stop("Atomic cmpxchg32 unsupported on this platform");
+  }
+}
+
+// atomic_cas
+//
+// Perform an atomic compare and exchange and return previous value
+//
+// inputs:
+//         prev temporary register (destroyed)
+//         oldval value to compare to
+//         newval value to store if *(base+offset) == oldval
+//         base   base address of storage location
+//         offset offset added to base to form dest address
+// output:
+//         returns previous value from *(base+offset) in R0
+
+void MacroAssembler::atomic_cas(Register temp1, Register temp2, Register oldval, Register newval, Register base, int offset) {
+  if (temp1 != R0) {
+    // try to read the previous value directly in R0
+    if (temp2 == R0) {
+      // R0 declared free
+      temp2 = temp1;
+      temp1 = R0;
+    } else if ((oldval != R0) && (newval != R0) && (base != R0)) {
+      // free, and scratched on return
+      temp1 = R0;
+    }
+  }
+  if (VM_Version::supports_ldrex()) {
+    Label loop;
+    assert_different_registers(temp1, temp2, oldval, newval, base);
+
+    bind(loop);
+    ldrex(temp1, Address(base, offset));
+    cmp(temp1, oldval);
+    strex(temp2, newval, Address(base, offset), eq);
+    cmp(temp2, 1, eq);
+    b(loop, eq);
+    if (temp1 != R0) {
+      mov(R0, temp1);
+    }
+  } else if (VM_Version::supports_kuser_cmpxchg32()) {
+    // On armv5 platforms we must use the Linux kernel helper
+    // function for atomic cas operations since ldrex/strex is
+    // not supported.
+    //
+    // This is a special routine at a fixed address 0xffff0fc0
+    //
+    // input:
+    //  r0 = oldval, r1 = newval, r2 = ptr, lr = return adress
+    // output:
+    //  r0 = 0 carry set on success
+    //  r0 != 0 carry clear on failure
+    //
+    // r3, ip and flags are clobbered
+    //
+    Label done;
+    Label loop;
+
+    push(RegisterSet(R1, R4) | RegisterSet(R12) | RegisterSet(LR));
+
+    if ( oldval != R0 || newval != R1 || base != R2 ) {
+      push(oldval);
+      push(newval);
+      push(base);
+      pop(R2);
+      pop(R1);
+      pop(R0);
+    }
+
+    if (offset != 0) {
+      add(R2, R2, offset);
+    }
+
+    mov(R4, R0);
+    bind(loop);
+    ldr(R0, Address(R2));
+    cmp(R0, R4);
+    b(done, ne);
+    mvn(R12, 0xf000);
+    mov(LR, PC);
+    sub(PC, R12, 0x3f);
+    b(loop, cc);
+    mov(R0, R4);
+    bind(done);
+
+    pop(RegisterSet(R1, R4) | RegisterSet(R12) | RegisterSet(LR));
+  } else {
+    // Should never run on a platform so old that it does not have kernel helper
+    stop("Atomic cmpxchg32 unsupported on this platform");
+  }
+}
+
+// atomic_cas64
+//
+// Perform a 64 bit atomic compare and exchange and return previous value
+// as well as returning status in 'result' register
+//
+// inputs:
+//         oldval_lo, oldval_hi value to compare to
+//         newval_lo, newval_hi value to store if *(base+offset) == oldval
+//         base   base address of storage location
+//         offset offset added to base to form dest address
+// output:
+//         memval_lo, memval_hi, result
+//         returns previous value from *(base+offset) in memval_lo/hi
+//         returns status in result, 1==success, 0==failure
+//         C1 just uses status result
+//         VM code uses previous value returned in memval_lo/hi
+
+void MacroAssembler::atomic_cas64(Register memval_lo, Register memval_hi, Register result, Register oldval_lo, Register oldval_hi, Register newval_lo, Register newval_hi, Register base, int offset) {
+  if (VM_Version::supports_ldrexd()) {
+    Label loop;
+    assert_different_registers(memval_lo, memval_hi, result, oldval_lo,
+                               oldval_hi, newval_lo, newval_hi, base);
+    assert(memval_hi == memval_lo + 1 && memval_lo < R9, "cmpxchg_long: illegal registers");
+    assert(oldval_hi == oldval_lo + 1 && oldval_lo < R9, "cmpxchg_long: illegal registers");
+    assert(newval_hi == newval_lo + 1 && newval_lo < R9, "cmpxchg_long: illegal registers");
+    assert(result != R10, "cmpxchg_long: illegal registers");
+    assert(base != R10, "cmpxchg_long: illegal registers");
+
+    mov(result, 0);
+    bind(loop);
+    ldrexd(memval_lo, Address(base, offset));
+    cmp(memval_lo, oldval_lo);
+    cmp(memval_hi, oldval_hi, eq);
+    strexd(result, newval_lo, Address(base, offset), eq);
+    rsbs(result, result, 1, eq);
+    b(loop, eq);
+  } else if (VM_Version::supports_kuser_cmpxchg64()) {
+    // On armv5 platforms we must use the Linux kernel helper
+    // function for atomic cas64 operations since ldrexd/strexd is
+    // not supported.
+    //
+    // This is a special routine at a fixed address 0xffff0f60
+    //
+    // input:
+    //  r0 = (long long *)oldval, r1 = (long long *)newval,
+    //  r2 = ptr, lr = return adress
+    // output:
+    //  r0 = 0 carry set on success
+    //  r0 != 0 carry clear on failure
+    //
+    // r3, and flags are clobbered
+    //
+    Label done;
+    Label loop;
+
+    if (result != R12) {
+      push(R12);
+    }
+    push(RegisterSet(R10) | RegisterSet(LR));
+    mov(R10, SP);         // Save SP
+
+    bic(SP, SP, StackAlignmentInBytes - 1);  // align stack
+    push(RegisterSet(oldval_lo, oldval_hi));
+    push(RegisterSet(newval_lo, newval_hi));
+
+    if ((offset != 0) || (base != R12)) {
+      add(R12, base, offset);
+    }
+    push(RegisterSet(R0, R3));
+    bind(loop);
+    ldrd(memval_lo, Address(R12)); //current
+    ldrd(oldval_lo, Address(SP, 24));
+    cmp(memval_lo, oldval_lo);
+    cmp(memval_hi, oldval_hi, eq);
+    pop(RegisterSet(R0, R3), ne);
+    mov(result, 0, ne);
+    b(done, ne);
+    // Setup for kernel call
+    mov(R2, R12);
+    add(R0, SP, 24);            // R0 == &oldval_lo
+    add(R1, SP, 16);            // R1 == &newval_lo
+    mvn(R3, 0xf000);            // call kernel helper at 0xffff0f60
+    mov(LR, PC);
+    sub(PC, R3, 0x9f);
+    b(loop, cc);                 // if Carry clear then oldval != current
+                                 // try again. Otherwise, return oldval
+    // Here on success
+    pop(RegisterSet(R0, R3));
+    mov(result, 1);
+    ldrd(memval_lo, Address(SP, 8));
+    bind(done);
+    pop(RegisterSet(newval_lo, newval_hi));
+    pop(RegisterSet(oldval_lo, oldval_hi));
+    mov(SP, R10);                 // restore SP
+    pop(RegisterSet(R10) | RegisterSet(LR));
+    if (result != R12) {
+      pop(R12);
+    }
+  } else {
+    stop("Atomic cmpxchg64 unsupported on this platform");
+  }
+}
diff --git a/hotspot/src/os_cpu/linux_arm/vm/orderAccess_linux_arm.inline.hpp b/hotspot/src/os_cpu/linux_arm/vm/orderAccess_linux_arm.inline.hpp
new file mode 100644
index 0000000..67e32a8
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/orderAccess_linux_arm.inline.hpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_ORDERACCESS_LINUX_ARM_INLINE_HPP
+#define OS_CPU_LINUX_ARM_VM_ORDERACCESS_LINUX_ARM_INLINE_HPP
+
+#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
+#include "vm_version_arm.hpp"
+
+// Implementation of class OrderAccess.
+// - we define the high level barriers below and use the general
+//   implementation in orderAccess.inline.hpp, with customizations
+//   on AARCH64 via the specialized_* template functions
+#define VM_HAS_GENERALIZED_ORDER_ACCESS 1
+
+// Memory Ordering on ARM is weak.
+//
+// Implement all 4 memory ordering barriers by DMB, since it is a
+// lighter version of DSB.
+// dmb_sy implies full system shareability domain. RD/WR access type.
+// dmb_st implies full system shareability domain. WR only access type.
+//
+// NOP on < ARMv6 (MP not supported)
+//
+// Non mcr instructions can be used if we build for armv7 or higher arch
+//    __asm__ __volatile__ ("dmb" : : : "memory");
+//    __asm__ __volatile__ ("dsb" : : : "memory");
+//
+// inline void _OrderAccess_dsb() {
+//    volatile intptr_t dummy = 0;
+//    if (os::is_MP()) {
+//      __asm__ volatile (
+//        "mcr p15, 0, %0, c7, c10, 4"
+//        : : "r" (dummy) : "memory");
+//   }
+// }
+
+inline static void dmb_sy() {
+   if (!os::is_MP()) {
+     return;
+   }
+#ifdef AARCH64
+   __asm__ __volatile__ ("dmb sy" : : : "memory");
+#else
+   if (VM_Version::arm_arch() >= 7) {
+#ifdef __thumb__
+     __asm__ volatile (
+     "dmb sy": : : "memory");
+#else
+     __asm__ volatile (
+     ".word 0xF57FF050 | 0xf" : : : "memory");
+#endif
+   } else {
+     intptr_t zero = 0;
+     __asm__ volatile (
+       "mcr p15, 0, %0, c7, c10, 5"
+       : : "r" (zero) : "memory");
+   }
+#endif
+}
+
+inline static void dmb_st() {
+   if (!os::is_MP()) {
+     return;
+   }
+#ifdef AARCH64
+   __asm__ __volatile__ ("dmb st" : : : "memory");
+#else
+   if (VM_Version::arm_arch() >= 7) {
+#ifdef __thumb__
+     __asm__ volatile (
+     "dmb st": : : "memory");
+#else
+     __asm__ volatile (
+     ".word 0xF57FF050 | 0xe" : : : "memory");
+#endif
+   } else {
+     intptr_t zero = 0;
+     __asm__ volatile (
+       "mcr p15, 0, %0, c7, c10, 5"
+       : : "r" (zero) : "memory");
+   }
+#endif
+}
+
+// Load-Load/Store barrier
+inline static void dmb_ld() {
+#ifdef AARCH64
+   if (!os::is_MP()) {
+     return;
+   }
+   __asm__ __volatile__ ("dmb ld" : : : "memory");
+#else
+   dmb_sy();
+#endif
+}
+
+
+inline void OrderAccess::loadload()   { dmb_ld(); }
+inline void OrderAccess::loadstore()  { dmb_ld(); }
+inline void OrderAccess::acquire()    { dmb_ld(); }
+inline void OrderAccess::storestore() { dmb_st(); }
+inline void OrderAccess::storeload()  { dmb_sy(); }
+inline void OrderAccess::release()    { dmb_sy(); }
+inline void OrderAccess::fence()      { dmb_sy(); }
+
+// specializations for Aarch64
+// TODO-AARCH64: evaluate effectiveness of ldar*/stlr* implementations compared to 32-bit ARM approach
+
+#ifdef AARCH64
+
+template<> inline jbyte    OrderAccess::specialized_load_acquire<jbyte>(volatile jbyte*   p) {
+  volatile jbyte result;
+  __asm__ volatile(
+    "ldarb %w[res], [%[ptr]]"
+    : [res] "=&r" (result)
+    : [ptr] "r" (p)
+    : "memory");
+  return result;
+}
+
+template<> inline jshort   OrderAccess::specialized_load_acquire<jshort>(volatile jshort*  p) {
+  volatile jshort result;
+  __asm__ volatile(
+    "ldarh %w[res], [%[ptr]]"
+    : [res] "=&r" (result)
+    : [ptr] "r" (p)
+    : "memory");
+  return result;
+}
+
+template<> inline jint     OrderAccess::specialized_load_acquire<jint>(volatile jint*    p) {
+  volatile jint result;
+  __asm__ volatile(
+    "ldar %w[res], [%[ptr]]"
+    : [res] "=&r" (result)
+    : [ptr] "r" (p)
+    : "memory");
+  return result;
+}
+
+template<> inline jfloat   OrderAccess::specialized_load_acquire<jfloat>(volatile jfloat*  p) {
+  return jfloat_cast(specialized_load_acquire((volatile jint*)p));
+}
+
+// This is implicit as jlong and intptr_t are both "long int"
+//template<> inline jlong    OrderAccess::specialized_load_acquire(volatile jlong*   p) {
+//  return (volatile jlong)specialized_load_acquire((volatile intptr_t*)p);
+//}
+
+template<> inline intptr_t OrderAccess::specialized_load_acquire<intptr_t>(volatile intptr_t*   p) {
+  volatile intptr_t result;
+  __asm__ volatile(
+    "ldar %[res], [%[ptr]]"
+    : [res] "=&r" (result)
+    : [ptr] "r" (p)
+    : "memory");
+  return result;
+}
+
+template<> inline jdouble  OrderAccess::specialized_load_acquire<jdouble>(volatile jdouble* p) {
+  return jdouble_cast(specialized_load_acquire((volatile intptr_t*)p));
+}
+
+
+template<> inline void     OrderAccess::specialized_release_store<jbyte>(volatile jbyte*   p, jbyte   v) {
+  __asm__ volatile(
+    "stlrb %w[val], [%[ptr]]"
+    :
+    : [ptr] "r" (p), [val] "r" (v)
+    : "memory");
+}
+
+template<> inline void     OrderAccess::specialized_release_store<jshort>(volatile jshort*  p, jshort  v) {
+  __asm__ volatile(
+    "stlrh %w[val], [%[ptr]]"
+    :
+    : [ptr] "r" (p), [val] "r" (v)
+    : "memory");
+}
+
+template<> inline void     OrderAccess::specialized_release_store<jint>(volatile jint*    p, jint    v) {
+  __asm__ volatile(
+    "stlr %w[val], [%[ptr]]"
+    :
+    : [ptr] "r" (p), [val] "r" (v)
+    : "memory");
+}
+
+template<> inline void     OrderAccess::specialized_release_store<jlong>(volatile jlong*   p, jlong   v) {
+  __asm__ volatile(
+    "stlr %[val], [%[ptr]]"
+    :
+    : [ptr] "r" (p), [val] "r" (v)
+    : "memory");
+}
+#endif // AARCH64
+
+#endif // OS_CPU_LINUX_ARM_VM_ORDERACCESS_LINUX_ARM_INLINE_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp b/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp
new file mode 100644
index 0000000..594a170
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp
@@ -0,0 +1,804 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "assembler_arm.inline.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "jvm_linux.h"
+#include "memory/allocation.inline.hpp"
+#include "nativeInst_arm.hpp"
+#include "os_share_linux.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm.h"
+#include "prims/jvm_misc.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/extendedPC.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/java.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/timer.hpp"
+#include "utilities/events.hpp"
+#include "utilities/vmError.hpp"
+
+// put OS-includes here
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <pthread.h>
+# include <signal.h>
+# include <errno.h>
+# include <dlfcn.h>
+# include <stdlib.h>
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/resource.h>
+# include <pthread.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/utsname.h>
+# include <sys/socket.h>
+# include <sys/wait.h>
+# include <pwd.h>
+# include <poll.h>
+# include <ucontext.h>
+# include <fpu_control.h>
+# include <asm/ptrace.h>
+
+#define SPELL_REG_SP  "sp"
+
+// Don't #define SPELL_REG_FP for thumb because it is not safe to use, so this makes sure we never fetch it.
+#ifndef __thumb__
+#define SPELL_REG_FP  AARCH64_ONLY("x29") NOT_AARCH64("fp")
+#endif
+
+address os::current_stack_pointer() {
+  register address sp __asm__ (SPELL_REG_SP);
+  return sp;
+}
+
+char* os::non_memory_address_word() {
+  // Must never look like an address returned by reserve_memory
+  return (char*) -1;
+}
+
+void os::initialize_thread(Thread* thr) {
+  // Nothing to do
+}
+
+#ifdef AARCH64
+
+#define arm_pc pc
+#define arm_sp sp
+#define arm_fp regs[29]
+#define arm_r0 regs[0]
+#define ARM_REGS_IN_CONTEXT  31
+
+#else
+
+#if NGREG == 16
+// These definitions are based on the observation that until
+// the certain version of GCC mcontext_t was defined as
+// a structure containing gregs[NGREG] array with 16 elements.
+// In later GCC versions mcontext_t was redefined as struct sigcontext,
+// along with NGREG constant changed to 18.
+#define arm_pc gregs[15]
+#define arm_sp gregs[13]
+#define arm_fp gregs[11]
+#define arm_r0 gregs[0]
+#endif
+
+#define ARM_REGS_IN_CONTEXT  16
+
+#endif // AARCH64
+
+address os::Linux::ucontext_get_pc(const ucontext_t* uc) {
+  return (address)uc->uc_mcontext.arm_pc;
+}
+
+void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
+  uc->uc_mcontext.arm_pc = (uintx)pc;
+}
+
+intptr_t* os::Linux::ucontext_get_sp(const ucontext_t* uc) {
+  return (intptr_t*)uc->uc_mcontext.arm_sp;
+}
+
+intptr_t* os::Linux::ucontext_get_fp(const ucontext_t* uc) {
+  return (intptr_t*)uc->uc_mcontext.arm_fp;
+}
+
+bool is_safe_for_fp(address pc) {
+#ifdef __thumb__
+  if (CodeCache::find_blob(pc) != NULL) {
+    return true;
+  }
+  // For thumb C frames, given an fp we have no idea how to access the frame contents.
+  return false;
+#else
+  // Calling os::address_is_in_vm() here leads to a dladdr call. Calling any libc
+  // function during os::get_native_stack() can result in a deadlock if JFR is
+  // enabled. For now, be more lenient and allow all pc's. There are other
+  // frame sanity checks in shared code, and to date they have been sufficient
+  // for other platforms.
+  //return os::address_is_in_vm(pc);
+  return true;
+#endif
+}
+
+// For Forte Analyzer AsyncGetCallTrace profiling support - thread
+// is currently interrupted by SIGPROF.
+// os::Solaris::fetch_frame_from_ucontext() tries to skip nested signal
+// frames. Currently we don't do that on Linux, so it's the same as
+// os::fetch_frame_from_context().
+ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
+  const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
+
+  assert(thread != NULL, "just checking");
+  assert(ret_sp != NULL, "just checking");
+  assert(ret_fp != NULL, "just checking");
+
+  return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
+}
+
+ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
+                    intptr_t** ret_sp, intptr_t** ret_fp) {
+
+  ExtendedPC  epc;
+  const ucontext_t* uc = (const ucontext_t*)ucVoid;
+
+  if (uc != NULL) {
+    epc = ExtendedPC(os::Linux::ucontext_get_pc(uc));
+    if (ret_sp) *ret_sp = os::Linux::ucontext_get_sp(uc);
+    if (ret_fp) {
+      intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+#ifndef __thumb__
+      if (CodeCache::find_blob(epc.pc()) == NULL) {
+        // It's a C frame. We need to adjust the fp.
+        fp += os::C_frame_offset;
+      }
+#endif
+      // Clear FP when stack walking is dangerous so that
+      // the frame created will not be walked.
+      // However, ensure FP is set correctly when reliable and
+      // potentially necessary.
+      if (!is_safe_for_fp(epc.pc())) {
+        // FP unreliable
+        fp = (intptr_t *)NULL;
+      }
+      *ret_fp = fp;
+    }
+  } else {
+    // construct empty ExtendedPC for return value checking
+    epc = ExtendedPC(NULL);
+    if (ret_sp) *ret_sp = (intptr_t *)NULL;
+    if (ret_fp) *ret_fp = (intptr_t *)NULL;
+  }
+
+  return epc;
+}
+
+frame os::fetch_frame_from_context(const void* ucVoid) {
+  intptr_t* sp;
+  intptr_t* fp;
+  ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
+  return frame(sp, fp, epc.pc());
+}
+
+frame os::get_sender_for_C_frame(frame* fr) {
+#ifdef __thumb__
+  // We can't reliably get anything from a thumb C frame.
+  return frame();
+#else
+  address pc = fr->sender_pc();
+  if (! is_safe_for_fp(pc)) {
+    return frame(fr->sender_sp(), (intptr_t *)NULL, pc);
+  } else {
+    return frame(fr->sender_sp(), fr->link() + os::C_frame_offset, pc);
+  }
+#endif
+}
+
+//
+// This actually returns two frames up. It does not return os::current_frame(),
+// which is the actual current frame. Nor does it return os::get_native_stack(),
+// which is the caller. It returns whoever called os::get_native_stack(). Not
+// very intuitive, but consistent with how this API is implemented on other
+// platforms.
+//
+frame os::current_frame() {
+#ifdef __thumb__
+  // We can't reliably get anything from a thumb C frame.
+  return frame();
+#else
+  register intptr_t* fp __asm__ (SPELL_REG_FP);
+  // fp is for os::current_frame. We want the fp for our caller.
+  frame myframe((intptr_t*)os::current_stack_pointer(), fp + os::C_frame_offset,
+                 CAST_FROM_FN_PTR(address, os::current_frame));
+  frame caller_frame = os::get_sender_for_C_frame(&myframe);
+
+  if (os::is_first_C_frame(&caller_frame)) {
+    // stack is not walkable
+    // Assert below was added because it does not seem like this can ever happen.
+    // How can this frame ever be the first C frame since it is called from C code?
+    // If it does ever happen, undo the assert and comment here on when/why it happens.
+    assert(false, "this should never happen");
+    return frame();
+  }
+
+  // return frame for our caller's caller
+  return os::get_sender_for_C_frame(&caller_frame);
+#endif
+}
+
+#ifndef AARCH64
+extern "C" address check_vfp_fault_instr;
+extern "C" address check_vfp3_32_fault_instr;
+
+address check_vfp_fault_instr = NULL;
+address check_vfp3_32_fault_instr = NULL;
+#endif // !AARCH64
+extern "C" address check_simd_fault_instr;
+address check_simd_fault_instr = NULL;
+
+// Utility functions
+
+extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
+                                       void* ucVoid, int abort_if_unrecognized) {
+  ucontext_t* uc = (ucontext_t*) ucVoid;
+
+  Thread* t = Thread::current_or_null_safe();
+
+  // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
+  // (no destructors can be run)
+  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+
+  SignalHandlerMark shm(t);
+
+  if (sig == SIGILL &&
+      ((info->si_addr == (caddr_t)check_simd_fault_instr)
+       NOT_AARCH64(|| info->si_addr == (caddr_t)check_vfp_fault_instr)
+       NOT_AARCH64(|| info->si_addr == (caddr_t)check_vfp3_32_fault_instr))) {
+    // skip faulty instruction + instruction that sets return value to
+    // success and set return value to failure.
+    os::Linux::ucontext_set_pc(uc, (address)info->si_addr + 8);
+    uc->uc_mcontext.arm_r0 = 0;
+    return true;
+  }
+
+  // Note: it's not uncommon that JNI code uses signal/sigset to install
+  // then restore certain signal handler (e.g. to temporarily block SIGPIPE,
+  // or have a SIGILL handler when detecting CPU type). When that happens,
+  // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
+  // avoid unnecessary crash when libjsig is not preloaded, try handle signals
+  // that do not require siginfo/ucontext first.
+
+  if (sig == SIGPIPE || sig == SIGXFSZ) {
+    // allow chained handler to go first
+    if (os::Linux::chained_handler(sig, info, ucVoid)) {
+      return true;
+    } else {
+      // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
+      return true;
+    }
+  }
+
+  JavaThread* thread = NULL;
+  VMThread* vmthread = NULL;
+  if (os::Linux::signal_handlers_are_installed) {
+    if (t != NULL ){
+      if(t->is_Java_thread()) {
+        thread = (JavaThread*)t;
+      }
+      else if(t->is_VM_thread()){
+        vmthread = (VMThread *)t;
+      }
+    }
+  }
+
+  address stub = NULL;
+  address pc = NULL;
+  bool unsafe_access = false;
+
+  if (info != NULL && uc != NULL && thread != NULL) {
+    pc = (address) os::Linux::ucontext_get_pc(uc);
+
+    // Handle ALL stack overflow variations here
+    if (sig == SIGSEGV) {
+      address addr = (address) info->si_addr;
+
+      if (StubRoutines::is_safefetch_fault(pc)) {
+        os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+        return 1;
+      }
+      // check if fault address is within thread stack
+      if (addr < thread->stack_base() &&
+          addr >= thread->stack_base() - thread->stack_size()) {
+        // stack overflow
+        if (thread->in_stack_yellow_reserved_zone(addr)) {
+          thread->disable_stack_yellow_reserved_zone();
+          if (thread->thread_state() == _thread_in_Java) {
+            // Throw a stack overflow exception.  Guard pages will be reenabled
+            // while unwinding the stack.
+            stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
+          } else {
+            // Thread was in the vm or native code.  Return and try to finish.
+            return 1;
+          }
+        } else if (thread->in_stack_red_zone(addr)) {
+          // Fatal red zone violation.  Disable the guard pages and fall through
+          // to handle_unexpected_exception way down below.
+          thread->disable_stack_red_zone();
+          tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
+        } else {
+          // Accessing stack address below sp may cause SEGV if current
+          // thread has MAP_GROWSDOWN stack. This should only happen when
+          // current thread was created by user code with MAP_GROWSDOWN flag
+          // and then attached to VM. See notes in os_linux.cpp.
+          if (thread->osthread()->expanding_stack() == 0) {
+             thread->osthread()->set_expanding_stack();
+             if (os::Linux::manually_expand_stack(thread, addr)) {
+               thread->osthread()->clear_expanding_stack();
+               return 1;
+             }
+             thread->osthread()->clear_expanding_stack();
+          } else {
+             fatal("recursive segv. expanding stack.");
+          }
+        }
+      }
+    }
+
+    if (thread->thread_state() == _thread_in_Java) {
+      // Java thread running in Java code => find exception handler if any
+      // a fault inside compiled code, the interpreter, or a stub
+
+      if (sig == SIGSEGV && os::is_poll_address((address)info->si_addr)) {
+        stub = SharedRuntime::get_poll_stub(pc);
+      } else if (sig == SIGBUS) {
+        // BugId 4454115: A read from a MappedByteBuffer can fault
+        // here if the underlying file has been truncated.
+        // Do not crash the VM in such a case.
+        CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
+        CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
+        if (nm != NULL && nm->has_unsafe_access()) {
+          unsafe_access = true;
+        }
+      } else if (sig == SIGSEGV && !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
+          // Determination of interpreter/vtable stub/compiled code null exception
+          CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
+          if (cb != NULL) {
+            stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+          }
+      } else if (sig == SIGILL && *(int *)pc == NativeInstruction::zombie_illegal_instruction) {
+        // Zombie
+        stub = SharedRuntime::get_handle_wrong_method_stub();
+      }
+    } else if (thread->thread_state() == _thread_in_vm &&
+               sig == SIGBUS && thread->doing_unsafe_access()) {
+        unsafe_access = true;
+    }
+
+    // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
+    // and the heap gets shrunk before the field access.
+    if (sig == SIGSEGV || sig == SIGBUS) {
+      address addr = JNI_FastGetField::find_slowcase_pc(pc);
+      if (addr != (address)-1) {
+        stub = addr;
+      }
+    }
+
+    // Check to see if we caught the safepoint code in the
+    // process of write protecting the memory serialization page.
+    // It write enables the page immediately after protecting it
+    // so we can just return to retry the write.
+    if (sig == SIGSEGV && os::is_memory_serialize_page(thread, (address) info->si_addr)) {
+      // Block current thread until the memory serialize page permission restored.
+      os::block_on_serialize_page_trap();
+      return true;
+    }
+  }
+
+  if (unsafe_access && stub == NULL) {
+    // it can be an unsafe access and we haven't found
+    // any other suitable exception reason,
+    // so assume it is an unsafe access.
+    address next_pc = pc + Assembler::InstructionSize;
+#ifdef __thumb__
+    if (uc->uc_mcontext.arm_cpsr & PSR_T_BIT) {
+      next_pc = (address)((intptr_t)next_pc | 0x1);
+    }
+#endif
+
+    stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
+  }
+
+  if (stub != NULL) {
+#ifdef __thumb__
+    if (uc->uc_mcontext.arm_cpsr & PSR_T_BIT) {
+      intptr_t p = (intptr_t)pc | 0x1;
+      pc = (address)p;
+
+      // Clear Thumb mode bit if we're redirected into the ARM ISA based code
+      if (((intptr_t)stub & 0x1) == 0) {
+        uc->uc_mcontext.arm_cpsr &= ~PSR_T_BIT;
+      }
+    } else {
+      // No Thumb2 compiled stubs are triggered from ARM ISA compiled JIT'd code today.
+      // The support needs to be added if that changes
+      assert((((intptr_t)stub & 0x1) == 0), "can't return to Thumb code");
+    }
+#endif
+
+    // save all thread context in case we need to restore it
+    if (thread != NULL) thread->set_saved_exception_pc(pc);
+
+    os::Linux::ucontext_set_pc(uc, stub);
+    return true;
+  }
+
+  // signal-chaining
+  if (os::Linux::chained_handler(sig, info, ucVoid)) {
+     return true;
+  }
+
+  if (!abort_if_unrecognized) {
+    // caller wants another chance, so give it to him
+    return false;
+  }
+
+  if (pc == NULL && uc != NULL) {
+    pc = os::Linux::ucontext_get_pc(uc);
+  }
+
+  // unmask current signal
+  sigset_t newset;
+  sigemptyset(&newset);
+  sigaddset(&newset, sig);
+  sigprocmask(SIG_UNBLOCK, &newset, NULL);
+
+  VMError::report_and_die(t, sig, pc, info, ucVoid);
+
+  ShouldNotReachHere();
+  return false;
+}
+
+void os::Linux::init_thread_fpu_state(void) {
+  os::setup_fpu();
+}
+
+int os::Linux::get_fpu_control_word(void) {
+  return 0;
+}
+
+void os::Linux::set_fpu_control_word(int fpu_control) {
+  // Nothing to do
+}
+
+void os::setup_fpu() {
+#ifdef AARCH64
+  __asm__ volatile ("msr fpcr, xzr");
+#else
+#if !defined(__SOFTFP__) && defined(__VFP_FP__)
+  // Turn on IEEE-754 compliant VFP mode
+  __asm__ volatile (
+    "mov %%r0, #0;"
+    "fmxr fpscr, %%r0"
+    : /* no output */ : /* no input */ : "r0"
+  );
+#endif
+#endif // AARCH64
+}
+
+bool os::is_allocatable(size_t bytes) {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// thread stack
+
+size_t os::Posix::_compiler_thread_min_stack_allowed = (48 DEBUG_ONLY(+ 4)) * K;
+size_t os::Posix::_java_thread_min_stack_allowed = (48 DEBUG_ONLY(+ 4)) * K;
+size_t os::Posix::_vm_internal_thread_min_stack_allowed = (48 DEBUG_ONLY(+ 4)) * K;
+
+// return default stack size for thr_type
+size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
+  // default stack size (compiler thread needs larger stack)
+  size_t s = (thr_type == os::compiler_thread ? 2 * M : 512 * K);
+  return s;
+}
+
+size_t os::Linux::default_guard_size(os::ThreadType thr_type) {
+  // Creating guard page is very expensive. Java thread has HotSpot
+  // guard page, only enable glibc guard page for non-Java threads.
+  return (thr_type == java_thread ? 0 : page_size());
+}
+
+// Java thread:
+//
+//   Low memory addresses
+//    +------------------------+
+//    |                        |\  JavaThread created by VM does not have glibc
+//    |    glibc guard page    | - guard, attached Java thread usually has
+//    |                        |/  1 page glibc guard.
+// P1 +------------------------+ Thread::stack_base() - Thread::stack_size()
+//    |                        |\
+//    |  HotSpot Guard Pages   | - red and yellow pages
+//    |                        |/
+//    +------------------------+ JavaThread::stack_yellow_zone_base()
+//    |                        |\
+//    |      Normal Stack      | -
+//    |                        |/
+// P2 +------------------------+ Thread::stack_base()
+//
+// Non-Java thread:
+//
+//   Low memory addresses
+//    +------------------------+
+//    |                        |\
+//    |  glibc guard page      | - usually 1 page
+//    |                        |/
+// P1 +------------------------+ Thread::stack_base() - Thread::stack_size()
+//    |                        |\
+//    |      Normal Stack      | -
+//    |                        |/
+// P2 +------------------------+ Thread::stack_base()
+//
+// ** P1 (aka bottom) and size ( P2 = P1 - size) are the address and stack size returned from
+//    pthread_attr_getstack()
+
+static void current_stack_region(address * bottom, size_t * size) {
+  if (os::Linux::is_initial_thread()) {
+     // initial thread needs special handling because pthread_getattr_np()
+     // may return bogus value.
+     *bottom = os::Linux::initial_thread_stack_bottom();
+     *size   = os::Linux::initial_thread_stack_size();
+  } else {
+     pthread_attr_t attr;
+
+     int rslt = pthread_getattr_np(pthread_self(), &attr);
+
+     // JVM needs to know exact stack location, abort if it fails
+     if (rslt != 0) {
+       if (rslt == ENOMEM) {
+         vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
+       } else {
+         fatal("pthread_getattr_np failed");
+       }
+     }
+
+     if (pthread_attr_getstack(&attr, (void **)bottom, size) != 0) {
+         fatal("Can not locate current stack attributes!");
+     }
+
+     pthread_attr_destroy(&attr);
+
+  }
+  assert(os::current_stack_pointer() >= *bottom &&
+         os::current_stack_pointer() < *bottom + *size, "just checking");
+}
+
+address os::current_stack_base() {
+  address bottom;
+  size_t size;
+  current_stack_region(&bottom, &size);
+  return (bottom + size);
+}
+
+size_t os::current_stack_size() {
+  // stack size includes normal stack and HotSpot guard pages
+  address bottom;
+  size_t size;
+  current_stack_region(&bottom, &size);
+  return size;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// helper functions for fatal error handler
+
+void os::print_context(outputStream *st, const void *context) {
+  if (context == NULL) return;
+  const ucontext_t *uc = (const ucontext_t*)context;
+
+  st->print_cr("Registers:");
+  intx* reg_area = (intx*)&uc->uc_mcontext.arm_r0;
+  for (int r = 0; r < ARM_REGS_IN_CONTEXT; r++) {
+    st->print_cr("  %-3s = " INTPTR_FORMAT, as_Register(r)->name(), reg_area[r]);
+  }
+#define U64_FORMAT "0x%016llx"
+#ifdef AARCH64
+  st->print_cr("  %-3s = " U64_FORMAT, "sp", uc->uc_mcontext.sp);
+  st->print_cr("  %-3s = " U64_FORMAT, "pc", uc->uc_mcontext.pc);
+  st->print_cr("  %-3s = " U64_FORMAT, "pstate", uc->uc_mcontext.pstate);
+#else
+  // now print flag register
+  st->print_cr("  %-4s = 0x%08lx", "cpsr",uc->uc_mcontext.arm_cpsr);
+#endif
+  st->cr();
+
+  intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
+  st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", p2i(sp));
+  print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t));
+  st->cr();
+
+  // Note: it may be unsafe to inspect memory near pc. For example, pc may
+  // point to garbage if entry point in an nmethod is corrupted. Leave
+  // this at the end, and hope for the best.
+  address pc = os::Linux::ucontext_get_pc(uc);
+  st->print_cr("Instructions: (pc=" INTPTR_FORMAT ")", p2i(pc));
+  print_hex_dump(st, pc - 32, pc + 32, Assembler::InstructionSize);
+}
+
+void os::print_register_info(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+  intx* reg_area = (intx*)&uc->uc_mcontext.arm_r0;
+
+  st->print_cr("Register to memory mapping:");
+  st->cr();
+  for (int r = 0; r < ARM_REGS_IN_CONTEXT; r++) {
+    st->print_cr("  %-3s = " INTPTR_FORMAT, as_Register(r)->name(), reg_area[r]);
+    print_location(st, reg_area[r]);
+    st->cr();
+  }
+#ifdef AARCH64
+  st->print_cr("  %-3s = " U64_FORMAT, "pc", uc->uc_mcontext.pc);
+  print_location(st, uc->uc_mcontext.pc);
+  st->cr();
+#endif
+  st->cr();
+}
+
+
+#ifndef AARCH64
+
+typedef jlong cmpxchg_long_func_t(jlong, jlong, volatile jlong*);
+
+cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap;
+
+jlong os::atomic_cmpxchg_long_bootstrap(jlong compare_value, jlong exchange_value, volatile jlong* dest) {
+  // try to use the stub:
+  cmpxchg_long_func_t* func = CAST_TO_FN_PTR(cmpxchg_long_func_t*, StubRoutines::atomic_cmpxchg_long_entry());
+
+  if (func != NULL) {
+    os::atomic_cmpxchg_long_func = func;
+    return (*func)(compare_value, exchange_value, dest);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  jlong old_value = *dest;
+  if (old_value == compare_value)
+    *dest = exchange_value;
+  return old_value;
+}
+typedef jlong load_long_func_t(volatile jlong*);
+
+load_long_func_t* os::atomic_load_long_func = os::atomic_load_long_bootstrap;
+
+jlong os::atomic_load_long_bootstrap(volatile jlong* src) {
+  // try to use the stub:
+  load_long_func_t* func = CAST_TO_FN_PTR(load_long_func_t*, StubRoutines::atomic_load_long_entry());
+
+  if (func != NULL) {
+    os::atomic_load_long_func = func;
+    return (*func)(src);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  jlong old_value = *src;
+  return old_value;
+}
+
+typedef void store_long_func_t(jlong, volatile jlong*);
+
+store_long_func_t* os::atomic_store_long_func = os::atomic_store_long_bootstrap;
+
+void os::atomic_store_long_bootstrap(jlong val, volatile jlong* dest) {
+  // try to use the stub:
+  store_long_func_t* func = CAST_TO_FN_PTR(store_long_func_t*, StubRoutines::atomic_store_long_entry());
+
+  if (func != NULL) {
+    os::atomic_store_long_func = func;
+    return (*func)(val, dest);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  *dest = val;
+}
+
+typedef jint  atomic_add_func_t(jint add_value, volatile jint *dest);
+
+atomic_add_func_t * os::atomic_add_func = os::atomic_add_bootstrap;
+
+jint  os::atomic_add_bootstrap(jint add_value, volatile jint *dest) {
+  atomic_add_func_t * func = CAST_TO_FN_PTR(atomic_add_func_t*,
+                                            StubRoutines::atomic_add_entry());
+  if (func != NULL) {
+    os::atomic_add_func = func;
+    return (*func)(add_value, dest);
+  }
+
+  jint old_value = *dest;
+  *dest = old_value + add_value;
+  return (old_value + add_value);
+}
+
+typedef jint  atomic_xchg_func_t(jint exchange_value, volatile jint *dest);
+
+atomic_xchg_func_t * os::atomic_xchg_func = os::atomic_xchg_bootstrap;
+
+jint  os::atomic_xchg_bootstrap(jint exchange_value, volatile jint *dest) {
+  atomic_xchg_func_t * func = CAST_TO_FN_PTR(atomic_xchg_func_t*,
+                                            StubRoutines::atomic_xchg_entry());
+  if (func != NULL) {
+    os::atomic_xchg_func = func;
+    return (*func)(exchange_value, dest);
+  }
+
+  jint old_value = *dest;
+  *dest = exchange_value;
+  return (old_value);
+}
+
+typedef jint cmpxchg_func_t(jint, jint, volatile jint*);
+
+cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap;
+
+jint os::atomic_cmpxchg_bootstrap(jint compare_value, jint exchange_value, volatile jint* dest) {
+  // try to use the stub:
+  cmpxchg_func_t* func = CAST_TO_FN_PTR(cmpxchg_func_t*, StubRoutines::atomic_cmpxchg_entry());
+
+  if (func != NULL) {
+    os::atomic_cmpxchg_func = func;
+    return (*func)(compare_value, exchange_value, dest);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  jint old_value = *dest;
+  if (old_value == compare_value)
+    *dest = exchange_value;
+  return old_value;
+}
+
+#endif // !AARCH64
+
+#ifndef PRODUCT
+void os::verify_stack_alignment() {
+}
+#endif
+
+int os::extra_bang_size_in_bytes() {
+  // ARM does not require an additional stack bang.
+  return 0;
+}
+
diff --git a/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.hpp b/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.hpp
new file mode 100644
index 0000000..3d78c34
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.hpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_OS_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_VM_OS_LINUX_ARM_HPP
+
+#ifndef __thumb__
+  enum {
+    // Offset to add to frame::_fp when dealing with non-thumb C frames
+#ifdef AARCH64
+    C_frame_offset =  0,
+#else
+    C_frame_offset =  -1,
+#endif
+  };
+#endif
+
+  static void setup_fpu();
+
+  static bool is_allocatable(size_t bytes);
+
+  // Used to register dynamic code cache area with the OS
+  // Note: Currently only used in 64 bit Windows implementations
+  static bool register_code_area(char *low, char *high) { return true; }
+
+#ifndef AARCH64
+  static jlong (*atomic_cmpxchg_long_func)(jlong compare_value,
+                                           jlong exchange_value,
+                                           volatile jlong *dest);
+
+  static jlong (*atomic_load_long_func)(volatile jlong*);
+
+  static void (*atomic_store_long_func)(jlong, volatile jlong*);
+
+  static jint  (*atomic_add_func)(jint add_value, volatile jint *dest);
+
+  static jint  (*atomic_xchg_func)(jint exchange_value, volatile jint *dest);
+
+  static jint  (*atomic_cmpxchg_func)(jint compare_value,
+                                      jint exchange_value,
+                                      volatile jint *dest);
+
+  static jlong atomic_cmpxchg_long_bootstrap(jlong, jlong, volatile jlong*);
+
+  static jlong atomic_load_long_bootstrap(volatile jlong*);
+
+  static void atomic_store_long_bootstrap(jlong, volatile jlong*);
+
+  static jint  atomic_add_bootstrap(jint add_value, volatile jint *dest);
+
+  static jint  atomic_xchg_bootstrap(jint exchange_value, volatile jint *dest);
+
+  static jint  atomic_cmpxchg_bootstrap(jint compare_value,
+                                        jint exchange_value,
+                                        volatile jint *dest);
+#endif // !AARCH64
+
+#endif // OS_CPU_LINUX_ARM_VM_OS_LINUX_ARM_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/prefetch_linux_arm.inline.hpp b/hotspot/src/os_cpu/linux_arm/vm/prefetch_linux_arm.inline.hpp
new file mode 100644
index 0000000..9f2cacd
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/prefetch_linux_arm.inline.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_PREFETCH_LINUX_ARM_INLINE_HPP
+#define OS_CPU_LINUX_ARM_VM_PREFETCH_LINUX_ARM_INLINE_HPP
+
+#include "runtime/prefetch.hpp"
+
+inline void Prefetch::read (void *loc, intx interval) {
+#ifdef AARCH64
+  __asm__ volatile ("prfm PLDL1KEEP, [%0]" : : "r" (loc));
+#else
+#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_5TE__)
+  __asm__ volatile ("pld [%0]" : : "r" (loc));
+#endif
+#endif // AARCH64
+}
+
+inline void Prefetch::write(void *loc, intx interval) {
+#ifdef AARCH64
+  __asm__ volatile ("prfm PSTL1KEEP, [%0]" : : "r" (loc));
+#else
+  // Not available on 32-bit ARM (prior to ARMv7 with MP extensions)
+#endif // AARCH64
+}
+
+#endif // OS_CPU_LINUX_ARM_VM_PREFETCH_LINUX_ARM_INLINE_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.cpp b/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.cpp
new file mode 100644
index 0000000..78cde2002
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/shared/barrierSet.inline.hpp"
+#include "gc/shared/cardTableModRefBS.inline.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "runtime/frame.inline.hpp"
+
+void JavaThread::cache_global_variables() {
+  BarrierSet* bs = Universe::heap()->barrier_set();
+
+  const bool allow_shared_alloc =
+    Universe::heap()->supports_inline_contig_alloc();
+
+  if (allow_shared_alloc) {
+    _heap_top_addr = (address) Universe::heap()->top_addr();
+  } else {
+    _heap_top_addr = NULL;
+  }
+
+  if (bs->is_a(BarrierSet::CardTableModRef)) {
+    _card_table_base = (address) (barrier_set_cast<CardTableModRefBS>(bs)->byte_map_base);
+  } else {
+    _card_table_base = NULL;
+  }
+
+}
+
+// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
+// currently interrupted by SIGPROF
+bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
+  void* ucontext, bool isInJava) {
+  assert(Thread::current() == this, "caller must be current thread");
+  return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+  return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
+  assert(this->is_Java_thread(), "must be JavaThread");
+
+  JavaThread* jt = (JavaThread *)this;
+
+  // If we have a last_Java_frame, then we should use it even if
+  // isInJava == true.  It should be more reliable than ucontext info.
+  if (jt->has_last_Java_frame() AARCH64_ONLY(&& jt->last_Java_pc() != NULL)) {
+    *fr_addr = jt->pd_last_frame();
+    return true;
+  }
+
+  // Could be in a code section that plays with the stack, like
+  // MacroAssembler::verify_heapbase()
+  if (jt->in_top_frame_unsafe_section()) {
+    return false;
+  }
+
+  // At this point, we don't have a last_Java_frame, so
+  // we try to glean some information out of the ucontext
+  // if we were running Java code when SIGPROF came in.
+  if (isInJava) {
+    ucontext_t* uc = (ucontext_t*) ucontext;
+
+    intptr_t* ret_fp;
+    intptr_t* ret_sp;
+    ExtendedPC addr = os::Linux::fetch_frame_from_ucontext(this, uc,
+      &ret_sp, &ret_fp);
+    if (addr.pc() == NULL || ret_sp == NULL ) {
+      // ucontext wasn't useful
+      return false;
+    }
+
+#if INCLUDE_CDS
+    if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) {
+      // In the middle of a trampoline call. Bail out for safety.
+      // This happens rarely so shouldn't affect profiling.
+      return false;
+    }
+#endif
+
+    frame ret_frame(ret_sp, ret_fp, addr.pc());
+    if (!ret_frame.safe_for_sender(jt)) {
+#ifdef COMPILER2
+      // C2 uses ebp as a general register see if NULL fp helps
+      frame ret_frame2(ret_sp, NULL, addr.pc());
+      if (!ret_frame2.safe_for_sender(jt)) {
+        // nothing else to try if the frame isn't good
+        return false;
+      }
+      ret_frame = ret_frame2;
+#else
+      // nothing else to try if the frame isn't good
+      return false;
+#endif /* COMPILER2 */
+    }
+    *fr_addr = ret_frame;
+    return true;
+  }
+
+  // nothing else to try
+  return false;
+}
diff --git a/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.hpp b/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.hpp
new file mode 100644
index 0000000..22a2a92
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/thread_linux_arm.hpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_THREAD_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_VM_THREAD_LINUX_ARM_HPP
+
+ private:
+  // The following thread-local variables replicate corresponding global variables.
+  // They are used for a quick access from compiled code via Rthread register.
+  address _heap_top_addr;
+  address _heap_lock_addr;
+  address _card_table_base;
+
+  void pd_initialize() {
+    _anchor.clear();
+    _in_top_frame_unsafe_section = NULL;
+  }
+
+  frame pd_last_frame() {
+    assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
+#ifdef AARCH64
+    assert (_anchor.last_Java_pc() != NULL, "pc should be stored");
+    return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
+#else
+    if (_anchor.last_Java_pc() != NULL) {
+      return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
+    } else {
+      // This will pick up pc from sp
+      return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp());
+    }
+#endif // AARCH64
+  }
+
+ public:
+  intptr_t* last_Java_fp()                       { return _anchor.last_Java_fp(); }
+  void  set_last_Java_fp(intptr_t* fp)           { _anchor.set_last_Java_fp(fp);  }
+  void  set_last_Java_pc(address pc)             { _anchor.set_last_Java_pc(pc);  }
+
+  static ByteSize last_Java_fp_offset()          {
+    return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset();
+  }
+
+  void set_base_of_stack_pointer(intptr_t* base_sp) {
+    // Nothing to do
+  }
+
+  intptr_t* base_of_stack_pointer() {
+    return NULL;
+  }
+
+  void record_base_of_stack_pointer() {
+    // Nothing to do
+  }
+
+  static ByteSize heap_top_addr_offset()         { return byte_offset_of(JavaThread, _heap_top_addr); }
+  static ByteSize card_table_base_offset()       { return byte_offset_of(JavaThread, _card_table_base); }
+
+private:
+  // Set to "this" if pd_get_top_frame should ignore this thread for now.
+  JavaThread *_in_top_frame_unsafe_section;
+
+public:
+  static ByteSize in_top_frame_unsafe_section_offset() { return byte_offset_of(JavaThread, _in_top_frame_unsafe_section); }
+  bool in_top_frame_unsafe_section() { return _in_top_frame_unsafe_section == this; }
+
+  bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
+
+  bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
+private:
+  bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
+public:
+
+  // These routines are only used on cpu architectures that
+  // have separate register stacks (Itanium).
+  static bool register_stack_overflow() { return false; }
+  static void enable_register_stack_guard() {}
+  static void disable_register_stack_guard() {}
+
+#endif // OS_CPU_LINUX_ARM_VM_THREAD_LINUX_ARM_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/vmStructs_linux_arm.hpp b/hotspot/src/os_cpu/linux_arm/vm/vmStructs_linux_arm.hpp
new file mode 100644
index 0000000..e34d06d
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/vmStructs_linux_arm.hpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_LINUX_ARM_VM_VMSTRUCTS_LINUX_ARM_HPP
+#define OS_CPU_LINUX_ARM_VM_VMSTRUCTS_LINUX_ARM_HPP
+
+// These are the OS and CPU-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+                                                                                                                                     \
+  /******************************/                                                                                                   \
+  /* Threads (NOTE: incomplete) */                                                                                                   \
+  /******************************/                                                                                                   \
+  nonstatic_field(OSThread,                      _thread_id,                                      OSThread::thread_id_t)             \
+  nonstatic_field(OSThread,                      _pthread_id,                                     pthread_t)
+
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+                                                                          \
+  /**********************/                                                \
+  /* Posix Thread IDs   */                                                \
+  /**********************/                                                \
+                                                                          \
+  declare_integer_type(OSThread::thread_id_t)                             \
+  declare_unsigned_integer_type(pthread_t)
+
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#endif // OS_CPU_LINUX_ARM_VM_VMSTRUCTS_LINUX_ARM_HPP
diff --git a/hotspot/src/os_cpu/linux_arm/vm/vm_version_linux_arm_32.cpp b/hotspot/src/os_cpu/linux_arm/vm/vm_version_linux_arm_32.cpp
new file mode 100644
index 0000000..9d18e5b
--- /dev/null
+++ b/hotspot/src/os_cpu/linux_arm/vm/vm_version_linux_arm_32.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "vm_version_arm.hpp"
+
+# include <sys/utsname.h>
+
+// Use uname() to find the architecture version
+void VM_Version::get_os_cpu_info() {
+  struct utsname name;
+  static bool done = false;
+
+  // Support for multiple calls in the init phase
+  if (done) return;
+  done = true;
+
+  uname(&name);
+  if (strncmp(name.machine, "aarch64", 7) == 0) {
+    _arm_arch = 8;
+  } else if (strncmp(name.machine, "armv", 4) == 0 &&
+      name.machine[4] >= '5' && name.machine[4] <= '9') {
+    _arm_arch = (int)(name.machine[4] - '0');
+  }
+}
+
+// Make sure that _arm_arch is initialized so that any calls to OrderAccess will
+// use proper dmb instruction
+void VM_Version::early_initialize() {
+  get_os_cpu_info();
+}
diff --git a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
index c906109..1ca241d 100644
--- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
+++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
@@ -171,6 +171,8 @@
 }
 
 frame os::current_frame() {
+  // Expected to return the stack pointer of this method.
+  // But if inlined, returns the stack pointer of our caller!
   intptr_t* csp = (intptr_t*) *((intptr_t*) os::current_stack_pointer());
   assert (csp != NULL, "sp should not be NULL");
   // Pass a dummy pc. This way we don't have to load it from the
@@ -184,8 +186,13 @@
     assert(senderFrame.pc() != NULL, "Sender pc should not be NULL");
     // Return sender of sender of current topframe which hopefully
     // both have pc != NULL.
+#ifdef _NMT_NOINLINE_   // Is set in slowdebug builds.
+    // Current_stack_pointer is not inlined, we must pop one more frame.
     frame tmp = os::get_sender_for_C_frame(&topframe);
     return os::get_sender_for_C_frame(&tmp);
+#else
+    return os::get_sender_for_C_frame(&topframe);
+#endif
   }
 }
 
@@ -374,7 +381,7 @@
         // BugId 4454115: A read from a MappedByteBuffer can fault here if the
         // underlying file has been truncated. Do not crash the VM in such a case.
         CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
-        nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
+        CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
         if (nm != NULL && nm->has_unsafe_access()) {
           // We don't really need a stub here! Just set the pending exeption and
           // continue at the next instruction after the faulting read. Returning
diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp
new file mode 100644
index 0000000..08283a9
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp
@@ -0,0 +1,907 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.hpp"
+#include "gc/g1/heapRegion.hpp"
+#include "gc/shared/gcLocker.hpp"
+#include "interpreter/abstractInterpreter.hpp"
+#include "jvmci/compilerRuntime.hpp"
+#include "jvmci/jvmciRuntime.hpp"
+#include "oops/method.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/vm_operations.hpp"
+
+bool AOTLib::_narrow_oop_shift_initialized = false;
+int  AOTLib::_narrow_oop_shift = 0;
+int  AOTLib::_narrow_klass_shift = 0;
+
+address AOTLib::load_symbol(const char *name) {
+  address symbol = (address) dlsym(_dl_handle, name);
+  if (symbol == NULL) {
+    tty->print_cr("Shared file %s error: missing %s", _name, name);
+    vm_exit(1);
+  }
+  return symbol;
+}
+
+Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, const Method* method) {
+  AOTKlassData* klass_data = (AOTKlassData*)_lib->load_symbol(klass_name);
+  Klass* k = (Klass*)_metaspace_got[klass_data->_got_index];
+  if (k == NULL) {
+    Thread* thread = Thread::current();
+    k = lookup_klass(klass_name, klass_len, method, thread);
+    // Note, exceptions are cleared.
+    if (k == NULL) {
+      fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name);
+      vm_exit(1);
+    }
+    _metaspace_got[klass_data->_got_index] = k;
+  }
+  return k;
+}
+
+Klass* AOTCodeHeap::lookup_klass(const char* name, int len, const Method* method, Thread* thread) {
+  ResourceMark rm(thread);
+  assert(method != NULL, "incorrect call parameter");
+  methodHandle caller(thread, (Method*)method);
+
+  // Use class loader of aot method.
+  Handle loader(thread, caller->method_holder()->class_loader());
+  Handle protection_domain(thread, caller->method_holder()->protection_domain());
+
+  // Ignore wrapping L and ;
+  if (name[0] == 'L') {
+    assert(len > 2, "small name %s", name);
+    name++;
+    len -= 2;
+  }
+  TempNewSymbol sym = SymbolTable::probe(name, len);
+  if (sym == NULL) {
+    log_debug(aot, class, resolve)("Probe failed for AOT class %s", name);
+    return NULL;
+  }
+  Klass* k = SystemDictionary::find_instance_or_array_klass(sym, loader, protection_domain, thread);
+  assert(!thread->has_pending_exception(), "should not throw");
+
+  if (k != NULL) {
+    log_info(aot, class, resolve)("%s %s (lookup)", caller->method_holder()->external_name(), k->external_name());
+  }
+  return k;
+}
+
+void AOTLib::handle_config_error(const char* format, ...) {
+  if (PrintAOT) {
+    va_list ap;
+    va_start(ap, format);
+    tty->vprint_cr(format, ap);
+    va_end(ap);
+  }
+  if (UseAOTStrictLoading) {
+    vm_exit(1);
+  }
+  _valid = false;
+}
+
+void AOTLib::verify_flag(bool aot_flag, bool flag, const char* name) {
+  if (_valid && aot_flag != flag) {
+    handle_config_error("Shared file %s error: %s has different value '%s' from current '%s'", _name, name , (aot_flag ? "true" : "false"), (flag ? "true" : "false"));
+  }
+}
+
+void AOTLib::verify_flag(int aot_flag, int flag, const char* name) {
+  if (_valid && aot_flag != flag) {
+    handle_config_error("Shared file %s error: %s has different value '%d' from current '%d'", _name, name , aot_flag, flag);
+  }
+}
+
+void AOTLib::verify_config() {
+  GrowableArray<AOTLib*>* libraries = AOTLoader::libraries();
+  for (GrowableArrayIterator<AOTLib*> lib = libraries->begin(); lib != libraries->end(); ++lib) {
+    if ((*lib)->_config == _config) {
+      handle_config_error("AOT library %s already loaded.", (*lib)->_name);
+      return;
+    }
+  }
+
+  if (_header->_version != AOTHeader::AOT_SHARED_VERSION) {
+    handle_config_error("Invalid version of the shared file %s. Expected %d but was %d", _name, _header->_version, AOTHeader::AOT_SHARED_VERSION);
+    return;
+  }
+
+  const char* aot_jvm_version = (const char*)_header + _header->_jvm_version_offset + 2;
+  if (strcmp(aot_jvm_version, VM_Version::jre_release_version()) != 0) {
+    handle_config_error("JVM version '%s' recorded in the shared file %s does not match current version '%s'", aot_jvm_version, _name, VM_Version::jre_release_version());
+    return;
+  }
+
+  // Debug VM has different layout of runtime and metadata structures
+#ifdef ASSERT
+  verify_flag(_config->_debug_VM, true, "Debug VM version");
+#else
+  verify_flag(!(_config->_debug_VM), true, "Product VM version");
+#endif
+  // Check configuration size
+  verify_flag(_config->_config_size, AOTConfiguration::CONFIG_SIZE, "AOT configuration size");
+
+  // Check flags
+  verify_flag(_config->_useCompressedOops, UseCompressedOops, "UseCompressedOops");
+  verify_flag(_config->_useCompressedClassPointers, UseCompressedClassPointers, "UseCompressedClassPointers");
+  verify_flag(_config->_useG1GC, UseG1GC, "UseG1GC");
+  verify_flag(_config->_useCMSGC, UseConcMarkSweepGC, "UseConcMarkSweepGC");
+  verify_flag(_config->_useTLAB, UseTLAB, "UseTLAB");
+  verify_flag(_config->_useBiasedLocking, UseBiasedLocking, "UseBiasedLocking");
+  verify_flag(_config->_objectAlignment, ObjectAlignmentInBytes, "ObjectAlignmentInBytes");
+  verify_flag(_config->_contendedPaddingWidth, ContendedPaddingWidth, "ContendedPaddingWidth");
+  verify_flag(_config->_fieldsAllocationStyle, FieldsAllocationStyle, "FieldsAllocationStyle");
+  verify_flag(_config->_compactFields, CompactFields, "CompactFields");
+  verify_flag(_config->_enableContended, EnableContended, "EnableContended");
+  verify_flag(_config->_restrictContended, RestrictContended, "RestrictContended");
+
+  if (!TieredCompilation && _config->_tieredAOT) {
+    handle_config_error("Shared file %s error: Expected to run with tiered compilation on", _name);
+  }
+
+  // Shifts are static values which initialized by 0 until java heap initialization.
+  // AOT libs are loaded before heap initialized so shift values are not set.
+  // It is okay since ObjectAlignmentInBytes flag which defines shifts value is set before AOT libs are loaded.
+  // Set shifts value based on first AOT library config.
+  if (UseCompressedOops && _valid) {
+    if (!_narrow_oop_shift_initialized) {
+      _narrow_oop_shift = _config->_narrowOopShift;
+      if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+        _narrow_klass_shift = _config->_narrowKlassShift;
+      }
+      _narrow_oop_shift_initialized = true;
+    } else {
+      verify_flag(_config->_narrowOopShift, _narrow_oop_shift, "aot_config->_narrowOopShift");
+      if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+        verify_flag(_config->_narrowKlassShift, _narrow_klass_shift, "aot_config->_narrowKlassShift");
+      }
+    }
+  }
+}
+
+AOTLib::~AOTLib() {
+  free((void*) _name);
+}
+
+AOTCodeHeap::~AOTCodeHeap() {
+  if (_classes != NULL) {
+    FREE_C_HEAP_ARRAY(AOTClass, _classes);
+  }
+  if (_code_to_aot != NULL) {
+    FREE_C_HEAP_ARRAY(CodeToAMethod, _code_to_aot);
+  }
+}
+
+AOTLib::AOTLib(void* handle, const char* name, int dso_id) : _valid(true), _dl_handle(handle), _dso_id(dso_id) {
+  _name = (const char*) strdup(name);
+
+  // Verify that VM runs with the same parameters as AOT tool.
+  _config = (AOTConfiguration*) load_symbol("JVM.config");
+  _header = (AOTHeader*) load_symbol("JVM.header");
+
+  verify_config();
+
+  if (!_valid && PrintAOT) {
+      tty->print("%7d ", (int) tty->time_stamp().milliseconds());
+      tty->print_cr("%4d     skipped %s  aot library", _dso_id, _name);
+  }
+}
+
+AOTCodeHeap::AOTCodeHeap(AOTLib* lib) :
+    CodeHeap("CodeHeap 'AOT'", CodeBlobType::AOT), _lib(lib), _classes(NULL), _code_to_aot(NULL) {
+  assert(_lib->is_valid(), "invalid library");
+
+  _lib_symbols_initialized = false;
+  _aot_id = 0;
+
+  _class_count = _lib->header()->_class_count;
+  _method_count = _lib->header()->_method_count;
+
+  // Collect metaspace info: names -> address in .got section
+  _metaspace_names = (const char*) _lib->load_symbol("JVM.metaspace.names");
+  _method_metadata =     (address) _lib->load_symbol("JVM.method.metadata");
+  _methods_offsets =     (address) _lib->load_symbol("JVM.methods.offsets");
+  _klasses_offsets =     (address) _lib->load_symbol("JVM.klasses.offsets");
+  _dependencies    =     (address) _lib->load_symbol("JVM.klasses.dependencies");
+  _code_space      =     (address) _lib->load_symbol("JVM.text");
+
+  // First cell is number of elements.
+  jlong* got_sect;
+  _metaspace_got      = (Metadata**) _lib->load_symbol("JVM.metaspace.got");
+  _metaspace_got_size = _lib->header()->_metaspace_got_size;
+
+  _metadata_got      = (Metadata**) _lib->load_symbol("JVM.metadata.got");
+  _metadata_got_size = _lib->header()->_metadata_got_size;
+
+  _oop_got      = (oop*) _lib->load_symbol("JVM.oop.got");
+  _oop_got_size = _lib->header()->_oop_got_size;
+
+  // Collect stubs info
+  _stubs_offsets = (int*) _lib->load_symbol("JVM.stubs.offsets");
+
+  // code segments table
+  _code_segments = (address) _lib->load_symbol("JVM.code.segments");
+
+  // method state
+  _method_state = (jlong*) _lib->load_symbol("JVM.method.state");
+
+  // Create a table for mapping classes
+  _classes = NEW_C_HEAP_ARRAY(AOTClass, _class_count, mtCode);
+  memset(_classes, 0, _class_count * sizeof(AOTClass));
+
+  // Create table for searching AOTCompiledMethod based on pc.
+  _code_to_aot = NEW_C_HEAP_ARRAY(CodeToAMethod, _method_count, mtCode);
+  memset(_code_to_aot, 0, _method_count * sizeof(CodeToAMethod));
+
+  _low_boundary = _code_space;
+  _memory.set_low_boundary((char *)_code_space);
+  _memory.set_high_boundary((char *)_code_space);
+  _memory.set_low((char *)_code_space);
+  _memory.set_high((char *)_code_space);
+
+  _segmap.set_low_boundary((char *)_code_segments);
+  _segmap.set_low((char *)_code_segments);
+
+  _log2_segment_size = exact_log2(_lib->config()->_codeSegmentSize);
+
+  // Register aot stubs
+  register_stubs();
+
+  if (PrintAOT || (PrintCompilation && PrintAOT)) {
+    tty->print("%7d ", (int) tty->time_stamp().milliseconds());
+    tty->print_cr("%4d     loaded    %s  aot library", _lib->id(), _lib->name());
+  }
+}
+
+void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id) {
+  // The method may be explicitly excluded by the user.
+  // Or Interpreter uses an intrinsic for this method.
+  if (CompilerOracle::should_exclude(mh) || !AbstractInterpreter::can_be_compiled(mh)) {
+    return;
+  }
+
+  address code = method_data->_code;
+  const char* name = method_data->_name;
+  aot_metadata* meta = method_data->_meta;
+
+  if (meta->scopes_pcs_begin() == meta->scopes_pcs_end()) {
+    // When the AOT compiler compiles something big we fail to generate metadata
+    // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end.
+    // In all successful cases we always have 2 entries of scope pcs.
+    return;
+  }
+
+  jlong* state_adr = &_method_state[code_id];
+  address metadata_table = method_data->_metadata_table;
+  int metadata_size = method_data->_metadata_size;
+  assert(code_id < _method_count, "sanity");
+  _aot_id++;
+
+#ifdef ASSERT
+  if (_aot_id > CIStop || _aot_id < CIStart) {
+    // Skip compilation
+    return;
+  }
+#endif
+  // Check one more time.
+  if (_code_to_aot[code_id]._state == invalid) {
+    return;
+  }
+  AOTCompiledMethod *aot = new AOTCompiledMethod(code, mh(), meta, metadata_table, metadata_size, state_adr, this, name, code_id, _aot_id);
+  assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized");
+  _code_to_aot[code_id]._aot = aot; // Should set this first
+  if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+    _code_to_aot[code_id]._aot = NULL; // Clean
+  } else { // success
+    // Publish method
+#ifdef TIERED
+    mh->set_aot_code(aot);
+#endif
+    Method::set_code(mh, aot);
+    if (PrintAOT || (PrintCompilation && PrintAOT)) {
+      aot->print_on(tty, NULL);
+    }
+    // Publish oop only after we are visible to CompiledMethodIterator
+    aot->set_oop(mh()->method_holder()->klass_holder());
+  }
+}
+
+void AOTCodeHeap::link_primitive_array_klasses() {
+  ResourceMark rm;
+  for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
+    BasicType t = (BasicType)i;
+    if (is_java_primitive(t)) {
+      const Klass* arr_klass = Universe::typeArrayKlassObj(t);
+      AOTKlassData* klass_data = (AOTKlassData*) dlsym(_lib->dl_handle(), arr_klass->signature_name());
+      if (klass_data != NULL) {
+        // Set both GOT cells, resolved and initialized klass pointers.
+        // _got_index points to second cell - resolved klass pointer.
+        _metaspace_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized
+        _metaspace_got[klass_data->_got_index  ] = (Metadata*)arr_klass; // Resolved
+        if (PrintAOT) {
+          tty->print_cr("[Found  %s  in  %s]", arr_klass->internal_name(), _lib->name());
+        }
+      }
+    }
+  }
+}
+
+void AOTCodeHeap::register_stubs() {
+  int stubs_count = _stubs_offsets[0]; // contains number
+  _stubs_offsets++;
+  AOTMethodOffsets* stub_offsets = (AOTMethodOffsets*)_stubs_offsets;
+  for (int i = 0; i < stubs_count; ++i) {
+    const char* stub_name = _metaspace_names + stub_offsets[i]._name_offset;
+    address entry = _code_space  + stub_offsets[i]._code_offset;
+    aot_metadata* meta = (aot_metadata *) (_method_metadata + stub_offsets[i]._meta_offset);
+    address metadata_table = (address)_metadata_got + stub_offsets[i]._metadata_got_offset;
+    int metadata_size = stub_offsets[i]._metadata_got_size;
+    int code_id = stub_offsets[i]._code_id;
+    assert(code_id < _method_count, "sanity");
+    jlong* state_adr = &_method_state[code_id];
+    int len = build_u2_from((address)stub_name);
+    stub_name += 2;
+    char* full_name = NEW_C_HEAP_ARRAY(char, len+5, mtCode);
+    if (full_name == NULL) { // No memory?
+      break;
+    }
+    memcpy(full_name, "AOT ", 4);
+    memcpy(full_name+4, stub_name, len);
+    full_name[len+4] = 0;
+    guarantee(_code_to_aot[code_id]._state != invalid, "stub %s can't be invalidated", full_name);
+    AOTCompiledMethod* aot = new AOTCompiledMethod(entry, NULL, meta, metadata_table, metadata_size, state_adr, this, full_name, code_id, i);
+    assert(_code_to_aot[code_id]._aot  == NULL, "should be not initialized");
+    _code_to_aot[code_id]._aot  = aot;
+    if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+      fatal("stab '%s' code state is %d", full_name, _code_to_aot[code_id]._state);
+    }
+    // Adjust code buffer boundaries only for stubs because they are last in the buffer.
+    adjust_boundaries(aot);
+    if (PrintAOT && Verbose) {
+      aot->print_on(tty, NULL);
+    }
+  }
+}
+
+#define SET_AOT_GLOBAL_SYMBOL_VALUE(AOTSYMNAME, AOTSYMTYPE, VMSYMVAL) \
+  {                                                                   \
+    char* error;                                                      \
+    /* Clear any existing error */                                    \
+    dlerror();                                                        \
+    AOTSYMTYPE * adr = (AOTSYMTYPE *) dlsym(_lib->dl_handle(), AOTSYMNAME);  \
+    /* Check for any dlsym lookup error */                            \
+    error = dlerror();                                                \
+    guarantee(error == NULL, "%s", error);                            \
+    *adr = (AOTSYMTYPE) VMSYMVAL;                                     \
+  }
+
+void AOTCodeHeap::link_graal_runtime_symbols()  {
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_monitorenter", address, JVMCIRuntime::monitorenter);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_monitorexit", address, JVMCIRuntime::monitorexit);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_object", address, JVMCIRuntime::log_object);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_printf", address, JVMCIRuntime::log_printf);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_log_primitive", address, JVMCIRuntime::log_primitive);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_instance", address, JVMCIRuntime::new_instance);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_array", address, JVMCIRuntime::new_array);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array", address, JVMCIRuntime::new_multi_array);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array", address, JVMCIRuntime::dynamic_new_array);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_validate_object", address, JVMCIRuntime::validate_object);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_pre", address, JVMCIRuntime::write_barrier_pre);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_identity_hash_code", address, JVMCIRuntime::identity_hash_code);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance", address, JVMCIRuntime::dynamic_new_instance);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_thread_is_interrupted", address, JVMCIRuntime::thread_is_interrupted);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_exception_handler_for_pc", address, JVMCIRuntime::exception_handler_for_pc);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_test_deoptimize_call_int", address, JVMCIRuntime::test_deoptimize_call_int);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_and_post_jvmti_exception", address, JVMCIRuntime::throw_and_post_jvmti_exception);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_klass_external_name_exception", address, JVMCIRuntime::throw_klass_external_name_exception);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_class_cast_exception", address, JVMCIRuntime::throw_class_cast_exception);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_vm_message", address, JVMCIRuntime::vm_message);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_vm_error", address, JVMCIRuntime::vm_error);
+}
+
+void AOTCodeHeap::link_shared_runtime_symbols() {
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_static_entry", address, SharedRuntime::get_resolve_static_call_stub());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_virtual_entry", address, SharedRuntime::get_resolve_virtual_call_stub());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_resolve_opt_virtual_entry", address, SharedRuntime::get_resolve_opt_virtual_call_stub());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_unpack", address, SharedRuntime::deopt_blob()->unpack());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_deopt_blob_uncommon_trap", address, SharedRuntime::deopt_blob()->uncommon_trap());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_ic_miss_stub", address, SharedRuntime::get_ic_miss_stub());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_handle_wrong_method_stub", address, SharedRuntime::get_handle_wrong_method_stub());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_klass_by_symbol", address, CompilerRuntime::resolve_klass_by_symbol);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_method_by_symbol_and_load_counters", address, CompilerRuntime::resolve_method_by_symbol_and_load_counters);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_initialize_klass_by_symbol", address, CompilerRuntime::initialize_klass_by_symbol);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_invocation_event", address, CompilerRuntime::invocation_event);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_backedge_event", address, CompilerRuntime::backedge_event);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dpow", address, SharedRuntime::dpow);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dexp", address, SharedRuntime::dexp);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dcos", address, SharedRuntime::dcos);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dsin", address, SharedRuntime::dsin);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dtan", address, SharedRuntime::dtan);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dlog", address, SharedRuntime::dlog);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_shared_runtime_dlog10", address, SharedRuntime::dlog10);
+}
+
+void AOTCodeHeap::link_stub_routines_symbols() {
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jbyte_arraycopy", address, StubRoutines::_jbyte_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jshort_arraycopy", address, StubRoutines::_jshort_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jint_arraycopy", address, StubRoutines::_jint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jlong_arraycopy", address, StubRoutines::_jlong_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_arraycopy", address, StubRoutines::_oop_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_arraycopy_uninit", address, StubRoutines::_oop_arraycopy_uninit);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jbyte_disjoint_arraycopy", address, StubRoutines::_jbyte_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jshort_disjoint_arraycopy", address, StubRoutines::_jshort_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jint_disjoint_arraycopy", address, StubRoutines::_jint_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_jlong_disjoint_arraycopy", address, StubRoutines::_jlong_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_disjoint_arraycopy", address, StubRoutines::_oop_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_oop_disjoint_arraycopy_uninit", address, StubRoutines::_oop_disjoint_arraycopy_uninit);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jbyte_arraycopy", address, StubRoutines::_arrayof_jbyte_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jshort_arraycopy", address, StubRoutines::_arrayof_jshort_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jint_arraycopy", address, StubRoutines::_arrayof_jint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jlong_arraycopy", address, StubRoutines::_arrayof_jlong_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_arraycopy", address, StubRoutines::_arrayof_oop_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_arraycopy_uninit", address, StubRoutines::_arrayof_oop_arraycopy_uninit);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy", address, StubRoutines::_arrayof_jbyte_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jshort_disjoint_arraycopy", address, StubRoutines::_arrayof_jshort_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jint_disjoint_arraycopy", address, StubRoutines::_arrayof_jint_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_jlong_disjoint_arraycopy", address, StubRoutines::_arrayof_jlong_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_decryptBlock", address, StubRoutines::_aescrypt_decryptBlock);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_encryptAESCrypt", address, StubRoutines::_cipherBlockChaining_encryptAESCrypt);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_decryptAESCrypt", address, StubRoutines::_cipherBlockChaining_decryptAESCrypt);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_update_bytes_crc32", address, StubRoutines::_updateBytesCRC32);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_crc_table_adr", address, StubRoutines::_crc_table_adr);
+
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha1_implCompress", address, StubRoutines::_sha1_implCompress);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha1_implCompressMB", address, StubRoutines::_sha1_implCompressMB);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha256_implCompress", address, StubRoutines::_sha256_implCompress);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha256_implCompressMB", address, StubRoutines::_sha256_implCompressMB);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha512_implCompress", address, StubRoutines::_sha512_implCompress);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_sha512_implCompressMB", address, StubRoutines::_sha512_implCompressMB);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_multiplyToLen", address, StubRoutines::_multiplyToLen);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_counterMode_AESCrypt", address, StubRoutines::_counterMode_AESCrypt);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_ghash_processBlocks", address, StubRoutines::_ghash_processBlocks);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_crc32c_table_addr", address, StubRoutines::_crc32c_table_addr);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_updateBytesCRC32C", address, StubRoutines::_updateBytesCRC32C);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_updateBytesAdler32", address, StubRoutines::_updateBytesAdler32);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_squareToLen", address, StubRoutines::_squareToLen);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_mulAdd", address, StubRoutines::_mulAdd);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_montgomeryMultiply",  address, StubRoutines::_montgomeryMultiply);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_montgomerySquare", address, StubRoutines::_montgomerySquare);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_vectorizedMismatch", address, StubRoutines::_vectorizedMismatch);
+
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_throw_delayed_StackOverflowError_entry", address, StubRoutines::_throw_delayed_StackOverflowError_entry);
+
+}
+
+void AOTCodeHeap::link_os_symbols() {
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_os_javaTimeMillis", address, os::javaTimeMillis);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_os_javaTimeNanos", address, os::javaTimeNanos);
+}
+
+/*
+ * Link any global symbols in precompiled DSO with dlopen() _dl_handle
+ * dso_handle.
+ */
+
+void AOTCodeHeap::link_global_lib_symbols() {
+  if (!_lib_symbols_initialized) {
+    _lib_symbols_initialized = true;
+
+    CollectedHeap* heap = Universe::heap();
+    CardTableModRefBS* ct = (CardTableModRefBS*)(heap->barrier_set());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_card_table_address", address, ct->byte_map_base);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_top_address", address, (heap->supports_inline_contig_alloc() ? heap->top_addr() : NULL));
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL));
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
+    link_shared_runtime_symbols();
+    link_stub_routines_symbols();
+    link_os_symbols();
+    link_graal_runtime_symbols();
+
+    // Link primitive array klasses.
+    link_primitive_array_klasses();
+  }
+}
+
+#ifndef PRODUCT
+int AOTCodeHeap::klasses_seen = 0;
+int AOTCodeHeap::aot_klasses_found = 0;
+int AOTCodeHeap::aot_klasses_fp_miss = 0;
+int AOTCodeHeap::aot_klasses_cl_miss = 0;
+int AOTCodeHeap::aot_methods_found = 0;
+
+void AOTCodeHeap::print_statistics() {
+  tty->print_cr("Classes seen: %d  AOT classes found: %d  AOT methods found: %d", klasses_seen, aot_klasses_found, aot_methods_found);
+  tty->print_cr("AOT fingerprint mismatches: %d  AOT class loader mismatches: %d", aot_klasses_fp_miss, aot_klasses_cl_miss);
+}
+#endif
+
+Method* AOTCodeHeap::find_method(KlassHandle klass, Thread* thread, const char* method_name) {
+  int method_name_len = build_u2_from((address)method_name);
+  method_name += 2;
+  const char* signature_name = method_name + method_name_len;
+  int signature_name_len = build_u2_from((address)signature_name);
+  signature_name += 2;
+  // The class should have been loaded so the method and signature should already be
+  // in the symbol table.  If they're not there, the method doesn't exist.
+  TempNewSymbol name = SymbolTable::probe(method_name, method_name_len);
+  TempNewSymbol signature = SymbolTable::probe(signature_name, signature_name_len);
+
+  Method* m;
+  if (name == NULL || signature == NULL) {
+    m = NULL;
+  } else if (name == vmSymbols::object_initializer_name() ||
+             name == vmSymbols::class_initializer_name()) {
+    // Never search superclasses for constructors
+    if (klass->is_instance_klass()) {
+      m = InstanceKlass::cast(klass())->find_method(name, signature);
+    } else {
+      m = NULL;
+    }
+  } else {
+    m = klass->lookup_method(name, signature);
+    if (m == NULL && klass->is_instance_klass()) {
+      m = InstanceKlass::cast(klass())->lookup_method_in_ordered_interfaces(name, signature);
+    }
+  }
+  if (m == NULL) {
+    // Fatal error because we assume classes and methods should not be changed since aot compilation.
+    const char* klass_name = klass->external_name();
+    int klass_len = (int)strlen(klass_name);
+    char* meta_name = NEW_RESOURCE_ARRAY(char, klass_len + 1 + method_name_len + signature_name_len + 1);
+    memcpy(meta_name, klass_name, klass_len);
+    meta_name[klass_len] = '.';
+    memcpy(&meta_name[klass_len + 1], method_name, method_name_len);
+    memcpy(&meta_name[klass_len + 1 + method_name_len], signature_name, signature_name_len);
+    meta_name[klass_len + 1 + method_name_len + signature_name_len] = '\0';
+    Handle exception = Exceptions::new_exception(thread, vmSymbols::java_lang_NoSuchMethodError(), meta_name);
+    java_lang_Throwable::print(exception, tty);
+    tty->cr();
+    java_lang_Throwable::print_stack_trace(exception(), tty);
+    tty->cr();
+    fatal("Failed to find method '%s'", meta_name);
+  }
+  NOT_PRODUCT( aot_methods_found++; )
+  return m;
+}
+
+AOTKlassData* AOTCodeHeap::find_klass(InstanceKlass* ik) {
+  ResourceMark rm;
+  AOTKlassData* klass_data = (AOTKlassData*) dlsym(_lib->dl_handle(), ik->signature_name());
+  return klass_data;
+}
+
+bool AOTCodeHeap::is_dependent_method(Klass* dependee, AOTCompiledMethod* aot) {
+  InstanceKlass *dependee_ik = InstanceKlass::cast(dependee);
+  AOTKlassData* klass_data = find_klass(dependee_ik);
+  if (klass_data == NULL) {
+    return false; // no AOT records for this class - no dependencies
+  }
+  if (!dependee_ik->has_passed_fingerprint_check()) {
+    return false; // different class
+  }
+
+  int methods_offset = klass_data->_dependent_methods_offset;
+  if (methods_offset >= 0) {
+    address methods_cnt_adr = _dependencies + methods_offset;
+    int methods_cnt = *(int*)methods_cnt_adr;
+    int* indexes = (int*)(methods_cnt_adr + 4);
+    for (int i = 0; i < methods_cnt; ++i) {
+      int code_id = indexes[i];
+      if (_code_to_aot[code_id]._aot == aot) {
+        return true; // found dependent method
+      }
+    }
+  }
+  return false;
+}
+
+void AOTCodeHeap::sweep_dependent_methods(AOTKlassData* klass_data) {
+  // Make dependent methods non_entrant forever.
+  int methods_offset = klass_data->_dependent_methods_offset;
+  if (methods_offset >= 0) {
+    int marked = 0;
+    address methods_cnt_adr = _dependencies + methods_offset;
+    int methods_cnt = *(int*)methods_cnt_adr;
+    int* indexes = (int*)(methods_cnt_adr + 4);
+    for (int i = 0; i < methods_cnt; ++i) {
+      int code_id = indexes[i];
+      // Invalidate aot code.
+      if (Atomic::cmpxchg(invalid, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+        if (_code_to_aot[code_id]._state == in_use) {
+          AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
+          assert(aot != NULL, "aot should be set");
+          if (!aot->is_runtime_stub()) { // Something is wrong - should not invalidate stubs.
+            aot->mark_for_deoptimization(false);
+            marked++;
+          }
+        }
+      }
+    }
+    if (marked > 0) {
+      VM_Deoptimize op;
+      VMThread::execute(&op);
+    }
+  }
+}
+
+bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) {
+  ResourceMark rm;
+
+  NOT_PRODUCT( klasses_seen++; )
+
+  AOTKlassData* klass_data = find_klass(kh());
+  if (klass_data == NULL) {
+    return false;
+  }
+
+  if (!kh->has_passed_fingerprint_check()) {
+    NOT_PRODUCT( aot_klasses_fp_miss++; )
+    log_trace(aot, class, fingerprint)("class  %s%s  has bad fingerprint in  %s tid=" INTPTR_FORMAT,
+                                   kh->internal_name(), kh->is_shared() ? " (shared)" : "",
+                                   _lib->name(), p2i(thread));
+    sweep_dependent_methods(klass_data);
+    return false;
+  }
+
+  if (kh->has_been_redefined()) {
+    log_trace(aot, class, load)("class  %s%s in %s  has been redefined tid=" INTPTR_FORMAT,
+                                   kh->internal_name(), kh->is_shared() ? " (shared)" : "",
+                                   _lib->name(), p2i(thread));
+    sweep_dependent_methods(klass_data);
+    return false;
+  }
+
+  assert(klass_data->_class_id < _class_count, "invalid class id");
+  AOTClass* aot_class = &_classes[klass_data->_class_id];
+  if (aot_class->_classloader != NULL && aot_class->_classloader != kh->class_loader_data()) {
+    log_trace(aot, class, load)("class  %s  in  %s already loaded for classloader %p vs %p tid=" INTPTR_FORMAT,
+                             kh->internal_name(), _lib->name(), aot_class->_classloader, kh->class_loader_data(), p2i(thread));
+    NOT_PRODUCT( aot_klasses_cl_miss++; )
+    return false;
+  }
+
+  NOT_PRODUCT( aot_klasses_found++; )
+
+  log_trace(aot, class, load)("found  %s  in  %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread));
+
+  aot_class->_classloader = kh->class_loader_data();
+  // Set klass's Resolve (second) got cell.
+  _metaspace_got[klass_data->_got_index] = kh();
+
+  // Initialize global symbols of the DSO to the correspondingVM symbol values.
+  link_global_lib_symbols();
+
+  int methods_offset = klass_data->_compiled_methods_offset;
+  if (methods_offset >= 0) {
+    address methods_cnt_adr = _methods_offsets + methods_offset;
+    int methods_cnt = *(int*)methods_cnt_adr;
+    // Collect data about compiled methods
+    AOTMethodData* methods_data = NEW_RESOURCE_ARRAY(AOTMethodData, methods_cnt);
+    AOTMethodOffsets* methods_offsets = (AOTMethodOffsets*)(methods_cnt_adr + 4);
+    for (int i = 0; i < methods_cnt; ++i) {
+      AOTMethodOffsets* method_offsets = &methods_offsets[i];
+      int code_id = method_offsets->_code_id;
+      if (_code_to_aot[code_id]._state == invalid) {
+        continue; // skip AOT methods slots which have been invalidated
+      }
+      AOTMethodData* method_data = &methods_data[i];
+      const char* aot_name = _metaspace_names + method_offsets->_name_offset;
+      method_data->_name = aot_name;
+      method_data->_code = _code_space  + method_offsets->_code_offset;
+      method_data->_meta = (aot_metadata*)(_method_metadata + method_offsets->_meta_offset);
+      method_data->_metadata_table = (address)_metadata_got + method_offsets->_metadata_got_offset;
+      method_data->_metadata_size  = method_offsets->_metadata_got_size;
+      // aot_name format: "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+      int klass_len = build_u2_from((address)aot_name);
+      const char* method_name = aot_name + 2 + klass_len;
+      Method* m = AOTCodeHeap::find_method(kh, thread, method_name);
+      methodHandle mh(thread, m);
+      if (mh->code() != NULL) { // Does it have already compiled code?
+        continue; // Don't overwrite
+      }
+      publish_aot(mh, method_data, code_id);
+    }
+  }
+  return true;
+}
+
+AOTCompiledMethod* AOTCodeHeap::next_in_use_at(int start) const {
+  for (int index = start; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    return aot;
+  }
+  return NULL;
+}
+
+void* AOTCodeHeap::first() const {
+  return next_in_use_at(0);
+}
+
+void* AOTCodeHeap::next(void* p) const {
+  AOTCompiledMethod *aot = (AOTCompiledMethod *)p;
+  int next_index = aot->method_index() + 1;
+  assert(next_index <= _method_count, "");
+  if (next_index == _method_count) {
+    return NULL;
+  }
+  return next_in_use_at(next_index);
+}
+
+void* AOTCodeHeap::find_start(void* p) const {
+  if (!contains(p)) {
+    return NULL;
+  }
+  size_t offset = pointer_delta(p, low_boundary(), 1);
+  // Use segments table
+  size_t seg_idx = offset / _lib->config()->_codeSegmentSize;
+  if ((int)(_code_segments[seg_idx]) == 0xff) {
+    return NULL;
+  }
+  while (_code_segments[seg_idx] > 0) {
+    seg_idx -= (int)_code_segments[seg_idx];
+  }
+  int code_offset = (int)seg_idx * _lib->config()->_codeSegmentSize;
+  int aot_index = *(int*)(_code_space + code_offset);
+  AOTCompiledMethod* aot = _code_to_aot[aot_index]._aot;
+  assert(aot != NULL, "should find registered aot method");
+  return aot;
+}
+
+AOTCompiledMethod* AOTCodeHeap::find_aot(address p) const {
+  assert(contains(p), "should be here");
+  return (AOTCompiledMethod *)find_start(p);
+}
+
+CodeBlob* AOTCodeHeap::find_blob_unsafe(void* start) const {
+  return (CodeBlob*)AOTCodeHeap::find_start(start);
+}
+
+void AOTCodeHeap::oops_do(OopClosure* f) {
+  for (int i = 0; i < _oop_got_size; i++) {
+    oop* p = &_oop_got[i];
+    if (*p == NULL)  continue;  // skip non-oops
+    f->do_oop(p);
+  }
+  for (int index = 0; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    aot->do_oops(f);
+  }
+}
+
+// Yes, this is faster than going through the relocations,
+// but there are two problems:
+// 1) GOT slots are sometimes patched with non-Metadata values
+// 2) We don't want to scan metadata for dead methods
+// Unfortunately we don't know if the metadata belongs to
+// live aot methods or not, so process them all.  If this
+// is for mark_on_stack, some old methods may stick around
+// forever instead of getting cleaned up.
+void AOTCodeHeap::got_metadata_do(void f(Metadata*)) {
+  for (int i = 1; i < _metaspace_got_size; i++) {
+    Metadata** p = &_metaspace_got[i];
+    Metadata* md = *p;
+    if (md == NULL)  continue;  // skip non-oops
+    intptr_t meta = (intptr_t)md;
+    if (meta == -1)  continue;  // skip non-oops
+    if (Metaspace::contains(md)) {
+      f(md);
+    }
+  }
+  for (int i = 1; i < _metadata_got_size; i++) {
+    Metadata** p = &_metadata_got[i];
+    Metadata* md = *p;
+    intptr_t meta = (intptr_t)md;
+    if ((meta & 1) == 1) {
+      // already resolved
+      md = (Metadata*)(meta & ~1);
+    } else {
+      continue;
+    }
+    if (md == NULL)  continue;  // skip non-oops
+    if (Metaspace::contains(md)) {
+      f(md);
+    }
+  }
+}
+
+void AOTCodeHeap::cleanup_inline_caches() {
+  for (int index = 0; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    aot->cleanup_inline_caches();
+  }
+}
+
+#ifdef ASSERT
+int AOTCodeHeap::verify_icholder_relocations() {
+  int count = 0;
+  for (int index = 0; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    count += aot->verify_icholder_relocations();
+  }
+  return count;
+}
+#endif
+
+void AOTCodeHeap::flush_evol_dependents_on(instanceKlassHandle dependee) {
+  for (int index = 0; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    aot->flush_evol_dependents_on(dependee);
+  }
+}
+
+void AOTCodeHeap::metadata_do(void f(Metadata*)) {
+  for (int index = 0; index < _method_count; index++) {
+    if (_code_to_aot[index]._state != in_use) {
+      continue; // Skip uninitialized entries.
+    }
+    AOTCompiledMethod* aot = _code_to_aot[index]._aot;
+    if (aot->_is_alive()) {
+      aot->metadata_do(f);
+    }
+  }
+#if 0
+  // With the marking above, this call doesn't seem to be needed
+  got_metadata_do(f);
+#endif
+}
diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.hpp b/hotspot/src/share/vm/aot/aotCodeHeap.hpp
new file mode 100644
index 0000000..21ce9a0
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_AOT_AOTCODEHEAP_HPP
+#define SHARE_VM_AOT_AOTCODEHEAP_HPP
+
+#include "aot/aotCompiledMethod.hpp"
+#include "classfile/symbolTable.hpp"
+#include "oops/metadata.hpp"
+#include "oops/method.hpp"
+
+enum CodeState {
+  not_set = 0, // _aot fields is not set yet
+  in_use  = 1, // _aot field is set to corresponding AOTCompiledMethod
+  invalid = 2  // AOT code is invalidated because dependencies failed
+};
+
+typedef struct {
+  AOTCompiledMethod* _aot;
+  CodeState _state; // State change cases: not_set->in_use, not_set->invalid
+} CodeToAMethod;
+
+class ClassLoaderData;
+
+class AOTClass {
+public:
+  ClassLoaderData* _classloader;
+};
+
+typedef struct {
+  int _name_offset;
+  int _code_offset;
+  int _meta_offset;
+  int _metadata_got_offset;
+  int _metadata_got_size;
+  int _code_id;
+} AOTMethodOffsets;
+
+typedef struct {
+  const char* _name;
+  address     _code;
+  aot_metadata* _meta;
+  jlong*      _state_adr;
+  address     _metadata_table;
+  int         _metadata_size;
+} AOTMethodData;
+
+typedef struct {
+  int _got_index;
+  int _class_id;
+  int _compiled_methods_offset;
+  int _dependent_methods_offset;
+  uint64_t _fingerprint;
+} AOTKlassData;
+
+typedef struct {
+  int _version;
+  int _class_count;
+  int _method_count;
+  int _metaspace_got_size;
+  int _metadata_got_size;
+  int _oop_got_size;
+  int _jvm_version_offset;
+
+  enum {
+    AOT_SHARED_VERSION = 1
+  };
+} AOTHeader;
+
+typedef struct {
+  enum { CONFIG_SIZE = 11 + 7 * 4 };
+  int _config_size;
+  int _narrowOopShift;
+  int _narrowKlassShift;
+  int _contendedPaddingWidth;
+  int _fieldsAllocationStyle;
+  int _objectAlignment;
+  int _codeSegmentSize;
+  // byte[11] array map to boolean values here
+  bool _debug_VM;
+  bool _useCompressedOops;
+  bool _useCompressedClassPointers;
+  bool _compactFields;
+  bool _useG1GC;
+  bool _useCMSGC;
+  bool _useTLAB;
+  bool _useBiasedLocking;
+  bool _tieredAOT;
+  bool _enableContended;
+  bool _restrictContended;
+} AOTConfiguration;
+
+class AOTLib : public CHeapObj<mtCode> {
+  static bool _narrow_oop_shift_initialized;
+  static int _narrow_oop_shift;
+  static int _narrow_klass_shift;
+
+  bool _valid;
+  void* _dl_handle;
+  const int _dso_id;
+  const char* _name;
+  // VM configuration during AOT compilation
+  AOTConfiguration* _config;
+  AOTHeader* _header;
+
+  void handle_config_error(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
+public:
+  AOTLib(void* handle, const char* name, int dso_id);
+  virtual ~AOTLib();
+  static int  narrow_oop_shift() { return _narrow_oop_shift; }
+  static int  narrow_klass_shift() { return _narrow_klass_shift; }
+  static bool narrow_oop_shift_initialized() { return _narrow_oop_shift_initialized; }
+
+  bool is_valid() const {
+    return _valid;
+  }
+  const char* name() const {
+    return _name;
+  }
+  void* dl_handle() const {
+    return _dl_handle;
+  }
+  int id() const {
+    return _dso_id;
+  }
+  AOTHeader* header() const {
+    return _header;
+  }
+  AOTConfiguration* config() const {
+    return _config;
+  }
+  void verify_config();
+  void verify_flag(bool aot_flag, bool flag, const char* name);
+  void verify_flag(int  aot_flag, int  flag, const char* name);
+
+  address load_symbol(const char *name);
+};
+
+
+class AOTCodeHeap : public CodeHeap {
+  AOTLib* _lib;
+  int _aot_id;
+
+  int _class_count;
+  int _method_count;
+  AOTClass* _classes;
+  CodeToAMethod* _code_to_aot;
+
+  address _code_space;
+  address _code_segments;
+  jlong*  _method_state;
+
+
+  // Collect metaspace info: names -> address in .got section
+  const char* _metaspace_names;
+  address _method_metadata;
+
+  address _methods_offsets;
+  address _klasses_offsets;
+  address _dependencies;
+
+  Metadata** _metaspace_got;
+  Metadata** _metadata_got;
+  oop*    _oop_got;
+
+  int _metaspace_got_size;
+  int _metadata_got_size;
+  int _oop_got_size;
+
+  // Collect stubs info
+  int* _stubs_offsets;
+
+  address _low_boundary;
+
+  bool _lib_symbols_initialized;
+
+  void adjust_boundaries(AOTCompiledMethod* method) {
+    address low = _low_boundary;
+    if (method->code_begin() < low) {
+      low = method->code_begin();
+    }
+    address high = high_boundary();
+    if (method->code_end() > high) {
+      high = method->code_end();
+    }
+    assert(_method_count > 0, "methods count should be set already");
+
+    _low_boundary = low;
+    _memory.set_high_boundary((char *)high);
+    _memory.set_high((char *)high);
+  }
+
+  void register_stubs();
+
+  void link_shared_runtime_symbols();
+  void link_stub_routines_symbols();
+  void link_os_symbols();
+  void link_graal_runtime_symbols();
+
+  void link_global_lib_symbols();
+  void link_primitive_array_klasses();
+  void publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id);
+
+
+  AOTCompiledMethod* next_in_use_at(int index) const;
+
+  // Find klass in SystemDictionary for aot metadata.
+  static Klass* lookup_klass(const char* name, int len, const Method* method, Thread* THREAD);
+public:
+  AOTCodeHeap(AOTLib* lib);
+  virtual ~AOTCodeHeap();
+
+  address low_boundary()  const { return _low_boundary; }
+  address high_boundary() const { return (address)CodeHeap::high(); }
+
+  bool contains(const void* p) const {
+    bool result = (low_boundary() <= p) && (p < high_boundary());
+    assert(!result || (_method_count > 0), "");
+    assert(result == CodeHeap::contains(p), "");
+    return result;
+  }
+  AOTCompiledMethod* find_aot(address p) const;
+
+  virtual void* find_start(void* p)     const;
+  virtual CodeBlob* find_blob_unsafe(void* start) const;
+  virtual void* first() const;
+  virtual void* next(void *p) const;
+
+  AOTKlassData* find_klass(InstanceKlass* ik);
+  bool load_klass_data(instanceKlassHandle kh, Thread* thread);
+  Klass* get_klass_from_got(const char* klass_name, int klass_len, const Method* method);
+  void sweep_dependent_methods(AOTKlassData* klass_data);
+  bool is_dependent_method(Klass* dependee, AOTCompiledMethod* aot);
+
+  const char* get_name_at(int offset) {
+    return _metaspace_names + offset;
+  }
+
+  void oops_do(OopClosure* f);
+  void metadata_do(void f(Metadata*));
+  void got_metadata_do(void f(Metadata*));
+
+#ifdef ASSERT
+  bool got_contains(Metadata **p) {
+    return (p >= &_metadata_got[0] && p < &_metadata_got[_metadata_got_size]) ||
+           (p >= &_metaspace_got[0] && p < &_metaspace_got[_metaspace_got_size]);
+  }
+#endif
+
+  int dso_id() const { return _lib->id(); }
+  int aot_id() const { return _aot_id; }
+
+  int method_count() { return _method_count; }
+
+  AOTCompiledMethod* get_code_desc_at_index(int index) {
+    if (index < _method_count && _code_to_aot[index]._state == in_use) {
+        AOTCompiledMethod* m = _code_to_aot[index]._aot;
+        assert(m != NULL, "AOT method should be set");
+        if (!m->is_runtime_stub()) {
+          return m;
+        }
+    }
+    return NULL;
+  }
+
+  static Method* find_method(KlassHandle klass, Thread* thread, const char* method_name);
+
+  void cleanup_inline_caches();
+
+  DEBUG_ONLY( int verify_icholder_relocations(); )
+
+  void flush_evol_dependents_on(instanceKlassHandle dependee);
+
+  void alive_methods_do(void f(CompiledMethod* nm));
+
+#ifndef PRODUCT
+  static int klasses_seen;
+  static int aot_klasses_found;
+  static int aot_klasses_fp_miss;
+  static int aot_klasses_cl_miss;
+  static int aot_methods_found;
+
+  static void print_statistics();
+#endif
+};
+
+#endif // SHARE_VM_AOT_AOTCODEHEAP_HPP
diff --git a/hotspot/src/share/vm/aot/aotCompiledMethod.cpp b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp
new file mode 100644
index 0000000..1f40284
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.hpp"
+#include "aot/compiledIC_aot.hpp"
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/nativeInst.hpp"
+#include "compiler/compilerOracle.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/gcLocker.hpp"
+#include "jvmci/compilerRuntime.hpp"
+#include "jvmci/jvmciRuntime.hpp"
+#include "oops/method.hpp"
+#include "runtime/java.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "utilities/array.hpp"
+#include "utilities/xmlstream.hpp"
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#if 0
+static void metadata_oops_do(Metadata** metadata_begin, Metadata **metadata_end, OopClosure* f) {
+  // Visit the metadata/oops section
+  for (Metadata** p = metadata_begin; p < metadata_end; p++) {
+    Metadata* m = *p;
+
+    intptr_t meta = (intptr_t)m;
+    if ((meta & 1) == 1) {
+      // already resolved
+      m = (Metadata*)(meta & ~1);
+    } else {
+      continue;
+    }
+    assert(Metaspace::contains(m), "");
+    if (m->is_method()) {
+      m = ((Method*)m)->method_holder();
+    }
+    assert(m->is_klass(), "must be");
+    oop o = ((Klass*)m)->klass_holder();
+    if (o != NULL) {
+      f->do_oop(&o);
+    }
+  }
+}
+#endif
+
+void AOTCompiledMethod::oops_do(OopClosure* f) {
+  if (_oop != NULL) {
+    f->do_oop(&_oop);
+  }
+#if 0
+  metadata_oops_do(metadata_begin(), metadata_end(), f);
+#endif
+}
+
+bool AOTCompiledMethod::do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred) {
+  return false;
+}
+
+oop AOTCompiledMethod::oop_at(int index) const {
+  if (index == 0) { // 0 is reserved
+    return NULL;
+  }
+  Metadata** entry = _metadata_got + (index - 1);
+  intptr_t meta = (intptr_t)*entry;
+  if ((meta & 1) == 1) {
+    // already resolved
+    Klass* k = (Klass*)(meta & ~1);
+    return k->java_mirror();
+  }
+  // The entry is string which we need to resolve.
+  const char* meta_name = _heap->get_name_at((int)meta);
+  int klass_len = build_u2_from((address)meta_name);
+  const char* klass_name = meta_name + 2;
+  // Quick check the current method's holder.
+  Klass* k = _method->method_holder();
+
+  ResourceMark rm; // for signature_name()
+  if (strncmp(k->signature_name(), klass_name, klass_len) != 0) { // Does not match?
+    // Search klass in got cells in DSO which have this compiled method.
+    k = _heap->get_klass_from_got(klass_name, klass_len, _method);
+  }
+  int method_name_len = build_u2_from((address)klass_name + klass_len);
+  guarantee(method_name_len == 0, "only klass is expected here");
+  meta = ((intptr_t)k) | 1;
+  *entry = (Metadata*)meta; // Should be atomic on x64
+  return k->java_mirror();
+}
+
+Metadata* AOTCompiledMethod::metadata_at(int index) const {
+  if (index == 0) { // 0 is reserved
+    return NULL;
+  }
+  assert(index - 1 < _metadata_size, "");
+  {
+    Metadata** entry = _metadata_got + (index - 1);
+    intptr_t meta = (intptr_t)*entry;
+    if ((meta & 1) == 1) {
+      // already resolved
+      Metadata *m = (Metadata*)(meta & ~1);
+      return m;
+    }
+    // The entry is string which we need to resolve.
+    const char* meta_name = _heap->get_name_at((int)meta);
+    int klass_len = build_u2_from((address)meta_name);
+    const char* klass_name = meta_name + 2;
+    // Quick check the current method's holder.
+    Klass* k = _method->method_holder();
+    bool klass_matched = true;
+
+    ResourceMark rm; // for signature_name() and find_method()
+    if (strncmp(k->signature_name(), klass_name, klass_len) != 0) { // Does not match?
+      // Search klass in got cells in DSO which have this compiled method.
+      k = _heap->get_klass_from_got(klass_name, klass_len, _method);
+      klass_matched = false;
+    }
+    int method_name_len = build_u2_from((address)klass_name + klass_len);
+    if (method_name_len == 0) { // Array or Klass name only?
+      meta = ((intptr_t)k) | 1;
+      *entry = (Metadata*)meta; // Should be atomic on x64
+      return (Metadata*)k;
+    } else { // Method
+      // Quick check the current method's name.
+      Method* m = _method;
+      int signature_len = build_u2_from((address)klass_name + klass_len + 2 + method_name_len);
+      int full_len = 2 + klass_len + 2 + method_name_len + 2 + signature_len;
+      if (!klass_matched || memcmp(_name, meta_name, full_len) != 0) { // Does not match?
+        Thread* thread = Thread::current();
+        KlassHandle klass = KlassHandle(thread, k);
+        const char* method_name = klass_name + klass_len;
+        m = AOTCodeHeap::find_method(klass, thread, method_name);
+      }
+      meta = ((intptr_t)m) | 1;
+      *entry = (Metadata*)meta; // Should be atomic on x64
+      return (Metadata*)m;
+    }
+    // need to resolve it here..., patching of GOT need to be CAS or atomic operation.
+    // FIXIT: need methods for debuginfo.
+    // return _method;
+  }
+  ShouldNotReachHere(); return NULL;
+}
+
+bool AOTCompiledMethod::make_not_entrant_helper(int new_state) {
+  // Make sure the method is not flushed in case of a safepoint in code below.
+  methodHandle the_method(method());
+  NoSafepointVerifier nsv;
+
+  {
+    // Enter critical section.  Does not block for safepoint.
+    MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
+
+    if (*_state_adr == new_state) {
+      // another thread already performed this transition so nothing
+      // to do, but return false to indicate this.
+      return false;
+    }
+
+    // Change state
+    OrderAccess::storestore();
+    *_state_adr = new_state;
+
+    // Log the transition once
+    log_state_change();
+
+#ifdef TIERED
+    // Remain non-entrant forever
+    if (new_state == not_entrant && method() != NULL) {
+        method()->set_aot_code(NULL);
+    }
+#endif
+
+    // Remove AOTCompiledMethod from method.
+    if (method() != NULL && (method()->code() == this ||
+                             method()->from_compiled_entry() == verified_entry_point())) {
+      HandleMark hm;
+      method()->clear_code(false /* already owns Patching_lock */);
+    }
+  } // leave critical region under Patching_lock
+
+
+  if (TraceCreateZombies) {
+    ResourceMark m;
+    const char *new_state_str = (new_state == not_entrant) ? "not entrant" : "not used";
+    tty->print_cr("aot method <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", new_state_str);
+  }
+
+  return true;
+}
+
+bool AOTCompiledMethod::make_entrant() {
+  assert(!method()->is_old(), "reviving evolved method!");
+  assert(*_state_adr != not_entrant, "%s", method()->has_aot_code() ? "has_aot_code() not cleared" : "caller didn't check has_aot_code()");
+
+  // Make sure the method is not flushed in case of a safepoint in code below.
+  methodHandle the_method(method());
+  NoSafepointVerifier nsv;
+
+  {
+    // Enter critical section.  Does not block for safepoint.
+    MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
+
+    if (*_state_adr == in_use) {
+      // another thread already performed this transition so nothing
+      // to do, but return false to indicate this.
+      return false;
+    }
+
+    // Change state
+    OrderAccess::storestore();
+    *_state_adr = in_use;
+
+    // Log the transition once
+    log_state_change();
+  } // leave critical region under Patching_lock
+
+
+  if (TraceCreateZombies) {
+    ResourceMark m;
+    tty->print_cr("aot method <" INTPTR_FORMAT "> %s code made entrant", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null");
+  }
+
+  return true;
+}
+
+// We don't have full dependencies for AOT methods, so flushing is
+// more conservative than for nmethods.
+void AOTCompiledMethod::flush_evol_dependents_on(instanceKlassHandle dependee) {
+  if (is_java_method()) {
+    cleanup_inline_caches();
+    mark_for_deoptimization();
+    make_not_entrant();
+  }
+}
+
+// Iterate over metadata calling this function.   Used by RedefineClasses
+// Copied from nmethod::metadata_do
+void AOTCompiledMethod::metadata_do(void f(Metadata*)) {
+  address low_boundary = verified_entry_point();
+  {
+    // Visit all immediate references that are embedded in the instruction stream.
+    RelocIterator iter(this, low_boundary);
+    while (iter.next()) {
+      if (iter.type() == relocInfo::metadata_type ) {
+        metadata_Relocation* r = iter.metadata_reloc();
+        // In this metadata, we must only follow those metadatas directly embedded in
+        // the code.  Other metadatas (oop_index>0) are seen as part of
+        // the metadata section below.
+        assert(1 == (r->metadata_is_immediate()) +
+               (r->metadata_addr() >= metadata_begin() && r->metadata_addr() < metadata_end()),
+               "metadata must be found in exactly one place");
+        if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
+          Metadata* md = r->metadata_value();
+          if (md != _method) f(md);
+        }
+      } else if (iter.type() == relocInfo::virtual_call_type) {
+        // Check compiledIC holders associated with this nmethod
+        CompiledIC *ic = CompiledIC_at(&iter);
+        if (ic->is_icholder_call()) {
+          CompiledICHolder* cichk = ic->cached_icholder();
+          f(cichk->holder_method());
+          f(cichk->holder_klass());
+        } else {
+          Metadata* ic_oop = ic->cached_metadata();
+          if (ic_oop != NULL) {
+            f(ic_oop);
+          }
+        }
+      }
+    }
+  }
+
+  // Visit the metadata section
+  for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
+    Metadata* m = *p;
+
+    intptr_t meta = (intptr_t)m;
+    if ((meta & 1) == 1) {
+      // already resolved
+      m = (Metadata*)(meta & ~1);
+    } else {
+      continue;
+    }
+    assert(Metaspace::contains(m), "");
+    f(m);
+  }
+
+  // Visit metadata not embedded in the other places.
+  if (_method != NULL) f(_method);
+}
+
+void AOTCompiledMethod::print() const {
+  print_on(tty, "AOTCompiledMethod");
+}
+
+void AOTCompiledMethod::print_on(outputStream* st) const {
+  print_on(st, "AOTCompiledMethod");
+}
+
+// Print out more verbose output usually for a newly created aot method.
+void AOTCompiledMethod::print_on(outputStream* st, const char* msg) const {
+  if (st != NULL) {
+    ttyLocker ttyl;
+    st->print("%7d ", (int) st->time_stamp().milliseconds());
+    st->print("%4d ", _aot_id);    // print compilation number
+    st->print("    aot[%2d]", _heap->dso_id());
+    // Stubs have _method == NULL
+    st->print("   %s", (_method == NULL ? _name : _method->name_and_sig_as_C_string()));
+    if (Verbose) {
+      st->print(" entry at " INTPTR_FORMAT, p2i(_code));
+    }
+    if (msg != NULL) {
+      st->print("   %s", msg);
+    }
+    st->cr();
+  }
+}
+
+void AOTCompiledMethod::print_value_on(outputStream* st) const {
+  st->print("AOTCompiledMethod ");
+  print_on(st, NULL);
+}
+
+// Print a short set of xml attributes to identify this aot method.  The
+// output should be embedded in some other element.
+void AOTCompiledMethod::log_identity(xmlStream* log) const {
+  log->print(" aot_id='%d'", _aot_id);
+  log->print(" aot='%2d'", _heap->dso_id());
+}
+
+void AOTCompiledMethod::log_state_change() const {
+  if (LogCompilation) {
+    ResourceMark m;
+    if (xtty != NULL) {
+      ttyLocker ttyl;  // keep the following output all in one block
+      if (*_state_adr == not_entrant) {
+        xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'",
+                         os::current_thread_id());
+      } else if (*_state_adr == not_used) {
+        xtty->begin_elem("make_not_used thread='" UINTX_FORMAT "'",
+                         os::current_thread_id());
+      } else if (*_state_adr == in_use) {
+        xtty->begin_elem("make_entrant thread='" UINTX_FORMAT "'",
+                         os::current_thread_id());
+      }
+      log_identity(xtty);
+      xtty->stamp();
+      xtty->end_elem();
+    }
+  }
+  if (PrintCompilation) {
+    ResourceMark m;
+    if (*_state_adr == not_entrant) {
+      print_on(tty, "made not entrant");
+    } else if (*_state_adr == not_used) {
+      print_on(tty, "made not used");
+    } else if (*_state_adr == in_use) {
+      print_on(tty, "made entrant");
+    }
+  }
+}
+
+
+NativeInstruction* PltNativeCallWrapper::get_load_instruction(virtual_call_Relocation* r) const {
+  return nativeLoadGot_at(_call->plt_load_got());
+}
+
+void PltNativeCallWrapper::verify_resolve_call(address dest) const {
+  CodeBlob* db = CodeCache::find_blob_unsafe(dest);
+  if (db == NULL) {
+    assert(dest == _call->plt_resolve_call(), "sanity");
+  }
+}
+
+void PltNativeCallWrapper::set_to_interpreted(const methodHandle& method, CompiledICInfo& info) {
+  assert(!info.to_aot(), "only for nmethod");
+  CompiledPltStaticCall* csc = CompiledPltStaticCall::at(instruction_address());
+  csc->set_to_interpreted(method, info.entry());
+}
+
+NativeCallWrapper* AOTCompiledMethod::call_wrapper_at(address call) const {
+  return new PltNativeCallWrapper((NativePltCall*) call);
+}
+
+NativeCallWrapper* AOTCompiledMethod::call_wrapper_before(address return_pc) const {
+  return new PltNativeCallWrapper(nativePltCall_before(return_pc));
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_at(Relocation* call_site) const {
+  return CompiledPltStaticCall::at(call_site);
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_at(address call_site) const {
+  return CompiledPltStaticCall::at(call_site);
+}
+
+CompiledStaticCall* AOTCompiledMethod::compiledStaticCall_before(address return_addr) const {
+  return CompiledPltStaticCall::before(return_addr);
+}
+
+address AOTCompiledMethod::call_instruction_address(address pc) const {
+  NativePltCall* pltcall = nativePltCall_before(pc);
+  return pltcall->instruction_address();
+}
+
+bool AOTCompiledMethod::is_evol_dependent_on(Klass* dependee) {
+  return !is_aot_runtime_stub() && _heap->is_dependent_method(dependee, this);
+}
+
+void AOTCompiledMethod::clear_inline_caches() {
+  assert(SafepointSynchronize::is_at_safepoint(), "cleaning of IC's only allowed at safepoint");
+  if (is_zombie()) {
+    return;
+  }
+
+  RelocIterator iter(this);
+  while (iter.next()) {
+    iter.reloc()->clear_inline_cache();
+    if (iter.type() == relocInfo::opt_virtual_call_type) {
+      CompiledIC* cic = CompiledIC_at(&iter);
+      assert(cic->is_clean(), "!");
+      nativePltCall_at(iter.addr())->set_stub_to_clean();
+    }
+  }
+}
+
diff --git a/hotspot/src/share/vm/aot/aotCompiledMethod.hpp b/hotspot/src/share/vm/aot/aotCompiledMethod.hpp
new file mode 100644
index 0000000..7fef6fd
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotCompiledMethod.hpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_AOT_AOTCOMPILEDMETHOD_HPP
+#define SHARE_VM_AOT_AOTCOMPILEDMETHOD_HPP
+
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/compiledMethod.hpp"
+#include "code/pcDesc.hpp"
+#include "code/relocInfo.hpp"
+
+class AOTCodeHeap;
+
+class aot_metadata {
+private:
+  int _size;
+  int _code_size;
+  int _entry;
+  int _verified_entry;
+  int _exception_handler_offset;
+  int _deopt_handler_offset;
+  int _stubs_offset;
+  int _frame_size;
+  // location in frame (offset for sp) that deopt can store the original
+  // pc during a deopt.
+  int _orig_pc_offset;
+  int _unsafe_access;
+
+  int _pc_desc_begin;
+  int _scopes_begin;
+  int _reloc_begin;
+  int _exception_table_begin;
+  int _oopmap_begin;
+  address at_offset(size_t offset) const { return ((address) this) + offset; }
+public:
+  int code_size() const { return _code_size; }
+  int frame_size() const { return _frame_size / HeapWordSize; }
+  PcDesc *scopes_pcs_begin() const { return (PcDesc *) at_offset(_pc_desc_begin); }
+  PcDesc *scopes_pcs_end() const { return (PcDesc *) at_offset(_scopes_begin); }
+  address scopes_data_begin() const { return at_offset(_scopes_begin); }
+  address scopes_data_end() const { return at_offset(_reloc_begin); }
+  relocInfo* relocation_begin() const { return (relocInfo*) at_offset(_reloc_begin); }
+  relocInfo* relocation_end() const { return (relocInfo*) at_offset(_exception_table_begin); }
+  address handler_table_begin   () const { return at_offset(_exception_table_begin); }
+  address handler_table_end() const { return at_offset(_oopmap_begin); }
+
+  address nul_chk_table_begin() const { return at_offset(_oopmap_begin); }
+  address nul_chk_table_end() const { return at_offset(_oopmap_begin); }
+
+  ImmutableOopMapSet* oopmap_set() const { return (ImmutableOopMapSet*) at_offset(_oopmap_begin); }
+
+  address consts_begin() const { return at_offset(_size); }
+  address consts_end() const { return at_offset(_size); }
+  int stub_offset() const { return _stubs_offset; }
+  int entry_offset() const { return _entry; }
+  int verified_entry_offset() const { return _verified_entry; }
+  int exception_handler_offset() const { return _exception_handler_offset; }
+  int deopt_handler_offset() const { return _deopt_handler_offset; }
+  int orig_pc_offset() const { return _orig_pc_offset; }
+
+  int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
+  int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
+  bool has_unsafe_access() const { return _unsafe_access != 0; }
+
+};
+
+/*
+ * Use this for AOTCompiledMethods since a lot of the fields in CodeBlob gets the same
+ * value when they come from AOT. code_begin == content_begin, etc... */
+class AOTCompiledMethodLayout : public CodeBlobLayout {
+public:
+  AOTCompiledMethodLayout(address code_begin, address code_end, address relocation_begin, address relocation_end) :
+    CodeBlobLayout(
+        code_begin, // code_begin
+        code_end, // code_end
+        code_begin, // content_begin
+        code_end, // content_end
+        code_end, // data_end
+        relocation_begin, // relocation_begin
+        relocation_end
+        ) {
+    }
+};
+
+class AOTCompiledMethod : public CompiledMethod, public CHeapObj<mtCode> {
+private:
+  address       _code;
+  aot_metadata* _meta;
+  Metadata**    _metadata_got;
+  jlong*        _state_adr; // Address of cell to indicate aot method state (in_use or not_entrant)
+  AOTCodeHeap*  _heap;    // code heap which has this method
+  const char*   _name;    // For stub: "AOT Stub<name>" for stub,
+                          // For nmethod: "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V"
+  const int _metadata_size; // size of _metadata_got
+  const int _aot_id;
+  const int _method_index;
+  oop _oop;  // method()->method_holder()->klass_holder()
+
+  address* orig_pc_addr(const frame* fr) { return (address*) ((address)fr->unextended_sp() + _meta->orig_pc_offset()); }
+  bool make_not_entrant_helper(int new_state);
+
+ public:
+  using CHeapObj<mtCode>::operator new;
+  using CHeapObj<mtCode>::operator delete;
+
+  int method_index() const { return _method_index; }
+  void set_oop(oop o) { _oop = o; }
+
+  AOTCompiledMethod(address code, Method* method, aot_metadata* meta, address metadata_got, int metadata_size, jlong* state_adr, AOTCodeHeap* heap, const char* name, int method_index, int aot_id) :
+    CompiledMethod(method, name, compiler_jvmci, // AOT code is generated by JVMCI compiler
+        AOTCompiledMethodLayout(code, code + meta->code_size(), (address) meta->relocation_begin(), (address) meta->relocation_end()),
+        0 /* frame_complete_offset */, meta->frame_size() /* frame_size */, meta->oopmap_set(), false /* caller_must_gc_arguments */),
+    _code(code),
+    _meta(meta),
+    _metadata_got((Metadata**) metadata_got),
+    _state_adr(state_adr),
+    _heap(heap),
+    _name(name),
+    _metadata_size(metadata_size),
+    _method_index(method_index),
+    _aot_id(aot_id) {
+
+    _is_far_code = CodeCache::is_far_target(code) ||
+                   CodeCache::is_far_target(code + meta->code_size());
+    _exception_cache = NULL;
+
+    _scopes_data_begin = (address) _meta->scopes_data_begin();
+    _deopt_handler_begin = (address) _code + _meta->deopt_handler_offset();
+    _deopt_mh_handler_begin = (address) this;
+
+    _pc_desc_container.reset_to(scopes_pcs_begin());
+
+    // Mark the AOTCompiledMethod as in_use
+    *_state_adr = nmethod::in_use;
+    set_has_unsafe_access(_meta->has_unsafe_access());
+    _oop = NULL;
+  }
+
+  virtual bool is_aot() const { return true; }
+  virtual bool is_runtime_stub() const { return is_aot_runtime_stub(); }
+
+  virtual bool is_compiled() const     { return !is_aot_runtime_stub(); }
+
+  virtual bool is_locked_by_vm() const { return false; }
+
+  int state() const { return *_state_adr; }
+
+  // Non-virtual for speed
+  bool _is_alive() const { return state() < zombie; }
+
+  virtual bool is_zombie() const { return state() == zombie; }
+  virtual bool is_unloaded() const { return state() == unloaded; }
+  virtual bool is_not_entrant() const { return state() == not_entrant ||
+                                                 state() == not_used; }
+  virtual bool is_alive() const { return _is_alive(); }
+  virtual bool is_in_use() const { return state() == in_use; }
+
+  address exception_begin() { return (address) _code + _meta->exception_handler_offset(); }
+
+  virtual const char* name() const { return _name; }
+
+  virtual int compile_id() const { return _aot_id; }
+
+  void print_on(outputStream* st) const;
+  void print_on(outputStream* st, const char* msg) const;
+  void print() const;
+
+  virtual void print_value_on(outputStream *stream) const;
+  virtual void print_block_comment(outputStream *stream, address block_begin) const { }
+  virtual void verify() {}
+
+  virtual int comp_level() const { return CompLevel_aot; }
+  virtual address verified_entry_point() const { return _code + _meta->verified_entry_offset(); }
+  virtual void log_identity(xmlStream* stream) const;
+  virtual void log_state_change() const;
+  virtual bool make_entrant();
+  virtual bool make_not_entrant() { return make_not_entrant_helper(not_entrant); }
+  virtual bool make_not_used() { return make_not_entrant_helper(not_used); }
+  virtual address entry_point() const { return _code + _meta->entry_offset(); }
+  virtual bool make_zombie() { ShouldNotReachHere(); return false; }
+  virtual bool is_osr_method() const { return false; }
+  virtual int osr_entry_bci() const { ShouldNotReachHere(); return -1; }
+  // AOT compiled methods do not get into zombie state
+  virtual bool can_convert_to_zombie() { return false; }
+
+  virtual bool is_evol_dependent_on(Klass* dependee);
+  virtual bool is_dependent_on_method(Method* dependee) { return true; }
+
+  virtual void clear_inline_caches();
+
+  virtual void print_pcs() {}
+
+  virtual address scopes_data_end() const { return _meta->scopes_data_end(); }
+
+  virtual oop oop_at(int index) const;
+  virtual Metadata* metadata_at(int index) const;
+
+  virtual PcDesc* scopes_pcs_begin() const { return _meta->scopes_pcs_begin(); }
+  virtual PcDesc* scopes_pcs_end() const { return _meta->scopes_pcs_end(); }
+
+  virtual address handler_table_begin() const { return _meta->handler_table_begin(); }
+  virtual address handler_table_end() const { return _meta->handler_table_end(); }
+
+  virtual address nul_chk_table_begin() const { return _meta->nul_chk_table_begin(); }
+  virtual address nul_chk_table_end() const { return _meta->nul_chk_table_end(); }
+
+  virtual address consts_begin() const { return _meta->consts_begin(); }
+  virtual address consts_end() const { return _meta->consts_end(); }
+
+  virtual address stub_begin() const { return code_begin() + _meta->stub_offset(); }
+  virtual address stub_end() const { return code_end(); }
+
+  virtual oop* oop_addr_at(int index) const { ShouldNotReachHere(); return NULL; }
+  virtual Metadata** metadata_addr_at(int index) const { ShouldNotReachHere(); return NULL; }
+
+  // Accessor/mutator for the original pc of a frame before a frame was deopted.
+  address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
+  void    set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
+
+#ifdef HOTSWAP
+  // Flushing and deoptimization in case of evolution
+  void flush_evol_dependents_on(instanceKlassHandle dependee);
+#endif // HOTSWAP
+
+  virtual void metadata_do(void f(Metadata*));
+
+  bool metadata_got_contains(Metadata **p) {
+    return p >= &_metadata_got[0] && p < &_metadata_got[_metadata_size];
+  }
+
+  Metadata** metadata_begin() const { return &_metadata_got[0] ; }
+  Metadata** metadata_end()   const { return &_metadata_got[_metadata_size] ; }
+  const char* compile_kind() const { return "AOT"; }
+
+  int get_state() const {
+    return (int) (*_state_adr);
+  }
+
+  virtual void oops_do(OopClosure* f);
+
+  // inlined and non-virtual for AOTCodeHeap::oops_do
+  void do_oops(OopClosure* f) {
+    assert(_is_alive(), "");
+    if (_oop != NULL) {
+      f->do_oop(&_oop);
+    }
+#if 0
+    metadata_oops_do(metadata_begin(), metadata_end(), f);
+#endif
+  }
+
+
+protected:
+  // AOT compiled methods are not flushed
+  void flush() {};
+
+  NativeCallWrapper* call_wrapper_at(address call) const;
+  NativeCallWrapper* call_wrapper_before(address return_pc) const;
+  address call_instruction_address(address pc) const;
+
+  CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const;
+  CompiledStaticCall* compiledStaticCall_at(address addr) const;
+  CompiledStaticCall* compiledStaticCall_before(address addr) const;
+private:
+  bool is_aot_runtime_stub() const { return _method == NULL; }
+
+protected:
+  virtual bool do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred);
+  virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred) { return false; }
+
+};
+
+class PltNativeCallWrapper: public NativeCallWrapper {
+private:
+  NativePltCall* _call;
+
+public:
+  PltNativeCallWrapper(NativePltCall* call) : _call(call) {}
+
+  virtual address destination() const { return _call->destination(); }
+  virtual address instruction_address() const { return _call->instruction_address(); }
+  virtual address next_instruction_address() const { return _call->next_instruction_address(); }
+  virtual address return_address() const { return _call->return_address(); }
+  virtual address get_resolve_call_stub(bool is_optimized) const { return _call->plt_resolve_call(); }
+  virtual void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
+  virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info);
+  virtual void verify() const { _call->verify(); }
+  virtual void verify_resolve_call(address dest) const;
+
+  virtual bool is_call_to_interpreted(address dest) const { return (dest == _call->plt_c2i_stub()); }
+  // TODO: assume for now that patching of aot code (got cell) is safe.
+  virtual bool is_safe_for_patching() const { return true; }
+
+  virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const;
+
+  virtual void *get_data(NativeInstruction* instruction) const {
+    return (void*)((NativeLoadGot*) instruction)->data();
+  }
+
+  virtual void set_data(NativeInstruction* instruction, intptr_t data) {
+    ((NativeLoadGot*) instruction)->set_data(data);
+  }
+};
+
+#endif //SHARE_VM_AOT_AOTCOMPILEDMETHOD_HPP
diff --git a/hotspot/src/share/vm/aot/aotLoader.cpp b/hotspot/src/share/vm/aot/aotLoader.cpp
new file mode 100644
index 0000000..0dbf9ff
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotLoader.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+#include "aot/aotCodeHeap.hpp"
+#include "aot/aotLoader.inline.hpp"
+#include "jvmci/jvmciRuntime.hpp"
+#include "oops/method.hpp"
+
+GrowableArray<AOTCodeHeap*>* AOTLoader::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTCodeHeap*> (2, true);
+GrowableArray<AOTLib*>* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTLib*> (2, true);
+
+// Iterate over all AOT CodeHeaps
+#define FOR_ALL_AOT_HEAPS(heap) for (GrowableArrayIterator<AOTCodeHeap*> heap = heaps()->begin(); heap != heaps()->end(); ++heap)
+// Iterate over all AOT Libraries
+#define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator<AOTLib*> lib = libraries()->begin(); lib != libraries()->end(); ++lib)
+
+void AOTLoader::load_for_klass(instanceKlassHandle kh, Thread* thread) {
+  if (UseAOT) {
+    FOR_ALL_AOT_HEAPS(heap) {
+      (*heap)->load_klass_data(kh, thread);
+    }
+  }
+}
+
+uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) {
+  FOR_ALL_AOT_HEAPS(heap) {
+    AOTKlassData* klass_data = (*heap)->find_klass(ik);
+    if (klass_data != NULL) {
+      return klass_data->_fingerprint;
+    }
+  }
+  return 0;
+}
+
+bool AOTLoader::find_klass(InstanceKlass* ik) {
+  FOR_ALL_AOT_HEAPS(heap) {
+    if ((*heap)->find_klass(ik) != NULL) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool AOTLoader::contains(address p) {
+  FOR_ALL_AOT_HEAPS(heap) {
+    if ((*heap)->contains(p)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void AOTLoader::oops_do(OopClosure* f) {
+  if (UseAOT) {
+    FOR_ALL_AOT_HEAPS(heap) {
+      (*heap)->oops_do(f);
+    }
+  }
+}
+
+void AOTLoader::metadata_do(void f(Metadata*)) {
+  if (UseAOT) {
+    FOR_ALL_AOT_HEAPS(heap) {
+      (*heap)->metadata_do(f);
+    }
+  }
+}
+
+address AOTLoader::exception_begin(JavaThread* thread, CodeBlob* blob, address return_address) {
+  assert(blob->is_aot(), "sanity");
+  AOTCompiledMethod* aotm = (AOTCompiledMethod*)blob;
+  // Set flag if return address is a method handle call site.
+  thread->set_is_method_handle_return(aotm->is_method_handle_return(return_address));
+  return aotm->exception_begin();
+}
+
+// Flushing and deoptimization in case of evolution
+void AOTLoader::flush_evol_dependents_on(instanceKlassHandle dependee) {
+  // make non entrant and mark for deoptimization
+  FOR_ALL_AOT_HEAPS(heap) {
+    (*heap)->flush_evol_dependents_on(dependee);
+  }
+  Deoptimization::deoptimize_dependents();
+}
+
+/**
+ * List of core modules for which we search for shared libraries.
+ */
+static const char* modules[] = {
+  "java.base",
+  "java.logging",
+  "jdk.compiler",
+  "jdk.scripting.nashorn",
+  "jdk.vm.ci",
+  "jdk.vm.compiler"
+};
+
+void AOTLoader::initialize() {
+  if (FLAG_IS_DEFAULT(UseAOT) && AOTLibrary != NULL) {
+    // Don't need to set UseAOT on command line when AOTLibrary is specified
+    FLAG_SET_DEFAULT(UseAOT, true);
+  }
+  if (UseAOT) {
+    // EagerInitialization is not compatible with AOT
+    if (EagerInitialization) {
+      if (PrintAOT) {
+        warning("EagerInitialization is not compatible with AOT (switching AOT off)");
+      }
+      FLAG_SET_DEFAULT(UseAOT, false);
+      return;
+    }
+
+    // -Xint is not compatible with AOT
+    if (Arguments::is_interpreter_only()) {
+      if (PrintAOT) {
+        warning("-Xint is not compatible with AOT (switching AOT off)");
+      }
+      FLAG_SET_DEFAULT(UseAOT, false);
+      return;
+    }
+
+    const char* home = Arguments::get_java_home();
+    const char* file_separator = os::file_separator();
+
+    for (int i = 0; i < (int) (sizeof(modules) / sizeof(const char*)); i++) {
+      char library[JVM_MAXPATHLEN];
+      jio_snprintf(library, sizeof(library), "%s%slib%slib%s%s%s.so", home, file_separator, file_separator, modules[i], UseCompressedOops ? "-coop" : "", UseG1GC ? "" : "-nong1");
+      load_library(library, false);
+    }
+
+    // Scan the AOTLibrary option.
+    if (AOTLibrary != NULL) {
+      const int len = strlen(AOTLibrary);
+      char* cp  = NEW_C_HEAP_ARRAY(char, len+1, mtCode);
+      if (cp != NULL) { // No memory?
+        memcpy(cp, AOTLibrary, len);
+        cp[len] = '\0';
+        char* end = cp + len;
+        while (cp < end) {
+          const char* name = cp;
+          while ((*cp) != '\0' && (*cp) != '\n' && (*cp) != ',' && (*cp) != ':' && (*cp) != ';')  cp++;
+          cp[0] = '\0';  // Terminate name
+          cp++;
+          load_library(name, true);
+        }
+      }
+    }
+  }
+}
+
+void AOTLoader::universe_init() {
+  if (UseAOT && libraries_count() > 0) {
+    // Shifts are static values which initialized by 0 until java heap initialization.
+    // AOT libs are loaded before heap initialized so shift values are not set.
+    // It is okay since ObjectAlignmentInBytes flag which defines shifts value is set before AOT libs are loaded.
+    // Set shifts value based on first AOT library config.
+    if (UseCompressedOops && AOTLib::narrow_oop_shift_initialized()) {
+      int oop_shift = Universe::narrow_oop_shift();
+      if (oop_shift == 0) {
+        Universe::set_narrow_oop_shift(AOTLib::narrow_oop_shift());
+      } else {
+        FOR_ALL_AOT_LIBRARIES(lib) {
+          (*lib)->verify_flag(AOTLib::narrow_oop_shift(), oop_shift, "Universe::narrow_oop_shift");
+        }
+      }
+      if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set
+        int klass_shift = Universe::narrow_klass_shift();
+        if (klass_shift == 0) {
+          Universe::set_narrow_klass_shift(AOTLib::narrow_klass_shift());
+        } else {
+          FOR_ALL_AOT_LIBRARIES(lib) {
+            (*lib)->verify_flag(AOTLib::narrow_klass_shift(), klass_shift, "Universe::narrow_klass_shift");
+          }
+        }
+      }
+    }
+    // Create heaps for all the libraries
+    FOR_ALL_AOT_LIBRARIES(lib) {
+      if ((*lib)->is_valid()) {
+        AOTCodeHeap* heap = new AOTCodeHeap(*lib);
+        {
+          MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+          add_heap(heap);
+          CodeCache::add_heap(heap);
+        }
+      }
+    }
+  }
+  if (heaps_count() == 0) {
+    if (FLAG_IS_DEFAULT(UseAOT)) {
+      FLAG_SET_DEFAULT(UseAOT, false);
+    }
+  }
+}
+
+void AOTLoader::set_narrow_klass_shift() {
+  // This method could be called from Metaspace::set_narrow_klass_base_and_shift().
+  // In case it is not called (during dump CDS, for example) the corresponding code in
+  // AOTLoader::universe_init(), which is called later, will set the shift value.
+  if (UseAOT && libraries_count() > 0 &&
+      UseCompressedOops && AOTLib::narrow_oop_shift_initialized() &&
+      UseCompressedClassPointers) {
+    int klass_shift = Universe::narrow_klass_shift();
+    if (klass_shift == 0) {
+      Universe::set_narrow_klass_shift(AOTLib::narrow_klass_shift());
+    } else {
+      FOR_ALL_AOT_LIBRARIES(lib) {
+        (*lib)->verify_flag(AOTLib::narrow_klass_shift(), klass_shift, "Universe::narrow_klass_shift");
+      }
+    }
+  }
+}
+
+void AOTLoader::load_library(const char* name, bool exit_on_error) {
+  void* handle = dlopen(name, RTLD_LAZY);
+  if (handle == NULL) {
+    if (exit_on_error) {
+      tty->print_cr("error opening file: %s", dlerror());
+      vm_exit(1);
+    }
+    return;
+  }
+  const int dso_id = libraries_count() + 1;
+  AOTLib* lib = new AOTLib(handle, name, dso_id);
+  if (!lib->is_valid()) {
+    delete lib;
+    dlclose(handle);
+    return;
+  }
+  add_library(lib);
+}
+
+#ifndef PRODUCT
+void AOTLoader::print_statistics() {
+  { ttyLocker ttyl;
+    tty->print_cr("--- AOT Statistics ---");
+    tty->print_cr("AOT libraries loaded: %d", heaps_count());
+    AOTCodeHeap::print_statistics();
+  }
+}
+#endif
diff --git a/hotspot/src/share/vm/aot/aotLoader.hpp b/hotspot/src/share/vm/aot/aotLoader.hpp
new file mode 100644
index 0000000..b556eb5
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotLoader.hpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_AOT_AOTLOADER_HPP
+#define SHARE_VM_AOT_AOTLOADER_HPP
+
+#include "runtime/globals_extension.hpp"
+#include "runtime/handles.hpp"
+
+class AOTCodeHeap;
+class AOTLib;
+class CodeBlob;
+template <class T> class GrowableArray;
+class InstanceKlass;
+class JavaThread;
+class Metadata;
+class OopClosure;
+
+class AOTLoader {
+private:
+#if INCLUDE_AOT
+  static GrowableArray<AOTCodeHeap*>* _heaps;
+  static GrowableArray<AOTLib*>* _libraries;
+#endif
+  static void load_library(const char* name, bool exit_on_error);
+
+public:
+#if INCLUDE_AOT
+  static GrowableArray<AOTCodeHeap*>* heaps();
+  static GrowableArray<AOTLib*>* libraries();
+  static int heaps_count();
+  static int libraries_count();
+  static void add_heap(AOTCodeHeap *heap);
+  static void add_library(AOTLib *lib);
+#endif
+  static void initialize() NOT_AOT({ FLAG_SET_ERGO(bool, UseAOT, false); });
+
+  static void universe_init() NOT_AOT_RETURN;
+  static void set_narrow_klass_shift() NOT_AOT_RETURN;
+  static bool contains(address p) NOT_AOT({ return false; });
+  static void load_for_klass(instanceKlassHandle, Thread* thread) NOT_AOT_RETURN;
+  static bool find_klass(InstanceKlass* ik) NOT_AOT({ return false; });
+  static uint64_t get_saved_fingerprint(InstanceKlass* ik) NOT_AOT({ return 0; });
+  static void oops_do(OopClosure* f) NOT_AOT_RETURN;
+  static void metadata_do(void f(Metadata*)) NOT_AOT_RETURN;
+  static address exception_begin(JavaThread* thread, CodeBlob* blob, address return_address) NOT_AOT({ return NULL; });
+
+  NOT_PRODUCT( static void print_statistics() NOT_AOT_RETURN; )
+
+#ifdef HOTSWAP
+  // Flushing and deoptimization in case of evolution
+  static void flush_evol_dependents_on(instanceKlassHandle dependee) NOT_AOT_RETURN;
+#endif // HOTSWAP
+
+};
+
+#endif // SHARE_VM_AOT_AOTLOADER_HPP
diff --git a/hotspot/src/share/vm/aot/aotLoader.inline.hpp b/hotspot/src/share/vm/aot/aotLoader.inline.hpp
new file mode 100644
index 0000000..0f3ba55
--- /dev/null
+++ b/hotspot/src/share/vm/aot/aotLoader.inline.hpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_AOT_AOTLOADER_INLLINE_HPP
+#define SHARE_VM_AOT_AOTLOADER_INLLINE_HPP
+
+#include "aot/aotLoader.hpp"
+#include "utilities/growableArray.hpp"
+
+#if INCLUDE_AOT
+GrowableArray<AOTCodeHeap*>* AOTLoader::heaps() { return _heaps; }
+GrowableArray<AOTLib*>* AOTLoader::libraries() { return _libraries; }
+int AOTLoader::heaps_count() { return heaps()->length(); }
+int AOTLoader::libraries_count() { return libraries()->length(); }
+void AOTLoader::add_heap(AOTCodeHeap *heap) { heaps()->append(heap); }
+void AOTLoader::add_library(AOTLib *lib) { libraries()->append(lib); }
+#endif
+
+#endif // SHARE_VM_AOT_AOTLOADER_INLLINE_HPP
diff --git a/hotspot/src/share/vm/aot/compiledIC_aot.cpp b/hotspot/src/share/vm/aot/compiledIC_aot.cpp
new file mode 100644
index 0000000..f841030
--- /dev/null
+++ b/hotspot/src/share/vm/aot/compiledIC_aot.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "aot/compiledIC_aot.hpp"
+
+bool CompiledPltStaticCall::is_call_to_interpreted() const {
+  // It is a call to interpreted, if it calls to a stub. Hence, the destination
+  // must be in the stub part of the nmethod that contains the call
+  return destination() == _call->plt_c2i_stub();
+}
+
+address CompiledPltStaticCall::find_stub() {
+  // It is static NativePltCall. Return c2i stub address.
+  return _call->plt_c2i_stub();
+}
diff --git a/hotspot/src/share/vm/aot/compiledIC_aot.hpp b/hotspot/src/share/vm/aot/compiledIC_aot.hpp
new file mode 100644
index 0000000..e2d2569
--- /dev/null
+++ b/hotspot/src/share/vm/aot/compiledIC_aot.hpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_AOT_COMPILEDIC_AOT_HPP
+#define SHARE_VM_AOT_COMPILEDIC_AOT_HPP
+
+#include "code/compiledIC.hpp"
+#include "code/nativeInst.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "oops/compiledICHolder.hpp"
+
+class CompiledPltStaticCall: public CompiledStaticCall {
+  friend class CompiledIC;
+  friend class PltNativeCallWrapper;
+
+  // Also used by CompiledIC
+  void set_to_interpreted(const methodHandle& callee, address entry);
+
+  address instruction_address() const { return _call->instruction_address(); }
+  void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
+
+  NativePltCall* _call;
+
+  CompiledPltStaticCall(NativePltCall* call) : _call(call) {}
+
+ public:
+
+  inline static CompiledPltStaticCall* before(address return_addr) {
+    CompiledPltStaticCall* st = new CompiledPltStaticCall(nativePltCall_before(return_addr));
+    st->verify();
+    return st;
+  }
+
+  static inline CompiledPltStaticCall* at(address native_call) {
+    CompiledPltStaticCall* st = new CompiledPltStaticCall(nativePltCall_at(native_call));
+    st->verify();
+    return st;
+  }
+
+  static inline CompiledPltStaticCall* at(Relocation* call_site) {
+    return at(call_site->addr());
+  }
+
+  // Delegation
+  address destination() const { return _call->destination(); }
+
+  virtual bool is_call_to_interpreted() const;
+
+  // Stub support
+  address find_stub();
+  static void set_stub_to_clean(static_stub_Relocation* static_stub);
+
+  // Misc.
+  void print()  PRODUCT_RETURN;
+  void verify() PRODUCT_RETURN;
+
+ protected:
+  virtual address resolve_call_stub() const { return _call->plt_resolve_call(); }
+  virtual void set_to_far(const methodHandle& callee, address entry) { set_to_compiled(entry); }
+  virtual const char* name() const { return "CompiledPltStaticCall"; }
+};
+
+#endif // SHARE_VM_AOT_COMPILEDIC_AOT_HPP
diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp
index 4af0a5f..9670344 100644
--- a/hotspot/src/share/vm/c1/c1_Compilation.cpp
+++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp
@@ -328,10 +328,9 @@
                                         locs_buffer_size / sizeof(relocInfo));
   code->initialize_consts_size(Compilation::desired_max_constant_size());
   // Call stubs + two deopt handlers (regular and MH) + exception handler
-  int call_stub_size = LIR_Assembler::call_stub_size;
-  int stub_size = (call_stub_estimate * call_stub_size) +
-                   LIR_Assembler::exception_handler_size +
-                   (2 * LIR_Assembler::deopt_handler_size);
+  int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size()) +
+                   LIR_Assembler::exception_handler_size() +
+                   (2 * LIR_Assembler::deopt_handler_size());
   if (stub_size >= code->insts_capacity()) return false;
   code->initialize_stubs_size(stub_size);
   return true;
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
index b71a0b5..75a4f8a 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -1813,14 +1813,10 @@
   ciKlass*              holder = stream()->get_declared_method_holder();
   const Bytecodes::Code bc_raw = stream()->cur_bc_raw();
   assert(declared_signature != NULL, "cannot be null");
+  assert(will_link == target->is_loaded(), "");
 
   ciInstanceKlass* klass = target->holder();
-
-  // Make sure there are no evident problems with linking the instruction.
-  bool is_resolved = true;
-  if (klass->is_loaded() && !target->is_loaded()) {
-    is_resolved = false; // method not found
-  }
+  assert(!target->is_loaded() || klass->is_loaded(), "loaded target must imply loaded klass");
 
   // check if CHA possible: if so, change the code to invoke_special
   ciInstanceKlass* calling_klass = method()->holder();
@@ -1868,7 +1864,7 @@
   ciMethod* cha_monomorphic_target = NULL;
   ciMethod* exact_target = NULL;
   Value better_receiver = NULL;
-  if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() &&
+  if (UseCHA && DeoptC1 && target->is_loaded() &&
       !(// %%% FIXME: Are both of these relevant?
         target->is_method_handle_intrinsic() ||
         target->is_compiled_lambda_form()) &&
@@ -1988,8 +1984,7 @@
   }
 
   // check if we could do inlining
-  if (!PatchALot && Inline && is_resolved &&
-      klass->is_loaded() && target->is_loaded() &&
+  if (!PatchALot && Inline && target->is_loaded() &&
       (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
       && !patch_for_appendix) {
     // callee is known => check if we have static binding
@@ -2032,7 +2027,6 @@
   CHECK_BAILOUT();
 
   // inlining not successful => standard invoke
-  bool is_loaded = target->is_loaded();
   ValueType* result_type = as_ValueType(declared_signature->return_type());
   ValueStack* state_before = copy_state_exhandling();
 
@@ -2049,7 +2043,7 @@
   // Currently only supported on Sparc.
   // The UseInlineCaches only controls dispatch to invokevirtuals for
   // loaded classes which we weren't able to statically bind.
-  if (!UseInlineCaches && is_resolved && is_loaded && code == Bytecodes::_invokevirtual
+  if (!UseInlineCaches && target->is_loaded() && code == Bytecodes::_invokevirtual
       && !target->can_be_statically_bound()) {
     // Find a vtable index if one is available
     // For arrays, callee_holder is Object. Resolving the call with
@@ -2062,16 +2056,24 @@
   }
 #endif
 
-  if (is_resolved) {
-    // invokespecial always needs a NULL check. invokevirtual where the target is
-    // final or where it's not known whether the target is final requires a NULL check.
-    // Otherwise normal invokevirtual will perform the null check during the lookup
-    // logic or the unverified entry point.  Profiling of calls requires that
-    // the null check is performed in all cases.
-    bool do_null_check = (recv != NULL) &&
-        (code == Bytecodes::_invokespecial || !is_loaded || target->is_final() || (is_profiling() && profile_calls()));
+  // A null check is required here (when there is a receiver) for any of the following cases
+  // - invokespecial, always need a null check.
+  // - invokevirtual, when the target is final and loaded. Calls to final targets will become optimized
+  //   and require null checking. If the target is loaded a null check is emitted here.
+  //   If the target isn't loaded the null check must happen after the call resolution. We achieve that
+  //   by using the target methods unverified entry point (see CompiledIC::compute_monomorphic_entry).
+  //   (The JVM specification requires that LinkageError must be thrown before a NPE. An unloaded target may
+  //   potentially fail, and can't have the null check before the resolution.)
+  // - A call that will be profiled. (But we can't add a null check when the target is unloaded, by the same
+  //   reason as above, so calls with a receiver to unloaded targets can't be profiled.)
+  //
+  // Normal invokevirtual will perform the null check during lookup
 
-    if (do_null_check) {
+  bool need_null_check = (code == Bytecodes::_invokespecial) ||
+      (target->is_loaded() && (target->is_final_method() || (is_profiling() && profile_calls())));
+
+  if (need_null_check) {
+    if (recv != NULL) {
       null_check(recv);
     }
 
@@ -2090,9 +2092,6 @@
         profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false);
       }
     }
-  } else {
-    // No need in null check or profiling: linkage error will be thrown at runtime
-    // during resolution.
   }
 
   Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before);
diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp
index c0d39d6..61dfbf3 100644
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp
+++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp
@@ -260,6 +260,21 @@
 
 #include CPU_HEADER(c1_LIRAssembler)
 
+  static int call_stub_size() {
+    if (UseAOT) {
+      return _call_stub_size + _call_aot_stub_size;
+    } else {
+      return _call_stub_size;
+    }
+  }
+
+  static int exception_handler_size() {
+    return _exception_handler_size;
+  }
+
+  static int deopt_handler_size() {
+    return _deopt_handler_size;
+  }
 };
 
 #endif // SHARE_VM_C1_C1_LIRASSEMBLER_HPP
diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
index dd21475..0c10e86 100644
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -2976,7 +2976,6 @@
   }
 
   // emit invoke code
-  bool optimized = x->target_is_loaded() && x->target_is_final();
   assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match");
 
   // JSR 292
@@ -3001,9 +3000,9 @@
     case Bytecodes::_invokespecial:
     case Bytecodes::_invokevirtual:
     case Bytecodes::_invokeinterface:
-      // for final target we still produce an inline cache, in order
-      // to be able to call mixed mode
-      if (x->code() == Bytecodes::_invokespecial || optimized) {
+      // for loaded and final (method or class) target we still produce an inline cache,
+      // in order to be able to call mixed mode
+      if (x->code() == Bytecodes::_invokespecial || x->target_is_final()) {
         __ call_opt_virtual(target, receiver, result_register,
                             SharedRuntime::get_resolve_opt_virtual_call_stub(),
                             arg_list, info);
diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
index cbc11c1..3cb9aaf 100644
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
@@ -33,7 +33,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeBlob.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/compiledIC.hpp"
 #include "code/pcDesc.hpp"
 #include "code/scopeDesc.hpp"
@@ -189,52 +188,44 @@
   int frame_size;
   bool must_gc_arguments;
 
-  if (!CodeCacheExtensions::skip_compiler_support()) {
-    // bypass useless code generation
-    Compilation::setup_code_buffer(&code, 0);
+  Compilation::setup_code_buffer(&code, 0);
 
-    // create assembler for code generation
-    StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
-    // generate code for runtime stub
-    oop_maps = generate_code_for(id, sasm);
-    assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
-           "if stub has an oop map it must have a valid frame size");
+  // create assembler for code generation
+  StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
+  // generate code for runtime stub
+  oop_maps = generate_code_for(id, sasm);
+  assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
+         "if stub has an oop map it must have a valid frame size");
 
 #ifdef ASSERT
-    // Make sure that stubs that need oopmaps have them
-    switch (id) {
-      // These stubs don't need to have an oopmap
-    case dtrace_object_alloc_id:
-    case g1_pre_barrier_slow_id:
-    case g1_post_barrier_slow_id:
-    case slow_subtype_check_id:
-    case fpu2long_stub_id:
-    case unwind_exception_id:
-    case counter_overflow_id:
+  // Make sure that stubs that need oopmaps have them
+  switch (id) {
+    // These stubs don't need to have an oopmap
+  case dtrace_object_alloc_id:
+  case g1_pre_barrier_slow_id:
+  case g1_post_barrier_slow_id:
+  case slow_subtype_check_id:
+  case fpu2long_stub_id:
+  case unwind_exception_id:
+  case counter_overflow_id:
 #if defined(SPARC) || defined(PPC32)
-    case handle_exception_nofpu_id:  // Unused on sparc
+  case handle_exception_nofpu_id:  // Unused on sparc
 #endif
-      break;
+    break;
 
-      // All other stubs should have oopmaps
-    default:
-      assert(oop_maps != NULL, "must have an oopmap");
-    }
-#endif
-
-    // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
-    sasm->align(BytesPerWord);
-    // make sure all code is in code buffer
-    sasm->flush();
-
-    frame_size = sasm->frame_size();
-    must_gc_arguments = sasm->must_gc_arguments();
-  } else {
-    /* ignored values */
-    oop_maps = NULL;
-    frame_size = 0;
-    must_gc_arguments = false;
+    // All other stubs should have oopmaps
+  default:
+    assert(oop_maps != NULL, "must have an oopmap");
   }
+#endif
+
+  // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
+  sasm->align(BytesPerWord);
+  // make sure all code is in code buffer
+  sasm->flush();
+
+  frame_size = sasm->frame_size();
+  must_gc_arguments = sasm->must_gc_arguments();
   // create blob - distinguish a few special cases
   CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id),
                                                  &code,
diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp
index 22f1828..f1eace4 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp
@@ -22,11 +22,13 @@
  *
  */
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/defaultMethods.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/moduleEntry.hpp"
 #include "classfile/symbolTable.hpp"
@@ -4349,13 +4351,34 @@
   assert(this_klass != NULL, "invariant");
   const Klass* const super = this_klass->super();
   if (super != NULL) {
+
+    // If the loader is not the boot loader then throw an exception if its
+    // superclass is in package jdk.internal.reflect and its loader is not a
+    // special reflection class loader
+    if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
+      assert(super->is_instance_klass(), "super is not instance klass");
+      PackageEntry* super_package = super->package();
+      if (super_package != NULL &&
+          super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
+          !java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) {
+        ResourceMark rm(THREAD);
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
+          this_klass->external_name(),
+          this_klass->class_loader_data()->loader_name(),
+          super->external_name());
+        return;
+      }
+    }
+
     Reflection::VerifyClassAccessResults vca_result =
       Reflection::verify_class_access(this_klass, super, false);
     if (vca_result != Reflection::ACCESS_OK) {
       ResourceMark rm(THREAD);
       char* msg =  Reflection::verify_class_access_msg(this_klass, super, vca_result);
       if (msg == NULL) {
-        ResourceMark rm(THREAD);
         Exceptions::fthrow(
           THREAD_AND_LOCATION,
           vmSymbols::java_lang_IllegalAccessError(),
@@ -4684,16 +4707,7 @@
   for (const char* p = name; p != name + length;) {
     jchar ch = *p;
     if (ch < 128) {
-      if (ch == '.') {
-        // permit '.' in module names unless it's the first char, or
-        // preceding char is also a '.', or last char is a '.'.
-        if ((type != ClassFileParser::LegalModule) ||
-          (p == name) || (*(p-1) == '.') ||
-          (p == name + length - 1)) {
-          return false;
-        }
-      }
-      if (ch == ';' || ch == '[' ) {
+      if (ch == '.' || ch == ';' || ch == '[' ) {
         return false;   // do not permit '.', ';', or '['
       }
       if (ch == '/') {
@@ -5190,6 +5204,19 @@
 
   assert(_klass == ik, "invariant");
 
+  ik->set_has_passed_fingerprint_check(false);
+  if (UseAOT && ik->supers_have_passed_fingerprint_checks()) {
+    uint64_t aot_fp = AOTLoader::get_saved_fingerprint(ik);
+    if (aot_fp != 0 && aot_fp == _stream->compute_fingerprint()) {
+      // This class matches with a class saved in an AOT library
+      ik->set_has_passed_fingerprint_check(true);
+    } else {
+      ResourceMark rm;
+      log_info(class, fingerprint)("%s :  expected = " PTR64_FORMAT " actual = " PTR64_FORMAT,
+                                 ik->external_name(), aot_fp, _stream->compute_fingerprint());
+    }
+  }
+
   return ik;
 }
 
@@ -5391,7 +5418,7 @@
     }
   }
 
-  TRACE_INIT_KLASS_ID(ik);
+  TRACE_INIT_ID(ik);
 
   // If we reach here, all is well.
   // Now remove the InstanceKlass* from the _klass_to_deallocate field
diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp
index ad62052..df9ff68 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp
@@ -72,7 +72,7 @@
     NOF_PUBLICITY_LEVELS
   };
 
-  enum { LegalClass, LegalField, LegalMethod, LegalModule }; // used to verify unqualified names
+  enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
 
  private:
   const ClassFileStream* _stream; // Actual input stream
diff --git a/hotspot/src/share/vm/classfile/classFileStream.cpp b/hotspot/src/share/vm/classfile/classFileStream.cpp
index 618f307..4ede5f4 100644
--- a/hotspot/src/share/vm/classfile/classFileStream.cpp
+++ b/hotspot/src/share/vm/classfile/classFileStream.cpp
@@ -24,6 +24,8 @@
 
 #include "precompiled.hpp"
 #include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "memory/resourceArea.hpp"
 
@@ -133,3 +135,12 @@
   }
   _current += length * 4;
 }
+
+uint64_t ClassFileStream::compute_fingerprint() const {
+  int classfile_size = length();
+  int classfile_crc = ClassLoader::crc32(0, (const char*)buffer(), length());
+  uint64_t fingerprint = (uint64_t(classfile_size) << 32) | uint64_t(uint32_t(classfile_crc));
+  assert(fingerprint != 0, "must not be zero");
+
+  return fingerprint;
+}
diff --git a/hotspot/src/share/vm/classfile/classFileStream.hpp b/hotspot/src/share/vm/classfile/classFileStream.hpp
index 90ae4e9..69ca60f 100644
--- a/hotspot/src/share/vm/classfile/classFileStream.hpp
+++ b/hotspot/src/share/vm/classfile/classFileStream.hpp
@@ -150,6 +150,8 @@
 
   // Tells whether eos is reached
   bool at_eos() const { return _current == _buffer_end; }
+
+  uint64_t compute_fingerprint() const;
 };
 
 #endif // SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp
index a7e2222..62ede6e 100644
--- a/hotspot/src/share/vm/classfile/classLoader.cpp
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp
@@ -504,7 +504,7 @@
 
     if (pkg_name != NULL) {
       if (!Universe::is_module_initialized()) {
-        location = (*JImageFindResource)(_jimage, "java.base", get_jimage_version_string(), name, &size);
+        location = (*JImageFindResource)(_jimage, JAVA_BASE_NAME, get_jimage_version_string(), name, &size);
 #if INCLUDE_CDS
         // CDS uses the boot class loader to load classes whose packages are in
         // modules defined for other class loaders.  So, for now, get their module
@@ -751,6 +751,21 @@
   }
 }
 
+// Determine whether the module has been patched via the command-line
+// option --patch-module
+bool ClassLoader::is_in_patch_mod_entries(Symbol* module_name) {
+  if (_patch_mod_entries != NULL && _patch_mod_entries->is_nonempty()) {
+    int table_len = _patch_mod_entries->length();
+    for (int i = 0; i < table_len; i++) {
+      ModuleClassPathList* patch_mod = _patch_mod_entries->at(i);
+      if (module_name->fast_compare(patch_mod->module_name()) == 0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) {
   int len = (int)strlen(class_path);
   int end = 0;
@@ -771,8 +786,8 @@
     // what the base or core piece of the boot loader search is.  Either a java runtime
     // image is present or this is an exploded module build situation.
     if (set_base_piece) {
-      assert(string_ends_with(path, MODULES_IMAGE_NAME) || string_ends_with(path, "java.base"),
-             "Incorrect boot loader search path, no java runtime image or java.base exploded build");
+      assert(string_ends_with(path, MODULES_IMAGE_NAME) || string_ends_with(path, JAVA_BASE_NAME),
+             "Incorrect boot loader search path, no java runtime image or " JAVA_BASE_NAME " exploded build");
       struct stat st;
       if (os::stat(path, &st) == 0) {
         // Directory found
@@ -1141,7 +1156,7 @@
 
   ResourceMark rm;
   jlong size;
-  JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", get_jimage_version_string(), MODULE_LOADER_MAP, &size);
+  JImageLocationRef location = (*JImageFindResource)(jimage, JAVA_BASE_NAME, get_jimage_version_string(), MODULE_LOADER_MAP, &size);
   if (location == 0) {
     vm_exit_during_initialization(
       "Cannot find ModuleLoaderMap location from modules jimage.", NULL);
@@ -1764,9 +1779,6 @@
 
 // Complete the ClassPathEntry setup for the boot loader
 void ClassLoader::classLoader_init2(TRAPS) {
-  // Create the moduleEntry for java.base
-  create_javabase();
-
   // Setup the list of module/path pairs for --patch-module processing
   // This must be done after the SymbolTable is created in order
   // to use fast_compare on module names instead of a string compare.
@@ -1774,6 +1786,10 @@
     setup_patch_mod_entries();
   }
 
+  // Create the ModuleEntry for java.base (must occur after setup_patch_mod_entries
+  // to successfully determine if java.base has been patched)
+  create_javabase();
+
   // Setup the initial java.base/path pair for the exploded build entries.
   // As more modules are defined during module system initialization, more
   // entries will be added to the exploded build array.
@@ -1823,7 +1839,7 @@
     MutexLocker ml(Module_lock, THREAD);
     ModuleEntry* jb_module = null_cld_modules->locked_create_entry_or_null(Handle(NULL), vmSymbols::java_base(), NULL, NULL, null_cld);
     if (jb_module == NULL) {
-      vm_exit_during_initialization("Unable to create ModuleEntry for java.base");
+      vm_exit_during_initialization("Unable to create ModuleEntry for " JAVA_BASE_NAME);
     }
     ModuleEntryTable::set_javabase_moduleEntry(jb_module);
   }
diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp
index 1bdbd70..b7f494c 100644
--- a/hotspot/src/share/vm/classfile/classLoader.hpp
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp
@@ -418,6 +418,8 @@
     }
   }
 
+  static bool is_in_patch_mod_entries(Symbol* module_name);
+
 #if INCLUDE_CDS
   // Sharing dump and restore
 
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp
index 7beff89..fbafa93 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp
@@ -97,7 +97,7 @@
   _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
                             Monitor::_safepoint_check_never)) {
-    // empty
+  TRACE_INIT_ID(this);
 }
 
 void ClassLoaderData::init_dependencies(TRAPS) {
@@ -167,9 +167,10 @@
 }
 
 void ClassLoaderData::classes_do(void f(Klass * const)) {
-  assert_locked_or_safepoint(_metaspace_lock);
-  for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
+  // Lock-free access requires load_ptr_acquire
+  for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
     f(k);
+    assert(k != k->next_link(), "no loops!");
   }
 }
 
@@ -812,6 +813,16 @@
   }
 }
 
+void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  // Only walk the head until any clds not purged from prior unloading
+  // (CMS doesn't purge right away).
+  for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
+    assert(cld->is_unloading(), "invariant");
+    cl->do_cld(cld);
+  }
+}
+
 void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
   for (ClassLoaderData* cld = _head;  cld != NULL; cld = cld->_next) {
     CLDClosure* closure = cld->keep_alive() ? strong : weak;
@@ -1042,7 +1053,7 @@
   }
 }
 
-void ClassLoaderDataGraph::post_class_unload_events(void) {
+void ClassLoaderDataGraph::post_class_unload_events() {
 #if INCLUDE_TRACE
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
   if (Tracing::enabled()) {
@@ -1191,9 +1202,7 @@
   EventClassUnload event(UNTIMED);
   event.set_endtime(_class_unload_time);
   event.set_unloadedClass(k);
-  oop defining_class_loader = k->class_loader();
-  event.set_definingClassLoader(defining_class_loader != NULL ?
-                                defining_class_loader->klass() : (Klass*)NULL);
+  event.set_definingClassLoader(k->class_loader_data());
   event.commit();
 }
 
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp
index e1798d3..b69c4e6 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp
@@ -30,6 +30,7 @@
 #include "memory/metaspace.hpp"
 #include "memory/metaspaceCounters.hpp"
 #include "runtime/mutex.hpp"
+#include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_TRACE
@@ -78,7 +79,7 @@
   static bool _metaspace_oom;
 
   static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
-  static void post_class_unload_events(void);
+  static void post_class_unload_events();
  public:
   static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
   static void purge();
@@ -89,6 +90,7 @@
   static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
   // cld do
   static void cld_do(CLDClosure* cl);
+  static void cld_unloading_do(CLDClosure* cl);
   static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
   static void keep_alive_cld_do(CLDClosure* cl);
   static void always_strong_cld_do(CLDClosure* cl);
@@ -210,6 +212,8 @@
   static Metaspace* _ro_metaspace;
   static Metaspace* _rw_metaspace;
 
+  TRACE_DEFINE_TRACE_ID_FIELD;
+
   void set_next(ClassLoaderData* next) { _next = next; }
   ClassLoaderData* next() const        { return _next; }
 
@@ -342,6 +346,8 @@
     assert(_shared_class_loader_id <0, "cannot be assigned more than once");
     _shared_class_loader_id = id;
   }
+
+  TRACE_DEFINE_TRACE_ID_METHODS;
 };
 
 // An iterator that distributes Klasses to parallel worker threads.
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp
index a9b6b28..d40b5fd 100644
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp
@@ -171,11 +171,11 @@
 
 void CompactSymbolTableWriter::add(unsigned int hash, Symbol *symbol) {
   address base_address = address(MetaspaceShared::shared_rs()->base());
-  uintx max_delta = uintx(MetaspaceShared::shared_rs()->size());
-  assert(max_delta <= MAX_SHARED_DELTA, "range check");
 
   uintx deltax = address(symbol) - base_address;
-  assert(deltax < max_delta, "range check");
+  // The symbols are in RO space, which is smaler than MAX_SHARED_DELTA.
+  // The assert below is just to be extra cautious.
+  assert(deltax <= MAX_SHARED_DELTA, "the delta is too large to encode");
   u4 delta = u4(deltax);
 
   CompactHashtableWriter::add(hash, delta);
diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp
index 3da3b09..91b5140 100644
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp
@@ -802,7 +802,7 @@
     if (javabase_was_defined) {
       ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
       assert(javabase_entry != NULL && javabase_entry->module() != NULL,
-             "Setting class module field, java.base should be defined");
+             "Setting class module field, " JAVA_BASE_NAME " should be defined");
       Handle javabase_handle(THREAD, JNIHandles::resolve(javabase_entry->module()));
       set_module(mirror(), javabase_handle());
     }
@@ -3525,17 +3525,24 @@
   return false;
 }
 
-oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
+// Return true if this is one of the class loaders associated with
+// the generated bytecodes for reflection.
+bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) {
   if (loader != NULL) {
-    // See whether this is one of the class loaders associated with
-    // the generated bytecodes for reflection, and if so, "magically"
-    // delegate to its parent to prevent class loading from occurring
-    // in places where applications using reflection didn't expect it.
     Klass* delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass();
     // This might be null in non-1.4 JDKs
-    if (delegating_cl_class != NULL && loader->is_a(delegating_cl_class)) {
-      return parent(loader);
-    }
+    return (delegating_cl_class != NULL && loader->is_a(delegating_cl_class));
+  }
+  return false;
+}
+
+oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
+  // See whether this is one of the class loaders associated with
+  // the generated bytecodes for reflection, and if so, "magically"
+  // delegate to its parent to prevent class loading from occurring
+  // in places where applications using reflection didn't expect it.
+  if (is_reflection_class_loader(loader)) {
+    return parent(loader);
   }
   return loader;
 }
@@ -3643,7 +3650,7 @@
 int java_lang_StackTraceElement::moduleVersion_offset;
 int java_lang_StackTraceElement::classLoaderName_offset;
 int java_lang_StackTraceElement::declaringClass_offset;
-int java_lang_StackTraceElement::classOrLoaderModuleClassName_offset;
+int java_lang_StackTraceElement::declaringClassObject_offset;
 int java_lang_StackFrameInfo::_declaringClass_offset;
 int java_lang_StackFrameInfo::_memberName_offset;
 int java_lang_StackFrameInfo::_bci_offset;
@@ -3693,7 +3700,7 @@
 }
 
 void java_lang_StackTraceElement::set_declaringClassObject(oop element, oop value) {
-  element->obj_field_put(classOrLoaderModuleClassName_offset, value);
+  element->obj_field_put(declaringClassObject_offset, value);
 }
 
 // Support for java_lang_StackFrameInfo
@@ -3811,7 +3818,7 @@
   java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x;
 
   // java_lang_StackTraceElement
-  java_lang_StackTraceElement::classOrLoaderModuleClassName_offset= java_lang_StackTraceElement::hc_classOrLoaderModuleClassName_offset* x + header;
+  java_lang_StackTraceElement::declaringClassObject_offset = java_lang_StackTraceElement::hc_declaringClassObject_offset * x + header;
   java_lang_StackTraceElement::classLoaderName_offset = java_lang_StackTraceElement::hc_classLoaderName_offset * x + header;
   java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header;
   java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header;
@@ -4014,7 +4021,7 @@
 
   // java.lang.StackTraceElement
 
-  CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classOrLoaderModuleClassName, "Ljava/lang/Object;");
+  CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClassObject, "Ljava/lang/Class;");
   CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classLoaderName, "Ljava/lang/String;");
   CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleName,      "Ljava/lang/String;");
   CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleVersion,   "Ljava/lang/String;");
diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp
index d4cba68..0cf0090 100644
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp
@@ -1243,6 +1243,10 @@
 
   static bool is_trusted_loader(oop loader);
 
+  // Return true if this is one of the class loaders associated with
+  // the generated bytecodes for reflection.
+  static bool is_reflection_class_loader(oop loader);
+
   // Fix for 4474172
   static oop  non_reflection_class_loader(oop loader);
 
@@ -1293,7 +1297,7 @@
 class java_lang_StackTraceElement: AllStatic {
  private:
   enum {
-    hc_classOrLoaderModuleClassName_offset = 0,
+    hc_declaringClassObject_offset    = 0,
     hc_classLoaderName_offset      = 1,
     hc_moduleName_offset           = 2,
     hc_moduleVersion_offset        = 3,
@@ -1303,7 +1307,7 @@
     hc_lineNumber_offset           = 7
   };
 
-  static int classOrLoaderModuleClassName_offset;
+  static int declaringClassObject_offset;
   static int classLoaderName_offset;
   static int moduleName_offset;
   static int moduleVersion_offset;
diff --git a/hotspot/src/share/vm/classfile/jimage.hpp b/hotspot/src/share/vm/classfile/jimage.hpp
index f34ba6e..e2268e9 100644
--- a/hotspot/src/share/vm/classfile/jimage.hpp
+++ b/hotspot/src/share/vm/classfile/jimage.hpp
@@ -94,7 +94,7 @@
  * Ex.
  *  const char* package = (*JImagePackageToModule)(image, "java/lang");
  *  tty->print_cr(package);
- *  —> java.base
+ *  -> java.base
  */
 
 extern "C" const char * JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name);
@@ -126,7 +126,7 @@
 
 
 /*
- * JImageGetResource - Given an open image file (see JImageOpen), a resource’s
+ * JImageGetResource - Given an open image file (see JImageOpen), a resource's
  * location information (see JImageFindResource), a buffer of appropriate
  * size and the size, retrieve the bytes associated with the
  * resource. If the size is less than the resource size then the read is truncated.
@@ -158,7 +158,7 @@
  * Ex.
  *   bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version,
  *                  const char* package, const char* name, const char* extension, void* arg) {
- *     if (strcmp(extension, “class”) == 0) {
+ *     if (strcmp(extension, "class") == 0) {
  *       char path[JIMAGE_MAX_PATH];
  *       Thread* THREAD = Thread::current();
  *       jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
diff --git a/hotspot/src/share/vm/classfile/klassFactory.cpp b/hotspot/src/share/vm/classfile/klassFactory.cpp
index 9b9507e..41ff031 100644
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp
@@ -212,6 +212,10 @@
     result->set_cached_class_file(cached_class_file);
   }
 
+  if (InstanceKlass::should_store_fingerprint()) {
+    result->store_fingerprint(!result->is_anonymous() ? stream->compute_fingerprint() : 0);
+  }
+
   TRACE_KLASS_CREATION(result, parser, THREAD);
 
 #if INCLUDE_CDS && INCLUDE_JVMTI
diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp
index e4bbb08..2b8279f 100644
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp
@@ -54,6 +54,17 @@
   }
 }
 
+bool ModuleEntry::is_non_jdk_module() {
+  ResourceMark rm;
+  if (location() != NULL) {
+    const char* loc = location()->as_C_string();
+    if (strncmp(loc, "jrt:/java.", 10) != 0 && strncmp(loc, "jrt:/jdk.", 9) != 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void ModuleEntry::set_version(Symbol* version) {
   if (_version != NULL) {
     // _version symbol's refcounts are managed by ModuleEntry,
@@ -290,7 +301,15 @@
   entry->set_version(version);
   entry->set_location(location);
 
-  TRACE_INIT_MODULE_ID(entry);
+  if (ClassLoader::is_in_patch_mod_entries(name)) {
+    entry->set_is_patched();
+    if (log_is_enabled(Trace, modules, patch)) {
+      ResourceMark rm;
+      log_trace(modules, patch)("Marked module %s as patched from --patch-module", name->as_C_string());
+    }
+  }
+
+  TRACE_INIT_ID(entry);
 
   return entry;
 }
@@ -354,12 +373,12 @@
   assert(module_table != NULL, "boot loader's ModuleEntryTable not defined");
 
   if (module_handle.is_null()) {
-    fatal("Unable to finalize module definition for java.base");
+    fatal("Unable to finalize module definition for " JAVA_BASE_NAME);
   }
 
   // Set java.lang.reflect.Module, version and location for java.base
   ModuleEntry* jb_module = javabase_moduleEntry();
-  assert(jb_module != NULL, "java.base ModuleEntry not defined");
+  assert(jb_module != NULL, JAVA_BASE_NAME " ModuleEntry not defined");
   jb_module->set_version(version);
   jb_module->set_location(location);
   // Once java.base's ModuleEntry _module field is set with the known
@@ -376,7 +395,8 @@
 // Their module field is set once java.base's java.lang.reflect.Module is known to the VM.
 void ModuleEntryTable::patch_javabase_entries(Handle module_handle) {
   if (module_handle.is_null()) {
-    fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module");
+    fatal("Unable to patch the module field of classes loaded prior to "
+          JAVA_BASE_NAME "'s definition, invalid java.lang.reflect.Module");
   }
 
   // Do the fixups for the basic primitive types
diff --git a/hotspot/src/share/vm/classfile/moduleEntry.hpp b/hotspot/src/share/vm/classfile/moduleEntry.hpp
index 6301d4e..85e898e 100644
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp
@@ -38,6 +38,7 @@
 #define UNNAMED_MODULE "Unnamed Module"
 #define JAVAPKG "java/"
 #define JAVAPKG_LEN 5
+#define JAVA_BASE_NAME "java.base"
 
 class ModuleClosure;
 
@@ -64,6 +65,7 @@
   bool _can_read_all_unnamed;
   bool _has_default_read_edges;        // JVMTI redefine/retransform support
   bool _must_walk_reads;               // walk module's reads list at GC safepoints to purge out dead modules
+  bool _is_patched;                    // whether the module is patched via --patch-module
   TRACE_DEFINE_TRACE_ID_FIELD;
   enum {MODULE_READS_SIZE = 101};      // Initial size of list of modules that the module can read.
 
@@ -78,6 +80,7 @@
     _can_read_all_unnamed = false;
     _has_default_read_edges = false;
     _must_walk_reads = false;
+    _is_patched = false;
   }
 
   Symbol*          name() const                        { return literal(); }
@@ -102,6 +105,7 @@
 
   Symbol*          location() const                    { return _location; }
   void             set_location(Symbol* location);
+  bool             is_non_jdk_module();
 
   bool             can_read(ModuleEntry* m) const;
   bool             has_reads() const;
@@ -131,6 +135,13 @@
     return prev;
   }
 
+  void set_is_patched() {
+      _is_patched = true;
+  }
+  bool is_patched() {
+      return _is_patched;
+  }
+
   ModuleEntry* next() const {
     return (ModuleEntry*)HashtableEntry<Symbol*, mtModule>::next();
   }
diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp
index 9c4aa89..becda53 100644
--- a/hotspot/src/share/vm/classfile/modules.cpp
+++ b/hotspot/src/share/vm/classfile/modules.cpp
@@ -51,10 +51,7 @@
 static bool verify_module_name(char *module_name) {
   if (module_name == NULL) return false;
   int len = (int)strlen(module_name);
-  return (len > 0 && len <= Symbol::max_length() &&
-    UTF8::is_legal_utf8((unsigned char *)module_name, len, false) &&
-    ClassFileParser::verify_unqualified_name(module_name, len,
-    ClassFileParser::LegalModule));
+  return (len > 0 && len <= Symbol::max_length());
 }
 
 bool Modules::verify_package_name(char *package_name) {
@@ -179,18 +176,18 @@
 
     if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-                "Bad package name for module: java.base");
+                "Bad package name for module: " JAVA_BASE_NAME);
     }
     char *package_name = java_lang_String::as_utf8_string(string_obj);
     if (!Modules::verify_package_name(package_name)) {
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-                err_msg("Invalid package name: %s for module: java.base", package_name));
+                err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name));
     }
     Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
     // append_if_missing() returns FALSE if entry already exists.
     if (!pkg_list->append_if_missing(pkg_symbol)) {
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-                err_msg("Duplicate package name: %s for module java.base",
+                err_msg("Duplicate package name: %s for module " JAVA_BASE_NAME,
                         package_name));
     }
   }
@@ -208,7 +205,7 @@
   assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table");
 
   // Ensure java.base's ModuleEntry has been created
-  assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for java.base");
+  assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for " JAVA_BASE_NAME);
 
   bool duplicate_javabase = false;
   {
@@ -229,7 +226,7 @@
         // Some of java.base's packages were added early in bootstrapping, ignore duplicates.
         if (package_table->lookup_only(pkg_list->at(x)) == NULL) {
           pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_moduleEntry());
-          assert(pkg != NULL, "Unable to create a java.base package entry");
+          assert(pkg != NULL, "Unable to create a " JAVA_BASE_NAME " package entry");
         }
         // Unable to have a GrowableArray of TempNewSymbol.  Must decrement the refcount of
         // the Symbol* that was created above for each package. The refcount was incremented
@@ -243,7 +240,7 @@
   }
   if (duplicate_javabase) {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-              "Module java.base is already defined");
+              "Module " JAVA_BASE_NAME " is already defined");
   }
 
   // Only the thread that actually defined the base module will get here,
@@ -252,15 +249,15 @@
   // Patch any previously loaded class's module field with java.base's java.lang.reflect.Module.
   ModuleEntryTable::patch_javabase_entries(module_handle);
 
-  log_debug(modules)("define_javabase_module(): Definition of module: java.base,"
-                     " version: %s, location: %s, package #: %d",
+  log_debug(modules)("define_javabase_module(): Definition of module: "
+                     JAVA_BASE_NAME ", version: %s, location: %s, package #: %d",
                      module_version != NULL ? module_version : "NULL",
                      module_location != NULL ? module_location : "NULL",
                      pkg_list->length());
 
   // packages defined to java.base
   for (int x = 0; x < pkg_list->length(); x++) {
-    log_trace(modules)("define_javabase_module(): creation of package %s for module java.base",
+    log_trace(modules)("define_javabase_module(): creation of package %s for module " JAVA_BASE_NAME,
                        (pkg_list->at(x))->as_C_string());
   }
 }
@@ -285,7 +282,7 @@
   }
 
   // Special handling of java.base definition
-  if (strcmp(module_name, "java.base") == 0) {
+  if (strcmp(module_name, JAVA_BASE_NAME) == 0) {
     define_javabase_module(module, version, location, packages, CHECK);
     return;
   }
@@ -608,7 +605,8 @@
 
 // This method is called by JFR and JNI.
 jobject Modules::get_module(jclass clazz, TRAPS) {
-  assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module before java.base is defined");
+  assert(ModuleEntryTable::javabase_defined(),
+         "Attempt to call get_module before " JAVA_BASE_NAME " is defined");
 
   if (clazz == NULL) {
     THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
@@ -654,7 +652,7 @@
 jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) {
   ResourceMark rm(THREAD);
   assert(ModuleEntryTable::javabase_defined(),
-         "Attempt to call get_module_from_pkg before java.base is defined");
+         "Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined");
 
   if (NULL == package) {
     THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
@@ -691,7 +689,7 @@
 
 jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
   assert(ModuleEntryTable::javabase_defined(),
-         "Attempt to call get_named_module before java.base is defined");
+         "Attempt to call get_named_module before " JAVA_BASE_NAME " is defined");
   assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
          "Class loader is not a subclass of java.lang.ClassLoader");
   assert(package_str != NULL, "the package_str should not be NULL");
diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp
index f358c51..7ee6c52 100644
--- a/hotspot/src/share/vm/classfile/packageEntry.cpp
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp
@@ -214,7 +214,7 @@
   entry->set_hash(hash);
   entry->set_literal(name);
 
-  TRACE_INIT_PACKAGE_ID(entry);
+  TRACE_INIT_ID(entry);
 
   // Initialize fields specific to a PackageEntry
   entry->init();
@@ -293,7 +293,7 @@
           (module_name->fast_compare(vmSymbols::java_base()) == 0) &&
           !pkg_list->contains(entry->name())) {
         ResourceMark rm;
-        vm_exit_during_initialization("A non-java.base package was loaded prior to module system initialization", entry->name()->as_C_string());
+        vm_exit_during_initialization("A non-" JAVA_BASE_NAME " package was loaded prior to module system initialization", entry->name()->as_C_string());
       }
     }
   }
diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp
index c6ae8e1..25d6783 100644
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.hpp"
@@ -621,35 +622,28 @@
   return (nh);
 }
 
-// utility function for class load event
 static void post_class_load_event(const Ticks& start_time,
                                   instanceKlassHandle k,
-                                  Handle initiating_loader) {
+                                  const ClassLoaderData* init_cld) {
 #if INCLUDE_TRACE
   EventClassLoad event(UNTIMED);
   if (event.should_commit()) {
     event.set_starttime(start_time);
     event.set_loadedClass(k());
-    oop defining_class_loader = k->class_loader();
-    event.set_definingClassLoader(defining_class_loader != NULL ?
-      defining_class_loader->klass() : (Klass*)NULL);
-    oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
-    event.set_initiatingClassLoader(class_loader != NULL ?
-      class_loader->klass() : (Klass*)NULL);
+    event.set_definingClassLoader(k->class_loader_data());
+    event.set_initiatingClassLoader(init_cld);
     event.commit();
   }
 #endif // INCLUDE_TRACE
 }
 
-// utility function for class define event
-static void class_define_event(instanceKlassHandle k) {
+static void class_define_event(instanceKlassHandle k,
+                               const ClassLoaderData* def_cld) {
 #if INCLUDE_TRACE
-  EventClassDefine event(UNTIMED);
+  EventClassDefine event;
   if (event.should_commit()) {
     event.set_definedClass(k());
-    oop defining_class_loader = k->class_loader();
-    event.set_definingClassLoader(defining_class_loader != NULL ?
-      defining_class_loader->klass() : (Klass*)NULL);
+    event.set_definingClassLoader(def_cld);
     event.commit();
   }
 #endif // INCLUDE_TRACE
@@ -907,7 +901,7 @@
     return NULL;
   }
 
-  post_class_load_event(class_load_start_time, k, class_loader);
+  post_class_load_event(class_load_start_time, k, loader_data);
 
 #ifdef ASSERT
   {
@@ -1090,7 +1084,7 @@
         JvmtiExport::post_class_load((JavaThread *) THREAD, k());
     }
 
-    post_class_load_event(class_load_start_time, k, class_loader);
+    post_class_load_event(class_load_start_time, k, loader_data);
   }
   assert(host_klass != NULL || NULL == cp_patches,
          "cp_patches only found with host_klass");
@@ -1158,13 +1152,21 @@
   Symbol* h_name = k->name();
   assert(class_name == NULL || class_name == h_name, "name mismatch");
 
+  bool define_succeeded = false;
   // Add class just loaded
   // If a class loader supports parallel classloading handle parallel define requests
   // find_or_define_instance_class may return a different InstanceKlass
   if (is_parallelCapable(class_loader)) {
-    k = find_or_define_instance_class(h_name, class_loader, k, CHECK_NULL);
+    instanceKlassHandle defined_k = find_or_define_instance_class(h_name, class_loader, k, CHECK_NULL);
+    if (k() == defined_k()) {
+      // we have won over other concurrent threads (if any) that are
+      // competing to define the same class.
+      define_succeeded = true;
+    }
+    k = defined_k;
   } else {
     define_instance_class(k, CHECK_NULL);
+    define_succeeded = true;
   }
 
   // Make sure we have an entry in the SystemDictionary on success
@@ -1408,6 +1410,19 @@
     // notify a class loaded from shared object
     ClassLoadingService::notify_class_loaded(ik(), true /* shared class */);
   }
+
+  ik->set_has_passed_fingerprint_check(false);
+  if (UseAOT && ik->supers_have_passed_fingerprint_checks()) {
+    uint64_t aot_fp = AOTLoader::get_saved_fingerprint(ik());
+    uint64_t cds_fp = ik->get_stored_fingerprint();
+    if (aot_fp != 0 && aot_fp == cds_fp) {
+      // This class matches with a class saved in an AOT library
+      ik->set_has_passed_fingerprint_check(true);
+    } else {
+      ResourceMark rm;
+      log_info(class, fingerprint)("%s :  expected = " PTR64_FORMAT " actual = " PTR64_FORMAT, ik->external_name(), aot_fp, cds_fp);
+    }
+  }
   return ik;
 }
 #endif // INCLUDE_CDS
@@ -1494,7 +1509,9 @@
 
     // find_or_define_instance_class may return a different InstanceKlass
     if (!k.is_null()) {
-      k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));
+      instanceKlassHandle defined_k =
+        find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));
+      k = defined_k;
     }
     return k;
   } else {
@@ -1641,7 +1658,7 @@
       JvmtiExport::post_class_load((JavaThread *) THREAD, k());
 
   }
-  class_define_event(k);
+  class_define_event(k, loader_data);
 }
 
 // Support parallel classloading
@@ -2897,11 +2914,11 @@
 // caller needs ResourceMark
 const char* SystemDictionary::loader_name(const oop loader) {
   return ((loader) == NULL ? "<bootloader>" :
-    InstanceKlass::cast((loader)->klass())->name()->as_C_string());
+          InstanceKlass::cast((loader)->klass())->name()->as_C_string());
 }
 
 // caller needs ResourceMark
 const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
   return (loader_data->class_loader() == NULL ? "<bootloader>" :
-    InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string());
+          SystemDictionary::loader_name(loader_data->class_loader()));
 }
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp
index 31e3519..3e902d9 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
 #define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
 
+#include "classfile/moduleEntry.hpp"
 #include "classfile/vmSymbols_ext.hpp"
 #include "oops/symbol.hpp"
 #include "memory/iterator.hpp"
@@ -50,7 +51,7 @@
 
 #define VM_SYMBOLS_DO(template, do_alias)                                                         \
   /* commonly used class, package, module names */                                                \
-  template(java_base,                                 "java.base")                                \
+  template(java_base,                                 JAVA_BASE_NAME)                             \
   template(java_lang_System,                          "java/lang/System")                         \
   template(java_lang_Object,                          "java/lang/Object")                         \
   template(java_lang_Class,                           "java/lang/Class")                          \
@@ -228,6 +229,7 @@
                                                                                                   \
   /* Support for reflection based on dynamic bytecode generation (JDK 1.4 and above) */           \
                                                                                                   \
+  template(jdk_internal_reflect,                      "jdk/internal/reflect")                     \
   template(reflect_MagicAccessorImpl,                 "jdk/internal/reflect/MagicAccessorImpl")       \
   template(reflect_MethodAccessorImpl,                "jdk/internal/reflect/MethodAccessorImpl")      \
   template(reflect_ConstructorAccessorImpl,           "jdk/internal/reflect/ConstructorAccessorImpl") \
diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp
index 66125a6..1d0634a 100644
--- a/hotspot/src/share/vm/code/codeBlob.cpp
+++ b/hotspot/src/share/vm/code/codeBlob.cpp
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "code/codeBlob.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/relocInfo.hpp"
 #include "compiler/disassembler.hpp"
 #include "interpreter/bytecode.hpp"
@@ -228,7 +227,6 @@
 
   BufferBlob* blob = NULL;
   unsigned int size = sizeof(BufferBlob);
-  CodeCacheExtensions::size_blob(name, &buffer_size);
   // align the size to CodeEntryAlignment
   size = CodeBlob::align_code_offset(size);
   size += round_to(buffer_size, oopSize);
@@ -312,7 +310,6 @@
 
   MethodHandlesAdapterBlob* blob = NULL;
   unsigned int size = sizeof(MethodHandlesAdapterBlob);
-  CodeCacheExtensions::size_blob("MethodHandles adapters", &buffer_size);
   // align the size to CodeEntryAlignment
   size = CodeBlob::align_code_offset(size);
   size += round_to(buffer_size, oopSize);
@@ -354,13 +351,11 @@
 {
   RuntimeStub* stub = NULL;
   ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
-  if (!CodeCacheExtensions::skip_code_generation()) {
-    // bypass useless code generation
+  {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     unsigned int size = CodeBlob::allocation_size(cb, sizeof(RuntimeStub));
     stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments);
   }
-  stub = (RuntimeStub*) CodeCacheExtensions::handle_generated_blob(stub, stub_name);
 
   trace_new_stub(stub, "RuntimeStub - ", stub_name);
 
diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp
index ff0f9cf..0f536b5 100644
--- a/hotspot/src/share/vm/code/codeBlob.hpp
+++ b/hotspot/src/share/vm/code/codeBlob.hpp
@@ -40,7 +40,7 @@
     MethodProfiled      = 1,    // Execution level 2 and 3 (profiled) nmethods
     NonNMethod          = 2,    // Non-nmethods like Buffers, Adapters and Runtime Stubs
     All                 = 3,    // All types (No code cache segmentation)
-    Pregenerated        = 4,    // Special blobs, managed by CodeCacheExtensions
+    AOT                 = 4,    // AOT methods
     NumTypes            = 5     // Number of CodeBlobTypes
   };
 };
@@ -118,6 +118,7 @@
   virtual bool is_safepoint_stub() const              { return false; }
   virtual bool is_adapter_blob() const                { return false; }
   virtual bool is_method_handles_adapter_blob() const { return false; }
+  virtual bool is_aot() const                         { return false; }
   virtual bool is_compiled() const                    { return false; }
 
   inline bool is_compiled_by_c1() const    { return _type == compiler_c1; };
@@ -131,6 +132,7 @@
   nmethod* as_nmethod()                        { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; }
   CompiledMethod* as_compiled_method_or_null() { return is_compiled() ? (CompiledMethod*) this : NULL; }
   CompiledMethod* as_compiled_method()         { assert(is_compiled(), "must be compiled"); return (CompiledMethod*) this; }
+  CodeBlob* as_codeblob_or_null() const        { return (CodeBlob*) this; }
 
   // Boundaries
   address header_begin() const        { return (address) this; }
@@ -159,7 +161,8 @@
   bool blob_contains(address addr) const         { return header_begin()       <= addr && addr < data_end();       }
   bool code_contains(address addr) const         { return code_begin()         <= addr && addr < code_end();       }
   bool contains(address addr) const              { return content_begin()      <= addr && addr < content_end();    }
-  bool is_frame_complete_at(address addr) const  { return code_contains(addr) && addr >= code_begin() + _frame_complete_offset; }
+  bool is_frame_complete_at(address addr) const  { return _frame_complete_offset != CodeOffsets::frame_never_safe &&
+                                                          code_contains(addr) && addr >= code_begin() + _frame_complete_offset; }
 
   // CodeCache support: really only used by the nmethods, but in order to get
   // asserts and certain bookkeeping to work in the CodeCache they are defined
@@ -205,6 +208,7 @@
 
   // Transfer ownership of comments to this CodeBlob
   void set_strings(CodeStrings& strings) {
+    assert(!is_aot(), "invalid on aot");
     _strings.assign(strings);
   }
 
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index 5d81805..80ce54f 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "code/codeBlob.hpp"
 #include "code/codeCache.hpp"
 #include "code/compiledIC.hpp"
@@ -128,6 +129,8 @@
 
 // Iterate over all CodeHeaps
 #define FOR_ALL_HEAPS(heap) for (GrowableArrayIterator<CodeHeap*> heap = _heaps->begin(); heap != _heaps->end(); ++heap)
+#define FOR_ALL_NMETHOD_HEAPS(heap) for (GrowableArrayIterator<CodeHeap*> heap = _nmethod_heaps->begin(); heap != _nmethod_heaps->end(); ++heap)
+
 // Iterate over all CodeBlobs (cb) on the given CodeHeap
 #define FOR_ALL_BLOBS(cb, heap) for (CodeBlob* cb = first_blob(heap); cb != NULL; cb = next_blob(heap, cb))
 
@@ -139,6 +142,8 @@
 
 // Initialize array of CodeHeaps
 GrowableArray<CodeHeap*>* CodeCache::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<CodeHeap*> (CodeBlobType::All, true);
+GrowableArray<CodeHeap*>* CodeCache::_compiled_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<CodeHeap*> (CodeBlobType::All, true);
+GrowableArray<CodeHeap*>* CodeCache::_nmethod_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<CodeHeap*> (CodeBlobType::All, true);
 
 void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, bool all_set) {
   size_t total_size = non_nmethod_size + profiled_size + non_profiled_size;
@@ -365,6 +370,28 @@
   return NULL;
 }
 
+int CodeCache::code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs) {
+  if (lhs->code_blob_type() == rhs->code_blob_type()) {
+    return (lhs > rhs) ? 1 : ((lhs < rhs) ? -1 : 0);
+  } else {
+    return lhs->code_blob_type() - rhs->code_blob_type();
+  }
+}
+
+void CodeCache::add_heap(CodeHeap* heap) {
+  assert(!Universe::is_fully_initialized(), "late heap addition?");
+
+  _heaps->insert_sorted<code_heap_compare>(heap);
+
+  int type = heap->code_blob_type();
+  if (code_blob_type_accepts_compiled(type)) {
+    _compiled_heaps->insert_sorted<code_heap_compare>(heap);
+  }
+  if (code_blob_type_accepts_nmethod(type)) {
+    _nmethod_heaps->insert_sorted<code_heap_compare>(heap);
+  }
+}
+
 void CodeCache::add_heap(ReservedSpace rs, const char* name, int code_blob_type) {
   // Check if heap is needed
   if (!heap_available(code_blob_type)) {
@@ -373,7 +400,7 @@
 
   // Create CodeHeap
   CodeHeap* heap = new CodeHeap(name, code_blob_type);
-  _heaps->append(heap);
+  add_heap(heap);
 
   // Reserve Space
   size_t size_initial = MIN2(InitialCodeCacheSize, rs.size());
@@ -389,7 +416,7 @@
 CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) {
   assert(cb != NULL, "CodeBlob is null");
   FOR_ALL_HEAPS(heap) {
-    if ((*heap)->contains(cb)) {
+    if ((*heap)->contains(cb->code_begin())) {
       return *heap;
     }
   }
@@ -426,10 +453,6 @@
   return (CodeBlob*)heap->next(cb);
 }
 
-CodeBlob* CodeCache::next_blob(CodeBlob* cb) {
-  return next_blob(get_code_heap(cb), cb);
-}
-
 /**
  * Do not seize the CodeCache lock here--if the caller has not
  * already done so, we are going to lose bigtime, since the code
@@ -494,7 +517,7 @@
     }
     if (PrintCodeCacheExtension) {
       ResourceMark rm;
-      if (_heaps->length() >= 1) {
+      if (_nmethod_heaps->length() >= 1) {
         tty->print("%s", heap->name());
       } else {
         tty->print("CodeCache");
@@ -559,6 +582,10 @@
   return false;
 }
 
+bool CodeCache::contains(nmethod *nm) {
+  return contains((void *)nm);
+}
+
 // This method is safe to call without holding the CodeCache_lock, as long as a dead CodeBlob is not
 // looked up (i.e., one that has been marked for deletion). It only depends on the _segmap to contain
 // valid indices, which it will always do, as long as the CodeBlob is not in the process of being recycled.
@@ -575,8 +602,8 @@
   // NMT can walk the stack before code cache is created
   if (_heaps != NULL && !_heaps->is_empty()) {
     FOR_ALL_HEAPS(heap) {
-      CodeBlob* result = (CodeBlob*) (*heap)->find_start(start);
-      if (result != NULL && result->blob_contains((address)start)) {
+      CodeBlob* result = (*heap)->find_blob_unsafe(start);
+      if (result != NULL) {
         return result;
       }
     }
@@ -592,7 +619,7 @@
 
 void CodeCache::blobs_do(void f(CodeBlob* nm)) {
   assert_locked_or_safepoint(CodeCache_lock);
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     FOR_ALL_BLOBS(cb, *heap) {
       f(cb);
     }
@@ -613,6 +640,7 @@
   while(iter.next_alive()) {
     iter.method()->metadata_do(f);
   }
+  AOTLoader::metadata_do(f);
 }
 
 int CodeCache::alignment_unit() {
@@ -634,11 +662,10 @@
 
 void CodeCache::blobs_do(CodeBlobClosure* f) {
   assert_locked_or_safepoint(CodeCache_lock);
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     FOR_ALL_BLOBS(cb, *heap) {
       if (cb->is_alive()) {
         f->do_code_blob(cb);
-
 #ifdef ASSERT
         if (cb->is_nmethod())
         ((nmethod*)cb)->verify_scavenge_root_oops();
@@ -835,13 +862,12 @@
   int count = 0;
   FOR_ALL_HEAPS(heap) {
     FOR_ALL_BLOBS(cb, *heap) {
-      if (cb->is_nmethod()) {
-        nmethod* nm = (nmethod*)cb;
+      CompiledMethod *nm = cb->as_compiled_method_or_null();
+      if (nm != NULL) {
         count += nm->verify_icholder_relocations();
       }
     }
   }
-
   assert(count + InlineCacheBuffer::pending_icholder_count() + CompiledICHolder::live_not_claimed_count() ==
          CompiledICHolder::live_count(), "must agree");
 #endif
@@ -902,7 +928,7 @@
 
 int CodeCache::nmethod_count() {
   int count = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     count += (*heap)->nmethod_count();
   }
   return count;
@@ -933,7 +959,7 @@
 
 size_t CodeCache::capacity() {
   size_t cap = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     cap += (*heap)->capacity();
   }
   return cap;
@@ -946,7 +972,7 @@
 
 size_t CodeCache::unallocated_capacity() {
   size_t unallocated_cap = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     unallocated_cap += (*heap)->unallocated_capacity();
   }
   return unallocated_cap;
@@ -954,7 +980,7 @@
 
 size_t CodeCache::max_capacity() {
   size_t max_cap = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     max_cap += (*heap)->max_capacity();
   }
   return max_cap;
@@ -980,7 +1006,7 @@
 
 size_t CodeCache::bytes_allocated_in_freelists() {
   size_t allocated_bytes = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     allocated_bytes += (*heap)->allocated_in_freelist();
   }
   return allocated_bytes;
@@ -988,7 +1014,7 @@
 
 int CodeCache::allocated_segments() {
   int number_of_segments = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     number_of_segments += (*heap)->allocated_segments();
   }
   return number_of_segments;
@@ -996,7 +1022,7 @@
 
 size_t CodeCache::freelists_length() {
   size_t length = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     length += (*heap)->freelist_length();
   }
   return length;
@@ -1039,6 +1065,8 @@
 
 void codeCache_init() {
   CodeCache::initialize();
+  // Load AOT libraries and add AOT code heaps.
+  AOTLoader::initialize();
 }
 
 //------------------------------------------------------------------------------------------------
@@ -1102,6 +1130,15 @@
   return (CompiledMethod*)cb;
 }
 
+bool CodeCache::is_far_target(address target) {
+#if INCLUDE_AOT
+  return NativeCall::is_far_call(_low_bound,  target) ||
+         NativeCall::is_far_call(_high_bound, target);
+#else
+  return false;
+#endif
+}
+
 #ifdef HOTSWAP
 int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
@@ -1204,7 +1241,7 @@
 void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) {
   // --- Compile_lock is not held. However we are at a safepoint.
   assert_locked_or_safepoint(Compile_lock);
-  if (number_of_nmethods_with_dependencies() == 0) return;
+  if (number_of_nmethods_with_dependencies() == 0 && !UseAOT) return;
 
   // CodeCache can only be updated by a thread_in_VM and they will all be
   // stopped during the safepoint so CodeCache will be safe to update without
@@ -1316,7 +1353,7 @@
 
 void CodeCache::print_memory_overhead() {
   size_t wasted_bytes = 0;
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
       CodeHeap* curr_heap = *heap;
       for (CodeBlob* cb = (CodeBlob*)curr_heap->first(); cb != NULL; cb = (CodeBlob*)curr_heap->next(cb)) {
         HeapBlock* heap_block = ((HeapBlock*)cb) - 1;
@@ -1362,8 +1399,8 @@
   ResourceMark rm;
 
   int i = 0;
-  FOR_ALL_HEAPS(heap) {
-    if ((_heaps->length() >= 1) && Verbose) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
+    if ((_nmethod_heaps->length() >= 1) && Verbose) {
       tty->print_cr("-- %s --", (*heap)->name());
     }
     FOR_ALL_BLOBS(cb, *heap) {
@@ -1459,7 +1496,7 @@
   CodeBlob_sizes live;
   CodeBlob_sizes dead;
 
-  FOR_ALL_HEAPS(heap) {
+  FOR_ALL_NMETHOD_HEAPS(heap) {
     FOR_ALL_BLOBS(cb, *heap) {
       if (!cb->is_alive()) {
         dead.add(cb);
@@ -1485,7 +1522,7 @@
     int number_of_blobs = 0;
     int number_of_oop_maps = 0;
     int map_size = 0;
-    FOR_ALL_HEAPS(heap) {
+    FOR_ALL_NMETHOD_HEAPS(heap) {
       FOR_ALL_BLOBS(cb, *heap) {
         if (cb->is_alive()) {
           number_of_blobs++;
@@ -1568,35 +1605,3 @@
             unallocated_capacity());
 }
 
-// Initialize iterator to given compiled method
-void CompiledMethodIterator::initialize(CompiledMethod* cm) {
-  _code_blob = (CodeBlob*)cm;
-  if (!SegmentedCodeCache) {
-    // Iterate over all CodeBlobs
-    _code_blob_type = CodeBlobType::All;
-  } else if (cm != NULL) {
-    _code_blob_type = CodeCache::get_code_blob_type(cm);
-  } else {
-    // Only iterate over method code heaps, starting with non-profiled
-    _code_blob_type = CodeBlobType::MethodNonProfiled;
-  }
-}
-
-// Advance iterator to the next compiled method in the current code heap
-bool CompiledMethodIterator::next_compiled_method() {
-  // Get first method CodeBlob
-  if (_code_blob == NULL) {
-    _code_blob = CodeCache::first_blob(_code_blob_type);
-    if (_code_blob == NULL) {
-      return false;
-    } else if (_code_blob->is_nmethod()) {
-      return true;
-    }
-  }
-  // Search for next method CodeBlob
-  _code_blob = CodeCache::next_blob(_code_blob);
-  while (_code_blob != NULL && !_code_blob->is_compiled()) {
-    _code_blob = CodeCache::next_blob(_code_blob);
-  }
-  return _code_blob != NULL;
-}
diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp
index 43aafbf..99209dc 100644
--- a/hotspot/src/share/vm/code/codeCache.hpp
+++ b/hotspot/src/share/vm/code/codeCache.hpp
@@ -77,13 +77,14 @@
 class CodeCache : AllStatic {
   friend class VMStructs;
   friend class JVMCIVMStructs;
-  friend class NMethodIterator;
-  friend class CompiledMethodIterator;
+  template <class T, class Filter> friend class CodeBlobIterator;
   friend class WhiteBox;
   friend class CodeCacheLoader;
  private:
   // CodeHeaps of the cache
   static GrowableArray<CodeHeap*>* _heaps;
+  static GrowableArray<CodeHeap*>* _compiled_heaps;
+  static GrowableArray<CodeHeap*>* _nmethod_heaps;
 
   static address _low_bound;                            // Lower bound of CodeHeap addresses
   static address _high_bound;                           // Upper bound of CodeHeap addresses
@@ -110,8 +111,7 @@
   // Iteration
   static CodeBlob* first_blob(CodeHeap* heap);                // Returns the first CodeBlob on the given CodeHeap
   static CodeBlob* first_blob(int code_blob_type);            // Returns the first CodeBlob of the given type
-  static CodeBlob* next_blob(CodeHeap* heap, CodeBlob* cb);   // Returns the first alive CodeBlob on the given CodeHeap
-  static CodeBlob* next_blob(CodeBlob* cb);                   // Returns the next CodeBlob of the given type succeeding the given CodeBlob
+  static CodeBlob* next_blob(CodeHeap* heap, CodeBlob* cb);   // Returns the next CodeBlob on the given CodeHeap
 
   static size_t bytes_allocated_in_freelists();
   static int    allocated_segments();
@@ -121,10 +121,20 @@
   static void prune_scavenge_root_nmethods();
   static void unlink_scavenge_root_nmethod(nmethod* nm, nmethod* prev);
 
+  // Make private to prevent unsafe calls.  Not all CodeBlob*'s are embedded in a CodeHeap.
+  static bool contains(CodeBlob *p) { fatal("don't call me!"); return false; }
+
  public:
   // Initialization
   static void initialize();
 
+  static int code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs);
+
+  static void add_heap(CodeHeap* heap);
+  static const GrowableArray<CodeHeap*>* heaps() { return _heaps; }
+  static const GrowableArray<CodeHeap*>* compiled_heaps() { return _compiled_heaps; }
+  static const GrowableArray<CodeHeap*>* nmethod_heaps() { return _nmethod_heaps; }
+
   // Allocation/administration
   static CodeBlob* allocate(int size, int code_blob_type, int orig_code_blob_type = CodeBlobType::All); // allocates a new CodeBlob
   static void commit(CodeBlob* cb);                        // called when the allocated CodeBlob has been filled
@@ -132,6 +142,7 @@
   static int  alignment_offset();                          // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
   static void free(CodeBlob* cb);                          // frees a CodeBlob
   static bool contains(void *p);                           // returns whether p is included
+  static bool contains(nmethod* nm);                       // returns whether nm is included
   static void blobs_do(void f(CodeBlob* cb));              // iterates over all CodeBlobs
   static void blobs_do(CodeBlobClosure* f);                // iterates over all CodeBlobs
   static void nmethods_do(void f(nmethod* nm));            // iterates over all nmethods
@@ -192,6 +203,9 @@
   static address high_bound()                         { return _high_bound; }
   static address high_bound(int code_blob_type);
 
+  // Have to use far call instructions to call this pc.
+  static bool is_far_target(address pc);
+
   // Profiling
   static size_t capacity();
   static size_t unallocated_capacity(int code_blob_type);
@@ -208,11 +222,21 @@
   // Returns true if an own CodeHeap for the given CodeBlobType is available
   static bool heap_available(int code_blob_type);
 
-  // Returns the CodeBlobType for the given nmethod
+  // Returns the CodeBlobType for the given CompiledMethod
   static int get_code_blob_type(CompiledMethod* cm) {
     return get_code_heap(cm)->code_blob_type();
   }
 
+  static bool code_blob_type_accepts_compiled(int type) {
+    bool result = type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled;
+    AOT_ONLY( result = result || type == CodeBlobType::AOT; )
+    return result;
+  }
+
+  static bool code_blob_type_accepts_nmethod(int type) {
+    return type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled;
+  }
+
   // Returns the CodeBlobType for the given compilation level
   static int get_code_blob_type(int comp_level) {
     if (comp_level == CompLevel_none ||
@@ -264,35 +288,47 @@
 
 
 // Iterator to iterate over nmethods in the CodeCache.
-class NMethodIterator : public StackObj {
+template <class T, class Filter> class CodeBlobIterator : public StackObj {
  private:
   CodeBlob* _code_blob;   // Current CodeBlob
-  int _code_blob_type;    // Refers to current CodeHeap
+  GrowableArrayIterator<CodeHeap*> _heap;
+  GrowableArrayIterator<CodeHeap*> _end;
 
  public:
-  NMethodIterator() {
-    initialize(NULL); // Set to NULL, initialized by first call to next()
+  CodeBlobIterator(T* nm = NULL) {
+    if (Filter::heaps() == NULL) {
+      return;
+    }
+    _heap = Filter::heaps()->begin();
+    _end = Filter::heaps()->end();
+    // If set to NULL, initialized by first call to next()
+    _code_blob = (CodeBlob*)nm;
+    if (nm != NULL) {
+      address start = nm->code_begin();
+      while(!(*_heap)->contains(start)) {
+        ++_heap;
+      }
+      assert((*_heap)->contains(start), "match not found");
+    }
   }
 
-  NMethodIterator(nmethod* nm) {
-    initialize(nm);
-  }
-
-  // Advance iterator to next nmethod
+  // Advance iterator to next blob
   bool next() {
     assert_locked_or_safepoint(CodeCache_lock);
-    assert(_code_blob_type < CodeBlobType::NumTypes, "end reached");
 
-    bool result = next_nmethod();
-    while (!result && (_code_blob_type < CodeBlobType::MethodProfiled)) {
-      // Advance to next code heap if segmented code cache
-      _code_blob_type++;
-      result = next_nmethod();
+    bool result = next_blob();
+    while (!result && _heap != _end) {
+      // Advance to next code heap of segmented code cache
+      if (++_heap == _end) {
+        break;
+      }
+      result = next_blob();
     }
+
     return result;
   }
 
-  // Advance iterator to next alive nmethod
+  // Advance iterator to next alive blob
   bool next_alive() {
     bool result = next();
     while(result && !_code_blob->is_alive()) {
@@ -302,90 +338,48 @@
   }
 
   bool end()        const   { return _code_blob == NULL; }
-  nmethod* method() const   { return (nmethod*)_code_blob; }
+  T* method() const   { return (T*)_code_blob; }
 
 private:
-  // Initialize iterator to given nmethod
-  void initialize(nmethod* nm) {
-    _code_blob = (CodeBlob*)nm;
-    if (!SegmentedCodeCache) {
-      // Iterate over all CodeBlobs
-      _code_blob_type = CodeBlobType::All;
-    } else if (nm != NULL) {
-      _code_blob_type = CodeCache::get_code_blob_type(nm);
-    } else {
-      // Only iterate over method code heaps, starting with non-profiled
-      _code_blob_type = CodeBlobType::MethodNonProfiled;
-    }
-  }
 
-  // Advance iterator to the next nmethod in the current code heap
-  bool next_nmethod() {
+  // Advance iterator to the next blob in the current code heap
+  bool next_blob() {
+    if (_heap == _end) {
+      return false;
+    }
+    CodeHeap *heap = *_heap;
     // Get first method CodeBlob
     if (_code_blob == NULL) {
-      _code_blob = CodeCache::first_blob(_code_blob_type);
+      _code_blob = CodeCache::first_blob(heap);
       if (_code_blob == NULL) {
         return false;
-      } else if (_code_blob->is_nmethod()) {
+      } else if (Filter::apply(_code_blob)) {
         return true;
       }
     }
     // Search for next method CodeBlob
-    _code_blob = CodeCache::next_blob(_code_blob);
-    while (_code_blob != NULL && !_code_blob->is_nmethod()) {
-      _code_blob = CodeCache::next_blob(_code_blob);
+    _code_blob = CodeCache::next_blob(heap, _code_blob);
+    while (_code_blob != NULL && !Filter::apply(_code_blob)) {
+      _code_blob = CodeCache::next_blob(heap, _code_blob);
     }
     return _code_blob != NULL;
   }
 };
 
-// Iterator to iterate over compiled methods in the CodeCache.
-class CompiledMethodIterator : public StackObj {
- private:
-  CodeBlob* _code_blob;   // Current CodeBlob
-  int _code_blob_type;    // Refers to current CodeHeap
 
- public:
-  CompiledMethodIterator() {
-    initialize(NULL); // Set to NULL, initialized by first call to next()
-  }
-
-  CompiledMethodIterator(CompiledMethod* cm) {
-    initialize(cm);
-  }
-
-  // Advance iterator to next compiled method
-  bool next() {
-    assert_locked_or_safepoint(CodeCache_lock);
-    assert(_code_blob_type < CodeBlobType::NumTypes, "end reached");
-
-    bool result = next_compiled_method();
-    while (!result && (_code_blob_type < CodeBlobType::MethodProfiled)) {
-      // Advance to next code heap if segmented code cache
-      _code_blob_type++;
-      result = next_compiled_method();
-    }
-    return result;
-  }
-
-  // Advance iterator to next alive compiled method
-  bool next_alive() {
-    bool result = next();
-    while(result && !_code_blob->is_alive()) {
-      result = next();
-    }
-    return result;
-  }
-
-  bool end()        const   { return _code_blob == NULL; }
-  CompiledMethod* method() const   { return (_code_blob != NULL) ? _code_blob->as_compiled_method() : NULL; }
-
-private:
-  // Initialize iterator to given compiled method
-  void initialize(CompiledMethod* cm);
-
-  // Advance iterator to the next compiled method in the current code heap
-  bool next_compiled_method();
+struct CompiledMethodFilter {
+  static bool apply(CodeBlob* cb) { return cb->is_compiled(); }
+  static const GrowableArray<CodeHeap*>* heaps() { return CodeCache::compiled_heaps(); }
 };
 
+
+struct NMethodFilter {
+  static bool apply(CodeBlob* cb) { return cb->is_nmethod(); }
+  static const GrowableArray<CodeHeap*>* heaps() { return CodeCache::nmethod_heaps(); }
+};
+
+
+typedef CodeBlobIterator<CompiledMethod, CompiledMethodFilter> CompiledMethodIterator;
+typedef CodeBlobIterator<nmethod, NMethodFilter> NMethodIterator;
+
 #endif // SHARE_VM_CODE_CODECACHE_HPP
diff --git a/hotspot/src/share/vm/code/codeCacheExtensions.hpp b/hotspot/src/share/vm/code/codeCacheExtensions.hpp
deleted file mode 100644
index a7fd50f..0000000
--- a/hotspot/src/share/vm/code/codeCacheExtensions.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
-#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
-
-#include "memory/allocation.hpp"
-
-class CodeCacheExtensionsSteps: AllStatic {
-public:
-  enum Step {
-    // Support for optional fine grain initialization hooks
-    // Note: these hooks must support refining the granularity
-    // (e.g. adding intermediate steps in the ordered enum
-    // if needed for future features)
-    Start,
-    VMVersion,
-    StubRoutines1,
-    Universe,
-    TemplateInterpreter,
-    Interpreter,
-    StubRoutines2,
-    InitGlobals,
-    CreateVM,
-    LastStep
-  };
-};
-
-#include "code/codeCacheExtensions_ext.hpp"
-
-#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
diff --git a/hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp b/hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
deleted file mode 100644
index 3edb1c7..0000000
--- a/hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
-#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
-
-#include "utilities/macros.hpp"
-#include "memory/allocation.hpp"
-#include "utilities/globalDefinitions.hpp"
-#include "interpreter/bytecodes.hpp"
-
-class AdapterHandlerEntry;
-class CodeBlob;
-class CodeBuffer;
-class InterpreterMacroAssembler;
-class Template;
-
-// All the methods defined here are placeholders for possible extensions.
-
-class CodeCacheExtensions: AllStatic {
-  friend class CodeCacheDumper;
-
-public:
-  // init both code saving and loading
-  // Must be called very early, before any code is generated.
-  static void initialize() {}
-
-  // Check whether the generated interpreter will be saved.
-  static bool saving_generated_interpreter() { return false; }
-
-  // Check whether a pregenerated interpreter is used.
-  static bool use_pregenerated_interpreter() { return false; }
-
-  // Placeholder for additional VM initialization code
-  static void complete_step(CodeCacheExtensionsSteps::Step phase) {}
-
-  // Return false for newly generated code, on systems where it is not
-  // executable.
-  static bool is_executable(void *pc) { return true; }
-
-  // Return whether dynamically generated code can be executable
-  static bool support_dynamic_code() { return true; }
-
-  // Skip new code generation when known to be useless.
-  static bool skip_code_generation() { return false; }
-
-  // Skip stubs used only for compiled code support.
-  static bool skip_compiler_support() { return false; }
-
-  // Ignore UseFastSignatureHandlers when returning false
-  static bool support_fast_signature_handlers() { return true; }
-
-  /////////////////////////
-  // Handle generated code:
-  // - allow newly generated code to be shared
-  // - allow pregenerated code to be used in place of the newly generated one
-  //   (modifying pc).
-  // - support remapping when doing both save and load
-  // 'remap' can be set to false if the addresses handled are not referenced
-  // from code generated later.
-
-  // Associate a name to a generated codelet and possibly modify the pc
-  // Note: use instead the specialized versions when they exist:
-  // - handle_generated_blob for CodeBlob
-  // - handle_generated_handler for SignatureHandlers
-  // See also the optimized calls below that handle several PCs at once.
-  static void handle_generated_pc(address &pc, const char *name) {}
-
-  // Adds a safe definition of the codelet, for codelets used right after
-  // generation (else we would need to immediately stop the JVM and convert
-  // the generated code to executable format before being able to go further).
-  static void handle_generated_pc(address &pc, const char *name, address default_entry) {}
-
-  // Special cases
-
-  // Special case for CodeBlobs, which may require blob specific actions.
-  static CodeBlob* handle_generated_blob(CodeBlob* blob, const char *name = NULL) { return blob; }
-
-  // Special case for Signature Handlers.
-  static void handle_generated_handler(address &handler_start, const char *name, address handler_end) {}
-
-  // Support for generating different variants of the interpreter
-  // that can be dynamically selected after reload.
-  //
-  // - init_interpreter_assembler allows to configure the assembler for
-  //   the current variant
-  //
-  // - needs_other_interpreter_variant returns true as long as other
-  //   variants are needed.
-  //
-  // - skip_template_interpreter_entries returns true if new entries
-  //   need not be generated for this masm setup and this bytecode
-  //
-  // - completed_template_interpreter_entries is called after new
-  //   entries have been generated and installed, for any non skipped
-  //   bytecode.
-  static void init_interpreter_assembler(InterpreterMacroAssembler* masm, CodeBuffer* code) {}
-  static bool needs_other_interpreter_variant() { return false; }
-  static bool skip_template_interpreter_entries(Bytecodes::Code code) { return false; }
-  static void completed_template_interpreter_entries(InterpreterMacroAssembler* masm, Bytecodes::Code code) {}
-
-  // Code size optimization. May optimize the requested size.
-  static void size_blob(const char* name, int *updatable_size) {}
-
-  // ergonomics
-  static void set_ergonomics_flags() {}
-};
-
-#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp
index 748589e..97db8a5 100644
--- a/hotspot/src/share/vm/code/compiledIC.cpp
+++ b/hotspot/src/share/vm/code/compiledIC.cpp
@@ -55,7 +55,7 @@
   assert (!is_optimized(), "an optimized virtual call does not have a cached metadata");
 
   if (!is_in_transition_state()) {
-    void* data = (void*)_value->data();
+    void* data = get_data();
     // If we let the metadata value here be initialized to zero...
     assert(data != NULL || Universe::non_oop_word() == NULL,
            "no raw nulls in CompiledIC metadatas, because of patching races");
@@ -77,13 +77,13 @@
   // Don't use ic_destination for this test since that forwards
   // through ICBuffer instead of returning the actual current state of
   // the CompiledIC.
-  if (is_icholder_entry(_ic_call->destination())) {
+  if (is_icholder_entry(_call->destination())) {
     // When patching for the ICStub case the cached value isn't
     // overwritten until the ICStub copied into the CompiledIC during
     // the next safepoint.  Make sure that the CompiledICHolder* is
     // marked for release at this point since it won't be identifiable
     // once the entry point is overwritten.
-    InlineCacheBuffer::queue_for_release((CompiledICHolder*)_value->data());
+    InlineCacheBuffer::queue_for_release((CompiledICHolder*)get_data());
   }
 
   if (TraceCompiledIC) {
@@ -102,10 +102,10 @@
   {
     MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
 #ifdef ASSERT
-    CodeBlob* cb = CodeCache::find_blob_unsafe(_ic_call);
+    CodeBlob* cb = CodeCache::find_blob_unsafe(_call->instruction_address());
     assert(cb != NULL && cb->is_compiled(), "must be compiled");
 #endif
-     _ic_call->set_destination_mt_safe(entry_point);
+    _call->set_destination_mt_safe(entry_point);
   }
 
   if (is_optimized() || is_icstub) {
@@ -118,7 +118,7 @@
 
   if (cache == NULL)  cache = (void*)Universe::non_oop_word();
 
-  _value->set_data((intptr_t)cache);
+  set_data((intptr_t)cache);
 }
 
 
@@ -131,7 +131,7 @@
 address CompiledIC::ic_destination() const {
  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
  if (!is_in_transition_state()) {
-   return _ic_call->destination();
+   return _call->destination();
  } else {
    return InlineCacheBuffer::ic_destination_for((CompiledIC *)this);
  }
@@ -140,7 +140,7 @@
 
 bool CompiledIC::is_in_transition_state() const {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
-  return InlineCacheBuffer::contains(_ic_call->destination());
+  return InlineCacheBuffer::contains(_call->destination());;
 }
 
 
@@ -153,7 +153,7 @@
 // the InlineCacheBuffer when it needs to find the stub.
 address CompiledIC::stub_address() const {
   assert(is_in_transition_state(), "should only be called when we are in a transition state");
-  return _ic_call->destination();
+  return _call->destination();
 }
 
 // Clears the IC stub if the compiled IC is in transition state
@@ -164,17 +164,16 @@
   }
 }
 
-
 //-----------------------------------------------------------------------------
 // High-level access to an inline cache. Guaranteed to be MT-safe.
 
 void CompiledIC::initialize_from_iter(RelocIterator* iter) {
-  assert(iter->addr() == _ic_call->instruction_address(), "must find ic_call");
+  assert(iter->addr() == _call->instruction_address(), "must find ic_call");
 
   if (iter->type() == relocInfo::virtual_call_type) {
     virtual_call_Relocation* r = iter->virtual_call_reloc();
     _is_optimized = false;
-    _value = nativeMovConstReg_at(r->cached_value());
+    _value = _call->get_load_instruction(r);
   } else {
     assert(iter->type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
     _is_optimized = true;
@@ -183,9 +182,10 @@
 }
 
 CompiledIC::CompiledIC(CompiledMethod* cm, NativeCall* call)
-  : _ic_call(call)
+  : _method(cm)
 {
-  address ic_call = _ic_call->instruction_address();
+  _call = _method->call_wrapper_at((address) call);
+  address ic_call = _call->instruction_address();
 
   assert(ic_call != NULL, "ic_call address must be set");
   assert(cm != NULL, "must pass compiled method");
@@ -201,9 +201,10 @@
 }
 
 CompiledIC::CompiledIC(RelocIterator* iter)
-  : _ic_call(nativeCall_at(iter->addr()))
+  : _method(iter->code())
 {
-  address ic_call = _ic_call->instruction_address();
+  _call = _method->call_wrapper_at(iter->addr());
+  address ic_call = _call->instruction_address();
 
   CompiledMethod* nm = iter->code();
   assert(ic_call != NULL, "ic_call address must be set");
@@ -311,20 +312,17 @@
     assert(!is_call_to_interpreted || (is_icholder_call() && cached_icholder() != NULL), "sanity check");
   } else {
     // Check if we are calling into our own codeblob (i.e., to a stub)
-    CodeBlob* cb = CodeCache::find_blob(_ic_call->instruction_address());
     address dest = ic_destination();
 #ifdef ASSERT
     {
-      CodeBlob* db = CodeCache::find_blob_unsafe(dest);
-      assert(!db->is_adapter_blob(), "must use stub!");
+      _call->verify_resolve_call(dest);
     }
 #endif /* ASSERT */
-    is_call_to_interpreted = cb->contains(dest);
+    is_call_to_interpreted = _call->is_call_to_interpreted(dest);
   }
   return is_call_to_interpreted;
 }
 
-
 void CompiledIC::set_to_clean(bool in_use) {
   assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call");
   if (TraceInlineCacheClearing || TraceICs) {
@@ -332,16 +330,11 @@
     print();
   }
 
-  address entry;
-  if (is_optimized()) {
-    entry = SharedRuntime::get_resolve_opt_virtual_call_stub();
-  } else {
-    entry = SharedRuntime::get_resolve_virtual_call_stub();
-  }
+  address entry = _call->get_resolve_call_stub(is_optimized());
 
   // A zombie transition will always be safe, since the metadata has already been set to NULL, so
   // we only need to patch the destination
-  bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
+  bool safe_transition = _call->is_safe_for_patching() || !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
 
   if (safe_transition) {
     // Kill any leftover stub we might have too
@@ -364,18 +357,15 @@
   // assert(is_clean(), "sanity check");
 }
 
-
 bool CompiledIC::is_clean() const {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
   bool is_clean = false;
   address dest = ic_destination();
-  is_clean = dest == SharedRuntime::get_resolve_opt_virtual_call_stub() ||
-             dest == SharedRuntime::get_resolve_virtual_call_stub();
+  is_clean = dest == _call->get_resolve_call_stub(is_optimized());
   assert(!is_clean || is_optimized() || cached_value() == NULL, "sanity check");
   return is_clean;
 }
 
-
 void CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
   // Updating a cache to the wrong entry can cause bugs that are very hard
@@ -391,7 +381,7 @@
   // transitions are mt_safe
 
   Thread *thread = Thread::current();
-  if (info.to_interpreter()) {
+  if (info.to_interpreter() || info.to_aot()) {
     // Call to interpreter
     if (info.is_optimized() && is_optimized()) {
        assert(is_clean(), "unsafe IC path");
@@ -401,13 +391,14 @@
       // At code generation time, this call has been emitted as static call
       // Call via stub
       assert(info.cached_metadata() != NULL && info.cached_metadata()->is_method(), "sanity check");
-      CompiledStaticCall* csc = compiledStaticCall_at(instruction_address());
       methodHandle method (thread, (Method*)info.cached_metadata());
-      csc->set_to_interpreted(method, info.entry());
+      _call->set_to_interpreted(method, info);
+
       if (TraceICs) {
          ResourceMark rm(thread);
-         tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter: %s",
+         tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to %s: %s",
            p2i(instruction_address()),
+           (info.to_aot() ? "aot" : "interpreter"),
            method->print_value_string());
       }
     } else {
@@ -460,13 +451,16 @@
 }
 
 
-// is_optimized: Compiler has generated an optimized call (i.e., no inline
-// cache) static_bound: The call can be static bound (i.e, no need to use
-// inline cache)
+// is_optimized: Compiler has generated an optimized call (i.e. fixed, no inline cache)
+// static_bound: The call can be static bound. If it isn't also optimized, the property
+// wasn't provable at time of compilation. An optimized call will have any necessary
+// null check, while a static_bound won't. A static_bound (but not optimized) must
+// therefore use the unverified entry point.
 void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
                                            KlassHandle receiver_klass,
                                            bool is_optimized,
                                            bool static_bound,
+                                           bool caller_is_nmethod,
                                            CompiledICInfo& info,
                                            TRAPS) {
   CompiledMethod* method_code = method->code();
@@ -475,51 +469,41 @@
   if (method_code != NULL && method_code->is_in_use()) {
     assert(method_code->is_compiled(), "must be compiled");
     // Call to compiled code
-    if (static_bound || is_optimized) {
+    //
+    // Note: the following problem exists with Compiler1:
+    //   - at compile time we may or may not know if the destination is final
+    //   - if we know that the destination is final (is_optimized), we will emit
+    //     an optimized virtual call (no inline cache), and need a Method* to make
+    //     a call to the interpreter
+    //   - if we don't know if the destination is final, we emit a standard
+    //     virtual call, and use CompiledICHolder to call interpreted code
+    //     (no static call stub has been generated)
+    //   - In the case that we here notice the call is static bound we
+    //     convert the call into what looks to be an optimized virtual call,
+    //     but we must use the unverified entry point (since there will be no
+    //     null check on a call when the target isn't loaded).
+    //     This causes problems when verifying the IC because
+    //     it looks vanilla but is optimized. Code in is_call_to_interpreted
+    //     is aware of this and weakens its asserts.
+    if (is_optimized) {
       entry      = method_code->verified_entry_point();
     } else {
       entry      = method_code->entry_point();
     }
   }
-  if (entry != NULL) {
-    // Call to compiled code
+  bool far_c2a = entry != NULL && caller_is_nmethod && method_code->is_far_code();
+  if (entry != NULL && !far_c2a) {
+    // Call to near compiled code (nmethod or aot).
     info.set_compiled_entry(entry, (static_bound || is_optimized) ? NULL : receiver_klass(), is_optimized);
   } else {
-    // Note: the following problem exists with Compiler1:
-    //   - at compile time we may or may not know if the destination is final
-    //   - if we know that the destination is final, we will emit an optimized
-    //     virtual call (no inline cache), and need a Method* to make a call
-    //     to the interpreter
-    //   - if we do not know if the destination is final, we emit a standard
-    //     virtual call, and use CompiledICHolder to call interpreted code
-    //     (no static call stub has been generated)
-    //     However in that case we will now notice it is static_bound
-    //     and convert the call into what looks to be an optimized
-    //     virtual call. This causes problems in verifying the IC because
-    //     it look vanilla but is optimized. Code in is_call_to_interpreted
-    //     is aware of this and weakens its asserts.
-
-    // static_bound should imply is_optimized -- otherwise we have a
-    // performance bug (statically-bindable method is called via
-    // dynamically-dispatched call note: the reverse implication isn't
-    // necessarily true -- the call may have been optimized based on compiler
-    // analysis (static_bound is only based on "final" etc.)
-#ifdef COMPILER2
-#ifdef TIERED
-#if defined(ASSERT)
-    // can't check the assert because we don't have the CompiledIC with which to
-    // find the address if the call instruction.
-    //
-    // CodeBlob* cb = find_blob_unsafe(instruction_address());
-    // assert(cb->is_compiled_by_c1() || !static_bound || is_optimized, "static_bound should imply is_optimized");
-#endif // ASSERT
-#else
-    assert(!static_bound || is_optimized, "static_bound should imply is_optimized");
-#endif // TIERED
-#endif // COMPILER2
     if (is_optimized) {
-      // Use stub entry
-      info.set_interpreter_entry(method()->get_c2i_entry(), method());
+      if (far_c2a) {
+        // Call to aot code from nmethod.
+        info.set_aot_entry(entry, method());
+      } else {
+        // Use stub entry
+        info.set_interpreter_entry(method()->get_c2i_entry(), method());
+      }
     } else {
       // Use icholder entry
       assert(method_code == NULL || method_code->is_compiled(), "must be compiled");
@@ -536,8 +520,15 @@
   return (cb != NULL && cb->is_adapter_blob());
 }
 
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm) {
+  // This call site might have become stale so inspect it carefully.
+  address dest = cm->call_wrapper_at(call_site->addr())->destination();
+  return is_icholder_entry(dest);
+}
+
 // Release the CompiledICHolder* associated with this call site is there is one.
-void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm) {
+  assert(cm->is_nmethod(), "must be nmethod");
   // This call site might have become stale so inspect it carefully.
   NativeCall* call = nativeCall_at(call_site->addr());
   if (is_icholder_entry(call->destination())) {
@@ -546,12 +537,6 @@
   }
 }
 
-bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
-  // This call site might have become stale so inspect it carefully.
-  NativeCall* call = nativeCall_at(call_site->addr());
-  return is_icholder_entry(call->destination());
-}
-
 // ----------------------------------------------------------------------------
 
 void CompiledStaticCall::set_to_clean() {
@@ -559,33 +544,52 @@
   // Reset call site
   MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
 #ifdef ASSERT
-  CodeBlob* cb = CodeCache::find_blob_unsafe(this);
+  CodeBlob* cb = CodeCache::find_blob_unsafe(instruction_address());
   assert(cb != NULL && cb->is_compiled(), "must be compiled");
 #endif
-  set_destination_mt_safe(SharedRuntime::get_resolve_static_call_stub());
+
+  set_destination_mt_safe(resolve_call_stub());
 
   // Do not reset stub here:  It is too expensive to call find_stub.
   // Instead, rely on caller (nmethod::clear_inline_caches) to clear
   // both the call and its stub.
 }
 
-
 bool CompiledStaticCall::is_clean() const {
-  return destination() == SharedRuntime::get_resolve_static_call_stub();
+  return destination() == resolve_call_stub();
 }
 
 bool CompiledStaticCall::is_call_to_compiled() const {
   return CodeCache::contains(destination());
 }
 
-
-bool CompiledStaticCall::is_call_to_interpreted() const {
+bool CompiledDirectStaticCall::is_call_to_interpreted() const {
   // It is a call to interpreted, if it calls to a stub. Hence, the destination
   // must be in the stub part of the nmethod that contains the call
   CompiledMethod* cm = CodeCache::find_compiled(instruction_address());
   return cm->stub_contains(destination());
 }
 
+bool CompiledDirectStaticCall::is_call_to_far() const {
+  // It is a call to aot method, if it calls to a stub. Hence, the destination
+  // must be in the stub part of the nmethod that contains the call
+  CodeBlob* desc = CodeCache::find_blob(instruction_address());
+  return desc->as_compiled_method()->stub_contains(destination());
+}
+
+void CompiledStaticCall::set_to_compiled(address entry) {
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("%s@" INTPTR_FORMAT ": set_to_compiled " INTPTR_FORMAT,
+        name(),
+        p2i(instruction_address()),
+        p2i(entry));
+  }
+  // Call to compiled code
+  assert(CodeCache::contains(entry), "wrong entry point");
+  set_destination_mt_safe(entry);
+}
+
 void CompiledStaticCall::set(const StaticCallInfo& info) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
@@ -598,26 +602,28 @@
   if (info._to_interpreter) {
     // Call to interpreted code
     set_to_interpreted(info.callee(), info.entry());
+#if INCLUDE_AOT
+  } else if (info._to_aot) {
+    // Call to far code
+    set_to_far(info.callee(), info.entry());
+#endif
   } else {
-    if (TraceICs) {
-      ResourceMark rm;
-      tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_compiled " INTPTR_FORMAT,
-                    p2i(instruction_address()),
-                    p2i(info.entry()));
-    }
-    // Call to compiled code
-    assert (CodeCache::contains(info.entry()), "wrong entry point");
-    set_destination_mt_safe(info.entry());
+    set_to_compiled(info.entry());
   }
 }
 
-
 // Compute settings for a CompiledStaticCall. Since we might have to set
 // the stub when calling to the interpreter, we need to return arguments.
-void CompiledStaticCall::compute_entry(const methodHandle& m, StaticCallInfo& info) {
+void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info) {
   CompiledMethod* m_code = m->code();
   info._callee = m;
   if (m_code != NULL && m_code->is_in_use()) {
+    if (caller_is_nmethod && m_code->is_far_code()) {
+      // Call to far aot code from nmethod.
+      info._to_aot = true;
+    } else {
+      info._to_aot = false;
+    }
     info._to_interpreter = false;
     info._entry  = m_code->verified_entry_point();
   } else {
@@ -629,18 +635,18 @@
   }
 }
 
-address CompiledStaticCall::find_stub() {
+address CompiledDirectStaticCall::find_stub_for(address instruction, bool is_aot) {
   // Find reloc. information containing this call-site
-  RelocIterator iter((nmethod*)NULL, instruction_address());
+  RelocIterator iter((nmethod*)NULL, instruction);
   while (iter.next()) {
-    if (iter.addr() == instruction_address()) {
+    if (iter.addr() == instruction) {
       switch(iter.type()) {
         case relocInfo::static_call_type:
-          return iter.static_call_reloc()->static_stub();
+          return iter.static_call_reloc()->static_stub(is_aot);
         // We check here for opt_virtual_call_type, since we reuse the code
         // from the CompiledIC implementation
         case relocInfo::opt_virtual_call_type:
-          return iter.opt_virtual_call_reloc()->static_stub();
+          return iter.opt_virtual_call_reloc()->static_stub(is_aot);
         case relocInfo::poll_type:
         case relocInfo::poll_return_type: // A safepoint can't overlap a call.
         default:
@@ -651,17 +657,20 @@
   return NULL;
 }
 
+address CompiledDirectStaticCall::find_stub(bool is_aot) {
+  return CompiledDirectStaticCall::find_stub_for(instruction_address(), is_aot);
+}
+
+address CompiledDirectStaticCall::resolve_call_stub() const {
+  return SharedRuntime::get_resolve_static_call_stub();
+}
 
 //-----------------------------------------------------------------------------
 // Non-product mode code
 #ifndef PRODUCT
 
 void CompiledIC::verify() {
-  // make sure code pattern is actually a call imm32 instruction
-  _ic_call->verify();
-  if (os::is_MP()) {
-    _ic_call->verify_alignment();
-  }
+  _call->verify();
   assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted()
           || is_optimized() || is_megamorphic(), "sanity check");
 }
@@ -676,12 +685,14 @@
              p2i(instruction_address()), is_call_to_interpreted() ? "interpreted " : "", p2i(ic_destination()), p2i(is_optimized() ? NULL : cached_value()));
 }
 
-void CompiledStaticCall::print() {
+void CompiledDirectStaticCall::print() {
   tty->print("static call at " INTPTR_FORMAT " -> ", p2i(instruction_address()));
   if (is_clean()) {
     tty->print("clean");
   } else if (is_call_to_compiled()) {
     tty->print("compiled");
+  } else if (is_call_to_far()) {
+    tty->print("far");
   } else if (is_call_to_interpreted()) {
     tty->print("interpreted");
   }
diff --git a/hotspot/src/share/vm/code/compiledIC.hpp b/hotspot/src/share/vm/code/compiledIC.hpp
index e4786c8..15af2b4 100644
--- a/hotspot/src/share/vm/code/compiledIC.hpp
+++ b/hotspot/src/share/vm/code/compiledIC.hpp
@@ -68,6 +68,7 @@
   bool    _is_icholder;          // Is the cached value a CompiledICHolder*
   bool    _is_optimized;       // it is an optimized virtual call (i.e., can be statically bound)
   bool    _to_interpreter;     // Call it to interpreter
+  bool    _to_aot;             // Call it to aot code
   bool    _release_icholder;
  public:
   address entry() const        { return _entry; }
@@ -81,12 +82,14 @@
     return icholder;
   }
   bool    is_optimized() const { return _is_optimized; }
-  bool         to_interpreter() const  { return _to_interpreter; }
+  bool  to_interpreter() const { return _to_interpreter; }
+  bool          to_aot() const { return _to_aot; }
 
   void set_compiled_entry(address entry, Klass* klass, bool is_optimized) {
     _entry      = entry;
     _cached_value = (void*)klass;
     _to_interpreter = false;
+    _to_aot = false;
     _is_icholder = false;
     _is_optimized = is_optimized;
     _release_icholder = false;
@@ -96,6 +99,17 @@
     _entry      = entry;
     _cached_value = (void*)method;
     _to_interpreter = true;
+    _to_aot = false;
+    _is_icholder = false;
+    _is_optimized = true;
+    _release_icholder = false;
+  }
+
+  void set_aot_entry(address entry, Method* method) {
+    _entry      = entry;
+    _cached_value = (void*)method;
+    _to_interpreter = false;
+    _to_aot = true;
     _is_icholder = false;
     _is_optimized = true;
     _release_icholder = false;
@@ -105,13 +119,14 @@
     _entry      = entry;
     _cached_value = (void*)icholder;
     _to_interpreter = true;
+    _to_aot = false;
     _is_icholder = true;
     _is_optimized = false;
     _release_icholder = true;
   }
 
   CompiledICInfo(): _entry(NULL), _cached_value(NULL), _is_icholder(false),
-                    _to_interpreter(false), _is_optimized(false), _release_icholder(false) {
+                    _to_interpreter(false), _to_aot(false), _is_optimized(false), _release_icholder(false) {
   }
   ~CompiledICInfo() {
     // In rare cases the info is computed but not used, so release any
@@ -125,15 +140,36 @@
   }
 };
 
+class NativeCallWrapper: public ResourceObj {
+public:
+  virtual address destination() const = 0;
+  virtual address instruction_address() const = 0;
+  virtual address next_instruction_address() const = 0;
+  virtual address return_address() const = 0;
+  virtual address get_resolve_call_stub(bool is_optimized) const = 0;
+  virtual void set_destination_mt_safe(address dest) = 0;
+  virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info) = 0;
+  virtual void verify() const = 0;
+  virtual void verify_resolve_call(address dest) const = 0;
+
+  virtual bool is_call_to_interpreted(address dest) const = 0;
+  virtual bool is_safe_for_patching() const = 0;
+
+  virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const = 0;
+
+  virtual void *get_data(NativeInstruction* instruction) const = 0;
+  virtual void set_data(NativeInstruction* instruction, intptr_t data) = 0;
+};
+
 class CompiledIC: public ResourceObj {
   friend class InlineCacheBuffer;
   friend class ICStub;
 
-
  private:
-  NativeCall*   _ic_call;       // the call instruction
-  NativeMovConstReg* _value;    // patchable value cell for this IC
+  NativeCallWrapper* _call;
+  NativeInstruction* _value;    // patchable value cell for this IC
   bool          _is_optimized;  // an optimized virtual call (i.e., no compiled IC)
+  CompiledMethod* _method;
 
   CompiledIC(CompiledMethod* cm, NativeCall* ic_call);
   CompiledIC(RelocIterator* iter);
@@ -177,8 +213,8 @@
   // This is used to release CompiledICHolder*s from nmethods that
   // are about to be freed.  The callsite might contain other stale
   // values of other kinds so it must be careful.
-  static void cleanup_call_site(virtual_call_Relocation* call_site);
-  static bool is_icholder_call_site(virtual_call_Relocation* call_site);
+  static void cleanup_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm);
+  static bool is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm);
 
   // Return the cached_metadata/destination associated with this inline cache. If the cache currently points
   // to a transition stub, it will read the values from the transition stub.
@@ -192,6 +228,14 @@
     return (Metadata*) cached_value();
   }
 
+  void* get_data() const {
+    return _call->get_data(_value);
+  }
+
+  void set_data(intptr_t data) {
+    _call->set_data(_value, data);
+  }
+
   address ic_destination() const;
 
   bool is_optimized() const   { return _is_optimized; }
@@ -204,7 +248,7 @@
 
   bool is_icholder_call() const;
 
-  address end_of_call() { return  _ic_call->return_address(); }
+  address end_of_call() { return  _call->return_address(); }
 
   // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledIC_ock
   // so you are guaranteed that no patching takes place. The same goes for verify.
@@ -223,10 +267,11 @@
   bool set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS);
 
   static void compute_monomorphic_entry(const methodHandle& method, KlassHandle receiver_klass,
-                                        bool is_optimized, bool static_bound, CompiledICInfo& info, TRAPS);
+                                        bool is_optimized, bool static_bound, bool caller_is_nmethod,
+                                        CompiledICInfo& info, TRAPS);
 
   // Location
-  address instruction_address() const { return _ic_call->instruction_address(); }
+  address instruction_address() const { return _call->instruction_address(); }
 
   // Misc
   void print()             PRODUCT_RETURN;
@@ -278,42 +323,38 @@
 //  Interpreted code: Calls to stub that set Method* reference
 //
 //
-class CompiledStaticCall;
 
 class StaticCallInfo {
  private:
   address      _entry;          // Entrypoint
   methodHandle _callee;         // Callee (used when calling interpreter)
   bool         _to_interpreter; // call to interpreted method (otherwise compiled)
+  bool         _to_aot;         // call to aot method (otherwise compiled)
 
   friend class CompiledStaticCall;
+  friend class CompiledDirectStaticCall;
+  friend class CompiledPltStaticCall;
  public:
   address      entry() const    { return _entry;  }
   methodHandle callee() const   { return _callee; }
 };
 
-
-class CompiledStaticCall: public NativeCall {
-  friend class CompiledIC;
-
-  // Also used by CompiledIC
-  void set_to_interpreted(methodHandle callee, address entry);
-  bool is_optimized_virtual();
-
+class CompiledStaticCall : public ResourceObj {
  public:
-  friend CompiledStaticCall* compiledStaticCall_before(address return_addr);
-  friend CompiledStaticCall* compiledStaticCall_at(address native_call);
-  friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site);
-
   // Code
   static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = NULL);
   static int to_interp_stub_size();
   static int reloc_to_interp_stub();
+  static void emit_to_aot_stub(CodeBuffer &cbuf, address mark = NULL);
+  static int to_aot_stub_size();
+  static int reloc_to_aot_stub();
 
-  // State
-  bool is_clean() const;
-  bool is_call_to_compiled() const;
-  bool is_call_to_interpreted() const;
+  // Compute entry point given a method
+  static void compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info);
+
+public:
+  // Clean static call (will force resolving on next use)
+  virtual address destination() const = 0;
 
   // Clean static call (will force resolving on next use)
   void set_to_clean();
@@ -323,33 +364,77 @@
   // a OptoRuntime::resolve_xxx.
   void set(const StaticCallInfo& info);
 
-  // Compute entry point given a method
-  static void compute_entry(const methodHandle& m, StaticCallInfo& info);
+  // State
+  bool is_clean() const;
+  bool is_call_to_compiled() const;
+  virtual bool is_call_to_interpreted() const = 0;
+
+  virtual address instruction_address() const = 0;
+protected:
+  virtual address resolve_call_stub() const = 0;
+  virtual void set_destination_mt_safe(address dest) = 0;
+#if INCLUDE_AOT
+  virtual void set_to_far(const methodHandle& callee, address entry) = 0;
+#endif
+  virtual void set_to_interpreted(const methodHandle& callee, address entry) = 0;
+  virtual const char* name() const = 0;
+
+  void set_to_compiled(address entry);
+};
+
+class CompiledDirectStaticCall : public CompiledStaticCall {
+private:
+  friend class CompiledIC;
+  friend class DirectNativeCallWrapper;
+
+  // Also used by CompiledIC
+  void set_to_interpreted(const methodHandle& callee, address entry);
+#if INCLUDE_AOT
+  void set_to_far(const methodHandle& callee, address entry);
+#endif
+  address instruction_address() const { return _call->instruction_address(); }
+  void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
+
+  NativeCall* _call;
+
+  CompiledDirectStaticCall(NativeCall* call) : _call(call) {}
+
+ public:
+  static inline CompiledDirectStaticCall* before(address return_addr) {
+    CompiledDirectStaticCall* st = new CompiledDirectStaticCall(nativeCall_before(return_addr));
+    st->verify();
+    return st;
+  }
+
+  static inline CompiledDirectStaticCall* at(address native_call) {
+    CompiledDirectStaticCall* st = new CompiledDirectStaticCall(nativeCall_at(native_call));
+    st->verify();
+    return st;
+  }
+
+  static inline CompiledDirectStaticCall* at(Relocation* call_site) {
+    return at(call_site->addr());
+  }
+
+  // Delegation
+  address destination() const { return _call->destination(); }
+
+  // State
+  virtual bool is_call_to_interpreted() const;
+  bool is_call_to_far() const;
 
   // Stub support
-  address find_stub();
+  static address find_stub_for(address instruction, bool is_aot);
+  address find_stub(bool is_aot);
   static void set_stub_to_clean(static_stub_Relocation* static_stub);
 
   // Misc.
   void print()  PRODUCT_RETURN;
   void verify() PRODUCT_RETURN;
+
+ protected:
+  virtual address resolve_call_stub() const;
+  virtual const char* name() const { return "CompiledDirectStaticCall"; }
 };
 
-
-inline CompiledStaticCall* compiledStaticCall_before(address return_addr) {
-  CompiledStaticCall* st = (CompiledStaticCall*)nativeCall_before(return_addr);
-  st->verify();
-  return st;
-}
-
-inline CompiledStaticCall* compiledStaticCall_at(address native_call) {
-  CompiledStaticCall* st = (CompiledStaticCall*)native_call;
-  st->verify();
-  return st;
-}
-
-inline CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) {
-  return compiledStaticCall_at(call_site->addr());
-}
-
 #endif // SHARE_VM_CODE_COMPILEDIC_HPP
diff --git a/hotspot/src/share/vm/code/compiledMethod.cpp b/hotspot/src/share/vm/code/compiledMethod.cpp
index c376a1a..30120b2 100644
--- a/hotspot/src/share/vm/code/compiledMethod.cpp
+++ b/hotspot/src/share/vm/code/compiledMethod.cpp
@@ -274,7 +274,7 @@
   RelocIterator iter(this);
   while(iter.next()) {
     if (iter.type() == relocInfo::virtual_call_type) {
-      if (CompiledIC::is_icholder_call_site(iter.virtual_call_reloc())) {
+      if (CompiledIC::is_icholder_call_site(iter.virtual_call_reloc(), this)) {
         CompiledIC *ic = CompiledIC_at(&iter);
         if (TraceCompiledIC) {
           tty->print("noticed icholder " INTPTR_FORMAT " ", p2i(ic->cached_icholder()));
@@ -410,6 +410,7 @@
 BoolObjectClosure* CheckClass::_is_alive = NULL;
 #endif // ASSERT
 
+
 void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) {
   if (ic->is_icholder_call()) {
     // The only exception is compiledICHolder oops which may
diff --git a/hotspot/src/share/vm/code/compiledMethod.hpp b/hotspot/src/share/vm/code/compiledMethod.hpp
index 77c7feb..863e8cf 100644
--- a/hotspot/src/share/vm/code/compiledMethod.hpp
+++ b/hotspot/src/share/vm/code/compiledMethod.hpp
@@ -35,6 +35,7 @@
 class AbstractCompiler;
 class xmlStream;
 class CompiledStaticCall;
+class NativeCallWrapper;
 
 // This class is used internally by nmethods, to cache
 // exception/pc/handler information.
@@ -334,6 +335,14 @@
   // corresponds to the given method as well.
   virtual bool is_dependent_on_method(Method* dependee) = 0;
 
+  virtual NativeCallWrapper* call_wrapper_at(address call) const = 0;
+  virtual NativeCallWrapper* call_wrapper_before(address return_pc) const = 0;
+  virtual address call_instruction_address(address pc) const = 0;
+
+  virtual CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const = 0;
+  virtual CompiledStaticCall* compiledStaticCall_at(address addr) const = 0;
+  virtual CompiledStaticCall* compiledStaticCall_before(address addr) const = 0;
+
   Method* attached_method(address call_pc);
   Method* attached_method_before_pc(address pc);
 
diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp
index a21ff70..7142004 100644
--- a/hotspot/src/share/vm/code/nmethod.cpp
+++ b/hotspot/src/share/vm/code/nmethod.cpp
@@ -400,6 +400,7 @@
   _lock_count                 = 0;
   _stack_traversal_mark       = 0;
   _unload_reported            = false; // jvmti state
+  _is_far_code                = false; // nmethods are located in CodeCache
 
 #ifdef ASSERT
   _oops_are_stale             = false;
@@ -2054,6 +2055,7 @@
 // should pass zombie_ok == true.
 void nmethodLocker::lock_nmethod(CompiledMethod* cm, bool zombie_ok) {
   if (cm == NULL)  return;
+  if (cm->is_aot()) return;  // FIXME: Revisit once _lock_count is added to aot_method
   nmethod* nm = cm->as_nmethod();
   Atomic::inc(&nm->_lock_count);
   assert(zombie_ok || !nm->is_zombie(), "cannot lock a zombie method");
@@ -2061,6 +2063,7 @@
 
 void nmethodLocker::unlock_nmethod(CompiledMethod* cm) {
   if (cm == NULL)  return;
+  if (cm->is_aot()) return;  // FIXME: Revisit once _lock_count is added to aot_method
   nmethod* nm = cm->as_nmethod();
   Atomic::dec(&nm->_lock_count);
   assert(nm->_lock_count >= 0, "unmatched nmethod lock/unlock");
@@ -2170,11 +2173,11 @@
         verify_interrupt_point(iter.addr());
         break;
       case relocInfo::opt_virtual_call_type:
-        stub = iter.opt_virtual_call_reloc()->static_stub();
+        stub = iter.opt_virtual_call_reloc()->static_stub(false);
         verify_interrupt_point(iter.addr());
         break;
       case relocInfo::static_call_type:
-        stub = iter.static_call_reloc()->static_stub();
+        stub = iter.static_call_reloc()->static_stub(false);
         //verify_interrupt_point(iter.addr());
         break;
       case relocInfo::runtime_call_type:
@@ -2724,6 +2727,114 @@
 
 }
 
+class DirectNativeCallWrapper: public NativeCallWrapper {
+private:
+  NativeCall* _call;
+
+public:
+  DirectNativeCallWrapper(NativeCall* call) : _call(call) {}
+
+  virtual address destination() const { return _call->destination(); }
+  virtual address instruction_address() const { return _call->instruction_address(); }
+  virtual address next_instruction_address() const { return _call->next_instruction_address(); }
+  virtual address return_address() const { return _call->return_address(); }
+
+  virtual address get_resolve_call_stub(bool is_optimized) const {
+    if (is_optimized) {
+      return SharedRuntime::get_resolve_opt_virtual_call_stub();
+    }
+    return SharedRuntime::get_resolve_virtual_call_stub();
+  }
+
+  virtual void set_destination_mt_safe(address dest) {
+#if INCLUDE_AOT
+    if (UseAOT) {
+      CodeBlob* callee = CodeCache::find_blob(dest);
+      CompiledMethod* cm = callee->as_compiled_method_or_null();
+      if (cm != NULL && cm->is_far_code()) {
+        // Temporary fix, see JDK-8143106
+        CompiledDirectStaticCall* csc = CompiledDirectStaticCall::at(instruction_address());
+        csc->set_to_far(methodHandle(cm->method()), dest);
+        return;
+      }
+    }
+#endif
+    _call->set_destination_mt_safe(dest);
+  }
+
+  virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info) {
+    CompiledDirectStaticCall* csc = CompiledDirectStaticCall::at(instruction_address());
+#if INCLUDE_AOT
+    if (info.to_aot()) {
+      csc->set_to_far(method, info.entry());
+    } else
+#endif
+    {
+      csc->set_to_interpreted(method, info.entry());
+    }
+  }
+
+  virtual void verify() const {
+    // make sure code pattern is actually a call imm32 instruction
+    _call->verify();
+    if (os::is_MP()) {
+      _call->verify_alignment();
+    }
+  }
+
+  virtual void verify_resolve_call(address dest) const {
+    CodeBlob* db = CodeCache::find_blob_unsafe(dest);
+    assert(!db->is_adapter_blob(), "must use stub!");
+  }
+
+  virtual bool is_call_to_interpreted(address dest) const {
+    CodeBlob* cb = CodeCache::find_blob(_call->instruction_address());
+    return cb->contains(dest);
+  }
+
+  virtual bool is_safe_for_patching() const { return false; }
+
+  virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const {
+    return nativeMovConstReg_at(r->cached_value());
+  }
+
+  virtual void *get_data(NativeInstruction* instruction) const {
+    return (void*)((NativeMovConstReg*) instruction)->data();
+  }
+
+  virtual void set_data(NativeInstruction* instruction, intptr_t data) {
+    ((NativeMovConstReg*) instruction)->set_data(data);
+  }
+};
+
+NativeCallWrapper* nmethod::call_wrapper_at(address call) const {
+  return new DirectNativeCallWrapper((NativeCall*) call);
+}
+
+NativeCallWrapper* nmethod::call_wrapper_before(address return_pc) const {
+  return new DirectNativeCallWrapper(nativeCall_before(return_pc));
+}
+
+address nmethod::call_instruction_address(address pc) const {
+  if (NativeCall::is_call_before(pc)) {
+    NativeCall *ncall = nativeCall_before(pc);
+    return ncall->instruction_address();
+  }
+  return NULL;
+}
+
+CompiledStaticCall* nmethod::compiledStaticCall_at(Relocation* call_site) const {
+  return CompiledDirectStaticCall::at(call_site);
+}
+
+CompiledStaticCall* nmethod::compiledStaticCall_at(address call_site) const {
+  return CompiledDirectStaticCall::at(call_site);
+}
+
+CompiledStaticCall* nmethod::compiledStaticCall_before(address return_addr) const {
+  return CompiledDirectStaticCall::before(return_addr);
+}
+
 #ifndef PRODUCT
 
 void nmethod::print_value_on(outputStream* st) const {
@@ -2743,7 +2854,7 @@
     }
     case relocInfo::static_call_type:
       st->print_cr("Static call at " INTPTR_FORMAT, p2i(iter.reloc()->addr()));
-      compiledStaticCall_at(iter.reloc())->print();
+      CompiledDirectStaticCall::at(iter.reloc())->print();
       break;
     }
   }
diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp
index 2e00f75..e076d67 100644
--- a/hotspot/src/share/vm/code/nmethod.hpp
+++ b/hotspot/src/share/vm/code/nmethod.hpp
@@ -302,13 +302,6 @@
   address entry_point() const                     { return _entry_point;             } // normal entry point
   address verified_entry_point() const            { return _verified_entry_point;    } // if klass is correct
 
-  enum { in_use       = 0,   // executable nmethod
-         not_entrant  = 1,   // marked for deoptimization but activations may still exist,
-                             // will be transformed to zombie when all activations are gone
-         zombie       = 2,   // no activations exist, nmethod is ready for purge
-         unloaded     = 3 }; // there should be no activations, should not be called,
-                             // will be transformed to zombie immediately
-
   // flag accessing and manipulation
   bool  is_in_use() const                         { return _state == in_use; }
   bool  is_alive() const                          { unsigned char s = _state; return s < zombie; }
@@ -583,6 +576,14 @@
   static int state_offset()                       { return offset_of(nmethod, _state); }
 
   virtual void metadata_do(void f(Metadata*));
+
+  NativeCallWrapper* call_wrapper_at(address call) const;
+  NativeCallWrapper* call_wrapper_before(address return_pc) const;
+  address call_instruction_address(address pc) const;
+
+  virtual CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const;
+  virtual CompiledStaticCall* compiledStaticCall_at(address addr) const;
+  virtual CompiledStaticCall* compiledStaticCall_before(address addr) const;
 };
 
 // Locks an nmethod so its code will not get removed and it will not
diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp
index d42646f..d9c095e 100644
--- a/hotspot/src/share/vm/code/relocInfo.cpp
+++ b/hotspot/src/share/vm/code/relocInfo.cpp
@@ -565,14 +565,18 @@
   short* p = (short*) dest->locs_end();
   CodeSection* insts = dest->outer()->insts();
   normalize_address(_static_call, insts);
-  p = pack_1_int_to(p, scaled_offset(_static_call, insts->start()));
+  jint is_aot = _is_aot ? 1 : 0;
+  p = pack_2_ints_to(p, scaled_offset(_static_call, insts->start()), is_aot);
   dest->set_locs_end((relocInfo*) p);
 }
 
 void static_stub_Relocation::unpack_data() {
   address base = binding()->section_start(CodeBuffer::SECT_INSTS);
-  jint offset = unpack_1_int();
+  jint offset;
+  jint is_aot;
+  unpack_2_ints(offset, is_aot);
   _static_call = address_from_scaled_offset(offset, base);
+  _is_aot = (is_aot == 1);
 }
 
 void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) {
@@ -796,14 +800,14 @@
 }
 
 
-address opt_virtual_call_Relocation::static_stub() {
+address opt_virtual_call_Relocation::static_stub(bool is_aot) {
   // search for the static stub who points back to this static call
   address static_call_addr = addr();
   RelocIterator iter(code());
   while (iter.next()) {
     if (iter.type() == relocInfo::static_stub_type) {
       static_stub_Relocation* stub_reloc = iter.static_stub_reloc();
-      if (stub_reloc->static_call() == static_call_addr) {
+      if (stub_reloc->static_call() == static_call_addr && stub_reloc->is_aot() == is_aot) {
         return iter.addr();
       }
     }
@@ -832,19 +836,19 @@
 
 void static_call_Relocation::clear_inline_cache() {
   // Safe call site info
-  CompiledStaticCall* handler = compiledStaticCall_at(this);
+  CompiledStaticCall* handler = this->code()->compiledStaticCall_at(this);
   handler->set_to_clean();
 }
 
 
-address static_call_Relocation::static_stub() {
+address static_call_Relocation::static_stub(bool is_aot) {
   // search for the static stub who points back to this static call
   address static_call_addr = addr();
   RelocIterator iter(code());
   while (iter.next()) {
     if (iter.type() == relocInfo::static_stub_type) {
       static_stub_Relocation* stub_reloc = iter.static_stub_reloc();
-      if (stub_reloc->static_call() == static_call_addr) {
+      if (stub_reloc->static_call() == static_call_addr && stub_reloc->is_aot() == is_aot) {
         return iter.addr();
       }
     }
@@ -875,7 +879,7 @@
 void static_stub_Relocation::clear_inline_cache() {
   // Call stub is only used when calling the interpreted code.
   // It does not really need to be cleared, except that we want to clean out the methodoop.
-  CompiledStaticCall::set_stub_to_clean(this);
+  CompiledDirectStaticCall::set_stub_to_clean(this);
 }
 
 
diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp
index 87fb97f..91eb4bb 100644
--- a/hotspot/src/share/vm/code/relocInfo.hpp
+++ b/hotspot/src/share/vm/code/relocInfo.hpp
@@ -1090,7 +1090,7 @@
   void clear_inline_cache();
 
   // find the matching static_stub
-  address static_stub();
+  address static_stub(bool is_aot);
 };
 
 
@@ -1124,24 +1124,26 @@
   void clear_inline_cache();
 
   // find the matching static_stub
-  address static_stub();
+  address static_stub(bool is_aot);
 };
 
 class static_stub_Relocation : public Relocation {
   relocInfo::relocType type() { return relocInfo::static_stub_type; }
 
  public:
-  static RelocationHolder spec(address static_call) {
+  static RelocationHolder spec(address static_call, bool is_aot = false) {
     RelocationHolder rh = newHolder();
-    new(rh) static_stub_Relocation(static_call);
+    new(rh) static_stub_Relocation(static_call, is_aot);
     return rh;
   }
 
  private:
   address _static_call;  // location of corresponding static_call
+  bool _is_aot;          // trampoline to aot code
 
-  static_stub_Relocation(address static_call) {
+  static_stub_Relocation(address static_call, bool is_aot) {
     _static_call = static_call;
+    _is_aot = is_aot;
   }
 
   friend class RelocIterator;
@@ -1151,6 +1153,7 @@
   void clear_inline_cache();
 
   address static_call() { return _static_call; }
+  bool is_aot() { return _is_aot; }
 
   // data is packed as a scaled offset in "1_int" format:  [c] or [Cc]
   void pack_data_to(CodeSection* dest);
diff --git a/hotspot/src/share/vm/code/relocInfo_ext.cpp b/hotspot/src/share/vm/code/relocInfo_ext.cpp
new file mode 100644
index 0000000..7f91010
--- /dev/null
+++ b/hotspot/src/share/vm/code/relocInfo_ext.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "code/codeCache.hpp"
+#include "code/relocInfo.hpp"
+#include "code/relocInfo_ext.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/universe.hpp"
+#include "runtime/os.hpp"
+#include "utilities/debug.hpp"
+#ifdef COMPILER1
+#include "c1/c1_globals.hpp"
+#endif
+
+address symbolic_Relocation::symbolic_value(symbolic_Relocation::symbolic_reference t) {
+  if (Universe::heap() == NULL) {
+    // the symbolic values are not needed so early
+    // (and most of them lead to errors if asked too early)
+    return NULL;
+  }
+  switch(t) {
+  case symbolic_Relocation::polling_page_reference: {
+    return os::get_polling_page();
+  }
+  case symbolic_Relocation::eden_top_reference: {
+    if (!Universe::heap()->supports_inline_contig_alloc()) {
+      return NULL;
+    }
+    return (address)Universe::heap()->top_addr();
+  }
+  case symbolic_Relocation::heap_end_reference: {
+    if (!Universe::heap()->supports_inline_contig_alloc()) {
+      return NULL;
+    }
+    return (address)Universe::heap()->end_addr();
+  }
+  case symbolic_Relocation::card_table_reference: {
+    BarrierSet* bs = Universe::heap()->barrier_set();
+    CardTableModRefBS* ct = (CardTableModRefBS*)bs;
+    return (address)ct->byte_map_base;
+  }
+  case symbolic_Relocation::mark_bits_reference: {
+    return (address)Universe::verify_mark_bits();
+  }
+  case symbolic_Relocation::mark_mask_reference: {
+    return (address)Universe::verify_mark_mask();
+  }
+  case symbolic_Relocation::oop_bits_reference: {
+    return (address)Universe::verify_oop_bits();
+  }
+  case symbolic_Relocation::oop_mask_reference: {
+    return (address)Universe::verify_oop_mask();
+  }
+  case symbolic_Relocation::debug_string_reference: {
+    return (address)"<Lost debug string>";
+  }
+  default: {
+    // missing declaration
+    ShouldNotReachHere();
+    return NULL;
+  }
+  }
+}
diff --git a/hotspot/src/share/vm/code/relocInfo_ext.hpp b/hotspot/src/share/vm/code/relocInfo_ext.hpp
new file mode 100644
index 0000000..b8d1b10
--- /dev/null
+++ b/hotspot/src/share/vm/code/relocInfo_ext.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CODE_RELOCINFO_EXT_HPP
+#define SHARE_VM_CODE_RELOCINFO_EXT_HPP
+
+// symbolic_Relocation allows to anotate some addresses in the generated code.
+//
+// This class was initially defined using the last unused relocType. The
+// new version tries to limit the impact on open source code changes.
+//
+// Without compiled code support, symbolic_Relocation need not be a real
+// relocation. To avoid using the last unused relocType, the
+// symbolic_Relocation::spec(<any symbolic type>) has been replaced
+// by additional methods using directly the symbolic type.
+//
+// Note: the order of the arguments in some methods had to reversed
+// to avoid confusion between the relocType enum and the
+// symbolic_reference enum.
+class symbolic_Relocation : AllStatic {
+
+ public:
+  enum symbolic_reference {
+    card_table_reference,
+    eden_top_reference,
+    heap_end_reference,
+    polling_page_reference,
+    mark_bits_reference,
+    mark_mask_reference,
+    oop_bits_reference,
+    oop_mask_reference,
+    debug_string_reference,
+    last_symbolic_reference
+  };
+
+  // get the new value for a given symbolic type
+  static address symbolic_value(symbolic_reference t);
+};
+
+#endif // SHARE_VM_CODE_RELOCINFO_EXT_HPP
diff --git a/hotspot/src/share/vm/code/stubs.cpp b/hotspot/src/share/vm/code/stubs.cpp
index 73a3924..37cc57b 100644
--- a/hotspot/src/share/vm/code/stubs.cpp
+++ b/hotspot/src/share/vm/code/stubs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -262,16 +262,3 @@
   }
 }
 
-// Fixup for pregenerated code
-void StubQueue::fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs) {
-  const int extra_bytes = CodeEntryAlignment;
-  _stub_buffer = buffer;
-  _queue_begin = 0;
-  _queue_end = queue_end - buffer;
-  _number_of_stubs = number_of_stubs;
-  int size = buffer_end - buffer;
-  // Note: _buffer_limit must differ from _queue_end in the iteration loops
-  // => add extra space at the end (preserving alignment for asserts) if needed
-  if (buffer_end == queue_end) size += extra_bytes;
-  _buffer_limit = _buffer_size = size;
-}
diff --git a/hotspot/src/share/vm/code/stubs.hpp b/hotspot/src/share/vm/code/stubs.hpp
index 2bb7f3f..b340b4b 100644
--- a/hotspot/src/share/vm/code/stubs.hpp
+++ b/hotspot/src/share/vm/code/stubs.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -217,8 +217,6 @@
   void  verify();                                // verifies the stub queue
   void  print();                                 // prints information about the stub queue
 
-  // Fixup for pregenerated code
-  void fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs);
 };
 
 #endif // SHARE_VM_CODE_STUBS_HPP
diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp
index b5af75d..c5dcd8c 100644
--- a/hotspot/src/share/vm/compiler/compileTask.cpp
+++ b/hotspot/src/share/vm/compiler/compileTask.cpp
@@ -292,8 +292,7 @@
   if (_osr_bci != CompileBroker::standard_entry_bci) {
     log->print(" osr_bci='%d'", _osr_bci);
   }
-  // Always print the level in tiered.
-  if (_comp_level != CompLevel_highest_tier || TieredCompilation) {
+  if (_comp_level != CompLevel_highest_tier) {
     log->print(" level='%d'", _comp_level);
   }
   if (_is_blocking) {
@@ -329,24 +328,6 @@
 
 
 // ------------------------------------------------------------------
-// CompileTask::log_task_dequeued
-void CompileTask::log_task_dequeued(const char* comment) {
-  if (LogCompilation && xtty != NULL) {
-    Thread* thread = Thread::current();
-    ttyLocker ttyl;
-    ResourceMark rm(thread);
-
-    xtty->begin_elem("task_dequeued");
-    log_task(xtty);
-    if (comment != NULL) {
-      xtty->print(" comment='%s'", comment);
-    }
-    xtty->end_elem();
-  }
-}
-
-
-// ------------------------------------------------------------------
 // CompileTask::log_task_start
 void CompileTask::log_task_start(CompileLog* log)   {
   log->begin_head("task");
diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp
index 79a75b5..2a5da50 100644
--- a/hotspot/src/share/vm/compiler/compileTask.hpp
+++ b/hotspot/src/share/vm/compiler/compileTask.hpp
@@ -193,7 +193,6 @@
 
   void         log_task(xmlStream* log);
   void         log_task_queued();
-  void         log_task_dequeued(const char* comment);
   void         log_task_start(CompileLog* log);
   void         log_task_done(CompileLog* log);
 
diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
index 6d8c2c0..9a08a97 100644
--- a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
+++ b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
@@ -47,8 +47,9 @@
 
 // Enumeration to distinguish tiers of compilation
 enum CompLevel {
-  CompLevel_any               = -1,
-  CompLevel_all               = -1,
+  CompLevel_any               = -2,
+  CompLevel_all               = -2,
+  CompLevel_aot               = -1,
   CompLevel_none              = 0,         // Interpreter
   CompLevel_simple            = 1,         // C1
   CompLevel_limited_profile   = 2,         // C1, invocation & backedge counters
diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp
index a4909b5..283fd48 100644
--- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp
+++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp
@@ -64,7 +64,7 @@
     cflags(TraceOptoOutput,         bool, false, TraceOptoOutput) \
     cflags(TraceSpilling,           bool, TraceSpilling, TraceSpilling) \
     cflags(Vectorize,               bool, false, Vectorize) \
-    cflags(VectorizeDebug,          bool, false, VectorizeDebug) \
+    cflags(VectorizeDebug,         uintx, 0, VectorizeDebug) \
     cflags(CloneMapDebug,           bool, false, CloneMapDebug) \
     cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \
     cflags(IGVPrintLevel,           intx, PrintIdealGraphLevel, IGVPrintLevel) \
@@ -140,6 +140,7 @@
   compilerdirectives_c1_flags(set_function_definition)
 
   void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } }
+  void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } }
   void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } }
   void print_double(outputStream* st, ccstr n, double v, bool mod) { if (mod) { st->print("%s:%f ", n, v); } }
   void print_ccstr(outputStream* st, ccstr n, ccstr v, bool mod) { if (mod) { st->print("%s:%s ", n, v); } }
diff --git a/hotspot/src/share/vm/compiler/directivesParser.hpp b/hotspot/src/share/vm/compiler/directivesParser.hpp
index ef0b48b..724ca55 100644
--- a/hotspot/src/share/vm/compiler/directivesParser.hpp
+++ b/hotspot/src/share/vm/compiler/directivesParser.hpp
@@ -31,6 +31,7 @@
 enum FlagType {
   boolFlag,
   intxFlag,
+  uintxFlag,
   doubleFlag,
   ccstrFlag,
   ccstrlistFlag,
@@ -40,6 +41,7 @@
 static const char* flag_type_names[] = {
     "bool",
     "int",
+    "uint",
     "double",
     "string",
     "string list",
diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp
index 4cc15c6..e5f878c 100644
--- a/hotspot/src/share/vm/compiler/disassembler.cpp
+++ b/hotspot/src/share/vm/compiler/disassembler.cpp
@@ -505,7 +505,21 @@
   }
   decode_env env(cb, st);
   env.output()->print_cr("----------------------------------------------------------------------");
-  env.output()->print_cr("%s", cb->name());
+  if (cb->is_aot()) {
+    env.output()->print("A ");
+    if (cb->is_compiled()) {
+      CompiledMethod* cm = (CompiledMethod*)cb;
+      env.output()->print("%d ",cm->compile_id());
+      cm->method()->method_holder()->name()->print_symbol_on(env.output());
+      env.output()->print(".");
+      cm->method()->name()->print_symbol_on(env.output());
+      cm->method()->signature()->print_symbol_on(env.output());
+    } else {
+      env.output()->print_cr("%s", cb->name());
+    }
+  } else {
+    env.output()->print_cr("%s", cb->name());
+  }
   env.output()->print_cr(" at  [" PTR_FORMAT ", " PTR_FORMAT "]  " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*));
   env.decode_instructions(cb->code_begin(), cb->code_end());
 }
diff --git a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp
index ccb513d..4456fe6 100644
--- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp
+++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp
@@ -395,9 +395,13 @@
   // event lock and do the read again in case some other thread had already
   // succeeded and done the resize.
   int cur_collection = GenCollectedHeap::heap()->total_collections();
-  if (_last_LNC_resizing_collection[i] != cur_collection) {
+  // Updated _last_LNC_resizing_collection[i] must not be visible before
+  // _lowest_non_clean and friends are visible. Therefore use acquire/release
+  // to guarantee this on non TSO architecures.
+  if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) {
     MutexLocker x(ParGCRareEvent_lock);
-    if (_last_LNC_resizing_collection[i] != cur_collection) {
+    // This load_acquire is here for clarity only. The MutexLocker already fences.
+    if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) {
       if (_lowest_non_clean[i] == NULL ||
           n_chunks != _lowest_non_clean_chunk_size[i]) {
 
@@ -417,7 +421,8 @@
             _lowest_non_clean[i][j] = NULL;
         }
       }
-      _last_LNC_resizing_collection[i] = cur_collection;
+      // Make sure this gets visible only after _lowest_non_clean* was initialized
+      OrderAccess::release_store(&_last_LNC_resizing_collection[i], cur_collection);
     }
   }
   // In any case, now do the initialization.
diff --git a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp
deleted file mode 100644
index cf1b182..0000000
--- a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/g1/bufferingOopClosure.hpp"
-#include "memory/iterator.hpp"
-#include "utilities/debug.hpp"
-
-/////////////// Unit tests ///////////////
-
-#ifndef PRODUCT
-
-class TestBufferingOopClosure {
-
-  // Helper class to fake a set of oop*s and narrowOop*s.
-  class FakeRoots {
-   public:
-    // Used for sanity checking of the values passed to the do_oops functions in the test.
-    static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1);
-
-    int    _num_narrow;
-    int    _num_full;
-    void** _narrow;
-    void** _full;
-
-    FakeRoots(int num_narrow, int num_full) :
-        _num_narrow(num_narrow),
-        _num_full(num_full),
-        _narrow((void**)::malloc(sizeof(void*) * num_narrow)),
-        _full((void**)::malloc(sizeof(void*) * num_full)) {
-
-      for (int i = 0; i < num_narrow; i++) {
-        _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i);
-      }
-      for (int i = 0; i < num_full; i++) {
-        _full[i] = (void*)(uintptr_t)i;
-      }
-    }
-
-    ~FakeRoots() {
-      ::free(_narrow);
-      ::free(_full);
-    }
-
-    void oops_do_narrow_then_full(OopClosure* cl) {
-      for (int i = 0; i < _num_narrow; i++) {
-        cl->do_oop((narrowOop*)_narrow[i]);
-      }
-      for (int i = 0; i < _num_full; i++) {
-        cl->do_oop((oop*)_full[i]);
-      }
-    }
-
-    void oops_do_full_then_narrow(OopClosure* cl) {
-      for (int i = 0; i < _num_full; i++) {
-        cl->do_oop((oop*)_full[i]);
-      }
-      for (int i = 0; i < _num_narrow; i++) {
-        cl->do_oop((narrowOop*)_narrow[i]);
-      }
-    }
-
-    void oops_do_mixed(OopClosure* cl) {
-      int i;
-      for (i = 0; i < _num_full && i < _num_narrow; i++) {
-        cl->do_oop((oop*)_full[i]);
-        cl->do_oop((narrowOop*)_narrow[i]);
-      }
-      for (int j = i; j < _num_full; j++) {
-        cl->do_oop((oop*)_full[i]);
-      }
-      for (int j = i; j < _num_narrow; j++) {
-        cl->do_oop((narrowOop*)_narrow[i]);
-      }
-    }
-
-    static const int MaxOrder = 2;
-
-    void oops_do(OopClosure* cl, int do_oop_order) {
-      switch(do_oop_order) {
-        case 0:
-          oops_do_narrow_then_full(cl);
-          break;
-        case 1:
-          oops_do_full_then_narrow(cl);
-          break;
-        case 2:
-          oops_do_mixed(cl);
-          break;
-        default:
-          oops_do_narrow_then_full(cl);
-          break;
-      }
-    }
-  };
-
-  class CountOopClosure : public OopClosure {
-    int _narrow_oop_count;
-    int _full_oop_count;
-   public:
-    CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {}
-    void do_oop(narrowOop* p) {
-      assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) != 0,
-          "The narrowOop was unexpectedly not marked with the NarrowOopMarker");
-      _narrow_oop_count++;
-    }
-
-    void do_oop(oop* p){
-      assert((uintptr_t(p) & FakeRoots::NarrowOopMarker) == 0,
-          "The oop was unexpectedly marked with the NarrowOopMarker");
-      _full_oop_count++;
-    }
-
-    int narrow_oop_count() { return _narrow_oop_count; }
-    int full_oop_count()   { return _full_oop_count; }
-    int all_oop_count()    { return _narrow_oop_count + _full_oop_count; }
-  };
-
-  class DoNothingOopClosure : public OopClosure {
-   public:
-    void do_oop(narrowOop* p) {}
-    void do_oop(oop* p)       {}
-  };
-
-  static void testCount(int num_narrow, int num_full, int do_oop_order) {
-    FakeRoots fr(num_narrow, num_full);
-
-    CountOopClosure coc;
-    BufferingOopClosure boc(&coc);
-
-    fr.oops_do(&boc, do_oop_order);
-
-    boc.done();
-
-    #define assert_testCount(got, expected)                                \
-       assert((got) == (expected),                                         \
-              "Expected: %d, got: %d, when running testCount(%d, %d, %d)", \
-              (got), (expected), num_narrow, num_full, do_oop_order)
-
-    assert_testCount(num_narrow, coc.narrow_oop_count());
-    assert_testCount(num_full, coc.full_oop_count());
-    assert_testCount(num_narrow + num_full, coc.all_oop_count());
-  }
-
-  static void testCount() {
-    int buffer_length = BufferingOopClosure::BufferLength;
-
-    for (int order = 0; order < FakeRoots::MaxOrder; order++) {
-      testCount(0,                 0,                 order);
-      testCount(10,                0,                 order);
-      testCount(0,                 10,                order);
-      testCount(10,                10,                order);
-      testCount(buffer_length,     10,                order);
-      testCount(10,                buffer_length,     order);
-      testCount(buffer_length,     buffer_length,     order);
-      testCount(buffer_length + 1, 10,                order);
-      testCount(10,                buffer_length + 1, order);
-      testCount(buffer_length + 1, buffer_length,     order);
-      testCount(buffer_length,     buffer_length + 1, order);
-      testCount(buffer_length + 1, buffer_length + 1, order);
-    }
-  }
-
-  static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) {
-    FakeRoots fr(num_narrow, num_full);
-
-    DoNothingOopClosure cl;
-    BufferingOopClosure boc(&cl);
-
-    fr.oops_do(&boc, 0);
-
-    #define assert_testIsBufferEmptyOrFull(got, expected)                        \
-        assert((got) == (expected),                                              \
-               "Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \
-               (got), (expected), num_narrow, num_full,                          \
-               BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full))
-
-    assert_testIsBufferEmptyOrFull(expect_empty, boc.is_buffer_empty());
-    assert_testIsBufferEmptyOrFull(expect_full, boc.is_buffer_full());
-  }
-
-  static void testIsBufferEmptyOrFull() {
-    int bl = BufferingOopClosure::BufferLength;
-
-    testIsBufferEmptyOrFull(0,       0, true,  false);
-    testIsBufferEmptyOrFull(1,       0, false, false);
-    testIsBufferEmptyOrFull(0,       1, false, false);
-    testIsBufferEmptyOrFull(1,       1, false, false);
-    testIsBufferEmptyOrFull(10,      0, false, false);
-    testIsBufferEmptyOrFull(0,      10, false, false);
-    testIsBufferEmptyOrFull(10,     10, false, false);
-    testIsBufferEmptyOrFull(0,      bl, false, true);
-    testIsBufferEmptyOrFull(bl,      0, false, true);
-    testIsBufferEmptyOrFull(bl/2, bl/2, false, true);
-    testIsBufferEmptyOrFull(bl-1,    1, false, true);
-    testIsBufferEmptyOrFull(1,    bl-1, false, true);
-    // Processed
-    testIsBufferEmptyOrFull(bl+1,    0, false, false);
-    testIsBufferEmptyOrFull(bl*2,    0, false, true);
-  }
-
-  static void testEmptyAfterDone(int num_narrow, int num_full) {
-    FakeRoots fr(num_narrow, num_full);
-
-    DoNothingOopClosure cl;
-    BufferingOopClosure boc(&cl);
-
-    fr.oops_do(&boc, 0);
-
-    // Make sure all get processed.
-    boc.done();
-
-    assert(boc.is_buffer_empty(),
-           "Should be empty after call to done(). testEmptyAfterDone(%d, %d)",
-           num_narrow, num_full);
-  }
-
-  static void testEmptyAfterDone() {
-    int bl = BufferingOopClosure::BufferLength;
-
-    testEmptyAfterDone(0,       0);
-    testEmptyAfterDone(1,       0);
-    testEmptyAfterDone(0,       1);
-    testEmptyAfterDone(1,       1);
-    testEmptyAfterDone(10,      0);
-    testEmptyAfterDone(0,      10);
-    testEmptyAfterDone(10,     10);
-    testEmptyAfterDone(0,      bl);
-    testEmptyAfterDone(bl,      0);
-    testEmptyAfterDone(bl/2, bl/2);
-    testEmptyAfterDone(bl-1,    1);
-    testEmptyAfterDone(1,    bl-1);
-    // Processed
-    testEmptyAfterDone(bl+1,    0);
-    testEmptyAfterDone(bl*2,    0);
-  }
-
-  public:
-  static void test() {
-    testCount();
-    testIsBufferEmptyOrFull();
-    testEmptyAfterDone();
-  }
-};
-
-void TestBufferingOopClosure_test() {
-  TestBufferingOopClosure::test();
-}
-
-#endif
diff --git a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.hpp b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.hpp
index 038aba6..5808168 100644
--- a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.hpp
+++ b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.hpp
@@ -42,7 +42,7 @@
 // buffered entries.
 
 class BufferingOopClosure: public OopClosure {
-  friend class TestBufferingOopClosure;
+  friend class BufferingOopClosureTest;
 protected:
   static const size_t BufferLength = 1024;
 
diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp
index 9c94863..a84a70f 100644
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp
@@ -156,9 +156,7 @@
       jlong mark_start = os::elapsed_counter();
       log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
 
-      int iter = 0;
-      do {
-        iter++;
+      for (uint iter = 1; true; ++iter) {
         if (!cm()->has_aborted()) {
           G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots");
           _cm->mark_from_roots();
@@ -178,11 +176,14 @@
           VM_CGC_Operation op(&final_cl, "Pause Remark");
           VMThread::execute(&op);
         }
-        if (cm()->restart_for_overflow()) {
-          log_debug(gc, marking)("Restarting Concurrent Marking because of Mark Stack Overflow in Remark (Iteration #%d).", iter);
-          log_info(gc, marking)("Concurrent Mark Restart due to overflow");
+
+        if (!cm()->restart_for_overflow() || cm()->has_aborted()) {
+          break;
         }
-      } while (cm()->restart_for_overflow());
+
+        log_info(gc, marking)("Concurrent Mark Restart due to overflow"
+                              " (iteration #%u", iter);
+      }
 
       if (!cm()->has_aborted()) {
         G1ConcPhaseTimer t(_cm, "Concurrent Create Live Data");
diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp
index 3a50ee4..435bd5a 100644
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp
@@ -227,7 +227,7 @@
     while (n <= next_boundary) {
       q = n;
       oop obj = oop(q);
-      if (obj->klass_or_null() == NULL) return q;
+      if (obj->klass_or_null_acquire() == NULL) return q;
       n += block_size(q);
     }
     assert(q <= next_boundary && n > next_boundary, "Consequence of loop");
diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp
index f207f25..9788eed 100644
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp
@@ -136,7 +136,7 @@
   while (n <= addr) {
     q = n;
     oop obj = oop(q);
-    if (obj->klass_or_null() == NULL) {
+    if (obj->klass_or_null_acquire() == NULL) {
       return q;
     }
     n += block_size(q);
@@ -148,7 +148,7 @@
 
 inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWord* q,
                                                                           const void* addr) {
-  if (oop(q)->klass_or_null() == NULL) {
+  if (oop(q)->klass_or_null_acquire() == NULL) {
     return q;
   }
   HeapWord* n = q + block_size(q);
diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
index 1ba5cb7..fce91a8 100644
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
@@ -300,6 +300,8 @@
   // thread to calculate the object size incorrectly.
   Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
 
+  // Next, pad out the unused tail of the last region with filler
+  // objects, for improved usage accounting.
   // How many words we use for filler objects.
   size_t word_fill_size = word_size_sum - word_size;
 
@@ -426,8 +428,7 @@
       log_debug(gc, ergo, heap)("Attempt heap expansion (humongous allocation request failed). Allocation request: " SIZE_FORMAT "B",
                                     word_size * HeapWordSize);
 
-
-      _hrm.expand_at(first, obj_regions);
+      _hrm.expand_at(first, obj_regions, workers());
       g1_policy()->record_new_heap_size(num_regions());
 
 #ifdef ASSERT
@@ -739,7 +740,7 @@
 
     // Perform the actual region allocation, exiting if it fails.
     // Then note how much new space we have allocated.
-    if (!_hrm.allocate_containing_regions(curr_range, &commits)) {
+    if (!_hrm.allocate_containing_regions(curr_range, &commits, workers())) {
       return false;
     }
     increase_used(word_size * HeapWordSize);
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp
index 52a9f48..bf507f2 100644
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp
@@ -2009,10 +2009,10 @@
   { }
 
   void operator()(oop obj) const {
-    guarantee(obj->is_oop(),
+    guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || obj->is_oop(),
               "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
               p2i(obj), _phase, _info);
-    guarantee(!_g1h->obj_in_cs(obj),
+    guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->obj_in_cs(obj),
               "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d",
               p2i(obj), _phase, _info);
   }
@@ -2436,6 +2436,7 @@
     if (elem == NULL) {
       break;
     }
+    assert(G1CMObjArrayProcessor::is_array_slice(elem) || elem->is_oop(), "Element " PTR_FORMAT " must be an array slice or oop", p2i(elem));
     bool success = _task_queue->push(elem);
     // We only call this when the local queue is empty or under a
     // given target limit. So, we do not expect this push to fail.
@@ -2448,7 +2449,9 @@
 }
 
 void G1CMTask::drain_local_queue(bool partially) {
-  if (has_aborted()) return;
+  if (has_aborted()) {
+    return;
+  }
 
   // Decide what the target size is, depending whether we're going to
   // drain it partially (so that other tasks can steal if they run out
@@ -2464,12 +2467,7 @@
     oop obj;
     bool ret = _task_queue->pop_local(obj);
     while (ret) {
-      assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" );
-      assert(!_g1h->is_on_master_free_list(
-                  _g1h->heap_region_containing((HeapWord*) obj)), "invariant");
-
       scan_object(obj);
-
       if (_task_queue->size() <= target_size || has_aborted()) {
         ret = false;
       } else {
@@ -2880,8 +2878,6 @@
     while (!has_aborted()) {
       oop obj;
       if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
-        assert(_nextMarkBitMap->isMarked((HeapWord*) obj),
-               "any stolen object should be marked");
         scan_object(obj);
 
         // And since we're towards the end, let's totally drain the
@@ -3003,6 +2999,7 @@
                    G1CMTaskQueueSet* task_queues)
   : _g1h(G1CollectedHeap::heap()),
     _worker_id(worker_id), _cm(cm),
+    _objArray_processor(this),
     _claimed(false),
     _nextMarkBitMap(NULL), _hash_seed(17),
     _task_queue(task_queue),
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp
index 68cc2b4..277e9fe 100644
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP
 
 #include "classfile/javaClasses.hpp"
+#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp"
 #include "gc/g1/g1RegionToSpaceMapper.hpp"
 #include "gc/g1/heapRegionSet.hpp"
 #include "gc/shared/taskqueue.hpp"
@@ -706,11 +707,13 @@
     words_scanned_period          = 12*1024,
     // The regular clock call is called once the number of visited
     // references reaches this limit
-    refs_reached_period           = 384,
+    refs_reached_period           = 1024,
     // Initial value for the hash seed, used in the work stealing code
     init_hash_seed                = 17
   };
 
+  G1CMObjArrayProcessor       _objArray_processor;
+
   uint                        _worker_id;
   G1CollectedHeap*            _g1h;
   G1ConcurrentMark*           _cm;
@@ -826,8 +829,10 @@
   bool is_below_finger(oop obj, HeapWord* global_finger) const;
 
   template<bool scan> void process_grey_object(oop obj);
-
 public:
+  // Apply the closure on the given area of the objArray. Return the number of words
+  // scanned.
+  inline size_t scan_objArray(objArrayOop obj, MemRegion mr);
   // It resets the task; it should be called right at the beginning of
   // a marking phase.
   void reset(G1CMBitMap* _nextMarkBitMap);
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp
index af42c85..13bd0b5 100644
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp
@@ -27,6 +27,7 @@
 
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1ConcurrentMark.hpp"
+#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
 #include "gc/g1/suspendibleThreadSet.hpp"
 #include "gc/shared/taskqueue.inline.hpp"
 
@@ -117,11 +118,11 @@
 
 inline void G1CMTask::push(oop obj) {
   HeapWord* objAddr = (HeapWord*) obj;
-  assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
-  assert(!_g1h->is_on_master_free_list(
+  assert(G1CMObjArrayProcessor::is_array_slice(obj) || _g1h->is_in_g1_reserved(objAddr), "invariant");
+  assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_on_master_free_list(
               _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
-  assert(!_g1h->is_obj_ill(obj), "invariant");
-  assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
+  assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_obj_ill(obj), "invariant");
+  assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked(objAddr), "invariant");
 
   if (!_task_queue->push(obj)) {
     // The local task queue looks full. We need to push some entries
@@ -169,17 +170,26 @@
 template<bool scan>
 inline void G1CMTask::process_grey_object(oop obj) {
   assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
-  assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
-
-  size_t obj_size = obj->size();
-  _words_scanned += obj_size;
+  assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked((HeapWord*) obj),
+         "Any stolen object should be a slice or marked");
 
   if (scan) {
-    obj->oop_iterate(_cm_oop_closure);
+    if (G1CMObjArrayProcessor::is_array_slice(obj)) {
+      _words_scanned += _objArray_processor.process_slice(obj);
+    } else if (G1CMObjArrayProcessor::should_be_sliced(obj)) {
+      _words_scanned += _objArray_processor.process_obj(obj);
+    } else {
+      _words_scanned += obj->oop_iterate_size(_cm_oop_closure);;
+    }
   }
   check_limits();
 }
 
+inline size_t G1CMTask::scan_objArray(objArrayOop obj, MemRegion mr) {
+  obj->oop_iterate(_cm_oop_closure, mr);
+  return mr.word_size();
+}
+
 inline void G1CMTask::make_reference_grey(oop obj) {
   if (_cm->par_mark(obj)) {
     // No OrderAccess:store_load() is needed. It is implicit in the
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp
new file mode 100644
index 0000000..d74bbd7
--- /dev/null
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1ConcurrentMark.inline.hpp"
+#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
+
+oop G1CMObjArrayProcessor::encode_array_slice(HeapWord* addr) {
+  return oop((void*)((uintptr_t)addr | ArraySliceBit));
+}
+
+HeapWord* G1CMObjArrayProcessor::decode_array_slice(oop value) {
+  assert(is_array_slice(value), "Given value " PTR_FORMAT " is not an array slice", p2i(value));
+  return (HeapWord*)((uintptr_t)(void*)value & ~ArraySliceBit);
+}
+
+void G1CMObjArrayProcessor::push_array_slice(HeapWord* what) {
+  oop obj = encode_array_slice(what);
+  _task->push(obj);
+}
+
+size_t G1CMObjArrayProcessor::process_array_slice(objArrayOop obj, HeapWord* start_from, size_t remaining) {
+  size_t words_to_scan = MIN2(remaining, ObjArrayMarkingStride);
+
+  if (remaining > ObjArrayMarkingStride) {
+    push_array_slice(start_from + ObjArrayMarkingStride);
+  }
+
+  // Then process current area.
+  MemRegion mr(start_from, words_to_scan);
+  return _task->scan_objArray(obj, mr);
+}
+
+size_t G1CMObjArrayProcessor::process_obj(oop obj) {
+  assert(should_be_sliced(obj), "Must be an array object %d and large " SIZE_FORMAT, obj->is_objArray(), (size_t)obj->size());
+
+  return process_array_slice(objArrayOop(obj), (HeapWord*)obj, (size_t)objArrayOop(obj)->size());
+}
+
+size_t G1CMObjArrayProcessor::process_slice(oop obj) {
+  HeapWord* const decoded_address = decode_array_slice(obj);
+
+  // Find the start address of the objArrayOop.
+  // Shortcut the BOT access if the given address is from a humongous object. The BOT
+  // slide is fast enough for "smaller" objects in non-humongous regions, but is slower
+  // than directly using heap region table.
+  G1CollectedHeap* g1h = G1CollectedHeap::heap();
+  HeapRegion* r = g1h->heap_region_containing(decoded_address);
+
+  HeapWord* const start_address = r->is_humongous() ?
+                                  r->humongous_start_region()->bottom() :
+                                  g1h->block_start(decoded_address);
+
+  assert(oop(start_address)->is_objArray(), "Address " PTR_FORMAT " does not refer to an object array ", p2i(start_address));
+  assert(start_address < decoded_address,
+         "Object start address " PTR_FORMAT " must be smaller than decoded address " PTR_FORMAT,
+         p2i(start_address),
+         p2i(decoded_address));
+
+  objArrayOop objArray = objArrayOop(start_address);
+
+  size_t already_scanned = decoded_address - start_address;
+  size_t remaining = objArray->size() - already_scanned;
+
+  return process_array_slice(objArray, decoded_address, remaining);
+}
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp
new file mode 100644
index 0000000..9e16e98
--- /dev/null
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
+#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
+
+#include "oops/oopsHierarchy.hpp"
+#include "memory/allocation.hpp"
+
+class G1CMTask;
+
+// Helper class to mark through large objArrays during marking in an efficient way.
+// Instead of pushing large object arrays, we push continuations onto the
+// mark stack. These continuations are identified by having their LSB set.
+// This allows incremental processing of large objects.
+class G1CMObjArrayProcessor VALUE_OBJ_CLASS_SPEC {
+private:
+  // The bit mask for the continuation indicator of elements on the mark stack.
+  static const size_t ArraySliceBit = 1;
+
+  // Reference to the task for doing the actual work.
+  G1CMTask* _task;
+
+  // Encodes the given address as a continuation "oop".
+  oop encode_array_slice(HeapWord* addr);
+  // Remove the continuation marker from the given oop from the mark stack.
+  HeapWord* decode_array_slice(oop value);
+
+  // Push the continuation at the given address onto the mark stack.
+  void push_array_slice(HeapWord* addr);
+
+  // Process (apply the closure) on the given continuation of the given objArray.
+  size_t process_array_slice(objArrayOop const obj, HeapWord* start_from, size_t remaining);
+public:
+  static bool is_array_slice(void* obj) { return ((uintptr_t)obj & ArraySliceBit) != 0; }
+
+  static bool should_be_sliced(oop obj);
+
+  G1CMObjArrayProcessor(G1CMTask* task) : _task(task) {
+  }
+
+  // Process the given continuation "oop". Returns the number of words scanned.
+  size_t process_slice(oop obj);
+  // Start processing the given objArrayOop by scanning the header and pushing its
+  // continuation.
+  size_t process_obj(oop obj);
+};
+
+#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP */
diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp
new file mode 100644
index 0000000..8c8481b
--- /dev/null
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
+#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
+
+#include "oops/oop.inline.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "runtime/globals.hpp"
+
+inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) {
+  return obj->is_objArray() && ((size_t)((objArrayOop)obj)->size()) >= 2 * ObjArrayMarkingStride;
+}
+
+#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP */
diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp
index 194cd8f..647e22f 100644
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp
@@ -36,7 +36,9 @@
 static const char* Indents[5] = {"", "  ", "    ", "      ", "        "};
 
 G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
-  _max_gc_threads(max_gc_threads)
+  _max_gc_threads(max_gc_threads),
+  _gc_start_counter(0),
+  _gc_pause_time_ms(0.0)
 {
   assert(max_gc_threads > 0, "Must have some GC threads");
 
@@ -67,6 +69,9 @@
   }
   _gc_par_phases[ScanRS] = new WorkerDataArray<double>(max_gc_threads, "Scan RS (ms):");
   _gc_par_phases[CodeRoots] = new WorkerDataArray<double>(max_gc_threads, "Code Root Scanning (ms):");
+#if INCLUDE_AOT
+  _gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>(max_gc_threads, "AOT Root Scanning (ms):");
+#endif
   _gc_par_phases[ObjCopy] = new WorkerDataArray<double>(max_gc_threads, "Object Copy (ms):");
   _gc_par_phases[Termination] = new WorkerDataArray<double>(max_gc_threads, "Termination (ms):");
   _gc_par_phases[GCWorkerTotal] = new WorkerDataArray<double>(max_gc_threads, "GC Worker Total (ms):");
@@ -95,13 +100,40 @@
   _gc_par_phases[NonYoungFreeCSet] = new WorkerDataArray<double>(max_gc_threads, "Non-Young Free Collection Set (ms):");
 
   _gc_par_phases[PreserveCMReferents] = new WorkerDataArray<double>(max_gc_threads, "Parallel Preserve CM Refs (ms):");
+
+  reset();
 }
 
-void G1GCPhaseTimes::note_gc_start() {
-  _gc_start_counter = os::elapsed_counter();
+void G1GCPhaseTimes::reset() {
+  _cur_collection_par_time_ms = 0.0;
+  _cur_collection_code_root_fixup_time_ms = 0.0;
+  _cur_strong_code_root_purge_time_ms = 0.0;
+  _cur_evac_fail_recalc_used = 0.0;
+  _cur_evac_fail_restore_remsets = 0.0;
+  _cur_evac_fail_remove_self_forwards = 0.0;
+  _cur_string_dedup_fixup_time_ms = 0.0;
+  _cur_clear_ct_time_ms = 0.0;
   _cur_expand_heap_time_ms = 0.0;
+  _cur_ref_proc_time_ms = 0.0;
+  _cur_ref_enq_time_ms = 0.0;
+  _cur_collection_start_sec = 0.0;
+  _root_region_scan_wait_time_ms = 0.0;
   _external_accounted_time_ms = 0.0;
   _recorded_clear_claimed_marks_time_ms = 0.0;
+  _recorded_young_cset_choice_time_ms = 0.0;
+  _recorded_non_young_cset_choice_time_ms = 0.0;
+  _recorded_redirty_logged_cards_time_ms = 0.0;
+  _recorded_preserve_cm_referents_time_ms = 0.0;
+  _recorded_merge_pss_time_ms = 0.0;
+  _recorded_total_free_cset_time_ms = 0.0;
+  _recorded_serial_free_cset_time_ms = 0.0;
+  _cur_fast_reclaim_humongous_time_ms = 0.0;
+  _cur_fast_reclaim_humongous_register_time_ms = 0.0;
+  _cur_fast_reclaim_humongous_total = 0;
+  _cur_fast_reclaim_humongous_candidates = 0;
+  _cur_fast_reclaim_humongous_reclaimed = 0;
+  _cur_verify_before_time_ms = 0.0;
+  _cur_verify_after_time_ms = 0.0;
 
   for (int i = 0; i < GCParPhasesSentinel; i++) {
     if (_gc_par_phases[i] != NULL) {
@@ -110,6 +142,11 @@
   }
 }
 
+void G1GCPhaseTimes::note_gc_start() {
+  _gc_start_counter = os::elapsed_counter();
+  reset();
+}
+
 #define ASSERT_PHASE_UNINITIALIZED(phase) \
     assert(_gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started");
 
@@ -184,7 +221,7 @@
 }
 
 template <class T>
-void G1GCPhaseTimes::details(T* phase, const char* indent) {
+void G1GCPhaseTimes::details(T* phase, const char* indent) const {
   Log(gc, phases, task) log;
   if (log.is_level(LogLevel::Trace)) {
     outputStream* trace_out = log.trace_stream();
@@ -193,7 +230,7 @@
   }
 }
 
-void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) {
+void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) const {
   out->print("%s", Indents[indent]);
   phase->print_summary_on(out, print_sum);
   details(phase, Indents[indent]);
@@ -206,7 +243,7 @@
   }
 }
 
-void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) {
+void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) const {
   Log(gc, phases) log;
   if (log.is_level(LogLevel::Debug)) {
     ResourceMark rm;
@@ -214,7 +251,7 @@
   }
 }
 
-void G1GCPhaseTimes::trace_phase(WorkerDataArray<double>* phase, bool print_sum) {
+void G1GCPhaseTimes::trace_phase(WorkerDataArray<double>* phase, bool print_sum) const {
   Log(gc, phases) log;
   if (log.is_level(LogLevel::Trace)) {
     ResourceMark rm;
@@ -222,37 +259,50 @@
   }
 }
 
-#define PHASE_DOUBLE_FORMAT "%s%s: %.1lfms"
-#define PHASE_SIZE_FORMAT "%s%s: " SIZE_FORMAT
+#define TIME_FORMAT "%.1lfms"
 
-#define info_line(str, value) \
-  log_info(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[1], str, value);
+void G1GCPhaseTimes::info_time(const char* name, double value) const {
+  log_info(gc, phases)("%s%s: " TIME_FORMAT, Indents[1], name, value);
+}
 
-#define debug_line(str, value) \
-  log_debug(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[2], str, value);
+void G1GCPhaseTimes::debug_time(const char* name, double value) const {
+  log_debug(gc, phases)("%s%s: " TIME_FORMAT, Indents[2], name, value);
+}
 
-#define trace_line(str, value) \
-  log_trace(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[3], str, value);
+void G1GCPhaseTimes::trace_time(const char* name, double value) const {
+  log_trace(gc, phases)("%s%s: " TIME_FORMAT, Indents[3], name, value);
+}
 
-#define trace_line_sz(str, value) \
-  log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value);
+void G1GCPhaseTimes::trace_count(const char* name, size_t value) const {
+  log_trace(gc, phases)("%s%s: " SIZE_FORMAT, Indents[3], name, value);
+}
 
-#define trace_line_ms(str, value) \
-  log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value);
+double G1GCPhaseTimes::print_pre_evacuate_collection_set() const {
+  const double sum_ms = _root_region_scan_wait_time_ms +
+                        _recorded_young_cset_choice_time_ms +
+                        _recorded_non_young_cset_choice_time_ms +
+                        _cur_fast_reclaim_humongous_register_time_ms;
 
-#define info_line_and_account(str, value) \
-  info_line(str, value);                  \
-  accounted_time_ms += value;
+  info_time("Pre Evacuate Collection Set", sum_ms);
 
-void G1GCPhaseTimes::print() {
-  note_gc_end();
-
-  double accounted_time_ms = _external_accounted_time_ms;
   if (_root_region_scan_wait_time_ms > 0.0) {
-    info_line_and_account("Root Region Scan Waiting", _root_region_scan_wait_time_ms);
+    debug_time("Root Region Scan Waiting", _root_region_scan_wait_time_ms);
+  }
+  debug_time("Choose Collection Set", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
+  if (G1EagerReclaimHumongousObjects) {
+    debug_time("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
+    trace_count("Humongous Total", _cur_fast_reclaim_humongous_total);
+    trace_count("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
   }
 
-  info_line_and_account("Evacuate Collection Set", _cur_collection_par_time_ms);
+  return sum_ms;
+}
+
+double G1GCPhaseTimes::print_evacuate_collection_set() const {
+  const double sum_ms = _cur_collection_par_time_ms;
+
+  info_time("Evacuate Collection Set", sum_ms);
+
   trace_phase(_gc_par_phases[GCWorkerStart], false);
   debug_phase(_gc_par_phases[ExtRootScan]);
   for (int i = ThreadRoots; i <= SATBFiltering; i++) {
@@ -264,63 +314,107 @@
   }
   debug_phase(_gc_par_phases[ScanRS]);
   debug_phase(_gc_par_phases[CodeRoots]);
+#if INCLUDE_AOT
+  debug_phase(_gc_par_phases[AOTCodeRoots]);
+#endif
   debug_phase(_gc_par_phases[ObjCopy]);
   debug_phase(_gc_par_phases[Termination]);
   debug_phase(_gc_par_phases[Other]);
   debug_phase(_gc_par_phases[GCWorkerTotal]);
   trace_phase(_gc_par_phases[GCWorkerEnd], false);
 
-  info_line_and_account("Code Roots", _cur_collection_code_root_fixup_time_ms + _cur_strong_code_root_purge_time_ms);
-  debug_line("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms);
-  debug_line("Code Roots Purge", _cur_strong_code_root_purge_time_ms);
+  return sum_ms;
+}
+
+double G1GCPhaseTimes::print_post_evacuate_collection_set() const {
+  const double evac_fail_handling = _cur_evac_fail_recalc_used +
+                                    _cur_evac_fail_remove_self_forwards +
+                                    _cur_evac_fail_restore_remsets;
+  const double sum_ms = evac_fail_handling +
+                        _cur_collection_code_root_fixup_time_ms +
+                        _recorded_preserve_cm_referents_time_ms +
+                        _cur_ref_proc_time_ms +
+                        _cur_ref_enq_time_ms +
+                        _cur_clear_ct_time_ms +
+                        _recorded_merge_pss_time_ms +
+                        _cur_strong_code_root_purge_time_ms +
+                        _recorded_redirty_logged_cards_time_ms +
+                        _recorded_clear_claimed_marks_time_ms +
+                        _recorded_total_free_cset_time_ms +
+                        _cur_fast_reclaim_humongous_time_ms +
+                        _cur_expand_heap_time_ms +
+                        _cur_string_dedup_fixup_time_ms;
+
+  info_time("Post Evacuate Collection Set", sum_ms);
+
+  debug_time("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms);
+
+  debug_time("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms);
+  trace_phase(_gc_par_phases[PreserveCMReferents]);
+
+  debug_time("Reference Processing", _cur_ref_proc_time_ms);
 
   if (G1StringDedup::is_enabled()) {
-    info_line_and_account("String Dedup Fixup", _cur_string_dedup_fixup_time_ms);
+    debug_time("String Dedup Fixup", _cur_string_dedup_fixup_time_ms);
     debug_phase(_gc_par_phases[StringDedupQueueFixup]);
     debug_phase(_gc_par_phases[StringDedupTableFixup]);
   }
-  info_line_and_account("Clear Card Table", _cur_clear_ct_time_ms);
-  info_line_and_account("Expand Heap After Collection", _cur_expand_heap_time_ms);
 
-  info_line_and_account("Free Collection Set", _recorded_total_free_cset_time_ms);
-  debug_line("Free Collection Set Serial", _recorded_serial_free_cset_time_ms);
-  debug_phase(_gc_par_phases[YoungFreeCSet]);
-  debug_phase(_gc_par_phases[NonYoungFreeCSet]);
+  debug_time("Clear Card Table", _cur_clear_ct_time_ms);
 
-  info_line_and_account("Merge Per-Thread State", _recorded_merge_pss_time_ms);
-
-  info_line("Other", _gc_pause_time_ms - accounted_time_ms);
-  if (_cur_verify_before_time_ms > 0.0) {
-    debug_line("Verify Before", _cur_verify_before_time_ms);
-  }
   if (G1CollectedHeap::heap()->evacuation_failed()) {
-    double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards +
-      _cur_evac_fail_restore_remsets;
-    debug_line("Evacuation Failure", evac_fail_handling);
-    trace_line("Recalculate Used", _cur_evac_fail_recalc_used);
-    trace_line("Remove Self Forwards",_cur_evac_fail_remove_self_forwards);
-    trace_line("Restore RemSet", _cur_evac_fail_restore_remsets);
+    debug_time("Evacuation Failure", evac_fail_handling);
+    trace_time("Recalculate Used", _cur_evac_fail_recalc_used);
+    trace_time("Remove Self Forwards",_cur_evac_fail_remove_self_forwards);
+    trace_time("Restore RemSet", _cur_evac_fail_restore_remsets);
   }
-  debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
-  debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms);
-  trace_phase(_gc_par_phases[PreserveCMReferents]);
-  debug_line("Reference Processing", _cur_ref_proc_time_ms);
-  debug_line("Reference Enqueuing", _cur_ref_enq_time_ms);
-  debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms);
+
+  debug_time("Reference Enqueuing", _cur_ref_enq_time_ms);
+
+  debug_time("Merge Per-Thread State", _recorded_merge_pss_time_ms);
+  debug_time("Code Roots Purge", _cur_strong_code_root_purge_time_ms);
+
+  debug_time("Redirty Cards", _recorded_redirty_logged_cards_time_ms);
   if (_recorded_clear_claimed_marks_time_ms > 0.0) {
-    debug_line("Clear Claimed Marks", _recorded_clear_claimed_marks_time_ms);
+    debug_time("Clear Claimed Marks", _recorded_clear_claimed_marks_time_ms);
   }
 
   trace_phase(_gc_par_phases[RedirtyCards]);
+
+  debug_time("Free Collection Set", _recorded_total_free_cset_time_ms);
+  trace_time("Free Collection Set Serial", _recorded_serial_free_cset_time_ms);
+  trace_phase(_gc_par_phases[YoungFreeCSet]);
+  trace_phase(_gc_par_phases[NonYoungFreeCSet]);
+
   if (G1EagerReclaimHumongousObjects) {
-    debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
-    trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total);
-    trace_line_sz("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
-    debug_line("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
-    trace_line_sz("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
+    debug_time("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
+    trace_count("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
   }
+  debug_time("Expand Heap After Collection", _cur_expand_heap_time_ms);
+
+
+  return sum_ms;
+}
+
+void G1GCPhaseTimes::print_other(double accounted_ms) const {
+  info_time("Other", _gc_pause_time_ms - accounted_ms);
+}
+
+void G1GCPhaseTimes::print() {
+  note_gc_end();
+
+  if (_cur_verify_before_time_ms > 0.0) {
+    debug_time("Verify Before", _cur_verify_before_time_ms);
+  }
+
+  double accounted_ms = 0.0;
+  accounted_ms += print_pre_evacuate_collection_set();
+  accounted_ms += print_evacuate_collection_set();
+  accounted_ms += print_post_evacuate_collection_set();
+  print_other(accounted_ms);
+
   if (_cur_verify_after_time_ms > 0.0) {
-    debug_line("Verify After", _cur_verify_after_time_ms);
+    debug_time("Verify After", _cur_verify_after_time_ms);
   }
 }
 
diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp
index 841756e..5889951 100644
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_GC_G1_G1GCPHASETIMES_HPP
 #define SHARE_VM_GC_G1_G1GCPHASETIMES_HPP
 
+#include "logging/logLevel.hpp"
 #include "memory/allocation.hpp"
 
 class LineBuffer;
@@ -58,6 +59,9 @@
     ScanHCC,
     ScanRS,
     CodeRoots,
+#if INCLUDE_AOT
+    AOTCodeRoots,
+#endif
     ObjCopy,
     Termination,
     Other,
@@ -129,12 +133,24 @@
 
   double worker_time(GCParPhases phase, uint worker);
   void note_gc_end();
+  void reset();
 
   template <class T>
-  void details(T* phase, const char* indent);
-  void log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum);
-  void debug_phase(WorkerDataArray<double>* phase);
-  void trace_phase(WorkerDataArray<double>* phase, bool print_sum = true);
+  void details(T* phase, const char* indent) const;
+
+  void log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) const;
+  void debug_phase(WorkerDataArray<double>* phase) const;
+  void trace_phase(WorkerDataArray<double>* phase, bool print_sum = true) const;
+
+  void info_time(const char* name, double value) const;
+  void debug_time(const char* name, double value) const;
+  void trace_time(const char* name, double value) const;
+  void trace_count(const char* name, size_t value) const;
+
+  double print_pre_evacuate_collection_set() const;
+  double print_evacuate_collection_set() const;
+  double print_post_evacuate_collection_set() const;
+  void print_other(double accounted_ms) const;
 
  public:
   G1GCPhaseTimes(uint max_gc_threads);
diff --git a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp
index 254baea..0a2a462 100644
--- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp
@@ -235,11 +235,12 @@
 public:
   G1PretouchTask(char* start_address, char* end_address, size_t page_size) :
     AbstractGangTask("G1 PreTouch",
-                     Universe::is_fully_initialized() ? GCId::current_raw() :
-                                                        // During VM initialization there is
-                                                        // no GC cycle that this task can be
-                                                        // associated with.
-                                                        GCId::undefined()),
+                     Universe::is_fully_initialized() &&
+                     Thread::current()->is_Named_thread() ? GCId::current_raw() :
+                                                            // During VM initialization there is
+                                                            // no GC cycle that this task can be
+                                                            // associated with.
+                                                            GCId::undefined()),
     _cur_addr(start_address),
     _start_addr(start_address),
     _end_addr(end_address),
@@ -262,15 +263,20 @@
 };
 
 void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) {
-  guarantee(pretouch_gang != NULL, "No pretouch gang specified.");
-
-  size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
-
-  uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
   G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size);
-  log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
-                      cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
-  pretouch_gang->run_task(&cl, num_workers);
+
+  if (pretouch_gang != NULL) {
+    size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
+
+    uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
+    log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
+                        cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
+    pretouch_gang->run_task(&cl, num_workers);
+  } else {
+    log_debug(gc, heap)("Running %s pre-touching " SIZE_FORMAT "B.",
+                        cl.name(), size_in_pages * _page_size);
+    cl.work(0);
+  }
 }
 
 bool G1PageBasedVirtualSpace::contains(const void* p) const {
diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp
index ccb8fbd..11a8806 100644
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp
@@ -575,18 +575,26 @@
   // And find the region containing it.
   HeapRegion* r = _g1->heap_region_containing(start);
 
-  // Why do we have to check here whether a card is on a young region,
-  // given that we dirty young regions and, as a result, the
-  // post-barrier is supposed to filter them out and never to enqueue
-  // them? When we allocate a new region as the "allocation region" we
-  // actually dirty its cards after we release the lock, since card
-  // dirtying while holding the lock was a performance bottleneck. So,
-  // as a result, it is possible for other threads to actually
-  // allocate objects in the region (after the acquire the lock)
-  // before all the cards on the region are dirtied. This is unlikely,
-  // and it doesn't happen often, but it can happen. So, the extra
-  // check below filters out those cards.
-  if (r->is_young()) {
+  // This check is needed for some uncommon cases where we should
+  // ignore the card.
+  //
+  // The region could be young.  Cards for young regions are
+  // distinctly marked (set to g1_young_gen), so the post-barrier will
+  // filter them out.  However, that marking is performed
+  // concurrently.  A write to a young object could occur before the
+  // card has been marked young, slipping past the filter.
+  //
+  // The card could be stale, because the region has been freed since
+  // the card was recorded. In this case the region type could be
+  // anything.  If (still) free or (reallocated) young, just ignore
+  // it.  If (reallocated) old or humongous, the later card trimming
+  // and additional checks in iteration may detect staleness.  At
+  // worst, we end up processing a stale card unnecessarily.
+  //
+  // In the normal (non-stale) case, the synchronization between the
+  // enqueueing of the card and processing it here will have ensured
+  // we see the up-to-date region type here.
+  if (!r->is_old_or_humongous()) {
     return false;
   }
 
@@ -617,26 +625,69 @@
     assert(!check_for_refs_into_cset, "sanity");
     assert(!SafepointSynchronize::is_at_safepoint(), "sanity");
 
+    const jbyte* orig_card_ptr = card_ptr;
     card_ptr = _hot_card_cache->insert(card_ptr);
     if (card_ptr == NULL) {
       // There was no eviction. Nothing to do.
       return false;
-    }
+    } else if (card_ptr != orig_card_ptr) {
+      // Original card was inserted and an old card was evicted.
+      start = _ct_bs->addr_for(card_ptr);
+      r = _g1->heap_region_containing(start);
 
-    start = _ct_bs->addr_for(card_ptr);
-    r = _g1->heap_region_containing(start);
-
-    // Checking whether the region we got back from the cache
-    // is young here is inappropriate. The region could have been
-    // freed, reallocated and tagged as young while in the cache.
-    // Hence we could see its young type change at any time.
+      // Check whether the region formerly in the cache should be
+      // ignored, as discussed earlier for the original card.  The
+      // region could have been freed while in the cache.  The cset is
+      // not relevant here, since we're in concurrent phase.
+      if (!r->is_old_or_humongous()) {
+        return false;
+      }
+    } // Else we still have the original card.
   }
 
+  // Trim the region designated by the card to what's been allocated
+  // in the region.  The card could be stale, or the card could cover
+  // (part of) an object at the end of the allocated space and extend
+  // beyond the end of allocation.
+  HeapWord* scan_limit;
+  if (_g1->is_gc_active()) {
+    // If we're in a STW GC, then a card might be in a GC alloc region
+    // and extend onto a GC LAB, which may not be parsable.  Stop such
+    // at the "scan_top" of the region.
+    scan_limit = r->scan_top();
+  } else {
+    // Non-humongous objects are only allocated in the old-gen during
+    // GC, so if region is old then top is stable.  Humongous object
+    // allocation sets top last; if top has not yet been set, this is
+    // a stale card and we'll end up with an empty intersection.  If
+    // this is not a stale card, the synchronization between the
+    // enqueuing of the card and processing it here will have ensured
+    // we see the up-to-date top here.
+    scan_limit = r->top();
+  }
+  if (scan_limit <= start) {
+    // If the trimmed region is empty, the card must be stale.
+    return false;
+  }
+
+  // Okay to clean and process the card now.  There are still some
+  // stale card cases that may be detected by iteration and dealt with
+  // as iteration failure.
+  *const_cast<volatile jbyte*>(card_ptr) = CardTableModRefBS::clean_card_val();
+
+  // This fence serves two purposes.  First, the card must be cleaned
+  // before processing the contents.  Second, we can't proceed with
+  // processing until after the read of top, for synchronization with
+  // possibly concurrent humongous object allocation.  It's okay that
+  // reading top and reading type were racy wrto each other.  We need
+  // both set, in any order, to proceed.
+  OrderAccess::fence();
+
   // Don't use addr_for(card_ptr + 1) which can ask for
-  // a card beyond the heap.  This is not safe without a perm
-  // gen at the upper end of the heap.
-  HeapWord* end   = start + CardTableModRefBS::card_size_in_words;
-  MemRegion dirtyRegion(start, end);
+  // a card beyond the heap.
+  HeapWord* end = start + CardTableModRefBS::card_size_in_words;
+  MemRegion dirty_region(start, MIN2(scan_limit, end));
+  assert(!dirty_region.is_empty(), "sanity");
 
   G1UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1,
                                                  _g1->g1_rem_set(),
@@ -655,29 +706,15 @@
                                 (OopClosure*)&mux :
                                 (OopClosure*)&update_rs_oop_cl));
 
-  // The region for the current card may be a young region. The
-  // current card may have been a card that was evicted from the
-  // card cache. When the card was inserted into the cache, we had
-  // determined that its region was non-young. While in the cache,
-  // the region may have been freed during a cleanup pause, reallocated
-  // and tagged as young.
-  //
-  // We wish to filter out cards for such a region but the current
-  // thread, if we're running concurrently, may "see" the young type
-  // change at any time (so an earlier "is_young" check may pass or
-  // fail arbitrarily). We tell the iteration code to perform this
-  // filtering when it has been determined that there has been an actual
-  // allocation in this region and making it safe to check the young type.
-
   bool card_processed =
-    r->oops_on_card_seq_iterate_careful(dirtyRegion,
-                                        &filter_then_update_rs_oop_cl,
-                                        card_ptr);
+    r->oops_on_card_seq_iterate_careful(dirty_region,
+                                        &filter_then_update_rs_oop_cl);
 
   // If unable to process the card then we encountered an unparsable
-  // part of the heap (e.g. a partially allocated object).  Redirty
-  // and re-enqueue: if we put off the card until a GC pause, then the
-  // allocation will have completed.
+  // part of the heap (e.g. a partially allocated object) while
+  // processing a stale card.  Despite the card being stale, redirty
+  // and re-enqueue, because we've already cleaned the card.  Without
+  // this we could incorrectly discard a non-stale card.
   if (!card_processed) {
     assert(!_g1->is_gc_active(), "Unparsable heap during GC");
     // The card might have gotten re-dirtied and re-enqueued while we
diff --git a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp
index 8c4642d..292f841 100644
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 
+#include "aot/aotLoader.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
@@ -290,6 +291,15 @@
     }
   }
 
+#if INCLUDE_AOT
+  if (UseAOT) {
+    G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::AOTCodeRoots, worker_i);
+    if (!_process_strong_tasks.is_task_claimed(G1RP_PS_aot_oops_do)) {
+        AOTLoader::oops_do(strong_roots);
+    }
+  }
+#endif
+
   {
     G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i);
     if (!_process_strong_tasks.is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) {
diff --git a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp
index 11cb672..771a29f 100644
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp
@@ -64,6 +64,7 @@
     G1RP_PS_ClassLoaderDataGraph_oops_do,
     G1RP_PS_jvmti_oops_do,
     G1RP_PS_CodeCache_oops_do,
+    G1RP_PS_aot_oops_do,
     G1RP_PS_filter_satb_buffers,
     G1RP_PS_refProcessor_oops_do,
     // Leave this one last.
diff --git a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp
index 006a658..a597ab9 100644
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp
@@ -178,44 +178,37 @@
 }
 
 void
-G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) {
+G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr) {
   volatile jbyte* byte = byte_for(mr.start());
   jbyte* last_byte = byte_for(mr.last());
   Thread* thr = Thread::current();
-  if (whole_heap) {
-    while (byte <= last_byte) {
-      *byte = dirty_card;
-      byte++;
-    }
-  } else {
     // skip all consecutive young cards
-    for (; byte <= last_byte && *byte == g1_young_gen; byte++);
+  for (; byte <= last_byte && *byte == g1_young_gen; byte++);
 
-    if (byte <= last_byte) {
-      OrderAccess::storeload();
-      // Enqueue if necessary.
-      if (thr->is_Java_thread()) {
-        JavaThread* jt = (JavaThread*)thr;
-        for (; byte <= last_byte; byte++) {
-          if (*byte == g1_young_gen) {
-            continue;
-          }
-          if (*byte != dirty_card) {
-            *byte = dirty_card;
-            jt->dirty_card_queue().enqueue(byte);
-          }
+  if (byte <= last_byte) {
+    OrderAccess::storeload();
+    // Enqueue if necessary.
+    if (thr->is_Java_thread()) {
+      JavaThread* jt = (JavaThread*)thr;
+      for (; byte <= last_byte; byte++) {
+        if (*byte == g1_young_gen) {
+          continue;
         }
-      } else {
-        MutexLockerEx x(Shared_DirtyCardQ_lock,
-                        Mutex::_no_safepoint_check_flag);
-        for (; byte <= last_byte; byte++) {
-          if (*byte == g1_young_gen) {
-            continue;
-          }
-          if (*byte != dirty_card) {
-            *byte = dirty_card;
-            _dcqs.shared_dirty_card_queue()->enqueue(byte);
-          }
+        if (*byte != dirty_card) {
+          *byte = dirty_card;
+          jt->dirty_card_queue().enqueue(byte);
+        }
+      }
+    } else {
+      MutexLockerEx x(Shared_DirtyCardQ_lock,
+                      Mutex::_no_safepoint_check_flag);
+      for (; byte <= last_byte; byte++) {
+        if (*byte == g1_young_gen) {
+          continue;
+        }
+        if (*byte != dirty_card) {
+          *byte = dirty_card;
+          _dcqs.shared_dirty_card_queue()->enqueue(byte);
         }
       }
     }
diff --git a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp
index d07d6c5..0cd8970 100644
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp
@@ -152,7 +152,7 @@
 
   // NB: if you do a whole-heap invalidation, the "usual invariant" defined
   // above no longer applies.
-  void invalidate(MemRegion mr, bool whole_heap = false);
+  void invalidate(MemRegion mr);
 
   void write_region_work(MemRegion mr)    { invalidate(mr); }
   void write_ref_array_work(MemRegion mr) { invalidate(mr); }
diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp
index f2df4a3..e62dbab 100644
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp
@@ -352,89 +352,101 @@
   _prev_marked_bytes = marked_bytes;
 }
 
+// Humongous objects are allocated directly in the old-gen.  Need
+// special handling for concurrent processing encountering an
+// in-progress allocation.
+static bool do_oops_on_card_in_humongous(MemRegion mr,
+                                         FilterOutOfRegionClosure* cl,
+                                         HeapRegion* hr,
+                                         G1CollectedHeap* g1h) {
+  assert(hr->is_humongous(), "precondition");
+  HeapRegion* sr = hr->humongous_start_region();
+  oop obj = oop(sr->bottom());
+
+  // If concurrent and klass_or_null is NULL, then space has been
+  // allocated but the object has not yet been published by setting
+  // the klass.  That can only happen if the card is stale.  However,
+  // we've already set the card clean, so we must return failure,
+  // since the allocating thread could have performed a write to the
+  // card that might be missed otherwise.
+  if (!g1h->is_gc_active() && (obj->klass_or_null_acquire() == NULL)) {
+    return false;
+  }
+
+  // We have a well-formed humongous object at the start of sr.
+  // Only filler objects follow a humongous object in the containing
+  // regions, and we can ignore those.  So only process the one
+  // humongous object.
+  if (!g1h->is_obj_dead(obj, sr)) {
+    if (obj->is_objArray() || (sr->bottom() < mr.start())) {
+      // objArrays are always marked precisely, so limit processing
+      // with mr.  Non-objArrays might be precisely marked, and since
+      // it's humongous it's worthwhile avoiding full processing.
+      // However, the card could be stale and only cover filler
+      // objects.  That should be rare, so not worth checking for;
+      // instead let it fall out from the bounded iteration.
+      obj->oop_iterate(cl, mr);
+    } else {
+      // If obj is not an objArray and mr contains the start of the
+      // obj, then this could be an imprecise mark, and we need to
+      // process the entire object.
+      obj->oop_iterate(cl);
+    }
+  }
+  return true;
+}
+
 bool HeapRegion::oops_on_card_seq_iterate_careful(MemRegion mr,
-                                                  FilterOutOfRegionClosure* cl,
-                                                  jbyte* card_ptr) {
-  assert(card_ptr != NULL, "pre-condition");
+                                                  FilterOutOfRegionClosure* cl) {
+  assert(MemRegion(bottom(), end()).contains(mr), "Card region not in heap region");
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
 
-  // If we're within a stop-world GC, then we might look at a card in a
-  // GC alloc region that extends onto a GC LAB, which may not be
-  // parseable.  Stop such at the "scan_top" of the region.
-  if (g1h->is_gc_active()) {
-    mr = mr.intersection(MemRegion(bottom(), scan_top()));
-  } else {
-    mr = mr.intersection(used_region());
+  // Special handling for humongous regions.
+  if (is_humongous()) {
+    return do_oops_on_card_in_humongous(mr, cl, this, g1h);
   }
-  if (mr.is_empty()) {
-    return true;
-  }
-  // Otherwise, find the obj that extends onto mr.start().
+  assert(is_old(), "precondition");
 
-  // The intersection of the incoming mr (for the card) and the
-  // allocated part of the region is non-empty. This implies that
-  // we have actually allocated into this region. The code in
-  // G1CollectedHeap.cpp that allocates a new region sets the
-  // is_young tag on the region before allocating. Thus we
-  // safely know if this region is young.
-  if (is_young()) {
-    return true;
-  }
-
-  // We can only clean the card here, after we make the decision that
-  // the card is not young.
-  *card_ptr = CardTableModRefBS::clean_card_val();
-  // We must complete this write before we do any of the reads below.
-  OrderAccess::storeload();
+  // Because mr has been trimmed to what's been allocated in this
+  // region, the parts of the heap that are examined here are always
+  // parsable; there's no need to use klass_or_null to detect
+  // in-progress allocation.
 
   // Cache the boundaries of the memory region in some const locals
   HeapWord* const start = mr.start();
   HeapWord* const end = mr.end();
 
-  // Update BOT as needed while finding start of (potential) object.
+  // Find the obj that extends onto mr.start().
+  // Update BOT as needed while finding start of (possibly dead)
+  // object containing the start of the region.
   HeapWord* cur = block_start(start);
-  assert(cur <= start, "Postcondition");
 
-  oop obj;
-
-  HeapWord* next = cur;
-  do {
-    cur = next;
-    obj = oop(cur);
-    if (obj->klass_or_null() == NULL) {
-      // Ran into an unparseable point.
-      assert(!g1h->is_gc_active(),
-             "Unparsable heap during GC at " PTR_FORMAT, p2i(cur));
-      return false;
-    }
-    // Otherwise...
-    next = cur + block_size(cur);
-  } while (next <= start);
-
-  // If we finish the above loop...We have a parseable object that
-  // begins on or before the start of the memory region, and ends
-  // inside or spans the entire region.
-  assert(cur <= start, "Loop postcondition");
-  assert(obj->klass_or_null() != NULL, "Loop postcondition");
+#ifdef ASSERT
+  {
+    assert(cur <= start,
+           "cur: " PTR_FORMAT ", start: " PTR_FORMAT, p2i(cur), p2i(start));
+    HeapWord* next = cur + block_size(cur);
+    assert(start < next,
+           "start: " PTR_FORMAT ", next: " PTR_FORMAT, p2i(start), p2i(next));
+  }
+#endif
 
   do {
-    obj = oop(cur);
-    assert((cur + block_size(cur)) > (HeapWord*)obj, "Loop invariant");
-    if (obj->klass_or_null() == NULL) {
-      // Ran into an unparseable point.
-      assert(!g1h->is_gc_active(),
-             "Unparsable heap during GC at " PTR_FORMAT, p2i(cur));
-      return false;
-    }
+    oop obj = oop(cur);
+    assert(obj->is_oop(true), "Not an oop at " PTR_FORMAT, p2i(cur));
+    assert(obj->klass_or_null() != NULL,
+           "Unparsable heap at " PTR_FORMAT, p2i(cur));
 
-    // Advance the current pointer. "obj" still points to the object to iterate.
-    cur = cur + block_size(cur);
-
-    if (!g1h->is_obj_dead(obj)) {
-      // Non-objArrays are sometimes marked imprecise at the object start. We
-      // always need to iterate over them in full.
-      // We only iterate over object arrays in full if they are completely contained
-      // in the memory region.
+    if (g1h->is_obj_dead(obj, this)) {
+      // Carefully step over dead object.
+      cur += block_size(cur);
+    } else {
+      // Step over live object, and process its references.
+      cur += obj->size();
+      // Non-objArrays are usually marked imprecise at the object
+      // start, in which case we need to iterate over them in full.
+      // objArrays are precisely marked, but can still be iterated
+      // over in full if completely covered.
       if (!obj->is_objArray() || (((HeapWord*)obj) >= start && cur <= end)) {
         obj->oop_iterate(cl);
       } else {
@@ -516,7 +528,7 @@
     _hr(hr), _failures(false) {}
 
   void do_code_blob(CodeBlob* cb) {
-    nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null();
+    nmethod* nm = (cb == NULL) ? NULL : cb->as_compiled_method()->as_nmethod_or_null();
     if (nm != NULL) {
       // Verify that the nemthod is live
       if (!nm->is_alive()) {
diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.hpp b/hotspot/src/share/vm/gc/g1/heapRegion.hpp
index 7f4de70..10e45c1 100644
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp
@@ -51,8 +51,9 @@
 // object is larger than a heap region, the following regions will
 // be of type ContinuesHumongous. In this case the top() of the
 // StartHumongous region and all ContinuesHumongous regions except
-// the last will point to their own end. For the last ContinuesHumongous
-// region, top() will equal the object's top.
+// the last will point to their own end. The last ContinuesHumongous
+// region may have top() equal the end of object if there isn't
+// room for filler objects to pad out to the end of the region.
 
 class G1CollectedHeap;
 class HeapRegionRemSet;
@@ -433,6 +434,8 @@
 
   bool is_old() const { return _type.is_old(); }
 
+  bool is_old_or_humongous() const { return _type.is_old_or_humongous(); }
+
   // A pinned region contains objects which are not moved by garbage collections.
   // Humongous regions and archive regions are pinned.
   bool is_pinned() const { return _type.is_pinned(); }
@@ -653,17 +656,18 @@
     }
   }
 
-  // Iterate over the card in the card designated by card_ptr,
-  // applying cl to all references in the region.
-  // mr: the memory region covered by the card.
-  // card_ptr: if we decide that the card is not young and we iterate
-  // over it, we'll clean the card before we start the iteration.
-  // Returns true if card was successfully processed, false if an
-  // unparsable part of the heap was encountered, which should only
-  // happen when invoked concurrently with the mutator.
+  // Iterate over the objects overlapping part of a card, applying cl
+  // to all references in the region.  This is a helper for
+  // G1RemSet::refine_card, and is tightly coupled with it.
+  // mr: the memory region covered by the card, trimmed to the
+  // allocated space for this region.  Must not be empty.
+  // This region must be old or humongous.
+  // Returns true if the designated objects were successfully
+  // processed, false if an unparsable part of the heap was
+  // encountered; that only happens when invoked concurrently with the
+  // mutator.
   bool oops_on_card_seq_iterate_careful(MemRegion mr,
-                                        FilterOutOfRegionClosure* cl,
-                                        jbyte* card_ptr);
+                                        FilterOutOfRegionClosure* cl);
 
   size_t recorded_rs_length() const        { return _recorded_rs_length; }
   double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }
diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp
index 7854671..91e4297 100644
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp
@@ -286,7 +286,7 @@
   while (true) {
     HeapRegion *hr = _regions.get_by_index(curr);
     if (hr == NULL) {
-      uint res = expand_at(curr, 1);
+      uint res = expand_at(curr, 1, NULL);
       if (res == 1) {
         *expanded = true;
         return curr;
@@ -304,7 +304,7 @@
   }
 }
 
-bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count) {
+bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers) {
   size_t commits = 0;
   uint start_index = (uint)_regions.get_index_by_address(range.start());
   uint last_index = (uint)_regions.get_index_by_address(range.last());
@@ -314,7 +314,7 @@
   for (uint curr_index = start_index; curr_index <= last_index; curr_index++) {
     if (!is_available(curr_index)) {
       commits++;
-      expand_at(curr_index, 1);
+      expand_at(curr_index, 1, pretouch_workers);
     }
     HeapRegion* curr_region  = _regions.get_by_index(curr_index);
     if (!curr_region->is_free()) {
diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp
index 4f88638..515553d 100644
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp
@@ -210,12 +210,12 @@
   // HeapRegions, or re-use existing ones. Returns the number of regions the
   // sequence was expanded by. If a HeapRegion allocation fails, the resulting
   // number of regions might be smaller than what's desired.
-  uint expand_by(uint num_regions, WorkGang* pretouch_workers = NULL);
+  uint expand_by(uint num_regions, WorkGang* pretouch_workers);
 
   // Makes sure that the regions from start to start+num_regions-1 are available
   // for allocation. Returns the number of regions that were committed to achieve
   // this.
-  uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers = NULL);
+  uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers);
 
   // Find a contiguous set of empty regions of length num. Returns the start index of
   // that set, or G1_NO_HRM_INDEX.
@@ -234,7 +234,7 @@
   // Allocate the regions that contain the address range specified, committing the
   // regions if necessary. Return false if any of the regions is already committed
   // and not free, and return the number of regions newly committed in commit_count.
-  bool allocate_containing_regions(MemRegion range, size_t* commit_count);
+  bool allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers);
 
   // Apply blk->doHeapRegion() on all committed regions in address order,
   // terminating the iteration early if doHeapRegion() returns true.
diff --git a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp
index b118020..e6566c3 100644
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -120,6 +120,8 @@
   // is_old regions may or may not also be pinned
   bool is_old() const { return (get() & OldMask) != 0; }
 
+  bool is_old_or_humongous() const { return (get() & (OldMask | HumongousMask)) != 0; }
+
   // is_pinned regions may be archive or humongous
   bool is_pinned() const { return (get() & PinnedMask) != 0; }
 
diff --git a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp
index 05efac3..17a1d8d 100644
--- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp
+++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
@@ -127,6 +128,7 @@
     case code_cache:
       // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
       //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
+      AOTLoader::oops_do(&mark_and_push_closure);
       break;
 
     default:
diff --git a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp
index 9fa9730..44495a7 100644
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -515,6 +516,7 @@
     ClassLoaderDataGraph::always_strong_cld_do(follow_cld_closure());
     // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
     //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure()));
+    AOTLoader::oops_do(mark_and_push_closure());
   }
 
   // Flush marking stack.
@@ -611,6 +613,7 @@
 
   CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations);
   CodeCache::blobs_do(&adjust_from_blobs);
+  AOTLoader::oops_do(adjust_pointer_closure());
   StringTable::oops_do(adjust_pointer_closure());
   ref_processor()->weak_oops_do(adjust_pointer_closure());
   PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp
index ccd4648..bddb2e0 100644
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -263,6 +264,13 @@
 }
 
 void
+PSParallelCompact::print_generic_summary_data(ParallelCompactData& summary_data,
+                                              HeapWord* const beg_addr,
+                                              HeapWord* const end_addr) {
+  ::print_generic_summary_data(summary_data,beg_addr, end_addr);
+}
+
+void
 print_generic_summary_data(ParallelCompactData& summary_data,
                            SpaceInfo* space_info)
 {
@@ -377,26 +385,6 @@
     print_generic_summary_data(summary_data, space->bottom(), space->top());
   } while (++id < PSParallelCompact::last_space_id);
 }
-
-void ParallelCompact_test() {
-  if (!UseParallelOldGC) {
-    return;
-  }
-  // Check that print_generic_summary_data() does not print the
-  // end region by placing a bad value in the destination of the
-  // end region.  The end region should not be printed because it
-  // corresponds to the space after the end of the heap.
-  ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
-  ParCompactionManager* const vmthread_cm =
-    ParCompactionManager::manager_array(ParallelGCThreads);
-  HeapWord* begin_heap =
-    (HeapWord*) heap->old_gen()->virtual_space()->low_boundary();
-  HeapWord* end_heap =
-    (HeapWord*) heap->young_gen()->virtual_space()->high_boundary();
-
-  print_generic_summary_data(PSParallelCompact::summary_data(),
-    begin_heap, end_heap);
-}
 #endif  // #ifndef PRODUCT
 
 #ifdef  ASSERT
@@ -2183,6 +2171,7 @@
 
   CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations);
   CodeCache::blobs_do(&adjust_from_blobs);
+  AOTLoader::oops_do(&oop_closure);
   StringTable::oops_do(&oop_closure);
   ref_processor()->weak_oops_do(&oop_closure);
   // Roots were visited so references into the young gen in roots
diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp
index 50b7bfb..4bc9ec8 100644
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp
@@ -965,6 +965,7 @@
   friend class AdjustPointerClosure;
   friend class AdjustKlassClosure;
   friend class RefProcTaskProxy;
+  friend class PSParallelCompactTest;
 
  private:
   static STWGCTimer           _gc_timer;
@@ -1101,6 +1102,13 @@
   // Reset time since last full gc
   static void reset_millis_since_last_gc();
 
+#ifndef PRODUCT
+  // Print generic summary data
+  static void print_generic_summary_data(ParallelCompactData& summary_data,
+                                         HeapWord* const beg_addr,
+                                         HeapWord* const end_addr);
+#endif  // #ifndef PRODUCT
+
  public:
 
   PSParallelCompact();
diff --git a/hotspot/src/share/vm/gc/parallel/psTasks.cpp b/hotspot/src/share/vm/gc/parallel/psTasks.cpp
index 9e95868..36290e7 100644
--- a/hotspot/src/share/vm/gc/parallel/psTasks.cpp
+++ b/hotspot/src/share/vm/gc/parallel/psTasks.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/parallel/cardTableExtension.hpp"
@@ -101,6 +102,7 @@
       {
         MarkingCodeBlobClosure each_scavengable_code_blob(&roots_to_old_closure, CodeBlobToOopClosure::FixRelocations);
         CodeCache::scavenge_root_nmethods_do(&each_scavengable_code_blob);
+        AOTLoader::oops_do(&roots_closure);
       }
       break;
 
diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp
index 9053ded..0d781f3 100644
--- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp
@@ -380,7 +380,7 @@
   }
 }
 
-void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) {
+void CardTableModRefBS::invalidate(MemRegion mr) {
   assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
   assert((HeapWord*)align_size_up  ((uintptr_t)mr.end(),   HeapWordSize) == mr.end(),   "Unaligned end"  );
   for (int i = 0; i < _cur_covered_regions; i++) {
diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp
index 89084ca..d1db7f3 100644
--- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp
@@ -260,7 +260,7 @@
   }
 
   // ModRefBS functions.
-  virtual void invalidate(MemRegion mr, bool whole_heap = false);
+  virtual void invalidate(MemRegion mr);
   void clear(MemRegion mr);
   void dirty(MemRegion mr);
 
diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp
index abf6ee0..8da8110 100644
--- a/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp
@@ -85,7 +85,7 @@
   CardArr* _lowest_non_clean;
   size_t*  _lowest_non_clean_chunk_size;
   uintptr_t* _lowest_non_clean_base_chunk_index;
-  int* _last_LNC_resizing_collection;
+  volatile int* _last_LNC_resizing_collection;
 
   // Initializes "lowest_non_clean" to point to the array for the region
   // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
diff --git a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp
index 2a11147..5139580 100644
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp
@@ -159,8 +159,8 @@
   void clear(MemRegion mr) { _ct_bs->clear(mr); }
   void clear_into_younger(Generation* old_gen);
 
-  void invalidate(MemRegion mr, bool whole_heap = false) {
-    _ct_bs->invalidate(mr, whole_heap);
+  void invalidate(MemRegion mr) {
+    _ct_bs->invalidate(mr);
   }
   void invalidate_or_clear(Generation* old_gen);
 
diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
index 1ad500c..4f2c469 100644
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
@@ -601,34 +601,3 @@
   _reserved.set_start(start);
   _reserved.set_end(end);
 }
-
-/////////////// Unit tests ///////////////
-
-#ifndef PRODUCT
-void CollectedHeap::test_is_in() {
-  CollectedHeap* heap = Universe::heap();
-
-  uintptr_t epsilon    = (uintptr_t) MinObjAlignment;
-  uintptr_t heap_start = (uintptr_t) heap->_reserved.start();
-  uintptr_t heap_end   = (uintptr_t) heap->_reserved.end();
-
-  // Test that NULL is not in the heap.
-  assert(!heap->is_in(NULL), "NULL is unexpectedly in the heap");
-
-  // Test that a pointer to before the heap start is reported as outside the heap.
-  assert(heap_start >= ((uintptr_t)NULL + epsilon), "sanity");
-  void* before_heap = (void*)(heap_start - epsilon);
-  assert(!heap->is_in(before_heap),
-         "before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap));
-
-  // Test that a pointer to after the heap end is reported as outside the heap.
-  assert(heap_end <= ((uintptr_t)-1 - epsilon), "sanity");
-  void* after_heap = (void*)(heap_end + epsilon);
-  assert(!heap->is_in(after_heap),
-         "after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap));
-}
-
-void CollectedHeap_test() {
-  CollectedHeap::test_is_in();
-}
-#endif
diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp
index b13fa97..774f329 100644
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp
@@ -612,9 +612,6 @@
     return false;
   }
 
-  /////////////// Unit tests ///////////////
-
-  NOT_PRODUCT(static void test_is_in();)
 };
 
 // Class to set and reset the GC cause for a CollectedHeap.
diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
index 2b4a720..5248654 100644
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
@@ -73,6 +74,7 @@
   GCH_PS_ClassLoaderDataGraph_oops_do,
   GCH_PS_jvmti_oops_do,
   GCH_PS_CodeCache_oops_do,
+  GCH_PS_aot_oops_do,
   GCH_PS_younger_gens,
   // Leave this one last.
   GCH_PS_NumElements
@@ -608,6 +610,9 @@
   if (!_process_strong_tasks->is_task_claimed(GCH_PS_jvmti_oops_do)) {
     JvmtiExport::oops_do(strong_roots);
   }
+  if (UseAOT && !_process_strong_tasks->is_task_claimed(GCH_PS_aot_oops_do)) {
+    AOTLoader::oops_do(strong_roots);
+  }
 
   if (!_process_strong_tasks->is_task_claimed(GCH_PS_SystemDictionary_oops_do)) {
     SystemDictionary::roots_oops_do(strong_roots, weak_roots);
diff --git a/hotspot/src/share/vm/gc/shared/modRefBarrierSet.hpp b/hotspot/src/share/vm/gc/shared/modRefBarrierSet.hpp
index f82db2c..8b65f61 100644
--- a/hotspot/src/share/vm/gc/shared/modRefBarrierSet.hpp
+++ b/hotspot/src/share/vm/gc/shared/modRefBarrierSet.hpp
@@ -86,10 +86,8 @@
     assert(false, "can't call");
   }
 
-  // Causes all refs in "mr" to be assumed to be modified.  If "whole_heap"
-  // is true, the caller asserts that the entire heap is being invalidated,
-  // which may admit an optimized implementation for some barriers.
-  virtual void invalidate(MemRegion mr, bool whole_heap = false) = 0;
+  // Causes all refs in "mr" to be assumed to be modified.
+  virtual void invalidate(MemRegion mr) = 0;
 
   // The caller guarantees that "mr" contains no references.  (Perhaps it's
   // objects have been moved elsewhere.)
diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp
index 1b05479..c7f3b70 100644
--- a/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp
@@ -124,29 +124,19 @@
   }
 
 #ifndef CC_INTERP
-  if (UseCRC32Intrinsics && m->is_native()) {
+  switch (m->intrinsic_id()) {
     // Use optimized stub code for CRC32 native methods.
-    switch (m->intrinsic_id()) {
-      case vmIntrinsics::_updateCRC32            : return java_util_zip_CRC32_update;
-      case vmIntrinsics::_updateBytesCRC32       : return java_util_zip_CRC32_updateBytes;
-      case vmIntrinsics::_updateByteBufferCRC32  : return java_util_zip_CRC32_updateByteBuffer;
-    }
-  }
-  if (UseCRC32CIntrinsics) {
+    case vmIntrinsics::_updateCRC32            : return java_util_zip_CRC32_update;
+    case vmIntrinsics::_updateBytesCRC32       : return java_util_zip_CRC32_updateBytes;
+    case vmIntrinsics::_updateByteBufferCRC32  : return java_util_zip_CRC32_updateByteBuffer;
     // Use optimized stub code for CRC32C methods.
-    switch (m->intrinsic_id()) {
-      case vmIntrinsics::_updateBytesCRC32C             : return java_util_zip_CRC32C_updateBytes;
-      case vmIntrinsics::_updateDirectByteBufferCRC32C  : return java_util_zip_CRC32C_updateDirectByteBuffer;
-    }
+    case vmIntrinsics::_updateBytesCRC32C             : return java_util_zip_CRC32C_updateBytes;
+    case vmIntrinsics::_updateDirectByteBufferCRC32C  : return java_util_zip_CRC32C_updateDirectByteBuffer;
+    case vmIntrinsics::_intBitsToFloat:      return java_lang_Float_intBitsToFloat;
+    case vmIntrinsics::_floatToRawIntBits:   return java_lang_Float_floatToRawIntBits;
+    case vmIntrinsics::_longBitsToDouble:    return java_lang_Double_longBitsToDouble;
+    case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits;
   }
-
-  switch(m->intrinsic_id()) {
-  case vmIntrinsics::_intBitsToFloat:      return java_lang_Float_intBitsToFloat;
-  case vmIntrinsics::_floatToRawIntBits:   return java_lang_Float_floatToRawIntBits;
-  case vmIntrinsics::_longBitsToDouble:    return java_lang_Double_longBitsToDouble;
-  case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits;
-  }
-
 #endif // CC_INTERP
 
   // Native method?
@@ -189,18 +179,13 @@
     case vmIntrinsics::_dlog10: return java_lang_math_log10;
     case vmIntrinsics::_dpow  : return java_lang_math_pow  ;
     case vmIntrinsics::_dexp  : return java_lang_math_exp  ;
+    case vmIntrinsics::_fmaD  : return java_lang_math_fmaD ;
+    case vmIntrinsics::_fmaF  : return java_lang_math_fmaF ;
 
     case vmIntrinsics::_Reference_get:
                                 return java_lang_ref_reference_get;
   }
 
-  if (UseFMA) {
-    switch (m->intrinsic_id()) {
-      case vmIntrinsics::_fmaD: return java_lang_math_fmaD;
-      case vmIntrinsics::_fmaF: return java_lang_math_fmaF;
-    }
-  }
-
   // Accessor method?
   if (m->is_getter()) {
     // TODO: We should have used ::is_accessor above, but fast accessors in Zero expect only getters.
diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
index b4154a6..573529f 100644
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
@@ -27,7 +27,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "compiler/compileBroker.hpp"
 #include "compiler/disassembler.hpp"
 #include "gc/shared/collectedHeap.hpp"
@@ -1199,7 +1198,6 @@
     ICache::invalidate_range(handler, insts_size);
     _handler = handler + insts_size;
   }
-  CodeCacheExtensions::handle_generated_handler(handler, buffer->name(), _handler);
   return handler;
 }
 
@@ -1208,7 +1206,7 @@
     // use slow signature handler if we can't do better
     int handler_index = -1;
     // check if we can use customized (fast) signature handler
-    if (UseFastSignatureHandlers && CodeCacheExtensions::support_fast_signature_handlers() && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) {
+    if (UseFastSignatureHandlers && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) {
       // use customized signature handler
       MutexLocker mu(SignatureHandlerLibrary_lock);
       // make sure data structure is initialized
@@ -1225,15 +1223,6 @@
           round_to((intptr_t)_buffer, CodeEntryAlignment) - (address)_buffer;
         CodeBuffer buffer((address)(_buffer + align_offset),
                           SignatureHandlerLibrary::buffer_size - align_offset);
-        if (!CodeCacheExtensions::support_dynamic_code()) {
-          // we need a name for the signature (for lookups or saving)
-          const int SYMBOL_SIZE = 50;
-          char *symbolName = NEW_RESOURCE_ARRAY(char, SYMBOL_SIZE);
-          // support for named signatures
-          jio_snprintf(symbolName, SYMBOL_SIZE,
-                       "native_" UINT64_FORMAT, fingerprint);
-          buffer.set_name(symbolName);
-        }
         InterpreterRuntime::SignatureHandlerGenerator(method, &buffer).generate(fingerprint);
         // copy into code heap
         address handler = set_handler(&buffer);
@@ -1251,7 +1240,6 @@
                           fingerprint,
                           buffer.insts_size());
             if (buffer.insts_size() > 0) {
-              // buffer may be empty for pregenerated handlers
               Disassembler::decode(handler, handler + buffer.insts_size());
             }
 #ifndef PRODUCT
diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
index 8b368a1..33e8aec 100644
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "interpreter/interp_masm.hpp"
@@ -52,29 +51,10 @@
     TraceTime timer("Interpreter generation", TRACETIME_LOG(Info, startuptime));
     int code_size = InterpreterCodeSize;
     NOT_PRODUCT(code_size *= 4;)  // debug uses extra interpreter code space
-#if INCLUDE_JVMTI
-    if (CodeCacheExtensions::saving_generated_interpreter()) {
-      // May requires several versions of the codelets.
-      // Final size will automatically be optimized.
-      code_size *= 2;
-    }
-#endif
     _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
                           "Interpreter");
     TemplateInterpreterGenerator g(_code);
   }
-  if (PrintInterpreter) {
-    if (CodeCacheExtensions::saving_generated_interpreter() &&
-        CodeCacheExtensions::use_pregenerated_interpreter()) {
-      ResourceMark rm;
-      tty->print("Printing the newly generated interpreter first");
-      print();
-      tty->print("Printing the pregenerated interpreter next");
-    }
-  }
-
-  // Install the pregenerated interpreter code before printing it
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::TemplateInterpreter);
 
   if (PrintInterpreter) {
     ResourceMark rm;
diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
index 73de575..45ad899 100644
--- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
+++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "interpreter/interp_masm.hpp"
@@ -55,226 +54,213 @@
 };
 
 void TemplateInterpreterGenerator::generate_all() {
-  // Loop, in case we need several variants of the interpreter entries
-  do {
-    if (!CodeCacheExtensions::skip_code_generation()) {
-      // bypass code generation when useless
-      { CodeletMark cm(_masm, "slow signature handler");
-        AbstractInterpreter::_slow_signature_handler = generate_slow_signature_handler();
-      }
+  { CodeletMark cm(_masm, "slow signature handler");
+    AbstractInterpreter::_slow_signature_handler = generate_slow_signature_handler();
+  }
 
-      { CodeletMark cm(_masm, "error exits");
-        _unimplemented_bytecode    = generate_error_exit("unimplemented bytecode");
-        _illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
-      }
+  { CodeletMark cm(_masm, "error exits");
+    _unimplemented_bytecode    = generate_error_exit("unimplemented bytecode");
+    _illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
+  }
 
 #ifndef PRODUCT
-      if (TraceBytecodes) {
-        CodeletMark cm(_masm, "bytecode tracing support");
-        Interpreter::_trace_code =
-          EntryPoint(
-                     generate_trace_code(btos),
-                     generate_trace_code(ztos),
-                     generate_trace_code(ctos),
-                     generate_trace_code(stos),
-                     generate_trace_code(atos),
-                     generate_trace_code(itos),
-                     generate_trace_code(ltos),
-                     generate_trace_code(ftos),
-                     generate_trace_code(dtos),
-                     generate_trace_code(vtos)
-                     );
-      }
+  if (TraceBytecodes) {
+    CodeletMark cm(_masm, "bytecode tracing support");
+    Interpreter::_trace_code =
+      EntryPoint(
+                 generate_trace_code(btos),
+                 generate_trace_code(ztos),
+                 generate_trace_code(ctos),
+                 generate_trace_code(stos),
+                 generate_trace_code(atos),
+                 generate_trace_code(itos),
+                 generate_trace_code(ltos),
+                 generate_trace_code(ftos),
+                 generate_trace_code(dtos),
+                 generate_trace_code(vtos)
+                 );
+  }
 #endif // !PRODUCT
 
-      { CodeletMark cm(_masm, "return entry points");
-        const int index_size = sizeof(u2);
-        for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
-          Interpreter::_return_entry[i] =
-            EntryPoint(
-                       generate_return_entry_for(itos, i, index_size),
-                       generate_return_entry_for(itos, i, index_size),
-                       generate_return_entry_for(itos, i, index_size),
-                       generate_return_entry_for(itos, i, index_size),
-                       generate_return_entry_for(atos, i, index_size),
-                       generate_return_entry_for(itos, i, index_size),
-                       generate_return_entry_for(ltos, i, index_size),
-                       generate_return_entry_for(ftos, i, index_size),
-                       generate_return_entry_for(dtos, i, index_size),
-                       generate_return_entry_for(vtos, i, index_size)
-                       );
-        }
+  { CodeletMark cm(_masm, "return entry points");
+    const int index_size = sizeof(u2);
+    for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
+      Interpreter::_return_entry[i] =
+        EntryPoint(
+                   generate_return_entry_for(itos, i, index_size),
+                   generate_return_entry_for(itos, i, index_size),
+                   generate_return_entry_for(itos, i, index_size),
+                   generate_return_entry_for(itos, i, index_size),
+                   generate_return_entry_for(atos, i, index_size),
+                   generate_return_entry_for(itos, i, index_size),
+                   generate_return_entry_for(ltos, i, index_size),
+                   generate_return_entry_for(ftos, i, index_size),
+                   generate_return_entry_for(dtos, i, index_size),
+                   generate_return_entry_for(vtos, i, index_size)
+                   );
+    }
+  }
+
+  { CodeletMark cm(_masm, "invoke return entry points");
+    // These states are in order specified in TosState, except btos/ztos/ctos/stos are
+    // really the same as itos since there is no top of stack optimization for these types
+    const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl};
+    const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
+    const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
+    const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
+
+    for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
+      TosState state = states[i];
+      assert(state != ilgl, "states array is wrong above");
+      Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
+      Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
+      Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
+    }
+  }
+
+  { CodeletMark cm(_masm, "earlyret entry points");
+    Interpreter::_earlyret_entry =
+      EntryPoint(
+                 generate_earlyret_entry_for(btos),
+                 generate_earlyret_entry_for(ztos),
+                 generate_earlyret_entry_for(ctos),
+                 generate_earlyret_entry_for(stos),
+                 generate_earlyret_entry_for(atos),
+                 generate_earlyret_entry_for(itos),
+                 generate_earlyret_entry_for(ltos),
+                 generate_earlyret_entry_for(ftos),
+                 generate_earlyret_entry_for(dtos),
+                 generate_earlyret_entry_for(vtos)
+                 );
+  }
+
+  { CodeletMark cm(_masm, "deoptimization entry points");
+    for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) {
+      Interpreter::_deopt_entry[i] =
+        EntryPoint(
+                   generate_deopt_entry_for(itos, i),
+                   generate_deopt_entry_for(itos, i),
+                   generate_deopt_entry_for(itos, i),
+                   generate_deopt_entry_for(itos, i),
+                   generate_deopt_entry_for(atos, i),
+                   generate_deopt_entry_for(itos, i),
+                   generate_deopt_entry_for(ltos, i),
+                   generate_deopt_entry_for(ftos, i),
+                   generate_deopt_entry_for(dtos, i),
+                   generate_deopt_entry_for(vtos, i)
+                   );
+    }
+  }
+
+  { CodeletMark cm(_masm, "result handlers for native calls");
+    // The various result converter stublets.
+    int is_generated[Interpreter::number_of_result_handlers];
+    memset(is_generated, 0, sizeof(is_generated));
+
+    for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
+      BasicType type = types[i];
+      if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
+        Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
       }
+    }
+  }
 
-      { CodeletMark cm(_masm, "invoke return entry points");
-        // These states are in order specified in TosState, except btos/ztos/ctos/stos are
-        // really the same as itos since there is no top of stack optimization for these types
-        const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl};
-        const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
-        const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
-        const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
+  { CodeletMark cm(_masm, "continuation entry points");
+    Interpreter::_continuation_entry =
+      EntryPoint(
+                 generate_continuation_for(btos),
+                 generate_continuation_for(ztos),
+                 generate_continuation_for(ctos),
+                 generate_continuation_for(stos),
+                 generate_continuation_for(atos),
+                 generate_continuation_for(itos),
+                 generate_continuation_for(ltos),
+                 generate_continuation_for(ftos),
+                 generate_continuation_for(dtos),
+                 generate_continuation_for(vtos)
+                 );
+  }
 
-        for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
-          TosState state = states[i];
-          assert(state != ilgl, "states array is wrong above");
-          Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
-          Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
-          Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
-        }
-      }
+  { CodeletMark cm(_masm, "safepoint entry points");
+    Interpreter::_safept_entry =
+      EntryPoint(
+                 generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(ztos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
+                 );
+  }
 
-      { CodeletMark cm(_masm, "earlyret entry points");
-        Interpreter::_earlyret_entry =
-          EntryPoint(
-                     generate_earlyret_entry_for(btos),
-                     generate_earlyret_entry_for(ztos),
-                     generate_earlyret_entry_for(ctos),
-                     generate_earlyret_entry_for(stos),
-                     generate_earlyret_entry_for(atos),
-                     generate_earlyret_entry_for(itos),
-                     generate_earlyret_entry_for(ltos),
-                     generate_earlyret_entry_for(ftos),
-                     generate_earlyret_entry_for(dtos),
-                     generate_earlyret_entry_for(vtos)
-                     );
-      }
+  { CodeletMark cm(_masm, "exception handling");
+    // (Note: this is not safepoint safe because thread may return to compiled code)
+    generate_throw_exception();
+  }
 
-      { CodeletMark cm(_masm, "deoptimization entry points");
-        for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) {
-          Interpreter::_deopt_entry[i] =
-            EntryPoint(
-                       generate_deopt_entry_for(itos, i),
-                       generate_deopt_entry_for(itos, i),
-                       generate_deopt_entry_for(itos, i),
-                       generate_deopt_entry_for(itos, i),
-                       generate_deopt_entry_for(atos, i),
-                       generate_deopt_entry_for(itos, i),
-                       generate_deopt_entry_for(ltos, i),
-                       generate_deopt_entry_for(ftos, i),
-                       generate_deopt_entry_for(dtos, i),
-                       generate_deopt_entry_for(vtos, i)
-                       );
-        }
-      }
-
-      { CodeletMark cm(_masm, "result handlers for native calls");
-        // The various result converter stublets.
-        int is_generated[Interpreter::number_of_result_handlers];
-        memset(is_generated, 0, sizeof(is_generated));
-
-        for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
-          BasicType type = types[i];
-          if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
-            Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
-          }
-        }
-      }
-
-      { CodeletMark cm(_masm, "continuation entry points");
-        Interpreter::_continuation_entry =
-          EntryPoint(
-                     generate_continuation_for(btos),
-                     generate_continuation_for(ztos),
-                     generate_continuation_for(ctos),
-                     generate_continuation_for(stos),
-                     generate_continuation_for(atos),
-                     generate_continuation_for(itos),
-                     generate_continuation_for(ltos),
-                     generate_continuation_for(ftos),
-                     generate_continuation_for(dtos),
-                     generate_continuation_for(vtos)
-                     );
-      }
-
-      { CodeletMark cm(_masm, "safepoint entry points");
-        Interpreter::_safept_entry =
-          EntryPoint(
-                     generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(ztos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
-                     generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
-                     );
-      }
-
-      { CodeletMark cm(_masm, "exception handling");
-        // (Note: this is not safepoint safe because thread may return to compiled code)
-        generate_throw_exception();
-      }
-
-      { CodeletMark cm(_masm, "throw exception entrypoints");
-        Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException");
-        Interpreter::_throw_ArrayStoreException_entry            = generate_klass_exception_handler("java/lang/ArrayStoreException"                 );
-        Interpreter::_throw_ArithmeticException_entry            = generate_exception_handler("java/lang/ArithmeticException"           , "/ by zero");
-        Interpreter::_throw_ClassCastException_entry             = generate_ClassCastException_handler();
-        Interpreter::_throw_NullPointerException_entry           = generate_exception_handler("java/lang/NullPointerException"          , NULL       );
-        Interpreter::_throw_StackOverflowError_entry             = generate_StackOverflowError_handler();
-      }
+  { CodeletMark cm(_masm, "throw exception entrypoints");
+    Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException");
+    Interpreter::_throw_ArrayStoreException_entry            = generate_klass_exception_handler("java/lang/ArrayStoreException"                 );
+    Interpreter::_throw_ArithmeticException_entry            = generate_exception_handler("java/lang/ArithmeticException"           , "/ by zero");
+    Interpreter::_throw_ClassCastException_entry             = generate_ClassCastException_handler();
+    Interpreter::_throw_NullPointerException_entry           = generate_exception_handler("java/lang/NullPointerException"          , NULL       );
+    Interpreter::_throw_StackOverflowError_entry             = generate_StackOverflowError_handler();
+  }
 
 
 
 #define method_entry(kind)                                              \
-      { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
-        Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
-        Interpreter::update_cds_entry_table(Interpreter::kind); \
-      }
+  { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
+    Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
+    Interpreter::update_cds_entry_table(Interpreter::kind); \
+  }
 
-      // all non-native method kinds
-      method_entry(zerolocals)
-      method_entry(zerolocals_synchronized)
-      method_entry(empty)
-      method_entry(accessor)
-      method_entry(abstract)
-      method_entry(java_lang_math_sin  )
-      method_entry(java_lang_math_cos  )
-      method_entry(java_lang_math_tan  )
-      method_entry(java_lang_math_abs  )
-      method_entry(java_lang_math_sqrt )
-      method_entry(java_lang_math_log  )
-      method_entry(java_lang_math_log10)
-      method_entry(java_lang_math_exp  )
-      method_entry(java_lang_math_pow  )
-      if (UseFMA) {
-        method_entry(java_lang_math_fmaF)
-        method_entry(java_lang_math_fmaD)
-      }
-      method_entry(java_lang_ref_reference_get)
+  // all non-native method kinds
+  method_entry(zerolocals)
+  method_entry(zerolocals_synchronized)
+  method_entry(empty)
+  method_entry(accessor)
+  method_entry(abstract)
+  method_entry(java_lang_math_sin  )
+  method_entry(java_lang_math_cos  )
+  method_entry(java_lang_math_tan  )
+  method_entry(java_lang_math_abs  )
+  method_entry(java_lang_math_sqrt )
+  method_entry(java_lang_math_log  )
+  method_entry(java_lang_math_log10)
+  method_entry(java_lang_math_exp  )
+  method_entry(java_lang_math_pow  )
+  method_entry(java_lang_math_fmaF )
+  method_entry(java_lang_math_fmaD )
+  method_entry(java_lang_ref_reference_get)
 
-      AbstractInterpreter::initialize_method_handle_entries();
+  AbstractInterpreter::initialize_method_handle_entries();
 
-      // all native method kinds (must be one contiguous block)
-      Interpreter::_native_entry_begin = Interpreter::code()->code_end();
-      method_entry(native)
-      method_entry(native_synchronized)
-      Interpreter::_native_entry_end = Interpreter::code()->code_end();
+  // all native method kinds (must be one contiguous block)
+  Interpreter::_native_entry_begin = Interpreter::code()->code_end();
+  method_entry(native)
+  method_entry(native_synchronized)
+  Interpreter::_native_entry_end = Interpreter::code()->code_end();
 
-      if (UseCRC32Intrinsics) {
-        method_entry(java_util_zip_CRC32_update)
-        method_entry(java_util_zip_CRC32_updateBytes)
-        method_entry(java_util_zip_CRC32_updateByteBuffer)
-      }
+  method_entry(java_util_zip_CRC32_update)
+  method_entry(java_util_zip_CRC32_updateBytes)
+  method_entry(java_util_zip_CRC32_updateByteBuffer)
+  method_entry(java_util_zip_CRC32C_updateBytes)
+  method_entry(java_util_zip_CRC32C_updateDirectByteBuffer)
 
-      if (UseCRC32CIntrinsics) {
-        method_entry(java_util_zip_CRC32C_updateBytes)
-        method_entry(java_util_zip_CRC32C_updateDirectByteBuffer)
-      }
-
-      method_entry(java_lang_Float_intBitsToFloat);
-      method_entry(java_lang_Float_floatToRawIntBits);
-      method_entry(java_lang_Double_longBitsToDouble);
-      method_entry(java_lang_Double_doubleToRawLongBits);
+  method_entry(java_lang_Float_intBitsToFloat);
+  method_entry(java_lang_Float_floatToRawIntBits);
+  method_entry(java_lang_Double_longBitsToDouble);
+  method_entry(java_lang_Double_doubleToRawLongBits);
 
 #undef method_entry
 
-      // Bytecodes
-      set_entry_points_for_all_bytes();
-    }
-  } while (CodeCacheExtensions::needs_other_interpreter_variant());
+  // Bytecodes
+  set_entry_points_for_all_bytes();
 
   // installation of code in other places in the runtime
   // (ExcutableCodeManager calls not needed to copy the entries)
@@ -321,9 +307,6 @@
 
 
 void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
-  if (CodeCacheExtensions::skip_template_interpreter_entries(code)) {
-    return;
-  }
   CodeletMark cm(_masm, Bytecodes::name(code), code);
   // initialize entry points
   assert(_unimplemented_bytecode    != NULL, "should have been generated before");
@@ -354,7 +337,6 @@
   EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, vep);
   Interpreter::_normal_table.set_entry(code, entry);
   Interpreter::_wentry_point[code] = wep;
-  CodeCacheExtensions::completed_template_interpreter_entries(_masm, code);
 }
 
 
@@ -451,7 +433,7 @@
   case Interpreter::java_lang_math_pow     : // fall thru
   case Interpreter::java_lang_math_exp     : // fall thru
   case Interpreter::java_lang_math_fmaD    : // fall thru
-  case Interpreter::java_lang_math_fmaF     : entry_point = generate_math_entry(kind);      break;
+  case Interpreter::java_lang_math_fmaF    : entry_point = generate_math_entry(kind);      break;
   case Interpreter::java_lang_ref_reference_get
                                            : entry_point = generate_Reference_get_entry(); break;
   case Interpreter::java_util_zip_CRC32_update
diff --git a/hotspot/src/share/vm/jvmci/compilerRuntime.cpp b/hotspot/src/share/vm/jvmci/compilerRuntime.cpp
new file mode 100644
index 0000000..80cf344
--- /dev/null
+++ b/hotspot/src/share/vm/jvmci/compilerRuntime.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "jvmci/compilerRuntime.hpp"
+#include "runtime/compilationPolicy.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/interfaceSupport.hpp"
+
+// Resolve and allocate String
+JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_string_by_symbol(JavaThread *thread, void* string_result, const char* name))
+  JRT_BLOCK
+    oop str = *(oop*)string_result; // Is it resolved already?
+    if (str == NULL) { // Do resolution
+      // First 2 bytes of name contains length (number of bytes).
+      int len = build_u2_from((address)name);
+      name += 2;
+      TempNewSymbol sym = SymbolTable::new_symbol(name, len, CHECK);
+      str = StringTable::intern(sym, CHECK);
+      assert(java_lang_String::is_instance(str), "must be string");
+      *(oop*)string_result = str; // Store result
+    }
+    assert(str != NULL, "Should be allocated!");
+    thread->set_vm_result(str);
+  JRT_BLOCK_END
+JRT_END
+
+
+
+Klass* CompilerRuntime::resolve_klass_helper(JavaThread *thread, const char* name, int len, TRAPS) {
+  ResourceMark rm(THREAD);
+  // last java frame on stack (which includes native call frames)
+  RegisterMap cbl_map(thread, false);
+  // Skip stub
+  frame caller_frame = thread->last_frame().sender(&cbl_map);
+  CodeBlob* caller_cb = caller_frame.cb();
+  guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method");
+  CompiledMethod* caller_nm = caller_cb->as_compiled_method_or_null();
+  methodHandle caller(THREAD, caller_nm->method());
+
+  // Use class loader of aot method.
+  Handle loader(THREAD, caller->method_holder()->class_loader());
+  Handle protection_domain(THREAD, caller->method_holder()->protection_domain());
+
+  // Ignore wrapping L and ;
+  if (name[0] == 'L') {
+    assert(len > 2, "small name %s", name);
+    name++;
+    len -= 2;
+  }
+  TempNewSymbol sym = SymbolTable::new_symbol(name, len, CHECK_NULL);
+  if (sym == NULL) {
+    return NULL;
+  }
+  Klass* k = SystemDictionary::resolve_or_fail(sym, loader, protection_domain, true, CHECK_NULL);
+
+  return k;
+}
+
+// Resolve Klass
+JRT_BLOCK_ENTRY(Klass*, CompilerRuntime::resolve_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name))
+  Klass* k = NULL;
+  JRT_BLOCK
+    k = *klass_result; // Is it resolved already?
+    if (k == NULL) { // Do resolution
+      // First 2 bytes of name contains length (number of bytes).
+      int len = build_u2_from((address)name);
+      name += 2;
+      k = CompilerRuntime::resolve_klass_helper(thread, name, len, CHECK_NULL);
+      *klass_result = k; // Store result
+    }
+  JRT_BLOCK_END
+  assert(k != NULL, " Should be loaded!");
+  return k;
+JRT_END
+
+
+Method* CompilerRuntime::resolve_method_helper(Klass* klass, const char* method_name, int method_name_len,
+                                                               const char* signature_name, int signature_name_len) {
+  Method* m = NULL;
+  TempNewSymbol name_symbol = SymbolTable::probe(method_name, method_name_len);
+  TempNewSymbol signature_symbol = SymbolTable::probe(signature_name, signature_name_len);
+  if (name_symbol != NULL && signature_symbol != NULL) {
+    if (name_symbol == vmSymbols::object_initializer_name() ||
+        name_symbol == vmSymbols::class_initializer_name()) {
+      // Never search superclasses for constructors
+      if (klass->is_instance_klass()) {
+        m = InstanceKlass::cast(klass)->find_method(name_symbol, signature_symbol);
+      }
+    } else {
+      m = klass->lookup_method(name_symbol, signature_symbol);
+      if (m == NULL && klass->is_instance_klass()) {
+        m = InstanceKlass::cast(klass)->lookup_method_in_ordered_interfaces(name_symbol, signature_symbol);
+      }
+    }
+  }
+  return m;
+}
+
+JRT_BLOCK_ENTRY(MethodCounters*, CompilerRuntime::resolve_method_by_symbol_and_load_counters(JavaThread *thread, MethodCounters** counters_result, Klass* klass, const char* data))
+  MethodCounters* c = *counters_result; // Is it resolved already?
+  JRT_BLOCK
+     if (c == NULL) { // Do resolution
+       // Get method name and its length
+       int method_name_len = build_u2_from((address)data);
+       data += sizeof(u2);
+       const char* method_name = data;
+       data += method_name_len;
+
+       // Get signature and its length
+       int signature_name_len = build_u2_from((address)data);
+       data += sizeof(u2);
+       const char* signature_name = data;
+
+       assert(klass != NULL, "Klass parameter must not be null");
+       Method* m = resolve_method_helper(klass, method_name, method_name_len, signature_name, signature_name_len);
+       assert(m != NULL, "Method must resolve successfully");
+
+       // Create method counters immediately to avoid check at runtime.
+       c = m->get_method_counters(thread);
+       if (c == NULL) {
+         THROW_MSG_NULL(vmSymbols::java_lang_OutOfMemoryError(), "Cannot allocate method counters");
+       }
+
+       *counters_result = c;
+     }
+  JRT_BLOCK_END
+  return c;
+JRT_END
+
+// Resolve and initialize Klass
+JRT_BLOCK_ENTRY(Klass*, CompilerRuntime::initialize_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name))
+  Klass* k = NULL;
+  JRT_BLOCK
+    k = klass_result[0]; // Is it initialized already?
+    if (k == NULL) { // Do initialized
+      k = klass_result[1]; // Is it resolved already?
+      if (k == NULL) { // Do resolution
+        // First 2 bytes of name contains length (number of bytes).
+        int len = build_u2_from((address)name);
+        const char *cname = name + 2;
+        k = CompilerRuntime::resolve_klass_helper(thread,  cname, len, CHECK_NULL);
+        klass_result[1] = k; // Store resolved result
+      }
+      Klass* k0 = klass_result[0]; // Is it initialized already?
+      if (k0 == NULL && k != NULL && k->is_instance_klass()) {
+        // Force initialization of instance class
+        InstanceKlass::cast(k)->initialize(CHECK_NULL);
+        // Double-check that it was really initialized,
+        // because we could be doing a recursive call
+        // from inside <clinit>.
+        if (InstanceKlass::cast(k)->is_initialized()) {
+          klass_result[0] = k; // Store initialized result
+        }
+      }
+    }
+  JRT_BLOCK_END
+  assert(k != NULL, " Should be loaded!");
+  return k;
+JRT_END
+
+
+JRT_BLOCK_ENTRY(void, CompilerRuntime::invocation_event(JavaThread *thread, MethodCounters* counters))
+  if (!TieredCompilation) {
+    // Ignore the event if tiered is off
+    return;
+  }
+  JRT_BLOCK
+    methodHandle mh(THREAD, counters->method());
+    RegisterMap map(thread, false);
+
+    // Compute the enclosing method
+    frame fr = thread->last_frame().sender(&map);
+    CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
+    assert(cm != NULL && cm->is_compiled(), "Sanity check");
+    methodHandle emh(THREAD, cm->method());
+
+    assert(!HAS_PENDING_EXCEPTION, "Should not have any exceptions pending");
+    CompilationPolicy::policy()->event(emh, mh, InvocationEntryBci, InvocationEntryBci, CompLevel_aot, cm, thread);
+    assert(!HAS_PENDING_EXCEPTION, "Event handler should not throw any exceptions");
+  JRT_BLOCK_END
+JRT_END
+
+JRT_BLOCK_ENTRY(void, CompilerRuntime::backedge_event(JavaThread *thread, MethodCounters* counters, int branch_bci, int target_bci))
+  if (!TieredCompilation) {
+    // Ignore the event if tiered is off
+    return;
+  }
+  assert(branch_bci != InvocationEntryBci && target_bci != InvocationEntryBci, "Wrong bci");
+  assert(target_bci <= branch_bci, "Expected a back edge");
+  JRT_BLOCK
+    methodHandle mh(THREAD, counters->method());
+    RegisterMap map(thread, false);
+
+    // Compute the enclosing method
+    frame fr = thread->last_frame().sender(&map);
+    CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
+    assert(cm != NULL && cm->is_compiled(), "Sanity check");
+    methodHandle emh(THREAD, cm->method());
+    assert(!HAS_PENDING_EXCEPTION, "Should not have any exceptions pending");
+    nmethod* osr_nm = CompilationPolicy::policy()->event(emh, mh, branch_bci, target_bci, CompLevel_aot, cm, thread);
+    assert(!HAS_PENDING_EXCEPTION, "Event handler should not throw any exceptions");
+    if (osr_nm != NULL) {
+      Deoptimization::deoptimize_frame(thread, fr.id());
+    }
+  JRT_BLOCK_END
+JRT_END
diff --git a/hotspot/src/share/vm/jvmci/compilerRuntime.hpp b/hotspot/src/share/vm/jvmci/compilerRuntime.hpp
new file mode 100644
index 0000000..1e3d708
--- /dev/null
+++ b/hotspot/src/share/vm/jvmci/compilerRuntime.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMPILERRUNTIME_HPP
+#define SHARE_VM_RUNTIME_COMPILERRUNTIME_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "utilities/exceptions.hpp"
+
+class CompilerRuntime : AllStatic {
+ public:
+  // Resolves klass for aot compiled method.
+  static Klass* resolve_klass_helper(JavaThread *thread, const char* name, int len, TRAPS);
+  // Resolves method for aot compiled method.
+  static Method* resolve_method_helper(Klass* klass, const char* method_name, int method_name_len,
+                                       const char* signature_name, int signature_name_len);
+  // Resolution methods for aot compiled code.
+  static void resolve_string_by_symbol(JavaThread *thread, void* string_result, const char* name);
+  static Klass* resolve_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name);
+  static Klass* initialize_klass_by_symbol(JavaThread *thread, Klass** klass_result, const char* name);
+  static MethodCounters* resolve_method_by_symbol_and_load_counters(JavaThread *thread, MethodCounters** counters_result, Klass* klass_hint, const char* data);
+  static void invocation_event(JavaThread *thread, MethodCounters* counters);
+  static void backedge_event(JavaThread *thread, MethodCounters* counters, int branch_bci, int target_bci);
+};
+
+#endif // SHARE_VM_RUNTIME_COMPILERRUNTIME_HPP
diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
index 95c7deb..f5e7e7a 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
@@ -172,6 +172,69 @@
   return map;
 }
 
+AOTOopRecorder::AOTOopRecorder(Arena* arena, bool deduplicate) : OopRecorder(arena, deduplicate) {
+  _meta_strings = new GrowableArray<const char*>();
+}
+
+int AOTOopRecorder::nr_meta_strings() const {
+  return _meta_strings->length();
+}
+
+const char* AOTOopRecorder::meta_element(int pos) const {
+  return _meta_strings->at(pos);
+}
+
+int AOTOopRecorder::find_index(Metadata* h) {
+  int index =  this->OopRecorder::find_index(h);
+
+  Klass* klass = NULL;
+  if (h->is_klass()) {
+    klass = (Klass*) h;
+    record_meta_string(klass->signature_name(), index);
+  } else if (h->is_method()) {
+    Method* method = (Method*) h;
+    // Need klass->signature_name() in method name
+    klass = method->method_holder();
+    const char* klass_name = klass->signature_name();
+    int klass_name_len  = (int)strlen(klass_name);
+    Symbol* method_name = method->name();
+    Symbol* signature   = method->signature();
+    int method_name_len = method_name->utf8_length();
+    int method_sign_len = signature->utf8_length();
+    int len             = klass_name_len + 1 + method_name_len + method_sign_len;
+    char* dest          = NEW_RESOURCE_ARRAY(char, len + 1);
+    strcpy(dest, klass_name);
+    dest[klass_name_len] = '.';
+    strcpy(&dest[klass_name_len + 1], method_name->as_C_string());
+    strcpy(&dest[klass_name_len + 1 + method_name_len], signature->as_C_string());
+    dest[len] = 0;
+    record_meta_string(dest, index);
+  }
+
+  return index;
+}
+
+int AOTOopRecorder::find_index(jobject h) {
+  if (h == NULL) {
+    return 0;
+  }
+  oop javaMirror = JNIHandles::resolve(h);
+  Klass* klass = java_lang_Class::as_Klass(javaMirror);
+  return find_index(klass);
+}
+
+void AOTOopRecorder::record_meta_string(const char* name, int index) {
+  assert(index > 0, "must be 1..n");
+  index -= 1; // reduce by one to convert to array index
+
+  if (index < _meta_strings->length()) {
+    assert(strcmp(name, _meta_strings->at(index)) == 0, "must match");
+  } else {
+    assert(index == _meta_strings->length(), "must be last");
+    _meta_strings->append(name);
+  }
+}
+
 void* CodeInstaller::record_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS) {
   /*
    * This method needs to return a raw (untyped) pointer, since the value of a pointer to the base
@@ -481,7 +544,10 @@
 JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS) {
   CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata");
   jobject compiled_code_obj = JNIHandles::make_local(compiled_code());
-  initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL, CHECK_OK);
+  AOTOopRecorder* recorder = new AOTOopRecorder(&_arena, true);
+  initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder, CHECK_OK);
+
+  metadata.set_oop_recorder(recorder);
 
   // Get instructions and constants CodeSections early because we need it.
   _instructions = buffer.insts();
@@ -553,7 +619,7 @@
                                        stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
                                        compiler, _debug_recorder, _dependencies, env, id,
                                        has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log);
-    cb = nm;
+    cb = nm->as_codeblob_or_null();
     if (nm != NULL && env == NULL) {
       DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler);
       bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption;
@@ -623,25 +689,40 @@
 }
 
 int CodeInstaller::estimate_stubs_size(TRAPS) {
-  // Estimate the number of static call stubs that might be emitted.
+  // Estimate the number of static and aot call stubs that might be emitted.
   int static_call_stubs = 0;
+  int aot_call_stubs = 0;
   objArrayOop sites = this->sites();
   for (int i = 0; i < sites->length(); i++) {
     oop site = sites->obj_at(i);
-    if (site != NULL && site->is_a(site_Mark::klass())) {
-      oop id_obj = site_Mark::id(site);
-      if (id_obj != NULL) {
-        if (!java_lang_boxing_object::is_instance(id_obj, T_INT)) {
-          JVMCI_ERROR_0("expected Integer id, got %s", id_obj->klass()->signature_name());
+    if (site != NULL) {
+      if (site->is_a(site_Mark::klass())) {
+        oop id_obj = site_Mark::id(site);
+        if (id_obj != NULL) {
+          if (!java_lang_boxing_object::is_instance(id_obj, T_INT)) {
+            JVMCI_ERROR_0("expected Integer id, got %s", id_obj->klass()->signature_name());
+          }
+          jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT));
+          if (id == INVOKESTATIC || id == INVOKESPECIAL) {
+            static_call_stubs++;
+          }
         }
-        jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT));
-        if (id == INVOKESTATIC || id == INVOKESPECIAL) {
-          static_call_stubs++;
+      }
+      if (UseAOT && site->is_a(site_Call::klass())) {
+        oop target = site_Call::target(site);
+        InstanceKlass* target_klass = InstanceKlass::cast(target->klass());
+        if (!target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) {
+          // Add far aot trampolines.
+          aot_call_stubs++;
         }
       }
     }
   }
-  return static_call_stubs * CompiledStaticCall::to_interp_stub_size();
+  int size = static_call_stubs * CompiledStaticCall::to_interp_stub_size();
+#if INCLUDE_AOT
+  size += aot_call_stubs * CompiledStaticCall::to_aot_stub_size();
+#endif
+  return size;
 }
 
 // perform data and call relocation on the CodeBuffer
@@ -1063,6 +1144,10 @@
 
   if (foreign_call.not_null()) {
     jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call);
+    if (_immutable_pic_compilation) {
+      // Use fake short distance during PIC compilation.
+      foreign_call_destination = (jlong)(_instructions->start() + pc_offset);
+    }
     CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, CHECK);
   } else { // method != NULL
     if (debug_info.is_null()) {
@@ -1075,6 +1160,10 @@
       // Need a static call stub for transitions from compiled to interpreted.
       CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset);
     }
+#if INCLUDE_AOT
+    // Trampoline to far aot code.
+    CompiledStaticCall::emit_to_aot_stub(buffer, _instructions->start() + pc_offset);
+#endif
   }
 
   _next_call_type = INVOKE_INVALID;
@@ -1093,9 +1182,18 @@
     if (constant.is_null()) {
       THROW(vmSymbols::java_lang_NullPointerException());
     } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) {
-      pd_patch_OopConstant(pc_offset, constant, CHECK);
+      if (!_immutable_pic_compilation) {
+        // Do not patch during PIC compilation.
+        pd_patch_OopConstant(pc_offset, constant, CHECK);
+      }
     } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) {
-      pd_patch_MetaspaceConstant(pc_offset, constant, CHECK);
+      if (!_immutable_pic_compilation) {
+        pd_patch_MetaspaceConstant(pc_offset, constant, CHECK);
+      }
+    } else if (constant->is_a(HotSpotSentinelConstant::klass())) {
+      if (!_immutable_pic_compilation) {
+        JVMCI_ERROR("sentinel constant not supported for normal compiles: %s", constant->klass()->signature_name());
+      }
     } else {
       JVMCI_ERROR("unknown constant type in data patch: %s", constant->klass()->signature_name());
     }
@@ -1158,6 +1256,8 @@
       case HEAP_END_ADDRESS:
       case NARROW_KLASS_BASE_ADDRESS:
       case CRC_TABLE_ADDRESS:
+      case LOG_OF_HEAP_REGION_GRAIN_BYTES:
+      case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
         break;
       default:
         JVMCI_ERROR("invalid mark id: %d", id);
diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
index 8c4aa51..d5e2d32 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
@@ -43,6 +43,21 @@
   char *_buffer;
 };
 
+class AOTOopRecorder : public OopRecorder {
+public:
+  AOTOopRecorder(Arena* arena = NULL, bool deduplicate = false);
+
+  virtual int find_index(Metadata* h);
+  virtual int find_index(jobject h);
+  int nr_meta_strings() const;
+  const char* meta_element(int pos) const;
+
+private:
+  void record_meta_string(const char* name, int index);
+
+  GrowableArray<const char*>* _meta_strings;
+};
+
 class CodeMetadata {
 public:
   CodeMetadata() {}
@@ -57,6 +72,8 @@
 
   RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; }
 
+  AOTOopRecorder* get_oop_recorder() { return _oop_recorder; }
+
   ExceptionHandlerTable* get_exception_table() { return _exception_table; }
 
   void set_pc_desc(PcDesc* desc, int count) {
@@ -69,6 +86,10 @@
     _nr_scopes_desc = size;
   }
 
+  void set_oop_recorder(AOTOopRecorder* recorder) {
+    _oop_recorder = recorder;
+  }
+
   void set_exception_table(ExceptionHandlerTable* table) {
     _exception_table = table;
   }
@@ -82,6 +103,7 @@
   int _nr_scopes_desc;
 
   RelocBuffer _reloc_buffer;
+  AOTOopRecorder* _oop_recorder;
   ExceptionHandlerTable* _exception_table;
 };
 
@@ -92,27 +114,29 @@
   friend class JVMCIVMStructs;
 private:
   enum MarkId {
-    VERIFIED_ENTRY             = 1,
-    UNVERIFIED_ENTRY           = 2,
-    OSR_ENTRY                  = 3,
-    EXCEPTION_HANDLER_ENTRY    = 4,
-    DEOPT_HANDLER_ENTRY        = 5,
-    INVOKEINTERFACE            = 6,
-    INVOKEVIRTUAL              = 7,
-    INVOKESTATIC               = 8,
-    INVOKESPECIAL              = 9,
-    INLINE_INVOKE              = 10,
-    POLL_NEAR                  = 11,
-    POLL_RETURN_NEAR           = 12,
-    POLL_FAR                   = 13,
-    POLL_RETURN_FAR            = 14,
-    CARD_TABLE_ADDRESS         = 15,
-    CARD_TABLE_SHIFT           = 16,
-    HEAP_TOP_ADDRESS           = 17,
-    HEAP_END_ADDRESS           = 18,
-    NARROW_KLASS_BASE_ADDRESS  = 19,
-    CRC_TABLE_ADDRESS          = 20,
-    INVOKE_INVALID             = -1
+    VERIFIED_ENTRY                         = 1,
+    UNVERIFIED_ENTRY                       = 2,
+    OSR_ENTRY                              = 3,
+    EXCEPTION_HANDLER_ENTRY                = 4,
+    DEOPT_HANDLER_ENTRY                    = 5,
+    INVOKEINTERFACE                        = 6,
+    INVOKEVIRTUAL                          = 7,
+    INVOKESTATIC                           = 8,
+    INVOKESPECIAL                          = 9,
+    INLINE_INVOKE                          = 10,
+    POLL_NEAR                              = 11,
+    POLL_RETURN_NEAR                       = 12,
+    POLL_FAR                               = 13,
+    POLL_RETURN_FAR                        = 14,
+    CARD_TABLE_ADDRESS                     = 15,
+    CARD_TABLE_SHIFT                       = 16,
+    HEAP_TOP_ADDRESS                       = 17,
+    HEAP_END_ADDRESS                       = 18,
+    NARROW_KLASS_BASE_ADDRESS              = 19,
+    CRC_TABLE_ADDRESS                      = 20,
+    LOG_OF_HEAP_REGION_GRAIN_BYTES         = 21,
+    INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 22,
+    INVOKE_INVALID                         = -1
   };
 
   Arena         _arena;
@@ -146,6 +170,8 @@
   Dependencies*             _dependencies;
   ExceptionHandlerTable     _exception_handler_table;
 
+  bool _immutable_pic_compilation;  // Installer is called for Immutable PIC compilation.
+
   static ConstantOopWriteValue* _oop_null_scope_value;
   static ConstantIntValue*    _int_m1_scope_value;
   static ConstantIntValue*    _int_0_scope_value;
@@ -173,7 +199,7 @@
 
 public:
 
-  CodeInstaller() : _arena(mtCompiler) {}
+  CodeInstaller(bool immutable_pic_compilation) : _arena(mtCompiler), _immutable_pic_compilation(immutable_pic_compilation) {}
 
   JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS);
   JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS);
diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
index a88f56a..f7eb56f 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
@@ -847,7 +847,8 @@
   JVMCICompiler* compiler = JVMCICompiler::instance(CHECK_JNI_ERR);
 
   TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer());
-  CodeInstaller installer;
+  bool is_immutable_PIC = HotSpotCompiledCode::isImmutablePIC(compiled_code_handle) > 0;
+  CodeInstaller installer(is_immutable_PIC);
   JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle, CHECK_0);
 
   if (PrintCodeCacheOnCompilation) {
@@ -905,7 +906,7 @@
 
   CodeMetadata code_metadata;
   CodeBlob *cb = NULL;
-  CodeInstaller installer;
+  CodeInstaller installer(true /* immutable PIC compilation */);
 
   JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, CHECK_0);
   if (result != JVMCIEnv::ok) {
@@ -941,7 +942,16 @@
     HotSpotMetaData::set_oopMaps(metadata_handle, oopMapArrayHandle());
   }
 
-  HotSpotMetaData::set_metadata(metadata_handle, NULL);
+  AOTOopRecorder* recorder = code_metadata.get_oop_recorder();
+
+  int nr_meta_strings = recorder->nr_meta_strings();
+  objArrayHandle metadataArrayHandle = oopFactory::new_objectArray(nr_meta_strings, CHECK_(JVMCIEnv::cache_full));
+  for (int i = 0; i < nr_meta_strings; ++i) {
+    const char* element = recorder->meta_element(i);
+    Handle java_string = java_lang_String::create_from_str(element, CHECK_(JVMCIEnv::cache_full));
+    metadataArrayHandle->obj_at_put(i, java_string());
+  }
+  HotSpotMetaData::set_metadata(metadata_handle, metadataArrayHandle());
 
   ExceptionHandlerTable* handler = code_metadata.get_exception_table();
   int table_size = handler->size_in_bytes();
@@ -1493,6 +1503,15 @@
   THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid profile data position %d", position));
 C2V_END
 
+C2V_VMENTRY(jlong, getFingerprint, (JNIEnv*, jobject, jlong metaspace_klass))
+  Klass *k = CompilerToVM::asKlass(metaspace_klass);
+  if (k->is_instance_klass()) {
+    return InstanceKlass::cast(k)->get_stored_fingerprint();
+  } else {
+    return 0;
+  }
+C2V_END
+
 C2V_VMENTRY(int, interpreterFrameSize, (JNIEnv*, jobject, jobject bytecode_frame_handle))
   if (bytecode_frame_handle == NULL) {
     THROW_0(vmSymbols::java_lang_NullPointerException());
@@ -1621,6 +1640,7 @@
   {CC "writeDebugOutput",                             CC "([BII)V",                                                                         FN_PTR(writeDebugOutput)},
   {CC "flushDebugOutput",                             CC "()V",                                                                             FN_PTR(flushDebugOutput)},
   {CC "methodDataProfileDataSize",                    CC "(JI)I",                                                                           FN_PTR(methodDataProfileDataSize)},
+  {CC "getFingerprint",                               CC "(J)J",                                                                            FN_PTR(getFingerprint)},
   {CC "interpreterFrameSize",                         CC "(" BYTECODE_FRAME ")I",                                                           FN_PTR(interpreterFrameSize)},
   {CC "compileToBytecode",                            CC "(" OBJECT ")V",                                                                   FN_PTR(compileToBytecode)},
 };
diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp
index e16dae8..c0f21e2 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp
@@ -125,6 +125,10 @@
     return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type));
   }
 
+  static inline Klass* asKlass(jlong metaspaceKlass) {
+    return (Klass*) (address) metaspaceKlass;
+  }
+
   static inline MethodData* asMethodData(jlong metaspaceMethodData) {
     return (MethodData*) (address) metaspaceMethodData;
   }
diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp
index 3972a6c..73e507f 100644
--- a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp
+++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp
@@ -44,7 +44,7 @@
   fieldDescriptor fd;
   if (!ik->find_field(name_symbol, signature_symbol, &fd)) {
     ResourceMark rm;
-    fatal("Invalid layout of %s at %s", name_symbol->as_C_string(), ik->external_name());
+    fatal("Invalid layout of %s %s at %s", name_symbol->as_C_string(), signature_symbol->as_C_string(), ik->external_name());
   }
   guarantee(fd.is_static() == static_field, "static/instance mismatch");
   dest_offset = fd.offset();
diff --git a/hotspot/src/share/vm/jvmci/vmStructs_compiler_runtime.hpp b/hotspot/src/share/vm/jvmci/vmStructs_compiler_runtime.hpp
new file mode 100644
index 0000000..6e47bbd
--- /dev/null
+++ b/hotspot/src/share/vm/jvmci/vmStructs_compiler_runtime.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_JVMCI_VMSTRUCTS_COMPILER_RUNTIME_HPP
+#define SHARE_VM_JVMCI_VMSTRUCTS_COMPILER_RUNTIME_HPP
+
+#if INCLUDE_AOT
+#include "jvmci/compilerRuntime.hpp"
+
+#define VM_ADDRESSES_COMPILER_RUNTIME(declare_address, declare_preprocessor_address, declare_function) \
+  declare_function(CompilerRuntime::resolve_string_by_symbol)                     \
+  declare_function(CompilerRuntime::resolve_klass_by_symbol)                      \
+  declare_function(CompilerRuntime::resolve_method_by_symbol_and_load_counters)   \
+  declare_function(CompilerRuntime::initialize_klass_by_symbol)                   \
+  declare_function(CompilerRuntime::invocation_event)                             \
+  declare_function(CompilerRuntime::backedge_event)
+
+#else // INCLUDE_AOT
+
+#define VM_ADDRESSES_COMPILER_RUNTIME(declare_address, declare_preprocessor_address, declare_function)
+
+#endif // INCLUDE_AOT
+
+#endif // SHARE_VM_AOT_VMSTRUCTS_COMPILER_RUNTIME_HPP
diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
index 0117b4b..2dad27f 100644
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
@@ -30,6 +30,7 @@
 #include "jvmci/jvmciCompilerToVM.hpp"
 #include "jvmci/jvmciEnv.hpp"
 #include "jvmci/jvmciRuntime.hpp"
+#include "jvmci/vmStructs_compiler_runtime.hpp"
 #include "jvmci/vmStructs_jvmci.hpp"
 #include "oops/oop.hpp"
 #include "oops/objArrayKlass.hpp"
@@ -43,7 +44,6 @@
 #include "gc/g1/heapRegion.hpp"
 #endif
 
-
 #define VM_STRUCTS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field) \
   static_field(CompilerToVM::Data,             Klass_vtable_start_offset,              int)                                          \
   static_field(CompilerToVM::Data,             Klass_vtable_length_offset,             int)                                          \
@@ -280,8 +280,25 @@
   static_field(StubRoutines,                _aescrypt_decryptBlock,                           address)                               \
   static_field(StubRoutines,                _cipherBlockChaining_encryptAESCrypt,             address)                               \
   static_field(StubRoutines,                _cipherBlockChaining_decryptAESCrypt,             address)                               \
+  static_field(StubRoutines,                _counterMode_AESCrypt,                            address)                               \
+  static_field(StubRoutines,                _ghash_processBlocks,                             address)                               \
+  static_field(StubRoutines,                _sha1_implCompress,                               address)                               \
+  static_field(StubRoutines,                _sha1_implCompressMB,                             address)                               \
+  static_field(StubRoutines,                _sha256_implCompress,                             address)                               \
+  static_field(StubRoutines,                _sha256_implCompressMB,                           address)                               \
+  static_field(StubRoutines,                _sha512_implCompress,                             address)                               \
+  static_field(StubRoutines,                _sha512_implCompressMB,                           address)                               \
   static_field(StubRoutines,                _updateBytesCRC32,                                address)                               \
   static_field(StubRoutines,                _crc_table_adr,                                   address)                               \
+  static_field(StubRoutines,                _crc32c_table_addr,                               address)                               \
+  static_field(StubRoutines,                _updateBytesCRC32C,                               address)                               \
+  static_field(StubRoutines,                _updateBytesAdler32,                              address)                               \
+  static_field(StubRoutines,                _multiplyToLen,                                   address)                               \
+  static_field(StubRoutines,                _squareToLen,                                     address)                               \
+  static_field(StubRoutines,                _mulAdd,                                          address)                               \
+  static_field(StubRoutines,                _montgomeryMultiply,                              address)                               \
+  static_field(StubRoutines,                _montgomerySquare,                                address)                               \
+  static_field(StubRoutines,                _vectorizedMismatch,                              address)                               \
                                                                                                                                      \
   nonstatic_field(Thread,                   _tlab,                                            ThreadLocalAllocBuffer)                \
   nonstatic_field(Thread,                   _allocated_bytes,                                 jlong)                                 \
@@ -413,6 +430,8 @@
   declare_constant(CodeInstaller::HEAP_END_ADDRESS)                       \
   declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS)              \
   declare_constant(CodeInstaller::CRC_TABLE_ADDRESS)                      \
+  declare_constant(CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES)         \
+  declare_constant(CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED) \
   declare_constant(CodeInstaller::INVOKE_INVALID)                         \
                                                                           \
   declare_constant(ConstantPool::CPCACHE_INDEX_TAG)                       \
@@ -879,7 +898,9 @@
   VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY,
                GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
                GENERATE_VM_FUNCTION_ENTRY)
-
+  VM_ADDRESSES_COMPILER_RUNTIME(GENERATE_VM_ADDRESS_ENTRY,
+               GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
+               GENERATE_VM_FUNCTION_ENTRY)
   VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY,
                   GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY,
                   GENERATE_VM_FUNCTION_ENTRY)
diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp
index 90638b4..e262d07 100644
--- a/hotspot/src/share/vm/logging/logTag.hpp
+++ b/hotspot/src/share/vm/logging/logTag.hpp
@@ -35,6 +35,7 @@
   LOG_TAG(add) \
   LOG_TAG(age) \
   LOG_TAG(alloc) \
+  LOG_TAG(aot) \
   LOG_TAG(annotation) \
   LOG_TAG(arguments) \
   LOG_TAG(attach) \
@@ -59,6 +60,7 @@
   LOG_TAG(ergo) \
   LOG_TAG(exceptions) \
   LOG_TAG(exit) \
+  LOG_TAG(fingerprint) \
   LOG_TAG(freelist) \
   LOG_TAG(gc) \
   LOG_TAG(hashtables) \
@@ -90,6 +92,7 @@
   LOG_TAG(oopmap) \
   LOG_TAG(os) \
   LOG_TAG(pagesize) \
+  LOG_TAG(patch) \
   LOG_TAG(path) \
   LOG_TAG(phases) \
   LOG_TAG(plab) \
diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp
index 7afab96..9d2179d 100644
--- a/hotspot/src/share/vm/memory/heap.cpp
+++ b/hotspot/src/share/vm/memory/heap.cpp
@@ -275,6 +275,13 @@
   return h->allocated_space();
 }
 
+CodeBlob* CodeHeap::find_blob_unsafe(void* start) const {
+  CodeBlob* result = (CodeBlob*)CodeHeap::find_start(start);
+  if (result != NULL && result->blob_contains((address)start)) {
+    return result;
+  }
+  return NULL;
+}
 
 size_t CodeHeap::alignment_unit() const {
   // this will be a power of two
diff --git a/hotspot/src/share/vm/memory/heap.hpp b/hotspot/src/share/vm/memory/heap.hpp
index a34cd12..d755596 100644
--- a/hotspot/src/share/vm/memory/heap.hpp
+++ b/hotspot/src/share/vm/memory/heap.hpp
@@ -81,8 +81,7 @@
 
 class CodeHeap : public CHeapObj<mtCode> {
   friend class VMStructs;
-  friend class PregeneratedCodeHeap;
- private:
+ protected:
   VirtualSpace _memory;                          // the memory holding the blocks
   VirtualSpace _segmap;                          // the memory holding the segment map
 
@@ -156,6 +155,7 @@
 
   virtual bool  contains(const void* p) const    { return low_boundary() <= p && p < high(); }
   virtual void* find_start(void* p)     const;   // returns the block containing p or NULL
+  virtual CodeBlob* find_blob_unsafe(void* start) const;
   size_t alignment_unit()       const;           // alignment of any block
   size_t alignment_offset()     const;           // offset of first byte of any block, within the enclosing alignment unit
   static size_t header_size();                   // returns the header size for each heap block
diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp
index 948629b..db4bf61 100644
--- a/hotspot/src/share/vm/memory/metaspace.cpp
+++ b/hotspot/src/share/vm/memory/metaspace.cpp
@@ -22,6 +22,7 @@
  *
  */
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/collectorPolicy.hpp"
 #include "gc/shared/gcLocker.hpp"
@@ -153,7 +154,7 @@
 
   // Map a size to a list index assuming that there are lists
   // for special, small, medium, and humongous chunks.
-  static ChunkIndex list_index(size_t size);
+  ChunkIndex list_index(size_t size);
 
   // Remove the chunk from its freelist.  It is
   // expected to be on one of the _free_chunks[] lists.
@@ -489,6 +490,10 @@
       // Get a mmap region anywhere if the SharedBaseAddress fails.
       _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages);
     }
+    if (!_rs.is_reserved()) {
+      vm_exit_during_initialization("Unable to allocate memory for shared space",
+        err_msg(SIZE_FORMAT " bytes.", bytes));
+    }
     MetaspaceShared::initialize_shared_rs(&_rs);
   } else
 #endif
@@ -592,9 +597,8 @@
 
   size_t free_bytes();
 
-  Metachunk* get_new_chunk(size_t word_size,
-                           size_t grow_chunks_by_words,
-                           size_t medium_chunk_bunch);
+  Metachunk* get_new_chunk(size_t chunk_word_size,
+                           size_t suggested_commit_granularity);
 
   bool expand_node_by(VirtualSpaceNode* node,
                       size_t min_words,
@@ -745,15 +749,22 @@
     MediumChunkMultiple = 4
   };
 
-  bool is_class() { return _mdtype == Metaspace::ClassType; }
+  static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; }
+  static size_t small_chunk_size(bool is_class)       { return is_class ? ClassSmallChunk : SmallChunk; }
+  static size_t medium_chunk_size(bool is_class)      { return is_class ? ClassMediumChunk : MediumChunk; }
+
+  static size_t smallest_chunk_size(bool is_class)    { return specialized_chunk_size(is_class); }
 
   // Accessors
-  size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; }
-  size_t small_chunk_size()       { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
-  size_t medium_chunk_size()      { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
-  size_t medium_chunk_bunch()     { return medium_chunk_size() * MediumChunkMultiple; }
+  bool is_class() const { return _mdtype == Metaspace::ClassType; }
 
-  size_t smallest_chunk_size()  { return specialized_chunk_size(); }
+  size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); }
+  size_t small_chunk_size()       const { return small_chunk_size(is_class()); }
+  size_t medium_chunk_size()      const { return medium_chunk_size(is_class()); }
+
+  size_t smallest_chunk_size()    const { return smallest_chunk_size(is_class()); }
+
+  size_t medium_chunk_bunch()     const { return medium_chunk_size() * MediumChunkMultiple; }
 
   size_t allocated_blocks_words() const { return _allocated_blocks_words; }
   size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
@@ -777,10 +788,13 @@
   // decremented for all the Metachunks in-use by this SpaceManager.
   void dec_total_from_size_metrics();
 
-  // Set the sizes for the initial chunks.
-  void get_initial_chunk_sizes(Metaspace::MetaspaceType type,
-                               size_t* chunk_word_size,
-                               size_t* class_chunk_word_size);
+  // Adjust the initial chunk size to match one of the fixed chunk list sizes,
+  // or return the unadjusted size if the requested size is humongous.
+  static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space);
+  size_t adjust_initial_chunk_size(size_t requested) const;
+
+  // Get the initial chunks size for this metaspace type.
+  size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
 
   size_t sum_capacity_in_chunks_in_use() const;
   size_t sum_used_in_chunks_in_use() const;
@@ -791,7 +805,7 @@
   size_t sum_count_in_chunks_in_use();
   size_t sum_count_in_chunks_in_use(ChunkIndex i);
 
-  Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words);
+  Metachunk* get_new_chunk(size_t chunk_word_size);
 
   // Block allocation and deallocation.
   // Allocates a block from the current chunk
@@ -1396,12 +1410,10 @@
   return false;
 }
 
-Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
-                                           size_t grow_chunks_by_words,
-                                           size_t medium_chunk_bunch) {
+Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) {
 
   // Allocate a chunk out of the current virtual space.
-  Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
+  Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size);
 
   if (next != NULL) {
     return next;
@@ -1410,8 +1422,8 @@
   // The expand amount is currently only determined by the requested sizes
   // and not how much committed memory is left in the current virtual space.
 
-  size_t min_word_size       = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words());
-  size_t preferred_word_size = align_size_up(medium_chunk_bunch,   Metaspace::commit_alignment_words());
+  size_t min_word_size       = align_size_up(chunk_word_size,              Metaspace::commit_alignment_words());
+  size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words());
   if (min_word_size >= preferred_word_size) {
     // Can happen when humongous chunks are allocated.
     preferred_word_size = min_word_size;
@@ -1419,7 +1431,7 @@
 
   bool expanded = expand_by(min_word_size, preferred_word_size);
   if (expanded) {
-    next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
+    next = current_virtual_space()->get_chunk_vs(chunk_word_size);
     assert(next != NULL, "The allocation was expected to succeed after the expansion");
   }
 
@@ -1783,7 +1795,11 @@
   st->print_cr("Sum free chunk total " SIZE_FORMAT "  count " SIZE_FORMAT,
                 sum_free_chunks(), sum_free_chunks_count());
 }
+
 ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
+  assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex,
+         "Bad index: %d", (int)index);
+
   return &_free_chunks[index];
 }
 
@@ -1887,7 +1903,7 @@
   }
 
   assert((word_size <= chunk->word_size()) ||
-         list_index(chunk->word_size() == HumongousIndex),
+         (list_index(chunk->word_size()) == HumongousIndex),
          "Non-humongous variable sized chunk");
   Log(gc, metaspace, freelist) log;
   if (log.is_debug()) {
@@ -1913,36 +1929,58 @@
 
 // SpaceManager methods
 
-void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type,
-                                           size_t* chunk_word_size,
-                                           size_t* class_chunk_word_size) {
-  switch (type) {
-  case Metaspace::BootMetaspaceType:
-    *chunk_word_size = Metaspace::first_chunk_word_size();
-    *class_chunk_word_size = Metaspace::first_class_chunk_word_size();
-    break;
-  case Metaspace::ROMetaspaceType:
-    *chunk_word_size = SharedReadOnlySize / wordSize;
-    *class_chunk_word_size = ClassSpecializedChunk;
-    break;
-  case Metaspace::ReadWriteMetaspaceType:
-    *chunk_word_size = SharedReadWriteSize / wordSize;
-    *class_chunk_word_size = ClassSpecializedChunk;
-    break;
-  case Metaspace::AnonymousMetaspaceType:
-  case Metaspace::ReflectionMetaspaceType:
-    *chunk_word_size = SpecializedChunk;
-    *class_chunk_word_size = ClassSpecializedChunk;
-    break;
-  default:
-    *chunk_word_size = SmallChunk;
-    *class_chunk_word_size = ClassSmallChunk;
-    break;
+size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) {
+  size_t chunk_sizes[] = {
+      specialized_chunk_size(is_class_space),
+      small_chunk_size(is_class_space),
+      medium_chunk_size(is_class_space)
+  };
+
+  // Adjust up to one of the fixed chunk sizes ...
+  for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) {
+    if (requested <= chunk_sizes[i]) {
+      return chunk_sizes[i];
+    }
   }
-  assert(*chunk_word_size != 0 && *class_chunk_word_size != 0,
-         "Initial chunks sizes bad: data  " SIZE_FORMAT
-         " class " SIZE_FORMAT,
-         *chunk_word_size, *class_chunk_word_size);
+
+  // ... or return the size as a humongous chunk.
+  return requested;
+}
+
+size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const {
+  return adjust_initial_chunk_size(requested, is_class());
+}
+
+size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const {
+  size_t requested;
+
+  if (is_class()) {
+    switch (type) {
+    case Metaspace::BootMetaspaceType:       requested = Metaspace::first_class_chunk_word_size(); break;
+    case Metaspace::ROMetaspaceType:         requested = ClassSpecializedChunk; break;
+    case Metaspace::ReadWriteMetaspaceType:  requested = ClassSpecializedChunk; break;
+    case Metaspace::AnonymousMetaspaceType:  requested = ClassSpecializedChunk; break;
+    case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break;
+    default:                                 requested = ClassSmallChunk; break;
+    }
+  } else {
+    switch (type) {
+    case Metaspace::BootMetaspaceType:       requested = Metaspace::first_chunk_word_size(); break;
+    case Metaspace::ROMetaspaceType:         requested = SharedReadOnlySize / wordSize; break;
+    case Metaspace::ReadWriteMetaspaceType:  requested = SharedReadWriteSize / wordSize; break;
+    case Metaspace::AnonymousMetaspaceType:  requested = SpecializedChunk; break;
+    case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break;
+    default:                                 requested = SmallChunk; break;
+    }
+  }
+
+  // Adjust to one of the fixed chunk sizes (unless humongous)
+  const size_t adjusted = adjust_initial_chunk_size(requested);
+
+  assert(adjusted != 0, "Incorrect initial chunk size. Requested: "
+         SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted);
+
+  return adjusted;
 }
 
 size_t SpaceManager::sum_free_in_chunks_in_use() const {
@@ -2127,8 +2165,8 @@
   }
 
   // Get another chunk
-  size_t grow_chunks_by_words = calc_chunk_size(word_size);
-  Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words);
+  size_t chunk_word_size = calc_chunk_size(word_size);
+  Metachunk* next = get_new_chunk(chunk_word_size);
 
   MetaWord* mem = NULL;
 
@@ -2338,22 +2376,18 @@
 }
 
 ChunkIndex ChunkManager::list_index(size_t size) {
-  switch (size) {
-    case SpecializedChunk:
-      assert(SpecializedChunk == ClassSpecializedChunk,
-             "Need branch for ClassSpecializedChunk");
-      return SpecializedIndex;
-    case SmallChunk:
-    case ClassSmallChunk:
-      return SmallIndex;
-    case MediumChunk:
-    case ClassMediumChunk:
-      return MediumIndex;
-    default:
-      assert(size > MediumChunk || size > ClassMediumChunk,
-             "Not a humongous chunk");
-      return HumongousIndex;
+  if (free_chunks(SpecializedIndex)->size() == size) {
+    return SpecializedIndex;
   }
+  if (free_chunks(SmallIndex)->size() == size) {
+    return SmallIndex;
+  }
+  if (free_chunks(MediumIndex)->size() == size) {
+    return MediumIndex;
+  }
+
+  assert(size > free_chunks(MediumIndex)->size(), "Not a humongous chunk");
+  return HumongousIndex;
 }
 
 void SpaceManager::deallocate(MetaWord* p, size_t word_size) {
@@ -2377,7 +2411,7 @@
 
   // Find the correct list and and set the current
   // chunk for that list.
-  ChunkIndex index = ChunkManager::list_index(new_chunk->word_size());
+  ChunkIndex index = chunk_manager()->list_index(new_chunk->word_size());
 
   if (index != HumongousIndex) {
     retire_current_chunk();
@@ -2427,14 +2461,12 @@
   }
 }
 
-Metachunk* SpaceManager::get_new_chunk(size_t word_size,
-                                       size_t grow_chunks_by_words) {
+Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) {
   // Get a chunk from the chunk freelist
-  Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
+  Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size);
 
   if (next == NULL) {
-    next = vs_list()->get_new_chunk(word_size,
-                                    grow_chunks_by_words,
+    next = vs_list()->get_new_chunk(chunk_word_size,
                                     medium_chunk_bunch());
   }
 
@@ -3012,6 +3044,7 @@
     assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces");
     Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
   }
+  AOTLoader::set_narrow_klass_shift();
 }
 
 #if INCLUDE_CDS
@@ -3172,7 +3205,7 @@
          SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize);
   assert(using_class_space(), "Must be using class space");
   _class_space_list = new VirtualSpaceList(rs);
-  _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk);
+  _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
 
   if (!_class_space_list->initialization_succeeded()) {
     vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
@@ -3342,75 +3375,62 @@
   MetaspaceGC::post_initialize();
 }
 
-Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype,
-                                               size_t chunk_word_size,
-                                               size_t chunk_bunch) {
+void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) {
+  Metachunk* chunk = get_initialization_chunk(type, mdtype);
+  if (chunk != NULL) {
+    // Add to this manager's list of chunks in use and current_chunk().
+    get_space_manager(mdtype)->add_chunk(chunk, true);
+  }
+}
+
+Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) {
+  size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
+
   // Get a chunk from the chunk freelist
   Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
-  if (chunk != NULL) {
-    return chunk;
+
+  if (chunk == NULL) {
+    chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size,
+                                                  get_space_manager(mdtype)->medium_chunk_bunch());
   }
 
-  return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch);
+  // For dumping shared archive, report error if allocation has failed.
+  if (DumpSharedSpaces && chunk == NULL) {
+    report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord);
+  }
+
+  return chunk;
+}
+
+void Metaspace::verify_global_initialization() {
+  assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized");
+  assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized");
+
+  if (using_class_space()) {
+    assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized");
+    assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized");
+  }
 }
 
 void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
+  verify_global_initialization();
 
-  assert(space_list() != NULL,
-    "Metadata VirtualSpaceList has not been initialized");
-  assert(chunk_manager_metadata() != NULL,
-    "Metadata ChunkManager has not been initialized");
-
+  // Allocate SpaceManager for metadata objects.
   _vsm = new SpaceManager(NonClassType, lock);
-  if (_vsm == NULL) {
-    return;
-  }
-  size_t word_size;
-  size_t class_word_size;
-  vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size);
 
   if (using_class_space()) {
-  assert(class_space_list() != NULL,
-    "Class VirtualSpaceList has not been initialized");
-  assert(chunk_manager_class() != NULL,
-    "Class ChunkManager has not been initialized");
-
     // Allocate SpaceManager for classes.
     _class_vsm = new SpaceManager(ClassType, lock);
-    if (_class_vsm == NULL) {
-      return;
-    }
   }
 
   MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
 
   // Allocate chunk for metadata objects
-  Metachunk* new_chunk = get_initialization_chunk(NonClassType,
-                                                  word_size,
-                                                  vsm()->medium_chunk_bunch());
-  // For dumping shared archive, report error if allocation has failed.
-  if (DumpSharedSpaces && new_chunk == NULL) {
-    report_insufficient_metaspace(MetaspaceAux::committed_bytes() + word_size * BytesPerWord);
-  }
-  assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
-  if (new_chunk != NULL) {
-    // Add to this manager's list of chunks in use and current_chunk().
-    vsm()->add_chunk(new_chunk, true);
-  }
+  initialize_first_chunk(type, NonClassType);
 
   // Allocate chunk for class metadata objects
   if (using_class_space()) {
-    Metachunk* class_chunk = get_initialization_chunk(ClassType,
-                                                      class_word_size,
-                                                      class_vsm()->medium_chunk_bunch());
-    if (class_chunk != NULL) {
-      class_vsm()->add_chunk(class_chunk, true);
-    } else {
-      // For dumping shared archive, report error if allocation has failed.
-      if (DumpSharedSpaces) {
-        report_insufficient_metaspace(MetaspaceAux::committed_bytes() + class_word_size * BytesPerWord);
-      }
-    }
+    initialize_first_chunk(type, ClassType);
   }
 
   _alloc_record_head = NULL;
@@ -3836,7 +3856,7 @@
     // vm_allocation_granularity aligned on Windows.
     size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
     large_size += (os::vm_page_size()/BytesPerWord);
-    vs_list->get_new_chunk(large_size, large_size, 0);
+    vs_list->get_new_chunk(large_size, 0);
   }
 
   static void test() {
@@ -4013,4 +4033,91 @@
   TestVirtualSpaceNodeTest::test();
   TestVirtualSpaceNodeTest::test_is_available();
 }
+
+// The following test is placed here instead of a gtest / unittest file
+// because the ChunkManager class is only available in this file.
+void ChunkManager_test_list_index() {
+  ChunkManager manager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
+
+  // Test previous bug where a query for a humongous class metachunk,
+  // incorrectly matched the non-class medium metachunk size.
+  {
+    assert(MediumChunk > ClassMediumChunk, "Precondition for test");
+
+    ChunkIndex index = manager.list_index(MediumChunk);
+
+    assert(index == HumongousIndex,
+           "Requested size is larger than ClassMediumChunk,"
+           " so should return HumongousIndex. Got index: %d", (int)index);
+  }
+
+  // Check the specified sizes as well.
+  {
+    ChunkIndex index = manager.list_index(ClassSpecializedChunk);
+    assert(index == SpecializedIndex, "Wrong index returned. Got index: %d", (int)index);
+  }
+  {
+    ChunkIndex index = manager.list_index(ClassSmallChunk);
+    assert(index == SmallIndex, "Wrong index returned. Got index: %d", (int)index);
+  }
+  {
+    ChunkIndex index = manager.list_index(ClassMediumChunk);
+    assert(index == MediumIndex, "Wrong index returned. Got index: %d", (int)index);
+  }
+  {
+    ChunkIndex index = manager.list_index(ClassMediumChunk + 1);
+    assert(index == HumongousIndex, "Wrong index returned. Got index: %d", (int)index);
+  }
+}
+
+
+// The following test is placed here instead of a gtest / unittest file
+// because the ChunkManager class is only available in this file.
+class SpaceManagerTest : AllStatic {
+  friend void SpaceManager_test_adjust_initial_chunk_size();
+
+  static void test_adjust_initial_chunk_size(bool is_class) {
+    const size_t smallest = SpaceManager::smallest_chunk_size(is_class);
+    const size_t normal   = SpaceManager::small_chunk_size(is_class);
+    const size_t medium   = SpaceManager::medium_chunk_size(is_class);
+
+#define test_adjust_initial_chunk_size(value, expected, is_class_value)          \
+    do {                                                                         \
+      size_t v = value;                                                          \
+      size_t e = expected;                                                       \
+      assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e,  \
+             "Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v);               \
+    } while (0)
+
+    // Smallest (specialized)
+    test_adjust_initial_chunk_size(1,            smallest, is_class);
+    test_adjust_initial_chunk_size(smallest - 1, smallest, is_class);
+    test_adjust_initial_chunk_size(smallest,     smallest, is_class);
+
+    // Small
+    test_adjust_initial_chunk_size(smallest + 1, normal, is_class);
+    test_adjust_initial_chunk_size(normal - 1,   normal, is_class);
+    test_adjust_initial_chunk_size(normal,       normal, is_class);
+
+    // Medium
+    test_adjust_initial_chunk_size(normal + 1, medium, is_class);
+    test_adjust_initial_chunk_size(medium - 1, medium, is_class);
+    test_adjust_initial_chunk_size(medium,     medium, is_class);
+
+    // Humongous
+    test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class);
+
+#undef test_adjust_initial_chunk_size
+  }
+
+  static void test_adjust_initial_chunk_size() {
+    test_adjust_initial_chunk_size(false);
+    test_adjust_initial_chunk_size(true);
+  }
+};
+
+void SpaceManager_test_adjust_initial_chunk_size() {
+  SpaceManagerTest::test_adjust_initial_chunk_size();
+}
+
 #endif
diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp
index 9958189..87ab903 100644
--- a/hotspot/src/share/vm/memory/metaspace.hpp
+++ b/hotspot/src/share/vm/memory/metaspace.hpp
@@ -105,14 +105,15 @@
   };
 
  private:
+  static void verify_global_initialization();
+
   void initialize(Mutex* lock, MetaspaceType type);
 
-  // Get the first chunk for a Metaspace.  Used for
+  // Initialize the first chunk for a Metaspace.  Used for
   // special cases such as the boot class loader, reflection
   // class loader and anonymous class loader.
-  Metachunk* get_initialization_chunk(MetadataType mdtype,
-                                      size_t chunk_word_size,
-                                      size_t chunk_bunch);
+  void initialize_first_chunk(MetaspaceType type, MetadataType mdtype);
+  Metachunk* get_initialization_chunk(MetaspaceType type, MetadataType mdtype);
 
   // Align up the word size to the allocation word size
   static size_t align_word_size_up(size_t);
@@ -139,6 +140,10 @@
 
   SpaceManager* _class_vsm;
   SpaceManager* class_vsm() const { return _class_vsm; }
+  SpaceManager* get_space_manager(MetadataType mdtype) {
+    assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
+    return mdtype == ClassType ? class_vsm() : vsm();
+  }
 
   // Allocate space for metadata of type mdtype. This is space
   // within a Metachunk and is used by
diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp
index 2a5cc28..028016a 100644
--- a/hotspot/src/share/vm/memory/metaspaceTracer.cpp
+++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp
@@ -62,18 +62,12 @@
                                                     Metaspace::MetadataType mdtype) const {
   E event;
   if (event.should_commit()) {
+    event.set_classLoader(cld);
     if (cld->is_anonymous()) {
-      event.set_classLoader(NULL);
       event.set_anonymousClassLoader(true);
     } else {
-      if (cld->is_the_null_class_loader_data()) {
-        event.set_classLoader((Klass*) NULL);
-      } else {
-        event.set_classLoader(cld->class_loader()->klass());
-      }
       event.set_anonymousClassLoader(false);
     }
-
     event.set_size(word_size * BytesPerWord);
     event.set_metadataType((u1) mdtype);
     event.set_metaspaceObjectType((u1) objtype);
diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp
index 97cd396..d56e8dd 100644
--- a/hotspot/src/share/vm/memory/universe.cpp
+++ b/hotspot/src/share/vm/memory/universe.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/javaClasses.hpp"
@@ -671,6 +672,8 @@
 
   Metaspace::global_initialize();
 
+  AOTLoader::universe_init();
+
   // Checks 'AfterMemoryInit' constraints.
   if (!CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterMemoryInit)) {
     return JNI_EINVAL;
diff --git a/hotspot/src/share/vm/memory/virtualspace.cpp b/hotspot/src/share/vm/memory/virtualspace.cpp
index 1c4bec9..4283c8b 100644
--- a/hotspot/src/share/vm/memory/virtualspace.cpp
+++ b/hotspot/src/share/vm/memory/virtualspace.cpp
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/virtualspace.hpp"
@@ -592,7 +591,7 @@
 ReservedCodeSpace::ReservedCodeSpace(size_t r_size,
                                      size_t rs_align,
                                      bool large) :
-  ReservedSpace(r_size, rs_align, large, /*executable*/ CodeCacheExtensions::support_dynamic_code()) {
+  ReservedSpace(r_size, rs_align, large, /*executable*/ true) {
   MemTracker::record_virtual_memory_type((address)base(), mtCode);
 }
 
diff --git a/hotspot/src/share/vm/memory/virtualspace.hpp b/hotspot/src/share/vm/memory/virtualspace.hpp
index 84c5b7f..ab3293f 100644
--- a/hotspot/src/share/vm/memory/virtualspace.hpp
+++ b/hotspot/src/share/vm/memory/virtualspace.hpp
@@ -184,6 +184,14 @@
   char* low_boundary()  const { return _low_boundary; }
   char* high_boundary() const { return _high_boundary; }
 
+#if INCLUDE_AOT
+  // Set boundaries for code section in AOT library.
+  void set_low_boundary(char *p)  { _low_boundary = p; }
+  void set_high_boundary(char *p) { _high_boundary = p; }
+  void set_low(char *p)           { _low = p; }
+  void set_high(char *p)          { _high = p; }
+#endif
+
   bool special() const { return _special; }
 
  public:
diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp
index 98088b6..d9107ad 100644
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp
@@ -90,7 +90,7 @@
     set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
     set_layout_helper(Klass::_lh_neutral_value);
     set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
-    TRACE_INIT_KLASS_ID(this);
+    TRACE_INIT_ID(this);
 }
 
 
@@ -105,7 +105,7 @@
   // These classes will be put on a fixup list and their module fields will be patched once
   // java.base is defined.
   assert((module_entry != NULL) || ((module_entry == NULL) && !ModuleEntryTable::javabase_defined()),
-         "module entry not available post java.base definition");
+         "module entry not available post " JAVA_BASE_NAME " definition");
   oop module = (module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL;
   java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(NULL), CHECK);
 }
diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp
index 568c6c4..45246ba 100644
--- a/hotspot/src/share/vm/oops/constMethod.hpp
+++ b/hotspot/src/share/vm/oops/constMethod.hpp
@@ -205,7 +205,7 @@
   // Adapter blob (i2c/c2i) for this Method*. Set once when method is linked.
   union {
     AdapterHandlerEntry* _adapter;
-    AdapterHandlerEntry** _adapter_trampoline;
+    AdapterHandlerEntry** _adapter_trampoline; // see comments around Method::link_method()
   };
 
   int               _constMethod_size;
diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp
index 32c2245..5b2180f 100644
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp
@@ -23,8 +23,10 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/moduleEntry.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -145,7 +147,8 @@
                                        parser.itable_size(),
                                        nonstatic_oop_map_size(parser.total_oop_map_count()),
                                        parser.is_interface(),
-                                       parser.is_anonymous());
+                                       parser.is_anonymous(),
+                                       should_store_fingerprint());
 
   const Symbol* const class_name = parser.class_name();
   assert(class_name != NULL, "invariant");
@@ -788,6 +791,9 @@
   }
 
 
+  // Look for aot compiled methods for this klass, including class initializer.
+  AOTLoader::load_for_klass(this_k, THREAD);
+
   // Step 8
   {
     assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
@@ -1951,6 +1957,72 @@
   }
 }
 
+bool InstanceKlass::supers_have_passed_fingerprint_checks() {
+  if (java_super() != NULL && !java_super()->has_passed_fingerprint_check()) {
+    ResourceMark rm;
+    log_trace(class, fingerprint)("%s : super %s not fingerprinted", external_name(), java_super()->external_name());
+    return false;
+  }
+
+  Array<Klass*>* local_interfaces = this->local_interfaces();
+  if (local_interfaces != NULL) {
+    int length = local_interfaces->length();
+    for (int i = 0; i < length; i++) {
+      InstanceKlass* intf = InstanceKlass::cast(local_interfaces->at(i));
+      if (!intf->has_passed_fingerprint_check()) {
+        ResourceMark rm;
+        log_trace(class, fingerprint)("%s : interface %s not fingerprinted", external_name(), intf->external_name());
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool InstanceKlass::should_store_fingerprint() {
+#if INCLUDE_AOT
+  // We store the fingerprint into the InstanceKlass only in the following 2 cases:
+  if (EnableJVMCI && !UseJVMCICompiler) {
+    // (1) We are running AOT to generate a shared library.
+    return true;
+  }
+  if (DumpSharedSpaces) {
+    // (2) We are running -Xshare:dump to create a shared archive
+    return true;
+  }
+#endif
+
+  // In all other cases we might set the _misc_has_passed_fingerprint_check bit,
+  // but do not store the 64-bit fingerprint to save space.
+  return false;
+}
+
+bool InstanceKlass::has_stored_fingerprint() const {
+#if INCLUDE_AOT
+  return should_store_fingerprint() || is_shared();
+#else
+  return false;
+#endif
+}
+
+uint64_t InstanceKlass::get_stored_fingerprint() const {
+  address adr = adr_fingerprint();
+  if (adr != NULL) {
+    return (uint64_t)Bytes::get_native_u8(adr); // adr may not be 64-bit aligned
+  }
+  return 0;
+}
+
+void InstanceKlass::store_fingerprint(uint64_t fingerprint) {
+  address adr = adr_fingerprint();
+  if (adr != NULL) {
+    Bytes::put_native_u8(adr, (u8)fingerprint); // adr may not be 64-bit aligned
+
+    ResourceMark rm;
+    log_trace(class, fingerprint)("stored as " PTR64_FORMAT " for class %s", fingerprint, external_name());
+  }
+}
 
 static void remove_unshareable_in_class(Klass* k) {
   // remove klass's unshareable info
@@ -2248,7 +2320,7 @@
         // the java.base module.  If a non-java.base package is erroneously placed
         // in the java.base module it will be caught later when java.base
         // is defined by ModuleEntryTable::verify_javabase_packages check.
-        assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "java.base module is NULL");
+        assert(ModuleEntryTable::javabase_moduleEntry() != NULL, JAVA_BASE_NAME " module is NULL");
         _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_moduleEntry());
       } else {
         assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL");
diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp
index f187ef5..015a86c 100644
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp
@@ -54,6 +54,7 @@
 //      indicating where oops are located in instances of this klass.
 //    [EMBEDDED implementor of the interface] only exist for interface
 //    [EMBEDDED host klass        ] only exist for an anonymous class (JSR 292 enabled)
+//    [EMBEDDED fingerprint       ] only if should_store_fingerprint()==true
 
 
 // forward declaration for class -- see below for definition
@@ -215,10 +216,12 @@
     _misc_has_nonstatic_concrete_methods      = 1 << 7,  // class/superclass/implemented interfaces has non-static, concrete methods
     _misc_declares_nonstatic_concrete_methods = 1 << 8,  // directly declares non-static, concrete methods
     _misc_has_been_redefined                  = 1 << 9,  // class has been redefined
-    _misc_is_scratch_class                    = 1 << 10, // class is the redefined scratch class
-    _misc_is_shared_boot_class                = 1 << 11, // defining class loader is boot class loader
-    _misc_is_shared_platform_class            = 1 << 12, // defining class loader is platform class loader
-    _misc_is_shared_app_class                 = 1 << 13  // defining class loader is app class loader
+    _misc_has_passed_fingerprint_check        = 1 << 10, // when this class was loaded, the fingerprint computed from its
+                                                         // code source was found to be matching the value recorded by AOT.
+    _misc_is_scratch_class                    = 1 << 11, // class is the redefined scratch class
+    _misc_is_shared_boot_class                = 1 << 12, // defining class loader is boot class loader
+    _misc_is_shared_platform_class            = 1 << 13, // defining class loader is platform class loader
+    _misc_is_shared_app_class                 = 1 << 14  // defining class loader is app class loader
   };
   u2 loader_type_bits() {
     return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
@@ -732,6 +735,23 @@
     _misc_flags |= _misc_has_been_redefined;
   }
 
+  bool has_passed_fingerprint_check() const {
+    return (_misc_flags & _misc_has_passed_fingerprint_check) != 0;
+  }
+  void set_has_passed_fingerprint_check(bool b) {
+    if (b) {
+      _misc_flags |= _misc_has_passed_fingerprint_check;
+    } else {
+      _misc_flags &= ~_misc_has_passed_fingerprint_check;
+    }
+  }
+  bool supers_have_passed_fingerprint_checks();
+
+  static bool should_store_fingerprint();
+  bool has_stored_fingerprint() const;
+  uint64_t get_stored_fingerprint() const;
+  void store_fingerprint(uint64_t fingerprint);
+
   bool is_scratch_class() const {
     return (_misc_flags & _misc_is_scratch_class) != 0;
   }
@@ -1028,19 +1048,21 @@
 
   static int size(int vtable_length, int itable_length,
                   int nonstatic_oop_map_size,
-                  bool is_interface, bool is_anonymous) {
+                  bool is_interface, bool is_anonymous, bool has_stored_fingerprint) {
     return align_metadata_size(header_size() +
            vtable_length +
            itable_length +
            nonstatic_oop_map_size +
            (is_interface ? (int)sizeof(Klass*)/wordSize : 0) +
-           (is_anonymous ? (int)sizeof(Klass*)/wordSize : 0));
+           (is_anonymous ? (int)sizeof(Klass*)/wordSize : 0) +
+           (has_stored_fingerprint ? (int)sizeof(uint64_t*)/wordSize : 0));
   }
   int size() const                    { return size(vtable_length(),
                                                itable_length(),
                                                nonstatic_oop_map_size(),
                                                is_interface(),
-                                               is_anonymous());
+                                               is_anonymous(),
+                                               has_stored_fingerprint());
   }
 #if INCLUDE_SERVICES
   virtual void collect_statistics(KlassSizeStats *sz) const;
@@ -1083,6 +1105,24 @@
     }
   }
 
+  address adr_fingerprint() const {
+    if (has_stored_fingerprint()) {
+      InstanceKlass** adr_host = adr_host_klass();
+      if (adr_host != NULL) {
+        return (address)(adr_host + 1);
+      }
+
+      Klass** adr_impl = adr_implementor();
+      if (adr_impl != NULL) {
+        return (address)(adr_impl + 1);
+      }
+
+      return (address)end_of_nonstatic_oop_maps();
+    } else {
+      return NULL;
+    }
+  }
+
   // Use this to return the size of an instance in heap words:
   int size_helper() const {
     return layout_helper_to_size_helper(layout_helper());
diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp
index 64c5c46..ebc5995 100644
--- a/hotspot/src/share/vm/oops/klass.cpp
+++ b/hotspot/src/share/vm/oops/klass.cpp
@@ -488,7 +488,7 @@
 
 void Klass::remove_unshareable_info() {
   assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
-  TRACE_REMOVE_KLASS_ID(this);
+  TRACE_REMOVE_ID(this);
 
   set_subklass(NULL);
   set_next_sibling(NULL);
@@ -501,7 +501,7 @@
 }
 
 void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
-  TRACE_RESTORE_KLASS_ID(this);
+  TRACE_RESTORE_ID(this);
 
   // If an exception happened during CDS restore, some of these fields may already be
   // set.  We leave the class on the CLD list, even if incomplete so that we don't
diff --git a/hotspot/src/share/vm/oops/metadata.cpp b/hotspot/src/share/vm/oops/metadata.cpp
index ecec5f7..2fb282e 100644
--- a/hotspot/src/share/vm/oops/metadata.cpp
+++ b/hotspot/src/share/vm/oops/metadata.cpp
@@ -42,7 +42,7 @@
 }
 
 char* Metadata::print_value_string() const {
-  char buf[100];
+  char buf[256];
   stringStream st(buf, sizeof(buf));
   if (this == NULL) {
     st.print("NULL");
diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp
index 0cd830f..4e3dcf0 100644
--- a/hotspot/src/share/vm/oops/method.cpp
+++ b/hotspot/src/share/vm/oops/method.cpp
@@ -953,34 +953,103 @@
 }
 #endif
 
+/****************************************************************************
+// The following illustrates how the entries work for CDS shared Methods:
+//
+// Our goal is to delay writing into a shared Method until it's compiled.
+// Hence, we want to determine the initial values for _i2i_entry,
+// _from_interpreted_entry and _from_compiled_entry during CDS dump time.
+//
+// In this example, both Methods A and B have the _i2i_entry of "zero_locals".
+// They also have similar signatures so that they will share the same
+// AdapterHandlerEntry.
+//
+// _adapter_trampoline points to a fixed location in the RW section of
+// the CDS archive. This location initially contains a NULL pointer. When the
+// first of method A or B is linked, an AdapterHandlerEntry is allocated
+// dynamically, and its c2i/i2c entries are generated.
+//
+// _i2i_entry and _from_interpreted_entry initially points to the same
+// (fixed) location in the CODE section of the CDS archive. This contains
+// an unconditional branch to the actual entry for "zero_locals", which is
+// generated at run time and may be on an arbitrary address. Thus, the
+// unconditional branch is also generated at run time to jump to the correct
+// address.
+//
+// Similarly, _from_compiled_entry points to a fixed address in the CODE
+// section. This address has enough space for an unconditional branch
+// instruction, and is initially zero-filled. After the AdapterHandlerEntry is
+// initialized, and the address for the actual c2i_entry is known, we emit a
+// branch instruction here to branch to the actual c2i_entry.
+//
+// The effect of the extra branch on the i2i and c2i entries is negligible.
+//
+// The reason for putting _adapter_trampoline in RO is many shared Methods
+// share the same AdapterHandlerEntry, so we can save space in the RW section
+// by having the extra indirection.
+
+
+[Method A: RW]
+  _constMethod ----> [ConstMethod: RO]
+                       _adapter_trampoline -----------+
+                                                      |
+  _i2i_entry              (same value as method B)    |
+  _from_interpreted_entry (same value as method B)    |
+  _from_compiled_entry    (same value as method B)    |
+                                                      |
+                                                      |
+[Method B: RW]                               +--------+
+  _constMethod ----> [ConstMethod: RO]       |
+                       _adapter_trampoline --+--->(AdapterHandlerEntry* ptr: RW)-+
+                                                                                 |
+                                                 +-------------------------------+
+                                                 |
+                                                 +----> [AdapterHandlerEntry] (allocated at run time)
+                                                              _fingerprint
+                                                              _c2i_entry ---------------------------------+->[c2i entry..]
+ _i2i_entry  -------------+                                   _i2c_entry ---------------+-> [i2c entry..] |
+ _from_interpreted_entry  |                                   _c2i_unverified_entry     |                 |
+         |                |                                                             |                 |
+         |                |  (_cds_entry_table: CODE)                                   |                 |
+         |                +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") |                 |
+         |                |                               (allocated at run time)       |                 |
+         |                |  ...                           [asm code ...]               |                 |
+         +-[not compiled]-+  [n]: jmp _entry_table[n]                                   |                 |
+         |                                                                              |                 |
+         |                                                                              |                 |
+         +-[compiled]-------------------------------------------------------------------+                 |
+                                                                                                          |
+ _from_compiled_entry------------>  (_c2i_entry_trampoline: CODE)                                         |
+                                    [jmp c2i_entry] ------------------------------------------------------+
+
+***/
+
 // Called when the method_holder is getting linked. Setup entrypoints so the method
 // is ready to be called from interpreter, compiler, and vtables.
 void Method::link_method(const methodHandle& h_method, TRAPS) {
   // If the code cache is full, we may reenter this function for the
   // leftover methods that weren't linked.
   if (is_shared()) {
-    if (adapter() != NULL) return;
-  } else {
-    if (_i2i_entry != NULL) return;
-
-    assert(adapter() == NULL, "init'd to NULL" );
+    address entry = Interpreter::entry_for_cds_method(h_method);
+    assert(entry != NULL && entry == _i2i_entry,
+           "should be correctly set during dump time");
+    if (adapter() != NULL) {
+      return;
+    }
+    assert(entry == _from_interpreted_entry,
+           "should be correctly set during dump time");
+  } else if (_i2i_entry != NULL) {
+    return;
   }
   assert( _code == NULL, "nothing compiled yet" );
 
   // Setup interpreter entrypoint
   assert(this == h_method(), "wrong h_method()" );
-  address entry;
 
-  if (this->is_shared()) {
-    entry = Interpreter::entry_for_cds_method(h_method);
-  } else {
-    entry = Interpreter::entry_for_method(h_method);
-  }
-  assert(entry != NULL, "interpreter entry must be non-null");
-  if (is_shared()) {
-    assert(entry == _i2i_entry && entry == _from_interpreted_entry,
-           "should be correctly set during dump time");
-  } else {
+  if (!is_shared()) {
+    assert(adapter() == NULL, "init'd to NULL");
+    address entry = Interpreter::entry_for_method(h_method);
+    assert(entry != NULL, "interpreter entry must be non-null");
     // Sets both _i2i_entry and _from_interpreted_entry
     set_interpreter_entry(entry);
   }
@@ -1024,7 +1093,7 @@
 
   if (mh->is_shared()) {
     assert(mh->adapter() == adapter, "must be");
-    assert(mh->_from_compiled_entry != NULL, "must be"); // FIXME, the instructions also not NULL
+    assert(mh->_from_compiled_entry != NULL, "must be");
   } else {
     mh->set_adapter_entry(adapter);
     mh->_from_compiled_entry = adapter->get_c2i_entry();
@@ -1034,9 +1103,9 @@
 
 void Method::restore_unshareable_info(TRAPS) {
   // Since restore_unshareable_info can be called more than once for a method, don't
-  // redo any work.   If this field is restored, there is nothing to do.
-  if (_from_compiled_entry == NULL) {
-    // restore method's vtable by calling a virtual function
+  // redo any work.
+  if (adapter() == NULL) {
+    // Restore Method's C++ vtable by calling a virtual function
     restore_vtable();
 
     methodHandle mh(THREAD, this);
diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp
index b15b19e..1c6e72d 100644
--- a/hotspot/src/share/vm/oops/method.hpp
+++ b/hotspot/src/share/vm/oops/method.hpp
@@ -103,6 +103,10 @@
   CompiledMethod* volatile _code;                       // Points to the corresponding piece of native code
   volatile address           _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry
 
+#if INCLUDE_AOT && defined(TIERED)
+  CompiledMethod* _aot_code;
+#endif
+
   // Constructor
   Method(ConstMethod* xconst, AccessFlags access_flags);
  public:
@@ -386,7 +390,20 @@
       mcs->set_rate(rate);
     }
   }
-#endif
+
+#if INCLUDE_AOT
+  void set_aot_code(CompiledMethod* aot_code) {
+    _aot_code = aot_code;
+  }
+
+  CompiledMethod* aot_code() const {
+    return _aot_code;
+  }
+#else
+  CompiledMethod* aot_code() const { return NULL; }
+#endif // INCLUDE_AOT
+#endif // TIERED
+
   int nmethod_age() const {
     if (method_counters() == NULL) {
       return INT_MAX;
@@ -648,6 +665,10 @@
   // simultaneously. Use with caution.
   bool has_compiled_code() const                 { return code() != NULL; }
 
+#ifdef TIERED
+  bool has_aot_code() const                      { return aot_code() != NULL; }
+#endif
+
   // sizing
   static int header_size()                       { return sizeof(Method)/wordSize; }
   static int size(bool is_native);
diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp
index 351cbff..df96b63 100644
--- a/hotspot/src/share/vm/oops/methodCounters.hpp
+++ b/hotspot/src/share/vm/oops/methodCounters.hpp
@@ -34,6 +34,9 @@
  friend class VMStructs;
  friend class JVMCIVMStructs;
  private:
+#if INCLUDE_AOT
+  Method*           _method;                     // Back link to Method
+#endif
 #if defined(COMPILER2) || INCLUDE_JVMCI
   int               _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered)
   u2                _interpreter_throwout_count; // Count of times method was exited via exception while interpreting
@@ -64,7 +67,11 @@
   u1                _highest_osr_comp_level;      // Same for OSR level
 #endif
 
-  MethodCounters(methodHandle mh) : _nmethod_age(INT_MAX)
+  MethodCounters(methodHandle mh) :
+#if INCLUDE_AOT
+                                    _method(mh()),
+#endif
+                                    _nmethod_age(INT_MAX)
 #ifdef TIERED
                                  , _rate(0),
                                    _prev_time(0),
@@ -107,6 +114,8 @@
   void deallocate_contents(ClassLoaderData* loader_data) {}
   DEBUG_ONLY(bool on_stack() { return false; })  // for template
 
+  AOT_ONLY(Method* method() const { return _method; })
+
   static int size() { return sizeof(MethodCounters) / wordSize; }
 
   bool is_klass() const { return false; }
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index 7322715..c298e31 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -5513,7 +5513,7 @@
   }
 
   assert(UseMontgomeryMultiplyIntrinsic, "not implemented on this platform");
-  const char* stubName = "montgomery_square";
+  const char* stubName = "montgomery_multiply";
 
   assert(callee()->signature()->size() == 7, "montgomeryMultiply has 7 parameters");
 
diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp
index b9368b42..d35d71a 100644
--- a/hotspot/src/share/vm/opto/loopTransform.cpp
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp
@@ -1742,7 +1742,7 @@
               // The result of the reduction must not be used in the loop
               for (DUIterator_Fast imax, i = def_node->fast_outs(imax); i < imax && ok; i++) {
                 Node* u = def_node->fast_out(i);
-                if (has_ctrl(u) && !loop->is_member(get_loop(get_ctrl(u)))) {
+                if (!loop->is_member(get_loop(ctrl_or_self(u)))) {
                   continue;
                 }
                 if (u == phi) {
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index 369af1f..9bae43a 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -1952,7 +1952,7 @@
       i_o = pf_phi_abio;
    } else if( UseTLAB && AllocatePrefetchStyle == 3 ) {
       // Insert a prefetch instruction for each allocation.
-      // This code is used for SPARC with BIS.
+      // This code is used to generate 1 prefetch instruction per cache line.
 
       // Generate several prefetch instructions.
       uint lines = (length != NULL) ? AllocatePrefetchLines : AllocateInstancePrefetchLines;
@@ -1965,11 +1965,8 @@
       transform_later(cache_adr);
       cache_adr = new CastP2XNode(needgc_false, cache_adr);
       transform_later(cache_adr);
-      // For BIS instructions to be emitted, the address must be aligned at cache line size.
-      // (The VM sets AllocatePrefetchStepSize to the cache line size, unless a value is
-      // specified at the command line.) If the address is not aligned at cache line size
-      // boundary, a standard store instruction is triggered (instead of the BIS). For the
-      // latter, 8-byte alignment is necessary.
+      // Address is aligned to execute prefetch to the beginning of cache line size
+      // (it is important when BIS instruction is used on SPARC as prefetch).
       Node* mask = _igvn.MakeConX(~(intptr_t)(step_size-1));
       cache_adr = new AndXNode(cache_adr, mask);
       transform_later(cache_adr);
diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp
index 833b760..9b33688 100644
--- a/hotspot/src/share/vm/opto/node.cpp
+++ b/hotspot/src/share/vm/opto/node.cpp
@@ -1117,8 +1117,8 @@
   if (this->is_Store()) {
     // Condition for back-to-back stores folding.
     return n->Opcode() == op && n->in(MemNode::Memory) == this;
-  } else if (this->is_Load()) {
-    // Condition for removing an unused LoadNode from the MemBarAcquire precedence input
+  } else if (this->is_Load() || this->is_DecodeN()) {
+    // Condition for removing an unused LoadNode or DecodeNNode from the MemBarAcquire precedence input
     return n->Opcode() == Op_MemBarAcquire;
   } else if (op == Op_AddL) {
     // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp
index 2de400e..e016427 100644
--- a/hotspot/src/share/vm/opto/output.cpp
+++ b/hotspot/src/share/vm/opto/output.cpp
@@ -292,6 +292,10 @@
           if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
             stub_size  += CompiledStaticCall::to_interp_stub_size();
             reloc_size += CompiledStaticCall::reloc_to_interp_stub();
+#if INCLUDE_AOT
+            stub_size  += CompiledStaticCall::to_aot_stub_size();
+            reloc_size += CompiledStaticCall::reloc_to_aot_stub();
+#endif
           }
         } else if (mach->is_MachSafePoint()) {
           // If call/safepoint are adjacent, account for possible
diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp
index 81bd00e..6e92398 100644
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp
@@ -66,7 +66,6 @@
 # include "classfile/vmSymbols.hpp"
 # include "code/codeBlob.hpp"
 # include "code/codeCache.hpp"
-# include "code/codeCacheExtensions.hpp"
 # include "code/compressedStream.hpp"
 # include "code/debugInfo.hpp"
 # include "code/debugInfoRec.hpp"
diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml
index 28144da..0f39021 100644
--- a/hotspot/src/share/vm/prims/jvmti.xml
+++ b/hotspot/src/share/vm/prims/jvmti.xml
@@ -404,7 +404,7 @@
     interfaces are more appropriate than <jvmti/> for many tools. 
     For more information on the Java Platform Debugger Architecture, 
     see the 
-    <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/architecture.html">Java 
+    <externallink id="docs/technotes/guides/jpda/architecture.html">Java 
       Platform Debugger Architecture website</externallink>. 
   </intro>
 
@@ -764,7 +764,8 @@
     An agent creates a <jvmti/> environment 
     by passing a <jvmti/> version 
     as the interface ID to the JNI Invocation API function 
-    <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#GetEnv"><code>GetEnv</code></externallink>.
+    <externallink id="docs/technotes/guides/jni/spec/invocation.html#GetEnv">
+      <code>GetEnv</code></externallink>.
     See <internallink id="jvmtiEnvAccess">Accessing <jvmti/> Functions</internallink>
     for more details on the creation and use of 
     <jvmti/> environments.
@@ -883,7 +884,7 @@
     Modified UTF-8 differs 
     from standard UTF-8 in the representation of supplementary characters 
     and of the null character. See the
-    <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html#wp16542">
+    <externallink id="docs/technotes/guides/jni/spec/types.html#modified_utf_8_strings">
       Modified UTF-8 Strings</externallink>
     section of the JNI specification for details.
   </intro>
@@ -913,7 +914,7 @@
     by calling <jvmti/> functions. 
     Access to <jvmti/> functions is by use of an interface pointer
     in the same manner as 
-    <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html">Java 
+    <externallink id="docs/technotes/guides/jni/spec/design.html">Java 
       Native Interface (JNI) functions</externallink> are accessed.
     The <jvmti/> interface pointer is called the 
     <i>environment pointer</i>.
@@ -1005,7 +1006,8 @@
     local references--these local references are created 
     during the <jvmti/> call.
     Local references are a resource that must be managed (see the 
-    <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp18654">JNI Documentation</externallink>).  
+    <externallink id="docs/technotes/guides/jni/spec/functions.html#local_references">
+      JNI Documentation</externallink>).  
     When threads return from native code all local references
     are freed.  Note that some threads, including typical
     agent threads, will never return from native code.
@@ -1040,7 +1042,7 @@
       <jvmti/> function.
       See the
       <externallink 
-        id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp770"
+        id="docs/technotes/guides/jni/spec/design.html#java_exceptions"
              >Java Exceptions</externallink>
       section of the JNI specification for information on handling exceptions.
     </intro>
@@ -2105,8 +2107,8 @@
         <functionlink id="GetAllStackTraces"/>).
 	<p/>
 	Upon execution of <code>proc</code>, the new thread will be attached to the
-	VM--see the JNI documentation on 
-	<externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#wp1060"
+	VM -- see the JNI documentation on 
+	<externallink id="docs/technotes/guides/jni/spec/invocation.html#attaching_to_the_vm"
 		      >Attaching to the VM</externallink>.
       </description>
       <origin>jvmdiClone</origin>
@@ -3370,7 +3372,7 @@
 	  </constant>
 	  <constant id="JVMTI_HEAP_REFERENCE_SUPERCLASS" num="10">
             Reference from a class to its superclass. 
-            A callback is bot sent if the superclass is <code>java.lang.Object</code>.
+            A callback is not sent if the superclass is <code>java.lang.Object</code>.
             Note: loaded classes define superclasses via a constant pool
             reference, so the referenced superclass may also be reported with 
             a <code>JVMTI_HEAP_REFERENCE_CONSTANT_POOL</code> reference kind.
@@ -6869,7 +6871,7 @@
       <synopsis>Get Class Signature</synopsis>
       <description>
         For the class indicated by <code>klass</code>, return the 
-        <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html#wp16432">JNI 
+        <externallink id="docs/technotes/guides/jni/spec/types.html#type_signatures">JNI 
             type signature</externallink> 
         and the generic signature of the class.
         For example, <code>java.util.List</code> is <code>"Ljava/util/List;"</code>
@@ -7989,8 +7991,9 @@
 	return the field name via <paramlink id="name_ptr"/> and field signature via
 	<paramlink id="signature_ptr"/>.
 	<p/>
-        Field signatures are defined in the JNI Specification and 
-        are referred to as <code>field descriptors</code> in
+        Field signatures are defined in the
+        <externallink id="docs/technotes/guides/jni/spec/jniTOC.html">JNI Specification</externallink>
+        and are referred to as <code>field descriptors</code> in
         <vmspec chapter="4.3.2"/>.
       </description>
       <origin>jvmdiClone</origin>
@@ -8185,8 +8188,9 @@
 	return the method name via <code>name_ptr</code> and method signature via
 	<code>signature_ptr</code>.
         <p/>
-        Method signatures are defined in the JNI Specification and are 
-        referred to as <code>method descriptors</code> in 
+        Method signatures are defined in the
+        <externallink id="docs/technotes/guides/jni/spec/jniTOC.html">JNI Specification</externallink>
+        and are referred to as <code>method descriptors</code> in 
         <vmspec chapter="4.3.3"/>.
 	Note this is different
 	than method signatures as defined in the <i>Java Language Specification</i>.
@@ -9158,7 +9162,7 @@
       Provides the ability to intercept and resend 
       Java Native Interface (JNI) function calls
       by manipulating the JNI function table.
-      See <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html">JNI
+      See <externallink id="docs/technotes/guides/jni/spec/functions.html">JNI
 	Functions</externallink> in the <i>Java Native Interface Specification</i>.
       <p/>
       The following example illustrates intercepting the 
@@ -10859,7 +10863,7 @@
 	  for a class. The segment is typically a directory or JAR file.
 	  <p/>	  
 	  In the live phase the <paramlink id="segment"/> may be used to specify any platform-dependent
-	  path to a <externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html">
+	  path to a <externallink id="docs/technotes/guides/jar/jar.html">
 	  JAR file</externallink>. The agent should take care that the JAR file does not
           contain any classes or resources other than those to be defined by the bootstrap
           class loader for the purposes of instrumentation.
@@ -10906,8 +10910,8 @@
 	  search path segment to be searched after the system class loader unsuccessfully searches
 	  for a class. The segment is typically a directory or JAR file.
 	  <p/>	  
-	  In the live phase the <paramlink id="segment"/> is a platform-dependent path to a <externallink 
-	  id="http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html">JAR file</externallink> to be
+	  In the live phase the <paramlink id="segment"/> is a platform-dependent path to a
+	  <externallink id="docs/technotes/guides/jar/jar.html">JAR file</externallink> to be
 	  searched after the system class loader unsuccessfully searches for a class. The agent should
           take care that the JAR file does not contain any classes or resources other than those to be
           defined by the system class loader for the purposes of instrumentation.
@@ -13741,7 +13745,8 @@
       <description>
 	Typedef for the JNI function table <code>JNINativeInterface</code>
 	defined in the 
-	<externallink id="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp23720">JNI Specification</externallink>.
+	<externallink id="docs/technotes/guides/jni/spec/functions.html#interface_function_table">
+          JNI Specification</externallink>.
 	The JNI reference implementation defines this with an underscore.
       </description>
     </basetype>
diff --git a/hotspot/src/share/vm/prims/jvmti.xsl b/hotspot/src/share/vm/prims/jvmti.xsl
index 00a1551..be4db55 100644
--- a/hotspot/src/share/vm/prims/jvmti.xsl
+++ b/hotspot/src/share/vm/prims/jvmti.xsl
@@ -1033,6 +1033,10 @@
 <xsl:template match="externallink">
   <a>
     <xsl:attribute name="href">
+      <!-- All external links start from the same prefix -->
+      <xsl:text>http://docs.oracle.com/javase/</xsl:text>
+      <xsl:value-of select="//specification/@majorversion"/>
+      <xsl:text>/</xsl:text>
       <xsl:value-of select="@id"/>
     </xsl:attribute>
     <xsl:value-of select="."/>
diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp
index 6911039..1f56b22 100644
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp
@@ -746,6 +746,7 @@
   JvmtiThreadState *   _state;
   KlassHandle *        _h_class_being_redefined;
   JvmtiClassLoadKind   _load_kind;
+  bool                 _has_been_modified;
 
  public:
   inline JvmtiClassFileLoadHookPoster(Symbol* h_name, Handle class_loader,
@@ -762,6 +763,7 @@
     _curr_data = *data_ptr;
     _curr_env = NULL;
     _cached_class_file_ptr = cache_ptr;
+    _has_been_modified = false;
 
     _state = _thread->jvmti_thread_state();
     if (_state != NULL) {
@@ -800,6 +802,8 @@
     copy_modified_data();
   }
 
+  bool has_been_modified() { return _has_been_modified; }
+
  private:
   void post_all_envs() {
     if (_load_kind != jvmti_class_load_kind_retransform) {
@@ -846,6 +850,7 @@
     }
     if (new_data != NULL) {
       // this agent has modified class data.
+      _has_been_modified = true;
       if (caching_needed && *_cached_class_file_ptr == NULL) {
         // data has been changed by the new retransformable agent
         // and it hasn't already been cached, cache it
@@ -893,14 +898,14 @@
 bool JvmtiExport::_should_post_class_file_load_hook = false;
 
 // this entry is for class file load hook on class load, redefine and retransform
-void JvmtiExport::post_class_file_load_hook(Symbol* h_name,
+bool JvmtiExport::post_class_file_load_hook(Symbol* h_name,
                                             Handle class_loader,
                                             Handle h_protection_domain,
                                             unsigned char **data_ptr,
                                             unsigned char **end_ptr,
                                             JvmtiCachedClassFileData **cache_ptr) {
   if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
-    return;
+    return false;
   }
 
   JvmtiClassFileLoadHookPoster poster(h_name, class_loader,
@@ -908,6 +913,7 @@
                                       data_ptr, end_ptr,
                                       cache_ptr);
   poster.post();
+  return poster.has_been_modified();
 }
 
 void JvmtiExport::report_unsupported(bool on) {
diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp
index d280f21..8599656 100644
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp
@@ -341,10 +341,11 @@
     JVMTI_ONLY(return _should_post_class_file_load_hook);
     NOT_JVMTI(return false;)
   }
-  static void post_class_file_load_hook(Symbol* h_name, Handle class_loader,
+  // Return true if the class was modified by the hook.
+  static bool post_class_file_load_hook(Symbol* h_name, Handle class_loader,
                                         Handle h_protection_domain,
                                         unsigned char **data_ptr, unsigned char **end_ptr,
-                                        JvmtiCachedClassFileData **cache_ptr) NOT_JVMTI_RETURN;
+                                        JvmtiCachedClassFileData **cache_ptr) NOT_JVMTI_RETURN_(false);
   static void post_native_method_bind(Method* method, address* function_ptr) NOT_JVMTI_RETURN;
   static void post_compiled_method_load(nmethod *nm) NOT_JVMTI_RETURN;
   static void post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) NOT_JVMTI_RETURN;
diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
index 8a84d0e..c1f8dd7 100644
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/metadataOnStackMark.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -4011,8 +4012,18 @@
     scratch_class->enclosing_method_method_index());
   scratch_class->set_enclosing_method_indices(old_class_idx, old_method_idx);
 
+  // Replace fingerprint data
+  the_class->set_has_passed_fingerprint_check(scratch_class->has_passed_fingerprint_check());
+  the_class->store_fingerprint(scratch_class->get_stored_fingerprint());
+
   the_class->set_has_been_redefined();
 
+  if (!the_class->should_be_initialized()) {
+    // Class was already initialized, so AOT has only seen the original version.
+    // We need to let AOT look at it again.
+    AOTLoader::load_for_klass(the_class, THREAD);
+  }
+
   // keep track of previous versions of this class
   the_class->add_previous_version(scratch_class, emcp_method_count);
 
diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp
index d21c0fa..717c1fe 100644
--- a/hotspot/src/share/vm/prims/methodHandles.cpp
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp
@@ -26,7 +26,6 @@
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/stringTable.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/dependencyContext.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/interpreter.hpp"
@@ -94,7 +93,6 @@
     StubCodeMark mark(this, "MethodHandle::interpreter_entry", vmIntrinsics::name_at(iid));
     address entry = MethodHandles::generate_method_handle_interpreter_entry(_masm, iid);
     if (entry != NULL) {
-      CodeCacheExtensions::handle_generated_pc(entry, vmIntrinsics::name_at(iid));
       Interpreter::set_entry_for_kind(mk, entry);
     }
     // If the entry is not set, it will throw AbstractMethodError.
diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp
index ba4f6b8..0440fab 100644
--- a/hotspot/src/share/vm/prims/whitebox.cpp
+++ b/hotspot/src/share/vm/prims/whitebox.cpp
@@ -1172,6 +1172,9 @@
 
 int WhiteBox::get_blob_type(const CodeBlob* code) {
   guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
+  if (code->is_aot()) {
+    return -1;
+  }
   return CodeCache::get_code_heap(code)->code_blob_type();
 }
 
@@ -1227,7 +1230,8 @@
   if (code == NULL) {
     return result;
   }
-  int insts_size = code->insts_size();
+  int comp_level = code->comp_level();
+  int insts_size = comp_level == CompLevel_aot ? code->code_end() - code->code_begin() : code->insts_size();
 
   ThreadToNativeFromVM ttn(thread);
   jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
@@ -1242,7 +1246,7 @@
   CHECK_JNI_EXCEPTION_(env, NULL);
   env->SetObjectArrayElement(result, 0, codeBlob);
 
-  jobject level = integerBox(thread, env, code->comp_level());
+  jobject level = integerBox(thread, env, comp_level);
   CHECK_JNI_EXCEPTION_(env, NULL);
   env->SetObjectArrayElement(result, 1, level);
 
diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
index 9b8e3e6..e20f931 100644
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
+++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
@@ -24,7 +24,6 @@
 
 #include "precompiled.hpp"
 #include "code/codeCache.hpp"
-#include "compiler/compileTask.hpp"
 #include "runtime/advancedThresholdPolicy.hpp"
 #include "runtime/simpleThresholdPolicy.inline.hpp"
 #if INCLUDE_JVMCI
@@ -206,7 +205,6 @@
         if (PrintTieredEvents) {
           print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level());
         }
-        task->log_task_dequeued("stale");
         compile_queue->remove_and_mark_stale(task);
         method->clear_queued_for_compilation();
         task = next_task;
@@ -276,6 +274,10 @@
 // the threshold values double.
 bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) {
   switch(cur_level) {
+  case CompLevel_aot: {
+    double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+    return loop_predicate_helper<CompLevel_aot>(i, b, k, method);
+  }
   case CompLevel_none:
   case CompLevel_limited_profile: {
     double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
@@ -292,6 +294,10 @@
 
 bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) {
   switch(cur_level) {
+  case CompLevel_aot: {
+    double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
+    return call_predicate_helper<CompLevel_aot>(i, b, k, method);
+  }
   case CompLevel_none:
   case CompLevel_limited_profile: {
     double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback);
@@ -394,31 +400,49 @@
     next_level = CompLevel_simple;
   } else {
     switch(cur_level) {
+    case CompLevel_aot: {
+      // If we were at full profile level, would we switch to full opt?
+      if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
+        next_level = CompLevel_full_optimization;
+      } else if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+                               Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+                               (this->*p)(i, b, cur_level, method))) {
+        next_level = CompLevel_full_profile;
+      }
+    }
+    break;
     case CompLevel_none:
       // If we were at full profile level, would we switch to full opt?
       if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) {
         next_level = CompLevel_full_optimization;
       } else if ((this->*p)(i, b, cur_level, method)) {
 #if INCLUDE_JVMCI
-        if (UseJVMCICompiler) {
+        if (EnableJVMCI && UseJVMCICompiler) {
           // Since JVMCI takes a while to warm up, its queue inevitably backs up during
-          // early VM execution.
+          // early VM execution. As of 2014-06-13, JVMCI's inliner assumes that the root
+          // compilation method and all potential inlinees have mature profiles (which
+          // includes type profiling). If it sees immature profiles, JVMCI's inliner
+          // can perform pathologically bad (e.g., causing OutOfMemoryErrors due to
+          // exploring/inlining too many graphs). Since a rewrite of the inliner is
+          // in progress, we simply disable the dialing back heuristic for now and will
+          // revisit this decision once the new inliner is completed.
           next_level = CompLevel_full_profile;
-          break;
-        }
+        } else
 #endif
-        // C1-generated fully profiled code is about 30% slower than the limited profile
-        // code that has only invocation and backedge counters. The observation is that
-        // if C2 queue is large enough we can spend too much time in the fully profiled code
-        // while waiting for C2 to pick the method from the queue. To alleviate this problem
-        // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long
-        // we choose to compile a limited profiled version and then recompile with full profiling
-        // when the load on C2 goes down.
-        if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) >
-            Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
-          next_level = CompLevel_limited_profile;
-        } else {
-          next_level = CompLevel_full_profile;
+        {
+          // C1-generated fully profiled code is about 30% slower than the limited profile
+          // code that has only invocation and backedge counters. The observation is that
+          // if C2 queue is large enough we can spend too much time in the fully profiled code
+          // while waiting for C2 to pick the method from the queue. To alleviate this problem
+          // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long
+          // we choose to compile a limited profiled version and then recompile with full profiling
+          // when the load on C2 goes down.
+          if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) >
+              Tier3DelayOn * compiler_count(CompLevel_full_optimization)) {
+            next_level = CompLevel_limited_profile;
+          } else {
+            next_level = CompLevel_full_profile;
+          }
         }
       }
       break;
@@ -438,6 +462,13 @@
           } else {
             next_level = CompLevel_full_optimization;
           }
+        } else {
+          // If there is no MDO we need to profile
+          if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <=
+                                   Tier3DelayOff * compiler_count(CompLevel_full_optimization) &&
+                                   (this->*p)(i, b, cur_level, method))) {
+            next_level = CompLevel_full_profile;
+          }
         }
       }
       break;
@@ -514,15 +545,39 @@
   CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, thread);
 }
 
+bool AdvancedThresholdPolicy::maybe_switch_to_aot(methodHandle mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread) {
+  if (UseAOT && !delay_compilation_during_startup()) {
+    if (cur_level == CompLevel_full_profile || cur_level == CompLevel_none) {
+      // If the current level is full profile or interpreter and we're switching to any other level,
+      // activate the AOT code back first so that we won't waste time overprofiling.
+      compile(mh, InvocationEntryBci, CompLevel_aot, thread);
+      // Fall through for JIT compilation.
+    }
+    if (next_level == CompLevel_limited_profile && cur_level != CompLevel_aot && mh->has_aot_code()) {
+      // If the next level is limited profile, use the aot code (if there is any),
+      // since it's essentially the same thing.
+      compile(mh, InvocationEntryBci, CompLevel_aot, thread);
+      // Not need to JIT, we're done.
+      return true;
+    }
+  }
+  return false;
+}
+
+
 // Handle the invocation event.
 void AdvancedThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
                                                       CompLevel level, CompiledMethod* nm, JavaThread* thread) {
   if (should_create_mdo(mh(), level)) {
     create_mdo(mh, thread);
   }
-  if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
-    CompLevel next_level = call_event(mh(), level, thread);
-    if (next_level != level) {
+  CompLevel next_level = call_event(mh(), level, thread);
+  if (next_level != level) {
+    if (maybe_switch_to_aot(mh, level, next_level, thread)) {
+      // No JITting necessary
+      return;
+    }
+    if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
       compile(mh, InvocationEntryBci, next_level, thread);
     }
   }
@@ -552,46 +607,56 @@
     // enough calls.
     CompLevel cur_level, next_level;
     if (mh() != imh()) { // If there is an enclosing method
-      guarantee(nm != NULL, "Should have nmethod here");
-      cur_level = comp_level(mh());
-      next_level = call_event(mh(), cur_level, thread);
+      if (level == CompLevel_aot) {
+        // Recompile the enclosing method to prevent infinite OSRs. Stay at AOT level while it's compiling.
+        if (max_osr_level != CompLevel_none && !CompileBroker::compilation_is_in_queue(mh)) {
+          compile(mh, InvocationEntryBci, MIN2((CompLevel)TieredStopAtLevel, CompLevel_full_profile), thread);
+        }
+      } else {
+        // Current loop event level is not AOT
+        guarantee(nm != NULL, "Should have nmethod here");
+        cur_level = comp_level(mh());
+        next_level = call_event(mh(), cur_level, thread);
 
-      if (max_osr_level == CompLevel_full_optimization) {
-        // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts
-        bool make_not_entrant = false;
-        if (nm->is_osr_method()) {
-          // This is an osr method, just make it not entrant and recompile later if needed
-          make_not_entrant = true;
-        } else {
-          if (next_level != CompLevel_full_optimization) {
-            // next_level is not full opt, so we need to recompile the
-            // enclosing method without the inlinee
-            cur_level = CompLevel_none;
+        if (max_osr_level == CompLevel_full_optimization) {
+          // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts
+          bool make_not_entrant = false;
+          if (nm->is_osr_method()) {
+            // This is an osr method, just make it not entrant and recompile later if needed
             make_not_entrant = true;
+          } else {
+            if (next_level != CompLevel_full_optimization) {
+              // next_level is not full opt, so we need to recompile the
+              // enclosing method without the inlinee
+              cur_level = CompLevel_none;
+              make_not_entrant = true;
+            }
+          }
+          if (make_not_entrant) {
+            if (PrintTieredEvents) {
+              int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
+              print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level);
+            }
+            nm->make_not_entrant();
           }
         }
-        if (make_not_entrant) {
-          if (PrintTieredEvents) {
-            int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
-            print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level);
-          }
-          nm->make_not_entrant();
-        }
-      }
-      if (!CompileBroker::compilation_is_in_queue(mh)) {
         // Fix up next_level if necessary to avoid deopts
         if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) {
           next_level = CompLevel_full_profile;
         }
         if (cur_level != next_level) {
-          compile(mh, InvocationEntryBci, next_level, thread);
+          if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
+            compile(mh, InvocationEntryBci, next_level, thread);
+          }
         }
       }
     } else {
-      cur_level = comp_level(imh());
-      next_level = call_event(imh(), cur_level, thread);
-      if (!CompileBroker::compilation_is_in_queue(imh) && (next_level != cur_level)) {
-        compile(imh, InvocationEntryBci, next_level, thread);
+      cur_level = comp_level(mh());
+      next_level = call_event(mh(), cur_level, thread);
+      if (next_level != cur_level) {
+        if (!maybe_switch_to_aot(mh, cur_level, next_level, thread) && !CompileBroker::compilation_is_in_queue(mh)) {
+          compile(mh, InvocationEntryBci, next_level, thread);
+        }
       }
     }
   }
diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
index c96b5e7..8e3903b 100644
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
+++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
@@ -205,6 +205,8 @@
 
   double _increase_threshold_at_ratio;
 
+  bool maybe_switch_to_aot(methodHandle mh, CompLevel cur_level, CompLevel next_level, JavaThread* thread);
+
 protected:
   void print_specific(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level);
 
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index f9f1e23..f1e90f9 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -25,9 +25,9 @@
 #include "precompiled.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/javaAssertions.hpp"
+#include "classfile/moduleEntry.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
 #include "gc/shared/referenceProcessor.hpp"
@@ -378,6 +378,7 @@
   { "AutoGCSelectPauseMillis",      JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
   { "UseAutoGCSelectPolicy",        JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
   { "UseParNewGC",                  JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
+  { "ExplicitGCInvokesConcurrentAndUnloadsClasses", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
   { "ConvertSleepToYield",          JDK_Version::jdk(9), JDK_Version::jdk(10),     JDK_Version::jdk(11) },
   { "ConvertYieldToSleep",          JDK_Version::jdk(9), JDK_Version::jdk(10),     JDK_Version::jdk(11) },
 
@@ -1318,22 +1319,31 @@
 #if INCLUDE_CDS
 void Arguments::check_unsupported_dumping_properties() {
   assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
-  const char* unsupported_properties[5] = { "jdk.module.main",
+  const char* unsupported_properties[] = { "jdk.module.main",
+                                           "jdk.module.limitmods",
                                            "jdk.module.path",
                                            "jdk.module.upgrade.path",
-                                           "jdk.module.addmods.0",
-                                           "jdk.module.limitmods" };
-  const char* unsupported_options[5] = { "-m",
+                                           "jdk.module.addmods.0" };
+  const char* unsupported_options[] = { "-m",
+                                        "--limit-modules",
                                         "--module-path",
                                         "--upgrade-module-path",
-                                        "--add-modules",
-                                        "--limit-modules" };
+                                        "--add-modules" };
+  assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
+  // If a vm option is found in the unsupported_options array with index less than the warning_idx,
+  // vm will exit with an error message. Otherwise, it will result in a warning message.
+  uint warning_idx = 2;
   SystemProperty* sp = system_properties();
   while (sp != NULL) {
-    for (int i = 0; i < 5; i++) {
+    for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
       if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
+        if (i < warning_idx) {
           vm_exit_during_initialization(
             "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
+        } else {
+          warning(
+            "the %s option is ignored when dumping the shared archive", unsupported_options[i]);
+        }
       }
     }
     sp = sp->next();
@@ -1871,7 +1881,6 @@
 #endif // _LP64
 #endif // !ZERO
 
-  CodeCacheExtensions::set_ergonomics_flags();
 }
 
 void Arguments::set_parallel_gc_flags() {
@@ -2027,10 +2036,36 @@
 static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress;
 
 void Arguments::set_heap_size() {
-  const julong phys_mem =
+  julong phys_mem =
     FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
                             : (julong)MaxRAM;
 
+  // Experimental support for CGroup memory limits
+  if (UseCGroupMemoryLimitForHeap) {
+    // This is a rough indicator that a CGroup limit may be in force
+    // for this process
+    const char* lim_file = "/sys/fs/cgroup/memory/memory.limit_in_bytes";
+    FILE *fp = fopen(lim_file, "r");
+    if (fp != NULL) {
+      julong cgroup_max = 0;
+      int ret = fscanf(fp, JULONG_FORMAT, &cgroup_max);
+      if (ret == 1 && cgroup_max > 0) {
+        // If unlimited, cgroup_max will be a very large, but unspecified
+        // value, so use initial phys_mem as a limit
+        log_info(gc, heap)("Setting phys_mem to the min of cgroup limit ("
+                           JULONG_FORMAT "MB) and initial phys_mem ("
+                           JULONG_FORMAT "MB)", cgroup_max/M, phys_mem/M);
+        phys_mem = MIN2(cgroup_max, phys_mem);
+      } else {
+        warning("Unable to read/parse cgroup memory limit from %s: %s",
+                lim_file, errno != 0 ? strerror(errno) : "unknown error");
+      }
+      fclose(fp);
+    } else {
+      warning("Unable to open cgroup memory limit file %s (%s)", lim_file, strerror(errno));
+    }
+  }
+
   // If the maximum heap size has not been set with -Xmx,
   // then set it as fraction of the size of physical memory,
   // respecting the maximum and minimum sizes of the heap.
@@ -3425,9 +3460,9 @@
   // This check is only required for java.base, all other duplicate module specifications
   // will be checked during module system initialization.  The module system initialization
   // will throw an ExceptionInInitializerError if this situation occurs.
-  if (strcmp(module_name, "java.base") == 0) {
+  if (strcmp(module_name, JAVA_BASE_NAME) == 0) {
     if (*patch_mod_javabase) {
-      vm_exit_during_initialization("Cannot specify java.base more than once to --patch-module");
+      vm_exit_during_initialization("Cannot specify " JAVA_BASE_NAME " more than once to --patch-module");
     } else {
       *patch_mod_javabase = true;
     }
diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp
index dcfd0b9..ed11880 100644
--- a/hotspot/src/share/vm/runtime/frame.cpp
+++ b/hotspot/src/share/vm/runtime/frame.cpp
@@ -644,6 +644,7 @@
 //
 // First letter indicates type of the frame:
 //    J: Java frame (compiled)
+//    A: Java frame (aot compiled)
 //    j: Java frame (interpreted)
 //    V: VM frame (C/C++)
 //    v: Other frames running VM generated code (e.g. stubs, adapters, etc.)
@@ -664,8 +665,10 @@
         if (module->is_named()) {
           module->name()->as_C_string(buf, buflen);
           st->print(" %s", buf);
-          module->version()->as_C_string(buf, buflen);
-          st->print("@%s", buf);
+          if (module->version() != NULL) {
+            module->version()->as_C_string(buf, buflen);
+            st->print("@%s", buf);
+          }
         }
       } else {
         st->print("j  " PTR_FORMAT, p2i(pc()));
@@ -683,7 +686,9 @@
       CompiledMethod* cm = (CompiledMethod*)_cb;
       Method* m = cm->method();
       if (m != NULL) {
-        if (cm->is_nmethod()) {
+        if (cm->is_aot()) {
+          st->print("A %d ", cm->compile_id());
+        } else if (cm->is_nmethod()) {
           nmethod* nm = cm->as_nmethod();
           st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : ""));
           st->print(" %s", nm->compiler_name());
@@ -694,8 +699,10 @@
         if (module->is_named()) {
           module->name()->as_C_string(buf, buflen);
           st->print(" %s", buf);
-          module->version()->as_C_string(buf, buflen);
-          st->print("@%s", buf);
+          if (module->version() != NULL) {
+            module->version()->as_C_string(buf, buflen);
+            st->print("@%s", buf);
+          }
         }
         st->print(" (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]",
                   m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin());
@@ -1262,8 +1269,10 @@
     // For now just label the frame
     CompiledMethod* cm = (CompiledMethod*)cb();
     values.describe(-1, info_address,
-                    FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s", frame_no,
-                                       p2i(cm), cm->method()->name_and_sig_as_C_string(),
+                    FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s%s", frame_no,
+                                       p2i(cm),
+                                       (cm->is_aot() ? "A ": "J "),
+                                       cm->method()->name_and_sig_as_C_string(),
                                        (_deopt_state == is_deoptimized) ?
                                        " (deoptimized)" :
                                        ((_deopt_state == unknown) ? " (state unknown)" : "")),
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 3afe94f..90b274e 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -1988,7 +1988,7 @@
   experimental(uintx, WorkStealingSpinToYieldRatio, 10,                     \
           "Ratio of hard spins to calls to yield")                          \
                                                                             \
-  develop(uintx, ObjArrayMarkingStride, 512,                                \
+  develop(uintx, ObjArrayMarkingStride, 2048,                               \
           "Number of object array elements to push onto the marking stack " \
           "before pushing a continuation entry")                            \
                                                                             \
@@ -2037,6 +2037,10 @@
           "MaxRAM / MaxRAMFraction")                                        \
           range(0, max_uintx)                                               \
                                                                             \
+  experimental(bool, UseCGroupMemoryLimitForHeap, false,                    \
+          "Use CGroup memory limit as physical memory limit for heap "      \
+          "sizing")                                                         \
+                                                                            \
   product(uintx, MaxRAMFraction, 4,                                         \
           "Maximum fraction (1/n) of real memory used for maximum heap "    \
           "size")                                                           \
@@ -3387,6 +3391,22 @@
           "Non-segmented code cache: X[%] of the total code cache")         \
           range(0, 100)                                                     \
                                                                             \
+  /* AOT parameters */                                                      \
+  product(bool, UseAOT, AOT_ONLY(true) NOT_AOT(false),                      \
+          "Use AOT compiled files")                                         \
+                                                                            \
+  product(ccstrlist, AOTLibrary, NULL,                                      \
+          "AOT library")                                                    \
+                                                                            \
+  product(bool, PrintAOT, false,                                            \
+          "Print used AOT klasses and methods")                             \
+                                                                            \
+  notproduct(bool, PrintAOTStatistics, false,                               \
+          "Print AOT statistics")                                           \
+                                                                            \
+  diagnostic(bool, UseAOTStrictLoading, false,                              \
+          "Exit the VM if any of the AOT libraries has invalid config")     \
+                                                                            \
   /* interpreter debugging */                                               \
   develop(intx, BinarySwitchThreshold, 5,                                   \
           "Minimal number of lookupswitch entries for rewriting to binary " \
@@ -3659,6 +3679,25 @@
           "Back edge threshold at which tier 3 OSR compilation is invoked") \
           range(0, max_jint)                                                \
                                                                             \
+  product(intx, Tier3AOTInvocationThreshold, 10000,                         \
+          "Compile if number of method invocations crosses this "           \
+          "threshold if coming from AOT")                                   \
+          range(0, max_jint)                                                \
+                                                                            \
+  product(intx, Tier3AOTMinInvocationThreshold, 1000,                       \
+          "Minimum invocation to compile at tier 3 if coming from AOT")     \
+          range(0, max_jint)                                                \
+                                                                            \
+  product(intx, Tier3AOTCompileThreshold, 15000,                            \
+          "Threshold at which tier 3 compilation is invoked (invocation "   \
+          "minimum must be satisfied) if coming from AOT")                  \
+          range(0, max_jint)                                                \
+                                                                            \
+  product(intx, Tier3AOTBackEdgeThreshold,  120000,                         \
+          "Back edge threshold at which tier 3 OSR compilation is invoked " \
+          "if coming from AOT")                                             \
+          range(0, max_jint)                                                \
+                                                                            \
   product(intx, Tier4InvocationThreshold, 5000,                             \
           "Compile if number of method invocations crosses this "           \
           "threshold")                                                      \
diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp
index 939dae7..4450d2c 100644
--- a/hotspot/src/share/vm/runtime/init.cpp
+++ b/hotspot/src/share/vm/runtime/init.cpp
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/icBuffer.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "interpreter/bytecodes.hpp"
@@ -105,20 +104,15 @@
   classLoader_init1();
   compilationPolicy_init();
   codeCache_init();
-  CodeCacheExtensions::initialize();
   VM_Version_init();
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::VMVersion);
   os_init_globals();
   stubRoutines_init1();
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines1);
   jint status = universe_init();  // dependent on codeCache_init and
                                   // stubRoutines_init1 and metaspace_init.
   if (status != JNI_OK)
     return status;
 
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::Universe);
   interpreter_init();  // before any methods loaded
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::Interpreter);
   invocationCounter_init();  // before any methods loaded
   marksweep_init();
   accessFlags_init();
@@ -148,7 +142,6 @@
   javaClasses_init();   // must happen after vtable initialization
   stubRoutines_init2(); // note: StubRoutines need 2-phase init
   MethodHandles::generate_adapters();
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines2);
 
 #if INCLUDE_NMT
   // Solaris stack is walkable only after stubRoutines are set up.
@@ -162,7 +155,6 @@
     CommandLineFlags::printFlags(tty, false, PrintFlagsRanges);
   }
 
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::InitGlobals);
   return JNI_OK;
 }
 
diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp
index b854623..0c7187c 100644
--- a/hotspot/src/share/vm/runtime/java.cpp
+++ b/hotspot/src/share/vm/runtime/java.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -280,6 +281,10 @@
 #endif
 #endif
 
+  if (PrintAOTStatistics) {
+    AOTLoader::print_statistics();
+  }
+
   if (PrintNMethodStatistics) {
     nmethod::print_statistics();
   }
diff --git a/hotspot/src/share/vm/runtime/semaphore.cpp b/hotspot/src/share/vm/runtime/semaphore.cpp
deleted file mode 100644
index 2fedafb..0000000
--- a/hotspot/src/share/vm/runtime/semaphore.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "utilities/debug.hpp"
-#include "runtime/semaphore.hpp"
-
-/////////////// Unit tests ///////////////
-
-#ifndef PRODUCT
-
-static void test_semaphore_single_separate(uint count) {
-  Semaphore sem(0);
-
-  for (uint i = 0; i < count; i++) {
-    sem.signal();
-  }
-
-  for (uint i = 0; i < count; i++) {
-    sem.wait();
-  }
-}
-
-static void test_semaphore_single_combined(uint count) {
-  Semaphore sem(0);
-
-  for (uint i = 0; i < count; i++) {
-    sem.signal();
-    sem.wait();
-  }
-}
-
-static void test_semaphore_many(uint value, uint max, uint increments) {
-  Semaphore sem(value);
-
-  uint total = value;
-
-  for (uint i = value; i + increments <= max; i += increments) {
-    sem.signal(increments);
-
-    total += increments;
-  }
-
-  for (uint i = 0; i < total; i++) {
-    sem.wait();
-  }
-}
-
-static void test_semaphore_many() {
-  for (uint max = 0; max < 10; max++) {
-    for (uint value = 0; value < max; value++) {
-      for (uint inc = 1; inc <= max - value; inc++) {
-        test_semaphore_many(value, max, inc);
-      }
-    }
-  }
-}
-
-void test_semaphore() {
-  for (uint i = 1; i < 10; i++) {
-    test_semaphore_single_separate(i);
-  }
-
-  for (uint i = 0; i < 10; i++) {
-    test_semaphore_single_combined(i);
-  }
-
-  test_semaphore_many();
-}
-
-#endif // PRODUCT
-
diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp
index 8a14881..c854e4a 100644
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp
@@ -23,12 +23,12 @@
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
 #include "code/compiledIC.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/scopeDesc.hpp"
 #include "code/vtableStubs.hpp"
 #include "compiler/abstractCompiler.hpp"
@@ -55,6 +55,7 @@
 #include "runtime/handles.inline.hpp"
 #include "runtime/init.hpp"
 #include "runtime/interfaceSupport.hpp"
+#include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
@@ -78,6 +79,7 @@
 RuntimeStub*        SharedRuntime::_resolve_opt_virtual_call_blob;
 RuntimeStub*        SharedRuntime::_resolve_virtual_call_blob;
 RuntimeStub*        SharedRuntime::_resolve_static_call_blob;
+address             SharedRuntime::_resolve_static_call_entry;
 
 DeoptimizationBlob* SharedRuntime::_deopt_blob;
 SafepointBlob*      SharedRuntime::_polling_page_vectors_safepoint_handler_blob;
@@ -97,6 +99,7 @@
   _resolve_opt_virtual_call_blob       = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C),   "resolve_opt_virtual_call");
   _resolve_virtual_call_blob           = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),       "resolve_virtual_call");
   _resolve_static_call_blob            = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),        "resolve_static_call");
+  _resolve_static_call_entry           = _resolve_static_call_blob->entry_point();
 
 #if defined(COMPILER2) || INCLUDE_JVMCI
   // Vectors are generated only by C2 and JVMCI.
@@ -475,7 +478,7 @@
   // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear
   // and other exception handler continuations do not read it
   thread->set_exception_pc(NULL);
-#endif
+#endif // INCLUDE_JVMCI
 
   // The fastest case first
   CodeBlob* blob = CodeCache::find_blob(return_address);
@@ -503,6 +506,13 @@
     }
   }
 
+#if INCLUDE_AOT
+  if (UseAOT && blob->is_aot()) {
+    // AOT Compiled code
+    return AOTLoader::exception_begin(thread, blob, return_address);
+  }
+#endif
+
   // Entry code
   if (StubRoutines::returns_to_call_stub(return_address)) {
     return StubRoutines::catch_exception_entry();
@@ -988,17 +998,12 @@
 }
 
 JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj))
-  assert(obj->is_oop(), "must be a valid oop");
 #if INCLUDE_JVMCI
-  // This removes the requirement for JVMCI compilers to emit code
-  // performing a dynamic check that obj has a finalizer before
-  // calling this routine. There should be no performance impact
-  // for C1 since it emits a dynamic check. C2 and the interpreter
-  // uses other runtime routines for registering finalizers.
   if (!obj->klass()->has_finalizer()) {
     return;
   }
 #endif // INCLUDE_JVMCI
+  assert(obj->is_oop(), "must be a valid oop");
   assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
   InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
 JRT_END
@@ -1225,7 +1230,6 @@
     assert(fr.is_entry_frame(), "must be");
     // fr is now pointing to the entry frame.
     callee_method = methodHandle(THREAD, fr.entry_frame_call_wrapper()->callee_method());
-    assert(fr.entry_frame_call_wrapper()->receiver() == NULL || !callee_method->is_static(), "non-null receiver for static call??");
   } else {
     Bytecodes::Code bc;
     CallInfo callinfo;
@@ -1354,16 +1358,18 @@
   address dest_entry_point = callee == NULL ? 0 : callee->entry_point(); // used below
 #endif
 
+  bool is_nmethod = caller_nm->is_nmethod();
+
   if (is_virtual) {
     assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check");
     bool static_bound = call_info.resolved_method()->can_be_statically_bound();
     KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass());
     CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
-                     is_optimized, static_bound, virtual_call_info,
+                     is_optimized, static_bound, is_nmethod, virtual_call_info,
                      CHECK_(methodHandle()));
   } else {
     // static call
-    CompiledStaticCall::compute_entry(callee_method, static_call_info);
+    CompiledStaticCall::compute_entry(callee_method, is_nmethod, static_call_info);
   }
 
   // grab lock, check for deoptimization and potentially patch caller
@@ -1394,7 +1400,7 @@
           inline_cache->set_to_monomorphic(virtual_call_info);
         }
       } else {
-        CompiledStaticCall* ssc = compiledStaticCall_before(caller_frame.pc());
+        CompiledStaticCall* ssc = caller_nm->compiledStaticCall_before(caller_frame.pc());
         if (ssc->is_clean()) ssc->set(static_call_info);
       }
     }
@@ -1510,6 +1516,7 @@
 JRT_END
 
 
+
 methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
   ResourceMark rm(thread);
   CallInfo call_info;
@@ -1622,7 +1629,7 @@
         inline_cache->compute_monomorphic_entry(callee_method,
                                                 receiver_klass,
                                                 inline_cache->is_optimized(),
-                                                false,
+                                                false, caller_nm->is_nmethod(),
                                                 info, CHECK_(methodHandle()));
         inline_cache->set_to_monomorphic(info);
       } else if (!inline_cache->is_megamorphic() && !inline_cache->is_clean()) {
@@ -1691,10 +1698,7 @@
       // busy patching it.
       MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
       // Location of call instruction
-      if (NativeCall::is_call_before(pc)) {
-        NativeCall *ncall = nativeCall_before(pc);
-        call_addr = ncall->instruction_address();
-      }
+      call_addr = caller_nm->call_instruction_address(pc);
     }
     // Make sure nmethod doesn't get deoptimized and removed until
     // this is done with it.
@@ -1724,9 +1728,10 @@
       // to a wrong method). It should not be performance critical, since the
       // resolve is only done once.
 
+      bool is_nmethod = caller_nm->is_nmethod();
       MutexLocker ml(CompiledIC_lock);
       if (is_static_call) {
-        CompiledStaticCall* ssc= compiledStaticCall_at(call_addr);
+        CompiledStaticCall* ssc = caller_nm->compiledStaticCall_at(call_addr);
         ssc->set_to_clean();
       } else {
         // compiled, dispatched call (which used to call an interpreted method)
@@ -1793,6 +1798,37 @@
 }
 #endif
 
+bool SharedRuntime::should_fixup_call_destination(address destination, address entry_point, address caller_pc, Method* moop, CodeBlob* cb) {
+  if (destination != entry_point) {
+    CodeBlob* callee = CodeCache::find_blob(destination);
+    // callee == cb seems weird. It means calling interpreter thru stub.
+    if (callee == cb || callee->is_adapter_blob()) {
+      // static call or optimized virtual
+      if (TraceCallFixup) {
+        tty->print("fixup callsite           at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
+        moop->print_short_name(tty);
+        tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
+      }
+      return true;
+    } else {
+      if (TraceCallFixup) {
+        tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
+        moop->print_short_name(tty);
+        tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
+      }
+      // assert is too strong could also be resolve destinations.
+      // assert(InlineCacheBuffer::contains(destination) || VtableStubs::contains(destination), "must be");
+    }
+  } else {
+    if (TraceCallFixup) {
+      tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
+      moop->print_short_name(tty);
+      tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
+    }
+  }
+  return false;
+}
+
 // ---------------------------------------------------------------------------
 // We are calling the interpreter via a c2i. Normally this would mean that
 // we were called by a compiled method. However we could have lost a race
@@ -1842,7 +1878,8 @@
     // Expect to find a native call there (unless it was no-inline cache vtable dispatch)
     MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
     if (NativeCall::is_call_before(return_pc)) {
-      NativeCall *call = nativeCall_before(return_pc);
+      ResourceMark mark;
+      NativeCallWrapper* call = nm->call_wrapper_before(return_pc);
       //
       // bug 6281185. We might get here after resolving a call site to a vanilla
       // virtual call. Because the resolvee uses the verified entry it may then
@@ -1863,32 +1900,8 @@
         return;
       }
       address destination = call->destination();
-      if (destination != entry_point) {
-        CodeBlob* callee = CodeCache::find_blob(destination);
-        // callee == cb seems weird. It means calling interpreter thru stub.
-        if (callee == cb || callee->is_adapter_blob()) {
-          // static call or optimized virtual
-          if (TraceCallFixup) {
-            tty->print("fixup callsite           at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
-            moop->print_short_name(tty);
-            tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
-          }
-          call->set_destination_mt_safe(entry_point);
-        } else {
-          if (TraceCallFixup) {
-            tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
-            moop->print_short_name(tty);
-            tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
-          }
-          // assert is too strong could also be resolve destinations.
-          // assert(InlineCacheBuffer::contains(destination) || VtableStubs::contains(destination), "must be");
-        }
-      } else {
-          if (TraceCallFixup) {
-            tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc));
-            moop->print_short_name(tty);
-            tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point));
-          }
+      if (should_fixup_call_destination(destination, entry_point, caller_pc, moop, cb)) {
+        call->set_destination_mt_safe(entry_point);
       }
     }
   }
@@ -1933,44 +1946,103 @@
   return generate_class_cast_message(caster_klass, target_klass);
 }
 
+// The caller of class_loader_and_module_name() (or one of its callers)
+// must use a ResourceMark in order to correctly free the result.
+const char* class_loader_and_module_name(Klass* klass) {
+  const char* delim = "/";
+  size_t delim_len = strlen(delim);
+
+  const char* fqn = klass->external_name();
+  // Length of message to return; always include FQN
+  size_t msglen = strlen(fqn) + 1;
+
+  bool has_cl_name = false;
+  bool has_mod_name = false;
+  bool has_version = false;
+
+  // Use class loader name, if exists and not builtin
+  const char* class_loader_name = "";
+  ClassLoaderData* cld = klass->class_loader_data();
+  assert(cld != NULL, "class_loader_data should not be NULL");
+  if (!cld->is_builtin_class_loader_data()) {
+    // If not builtin, look for name
+    oop loader = klass->class_loader();
+    if (loader != NULL) {
+      oop class_loader_name_oop = java_lang_ClassLoader::name(loader);
+      if (class_loader_name_oop != NULL) {
+        class_loader_name = java_lang_String::as_utf8_string(class_loader_name_oop);
+        if (class_loader_name != NULL && class_loader_name[0] != '\0') {
+          has_cl_name = true;
+          msglen += strlen(class_loader_name) + delim_len;
+        }
+      }
+    }
+  }
+
+  const char* module_name = "";
+  const char* version = "";
+  Klass* bottom_klass = klass->is_objArray_klass() ?
+    ObjArrayKlass::cast(klass)->bottom_klass() : klass;
+  if (bottom_klass->is_instance_klass()) {
+    ModuleEntry* module = InstanceKlass::cast(bottom_klass)->module();
+    // Use module name, if exists
+    if (module->is_named()) {
+      has_mod_name = true;
+      module_name = module->name()->as_C_string();
+      msglen += strlen(module_name);
+      // Use version if exists and is not a jdk module
+      if (module->is_non_jdk_module() && module->version() != NULL) {
+        has_version = true;
+        version = module->version()->as_C_string();
+        msglen += strlen("@") + strlen(version);
+      }
+    }
+  } else {
+    // klass is an array of primitives, so its module is java.base
+    module_name = JAVA_BASE_NAME;
+  }
+
+  if (has_cl_name || has_mod_name) {
+    msglen += delim_len;
+  }
+
+  char* message = NEW_RESOURCE_ARRAY_RETURN_NULL(char, msglen);
+
+  // Just return the FQN if error in allocating string
+  if (message == NULL) {
+    return fqn;
+  }
+
+  jio_snprintf(message, msglen, "%s%s%s%s%s%s%s",
+               class_loader_name,
+               (has_cl_name) ? delim : "",
+               (has_mod_name) ? module_name : "",
+               (has_version) ? "@" : "",
+               (has_version) ? version : "",
+               (has_cl_name || has_mod_name) ? delim : "",
+               fqn);
+  return message;
+}
+
 char* SharedRuntime::generate_class_cast_message(
     Klass* caster_klass, Klass* target_klass) {
 
-  const char* caster_klass_name = caster_klass->external_name();
-  Klass* c_klass = caster_klass->is_objArray_klass() ?
-    ObjArrayKlass::cast(caster_klass)->bottom_klass() : caster_klass;
-  ModuleEntry* caster_module;
-  const char* caster_module_name;
-  if (c_klass->is_instance_klass()) {
-    caster_module = InstanceKlass::cast(c_klass)->module();
-    caster_module_name = caster_module->is_named() ?
-      caster_module->name()->as_C_string() : UNNAMED_MODULE;
-  } else {
-    caster_module_name = "java.base";
-  }
-  const char* target_klass_name = target_klass->external_name();
-  Klass* t_klass = target_klass->is_objArray_klass() ?
-    ObjArrayKlass::cast(target_klass)->bottom_klass() : target_klass;
-  ModuleEntry* target_module;
-  const char* target_module_name;
-  if (t_klass->is_instance_klass()) {
-    target_module = InstanceKlass::cast(t_klass)->module();
-    target_module_name = target_module->is_named() ?
-      target_module->name()->as_C_string(): UNNAMED_MODULE;
-  } else {
-    target_module_name = "java.base";
-  }
+  const char* caster_name = class_loader_and_module_name(caster_klass);
 
-  size_t msglen = strlen(caster_klass_name) + strlen(caster_module_name) +
-     strlen(target_klass_name) + strlen(target_module_name) + 50;
+  const char* target_name = class_loader_and_module_name(target_klass);
 
-  char* message = NEW_RESOURCE_ARRAY(char, msglen);
-  if (NULL == message) {
+  size_t msglen = strlen(caster_name) + strlen(" cannot be cast to ") + strlen(target_name) + 1;
+
+  char* message = NEW_RESOURCE_ARRAY_RETURN_NULL(char, msglen);
+  if (message == NULL) {
     // Shouldn't happen, but don't cause even more problems if it does
-    message = const_cast<char*>(caster_klass_name);
+    message = const_cast<char*>(caster_klass->external_name());
   } else {
-    jio_snprintf(message, msglen, "%s (in module: %s) cannot be cast to %s (in module: %s)",
-      caster_klass_name, caster_module_name, target_klass_name, target_module_name);
+    jio_snprintf(message,
+                 msglen,
+                 "%s cannot be cast to %s",
+                 caster_name,
+                 target_name);
   }
   return message;
 }
@@ -2507,27 +2579,15 @@
   if (_adapters != NULL) return;
   _adapters = new AdapterHandlerTable();
 
-  if (!CodeCacheExtensions::skip_compiler_support()) {
-    // Create a special handler for abstract methods.  Abstract methods
-    // are never compiled so an i2c entry is somewhat meaningless, but
-    // throw AbstractMethodError just in case.
-    // Pass wrong_method_abstract for the c2i transitions to return
-    // AbstractMethodError for invalid invocations.
-    address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
-    _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
-                                                                StubRoutines::throw_AbstractMethodError_entry(),
-                                                                wrong_method_abstract, wrong_method_abstract);
-  } else {
-    // Adapters are not supposed to be used.
-    // Generate a special one to cause an error if used (and store this
-    // singleton in place of the useless _abstract_method_error adapter).
-    address entry = (address) &unexpected_adapter_call;
-    _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
-                                                                entry,
-                                                                entry,
-                                                                entry);
-
-  }
+  // Create a special handler for abstract methods.  Abstract methods
+  // are never compiled so an i2c entry is somewhat meaningless, but
+  // throw AbstractMethodError just in case.
+  // Pass wrong_method_abstract for the c2i transitions to return
+  // AbstractMethodError for invalid invocations.
+  address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
+  _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
+                                                              StubRoutines::throw_AbstractMethodError_entry(),
+                                                              wrong_method_abstract, wrong_method_abstract);
 }
 
 AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
@@ -2540,6 +2600,7 @@
 AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
   AdapterHandlerEntry* entry = get_adapter0(method);
   if (method->is_shared()) {
+    // See comments around Method::link_method()
     MutexLocker mu(AdapterHandlerLibrary_lock);
     if (method->adapter() == NULL) {
       method->update_adapter_trampoline(entry);
@@ -2549,6 +2610,7 @@
       CodeBuffer buffer(trampoline, (int)SharedRuntime::trampoline_size());
       MacroAssembler _masm(&buffer);
       SharedRuntime::generate_trampoline(&_masm, entry->get_c2i_entry());
+      assert(*(int*)trampoline != 0, "Instruction(s) for trampoline must not be encoded as zeros.");
 
       if (PrintInterpreter) {
         Disassembler::decode(buffer.insts_begin(), buffer.insts_end());
@@ -2576,17 +2638,6 @@
     // make sure data structure is initialized
     initialize();
 
-    // during dump time, always generate adapters, even if the
-    // compiler has been turned off.
-    if (!DumpSharedSpaces && CodeCacheExtensions::skip_compiler_support()) {
-      // adapters are useless and should not be used, including the
-      // abstract_method_handler. However, some callers check that
-      // an adapter was installed.
-      // Return the singleton adapter, stored into _abstract_method_handler
-      // and modified to cause an error if we ever call it.
-      return _abstract_method_handler;
-    }
-
     if (method->is_abstract()) {
       return _abstract_method_handler;
     }
diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp
index d938217..852f095 100644
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp
@@ -60,6 +60,7 @@
   static RuntimeStub*        _resolve_opt_virtual_call_blob;
   static RuntimeStub*        _resolve_virtual_call_blob;
   static RuntimeStub*        _resolve_static_call_blob;
+  static address             _resolve_static_call_entry;
 
   static DeoptimizationBlob* _deopt_blob;
 
@@ -676,6 +677,9 @@
   void print_adapter_on(outputStream* st) const;
 };
 
+// This class is used only with DumpSharedSpaces==true. It holds extra information
+// that's used only during CDS dump time.
+// For details, see comments around Method::link_method()
 class CDSAdapterHandlerEntry: public AdapterHandlerEntry {
   address               _c2i_entry_trampoline;   // allocated from shared spaces "MC" region
   AdapterHandlerEntry** _adapter_trampoline;     // allocated from shared spaces "MD" region
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
index 4f53212..4dc4656 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
@@ -33,6 +33,7 @@
 #include "jvmci/jvmciRuntime.hpp"
 #endif
 
+#ifdef TIERED
 
 void SimpleThresholdPolicy::print_counters(const char* prefix, methodHandle mh) {
   int invocation_count = mh->invocation_count();
@@ -242,6 +243,23 @@
   if (level == CompLevel_none) {
     return;
   }
+  if (level == CompLevel_aot) {
+    if (mh->has_aot_code()) {
+      if (PrintTieredEvents) {
+        print_event(COMPILE, mh, mh, bci, level);
+      }
+      MutexLocker ml(Compile_lock);
+      NoSafepointVerifier nsv;
+      if (mh->has_aot_code() && mh->code() != mh->aot_code()) {
+        mh->aot_code()->make_entrant();
+        if (mh->has_compiled_code()) {
+          mh->code()->make_not_entrant();
+        }
+        Method::set_code(mh, mh->aot_code());
+      }
+    }
+    return;
+  }
 
   // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling
   // in the interpreter and then compile with C2 (the transition function will request that,
@@ -275,6 +293,9 @@
 // are passed to common() transition function).
 bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) {
   switch(cur_level) {
+  case CompLevel_aot: {
+    return loop_predicate_helper<CompLevel_aot>(i, b, 1.0, method);
+  }
   case CompLevel_none:
   case CompLevel_limited_profile: {
     return loop_predicate_helper<CompLevel_none>(i, b, 1.0, method);
@@ -289,6 +310,9 @@
 
 bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) {
   switch(cur_level) {
+  case CompLevel_aot: {
+    return call_predicate_helper<CompLevel_aot>(i, b, 1.0, method);
+  }
   case CompLevel_none:
   case CompLevel_limited_profile: {
     return call_predicate_helper<CompLevel_none>(i, b, 1.0, method);
@@ -321,10 +345,16 @@
   int i = method->invocation_count();
   int b = method->backedge_count();
 
-  if (is_trivial(method)) {
+  if (is_trivial(method) && cur_level != CompLevel_aot) {
     next_level = CompLevel_simple;
   } else {
     switch(cur_level) {
+    case CompLevel_aot: {
+      if ((this->*p)(i, b, cur_level, method)) {
+        next_level = CompLevel_full_profile;
+      }
+    }
+    break;
     case CompLevel_none:
       // If we were at full profile level, would we switch to full opt?
       if (common(p, method, CompLevel_full_profile) == CompLevel_full_optimization) {
@@ -438,3 +468,5 @@
     }
   }
 }
+
+#endif
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
index 9960c14..e67175e 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
@@ -30,6 +30,8 @@
 #include "runtime/compilationPolicy.hpp"
 #include "utilities/globalDefinitions.hpp"
 
+#ifdef TIERED
+
 class CompileTask;
 class CompileQueue;
 
@@ -118,4 +120,6 @@
   }
 };
 
+#endif // TIERED
+
 #endif // SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_HPP
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
index fc7b2d72..cbec987 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
@@ -27,6 +27,8 @@
 
 #include "compiler/compilerOracle.hpp"
 
+#ifdef TIERED
+
 template<CompLevel level>
 bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) {
   double threshold_scaling;
@@ -34,6 +36,9 @@
     scale *= threshold_scaling;
   }
   switch(level) {
+  case CompLevel_aot:
+    return (i >= Tier3AOTInvocationThreshold * scale) ||
+           (i >= Tier3AOTMinInvocationThreshold * scale && i + b >= Tier3AOTCompileThreshold * scale);
   case CompLevel_none:
   case CompLevel_limited_profile:
     return (i >= Tier3InvocationThreshold * scale) ||
@@ -52,6 +57,8 @@
     scale *= threshold_scaling;
   }
   switch(level) {
+  case CompLevel_aot:
+    return b >= Tier3AOTBackEdgeThreshold * scale;
   case CompLevel_none:
   case CompLevel_limited_profile:
     return b >= Tier3BackEdgeThreshold * scale;
@@ -87,4 +94,6 @@
   return false;
 }
 
+#endif // TIERED
+
 #endif // SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP
diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp
index db44029..c36c7b8 100644
--- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp
+++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp
@@ -26,7 +26,6 @@
 #include "asm/macroAssembler.hpp"
 #include "asm/macroAssembler.inline.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "compiler/disassembler.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/forte.hpp"
diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp
index 12e0e3a..a7683f2 100644
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp
@@ -24,7 +24,6 @@
 
 #include "precompiled.hpp"
 #include "asm/codeBuffer.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/interfaceSupport.hpp"
@@ -204,12 +203,6 @@
 
 // simple tests of generated arraycopy functions
 static void test_arraycopy_func(address func, int alignment) {
-  if (CodeCacheExtensions::use_pregenerated_interpreter() || !CodeCacheExtensions::is_executable(func)) {
-    // Exit safely if stubs were generated but cannot be used.
-    // Also excluding pregenerated interpreter since the code may depend on
-    // some registers being properly initialized (for instance Rthread)
-    return;
-  }
   int v = 0xcc;
   int v2 = 0x11;
   jlong lbuffer[8];
diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp
index 60fc91c..8dad912 100644
--- a/hotspot/src/share/vm/runtime/sweeper.cpp
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp
@@ -213,6 +213,8 @@
   if (_current.method() != NULL) {
     if (_current.method()->is_nmethod()) {
       assert(CodeCache::find_blob_unsafe(_current.method()) == _current.method(), "Sweeper nmethod cached state invalid");
+    } else if (_current.method()->is_aot()) {
+      assert(CodeCache::find_blob_unsafe(_current.method()->code_begin()) == _current.method(), "Sweeper AOT method cached state invalid");
     } else {
       ShouldNotReachHere();
     }
@@ -570,7 +572,7 @@
     RelocIterator iter(nm);
     while (iter.next()) {
       if (iter.type() == relocInfo::virtual_call_type) {
-        CompiledIC::cleanup_call_site(iter.virtual_call_reloc());
+        CompiledIC::cleanup_call_site(iter.virtual_call_reloc(), nm);
       }
     }
   }
diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp
index 24e2242..abdcab5 100644
--- a/hotspot/src/share/vm/runtime/thread.cpp
+++ b/hotspot/src/share/vm/runtime/thread.cpp
@@ -29,7 +29,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "code/scopeDesc.hpp"
 #include "compiler/compileBroker.hpp"
 #include "compiler/compileTask.hpp"
@@ -3842,8 +3841,6 @@
     }
   }
 
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::CreateVM);
-
   create_vm_timer.end();
 #ifdef ASSERT
   _vm_complete = true;
diff --git a/hotspot/src/share/vm/runtime/vframe_hp.cpp b/hotspot/src/share/vm/runtime/vframe_hp.cpp
index 168deb0..30b08a0 100644
--- a/hotspot/src/share/vm/runtime/vframe_hp.cpp
+++ b/hotspot/src/share/vm/runtime/vframe_hp.cpp
@@ -198,7 +198,7 @@
   if (scope() == NULL) {
     CompiledMethod* nm = code();
     Method* method = nm->method();
-    assert(method->is_native(), "");
+    assert(method->is_native() || nm->is_aot(), "Expect a native method or precompiled method");
     if (!method->is_synchronized()) {
       return new GrowableArray<MonitorInfo*>(0);
     }
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index 514da11..c9ac7e9 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -2537,6 +2537,24 @@
   declare_constant(InstanceKlass::fully_initialized)                      \
   declare_constant(InstanceKlass::initialization_error)                   \
                                                                           \
+  /***************************************/                               \
+  /* InstanceKlass enums for _misc_flags */                               \
+  /***************************************/                               \
+                                                                          \
+  declare_constant(InstanceKlass::_misc_rewritten)                        \
+  declare_constant(InstanceKlass::_misc_has_nonstatic_fields)             \
+  declare_constant(InstanceKlass::_misc_should_verify_class)              \
+  declare_constant(InstanceKlass::_misc_is_anonymous)                     \
+  declare_constant(InstanceKlass::_misc_is_contended)                     \
+  declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods)   \
+  declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods)\
+  declare_constant(InstanceKlass::_misc_has_been_redefined)               \
+  declare_constant(InstanceKlass::_misc_has_passed_fingerprint_check)     \
+  declare_constant(InstanceKlass::_misc_is_scratch_class)                 \
+  declare_constant(InstanceKlass::_misc_is_shared_boot_class)             \
+  declare_constant(InstanceKlass::_misc_is_shared_platform_class)         \
+  declare_constant(InstanceKlass::_misc_is_shared_app_class)              \
+                                                                          \
   /*********************************/                                     \
   /* Symbol* - symbol max length */                                       \
   /*********************************/                                     \
@@ -2685,6 +2703,7 @@
   declare_constant(CompLevel_limited_profile)                             \
   declare_constant(CompLevel_full_profile)                                \
   declare_constant(CompLevel_full_optimization)                           \
+  declare_constant(CompLevel_aot)                                         \
                                                                           \
   /***************/                                                       \
   /* OopMapValue */                                                       \
diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp
index 26a8cbe..1481f72 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp
@@ -26,7 +26,6 @@
 #include "classfile/symbolTable.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc/shared/isGCActiveMark.hpp"
 #include "logging/log.hpp"
@@ -390,7 +389,6 @@
 Thread * VM_Exit::_shutdown_thread = NULL;
 
 int VM_Exit::set_vm_exited() {
-  CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::LastStep);
 
   Thread * thr_cur = Thread::current();
 
diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp
index 08e15dc..7d7dcc4 100644
--- a/hotspot/src/share/vm/runtime/vm_version.cpp
+++ b/hotspot/src/share/vm/runtime/vm_version.cpp
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "code/codeCacheExtensions.hpp"
 #include "logging/log.hpp"
 #include "memory/universe.hpp"
 #include "oops/oop.inline.hpp"
@@ -127,14 +126,23 @@
 
 
 const char* Abstract_VM_Version::vm_info_string() {
-  if (CodeCacheExtensions::use_pregenerated_interpreter()) {
-    return "interpreted mode, pregenerated";
-  }
   switch (Arguments::mode()) {
     case Arguments::_int:
       return UseSharedSpaces ? "interpreted mode, sharing" : "interpreted mode";
     case Arguments::_mixed:
-      return UseSharedSpaces ? "mixed mode, sharing"       :  "mixed mode";
+      if (UseSharedSpaces) {
+          if (UseAOT) {
+            return "mixed mode, aot, sharing";
+          } else {
+            return "mixed mode, sharing";
+          }
+      } else {
+        if (UseAOT) {
+          return "mixed mode, aot";
+        } else {
+          return "mixed mode";
+        }
+      }
     case Arguments::_comp:
       return UseSharedSpaces ? "compiled mode, sharing"    : "compiled mode";
   };
diff --git a/hotspot/src/share/vm/services/nmtCommon.hpp b/hotspot/src/share/vm/services/nmtCommon.hpp
index f057484..2864ff2 100644
--- a/hotspot/src/share/vm/services/nmtCommon.hpp
+++ b/hotspot/src/share/vm/services/nmtCommon.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,9 @@
  public:
   // Map memory type to index
   static inline int flag_to_index(MEMFLAGS flag) {
-    return (flag & 0xff);
+    const int index = flag & 0xff;
+    assert(index >= 0 && index < (int)mt_number_of_types, "Index out of bounds");
+    return index;
   }
 
   // Map memory type to human readable name
@@ -65,6 +67,7 @@
 
   // Map an index to memory type
   static MEMFLAGS index_to_flag(int index) {
+    assert(index >= 0 && index < (int) mt_number_of_types, "Index out of bounds");
     return (MEMFLAGS)index;
   }
 
diff --git a/hotspot/src/share/vm/trace/traceEventClasses.xsl b/hotspot/src/share/vm/trace/traceEventClasses.xsl
index 16b30c7..0bd5619 100644
--- a/hotspot/src/share/vm/trace/traceEventClasses.xsl
+++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl
@@ -119,7 +119,7 @@
 <xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-fields"/>
 
   void writeEventContent(void) {
-    TraceStream ts(*tty);
+    TraceStream ts;
     ts.print("<xsl:value-of select="@label"/>: [");
 <xsl:apply-templates select="value|structvalue" mode="write-data"/>
     ts.print("]\n");
diff --git a/hotspot/src/share/vm/trace/traceMacros.hpp b/hotspot/src/share/vm/trace/traceMacros.hpp
index f325dd8..3284988 100644
--- a/hotspot/src/share/vm/trace/traceMacros.hpp
+++ b/hotspot/src/share/vm/trace/traceMacros.hpp
@@ -31,13 +31,9 @@
 #define EVENT_THREAD_DESTRUCT(thread)
 #define TRACE_KLASS_CREATION(k, p, t)
 
-#define TRACE_INIT_KLASS_ID(k)
-#define TRACE_REMOVE_KLASS_ID(k)
-#define TRACE_RESTORE_KLASS_ID(k)
-
-#define TRACE_INIT_MODULE_ID(m)
-#define TRACE_INIT_PACKAGE_ID(p)
-#define TRACE_INIT_THREAD_ID(td)
+#define TRACE_INIT_ID(k)
+#define TRACE_REMOVE_ID(k)
+#define TRACE_RESTORE_ID(k)
 #define TRACE_DATA TraceThreadData
 
 #define THREAD_TRACE_ID(thread) ((traceid)thread->osthread()->thread_id())
diff --git a/hotspot/src/share/vm/trace/traceStream.cpp b/hotspot/src/share/vm/trace/traceStream.cpp
new file mode 100644
index 0000000..70291c0
--- /dev/null
+++ b/hotspot/src/share/vm/trace/traceStream.cpp
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code 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 General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "trace/traceStream.hpp"
+#if INCLUDE_TRACE
+#include "classfile/classLoaderData.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "oops/symbol.hpp"
+
+void TraceStream::print_val(const char* label, const Klass* val) const {
+  ResourceMark rm;
+  const char* description = "NULL";
+  if (val != NULL) {
+    const Symbol* name = val->name();
+    if (name != NULL) {
+      description = name->as_C_string();
+    }
+  }
+  tty->print("%s = %s", label, description);
+}
+
+void TraceStream::print_val(const char* label, const Method* val) const {
+  ResourceMark rm;
+  const char* description = "NULL";
+  if (val != NULL) {
+    description = val->name_and_sig_as_C_string();
+  }
+  tty->print("%s = %s", label, description);
+}
+
+void TraceStream::print_val(const char* label, const ClassLoaderData* cld) const {
+  ResourceMark rm;
+  if (cld == NULL || cld->is_anonymous()) {
+    tty->print("%s = NULL", label);
+    return;
+  }
+  const char* class_loader_name = "NULL";
+  const char* class_loader_type_name = "NULL";
+  const oop class_loader_oop = cld->class_loader();
+
+  if (class_loader_oop != NULL) {
+    const Klass* k = class_loader_oop->klass();
+    assert(k != NULL, "invariant");
+    const Symbol* klass_name_sym = k->name();
+    if (klass_name_sym != NULL) {
+      class_loader_type_name = klass_name_sym->as_C_string();
+    }
+    const oop class_loader_name_oop =
+      java_lang_ClassLoader::name(class_loader_oop);
+    if (class_loader_name_oop != NULL) {
+      const char* class_loader_name_from_oop =
+        java_lang_String::as_utf8_string(class_loader_name_oop);
+      if (class_loader_name_from_oop != NULL &&
+            class_loader_name_from_oop[0] != '\0') {
+        class_loader_name = class_loader_name_from_oop;
+      }
+    }
+  } else {
+    assert(class_loader_oop == NULL, "invariant");
+    // anonymous CLDs are excluded, this would be the boot loader
+    class_loader_name = "boot";
+  }
+  tty->print("%s = name=%s class=%s", label, class_loader_name, class_loader_type_name);
+}
+
+#endif // INCLUDE_TRACE
diff --git a/hotspot/src/share/vm/trace/traceStream.hpp b/hotspot/src/share/vm/trace/traceStream.hpp
index 405e462..be04043 100644
--- a/hotspot/src/share/vm/trace/traceStream.hpp
+++ b/hotspot/src/share/vm/trace/traceStream.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,87 +27,71 @@
 
 #include "utilities/macros.hpp"
 #if INCLUDE_TRACE
-#include "memory/resourceArea.hpp"
-#include "oops/klass.hpp"
-#include "oops/method.hpp"
-#include "oops/symbol.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
 #include "utilities/ostream.hpp"
 
+class ClassLoaderData;
+class Klass;
+class Method;
+
 class TraceStream : public StackObj {
- private:
-  outputStream& _st;
-
  public:
-  TraceStream(outputStream& stream): _st(stream) {}
-
-  void print_val(const char* label, u1 val) {
-    _st.print("%s = " UINT32_FORMAT, label, val);
+  TraceStream() {
+    assert(tty != NULL, "invariant");
   }
 
-  void print_val(const char* label, u2 val) {
-    _st.print("%s = " UINT32_FORMAT, label, val);
+  void print(const char* val) const {
+    tty->print("%s", val);
   }
 
-  void print_val(const char* label, s2 val) {
-    _st.print("%s = " INT32_FORMAT, label, val);
+  void print_val(const char* label, u1 val) const {
+    tty->print("%s = " UINT32_FORMAT, label, val);
   }
 
-  void print_val(const char* label, u4 val) {
-    _st.print("%s = " UINT32_FORMAT, label, val);
+  void print_val(const char* label, u2 val) const {
+    tty->print("%s = " UINT32_FORMAT, label, val);
   }
 
-  void print_val(const char* label, s4 val) {
-    _st.print("%s = " INT32_FORMAT, label, val);
+  void print_val(const char* label, s2 val) const {
+    tty->print("%s = " INT32_FORMAT, label, val);
   }
 
-  void print_val(const char* label, u8 val) {
-    _st.print("%s = " UINT64_FORMAT, label, val);
+  void print_val(const char* label, u4 val) const {
+    tty->print("%s = " UINT32_FORMAT, label, val);
   }
 
-  void print_val(const char* label, s8 val) {
-    _st.print("%s = " INT64_FORMAT, label, (int64_t) val);
+  void print_val(const char* label, s4 val) const {
+    tty->print("%s = " INT32_FORMAT, label, val);
   }
 
-  void print_val(const char* label, bool val) {
-    _st.print("%s = %s", label, val ? "true" : "false");
+  void print_val(const char* label, u8 val) const {
+    tty->print("%s = " UINT64_FORMAT, label, val);
   }
 
-  void print_val(const char* label, float val) {
-    _st.print("%s = %f", label, val);
+  void print_val(const char* label, s8 val) const {
+    tty->print("%s = " INT64_FORMAT, label, (int64_t) val);
   }
 
-  void print_val(const char* label, double val) {
-    _st.print("%s = %f", label, val);
+  void print_val(const char* label, bool val) const {
+    tty->print("%s = %s", label, val ? "true" : "false");
   }
 
-  void print_val(const char* label, const Klass* const val) {
-    ResourceMark rm;
-    const char* description = "NULL";
-    if (val != NULL) {
-      Symbol* name = val->name();
-      if (name != NULL) {
-        description = name->as_C_string();
-      }
-    }
-    _st.print("%s = %s", label, description);
+  void print_val(const char* label, float val) const {
+    tty->print("%s = %f", label, val);
   }
 
-  void print_val(const char* label, const Method* const val) {
-    ResourceMark rm;
-    const char* description = "NULL";
-    if (val != NULL) {
-      description = val->name_and_sig_as_C_string();
-    }
-    _st.print("%s = %s", label, description);
+  void print_val(const char* label, double val) const {
+    tty->print("%s = %f", label, val);
   }
 
-  void print_val(const char* label, const char* val) {
-    _st.print("%s = '%s'", label, val);
+  void print_val(const char* label, const char* val) const {
+    tty->print("%s = '%s'", label, val);
   }
 
-  void print(const char* val) {
-    _st.print("%s", val);
-  }
+  void print_val(const char* label, const Klass* val) const;
+  void print_val(const char* label, const Method* val) const ;
+  void print_val(const char* label, const ClassLoaderData* cld) const;
 };
 
 #endif // INCLUDE_TRACE
diff --git a/hotspot/src/share/vm/trace/traceevents.xml b/hotspot/src/share/vm/trace/traceevents.xml
index c2a5fe7..10be0bc 100644
--- a/hotspot/src/share/vm/trace/traceevents.xml
+++ b/hotspot/src/share/vm/trace/traceevents.xml
@@ -113,20 +113,20 @@
   <event id="ClassLoad" path="vm/class/load" label="Class Load"
          has_thread="true" has_stacktrace="true" is_instant="false">
     <value type="CLASS" field="loadedClass" label="Loaded Class"/>
-    <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
-    <value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
+    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
+    <value type="CLASSLOADER" field="initiatingClassLoader" label="Initiating Class Loader"/>
   </event>
 
   <event id="ClassDefine" path="vm/class/define" label="Class Define"
          has_thread="true" has_stacktrace="true" is_instant="true">
     <value type="CLASS" field="definedClass" label="Defined Class"/>
-    <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
   </event>
 
   <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
          has_thread="true" is_instant="true">
     <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
-    <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+    <value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
   </event>
 
   <event id="IntFlagChanged" path="vm/flag/int_changed" label="Int Flag Changed"
@@ -229,7 +229,7 @@
   </event>
 
   <event id="MetaspaceAllocationFailure" path="vm/gc/metaspace/allocation_failure" label="Metaspace Allocation Failure" is_instant="true" has_stacktrace="true">
-    <value type="CLASS" field="classLoader" label="Class Loader" />
+    <value type="CLASSLOADER" field="classLoader" label="Class Loader" />
     <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
     <value type="BYTES64" field="size" label="Size" />
     <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
@@ -237,7 +237,7 @@
   </event>
 
   <event id="MetaspaceOOM" path="vm/gc/metaspace/out_of_memory" label="Metaspace Out of Memory" is_instant="true" has_stacktrace="true">
-    <value type="CLASS" field="classLoader" label="Class Loader" />
+    <value type="CLASSLOADER" field="classLoader" label="Class Loader" />
     <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
     <value type="BYTES64" field="size" label="Size" />
     <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
diff --git a/hotspot/src/share/vm/trace/tracetypes.xml b/hotspot/src/share/vm/trace/tracetypes.xml
index 003b901..8670045 100644
--- a/hotspot/src/share/vm/trace/tracetypes.xml
+++ b/hotspot/src/share/vm/trace/tracetypes.xml
@@ -68,21 +68,27 @@
       <value type="THREADGROUP" field="group" label="Java Thread Group"/>
     </content_type>
 
-    <content_type id="ThreadGroup" hr_name="Thread group"
+    <content_type id="ThreadGroup" hr_name="Thread Group"
                   type="U8" jvm_type="THREADGROUP">
       <value type="THREADGROUP" field="parent" label="Parent"/>
       <value type="STRING" field="name" label="Name"/>
     </content_type>
 
-    <content_type id="Class" hr_name="Java class"
+    <content_type id="Class" hr_name="Java Class"
                   type="U8" builtin_type="CLASS">
-      <value type="CLASS" field="classLoaderType" label="Class Loader"/>
+      <value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
       <value type="SYMBOL" field="name" label="Name"/>
       <value type="PACKAGE" field="package" label="Package"/>
       <value type="INTEGER" field="modifiers" label="Access Modifiers"/>
     </content_type>
 
-    <content_type id="Method" hr_name="Java method"
+    <content_type id="ClassLoader" hr_name="Java Class Loader"
+                  type="U8" jvm_type="CLASSLOADER">
+      <value type="CLASS" field="type" label="Type"/>
+      <value type="SYMBOL" field="name" label="Name"/>
+    </content_type>
+
+    <content_type id="Method" hr_name="Java Method"
                   type="U8" jvm_type="METHOD">
       <value type="CLASS" field="type" label="Type"/>
       <value type="SYMBOL" field="name" label="Name"/>
@@ -126,7 +132,7 @@
       <value type="STRING" field="type" label="Type" />
     </content_type>
 
-    <content_type id="GCThresholdUpdater" hr_name="GC Treshold Updater"
+    <content_type id="GCThresholdUpdater" hr_name="GC Threshold Updater"
                   type="U8" jvm_type="GCTHRESHOLDUPDATER">
       <value type="STRING" field="updater" label="Updater" />
     </content_type>
@@ -146,7 +152,7 @@
       <value type="STRING" field="type" label="Type" />
     </content_type>
 
-    <content_type id="NarrowOopMode" hr_name="Narrow oop Mode"
+    <content_type id="NarrowOopMode" hr_name="Narrow Oop Mode"
                   type="U8" jvm_type="NARROWOOPMODE">
       <value type="STRING" field="mode" label="Mode" />
     </content_type>
@@ -181,7 +187,7 @@
       <value type="SYMBOL" field="name" label="Name"/>
       <value type="SYMBOL" field="version" label="Version"/>
       <value type="SYMBOL" field="location" label="Location"/>
-      <value type="CLASS" field="classLoader" label="Class Loader"/>
+      <value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
     </content_type>
 
     <content_type id="Package" hr_name="Package"
@@ -303,6 +309,9 @@
     <primary_type symbol="CLASS" datatype="U8" contenttype="CLASS"
                   type="const Klass*" sizeop="sizeof(u8)"/>
 
+    <primary_type symbol="CLASSLOADER" datatype="U8" contenttype="CLASSLOADER"
+              type="const ClassLoaderData*" sizeop="sizeof(u8)"/>
+
     <primary_type symbol="MODULE" datatype="U8" contenttype="MODULE"
                   type="const ModuleEntry*" sizeop="sizeof(u8)"/>
 
diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp
index b0b7d56..19a54cc 100644
--- a/hotspot/src/share/vm/utilities/bitMap.cpp
+++ b/hotspot/src/share/vm/utilities/bitMap.cpp
@@ -680,118 +680,4 @@
   tty->cr();
 }
 
-class TestBitMap : public AllStatic {
-  const static BitMap::idx_t BITMAP_SIZE = 1024;
-
-  template <class ResizableBitMapClass>
-  static void fillBitMap(ResizableBitMapClass& map) {
-    map.set_bit(1);
-    map.set_bit(3);
-    map.set_bit(17);
-    map.set_bit(512);
-  }
-
-  template <class ResizableBitMapClass>
-  static void testResize(BitMap::idx_t start_size) {
-    ResourceMark rm;
-
-    ResizableBitMapClass map(start_size);
-    map.resize(BITMAP_SIZE);
-    fillBitMap(map);
-
-    ResizableBitMapClass map2(BITMAP_SIZE);
-    fillBitMap(map2);
-    assert(map.is_same(map2), "could be");
-  }
-
-  template <class ResizableBitMapClass>
-  static void testResizeGrow() {
-    testResize<ResizableBitMapClass>(0);
-    testResize<ResizableBitMapClass>(128);
-  }
-
-  template <class ResizableBitMapClass>
-  static void testResizeSame() {
-    testResize<ResizableBitMapClass>(BITMAP_SIZE);
-  }
-
-  template <class ResizableBitMapClass>
-  static void testResizeShrink() {
-    testResize<ResizableBitMapClass>(BITMAP_SIZE * 2);
-  }
-
-  static void testResizeGrow() {
-    testResizeGrow<ResourceBitMap>();
-    testResizeGrow<CHeapBitMap>();
-  }
-
-  static void testResizeSame() {
-    testResizeSame<ResourceBitMap>();
-    testResizeSame<CHeapBitMap>();
-  }
-
-  static void testResizeShrink() {
-    testResizeShrink<ResourceBitMap>();
-    testResizeShrink<CHeapBitMap>();
-  }
-
-  static void testResize() {
-    testResizeGrow();
-    testResizeSame();
-    testResizeShrink();
-  }
-
-  template <class InitializableBitMapClass>
-  static void testInitialize() {
-    ResourceMark rm;
-
-    InitializableBitMapClass map;
-    map.initialize(BITMAP_SIZE);
-    fillBitMap(map);
-
-    InitializableBitMapClass map2(BITMAP_SIZE);
-    fillBitMap(map2);
-    assert(map.is_same(map2), "could be");
-  }
-
-  static void testInitialize() {
-    testInitialize<ResourceBitMap>();
-    testInitialize<CHeapBitMap>();
-  }
-
-  template <class ReinitializableBitMapClass>
-  static void testReinitialize(BitMap::idx_t init_size) {
-    ResourceMark rm;
-
-    ReinitializableBitMapClass map(init_size);
-    map.reinitialize(BITMAP_SIZE);
-    fillBitMap(map);
-
-    ReinitializableBitMapClass map2(BITMAP_SIZE);
-    fillBitMap(map2);
-    assert(map.is_same(map2), "could be");
-  }
-
-  template <class ReinitializableBitMapClass>
-  static void testReinitialize() {
-    testReinitialize<ReinitializableBitMapClass>(0);
-    testReinitialize<ReinitializableBitMapClass>(128);
-    testReinitialize<ReinitializableBitMapClass>(BITMAP_SIZE);
-  }
-
-  static void testReinitialize() {
-    testReinitialize<ResourceBitMap>();
-  }
-
- public:
-  static void test() {
-    testResize();
-    testInitialize();
-    testReinitialize();
-  }
-};
-
-void TestBitMap_test() {
-  TestBitMap::test();
-}
 #endif
diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp
index 919a54c..cc08eab 100644
--- a/hotspot/src/share/vm/utilities/bitMap.hpp
+++ b/hotspot/src/share/vm/utilities/bitMap.hpp
@@ -312,7 +312,6 @@
 
 // A BitMap with storage in a ResourceArea.
 class ResourceBitMap : public BitMap {
-  friend class TestBitMap;
 
  public:
   ResourceBitMap() : BitMap(NULL, 0) {}
@@ -351,7 +350,6 @@
 
 // A BitMap with storage in the CHeap.
 class CHeapBitMap : public BitMap {
-  friend class TestBitMap;
 
  private:
   // Don't allow copy or assignment, to prevent the
diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp
index a6fd15b..27c568b 100644
--- a/hotspot/src/share/vm/utilities/debug.cpp
+++ b/hotspot/src/share/vm/utilities/debug.cpp
@@ -771,7 +771,7 @@
 
   // see if it's a valid frame
   if (fr.pc()) {
-    st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
+    st->print_cr("Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)");
 
     int count = 0;
     while (count++ < StackPrintLimit) {
diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.cpp b/hotspot/src/share/vm/utilities/globalDefinitions.cpp
index b718c78..3de8a9e 100644
--- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp
@@ -368,93 +368,3 @@
 
 STATIC_ASSERT(left_n_bits(3)   == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000));
 STATIC_ASSERT(left_n_bits(1|2) == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000));
-
-
-#ifndef PRODUCT
-// For unit testing only
-class TestGlobalDefinitions {
-private:
-
-  static void test_clamp_address_in_page() {
-    intptr_t page_sizes[] = { os::vm_page_size(), 4096, 8192, 65536, 2*1024*1024 };
-    const int num_page_sizes = sizeof(page_sizes) / sizeof(page_sizes[0]);
-
-    for (int i = 0; i < num_page_sizes; i++) {
-      intptr_t page_size = page_sizes[i];
-
-      address a_page = (address)(10*page_size);
-
-      // Check that address within page is returned as is
-      assert(clamp_address_in_page(a_page, a_page, page_size) == a_page, "incorrect");
-      assert(clamp_address_in_page(a_page + 128, a_page, page_size) == a_page + 128, "incorrect");
-      assert(clamp_address_in_page(a_page + page_size - 1, a_page, page_size) == a_page + page_size - 1, "incorrect");
-
-      // Check that address above page returns start of next page
-      assert(clamp_address_in_page(a_page + page_size, a_page, page_size) == a_page + page_size, "incorrect");
-      assert(clamp_address_in_page(a_page + page_size + 1, a_page, page_size) == a_page + page_size, "incorrect");
-      assert(clamp_address_in_page(a_page + page_size*5 + 1, a_page, page_size) == a_page + page_size, "incorrect");
-
-      // Check that address below page returns start of page
-      assert(clamp_address_in_page(a_page - 1, a_page, page_size) == a_page, "incorrect");
-      assert(clamp_address_in_page(a_page - 2*page_size - 1, a_page, page_size) == a_page, "incorrect");
-      assert(clamp_address_in_page(a_page - 5*page_size - 1, a_page, page_size) == a_page, "incorrect");
-    }
-  }
-
-  static void test_exact_unit_for_byte_size() {
-    assert(strcmp(exact_unit_for_byte_size(0),     "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(1),     "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(K - 1), "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(K),     "K") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(K + 1), "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(M - 1), "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(M),     "M") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(M + 1), "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(M + K), "K") == 0, "incorrect");
-#ifdef LP64
-    assert(strcmp(exact_unit_for_byte_size(G - 1),     "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(G),         "G") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(G + 1),     "B") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(G + K),     "K") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(G + M),     "M") == 0, "incorrect");
-    assert(strcmp(exact_unit_for_byte_size(G + M + K), "K") == 0, "incorrect");
-#endif
-  }
-
-  static void test_byte_size_in_exact_unit() {
-    assert(byte_size_in_exact_unit(0)     == 0,     "incorrect");
-    assert(byte_size_in_exact_unit(1)     == 1,     "incorrect");
-    assert(byte_size_in_exact_unit(K - 1) == K - 1, "incorrect");
-    assert(byte_size_in_exact_unit(K)     == 1,     "incorrect");
-    assert(byte_size_in_exact_unit(K + 1) == K + 1, "incorrect");
-    assert(byte_size_in_exact_unit(M - 1) == M - 1, "incorrect");
-    assert(byte_size_in_exact_unit(M)     == 1,     "incorrect");
-    assert(byte_size_in_exact_unit(M + 1) == M + 1, "incorrect");
-    assert(byte_size_in_exact_unit(M + K) == K + 1, "incorrect");
-#ifdef LP64
-    assert(byte_size_in_exact_unit(G - 1)     == G - 1,     "incorrect");
-    assert(byte_size_in_exact_unit(G)         == 1,         "incorrect");
-    assert(byte_size_in_exact_unit(G + 1)     == G + 1,     "incorrect");
-    assert(byte_size_in_exact_unit(G + K)     == M + 1,     "incorrect");
-    assert(byte_size_in_exact_unit(G + M)     == K + 1,     "incorrect");
-    assert(byte_size_in_exact_unit(G + M + K) == M + K + 1, "incorrect");
-#endif
-  }
-
-  static void test_exact_units() {
-    test_exact_unit_for_byte_size();
-    test_byte_size_in_exact_unit();
-  }
-
-public:
-  static void test() {
-    test_clamp_address_in_page();
-    test_exact_units();
-  }
-};
-
-void TestGlobalDefinitions_test() {
-  TestGlobalDefinitions::test();
-}
-
-#endif // PRODUCT
diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp
index abe5ace..17169c9 100644
--- a/hotspot/src/share/vm/utilities/growableArray.hpp
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp
@@ -503,6 +503,7 @@
   }
 
  public:
+  GrowableArrayIterator() : _array(NULL), _position(0) { }
   GrowableArrayIterator<E>& operator++()  { ++_position; return *this; }
   E operator*()                           { return _array->at(_position); }
 
diff --git a/hotspot/src/share/vm/utilities/internalVMTests.cpp b/hotspot/src/share/vm/utilities/internalVMTests.cpp
index 3ce4167..eae11ff 100644
--- a/hotspot/src/share/vm/utilities/internalVMTests.cpp
+++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp
@@ -41,25 +41,17 @@
 
 void InternalVMTests::run() {
   tty->print_cr("Running internal VM tests");
-  run_unit_test(test_semaphore);
   run_unit_test(TestReservedSpace_test);
   run_unit_test(TestReserveMemorySpecial_test);
   run_unit_test(TestVirtualSpace_test);
   run_unit_test(TestMetaspaceAux_test);
   run_unit_test(TestVirtualSpaceNode_test);
-  run_unit_test(TestGlobalDefinitions_test);
   run_unit_test(GCTimer_test);
-  run_unit_test(CollectedHeap_test);
-  run_unit_test(TestBitMap_test);
   run_unit_test(ObjectMonitor_test);
   run_unit_test(DirectivesParser_test);
 #if INCLUDE_VM_STRUCTS
   run_unit_test(VMStructs_test);
 #endif
-#if INCLUDE_ALL_GCS
-  run_unit_test(TestBufferingOopClosure_test);
-  run_unit_test(ParallelCompact_test);
-#endif
   tty->print_cr("All internal VM tests passed");
 }
 
diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp
index aa46c07..f24e4ff 100644
--- a/hotspot/src/share/vm/utilities/macros.hpp
+++ b/hotspot/src/share/vm/utilities/macros.hpp
@@ -180,6 +180,14 @@
 #define INCLUDE_JVMCI 1
 #endif
 
+#ifdef INCLUDE_AOT
+# if INCLUDE_AOT && !(INCLUDE_JVMCI)
+#   error "Must have JVMCI for AOT"
+# endif
+#else
+# define INCLUDE_AOT 0
+#endif
+
 #if INCLUDE_JVMCI
 #define JVMCI_ONLY(code) code
 #define NOT_JVMCI(code)
@@ -190,6 +198,16 @@
 #define NOT_JVMCI_RETURN {}
 #endif // INCLUDE_JVMCI
 
+#if INCLUDE_AOT
+#define AOT_ONLY(code) code
+#define NOT_AOT(code)
+#define NOT_AOT_RETURN /* next token must be ; */
+#else
+#define AOT_ONLY(code)
+#define NOT_AOT(code) code
+#define NOT_AOT_RETURN {}
+#endif // INCLUDE_AOT
+
 // COMPILER1 variant
 #ifdef COMPILER1
 #ifdef COMPILER2
diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile
index e37f990..49527c4 100644
--- a/hotspot/test/Makefile
+++ b/hotspot/test/Makefile
@@ -118,13 +118,8 @@
 # Set up the directory in which the jvm directories live (client/, server/, etc.)
 ifeq ($(PLATFORM),windows)
 JVMS_DIR := $(PRODUCT_HOME)/bin
-else ifeq ($(PLATFORM),bsd)
-JVMS_DIR := $(PRODUCT_HOME)/lib
 else
-# The jvms live in the architecture directory (amd64, sparcv9,
-# etc.). By using a wildcard there's no need to figure out the exact
-# name of that directory.
-JVMS_DIR := $(PRODUCT_HOME)/lib/*
+JVMS_DIR := $(PRODUCT_HOME)/lib
 endif
 
 # Use the existance of a directory as a sign that jvm variant is available
diff --git a/hotspot/test/ProblemList.txt b/hotspot/test/ProblemList.txt
new file mode 100644
index 0000000..6088cb3
--- /dev/null
+++ b/hotspot/test/ProblemList.txt
@@ -0,0 +1,83 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#############################################################################
+#
+# List of quarantined tests -- tests that should not be run by default, because
+# they may fail due to known reason. The reason (CR#) must be mandatory specified.
+#
+# List items are testnames followed by labels, all MUST BE commented
+#   as to why they are here and use a label:
+#     generic-all   Problems on all platforms
+#     generic-ARCH  Where ARCH is one of: sparc, sparcv9, x64, i586, etc.
+#     OSNAME-all    Where OSNAME is one of: solaris, linux, windows, macosx, aix
+#     OSNAME-ARCH   Specific on to one OSNAME and ARCH, e.g. solaris-amd64
+#     OSNAME-REV    Specific on to one OSNAME and REV, e.g. solaris-5.8
+#
+# More than one label is allowed but must be on the same line.
+#
+#############################################################################
+
+# :hotspot_compiler
+
+compiler/codecache/stress/OverloadCompileQueueTest.java 8166554 generic-all
+compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8140405 generic-all
+compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java 8158860 generic-all
+compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java 8163894 generic-all
+compiler/startup/SmallCodeCacheStartup.java 8134286 generic-all
+compiler/tiered/LevelTransitionTest.java 8067651 generic-all
+compiler/types/correctness/CorrectnessTest.java 8066173 generic-all
+compiler/types/correctness/OffTest.java 8066173 generic-all
+
+#############################################################################
+
+# :hotspot_gc
+
+gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all
+gc/survivorAlignment/TestPromotionToSurvivor.java 8129886 generic-all
+gc/stress/TestStressG1Humongous.java 8171045 generic-all
+
+#############################################################################
+
+# :hotspot_runtime
+
+runtime/CompressedOops/UseCompressedOops.java 8079353 generic-all
+# This test is disabled since it will stress NMT and timeout during normal testing
+runtime/NMT/MallocStressTest.java 8166548 generic-all
+runtime/SharedArchiveFile/BootAppendTests.java 8150683 generic-all
+runtime/SharedArchiveFile/DefaultUseWithClient.java 8154204 generic-all
+
+#############################################################################
+
+# :hotspot_serviceability
+
+serviceability/dcmd/jvmti/LoadAgentDcmdTest.java 8150318 generic-all
+serviceability/jdwp/AllModulesCommandTest.java 8168478 generic-all
+serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all
+
+#############################################################################
+
+# :hotspot_misc
+
+#############################################################################
+
diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT
index cce42af..45e21c6 100644
--- a/hotspot/test/TEST.ROOT
+++ b/hotspot/test/TEST.ROOT
@@ -34,7 +34,7 @@
 # Source files for classes that will be used at the beginning of each test suite run,
 # to determine additional characteristics of the system for use with the @requires tag.
 # Note: compiled bootlibs code will be located in the folder 'bootClasses'
-requires.extraPropDefns = ../../test/jtreg-ext/requires/VMProps.java
+requires.extraPropDefns = ../../test/jtreg-ext/requires/VMProps.java [../../closed/test/jtreg-ext/requires/VMPropsExt.java]
 requires.extraPropDefns.bootlibs = ../../test/lib/sun
 requires.extraPropDefns.vmOpts = -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:bootClasses
 requires.properties= \
@@ -45,6 +45,7 @@
     vm.gc.Serial \
     vm.gc.Parallel \
     vm.gc.ConcMarkSweep \
+    vm.jvmci \
     vm.debug
 
 # Tests using jtreg 4.2 b04 features
diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups
index 9c247c7..c50c741 100644
--- a/hotspot/test/TEST.groups
+++ b/hotspot/test/TEST.groups
@@ -52,19 +52,19 @@
 
 hotspot_all = \
   /
-  
+
 hotspot_compiler = \
   compiler
-  
+
 hotspot_gc = \
   gc
 
 hotspot_runtime = \
   runtime
-  
+
 hotspot_serviceability = \
   serviceability
-  
+
 hotspot_misc = \
   / \
  -:hotspot_compiler \
@@ -83,6 +83,7 @@
 # can be resolved in some cases by using tools from the compile-jdk.
 #
 needs_jdk = \
+  compiler/aot \
   gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java \
   gc/metaspace/TestMetaspacePerfCounters.java \
   gc/metaspace/TestPerfCountersAndMemoryPools.java \
@@ -273,6 +274,7 @@
   native_sanity
 
 hotspot_fast_compiler_1 = \
+  compiler/aot/ \
   compiler/arraycopy/ \
   compiler/c1/ \
   compiler/c2/ \
@@ -330,6 +332,13 @@
 hotspot_fast_compiler_closed = \
   sanity/ExecuteInternalVMTests.java
 
+hotspot_not_fast_compiler = \
+  :hotspot_compiler \
+  -:hotspot_fast_compiler_1 \
+  -:hotspot_fast_compiler_2 \
+  -:hotspot_fast_compiler_3 \
+  -:hotspot_fast_compiler_closed
+
 hotspot_fast_gc_1 = \
   gc/g1/
 
@@ -414,7 +423,7 @@
   :hotspot_fast_gc_gcold \
   :hotspot_fast_runtime \
   :hotspot_fast_serviceability
-  
+
 hotspot_runtime_tier2 = \
   runtime/ \
   serviceability/ \
@@ -423,11 +432,11 @@
  -:hotspot_fast_runtime \
  -:hotspot_fast_serviceability \
  -:hotspot_runtime_tier2_platform_agnostic
- 
+
 hotspot_runtime_tier2_platform_agnostic = \
   runtime/SelectionResolution \
  -:hotspot_fast_runtime
- 
+
 hotspot_runtime_tier3 = \
   runtime/ \
   serviceability/ \
@@ -440,7 +449,7 @@
   runtime/MinimalVM \
   runtime/ErrorHandling \
   runtime/logging
-  
+
 #All tests that depends on nashorn extension.
 #
 needs_nashorn = \
diff --git a/hotspot/test/compiler/aot/AotCompiler.java b/hotspot/test/compiler/aot/AotCompiler.java
new file mode 100644
index 0000000..68a2246
--- /dev/null
+++ b/hotspot/test/compiler/aot/AotCompiler.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+
+/**
+ * A simple class calling AOT compiler over requested items
+ */
+public class AotCompiler {
+
+    private final static String METHODS_LIST_FILENAME = "methodsList.txt";
+
+    public static void main(String args[]) {
+        String className = null;
+        List<String> compileList = new ArrayList<>();
+        String libName = null;
+        List<String> extraopts = new ArrayList<>();
+        for (int i = 0; i < args.length; i++) {
+            switch (args[i]) {
+                case "-class":
+                    className = args[++i];
+                    break;
+                case "-compile":
+                    compileList.add("compileOnly " + args[++i]);
+                    break;
+                case "-libname":
+                    libName = args[++i];
+                    break;
+                case "-extraopt":
+                    extraopts.add(args[++i]);
+                    break;
+                default:
+                    throw new Error("Unknown option: " + args[i]);
+            }
+        }
+        extraopts.add("-classpath");
+        extraopts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC);
+        if (className != null && libName != null) {
+            OutputAnalyzer oa = launchCompiler(libName, className + ".class", extraopts, compileList);
+            oa.shouldHaveExitValue(0);
+        } else {
+            printUsage();
+            throw new Error("Mandatory arguments aren't passed");
+        }
+    }
+
+    public static OutputAnalyzer launchCompilerSimple(String... args) {
+        return launchJaotc(Arrays.asList(args), null);
+    }
+
+    public static OutputAnalyzer launchCompiler(String libName, String item, List<String> extraopts,
+            List<String> compList) {
+        Path file = null;
+        if (compList != null && !compList.isEmpty()) {
+            file = Paths.get(METHODS_LIST_FILENAME);
+            try {
+                Files.write(file, compList, StandardOpenOption.CREATE);
+            } catch (IOException e) {
+                throw new Error("Couldn't write " + METHODS_LIST_FILENAME + " " + e, e);
+            }
+        }
+        List<String> args = new ArrayList<>();
+        args.add("--output");
+        args.add(libName);
+        if (file != null) {
+            args.add("--compile-commands");
+            args.add(file.toString());
+        }
+        args.add(item);
+        return launchJaotc(args, extraopts);
+    }
+
+    private static OutputAnalyzer launchJaotc(List<String> args, List<String> extraVmOpts) {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jaotc");
+        for (String vmOpt : Utils.getTestJavaOpts()) {
+            launcher.addVMArg(vmOpt);
+        }
+        if (extraVmOpts != null) {
+            for (String vmOpt : extraVmOpts) {
+                launcher.addVMArg(vmOpt);
+            }
+        }
+        for (String arg : args) {
+            launcher.addToolArg(arg);
+        }
+        try {
+            return new OutputAnalyzer(new ProcessBuilder(launcher.getCommand()).inheritIO().start());
+        } catch (IOException e) {
+            throw new Error("Can't start test process: " + e, e);
+        }
+    }
+
+    public static void printUsage() {
+        System.err.println("Usage: " + AotCompiler.class.getName()
+                + " -class <class> -libname <.so name>"
+                + " [-compile <compileItems>]* [-extraopt <java option>]*");
+    }
+}
diff --git a/hotspot/test/compiler/aot/DeoptimizationTest.java b/hotspot/test/compiler/aot/DeoptimizationTest.java
new file mode 100644
index 0000000..f027500
--- /dev/null
+++ b/hotspot/test/compiler/aot/DeoptimizationTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.DeoptimizationTest
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname libDeoptimizationTest.so
+ *     -class compiler.aot.DeoptimizationTest
+ *     -compile compiler.aot.DeoptimizationTest.testMethod()D
+ *     -extraopt -XX:-UseCompressedOops
+ * @run main/othervm -Xmixed -XX:+UseAOT -XX:+TieredCompilation
+ *     -XX:-UseCompressedOops
+ *     -XX:CompileCommand=dontinline,compiler.aot.DeoptimizationTest::*
+ *     -XX:AOTLibrary=./libDeoptimizationTest.so -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     compiler.aot.DeoptimizationTest
+ * @summary check if aot code can be deoptimized
+ */
+
+package compiler.aot;
+
+import java.lang.reflect.Method;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Utils;
+import sun.hotspot.WhiteBox;
+import compiler.whitebox.CompilerWhiteBoxTest;
+
+public final class DeoptimizationTest {
+    private static final String TEST_METHOD = "testMethod";
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+    private final Method testMethod;
+
+    private DeoptimizationTest() {
+        try {
+            testMethod = getClass().getDeclaredMethod(TEST_METHOD);
+        } catch (NoSuchMethodException e) {
+            throw new Error("TEST BUG: no test method found", e);
+        }
+    }
+
+    public static void main(String args[]) {
+        new DeoptimizationTest().test();
+    }
+
+    private double testMethod() {
+        return 42 / 0;
+    }
+
+    private void test() {
+        Asserts.assertTrue(WB.isMethodCompiled(testMethod),
+                "Method expected to be compiled");
+        Asserts.assertEQ(WB.getMethodCompilationLevel(testMethod),
+                CompilerWhiteBoxTest.COMP_LEVEL_AOT,
+                "Unexpected compilation level at start");
+        Utils.runAndCheckException(() -> testMethod(), ArithmeticException.class);
+        Asserts.assertFalse(WB.isMethodCompiled(testMethod),
+                "Method is unexpectedly compiled after deoptimization");
+        Asserts.assertEQ(WB.getMethodCompilationLevel(testMethod), 0,
+                "Unexpected compilation level after deoptimization");
+    }
+}
diff --git a/hotspot/test/compiler/aot/HelloWorldPrinter.java b/hotspot/test/compiler/aot/HelloWorldPrinter.java
new file mode 100644
index 0000000..43c1e17
--- /dev/null
+++ b/hotspot/test/compiler/aot/HelloWorldPrinter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot;
+
+public class HelloWorldPrinter {
+    public static final String MESSAGE = "Hello world";
+    public static final String CLINIT_MESSAGE = "Hello <clinit> world";
+
+    static {
+        System.out.println(CLINIT_MESSAGE);
+    }
+
+    public static void main(String args[]) {
+        print();
+    }
+
+    public static void print() {
+        System.out.println(MESSAGE);
+    }
+}
diff --git a/hotspot/test/compiler/aot/RecompilationTest.java b/hotspot/test/compiler/aot/RecompilationTest.java
new file mode 100644
index 0000000..466c834
--- /dev/null
+++ b/hotspot/test/compiler/aot/RecompilationTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.RecompilationTest
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname libRecompilationTest1.so
+ *     -class compiler.whitebox.SimpleTestCaseHelper
+ *     -extraopt -Dgraal.TieredAOT=true -extraopt -Dgraal.ProfileSimpleMethods=true
+ *     -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ *     -extraopt -XX:-UseCompressedOops
+ *     -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
+ * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation
+ *     -XX:-UseCounterDecay -XX:-UseCompressedOops
+ *     -XX:-Inline
+ *     -XX:AOTLibrary=./libRecompilationTest1.so -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -Dcompiler.aot.RecompilationTest.check_level=1
+ *     compiler.aot.RecompilationTest
+ * @run main compiler.aot.AotCompiler -libname libRecompilationTest2.so
+ *     -class compiler.whitebox.SimpleTestCaseHelper
+ *     -extraopt -Dgraal.TieredAOT=false
+ *     -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ *     -extraopt -XX:-UseCompressedOops
+ *     -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
+ * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation
+ *     -XX:-UseCounterDecay -XX:-UseCompressedOops
+ *     -XX:-Inline
+ *     -XX:AOTLibrary=./libRecompilationTest2.so -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -Dcompiler.aot.RecompilationTest.check_level=-1
+ *     compiler.aot.RecompilationTest
+ * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:-TieredCompilation
+ *     -XX:-UseCounterDecay -XX:-UseCompressedOops
+ *     -XX:-Inline
+ *     -XX:AOTLibrary=./libRecompilationTest2.so -Xbootclasspath/a:.
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -Dcompiler.aot.RecompilationTest.check_level=-1
+ *     compiler.aot.RecompilationTest
+ * @summary check if recompilation after aot goes fine
+ */
+
+ /* having whitebox-related options for aot compiler is a temporary solution,
+    because of JDK-8146201
+ */
+
+package compiler.aot;
+
+import compiler.whitebox.CompilerWhiteBoxTest;
+import java.lang.reflect.Executable;
+import jdk.test.lib.Asserts;
+
+public final class RecompilationTest extends CompilerWhiteBoxTest {
+    private static final int CHECK_LEVEL = Integer.getInteger(
+                "compiler.aot.RecompilationTest.check_level");
+
+    public static void main(String args[]) {
+        CompilerWhiteBoxTest.main(RecompilationTest::new, args);
+    }
+
+    private RecompilationTest(TestCase testCase) {
+        super(testCase);
+    }
+
+    @Override
+    protected void test() throws Exception {
+        if (testCase.isOsr()) {
+            /* aot compiler is not using osr compilation */
+            System.out.println("Skipping OSR case");
+            return;
+        }
+        Executable e = testCase.getExecutable();
+        Asserts.assertTrue(WHITE_BOX.isMethodCompiled(e),
+                testCase.name() +  ": an executable expected to be compiled");
+        Asserts.assertEQ(WHITE_BOX.getMethodCompilationLevel(e),
+                COMP_LEVEL_AOT,
+                String.format("%s: unexpected compilation level at start",
+                        testCase.name()));
+        compile();
+        Asserts.assertTrue(WHITE_BOX.isMethodCompiled(e), testCase.name()
+                + ": method expected to be compiled");
+        /* a case with AOT'ed code checks exact compilation level equality
+           while another case checks minimum level and if method compiled
+           because there might be different compilation level transitions */
+        if (CHECK_LEVEL != COMP_LEVEL_AOT) {
+            Asserts.assertGTE(WHITE_BOX.getMethodCompilationLevel(e),
+                CHECK_LEVEL,
+                String.format("%s: expected compilation level"
+                        + " after compilation to be no less than %d for %s",
+                        testCase.name(), CHECK_LEVEL, testCase.name()));
+        } else {
+            Asserts.assertEQ(WHITE_BOX.getMethodCompilationLevel(e),
+                COMP_LEVEL_AOT, String.format("%s: expected compilation"
+                        + " level after compilation to be equal to %d for %s",
+                        testCase.name(), COMP_LEVEL_AOT, testCase.name()));
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/SharedUsageTest.java b/hotspot/test/compiler/aot/SharedUsageTest.java
new file mode 100644
index 0000000..829f63d
--- /dev/null
+++ b/hotspot/test/compiler/aot/SharedUsageTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.SharedUsageTest
+ *        compiler.aot.AotCompiler
+ * @run main compiler.aot.AotCompiler -libname libSharedUsageTest.so
+ *      -class compiler.aot.SharedUsageTest
+ *      -extraopt -XX:-UseCompressedOops
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./libSharedUsageTest.so
+ *      -XX:-UseCompressedOops
+ *      -Dcompiler.aot.SharedUsageTest.parent=true
+ *      compiler.aot.SharedUsageTest
+ * @summary check if .so can be successfully shared with 2 java processes
+ */
+
+package compiler.aot;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.Utils;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class SharedUsageTest {
+    private static final String HELLO_MSG = "HelloWorld";
+    private static final boolean ADD_TEST_VM_OPTION = false;
+    private static boolean shouldBeFalseInParent = false;
+    private static final boolean IS_PARENT = Boolean.getBoolean(
+        "compiler.aot.SharedUsageTest.parent");
+
+    public static void main(String args[]) throws Throwable {
+        Asserts.assertFalse(shouldBeFalseInParent,
+                "A test invariant is broken");
+        if (IS_PARENT) {
+            /* An output of .so being used is verified after launch.
+               A respective message is triggered by PrintAOT option. */
+            CommandLineOptionTest.verifyJVMStartup(
+                    new String[]{"libSharedUsageTest.so  aot library",
+                        HELLO_MSG}, null, "Unexpected exit code",
+                    "Unexpected output", ExitCode.OK, ADD_TEST_VM_OPTION,
+                    "-XX:+UseAOT", "-XX:+PrintAOT",
+                    "-Dtest.jdk=" + Utils.TEST_JDK,
+                    "-XX:AOTLibrary=./libSharedUsageTest.so",
+                    SharedUsageTest.class.getName());
+            Asserts.assertFalse(shouldBeFalseInParent, "A static member got "
+                    + "unexpectedly changed");
+        } else {
+            shouldBeFalseInParent = true;
+            Asserts.assertTrue(shouldBeFalseInParent, "A static member wasn't"
+                    + "changed as expected");
+            System.out.println(HELLO_MSG);
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java
new file mode 100644
index 0000000..2abd5b4
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @ignore 8132547
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeDynamic2AotTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./AotInvokeDynamic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic
+ *      -checkCallerCompileLevel -1 -checkCalleeCompileLevel -1
+ * @summary check calls from aot to aot code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java
new file mode 100644
index 0000000..ec09662
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @ignore 8132547
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeDynamic2CompiledTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeDynamic2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic -compileCallee 1
+ *      -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeDynamic2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic -compileCallee 4
+ *      -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java
new file mode 100644
index 0000000..96dfd19
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @ignore 8132547
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeDynamic2InterpretedTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm -XX:AOTLibrary=./AotInvokeDynamic2InterpretedTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      -XX:+UseAOT compiler.calls.common.InvokeDynamic -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java
new file mode 100644
index 0000000..c1c9a44
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @ignore 8132547
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeDynamic2NativeTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -compile compiler.calls.common.InvokeDynamic.caller()V
+ * @run main/othervm/native -XX:+UseAOT
+ *       -XX:AOTLibrary=./AotInvokeDynamic2NativeTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *       compiler.calls.common.InvokeDynamic -nativeCallee -checkCallerCompileLevel -1
+ * @summary check calls from aot to native code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java
new file mode 100644
index 0000000..9a739a6
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeInterface2AotTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./AotInvokeInterface2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface
+ *      -checkCallerCompileLevel -1 -checkCalleeCompileLevel -1
+ * @summary check calls from aot to aot code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java
new file mode 100644
index 0000000..e9bcdef
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeInterface2CompiledTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeInterface2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -compileCallee 1
+ *      -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeInterface2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -compileCallee 4
+ *      -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java
new file mode 100644
index 0000000..ad1b0f9
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeInterface2InterpretedTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeInterface2InterpretedTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java
new file mode 100644
index 0000000..89afb38
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeInterface2NativeTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -compile compiler.calls.common.InvokeInterface.caller()V
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeInterface2NativeTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -nativeCallee -checkCallerCompileLevel -1
+ * @summary check calls from aot to native code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java
new file mode 100644
index 0000000..5b9ca47
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeSpecial2AotTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./AotInvokeSpecial2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial
+ *      -checkCallerCompileLevel -1 -checkCalleeCompileLevel -1
+ * @summary check calls from aot to aot code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java
new file mode 100644
index 0000000..5a338c1
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeSpecial2CompiledTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeSpecial2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -compileCallee 1
+ *      -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeSpecial2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -compileCallee 4
+ *      -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java
new file mode 100644
index 0000000..a011eee
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeSpecial2InterpretedTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeSpecial2InterpretedTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java
new file mode 100644
index 0000000..9c52071
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeSpecial2NativeTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.caller()V
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeSpecial2NativeTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -nativeCallee -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java
new file mode 100644
index 0000000..28928e1
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeStatic2AotTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./AotInvokeStatic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic
+ *      -checkCallerCompileLevel -1 -checkCalleeCompileLevel -1
+ * @summary check calls from aot to aot code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java
new file mode 100644
index 0000000..9bdc0b9
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeStatic2CompiledTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeStatic2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -compileCallee 1
+ *      -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeStatic2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -compileCallee 4
+ *      -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java
new file mode 100644
index 0000000..d06930f
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeStatic2InterpretedTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeStatic2InterpretedTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java
new file mode 100644
index 0000000..a401340
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeStatic2NativeTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.caller()V
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeStatic2NativeTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -nativeCallee -checkCallerCompileLevel -1
+ * @summary check calls from aot to native code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java
new file mode 100644
index 0000000..515d2b0
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeVirtual2AotTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
+ * @run main/othervm -XX:+UseAOT -XX:AOTLibrary=./AotInvokeVirtual2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual
+ *      -checkCallerCompileLevel -1 -checkCalleeCompileLevel -1
+ * @summary check calls from aot to aot code, using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java
new file mode 100644
index 0000000..90709cf
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeVirtual2CompiledTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeVirtual2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -compileCallee 1
+ *      -checkCalleeCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeVirtual2CompiledTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -compileCallee 4
+ *      -checkCalleeCompileLevel 4
+ * @summary check calls from aot to jit-compiled code, using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java
new file mode 100644
index 0000000..3a9b881
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname AotInvokeVirtual2InterpretedTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeVirtual2InterpretedTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -checkCallerCompileLevel -1
+ * @summary check calls from aot to interpreted code, using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java
new file mode 100644
index 0000000..ee163a1
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname AotInvokeVirtual2NativeTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.caller()V
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./AotInvokeVirtual2NativeTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -nativeCallee -checkCallerCompileLevel -1
+ * @summary check calls from aot to native code, using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java
new file mode 100644
index 0000000..133e98c
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main compiler.aot.AotCompiler -libname CompiledInvokeDynamic2AotTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -compile compiler.calls.common.InvokeDynamic.callee.*
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeDynamic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic -compileCaller 1
+ *      -checkCalleeCompileLevel -1 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeDynamic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic -compileCaller 4
+ *      -checkCallerCompileLevel 4 -checkCalleeCompileLevel -1
+ * @summary check calls from jit-compiled to aot code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java
new file mode 100644
index 0000000..3cab0a8
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *      compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname CompiledInvokeInterface2AotTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -compile compiler.calls.common.InvokeInterface.callee.*
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeInterface2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -compileCaller 1
+ *      -checkCalleeCompileLevel -1 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeInterface2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -compileCaller 4
+ *      -checkCallerCompileLevel 4 -checkCalleeCompileLevel -1
+ * @summary check calls from jit-compiled to aot code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java
new file mode 100644
index 0000000..daa8f9c
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname CompiledInvokeSpecial2AotTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeSpecial2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -compileCaller 1
+ *      -checkCalleeCompileLevel -1 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeSpecial2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -compileCaller 4
+ *      -checkCallerCompileLevel 4 -checkCalleeCompileLevel -1
+ * @summary check calls from jit-compiled to aot code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java
new file mode 100644
index 0000000..5dcf91d
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname CompiledInvokeStatic2AotTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeStatic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -compileCaller 1
+ *      -checkCalleeCompileLevel -1 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeStatic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -compileCaller 4
+ *      -checkCallerCompileLevel 4 -checkCalleeCompileLevel -1
+ * @summary check calls from jit-compiled to aot code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java
new file mode 100644
index 0000000..429d60b
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname CompiledInvokeVirtual2AotTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeVirtual2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -compileCaller 1
+ *      -checkCalleeCompileLevel -1 -checkCallerCompileLevel 1
+ * @run main/othervm -Xbatch -XX:+UseAOT
+ *      -XX:AOTLibrary=./CompiledInvokeVirtual2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -compileCaller 4
+ *      -checkCallerCompileLevel 4 -checkCalleeCompileLevel -1
+ * @summary check calls from jit-compiled to aot code using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java
new file mode 100644
index 0000000..ecdf79a
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeDynamic
+ *        compiler.calls.common.InvokeDynamicPatcher
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.calls.common.InvokeDynamicPatcher
+ * @run main compiler.aot.AotCompiler
+ *      -libname InterpretedInvokeDynamic2AotTest.so
+ *      -class compiler.calls.common.InvokeDynamic
+ *      -compile compiler.calls.common.InvokeDynamic.callee.*
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./InterpretedInvokeDynamic2AotTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeDynamic -checkCalleeCompileLevel -1
+ * @summary check calls from interpreted to aot code using invokedynamic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java
new file mode 100644
index 0000000..8b7db4e
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeInterface
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname InterpretedInvokeInterface2AotTest.so
+ *      -class compiler.calls.common.InvokeInterface
+ *      -compile compiler.calls.common.InvokeInterface.callee.*
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./InterpretedInvokeInterface2AotTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeInterface -checkCalleeCompileLevel -1
+ * @summary check calls from interpreted to aot code using invokeinterface
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java
new file mode 100644
index 0000000..5510136
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname InterpretedInvokeSpecial2AotTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./InterpretedInvokeSpecial2AotTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -checkCalleeCompileLevel -1
+ * @summary check calls from interpreted to aot code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java
new file mode 100644
index 0000000..0c2b9db
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname InterpretedInvokeStatic2AotTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./InterpretedInvokeStatic2AotTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -checkCalleeCompileLevel -1
+ * @summary check calls from interpreted to aot code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java
new file mode 100644
index 0000000..9738f48
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler
+ *      -libname InterpretedInvokeVirtual2AotTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm -XX:+UseAOT
+ *      -XX:AOTLibrary=./InterpretedInvokeVirtual2AotTest.so
+ *      -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -checkCalleeCompileLevel -1
+ * @summary check calls from interpreted to aot code using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java
new file mode 100644
index 0000000..4b09209
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeSpecial
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname NativeInvokeSpecial2AotTest.so
+ *      -class compiler.calls.common.InvokeSpecial
+ *      -compile compiler.calls.common.InvokeSpecial.callee.*
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./NativeInvokeSpecial2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeSpecial -nativeCaller -checkCalleeCompileLevel -1
+ * @summary check calls from native to aot code using invokespecial
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java
new file mode 100644
index 0000000..00b75a4
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeStatic
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname NativeInvokeStatic2AotTest.so
+ *      -class compiler.calls.common.InvokeStatic
+ *      -compile compiler.calls.common.InvokeStatic.callee.*
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./NativeInvokeStatic2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeStatic -nativeCaller -checkCalleeCompileLevel -1
+ * @summary check calls from native to aot code using invokestatic
+ */
diff --git a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java
new file mode 100644
index 0000000..6ba1d23
--- /dev/null
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.calls.common.InvokeVirtual
+ *        compiler.aot.AotCompiler
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *      sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main compiler.aot.AotCompiler -libname NativeInvokeVirtual2AotTest.so
+ *      -class compiler.calls.common.InvokeVirtual
+ *      -compile compiler.calls.common.InvokeVirtual.callee.*
+ * @run main/othervm/native -XX:+UseAOT
+ *      -XX:AOTLibrary=./NativeInvokeVirtual2AotTest.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      compiler.calls.common.InvokeVirtual -nativeCaller -checkCalleeCompileLevel -1
+ * @summary check calls from native to aot code using invokevirtual
+ */
diff --git a/hotspot/test/compiler/aot/cli/AotLibraryNegativeBase.java b/hotspot/test/compiler/aot/cli/AotLibraryNegativeBase.java
new file mode 100644
index 0000000..8b62ce4
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/AotLibraryNegativeBase.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class AotLibraryNegativeBase {
+    private static final String[] UNEXPECTED_MESSAGES = new String[] {
+        HelloWorldPrinter.MESSAGE
+    };
+
+    public static void launchTest(String option, String expectedMessages[]) {
+        try {
+            boolean addTestVMOptions = true;
+            CommandLineOptionTest.verifyJVMStartup(expectedMessages,
+                    UNEXPECTED_MESSAGES,
+                    "Unexpected exit code using " + option,
+                    "Unexpected output using " + option, ExitCode.FAIL,
+                    addTestVMOptions, "-XX:+UseAOT", "-XX:+PrintAOT",
+                    option, HelloWorldPrinter.class.getName());
+        } catch (Throwable t) {
+            throw new Error("Problems executing test using " + option
+                    + ": " + t, t);
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/DisabledAOTWithLibraryTest.java b/hotspot/test/compiler/aot/cli/DisabledAOTWithLibraryTest.java
new file mode 100644
index 0000000..3a9f2f0
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/DisabledAOTWithLibraryTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.DisabledAOTWithLibraryTest
+ *        compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libDisabledAOTWithLibraryTest.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ * @run driver compiler.aot.cli.DisabledAOTWithLibraryTest
+ * @summary check if providing aot library with aot disabled is handled properly
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class DisabledAOTWithLibraryTest {
+    private final static String LIB_NAME = "libDisabledAOTWithLibraryTest.so";
+    private final static String[] UNEXPECTED_MESSAGES = new String[] {
+        LIB_NAME + "  aot library"
+    };
+
+    private final static String[] EXPECTED_MESSAGES = new String[] {
+        HelloWorldPrinter.MESSAGE
+    };
+
+    public static void main(String args[]) {
+        try {
+            boolean addTestVMOptions = true;
+            CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+                    UNEXPECTED_MESSAGES, "Unexpected exit code",
+                    "Unexpected output", ExitCode.OK, addTestVMOptions,
+                    "-XX:-UseAOT", "-XX:+PrintAOT",
+                    "-XX:AOTLibrary=./" + LIB_NAME,
+                    HelloWorldPrinter.class.getName());
+        } catch (Throwable t) {
+            throw new Error("Problems executing test " + t, t);
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/IncorrectAOTLibraryTest.java b/hotspot/test/compiler/aot/cli/IncorrectAOTLibraryTest.java
new file mode 100644
index 0000000..89884b4
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/IncorrectAOTLibraryTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @run driver ClassFileInstaller ClassFileInstaller
+ * @run driver compiler.aot.cli.IncorrectAOTLibraryTest
+ * @summary check if incorrect aot library is handled properly
+ */
+
+package compiler.aot.cli;
+
+public class IncorrectAOTLibraryTest {
+    private static final String OPTION
+            = "-XX:AOTLibrary=./ClassFileInstaller.class";
+    private static final String[] EXPECTED_MESSAGES = new String[] {
+        "error opening file:"
+    };
+
+    public static void main(String args[]) {
+        AotLibraryNegativeBase.launchTest(OPTION, EXPECTED_MESSAGES);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/MultipleAOTLibraryTest.java b/hotspot/test/compiler/aot/cli/MultipleAOTLibraryTest.java
new file mode 100644
index 0000000..7cac002
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/MultipleAOTLibraryTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.MultipleAOTLibraryTest
+ *        compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler
+ *      -libname libMultipleAOTLibraryTest1.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.*
+ *      -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler
+ *      -libname libMultipleAOTLibraryTest2.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.MultipleAOTLibraryTest -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libMultipleAOTLibraryTest1.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.*
+ *      -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libMultipleAOTLibraryTest2.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.MultipleAOTLibraryTest -XX:-UseCompressedOops
+ * @summary check if multiple aot libraries are loaded successfully
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import java.util.Arrays;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public final class MultipleAOTLibraryTest {
+    private final static String EXPECTED_OUTPUT[] = new String[] {
+                "libMultipleAOTLibraryTest1.so  aot library",
+                "libMultipleAOTLibraryTest2.so  aot library",
+                HelloWorldPrinter.MESSAGE
+    };
+    private final static String UNEXPECTED_OUTPUT[] = null;
+
+    public static void main(String args[]) {
+        new MultipleAOTLibraryTest().runTest(args);
+    }
+
+    private void runTest(String args[]) {
+        try {
+            boolean addTestVMOptions = true;
+            String[] allArgs = Arrays.copyOf(args, args.length + 4);
+            allArgs[args.length] = "-XX:AOTLibrary="
+                    + "./libMultipleAOTLibraryTest1.so:"
+                    + "./libMultipleAOTLibraryTest2.so";
+            allArgs[args.length + 1] = "-XX:+PrintAOT";
+            allArgs[args.length + 2] = "-XX:+UseAOT";
+            allArgs[args.length + 3] = HelloWorldPrinter.class.getName();
+            CommandLineOptionTest.verifyJVMStartup(EXPECTED_OUTPUT,
+                    UNEXPECTED_OUTPUT, "Unexpected exit code",
+                    "Unexpected output", ExitCode.OK, addTestVMOptions,
+                    allArgs);
+        } catch (Throwable t) {
+            throw new Error("Problems executing test: " + t, t);
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/NonExistingAOTLibraryTest.java b/hotspot/test/compiler/aot/cli/NonExistingAOTLibraryTest.java
new file mode 100644
index 0000000..bd8c021
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/NonExistingAOTLibraryTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @run driver compiler.aot.cli.NonExistingAOTLibraryTest
+ * @summary check if non-existing aot library is handled properly
+ */
+
+package compiler.aot.cli;
+
+import java.io.File;
+
+public class NonExistingAOTLibraryTest {
+    private static final String PATH = "./NonExisting.so";
+    private static final String OPTION = "-XX:AOTLibrary=" + PATH;
+    private static final String[] EXPECTED_MESSAGES = new String[] {
+        "cannot open shared object file"
+    };
+
+    public static void main(String args[]) {
+        if (new File(PATH).exists()) {
+            throw new Error("TESTBUG: " + PATH + " unexpectedly exists");
+        }
+        AotLibraryNegativeBase.launchTest(OPTION, EXPECTED_MESSAGES);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/SingleAOTLibraryTest.java b/hotspot/test/compiler/aot/cli/SingleAOTLibraryTest.java
new file mode 100644
index 0000000..67e2c77
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/SingleAOTLibraryTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib / /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.SingleAOTLibraryTest
+ *        compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTLibraryTest.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTLibraryTest -XX:+UseCompressedOops
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTLibraryTest.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTLibraryTest -XX:-UseCompressedOops
+ * @summary check if single aot library is loaded successfully
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public final class SingleAOTLibraryTest {
+    private static final String[] EXPECTED_MESSAGES = new String[] {
+        "libSingleAOTLibraryTest.so  aot library",
+        HelloWorldPrinter.MESSAGE
+    };
+    private static final String[] UNEXPECTED_MESSAGES = null;
+    public static void main(String args[]) {
+        if (args.length == 1) {
+            new SingleAOTLibraryTest().runTest(args[0]);
+        } else {
+            throw new Error("Test expects 1 parameter");
+        }
+    }
+
+    private void runTest(String arg) {
+        try {
+            boolean addTestVMOptions = true;
+            CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+                    UNEXPECTED_MESSAGES, "Unexpected exit code using " + arg,
+                    "Unexpected output using " + arg, ExitCode.OK,
+                    addTestVMOptions, "-XX:+UseAOT", "-XX:+PrintAOT", arg,
+                    "-XX:AOTLibrary=./libSingleAOTLibraryTest.so",
+                    HelloWorldPrinter.class.getName());
+        } catch (Throwable t) {
+            throw new Error("Problems executing test: " + t, t);
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/SingleAOTOptionTest.java b/hotspot/test/compiler/aot/cli/SingleAOTOptionTest.java
new file mode 100644
index 0000000..6e33256
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/SingleAOTOptionTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /testlibrary /
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.SingleAOTOptionTest
+ *        compiler.aot.AotCompiler
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTOptionTest.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:+UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTOptionTest -XX:+UseCompressedOops
+ *      -XX:AOTLibrary=./libSingleAOTOptionTest.so
+ * @run main compiler.aot.cli.SingleAOTOptionTest
+ *      -XX:+UseCompressedOops -XX:+UseAOT
+ * @run driver compiler.aot.AotCompiler -libname libSingleAOTOptionTest.so
+ *      -class compiler.aot.HelloWorldPrinter
+ *      -compile compiler.aot.HelloWorldPrinter.print()V
+ *      -extraopt -XX:-UseCompressedOops
+ * @run driver compiler.aot.cli.SingleAOTOptionTest -XX:-UseCompressedOops
+ *      -XX:AOTLibrary=./libSingleAOTOptionTest.so
+ * @run driver compiler.aot.cli.SingleAOTOptionTest
+ *      -XX:-UseCompressedOops -XX:+UseAOT
+ * @summary check if specifying only one aot option handled properly
+ */
+
+package compiler.aot.cli;
+
+import compiler.aot.HelloWorldPrinter;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.cli.CommandLineOptionTest;
+
+public class SingleAOTOptionTest {
+    private static final String[] EXPECTED_MESSAGES = new String[] {
+        HelloWorldPrinter.MESSAGE
+    };
+    private static final String[] UNEXPECTED_MESSAGES = null;
+
+    public static void main(String args[]) {
+        if (args.length == 2) {
+            new SingleAOTOptionTest().runTest(args[0], args[1]);
+        } else {
+            throw new Error("Test expects 2 parameters");
+        }
+    }
+
+    private void runTest(String arg1, String arg2) {
+        try {
+            String exitCodeErrorMessage = String.format("Unexpected exit code "
+                    + "using %s and %s", arg1, arg2);
+            String outputErrorMessage = String.format("Unexpected output using"
+                    + " %s and %s", arg1, arg2);
+            boolean addTestVMOptions = true;
+            CommandLineOptionTest.verifyJVMStartup(EXPECTED_MESSAGES,
+                    UNEXPECTED_MESSAGES, exitCodeErrorMessage,
+                    outputErrorMessage, ExitCode.OK, addTestVMOptions, arg1,
+                    arg2, HelloWorldPrinter.class.getName());
+        } catch (Throwable t) {
+            throw new Error("Problems executing test: " + t, t);
+        }
+    }
+
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java
new file mode 100644
index 0000000..eeee8db
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.ClasspathOptionTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ClasspathOptionTest
+ * @summary check jaotc can compile class from classpath
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ClasspathOptionTest {
+    public static void main(String[] args) {
+        Path cp = Paths.get("testClasspath");
+        try {
+            Files.createDirectory(cp);
+            Files.move(Paths.get("compiler"), cp.resolve("compiler"));
+        } catch (IOException e) {
+            throw new Error("TESTBUG: can't create test data " + e, e);
+        }
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--classpath", cp.toString(),
+                JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class));
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java
new file mode 100644
index 0000000..1b99249
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /testlibrary/ /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @compile data/HelloWorldOne.java
+ * @run driver compiler.aot.cli.jaotc.ClasspathOptionUnknownClassTest
+ * @summary check jaotc can't compile class not from classpath
+ */
+
+package compiler.aot.cli.jaotc;
+
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ClasspathOptionUnknownClassTest {
+    public static void main(String[] args) {
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("HelloWorldOne.class");
+        Asserts.assertNE(oa.getExitValue(), 0, "Unexpected compilation exit code");
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertFalse(compiledLibrary.exists(), "Compiler library unexpectedly exists");
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java
new file mode 100644
index 0000000..a59e9e5
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.CompileClassTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.CompileClassTest
+ * @summary check jaotc can compile class
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileClassTest {
+    public static void main(String[] args) {
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary(JaotcTestHelper
+                .getClassAotCompilationName(HelloWorldOne.class));
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java
new file mode 100644
index 0000000..7157294
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.CompileDirectoryTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ *                                compiler.aot.cli.jaotc.data.HelloWorldTwo
+ * @run driver compiler.aot.cli.jaotc.CompileDirectoryTest
+ * @summary check jaotc can compile directory with classes
+ */
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileDirectoryTest {
+    public static void main(String[] args) {
+        OutputAnalyzer oa =JaotcTestHelper.compileLibrary(".");
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+        JaotcTestHelper.checkLibraryUsage(HelloWorldTwo.class.getName());
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java
new file mode 100644
index 0000000..b94265a
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.CompileJarTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ *                                compiler.aot.cli.jaotc.data.HelloWorldTwo
+ * @run driver compiler.aot.cli.jaotc.CompileJarTest
+ * @summary check jaotc can compile jar
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import java.io.IOException;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileJarTest {
+    private static final String JAR_NAME = "test.jar";
+
+    public static void main(String[] args) {
+        createJar();
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary(JAR_NAME);
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName());
+        JaotcTestHelper.checkLibraryUsage(HelloWorldTwo.class.getName());
+    }
+
+    private static void createJar() {
+        JDKToolLauncher jar = JDKToolLauncher.create("jar")
+                .addToolArg("-cf")
+                .addToolArg(JAR_NAME)
+                .addToolArg("-C")
+                .addToolArg(".")
+                .addToolArg(".");
+        OutputAnalyzer oa;
+        try {
+            oa = new OutputAnalyzer(new ProcessBuilder(jar.getCommand()).start());
+        } catch (IOException e) {
+            throw new Error("Problems launching jar: " + e, e);
+        }
+        oa.shouldHaveExitValue(0);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileModuleTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileModuleTest.java
new file mode 100644
index 0000000..4e0ce88
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileModuleTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @run driver compiler.aot.cli.jaotc.CompileModuleTest
+ * @summary check jaotc can compile module
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldTwo;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class CompileModuleTest {
+    private static final String TESTED_CLASS_NAME = HelloWorldTwo.class.getName();
+    private static final String STRING_LENGTH = String.class.getName() + ".length";
+    private static final String COMPILE_COMMAND = "compileOnly " + STRING_LENGTH + ".*";
+    private static final Path COMPILE_COMMAND_FILE = Paths.get("stringLengthOnly.list");
+    private static final String[] EXPECTED = new String[]{
+        JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+        STRING_LENGTH
+    };
+    private static final String[] UNEXPECTED = new String[]{
+        TESTED_CLASS_NAME
+    };
+
+    public static void main(String[] args) {
+        // compile only java.lang.String::length from java.base module to have reasonable compilation time
+        try {
+            Files.write(COMPILE_COMMAND_FILE, Arrays.asList(COMPILE_COMMAND),
+                    StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
+        } catch (IOException e) {
+            throw new Error("TESTBUG: can't write list file " + e, e);
+        }
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands",
+                COMPILE_COMMAND_FILE.toString(), "--module", "java.base");
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(TESTED_CLASS_NAME, EXPECTED, UNEXPECTED);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java
new file mode 100644
index 0000000..06bca2a
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc;
+
+import java.io.File;
+import java.io.IOException;
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+import jdk.test.lib.cli.CommandLineOptionTest;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class JaotcTestHelper {
+    public static final String DEFAULT_LIB_PATH = "./unnamed.so";
+    public static final String DEFAULT_LIBRARY_LOAD_MESSAGE = "loaded    " + DEFAULT_LIB_PATH
+            + "  aot library";
+    private static final String ENABLE_AOT = "-XX:+UseAOT";
+    private static final String AOT_LIBRARY = "-XX:AOTLibrary=" + DEFAULT_LIB_PATH;
+    private static final String PRINT_AOT = "-XX:+PrintAOT";
+
+    public static OutputAnalyzer compileLibrary(String... args) {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jaotc");
+        for (String vmOpt : Utils.getTestJavaOpts()) {
+            launcher.addVMArg(vmOpt);
+        }
+        for (String arg : args) {
+            launcher.addToolArg(arg);
+        }
+        String[] cmd = launcher.getCommand();
+        try {
+            return new OutputAnalyzer(new ProcessBuilder(cmd).start());
+        } catch (IOException e) {
+            throw new Error("Can't start test process: " + e, e);
+        }
+    }
+
+    public static void checkLibraryUsage(String classToRun) {
+        checkLibraryUsage(classToRun, new String[]{DEFAULT_LIBRARY_LOAD_MESSAGE}, null);
+    }
+
+    public static void checkLibraryUsage(String classToRun, String[] expectedOutput,
+            String[] unexpectedOutput) {
+        try {
+            CommandLineOptionTest.verifyJVMStartup(expectedOutput, unexpectedOutput,
+                    "Unexpected exit code", "Unexpected output", ExitCode.OK,
+                    /* addTestVMOpts */ true, ENABLE_AOT, AOT_LIBRARY, PRINT_AOT, classToRun);
+        } catch (Throwable t) {
+            throw new Error("Library usage verification failed: " + t, t);
+        }
+    }
+
+    public static String getClassAotCompilationName(Class<?> classToCompile) {
+        return classToCompile.getName().replaceAll("\\.", File.separator) + ".class";
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java
new file mode 100644
index 0000000..099554f
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.ListOptionNotExistingTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionNotExistingTest
+ * @summary check jaotc can handle situation with missing --compile-commands file
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionNotExistingTest {
+    private static final String COMPILE_ITEM
+            = JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class);
+
+    public static void main(String[] args) {
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", "./notExisting.list",
+                COMPILE_ITEM);
+        int exitCode = oa.getExitValue();
+        Asserts.assertNE(exitCode, 0, "Unexpected compilation exit code");
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertFalse(compiledLibrary.exists(), "Compiler library unexpectedly exists");
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java
new file mode 100644
index 0000000..e0b52f5
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.ListOptionTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionTest
+ * @summary check jaotc can use --compile-commands option successfully and respective compileCommand is applied
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionTest {
+    private static final String TESTED_CLASS_NAME = HelloWorldOne.class.getName();
+    private static final String HELLOWORLDONE_MAIN = TESTED_CLASS_NAME + ".main";
+    private static final String COMPILE_COMMAND = "compileOnly " + HELLOWORLDONE_MAIN + ".*";
+    private static final Path COMPILE_COMMAND_FILE = Paths.get("helloWorldMainMethodOnly.list");
+    private static final String[] EXPECTED = new String[]{
+        JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+        TESTED_CLASS_NAME + ".main"
+    };
+    private static final String[] UNEXPECTED = new String[]{
+        TESTED_CLASS_NAME + ".<init>"
+    };
+
+    public static void main(String[] args) {
+        try {
+            Files.write(COMPILE_COMMAND_FILE, Arrays.asList(COMPILE_COMMAND),
+                    StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
+        } catch (IOException e) {
+            throw new Error("TESTBUG: can't write list file " + e, e);
+        }
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_COMMAND_FILE.toString(),
+                JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class));
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing");
+        Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size");
+        JaotcTestHelper.checkLibraryUsage(TESTED_CLASS_NAME, EXPECTED, UNEXPECTED);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java
new file mode 100644
index 0000000..b3f0d1e
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library / /test/lib /testlibrary
+ * @modules java.base/jdk.internal.misc
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.cli.jaotc.ListOptionWrongFileTest
+ * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
+ * @run driver compiler.aot.cli.jaotc.ListOptionWrongFileTest
+ * @summary check jaotc can handle incorrect --compile-commands file
+ */
+
+package compiler.aot.cli.jaotc;
+
+import compiler.aot.cli.jaotc.data.HelloWorldOne;
+import java.io.File;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class ListOptionWrongFileTest {
+    private static final String TESTED_CLASS_NAME = HelloWorldOne.class.getName();
+    private static final String[] EXPECTED = new String[]{
+        JaotcTestHelper.DEFAULT_LIBRARY_LOAD_MESSAGE,
+        TESTED_CLASS_NAME
+    };
+
+    private static final String COMPILE_ITEM
+            = JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class);
+
+    public static void main(String[] args) {
+        // expecting wrong file to be read but no compilation directive recognized, so, all compiled
+        OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_ITEM, COMPILE_ITEM);
+        oa.shouldHaveExitValue(0);
+        File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH);
+        Asserts.assertTrue(compiledLibrary.exists(), "Expecte compiler library to exist");
+        JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName(), EXPECTED, null);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldOne.java b/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldOne.java
new file mode 100644
index 0000000..a551159
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldOne.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc.data;
+
+public class HelloWorldOne {
+    public static final String MESSAGE = "HelloWorld1";
+
+    public static void main(String args[]) {
+        System.out.println(MESSAGE);
+    }
+}
diff --git a/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldTwo.java b/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldTwo.java
new file mode 100644
index 0000000..487659e
--- /dev/null
+++ b/hotspot/test/compiler/aot/cli/jaotc/data/HelloWorldTwo.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.cli.jaotc.data;
+
+public class HelloWorldTwo {
+    public static final String MESSAGE = "HelloWorld2";
+
+    public static void main(String args[]) {
+        System.out.println(MESSAGE);
+        System.out.println("Message length = " + MESSAGE.length());
+    }
+}
diff --git a/hotspot/test/compiler/aot/fingerprint/CDSDumper.java b/hotspot/test/compiler/aot/fingerprint/CDSDumper.java
new file mode 100644
index 0000000..1041afe
--- /dev/null
+++ b/hotspot/test/compiler/aot/fingerprint/CDSDumper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.fingerprint;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+// Usage:
+// java CDSDumper <classpath> <classlist> <archive> <class1> <class2> ...
+public class CDSDumper {
+    public static void main(String[] args) throws Exception {
+        String classpath = args[0];
+        String classlist = args[1];
+        String archive = args[2];
+
+        // Prepare the classlist
+        FileOutputStream fos = new FileOutputStream(classlist);
+        PrintStream ps = new PrintStream(fos);
+
+        for (int i=3; i<args.length; i++) {
+            ps.println(args[i].replace('.', '/'));
+        }
+        ps.close();
+        fos.close();
+
+        // Dump the archive
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+            "-XX:+UnlockCommercialFeatures",
+            "-XX:+UseAppCDS",
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-cp", classpath,
+            "-XX:ExtraSharedClassListFile=" + classlist,
+            "-XX:SharedArchiveFile=" + archive,
+            "-Xshare:dump",
+            "-XX:+PrintSharedSpaces");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldContain("Loading classes to share");
+        output.shouldHaveExitValue(0);
+    }
+}
diff --git a/hotspot/test/compiler/aot/fingerprint/CDSRunner.java b/hotspot/test/compiler/aot/fingerprint/CDSRunner.java
new file mode 100644
index 0000000..10bd56f
--- /dev/null
+++ b/hotspot/test/compiler/aot/fingerprint/CDSRunner.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+// Usage:
+// java CDSRunner <vmargs> <class> <args> ...
+public class CDSRunner {
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+        System.out.println("[stdout = " + output.getStdout() + "]");
+        System.out.println("[stderr = " + output.getStderr() + "]");
+
+        output.shouldContain("PASSED");
+        output.shouldHaveExitValue(0);
+    }
+}
diff --git a/hotspot/test/compiler/aot/fingerprint/SelfChanged.java b/hotspot/test/compiler/aot/fingerprint/SelfChanged.java
new file mode 100644
index 0000000..f15370e
--- /dev/null
+++ b/hotspot/test/compiler/aot/fingerprint/SelfChanged.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed.
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.fingerprint.SelfChanged
+ *        compiler.aot.AotCompiler
+ *
+ * @run main
+ *      compiler.aot.fingerprint.SelfChanged WRITE-UNMODIFIED-CLASS
+ * @run main/othervm compiler.aot.AotCompiler -libname libSelfChanged.so
+ *      -class compiler.aot.fingerprint.Blah
+ *
+ * @run main/othervm
+ *      compiler.aot.fingerprint.SelfChanged TEST-UNMODIFIED
+ * @run main/othervm -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.SelfChanged TEST-UNMODIFIED
+ *
+ * @run main
+ *      compiler.aot.fingerprint.SelfChanged WRITE-MODIFIED-CLASS
+ * @run main
+ *      compiler.aot.fingerprint.SelfChanged TEST-MODIFIED
+ * @run main/othervm -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.SelfChanged TEST-MODIFIED
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.InMemoryJavaCompiler;
+
+import java.io.*;
+
+class Blah {
+    volatile int z;
+    int getX() {
+        for (z = 0; z < 10000; z++) {
+            if (z % 7 == 1) {
+                z += 2;
+            }
+        }
+        return 0;
+    }
+}
+
+public class SelfChanged {
+    public static void main(String args[]) throws Throwable {
+        Blah f = new Blah();
+        System.out.println("f.getX = " + f.getX());
+        switch (args[0]) {
+        case "WRITE-UNMODIFIED-CLASS":
+            compileClass(false);
+            break;
+        case "WRITE-MODIFIED-CLASS":
+            compileClass(true);
+            break;
+        case "TEST-UNMODIFIED":
+            Asserts.assertTrue(f.getX() == 0, "getX from unmodified Blah class should return 0");
+            break;
+        case "TEST-MODIFIED":
+            Asserts.assertTrue(f.getX() == 1, "getX from modified Blah class should return 1");
+            break;
+        default:
+            throw new RuntimeException("unexpected option: " + args[0]);
+        }
+    }
+
+    static void compileClass(boolean isModified) throws Throwable {
+        String src =
+               "package compiler.aot.fingerprint;"
+             + "public class Blah {"
+             + "    volatile int z;"
+             + "    int getX() {"
+             + "        for (z = 0; z < 10000; z++) {"
+             + "            if (z % 7 == 1) {"
+             + "                z += 2;"
+             + "            }"
+             + "        }"
+             + "        return " + ((isModified) ? "1" : "0") + ";"
+             + "    }"
+             + "    int getY() {return 255;}"
+
+            // The following is for the SelfChangedCDS.java test case. We always load an unmodified
+            // version of Blah from the CDS archive. However, we would load an AOT library that
+            // was compiled using a modified version of Blah. The getX method in this AOT library should
+            // not be used.
+
+            + "    public static void main(String args[]) {"
+             + "        Blah b = new Blah();"
+             + "        int n = b.getX();"
+             + "        if (n != 0) {"
+             + "            throw new RuntimeException(args[0] +  \" : \" + n);"
+             + "        }"
+             + "        System.out.println(\"PASSED\");"
+             + "    }"
+             + "}";
+
+        String filename = System.getProperty("test.classes") + "/compiler/aot/fingerprint/Blah.class";
+        FileOutputStream fos = new FileOutputStream(filename);
+        fos.write(InMemoryJavaCompiler.compile("compiler.aot.fingerprint.Blah", src));
+        fos.close();
+    }
+}
diff --git a/hotspot/test/compiler/aot/fingerprint/SelfChangedCDS.java b/hotspot/test/compiler/aot/fingerprint/SelfChangedCDS.java
new file mode 100644
index 0000000..960c216
--- /dev/null
+++ b/hotspot/test/compiler/aot/fingerprint/SelfChangedCDS.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed (with CDS).
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.fingerprint.SelfChanged
+ *        compiler.aot.AotCompiler
+ *
+ * @run main compiler.aot.fingerprint.SelfChanged WRITE-UNMODIFIED-CLASS
+ * @run main/othervm compiler.aot.AotCompiler -libname libSelfChanged.so
+ *      -class compiler.aot.fingerprint.Blah
+ *
+ * @run main ClassFileInstaller -jar SelfChangedCDS.jar compiler.aot.fingerprint.Blah
+ * @run main compiler.aot.fingerprint.CDSDumper SelfChangedCDS.jar SelfChangedCDS.classlist SelfChangedCDS.jsa
+ *      compiler.aot.fingerprint.Blah
+ *
+ * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ *      compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ *      -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=SelfChangedCDS.jsa
+ *      -Xshare:auto -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -showversion
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.Blah TEST-UNMODIFIED
+ *
+ * @run main
+ *      compiler.aot.fingerprint.SelfChanged WRITE-MODIFIED-CLASS
+ * @run main/othervm compiler.aot.AotCompiler -libname libSelfChanged.so
+ *      -class compiler.aot.fingerprint.Blah
+ *
+ * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ *      compiler.aot.fingerprint.Blah TEST-MODIFIED
+ * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar
+ *      -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so
+ *      -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=SelfChangedCDS.jsa
+ *      -Xshare:auto -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -showversion
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.Blah TEST-MODIFIED
+ */
diff --git a/hotspot/test/compiler/aot/fingerprint/SuperChanged.java b/hotspot/test/compiler/aot/fingerprint/SuperChanged.java
new file mode 100644
index 0000000..253eee0
--- /dev/null
+++ b/hotspot/test/compiler/aot/fingerprint/SuperChanged.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary AOT methods should be swept if a super class has changed.
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @build compiler.aot.fingerprint.SuperChanged
+ *        compiler.aot.AotCompiler
+ *
+ * @run main
+ *      compiler.aot.fingerprint.SuperChanged WRITE-UNMODIFIED-CLASS
+ * @run main/othervm compiler.aot.AotCompiler -libname libSuperChanged.so
+ *      -class compiler.aot.fingerprint.Foo
+ *
+ * @run main
+ *      compiler.aot.fingerprint.SuperChanged TEST-UNMODIFIED
+ * @run main/othervm -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSuperChanged.so
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.SuperChanged TEST-UNMODIFIED
+  *
+ * @run main
+ *      compiler.aot.fingerprint.SuperChanged WRITE-MODIFIED-CLASS
+ * @run main
+ *      compiler.aot.fingerprint.SuperChanged TEST-MODIFIED
+ * @run main/othervm -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSuperChanged.so
+ *      -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace
+ *      compiler.aot.fingerprint.SuperChanged TEST-MODIFIED
+ */
+
+package compiler.aot.fingerprint;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.InMemoryJavaCompiler;
+
+import java.io.*;
+
+class Bar {
+    volatile int x = 0;
+    volatile int y = 1;
+}
+
+class Foo extends Bar {
+
+    volatile int z;
+    int getX() {
+        for (z = 0; z < 10000; z++) {
+            if (z % 7 == 1) {
+                z += 2;
+            }
+        }
+        return x;
+    }
+}
+
+public class SuperChanged {
+    public static void main(String args[]) throws Throwable {
+        Foo f = new Foo();
+        System.out.println("f.getX = " + f.getX());
+        switch (args[0]) {
+        case "WRITE-UNMODIFIED-CLASS":
+            compileClass(false);
+            break;
+        case "WRITE-MODIFIED-CLASS":
+            compileClass(true);
+            break;
+        case "TEST-UNMODIFIED":
+            Asserts.assertTrue(f.getX() == 0, "getX from unmodified Foo class should return 0");
+            break;
+        case "TEST-MODIFIED":
+            Asserts.assertTrue(f.getX() == 1, "getX from modified Foo class should return 1");
+            break;
+        default:
+            throw new RuntimeException("unexpected option: " + args[0]);
+        }
+    }
+
+    static void compileClass(boolean isModified) throws Throwable {
+        String class_src_0 = "package compiler.aot.fingerprint; class Bar {volatile int x = 0;  volatile int y = 1;}";
+        String class_src_1 = "package compiler.aot.fingerprint; class Bar {volatile int y = 0;  volatile int x = 1;}";
+        String src = (isModified) ? class_src_1 : class_src_0;
+
+        String filename = System.getProperty("test.classes") + "/compiler/aot/fingerprint/Bar.class";
+        FileOutputStream fos = new FileOutputStream(filename);
+        fos.write(InMemoryJavaCompiler.compile("compiler.aot.fingerprint.Bar", src));
+        fos.close();
+    }
+}
diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.jnilibelf.test/src/jdk/tools/jaotc/jnilibelf/test/JNILibELFTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.jnilibelf.test/src/jdk/tools/jaotc/jnilibelf/test/JNILibELFTest.java
new file mode 100644
index 0000000..9e5707a
--- /dev/null
+++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.jnilibelf.test/src/jdk/tools/jaotc/jnilibelf/test/JNILibELFTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc.jnilibelf.test;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import jdk.tools.jaotc.jnilibelf.JNIELFContainer;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd;
+import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
+
+public class JNILibELFTest {
+
+    public static void main(String[] args) {
+        // if (args.length != 2) {
+        // System.out.println("Please provide file-name as argument");
+        // return;
+        // }
+        createSharedLib();
+    }
+
+    private static boolean createSharedLib() {
+
+        int numProgHdrs = 1;
+        JNIELFContainer elfContainer = new JNIELFContainer("ELF");
+
+        // Allocate ELF Header
+        elfContainer.createELFHeader(ELF.ET_DYN);
+
+        // Allocate 'numProgHdrs' program headers
+
+        if (!elfContainer.createProgramHeader(numProgHdrs)) {
+            System.out.println("Failed to create Program Headers");
+            return false;
+        }
+
+        // Hash table content
+        int[] bhashWords = {0x01234567, 0x89abcdef, 0xdeadc0de};
+        // int[] data = { 100, 200, 300, 400 };
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(bhashWords.length * 4);
+        IntBuffer intBuffer = byteBuffer.asIntBuffer();
+        intBuffer.put(bhashWords);
+
+        // byte[] int_hash_array = byteBuffer.array();
+
+        // Hash Table content
+        // ByteBuffer hash_words = ByteBuffer.allocate(14).putInt(0x01234567);
+        // hash_words.putInt(0x89abcdef);
+        // hash_words.putInt(0xdeadc0de);
+
+        // Create a hash section
+        // Setting sh_link as 0 since this is just a demo - the value should actually be the section
+        // header index
+        // of the symbol table to which the hash table applies.
+        int index = elfContainer.createSection(".hash", byteBuffer.array(), Elf_Type.ELF_T_WORD, 4, ELF.SHT_HASH, ELF.SHF_ALLOC, 0, 0);
+        if (index == 0) {
+            System.out.println("Failed to create hash section");
+            return false;
+        }
+
+        elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, (ELF.SHF_STRINGS | ELF.SHF_ALLOC), ELF.SHN_UNDEF, 0);
+        // Now, finally, after creating all sections, create shstrtab section
+        elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
+        // Run elf_update
+        elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL);
+
+        // Set program header type to self
+        elfContainer.setProgHdrTypeToSelf();
+        // Setting pheader to self type also sets it to be dirty. So run elfUpdate again
+        // to write it out.
+        elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE);
+        // Finish ELF processing
+        elfContainer.elfEnd();
+        return true;
+    }
+}
diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
new file mode 100644
index 0000000..1b9a1a4
--- /dev/null
+++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @requires os.family == "linux" & vm.bits == "64" & os.arch == "amd64"
+ * @modules jdk.aot/jdk.tools.jaotc.utils
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.tools.jaotc.test.NativeOrderOutputStreamTest
+ */
+
+package jdk.tools.jaotc.test;
+
+import jdk.tools.jaotc.utils.NativeOrderOutputStream;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class NativeOrderOutputStreamTest {
+
+    private NativeOrderOutputStream target;
+
+    @Before
+    public void setup() {
+        target = new NativeOrderOutputStream();
+    }
+
+    @Test
+    public void shouldAdd4BytesForInt() {
+        target.putInt(5);
+        Assert.assertEquals(4, target.position());
+    }
+
+    @Test
+    public void shouldAdd8BytesForLong() {
+        target.putLong(8);
+        Assert.assertEquals(8, target.position());
+    }
+
+    @Test
+    public void shouldHaveCorrectSizeBeforePatch() {
+        target.patchableInt();
+        Assert.assertEquals(4, target.position());
+    }
+
+    @Test
+    public void shouldHaveCorrectSizeAfterPatch() {
+        NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+        patchableInt.set(12);
+        Assert.assertEquals(4, target.position());
+    }
+
+    @Test
+    public void shouldSetCorrectValueInPatch() {
+        NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+        patchableInt.set(42);
+        Assert.assertEquals(42, getInt(0));
+    }
+
+    private int getInt(int pos) {
+        ByteBuffer buffer = ByteBuffer.wrap(target.array());
+        buffer.order(ByteOrder.nativeOrder());
+        return buffer.getInt(pos);
+    }
+
+    @Test
+    public void shouldPutArrayCorrectly() {
+        target.put(new byte[]{42, 5, 43, 44});
+        Assert.assertEquals(4, target.position());
+        Assert.assertEquals(42, target.array()[0]);
+        Assert.assertEquals(4, target.position());
+    }
+
+    @Test
+    public void shouldOnlyPatchSlot() {
+        NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+        target.putInt(7);
+        patchableInt.set(39);
+        Assert.assertEquals(39, getInt(0));
+        Assert.assertEquals(7, getInt(4));
+    }
+
+    @Test
+    public void shouldBeAbleToPatchAnywhere() {
+        target.putInt(19);
+        NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+        patchableInt.set(242);
+
+        Assert.assertEquals(19, getInt(0));
+        Assert.assertEquals(242, getInt(4));
+    }
+
+    @Test
+    public void shouldHavePatchableAtRightOffset() {
+        target.putInt(27);
+        Assert.assertEquals(4, target.position());
+        NativeOrderOutputStream.PatchableInt patchableInt = target.patchableInt();
+        Assert.assertEquals(4, patchableInt.position());
+    }
+
+    @Test
+    public void shouldAlign() {
+        target.putInt(9);
+        target.align(16);
+        target.put(new byte[]{3});
+        target.align(8);
+        Assert.assertEquals(24, target.position());
+    }
+}
diff --git a/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java b/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java
new file mode 100644
index 0000000..b274138
--- /dev/null
+++ b/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.ClassAndLibraryNotMatchTest
+ * @run driver compiler.aot.verification.ClassAndLibraryNotMatchTest
+ * @summary check if class and aot library are properly bound to each other
+ */
+
+package compiler.aot.verification;
+
+import compiler.aot.AotCompiler;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class ClassAndLibraryNotMatchTest {
+    private static final String HELLO_WORLD_CLASS_NAME = "HelloWorld";
+    private static final String LIB_NAME = "lib" + HELLO_WORLD_CLASS_NAME + ".so";
+    private static final String HELLO_WORLD_MSG1 = "HelloWorld1";
+    private static final String HELLO_WORLD_MSG2 = "HelloWorld2";
+    private static final String HELLO_WORLD_FILE = "./" + HELLO_WORLD_CLASS_NAME + ".java";
+    private static final String HELLO_WORLD_PRE = "public class "
+            + HELLO_WORLD_CLASS_NAME + " {\n"
+            + "    public static void main(String args[]) {\n"
+            + "        System.out.println(\"";
+    private static final String HELLO_WORLD_POST = "\");\n"
+            + "    }\n"
+            + "}\n";
+
+    public static void main(String args[]) {
+        new ClassAndLibraryNotMatchTest().runTest();
+    }
+
+    private void writeHelloWorld(String message) {
+        String src = HELLO_WORLD_PRE + message + HELLO_WORLD_POST;
+        try{
+            Files.write(Paths.get(HELLO_WORLD_FILE), src.getBytes(), StandardOpenOption.CREATE);
+        } catch (IOException e) {
+            throw new Error("Can't write HelloWorld " + e, e);
+        }
+    }
+
+    private void compileHelloWorld() {
+        String javac = JDKToolFinder.getCompileJDKTool("javac");
+        ProcessBuilder pb = new ProcessBuilder(javac, HELLO_WORLD_FILE);
+        OutputAnalyzer oa;
+        try {
+            oa = ProcessTools.executeProcess(pb);
+        } catch (Exception e) {
+            throw new Error("Can't compile class " + e, e);
+        }
+        oa.shouldHaveExitValue(0);
+    }
+
+    private void compileAotLibrary() {
+        AotCompiler.launchCompiler(LIB_NAME, HELLO_WORLD_CLASS_NAME + ".class",
+                Arrays.asList("-classpath", Utils.TEST_CLASS_PATH + File.pathSeparator
+                        + Utils.TEST_SRC), null);
+    }
+
+    private void runAndCheckHelloWorld(String checkString) {
+        ProcessBuilder pb;
+        try {
+            pb = ProcessTools.createJavaProcessBuilder(true, "-cp", ".",
+                    "-XX:+UseAOT", "-XX:AOTLibrary=./" + LIB_NAME,
+                    HELLO_WORLD_CLASS_NAME);
+        } catch (Exception e) {
+            throw new Error("Can't create ProcessBuilder to run "
+                    + HELLO_WORLD_CLASS_NAME + " " + e, e);
+        }
+        OutputAnalyzer oa;
+        try {
+            oa = ProcessTools.executeProcess(pb);
+        } catch (Exception e) {
+            throw new Error("Can't execute " + HELLO_WORLD_CLASS_NAME + " " + e, e);
+        }
+        oa.shouldHaveExitValue(0);
+        oa.shouldContain(checkString);
+    }
+
+    private void createHelloWorld(String msg) {
+        writeHelloWorld(msg);
+        compileHelloWorld();
+    }
+
+    private void runTest() {
+        createHelloWorld(HELLO_WORLD_MSG1);
+        compileAotLibrary();
+        runAndCheckHelloWorld(HELLO_WORLD_MSG1);
+        createHelloWorld(HELLO_WORLD_MSG2);
+        runAndCheckHelloWorld(HELLO_WORLD_MSG2);
+    }
+}
diff --git a/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java b/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java
new file mode 100644
index 0000000..bc60c1c
--- /dev/null
+++ b/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.aot.verification.vmflags;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+import compiler.aot.HelloWorldPrinter;
+import compiler.aot.AotCompiler;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class with common launch and check logic for testing vm flags change
+ */
+public class BasicFlagsChange {
+    private static final boolean CAN_LOAD = true;
+    /**
+     * A main method which parse arguments, expecting vm option name to
+     *     be present, launch java process with combinations of provided flag
+     *     enabled/disable in aot library and vm flag expecting different flag
+     *     values in library and vm to be negative cases
+     * @param args should have true/false treated as "loadAlways" for
+     *     tracked/non-tracked options and vm option name
+     */
+    public static void main(String args[]) {
+        if (args.length != 2) {
+            throw new Error("TESTBUG: Unexpected number of arguments: "
+                    + args.length);
+        }
+        if (!"false".equals(args[0]) && !"true".equals(args[0])) {
+            throw new Error("TESTBUG: unexpected value of 1st parameter: "
+                    + args[0]);
+        }
+        boolean loadAlways = Boolean.parseBoolean(args[0]);
+        String optName = args[1];
+        String optEnabled = "-XX:+" + optName;
+        String optDisabled = "-XX:-" + optName;
+        String enabledLibName = "libEnabled.so";
+        String disabledLibName = "libDisabled.so";
+        // compile libraries
+        compileLibrary(optEnabled, enabledLibName);
+        compileLibrary(optDisabled, disabledLibName);
+        // run 4 combinations
+        runAndCheck(optEnabled, enabledLibName, CAN_LOAD || loadAlways);
+        runAndCheck(optDisabled, enabledLibName, !CAN_LOAD || loadAlways);
+        runAndCheck(optEnabled, disabledLibName, !CAN_LOAD || loadAlways);
+        runAndCheck(optDisabled, disabledLibName, CAN_LOAD || loadAlways);
+    }
+
+    private static void compileLibrary(String option, String libName) {
+        String className = BasicFlagsChange.class.getName();
+        List<String> extraOpts = new ArrayList<>();
+        extraOpts.add(option);
+        extraOpts.add("-classpath");
+        extraOpts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC);
+        AotCompiler.launchCompiler(libName, className + ".class", extraOpts, null);
+    }
+
+    private static void runAndCheck(String option, String libName,
+            boolean positiveCase) {
+        ProcessBuilder pb;
+        try {
+            /* using +PrintAOT to check if library has been loaded or skipped,
+               so, a message like "skipped $pathTolibrary aot library" or
+               "loaded    $pathToLibrary  aot library" is present for cases of
+               incompatible or compatible flags respectively */
+            pb = ProcessTools.createJavaProcessBuilder(true, "-XX:+UseAOT",
+                    "-XX:+PrintAOT", "-XX:AOTLibrary=./" + libName, option,
+                    HelloWorldPrinter.class.getName());
+        } catch (Exception ex) {
+            throw new Error("Problems creating ProcessBuilder using " + option
+                    + " Caused by: " + ex, ex);
+        }
+        OutputAnalyzer oa;
+        try {
+            oa = ProcessTools.executeProcess(pb);
+        } catch (Exception ex) {
+            throw new Error("Problems execution child process using case "
+                    + option + " Caused by: " + ex, ex);
+        }
+        oa.shouldHaveExitValue(0);
+        oa.shouldContain(HelloWorldPrinter.MESSAGE);
+        if (positiveCase) {
+            oa.shouldContain("loaded    ./" + libName + "  aot library");
+        } else {
+            oa.shouldContain("skipped ./" + libName + "  aot library");
+        }
+    }
+}
diff --git a/hotspot/test/compiler/aot/verification/vmflags/NotTrackedFlagTest.java b/hotspot/test/compiler/aot/verification/vmflags/NotTrackedFlagTest.java
new file mode 100644
index 0000000..203bd32
--- /dev/null
+++ b/hotspot/test/compiler/aot/verification/vmflags/NotTrackedFlagTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.vmflags.BasicFlagsChange
+ * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
+ *     true PrintCommandLineFlags
+ * @summary check if some not aot-related vm flag change doesn't affect aot library loading
+ */
diff --git a/hotspot/test/compiler/aot/verification/vmflags/TrackedFlagTest.java b/hotspot/test/compiler/aot/verification/vmflags/TrackedFlagTest.java
new file mode 100644
index 0000000..4f6bb01
--- /dev/null
+++ b/hotspot/test/compiler/aot/verification/vmflags/TrackedFlagTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib /
+ * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux"
+ * @modules java.base/jdk.internal.misc
+ * @build compiler.aot.verification.vmflags.BasicFlagsChange
+ * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
+ *      false UseCompressedOops
+ * @summary check if tracked flag UseCompressedOops is controlled properly
+ */
+
diff --git a/hotspot/test/compiler/calls/common/CallsBase.java b/hotspot/test/compiler/calls/common/CallsBase.java
index 44549a3..5d49992 100644
--- a/hotspot/test/compiler/calls/common/CallsBase.java
+++ b/hotspot/test/compiler/calls/common/CallsBase.java
@@ -82,16 +82,16 @@
      */
     protected final boolean compilationLevelsSupported() {
         int[] compLevels = CompilerUtils.getAvailableCompilationLevels();
-        boolean callerCompLevelSupported = compileCaller > 0
+        boolean callerCompLevelSupported = compileCaller <= 0 || (compileCaller > 0
                 && Arrays.stream(compLevels)
                         .filter(elem -> elem == compileCaller)
                         .findAny()
-                        .isPresent();
-        boolean calleeCompLevelSupported = compileCallee > 0
+                        .isPresent());
+        boolean calleeCompLevelSupported = compileCallee <= 0 || (compileCallee > 0
                 && Arrays.stream(compLevels)
                         .filter(elem -> elem == compileCallee)
                         .findAny()
-                        .isPresent();
+                        .isPresent());
         return callerCompLevelSupported && calleeCompLevelSupported;
     }
 
diff --git a/hotspot/test/compiler/ciReplay/SABase.java b/hotspot/test/compiler/ciReplay/SABase.java
index 731e256..0354835 100644
--- a/hotspot/test/compiler/ciReplay/SABase.java
+++ b/hotspot/test/compiler/ciReplay/SABase.java
@@ -39,7 +39,12 @@
 public class SABase extends CiReplayBase {
     private static final String REPLAY_FILE_COPY = "replay_vm.txt";
 
-    public static void main(String args[]) {
+    public static void main(String args[]) throws Exception {
+        if (!Platform.shouldSAAttach()) {
+            System.out.println("SA attach not expected to work - test skipped.");
+            return;
+        }
+
         checkSetLimits();
         new SABase(args).runTest(/* needCoreDump = */ true, args);
     }
diff --git a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
index ea2d192..1e8f790 100644
--- a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
+++ b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
@@ -42,12 +42,11 @@
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLConnection;
+import compiler.whitebox.CompilerWhiteBoxTest;
 
 public class TestAnonymousClassUnloading {
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
-    private static int COMP_LEVEL_SIMPLE = 1;
-    private static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 
     /**
      * We override hashCode here to be able to access this implementation
@@ -87,9 +86,9 @@
         // Check if already compiled
         if (!WHITE_BOX.isMethodCompiled(m)) {
             // If not, try to compile it with C2
-            if(!WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION)) {
+            if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
                 // C2 compiler not available, try to compile with C1
-                WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_SIMPLE);
+                WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
             }
             // Because background compilation is disabled, method should now be compiled
             if(!WHITE_BOX.isMethodCompiled(m)) {
diff --git a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java
index 9b0598f..b5d74dd 100644
--- a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java
+++ b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java
@@ -46,14 +46,13 @@
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLClassLoader;
+import compiler.whitebox.CompilerWhiteBoxTest;
 
 public class TestMethodUnloading {
     private static final String workerClassName = "compiler.classUnloading.methodUnloading.WorkerClass";
     private static int work = -1;
 
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
-    private static int COMP_LEVEL_SIMPLE = 1;
-    private static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 
     /**
      * Does some work by either using the workerClass or locally producing values.
@@ -93,9 +92,9 @@
         // Check if already compiled
         if (!WHITE_BOX.isMethodCompiled(m)) {
             // If not, try to compile it with C2
-            if(!WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION)) {
+            if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
                 // C2 compiler not available, try to compile with C1
-                WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_SIMPLE);
+                WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
             }
             // Because background compilation is disabled, method should now be compiled
             if(!WHITE_BOX.isMethodCompiled(m)) {
diff --git a/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java
index 0392afe..535e702 100644
--- a/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java
+++ b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *
- * @ignore 8166554
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java b/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java
index ed76061..cb474d0 100644
--- a/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java
+++ b/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  * @library /test/lib /
  *
- * @ignore 8140405
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/compiler/floatingpoint/TestFMA.java b/hotspot/test/compiler/floatingpoint/TestFMA.java
new file mode 100644
index 0000000..196b799
--- /dev/null
+++ b/hotspot/test/compiler/floatingpoint/TestFMA.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2016, Red Hat, Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8162338
+ * @summary intrinsify fused mac operations
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestFMA
+ *
+ */
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+// Test all fused mac instructions that can be generated
+public class TestFMA {
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = 57.0F)
+    static float test1(float a, float b, float c) {
+        return Math.fma(a, b, c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = 57.0D)
+    static double test2(double a, double b, double c) {
+        return Math.fma(a, b, c);
+    }
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = -43.0F)
+    static float test3(float a, float b, float c) {
+        return Math.fma(-a, b, c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = -43.0D)
+    static double test4(double a, double b, double c) {
+        return Math.fma(-a, b, c);
+    }
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = -43.0F)
+    static float test5(float a, float b, float c) {
+        return Math.fma(a, -b, c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = -43.0D)
+    static double test6(double a, double b, double c) {
+        return Math.fma(a, -b, c);
+    }
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = -57.0F)
+    static float test7(float a, float b, float c) {
+        return Math.fma(-a, b, -c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = -57.0D)
+    static double test8(double a, double b, double c) {
+        return Math.fma(-a, b, -c);
+    }
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = -57.0F)
+    static float test9(float a, float b, float c) {
+        return Math.fma(a, -b, -c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = -57.0D)
+    static double test10(double a, double b, double c) {
+        return Math.fma(a, -b, -c);
+    }
+
+    @Test(args = {5.0F, 10.0F, 7.0F}, res = 43.0F)
+    static float test11(float a, float b, float c) {
+        return Math.fma(a, b, -c);
+    }
+
+    @Test(args = {5.0D, 10.0D, 7.0D}, res = 43.0D)
+    static double test12(double a, double b, double c) {
+        return Math.fma(a, b, -c);
+    }
+
+    static public void main(String[] args) throws Exception {
+        TestFMA t = new TestFMA();
+        for (Method m : t.getClass().getDeclaredMethods()) {
+            if (m.getName().matches("test[0-9]+?")) {
+                t.doTest(m);
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Test {
+        double[] args();
+        double res();
+    }
+
+    void doTest(Method m) throws Exception {
+        String name = m.getName();
+        System.out.println("Testing " + name);
+        Class retType = m.getReturnType();
+        Test test = m.getAnnotation(Test.class);
+        double[] args = test.args();
+        double expected = test.res();
+
+        for (int i = 0; i < 20000; i++) {
+            if (retType == double.class) {
+                Object res = m.invoke(null, (double)args[0], (double)args[1], (double)args[2]);
+                if ((double)res != expected) {
+                    throw new RuntimeException(name + " failed : " + (double)res + " != " + expected);
+                }
+            } else {
+                Object res = m.invoke(null, (float)args[0], (float)args[1], (float)args[2]);
+                if ((float)res != (float)expected) {
+                    throw new RuntimeException(name + " failed : " + (float)res + " != " + (float)expected);
+                }
+            }
+        }
+    }
+}
diff --git a/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java b/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java
index 3523aa6..155956c 100644
--- a/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java
+++ b/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java
@@ -25,7 +25,7 @@
  * @test
  * @bug 8138651
  * @modules java.base/jdk.internal.misc
- * @library /test/lib
+ * @library /test/lib /
  *
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
@@ -44,6 +44,7 @@
 
 import jdk.test.lib.Platform;
 import sun.hotspot.WhiteBox;
+import compiler.whitebox.CompilerWhiteBoxTest;
 
 import java.lang.reflect.Executable;
 import java.util.Objects;
@@ -52,12 +53,6 @@
 
     private static final WhiteBox wb = WhiteBox.getWhiteBox();
 
-    /* Compilation level corresponding to C1. */
-    private static final int COMP_LEVEL_SIMPLE = 1;
-
-    /* Compilation level corresponding to C2. */
-    private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
-
     /* Determine if tiered compilation is enabled. */
     private static final boolean TIERED_COMPILATION = wb.getBooleanVMFlag("TieredCompilation");
 
@@ -202,13 +197,13 @@
     }
 
     public static void main(String args[]) {
-        if (Platform.isServer() && (TIERED_STOP_AT_LEVEL == COMP_LEVEL_FULL_OPTIMIZATION)) {
+        if (Platform.isServer() && (TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
             if (TIERED_COMPILATION) {
-                test(COMP_LEVEL_SIMPLE);
+                test(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
             }
-            test(COMP_LEVEL_FULL_OPTIMIZATION);
+            test(CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
         } else {
-            test(COMP_LEVEL_SIMPLE);
+            test(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
         }
     }
 }
diff --git a/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java b/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java
index 42e312c..a8c3455 100644
--- a/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java
+++ b/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java
@@ -29,7 +29,7 @@
  * @requires vm.flavor == "server"
  * @modules java.base/jdk.internal.misc:open
  * @modules java.base/java.math:open
- * @library /test/lib
+ * @library /test/lib /
  *
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
@@ -42,6 +42,7 @@
 
 import jdk.test.lib.Platform;
 import sun.hotspot.WhiteBox;
+import compiler.whitebox.CompilerWhiteBoxTest;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -57,9 +58,6 @@
 
     private static final WhiteBox wb = WhiteBox.getWhiteBox();
 
-    /* Compilation level corresponding to C2. */
-    private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
-
     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
 
     static final MethodHandle montgomeryMultiplyHandle, montgomerySquareHandle;
@@ -319,8 +317,8 @@
         if (!Platform.isServer()) {
             throw new Error("TESTBUG: Not server VM");
         }
-        if (wb.isIntrinsicAvailable(getExecutable(true), COMP_LEVEL_FULL_OPTIMIZATION) &&
-                wb.isIntrinsicAvailable(getExecutable(false), COMP_LEVEL_FULL_OPTIMIZATION)) {
+        if (wb.isIntrinsicAvailable(getExecutable(true), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) &&
+                wb.isIntrinsicAvailable(getExecutable(false), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
             try {
                 new MontgomeryMultiplyTest().testMontgomeryMultiplyChecks();
                 new MontgomeryMultiplyTest().testResultValues();
diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
index b5aeffb..10ae924 100644
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
@@ -54,18 +54,18 @@
             if (TIERED_COMPILATION) {
                 int max_level = TIERED_STOP_AT_LEVEL;
                 expectedIntrinsicCount = (max_level == COMP_LEVEL_MAX) ? 1 : 0;
-                for (int i = CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE; i <= max_level; ++i) {
+                for (int i = COMP_LEVEL_SIMPLE; i <= max_level; ++i) {
                     deoptimize();
                     compileAtLevel(i);
                 }
             } else {
                 expectedIntrinsicCount = 1;
                 deoptimize();
-                compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_MAX);
+                compileAtLevel(COMP_LEVEL_MAX);
             }
         } else {
             deoptimize();
-            compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
+            compileAtLevel(COMP_LEVEL_SIMPLE);
         }
 
         if (!isIntrinsicAvailable()) {
diff --git a/hotspot/test/compiler/intrinsics/sha/cli/SHAOptionsBase.java b/hotspot/test/compiler/intrinsics/sha/cli/SHAOptionsBase.java
index 7dd2154..120f102 100644
--- a/hotspot/test/compiler/intrinsics/sha/cli/SHAOptionsBase.java
+++ b/hotspot/test/compiler/intrinsics/sha/cli/SHAOptionsBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,7 +74,7 @@
      *         instructions required by the option are not supported.
      */
     public static String getWarningForUnsupportedCPU(String optionName) {
-        if (Platform.isSparc() || Platform.isAArch64() ||
+        if (Platform.isAArch64() || Platform.isS390x() || Platform.isSparc() ||
             Platform.isX64() || Platform.isX86()) {
             switch (optionName) {
             case SHAOptionsBase.USE_SHA_OPTION:
@@ -89,7 +89,7 @@
                 throw new Error("Unexpected option " + optionName);
             }
         } else {
-            throw new Error("Support for CPUs different fromn X86, SPARC, and AARCH64 "
+            throw new Error("Support for CPUs different fromn AARCH64, S390x, SPARC, and X86 "
                             + "is not implemented");
         }
     }
diff --git a/hotspot/test/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java b/hotspot/test/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java
index 9d89494..698afa0 100644
--- a/hotspot/test/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java
+++ b/hotspot/test/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java
@@ -37,11 +37,12 @@
 public class GenericTestCaseForOtherCPU extends
         SHAOptionsBase.TestCase {
     public GenericTestCaseForOtherCPU(String optionName) {
-        // Execute the test case on any CPU except SPARC and X86
+        // Execute the test case on any CPU except AArch64, S390x, SPARC and X86.
         super(optionName, new NotPredicate(
-                new OrPredicate(
-                    new OrPredicate(Platform::isSparc, Platform::isAArch64),
-                    new OrPredicate(Platform::isX64, Platform::isX86))));
+                              new OrPredicate(Platform::isAArch64,
+                              new OrPredicate(Platform::isS390x,
+                              new OrPredicate(Platform::isSparc,
+                              new OrPredicate(Platform::isX64, Platform::isX86))))));
     }
 
     @Override
diff --git a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java
index 667cb9e..481334f 100644
--- a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java
+++ b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @modules java.base/jdk.internal.misc
  * @modules jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java
index 8a91560..b86cfbf 100644
--- a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java
+++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java b/hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java
index 630780d..4f40c5b 100644
--- a/hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java
+++ b/hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java
@@ -24,7 +24,7 @@
 /*
  * @test TestBasicLogOutput
  * @summary Ensure -XX:-JVMCIPrintProperties can be enabled and successfully prints expected output to stdout.
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib
  */
 
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java
index dbf618d..adfece8 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AsResolvedJavaMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AsResolvedJavaMethodTest.java
index 1234edb..09e8f0e 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/AsResolvedJavaMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/AsResolvedJavaMethodTest.java
@@ -19,13 +19,12 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
- *
  */
 
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java
index 020521b..092acf1 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java
index b3627b7..507c569 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib/
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java
index 13caa19..806c2e7 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java
index f5929d7..9101d2a 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java
index d021356..574604c 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java
index 4c50933..5d7c4d3 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
 package compiler.jvmci.compilerToVM;
 
 import jdk.test.lib.Asserts;
@@ -16,7 +39,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java
index 25cbb97..4f39cf0 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java
index 0c82010..e959482 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java
index 8204043..5dcc9f4 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java
index 98937f9..2aa3937 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java
index fdfe329..af7c9bb 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java
index d9dd305..3811c74 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib/
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java
index e27e85f..33b20f2 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @library ../common/patches
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java
index 503145a..8202d12 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java
index 438eab2..0923e10 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib/
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java
index 110c2cb..0b079f37 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java
index 2349b9e..b50dd8e 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java
@@ -24,7 +24,7 @@
  /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc:+open
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java
index 38adf2f..483f141 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java
@@ -24,14 +24,13 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
  *
- * @ignore 8158860
  * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
  *        jdk.vm.ci/jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject
  *        sun.hotspot.WhiteBox
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java
index 1961de5..0c3e4ba 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java
index 8f46daa..87c4053 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc:+open
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java
index 50c66cc..8cfc1d8 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java
index 6f7f2c2..969a7f6 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java
index 3c92490..57ec63a 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java
index c16e020..828dc77 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
@@ -34,7 +34,6 @@
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.runtime
  *
- * @ignore 8163894
  * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
  * @build compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest
  * @build sun.hotspot.WhiteBox
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java
index 9668ec4..e1427d0 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  *          ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java
index 0c4e466..826868a 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @modules java.base/jdk.internal.misc:open
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot:open
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java
index b619ae0..690ef34 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method
  * @library /test/lib /
  * @library ../common/patches
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java
index e3e7197..e53d695 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java
index 5c8a8cb..f6d139c 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java
index 8c395e3..ed376e0 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java
index 6262c85..e01f023 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java
index 9807fbf..3dc8a64 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java
index 20d57ba..225da69 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java
index c4068a1..dee13cf 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  *         & (vm.compMode != "Xcomp" | vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true)
  * @summary no "-Xcomp -XX:-TieredCompilation" combination allowed until JDK-8140018 is resolved
  * @library / /test/lib
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java
index aa5c55a..6f87bcf 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReadConfigurationTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReadConfigurationTest.java
index b10ef88..866756c 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ReadConfigurationTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadConfigurationTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java
index 3a731c5..9953d4c 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64") & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 3)
+ * @requires vm.jvmci & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 3)
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java
index dc06f68..63aef07 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java
index b6294b9..2ee506b 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java
index f3fd052..248077d 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java
index e78322f..ca91e75 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8138708
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java
index 02b288b..3f48fd2 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method
  * @library /test/lib /
  * @library ../common/patches
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java
index 2e66c2e..18a571b 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib/
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java
index 80d1c35..675a136 100644
--- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java
index 4cc3524..7ef5f8e 100644
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.code.site
diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java
index e4a4d46..8d3e92b 100644
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.code.site
diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java
index ad1a1d5..2e3f5f6 100644
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.code.site
diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java
index fdd7a00..84a4c90 100644
--- a/hotspot/test/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java
+++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8156034
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java
index bec53e6..bb888c3 100644
--- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java
+++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library / /test/lib
  * @library ../common/patches
  * @modules java.base/jdk.internal.misc
diff --git a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java
index dc09736..76f6538 100644
--- a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java
+++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8136421
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @modules java.base/jdk.internal.misc
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java
index c2e3edf..10a968f 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java
index db19e22..05d8bdb 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.code.site
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java
index 4a95328..7896557 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java
index 0800e7b..49a52f8 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /test/lib /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.code
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java
index 1f69fc8..908eaf6 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java
index 85c7b45..6f3833e 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java
index bee4f8d..88625aa 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @requires vm.jvmci & (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9")
  * @library /
  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotConstantReflectionProviderTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotConstantReflectionProviderTest.java
index c820b7e..b3ee631 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotConstantReflectionProviderTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotConstantReflectionProviderTest.java
@@ -23,7 +23,7 @@
 
 /*
  * @test jdk.vm.ci.hotspot.test.HotSpotConstantReflectionProviderTest
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.runtime
  *          jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.hotspot
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderTest.java
index e99f7bb..bbf4c3a 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderTest.java
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 8152341
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /compiler/jvmci/jdk.vm.ci.hotspot.test/src
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.common
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java
index a7d2cdd..153cfc9 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java
@@ -25,7 +25,7 @@
  * @test
  * @bug 8152343
  * @bug 8161068
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /compiler/jvmci/jdk.vm.ci.hotspot.test/src
  * @modules java.base/java.lang.invoke:+open
  * @modules jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java
index 69323c1..fb0f1a2 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java
index f859ddf..8f0ce0c 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java
index 21cdc85..78c5a79 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveConcreteMethodTest
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java
index a32395c..f4b15b2 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveMethodTest
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java
index 5d91756..43cd69f 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java
index 622c25e..7929018 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java
index 5af25f8..a8edfec 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java
index 66e5069..669b579 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java
index 4352654..37d7d52 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java
index 3c15295..48a6dc8 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java
index e5dfb85..c4fc8fc 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
@@ -278,7 +278,7 @@
                 java.lang.reflect.Parameter exp = expected[i];
                 Parameter act = actual[i];
                 assertEquals(exp.getName(), act.getName());
-                assertEquals(exp.getModifiers(), act.getModifiers());
+                assertEquals(exp.isNamePresent(), act.isNamePresent());
                 assertEquals(exp.getModifiers(), act.getModifiers());
                 assertArrayEquals(exp.getAnnotations(), act.getAnnotations());
                 assertEquals(exp.getType().getName(), act.getType().toClassName());
diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java
index be0b055..e8f9f9b 100644
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library ../../../../../
  * @modules java.base/jdk.internal.reflect
  *          jdk.vm.ci/jdk.vm.ci.meta
diff --git a/hotspot/test/compiler/jvmci/meta/StableFieldTest.java b/hotspot/test/compiler/jvmci/meta/StableFieldTest.java
index 25bc2a9..147811f 100644
--- a/hotspot/test/compiler/jvmci/meta/StableFieldTest.java
+++ b/hotspot/test/compiler/jvmci/meta/StableFieldTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 8151664
- * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
+ * @requires vm.jvmci
  * @library /test/lib /
  * @modules java.base/jdk.internal.misc
  * @modules java.base/jdk.internal.vm.annotation
diff --git a/hotspot/test/compiler/startup/SmallCodeCacheStartup.java b/hotspot/test/compiler/startup/SmallCodeCacheStartup.java
index a361baa..8e2e6a1 100644
--- a/hotspot/test/compiler/startup/SmallCodeCacheStartup.java
+++ b/hotspot/test/compiler/startup/SmallCodeCacheStartup.java
@@ -31,7 +31,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *
- * @ignore 8134286
  * @run driver compiler.startup.SmallCodeCacheStartup
  */
 
diff --git a/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java
index 11792d7..98612cd 100644
--- a/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java
+++ b/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,33 +59,35 @@
     };
 
     public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE
-            = new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" },null),
-              new OrPredicate(
-                      new CPUSpecificPredicate("sparc.*", new String[] { "sha1" },null),
-                      new CPUSpecificPredicate("aarch64.*", new String[] { "sha1" },null)))));
+            = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha1" }, null),
+              new OrPredicate(new CPUSpecificPredicate("s390.*",    new String[] { "sha1" }, null),
+              new OrPredicate(new CPUSpecificPredicate("sparc.*",   new String[] { "sha1" }, null),
+              // x86 variants
+              new OrPredicate(new CPUSpecificPredicate("amd64.*",   new String[] { "sha" },  null),
+              new OrPredicate(new CPUSpecificPredicate("i386.*",    new String[] { "sha" },  null),
+                              new CPUSpecificPredicate("x86.*",     new String[] { "sha" },  null))))));
 
     public static final BooleanSupplier SHA256_INSTRUCTION_AVAILABLE
-            = new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] {
-"sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null),
-              new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null),
-              new OrPredicate(
-                      new CPUSpecificPredicate("sparc.*", new String[] { "sha256" },null),
-                      new CPUSpecificPredicate("aarch64.*", new String[] { "sha256" },null)))))));
+            = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha256"       }, null),
+              new OrPredicate(new CPUSpecificPredicate("s390.*",    new String[] { "sha256"       }, null),
+              new OrPredicate(new CPUSpecificPredicate("sparc.*",   new String[] { "sha256"       }, null),
+              // x86 variants
+              new OrPredicate(new CPUSpecificPredicate("amd64.*",   new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("i386.*",    new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("x86.*",     new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("amd64.*",   new String[] { "avx2", "bmi2" }, null),
+                              new CPUSpecificPredicate("x86_64",    new String[] { "avx2", "bmi2" }, null))))))));
 
     public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE
-            = new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" },null),
-              new OrPredicate(new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null),
-              new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null),
-              new OrPredicate(
-                      new CPUSpecificPredicate("sparc.*", new String[] { "sha512" },null),
-                      new CPUSpecificPredicate("aarch64.*", new String[] { "sha512" },null)))))));
+            = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha512"       }, null),
+              new OrPredicate(new CPUSpecificPredicate("s390.*",    new String[] { "sha512"       }, null),
+              new OrPredicate(new CPUSpecificPredicate("sparc.*",   new String[] { "sha512"       }, null),
+              // x86 variants
+              new OrPredicate(new CPUSpecificPredicate("amd64.*",   new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("i386.*",    new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("x86.*",     new String[] { "sha"          }, null),
+              new OrPredicate(new CPUSpecificPredicate("amd64.*",   new String[] { "avx2", "bmi2" }, null),
+                              new CPUSpecificPredicate("x86_64",    new String[] { "avx2", "bmi2" }, null))))))));
 
     public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE
             = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE,
diff --git a/hotspot/test/compiler/tiered/LevelTransitionTest.java b/hotspot/test/compiler/tiered/LevelTransitionTest.java
index 6730c18..ea6a759 100644
--- a/hotspot/test/compiler/tiered/LevelTransitionTest.java
+++ b/hotspot/test/compiler/tiered/LevelTransitionTest.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *
- * @ignore 8067651
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
@@ -266,4 +265,5 @@
         }
     }
 
-}
\ No newline at end of file
+}
+
diff --git a/hotspot/test/compiler/types/correctness/CorrectnessTest.java b/hotspot/test/compiler/types/correctness/CorrectnessTest.java
index 9198a3e..6b588cf 100644
--- a/hotspot/test/compiler/types/correctness/CorrectnessTest.java
+++ b/hotspot/test/compiler/types/correctness/CorrectnessTest.java
@@ -30,7 +30,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *
- * @ignore 8066173
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/compiler/types/correctness/OffTest.java b/hotspot/test/compiler/types/correctness/OffTest.java
index a88387e..7593fc6 100644
--- a/hotspot/test/compiler/types/correctness/OffTest.java
+++ b/hotspot/test/compiler/types/correctness/OffTest.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *
- * @ignore 8066173
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/compiler/uncommontrap/Test8009761.java b/hotspot/test/compiler/uncommontrap/Test8009761.java
index c9f4897..b844efb 100644
--- a/hotspot/test/compiler/uncommontrap/Test8009761.java
+++ b/hotspot/test/compiler/uncommontrap/Test8009761.java
@@ -40,14 +40,12 @@
 package compiler.uncommontrap;
 
 import sun.hotspot.WhiteBox;
-
 import java.lang.reflect.Method;
+import compiler.whitebox.CompilerWhiteBoxTest;
 
 public class Test8009761 {
 
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
-    private static int COMP_LEVEL_SIMPLE = 1;
-    private static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
     private static Method m3 = null;
 
     static Object m1(boolean deopt) {
@@ -263,9 +261,9 @@
         c1 = count;
 
         // Force the compilation of m3() that will inline m1()
-        if(!WHITE_BOX.enqueueMethodForCompilation(m3, COMP_LEVEL_FULL_OPTIMIZATION)) {
+        if(!WHITE_BOX.enqueueMethodForCompilation(m3, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
             // C2 compiler not available, compile with C1
-            WHITE_BOX.enqueueMethodForCompilation(m3, COMP_LEVEL_SIMPLE);
+            WHITE_BOX.enqueueMethodForCompilation(m3, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
         }
 
         // Because background compilation is disabled, method should now be compiled
diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
index bc46d9e..86d15bd 100644
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,9 @@
     /** {@code CompLevel::CompLevel_none} -- Interpreter */
     public static final int COMP_LEVEL_NONE = 0;
     /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
-    public static final int COMP_LEVEL_ANY = -1;
+    public static final int COMP_LEVEL_ANY = -2;
+    /** {@code CompLevel::CompLevel_aot} -- AOT */
+    public static final int COMP_LEVEL_AOT = -1;
     /** {@code CompLevel::CompLevel_simple} -- C1 */
     public static final int COMP_LEVEL_SIMPLE = 1;
     /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation &amp; backedge counters */
diff --git a/hotspot/test/gc/TestFullGCCount.java b/hotspot/test/gc/TestFullGCCount.java
index 9e5dddf..416b18a 100644
--- a/hotspot/test/gc/TestFullGCCount.java
+++ b/hotspot/test/gc/TestFullGCCount.java
@@ -21,10 +21,11 @@
  * questions.
  */
 
-/*
+/**
  * @test TestFullGCCount.java
  * @bug 7072527
  * @summary CMS: JMM GC counters overcount in some cases
+ * @requires !(vm.gc.ConcMarkSweep & vm.opt.ExplicitGCInvokesConcurrent == true)
  * @modules java.management
  * @run main/othervm -Xlog:gc TestFullGCCount
  */
diff --git a/hotspot/test/gc/arguments/TestExplicitGCInvokesConcurrentAndUnloadsClasses.java b/hotspot/test/gc/arguments/TestExplicitGCInvokesConcurrentAndUnloadsClasses.java
new file mode 100644
index 0000000..83f0757
--- /dev/null
+++ b/hotspot/test/gc/arguments/TestExplicitGCInvokesConcurrentAndUnloadsClasses.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestExplicitGCInvokesConcurrentAndUnloadsClasses
+ * @summary Test that the flag ExplicitGCInvokesConcurrentAndUnloadsClasses is deprecated
+ * @bug 8170388
+ * @key gc
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run driver TestExplicitGCInvokesConcurrentAndUnloadsClasses
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class TestExplicitGCInvokesConcurrentAndUnloadsClasses {
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb =
+            ProcessTools.createJavaProcessBuilder("-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses",
+                                                  "-Xlog:gc",
+                                                  "-version");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldContain("ExplicitGCInvokesConcurrentAndUnloadsClasses was deprecated");
+        output.shouldHaveExitValue(0);
+    }
+}
diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java
index 5d6ddba..49d9d9f 100644
--- a/hotspot/test/gc/g1/TestGCLogMessages.java
+++ b/hotspot/test/gc/g1/TestGCLogMessages.java
@@ -73,6 +73,11 @@
     };
 
     private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] {
+        new LogMessageWithLevel("Pre Evacuate Collection Set", Level.INFO),
+        new LogMessageWithLevel("Evacuate Collection Set", Level.INFO),
+        new LogMessageWithLevel("Post Evacuate Collection Set", Level.INFO),
+        new LogMessageWithLevel("Other", Level.INFO),
+
         // Update RS
         new LogMessageWithLevel("Scan HCC", Level.TRACE),
         // Ext Root Scan
@@ -96,20 +101,20 @@
         new LogMessageWithLevel("Redirtied Cards", Level.TRACE),
         // Misc Top-level
         new LogMessageWithLevel("Code Roots Purge", Level.DEBUG),
-        new LogMessageWithLevel("String Dedup Fixup", Level.INFO),
-        new LogMessageWithLevel("Expand Heap After Collection", Level.INFO),
+        new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG),
+        new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
         // Free CSet
-        new LogMessageWithLevel("Free Collection Set", Level.INFO),
-        new LogMessageWithLevel("Free Collection Set Serial", Level.DEBUG),
-        new LogMessageWithLevel("Young Free Collection Set", Level.DEBUG),
-        new LogMessageWithLevel("Non-Young Free Collection Set", Level.DEBUG),
+        new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
+        new LogMessageWithLevel("Free Collection Set Serial", Level.TRACE),
+        new LogMessageWithLevel("Young Free Collection Set", Level.TRACE),
+        new LogMessageWithLevel("Non-Young Free Collection Set", Level.TRACE),
         // Humongous Eager Reclaim
         new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG),
         new LogMessageWithLevel("Humongous Register", Level.DEBUG),
         // Preserve CM Referents
         new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG),
         // Merge PSS
-        new LogMessageWithLevel("Merge Per-Thread State", Level.INFO),
+        new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG),
     };
 
     void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception {
diff --git a/hotspot/test/gc/g1/TestParallelAlwaysPreTouch.java b/hotspot/test/gc/g1/TestParallelAlwaysPreTouch.java
new file mode 100644
index 0000000..75c90d0
--- /dev/null
+++ b/hotspot/test/gc/g1/TestParallelAlwaysPreTouch.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169703
+ * @summary Regression test to ensure AlwaysPreTouch with multiple threads works at mutator time.
+ * Allocates a few humongous objects that will be allocated by expanding the heap, causing concurrent parallel
+ * pre-touch.
+ * @requires vm.gc.G1
+ * @key gc
+ * @key regression
+ * @run main/othervm -XX:+UseG1GC -Xms10M -Xmx100m -XX:G1HeapRegionSize=1M -XX:+AlwaysPreTouch -XX:PreTouchParallelChunkSize=512k -Xlog:gc+ergo+heap=debug,gc+heap=debug,gc=debug TestParallelAlwaysPreTouch
+ */
+
+public class TestParallelAlwaysPreTouch {
+    public static void main(String[] args) throws Exception {
+        final int M = 1024 * 1024; // Something guaranteed to be larger than a region to be counted as humongous.
+
+        for (int i = 0; i < 10; i++) {
+            Object[] obj = new Object[M];
+            System.out.println(obj);
+        }
+    }
+}
+
diff --git a/hotspot/test/gc/g1/TestSharedArchiveWithPreTouch.java b/hotspot/test/gc/g1/TestSharedArchiveWithPreTouch.java
new file mode 100644
index 0000000..183c7c8
--- /dev/null
+++ b/hotspot/test/gc/g1/TestSharedArchiveWithPreTouch.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169703
+ * @summary Verifies that dumping and loading a CDS archive succeeds with AlwaysPreTouch
+ * @requires vm.gc.G1
+ * @key gc
+ * @key regression
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run main TestSharedArchiveWithPreTouch
+ */
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import jdk.test.lib.Platform;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestSharedArchiveWithPreTouch {
+    public static void main(String[] args) throws Exception {
+        final String ArchiveFileName = "./SharedArchiveWithPreTouch.jsa";
+
+        final List<String> BaseOptions = Arrays.asList(new String[] {"-XX:+UseG1GC", "-XX:+AlwaysPreTouch",
+            "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + ArchiveFileName });
+
+        ProcessBuilder pb;
+
+        List<String> dump_args = new ArrayList<String>(BaseOptions);
+
+        if (Platform.is64bit()) {
+          dump_args.addAll(0, Arrays.asList(new String[] { "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops" }));
+        }
+        dump_args.addAll(Arrays.asList(new String[] { "-Xshare:dump" }));
+
+        pb = ProcessTools.createJavaProcessBuilder(dump_args.toArray(new String[0]));
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        try {
+            output.shouldContain("Loading classes to share");
+            output.shouldHaveExitValue(0);
+
+            List<String> load_args = new ArrayList<String>(BaseOptions);
+
+            if (Platform.is64bit()) {
+                load_args.addAll(0, Arrays.asList(new String[] { "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops" }));
+            }
+            load_args.addAll(Arrays.asList(new String[] { "-Xshare:on", "-version" }));
+
+            pb = ProcessTools.createJavaProcessBuilder(load_args.toArray(new String[0]));
+            output = new OutputAnalyzer(pb.start());
+            output.shouldContain("sharing");
+            output.shouldHaveExitValue(0);
+        } catch (RuntimeException e) {
+            // Report 'passed' if CDS was turned off.
+            output.shouldContain("Unable to use shared archive");
+            output.shouldHaveExitValue(1);
+        }
+    }
+}
diff --git a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java
index 7e51d2e..8737788 100644
--- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java
+++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java
@@ -52,7 +52,6 @@
  * @library /test/lib /
  * @modules java.management java.base/jdk.internal.misc
  * @build sun.hotspot.WhiteBox
- * @ignore 8156755
  *
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/gc/g1/logging/TestG1LoggingFailure.java b/hotspot/test/gc/g1/logging/TestG1LoggingFailure.java
index 8f89007..52ee2ef 100644
--- a/hotspot/test/gc/g1/logging/TestG1LoggingFailure.java
+++ b/hotspot/test/gc/g1/logging/TestG1LoggingFailure.java
@@ -66,7 +66,6 @@
         OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()]));
 
         out.shouldNotContain("pure virtual method called");
-        out.shouldContain("Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread \"main\"");
 
         if (out.getExitValue() == 0) {
             System.out.println(out.getOutput());
diff --git a/hotspot/test/gc/stress/TestStressG1Humongous.java b/hotspot/test/gc/stress/TestStressG1Humongous.java
index 501f646..cd951ea 100644
--- a/hotspot/test/gc/stress/TestStressG1Humongous.java
+++ b/hotspot/test/gc/stress/TestStressG1Humongous.java
@@ -21,7 +21,7 @@
  * questions.
  */
 
- /*
+/*
  * @test TestStressG1Humongous
  * @key gc
  * @key stress
@@ -42,8 +42,6 @@
 import java.util.List;
 import java.util.Collections;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class TestStressG1Humongous {
@@ -56,7 +54,7 @@
     private static final int NUMBER_OF_FREE_REGIONS = 2;
 
     private volatile boolean isRunning;
-    private final ExecutorService threadExecutor;
+    private final Thread[] threads;
     private final AtomicInteger alocatedObjectsCount;
     private CountDownLatch countDownLatch;
     public static final List<Object> GARBAGE = Collections.synchronizedList(new ArrayList<>());
@@ -67,12 +65,12 @@
 
     public TestStressG1Humongous() {
         isRunning = true;
-        threadExecutor = Executors.newFixedThreadPool(THREAD_COUNT + 1);
+        threads = new Thread[THREAD_COUNT];
         alocatedObjectsCount = new AtomicInteger(0);
     }
 
     private void run() throws InterruptedException {
-        threadExecutor.submit(new Timer());
+        new Thread(new Timer()).start();
         int checkedAmountOfHObjects = getExpectedAmountOfObjects();
         while (isRunning()) {
             countDownLatch = new CountDownLatch(THREAD_COUNT);
@@ -82,7 +80,6 @@
             System.out.println("Allocated " + alocatedObjectsCount.get() + " objects.");
             alocatedObjectsCount.set(0);
         }
-        threadExecutor.shutdown();
         System.out.println("Done!");
     }
 
@@ -110,9 +107,12 @@
         int objectsPerThread = totalObjects / THREAD_COUNT;
         int objectsForLastThread = objectsPerThread + totalObjects % THREAD_COUNT;
         for (int i = 0; i < THREAD_COUNT - 1; ++i) {
-            threadExecutor.submit(new AllocationThread(countDownLatch, objectsPerThread, alocatedObjectsCount));
+            threads[i] = new Thread(new AllocationThread(countDownLatch, objectsPerThread, alocatedObjectsCount));
         }
-        threadExecutor.submit(new AllocationThread(countDownLatch, objectsForLastThread, alocatedObjectsCount));
+        threads[THREAD_COUNT - 1] = new Thread(new AllocationThread(countDownLatch, objectsForLastThread, alocatedObjectsCount));
+        for (int i = 0; i < THREAD_COUNT; ++i) {
+            threads[i].start();
+        }
     }
 
     /**
diff --git a/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java b/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java
index 5c6dd81..10bd210 100644
--- a/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java
@@ -30,7 +30,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  * @build sun.hotspot.WhiteBox
- * @ignore 8129886
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
diff --git a/hotspot/test/native/gc/g1/test_bufferingOopClosure.cpp b/hotspot/test/native/gc/g1/test_bufferingOopClosure.cpp
new file mode 100644
index 0000000..1bc5118
--- /dev/null
+++ b/hotspot/test/native/gc/g1/test_bufferingOopClosure.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/bufferingOopClosure.hpp"
+#include "memory/iterator.hpp"
+#include "unittest.hpp"
+
+class BufferingOopClosureTest : public ::testing::Test {
+ public:
+  // Helper class to fake a set of oop*s and narrowOop*s.
+  class FakeRoots {
+   public:
+    // Used for sanity checking of the values passed to the do_oops functions in the test.
+    static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1);
+
+    int    _num_narrow;
+    int    _num_full;
+    void** _narrow;
+    void** _full;
+
+    FakeRoots(int num_narrow, int num_full) :
+        _num_narrow(num_narrow),
+        _num_full(num_full),
+        _narrow((void**)::malloc(sizeof(void*) * num_narrow)),
+        _full((void**)::malloc(sizeof(void*) * num_full)) {
+
+      for (int i = 0; i < num_narrow; i++) {
+        _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i);
+      }
+      for (int i = 0; i < num_full; i++) {
+        _full[i] = (void*)(uintptr_t)i;
+      }
+    }
+
+    ~FakeRoots() {
+      ::free(_narrow);
+      ::free(_full);
+    }
+
+    void oops_do_narrow_then_full(OopClosure* cl) {
+      for (int i = 0; i < _num_narrow; i++) {
+        cl->do_oop((narrowOop*)_narrow[i]);
+      }
+      for (int i = 0; i < _num_full; i++) {
+        cl->do_oop((oop*)_full[i]);
+      }
+    }
+
+    void oops_do_full_then_narrow(OopClosure* cl) {
+      for (int i = 0; i < _num_full; i++) {
+        cl->do_oop((oop*)_full[i]);
+      }
+      for (int i = 0; i < _num_narrow; i++) {
+        cl->do_oop((narrowOop*)_narrow[i]);
+      }
+    }
+
+    void oops_do_mixed(OopClosure* cl) {
+      int i;
+      for (i = 0; i < _num_full && i < _num_narrow; i++) {
+        cl->do_oop((oop*)_full[i]);
+        cl->do_oop((narrowOop*)_narrow[i]);
+      }
+      for (int j = i; j < _num_full; j++) {
+        cl->do_oop((oop*)_full[i]);
+      }
+      for (int j = i; j < _num_narrow; j++) {
+        cl->do_oop((narrowOop*)_narrow[i]);
+      }
+    }
+
+    static const int MaxOrder = 2;
+
+    void oops_do(OopClosure* cl, int do_oop_order) {
+      switch(do_oop_order) {
+        case 0:
+          oops_do_narrow_then_full(cl);
+          break;
+        case 1:
+          oops_do_full_then_narrow(cl);
+          break;
+        case 2:
+          oops_do_mixed(cl);
+          break;
+        default:
+          oops_do_narrow_then_full(cl);
+          break;
+      }
+    }
+  };
+
+  class CountOopClosure : public OopClosure {
+    int _narrow_oop_count;
+    int _full_oop_count;
+   public:
+    CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {}
+    void do_oop(narrowOop* p) {
+      EXPECT_NE(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker))
+              << "The narrowOop was unexpectedly not marked with the NarrowOopMarker";
+      _narrow_oop_count++;
+    }
+
+    void do_oop(oop* p){
+      EXPECT_EQ(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker))
+              << "The oop was unexpectedly marked with the NarrowOopMarker";
+      _full_oop_count++;
+    }
+
+    int narrow_oop_count() { return _narrow_oop_count; }
+    int full_oop_count()   { return _full_oop_count; }
+    int all_oop_count()    { return _narrow_oop_count + _full_oop_count; }
+  };
+
+  class DoNothingOopClosure : public OopClosure {
+   public:
+    void do_oop(narrowOop* p) {}
+    void do_oop(oop* p)       {}
+  };
+
+  static void testCount(int num_narrow, int num_full, int do_oop_order) {
+    FakeRoots fr(num_narrow, num_full);
+
+    CountOopClosure coc;
+    BufferingOopClosure boc(&coc);
+
+    fr.oops_do(&boc, do_oop_order);
+
+    boc.done();
+
+    EXPECT_EQ(num_narrow, coc.narrow_oop_count()) << "when running testCount("
+            << num_narrow << ", " << num_full << ", " << do_oop_order << ")";
+
+    EXPECT_EQ(num_full, coc.full_oop_count()) << "when running testCount("
+            << num_narrow << ", " << num_full << ", " << do_oop_order << ")";
+
+    EXPECT_EQ(num_narrow + num_full, coc.all_oop_count()) << "when running testCount("
+            << num_narrow << ", " << num_full << ", " << do_oop_order << ")";
+  }
+
+  static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) {
+    FakeRoots fr(num_narrow, num_full);
+
+    DoNothingOopClosure cl;
+    BufferingOopClosure boc(&cl);
+
+    fr.oops_do(&boc, 0);
+
+    EXPECT_EQ(expect_empty, boc.is_buffer_empty())
+            << "when running testIsBufferEmptyOrFull("
+            << num_narrow << ", " << num_full << ", "
+            << expect_empty << ", " << expect_full << ")";
+
+    EXPECT_EQ(expect_full, boc.is_buffer_full())
+            << "when running testIsBufferEmptyOrFull("
+            << num_narrow << ", " << num_full << ", "
+            << expect_empty << ", " << expect_full << ")";
+  }
+
+  static void testEmptyAfterDone(int num_narrow, int num_full) {
+    FakeRoots fr(num_narrow, num_full);
+
+    DoNothingOopClosure cl;
+    BufferingOopClosure boc(&cl);
+
+    fr.oops_do(&boc, 0);
+
+    // Make sure all get processed.
+    boc.done();
+
+    EXPECT_TRUE(boc.is_buffer_empty()) << "Should be empty after call to done()."
+            << " testEmptyAfterDone(" << num_narrow << ", " << num_full << ")";
+  }
+
+  static int get_buffer_length() {
+    return BufferingOopClosure::BufferLength;
+  }
+};
+
+TEST_VM_F(BufferingOopClosureTest, count_test) {
+  int bl = BufferingOopClosureTest::get_buffer_length();
+
+  for (int order = 0; order < FakeRoots::MaxOrder; order++) {
+    testCount(0,      0,      order);
+    testCount(10,     0,      order);
+    testCount(0,      10,     order);
+    testCount(10,     10,     order);
+    testCount(bl,     10,     order);
+    testCount(10,     bl,     order);
+    testCount(bl,     bl,     order);
+    testCount(bl + 1, 10,     order);
+    testCount(10,     bl + 1, order);
+    testCount(bl + 1, bl,     order);
+    testCount(bl,     bl + 1, order);
+    testCount(bl + 1, bl + 1, order);
+  }
+}
+
+TEST_VM_F(BufferingOopClosureTest, buffer_empty_or_full) {
+  int bl = BufferingOopClosureTest::get_buffer_length();
+
+  testIsBufferEmptyOrFull(0,      0,      true,  false);
+  testIsBufferEmptyOrFull(1,      0,      false, false);
+  testIsBufferEmptyOrFull(0,      1,      false, false);
+  testIsBufferEmptyOrFull(1,      1,      false, false);
+  testIsBufferEmptyOrFull(10,     0,      false, false);
+  testIsBufferEmptyOrFull(0,      10,     false, false);
+  testIsBufferEmptyOrFull(10,     10,     false, false);
+  testIsBufferEmptyOrFull(0,      bl,     false, true);
+  testIsBufferEmptyOrFull(bl,     0,      false, true);
+  testIsBufferEmptyOrFull(bl / 2, bl / 2, false, true);
+  testIsBufferEmptyOrFull(bl - 1, 1,      false, true);
+  testIsBufferEmptyOrFull(1,      bl - 1, false, true);
+  // Processed
+  testIsBufferEmptyOrFull(bl + 1, 0,      false, false);
+  testIsBufferEmptyOrFull(bl * 2, 0,      false, true);
+}
+
+TEST_VM_F(BufferingOopClosureTest, empty_after_done) {
+  int bl = BufferingOopClosureTest::get_buffer_length();
+
+  testEmptyAfterDone(0,      0);
+  testEmptyAfterDone(1,      0);
+  testEmptyAfterDone(0,      1);
+  testEmptyAfterDone(1,      1);
+  testEmptyAfterDone(10,     0);
+  testEmptyAfterDone(0,      10);
+  testEmptyAfterDone(10,     10);
+  testEmptyAfterDone(0,      bl);
+  testEmptyAfterDone(bl,     0);
+  testEmptyAfterDone(bl / 2, bl / 2);
+  testEmptyAfterDone(bl - 1, 1);
+  testEmptyAfterDone(1,      bl - 1);
+  // Processed
+  testEmptyAfterDone(bl + 1, 0);
+  testEmptyAfterDone(bl * 2, 0);
+}
diff --git a/hotspot/test/native/gc/parallel/test_psParallelCompact.cpp b/hotspot/test/native/gc/parallel/test_psParallelCompact.cpp
new file mode 100644
index 0000000..fee3179
--- /dev/null
+++ b/hotspot/test/native/gc/parallel/test_psParallelCompact.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "gc/parallel/psParallelCompact.hpp"
+#include "gc/parallel/psCompactionManager.inline.hpp"
+#include "unittest.hpp"
+
+#ifndef PRODUCT
+
+class PSParallelCompactTest : public ::testing::Test {
+ public:
+  static void print_generic_summary_data(ParallelCompactData& summary_data,
+                                         HeapWord* const beg_addr,
+                                         HeapWord* const end_addr) {
+    PSParallelCompact::print_generic_summary_data(summary_data,
+                                                  beg_addr, end_addr);
+  }
+};
+
+// @requires UseParallelGC
+TEST_VM(PSParallelCompact, print_generic_summary_data) {
+  if (!UseParallelOldGC) {
+    return;
+  }
+  // Check that print_generic_summary_data() does not print the
+  // end region by placing a bad value in the destination of the
+  // end region.  The end region should not be printed because it
+  // corresponds to the space after the end of the heap.
+  ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
+  ParCompactionManager* const vmthread_cm =
+    ParCompactionManager::manager_array(ParallelGCThreads);
+  HeapWord* begin_heap =
+    (HeapWord*) heap->old_gen()->virtual_space()->low_boundary();
+  HeapWord* end_heap =
+    (HeapWord*) heap->young_gen()->virtual_space()->high_boundary();
+
+  PSParallelCompactTest::print_generic_summary_data(PSParallelCompact::summary_data(),
+    begin_heap, end_heap);
+}
+
+#endif
diff --git a/hotspot/test/native/gc/shared/test_collectedHeap.cpp b/hotspot/test/native/gc/shared/test_collectedHeap.cpp
new file mode 100644
index 0000000..17c1a00
--- /dev/null
+++ b/hotspot/test/native/gc/shared/test_collectedHeap.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "unittest.hpp"
+
+TEST_VM(CollectedHeap, is_in) {
+  CollectedHeap* heap = Universe::heap();
+
+  uintptr_t epsilon = (uintptr_t) MinObjAlignment;
+  uintptr_t heap_start = (uintptr_t) heap->reserved_region().start();
+  uintptr_t heap_end = (uintptr_t) heap->reserved_region().end();
+
+  // Test that NULL is not in the heap.
+  ASSERT_FALSE(heap->is_in(NULL)) << "NULL is unexpectedly in the heap";
+
+  // Test that a pointer to before the heap start is reported as outside the heap.
+  ASSERT_GE(heap_start, ((uintptr_t) NULL + epsilon))
+          << "Sanity check - heap should not start at 0";
+
+  void* before_heap = (void*) (heap_start - epsilon);
+  ASSERT_FALSE(heap->is_in(before_heap)) << "before_heap: " << p2i(before_heap)
+          << " is unexpectedly in the heap";
+
+  // Test that a pointer to after the heap end is reported as outside the heap.
+  ASSERT_LE(heap_end, ((uintptr_t)-1 - epsilon))
+          << "Sanity check - heap should not end at the end of address space";
+
+  void* after_heap = (void*) (heap_end + epsilon);
+  ASSERT_FALSE(heap->is_in(after_heap)) << "after_heap: " << p2i(after_heap)
+          << " is unexpectedly in the heap";
+}
diff --git a/hotspot/test/native/logging/test_logDecorations.cpp b/hotspot/test/native/logging/test_logDecorations.cpp
index f4c7b87..68c0210 100644
--- a/hotspot/test/native/logging/test_logDecorations.cpp
+++ b/hotspot/test/native/logging/test_logDecorations.cpp
@@ -131,10 +131,9 @@
   time_t expected_ts = time(NULL);
 
   // Verify format
-  int y, M, d, h, m;
-  double s;
-  int read = sscanf(timestr, "%d-%d-%dT%d:%d:%lf", &y, &M, &d, &h, &m, &s);
-  ASSERT_EQ(6, read) << "Invalid format: " << timestr;
+  int y, M, d, h, m, s, ms;
+  int read = sscanf(timestr, "%d-%d-%dT%d:%d:%d.%d", &y, &M, &d, &h, &m, &s, &ms);
+  ASSERT_EQ(7, read) << "Invalid format: " << timestr;
 
   // Verify reported time & date
   struct tm reported_time = {0};
@@ -167,17 +166,16 @@
 
   // Verify format
   char trailing_character;
-  int y, M, d, h, m, offset;
-  double s;
-  int read = sscanf(timestr, "%d-%d-%dT%d:%d:%lf%c%d", &y, &M, &d, &h, &m, &s, &trailing_character, &offset);
-  ASSERT_GT(read, 7) << "Invalid format: " << timestr;
+  int y, M, d, h, m, s, ms, offset;
+
+  int read = sscanf(timestr, "%d-%d-%dT%d:%d:%d.%d%c%d", &y, &M, &d, &h, &m, &s, &ms, &trailing_character, &offset);
+
+  ASSERT_EQ(9, read) << "Invalid format: " << timestr;
 
   // Ensure time is UTC (no offset)
-  if (trailing_character == '+') {
-    ASSERT_EQ(0, offset) << "Invalid offset: " << timestr;
-  } else {
-    ASSERT_EQ('Z', trailing_character) << "Invalid offset: " << timestr;
-  }
+  ASSERT_EQ('+', trailing_character) << "Invalid trailing character for UTC: "
+          << trailing_character;
+  ASSERT_EQ(0, offset) << "Invalid offset: " << timestr;
 
   struct tm reported_time = {0};
   reported_time.tm_year = y - 1900;
diff --git a/hotspot/test/native/memory/test_chunkManager.cpp b/hotspot/test/native/memory/test_chunkManager.cpp
new file mode 100644
index 0000000..6aa5b5e
--- /dev/null
+++ b/hotspot/test/native/memory/test_chunkManager.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+// The test function is only available in debug builds
+#ifdef ASSERT
+
+#include "unittest.hpp"
+
+void ChunkManager_test_list_index();
+
+TEST(ChunkManager, list_index) {
+  // The ChunkManager is only available in metaspace.cpp,
+  // so the test code is located in that file.
+  ChunkManager_test_list_index();
+}
+
+#endif // ASSERT
diff --git a/hotspot/test/native/memory/test_spaceManager.cpp b/hotspot/test/native/memory/test_spaceManager.cpp
new file mode 100644
index 0000000..b253d22
--- /dev/null
+++ b/hotspot/test/native/memory/test_spaceManager.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+
+// The test function is only available in debug builds
+#ifdef ASSERT
+
+#include "unittest.hpp"
+
+void SpaceManager_test_adjust_initial_chunk_size();
+
+TEST(SpaceManager, adjust_initial_chunk_size) {
+  // The SpaceManager is only available in metaspace.cpp,
+  // so the test code is located in that file.
+  SpaceManager_test_adjust_initial_chunk_size();
+}
+
+#endif // ASSERT
diff --git a/hotspot/test/native/runtime/test_semaphore.cpp b/hotspot/test/native/runtime/test_semaphore.cpp
new file mode 100644
index 0000000..3193942
--- /dev/null
+++ b/hotspot/test/native/runtime/test_semaphore.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "runtime/semaphore.hpp"
+#include "unittest.hpp"
+
+static void test_semaphore_single_separate(uint count) {
+  Semaphore sem(0);
+
+  for (uint i = 0; i < count; i++) {
+    sem.signal();
+  }
+
+  for (uint i = 0; i < count; i++) {
+    sem.wait();
+  }
+}
+
+static void test_semaphore_single_combined(uint count) {
+  Semaphore sem(0);
+
+  for (uint i = 0; i < count; i++) {
+    sem.signal();
+    sem.wait();
+  }
+}
+
+static void test_semaphore_many(uint value, uint max, uint increments) {
+  Semaphore sem(value);
+
+  uint total = value;
+
+  for (uint i = value; i + increments <= max; i += increments) {
+    sem.signal(increments);
+
+    total += increments;
+  }
+
+  for (uint i = 0; i < total; i++) {
+    sem.wait();
+  }
+}
+
+TEST(Semaphore, single_separate) {
+  for (uint i = 1; i < 10; i++) {
+    test_semaphore_single_separate(i);
+  }
+}
+
+TEST(Semaphore, single_combined) {
+  for (uint i = 1; i < 10; i++) {
+    test_semaphore_single_combined(i);
+  }
+}
+
+TEST(Semaphore, many) {
+  for (uint max = 0; max < 10; max++) {
+    for (uint value = 0; value < max; value++) {
+      for (uint inc = 1; inc <= max - value; inc++) {
+        test_semaphore_many(value, max, inc);
+      }
+    }
+  }
+}
diff --git a/hotspot/test/native/utilities/test_bitMap.cpp b/hotspot/test/native/utilities/test_bitMap.cpp
new file mode 100644
index 0000000..931e502
--- /dev/null
+++ b/hotspot/test/native/utilities/test_bitMap.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/bitMap.inline.hpp"
+#include "unittest.hpp"
+
+class BitMapTest {
+
+  template <class ResizableBitMapClass>
+  static void fillBitMap(ResizableBitMapClass& map) {
+    map.set_bit(1);
+    map.set_bit(3);
+    map.set_bit(17);
+    map.set_bit(512);
+  }
+
+  template <class ResizableBitMapClass>
+  static void testResize(BitMap::idx_t start_size) {
+    ResourceMark rm;
+
+    ResizableBitMapClass map(start_size);
+    map.resize(BITMAP_SIZE);
+    fillBitMap(map);
+
+    ResizableBitMapClass map2(BITMAP_SIZE);
+    fillBitMap(map2);
+    EXPECT_TRUE(map.is_same(map2)) << "With start_size " << start_size;
+  }
+
+ public:
+  const static BitMap::idx_t BITMAP_SIZE = 1024;
+
+
+  template <class ResizableBitMapClass>
+  static void testResizeGrow() {
+    testResize<ResizableBitMapClass>(0);
+    testResize<ResizableBitMapClass>(BITMAP_SIZE >> 3);
+  }
+
+  template <class ResizableBitMapClass>
+  static void testResizeSame() {
+    testResize<ResizableBitMapClass>(BITMAP_SIZE);
+  }
+
+  template <class ResizableBitMapClass>
+  static void testResizeShrink() {
+    testResize<ResizableBitMapClass>(BITMAP_SIZE * 2);
+  }
+
+  template <class InitializableBitMapClass>
+  static void testInitialize() {
+    ResourceMark rm;
+
+    InitializableBitMapClass map;
+    map.initialize(BITMAP_SIZE);
+    fillBitMap(map);
+
+    InitializableBitMapClass map2(BITMAP_SIZE);
+    fillBitMap(map2);
+    EXPECT_TRUE(map.is_same(map2));
+  }
+
+
+  static void testReinitialize(BitMap::idx_t init_size) {
+    ResourceMark rm;
+
+    ResourceBitMap map(init_size);
+    map.reinitialize(BITMAP_SIZE);
+    fillBitMap(map);
+
+    ResourceBitMap map2(BITMAP_SIZE);
+    fillBitMap(map2);
+    EXPECT_TRUE(map.is_same(map2)) << "With init_size " << init_size;
+  }
+
+};
+
+TEST_VM(BitMap, resize_grow) {
+  BitMapTest::testResizeGrow<ResourceBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap";
+  BitMapTest::testResizeGrow<CHeapBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap";
+}
+
+TEST_VM(BitMap, resize_shrink) {
+  BitMapTest::testResizeShrink<ResourceBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap";
+  BitMapTest::testResizeShrink<CHeapBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap";
+}
+
+TEST_VM(BitMap, resize_same) {
+  BitMapTest::testResizeSame<ResourceBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap";
+  BitMapTest::testResizeSame<CHeapBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap";
+}
+
+TEST_VM(BitMap, initialize) {
+  BitMapTest::testInitialize<ResourceBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap";
+  BitMapTest::testInitialize<CHeapBitMap>();
+  EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap";
+}
+
+TEST_VM(BitMap, reinitialize) {
+  BitMapTest::testReinitialize(0);
+  BitMapTest::testReinitialize(BitMapTest::BITMAP_SIZE >> 3);
+  BitMapTest::testReinitialize(BitMapTest::BITMAP_SIZE);
+}
diff --git a/hotspot/test/native/utilities/test_globalDefinitions.cpp b/hotspot/test/native/utilities/test_globalDefinitions.cpp
new file mode 100644
index 0000000..f77f0b4
--- /dev/null
+++ b/hotspot/test/native/utilities/test_globalDefinitions.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "unittest.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+static ::testing::AssertionResult testPageAddress(
+  const char* expected_addr_expr,
+  const char* addr_expr,
+  const char* page_addr_expr,
+  const char* page_size_expr,
+  const char* actual_addr_expr,
+  address expected_addr,
+  address addr,
+  address page_addr,
+  intptr_t page_size,
+  address actual_addr) {
+  if (expected_addr == actual_addr) {
+    return ::testing::AssertionSuccess();
+  }
+
+  return ::testing::AssertionFailure()
+    << actual_addr_expr << " returned unexpected address " << (void*) actual_addr << std::endl
+    << "Expected " << expected_addr_expr << ": " << (void*) expected_addr << std::endl
+    << "where" << std::endl
+    << addr_expr << ": " << (void*) addr << std::endl
+    << page_addr_expr << ": " << (void*) page_addr << std::endl
+    << page_size_expr << ": " << page_size;
+}
+
+TEST_VM(globalDefinitions, clamp_address_in_page) {
+  const intptr_t page_sizes[] = {os::vm_page_size(), 4096, 8192, 65536, 2 * 1024 * 1024};
+  const int num_page_sizes = sizeof(page_sizes) / sizeof(page_sizes[0]);
+
+  for (int i = 0; i < num_page_sizes; i++) {
+    intptr_t page_size = page_sizes[i];
+    address page_address = (address) (10 * page_size);
+
+    const intptr_t within_page_offsets[] = {0, 128, page_size - 1};
+    const int num_within_page_offsets = sizeof(within_page_offsets) / sizeof(within_page_offsets[0]);
+
+    for (int k = 0; k < num_within_page_offsets; ++k) {
+      address addr = page_address + within_page_offsets[k];
+      address expected_address = addr;
+      EXPECT_PRED_FORMAT5(testPageAddress, expected_address, addr, page_address, page_size,
+                          clamp_address_in_page(addr, page_address, page_size))
+        << "Expect that address within page is returned as is";
+    }
+
+    const intptr_t above_page_offsets[] = {page_size, page_size + 1, 5 * page_size + 1};
+    const int num_above_page_offsets = sizeof(above_page_offsets) / sizeof(above_page_offsets[0]);
+
+    for (int k = 0; k < num_above_page_offsets; ++k) {
+      address addr = page_address + above_page_offsets[k];
+      address expected_address = page_address + page_size;
+      EXPECT_PRED_FORMAT5(testPageAddress, expected_address, addr, page_address, page_size,
+                          clamp_address_in_page(addr, page_address, page_size))
+        << "Expect that address above page returns start of next page";
+    }
+
+    const intptr_t below_page_offsets[] = {1, 2 * page_size + 1, 5 * page_size + 1};
+    const int num_below_page_offsets = sizeof(below_page_offsets) / sizeof(below_page_offsets[0]);
+
+    for (int k = 0; k < num_below_page_offsets; ++k) {
+      address addr = page_address - below_page_offsets[k];
+      address expected_address = page_address;
+      EXPECT_PRED_FORMAT5(testPageAddress, expected_address, addr, page_address, page_size,
+                          clamp_address_in_page(addr, page_address, page_size))
+        << "Expect that address below page returns start of page";
+    }
+  }
+}
+
+TEST(globalDefinitions, exact_unit_for_byte_size) {
+  EXPECT_STREQ("B", exact_unit_for_byte_size(0));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(1));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(K - 1));
+  EXPECT_STREQ("K", exact_unit_for_byte_size(K));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(K + 1));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(M - 1));
+  EXPECT_STREQ("M", exact_unit_for_byte_size(M));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(M + 1));
+  EXPECT_STREQ("K", exact_unit_for_byte_size(M + K));
+#ifdef LP64
+  EXPECT_STREQ("B", exact_unit_for_byte_size(G - 1));
+  EXPECT_STREQ("G", exact_unit_for_byte_size(G));
+  EXPECT_STREQ("B", exact_unit_for_byte_size(G + 1));
+  EXPECT_STREQ("K", exact_unit_for_byte_size(G + K));
+  EXPECT_STREQ("M", exact_unit_for_byte_size(G + M));
+  EXPECT_STREQ("K", exact_unit_for_byte_size(G + M + K));
+#endif
+}
+
+TEST(globalDefinitions, byte_size_in_exact_unit) {
+  EXPECT_EQ(0u, byte_size_in_exact_unit(0));
+  EXPECT_EQ(1u, byte_size_in_exact_unit(1));
+  EXPECT_EQ(K - 1, byte_size_in_exact_unit(K - 1));
+  EXPECT_EQ(1u, byte_size_in_exact_unit(K));
+  EXPECT_EQ(K + 1, byte_size_in_exact_unit(K + 1));
+  EXPECT_EQ(M - 1, byte_size_in_exact_unit(M - 1));
+  EXPECT_EQ(1u, byte_size_in_exact_unit(M));
+  EXPECT_EQ(M + 1, byte_size_in_exact_unit(M + 1));
+  EXPECT_EQ(K + 1, byte_size_in_exact_unit(M + K));
+#ifdef LP64
+  EXPECT_EQ(G - 1, byte_size_in_exact_unit(G - 1));
+  EXPECT_EQ(1u, byte_size_in_exact_unit(G));
+  EXPECT_EQ(G + 1, byte_size_in_exact_unit(G + 1));
+  EXPECT_EQ(M + 1, byte_size_in_exact_unit(G + K));
+  EXPECT_EQ(K + 1, byte_size_in_exact_unit(G + M));
+  EXPECT_EQ(M + K + 1, byte_size_in_exact_unit(G + M + K));
+#endif
+}
diff --git a/hotspot/test/native/utilities/test_json.cpp b/hotspot/test/native/utilities/test_json.cpp
index 758ea8a..e55fed6 100644
--- a/hotspot/test/native/utilities/test_json.cpp
+++ b/hotspot/test/native/utilities/test_json.cpp
@@ -19,497 +19,506 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
- *
  */
 
 #include "precompiled.hpp"
+#include "memory/resourceArea.hpp"
 #include "prims/jvm.h"
 #include "utilities/json.hpp"
 #include "unittest.hpp"
 
 class JSON_GTest : public JSON {
-public:
-    static void test(const char* json, bool valid);
+ public:
+  static void test(const char* json, bool valid);
+  char* get_output();
 
-private:
-    JSON_GTest(const char* text);
+ private:
+  JSON_GTest(const char* text);
+  stringStream output;
 
-    void log(uint level, const char* format, ...) ATTRIBUTE_PRINTF(3, 4);
+  void log(uint level, const char* format, ...) ATTRIBUTE_PRINTF(3, 4);
 
-    bool callback(JSON_TYPE t, JSON_VAL* v, uint level);
-    JSON_TYPE prev;
+  bool callback(JSON_TYPE t, JSON_VAL* v, uint level);
+  JSON_TYPE prev;
 };
 
-void JSON_GTest::test(const char* text, bool should_pass) {
-    JSON_GTest json(text);
-    if (should_pass) {
-        ASSERT_TRUE(json.valid()) << "failed on a valid json string";
-    } else {
-        ASSERT_FALSE(json.valid()) << "succeeded on an invalid json string";
-    }
+char* JSON_GTest::get_output() {
+  return output.as_string();
 }
 
-JSON_GTest::JSON_GTest(const char* text) : JSON(text, false, tty) {
-    prev = JSON_NONE;
-    parse();
+void JSON_GTest::test(const char* text, bool should_pass) {
+  ResourceMark rm;
+  JSON_GTest json(text);
+  if (should_pass) {
+    ASSERT_TRUE(json.valid()) << "failed on a valid json string"
+            << std::endl << "debug output:" << std::endl << json.get_output();
+  } else {
+    ASSERT_FALSE(json.valid()) << "succeeded on an invalid json string"
+            << std::endl << "debug output:" << std::endl << json.get_output();
+  }
+}
+
+JSON_GTest::JSON_GTest(const char* text) : JSON(text, false, &output) {
+  prev = JSON_NONE;
+  parse();
 }
 
 TEST_VM(utilities, json_curly_braces) {
-    JSON_GTest::test("{}", true);
+  JSON_GTest::test("{}", true);
 }
 
 TEST_VM(utilities, json_brackets) {
-    JSON_GTest::test("[]", true);
+  JSON_GTest::test("[]", true);
 }
 
 TEST_VM(utilities, json_space_braces) {
-    JSON_GTest::test("  {  }  ", true);
+  JSON_GTest::test("  {  }  ", true);
 }
 
 TEST_VM(utilities, json_space_bracketes) {
-    JSON_GTest::test("  [  ]  ", true);
+  JSON_GTest::test("  [  ]  ", true);
 }
 
 TEST_VM(utilities, json_quoted_error) {
-    JSON_GTest::test("\"error\"", false);
+  JSON_GTest::test("\"error\"", false);
 }
 
 TEST_VM(utilities, json_error_string) {
-    JSON_GTest::test("error", false);
+  JSON_GTest::test("error", false);
 }
 
 TEST_VM(utilities, json_simple_integer) {
-    JSON_GTest::test("1", false);
+  JSON_GTest::test("1", false);
 }
 
 TEST_VM(utilities, json_siple_float) {
-    JSON_GTest::test("1.2", false);
+  JSON_GTest::test("1.2", false);
 }
 
 TEST_VM(utilities, json_simple_boolean_true) {
-    JSON_GTest::test("true", false);
+  JSON_GTest::test("true", false);
 }
 
 TEST_VM(utilities, json_simple_boolean_false) {
-    JSON_GTest::test("false", false);
+  JSON_GTest::test("false", false);
 }
 
 TEST_VM(utilities, json_simple_null) {
-    JSON_GTest::test("null", false);
+  JSON_GTest::test("null", false);
 }
 
 TEST_VM(utilities, json_one_element_int_array) {
-    JSON_GTest::test("[ 1 ]", true);
+  JSON_GTest::test("[ 1 ]", true);
 }
 
 TEST_VM(utilities, json_int_array) {
-    JSON_GTest::test("[ 1, ]", true);
+  JSON_GTest::test("[ 1, ]", true);
 }
 
 TEST_VM(utilities, json_one_element_bool_array) {
-    JSON_GTest::test("[ true ]", true);
+  JSON_GTest::test("[ true ]", true);
 }
 
 TEST_VM(utilities, json_bool_array) {
-    JSON_GTest::test("[ true, ]", true);
+  JSON_GTest::test("[ true, ]", true);
 }
 
 TEST_VM(utilities, json_one_element_false_array) {
-    JSON_GTest::test("[ false ]", true);
+  JSON_GTest::test("[ false ]", true);
 }
 
 TEST_VM(utilities, json_false_bool_array) {
-    JSON_GTest::test("[ false, ]", true);
+  JSON_GTest::test("[ false, ]", true);
 }
 
 TEST_VM(utilities, json_one_null_array) {
-    JSON_GTest::test("[ null ]", true);
+  JSON_GTest::test("[ null ]", true);
 }
 
 TEST_VM(utilities, json_null_array) {
-    JSON_GTest::test("[ null, ]", true);
+  JSON_GTest::test("[ null, ]", true);
 }
 
 TEST_VM(utilities, json_one_empty_string_array) {
-    JSON_GTest::test("[ \"\" ]", true);
+  JSON_GTest::test("[ \"\" ]", true);
 }
 
 TEST_VM(utilities, json_empty_string_array) {
-    JSON_GTest::test("[ \"\", ]", true);
+  JSON_GTest::test("[ \"\", ]", true);
 }
 
 TEST_VM(utilities, json_single_string_array) {
-    JSON_GTest::test("[ \"elem1\" ]", true);
+  JSON_GTest::test("[ \"elem1\" ]", true);
 }
 
 TEST_VM(utilities, json_string_comma_arrray) {
-    JSON_GTest::test("[ \"elem1\", ]", true);
+  JSON_GTest::test("[ \"elem1\", ]", true);
 }
 
 TEST_VM(utilities, json_two_strings_array) {
-    JSON_GTest::test("[ \"elem1\", \"elem2\" ]", true);
+  JSON_GTest::test("[ \"elem1\", \"elem2\" ]", true);
 }
 
 TEST_VM(utilities, json_two_strings_comma_array) {
-    JSON_GTest::test("[ \"elem1\", \"elem2\", ]", true);
+  JSON_GTest::test("[ \"elem1\", \"elem2\", ]", true);
 }
 
 TEST_VM(utilities, json_curly_braces_outside) {
-    JSON_GTest::test("[ \"elem1\" ] { }", false);
+  JSON_GTest::test("[ \"elem1\" ] { }", false);
 }
 
 TEST_VM(utilities, json_element_in_array) {
-    JSON_GTest::test("[ elem1, \"elem2\" ]", false);
+  JSON_GTest::test("[ elem1, \"elem2\" ]", false);
 }
 
 TEST_VM(utilities, json_incorrect_end_array) {
-    JSON_GTest::test("[ \"elem1\"", false);
+  JSON_GTest::test("[ \"elem1\"", false);
 }
 
 TEST_VM(utilities, json_incorrect_string_end) {
-    JSON_GTest::test("[ \"elem1 ]", false);
+  JSON_GTest::test("[ \"elem1 ]", false);
 }
 
 TEST_VM(utilities, json_incorrect_end_of_two_elements_array) {
-    JSON_GTest::test("[ \"elem1\", \"elem2\"", false);
+  JSON_GTest::test("[ \"elem1\", \"elem2\"", false);
 }
 
 TEST_VM(utilities, json_incorrect_bool_true_array) {
-    JSON_GTest::test("[ truefoo ]", false);
+  JSON_GTest::test("[ truefoo ]", false);
 }
 
 TEST_VM(utilities, json_incorrect_bool_false_array) {
-    JSON_GTest::test("[ falsefoo ]", false);
+  JSON_GTest::test("[ falsefoo ]", false);
 }
 
 TEST_VM(utilities, json_incorrect_null_array) {
-    JSON_GTest::test("[ nullfoo ]", false);
+  JSON_GTest::test("[ nullfoo ]", false);
 }
 
 TEST_VM(utilities, json_key_pair) {
-    JSON_GTest::test("{ key : 1 }", true);
+  JSON_GTest::test("{ key : 1 }", true);
 }
 
 TEST_VM(utilities, json_key_pair_comma) {
-    JSON_GTest::test("{ key : 1, }", true);
+  JSON_GTest::test("{ key : 1, }", true);
 }
 
 TEST_VM(utilities, json_bool_true_key) {
-    JSON_GTest::test("{ key : true }", true);
+  JSON_GTest::test("{ key : true }", true);
 }
 
 TEST_VM(utilities, json_bool_true_key_comma) {
-    JSON_GTest::test("{ key : true, }", true);
+  JSON_GTest::test("{ key : true, }", true);
 }
 
 TEST_VM(utilities, json_bool_false_key) {
-    JSON_GTest::test("{ key : false }", true);
+  JSON_GTest::test("{ key : false }", true);
 }
 
 TEST_VM(utilities, json_bool_false_key_comma) {
-    JSON_GTest::test("{ key : false, }", true);
+  JSON_GTest::test("{ key : false, }", true);
 }
 
 TEST_VM(utilities, json_null_key) {
-    JSON_GTest::test("{ key : null }", true);
+  JSON_GTest::test("{ key : null }", true);
 }
 
 TEST_VM(utilities, json_null_key_comma) {
-    JSON_GTest::test("{ key : null, }", true);
+  JSON_GTest::test("{ key : null, }", true);
 }
 
 TEST_VM(utilities, json_pair_of_empty_strings) {
-    JSON_GTest::test("{ \"\" : \"\" }", true);
+  JSON_GTest::test("{ \"\" : \"\" }", true);
 }
 
 TEST_VM(utilities, json_pair_of_empty_strings_comma) {
-    JSON_GTest::test("{ \"\" : \"\", }", true);
+  JSON_GTest::test("{ \"\" : \"\", }", true);
 }
 
 TEST_VM(utilities, json_pair_of_strings) {
-    JSON_GTest::test("{ \"key1\" : \"val1\" }", true);
+  JSON_GTest::test("{ \"key1\" : \"val1\" }", true);
 }
 
 TEST_VM(utilities, json_pair_of_strings_comma) {
-    JSON_GTest::test("{ \"key1\" : \"val1\", }", true);
+  JSON_GTest::test("{ \"key1\" : \"val1\", }", true);
 }
 
 TEST_VM(utilities, json_two_pairs_of_strings) {
-    JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true);
+  JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true);
 }
 
 TEST_VM(utilities, json_two_pairs_of_strings_comma) {
-    JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true);
+  JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true);
 }
 
 TEST_VM(utilities, json_array_outside) {
-    JSON_GTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false);
+  JSON_GTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false);
 }
 
 TEST_VM(utilities, json_incorrect_object_end) {
-    JSON_GTest::test("{ \"key\" : \"val\" ", false);
+  JSON_GTest::test("{ \"key\" : \"val\" ", false);
 }
 
 TEST_VM(utilities, json_empty_comment) {
-    JSON_GTest::test("/**/ { }", true);
+  JSON_GTest::test("/**/ { }", true);
 }
 
 TEST_VM(utilities, json_space_comment) {
-    JSON_GTest::test("/* */ { }", true);
+  JSON_GTest::test("/* */ { }", true);
 }
 
 TEST_VM(utilities, json_comment) {
-    JSON_GTest::test("/*foo*/ { }", true);
+  JSON_GTest::test("/*foo*/ { }", true);
 }
 
 TEST_VM(utilities, json_star_comment) {
-    JSON_GTest::test("/* *foo */ { }", true);
+  JSON_GTest::test("/* *foo */ { }", true);
 }
 
 TEST_VM(utilities, json_stars_comment) {
-    JSON_GTest::test("/* *foo* */ { }", true);
+  JSON_GTest::test("/* *foo* */ { }", true);
 }
 
 TEST_VM(utilities, json_special_comment) {
-    JSON_GTest::test("/* /*foo */ { }", true);
+  JSON_GTest::test("/* /*foo */ { }", true);
 }
 
 TEST_VM(utilities, json_comment_after) {
-    JSON_GTest::test("{ } /* foo */", true);
+  JSON_GTest::test("{ } /* foo */", true);
 }
 
 TEST_VM(utilities, json_comment_after_and_space) {
-    JSON_GTest::test("{ } /* foo */ ", true);
+  JSON_GTest::test("{ } /* foo */ ", true);
 }
 
 TEST_VM(utilities, json_one_line_empty_comment_after) {
-    JSON_GTest::test("{ } //", true);
+  JSON_GTest::test("{ } //", true);
 }
 
 TEST_VM(utilities, json_one_line_space_comment_after) {
-    JSON_GTest::test("{ } // ", true);
+  JSON_GTest::test("{ } // ", true);
 }
 
 TEST_VM(utilities, json_one_line_comment_after) {
-    JSON_GTest::test("{ } // foo", true);
+  JSON_GTest::test("{ } // foo", true);
 }
 
 TEST_VM(utilities, json_incorrect_multiline_comment) {
-    JSON_GTest::test("/* * / { }", false);
+  JSON_GTest::test("/* * / { }", false);
 }
 
 TEST_VM(utilities, json_incorrect_multiline_comment_begin) {
-    JSON_GTest::test("/ * */ { }", false);
+  JSON_GTest::test("/ * */ { }", false);
 }
 
 TEST_VM(utilities, json_oneline_comment_only) {
-    JSON_GTest::test("// { }", false);
+  JSON_GTest::test("// { }", false);
 }
 
 TEST_VM(utilities, json_multiline_comment_only) {
-    JSON_GTest::test("/* { } */", false);
+  JSON_GTest::test("/* { } */", false);
 }
 
 TEST_VM(utilities, json_multiline_comment_2) {
-    JSON_GTest::test("/* { } */ ", false);
+  JSON_GTest::test("/* { } */ ", false);
 }
 
 TEST_VM(utilities, json_incorrectly_commented_object) {
-    JSON_GTest::test("/* { } ", false);
+  JSON_GTest::test("/* { } ", false);
 }
 
 TEST_VM(utilities, json_missing_multiline_end) {
-    JSON_GTest::test("{ } /* ", false);
+  JSON_GTest::test("{ } /* ", false);
 }
 
 TEST_VM(utilities, json_missing_multiline_slash) {
-    JSON_GTest::test("/* { } *", false);
+  JSON_GTest::test("/* { } *", false);
 }
 
 TEST_VM(utilities, json_commented_object_end) {
-    JSON_GTest::test("{ /* } */", false);
+  JSON_GTest::test("{ /* } */", false);
 }
 
 TEST_VM(utilities, json_commented_array_end) {
-    JSON_GTest::test("[ /* ] */", false);
+  JSON_GTest::test("[ /* ] */", false);
 }
 
 TEST_VM(utilities, json_missing_object_end) {
-    JSON_GTest::test("{ key : \"val\", /* } */", false);
+  JSON_GTest::test("{ key : \"val\", /* } */", false);
 }
 
 TEST_VM(utilities, json_missing_array_end) {
-    JSON_GTest::test("[ \"val\", /* ] */", false);
+  JSON_GTest::test("[ \"val\", /* ] */", false);
 }
 
 TEST_VM(utilities, json_key_values_1) {
-    JSON_GTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
-            "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
-            " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
+  JSON_GTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
+          "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
+          " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
 }
 
 TEST_VM(utilities, json_key_values_2) {
-    JSON_GTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
-            "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
-            " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
+  JSON_GTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
+          "{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
+          " : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
 }
 
 TEST_VM(utilities, json_quoted_symbols) {
-    JSON_GTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},"
-            "\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true);
+  JSON_GTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},"
+          "\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true);
 }
 
 TEST_VM(utilities, json_incorrect_key) {
-    JSON_GTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\","
-            " \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}",
-            false); // first key needs to be quoted since it contains a space
+  JSON_GTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\","
+          " \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}",
+          false); // first key needs to be quoted since it contains a space
 }
 
 TEST_VM(utilities, json_array_with_newline) {
-    JSON_GTest::test("[\n]", true);
+  JSON_GTest::test("[\n]", true);
 }
 
 TEST_VM(utilities, json_directives_file) {
-    JSON_GTest::test(
-            "[" "\n"
-            "   {"
-            "         // pattern to match against class+method+signature" "\n"
-            "         // leading and trailing wildcard (*) allowed" "\n"
-            "         match: \"foo.bar.*\"," "\n"
-            " " "\n"
-            "         // override defaults for specified compiler" "\n"
-            "         // we may differentiate between levels too. TBD." "\n"
-            "         c1:  {" "\n"
-            "           //override c1 presets " "\n"
-            "           array_bounds_check_removal: false" "\n"
-            "         }," "\n"
-            "" "\n"
-            "         c2: {" "\n"
-            "           // control inlining of method" "\n"
-            "           // + force inline, - dont inline" "\n"
-            "           inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
-            "         }," "\n"
-            "" "\n"
-            "         // directives outside a specific preset applies to all compilers" "\n"
-            "         inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
-            "         print_assembly: true," "\n"
-            "         verify_oopmaps: true," "\n"
-            "         max_loop_unrolling: 5" "\n"
-            "   }," "\n"
-            "   {" "\n"
-            "         // matching several patterns require an array" "\n"
-            "         match: [\"baz.*\",\"frob*\"]," "\n"
-            "" "\n"
-            "         // only enable c1 for this directive" "\n"
-            "         // all enabled by default. Command disables all not listed" "\n"
-            "         enable: \"c1\"," "\n"
-            "" "\n"
-            "         // applies to all compilers" "\n"
-            "         // + force inline, - dont inline" "\n"
-            "         inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
-            "         print_inlining: true," "\n"
-            "" "\n"
-            "         // force matching compiles to be blocking/syncronous" "\n"
-            "         blocking_compile: true" "\n"
-            "   }," "\n"
-            "]" "\n", true);
+  JSON_GTest::test(
+          "[" "\n"
+          "   {"
+          "         // pattern to match against class+method+signature" "\n"
+          "         // leading and trailing wildcard (*) allowed" "\n"
+          "         match: \"foo.bar.*\"," "\n"
+          " " "\n"
+          "         // override defaults for specified compiler" "\n"
+          "         // we may differentiate between levels too. TBD." "\n"
+          "         c1:  {" "\n"
+          "           //override c1 presets " "\n"
+          "           array_bounds_check_removal: false" "\n"
+          "         }," "\n"
+          "" "\n"
+          "         c2: {" "\n"
+          "           // control inlining of method" "\n"
+          "           // + force inline, - dont inline" "\n"
+          "           inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
+          "         }," "\n"
+          "" "\n"
+          "         // directives outside a specific preset applies to all compilers" "\n"
+          "         inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
+          "         print_assembly: true," "\n"
+          "         verify_oopmaps: true," "\n"
+          "         max_loop_unrolling: 5" "\n"
+          "   }," "\n"
+          "   {" "\n"
+          "         // matching several patterns require an array" "\n"
+          "         match: [\"baz.*\",\"frob*\"]," "\n"
+          "" "\n"
+          "         // only enable c1 for this directive" "\n"
+          "         // all enabled by default. Command disables all not listed" "\n"
+          "         enable: \"c1\"," "\n"
+          "" "\n"
+          "         // applies to all compilers" "\n"
+          "         // + force inline, - dont inline" "\n"
+          "         inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
+          "         print_inlining: true," "\n"
+          "" "\n"
+          "         // force matching compiles to be blocking/syncronous" "\n"
+          "         blocking_compile: true" "\n"
+          "   }," "\n"
+          "]" "\n", true);
 }
 
 void JSON_GTest::log(uint indent, const char* format, ...) {
-    if (prev != JSON_KEY) {
-        for (uint i = 0; i < indent; i++) {
-            _st->print("  ");
-        }
+  if (prev != JSON_KEY) {
+    for (uint i = 0; i < indent; i++) {
+      _st->print("  ");
     }
-    va_list args;
-    va_start(args, format);
-    _st->vprint(format, args);
-    va_end(args);
+  }
+  va_list args;
+  va_start(args, format);
+  _st->vprint(format, args);
+  va_end(args);
 }
 
 bool JSON_GTest::callback(JSON_TYPE t, JSON_VAL* v, uint rlevel) {
-    switch (t) {
-        case JSON_OBJECT_BEGIN:
-            log(rlevel, "{\n");
-            prev = JSON_NONE; // Only care about JSON_KEY, to indent correctly
-            return true;
+  switch (t) {
+    case JSON_OBJECT_BEGIN:
+      log(rlevel, "{\n");
+      prev = JSON_NONE; // Only care about JSON_KEY, to indent correctly
+      return true;
 
-        case JSON_OBJECT_END:
-            log(rlevel, "},\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_OBJECT_END:
+      log(rlevel, "},\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_ARRAY_BEGIN:
-            log(rlevel, "[\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_ARRAY_BEGIN:
+      log(rlevel, "[\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_ARRAY_END:
-            log(rlevel, "],\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_ARRAY_END:
+      log(rlevel, "],\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_KEY:
-            for (uint i = 0; i < rlevel; i++) {
-                _st->print("  ");
-            }
-            _st->print("<key>");
-            for (size_t i = 0; i < v->str.length; i++) {
-                u_char c = v->str.start[i];
-                if (c == 0) {
-                    return false;
-                }
-                _st->print("%c", c);
-            }
-            _st->print(" : ");
-            prev = JSON_KEY;
-            return true;
+    case JSON_KEY:
+      for (uint i = 0; i < rlevel; i++) {
+        _st->print("  ");
+      }
+      _st->print("<key>");
+      for (size_t i = 0; i < v->str.length; i++) {
+        u_char c = v->str.start[i];
+        if (c == 0) {
+          return false;
+        }
+        _st->print("%c", c);
+      }
+      _st->print(" : ");
+      prev = JSON_KEY;
+      return true;
 
-        case JSON_STRING:
-            if (prev != JSON_KEY) {
-                for (uint i = 0; i < rlevel; i++) {
-                    _st->print("  ");
-                }
-            }
-            _st->print("<str>");
-            for (size_t i = 0; i < v->str.length; i++) {
-                u_char c = v->str.start[i];
-                if (c == 0) {
-                    return false;
-                }
-                _st->print("%c", c);
-            }
-            _st->print(",\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_STRING:
+      if (prev != JSON_KEY) {
+        for (uint i = 0; i < rlevel; i++) {
+          _st->print("  ");
+        }
+      }
+      _st->print("<str>");
+      for (size_t i = 0; i < v->str.length; i++) {
+        u_char c = v->str.start[i];
+        if (c == 0) {
+          return false;
+        }
+        _st->print("%c", c);
+      }
+      _st->print(",\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_NUMBER_INT:
-            log(rlevel, "<int>%" PRId64 ",\n", v->int_value);
-            prev = JSON_NONE;
-            return true;
+    case JSON_NUMBER_INT:
+      log(rlevel, "<int>%" PRId64 ",\n", v->int_value);
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_NUMBER_FLOAT:
-            log(rlevel, "<double>%lf,\n", v->double_value);
-            prev = JSON_NONE;
-            return true;
+    case JSON_NUMBER_FLOAT:
+      log(rlevel, "<double>%lf,\n", v->double_value);
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_TRUE:
-            log(rlevel, "<true>,\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_TRUE:
+      log(rlevel, "<true>,\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_FALSE:
-            log(rlevel, "<false>,\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_FALSE:
+      log(rlevel, "<false>,\n");
+      prev = JSON_NONE;
+      return true;
 
-        case JSON_NULL:
-            log(rlevel, "<null>,\n");
-            prev = JSON_NONE;
-            return true;
+    case JSON_NULL:
+      log(rlevel, "<null>,\n");
+      prev = JSON_NONE;
+      return true;
 
-        default:
-            error(INTERNAL_ERROR, "unknown JSON type");
-            return false;
-    }
+    default:
+      error(INTERNAL_ERROR, "unknown JSON type");
+      return false;
+  }
 }
diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
index 6108400..d6cf052 100644
--- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
+++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
@@ -64,6 +64,7 @@
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
             "-XX:+UnlockDiagnosticVMOptions",
             "-Xmx30g",
+            "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
             "-Xlog:gc+metaspace=trace",
             "-XX:+VerifyBeforeGC", "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
diff --git a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java
index 4753dc6..6587423 100644
--- a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java
+++ b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java
@@ -26,7 +26,6 @@
  * @bug 8022865
  * @summary Tests for different combination of UseCompressedOops options
  * @library /test/lib
- * @ignore 8079353
  * @modules java.base/jdk.internal.misc
  *          java.management
  * @run main UseCompressedOops
diff --git a/hotspot/test/runtime/NMT/MallocStressTest.java b/hotspot/test/runtime/NMT/MallocStressTest.java
index b63166c..3e7624f 100644
--- a/hotspot/test/runtime/NMT/MallocStressTest.java
+++ b/hotspot/test/runtime/NMT/MallocStressTest.java
@@ -29,7 +29,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  * @build sun.hotspot.WhiteBox
- * @ignore - This test is disabled since it will stress NMT and timeout during normal testing
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocStressTest
  */
diff --git a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java
index 6510e60..d00c1df 100644
--- a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java
+++ b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jvmstat/sun.jvmstat.monitor
- * @ignore 8150683
  * @compile javax/sound/sampled/MyClass.jasm
  * @compile org/omg/CORBA/Context.jasm
  * @compile nonjdk/myPackage/MyClass.java
diff --git a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java
index 397a45f..59cfae0 100644
--- a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java
+++ b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java
@@ -27,7 +27,6 @@
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  *          java.management
- * @ignore 8154204
  * @run main DefaultUseWithClient
  * @bug 8032224
  */
diff --git a/hotspot/test/runtime/SharedArchiveFile/LargeSharedSpace.java b/hotspot/test/runtime/SharedArchiveFile/LargeSharedSpace.java
new file mode 100644
index 0000000..35d017b
--- /dev/null
+++ b/hotspot/test/runtime/SharedArchiveFile/LargeSharedSpace.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test LargeSharedSpace
+ * @bug 8168790 8169870
+ * @summary Test CDS dumping using specific space size without crashing.
+ * The space size used in the test might not be suitable on windows.
+ * @requires (os.family != "windows")
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run main LargeSharedSpace
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.Platform;
+
+public class LargeSharedSpace {
+    public static void main(String[] args) throws Exception {
+       ProcessBuilder pb;
+       OutputAnalyzer output;
+
+       // Test case 1: -XX:SharedMiscCodeSize=1066924031
+       //
+       // The archive should be dumped successfully. It might fail to reserve memory
+       // for shared space under low memory condition. The dumping process should not crash.
+       pb = ProcessTools.createJavaProcessBuilder(
+                "-XX:SharedMiscCodeSize=1066924031", "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:SharedArchiveFile=./LargeSharedSpace.jsa", "-Xshare:dump");
+       output = new OutputAnalyzer(pb.start());
+       try {
+           output.shouldContain("Loading classes to share");
+       } catch (RuntimeException e1) {
+           output.shouldContain("Unable to allocate memory for shared space");
+       }
+
+       // Test case 2: -XX:SharedMiscCodeSize=1600386047
+       //
+       // On 64-bit platform, compressed class pointer is used. When the combined
+       // shared space size and the compressed space size is larger than the 4G
+       // compressed klass limit (0x100000000), error is reported.
+       //
+       // The dumping process should not crash.
+       if (Platform.is64bit()) {
+           pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:+UseCompressedClassPointers", "-XX:CompressedClassSpaceSize=3G",
+                    "-XX:SharedMiscCodeSize=1600386047", "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:SharedArchiveFile=./LargeSharedSpace.jsa", "-Xshare:dump");
+           output = new OutputAnalyzer(pb.start());
+           output.shouldContain("larger than compressed klass limit");
+        }
+
+        // Test case 3: -XX:SharedMiscCodeSize=1600386047
+        //
+        // On 32-bit platform, compressed class pointer is not used. It may fail
+        // to reserve memory under low memory condition.
+        //
+        // The dumping process should not crash.
+        if (Platform.is32bit()) {
+           pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:SharedMiscCodeSize=1600386047", "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:SharedArchiveFile=./LargeSharedSpace.jsa", "-Xshare:dump");
+           output = new OutputAnalyzer(pb.start());
+           try {
+               output.shouldContain("Loading classes to share");
+           } catch (RuntimeException e3) {
+               output.shouldContain("Unable to allocate memory for shared space");
+           }
+        }
+    }
+}
diff --git a/hotspot/test/runtime/SharedArchiveFile/TestInterpreterMethodEntries.java b/hotspot/test/runtime/SharedArchiveFile/TestInterpreterMethodEntries.java
new file mode 100644
index 0000000..0526d3c
--- /dev/null
+++ b/hotspot/test/runtime/SharedArchiveFile/TestInterpreterMethodEntries.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test InterpreterMethodEntries
+ * @bug 8169711
+ * @summary Test interpreter method entries for intrinsics with CDS (class data sharing)
+ *          and different settings of the intrinsic flag during dump/use of the archive.
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run main TestInterpreterMethodEntries
+ */
+
+import java.lang.Math;
+import java.util.zip.CRC32;
+import java.util.zip.CRC32C;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestInterpreterMethodEntries {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+          // Dump and use shared archive with different flag combinations
+          dumpAndUseSharedArchive("+", "-");
+          dumpAndUseSharedArchive("-", "+");
+        } else {
+          // Call intrinsified java.lang.Math::fma()
+          Math.fma(1.0, 2.0, 3.0);
+
+          byte[] buffer = new byte[256];
+          // Call intrinsified java.util.zip.CRC32::update()
+          CRC32 crc32 = new CRC32();
+          crc32.update(buffer, 0, 256);
+
+          // Call intrinsified java.util.zip.CRC32C::updateBytes(..)
+          CRC32C crc32c = new CRC32C();
+          crc32c.update(buffer, 0, 256);
+        }
+    }
+
+    private static void dumpAndUseSharedArchive(String dump, String use) throws Exception {
+        String dumpFMA    = "-XX:" + dump + "UseFMA";
+        String dumpCRC32  = "-XX:" + dump + "UseCRC32Intrinsics";
+        String dumpCRC32C = "-XX:" + dump + "UseCRC32CIntrinsics";
+        String useFMA     = "-XX:" + use  + "UseFMA";
+        String useCRC32   = "-XX:" + use  + "UseCRC32Intrinsics";
+        String useCRC32C  = "-XX:" + use  + "UseCRC32CIntrinsics";
+
+        // Dump shared archive
+        String filename = "./TestInterpreterMethodEntries" + dump + ".jsa";
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:SharedArchiveFile=" + filename,
+            "-Xshare:dump",
+            dumpFMA, dumpCRC32, dumpCRC32C);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        CDSTestUtils.checkDump(output);
+
+        // Use shared archive
+        pb = ProcessTools.createJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:SharedArchiveFile=" + filename,
+            "-Xshare:on",
+            useFMA, useCRC32, useCRC32C,
+            "TestInterpreterMethodEntries", "run");
+        output = new OutputAnalyzer(pb.start());
+        if (CDSTestUtils.isUnableToMap(output)) {
+          System.out.println("Unable to map shared archive: test did not complete; assumed PASS");
+          return;
+        }
+        output.shouldHaveExitValue(0);
+    }
+}
+
diff --git a/hotspot/test/runtime/StackGuardPages/testme.sh b/hotspot/test/runtime/StackGuardPages/testme.sh
index 22c5001..96759ad 100644
--- a/hotspot/test/runtime/StackGuardPages/testme.sh
+++ b/hotspot/test/runtime/StackGuardPages/testme.sh
@@ -42,7 +42,7 @@
   exit 0
 fi
 
-LD_LIBRARY_PATH=.:${TESTJAVA}/jre/lib/${VM_CPU}/${VM_TYPE}:${TESTJAVA}/lib/${VM_CPU}/${VM_TYPE}:/usr/lib:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=.:${TESTJAVA}/lib/${VM_TYPE}:/usr/lib:$LD_LIBRARY_PATH
 export LD_LIBRARY_PATH
 
 # Run the test for a java and native overflow
diff --git a/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c b/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
index 7e879e4..b84e039 100644
--- a/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
+++ b/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,7 +66,7 @@
 // method to load the dynamic library libjvm
 void loadJVM() {
   char lib[PATH_MAX];
-  snprintf(lib, sizeof (lib), "%s/lib/sparcv9/server/libjvm.so", path);
+  snprintf(lib, sizeof (lib), "%s/lib/server/libjvm.so", path);
   handle = dlopen(lib, RTLD_LAZY);
   if (!handle) {
     handleError(dlerror(), "2");
diff --git a/hotspot/test/runtime/classFileParserBug/FakeMethodAcc.java b/hotspot/test/runtime/classFileParserBug/FakeMethodAcc.java
new file mode 100644
index 0000000..ba83043
--- /dev/null
+++ b/hotspot/test/runtime/classFileParserBug/FakeMethodAcc.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8166304
+ * @summary Skipping access check for classes generated by core reflection
+ * @compile fakeMethodAccessor.jasm
+ * @run main FakeMethodAcc
+ */
+
+/*
+ * Test that trying to create a sub-type of a 'magic' jdk.internal.reflect
+ * class should fail with an IllegalAccessError exception.
+*/
+public class FakeMethodAcc {
+    public static void main(String args[]) throws Throwable {
+
+        System.out.println("Regression test for bug 8166304");
+        try {
+            Class newClass = Class.forName("fakeMethodAccessor");
+            throw new RuntimeException(
+                "Missing expected IllegalAccessError exception");
+        } catch (java.lang.IllegalAccessError e) {
+        }
+    }
+}
diff --git a/hotspot/test/runtime/classFileParserBug/fakeMethodAccessor.jasm b/hotspot/test/runtime/classFileParserBug/fakeMethodAccessor.jasm
new file mode 100644
index 0000000..36cebcb
--- /dev/null
+++ b/hotspot/test/runtime/classFileParserBug/fakeMethodAccessor.jasm
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ // This is the Java representation of the below jasm code.  The test tries
+ // to create a sub-type of jdk.internal.reflect.MethodAccessorImpl in order
+ // to bypass Reflection.getCallerClass.  That should fail with an IAE.
+ //
+ import java.lang.reflect.Module;
+ class fakeMethodAccessor extends jdk.internal.reflect.MethodAccessorImpl {
+     public static void main(String[] a) throws Exception {
+        fakeMethodAccessor f = new fakeMethodAccessor();
+        System.out.println(String.class.getModule()
+           .isExported("jdk.internal.misc", fakeMethodAccessor.class.getModule()));
+     }
+ }
+*/
+
+super class fakeMethodAccessor
+    extends jdk/internal/reflect/MethodAccessorImpl
+    version 53:0
+{
+
+
+Method "<init>":"()V"
+    stack 1 locals 1
+{
+        aload_0;
+        invokespecial    Method jdk/internal/reflect/MethodAccessorImpl."<init>":"()V";
+        return;
+}
+
+public static Method main:"([Ljava/lang/String;)V"
+    throws java/lang/Exception
+    stack 4 locals 2
+{
+        new    class FakeMethodAccessor;
+        dup;
+        invokespecial    Method "<init>":"()V";
+        astore_1;
+        getstatic    Field java/lang/System.out:"Ljava/io/PrintStream;";
+        ldc    class java/lang/String;
+        invokevirtual    Method java/lang/Class.getModule:"()Ljava/lang/reflect/Module;";
+        ldc    String "jdk.internal.misc";
+        ldc    class FakeMethodAccessor;
+        invokevirtual    Method java/lang/Class.getModule:"()Ljava/lang/reflect/Module;";
+        invokevirtual    Method java/lang/reflect/Module.isExported:"(Ljava/lang/String;Ljava/lang/reflect/Module;)Z";
+        invokevirtual    Method java/io/PrintStream.println:"(Z)V";
+        return;
+}
+
+} // end Class FakeMethodAccessor
diff --git a/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java b/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java
index 54872b9..b9ee748 100644
--- a/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java
+++ b/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java
@@ -32,7 +32,6 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Supplier;
 
 /**
  * A container of modules that acts as a ModuleFinder for testing
@@ -52,12 +51,13 @@
 
                 URI uri = URI.create("module:/" + descriptor.name());
 
-                Supplier<ModuleReader> supplier = () -> {
-                    throw new UnsupportedOperationException();
+                ModuleReference mref = new ModuleReference(descriptor, uri) {
+                    @Override
+                    public ModuleReader open() {
+                        throw new UnsupportedOperationException();
+                    }
                 };
 
-                ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-
                 namesToReference.put(name, mref);
             }
         }
diff --git a/hotspot/test/runtime/modules/CCE_module_msg.java b/hotspot/test/runtime/modules/CCE_module_msg.java
index 54ece08..38ff41f 100644
--- a/hotspot/test/runtime/modules/CCE_module_msg.java
+++ b/hotspot/test/runtime/modules/CCE_module_msg.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,17 +23,39 @@
 
 /**
  * @test
- * @run main/othervm CCE_module_msg
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib ..
+ * @compile p2/c2.java
+ * @compile p4/c4.java
+ * @build sun.hotspot.WhiteBox
+ * @compile/module=java.base java/lang/reflect/ModuleHelper.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI CCE_module_msg
  */
 
+import java.io.*;
+import java.lang.reflect.Module;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import static jdk.test.lib.Asserts.*;
+
 // Test that the message in a runtime ClassCastException contains module info.
 public class CCE_module_msg {
+    private static final Path CLASSES_DIR = Paths.get("classes");
 
-    public static void main(String[] args) {
-        invalidCastTest();
+    public static void main(String[] args) throws Throwable {
+        // Should not display version
+        invalidObjectToDerived();
+        // Should display version
+        invalidClassToString();
+        // Should display customer class loader
+        invalidClassToStringCustomLoader();
     }
 
-    public static void invalidCastTest() {
+    public static void invalidObjectToDerived() {
         java.lang.Object instance = new java.lang.Object();
         int left = 23;
         int right = 42;
@@ -44,11 +66,69 @@
             throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
         } catch (ClassCastException cce) {
             System.out.println(cce.getMessage());
-            if (!cce.getMessage().contains("java.lang.Object (in module: java.base) cannot be cast")) {
+            if (!cce.getMessage().contains("java.base/java.lang.Object cannot be cast to Derived")) {
                 throw new RuntimeException("Wrong message: " + cce.getMessage());
             }
         }
     }
+
+    public static void invalidClassToString() throws Throwable {
+        // Get the java.lang.reflect.Module object for module java.base.
+        Class jlObject = Class.forName("java.lang.Object");
+        Object jlObject_jlrM = jlObject.getModule();
+        assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null");
+
+        // Get the class loader for CCE_module_msg and assume it's also used to
+        // load classes p1.c1 and p2.c2.
+        ClassLoader this_cldr = CCE_module_msg.class.getClassLoader();
+
+        // Define a module for p2.
+        Object m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" });
+        assertNotNull(m2, "Module should not be null");
+        ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" });
+        ModuleHelper.AddReadsModule(m2, jlObject_jlrM);
+
+        try {
+            ModuleHelper.AddModuleExportsToAll(m2, "p2");
+            Object p2Obj = new p2.c2();
+            System.out.println((String)p2Obj);
+            throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
+        } catch (ClassCastException cce) {
+            String exception = cce.getMessage();
+            System.out.println(exception);
+            if (exception.contains("module2/p2.c2") ||
+                !(exception.contains("module2@") &&
+                  exception.contains("/p2.c2 cannot be cast to java.base/java.lang.String"))) {
+                throw new RuntimeException("Wrong message: " + exception);
+            }
+        }
+    }
+
+    public static void invalidClassToStringCustomLoader() throws Throwable {
+        // Get the java.lang.reflect.Module object for module java.base.
+        Class jlObject = Class.forName("java.lang.Object");
+        Object jlObject_jlrM = jlObject.getModule();
+        assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null");
+
+        // Create a customer class loader to load class p4/c4.
+        URL[] urls = new URL[] { CLASSES_DIR.toUri().toURL() };
+        ClassLoader parent = ClassLoader.getSystemClassLoader();
+        MyURLClassLoader myCldr = new MyURLClassLoader("MyClassLoader", urls, parent);
+
+        try {
+            // Class p4.c4 should be defined to the unnamed module of myCldr
+            Class p4_c4_class = myCldr.loadClass("p4.c4");
+            Object c4Obj = p4_c4_class.newInstance();
+            System.out.println((String)c4Obj);
+            throw new RuntimeException("ClassCastException wasn't thrown, test failed.");
+        } catch (ClassCastException cce) {
+            String exception = cce.getMessage();
+            System.out.println(exception);
+            if (!exception.contains("MyClassLoader//p4.c4 cannot be cast to java.base/java.lang.String")) {
+                throw new RuntimeException("Wrong message: " + exception);
+            }
+        }
+    }
 }
 
 class Derived extends java.lang.Object {
@@ -56,3 +136,35 @@
         return right;
     }
 }
+
+class MyURLClassLoader extends URLClassLoader {
+    public MyURLClassLoader(String name,
+                          URL[] urls,
+                          ClassLoader parent) {
+        super(name, urls, parent);
+    }
+
+    public Class loadClass(String name) throws ClassNotFoundException {
+        if (!name.equals("p4.c4")) {
+            return super.loadClass(name);
+        }
+        byte[] data = getClassData(name);
+        return defineClass(name, data, 0, data.length);
+    }
+
+    byte[] getClassData(String name) {
+        try {
+           String TempName = name.replaceAll("\\.", "/");
+           String currentDir = System.getProperty("test.classes");
+           String filename = currentDir + File.separator + TempName + ".class";
+           FileInputStream fis = new FileInputStream(filename);
+           byte[] b = new byte[5000];
+           int cnt = fis.read(b, 0, 5000);
+           byte[] c = new byte[cnt];
+           for (int i=0; i<cnt; i++) c[i] = b[i];
+              return c;
+        } catch (IOException e) {
+           return null;
+        }
+    }
+}
diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java
index bc080e5..dd19770 100644
--- a/hotspot/test/runtime/modules/JVMDefineModule.java
+++ b/hotspot/test/runtime/modules/JVMDefineModule.java
@@ -58,9 +58,9 @@
 */
 
         // NULL package argument, should not throw an exception
-        m = ModuleHelper.ModuleObject("mymodule2", cl, new String[] { "nullpkg" });
+        m = ModuleHelper.ModuleObject("mymoduleTwo", cl, new String[] { "nullpkg" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, "9.0", "mymodule2/here", null);
+        ModuleHelper.DefineModule(m, "9.0", "mymoduleTwo/here", null);
 
         // Null module argument, expect an NPE
         try {
@@ -160,7 +160,7 @@
             // Expected
         }
 
-        // Bad module name, expect an IAE
+        // Module name with ';', not allowed in java source
         try {
             m = ModuleHelper.ModuleObject("bad;name", cl, new String[] { "mypackage9" });
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9" });
@@ -169,7 +169,7 @@
             // Expected
         }
 
-        // Bad module name, expect an IAE
+        // Module name with leading dot, not allowed in java source
         try {
             m = ModuleHelper.ModuleObject(".leadingdot", cl, new String[] { "mypackage9a" });
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9a" });
@@ -178,7 +178,7 @@
             // Expected
         }
 
-        // Bad module name, expect an IAE
+        // Module name with trailing dot, not allowed in java source
         try {
             m = ModuleHelper.ModuleObject("trailingdot.", cl, new String[] { "mypackage9b" });
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9b" });
@@ -187,11 +187,11 @@
             // Expected
         }
 
-        // Bad module name, expect an IAE
-        m = ModuleHelper.ModuleObject("consecutive..dots", cl, new String[] { "mypackage9c" });
+        // Module name with consecutive dots, not allowed in java source
         try {
-            ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9c" });
-            throw new RuntimeException("Failed to get expected IAE for consecutive..dots");
+            m = ModuleHelper.ModuleObject("trailingdot.", cl, new String[] { "mypackage9b" });
+            ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9b" });
+            throw new RuntimeException("Failed to get expected IAE for trailingdot.");
         } catch(IllegalArgumentException e) {
             // Expected
         }
@@ -207,7 +207,7 @@
         ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { });
 
         // Invalid package name, expect an IAE
-        m = ModuleHelper.ModuleObject("module5", cl, new String[] { "your.package" });
+        m = ModuleHelper.ModuleObject("moduleFive", cl, new String[] { "your.package" });
         try {
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "your.package" });
             throw new RuntimeException("Failed to get expected IAE for your.package");
@@ -218,7 +218,7 @@
         }
 
         // Invalid package name, expect an IAE
-        m = ModuleHelper.ModuleObject("module6", cl, new String[] { "foo" }); // Name irrelevant
+        m = ModuleHelper.ModuleObject("moduleSix", cl, new String[] { "foo" }); // Name irrelevant
         try {
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { ";your/package" });
             throw new RuntimeException("Failed to get expected IAE for ;your.package");
@@ -229,7 +229,7 @@
         }
 
         // Invalid package name, expect an IAE
-        m = ModuleHelper.ModuleObject("module7", cl, new String[] { "foo" }); // Name irrelevant
+        m = ModuleHelper.ModuleObject("moduleSeven", cl, new String[] { "foo" }); // Name irrelevant
         try {
             ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "7[743" });
             throw new RuntimeException("Failed to get expected IAE for package 7[743");
@@ -240,10 +240,10 @@
         }
 
         // Package named "java" defined to a class loader other than the boot or platform class loader, expect an IAE
-        m = ModuleHelper.ModuleObject("modulejavapkg1", cl, new String[] { "java/foo" });
+        m = ModuleHelper.ModuleObject("modulejavapkgOne", cl, new String[] { "java/foo" });
         try {
             // module m is defined to an instance of MyClassLoader class loader
-            ModuleHelper.DefineModule(m, "9.0", "modulejavapkg1", new String[] { "java/foo" });
+            ModuleHelper.DefineModule(m, "9.0", "modulejavapkgOne", new String[] { "java/foo" });
             throw new RuntimeException("Failed to get expected IAE for package java/foo");
         } catch(IllegalArgumentException e) {
             if (!e.getMessage().contains("prohibited package name")) {
@@ -252,43 +252,43 @@
         }
 
         // Package named "javabar" defined to a class loader other than the boot or platform class loader, should be ok
-        m = ModuleHelper.ModuleObject("modulejavapkg2", cl, new String[] { "javabar" });
+        m = ModuleHelper.ModuleObject("modulejavapkgTwo", cl, new String[] { "javabar" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg2", new String[] { "javabar" });
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkgTwo", new String[] { "javabar" });
 
         // Package named "java" defined to the boot class loader, should be ok
         //   m's type is a java.lang.Object, module is java.base
         //   java.base module is defined to the boot loader
         ClassLoader boot_loader = m.getClass().getClassLoader();
-        m = ModuleHelper.ModuleObject("modulejavapkg3", boot_loader, new String[] { "java/foo" });
+        m = ModuleHelper.ModuleObject("modulejavapkgThree", boot_loader, new String[] { "java/foo" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg3", new String[] { "java/foo" });
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkgThree", new String[] { "java/foo" });
 
         // Package named "java" defined to the platform class loader, should be ok
         //   java.sql module defined to the platform class loader.
         java.sql.Time jst = new java.sql.Time(45 * 1000);
         ClassLoader platform_loader = jst.getClass().getClassLoader();
-        m = ModuleHelper.ModuleObject("modulejavapkg4", platform_loader, new String[] { "java/foo" });
+        m = ModuleHelper.ModuleObject("modulejavapkgFour", platform_loader, new String[] { "java/foo" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg4", new String[] { "java/foo" });
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkgFour", new String[] { "java/foo" });
 
         // module version that is null, should be okay
-        m = ModuleHelper.ModuleObject("module8", cl, new String[] { "a_package_8" });
+        m = ModuleHelper.ModuleObject("moduleEight", cl, new String[] { "a_package_8" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, null, "module8/here", new String[] { "a_package_8" });
+        ModuleHelper.DefineModule(m, null, "moduleEight/here", new String[] { "a_package_8" });
 
         // module version that is "", should be okay
-        m = ModuleHelper.ModuleObject("module9", cl, new String[] { "a_package_9" });
+        m = ModuleHelper.ModuleObject("moduleNine", cl, new String[] { "a_package_9" });
         assertNotNull(m, "Module should not be null");
-        ModuleHelper.DefineModule(m, "", "module9/here", new String[] { "a_package_9" });
+        ModuleHelper.DefineModule(m, "", "moduleNine/here", new String[] { "a_package_9" });
 
         // module location that is null, should be okay
-        m = ModuleHelper.ModuleObject("module10", cl, new String[] { "a_package_10" });
+        m = ModuleHelper.ModuleObject("moduleTen", cl, new String[] { "a_package_10" });
         assertNotNull(m, "Module should not be null");
         ModuleHelper.DefineModule(m, "9.0", null, new String[] { "a_package_10" });
 
         // module location that is "", should be okay
-        m = ModuleHelper.ModuleObject("module11", cl, new String[] { "a_package_11" });
+        m = ModuleHelper.ModuleObject("moduleEleven", cl, new String[] { "a_package_11" });
         assertNotNull(m, "Module should not be null");
         ModuleHelper.DefineModule(m, "9.0", "", new String[] { "a_package_11" });
     }
diff --git a/hotspot/test/runtime/modules/p4/c4.java b/hotspot/test/runtime/modules/p4/c4.java
new file mode 100644
index 0000000..080031f
--- /dev/null
+++ b/hotspot/test/runtime/modules/p4/c4.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Small class used by multiple hotspot/runtime/modules/AccessCheck* tests.
+package p4;
+
+public class c4 {
+    public void method4() { }
+}
diff --git a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
index 07251f3..c22be26 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
@@ -116,7 +116,8 @@
         // Validate code cache segments
         String line;
         Matcher m;
-        for (int s = 0; s < segmentsCount; ++s) {
+        int matchedCount = 0;
+        while (true) {
           // Validate first line
           line = lines.next();
           m = line1.matcher(line);
@@ -128,7 +129,7 @@
                   }
               }
           } else {
-              Assert.fail("Regexp 1 failed to match line: " + line);
+              break;
           }
 
           // Validate second line
@@ -149,10 +150,14 @@
           } else {
               Assert.fail("Regexp 2 failed to match line: " + line);
           }
+          ++matchedCount;
+        }
+        // Because of CodeCacheExtensions, we could match more than expected
+        if (matchedCount < segmentsCount) {
+            Assert.fail("Fewer segments matched (" + matchedCount + ") than expected (" + segmentsCount + ")");
         }
 
         // Validate third line
-        line = lines.next();
         m = line3.matcher(line);
         if (m.matches()) {
             int blobs = Integer.parseInt(m.group(1));
diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
index 82b563b..089e8df 100644
--- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
+++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
@@ -43,7 +43,6 @@
  *          java.management
  *          jdk.jvmstat/sun.jvmstat.monitor
  * @build SimpleJvmtiAgent
- * @ignore 8150318
  * @run main ClassFileInstaller SimpleJvmtiAgent
  * @run testng LoadAgentDcmdTest
  */
diff --git a/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java b/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java
index 7cd5041..7c682b5 100644
--- a/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java
+++ b/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java
@@ -49,6 +49,17 @@
 
 public class JvmtiGetAllModulesTest {
 
+    static class MyModuleReference extends ModuleReference {
+        public MyModuleReference(ModuleDescriptor descriptor, URI uri) {
+            super(descriptor, uri);
+        }
+
+        // Trivial implementation to make the class non-abstract
+        public ModuleReader open() {
+            return null;
+        }
+    }
+
     private static native Module[] getModulesNative();
 
     private static Set<Module> getModulesJVMTI() {
@@ -103,11 +114,7 @@
 
             URI uri = URI.create("module:/" + name);
 
-            Supplier<ModuleReader> supplier = () -> {
-                throw new UnsupportedOperationException();
-            };
-
-            ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+            ModuleReference mref = new MyModuleReference(descriptor, uri);
 
             namesToReference.put(name, mref);
         }
diff --git a/hotspot/test/serviceability/sa/TestInstanceKlassSize.java b/hotspot/test/serviceability/sa/TestInstanceKlassSize.java
index e99b2a9..9890b3d 100644
--- a/hotspot/test/serviceability/sa/TestInstanceKlassSize.java
+++ b/hotspot/test/serviceability/sa/TestInstanceKlassSize.java
@@ -45,20 +45,11 @@
  * @test
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
- * @compile -XDignore.symbol.file=true
- *          --add-modules=jdk.hotspot.agent
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
- *          TestInstanceKlassSize.java
- * @run main/othervm
- *          --add-modules=jdk.hotspot.agent
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
- *          TestInstanceKlassSize
+ *          jdk.hotspot.agent/sun.jvm.hotspot
+ *          jdk.hotspot.agent/sun.jvm.hotspot.utilities
+ *          jdk.hotspot.agent/sun.jvm.hotspot.oops
+ *          jdk.hotspot.agent/sun.jvm.hotspot.debugger
+ * @run main/othervm TestInstanceKlassSize
  */
 
 public class TestInstanceKlassSize {
diff --git a/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java b/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java
index abf5412..5369c76 100644
--- a/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java
+++ b/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java
@@ -38,20 +38,11 @@
  * @test
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
- * @compile -XDignore.symbol.file=true
- *          --add-modules=jdk.hotspot.agent
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
- *          TestInstanceKlassSizeForInterface.java
- * @run main/othervm
- *          --add-modules=jdk.hotspot.agent
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
- *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED
- *          TestInstanceKlassSizeForInterface
+ *          jdk.hotspot.agent/sun.jvm.hotspot
+ *          jdk.hotspot.agent/sun.jvm.hotspot.utilities
+ *          jdk.hotspot.agent/sun.jvm.hotspot.oops
+ *          jdk.hotspot.agent/sun.jvm.hotspot.debugger
+ * @run main/othervm TestInstanceKlassSizeForInterface
  */
 
 interface Language {
diff --git a/hotspot/test/serviceability/sa/sadebugd/SADebugDTest.java b/hotspot/test/serviceability/sa/sadebugd/SADebugDTest.java
index 51b1846..80b45ec 100644
--- a/hotspot/test/serviceability/sa/sadebugd/SADebugDTest.java
+++ b/hotspot/test/serviceability/sa/sadebugd/SADebugDTest.java
@@ -28,7 +28,6 @@
  * @modules java.base/jdk.internal.misc
  * @library /test/lib
  *
- * @ignore 8163805
  * @run main/othervm SADebugDTest
  */
 import java.io.File;
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java
index 08b72d1..6723e6e 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java
@@ -45,7 +45,7 @@
         measurement1.assertConsistency();
 
         // Provoke a gc and verify the changed values
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
         gcProvoker.provokeGc();
         JstatGcCapacityResults measurement2 = jstatGcTool.measure();
         measurement2.assertConsistency();
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java
index 60c0a60..9e4c5eb 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java
@@ -47,7 +47,7 @@
         JstatGcCauseResults measurement1 = jstatGcTool.measure();
         measurement1.assertConsistency();
 
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
 
         // Provoke GC then run the tool again and get the results  asserting that they are reasonable
         gcProvoker.provokeGc();
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java
index 56ef938..2bdf04d 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java
@@ -27,11 +27,11 @@
  *          Test scenario:
  *          tests forces debuggee application eat ~70% of heap and runs jstat.
  *          jstat should show that ~70% of heap (OC/OU ~= 70%).
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
  * @modules java.base/jdk.internal.misc
  * @library /test/lib
  * @library ../share
- * @ignore 8168396
- * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcCauseTest02
+ * @run main/othervm -XX:+UsePerfData -XX:InitialHeapSize=128M -XX:MaxHeapSize=128M -XX:MaxMetaspaceSize=128M GcCauseTest02
  */
 import utils.*;
 
@@ -48,10 +48,12 @@
         JstatGcCauseResults measurement1 = jstatGcTool.measure();
         measurement1.assertConsistency();
 
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
 
         // Eat metaspace and heap then run the tool again and get the results  asserting that they are reasonable
-        gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent);
+        gcProvoker.allocateAvailableMetaspaceAndHeap(targetMemoryUsagePercent);
+        // Collect garbage. Also update VM statistics
+        System.gc();
         JstatGcCauseResults measurement2 = jstatGcTool.measure();
         measurement2.assertConsistency();
 
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java
index 10a8e60..8e1d6ae 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java
@@ -46,7 +46,7 @@
         JstatGcNewResults measurement1 = jstatGcTool.measure();
         measurement1.assertConsistency();
 
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
 
         // Provoke GC and run the tool again
         gcProvoker.provokeGc();
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcTest01.java b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java
index cabfc9e..cc0bf52 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcTest01.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java
@@ -50,7 +50,7 @@
         JstatGcResults measurement1 = jstatGcTool.measure();
         measurement1.assertConsistency();
 
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
 
         // Provoke GC then run the tool again and get the results
         // asserting that they are reasonable
diff --git a/hotspot/test/serviceability/tmtools/jstat/GcTest02.java b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java
index c46b4ad..91406fa 100644
--- a/hotspot/test/serviceability/tmtools/jstat/GcTest02.java
+++ b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java
@@ -28,11 +28,11 @@
  *          Test scenario:
  *          tests forces debuggee application eat ~70% of heap and runs jstat.
  *          jstat should show that ~70% of heap is utilized (OC/OU ~= 70%).
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
  * @modules java.base/jdk.internal.misc
  * @library /test/lib
  * @library ../share
- * @ignore 8168396
- * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcTest02
+ * @run main/othervm -XX:+UsePerfData -XX:InitialHeapSize=128M -XX:MaxHeapSize=128M -XX:MaxMetaspaceSize=128M GcTest02
  */
 
 public class GcTest02 {
@@ -48,10 +48,12 @@
         JstatGcResults measurement1 = jstatGcTool.measure();
         measurement1.assertConsistency();
 
-        GcProvoker gcProvoker = GcProvoker.createGcProvoker();
+        GcProvoker gcProvoker = new GcProvoker();
 
         // Eat metaspace and heap then run the tool again and get the results  asserting that they are reasonable
-        gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent);
+        gcProvoker.allocateAvailableMetaspaceAndHeap(targetMemoryUsagePercent);
+        // Collect garbage. Also updates VM statistics
+        System.gc();
         JstatGcResults measurement2 = jstatGcTool.measure();
         measurement2.assertConsistency();
 
diff --git a/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java
index 697b422..f2111fa 100644
--- a/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,34 +22,136 @@
  */
 package utils;
 
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
- * This is an interface used to provoke GC and perform other GC-related
+ * This is an class used to provoke GC and perform other GC-related
  * procedures
  *
  */
-public interface GcProvoker {
+public class GcProvoker{
 
-    /**
-     * The default implementation
-     *
-     * @return the default GC provoker
-     */
-    public static GcProvoker createGcProvoker() {
-        return new GcProvokerImpl();
+    // Uses fixed small objects to avoid Humongous objects allocation in G1
+    public static final int MEMORY_CHUNK = 2048;
+    public static final float ALLOCATION_TOLERANCE = 0.05f;
+
+    public static List<Object> allocatedMetaspace;
+    public static List<Object> allocatedMemory;
+
+    private final Runtime runtime;
+
+    private List<Object> allocateHeap(float targetUsage) {
+        long maxMemory = runtime.maxMemory();
+        List<Object> list = new ArrayList<>();
+        long used = 0;
+        long target = (long) (maxMemory * targetUsage);
+        while (used < target) {
+            try {
+                list.add(new byte[MEMORY_CHUNK]);
+                used += MEMORY_CHUNK;
+            } catch (OutOfMemoryError e) {
+                list = null;
+                throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "' while eating " + targetUsage + " of heap memory.");
+            }
+        }
+        return list;
+    }
+
+    private List<Object> allocateAvailableHeap(float targetUsage) {
+        // Calculates size of free memory after allocation with small tolerance.
+        long minFreeMemory = (long) ((1.0 - (targetUsage + ALLOCATION_TOLERANCE)) * runtime.maxMemory());
+        List<Object> list = new ArrayList<>();
+        do {
+            try {
+                list.add(new byte[MEMORY_CHUNK]);
+            } catch (OutOfMemoryError e) {
+                list = null;
+                throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "' while eating " + targetUsage + " of heap memory.");
+            }
+        } while (runtime.freeMemory() > minFreeMemory);
+        return list;
     }
 
     /**
      * This method provokes a GC
      */
-    public void provokeGc();
+    public void provokeGc() {
+        for (int i = 0; i < 3; i++) {
+            long edenSize = Pools.getEdenCommittedSize();
+            long heapSize = Pools.getHeapCommittedSize();
+            float targetPercent = ((float) edenSize) / (heapSize);
+            if ((targetPercent < 0) || (targetPercent > 1.0)) {
+                throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")");
+            }
+            allocateHeap(targetPercent);
+            allocateHeap(targetPercent);
+            System.gc();
+        }
+    }
 
     /**
-     * Eats heap and metaspace Upon exit targetMemoryUsagePercent percents of
-     * heap and metaspace is have been eaten
+     * Allocates heap and metaspace upon exit not less than targetMemoryUsagePercent percents
+     * of heap and metaspace have been consumed.
      *
      * @param targetMemoryUsagePercent how many percent of heap and metaspace to
-     * eat
+     * allocate
      */
-    public void eatMetaspaceAndHeap(float targetMemoryUsagePercent);
+
+    public void allocateMetaspaceAndHeap(float targetMemoryUsagePercent) {
+        // Metaspace should be filled before Java Heap to prevent unexpected OOME
+        // in the Java Heap while filling Metaspace
+        allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent);
+        allocatedMemory = allocateHeap(targetMemoryUsagePercent);
+    }
+
+    /**
+     * Allocates heap and metaspace upon exit targetMemoryUsagePercent percents
+     * of heap and metaspace have been consumed.
+     *
+     * @param targetMemoryUsagePercent how many percent of heap and metaspace to
+     * allocate
+     */
+    public void allocateAvailableMetaspaceAndHeap(float targetMemoryUsagePercent) {
+        // Metaspace should be filled before Java Heap to prevent unexpected OOME
+        // in the Java Heap while filling Metaspace
+        allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent);
+        allocatedMemory = allocateAvailableHeap(targetMemoryUsagePercent);
+    }
+
+    private List<Object> eatMetaspace(float targetUsage) {
+        List<Object> list = new ArrayList<>();
+        final String metaspacePoolName = "Metaspace";
+        MemoryPoolMXBean metaspacePool = null;
+        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+            if (pool.getName().contains(metaspacePoolName)) {
+                metaspacePool = pool;
+                break;
+            }
+        }
+        if (metaspacePool == null) {
+            throw new RuntimeException("MXBean for Metaspace pool wasn't found");
+        }
+        float currentUsage;
+        GeneratedClassProducer gp = new GeneratedClassProducer();
+        do {
+            try {
+                list.add(gp.create(0));
+            } catch (OutOfMemoryError oome) {
+                list = null;
+                throw new RuntimeException("Unexpected OOME '" + oome.getMessage() + "' while eating " + targetUsage + " of Metaspace.");
+            }
+            MemoryUsage memoryUsage = metaspacePool.getUsage();
+            currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax());
+        } while (currentUsage < targetUsage);
+        return list;
+    }
+
+    public GcProvoker() {
+        runtime = Runtime.getRuntime();
+    }
 
 }
diff --git a/hotspot/test/test_env.sh b/hotspot/test/test_env.sh
index 4814471..43d1a76 100644
--- a/hotspot/test/test_env.sh
+++ b/hotspot/test/test_env.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-#  Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+#  Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
 #  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 # 
 #  This code is free software; you can redistribute it and/or modify it
@@ -204,6 +204,11 @@
 then
   VM_CPU="ia64"
 fi
+grep "s390x" vm_version.out > ${NULL}
+if [ $? = 0 ]
+then
+  VM_CPU="s390x"
+fi
 grep "aarch64" vm_version.out > ${NULL}
 if [ $? = 0 ]
 then
diff --git a/hotspot/test/testlibrary/jittester/Makefile b/hotspot/test/testlibrary/jittester/Makefile
index 720b69c..14f0cb3 100644
--- a/hotspot/test/testlibrary/jittester/Makefile
+++ b/hotspot/test/testlibrary/jittester/Makefile
@@ -107,7 +107,7 @@
 INIT: $(DIST_DIR)
 	$(shell if [ ! -d $(CLASSES_DIR) ]; then mkdir -p $(CLASSES_DIR); fi)
 
-install: clean_testbase testgroup testroot copytestlibrary JAR cleantmp
+install: clean_testbase testgroup testroot copytestlibrary copyaot JAR cleantmp
 	$(JAVA) --add-exports=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED -ea -jar $(DIST_JAR) $(APPLICATION_ARGS)
 
 clean_testbase:
@@ -121,6 +121,9 @@
 	@cp -r src/jdk/test/lib/jittester/jtreg/*.java $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
 	@cp -r $(TESTLIBRARY_SRC_DIR) $(TESTBASE_DIR)/jdk/test/
 
+copyaot: $(TESTBASE_DIR)/compiler/aot
+	@cp ../../compiler/aot/AotCompiler.java $(TESTBASE_DIR)/compiler/aot
+
 testgroup: $(TESTBASE_DIR)
 	@echo 'jittester_all = \\' > $(TESTGROUP_FILE)
 	@echo '	/' >> $(TESTGROUP_FILE)
@@ -129,6 +132,6 @@
 testroot: $(TESTBASE_DIR)
 	@echo 'groups=TEST.groups' > $(TESTROOT_FILE)
 
-$(TESTBASE_DIR) $(DIST_DIR) $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg:
+$(TESTBASE_DIR) $(DIST_DIR) $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg $(TESTBASE_DIR)/compiler/aot:
 	$(shell if [ ! -d $@ ]; then mkdir -p $@; fi)
 
diff --git a/hotspot/test/testlibrary/jittester/conf/default.properties b/hotspot/test/testlibrary/jittester/conf/default.properties
index e5d8a0b..2582c59 100644
--- a/hotspot/test/testlibrary/jittester/conf/default.properties
+++ b/hotspot/test/testlibrary/jittester/conf/default.properties
@@ -9,5 +9,5 @@
 print-complexity=true
 print-hierarchy=true
 disable-static=true
-generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory
+generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory,jdk.test.lib.jittester.AotTestGeneratorsFactory
 generators=JavaCode,ByteCode
diff --git a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java
new file mode 100644
index 0000000..491c32d
--- /dev/null
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/AotTestGeneratorsFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jittester;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class AotTestGeneratorsFactory implements Function<String[], List<TestsGenerator>> {
+    private static final String AOT_OPTIONS = "-XX:+UseAOT -XX:AOTLibrary=./aottest.so";
+    private static final String AOT_COMPILER_BUILD_ACTION
+            = "@build compiler.aot.AotCompiler";
+    private static final String AOT_COMPILER_RUN_ACTION_PREFIX
+            = "@run driver compiler.aot.AotCompiler -libname aottest.so -class ";
+
+    @Override
+    public List<TestsGenerator> apply(String[] input) {
+        List<TestsGenerator> result = new ArrayList<>();
+        for (String generatorName : input) {
+            switch (generatorName) {
+                case "ByteCode":
+                    result.add(new ByteCodeGenerator("aot_bytecode_tests",
+                            AotTestGeneratorsFactory::generateBytecodeHeader, AOT_OPTIONS));
+                    break;
+                case "JavaCode":
+                    result.add(new JavaCodeGenerator("aot_java_tests",
+                            AotTestGeneratorsFactory::generateJavaHeader, AOT_OPTIONS));
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown generator: " + generatorName);
+            }
+        }
+        return result;
+    }
+
+    private static String[] generateBytecodeHeader(String mainClassName) {
+        return new String[]{
+            AOT_COMPILER_BUILD_ACTION,
+            AOT_COMPILER_RUN_ACTION_PREFIX + mainClassName
+        };
+    }
+
+    private static String[] generateJavaHeader(String mainClassName) {
+        return new String[]{
+            "@compile " + mainClassName + ".java",
+            AOT_COMPILER_BUILD_ACTION,
+            AOT_COMPILER_RUN_ACTION_PREFIX + mainClassName
+        };
+    }
+}
diff --git a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
index 0d38e16..43c9715 100644
--- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
+++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
@@ -45,7 +45,7 @@
  */
 public class TestMutuallyExclusivePlatformPredicates {
     private static enum MethodGroup {
-        ARCH("isARM", "isPPC", "isSparc", "isX86", "isX64", "isAArch64"),
+        ARCH("isAArch64", "isARM", "isPPC", "isS390x", "isSparc", "isX64", "isX86"),
         BITNESS("is32bit", "is64bit"),
         OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"),
         VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"),
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index 70aeffb..f45d26b 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -391,3 +391,4 @@
 09eda28b98e4b9cae1d29e94f0cf1a01cc42c207 jdk-9+146
 149559dd882ddca2c78355641a46db9138b12763 jdk-9+147
 c45db75bfe8bc20bb80b4a009ae3f69c9cd2d885 jdk-9+148
+5978df8bfa3894f2b3d07b7256f25f78dffb1f9c jdk-9+149
diff --git a/jaxp/THIRD_PARTY_README b/jaxp/THIRD_PARTY_README
deleted file mode 100644
index 4d30070..0000000
--- a/jaxp/THIRD_PARTY_README
+++ /dev/null
@@ -1,3604 +0,0 @@
-DO NOT TRANSLATE OR LOCALIZE.
------------------------------
-
-%% This notice is provided with respect to ASM Bytecode Manipulation 
-Framework v5.0, which may be included with JRE 8, and JDK 8, and 
-OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2011 France Télécom
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holders nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to BSDiff v4.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 2003-2005 Colin Percival
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CodeViewer 1.0, which may be
-included with JDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1999 by CoolServlets.com.
-
-Any errors or suggested improvements to this class can be reported as
-instructed on CoolServlets.com. We hope you enjoy this program... your
-comments will encourage further development!  This software is distributed
-under the terms of the BSD License.  Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-Neither name of CoolServlets.com nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Cryptix AES 3.2.0, which may be
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Cryptix General License
-
-Copyright (c) 1995-2005 The Cryptix Foundation Limited.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  1. Redistributions of source code must retain the copyright notice,
-     this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CUP Parser Generator for 
-Java 0.10k, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted, provided
-that the above copyright notice appear in all copies and that both the
-copyright notice and this permission notice and warranty disclaimer appear in
-supporting documentation, and that the names of the authors or their
-employers not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission.
-
-The authors and their employers disclaim all warranties with regard to
-this software, including all implied warranties of merchantability and fitness.
-In no event shall the authors or their employers be liable for any special,
-indirect or consequential damages or any damages whatsoever resulting from
-loss of use, data or profits, whether in an action of contract, negligence or
-other tortious action, arising out of or in connection with the use or
-performance of this software.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Document Object Model (DOM) Level 2
-& 3, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-W3C SOFTWARE NOTICE AND LICENSE
-
-http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
-
-This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license. By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following terms
-and conditions.
-
-Permission to copy, modify, and distribute this software and its
-documentation, with or without modification, for any purpose and without fee
-or royalty is hereby granted, provided that you include the following on ALL
-copies of the software and documentation or portions thereof, including
-modifications:
-
-   1.The full text of this NOTICE in a location viewable to users of the
-   redistributed or derivative work.
-
-   2.Any pre-existing intellectual property disclaimers, notices, or terms and
-   conditions. If none exist, the W3C Software Short Notice should be included
-   (hypertext is preferred, text is permitted) within the body of any
-   redistributed or derivative code.
-
-   3.Notice of any changes or modifications to the files, including the date
-   changes were made. (We recommend you provide URIs to the location from
-   which the code is derived.)
-
-THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
-THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
-COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
-in advertising or publicity pertaining to the software without specific,
-written prior permission. Title to copyright in this software and any
-associated documentation will at all times remain with copyright holders.
-
-____________________________________
-
-This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C, reflects
-that ERCIM is now a host of the W3C, includes references to this specific
-dated version of the license, and removes the ambiguous grant of "use".
-Otherwise, this version is the same as the previous version and is written so
-as to preserve the Free Software Foundation's assessment of GPL compatibility
-and OSI's certification under the Open Source Definition. Please see our
-Copyright FAQ for common questions about using materials from our site,
-including specific terms and conditions for packages like libwww, Amaya, and
-Jigsaw. Other questions about this notice can be directed to
-site-policy@w3.org.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Dynalink v0.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2009-2013, Attila Szegedi
-
-All rights reserved.Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following conditions are
-met:* Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.  * Redistributions in
-binary form must reproduce the above copyright notice,   this list of
-conditions and the following disclaimer in the documentation  and/or other
-materials provided with the distribution.  * Neither the name of Attila
-Szegedi nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Elliptic Curve Cryptography, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
-You are receiving a copy of the Elliptic Curve Cryptography library in source
-form with the JDK 8 and OpenJDK 8 source distributions, and as object code in
-the JRE 8 & JDK 8 runtimes.
-
-In the case of the JRE 8 & JDK 8 runtimes, the terms of the Oracle license do
-NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
-following license, separately from Oracle's JDK & JRE.  If you do not wish to
-install the Elliptic Curve Cryptography library, you may delete the library
-named libsunec.so (on Solaris and Linux systems) or sunec.dll (on Windows
-systems) from the JRE bin directory reserved for native libraries.
-
-
---- begin of LICENSE ---
-
-                  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!
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to  ECMAScript Language
-Specification ECMA-262 Edition 5.1 which may be included with 
-JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright notice
-Copyright © 2011 Ecma International
-Ecma International
-Rue du Rhone 114
-CH-1204 Geneva
-Tel: +41 22 849 6000
-Fax: +41 22 849 6001
-Web: http://www.ecma-international.org
-
-This document and possible translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it or assist
-in its implementation may be prepared, copied, published, and distributed, in
-whole or in part, without restriction of any kind, provided that the above
-copyright notice and this section are included on all such copies and derivative
-works. However, this document itself may not be modified in any way, including
-by removing the copyright notice or references to Ecma International, except as
-needed for the purpose of developing any document or deliverable produced by
-Ecma International (in which case the rules applied to copyrights must be
-followed) or as required to translate it into languages other than English. The
-limited permissions granted above are perpetual and will not be revoked by Ecma
-International or its successors or assigns. This document and the information
-contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL
-DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
-WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
-RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
-PURPOSE." Software License
-
-All Software contained in this document ("Software)" is protected by copyright
-and is being made available under the "BSD License", included below. This
-Software may be subject to third party rights (rights from parties other than
-Ecma International), including patent rights, and no licenses under such third
-party rights are granted under this license even if the third party concerned is
-a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS
-AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
-INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO
-IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the authors nor Ecma International may be used to endorse
-or promote products derived from this software without specific prior written
-permission.
-
-THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Dynalink library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Copyright (c) 2009-2013, Attila Szegedi
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the copyright holder nor the names of
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Joni library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to FontConfig 2.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 source distributions on
-Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright © 2001,2003 Keith Packard
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation, and that
-the name of Keith Packard not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior permission.
-Keith Packard makes no representations about the suitability of this software
-for any purpose.  It is provided "as is" without express or implied warranty.
-
-KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IAIK PKCS#11 Wrapper, 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-IAIK PKCS#11 Wrapper License
-
-Copyright (c) 2002 Graz University of Technology. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-   "This product includes software developed by IAIK of Graz University of
-    Technology."
-
-   Alternately, this acknowledgment may appear in the software itself, if and
-   wherever such third-party acknowledgments normally appear.
-
-4. The names "Graz University of Technology" and "IAIK of Graz University of
-   Technology" must not be used to endorse or promote products derived from this
-   software without prior written permission.
-
-5. Products derived from this software may not be called "IAIK PKCS Wrapper",
-   nor may "IAIK" appear in their name, without prior written permission of
-   Graz University of Technology.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to ICU4C 4.0.1 and ICU4J 4.4, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 1995-2010 International Business Machines Corporation and others 
-
-All rights reserved. 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice appear
-in all copies of the Software and that both the above copyright notice(s) and
-this permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
-All trademarks and registered trademarks mentioned herein are the property of
-their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IJG JPEG 6b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library.  If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it.  This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Joni v1.1.9, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JOpt-Simple v3.0,  which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (c) 2004-2009 Paul R. Holser, Jr.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JSON, which may be included 
-with JRE 8 & JDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality, which 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- (C) Copyright IBM Corp. 1999 All Rights Reserved.
- Copyright 1997 The Open Group Research Institute. All rights reserved.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality from 
-FundsXpress, INC., which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (C) 1998 by the FundsXpress, INC.
-
- All rights reserved.
-
- Export of this software from the United States of America may require
- a specific license from the United States Government.  It is the
- responsibility of any person or organization contemplating export to
- obtain such a license before exporting.
-
- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- distribute this software and its documentation for any purpose and
- without fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation, and that
- the name of FundsXpress. not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.  FundsXpress makes no representations about the suitability of
- this software for any purpose.  It is provided "as is" without express
- or implied warranty.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kronos OpenGL headers, which may be 
-included with JDK 8 and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Copyright (c) 2007 The Khronos Group Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and/or associated documentation files (the "Materials"), to
- deal in the Materials without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Materials, and to permit persons to whom the Materials are
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Materials.
-
- THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- MATERIALS.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions Copyright Eastman Kodak Company 1992
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libpng 1.5.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This copy of the libpng notices is provided for your convenience.  In case of
-any discrepancy between this copy and the notices in the file png.h that is
-included in the libpng distribution, the latter shall prevail.
-
-COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
-
-If you modify libpng you may insert additional notices immediately following
-this sentence.
-
-This code is released under the libpng license.
-
-libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
-Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.2.5
-with the following individual added to the list of Contributing Authors
-
-   Cosmin Truta
-
-libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
-Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.0.6
-with the following individuals added to the list of Contributing Authors
-
-   Simon-Pierre Cadieux
-   Eric S. Raymond
-   Gilles Vollant
-
-and with the following additions to the disclaimer:
-
-   There is no warranty against interference with your enjoyment of the
-   library or against infringement.  There is no warranty that our
-   efforts or the library will fulfill any of your particular purposes
-   or needs.  This library is provided with all faults, and the entire
-   risk of satisfactory quality, performance, accuracy, and effort is with
-   the user.
-
-libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
-Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-0.96,
-with the following individuals added to the list of Contributing Authors:
-
-   Tom Lane
-   Glenn Randers-Pehrson
-   Willem van Schaik
-
-libpng versions 0.89, June 1996, through 0.96, May 1997, are
-Copyright (c) 1996, 1997 Andreas Dilger
-Distributed according to the same disclaimer and license as libpng-0.88,
-with the following individuals added to the list of Contributing Authors:
-
-   John Bowler
-   Kevin Bracey
-   Sam Bushell
-   Magnus Holmgren
-   Greg Roelofs
-   Tom Tanner
-
-libpng versions 0.5, May 1995, through 0.88, January 1996, are
-Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-
-For the purposes of this copyright and license, "Contributing Authors"
-is defined as the following set of individuals:
-
-   Andreas Dilger
-   Dave Martindale
-   Guy Eric Schalnat
-   Paul Schmidt
-   Tim Wegner
-
-The PNG Reference Library is supplied "AS IS".  The Contributing Authors
-and Group 42, Inc. disclaim all warranties, expressed or implied,
-including, without limitation, the warranties of merchantability and of
-fitness for any purpose.  The Contributing Authors and Group 42, Inc.
-assume no liability for direct, indirect, incidental, special, exemplary,
-or consequential damages, which may result from the use of the PNG
-Reference Library, even if advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-source code, or portions hereof, for any purpose, without fee, subject
-to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-
-2. Altered versions must be plainly marked as such and must not
-   be misrepresented as being the original source.
-
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The Contributing Authors and Group 42, Inc. specifically permit, without
-fee, and encourage the use of this source code as a component to
-supporting the PNG file format in commercial products.  If you use this
-source code in a product, acknowledgment is not required but would be
-appreciated.
-
-
-A "png_get_copyright" function is available, for convenient use in "about"
-boxes and the like:
-
-   printf("%s",png_get_copyright(NULL));
-
-Also, the PNG logo (in PNG format, of course) is supplied in the
-files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
-
-Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
-certification mark of the Open Source Initiative.
-
-Glenn Randers-Pehrson
-glennrp at users.sourceforge.net
-July 7, 2011
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libungif 4.1.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Little CMS 2.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Little CMS
-Copyright (c) 1998-2010 Marti Maria Saguer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Lucida is a registered trademark or trademark of Bigelow & Holmes in the
-U.S. and other countries.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mesa 3D Graphics Library v4.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Mesa 3-D graphics library
- Version:  4.1
-
- Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mozilla Network Security
-Services (NSS), which is supplied with the JDK test suite in the OpenJDK
-source code repository. It is licensed under Mozilla Public License (MPL),
-version 2.0.
-
-The NSS libraries are supplied in executable form, built from unmodified
-NSS source code labeled with the "NSS_3.13.1_RTM" release tag.
-
-The NSS source code is available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/src
-
-The NSS libraries are available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/lib
-
---- begin of LICENSE ---
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PC/SC Lite for Suse Linux v.1.1.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
-Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by: 
-      David Corcoran <corcoran@linuxnet.com>
-      http://www.linuxnet.com (MUSCLE)
-4. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-Changes to this license can be made only by the copyright author with 
-explicit written consent.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PorterStemmer v4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-See: http://tartarus.org/~martin/PorterStemmer
-
-The software is completely free for any purpose, unless notes at the head of
-the program text indicates otherwise (which is rare). In any case, the notes
-about licensing are never more restrictive than the BSD License.
-
-In every case where the software is not written by me (Martin Porter), this
-licensing arrangement has been endorsed by the contributor, and it is
-therefore unnecessary to ask the contributor again to confirm it.
-
-I have not asked any contributors (or their employers, if they have them) for
-proofs that they have the right to distribute their software in this way.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Relax NG Object/Parser v.20050510,
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions: The above copyright
-notice and this permission notice shall be included in all copies or
-substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to RelaxNGCC v1.12, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2003 Daisuke Okajima and Kohsuke Kawaguchi.  
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-    "This product includes software developed by Daisuke Okajima
-    and Kohsuke Kawaguchi (http://relaxngcc.sf.net/)."
-
-Alternately, this acknowledgment may appear in the software itself, if and
-wherever such third-party acknowledgments normally appear.
-
-4. The names of the copyright holders must not be used to endorse or promote
-   products derived from this software without prior written permission. For
-   written permission, please contact the copyright holders.
-
-5. Products derived from this software may not be called "RELAXNGCC", nor may
-  "RELAXNGCC" appear in their name, without prior written permission of the
-  copyright holders.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE APACHE
-SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SAX 2.0.1, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- SAX is free!
-
- In fact, it's not possible to own a license to SAX, since it's been placed in
- the public domain.
-
- No Warranty
-
- Because SAX is released to the public domain, there is no warranty for the
- design or for the software implementation, to the extent permitted by
- applicable law. Except when otherwise stated in writing the copyright holders
- and/or other parties provide SAX "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 SAX is with you. Should SAX prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- 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
- SAX, be liable to you for damages, including any general, special, incidental
- or consequential damages arising out of the use or inability to use SAX
- (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 SAX to
- operate with any other programs), even if such holder or other party has been
- advised of the possibility of such damages.
-
- Copyright Disclaimers 
-
- This page includes statements to that effect by David Megginson, who would
- have been able to claim copyright for the original work.  SAX 1.0
-
- Version 1.0 of the Simple API for XML (SAX), created collectively by the
- membership of the XML-DEV mailing list, is hereby released into the public
- domain.
-
- No one owns SAX: you may use it freely in both commercial and non-commercial
- applications, bundle it with your software distribution, include it on a
- CD-ROM, list the source code in a book, mirror the documentation at your own
- web site, or use it in any other way you see fit.
-
- David Megginson, sax@megginson.com
- 1998-05-11
-
- SAX 2.0 
-
- I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and
- release all of the SAX 2.0 source code, compiled code, and documentation
- contained in this distribution into the Public Domain. SAX comes with NO
- WARRANTY or guarantee of fitness for any purpose.
-
- David Megginson, david@megginson.com
- 2000-05-05
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SoftFloat version 2b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux/ARM.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-SoftFloat was written by me, John R. Hauser. This work was made possible in 
-part by the International Computer Science Institute, located at Suite 600, 
-1947 Center Street, Berkeley, California 94704. Funding was partially 
-provided by the National Science Foundation under grant MIP-9311980. The 
-original version of this code was written as part of a project to build 
-a fixed-point vector processor in collaboration with the University of 
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. 
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort 
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT 
-TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO 
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL 
-LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO 
-FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER 
-SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, 
-COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE 
-SOFTWARE. 
-
-Derivative works are acceptable, even for commercial purposes, provided 
-that the minimal documentation requirements stated in the source code are 
-satisfied. 
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Sparkle 1.5,
-which may be included with JRE 8 on Mac OS X.
-
---- begin of LICENSE ---
-
-Copyright (c) 2012 Sparkle.org and Andy Matuschak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions licensed from Taligent, Inc.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Thai Dictionary, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (C) 1982 The Royal Institute, Thai Royal Government.
-
-Copyright (C) 1998 National Electronics and Computer Technology Center,
-National Science and Technology Development Agency,
-Ministry of Science Technology and Environment,
-Thai Royal Government.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Unicode 6.2.0 & CLDR 21.0.1
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Unicode Terms of Use
-
-For the general privacy policy governing access to this site, see the Unicode
-Privacy Policy. For trademark usage, see the Unicode® Consortium Name and
-Trademark Usage Policy.
-
-A. Unicode Copyright.
-   1. Copyright © 1991-2013 Unicode, Inc. All rights reserved.
-
-   2. Certain documents and files on this website contain a legend indicating
-      that "Modification is permitted." Any person is hereby authorized,
-      without fee, to modify such documents and files to create derivative
-      works conforming to the Unicode® Standard, subject to Terms and
-      Conditions herein.
-
-    3. Any person is hereby authorized, without fee, to view, use, reproduce,
-       and distribute all documents and files solely for informational
-       purposes in the creation of products supporting the Unicode Standard,
-       subject to the Terms and Conditions herein.
-
-    4. Further specifications of rights and restrictions pertaining to the use
-       of the particular set of data files known as the "Unicode Character
-       Database" can be found in Exhibit 1.
-
-    5. Each version of the Unicode Standard has further specifications of
-       rights and restrictions of use. For the book editions (Unicode 5.0 and
-       earlier), these are found on the back of the title page. The online
-       code charts carry specific restrictions. All other files, including
-       online documentation of the core specification for Unicode 6.0 and
-       later, are covered under these general Terms of Use.
-
-    6. No license is granted to "mirror" the Unicode website where a fee is
-       charged for access to the "mirror" site.
-
-    7. Modification is not permitted with respect to this document. All copies
-       of this document must be verbatim.
-
-B. Restricted Rights Legend. Any technical data or software which is licensed
-   to the United States of America, its agencies and/or instrumentalities
-   under this Agreement is commercial technical data or commercial computer
-   software developed exclusively at private expense as defined in FAR 2.101,
-   or DFARS 252.227-7014 (June 1995), as applicable. For technical data, use,
-   duplication, or disclosure by the Government is subject to restrictions as
-   set forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov
-   1995) and this Agreement. For Software, in accordance with FAR 12-212 or
-   DFARS 227-7202, as applicable, use, duplication or disclosure by the
-   Government is subject to the restrictions set forth in this Agreement.
-
-C. Warranties and Disclaimers.
-   1. This publication and/or website may include technical or typographical
-      errors or other inaccuracies . Changes are periodically added to the
-      information herein; these changes will be incorporated in new editions
-      of the publication and/or website. Unicode may make improvements and/or
-      changes in the product(s) and/or program(s) described in this
-      publication and/or website at any time.
-
-    2. If this file has been purchased on magnetic or optical media from
-       Unicode, Inc. the sole and exclusive remedy for any claim will be
-       exchange of the defective media within ninety (90) days of original
-       purchase.
-
-    3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR SOFTWARE IS
-       PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, IMPLIED,
-       OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
-       UNICODE AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR
-       OMISSIONS IN THIS PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH
-       ARE REFERENCED BY OR LINKED TO THIS PUBLICATION OR THE UNICODE WEBSITE.
-
-D. Waiver of Damages. In no event shall Unicode or its licensors be liable for
-   any special, incidental, indirect or consequential damages of any kind, or
-   any damages whatsoever, whether or not Unicode was advised of the
-   possibility of the damage, including, without limitation, those resulting
-   from the following: loss of use, data or profits, in connection with the
-   use, modification or distribution of this information or its derivatives.
-
-E.Trademarks & Logos.
-   1. The Unicode Word Mark and the Unicode Logo are trademarks of Unicode,
-      Inc.  “The Unicode Consortium” and “Unicode, Inc.” are trade names of
-      Unicode, Inc.  Use of the information and materials found on this
-      website indicates your acknowledgement of Unicode, Inc.’s exclusive
-      worldwide rights in the Unicode Word Mark, the Unicode Logo, and the
-      Unicode trade names.
-
-   2. The Unicode Consortium Name and Trademark Usage Policy (“Trademark
-      Policy”) are incorporated herein by reference and you agree to abide by
-      the provisions of the Trademark Policy, which may be changed from time
-      to time in the sole discretion of Unicode, Inc.
-
-   3. All third party trademarks referenced herein are the property of their
-      respective owners.
-
-Miscellaneous.
-   1. Jurisdiction and Venue. This server is operated from a location in the
-      State of California, United States of America. Unicode makes no
-      representation that the materials are appropriate for use in other
-      locations. If you access this server from other locations, you are
-      responsible for compliance with local laws. This Agreement, all use of
-      this site and any claims and damages resulting from use of this site are
-      governed solely by the laws of the State of California without regard to
-      any principles which would apply the laws of a different jurisdiction.
-      The user agrees that any disputes regarding this site shall be resolved
-      solely in the courts located in Santa Clara County, California. The user
-      agrees said courts have personal jurisdiction and agree to waive any
-      right to transfer the dispute to any other forum.
-
-   2. Modification by Unicode.  Unicode shall have the right to modify this
-      Agreement at any time by posting it to this site. The user may not
-      assign any part of this Agreement without Unicode’s prior written
-      consent.
-
-   3. Taxes. The user agrees to pay any taxes arising from access to this
-      website or use of the information herein, except for those based on
-      Unicode’s net income.
-
-   4. Severability.  If any provision of this Agreement is declared invalid or
-      unenforceable, the remaining provisions of this Agreement shall remain
-      in effect.
-
-   5. Entire Agreement. This Agreement constitutes the entire agreement
-      between the parties.
-
-EXHIBIT 1
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-Unicode Data Files include all data files under the directories
-http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
-http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
-online code charts under the directory http://www.unicode.org/Public/.
-Software includes any source code published in the Unicode Standard or under
-the directories http://www.unicode.org/Public/,
-http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
-
-NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
-INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
-FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
-BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
-AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
-SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under the
-Terms of Use in http://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the Unicode data files and any associated documentation (the "Data Files")
-or Unicode software and any associated documentation (the "Software") to deal
-in the Data Files or Software without restriction, including without
-limitation the rights to use, copy, modify, merge, publish, distribute, and/or
-sell copies of the Data Files or Software, and to permit persons to whom the
-Data Files or Software are furnished to do so, provided that (a) the above
-copyright notice(s) and this permission notice appear with all copies of the
-Data Files or Software, (b) both the above copyright notice(s) and this
-permission notice appear in associated documentation, and (c) there is clear
-notice in each modified Data File or in the Software as well as in the
-documentation associated with the Data File(s) or Software that the data or
-software has been modified.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
-THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
-DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in these Data Files or Software without prior written authorization of the
-copyright holder.
-
-Unicode and the Unicode logo are trademarks of Unicode, Inc. in the United
-States and other countries. All third party trademarks referenced herein are
-the property of their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to UPX v3.01, which may be included 
-with JRE 8 on Windows.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-
-                 ooooo     ooo ooooooooo.   ooooooo  ooooo
-                 `888'     `8' `888   `Y88.  `8888    d8'
-                  888       8   888   .d88'    Y888..8P
-                  888       8   888ooo88P'      `8888'
-                  888       8   888            .8PY888.
-                  `88.    .8'   888           d8'  `888b
-                    `YbodP'    o888o        o888o  o88888o
-
-
-                    The Ultimate Packer for eXecutables
-          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
-               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
-                          http://www.nexus.hu/upx
-                            http://upx.tsx.org
-
-
-PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
-TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
-
-
-ABSTRACT
-========
-
-   UPX and UCL are copyrighted software distributed under the terms
-   of the GNU General Public License (hereinafter the "GPL").
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   As a special exception we grant the free usage of UPX for all
-   executables, including commercial programs.
-   See below for details and restrictions.
-
-
-COPYRIGHT
-=========
-
-   UPX and UCL are copyrighted software. All rights remain with the authors.
-
-   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-   UPX is Copyright (C) 1996-2000 Laszlo Molnar
-
-   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-
-
-GNU GENERAL PUBLIC LICENSE
-==========================
-
-   UPX and the UCL library are free software; you can redistribute them
-   and/or modify them under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   UPX and UCL are distributed in the hope that they will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; see the file COPYING.
-
-
-SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
-============================================
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
-   permission to freely use and distribute all UPX compressed programs
-   (including commercial ones), subject to the following restrictions:
-
-   1. You must compress your program with a completely unmodified UPX
-      version; either with our precompiled version, or (at your option)
-      with a self compiled version of the unmodified UPX sources as
-      distributed by us.
-   2. This also implies that the UPX stub must be completely unmodfied, i.e.
-      the stub imbedded in your compressed program must be byte-identical
-      to the stub that is produced by the official unmodified UPX version.
-   3. The decompressor and any other code from the stub must exclusively get
-      used by the unmodified UPX stub for decompressing your program at
-      program startup. No portion of the stub may get read, copied,
-      called or otherwise get used or accessed by your program.
-
-
-ANNOTATIONS
-===========
-
-  - You can use a modified UPX version or modified UPX stub only for
-    programs that are compatible with the GNU General Public License.
-
-  - We grant you special permission to freely use and distribute all UPX
-    compressed programs. But any modification of the UPX stub (such as,
-    but not limited to, removing our copyright string or making your
-    program non-decompressible) will immediately revoke your right to
-    use and distribute a UPX compressed program.
-
-  - UPX is not a software protection tool; by requiring that you use
-    the unmodified UPX version for your proprietary programs we
-    make sure that any user can decompress your program. This protects
-    both you and your users as nobody can hide malicious code -
-    any program that cannot be decompressed is highly suspicious
-    by definition.
-
-  - You can integrate all or part of UPX and UCL into projects that
-    are compatible with the GNU GPL, but obviously you cannot grant
-    any special exceptions beyond the GPL for our code in your project.
-
-  - We want to actively support manufacturers of virus scanners and
-    similar security software. Please contact us if you would like to
-    incorporate parts of UPX or UCL into such a product.
-
-
-
-Markus F.X.J. Oberhumer                   Laszlo Molnar
-markus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu
-
-Linz, Austria, 25 Feb 2000
-
-Additional License(s)
-
-The UPX license file is at http://upx.sourceforge.net/upx-license.html.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Xfree86-VidMode Extension 1.0,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Version 1.1 of XFree86 ProjectLicence.
-
-Copyright (C) 1994-2004 The XFree86 Project, Inc.    All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicence, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so,subject to the following conditions:
-
-   1. Redistributions of source code must retain the above copyright
-   notice,this list of conditions, and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution, and in the same place
-   and form as other copyright, license and disclaimer information.
-
-   3. The end-user documentation included with the redistribution, if any,must
-   include the following acknowledgment: "This product includes
-   software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and
-   its contributors", in the same place and form as other third-party
-   acknowledgments. Alternately, this acknowledgment may appear in the software
-   itself, in the same form and location as other such third-party
-   acknowledgments.
-
-    4. Except as contained in this notice, the name of The XFree86 Project,Inc
-    shall not be used in advertising or otherwise to promote the sale, use
-    or other dealings in this Software without prior written authorization from
-    The XFree86 Project, Inc.
-
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-    WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-    EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-    DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-    DAMAGE.  
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to X Window System 6.8.2, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-          Licenses
-The X.Org Foundation March 2004
-
-1. Introduction
-
-The X.org Foundation X Window System distribution is a compilation of code and
-documentation from many sources. This document is intended primarily as a
-guide to the licenses used in the distribution: you must check each file
-and/or package for precise redistribution terms. None-the-less, this summary
-may be useful to many users. No software incorporating the XFree86 1.1 license
-has been incorporated.
-
-This document is based on the compilation from XFree86.
-
-2. XFree86 License
-
-XFree86 code without an explicit copyright is covered by the following
-copyright/license:
-
-Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the XFree86 Project shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from the XFree86 Project.
-
-3. Other Licenses
-
-Portions of code are covered by the following licenses/copyrights. See
-individual files for the copyright dates.
-
-3.1. X/MIT Copyrights
-
-3.1.1. X Consortium
-
-Copyright (C) <date> X Consortium
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
-CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from the X Consortium.
-
-X Window System is a trademark of X Consortium, Inc.
-
-3.1.2. The Open Group
-
-Copyright <date> The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation.
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from The Open Group.  3.2.
-Berkeley-based copyrights:
-
-o
-3.2.1. General
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.2. UCB/LBL
-
-Copyright (c) 1993 The Regents of the University of California. All rights
-reserved.
-
-This software was developed by the Computer Systems Engineering group at
-Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to
-Berkeley.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement: This product includes software
-developed by the University of California, Lawrence Berkeley Laboratory.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the University of California, Berkeley and its contributors.
-
-   4. Neither the name of the University nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.3. The
-NetBSD Foundation, Inc.
-
-Copyright (c) 2003 The NetBSD Foundation, Inc. All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation by Ben
-Collver <collver1@attbi.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the NetBSD Foundation, Inc. and its contributors.
-
-   4. Neither the name of The NetBSD Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS
-IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.4. Theodore
-Ts'o.
-
-Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   and the entire permission notice in its entirety, including the disclaimer
-   of warranties.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. he name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.5. Theo de Raadt and Damien Miller
-
-Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. Copyright (c)
-2001-2002 Damien Miller. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.6. Todd C. Miller
-
-Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  3.2.7. Thomas
-Winischhofer
-
-Copyright (C) 2001-2004 Thomas Winischhofer
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.3. NVIDIA Corp
-
-Copyright (c) 1996 NVIDIA, Corp. All rights reserved.
-
-NOTICE TO USER: The source code is copyrighted under U.S. and international
-laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design
-patents pending on the design and interface of the NV chips. Users and
-possessors of this source code are hereby granted a nonexclusive, royalty-free
-copyright and design patent license to use this code in individual and
-commercial software.
-
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
-
-Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and
-foreign countries.
-
-NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
-CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
-WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE
-FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.  3.4. GLX Public
-License
-
-GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License")
-
-Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby
-grants permission to Recipient (defined below), under Recipient's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below), and to permit persons to whom the Subject Software is
-furnished in accordance with this License to do the same, subject to all of
-the following terms and conditions, which Recipient accepts by engaging in any
-such use, copying, modifying, merging, publishing, distributing, sublicensing
-or selling:
-
-1. Definitions.
-
-    (a) "Original Software" means source code of computer software code which
-    is described in Exhibit A as Original Software.
-
-    (b) "Modifications" means any addition to or deletion from the substance
-    or structure of either the Original Software or any previous
-    Modifications. When Subject Software is released as a series of files, a
-    Modification means (i) any addition to or deletion from the contents of a
-    file containing Original Software or previous Modifications and (ii) any
-    new file that contains any part of the Original Code or previous
-    Modifications.
-
-    (c) "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    (d) "Recipient" means an individual or a legal entity exercising rights
-    under, and complying with all of the terms of, this License. For legal
-    entities, "Recipient" includes any entity which controls, is controlled
-    by, or is under common control with Recipient. For purposes of this
-    definition, "control" of an entity means (a) the power, direct or
-    indirect, to direct or manage such entity, or (b) ownership of fifty
-    percent (50%) or more of the outstanding shares or beneficial ownership of
-    such entity.
-
-2. Redistribution of Source Code Subject to These Terms. Redistributions of
-Subject Software in source code form must retain the notice set forth in
-Exhibit A, below, in every file. A copy of this License must be included in
-any documentation for such Subject Software where the recipients' rights
-relating to Subject Software are described. Recipient may distribute the
-source code version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the source code version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-3. Redistribution in Executable Form. The notice set forth in Exhibit A must
-be conspicuously included in any notice in an executable version of Subject
-Software, related documentation or collateral in which Recipient describes the
-user's rights relating to the Subject Software. Recipient may distribute the
-executable version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the executable version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-4. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software which is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-5. No Trademark Rights. This License does not grant any rights to use any
-trade name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from
-the Subject Software without prior written permission of SGI.
-
-6. No Other Rights. This License does not grant any rights with respect to the
-OpenGL API or to any software or hardware implementation thereof or to any
-other software whatsoever, nor shall any other rights or licenses not
-expressly granted hereunder arise by implication, estoppel or otherwise with
-respect to the Subject Software. Title to and ownership of the Original
-Software at all times remains with SGI. All rights in the Original Software
-not expressly granted under this License are reserved.
-
-7. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-8. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Exhibit A notice required under Sections 2 and 3,
-above, and in the text of any related documentation, license agreement or
-collateral in which Recipient describes end user's rights relating to the
-Subject Software. If Recipient obtains such knowledge after it makes Subject
-Software available to any other person or entity, Recipient shall take other
-steps (such as notifying appropriate mailing lists or newsgroups) reasonably
-calculated to inform those who received the Subject Software that new
-knowledge has been obtained.
-
-9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
-STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF
-THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY
-TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO
-THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT.
-
-11. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from
-and against any loss, liability, damages, costs or expenses (including the
-payment of reasonable attorneys fees) arising out of Recipient's use,
-modification, reproduction and distribution of the Subject Software or out of
-any representation or warranty made by Recipient.
-
-12. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-13. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed so as to achieve as nearly as
-possible the same economic effect as the original provision and the remainder
-of this License will remain in effect. This License shall be governed by and
-construed in accordance with the laws of the United States and the State of
-California as applied to agreements entered into and to be performed entirely
-within California between California residents. Any litigation relating to
-this License shall be subject to the exclusive jurisdiction of the Federal
-Courts of the Northern District of California (or, absent subject matter
-jurisdiction in such courts, the courts of the State of California), with
-venue lying exclusively in Santa Clara County, California, with the losing
-party responsible for costs, including without limitation, court costs and
-reasonable attorneys fees and expenses. The application of the United Nations
-Convention on Contracts for the International Sale of Goods is expressly
-excluded. Any law or regulation which provides that the language of a contract
-shall be construed against the drafter shall not apply to this License.
-
-Exhibit A
-
-The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13
-of the GLX Public License Version 1.0 (the "License"). You may not use this
-file except in compliance with those sections of the License. You may obtain a
-copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N.
-Shoreline Blvd., Mountain View, CA 94043 or at
-http://www.sgi.com/software/opensource/glx/license.html.
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON-
-INFRINGEMENT. See the License for the specific language governing rights and
-limitations under the License.
-
-The Original Software is GLX version 1.2 source code, released February, 1999.
-The developer of the Original Software is Silicon Graphics, Inc. Those
-portions of the Subject Software created by Silicon Graphics, Inc. are
-Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.  3.5. CID
-Font Code Public License
-
-CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License")
-
-Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI")
-hereby grants permission to Recipient (defined below), under SGI's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below) in both source code and executable form, and to permit persons
-to whom the Subject Software is furnished in accordance with this License to
-do the same, subject to all of the following terms and conditions, which
-Recipient accepts by engaging in any such use, copying, modifying, merging,
-publication, distributing, sublicensing or selling:
-
-1. Definitions.
-
-    a. "Original Software" means source code of computer software code that is
-    described in Exhibit A as Original Software.
-
-    b. "Modifications" means any addition to or deletion from the substance or
-    structure of either the Original Software or any previous Modifications.
-    When Subject Software is released as a series of files, a Modification
-    means (i) any addition to or deletion from the contents of a file
-    containing Original Software or previous Modifications and (ii) any new
-    file that contains any part of the Original Code or previous
-    Modifications.
-
-    c. "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    d. "Recipient" means an individual or a legal entity exercising rights
-    under the terms of this License. For legal entities, "Recipient" includes
-    any entity that controls, is controlled by, or is under common control
-    with Recipient. For purposes of this definition, "control" of an entity
-    means (i) the power, direct or indirect, to direct or manage such entity,
-    or (ii) ownership of fifty percent (50%) or more of the outstanding shares
-    or beneficial ownership of such entity.
-
-    e. "Required Notice" means the notice set forth in Exhibit A to this
-    License.
-
-    f. "Accompanying Technology" means any software or other technology that
-    is not a Modification and that is distributed or made publicly available
-    by Recipient with the Subject Software. Separate software files that do
-    not contain any Original Software or any previous Modification shall not
-    be deemed a Modification, even if such software files are aggregated as
-    part of a product, or in any medium of storage, with any file that does
-    contain Original Software or any previous Modification.
-
-2. License Terms. All distribution of the Subject Software must be made
-subject to the terms of this License. A copy of this License and the Required
-Notice must be included in any documentation for Subject Software where
-Recipient's rights relating to Subject Software and/or any Accompanying
-Technology are described. Distributions of Subject Software in source code
-form must also include the Required Notice in every file distributed. In
-addition, a ReadMe file entitled "Important Legal Notice" must be distributed
-with each distribution of one or more files that incorporate Subject Software.
-That file must be included with distributions made in both source code and
-executable form. A copy of the License and the Required Notice must be
-included in that file. Recipient may distribute Accompanying Technology under
-a license of Recipient's choice, which may contain terms different from this
-License, provided that (i) Recipient is in compliance with the terms of this
-License, (ii) such other license terms do not modify or supersede the terms of
-this License as applicable to the Subject Software, (iii) Recipient hereby
-indemnifies SGI for any liability incurred by SGI as a result of the
-distribution of Accompanying Technology or the use of other license terms.
-
-3. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software that is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-4. Trademark Rights. This License does not grant any rights to use any trade
-name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from or
-incorporating any Subject Software without prior written permission of SGI.
-
-5. No Other Rights. No rights or licenses not expressly granted hereunder
-shall arise by implication, estoppel or otherwise. Title to and ownership of
-the Original Software at all times remains with SGI. All rights in the
-Original Software not expressly granted under this License are reserved.
-
-6. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity, or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-7. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Required Notice, and in the text of any related
-documentation, license agreement or collateral in which Recipient describes
-end user's rights relating to the Subject Software. If Recipient obtains such
-knowledge after it makes Subject Software available to any other person or
-entity, Recipient shall take other steps (such as notifying appropriate
-mailing lists or newsgroups) reasonably calculated to provide such knowledge
-to those who received the Subject Software.
-
-8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND
-LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED.
-
-10. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold SGI and its successors and assigns
-harmless from and against any loss, liability, damages, costs or expenses
-(including the payment of reasonable attorneys fees) arising out of
-(Recipient's use, modification, reproduction and distribution of the Subject
-Software or out of any representation or warranty made by Recipient.
-
-11. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-12. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable by any judicial or administrative authority having proper
-jurisdiction with respect thereto, such provision shall be reformed so as to
-achieve as nearly as possible the same economic effect as the original
-provision and the remainder of this License will remain in effect. This
-License shall be governed by and construed in accordance with the laws of the
-United States and the State of California as applied to agreements entered
-into and to be performed entirely within California between California
-residents. Any litigation relating to this License shall be subject to the
-exclusive jurisdiction of the Federal Courts of the Northern District of
-California (or, absent subject matter jurisdiction in such courts, the courts
-of the State of California), with venue lying exclusively in Santa Clara
-County, California, with the losing party responsible for costs, including
-without limitation, court costs and reasonable attorneys fees and expenses.
-The application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded. Any law or regulation that
-provides that the language of a contract shall be construed against the
-drafter shall not apply to this License.
-
-Exhibit A
-
-Copyright (c) 1994-1999 Silicon Graphics, Inc.
-
-The contents of this file are subject to the CID Font Code Public License
-Version 1.0 (the "License"). You may not use this file except in compliance
-with the License. You may obtain a copy of the License at Silicon Graphics,
-Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
-or at http://www.sgi.com/software/opensource/cid/license.html
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF
-NON-INFRINGEMENT. See the License for the specific language governing rights
-and limitations under the License.
-
-The Original Software (as defined in the License) is CID font code that was
-developed by Silicon Graphics, Inc. Those portions of the Subject Software (as
-defined in the License) that were created by Silicon Graphics, Inc. are
-Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved.
-
-[NOTE: When using this text in connection with Subject Software delivered
-solely in object code form, Recipient may replace the words "this file" with
-"this software" in both the first and second sentences.] 3.6. Bitstream Vera
-Fonts Copyright
-
-The fonts have a generous copyright, allowing derivative works (as long as
-"Bitstream" or "Vera" are not in the names), and full redistribution (so long
-as they are not *sold* by themselves). They can be be bundled, redistributed
-and sold with any software.
-
-The fonts are distributed under the following copyright:
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.  3.7. Bigelow & Holmes
-Inc and URW++ GmbH Luxi font license
-
-Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font instruction
-code copyright (c) 2001 by URW++ GmbH. All Rights Reserved. Luxi is a
-registered trademark of Bigelow & Holmes Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of these Fonts and associated documentation files (the "Font Software"), to
-deal in the Font Software, including without limitation the rights to use,
-copy, merge, publish, distribute, sublicense, and/or sell copies of the Font
-Software, and to permit persons to whom the Font Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software.
-
-The Font Software may not be modified, altered, or added to, and in particular
-the designs of glyphs or characters in the Fonts may not be modified nor may
-additional glyphs or characters be added to the Fonts. This License becomes
-null and void when the Fonts or Font Software have been modified.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BIGELOW & HOLMES INC. OR URW++
-GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
-GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
-Except as contained in this notice, the names of Bigelow & Holmes Inc. and
-URW++ GmbH. shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Font Software without prior written
-authorization from Bigelow & Holmes Inc. and URW++ GmbH.
-
-For further information, contact:
-
-info@urwpp.de or design@bigelowandholmes.com
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to zlib v1.2.5, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-  version 1.2.5, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to the following which may be 
-included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
-
-  Apache Commons Math 2.2
-  Apache Derby 10.10.1.2        [included with JDK 8]
-  Apache Jakarta BCEL 5.2 
-  Apache Santuario XML Security for Java 1.5.4
-  Apache Xalan-Java 2.7.1 
-  Apache Xerces Java 2.10.0 
-  Apache XML Resolver 1.1 
-  Dynalink 0.5
-
-
---- begin of LICENSE ---
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
index e23c003..0908e20 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
@@ -23,6 +23,8 @@
 
 package com.sun.org.apache.xalan.internal.utils;
 
+import java.util.function.Supplier;
+
 /**
  * This class is duplicated for each JAXP subpackage so keep it in sync.
  * It is package private and therefore is not exposed as part of the JAXP
@@ -46,9 +48,9 @@
 
 
     /** Prints a message to standard error if debugging is enabled. */
-    private static void debugPrintln(String msg) {
+    private static void debugPrintln(Supplier<String> msgGen) {
         if (DEBUG) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     } // debugPrintln(String)
 
@@ -125,8 +127,8 @@
         try{
             Class providerClass = findProviderClass(className, cl, doFallback);
             Object instance = providerClass.newInstance();
-            if (DEBUG) debugPrintln("created new instance of " + providerClass +
-                   " using ClassLoader: " + cl);
+            debugPrintln(()->"created new instance of " + providerClass +
+                             " using ClassLoader: " + cl);
             return instance;
         } catch (ClassNotFoundException x) {
             throw new ConfigurationError(
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java
index fc2b202..37d4cf9 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java
@@ -128,8 +128,7 @@
                 parser.reportError(Constants.ERROR, err);
             }
             setName(parser.getQNameIgnoreDefaultNs(name));
-        }
-        else {
+        } else {
             reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
         }
 
@@ -151,8 +150,7 @@
             if (tselect instanceof ReferenceType == false) {
                 _select = new CastExpr(_select, Type.Reference);
             }
-        }
-        else {
+        } else {
             typeCheckContents(stable);
         }
         return Type.Void;
@@ -163,23 +161,24 @@
      * a 'select' attribute, or in the with-param element's body
      */
     public void translateValue(ClassGenerator classGen,
-                               MethodGenerator methodGen) {
+                               MethodGenerator methodGen)
+    {
         // Compile expression is 'select' attribute if present
         if (_select != null) {
             _select.translate(classGen, methodGen);
             _select.startIterator(classGen, methodGen);
-        }
         // If not, compile result tree from parameter body if present.
         // Store result tree into local variable for releasing it later
-        else if (hasContents()) {
+        } else if (hasContents()) {
             final InstructionList il = methodGen.getInstructionList();
             compileResultTree(classGen, methodGen);
-            _domAdapter = methodGen.addLocalVariable2("@" + _escapedName, Type.ResultTree.toJCType(), il.getEnd());
+            _domAdapter = methodGen.addLocalVariable2("@" + _escapedName,
+                                                      Type.ResultTree.toJCType(),
+                                                      il.getEnd());
             il.append(DUP);
             il.append(new ASTORE(_domAdapter.getIndex()));
-        }
         // If neither are present then store empty string in parameter slot
-        else {
+        } else {
             final ConstantPoolGen cpg = classGen.getConstantPool();
             final InstructionList il = methodGen.getInstructionList();
             il.append(new PUSH(cpg, Constants.EMPTYSTRING));
@@ -223,22 +222,31 @@
     /**
      * Release the compiled result tree.
      */
-    public void releaseResultTree(ClassGenerator classGen, MethodGenerator methodGen) {
+    public void releaseResultTree(ClassGenerator classGen,
+                                  MethodGenerator methodGen)
+    {
         if (_domAdapter != null) {
             final ConstantPoolGen cpg = classGen.getConstantPool();
             final InstructionList il = methodGen.getInstructionList();
-            if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) {
-                final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V");
+            if (classGen.getStylesheet().callsNodeset() &&
+                classGen.getDOMClass().equals(MULTI_DOM_CLASS))
+            {
+                final int removeDA =
+                    cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter",
+                                     "(" + DOM_ADAPTER_SIG + ")V");
                 il.append(methodGen.loadDOM());
                 il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS)));
                 il.append(new ALOAD(_domAdapter.getIndex()));
                 il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS)));
                 il.append(new INVOKEVIRTUAL(removeDA));
             }
-            final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V");
+            final int release =
+                cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V");
             il.append(new ALOAD(_domAdapter.getIndex()));
             il.append(new INVOKEINTERFACE(release, 1));
+            _domAdapter.setEnd(il.getEnd());
+            methodGen.removeLocalVariable(_domAdapter);
             _domAdapter = null;
-         }
-     }
+        }
+    }
 }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
index f47a3eb..ebd4456 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.runtime;
 
@@ -685,7 +682,8 @@
                     handler.setVersion(_version);
                 }
                 handler.setIndent(_indent);
-                handler.setIndentAmount(_indentamount);
+                if (_indentamount >= 0)
+                    handler.setIndentAmount(_indentamount);
                 if (_doctypeSystem != null) {
                     handler.setDoctype(_doctypeSystem, _doctypePublic);
                 }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
index 746418b..4c0512e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
@@ -32,7 +32,6 @@
 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
 import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.io.NotSerializableException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -42,6 +41,7 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
+import java.lang.module.ModuleReader;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.security.AccessController;
@@ -403,10 +403,12 @@
     private Module createModule(ModuleDescriptor descriptor, ClassLoader loader) {
         String mn = descriptor.name();
 
-        ModuleReference mref = new ModuleReference(descriptor, null, () -> {
-            IOException ioe = new IOException("<dynamic module>");
-            throw new UncheckedIOException(ioe);
-        });
+        ModuleReference mref = new ModuleReference(descriptor, null) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
 
         ModuleFinder finder = new ModuleFinder() {
             @Override
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
index 23da98e..9109baa 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: TransformerImpl.java,v 1.10 2007/06/13 01:57:09 joehw Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.trax;
 
@@ -160,7 +157,7 @@
     /**
      * Number of indent spaces to add when indentation is on.
      */
-    private int _indentNumber;
+    private int _indentNumber = -1;
 
     /**
      * A reference to the transformer factory that this templates
@@ -1462,7 +1459,7 @@
         _uriResolver = null;
         _dom = null;
         _parameters = null;
-        _indentNumber = 0;
+        _indentNumber = -1;
         setOutputProperties (null);
         _tohFactory = null;
         _ostream = null;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
index 04b2280..61008e8 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
@@ -218,8 +218,8 @@
     };
 
 
-    private static final char [] cdata = {'[','C','D','A','T','A','['};
-    static final char [] xmlDecl = {'<','?','x','m','l'};
+    private static final char [] CDATA = {'[','C','D','A','T','A','['};
+    static final char [] XMLDECL = {'<','?','x','m','l'};
     // private static final char [] endTag = {'<','/'};
     // debugging
 
@@ -232,13 +232,9 @@
     /** Debug content driver scanning. */
     protected static final boolean DEBUG_START_END_ELEMENT = false;
 
-
-    /** Debug driver next */
-    protected static final boolean DEBUG_NEXT = false ;
-
     /** Debug driver next */
     protected static final boolean DEBUG = false;
-    protected static final boolean DEBUG_COALESCE = false;
+
     //
     // Data
     //
@@ -371,16 +367,16 @@
     protected XMLString fTempString2 = new XMLString();
 
     /** Array of 3 strings. */
-    private String[] fStrings = new String[3];
+    private final String[] fStrings = new String[3];
 
-    /** Making the buffer accesible to derived class -- String buffer. */
+    /** Making the buffer accessible to derived class -- String buffer. */
     protected XMLStringBuffer fStringBuffer = new XMLStringBuffer();
 
-    /** Making the buffer accesible to derived class -- String buffer. */
+    /** Making the buffer accessible to derived class -- String buffer. */
     protected XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
 
     /** stores character data. */
-    /** Making the buffer accesible to derived class -- stores PI data */
+    /** Making the buffer accessible to derived class -- stores PI data */
     protected XMLStringBuffer fContentBuffer = new XMLStringBuffer();
 
     /** Single character array. */
@@ -633,22 +629,23 @@
 
         // other settings
         // fDocumentSystemId = null;
-        fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
+        fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE));
         fNotifyBuiltInRefs = false ;
 
         //fElementStack2.clear();
         //fReplaceEntityReferences = true;
         //fSupportExternalEntities = true;
         Boolean bo = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES);
-        fReplaceEntityReferences = bo.booleanValue();
+        fReplaceEntityReferences = bo;
         bo = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES);
-        fSupportExternalEntities = bo.booleanValue();
-        Boolean cdata = (Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
+        fSupportExternalEntities = bo;
+        Boolean cdata = (Boolean)propertyManager.getProperty(
+                Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
         if(cdata != null)
-            fReportCdataEvent = cdata.booleanValue() ;
+            fReportCdataEvent = cdata ;
         Boolean coalesce = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_COALESCING) ;
         if(coalesce != null)
-            fIsCoalesce = coalesce.booleanValue();
+            fIsCoalesce = coalesce;
         fReportCdataEvent = fIsCoalesce ? false : (fReportCdataEvent && true) ;
         //if fIsCoalesce is set to true, set the value of fReplaceEntityReferences to true,
         //if fIsCoalesce is set to false, take the value of fReplaceEntityReferences as set by application
@@ -703,7 +700,7 @@
      * are recognized by this component.
      */
     public String[] getRecognizedFeatures() {
-        return (String[])(RECOGNIZED_FEATURES.clone());
+        return RECOGNIZED_FEATURES.clone();
     } // getRecognizedFeatures():String[]
 
     /**
@@ -742,7 +739,7 @@
      * are recognized by this component.
      */
     public String[] getRecognizedProperties() {
-        return (String[])(RECOGNIZED_PROPERTIES.clone());
+        return RECOGNIZED_PROPERTIES.clone();
     } // getRecognizedProperties():String[]
 
     /**
@@ -990,7 +987,8 @@
         // set standalone
         fStandaloneSet = standalone != null;
         fStandalone = fStandaloneSet && standalone.equals("yes");
-        ///xxx see where its used.. this is not used anywhere. it may be useful for entity to store this information
+        ///xxx see where its used.. this is not used anywhere.
+        //it may be useful for entity to store this information
         //but this information is only related with Document Entity.
         fEntityManager.setStandalone(fStandalone);
 
@@ -1199,7 +1197,8 @@
             if(rawname != null && skipFromTheBuffer(rawname)){
                 fLastPointerLocation++ ;
                 if(DEBUG_SKIP_ALGORITHM){
-                    System.out.println("Element " + fElementRawname + " was SKIPPED at pointer location = " + fLastPointerLocation);
+                    System.out.println("Element " + fElementRawname +
+                            " was SKIPPED at pointer location = " + fLastPointerLocation);
                 }
                 return true ;
             } else{
@@ -1233,7 +1232,8 @@
             if(fElementArray[pointer] != null && skipFromTheBuffer(fElementArray[pointer])){
                 if(DEBUG_SKIP_ALGORITHM){
                     System.out.println();
-                    System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " + fElementStack.fDepth + " column = " + column );
+                    System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " +
+                            fElementStack.fDepth + " column = " + column );
                     System.out.println();
                 }
                 fLastPointerLocation = pointer ;
@@ -1317,7 +1317,8 @@
             if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
             if(DEBUG_SKIP_ALGORITHM){
                 if(fAdd){
-                    System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
+                    System.out.println("Elements are being ADDED -- elemet added is = " +
+                            fElementQName.rawname + " at count = " + fElementStack.fCount);
                 }
             }
 
@@ -1395,7 +1396,8 @@
         }
 
 
-        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() + "<<< scanStartElement(): "+fEmptyElement);
+        if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +
+                "<<< scanStartElement(): "+fEmptyElement);
         return fEmptyElement;
 
     } // scanStartElement():boolean
@@ -1434,84 +1436,9 @@
     }
 
     public boolean hasAttributes(){
-        return fAttributes.getLength() > 0 ? true : false ;
+        return fAttributes.getLength() > 0;
     }
 
-
-    /**
-     * Scans an attribute.
-     * <p>
-     * <pre>
-     * [41] Attribute ::= Name Eq AttValue
-     * </pre>
-     * <p>
-     * <strong>Note:</strong> This method assumes that the next
-     * character on the stream is the first character of the attribute
-     * name.
-     * <p>
-     * <strong>Note:</strong> This method uses the fAttributeQName and
-     * fQName variables. The contents of these variables will be
-     * destroyed.
-     *
-     * @param attributes The attributes list for the scanned attribute.
-     */
-
-    /**
-     * protected void scanAttribute(AttributeIteratorImpl attributes)
-     * throws IOException, XNIException {
-     * if (DEBUG_START_END_ELEMENT) System.out.println(">>> scanAttribute()");
-     *
-     *
-     * // name
-     * if (fNamespaces) {
-     * fEntityScanner.scanQName(fAttributeQName);
-     * }
-     * else {
-     * String name = fEntityScanner.scanName();
-     * fAttributeQName.setValues(null, name, name, null);
-     * }
-     *
-     * // equals
-     * fEntityScanner.skipSpaces();
-     * if (!fEntityScanner.skipChar('=')) {
-     * reportFatalError("EqRequiredInAttribute",
-     * new Object[]{fAttributeQName.rawname});
-     * }
-     * fEntityScanner.skipSpaces();
-     *
-     *
-     * // content
-     * int oldLen = attributes.getLength();
-     */
-    /**xxx there is one check of duplicate attribute that has been removed.
-     * attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
-     *
-     * // WFC: Unique Att Spec
-     * if (oldLen == attributes.getLength()) {
-     * reportFatalError("AttributeNotUnique",
-     * new Object[]{fCurrentElement.rawname,
-     * fAttributeQName.rawname});
-     * }
-     */
-
-    /*
-        //REVISIT: one more case needs to be included: external PE and standalone is no
-        boolean isVC =  fHasExternalDTD && !fStandalone;
-        scanAttributeValue(fTempString, fTempString2,
-                           fAttributeQName.rawname, attributes,
-                           oldLen, isVC);
-
-        //attributes.setValue(oldLen, fTempString.toString());
-        //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
-        //attributes.setSpecified(oldLen, true);
-
-        AttributeImpl attribute = new AttributeImpl(fAttributeQName.prefix,fAttributeQName.localpart,fAttributeQName.uri,fTempString.toString(),fTempString2.toString(),XMLSymbols.fCDATASymbol,true);
-        fAttributes.addAttribute(attribute);
-        if (DEBUG_START_END_ELEMENT) System.out.println("<<< scanAttribute()");
-    } // scanAttribute(XMLAttributes)
-
-     */
-
     /** return the attribute iterator implementation */
     public XMLAttributesIteratorImpl getAttributeIterator(){
         if(dtdGrammarUtil != null && fAddDefaultAttr){
@@ -2624,7 +2551,7 @@
                                         null);
                             }
                             setScannerState(SCANNER_STATE_COMMENT);
-                        } else if (fEntityScanner.skipString(cdata)) {
+                        } else if (fEntityScanner.skipString(CDATA)) {
                             fCDataStart = true;
                             setScannerState(SCANNER_STATE_CDATA );
                         } else if (!scanForDoctypeHook()) {
@@ -2710,62 +2637,56 @@
         public int next() throws IOException, XNIException {
             while (true) {
             try {
-                if(DEBUG_NEXT){
-                    System.out.println("NOW IN FragmentContentDriver");
-                    System.out.println("Entering the FragmentContentDriver with = " + getScannerStateName(fScannerState));
-                }
 
                 //decide the actual sub state of the scanner.For more information refer to the javadoc of
                 //decideSubState.
 
-                switch (fScannerState) {
-                    case SCANNER_STATE_CONTENT: {
-                        final int ch = fEntityScanner.peekChar();
-                        if (ch == '<') {
-                            fEntityScanner.scanChar(null);
-                            setScannerState(SCANNER_STATE_START_OF_MARKUP);
-                        } else if (ch == '&') {
-                            fEntityScanner.scanChar(NameType.REFERENCE);
-                            setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
-                            break;
-                        } else {
-                            //element content is there..
-                            setScannerState(SCANNER_STATE_CHARACTER_DATA);
-                            break;
-                        }
+                if (fScannerState == SCANNER_STATE_CONTENT) {
+                    final int ch = fEntityScanner.peekChar();
+                    if (ch == '<') {
+                        fEntityScanner.scanChar(null);
+                        setScannerState(SCANNER_STATE_START_OF_MARKUP);
+                    } else if (ch == '&') {
+                        fEntityScanner.scanChar(NameType.REFERENCE);
+                        setScannerState(SCANNER_STATE_REFERENCE) ;
+                    } else {
+                        //element content is there..
+                        setScannerState(SCANNER_STATE_CHARACTER_DATA);
                     }
+                }
 
-                    case SCANNER_STATE_START_OF_MARKUP: {
-                        startOfMarkup();
-                        break;
-                    }//case: SCANNER_STATE_START_OF_MARKUP
+                if (fScannerState == SCANNER_STATE_START_OF_MARKUP) {
+                    startOfMarkup();
+                }
 
-                }//end of switch
                 //decideSubState() ;
 
                 //do some special handling if isCoalesce is set to true.
-                if(fIsCoalesce){
+                if (fIsCoalesce) {
                     fUsebuffer = true ;
                     //if the last section was character data
-                    if(fLastSectionWasCharacterData){
+                    if (fLastSectionWasCharacterData) {
 
-                        //if we dont encounter any CDATA or ENTITY REFERENCE and current state is also not SCANNER_STATE_CHARACTER_DATA
+                        //if we dont encounter any CDATA or ENTITY REFERENCE and
+                        //current state is also not SCANNER_STATE_CHARACTER_DATA
                         //return the last scanned charactrer data.
-                        if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
-                        && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
+                        if ((fScannerState != SCANNER_STATE_CDATA)
+                                && (fScannerState != SCANNER_STATE_REFERENCE)
+                                && (fScannerState != SCANNER_STATE_CHARACTER_DATA)) {
                             fLastSectionWasCharacterData = false;
                             return XMLEvent.CHARACTERS;
                         }
                     }//if last section was CDATA or ENTITY REFERENCE
                     //xxx: there might be another entity reference or CDATA after this
                     //<foo>blah blah &amp;&lt;<![CDATA[[aa]]>blah blah</foo>
-                    else if((fLastSectionWasCData || fLastSectionWasEntityReference)){
+                    else if ((fLastSectionWasCData || fLastSectionWasEntityReference)) {
                         //and current state is not SCANNER_STATE_CHARACTER_DATA
                         //or SCANNER_STATE_CDATA or SCANNER_STATE_REFERENCE
                         //this means there is nothing more to be coalesced.
                         //return the CHARACTERS event.
-                        if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
-                        && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
+                        if ((fScannerState != SCANNER_STATE_CDATA)
+                                && (fScannerState != SCANNER_STATE_REFERENCE)
+                                && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
 
                             fLastSectionWasCData = false;
                             fLastSectionWasEntityReference = false;
@@ -2774,11 +2695,6 @@
                     }
                 }
 
-
-                if(DEBUG_NEXT){
-                    System.out.println("Actual scanner state set by decideSubState is = " + getScannerStateName(fScannerState));
-                }
-
                 switch(fScannerState){
 
                     case XMLEvent.START_DOCUMENT :
@@ -2786,7 +2702,6 @@
 
                     case SCANNER_STATE_START_ELEMENT_TAG :{
 
-                        //xxx this function returns true when element is empty.. can be linked to end element event.
                         //returns true if the element is empty
                         fEmptyElement = scanStartElement() ;
                         //if the element is empty the next event is "end element"
@@ -2800,15 +2715,16 @@
                     }
 
                     case SCANNER_STATE_CHARACTER_DATA: {
-                        if(DEBUG_COALESCE){
-                            System.out.println("fLastSectionWasCData = " + fLastSectionWasCData);
-                            System.out.println("fIsCoalesce = " + fIsCoalesce);
-                        }
-                        //if last section was either entity reference or cdata or character data we should be using buffer
-                        fUsebuffer = fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData ;
 
-                        //When coalesce is set to true and last state was REFERENCE or CDATA or CHARACTER_DATA, buffer should not be cleared.
-                        if( fIsCoalesce && (fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData) ){
+                        //if last section was either entity reference or cdata or
+                        //character data we should be using buffer
+                        fUsebuffer = fLastSectionWasEntityReference || fLastSectionWasCData
+                                || fLastSectionWasCharacterData ;
+
+                        //When coalesce is set to true and last state was REFERENCE or
+                        //CDATA or CHARACTER_DATA, buffer should not be cleared.
+                        if( fIsCoalesce && (fLastSectionWasEntityReference ||
+                                fLastSectionWasCData || fLastSectionWasCharacterData) ){
                             fLastSectionWasEntityReference = false;
                             fLastSectionWasCData = false;
                             fLastSectionWasCharacterData = true ;
@@ -2822,9 +2738,7 @@
                         //scanContent sets the correct co-ordinates as per the content read
                         fTempString.length = 0;
                         int c = fEntityScanner.scanContent(fTempString);
-                        if(DEBUG){
-                            System.out.println("fTempString = " + fTempString);
-                        }
+
                         if(fEntityScanner.skipChar('<', null)){
                             //check if we have reached end of element
                             if(fEntityScanner.skipChar('/', NameType.ELEMENTEND)){
@@ -2841,21 +2755,17 @@
                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
                                 //there can be cdata ahead if coalesce is true we should call again
                                 if(fIsCoalesce){
-                                    fUsebuffer = true;
                                     fLastSectionWasCharacterData = true;
-                                    fContentBuffer.append(fTempString);
-                                    fTempString.length = 0;
+                                    bufferContent();
                                     continue;
                                 }
                             }
-                            //in case last section was either entity reference or cdata or character data -- we should be using buffer
+                            //in case last section was either entity reference or
+                            //cdata or character data -- we should be using buffer
                             if(fUsebuffer){
-                                fContentBuffer.append(fTempString);
-                                fTempString.length = 0;
+                                bufferContent();
                             }
-                            if(DEBUG){
-                                System.out.println("NOT USING THE BUFFER, STRING = " + fTempString.toString());
-                            }
+
                             if(dtdGrammarUtil!= null && dtdGrammarUtil.isIgnorableWhiteSpace(fContentBuffer)){
                                 if(DEBUG)System.out.println("Return SPACE EVENT");
                                 return XMLEvent.SPACE;
@@ -2863,13 +2773,7 @@
                                 return XMLEvent.CHARACTERS;
 
                         } else{
-                            fUsebuffer = true ;
-                            if(DEBUG){
-                                System.out.println("fContentBuffer = " + fContentBuffer);
-                                System.out.println("fTempString = " + fTempString);
-                            }
-                            fContentBuffer.append(fTempString);
-                            fTempString.length = 0;
+                            bufferContent();
                         }
                         if (c == '\r') {
                             if(DEBUG){
@@ -2969,7 +2873,8 @@
                             setScannerState(SCANNER_STATE_CONTENT);
                             //check the case when there is comment after single element document
                             //<foo/> and some comment after this
-                            return (fMarkupDepth == 0 && elementDepthIsZeroHook() ) ? XMLEvent.END_ELEMENT : XMLEvent.END_ELEMENT ;
+                            return (fMarkupDepth == 0 && elementDepthIsZeroHook() ) ?
+                                    XMLEvent.END_ELEMENT : XMLEvent.END_ELEMENT ;
 
                         } else if(scanEndElement() == 0) {
                             //It is last element of the document
@@ -3093,7 +2998,8 @@
 
                             if(fScannerState == SCANNER_STATE_REFERENCE){
                                 setScannerState(SCANNER_STATE_CONTENT);
-                                if (fReplaceEntityReferences && fEntityStore.isDeclaredEntity(fCurrentEntityName)) {
+                                if (fReplaceEntityReferences &&
+                                        fEntityStore.isDeclaredEntity(fCurrentEntityName)) {
                                     // Skip the entity reference, we don't care
                                     continue;
                                 }
@@ -3126,7 +3032,8 @@
                                         fStringBuffer.append((char)fEntityScanner.scanChar(null));
                                     }
                                 }
-                                String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
+                                String target = fSymbolTable.addSymbol(fStringBuffer.ch,
+                                        fStringBuffer.offset, fStringBuffer.length);
                                 fContentBuffer.clear();
                                 scanPIData(target, fContentBuffer);
                             }
@@ -3269,7 +3176,8 @@
      */
 
     protected XMLString getString(){
-        if(fAttributeCacheUsedCount < initialCacheCount || fAttributeCacheUsedCount < attributeValueCache.size()){
+        if(fAttributeCacheUsedCount < initialCacheCount ||
+                fAttributeCacheUsedCount < attributeValueCache.size()){
             return attributeValueCache.get(fAttributeCacheUsedCount++);
         } else{
             XMLString str = new XMLString();
@@ -3299,13 +3207,20 @@
             fAttributes.refresh();
         }
         if(fScannerState == SCANNER_STATE_CHARACTER_DATA){
-            //since fTempString directly matches to the underlying main buffer
-            //store the data into buffer
-            fContentBuffer.append(fTempString);
-            //clear the XMLString so that data can't be added again.
-            fTempString.length = 0;
-            fUsebuffer = true;
+            bufferContent();
         }
     }
 
+    /**
+     * Since 'TempString' shares the buffer (a char array) with the CurrentEntity,
+     * when the cursor position reaches the end, that is, before the buffer is
+     * being loaded with new data, the content in the TempString needs to be
+     * copied into the ContentBuffer.
+     */
+    private void bufferContent() {
+        fContentBuffer.append(fTempString);
+        //clear the XMLString so that data can't be added again.
+        fTempString.length = 0;
+        fUsebuffer = true;
+    }
 } // class XMLDocumentFragmentScannerImpl
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java
index 1c7cc3d..1226fe3 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java
@@ -733,9 +733,6 @@
 
 
         public int next() throws IOException, XNIException {
-            if(DEBUG_NEXT){
-                System.out.println("NOW IN XMLDeclDriver");
-            }
 
             // next driver is prolog regardless of whether there
             // is an XMLDecl in this document
@@ -745,7 +742,7 @@
             //System.out.println("fEntityScanner = " + fEntityScanner);
             // scan XMLDecl
             try {
-                if (fEntityScanner.skipString(xmlDecl)) {
+                if (fEntityScanner.skipString(XMLDECL)) {
                     if (fEntityScanner.peekChar() == ' ') {
                         fMarkupDepth++;
                         scanXMLDeclOrTextDecl(false);
@@ -797,11 +794,7 @@
          */
 
         public int next() throws IOException, XNIException {
-            //System.out.println("here in next");
 
-            if(DEBUG_NEXT){
-                System.out.println("NOW IN PrologDriver");
-            }
             try {
                 do {
                     switch (fScannerState) {
@@ -1014,17 +1007,9 @@
         //
 
         public int next() throws IOException, XNIException{
-            // throw new XNIException("DTD Parsing is currently not supported");
-            if(DEBUG_NEXT){
-                System.out.println("Now in DTD Driver");
-            }
 
             dispatch(true);
 
-            if(DEBUG_NEXT){
-                System.out.println("After calling dispatch(true) -- At this point whole DTD is read.");
-            }
-
             //xxx: remove this hack and align this with reusing DTD components
             //currently this routine will only be executed from Stax
             if(fPropertyManager != null){
@@ -1380,10 +1365,9 @@
                             break;
                         }
                     }
-                }while(fScannerState == SCANNER_STATE_START_OF_MARKUP || fScannerState == SCANNER_STATE_TRAILING_MISC);
-                if(DEBUG_NEXT){
-                    System.out.println("State set by deciding while loop [TrailingMiscellaneous] is = " + getScannerStateName(fScannerState));
-                }
+                } while(fScannerState == SCANNER_STATE_START_OF_MARKUP ||
+                        fScannerState == SCANNER_STATE_TRAILING_MISC);
+
                 switch (fScannerState){
                     case SCANNER_STATE_PI: {
                         fContentBuffer.clear();
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index eb16a26..2cf99ab 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -967,7 +967,7 @@
      */
 
     public void setEntityHandler(com.sun.org.apache.xerces.internal.impl.XMLEntityHandler entityHandler) {
-        fEntityHandler = (XMLEntityHandler) entityHandler;
+        fEntityHandler = entityHandler;
     } // setEntityHandler(XMLEntityHandler)
 
     //this function returns StaxXMLInputSource
@@ -1266,11 +1266,11 @@
         for (int i = size; i >= 0; i--) {
             Entity activeEntity = i == size
                     ? fCurrentEntity
-                    : (Entity)fEntityStack.elementAt(i);
+                    : fEntityStack.elementAt(i);
             if (activeEntity.name == entityName) {
                 String path = entityName;
                 for (int j = i + 1; j < size; j++) {
-                    activeEntity = (Entity)fEntityStack.elementAt(j);
+                    activeEntity = fEntityStack.elementAt(j);
                     path = path + " -> " + activeEntity.name;
                 }
                 path = path + " -> " + fCurrentEntity.name;
@@ -1704,7 +1704,7 @@
      * are recognized by this component.
      */
     public String[] getRecognizedFeatures() {
-        return (String[])(RECOGNIZED_FEATURES.clone());
+        return RECOGNIZED_FEATURES.clone();
     } // getRecognizedFeatures():String[]
 
     /**
@@ -1824,7 +1824,7 @@
      * are recognized by this component.
      */
     public String[] getRecognizedProperties() {
-        return (String[])(RECOGNIZED_PROPERTIES.clone());
+        return RECOGNIZED_PROPERTIES.clone();
     } // getRecognizedProperties():String[]
     /**
      * Returns the default state for a feature, or null if this
@@ -2952,7 +2952,7 @@
         public CharacterBuffer getBuffer(boolean external) {
             if (external) {
                 if (fExternalTop > -1) {
-                    return (CharacterBuffer)fExternalBufferPool[fExternalTop--];
+                    return fExternalBufferPool[fExternalTop--];
                 }
                 else {
                     return new CharacterBuffer(true, fExternalBufferSize);
@@ -2960,7 +2960,7 @@
             }
             else {
                 if (fInternalTop > -1) {
-                    return (CharacterBuffer)fInternalBufferPool[fInternalTop--];
+                    return fInternalBufferPool[fInternalTop--];
                 }
                 else {
                     return new CharacterBuffer(false, fInternalBufferSize);
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java
index 9b961b3..d937f53 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java
@@ -25,42 +25,44 @@
 
 package com.sun.org.apache.xerces.internal.impl;
 
+import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper;
+import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
+import com.sun.org.apache.xerces.internal.util.SymbolTable;
+import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
+import com.sun.org.apache.xerces.internal.util.XMLChar;
+import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
+import com.sun.org.apache.xerces.internal.xni.XNIException;
+import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
 import com.sun.xml.internal.stream.Entity;
 import com.sun.xml.internal.stream.StaxErrorReporter;
 import com.sun.xml.internal.stream.XMLEntityStorage;
+import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
+import com.sun.xml.internal.stream.dtd.nonvalidating.XMLNotationDecl;
 import com.sun.xml.internal.stream.events.EntityDeclarationImpl;
 import com.sun.xml.internal.stream.events.NotationDeclarationImpl;
-import javax.xml.namespace.NamespaceContext;
-import com.sun.org.apache.xerces.internal.xni.XNIException;
-import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
-import javax.xml.XMLConstants;
-import javax.xml.namespace.QName;
-import javax.xml.stream.Location;
-import javax.xml.stream.events.XMLEvent;
-import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper;
-import com.sun.org.apache.xerces.internal.util.SymbolTable;
-import com.sun.xml.internal.stream.dtd.nonvalidating.XMLNotationDecl;
-import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
-import com.sun.org.apache.xerces.internal.util.XMLChar;
-import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
-import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
-import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
+import javax.xml.stream.events.EntityDeclaration;
+import javax.xml.stream.events.NotationDeclaration;
+import javax.xml.stream.events.XMLEvent;
 
-/** This class implements javax.xml.stream.XMLStreamReader. It makes use of XML*Scanner classes to
- * derive most of its functionality. If desired, Application can reuse this instance by calling
- * reset() and setInputSource().
+/**
+ * This class implements javax.xml.stream.XMLStreamReader. It makes use of
+ * XML*Scanner classes to derive most of its functionality. If desired,
+ * Application can reuse this instance by calling reset() and setInputSource().
  *
  * @author Neeraj Bajaj Sun Microsystems,Inc.
  * @author K.Venugopal Sun Microsystems,Inc.
@@ -68,49 +70,68 @@
  */
 public class XMLStreamReaderImpl implements javax.xml.stream.XMLStreamReader {
 
-    /** Property identifier: entity manager. */
-    protected static final String ENTITY_MANAGER =
-    Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
+    /**
+     * Property identifier: entity manager.
+     */
+    protected static final String ENTITY_MANAGER
+            = Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 
-    /** Property identifier: Error Reporter. */
-    protected static final String ERROR_REPORTER =
-    Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
+    /**
+     * Property identifier: Error Reporter.
+     */
+    protected static final String ERROR_REPORTER
+            = Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 
-    /** Property identifier: Symbol table. */
-    protected static final String SYMBOL_TABLE =
-    Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
+    /**
+     * Property identifier: Symbol table.
+     */
+    protected static final String SYMBOL_TABLE
+            = Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 
-    protected static final String READER_IN_DEFINED_STATE =
-    Constants.READER_IN_DEFINED_STATE;
+    protected static final String READER_IN_DEFINED_STATE
+            = Constants.READER_IN_DEFINED_STATE;
 
     private SymbolTable fSymbolTable = new SymbolTable();
 
-    /** Document scanner. */
+    /**
+     * Document scanner.
+     */
     protected XMLDocumentScannerImpl fScanner = new XMLNSDocumentScannerImpl();
 
-    //make Global NamespaceContextWrapper object,  fScanner.getNamespaceContext() is dynamic object and ita value changes
-    //as per the state of the parser.
-    protected NamespaceContextWrapper fNamespaceContextWrapper = new NamespaceContextWrapper((NamespaceSupport)fScanner.getNamespaceContext()) ;
+    //make Global NamespaceContextWrapper object,  fScanner.getNamespaceContext()
+    //is dynamic object and ita value changes as per the state of the parser.
+    protected NamespaceContextWrapper fNamespaceContextWrapper =
+            new NamespaceContextWrapper((NamespaceSupport) fScanner.getNamespaceContext());
     protected XMLEntityManager fEntityManager = new XMLEntityManager();
     protected StaxErrorReporter fErrorReporter = new StaxErrorReporter();
 
-
-    /** Entity scanner, this alwasy works on last entity that was opened. */
+    /**
+     * Entity scanner, this alwasy works on last entity that was opened.
+     */
     protected XMLEntityScanner fEntityScanner = null;
 
-    /** Input Source */
+    /**
+     * Input Source
+     */
     protected XMLInputSource fInputSource = null;
-    /** Store properties*/
-    protected PropertyManager fPropertyManager = null ;
+    /**
+     * Store properties
+     */
+    protected PropertyManager fPropertyManager = null;
 
-    /** current event type */
-    private int fEventType ;
-    /** debug flag*/
-    static final boolean DEBUG = false ;
-    /** more to scan */
+    /**
+     * current event type
+     */
+    private int fEventType;
+    /**
+     * debug flag
+     */
+    static final boolean DEBUG = false;
+    /**
+     * more to scan
+     */
     private boolean fReuse = true;
-    private boolean fReaderInDefinedState = true ;
-    private boolean fBindNamespaces = true;
+    private boolean fReaderInDefinedState = true;
     private String fDTDDecl = null;
     private String versionStr = null;
 
@@ -119,24 +140,25 @@
      * @param props
      * @throws XMLStreamException
      */
-    public XMLStreamReaderImpl(InputStream inputStream, PropertyManager props) throws  XMLStreamException {
+    public XMLStreamReaderImpl(InputStream inputStream, PropertyManager props) throws XMLStreamException {
         init(props);
         //publicId, systemid, baseSystemId, inputStream, enocding
-        XMLInputSource inputSource = new XMLInputSource(null,null,null,inputStream,null);
+        XMLInputSource inputSource = new XMLInputSource(null, null, null, inputStream, null);
         //pass the input source to document scanner impl.
         setInputSource(inputSource);
     }
 
-    public XMLDocumentScannerImpl getScanner(){
+    public XMLDocumentScannerImpl getScanner() {
         System.out.println("returning scanner");
         return fScanner;
     }
+
     /**
      * @param systemid
      * @param props
      * @throws XMLStreamException
      */
-    public XMLStreamReaderImpl(String systemid, PropertyManager props) throws  XMLStreamException {
+    public XMLStreamReaderImpl(String systemid, PropertyManager props) throws XMLStreamException {
         init(props);
         //publicId, systemid, baseSystemId, inputStream, enocding
         XMLInputSource inputSource = new XMLInputSource(null, systemid, null, false);
@@ -144,17 +166,18 @@
         setInputSource(inputSource);
     }
 
-
     /**
      * @param inputStream
      * @param encoding
      * @param props
      * @throws XMLStreamException
      */
-    public XMLStreamReaderImpl(InputStream inputStream, String encoding, PropertyManager props ) throws  XMLStreamException {
+    public XMLStreamReaderImpl(InputStream inputStream, String encoding, PropertyManager props)
+            throws XMLStreamException {
         init(props);
         //publicId, systemid, baseSystemId, inputStream, enocding
-        XMLInputSource inputSource = new XMLInputSource(null,null,null, new BufferedInputStream(inputStream),encoding );
+        XMLInputSource inputSource = new XMLInputSource(null, null, null,
+                new BufferedInputStream(inputStream), encoding);
         //pass the input source to document scanner impl.
         setInputSource(inputSource);
     }
@@ -164,11 +187,13 @@
      * @param props
      * @throws XMLStreamException
      */
-    public XMLStreamReaderImpl(Reader reader, PropertyManager props) throws  XMLStreamException {
+    public XMLStreamReaderImpl(Reader reader, PropertyManager props)
+            throws XMLStreamException {
         init(props);
         //publicId, systemid, baseSystemId, inputStream, enocding
         //xxx: Using buffered reader
-        XMLInputSource inputSource = new XMLInputSource(null,null,null,new BufferedReader(reader),null);
+        XMLInputSource inputSource = new XMLInputSource(null, null, null,
+                new BufferedReader(reader), null);
         //pass the input source to document scanner impl.
         setInputSource(inputSource);
     }
@@ -178,7 +203,8 @@
      * @param props
      * @throws XMLStreamException
      */
-    public XMLStreamReaderImpl(XMLInputSource inputSource, PropertyManager props) throws  XMLStreamException {
+    public XMLStreamReaderImpl(XMLInputSource inputSource, PropertyManager props)
+            throws XMLStreamException {
         init(props);
         //pass the input source to document scanner impl.
         setInputSource(inputSource);
@@ -188,34 +214,36 @@
      * @param inputSource
      * @throws XMLStreamException
      */
-    public void setInputSource(XMLInputSource inputSource ) throws XMLStreamException {
+    public final void setInputSource(XMLInputSource inputSource) throws XMLStreamException {
         //once setInputSource() is called this instance is busy parsing the inputsource supplied
         //this instances is free for reuse if parser has reached END_DOCUMENT state or application has
         //called close()
         fReuse = false;
 
-        try{
+        try {
 
-            fScanner.setInputSource(inputSource) ;
+            fScanner.setInputSource(inputSource);
             //XMLStreamReader should be in defined state
-            if(fReaderInDefinedState){
+            if (fReaderInDefinedState) {
                 fEventType = fScanner.next();
-                if (versionStr == null)
+                if (versionStr == null) {
                     versionStr = getVersion();
+                }
 
-                if (fEventType == XMLStreamConstants.START_DOCUMENT && versionStr != null && versionStr.equals("1.1")){
+                if (fEventType == XMLStreamConstants.START_DOCUMENT && versionStr != null
+                        && versionStr.equals("1.1")) {
                     switchToXML11Scanner();
                 }
 
             }
-        }catch(java.io.IOException ex){
+        } catch (java.io.IOException ex) {
             throw new XMLStreamException(ex);
-        } catch(XNIException ex){ //Issue 56 XNIException not caught
+        } catch (XNIException ex) { //Issue 56 XNIException not caught
             throw new XMLStreamException(ex.getMessage(), getLocation(), ex.getException());
         }
     }//setInputSource
 
-    void init(PropertyManager propertyManager) throws XMLStreamException {
+    final void init(PropertyManager propertyManager) throws XMLStreamException {
         fPropertyManager = propertyManager;
         //set Stax internal properties -- Note that these instances are being created in XMLReaderImpl.
         //1.SymbolTable
@@ -223,23 +251,23 @@
         //3.XMLEntityManager
         //4. call reset()
         //1.
-        propertyManager.setProperty(SYMBOL_TABLE,  fSymbolTable ) ;
+        propertyManager.setProperty(SYMBOL_TABLE, fSymbolTable);
         //2.
-        propertyManager.setProperty(ERROR_REPORTER,  fErrorReporter ) ;
+        propertyManager.setProperty(ERROR_REPORTER, fErrorReporter);
         //3.
         propertyManager.setProperty(ENTITY_MANAGER, fEntityManager);
         //4.
         reset();
     }
 
-    /** This function tells if this instances is available for reuse.
-     * One must call reset() and setInputSource() to be able to reuse
-     * this instance.
+    /**
+     * This function tells if this instances is available for reuse. One must
+     * call reset() and setInputSource() to be able to reuse this instance.
      */
-    public boolean canReuse(){
-        if(DEBUG){
+    public boolean canReuse() {
+        if (DEBUG) {
             System.out.println("fReuse = " + fReuse);
-            System.out.println("fEventType = " + getEventTypeString(fEventType) );
+            System.out.println("fEventType = " + getEventTypeString(fEventType));
         }
         //when parsing begins, fReuse is set to false
         //fReuse is set to 'true' when application calls close()
@@ -249,9 +277,9 @@
     /**
      * Resets this instance so that this instance is ready for reuse.
      */
-    public void reset(){
+    public void reset() {
         fReuse = true;
-        fEventType = 0 ;
+        fEventType = 0;
         //reset entity manager
         fEntityManager.reset(fPropertyManager);
         //reset the scanner
@@ -259,26 +287,30 @@
         //REVISIT:this is too ugly -- we are getting XMLEntityManager and XMLEntityReader from
         //property manager, it should be only XMLEntityManager
         fDTDDecl = null;
-        fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner()  ;
-        //default value for this property is true. However, this should be false when using XMLEventReader... Ugh..
-        //because XMLEventReader should not have defined state.
-        fReaderInDefinedState = ((Boolean)fPropertyManager.getProperty(READER_IN_DEFINED_STATE)).booleanValue();
-        fBindNamespaces = ((Boolean)fPropertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
+        fEntityScanner = fEntityManager.getEntityScanner();
+        //default value for this property is true. However, this should be false
+        //when using XMLEventReader, because XMLEventReader should not have defined state.
+        fReaderInDefinedState = ((Boolean) fPropertyManager.getProperty(READER_IN_DEFINED_STATE));
         versionStr = null;
     }
 
-
-    /** Frees any resources associated with this Reader. This method does not close the underlying input source.
-     * @throws XMLStreamException if there are errors freeing associated resources
+    /**
+     * Frees any resources associated with this Reader. This method does not
+     * close the underlying input source.
+     *
+     * @throws XMLStreamException if there are errors freeing associated
+     * resources
      */
     public void close() throws XMLStreamException {
         //xxx: Check what this function is intended to do.
         //reset();
-        fReuse = true ;
+        fReuse = true;
     }
 
-
-    /** Returns the character encoding declared on the xml declaration Returns null if none was declared
+    /**
+     * Returns the character encoding declared on the xml declaration Returns
+     * null if none was declared
+     *
      * @return the encoding declared in the document or null
      */
     public String getCharacterEncodingScheme() {
@@ -286,7 +318,6 @@
 
     }
 
-
     /**
      * @return
      */
@@ -294,37 +325,45 @@
         return fEntityScanner.getColumnNumber();
     }//getColumnNumber
 
-    /** Return input encoding if known or null if unknown.
+    /**
+     * Return input encoding if known or null if unknown.
+     *
      * @return the encoding of this instance or null
      */
     public String getEncoding() {
         return fEntityScanner.getEncoding();
     }//getEncoding
 
-    /** Returns the current value of the parse event as a string, this returns the string value of a CHARACTERS event, returns the value of a COMMENT, the replacement value for an ENTITY_REFERENCE, the string value of a CDATA section, the string value for a SPACE event, or the String value of the internal subset of the DTD. If an ENTITY_REFERENCE has been resolved, any character data will be reported as CHARACTERS events.
+    /**
+     * Returns the current value of the parse event as a string, this returns
+     * the string value of a CHARACTERS event, returns the value of a COMMENT,
+     * the replacement value for an ENTITY_REFERENCE, the string value of a
+     * CDATA section, the string value for a SPACE event, or the String value of
+     * the internal subset of the DTD. If an ENTITY_REFERENCE has been resolved,
+     * any character data will be reported as CHARACTERS events.
+     *
      * @return the current text or null
      */
     public int getEventType() {
-        return fEventType ;
+        return fEventType;
     }//getEventType
 
     /**
      * @return
      */
     public int getLineNumber() {
-        return fEntityScanner.getLineNumber() ;
+        return fEntityScanner.getLineNumber();
     }//getLineNumber
 
     public String getLocalName() {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
             //xxx check whats the value of fCurrentElement
-            return fScanner.getElementQName().localpart ;
-        }
-        else if(fEventType == XMLEvent.ENTITY_REFERENCE){
+            return fScanner.getElementQName().localpart;
+        } else if (fEventType == XMLEvent.ENTITY_REFERENCE) {
             return fScanner.getEntityName();
         }
-        throw new IllegalStateException("Method getLocalName() cannot be called for " +
-            getEventTypeString(fEventType) + " event.");
+        throw new IllegalStateException("Method getLocalName() cannot be called for "
+                + getEventTypeString(fEventType) + " event.");
     }//getLocalName()
 
     /**
@@ -332,115 +371,119 @@
      */
     public String getNamespaceURI() {
         //doesn't take care of Attribute as separte event
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
-            return fScanner.getElementQName().uri ;
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
+            return fScanner.getElementQName().uri;
         }
-        return null ;
+        return null;
     }//getNamespaceURI
 
-    /** Get the data section of a processing instruction
+    /**
+     * Get the data section of a processing instruction
+     *
      * @return the data or null
      */
-
     public String getPIData() {
-        if( fEventType == XMLEvent.PROCESSING_INSTRUCTION){
+        if (fEventType == XMLEvent.PROCESSING_INSTRUCTION) {
             return fScanner.getPIData().toString();
+        } else {
+            throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType)
+                    + " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION);
         }
-        else throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType) +
-        " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION  ) ;
     }//getPIData
 
-
-    /** Get the target of a processing instruction
+    /**
+     * Get the target of a processing instruction
+     *
      * @return the target or null
      */
     public String getPITarget() {
-        if( fEventType == XMLEvent.PROCESSING_INSTRUCTION){
+        if (fEventType == XMLEvent.PROCESSING_INSTRUCTION) {
             return fScanner.getPITarget();
+        } else {
+            throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType)
+                    + " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION);
         }
-        else throw new java.lang.IllegalStateException("Current state of the parser is " + getEventTypeString(fEventType) +
-        " But Expected state is " + XMLEvent.PROCESSING_INSTRUCTION  ) ;
 
     }//getPITarget
 
-
     /**
-    * @return the prefix of the current event, or null if the event does
-    * not have a prefix. For START_ELEMENT and END_ELEMENT, return
-    * XMLConstants.DEFAULT_NS_PREFIX when no prefix is available.
-    */
+     * @return the prefix of the current event, or null if the event does not
+     * have a prefix. For START_ELEMENT and END_ELEMENT, return
+     * XMLConstants.DEFAULT_NS_PREFIX when no prefix is available.
+     */
     public String getPrefix() {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
             String prefix = fScanner.getElementQName().prefix;
             return prefix == null ? XMLConstants.DEFAULT_NS_PREFIX : prefix;
         }
-        return null ;
+        return null;
     }//getPrefix()
 
-
-
     /**
      * @return
      */
     public char[] getTextCharacters() {
-        if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
-                 || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
-             return fScanner.getCharacterData().ch;
-         } else{
-             throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
-                     + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
-                     + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextCharacters() " ) ;
-         }
+        if (fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
+                || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE) {
+            return fScanner.getCharacterData().ch;
+        } else {
+            throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
+                    + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
+                    + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
+                    + " , " + getEventTypeString(XMLEvent.SPACE) + " valid for getTextCharacters() ");
+        }
     }
 
     /**
      * @return
      */
     public int getTextLength() {
-        if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
-                 || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
-             return fScanner.getCharacterData().length;
-         } else{
-             throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
-                     + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
-                     + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextLength() " ) ;
-         }
+        if (fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
+                || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE) {
+            return fScanner.getCharacterData().length;
+        } else {
+            throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
+                    + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
+                    + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
+                    + " , " + getEventTypeString(XMLEvent.SPACE) + " valid for getTextLength() ");
+        }
 
-   }
+    }
 
     /**
      * @return
      */
     public int getTextStart() {
-        if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
-             return  fScanner.getCharacterData().offset;
-         } else{
-             throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
-                     + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
-                     + " , " + getEventTypeString(XMLEvent.SPACE) +" valid for getTextStart() " ) ;
-         }
+        if (fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
+                || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE) {
+            return fScanner.getCharacterData().offset;
+        } else {
+            throw new IllegalStateException("Current state = " + getEventTypeString(fEventType)
+                    + " is not among the states " + getEventTypeString(XMLEvent.CHARACTERS) + " , "
+                    + getEventTypeString(XMLEvent.COMMENT) + " , " + getEventTypeString(XMLEvent.CDATA)
+                    + " , " + getEventTypeString(XMLEvent.SPACE) + " valid for getTextStart() ");
+        }
     }
 
     /**
      * @return
      */
     public String getValue() {
-        if(fEventType == XMLEvent.PROCESSING_INSTRUCTION){
+        if (fEventType == XMLEvent.PROCESSING_INSTRUCTION) {
             return fScanner.getPIData().toString();
-        } else if(fEventType == XMLEvent.COMMENT){
+        } else if (fEventType == XMLEvent.COMMENT) {
             return fScanner.getComment();
-        } else if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT){
-            return fScanner.getElementQName().localpart ;
-        } else if(fEventType == XMLEvent.CHARACTERS){
+        } else if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
+            return fScanner.getElementQName().localpart;
+        } else if (fEventType == XMLEvent.CHARACTERS) {
             return fScanner.getCharacterData().toString();
         }
         return null;
     }//getValue()
 
-    /** Get the XML language version of the current document being parsed */
+    /**
+     * Get the XML language version of the current document being parsed
+     */
     public String getVersion() {
         //apply SAP's patch: the default version in the scanner was set to 1.0 because of DOM and SAX
         //so this patch is a workaround of the difference between StAX and DOM
@@ -455,14 +498,16 @@
      * @return
      */
     public boolean hasAttributes() {
-        return fScanner.getAttributeIterator().getLength() > 0 ? true : false ;
+        return fScanner.getAttributeIterator().getLength() > 0 ? true : false;
     }
 
-    /** this Funtion returns true if the current event has name */
+    /**
+     * this Funtion returns true if the current event has name
+     */
     public boolean hasName() {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
             return true;
-        }  else {
+        } else {
             return false;
         }
     }//hasName()
@@ -473,7 +518,9 @@
      */
     public boolean hasNext() throws XMLStreamException {
         //the scanner returns -1 when it detects a broken stream
-        if (fEventType == -1) return false;
+        if (fEventType == -1) {
+            return false;
+        }
         //we can check in scanners if the scanner state is not set to
         //terminating, we still have more events.
         return fEventType != XMLEvent.END_DOCUMENT;
@@ -483,9 +530,9 @@
      * @return
      */
     public boolean hasValue() {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
-        || fEventType == XMLEvent.ENTITY_REFERENCE || fEventType == XMLEvent.PROCESSING_INSTRUCTION
-        || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CHARACTERS) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
+                || fEventType == XMLEvent.ENTITY_REFERENCE || fEventType == XMLEvent.PROCESSING_INSTRUCTION
+                || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CHARACTERS) {
             return true;
         } else {
             return false;
@@ -515,18 +562,19 @@
     }
 
     /**
-     *  Returns true if the cursor points to a character data event that consists of all whitespace
-     *  Application calling this method needs to cache the value and avoid calling this method again
-     *  for the same event.
+     * Returns true if the cursor points to a character data event that consists
+     * of all whitespace Application calling this method needs to cache the
+     * value and avoid calling this method again for the same event.
+     *
      * @return
      */
     public boolean isWhiteSpace() {
-        if(isCharacters() || (fEventType == XMLStreamConstants.CDATA)){
-            char [] ch = this.getTextCharacters();
+        if (isCharacters() || (fEventType == XMLStreamConstants.CDATA)) {
+            char[] ch = this.getTextCharacters();
             final int start = this.getTextStart();
             final int end = start + this.getTextLength();
-            for (int i = start; i < end; i++){
-                if(!XMLChar.isSpace(ch[i])){
+            for (int i = start; i < end; i++) {
+                if (!XMLChar.isSpace(ch[i])) {
                     return false;
                 }
             }
@@ -535,18 +583,18 @@
         return false;
     }
 
-
-
     /**
      * @throws XMLStreamException
      * @return
      */
     public int next() throws XMLStreamException {
-        if( !hasNext() ) {
+        if (!hasNext()) {
             if (fEventType != -1) {
-                throw new java.util.NoSuchElementException( "END_DOCUMENT reached: no more elements on the stream." );
+                throw new java.util.NoSuchElementException(
+                        "END_DOCUMENT reached: no more elements on the stream.");
             } else {
-                throw new XMLStreamException( "Error processing input source. The input stream is not complete." );
+                throw new XMLStreamException(
+                        "Error processing input source. The input stream is not complete.");
             }
         }
         try {
@@ -566,14 +614,14 @@
         } catch (IOException ex) {
             // if this error occured trying to resolve the external DTD subset
             // and IS_VALIDATING == false, then this is not an XML error
-            if (fScanner.fScannerState == fScanner.SCANNER_STATE_DTD_EXTERNAL) {
+            if (fScanner.fScannerState == XMLDocumentScannerImpl.SCANNER_STATE_DTD_EXTERNAL) {
                 Boolean isValidating = (Boolean) fPropertyManager.getProperty(
                         XMLInputFactory.IS_VALIDATING);
                 if (isValidating != null
                         && !isValidating.booleanValue()) {
                     // ignore the error, set scanner to known state
                     fEventType = XMLEvent.DTD;
-                    fScanner.setScannerState(fScanner.SCANNER_STATE_PROLOG);
+                    fScanner.setScannerState(XMLDocumentScannerImpl.SCANNER_STATE_PROLOG);
                     fScanner.setDriver(fScanner.fPrologDriver);
                     if (fDTDDecl == null
                             || fDTDDecl.length() == 0) {
@@ -597,10 +645,11 @@
         }
     } //next()
 
-    private void switchToXML11Scanner() throws IOException{
+    private void switchToXML11Scanner() throws IOException {
 
         int oldEntityDepth = fScanner.fEntityDepth;
-        com.sun.org.apache.xerces.internal.xni.NamespaceContext oldNamespaceContext = fScanner.fNamespaceContext;
+        com.sun.org.apache.xerces.internal.xni.NamespaceContext oldNamespaceContext
+                = fScanner.fNamespaceContext;
 
         fScanner = new XML11NSDocumentScannerImpl();
 
@@ -617,10 +666,8 @@
         fEventType = fScanner.next();
     }
 
-
-
     final static String getEventTypeString(int eventType) {
-        switch (eventType){
+        switch (eventType) {
             case XMLEvent.START_ELEMENT:
                 return "START_ELEMENT";
             case XMLEvent.END_ELEMENT:
@@ -649,10 +696,11 @@
         return "UNKNOWN_EVENT_TYPE, " + String.valueOf(eventType);
     }
 
-    /** Returns the count of attributes on this START_ELEMENT,
-     * this method is only valid on a START_ELEMENT or ATTRIBUTE.  This
-     * count excludes namespace definitions.  Attribute indices are
-     * zero-based.
+    /**
+     * Returns the count of attributes on this START_ELEMENT, this method is
+     * only valid on a START_ELEMENT or ATTRIBUTE. This count excludes namespace
+     * definitions. Attribute indices are zero-based.
+     *
      * @return returns the number of attributes
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
@@ -661,31 +709,32 @@
         //does length includes namespace declarations ?
 
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
-            return fScanner.getAttributeIterator().getLength() ;
-        } else{
-            throw new java.lang.IllegalStateException( "Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeCount()") ;
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+            return fScanner.getAttributeIterator().getLength();
+        } else {
+            throw new java.lang.IllegalStateException("Current state is not among the states "
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeCount()");
         }
     }//getAttributeCount
 
-    /** Returns the localName of the attribute at the provided
-     * index
+    /**
+     * Returns the localName of the attribute at the provided index
+     *
      * @param index the position of the attribute
      * @return the localName of the attribute
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public QName getAttributeName(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
-            return convertXNIQNametoJavaxQName(fScanner.getAttributeIterator().getQualifiedName(index)) ;
-        } else{
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+            return convertXNIQNametoJavaxQName(fScanner.getAttributeIterator().getQualifiedName(index));
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeName()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeName()");
         }
     }//getAttributeName
 
@@ -695,51 +744,54 @@
      */
     public String getAttributeLocalName(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
-            return fScanner.getAttributeIterator().getLocalName(index) ;
-        } else{
-            throw new java.lang.IllegalStateException() ;
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+            return fScanner.getAttributeIterator().getLocalName(index);
+        } else {
+            throw new java.lang.IllegalStateException();
         }
     }//getAttributeName
 
-    /** Returns the namespace of the attribute at the provided
-     * index
+    /**
+     * Returns the namespace of the attribute at the provided index
+     *
      * @param index the position of the attribute
      * @return the namespace URI (can be null)
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public String getAttributeNamespace(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
             return fScanner.getAttributeIterator().getURI(index);
-        } else{
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeNamespace()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeNamespace()");
         }
 
     }//getAttributeNamespace
 
-    /** Returns the prefix of this attribute at the
-     * provided index
+    /**
+     * Returns the prefix of this attribute at the provided index
+     *
      * @param index the position of the attribute
      * @return the prefix of the attribute
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public String getAttributePrefix(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
             return fScanner.getAttributeIterator().getPrefix(index);
-        } else{
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributePrefix()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributePrefix()");
         }
     }//getAttributePrefix
 
-    /** Returns the qname of the attribute at the provided index
+    /**
+     * Returns the qname of the attribute at the provided index
      *
      * @param index the position of the attribute
      * @return the QName of the attribute
@@ -747,53 +799,55 @@
      */
     public javax.xml.namespace.QName getAttributeQName(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
             // create new object at runtime..
-            String localName = fScanner.getAttributeIterator().getLocalName(index) ;
-            String uri = fScanner.getAttributeIterator().getURI(index) ;
-            return new javax.xml.namespace.QName(uri, localName) ;
-        } else{
+            String localName = fScanner.getAttributeIterator().getLocalName(index);
+            String uri = fScanner.getAttributeIterator().getURI(index);
+            return new javax.xml.namespace.QName(uri, localName);
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeQName()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeQName()");
         }
     }//getAttributeQName
 
-    /** Returns the XML type of the attribute at the provided
-     * index
+    /**
+     * Returns the XML type of the attribute at the provided index
+     *
      * @param index the position of the attribute
      * @return the XML type of the attribute
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public String getAttributeType(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
-            return fScanner.getAttributeIterator().getType(index) ;
-        } else{
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+            return fScanner.getAttributeIterator().getType(index);
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeType()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeType()");
         }
 
     }//getAttributeType
 
-    /** Returns the value of the attribute at the
-     * index
+    /**
+     * Returns the value of the attribute at the index
+     *
      * @param index the position of the attribute
      * @return the attribute value
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public String getAttributeValue(int index) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
-            return fScanner.getAttributeIterator().getValue(index) ;
-        } else{
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+            return fScanner.getAttributeIterator().getValue(index);
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeValue()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeValue()");
         }
 
     }//getAttributeValue
@@ -805,67 +859,69 @@
      */
     public String getAttributeValue(String namespaceURI, String localName) {
         //State should be either START_ELEMENT or ATTRIBUTE
-        if( fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.ATTRIBUTE) {
             XMLAttributesImpl attributes = fScanner.getAttributeIterator();
             if (namespaceURI == null) { //sjsxp issue 70
-                return attributes.getValue(attributes.getIndexByLocalName(localName)) ;
+                return attributes.getValue(attributes.getIndexByLocalName(localName));
             } else {
                 return fScanner.getAttributeIterator().getValue(
-                        namespaceURI.length() == 0 ? null : namespaceURI, localName) ;
+                        namespaceURI.length() == 0 ? null : namespaceURI, localName);
             }
 
-        } else{
+        } else {
             throw new java.lang.IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for getAttributeValue()") ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for getAttributeValue()");
         }
 
     }
 
-    /** Reads the content of a text-only element. Precondition:
-     * the current event is START_ELEMENT. Postcondition:
-     * The current event is the corresponding END_ELEMENT.
-     * @throws XMLStreamException if the current event is not a START_ELEMENT or if
-     * a non text element is encountered
+    /**
+     * Reads the content of a text-only element. Precondition: the current event
+     * is START_ELEMENT. Postcondition: The current event is the corresponding
+     * END_ELEMENT.
+     *
+     * @throws XMLStreamException if the current event is not a START_ELEMENT or
+     * if a non text element is encountered
      */
     public String getElementText() throws XMLStreamException {
 
-        if(getEventType() != XMLStreamConstants.START_ELEMENT) {
+        if (getEventType() != XMLStreamConstants.START_ELEMENT) {
             throw new XMLStreamException(
-            "parser must be on START_ELEMENT to read next text", getLocation());
+                    "parser must be on START_ELEMENT to read next text", getLocation());
         }
         int eventType = next();
-        StringBuffer content = new StringBuffer();
-        while(eventType != XMLStreamConstants.END_ELEMENT ) {
-            if(eventType == XMLStreamConstants.CHARACTERS
-            || eventType == XMLStreamConstants.CDATA
-            || eventType == XMLStreamConstants.SPACE
-            || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
+        StringBuilder content = new StringBuilder();
+        while (eventType != XMLStreamConstants.END_ELEMENT) {
+            if (eventType == XMLStreamConstants.CHARACTERS
+                    || eventType == XMLStreamConstants.CDATA
+                    || eventType == XMLStreamConstants.SPACE
+                    || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
                 content.append(getText());
-            } else if(eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
-            || eventType == XMLStreamConstants.COMMENT) {
+            } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
+                    || eventType == XMLStreamConstants.COMMENT) {
                 // skipping
-            } else if(eventType == XMLStreamConstants.END_DOCUMENT) {
-                throw new XMLStreamException("unexpected end of document when reading element text content");
-            } else if(eventType == XMLStreamConstants.START_ELEMENT) {
+            } else if (eventType == XMLStreamConstants.END_DOCUMENT) {
                 throw new XMLStreamException(
-                "elementGetText() function expects text only elment but START_ELEMENT was encountered.", getLocation());
+                        "unexpected end of document when reading element text content");
+            } else if (eventType == XMLStreamConstants.START_ELEMENT) {
+                throw new XMLStreamException("elementGetText() function expects text "
+                        + "only elment but START_ELEMENT was encountered.", getLocation());
             } else {
                 throw new XMLStreamException(
-                "Unexpected event type "+ eventType, getLocation());
+                        "Unexpected event type " + eventType, getLocation());
             }
             eventType = next();
         }
         return content.toString();
     }
 
-    /** Return the current location of the processor.
-     * If the Location is unknown the processor should return
-     * an implementation of Location that returns -1 for the
-     * location and null for the publicId and systemId.
-     * The location information is only valid until next() is
-     * called.
+    /**
+     * Return the current location of the processor. If the Location is unknown
+     * the processor should return an implementation of Location that returns -1
+     * for the location and null for the publicId and systemId. The location
+     * information is only valid until next() is called.
      */
     public Location getLocation() {
         return new Location() {
@@ -874,11 +930,12 @@
             int _offset = fEntityScanner.getCharacterOffset();
             int _columnNumber = fEntityScanner.getColumnNumber();
             int _lineNumber = fEntityScanner.getLineNumber();
-            public String getLocationURI(){
+
+            public String getLocationURI() {
                 return _systemId;
             }
 
-            public int getCharacterOffset(){
+            public int getCharacterOffset() {
                 return _offset;
             }
 
@@ -886,224 +943,256 @@
                 return _columnNumber;
             }
 
-            public int getLineNumber(){
+            public int getLineNumber() {
                 return _lineNumber;
             }
 
-            public String getPublicId(){
+            public String getPublicId() {
                 return _publicId;
             }
 
-            public String getSystemId(){
+            public String getSystemId() {
                 return _systemId;
             }
 
-            public String toString(){
-                StringBuffer sbuffer = new StringBuffer() ;
+            public String toString() {
+                StringBuilder sbuffer = new StringBuilder();
                 sbuffer.append("Line number = " + getLineNumber());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 sbuffer.append("Column number = " + getColumnNumber());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 sbuffer.append("System Id = " + getSystemId());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 sbuffer.append("Public Id = " + getPublicId());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 sbuffer.append("Location Uri= " + getLocationURI());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 sbuffer.append("CharacterOffset = " + getCharacterOffset());
-                sbuffer.append("\n") ;
+                sbuffer.append("\n");
                 return sbuffer.toString();
             }
-        } ;
+        };
 
     }
 
-    /** Returns a QName for the current START_ELEMENT or END_ELEMENT event
+    /**
+     * Returns a QName for the current START_ELEMENT or END_ELEMENT event
+     *
      * @return the QName for the current START_ELEMENT or END_ELEMENT event
      */
     public javax.xml.namespace.QName getName() {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT)
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT) {
             return convertXNIQNametoJavaxQName(fScanner.getElementQName());
-        else
-            throw new java.lang.IllegalStateException("Illegal to call getName() "+
-            "when event type is "+ getEventTypeString(fEventType) + "."
-                     + " Valid states are " + getEventTypeString(XMLEvent.START_ELEMENT) + ", "
-                     + getEventTypeString(XMLEvent.END_ELEMENT));
+        } else {
+            throw new java.lang.IllegalStateException("Illegal to call getName() "
+                    + "when event type is " + getEventTypeString(fEventType) + "."
+                    + " Valid states are " + getEventTypeString(XMLEvent.START_ELEMENT) + ", "
+                    + getEventTypeString(XMLEvent.END_ELEMENT));
+        }
     }
 
-    /** Returns a read only namespace context for the current
-     * position.  The context is transient and only valid until
-     * a call to next() changes the state of the reader.
+    /**
+     * Returns a read only namespace context for the current position. The
+     * context is transient and only valid until a call to next() changes the
+     * state of the reader.
+     *
      * @return return a namespace context
      */
     public NamespaceContext getNamespaceContext() {
-        return fNamespaceContextWrapper ;
+        return fNamespaceContextWrapper;
     }
 
-    /** Returns the count of namespaces declared on this START_ELEMENT or END_ELEMENT,
-     * this method is only valid on a START_ELEMENT, END_ELEMENT or NAMESPACE. On
-     * an END_ELEMENT the count is of the namespaces that are about to go
-     * out of scope.  This is the equivalent of the information reported
-     * by SAX callback for an end element event.
-     * @return returns the number of namespace declarations on this specific element
-     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
+    /**
+     * Returns the count of namespaces declared on this START_ELEMENT or
+     * END_ELEMENT, this method is only valid on a START_ELEMENT, END_ELEMENT or
+     * NAMESPACE. On an END_ELEMENT the count is of the namespaces that are
+     * about to go out of scope. This is the equivalent of the information
+     * reported by SAX callback for an end element event.
+     *
+     * @return returns the number of namespace declarations on this specific
+     * element
+     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT
+     * or NAMESPACE
      */
     public int getNamespaceCount() {
         //namespaceContext is dynamic object.
         //REVISIT: check if it specifies all conditions mentioned in the javadoc
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
-            return fScanner.getNamespaceContext().getDeclaredPrefixCount() ;
-        } else{
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
+                || fEventType == XMLEvent.NAMESPACE) {
+            return fScanner.getNamespaceContext().getDeclaredPrefixCount();
+        } else {
             throw new IllegalStateException("Current event state is " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
-             + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
-                     + getEventTypeString(XMLEvent.NAMESPACE)
-             + " valid for getNamespaceCount()." );
+                    + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
+                    + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
+                    + getEventTypeString(XMLEvent.NAMESPACE)
+                    + " valid for getNamespaceCount().");
         }
     }
 
-    /** Returns the prefix for the namespace declared at the
-     * index.  Returns null if this is the default namespace
-     * declaration
+    /**
+     * Returns the prefix for the namespace declared at the index. Returns null
+     * if this is the default namespace declaration
      *
      * @param index the position of the namespace declaration
      * @return returns the namespace prefix
-     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
+     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT
+     * or NAMESPACE
      */
     public String getNamespacePrefix(int index) {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
+                || fEventType == XMLEvent.NAMESPACE) {
             //namespaceContext is dynamic object.
-            String prefix = fScanner.getNamespaceContext().getDeclaredPrefixAt(index) ;
-            return prefix.equals("") ? null : prefix ;
-        }
-        else{
+            String prefix = fScanner.getNamespaceContext().getDeclaredPrefixAt(index);
+            return prefix.equals("") ? null : prefix;
+        } else {
             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
-             + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
-                     + getEventTypeString(XMLEvent.NAMESPACE)
-             + " valid for getNamespacePrefix()." );
+                    + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
+                    + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
+                    + getEventTypeString(XMLEvent.NAMESPACE)
+                    + " valid for getNamespacePrefix().");
         }
     }
 
-    /** Returns the uri for the namespace declared at the
-     * index.
+    /**
+     * Returns the uri for the namespace declared at the index.
      *
      * @param index the position of the namespace declaration
      * @return returns the namespace uri
-     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT or NAMESPACE
+     * @throws IllegalStateException if this is not a START_ELEMENT, END_ELEMENT
+     * or NAMESPACE
      */
     public String getNamespaceURI(int index) {
-        if(fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT || fEventType == XMLEvent.NAMESPACE){
+        if (fEventType == XMLEvent.START_ELEMENT || fEventType == XMLEvent.END_ELEMENT
+                || fEventType == XMLEvent.NAMESPACE) {
             //namespaceContext is dynamic object.
-            return fScanner.getNamespaceContext().getURI(fScanner.getNamespaceContext().getDeclaredPrefixAt(index));
-        }
-        else{
+            return fScanner.getNamespaceContext().getURI(fScanner.getNamespaceContext()
+                    .getDeclaredPrefixAt(index));
+        } else {
             throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
-             + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
-             + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
-                     + getEventTypeString(XMLEvent.NAMESPACE)
-             + " valid for getNamespaceURI()." );
+                    + " is not among the states " + getEventTypeString(XMLEvent.START_ELEMENT)
+                    + ", " + getEventTypeString(XMLEvent.END_ELEMENT) + ", "
+                    + getEventTypeString(XMLEvent.NAMESPACE)
+                    + " valid for getNamespaceURI().");
         }
 
     }
 
-    /** Get the value of a feature/property from the underlying implementation
+    /**
+     * Get the value of a feature/property from the underlying implementation
+     *
      * @param name The name of the property, may not be null
      * @return The value of the property
      * @throws IllegalArgumentException if name is null
      */
     public Object getProperty(java.lang.String name) throws java.lang.IllegalArgumentException {
-        if(name == null) throw new java.lang.IllegalArgumentException() ;
-        if (fPropertyManager != null ){
-            if(name.equals(fPropertyManager.STAX_NOTATIONS)){
+        if (name == null) {
+            throw new java.lang.IllegalArgumentException();
+        }
+        if (fPropertyManager != null) {
+            if (name.equals(PropertyManager.STAX_NOTATIONS)) {
                 return getNotationDecls();
-            }else if(name.equals(fPropertyManager.STAX_ENTITIES)){
+            } else if (name.equals(PropertyManager.STAX_ENTITIES)) {
                 return getEntityDecls();
-            }else
+            } else {
                 return fPropertyManager.getProperty(name);
+            }
         }
         return null;
     }
 
-    /** Returns the current value of the parse event as a string,
-     * this returns the string value of a CHARACTERS event,
-     * returns the value of a COMMENT, the replacement value
-     * for an ENTITY_REFERENCE,
-     * or the String value of the DTD
+    /**
+     * Returns the current value of the parse event as a string, this returns
+     * the string value of a CHARACTERS event, returns the value of a COMMENT,
+     * the replacement value for an ENTITY_REFERENCE, or the String value of the
+     * DTD
+     *
      * @return the current text or null
-     * @throws java.lang.IllegalStateException if this state is not
-     * a valid text state.
+     * @throws java.lang.IllegalStateException if this state is not a valid text
+     * state.
      */
     public String getText() {
-        if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
-                || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE){
+        if (fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
+                || fEventType == XMLEvent.CDATA || fEventType == XMLEvent.SPACE) {
             //this requires creation of new string
             //fEventType == XMLEvent.ENTITY_REFERENCE
-            return fScanner.getCharacterData().toString() ;
-        } else if(fEventType == XMLEvent.ENTITY_REFERENCE){
+            return fScanner.getCharacterData().toString();
+        } else if (fEventType == XMLEvent.ENTITY_REFERENCE) {
             String name = fScanner.getEntityName();
-            if(name != null){
-                if(fScanner.foundBuiltInRefs)
+            if (name != null) {
+                if (fScanner.foundBuiltInRefs) {
                     return fScanner.getCharacterData().toString();
+                }
 
                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
                 Entity en = entityStore.getEntity(name);
-                if(en == null)
+                if (en == null) {
                     return null;
-                if(en.isExternal())
-                    return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId();
-                else
-                    return ((Entity.InternalEntity)en).text;
-            }else
-                return null;
-        }
-        else if(fEventType == XMLEvent.DTD){
-                if(fDTDDecl != null){
-                    return fDTDDecl;
                 }
-                XMLStringBuffer tmpBuffer = fScanner.getDTDDecl();
-                fDTDDecl = tmpBuffer.toString();
+                if (en.isExternal()) {
+                    return ((Entity.ExternalEntity) en).entityLocation.getExpandedSystemId();
+                } else {
+                    return ((Entity.InternalEntity) en).text;
+                }
+            } else {
+                return null;
+            }
+        } else if (fEventType == XMLEvent.DTD) {
+            if (fDTDDecl != null) {
                 return fDTDDecl;
-        } else{
-                throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
-                     + " is not among the states" + getEventTypeString(XMLEvent.CHARACTERS) + ", "
-                     + getEventTypeString(XMLEvent.COMMENT) + ", "
-                     + getEventTypeString(XMLEvent.CDATA) + ", "
-                     + getEventTypeString(XMLEvent.SPACE) + ", "
-                     + getEventTypeString(XMLEvent.ENTITY_REFERENCE) + ", "
-                     + getEventTypeString(XMLEvent.DTD) + " valid for getText() " ) ;
+            }
+            XMLStringBuffer tmpBuffer = fScanner.getDTDDecl();
+            fDTDDecl = tmpBuffer.toString();
+            return fDTDDecl;
+        } else {
+            throw new IllegalStateException("Current state " + getEventTypeString(fEventType)
+                    + " is not among the states" + getEventTypeString(XMLEvent.CHARACTERS) + ", "
+                    + getEventTypeString(XMLEvent.COMMENT) + ", "
+                    + getEventTypeString(XMLEvent.CDATA) + ", "
+                    + getEventTypeString(XMLEvent.SPACE) + ", "
+                    + getEventTypeString(XMLEvent.ENTITY_REFERENCE) + ", "
+                    + getEventTypeString(XMLEvent.DTD) + " valid for getText() ");
         }
     }//getText
 
-
-    /** Test if the current event is of the given type and if the namespace and name match the current namespace and name of the current event.
-     * If the namespaceURI is null it is not checked for equality, if the localName is null it is not checked for equality.
+    /**
+     * Test if the current event is of the given type and if the namespace and
+     * name match the current namespace and name of the current event. If the
+     * namespaceURI is null it is not checked for equality, if the localName is
+     * null it is not checked for equality.
+     *
      * @param type the event type
      * @param namespaceURI the uri of the event, may be null
      * @param localName the localName of the event, may be null
      * @throws XMLStreamException if the required values are not matched.
      */
     public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
-        if( type != fEventType)
-             throw new XMLStreamException("Event type " + getEventTypeString(type) + " specified did " +
-                     "not match with current parser event " + getEventTypeString(fEventType));
-          if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI()) )
-             throw new XMLStreamException("Namespace URI " + namespaceURI +" specified did not match " +
-                     "with current namespace URI");
-          if(localName != null && !localName.equals(getLocalName()))
-             throw new XMLStreamException("LocalName " + localName +" specified did not match with " +
-                     "current local name");
+        if (type != fEventType) {
+            throw new XMLStreamException("Event type " + getEventTypeString(type) + " specified did "
+                    + "not match with current parser event " + getEventTypeString(fEventType));
+        }
+        if (namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) {
+            throw new XMLStreamException("Namespace URI " + namespaceURI + " specified did not match "
+                    + "with current namespace URI");
+        }
+        if (localName != null && !localName.equals(getLocalName())) {
+            throw new XMLStreamException("LocalName " + localName + " specified did not match with "
+                    + "current local name");
+        }
         return;
     }
 
-    /** Gets the the text associated with a CHARACTERS, SPACE or CDATA event.
-     * Text starting a "sourceStart" is copied into "destination" starting at "targetStart".
-     * Up to "length" characters are copied.  The number of characters actually copied is returned.
+    /**
+     * Gets the the text associated with a CHARACTERS, SPACE or CDATA event.
+     * Text starting a "sourceStart" is copied into "destination" starting at
+     * "targetStart". Up to "length" characters are copied. The number of
+     * characters actually copied is returned.
      *
-     * The "sourceStart" argument must be greater or equal to 0 and less than or equal to
-     * the number of characters associated with the event.  Usually, one requests text starting at a "sourceStart" of 0.
-     * If the number of characters actually copied is less than the "length", then there is no more text.
-     * Otherwise, subsequent calls need to be made until all text has been retrieved. For example:
+     * The "sourceStart" argument must be greater or equal to 0 and less than or
+     * equal to the number of characters associated with the event. Usually, one
+     * requests text starting at a "sourceStart" of 0. If the number of
+     * characters actually copied is less than the "length", then there is no
+     * more text. Otherwise, subsequent calls need to be made until all text has
+     * been retrieved. For example:
      *
      * <code>
      * int length = 1024;
@@ -1116,30 +1205,36 @@
      *   if (nCopied < length)
      *       break;
      * }
-     * </code>
-     * XMLStreamException may be thrown if there are any XML errors in the underlying source.
-     * The "targetStart" argument must be greater than or equal to 0 and less than the length of "target",
-     * Length must be greater than 0 and "targetStart + length" must be less than or equal to length of "target".
+     * </code> XMLStreamException may be thrown if there are any XML errors in
+     * the underlying source. The "targetStart" argument must be greater than or
+     * equal to 0 and less than the length of "target", Length must be greater
+     * than 0 and "targetStart + length" must be less than or equal to length of
+     * "target".
      *
-     * @param sourceStart the index of the first character in the source array to copy
+     * @param sourceStart the index of the first character in the source array
+     * to copy
      * @param target the destination array
      * @param targetStart the start offset in the target array
      * @param length the number of characters to copy
      * @return the number of characters actually copied
-     * @throws XMLStreamException if the underlying XML source is not well-formed
-     * @throws IndexOutOfBoundsException if targetStart < 0 or > than the length of target
-     * @throws IndexOutOfBoundwhile(isCharacters()) ;sException if length < 0 or targetStart + length > length of target
+     * @throws XMLStreamException if the underlying XML source is not
+     * well-formed
+     * @throws IndexOutOfBoundsException if targetStart < 0 or > than the length
+     * of target
+     * @throws IndexOutOfBoundwhile(isCharacters()) ;sException if length < 0 or targetStart + length
+     * > length of target
      * @throws UnsupportedOperationException if this method is not supported
      * @throws NullPointerException is if target is null
      */
-    public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
+    public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+            throws XMLStreamException {
 
-        if(target == null){
-            throw new NullPointerException("target char array can't be null") ;
+        if (target == null) {
+            throw new NullPointerException("target char array can't be null");
         }
 
-        if(targetStart < 0 || length < 0 || sourceStart < 0 || targetStart >= target.length ||
-            (targetStart + length ) > target.length) {
+        if (targetStart < 0 || length < 0 || sourceStart < 0 || targetStart >= target.length
+                || (targetStart + length) > target.length) {
             throw new IndexOutOfBoundsException();
         }
 
@@ -1148,97 +1243,105 @@
         int copiedLength = 0;
         //int presentDataLen = getTextLength() - (getTextStart()+sourceStart);
         int available = getTextLength() - sourceStart;
-        if(available < 0){
-            throw new IndexOutOfBoundsException("sourceStart is greater than" +
-                "number of characters associated with this event");
+        if (available < 0) {
+            throw new IndexOutOfBoundsException("sourceStart is greater than"
+                    + "number of characters associated with this event");
         }
-        if(available < length){
+        if (available < length) {
             copiedLength = available;
-        } else{
+        } else {
             copiedLength = length;
         }
 
-        System.arraycopy(getTextCharacters(), getTextStart() + sourceStart , target, targetStart, copiedLength);
+        System.arraycopy(getTextCharacters(), getTextStart() + sourceStart, target, targetStart, copiedLength);
         return copiedLength;
     }
 
-    /** Return true if the current event has text, false otherwise
-     * The following events have text:
-     * CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT
+    /**
+     * Return true if the current event has text, false otherwise The following
+     * events have text: CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT
      */
     public boolean hasText() {
-        if(DEBUG) pr("XMLReaderImpl#EVENT TYPE = " + fEventType ) ;
-        if( fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT || fEventType == XMLEvent.CDATA) {
+        if (DEBUG) {
+            pr("XMLReaderImpl#EVENT TYPE = " + fEventType);
+        }
+        if (fEventType == XMLEvent.CHARACTERS || fEventType == XMLEvent.COMMENT
+                || fEventType == XMLEvent.CDATA) {
             return fScanner.getCharacterData().length > 0;
-        } else if(fEventType == XMLEvent.ENTITY_REFERENCE) {
+        } else if (fEventType == XMLEvent.ENTITY_REFERENCE) {
             String name = fScanner.getEntityName();
-            if(name != null){
-                if(fScanner.foundBuiltInRefs)
+            if (name != null) {
+                if (fScanner.foundBuiltInRefs) {
                     return true;
+                }
 
                 XMLEntityStorage entityStore = fEntityManager.getEntityStore();
                 Entity en = entityStore.getEntity(name);
-                if(en == null)
+                if (en == null) {
                     return false;
-                if(en.isExternal()){
-                    return ((Entity.ExternalEntity)en).entityLocation.getExpandedSystemId() != null;
-                } else{
-                    return ((Entity.InternalEntity)en).text != null ;
                 }
-            }else
+                if (en.isExternal()) {
+                    return ((Entity.ExternalEntity) en).entityLocation.getExpandedSystemId() != null;
+                } else {
+                    return ((Entity.InternalEntity) en).text != null;
+                }
+            } else {
                 return false;
-        } else {
-            if(fEventType == XMLEvent.DTD)
-                return fScanner.fSeenDoctypeDecl;
+            }
+        } else if (fEventType == XMLEvent.DTD) {
+            return fScanner.fSeenDoctypeDecl;
         }
         return false;
     }
 
-    /** Returns a boolean which indicates if this
-     * attribute was created by default
+    /**
+     * Returns a boolean which indicates if this attribute was created by
+     * default
+     *
      * @param index the position of the attribute
      * @return true if this is a default attribute
      * @throws IllegalStateException if this is not a START_ELEMENT or ATTRIBUTE
      */
     public boolean isAttributeSpecified(int index) {
         //check that current state should be either START_ELEMENT or ATTRIBUTE
-        if( (fEventType == XMLEvent.START_ELEMENT) || (fEventType == XMLEvent.ATTRIBUTE)){
-            return fScanner.getAttributeIterator().isSpecified(index) ;
-        } else{
+        if ((fEventType == XMLEvent.START_ELEMENT) || (fEventType == XMLEvent.ATTRIBUTE)) {
+            return fScanner.getAttributeIterator().isSpecified(index);
+        } else {
             throw new IllegalStateException("Current state is not among the states "
-                     + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
-                     + getEventTypeString(XMLEvent.ATTRIBUTE)
-                     + "valid for isAttributeSpecified()")  ;
+                    + getEventTypeString(XMLEvent.START_ELEMENT) + " , "
+                    + getEventTypeString(XMLEvent.ATTRIBUTE)
+                    + "valid for isAttributeSpecified()");
         }
     }
 
-    /** Returns true if the cursor points to a character data event
+    /**
+     * Returns true if the cursor points to a character data event
+     *
      * @return true if the cursor points to character data, false otherwise
      */
     public boolean isCharacters() {
-        return fEventType == XMLEvent.CHARACTERS ;
+        return fEventType == XMLEvent.CHARACTERS;
     }
 
-    /** Skips any insignificant events (COMMENT and PROCESSING_INSTRUCTION)
-     * until a START_ELEMENT or
-     * END_ELEMENT is reached. If other than space characters are
-     * encountered, an exception is thrown. This method should
-     * be used when processing element-only content because
-     * the parser is not able to recognize ignorable whitespace if
-     * then DTD is missing or not interpreted.
+    /**
+     * Skips any insignificant events (COMMENT and PROCESSING_INSTRUCTION) until
+     * a START_ELEMENT or END_ELEMENT is reached. If other than space characters
+     * are encountered, an exception is thrown. This method should be used when
+     * processing element-only content because the parser is not able to
+     * recognize ignorable whitespace if then DTD is missing or not interpreted.
+     *
      * @return the event type of the element read
      * @throws XMLStreamException if the current event is not white space
      */
     public int nextTag() throws XMLStreamException {
 
         int eventType = next();
-        while((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace
-        || (eventType == XMLStreamConstants.CDATA && isWhiteSpace())
-        // skip whitespace
-        || eventType == XMLStreamConstants.SPACE
-        || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
-        || eventType == XMLStreamConstants.COMMENT
-        ) {
+        while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace
+                || (eventType == XMLStreamConstants.CDATA && isWhiteSpace())
+                // skip whitespace
+                || eventType == XMLStreamConstants.SPACE
+                || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
+                || eventType == XMLStreamConstants.COMMENT) {
             eventType = next();
         }
 
@@ -1253,87 +1356,100 @@
         return eventType;
     }
 
-    /** Checks if standalone was set in the document
+    /**
+     * Checks if standalone was set in the document
+     *
      * @return true if standalone was set in the document, or false otherwise
      */
     public boolean standaloneSet() {
         //xxx: it requires if the standalone was set in the document ? This is different that if the document
         // is standalone
-        return fScanner.standaloneSet() ;
+        return fScanner.standaloneSet();
     }
 
     /**
      * @param qname
      * @return
      */
-    public javax.xml.namespace.QName convertXNIQNametoJavaxQName(com.sun.org.apache.xerces.internal.xni.QName qname){
-        if (qname == null) return null;
+    public javax.xml.namespace.QName convertXNIQNametoJavaxQName(
+            com.sun.org.apache.xerces.internal.xni.QName qname) {
+        if (qname == null) {
+            return null;
+        }
         //xxx: prefix definition ?
-        if(qname.prefix == null){
-            return new javax.xml.namespace.QName(qname.uri, qname.localpart) ;
-        } else{
-            return new javax.xml.namespace.QName(qname.uri, qname.localpart, qname.prefix) ;
+        if (qname.prefix == null) {
+            return new javax.xml.namespace.QName(qname.uri, qname.localpart);
+        } else {
+            return new javax.xml.namespace.QName(qname.uri, qname.localpart, qname.prefix);
         }
     }
 
-    /** Return the uri for the given prefix.
-     * The uri returned depends on the current state of the processor.
+    /**
+     * Return the uri for the given prefix. The uri returned depends on the
+     * current state of the processor.
      *
-     * <p><strong>NOTE:</strong>The 'xml' prefix is bound as defined in
-     * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in XML</a>
+     * <p>
+     * <strong>NOTE:</strong>The 'xml' prefix is bound as defined in
+     * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in
+     * XML</a>
      * specification to "http://www.w3.org/XML/1998/namespace".
      *
-     * <p><strong>NOTE:</strong> The 'xmlns' prefix must be resolved to following namespace
+     * <p>
+     * <strong>NOTE:</strong> The 'xmlns' prefix must be resolved to following
+     * namespace
      * <a href="http://www.w3.org/2000/xmlns/">http://www.w3.org/2000/xmlns/</a>
+     *
      * @return the uri bound to the given prefix or null if it is not bound
      * @param prefix The prefix to lookup, may not be null
      * @throws IllegalStateException - if the prefix is null
      */
     public String getNamespaceURI(String prefix) {
-        if(prefix == null) throw new java.lang.IllegalArgumentException("prefix cannot be null.") ;
+        if (prefix == null) {
+            throw new java.lang.IllegalArgumentException("prefix cannot be null.");
+        }
 
         //first add the string to symbol table.. since internally identity comparisons are done.
-        return fScanner.getNamespaceContext().getURI(fSymbolTable.addSymbol(prefix)) ;
+        return fScanner.getNamespaceContext().getURI(fSymbolTable.addSymbol(prefix));
     }
 
     //xxx: this function is not being used.
-    protected void setPropertyManager(PropertyManager propertyManager){
-        fPropertyManager = propertyManager ;
+    protected void setPropertyManager(PropertyManager propertyManager) {
+        fPropertyManager = propertyManager;
         //REVISIT: we were supplying hashmap ealier
-        fScanner.setProperty("stax-properties",propertyManager);
-        fScanner.setPropertyManager(propertyManager) ;
+        fScanner.setProperty("stax-properties", propertyManager);
+        fScanner.setPropertyManager(propertyManager);
     }
 
     /**
      * @return returns the reference to property manager.
      */
-    protected PropertyManager getPropertyManager(){
-        return fPropertyManager ;
+    protected PropertyManager getPropertyManager() {
+        return fPropertyManager;
     }
 
     static void pr(String str) {
-        System.out.println(str) ;
+        System.out.println(str);
     }
 
-    protected List getEntityDecls(){
-        if(fEventType == XMLStreamConstants.DTD){
+    protected List<EntityDeclaration> getEntityDecls() {
+        if (fEventType == XMLStreamConstants.DTD) {
             XMLEntityStorage entityStore = fEntityManager.getEntityStore();
-            ArrayList list = null;
-            if(entityStore.hasEntities()){
+            ArrayList<EntityDeclaration> list = null;
+            Map<String, Entity> entities = entityStore.getEntities();
+            if (entities.size() > 0) {
                 EntityDeclarationImpl decl = null;
-                list = new ArrayList(entityStore.getEntitySize());
-                Enumeration enu = entityStore.getEntityKeys();
-                while(enu.hasMoreElements()){
-                    String key = (String)enu.nextElement();
-                    Entity en = (Entity)entityStore.getEntity(key);
+                list = new ArrayList<>(entities.size());
+                for (Map.Entry<String, Entity> entry : entities.entrySet()) {
+                    String key = entry.getKey();
+                    Entity en = entry.getValue();
                     decl = new EntityDeclarationImpl();
                     decl.setEntityName(key);
-                    if(en.isExternal()){
-                        decl.setXMLResourceIdentifier(((Entity.ExternalEntity)en).entityLocation);
-                        decl.setNotationName(((Entity.ExternalEntity)en).notation);
+                    if (en.isExternal()) {
+                        decl.setXMLResourceIdentifier(((Entity.ExternalEntity) en).entityLocation);
+                        decl.setNotationName(((Entity.ExternalEntity) en).notation);
+                    } else {
+                        decl.setEntityReplacementText(((Entity.InternalEntity) en).text);
                     }
-                    else
-                        decl.setEntityReplacementText(((Entity.InternalEntity)en).text);
                     list.add(decl);
                 }
             }
@@ -1342,19 +1458,20 @@
         return null;
     }
 
-    protected List getNotationDecls(){
-        if(fEventType == XMLStreamConstants.DTD){
-            if(fScanner.fDTDScanner == null) return null;
-            DTDGrammar grammar = ((XMLDTDScannerImpl)(fScanner.fDTDScanner)).getGrammar();
-            if(grammar == null) return null;
-            List notations = grammar.getNotationDecls();
-
-            Iterator it = notations.iterator();
-            ArrayList list = new ArrayList();
-            while(it.hasNext()){
-                XMLNotationDecl ni = (XMLNotationDecl)it.next();
-                if(ni!= null){
-                    list.add(new NotationDeclarationImpl(ni));
+    protected List<NotationDeclaration> getNotationDecls() {
+        if (fEventType == XMLStreamConstants.DTD) {
+            if (fScanner.fDTDScanner == null) {
+                return null;
+            }
+            DTDGrammar grammar = ((XMLDTDScannerImpl) (fScanner.fDTDScanner)).getGrammar();
+            if (grammar == null) {
+                return null;
+            }
+            List<XMLNotationDecl> notations = grammar.getNotationDecls();
+            ArrayList<NotationDeclaration> list = new ArrayList<>();
+            for (XMLNotationDecl notation : notations) {
+                if (notation != null) {
+                    list.add(new NotationDeclarationImpl(notation));
                 }
             }
             return list;
@@ -1362,6 +1479,4 @@
         return null;
     }
 
-
-
 }//XMLReaderImpl
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/ObjectFactory.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/ObjectFactory.java
index dc7f85f..f7ed5d0 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/ObjectFactory.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/ObjectFactory.java
@@ -20,6 +20,8 @@
 
 package com.sun.org.apache.xerces.internal.utils;
 
+import java.util.function.Supplier;
+
 /**
  * This class is duplicated for each JAXP subpackage so keep it in sync.
  * It is package private and therefore is not exposed as part of the JAXP
@@ -61,9 +63,9 @@
     } // isDebugEnabled()
 
     /** Prints a message to standard error if debugging is enabled. */
-    private static void debugPrintln(String msg) {
+    private static void debugPrintln(Supplier<String> msgGen) {
         if (DEBUG) {
-            System.err.println("XERCES: " + msg);
+            System.err.println("XERCES: " + msgGen.get());
         }
     } // debugPrintln(String)
 
@@ -155,8 +157,8 @@
         try{
             Class providerClass = findProviderClass(className, cl, doFallback);
             Object instance = providerClass.newInstance();
-            if (DEBUG) debugPrintln("created new instance of " + providerClass +
-                   " using ClassLoader: " + cl);
+            debugPrintln(()->"created new instance of " + providerClass +
+                             " using ClassLoader: " + cl);
             return instance;
         } catch (ClassNotFoundException x) {
             throw new ConfigurationError(
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java
index 9d8e2c7..c3ee8d4 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java
@@ -93,9 +93,11 @@
     protected AttributesImplSerializer m_attributes = new AttributesImplSerializer();
 
     /**
-     * Tells if we're in an EntityRef event.
+     * Tells if we're in an EntityRef event, true if it's greater than 0. Use
+     * integer type to handle nested entity reference, increase m_inEntityRef in
+     * startEntity, decrease m_inEntityRef in endEntity.
      */
-    protected boolean m_inEntityRef = false;
+    protected int m_inEntityRef = 0;
 
     /** This flag is set while receiving events from the external DTD */
     protected boolean m_inExternalDTD = false;
@@ -144,7 +146,7 @@
     /**
      * Amount to indent.
      */
-    protected int m_indentAmount = 0;
+    protected int m_indentAmount = 4;
 
     /**
      * Tells the XML version, for writing out to the XML decl.
@@ -444,13 +446,24 @@
     public void endEntity(String name) throws org.xml.sax.SAXException {
         if (name.equals("[dtd]"))
             m_inExternalDTD = false;
-        m_inEntityRef = false;
+
+        if (!m_inExternalDTD)
+            m_inEntityRef--;
 
         if (m_tracer != null)
             this.fireEndEntity(name);
     }
 
     /**
+     * This method checks if current node is in entity reference.
+     *
+     * @return True if current node is in entity reference.
+     */
+    protected boolean isInEntityRef() {
+        return m_inEntityRef > 0;
+    }
+
+    /**
      * Flush and close the underlying java.io.Writer. This method applies to
      * ToStream serializers, not ToSAXHandler serializers.
      * @see ToStream
@@ -1139,8 +1152,8 @@
         this.m_doctypePublic = null;
         this.m_doctypeSystem = null;
         this.m_doIndent = false;
-        this.m_indentAmount = 0;
-        this.m_inEntityRef = false;
+        this.m_indentAmount = 4;
+        this.m_inEntityRef = 0;
         this.m_inExternalDTD = false;
         this.m_mediatype = null;
         this.m_needToCallStartDocument = true;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java
index f43faee..502a8b8 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java
@@ -1,17 +1,15 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the  "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,23 +17,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: ToHTMLStream.java,v 1.2.4.1 2005/09/15 08:15:26 suresh_emailid Exp $
- */
+
 package com.sun.org.apache.xml.internal.serializer;
 
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Properties;
 
 import javax.xml.transform.Result;
 
-import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
-import com.sun.org.apache.xml.internal.serializer.utils.Utils;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
+import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
+import com.sun.org.apache.xml.internal.serializer.utils.Utils;
+
 /**
  * This serializer takes a series of SAX or
  * SAX-like events and writes its output
@@ -52,9 +47,8 @@
     /** This flag is set while receiving events from the DTD */
     protected boolean m_inDTD = false;
 
-    /** True if the current element is a block element.  (seems like
-     *  this needs to be a stack. -sb). */
-    private boolean m_inBlockElem = false;
+    /** True if the previous element is a block element. */
+    private boolean m_isprevblock = false;
 
     /**
      * Map that tells which XML characters should have special treatment, and it
@@ -723,7 +717,7 @@
      */
     public final void endDocument() throws org.xml.sax.SAXException
     {
-
+        flushCharactersBuffer();
         flushPending();
         if (m_doIndent && !m_isprevtext)
         {
@@ -743,26 +737,48 @@
     }
 
     /**
-     *  Receive notification of the beginning of an element.
+     * If the previous is an inline element, won't insert a new line before the
+     * text.
+     *
+     */
+    protected boolean shouldIndentForText() {
+        return super.shouldIndentForText() && m_isprevblock;
+    }
+
+    /**
+     * Only check m_doIndent, disregard m_ispreserveSpace.
+     *
+     * @return True if the content should be formatted.
+     */
+    protected boolean shouldFormatOutput() {
+        return m_doIndent;
+    }
+
+    /**
+     * Receive notification of the beginning of an element.
      *
      *
-     *  @param namespaceURI
-     *  @param localName
-     *  @param name The element type name.
-     *  @param atts The attributes attached to the element, if any.
-     *  @throws org.xml.sax.SAXException Any SAX exception, possibly
-     *             wrapping another exception.
-     *  @see #endElement
-     *  @see org.xml.sax.AttributeList
+     * @param namespaceURI
+     * @param localName
+     * @param name
+     *            The element type name.
+     * @param atts
+     *            The attributes attached to the element, if any.
+     * @throws org.xml.sax.SAXException
+     *             Any SAX exception, possibly wrapping another exception.
+     * @see #endElement
+     * @see org.xml.sax.AttributeList
      */
     public void startElement(
         String namespaceURI,
         String localName,
         String name,
         Attributes atts)
-        throws org.xml.sax.SAXException
+        throws SAXException
     {
-
+        // will add extra one if having namespace but no matter
+        m_childNodeNum++;
+        flushCharactersBuffer();
         ElemContext elemContext = m_elemContext;
 
         // clean up any pending things first
@@ -800,22 +816,18 @@
             // deal with indentation issues first
             if (m_doIndent)
             {
-
                 boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
-                if (m_ispreserve)
-                    m_ispreserve = false;
-                else if (
-                    (null != elemContext.m_elementName)
-                    && (!m_inBlockElem
-                        || isBlockElement) /* && !isWhiteSpaceSensitive */
-                    )
+                if ((elemContext.m_elementName != null)
+                        // If this element is a block element,
+                        // or if this is not a block element, then if the
+                        // previous is neither a text nor an inline
+                        && (isBlockElement || (!(m_isprevtext || !m_isprevblock))))
                 {
                     m_startNewLine = true;
 
                     indent();
-
                 }
-                m_inBlockElem = !isBlockElement;
+                m_isprevblock = isBlockElement;
             }
 
             // save any attributes for later processing
@@ -827,7 +839,8 @@
             writer.write('<');
             writer.write(name);
 
-
+            m_childNodeNumStack.push(m_childNodeNum);
+            m_childNodeNum = 0;
 
             if (m_tracer != null)
                 firePseudoAttributes();
@@ -850,6 +863,15 @@
                 m_elemContext = elemContext;
                 elemContext.m_elementDesc = elemDesc;
                 elemContext.m_isRaw = (elemFlags & ElemDesc.RAW) != 0;
+
+                // set m_startNewLine for the next element
+                if (m_doIndent) {
+                    // elemFlags is equivalent to m_elemContext.m_elementDesc.getFlags(),
+                    // in this branch m_elemContext.m_elementName is not null
+                    boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
+                    if (isBlockElement)
+                        m_startNewLine = true;
+                }
             }
 
 
@@ -893,6 +915,7 @@
         final String name)
         throws org.xml.sax.SAXException
     {
+        flushCharactersBuffer();
         // deal with any pending issues
         if (m_cdataTagOpen)
             closeCDATA();
@@ -919,18 +942,18 @@
                 final boolean isBlockElement = (elemFlags&ElemDesc.BLOCK) != 0;
                 boolean shouldIndent = false;
 
-                if (m_ispreserve)
-                {
-                    m_ispreserve = false;
-                }
-                else if (m_doIndent && (!m_inBlockElem || isBlockElement))
+                // If this element is a block element,
+                // or if this is not a block element, then if the previous is
+                // neither a text nor an inline
+                if (isBlockElement || (!(m_isprevtext || !m_isprevblock)))
                 {
                     m_startNewLine = true;
                     shouldIndent = true;
                 }
-                if (!elemContext.m_startTagOpen && shouldIndent)
+                if (!elemContext.m_startTagOpen && shouldIndent && (m_childNodeNum > 1 || !m_isprevtext))
                     indent(elemContext.m_currentElemDepth - 1);
-                m_inBlockElem = !isBlockElement;
+
+                m_isprevblock = isBlockElement;
             }
 
             final java.io.Writer writer = m_writer;
@@ -974,6 +997,7 @@
                 }
             }
 
+            m_childNodeNum = m_childNodeNumStack.pop();
             // clean up because the element has ended
             if ((elemFlags & ElemDesc.WHITESPACESENSITIVE) != 0)
                 m_ispreserve = true;
@@ -1511,7 +1535,7 @@
                 // writer.write("<![CDATA[");
                 // writer.write(chars, start, length);
                 writeNormalizedChars(chars, start, length, false, m_lineSepUse);
-
+                m_isprevtext = true;
                 // writer.write("]]>");
 
                 // time to generate characters event
@@ -1566,7 +1590,6 @@
     public final void cdata(char ch[], int start, int length)
         throws org.xml.sax.SAXException
     {
-
         if ((null != m_elemContext.m_elementName)
             && (m_elemContext.m_elementName.equalsIgnoreCase("SCRIPT")
                 || m_elemContext.m_elementName.equalsIgnoreCase("STYLE")))
@@ -1617,7 +1640,8 @@
     public void processingInstruction(String target, String data)
         throws org.xml.sax.SAXException
     {
-
+        m_childNodeNum++;
+        flushCharactersBuffer();
         // Process any pending starDocument and startElement first.
         flushPending();
 
@@ -1945,10 +1969,8 @@
 
     private void initToHTMLStream()
     {
-//        m_elementDesc = null;
-        m_inBlockElem = false;
+        m_isprevblock = false;
         m_inDTD = false;
-//        m_isRawStack.clear();
         m_omitMetaTag = false;
         m_specialEscapeURLs = true;
     }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java
index 976b495..994a780 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java
@@ -29,12 +29,16 @@
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.EmptyStackException;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.Properties;
+import java.util.Queue;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.ArrayList;
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
@@ -89,6 +93,29 @@
     Object m_charToByteConverter = null;
 
     /**
+     * Used to buffer the text nodes and the entity reference nodes if
+     * indentation is on.
+     */
+    protected CharacterBuffer m_charactersBuffer = new CharacterBuffer();
+
+    /**
+     * Used to decide if a text node is pretty-printed with indentation.
+     * If m_childNodeNum > 1, the text node will be indented.
+     *
+     */
+    protected Deque<Integer> m_childNodeNumStack = new ArrayDeque<>();
+
+    protected int m_childNodeNum = 0;
+
+    /**
+     * Used to handle xml:space attribute
+     *
+     */
+    protected BoolStack m_preserveSpaces = new BoolStack();
+
+    protected boolean m_ispreserveSpace = false;
+
+    /**
      * Stack to keep track of whether or not we need to
      * preserve whitespace.
      *
@@ -767,12 +794,10 @@
 
         if (m_startNewLine)
             outputLineSep();
-        /* For m_indentAmount > 0 this extra test might be slower
-         * but Xalan's default value is 0, so this extra test
-         * will run faster in that situation.
+        /*
+         * Default value is 4, so printSpace directly.
          */
-        if (m_indentAmount > 0)
-            printSpace(depth * m_indentAmount);
+        printSpace(depth * m_indentAmount);
 
     }
 
@@ -1234,7 +1259,6 @@
     protected void cdata(char ch[], int start, final int length)
         throws org.xml.sax.SAXException
     {
-
         try
         {
             final int old_start = start;
@@ -1323,7 +1347,7 @@
         throws org.xml.sax.SAXException
     {
 
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
         try
         {
@@ -1378,9 +1402,11 @@
         // characters to read from array is 0.
         // Section 7.6.1 of XSLT 1.0 (http://www.w3.org/TR/xslt#value-of) suggest no text node
         // is created if string is empty.
-        if (length == 0 || (m_inEntityRef && !m_expandDTDEntities))
+        if (length == 0 || (isInEntityRef()))
             return;
-        if (m_elemContext.m_startTagOpen)
+
+        final boolean shouldFormat = shouldFormatOutput();
+        if (m_elemContext.m_startTagOpen && !shouldFormat)
         {
             closeStartTag();
             m_elemContext.m_startTagOpen = false;
@@ -1407,7 +1433,7 @@
         if (m_disableOutputEscapingStates.peekOrFalse() || (!m_escaping))
         {
             charactersRaw(chars, start, length);
-
+            m_isprevtext = true;
             // time to fire off characters generation event
             if (m_tracer != null)
                 super.fireCharEvent(chars, start, length);
@@ -1415,13 +1441,41 @@
             return;
         }
 
-        if (m_elemContext.m_startTagOpen)
+        if (m_elemContext.m_startTagOpen && !shouldFormat)
         {
             closeStartTag();
             m_elemContext.m_startTagOpen = false;
         }
 
+        if (shouldFormat) {
+            m_charactersBuffer.addText(chars, start, length);
+        } else {
+            outputCharacters(chars, start, length);
+        }
 
+        // time to fire off characters generation event
+        if (m_tracer != null)
+            super.fireCharEvent(chars, start, length);
+    }
+
+
+    /**
+     * This method checks if the content in current element should be formatted.
+     *
+     * @return True if the content should be formatted.
+     */
+    protected boolean shouldFormatOutput() {
+        return !m_ispreserveSpace && m_doIndent;
+    }
+
+    /**
+     * Write out the characters.
+     *
+     * @param chars The characters of the text.
+     * @param start The start position in the char array.
+     * @param length The number of characters from the char array.
+     */
+    private void outputCharacters(final char chars[], final int start, final int length) throws SAXException {
         try
         {
             int i;
@@ -1459,8 +1513,8 @@
                 m_ispreserve = true;
 
 
-//            int lengthClean;    // number of clean characters in a row
-//            final boolean[] isAsciiClean = m_charInfo.getASCIIClean();
+//          int lengthClean;    // number of clean characters in a row
+//          final boolean[] isAsciiClean = m_charInfo.getASCIIClean();
 
             final boolean isXML10 = XMLVERSION10.equals(getVersion());
             // we've skipped the leading whitespace, now deal with the rest
@@ -1514,11 +1568,54 @@
         {
             throw new SAXException(e);
         }
-
-        // time to fire off characters generation event
-        if (m_tracer != null)
-            super.fireCharEvent(chars, start, length);
     }
+
+    /**
+     * Used to flush the buffered characters when indentation is on, this method
+     * will be called when the next node is traversed.
+     *
+     */
+    final protected void flushCharactersBuffer() throws SAXException {
+        try {
+            if (shouldFormatOutput() && m_charactersBuffer.hasContent()) {
+                if (m_elemContext.m_startTagOpen) {
+                    closeStartTag();
+                    m_elemContext.m_startTagOpen = false;
+                }
+
+                if (m_elemContext.m_isCdataSection) {
+                    /*
+                     * due to cdata-section-elements atribute, we need this as
+                     * cdata
+                     */
+                    char[] chars = m_charactersBuffer.toChars();
+                    cdata(chars, 0, chars.length);
+                    return;
+                }
+
+                m_childNodeNum++;
+                if (shouldIndentForText()) {
+                    indent();
+                    m_startNewLine = true;
+                }
+                m_charactersBuffer.flush();
+            }
+        } catch (IOException e) {
+            throw new SAXException(e);
+        } finally {
+            m_charactersBuffer.clear();
+        }
+    }
+
+    /**
+     * True if should indent in flushCharactersBuffer method.
+     * This method may be overridden in sub-class.
+     *
+     */
+    protected boolean shouldIndentForText() {
+        return (shouldIndent() && m_childNodeNum > 1);
+    }
+
     /**
      * This method checks if a given character is between C0 or C1 range
      * of Control characters.
@@ -1610,7 +1707,7 @@
      */
     public void characters(String s) throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef && !m_expandDTDEntities)
+        if (isInEntityRef())
             return;
         final int length = s.length();
         if (length > m_charsBuff.length)
@@ -1758,9 +1855,12 @@
         Attributes atts)
         throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        m_childNodeNum++;
+        flushCharactersBuffer();
+
         if (m_needToCallStartDocument)
         {
             startDocumentInternal();
@@ -1812,6 +1912,12 @@
         if (atts != null)
             addAttributes(atts);
 
+        m_ispreserveSpace = m_preserveSpaces.peekOrFalse();
+        m_preserveSpaces.push(m_ispreserveSpace);
+
+        m_childNodeNumStack.push(m_childNodeNum);
+        m_childNodeNum = 0;
+
         m_elemContext = m_elemContext.push(namespaceURI,localName,name);
         m_isprevtext = false;
 
@@ -2019,9 +2125,10 @@
         throws org.xml.sax.SAXException
     {
 
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        flushCharactersBuffer();
         // namespaces declared at the current depth are no longer valid
         // so get rid of them
         m_prefixMap.popNamespaces(m_elemContext.m_currentElemDepth, null);
@@ -2055,7 +2162,7 @@
                 if (m_cdataTagOpen)
                     closeCDATA();
 
-                if (shouldIndent())
+                if (shouldIndent() && (m_childNodeNum > 1 || !m_isprevtext))
                     indent(m_elemContext.m_currentElemDepth - 1);
                 writer.write('<');
                 writer.write('/');
@@ -2073,6 +2180,9 @@
             m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
         }
 
+        m_ispreserveSpace = m_preserveSpaces.popAndTop();
+        m_childNodeNum = m_childNodeNumStack.pop();
+
         m_isprevtext = false;
 
         // fire off the end element event
@@ -2208,8 +2318,10 @@
     {
 
         int start_old = start;
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
+        m_childNodeNum++;
+        flushCharactersBuffer();
         if (m_elemContext.m_startTagOpen)
         {
             closeStartTag();
@@ -2389,6 +2501,9 @@
      */
     public void startCDATA() throws org.xml.sax.SAXException
     {
+        m_childNodeNum++;
+        flushCharactersBuffer();
+
         m_cdataStartCalled = true;
     }
 
@@ -2412,17 +2527,30 @@
         if (name.equals("[dtd]"))
             m_inExternalDTD = true;
 
-        if (!m_expandDTDEntities && !m_inExternalDTD) {
-            /* Only leave the entity as-is if
-             * we've been told not to expand them
-             * and this is not the magic [dtd] name.
-             */
-            startNonEscaping();
-            characters("&" + name + ';');
-            endNonEscaping();
+        // if this is not the magic [dtd] name
+        if (!m_inExternalDTD) {
+            // if it's not in nested entity reference
+            if (!isInEntityRef()) {
+                if (shouldFormatOutput()) {
+                    m_charactersBuffer.addEntityReference(name);
+                } else {
+                    outputEntityReference(name);
+                }
+            }
+            m_inEntityRef++;
         }
+    }
 
-        m_inEntityRef = true;
+    /**
+     * Write out the entity reference with the form as "&amp;entityName;".
+     *
+     * @param name The name of the entity.
+     */
+    private void outputEntityReference(String name) throws SAXException {
+        startNonEscaping();
+        characters("&" + name + ';');
+        endNonEscaping();
+        m_isprevtext = true;
     }
 
     /**
@@ -2523,7 +2651,7 @@
      */
     protected boolean shouldIndent()
     {
-        return m_doIndent && (!m_ispreserve && !m_isprevtext) && (m_elemContext.m_currentElemDepth > 0 || m_isStandalone);
+        return shouldFormatOutput() && (m_elemContext.m_currentElemDepth > 0 || m_isStandalone);
     }
 
     /**
@@ -2815,10 +2943,37 @@
         String value,
         boolean xslAttribute)
     {
+        if (m_charactersBuffer.isAnyCharactersBuffered()) {
+            /*
+             * If stylesheet includes xsl:copy-of an attribute node, XSLTC will
+             * fire an addAttribute event. When a text node is handling in
+             * ToStream, addAttribute has no effect. But closeStartTag call is
+             * delayed to flushCharactersBuffer() method if the text node is
+             * buffered, so here we ignore the attribute to avoid corrupting the
+             * start tag content.
+             *
+             */
+            return m_attributes.getIndex(rawName) < 0;
+        } else {
+            return doAddAttributeAlways(uri, localName, rawName, type, value, xslAttribute);
+        }
+    }
+
+    /**
+     * Does really add the attribute to the set of attributes.
+     */
+    private boolean doAddAttributeAlways(
+        String uri,
+        String localName,
+        String rawName,
+        String type,
+        String value,
+        boolean xslAttribute)
+    {
         boolean was_added;
         int index;
         //if (uri == null || localName == null || uri.length() == 0)
-            index = m_attributes.getIndex(rawName);
+        index = m_attributes.getIndex(rawName);
         // Don't use 'localName' as it gives incorrect value, rely only on 'rawName'
         /*else {
             index = m_attributes.getIndex(uri, localName);
@@ -2923,12 +3078,26 @@
                     e.printStackTrace();
                 }
             }
+
             m_attributes.addAttribute(uri, localName, rawName, type, value);
             was_added = true;
             if (m_tracer != null){
                 firePseudoAttributes();
             }
         }
+
+        if (rawName.equals("xml:space")) {
+            if (value.equals("preserve")) {
+                m_ispreserveSpace = true;
+                if (m_preserveSpaces.size() > 0)
+                    m_preserveSpaces.setTop(m_ispreserveSpace);
+            } else if (value.equals("default")) {
+                m_ispreserveSpace = false;
+                if (m_preserveSpaces.size() > 0)
+                    m_preserveSpaces.setTop(m_ispreserveSpace);
+            }
+        }
+
         return was_added;
     }
 
@@ -3059,10 +3228,14 @@
          // this.m_format = null;
          this.m_inDoctype = false;
          this.m_ispreserve = false;
-         this.m_ispreserve = false;
+         this.m_preserves.clear();
+         this.m_ispreserveSpace = false;
+         this.m_preserveSpaces.clear();
+         this.m_childNodeNum = 0;
+         this.m_childNodeNumStack.clear();
+         this.m_charactersBuffer.clear();
          this.m_isprevtext = false;
          this.m_isUTF8 = false; //  ?? used anywhere ??
-         this.m_preserves.clear();
          this.m_shouldFlush = true;
          this.m_spaceBeforeClose = false;
          this.m_startNewLine = false;
@@ -3238,6 +3411,129 @@
         }
     }
 
+    /**
+     * This inner class is used to buffer the text nodes and the entity
+     * reference nodes if indentation is on. There is only one CharacterBuffer
+     * instance in ToStream, it contains a queue of GenericCharacters,
+     * GenericCharacters can be a text node or an entity reference node. The
+     * text nodes and entity reference nodes are joined together and then are
+     * flushed.
+     */
+    private class CharacterBuffer {
+        /**
+         * GenericCharacters is immutable.
+         */
+        private abstract class GenericCharacters {
+            /**
+             * @return True if having any character other than whitespace or
+             *         line feed.
+             */
+            abstract boolean hasContent();
+
+            abstract void flush() throws SAXException;
+
+            /**
+             * Converts this GenericCharacters to a new character array.
+             */
+            abstract char[] toChars();
+        }
+
+        private Queue<GenericCharacters> bufferedCharacters = new ArrayDeque<>();
+
+        /**
+         * Append a text node to the buffer.
+         */
+        public void addText(final char chars[], final int start, final int length) {
+            bufferedCharacters.add(new GenericCharacters() {
+                char[] text;
+
+                {
+                    text = Arrays.copyOfRange(chars, start, start + length);
+                }
+
+                boolean hasContent() {
+                    for (int i = 0; i < text.length; i++) {
+                        if (!isWhiteSpace(text[i])) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+                void flush() throws SAXException {
+                    outputCharacters(text, 0, text.length);
+                }
+
+                char[] toChars() {
+                    return text;
+                }
+
+                boolean isWhiteSpace(char ch) {
+                    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+                }
+
+            });
+        }
+
+        /**
+         * Append an entity reference to the buffer.
+         */
+        public void addEntityReference(String entityName) {
+            bufferedCharacters.add(new GenericCharacters() {
+                boolean hasContent() {
+                    return true;
+                }
+
+                void flush() throws SAXException {
+                    outputEntityReference(entityName);
+                }
+
+                char[] toChars() {
+                    return ("&" + entityName + ";").toCharArray();
+                }
+            });
+        }
+
+        /**
+         * @return True if any GenericCharacters is already buffered.
+         */
+        public boolean isAnyCharactersBuffered() {
+            return !bufferedCharacters.isEmpty();
+        }
+
+        /**
+         * @return True if any buffered GenericCharacters has content.
+         */
+        public boolean hasContent() {
+            return bufferedCharacters.stream().anyMatch(GenericCharacters::hasContent);
+        }
+
+        /**
+         * Flush all buffered GenericCharacters.
+         */
+        public void flush() throws SAXException {
+            GenericCharacters element;
+            while ((element = bufferedCharacters.poll()) != null)
+                element.flush();
+        }
+
+        /**
+         * Converts all buffered GenericCharacters to a new character array.
+         */
+        public char[] toChars() {
+            return bufferedCharacters.stream().map(GenericCharacters::toChars)
+                    .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString()
+                    .toCharArray();
+        }
+
+        /**
+         * Clear the buffer.
+         */
+        public void clear() {
+            bufferedCharacters.clear();
+        }
+    }
+
     // Implement DTDHandler
     /**
      * If this method is called, the serializer is used as a
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java
index 00463bc..681737e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java
@@ -1,15 +1,15 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * Copyright 2001-2004 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,9 +17,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: ToXMLStream.java,v 1.2.4.2 2005/09/15 12:01:25 suresh_emailid Exp $
- */
+
  package com.sun.org.apache.xml.internal.serializer;
 
 import java.io.IOException;
@@ -92,6 +90,12 @@
 
         m_ispreserve = xmlListener.m_ispreserve;
         m_preserves = xmlListener.m_preserves;
+        m_ispreserveSpace = xmlListener.m_ispreserveSpace;
+        m_preserveSpaces = xmlListener.m_preserveSpaces;
+        m_childNodeNum = xmlListener.m_childNodeNum;
+        m_childNodeNumStack = xmlListener.m_childNodeNumStack;
+        m_charactersBuffer = xmlListener.m_charactersBuffer;
+        m_inEntityRef = xmlListener.m_inEntityRef;
         m_isprevtext = xmlListener.m_isprevtext;
         m_doIndent = xmlListener.m_doIndent;
         setIndentAmount(xmlListener.getIndentAmount());
@@ -124,7 +128,7 @@
             super.startDocumentInternal();
             m_needToCallStartDocument = false;
 
-            if (m_inEntityRef)
+            if (isInEntityRef())
                 return;
 
             m_needToOutputDocTypeDecl = true;
@@ -197,6 +201,7 @@
      */
     public void endDocument() throws org.xml.sax.SAXException
     {
+        flushCharactersBuffer();
         flushPending();
         if (m_doIndent && !m_isprevtext)
         {
@@ -265,9 +270,11 @@
     public void processingInstruction(String target, String data)
         throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        m_childNodeNum++;
+        flushCharactersBuffer();
         flushPending();
 
         if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java
index f44ca26..68864ca 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -368,8 +368,6 @@
     private final void dispatachChars(Node node)
         throws org.xml.sax.SAXException {
         if (fSerializer != null) {
-            this.fSerializer.characters(node);
-        } else {
             String data = ((Text) node).getData();
             this.fSerializer.characters(data.toCharArray(), 0, data.length());
         }
@@ -1066,7 +1064,9 @@
                 // should we pass entity reference nodes to the filter???
             }
 
-            if (fLexicalHandler != null) {
+            // if "entities" is true, or EntityReference node has no children,
+            // it will be serialized as the form "&entityName;" in the output.
+            if (fLexicalHandler != null && ((fFeatures & ENTITIES) != 0 || !node.hasChildNodes())) {
 
                 // startEntity outputs only Text but not Element, Attr, Comment
                 // and PI child nodes.  It does so by setting the m_inEntityRef
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties
index ff16c65..5230e5e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties
@@ -1,11 +1,12 @@
 ###########################################################################
-# reserved comment block
-# DO NOT REMOVE OR ALTER!
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 ###########################################################################
-###########################################################################
-# Copyright 2003-2004 The Apache Software Foundation.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
+##
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the  "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
@@ -16,11 +17,9 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-##########################################################################
+##
 #
-# $Id: output_html.properties,v 1.2.4.1 2005/09/15 08:15:32 suresh_emailid Exp $
-#
-# Specify defaults when method="html".  These defaults use output_xml.properties 
+# Specify defaults when method="html".  These defaults use output_xml.properties
 # as a base.
 #
 
@@ -39,7 +38,7 @@
 #              xalan:content-handler="MyContentHandler"/>
 #  ...
 # Note that the colon after the protocol needs to be escaped.
-{http\u003a//xml.apache.org/xalan}indent-amount=0
+{http\u003a//xml.apache.org/xalan}indent-amount=4
 {http\u003a//xml.apache.org/xalan}content-handler=com.sun.org.apache.xml.internal.serializer.ToHTMLStream
 {http\u003a//xml.apache.org/xalan}entities=com/sun/org/apache/xml/internal/serializer/HTMLEntities
 {http\u003a//xml.apache.org/xalan}use-url-escaping=yes
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEntityStorage.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEntityStorage.java
index 6252f22..5462e2a 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEntityStorage.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEntityStorage.java
@@ -35,8 +35,6 @@
 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
-import java.util.Collections;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -142,16 +140,8 @@
         return fEntities.get(name);
     } // getEntity(String)
 
-    public boolean hasEntities() {
-            return (fEntities!=null);
-    } // getEntity(String)
-
-    public int getEntitySize() {
-        return fEntities.size();
-    } // getEntity(String)
-
-    public Enumeration getEntityKeys() {
-        return Collections.enumeration(fEntities.keySet());
+    public Map<String, Entity> getEntities() {
+        return fEntities;
     }
     /**
      * Adds an internal entity declaration.
@@ -310,9 +300,9 @@
 
         fCurrentEntity = fEntityManager.getCurrentEntity();
         if (!fEntities.containsKey(name)) {
-            Entity entity = new Entity.ExternalEntity(name, new XMLResourceIdentifierImpl(publicId, systemId, baseSystemId, null), notation, fInExternalSubset);
-            //                  (fCurrentEntity == null) ? fasle : fCurrentEntity.isEntityDeclInExternalSubset());
-            //                  fCurrentEntity.isEntityDeclInExternalSubset());
+            Entity entity = new Entity.ExternalEntity(name,
+                    new XMLResourceIdentifierImpl(publicId, systemId, baseSystemId, null),
+                    notation, fInExternalSubset);
             fEntities.put(name, entity);
         }
         else{
@@ -438,7 +428,7 @@
         userDir = userDir.replace(separator, '/');
 
         int len = userDir.length(), ch;
-        StringBuffer buffer = new StringBuffer(len*3);
+        StringBuilder buffer = new StringBuilder(len*3);
         // change C:/blah to /C:/blah
         if (len >= 2 && userDir.charAt(1) == ':') {
             ch = Character.toUpperCase(userDir.charAt(0));
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/DTDGrammarUtil.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/DTDGrammarUtil.java
index b1331b5..566b5c0 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/DTDGrammarUtil.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/DTDGrammarUtil.java
@@ -1,15 +1,16 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
- * Copyright 2005 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,8 +25,6 @@
 import com.sun.xml.internal.stream.dtd.nonvalidating.XMLElementDecl;
 import com.sun.xml.internal.stream.dtd.nonvalidating.XMLSimpleType;
 import com.sun.org.apache.xerces.internal.impl.Constants;
-import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
-import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
 import com.sun.org.apache.xerces.internal.util.XMLChar;
 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
@@ -33,13 +32,10 @@
 import com.sun.org.apache.xerces.internal.xni.QName;
 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
-import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
-import com.sun.org.apache.xerces.internal.xni.XMLLocator;
 import com.sun.org.apache.xerces.internal.xni.XMLString;
 import com.sun.org.apache.xerces.internal.xni.XNIException;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
-import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
 import javax.xml.XMLConstants;
 
  /*
@@ -96,7 +92,7 @@
     private QName fTempQName = new QName();
 
     /** Temporary string buffers. */
-    private StringBuffer fBuffer = new StringBuffer();
+    private StringBuilder fBuffer = new StringBuilder();
 
     private NamespaceContext fNamespaceContext = null;
 
@@ -396,7 +392,7 @@
                     XMLSymbols.fENTITYSymbol;
             }
             case XMLSimpleType.TYPE_ENUMERATION: {
-                StringBuffer buffer = new StringBuffer();
+                StringBuilder buffer = new StringBuilder();
                 buffer.append('(');
                 for (int i = 0; i < attrDecl.simpleType.enumeration.length; i++) {
                     if (i > 0) {
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/DTDGrammar.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/DTDGrammar.java
index 2cef9fa..fdd45ef 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/DTDGrammar.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/DTDGrammar.java
@@ -1,15 +1,16 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
- * Copyright 2005 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -34,7 +35,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
 
 /**
  * A DTD grammar. This class implements the XNI handler interfaces
@@ -95,8 +95,8 @@
     protected boolean fReadingExternalDTD = false;
 
     /** Symbol table. */
-    private SymbolTable fSymbolTable;
-    private ArrayList notationDecls = new ArrayList();
+    private final SymbolTable fSymbolTable;
+    private final ArrayList<XMLNotationDecl> notationDecls = new ArrayList<>();
 
     // element declarations
 
@@ -334,18 +334,19 @@
         fSimpleType.clear();
         if ( defaultType != null ) {
             if ( defaultType.equals( "#FIXED") ) {
-                fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_FIXED;
+                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_FIXED;
             } else if ( defaultType.equals( "#IMPLIED") ) {
-                fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_IMPLIED;
+                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
             } else if ( defaultType.equals( "#REQUIRED") ) {
-                fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_REQUIRED;
+                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_REQUIRED;
             }
         }
         if ( DEBUG ) {
             System.out.println("defaultvalue = " + defaultValue.toString() );
         }
-        fSimpleType.defaultValue      = defaultValue!=null ?  defaultValue.toString() : null;
-        fSimpleType.nonNormalizedDefaultValue      = nonNormalizedDefaultValue!=null ?  nonNormalizedDefaultValue.toString() : null;
+        fSimpleType.defaultValue = defaultValue!=null ? defaultValue.toString() : null;
+        fSimpleType.nonNormalizedDefaultValue = nonNormalizedDefaultValue!=null ?
+                nonNormalizedDefaultValue.toString() : null;
         fSimpleType.enumeration       = enumeration;
 
         if (type.equals("CDATA")) {
@@ -731,7 +732,7 @@
         notationDecls.add(notationDecl);
     }
 
-    public List getNotationDecls(){
+    public List<XMLNotationDecl> getNotationDecls() {
         return notationDecls;
     }
 
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLAttributeDecl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLAttributeDecl.java
index b3e8f5a..faeafdd 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLAttributeDecl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLAttributeDecl.java
@@ -3,13 +3,14 @@
  */
 
 /*
- * Copyright 2005 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLElementDecl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLElementDecl.java
index d0d950f..8673159 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLElementDecl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLElementDecl.java
@@ -3,13 +3,14 @@
  */
 
 /*
- * Copyright 2005 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLNotationDecl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLNotationDecl.java
index a164583..ab68f50 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLNotationDecl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/dtd/nonvalidating/XMLNotationDecl.java
@@ -3,13 +3,14 @@
  */
 
 /*
- * Copyright 2005 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/DTDEvent.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/DTDEvent.java
index 9b81520..425c431 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/DTDEvent.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/DTDEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,80 +25,88 @@
 
 package com.sun.xml.internal.stream.events;
 
+import java.util.List;
 import javax.xml.stream.events.DTD;
+import javax.xml.stream.events.EntityDeclaration;
+import javax.xml.stream.events.NotationDeclaration;
 import javax.xml.stream.events.XMLEvent;
 
 /**
  *
- * @author  Neeraj Bajaj, Sun Microsystesm.
+ * @author Neeraj Bajaj, Sun Microsystesm.
  *
  */
-public class DTDEvent extends DummyEvent implements DTD{
+public class DTDEvent extends DummyEvent implements DTD {
 
     private String fDoctypeDeclaration;
-    private java.util.List fNotations;
-    private java.util.List fEntities;
+    private List<NotationDeclaration> fNotations;
+    private List<EntityDeclaration> fEntities;
 
-    /** Creates a new instance of DTDEvent */
+    /**
+     * Creates a new instance of DTDEvent
+     */
     public DTDEvent() {
         init();
     }
 
-    public DTDEvent(String doctypeDeclaration){
+    public DTDEvent(String doctypeDeclaration) {
         init();
         fDoctypeDeclaration = doctypeDeclaration;
     }
 
-    public void setDocumentTypeDeclaration(String doctypeDeclaration){
+    public void setDocumentTypeDeclaration(String doctypeDeclaration) {
         fDoctypeDeclaration = doctypeDeclaration;
     }
 
+    @Override
     public String getDocumentTypeDeclaration() {
         return fDoctypeDeclaration;
     }
 
     //xxx: we can change the signature if the implementation doesn't store the entities in List Datatype.
     //and then convert that DT to list format here. That way callee dont need to bother about conversion
-
-    public void setEntities(java.util.List entites){
+    public void setEntities(List<EntityDeclaration> entites) {
         fEntities = entites;
     }
 
-    public java.util.List getEntities() {
+    @Override
+    public List<EntityDeclaration> getEntities() {
         return fEntities;
     }
 
     //xxx: we can change the signature if the implementation doesn't store the entities in List Datatype.
     //and then convert that DT to list format here. That way callee dont need to bother about conversion
-
-    public void setNotations(java.util.List notations){
+    public void setNotations(List<NotationDeclaration> notations) {
         fNotations = notations;
     }
 
-    public java.util.List getNotations() {
+    @Override
+    public List<NotationDeclaration> getNotations() {
         return fNotations;
     }
 
     /**
-     *Returns an implementation defined representation of the DTD.
-     * This method may return null if no representation is available.
+     * Returns an implementation defined representation of the DTD. This method
+     * may return null if no representation is available.
      *
      */
+    @Override
     public Object getProcessedDTD() {
         return null;
     }
 
-    protected void init(){
+    protected final void init() {
         setEventType(XMLEvent.DTD);
     }
 
-    public String toString(){
-        return fDoctypeDeclaration ;
+    @Override
+    public String toString() {
+        return fDoctypeDeclaration;
     }
 
+    @Override
     protected void writeAsEncodedUnicodeEx(java.io.Writer writer)
-    throws java.io.IOException
-    {
+            throws java.io.IOException {
         writer.write(fDoctypeDeclaration);
     }
 }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/EndElementEvent.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/EndElementEvent.java
index c441d42..e57a365 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/EndElementEvent.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/EndElementEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,8 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
-package com.sun.xml.internal.stream.events ;
+package com.sun.xml.internal.stream.events;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -31,35 +30,33 @@
 import javax.xml.namespace.QName;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.Namespace;
-import java.io.Writer;
 import java.util.Iterator;
 import javax.xml.stream.events.XMLEvent;
 import com.sun.xml.internal.stream.util.ReadOnlyIterator;
 
-/** Implementation of EndElement event.
+/**
+ * Implementation of EndElement event.
  *
  * @author Neeraj Bajaj Sun Microsystems,Inc.
  * @author K.Venugopal Sun Microsystems,Inc.
  */
-
 public class EndElementEvent extends DummyEvent
-implements EndElement {
+        implements EndElement {
 
-    List fNamespaces = null;
-    QName fQName ;
+    List<Namespace> fNamespaces = null;
+    QName fQName;
 
     public EndElementEvent() {
         init();
     }
 
-    protected void init() {
+    protected final void init() {
         setEventType(XMLEvent.END_ELEMENT);
-        fNamespaces = new ArrayList();
+        fNamespaces = new ArrayList<>();
     }
 
-
-    public EndElementEvent(String prefix,  String uri, String localpart) {
-        this(new QName(uri,localpart,prefix));
+    public EndElementEvent(String prefix, String uri, String localpart) {
+        this(new QName(uri, localpart, prefix));
     }
 
     public EndElementEvent(QName qname) {
@@ -67,6 +64,7 @@
         init();
     }
 
+    @Override
     public QName getName() {
         return fQName;
     }
@@ -75,34 +73,36 @@
         this.fQName = qname;
     }
 
+    @Override
     protected void writeAsEncodedUnicodeEx(java.io.Writer writer)
-    throws java.io.IOException
-    {
+            throws java.io.IOException {
         writer.write("</");
         String prefix = fQName.getPrefix();
         if (prefix != null && prefix.length() > 0) {
             writer.write(prefix);
             writer.write(':');
-     }
+        }
         writer.write(fQName.getLocalPart());
         writer.write('>');
     }
 
-    /** Returns an Iterator of namespaces that have gone out
-     * of scope.  Returns an empty iterator if no namespaces have gone
-     * out of scope.
-     * @return an Iterator over Namespace interfaces, or an
-     * empty iterator
+    /**
+     * Returns an Iterator of namespaces that have gone out of scope. Returns an
+     * empty iterator if no namespaces have gone out of scope.
+     *
+     * @return an Iterator over Namespace interfaces, or an empty iterator
      */
-    public Iterator getNamespaces() {
-        if(fNamespaces != null)
+    @Override
+    public Iterator<Namespace> getNamespaces() {
+        if (fNamespaces != null) {
             fNamespaces.iterator();
-        return new ReadOnlyIterator();
+        }
+        return new ReadOnlyIterator<>();
     }
 
-    void addNamespace(Namespace attr){
-        if(attr != null){
-            fNamespaces.add(attr);
+    void addNamespace(Namespace ns) {
+        if (ns != null) {
+            fNamespaces.add(ns);
         }
     }
 
@@ -113,12 +113,15 @@
     }
 
     public String nameAsString() {
-        if("".equals(fQName.getNamespaceURI()))
+        if ("".equals(fQName.getNamespaceURI())) {
             return fQName.getLocalPart();
-        if(fQName.getPrefix() != null)
+        }
+
+        if (fQName.getPrefix() != null) {
             return "['" + fQName.getNamespaceURI() + "']:" + fQName.getPrefix() + ":" + fQName.getLocalPart();
-        else
+        } else {
             return "['" + fQName.getNamespaceURI() + "']:" + fQName.getLocalPart();
+        }
     }
 
 }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/StartElementEvent.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/StartElementEvent.java
index 71f6989..577385f 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/StartElementEvent.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/StartElementEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,35 +23,33 @@
  * questions.
  */
 
-package com.sun.xml.internal.stream.events ;
+package com.sun.xml.internal.stream.events;
 
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
+import com.sun.xml.internal.stream.util.ReadOnlyIterator;
 import java.util.ArrayList;
 import java.util.Collection;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.Attribute;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import javax.xml.namespace.NamespaceContext;
-import java.io.Writer;
-import com.sun.xml.internal.stream.util.ReadOnlyIterator;
+import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.StartElement;
 
-/** Implementation of StartElementEvent.
+/**
+ * Implementation of StartElementEvent.
  *
  * @author Neeraj Bajaj Sun Microsystems,Inc.
  * @author K.Venugopal Sun Microsystems,Inc.
  */
-
 public class StartElementEvent extends DummyEvent
-implements StartElement {
+        implements StartElement {
 
-    private Map fAttributes;
-    private List fNamespaces;
+    private Map<QName, Attribute> fAttributes;
+    private List<Namespace> fNamespaces;
     private NamespaceContext fNamespaceContext = null;
     private QName fQName;
 
@@ -70,12 +68,13 @@
         addNamespaceAttributes(startelement.getNamespaces());
     }
 
-    protected void init() {
+    protected final void init() {
         setEventType(XMLStreamConstants.START_ELEMENT);
-        fAttributes = new HashMap();
-        fNamespaces = new ArrayList();
+        fAttributes = new HashMap<>();
+        fNamespaces = new ArrayList<>();
     }
 
+    @Override
     public QName getName() {
         return fQName;
     }
@@ -84,50 +83,60 @@
         this.fQName = qname;
     }
 
-    public Iterator getAttributes() {
-        if(fAttributes != null){
-            Collection coll = fAttributes.values();
-            return new ReadOnlyIterator(coll.iterator());
+    @Override
+    public Iterator<Attribute> getAttributes() {
+        if (fAttributes != null) {
+            Collection<Attribute> coll = fAttributes.values();
+            return new ReadOnlyIterator<>(coll.iterator());
         }
-        return new ReadOnlyIterator();
+        return new ReadOnlyIterator<>();
     }
 
-    public Iterator getNamespaces() {
-        if(fNamespaces != null){
-            return new ReadOnlyIterator(fNamespaces.iterator());
+    @Override
+    public Iterator<Namespace> getNamespaces() {
+        if (fNamespaces != null) {
+            return new ReadOnlyIterator<>(fNamespaces.iterator());
         }
-        return new ReadOnlyIterator();
+        return new ReadOnlyIterator<>();
     }
 
+    @Override
     public Attribute getAttributeByName(QName qname) {
-        if(qname == null)
+        if (qname == null) {
             return null;
-        return (Attribute)fAttributes.get(qname);
+        }
+        return fAttributes.get(qname);
     }
 
-    public String getNamespace(){
+    public String getNamespace() {
         return fQName.getNamespaceURI();
     }
 
+    @Override
     public String getNamespaceURI(String prefix) {
         //check that URI was supplied when creating this startElement event and prefix matches
-        if( getNamespace() != null && fQName.getPrefix().equals(prefix)) return getNamespace();
+        if (getNamespace() != null && fQName.getPrefix().equals(prefix)) {
+            return getNamespace();
+        }
         //else check the namespace context
-        if(fNamespaceContext != null)
+        if (fNamespaceContext != null) {
             return fNamespaceContext.getNamespaceURI(prefix);
+        }
         return null;
     }
 
     /**
-     * <p>Return a <code>String</code> representation of this
+     * <p>
+     * Return a <code>String</code> representation of this
      * <code>StartElement</code> formatted as XML.</p>
      *
      * @return <code>String</code> representation of this
-     *   <code>StartElement</code> formatted as XML.
+     * <code>StartElement</code> formatted as XML.
      */
+    @Override
     public String toString() {
 
-        StringBuffer startElement = new StringBuffer();
+        StringBuilder startElement = new StringBuilder();
 
         // open element
         startElement.append("<");
@@ -135,10 +144,10 @@
 
         // add any attributes
         if (fAttributes != null) {
-            Iterator it = this.getAttributes();
-            Attribute attr = null;
+            Iterator<Attribute> it = this.getAttributes();
+            Attribute attr;
             while (it.hasNext()) {
-                attr = (Attribute) it.next();
+                attr = it.next();
                 startElement.append(" ");
                 startElement.append(attr.toString());
             }
@@ -146,12 +155,12 @@
 
         // add any namespaces
         if (fNamespaces != null) {
-            Iterator it = fNamespaces.iterator();
-            Namespace attr = null;
+            Iterator<Namespace> it = fNamespaces.iterator();
+            Namespace ns;
             while (it.hasNext()) {
-                attr = (Namespace) it.next();
+                ns = it.next();
                 startElement.append(" ");
-                startElement.append(attr.toString());
+                startElement.append(ns.toString());
             }
         }
 
@@ -162,26 +171,31 @@
         return startElement.toString();
     }
 
-    /** Return this event as String
+    /**
+     * Return this event as String
+     *
      * @return String Event returned as string.
      */
     public String nameAsString() {
-        if("".equals(fQName.getNamespaceURI()))
+        if ("".equals(fQName.getNamespaceURI())) {
             return fQName.getLocalPart();
-        if(fQName.getPrefix() != null)
-            return "['" + fQName.getNamespaceURI() + "']:" + fQName.getPrefix() + ":" + fQName.getLocalPart();
-        else
+        }
+        if (fQName.getPrefix() != null) {
+            return "['" + fQName.getNamespaceURI() + "']:" + fQName.getPrefix()
+                    + ":" + fQName.getLocalPart();
+        } else {
             return "['" + fQName.getNamespaceURI() + "']:" + fQName.getLocalPart();
+        }
     }
 
-
-    /** Gets a read-only namespace context. If no context is
-     * available this method will return an empty namespace context.
-     * The NamespaceContext contains information about all namespaces
-     * in scope for this StartElement.
+    /**
+     * Gets a read-only namespace context. If no context is available this
+     * method will return an empty namespace context. The NamespaceContext
+     * contains information about all namespaces in scope for this StartElement.
      *
      * @return the current namespace context
      */
+    @Override
     public NamespaceContext getNamespaceContext() {
         return fNamespaceContext;
     }
@@ -190,40 +204,43 @@
         fNamespaceContext = nc;
     }
 
+    @Override
     protected void writeAsEncodedUnicodeEx(java.io.Writer writer)
-    throws java.io.IOException
-    {
+            throws java.io.IOException {
         writer.write(toString());
     }
 
-    void addAttribute(Attribute attr){
-        if(attr.isNamespace()){
-            fNamespaces.add(attr);
-        }else{
-            fAttributes.put(attr.getName(),attr);
+    void addAttribute(Attribute attr) {
+        if (attr.isNamespace()) {
+            fNamespaces.add((Namespace) attr);
+        } else {
+            fAttributes.put(attr.getName(), attr);
         }
     }
 
-    void addAttributes(Iterator attrs){
-        if(attrs == null)
+    final void addAttributes(Iterator<? extends Attribute> attrs) {
+        if (attrs == null) {
             return;
-        while(attrs.hasNext()){
-            Attribute attr = (Attribute)attrs.next();
-            fAttributes.put(attr.getName(),attr);
+        }
+        while (attrs.hasNext()) {
+            Attribute attr = attrs.next();
+            fAttributes.put(attr.getName(), attr);
         }
     }
 
-    void addNamespaceAttribute(Namespace attr){
-        if(attr == null)
+    void addNamespaceAttribute(Namespace attr) {
+        if (attr == null) {
             return;
+        }
         fNamespaces.add(attr);
     }
 
-    void addNamespaceAttributes(Iterator attrs){
-        if(attrs == null)
+    final void addNamespaceAttributes(Iterator<? extends Namespace> attrs) {
+        if (attrs == null) {
             return;
-        while(attrs.hasNext()){
-            Namespace attr = (Namespace)attrs.next();
+        }
+        while (attrs.hasNext()) {
+            Namespace attr = attrs.next();
             fNamespaces.add(attr);
         }
     }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventAllocatorImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventAllocatorImpl.java
index 065a7cd..b59771e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventAllocatorImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventAllocatorImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,6 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package com.sun.xml.internal.stream.events;
 
 import com.sun.org.apache.xerces.internal.impl.PropertyManager;
@@ -34,29 +33,36 @@
 import javax.xml.namespace.QName;
 import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper;
 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
+import javax.xml.stream.util.XMLEventConsumer;
 
 /**
  * Implementation of XMLEvent Allocator.
+ *
  * @author Neeraj.bajaj@sun.com, k.venugopal@sun.com
  */
 public class XMLEventAllocatorImpl implements XMLEventAllocator {
 
-    /** Creates a new instance of XMLEventAllocator */
+    /**
+     * Creates a new instance of XMLEventAllocator
+     */
     public XMLEventAllocatorImpl() {
     }
 
-    public javax.xml.stream.events.XMLEvent allocate(javax.xml.stream.XMLStreamReader xMLStreamReader) throws javax.xml.stream.XMLStreamException {
-        if(xMLStreamReader == null )
+    public XMLEvent allocate(XMLStreamReader xMLStreamReader) throws XMLStreamException {
+        if (xMLStreamReader == null) {
             throw new XMLStreamException("Reader cannot be null");
+        }
         //        allocate is not supposed to change the state of the reader so we shouldn't be calling next.
         //        return getNextEvent(xMLStreamReader);
         return getXMLEvent(xMLStreamReader);
     }
 
-    public void allocate(javax.xml.stream.XMLStreamReader xMLStreamReader, javax.xml.stream.util.XMLEventConsumer xMLEventConsumer) throws javax.xml.stream.XMLStreamException {
+    public void allocate(XMLStreamReader xMLStreamReader, XMLEventConsumer xMLEventConsumer)
+            throws XMLStreamException {
         XMLEvent currentEvent = getXMLEvent(xMLStreamReader);
-        if(currentEvent != null )
+        if (currentEvent != null) {
             xMLEventConsumer.add(currentEvent);
+        }
 
         return;
     }
@@ -66,141 +72,149 @@
     }
 
     //REVISIT: shouldn't we be using XMLEventFactory to create events.
-    XMLEvent getXMLEvent(XMLStreamReader streamReader){
+    XMLEvent getXMLEvent(XMLStreamReader streamReader) {
         XMLEvent event = null;
         //returns the current event
         int eventType = streamReader.getEventType();
-        switch(eventType){
+        switch (eventType) {
 
-            case XMLEvent.START_ELEMENT:{
+            case XMLEvent.START_ELEMENT: {
                 StartElementEvent startElementEvent = new StartElementEvent(getQName(streamReader));
-                fillAttributes(startElementEvent,streamReader);
-                //we might have different XMLStreamReader so check every time for the namespace aware property
-                //we should be setting namespace related values only when isNamespaceAware is 'true'
-                if( ((Boolean)streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue() ){
+                fillAttributes(startElementEvent, streamReader);
+                //we might have different XMLStreamReader so check every time for
+                //the namespace aware property. we should be setting namespace
+                //related values only when isNamespaceAware is 'true'
+                if (((Boolean) streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE))) {
                     fillNamespaceAttributes(startElementEvent, streamReader);
-                    setNamespaceContext(startElementEvent,streamReader);
+                    setNamespaceContext(startElementEvent, streamReader);
                 }
 
                 startElementEvent.setLocation(streamReader.getLocation());
-                event = startElementEvent ;
+                event = startElementEvent;
                 break;
             }
-            case XMLEvent.END_ELEMENT:{
+            case XMLEvent.END_ELEMENT: {
                 EndElementEvent endElementEvent = new EndElementEvent(getQName(streamReader));
                 endElementEvent.setLocation(streamReader.getLocation());
 
-                if( ((Boolean)streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue() ){
-                    fillNamespaceAttributes(endElementEvent,streamReader);
+                if (((Boolean) streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE))) {
+                    fillNamespaceAttributes(endElementEvent, streamReader);
                 }
-                event = endElementEvent ;
+                event = endElementEvent;
                 break;
             }
-            case XMLEvent.PROCESSING_INSTRUCTION:{
-                ProcessingInstructionEvent piEvent = new ProcessingInstructionEvent(streamReader.getPITarget(),streamReader.getPIData());
+            case XMLEvent.PROCESSING_INSTRUCTION: {
+                ProcessingInstructionEvent piEvent = new ProcessingInstructionEvent(
+                        streamReader.getPITarget(), streamReader.getPIData());
                 piEvent.setLocation(streamReader.getLocation());
-                event = piEvent ;
+                event = piEvent;
                 break;
             }
-            case XMLEvent.CHARACTERS:{
+            case XMLEvent.CHARACTERS: {
                 CharacterEvent cDataEvent = new CharacterEvent(streamReader.getText());
                 cDataEvent.setLocation(streamReader.getLocation());
-                event = cDataEvent ;
+                event = cDataEvent;
                 break;
             }
-            case XMLEvent.COMMENT:{
+            case XMLEvent.COMMENT: {
                 CommentEvent commentEvent = new CommentEvent(streamReader.getText());
                 commentEvent.setLocation(streamReader.getLocation());
-                event = commentEvent ;
+                event = commentEvent;
                 break;
             }
-            case XMLEvent.START_DOCUMENT:{
+            case XMLEvent.START_DOCUMENT: {
                 StartDocumentEvent sdEvent = new StartDocumentEvent();
                 sdEvent.setVersion(streamReader.getVersion());
                 sdEvent.setEncoding(streamReader.getEncoding());
-                if(streamReader.getCharacterEncodingScheme() != null){
+                if (streamReader.getCharacterEncodingScheme() != null) {
                     sdEvent.setDeclaredEncoding(true);
-                }else{
+                } else {
                     sdEvent.setDeclaredEncoding(false);
                 }
                 sdEvent.setStandalone(streamReader.isStandalone());
                 sdEvent.setLocation(streamReader.getLocation());
-                event = sdEvent ;
+                event = sdEvent;
                 break;
             }
-            case XMLEvent.END_DOCUMENT:{
-                EndDocumentEvent endDocumentEvent = new EndDocumentEvent() ;
+            case XMLEvent.END_DOCUMENT: {
+                EndDocumentEvent endDocumentEvent = new EndDocumentEvent();
                 endDocumentEvent.setLocation(streamReader.getLocation());
-                event = endDocumentEvent ;
+                event = endDocumentEvent;
                 break;
             }
-            case XMLEvent.ENTITY_REFERENCE:{
-                EntityReferenceEvent entityEvent =  new EntityReferenceEvent(streamReader.getLocalName(), new EntityDeclarationImpl(streamReader.getLocalName(),streamReader.getText()));
+            case XMLEvent.ENTITY_REFERENCE: {
+                EntityReferenceEvent entityEvent = new EntityReferenceEvent(streamReader.getLocalName(),
+                        new EntityDeclarationImpl(streamReader.getLocalName(), streamReader.getText()));
                 entityEvent.setLocation(streamReader.getLocation());
                 event = entityEvent;
                 break;
 
             }
-            case XMLEvent.ATTRIBUTE:{
-                event = null ;
+            case XMLEvent.ATTRIBUTE: {
+                event = null;
                 break;
             }
-            case XMLEvent.DTD:{
+            case XMLEvent.DTD: {
                 DTDEvent dtdEvent = new DTDEvent(streamReader.getText());
                 dtdEvent.setLocation(streamReader.getLocation());
-                List entities = (List)streamReader.getProperty(PropertyManager.STAX_ENTITIES);
-                if (entities != null && entities.size() != 0) dtdEvent.setEntities(entities);
-                List notations = (List)streamReader.getProperty(PropertyManager.STAX_NOTATIONS);
-                if (notations != null && notations.size() != 0) dtdEvent.setNotations(notations);
+                @SuppressWarnings("unchecked")
+                List<EntityDeclaration> entities = (List<EntityDeclaration>)
+                        streamReader.getProperty(PropertyManager.STAX_ENTITIES);
+                if (entities != null && entities.size() != 0) {
+                    dtdEvent.setEntities(entities);
+                }
+                @SuppressWarnings("unchecked")
+                List<NotationDeclaration> notations = (List<NotationDeclaration>)
+                        streamReader.getProperty(PropertyManager.STAX_NOTATIONS);
+                if (notations != null && !notations.isEmpty()) {
+                    dtdEvent.setNotations(notations);
+                }
                 event = dtdEvent;
                 break;
             }
-            case XMLEvent.CDATA:{
-                CharacterEvent cDataEvent = new CharacterEvent(streamReader.getText(),true);
+            case XMLEvent.CDATA: {
+                CharacterEvent cDataEvent = new CharacterEvent(streamReader.getText(), true);
                 cDataEvent.setLocation(streamReader.getLocation());
-                event = cDataEvent ;
+                event = cDataEvent;
                 break;
             }
-            case XMLEvent.SPACE:{
-                CharacterEvent spaceEvent = new CharacterEvent(streamReader.getText(),false,true);
+            case XMLEvent.SPACE: {
+                CharacterEvent spaceEvent = new CharacterEvent(streamReader.getText(), false, true);
                 spaceEvent.setLocation(streamReader.getLocation());
-                event = spaceEvent ;
+                event = spaceEvent;
                 break;
             }
         }
-        return event ;
+        return event;
     }
 
     //this function is not used..
-    protected XMLEvent getNextEvent(XMLStreamReader streamReader) throws XMLStreamException{
+    protected XMLEvent getNextEvent(XMLStreamReader streamReader) throws XMLStreamException {
         //advance the reader to next event.
         streamReader.next();
         return getXMLEvent(streamReader);
     }
 
-    protected void fillAttributes(StartElementEvent event,XMLStreamReader xmlr){
+    protected void fillAttributes(StartElementEvent event, XMLStreamReader xmlr) {
 
         int len = xmlr.getAttributeCount();
         QName qname = null;
         AttributeImpl attr = null;
         NamespaceImpl nattr = null;
-        for(int i=0; i<len ;i++){
+        for (int i = 0; i < len; i++) {
             qname = xmlr.getAttributeName(i);
             //this method doesn't include namespace declarations
             //so we can be sure that there wont be any namespace declaration as part of this function call
             //we can avoid this check - nb.
             /**
-             * prefix = qname.getPrefix();
-             * localpart = qname.getLocalPart();
-             * if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE) ) {
-             * attr = new NamespaceImpl(localpart,xmlr.getAttributeValue(i));
-             * }else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)){
-             * attr = new NamespaceImpl(xmlr.getAttributeValue(i));
-             * }else{
-             * attr = new AttributeImpl();
-             * attr.setName(qname);
-             * }
-             **/
+             * prefix = qname.getPrefix(); localpart = qname.getLocalPart(); if
+             * (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE) ) { attr = new
+             * NamespaceImpl(localpart,xmlr.getAttributeValue(i)); }else if
+             * (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)){ attr = new
+             * NamespaceImpl(xmlr.getAttributeValue(i)); }else{ attr = new
+             * AttributeImpl(); attr.setName(qname); }
+             *
+             */
             attr = new AttributeImpl();
             attr.setName(qname);
             attr.setAttributeType(xmlr.getAttributeType(i));
@@ -210,42 +224,42 @@
         }
     }
 
-    protected void fillNamespaceAttributes(StartElementEvent event,XMLStreamReader xmlr){
+    protected void fillNamespaceAttributes(StartElementEvent event, XMLStreamReader xmlr) {
         int count = xmlr.getNamespaceCount();
         String uri = null;
         String prefix = null;
         NamespaceImpl attr = null;
-        for(int i=0;i< count;i++){
+        for (int i = 0; i < count; i++) {
             uri = xmlr.getNamespaceURI(i);
             prefix = xmlr.getNamespacePrefix(i);
-            if(prefix == null){
+            if (prefix == null) {
                 prefix = XMLConstants.DEFAULT_NS_PREFIX;
             }
-            attr = new NamespaceImpl(prefix,uri);
+            attr = new NamespaceImpl(prefix, uri);
             event.addNamespaceAttribute(attr);
         }
     }
 
-    protected void fillNamespaceAttributes(EndElementEvent event,XMLStreamReader xmlr){
+    protected void fillNamespaceAttributes(EndElementEvent event, XMLStreamReader xmlr) {
         int count = xmlr.getNamespaceCount();
         String uri = null;
         String prefix = null;
         NamespaceImpl attr = null;
-        for(int i=0;i< count;i++){
+        for (int i = 0; i < count; i++) {
             uri = xmlr.getNamespaceURI(i);
             prefix = xmlr.getNamespacePrefix(i);
-            if(prefix == null){
+            if (prefix == null) {
                 prefix = XMLConstants.DEFAULT_NS_PREFIX;
             }
-            attr = new NamespaceImpl(prefix,uri);
+            attr = new NamespaceImpl(prefix, uri);
             event.addNamespace(attr);
         }
     }
 
     //Revisit : Creating a new Namespacecontext for now.
     //see if we can do better job.
-    private void setNamespaceContext(StartElementEvent event , XMLStreamReader xmlr){
-        NamespaceContextWrapper contextWrapper =(NamespaceContextWrapper) xmlr.getNamespaceContext();
+    private void setNamespaceContext(StartElementEvent event, XMLStreamReader xmlr) {
+        NamespaceContextWrapper contextWrapper = (NamespaceContextWrapper) xmlr.getNamespaceContext();
         NamespaceSupport ns = new NamespaceSupport(contextWrapper.getNamespaceContext());
         event.setNamespaceContext(new NamespaceContextWrapper(ns));
     }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventFactoryImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventFactoryImpl.java
index 669546b..81fbbd4 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventFactoryImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/events/XMLEventFactoryImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,19 @@
 
 package com.sun.xml.internal.stream.events;
 
+import java.util.Iterator;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
 import javax.xml.stream.XMLEventFactory;
 import javax.xml.stream.Location;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.ProcessingInstruction;
 import javax.xml.stream.events.Namespace;
 import javax.xml.stream.events.EntityDeclaration;
+import javax.xml.stream.events.EntityReference;
+import javax.xml.stream.events.StartDocument;
+import javax.xml.stream.events.StartElement;
 
 
 /**
@@ -42,23 +51,27 @@
     public XMLEventFactoryImpl() {
     }
 
-    public javax.xml.stream.events.Attribute createAttribute(String localName, String value) {
+    @Override
+    public Attribute createAttribute(String localName, String value) {
         AttributeImpl attr =  new AttributeImpl(localName, value);
         if(location != null)attr.setLocation(location);
         return attr;
     }
 
-    public javax.xml.stream.events.Attribute createAttribute(javax.xml.namespace.QName name, String value) {
+    @Override
+    public Attribute createAttribute(QName name, String value) {
         return createAttribute(name.getPrefix(), name.getNamespaceURI(), name.getLocalPart(), value);
     }
 
-    public javax.xml.stream.events.Attribute createAttribute(String prefix, String namespaceURI, String localName, String value) {
+    @Override
+    public Attribute createAttribute(String prefix, String namespaceURI, String localName, String value) {
         AttributeImpl attr =  new AttributeImpl(prefix, namespaceURI, localName, value, null);
         if(location != null)attr.setLocation(location);
         return attr;
     }
 
-    public javax.xml.stream.events.Characters createCData(String content) {
+    @Override
+    public Characters createCData(String content) {
         //stax doesn't have separate CDATA event. This is taken care by
         //CHRACTERS event setting the cdata flag to true.
         CharacterEvent charEvent =  new CharacterEvent(content, true);
@@ -66,126 +79,156 @@
         return charEvent;
     }
 
-    public javax.xml.stream.events.Characters createCharacters(String content) {
+    @Override
+    public Characters createCharacters(String content) {
         CharacterEvent charEvent =  new CharacterEvent(content);
         if(location != null)charEvent.setLocation(location);
         return charEvent;
     }
 
+    @Override
     public javax.xml.stream.events.Comment createComment(String text) {
         CommentEvent charEvent =  new CommentEvent(text);
         if(location != null)charEvent.setLocation(location);
         return charEvent;
     }
 
+    @Override
     public javax.xml.stream.events.DTD createDTD(String dtd) {
         DTDEvent dtdEvent = new DTDEvent(dtd);
         if(location != null)dtdEvent.setLocation(location);
         return dtdEvent;
     }
 
+    @Override
     public javax.xml.stream.events.EndDocument createEndDocument() {
         EndDocumentEvent event =new EndDocumentEvent();
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.EndElement createEndElement(javax.xml.namespace.QName name, java.util.Iterator namespaces) {
+    @Override
+    public javax.xml.stream.events.EndElement createEndElement(QName name,
+            Iterator<? extends Namespace> namespaces) {
         return createEndElement(name.getPrefix(), name.getNamespaceURI(), name.getLocalPart());
     }
 
-    public javax.xml.stream.events.EndElement createEndElement(String prefix, String namespaceUri, String localName) {
+    @Override
+    public javax.xml.stream.events.EndElement createEndElement(
+            String prefix, String namespaceUri, String localName) {
         EndElementEvent event =  new EndElementEvent(prefix, namespaceUri, localName);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.EndElement createEndElement(String prefix, String namespaceUri, String localName, java.util.Iterator namespaces) {
+    @Override
+    public javax.xml.stream.events.EndElement createEndElement(String prefix, String namespaceUri,
+            String localName, Iterator<? extends Namespace> namespaces) {
 
         EndElementEvent event =  new EndElementEvent(prefix, namespaceUri, localName);
         if(namespaces!=null){
             while(namespaces.hasNext())
-                event.addNamespace((Namespace)namespaces.next());
+                event.addNamespace(namespaces.next());
         }
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.EntityReference createEntityReference(String name, EntityDeclaration entityDeclaration) {
+    @Override
+    public EntityReference createEntityReference(String name, EntityDeclaration entityDeclaration) {
         EntityReferenceEvent event =  new EntityReferenceEvent(name, entityDeclaration);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.Characters createIgnorableSpace(String content) {
+    @Override
+    public Characters createIgnorableSpace(String content) {
         CharacterEvent event =  new CharacterEvent(content, false, true);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.Namespace createNamespace(String namespaceURI) {
+    @Override
+    public Namespace createNamespace(String namespaceURI) {
         NamespaceImpl event =  new NamespaceImpl(namespaceURI);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.Namespace createNamespace(String prefix, String namespaceURI) {
+    @Override
+    public Namespace createNamespace(String prefix, String namespaceURI) {
         NamespaceImpl event =  new NamespaceImpl(prefix, namespaceURI);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.ProcessingInstruction createProcessingInstruction(String target, String data) {
+    @Override
+    public ProcessingInstruction createProcessingInstruction(String target, String data) {
         ProcessingInstructionEvent event =  new ProcessingInstructionEvent(target, data);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.Characters createSpace(String content) {
+    @Override
+    public Characters createSpace(String content) {
         CharacterEvent event =  new CharacterEvent(content);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartDocument createStartDocument() {
+    @Override
+    public StartDocument createStartDocument() {
         StartDocumentEvent event = new StartDocumentEvent();
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartDocument createStartDocument(String encoding) {
+    @Override
+    public StartDocument createStartDocument(String encoding) {
         StartDocumentEvent event =  new StartDocumentEvent(encoding);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartDocument createStartDocument(String encoding, String version) {
+    @Override
+    public StartDocument createStartDocument(String encoding, String version) {
         StartDocumentEvent event =  new StartDocumentEvent(encoding, version);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartDocument createStartDocument(String encoding, String version, boolean standalone) {
+    @Override
+    public StartDocument createStartDocument(String encoding, String version, boolean standalone) {
         StartDocumentEvent event =  new StartDocumentEvent(encoding, version, standalone);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartElement createStartElement(javax.xml.namespace.QName name, java.util.Iterator attributes, java.util.Iterator namespaces) {
-        return createStartElement(name.getPrefix(), name.getNamespaceURI(), name.getLocalPart(), attributes, namespaces);
+    @Override
+    public StartElement createStartElement(QName name, Iterator<? extends Attribute> attributes,
+            Iterator<? extends Namespace> namespaces) {
+        return createStartElement(name.getPrefix(), name.getNamespaceURI(),
+                name.getLocalPart(), attributes, namespaces);
     }
 
-    public javax.xml.stream.events.StartElement createStartElement(String prefix, String namespaceUri, String localName) {
+    @Override
+    public StartElement createStartElement(String prefix, String namespaceUri, String localName) {
         StartElementEvent event =  new StartElementEvent(prefix, namespaceUri, localName);
         if(location != null)event.setLocation(location);
         return event;
     }
 
-    public javax.xml.stream.events.StartElement createStartElement(String prefix, String namespaceUri, String localName, java.util.Iterator attributes, java.util.Iterator namespaces) {
+    @Override
+    public StartElement createStartElement(String prefix, String namespaceUri,
+            String localName, Iterator<? extends Attribute> attributes,
+            Iterator<? extends Namespace> namespaces) {
         return createStartElement(prefix, namespaceUri, localName, attributes, namespaces, null);
     }
 
-    public javax.xml.stream.events.StartElement createStartElement(String prefix, String namespaceUri, String localName, java.util.Iterator attributes, java.util.Iterator namespaces, javax.xml.namespace.NamespaceContext context) {
+    @Override
+    public StartElement createStartElement(String prefix, String namespaceUri,
+            String localName, Iterator<? extends Attribute> attributes,
+            Iterator<? extends Namespace> namespaces, NamespaceContext context) {
         StartElementEvent elem =  new StartElementEvent(prefix, namespaceUri, localName);
         elem.addAttributes(attributes);
         elem.addNamespaceAttributes(namespaces);
@@ -194,6 +237,7 @@
         return elem;
     }
 
+    @Override
     public void setLocation(javax.xml.stream.Location location) {
         this.location = location;
     }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java
index c1fd3c7..3106d15 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,35 +31,32 @@
 
 import java.util.Iterator;
 
-public class ReadOnlyIterator implements Iterator {
+public class ReadOnlyIterator<T> implements Iterator<T> {
 
-    Iterator iterator = null;
+    Iterator<T> iterator = null;
 
     public ReadOnlyIterator(){
     }
 
-    public ReadOnlyIterator(Iterator itr){
+    public ReadOnlyIterator(Iterator<T> itr){
         iterator = itr;
     }
 
-    /**
-     * @return
-     */
+    @Override
     public boolean hasNext() {
         if(iterator  != null)
             return iterator.hasNext();
         return false;
     }
 
-    /**
-     * @return
-     */
-    public Object next() {
+    @Override
+    public T next() {
         if(iterator  != null)
             return iterator.next();
         return null;
     }
 
+    @Override
     public void remove() {
         throw new  UnsupportedOperationException("Remove operation is not supported");
     }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ThreadLocalBufferAllocator.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ThreadLocalBufferAllocator.java
index 25bdf6b..edb3eda 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ThreadLocalBufferAllocator.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ThreadLocalBufferAllocator.java
@@ -39,15 +39,15 @@
  * @author Santiago.PericasGeertsen@sun.com
  */
 public class ThreadLocalBufferAllocator {
-   private static ThreadLocal tlba = new ThreadLocal();
+   private static ThreadLocal<SoftReference> tlba = new ThreadLocal<>();
 
    public static BufferAllocator getBufferAllocator() {
-        SoftReference bAllocatorRef = (SoftReference) tlba.get();
+        SoftReference<BufferAllocator> bAllocatorRef = tlba.get();
         if (bAllocatorRef == null || bAllocatorRef.get() == null) {
             bAllocatorRef = new SoftReference(new BufferAllocator());
             tlba.set(bAllocatorRef);
         }
 
-        return (BufferAllocator) bAllocatorRef.get();
+        return bAllocatorRef.get();
    }
 }
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/UTF8OutputStreamWriter.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/UTF8OutputStreamWriter.java
index 552e030..7ee48af 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/UTF8OutputStreamWriter.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/UTF8OutputStreamWriter.java
@@ -89,7 +89,7 @@
         // Otherwise, encode char as defined in UTF-8
         if (c < 0x80) {
             // 1 byte, 7 bits
-            out.write((int) c);
+            out.write(c);
         }
         else if (c < 0x800) {
             // 2 bytes, 11 bits
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java
index 75500e8..e92508f 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java
@@ -26,9 +26,12 @@
 package com.sun.xml.internal.stream.writers;
 
 import java.util.Iterator;
+import javax.xml.namespace.NamespaceContext;
 import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLEventWriter;
 import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
 import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.Characters;
 import javax.xml.stream.events.Comment;
@@ -39,24 +42,24 @@
 import javax.xml.stream.events.StartDocument;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.XMLStreamWriter;
 
 /**
  *
- * @author  Neeraj Bajaj, Sun Microsystems.
+ * @author Neeraj Bajaj, Sun Microsystems.
  *
  */
-public class XMLEventWriterImpl implements XMLEventWriter{
+public class XMLEventWriterImpl implements XMLEventWriter {
 
     //delegate everything to XMLStreamWriter..
-    private final XMLStreamWriterBase fStreamWriter ;
+    private final XMLStreamWriterBase fStreamWriter;
     private static final boolean DEBUG = false;
+
     /**
      *
      * @param streamWriter
      */
-    public XMLEventWriterImpl(XMLStreamWriter streamWriter){
-        fStreamWriter = (XMLStreamWriterBase)streamWriter;
+    public XMLEventWriterImpl(XMLStreamWriter streamWriter) {
+        fStreamWriter = (XMLStreamWriterBase) streamWriter;
     }
 
     /**
@@ -64,9 +67,11 @@
      * @param xMLEventReader
      * @throws XMLStreamException
      */
-    public void add(javax.xml.stream.XMLEventReader xMLEventReader) throws javax.xml.stream.XMLStreamException {
-        if(xMLEventReader == null) throw new XMLStreamException("Event reader shouldn't be null");
-        while(xMLEventReader.hasNext()){
+    public void add(XMLEventReader xMLEventReader) throws XMLStreamException {
+        if (xMLEventReader == null) {
+            throw new XMLStreamException("Event reader shouldn't be null");
+        }
+        while (xMLEventReader.hasNext()) {
             add(xMLEventReader.nextEvent());
         }
     }
@@ -76,101 +81,127 @@
      * @param xMLEvent
      * @throws XMLStreamException
      */
-    public void add(javax.xml.stream.events.XMLEvent xMLEvent) throws javax.xml.stream.XMLStreamException {
+    public void add(XMLEvent xMLEvent) throws XMLStreamException {
         int type = xMLEvent.getEventType();
-        switch(type){
-            case XMLEvent.DTD:{
-                DTD dtd = (DTD)xMLEvent ;
-                if (DEBUG)System.out.println("Adding DTD = " + dtd.toString());
+        switch (type) {
+            case XMLEvent.DTD: {
+                DTD dtd = (DTD) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding DTD = " + dtd.toString());
+                }
                 fStreamWriter.writeDTD(dtd.getDocumentTypeDeclaration());
                 break;
             }
-            case XMLEvent.START_DOCUMENT :{
-                StartDocument startDocument = (StartDocument)xMLEvent ;
-                if (DEBUG)System.out.println("Adding StartDocument = " + startDocument.toString());
+            case XMLEvent.START_DOCUMENT: {
+                StartDocument startDocument = (StartDocument) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding StartDocument = " + startDocument.toString());
+                }
                 try {
-                   fStreamWriter.writeStartDocument(startDocument.getCharacterEncodingScheme(), startDocument.getVersion(),
-                           startDocument.isStandalone(), startDocument.standaloneSet());
-                }catch(XMLStreamException e) {
+                    fStreamWriter.writeStartDocument(startDocument.getCharacterEncodingScheme(),
+                            startDocument.getVersion(),
+                            startDocument.isStandalone(), startDocument.standaloneSet());
+                } catch (XMLStreamException e) {
                     fStreamWriter.writeStartDocument(startDocument.getVersion());
                 }
                 break;
             }
-            case XMLEvent.START_ELEMENT :{
-                StartElement startElement = xMLEvent.asStartElement() ;
-                if (DEBUG)System.out.println("Adding startelement = " + startElement.toString());
+            case XMLEvent.START_ELEMENT: {
+                StartElement startElement = xMLEvent.asStartElement();
+                if (DEBUG) {
+                    System.out.println("Adding startelement = " + startElement.toString());
+                }
                 QName qname = startElement.getName();
-                fStreamWriter.writeStartElement(qname.getPrefix(), qname.getLocalPart(), qname.getNamespaceURI());
+                fStreamWriter.writeStartElement(qname.getPrefix(), qname.getLocalPart(),
+                        qname.getNamespaceURI());
 
-                //getNamespaces() Returns an Iterator of namespaces declared on this element. This Iterator does not contain
-                //previously declared namespaces unless they appear on the current START_ELEMENT. Therefore
-                //this list may contain redeclared namespaces and duplicate namespace declarations. Use the
-                //getNamespaceContext() method to get the current context of namespace declarations.
-
-                //so we should be using getNamespaces() to write namespace declarations for this START_ELEMENT
-                Iterator iterator = startElement.getNamespaces();
-                while(iterator.hasNext()){
-                    Namespace namespace = (Namespace)iterator.next();
+                /*
+                  getNamespaces() Returns an Iterator of namespaces declared on this element.
+                This Iterator does not contain previously declared namespaces unless they
+                appear on the current START_ELEMENT. Therefore this list may contain redeclared
+                namespaces and duplicate namespace declarations. Use the getNamespaceContext()
+                method to get the current context of namespace declarations. We should be
+                using getNamespaces() to write namespace declarations for this START_ELEMENT
+                */
+                Iterator<? extends Namespace> iterator = startElement.getNamespaces();
+                while (iterator.hasNext()) {
+                    Namespace namespace = iterator.next();
                     fStreamWriter.writeNamespace(namespace.getPrefix(), namespace.getNamespaceURI());
                 }
                 //REVISIT: What about writing attributes ?
-                Iterator attributes = startElement.getAttributes();
-                while(attributes.hasNext()){
-                    Attribute attribute = (Attribute)attributes.next();
+                Iterator<? extends Attribute> attributes = startElement.getAttributes();
+                while (attributes.hasNext()) {
+                    Attribute attribute = attributes.next();
                     QName aqname = attribute.getName();
-                    fStreamWriter.writeAttribute(aqname.getPrefix(), aqname.getNamespaceURI(), aqname.getLocalPart(),attribute.getValue());
+                    fStreamWriter.writeAttribute(aqname.getPrefix(), aqname.getNamespaceURI(),
+                            aqname.getLocalPart(), attribute.getValue());
                 }
                 break;
             }
-            case XMLEvent.NAMESPACE:{
-                Namespace namespace = (Namespace)xMLEvent;
-                if (DEBUG)System.out.println("Adding namespace = " + namespace.toString());
+            case XMLEvent.NAMESPACE: {
+                Namespace namespace = (Namespace) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding namespace = " + namespace.toString());
+                }
                 fStreamWriter.writeNamespace(namespace.getPrefix(), namespace.getNamespaceURI());
-                break ;
+                break;
             }
             case XMLEvent.COMMENT: {
-                Comment comment = (Comment)xMLEvent ;
-                if (DEBUG)System.out.println("Adding comment = " + comment.toString());
+                Comment comment = (Comment) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding comment = " + comment.toString());
+                }
                 fStreamWriter.writeComment(comment.getText());
                 break;
             }
-            case XMLEvent.PROCESSING_INSTRUCTION:{
-                ProcessingInstruction processingInstruction = (ProcessingInstruction)xMLEvent ;
-                if (DEBUG)System.out.println("Adding processing instruction = " + processingInstruction.toString());
-                fStreamWriter.writeProcessingInstruction(processingInstruction.getTarget(), processingInstruction.getData());
+            case XMLEvent.PROCESSING_INSTRUCTION: {
+                ProcessingInstruction processingInstruction = (ProcessingInstruction) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding processing instruction = " + processingInstruction.toString());
+                }
+                fStreamWriter.writeProcessingInstruction(processingInstruction.getTarget(),
+                        processingInstruction.getData());
                 break;
             }
-            case XMLEvent.CHARACTERS:{
+            case XMLEvent.CHARACTERS: {
                 Characters characters = xMLEvent.asCharacters();
-                if (DEBUG)System.out.println("Adding characters = " + characters.toString());
-                //check if the CHARACTERS are CDATA
-                if(characters.isCData()){
-                    fStreamWriter.writeCData(characters.getData());
+                if (DEBUG) {
+                    System.out.println("Adding characters = " + characters.toString());
                 }
-                else{
+                //check if the CHARACTERS are CDATA
+                if (characters.isCData()) {
+                    fStreamWriter.writeCData(characters.getData());
+                } else {
                     fStreamWriter.writeCharacters(characters.getData());
                 }
                 break;
             }
-            case XMLEvent.ENTITY_REFERENCE:{
-                EntityReference entityReference = (EntityReference)xMLEvent ;
-                if (DEBUG)System.out.println("Adding Entity Reference = "+ entityReference.toString());
+            case XMLEvent.ENTITY_REFERENCE: {
+                EntityReference entityReference = (EntityReference) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding Entity Reference = " + entityReference.toString());
+                }
                 fStreamWriter.writeEntityRef(entityReference.getName());
                 break;
             }
-            case XMLEvent.ATTRIBUTE:{
-                Attribute attribute = (Attribute)xMLEvent;
-                if (DEBUG)System.out.println("Adding Attribute = " + attribute.toString());
+            case XMLEvent.ATTRIBUTE: {
+                Attribute attribute = (Attribute) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding Attribute = " + attribute.toString());
+                }
                 QName qname = attribute.getName();
-                fStreamWriter.writeAttribute(qname.getPrefix(), qname.getNamespaceURI(), qname.getLocalPart(),attribute.getValue());
+                fStreamWriter.writeAttribute(qname.getPrefix(), qname.getNamespaceURI(),
+                        qname.getLocalPart(), attribute.getValue());
                 break;
             }
-            case XMLEvent.CDATA:{
+            case XMLEvent.CDATA: {
                 //there is no separate CDATA datatype but CDATA event can be reported
                 //by using vendor specific CDATA property.
-                Characters characters = (Characters)xMLEvent;
-                if (DEBUG)System.out.println("Adding characters = " + characters.toString());
-                if(characters.isCData()){
+                Characters characters = (Characters) xMLEvent;
+                if (DEBUG) {
+                    System.out.println("Adding characters = " + characters.toString());
+                }
+                if (characters.isCData()) {
                     fStreamWriter.writeCData(characters.getData());
                 }
                 break;
@@ -179,15 +210,11 @@
             //case XMLEvent.NOTATION_DECLARATION:{
             //}
 
-            case XMLEvent.END_ELEMENT:{
-                //we dont need to typecast it.. just call writeEndElement() and fStreamWriter will take care of it.
-                //EndElement endElement = (EndElement)xMLEvent;
+            case XMLEvent.END_ELEMENT: {
                 fStreamWriter.writeEndElement();
                 break;
             }
-            case XMLEvent.END_DOCUMENT:{
-                //we dont need to typecast just call writeEndDocument() and fStreamWriter will take care rest.
-                //EndDocument endDocument = (EndDocument)xMLEvent;
+            case XMLEvent.END_DOCUMENT: {
                 fStreamWriter.writeEndDocument();
                 break;
             }
@@ -200,16 +227,16 @@
      *
      * @throws XMLStreamException
      */
-    public void close() throws javax.xml.stream.XMLStreamException {
+    public void close() throws XMLStreamException {
         fStreamWriter.close();
     }
 
     /**
      *
-     * @throws XMLStreamException will inturn call flush on the stream to which data is being
-     * written.
+     * @throws XMLStreamException will inturn call flush on the stream to which
+     * data is being written.
      */
-    public void flush() throws javax.xml.stream.XMLStreamException {
+    public void flush() throws XMLStreamException {
         fStreamWriter.flush();
     }
 
@@ -217,7 +244,7 @@
      *
      * @return
      */
-    public javax.xml.namespace.NamespaceContext getNamespaceContext() {
+    public NamespaceContext getNamespaceContext() {
         return fStreamWriter.getNamespaceContext();
     }
 
@@ -227,7 +254,7 @@
      * @throws XMLStreamException
      * @return prefix associated with the URI.
      */
-    public String getPrefix(String namespaceURI) throws javax.xml.stream.XMLStreamException {
+    public String getPrefix(String namespaceURI) throws XMLStreamException {
         return fStreamWriter.getPrefix(namespaceURI);
     }
 
@@ -236,7 +263,7 @@
      * @param uri Namespace URI
      * @throws XMLStreamException
      */
-    public void setDefaultNamespace(String uri) throws javax.xml.stream.XMLStreamException {
+    public void setDefaultNamespace(String uri) throws XMLStreamException {
         fStreamWriter.setDefaultNamespace(uri);
     }
 
@@ -245,7 +272,8 @@
      * @param namespaceContext Namespace Context
      * @throws XMLStreamException
      */
-    public void setNamespaceContext(javax.xml.namespace.NamespaceContext namespaceContext) throws javax.xml.stream.XMLStreamException {
+    public void setNamespaceContext(NamespaceContext namespaceContext)
+            throws XMLStreamException {
         fStreamWriter.setNamespaceContext(namespaceContext);
     }
 
@@ -255,7 +283,7 @@
      * @param uri Namespace URI
      * @throws XMLStreamException
      */
-    public void setPrefix(String prefix, String uri) throws javax.xml.stream.XMLStreamException {
+    public void setPrefix(String prefix, String uri) throws XMLStreamException {
         fStreamWriter.setPrefix(prefix, uri);
     }
 
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java
index b7a0652..3ec7f7c 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLStreamWriterImpl.java
@@ -35,7 +35,6 @@
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Random;
 import java.util.Vector;
 import java.util.Set;
@@ -46,7 +45,6 @@
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.stream.StreamResult;
 
 import com.sun.org.apache.xerces.internal.impl.Constants;
@@ -71,7 +69,8 @@
  * @author Santiago.Pericas-Geertsen@sun.com
  * @author Sunitha.Reddy@sun.com
  */
-public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamWriterBase {
+public final class XMLStreamWriterImpl extends AbstractMap<Object, Object>
+        implements XMLStreamWriterBase {
 
     public static final String START_COMMENT = "<!--";
     public static final String END_COMMENT = "-->";
@@ -115,12 +114,12 @@
     /**
      * Collects attributes when the writer is in reparing mode.
      */
-    private ArrayList fAttributeCache;
+    private ArrayList<Attribute> fAttributeCache;
 
     /**
      * Collects namespace declarations when the writer is in reparing mode.
      */
-    private ArrayList fNamespaceDecls;
+    private ArrayList<QName> fNamespaceDecls;
 
     /**
      * Namespace context encapsulating user specified context
@@ -153,7 +152,7 @@
 
     final private String DEFAULT_PREFIX = fSymbolTable.addSymbol("");
 
-    private final ReadOnlyIterator fReadOnlyIterator = new ReadOnlyIterator();
+    private final ReadOnlyIterator<String> fReadOnlyIterator = new ReadOnlyIterator<>();
 
     /**
      * In some cases, this charset encoder is used to determine if a char is
@@ -168,7 +167,7 @@
      * the same uri as the default namespace; It's added to avoid changing the
      * current impl. which has many redundant code for the repair mode
      */
-    HashMap fAttrNamespace = null;
+    HashMap<String, String> fAttrNamespace = null;
 
     /**
      * Creates a new instance of XMLStreamWriterImpl. Uses platform's default
@@ -230,9 +229,9 @@
      */
     private void init() {
         fReuse = false;
-        fNamespaceDecls = new ArrayList();
+        fNamespaceDecls = new ArrayList<>();
         fPrefixGen = new Random();
-        fAttributeCache = new ArrayList();
+        fAttributeCache = new ArrayList<>();
         fInternalNamespaceContext = new NamespaceSupport();
         fInternalNamespaceContext.reset();
         fNamespaceContext = new NamespaceContextImpl();
@@ -240,9 +239,9 @@
 
         // Set internal state based on property values
         Boolean ob = (Boolean) fPropertyManager.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
-        fIsRepairingNamespace = ob.booleanValue();
+        fIsRepairingNamespace = ob;
         ob = (Boolean) fPropertyManager.getProperty(Constants.ESCAPE_CHARACTERS);
-        setEscapeCharacters(ob.booleanValue());
+        setEscapeCharacters(ob);
     }
 
     /**
@@ -279,9 +278,9 @@
 
         if (resetProperties) {
             Boolean ob = (Boolean) fPropertyManager.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
-            fIsRepairingNamespace = ob.booleanValue();
+            fIsRepairingNamespace = ob;
             ob = (Boolean) fPropertyManager.getProperty(Constants.ESCAPE_CHARACTERS);
-            setEscapeCharacters(ob.booleanValue());
+            setEscapeCharacters(ob);
         }
     }
 
@@ -369,6 +368,7 @@
     /**
      * Close this XMLStreamWriter by closing underlying writer.
      */
+    @Override
     public void close() throws XMLStreamException {
         if (fWriter != null) {
             try {
@@ -392,6 +392,7 @@
     /**
      * Flush this XMLStreamWriter by flushin underlying writer.
      */
+    @Override
     public void flush() throws XMLStreamException {
         try {
             fWriter.flush();
@@ -405,6 +406,7 @@
      *
      * @return NamespaceContext
      */
+    @Override
     public NamespaceContext getNamespaceContext() {
         return fNamespaceContext;
     }
@@ -416,6 +418,7 @@
      * @param  uri The namespace uri
      * @throws XMLStreamException if uri specified is "" or null
      */
+    @Override
     public String getPrefix(String uri) throws XMLStreamException {
         return fNamespaceContext.getPrefix(uri);
     }
@@ -427,6 +430,7 @@
      * @throws IllegalArgumentException if the specified property is not supported
      * @return value associated with the specified property.
      */
+    @Override
     public Object getProperty(String str)
         throws IllegalArgumentException {
         if (str == null) {
@@ -446,6 +450,7 @@
      *
      * @param uri Namespace URI
      */
+    @Override
     public void setDefaultNamespace(String uri) throws XMLStreamException {
         if (uri != null) {
             uri = fSymbolTable.addSymbol(uri);
@@ -479,6 +484,7 @@
      * @param namespaceContext the namespace context to use for this writer, may not be null
      * @throws XMLStreamException
      */
+    @Override
     public void setNamespaceContext(NamespaceContext namespaceContext)
         throws XMLStreamException {
         fNamespaceContext.userContext = namespaceContext;
@@ -493,6 +499,7 @@
      * @param uri
      * @throws XMLStreamException
      */
+    @Override
     public void setPrefix(String prefix, String uri) throws XMLStreamException {
 
         if (prefix == null) {
@@ -525,6 +532,7 @@
         fInternalNamespaceContext.declarePrefix(prefix, uri);
     }
 
+    @Override
     public void writeAttribute(String localName, String value)
         throws XMLStreamException {
         try {
@@ -554,6 +562,7 @@
         }
     }
 
+    @Override
     public void writeAttribute(String namespaceURI, String localName,
         String value) throws XMLStreamException {
         try {
@@ -590,7 +599,7 @@
         String value) throws IOException {
         fWriter.write(SPACE);
 
-        if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
+        if ((prefix != null) && (!prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))) {
             fWriter.write(prefix);
             fWriter.write(":");
         }
@@ -603,6 +612,7 @@
         fWriter.write("\"");
     }
 
+    @Override
     public void writeAttribute(String prefix, String namespaceURI,
         String localName, String value) throws XMLStreamException {
         try {
@@ -629,7 +639,8 @@
                     }
                 }
 
-                if (!prefix.equals(XMLConstants.XML_NS_PREFIX) || !namespaceURI.equals(XMLConstants.XML_NS_URI)) {
+                if (!prefix.equals(XMLConstants.XML_NS_PREFIX) ||
+                        !namespaceURI.equals(XMLConstants.XML_NS_URI)) {
 
                     prefix = fSymbolTable.addSymbol(prefix);
                     namespaceURI = fSymbolTable.addSymbol(namespaceURI);
@@ -663,6 +674,7 @@
         }
     }
 
+    @Override
     public void writeCData(String cdata) throws XMLStreamException {
         try {
             if (cdata == null) {
@@ -681,6 +693,7 @@
         }
     }
 
+    @Override
     public void writeCharacters(String data) throws XMLStreamException {
         try {
             if (fStartTagOpened) {
@@ -693,6 +706,7 @@
         }
     }
 
+    @Override
     public void writeCharacters(char[] data, int start, int len)
         throws XMLStreamException {
         try {
@@ -706,6 +720,7 @@
         }
     }
 
+    @Override
     public void writeComment(String comment) throws XMLStreamException {
         try {
             if (fStartTagOpened) {
@@ -724,6 +739,7 @@
         }
     }
 
+    @Override
     public void writeDTD(String dtd) throws XMLStreamException {
         try {
             if (fStartTagOpened) {
@@ -750,11 +766,12 @@
      * @see <a href="http://www.w3.org/TR/REC-xml-names/#defaulting">
      *   Namespaces in XML, 5.2 Namespace Defaulting</a>
      */
+    @Override
     public void writeDefaultNamespace(String namespaceURI)
         throws XMLStreamException {
 
         // normalize namespaceURI
-        String namespaceURINormalized = null;
+        String namespaceURINormalized;
         if (namespaceURI == null) {
             namespaceURINormalized = ""; // XMLConstants.NULL_NS_URI
         } else {
@@ -782,7 +799,7 @@
 
                 String tmp = fInternalNamespaceContext.getURI("");
 
-                if (tmp != null && tmp != namespaceURINormalized) {
+                if (tmp != null && !tmp.equals(namespaceURINormalized)) {
                         throw new XMLStreamException(
                                 "xmlns has been already bound to " +tmp +
                                 ". Rebinding it to "+ namespaceURINormalized +
@@ -798,6 +815,7 @@
         }
     }
 
+    @Override
     public void writeEmptyElement(String localName) throws XMLStreamException {
         try {
             if (fStartTagOpened) {
@@ -816,6 +834,7 @@
         }
     }
 
+    @Override
     public void writeEmptyElement(String namespaceURI, String localName)
         throws XMLStreamException {
         if (namespaceURI == null) {
@@ -828,6 +847,7 @@
         writeEmptyElement(prefix, localName, namespaceURI);
     }
 
+    @Override
     public void writeEmptyElement(String prefix, String localName,
         String namespaceURI) throws XMLStreamException {
         try {
@@ -863,7 +883,7 @@
                 return;
             }
 
-            if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
+            if ((prefix != null) && (!prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))) {
                 fWriter.write(prefix);
                 fWriter.write(":");
             }
@@ -874,16 +894,15 @@
         }
     }
 
+    @Override
     public void writeEndDocument() throws XMLStreamException {
         try {
             if (fStartTagOpened) {
                 closeStartTag();
             }
 
-            ElementState elem = null;
-
             while (!fElementStack.empty()) {
-                elem = (ElementState) fElementStack.pop();
+                ElementState elem = fElementStack.pop();
                 fInternalNamespaceContext.popContext();
 
                 if (elem.isEmpty) {
@@ -907,13 +926,14 @@
         }
     }
 
+    @Override
     public void writeEndElement() throws XMLStreamException {
         try {
             if (fStartTagOpened) {
                 closeStartTag();
             }
 
-            ElementState currentElement = (ElementState) fElementStack.pop();
+            ElementState currentElement = fElementStack.pop();
 
             if (currentElement == null) {
                 throw new XMLStreamException("No element was found to write");
@@ -944,6 +964,7 @@
         }
     }
 
+    @Override
     public void writeEntityRef(String refName) throws XMLStreamException {
         try {
             if (fStartTagOpened) {
@@ -973,11 +994,12 @@
      * @see <a href="http://www.w3.org/TR/REC-xml-names/#defaulting">
      *   Namespaces in XML, 5.2 Namespace Defaulting</a>
      */
+    @Override
     public void writeNamespace(String prefix, String namespaceURI)
         throws XMLStreamException {
 
         // normalize namespaceURI
-        String namespaceURINormalized = null;
+        String namespaceURINormalized;
         if (namespaceURI == null) {
             namespaceURINormalized = ""; // XMLConstants.NULL_NS_URI
         } else {
@@ -985,7 +1007,7 @@
         }
 
         try {
-            QName qname = null;
+            QName qname;
 
             if (!fStartTagOpened) {
                 throw new IllegalStateException(
@@ -1013,7 +1035,7 @@
             if (fIsRepairingNamespace) {
                 String tmpURI = fInternalNamespaceContext.getURI(prefix);
 
-                if ((tmpURI != null) && (tmpURI == namespaceURINormalized)) {
+                if ((tmpURI != null) && (tmpURI.equals(namespaceURINormalized))) {
                     return;
                 }
 
@@ -1030,7 +1052,7 @@
 
                 String tmp = fInternalNamespaceContext.getURI(prefix);
 
-                if (tmp != null && tmp != namespaceURINormalized) {
+                if (tmp != null && !tmp.equals(namespaceURINormalized)) {
 
                        throw new XMLStreamException("prefix "+prefix+
                             " has been already bound to " +tmp +
@@ -1051,7 +1073,7 @@
         throws IOException {
         fWriter.write(" xmlns");
 
-        if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
+        if ((prefix != null) && (!prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))) {
             fWriter.write(":");
             fWriter.write(prefix);
         }
@@ -1064,6 +1086,7 @@
         fWriter.write("\"");
     }
 
+    @Override
     public void writeProcessingInstruction(String target)
         throws XMLStreamException {
         try {
@@ -1090,6 +1113,7 @@
      * @param data
      * @throws XMLStreamException
      */
+    @Override
     public void writeProcessingInstruction(String target, String data)
         throws XMLStreamException {
         try {
@@ -1116,6 +1140,7 @@
      *
      * @throws XMLStreamException in case of an IOException
      */
+    @Override
     public void writeStartDocument() throws XMLStreamException {
         writeStartDocument(null, null, false, false);
     }
@@ -1126,6 +1151,7 @@
      * @param version the specified version
      * @throws XMLStreamException in case of an IOException
      */
+    @Override
     public void writeStartDocument(String version) throws XMLStreamException {
         writeStartDocument(null, version, false, false);
     }
@@ -1143,7 +1169,6 @@
         writeStartDocument(encoding, version, false, false);
     }
 
-    @Override
     public void writeStartDocument(String encoding, String version,
             boolean standalone, boolean standaloneSet)
         throws XMLStreamException {
@@ -1212,9 +1237,9 @@
         if (streamEncoding != null && !streamEncoding.equalsIgnoreCase(encoding)) {
             // If the equality check failed, check for charset encoding aliases
             boolean foundAlias = false;
-            Set aliases = Charset.forName(encoding).aliases();
-            for (Iterator it = aliases.iterator(); !foundAlias && it.hasNext(); ) {
-                if (streamEncoding.equalsIgnoreCase((String) it.next())) {
+            Set<String> aliases = Charset.forName(encoding).aliases();
+            for (Iterator<String> it = aliases.iterator(); !foundAlias && it.hasNext(); ) {
+                if (streamEncoding.equalsIgnoreCase(it.next())) {
                     foundAlias = true;
                 }
             }
@@ -1232,6 +1257,7 @@
      * @param localName
      * @throws XMLStreamException
      */
+    @Override
     public void writeStartElement(String localName) throws XMLStreamException {
         try {
             if (localName == null) {
@@ -1261,6 +1287,7 @@
      * @param localName
      * @throws XMLStreamException
      */
+    @Override
     public void writeStartElement(String namespaceURI, String localName)
         throws XMLStreamException {
         if (localName == null) {
@@ -1292,6 +1319,7 @@
      * @param namespaceURI
      * @throws XMLStreamException
      */
+    @Override
     public void writeStartElement(String prefix, String localName,
         String namespaceURI) throws XMLStreamException {
         try {
@@ -1537,10 +1565,10 @@
                 fWriter.write(currentElement.localpart);
 
                 int len = fNamespaceDecls.size();
-                QName qname = null;
+                QName qname;
 
                 for (int i = 0; i < len; i++) {
-                    qname = (QName) fNamespaceDecls.get(i);
+                    qname = fNamespaceDecls.get(i);
 
                     if (qname != null) {
                         if (fInternalNamespaceContext.declarePrefix(qname.prefix,
@@ -1552,16 +1580,16 @@
 
                 fNamespaceDecls.clear();
 
-                Attribute attr = null;
+                Attribute attr;
 
                 for (int j = 0; j < fAttributeCache.size(); j++) {
-                    attr = (Attribute) fAttributeCache.get(j);
+                    attr = fAttributeCache.get(j);
 
                     if ((attr.prefix != null) && (attr.uri != null)) {
                         if (!attr.prefix.equals("") && !attr.uri.equals("") ) {
                             String tmp = fInternalNamespaceContext.getPrefix(attr.uri);
 
-                            if ((tmp == null) || (tmp != attr.prefix)) {
+                            if ((tmp == null) || (!tmp.equals(attr.prefix))) {
                                 tmp = getAttrPrefix(attr.uri);
                                 if (tmp == null) {
                                     if (fInternalNamespaceContext.declarePrefix(attr.prefix,
@@ -1611,29 +1639,29 @@
      * @return
      */
     private void correctPrefix(QName attr, int type) {
-        String tmpPrefix = null;
+        String tmpPrefix;
         String prefix;
         String uri;
         prefix = attr.prefix;
         uri = attr.uri;
         boolean isSpecialCaseURI = false;
 
-        if (prefix == null || prefix.equals("")) {
+        if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
             if (uri == null) {
                 return;
             }
 
-            if (prefix == XMLConstants.DEFAULT_NS_PREFIX && uri == XMLConstants.DEFAULT_NS_PREFIX)
+            if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix) && uri.equals(XMLConstants.DEFAULT_NS_PREFIX))
                 return;
 
             uri = fSymbolTable.addSymbol(uri);
 
-            QName decl = null;
+            QName decl;
 
             for (int i = 0; i < fNamespaceDecls.size(); i++) {
-                decl = (QName) fNamespaceDecls.get(i);
+                decl = fNamespaceDecls.get(i);
 
-                if ((decl != null) && (decl.uri == attr.uri)) {
+                if ((decl != null) && (decl.uri.equals(attr.uri))) {
                     attr.prefix = decl.prefix;
 
                     return;
@@ -1642,7 +1670,7 @@
 
             tmpPrefix = fNamespaceContext.getPrefix(uri);
 
-            if (tmpPrefix == XMLConstants.DEFAULT_NS_PREFIX) {
+            if (XMLConstants.DEFAULT_NS_PREFIX.equals(tmpPrefix)) {
                 if (type == XMLStreamConstants.START_ELEMENT) {
                     return;
                 }
@@ -1654,7 +1682,7 @@
             }
 
             if (tmpPrefix == null) {
-                StringBuffer genPrefix = new StringBuffer("zdef");
+                StringBuilder genPrefix = new StringBuilder("zdef");
 
                 for (int i = 0; i < 1; i++) {
                     genPrefix.append(fPrefixGen.nextInt());
@@ -1687,13 +1715,13 @@
      */
     private String getAttrPrefix(String uri) {
         if (fAttrNamespace != null) {
-            return (String)fAttrNamespace.get(uri);
+            return fAttrNamespace.get(uri);
         }
         return null;
     }
     private void addAttrNamespace(String prefix, String uri) {
         if (fAttrNamespace == null) {
-            fAttrNamespace = new HashMap();
+            fAttrNamespace = new HashMap<>();
         }
         fAttrNamespace.put(prefix, uri);
     }
@@ -1704,7 +1732,7 @@
     private boolean isDefaultNamespace(String uri) {
         String defaultNamespace = fInternalNamespaceContext.getURI(DEFAULT_PREFIX);
 
-        if (uri == defaultNamespace) {
+        if (uri.equals(defaultNamespace)) {
             return true;
         }
 
@@ -1732,13 +1760,13 @@
      * Correct's namespaces  as per requirements of isReparisingNamespace property.
      */
     protected void repair() {
-        Attribute attr = null;
-        Attribute attr2 = null;
+        Attribute attr;
+        Attribute attr2;
         ElementState currentElement = fElementStack.peek();
         removeDuplicateDecls();
 
         for(int i=0 ; i< fAttributeCache.size();i++){
-            attr = (Attribute)fAttributeCache.get(i);
+            attr = fAttributeCache.get(i);
             if((attr.prefix != null && !attr.prefix.equals("")) || (attr.uri != null && !attr.uri.equals(""))) {
                 correctPrefix(currentElement,attr);
             }
@@ -1754,9 +1782,9 @@
         }
 
         for(int i=0 ; i< fAttributeCache.size();i++){
-            attr = (Attribute)fAttributeCache.get(i);
+            attr = fAttributeCache.get(i);
             for(int j=i+1;j<fAttributeCache.size();j++){
-                attr2 = (Attribute)fAttributeCache.get(j);
+                attr2 = fAttributeCache.get(j);
                 if(!"".equals(attr.prefix)&& !"".equals(attr2.prefix)){
                     correctPrefix(attr,attr2);
                 }
@@ -1765,10 +1793,10 @@
 
         repairNamespaceDecl(currentElement);
 
-        int i = 0;
+        int i;
 
         for (i = 0; i < fAttributeCache.size(); i++) {
-            attr = (Attribute) fAttributeCache.get(i);
+            attr = fAttributeCache.get(i);
             /* If 'attr' is an attribute and it is in no namespace(which means that prefix="", uri=""), attr's
                namespace should not be redinded. See [http://www.w3.org/TR/REC-xml-names/#defaulting].
              */
@@ -1780,7 +1808,7 @@
         QName qname = null;
 
         for (i = 0; i < fNamespaceDecls.size(); i++) {
-            qname = (QName) fNamespaceDecls.get(i);
+            qname = fNamespaceDecls.get(i);
 
             if (qname != null) {
                 fInternalNamespaceContext.declarePrefix(qname.prefix, qname.uri);
@@ -1788,7 +1816,7 @@
         }
 
         for (i = 0; i < fAttributeCache.size(); i++) {
-            attr = (Attribute) fAttributeCache.get(i);
+            attr = fAttributeCache.get(i);
             correctPrefix(attr, XMLStreamConstants.ATTRIBUTE);
         }
     }
@@ -1801,9 +1829,8 @@
      *that is bound to the namespace URIs of those attributes.
      */
     void correctPrefix(QName attr1, QName attr2) {
-        String tmpPrefix = null;
-        QName decl = null;
-        boolean done = false;
+        String tmpPrefix;
+        QName decl;
 
         checkForNull(attr1);
         checkForNull(attr2);
@@ -1815,10 +1842,9 @@
             if (tmpPrefix != null) {
                 attr2.prefix = fSymbolTable.addSymbol(tmpPrefix);
             } else {
-                decl = null;
-                for(int n=0;n<fNamespaceDecls.size();n++){
-                    decl = (QName)fNamespaceDecls.get(n);
-                    if(decl != null && (decl.uri == attr2.uri)){
+                for (int n=0; n<fNamespaceDecls.size(); n++) {
+                    decl = fNamespaceDecls.get(n);
+                    if(decl != null && (decl.uri.equals(attr2.uri))){
                         attr2.prefix = decl.prefix;
 
                         return;
@@ -1826,7 +1852,7 @@
                 }
 
                 //No namespace mapping found , so declare prefix.
-                StringBuffer genPrefix = new StringBuffer("zdef");
+                StringBuilder genPrefix = new StringBuilder("zdef");
 
                 for (int k = 0; k < 1; k++) {
                     genPrefix.append(fPrefixGen.nextInt());
@@ -1851,11 +1877,11 @@
 
     void removeDuplicateDecls(){
         QName decl1,decl2;
-        for(int i =0;i<fNamespaceDecls.size();i++){
-            decl1 = (QName)fNamespaceDecls.get(i);
+        for(int i =0; i<fNamespaceDecls.size(); i++) {
+            decl1 = fNamespaceDecls.get(i);
             if(decl1!=null) {
                 for(int j=i+1;j<fNamespaceDecls.size();j++){
-                    decl2 = (QName)fNamespaceDecls.get(j);
+                    decl2 = fNamespaceDecls.get(j);
                     // QName.equals relies on identity equality, so we can't use it,
                     // because prefixes aren't interned
                     if(decl2!=null && decl1.prefix.equals(decl2.prefix) && decl1.uri.equals(decl2.uri))
@@ -1873,12 +1899,12 @@
      *
      */
     void repairNamespaceDecl(QName attr) {
-        QName decl = null;
+        QName decl;
         String tmpURI;
 
         //check for null prefix.
         for (int j = 0; j < fNamespaceDecls.size(); j++) {
-            decl = (QName) fNamespaceDecls.get(j);
+            decl = fNamespaceDecls.get(j);
 
             if (decl != null) {
                 if ((attr.prefix != null) &&
@@ -1900,13 +1926,13 @@
     }
 
     boolean isDeclared(QName attr) {
-        QName decl = null;
+        QName decl;
 
         for (int n = 0; n < fNamespaceDecls.size(); n++) {
-            decl = (QName) fNamespaceDecls.get(n);
+            decl = fNamespaceDecls.get(n);
 
             if ((attr.prefix != null) &&
-                    ((attr.prefix == decl.prefix) && (decl.uri == attr.uri))) {
+                    ((attr.prefix.equals(decl.prefix)) && (decl.uri.equals(attr.uri)))) {
                 return true;
             }
         }
@@ -2121,9 +2147,10 @@
             return null;
         }
 
-        public java.util.Iterator getPrefixes(String uri) {
+        //Cleanup note: leaving these warnings to a xerces.internal.util cleanup
+        public Iterator<String> getPrefixes(String uri) {
             Vector prefixes = null;
-            Iterator itr = null;
+            Iterator<String> itr = null;
 
             if (uri != null) {
                 uri = fSymbolTable.addSymbol(uri);
@@ -2140,12 +2167,12 @@
             if ((prefixes == null) && (itr != null)) {
                 return itr;
             } else if ((prefixes != null) && (itr == null)) {
-                return new ReadOnlyIterator(prefixes.iterator());
+                return new ReadOnlyIterator<>(prefixes.iterator());
             } else if ((prefixes != null) && (itr != null)) {
                 String ob = null;
 
                 while (itr.hasNext()) {
-                    ob = (String) itr.next();
+                    ob = itr.next();
 
                     if (ob != null) {
                         ob = fSymbolTable.addSymbol(ob);
@@ -2156,7 +2183,7 @@
                     }
                 }
 
-                return new ReadOnlyIterator(prefixes.iterator());
+                return new ReadOnlyIterator<>(prefixes.iterator());
             }
 
             return fReadOnlyIterator;
@@ -2165,14 +2192,17 @@
 
     // -- Map Interface --------------------------------------------------
 
+    @Override
     public int size() {
         return 1;
     }
 
+    @Override
     public boolean isEmpty() {
         return false;
     }
 
+    @Override
     public boolean containsKey(Object key) {
         return key.equals(OUTPUTSTREAM_PROPERTY);
     }
@@ -2181,6 +2211,7 @@
      * Returns the value associated to an implementation-specific
      * property.
      */
+    @Override
     public Object get(Object key) {
         if (key.equals(OUTPUTSTREAM_PROPERTY)) {
             return fOutputStream;
@@ -2188,7 +2219,8 @@
         return null;
     }
 
-    public java.util.Set entrySet() {
+    @Override
+    public Set<Entry<Object,Object>> entrySet() {
         throw new UnsupportedOperationException();
     }
 
@@ -2198,6 +2230,7 @@
      * AbstractMap would cause an unsupported exection to
      * be thrown.
      */
+    @Override
     public String toString() {
         return getClass().getName() + "@" + Integer.toHexString(hashCode());
     }
@@ -2206,6 +2239,7 @@
      * Overrides the method defined in AbstractMap
      * This is required by the toString() method
      */
+    @Override
     public int hashCode() {
         return fElementStack.hashCode();
     }
@@ -2213,6 +2247,7 @@
      * Overrides the method defined in AbstractMap
      * This is required to satisfy the contract for hashCode.
      */
+    @Override
     public boolean equals(Object obj) {
         return (this == obj);
     }
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/datatype/FactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/datatype/FactoryFinder.java
index 72ee2e5..770284a 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/datatype/FactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/datatype/FactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * <p>Implements pluggable Datatypes.</p>
@@ -80,9 +81,9 @@
         }
     }
 
-    private static void dPrint(String msg) {
+    private static void dPrint(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -190,10 +191,9 @@
                 throw new ClassCastException(className + " cannot be cast to " + type.getName());
             }
             Object instance = providerClass.newInstance();
-            if (debug) {    // Extra check to avoid computing cl strings
-                dPrint("created new instance of " + providerClass +
-                       " using ClassLoader: " + cl);
-            }
+            final ClassLoader clD = cl;
+            dPrint(()->"created new instance of " + providerClass +
+                       " using ClassLoader: " + clD);
             return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
@@ -223,13 +223,13 @@
         throws DatatypeConfigurationException
     {
         final String factoryId = type.getName();
-        dPrint("find factoryId =" + factoryId);
+        dPrint(()->"find factoryId =" + factoryId);
 
         // Use the system property first
         try {
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
-                dPrint("found system property, value=" + systemProp);
+                dPrint(()->"found system property, value=" + systemProp);
                 return newInstance(type, systemProp, null, true);
             }
         }
@@ -247,7 +247,7 @@
                         File f = new File(configFile);
                         firstTime = false;
                         if (ss.doesFileExist(f)) {
-                            dPrint("Read properties file "+f);
+                            dPrint(()->"Read properties file "+f);
                             cacheProps.load(ss.getFileInputStream(f));
                         }
                     }
@@ -256,7 +256,7 @@
             final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
-                dPrint("found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
+                dPrint(()->"found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
                 return newInstance(type, factoryClassName, null, true);
             }
         }
@@ -274,7 +274,7 @@
                 "Provider for " + factoryId + " cannot be found");
         }
 
-        dPrint("loaded from fallback value: " + fallbackClassName);
+        dPrint(()->"loaded from fallback value: " + fallbackClassName);
         return newInstance(type, fallbackClassName, null, true);
     }
 
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/parsers/FactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/parsers/FactoryFinder.java
index e17b4dd..88a772d 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/parsers/FactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/parsers/FactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * <p>Implements pluggable Parsers.</p>
@@ -80,9 +81,9 @@
         }
     }
 
-    private static void dPrint(String msg) {
+    private static void dPrint(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -190,10 +191,9 @@
                 throw new ClassCastException(className + " cannot be cast to " + type.getName());
             }
             Object instance = providerClass.newInstance();
-            if (debug) {    // Extra check to avoid computing cl strings
-                dPrint("created new instance of " + providerClass +
-                       " using ClassLoader: " + cl);
-            }
+            final ClassLoader clD = cl;
+            dPrint(()->"created new instance of " + providerClass +
+                       " using ClassLoader: " + clD);
             return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
@@ -222,13 +222,13 @@
         throws FactoryConfigurationError
     {
         final String factoryId = type.getName();
-        dPrint("find factoryId =" + factoryId);
+        dPrint(()->"find factoryId =" + factoryId);
 
         // Use the system property first
         try {
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
-                dPrint("found system property, value=" + systemProp);
+                dPrint(()->"found system property, value=" + systemProp);
                 return newInstance(type, systemProp, null, true);
             }
         }
@@ -246,7 +246,7 @@
                         File f = new File(configFile);
                         firstTime = false;
                         if (ss.doesFileExist(f)) {
-                            dPrint("Read properties file "+f);
+                            dPrint(()->"Read properties file "+f);
                             cacheProps.load(ss.getFileInputStream(f));
                         }
                     }
@@ -255,7 +255,7 @@
             final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
-                dPrint("found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
+                dPrint(()->"found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
                 return newInstance(type, factoryClassName, null, true);
             }
         }
@@ -273,7 +273,7 @@
                 "Provider for " + factoryId + " cannot be found");
         }
 
-        dPrint("loaded from fallback value: " + fallbackClassName);
+        dPrint(()->"loaded from fallback value: " + fallbackClassName);
         return newInstance(type, fallbackClassName, null, true);
     }
 
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/EventFilter.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/EventFilter.java
index 61feecb..4c9e5ff 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/EventFilter.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/EventFilter.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import javax.xml.stream.events.XMLEvent;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java
index 6192f3d..2351f59 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,9 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
 
 package javax.xml.stream;
 
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryFinder.java
index c9c4a08..2496e20 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/FactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * <p>Implements pluggable streams.</p>
@@ -81,9 +82,9 @@
         }
     }
 
-    private static void dPrint(String msg) {
+    private static void dPrint(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -191,10 +192,9 @@
                 throw new ClassCastException(className + " cannot be cast to " + type.getName());
             }
             Object instance = providerClass.newInstance();
-            if (debug) {    // Extra check to avoid computing cl strings
-                dPrint("created new instance of " + providerClass +
-                       " using ClassLoader: " + cl);
-            }
+            final ClassLoader clD = cl;
+            dPrint(()->"created new instance of " + providerClass +
+                       " using ClassLoader: " + clD);
             return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
@@ -249,7 +249,7 @@
     static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName)
         throws FactoryConfigurationError
     {
-        dPrint("find factoryId =" + factoryId);
+        dPrint(()->"find factoryId =" + factoryId);
 
         // Use the system property first
         try {
@@ -261,7 +261,7 @@
                 systemProp = System.getProperty(factoryId);
             }
             if (systemProp != null) {
-                dPrint("found system property, value=" + systemProp);
+                dPrint(()->"found system property, value=" + systemProp);
                 return newInstance(type, systemProp, cl, true);
             }
         }
@@ -279,19 +279,19 @@
                     if (firstTime) {
                         configFile = ss.getSystemProperty("java.home") + File.separator +
                             "lib" + File.separator + "stax.properties";
-                        File f = new File(configFile);
+                        final File fStax = new File(configFile);
                         firstTime = false;
-                        if (ss.doesFileExist(f)) {
-                            dPrint("Read properties file "+f);
-                            cacheProps.load(ss.getFileInputStream(f));
+                        if (ss.doesFileExist(fStax)) {
+                            dPrint(()->"Read properties file "+fStax);
+                            cacheProps.load(ss.getFileInputStream(fStax));
                         }
                         else {
                             configFile = ss.getSystemProperty("java.home") + File.separator +
                                 "conf" + File.separator + "jaxp.properties";
-                            f = new File(configFile);
-                            if (ss.doesFileExist(f)) {
-                                dPrint("Read properties file "+f);
-                                cacheProps.load(ss.getFileInputStream(f));
+                            final File fJaxp = new File(configFile);
+                            if (ss.doesFileExist(fJaxp)) {
+                                dPrint(()->"Read properties file "+fJaxp);
+                                cacheProps.load(ss.getFileInputStream(fJaxp));
                             }
                         }
                     }
@@ -300,7 +300,8 @@
             final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
-                dPrint("found in " + configFile + " value=" + factoryClassName);
+                final String foundIn = configFile;
+                dPrint(()->"found in " + foundIn + " value=" + factoryClassName);
                 return newInstance(type, factoryClassName, cl, true);
             }
         }
@@ -325,7 +326,7 @@
                 "Provider for " + factoryId + " cannot be found", null);
         }
 
-        dPrint("loaded from fallback value: " + fallbackClassName);
+        dPrint(()->"loaded from fallback value: " + fallbackClassName);
         return newInstance(type, fallbackClassName, cl, true);
     }
 
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/Location.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/Location.java
index 74a25f3..f9fb34f 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/Location.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/Location.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/SecuritySupport.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/SecuritySupport.java
index b4d81c3..328c49c 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/SecuritySupport.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/SecuritySupport.java
@@ -39,53 +39,34 @@
 
 
     ClassLoader getContextClassLoader() throws SecurityException{
-        return (ClassLoader)
-                AccessController.doPrivileged(new PrivilegedAction() {
-            public Object run() {
-                ClassLoader cl = null;
-                //try {
-                cl = Thread.currentThread().getContextClassLoader();
-                //} catch (SecurityException ex) { }
+        return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
 
-                if (cl == null)
-                    cl = ClassLoader.getSystemClassLoader();
+            if (cl == null)
+                cl = ClassLoader.getSystemClassLoader();
 
-                return cl;
-            }
+            return cl;
         });
     }
 
     String getSystemProperty(final String propName) {
-        return (String)
-            AccessController.doPrivileged(new PrivilegedAction() {
-                public Object run() {
-                    return System.getProperty(propName);
-                }
-            });
+        return AccessController.doPrivileged((PrivilegedAction<String>) () ->
+                System.getProperty(propName));
     }
 
     FileInputStream getFileInputStream(final File file)
         throws FileNotFoundException
     {
         try {
-            return (FileInputStream)
-                AccessController.doPrivileged(new PrivilegedExceptionAction() {
-                    public Object run() throws FileNotFoundException {
-                        return new FileInputStream(file);
-                    }
-                });
+            return AccessController.doPrivileged((PrivilegedExceptionAction<FileInputStream>) ()
+                    -> new FileInputStream(file));
         } catch (PrivilegedActionException e) {
             throw (FileNotFoundException)e.getException();
         }
     }
 
     boolean doesFileExist(final File f) {
-    return ((Boolean)
-            AccessController.doPrivileged(new PrivilegedAction() {
-                public Object run() {
-                    return new Boolean(f.exists());
-                }
-            })).booleanValue();
+        return AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> f.exists());
     }
 
 }
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/StreamFilter.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/StreamFilter.java
index d248d6d..b2e967f 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/StreamFilter.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/StreamFilter.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java
index 37e5f7a..9428a2e 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventFactory.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009, 2015, by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 import com.sun.xml.internal.stream.events.XMLEventFactoryImpl;
 import java.util.Iterator;
@@ -53,8 +50,7 @@
     static final String JAXPFACTORYID = "javax.xml.stream.XMLEventFactory";
     static final String DEFAULIMPL = "com.sun.xml.internal.stream.events.XMLEventFactoryImpl";
 
-
-  /**
+   /**
    * Creates a new instance of the {@code XMLEventFactory} builtin
    * system-default implementation.
    *
@@ -159,6 +155,7 @@
    *              #newFactory(java.lang.String, java.lang.ClassLoader)}
    *              method defines no changes in behavior.
    */
+  @Deprecated(since="7")
   public static XMLEventFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
@@ -307,8 +304,8 @@
    * @return an instance of the requested StartElement
    */
   public abstract StartElement createStartElement(QName name,
-                                                  Iterator attributes,
-                                                  Iterator namespaces);
+                                                  Iterator<? extends Attribute> attributes,
+                                                  Iterator<? extends Namespace> namespaces);
 
   /**
    * Create a new StartElement.  This defaults the NamespaceContext to
@@ -341,8 +338,8 @@
   public abstract StartElement createStartElement(String prefix,
                                                   String namespaceUri,
                                                   String localName,
-                                                  Iterator attributes,
-                                                  Iterator namespaces
+                                                  Iterator<? extends Attribute> attributes,
+                                                  Iterator<? extends Namespace> namespaces
                                                   );
   /**
    * Create a new StartElement.  Namespaces can be added to this StartElement
@@ -363,8 +360,8 @@
   public abstract StartElement createStartElement(String prefix,
                                                   String namespaceUri,
                                                   String localName,
-                                                  Iterator attributes,
-                                                  Iterator namespaces,
+                                                  Iterator<? extends Attribute> attributes,
+                                                  Iterator<? extends Namespace> namespaces,
                                                   NamespaceContext context
                                                   );
 
@@ -376,7 +373,7 @@
    * @return an instance of the requested EndElement
    */
   public abstract EndElement createEndElement(QName name,
-                                              Iterator namespaces);
+                                              Iterator<? extends Namespace> namespaces);
 
   /**
    * Create a new EndElement
@@ -400,7 +397,7 @@
   public abstract EndElement createEndElement(String prefix,
                                               String namespaceUri,
                                               String localName,
-                                              Iterator namespaces);
+                                              Iterator<? extends Namespace> namespaces);
 
   /**
    * Create a Characters event, this method does not check if the content
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java
index 30050ba..d20fe24 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import javax.xml.stream.events.XMLEvent;
@@ -44,7 +41,7 @@
  * @see XMLEventWriter
  * @since 1.6
  */
-public interface XMLEventReader extends Iterator {
+public interface XMLEventReader extends Iterator<Object> {
   /**
    * Gets the next XMLEvent. The initial event is
    * {@link javax.xml.stream.events.StartDocument StartDocument}.
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventWriter.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventWriter.java
index f389da6..e94feae 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventWriter.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventWriter.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import javax.xml.stream.events.*;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLInputFactory.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLInputFactory.java
index cb936ac..717dee5 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLInputFactory.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLInputFactory.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import com.sun.xml.internal.stream.XMLInputFactoryImpl;
@@ -225,6 +222,7 @@
    *   java.util.ServiceConfigurationError service configuration error} or if
    *   the implementation is not available or cannot be instantiated.
    */
+  @Deprecated(since="7")
   public static XMLInputFactory newFactory()
     throws FactoryConfigurationError
   {
@@ -246,6 +244,7 @@
    *              #newFactory(java.lang.String, java.lang.ClassLoader)} method
    *              defines no changes in behavior.
    */
+  @Deprecated(since="7")
   public static XMLInputFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLOutputFactory.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLOutputFactory.java
index 939cb67..50b6ba7 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLOutputFactory.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLOutputFactory.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import com.sun.xml.internal.stream.XMLOutputFactoryImpl;
@@ -121,7 +118,7 @@
 
   protected XMLOutputFactory(){}
 
-  /**
+   /**
    * Creates a new instance of the {@code XMLOutputFactory} builtin
    * system-default implementation.
    *
@@ -225,6 +222,7 @@
    *              Use the new method {@link #newFactory(java.lang.String,
    *              java.lang.ClassLoader)} instead.
    */
+  @Deprecated(since="7")
   public static XMLInputFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLReporter.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLReporter.java
index f78648e..6cf5cb9 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLReporter.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLReporter.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLResolver.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLResolver.java
index dbb177b..c43eb26 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLResolver.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLResolver.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamConstants.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamConstants.java
index 6ceb1c6..ab50fd2 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamConstants.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamConstants.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java
index 48e510c..4b3d644 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java
index 102228b..23322b9 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import javax.xml.namespace.NamespaceContext;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java
index ca05fc0..6fc1722 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamWriter.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream;
 
 import javax.xml.namespace.NamespaceContext;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Attribute.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Attribute.java
index 248d060..ffc5350 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Attribute.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Attribute.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import javax.xml.namespace.QName;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Characters.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Characters.java
index 76dab7f..ab59dcb 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Characters.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Characters.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Comment.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Comment.java
index 8ed0929..1ebee8f 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Comment.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Comment.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/DTD.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/DTD.java
index 3b0bb9f..e9d5ba4 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/DTD.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/DTD.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import java.util.List;
@@ -39,36 +36,40 @@
  */
 public interface DTD extends XMLEvent {
 
-  /**
-   * Returns the entire Document Type Declaration as a string, including
-   * the internal DTD subset.
-   * This may be null if there is not an internal subset.
-   * If it is not null it must return the entire
-   * Document Type Declaration which matches the doctypedecl
-   * production in the XML 1.0 specification
-   */
-  String getDocumentTypeDeclaration();
+    /**
+     * Returns the entire Document Type Declaration as a string, including the
+     * internal DTD subset. This may be null if there is not an internal subset.
+     * If it is not null it must return the entire Document Type Declaration
+     * which matches the doctypedecl production in the XML 1.0 specification
+     *
+     * @return the Document Type Declaration
+     */
+    String getDocumentTypeDeclaration();
 
-  /**
-   * Returns an implementation defined representation of the DTD.
-   * This method may return null if no representation is available.
-   */
-  Object getProcessedDTD();
+    /**
+     * Returns an implementation defined representation of the DTD. This method
+     * may return null if no representation is available.
+     *
+     * @return the representation of the DTD
+     */
+    Object getProcessedDTD();
 
-  /**
-   * Return a List containing the notations declared in the DTD.
-   * This list must contain NotationDeclaration events.
-   * @see NotationDeclaration
-   * @return an unordered list of NotationDeclaration events
-   */
-  List getNotations();
+    /**
+     * Return a List containing the notations declared in the DTD. This list
+     * must contain NotationDeclaration events.
+     *
+     * @see NotationDeclaration
+     * @return an unordered list of NotationDeclaration events
+     */
+    List<NotationDeclaration> getNotations();
 
-  /**
-   * Return a List containing the general entities,
-   * both external and internal, declared in the DTD.
-   * This list must contain EntityDeclaration events.
-   * @see EntityDeclaration
-   * @return an unordered list of EntityDeclaration events
-   */
-  List getEntities();
+    /**
+     * Return a List containing the general entities, both external and
+     * internal, declared in the DTD. This list must contain EntityDeclaration
+     * events.
+     *
+     * @see EntityDeclaration
+     * @return an unordered list of EntityDeclaration events
+     */
+    List<EntityDeclaration> getEntities();
 }
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndDocument.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndDocument.java
index 0e7ab31..20e89cc 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndDocument.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndDocument.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndElement.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndElement.java
index fd6d5f2..76575f9 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndElement.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EndElement.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import java.util.Iterator;
@@ -54,6 +51,6 @@
    * @return an Iterator over Namespace interfaces, or an
    * empty iterator
    */
-  public Iterator getNamespaces();
+  public Iterator<Namespace> getNamespaces();
 
 }
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityDeclaration.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityDeclaration.java
index 74610da..5edb683 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityDeclaration.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityDeclaration.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 /**
  * An interface for handling Entity Declarations
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityReference.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityReference.java
index 8871460..0087b0a 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityReference.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/EntityReference.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 /**
  * An interface for handling Entity events.
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Namespace.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Namespace.java
index df5e6bd..fac3a7e 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Namespace.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/Namespace.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import javax.xml.namespace.QName;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/NotationDeclaration.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/NotationDeclaration.java
index fc5f790..6d5ba68 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/NotationDeclaration.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/NotationDeclaration.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 /**
  * An interface for handling Notation Declarations
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/ProcessingInstruction.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/ProcessingInstruction.java
index 9ee77d8..4fb2df3 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/ProcessingInstruction.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/ProcessingInstruction.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 /**
  * An interface that describes the data found in processing instructions
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartDocument.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartDocument.java
index d46c070..6cd1fc4 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartDocument.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartDocument.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 /**
  * An interface for the start document event
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartElement.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartElement.java
index 9b286a6..4336c1b 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartElement.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/StartElement.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,16 +23,10 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import javax.xml.namespace.QName;
 import javax.xml.namespace.NamespaceContext;
-
-import java.util.Map;
 import java.util.Iterator;
 
 /**
@@ -62,7 +57,7 @@
    * @return a readonly Iterator over Attribute interfaces, or an
    * empty iterator
    */
-  public Iterator getAttributes();
+  public Iterator<Attribute> getAttributes();
 
   /**
    * Returns an Iterator of namespaces declared on this element.
@@ -87,7 +82,7 @@
    * empty iterator
    *
    */
-  public Iterator getNamespaces();
+  public Iterator<Namespace> getNamespaces();
 
   /**
    * Returns the attribute referred to by this name
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/XMLEvent.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/XMLEvent.java
index 338b5cb..43f8bec 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/events/XMLEvent.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/events/XMLEvent.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.events;
 
 import java.io.Writer;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java
index 9e2fbd3..b7600ac 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,17 +23,10 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.util;
 
-import javax.xml.namespace.QName;
-import javax.xml.namespace.NamespaceContext;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.Location;
 import javax.xml.stream.XMLStreamException;
 
 /**
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java
index f04a985..f94d1db 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,13 +23,8 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.util;
 
-import java.io.Reader;
 import javax.xml.namespace.QName;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.stream.XMLStreamReader;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventAllocator.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventAllocator.java
index 11e6e7c..dbcfea0 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventAllocator.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventAllocator.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.util;
 
 import javax.xml.stream.events.XMLEvent;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventConsumer.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventConsumer.java
index 062f706..b1ba160 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventConsumer.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/util/XMLEventConsumer.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +23,6 @@
  * questions.
  */
 
-/*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
- */
-
 package javax.xml.stream.util;
 
 import javax.xml.stream.events.XMLEvent;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/FactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/FactoryFinder.java
index 2577230..99413a2 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/transform/FactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/FactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * <p>Implements pluggable Datatypes.</p>
@@ -83,9 +84,9 @@
         }
     }
 
-    private static void dPrint(String msg) {
+    private static void dPrint(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -177,10 +178,9 @@
             if (instance == null) {
                 instance = providerClass.newInstance();
             }
-            if (debug) {    // Extra check to avoid computing cl strings
-                dPrint("created new instance of " + providerClass +
-                       " using ClassLoader: " + cl);
-            }
+            final ClassLoader clD = cl;
+            dPrint(()->"created new instance of " + providerClass +
+                       " using ClassLoader: " + clD);
             return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
@@ -255,12 +255,12 @@
 
         final String factoryId = type.getName();
 
-        dPrint("find factoryId =" + factoryId);
+        dPrint(()->"find factoryId =" + factoryId);
         // Use the system property first
         try {
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
-                dPrint("found system property, value=" + systemProp);
+                dPrint(()->"found system property, value=" + systemProp);
                 return newInstance(type, systemProp, null, true, true);
             }
         }
@@ -278,7 +278,7 @@
                         File f = new File(configFile);
                         firstTime = false;
                         if (ss.doesFileExist(f)) {
-                            dPrint("Read properties file "+f);
+                            dPrint(()->"Read properties file "+f);
                             cacheProps.load(ss.getFileInputStream(f));
                         }
                     }
@@ -287,7 +287,7 @@
             final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
-                dPrint("found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
+                dPrint(()->"found in ${java.home}/conf/jaxp.properties, value=" + factoryClassName);
                 return newInstance(type, factoryClassName, null, true, true);
             }
         }
@@ -305,7 +305,7 @@
                 "Provider for " + factoryId + " cannot be found");
         }
 
-        dPrint("loaded from fallback value: " + fallbackClassName);
+        dPrint(()->"loaded from fallback value: " + fallbackClassName);
         return newInstance(type, fallbackClassName, null, true, true);
     }
 
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
index b0ae3a4..8128829 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * Implementation of {@link SchemaFactory#newInstance(String)}.
@@ -72,11 +73,11 @@
     /**
      * <p>Conditional debug printing.</p>
      *
-     * @param msg to print
+     * @param msgGen Supplier function that returns debug message
      */
-    private static void debugPrintln(String msg) {
+    private static void debugPrintln(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -106,7 +107,7 @@
     private void debugDisplayClassLoader() {
         try {
             if( classLoader == ss.getContextClassLoader() ) {
-                debugPrintln("using thread context class loader ("+classLoader+") for search");
+                debugPrintln(()->"using thread context class loader ("+classLoader+") for search");
                 return;
             }
         } catch( Throwable unused ) {
@@ -114,11 +115,11 @@
         }
 
         if( classLoader==ClassLoader.getSystemClassLoader() ) {
-            debugPrintln("using system class loader ("+classLoader+") for search");
+            debugPrintln(()->"using system class loader ("+classLoader+") for search");
             return;
         }
 
-        debugPrintln("using class loader ("+classLoader+") for search");
+        debugPrintln(()->"using class loader ("+classLoader+") for search");
     }
 
     /**
@@ -142,9 +143,9 @@
         }
         SchemaFactory f = _newFactory(schemaLanguage);
         if (f != null) {
-            debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
+            debugPrintln(()->"factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
         } else {
-            debugPrintln("unable to find a factory for " + schemaLanguage);
+            debugPrintln(()->"unable to find a factory for " + schemaLanguage);
         }
         return f;
     }
@@ -163,17 +164,17 @@
 
         // system property look up
         try {
-            debugPrintln("Looking up system property '"+propertyName+"'" );
+            debugPrintln(()->"Looking up system property '"+propertyName+"'" );
             String r = ss.getSystemProperty(propertyName);
             if(r!=null) {
-                debugPrintln("The value is '"+r+"'");
+                debugPrintln(()->"The value is '"+r+"'");
                 sf = createInstance(r, true);
                 if(sf!=null)    return sf;
             } else
-                debugPrintln("The property is undefined.");
+                debugPrintln(()->"The property is undefined.");
         } catch( Throwable t ) {
             if( debug ) {
-                debugPrintln("failed to look up system property '"+propertyName+"'" );
+                debugPrintln(()->"failed to look up system property '"+propertyName+"'" );
                 t.printStackTrace();
             }
         }
@@ -191,14 +192,14 @@
                         File f=new File( configFile );
                         firstTime = false;
                         if(ss.doesFileExist(f)){
-                            debugPrintln("Read properties file " + f);
+                            debugPrintln(()->"Read properties file " + f);
                             cacheProps.load(ss.getFileInputStream(f));
                         }
                     }
                 }
             }
             final String factoryClassName = cacheProps.getProperty(propertyName);
-            debugPrintln("found " + factoryClassName + " in $java.home/conf/jaxp.properties");
+            debugPrintln(()->"found " + factoryClassName + " in $java.home/conf/jaxp.properties");
 
             if (factoryClassName != null) {
                 sf = createInstance(factoryClassName, true);
@@ -225,11 +226,11 @@
 
         // platform default
         if(schemaLanguage.equals("http://www.w3.org/2001/XMLSchema")) {
-            debugPrintln("attempting to use the platform default XML Schema validator");
+            debugPrintln(()->"attempting to use the platform default XML Schema validator");
             return createInstance("com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", true);
         }
 
-        debugPrintln("all things were tried, but none was found. bailing out.");
+        debugPrintln(()->"all things were tried, but none was found. bailing out.");
         return null;
     }
 
@@ -280,15 +281,15 @@
     SchemaFactory createInstance( String className, boolean useServicesMechanism ) {
         SchemaFactory schemaFactory = null;
 
-        debugPrintln("createInstance(" + className + ")");
+        debugPrintln(()->"createInstance(" + className + ")");
 
         // get Class from className
         Class<?> clazz = createClass(className);
         if (clazz == null) {
-                debugPrintln("failed to getClass(" + className + ")");
+                debugPrintln(()->"failed to getClass(" + className + ")");
                 return null;
         }
-        debugPrintln("loaded " + className + " from " + which(clazz));
+        debugPrintln(()->"loaded " + className + " from " + which(clazz));
 
         // instantiate Class as a SchemaFactory
         try {
@@ -303,19 +304,19 @@
                     schemaFactory = (SchemaFactory) clazz.newInstance();
                 }
         } catch (ClassCastException classCastException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         classCastException.printStackTrace();
                 }
                 return null;
         } catch (IllegalAccessException illegalAccessException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         illegalAccessException.printStackTrace();
                 }
                 return null;
         } catch (InstantiationException instantiationException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         instantiationException.printStackTrace();
                 }
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
index dc950cb..97c923e 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import java.util.Properties;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 /**
  * Implementation of {@link XPathFactory#newInstance(String)}.
@@ -69,11 +70,11 @@
     /**
      * <p>Conditional debug printing.</p>
      *
-     * @param msg to print
+     * @param msgGen Supplier function that returns debug message
      */
-    private static void debugPrintln(String msg) {
+    private static void debugPrintln(Supplier<String> msgGen) {
         if (debug) {
-            System.err.println("JAXP: " + msg);
+            System.err.println("JAXP: " + msgGen.get());
         }
     }
 
@@ -102,7 +103,7 @@
     private void debugDisplayClassLoader() {
         try {
             if( classLoader == ss.getContextClassLoader() ) {
-                debugPrintln("using thread context class loader ("+classLoader+") for search");
+                debugPrintln(() -> "using thread context class loader ("+classLoader+") for search");
                 return;
             }
         } catch( Throwable unused ) {
@@ -110,11 +111,11 @@
         }
 
         if( classLoader==ClassLoader.getSystemClassLoader() ) {
-            debugPrintln("using system class loader ("+classLoader+") for search");
+            debugPrintln(() -> "using system class loader ("+classLoader+") for search");
             return;
         }
 
-        debugPrintln("using class loader ("+classLoader+") for search");
+        debugPrintln(() -> "using class loader ("+classLoader+") for search");
     }
 
     /**
@@ -135,9 +136,9 @@
         }
         XPathFactory f = _newFactory(uri);
         if (f != null) {
-            debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
+            debugPrintln(()->"factory '" + f.getClass().getName() + "' was found for " + uri);
         } else {
-            debugPrintln("unable to find a factory for " + uri);
+            debugPrintln(()->"unable to find a factory for " + uri);
         }
         return f;
     }
@@ -156,19 +157,19 @@
 
         // system property look up
         try {
-            debugPrintln("Looking up system property '"+propertyName+"'" );
+            debugPrintln(()->"Looking up system property '"+propertyName+"'" );
             String r = ss.getSystemProperty(propertyName);
             if(r!=null) {
-                debugPrintln("The value is '"+r+"'");
+                debugPrintln(()->"The value is '"+r+"'");
                 xpathFactory = createInstance(r, true);
                 if (xpathFactory != null) {
                     return xpathFactory;
                 }
             } else
-                debugPrintln("The property is undefined.");
+                debugPrintln(()->"The property is undefined.");
         } catch( Throwable t ) {
             if( debug ) {
-                debugPrintln("failed to look up system property '"+propertyName+"'" );
+                debugPrintln(()->"failed to look up system property '"+propertyName+"'" );
                 t.printStackTrace();
             }
         }
@@ -185,14 +186,14 @@
                         File f=new File( configFile );
                         firstTime = false;
                         if(ss.doesFileExist(f)){
-                            debugPrintln("Read properties file " + f);
+                            debugPrintln(()->"Read properties file " + f);
                             cacheProps.load(ss.getFileInputStream(f));
                         }
                     }
                 }
             }
             final String factoryClassName = cacheProps.getProperty(propertyName);
-            debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
+            debugPrintln(()->"found " + factoryClassName + " in $java.home/jaxp.properties");
 
             if (factoryClassName != null) {
                 xpathFactory = createInstance(factoryClassName, true);
@@ -220,11 +221,11 @@
 
         // platform default
         if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
-            debugPrintln("attempting to use the platform default W3C DOM XPath lib");
+            debugPrintln(()->"attempting to use the platform default W3C DOM XPath lib");
             return createInstance("com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", true);
         }
 
-        debugPrintln("all things were tried, but none was found. bailing out.");
+        debugPrintln(()->"all things were tried, but none was found. bailing out.");
         return null;
     }
 
@@ -280,15 +281,15 @@
     {
         XPathFactory xPathFactory = null;
 
-        debugPrintln("createInstance(" + className + ")");
+        debugPrintln(()->"createInstance(" + className + ")");
 
         // get Class from className
         Class<?> clazz = createClass(className);
         if (clazz == null) {
-            debugPrintln("failed to getClass(" + className + ")");
+            debugPrintln(()->"failed to getClass(" + className + ")");
             return null;
         }
-        debugPrintln("loaded " + className + " from " + which(clazz));
+        debugPrintln(()->"loaded " + className + " from " + which(clazz));
 
         // instantiate Class as a XPathFactory
         try {
@@ -299,19 +300,19 @@
                 xPathFactory = (XPathFactory) clazz.newInstance();
             }
         } catch (ClassCastException classCastException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         classCastException.printStackTrace();
                 }
                 return null;
         } catch (IllegalAccessException illegalAccessException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         illegalAccessException.printStackTrace();
                 }
                 return null;
         } catch (InstantiationException instantiationException) {
-                debugPrintln("could not instantiate " + clazz.getName());
+                debugPrintln(()->"could not instantiate " + clazz.getName());
                 if (debug) {
                         instantiationException.printStackTrace();
                 }
diff --git a/jaxp/src/java.xml/share/legal/bcel.md b/jaxp/src/java.xml/share/legal/bcel.md
new file mode 100644
index 0000000..3ac4532
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/bcel.md
@@ -0,0 +1,222 @@
+## Apache Byte Code Engineering Library v5.2
+
+### Notice
+<pre>
+
+    =========================================================================
+    ==  NOTICE file corresponding to the section 4 d of                    ==
+    ==  the Apache License, Version 2.0,                                   ==
+    ==  in this case for the Apache Jakarta-BCEL distribution.             ==
+    =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+</pre>
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jaxp/src/java.xml/share/legal/dom.md b/jaxp/src/java.xml/share/legal/dom.md
new file mode 100644
index 0000000..de63edd
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/dom.md
@@ -0,0 +1,62 @@
+## DOM Level 3 core specification, v1.0
+
+## W3C License
+<pre>
+
+W3C SOFTWARE NOTICE AND LICENSE
+
+http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+This work (and included software, documentation such as READMEs, or other
+related items) is being provided by the copyright holders under the following
+license. By obtaining, using and/or copying this work, you (the licensee)
+agree that you have read, understood, and will comply with the following terms
+and conditions.
+
+Permission to copy, modify, and distribute this software and its
+documentation, with or without modification, for any purpose and without fee
+or royalty is hereby granted, provided that you include the following on ALL
+copies of the software and documentation or portions thereof, including
+modifications:
+
+   1.The full text of this NOTICE in a location viewable to users of the
+   redistributed or derivative work.
+
+   2.Any pre-existing intellectual property disclaimers, notices, or terms and
+   conditions. If none exist, the W3C Software Short Notice should be included
+   (hypertext is preferred, text is permitted) within the body of any
+   redistributed or derivative code.
+
+   3.Notice of any changes or modifications to the files, including the date
+   changes were made. (We recommend you provide URIs to the location from
+   which the code is derived.)
+
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
+MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
+PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
+OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
+in advertising or publicity pertaining to the software without specific,
+written prior permission. Title to copyright in this software and any
+associated documentation will at all times remain with copyright holders.
+
+____________________________________
+
+This formulation of W3C's notice and license became active on December 31
+2002. This version removes the copyright ownership notice such that this
+license can be used with materials other than those owned by the W3C, reflects
+that ERCIM is now a host of the W3C, includes references to this specific
+dated version of the license, and removes the ambiguous grant of "use".
+Otherwise, this version is the same as the previous version and is written so
+as to preserve the Free Software Foundation's assessment of GPL compatibility
+and OSI's certification under the Open Source Definition. Please see our
+Copyright FAQ for common questions about using materials from our site,
+including specific terms and conditions for packages like libwww, Amaya, and
+Jigsaw. Other questions about this notice can be directed to
+site-policy@w3.org.
+
+</pre>
diff --git a/jaxp/src/java.xml/share/legal/jcup.md b/jaxp/src/java.xml/share/legal/jcup.md
new file mode 100644
index 0000000..acceffd
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/jcup.md
@@ -0,0 +1,24 @@
+## CUP Parser Generator for Java v 0.10k
+
+### CUP Parser Generator License
+<pre>
+
+Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both
+the copyright notice and this permission notice and warranty disclaimer
+appear in supporting documentation, and that the names of the authors or
+their employers not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+The authors and their employers disclaim all warranties with regard to
+this software, including all implied warranties of merchantability and
+fitness. In no event shall the authors or their employers be liable for
+any special, indirect or consequential damages or any damages whatsoever
+resulting from loss of use, data or profits, whether in an action of
+contract, negligence or other tortious action, arising out of or in
+connection with the use or performance of this software.
+
+</pre>
diff --git a/jaxp/src/java.xml/share/legal/xalan.md b/jaxp/src/java.xml/share/legal/xalan.md
new file mode 100644
index 0000000..5c1749b
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/xalan.md
@@ -0,0 +1,229 @@
+## Apache Xalan v2.7.1
+
+### Notice
+<pre>
+
+    ======================================================================================
+    ==  NOTICE file corresponding to the section 4d of the Apache License, Version 2.0, ==
+    ==  in this case for the Apache Xalan distribution.                                 ==
+    ======================================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Portions of this software was originally based on the following:
+
+     - software copyright (c) 1999-2002, Lotus Development Corporation., http://www.lotus.com.
+     - software copyright (c) 2001-2002, Sun Microsystems., http://www.sun.com.
+     - software copyright (c) 2003, IBM Corporation., http://www.ibm.com.
+     - voluntary contributions made by Ovidiu Predescu (ovidiu@cup.hp.com) on behalf of the
+       Apache Software Foundation and was originally developed at Hewlett Packard Company.
+
+</pre>
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jaxp/src/java.xml/share/legal/xerces.md b/jaxp/src/java.xml/share/legal/xerces.md
new file mode 100644
index 0000000..438419b
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/xerces.md
@@ -0,0 +1,226 @@
+## Apache Xerces v2.11.0
+
+### Notice
+
+    =========================================================================
+    == NOTICE file corresponding to section 4(d) of the Apache License, ==
+    == Version 2.0, in this case for the Apache Xerces Java distribution. ==
+    =========================================================================
+    
+    Apache Xerces Java
+    Copyright 1999-2010 The Apache Software Foundation
+    This product includes software developed at
+    The Apache Software Foundation (http://www.apache.org/).
+    Portions of this software were originally based on the following:
+    - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.
+    - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.
+    - voluntary contributions made by Paul Eng on behalf of the
+    Apache Software Foundation that were originally developed at iClick, Inc.,
+    software copyright (c) 1999.
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jaxp/src/java.xml/share/legal/xmlresolver.md b/jaxp/src/java.xml/share/legal/xmlresolver.md
new file mode 100644
index 0000000..cf18bb4
--- /dev/null
+++ b/jaxp/src/java.xml/share/legal/xmlresolver.md
@@ -0,0 +1,223 @@
+## Apache XML Resolver Library v1.2
+
+### Notice
+<pre>
+
+Apache XML Commons Resolver
+Copyright 2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation http://www.apache.org/
+
+Portions of this code are derived from classes placed in the
+public domain by Arbortext on 10 Apr 2000. See:
+http://www.arbortext.com/customer_support/updates_and_technical_notes/catalogs/docs/README.htm
+
+</pre>
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out
index 1fc9136..4e64631 100644
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java b/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java
index b605137..8712697 100644
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java
@@ -25,14 +25,13 @@
 
 import static java.lang.String.valueOf;
 import static jaxp.library.JAXPTestUtilities.USER_DIR;
-import static org.testng.Assert.assertEquals;
+import static jaxp.library.JAXPTestUtilities.compareWithGold;
+import static org.testng.Assert.assertTrue;
 import static test.astro.AstroConstants.ASTROCAT;
 import static test.astro.AstroConstants.GOLDEN_DIR;
 
-import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.List;
 
 import javax.xml.transform.sax.TransformerHandler;
 
@@ -77,10 +76,10 @@
     @BeforeClass
     public void setup() throws Exception {
         data = new FiltersAndGolden[4];
-        data[0] = new FiltersAndGolden(getGoldenFileContent(1), astro -> astro.getRAFilter(0.106, 0.108));
-        data[1] = new FiltersAndGolden(getGoldenFileContent(2), astro -> astro.getStellarTypeFilter("K0IIIbCN-0.5"));
-        data[2] = new FiltersAndGolden(getGoldenFileContent(3), astro -> astro.getStellarTypeFilter("G"), astro -> astro.getDecFilter(-5.0, 60.0));
-        data[3] = new FiltersAndGolden(getGoldenFileContent(4), astro -> astro.getRADECFilter(0.084, 0.096, -5.75, 14.0));
+        data[0] = new FiltersAndGolden(getGoldenFileName(1), astro -> astro.getRAFilter(0.106, 0.108));
+        data[1] = new FiltersAndGolden(getGoldenFileName(2), astro -> astro.getStellarTypeFilter("K0IIIbCN-0.5"));
+        data[2] = new FiltersAndGolden(getGoldenFileName(3), astro -> astro.getStellarTypeFilter("G"), astro -> astro.getDecFilter(-5.0, 60.0));
+        data[3] = new FiltersAndGolden(getGoldenFileName(4), astro -> astro.getRADECFilter(0.084, 0.096, -5.75, 14.0));
     }
 
     /*
@@ -102,11 +101,11 @@
         AstroProcessor astro = new AstroProcessor(fFactClass, ASTROCAT, isFactClass);
 
         for (int i = 0; i < data.length; i++) {
-            runProcess(astro, valueOf(i + 1), data[i].getGolden(), data[i].getFilters());
+            runProcess(astro, valueOf(i + 1), data[i].getGoldenFileName(), data[i].getFilters());
         }
     }
 
-    private void runProcess(AstroProcessor astro, String processNum, List<String> goldenfileContent, FilterCreator... filterCreators) throws Exception {
+    private void runProcess(AstroProcessor astro, String processNum, String goldenFileName, FilterCreator... filterCreators) throws Exception {
         System.out.println("run process " + processNum);
         TransformerHandler[] filters = new TransformerHandler[filterCreators.length];
         for (int i = 0; i < filterCreators.length; i++)
@@ -115,11 +114,11 @@
         String outputfile = Files.createTempFile(Paths.get(USER_DIR), "query" + processNum + ".out.", null).toString();
         System.out.println("output file: " + outputfile);
         astro.process(outputfile, filters);
-        assertEquals(Files.readAllLines(Paths.get(outputfile)), goldenfileContent);
+        assertTrue(compareWithGold(goldenFileName, outputfile));
     }
 
-    private List<String>  getGoldenFileContent(int num) throws IOException {
-        return Files.readAllLines(Paths.get(GOLDEN_DIR + "query" + num + ".out"));
+    private String getGoldenFileName(int num) {
+        return GOLDEN_DIR + "query" + num + ".out";
     }
 
     @FunctionalInterface
@@ -129,19 +128,19 @@
 
     private static class FiltersAndGolden {
         private FilterCreator[] filters;
-        private List<String> golden;
+        private String goldenFileName;
 
-        FiltersAndGolden(List<String> golden, FilterCreator... filters) {
+        FiltersAndGolden(String goldenFileName, FilterCreator... filters) {
             this.filters = filters;
-            this.golden = golden;
+            this.goldenFileName = goldenFileName;
         }
 
         FilterCreator[] getFilters() {
             return filters;
         }
 
-        List<String> getGolden() {
-            return golden;
+        String getGoldenFileName() {
+            return goldenFileName;
         }
     }
 }
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out
index d5ccc94..1c5fb9c 100644
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out
@@ -1,15 +1,24 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>7<br>
-<b>Constellation: </b>Cas<br>
-<b>Description: </b>10    Cas<br>
-<b>RA J2000: </b>00:06:26.5<br>
-<b>DEC J2000: </b>64:11:46<br>
-<b>Visual Magnitude: </b>5.59<br>
-<b>Spectral Type: </b>B9III<br>
-<b>Galactic Longitude: </b>118.06<br>
-<b>Galactic Latitude: </b>1.75<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>7
+        <br>
+        <b>Constellation: </b>Cas
+        <br>
+        <b>Description: </b>10    Cas
+        <br>
+        <b>RA J2000: </b>00:06:26.5
+        <br>
+        <b>DEC J2000: </b>64:11:46
+        <br>
+        <b>Visual Magnitude: </b>5.59
+        <br>
+        <b>Spectral Type: </b>B9III
+        <br>
+        <b>Galactic Longitude: </b>118.06
+        <br>
+        <b>Galactic Latitude: </b>1.75
+        <br>
+        <hr>
+    </body>
 </html>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out
index 22dc28c..9072096 100644
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out
@@ -1,15 +1,24 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>3<br>
-<b>Constellation: </b>Psc<br>
-<b>Description: </b>33    Psc<br>
-<b>RA J2000: </b>00:05:20.1<br>
-<b>DEC J2000: </b>05:42:27<br>
-<b>Visual Magnitude: </b>4.61<br>
-<b>Spectral Type: </b>K0IIIbCN-0.5<br>
-<b>Galactic Longitude: </b>93.75<br>
-<b>Galactic Latitude: </b>-65.93<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>3
+        <br>
+        <b>Constellation: </b>Psc
+        <br>
+        <b>Description: </b>33    Psc
+        <br>
+        <b>RA J2000: </b>00:05:20.1
+        <br>
+        <b>DEC J2000: </b>05:42:27
+        <br>
+        <b>Visual Magnitude: </b>4.61
+        <br>
+        <b>Spectral Type: </b>K0IIIbCN-0.5
+        <br>
+        <b>Galactic Longitude: </b>93.75
+        <br>
+        <b>Galactic Latitude: </b>-65.93
+        <br>
+        <hr>
+    </body>
 </html>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out
index e3f7184..4e59b3a 100644
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out
@@ -1,39 +1,62 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>2<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:05:03.8<br>
-<b>DEC J2000: </b>00:30:11<br>
-<b>Visual Magnitude: </b>6.29<br>
-<b>Spectral Type: </b>gG9<br>
-<b>Galactic Longitude: </b>98.33<br>
-<b>Galactic Latitude: </b>-61.14<br>
-<hr>
-<b>Star Id: </b>4<br>
-<b>Constellation: </b>Peg<br>
-<b>Description: </b>86    Peg<br>
-<b>RA J2000: </b>00:05:42.0<br>
-<b>DEC J2000: </b>13:23:46<br>
-<b>Visual Magnitude: </b>5.51<br>
-<b>Spectral Type: </b>G5III<br>
-<b>Galactic Longitude: </b>106.19<br>
-<b>Galactic Latitude: </b>-47.98<br>
-<hr>
-<b>Star Id: </b>5<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:06:16.0<br>
-<b>DEC J2000: </b>58:26:12<br>
-<b>Visual Magnitude: </b>5.96<br>
-<b>Spectral Type: </b>G5V<br>
-<b>Galactic Longitude: </b>117.03<br>
-<b>Galactic Latitude: </b>-03.92<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>2
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:05:03.8
+        <br>
+        <b>DEC J2000: </b>00:30:11
+        <br>
+        <b>Visual Magnitude: </b>6.29
+        <br>
+        <b>Spectral Type: </b>gG9
+        <br>
+        <b>Galactic Longitude: </b>98.33
+        <br>
+        <b>Galactic Latitude: </b>-61.14
+        <br>
+        <hr>
+        <b>Star Id: </b>4
+        <br>
+        <b>Constellation: </b>Peg
+        <br>
+        <b>Description: </b>86    Peg
+        <br>
+        <b>RA J2000: </b>00:05:42.0
+        <br>
+        <b>DEC J2000: </b>13:23:46
+        <br>
+        <b>Visual Magnitude: </b>5.51
+        <br>
+        <b>Spectral Type: </b>G5III
+        <br>
+        <b>Galactic Longitude: </b>106.19
+        <br>
+        <b>Galactic Latitude: </b>-47.98
+        <br>
+        <hr>
+        <b>Star Id: </b>5
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:06:16.0
+        <br>
+        <b>DEC J2000: </b>58:26:12
+        <br>
+        <b>Visual Magnitude: </b>5.96
+        <br>
+        <b>Spectral Type: </b>G5V
+        <br>
+        <b>Galactic Longitude: </b>117.03
+        <br>
+        <b>Galactic Latitude: </b>-03.92
+        <br>
+        <hr>
+    </body>
 </html>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out
index 71b9960..0f23e98 100644
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out
@@ -1,37 +1,62 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>2<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:05:03.8<br>
-<b>DEC J2000: </b>00:30:11<br>
-<b>Visual Magnitude: </b>6.29<br>
-<b>Spectral Type: </b>gG9<br>
-<b>Galactic Longitude: </b>98.33<br>
-<b>Galactic Latitude: </b>-61.14<br>
-<hr>
-<b>Star Id: </b>3<br>
-<b>Constellation: </b>Psc<br>
-<b>Description: </b>33    Psc<br>
-<b>RA J2000: </b>00:05:20.1<br>
-<b>DEC J2000: </b>05:42:27<br>
-<b>Visual Magnitude: </b>4.61<br>
-<b>Spectral Type: </b>K0IIIbCN-0.5<br>
-<b>Galactic Longitude: </b>93.75<br>
-<b>Galactic Latitude: </b>-65.93<br>
-<hr>
-<b>Star Id: </b>4<br>
-<b>Constellation: </b>Peg<br>
-<b>Description: </b>86    Peg<br>
-<b>RA J2000: </b>00:05:42.0<br>
-<b>DEC J2000: </b>13:23:46<br>
-<b>Visual Magnitude: </b>5.51<br>
-<b>Spectral Type: </b>G5III<br>
-<b>Galactic Longitude: </b>106.19<br>
-<b>Galactic Latitude: </b>-47.98<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>2
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:05:03.8
+        <br>
+        <b>DEC J2000: </b>00:30:11
+        <br>
+        <b>Visual Magnitude: </b>6.29
+        <br>
+        <b>Spectral Type: </b>gG9
+        <br>
+        <b>Galactic Longitude: </b>98.33
+        <br>
+        <b>Galactic Latitude: </b>-61.14
+        <br>
+        <hr>
+        <b>Star Id: </b>3
+        <br>
+        <b>Constellation: </b>Psc
+        <br>
+        <b>Description: </b>33    Psc
+        <br>
+        <b>RA J2000: </b>00:05:20.1
+        <br>
+        <b>DEC J2000: </b>05:42:27
+        <br>
+        <b>Visual Magnitude: </b>4.61
+        <br>
+        <b>Spectral Type: </b>K0IIIbCN-0.5
+        <br>
+        <b>Galactic Longitude: </b>93.75
+        <br>
+        <b>Galactic Latitude: </b>-65.93
+        <br>
+        <hr>
+        <b>Star Id: </b>4
+        <br>
+        <b>Constellation: </b>Peg
+        <br>
+        <b>Description: </b>86    Peg
+        <br>
+        <b>RA J2000: </b>00:05:42.0
+        <br>
+        <b>DEC J2000: </b>13:23:46
+        <br>
+        <b>Visual Magnitude: </b>5.51
+        <br>
+        <b>Spectral Type: </b>G5III
+        <br>
+        <b>Galactic Longitude: </b>106.19
+        <br>
+        <b>Galactic Latitude: </b>-47.98
+        <br>
+        <hr>
+    </body>
 </html>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/PrettyPrintTest.java b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/PrettyPrintTest.java
new file mode 100644
index 0000000..be54c6c
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/PrettyPrintTest.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package common.prettyprint;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/*
+ * @test
+ * @bug 6439439 8087303
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @run testng/othervm -DrunSecMngr=true common.prettyprint.PrettyPrintTest
+ * @run testng/othervm common.prettyprint.PrettyPrintTest
+ * @summary Test serializing xml and html with indentation.
+ */
+@Listeners({jaxp.library.FilePolicy.class})
+public class PrettyPrintTest {
+    /*
+     * test CDATA, elements only, text and element, whitespace and element,
+     * xml:space property and nested xml:space property, mixed node types.
+     */
+    @DataProvider(name = "xml-data")
+    public Object[][] xmlData() throws Exception {
+        return new Object[][] {
+                { read("xmltest1.xml"), read("xmltest1.out") },
+                { read("xmltest2.xml"), read("xmltest2.out") },
+                { read("xmltest3.xml"), read("xmltest3.out") },
+                { read("xmltest4.xml"), read("xmltest4.out") },
+                { read("xmltest5.xml"), read("xmltest5.out") },
+                { read("xmltest6.xml"), read("xmltest6.out") },
+                { read("xmltest7.xml"), read("xmltest7.out") },
+                { read("xmltest8.xml"), read("xmltest8.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Test the whitespace text nodes are serialized with pretty-print by LSSerializer and transformer correctly
+     *
+     */
+    @Test(dataProvider = "xml-data")
+    public void testXMLPrettyPrint(String source, String expected) throws Exception {
+        // test it's no change if no pretty-print
+        String result = serializerWrite(toXmlDocument(source), false);
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
+        // test pretty-print
+        assertEquals(serializerWrite(toXmlDocument(source), true), expected);
+        // test it's no change if no pretty-print
+        result = transform(toXmlDocument(source), false);
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
+        // test pretty-print
+        assertEquals(transform(toXmlDocument(source), true).replaceAll("\r\n", "\n"), expected);
+    }
+
+    /*
+     * test pure text content, and sequent Text nodes.
+     */
+    @DataProvider(name = "xml-node-data")
+    public Object[][] xmlNodeData() throws Exception {
+        return new Object[][] {
+                { newTextNode(read("nodetest1.txt")), read("nodetest1.out") },
+                { createDocWithSequentTextNodes(), read("nodetest2.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Test the whitespace text nodes are serialized with pretty-print by LSSerializer and transformer correctly,
+     * doesn't compare with the source because the test data is Node object
+     *
+     */
+    @Test(dataProvider = "xml-node-data")
+    public void testXMLNodePrettyPrint(Node xml, String expected) throws Exception {
+        assertEquals(serializerWrite(xml, true), expected);
+        assertEquals(transform(xml, true).replaceAll("\r\n", "\n"), expected);
+    }
+
+    /*
+     * test block element, inline element, text, and mixed elements.
+     */
+    @DataProvider(name = "html-data")
+    public Object[][] htmlData() throws Exception {
+        return new Object[][] {
+            { read("htmltest1.xml"), read("htmltest1.out") },
+            { read("htmltest2.xml"), read("htmltest2.out") },
+            { read("htmltest3.xml"), read("htmltest3.out") },
+            { read("htmltest4.xml"), read("htmltest4.out") },
+            { read("htmltest5.xml"), read("htmltest5.out") },
+            { read("htmltest6.xml"), read("htmltest6.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Transform to HTML, test Pretty Print for HTML.
+     *
+     */
+    @Test(dataProvider = "html-data")
+    public void testTransformToHTML(String source, String expected) throws Exception {
+        // test it's no change if no pretty-print
+        StringWriter writer = new StringWriter();
+        getTransformer(true, false).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(writer.toString())), "The actual is: " + writer.toString());
+
+        // test pretty-print
+        writer = new StringWriter();
+        getTransformer(true, true).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
+        assertEquals(writer.toString().replaceAll("\r\n", "\n"), expected);
+    }
+
+    @Test
+    public void testLSSerializerFormatPrettyPrint() {
+
+        final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n"
+                + "<hello>before child element<child><children/><children/></child>after child element</hello>";
+        /**JDK-8035467
+         * no newline in default output
+         */
+        final String XML_DOCUMENT_DEFAULT_PRINT =
+                "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
+                + "<hello>"
+                + "before child element"
+                + "<child><children/><children/></child>"
+                + "after child element</hello>";
+
+        final String XML_DOCUMENT_PRETTY_PRINT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?><hello>\n" +
+                "    before child element\n" +
+                "    <child>\n" +
+                "        <children/>\n" +
+                "        <children/>\n" +
+                "    </child>\n" +
+                "    after child element\n" +
+                "</hello>\n";
+
+        // it all begins with a Document
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder = null;
+        try {
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch (ParserConfigurationException parserConfigurationException) {
+            parserConfigurationException.printStackTrace();
+            Assert.fail(parserConfigurationException.toString());
+        }
+        Document document = null;
+
+        StringReader stringReader = new StringReader(XML_DOCUMENT);
+        InputSource inputSource = new InputSource(stringReader);
+        try {
+            document = documentBuilder.parse(inputSource);
+        } catch (SAXException saxException) {
+            saxException.printStackTrace();
+            Assert.fail(saxException.toString());
+        } catch (IOException ioException) {
+            ioException.printStackTrace();
+            Assert.fail(ioException.toString());
+        }
+
+        // query DOM Interfaces to get to a LSSerializer
+        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
+        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
+        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
+
+        System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
+
+        // get configuration
+        DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
+
+        // query current configuration
+        Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
+        Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
+        Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
+
+        System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
+                + canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
+
+        // test values
+        assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
+
+        assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
+                + Boolean.TRUE);
+
+        assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
+                + Boolean.TRUE);
+
+        // get default serialization
+        String prettyPrintDefault = lsSerializer.writeToString(document);
+        System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintDefault + "\"");
+
+        assertEquals(prettyPrintDefault, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+
+        // configure LSSerializer to not format-pretty-print
+        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
+        String prettyPrintFalse = lsSerializer.writeToString(document);
+        System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintFalse + "\"");
+
+        assertEquals(prettyPrintFalse, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+
+        // configure LSSerializer to format-pretty-print
+        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
+        String prettyPrintTrue = lsSerializer.writeToString(document);
+        System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintTrue + "\"");
+
+        assertEquals(prettyPrintTrue, XML_DOCUMENT_PRETTY_PRINT, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+    }
+
+    private String serializerWrite(Node xml, boolean pretty) throws Exception {
+        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
+        DOMImplementationLS domImplementation = (DOMImplementationLS) registry.getDOMImplementation("LS");
+        StringWriter writer = new StringWriter();
+        LSOutput formattedOutput = domImplementation.createLSOutput();
+        formattedOutput.setCharacterStream(writer);
+        LSSerializer domSerializer = domImplementation.createLSSerializer();
+        domSerializer.getDomConfig().setParameter(DOM_FORMAT_PRETTY_PRINT, pretty);
+        domSerializer.getDomConfig().setParameter("xml-declaration", false);
+        domSerializer.write(xml, formattedOutput);
+        return writer.toString();
+    }
+
+    private String transform(Node xml, boolean pretty) throws Exception {
+        Transformer transformer = getTransformer(false, pretty);
+        StringWriter writer = new StringWriter();
+        transformer.transform(new DOMSource(xml), new StreamResult(writer));
+        return writer.toString();
+    }
+
+    private Document toXmlDocument(String xmlString) throws Exception {
+        InputSource xmlInputSource = new InputSource(new StringReader(xmlString));
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setValidating(true);
+        DocumentBuilder xmlDocumentBuilder = dbf.newDocumentBuilder();
+        Document node = xmlDocumentBuilder.parse(xmlInputSource);
+        return node;
+    }
+
+    private Text newTextNode(String text) throws Exception {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        return db.newDocument().createTextNode(text);
+    }
+
+    private Document createDocWithSequentTextNodes() throws Exception {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        Document doc = db.newDocument();
+        Node root = doc.createElement("root");
+        doc.appendChild(root);
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode("t"));
+        root.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createTextNode("t"));
+        root.appendChild(doc.createTextNode("   "));
+        Node child1 = doc.createElement("child1");
+        root.appendChild(child1);
+        child1.appendChild(doc.createTextNode(" "));
+        child1.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createTextNode("t"));
+        Node child2 = doc.createElement("child2");
+        root.appendChild(child2);
+        child2.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        Node child3 = doc.createElement("child3");
+        root.appendChild(child3);
+        child3.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        Node child4 = doc.createElement("child4");
+        root.appendChild(child4);
+        child4.appendChild(doc.createTextNode(" "));
+
+        root.appendChild(doc.createTextNode(" "));
+        Node child5 = doc.createElement("child5");
+        root.appendChild(child5);
+        child5.appendChild(doc.createTextNode("t"));
+
+        Node child51 = doc.createElement("child51");
+        child5.appendChild(child51);
+        child51.appendChild(doc.createTextNode(" "));
+        Node child511 = doc.createElement("child511");
+        child51.appendChild(child511);
+        child511.appendChild(doc.createTextNode("t"));
+        child51.appendChild(doc.createTextNode(" "));
+        child5.appendChild(doc.createTextNode("t"));
+
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createComment(" test comment "));
+        root.appendChild(doc.createTextNode(" \n"));
+        root.appendChild(doc.createComment(" "));
+        root.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createProcessingInstruction("target1", "test"));
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        return doc;
+    }
+
+    private Transformer getTransformer(boolean html, boolean pretty) throws Exception {
+        Transformer transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        if (html)
+            transformer.setOutputProperty(OutputKeys.METHOD, "html");
+        transformer.setOutputProperty(OutputKeys.INDENT, pretty ? "yes" : "no");
+        return transformer;
+    }
+
+
+    private String read(String filename) throws Exception {
+        try (InputStream in = PrettyPrintTest.class.getResourceAsStream(filename)) {
+            return new String(in.readAllBytes());
+        }
+    }
+
+    private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
+}
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.out
new file mode 100644
index 0000000..d142675
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.out
@@ -0,0 +1,6 @@
+<rss version="2.0">
+    <channel xml:space="preserve">
+        <title>Java Tutorials and Examples 1</title>
+        <language>en-us</language>
+    </channel>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.xml
new file mode 100644
index 0000000..5046062
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.xml
@@ -0,0 +1 @@
+<rss version="2.0"><channel xml:space="preserve"><title>Java Tutorials and Examples 1</title> <language>en-us</language></channel></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.out
new file mode 100644
index 0000000..8c083a5
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.out
@@ -0,0 +1,3 @@
+<html>
+    <code>Java</code><b><sup>TM</sup></b>
+</html>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.xml
new file mode 100644
index 0000000..d1f1616
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.xml
@@ -0,0 +1 @@
+<html><code>Java</code><b><sup>TM</sup></b></html>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.out
new file mode 100644
index 0000000..e7f9eea
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.out
@@ -0,0 +1,3 @@
+<p>
+    this is <a href="test.html">a <strong>test</strong></a> page
+</p>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.xml
new file mode 100644
index 0000000..51f84ba
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.xml
@@ -0,0 +1 @@
+<p>this is <a href="test.html">a <strong>test</strong></a> page</p>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.out
new file mode 100644
index 0000000..7eb8ff1
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.out
@@ -0,0 +1,10 @@
+<html>
+    <body>
+        <h1>A heading</h1>
+        <p>
+            new paragraph
+            <form>an empty form</form>
+            <a href="test.html">test</a>
+        </p>
+    </body>
+</html>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.xml
new file mode 100644
index 0000000..eca3dec
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.xml
@@ -0,0 +1 @@
+<html><body><h1>A heading</h1><p>new paragraph<form>an empty form</form><a href="test.html">test</a></p></body></html>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.out
new file mode 100644
index 0000000..ce2d1ca
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.out
@@ -0,0 +1,7 @@
+<html>
+    <p>
+        this is a mixed test <a href="test.html">click
+            <p>to the test</p>
+            page</a>link end
+    </p>
+</html>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.xml
new file mode 100644
index 0000000..cfcf67f
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.xml
@@ -0,0 +1 @@
+<html><p>this is a mixed test <a href="test.html">click<p>to the test</p>page</a>link end</p></html>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.out
new file mode 100644
index 0000000..e8ab1a2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.out
@@ -0,0 +1,6 @@
+<p>
+    <a href="test.html">text
+        <table></table>
+    </a> another
+    <form></form>
+</p>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.xml
new file mode 100644
index 0000000..b6820ae
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.xml
@@ -0,0 +1 @@
+<p><a href="test.html">text<table/></a> another<form/></p>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.out
new file mode 100644
index 0000000..cd7d2cc
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.out
@@ -0,0 +1,4 @@
+  abc def 
+line2 &amp;a 
+ test
+ 
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.txt b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.txt
new file mode 100644
index 0000000..086050d
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.txt
@@ -0,0 +1,4 @@
+  abc def 
+line2 &a 
+ test
+ 
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest2.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest2.out
new file mode 100644
index 0000000..a0d9436
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest2.out
@@ -0,0 +1,19 @@
+<root>
+     t
+t   
+    <child1/>
+    t
+    <child2/>
+    <child3/>
+    <child4/>
+    <child5>
+        t
+        <child51>
+            <child511>t</child511>
+        </child51>
+        t
+    </child5>
+    <!-- test comment -->
+    <!-- -->
+    <?target1 test?>
+</root>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.out
new file mode 100644
index 0000000..7d51a35
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.out
@@ -0,0 +1,3 @@
+<a>
+    <![CDATA[ ]]>
+</a>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.xml
new file mode 100644
index 0000000..7a1317a
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.xml
@@ -0,0 +1 @@
+<a><![CDATA[ ]]></a>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.out
new file mode 100644
index 0000000..ab37d7c
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.out
@@ -0,0 +1,5 @@
+<a>
+    <![CDATA[  abc def 
+line2 &a 
+ test]]>
+</a>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.xml
new file mode 100644
index 0000000..8340ae4
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.xml
@@ -0,0 +1,3 @@
+<a><![CDATA[  abc def 
+line2 &a 
+ test]]></a>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.out
new file mode 100644
index 0000000..d37bef0
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.out
@@ -0,0 +1,5 @@
+<rss version="2.0">
+    <ns:test id="i001">
+        <ns:child/>
+    </ns:test>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.xml
new file mode 100644
index 0000000..99d7a63
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.xml
@@ -0,0 +1 @@
+<rss version="2.0"><ns:test id='i001'><ns:child></ns:child></ns:test></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.out
new file mode 100644
index 0000000..fedb956
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.out
@@ -0,0 +1,6 @@
+<rss version="2.0">
+    <ns:test id="i001">
+        <ns:child>child1</ns:child>
+        <test att1="v1">  abc test</test>
+    </ns:test>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.xml
new file mode 100644
index 0000000..b79c9b2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.xml
@@ -0,0 +1 @@
+<rss version="2.0"><ns:test id='i001'><ns:child>child1</ns:child><test att1='v1'>  abc test</test></ns:test></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.out
new file mode 100644
index 0000000..562ccc6
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.out
@@ -0,0 +1,10 @@
+<rss version="2.0">
+    <channel>
+        <title>Java Tutorials and Examples 1</title>
+        <language>en-us</language>
+    </channel>
+    <a>
+        <b/>
+    </a>
+    <c/>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.xml
new file mode 100644
index 0000000..3ff19ef
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.xml
@@ -0,0 +1,3 @@
+<rss version="2.0"><channel> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel><a><b> </b></a> <c>
+ 
+</c></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.out
new file mode 100644
index 0000000..266c378
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.out
@@ -0,0 +1,3 @@
+<rss version="2.0">
+    <channel xml:space="preserve"> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.xml
new file mode 100644
index 0000000..21a41f1
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.xml
@@ -0,0 +1 @@
+<rss version="2.0"><channel xml:space="preserve"> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.out
new file mode 100644
index 0000000..ba002da
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.out
@@ -0,0 +1,10 @@
+<rss>
+    <layer1 xml:space="preserve"> <title>Java </title> <layer2 xml:space="asfsa"> <layer3> <layer4 xml:space="default">
+                    <l5>5</l5>
+                </layer4> </layer3> </layer2> <layer2 xml:space="default">
+            <layer3>
+                <l4/>
+            </layer3>
+            <layer3 xml:space="preserve"> <l4> </l4> </layer3>
+        </layer2> </layer1>
+</rss>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.xml
new file mode 100644
index 0000000..6e6b3de
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.xml
@@ -0,0 +1,2 @@
+<rss><layer1 xml:space="preserve"> <title>Java </title> <layer2 xml:space="asfsa"> <layer3> <layer4 xml:space="default"> <l5>5</l5> 
+ </layer4> </layer3> </layer2> <layer2 xml:space="default"> <layer3> <l4> </l4> </layer3> <layer3 xml:space="preserve"> <l4> </l4> </layer3></layer2> </layer1></rss>
\ No newline at end of file
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.out b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.out
new file mode 100644
index 0000000..621263f
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.out
@@ -0,0 +1,25 @@
+<root>
+    
+     t
+    <![CDATA[ ]]>
+    
+t   
+    
+    <child1/>
+    
+    t
+    <!-- test comment -->
+    <child2/>
+    <child5>
+        
+        t
+        <?target1 test?>
+        <child51>
+            <child511>t</child511>
+        </child51>
+        <?target1 test?>
+        
+        t
+    
+    </child5>
+</root>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.xml b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.xml
new file mode 100644
index 0000000..e9c1c47
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.xml
@@ -0,0 +1,15 @@
+<root>
+     t<![CDATA[ ]]>
+t   
+    <child1/>
+    t<!-- test comment -->
+    <child2/>
+    <child5>
+        t<?target1 test?>
+        <child51>
+            <child511>t</child511>
+        </child51><?target1 test?>
+        t
+    </child5>
+    
+</root> 
diff --git a/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java b/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java
index f101936..9068969 100644
--- a/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java
+++ b/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java
@@ -23,6 +23,8 @@
 
 package dom.ls;
 
+import static org.w3c.dom.ls.DOMImplementationLS.MODE_SYNCHRONOUS;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.StringReader;
@@ -35,22 +37,22 @@
 import org.testng.Assert;
 import org.testng.annotations.Listeners;
 import org.testng.annotations.Test;
-import org.w3c.dom.DOMConfiguration;
 import org.w3c.dom.DOMError;
 import org.w3c.dom.DOMErrorHandler;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 import org.w3c.dom.ls.DOMImplementationLS;
 import org.w3c.dom.ls.LSException;
+import org.w3c.dom.ls.LSInput;
 import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSParser;
 import org.w3c.dom.ls.LSSerializer;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
-
 /*
  * @test
- * @bug 6439439 8080906
+ * @bug 8080906 8114834
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  * @run testng/othervm -DrunSecMngr=true dom.ls.LSSerializerTest
  * @run testng/othervm dom.ls.LSSerializerTest
@@ -58,7 +60,6 @@
  */
 @Listeners({jaxp.library.BasePolicy.class})
 public class LSSerializerTest {
-    private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
 
     class DOMErrorHandlerImpl implements DOMErrorHandler {
 
@@ -167,101 +168,6 @@
     }
 
     @Test
-    public void testFormatPrettyPrint() {
-
-        final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n" + "<hello>" + "world" + "<child><children/><children/></child>"
-                + "</hello>";
-        /**JDK-8035467
-         * no newline in default output
-         */
-        final String XML_DOCUMENT_DEFAULT_PRINT =
-                "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
-                + "<hello>"
-                + "world"
-                + "<child><children/><children/></child>"
-                + "</hello>";
-
-        final String XML_DOCUMENT_PRETTY_PRINT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<hello>" + "world" + "<child>" + "\n" + "        "
-                + "<children/>" + "\n" + "        " + "<children/>" + "\n" + "    " + "</child>" + "\n" + "</hello>" + "\n";
-
-        // it all begins with a Document
-        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
-        DocumentBuilder documentBuilder = null;
-        try {
-            documentBuilder = documentBuilderFactory.newDocumentBuilder();
-        } catch (ParserConfigurationException parserConfigurationException) {
-            parserConfigurationException.printStackTrace();
-            Assert.fail(parserConfigurationException.toString());
-        }
-        Document document = null;
-
-        StringReader stringReader = new StringReader(XML_DOCUMENT);
-        InputSource inputSource = new InputSource(stringReader);
-        try {
-            document = documentBuilder.parse(inputSource);
-        } catch (SAXException saxException) {
-            saxException.printStackTrace();
-            Assert.fail(saxException.toString());
-        } catch (IOException ioException) {
-            ioException.printStackTrace();
-            Assert.fail(ioException.toString());
-        }
-
-        // query DOM Interfaces to get to a LSSerializer
-        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
-        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
-        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
-
-        System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
-
-        // get configuration
-        DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
-
-        // query current configuration
-        Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
-        Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
-        Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
-
-        System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
-                + canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
-
-        // test values
-        Assert.assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
-
-        Assert.assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
-                + Boolean.TRUE);
-
-        Assert.assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
-                + Boolean.TRUE);
-
-        // get default serialization
-        String prettyPrintDefault = lsSerializer.writeToString(document);
-        System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintDefault + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_DEFAULT_PRINT, prettyPrintDefault, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-
-        // configure LSSerializer to not format-pretty-print
-        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
-        String prettyPrintFalse = lsSerializer.writeToString(document);
-        System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintFalse + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_DEFAULT_PRINT, prettyPrintFalse, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-
-        // configure LSSerializer to format-pretty-print
-        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
-        String prettyPrintTrue = lsSerializer.writeToString(document);
-        System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintTrue + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_PRETTY_PRINT, prettyPrintTrue, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-    }
-
-    @Test
     public void testXML11() {
 
         /**
@@ -318,4 +224,109 @@
         // output should == input
         Assert.assertEquals(XML11_DOCUMENT_OUTPUT, defaultSerialization, "Invalid serialization of XML 1.1 document: ");
     }
+
+    /*
+     * @bug 8114834 test entity reference, nested entity reference when entities
+     * is true and false
+     */
+    @Test
+    public void testEntityReference() throws Exception {
+        final String XML_DOCUMENT = "<?xml version=\"1.1\" encoding=\"UTF-16\"?>\n" +
+                "<!DOCTYPE author [\n" +
+                " <!ENTITY name \"Jo Smith\">" +
+                " <!ENTITY name1 \"&name;\">" +
+                " <!ENTITY name2 \"&name1;\">" +
+                "<!ENTITY ele \"<aa><bb>text</bb></aa>\">" +
+                " <!ENTITY ele1 \"&ele;\">" +
+                " <!ENTITY ele2 \"&ele1;\">" +
+                " ]>" +
+                " <author><a>&name1;</a>" +
+                "<b>b &name2; &name1; b</b>" +
+                "<c> &name; </c>" +
+                "<d>&ele1;d</d>" +
+                "<e> &ele2;eee </e>" +
+                "<f>&lt;att&gt;</f>" +
+                "<g> &ele; g</g>" +
+                "<h>&ele2;</h></author>" ;
+
+
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+
+        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
+        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
+
+        LSParser domParser = domImplementationLS.createLSParser(MODE_SYNCHRONOUS, null);
+        domParser.getDomConfig().setParameter("entities", Boolean.TRUE);
+
+        LSInput src = domImplementationLS.createLSInput();
+        src.setStringData(XML_DOCUMENT);
+        Document document = domParser.parse(src);
+
+        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
+
+        lsSerializer.getDomConfig().setParameter("format-pretty-print", true);
+        System.out.println("test with default entities is " + lsSerializer.getDomConfig().getParameter("entities"));
+        Assert.assertEquals(lsSerializer.writeToString(document),
+                "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" +
+                "<!ENTITY name 'Jo Smith'>\n" +
+                "<!ENTITY name1 '&name;'>\n" +
+                "<!ENTITY name2 '&name1;'>\n" +
+                "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" +
+                "<!ENTITY ele1 '&ele;'>\n" +
+                "<!ENTITY ele2 '&ele1;'>\n" +
+                "]>\n" +
+                "<author>\n" +
+                "    <a>&name1;Jo Smith</a>\n" +
+                "    <b>b &name2;Jo Smith &name1;Jo Smith b</b>\n" +
+                "    <c> &name;Jo Smith </c>\n" +
+                "    <d>&ele1;d</d>\n" +
+                "    <e> &ele2;eee </e>\n" +
+                "    <f>&lt;att&gt;</f>\n" +
+                "    <g> &ele; g</g>\n" +
+                "    <h>&ele2;</h>\n" +
+                "</author>\n");
+
+        lsSerializer.getDomConfig().setParameter("entities", Boolean.FALSE);
+        System.out.println("test with entities is false");
+        Assert.assertEquals(lsSerializer.writeToString(document),
+                "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" +
+                "<!ENTITY name 'Jo Smith'>\n" +
+                "<!ENTITY name1 '&name;'>\n" +
+                "<!ENTITY name2 '&name1;'>\n" +
+                "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" +
+                "<!ENTITY ele1 '&ele;'>\n" +
+                "<!ENTITY ele2 '&ele1;'>\n" +
+                "]>\n" +
+                "<author>\n" +
+                "    <a>&name;Jo Smith</a>\n" +
+                "    <b>b &name;Jo Smith &name;Jo Smith b</b>\n" +
+                "    <c> &name;Jo Smith </c>\n" +
+                "    <d>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "        d\n" +
+                "    </d>\n" +
+                "    <e>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "        eee \n" +
+                "    </e>\n" +
+                "    <f>&lt;att&gt;</f>\n" +
+                "    <g>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "         g\n" +
+                "    </g>\n" +
+                "    <h>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "    </h>\n" +
+                "</author>\n");
+
+    }
 }
diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8169112.xsl b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8169112.xsl
new file mode 100644
index 0000000..e16639b
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8169112.xsl
@@ -0,0 +1,8382 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+                xmlns:TRI="http://www.exchangenetwork.net/schema/TRI/6"
+                xmlns:sc="urn:us:net:exchangenetwork:sc:1:0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                exclude-result-prefixes="TRI sc">
+  <xsl:output method="html" version="4.0" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" doctype-system="http://www.w3.org/TR/html4/loose.dtd" />
+  <xsl:template match="/">
+    <html>
+    <head>
+      <title>TRI Reporting Form</title>
+      <script type="text/javascript">
+				var PhantomJSPrinting = {
+					header: {
+						height: '0.0in',
+						contents: function(pageNum, numPages) { return ""; }
+						},
+					footer: {
+						height: '0.0in',
+						contents: function(pageNum, numPages) { return ""; }
+						}
+				};
+	  </script>
+      <style type="text/css">
+          p {
+            font-family: Arial;
+            padding: 0;
+            margin: 0;
+            border: 0;
+          }
+
+          .answerText {
+              color: blue;
+              font-size: 9pt;
+              font-weight: bold;
+          }
+
+          .smallAnswer {
+              color: blue;
+              font-size: 8pt;
+              font-weight: bold;
+          }
+
+          .teqAnswer {
+              color: blue;
+              font-size: 8pt;
+              font-weight: bold;
+          }
+
+          .fieldLabel {
+              font-family: Arial, Helvetica, sans-serif;
+              font-size: 12px;
+              font-weight: bold;
+              padding-right: 5px;
+          }
+
+          a { padding-right: 10px; }
+
+          @page land { size: landscape; margin: 0.1in; }
+
+          .landscapeArea { page: land; width: 1010px; page-break-before: always; }
+
+          @page { margin: 0.1in; }
+
+          }
+        </style>
+    </head>
+    <body style="font-family: arial">
+    <xsl:for-each select="//TRI:Report">
+      <xsl:variable name="formID"><xsl:value-of select="sc:ReportIdentifier"/></xsl:variable>
+	<xsl:variable name="OMBNumberFormR">
+	<xsl:choose>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2005'">2070-0093</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2006'">2070-0093</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2007'">2070-0093</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2008'">2070-0093</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2009'">2025-0009</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2010'">2025-0009</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2011'">2025-0009</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2012'">2025-0009</xsl:when>
+	        </xsl:choose>
+	</xsl:variable>
+	<xsl:variable name="OMBNumberFormA">
+	 <xsl:choose>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2005'">2070-0143</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2006'">2070-0143</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2007'">2070-0143</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2008'">2070-0143</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2009'">2025-0010</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2010'">2025-0010</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2011'">2025-0009</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2012'">2025-0009</xsl:when>
+	        </xsl:choose>
+	</xsl:variable>
+	<xsl:variable name="OMBNumberSchedule1">
+	  <xsl:choose>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2008'">2025-0007</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2009'">2025-0007</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2010'">2025-0007</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2011'">2025-0009</xsl:when>
+	          <xsl:when test="TRI:SubmissionReportingYear = '2012'">2025-0009</xsl:when>
+	        </xsl:choose>
+	</xsl:variable>
+
+      <xsl:variable name="RevisionDateFormR">
+        <xsl:choose>
+           <xsl:when test="TRI:SubmissionReportingYear = '2005'">08/2005</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2006'">08/2006</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2007'">01/2008</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2008'">08/2008</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2009'">10/2009</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2010'">10/2009</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2011'">10/2011</xsl:when>
+           <xsl:when test="TRI:SubmissionReportingYear = '2012'">10/2012</xsl:when>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="RevisionDateFormA">
+        <xsl:choose>
+          <xsl:when test="TRI:SubmissionReportingYear = '2005'">08/2005</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2006'">11/2006</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2007'">01/2008</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2008'">03/2009</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2009'">10/2009</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2010'">03/2009</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2011'">10/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2012'">10/2012</xsl:when>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:variable name="ApprovalDateFormR">
+        <xsl:choose>
+          <xsl:when test="TRI:SubmissionReportingYear = '2005'">01/31/2008</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2006'">01/31/2008</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2007'">01/31/2010</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2008'">03/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2009'">07/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2010'">07/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2011'">10/31/2014</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2012'">10/31/2014</xsl:when>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="ApprovalDateFormA">
+        <xsl:choose>
+          <xsl:when test="TRI:SubmissionReportingYear = '2005'">01/31/2008</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2006'">01/31/2008</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2007'">03/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2008'">03/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2009'">07/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2010'">07/31/2011</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2011'">10/31/2014</xsl:when>
+          <xsl:when test="TRI:SubmissionReportingYear = '2012'">10/31/2014</xsl:when>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="ApprovalDateSchedule1">
+		  <xsl:choose>
+			  <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'"> 07/31/2011</xsl:when>
+			  <xsl:otherwise>10/31/2014</xsl:otherwise>
+		  </xsl:choose>
+      </xsl:variable>
+
+      <xsl:variable name="ScheduleOneNA">
+      <xsl:choose>
+          <xsl:when test="TRI:SubmissionReportingYear &gt; '2007'
+                          and TRI:ChemicalIdentification/sc:CASNumber = 'N150'
+                          and count(descendant-or-self::TRI:ToxicEquivalencyIdentification[TRI:ToxicEquivalencyNAIndicator = 'false']) &gt; 0">false</xsl:when>
+          <xsl:otherwise>true</xsl:otherwise>
+      </xsl:choose>
+      </xsl:variable>
+
+      <xsl:choose>
+      <xsl:when test="TRI:ReportType/TRI:ReportTypeCode = 'TRI_FORM_R'">
+          <xsl:if test="count(preceding::TRI:Report) &gt; 0">
+            <p style="page-break-before: always">&#160;</p>
+          </xsl:if>
+
+          <!-- Page 1 : Facility Information -->
+          <br/>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" border="0">
+            <tr>
+              <td align="center" width="100%">
+                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+                  *** Do not send to EPA: This is the final copy of your form.***
+                &#160;</span>
+              </td>
+            </tr>
+
+            <xsl:if test="SubmissionStatusText">
+              <tr>
+                <td align="left">
+                  <span class="fieldLabel" style="color:red">
+                    Form Status:
+                    <xsl:value-of select="SubmissionStatusText"/>
+                  &#160;</span>
+                </td>
+              </tr>
+            </xsl:if>
+            <xsl:if test="ValidationStatusText">
+              <tr>
+                <td align="left">
+                  <span class="fieldLabel" style="color:red">
+                    Validation Status:
+                    <xsl:value-of select="ValidationStatusText"/>
+                  &#160;</span>
+                </td>
+              </tr>
+            </xsl:if>
+
+
+          </table>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+            <tr>
+              <td width="30%">
+              	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                	<p style="font-size: 8pt">
+                	  Form Approved OMB Number:
+                	  <span class="smallAnswer">
+                	    <xsl:value-of select="$OMBNumberFormR"/>
+                	  &#160;</span>
+                	</p>
+                </xsl:if>
+              </td>
+              <td width="10%">
+                <br/>
+              </td>
+            </tr>
+            <tr>
+              <td width="60%">
+              	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	                <p style="font-size: 8pt"><i>(IMPORTANT: Read instructions before completing form; type or use fill-and-print form)</i></p>
+	            </xsl:if>
+              </td>
+              <td width="30%">
+              	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	                <p style="font-size: 8pt">
+    	              Approval Expires:
+        	          <span class="smallAnswer">
+            	        <xsl:value-of select="$ApprovalDateFormR"/>
+                	  &#160;</span>
+                	</p>
+                </xsl:if>
+              </td>
+              <td width="10%">
+                <p style="font-size: 8pt">
+                  <b>Page 1 of 5 </b>
+                </p>
+              </td>
+            </tr>
+
+          </table>
+          <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt;">
+              <tr>
+                <td colspan="2" align="center">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="0" cellspacing="0" cellpadding="0" frame="void">
+                    <tr>
+                      <td style="font-size: 8pt">
+                        <p style="font-size: 10pt"><b>EPA</b></p>
+                      </td>
+                      <td align="center" style="font-size: 10pt">
+                        <p style="font-size: 14pt"><b>FORM R</b></p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td>
+                        <p style="font-size: 8pt">
+                          United States <br/> Environmental Protection<br/>Agency
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          Section 313 of the Emergency Planning and Community Right-to-know Act of 1986,
+                          <br/>
+                          also known as Title III of the Superfund Amendments and Reauthorization Act.
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+                <td style="font-size:8pt">
+                    TRI Facility ID Number
+                    <hr />
+                    <span class="answerText">
+                      <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                    &#160;</span>
+                  <hr />
+                  Toxic Chemical, Category, or Generic Name
+                  <hr/>
+                  <span class="answerText">
+                    <xsl:choose>
+                      <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                        <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                      </xsl:otherwise>
+                    </xsl:choose>
+                  &#160;</span>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="3">
+                  <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt" frame="void">
+                    <tr>
+                      <td align="center" width="15%">
+                        <p style="font-size: 8pt">WHERE TO SEND COMPLETED FORMS: </p>
+                      </td>
+                      <td nowrap="nowrap">
+                        <p style="font-size: 8pt">
+                          1. TRI Data Processing Center
+                          <br />
+                          P.O. Box 10163
+                          <br />
+                          Fairfax, VA 22038
+                          <br />
+                        </p>
+                      </td>
+                      <td nowrap="nowrap">
+                        <p style="font-size: 8pt">2. APPROPRIATE STATE OFFICE<br/>(See instructions in Appendix F)</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td colspan="3"></td>
+                    </tr>
+                  </table>
+                  <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" frame="void">
+                    <tr>
+                      <td width="33%">
+                        <p style="font-size: 9pt">This section only applies if you are revising or withdrawing a previously submitted form, otherwise leave blank:</p>
+                      </td>
+                      <td align="center" width="33%">
+                        <p style="font-size: 9pt">
+                          Revision (Enter up to two code(s))
+                          <br/>
+                          <br/>
+                          [
+                          <span class="answerText">
+                            <xsl:value-of select="TRI:ChemicalReportRevisionCode[1]"/>
+                          &#160;</span>
+                          ] [
+                          <span class="answerText">
+                            <xsl:value-of select="TRI:ChemicalReportRevisionCode[2]"/>
+                          &#160;</span>
+                          ]
+                        </p>
+                      </td>
+                      <td align="center" width="34%">
+                        <p style="font-size: 9pt">
+                          Withdrawal (Enter up to two code(s))
+                          <br/>
+                          <br/>
+                          [
+                          <span class="answerText">
+                            <xsl:value-of select="TRI:ChemicalReportWithdrawalCode[1]"/>
+                          &#160;</span>
+                          ] [
+                          <span class="answerText">
+                            <xsl:value-of select="TRI:ChemicalReportWithdrawalCode[2]"/>
+                          &#160;</span>
+                          ]
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Important: See Instructions to determine when "Not Applicable (NA)" boxes should be checked.</p>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Part I. FACILITY IDENTIFICATION INFORMATION </p>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">SECTION 1. REPORTING YEAR :
+                    <u><span class="answerText"><xsl:value-of select="TRI:SubmissionReportingYear"/></span></u>
+                  </p>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">SECTION 2. TRADE SECRET INFORMATION</p>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" style="font-size: 8pt">
+                    <dl>
+                      <dt>2.1 Are you claiming the toxic chemical identified on
+                          page 2 trade secret?</dt>
+                      <dd>
+                        [
+                        <xsl:choose>
+                          <xsl:when test="TRI:ChemicalTradeSecretIndicator = 'true'">
+                            <span class="answerText">X</span>
+                          </xsl:when>
+                        </xsl:choose>
+                        ] Yes (Answer question 2.2; attach substantiation forms)
+                      </dd>
+                      <dd>
+                        [
+                        <xsl:choose>
+                          <xsl:when test="TRI:ChemicalTradeSecretIndicator = 'false'">
+                            <span class="answerText">X</span>
+                          </xsl:when>
+                        </xsl:choose>
+                        ] NO (Do not answer 2.2; go to Section 3)
+                      </dd>
+                    </dl>
+                </td>
+                <td align="left" style="font-size: 8pt">
+                    <dl>
+                      <dt>2.2 Is this copy</dt>
+                      <dd>
+                        [
+                        ] Sanitized [
+                        ] Unsanitized
+                      </dd>
+                      <dd>(Answer only if "Yes" in 2.1)</dd>
+                    </dl>
+                </td>
+                <td>
+                  <br/>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">SECTION 3. CERTIFICATION (Important: Read and sign after completing all form sections.)</p>
+                </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3">
+                  <p style="font-size: 8pt">
+                        I hereby certify that I have reviewed the attached documents and that, to the best of my knowledge and belief, the submitted
+                        information is true and complete and that the amounts and values in this report are accurate based on reasonable estimates using data
+                        available to the preparers of this report.
+                  </p>
+                  <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt" frame="above">
+                    <tr>
+                      <td>Name and official title of owner/operator or senior management official:</td>
+                      <td>Signature:</td>
+                      <td>Date Signed:</td>
+                    </tr>
+                    <tr>
+                      <td>
+  						<p>
+      						<span class="answerText"><xsl:value-of select="TRI:CertifierName"/>&#160;&#160;&#160;</span>
+      						<span class="answerText"><xsl:value-of select="TRI:CertifierTitleText"/></span>
+  						</p>
+					  </td>
+					  <td>
+    					<p>
+      						<span style="font-size: 9pt; color: red; font-weight: bold;">Reference Copy: Copy of Record Resides in CDX</span>
+    					</p>
+					  </td>
+					  <td>
+     					<span class="answerText">
+					    	<xsl:if test="TRI:CertificationSignedDate != '' and TRI:CertificationSignedDate != '1900-01-01'">
+	                    		<xsl:value-of select="TRI:CertificationSignedDate"/>
+	                   		</xsl:if>
+     					</span>
+					  </td>
+                    </tr>
+                  </table>
+                  </td>
+              </tr>
+              <tr>
+                <td align="left" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">SECTION 4. FACILITY IDENTIFICATION </p>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="3">
+                  <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0" border="1" frame="void" style="font-size: 8pt">
+                    <tr>
+                      <td width="5%" style="font-size: 8pt">
+                        <p style="font-size: 8pt">4.1</p>
+                      </td>
+                      <td colspan="4" width="45%">&#160;</td>
+                      <td colspan="2" width="20%">
+                        <p style="font-size: 8pt">TRI Facility ID Number</p>
+                      </td>
+                      <td colspan="2" width="30%">
+                        <p>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                    </tr>
+
+                    <xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+	                    <tr>
+	                      <td colspan="5">
+	                        <p style="font-size: 7pt">
+	                          <u style="font-size: 7pt">Facility or Establishment Name</u>
+	                          <br/>
+	                          <span class="answerText">
+	                            <xsl:value-of select="../TRI:Facility/sc:FacilitySiteName"/>
+	                          </span>
+	                        </p>
+	                      </td>
+	                      <td colspan="4">
+	                        <p style="font-size: 7pt">
+	                          <u style="font-size: 7pt">Facility or Establishment Name or Mailing Address(if different from street address)</u>
+	                          <br/>
+	                          <span class="answerText">
+	                            <xsl:value-of select="../TRI:Facility/TRI:MailingFacilitySiteName"/>
+	                          </span>
+	                        </p>
+	                      </td>
+	                    </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <tr>
+		                  <td colspan="9">
+		                   <p>
+		                    <u style="font-size: 7pt">Facility or Establishment Name</u>
+		                   </p>
+		                   <p>
+		                    <span class="answerText">
+		                     <xsl:value-of select="../TRI:Facility/sc:FacilitySiteName"/>
+		                    &#160;</span>
+		                   </p>
+		                  </td>
+		                </tr>
+                      </xsl:otherwise>
+                    </xsl:choose>
+
+                    <tr>
+                      <td colspan="5">
+                        <p>
+                          <u style="font-size: 7pt">Street</u>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocationAddressText"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                      <td colspan="4">
+                        <p>
+                          <u style="font-size: 7pt">Mailing Address (if different from physical street address)</u>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:MailingAddressText"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td colspan="5">
+                        <p>
+                        <xsl:choose>
+                            <xsl:when test="TRI:SubmissionReportingYear >= '2012' ">
+                               <u style="font-size: 7pt">City/County/Tribe/State/ZIP Code</u>
+                               <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocalityName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                          &#160;</span>
+                           /
+                          <span class="answerText">
+                           BIA Code: <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:TribalIdentity/sc:TribalCode"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:AddressPostalCode"/>
+                          &#160;</span>
+                          </xsl:when>
+
+                          <xsl:otherwise>
+                            <u style="font-size: 7pt">City/County/State/ZIP Code</u>
+                               <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocalityName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:AddressPostalCode"/>
+                          &#160;</span>
+                          </xsl:otherwise>
+                          </xsl:choose>
+
+                        </p>
+                      </td>
+                      <td colspan="3">
+                        <p>
+                          <u style="font-size: 7pt">City/State/ZIP Code</u>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:MailingAddressCityName"/>
+                          &#160;</span>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/TRI:ProvinceNameText"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:StateIdentity/sc:StateName"/>
+                          &#160;</span>
+                          /
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:AddressPostalCode"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                      <td colspan="1" width="15%">
+                        <p>
+                          <u style="font-size: 7pt">Country (Non-US)</u>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:CountryIdentity/sc:CountryName"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="3">
+                  <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0" border="1"
+                         frame="void" style="font-size: 8pt">
+                    <tr>
+                      <td width="5%" style="font-size: 8pt">
+                        <p style="font-size: 8pt">4.2</p>
+                      </td>
+                      <td nowrap="nowrap">
+                        <p style="font-size: 8pt">
+                          This report contains information for :
+                          <br/>
+                          (
+                          <u>Important: </u>
+                          check a or b; check c or d if applicable)
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          a. [
+                          <xsl:choose>
+                            <xsl:when test="TRI:SubmissionPartialFacilityIndicator = 'false'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ] An Entire facility
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          b. [
+                          <xsl:choose>
+                            <xsl:when test="TRI:SubmissionPartialFacilityIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ] Part of a facility
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          c. [
+                          <xsl:choose>
+                            <xsl:when test="TRI:SubmissionFederalFacilityIndicator = 'Y'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ] A Federal facility
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          d. [
+                          <xsl:choose>
+                            <xsl:when test="TRI:SubmissionGOCOFacilityIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ] GOCO
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="3">
+                  <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0" border="1"
+                         frame="void" style="font-size: 8pt">
+                    <tr>
+                      <td width="5%" style="font-size: 8pt">
+                        <p style="font-size: 8pt">4.3</p>
+                      </td>
+                      <td colspan="2" nowrap="nowrap" align="center">
+                        <p style="font-size: 8pt">Technical Contact name </p>
+                      </td>
+                      <td colspan="2">
+                        <span class="answerText" style="width:150px; word-wrap:break-word;">
+                          <xsl:value-of select="TRI:TechnicalContactNameText/sc:IndividualFullName"/>
+                        &#160;</span>
+                      </td>
+                      <td colspan="2" nowrap="nowrap">
+                        <p style="font-size: 8pt">
+                          <u style="font-size: 7pt">Email Address</u>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="TRI:TechnicalContactEmailAddressText"/>
+                          &#160;</span>
+                        </p>
+                      </td>
+                      <td colspan="2" nowrap="nowrap">
+                        <p style="font-size: 8pt">
+       					<xsl:choose>
+							<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+        						<u style="font-size: 7pt">Telephone Number (include area code and ext.)</u>
+        		 			</xsl:when>
+        					<xsl:otherwise>
+        						<u style="font-size: 7pt">Telephone Number (include area code)</u>
+        					</xsl:otherwise>
+       					</xsl:choose>
+                          <br/>
+                          <span class="answerText">
+                            <xsl:value-of select="substring(TRI:TechnicalContactPhoneText,1, 3)"/>&#45;<xsl:value-of select="substring(TRI:TechnicalContactPhoneText,4, 3)"/>&#45;<xsl:value-of select="substring(TRI:TechnicalContactPhoneText,7)"/>
+                          &#160;</span>
+                          <xsl:if test="TRI:SubmissionReportingYear &gt; '2013' ">
+                          	 <span class="answerText">
+                            	<xsl:if test="string-length(TRI:TechnicalContactPhoneExtText) &gt; 0 ">
+									&#045; &#160;<xsl:value-of select="TRI:TechnicalContactPhoneExtText"/>
+								</xsl:if>
+                          	&#160;</span>
+                          </xsl:if>
+                        </p>
+                      </td>
+                    </tr>
+                    <xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear >= '2007' or TRI:SubmissionReportingYear &lt;= '2004'">
+                        <tr>
+                          <td width="5%" style="font-size: 8pt">
+                            <p style="font-size: 8pt">4.4</p>
+                          </td>
+                          <td colspan="2" nowrap="nowrap" align="center">
+                            <p style="font-size: 8pt">Public Contact name </p>
+                          </td>
+                          <td colspan="2">
+                            <span class="answerText">
+                              <xsl:value-of select="TRI:PublicContactNameText"/>
+                            &#160;</span>
+                          </td>
+                          <td colspan="2" nowrap="nowrap">
+                            <p style="font-size: 8pt">
+                              <u style="font-size: 7pt">Email Address</u>
+                              <br/>
+                              <span class="answerText">
+                                <xsl:value-of select="TRI:PublicContactEmailAddressText"/>
+                              &#160;</span>
+                            </p>
+                          </td>
+                          <td colspan="2" nowrap="nowrap">
+                            <p style="font-size: 8pt">
+                            <xsl:choose>
+								<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+        							<u style="font-size: 7pt">Telephone Number (include area code and ext.)</u>
+        						</xsl:when>
+        						<xsl:otherwise>
+        							<u style="font-size: 7pt">Telephone Number (include area code)</u>
+        						</xsl:otherwise>
+       						</xsl:choose>
+                              <br/>
+                              <span class="answerText">
+                              	<xsl:if test="string-length(TRI:PublicContactPhoneText)  &gt; 0">
+                              		<xsl:value-of select="substring(TRI:PublicContactPhoneText,1, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,4, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,7)"/>
+                              	</xsl:if>
+                              &#160;</span>
+                              <xsl:if test="TRI:SubmissionReportingYear &gt; '2013' ">
+                          		 <span class="answerText">
+                            		<xsl:if test="string-length(TRI:PublicContactPhoneExtText) &gt; 0 ">
+										&#045; &#160;<xsl:value-of select="TRI:PublicContactPhoneExtText"/>
+									</xsl:if>
+                          		&#160;</span>
+                          	  </xsl:if>
+                            </p>
+                          </td>
+                        </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <tr>
+                          <td width="5%" style="font-size: 8pt">
+                            <p style="font-size: 8pt">4.4</p>
+                          </td>
+                          <td colspan="2" nowrap="nowrap" align="center">
+                            <p style="font-size: 8pt">Public Contact name </p>
+                          </td>
+                          <td colspan="4">
+                            <span class="answerText">
+                              <xsl:value-of select="TRI:PublicContactNameText"/>
+                            &#160;</span>
+                          </td>
+                          <td colspan="2" nowrap="nowrap">
+                            <p style="font-size: 8pt">
+                            <xsl:choose>
+								<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+        							<u style="font-size: 7pt">Telephone Number (include area code and ext.)</u>
+        						</xsl:when>
+        						<xsl:otherwise>
+        							<u style="font-size: 7pt">Telephone Number (include area code)</u>
+        						</xsl:otherwise>
+       						</xsl:choose>
+                              <br/>
+                              <span class="answerText">
+                               <xsl:if test="string-length(TRI:PublicContactPhoneText)  &gt; 0">
+                                <xsl:value-of select="substring(TRI:PublicContactPhoneText,1, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,4, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,7)"/>
+                                </xsl:if>
+                              &#160;</span>
+                              <xsl:if test="TRI:SubmissionReportingYear &gt; '2013' ">
+                          		 <span class="answerText">
+                            		<xsl:if test="string-length(TRI:PublicContactPhoneExtText) &gt; 0 ">
+										&#045; &#160;<xsl:value-of select="TRI:PublicContactPhoneExtText"/>
+									</xsl:if>
+                          		&#160;</span>
+                          	  </xsl:if>
+                            </p>
+                          </td>
+                        </tr>
+                      </xsl:otherwise>
+                    </xsl:choose>
+                    <xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear &lt;= '2005'">
+                        <tr>
+                          <td width="5%" style="font-size: 8pt">
+                            <p style="font-size: 8pt">4.5</p>
+                          </td>
+                          <td colspan="2" nowrap="nowrap" width="35%"
+                              align="center">
+                            <p style="font-size: 8pt">SIC Code(s) (4 digits)</p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              a.
+                              <xsl:for-each select="../TRI:Facility/TRI:FacilitySIC">
+                                <xsl:choose>
+                                  <xsl:when test="sc:SICPrimaryIndicator = 'Primary'">
+                                    <span class="answerText">
+                                      <xsl:value-of select="sc:SICCode"/>
+                                      (Primary)
+                                    &#160;</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              b.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 1">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[2]/sc:SICCode"/>
+                                  &#160;</span>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              c.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 2">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[3]/sc:SICCode"/>
+                                  &#160;</span>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              d.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 3">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[4]/sc:SICCode"/>
+                                  &#160;</span>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              e.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 4">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[5]/sc:SICCode"/>
+                                  &#160;</span>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              f.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 5">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[6]/sc:SICCode"/>
+                                  &#160;</span>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                        </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <tr>
+                          <td width="5%" style="font-size: 8pt">
+                            <p style="font-size: 8pt">4.5</p>
+                          </td>
+                          <td colspan="2" nowrap="nowrap" width="35%"
+                              align="center">
+                            <p style="font-size: 8pt">NAICS Code(s) (6 digits)</p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              a.
+                              <xsl:for-each select="../TRI:Facility/TRI:FacilityNAICS">
+                                <xsl:choose>
+                                  <xsl:when test="sc:NAICSPrimaryIndicator = 'Primary'">
+                                    <span class="answerText">
+                                      <xsl:value-of select="sc:NAICSCode"/>
+                                      (Primary)
+                                    &#160;</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              b.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 1">
+                                <xsl:choose>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[1]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[1]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[2]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[2]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              c.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 2">
+                                  <xsl:choose>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[3]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[3]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              d.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 3">
+                                   <xsl:choose>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[4]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[4]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              e.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 4">
+                                   <xsl:choose>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[5]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[5]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                          <td colspan="1" width="10%">
+                            <p style="font-size: 8pt">
+                              f.
+                              <xsl:choose>
+                                <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 5">
+                                   <xsl:choose>
+                                  <xsl:when test="../TRI:Facility/TRI:FacilityNAICS[6]/sc:NAICSPrimaryIndicator = 'Unknown'">
+                                  <span class="answerText">
+                                    <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[6]/sc:NAICSCode"/>
+                                  &#160;</span>
+                                  </xsl:when>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </p>
+                          </td>
+                        </tr>
+                      </xsl:otherwise>
+                    </xsl:choose>
+                    <tr>
+                      <td colspan="9">
+                        <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0"
+                               border="1" frame="void" style="font-size: 8pt"
+                               rules="all">
+                          <tr>
+                            <td width="5%" style="font-size: 8pt">
+                              <p style="font-size: 8pt">4.6</p>
+                            </td>
+                            <td nowrap="nowrap">
+                              <p style="font-size: 8pt">
+                                Dun and Bradstreet
+                                <br/>
+                                Number(s) (9 digits)
+                              </p>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2">
+                              <p style="font-size: 8pt">
+                                a.
+                                <span class="answerText">
+                                  <xsl:value-of select="../TRI:Facility/TRI:FacilityDunBradstreetCode[1]"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2">
+                              <p style="font-size: 8pt">
+                                b.
+                                <span class="answerText">
+                                  <xsl:value-of select="../TRI:Facility/TRI:FacilityDunBradstreetCode[2]"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                          </tr>
+                        </table>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="9" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 5. PARENT COMPANY INFORMATION</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" style="font-size: 8pt">
+                        <p style="font-size: 8pt">5.1</p>
+                      </td>
+                      <td colspan="2" align="left">
+                        <p style="font-size: 8pt">
+                        <xsl:choose>
+						  <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+						    Name of Parent Company
+						  </xsl:when>
+						  <xsl:otherwise>
+						    Name of U.S. Parent Company (for TRI Reporting purposes)
+						  </xsl:otherwise>
+						</xsl:choose>
+                        </p>
+                      </td>
+                      <xsl:choose>
+						  <xsl:when test="TRI:SubmissionReportingYear &gt; '2010'">
+						  <td colspan="5">
+                        <span class="answerText">
+                        <xsl:if test="../TRI:Facility/TRI:ParentCompanyNameText != 'NA'">
+                    		<xsl:value-of select="../TRI:Facility/TRI:ParentCompanyNameText"/>
+                   		</xsl:if>
+                        &#160;</span>
+                        <br/>
+                      </td>
+                      <td colspan="1">
+                        <p style="font-size: 8pt">
+						    No U.S. Parent Company (for TRI Reporting purposes) [
+					    <xsl:choose>
+                            <xsl:when test="../TRI:Facility/TRI:ParentCompanyNameNAIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ]
+                        </p>
+                      </td>
+						  </xsl:when>
+						  <xsl:otherwise>
+					                       <td colspan="1">
+                        <p style="font-size: 8pt">
+						    NA [
+
+					    <xsl:choose>
+                            <xsl:when test="../TRI:Facility/TRI:ParentCompanyNameNAIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ]
+                        </p>
+                      </td>
+                      <td colspan="5">
+                        <span class="answerText">
+                          <xsl:value-of select="../TRI:Facility/TRI:ParentCompanyNameText"/>
+                        &#160;</span>
+                        <br/>
+                      </td>
+					  	  </xsl:otherwise>
+					  </xsl:choose>
+
+                    </tr>
+                    <tr>
+                      <td width="5%" style="font-size: 8pt">
+                        <p style="font-size: 8pt">5.2</p>
+                      </td>
+                      <td colspan="2" align="left">
+                        <p style="font-size: 8pt">Parent Company's Dun &amp; Bradstreet Number </p>
+                      </td>
+                      <td colspan="1">
+                        <p style="font-size: 8pt">
+                          NA [
+                          <xsl:choose>
+                            <xsl:when test="../TRI:Facility/TRI:ParentDunBradstreetCode = 'NA'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ]
+                        </p>
+                      </td>
+                      <td colspan="5">
+                        <xsl:choose>
+                          <xsl:when test="../TRI:Facility/TRI:ParentDunBradstreetCode != 'NA'">
+                            <span class="answerText">
+                              <xsl:value-of select="../TRI:Facility/TRI:ParentDunBradstreetCode"/>
+                            &#160;</span>
+                          </xsl:when>
+                        </xsl:choose>
+                        <br/>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </center>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+              <td width="60%">
+                <p style="font-size: 8pt">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		EPA Form 9350-1 (Rev. <xsl:value-of select="$RevisionDateFormR"/>) - Previous editions are obsolete.
+                  	</xsl:if>
+                </p>
+              </td>
+              <td width="30%">
+                <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+              </td>
+            </tr>
+          </table>
+
+          <p style="page-break-before: always">&#160;</p>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1" style="font-size: 8pt" border="0">
+            <tr>
+            <!--<td width="90%">
+                <a name="PG-2_{$formID}"></a>
+                <p style="font-size: 8pt">
+                  <a href="#PG-1_{$formID}">1</a>
+                  <a href="#PG-2_{$formID}">2</a>
+                  <a href="#PG-3_{$formID}">3</a>
+                  <a href="#PG-4_{$formID}">4</a>
+                  <a href="#PG-5_{$formID}">5</a>
+                  <a href="#PG-6_{$formID}">Additional Info</a>
+                  <xsl:if test="$ScheduleOneNA = 'false'">
+                      <a href="#S1_PG-1_{$formID}">Schedule 1</a>
+                  </xsl:if>
+                </p>
+              </td>-->
+              <td width="10%">
+                <p style="font-size: 8pt">
+                  <b>Page 2 of 5 </b>
+                </p>
+              </td>
+            </tr>
+          </table>
+          <center>
+          <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+           </tr>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt">
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                         cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td width="65%" align="center" style="font-size: 10pt">
+                        <p style="font-size: 10pt">
+                          <b>EPA FORM R</b>
+                          <br/>
+                          <b>PART II. CHEMICAL - SPECIFIC INFORMATION</b>
+                        </p>
+                      </td>
+                      <td>
+                          TRI Facility ID Number
+                          <hr />
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                          &#160;</span>
+                        <hr />
+                        Toxic Chemical, Category, or Generic Name
+                        <hr/>
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <tr>
+                      <td align="left" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 1. TOXIC CHEMICAL IDENTITY </p>
+                      </td>
+                      <td align="left" style="font-size: 8pt">
+                        <p style="font-size: 8pt">(Important: DO NOT complete this section if you are reporting a mixture component in Section 2 below.)</p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" width="5%">
+                  <p style="font-size: 8pt">1.1</p>
+                </td>
+                <td width="95%" style="font-size: 8pt">
+                    CAS Number (Important: Enter only one number exactly as it
+                    appears on the Section 313 list. Enter category code if
+                    reporting a chemical category.)
+                    <hr />
+                    <span style="color: blue;text-indent: 5em;font-weight:bold">
+                      <xsl:value-of select="TRI:ChemicalIdentification/sc:CASNumber"/>
+                    &#160;</span>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" width="5%">
+                  <p style="font-size: 8pt">1.2</p>
+                </td>
+                <td style="font-size: 8pt">
+                    Toxic Chemical or Chemical Category Name (Important: Enter
+                    only one name exactly as it appears on the Section 313 list.)
+                    <hr />
+                    <span style="color: blue;font-size: 8pt;text-indent: 5em;font-weight:bold">
+                      <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                    &#160;</span>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" width="5%">
+                  <p style="font-size: 8pt">1.3</p>
+                </td>
+                <td style="font-size: 8pt">
+                    Generic Chemical Name (Important: Complete only if Part I,
+                    Section 2.1 is checked "Yes". Generic Name must be
+                    structurally descriptive).
+                    <hr />
+                    <span style="color: blue;font-size: 8pt;text-indent: 5em;font-weight:bold">NA&#160;</span>
+                </td>
+              </tr>
+
+              <!-- Section 1.4, only display if < RY08 -->
+              <xsl:if test="TRI:SubmissionReportingYear &lt;= '2008' and TRI:SubmissionReportingYear >= '2000'">
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td align="center" width="5%">
+                        <p style="font-size: 8pt">1.4</p>
+                      </td>
+                      <td colspan="17">
+                        <p style="font-size: 8pt">
+                          Distribution of Each Member of the Dioxin and
+                          Dioxin-like Compounds Category.
+                          <br/>
+                          (If there are any numbers in boxes 1-17, then every
+                          field must be filled in with either 0 or some number
+                          between 0.01 and 100. Distribution should be reported
+                          in percentages and the total should equal 100%. If you
+                          do not have speciation data available, indicate NA.)
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <xsl:for-each select="TRI:ChemicalIdentification">
+                        <xsl:choose>
+                          <xsl:when test="TRI:DioxinDistributionNAIndicator= 'true'">
+                            <td align="center" width="5%">
+                              <p style="font-size: 8pt">
+                                NA [
+                                <span class="answerText">X</span>
+                                ]
+                              </p>
+                            </td>
+                            <td><p style="font-size: 8pt">1<hr/></p></td>
+                            <td><p style="font-size: 8pt">2<hr/></p></td>
+                            <td><p style="font-size: 8pt">3<hr/></p></td>
+                            <td><p style="font-size: 8pt">4<hr/></p></td>
+                            <td><p style="font-size: 8pt">5<hr/></p></td>
+                            <td><p style="font-size: 8pt">6<hr/></p></td>
+                            <td><p style="font-size: 8pt">7<hr/></p></td>
+                            <td><p style="font-size: 8pt">8<hr/></p></td>
+                            <td><p style="font-size: 8pt">9<hr/></p></td>
+                            <td><p style="font-size: 8pt">10<hr/></p></td>
+                            <td><p style="font-size: 8pt">11<hr/></p></td>
+                            <td><p style="font-size: 8pt">12<hr/></p></td>
+                            <td><p style="font-size: 8pt">13<hr/></p></td>
+                            <td><p style="font-size: 8pt">14<hr/></p></td>
+                            <td><p style="font-size: 8pt">15<hr/></p></td>
+                            <td><p style="font-size: 8pt">16<hr/></p></td>
+                            <td><p style="font-size: 8pt">17<hr/></p></td>
+                          </xsl:when>
+                          <xsl:otherwise>
+                            <td align="center" width="5%">
+                              <p style="font-size: 8pt">NA [ ]</p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                1
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution1Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                2
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution2Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                3
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution3Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                4
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution4Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                5
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution5Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                6
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution6Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                7
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution7Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                8
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution8Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                9
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution9Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                10
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution10Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                11
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution11Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                12
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution12Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                13
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution13Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                14
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution14Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                15
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution15Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                16
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution16Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                17
+                                <hr/>
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:DioxinDistribution17Percent"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                          </xsl:otherwise>
+                        </xsl:choose>
+                      </xsl:for-each>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              </xsl:if>
+              <!-- End prior to RY08 dioxin section -->
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <tr>
+                      <td align="left" colspan="2" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 2. MIXTURE COMPONENT
+                                                  IDENTITY (Important: DO NOT
+                                                  complete this section if you
+                                                  completed Section 1.)</p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" width="5%">
+                  <p style="font-size: 8pt">2.1</p>
+                </td>
+                <td style="font-size: 8pt">
+                    Generic Chemical Name Provided by Supplier (Important:
+                    Maximum of 70 characters, including numbers, spaces, and
+                    punctuation.)
+                    <hr />
+                    <b style="color: blue;font-size: 9pt; font-family:arial">
+                      <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                    </b>
+                    <br />
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+                    <tr>
+                      <td align="left" colspan="2" style="font-size: 8pt">
+                          SECTION 3. ACTIVITIES AND USES OF THE TOXIC CHEMICAL AT THE FACILITY
+                          <br />
+                          (Important: Check all that apply.)
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td align="center" width="5%">3.1</td>
+                      <td>Manufacture the toxic chemical:</td>
+                      <td align="center" width="5%">3.2</td>
+                      <td>Process the toxic chemical:</td>
+                      <td align="center" width="5%">3.3</td>
+                      <td>Otherwise use the toxic chemical:</td>
+                    </tr>
+                    <tr>
+                      <td colspan="2" align="center">
+                          a. [
+                          <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                            <xsl:choose>
+                              <xsl:when test="TRI:ChemicalProducedIndicator = 'true'">
+                                <span class="answerText">X</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ] Produce b. [
+                          <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                            <xsl:choose>
+                              <xsl:when test="TRI:ChemicalImportedIndicator = 'true'">
+                                <span class="answerText">X</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ] Import
+                      </td>
+                      <td colspan="4"><br /></td>
+                    </tr>
+                    <tr>
+                      <td colspan="2" style="font-size: 8pt">
+                          <dl>
+                            <dt>If produce or import:</dt>
+                            <dd>
+                              c. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalUsedProcessedIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] For on-site use/processing
+                            </dd>
+                            <dd>
+                              d. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalSalesDistributionIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] For sale/distribution
+                            </dd>
+                            <dd>
+                              e. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalByproductIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As a byproduct
+                            </dd>
+                            <dd>
+                              f. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalManufactureImpurityIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As an impurity
+                            </dd>
+                          </dl>
+                      </td>
+                      <td colspan="2" style="font-size: 8pt">
+                          <dl>
+                            <dd>
+                              a. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalReactantIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As a reactant
+                            </dd>
+                            <dd>
+                              b. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalFormulationComponentIndicator= 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As a formulation component
+                            </dd>
+                            <dd>
+                              c. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalArticleComponentIndicator= 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As an article component
+                            </dd>
+                            <dd>
+                              d. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalRepackagingIndicator= 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] Repackaging
+                            </dd>
+                            <dd>
+                              e. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalProcessImpurityIndicator= 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As an impurity
+                            </dd>
+                          </dl>
+                      </td>
+                      <td colspan="2" style="font-size: 8pt">
+                          <dl>
+                            <dd>
+                              a. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalProcessingAidIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As a chemical processing aid
+                            </dd>
+                            <dd>
+                              b. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalManufactureAidIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] As a manufacturing aid
+                            </dd>
+                            <dd>
+                              c. [
+                              <xsl:for-each select="TRI:ChemicalActivitiesAndUses">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:ChemicalAncillaryUsageIndicator= 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:for-each>
+                              ] Ancillary or other use
+                            </dd>
+                          </dl>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <tr>
+                      <td align="left" colspan="2" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 4. MAXIMUM AMOUNT OF
+                                                  THE TOXIC CHEMICAL ON-SITE AT
+                                                  ANY TIME DURING THE CALENDAR
+                                                  YEAR </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td align="right" width="5%">
+                  <p style="font-size: 8pt">4.1</p>
+                </td>
+                <td style="font-size: 8pt">
+                  [
+                  <span class="answerText">
+                    <xsl:if test="not(string-length(TRI:MaximumChemicalAmountCode)=0)">
+                      <xsl:value-of select="TRI:MaximumChemicalAmountCode"/>
+                    </xsl:if>
+                  &#160;</span>
+                  ] (Enter two-digit code from instruction package.)
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <tr>
+                      <td align="left" colspan="2" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 5.QUANTITY OF THE
+                                                  TOXIC CHEMICAL ENTERING EACH
+                                                  ENVIRONMENTAL MEDIUM ON-SITE </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                         cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td colspan="3"></td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          A. Total Release (pounds/year*)
+                          <br/>
+                          (Enter range code or estimate**)
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          B. Basis of Estimate
+                          <br/>
+                          (Enter code)
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">C. Percent from Stormwater</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="center" width="5%">
+                        <p style="font-size: 8pt">5.1</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Fugitive or non-point
+                          <br/>
+                          air emissions
+                        </p>
+                      </td>
+                      <td style="font-size: 8pt">
+                        <p style="font-size: 8pt">
+                          NA [
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR FUG'">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ]
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR FUG'">
+                                <span class="answerText">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                      <br/>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                      <br/>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR FUG'">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td style="background-color: gray">&#160;</td>
+                    </tr>
+                    <tr>
+                      <td align="center" width="5%">
+                        <p style="font-size: 8pt">5.2</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Stack or point
+                          <br/>
+                          air emissions
+                        </p>
+                      </td>
+                      <td style="font-size: 8pt">
+                        <p style="font-size: 8pt">
+                          NA [
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR STACK'">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ]
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR STACK'">
+                                <span class="answerText">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                      <br/>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                      <br/>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'AIR STACK'">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td style="background-color: gray">&#160;</td>
+                    </tr>
+                    <tr>
+                      <td align="center" width="5%">
+                        <p style="font-size: 8pt">5.3</p>
+                      </td>
+	                  <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Discharges to receiving streams or
+	                          <br/>
+	                          water bodies (Enter one name per box)
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <xsl:choose>
+							  <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+							    &#160;
+							  </xsl:when>
+							  <xsl:otherwise>
+								<p style="font-size: 8pt">
+								  NA [
+								  <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+									<xsl:choose>
+									  <xsl:when test="TRI:EnvironmentalMediumCode = 'WATER'">
+										<xsl:choose>
+										  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+											<span class="answerText">X</span>
+										  </xsl:when>
+										</xsl:choose>
+									  </xsl:when>
+									</xsl:choose>
+								  </xsl:for-each>
+								  ]
+								</p>
+							  </xsl:otherwise>
+							</xsl:choose>
+	                  </td>
+					  <td colspan="2" style="background-color: gray">&#160;</td>
+                      <td style="background-color: gray">&#160;</td>
+                    </tr>
+                    <tr>
+                      <td colspan="2" style="font-size: 9pt" align="center">
+                        <p style="font-size: 8pt">Stream or Water Body Name </p>
+                      </td>
+                      <xsl:choose>
+                      	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+                      		<td style="font-size: 9pt" align="center">
+                      			<p style="font-size: 8pt">Reach Code (optional)</p>
+                      		</td>
+                      	</xsl:when>
+                      </xsl:choose>
+                      <td>
+                        <br/>
+                      </td>
+                      <td>
+                        <br/>
+                      </td>
+                      <td>
+                        <br/>
+                      </td>
+                    </tr>
+                    <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                      <xsl:choose>
+                        <xsl:when test="TRI:EnvironmentalMediumCode = 'WATER'">
+                          <xsl:choose>
+                            <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                              <tr>
+                                <td align="center" width="5%">
+                                  <p style="font-size: 8pt">5.3.1</p>
+                                </td>
+                                <td colspan="2">
+                                  <p style="font-size: 8pt">
+                                    <span class="answerText">NA&#160;</span>
+                                    <br/>
+                                  </p>
+                                </td>
+                                <td></td>
+                                <td></td>
+                                <td></td>
+                                <xsl:choose>
+                                	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+                                		<td></td>
+                               	 	</xsl:when>
+                                </xsl:choose>
+                              </tr>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <tr>
+                                <td align="center" width="5%">
+                                  <p style="font-size: 8pt">
+                                    5.3.<xsl:value-of select="TRI:WaterStream/TRI:WaterSequenceNumber"/>
+                                  </p>
+                                </td>
+                                <td>
+                                  <p style="font-size: 8pt">
+                                    <span class="answerText">
+                                      <xsl:value-of select="TRI:WaterStream/TRI:StreamName"/>
+                                    &#160;</span>
+                                    <br/>
+                                  </p>
+                                </td>
+                                <xsl:choose>
+	                            <xsl:when test="../TRI:SubmissionReportingYear &gt; '2013'">
+	                                	<td>
+	                                	  <p style="font-size: 8pt">
+	                                	    <span class="answerText">
+	                                	      <xsl:value-of select="TRI:WaterStream/TRI:StreamReachCode"/>
+	                                	    &#160;</span>
+	                                	    <br/>
+	                                	  </p>
+	                                	</td>
+	                                </xsl:when>
+                                </xsl:choose>
+                                <td>
+                                  <p style="font-size: 8pt">
+                                    <span class="answerText">
+                                      <xsl:choose>
+                                        <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+                                          <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                          <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                        </xsl:otherwise>
+                                      </xsl:choose>
+                                    &#160;</span>
+                                    <br/>
+                                  </p>
+                                </td>
+                                <td>
+                                  <p style="font-size: 8pt">
+                                    <span class="answerText">
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                    &#160;</span>
+                                    <br/>
+                                  </p>
+                                </td>
+                                <td>
+                                  <p style="font-size: 8pt">
+                                    <span class="answerText">
+                                      <xsl:choose>
+                                      <xsl:when test="TRI:WaterStream/TRI:ReleaseStormWaterNAIndicator = 'true'">NA</xsl:when>
+                                      <xsl:otherwise><xsl:value-of select="TRI:WaterStream/TRI:ReleaseStormWaterPercent"/>%</xsl:otherwise>
+                                      </xsl:choose>
+                                    &#160;</span>
+                                    <br/>
+                                  </p>
+                                </td>
+                              </tr>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        </xsl:when>
+                      </xsl:choose>
+                    </xsl:for-each>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </center>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0"
+                 style="font-size: 8pt" border="0">
+            <tr>
+              <td colspan="2" align="right">
+                <p style="font-size: 8pt">*For Dioxin and Dioxin-like Compounds,
+                                          report in grams/year</p>
+              </td>
+            </tr>
+            <tr>
+              <td width="50%">
+                <p style="font-size: 8pt">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		EPA Form 9350-1 (Rev. <xsl:value-of select="$RevisionDateFormR"/>) - Previous editions are obsolete.
+                  	</xsl:if>
+                </p>
+              </td>
+              <td width="50%" align="right">
+                <p style="font-size: 8pt">**Range Codes: A=1-10 pounds; B=11-499
+                                          pounds; C=500-999 pounds.</p>
+              </td>
+            </tr>
+          </table>
+          <p style="page-break-before: always">&#160;</p>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0">
+            <tr>
+             <!--<td width="90%">
+                <a name="PG-3_{$formID}"></a>
+                <p style="font-size: 8pt">
+                  <a href="#PG-1_{$formID}">1</a>
+                  <a href="#PG-2_{$formID}">2</a>
+                  <a href="#PG-3_{$formID}">3</a>
+                  <a href="#PG-4_{$formID}">4</a>
+                  <a href="#PG-5_{$formID}">5</a>
+                  <a href="#PG-6_{$formID}">Additional Info</a>
+                  <xsl:if test="$ScheduleOneNA = 'false'">
+                      <a href="#S1_PG-1_{$formID}">Schedule 1</a>
+                  </xsl:if>
+                </p>
+              </td>-->
+              <td width="10%">
+                <p style="font-size: 8pt">
+                  <b>Page 3 of 5 </b>
+                </p>
+              </td>
+            </tr>
+          </table>
+          <center>
+          <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+          </tr>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%"
+                   style="font-size: 8pt">
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td width="65%" align="center" style="font-size: 10pt">
+                        <p style="font-size: 10pt">
+                          <b>EPA FORM R</b>
+                          <br/>
+                          <b>PART II. CHEMICAL - SPECIFIC INFORMATION (CONTINUED)</b>
+                        </p>
+                      </td>
+                      <td>
+                          TRI Facility ID Number
+                          <hr />
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                          &#160;</span>
+                        <hr />
+                        Toxic Chemical, Category, or Generic Name
+                        <hr />
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <tr>
+                      <td align="left" style="font-size: 8pt" colspan="2">
+                        <p style="font-size: 8pt">
+                          SECTION 5. QUANTITY OF THE TOXIC CHEMICAL ENTERING
+                          EACH ENVIRONMENTAL MEDIUM ON-SITE
+                          <font style="font-size: 7pt">(Continued)</font>
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                         cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td colspan="2"></td>
+                      <td style="font-size: 8pt" align="center">
+                        <p style="font-size: 8pt">
+                          <b>NA</b>
+                        </p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 8pt">A. Total Release
+                                                  (pounds/year*) (Enter range
+                                                  code** or estimate)</p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 8pt">B. Basis of Estimate (Enter
+                                                  code)</p>
+                      </td>
+                    </tr>
+                    <xsl:choose>
+                    	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+                    		<tr>
+                    	  		<td width="5%" align="center">
+                    	  			<p style="font-size: 8pt">5.4-5.5</p>
+                    	  		</td>
+                    	  		<td align="left">
+                    	  	  		<p style="font-size: 8pt">
+                    		      		Disposal to land on-site
+                    		      		<br/>
+                    		    	</p>
+                    		  	</td>
+                    		  	<td colspan="3" style="background-color: gray">&#160;</td>
+                    		</tr>
+                    	</xsl:when>
+                    </xsl:choose>
+                    <xsl:choose>
+          		      <xsl:when test="TRI:SubmissionReportingYear &gt;= '1991' and TRI:SubmissionReportingYear &lt;= '1995'">
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.4</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          UIC Injections Aggregate
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ8795'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ8795'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ8795'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+		                </tr>
+	                  </xsl:when>
+	                  <xsl:otherwise>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.4.1</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+		                        <xsl:choose>
+		                        	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+		                          		Class I Underground
+		                          		<br/>
+		                          		Injection wells
+		                        	</xsl:when>
+		                        	<xsl:otherwise>
+		                        		Underground Injection onsite
+		                        	  	<br/>
+		                        	  	to Class I wells
+		                        	</xsl:otherwise>
+		                        </xsl:choose>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ I'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ I'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                        </p>
+	                        <br/>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ I'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                        </p>
+	                        <br/>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.4.2</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                        <xsl:choose>
+	                        	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+	                        		Class II-V Underground
+	                          		<br/>
+	                          		Injection wells
+								</xsl:when>
+								<xsl:otherwise>
+									Underground Injection onsite
+	                          		<br/>
+	                          		to Class II-V wells
+								</xsl:otherwise>
+	                        </xsl:choose>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ IIV'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ IIV'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'UNINJ IIV'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+		                </tr>
+	                  </xsl:otherwise>
+                    </xsl:choose>
+                    <xsl:if test="TRI:SubmissionReportingYear &lt; '2014'">
+                    	<tr>
+                      		<td width="5%" align="center">
+                        		<p style="font-size: 8pt">5.5</p>
+                      		</td>
+                      		<td align="left">
+                        		<p style="font-size: 8pt">
+                          			Disposal to land on-site
+                          			<br/>
+                        		</p>
+                      		</td>
+                      		<td colspan="3" style="background-color: gray">&#160;</td>
+                    	</tr>
+                    </xsl:if>
+                    <xsl:choose>
+          		      <xsl:when test="TRI:SubmissionReportingYear &gt;= '1991' and TRI:SubmissionReportingYear &lt;= '1995'">
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.1</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Total Landfill Releases
+	                          <br/>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LANDF8795'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LANDF8795'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LANDF8795'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.1.A</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          RCRA subtitle C landfills
+	                          <br/>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'RCRA C'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'RCRA C'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'RCRA C'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.1.B</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Other landfills
+	                          <br/>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH LANDF'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH LANDF'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH LANDF'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                 </xsl:otherwise>
+                    </xsl:choose>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">5.5.2</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Land treatment/application
+                          <br/>
+                          farming
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          [
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LAND TREA'">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ]
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LAND TREA'">
+                                <span class="answerText">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                      <br/>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                      <br/>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'LAND TREA'">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <xsl:choose>
+          		      <xsl:when test="TRI:SubmissionReportingYear &gt;= '1991' and TRI:SubmissionReportingYear &lt;= '2002'">
+          		        <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.3</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Surface impoundment
+	                          <br/>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SURF IMP'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SURF IMP'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SURF IMP'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+          		      </xsl:when>
+          		      <xsl:otherwise>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.3A</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          RCRA Subtitle C
+	                          <br/>
+	                          surface impoundments
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3A'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3A'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3A'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">5.5.3B</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Other surface impoundments
+	                          <br/>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3B'">
+	                                <xsl:choose>
+	                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+	                                    <span class="answerText">X</span>
+	                                  </xsl:when>
+	                                </xsl:choose>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          ]
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3B'">
+	                                <span class="answerText">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+	                                      <br/>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+	                                      <br/>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+	                            <xsl:choose>
+	                              <xsl:when test="TRI:EnvironmentalMediumCode = 'SI 5.5.3B'">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+	                                &#160;</span>
+	                              </xsl:when>
+	                            </xsl:choose>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                  </xsl:otherwise>
+	                </xsl:choose>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">5.5.4</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Other disposal
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          [
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH DISP'">
+                                <xsl:choose>
+                                  <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                                    <span class="answerText">X</span>
+                                  </xsl:when>
+                                </xsl:choose>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ]
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH DISP'">
+                                <span class="answerText">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                      <br/>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                      <br/>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:OnsiteReleaseQuantity">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnvironmentalMediumCode = 'OTH DISP'">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:OnsiteWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                &#160;</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                         cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                    	<xsl:choose>
+                    		<xsl:when test="TRI:SubmissionReportingYear &lt; '2014'">
+                    			<td align="left" colspan="8" style="font-size: 8pt">
+                        			<p style="font-size: 8pt">SECTION 6. TRANSFER(S) OF THE
+                                                  TOXIC CHEMICAL IN WASTES TO
+                                                  OFF-SITE LOCATIONS </p>
+                      			</td>
+                    		</xsl:when>
+                    		<xsl:otherwise>
+                    			<td align="left" colspan="10" style="font-size: 8pt">
+                        			<p style="font-size: 8pt">SECTION 6. TRANSFER(S) OF THE
+                                                  TOXIC CHEMICAL IN WASTES TO
+                                                  OFF-SITE LOCATIONS </p>
+                      			</td>
+                    		</xsl:otherwise>
+                    	</xsl:choose>
+                    </tr>
+
+                    <xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear &gt; '2010'">
+                      <xsl:choose>
+	                      <xsl:when test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true' or not(TRI:POTWWasteQuantity)">
+		                    <tr>
+		                      <td align="left" style="font-size: 8pt;">
+		                        <p style="font-size: 8pt">6.1 DISCHARGES TO PUBLICLY
+		                                                  OWNED TREATMENT WORKS (POTWs)</p>
+		                      </td>
+		                      <td align="left" style="font-size: 8pt">
+		                        <p style="font-size: 8pt">
+		                          NA [
+		                            <xsl:if test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true' or not(TRI:POTWWasteQuantity)">
+		                              <span class="answerText">X</span>
+		                            </xsl:if>
+		                          ]
+		                        </p>
+		                      </td>
+		                    </tr>
+		                  </xsl:when>
+		                  <xsl:otherwise>
+		                    <tr>
+		                      <td align="left" style="font-size: 8pt;" colspan="3">
+		                        <p style="font-size: 8pt">6.1 DISCHARGES TO PUBLICLY
+		                                                  OWNED TREATMENT WORKS (POTWs)</p>
+		                      </td>
+		                      	<xsl:choose>
+									<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+											<td align="left" style="font-size: 8pt" colspan="8">  <!-- 2014 -->
+		                        				<p style="font-size: 8pt">
+		                          				NA [
+		                            				<xsl:if test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true' or not(TRI:POTWWasteQuantity)">
+		                            					<span class="answerText">X</span>
+		                            				</xsl:if>
+		                          				]
+		                        				</p>
+		                      				</td>
+								    	</xsl:when>
+        								<xsl:otherwise>
+											<td align="left" style="font-size: 6pt" colspan="6">  <!-- 2013 Issue here -->
+		                        				<p style="font-size: 8pt">
+		                          				NA [
+		                            				<xsl:if test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true' or not(TRI:POTWWasteQuantity)">
+		                            					<span class="answerText">X</span>
+		                            				</xsl:if>
+		                          				]
+		                        				</p>
+		                      				</td>
+        								</xsl:otherwise>
+								</xsl:choose>
+		                    </tr>
+		                  </xsl:otherwise>
+	                  </xsl:choose>
+	                </xsl:when>
+	                <xsl:otherwise>
+						<tr>
+						  <td align="left" colspan="8" style="font-size: 8pt">
+							<p style="font-size: 8pt">6.1 DISCHARGES TO PUBLICLY
+													  OWNED TREATMENT WORKS (POTWs)</p>
+						  </td>
+						</tr>
+						<tr>
+						  <td align="left" colspan="8" style="font-size: 8pt">
+							<p style="font-size: 8pt">6.1.A Total Quantity
+													  Transferred to POTWs and Basis
+													  of Estimate</p>
+						  </td>
+						</tr>
+						<tr>
+						  <td align="left" colspan="4">
+							<p style="font-size: 8pt">
+							  6.1.A.1 Total Transfers (pounds/year*)
+							  <br/>
+							  (Enter range code** or estimate)
+							</p>
+						  </td>
+						  <td align="center" colspan="4">
+							<p style="font-size: 8pt">
+							  6.1.A.2 Basis of Estimate
+							  <br/>
+							  (Enter code)
+							</p>
+						  </td>
+						</tr>
+						<tr>
+						  <td align="center" colspan="4">
+							<p style="font-size: 8pt">
+							  <span class="answerText">
+								<xsl:choose>
+								  <xsl:when test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">NA</xsl:when>
+								  <xsl:otherwise>
+									<xsl:choose>
+									  <xsl:when test="TRI:POTWWasteQuantity/TRI:WasteQuantityMeasure >= '0'">
+										<xsl:value-of select="TRI:POTWWasteQuantity/TRI:WasteQuantityMeasure"/>
+										<br/>
+									  </xsl:when>
+									  <xsl:otherwise>
+										<xsl:value-of select="TRI:POTWWasteQuantity/TRI:WasteQuantityRangeCode"/>
+										<br/>
+									  </xsl:otherwise>
+									</xsl:choose>
+								  </xsl:otherwise>
+								</xsl:choose>
+							  </span>
+							  <br/>
+							</p>
+						  </td>
+						  <td align="center" colspan="4">
+							<p style="font-size: 8pt">
+							  <span class="answerText">
+								<xsl:value-of select="TRI:POTWWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+							  </span>
+							  <br/>
+							</p>
+						  </td>
+						</tr>
+                      </xsl:otherwise>
+                    </xsl:choose>
+
+                    <xsl:for-each select="TRI:TransferLocation">
+                      <xsl:if test="TRI:POTWIndicator = 'true'">
+                        <tr>
+                          <td align="center" colspan="2">
+                            <p style="font-size: 8pt">
+                              <br/>
+                               <xsl:choose>
+							     <xsl:when test="../TRI:SubmissionReportingYear &gt; '2010'">
+								  6.1.<xsl:value-of select="TRI:TransferLocationSequenceNumber"/>
+							     </xsl:when>
+							     <xsl:otherwise>
+							      6.1.B.<xsl:value-of select="TRI:TransferLocationSequenceNumber"/>
+							     </xsl:otherwise>
+							   </xsl:choose>
+                              <br/>
+                              <u>POTW Name</u>
+                              <br/>
+                            </p>
+                          </td>
+								<xsl:choose>
+									<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+                          				<td align="left" colspan="8"> <!-- 2014  -->
+                            				<p style="font-size: 8pt">
+                              				<span class="answerText">
+                                			<xsl:value-of select="sc:FacilitySiteName"/>
+                              				&#160;</span>
+                              				<br/>
+                            				</p>
+                          				</td>
+
+								    </xsl:when>
+        							<xsl:otherwise>
+			                          <td align="left" colspan="6"> <!-- 2013  -->
+                            			<p style="font-size: 8pt">
+                              				<span class="answerText">
+                                		<xsl:value-of select="sc:FacilitySiteName"/>
+                              			&#160;</span>
+                              			<br/>
+                            			</p>
+                          			</td>
+     								</xsl:otherwise>
+							</xsl:choose>
+                        </tr>
+                        <tr>
+                          <td align="center" colspan="2" width="25%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              POTW Address
+                              <br/>
+                            </p>
+                          </td>
+                          <xsl:choose>
+                          	<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+					                    <td align="left" colspan="8"> <!-- 2014  -->
+                            				<p style="font-size: 8pt">
+                              				<span class="answerText">
+                                			<xsl:value-of select="sc:LocationAddress/sc:LocationAddressText"/>
+				                              &#160; </span>
+                              				<br/>
+                            				</p>
+                          				</td>
+                          	</xsl:when>
+                          	<xsl:otherwise>
+                          	            <td align="left" colspan="6"> <!-- 2013  -->
+                            				<p style="font-size: 8pt">
+                              				<span class="answerText">
+                                				<xsl:value-of select="sc:LocationAddress/sc:LocationAddressText"/>
+                              					&#160; </span>
+                              					<br/>
+                            				</p>
+                          				</td>
+                          	</xsl:otherwise>
+                          </xsl:choose>
+                        </tr>
+                        <tr>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              City
+                              <br/>
+                            </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:LocalityName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                          <xsl:choose>
+							<xsl:when test="../TRI:SubmissionReportingYear &lt; '2011'">
+							  <td width="5%">
+								<p style="font-size: 8pt">
+								  <br/>
+								  State
+								  <br/>
+								</p>
+							  </td>
+							  <td>
+								<p style="font-size: 8pt">
+								  <span class="answerText">
+									<xsl:value-of select="sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+								  </span>
+                              <br/>
+                            </p>
+                          </td>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              County
+                              <br/>
+                            </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                              &#160;</span>
+	  <br/>
+								</p>
+							  </td>
+                          </xsl:when>
+						  <xsl:otherwise>
+						  <td width="5%">
+								<p style="font-size: 8pt">
+								  <br/>
+								  County
+								  <br/>
+								</p>
+							  </td>
+							  <td>
+								<p style="font-size: 8pt">
+								  <span class="answerText">
+									<xsl:value-of select="sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+								  </span>
+                              <br/>
+                            </p>
+                          </td>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              State
+                              <br/>
+                            </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+						  </xsl:otherwise>
+						</xsl:choose>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              ZIP
+                              <br/>
+                            </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:AddressPostalCode"/>
+                              </span>
+                              <br/>
+                            </p>
+                          </td>
+                               <!-- Country column for RY-2014 and later -->
+                          <xsl:if test="../TRI:SubmissionReportingYear &gt; '2013' ">
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              Country
+                              <br/>
+                              (Non-US)
+                            </p>
+                          </td>
+
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:CountryIdentity/sc:CountryName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                          </xsl:if>
+
+                        </tr>
+
+                         <xsl:if test="../TRI:SubmissionReportingYear &gt; '2010'">
+	                        <tr>
+		                            <xsl:choose>
+										<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+											<td align="center" colspan="5">  <!-- 2014-->
+											<p style="font-size: 8pt">
+		                          				A. Quantity Transferred to this POTW
+		                          				<br/>
+		                          				(pounds/year*) (Enter range code**or estimate)
+		                        			</p>
+		                      				</td>
+								    	</xsl:when>
+        								<xsl:otherwise>
+											<td align="center" colspan="4">  <!-- 2013 -->
+											<p style="font-size: 8pt">
+		                          				A. Quantity Transferred to this POTW
+		                          				<br/>
+		                          				(pounds/year*) (Enter range code**or estimate)
+		                        			</p>
+		                      				</td>
+
+        								</xsl:otherwise>
+       								</xsl:choose>
+		                           <xsl:choose>
+										<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+											<td align="center" colspan="5"> <!-- 2014-->
+											<p style="font-size: 8pt">
+		                          			B. Basis of Estimate
+		                          				<br/>
+		                          			(Enter code)
+		                        			</p>
+		                      				</td>
+								    	</xsl:when>
+        								<xsl:otherwise>
+											<td align="center" colspan="4"> <!-- 2013 -->
+											<p style="font-size: 8pt">
+		                          			B. Basis of Estimate
+		                          				<br/>
+		                          			(Enter code)
+		                        			</p>
+		                      				</td>
+
+        								</xsl:otherwise>
+       								</xsl:choose>
+		                    </tr>
+
+		                    <xsl:variable name="locationSequence" select="TRI:TransferLocationSequenceNumber"/>
+		                    <xsl:for-each select="../TRI:POTWWasteQuantity">
+			                    <xsl:if test="TRI:POTWSequenceNumber = $locationSequence">
+				                 <tr>
+       								<xsl:choose>
+									<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+									<td align="center" colspan="5">  <!-- 2014 -->
+			                        <p style="font-size: 8pt">
+			                          <span class="answerText">
+			                            <xsl:choose>
+			                              <xsl:when test="TRI:WasteQuantityNAIndicator = 'true'">NA</xsl:when>
+			                              <xsl:otherwise>
+			                                <xsl:choose>
+			                                  <xsl:when test="TRI:WasteQuantityMeasure >= '0'">
+			                                    <xsl:value-of select="TRI:WasteQuantityMeasure"/>
+			                                  </xsl:when>
+			                                  <xsl:otherwise>
+			                                    <xsl:value-of select="TRI:WasteQuantityRangeCode"/>
+			                                    <br/>
+			                                  </xsl:otherwise>
+			                                </xsl:choose>
+			                              </xsl:otherwise>
+			                            </xsl:choose>
+			                          &#160;</span>
+			                          <br/>
+			                        </p>
+			                      </td>
+								  </xsl:when>
+        						  <xsl:otherwise>
+									<td align="center" colspan="4">  <!-- 2013 -->
+										<p style="font-size: 8pt">
+			                          <span class="answerText">
+			                            <xsl:choose>
+			                              <xsl:when test="TRI:WasteQuantityNAIndicator = 'true'">NA</xsl:when>
+			                              <xsl:otherwise>
+			                                <xsl:choose>
+			                                  <xsl:when test="TRI:WasteQuantityMeasure >= '0'">
+			                                    <xsl:value-of select="TRI:WasteQuantityMeasure"/>
+			                                  </xsl:when>
+			                                  <xsl:otherwise>
+			                                    <xsl:value-of select="TRI:WasteQuantityRangeCode"/>
+			                                    <br/>
+			                                  </xsl:otherwise>
+			                                </xsl:choose>
+			                              </xsl:otherwise>
+			                            </xsl:choose>
+			                          &#160;</span>
+			                          <br/>
+			                        </p>
+			                      </td>
+    								</xsl:otherwise>
+								</xsl:choose>
+								<xsl:choose>
+										<xsl:when test="../TRI:SubmissionReportingYear &gt; '2013' ">
+											<td align="center" colspan="5"> <!-- 2014 -->
+					                        <p style="font-size: 8pt">
+					                          <span class="answerText">
+			                            	<xsl:value-of select="TRI:QuantityBasisEstimationCode"/>
+			                          			&#160;</span>
+			                          			<br/>
+			                        		</p>
+			                      			</td>
+								    	</xsl:when>
+        								<xsl:otherwise>
+											<td align="center" colspan="4"> <!-- 2013 -->
+					                        <p style="font-size: 8pt">
+					                          <span class="answerText">
+			                            	<xsl:value-of select="TRI:QuantityBasisEstimationCode"/>
+			                          			&#160;</span>
+			                          			<br/>
+			                        		</p>
+			                      			</td>
+
+        								</xsl:otherwise>
+									</xsl:choose>
+			                    </tr>
+			                   </xsl:if>
+		                  	</xsl:for-each>
+	                    </xsl:if>
+
+
+                      </xsl:if>
+                    </xsl:for-each>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </center>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0">
+            <tr>
+              <td colspan="2" align="right">
+                <p style="font-size: 8pt">*For Dioxin and Dioxin-like Compounds, report in grams/year</p>
+              </td>
+            </tr>
+            <tr>
+              <td width="50%">
+                <p style="font-size: 8pt">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		EPA Form 9350-1 (Rev. <xsl:value-of select="$RevisionDateFormR"/>) - Previous editions are obsolete.
+                  	</xsl:if>
+                </p>
+              </td>
+              <td width="50%" align="right">
+                <p style="font-size: 8pt">**Range Codes: A=1-10 pounds; B=11-499 pounds; C=500-999 pounds.</p>
+              </td>
+            </tr>
+          </table>
+          <p style="page-break-before: always">&#160;</p>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0" rules="all">
+            <tr>
+            <!--<td width="90%">
+                <a name="PG-4_{$formID}"></a>
+                <p style="font-size: 8pt">
+                  <a href="#PG-1_{$formID}">1</a>
+                  <a href="#PG-2_{$formID}">2</a>
+                  <a href="#PG-3_{$formID}">3</a>
+                  <a href="#PG-4_{$formID}">4</a>
+                  <a href="#PG-5_{$formID}">5</a>
+                  <a href="#PG-6_{$formID}">Additional Info</a>
+                  <xsl:if test="$ScheduleOneNA = 'false'">
+                      <a href="#S1_PG-1_{$formID}">Schedule 1</a>
+                  </xsl:if>
+                </p>
+              </td>-->
+              <td width="10%">
+                <p style="font-size: 8pt">
+                  <b>Page 4 of 5 </b>
+                </p>
+              </td>
+            </tr>
+          </table>
+          <center>
+          <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+          </tr>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%"
+                   style="font-size: 8pt">
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td width="65%" align="center" style="font-size: 10pt">
+                        <p style="font-size: 10pt">
+                          <b>EPA FORM R</b>
+                          <br/>
+                          <b>PART II. CHEMICAL - SPECIFIC INFORMATION (CONTINUED)</b>
+                        </p>
+                      </td>
+                      <td>
+                          TRI Facility ID Number
+                          <hr />
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                          &#160;</span>
+                        <hr />
+                        Toxic Chemical, Category, or Generic Name
+                        <hr />
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+               <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" border="0" style="font-size: 8pt" cellspacing="0"
+                         cellpadding="1">
+                    <xsl:if test="TRI:SubmissionReportingYear &gt; '2010'">
+	                    <tr>
+	                      <td align="left" style="font-size: 8pt; width: 405px; border-right: ridge 2px;">
+	                        <p style="font-size: 8pt">SECTION 6.2 TRANSFERS TO OTHER OFF-SITE LOCATIONS </p>
+	                      </td>
+	                      <td align="left" style="font-size: 8pt;">
+	                        <p style="font-size: 8pt">
+		                      NA [
+
+		                      	  <xsl:if test="not(TRI:TransferLocation)">
+
+			                              <span class="answerText">X</span>
+
+		                      	  </xsl:if>
+
+	                      	 ]
+		                    </p>
+	                      </td>
+	                    </tr>
+                    </xsl:if>
+                    <xsl:if test="TRI:SubmissionReportingYear &lt; '2011'">
+                      <tr>
+                    	<td align="left" style="font-size: 8pt;">
+	                        <p style="font-size: 8pt">SECTION 6.2 TRANSFERS TO OTHER OFF-SITE LOCATIONS </p>
+	                    </td>
+	                  </tr>
+                    </xsl:if>
+                  </table>
+                </td>
+              </tr>
+              <xsl:for-each select="TRI:TransferLocation">
+                <xsl:if test="TRI:POTWIndicator = 'false'">
+                  <tr>
+                    <td colspan="2">
+                      <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                        <tr>
+                          <xsl:choose>
+                            <xsl:when test="../TRI:TransferLocation[1]/TRI:POTWIndicator = 'true'">
+                              <td width="55%" style="font-size: 10pt">
+                                <p style="font-size: 8pt">
+                                  6.2.<xsl:value-of select="count(preceding-sibling::TRI:TransferLocation) - 1"/>
+                                  Off-Site EPA Identification Number (RCRA ID
+                                  No.)
+                                </p>
+                              </td>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <td width="55%" style="font-size: 10pt">
+                                <p style="font-size: 8pt">
+                                  6.2.<xsl:value-of select="count(preceding-sibling::TRI:TransferLocation) + 1"/>
+                                  Off-Site EPA Identification Number (RCRA ID No.)
+                                </p>
+                              </td>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="TRI:RCRAIdentificationNumber"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                        <tr>
+                          <td width="25%" style="text-indent: 2em">
+                            <p style="font-size: 8pt">Off-Site Location Name: </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:FacilitySiteName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                        <tr>
+                          <td width="25%" style="text-indent: 2em">
+                            <p style="font-size: 8pt">Off-Site Address: </p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:LocationAddressText"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                      </table>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td colspan="2">
+                      <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                             cellspacing="0" cellpadding="1" frame="void">
+                        <tr>
+                          <td width="5%">
+                            <p style="font-size: 8pt">City</p>
+                          </td>
+                          <td width="20%">
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:LocalityName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+						<xsl:choose>
+						<xsl:when test="../TRI:SubmissionReportingYear &lt; '2011'">
+						  <td width="5%">
+							<p style="font-size: 8pt">State</p>
+						  </td>
+						  <td width="5%">
+							<p style="font-size: 8pt">
+							  <span class="answerText">
+								<xsl:value-of select="sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+							  </span>
+							  <br/>
+							</p>
+						  </td>
+						  <td width="10%">
+							<p style="font-size: 8pt">County</p>
+						  </td>
+						  <td width="20%">
+							<p style="font-size: 8pt">
+							  <span class="answerText">
+								<xsl:value-of select="sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+							  </span>
+							  <br/>
+							</p>
+						  </td>
+						</xsl:when>
+						<xsl:otherwise>
+                          <td width="10%">
+                            <p style="font-size: 8pt">County</p>
+                          </td>
+                          <td width="20%">
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                              </span>
+                              <br/>
+                            </p>
+                          </td>
+                          <td width="5%">
+                            <p style="font-size: 8pt">State</p>
+                          </td>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+						</xsl:otherwise>
+						</xsl:choose>
+                          <td width="5%">
+                            <p style="font-size: 8pt">ZIP</p>
+                          </td>
+                          <td width="15%">
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:AddressPostalCode"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                          <td width="10%">
+                            <p style="font-size: 8pt">
+                              Country
+                              <br/>
+                              (Non-US)
+                            </p>
+                          </td>
+                          <td width="5%">
+                            <p style="font-size: 8pt">
+                              <span class="answerText">
+                                <xsl:value-of select="sc:LocationAddress/sc:CountryIdentity/sc:CountryName"/>
+                              &#160;</span>
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                        <tr>
+                          <td colspan="6" style="text-indent: 4em">
+                            <p style="font-size: 8pt">Is location under control
+                                                      of reporting facility or
+                                                      parent company?</p>
+                          </td>
+                          <td colspan="4" style="font-size: 8pt">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              [
+                              <xsl:choose>
+                                <xsl:when test="sc:FacilitySiteName = 'NA'"></xsl:when>
+                                <xsl:otherwise>
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:ControlledLocationIndicator = 'true'">
+                                      <span class="answerText">X</span>
+                                    </xsl:when>
+                                  </xsl:choose>
+                                </xsl:otherwise>
+                              </xsl:choose>
+                              ] Yes [
+                              <xsl:choose>
+                                <xsl:when test="sc:FacilitySiteName = 'NA'"></xsl:when>
+                                <xsl:otherwise>
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:ControlledLocationIndicator = 'false'">
+                                      <span class="answerText">X</span>
+                                    </xsl:when>
+                                  </xsl:choose>
+                                </xsl:otherwise>
+                              </xsl:choose>
+                              ] No
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                      </table>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td colspan="2">
+                      <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                             cellspacing="0" cellpadding="1" frame="void">
+                        <tr>
+                          <td align="center">
+                            <p style="font-size: 8pt">
+                              A. Total Transfer (pounds/year*)
+                              <br/>
+                              (Enter range code** or estimate)
+                            </p>
+                          </td>
+                          <td align="center">
+                            <p style="font-size: 8pt">
+                              B. Basis of Estimate
+                              <br/>
+                              (Enter code)
+                            </p>
+                          </td>
+                          <td align="center">
+                            <p style="font-size: 8pt">
+                              C. Type of Waste Treatment/Disposal/
+                              <br/>
+                              Recycling/Energy Recovery (Enter code)
+                            </p>
+                          </td>
+                        </tr>
+                        <xsl:for-each select="TRI:TransferQuantity">
+                          <tr style="height: 25px">
+                            <td style="text-indent: 2em">
+                              <p style="font-size: 8pt">
+                                <xsl:value-of select="count(preceding-sibling::TRI:TransferQuantity) + 1"/>
+                                .
+                                <span class="answerText">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TransferWasteQuantity/TRI:WasteQuantityMeasure[.!='']">
+                                      <xsl:value-of select="TRI:TransferWasteQuantity/TRI:WasteQuantityMeasure"/>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <xsl:value-of select="TRI:TransferWasteQuantity/TRI:WasteQuantityRangeCode"/>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td style="text-indent: 1em">
+                              <p style="font-size: 8pt">
+                                <xsl:value-of select="count(preceding-sibling::TRI:TransferQuantity) + 1"/>
+                                .
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:TransferWasteQuantity/TRI:QuantityBasisEstimationCode"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                            <td style="text-indent: 2em">
+                              <p style="font-size: 8pt">
+                                <xsl:value-of select="count(preceding-sibling::TRI:TransferQuantity) + 1"/>
+                                .
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:WasteManagementTypeCode"/>
+                                &#160;</span>
+                              </p>
+                            </td>
+                          </tr>
+                        </xsl:for-each>
+                      </table>
+                    </td>
+                  </tr>
+                </xsl:if>
+              </xsl:for-each>
+              <tr>
+                <td colspan="2">
+                  <xsl:choose>
+                    <xsl:when test="TRI:SubmissionReportingYear &gt;= '1991' and TRI:SubmissionReportingYear &lt; '2005'">
+                      <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+	                         cellspacing="0" cellpadding="1" frame="void">
+	                    <tr>
+	                      <td colspan="7" style="font-size: 8pt">
+	                        <p style="font-size: 8pt">SECTION 7A. ONSITE WASTE TREATMENT METHODS AND EFFICIENCY</p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td colspan="7">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:choose>
+	                            <xsl:when test="TRI:WasteTreatmentNAIndicator = 'true'">
+	                              <span class="answerText">X</span>
+	                            </xsl:when>
+	                            <xsl:otherwise></xsl:otherwise>
+	                          </xsl:choose>
+	                          ] Not Applicable (NA) - Check here if no on-site waste
+	                          treatment is applied to any waste stream containing
+	                          the toxic chemical or chemical category.
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="15%" align="center">
+	                        <p style="font-size: 8pt">
+	                          a. General
+	                          <br/>
+	                          Waste Stream
+	                          <br/>
+	                          (enter code)
+	                        </p>
+	                      </td>
+	                      <td width="45%" align="center">
+	                        <p style="font-size: 8pt">
+	                          b. Waste Treatment Method(s) Sequence
+	                          <br/>
+	                          [enter 3-character code(s)]
+	                        </p>
+	                      </td>
+	                      <td align="center">
+	                      	<p style="font-size: 8pt">
+	                          c. Influent Concentration
+	                        </p>
+	                      </td>
+	                      <td align="center">
+	                        <p style="font-size: 8pt">
+	                          d. % Waste Treatment
+	                          <br/>
+	                          Efficiency
+	                        </p>
+	                      </td>
+	                      <td align="center">
+	                        <p style="font-size: 8pt">
+	                          e. Based on
+	                          <br/>
+	                          Operating Data?
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <xsl:choose>
+	                      <xsl:when test="TRI:WasteTreatmentNAIndicator = 'true'"></xsl:when>
+	                      <xsl:otherwise>
+	                        <xsl:for-each select="TRI:WasteTreatmentDetails">
+	                          <tr>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  a
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                            <td width="45%" align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  b
+	                                </b>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  c
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  d
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  e
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                          </tr>
+	                          <tr>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:WasteStreamTypeCode"/>
+	                                &#160;</span>
+	                              </p>
+	                            </td>
+	                            <td width="45%" align="center">
+	                              <p style="font-size: 8pt">
+	                                <xsl:for-each select="TRI:WasteTreatmentMethod">
+	                                  <xsl:value-of select="TRI:WasteTreatmentSequenceNumber + 1"/>
+	                                  :
+	                                  <span class="answerText">
+	                                    <xsl:value-of select="TRI:WasteTreatmentMethodCode"/>
+	                                    <xsl:text> </xsl:text>
+	                                  &#160;</span>
+	                                </xsl:for-each>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <span class="answerText">
+	                                <xsl:value-of select="TRI:InfluentConcentrationRangeCode"/>
+	                              &#160;</span>
+	                            </td>
+	                            <td align="center">
+	                              <span class="answerText">
+	                                <xsl:value-of select="TRI:TreatmentEfficiencyEstimatePercent"/>
+	                              &#160;</span>
+	                            </td>
+	                            <td align="center">
+	                              <span class="answerText">
+	                                <xsl:choose>
+		                              <xsl:when test="TRI:OperatingDataIndicator = 'true'">
+		                                <span class="answerText">X</span>
+		                              </xsl:when>
+		                              <xsl:otherwise></xsl:otherwise>
+		                            </xsl:choose>
+	                              &#160;</span>
+	                            </td>
+	                          </tr>
+	                        </xsl:for-each>
+	                      </xsl:otherwise>
+	                    </xsl:choose>
+	                  </table>
+                    </xsl:when>
+                    <xsl:otherwise>
+	                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+	                         cellspacing="0" cellpadding="1" frame="void">
+	                    <tr>
+	                      <td colspan="5" style="font-size: 8pt">
+	                        <p style="font-size: 8pt">SECTION 7A. ONSITE WASTE TREATMENT METHODS AND EFFICIENCY</p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td colspan="5">
+	                        <p style="font-size: 8pt">
+	                          [
+	                          <xsl:choose>
+	                            <xsl:when test="TRI:WasteTreatmentNAIndicator = 'true'">
+	                              <span class="answerText">X</span>
+	                            </xsl:when>
+	                            <xsl:otherwise></xsl:otherwise>
+	                          </xsl:choose>
+	                          ] Not Applicable (NA) - Check here if no on-site waste
+	                          treatment is applied to any waste stream containing
+	                          the toxic chemical or chemical category.
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="15%" align="center">
+	                        <p style="font-size: 8pt">
+	                          a. General
+	                          <br/>
+	                          Waste Stream
+	                          <br/>
+	                          (enter code)
+	                        </p>
+	                      </td>
+	                      <td width="45%" align="center">
+	                        <p style="font-size: 8pt">
+	                          b. Waste Treatment Method(s) Sequence
+	                          <br/>
+	                          [enter 3-character code(s)]
+	                        </p>
+	                      </td>
+	                      <td align="center">
+	                        <p style="font-size: 8pt">
+	                          d. Waste Treatment
+	                          <br/>
+	                          Efficiency
+	                          <br/>
+	                          Estimate
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <xsl:choose>
+	                      <xsl:when test="TRI:WasteTreatmentNAIndicator = 'true'"></xsl:when>
+	                      <xsl:otherwise>
+	                        <xsl:for-each select="TRI:WasteTreatmentDetails">
+	                          <tr>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  a
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                            <td width="45%" align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  b
+	                                </b>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <b style="color: black;font-size: 9pt">
+	                                  7A.
+	                                  <xsl:value-of select="count(preceding-sibling::TRI:WasteTreatmentDetails) + 1"/>
+	                                  d
+	                                </b>
+	                                <br/>
+	                              </p>
+	                            </td>
+	                          </tr>
+	                          <tr>
+	                            <td align="center">
+	                              <p style="font-size: 8pt">
+	                                <span class="answerText">
+	                                  <xsl:value-of select="TRI:WasteStreamTypeCode"/>
+	                                &#160;</span>
+	                              </p>
+	                            </td>
+	                            <td width="45%" align="center">
+	                              <p style="font-size: 8pt">
+	                                <xsl:for-each select="TRI:WasteTreatmentMethod">
+	                                  <xsl:value-of select="TRI:WasteTreatmentSequenceNumber + 1"/>
+	                                  :
+	                                  <span class="answerText">
+	                                    <xsl:value-of select="TRI:WasteTreatmentMethodCode"/>
+	                                    <xsl:text> </xsl:text>
+	                                  &#160;</span>
+	                                </xsl:for-each>
+	                              </p>
+	                            </td>
+	                            <td align="center">
+	                              <span class="answerText">
+	                                <xsl:value-of select="TRI:TreatmentEfficiencyRangeCode"/>
+	                              &#160;</span>
+	                            </td>
+	                          </tr>
+	                        </xsl:for-each>
+	                      </xsl:otherwise>
+	                    </xsl:choose>
+	                  </table>
+	                </xsl:otherwise>
+                  </xsl:choose>
+                </td>
+              </tr>
+            </table>
+          </center>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0">
+            <tr>
+              <td colspan="2" align="right">
+                <p style="font-size: 8pt">*For Dioxin and Dioxin-like Compounds,
+                                          report in grams/year</p>
+              </td>
+            </tr>
+            <tr>
+              <td width="50%">
+                <p style="font-size: 8pt">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		EPA Form 9350-1 (Rev. <xsl:value-of select="$RevisionDateFormR"/>) - Previous editions are obsolete.
+                  	</xsl:if>
+                </p>
+              </td>
+              <td width="50%" align="right">
+                <p style="font-size: 8pt">**Range Codes: A=1-10 pounds; B=11-499
+                                          pounds; C=500-999 pounds.</p>
+              </td>
+            </tr>
+          </table>
+          <p style="page-break-before: always">&#160;</p>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0">
+            <tr>
+             <!--<td width="90%">
+                <a name="PG-5_{$formID}"></a>
+                <p style="font-size: 8pt">
+                  <a href="#PG-1_{$formID}">1</a>
+                  <a href="#PG-2_{$formID}">2</a>
+                  <a href="#PG-3_{$formID}">3</a>
+                  <a href="#PG-4_{$formID}">4</a>
+                  <a href="#PG-5_{$formID}">5</a>
+                  <a href="#PG-6_{$formID}">Additional Info</a>
+                  <xsl:if test="$ScheduleOneNA = 'false'">
+                      <a href="#S1_PG-1_{$formID}">Schedule 1</a>
+                  </xsl:if>
+                </p>
+              </td>-->
+              <td width="10%">
+                <p style="font-size: 8pt">
+                  <b>Page 5 of 5 </b>
+                </p>
+              </td>
+            </tr>
+          </table>
+          <center>
+          <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+          </tr>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%"
+                   style="font-size: 8pt">
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td width="65%" align="center" style="font-size: 10pt">
+                        <p style="font-size: 10pt">
+                          <b>EPA FORM R</b>
+                          <br/>
+                          <b>PART II. CHEMICAL - SPECIFIC INFORMATION (CONTINUED)</b>
+                        </p>
+                      </td>
+                      <td>
+                          TRI Facility ID Number
+                          <hr />
+                          <span class="answerText">
+                            <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                          &#160;</span>
+                        <hr />
+                        Toxic Chemical, Category, or Generic Name
+                        <hr />
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                            </xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0" cellpadding="1" border="0" frame="void">
+                    <tr>
+                      <td align="left" colspan="8">SECTION 7B. ON-SITE ENERGY RECOVERY PROCESSES</td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="8">
+                          [
+                          <xsl:for-each select="TRI:OnsiteRecoveryProcess">
+                            <xsl:choose>
+                              <xsl:when test="TRI:EnergyRecoveryNAIndicator = 'true'">
+                                <span class="answerText">X</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ] NA - Check here if no on-site
+                          energy recovery is applied to any waste
+                          <br />
+                          stream containing the toxic chemical or chemical
+                          category.
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="8">
+                        <p style="font-size: 8pt">
+                          Energy Recovery Methods [Enter 3-character code(s)]
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="8">
+                      <xsl:for-each select="TRI:OnsiteRecoveryProcess">
+                        <xsl:choose>
+                          <xsl:when test="TRI:EnergyRecoveryNAIndicator = 'true'"></xsl:when>
+                          <xsl:otherwise>
+                            <xsl:for-each select="TRI:EnergyRecoveryMethodCode">
+                              <span style="border: solid; border-width: thin; padding-left:20px; padding-right:20px;">
+                                  <xsl:value-of select="count(preceding-sibling::*) + 1"/>.
+                                  <span class="answerText">
+                                    <xsl:value-of select="."/>
+                                  &#160;</span>
+                              &#160;</span>&#160;&#160;
+                            </xsl:for-each>
+                          </xsl:otherwise>
+                        </xsl:choose>
+                      </xsl:for-each>
+                      &#160;
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0" cellpadding="1" border="0" frame="void">
+                    <tr>
+                      <td align="left" colspan="6">
+                        SECTION 7C. ON-SITE RECYCLING PROCESSES
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="6">
+                          [
+                          <xsl:for-each select="TRI:OnsiteRecyclingProcess">
+                            <xsl:choose>
+                              <xsl:when test="TRI:OnsiteRecyclingNAIndicator = 'true'">
+                                <span class="answerText">X</span>
+                              </xsl:when>
+                            </xsl:choose>
+                          </xsl:for-each>
+                          ] NA - Check here if no on-site
+                          recycling is applied to any waste
+                          <br/>
+                          stream containing the toxic chemical or chemical
+                          category.
+                      </td>
+                    </tr>
+                    <tr>
+                      <td align="left" colspan="6">
+                        <p style="font-size: 8pt">
+                          Recycling Methods [Enter 3-character code(s)]
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td>
+                      <xsl:for-each select="TRI:OnsiteRecyclingProcess">
+                        <xsl:choose>
+                          <xsl:when test="TRI:OnsiteRecyclingNAIndicator = 'true'"></xsl:when>
+                          <xsl:otherwise>
+                            <xsl:for-each select="TRI:OnsiteRecyclingMethodCode">
+                              <span style="border: solid; border-width: thin; padding-left: 20px; padding-right:20px; width: 85px;">
+                                  <xsl:value-of select="count(preceding-sibling::*) + 1"/>.
+                                  <span class="answerText">
+                                    <xsl:value-of select="."/>
+                                  &#160;</span>
+                              &#160;</span>&#160;&#160;
+                            </xsl:for-each>
+                          </xsl:otherwise>
+                        </xsl:choose>
+                      </xsl:for-each>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+              <tr>
+                <td colspan="2">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                    <tr>
+                      <td colspan="6" align="left" style="font-size: 8pt">
+                        <p style="font-size: 8pt">SECTION 8. SOURCE REDUCTION AND WASTE MANAGEMENT</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td colspan="2"></td>
+                      <td align="center">
+                        <p style="font-size: 8pt">
+                          Column A
+                          <br />
+                          Prior Year
+                          <br />
+                          (pounds/year*)
+                        </p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 8pt">
+                          Column B
+                          <br/>
+                          Current Reporting Year
+                          <br/>
+                          (pounds/year*)
+                        </p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 8pt">
+                          Column C
+                          <br/>
+                          Following Year
+                          <br/>
+                          (pounds/year*)
+                        </p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 8pt">
+                          Column D
+                          <br/>
+                          Second Following Year
+                          <br/>
+                          (pounds/year*)
+                        </p>
+                      </td>
+                    </tr>
+                    <xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear &gt;= '1991' and TRI:SubmissionReportingYear &lt;= '2002'">
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">8.1</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Quantity Released
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+	                    <tr>
+	                    	<xsl:choose>
+	                    		<xsl:when test="TRI:SubmissionReportingYear &lt; '2014'">
+	                    			<td width="5%" align="center">
+	                        			<p style="font-size: 8pt">8.1</p>
+	                      			</td>
+	                      			<td align="center">
+	                        			<p style="font-size: 8pt">&#160;</p>
+	                      			</td>
+	                    		</xsl:when>
+	                    		<xsl:otherwise>
+	                    			<td width="5%" align="center" colspan="2">
+	                        			<p style="font-size: 8pt">8.1 - 8.7 Production-Related Waste Managed</p>
+	                      			</td>
+	                    		</xsl:otherwise>
+	                    	</xsl:choose>
+
+	                      <td>
+	                        <p style="background-color: gray">
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="background-color: gray">
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="background-color: gray">
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="background-color: gray">
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">8.1a</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Total on-site disposal to Class I
+	                          <br/>
+	                          Underground Injection Wells, RCRA
+	                          <br/>
+	                          Subtitle C landfills, and other landfills
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">8.1b</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Total other on-site disposal or other
+	                          <br/>
+	                          releases
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OnsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">8.1c</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Total off-site disposal to Class I
+	                          <br/>
+	                          Underground Injection Wells, RCRA
+	                          <br/>
+	                          Subtitle C landfills, and other landfills
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteUICDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                    <tr>
+	                      <td width="5%" align="center">
+	                        <p style="font-size: 8pt">8.1d</p>
+	                      </td>
+	                      <td align="left">
+	                        <p style="font-size: 8pt">
+	                          Total other off-site disposal or other
+	                          <br/>
+	                          releases
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                      <td>
+	                        <p style="font-size: 8pt">
+	                          <xsl:for-each select="TRI:SourceReductionQuantity">
+	                            <xsl:for-each select="TRI:OffsiteOtherDisposalQuantity">
+	                              <xsl:choose>
+	                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+	                                  <xsl:choose>
+	                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+	                                      <span class="answerText">NA&#160;</span>
+	                                    </xsl:when>
+	                                    <xsl:otherwise>
+	                                      <span class="answerText">
+	                                        <xsl:value-of select="TRI:TotalQuantity"/>
+	                                      &#160;</span>
+	                                    </xsl:otherwise>
+	                                  </xsl:choose>
+	                                </xsl:when>
+	                              </xsl:choose>
+	                            </xsl:for-each>
+	                          </xsl:for-each>
+	                          <br/>
+	                        </p>
+	                      </td>
+	                    </tr>
+	                  </xsl:otherwise>
+                    </xsl:choose>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.2</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity used for energy recovery
+                          <br/>
+                          on-site
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.3</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity used for energy recovery
+                          <br/>
+                          off-site
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteEnergyRecoveryQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.4</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity recycled on-site
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.5</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity recycled off-site
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteRecycledQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.6</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity treated on-site
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OnsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.7</p>
+                      </td>
+                      <td align="left">
+                        <p style="font-size: 8pt">
+                          Quantity treated off-site
+                          <br/>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '-1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '0'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '1'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                          <xsl:for-each select="TRI:SourceReductionQuantity">
+                            <xsl:for-each select="TRI:OffsiteTreatedQuantity">
+                              <xsl:choose>
+                                <xsl:when test="TRI:YearOffsetMeasure = '2'">
+                                  <xsl:choose>
+                                    <xsl:when test="TRI:TotalQuantityNAIndicator = 'true'">
+                                      <span class="answerText">NA&#160;</span>
+                                    </xsl:when>
+                                    <xsl:otherwise>
+                                      <span class="answerText">
+                                        <xsl:value-of select="TRI:TotalQuantity"/>
+                                      &#160;</span>
+                                    </xsl:otherwise>
+                                  </xsl:choose>
+                                </xsl:when>
+                              </xsl:choose>
+                            </xsl:for-each>
+                          </xsl:for-each>
+                          <br/>
+                        </p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.8</p>
+                      </td>
+                      <td colspan="2" align="left">
+                        <p style="font-size: 8pt">
+                        	<xsl:choose>
+                        		<xsl:when test="TRI:SubmissionReportingYear &lt; '2014'">
+                        			Quantity released to the environment as a result of
+                          			remedial actions,
+                          			<br/>
+                          			catastrophic events, or one-time events not associated
+                          			with production processes (pounds/year)
+                        		</xsl:when>
+                        		<xsl:otherwise>
+                        			Non-production-related waste managed**
+                        		</xsl:otherwise>
+                        	</xsl:choose>
+                        </p>
+                      </td>
+                      <td colspan="3">
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:SourceReductionQuantity/TRI:OneTimeReleaseNAIndicator = 'true'">NA</xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OneTimeReleaseQuantity"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                        <br/>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.9</p>
+                      </td>
+                      <xsl:choose>
+	                      <xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+	                      	<td colspan="2" align="left">
+		                        <p style="font-size: 8pt">
+		                          <xsl:choose>
+		                            <xsl:when test="TRI:SourceReductionQuantity/TRI:ProductionRatioType = 'PRODUCTION'">[<span class="answerText">X</span>]</xsl:when>
+		                            <xsl:otherwise>[&#160;]</xsl:otherwise>
+		                          </xsl:choose>
+		                          Production ratio or
+		                          <xsl:choose>
+		                            <xsl:when test="TRI:SourceReductionQuantity/TRI:ProductionRatioType = 'ACTIVITY'">[<span class="answerText">X</span>]</xsl:when>
+		                            <xsl:otherwise>[&#160;]</xsl:otherwise>
+		                          </xsl:choose>
+		                          Activity ratio (select one and enter value to right)
+		                        </p>
+		                      </td>
+	                      </xsl:when>
+	                      <xsl:otherwise>
+		                      <td colspan="2" align="left">
+		                        <p style="font-size: 8pt">Production ratio or activity index</p>
+		                      </td>
+	                      </xsl:otherwise>
+                      </xsl:choose>
+                      <td colspan="3">
+                        <span class="answerText">
+                          <xsl:choose>
+                            <xsl:when test="TRI:SourceReductionQuantity/TRI:ProductionRatioNAIndicator = 'true'">NA</xsl:when>
+                            <xsl:otherwise>
+                              <xsl:value-of select="TRI:SourceReductionQuantity/TRI:ProductionRatioMeasure"/>
+                            </xsl:otherwise>
+                          </xsl:choose>
+                        &#160;</span>
+                        <br/>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td width="5%" align="center">
+                        <p style="font-size: 8pt">8.10</p>
+                      </td>
+                      <xsl:choose>
+						<xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+						   <td colspan="5">
+						   <p style="font-size: 8pt">
+						     Did your facility engage in any source reduction activities for this chemical during the reporting
+year? If not, enter "NA" in Section 8.10.1 and answer Section 8.11.
+						   </p>
+						  </td>
+						</xsl:when>
+						<xsl:otherwise>
+						   <td colspan="2">
+						   <p style="font-size: 8pt">
+							  Did your facility engage in any newly implemented source reduction activities for this
+							  chemical during the reporting year?
+							  <br/>
+							  If so, complete the following section; if not, check NA.
+							</p>
+						  </td>
+						  <td colspan="3">
+								NA [
+	                          <xsl:choose>
+	                            <xsl:when test="TRI:SourceReductionNAIndicator = 'true'">
+	                              <span class="answerText">X</span>
+	                            </xsl:when>
+	                            <xsl:otherwise>&#160;</xsl:otherwise>
+	                          </xsl:choose>
+	                          ]
+
+							<br/>
+							</td>
+						</xsl:otherwise>
+					</xsl:choose>
+
+                    </tr>
+                  </table>
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1"
+                         cellspacing="0" cellpadding="1" frame="above">
+                    <tr>
+                      <td width="5%"></td>
+                      <td align="center">
+                        <p style="font-size: 8pt">
+                          Source Reduction Activities
+                          <br/>
+                          (Enter code(s))
+                        </p>
+                      </td>
+                      <td colspan="3" align="center">
+                        <p style="font-size: 8pt">Methods to Identify Activity
+                                                  (Enter code(s))</p>
+                      </td>
+                      <xsl:if test="TRI:SubmissionReportingYear &gt; '2013'">
+                      	<td align="center">
+                        	<p style="font-size: 8pt">Estimated annual
+                        								reduction
+                        								(Enter code(s))
+                        								(optional)</p>
+                      	</td>
+                      </xsl:if>
+                    </tr>
+                    <xsl:choose>
+                      <xsl:when test="TRI:SourceReductionNAIndicator = 'true'">
+                        <tr>
+                          <td width="5%" align="center">
+                            <p style="font-size: 8pt">8.10.1</p>
+                          </td>
+                          <td>
+                            <p style="font-size: 8pt">
+                              <b style="color: blue;font-size: 9pt">NA</b>
+                              <br/>
+                            </p>
+                          </td>
+                          <td style="text-indent: 1em">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              <br/>
+                            </p>
+                          </td>
+                          <td style="text-indent: 1em">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              <br/>
+                            </p>
+                          </td>
+                          <td style="text-indent: 1em">
+                            <p style="font-size: 8pt">
+                              <br/>
+                              <br/>
+                            </p>
+                          </td>
+                        </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <xsl:for-each select="TRI:SourceReductionActivity">
+                          <tr>
+                            <td width="5%" align="center">
+                              <p style="font-size: 8pt">
+                                8.10.<xsl:value-of select="count(preceding-sibling::TRI:SourceReductionActivity) + 1"/>
+                              </p>
+                            </td>
+                            <td>
+                              <p style="font-size: 8pt">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:SourceReductionActivityCode"/>
+                                &#160;</span>
+                                <br/>
+                              </p>
+                            </td>
+                            <td style="text-indent: 1em" width="15%"
+                                align="center">
+                              <p style="font-size: 8pt">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:SourceReductionMethodCode[1]"/>
+                                &#160;</span>
+                                <br/>
+                                <br/>
+                              </p>
+                            </td>
+                            <td style="text-indent: 1em" width="15%"
+                                align="center">
+                              <p style="font-size: 8pt">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:SourceReductionMethodCode[2]"/>
+                                &#160;</span>
+                                <br/>
+                                <br/>
+                              </p>
+                            </td>
+                            <td style="text-indent: 1em" width="15%"
+                                align="center">
+                              <p style="font-size: 8pt">
+                                <span class="answerText">
+                                  <xsl:value-of select="TRI:SourceReductionMethodCode[3]"/>
+                                &#160;</span>
+                                <br/>
+                                <br/>
+                              </p>
+                            </td>
+                            <xsl:choose>
+	                            <xsl:when test="../TRI:SubmissionReportingYear &gt; '2013'">
+	                            	<td style="text-indent: 1em" width="15%"
+		                                align="center">
+		                              <p style="font-size: 8pt">
+		                                <span class="answerText">
+		                                  <xsl:value-of select="TRI:SourceReductionEfficiencyCode"/>
+		                                &#160;</span>
+		                                <br/>
+		                                <br/>
+		                              </p>
+		                            </td>
+	                            </xsl:when>
+                            </xsl:choose>
+                          </tr>
+                        </xsl:for-each>
+                      </xsl:otherwise>
+                    </xsl:choose>
+                    <xsl:if test="TRI:SubmissionReportingYear &lt; '2011'">
+                      <tr>
+
+						  <td width="5%" align="center">
+							<p style="font-size: 8pt">8.11</p>
+						  </td>
+						  <td colspan="2">
+
+							<p style="font-size: 8pt">If you wish to submit
+													  additional optional
+													  information on source
+													  reduction, recycling, or
+													  pollution control activities,
+													  check "Yes."</p>
+						  </td>
+						  <td colspan="2" style="font-size: 8pt">
+							<p style="font-size: 8pt">
+							  Yes [
+
+							  <xsl:choose>
+								<xsl:when test="TRI:SubmissionAdditionalDataIndicator = 'true'">
+								  <span class="answerText">X</span>
+								</xsl:when>
+							  </xsl:choose>
+							  ]
+
+							</p>
+						  </td>
+						</tr>
+                    </xsl:if>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </center>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0"
+                 style="font-size: 8pt" border="0">
+            <tr>
+              <td width="50%">
+                <p style="font-size: 8pt">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		EPA Form 9350-1 (Rev. <xsl:value-of select="$RevisionDateFormR"/>) - Previous editions are obsolete.
+                  	</xsl:if>
+                </p>
+              </td>
+              <td align="right">
+                <p style="font-size: 8pt">
+                	*For Dioxin and Dioxin-like Compounds, report in grams/year<br/>
+                	<xsl:if test="TRI:SubmissionReportingYear &gt; '2013'">
+                		** Includes quantities released to the environment or transferred off-site as a result of remedial actions, catastrophic events, or other one-time events not associated with production processes
+                	</xsl:if>
+                </p>
+              </td>
+            </tr>
+          </table>
+          <p style="page-break-before: always">&#160;</p>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1"
+                 style="font-size: 8pt" border="0">
+            <tr>
+             <!--   <td width="90%">
+                <a name="PG-6_{$formID}"></a>
+                <p style="font-size: 8pt">
+                  <a href="#PG-1_{$formID}">1</a>
+                  <a href="#PG-2_{$formID}">2</a>
+                  <a href="#PG-3_{$formID}">3</a>
+                  <a href="#PG-4_{$formID}">4</a>
+                  <a href="#PG-5_{$formID}">5</a>
+                  <a href="#PG-6_{$formID}">Additional Info</a>
+                  <xsl:if test="$ScheduleOneNA = 'false'">
+                      <a href="#S1_PG-1_{$formID}">Schedule 1</a>
+                  </xsl:if>
+                </p>
+              </td>-->
+            </tr>
+          </table>
+          <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%"
+                 style="font-size: 8pt">
+            <tr>
+              <td colspan="2">
+                <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="1" cellspacing="0" cellpadding="1" frame="void">
+                  <tr>
+                    <td>
+                        TRI Facility ID Number
+                        <hr />
+                        <span class="answerText">
+                          <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                        &#160;</span>
+                      <hr />
+                      Toxic Chemical, Category, or Generic Name
+                      <hr />
+                      <span class="answerText">
+                        <xsl:choose>
+                          <xsl:when test="TRI:ChemicalIdentification/TRI:ChemicalNameText='NA'">
+                            <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                          </xsl:when>
+                          <xsl:otherwise>
+                            <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalNameText"/>
+                          </xsl:otherwise>
+                        </xsl:choose>
+                      &#160;</span>
+                    </td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <br/>
+          <table border="1" width="99%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+            <tr>
+              <td align="left" style="font-size: 8pt">
+                <p style="font-size: 8pt">
+                  <b>Additional optional information on source reduction,
+                     recycling, or pollution control activities.</b>
+                </p>
+              </td>
+            </tr>
+            <tr>
+              <td align="left" style="font-size: 8pt">
+                <span class="answerText">
+                  <xsl:value-of select="TRI:OptionalInformationText"/>
+                  &#160;
+                </span>
+              </td>
+            </tr>
+          </table>
+          <br/>
+          <xsl:choose>
+          	<xsl:when test="TRI:SubmissionReportingYear &gt; '2013'">
+          		<table summary="table used for layout purposes" border="1" width="99%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+		            <tr>
+		              <td colspan="2" align="left" style="font-size: 8pt">
+		                <p style="font-size: 8pt">
+		                  <b>Section 8.11: If you wish to submit additional optional information on source reduction, recycling, or pollution control activities, provide it here.</b>
+		                </p>
+		              </td>
+		            </tr>
+		            <tr>
+			           <td style="width: 20%;">
+			            <p style="font-size: 8pt">
+			             <b>Topic</b>
+			            </p>
+			           </td>
+			           <td>
+			            <p style="font-size: 8pt">
+			             <b>Comment</b>
+			            </p>
+			           </td>
+	        		</tr>
+		            <xsl:for-each select="TRI:TRIComment">
+		            	<xsl:if test="TRI:TRICommentSection = '8.11'">
+			            	<tr>
+			            		<td style="width: 20%;">
+			            			<p style="font-size: 8pt">
+			            				<xsl:value-of select="TRI:TRICommentTypeDescription"/>
+			            			</p>
+			            		</td>
+			            		<td>
+			            			<p style="font-size: 8pt">
+			            				<xsl:value-of select="TRI:TRICommentText"/>
+			            			</p>
+			            		</td>
+			            	</tr>
+		            	</xsl:if>
+		            </xsl:for-each>
+		          </table>
+		          <br/>
+		          <table summary="table used for layout purposes" border="1" width="99%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+		            <tr>
+		              <td colspan="2" align="left" style="font-size: 8pt">
+		                <p style="font-size: 8pt">
+		                  <b>Section 9.1: If you wish to submit any miscellaneous, additional, or optional information regarding your Form R submission, provide it here.</b>
+		                </p>
+		              </td>
+		            </tr>
+		            <tr>
+			           <td style="width: 20%;">
+			            <p style="font-size: 8pt">
+			             <b>Topic</b>
+			            </p>
+			           </td>
+			           <td>
+			            <p style="font-size: 8pt">
+			             <b>Comment</b>
+			            </p>
+			           </td>
+	        		</tr>
+		            <xsl:for-each select="TRI:TRIComment">
+		            	<xsl:if test="TRI:TRICommentSection = '9.1'">
+			            	<xsl:if test="TRI:TRICommentText !=''">
+			            	<tr>
+			            		<td style="width: 20%;">
+			            			<p style="font-size: 8pt">
+			            				<xsl:value-of select="TRI:TRICommentTypeDescription"/>
+			            			</p>
+			            		</td>
+			            		<td>
+			            			<p style="font-size: 8pt">
+			            				<xsl:value-of select="TRI:TRICommentText"/>
+			            			</p>
+			            		</td>
+			            	</tr>
+		            	</xsl:if>
+		            	</xsl:if>
+		            </xsl:for-each>
+		          </table>
+          	</xsl:when>
+	        <xsl:when test="TRI:SubmissionReportingYear &gt; '2010'">
+		        <table summary="table used for layout purposes" border="1" width="99%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+		          <tr>
+		            <td align="left" style="font-size: 8pt">
+		              <p style="font-size: 8pt">
+		                <b>Miscellaneous, additional, or optional information regarding the Form R submission</b>
+		              </p>
+		            </td>
+		          </tr>
+		          <tr>
+		            <td align="left" style="font-size: 8pt">
+		              <span class="answerText">
+		                <xsl:value-of select="TRI:MiscellaneousInformationText"/>
+		              &#160;</span>
+		            </td>
+		          </tr>
+		        </table>
+		    </xsl:when>
+	      </xsl:choose>
+
+          <p style="page-break-before: always"></p>
+
+          <xsl:if test="$ScheduleOneNA = 'false'">
+              <!-- Schedule 1 Page One -->
+
+              <xsl:call-template name="ScheduleOnePageOne">
+                <xsl:with-param name="baseStreamID">0</xsl:with-param>
+                <xsl:with-param name="formID"><xsl:value-of select="$formID" /></xsl:with-param>
+                <xsl:with-param name="OMBNumberSchedule1"><xsl:value-of select="$OMBNumberSchedule1" /></xsl:with-param>
+                <xsl:with-param name="ApprovalDateSchedule1"><xsl:value-of select="$ApprovalDateSchedule1" /></xsl:with-param>
+              </xsl:call-template>
+
+              <!-- Additional Page One(s) if necessary -->
+              <xsl:for-each select="TRI:OnsiteReleaseQuantity/TRI:WaterStream">
+                <xsl:if test="TRI:WaterSequenceNumber > 2 and TRI:WaterSequenceNumber mod 3 = 0">
+                  <xsl:variable name="baseStreamID" select="TRI:WaterSequenceNumber" />
+                  <xsl:for-each select="../..">
+                    <xsl:call-template name="ScheduleOnePageOne">
+                      <xsl:with-param name="baseStreamID"><xsl:value-of select="$baseStreamID" /></xsl:with-param>
+                      <xsl:with-param name="formID"><xsl:value-of select="$formID" /></xsl:with-param>
+                      <xsl:with-param name="OMBNumberSchedule1"><xsl:value-of select="$OMBNumberSchedule1" /></xsl:with-param>
+                      <xsl:with-param name="ApprovalDateSchedule1"><xsl:value-of select="$ApprovalDateSchedule1" /></xsl:with-param>
+                    </xsl:call-template>
+                  </xsl:for-each>
+                </xsl:if>
+              </xsl:for-each>
+
+          <!-- Schedule 1 Page Two -->
+          <div class="landscapeArea">
+          <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+           </tr>
+            <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+              <tr>
+                <td width="30%">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	                  Form Approved OMB Number:<span class="smallAnswer"><xsl:value-of select="$OMBNumberSchedule1" />&#160;</span><br />
+	                  Approval Expires: <span class="smallAnswer"><xsl:value-of select="$ApprovalDateSchedule1" />&#160;</span>
+	                </xsl:if>
+                </td>
+                <td width="10%">
+                  <p style="font-size: 8pt"><b>Page 2 of 4</b></p>
+                </td>
+              </tr>
+            </table>
+
+          <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt;">
+
+              <tr>
+                <td colspan="26" align="center">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="0" cellspacing="0" cellpadding="0" frame="void">
+                    <tr>
+                      <td style="font-size: 10pt"><b> EPA </b></td>
+                      <td align="center" style="font-size: 14pt"><b>FORM R Schedule 1</b></td>
+                      <td><p style="font-size: 8pt">TRI Facility ID Number:</p></td>
+                    </tr>
+                    <tr>
+                      <td>
+                        <p style="font-size: 8pt">United States<br />Environmental Protection<br />Agency</p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 14pt"><b>PART II.  CHEMICAL-SPECIFIC INFORMATION (continued)</b></p>
+                      </td>
+                      <td class="answerText"><xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+
+              <tr>
+                <td align="left" colspan="26" style="font-size: 8pt">
+                  <p style="font-size: 9pt"><b>Section 5. Quantity Of Dioxin And Dioxin-Like Compounds Entering Each Environmental Medium On-site (continued)</b></p>
+                </td>
+              </tr>
+
+              <tr>
+                <td colspan="2" rowspan="3" style="background-color: gray">&#160;</td>
+                <td align="center" colspan="6" style="font-size: 8pt">
+                  <p style="font-size: 8pt"><b>5.4</b>&#160;&#160; Underground Injection</p>
+                </td>
+                <td align="center" colspan="18" style="font-size: 8pt">
+                  <p style="font-size: 8pt"><b>5.5</b>&#160;&#160; Disposal to Land On-site</p>
+                </td>
+              </tr>
+
+              <tr>
+                <td style="font-size: 8pt" align="center"><b>5.4.1</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'UNINJ I'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.4.2</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'UNINJ IIV'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.1A</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'RCRA C'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.1B</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'OTH LANDF'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.2</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'LAND TREA'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.3A</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'SI 5.5.3A'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.3B</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'SI 5.5.3B'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+                <td style="font-size: 8pt" align="center"><b>5.5.4</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator[../../TRI:EnvironmentalMediumCode = 'OTH DISP'] = 'true'">
+                  X
+                  </xsl:if>&#160;
+                </td>
+
+              </tr>
+
+              <tr>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                	<xsl:choose>
+                		<xsl:when test="TRI:SubmissionReportingYear &lt; '2014'">
+                			Underground Injection on-site to Class I Wells
+                		</xsl:when>
+                		<xsl:otherwise>
+                			Class I Underground Injection Wells
+                		</xsl:otherwise>
+                	</xsl:choose>
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                	<xsl:choose>
+                		<xsl:when test="TRI:SubmissionReportingYear &lt; '2014'">
+                			Underground Injection on-site to Class II-V Wells
+                		</xsl:when>
+                		<xsl:otherwise>
+                			Class II-V Underground Injection Wells
+                		</xsl:otherwise>
+                	</xsl:choose>
+
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  RCRA Subtitle C landfills
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  Other landfills
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  Land treatment/application farming
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  RCRA Subtitle C surface impoundment
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  Other surface impoundment
+                </td>
+                <td colspan="3" style="font-size: 8pt" align="center">
+                  Other disposal
+                </td>
+              </tr>
+
+              <xsl:call-template name="ScheduleOnePageTwoRow" />
+
+            </table>
+          </center>
+
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+              <td width="60%">
+                <p style="font-size: 8pt">
+                  EPA Form 9350-3
+                </p>
+              </td>
+              <td width="30%">
+                <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+              </td>
+            </tr>
+          </table>
+          </div>
+
+          <!-- Schedule 1 Page Three -->
+          <xsl:variable name="potwTEQ" select="TRI:POTWWasteQuantity/TRI:ToxicEquivalencyIdentification" />
+
+            <div style="width: 1010px;" class="landscapeArea">
+            <tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+            </tr>
+            <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+              <tr>
+                <td width="30%">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	                  Form Approved OMB Number:<span class="smallAnswer"><xsl:value-of select="$OMBNumberSchedule1" />&#160;</span><br />
+    	              Approval Expires: <span class="smallAnswer"><xsl:value-of select="$ApprovalDateSchedule1" />&#160;</span>
+    	            </xsl:if>
+                </td>
+                <td width="10%">
+                  <p style="font-size: 8pt"><b>Page 3 of 4</b></p>
+                </td>
+              </tr>
+            </table>
+
+          <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt;">
+              <tr>
+                <td colspan="18" align="center">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="0" cellspacing="0" cellpadding="0" frame="void">
+                    <tr>
+                      <td style="font-size: 8pt">
+                        <p style="font-size: 10pt"><b> EPA </b></p>
+                      </td>
+                      <td align="center" style="font-size: 10pt">
+                        <p style="font-size: 14pt"><b>FORM R Schedule 1</b></p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">TRI Facility ID Number:</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td>
+                        <p style="font-size: 8pt">United States<br />Environmental Protection<br />Agency</p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 14pt"><b>PART II.  CHEMICAL-SPECIFIC INFORMATION (continued)</b></p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                            <span class="answerText">
+                              <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                            &#160;</span>
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+
+              <tr>
+                <td align="left" colspan="18" style="font-size: 8pt">
+                  <p style="font-size: 9pt"><b>SECTION 6. TRANSFERS OF DIOXIN AND DIOXIN-LIKE COMPOUNDS IN WASTES TO OFF-SITE LOCATIONS</b></p>
+                </td>
+              </tr>
+              <tr>
+                 <xsl:choose>
+				  <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+					 <td align="left" colspan="18" style="font-size: 8pt" width="50%">
+					  <p style="font-size: 9pt"><b>6.1 DISCHARGES TO PUBLICLY-OWNED TREATMENT WORKS (POTWs)</b></p>
+					</td>
+				  </xsl:when>
+				  <xsl:otherwise>
+					<td align="left" colspan="9" style="font-size: 8pt" width="50%">
+					  <p style="font-size: 9pt"><b>6.1 DISCHARGES TO PUBLICLY-OWNED TREATMENT WORKS (POTWs)</b></p>
+					</td>
+					<td align="left" colspan="9" style="font-size: 8pt" width="50%">
+					  <p style="font-size: 8pt">
+						NA [
+						  <xsl:if test="TRI:POTWWasteQuantity/TRI:WasteQuantityNAIndicator = 'true' or not(TRI:POTWWasteQuantity)">
+							<span class="answerText">X</span>
+						  </xsl:if>
+						]
+					  </p>
+					</td>
+				  </xsl:otherwise>
+				</xsl:choose>
+              </tr>
+              <xsl:for-each select="TRI:POTWWasteQuantity">
+              <xsl:choose>
+				<xsl:when test="../TRI:SubmissionReportingYear &lt; '2011'">
+				  <tr>
+					  <td colspan="18" align="center" style="font-size: 8pt"><b>6.1.A.3 Mass (grams) of each compound in the category (1-17)
+					  </b>
+					</td>
+				  </tr>
+				   <tr>
+					  <td style="font-size: 8pt">1</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency1Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">2</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency2Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">3</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency3Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">4</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency4Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">5</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency5Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">6</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency6Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">7</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency7Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">8</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency8Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">9</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency9Value" />&#160;</td>
+					</tr>
+					<tr>
+					  <td style="font-size: 8pt">10</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency10Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">11</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency11Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">12</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency12Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">13</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency13Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">14</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency14Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">15</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency15Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">16</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency16Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">17</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency17Value" />&#160;</td>
+
+					  <td colspan="2" style="background-color:gray">&#160;</td>
+				  </tr>
+				</xsl:when>
+				<xsl:otherwise>
+				  <tr>
+					  <td colspan="2" align="left" style="font-size: 9pt"><b>6.1.<xsl:value-of select="TRI:POTWSequenceNumber" />
+					  </b></td>
+					  <td colspan="16" align="left" style="font-size: 8pt"><b>C. Mass (grams) of each compound in the category (1-17)
+					  </b></td>
+				  </tr>
+				  <tr>
+					  <td align="center" colspan="2" style="font-size: 8pt">
+						  <b><xsl:value-of select="TRI:POTWSequenceNumber" />.</b>
+					  </td>
+					  <td style="font-size: 8pt">1</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency1Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">2</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency2Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">3</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency3Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">4</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency4Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">5</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency5Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">6</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency6Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">7</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency7Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">8</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency8Value" />&#160;</td>
+					</tr>
+					<tr>
+					  <td style="font-size: 8pt">9</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency9Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">10</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency10Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">11</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency11Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">12</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency12Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">13</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency13Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">14</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency14Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">15</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency15Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">16</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency16Value" />&#160;</td>
+
+					  <td style="font-size: 8pt">17</td>
+					  <td align="center" class="teqAnswer"><xsl:value-of select="TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency17Value" />&#160;</td>
+				  </tr>
+		        </xsl:otherwise>
+                </xsl:choose>
+
+          	</xsl:for-each>
+              <tr>
+                <xsl:choose>
+				  <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+				    <td align="left" colspan="18" style="font-size: 8pt">
+					  <p style="font-size: 9pt"><b>6.2  TRANSFERS TO OTHER OFF-SITE LOCATIONS</b></p>
+					</td>
+				  </xsl:when>
+				  <xsl:otherwise>
+				    <td align="left" colspan="9" style="font-size: 8pt">
+					  <p style="font-size: 9pt"><b>6.2  TRANSFERS TO OTHER OFF-SITE LOCATIONS</b></p>
+					</td>
+					<td align="left" colspan="9" style="font-size: 8pt;">
+						<p style="font-size: 8pt">
+					   NA [
+
+						  <xsl:if test="not(TRI:TransferLocation)">
+
+								<span class="answerText">X</span>
+
+						  </xsl:if>
+
+						 ]
+					 </p>
+					</td>
+				  </xsl:otherwise>
+				</xsl:choose>
+              </tr>
+
+
+              <!-- Loop through transfers; if not potw write header and call template for transfer TEQ quantities -->
+              <xsl:for-each select="TRI:TransferLocation">
+                <xsl:if test="TRI:POTWIndicator = 'false'">
+                  <tr>
+                    <td colspan="2" align="left" style="font-size: 8pt">
+                      <p style="font-size: 9pt">
+                        <xsl:choose>
+                        <xsl:when test="../TRI:TransferLocation[1]/TRI:POTWIndicator = 'true'">
+                          <b>6.2.<xsl:value-of select="count(preceding-sibling::TRI:TransferLocation)-1"/></b>
+                        </xsl:when>
+                        <xsl:otherwise>
+                          <b>6.2.<xsl:value-of select="count(preceding-sibling::TRI:TransferLocation)-1"/></b>
+                        </xsl:otherwise>
+                        </xsl:choose>
+                      </p>
+                    </td>
+                    <td colspan="16" align="left" style="font-size: 8pt">
+                      <p style="font-size: 8pt"><b>D. Mass (grams) of each compound in the category (1-17)</b></p>
+                    </td>
+                  </tr>
+
+                  <!-- Loop through TEQ values -->
+                  <xsl:for-each select="TRI:TransferQuantity">
+                    <xsl:call-template name="ScheduleOnePageThreeRow" />
+                  </xsl:for-each>
+
+                </xsl:if>
+              </xsl:for-each>
+
+              <!-- Put in 2 blank section 6.2 TEQ sections if there is no data -->
+              <xsl:if test="count(TRI:TransferLocation) = 0 or (count(TRI:TransferLocation) = 1 and TRI:TransferLocation[1]/TRI:POTWIndicator = 'true')">
+                  <xsl:call-template name="ScheduleOnePageThreeRowBlank"><xsl:with-param name="i">1</xsl:with-param></xsl:call-template>
+                  <xsl:call-template name="ScheduleOnePageThreeRowBlank"><xsl:with-param name="i">2</xsl:with-param></xsl:call-template>
+              </xsl:if>
+
+              <tr>
+                <td align="left" colspan="18" style="font-size: 8pt">
+                  <!--p style="font-size: 8pt">
+                    If additional pages of Section 6.2 are attached, indicate the total number of pages in this box&#160;&#160;
+                    <span style="border: 1px solid black; padding: 2px; text-align:center; width: 25px;">
+                      &#160;
+                    &#160;</span>
+                    <br />
+                    and indicate the Section 6.2 page number in this box&#160;&#160;
+                    <span style="border: 1px solid black; padding: 2px; text-align:center; width: 25px;">
+                      &#160;
+                    &#160;</span>&#160;
+                    (example: 1,2,3, etc.)
+                  </p-->
+                  &#160;
+                </td>
+              </tr>
+
+            </table>
+          </center>
+
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+              <td width="60%">
+                <p style="font-size: 8pt">
+                  EPA Form 9350-3
+                </p>
+              </td>
+              <td width="30%">
+                <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+              </td>
+            </tr>
+          </table>
+          </div>
+
+          <!-- Schedule 1 Page Four -->
+
+         <div width="1010px;" class="landscapeArea">
+         	<tr>
+	              <td align="center" width="100%">
+	                <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+	                  *** Do not send to EPA: This is the final copy of your form.***
+	                &#160;</span>
+	              </td>
+            </tr>
+            <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+              <tr>
+                <td width="30%">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                  		Form Approved OMB Number:<span class="smallAnswer"><xsl:value-of select="$OMBNumberSchedule1" />&#160;</span><br />
+                  		Approval Expires: <span class="smallAnswer"><xsl:value-of select="$ApprovalDateSchedule1" />&#160;</span>
+                  	</xsl:if>
+                </td>
+                <td width="10%">
+                  <p style="font-size: 8pt"><b>Page 4 of 4</b></p>
+                </td>
+              </tr>
+            </table>
+
+          <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt;">
+              <tr>
+                <td colspan="13" align="center">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="0" cellspacing="0" cellpadding="0" frame="void">
+                    <tr>
+                      <td style="font-size: 8pt">
+                        <p style="font-size: 10pt"><b> EPA </b></p>
+                      </td>
+                      <td align="center" style="font-size: 10pt">
+                        <p style="font-size: 14pt"><b>FORM R Schedule 1</b></p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">TRI Facility ID Number:</p>
+                      </td>
+                    </tr>
+                    <tr>
+                      <td>
+                        <p style="font-size: 8pt">United States<br />Environmental Protection<br />Agency</p>
+                      </td>
+                      <td align="center">
+                        <p style="font-size: 14pt"><b>PART II.  CHEMICAL-SPECIFIC INFORMATION (continued)</b></p>
+                      </td>
+                      <td>
+                        <p style="font-size: 8pt">
+                            <span class="answerText">
+                              <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                            &#160;</span>
+                        </p>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+
+              <tr>
+                <td align="left" colspan="13" style="font-size: 8pt">
+                  <p style="font-size: 9pt"><b>SECTION 8. SOURCE REDUCTION AND WASTE MANAGEMENT FOR DIOXIN AND DIOXIN-LIKE COMPOUNDS (current year only)</b></p>
+                </td>
+              </tr>
+
+
+              <tr>
+                <td colspan="2" rowspan="2" style="background-color:gray">&#160;</td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.1a</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.1b</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.1c</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.1d</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.2</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.3</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.4</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.5</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.6</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.7</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">8.8</p>
+                </td>
+              </tr>
+
+              <tr>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Total on-site disposal to Class 1 Underground Injection Wells, RCRA Subtitle C landfills, and other landfills</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Total other on-site disposal or other releases</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Total off-site disposal to Class 1 Underground Injection Wells, RCRA Subtitle C landfills, and other landfills</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Total other off-site disposal or other releases</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity used for energy recovery on-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity used for energy recovery off-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity recycled on-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity recycled off-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity treated on-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity treated off-site</p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Quantity released to the environment as a result of remedial actions, catastrophic events, or one-time events not associated with production processes</p>
+                </td>
+              </tr>
+
+              <xsl:call-template name="ScheduleOnePageFourRow" />
+
+            </table>
+          </center>
+
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+              <td width="60%">
+                <p style="font-size: 8pt">
+                  EPA Form 9350-3
+                </p>
+              </td>
+              <td width="30%">
+                <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+              </td>
+            </tr>
+          </table>
+          </div>
+          </xsl:if>
+
+      </xsl:when>
+      <xsl:otherwise>
+          <!-- Begin Form A : Form A data will be grouped together by revision codes, withdrawal codes, and public and technical contact infomration.
+                So, the following test chooses only to enter the form a section if the form a data encountered has not been encountered yet.
+          -->
+
+          <xsl:if test="count(preceding::TRI:Report[TRI:ReportType/TRI:ReportTypeCode = current()/TRI:ReportType/TRI:ReportTypeCode
+                                                         and concat(TRI:TechnicalContactNameText/sc:IndividualFullName, 'xx') = concat(current()/TRI:TechnicalContactNameText/sc:IndividualFullName, 'xx')
+                                                         and concat(TRI:TechnicalContactPhoneText, 'xx') = concat(current()/TRI:TechnicalContactPhoneText, 'xx')
+                                                         and concat(TRI:TechnicalContactEmailAddressText, 'xx') = concat(current()/TRI:TechnicalContactEmailAddressText, 'xx')
+                                                         and concat(TRI:PublicContactNameText/sc:IndividualFullName, 'xx') = concat(current()/TRI:PublicContactNameText/sc:IndividualFullName, 'xx')
+                                                         and concat(TRI:PublicContactPhoneText, 'xx') = concat(current()/TRI:PublicContactPhoneText, 'xx')
+                                                         and concat(TRI:PublicContactEmailAddressText, 'xx') = concat(current()/TRI:PublicContactEmailAddressText, 'xx')
+                                                         and sc:RevisionIndicator = current()/sc:RevisionIndicator
+                                                         and concat(TRI:ChemicalReportRevisionCode[1], 'xx') = concat(current()/TRI:ChemicalReportRevisionCode[1], 'xx')
+                                                         and concat(TRI:ChemicalReportRevisionCode[2], 'xx') = concat(current()/TRI:ChemicalReportRevisionCode[2], 'xx')
+                                                         and concat(TRI:ChemicalReportWithdrawalCode[1], 'xx') = concat(current()/TRI:ChemicalReportWithdrawalCode[1], 'xx')
+                                                         and concat(TRI:ChemicalReportWithdrawalCode[2], 'xx') = concat(current()/TRI:ChemicalReportWithdrawalCode[2], 'xx')
+                                                         and ../TRI:Facility = current()/../TRI:Facility
+                                                         ]) = 0">
+          <xsl:if test="count(preceding::TRI:Report) &gt; 0">
+            <p style="page-break-before: always">&#160;</p>
+          </xsl:if>
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" border="0">
+            <tr>
+             <td align="center" width="100%">
+              <span style="font-size: 12pt; color: red; font-weight: bold;" class="noPrint">
+               *** File Copy Only: Do Not Submit Paper Form to EPA ***
+              &#160;</span>
+             </td>
+            </tr>
+
+            <xsl:if test="SubmissionStatusText">
+             <tr>
+              <td>
+               <span class="fieldLabel" style="color:red">
+                Form Status:
+                <xsl:value-of select="SubmissionStatusText"/>
+               &#160;</span>
+              </td>
+             </tr>
+            </xsl:if>
+            <xsl:if test="ValidationStatusText">
+             <tr>
+              <td>
+               <span class="fieldLabel" style="color:red">
+                Validation Status:
+                <xsl:value-of select="ValidationStatusText"/>
+               &#160;</span>
+              </td>
+             </tr>
+            </xsl:if>
+
+           </table>
+           <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+            <tr>
+             <td width="30%">
+             	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	              <p style="font-size: 8pt">
+    	          Form Approved OMB Number:
+        	      <span class="smallAnswer">
+        	       <xsl:value-of select="$OMBNumberFormA"/>
+        	      &#160;</span>
+        	      </p>
+        	    </xsl:if>
+             </td>
+             <td width="10%">
+              <br/>
+             </td>
+            </tr>
+            <tr>
+             <td width="60%">
+              <p style="font-size: 8pt">
+              	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	               <i>(IMPORTANT: Read instructions before completing form; type or use fill-and-print form)</i>
+	            </xsl:if>
+              </p>
+             </td>
+             <td width="30%">
+             	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	              <p style="font-size: 8pt">
+    	          Approval Expires:
+    	          <span class="smallAnswer">
+    	           <xsl:value-of select="$ApprovalDateFormA"/>
+    	          &#160;</span>
+    	          </p>
+    	        </xsl:if>
+             </td>
+             <td width="10%">
+              <br/>
+             </td>
+            </tr>
+           </table>
+           <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-family: 'Arial'; font-size: 8pt">
+             <tr>
+              <td colspan="2" align="center">
+               <table summary="table used for layout purposes" width="100%" style="font-size: 10pt" cellspacing="0" cellpadding="1">
+                <tr>
+                 <td width="20%">
+                  <p style="font-size: 9pt">
+                   <span style="font-weight:bold">
+                    United States
+                    <br/>
+                    Environmental Protection Agency
+                   &#160;</span>
+                  </p>
+                 </td>
+                 <td nowrap="nowrap" align="center">
+                  <p style="font-size: 10pt">
+                   <span style="font-weight:bold">
+                    TOXICS CHEMICAL RELEASE INVENTORY
+                    <br/>
+                    FORM A
+                   &#160;</span>
+                  </p>
+                 </td>
+                </tr>
+               </table>
+              </td>
+              <td style="font-size: 8pt">
+                TRI Facility ID Number
+                <hr />
+                <span class="answerText">
+                 <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>&#160;</span>
+              </td>
+             </tr>
+             <tr>
+              <td colspan="3">
+               <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt" frame="void">
+                <tr>
+                 <td align="center" width="15%">
+                  <p style="font-size: 8pt">WHERE TO SEND COMPLETED FORMS: </p>
+                 </td>
+                 <td nowrap="nowrap">
+                  <p style="font-size: 8pt">
+                   1. TRI Data Processing Center
+                   <br />
+                   P.O. Box 10163
+                   <br />
+                   Fairfax, VA 22038
+                   <br />
+                   <span style="font-size: 8pt; color: red; font-weight: bold;">
+                   *** File Copy Only: Do Not Submit Paper Form to EPA ***
+                   &#160;</span>
+                  </p>
+                 </td>
+                 <td nowrap="nowrap">
+                  <p style="font-size: 8pt">
+                   2. APPROPRIATE STATE OFFICE
+                   <br/>
+                   (See instructions in Appendix F)
+                  </p>
+                 </td>
+                </tr>
+                <tr>
+                 <td colspan="3"></td>
+                </tr>
+               </table>
+               <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" frame="void">
+                <tr>
+                 <td width="33%">
+                  <p style="font-size: 9pt">This section only applies if you are revising or withdrawing a previously submitted form, otherwise leave blank:</p>
+                 </td>
+                 <td align="center" width="33%">
+                  <p style="font-size: 9pt">
+                   Revision (Enter up to two code(s))
+                   <br/>
+                   <br/>
+                   [
+                   <span class="answerText">
+                    <xsl:value-of select="TRI:ChemicalReportRevisionCode[1]"/>
+                   &#160;</span>
+                   ] [
+                   <span class="answerText">
+                    <xsl:value-of select="TRI:ChemicalReportRevisionCode[2]"/>
+                   &#160;</span>
+                   ]
+                  </p>
+                 </td>
+                 <td align="center" width="34%">
+                  <p style="font-size: 9pt">
+                   Withdrawal (Enter up to two code(s))
+                   <br/>
+                   <br/>
+                   [
+                   <span class="answerText">
+                    <xsl:value-of select="TRI:ChemicalReportWithdrawalCode[1]"/>
+                   &#160;</span>
+                   ] [
+                   <span class="answerText">
+                    <xsl:value-of select="TRI:ChemicalReportWithdrawalCode[2]"/>
+                   &#160;</span>
+                   ]
+                  </p>
+                 </td>
+                </tr>
+               </table>
+              </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3" style="font-size: 8pt">
+               <p style="font-size: 8pt">Important: See Instructions to determine when "Not Applicable (NA)" boxes should be checked.</p>
+              </td>
+             </tr>
+             <tr>
+              <td align="center" colspan="3">
+               <p style="font-size: 8pt">Part I. FACILITY IDENTIFICATION INFORMATION </p>
+              </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3" style="font-size: 8pt">
+                SECTION 1. REPORTING YEAR :
+                <u><span class="answerText"><xsl:value-of select="TRI:SubmissionReportingYear"/></span></u>
+                <br />
+              </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3">
+               <p style="font-size: 8pt">SECTION 2. TRADE SECRET INFORMATION </p>
+              </td>
+             </tr>
+             <tr>
+              <td align="left" style="font-size: 8pt">
+               <dl>
+                <dt>
+                 2.1 Are you claiming the toxic chemical identified on page 2 trade secret?
+                </dt>
+                <dd>
+                  [
+                  <xsl:choose>
+                   <xsl:when test="TRI:ChemicalTradeSecretIndicator = 'true'">
+                    <span class="answerText">X</span>
+                   </xsl:when>
+                  </xsl:choose>
+                  ] Yes (Answer question 2.2; attach substantiation forms)
+                </dd>
+                <dd>
+                  [
+                  <xsl:choose>
+                   <xsl:when test="TRI:ChemicalTradeSecretIndicator = 'false'">
+                    <span class="answerText">X</span>
+                   </xsl:when>
+                  </xsl:choose>
+                  ] NO (Do not answer 2.2; go to Section 3)
+                </dd>
+               </dl>
+              </td>
+              <td align="left">
+               <dl>
+                <dt>
+                 2.2 Is this copy
+                </dt>
+                <dd>
+                 <p style="font-size: 8pt">[ ] Sanitized [ ] Unsanitized</p>
+                </dd>
+                <dd>
+                 <p style="font-size: 8pt">(Answer only if "Yes" in 2.1)</p>
+                </dd>
+               </dl>
+              </td>
+              <td>
+               <br/>
+              </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3">
+               <p style="font-size: 8pt">SECTION 3. CERTIFICATION (Important: Read and sign after completing all form sections.)</p>
+              </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3">
+               <p style="font-size: 8pt">
+                <xsl:choose>
+                 <xsl:when test="TRI:SubmissionReportingYear = '2006'">
+                      Pursuant to 40 CFR 372.27(a)(1), "I hereby certify that to the best of my knowledge and belief for the
+                      toxic chemical(s) listed in this statement, for this reporting year, the annual reportable amount for each
+                      chemical, as defined in 40 CFR 372.27(a)(1), did not exceed 5,000 pounds, which included no more than 2,000
+                      pounds of total disposal or other releases to the environment, and that the chemical was manufactured,
+                      or processed, or otherwise used in an amount not exceeding 1 million pounds during this reporting
+                      year;" and/or Pursuant to 40 CFR 372.27(a)(2), "I hereby certify that to the best of my knowledge and
+                      belief for the toxic chemical(s) of special concern listed in this statement, there were zero disposals or
+                      other releases to the environment (including disposals or other releases that resulted from catastrophic
+                      events) for this reporting year, the "Annual Reportable Amount of a Chemical of Special Concern"
+                      for each such chemical, as defined in 40 CFR 372.27(a)(2), did not exceed 500 pounds for this
+                      reporting year, and that the chemical was manufactured, or processed, or otherwise used in an
+                      amount not exceeding 1 million pounds during this reporting year."
+                 </xsl:when>
+				 <xsl:when test="TRI:SubmissionReportingYear = '2007'">
+                      Pursuant to 40 CFR 372.27(a)(1), "I hereby certify that to the best of my knowledge and belief for the
+                      toxic chemical(s) listed in this statement, for this reporting year, the annual reportable amount for each
+                      chemical, as defined in 40 CFR 372.27(a)(1), did not exceed 5,000 pounds, which included no more than 2,000
+                      pounds of total disposal or other releases to the environment, and that the chemical was manufactured,
+                      or processed, or otherwise used in an amount not exceeding 1 million pounds during this reporting
+                      year;" and/or Pursuant to 40 CFR 372.27(a)(2), "I hereby certify that to the best of my knowledge and
+                      belief for the toxic chemical(s) of special concern listed in this statement, there were zero disposals or
+                      other releases to the environment (including disposals or other releases that resulted from catastrophic
+                      events) for this reporting year, the "Annual Reportable Amount of a Chemical of Special Concern"
+                      for each such chemical, as defined in 40 CFR 372.27(a)(2), did not exceed 500 pounds for this
+                      reporting year, and that the chemical was manufactured, or processed, or otherwise used in an
+                      amount not exceeding 1 million pounds during this reporting year."
+                 </xsl:when>
+                 <xsl:otherwise>
+				 I hereby certify that to the best of my knowledge and belief, for each toxic chemical listed in the statement,
+				 the annual reportable amount as defined in 40 CFR 372.27 (a), did not exceed 500 pounds for this reporting year
+				 and the chemical was manufactured, processed, or otherwise used in an amount not exceeding 1 million pounds during
+				 this reporting year.
+				 </xsl:otherwise>
+                </xsl:choose>
+               </p>
+               <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt" frame="above">
+                <tr>
+                 <td>
+                  <p style="font-size: 8pt">Name and official title of owner/operator or senior management official:</p>
+                 </td>
+                 <td>
+                  <p style="font-size: 8pt">Signature:</p>
+                 </td>
+                 <td>
+                  <p style="font-size: 8pt">Date Signed: </p>
+                 </td>
+                </tr>
+                <tr>
+                      <td>
+  						<p>
+      						<span class="answerText"><xsl:value-of select="TRI:CertifierName"/>&#160;&#160;&#160;</span>
+      						<span class="answerText"><xsl:value-of select="TRI:CertifierTitleText"/></span>
+  						</p>
+					  </td>
+					  <td>
+    					<p>
+      						<span style="font-size: 9pt; color: red; font-weight: bold;">Reference Copy: Copy of Record Resides in CDX</span>
+    					</p>
+					  </td>
+					  <td>
+     					<span class="answerText">
+					    	<xsl:if test="TRI:CertificationSignedDate != '' and TRI:CertificationSignedDate != '1900-01-01'">
+	                    		<xsl:value-of select="TRI:CertificationSignedDate"/>
+	                   		</xsl:if>
+     					</span>
+					  </td>
+                    </tr>
+               </table>
+               </td>
+             </tr>
+             <tr>
+              <td align="left" colspan="3">
+               <p style="font-size: 8pt">SECTION 4. FACILITY IDENTIFICATION </p>
+              </td>
+             </tr>
+             <tr>
+              <td colspan="3">
+               <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0" border="1" frame="void" style="font-size: 8pt">
+                <tr>
+                 <td width="5%">4.1</td>
+                 <td colspan="4" width="45%">&#160;</td>
+                 <td colspan="2" width="20%">TRI Facility ID Number</td>
+                 <td colspan="2" width="30%">
+                  <p>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                </tr>
+ 				<xsl:choose>
+                      <xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+	                    <tr>
+	                      <td colspan="5">
+	                        <p style="font-size: 7pt">
+	                          <u style="font-size: 7pt">Facility or Establishment Name</u>
+	                          <br/>
+	                          <span class="answerText">
+	                            <xsl:value-of select="../TRI:Facility/sc:FacilitySiteName"/>
+	                          </span>
+	                        </p>
+	                      </td>
+	                      <td colspan="4">
+	                        <p style="font-size: 7pt">
+	                          <u style="font-size: 7pt">Facility or Establishment Name or Mailing Address(if different from street address)</u>
+	                          <br/>
+	                          <span class="answerText">
+	                            <xsl:value-of select="../TRI:Facility/TRI:MailingFacilitySiteName"/>
+	                          </span>
+	                        </p>
+	                      </td>
+	                    </tr>
+                      </xsl:when>
+                      <xsl:otherwise>
+                        <tr>
+		                  <td colspan="9">
+		                   <p>
+		                    <u style="font-size: 7pt">Facility or Establishment Name</u>
+		                   </p>
+		                   <p>
+		                    <span class="answerText">
+		                     <xsl:value-of select="../TRI:Facility/sc:FacilitySiteName"/>
+		                    &#160;</span>
+		                   </p>
+		                  </td>
+		                </tr>
+                      </xsl:otherwise>
+                </xsl:choose>
+                <tr>
+                 <td colspan="5">
+                  <p>
+                   <u style="font-size: 7pt">Street</u>
+                  </p>
+                  <p>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocationAddressText"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                 <td colspan="4">
+                  <p>
+                   <u style="font-size: 7pt">Mailing Address (if different from physical street address)</u>
+                  </p>
+                  <p>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:MailingAddressText"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                </tr>
+                <tr>
+                 <td colspan="5">
+                  <p>
+                  <xsl:choose>
+                   <xsl:when test="TRI:SubmissionReportingYear >= '2012' ">
+                      <u style="font-size: 7pt">City/County/Tribe/State/ZIP Code</u>
+                      <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocalityName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                   &#160;</span>
+                    /
+                   <span class="answerText">
+                     BIA Code: <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:TribalIdentity/sc:TribalCode"/>
+                     &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:AddressPostalCode"/>
+                   &#160;</span>
+                   </xsl:when>
+
+                   <xsl:otherwise>
+                     <u style="font-size: 7pt">City/County/State/ZIP Code</u>
+                      <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:LocalityName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:CountyIdentity/sc:CountyName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:StateIdentity/sc:StateName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/sc:LocationAddress/sc:AddressPostalCode"/>
+                   &#160;</span>
+                   </xsl:otherwise>
+                   </xsl:choose>
+                  </p>
+                 </td>
+                 <td colspan="3">
+                  <p>
+                   <u style="font-size: 7pt">City/State/ZIP Code</u>
+                   <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:MailingAddressCityName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:StateIdentity/sc:StateName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:AddressPostalCode"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                 <td colspan="1" width="15%">
+                  <p>
+                   <u style="font-size: 7pt">Country (Non-US)</u>
+                   <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/sc:CountryIdentity/sc:CountryName"/>
+                   &#160;</span>
+                   /
+                   <span class="answerText">
+                    <xsl:value-of select="../TRI:Facility/TRI:MailingAddress/TRI:ProvinceNameText"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                </tr>
+                <tr>
+                 <td width="5%">
+                  <p style="font-size: 8pt">4.2</p>
+                 </td>
+                 <td colspan="4">
+                  <p style="font-size: 8pt">
+                   This report contains information for : (
+                   <u>Important:</u>
+                   check c or d if applicable)
+                  </p>
+                 </td>
+                 <td colspan="2">
+                  c. [
+                  <xsl:choose>
+                   <xsl:when test="TRI:SubmissionFederalFacilityIndicator = 'Y'">
+                    <span class="answerText">X</span>
+                   </xsl:when>
+                  </xsl:choose>
+                  ] A Federal facility
+                 </td>
+                 <td colspan="2">
+                  d. [
+                  <xsl:choose>
+                   <xsl:when test="TRI:SubmissionGOCOFacilityIndicator = 'true'">
+                    <span class="answerText">X</span>
+                   </xsl:when>
+                  </xsl:choose>
+                  ] GOCO
+                 </td>
+                </tr>
+                <tr>
+                 <td width="5%">
+                  <p style="font-size: 8pt">4.3</p>
+                 </td>
+                 <td colspan="2" nowrap="nowrap" align="center">
+                  <p style="font-size: 8pt">Technical Contact name</p>
+                 </td>
+                 <td colspan="2">
+                  <span class="answerText">
+                   <xsl:value-of select="TRI:TechnicalContactNameText/sc:IndividualFullName"/>
+                  &#160;</span>
+                 </td>
+                 <td colspan="2" nowrap="nowrap">
+                  <p>
+                   <u style="font-size: 7pt">Email Address</u>
+                   <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="TRI:TechnicalContactEmailAddressText"/>
+                   &#160;</span>
+                  </p>
+                 </td>
+                 <td colspan="2" nowrap="nowrap">
+                  <p>
+                   <xsl:choose>
+						<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+							<u style="font-size: 7pt">Telephone Number (include area code and ext.)</u>
+						</xsl:when>
+        				<xsl:otherwise>
+							<u style="font-size: 7pt">Telephone Number (include area code)</u>
+        				</xsl:otherwise>
+					</xsl:choose>
+                   <br/>
+                   <span class="answerText">
+                    <xsl:value-of select="substring(TRI:TechnicalContactPhoneText,1, 3)"/>&#45;<xsl:value-of select="substring(TRI:TechnicalContactPhoneText,4, 3)"/>&#45;<xsl:value-of select="substring(TRI:TechnicalContactPhoneText,7)"/>
+                   &#160;</span>
+                   <xsl:if test="TRI:SubmissionReportingYear &gt; '2013' ">
+                          	 <span class="answerText">
+                            	<xsl:if test="string-length(TRI:TechnicalContactPhoneExtText) &gt; 0 ">
+									&#045; &#160;<xsl:value-of select="TRI:TechnicalContactPhoneExtText"/>
+								</xsl:if>
+                          	&#160;</span>
+                    </xsl:if>
+                  </p>
+                 </td>
+                </tr>
+                <xsl:choose>
+                 <xsl:when test="TRI:SubmissionReportingYear >= '2007' or TRI:SubmissionReportingYear &lt;= '2004'">
+                  <tr>
+                   <td width="5%" style="font-size: 8pt">
+                    <p style="font-size: 8pt">4.4</p>
+                   </td>
+                   <td colspan="2" nowrap="nowrap" align="center">
+                    <p style="font-size: 8pt">Public Contact name </p>
+                   </td>
+                   <td colspan="2">
+                    <span class="answerText">
+                     <xsl:value-of select="TRI:PublicContactNameText"/>
+                    &#160;</span>
+                   </td>
+                   <td colspan="2" nowrap="nowrap">
+                    <p style="font-size: 8pt">
+                     <u style="font-size: 7pt">Email Address</u>
+                     <br/>
+                     <span class="answerText">
+                      <xsl:value-of select="TRI:PublicContactEmailAddressText"/>
+                     &#160;</span>
+                    </p>
+                   </td>
+                   <td colspan="2" nowrap="nowrap">
+                    <p style="font-size: 8pt">
+                   <xsl:choose>
+						<xsl:when test="TRI:SubmissionReportingYear &gt; '2013' ">
+							<u style="font-size: 7pt">Telephone Number (include area code and ext.)</u>
+						</xsl:when>
+        				<xsl:otherwise>
+							<u style="font-size: 7pt">Telephone Number (include area code)</u>
+        				</xsl:otherwise>
+					</xsl:choose>
+                     <br/>
+                     <span class="answerText">
+                     <xsl:if test="string-length(TRI:PublicContactPhoneText)  &gt; 0">
+                      <xsl:value-of select="substring(TRI:PublicContactPhoneText,1, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,4, 3)"/>&#45;<xsl:value-of select="substring(TRI:PublicContactPhoneText,7)"/>
+                      </xsl:if>
+                     &#160;</span>
+                     <xsl:if test="TRI:SubmissionReportingYear &gt; '2013' ">
+                          		 <span class="answerText">
+                            		<xsl:if test="string-length(TRI:PublicContactPhoneExtText) &gt; 0 ">
+										&#045; &#160;<xsl:value-of select="TRI:PublicContactPhoneExtText"/>
+									</xsl:if>
+                          		&#160;</span>
+                     </xsl:if>
+
+                    </p>
+                   </td>
+                  </tr>
+                 </xsl:when>
+                 <xsl:otherwise>
+                  <tr>
+                   <td width="5%">
+                    <p style="font-size: 8pt">4.4</p>
+                   </td>
+                   <td colspan="8">
+                    <p style="font-size: 8pt">Intentionally left blank</p>
+                   </td>
+                  </tr>
+                 </xsl:otherwise>
+                </xsl:choose>
+                <xsl:choose>
+                 <xsl:when test="TRI:SubmissionReportingYear &lt;= '2005'">
+                  <tr>
+                   <td width="5%" style="font-size: 8pt">
+                    <p style="font-size: 8pt">4.5</p>
+                   </td>
+                   <td colspan="2" nowrap="nowrap" width="35%" align="center">
+                    <p style="font-size: 8pt">SIC Code(s) (4 digits)</p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     a.
+                     <xsl:for-each select="../TRI:Facility/TRI:FacilitySIC">
+                      <xsl:choose>
+                       <xsl:when test="sc:SICPrimaryIndicator = 'Primary'">
+                        <span class="answerText">
+                         <xsl:value-of select="sc:SICCode"/>
+                         (Primary)
+                        &#160;</span>
+                       </xsl:when>
+                      </xsl:choose>
+                     </xsl:for-each>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     b.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 1">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[2]/sc:SICCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     c.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 2">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[3]/sc:SICCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     d.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 3">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[4]/sc:SICCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     e.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 4">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[5]/sc:SICCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     f.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilitySIC) > 5">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilitySIC[6]/sc:SICCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                  </tr>
+                 </xsl:when>
+                 <xsl:otherwise>
+                  <tr>
+                   <td width="5%" style="font-size: 8pt">
+                    <p style="font-size: 8pt">4.5</p>
+                   </td>
+                   <td colspan="2" nowrap="nowrap" width="35%" align="center">
+                    <p style="font-size: 8pt">NAICS Code(s) (6 digits)</p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     a.
+                     <xsl:for-each select="../TRI:Facility/TRI:FacilityNAICS">
+                      <xsl:choose>
+                       <xsl:when test="sc:NAICSPrimaryIndicator = 'Primary'">
+                        <span class="answerText">
+                         <xsl:value-of select="sc:NAICSCode"/>
+                         (Primary)
+                        &#160;</span>
+                       </xsl:when>
+                      </xsl:choose>
+                     </xsl:for-each>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     b.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 1">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[2]/sc:NAICSCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     c.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 2">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[3]/sc:NAICSCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     d.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 3">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[4]/sc:NAICSCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     e.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 4">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[5]/sc:NAICSCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                   <td colspan="1" width="10%">
+                    <p style="font-size: 8pt">
+                     f.
+                     <xsl:choose>
+                      <xsl:when test="count(../TRI:Facility/TRI:FacilityNAICS) > 5">
+                       <span class="answerText">
+                        <xsl:value-of select="../TRI:Facility/TRI:FacilityNAICS[6]/sc:NAICSCode"/>
+                       &#160;</span>
+                      </xsl:when>
+                     </xsl:choose>
+                    </p>
+                   </td>
+                  </tr>
+                 </xsl:otherwise>
+                </xsl:choose>
+                <tr>
+                 <td colspan="9">
+                  <table summary="table used for layout purposes" width="100%" cellpadding="1" cellspacing="0" border="1" frame="void" style="font-size: 8pt" rules="all">
+                   <tr>
+                    <td width="5%" style="font-size: 8pt">
+                     <p style="font-size: 8pt">4.7</p>
+                    </td>
+                    <td nowrap="nowrap">
+                     <p style="font-size: 8pt">
+                      Dun and Bradstreet
+                      <br/>
+                      Number(s) (9 digits)
+                     </p>
+                    </td>
+                   </tr>
+                   <tr>
+                    <td colspan="2">
+                     <p style="font-size: 8pt">
+                      a.
+                      <span class="answerText">
+                       <xsl:value-of select="../TRI:Facility/TRI:FacilityDunBradstreetCode[1]"/>
+                      &#160;</span>
+                     </p>
+                    </td>
+                   </tr>
+                   <tr>
+                    <td colspan="2">
+                     <p style="font-size: 8pt">
+                      b.
+                      <span class="answerText">
+                       <xsl:value-of select="../TRI:Facility/TRI:FacilityDunBradstreetCode[2]"/>
+                      &#160;</span>
+                     </p>
+                    </td>
+                   </tr>
+                  </table>
+                 </td>
+                </tr>
+                <tr>
+                 <td align="left" colspan="9">
+                  <p style="font-size: 8pt">SECTION 5. PARENT COMPANY INFORMATION</p>
+                 </td>
+                </tr>
+                <tr>
+                 <td width="5%" style="font-size: 8pt">
+                  <p style="font-size: 8pt">5.1</p>
+                 </td>
+                 <td colspan="2" align="center">
+                  <p style="font-size: 8pt">
+				  <xsl:choose>
+					<xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+					  Name of Parent Company
+					</xsl:when>
+					<xsl:otherwise>
+					  Name of U.S. Parent Company (for TRI Reporting purposes)
+					</xsl:otherwise>
+			       </xsl:choose>
+                  </p>
+                 </td>
+                 <xsl:choose>
+						  <xsl:when test="TRI:SubmissionReportingYear &gt; '2010'">
+						  <td colspan="5">
+                        <span class="answerText">
+                        <xsl:if test="../TRI:Facility/TRI:ParentCompanyNameText != 'NA'">
+                    		<xsl:value-of select="../TRI:Facility/TRI:ParentCompanyNameText"/>
+                   		</xsl:if>
+                        &#160;</span>
+                        <br/>
+                      </td>
+					  <td colspan="1">
+                        <p style="font-size: 8pt">
+						    No U.S. Parent Company (for TRI Reporting purposes) [
+					    <xsl:choose>
+                            <xsl:when test="../TRI:Facility/TRI:ParentCompanyNameNAIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ]
+                        </p>
+                      </td>
+						  </xsl:when>
+						  <xsl:otherwise>
+					                       <td colspan="1">
+                        <p style="font-size: 8pt">
+						    NA [
+
+					    <xsl:choose>
+                            <xsl:when test="../TRI:Facility/TRI:ParentCompanyNameNAIndicator = 'true'">
+                              <span class="answerText">X</span>
+                            </xsl:when>
+                          </xsl:choose>
+                          ]
+                        </p>
+                      </td>
+                      <td colspan="5">
+                        <span class="answerText">
+                          <xsl:value-of select="../TRI:Facility/TRI:ParentCompanyNameText"/>
+                        &#160;</span>
+                        <br/>
+                      </td>
+					  	  </xsl:otherwise>
+					  </xsl:choose>
+                </tr>
+                <tr>
+                 <td width="5%" style="font-size: 8pt">
+                  <p style="font-size: 8pt">5.2</p>
+                 </td>
+                 <td colspan="2" align="left">
+                  <p style="font-size: 8pt">Parent Company's Dun &amp; Bradstreet Number </p>
+                 </td>
+                 <td colspan="1">
+                  <p style="font-size: 8pt">
+                   NA [
+                   <xsl:choose>
+                    <xsl:when test="../TRI:Facility/TRI:ParentDunBradstreetCode = 'NA'">
+                     <span class="answerText">X</span>
+                    </xsl:when>
+                   </xsl:choose>
+                   ]
+                  </p>
+                 </td>
+                 <td colspan="5">
+                  <xsl:choose>
+                   <xsl:when test="../TRI:Facility/TRI:ParentDunBradstreetCode != 'NA'">
+                    <span class="answerText">
+                     <xsl:value-of select="../TRI:Facility/TRI:ParentDunBradstreetCode"/>
+                    &#160;</span>
+                   </xsl:when>
+                  </xsl:choose>
+                  <br/>
+                 </td>
+                </tr>
+               </table>
+              </td>
+             </tr>
+            </table>
+           </center>
+           <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="1" style="font-size: 8pt" border="0">
+            <tr>
+             <td width="60%">
+              <p style="font-size: 8pt">
+              	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+               		EPA Form 9350-2 (Rev. <xsl:value-of select="$RevisionDateFormA"/>) - Previous editions are obsolete.
+               	</xsl:if>
+              </p>
+             </td>
+             <td width="30%">
+              <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+             </td>
+            </tr>
+           </table>
+
+           <!-- Start Form A Page Two -->
+          <xsl:for-each select="//TRI:Report[TRI:ReportType/TRI:ReportTypeCode = current()/TRI:ReportType/TRI:ReportTypeCode
+                                                         and concat(TRI:TechnicalContactNameText/sc:IndividualFullName, 'xx') = concat(current()/TRI:TechnicalContactNameText/sc:IndividualFullName, 'xx')
+                                                         and concat(TRI:TechnicalContactPhoneText, 'xx') = concat(current()/TRI:TechnicalContactPhoneText, 'xx')
+                                                         and concat(TRI:TechnicalContactEmailAddressText, 'xx') = concat(current()/TRI:TechnicalContactEmailAddressText, 'xx')
+                                                         and concat(TRI:PublicContactNameText/sc:IndividualFullName, 'xx') = concat(current()/TRI:PublicContactNameText/sc:IndividualFullName, 'xx')
+                                                         and concat(TRI:PublicContactPhoneText, 'xx') = concat(current()/TRI:PublicContactPhoneText, 'xx')
+                                                         and concat(TRI:PublicContactEmailAddressText, 'xx') = concat(current()/TRI:PublicContactEmailAddressText, 'xx')
+                                                         and sc:RevisionIndicator = current()/sc:RevisionIndicator
+                                                         and concat(TRI:ChemicalReportRevisionCode[1], 'xx') = concat(current()/TRI:ChemicalReportRevisionCode[1], 'xx')
+                                                         and concat(TRI:ChemicalReportRevisionCode[2], 'xx') = concat(current()/TRI:ChemicalReportRevisionCode[2], 'xx')
+                                                         and concat(TRI:ChemicalReportWithdrawalCode[1], 'xx') = concat(current()/TRI:ChemicalReportWithdrawalCode[1], 'xx')
+                                                         and concat(TRI:ChemicalReportWithdrawalCode[2], 'xx') = concat(current()/TRI:ChemicalReportWithdrawalCode[2], 'xx')
+                                                         and ../TRI:Facility = current()/../TRI:Facility
+                                                         ]">
+            <xsl:choose>
+            <xsl:when test="(position() - 1) mod 4 = 0">
+           <p style="page-break-before: always">&#160;</p>
+           <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+             <td width="60%">
+              <p style="font-size: 8pt">
+               <xsl:call-template name="FormAPage2Links">
+                  <xsl:with-param name="reportID"><xsl:value-of select="$formID"/></xsl:with-param>
+                  <xsl:with-param name="lastPosition"><xsl:value-of select="last()"/></xsl:with-param>
+                  <xsl:with-param name="currentPosition">4</xsl:with-param>
+               </xsl:call-template>
+               	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	               IMPORTANT: Read instructions before completing form; type or use fill-and-print form
+	            </xsl:if>
+              </p>
+             </td>
+             <td width="10%">
+
+             </td>
+            </tr>
+           </table>
+
+           <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt">
+            <tr>
+             <td colspan="2">
+              <table summary="table used for layout purposes" width="100%" style="font-size: 10pt" cellspacing="0" cellpadding="1">
+               <tr>
+                <td width="80%" align="center" style="font-size: 9pt">
+                  <span style="font-weight:bold">EPA FORM A</span>
+                  <br/>
+                  <span style="font-weight:bold">PART II. CHEMICAL IDENTIFICATION</span>
+                  <br/>
+                  <p style="font-size: 8pt">
+                   <xsl:choose>
+                    <xsl:when test="TRI:SubmissionReportingYear = '2005'">
+                        Do not use this form for reporting PBT chemicals including Dioxin and Dioxin-like Compounds*
+                    </xsl:when>
+                    <xsl:otherwise>
+                        Do not use this form for reporting Dioxin and Dioxin-like Compounds*</xsl:otherwise>
+                   </xsl:choose>
+                  </p>
+                </td>
+               </tr>
+              </table>
+             </td>
+             <td>TRI Facility ID Number
+               <hr />
+               <span class="answerText">
+                <xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/>
+               &#160;</span>
+             </td>
+            </tr>
+           </table>
+           </xsl:when>
+           </xsl:choose>
+
+           <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt">
+            <tr>
+             <td colspan="2">
+              <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0" cellpadding="1">
+               <tr>
+                <td align="left" width="75%">
+                 <p style="font-size: 7pt">SECTION 1. TOXIC CHEMICAL IDENTITY</p>
+                </td>
+                <td align="right">
+                 <p style="font-size: 7pt">Report <span class="smallAnswer"><xsl:value-of  select="position()"/></span> of <span class="smallAnswer"><xsl:value-of  select="last()"/></span></p>
+                </td>
+               </tr>
+              </table>
+             </td>
+            </tr>
+              <xsl:for-each select="TRI:ChemicalIdentification">
+               <tr>
+                <td align="center" width="5%">
+                 <p style="font-size: 7pt">1.1</p>
+                </td>
+                <td width="95%" style="font-size: 7pt">
+                  CAS Number (Important: Enter only one number as it appears on the
+                  Section 313 list. Enter category code if reporting a chemical
+                  category.)
+                  <hr/>
+                  <span style="color: blue;text-indent: 5em;font-weight:bold">
+                   <xsl:value-of select="sc:CASNumber"/>
+                  &#160;</span>
+                </td>
+               </tr>
+               <tr>
+                <td align="center" width="5%">
+                 <p style="font-family: arial;font-size: 7pt">1.2</p>
+                </td>
+                <td style="font-size: 7pt">
+                  Toxic Chemical or Chemical Category Name (Important: Enter only one
+                  name exactly as it appears on the Section 313 list.)
+                  <hr/>
+                  <span style="color: blue;font-size: 7pt;text-indent: 5em;font-weight:bold">
+                   <xsl:value-of select="TRI:ChemicalNameText"/>
+                  &#160;</span>
+                </td>
+               </tr>
+              </xsl:for-each>
+              <tr>
+               <td align="center" width="5%">
+                <p style=" font-family: arial;font-size: 7pt">1.3</p>
+               </td>
+               <td style="font-size: 7pt">
+                 Generic Chemical Name (Important: Complete only if Part I, Section
+                 2.1 is checked "Yes". Generic Name must be structurally descriptive).
+                 <hr/>
+                 <span style="color: blue;font-size: 7pt;text-indent: 5em;font-weight:bold">NA</span>
+               </td>
+              </tr>
+              <tr>
+               <td colspan="2">
+                <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" cellspacing="0"
+                       cellpadding="1">
+                 <tr>
+                  <td align="left" colspan="2">
+                   <p style="font-family: arial;font-size: 8pt">
+                      SECTION 2. MIXTURE COMPONENT IDENTITY (Important: DO NOT complete this section if you completed Section 1.)
+                   </p>
+                  </td>
+                 </tr>
+                </table>
+               </td>
+              </tr>
+              <tr>
+               <td align="center" width="5%">
+                <p style="font-family: arial;font-size: 7pt">2.1</p>
+               </td>
+               <td style="font-size: 8pt">
+                 Generic Chemical Name Provided by Supplier (Important: Maximum of 70
+                 characters, including numbers, spaces, and punctuation.)
+                 <hr/>
+                 <b style="color: blue;font-size: 9pt; font-family:arial">
+                  <xsl:value-of select="TRI:ChemicalIdentification/TRI:ChemicalMixtureNameText"/>
+                 </b>
+                 <br/>
+               </td>
+              </tr>
+             </table>
+             <br />
+        <xsl:choose>
+        <xsl:when test="((position() mod 4 = 0) or (position() = last()))">
+
+               <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+                <tr>
+                 <td colspan="2" align="center">
+                  <p style="font-family: arial;font-size: 7pt">
+                   <xsl:choose>
+                    <xsl:when test="TRI:SubmissionReportingYear = '2005'">
+                        *See the TRI Reporting Forms and Instructions Manual for the list of PBT
+                         Chemicals(including Dioxin and Dioxin-like Compounds)
+                    </xsl:when>
+                    <xsl:otherwise>*See the TRI Reporting Forms and Instructions
+                                   Manual for the TRI-listed Dioxin and Dioxin-like
+                                   Compounds</xsl:otherwise>
+                   </xsl:choose>
+                  </p>
+                 </td>
+                </tr>
+                <tr>
+                 <td width="60%">
+                  <p style="font-family: arial;font-size: 7pt">
+                  	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+                   		EPA Form 9350-2 (Rev. <xsl:value-of select="$RevisionDateFormA"/>) - Previous editions are obsolete.
+                   	</xsl:if>
+                  </p>
+                 </td>
+                 <td width="40%" align="right" style="font-size: 7pt">
+                  <p style="font-family: arial;font-size: 7pt">&#160;</p>
+                 </td>
+                </tr>
+               </table>
+            </xsl:when>
+          </xsl:choose>
+           <!-- End Form A Page Two -->
+           </xsl:for-each>
+        </xsl:if>
+      </xsl:otherwise>
+      </xsl:choose>
+      </xsl:for-each>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="ScheduleOnePageOne">
+    <xsl:param name="baseStreamID" />
+    <xsl:param name="formID" />
+
+    <xsl:param name="OMBNumberSchedule1" />
+    <xsl:param name="ApprovalDateSchedule1" />
+
+    <xsl:param name="fugitiveRelease" select="TRI:OnsiteReleaseQuantity[TRI:EnvironmentalMediumCode = 'AIR FUG' and $baseStreamID = 0]" />
+    <xsl:param name="stackRelease" select="TRI:OnsiteReleaseQuantity[TRI:EnvironmentalMediumCode = 'AIR STACK' and $baseStreamID = 0]" />
+    <xsl:param name="firstStreamRelease" select="TRI:OnsiteReleaseQuantity[TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 1]" />
+    <xsl:param name="secondStreamRelease" select="TRI:OnsiteReleaseQuantity[TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 2]" />
+    <xsl:param name="thirdStreamRelease" select="TRI:OnsiteReleaseQuantity[TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 3]" />
+
+    <div class="landscapeArea">
+        <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 8pt" border="0">
+              <tr>
+                <td width="30%">
+                	<xsl:if test="TRI:SubmissionReportingYear &lt; '2014' ">
+	                  Form Approved OMB Number:<span class="smallAnswer"><xsl:value-of select="$OMBNumberSchedule1" />&#160;</span><br />
+    	              Approval Expires: <span class="smallAnswer"><xsl:value-of select="$ApprovalDateSchedule1" />&#160;</span>
+    	            </xsl:if>
+                </td>
+                <td width="10%">
+                  <p style="font-size: 8pt"><b>Page 1 of 4</b></p>
+                </td>
+              </tr>
+            </table>
+
+          <center>
+            <table summary="table used for layout purposes" border="1" cellspacing="0" cellpadding="1" width="100%" style="font-size: 8pt;">
+
+              <tr>
+                <td colspan="13" align="center">
+                  <table summary="table used for layout purposes" width="100%" style="font-size: 8pt" border="0" cellspacing="0" cellpadding="0" frame="void">
+                    <tr>
+                      <td style="font-size: 10pt"><b> EPA </b></td>
+                      <td align="center" style="font-size: 14pt"><b>FORM R Schedule 1</b></td>
+                      <td><p style="font-size: 8pt">TRI Facility ID Number:</p></td>
+                    </tr>
+                    <tr>
+                      <td><p style="font-size: 8pt">United States<br />Environmental Protection<br />Agency</p></td>
+                      <td align="center"><p style="font-size: 14pt"><b>PART II.  CHEMICAL-SPECIFIC INFORMATION (continued)</b></p></td>
+                      <td class="answerText"><xsl:value-of select="../TRI:Facility/TRI:FacilityIdentifier"/></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+
+              <tr>
+                <td align="left" colspan="13" style="font-size: 8pt">
+                  <p style="font-size: 9pt"><b>Section 5. Quantity Of Dioxin And Dioxin-Like Compounds Entering Each Environmental Medium On-site</b></p>
+                </td>
+              </tr>
+
+              <tr>
+                <td colspan="2" rowspan="2" style="background-color: gray">&#160;</td>
+                <td align="center" style="font-size: 8pt"><b>5.1</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="$fugitiveRelease/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                    X
+                  </xsl:if>&#160;
+                </td>
+
+                <td align="center" style="font-size: 8pt"><b>5.2</b></td>
+                <td align="center" style="font-size: 8pt">NA</td>
+                <td align="center" class="smallAnswer">
+                  <xsl:if test="$stackRelease/TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+                    X
+                  </xsl:if>&#160;
+                </td>
+
+                <td align="center" colspan="5" style="font-size: 8pt">
+                  <b>5.3</b>&#160;&#160;&#160;Discharges to receiving streams or water
+                  bodies&#160;&#160;&#160;&#160;&#160;&#160;
+				  <xsl:choose>
+					<xsl:when test="TRI:SubmissionReportingYear &lt; '2011'">
+					  &#160;
+					</xsl:when>
+					<xsl:otherwise>
+					  NA&#160;&#160;&#160;
+                  [&#160;<xsl:for-each select="TRI:OnsiteReleaseQuantity">
+					  <xsl:choose>
+					    <xsl:when test="TRI:EnvironmentalMediumCode = 'WATER'">
+					      <xsl:choose>
+					        <xsl:when test="TRI:OnsiteWasteQuantity/TRI:WasteQuantityNAIndicator = 'true'">
+					          <span class="smallAnswer">X</span>
+					        </xsl:when>
+					      </xsl:choose>
+					    </xsl:when>
+					  </xsl:choose>
+					</xsl:for-each>&#160;]
+					</xsl:otherwise>
+				  </xsl:choose>
+                </td>
+              </tr>
+              <tr>
+                <td align="center" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Fugitive or non-point air emissions</p>
+                </td>
+
+                <td align="center" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">Stack or point air emissions</p>
+                </td>
+
+                <td align="center" colspan="3" style="font-size: 8pt">
+                  <p style="font-size: 8pt">5.3.<xsl:value-of select="$baseStreamID + 1" />&#160;
+                    <xsl:value-of select="$firstStreamRelease/TRI:WaterStream/TRI:StreamName" />
+                  </p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">5.3.<xsl:value-of select="$baseStreamID + 2" />&#160;
+                    <xsl:value-of select="$secondStreamRelease/TRI:WaterStream/TRI:StreamName" />
+                  </p>
+                </td>
+                <td align="center" style="font-size: 8pt">
+                  <p style="font-size: 8pt">5.3.<xsl:value-of select="$baseStreamID + 3" />&#160;
+                    <xsl:value-of select="$thirdStreamRelease/TRI:WaterStream/TRI:StreamName" />
+                  </p>
+                </td>
+              </tr>
+
+            <xsl:call-template name="ScheduleOnePageOneRow">
+              <xsl:with-param name="baseStreamID"><xsl:value-of select="$baseStreamID" /></xsl:with-param>
+            </xsl:call-template>
+
+              <tr>
+                <td align="left" colspan="13" style="font-size: 8pt">
+                  <p style="font-size: 8pt">
+                    If additional pages of Section 6.1 or 6.2 are attached, indicate the total number of pages in this box&#160;&#160;
+                    <span style="border: 1px solid black; padding: 2px; text-align:center; width: 25px;">
+                      <xsl:if test="count(TRI:OnsiteReleaseQuantity/TRI:WaterStream) &gt; 3">
+                          <span class="answerText"><xsl:value-of select="(floor(count(TRI:OnsiteReleaseQuantity/TRI:WaterStream) div 3)) + 1" />&#160;</span>
+                      </xsl:if>&#160;
+                    &#160;</span>
+                    <br />
+                    and indicate the Section 6.1 or 6.2 page number in this box&#160;&#160;
+                    <span style="border: 1px solid black; padding: 2px; text-align:center; width: 25px;">
+                      <xsl:if test="count(TRI:OnsiteReleaseQuantity/TRI:WaterStream) &gt; 3">
+                          <span class="answerText"><xsl:value-of select="($baseStreamID div 3) + 1" />&#160;</span>
+                      </xsl:if>&#160;
+                    &#160;</span>&#160;
+                    (Example: 1,2,3, etc.)
+                  </p>
+                </td>
+              </tr>
+
+            </table>
+          </center>
+
+          <table summary="table used for layout purposes" width="100%" cellspacing="0" cellpadding="0" style="font-size: 7pt" border="0">
+            <tr>
+              <td width="60%">
+                <p style="font-size: 8pt">
+                  EPA Form 9350-3
+                </p>
+              </td>
+              <td width="30%">
+                <p style="font-size: 8pt">Printed using TRI-MEweb</p>
+              </td>
+            </tr>
+          </table>
+          </div>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageOneRow">
+        <xsl:param name="baseStreamID" />
+        <xsl:param name="i">1</xsl:param>
+        <xsl:param name="teqNodeName"><xsl:value-of select="concat('TRI:ToxicEquivalency',$i,'Value')" /></xsl:param>
+        <xsl:param name="fugitiveTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'AIR FUG' and $baseStreamID = 0]" />
+        <xsl:param name="stackTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'AIR STACK' and $baseStreamID = 0]" />
+        <xsl:param name="firstStreamTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 1]" />
+        <xsl:param name="secondStreamTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 2]" />
+        <xsl:param name="thirdStreamTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:WaterStream/TRI:WaterSequenceNumber = $baseStreamID + 3]" />
+
+        <xsl:if test="$i &lt; 18">
+        <tr>
+          <xsl:if test="$i = 1">
+            <td align="center" rowspan="17" style="font-size: 8pt">
+              <p style="font-size: 8pt"><b>D. Mass<br />(grams)<br />of<br />each<br />compound<br />in<br />the<br />category<br />(1-17)</b></p>
+            </td>
+          </xsl:if>
+
+            <td align="center" style="font-size: 8pt">
+              <xsl:value-of select="$i" />
+            </td>
+            <td align="center" colspan="3" class="teqAnswer">
+                <xsl:value-of select="$fugitiveTEQ/*[name() = $teqNodeName]" /><br />
+            </td>
+            <td align="center" colspan="3" class="teqAnswer">
+                <xsl:value-of select="$stackTEQ/*[name() = $teqNodeName]" /><br />
+            </td>
+            <td align="center" colspan="3" class="teqAnswer">
+                <xsl:value-of select="$firstStreamTEQ/*[name() = $teqNodeName]" /><br />
+            </td>
+            <td align="center" class="teqAnswer">
+                <xsl:value-of select="$secondStreamTEQ/*[name() = $teqNodeName]" /><br />
+            </td>
+            <td align="center" class="teqAnswer">
+                <xsl:value-of select="$thirdStreamTEQ/*[name() = $teqNodeName]" /><br />
+            </td>
+          </tr>
+
+          <xsl:call-template name="ScheduleOnePageOneRow">
+              <xsl:with-param name="i"><xsl:value-of select="$i + 1" /></xsl:with-param>
+              <xsl:with-param name="baseStreamID"><xsl:value-of select="$baseStreamID" /></xsl:with-param>
+          </xsl:call-template>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageTwoRow">
+        <xsl:param name="i">1</xsl:param>
+        <xsl:param name="teqNodeName"><xsl:value-of select="concat('TRI:ToxicEquivalency',$i,'Value')" /></xsl:param>
+        <xsl:param name="uicClass1TEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'UNINJ I']" />
+        <xsl:param name="uicClass25TEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'UNINJ IIV']" />
+        <xsl:param name="rcraLandfillTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'RCRA C']" />
+        <xsl:param name="otherLandfillTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'OTH LANDF']" />
+        <xsl:param name="farmingTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'LAND TREA']" />
+        <xsl:param name="rcraSITEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'SI 5.5.3A']" />
+        <xsl:param name="otherSITEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'SI 5.5.3B']" />
+        <xsl:param name="otherTEQ" select="TRI:OnsiteReleaseQuantity/TRI:OnsiteWasteQuantity/TRI:ToxicEquivalencyIdentification[../../TRI:EnvironmentalMediumCode = 'OTH DISP']" />
+
+        <xsl:if test="$i &lt; 18">
+            <tr>
+              <xsl:if test="$i = 1">
+              <td align="center" rowspan="17" style="font-size: 8pt">
+                <b>C. Mass<br />(grams)<br />of<br />each<br />compound<br />in<br />the<br />category<br />(1-17)</b>
+              </td>
+              </xsl:if>
+              <td align="center" style="font-size: 8pt">
+                <xsl:value-of select="$i" />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$uicClass1TEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$uicClass25TEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$rcraLandfillTEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$otherLandfillTEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$farmingTEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$rcraSITEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$otherSITEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+              <td colspan="3" align="center" class="teqAnswer">
+                <xsl:value-of select="$otherTEQ/*[name() = $teqNodeName]" /><br />
+              </td>
+            </tr>
+
+            <xsl:call-template name="ScheduleOnePageTwoRow">
+              <xsl:with-param name="i"><xsl:value-of select="$i + 1" /></xsl:with-param>
+            </xsl:call-template>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageThreeRowBlank">
+        <xsl:param name="i">1</xsl:param>
+
+        <tr>
+          <td colspan="2" align="left" style="font-size: 9pt"><b>6.2_<xsl:value-of select="$i" /></b></td>
+          <td colspan="16" align="left" style="font-size: 8pt"><b>. Mass (grams) of each compound in the Category (1-17)</b></td>
+        </tr>
+
+        <xsl:call-template name="ScheduleOnePageThreeDetailBlank"><xsl:with-param name="j">1</xsl:with-param></xsl:call-template>
+        <xsl:call-template name="ScheduleOnePageThreeDetailBlank"><xsl:with-param name="j">2</xsl:with-param></xsl:call-template>
+        <xsl:call-template name="ScheduleOnePageThreeDetailBlank"><xsl:with-param name="j">3</xsl:with-param></xsl:call-template>
+        <xsl:call-template name="ScheduleOnePageThreeDetailBlank"><xsl:with-param name="j">4</xsl:with-param></xsl:call-template>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageThreeDetailBlank">
+        <xsl:param name="j">1</xsl:param>
+
+        <tr>
+          <td align="center" colspan="2" style="font-size: 8pt">
+              <b><xsl:value-of select="$j" />.</b>
+          </td>
+          <td style="font-size: 8pt">1</td><td>&#160;</td>
+          <td style="font-size: 8pt">2</td><td>&#160;</td>
+          <td style="font-size: 8pt">3</td><td>&#160;</td>
+          <td style="font-size: 8pt">4</td><td>&#160;</td>
+          <td style="font-size: 8pt">5</td><td>&#160;</td>
+          <td style="font-size: 8pt">6</td><td>&#160;</td>
+          <td style="font-size: 8pt">7</td><td>&#160;</td>
+          <td style="font-size: 8pt">8</td><td>&#160;</td>
+        </tr>
+        <tr>
+          <td style="font-size: 8pt">9</td><td>&#160;</td>
+          <td style="font-size: 8pt">10</td><td>&#160;</td>
+          <td style="font-size: 8pt">11</td><td>&#160;</td>
+          <td style="font-size: 8pt">12</td><td>&#160;</td>
+          <td style="font-size: 8pt">13</td><td>&#160;</td>
+          <td style="font-size: 8pt">14</td><td>&#160;</td>
+          <td style="font-size: 8pt">15</td><td>&#160;</td>
+          <td style="font-size: 8pt">16</td><td>&#160;</td>
+          <td style="font-size: 8pt">17</td><td>&#160;</td>
+        </tr>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageThreeRow">
+        <tr>
+          <td align="center" colspan="2" style="font-size: 8pt">
+              <b><xsl:value-of select="TRI:TransferSequenceNumber + 1" />.</b>
+          </td>
+          <td style="font-size: 8pt">1</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency1Value" />&#160;</td>
+
+          <td style="font-size: 8pt">2</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency2Value" />&#160;</td>
+
+          <td style="font-size: 8pt">3</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency3Value" />&#160;</td>
+
+          <td style="font-size: 8pt">4</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency4Value" />&#160;</td>
+
+          <td style="font-size: 8pt">5</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency5Value" />&#160;</td>
+
+          <td style="font-size: 8pt">6</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency6Value" />&#160;</td>
+
+          <td style="font-size: 8pt">7</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency7Value" />&#160;</td>
+
+          <td style="font-size: 8pt">8</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency8Value" />&#160;</td>
+        </tr>
+
+        <tr>
+          <td style="font-size: 8pt">9</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency9Value" />&#160;</td>
+
+          <td style="font-size: 8pt">10</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency10Value" />&#160;</td>
+
+          <td style="font-size: 8pt">11</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency11Value" />&#160;</td>
+
+          <td style="font-size: 8pt">12</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency12Value" />&#160;</td>
+
+          <td style="font-size: 8pt">13</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency13Value" />&#160;</td>
+
+          <td style="font-size: 8pt">14</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency14Value" />&#160;</td>
+
+          <td style="font-size: 8pt">15</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency15Value" />&#160;</td>
+
+          <td style="font-size: 8pt">16</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency16Value" />&#160;</td>
+
+          <td style="font-size: 8pt">17</td>
+          <td align="center" class="teqAnswer"><xsl:value-of select="TRI:TransferWasteQuantity/TRI:ToxicEquivalencyIdentification/TRI:ToxicEquivalency17Value" />&#160;</td>
+        </tr>
+    </xsl:template>
+
+    <xsl:template name="ScheduleOnePageFourRow">
+      <xsl:param name="i">1</xsl:param>
+      <xsl:param name="teqNodeName"><xsl:value-of select="concat('TRI:ToxicEquivalency',$i,'Value')" /></xsl:param>
+
+      <xsl:if test="$i &lt; 18">
+        <tr>
+          <xsl:if test="$i = 1">
+          <td rowspan="17" align="center" style="font-size: 8pt">
+            <b>F. Mass<br />(grams)<br />of<br />each<br />compound<br />in<br />the<br />category<br />(1-17)</b>
+          </td>
+          </xsl:if>
+
+          <td align="center" style="font-size: 8pt"><xsl:value-of select="$i" /></td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OnsiteUICDisposalQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OnsiteOtherDisposalQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OffsiteUICDisposalQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OffsiteOtherDisposalQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OnsiteEnergyRecoveryQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OffsiteEnergyRecoveryQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OnsiteRecycledQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OffsiteRecycledQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OnsiteTreatedQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:OffsiteTreatedQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+          <td align="center" class="teqAnswer">
+            <xsl:value-of select="TRI:SourceReductionQuantity/TRI:ToxicEquivalencyIdentification/*[name() = $teqNodeName]" /><br />
+          </td>
+        </tr>
+
+        <xsl:call-template name="ScheduleOnePageFourRow">
+          <xsl:with-param name="i"><xsl:value-of select="$i + 1" /></xsl:with-param>
+        </xsl:call-template>
+
+      </xsl:if>
+    </xsl:template>
+
+    <xsl:template name="FormAPage2Links">
+      <xsl:param name="lastPosition">0</xsl:param>
+      <xsl:param name="currentPosition">0</xsl:param>
+      <xsl:param name="reportID">0</xsl:param>
+      <xsl:if test="$currentPosition &lt;= $lastPosition and $lastPosition &gt; 4">
+          <xsl:call-template name="FormAPage2Links">
+            <xsl:with-param name="lastPosition"><xsl:value-of select="$lastPosition"/></xsl:with-param>
+            <xsl:with-param name="currentPosition"><xsl:value-of select="$currentPosition + 1"/></xsl:with-param>
+            <xsl:with-param name="reportID"><xsl:value-of select="$reportID"/></xsl:with-param>
+          </xsl:call-template>
+      </xsl:if>
+    </xsl:template>
+</xsl:stylesheet>
diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
index c479ab1..1ae853d 100644
--- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
@@ -29,6 +29,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.StringReader;
@@ -73,7 +74,7 @@
  * @run testng/othervm -DrunSecMngr=true transform.TransformerTest
  * @run testng/othervm transform.TransformerTest
  * @summary Transformer Tests
- * @bug 6272879 6305029 6505031 8150704 8162598 8169772
+ * @bug 6272879 6305029 6505031 8150704 8162598 8169112 8169772
  */
 @Listeners({jaxp.library.FilePolicy.class})
 public class TransformerTest {
@@ -437,6 +438,27 @@
     }
 
     /**
+     * @bug 8169112
+     * @summary Test compilation of large xsl file with outlining.
+     *
+     * This test merely compiles a large xsl file and tests if its bytecode
+     * passes verification by invoking the transform() method for
+     * dummy content. The test succeeds if no Exception is thrown
+     */
+    @Test
+    public final void testBug8169112() throws FileNotFoundException,
+        TransformerException
+    {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        String xslFile = getClass().getResource("Bug8169112.xsl").toString();
+        Transformer t = tf.newTransformer(new StreamSource(xslFile));
+        String xmlIn = "<?xml version=\"1.0\"?><DOCROOT/>";
+        ByteArrayInputStream bis = new ByteArrayInputStream(xmlIn.getBytes());
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        t.transform(new StreamSource(bis), new StreamResult(bos));
+    }
+
+    /**
      * @bug 8169772
      * @summary Test transformation of DOM with null valued text node
      *
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 005ff37..8394046 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -394,3 +394,4 @@
 1461e3e07876ea61bd0a07355a43912c9b04022a jdk-9+146
 be37411855de5b76035bef6f1b0d90d8607f2205 jdk-9+147
 c8c9c334743caf8155c9809b6b4ac315d3a66476 jdk-9+148
+72554d319b474b3636c7d02fe3c110254d111b1a jdk-9+149
diff --git a/jaxws/THIRD_PARTY_README b/jaxws/THIRD_PARTY_README
deleted file mode 100644
index a93b35b..0000000
--- a/jaxws/THIRD_PARTY_README
+++ /dev/null
@@ -1,3605 +0,0 @@
-DO NOT TRANSLATE OR LOCALIZE.
------------------------------
-
-%% This notice is provided with respect to ASM Bytecode Manipulation 
-Framework v5.0, which may be included with JRE 8, and JDK 8, and 
-OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2011 France Télécom
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holders nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to BSDiff v4.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 2003-2005 Colin Percival
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CodeViewer 1.0, which may be
-included with JDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1999 by CoolServlets.com.
-
-Any errors or suggested improvements to this class can be reported as
-instructed on CoolServlets.com. We hope you enjoy this program... your
-comments will encourage further development!  This software is distributed
-under the terms of the BSD License.  Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-Neither name of CoolServlets.com nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Cryptix AES 3.2.0, which may be
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Cryptix General License
-
-Copyright (c) 1995-2005 The Cryptix Foundation Limited.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  1. Redistributions of source code must retain the copyright notice,
-     this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CUP Parser Generator for 
-Java 0.10k, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted, provided
-that the above copyright notice appear in all copies and that both the
-copyright notice and this permission notice and warranty disclaimer appear in
-supporting documentation, and that the names of the authors or their
-employers not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission.
-
-The authors and their employers disclaim all warranties with regard to
-this software, including all implied warranties of merchantability and fitness.
-In no event shall the authors or their employers be liable for any special,
-indirect or consequential damages or any damages whatsoever resulting from
-loss of use, data or profits, whether in an action of contract, negligence or
-other tortious action, arising out of or in connection with the use or
-performance of this software.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Document Object Model (DOM) Level 2
-& 3, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-W3C SOFTWARE NOTICE AND LICENSE
-
-http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
-
-This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license. By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following terms
-and conditions.
-
-Permission to copy, modify, and distribute this software and its
-documentation, with or without modification, for any purpose and without fee
-or royalty is hereby granted, provided that you include the following on ALL
-copies of the software and documentation or portions thereof, including
-modifications:
-
-   1.The full text of this NOTICE in a location viewable to users of the
-   redistributed or derivative work.
-
-   2.Any pre-existing intellectual property disclaimers, notices, or terms and
-   conditions. If none exist, the W3C Software Short Notice should be included
-   (hypertext is preferred, text is permitted) within the body of any
-   redistributed or derivative code.
-
-   3.Notice of any changes or modifications to the files, including the date
-   changes were made. (We recommend you provide URIs to the location from
-   which the code is derived.)
-
-THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
-THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
-COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
-in advertising or publicity pertaining to the software without specific,
-written prior permission. Title to copyright in this software and any
-associated documentation will at all times remain with copyright holders.
-
-____________________________________
-
-This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C, reflects
-that ERCIM is now a host of the W3C, includes references to this specific
-dated version of the license, and removes the ambiguous grant of "use".
-Otherwise, this version is the same as the previous version and is written so
-as to preserve the Free Software Foundation's assessment of GPL compatibility
-and OSI's certification under the Open Source Definition. Please see our
-Copyright FAQ for common questions about using materials from our site,
-including specific terms and conditions for packages like libwww, Amaya, and
-Jigsaw. Other questions about this notice can be directed to
-site-policy@w3.org.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Dynalink v0.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2009-2013, Attila Szegedi
-
-All rights reserved.Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following conditions are
-met:* Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.  * Redistributions in
-binary form must reproduce the above copyright notice,   this list of
-conditions and the following disclaimer in the documentation  and/or other
-materials provided with the distribution.  * Neither the name of Attila
-Szegedi nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Elliptic Curve Cryptography, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
-You are receiving a copy of the Elliptic Curve Cryptography library in source
-form with the JDK 8 and OpenJDK 8 source distributions, and as object code in
-the JRE 8 & JDK 8 runtimes.
-
-In the case of the JRE 8 & JDK 8 runtimes, the terms of the Oracle license do
-NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
-following license, separately from Oracle's JDK & JRE.  If you do not wish to
-install the Elliptic Curve Cryptography library, you may delete the library
-named libsunec.so (on Solaris and Linux systems) or sunec.dll (on Windows
-systems) from the JRE bin directory reserved for native libraries.
-
-
---- begin of LICENSE ---
-
-                  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!
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to  ECMAScript Language
-Specification ECMA-262 Edition 5.1 which may be included with 
-JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright notice
-Copyright © 2011 Ecma International
-Ecma International
-Rue du Rhone 114
-CH-1204 Geneva
-Tel: +41 22 849 6000
-Fax: +41 22 849 6001
-Web: http://www.ecma-international.org
-
-This document and possible translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it or assist
-in its implementation may be prepared, copied, published, and distributed, in
-whole or in part, without restriction of any kind, provided that the above
-copyright notice and this section are included on all such copies and derivative
-works. However, this document itself may not be modified in any way, including
-by removing the copyright notice or references to Ecma International, except as
-needed for the purpose of developing any document or deliverable produced by
-Ecma International (in which case the rules applied to copyrights must be
-followed) or as required to translate it into languages other than English. The
-limited permissions granted above are perpetual and will not be revoked by Ecma
-International or its successors or assigns. This document and the information
-contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL
-DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
-WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
-RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
-PURPOSE." Software License
-
-All Software contained in this document ("Software)" is protected by copyright
-and is being made available under the "BSD License", included below. This
-Software may be subject to third party rights (rights from parties other than
-Ecma International), including patent rights, and no licenses under such third
-party rights are granted under this license even if the third party concerned is
-a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS
-AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
-INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO
-IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the authors nor Ecma International may be used to endorse
-or promote products derived from this software without specific prior written
-permission.
-
-THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Dynalink library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Copyright (c) 2009-2013, Attila Szegedi
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the copyright holder nor the names of
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Joni library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to FontConfig 2.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 source distributions on
-Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright © 2001,2003 Keith Packard
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation, and that
-the name of Keith Packard not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior permission.
-Keith Packard makes no representations about the suitability of this software
-for any purpose.  It is provided "as is" without express or implied warranty.
-
-KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IAIK PKCS#11 Wrapper, 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-IAIK PKCS#11 Wrapper License
-
-Copyright (c) 2002 Graz University of Technology. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-   "This product includes software developed by IAIK of Graz University of
-    Technology."
-
-   Alternately, this acknowledgment may appear in the software itself, if and
-   wherever such third-party acknowledgments normally appear.
-
-4. The names "Graz University of Technology" and "IAIK of Graz University of
-   Technology" must not be used to endorse or promote products derived from this
-   software without prior written permission.
-
-5. Products derived from this software may not be called "IAIK PKCS Wrapper",
-   nor may "IAIK" appear in their name, without prior written permission of
-   Graz University of Technology.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to ICU4C 4.0.1 and ICU4J 4.4, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 1995-2010 International Business Machines Corporation and others 
-
-All rights reserved. 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice appear
-in all copies of the Software and that both the above copyright notice(s) and
-this permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
-All trademarks and registered trademarks mentioned herein are the property of
-their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IJG JPEG 6b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library.  If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it.  This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Joni v1.1.9, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JOpt-Simple v3.0,  which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (c) 2004-2009 Paul R. Holser, Jr.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JSON, which may be included 
-with JRE 8 & JDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality, which 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- (C) Copyright IBM Corp. 1999 All Rights Reserved.
- Copyright 1997 The Open Group Research Institute. All rights reserved.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality from 
-FundsXpress, INC., which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (C) 1998 by the FundsXpress, INC.
-
- All rights reserved.
-
- Export of this software from the United States of America may require
- a specific license from the United States Government.  It is the
- responsibility of any person or organization contemplating export to
- obtain such a license before exporting.
-
- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- distribute this software and its documentation for any purpose and
- without fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation, and that
- the name of FundsXpress. not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.  FundsXpress makes no representations about the suitability of
- this software for any purpose.  It is provided "as is" without express
- or implied warranty.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kronos OpenGL headers, which may be 
-included with JDK 8 and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Copyright (c) 2007 The Khronos Group Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and/or associated documentation files (the "Materials"), to
- deal in the Materials without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Materials, and to permit persons to whom the Materials are
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Materials.
-
- THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- MATERIALS.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions Copyright Eastman Kodak Company 1992
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libpng 1.5.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This copy of the libpng notices is provided for your convenience.  In case of
-any discrepancy between this copy and the notices in the file png.h that is
-included in the libpng distribution, the latter shall prevail.
-
-COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
-
-If you modify libpng you may insert additional notices immediately following
-this sentence.
-
-This code is released under the libpng license.
-
-libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
-Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.2.5
-with the following individual added to the list of Contributing Authors
-
-   Cosmin Truta
-
-libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
-Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.0.6
-with the following individuals added to the list of Contributing Authors
-
-   Simon-Pierre Cadieux
-   Eric S. Raymond
-   Gilles Vollant
-
-and with the following additions to the disclaimer:
-
-   There is no warranty against interference with your enjoyment of the
-   library or against infringement.  There is no warranty that our
-   efforts or the library will fulfill any of your particular purposes
-   or needs.  This library is provided with all faults, and the entire
-   risk of satisfactory quality, performance, accuracy, and effort is with
-   the user.
-
-libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
-Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-0.96,
-with the following individuals added to the list of Contributing Authors:
-
-   Tom Lane
-   Glenn Randers-Pehrson
-   Willem van Schaik
-
-libpng versions 0.89, June 1996, through 0.96, May 1997, are
-Copyright (c) 1996, 1997 Andreas Dilger
-Distributed according to the same disclaimer and license as libpng-0.88,
-with the following individuals added to the list of Contributing Authors:
-
-   John Bowler
-   Kevin Bracey
-   Sam Bushell
-   Magnus Holmgren
-   Greg Roelofs
-   Tom Tanner
-
-libpng versions 0.5, May 1995, through 0.88, January 1996, are
-Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-
-For the purposes of this copyright and license, "Contributing Authors"
-is defined as the following set of individuals:
-
-   Andreas Dilger
-   Dave Martindale
-   Guy Eric Schalnat
-   Paul Schmidt
-   Tim Wegner
-
-The PNG Reference Library is supplied "AS IS".  The Contributing Authors
-and Group 42, Inc. disclaim all warranties, expressed or implied,
-including, without limitation, the warranties of merchantability and of
-fitness for any purpose.  The Contributing Authors and Group 42, Inc.
-assume no liability for direct, indirect, incidental, special, exemplary,
-or consequential damages, which may result from the use of the PNG
-Reference Library, even if advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-source code, or portions hereof, for any purpose, without fee, subject
-to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-
-2. Altered versions must be plainly marked as such and must not
-   be misrepresented as being the original source.
-
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The Contributing Authors and Group 42, Inc. specifically permit, without
-fee, and encourage the use of this source code as a component to
-supporting the PNG file format in commercial products.  If you use this
-source code in a product, acknowledgment is not required but would be
-appreciated.
-
-
-A "png_get_copyright" function is available, for convenient use in "about"
-boxes and the like:
-
-   printf("%s",png_get_copyright(NULL));
-
-Also, the PNG logo (in PNG format, of course) is supplied in the
-files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
-
-Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
-certification mark of the Open Source Initiative.
-
-Glenn Randers-Pehrson
-glennrp at users.sourceforge.net
-July 7, 2011
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libungif 4.1.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Little CMS 2.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Little CMS
-Copyright (c) 1998-2010 Marti Maria Saguer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Lucida is a registered trademark or trademark of Bigelow & Holmes in the
-U.S. and other countries.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mesa 3D Graphics Library v4.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Mesa 3-D graphics library
- Version:  4.1
-
- Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mozilla Network Security
-Services (NSS), which is supplied with the JDK test suite in the OpenJDK
-source code repository. It is licensed under Mozilla Public License (MPL),
-version 2.0.
-
-The NSS libraries are supplied in executable form, built from unmodified
-NSS source code labeled with the "NSS_3.13.1_RTM" release tag.
-
-The NSS source code is available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/src
-
-The NSS libraries are available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/lib
-
---- begin of LICENSE ---
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PC/SC Lite for Suse Linux v.1.1.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
-Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by: 
-      David Corcoran <corcoran@linuxnet.com>
-      http://www.linuxnet.com (MUSCLE)
-4. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-Changes to this license can be made only by the copyright author with 
-explicit written consent.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PorterStemmer v4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-See: http://tartarus.org/~martin/PorterStemmer
-
-The software is completely free for any purpose, unless notes at the head of
-the program text indicates otherwise (which is rare). In any case, the notes
-about licensing are never more restrictive than the BSD License.
-
-In every case where the software is not written by me (Martin Porter), this
-licensing arrangement has been endorsed by the contributor, and it is
-therefore unnecessary to ask the contributor again to confirm it.
-
-I have not asked any contributors (or their employers, if they have them) for
-proofs that they have the right to distribute their software in this way.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Relax NG Object/Parser v.20050510,
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions: The above copyright
-notice and this permission notice shall be included in all copies or
-substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to RelaxNGCC v1.12, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2003 Daisuke Okajima and Kohsuke Kawaguchi.  
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-    "This product includes software developed by Daisuke Okajima
-    and Kohsuke Kawaguchi (http://relaxngcc.sf.net/)."
-
-Alternately, this acknowledgment may appear in the software itself, if and
-wherever such third-party acknowledgments normally appear.
-
-4. The names of the copyright holders must not be used to endorse or promote
-   products derived from this software without prior written permission. For
-   written permission, please contact the copyright holders.
-
-5. Products derived from this software may not be called "RELAXNGCC", nor may
-  "RELAXNGCC" appear in their name, without prior written permission of the
-  copyright holders.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE APACHE
-SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SAX 2.0.1, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- SAX is free!
-
- In fact, it's not possible to own a license to SAX, since it's been placed in
- the public domain.
-
- No Warranty
-
- Because SAX is released to the public domain, there is no warranty for the
- design or for the software implementation, to the extent permitted by
- applicable law. Except when otherwise stated in writing the copyright holders
- and/or other parties provide SAX "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 SAX is with you. Should SAX prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- 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
- SAX, be liable to you for damages, including any general, special, incidental
- or consequential damages arising out of the use or inability to use SAX
- (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 SAX to
- operate with any other programs), even if such holder or other party has been
- advised of the possibility of such damages.
-
- Copyright Disclaimers 
-
- This page includes statements to that effect by David Megginson, who would
- have been able to claim copyright for the original work.  SAX 1.0
-
- Version 1.0 of the Simple API for XML (SAX), created collectively by the
- membership of the XML-DEV mailing list, is hereby released into the public
- domain.
-
- No one owns SAX: you may use it freely in both commercial and non-commercial
- applications, bundle it with your software distribution, include it on a
- CD-ROM, list the source code in a book, mirror the documentation at your own
- web site, or use it in any other way you see fit.
-
- David Megginson, sax@megginson.com
- 1998-05-11
-
- SAX 2.0 
-
- I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and
- release all of the SAX 2.0 source code, compiled code, and documentation
- contained in this distribution into the Public Domain. SAX comes with NO
- WARRANTY or guarantee of fitness for any purpose.
-
- David Megginson, david@megginson.com
- 2000-05-05
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SoftFloat version 2b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux/ARM.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-SoftFloat was written by me, John R. Hauser. This work was made possible in 
-part by the International Computer Science Institute, located at Suite 600, 
-1947 Center Street, Berkeley, California 94704. Funding was partially 
-provided by the National Science Foundation under grant MIP-9311980. The 
-original version of this code was written as part of a project to build 
-a fixed-point vector processor in collaboration with the University of 
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. 
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort 
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT 
-TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO 
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL 
-LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO 
-FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER 
-SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, 
-COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE 
-SOFTWARE. 
-
-Derivative works are acceptable, even for commercial purposes, provided 
-that the minimal documentation requirements stated in the source code are 
-satisfied. 
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Sparkle 1.5,
-which may be included with JRE 8 on Mac OS X.
-
---- begin of LICENSE ---
-
-Copyright (c) 2012 Sparkle.org and Andy Matuschak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions licensed from Taligent, Inc.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Thai Dictionary, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (C) 1982 The Royal Institute, Thai Royal Government.
-
-Copyright (C) 1998 National Electronics and Computer Technology Center,
-National Science and Technology Development Agency,
-Ministry of Science Technology and Environment,
-Thai Royal Government.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Unicode 6.2.0 & CLDR 21.0.1
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Unicode Terms of Use
-
-For the general privacy policy governing access to this site, see the Unicode
-Privacy Policy. For trademark usage, see the Unicode® Consortium Name and
-Trademark Usage Policy.
-
-A. Unicode Copyright.
-   1. Copyright © 1991-2013 Unicode, Inc. All rights reserved.
-
-   2. Certain documents and files on this website contain a legend indicating
-      that "Modification is permitted." Any person is hereby authorized,
-      without fee, to modify such documents and files to create derivative
-      works conforming to the Unicode® Standard, subject to Terms and
-      Conditions herein.
-
-    3. Any person is hereby authorized, without fee, to view, use, reproduce,
-       and distribute all documents and files solely for informational
-       purposes in the creation of products supporting the Unicode Standard,
-       subject to the Terms and Conditions herein.
-
-    4. Further specifications of rights and restrictions pertaining to the use
-       of the particular set of data files known as the "Unicode Character
-       Database" can be found in Exhibit 1.
-
-    5. Each version of the Unicode Standard has further specifications of
-       rights and restrictions of use. For the book editions (Unicode 5.0 and
-       earlier), these are found on the back of the title page. The online
-       code charts carry specific restrictions. All other files, including
-       online documentation of the core specification for Unicode 6.0 and
-       later, are covered under these general Terms of Use.
-
-    6. No license is granted to "mirror" the Unicode website where a fee is
-       charged for access to the "mirror" site.
-
-    7. Modification is not permitted with respect to this document. All copies
-       of this document must be verbatim.
-
-B. Restricted Rights Legend. Any technical data or software which is licensed
-   to the United States of America, its agencies and/or instrumentalities
-   under this Agreement is commercial technical data or commercial computer
-   software developed exclusively at private expense as defined in FAR 2.101,
-   or DFARS 252.227-7014 (June 1995), as applicable. For technical data, use,
-   duplication, or disclosure by the Government is subject to restrictions as
-   set forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov
-   1995) and this Agreement. For Software, in accordance with FAR 12-212 or
-   DFARS 227-7202, as applicable, use, duplication or disclosure by the
-   Government is subject to the restrictions set forth in this Agreement.
-
-C. Warranties and Disclaimers.
-   1. This publication and/or website may include technical or typographical
-      errors or other inaccuracies . Changes are periodically added to the
-      information herein; these changes will be incorporated in new editions
-      of the publication and/or website. Unicode may make improvements and/or
-      changes in the product(s) and/or program(s) described in this
-      publication and/or website at any time.
-
-    2. If this file has been purchased on magnetic or optical media from
-       Unicode, Inc. the sole and exclusive remedy for any claim will be
-       exchange of the defective media within ninety (90) days of original
-       purchase.
-
-    3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR SOFTWARE IS
-       PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, IMPLIED,
-       OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
-       UNICODE AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR
-       OMISSIONS IN THIS PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH
-       ARE REFERENCED BY OR LINKED TO THIS PUBLICATION OR THE UNICODE WEBSITE.
-
-D. Waiver of Damages. In no event shall Unicode or its licensors be liable for
-   any special, incidental, indirect or consequential damages of any kind, or
-   any damages whatsoever, whether or not Unicode was advised of the
-   possibility of the damage, including, without limitation, those resulting
-   from the following: loss of use, data or profits, in connection with the
-   use, modification or distribution of this information or its derivatives.
-
-E.Trademarks & Logos.
-   1. The Unicode Word Mark and the Unicode Logo are trademarks of Unicode,
-      Inc.  “The Unicode Consortium” and “Unicode, Inc.” are trade names of
-      Unicode, Inc.  Use of the information and materials found on this
-      website indicates your acknowledgement of Unicode, Inc.’s exclusive
-      worldwide rights in the Unicode Word Mark, the Unicode Logo, and the
-      Unicode trade names.
-
-   2. The Unicode Consortium Name and Trademark Usage Policy (“Trademark
-      Policy”) are incorporated herein by reference and you agree to abide by
-      the provisions of the Trademark Policy, which may be changed from time
-      to time in the sole discretion of Unicode, Inc.
-
-   3. All third party trademarks referenced herein are the property of their
-      respective owners.
-
-Miscellaneous.
-   1. Jurisdiction and Venue. This server is operated from a location in the
-      State of California, United States of America. Unicode makes no
-      representation that the materials are appropriate for use in other
-      locations. If you access this server from other locations, you are
-      responsible for compliance with local laws. This Agreement, all use of
-      this site and any claims and damages resulting from use of this site are
-      governed solely by the laws of the State of California without regard to
-      any principles which would apply the laws of a different jurisdiction.
-      The user agrees that any disputes regarding this site shall be resolved
-      solely in the courts located in Santa Clara County, California. The user
-      agrees said courts have personal jurisdiction and agree to waive any
-      right to transfer the dispute to any other forum.
-
-   2. Modification by Unicode.  Unicode shall have the right to modify this
-      Agreement at any time by posting it to this site. The user may not
-      assign any part of this Agreement without Unicode’s prior written
-      consent.
-
-   3. Taxes. The user agrees to pay any taxes arising from access to this
-      website or use of the information herein, except for those based on
-      Unicode’s net income.
-
-   4. Severability.  If any provision of this Agreement is declared invalid or
-      unenforceable, the remaining provisions of this Agreement shall remain
-      in effect.
-
-   5. Entire Agreement. This Agreement constitutes the entire agreement
-      between the parties.
-
-EXHIBIT 1
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-Unicode Data Files include all data files under the directories
-http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
-http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
-online code charts under the directory http://www.unicode.org/Public/.
-Software includes any source code published in the Unicode Standard or under
-the directories http://www.unicode.org/Public/,
-http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
-
-NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
-INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
-FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
-BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
-AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
-SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under the
-Terms of Use in http://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the Unicode data files and any associated documentation (the "Data Files")
-or Unicode software and any associated documentation (the "Software") to deal
-in the Data Files or Software without restriction, including without
-limitation the rights to use, copy, modify, merge, publish, distribute, and/or
-sell copies of the Data Files or Software, and to permit persons to whom the
-Data Files or Software are furnished to do so, provided that (a) the above
-copyright notice(s) and this permission notice appear with all copies of the
-Data Files or Software, (b) both the above copyright notice(s) and this
-permission notice appear in associated documentation, and (c) there is clear
-notice in each modified Data File or in the Software as well as in the
-documentation associated with the Data File(s) or Software that the data or
-software has been modified.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
-THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
-DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in these Data Files or Software without prior written authorization of the
-copyright holder.
-
-Unicode and the Unicode logo are trademarks of Unicode, Inc. in the United
-States and other countries. All third party trademarks referenced herein are
-the property of their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to UPX v3.01, which may be included 
-with JRE 8 on Windows.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-
-                 ooooo     ooo ooooooooo.   ooooooo  ooooo
-                 `888'     `8' `888   `Y88.  `8888    d8'
-                  888       8   888   .d88'    Y888..8P
-                  888       8   888ooo88P'      `8888'
-                  888       8   888            .8PY888.
-                  `88.    .8'   888           d8'  `888b
-                    `YbodP'    o888o        o888o  o88888o
-
-
-                    The Ultimate Packer for eXecutables
-          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
-               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
-                          http://www.nexus.hu/upx
-                            http://upx.tsx.org
-
-
-PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
-TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
-
-
-ABSTRACT
-========
-
-   UPX and UCL are copyrighted software distributed under the terms
-   of the GNU General Public License (hereinafter the "GPL").
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   As a special exception we grant the free usage of UPX for all
-   executables, including commercial programs.
-   See below for details and restrictions.
-
-
-COPYRIGHT
-=========
-
-   UPX and UCL are copyrighted software. All rights remain with the authors.
-
-   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-   UPX is Copyright (C) 1996-2000 Laszlo Molnar
-
-   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-
-
-GNU GENERAL PUBLIC LICENSE
-==========================
-
-   UPX and the UCL library are free software; you can redistribute them
-   and/or modify them under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   UPX and UCL are distributed in the hope that they will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; see the file COPYING.
-
-
-SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
-============================================
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
-   permission to freely use and distribute all UPX compressed programs
-   (including commercial ones), subject to the following restrictions:
-
-   1. You must compress your program with a completely unmodified UPX
-      version; either with our precompiled version, or (at your option)
-      with a self compiled version of the unmodified UPX sources as
-      distributed by us.
-   2. This also implies that the UPX stub must be completely unmodfied, i.e.
-      the stub imbedded in your compressed program must be byte-identical
-      to the stub that is produced by the official unmodified UPX version.
-   3. The decompressor and any other code from the stub must exclusively get
-      used by the unmodified UPX stub for decompressing your program at
-      program startup. No portion of the stub may get read, copied,
-      called or otherwise get used or accessed by your program.
-
-
-ANNOTATIONS
-===========
-
-  - You can use a modified UPX version or modified UPX stub only for
-    programs that are compatible with the GNU General Public License.
-
-  - We grant you special permission to freely use and distribute all UPX
-    compressed programs. But any modification of the UPX stub (such as,
-    but not limited to, removing our copyright string or making your
-    program non-decompressible) will immediately revoke your right to
-    use and distribute a UPX compressed program.
-
-  - UPX is not a software protection tool; by requiring that you use
-    the unmodified UPX version for your proprietary programs we
-    make sure that any user can decompress your program. This protects
-    both you and your users as nobody can hide malicious code -
-    any program that cannot be decompressed is highly suspicious
-    by definition.
-
-  - You can integrate all or part of UPX and UCL into projects that
-    are compatible with the GNU GPL, but obviously you cannot grant
-    any special exceptions beyond the GPL for our code in your project.
-
-  - We want to actively support manufacturers of virus scanners and
-    similar security software. Please contact us if you would like to
-    incorporate parts of UPX or UCL into such a product.
-
-
-
-Markus F.X.J. Oberhumer                   Laszlo Molnar
-markus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu
-
-Linz, Austria, 25 Feb 2000
-
-Additional License(s)
-
-The UPX license file is at http://upx.sourceforge.net/upx-license.html.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Xfree86-VidMode Extension 1.0,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Version 1.1 of XFree86 ProjectLicence.
-
-Copyright (C) 1994-2004 The XFree86 Project, Inc.    All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicence, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so,subject to the following conditions:
-
-   1. Redistributions of source code must retain the above copyright
-   notice,this list of conditions, and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution, and in the same place
-   and form as other copyright, license and disclaimer information.
-
-   3. The end-user documentation included with the redistribution, if any,must
-   include the following acknowledgment: "This product includes
-   software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and
-   its contributors", in the same place and form as other third-party
-   acknowledgments. Alternately, this acknowledgment may appear in the software
-   itself, in the same form and location as other such third-party
-   acknowledgments.
-
-    4. Except as contained in this notice, the name of The XFree86 Project,Inc
-    shall not be used in advertising or otherwise to promote the sale, use
-    or other dealings in this Software without prior written authorization from
-    The XFree86 Project, Inc.
-
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-    WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-    EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-    DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-    DAMAGE.  
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to X Window System 6.8.2, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-          Licenses
-The X.Org Foundation March 2004
-
-1. Introduction
-
-The X.org Foundation X Window System distribution is a compilation of code and
-documentation from many sources. This document is intended primarily as a
-guide to the licenses used in the distribution: you must check each file
-and/or package for precise redistribution terms. None-the-less, this summary
-may be useful to many users. No software incorporating the XFree86 1.1 license
-has been incorporated.
-
-This document is based on the compilation from XFree86.
-
-2. XFree86 License
-
-XFree86 code without an explicit copyright is covered by the following
-copyright/license:
-
-Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the XFree86 Project shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from the XFree86 Project.
-
-3. Other Licenses
-
-Portions of code are covered by the following licenses/copyrights. See
-individual files for the copyright dates.
-
-3.1. X/MIT Copyrights
-
-3.1.1. X Consortium
-
-Copyright (C) <date> X Consortium
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
-CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from the X Consortium.
-
-X Window System is a trademark of X Consortium, Inc.
-
-3.1.2. The Open Group
-
-Copyright <date> The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation.
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from The Open Group.  3.2.
-Berkeley-based copyrights:
-
-o
-3.2.1. General
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.2. UCB/LBL
-
-Copyright (c) 1993 The Regents of the University of California. All rights
-reserved.
-
-This software was developed by the Computer Systems Engineering group at
-Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to
-Berkeley.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement: This product includes software
-developed by the University of California, Lawrence Berkeley Laboratory.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the University of California, Berkeley and its contributors.
-
-   4. Neither the name of the University nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.3. The
-NetBSD Foundation, Inc.
-
-Copyright (c) 2003 The NetBSD Foundation, Inc. All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation by Ben
-Collver <collver1@attbi.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the NetBSD Foundation, Inc. and its contributors.
-
-   4. Neither the name of The NetBSD Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS
-IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.4. Theodore
-Ts'o.
-
-Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   and the entire permission notice in its entirety, including the disclaimer
-   of warranties.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. he name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.5. Theo de Raadt and Damien Miller
-
-Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. Copyright (c)
-2001-2002 Damien Miller. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.6. Todd C. Miller
-
-Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  3.2.7. Thomas
-Winischhofer
-
-Copyright (C) 2001-2004 Thomas Winischhofer
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.3. NVIDIA Corp
-
-Copyright (c) 1996 NVIDIA, Corp. All rights reserved.
-
-NOTICE TO USER: The source code is copyrighted under U.S. and international
-laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design
-patents pending on the design and interface of the NV chips. Users and
-possessors of this source code are hereby granted a nonexclusive, royalty-free
-copyright and design patent license to use this code in individual and
-commercial software.
-
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
-
-Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and
-foreign countries.
-
-NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
-CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
-WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE
-FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.  3.4. GLX Public
-License
-
-GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License")
-
-Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby
-grants permission to Recipient (defined below), under Recipient's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below), and to permit persons to whom the Subject Software is
-furnished in accordance with this License to do the same, subject to all of
-the following terms and conditions, which Recipient accepts by engaging in any
-such use, copying, modifying, merging, publishing, distributing, sublicensing
-or selling:
-
-1. Definitions.
-
-    (a) "Original Software" means source code of computer software code which
-    is described in Exhibit A as Original Software.
-
-    (b) "Modifications" means any addition to or deletion from the substance
-    or structure of either the Original Software or any previous
-    Modifications. When Subject Software is released as a series of files, a
-    Modification means (i) any addition to or deletion from the contents of a
-    file containing Original Software or previous Modifications and (ii) any
-    new file that contains any part of the Original Code or previous
-    Modifications.
-
-    (c) "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    (d) "Recipient" means an individual or a legal entity exercising rights
-    under, and complying with all of the terms of, this License. For legal
-    entities, "Recipient" includes any entity which controls, is controlled
-    by, or is under common control with Recipient. For purposes of this
-    definition, "control" of an entity means (a) the power, direct or
-    indirect, to direct or manage such entity, or (b) ownership of fifty
-    percent (50%) or more of the outstanding shares or beneficial ownership of
-    such entity.
-
-2. Redistribution of Source Code Subject to These Terms. Redistributions of
-Subject Software in source code form must retain the notice set forth in
-Exhibit A, below, in every file. A copy of this License must be included in
-any documentation for such Subject Software where the recipients' rights
-relating to Subject Software are described. Recipient may distribute the
-source code version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the source code version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-3. Redistribution in Executable Form. The notice set forth in Exhibit A must
-be conspicuously included in any notice in an executable version of Subject
-Software, related documentation or collateral in which Recipient describes the
-user's rights relating to the Subject Software. Recipient may distribute the
-executable version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the executable version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-4. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software which is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-5. No Trademark Rights. This License does not grant any rights to use any
-trade name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from
-the Subject Software without prior written permission of SGI.
-
-6. No Other Rights. This License does not grant any rights with respect to the
-OpenGL API or to any software or hardware implementation thereof or to any
-other software whatsoever, nor shall any other rights or licenses not
-expressly granted hereunder arise by implication, estoppel or otherwise with
-respect to the Subject Software. Title to and ownership of the Original
-Software at all times remains with SGI. All rights in the Original Software
-not expressly granted under this License are reserved.
-
-7. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-8. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Exhibit A notice required under Sections 2 and 3,
-above, and in the text of any related documentation, license agreement or
-collateral in which Recipient describes end user's rights relating to the
-Subject Software. If Recipient obtains such knowledge after it makes Subject
-Software available to any other person or entity, Recipient shall take other
-steps (such as notifying appropriate mailing lists or newsgroups) reasonably
-calculated to inform those who received the Subject Software that new
-knowledge has been obtained.
-
-9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
-STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF
-THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY
-TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO
-THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT.
-
-11. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from
-and against any loss, liability, damages, costs or expenses (including the
-payment of reasonable attorneys fees) arising out of Recipient's use,
-modification, reproduction and distribution of the Subject Software or out of
-any representation or warranty made by Recipient.
-
-12. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-13. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed so as to achieve as nearly as
-possible the same economic effect as the original provision and the remainder
-of this License will remain in effect. This License shall be governed by and
-construed in accordance with the laws of the United States and the State of
-California as applied to agreements entered into and to be performed entirely
-within California between California residents. Any litigation relating to
-this License shall be subject to the exclusive jurisdiction of the Federal
-Courts of the Northern District of California (or, absent subject matter
-jurisdiction in such courts, the courts of the State of California), with
-venue lying exclusively in Santa Clara County, California, with the losing
-party responsible for costs, including without limitation, court costs and
-reasonable attorneys fees and expenses. The application of the United Nations
-Convention on Contracts for the International Sale of Goods is expressly
-excluded. Any law or regulation which provides that the language of a contract
-shall be construed against the drafter shall not apply to this License.
-
-Exhibit A
-
-The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13
-of the GLX Public License Version 1.0 (the "License"). You may not use this
-file except in compliance with those sections of the License. You may obtain a
-copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N.
-Shoreline Blvd., Mountain View, CA 94043 or at
-http://www.sgi.com/software/opensource/glx/license.html.
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON-
-INFRINGEMENT. See the License for the specific language governing rights and
-limitations under the License.
-
-The Original Software is GLX version 1.2 source code, released February, 1999.
-The developer of the Original Software is Silicon Graphics, Inc. Those
-portions of the Subject Software created by Silicon Graphics, Inc. are
-Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.  3.5. CID
-Font Code Public License
-
-CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License")
-
-Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI")
-hereby grants permission to Recipient (defined below), under SGI's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below) in both source code and executable form, and to permit persons
-to whom the Subject Software is furnished in accordance with this License to
-do the same, subject to all of the following terms and conditions, which
-Recipient accepts by engaging in any such use, copying, modifying, merging,
-publication, distributing, sublicensing or selling:
-
-1. Definitions.
-
-    a. "Original Software" means source code of computer software code that is
-    described in Exhibit A as Original Software.
-
-    b. "Modifications" means any addition to or deletion from the substance or
-    structure of either the Original Software or any previous Modifications.
-    When Subject Software is released as a series of files, a Modification
-    means (i) any addition to or deletion from the contents of a file
-    containing Original Software or previous Modifications and (ii) any new
-    file that contains any part of the Original Code or previous
-    Modifications.
-
-    c. "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    d. "Recipient" means an individual or a legal entity exercising rights
-    under the terms of this License. For legal entities, "Recipient" includes
-    any entity that controls, is controlled by, or is under common control
-    with Recipient. For purposes of this definition, "control" of an entity
-    means (i) the power, direct or indirect, to direct or manage such entity,
-    or (ii) ownership of fifty percent (50%) or more of the outstanding shares
-    or beneficial ownership of such entity.
-
-    e. "Required Notice" means the notice set forth in Exhibit A to this
-    License.
-
-    f. "Accompanying Technology" means any software or other technology that
-    is not a Modification and that is distributed or made publicly available
-    by Recipient with the Subject Software. Separate software files that do
-    not contain any Original Software or any previous Modification shall not
-    be deemed a Modification, even if such software files are aggregated as
-    part of a product, or in any medium of storage, with any file that does
-    contain Original Software or any previous Modification.
-
-2. License Terms. All distribution of the Subject Software must be made
-subject to the terms of this License. A copy of this License and the Required
-Notice must be included in any documentation for Subject Software where
-Recipient's rights relating to Subject Software and/or any Accompanying
-Technology are described. Distributions of Subject Software in source code
-form must also include the Required Notice in every file distributed. In
-addition, a ReadMe file entitled "Important Legal Notice" must be distributed
-with each distribution of one or more files that incorporate Subject Software.
-That file must be included with distributions made in both source code and
-executable form. A copy of the License and the Required Notice must be
-included in that file. Recipient may distribute Accompanying Technology under
-a license of Recipient's choice, which may contain terms different from this
-License, provided that (i) Recipient is in compliance with the terms of this
-License, (ii) such other license terms do not modify or supersede the terms of
-this License as applicable to the Subject Software, (iii) Recipient hereby
-indemnifies SGI for any liability incurred by SGI as a result of the
-distribution of Accompanying Technology or the use of other license terms.
-
-3. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software that is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-4. Trademark Rights. This License does not grant any rights to use any trade
-name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from or
-incorporating any Subject Software without prior written permission of SGI.
-
-5. No Other Rights. No rights or licenses not expressly granted hereunder
-shall arise by implication, estoppel or otherwise. Title to and ownership of
-the Original Software at all times remains with SGI. All rights in the
-Original Software not expressly granted under this License are reserved.
-
-6. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity, or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-7. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Required Notice, and in the text of any related
-documentation, license agreement or collateral in which Recipient describes
-end user's rights relating to the Subject Software. If Recipient obtains such
-knowledge after it makes Subject Software available to any other person or
-entity, Recipient shall take other steps (such as notifying appropriate
-mailing lists or newsgroups) reasonably calculated to provide such knowledge
-to those who received the Subject Software.
-
-8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND
-LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED.
-
-10. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold SGI and its successors and assigns
-harmless from and against any loss, liability, damages, costs or expenses
-(including the payment of reasonable attorneys fees) arising out of
-(Recipient's use, modification, reproduction and distribution of the Subject
-Software or out of any representation or warranty made by Recipient.
-
-11. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-12. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable by any judicial or administrative authority having proper
-jurisdiction with respect thereto, such provision shall be reformed so as to
-achieve as nearly as possible the same economic effect as the original
-provision and the remainder of this License will remain in effect. This
-License shall be governed by and construed in accordance with the laws of the
-United States and the State of California as applied to agreements entered
-into and to be performed entirely within California between California
-residents. Any litigation relating to this License shall be subject to the
-exclusive jurisdiction of the Federal Courts of the Northern District of
-California (or, absent subject matter jurisdiction in such courts, the courts
-of the State of California), with venue lying exclusively in Santa Clara
-County, California, with the losing party responsible for costs, including
-without limitation, court costs and reasonable attorneys fees and expenses.
-The application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded. Any law or regulation that
-provides that the language of a contract shall be construed against the
-drafter shall not apply to this License.
-
-Exhibit A
-
-Copyright (c) 1994-1999 Silicon Graphics, Inc.
-
-The contents of this file are subject to the CID Font Code Public License
-Version 1.0 (the "License"). You may not use this file except in compliance
-with the License. You may obtain a copy of the License at Silicon Graphics,
-Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
-or at http://www.sgi.com/software/opensource/cid/license.html
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF
-NON-INFRINGEMENT. See the License for the specific language governing rights
-and limitations under the License.
-
-The Original Software (as defined in the License) is CID font code that was
-developed by Silicon Graphics, Inc. Those portions of the Subject Software (as
-defined in the License) that were created by Silicon Graphics, Inc. are
-Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved.
-
-[NOTE: When using this text in connection with Subject Software delivered
-solely in object code form, Recipient may replace the words "this file" with
-"this software" in both the first and second sentences.] 3.6. Bitstream Vera
-Fonts Copyright
-
-The fonts have a generous copyright, allowing derivative works (as long as
-"Bitstream" or "Vera" are not in the names), and full redistribution (so long
-as they are not *sold* by themselves). They can be be bundled, redistributed
-and sold with any software.
-
-The fonts are distributed under the following copyright:
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.  3.7. Bigelow & Holmes
-Inc and URW++ GmbH Luxi font license
-
-Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font instruction
-code copyright (c) 2001 by URW++ GmbH. All Rights Reserved. Luxi is a
-registered trademark of Bigelow & Holmes Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of these Fonts and associated documentation files (the "Font Software"), to
-deal in the Font Software, including without limitation the rights to use,
-copy, merge, publish, distribute, sublicense, and/or sell copies of the Font
-Software, and to permit persons to whom the Font Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software.
-
-The Font Software may not be modified, altered, or added to, and in particular
-the designs of glyphs or characters in the Fonts may not be modified nor may
-additional glyphs or characters be added to the Fonts. This License becomes
-null and void when the Fonts or Font Software have been modified.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BIGELOW & HOLMES INC. OR URW++
-GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
-GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
-Except as contained in this notice, the names of Bigelow & Holmes Inc. and
-URW++ GmbH. shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Font Software without prior written
-authorization from Bigelow & Holmes Inc. and URW++ GmbH.
-
-For further information, contact:
-
-info@urwpp.de or design@bigelowandholmes.com
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to zlib v1.2.5, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-  version 1.2.5, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to the following which may be 
-included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
-
-  Apache Commons Math 2.2
-  Apache Derby 10.10.1.2        [included with JDK 8]
-  Apache Jakarta BCEL 5.2 
-  Apache Jakarta Regexp 1.4 
-  Apache Santuario XML Security for Java 1.5.4
-  Apache Xalan-Java 2.7.1 
-  Apache Xerces Java 2.10.0 
-  Apache XML Resolver 1.1 
-  Dynalink 0.5
-
-
---- begin of LICENSE ---
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
diff --git a/jaxws/src/jdk.xml.bind/share/legal/relaxngdatatype.md b/jaxws/src/jdk.xml.bind/share/legal/relaxngdatatype.md
new file mode 100644
index 0000000..54343b7
--- /dev/null
+++ b/jaxws/src/jdk.xml.bind/share/legal/relaxngdatatype.md
@@ -0,0 +1,37 @@
+## RelaxNG Datatype
+
+### RelaxNG Datatype License
+<pre>
+
+Copyright (c) 2001, Thai Open Source Software Center Ltd, Sun Microsystems.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    Neither the names of the copyright holders nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jaxws/src/jdk.xml.bind/share/legal/rngom.md b/jaxws/src/jdk.xml.bind/share/legal/rngom.md
new file mode 100644
index 0000000..c71f8c3
--- /dev/null
+++ b/jaxws/src/jdk.xml.bind/share/legal/rngom.md
@@ -0,0 +1,25 @@
+## RelaxNG Object Model/Parser v20061207
+
+### RelaxNG Object Model/Parser License
+<pre>
+
+Copyright (c) 2004-2012 RELAXNG
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+</pre>
diff --git a/jaxws/src/jdk.xml.bind/share/legal/xmlresolver.md b/jaxws/src/jdk.xml.bind/share/legal/xmlresolver.md
new file mode 100644
index 0000000..cf18bb4
--- /dev/null
+++ b/jaxws/src/jdk.xml.bind/share/legal/xmlresolver.md
@@ -0,0 +1,223 @@
+## Apache XML Resolver Library v1.2
+
+### Notice
+<pre>
+
+Apache XML Commons Resolver
+Copyright 2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation http://www.apache.org/
+
+Portions of this code are derived from classes placed in the
+public domain by Arbortext on 10 Apr 2000. See:
+http://www.arbortext.com/customer_support/updates_and_technical_notes/catalogs/docs/README.htm
+
+</pre>
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jdk/.hgtags b/jdk/.hgtags
index 8aee88c..a491956 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -391,3 +391,4 @@
 6e4ff59afb5d0adf21a72c4ff534326594a99e5d jdk-9+146
 c41140100bf1e5c10c7b8f3bde91c16eff7485f5 jdk-9+147
 9098b2b9d997d65af0026fc2f39cf75234e26bc5 jdk-9+148
+5a846396a24c7aff01d6a8feaa7afc0a6369f04d jdk-9+149
diff --git a/jdk/THIRD_PARTY_README b/jdk/THIRD_PARTY_README
deleted file mode 100644
index 767609f..0000000
--- a/jdk/THIRD_PARTY_README
+++ /dev/null
@@ -1,3605 +0,0 @@
-DO NOT TRANSLATE OR LOCALIZE.
------------------------------
-
-%% This notice is provided with respect to ASM Bytecode Manipulation 
-Framework v5.0, which may be included with JRE 8, and JDK 8, and 
-OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2011 France Télécom
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holders nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to BSDiff v4.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 2003-2005 Colin Percival
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CodeViewer 1.0, which may be
-included with JDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1999 by CoolServlets.com.
-
-Any errors or suggested improvements to this class can be reported as
-instructed on CoolServlets.com. We hope you enjoy this program... your
-comments will encourage further development!  This software is distributed
-under the terms of the BSD License.  Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-Neither name of CoolServlets.com nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Cryptix AES 3.2.0, which may be
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Cryptix General License
-
-Copyright (c) 1995-2005 The Cryptix Foundation Limited.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  1. Redistributions of source code must retain the copyright notice,
-     this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CUP Parser Generator for 
-Java 0.10k, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted, provided
-that the above copyright notice appear in all copies and that both the
-copyright notice and this permission notice and warranty disclaimer appear in
-supporting documentation, and that the names of the authors or their
-employers not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission.
-
-The authors and their employers disclaim all warranties with regard to
-this software, including all implied warranties of merchantability and fitness.
-In no event shall the authors or their employers be liable for any special,
-indirect or consequential damages or any damages whatsoever resulting from
-loss of use, data or profits, whether in an action of contract, negligence or
-other tortious action, arising out of or in connection with the use or
-performance of this software.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Document Object Model (DOM) Level 2
-& 3, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-W3C SOFTWARE NOTICE AND LICENSE
-
-http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
-
-This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license. By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following terms
-and conditions.
-
-Permission to copy, modify, and distribute this software and its
-documentation, with or without modification, for any purpose and without fee
-or royalty is hereby granted, provided that you include the following on ALL
-copies of the software and documentation or portions thereof, including
-modifications:
-
-   1.The full text of this NOTICE in a location viewable to users of the
-   redistributed or derivative work.
-
-   2.Any pre-existing intellectual property disclaimers, notices, or terms and
-   conditions. If none exist, the W3C Software Short Notice should be included
-   (hypertext is preferred, text is permitted) within the body of any
-   redistributed or derivative code.
-
-   3.Notice of any changes or modifications to the files, including the date
-   changes were made. (We recommend you provide URIs to the location from
-   which the code is derived.)
-
-THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
-THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
-COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
-in advertising or publicity pertaining to the software without specific,
-written prior permission. Title to copyright in this software and any
-associated documentation will at all times remain with copyright holders.
-
-____________________________________
-
-This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C, reflects
-that ERCIM is now a host of the W3C, includes references to this specific
-dated version of the license, and removes the ambiguous grant of "use".
-Otherwise, this version is the same as the previous version and is written so
-as to preserve the Free Software Foundation's assessment of GPL compatibility
-and OSI's certification under the Open Source Definition. Please see our
-Copyright FAQ for common questions about using materials from our site,
-including specific terms and conditions for packages like libwww, Amaya, and
-Jigsaw. Other questions about this notice can be directed to
-site-policy@w3.org.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Dynalink v0.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2009-2013, Attila Szegedi
-
-All rights reserved.Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following conditions are
-met:* Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.  * Redistributions in
-binary form must reproduce the above copyright notice,   this list of
-conditions and the following disclaimer in the documentation  and/or other
-materials provided with the distribution.  * Neither the name of Attila
-Szegedi nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Elliptic Curve Cryptography, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
-You are receiving a copy of the Elliptic Curve Cryptography library in source
-form with the JDK 8 and OpenJDK 8 source distributions, and as object code in
-the JRE 8 & JDK 8 runtimes.
-
-In the case of the JRE 8 & JDK 8 runtimes, the terms of the Oracle license do
-NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
-following license, separately from Oracle's JDK & JRE.  If you do not wish to
-install the Elliptic Curve Cryptography library, you may delete the library
-named libsunec.so (on Solaris and Linux systems) or sunec.dll (on Windows
-systems) from the JRE bin directory reserved for native libraries.
-
-
---- begin of LICENSE ---
-
-                  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!
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to  ECMAScript Language
-Specification ECMA-262 Edition 5.1 which may be included with 
-JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright notice
-Copyright © 2011 Ecma International
-Ecma International
-Rue du Rhone 114
-CH-1204 Geneva
-Tel: +41 22 849 6000
-Fax: +41 22 849 6001
-Web: http://www.ecma-international.org
-
-This document and possible translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it or assist
-in its implementation may be prepared, copied, published, and distributed, in
-whole or in part, without restriction of any kind, provided that the above
-copyright notice and this section are included on all such copies and derivative
-works. However, this document itself may not be modified in any way, including
-by removing the copyright notice or references to Ecma International, except as
-needed for the purpose of developing any document or deliverable produced by
-Ecma International (in which case the rules applied to copyrights must be
-followed) or as required to translate it into languages other than English. The
-limited permissions granted above are perpetual and will not be revoked by Ecma
-International or its successors or assigns. This document and the information
-contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL
-DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
-WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
-RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
-PURPOSE." Software License
-
-All Software contained in this document ("Software)" is protected by copyright
-and is being made available under the "BSD License", included below. This
-Software may be subject to third party rights (rights from parties other than
-Ecma International), including patent rights, and no licenses under such third
-party rights are granted under this license even if the third party concerned is
-a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS
-AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
-INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO
-IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the authors nor Ecma International may be used to endorse
-or promote products derived from this software without specific prior written
-permission.
-
-THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Dynalink library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Copyright (c) 2009-2013, Attila Szegedi
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the copyright holder nor the names of
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Joni library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to FontConfig 2.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 source distributions on
-Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright © 2001,2003 Keith Packard
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation, and that
-the name of Keith Packard not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior permission.
-Keith Packard makes no representations about the suitability of this software
-for any purpose.  It is provided "as is" without express or implied warranty.
-
-KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IAIK PKCS#11 Wrapper, 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-IAIK PKCS#11 Wrapper License
-
-Copyright (c) 2002 Graz University of Technology. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-   "This product includes software developed by IAIK of Graz University of
-    Technology."
-
-   Alternately, this acknowledgment may appear in the software itself, if and
-   wherever such third-party acknowledgments normally appear.
-
-4. The names "Graz University of Technology" and "IAIK of Graz University of
-   Technology" must not be used to endorse or promote products derived from this
-   software without prior written permission.
-
-5. Products derived from this software may not be called "IAIK PKCS Wrapper",
-   nor may "IAIK" appear in their name, without prior written permission of
-   Graz University of Technology.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to ICU4C 4.0.1 and ICU4J 4.4, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 1995-2010 International Business Machines Corporation and others 
-
-All rights reserved. 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice appear
-in all copies of the Software and that both the above copyright notice(s) and
-this permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
-All trademarks and registered trademarks mentioned herein are the property of
-their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IJG JPEG 6b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library.  If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it.  This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Joni v1.1.9, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JOpt-Simple v3.0,  which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (c) 2004-2009 Paul R. Holser, Jr.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JSON, which may be included 
-with JRE 8 & JDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality, which 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- (C) Copyright IBM Corp. 1999 All Rights Reserved.
- Copyright 1997 The Open Group Research Institute. All rights reserved.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality from 
-FundsXpress, INC., which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (C) 1998 by the FundsXpress, INC.
-
- All rights reserved.
-
- Export of this software from the United States of America may require
- a specific license from the United States Government.  It is the
- responsibility of any person or organization contemplating export to
- obtain such a license before exporting.
-
- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- distribute this software and its documentation for any purpose and
- without fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation, and that
- the name of FundsXpress. not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.  FundsXpress makes no representations about the suitability of
- this software for any purpose.  It is provided "as is" without express
- or implied warranty.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kronos OpenGL headers, which may be 
-included with JDK 8 and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Copyright (c) 2007 The Khronos Group Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and/or associated documentation files (the "Materials"), to
- deal in the Materials without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Materials, and to permit persons to whom the Materials are
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Materials.
-
- THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- MATERIALS.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions Copyright Eastman Kodak Company 1992
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libpng 1.5.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This copy of the libpng notices is provided for your convenience.  In case of
-any discrepancy between this copy and the notices in the file png.h that is
-included in the libpng distribution, the latter shall prevail.
-
-COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
-
-If you modify libpng you may insert additional notices immediately following
-this sentence.
-
-This code is released under the libpng license.
-
-libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
-Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.2.5
-with the following individual added to the list of Contributing Authors
-
-   Cosmin Truta
-
-libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
-Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.0.6
-with the following individuals added to the list of Contributing Authors
-
-   Simon-Pierre Cadieux
-   Eric S. Raymond
-   Gilles Vollant
-
-and with the following additions to the disclaimer:
-
-   There is no warranty against interference with your enjoyment of the
-   library or against infringement.  There is no warranty that our
-   efforts or the library will fulfill any of your particular purposes
-   or needs.  This library is provided with all faults, and the entire
-   risk of satisfactory quality, performance, accuracy, and effort is with
-   the user.
-
-libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
-Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-0.96,
-with the following individuals added to the list of Contributing Authors:
-
-   Tom Lane
-   Glenn Randers-Pehrson
-   Willem van Schaik
-
-libpng versions 0.89, June 1996, through 0.96, May 1997, are
-Copyright (c) 1996, 1997 Andreas Dilger
-Distributed according to the same disclaimer and license as libpng-0.88,
-with the following individuals added to the list of Contributing Authors:
-
-   John Bowler
-   Kevin Bracey
-   Sam Bushell
-   Magnus Holmgren
-   Greg Roelofs
-   Tom Tanner
-
-libpng versions 0.5, May 1995, through 0.88, January 1996, are
-Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-
-For the purposes of this copyright and license, "Contributing Authors"
-is defined as the following set of individuals:
-
-   Andreas Dilger
-   Dave Martindale
-   Guy Eric Schalnat
-   Paul Schmidt
-   Tim Wegner
-
-The PNG Reference Library is supplied "AS IS".  The Contributing Authors
-and Group 42, Inc. disclaim all warranties, expressed or implied,
-including, without limitation, the warranties of merchantability and of
-fitness for any purpose.  The Contributing Authors and Group 42, Inc.
-assume no liability for direct, indirect, incidental, special, exemplary,
-or consequential damages, which may result from the use of the PNG
-Reference Library, even if advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-source code, or portions hereof, for any purpose, without fee, subject
-to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-
-2. Altered versions must be plainly marked as such and must not
-   be misrepresented as being the original source.
-
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The Contributing Authors and Group 42, Inc. specifically permit, without
-fee, and encourage the use of this source code as a component to
-supporting the PNG file format in commercial products.  If you use this
-source code in a product, acknowledgment is not required but would be
-appreciated.
-
-
-A "png_get_copyright" function is available, for convenient use in "about"
-boxes and the like:
-
-   printf("%s",png_get_copyright(NULL));
-
-Also, the PNG logo (in PNG format, of course) is supplied in the
-files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
-
-Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
-certification mark of the Open Source Initiative.
-
-Glenn Randers-Pehrson
-glennrp at users.sourceforge.net
-July 7, 2011
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libungif 4.1.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Little CMS 2.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Little CMS
-Copyright (c) 1998-2010 Marti Maria Saguer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Lucida is a registered trademark or trademark of Bigelow & Holmes in the
-U.S. and other countries.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mesa 3D Graphics Library v4.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Mesa 3-D graphics library
- Version:  4.1
-
- Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mozilla Network Security
-Services (NSS), which is supplied with the JDK test suite in the OpenJDK
-source code repository. It is licensed under Mozilla Public License (MPL),
-version 2.0.
-
-The NSS libraries are supplied in executable form, built from unmodified
-NSS source code labeled with the "NSS_3_16_RTM" HG tag.
-
-The NSS source code is available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/src
-
-The NSS libraries are available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/lib
-
---- begin of LICENSE ---
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PC/SC Lite for Suse Linux v.1.1.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
-Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by: 
-      David Corcoran <corcoran@linuxnet.com>
-      http://www.linuxnet.com (MUSCLE)
-4. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-Changes to this license can be made only by the copyright author with 
-explicit written consent.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PorterStemmer v4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-See: http://tartarus.org/~martin/PorterStemmer
-
-The software is completely free for any purpose, unless notes at the head of
-the program text indicates otherwise (which is rare). In any case, the notes
-about licensing are never more restrictive than the BSD License.
-
-In every case where the software is not written by me (Martin Porter), this
-licensing arrangement has been endorsed by the contributor, and it is
-therefore unnecessary to ask the contributor again to confirm it.
-
-I have not asked any contributors (or their employers, if they have them) for
-proofs that they have the right to distribute their software in this way.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Relax NG Object/Parser v.20050510,
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions: The above copyright
-notice and this permission notice shall be included in all copies or
-substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to RelaxNGCC v1.12, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2003 Daisuke Okajima and Kohsuke Kawaguchi.  
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-    "This product includes software developed by Daisuke Okajima
-    and Kohsuke Kawaguchi (http://relaxngcc.sf.net/)."
-
-Alternately, this acknowledgment may appear in the software itself, if and
-wherever such third-party acknowledgments normally appear.
-
-4. The names of the copyright holders must not be used to endorse or promote
-   products derived from this software without prior written permission. For
-   written permission, please contact the copyright holders.
-
-5. Products derived from this software may not be called "RELAXNGCC", nor may
-  "RELAXNGCC" appear in their name, without prior written permission of the
-  copyright holders.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE APACHE
-SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SAX 2.0.1, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- SAX is free!
-
- In fact, it's not possible to own a license to SAX, since it's been placed in
- the public domain.
-
- No Warranty
-
- Because SAX is released to the public domain, there is no warranty for the
- design or for the software implementation, to the extent permitted by
- applicable law. Except when otherwise stated in writing the copyright holders
- and/or other parties provide SAX "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 SAX is with you. Should SAX prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- 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
- SAX, be liable to you for damages, including any general, special, incidental
- or consequential damages arising out of the use or inability to use SAX
- (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 SAX to
- operate with any other programs), even if such holder or other party has been
- advised of the possibility of such damages.
-
- Copyright Disclaimers 
-
- This page includes statements to that effect by David Megginson, who would
- have been able to claim copyright for the original work.  SAX 1.0
-
- Version 1.0 of the Simple API for XML (SAX), created collectively by the
- membership of the XML-DEV mailing list, is hereby released into the public
- domain.
-
- No one owns SAX: you may use it freely in both commercial and non-commercial
- applications, bundle it with your software distribution, include it on a
- CD-ROM, list the source code in a book, mirror the documentation at your own
- web site, or use it in any other way you see fit.
-
- David Megginson, sax@megginson.com
- 1998-05-11
-
- SAX 2.0 
-
- I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and
- release all of the SAX 2.0 source code, compiled code, and documentation
- contained in this distribution into the Public Domain. SAX comes with NO
- WARRANTY or guarantee of fitness for any purpose.
-
- David Megginson, david@megginson.com
- 2000-05-05
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SoftFloat version 2b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux/ARM.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-SoftFloat was written by me, John R. Hauser. This work was made possible in 
-part by the International Computer Science Institute, located at Suite 600, 
-1947 Center Street, Berkeley, California 94704. Funding was partially 
-provided by the National Science Foundation under grant MIP-9311980. The 
-original version of this code was written as part of a project to build 
-a fixed-point vector processor in collaboration with the University of 
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. 
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort 
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT 
-TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO 
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL 
-LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO 
-FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER 
-SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, 
-COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE 
-SOFTWARE. 
-
-Derivative works are acceptable, even for commercial purposes, provided 
-that the minimal documentation requirements stated in the source code are 
-satisfied. 
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Sparkle 1.5,
-which may be included with JRE 8 on Mac OS X.
-
---- begin of LICENSE ---
-
-Copyright (c) 2012 Sparkle.org and Andy Matuschak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions licensed from Taligent, Inc.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Thai Dictionary, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (C) 1982 The Royal Institute, Thai Royal Government.
-
-Copyright (C) 1998 National Electronics and Computer Technology Center,
-National Science and Technology Development Agency,
-Ministry of Science Technology and Environment,
-Thai Royal Government.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Unicode 6.2.0 & CLDR 21.0.1
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Unicode Terms of Use
-
-For the general privacy policy governing access to this site, see the Unicode
-Privacy Policy. For trademark usage, see the Unicode® Consortium Name and
-Trademark Usage Policy.
-
-A. Unicode Copyright.
-   1. Copyright © 1991-2013 Unicode, Inc. All rights reserved.
-
-   2. Certain documents and files on this website contain a legend indicating
-      that "Modification is permitted." Any person is hereby authorized,
-      without fee, to modify such documents and files to create derivative
-      works conforming to the Unicode® Standard, subject to Terms and
-      Conditions herein.
-
-    3. Any person is hereby authorized, without fee, to view, use, reproduce,
-       and distribute all documents and files solely for informational
-       purposes in the creation of products supporting the Unicode Standard,
-       subject to the Terms and Conditions herein.
-
-    4. Further specifications of rights and restrictions pertaining to the use
-       of the particular set of data files known as the "Unicode Character
-       Database" can be found in Exhibit 1.
-
-    5. Each version of the Unicode Standard has further specifications of
-       rights and restrictions of use. For the book editions (Unicode 5.0 and
-       earlier), these are found on the back of the title page. The online
-       code charts carry specific restrictions. All other files, including
-       online documentation of the core specification for Unicode 6.0 and
-       later, are covered under these general Terms of Use.
-
-    6. No license is granted to "mirror" the Unicode website where a fee is
-       charged for access to the "mirror" site.
-
-    7. Modification is not permitted with respect to this document. All copies
-       of this document must be verbatim.
-
-B. Restricted Rights Legend. Any technical data or software which is licensed
-   to the United States of America, its agencies and/or instrumentalities
-   under this Agreement is commercial technical data or commercial computer
-   software developed exclusively at private expense as defined in FAR 2.101,
-   or DFARS 252.227-7014 (June 1995), as applicable. For technical data, use,
-   duplication, or disclosure by the Government is subject to restrictions as
-   set forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov
-   1995) and this Agreement. For Software, in accordance with FAR 12-212 or
-   DFARS 227-7202, as applicable, use, duplication or disclosure by the
-   Government is subject to the restrictions set forth in this Agreement.
-
-C. Warranties and Disclaimers.
-   1. This publication and/or website may include technical or typographical
-      errors or other inaccuracies . Changes are periodically added to the
-      information herein; these changes will be incorporated in new editions
-      of the publication and/or website. Unicode may make improvements and/or
-      changes in the product(s) and/or program(s) described in this
-      publication and/or website at any time.
-
-    2. If this file has been purchased on magnetic or optical media from
-       Unicode, Inc. the sole and exclusive remedy for any claim will be
-       exchange of the defective media within ninety (90) days of original
-       purchase.
-
-    3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR SOFTWARE IS
-       PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, IMPLIED,
-       OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
-       UNICODE AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR
-       OMISSIONS IN THIS PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH
-       ARE REFERENCED BY OR LINKED TO THIS PUBLICATION OR THE UNICODE WEBSITE.
-
-D. Waiver of Damages. In no event shall Unicode or its licensors be liable for
-   any special, incidental, indirect or consequential damages of any kind, or
-   any damages whatsoever, whether or not Unicode was advised of the
-   possibility of the damage, including, without limitation, those resulting
-   from the following: loss of use, data or profits, in connection with the
-   use, modification or distribution of this information or its derivatives.
-
-E.Trademarks & Logos.
-   1. The Unicode Word Mark and the Unicode Logo are trademarks of Unicode,
-      Inc.  “The Unicode Consortium” and “Unicode, Inc.” are trade names of
-      Unicode, Inc.  Use of the information and materials found on this
-      website indicates your acknowledgement of Unicode, Inc.’s exclusive
-      worldwide rights in the Unicode Word Mark, the Unicode Logo, and the
-      Unicode trade names.
-
-   2. The Unicode Consortium Name and Trademark Usage Policy (“Trademark
-      Policy”) are incorporated herein by reference and you agree to abide by
-      the provisions of the Trademark Policy, which may be changed from time
-      to time in the sole discretion of Unicode, Inc.
-
-   3. All third party trademarks referenced herein are the property of their
-      respective owners.
-
-Miscellaneous.
-   1. Jurisdiction and Venue. This server is operated from a location in the
-      State of California, United States of America. Unicode makes no
-      representation that the materials are appropriate for use in other
-      locations. If you access this server from other locations, you are
-      responsible for compliance with local laws. This Agreement, all use of
-      this site and any claims and damages resulting from use of this site are
-      governed solely by the laws of the State of California without regard to
-      any principles which would apply the laws of a different jurisdiction.
-      The user agrees that any disputes regarding this site shall be resolved
-      solely in the courts located in Santa Clara County, California. The user
-      agrees said courts have personal jurisdiction and agree to waive any
-      right to transfer the dispute to any other forum.
-
-   2. Modification by Unicode.  Unicode shall have the right to modify this
-      Agreement at any time by posting it to this site. The user may not
-      assign any part of this Agreement without Unicode’s prior written
-      consent.
-
-   3. Taxes. The user agrees to pay any taxes arising from access to this
-      website or use of the information herein, except for those based on
-      Unicode’s net income.
-
-   4. Severability.  If any provision of this Agreement is declared invalid or
-      unenforceable, the remaining provisions of this Agreement shall remain
-      in effect.
-
-   5. Entire Agreement. This Agreement constitutes the entire agreement
-      between the parties.
-
-EXHIBIT 1
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-Unicode Data Files include all data files under the directories
-http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
-http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
-online code charts under the directory http://www.unicode.org/Public/.
-Software includes any source code published in the Unicode Standard or under
-the directories http://www.unicode.org/Public/,
-http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
-
-NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
-INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
-FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
-BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
-AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
-SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under the
-Terms of Use in http://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the Unicode data files and any associated documentation (the "Data Files")
-or Unicode software and any associated documentation (the "Software") to deal
-in the Data Files or Software without restriction, including without
-limitation the rights to use, copy, modify, merge, publish, distribute, and/or
-sell copies of the Data Files or Software, and to permit persons to whom the
-Data Files or Software are furnished to do so, provided that (a) the above
-copyright notice(s) and this permission notice appear with all copies of the
-Data Files or Software, (b) both the above copyright notice(s) and this
-permission notice appear in associated documentation, and (c) there is clear
-notice in each modified Data File or in the Software as well as in the
-documentation associated with the Data File(s) or Software that the data or
-software has been modified.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
-THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
-DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in these Data Files or Software without prior written authorization of the
-copyright holder.
-
-Unicode and the Unicode logo are trademarks of Unicode, Inc. in the United
-States and other countries. All third party trademarks referenced herein are
-the property of their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to UPX v3.01, which may be included 
-with JRE 8 on Windows.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-
-                 ooooo     ooo ooooooooo.   ooooooo  ooooo
-                 `888'     `8' `888   `Y88.  `8888    d8'
-                  888       8   888   .d88'    Y888..8P
-                  888       8   888ooo88P'      `8888'
-                  888       8   888            .8PY888.
-                  `88.    .8'   888           d8'  `888b
-                    `YbodP'    o888o        o888o  o88888o
-
-
-                    The Ultimate Packer for eXecutables
-          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
-               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
-                          http://www.nexus.hu/upx
-                            http://upx.tsx.org
-
-
-PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
-TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
-
-
-ABSTRACT
-========
-
-   UPX and UCL are copyrighted software distributed under the terms
-   of the GNU General Public License (hereinafter the "GPL").
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   As a special exception we grant the free usage of UPX for all
-   executables, including commercial programs.
-   See below for details and restrictions.
-
-
-COPYRIGHT
-=========
-
-   UPX and UCL are copyrighted software. All rights remain with the authors.
-
-   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-   UPX is Copyright (C) 1996-2000 Laszlo Molnar
-
-   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-
-
-GNU GENERAL PUBLIC LICENSE
-==========================
-
-   UPX and the UCL library are free software; you can redistribute them
-   and/or modify them under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   UPX and UCL are distributed in the hope that they will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; see the file COPYING.
-
-
-SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
-============================================
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
-   permission to freely use and distribute all UPX compressed programs
-   (including commercial ones), subject to the following restrictions:
-
-   1. You must compress your program with a completely unmodified UPX
-      version; either with our precompiled version, or (at your option)
-      with a self compiled version of the unmodified UPX sources as
-      distributed by us.
-   2. This also implies that the UPX stub must be completely unmodfied, i.e.
-      the stub imbedded in your compressed program must be byte-identical
-      to the stub that is produced by the official unmodified UPX version.
-   3. The decompressor and any other code from the stub must exclusively get
-      used by the unmodified UPX stub for decompressing your program at
-      program startup. No portion of the stub may get read, copied,
-      called or otherwise get used or accessed by your program.
-
-
-ANNOTATIONS
-===========
-
-  - You can use a modified UPX version or modified UPX stub only for
-    programs that are compatible with the GNU General Public License.
-
-  - We grant you special permission to freely use and distribute all UPX
-    compressed programs. But any modification of the UPX stub (such as,
-    but not limited to, removing our copyright string or making your
-    program non-decompressible) will immediately revoke your right to
-    use and distribute a UPX compressed program.
-
-  - UPX is not a software protection tool; by requiring that you use
-    the unmodified UPX version for your proprietary programs we
-    make sure that any user can decompress your program. This protects
-    both you and your users as nobody can hide malicious code -
-    any program that cannot be decompressed is highly suspicious
-    by definition.
-
-  - You can integrate all or part of UPX and UCL into projects that
-    are compatible with the GNU GPL, but obviously you cannot grant
-    any special exceptions beyond the GPL for our code in your project.
-
-  - We want to actively support manufacturers of virus scanners and
-    similar security software. Please contact us if you would like to
-    incorporate parts of UPX or UCL into such a product.
-
-
-
-Markus F.X.J. Oberhumer                   Laszlo Molnar
-markus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu
-
-Linz, Austria, 25 Feb 2000
-
-Additional License(s)
-
-The UPX license file is at http://upx.sourceforge.net/upx-license.html.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Xfree86-VidMode Extension 1.0,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Version 1.1 of XFree86 ProjectLicence.
-
-Copyright (C) 1994-2004 The XFree86 Project, Inc.    All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicence, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so,subject to the following conditions:
-
-   1. Redistributions of source code must retain the above copyright
-   notice,this list of conditions, and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution, and in the same place
-   and form as other copyright, license and disclaimer information.
-
-   3. The end-user documentation included with the redistribution, if any,must
-   include the following acknowledgment: "This product includes
-   software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and
-   its contributors", in the same place and form as other third-party
-   acknowledgments. Alternately, this acknowledgment may appear in the software
-   itself, in the same form and location as other such third-party
-   acknowledgments.
-
-    4. Except as contained in this notice, the name of The XFree86 Project,Inc
-    shall not be used in advertising or otherwise to promote the sale, use
-    or other dealings in this Software without prior written authorization from
-    The XFree86 Project, Inc.
-
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-    WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-    EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-    DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-    DAMAGE.  
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to X Window System 6.8.2, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-          Licenses
-The X.Org Foundation March 2004
-
-1. Introduction
-
-The X.org Foundation X Window System distribution is a compilation of code and
-documentation from many sources. This document is intended primarily as a
-guide to the licenses used in the distribution: you must check each file
-and/or package for precise redistribution terms. None-the-less, this summary
-may be useful to many users. No software incorporating the XFree86 1.1 license
-has been incorporated.
-
-This document is based on the compilation from XFree86.
-
-2. XFree86 License
-
-XFree86 code without an explicit copyright is covered by the following
-copyright/license:
-
-Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the XFree86 Project shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from the XFree86 Project.
-
-3. Other Licenses
-
-Portions of code are covered by the following licenses/copyrights. See
-individual files for the copyright dates.
-
-3.1. X/MIT Copyrights
-
-3.1.1. X Consortium
-
-Copyright (C) <date> X Consortium
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
-CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from the X Consortium.
-
-X Window System is a trademark of X Consortium, Inc.
-
-3.1.2. The Open Group
-
-Copyright <date> The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation.
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from The Open Group.  3.2.
-Berkeley-based copyrights:
-
-o
-3.2.1. General
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.2. UCB/LBL
-
-Copyright (c) 1993 The Regents of the University of California. All rights
-reserved.
-
-This software was developed by the Computer Systems Engineering group at
-Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to
-Berkeley.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement: This product includes software
-developed by the University of California, Lawrence Berkeley Laboratory.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the University of California, Berkeley and its contributors.
-
-   4. Neither the name of the University nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.3. The
-NetBSD Foundation, Inc.
-
-Copyright (c) 2003 The NetBSD Foundation, Inc. All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation by Ben
-Collver <collver1@attbi.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the NetBSD Foundation, Inc. and its contributors.
-
-   4. Neither the name of The NetBSD Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS
-IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.4. Theodore
-Ts'o.
-
-Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   and the entire permission notice in its entirety, including the disclaimer
-   of warranties.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. he name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.5. Theo de Raadt and Damien Miller
-
-Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. Copyright (c)
-2001-2002 Damien Miller. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.6. Todd C. Miller
-
-Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  3.2.7. Thomas
-Winischhofer
-
-Copyright (C) 2001-2004 Thomas Winischhofer
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.3. NVIDIA Corp
-
-Copyright (c) 1996 NVIDIA, Corp. All rights reserved.
-
-NOTICE TO USER: The source code is copyrighted under U.S. and international
-laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design
-patents pending on the design and interface of the NV chips. Users and
-possessors of this source code are hereby granted a nonexclusive, royalty-free
-copyright and design patent license to use this code in individual and
-commercial software.
-
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
-
-Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and
-foreign countries.
-
-NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
-CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
-WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE
-FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.  3.4. GLX Public
-License
-
-GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License")
-
-Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby
-grants permission to Recipient (defined below), under Recipient's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below), and to permit persons to whom the Subject Software is
-furnished in accordance with this License to do the same, subject to all of
-the following terms and conditions, which Recipient accepts by engaging in any
-such use, copying, modifying, merging, publishing, distributing, sublicensing
-or selling:
-
-1. Definitions.
-
-    (a) "Original Software" means source code of computer software code which
-    is described in Exhibit A as Original Software.
-
-    (b) "Modifications" means any addition to or deletion from the substance
-    or structure of either the Original Software or any previous
-    Modifications. When Subject Software is released as a series of files, a
-    Modification means (i) any addition to or deletion from the contents of a
-    file containing Original Software or previous Modifications and (ii) any
-    new file that contains any part of the Original Code or previous
-    Modifications.
-
-    (c) "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    (d) "Recipient" means an individual or a legal entity exercising rights
-    under, and complying with all of the terms of, this License. For legal
-    entities, "Recipient" includes any entity which controls, is controlled
-    by, or is under common control with Recipient. For purposes of this
-    definition, "control" of an entity means (a) the power, direct or
-    indirect, to direct or manage such entity, or (b) ownership of fifty
-    percent (50%) or more of the outstanding shares or beneficial ownership of
-    such entity.
-
-2. Redistribution of Source Code Subject to These Terms. Redistributions of
-Subject Software in source code form must retain the notice set forth in
-Exhibit A, below, in every file. A copy of this License must be included in
-any documentation for such Subject Software where the recipients' rights
-relating to Subject Software are described. Recipient may distribute the
-source code version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the source code version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-3. Redistribution in Executable Form. The notice set forth in Exhibit A must
-be conspicuously included in any notice in an executable version of Subject
-Software, related documentation or collateral in which Recipient describes the
-user's rights relating to the Subject Software. Recipient may distribute the
-executable version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the executable version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-4. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software which is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-5. No Trademark Rights. This License does not grant any rights to use any
-trade name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from
-the Subject Software without prior written permission of SGI.
-
-6. No Other Rights. This License does not grant any rights with respect to the
-OpenGL API or to any software or hardware implementation thereof or to any
-other software whatsoever, nor shall any other rights or licenses not
-expressly granted hereunder arise by implication, estoppel or otherwise with
-respect to the Subject Software. Title to and ownership of the Original
-Software at all times remains with SGI. All rights in the Original Software
-not expressly granted under this License are reserved.
-
-7. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-8. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Exhibit A notice required under Sections 2 and 3,
-above, and in the text of any related documentation, license agreement or
-collateral in which Recipient describes end user's rights relating to the
-Subject Software. If Recipient obtains such knowledge after it makes Subject
-Software available to any other person or entity, Recipient shall take other
-steps (such as notifying appropriate mailing lists or newsgroups) reasonably
-calculated to inform those who received the Subject Software that new
-knowledge has been obtained.
-
-9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
-STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF
-THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY
-TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO
-THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT.
-
-11. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from
-and against any loss, liability, damages, costs or expenses (including the
-payment of reasonable attorneys fees) arising out of Recipient's use,
-modification, reproduction and distribution of the Subject Software or out of
-any representation or warranty made by Recipient.
-
-12. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-13. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed so as to achieve as nearly as
-possible the same economic effect as the original provision and the remainder
-of this License will remain in effect. This License shall be governed by and
-construed in accordance with the laws of the United States and the State of
-California as applied to agreements entered into and to be performed entirely
-within California between California residents. Any litigation relating to
-this License shall be subject to the exclusive jurisdiction of the Federal
-Courts of the Northern District of California (or, absent subject matter
-jurisdiction in such courts, the courts of the State of California), with
-venue lying exclusively in Santa Clara County, California, with the losing
-party responsible for costs, including without limitation, court costs and
-reasonable attorneys fees and expenses. The application of the United Nations
-Convention on Contracts for the International Sale of Goods is expressly
-excluded. Any law or regulation which provides that the language of a contract
-shall be construed against the drafter shall not apply to this License.
-
-Exhibit A
-
-The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13
-of the GLX Public License Version 1.0 (the "License"). You may not use this
-file except in compliance with those sections of the License. You may obtain a
-copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N.
-Shoreline Blvd., Mountain View, CA 94043 or at
-http://www.sgi.com/software/opensource/glx/license.html.
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON-
-INFRINGEMENT. See the License for the specific language governing rights and
-limitations under the License.
-
-The Original Software is GLX version 1.2 source code, released February, 1999.
-The developer of the Original Software is Silicon Graphics, Inc. Those
-portions of the Subject Software created by Silicon Graphics, Inc. are
-Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.  3.5. CID
-Font Code Public License
-
-CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License")
-
-Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI")
-hereby grants permission to Recipient (defined below), under SGI's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below) in both source code and executable form, and to permit persons
-to whom the Subject Software is furnished in accordance with this License to
-do the same, subject to all of the following terms and conditions, which
-Recipient accepts by engaging in any such use, copying, modifying, merging,
-publication, distributing, sublicensing or selling:
-
-1. Definitions.
-
-    a. "Original Software" means source code of computer software code that is
-    described in Exhibit A as Original Software.
-
-    b. "Modifications" means any addition to or deletion from the substance or
-    structure of either the Original Software or any previous Modifications.
-    When Subject Software is released as a series of files, a Modification
-    means (i) any addition to or deletion from the contents of a file
-    containing Original Software or previous Modifications and (ii) any new
-    file that contains any part of the Original Code or previous
-    Modifications.
-
-    c. "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    d. "Recipient" means an individual or a legal entity exercising rights
-    under the terms of this License. For legal entities, "Recipient" includes
-    any entity that controls, is controlled by, or is under common control
-    with Recipient. For purposes of this definition, "control" of an entity
-    means (i) the power, direct or indirect, to direct or manage such entity,
-    or (ii) ownership of fifty percent (50%) or more of the outstanding shares
-    or beneficial ownership of such entity.
-
-    e. "Required Notice" means the notice set forth in Exhibit A to this
-    License.
-
-    f. "Accompanying Technology" means any software or other technology that
-    is not a Modification and that is distributed or made publicly available
-    by Recipient with the Subject Software. Separate software files that do
-    not contain any Original Software or any previous Modification shall not
-    be deemed a Modification, even if such software files are aggregated as
-    part of a product, or in any medium of storage, with any file that does
-    contain Original Software or any previous Modification.
-
-2. License Terms. All distribution of the Subject Software must be made
-subject to the terms of this License. A copy of this License and the Required
-Notice must be included in any documentation for Subject Software where
-Recipient's rights relating to Subject Software and/or any Accompanying
-Technology are described. Distributions of Subject Software in source code
-form must also include the Required Notice in every file distributed. In
-addition, a ReadMe file entitled "Important Legal Notice" must be distributed
-with each distribution of one or more files that incorporate Subject Software.
-That file must be included with distributions made in both source code and
-executable form. A copy of the License and the Required Notice must be
-included in that file. Recipient may distribute Accompanying Technology under
-a license of Recipient's choice, which may contain terms different from this
-License, provided that (i) Recipient is in compliance with the terms of this
-License, (ii) such other license terms do not modify or supersede the terms of
-this License as applicable to the Subject Software, (iii) Recipient hereby
-indemnifies SGI for any liability incurred by SGI as a result of the
-distribution of Accompanying Technology or the use of other license terms.
-
-3. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software that is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-4. Trademark Rights. This License does not grant any rights to use any trade
-name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from or
-incorporating any Subject Software without prior written permission of SGI.
-
-5. No Other Rights. No rights or licenses not expressly granted hereunder
-shall arise by implication, estoppel or otherwise. Title to and ownership of
-the Original Software at all times remains with SGI. All rights in the
-Original Software not expressly granted under this License are reserved.
-
-6. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity, or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-7. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Required Notice, and in the text of any related
-documentation, license agreement or collateral in which Recipient describes
-end user's rights relating to the Subject Software. If Recipient obtains such
-knowledge after it makes Subject Software available to any other person or
-entity, Recipient shall take other steps (such as notifying appropriate
-mailing lists or newsgroups) reasonably calculated to provide such knowledge
-to those who received the Subject Software.
-
-8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND
-LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED.
-
-10. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold SGI and its successors and assigns
-harmless from and against any loss, liability, damages, costs or expenses
-(including the payment of reasonable attorneys fees) arising out of
-(Recipient's use, modification, reproduction and distribution of the Subject
-Software or out of any representation or warranty made by Recipient.
-
-11. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-12. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable by any judicial or administrative authority having proper
-jurisdiction with respect thereto, such provision shall be reformed so as to
-achieve as nearly as possible the same economic effect as the original
-provision and the remainder of this License will remain in effect. This
-License shall be governed by and construed in accordance with the laws of the
-United States and the State of California as applied to agreements entered
-into and to be performed entirely within California between California
-residents. Any litigation relating to this License shall be subject to the
-exclusive jurisdiction of the Federal Courts of the Northern District of
-California (or, absent subject matter jurisdiction in such courts, the courts
-of the State of California), with venue lying exclusively in Santa Clara
-County, California, with the losing party responsible for costs, including
-without limitation, court costs and reasonable attorneys fees and expenses.
-The application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded. Any law or regulation that
-provides that the language of a contract shall be construed against the
-drafter shall not apply to this License.
-
-Exhibit A
-
-Copyright (c) 1994-1999 Silicon Graphics, Inc.
-
-The contents of this file are subject to the CID Font Code Public License
-Version 1.0 (the "License"). You may not use this file except in compliance
-with the License. You may obtain a copy of the License at Silicon Graphics,
-Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
-or at http://www.sgi.com/software/opensource/cid/license.html
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF
-NON-INFRINGEMENT. See the License for the specific language governing rights
-and limitations under the License.
-
-The Original Software (as defined in the License) is CID font code that was
-developed by Silicon Graphics, Inc. Those portions of the Subject Software (as
-defined in the License) that were created by Silicon Graphics, Inc. are
-Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved.
-
-[NOTE: When using this text in connection with Subject Software delivered
-solely in object code form, Recipient may replace the words "this file" with
-"this software" in both the first and second sentences.] 3.6. Bitstream Vera
-Fonts Copyright
-
-The fonts have a generous copyright, allowing derivative works (as long as
-"Bitstream" or "Vera" are not in the names), and full redistribution (so long
-as they are not *sold* by themselves). They can be be bundled, redistributed
-and sold with any software.
-
-The fonts are distributed under the following copyright:
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.  3.7. Bigelow & Holmes
-Inc and URW++ GmbH Luxi font license
-
-Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font instruction
-code copyright (c) 2001 by URW++ GmbH. All Rights Reserved. Luxi is a
-registered trademark of Bigelow & Holmes Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of these Fonts and associated documentation files (the "Font Software"), to
-deal in the Font Software, including without limitation the rights to use,
-copy, merge, publish, distribute, sublicense, and/or sell copies of the Font
-Software, and to permit persons to whom the Font Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software.
-
-The Font Software may not be modified, altered, or added to, and in particular
-the designs of glyphs or characters in the Fonts may not be modified nor may
-additional glyphs or characters be added to the Fonts. This License becomes
-null and void when the Fonts or Font Software have been modified.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BIGELOW & HOLMES INC. OR URW++
-GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
-GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
-Except as contained in this notice, the names of Bigelow & Holmes Inc. and
-URW++ GmbH. shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Font Software without prior written
-authorization from Bigelow & Holmes Inc. and URW++ GmbH.
-
-For further information, contact:
-
-info@urwpp.de or design@bigelowandholmes.com
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to zlib v1.2.5, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-  version 1.2.5, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to the following which may be 
-included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
-
-  Apache Commons Math 2.2
-  Apache Derby 10.10.1.2        [included with JDK 8]
-  Apache Jakarta BCEL 5.2 
-  Apache Jakarta Regexp 1.4 
-  Apache Santuario XML Security for Java 1.5.4
-  Apache Xalan-Java 2.7.1 
-  Apache Xerces Java 2.10.0 
-  Apache XML Resolver 1.1 
-  Dynalink 0.5
-
-
---- begin of LICENSE ---
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk
index c9964cc..2f26a83 100644
--- a/jdk/make/copy/Copy-java.base.gmk
+++ b/jdk/make/copy/Copy-java.base.gmk
@@ -100,8 +100,7 @@
   # Allow override by ALT_JVMCFG_SRC if it exists
   JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC))
 endif
-JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)
-JVMCFG := $(JVMCFG_DIR)/jvm.cfg
+JVMCFG := $(LIB_DST_DIR)/jvm.cfg
 
 # To do: should this also support -zeroshark?
 
@@ -233,3 +232,17 @@
 endif
 
 ################################################################################
+
+# JDK license and assembly exception files to be packaged in JMOD
+
+JDK_LICENSE ?= $(JDK_TOPDIR)/LICENSE
+JDK_NOTICE  ?= $(JDK_TOPDIR)/ASSEMBLY_EXCEPTION
+
+$(eval $(call SetupCopyFiles, COPY_JDK_NOTICES, \
+    FILES := $(JDK_LICENSE) $(JDK_NOTICE), \
+    DEST := $(LEGAL_DST_DIR), \
+    FLATTEN := true, \
+))
+
+TARGETS += $(COPY_JDK_NOTICES)
+
diff --git a/jdk/make/copy/Copy-java.desktop.gmk b/jdk/make/copy/Copy-java.desktop.gmk
index 51db98a..49d6b86 100644
--- a/jdk/make/copy/Copy-java.desktop.gmk
+++ b/jdk/make/copy/Copy-java.desktop.gmk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,7 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype)
   else
-    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)/$(call SHARED_LIBRARY,freetype).6
+    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
   endif
 
   # We can't use $(install-file) in this rule because it preserves symbolic links and
diff --git a/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk b/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk
deleted file mode 100644
index b9771de..0000000
--- a/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include CopyCommon.gmk
-
-################################################################################
-
-ifeq ($(OPENJDK_TARGET_OS), solaris)
-
-  SUNPKCS11_CFG_SRC := \
-      $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg
-  SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
-
-  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
-	$(call install-file)
-
-  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
-
-  TARGETS := $(SUNPKCS11_CFG_DST)
-
-endif
-
-################################################################################
diff --git a/jdk/make/copy/Copy-jdk.crypto.token.gmk b/jdk/make/copy/Copy-jdk.crypto.token.gmk
new file mode 100644
index 0000000..d35f655
--- /dev/null
+++ b/jdk/make/copy/Copy-jdk.crypto.token.gmk
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+  SUNPKCS11_CFG_SRC := \
+      $(JDK_TOPDIR)/src/jdk.crypto.token/solaris/conf/security/sunpkcs11-solaris.cfg
+  SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
+
+  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
+	$(call install-file)
+
+  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
+
+  TARGETS := $(SUNPKCS11_CFG_DST)
+
+endif
+
+################################################################################
diff --git a/jdk/make/copy/CopyCommon.gmk b/jdk/make/copy/CopyCommon.gmk
index cb87c80..c82edd2 100644
--- a/jdk/make/copy/CopyCommon.gmk
+++ b/jdk/make/copy/CopyCommon.gmk
@@ -26,6 +26,7 @@
 INCLUDE_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_include/$(MODULE)
 LIB_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)
 CONF_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_conf/$(MODULE)
+LEGAL_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_legal/$(MODULE)
 
 INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/$(OPENJDK_TARGET_OS)
 
diff --git a/jdk/make/launcher/Launcher-java.base.gmk b/jdk/make/launcher/Launcher-java.base.gmk
index 4d4b981..f70d900 100644
--- a/jdk/make/launcher/Launcher-java.base.gmk
+++ b/jdk/make/launcher/Launcher-java.base.gmk
@@ -74,7 +74,7 @@
 BUILD_JEXEC :=
 BUILD_JEXEC_SRC :=
 BUILD_JEXEC_INC :=
-BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 
 #
 # UNHANDLED:
@@ -138,7 +138,7 @@
 BUILD_JSPAWNHELPER :=
 BUILD_JSPAWNHELPER_SRC := $(JDK_TOPDIR)/src/java.base/unix/native/jspawnhelper
 JSPAWNHELPER_CFLAGS := -I$(JDK_TOPDIR)/src/java.base/unix/native/libjava
-BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 LINK_JSPAWNHELPER_OBJECTS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjava/childproc.o
 BUILD_JSPAWNHELPER_LDFLAGS :=
 
diff --git a/jdk/make/launcher/Launcher-jdk.aot.gmk b/jdk/make/launcher/Launcher-jdk.aot.gmk
new file mode 100644
index 0000000..a827a66
--- /dev/null
+++ b/jdk/make/launcher/Launcher-jdk.aot.gmk
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, jaotc, \
+    MAIN_CLASS := jdk.tools.jaotc.Main, \
+    JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
+        -XX:+UseAOT \
+        -Djvmci.UseProfilingInformation=false \
+        -Dgraal.UseExceptionProbability=false \
+        -Djvmci.Compiler=graal \
+        --add-modules ALL-DEFAULT \
+    , \
+))
diff --git a/jdk/make/launcher/Launcher-jdk.jshell.gmk b/jdk/make/launcher/Launcher-jdk.jshell.gmk
index e80876f..349eb88 100644
--- a/jdk/make/launcher/Launcher-jdk.jshell.gmk
+++ b/jdk/make/launcher/Launcher-jdk.jshell.gmk
@@ -26,6 +26,6 @@
 include LauncherCommon.gmk
 
 $(eval $(call SetupBuildLauncher, jshell, \
-    MAIN_CLASS := jdk.internal.jshell.tool.JShellTool, \
+    MAIN_CLASS := jdk.internal.jshell.tool.JShellToolProvider, \
     CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \
 ))
diff --git a/jdk/make/launcher/Launcher-jdk.pack.gmk b/jdk/make/launcher/Launcher-jdk.pack.gmk
new file mode 100644
index 0000000..2ee08c7
--- /dev/null
+++ b/jdk/make/launcher/Launcher-jdk.pack.gmk
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, pack200, \
+    MAIN_MODULE := java.base, \
+    MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
+))
+
+################################################################################
+# The order of the object files on the link command line affects the size of the resulting
+# binary (at least on linux) which causes the size to differ between old and new build.
+
+UNPACKEXE_SRC := $(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+    $(JDK_TOPDIR)/src/jdk.pack/share/native/unpack200
+UNPACKEXE_CFLAGS := -I$(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+    -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
+    -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava
+
+ifeq ($(USE_EXTERNAL_LIBZ), true)
+  UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB
+  UNPACKEXE_LIBS := -lz
+else
+  UNPACKEXE_CFLAGS += -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8
+  UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/deflate$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/trees$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zadler32$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/compress$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zutil$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inflate$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/infback$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inftrees$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inffast$(OBJ_SUFFIX)
+
+endif
+
+UNPACK_MAPFILE_DIR := $(JDK_TOPDIR)/make/mapfiles/libunpack
+UNPACK_MAPFILE_PLATFORM_FILE := \
+    $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH)
+
+# The linker on older SuSE distros (e.g. on SLES 10) complains with:
+# "Invalid version tag `SUNWprivate_1.1'. Only anonymous version tag is allowed in executable."
+# if feeded with a version script which contains named tags.
+ifeq ($(USING_BROKEN_SUSE_LD), yes)
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200.anonymous
+else ifneq ($(wildcard $(UNPACK_MAPFILE_PLATFORM_FILE)), )
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_PLATFORM_FILE)
+else
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200
+endif
+
+$(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \
+    SRC := $(UNPACKEXE_SRC), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \
+    CFLAGS_release := -DPRODUCT, \
+    CFLAGS_linux := -fPIC, \
+    CFLAGS_solaris := -KPIC, \
+    CFLAGS_macosx := -fPIC, \
+    DISABLED_WARNINGS_gcc := unused-result, \
+    MAPFILE := $(UNPACK_MAPFILE),\
+    LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
+        $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
+    LIBS_solaris :=  -lc, \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe, \
+    OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/$(MODULE), \
+    PROGRAM := unpack200, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=unpack200.exe" \
+        -D "JDK_INTERNAL_NAME=unpack200" \
+        -D "JDK_FTYPE=0x1L", \
+    MANIFEST := $(JDK_TOPDIR)/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest, \
+    MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \
+))
+
+ifneq ($(USE_EXTERNAL_LIBZ), true)
+
+  $(BUILD_UNPACKEXE): $(UNPACKEXE_ZIPOBJS)
+
+endif
+
+TARGETS += $(BUILD_UNPACKEXE)
+
+################################################################################
diff --git a/jdk/make/launcher/Launcher-jdk.pack200.gmk b/jdk/make/launcher/Launcher-jdk.pack200.gmk
deleted file mode 100644
index 32b29b0..0000000
--- a/jdk/make/launcher/Launcher-jdk.pack200.gmk
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LauncherCommon.gmk
-
-$(eval $(call SetupBuildLauncher, pack200, \
-    MAIN_MODULE := java.base, \
-    MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
-))
-
-################################################################################
-# The order of the object files on the link command line affects the size of the resulting
-# binary (at least on linux) which causes the size to differ between old and new build.
-
-UNPACKEXE_SRC := $(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-    $(JDK_TOPDIR)/src/jdk.pack200/share/native/unpack200
-UNPACKEXE_CFLAGS := -I$(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-    -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
-    -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava
-
-ifeq ($(USE_EXTERNAL_LIBZ), true)
-  UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB
-  UNPACKEXE_LIBS := -lz
-else
-  UNPACKEXE_CFLAGS += -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8
-  UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/deflate$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/trees$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zadler32$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/compress$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zutil$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inflate$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/infback$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inftrees$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inffast$(OBJ_SUFFIX)
-
-endif
-
-UNPACK_MAPFILE_DIR := $(JDK_TOPDIR)/make/mapfiles/libunpack
-UNPACK_MAPFILE_PLATFORM_FILE := \
-    $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH)
-
-# The linker on older SuSE distros (e.g. on SLES 10) complains with:
-# "Invalid version tag `SUNWprivate_1.1'. Only anonymous version tag is allowed in executable."
-# if feeded with a version script which contains named tags.
-ifeq ($(USING_BROKEN_SUSE_LD), yes)
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200.anonymous
-else ifneq ($(wildcard $(UNPACK_MAPFILE_PLATFORM_FILE)), )
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_PLATFORM_FILE)
-else
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200
-endif
-
-$(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \
-    SRC := $(UNPACKEXE_SRC), \
-    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \
-    CFLAGS_release := -DPRODUCT, \
-    CFLAGS_linux := -fPIC, \
-    CFLAGS_solaris := -KPIC, \
-    CFLAGS_macosx := -fPIC, \
-    DISABLED_WARNINGS_gcc := unused-result, \
-    MAPFILE := $(UNPACK_MAPFILE),\
-    LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
-        $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
-    LIBS_solaris :=  -lc, \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe, \
-    OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/$(MODULE), \
-    PROGRAM := unpack200, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=unpack200.exe" \
-        -D "JDK_INTERNAL_NAME=unpack200" \
-        -D "JDK_FTYPE=0x1L", \
-    MANIFEST := $(JDK_TOPDIR)/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest, \
-    MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \
-))
-
-ifneq ($(USE_EXTERNAL_LIBZ), true)
-
-  $(BUILD_UNPACKEXE): $(UNPACKEXE_ZIPOBJS)
-
-endif
-
-TARGETS += $(BUILD_UNPACKEXE)
-
-################################################################################
diff --git a/jdk/make/launcher/LauncherCommon.gmk b/jdk/make/launcher/LauncherCommon.gmk
index 1bef88f..a417803 100644
--- a/jdk/make/launcher/LauncherCommon.gmk
+++ b/jdk/make/launcher/LauncherCommon.gmk
@@ -32,13 +32,13 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     DISABLE_MAPFILES := true
   endif
-  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR)/jli)
+  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib/jli)
 
   # Applications expect to be able to link against libjawt without invoking
   # System.loadLibrary("jawt") first. This was the behaviour described in the
   # devloper documentation of JAWT and what worked with OpenJDK6.
   ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
-    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR))
+    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib)
   endif
 endif
 
@@ -190,9 +190,9 @@
           $$(ORIGIN_ARG) \
           $$($1_LDFLAGS), \
       LDFLAGS_linux := \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       MAPFILE := $$($1_MAPFILE), \
       LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
       LIBS_unix := $$($1_LIBS_unix), \
diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk
index 09423e4..6704346 100644
--- a/jdk/make/lib/Awt2dLibraries.gmk
+++ b/jdk/make/lib/Awt2dLibraries.gmk
@@ -418,6 +418,7 @@
     DISABLED_WARNINGS_gcc := format-nonliteral type-limits misleading-indentation, \
     DISABLED_WARNINGS_clang := tautological-compare, \
     DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
+    DISABLED_WARNINGS_microsoft := 4819, \
     MAPFILE := $(JDK_TOPDIR)/make/mapfiles/liblcms/mapfile-vers, \
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
@@ -681,7 +682,7 @@
     DISABLED_WARNINGS_CXX_solstudio := \
         truncwarn wvarhidenmem wvarhidemem wbadlkginit identexpected \
         hidevf w_novirtualdescr arrowrtn2, \
-    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334, \
+    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334 4819, \
     MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \
     LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk
index 27dad35..6fba2fa 100644
--- a/jdk/make/lib/CoreLibraries.gmk
+++ b/jdk/make/lib/CoreLibraries.gmk
@@ -340,9 +340,6 @@
 
 LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS))
 
-# Append defines depending on target platform
-LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
-
 ifneq ($(USE_EXTERNAL_LIBZ), true)
   LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
   LIBJLI_EXTRA_FILES += \
diff --git a/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk b/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk
deleted file mode 100644
index 82618b1..0000000
--- a/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LibCommon.gmk
-
-################################################################################
-
-LIBJ2PKCS11_SRC := $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/share/native/libj2pkcs11 \
-    $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/$(OPENJDK_TARGET_OS_TYPE)/native/libj2pkcs11
-
-$(eval $(call SetupNativeCompilation,BUILD_LIBJ2PKCS11, \
-    LIBRARY := j2pkcs11, \
-    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-    SRC := $(LIBJ2PKCS11_SRC), \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2PKCS11_SRC)) \
-        $(LIBJAVA_HEADER_FLAGS) \
-        -I$(SUPPORT_OUTPUTDIR)/headers/jdk.crypto.pkcs11, \
-    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2pkcs11/mapfile-vers, \
-    LDFLAGS := $(LDFLAGS_JDKLIB) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LIBS_unix := $(LIBDL), \
-    LIBS_solaris := -lc, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=j2pkcs11.dll" \
-        -D "JDK_INTERNAL_NAME=j2pkcs11" \
-        -D "JDK_FTYPE=0x2L", \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libj2pkcs11, \
-))
-
-TARGETS += $(BUILD_LIBJ2PKCS11)
-
-################################################################################
diff --git a/jdk/make/lib/Lib-jdk.crypto.token.gmk b/jdk/make/lib/Lib-jdk.crypto.token.gmk
new file mode 100644
index 0000000..9e015be
--- /dev/null
+++ b/jdk/make/lib/Lib-jdk.crypto.token.gmk
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+LIBJ2PKCS11_SRC := $(JDK_TOPDIR)/src/jdk.crypto.token/share/native/libj2pkcs11 \
+    $(JDK_TOPDIR)/src/jdk.crypto.token/$(OPENJDK_TARGET_OS_TYPE)/native/libj2pkcs11
+
+$(eval $(call SetupNativeCompilation,BUILD_LIBJ2PKCS11, \
+    LIBRARY := j2pkcs11, \
+    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+    SRC := $(LIBJ2PKCS11_SRC), \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2PKCS11_SRC)) \
+        $(LIBJAVA_HEADER_FLAGS) \
+        -I$(SUPPORT_OUTPUTDIR)/headers/jdk.crypto.token, \
+    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2pkcs11/mapfile-vers, \
+    LDFLAGS := $(LDFLAGS_JDKLIB) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LIBS_unix := $(LIBDL), \
+    LIBS_solaris := -lc, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=j2pkcs11.dll" \
+        -D "JDK_INTERNAL_NAME=j2pkcs11" \
+        -D "JDK_FTYPE=0x2L", \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libj2pkcs11, \
+))
+
+TARGETS += $(BUILD_LIBJ2PKCS11)
+
+################################################################################
diff --git a/jdk/make/lib/Lib-jdk.pack.gmk b/jdk/make/lib/Lib-jdk.pack.gmk
new file mode 100644
index 0000000..cc482c9
--- /dev/null
+++ b/jdk/make/lib/Lib-jdk.pack.gmk
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+$(eval $(call SetupNativeCompilation,BUILD_LIBUNPACK, \
+    LIBRARY := unpack, \
+    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+    SRC := $(JDK_TOPDIR)/src/jdk.pack/share/native/libunpack \
+        $(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack, \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(CXXFLAGS_JDKLIB) \
+        -DNO_ZLIB -DUNPACK_JNI -DFULL \
+        -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+        -I$(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+        $(LIBJAVA_HEADER_FLAGS), \
+    CFLAGS_release := -DPRODUCT, \
+    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers, \
+    LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
+    LIBS_unix := -ljvm $(LIBCXX) -ljava -lc, \
+    LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libunpack, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=unpack.dll" \
+        -D "JDK_INTERNAL_NAME=unpack" \
+        -D "JDK_FTYPE=0x2L", \
+))
+
+$(BUILD_LIBUNPACK): $(call FindLib, java.base, java)
+
+TARGETS += $(BUILD_LIBUNPACK)
+
+################################################################################
diff --git a/jdk/make/lib/Lib-jdk.pack200.gmk b/jdk/make/lib/Lib-jdk.pack200.gmk
deleted file mode 100644
index 7f942fc..0000000
--- a/jdk/make/lib/Lib-jdk.pack200.gmk
+++ /dev/null
@@ -1,61 +0,0 @@
-#
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LibCommon.gmk
-
-################################################################################
-
-$(eval $(call SetupNativeCompilation,BUILD_LIBUNPACK, \
-    LIBRARY := unpack, \
-    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-    SRC := $(JDK_TOPDIR)/src/jdk.pack200/share/native/libunpack \
-        $(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack, \
-    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(CXXFLAGS_JDKLIB) \
-        -DNO_ZLIB -DUNPACK_JNI -DFULL \
-        -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
-        -I$(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-        $(LIBJAVA_HEADER_FLAGS), \
-    CFLAGS_release := -DPRODUCT, \
-    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers, \
-    LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
-    LIBS_unix := -ljvm $(LIBCXX) -ljava -lc, \
-    LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libunpack, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=unpack.dll" \
-        -D "JDK_INTERNAL_NAME=unpack" \
-        -D "JDK_FTYPE=0x2L", \
-))
-
-$(BUILD_LIBUNPACK): $(call FindLib, java.base, java)
-
-TARGETS += $(BUILD_LIBUNPACK)
-
-################################################################################
diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers
index 5d7cc4a..c08bc2c 100644
--- a/jdk/make/mapfiles/libjava/mapfile-vers
+++ b/jdk/make/mapfiles/libjava/mapfile-vers
@@ -114,6 +114,7 @@
 		Java_java_io_UnixFileSystem_getBooleanAttributes0;
 		Java_java_io_UnixFileSystem_getLastModifiedTime;
 		Java_java_io_UnixFileSystem_getLength;
+		Java_java_io_UnixFileSystem_getNameMax0;
 		Java_java_io_UnixFileSystem_getSpace;
 		Java_java_io_UnixFileSystem_initIDs;
 		Java_java_io_UnixFileSystem_list;
@@ -150,7 +151,6 @@
 		Java_java_lang_StrictMath_atan;
 		Java_java_lang_StrictMath_atan2;
 		Java_java_lang_StrictMath_cos;
-		Java_java_lang_StrictMath_exp;
 		Java_java_lang_StrictMath_log;
 		Java_java_lang_StrictMath_log10;
 		Java_java_lang_StrictMath_sin;
diff --git a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
index bf0f03b..99f6d0f 100644
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
@@ -26,6 +26,7 @@
 package build.tools.jigsaw;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
@@ -35,14 +36,17 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Function;
-import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
 
 /**
@@ -67,42 +71,25 @@
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> (m.name().startsWith("java.") &&
                                                !m.name().equals("java.smartcardio")))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
         Set<ModuleDescriptor> jdkModules
             = new TreeSet<>(finder.findAll().stream()
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> !javaSEModules.contains(m))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
 
-        GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules);
+        GenGraphs genGraphs = new GenGraphs(dir, javaSEModules, jdkModules);
         Set<String> mods = new HashSet<>();
         for (ModuleReference mref: finder.findAll()) {
-            ModuleDescriptor descriptor = mref.descriptor();
-            String name = descriptor.name();
-            mods.add(name);
-            Configuration cf = Configuration.empty()
-                    .resolveRequires(finder,
-                                     ModuleFinder.of(),
-                                     Set.of(name));
-            genGraphs.genDotFile(dir, name, cf);
+            mods.add(mref.descriptor().name());
+            genGraphs.genDotFile(mref);
         }
 
-        Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 mods);
-        genGraphs.genDotFile(dir, "jdk", cf);
+        // all modules
+        genGraphs.genDotFile("jdk", mods);
 
     }
 
-    private final Set<ModuleDescriptor> javaGroup;
-    private final Set<ModuleDescriptor> jdkGroup;
-
-    GenGraphs(Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
-        this.javaGroup = Collections.unmodifiableSet(javaGroup);
-        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
-    }
-
     private static final String ORANGE = "#e76f00";
     private static final String BLUE = "#437291";
     private static final String GRAY = "#dddddd";
@@ -112,6 +99,7 @@
     private static final String REQUIRES_BASE = "color=\"" + GRAY + "\"";
 
     private static final Map<String,Integer> weights = new HashMap<>();
+    private static final List<Set<String>> ranks = new ArrayList<>();
 
     private static void weight(String s, String t, int w) {
         weights.put(s + ":" + t, w);
@@ -128,23 +116,84 @@
 
     static {
         int h = 1000;
-        weight("java.se", "java.compact3", h * 10);
-        weight("jdk.compact3", "java.compact3", h * 10);
-        weight("java.compact3", "java.compact2", h * 10);
-        weight("java.compact2", "java.compact1", h * 10);
-        weight("java.compact1", "java.logging", h * 10);
-        weight("java.logging", "java.base", h * 10);
+        weight("java.se", "java.sql.rowset", h * 10);
+        weight("java.sql.rowset", "java.sql", h * 10);
+        weight("java.sql", "java.xml", h * 10);
+        weight("java.xml", "java.base", h * 10);
+
+        ranks.add(Set.of("java.logging", "java.scripting", "java.xml"));
+        ranks.add(Set.of("java.sql"));
+        ranks.add(Set.of("java.compiler", "java.instrument"));
+        ranks.add(Set.of("java.desktop", "java.management"));
+        ranks.add(Set.of("java.corba", "java.xml.ws"));
+        ranks.add(Set.of("java.xml.bind", "java.annotations.common"));
+
     }
 
-    private void genDotFile(Path dir, String name, Configuration cf) throws IOException {
-        try (PrintStream out
-                 = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
+    private final Path dir;
+    private final Set<ModuleDescriptor> javaGroup;
+    private final Set<ModuleDescriptor> jdkGroup;
 
-            Map<String, ModuleDescriptor> nameToModule = cf.modules().stream()
-                    .map(ResolvedModule::reference)
-                    .map(ModuleReference::descriptor)
-                    .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
+    GenGraphs(Path dir, Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
+        this.dir = dir;
+        this.javaGroup = Collections.unmodifiableSet(javaGroup);
+        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
+    }
 
+    /**
+     * Generates a dot file for the given module reference as the root.
+     */
+    void genDotFile(ModuleReference mref) throws IOException {
+        String name = mref.descriptor().name();
+        genDotFile(name, Set.of(name));
+    }
+
+    /**
+     * Generates a dot file for the given set of root modules.
+     */
+    void genDotFile(String name, Set<String> roots) throws IOException {
+        Configuration cf =
+            Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
+                                                  ModuleFinder.of(),
+                                                  roots);
+
+        Set<ModuleDescriptor> mds = cf.modules().stream()
+                .map(ResolvedModule::reference)
+                .map(ModuleReference::descriptor)
+                .collect(toSet());
+
+        // generate a dot file for the resolved graph
+        try (OutputStream os = Files.newOutputStream(dir.resolve(name + ".dot"));
+             PrintStream out = new PrintStream(os)) {
+            printGraph(out, name, gengraph(cf),
+                       mds.stream()
+                          .collect(toMap(ModuleDescriptor::name, Function.identity()))
+            );
+        }
+
+        if (name.equals("java.se") || name.equals("java.se.ee")) {
+            // generate a dot file for Java SE module graph
+            try (OutputStream os = Files.newOutputStream(dir.resolve(name + "-spec.dot"));
+                 PrintStream out = new PrintStream(os)) {
+                // transitive reduction on the graph of `requires transitive` edges
+                // filter out jdk.* modules which are implementation dependences
+                Graph<String> graph = requiresTransitiveGraph(cf, true);
+                printGraph(out, name, graph,
+                           mds.stream()
+                              .filter(md -> !md.name().startsWith("jdk.") &&
+                                                graph.nodes().contains(md.name()))
+                              .collect(toMap(ModuleDescriptor::name, Function.identity()))
+                );
+            }
+        }
+    }
+
+    private void printGraph(PrintStream out,
+                            String name,
+                            Graph<String> graph,
+                            Map<String, ModuleDescriptor> nameToModule)
+        throws IOException
+    {
             Set<ModuleDescriptor> descriptors = new TreeSet<>(nameToModule.values());
 
             out.format("digraph \"%s\" {%n", name);
@@ -162,33 +211,45 @@
                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
                                           mn, ORANGE, "java"));
             out.format("}%n");
+
+            // same ranks
+            ranks.stream()
+                .map(group -> descriptors.stream()
+                                         .map(ModuleDescriptor::name)
+                                         .filter(group::contains)
+                                         .map(mn -> "\"" + mn + "\"")
+                                         .collect(joining(",")))
+                .filter(group -> group.length() > 0)
+                .forEach(group -> out.format("{rank=same %s}%n", group));
+
             descriptors.stream()
                 .filter(jdkGroup::contains)
                 .map(ModuleDescriptor::name)
                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
                                           mn, BLUE, "jdk"));
 
-            // transitive reduction
-            Graph<String> graph = gengraph(cf);
-            descriptors.forEach(md -> {
-                String mn = md.name();
-                Set<String> requiresTransitive = md.requires().stream()
-                        .filter(d -> d.modifiers().contains(TRANSITIVE))
-                        .map(d -> d.name())
-                        .collect(Collectors.toSet());
+            descriptors.stream()
+                .forEach(md -> {
+                    String mn = md.name();
+                    Set<String> requiresTransitive = md.requires().stream()
+                            .filter(d -> d.modifiers().contains(TRANSITIVE))
+                            .map(d -> d.name())
+                            .collect(toSet());
 
-                graph.adjacentNodes(mn).forEach(dn -> {
-                    String attr = dn.equals("java.base") ? REQUIRES_BASE
-                            : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
-                    int w = weightOf(mn, dn);
-                    if (w > 1)
-                        attr += "weight=" + w;
-                    out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                    graph.adjacentNodes(mn)
+                         .stream()
+                         .filter(nameToModule::containsKey)
+                         .forEach(dn -> {
+                             String attr = dn.equals("java.base") ? REQUIRES_BASE
+                                    : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
+                             int w = weightOf(mn, dn);
+                             if (w > 1)
+                                 attr += "weight=" + w;
+                             out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                         });
                 });
-            });
 
             out.println("}");
-        }
     }
 
     /**
@@ -208,7 +269,7 @@
                     .map(ResolvedModule::name)
                     .forEach(target -> builder.addEdge(mn, target));
         }
-        Graph<String> rpg = requiresTransitiveGraph(cf);
+        Graph<String> rpg = requiresTransitiveGraph(cf, false);
         return builder.build().reduce(rpg);
     }
 
@@ -216,13 +277,14 @@
      * Returns a Graph containing only requires transitive edges
      * with transitive reduction.
      */
-    private Graph<String> requiresTransitiveGraph(Configuration cf) {
+    private Graph<String> requiresTransitiveGraph(Configuration cf, boolean includeBase) {
         Graph.Builder<String> builder = new Graph.Builder<>();
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
             String mn = descriptor.name();
             descriptor.requires().stream()
-                    .filter(d -> d.modifiers().contains(TRANSITIVE))
+                    .filter(d -> d.modifiers().contains(TRANSITIVE)
+                                    || (includeBase && d.name().equals("java.base")))
                     .map(d -> d.name())
                     .forEach(d -> builder.addEdge(mn, d));
         }
diff --git a/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c b/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c
index c6c3659..f21201c 100644
--- a/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c
+++ b/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c
@@ -171,8 +171,6 @@
  * Main
  */
 
-#define GetArch() GetArchPath(CURRENT_DATA_MODEL)
-
 /* Store the name of the executable once computed */
 static char *execname = NULL;
 
@@ -184,16 +182,6 @@
     return execname;
 }
 
-const char *
-GetArchPath(int nbits)
-{
-    switch(nbits) {
-        default:
-            return LIBARCHNAME;
-    }
-}
-
-
 /*
  * Exports the JNI interface from libjli
  *
@@ -211,7 +199,7 @@
     if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
 
     char jrePath[PATH_MAX];
-    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE);
+    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
     if (!gotJREPath) {
         JLI_ReportErrorMessage("Failed to GetJREPath()");
         return NULL;
@@ -229,7 +217,7 @@
     }
 
     char jvmPath[PATH_MAX];
-    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
+    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), CURRENT_DATA_MODEL);
     if (!gotJVMPath) {
         JLI_ReportErrorMessage("Failed to GetJVMPath()");
         return NULL;
@@ -390,7 +378,6 @@
 
     /* Check data model flags, and exec process, if needed */
     {
-      char *arch        = (char *)GetArch(); /* like sparc or sparcv9 */
       char * jvmtype    = NULL;
       int  argc         = *pargc;
       char **argv       = *pargv;
@@ -462,7 +449,7 @@
          jvmpath does not exist */
       if (wanted == running) {
         /* Find out where the JRE is that we will be using. */
-        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+        if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
           JLI_ReportErrorMessage(JRE_ERROR1);
           exit(2);
         }
@@ -481,7 +468,7 @@
             exit(4);
         }
 
-        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {
+        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted)) {
           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
           exit(4);
         }
@@ -502,7 +489,7 @@
 #if defined(DUAL_MODE)
         if (running != wanted) {
           /* Find out where the JRE is that we will be using. */
-          if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {
+          if (!GetJREPath(jrepath, so_jrepath, JNI_TRUE)) {
             /* give up and let other code report error message */
             JLI_ReportErrorMessage(JRE_ERROR2, wanted);
             exit(1);
@@ -526,7 +513,7 @@
           }
 
           /* exec child can do error checking on the existence of the path */
-          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);
+          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted);
         }
 #else /* ! DUAL_MODE */
         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
@@ -579,7 +566,7 @@
  */
 static jboolean
 GetJVMPath(const char *jrepath, const char *jvmtype,
-           char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+           char *jvmpath, jint jvmpathsize, int bitsWanted)
 {
     struct stat s;
 
@@ -613,7 +600,7 @@
  * Find path to JRE based on .exe's location or registry settings.
  */
 static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
 {
     char libjava[MAXPATHLEN];
 
@@ -841,7 +828,7 @@
 void* SplashProcAddress(const char* name) {
     if (!hSplashLib) {
         char jrePath[PATH_MAX];
-        if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {
+        if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
             JLI_ReportErrorMessage(JRE_ERROR1);
             return NULL;
         }
diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java
index f903754..4e93d6f 100644
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java
@@ -142,6 +142,9 @@
      */
     int encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset) {
+        if (plainLen <= 0) {
+            return plainLen;
+        }
         cryptBlockSizeCheck(plainLen);
         cryptNullAndBoundsCheck(plain, plainOffset, plainLen);
         cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen);
@@ -190,6 +193,9 @@
      */
     int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
                 byte[] plain, int plainOffset) {
+        if (cipherLen <= 0) {
+            return cipherLen;
+        }
         cryptBlockSizeCheck(cipherLen);
         cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen);
         cryptNullAndBoundsCheck(plain, plainOffset, cipherLen);
@@ -220,10 +226,6 @@
     }
 
     private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) {
-        if (len <= 0) {
-            return; // not an error because cryptImpl/decryptImpl won't execute if len <= 0
-        }
-
         Objects.requireNonNull(array);
 
         if (offset < 0 || offset >= array.length) {
diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java
index da6c10a..a1c33ae 100644
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java
@@ -172,10 +172,12 @@
      * are encrypted on demand.
      */
     private int crypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-
-      Objects.checkFromIndexSize(inOff, len, in.length);
-      Objects.checkFromIndexSize(outOff, len, out.length);
-      return implCrypt(in, inOff, len, out, outOff);
+        if (len == 0) {
+            return 0;
+        }
+        Objects.checkFromIndexSize(inOff, len, in.length);
+        Objects.checkFromIndexSize(outOff, len, out.length);
+        return implCrypt(in, inOff, len, out, outOff);
     }
 
     // Implementation of crpyt() method. Possibly replaced with a compiler intrinsic.
diff --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
index 203fde3..fa36c3f 100644
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
@@ -317,7 +317,7 @@
                 this(null, je);
             }
             boolean isClassFile() {
-                if (!name.endsWith(".class")) {
+                if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
                     return false;
                 }
                 for (String prefix = name;;) {
diff --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties
index 14bc2ad..c31b1a0 100644
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties
@@ -14,15 +14,6 @@
 pack.class.attribute.SourceID = RUH
 pack.class.attribute.CompilationID = RUH
 
-# Module attributes, supported by the tool and not JSR-200
-pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]]
-pack.class.attribute.ModulePackages = NH[RUH]
-pack.class.attribute.ModuleVersion = RUH
-pack.class.attribute.ModuleMainClass = RCH
-pack.class.attribute.ModuleTarget = RUHRUHRUH
-pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]]
-
-
 # Note:  Zero-length ("marker") attributes do not need to be specified here.
 # They are automatically defined to have an empty layout.
 #pack.class.attribute.Deprecated =
diff --git a/jdk/src/java.base/share/classes/java/io/File.java b/jdk/src/java.base/share/classes/java/io/File.java
index 0e96665..1598694 100644
--- a/jdk/src/java.base/share/classes/java/io/File.java
+++ b/jdk/src/java.base/share/classes/java/io/File.java
@@ -1903,20 +1903,72 @@
 
         // file name generation
         private static final SecureRandom random = new SecureRandom();
+        private static int shortenSubName(int subNameLength, int excess,
+            int nameMin) {
+            int newLength = Math.max(nameMin, subNameLength - excess);
+            if (newLength < subNameLength) {
+                return newLength;
+            }
+            return subNameLength;
+        }
         static File generateFile(String prefix, String suffix, File dir)
             throws IOException
         {
             long n = random.nextLong();
+            String nus = Long.toUnsignedString(n);
 
             // Use only the file name from the supplied prefix
             prefix = (new File(prefix)).getName();
-            String name = prefix + Long.toUnsignedString(n) + suffix;
+
+            int prefixLength = prefix.length();
+            int nusLength = nus.length();
+            int suffixLength = suffix.length();;
+
+            String name;
+            int nameMax = fs.getNameMax(dir.getPath());
+            int excess = prefixLength + nusLength + suffixLength - nameMax;
+            if (excess <= 0) {
+                name = prefix + nus + suffix;
+            } else {
+                // Name exceeds the maximum path component length: shorten it
+
+                // Attempt to shorten the prefix length to no less then 3
+                prefixLength = shortenSubName(prefixLength, excess, 3);
+                excess = prefixLength + nusLength + suffixLength - nameMax;
+
+                if (excess > 0) {
+                    // Attempt to shorten the suffix length to no less than
+                    // 0 or 4 depending on whether it begins with a dot ('.')
+                    suffixLength = shortenSubName(suffixLength, excess,
+                        suffix.indexOf(".") == 0 ? 4 : 0);
+                    suffixLength = shortenSubName(suffixLength, excess, 3);
+                    excess = prefixLength + nusLength + suffixLength - nameMax;
+                }
+
+                if (excess > 0 && excess <= nusLength - 5) {
+                    // Attempt to shorten the random character string length
+                    // to no less than 5
+                    nusLength = shortenSubName(nusLength, excess, 5);
+                }
+
+                StringBuilder sb =
+                    new StringBuilder(prefixLength + nusLength + suffixLength);
+                sb.append(prefixLength < prefix.length() ?
+                    prefix.substring(0, prefixLength) : prefix);
+                sb.append(nusLength < nus.length() ?
+                    nus.substring(0, nusLength) : nus);
+                sb.append(suffixLength < suffix.length() ?
+                    suffix.substring(0, suffixLength) : suffix);
+                name = sb.toString();
+            }
+
             File f = new File(dir, name);
             if (!name.equals(f.getName()) || f.isInvalid()) {
                 if (System.getSecurityManager() != null)
                     throw new IOException("Unable to create temporary file");
                 else
-                    throw new IOException("Unable to create temporary file, " + f);
+                    throw new IOException("Unable to create temporary file, "
+                        + name);
             }
             return f;
         }
diff --git a/jdk/src/java.base/share/classes/java/io/FilePermission.java b/jdk/src/java.base/share/classes/java/io/FilePermission.java
index c3d5113..5bd2960 100644
--- a/jdk/src/java.base/share/classes/java/io/FilePermission.java
+++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java
@@ -206,12 +206,6 @@
             DefaultFileSystemProvider.create()
                     .getFileSystem(URI.create("file:///"));
 
-    /**
-     * Creates FilePermission objects with special internals.
-     * See {@link FilePermCompat#newPermPlusAltPath(Permission)} and
-     * {@link FilePermCompat#newPermUsingAltPath(Permission)}.
-     */
-
     private static final Path here = builtInFS.getPath(
             GetPropertyAction.privilegedGetProperty("user.dir"));
 
@@ -261,9 +255,14 @@
 
     static {
         SharedSecrets.setJavaIOFilePermissionAccess(
+            /**
+             * Creates FilePermission objects with special internals.
+             * See {@link FilePermCompat#newPermPlusAltPath(Permission)} and
+             * {@link FilePermCompat#newPermUsingAltPath(Permission)}.
+             */
             new JavaIOFilePermissionAccess() {
                 public FilePermission newPermPlusAltPath(FilePermission input) {
-                    if (input.npath2 == null && !input.allFiles) {
+                    if (!input.invalid && input.npath2 == null && !input.allFiles) {
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // Please note the name of the new permission is
@@ -281,7 +280,7 @@
                     return input;
                 }
                 public FilePermission newPermUsingAltPath(FilePermission input) {
-                    if (!input.allFiles) {
+                    if (!input.invalid && !input.allFiles) {
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // New name, see above.
@@ -340,6 +339,16 @@
                 // Windows. Some JDK codes generate such illegal names.
                 npath = builtInFS.getPath(new File(name).getPath())
                         .normalize();
+                // lastName should always be non-null now
+                Path lastName = npath.getFileName();
+                if (lastName != null && lastName.toString().equals("-")) {
+                    directory = true;
+                    recursive = !rememberStar;
+                    npath = npath.getParent();
+                }
+                if (npath == null) {
+                    npath = builtInFS.getPath("");
+                }
                 invalid = false;
             } catch (InvalidPathException ipe) {
                 // Still invalid. For compatibility reason, accept it
@@ -348,16 +357,6 @@
                 invalid = true;
             }
 
-            // lastName should always be non-null now
-            Path lastName = npath.getFileName();
-            if (lastName != null && lastName.toString().equals("-")) {
-                directory = true;
-                recursive = !rememberStar;
-                npath = npath.getParent();
-            }
-            if (npath == null) {
-                npath = builtInFS.getPath("");
-            }
         } else {
             if ((cpath = getName()) == null)
                 throw new NullPointerException("name can't be null");
@@ -452,6 +451,8 @@
      * is converted to a {@link java.nio.file.Path} object named {@code npath}
      * after {@link Path#normalize() normalization}. No canonicalization is
      * performed which means the underlying file system is not accessed.
+     * If an {@link InvalidPathException} is thrown during the conversion,
+     * this {@code FilePermission} will be labeled as invalid.
      * <P>
      * In either case, the "*" or "-" character at the end of a wildcard
      * {@code path} is removed before canonicalization or normalization.
@@ -532,7 +533,12 @@
      * {@code  simple_npath.relativize(wildcard_npath)} is exactly "..",
      * a simple {@code npath} is recursively inside a wildcard {@code npath}
      * if and only if {@code simple_npath.relativize(wildcard_npath)}
-     * is a series of one or more "..".
+     * is a series of one or more "..". An invalid {@code FilePermission} does
+     * not imply any object except for itself. An invalid {@code FilePermission}
+     * is not implied by any object except for itself or a {@code FilePermission}
+     * on {@literal "<<ALL FILES>>"} whose actions is a superset of this
+     * invalid {@code FilePermission}. Even if two {@code FilePermission}
+     * are created with the same invalid path, one does not imply the other.
      *
      * @param p the permission to check against.
      *
@@ -566,12 +572,12 @@
             if (this == that) {
                 return true;
             }
-            if (this.invalid || that.invalid) {
-                return false;
-            }
             if (allFiles) {
                 return true;
             }
+            if (this.invalid || that.invalid) {
+                return false;
+            }
             if (that.allFiles) {
                 return false;
             }
@@ -699,6 +705,10 @@
      * (if {@code jdk.io.permissionsUseCanonicalPath} is {@code true}) or
      * {@code npath} (if {@code jdk.io.permissionsUseCanonicalPath}
      * is {@code false}) are equal. Or they are both {@literal "<<ALL FILES>>"}.
+     * <p>
+     * When {@code jdk.io.permissionsUseCanonicalPath} is {@code false}, an
+     * invalid {@code FilePermission} does not equal to any object except
+     * for itself, even if they are created using the same invalid path.
      *
      * @param obj the object we are testing for equality with this object.
      * @return <code>true</code> if obj is a FilePermission, and has the same
diff --git a/jdk/src/java.base/share/classes/java/io/FileSystem.java b/jdk/src/java.base/share/classes/java/io/FileSystem.java
index a7528a9..dab7fa8 100644
--- a/jdk/src/java.base/share/classes/java/io/FileSystem.java
+++ b/jdk/src/java.base/share/classes/java/io/FileSystem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -213,6 +213,13 @@
     /* -- Basic infrastructure -- */
 
     /**
+     * Retrieve the maximum length of a component of a file path.
+     *
+     * @return The maximum length of a file path component.
+     */
+    public abstract int getNameMax(String path);
+
+    /**
      * Compare two abstract pathnames lexicographically.
      */
     public abstract int compare(File f1, File f2);
diff --git a/jdk/src/java.base/share/classes/java/lang/FdLibm.java b/jdk/src/java.base/share/classes/java/lang/FdLibm.java
index dfecf79..e1d3085 100644
--- a/jdk/src/java.base/share/classes/java/lang/FdLibm.java
+++ b/jdk/src/java.base/share/classes/java/lang/FdLibm.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,8 @@
      */
     private static double __LO(double x, int low) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+                                       (low    & 0x0000_0000_FFFF_FFFFL));
     }
 
     /**
@@ -96,7 +97,8 @@
      */
     private static double __HI(double x, int high) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+                                       ( ((long)high)) << 32 );
     }
 
     /**
@@ -580,4 +582,152 @@
             return s * z;
         }
     }
+
+    /**
+     * Returns the exponential of x.
+     *
+     * Method
+     *   1. Argument reduction:
+     *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+     *      Given x, find r and integer k such that
+     *
+     *               x = k*ln2 + r,  |r| <= 0.5*ln2.
+     *
+     *      Here r will be represented as r = hi-lo for better
+     *      accuracy.
+     *
+     *   2. Approximation of exp(r) by a special rational function on
+     *      the interval [0,0.34658]:
+     *      Write
+     *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+     *      We use a special Reme algorithm on [0,0.34658] to generate
+     *      a polynomial of degree 5 to approximate R. The maximum error
+     *      of this polynomial approximation is bounded by 2**-59. In
+     *      other words,
+     *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+     *      (where z=r*r, and the values of P1 to P5 are listed below)
+     *      and
+     *          |                  5          |     -59
+     *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+     *          |                             |
+     *      The computation of exp(r) thus becomes
+     *                             2*r
+     *              exp(r) = 1 + -------
+     *                            R - r
+     *                                 r*R1(r)
+     *                     = 1 + r + ----------- (for better accuracy)
+     *                                2 - R1(r)
+     *      where
+     *                               2       4             10
+     *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+     *
+     *   3. Scale back to obtain exp(x):
+     *      From step 1, we have
+     *         exp(x) = 2^k * exp(r)
+     *
+     * Special cases:
+     *      exp(INF) is INF, exp(NaN) is NaN;
+     *      exp(-INF) is 0, and
+     *      for finite argument, only exp(0)=1 is exact.
+     *
+     * Accuracy:
+     *      according to an error analysis, the error is always less than
+     *      1 ulp (unit in the last place).
+     *
+     * Misc. info.
+     *      For IEEE double
+     *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+     *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+     *
+     * Constants:
+     * The hexadecimal values are the intended ones for the following
+     * constants. The decimal values may be used, provided that the
+     * compiler will convert from decimal to binary accurately enough
+     * to produce the hexadecimal values shown.
+     */
+    static class Exp {
+        private static final double one     = 1.0;
+        private static final double[] half = {0.5, -0.5,};
+        private static final double huge    = 1.0e+300;
+        private static final double twom1000=     0x1.0p-1000;             //  9.33263618503218878990e-302 = 2^-1000
+        private static final double o_threshold=  0x1.62e42fefa39efp9;     //  7.09782712893383973096e+02
+        private static final double u_threshold= -0x1.74910d52d3051p9;     // -7.45133219101941108420e+02;
+        private static final double[] ln2HI   ={  0x1.62e42feep-1,         //  6.93147180369123816490e-01
+                                                 -0x1.62e42feep-1};        // -6.93147180369123816490e-01
+        private static final double[] ln2LO   ={  0x1.a39ef35793c76p-33,   //  1.90821492927058770002e-10
+                                                 -0x1.a39ef35793c76p-33};  // -1.90821492927058770002e-10
+        private static final double invln2 =      0x1.71547652b82fep0;     //  1.44269504088896338700e+00
+
+        private static final double P1   =  0x1.555555555553ep-3;  //  1.66666666666666019037e-01
+        private static final double P2   = -0x1.6c16c16bebd93p-9;  // -2.77777777770155933842e-03
+        private static final double P3   =  0x1.1566aaf25de2cp-14; //  6.61375632143793436117e-05
+        private static final double P4   = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
+        private static final double P5   =  0x1.6376972bea4d0p-25; //  4.13813679705723846039e-08
+
+        // should be able to forgo strictfp due to controlled over/underflow
+        public static strictfp double compute(double x) {
+            double y;
+            double hi = 0.0;
+            double lo = 0.0;
+            double c;
+            double t;
+            int k = 0;
+            int xsb;
+            /*unsigned*/ int hx;
+
+            hx  = __HI(x);  /* high word of x */
+            xsb = (hx >> 31) & 1;               /* sign bit of x */
+            hx &= 0x7fffffff;               /* high word of |x| */
+
+            /* filter out non-finite argument */
+            if (hx >= 0x40862E42) {                  /* if |x| >= 709.78... */
+                if (hx >= 0x7ff00000) {
+                    if (((hx & 0xfffff) | __LO(x)) != 0)
+                        return x + x;                /* NaN */
+                    else
+                        return (xsb == 0) ? x : 0.0;    /* exp(+-inf) = {inf, 0} */
+                }
+                if (x > o_threshold)
+                    return huge * huge; /* overflow */
+                if (x < u_threshold) // unsigned compare needed here?
+                    return twom1000 * twom1000; /* underflow */
+            }
+
+            /* argument reduction */
+            if (hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+                if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                    hi = x - ln2HI[xsb];
+                    lo=ln2LO[xsb];
+                    k = 1 - xsb - xsb;
+                } else {
+                    k  = (int)(invln2 * x + half[xsb]);
+                    t  = k;
+                    hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                    lo = t*ln2LO[0];
+                }
+                x  = hi - lo;
+            } else if (hx < 0x3e300000)  {     /* when |x|<2**-28 */
+                if (huge + x > one)
+                    return one + x; /* trigger inexact */
+            } else {
+                k = 0;
+            }
+
+            /* x is now in primary range */
+            t  = x * x;
+            c  = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
+            if (k == 0)
+                return one - ((x*c)/(c - 2.0) - x);
+            else
+                y = one - ((lo - (x*c)/(2.0 - c)) - hi);
+
+            if(k >= -1021) {
+                y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
+                return y;
+            } else {
+                y = __HI(y, __HI(y) + ((k + 1000) << 20)); /* add k to y's exponent */
+                return y * twom1000;
+            }
+        }
+    }
 }
diff --git a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
index 04ba817..d95ea5e 100644
--- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
+++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
@@ -26,11 +26,13 @@
 package java.lang;
 
 import jdk.internal.loader.BuiltinClassLoader;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
 import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.util.HashSet;
@@ -51,12 +53,13 @@
  * @author Josh Bloch
  */
 public final class StackTraceElement implements java.io.Serializable {
-    // This field is set to the compacted String representation used
-    // by StackTraceElement::toString and stored in serial form.
+
+    // For Throwables and StackWalker, the VM initially sets this field to a
+    // reference to the declaring Class.  The Class reference is used to
+    // construct the 'format' bitmap, and then is cleared.
     //
-    // This field is of Object type. VM initially sets this field to
-    // the Class object of the declaring class to build the compacted string.
-    private Object classOrLoaderModuleClassName;
+    // For STEs constructed using the public constructors, this field is not used.
+    private transient Class<?> declaringClassObject;
 
     // Normally initialized by VM
     private String classLoaderName;
@@ -66,6 +69,7 @@
     private String methodName;
     private String fileName;
     private int    lineNumber;
+    private byte   format = 0; // Default to show all
 
     /**
      * Creates a stack trace element representing the specified execution
@@ -256,9 +260,10 @@
     }
 
     /**
-     * Returns a string representation of this stack trace element.  The
-     * format of this string depends on the implementation, but the following
-     * examples may be regarded as typical:
+     * Returns a string representation of this stack trace element.
+     *
+     * @apiNote The format of this string depends on the implementation, but the
+     * following examples may be regarded as typical:
      * <ul>
      * <li>
      *     "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}"
@@ -309,7 +314,7 @@
      * then the second element is omitted as shown in
      * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}".
      *
-     * If the class loader is a <a href="ClassLoader.html#builtinLoaders">
+     * <p> If the class loader is a <a href="ClassLoader.html#builtinLoaders">
      * built-in class loader</a> or is not named then the first element
      * and its following {@code "/"} are omitted as shown in
      * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}".
@@ -317,25 +322,30 @@
      * the second element and its following {@code "/"} are also omitted
      * as shown in "{@code MyClass.mash(MyClass.java:9)}".
      *
+     * <p> The {@code toString} method may return two different values on two
+     * {@code StackTraceElement} instances that are
+     * {@linkplain #equals(Object) equal}, for example one created via the
+     * constructor, and one obtained from {@link java.lang.Throwable} or
+     * {@link java.lang.StackWalker.StackFrame}, where an implementation may
+     * choose to omit some element in the returned string.
+     *
      * @see    Throwable#printStackTrace()
      */
     public String toString() {
-        String s = buildLoaderModuleClassName();
-        if (s == null) {
-            // all elements will be included
-            s = "";
-            if (classLoaderName != null && !classLoaderName.isEmpty()) {
-                s += classLoaderName + "/";
-            }
-            if (moduleName != null && !moduleName.isEmpty()) {
-                s += moduleName;
-
-                if (moduleVersion != null && !moduleVersion.isEmpty()) {
-                    s += "@" + moduleVersion;
-                }
-            }
-            s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
+        String s = "";
+        if (!dropClassLoaderName() && classLoaderName != null &&
+                !classLoaderName.isEmpty()) {
+            s += classLoaderName + "/";
         }
+        if (moduleName != null && !moduleName.isEmpty()) {
+            s += moduleName;
+
+            if (!dropModuleVersion() && moduleVersion != null &&
+                    !moduleVersion.isEmpty()) {
+                s += "@" + moduleVersion;
+            }
+        }
+        s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
 
         return s + "." + methodName + "(" +
              (isNativeMethod() ? "Native Method)" :
@@ -397,67 +407,53 @@
 
 
     /**
-     * Build the compacted String representation to be returned by
-     * toString method from the declaring Class object.
+     * Called from of() methods to set the 'format' bitmap using the Class
+     * reference stored in declaringClassObject, and then clear the reference.
+     *
+     * <p>
+     * If the module is a non-upgradeable JDK module, then set
+     * JDK_NON_UPGRADEABLE_MODULE to omit its version string.
+     * <p>
+     * If the loader is one of the built-in loaders (`boot`, `platform`, or `app`)
+     * then set BUILTIN_CLASS_LOADER to omit the first element (`<loader>/`).
      */
-    synchronized String buildLoaderModuleClassName() {
-        if (classOrLoaderModuleClassName == null)
-            return null;
+    private synchronized void computeFormat() {
+        try {
+            Class<?> cls = (Class<?>) declaringClassObject;
+            ClassLoader loader = cls.getClassLoader0();
+            Module m = cls.getModule();
+            byte bits = 0;
 
-        if (classOrLoaderModuleClassName instanceof Class) {
-            Class<?> cls = (Class<?>)classOrLoaderModuleClassName;
-            classOrLoaderModuleClassName = toLoaderModuleClassName(cls);
+            // First element - class loader name
+            // Call package-private ClassLoader::name method
+
+            if (loader instanceof BuiltinClassLoader) {
+                bits |= BUILTIN_CLASS_LOADER;
+            }
+
+            // Second element - module name and version
+
+            // Omit if is a JDK non-upgradeable module (recorded in the hashes
+            // in java.base)
+            if (isHashedInJavaBase(m)) {
+                bits |= JDK_NON_UPGRADEABLE_MODULE;
+            }
+            format = bits;
+        } finally {
+            // Class reference no longer needed, clear it
+            declaringClassObject = null;
         }
-        return (String)classOrLoaderModuleClassName;
     }
 
-    /**
-     * Returns <loader>/<module>/<fully-qualified-classname> string
-     * representation of the given class.
-     * <p>
-     * If the module is a non-upgradeable JDK module then omit
-     * its version string.
-     * <p>
-     * If the loader has no name, or if the loader is one of the built-in
-     * loaders (`boot`, `platform`, or `app`) then drop the first element
-     * (`<loader>/`).
-     * <p>
-     * If the first element has been dropped and the module is unnamed
-     * then drop the second element (`<module>/`).
-     * <p>
-     * If the first element is not dropped and the module is unnamed
-     * then drop `<module>`.
-     */
-    private static String toLoaderModuleClassName(Class<?> cls) {
-        ClassLoader loader = cls.getClassLoader0();
-        Module m = cls.getModule();
+    private static final byte BUILTIN_CLASS_LOADER       = 0x1;
+    private static final byte JDK_NON_UPGRADEABLE_MODULE = 0x2;
 
-        // First element - class loader name
-        // Call package-private ClassLoader::name method
-        String s = "";
-        if (loader != null && loader.name() != null &&
-                !(loader instanceof BuiltinClassLoader)) {
-            s = loader.name() + "/";
-        }
+    private boolean dropClassLoaderName() {
+        return (format & BUILTIN_CLASS_LOADER) == BUILTIN_CLASS_LOADER;
+    }
 
-        // Second element - module name and version
-        if (m != null && m.isNamed()) {
-            s += m.getName();
-            // Include version if it is a user module or upgradeable module
-            //
-            // If it is JDK non-upgradeable module which is recorded
-            // in the hashes in java.base, omit the version.
-            if (!isHashedInJavaBase(m)) {
-                Optional<Version> ov = m.getDescriptor().version();
-                if (ov.isPresent()) {
-                    String version = "@" + ov.get().toString();
-                    s += version;
-                }
-            }
-        }
-
-        // fully-qualified class name
-        return s.isEmpty() ? cls.getName() : s + "/" + cls.getName();
+    private boolean dropModuleVersion() {
+        return (format & JDK_NON_UPGRADEABLE_MODULE) == JDK_NON_UPGRADEABLE_MODULE;
     }
 
     /**
@@ -484,13 +480,16 @@
         static Set<String> HASHED_MODULES = hashedModules();
 
         static Set<String> hashedModules() {
-            Module javaBase = Layer.boot().findModule("java.base").get();
-            Optional<ModuleHashes> ohashes =
-                SharedSecrets.getJavaLangModuleAccess()
-                             .hashes(javaBase.getDescriptor());
 
-            if (ohashes.isPresent()) {
-                Set<String> names = new HashSet<>(ohashes.get().names());
+            Optional<ResolvedModule> resolvedModule = Layer.boot()
+                    .configuration()
+                    .findModule("java.base");
+            assert resolvedModule.isPresent();
+            ModuleReference mref = resolvedModule.get().reference();
+            assert mref instanceof ModuleReferenceImpl;
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes != null) {
+                Set<String> names = new HashSet<>(hashes.names());
                 names.add("java.base");
                 return names;
             }
@@ -519,7 +518,7 @@
 
         // ensure the proper StackTraceElement initialization
         for (StackTraceElement ste : stackTrace) {
-            ste.buildLoaderModuleClassName();
+            ste.computeFormat();
         }
         return stackTrace;
     }
@@ -531,7 +530,7 @@
         StackTraceElement ste = new StackTraceElement();
         initStackTraceElement(ste, sfi);
 
-        ste.buildLoaderModuleClassName();
+        ste.computeFormat();
         return ste;
     }
 
diff --git a/jdk/src/java.base/share/classes/java/lang/StrictMath.java b/jdk/src/java.base/share/classes/java/lang/StrictMath.java
index 1491a84..63d895f 100644
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java
+++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java
@@ -227,7 +227,9 @@
      * @return  the value <i>e</i><sup>{@code a}</sup>,
      *          where <i>e</i> is the base of the natural logarithms.
      */
-    public static native double exp(double a);
+    public static double exp(double a) {
+        return FdLibm.Exp.compute(a);
+    }
 
     /**
      * Returns the natural logarithm (base <i>e</i>) of a {@code double}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index 0c9da2c..d195d3d 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -172,6 +172,7 @@
      * @throws IllegalAccessException if the access check specified above fails
      * @throws SecurityException if denied by the security manager
      * @since 9
+     * @see Lookup#dropLookupMode
      */
     public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
         SecurityManager sm = System.getSecurityManager();
@@ -691,10 +692,15 @@
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
+         *  Mode bits can also be
+         *  {@linkplain java.lang.invoke.MethodHandles.Lookup#dropLookupMode directly cleared}.
+         *  Once cleared, mode bits cannot be restored from the downgraded lookup object.
          *  The purpose of this is to restrict access via the new lookup object,
          *  so that it can access only names which can be reached by the original
          *  lookup object, and also by the new lookup class.
          *  @return the lookup modes, which limit the kinds of access performed by this lookup object
+         *  @see #in
+         *  @see #dropLookupMode
          */
         public int lookupModes() {
             return allowedModes & ALL_MODES;
@@ -748,7 +754,8 @@
          * which may change due to this operation.
          *
          * @param requestedLookupClass the desired lookup class for the new lookup object
-         * @return a lookup object which reports the desired lookup class
+         * @return a lookup object which reports the desired lookup class, or the same object
+         * if there is no change
          * @throws NullPointerException if the argument is null
          */
         public Lookup in(Class<?> requestedLookupClass) {
@@ -788,6 +795,40 @@
             return new Lookup(requestedLookupClass, newModes);
         }
 
+
+        /**
+         * Creates a lookup on the same lookup class which this lookup object
+         * finds members, but with a lookup mode that has lost the given lookup mode.
+         * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
+         * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
+         * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
+         * mode will never have this access capability. When dropping {@code PACKAGE}
+         * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
+         * access. When dropping {@code MODULE} then the resulting lookup will not
+         * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
+         * PUBLIC} is dropped then the resulting lookup has no access.
+         * @param modeToDrop the lookup mode to drop
+         * @return a lookup object which lacks the indicated mode, or the same object if there is no change
+         * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
+         * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
+         * @since 9
+         * @see MethodHandles#privateLookupIn
+         */
+        public Lookup dropLookupMode(int modeToDrop) {
+            int oldModes = lookupModes();
+            int newModes = oldModes & ~(modeToDrop | PROTECTED);
+            switch (modeToDrop) {
+                case PUBLIC: newModes &= ~(ALL_MODES); break;
+                case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
+                case PACKAGE: newModes &= ~(PRIVATE); break;
+                case PROTECTED:
+                case PRIVATE: break;
+                default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+            }
+            if (newModes == oldModes) return this;  // return self if no change
+            return new Lookup(lookupClass(), newModes);
+        }
+
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
index b527ffa..b10d986 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
@@ -29,7 +29,6 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -38,7 +37,6 @@
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -52,7 +50,7 @@
 import static java.util.Objects.*;
 
 import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 
 
 /**
@@ -123,8 +121,9 @@
 
         private final Set<Modifier> mods;
         private final String name;
+        private final Version compiledVersion;
 
-        private Requires(Set<Modifier> ms, String mn) {
+        private Requires(Set<Modifier> ms, String mn, Version v) {
             if (ms.isEmpty()) {
                 ms = Collections.emptySet();
             } else {
@@ -132,11 +131,13 @@
             }
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
-        private Requires(Set<Modifier> ms, String mn, boolean unused) {
+        private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
         /**
@@ -158,12 +159,26 @@
         }
 
         /**
+         * Returns the version of the module if recorded at compile-time.
+         *
+         * @return The version of the module if recorded at compile-time
+         */
+        public Optional<Version> compiledVersion() {
+            return Optional.ofNullable(compiledVersion);
+        }
+
+        /**
          * Compares this module dependence to another.
          *
          * <p> Two {@code Requires} objects are compared by comparing their
          * module name lexicographically.  Where the module names are equal then
          * the sets of modifiers are compared based on a value computed from the
-         * ordinal of each modifier. </p>
+         * ordinal of each modifier. Where the module names are equal and the
+         * set of modifiers are equal then the version of the modules recorded
+         * at compile-time are compared. When comparing the versions recorded
+         * at compile-time then a dependence that has a recorded version is
+         * considered to succeed a dependence that does not have a recorded
+         * version. </p>
          *
          * @return A negative integer, zero, or a positive integer if this module
          *         dependence is less than, equal to, or greater than the given
@@ -174,8 +189,24 @@
             int c = this.name().compareTo(that.name());
             if (c != 0)
                 return c;
-            // same name, compare by modifiers
-            return Long.compare(this.modsValue(), that.modsValue());
+
+            // modifiers
+            c = Long.compare(this.modsValue(), that.modsValue());
+            if (c != 0)
+                return c;
+
+            // compiledVersion
+            if (this.compiledVersion != null) {
+                if (that.compiledVersion != null)
+                    c = this.compiledVersion.compareTo(that.compiledVersion);
+                else
+                    c = 1;
+            } else {
+                if (that.compiledVersion != null)
+                    c = -1;
+            }
+
+            return c;
         }
 
         /**
@@ -195,7 +226,9 @@
          *
          * <p> If the given object is not a {@code Requires} then this method
          * returns {@code false}. Two module dependence objects are equal if
-         * the module names are equal and set of modifiers are equal. </p>
+         * the module names are equal, set of modifiers are equal, and the
+         * compiled version of both modules is equal or not recorded for
+         * both modules. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -211,21 +244,25 @@
             if (!(ob instanceof Requires))
                 return false;
             Requires that = (Requires)ob;
-            return (name.equals(that.name) && mods.equals(that.mods));
+            return name.equals(that.name) && mods.equals(that.mods)
+                    && Objects.equals(compiledVersion, that.compiledVersion);
         }
 
         /**
          * Computes a hash code for this module dependence.
          *
-         * <p> The hash code is based upon the module name and modifiers. It
-         * satisfies the general contract of the {@link Object#hashCode
-         * Object.hashCode} method. </p>
+         * <p> The hash code is based upon the module name, modifiers, and the
+         * module version if recorded at compile time. It satisfies the general
+         * contract of the {@link Object#hashCode Object.hashCode} method. </p>
          *
          * @return The hash-code value for this module dependence
          */
         @Override
         public int hashCode() {
-            return name.hashCode() * 43 + mods.hashCode();
+            int hash = name.hashCode() * 43 + mods.hashCode();
+            if (compiledVersion != null)
+                hash = hash * 43 + compiledVersion.hashCode();
+            return hash;
         }
 
         /**
@@ -235,7 +272,13 @@
          */
         @Override
         public String toString() {
-            return ModuleDescriptor.toString(mods, name);
+            String what;
+            if (compiledVersion != null) {
+                what = name() + " (@" + compiledVersion + ")";
+            } else {
+                what = name();
+            }
+            return ModuleDescriptor.toString(mods, what);
         }
     }
 
@@ -967,9 +1010,8 @@
     }
 
 
-
-    // From module declarations
     private final String name;
+    private final Version version;
     private final boolean open;
 
     // Indicates if synthesised for a JAR file found on the module path
@@ -984,17 +1026,16 @@
     private final Set<String> uses;
     private final Set<Provides> provides;
 
-    // "Extended" information, added post-compilation by tools
-    private final Version version;
+    // Added post-compilation by tools
+    private final Set<String> packages;
     private final String mainClass;
     private final String osName;
     private final String osArch;
     private final String osVersion;
-    private final Set<String> packages;
-    private final ModuleHashes hashes;
 
 
     private ModuleDescriptor(String name,
+                             Version version,
                              boolean open,
                              boolean automatic,
                              boolean synthetic,
@@ -1003,16 +1044,14 @@
                              Set<Opens> opens,
                              Set<String> uses,
                              Set<Provides> provides,
-                             Version version,
+                             Set<String> packages,
                              String mainClass,
                              String osName,
                              String osArch,
-                             String osVersion,
-                             Set<String> packages,
-                             ModuleHashes hashes)
+                             String osVersion)
     {
-
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1020,18 +1059,16 @@
         assert (requires.stream().map(Requires::name).distinct().count()
                 == requires.size());
         this.requires = emptyOrUnmodifiableSet(requires);
-
         this.exports = emptyOrUnmodifiableSet(exports);
         this.opens = emptyOrUnmodifiableSet(opens);
         this.uses = emptyOrUnmodifiableSet(uses);
         this.provides = emptyOrUnmodifiableSet(provides);
-        this.version = version;
+
+        this.packages = emptyOrUnmodifiableSet(packages);
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = hashes;
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1039,6 +1076,7 @@
      */
     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
         this.name = md.name;
+        this.version = md.version;
         this.open = md.open;
         this.automatic = md.automatic;
         this.synthetic = md.synthetic;
@@ -1049,16 +1087,14 @@
         this.uses = md.uses;
         this.provides = md.provides;
 
-        this.version = md.version;
+        Set<String> packages = new HashSet<>(md.packages);
+        packages.addAll(pkgs);
+        this.packages = emptyOrUnmodifiableSet(packages);
+
         this.mainClass = md.mainClass;
         this.osName = md.osName;
         this.osArch = md.osArch;
         this.osVersion = md.osVersion;
-        this.hashes = null; // need to ignore
-
-        Set<String> packages = new HashSet<>(md.packages);
-        packages.addAll(pkgs);
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1066,6 +1102,7 @@
      * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
+                     Version version,
                      boolean open,
                      boolean automatic,
                      boolean synthetic,
@@ -1074,16 +1111,15 @@
                      Set<Opens> opens,
                      Set<String> uses,
                      Set<Provides> provides,
-                     Version version,
+                     Set<String> packages,
                      String mainClass,
                      String osName,
                      String osArch,
                      String osVersion,
-                     Set<String> packages,
-                     ModuleHashes hashes,
                      int hashCode,
                      boolean unused) {
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1093,12 +1129,10 @@
         this.uses = uses;
         this.provides = provides;
         this.packages = packages;
-        this.version = version;
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = hashes;
         this.hash = hashCode;
     }
 
@@ -1284,13 +1318,6 @@
         return packages;
     }
 
-    /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes() {
-        return Optional.ofNullable(hashes);
-    }
-
 
     /**
      * A builder used for building {@link ModuleDescriptor} objects.
@@ -1317,15 +1344,13 @@
     public static final class Builder {
         final String name;
         final boolean strict; // true if module names are checked
-        boolean open;
+        final boolean open;
+        final boolean synthetic;
         boolean automatic;
-        boolean synthetic;
         final Map<String, Requires> requires = new HashMap<>();
-
         final Map<String, Exports> exports = new HashMap<>();
         final Map<String, Opens> opens = new HashMap<>();
         final Set<String> concealedPackages = new HashSet<>();
-
         final Set<String> uses = new HashSet<>();
         final Map<String, Provides> provides = new HashMap<>();
         Version version;
@@ -1333,7 +1358,6 @@
         String osArch;
         String osVersion;
         String mainClass;
-        ModuleHashes hashes;
 
         /**
          * Initializes a new builder with the given module name.
@@ -1341,14 +1365,11 @@
          * @param strict
          *        Indicates whether module names are checked or not
          */
-        Builder(String name, boolean strict) {
-            this.strict = strict;
+        Builder(String name, boolean strict, boolean open, boolean synthetic) {
             this.name = (strict) ? requireModuleName(name) : name;
-        }
-
-        /* package */ Builder open(boolean open) {
+            this.strict = strict;
             this.open = open;
-            return this;
+            this.synthetic = synthetic;
         }
 
         /* package */ Builder automatic(boolean automatic) {
@@ -1356,10 +1377,20 @@
             return this;
         }
 
-        /* package */ boolean isOpen() { return open; }
+        /**
+         * Returns the set of packages that are exported (unconditionally or
+         * unconditionally).
+         */
+        /* package */ Set<String> exportedPackages() {
+            return exports.keySet();
+        }
 
-        /* package */ boolean isAutomatic() {
-            return automatic;
+        /**
+         * Returns the set of packages that are opened (unconditionally or
+         * unconditionally).
+         */
+        /* package */Set<String> openPackages() {
+            return opens.keySet();
         }
 
         /**
@@ -1389,6 +1420,36 @@
 
         /**
          * Adds a dependence on a module with the given (and possibly empty)
+         * set of modifiers. The dependence includes the version of the
+         * module that that was recorded at compile-time.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  mn
+         *         The module name
+         * @param  compiledVersion
+         *         The version of the module recorded at compile-time
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null}, is not a legal Java
+         *         identifier, or is equal to the module name that this builder
+         *         was initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(Set<Requires.Modifier> ms,
+                                String mn,
+                                Version compiledVersion) {
+            Objects.requireNonNull(compiledVersion);
+            if (strict)
+                mn = requireModuleName(mn);
+            return requires(new Requires(ms, mn, compiledVersion));
+        }
+
+        /**
+         * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
          *
          * @param  ms
@@ -1408,7 +1469,7 @@
         public Builder requires(Set<Requires.Modifier> ms, String mn) {
             if (strict)
                 mn = requireModuleName(mn);
-            return requires(new Requires(ms, mn));
+            return requires(new Requires(ms, mn, null));
         }
 
         /**
@@ -1705,17 +1766,6 @@
             return opens(Collections.emptySet(), pn);
         }
 
-
-        // Used by ModuleInfo, after a packageFinder is invoked
-        /* package */ Set<String> exportedAndOpenPackages() {
-            if (opens.isEmpty())
-                return exports.keySet();
-            Set<String> result = new HashSet<>();
-            result.addAll(exports.keySet());
-            result.addAll(opens.keySet());
-            return result;
-        }
-
         /**
          * Adds a service dependence.
          *
@@ -1789,7 +1839,6 @@
             if (providerNames.isEmpty())
                 throw new IllegalArgumentException("Empty providers set");
             providerNames.forEach(Checks::requireServiceProviderName);
-
             provides.put(service, p);
             return this;
         }
@@ -1914,7 +1963,7 @@
          *         If {@code mainClass} is null or is not a legal Java identifier
          */
         public Builder mainClass(String mc) {
-            mainClass = requireJavaIdentifier("main class name", mc);
+            mainClass = requireBinaryName("main class name", mc);
             return this;
         }
 
@@ -1972,16 +2021,6 @@
             return this;
         }
 
-        /* package */ Builder hashes(ModuleHashes hashes) {
-            this.hashes = hashes;
-            return this;
-        }
-
-        /* package */ Builder synthetic(boolean v) {
-            this.synthetic = v;
-            return this;
-        }
-
         /**
          * Builds and returns a {@code ModuleDescriptor} from its components.
          *
@@ -1990,7 +2029,9 @@
         public ModuleDescriptor build() {
             Set<Requires> requires = new HashSet<>(this.requires.values());
 
-            Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+            Set<String> packages = new HashSet<>();
+            packages.addAll(exports.keySet());
+            packages.addAll(opens.keySet());
             packages.addAll(concealedPackages);
 
             Set<Exports> exports = new HashSet<>(this.exports.values());
@@ -1999,6 +2040,7 @@
             Set<Provides> provides = new HashSet<>(this.provides.values());
 
             return new ModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -2007,13 +2049,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
-                                        osVersion,
-                                        packages,
-                                        hashes);
+                                        osVersion);
         }
 
     }
@@ -2088,8 +2128,7 @@
                 && Objects.equals(osName, that.osName)
                 && Objects.equals(osArch, that.osArch)
                 && Objects.equals(osVersion, that.osVersion)
-                && Objects.equals(packages, that.packages)
-                && Objects.equals(hashes, that.hashes));
+                && Objects.equals(packages, that.packages));
     }
 
     private transient int hash;  // cached hash code
@@ -2122,7 +2161,6 @@
             hc = hc * 43 + Objects.hashCode(osArch);
             hc = hc * 43 + Objects.hashCode(osVersion);
             hc = hc * 43 + Objects.hashCode(packages);
-            hc = hc * 43 + Objects.hashCode(hashes);
             if (hc == 0)
                 hc = -1;
             hash = hc;
@@ -2145,7 +2183,7 @@
         if (!requires.isEmpty())
             sb.append(", ").append(requires);
         if (!uses.isEmpty())
-            sb.append(", ").append(uses);
+            sb.append(", uses: ").append(uses);
         if (!exports.isEmpty())
             sb.append(", exports: ").append(exports);
         if (!opens.isEmpty())
@@ -2171,7 +2209,7 @@
      *         identifier
      */
     public static Builder module(String name) {
-        return new Builder(name, true);
+        return new Builder(name, true, false, false);
     }
 
     /**
@@ -2199,7 +2237,7 @@
      *         identifier
      */
     public static Builder openModule(String name) {
-        return new Builder(name, true).open(true);
+        return new Builder(name, true, true, false);
     }
 
     /**
@@ -2221,7 +2259,7 @@
      * @see ModuleFinder#of(Path[])
      */
     public static Builder automaticModule(String name) {
-        return new Builder(name, true).automatic(true);
+        return new Builder(name, true, false, false).automatic(true);
     }
 
 
@@ -2263,7 +2301,7 @@
                                         Supplier<Set<String>> packageFinder)
         throws IOException
     {
-        return ModuleInfo.read(in, requireNonNull(packageFinder));
+        return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2281,7 +2319,7 @@
      *         If an I/O error occurs reading from the input stream
      */
     public static ModuleDescriptor read(InputStream in) throws IOException {
-        return ModuleInfo.read(in, null);
+        return ModuleInfo.read(in, null).descriptor();
     }
 
     /**
@@ -2320,7 +2358,7 @@
     public static ModuleDescriptor read(ByteBuffer bb,
                                         Supplier<Set<String>> packageFinder)
     {
-        return ModuleInfo.read(bb, requireNonNull(packageFinder));
+        return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2336,7 +2374,7 @@
      *         If an invalid module descriptor is detected
      */
     public static ModuleDescriptor read(ByteBuffer bb) {
-        return ModuleInfo.read(bb, null);
+        return ModuleInfo.read(bb, null).descriptor();
     }
 
     private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
@@ -2377,18 +2415,26 @@
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
                 @Override
-                public Builder newModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict);
+                public Builder newModuleBuilder(String mn,
+                                                boolean strict,
+                                                boolean open,
+                                                boolean synthetic) {
+                    return new Builder(mn, strict, open, synthetic);
                 }
 
                 @Override
-                public Builder newOpenModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict).open(true);
+                public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
+                    return builder.exportedPackages();
                 }
 
                 @Override
-                public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
-                    return new Requires(ms, mn, true);
+                public Set<String> openPackages(ModuleDescriptor.Builder builder) {
+                    return builder.openPackages();
+                }
+
+                @Override
+                public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
+                    return new Requires(ms, mn, v, true);
                 }
 
                 @Override
@@ -2433,6 +2479,7 @@
 
                 @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
+                                                            Version version,
                                                             boolean open,
                                                             boolean automatic,
                                                             boolean synthetic,
@@ -2441,15 +2488,14 @@
                                                             Set<Opens> opens,
                                                             Set<String> uses,
                                                             Set<Provides> provides,
-                                                            Version version,
+                                                            Set<String> packages,
                                                             String mainClass,
                                                             String osName,
                                                             String osArch,
                                                             String osVersion,
-                                                            Set<String> packages,
-                                                            ModuleHashes hashes,
                                                             int hashCode) {
                     return new ModuleDescriptor(name,
+                                                version,
                                                 open,
                                                 automatic,
                                                 synthetic,
@@ -2458,23 +2504,16 @@
                                                 opens,
                                                 uses,
                                                 provides,
-                                                version,
+                                                packages,
                                                 mainClass,
                                                 osName,
                                                 osArch,
                                                 osVersion,
-                                                packages,
-                                                hashes,
                                                 hashCode,
                                                 false);
                 }
 
                 @Override
-                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
-                    return descriptor.hashes();
-                }
-
-                @Override
                 public Configuration resolveRequiresAndUses(ModuleFinder finder,
                                                             Collection<String> roots,
                                                             boolean check,
@@ -2482,20 +2521,6 @@
                 {
                     return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
                 }
-
-                @Override
-                public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                                        URI location,
-                                                        Supplier<ModuleReader> s) {
-                    return new ModuleReference(descriptor, location, s, true, null);
-                }
-
-                @Override
-                public ModuleFinder newModulePath(Runtime.Version version,
-                                                  boolean isLinkPhase,
-                                                  Path... entries) {
-                    return new ModulePath(version, isLinkPhase, entries);
-                }
             });
     }
 
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
index 4b98bf4..5d01f69 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
@@ -42,6 +42,8 @@
 import java.util.Optional;
 import java.util.Set;
 
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.SystemModuleFinder;
 import sun.security.action.GetPropertyAction;
 
 /**
@@ -137,7 +139,7 @@
 
     /**
      * Returns a module finder that locates the <em>system modules</em>. The
-     * system modules are typically linked into the Java run-time image.
+     * system modules are the modules in the Java run-time image.
      * The module finder will always find {@code java.base}.
      *
      * <p> If there is a security manager set then its {@link
@@ -166,7 +168,7 @@
 
         Path modules = Paths.get(home, "lib", "modules");
         if (Files.isRegularFile(modules)) {
-            return new SystemModuleFinder();
+            return SystemModuleFinder.getInstance();
         } else {
             Path mlib = Paths.get(home, "modules");
             if (Files.isDirectory(mlib)) {
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java
deleted file mode 100644
index b1c8281..0000000
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.module;
-
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Builder;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Opens;
-import java.nio.ByteBuffer;
-import java.nio.BufferUnderflowException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
-
-import static jdk.internal.module.ClassFileConstants.*;
-
-
-/**
- * Read module information from a {@code module-info} class file.
- *
- * @implNote The rationale for the hand-coded reader is startup performance
- * and fine control over the throwing of InvalidModuleDescriptorException.
- */
-
-final class ModuleInfo {
-
-    // supplies the set of packages when ModulePackages attribute not present
-    private final Supplier<Set<String>> packageFinder;
-
-    // indicates if the ModuleHashes attribute should be parsed
-    private final boolean parseHashes;
-
-    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
-        packageFinder = pf;
-        parseHashes = ph;
-    }
-
-    private ModuleInfo(Supplier<Set<String>> pf) {
-        this(pf, true);
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given input stream.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws IOException
-     */
-    public static ModuleDescriptor read(InputStream in,
-                                        Supplier<Set<String>> pf)
-        throws IOException
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputStream(in));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    public static ModuleDescriptor read(ByteBuffer bb,
-                                        Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer
-     * but ignore the {@code ModuleHashes} attribute.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
-                                               Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads the input as a module-info class file.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
-     *         because an identifier is not a legal Java identifier, duplicate
-     *         exports, and many other reasons
-     */
-    private ModuleDescriptor doRead(DataInput in) throws IOException {
-
-        int magic = in.readInt();
-        if (magic != 0xCAFEBABE)
-            throw invalidModuleDescriptor("Bad magic number");
-
-        int minor_version = in.readUnsignedShort();
-        int major_version = in.readUnsignedShort();
-        if (major_version < 53) {
-            throw invalidModuleDescriptor("Must be >= 53.0");
-        }
-
-        ConstantPool cpool = new ConstantPool(in);
-
-        int access_flags = in.readUnsignedShort();
-        if (access_flags != ACC_MODULE)
-            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
-
-        int this_class = in.readUnsignedShort();
-        if (this_class != 0)
-            throw invalidModuleDescriptor("this_class must be 0");
-
-        int super_class = in.readUnsignedShort();
-        if (super_class > 0)
-            throw invalidModuleDescriptor("bad #super_class");
-
-        int interfaces_count = in.readUnsignedShort();
-        if (interfaces_count > 0)
-            throw invalidModuleDescriptor("Bad #interfaces");
-
-        int fields_count = in.readUnsignedShort();
-        if (fields_count > 0)
-            throw invalidModuleDescriptor("Bad #fields");
-
-        int methods_count = in.readUnsignedShort();
-        if (methods_count > 0)
-            throw invalidModuleDescriptor("Bad #methods");
-
-        int attributes_count = in.readUnsignedShort();
-
-        // the names of the attributes found in the class file
-        Set<String> attributes = new HashSet<>();
-
-        Builder builder = null;
-        Set<String> packages = null;
-        String version = null;
-        String mainClass = null;
-        String[] osValues = null;
-        ModuleHashes hashes = null;
-
-        for (int i = 0; i < attributes_count ; i++) {
-            int name_index = in.readUnsignedShort();
-            String attribute_name = cpool.getUtf8(name_index);
-            int length = in.readInt();
-
-            boolean added = attributes.add(attribute_name);
-            if (!added && isAttributeAtMostOnce(attribute_name)) {
-                throw invalidModuleDescriptor("More than one "
-                                              + attribute_name + " attribute");
-            }
-
-            switch (attribute_name) {
-
-                case MODULE :
-                    builder = readModuleAttribute(in, cpool);
-                    break;
-
-                case MODULE_PACKAGES :
-                    packages = readModulePackagesAttribute(in, cpool);
-                    break;
-
-                case MODULE_VERSION :
-                    version = readModuleVersionAttribute(in, cpool);
-                    break;
-
-                case MODULE_MAIN_CLASS :
-                    mainClass = readModuleMainClassAttribute(in, cpool);
-                    break;
-
-                case MODULE_TARGET :
-                    osValues = readModuleTargetAttribute(in, cpool);
-                    break;
-
-                case MODULE_HASHES :
-                    if (parseHashes) {
-                        hashes = readModuleHashesAttribute(in, cpool);
-                    } else {
-                        in.skipBytes(length);
-                    }
-                    break;
-
-                default:
-                    if (isAttributeDisallowed(attribute_name)) {
-                        throw invalidModuleDescriptor(attribute_name
-                                                      + " attribute not allowed");
-                    } else {
-                        in.skipBytes(length);
-                    }
-
-            }
-        }
-
-        // the Module attribute is required
-        if (builder == null) {
-            throw invalidModuleDescriptor(MODULE + " attribute not found");
-        }
-
-        // If the ModulePackages attribute is not present then the packageFinder
-        // is used to find the set of packages
-        boolean usedPackageFinder = false;
-        if (packages == null && packageFinder != null) {
-            try {
-                packages = new HashSet<>(packageFinder.get());
-            } catch (UncheckedIOException x) {
-                throw x.getCause();
-            }
-            usedPackageFinder = true;
-        }
-        if (packages != null) {
-            for (String pn : builder.exportedAndOpenPackages()) {
-                if (!packages.contains(pn)) {
-                    String tail;
-                    if (usedPackageFinder) {
-                        tail = " not found by package finder";
-                    } else {
-                        tail = " missing from ModulePackages attribute";
-                    }
-                    throw invalidModuleDescriptor("Package " + pn + tail);
-                }
-                packages.remove(pn);
-            }
-            builder.contains(packages);
-        }
-
-        if (version != null)
-            builder.version(version);
-        if (mainClass != null)
-            builder.mainClass(mainClass);
-        if (osValues != null) {
-            if (osValues[0] != null) builder.osName(osValues[0]);
-            if (osValues[1] != null) builder.osArch(osValues[1]);
-            if (osValues[2] != null) builder.osVersion(osValues[2]);
-        }
-        if (hashes != null)
-            builder.hashes(hashes);
-
-        return builder.build();
-    }
-
-    /**
-     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
-     * build the corresponding ModuleDescriptor.
-     */
-    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        // module_name
-        int module_name_index = in.readUnsignedShort();
-        String mn = cpool.getUtf8AsBinaryName(module_name_index);
-
-        Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
-
-        int module_flags = in.readUnsignedShort();
-        boolean open = ((module_flags & ACC_OPEN) != 0);
-        if (open)
-            builder.open(true);
-        if ((module_flags & ACC_SYNTHETIC) != 0)
-            builder.synthetic(true);
-
-        int requires_count = in.readUnsignedShort();
-        boolean requiresJavaBase = false;
-        for (int i=0; i<requires_count; i++) {
-            int index = in.readUnsignedShort();
-            int flags = in.readUnsignedShort();
-            String dn = cpool.getUtf8AsBinaryName(index);
-            Set<Requires.Modifier> mods;
-            if (flags == 0) {
-                mods = Collections.emptySet();
-            } else {
-                mods = new HashSet<>();
-                if ((flags & ACC_TRANSITIVE) != 0)
-                    mods.add(Requires.Modifier.TRANSITIVE);
-                if ((flags & ACC_STATIC_PHASE) != 0)
-                    mods.add(Requires.Modifier.STATIC);
-                if ((flags & ACC_SYNTHETIC) != 0)
-                    mods.add(Requires.Modifier.SYNTHETIC);
-                if ((flags & ACC_MANDATED) != 0)
-                    mods.add(Requires.Modifier.MANDATED);
-            }
-            builder.requires(mods, dn);
-            if (dn.equals("java.base"))
-                requiresJavaBase = true;
-        }
-        if (mn.equals("java.base")) {
-            if (requires_count > 0) {
-                throw invalidModuleDescriptor("The requires table for java.base"
-                                              + " must be 0 length");
-            }
-        } else if (!requiresJavaBase) {
-            throw invalidModuleDescriptor("The requires table must have"
-                                          + " an entry for java.base");
-        }
-
-        int exports_count = in.readUnsignedShort();
-        if (exports_count > 0) {
-            for (int i=0; i<exports_count; i++) {
-                int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8AsBinaryName(index);
-
-                Set<Exports.Modifier> mods;
-                int flags = in.readUnsignedShort();
-                if (flags == 0) {
-                    mods = Collections.emptySet();
-                } else {
-                    mods = new HashSet<>();
-                    if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Exports.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Exports.Modifier.MANDATED);
-                }
-
-                int exports_to_count = in.readUnsignedShort();
-                if (exports_to_count > 0) {
-                    Set<String> targets = new HashSet<>(exports_to_count);
-                    for (int j=0; j<exports_to_count; j++) {
-                        int exports_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
-                    }
-                    builder.exports(mods, pkg, targets);
-                } else {
-                    builder.exports(mods, pkg);
-                }
-            }
-        }
-
-        int opens_count = in.readUnsignedShort();
-        if (opens_count > 0) {
-            if (open) {
-                throw invalidModuleDescriptor("The opens table for an open"
-                                              + " module must be 0 length");
-            }
-            for (int i=0; i<opens_count; i++) {
-                int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8AsBinaryName(index);
-
-                Set<Opens.Modifier> mods;
-                int flags = in.readUnsignedShort();
-                if (flags == 0) {
-                    mods = Collections.emptySet();
-                } else {
-                    mods = new HashSet<>();
-                    if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Opens.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Opens.Modifier.MANDATED);
-                }
-
-                int open_to_count = in.readUnsignedShort();
-                if (open_to_count > 0) {
-                    Set<String> targets = new HashSet<>(open_to_count);
-                    for (int j=0; j<open_to_count; j++) {
-                        int opens_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getUtf8AsBinaryName(opens_to_index));
-                    }
-                    builder.opens(mods, pkg, targets);
-                } else {
-                    builder.opens(mods, pkg);
-                }
-            }
-        }
-
-        int uses_count = in.readUnsignedShort();
-        if (uses_count > 0) {
-            for (int i=0; i<uses_count; i++) {
-                int index = in.readUnsignedShort();
-                String sn = cpool.getClassNameAsBinaryName(index);
-                builder.uses(sn);
-            }
-        }
-
-        int provides_count = in.readUnsignedShort();
-        if (provides_count > 0) {
-            for (int i=0; i<provides_count; i++) {
-                int index = in.readUnsignedShort();
-                String sn = cpool.getClassNameAsBinaryName(index);
-                int with_count = in.readUnsignedShort();
-                List<String> providers = new ArrayList<>(with_count);
-                for (int j=0; j<with_count; j++) {
-                    index = in.readUnsignedShort();
-                    String pn = cpool.getClassNameAsBinaryName(index);
-                    providers.add(pn);
-                }
-                builder.provides(sn, providers);
-            }
-        }
-
-        return builder;
-    }
-
-    /**
-     * Reads the ModulePackages attribute
-     */
-    private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int package_count = in.readUnsignedShort();
-        Set<String> packages = new HashSet<>(package_count);
-        for (int i=0; i<package_count; i++) {
-            int index = in.readUnsignedShort();
-            String pn = cpool.getUtf8AsBinaryName(index);
-            packages.add(pn);
-        }
-        return packages;
-    }
-
-    /**
-     * Reads the ModuleVersion attribute
-     */
-    private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getUtf8(index);
-    }
-
-    /**
-     * Reads the ModuleMainClass attribute
-     */
-    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getClassNameAsBinaryName(index);
-    }
-
-    /**
-     * Reads the ModuleTarget attribute
-     */
-    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        String[] values = new String[3];
-
-        int name_index = in.readUnsignedShort();
-        if (name_index != 0)
-            values[0] = cpool.getUtf8(name_index);
-
-        int arch_index = in.readUnsignedShort();
-        if (arch_index != 0)
-            values[1] = cpool.getUtf8(arch_index);
-
-        int version_index = in.readUnsignedShort();
-        if (version_index != 0)
-            values[2] = cpool.getUtf8(version_index);
-
-        return values;
-    }
-
-
-    /**
-     * Reads the ModuleHashes attribute
-     */
-    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int algorithm_index = in.readUnsignedShort();
-        String algorithm = cpool.getUtf8(algorithm_index);
-
-        int hash_count = in.readUnsignedShort();
-        Map<String, byte[]> map = new HashMap<>(hash_count);
-        for (int i=0; i<hash_count; i++) {
-            int module_name_index = in.readUnsignedShort();
-            String mn = cpool.getUtf8AsBinaryName(module_name_index);
-            int hash_length = in.readUnsignedShort();
-            if (hash_length == 0) {
-                throw invalidModuleDescriptor("hash_length == 0");
-            }
-            byte[] hash = new byte[hash_length];
-            in.readFully(hash);
-            map.put(mn, hash);
-        }
-
-        return new ModuleHashes(algorithm, map);
-    }
-
-
-    /**
-     * Returns true if the given attribute can be present at most once
-     * in the class file. Returns false otherwise.
-     */
-    private static boolean isAttributeAtMostOnce(String name) {
-
-        if (name.equals(MODULE) ||
-                name.equals(SOURCE_FILE) ||
-                name.equals(SDE) ||
-                name.equals(MODULE_PACKAGES) ||
-                name.equals(MODULE_VERSION) ||
-                name.equals(MODULE_MAIN_CLASS) ||
-                name.equals(MODULE_TARGET) ||
-                name.equals(MODULE_HASHES))
-            return true;
-
-        return false;
-    }
-
-    /**
-     * Return true if the given attribute name is the name of a pre-defined
-     * attribute that is not allowed in the class file.
-     *
-     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
-     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
-     */
-    private static boolean isAttributeDisallowed(String name) {
-        Set<String> notAllowed = predefinedNotAllowed;
-        if (notAllowed == null) {
-            notAllowed = Set.of(
-                    "ConstantValue",
-                    "Code",
-                    "StackMapTable",
-                    "Exceptions",
-                    "EnclosingMethod",
-                    "Signature",
-                    "LineNumberTable",
-                    "LocalVariableTable",
-                    "LocalVariableTypeTable",
-                    "RuntimeVisibleParameterAnnotations",
-                    "RuntimeInvisibleParameterAnnotations",
-                    "RuntimeVisibleTypeAnnotations",
-                    "RuntimeInvisibleTypeAnnotations",
-                    "Synthetic",
-                    "AnnotationDefault",
-                    "BootstrapMethods",
-                    "MethodParameters");
-            predefinedNotAllowed = notAllowed;
-        }
-        return notAllowed.contains(name);
-    }
-
-    // lazily created set the pre-defined attributes that are not allowed
-    private static volatile Set<String> predefinedNotAllowed;
-
-
-    /**
-     * The constant pool in a class file.
-     */
-    private static class ConstantPool {
-        static final int CONSTANT_Utf8 = 1;
-        static final int CONSTANT_Integer = 3;
-        static final int CONSTANT_Float = 4;
-        static final int CONSTANT_Long = 5;
-        static final int CONSTANT_Double = 6;
-        static final int CONSTANT_Class = 7;
-        static final int CONSTANT_String = 8;
-        static final int CONSTANT_Fieldref = 9;
-        static final int CONSTANT_Methodref = 10;
-        static final int CONSTANT_InterfaceMethodref = 11;
-        static final int CONSTANT_NameAndType = 12;
-        static final int CONSTANT_MethodHandle = 15;
-        static final int CONSTANT_MethodType = 16;
-        static final int CONSTANT_InvokeDynamic = 18;
-
-        private static class Entry {
-            protected Entry(int tag) {
-                this.tag = tag;
-            }
-            final int tag;
-        }
-
-        private static class IndexEntry extends Entry {
-            IndexEntry(int tag, int index) {
-                super(tag);
-                this.index = index;
-            }
-            final int index;
-        }
-
-        private static class Index2Entry extends Entry {
-            Index2Entry(int tag, int index1, int index2) {
-                super(tag);
-                this.index1 = index1;
-                this.index2 = index2;
-            }
-            final int index1,  index2;
-        }
-
-        private static class ValueEntry extends Entry {
-            ValueEntry(int tag, Object value) {
-                super(tag);
-                this.value = value;
-            }
-            final Object value;
-        }
-
-        final Entry[] pool;
-
-        ConstantPool(DataInput in) throws IOException {
-            int count = in.readUnsignedShort();
-            pool = new Entry[count];
-
-            for (int i = 1; i < count; i++) {
-                int tag = in.readUnsignedByte();
-                switch (tag) {
-
-                    case CONSTANT_Utf8:
-                        String svalue = in.readUTF();
-                        pool[i] = new ValueEntry(tag, svalue);
-                        break;
-
-                    case CONSTANT_Class:
-                    case CONSTANT_String:
-                        int index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Double:
-                        double dvalue = in.readDouble();
-                        pool[i] = new ValueEntry(tag, dvalue);
-                        i++;
-                        break;
-
-                    case CONSTANT_Fieldref:
-                    case CONSTANT_InterfaceMethodref:
-                    case CONSTANT_Methodref:
-                    case CONSTANT_InvokeDynamic:
-                    case CONSTANT_NameAndType:
-                        int index1 = in.readUnsignedShort();
-                        int index2 = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, index1, index2);
-                        break;
-
-                    case CONSTANT_MethodHandle:
-                        int refKind = in.readUnsignedByte();
-                        index = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, refKind, index);
-                        break;
-
-                    case CONSTANT_MethodType:
-                        index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Float:
-                        float fvalue = in.readFloat();
-                        pool[i] = new ValueEntry(tag, fvalue);
-                        break;
-
-                    case CONSTANT_Integer:
-                        int ivalue = in.readInt();
-                        pool[i] = new ValueEntry(tag, ivalue);
-                        break;
-
-                    case CONSTANT_Long:
-                        long lvalue = in.readLong();
-                        pool[i] = new ValueEntry(tag, lvalue);
-                        i++;
-                        break;
-
-                    default:
-                        throw invalidModuleDescriptor("Bad constant pool entry: "
-                                                      + i);
-                }
-            }
-        }
-
-        String getClassName(int index) {
-            checkIndex(index);
-            Entry e = pool[index];
-            if (e.tag != CONSTANT_Class) {
-                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
-                                              + index);
-            }
-            return getUtf8(((IndexEntry) e).index);
-        }
-
-        String getClassNameAsBinaryName(int index) {
-            String value = getClassName(index);
-            return value.replace('/', '.');  // internal form -> binary name
-        }
-
-        String getUtf8(int index) {
-            checkIndex(index);
-            Entry e = pool[index];
-            if (e.tag != CONSTANT_Utf8) {
-                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
-                                              + index);
-            }
-            return (String) (((ValueEntry) e).value);
-        }
-
-        String getUtf8AsBinaryName(int index) {
-            String value = getUtf8(index);
-            return value.replace('/', '.');  // internal -> binary name
-        }
-
-        void checkIndex(int index) {
-            if (index < 1 || index >= pool.length)
-                throw invalidModuleDescriptor("Index into constant pool out of range");
-        }
-    }
-
-    /**
-     * A DataInput implementation that reads from a ByteBuffer.
-     */
-    private static class DataInputWrapper implements DataInput {
-        private final ByteBuffer bb;
-
-        DataInputWrapper(ByteBuffer bb) {
-            this.bb = bb;
-        }
-
-        @Override
-        public void readFully(byte b[]) throws IOException {
-            readFully(b, 0, b.length);
-        }
-
-        @Override
-        public void readFully(byte b[], int off, int len) throws IOException {
-            try {
-                bb.get(b, off, len);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int skipBytes(int n) {
-            int skip = Math.min(n, bb.remaining());
-            bb.position(bb.position() + skip);
-            return skip;
-        }
-
-        @Override
-        public boolean readBoolean() throws IOException {
-            try {
-                int ch = bb.get();
-                return (ch != 0);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public byte readByte() throws IOException {
-            try {
-                return bb.get();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedByte() throws IOException {
-            try {
-                return ((int) bb.get()) & 0xff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public short readShort() throws IOException {
-            try {
-                return bb.getShort();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedShort() throws IOException {
-            try {
-                return ((int) bb.getShort()) & 0xffff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public char readChar() throws IOException {
-            try {
-                return bb.getChar();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readInt() throws IOException {
-            try {
-                return bb.getInt();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public long readLong() throws IOException {
-            try {
-                return bb.getLong();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public float readFloat() throws IOException {
-            try {
-                return bb.getFloat();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public double readDouble() throws IOException {
-            try {
-                return bb.getDouble();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public String readLine() {
-            throw new RuntimeException("not implemented");
-        }
-
-        @Override
-        public String readUTF() throws IOException {
-            // ### Need to measure the performance and feasibility of using
-            // the UTF-8 decoder instead.
-            return DataInputStream.readUTF(this);
-        }
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with the given detail
-     * message
-     */
-    private static InvalidModuleDescriptorException
-    invalidModuleDescriptor(String msg) {
-        return new InvalidModuleDescriptorException(msg);
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with a detail message to
-     * indicate that the class file is truncated.
-     */
-    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
-        return invalidModuleDescriptor("Truncated module-info.class");
-    }
-
-}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java
deleted file mode 100644
index 15df030..0000000
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.module;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.jmod.JmodFile.Section;
-import jdk.internal.module.Checks;
-import jdk.internal.perf.PerfCounter;
-import jdk.internal.util.jar.VersionedStream;
-
-
-/**
- * A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
- */
-
-class ModulePath implements ModuleFinder {
-    private static final String MODULE_INFO = "module-info.class";
-
-    // the version to use for multi-release modular JARs
-    private final Runtime.Version releaseVersion;
-
-    // true for the link phase (supports modules packaged in JMOD format)
-    private final boolean isLinkPhase;
-
-    // the entries on this module path
-    private final Path[] entries;
-    private int next;
-
-    // map of module name to module reference map for modules already located
-    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
-
-    ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
-        this.releaseVersion = version;
-        this.isLinkPhase = isLinkPhase;
-        this.entries = entries.clone();
-        for (Path entry : this.entries) {
-            Objects.requireNonNull(entry);
-        }
-    }
-
-    ModulePath(Path... entries) {
-        this(JarFile.runtimeVersion(), false, entries);
-    }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-
-        // try cached modules
-        ModuleReference m = cachedModules.get(name);
-        if (m != null)
-            return Optional.of(m);
-
-        // the module may not have been encountered yet
-        while (hasNextEntry()) {
-            scanNextEntry();
-            m = cachedModules.get(name);
-            if (m != null)
-                return Optional.of(m);
-        }
-        return Optional.empty();
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        // need to ensure that all entries have been scanned
-        while (hasNextEntry()) {
-            scanNextEntry();
-        }
-        return cachedModules.values().stream().collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns {@code true} if there are additional entries to scan
-     */
-    private boolean hasNextEntry() {
-        return next < entries.length;
-    }
-
-    /**
-     * Scans the next entry on the module path. A no-op if all entries have
-     * already been scanned.
-     *
-     * @throws FindException if an error occurs scanning the next entry
-     */
-    private void scanNextEntry() {
-        if (hasNextEntry()) {
-
-            long t0 = System.nanoTime();
-
-            Path entry = entries[next];
-            Map<String, ModuleReference> modules = scan(entry);
-            next++;
-
-            // update cache, ignoring duplicates
-            int initialSize = cachedModules.size();
-            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
-                cachedModules.putIfAbsent(e.getKey(), e.getValue());
-            }
-
-            // update counters
-            int added = cachedModules.size() - initialSize;
-            moduleCount.add(added);
-
-            scanTime.addElapsedTimeFrom(t0);
-        }
-    }
-
-
-    /**
-     * Scan the given module path entry. If the entry is a directory then it is
-     * a directory of modules or an exploded module. If the entry is a regular
-     * file then it is assumed to be a packaged module.
-     *
-     * @throws FindException if an error occurs scanning the entry
-     */
-    private Map<String, ModuleReference> scan(Path entry) {
-
-        BasicFileAttributes attrs;
-        try {
-            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-        } catch (NoSuchFileException e) {
-            return Collections.emptyMap();
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-
-        try {
-
-            if (attrs.isDirectory()) {
-                Path mi = entry.resolve(MODULE_INFO);
-                if (!Files.exists(mi)) {
-                    // does not exist or unable to determine so assume a
-                    // directory of modules
-                    return scanDirectory(entry);
-                }
-            }
-
-            // packaged or exploded module
-            ModuleReference mref = readModule(entry, attrs);
-            if (mref != null) {
-                String name = mref.descriptor().name();
-                return Collections.singletonMap(name, mref);
-            } else {
-                // skipped
-                return Collections.emptyMap();
-            }
-
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-    }
-
-
-    /**
-     * Scans the given directory for packaged or exploded modules.
-     *
-     * @return a map of module name to ModuleReference for the modules found
-     *         in the directory
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if an error occurs scanning the entry or the
-     *         directory contains two or more modules with the same name
-     */
-    private Map<String, ModuleReference> scanDirectory(Path dir)
-        throws IOException
-    {
-        // The map of name -> mref of modules found in this directory.
-        Map<String, ModuleReference> nameToReference = new HashMap<>();
-
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
-            for (Path entry : stream) {
-                BasicFileAttributes attrs;
-                try {
-                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-                } catch (NoSuchFileException ignore) {
-                    // file has been removed or moved, ignore for now
-                    continue;
-                }
-
-                ModuleReference mref = readModule(entry, attrs);
-
-                // module found
-                if (mref != null) {
-                    // can have at most one version of a module in the directory
-                    String name = mref.descriptor().name();
-                    ModuleReference previous = nameToReference.put(name, mref);
-                    if (previous != null) {
-                        String fn1 = fileName(mref);
-                        String fn2 = fileName(previous);
-                        throw new FindException("Two versions of module "
-                                                 + name + " found in " + dir
-                                                 + " (" + fn1 + " and " + fn2 + ")");
-                    }
-                }
-            }
-        }
-
-        return nameToReference;
-    }
-
-
-    /**
-     * Locates a packaged or exploded module, returning a {@code ModuleReference}
-     * to the module. Returns {@code null} if the entry is skipped because it is
-     * to a directory that does not contain a module-info.class or it's a hidden
-     * file.
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if the file is not recognized as a module or an
-     *         error occurs parsing its module descriptor
-     */
-    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
-        throws IOException
-    {
-        try {
-
-            if (attrs.isDirectory()) {
-                return readExplodedModule(entry); // may return null
-            }
-
-            String fn = entry.getFileName().toString();
-            if (attrs.isRegularFile()) {
-                if (fn.endsWith(".jar")) {
-                    return readJar(entry);
-                } else if (fn.endsWith(".jmod")) {
-                    if (isLinkPhase)
-                        return readJMod(entry);
-                    throw new FindException("JMOD files not supported: " + entry);
-                }
-            }
-
-            // skip hidden files
-            if (fn.startsWith(".") || Files.isHidden(entry)) {
-                return null;
-            } else {
-                throw new FindException("Unrecognized module: " + entry);
-            }
-
-        } catch (InvalidModuleDescriptorException e) {
-            throw new FindException("Error reading module: " + entry, e);
-        }
-    }
-
-
-    /**
-     * Returns a string with the file name of the module if possible.
-     * If the module location is not a file URI then return the URI
-     * as a string.
-     */
-    private String fileName(ModuleReference mref) {
-        URI uri = mref.location().orElse(null);
-        if (uri != null) {
-            if (uri.getScheme().equalsIgnoreCase("file")) {
-                Path file = Paths.get(uri);
-                return file.getFileName().toString();
-            } else {
-                return uri.toString();
-            }
-        } else {
-            return "<unknown>";
-        }
-    }
-
-    // -- jmod files --
-
-    private Set<String> jmodPackages(JmodFile jf) {
-        return jf.stream()
-            .filter(e -> e.section() == Section.CLASSES)
-            .map(JmodFile.Entry::name)
-            .map(this::toPackageName)
-            .flatMap(Optional::stream)
-            .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in jmod file on the
-     * file system.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJMod(Path file) throws IOException {
-        try (JmodFile jf = new JmodFile(file)) {
-            ModuleDescriptor md;
-            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
-                md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
-            }
-            return ModuleReferences.newJModModule(md, file);
-        }
-    }
-
-
-    // -- JAR files --
-
-    private static final String SERVICES_PREFIX = "META-INF/services/";
-
-    /**
-     * Returns the service type corresponding to the name of a services
-     * configuration file if it is a valid Java identifier.
-     *
-     * For example, if called with "META-INF/services/p.S" then this method
-     * returns a container with the value "p.S".
-     */
-    private Optional<String> toServiceName(String cf) {
-        assert cf.startsWith(SERVICES_PREFIX);
-        int index = cf.lastIndexOf("/") + 1;
-        if (index < cf.length()) {
-            String prefix = cf.substring(0, index);
-            if (prefix.equals(SERVICES_PREFIX)) {
-                String sn = cf.substring(index);
-                if (Checks.isJavaIdentifier(sn))
-                    return Optional.of(sn);
-            }
-        }
-        return Optional.empty();
-    }
-
-    /**
-     * Reads the next line from the given reader and trims it of comments and
-     * leading/trailing white space.
-     *
-     * Returns null if the reader is at EOF.
-     */
-    private String nextLine(BufferedReader reader) throws IOException {
-        String ln = reader.readLine();
-        if (ln != null) {
-            int ci = ln.indexOf('#');
-            if (ci >= 0)
-                ln = ln.substring(0, ci);
-            ln = ln.trim();
-        }
-        return ln;
-    }
-
-    /**
-     * Treat the given JAR file as a module as follows:
-     *
-     * 1. The module name (and optionally the version) is derived from the file
-     *    name of the JAR file
-     * 2. All packages are exported and open
-     * 3. It has no non-exported/non-open packages
-     * 4. The contents of any META-INF/services configuration files are mapped
-     *    to "provides" declarations
-     * 5. The Main-Class attribute in the main attributes of the JAR manifest
-     *    is mapped to the module descriptor mainClass
-     */
-    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
-        throws IOException
-    {
-        // Derive module name and version from JAR file name
-
-        String fn = jf.getName();
-        int i = fn.lastIndexOf(File.separator);
-        if (i != -1)
-            fn = fn.substring(i+1);
-
-        // drop .jar
-        String mn = fn.substring(0, fn.length()-4);
-        String vs = null;
-
-        // find first occurrence of -${NUMBER}. or -${NUMBER}$
-        Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
-        if (matcher.find()) {
-            int start = matcher.start();
-
-            // attempt to parse the tail as a version string
-            try {
-                String tail = mn.substring(start+1);
-                ModuleDescriptor.Version.parse(tail);
-                vs = tail;
-            } catch (IllegalArgumentException ignore) { }
-
-            mn = mn.substring(0, start);
-        }
-
-        // finally clean up the module name
-        mn = cleanModuleName(mn);
-
-        // Builder throws IAE if module name is empty or invalid
-        ModuleDescriptor.Builder builder
-            = ModuleDescriptor.automaticModule(mn)
-                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
-        if (vs != null)
-            builder.version(vs);
-
-        // scan the names of the entries in the JAR file
-        Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
-                                                   Collectors.toSet()));
-
-        Set<String> resources = map.get(Boolean.FALSE);
-        Set<String> configFiles = map.get(Boolean.TRUE);
-        // all packages are exported and open
-        resources.stream()
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .distinct()
-                .forEach(pn -> builder.exports(pn).opens(pn));
-
-        // map names of service configuration files to service names
-        Set<String> serviceNames = configFiles.stream()
-                .map(this::toServiceName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-
-        // parse each service configuration file
-        for (String sn : serviceNames) {
-            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            List<String> providerClasses = new ArrayList<>();
-            try (InputStream in = jf.getInputStream(entry)) {
-                BufferedReader reader
-                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-                String cn;
-                while ((cn = nextLine(reader)) != null) {
-                    if (cn.length() > 0) {
-                        providerClasses.add(cn);
-                    }
-                }
-            }
-            if (!providerClasses.isEmpty())
-                builder.provides(sn, providerClasses);
-        }
-
-        // Main-Class attribute if it exists
-        Manifest man = jf.getManifest();
-        if (man != null) {
-            Attributes attrs = man.getMainAttributes();
-            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
-            if (mainClass != null)
-                builder.mainClass(mainClass.replace("/", "."));
-        }
-
-        return builder.build();
-    }
-
-    /**
-     * Patterns used to derive the module name from a JAR file name.
-     */
-    private static class Patterns {
-        static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
-        static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
-        static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
-        static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
-        static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
-        static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
-    }
-
-    /**
-     * Clean up candidate module name derived from a JAR file name.
-     */
-    private static String cleanModuleName(String mn) {
-        // drop trailing version from name
-        mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
-
-        // replace non-alphanumeric
-        mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
-
-        // collapse repeating dots
-        mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
-
-        // drop leading dots
-        if (mn.length() > 0 && mn.charAt(0) == '.')
-            mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
-
-        // drop trailing dots
-        int len = mn.length();
-        if (len > 0 && mn.charAt(len-1) == '.')
-            mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
-
-        return mn;
-    }
-
-    private Set<String> jarPackages(JarFile jf) {
-        return VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in modular JAR file on
-     * the file system.
-     *
-     * @throws IOException
-     * @throws FindException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJar(Path file) throws IOException {
-        try (JarFile jf = new JarFile(file.toFile(),
-                                      true,               // verify
-                                      ZipFile.OPEN_READ,
-                                      releaseVersion))
-        {
-            ModuleDescriptor md;
-            JarEntry entry = jf.getJarEntry(MODULE_INFO);
-            if (entry == null) {
-
-                // no module-info.class so treat it as automatic module
-                try {
-                    md = deriveModuleDescriptor(jf);
-                } catch (IllegalArgumentException iae) {
-                    throw new FindException(
-                        "Unable to derive module descriptor for: "
-                        + jf.getName(), iae);
-                }
-
-            } else {
-                md = ModuleDescriptor.read(jf.getInputStream(entry),
-                                           () -> jarPackages(jf));
-            }
-
-            return ModuleReferences.newJarModule(md, file);
-        }
-    }
-
-
-    // -- exploded directories --
-
-    private Set<String> explodedPackages(Path dir) {
-        try {
-            return Files.find(dir, Integer.MAX_VALUE,
-                              ((path, attrs) -> attrs.isRegularFile()))
-                    .map(path -> dir.relativize(path))
-                    .map(this::toPackageName)
-                    .flatMap(Optional::stream)
-                    .collect(Collectors.toSet());
-        } catch (IOException x) {
-            throw new UncheckedIOException(x);
-        }
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to an exploded module on the file
-     * system or {@code null} if {@code module-info.class} not found.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readExplodedModule(Path dir) throws IOException {
-        Path mi = dir.resolve(MODULE_INFO);
-        ModuleDescriptor md;
-        try (InputStream in = Files.newInputStream(mi)) {
-            md = ModuleDescriptor.read(new BufferedInputStream(in),
-                                       () -> explodedPackages(dir));
-        } catch (NoSuchFileException e) {
-            // for now
-            return null;
-        }
-        return ModuleReferences.newExplodedModule(md, dir);
-    }
-
-    /**
-     * Maps the name of an entry in a JAR or ZIP file to a package name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory of the JAR/ZIP file (and it's
-     *         not module-info.class)
-     */
-    private Optional<String> toPackageName(String name) {
-        assert !name.endsWith("/");
-
-        int index = name.lastIndexOf("/");
-        if (index == -1) {
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in top-level directory:"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = name.substring(0, index).replace('/', '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    /**
-     * Maps the relative path of an entry in an exploded module to a package
-     * name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory (and it's not module-info.class)
-     */
-    private Optional<String> toPackageName(Path file) {
-        assert file.getRoot() == null;
-
-        Path parent = file.getParent();
-        if (parent == null) {
-            String name = file.toString();
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in in top-level directory"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = parent.toString().replace(File.separatorChar, '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    private static final PerfCounter scanTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
-}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
index cbf84cf..09a5ace 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
@@ -26,96 +26,42 @@
 package java.lang.module;
 
 import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes.HashSupplier;
 
 
 /**
  * A reference to a module's content.
  *
- * <p> A module reference contains the module's descriptor and its location, if
- * known.  It also has the ability to create a {@link ModuleReader} in order to
- * access the module's content, which may be inside the Java run-time system
- * itself or in an artifact such as a modular JAR file.
+ * <p> A module reference is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. It contains the
+ * module's descriptor and its location, if known.  It also has the ability to
+ * create a {@link ModuleReader} in order to access the module's content, which
+ * may be inside the Java run-time system itself or in an artifact such as a
+ * modular JAR file.
  *
  * @see ModuleFinder
  * @see ModuleReader
  * @since 9
  */
 
-public final class ModuleReference {
+public abstract class ModuleReference {
 
     private final ModuleDescriptor descriptor;
     private final URI location;
-    private final Supplier<ModuleReader> readerSupplier;
-
-    // true if this is a reference to a patched module
-    private boolean patched;
-
-    // the function that computes the hash of this module reference
-    private final HashSupplier hasher;
-
-    // cached hash to avoid needing to compute it many times
-    private byte[] cachedHash;
-
 
     /**
      * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    boolean patched,
-                    HashSupplier hasher)
-
-    {
-        this.descriptor = Objects.requireNonNull(descriptor);
-        this.location = location;
-        this.readerSupplier = Objects.requireNonNull(readerSupplier);
-        this.patched = patched;
-        this.hasher = hasher;
-    }
-
-    /**
-     * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    HashSupplier hasher)
-
-    {
-        this(descriptor, location, readerSupplier, false, hasher);
-    }
-
-
-    /**
-     * Constructs a new instance of this class.
-     *
-     * <p> The {@code readSupplier} parameter is the supplier of the {@link
-     * ModuleReader} that may be used to read the module content. Its {@link
-     * Supplier#get() get()} method throws {@link UncheckedIOException} if an
-     * I/O error occurs opening the module content. The {@code get()} method
-     * throws {@link SecurityException} if opening the module is denied by the
-     * security manager.
      *
      * @param descriptor
      *        The module descriptor
      * @param location
      *        The module location or {@code null} if not known
-     * @param readerSupplier
-     *        The {@code Supplier} of the {@code ModuleReader}
      */
-    public ModuleReference(ModuleDescriptor descriptor,
-                           URI location,
-                           Supplier<ModuleReader> readerSupplier)
-    {
-        this(descriptor, location, readerSupplier, false, null);
+    protected ModuleReference(ModuleDescriptor descriptor, URI location) {
+        this.descriptor = Objects.requireNonNull(descriptor);
+        this.location = location;
     }
 
     /**
@@ -123,11 +69,10 @@
      *
      * @return The module descriptor
      */
-    public ModuleDescriptor descriptor() {
+    public final ModuleDescriptor descriptor() {
         return descriptor;
     }
 
-
     /**
      * Returns the location of this module's content, if known.
      *
@@ -139,18 +84,13 @@
      *
      * @return The location or an empty {@code Optional} if not known
      */
-    public Optional<URI> location() {
+    public final Optional<URI> location() {
         return Optional.ofNullable(location);
     }
 
-
     /**
      * Opens the module content for reading.
      *
-     * <p> This method opens the module content by invoking the {@link
-     * Supplier#get() get()} method of the {@code readSupplier} specified at
-     * construction time. </p>
-     *
      * @return A {@code ModuleReader} to read the module
      *
      * @throws IOException
@@ -158,113 +98,5 @@
      * @throws SecurityException
      *         If denied by the security manager
      */
-    public ModuleReader open() throws IOException {
-        try {
-            return readerSupplier.get();
-        } catch (UncheckedIOException e) {
-            throw e.getCause();
-        }
-
-    }
-
-
-    /**
-     * Returns {@code true} if this module has been patched via --patch-module.
-     */
-    boolean isPatched() {
-        return patched;
-    }
-
-    /**
-     * Returns the hash supplier for this module.
-     */
-    HashSupplier hasher() {
-        return hasher;
-    }
-
-    /**
-     * Computes the hash of this module. Returns {@code null} if the hash
-     * cannot be computed.
-     *
-     * @throws java.io.UncheckedIOException if an I/O error occurs
-     */
-    byte[] computeHash(String algorithm) {
-        byte[] result = cachedHash;
-        if (result != null)
-            return result;
-        if (hasher == null)
-            return null;
-        cachedHash = result = hasher.generate(algorithm);
-        return result;
-    }
-
-    /**
-     * Computes a hash code for this module reference.
-     *
-     * <p> The hash code is based upon the components of the reference, and
-     * satisfies the general contract of the {@link Object#hashCode
-     * Object.hashCode} method. </p>
-     *
-     * @return The hash-code value for this module reference
-     */
-    @Override
-    public int hashCode() {
-        int hc = hash;
-        if (hc == 0) {
-            hc = descriptor.hashCode();
-            hc = 43 * hc + readerSupplier.hashCode();
-            hc = 43 * hc + Objects.hashCode(location);
-            hc = 43 * hc + Objects.hashCode(hasher);
-            hc = 43 * hc + Boolean.hashCode(patched);
-            if (hc == 0)
-                hc = -1;
-            hash = hc;
-        }
-        return hc;
-    }
-
-    private int hash;
-
-    /**
-     * Tests this module reference for equality with the given object.
-     *
-     * <p> If the given object is not a {@code ModuleReference} then this
-     * method returns {@code false}. Two module references are equal if their
-     * module descriptors are equal, their locations are equal or both unknown,
-     * and were created with equal supplier objects to access the module
-     * content. </p>
-     *
-     * <p> This method satisfies the general contract of the {@link
-     * java.lang.Object#equals(Object) Object.equals} method. </p>
-     *
-     * @param   ob
-     *          the object to which this object is to be compared
-     *
-     * @return  {@code true} if, and only if, the given object is a module
-     *          reference that is equal to this module reference
-     */
-    @Override
-    public boolean equals(Object ob) {
-        if (!(ob instanceof ModuleReference))
-            return false;
-        ModuleReference that = (ModuleReference)ob;
-
-        return Objects.equals(this.descriptor, that.descriptor)
-                && Objects.equals(this.location, that.location)
-                && Objects.equals(this.readerSupplier, that.readerSupplier)
-                && Objects.equals(this.hasher, that.hasher)
-                && this.patched == that.patched;
-    }
-
-    /**
-     * Returns a string describing this module reference.
-     *
-     * @return A string describing this module reference
-     */
-    @Override
-    public String toString() {
-        return ("[module " + descriptor().name()
-                + ", location=" + location + "]");
-    }
-
+    public abstract ModuleReader open() throws IOException;
 }
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java
deleted file mode 100644
index e53ba04..0000000
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.module;
-
-import java.io.File;
-import java.io.IOError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Supplier;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModuleHashes;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.module.ModulePatcher;
-import jdk.internal.util.jar.VersionedStream;
-import sun.net.www.ParseUtil;
-
-
-/**
- * A factory for creating ModuleReference implementations where the modules are
- * packaged as modular JAR file, JMOD files or where the modules are exploded
- * on the file system.
- */
-
-class ModuleReferences {
-
-    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
-    private ModuleReferences() { }
-
-    /**
-     * Creates a ModuleReference to a module or to patched module when
-     * creating modules for the boot Layer and --patch-module is specified.
-     */
-    private static ModuleReference newModule(ModuleDescriptor md,
-                                             URI uri,
-                                             Supplier<ModuleReader> supplier,
-                                             HashSupplier hasher) {
-
-        ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
-        if (JLA.getBootLayer() == null)
-            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a modular JAR.
-     */
-    static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, uri, supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a JMOD.
-     */
-    static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, file.toUri(), supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to an exploded module.
-     */
-    static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
-        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
-        return newModule(md, dir.toUri(), supplier, null);
-    }
-
-
-    /**
-     * A base module reader that encapsulates machinery required to close the
-     * module reader safely.
-     */
-    static abstract class SafeCloseModuleReader implements ModuleReader {
-
-        // RW lock to support safe close
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private final Lock readLock = lock.readLock();
-        private final Lock writeLock = lock.writeLock();
-        private boolean closed;
-
-        SafeCloseModuleReader() { }
-
-        /**
-         * Returns a URL to  resource. This method is invoked by the find
-         * method to do the actual work of finding the resource.
-         */
-        abstract Optional<URI> implFind(String name) throws IOException;
-
-        /**
-         * Returns an input stream for reading a resource. This method is
-         * invoked by the open method to do the actual work of opening
-         * an input stream to the resource.
-         */
-        abstract Optional<InputStream> implOpen(String name) throws IOException;
-
-        /**
-         * Returns a stream of the names of resources in the module. This
-         * method is invoked by the list method to do the actual work of
-         * creating the stream.
-         */
-        abstract Stream<String> implList() throws IOException;
-
-        /**
-         * Closes the module reader. This method is invoked by close to do the
-         * actual work of closing the module reader.
-         */
-        abstract void implClose() throws IOException;
-
-        @Override
-        public final Optional<URI> find(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implFind(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-
-        @Override
-        public final Optional<InputStream> open(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implOpen(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final Stream<String> list() throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implList();
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final void close() throws IOException {
-            writeLock.lock();
-            try {
-                if (!closed) {
-                    closed = true;
-                    implClose();
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a modular JAR file.
-     */
-    static class JarModuleReader extends SafeCloseModuleReader {
-        private final JarFile jf;
-        private final URI uri;
-
-        static JarFile newJarFile(Path path) {
-            try {
-                return new JarFile(path.toFile(),
-                                   true,               // verify
-                                   ZipFile.OPEN_READ,
-                                   JarFile.runtimeVersion());
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JarModuleReader(Path path, URI uri) {
-            this.jf = newJarFile(path);
-            this.uri = uri;
-        }
-
-        private JarEntry getEntry(String name) {
-            return jf.getJarEntry(Objects.requireNonNull(name));
-        }
-
-        @Override
-        Optional<URI> implFind(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                if (jf.isMultiRelease())
-                    name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jar:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = VersionedStream.stream(jf)
-                    .filter(e -> !e.isDirectory())
-                    .map(JarEntry::getName)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a JMOD file.
-     */
-    static class JModModuleReader extends SafeCloseModuleReader {
-        private final JmodFile jf;
-        private final URI uri;
-
-        static JmodFile newJmodFile(Path path) {
-            try {
-                return new JmodFile(path);
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JModModuleReader(Path path, URI uri) {
-            this.jf = newJmodFile(path);
-            this.uri = uri;
-        }
-
-        private JmodFile.Entry getEntry(String name) {
-            Objects.requireNonNull(name);
-            return jf.getEntry(JmodFile.Section.CLASSES, name);
-        }
-
-        @Override
-        Optional<URI> implFind(String name) {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jmod:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = jf.stream()
-                    .filter(e -> e.section() == JmodFile.Section.CLASSES)
-                    .map(JmodFile.Entry::name)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for an exploded module.
-     */
-    static class ExplodedModuleReader implements ModuleReader {
-        private final Path dir;
-        private volatile boolean closed;
-
-        ExplodedModuleReader(Path dir) {
-            this.dir = dir;
-
-            // when running with a security manager then check that the caller
-            // has access to the directory.
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                boolean unused = Files.isDirectory(dir);
-            }
-        }
-
-        /**
-         * Returns a Path to access to the given resource.
-         */
-        private Path toPath(String name) {
-            Path path = Paths.get(name.replace('/', File.separatorChar));
-            if (path.getRoot() == null) {
-                return dir.resolve(path);
-            } else {
-                // drop the root component so that the resource is
-                // located relative to the module directory
-                int n = path.getNameCount();
-                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
-            }
-        }
-
-        /**
-         * Throws IOException if the module reader is closed;
-         */
-        private void ensureOpen() throws IOException {
-            if (closed) throw new IOException("ModuleReader is closed");
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                try {
-                    return Optional.of(path.toUri());
-                } catch (IOError e) {
-                    throw (IOException) e.getCause();
-                }
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(Files.newInputStream(path));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            ensureOpen();
-            // sym links not followed
-            return Files.find(dir, Integer.MAX_VALUE,
-                              (path, attrs) -> attrs.isRegularFile())
-                    .map(f -> dir.relativize(f)
-                                 .toString()
-                                 .replace(File.separatorChar, '/'));
-        }
-
-        @Override
-        public void close() {
-            closed = true;
-        }
-    }
-
-}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
index 5f716b1..d2aafdc 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
@@ -46,6 +46,7 @@
 import java.util.stream.Collectors;
 
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
@@ -438,24 +439,32 @@
      */
     private void checkHashes() {
         for (ModuleReference mref : nameToReference.values()) {
-            ModuleDescriptor descriptor = mref.descriptor();
 
-            // get map of module hashes
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (!ohashes.isPresent())
+            // get the recorded hashes, if any
+            if (!(mref instanceof ModuleReferenceImpl))
                 continue;
-            ModuleHashes hashes = ohashes.get();
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes == null)
+                continue;
 
+            ModuleDescriptor descriptor = mref.descriptor();
             String algorithm = hashes.algorithm();
             for (String dn : hashes.names()) {
-                ModuleReference other = nameToReference.get(dn);
-                if (other == null) {
+                ModuleReference mref2 = nameToReference.get(dn);
+                if (mref2 == null) {
                     ResolvedModule resolvedModule = findInParent(dn);
                     if (resolvedModule != null)
-                        other = resolvedModule.reference();
+                        mref2 = resolvedModule.reference();
+                }
+                if (mref2 == null)
+                    continue;
+
+                if (!(mref2 instanceof ModuleReferenceImpl)) {
+                    fail("Unable to compute the hash of module %s", dn);
                 }
 
                 // skip checking the hash if the module has been patched
+                ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
                 if (other != null && !other.isPatched()) {
                     byte[] recordedHash = hashes.hashFor(dn);
                     byte[] actualHash = other.computeHash(algorithm);
diff --git a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java
deleted file mode 100644
index 6de8ce8..0000000
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.module;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.net.URLConnection;
-import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-import jdk.internal.jimage.ImageReaderFactory;
-import jdk.internal.misc.JavaNetUriAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModuleHashes;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.module.SystemModules;
-import jdk.internal.module.ModulePatcher;
-import jdk.internal.perf.PerfCounter;
-
-/**
- * A {@code ModuleFinder} that finds modules that are linked into the
- * run-time image.
- *
- * The modules linked into the run-time image are assumed to have the
- * Packages attribute.
- */
-
-class SystemModuleFinder implements ModuleFinder {
-
-    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
-
-    private static final PerfCounter initTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
-    private static final PerfCounter packageCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
-    private static final PerfCounter exportsCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-    // ImageReader used to access all modules in the image
-    private static final ImageReader imageReader;
-
-    // the set of modules in the run-time image
-    private static final Set<ModuleReference> modules;
-
-    // maps module name to module reference
-    private static final Map<String, ModuleReference> nameToModule;
-
-    /**
-     * For now, the module references are created eagerly on the assumption
-     * that service binding will require all modules to be located.
-     */
-    static {
-        long t0 = System.nanoTime();
-        imageReader = ImageReaderFactory.getImageReader();
-
-        String[] names = moduleNames();
-        ModuleDescriptor[] descriptors = descriptors(names);
-
-        int n = names.length;
-        moduleCount.add(n);
-
-        ModuleReference[] mods = new ModuleReference[n];
-
-        @SuppressWarnings(value = {"rawtypes", "unchecked"})
-        Entry<String, ModuleReference>[] map
-            = (Entry<String, ModuleReference>[])new Entry[n];
-
-        for (int i = 0; i < n; i++) {
-            ModuleDescriptor md = descriptors[i];
-
-            // create the ModuleReference
-            ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
-
-            mods[i] = mref;
-            map[i] = Map.entry(names[i], mref);
-
-            // counters
-            packageCount.add(md.packages().size());
-            exportsCount.add(md.exports().size());
-        }
-
-        modules = Set.of(mods);
-        nameToModule = Map.ofEntries(map);
-
-        initTime.addElapsedTimeFrom(t0);
-    }
-
-    /*
-     * Returns an array of ModuleDescriptor of the given module names.
-     *
-     * This obtains ModuleDescriptors from SystemModules class that is generated
-     * from the jlink system-modules plugin.  ModuleDescriptors have already
-     * been validated at link time.
-     *
-     * If java.base is patched, or fastpath is disabled for troubleshooting
-     * purpose, it will fall back to find system modules via jrt file system.
-     */
-    private static ModuleDescriptor[] descriptors(String[] names) {
-        // fastpath is enabled by default.
-        // It can be disabled for troubleshooting purpose.
-        boolean disabled =
-            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
-
-        // fast loading of ModuleDescriptor of system modules
-        if (isFastPathSupported() && !disabled)
-            return SystemModules.modules();
-
-        // if fast loading of ModuleDescriptors is disabled
-        // fallback to read module-info.class
-        ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
-        for (int i = 0; i < names.length; i++) {
-            String mn = names[i];
-            ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
-            descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
-
-            // add the recorded hashes of tied modules
-            Hashes.add(descriptors[i]);
-        }
-        return descriptors;
-    }
-
-    private static boolean isFastPathSupported() {
-       return SystemModules.MODULE_NAMES.length > 0;
-    }
-
-    private static String[] moduleNames() {
-        if (isFastPathSupported())
-            // module names recorded at link time
-            return SystemModules.MODULE_NAMES;
-
-        // this happens when java.base is patched with java.base
-        // from an exploded image
-        return imageReader.getModuleNames();
-    }
-
-    private static ModuleReference toModuleReference(ModuleDescriptor md,
-                                                     HashSupplier hash)
-    {
-        String mn = md.name();
-        URI uri = JNUA.create("jrt", "/".concat(mn));
-
-        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
-            @Override
-            public ModuleReader get() {
-                return new ImageModuleReader(mn, uri);
-            }
-        };
-
-        ModuleReference mref =
-            new ModuleReference(md, uri, readerSupplier, hash);
-
-        // may need a reference to a patched module if --patch-module specified
-        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    private static HashSupplier hashSupplier(int index, String name) {
-        if (isFastPathSupported()) {
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return SystemModules.MODULES_TO_HASH[index];
-                }
-            };
-        } else {
-            return Hashes.hashFor(name);
-        }
-    }
-
-    /*
-     * This helper class is only used when SystemModules is patched.
-     * It will get the recorded hashes from module-info.class.
-     */
-    private static class Hashes {
-        static Map<String, byte[]> hashes = new HashMap<>();
-
-        static void add(ModuleDescriptor descriptor) {
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (ohashes.isPresent()) {
-                hashes.putAll(ohashes.get().hashes());
-            }
-        }
-
-        static HashSupplier hashFor(String name) {
-            if (!hashes.containsKey(name))
-                return null;
-
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return hashes.get(name);
-                }
-            };
-        }
-    }
-
-    SystemModuleFinder() { }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-        return Optional.ofNullable(nameToModule.get(name));
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        return modules;
-    }
-
-
-    /**
-     * A ModuleReader for reading resources from a module linked into the
-     * run-time image.
-     */
-    static class ImageModuleReader implements ModuleReader {
-        private final String module;
-        private volatile boolean closed;
-
-        /**
-         * If there is a security manager set then check permission to
-         * connect to the run-time image.
-         */
-        private static void checkPermissionToConnect(URI uri) {
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                try {
-                    URLConnection uc = uri.toURL().openConnection();
-                    sm.checkPermission(uc.getPermission());
-                } catch (IOException ioe) {
-                    throw new UncheckedIOException(ioe);
-                }
-            }
-        }
-
-        ImageModuleReader(String module, URI uri) {
-            checkPermissionToConnect(uri);
-            this.module = module;
-        }
-
-        /**
-         * Returns the ImageLocation for the given resource, {@code null}
-         * if not found.
-         */
-        private ImageLocation findImageLocation(String name) throws IOException {
-            Objects.requireNonNull(name);
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-            if (imageReader != null) {
-                return imageReader.findLocation(module, name);
-            } else {
-                // not an images build
-                return null;
-            }
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                URI u = URI.create("jrt:/" + module + "/" + name);
-                return Optional.of(u);
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            return read(name).map(this::toInputStream);
-        }
-
-        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
-            try {
-                int rem = bb.remaining();
-                byte[] bytes = new byte[rem];
-                bb.get(bytes);
-                return new ByteArrayInputStream(bytes);
-            } finally {
-                release(bb);
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                return Optional.of(imageReader.getResourceBuffer(location));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public void release(ByteBuffer bb) {
-            Objects.requireNonNull(bb);
-            ImageReader.releaseByteBuffer(bb);
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-
-            Spliterator<String> s = new ModuleContentSpliterator(module);
-            return StreamSupport.stream(s, false);
-        }
-
-        @Override
-        public void close() {
-            // nothing else to do
-            closed = true;
-        }
-    }
-
-    /**
-     * A Spliterator for traversing the resources of a module linked into the
-     * run-time image.
-     */
-    static class ModuleContentSpliterator implements Spliterator<String> {
-        final String moduleRoot;
-        final Deque<ImageReader.Node> stack;
-        Iterator<ImageReader.Node> iterator;
-
-        ModuleContentSpliterator(String module) throws IOException {
-            moduleRoot = "/modules/" + module;
-            stack = new ArrayDeque<>();
-
-            // push the root node to the stack to get started
-            ImageReader.Node dir = imageReader.findNode(moduleRoot);
-            if (dir == null || !dir.isDirectory())
-                throw new IOException(moduleRoot + " not a directory");
-            stack.push(dir);
-            iterator = Collections.emptyIterator();
-        }
-
-        /**
-         * Returns the name of the next non-directory node or {@code null} if
-         * there are no remaining nodes to visit.
-         */
-        private String next() throws IOException {
-            for (;;) {
-                while (iterator.hasNext()) {
-                    ImageReader.Node node = iterator.next();
-                    String name = node.getName();
-                    if (node.isDirectory()) {
-                        // build node
-                        ImageReader.Node dir = imageReader.findNode(name);
-                        assert dir.isDirectory();
-                        stack.push(dir);
-                    } else {
-                        // strip /modules/$MODULE/ prefix
-                        return name.substring(moduleRoot.length() + 1);
-                    }
-                }
-
-                if (stack.isEmpty()) {
-                    return null;
-                } else {
-                    ImageReader.Node dir = stack.poll();
-                    assert dir.isDirectory();
-                    iterator = dir.getChildren().iterator();
-                }
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(Consumer<? super String> action) {
-            String next;
-            try {
-                next = next();
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-            if (next != null) {
-                action.accept(next);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public Spliterator<String> trySplit() {
-            return null;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-    }
-}
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
index a046a74..f585b47 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
@@ -28,9 +28,11 @@
 import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
+import jdk.internal.misc.VM;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
+import sun.security.action.GetPropertyAction;
 
 /**
  * The AccessibleObject class is the base class for Field, Method and
@@ -172,8 +174,10 @@
 
         // package is open to caller
         String pn = packageName(declaringClass);
-        if (declaringModule.isOpen(pn, callerModule))
+        if (declaringModule.isOpen(pn, callerModule)) {
+            printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // package is exported to caller and class/member is public
         boolean isExported = declaringModule.isExported(pn, callerModule);
@@ -185,8 +189,10 @@
             modifiers = ((Field) this).getModifiers();
         }
         boolean isMemberPublic = Modifier.isPublic(modifiers);
-        if (isExported && isClassPublic && isMemberPublic)
+        if (isExported && isClassPublic && isMemberPublic) {
+            printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // not accessible
         String msg = "Unable to make ";
@@ -198,7 +204,44 @@
         else
             msg += "opens";
         msg += " " + pn + "\" to " + callerModule;
-        Reflection.throwInaccessibleObjectException(msg);
+        InaccessibleObjectException e = new InaccessibleObjectException(msg);
+        if (Reflection.printStackTraceWhenAccessFails()) {
+            e.printStackTrace(System.err);
+        }
+        throw e;
+    }
+
+    private void printStackTraceIfOpenedReflectively(Module module,
+                                                     String pn,
+                                                     Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, true);
+    }
+
+    private void printStackTraceIfExportedReflectively(Module module,
+                                                       String pn,
+                                                       Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, false);
+    }
+
+    private void printStackTraceIfExposedReflectively(Module module,
+                                                      String pn,
+                                                      Module other,
+                                                      boolean open)
+    {
+        if (Reflection.printStackTraceWhenAccessSucceeds()
+            && !module.isStaticallyExportedOrOpen(pn, other, open))
+        {
+            String msg = other + " allowed to invoke setAccessible on ";
+            if (this instanceof Field)
+                msg += "field ";
+            msg += this;
+            new Exception(msg) {
+                private static final long serialVersionUID = 42L;
+                public String toString() {
+                    return "WARNING: " + getMessage();
+                }
+            }.printStackTrace(System.err);
+        }
     }
 
     /**
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
index 7466c57..4b4588c 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
@@ -246,7 +246,6 @@
          */
         public Controller addOpens(Module source, String pn, Module target) {
             Objects.requireNonNull(source);
-            Objects.requireNonNull(source);
             Objects.requireNonNull(target);
             ensureInLayer(source);
             Modules.addOpens(source, pn, target);
@@ -541,7 +540,7 @@
      * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
      * avoid deadlocks during class loading. In addition, the entity creating
      * a new layer with this method should arrange that the class loaders are
-     * ready to load from these module before there are any attempts to load
+     * ready to load from these modules before there are any attempts to load
      * classes or resources.
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
@@ -603,12 +602,8 @@
 
         checkGetClassLoaderPermission();
 
-        // For now, no two modules in the boot Layer may contain the same
-        // package so we use a simple check for the boot Layer to keep
-        // the overhead at startup to a minimum
-        if (boot() == null) {
-            checkBootModulesForDuplicatePkgs(cf);
-        } else {
+        // The boot layer is checked during module system initialization
+        if (boot() != null) {
             checkForDuplicatePkgs(cf, clf);
         }
 
@@ -658,27 +653,6 @@
     }
 
     /**
-     * Checks a configuration for the boot Layer to ensure that no two modules
-     * have the same package.
-     *
-     * @throws LayerInstantiationException
-     */
-    private static void checkBootModulesForDuplicatePkgs(Configuration cf) {
-        Map<String, String> packageToModule = new HashMap<>();
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
-            String name = descriptor.name();
-            for (String p : descriptor.packages()) {
-                String other = packageToModule.putIfAbsent(p, name);
-                if (other != null) {
-                    throw fail("Package " + p + " in both module "
-                               + name + " and module " + other);
-                }
-            }
-        }
-    }
-
-    /**
      * Checks a configuration and the module-to-loader mapping to ensure that
      * no two modules mapped to the same class loader have the same package.
      * It also checks that no two automatic modules have the same package.
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
index 29f21cc..a71b4b3 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
@@ -559,7 +559,7 @@
      * Returns {@code true} if this module exports or opens a package to
      * the given module via its module declaration.
      */
-    private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+    boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
         // package is open to everyone or <other>
         Map<String, Set<Module>> openPackages = this.openPackages;
         if (openPackages != null) {
@@ -643,6 +643,12 @@
      * <em>open</em>) to the given module. It also has no effect if
      * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
      *
+     * @apiNote As specified in section 5.4.3 of the <cite>The Java&trade;
+     * Virtual Machine Specification </cite>, if an attempt to resolve a
+     * symbolic reference fails because of a linkage error, then subsequent
+     * attempts to resolve the reference always fail with the same error that
+     * was thrown as a result of the initial resolution attempt.
+     *
      * @param  pn
      *         The package name
      * @param  other
@@ -656,6 +662,7 @@
      * @throws IllegalStateException
      *         If this is a named module and the caller is not this module
      *
+     * @jvms 5.4.3 Resolution
      * @see #isExported(String,Module)
      */
     @CallerSensitive
@@ -676,8 +683,8 @@
     }
 
     /**
-     * If the caller's module is this module then update this module to
-     * <em>open</em> the given package to the given module.
+     * If this module has <em>opened</em> a package to at least the caller
+     * module then update this module to open the package to the given module.
      * Opening a package with this method allows all types in the package,
      * and all their members, not just public types and their public members,
      * to be reflected on by the given module when using APIs that support
@@ -699,7 +706,8 @@
      *         If {@code pn} is {@code null}, or this is a named module and the
      *         package {@code pn} is not a package in this module
      * @throws IllegalStateException
-     *         If this is a named module and the caller is not this module
+     *         If this is a named module and this module has not opened the
+     *         package to at least the caller
      *
      * @see #isOpen(String,Module)
      * @see AccessibleObject#setAccessible(boolean)
@@ -713,9 +721,8 @@
 
         if (isNamed() && !descriptor.isOpen()) {
             Module caller = Reflection.getCallerClass().getModule();
-            if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
-            }
+            if (caller != this && !isOpen(pn, caller))
+                throw new IllegalStateException(pn + " is not open to " + caller);
             implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
         }
 
@@ -1568,6 +1575,10 @@
                 public Stream<Layer> layers(ClassLoader loader) {
                     return Layer.layers(loader);
                 }
+                @Override
+                public boolean isStaticallyExported(Module module, String pn, Module other) {
+                    return module.isStaticallyExportedOrOpen(pn, other, false);
+                }
             });
     }
 }
diff --git a/jdk/src/java.base/share/classes/java/security/KeyStore.java b/jdk/src/java.base/share/classes/java/security/KeyStore.java
index 811422f..f963cae 100644
--- a/jdk/src/java.base/share/classes/java/security/KeyStore.java
+++ b/jdk/src/java.base/share/classes/java/security/KeyStore.java
@@ -824,10 +824,14 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyStore." + type.toUpperCase() + " type from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Returns a keystore object of the specified type.
      *
diff --git a/jdk/src/java.base/share/classes/java/security/MessageDigest.java b/jdk/src/java.base/share/classes/java/security/MessageDigest.java
index dac789f..692dce5 100644
--- a/jdk/src/java.base/share/classes/java/security/MessageDigest.java
+++ b/jdk/src/java.base/share/classes/java/security/MessageDigest.java
@@ -430,13 +430,17 @@
         return digest();
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Returns a string representation of this message digest object.
      */
     public String toString() {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         PrintStream p = new PrintStream(baos);
-        p.print(algorithm+" Message Digest from "+provider.getName()+", ");
+        p.print(algorithm+" Message Digest from "+getProviderName()+", ");
         switch (state) {
         case INITIAL:
             p.print("<initialized>");
diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandom.java b/jdk/src/java.base/share/classes/java/security/SecureRandom.java
index 12b60f6..ac4ee6e 100644
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java
@@ -310,10 +310,14 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("SecureRandom." + algorithm +
-                " algorithm from: " + this.provider.getName());
+                " algorithm from: " + getProviderName());
         }
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Returns a {@code SecureRandom} object that implements the specified
      * Random Number Generator (RNG) algorithm.
diff --git a/jdk/src/java.base/share/classes/java/security/Signature.java b/jdk/src/java.base/share/classes/java/security/Signature.java
index df326f4..df5350e 100644
--- a/jdk/src/java.base/share/classes/java/security/Signature.java
+++ b/jdk/src/java.base/share/classes/java/security/Signature.java
@@ -452,6 +452,10 @@
         return this.provider;
     }
 
+    private String getProviderName() {
+        return (provider == null)  ? "(no provider)" : provider.getName();
+    }
+
     void chooseFirstProvider() {
         // empty, overridden in Delegate
     }
@@ -473,7 +477,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -522,7 +526,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -543,7 +547,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
@@ -566,7 +570,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
diff --git a/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java b/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
index f289fdb..7ae6294 100644
--- a/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
+++ b/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -73,11 +73,13 @@
 import java.io.Serializable;
 import java.time.DateTimeException;
 import java.time.LocalDate;
+import java.time.format.TextStyle;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalField;
 import java.time.temporal.UnsupportedTemporalTypeException;
 import java.time.temporal.ValueRange;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.Objects;
 
 import sun.util.calendar.CalendarDate;
@@ -125,8 +127,8 @@
      */
     public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
 
-    // the number of defined JapaneseEra constants.
-    // There could be an extra era defined in its configuration.
+    // The number of predefined JapaneseEra constants.
+    // There may be a supplemental era defined by the property.
     private static final int N_ERA_CONSTANTS = HEISEI.getValue() + ERA_OFFSET;
 
     /**
@@ -237,6 +239,32 @@
         return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
     }
 
+    /**
+     * Gets the textual representation of this era.
+     * <p>
+     * This returns the textual name used to identify the era,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value}
+     * is returned.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the era, not null
+     * @since 9
+     */
+    @Override
+    public String getDisplayName(TextStyle style, Locale locale) {
+        // If this JapaneseEra is a supplemental one, obtain the name from
+        // the era definition.
+        if (getValue() > N_ERA_CONSTANTS - ERA_OFFSET) {
+            Objects.requireNonNull(locale, "locale");
+            return style.asNormal() == TextStyle.NARROW ? getAbbreviation() : getName();
+        }
+        return Era.super.getDisplayName(style, locale);
+    }
+
     //-----------------------------------------------------------------------
     /**
      * Obtains an instance of {@code JapaneseEra} from a date.
@@ -338,11 +366,7 @@
 
     //-----------------------------------------------------------------------
     String getAbbreviation() {
-        int index = ordinal(getValue());
-        if (index == 0) {
-            return "";
-        }
-        return ERA_CONFIG[index].getAbbreviation();
+        return ERA_CONFIG[ordinal(getValue())].getAbbreviation();
     }
 
     String getName() {
diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
index 7f8559d..78e86e5 100644
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -60,7 +60,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.jar.JarEntry;
-import java.util.spi.ResourceBundleControlProvider;
 import java.util.spi.ResourceBundleProvider;
 
 import jdk.internal.loader.BootLoader;
@@ -232,8 +231,6 @@
  * <li>{@code ResourceBundle.Control} is <em>not</em> supported in named modules.
  * If the {@code getBundle} method with a {@code ResourceBundle.Control} is called
  * in a named module, the method will throw an {@code UnsupportedOperationException}.
- * Any service providers of {@link ResourceBundleControlProvider} are ignored in
- * named modules.
  * </li>
  * </ul>
  *
@@ -264,17 +261,6 @@
  * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
  * factory method for details.
  *
- * <p><a name="modify_default_behavior">For the {@code getBundle} factory</a>
- * methods that take no {@link Control} instance, their <a
- * href="#default_behavior"> default behavior</a> of resource bundle loading
- * can be modified with <em>installed</em> {@link
- * ResourceBundleControlProvider} implementations. Any installed providers are
- * detected at the {@code ResourceBundle} class loading time. If any of the
- * providers provides a {@link Control} for the given base name, that {@link
- * Control} will be used instead of the default {@link Control}. If there is
- * more than one service provider installed for supporting the same base name,
- * the first one returned from {@link ServiceLoader} will be used.
- *
  * <h3>Cache Management</h3>
  *
  * Resource bundle instances created by the <code>getBundle</code> factory
@@ -469,21 +455,6 @@
      */
     private volatile Set<String> keySet;
 
-    private static final List<ResourceBundleControlProvider> providers;
-
-    static {
-        List<ResourceBundleControlProvider> list = null;
-        ServiceLoader<ResourceBundleControlProvider> serviceLoaders
-                = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
-        for (ResourceBundleControlProvider provider : serviceLoaders) {
-            if (list == null) {
-                list = new ArrayList<>();
-            }
-            list.add(provider);
-        }
-        providers = list;
-    }
-
     /**
      * Sole constructor.  (For invocation by subclass constructors, typically
      * implicit.)
@@ -948,7 +919,7 @@
     {
         Class<?> caller = Reflection.getCallerClass();
         return getBundleImpl(baseName, Locale.getDefault(),
-                             caller, getDefaultControl(caller, baseName));
+                             caller, Control.INSTANCE);
     }
 
     /**
@@ -1022,7 +993,7 @@
     {
         Class<?> caller = Reflection.getCallerClass();
         return getBundleImpl(baseName, locale,
-                             caller, getDefaultControl(caller, baseName));
+                             caller, Control.INSTANCE);
     }
 
     /**
@@ -1163,10 +1134,7 @@
      *
      * <p>This method behaves the same as calling
      * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
-     * default instance of {@link Control} unless another {@link Control} is
-     * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the
-     * description of <a href="#modify_default_behavior">modifying the default
-     * behavior</a>.
+     * default instance of {@link Control}.
      *
      * <p><a name="default_behavior">The following describes the default
      * behavior</a>.
@@ -1364,7 +1332,7 @@
             throw new NullPointerException();
         }
         Class<?> caller = Reflection.getCallerClass();
-        return getBundleImpl(baseName, locale, caller, loader, getDefaultControl(caller, baseName));
+        return getBundleImpl(baseName, locale, caller, loader, Control.INSTANCE);
     }
 
     /**
@@ -1589,18 +1557,6 @@
         return getBundleImpl(baseName, targetLocale, caller, loader, control);
     }
 
-    private static Control getDefaultControl(Class<?> caller, String baseName) {
-        if (providers != null && !caller.getModule().isNamed()) {
-            for (ResourceBundleControlProvider provider : providers) {
-                Control control = provider.getControl(baseName);
-                if (control != null) {
-                    return control;
-                }
-            }
-        }
-        return Control.INSTANCE;
-    }
-
     private static void checkNamedModule(Class<?> caller) {
         if (caller.getModule().isNamed()) {
             throw new UnsupportedOperationException(
@@ -2573,8 +2529,7 @@
      * @apiNote <a name="note">{@code ResourceBundle.Control} is not supported
      * in named modules.</a> If the {@code ResourceBundle.getBundle} method with
      * a {@code ResourceBundle.Control} is called in a named module, the method
-     * will throw an {@link UnsupportedOperationException}. Any service providers
-     * of {@link ResourceBundleControlProvider} are ignored in named modules.
+     * will throw an {@link UnsupportedOperationException}.
      *
      * @since 1.6
      * @see java.util.spi.ResourceBundleProvider
diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
index 3005df4..8d383f8 100644
--- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
+++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
@@ -35,21 +35,19 @@
  * no {@link java.util.ResourceBundle.Control} instance can be modified with {@code
  * ResourceBundleControlProvider} implementations.
  *
- * <p>Provider implementations must be packaged using the <a
- * href="../../../../technotes/guides/extensions/index.html">Java Extension
- * Mechanism</a> as installed extensions. Refer to {@link java.util.ServiceLoader}
- * for the extension packaging. Any installed {@code
- * ResourceBundleControlProvider} implementations are loaded using {@link
- * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time.
- *
- * <p>All {@code ResourceBundleControlProvider}s are ignored in named modules.
- *
  * @author Masayoshi Okutsu
  * @since 1.8
  * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
  *      ResourceBundle.getBundle
  * @see java.util.ServiceLoader#loadInstalled(Class)
+ * @deprecated There is no longer any mechanism to install a custom
+ * {@code ResourceBundleControlProvider} implementation defined
+ * by the platform class loader or its ancestor. The recommended
+ * way to use a custom {@code Control} implementation to load resource bundle
+ * is to use {@link java.util.ResourceBundle#getBundle(String, Control)}
+ * or other factory methods that take custom {@link java.util.ResourceBundle.Control}.
  */
+@Deprecated(since="9", forRemoval=true)
 public interface ResourceBundleControlProvider {
     /**
      * Returns a {@code ResourceBundle.Control} instance that is used
diff --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java
index 8a53a27..17c743a 100644
--- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java
+++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java
@@ -1268,10 +1268,16 @@
      * to a {@code Predicate}, and organizes them into a
      * {@code Map<Boolean, List<T>>}.
      *
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
      * There are no guarantees on the type, mutability,
      * serializability, or thread-safety of the {@code Map} or {@code List}
      * returned.
      *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * an empty List.
+     *
      * @param <T> the type of the input elements
      * @param predicate a predicate used for classifying input elements
      * @return a {@code Collector} implementing the partitioning operation
@@ -1290,9 +1296,17 @@
      * {@code Map<Boolean, D>} whose values are the result of the downstream
      * reduction.
      *
-     * <p>There are no guarantees on the type, mutability,
+     * <p>
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
+     * There are no guarantees on the type, mutability,
      * serializability, or thread-safety of the {@code Map} returned.
      *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * obtained by calling the downstream collector's supplier function and then
+     * applying the finisher function.
+     *
      * @param <T> the type of the input elements
      * @param <A> the intermediate accumulation type of the downstream collector
      * @param <D> the result type of the downstream reduction
diff --git a/jdk/src/java.base/share/classes/javax/crypto/Cipher.java b/jdk/src/java.base/share/classes/javax/crypto/Cipher.java
index 4c3ba78..48ca2b0 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/Cipher.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/Cipher.java
@@ -611,6 +611,10 @@
         return getInstance(transformation, p);
     }
 
+    private String getProviderName() {
+        return (provider == null)  ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Returns a {@code Cipher} object that implements the specified
      * transformation.
@@ -1278,7 +1282,7 @@
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -1421,7 +1425,7 @@
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -1564,7 +1568,7 @@
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -1754,7 +1758,7 @@
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
diff --git a/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java b/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java
index be333ff..47449b3 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java
@@ -484,7 +484,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -517,6 +517,10 @@
         init(key, params, JceSecurity.RANDOM);
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Initializes this key agreement with the given key, set of
      * algorithm parameters, and source of randomness.
@@ -545,7 +549,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
diff --git a/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java b/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java
index a5277d8b..4cb8b79 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java
@@ -154,7 +154,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -172,10 +172,14 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Returns the algorithm name of this {@code KeyGenerator} object.
      *
diff --git a/jdk/src/java.base/share/classes/javax/crypto/Mac.java b/jdk/src/java.base/share/classes/javax/crypto/Mac.java
index 97cd19a..5a1d12d 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/Mac.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/Mac.java
@@ -415,6 +415,10 @@
         return spi.engineGetMacLength();
     }
 
+    private String getProviderName() {
+        return (provider == null) ? "(no provider)" : provider.getName();
+    }
+
     /**
      * Initializes this {@code Mac} object with the given key.
      *
@@ -437,7 +441,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
@@ -464,7 +468,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
-                this.provider.getName());
+                getProviderName());
         }
     }
 
diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
index 300265c..2c724f7 100644
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
@@ -27,6 +27,8 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
 
 
 /**
@@ -1332,4 +1334,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLEngine}
+     * <dd> The function's first argument allows the current {@code SSLEngine}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverEngine.setHandshakeApplicationProtocolSelector(
+     *         (serverEngine, clientProtocols) -> {
+     *             SSLSession session = serverEngine.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverEngine,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLEngine} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to disable the callback
+     *         functionality.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLEngine, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLEngine, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java
index daaefe0..ebbc9d9 100644
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java
@@ -28,6 +28,8 @@
 
 import java.io.IOException;
 import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
 
 /**
  * This class extends <code>Socket</code>s and provides secure
@@ -742,4 +744,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLSocket}
+     * <dd> The function's first argument allows the current {@code SSLSocket}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverSocket.setHandshakeApplicationProtocolSelector(
+     *         (serverSocket, clientProtocols) -> {
+     *             SSLSession session = serverSocket.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverSocket,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLSocket} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to de-register.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLSocket, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLSocket, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java
index d979f98..1284a3f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java
@@ -64,8 +64,10 @@
     private static final int CONSTANT_MethodHandle = 15;
     private static final int CONSTANT_MethodType = 16;
     private static final int CONSTANT_InvokeDynamic = 18;
+    private static final int CONSTANT_Module = 19;
+    private static final int CONSTANT_Package = 20;
 
-    private static final int[] SIZES = new int[20];
+    private static final int[] SIZES = new int[21];
 
     static {
 
@@ -83,6 +85,8 @@
         SIZES[CONSTANT_MethodHandle] = 3;
         SIZES[CONSTANT_MethodType] = 2;
         SIZES[CONSTANT_InvokeDynamic] = 4;
+        SIZES[CONSTANT_Module] = 2;
+        SIZES[CONSTANT_Package] = 2;
     }
 
     public static int[] getSizes() {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
index 01cece1..34e99df 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
@@ -31,7 +31,10 @@
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Iterator;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -70,12 +73,13 @@
      * JMOD sections
      */
     public static enum Section {
-        NATIVE_LIBS("native"),
-        NATIVE_CMDS("bin"),
         CLASSES("classes"),
         CONFIG("conf"),
         HEADER_FILES("include"),
-        MAN_PAGES("man");
+        LEGAL_NOTICES("legal"),
+        MAN_PAGES("man"),
+        NATIVE_LIBS("native"),
+        NATIVE_CMDS("bin");
 
         private final String jmodDir;
         private Section(String jmodDir) {
@@ -87,7 +91,6 @@
          * this section
          */
         public String jmodDir() { return jmodDir; }
-
     }
 
     /**
@@ -109,7 +112,7 @@
             }
 
             this.zipEntry = e;
-            this.section = section(name);
+            this.section = section(name.substring(0, i));
             this.name = name.substring(i+1);
         }
 
@@ -143,26 +146,21 @@
             return section.jmodDir() + "/" + name;
         }
 
+        /*
+         * A map from the jmodDir name to Section
+         */
+        static final Map<String, Section> NAME_TO_SECTION =
+            Arrays.stream(Section.values())
+                  .collect(Collectors.toMap(Section::jmodDir, Function.identity()));
+
         static Section section(String name) {
-            int i = name.indexOf('/');
-            String s = name.substring(0, i);
-            switch (s) {
-                case "native":
-                    return Section.NATIVE_LIBS;
-                case "bin":
-                    return Section.NATIVE_CMDS;
-                case "classes":
-                    return Section.CLASSES;
-                case "conf":
-                    return Section.CONFIG;
-                case "include":
-                    return Section.HEADER_FILES;
-                case "man":
-                    return Section.MAN_PAGES;
-                default:
-                    throw new IllegalArgumentException("invalid section: " + s);
+            if (!NAME_TO_SECTION.containsKey(name)) {
+                throw new IllegalArgumentException("invalid section: " + name);
+
             }
+            return NAME_TO_SECTION.get(name);
         }
+
     }
 
     private final Path file;
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
index d0b1c19..eed7a2d 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
@@ -38,10 +38,8 @@
 import java.lang.module.ModuleReference;
 import java.net.URI;
 import java.nio.file.Path;
-import java.util.Map;
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
 
@@ -59,21 +57,28 @@
      * @param strict
      *        Indicates whether module names are checked or not
      */
-    ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+    ModuleDescriptor.Builder newModuleBuilder(String mn,
+                                              boolean strict,
+                                              boolean open,
+                                              boolean synthetic);
 
     /**
-     * Creates a builder for building an open module with the given module name.
-     *
-     * @param strict
-     *        Indicates whether module names are checked or not
+     * Returns the set of packages that are exported (unconditionally or
+     * unconditionally).
      */
-    ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+    Set<String> exportedPackages(ModuleDescriptor.Builder builder);
+
+    /**
+     * Returns the set of packages that are opened (unconditionally or
+     * unconditionally).
+     */
+    Set<String> openPackages(ModuleDescriptor.Builder builder);
 
     /**
      * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
      * and module name.
      */
-    Requires newRequires(Set<Requires.Modifier> ms, String mn);
+    Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v);
 
     /**
      * Returns an unqualified {@code ModuleDescriptor.Exports}
@@ -122,6 +127,7 @@
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
+                                         Version version,
                                          boolean open,
                                          boolean automatic,
                                          boolean synthetic,
@@ -130,21 +136,14 @@
                                          Set<Opens> opens,
                                          Set<String> uses,
                                          Set<Provides> provides,
-                                         Version version,
+                                         Set<String> packages,
                                          String mainClass,
                                          String osName,
                                          String osArch,
                                          String osVersion,
-                                         Set<String> packages,
-                                         ModuleHashes hashes,
                                          int hashCode);
 
     /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
-
-    /**
      * Resolves a collection of root modules, with service binding
      * and the empty configuration as the parent. The post resolution
      * checks are optionally run.
@@ -154,18 +153,4 @@
                                          boolean check,
                                          PrintStream traceOutput);
 
-    /**
-     * Creates a ModuleReference to a "patched" module.
-     */
-    ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                     URI location,
-                                     Supplier<ModuleReader> readerSupplier);
-
-    /**
-     * Creates a ModuleFinder for a module path.
-     */
-    ModuleFinder newModulePath(Runtime.Version version,
-                               boolean isLinkPhase,
-                               Path... entries);
-
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
index 5577279..7bf6a1f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java
@@ -123,4 +123,12 @@
      * given class loader.
      */
     Stream<Layer> layers(ClassLoader loader);
+
+    /**
+     * Tests if a module exports a package at least {@code other} via its
+     * module declaration.
+     *
+     * @apiNote This is a temporary method for debugging features.
+     */
+    boolean isStaticallyExported(Module module, String pn, Module other);
 }
\ No newline at end of file
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
index 961dd08..2ef9c11 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
@@ -30,11 +30,8 @@
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import jdk.internal.misc.JavaLangModuleAccess;
@@ -52,7 +49,7 @@
  * SystemModules should contain modules for the boot layer.
  */
 final class Builder {
-    private static final JavaLangModuleAccess jlma =
+    private static final JavaLangModuleAccess JLMA =
         SharedSecrets.getJavaLangModuleAccess();
 
     // Static cache of the most recently seen Version to cheaply deduplicate
@@ -60,13 +57,36 @@
     static Version cachedVersion;
 
     /**
-     * Returns a {@link Requires} for a dependence on a module
-     * with the given (and possibly empty) set of modifiers.
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
+     */
+    public static Requires newRequires(Set<Requires.Modifier> mods,
+                                       String mn,
+                                       String compiledVersion)
+    {
+        Version version = null;
+        if (compiledVersion != null) {
+            // use the cached version if the same version string
+            Version ver = cachedVersion;
+            if (ver != null && compiledVersion.equals(ver.toString())) {
+                version = ver;
+            } else {
+                version = Version.parse(compiledVersion);
+            }
+        }
+        return JLMA.newRequires(mods, mn, version);
+    }
+
+    /**
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
      */
     public static Requires newRequires(Set<Requires.Modifier> mods,
                                        String mn)
     {
-        return jlma.newRequires(mods, mn);
+        return newRequires(mods, mn, null);
     }
 
     /**
@@ -77,7 +97,7 @@
     public static Exports newExports(Set<Exports.Modifier> ms,
                                      String pn,
                                      Set<String> targets) {
-        return jlma.newExports(ms, pn, targets);
+        return JLMA.newExports(ms, pn, targets);
     }
 
     /**
@@ -85,7 +105,7 @@
      * modifiers.
      */
     public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
-        return jlma.newOpens(ms, pn);
+        return JLMA.newOpens(ms, pn);
     }
 
     /**
@@ -96,7 +116,7 @@
     public static Opens newOpens(Set<Opens.Modifier> ms,
                                  String pn,
                                  Set<String> targets) {
-        return jlma.newOpens(ms, pn, targets);
+        return JLMA.newOpens(ms, pn, targets);
     }
 
     /**
@@ -104,7 +124,7 @@
      * of modifiers.
      */
     public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
-        return jlma.newExports(ms, pn);
+        return JLMA.newExports(ms, pn);
     }
 
     /**
@@ -112,7 +132,7 @@
      * implementation classes.
      */
     public static Provides newProvides(String st, List<String> pcs) {
-        return jlma.newProvides(st, pcs);
+        return JLMA.newProvides(st, pcs);
     }
 
     final String name;
@@ -130,8 +150,6 @@
     String osName;
     String osArch;
     String osVersion;
-    String algorithm;
-    Map<String, byte[]> hashes;
 
     Builder(String name) {
         this.name = name;
@@ -275,34 +293,13 @@
     }
 
     /**
-     * Sets the algorithm of the module hashes
-     */
-    public Builder algorithm(String algorithm) {
-        this.algorithm = algorithm;
-        return this;
-    }
-
-    /**
-     * Sets the module hash for the given module name
-     */
-    public Builder moduleHash(String mn, byte[] hash) {
-        if (hashes == null)
-            hashes = new HashMap<>();
-
-        hashes.put(mn, hash);
-        return this;
-    }
-
-    /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
     public ModuleDescriptor build(int hashCode) {
         assert name != null;
 
-        ModuleHashes moduleHashes =
-            hashes != null ? new ModuleHashes(algorithm, hashes) : null;
-
-        return jlma.newModuleDescriptor(name,
+        return JLMA.newModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -311,13 +308,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
                                         osVersion,
-                                        packages,
-                                        moduleHashes,
                                         hashCode);
     }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
index 9f02048..2fdeaab 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
@@ -25,79 +25,200 @@
 
 package jdk.internal.module;
 
+/**
+ * Utility class for checking module name and binary names.
+ */
+
 public final class Checks {
 
     private Checks() { }
 
-    private static void fail(String what, String id, int i) {
-        throw new IllegalArgumentException(id
-                                           + ": Invalid " + what + ": "
-                                           + " Illegal character"
-                                           + " at index " + i);
+    /**
+     * Checks a name to ensure that it's a legal module name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         module name
+     */
+    public static String requireModuleName(String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null module name");
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid module name"
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1) {
+            String id = name.substring(off);
+            throw new IllegalArgumentException(name + ": Invalid module name"
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        //if (!Character.isJavaIdentifierStart(last))
+        //    throw new IllegalArgumentException(name + ": Module name ends in digit");
+        return name;
     }
 
     /**
-     * Returns {@code true} if the given identifier is a legal Java identifier.
+     * Returns {@code true} if the given name is a legal module name.
      */
-    public static boolean isJavaIdentifier(String id) {
-        int n = id.length();
-        if (n == 0)
-            return false;
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-            return false;
-        int cp = id.codePointAt(0);
-        int i = Character.charCount(cp);
-        for (; i < n; i += Character.charCount(cp)) {
-            cp = id.codePointAt(i);
-            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
+    public static boolean isModuleName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
                 return false;
+            off = next+1;
         }
-        if (cp == '.')
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1)
             return false;
-
+        //if (!Character.isJavaIdentifierStart(last))
+        //    return false;
         return true;
     }
 
     /**
-     * Checks if a given identifier is a legal Java identifier.
+     * Checks a name to ensure that it's a legal package name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         package name
      */
-    public static String requireJavaIdentifier(String what, String id) {
-        if (id == null)
-            throw new IllegalArgumentException("Null " + what);
-        int n = id.length();
-        if (n == 0)
-            throw new IllegalArgumentException("Empty " + what);
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-            fail(what, id, 0);
-        int cp = id.codePointAt(0);
-        int i = Character.charCount(cp);
-        int last = 0;
-        for (; i < n; i += Character.charCount(cp)) {
-            cp = id.codePointAt(i);
-            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
-                fail(what, id, i);
-            last = i;
+    public static String requirePackageName(String name) {
+        return requireBinaryName("package name", name);
+    }
+
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
+     */
+    public static String requireServiceTypeName(String name) {
+        return requireBinaryName("service type name", name);
+    }
+
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
+     */
+    public static String requireServiceProviderName(String name) {
+        return requireBinaryName("service provider name", name);
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isJavaIdentifier(String name) {
+        return isBinaryName(name);
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isBinaryName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
+                return false;
+            off = next+1;
         }
-        if (cp == '.')
-            fail(what, id, last);
-
-        return id;
+        int count = name.length() - off;
+        return (isJavaIdentifier(name, off, count) != -1);
     }
 
-    public static String requireModuleName(String id) {
-        return requireJavaIdentifier("module name", id);
+    /**
+     * Checks if the given name is a legal binary name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         binary name
+     */
+    public static String requireBinaryName(String what, String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null " + what);
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid " + what
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next + 1;
+        }
+        if (isJavaIdentifier(name, off, name.length() - off) == -1) {
+            String id = name.substring(off, name.length());
+            throw new IllegalArgumentException(name + ": Invalid " + what
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        return name;
     }
 
-    public static String requirePackageName(String id) {
-        return requireJavaIdentifier("package name", id);
+    /**
+     * Returns {@code true} if the last character of the given name is legal
+     * as the last character of a module name.
+     *
+     * @throws IllegalArgumentException if name is empty
+     */
+    public static boolean hasLegalModuleNameLastCharacter(String name) {
+        if (name.isEmpty())
+            throw new IllegalArgumentException("name is empty");
+        int len = name.length();
+        if (isASCIIString(name)) {
+            char c = name.charAt(len-1);
+            return Character.isJavaIdentifierStart(c);
+        } else {
+            int i = 0;
+            int cp = -1;
+            while (i < len) {
+                cp = name.codePointAt(i);
+                i += Character.charCount(cp);
+            }
+            return Character.isJavaIdentifierStart(cp);
+        }
     }
 
-    public static String requireServiceTypeName(String id) {
-        return requireJavaIdentifier("service type name", id);
+    /**
+     * Returns true if the given string only contains ASCII characters.
+     */
+    private static boolean isASCIIString(String s) {
+        int i = 0;
+        while (i < s.length()) {
+            int c = s.charAt(i);
+            if (c > 0x7F)
+                return false;
+            i++;
+        }
+        return true;
     }
 
-    public static String requireServiceProviderName(String id) {
-        return requireJavaIdentifier("service provider name", id);
-    }
+    /**
+     * Checks if a char sequence is a legal Java identifier, returning the code
+     * point of the last character if legal or {@code -1} if not legal.
+     */
+    private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
+        if (count == 0)
+            return -1;
+        int first = Character.codePointAt(cs, offset);
+        if (!Character.isJavaIdentifierStart(first))
+            return -1;
 
+        int cp = first;
+        int i = Character.charCount(first);
+        while (i < count) {
+            cp = Character.codePointAt(cs, offset+i);
+            if (!Character.isJavaIdentifierPart(cp))
+                return -1;
+            i += Character.charCount(cp);
+        }
+
+        return cp;
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
index 908b137..69c7ee6 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
@@ -68,12 +68,18 @@
             = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
+        private Version replacementVersion;
 
         public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
+        public ModuleAttribute(Version v) {
+            super(MODULE);
+            this.replacementVersion = v;
+        }
+
         public ModuleAttribute() {
             super(MODULE);
         }
@@ -86,46 +92,70 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleAttribute attr = new ModuleAttribute();
-
-            // module_name
-            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            // module_name (CONSTANT_Module_info)
+            String mn = cr.readModule(off, buf);
             off += 2;
 
             // module_flags
             int module_flags = cr.readUnsignedShort(off);
             boolean open = ((module_flags & ACC_OPEN) != 0);
+            boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
             off += 2;
 
-            ModuleDescriptor.Builder builder;
-            if (open) {
-                builder = JLMA.newOpenModuleBuilder(mn, false);
-            } else {
-                builder = JLMA.newModuleBuilder(mn, false);
+            ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
+                                                                     false,
+                                                                     open,
+                                                                     synthetic);
+
+            // module_version
+            String module_version = cr.readUTF8(off, buf);
+            off += 2;
+            if (replacementVersion != null) {
+                builder.version(replacementVersion);
+            } else if (module_version != null) {
+                builder.version(module_version);
             }
 
             // requires_count and requires[requires_count]
             int requires_count = cr.readUnsignedShort(off);
             off += 2;
             for (int i=0; i<requires_count; i++) {
-                String dn = cr.readUTF8(off, buf).replace('/', '.');
-                int flags = cr.readUnsignedShort(off + 2);
+                // CONSTANT_Module_info
+                String dn = cr.readModule(off, buf);
+                off += 2;
+
+                // requires_flags
+                int requires_flags = cr.readUnsignedShort(off);
+                off += 2;
                 Set<Requires.Modifier> mods;
-                if (flags == 0) {
+                if (requires_flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_TRANSITIVE) != 0)
+                    if ((requires_flags & ACC_TRANSITIVE) != 0)
                         mods.add(Requires.Modifier.TRANSITIVE);
-                    if ((flags & ACC_STATIC_PHASE) != 0)
+                    if ((requires_flags & ACC_STATIC_PHASE) != 0)
                         mods.add(Requires.Modifier.STATIC);
-                    if ((flags & ACC_SYNTHETIC) != 0)
+                    if ((requires_flags & ACC_SYNTHETIC) != 0)
                         mods.add(Requires.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
+                    if ((requires_flags & ACC_MANDATED) != 0)
                         mods.add(Requires.Modifier.MANDATED);
                 }
-                builder.requires(mods, dn);
-                off += 4;
+
+
+                // requires_version
+                Version compiledVersion = null;
+                String requires_version = cr.readUTF8(off, buf);
+                off += 2;
+                if (requires_version != null) {
+                    compiledVersion = Version.parse(requires_version);
+                }
+
+                if (compiledVersion == null) {
+                    builder.requires(mods, dn);
+                } else {
+                    builder.requires(mods, dn, compiledVersion);
+                }
             }
 
             // exports_count and exports[exports_count]
@@ -133,19 +163,20 @@
             off += 2;
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int exports_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Exports.Modifier> mods;
-                    if (flags == 0) {
+                    if (exports_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((exports_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Exports.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((exports_flags & ACC_MANDATED) != 0)
                             mods.add(Exports.Modifier.MANDATED);
                     }
 
@@ -154,7 +185,7 @@
                     if (exports_to_count > 0) {
                         Set<String> targets = new HashSet<>();
                         for (int j=0; j<exports_to_count; j++) {
-                            String t = cr.readUTF8(off, buf).replace('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -170,19 +201,20 @@
             off += 2;
             if (open_count > 0) {
                 for (int i=0; i<open_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int opens_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Opens.Modifier> mods;
-                    if (flags == 0) {
+                    if (opens_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((opens_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Opens.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((opens_flags & ACC_MANDATED) != 0)
                             mods.add(Opens.Modifier.MANDATED);
                     }
 
@@ -191,7 +223,7 @@
                     if (opens_to_count > 0) {
                         Set<String> targets = new HashSet<>();
                         for (int j=0; j<opens_to_count; j++) {
-                            String t = cr.readUTF8(off, buf).replace('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -232,8 +264,7 @@
                 }
             }
 
-            attr.descriptor = builder.build();
-            return attr;
+            return new ModuleAttribute(builder.build());
         }
 
         @Override
@@ -248,7 +279,7 @@
 
             // module_name
             String mn = descriptor.name();
-            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            int module_name_index = cw.newModule(mn);
             attr.putShort(module_name_index);
 
             // module_flags
@@ -259,66 +290,83 @@
                 module_flags |= ACC_SYNTHETIC;
             attr.putShort(module_flags);
 
+            // module_version
+            Version v = descriptor.version().orElse(null);
+            if (v == null) {
+                attr.putShort(0);
+            } else {
+                int module_version_index = cw.newUTF8(v.toString());
+                attr.putShort(module_version_index);
+            }
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
             // requires[requires_count]
-            for (Requires md : descriptor.requires()) {
-                String dn = md.name();
-                int flags = 0;
-                if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
-                    flags |= ACC_TRANSITIVE;
-                if (md.modifiers().contains(Requires.Modifier.STATIC))
-                    flags |= ACC_STATIC_PHASE;
-                if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
-                if (md.modifiers().contains(Requires.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn.replace('.', '/'));
-                attr.putShort(index);
-                attr.putShort(flags);
+            for (Requires r : descriptor.requires()) {
+                int requires_index = cw.newModule(r.name());
+                attr.putShort(requires_index);
+
+                int requires_flags = 0;
+                if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
+                    requires_flags |= ACC_TRANSITIVE;
+                if (r.modifiers().contains(Requires.Modifier.STATIC))
+                    requires_flags |= ACC_STATIC_PHASE;
+                if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
+                    requires_flags |= ACC_SYNTHETIC;
+                if (r.modifiers().contains(Requires.Modifier.MANDATED))
+                    requires_flags |= ACC_MANDATED;
+                attr.putShort(requires_flags);
+
+                int requires_version_index;
+                v = r.compiledVersion().orElse(null);
+                if (v == null) {
+                    requires_version_index = 0;
+                } else {
+                    requires_version_index = cw.newUTF8(v.toString());
+                }
+                attr.putShort(requires_version_index);
             }
 
             // exports_count and exports[exports_count];
             attr.putShort(descriptor.exports().size());
             for (Exports e : descriptor.exports()) {
                 String pkg = e.source().replace('.', '/');
-                attr.putShort(cw.newUTF8(pkg));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int exports_flags = 0;
                 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    exports_flags |= ACC_SYNTHETIC;
                 if (e.modifiers().contains(Exports.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    exports_flags |= ACC_MANDATED;
+                attr.putShort(exports_flags);
 
                 if (e.isQualified()) {
                     Set<String> ts = e.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } else {
                     attr.putShort(0);
                 }
             }
 
-
             // opens_counts and opens[opens_counts]
             attr.putShort(descriptor.opens().size());
             for (Opens obj : descriptor.opens()) {
                 String pkg = obj.source().replace('.', '/');
-                attr.putShort(cw.newUTF8(pkg));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int opens_flags = 0;
                 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    opens_flags |= ACC_SYNTHETIC;
                 if (obj.modifiers().contains(Opens.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    opens_flags |= ACC_MANDATED;
+                attr.putShort(opens_flags);
 
                 if (obj.isQualified()) {
                     Set<String> ts = obj.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } else {
                     attr.putShort(0);
                 }
@@ -369,7 +417,7 @@
      *
      *   // the number of entries in the packages table
      *   u2 packages_count;
-     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
+     *   { // index to CONSTANT_Package_info structure with the package name
      *     u2 package_index
      *   } packages[package_count];
      *
@@ -402,7 +450,7 @@
             // packages
             Set<String> packages = new HashSet<>();
             for (int i=0; i<package_count; i++) {
-                String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                String pkg = cr.readPackage(off, buf).replace('/', '.');
                 packages.add(pkg);
                 off += 2;
             }
@@ -427,7 +475,7 @@
             // packages
             packages.stream()
                 .map(p -> p.replace('.', '/'))
-                .forEach(p -> attr.putShort(cw.newUTF8(p)));
+                .forEach(p -> attr.putShort(cw.newPackage(p)));
 
             return attr;
         }
@@ -435,61 +483,6 @@
     }
 
     /**
-     * ModuleVersion attribute.
-     *
-     * <pre> {@code
-     *
-     * ModuleVersion_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleVersion"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
-     *   u2 version_index;
-     * }
-     *
-     * } </pre>
-     */
-    public static class ModuleVersionAttribute extends Attribute {
-        private final Version version;
-
-        public ModuleVersionAttribute(Version version) {
-            super(MODULE_VERSION);
-            this.version = version;
-        }
-
-        public ModuleVersionAttribute() {
-            this(null);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            String value = cr.readUTF8(off, buf);
-            return new ModuleVersionAttribute(Version.parse(value));
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            int index = cw.newUTF8(version.toString());
-            attr.putShort(index);
-            return attr;
-        }
-    }
-
-    /**
      * ModuleMainClass attribute.
      *
      * <pre> {@code
@@ -526,7 +519,7 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            String value = cr.readClass(off, buf);
+            String value = cr.readClass(off, buf).replace('/', '.');
             return new ModuleMainClassAttribute(value);
         }
 
@@ -538,7 +531,7 @@
                                    int maxLocals)
         {
             ByteVector attr = new ByteVector();
-            int index = cw.newClass(mainClass);
+            int index = cw.newClass(mainClass.replace('.', '/'));
             attr.putShort(index);
             return attr;
         }
@@ -555,11 +548,11 @@
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
+     *   // index to CONSTANT_utf8_info structure with the OS name
      *   u2 os_name_index;
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
+     *   // index to CONSTANT_utf8_info structure with the OS arch
      *   u2 os_arch_index
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
+     *   // index to CONSTANT_utf8_info structure with the OS version
      *   u2 os_version_index;
      * }
      *
@@ -656,7 +649,7 @@
      *
      *   // the number of entries in the hashes table
      *   u2 hashes_count;
-     *   {   u2 module_name_index
+     *   {   u2 module_name_index (index to CONSTANT_Module_info structure)
      *       u2 hash_length;
      *       u1 hash[hash_length];
      *   } hashes[hashes_count];
@@ -691,7 +684,7 @@
 
             Map<String, byte[]> map = new HashMap<>();
             for (int i=0; i<hashes_count; i++) {
-                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                String mn = cr.readModule(off, buf);
                 off += 2;
 
                 int hash_length = cr.readUnsignedShort(off);
@@ -728,7 +721,7 @@
             for (String mn : names) {
                 byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+                attr.putShort(cw.newModule(mn));
 
                 attr.putShort(hash.length);
                 for (byte b: hash) {
@@ -740,4 +733,58 @@
         }
     }
 
+    /**
+     *  ModuleResolution_attribute {
+     *    u2 attribute_name_index;    // "ModuleResolution"
+     *    u4 attribute_length;        // 2
+     *    u2 resolution_flags;
+     *
+     *  The value of the resolution_flags item is a mask of flags used to denote
+     *  properties of module resolution. The flags are as follows:
+     *
+     *   // Optional
+     *   0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
+     *
+     *   // At most one of:
+     *   0x0002 (WARN_DEPRECATED)
+     *   0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
+     *   0x0008 (WARN_INCUBATING)
+     */
+    static class ModuleResolutionAttribute extends Attribute {
+        private final int value;
+
+        ModuleResolutionAttribute() {
+            super(MODULE_RESOLUTION);
+            value = 0;
+        }
+
+        ModuleResolutionAttribute(int value) {
+            super(MODULE_RESOLUTION);
+            this.value = value;
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            int flags = cr.readUnsignedShort(off);
+            return new ModuleResolutionAttribute(flags);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            attr.putShort(value);
+            return attr;
+        }
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
index bf8955c..48fe536 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
@@ -38,10 +38,10 @@
     public static final String SDE                = "SourceDebugExtension";
 
     public static final String MODULE_PACKAGES    = "ModulePackages";
-    public static final String MODULE_VERSION     = "ModuleVersion";
     public static final String MODULE_MAIN_CLASS  = "ModuleMainClass";
     public static final String MODULE_TARGET      = "ModuleTarget";
     public static final String MODULE_HASHES      = "ModuleHashes";
+    public static final String MODULE_RESOLUTION  = "ModuleResolution";
 
     // access, requires, exports, and opens flags
     public static final int ACC_MODULE        = 0x8000;
@@ -51,4 +51,10 @@
     public static final int ACC_SYNTHETIC     = 0x1000;
     public static final int ACC_MANDATED      = 0x8000;
 
+    // ModuleResolution_attribute resolution flags
+    public static final int DO_NOT_RESOLVE_BY_DEFAULT   = 0x0001;
+    public static final int WARN_DEPRECATED             = 0x0002;
+    public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
+    public static final int WARN_INCUBATING             = 0x0008;
+
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
index 1a00ede..7140646 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
@@ -195,7 +195,9 @@
         // module is the unnamed module of the application class loader. This
         // is implemented by resolving "java.se" and all (non-java.*) modules
         // that export an API. If "java.se" is not observable then all java.*
-        // modules are resolved.
+        // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
+        // bit set in their ModuleResolution attribute flags are excluded from
+        // the default set of roots.
         if (mainModule == null || addAllDefaultModules) {
             boolean hasJava = false;
             if (systemModules.find(JAVA_SE).isPresent()) {
@@ -212,6 +214,9 @@
                 if (hasJava && mn.startsWith("java."))
                     continue;
 
+                if (ModuleResolution.doNotResolveByDefault(mref))
+                    continue;
+
                 // add as root if observable and exports at least one package
                 if ((finder == systemModules || finder.find(mn).isPresent())) {
                     ModuleDescriptor descriptor = mref.descriptor();
@@ -231,6 +236,7 @@
             ModuleFinder f = finder;  // observable modules
             systemModules.findAll()
                 .stream()
+                .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
                 .map(ModuleReference::descriptor)
                 .map(ModuleDescriptor::name)
                 .filter(mn -> f.find(mn).isPresent())  // observable
@@ -277,6 +283,8 @@
         // time to create configuration
         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
 
+        // check module names and incubating status
+        checkModuleNamesAndStatus(cf);
 
         // mapping of modules to class loaders
         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -298,8 +306,32 @@
                         fail(name + ": cannot be loaded from application module path");
                 }
             }
+
+            // check if module specified in --patch-module is present
+            for (String mn: patcher.patchedModules()) {
+                if (!cf.findModule(mn).isPresent()) {
+                    warnUnknownModule(PATCH_MODULE, mn);
+                }
+            }
         }
 
+        // if needed check that there are no split packages in the set of
+        // resolved modules for the boot layer
+        if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
+                Map<String, String> packageToModule = new HashMap<>();
+                for (ResolvedModule resolvedModule : cf.modules()) {
+                    ModuleDescriptor descriptor =
+                        resolvedModule.reference().descriptor();
+                    String name = descriptor.name();
+                    for (String p : descriptor.packages()) {
+                        String other = packageToModule.putIfAbsent(p, name);
+                        if (other != null) {
+                            fail("Package " + p + " in both module "
+                                 + name + " and module " + other);
+                        }
+                    }
+                }
+            }
 
         long t4 = System.nanoTime();
 
@@ -456,7 +488,7 @@
             String mn = e.getKey();
             Optional<Module> om = bootLayer.findModule(mn);
             if (!om.isPresent()) {
-                warn("Unknown module: " + mn);
+                warnUnknownModule(ADD_READS, mn);
                 continue;
             }
             Module m = om.get();
@@ -470,7 +502,7 @@
                     if (om.isPresent()) {
                         Modules.addReads(m, om.get());
                     } else {
-                        warn("Unknown module: " + name);
+                        warnUnknownModule(ADD_READS, name);
                     }
                 }
             }
@@ -502,24 +534,25 @@
                                                Map<String, List<String>> map,
                                                boolean opens)
     {
+        String option = opens ? ADD_OPENS : ADD_EXPORTS;
         for (Map.Entry<String, List<String>> e : map.entrySet()) {
 
             // the key is $MODULE/$PACKAGE
             String key = e.getKey();
             String[] s = key.split("/");
             if (s.length != 2)
-                fail("Unable to parse: " + key);
+                fail(unableToParse(option,  "<module>/<package>", key));
 
             String mn = s[0];
             String pn = s[1];
             if (mn.isEmpty() || pn.isEmpty())
-                fail("Module and package name must be specified:" + key);
+                fail(unableToParse(option,  "<module>/<package>", key));
 
             // The exporting module is in the boot layer
             Module m;
             Optional<Module> om = bootLayer.findModule(mn);
             if (!om.isPresent()) {
-                warn("Unknown module: " + mn);
+                warnUnknownModule(option, mn);
                 continue;
             }
 
@@ -541,7 +574,7 @@
                     if (om.isPresent()) {
                         other = om.get();
                     } else {
-                        warn("Unknown module: " + name);
+                        warnUnknownModule(option, name);
                         continue;
                     }
                 }
@@ -585,24 +618,30 @@
 
             int pos = value.indexOf('=');
             if (pos == -1)
-                fail("Unable to parse: " + value);
+                fail(unableToParse(option(prefix), "<module>=<value>", value));
             if (pos == 0)
-                fail("Missing module name in: " + value);
+                fail(unableToParse(option(prefix), "<module>=<value>", value));
 
             // key is <module> or <module>/<package>
             String key = value.substring(0, pos);
 
             String rhs = value.substring(pos+1);
             if (rhs.isEmpty())
-                fail("Unable to parse: " + value);
+                fail(unableToParse(option(prefix), "<module>=<value>", value));
 
             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
             if (!allowDuplicates && map.containsKey(key))
-                fail(key + " specified more than once");
+                fail(key + " specified more than once in " + option(prefix));
             List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
+            int ntargets = 0;
             for (String s : rhs.split(regex)) {
-                if (s.length() > 0) values.add(s);
+                if (s.length() > 0) {
+                    values.add(s);
+                    ntargets++;
+                }
             }
+            if (ntargets == 0)
+                fail("Target must be specified: " + option(prefix) + " " + value);
 
             index++;
             value = getAndRemoveProperty(prefix + index);
@@ -627,6 +666,33 @@
     }
 
     /**
+     * Checks the names and resolution bit of each module in the configuration,
+     * emitting warnings if needed.
+     */
+    private static void checkModuleNamesAndStatus(Configuration cf) {
+        String incubating = null;
+        for (ResolvedModule rm : cf.modules()) {
+            ModuleReference mref = rm.reference();
+            String mn = mref.descriptor().name();
+
+            // emit warning if module name ends with a non-Java letter
+            if (!Checks.hasLegalModuleNameLastCharacter(mn))
+                warn("Module name \"" + mn + "\" may soon be illegal");
+
+            // emit warning if the WARN_INCUBATING module resolution bit set
+            if (ModuleResolution.hasIncubatingWarning(mref)) {
+                if (incubating == null) {
+                    incubating = mn;
+                } else {
+                    incubating += ", " + mn;
+                }
+            }
+        }
+        if (incubating != null)
+            warn("Using incubator modules: " + incubating);
+    }
+
+    /**
      * Throws a RuntimeException with the given message
      */
     static void fail(String m) {
@@ -637,6 +703,42 @@
         System.err.println("WARNING: " + m);
     }
 
+    static void warnUnknownModule(String option, String mn) {
+        warn("Unknown module: " + mn + " specified in " + option);
+    }
+
+    static String unableToParse(String option, String text, String value) {
+        return "Unable to parse " +  option + " " + text + ": " + value;
+    }
+
+    private static final String ADD_MODULES  = "--add-modules";
+    private static final String ADD_EXPORTS  = "--add-exports";
+    private static final String ADD_OPENS    = "--add-opens";
+    private static final String ADD_READS    = "--add-reads";
+    private static final String PATCH_MODULE = "--patch-module";
+
+
+    /*
+     * Returns the command-line option name corresponds to the specified
+     * system property prefix.
+     */
+    static String option(String prefix) {
+        switch (prefix) {
+            case "jdk.module.addexports.":
+                return ADD_EXPORTS;
+            case "jdk.module.addopens.":
+                return ADD_OPENS;
+            case "jdk.module.addreads.":
+                return ADD_READS;
+            case "jdk.module.patch.":
+                return PATCH_MODULE;
+            case "jdk.module.addmods.":
+                return ADD_MODULES;
+            default:
+                throw new IllegalArgumentException(prefix);
+        }
+    }
+
     static class PerfCounters {
 
         static PerfCounter systemModulesTime
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
index 107305e..f4e5fcb 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
@@ -35,6 +35,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -50,7 +51,6 @@
         byte[] generate(String algorithm);
     }
 
-
     private final String algorithm;
     private final Map<String, byte[]> nameToHash;
 
@@ -142,4 +142,37 @@
         }
         return new ModuleHashes(algorithm, nameToHash);
     }
+
+    /**
+     * This is used by jdk.internal.module.SystemModules class
+     * generated at link time.
+     */
+    public static class Builder {
+        final String algorithm;
+        final Map<String, byte[]> nameToHash;
+
+        Builder(String algorithm, int initialCapacity) {
+            this.nameToHash = new HashMap<>(initialCapacity);
+            this.algorithm =  Objects.requireNonNull(algorithm);
+        }
+
+        /**
+         * Sets the module hash for the given module name
+         */
+        public Builder hashForModule(String mn, byte[] hash) {
+            nameToHash.put(mn, hash);
+            return this;
+        }
+
+        /**
+         * Builds a {@code ModuleHashes}.
+         */
+        public ModuleHashes build() {
+            if (!nameToHash.isEmpty()) {
+                return new ModuleHashes(algorithm, nameToHash);
+            } else {
+                return null;
+            }
+        }
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
new file mode 100644
index 0000000..3aac651
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleResolution;
+
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Read module information from a {@code module-info} class file.
+ *
+ * @implNote The rationale for the hand-coded reader is startup performance
+ * and fine control over the throwing of InvalidModuleDescriptorException.
+ */
+
+public final class ModuleInfo {
+
+    private static final JavaLangModuleAccess JLMA
+        = SharedSecrets.getJavaLangModuleAccess();
+
+    // supplies the set of packages when ModulePackages attribute not present
+    private final Supplier<Set<String>> packageFinder;
+
+    // indicates if the ModuleHashes attribute should be parsed
+    private final boolean parseHashes;
+
+    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
+        packageFinder = pf;
+        parseHashes = ph;
+    }
+
+    private ModuleInfo(Supplier<Set<String>> pf) {
+        this(pf, true);
+    }
+
+    /**
+     * A holder class for the ModuleDescriptor that is created by reading the
+     * Module and other standard class file attributes. It also holds the objects
+     * that represent the non-standard class file attributes that are read from
+     * the class file.
+     */
+    public static final class Attributes {
+        private final ModuleDescriptor descriptor;
+        private final ModuleHashes recordedHashes;
+        private final ModuleResolution moduleResolution;
+        Attributes(ModuleDescriptor descriptor,
+                   ModuleHashes recordedHashes,
+                   ModuleResolution moduleResolution) {
+            this.descriptor = descriptor;
+            this.recordedHashes = recordedHashes;
+            this.moduleResolution = moduleResolution;
+        }
+        public ModuleDescriptor descriptor() {
+            return descriptor;
+        }
+        public ModuleHashes recordedHashes() {
+            return recordedHashes;
+        }
+        public ModuleResolution moduleResolution() {
+            return moduleResolution;
+        }
+    }
+
+
+    /**
+     * Reads a {@code module-info.class} from the given input stream.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws IOException
+     */
+    public static Attributes read(InputStream in, Supplier<Set<String>> pf)
+        throws IOException
+    {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputStream(in));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer
+     * but ignore the {@code ModuleHashes} attribute.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads the input as a module-info class file.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
+     *         because an identifier is not a legal Java identifier, duplicate
+     *         exports, and many other reasons
+     */
+    private Attributes doRead(DataInput in) throws IOException {
+
+        int magic = in.readInt();
+        if (magic != 0xCAFEBABE)
+            throw invalidModuleDescriptor("Bad magic number");
+
+        int minor_version = in.readUnsignedShort();
+        int major_version = in.readUnsignedShort();
+        if (major_version < 53) {
+            throw invalidModuleDescriptor("Must be >= 53.0");
+        }
+
+        ConstantPool cpool = new ConstantPool(in);
+
+        int access_flags = in.readUnsignedShort();
+        if (access_flags != ACC_MODULE)
+            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
+
+        int this_class = in.readUnsignedShort();
+        String mn = cpool.getClassName(this_class);
+        if (!"module-info".equals(mn))
+            throw invalidModuleDescriptor("this_class should be module-info");
+
+        int super_class = in.readUnsignedShort();
+        if (super_class > 0)
+            throw invalidModuleDescriptor("bad #super_class");
+
+        int interfaces_count = in.readUnsignedShort();
+        if (interfaces_count > 0)
+            throw invalidModuleDescriptor("Bad #interfaces");
+
+        int fields_count = in.readUnsignedShort();
+        if (fields_count > 0)
+            throw invalidModuleDescriptor("Bad #fields");
+
+        int methods_count = in.readUnsignedShort();
+        if (methods_count > 0)
+            throw invalidModuleDescriptor("Bad #methods");
+
+        int attributes_count = in.readUnsignedShort();
+
+        // the names of the attributes found in the class file
+        Set<String> attributes = new HashSet<>();
+
+        Builder builder = null;
+        Set<String> packages = null;
+        String mainClass = null;
+        String[] osValues = null;
+        ModuleHashes hashes = null;
+        ModuleResolution moduleResolution = null;
+
+        for (int i = 0; i < attributes_count ; i++) {
+            int name_index = in.readUnsignedShort();
+            String attribute_name = cpool.getUtf8(name_index);
+            int length = in.readInt();
+
+            boolean added = attributes.add(attribute_name);
+            if (!added && isAttributeAtMostOnce(attribute_name)) {
+                throw invalidModuleDescriptor("More than one "
+                                              + attribute_name + " attribute");
+            }
+
+            switch (attribute_name) {
+
+                case MODULE :
+                    builder = readModuleAttribute(in, cpool);
+                    break;
+
+                case MODULE_PACKAGES :
+                    packages = readModulePackagesAttribute(in, cpool);
+                    break;
+
+                case MODULE_MAIN_CLASS :
+                    mainClass = readModuleMainClassAttribute(in, cpool);
+                    break;
+
+                case MODULE_TARGET :
+                    osValues = readModuleTargetAttribute(in, cpool);
+                    break;
+
+                case MODULE_HASHES :
+                    if (parseHashes) {
+                        hashes = readModuleHashesAttribute(in, cpool);
+                    } else {
+                        in.skipBytes(length);
+                    }
+                    break;
+
+                case MODULE_RESOLUTION :
+                    moduleResolution = readModuleResolution(in, cpool);
+                    break;
+
+                default:
+                    if (isAttributeDisallowed(attribute_name)) {
+                        throw invalidModuleDescriptor(attribute_name
+                                                      + " attribute not allowed");
+                    } else {
+                        in.skipBytes(length);
+                    }
+
+            }
+        }
+
+        // the Module attribute is required
+        if (builder == null) {
+            throw invalidModuleDescriptor(MODULE + " attribute not found");
+        }
+
+        // If the ModulePackages attribute is not present then the packageFinder
+        // is used to find the set of packages
+        boolean usedPackageFinder = false;
+        if (packages == null && packageFinder != null) {
+            try {
+                packages = new HashSet<>(packageFinder.get());
+            } catch (UncheckedIOException x) {
+                throw x.getCause();
+            }
+            usedPackageFinder = true;
+        }
+        if (packages != null) {
+            Set<String> exportedPackages = JLMA.exportedPackages(builder);
+            Set<String> openPackages = JLMA.openPackages(builder);
+            if (packages.containsAll(exportedPackages)
+                    && packages.containsAll(openPackages)) {
+                packages.removeAll(exportedPackages);
+                packages.removeAll(openPackages);
+            } else {
+                // the set of packages is not complete
+                Set<String> exportedAndOpenPackages = new HashSet<>();
+                exportedAndOpenPackages.addAll(exportedPackages);
+                exportedAndOpenPackages.addAll(openPackages);
+                for (String pn : exportedAndOpenPackages) {
+                    if (!packages.contains(pn)) {
+                        String tail;
+                        if (usedPackageFinder) {
+                            tail = " not found by package finder";
+                        } else {
+                            tail = " missing from ModulePackages attribute";
+                        }
+                        throw invalidModuleDescriptor("Package " + pn + tail);
+                    }
+                }
+                assert false; // should not get here
+            }
+            builder.contains(packages);
+        }
+
+        if (mainClass != null)
+            builder.mainClass(mainClass);
+        if (osValues != null) {
+            if (osValues[0] != null) builder.osName(osValues[0]);
+            if (osValues[1] != null) builder.osArch(osValues[1]);
+            if (osValues[2] != null) builder.osVersion(osValues[2]);
+        }
+
+        ModuleDescriptor descriptor = builder.build();
+        return new Attributes(descriptor, hashes, moduleResolution);
+    }
+
+    /**
+     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+     * build the corresponding ModuleDescriptor.
+     */
+    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        // module_name
+        int module_name_index = in.readUnsignedShort();
+        String mn = cpool.getModuleName(module_name_index);
+
+        int module_flags = in.readUnsignedShort();
+        boolean open = ((module_flags & ACC_OPEN) != 0);
+        boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
+
+        Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+
+        int module_version_index = in.readUnsignedShort();
+        if (module_version_index != 0) {
+            String vs = cpool.getUtf8(module_version_index);
+            builder.version(vs);
+        }
+
+        int requires_count = in.readUnsignedShort();
+        boolean requiresJavaBase = false;
+        for (int i=0; i<requires_count; i++) {
+            int requires_index = in.readUnsignedShort();
+            String dn = cpool.getModuleName(requires_index);
+
+            int requires_flags = in.readUnsignedShort();
+            Set<Requires.Modifier> mods;
+            if (requires_flags == 0) {
+                mods = Collections.emptySet();
+            } else {
+                mods = new HashSet<>();
+                if ((requires_flags & ACC_TRANSITIVE) != 0)
+                    mods.add(Requires.Modifier.TRANSITIVE);
+                if ((requires_flags & ACC_STATIC_PHASE) != 0)
+                    mods.add(Requires.Modifier.STATIC);
+                if ((requires_flags & ACC_SYNTHETIC) != 0)
+                    mods.add(Requires.Modifier.SYNTHETIC);
+                if ((requires_flags & ACC_MANDATED) != 0)
+                    mods.add(Requires.Modifier.MANDATED);
+            }
+
+            int requires_version_index = in.readUnsignedShort();
+            Version compiledVersion = null;
+            if (requires_version_index != 0) {
+                String vs = cpool.getUtf8(requires_version_index);
+                compiledVersion = Version.parse(vs);
+            }
+
+            if (compiledVersion == null) {
+                builder.requires(mods, dn);
+            } else {
+                builder.requires(mods, dn, compiledVersion);
+            }
+
+            if (dn.equals("java.base"))
+                requiresJavaBase = true;
+        }
+        if (mn.equals("java.base")) {
+            if (requires_count > 0) {
+                throw invalidModuleDescriptor("The requires table for java.base"
+                                              + " must be 0 length");
+            }
+        } else if (!requiresJavaBase) {
+            throw invalidModuleDescriptor("The requires table must have"
+                                          + " an entry for java.base");
+        }
+
+        int exports_count = in.readUnsignedShort();
+        if (exports_count > 0) {
+            for (int i=0; i<exports_count; i++) {
+                int exports_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(exports_index);
+
+                Set<Exports.Modifier> mods;
+                int exports_flags = in.readUnsignedShort();
+                if (exports_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((exports_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Exports.Modifier.SYNTHETIC);
+                    if ((exports_flags & ACC_MANDATED) != 0)
+                        mods.add(Exports.Modifier.MANDATED);
+                }
+
+                int exports_to_count = in.readUnsignedShort();
+                if (exports_to_count > 0) {
+                    Set<String> targets = new HashSet<>(exports_to_count);
+                    for (int j=0; j<exports_to_count; j++) {
+                        int exports_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getModuleName(exports_to_index));
+                    }
+                    builder.exports(mods, pkg, targets);
+                } else {
+                    builder.exports(mods, pkg);
+                }
+            }
+        }
+
+        int opens_count = in.readUnsignedShort();
+        if (opens_count > 0) {
+            if (open) {
+                throw invalidModuleDescriptor("The opens table for an open"
+                                              + " module must be 0 length");
+            }
+            for (int i=0; i<opens_count; i++) {
+                int opens_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(opens_index);
+
+                Set<Opens.Modifier> mods;
+                int opens_flags = in.readUnsignedShort();
+                if (opens_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((opens_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Opens.Modifier.SYNTHETIC);
+                    if ((opens_flags & ACC_MANDATED) != 0)
+                        mods.add(Opens.Modifier.MANDATED);
+                }
+
+                int open_to_count = in.readUnsignedShort();
+                if (open_to_count > 0) {
+                    Set<String> targets = new HashSet<>(open_to_count);
+                    for (int j=0; j<open_to_count; j++) {
+                        int opens_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getModuleName(opens_to_index));
+                    }
+                    builder.opens(mods, pkg, targets);
+                } else {
+                    builder.opens(mods, pkg);
+                }
+            }
+        }
+
+        int uses_count = in.readUnsignedShort();
+        if (uses_count > 0) {
+            for (int i=0; i<uses_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index);
+                builder.uses(sn);
+            }
+        }
+
+        int provides_count = in.readUnsignedShort();
+        if (provides_count > 0) {
+            for (int i=0; i<provides_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index);
+                int with_count = in.readUnsignedShort();
+                List<String> providers = new ArrayList<>(with_count);
+                for (int j=0; j<with_count; j++) {
+                    index = in.readUnsignedShort();
+                    String pn = cpool.getClassName(index);
+                    providers.add(pn);
+                }
+                builder.provides(sn, providers);
+            }
+        }
+
+        return builder;
+    }
+
+    /**
+     * Reads the ModulePackages attribute
+     */
+    private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int package_count = in.readUnsignedShort();
+        Set<String> packages = new HashSet<>(package_count);
+        for (int i=0; i<package_count; i++) {
+            int index = in.readUnsignedShort();
+            String pn = cpool.getPackageName(index);
+            boolean added = packages.add(pn);
+            if (!added) {
+                throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
+                                              + "attribute more than once");
+            }
+        }
+        return packages;
+    }
+
+    /**
+     * Reads the ModuleMainClass attribute
+     */
+    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        return cpool.getClassName(index);
+    }
+
+    /**
+     * Reads the ModuleTarget attribute
+     */
+    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        String[] values = new String[3];
+
+        int name_index = in.readUnsignedShort();
+        if (name_index != 0)
+            values[0] = cpool.getUtf8(name_index);
+
+        int arch_index = in.readUnsignedShort();
+        if (arch_index != 0)
+            values[1] = cpool.getUtf8(arch_index);
+
+        int version_index = in.readUnsignedShort();
+        if (version_index != 0)
+            values[2] = cpool.getUtf8(version_index);
+
+        return values;
+    }
+
+
+    /**
+     * Reads the ModuleHashes attribute
+     */
+    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int algorithm_index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(algorithm_index);
+
+        int hash_count = in.readUnsignedShort();
+        Map<String, byte[]> map = new HashMap<>(hash_count);
+        for (int i=0; i<hash_count; i++) {
+            int module_name_index = in.readUnsignedShort();
+            String mn = cpool.getModuleName(module_name_index);
+            int hash_length = in.readUnsignedShort();
+            if (hash_length == 0) {
+                throw invalidModuleDescriptor("hash_length == 0");
+            }
+            byte[] hash = new byte[hash_length];
+            in.readFully(hash);
+            map.put(mn, hash);
+        }
+
+        return new ModuleHashes(algorithm, map);
+    }
+
+    /**
+     * Reads the ModuleResolution attribute.
+     */
+    private ModuleResolution readModuleResolution(DataInput in,
+                                                  ConstantPool cpool)
+        throws IOException
+    {
+        int flags = in.readUnsignedShort();
+
+        int reason = 0;
+        if ((flags & WARN_DEPRECATED) != 0)
+            reason = WARN_DEPRECATED;
+        if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+            reason = WARN_DEPRECATED_FOR_REMOVAL;
+        }
+        if ((flags & WARN_INCUBATING) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+        }
+
+        return new ModuleResolution(flags);
+    }
+
+
+    /**
+     * Returns true if the given attribute can be present at most once
+     * in the class file. Returns false otherwise.
+     */
+    private static boolean isAttributeAtMostOnce(String name) {
+
+        if (name.equals(MODULE) ||
+                name.equals(SOURCE_FILE) ||
+                name.equals(SDE) ||
+                name.equals(MODULE_PACKAGES) ||
+                name.equals(MODULE_MAIN_CLASS) ||
+                name.equals(MODULE_TARGET) ||
+                name.equals(MODULE_HASHES) ||
+                name.equals(MODULE_RESOLUTION))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Return true if the given attribute name is the name of a pre-defined
+     * attribute that is not allowed in the class file.
+     *
+     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
+     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     */
+    private static boolean isAttributeDisallowed(String name) {
+        Set<String> notAllowed = predefinedNotAllowed;
+        if (notAllowed == null) {
+            notAllowed = Set.of(
+                    "ConstantValue",
+                    "Code",
+                    "StackMapTable",
+                    "Exceptions",
+                    "EnclosingMethod",
+                    "Signature",
+                    "LineNumberTable",
+                    "LocalVariableTable",
+                    "LocalVariableTypeTable",
+                    "RuntimeVisibleParameterAnnotations",
+                    "RuntimeInvisibleParameterAnnotations",
+                    "RuntimeVisibleTypeAnnotations",
+                    "RuntimeInvisibleTypeAnnotations",
+                    "Synthetic",
+                    "AnnotationDefault",
+                    "BootstrapMethods",
+                    "MethodParameters");
+            predefinedNotAllowed = notAllowed;
+        }
+        return notAllowed.contains(name);
+    }
+
+    // lazily created set the pre-defined attributes that are not allowed
+    private static volatile Set<String> predefinedNotAllowed;
+
+
+    /**
+     * The constant pool in a class file.
+     */
+    private static class ConstantPool {
+        static final int CONSTANT_Utf8 = 1;
+        static final int CONSTANT_Integer = 3;
+        static final int CONSTANT_Float = 4;
+        static final int CONSTANT_Long = 5;
+        static final int CONSTANT_Double = 6;
+        static final int CONSTANT_Class = 7;
+        static final int CONSTANT_String = 8;
+        static final int CONSTANT_Fieldref = 9;
+        static final int CONSTANT_Methodref = 10;
+        static final int CONSTANT_InterfaceMethodref = 11;
+        static final int CONSTANT_NameAndType = 12;
+        static final int CONSTANT_MethodHandle = 15;
+        static final int CONSTANT_MethodType = 16;
+        static final int CONSTANT_InvokeDynamic = 18;
+        static final int CONSTANT_Module = 19;
+        static final int CONSTANT_Package = 20;
+
+        private static class Entry {
+            protected Entry(int tag) {
+                this.tag = tag;
+            }
+            final int tag;
+        }
+
+        private static class IndexEntry extends Entry {
+            IndexEntry(int tag, int index) {
+                super(tag);
+                this.index = index;
+            }
+            final int index;
+        }
+
+        private static class Index2Entry extends Entry {
+            Index2Entry(int tag, int index1, int index2) {
+                super(tag);
+                this.index1 = index1;
+                this.index2 = index2;
+            }
+            final int index1,  index2;
+        }
+
+        private static class ValueEntry extends Entry {
+            ValueEntry(int tag, Object value) {
+                super(tag);
+                this.value = value;
+            }
+            final Object value;
+        }
+
+        final Entry[] pool;
+
+        ConstantPool(DataInput in) throws IOException {
+            int count = in.readUnsignedShort();
+            pool = new Entry[count];
+
+            for (int i = 1; i < count; i++) {
+                int tag = in.readUnsignedByte();
+                switch (tag) {
+
+                    case CONSTANT_Utf8:
+                        String svalue = in.readUTF();
+                        pool[i] = new ValueEntry(tag, svalue);
+                        break;
+
+                    case CONSTANT_Class:
+                    case CONSTANT_Package:
+                    case CONSTANT_Module:
+                    case CONSTANT_String:
+                        int index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Double:
+                        double dvalue = in.readDouble();
+                        pool[i] = new ValueEntry(tag, dvalue);
+                        i++;
+                        break;
+
+                    case CONSTANT_Fieldref:
+                    case CONSTANT_InterfaceMethodref:
+                    case CONSTANT_Methodref:
+                    case CONSTANT_InvokeDynamic:
+                    case CONSTANT_NameAndType:
+                        int index1 = in.readUnsignedShort();
+                        int index2 = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, index1, index2);
+                        break;
+
+                    case CONSTANT_MethodHandle:
+                        int refKind = in.readUnsignedByte();
+                        index = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, refKind, index);
+                        break;
+
+                    case CONSTANT_MethodType:
+                        index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Float:
+                        float fvalue = in.readFloat();
+                        pool[i] = new ValueEntry(tag, fvalue);
+                        break;
+
+                    case CONSTANT_Integer:
+                        int ivalue = in.readInt();
+                        pool[i] = new ValueEntry(tag, ivalue);
+                        break;
+
+                    case CONSTANT_Long:
+                        long lvalue = in.readLong();
+                        pool[i] = new ValueEntry(tag, lvalue);
+                        i++;
+                        break;
+
+                    default:
+                        throw invalidModuleDescriptor("Bad constant pool entry: "
+                                                      + i);
+                }
+            }
+        }
+
+        String getClassName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Class) {
+                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Class", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getPackageName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Package) {
+                throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Package", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getModuleName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Module) {
+                throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            return decodeModuleName(index, value);
+        }
+
+        String getUtf8(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Utf8) {
+                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
+                                              + index);
+            }
+            return (String) (((ValueEntry) e).value);
+        }
+
+        void checkIndex(int index) {
+            if (index < 1 || index >= pool.length)
+                throw invalidModuleDescriptor("Index into constant pool out of range");
+        }
+
+        void checkUnqualifiedName(String what, int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor(what + " at entry " + index
+                                              + " has zero length");
+            }
+            for (int i=0; i<len; i++) {
+                char c = value.charAt(i);
+                if (c == '.' || c == ';' || c == '[') {
+                    throw invalidModuleDescriptor(what + " at entry " + index
+                                                  + " has illegal character: '"
+                                                  + c + "'");
+                }
+            }
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool.
+         */
+        String decodeModuleName(int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                              + index + " is zero length");
+            }
+            int i = 0;
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\')
+                    return decodeModuleName(index, i, value);
+
+                i += Character.charCount(cp);
+            }
+            return value;
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool and
+         * partly checked for illegal characters (up to position {@code i}).
+         */
+        String decodeModuleName(int index, int i, String value) {
+            StringBuilder sb = new StringBuilder();
+
+            // copy the code points that have been checked
+            int j = 0;
+            while (j < i) {
+                int cp = value.codePointAt(j);
+                sb.appendCodePoint(cp);
+                j += Character.charCount(cp);
+            }
+
+            // decode from position {@code i} to end
+            int len = value.length();
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\') {
+                    j = i + Character.charCount(cp);
+                    if (j >= len) {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                       + index + " has illegal "
+                                                       + "escape sequence");
+                    }
+                    int next = value.codePointAt(j);
+                    if (next != '\\' && next != ':' && next != '@') {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                      + index + " has illegal "
+                                                      + "escape sequence");
+                    }
+                    sb.appendCodePoint(next);
+                    i += Character.charCount(next);
+                } else {
+                    sb.appendCodePoint(cp);
+                }
+
+                i += Character.charCount(cp);
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * A DataInput implementation that reads from a ByteBuffer.
+     */
+    private static class DataInputWrapper implements DataInput {
+        private final ByteBuffer bb;
+
+        DataInputWrapper(ByteBuffer bb) {
+            this.bb = bb;
+        }
+
+        @Override
+        public void readFully(byte b[]) throws IOException {
+            readFully(b, 0, b.length);
+        }
+
+        @Override
+        public void readFully(byte b[], int off, int len) throws IOException {
+            try {
+                bb.get(b, off, len);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int skipBytes(int n) {
+            int skip = Math.min(n, bb.remaining());
+            bb.position(bb.position() + skip);
+            return skip;
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            try {
+                int ch = bb.get();
+                return (ch != 0);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public byte readByte() throws IOException {
+            try {
+                return bb.get();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readUnsignedByte() throws IOException {
+            try {
+                return ((int) bb.get()) & 0xff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public short readShort() throws IOException {
+            try {
+                return bb.getShort();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            try {
+                return ((int) bb.getShort()) & 0xffff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public char readChar() throws IOException {
+            try {
+                return bb.getChar();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readInt() throws IOException {
+            try {
+                return bb.getInt();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public long readLong() throws IOException {
+            try {
+                return bb.getLong();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public float readFloat() throws IOException {
+            try {
+                return bb.getFloat();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public double readDouble() throws IOException {
+            try {
+                return bb.getDouble();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public String readLine() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public String readUTF() throws IOException {
+            // ### Need to measure the performance and feasibility of using
+            // the UTF-8 decoder instead.
+            return DataInputStream.readUTF(this);
+        }
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with the given detail
+     * message
+     */
+    private static InvalidModuleDescriptorException
+    invalidModuleDescriptor(String msg) {
+        return new InvalidModuleDescriptorException(msg);
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with a detail message to
+     * indicate that the class file is truncated.
+     */
+    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
+        return invalidModuleDescriptor("Truncated module-info.class");
+    }
+
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
index 07bb402..952a328 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
@@ -70,6 +70,9 @@
     // the hashes for the Hashes attribute
     private ModuleHashes hashes;
 
+    // the value of the ModuleResolution attribute
+    private ModuleResolution moduleResolution;
+
     private ModuleInfoExtender(InputStream in) {
         this.in = in;
     }
@@ -121,6 +124,14 @@
     }
 
     /**
+     * Sets the value for the ModuleResolution attribute.
+     */
+    public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
+        this.moduleResolution = mres;
+        return this;
+    }
+
+    /**
      * A ClassVisitor that supports adding class file attributes. If an
      * attribute already exists then the first occurence of the attribute
      * is replaced.
@@ -183,21 +194,20 @@
 
         if (packages != null)
             cv.addAttribute(new ModulePackagesAttribute(packages));
-        if (version != null)
-            cv.addAttribute(new ModuleVersionAttribute(version));
         if (mainClass != null)
             cv.addAttribute(new ModuleMainClassAttribute(mainClass));
         if (osName != null || osArch != null || osVersion != null)
             cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         if (hashes != null)
             cv.addAttribute(new ModuleHashesAttribute(hashes));
+        if (moduleResolution != null)
+            cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
 
         List<Attribute> attrs = new ArrayList<>();
 
         // prototypes of attributes that should be parsed
-        attrs.add(new ModuleAttribute());
+        attrs.add(new ModuleAttribute(version));
         attrs.add(new ModulePackagesAttribute());
-        attrs.add(new ModuleVersionAttribute());
         attrs.add(new ModuleMainClassAttribute());
         attrs.add(new ModuleTargetAttribute());
         attrs.add(new ModuleHashesAttribute());
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
index 5e4efff..5a17442 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
@@ -49,13 +49,12 @@
      * returning it in a byte array.
      */
     private static byte[] toModuleInfo(ModuleDescriptor md) {
-
         ClassWriter cw = new ClassWriter(0);
-        cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
+        cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
         cw.visitAttribute(new ModuleAttribute(md));
 
-        // for tests: write the Packages attribute when there are packages that
-        // aren't exported or open
+        // for tests: write the ModulePackages attribute when there are packages
+        // that aren't exported or open
         Stream<String> exported = md.exports().stream()
                 .map(ModuleDescriptor.Exports::source);
         Stream<String> open = md.opens().stream()
@@ -64,10 +63,10 @@
         if (md.packages().size() > exportedOrOpen)
             cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
 
-        md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
+        // write ModuleMainClass if the module has a main class
         md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
 
-        // write the TargetPlatform attribute if have any of OS name/arch/version
+        // write ModuleTarget attribute if have any of OS name/arch/version
         String osName = md.osName().orElse(null);
         String osArch = md.osArch().orElse(null);
         String osVersion = md.osVersion().orElse(null);
@@ -76,7 +75,6 @@
         }
 
         cw.visitEnd();
-
         return cw.toByteArray();
     }
 
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
index 97966bd..5bd7ef5 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
@@ -149,9 +149,22 @@
 
         // return a module reference to the patched module
         URI location = mref.location().orElse(null);
-        return JLMA.newPatchedModule(descriptor,
-                                     location,
-                                     () -> new PatchedModuleReader(paths, mref));
+
+        ModuleHashes recordedHashes = null;
+        ModuleResolution mres = null;
+        if (mref instanceof ModuleReferenceImpl) {
+            ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
+            recordedHashes = impl.recordedHashes();
+            mres = impl.moduleResolution();
+        }
+
+        return new ModuleReferenceImpl(descriptor,
+                                       location,
+                                       () -> new PatchedModuleReader(paths, mref),
+                                       this,
+                                       recordedHashes,
+                                       null,
+                                       mres);
 
     }
 
@@ -162,6 +175,12 @@
         return map.isEmpty();
     }
 
+    /*
+     * Returns the names of the patched modules.
+     */
+    Set<String> patchedModules() {
+        return map.keySet();
+    }
 
     /**
      * A ModuleReader that reads resources from a patched module.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
new file mode 100644
index 0000000..fb7871d
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.module.FindException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
+import jdk.internal.perf.PerfCounter;
+import jdk.internal.util.jar.VersionedStream;
+
+
+/**
+ * A {@code ModuleFinder} that locates modules on the file system by searching
+ * a sequence of directories or packaged modules.
+ *
+ * The {@code ModuleFinder} can be created to work in either the run-time
+ * or link-time phases. In both cases it locates modular JAR and exploded
+ * modules. When created for link-time then it additionally locates
+ * modules in JMOD files.
+ */
+
+public class ModulePath implements ModuleFinder {
+    private static final String MODULE_INFO = "module-info.class";
+
+    // the version to use for multi-release modular JARs
+    private final Runtime.Version releaseVersion;
+
+    // true for the link phase (supports modules packaged in JMOD format)
+    private final boolean isLinkPhase;
+
+    // the entries on this module path
+    private final Path[] entries;
+    private int next;
+
+    // map of module name to module reference map for modules already located
+    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
+
+    public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
+        this.releaseVersion = version;
+        this.isLinkPhase = isLinkPhase;
+        this.entries = entries.clone();
+        for (Path entry : this.entries) {
+            Objects.requireNonNull(entry);
+        }
+    }
+
+    public ModulePath(Path... entries) {
+        this(JarFile.runtimeVersion(), false, entries);
+    }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+
+        // try cached modules
+        ModuleReference m = cachedModules.get(name);
+        if (m != null)
+            return Optional.of(m);
+
+        // the module may not have been encountered yet
+        while (hasNextEntry()) {
+            scanNextEntry();
+            m = cachedModules.get(name);
+            if (m != null)
+                return Optional.of(m);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        // need to ensure that all entries have been scanned
+        while (hasNextEntry()) {
+            scanNextEntry();
+        }
+        return cachedModules.values().stream().collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns {@code true} if there are additional entries to scan
+     */
+    private boolean hasNextEntry() {
+        return next < entries.length;
+    }
+
+    /**
+     * Scans the next entry on the module path. A no-op if all entries have
+     * already been scanned.
+     *
+     * @throws FindException if an error occurs scanning the next entry
+     */
+    private void scanNextEntry() {
+        if (hasNextEntry()) {
+
+            long t0 = System.nanoTime();
+
+            Path entry = entries[next];
+            Map<String, ModuleReference> modules = scan(entry);
+            next++;
+
+            // update cache, ignoring duplicates
+            int initialSize = cachedModules.size();
+            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
+                cachedModules.putIfAbsent(e.getKey(), e.getValue());
+            }
+
+            // update counters
+            int added = cachedModules.size() - initialSize;
+            moduleCount.add(added);
+
+            scanTime.addElapsedTimeFrom(t0);
+        }
+    }
+
+
+    /**
+     * Scan the given module path entry. If the entry is a directory then it is
+     * a directory of modules or an exploded module. If the entry is a regular
+     * file then it is assumed to be a packaged module.
+     *
+     * @throws FindException if an error occurs scanning the entry
+     */
+    private Map<String, ModuleReference> scan(Path entry) {
+
+        BasicFileAttributes attrs;
+        try {
+            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+        } catch (NoSuchFileException e) {
+            return Collections.emptyMap();
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+
+        try {
+
+            if (attrs.isDirectory()) {
+                Path mi = entry.resolve(MODULE_INFO);
+                if (!Files.exists(mi)) {
+                    // does not exist or unable to determine so assume a
+                    // directory of modules
+                    return scanDirectory(entry);
+                }
+            }
+
+            // packaged or exploded module
+            ModuleReference mref = readModule(entry, attrs);
+            if (mref != null) {
+                String name = mref.descriptor().name();
+                return Collections.singletonMap(name, mref);
+            } else {
+                // skipped
+                return Collections.emptyMap();
+            }
+
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+    }
+
+
+    /**
+     * Scans the given directory for packaged or exploded modules.
+     *
+     * @return a map of module name to ModuleReference for the modules found
+     *         in the directory
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if an error occurs scanning the entry or the
+     *         directory contains two or more modules with the same name
+     */
+    private Map<String, ModuleReference> scanDirectory(Path dir)
+        throws IOException
+    {
+        // The map of name -> mref of modules found in this directory.
+        Map<String, ModuleReference> nameToReference = new HashMap<>();
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+            for (Path entry : stream) {
+                BasicFileAttributes attrs;
+                try {
+                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+                } catch (NoSuchFileException ignore) {
+                    // file has been removed or moved, ignore for now
+                    continue;
+                }
+
+                ModuleReference mref = readModule(entry, attrs);
+
+                // module found
+                if (mref != null) {
+                    // can have at most one version of a module in the directory
+                    String name = mref.descriptor().name();
+                    ModuleReference previous = nameToReference.put(name, mref);
+                    if (previous != null) {
+                        String fn1 = fileName(mref);
+                        String fn2 = fileName(previous);
+                        throw new FindException("Two versions of module "
+                                                 + name + " found in " + dir
+                                                 + " (" + fn1 + " and " + fn2 + ")");
+                    }
+                }
+            }
+        }
+
+        return nameToReference;
+    }
+
+
+    /**
+     * Locates a packaged or exploded module, returning a {@code ModuleReference}
+     * to the module. Returns {@code null} if the entry is skipped because it is
+     * to a directory that does not contain a module-info.class or it's a hidden
+     * file.
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if the file is not recognized as a module or an
+     *         error occurs parsing its module descriptor
+     */
+    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
+        throws IOException
+    {
+        try {
+
+            if (attrs.isDirectory()) {
+                return readExplodedModule(entry); // may return null
+            }
+
+            String fn = entry.getFileName().toString();
+            if (attrs.isRegularFile()) {
+                if (fn.endsWith(".jar")) {
+                    return readJar(entry);
+                } else if (fn.endsWith(".jmod")) {
+                    if (isLinkPhase)
+                        return readJMod(entry);
+                    throw new FindException("JMOD files not supported: " + entry);
+                }
+            }
+
+            // skip hidden files
+            if (fn.startsWith(".") || Files.isHidden(entry)) {
+                return null;
+            } else {
+                throw new FindException("Unrecognized module: " + entry);
+            }
+
+        } catch (InvalidModuleDescriptorException e) {
+            throw new FindException("Error reading module: " + entry, e);
+        }
+    }
+
+
+    /**
+     * Returns a string with the file name of the module if possible.
+     * If the module location is not a file URI then return the URI
+     * as a string.
+     */
+    private String fileName(ModuleReference mref) {
+        URI uri = mref.location().orElse(null);
+        if (uri != null) {
+            if (uri.getScheme().equalsIgnoreCase("file")) {
+                Path file = Paths.get(uri);
+                return file.getFileName().toString();
+            } else {
+                return uri.toString();
+            }
+        } else {
+            return "<unknown>";
+        }
+    }
+
+    // -- jmod files --
+
+    private Set<String> jmodPackages(JmodFile jf) {
+        return jf.stream()
+            .filter(e -> e.section() == Section.CLASSES)
+            .map(JmodFile.Entry::name)
+            .map(this::toPackageName)
+            .flatMap(Optional::stream)
+            .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in jmod file on the
+     * file system.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readJMod(Path file) throws IOException {
+        try (JmodFile jf = new JmodFile(file)) {
+            ModuleInfo.Attributes attrs;
+            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+                attrs  = ModuleInfo.read(in, () -> jmodPackages(jf));
+            }
+            return ModuleReferences.newJModModule(attrs, file);
+        }
+    }
+
+
+    // -- JAR files --
+
+    private static final String SERVICES_PREFIX = "META-INF/services/";
+
+    /**
+     * Returns the service type corresponding to the name of a services
+     * configuration file if it is a valid Java identifier.
+     *
+     * For example, if called with "META-INF/services/p.S" then this method
+     * returns a container with the value "p.S".
+     */
+    private Optional<String> toServiceName(String cf) {
+        assert cf.startsWith(SERVICES_PREFIX);
+        int index = cf.lastIndexOf("/") + 1;
+        if (index < cf.length()) {
+            String prefix = cf.substring(0, index);
+            if (prefix.equals(SERVICES_PREFIX)) {
+                String sn = cf.substring(index);
+                if (Checks.isJavaIdentifier(sn))
+                    return Optional.of(sn);
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Reads the next line from the given reader and trims it of comments and
+     * leading/trailing white space.
+     *
+     * Returns null if the reader is at EOF.
+     */
+    private String nextLine(BufferedReader reader) throws IOException {
+        String ln = reader.readLine();
+        if (ln != null) {
+            int ci = ln.indexOf('#');
+            if (ci >= 0)
+                ln = ln.substring(0, ci);
+            ln = ln.trim();
+        }
+        return ln;
+    }
+
+    /**
+     * Treat the given JAR file as a module as follows:
+     *
+     * 1. The module name (and optionally the version) is derived from the file
+     *    name of the JAR file
+     * 2. All packages are exported and open
+     * 3. It has no non-exported/non-open packages
+     * 4. The contents of any META-INF/services configuration files are mapped
+     *    to "provides" declarations
+     * 5. The Main-Class attribute in the main attributes of the JAR manifest
+     *    is mapped to the module descriptor mainClass
+     */
+    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
+        throws IOException
+    {
+        // Derive module name and version from JAR file name
+
+        String fn = jf.getName();
+        int i = fn.lastIndexOf(File.separator);
+        if (i != -1)
+            fn = fn.substring(i+1);
+
+        // drop .jar
+        String mn = fn.substring(0, fn.length()-4);
+        String vs = null;
+
+        // find first occurrence of -${NUMBER}. or -${NUMBER}$
+        Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
+        if (matcher.find()) {
+            int start = matcher.start();
+
+            // attempt to parse the tail as a version string
+            try {
+                String tail = mn.substring(start+1);
+                ModuleDescriptor.Version.parse(tail);
+                vs = tail;
+            } catch (IllegalArgumentException ignore) { }
+
+            mn = mn.substring(0, start);
+        }
+
+        // finally clean up the module name
+        mn = cleanModuleName(mn);
+
+        // Builder throws IAE if module name is empty or invalid
+        ModuleDescriptor.Builder builder
+            = ModuleDescriptor.automaticModule(mn)
+                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
+        if (vs != null)
+            builder.version(vs);
+
+        // scan the names of the entries in the JAR file
+        Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
+                .filter(e -> !e.isDirectory())
+                .map(JarEntry::getName)
+                .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
+                                                   Collectors.toSet()));
+
+        Set<String> resources = map.get(Boolean.FALSE);
+        Set<String> configFiles = map.get(Boolean.TRUE);
+        // all packages are exported and open
+        resources.stream()
+                .map(this::toPackageName)
+                .flatMap(Optional::stream)
+                .distinct()
+                .forEach(pn -> builder.exports(pn).opens(pn));
+
+        // map names of service configuration files to service names
+        Set<String> serviceNames = configFiles.stream()
+                .map(this::toServiceName)
+                .flatMap(Optional::stream)
+                .collect(Collectors.toSet());
+
+        // parse each service configuration file
+        for (String sn : serviceNames) {
+            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
+            List<String> providerClasses = new ArrayList<>();
+            try (InputStream in = jf.getInputStream(entry)) {
+                BufferedReader reader
+                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+                String cn;
+                while ((cn = nextLine(reader)) != null) {
+                    if (cn.length() > 0) {
+                        providerClasses.add(cn);
+                    }
+                }
+            }
+            if (!providerClasses.isEmpty())
+                builder.provides(sn, providerClasses);
+        }
+
+        // Main-Class attribute if it exists
+        Manifest man = jf.getManifest();
+        if (man != null) {
+            Attributes attrs = man.getMainAttributes();
+            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
+            if (mainClass != null)
+                builder.mainClass(mainClass.replace("/", "."));
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Patterns used to derive the module name from a JAR file name.
+     */
+    private static class Patterns {
+        static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
+        static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
+        static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
+        static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
+        static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
+        static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
+    }
+
+    /**
+     * Clean up candidate module name derived from a JAR file name.
+     */
+    private static String cleanModuleName(String mn) {
+        // drop trailing version from name
+        mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
+
+        // replace non-alphanumeric
+        mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
+
+        // collapse repeating dots
+        mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
+
+        // drop leading dots
+        if (mn.length() > 0 && mn.charAt(0) == '.')
+            mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
+
+        // drop trailing dots
+        int len = mn.length();
+        if (len > 0 && mn.charAt(len-1) == '.')
+            mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
+
+        return mn;
+    }
+
+    private Set<String> jarPackages(JarFile jf) {
+        return VersionedStream.stream(jf)
+                .filter(e -> !e.isDirectory())
+                .map(JarEntry::getName)
+                .map(this::toPackageName)
+                .flatMap(Optional::stream)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in modular JAR file on
+     * the file system.
+     *
+     * @throws IOException
+     * @throws FindException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readJar(Path file) throws IOException {
+        try (JarFile jf = new JarFile(file.toFile(),
+                                      true,               // verify
+                                      ZipFile.OPEN_READ,
+                                      releaseVersion))
+        {
+            ModuleInfo.Attributes attrs;
+            JarEntry entry = jf.getJarEntry(MODULE_INFO);
+            if (entry == null) {
+
+                // no module-info.class so treat it as automatic module
+                try {
+                    ModuleDescriptor md = deriveModuleDescriptor(jf);
+                    attrs = new ModuleInfo.Attributes(md, null, null);
+                } catch (IllegalArgumentException iae) {
+                    throw new FindException(
+                        "Unable to derive module descriptor for: "
+                        + jf.getName(), iae);
+                }
+
+            } else {
+                attrs = ModuleInfo.read(jf.getInputStream(entry),
+                                        () -> jarPackages(jf));
+            }
+
+            return ModuleReferences.newJarModule(attrs, file);
+        }
+    }
+
+
+    // -- exploded directories --
+
+    private Set<String> explodedPackages(Path dir) {
+        try {
+            return Files.find(dir, Integer.MAX_VALUE,
+                              ((path, attrs) -> attrs.isRegularFile()))
+                    .map(path -> dir.relativize(path))
+                    .map(this::toPackageName)
+                    .flatMap(Optional::stream)
+                    .collect(Collectors.toSet());
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        }
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to an exploded module on the file
+     * system or {@code null} if {@code module-info.class} not found.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readExplodedModule(Path dir) throws IOException {
+        Path mi = dir.resolve(MODULE_INFO);
+        ModuleInfo.Attributes attrs;
+        try (InputStream in = Files.newInputStream(mi)) {
+            attrs = ModuleInfo.read(new BufferedInputStream(in),
+                                    () -> explodedPackages(dir));
+        } catch (NoSuchFileException e) {
+            // for now
+            return null;
+        }
+        return ModuleReferences.newExplodedModule(attrs, dir);
+    }
+
+    /**
+     * Maps the name of an entry in a JAR or ZIP file to a package name.
+     *
+     * @throws IllegalArgumentException if the name is a class file in
+     *         the top-level directory of the JAR/ZIP file (and it's
+     *         not module-info.class)
+     */
+    private Optional<String> toPackageName(String name) {
+        assert !name.endsWith("/");
+
+        int index = name.lastIndexOf("/");
+        if (index == -1) {
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                throw new IllegalArgumentException(name
+                        + " found in top-level directory:"
+                        + " (unnamed package not allowed in module)");
+            }
+            return Optional.empty();
+        }
+
+        String pn = name.substring(0, index).replace('/', '.');
+        if (Checks.isJavaIdentifier(pn)) {
+            return Optional.of(pn);
+        } else {
+            // not a valid package name
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Maps the relative path of an entry in an exploded module to a package
+     * name.
+     *
+     * @throws IllegalArgumentException if the name is a class file in
+     *         the top-level directory (and it's not module-info.class)
+     */
+    private Optional<String> toPackageName(Path file) {
+        assert file.getRoot() == null;
+
+        Path parent = file.getParent();
+        if (parent == null) {
+            String name = file.toString();
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                throw new IllegalArgumentException(name
+                        + " found in in top-level directory"
+                        + " (unnamed package not allowed in module)");
+            }
+            return Optional.empty();
+        }
+
+        String pn = parent.toString().replace(File.separatorChar, '.');
+        if (Checks.isJavaIdentifier(pn)) {
+            return Optional.of(pn);
+        } else {
+            // not a valid package name
+            return Optional.empty();
+        }
+    }
+
+    private static final PerfCounter scanTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
new file mode 100644
index 0000000..2ab42bd
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * A ModuleReference implementation that supports referencing a module that
+ * is patched and/or can be tied to other modules by means of hashes.
+ */
+
+public class ModuleReferenceImpl extends ModuleReference {
+
+    private final Supplier<ModuleReader> readerSupplier;
+
+    // non-null if the module is patched
+    private final ModulePatcher patcher;
+
+    // the hashes of other modules recorded in this module
+    private final ModuleHashes recordedHashes;
+
+    // the function that computes the hash of this module
+    private final ModuleHashes.HashSupplier hasher;
+
+    // ModuleResolution flags
+    private final ModuleResolution moduleResolution;
+
+    // cached hash of this module to avoid needing to compute it many times
+    private byte[] cachedHash;
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    ModuleReferenceImpl(ModuleDescriptor descriptor,
+                        URI location,
+                        Supplier<ModuleReader> readerSupplier,
+                        ModulePatcher patcher,
+                        ModuleHashes recordedHashes,
+                        ModuleHashes.HashSupplier hasher,
+                        ModuleResolution moduleResolution)
+    {
+        super(descriptor, Objects.requireNonNull(location));
+        this.readerSupplier = readerSupplier;
+        this.patcher = patcher;
+        this.recordedHashes = recordedHashes;
+        this.hasher = hasher;
+        this.moduleResolution = moduleResolution;
+    }
+
+    @Override
+    public ModuleReader open() throws IOException {
+        try {
+            return readerSupplier.get();
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this module has been patched via --patch-module.
+     */
+    public boolean isPatched() {
+        return (patcher != null);
+    }
+
+    /**
+     * Returns the hashes recorded in this module or {@code null} if there
+     * are no hashes recorded.
+     */
+    public ModuleHashes recordedHashes() {
+        return recordedHashes;
+    }
+
+    /**
+     * Returns the supplier that computes the hash of this module.
+     */
+    ModuleHashes.HashSupplier hasher() {
+        return hasher;
+    }
+
+    /**
+     * Returns the ModuleResolution flags.
+     */
+    public ModuleResolution moduleResolution() {
+        return moduleResolution;
+    }
+
+    /**
+     * Computes the hash of this module. Returns {@code null} if the hash
+     * cannot be computed.
+     *
+     * @throws java.io.UncheckedIOException if an I/O error occurs
+     */
+    public byte[] computeHash(String algorithm) {
+        byte[] result = cachedHash;
+        if (result != null)
+            return result;
+        if (hasher == null)
+            return null;
+        cachedHash = result = hasher.generate(algorithm);
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        int hc = hash;
+        if (hc == 0) {
+            hc = descriptor().hashCode();
+            hc = 43 * hc + Objects.hashCode(location());
+            hc = 43 * hc + Objects.hashCode(patcher);
+            if (hc == 0)
+                hc = -1;
+            hash = hc;
+        }
+        return hc;
+    }
+
+    private int hash;
+
+    @Override
+    public boolean equals(Object ob) {
+        if (!(ob instanceof ModuleReferenceImpl))
+            return false;
+        ModuleReferenceImpl that = (ModuleReferenceImpl)ob;
+
+        // assume module content, recorded hashes, etc. are the same
+        // when the modules have equal module descriptors, are at the
+        // same location, and are patched by the same patcher.
+        return Objects.equals(this.descriptor(), that.descriptor())
+                && Objects.equals(this.location(), that.location())
+                && Objects.equals(this.patcher, that.patcher);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString();
+    }
+
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
new file mode 100644
index 0000000..a2aff8f
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Supplier;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+import jdk.internal.util.jar.VersionedStream;
+import sun.net.www.ParseUtil;
+
+
+/**
+ * A factory for creating ModuleReference implementations where the modules are
+ * packaged as modular JAR file, JMOD files or where the modules are exploded
+ * on the file system.
+ */
+
+class ModuleReferences {
+
+    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+    private ModuleReferences() { }
+
+    /**
+     * Creates a ModuleReference to a module or to patched module when
+     * creating modules for the boot Layer and --patch-module is specified.
+     */
+    private static ModuleReference newModule(ModuleInfo.Attributes attrs,
+                                             URI uri,
+                                             Supplier<ModuleReader> supplier,
+                                             HashSupplier hasher) {
+
+        ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
+                                                       uri,
+                                                       supplier,
+                                                       null,
+                                                       attrs.recordedHashes(),
+                                                       hasher,
+                                                       attrs.moduleResolution());
+        if (JLA.getBootLayer() == null)
+            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+        return mref;
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a modular JAR.
+     */
+    static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+        return newModule(attrs, uri, supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a JMOD.
+     */
+    static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+        return newModule(attrs, uri, supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to an exploded module.
+     */
+    static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
+        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
+        return newModule(attrs, dir.toUri(), supplier, null);
+    }
+
+
+    /**
+     * A base module reader that encapsulates machinery required to close the
+     * module reader safely.
+     */
+    static abstract class SafeCloseModuleReader implements ModuleReader {
+
+        // RW lock to support safe close
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private final Lock readLock = lock.readLock();
+        private final Lock writeLock = lock.writeLock();
+        private boolean closed;
+
+        SafeCloseModuleReader() { }
+
+        /**
+         * Returns a URL to  resource. This method is invoked by the find
+         * method to do the actual work of finding the resource.
+         */
+        abstract Optional<URI> implFind(String name) throws IOException;
+
+        /**
+         * Returns an input stream for reading a resource. This method is
+         * invoked by the open method to do the actual work of opening
+         * an input stream to the resource.
+         */
+        abstract Optional<InputStream> implOpen(String name) throws IOException;
+
+        /**
+         * Returns a stream of the names of resources in the module. This
+         * method is invoked by the list method to do the actual work of
+         * creating the stream.
+         */
+        abstract Stream<String> implList() throws IOException;
+
+        /**
+         * Closes the module reader. This method is invoked by close to do the
+         * actual work of closing the module reader.
+         */
+        abstract void implClose() throws IOException;
+
+        @Override
+        public final Optional<URI> find(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implFind(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+
+        @Override
+        public final Optional<InputStream> open(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implOpen(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+        @Override
+        public final Stream<String> list() throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implList();
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+        @Override
+        public final void close() throws IOException {
+            writeLock.lock();
+            try {
+                if (!closed) {
+                    closed = true;
+                    implClose();
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a modular JAR file.
+     */
+    static class JarModuleReader extends SafeCloseModuleReader {
+        private final JarFile jf;
+        private final URI uri;
+
+        static JarFile newJarFile(Path path) {
+            try {
+                return new JarFile(path.toFile(),
+                                   true,               // verify
+                                   ZipFile.OPEN_READ,
+                                   JarFile.runtimeVersion());
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JarModuleReader(Path path, URI uri) {
+            this.jf = newJarFile(path);
+            this.uri = uri;
+        }
+
+        private JarEntry getEntry(String name) {
+            return jf.getJarEntry(Objects.requireNonNull(name));
+        }
+
+        @Override
+        Optional<URI> implFind(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                if (jf.isMultiRelease())
+                    name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jar:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Stream<String> implList() throws IOException {
+            // take snapshot to avoid async close
+            List<String> names = VersionedStream.stream(jf)
+                    .filter(e -> !e.isDirectory())
+                    .map(JarEntry::getName)
+                    .collect(Collectors.toList());
+            return names.stream();
+        }
+
+        @Override
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a JMOD file.
+     */
+    static class JModModuleReader extends SafeCloseModuleReader {
+        private final JmodFile jf;
+        private final URI uri;
+
+        static JmodFile newJmodFile(Path path) {
+            try {
+                return new JmodFile(path);
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JModModuleReader(Path path, URI uri) {
+            this.jf = newJmodFile(path);
+            this.uri = uri;
+        }
+
+        private JmodFile.Entry getEntry(String name) {
+            Objects.requireNonNull(name);
+            return jf.getEntry(JmodFile.Section.CLASSES, name);
+        }
+
+        @Override
+        Optional<URI> implFind(String name) {
+            JmodFile.Entry je = getEntry(name);
+            if (je != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jmod:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JmodFile.Entry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Stream<String> implList() throws IOException {
+            // take snapshot to avoid async close
+            List<String> names = jf.stream()
+                    .filter(e -> e.section() == JmodFile.Section.CLASSES)
+                    .map(JmodFile.Entry::name)
+                    .collect(Collectors.toList());
+            return names.stream();
+        }
+
+        @Override
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for an exploded module.
+     */
+    static class ExplodedModuleReader implements ModuleReader {
+        private final Path dir;
+        private volatile boolean closed;
+
+        ExplodedModuleReader(Path dir) {
+            this.dir = dir;
+
+            // when running with a security manager then check that the caller
+            // has access to the directory.
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                boolean unused = Files.isDirectory(dir);
+            }
+        }
+
+        /**
+         * Returns a Path to access to the given resource.
+         */
+        private Path toPath(String name) {
+            Path path = Paths.get(name.replace('/', File.separatorChar));
+            if (path.getRoot() == null) {
+                return dir.resolve(path);
+            } else {
+                // drop the root component so that the resource is
+                // located relative to the module directory
+                int n = path.getNameCount();
+                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
+            }
+        }
+
+        /**
+         * Throws IOException if the module reader is closed;
+         */
+        private void ensureOpen() throws IOException {
+            if (closed) throw new IOException("ModuleReader is closed");
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                try {
+                    return Optional.of(path.toUri());
+                } catch (IOError e) {
+                    throw (IOException) e.getCause();
+                }
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(Files.newInputStream(path));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Stream<String> list() throws IOException {
+            ensureOpen();
+            // sym links not followed
+            return Files.find(dir, Integer.MAX_VALUE,
+                              (path, attrs) -> attrs.isRegularFile())
+                    .map(f -> dir.relativize(f)
+                                 .toString()
+                                 .replace(File.separatorChar, '/'));
+        }
+
+        @Override
+        public void close() {
+            closed = true;
+        }
+    }
+
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java
new file mode 100644
index 0000000..76c4236
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleReference;
+import static jdk.internal.module.ClassFileConstants.*;
+
+/**
+ * Represents the Module Resolution flags.
+ */
+public final class ModuleResolution {
+
+    final int value;
+
+    ModuleResolution(int value) {
+        this.value = value;
+    }
+
+    public static ModuleResolution empty() {
+        return new ModuleResolution(0);
+    }
+
+    public boolean doNotResolveByDefault() {
+        return (value & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
+    }
+
+    public boolean hasDeprecatedWarning() {
+        return (value & WARN_DEPRECATED) != 0;
+    }
+
+    public boolean hasDeprecatedForRemovalWarning() {
+        return (value & WARN_DEPRECATED_FOR_REMOVAL) != 0;
+    }
+
+    public boolean hasIncubatingWarning() {
+        return (value & WARN_INCUBATING) != 0;
+    }
+
+    public ModuleResolution withDoNotResolveByDefault() {
+        return new ModuleResolution(value | DO_NOT_RESOLVE_BY_DEFAULT);
+    }
+
+    public ModuleResolution withDeprecated() {
+        if ((value & (WARN_DEPRECATED_FOR_REMOVAL | WARN_INCUBATING)) != 0)
+            throw new InternalError("cannot add deprecated to " + value);
+        return new ModuleResolution(value | WARN_DEPRECATED);
+    }
+
+    public ModuleResolution withDeprecatedForRemoval() {
+        if ((value & (WARN_DEPRECATED | WARN_INCUBATING)) != 0)
+            throw new InternalError("cannot add deprecated for removal to " + value);
+        return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
+    }
+    public ModuleResolution withIncubating() {
+        if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
+            throw new InternalError("cannot add incubating to " + value);
+        return new ModuleResolution(value | WARN_INCUBATING);
+    }
+
+    public int value() {
+        return value;
+    }
+
+    public static boolean doNotResolveByDefault(ModuleReference mref) {
+        // get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
+        if (!(mref instanceof ModuleReferenceImpl))
+            return false;
+
+        ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+        if (mres != null)
+            return mres.doNotResolveByDefault();
+
+        return false;
+    }
+
+    public static boolean hasIncubatingWarning(ModuleReference mref) {
+        if (!(mref instanceof ModuleReferenceImpl))
+            return false;
+
+        ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+        if (mres != null)
+            return mres.hasIncubatingWarning();
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "[value=" + value + "]";
+    }
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
new file mode 100644
index 0000000..5ec0a62
--- /dev/null
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.misc.JavaNetUriAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+import jdk.internal.perf.PerfCounter;
+
+/**
+ * A {@code ModuleFinder} that finds modules that are linked into the
+ * run-time image.
+ *
+ * The modules linked into the run-time image are assumed to have the
+ * Packages attribute.
+ */
+
+public class SystemModuleFinder implements ModuleFinder {
+
+    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
+
+    private static final PerfCounter initTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
+    private static final PerfCounter packageCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
+    private static final PerfCounter exportsCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
+    // ImageReader used to access all modules in the image
+    private static final ImageReader imageReader;
+
+    // singleton finder to find modules in the run-time images
+    private static final SystemModuleFinder INSTANCE;
+
+    public static SystemModuleFinder getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * For now, the module references are created eagerly on the assumption
+     * that service binding will require all modules to be located.
+     */
+    static {
+        long t0 = System.nanoTime();
+        imageReader = ImageReaderFactory.getImageReader();
+
+        INSTANCE = new SystemModuleFinder();
+
+        initTime.addElapsedTimeFrom(t0);
+    }
+
+    private static boolean isFastPathSupported() {
+       return SystemModules.MODULE_NAMES.length > 0;
+    }
+
+    private static String[] moduleNames() {
+        if (isFastPathSupported())
+            // module names recorded at link time
+            return SystemModules.MODULE_NAMES;
+
+        // this happens when java.base is patched with java.base
+        // from an exploded image
+        return imageReader.getModuleNames();
+    }
+
+    // the set of modules in the run-time image
+    private final Set<ModuleReference> modules;
+
+    // maps module name to module reference
+    private final Map<String, ModuleReference> nameToModule;
+
+    // module name to hashes
+    private final Map<String, byte[]> hashes;
+
+    private SystemModuleFinder() {
+        String[] names = moduleNames();
+        int n = names.length;
+        moduleCount.add(n);
+
+        // fastpath is enabled by default.
+        // It can be disabled for troubleshooting purpose.
+        boolean disabled =
+            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
+
+        ModuleDescriptor[] descriptors;
+        ModuleHashes[] recordedHashes;
+        ModuleResolution[] moduleResolutions;
+
+        // fast loading of ModuleDescriptor of system modules
+        if (isFastPathSupported() && !disabled) {
+            descriptors = SystemModules.descriptors();
+            recordedHashes = SystemModules.hashes();
+            moduleResolutions = SystemModules.moduleResolutions();
+        } else {
+            // if fast loading of ModuleDescriptors is disabled
+            // fallback to read module-info.class
+            descriptors = new ModuleDescriptor[n];
+            recordedHashes = new ModuleHashes[n];
+            moduleResolutions = new ModuleResolution[n];
+            for (int i = 0; i < names.length; i++) {
+                String mn = names[i];
+                ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
+                ModuleInfo.Attributes attrs =
+                    ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
+                descriptors[i] = attrs.descriptor();
+                recordedHashes[i] = attrs.recordedHashes();
+                moduleResolutions[i] = attrs.moduleResolution();
+            }
+        }
+
+        Map<String, byte[]> hashes = null;
+        boolean secondSeen = false;
+        // record the hashes to build HashSupplier
+        for (ModuleHashes mh : recordedHashes) {
+            if (mh != null) {
+                // if only one module contain ModuleHashes, use it
+                if (hashes == null) {
+                    hashes = mh.hashes();
+                } else {
+                    if (!secondSeen) {
+                        hashes = new HashMap<>(hashes);
+                        secondSeen = true;
+                    }
+                    hashes.putAll(mh.hashes());
+                }
+            }
+        }
+        this.hashes = (hashes == null) ? Map.of() : hashes;
+
+        ModuleReference[] mods = new ModuleReference[n];
+
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ModuleReference>[] map
+            = (Entry<String, ModuleReference>[])new Entry[n];
+
+        for (int i = 0; i < n; i++) {
+            ModuleDescriptor md = descriptors[i];
+
+            // create the ModuleReference
+            ModuleReference mref = toModuleReference(md,
+                                                     recordedHashes[i],
+                                                     hashSupplier(names[i]),
+                                                     moduleResolutions[i]);
+            mods[i] = mref;
+            map[i] = Map.entry(names[i], mref);
+
+            // counters
+            packageCount.add(md.packages().size());
+            exportsCount.add(md.exports().size());
+        }
+
+        modules = Set.of(mods);
+        nameToModule = Map.ofEntries(map);
+    }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+        return Optional.ofNullable(nameToModule.get(name));
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        return modules;
+    }
+
+    private ModuleReference toModuleReference(ModuleDescriptor md,
+                                              ModuleHashes recordedHashes,
+                                              HashSupplier hasher,
+                                              ModuleResolution mres) {
+        String mn = md.name();
+        URI uri = JNUA.create("jrt", "/".concat(mn));
+
+        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+            @Override
+            public ModuleReader get() {
+                return new ImageModuleReader(mn, uri);
+            }
+        };
+
+        ModuleReference mref =
+            new ModuleReferenceImpl(md, uri, readerSupplier, null,
+                                    recordedHashes, hasher, mres);
+
+        // may need a reference to a patched module if --patch-module specified
+        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+        return mref;
+    }
+
+    private HashSupplier hashSupplier(String name) {
+        if (!hashes.containsKey(name))
+            return null;
+
+        return new HashSupplier() {
+            @Override
+            public byte[] generate(String algorithm) {
+                return hashes.get(name);
+            }
+        };
+    }
+
+    /**
+     * A ModuleReader for reading resources from a module linked into the
+     * run-time image.
+     */
+    static class ImageModuleReader implements ModuleReader {
+        private final String module;
+        private volatile boolean closed;
+
+        /**
+         * If there is a security manager set then check permission to
+         * connect to the run-time image.
+         */
+        private static void checkPermissionToConnect(URI uri) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    URLConnection uc = uri.toURL().openConnection();
+                    sm.checkPermission(uc.getPermission());
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            }
+        }
+
+        ImageModuleReader(String module, URI uri) {
+            checkPermissionToConnect(uri);
+            this.module = module;
+        }
+
+        /**
+         * Returns the ImageLocation for the given resource, {@code null}
+         * if not found.
+         */
+        private ImageLocation findImageLocation(String name) throws IOException {
+            Objects.requireNonNull(name);
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+            if (imageReader != null) {
+                return imageReader.findLocation(module, name);
+            } else {
+                // not an images build
+                return null;
+            }
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                URI u = URI.create("jrt:/" + module + "/" + name);
+                return Optional.of(u);
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            return read(name).map(this::toInputStream);
+        }
+
+        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+            try {
+                int rem = bb.remaining();
+                byte[] bytes = new byte[rem];
+                bb.get(bytes);
+                return new ByteArrayInputStream(bytes);
+            } finally {
+                release(bb);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                return Optional.of(imageReader.getResourceBuffer(location));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            Objects.requireNonNull(bb);
+            ImageReader.releaseByteBuffer(bb);
+        }
+
+        @Override
+        public Stream<String> list() throws IOException {
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+
+            Spliterator<String> s = new ModuleContentSpliterator(module);
+            return StreamSupport.stream(s, false);
+        }
+
+        @Override
+        public void close() {
+            // nothing else to do
+            closed = true;
+        }
+    }
+
+    /**
+     * A Spliterator for traversing the resources of a module linked into the
+     * run-time image.
+     */
+    static class ModuleContentSpliterator implements Spliterator<String> {
+        final String moduleRoot;
+        final Deque<ImageReader.Node> stack;
+        Iterator<ImageReader.Node> iterator;
+
+        ModuleContentSpliterator(String module) throws IOException {
+            moduleRoot = "/modules/" + module;
+            stack = new ArrayDeque<>();
+
+            // push the root node to the stack to get started
+            ImageReader.Node dir = imageReader.findNode(moduleRoot);
+            if (dir == null || !dir.isDirectory())
+                throw new IOException(moduleRoot + " not a directory");
+            stack.push(dir);
+            iterator = Collections.emptyIterator();
+        }
+
+        /**
+         * Returns the name of the next non-directory node or {@code null} if
+         * there are no remaining nodes to visit.
+         */
+        private String next() throws IOException {
+            for (;;) {
+                while (iterator.hasNext()) {
+                    ImageReader.Node node = iterator.next();
+                    String name = node.getName();
+                    if (node.isDirectory()) {
+                        // build node
+                        ImageReader.Node dir = imageReader.findNode(name);
+                        assert dir.isDirectory();
+                        stack.push(dir);
+                    } else {
+                        // strip /modules/$MODULE/ prefix
+                        return name.substring(moduleRoot.length() + 1);
+                    }
+                }
+
+                if (stack.isEmpty()) {
+                    return null;
+                } else {
+                    ImageReader.Node dir = stack.poll();
+                    assert dir.isDirectory();
+                    iterator = dir.getChildren().iterator();
+                }
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super String> action) {
+            String next;
+            try {
+                next = next();
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public Spliterator<String> trySplit() {
+            return null;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
index 299c622..596bb69 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java
@@ -29,14 +29,14 @@
 
 /*
  * SystemModules class will be generated at link time to create
- * ModuleDescriptor for the installed modules directly to improve
+ * ModuleDescriptor for the system modules directly to improve
  * the module descriptor reconstitution time.
  *
  * This will skip parsing of module-info.class file and validating
  * names such as module name, package name, service and provider type names.
  * It also avoids taking a defensive copy of any collection.
  *
- * @see jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin
+ * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
  */
 public final class SystemModules {
     /**
@@ -49,11 +49,6 @@
     public static final String[] MODULE_NAMES = new String[0];
 
     /**
-     * Hash of system modules.
-     */
-    public static byte[][] MODULES_TO_HASH = new byte[0][];
-
-    /**
      * Number of packages in the boot layer from the installed modules.
      *
      * Don't make it final to avoid inlining during compile time as
@@ -62,12 +57,36 @@
     public static int PACKAGES_IN_BOOT_LAYER = 1024;
 
     /**
+     * @return {@code false} if there are no split packages in the run-time
+     *         image, {@code true} if there are or if it's not been checked.
+     */
+    public static boolean hasSplitPackages() {
+        return true;
+    }
+
+    /**
      * Returns a non-empty array of ModuleDescriptors in the run-time image.
      *
      * When running an exploded image it returns an empty array.
      */
-    public static ModuleDescriptor[] modules() {
-        throw new InternalError("should not reach here");
+    public static ModuleDescriptor[] descriptors() {
+        throw new InternalError("expected to be overridden at link time");
     }
 
+    /**
+     * Returns a non-empty array of ModuleHashes recorded in each module
+     * in the run-time image.
+     *
+     * When running an exploded image it returns an empty array.
+     */
+    public static ModuleHashes[] hashes() {
+        throw new InternalError("expected to be overridden at link time");
+    }
+
+    /**
+     * Returns a non-empty array of ModuleResolutions in the run-time image.
+     */
+    public static ModuleResolution[] moduleResolutions() {
+        throw new InternalError("expected to be overridden at link time");
+    }
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
index 90593f5..4d91a00 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java
@@ -2491,6 +2491,40 @@
     }
 
     /**
+     * Reads a CONSTANT_Module_info item in {@code b}. This method is intended
+     * for {@link Attribute} sub classes, and is normally not needed by class
+     * generators or adapters.</i>
+     *
+     * @param  index
+     *         the start index of an unsigned short value in {@link #b b},
+     *         whose value is the index of a module constant pool item.
+     * @param  buf
+     *         buffer to be used to read the item. This buffer must be
+     *         sufficiently large. It is not automatically resized.
+     * @return the String corresponding to the specified module item.
+     */
+    public String readModule(int index, char[] buf) {
+        return readUTF8(items[readUnsignedShort(index)], buf);
+    }
+
+    /**
+     * Reads a CONSTANT_Pakcage_info item in {@code b}.  This method is
+     * intended for {@link Attribute} sub slasses, and is normally not needed
+     * by class generators or adapters.</i>
+     *
+     * @param  index
+     *         the start index of an unsigned short value in {@link #b b},
+     *         whose value is the index of a package constant pool item.
+     * @param  buf
+     *         buffer to be used to read the item. This buffer must be
+     *         sufficiently large. It is not automatically resized.
+     * @return the String corresponding to the specified package item.
+     */
+    public String readPackage(int index, char[] buf) {
+        return readUTF8(items[readUnsignedShort(index)], buf);
+    }
+
+    /**
      * Reads a numeric or string constant pool item in {@link #b b}. <i>This
      * method is intended for {@link Attribute} sub classes, and is normally not
      * needed by class generators or adapters.</i>
@@ -2516,6 +2550,8 @@
         case ClassWriter.DOUBLE:
             return Double.longBitsToDouble(readLong(index));
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
             return Type.getObjectType(readUTF8(index, buf));
         case ClassWriter.STR:
             return readUTF8(index, buf);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java
index a577f93..bd0978c 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java
@@ -272,6 +272,16 @@
     static final int INDY = 18;
 
     /**
+     * The type of CONSTANT_Module constant pool items.
+     */
+    static final int MODULE = 19;
+
+    /**
+     * The type of CONSTANT_Package constant pool items.
+     */
+    static final int PACKAGE = 20;
+
+    /**
      * The base value for all CONSTANT_MethodHandle constant pool items.
      * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
      * different items.
@@ -1161,6 +1171,50 @@
     }
 
     /**
+     * Adds a module name to the constant pool.
+     *
+     * Does nothing if the constant pool already contains a similar item.
+     * <i>This method is intended for {@link Attribute} sub classes, and is
+     * normally not needed by class generators or adapters.</i>
+     *
+     * @param  value
+     *         the module name
+     * @return the index of a new or already existing module reference item.
+     */
+    public int newModule(String value) {
+        key2.set(MODULE, value, null, null);
+        Item result = get(key2);
+        if (result == null) {
+            pool.put12(MODULE, newUTF8(value));
+            result = new Item(index++, key2);
+            put(result);
+        }
+        return result.index;
+    }
+
+    /**
+     * Adds a package name to the constant pool.
+     *
+     * Does nothing if the constant pool already contains a similar item.
+     * <i>This method is intended for {@link Attribute} sub classes, and is
+     * normally not needed by class generators or adapters.</i>
+     *
+     * @param  value
+     *         the internal name of the package.
+     * @return the index of a new or already existing package reference item.
+     */
+    public int newPackage(String value) {
+        key2.set(PACKAGE, value, null, null);
+        Item result = get(key2);
+        if (result == null) {
+            pool.put12(PACKAGE, newUTF8(value));
+            result = new Item(index++, key2);
+            put(result);
+        }
+        return result.index;
+    }
+
+    /**
      * Adds a method type reference to the constant pool of the class being
      * build. Does nothing if the constant pool already contains a similar item.
      * <i>This method is intended for {@link Attribute} sub classes, and is
diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java
index 25ed377..b0b8090 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java
@@ -239,6 +239,8 @@
         this.strVal3 = strVal3;
         switch (type) {
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
             this.intVal = 0;     // intVal of a class must be zero, see visitInnerClass
         case ClassWriter.UTF8:
         case ClassWriter.STR:
@@ -311,6 +313,8 @@
         case ClassWriter.UTF8:
         case ClassWriter.STR:
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
         case ClassWriter.MTYPE:
         case ClassWriter.TYPE_NORMAL:
             return i.strVal1.equals(strVal1);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java
index 84c0f61..5522c0c 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java
@@ -58,7 +58,6 @@
 
 public class Cleaner
     extends PhantomReference<Object>
-    implements Runnable
 {
 
     // Dummy reference queue, needed because the PhantomReference constructor
@@ -153,12 +152,4 @@
                     }});
         }
     }
-
-    @Override public void run() {
-        SecurityManager security = System.getSecurityManager();
-        if (security != null)
-            security.checkPackageAccess("jdk.internal.ref");
-        this.clean();
-    }
-
 }
diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
index 0c4cb74..9a41004 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
@@ -31,6 +31,7 @@
 import java.util.Map;
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import sun.security.action.GetPropertyAction;
 
@@ -218,8 +219,16 @@
         if (c.isPrimitive())
             return true;
 
-        // check that memberModule exports the package to currentModule
-        return memberModule.isExported(c.getPackageName(), currentModule);
+        String pkg = c.getPackageName();
+        boolean allowed = memberModule.isExported(pkg, currentModule);
+        if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
+            if (!SharedSecrets.getJavaLangReflectModuleAccess()
+                    .isStaticallyExported(memberModule, pkg, currentModule)) {
+                String msg = currentModule + " allowed access to member of " + memberClass;
+                new Exception(msg).printStackTrace(System.err);
+            }
+        }
+        return allowed;
     }
 
     /**
@@ -348,23 +357,41 @@
     }
 
 
-    // true to print a stack trace when IAE is thrown
+    // true to print a stack trace when access fails
     private static volatile boolean printStackWhenAccessFails;
 
-    // true if printStackWhenAccessFails has been initialized
-    private static volatile boolean printStackWhenAccessFailsSet;
+    // true to print a stack trace when access succeeds
+    private static volatile boolean printStackWhenAccessSucceeds;
 
-    private static void printStackTraceIfNeeded(Throwable e) {
-        if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
+    // true if printStack* values are initialized
+    private static volatile boolean printStackPropertiesSet;
+
+    private static void ensurePrintStackPropertiesSet() {
+        if (!printStackPropertiesSet && VM.initLevel() >= 1) {
             String s = GetPropertyAction.privilegedGetProperty(
                     "sun.reflect.debugModuleAccessChecks");
-            printStackWhenAccessFails =
-                    (s != null && !s.equalsIgnoreCase("false"));
-            printStackWhenAccessFailsSet = true;
+            if (s != null) {
+                printStackWhenAccessFails = !s.equalsIgnoreCase("false");
+                printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
+            }
+            printStackPropertiesSet = true;
         }
-        if (printStackWhenAccessFails) {
-            e.printStackTrace();
-        }
+    }
+
+    public static void enableStackTraces() {
+        printStackWhenAccessFails = true;
+        printStackWhenAccessSucceeds = true;
+        printStackPropertiesSet = true;
+    }
+
+    public static boolean printStackTraceWhenAccessFails() {
+        ensurePrintStackPropertiesSet();
+        return printStackWhenAccessFails;
+    }
+
+    public static boolean printStackTraceWhenAccessSucceeds() {
+        ensurePrintStackPropertiesSet();
+        return printStackWhenAccessSucceeds;
     }
 
     /**
@@ -416,17 +443,10 @@
         throws IllegalAccessException
     {
         IllegalAccessException e = new IllegalAccessException(msg);
-        printStackTraceIfNeeded(e);
+        ensurePrintStackPropertiesSet();
+        if (printStackWhenAccessFails) {
+            e.printStackTrace(System.err);
+        }
         throw e;
     }
-
-    /**
-     * Throws InaccessibleObjectException with the given exception message.
-     */
-    public static void throwInaccessibleObjectException(String msg) {
-        InaccessibleObjectException e = new InaccessibleObjectException(msg);
-        printStackTraceIfNeeded(e);
-        throw e;
-    }
-
 }
diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java
index 2d38377..0c455f8 100644
--- a/jdk/src/java.base/share/classes/module-info.java
+++ b/jdk/src/java.base/share/classes/module-info.java
@@ -180,7 +180,8 @@
         java.management,
         jdk.jvmstat;
     exports jdk.internal.ref to
-        java.desktop;
+        java.desktop,
+        jdk.unsupported;
     exports jdk.internal.reflect to
         java.corba,
         java.logging,
@@ -218,8 +219,9 @@
         java.security.jgss;
     exports sun.nio.ch to
         java.management,
-        jdk.crypto.pkcs11,
-        jdk.sctp;
+        jdk.crypto.token,
+        jdk.sctp,
+        jdk.unsupported;
     exports sun.nio.cs to
         java.desktop,
         jdk.charsets;
@@ -242,14 +244,14 @@
         java.desktop,
         java.security.jgss;
     exports sun.security.internal.interfaces to
-        jdk.crypto.pkcs11;
+        jdk.crypto.token;
     exports sun.security.internal.spec to
-        jdk.crypto.pkcs11;
+        jdk.crypto.token;
     exports sun.security.jca to
         java.smartcardio,
         java.xml.crypto,
         jdk.crypto.ec,
-        jdk.crypto.pkcs11,
+        jdk.crypto.token,
         jdk.naming.dns;
     exports sun.security.pkcs to
         jdk.crypto.ec,
@@ -257,13 +259,13 @@
     exports sun.security.provider to
         java.rmi,
         java.security.jgss,
-        jdk.crypto.pkcs11,
+        jdk.crypto.token,
         jdk.policytool,
         jdk.security.auth;
     exports sun.security.provider.certpath to
         java.naming;
     exports sun.security.rsa to
-        jdk.crypto.pkcs11;
+        jdk.crypto.token;
     exports sun.security.ssl to
         java.security.jgss;
     exports sun.security.timestamp to
@@ -278,14 +280,14 @@
         java.security.sasl,
         java.smartcardio,
         jdk.crypto.ec,
-        jdk.crypto.pkcs11,
+        jdk.crypto.token,
         jdk.jartool,
         jdk.policytool,
         jdk.security.auth,
         jdk.security.jgss;
     exports sun.security.x509 to
         jdk.crypto.ec,
-        jdk.crypto.pkcs11,
+        jdk.crypto.token,
         jdk.jartool,
         jdk.security.auth;
     exports sun.text.resources to
diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/Negotiator.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/Negotiator.java
index 856efe1..7993b9d 100644
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/Negotiator.java
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/Negotiator.java
@@ -48,7 +48,9 @@
         Class<?> clazz;
         Constructor<?> c;
         try {
-            clazz = Class.forName("sun.net.www.protocol.http.spnego.NegotiatorImpl", true, null);
+            clazz = Class.forName("sun.net.www.protocol.http.spnego.NegotiatorImpl",
+                                  true,
+                                  ClassLoader.getPlatformClassLoader());
             c = clazz.getConstructor(HttpCallerInfo.class);
         } catch (ClassNotFoundException cnfe) {
             finest(cnfe);
diff --git a/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java b/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java
index b5d93a8f..f1daded 100644
--- a/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java
+++ b/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java
@@ -157,6 +157,9 @@
         // Method possible replaced with a compiler intrinsic.
         private static int encodeISOArray(char[] sa, int sp,
                                           byte[] da, int dp, int len) {
+            if (len <= 0) {
+                return 0;
+            }
             encodeISOArrayCheck(sa, sp, da, dp, len);
             return implEncodeISOArray(sa, sp, da, dp, len);
         }
@@ -177,10 +180,6 @@
 
         private static void encodeISOArrayCheck(char[] sa, int sp,
                                                 byte[] da, int dp, int len) {
-            if (len <= 0) {
-                return;  // not an error because encodeISOArrayImpl won't execute if len <= 0
-            }
-
             Objects.requireNonNull(sa);
             Objects.requireNonNull(da);
 
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java
index 2e309dc..f830bc7 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java
@@ -36,6 +36,7 @@
 import java.security.AccessControlContext;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
+import java.util.function.BiFunction;
 
 import javax.crypto.*;
 import javax.crypto.spec.*;
@@ -122,6 +123,14 @@
     // Negotiated ALPN value
     String applicationProtocol = null;
 
+    // Application protocol callback function (for SSLEngine)
+    BiFunction<SSLEngine,List<String>,String>
+        appProtocolSelectorSSLEngine = null;
+
+    // Application protocol callback function (for SSLSocket)
+    BiFunction<SSLSocket,List<String>,String>
+        appProtocolSelectorSSLSocket = null;
+
     // The maximum expected network packet size for SSL/TLS/DTLS records.
     int                         maximumPacketSize = 0;
 
@@ -501,6 +510,22 @@
     }
 
     /**
+     * Sets the Application Protocol selector function for SSLEngine.
+     */
+    void setApplicationProtocolSelectorSSLEngine(
+        BiFunction<SSLEngine,List<String>,String> selector) {
+        this.appProtocolSelectorSSLEngine = selector;
+    }
+
+    /**
+     * Sets the Application Protocol selector function for SSLSocket.
+     */
+    void setApplicationProtocolSelectorSSLSocket(
+        BiFunction<SSLSocket,List<String>,String> selector) {
+        this.appProtocolSelectorSSLSocket = selector;
+    }
+
+    /**
      * Sets the cipher suites preference.
      */
     void setUseCipherSuitesOrder(boolean on) {
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java
index 6aaaf89..188ba82 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java
@@ -27,8 +27,9 @@
 
 import java.io.*;
 import java.nio.*;
-import java.util.*;
 import java.security.*;
+import java.util.*;
+import java.util.function.BiFunction;
 
 import javax.crypto.BadPaddingException;
 
@@ -206,6 +207,10 @@
     // The value under negotiation will be obtained from handshaker.
     String applicationProtocol = null;
 
+    // Callback function that selects the application protocol value during
+    // the SSL/TLS handshake.
+    BiFunction<SSLEngine, List<String>, String> applicationProtocolSelector;
+
     // Have we been told whether we're client or server?
     private boolean                     serverModeSet = false;
     private boolean                     roleIsServer;
@@ -442,6 +447,8 @@
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
         handshaker.setApplicationProtocols(applicationProtocols);
+        handshaker.setApplicationProtocolSelectorSSLEngine(
+            applicationProtocolSelector);
 
         outputRecord.initHandshaker();
     }
@@ -2237,7 +2244,7 @@
         }
         applicationProtocols = params.getApplicationProtocols();
 
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setIdentificationProtocol(identificationProtocol);
             handshaker.setAlgorithmConstraints(algorithmConstraints);
             handshaker.setMaximumPacketSize(maximumPacketSize);
@@ -2264,6 +2271,21 @@
         return null;
     }
 
+    @Override
+    public synchronized void setHandshakeApplicationProtocolSelector(
+        BiFunction<SSLEngine, List<String>, String> selector) {
+        applicationProtocolSelector = selector;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setApplicationProtocolSelectorSSLEngine(selector);
+        }
+    }
+
+    @Override
+    public synchronized BiFunction<SSLEngine, List<String>, String>
+        getHandshakeApplicationProtocolSelector() {
+        return this.applicationProtocolSelector;
+    }
+
     /**
      * Returns a printable representation of this end of the connection.
      */
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
index 880c98a..be69a76 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -37,6 +37,7 @@
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiFunction;
 
 import javax.crypto.BadPaddingException;
 import javax.net.ssl.*;
@@ -223,6 +224,10 @@
     // The value under negotiation will be obtained from handshaker.
     String applicationProtocol = null;
 
+    // Callback function that selects the application protocol value during
+    // the SSL/TLS handshake.
+    BiFunction<SSLSocket, List<String>, String> applicationProtocolSelector;
+
     /*
      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
      * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
@@ -1370,6 +1375,8 @@
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
         handshaker.setApplicationProtocols(applicationProtocols);
+        handshaker.setApplicationProtocolSelectorSSLSocket(
+            applicationProtocolSelector);
     }
 
     /**
@@ -2151,7 +2158,7 @@
                         Utilities.addToSNIServerNameList(serverNames, host);
 
                 if (!roleIsServer &&
-                        (handshaker != null) && !handshaker.started()) {
+                        (handshaker != null) && !handshaker.activated()) {
                     handshaker.setSNIServerNames(serverNames);
                 }
             }
@@ -2179,7 +2186,7 @@
         this.serverNames =
             Utilities.addToSNIServerNameList(this.serverNames, this.host);
 
-        if (!roleIsServer && (handshaker != null) && !handshaker.started()) {
+        if (!roleIsServer && (handshaker != null) && !handshaker.activated()) {
             handshaker.setSNIServerNames(serverNames);
         }
     }
@@ -2631,7 +2638,7 @@
 
         applicationProtocols = params.getApplicationProtocols();
 
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setIdentificationProtocol(identificationProtocol);
             handshaker.setAlgorithmConstraints(algorithmConstraints);
             handshaker.setMaximumPacketSize(maximumPacketSize);
@@ -2658,6 +2665,21 @@
         return null;
     }
 
+    @Override
+    public synchronized void setHandshakeApplicationProtocolSelector(
+        BiFunction<SSLSocket, List<String>, String> selector) {
+        applicationProtocolSelector = selector;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setApplicationProtocolSelectorSSLSocket(selector);
+        }
+    }
+
+    @Override
+    public synchronized BiFunction<SSLSocket, List<String>, String>
+        getHandshakeApplicationProtocolSelector() {
+        return this.applicationProtocolSelector;
+    }
+
     //
     // We allocate a separate thread to deliver handshake completion
     // events.  This ensures that the notifications don't block the
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java
index 1777782..4ad18b1 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java
@@ -34,6 +34,7 @@
 import java.security.interfaces.*;
 import java.security.spec.ECParameterSpec;
 import java.math.BigInteger;
+import java.util.function.BiFunction;
 
 import javax.crypto.SecretKey;
 import javax.net.ssl.*;
@@ -532,31 +533,39 @@
         ALPNExtension clientHelloALPN = (ALPNExtension)
             mesg.extensions.get(ExtensionType.EXT_ALPN);
 
-        if ((clientHelloALPN != null) && (localApl.length > 0)) {
+        // Use the application protocol callback when provided.
+        // Otherwise use the local list of application protocols.
+        boolean hasAPCallback =
+            ((engine != null && appProtocolSelectorSSLEngine != null) ||
+                (conn != null && appProtocolSelectorSSLSocket != null));
 
-            // Intersect the requested and the locally supported,
-            // and save for later.
-            String negotiatedValue = null;
-            List<String> protocols = clientHelloALPN.getPeerAPs();
+        if (!hasAPCallback) {
+            if ((clientHelloALPN != null) && (localApl.length > 0)) {
 
-            // Use server preference order
-            for (String ap : localApl) {
-                if (protocols.contains(ap)) {
-                    negotiatedValue = ap;
-                    break;
+                // Intersect the requested and the locally supported,
+                // and save for later.
+                String negotiatedValue = null;
+                List<String> protocols = clientHelloALPN.getPeerAPs();
+
+                // Use server preference order
+                for (String ap : localApl) {
+                    if (protocols.contains(ap)) {
+                        negotiatedValue = ap;
+                        break;
+                    }
                 }
-            }
 
-            if (negotiatedValue == null) {
-                fatalSE(Alerts.alert_no_application_protocol,
-                    new SSLHandshakeException(
-                        "No matching ALPN values"));
-            }
-            applicationProtocol = negotiatedValue;
+                if (negotiatedValue == null) {
+                    fatalSE(Alerts.alert_no_application_protocol,
+                        new SSLHandshakeException(
+                            "No matching ALPN values"));
+                }
+                applicationProtocol = negotiatedValue;
 
-        } else {
-            applicationProtocol = "";
-        }
+            } else {
+                applicationProtocol = "";
+            }
+        }  // Otherwise, applicationProtocol will be set by the callback.
 
         session = null; // forget about the current session
         //
@@ -892,8 +901,36 @@
         }
 
         // Prepare the ALPN response
-        if (applicationProtocol != null && !applicationProtocol.isEmpty()) {
-            m1.extensions.add(new ALPNExtension(applicationProtocol));
+        if (clientHelloALPN != null) {
+            List<String> peerAPs = clientHelloALPN.getPeerAPs();
+
+            // check for a callback function
+            if (hasAPCallback) {
+                if (conn != null) {
+                    applicationProtocol =
+                        appProtocolSelectorSSLSocket.apply(conn, peerAPs);
+                } else {
+                    applicationProtocol =
+                        appProtocolSelectorSSLEngine.apply(engine, peerAPs);
+                }
+            }
+
+            // check for no-match and that the selected name was also proposed
+            // by the TLS peer
+            if (applicationProtocol == null ||
+                   (!applicationProtocol.isEmpty() &&
+                        !peerAPs.contains(applicationProtocol))) {
+
+                fatalSE(Alerts.alert_no_application_protocol,
+                    new SSLHandshakeException(
+                        "No matching ALPN values"));
+
+            } else if (!applicationProtocol.isEmpty()) {
+                m1.extensions.add(new ALPNExtension(applicationProtocol));
+            }
+        } else {
+            // Nothing was negotiated, returned at end of the handshake
+            applicationProtocol = "";
         }
 
         if (debug != null && Debug.isOn("handshake")) {
diff --git a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java
index 3ff90bf..a7754e6 100644
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java
@@ -1024,7 +1024,7 @@
         }
     }
 
-    // Values from SP800-57 part 1 rev 3 tables 2 and three
+    // Values from SP800-57 part 1 rev 4 tables 2 and 3
     private static String ecStrength (int bitLength) {
         if (bitLength >= 512) { // 256 bits of strength
             return "SHA512";
@@ -1035,7 +1035,7 @@
         }
     }
 
-    // same values for RSA and DSA
+    // Same values for RSA and DSA
     private static String ifcFfcStrength (int bitLength) {
         if (bitLength > 7680) { // 256 bits
             return "SHA512";
diff --git a/jdk/src/java.base/share/legal/aes.md b/jdk/src/java.base/share/legal/aes.md
new file mode 100644
index 0000000..6d0ee2e
--- /dev/null
+++ b/jdk/src/java.base/share/legal/aes.md
@@ -0,0 +1,36 @@
+## Cryptix AES v3.2.0
+
+### Cryptix General License
+<pre>
+
+Cryptix General License
+
+Copyright (c) 1995-2005 The Cryptix Foundation Limited.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  1. Redistributions of source code must retain the copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
+CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jdk/src/java.base/share/legal/asm.md b/jdk/src/java.base/share/legal/asm.md
new file mode 100644
index 0000000..584b205
--- /dev/null
+++ b/jdk/src/java.base/share/legal/asm.md
@@ -0,0 +1,36 @@
+## ASM Bytecode Manipulation Framework v5.1
+
+### ASM License
+<pre>
+
+Copyright (c) 2000-2011 France Télécom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jdk/src/java.base/share/legal/cldr.md b/jdk/src/java.base/share/legal/cldr.md
new file mode 100644
index 0000000..21e6d4c
--- /dev/null
+++ b/jdk/src/java.base/share/legal/cldr.md
@@ -0,0 +1,42 @@
+## Unicode Common Local Data Repository (CLDR) v29
+
+### CLDR License
+<pre>
+
+Copyright © 1991-2016 Unicode, Inc. All rights reserved.
+
+Distributed under the Terms of Use in
+http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation
+(the "Data Files") or Unicode software and any associated documentation
+(the "Software") to deal in the Data Files or Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of
+the Data Files or Software, and to permit persons to whom the Data Files
+or Software are furnished to do so, provided that
+(a) this copyright and permission notice appear with all copies
+of the Data Files or Software,
+(b) this copyright and permission notice appear in associated
+documentation, and
+(c) there is clear notice in each modified Data File or in the Software
+as well as in the documentation associated with the Data File(s) or
+Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in these Data Files or Software without prior written authorization of
+the copyright holder.
+
+</pre>
diff --git a/jdk/src/java.base/share/legal/icu.md b/jdk/src/java.base/share/legal/icu.md
new file mode 100644
index 0000000..4b24757
--- /dev/null
+++ b/jdk/src/java.base/share/legal/icu.md
@@ -0,0 +1,63 @@
+## International Components for Unicode (ICU4J) v56.1
+
+### ICU4J License
+<pre>
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and
+http://www.unicode.org/utility/trac/browser/.
+
+Unicode Data Files do not include PDF online code charts under the
+directory http://www.unicode.org/Public/.
+
+Software includes any source code published in the Unicode Standard
+or under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and
+http://www.unicode.org/utility/trac/browser/.
+
+NOTICE TO USER: Carefully read the following legal agreement.
+BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
+DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
+YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+TERMS AND CONDITIONS OF THIS AGREEMENT.
+IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
+THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2016 Unicode, Inc. All rights reserved.
+Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation
+(the "Data Files") or Unicode software and any associated documentation
+(the "Software") to deal in the Data Files or Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of
+the Data Files or Software, and to permit persons to whom the Data Files
+or Software are furnished to do so, provided that either
+(a) this copyright and permission notice appear with all copies
+of the Data Files or Software, or
+(b) this copyright and permission notice appear in associated
+Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in these Data Files or Software without prior
+written authorization of the copyright holder.
+
+</pre>
diff --git a/jdk/src/java.base/share/legal/zlib.md b/jdk/src/java.base/share/legal/zlib.md
new file mode 100644
index 0000000..bbf40f9
--- /dev/null
+++ b/jdk/src/java.base/share/legal/zlib.md
@@ -0,0 +1,27 @@
+## zlib v1.2.8
+
+### zlib License
+<pre>
+
+Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+</pre>
diff --git a/jdk/src/java.base/share/lib/security/default.policy b/jdk/src/java.base/share/lib/security/default.policy
index 9014111..0c1798f 100644
--- a/jdk/src/java.base/share/lib/security/default.policy
+++ b/jdk/src/java.base/share/lib/security/default.policy
@@ -125,7 +125,7 @@
     permission java.security.SecurityPermission "removeProviderProperty.SunEC";
 };
 
-grant codeBase "jrt:/jdk.crypto.pkcs11" {
+grant codeBase "jrt:/jdk.crypto.token" {
     permission java.lang.RuntimePermission
                    "accessClassInPackage.sun.security.*";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
diff --git a/jdk/src/java.base/share/native/libjava/StrictMath.c b/jdk/src/java.base/share/native/libjava/StrictMath.c
index 6c5ba31..32d4221 100644
--- a/jdk/src/java.base/share/native/libjava/StrictMath.c
+++ b/jdk/src/java.base/share/native/libjava/StrictMath.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,12 +65,6 @@
 }
 
 JNIEXPORT jdouble JNICALL
-Java_java_lang_StrictMath_exp(JNIEnv *env, jclass unused, jdouble d)
-{
-    return (jdouble) jexp((double)d);
-}
-
-JNIEXPORT jdouble JNICALL
 Java_java_lang_StrictMath_log(JNIEnv *env, jclass unused, jdouble d)
 {
     return (jdouble) jlog((double)d);
diff --git a/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp b/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp
index 72de36d..e2dbb79 100644
--- a/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp
+++ b/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp
@@ -181,7 +181,7 @@
         }
     } while (has_header);
     memcpy(uncompressed, decompressed_resource, (size_t) uncompressed_size);
-    delete decompressed_resource;
+    delete[] decompressed_resource;
 }
 
 // Zip decompressor
diff --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c
index d3f05a6..645d732 100644
--- a/jdk/src/java.base/share/native/libjli/java.c
+++ b/jdk/src/java.base/share/native/libjli/java.c
@@ -573,6 +573,17 @@
            JLI_StrCmp(name, "--patch-module") == 0;
 }
 
+static jboolean
+IsLongFormModuleOption(const char* name) {
+    return JLI_StrCCmp(name, "--module-path=") == 0 ||
+           JLI_StrCCmp(name, "--upgrade-module-path=") == 0 ||
+           JLI_StrCCmp(name, "--add-modules=") == 0 ||
+           JLI_StrCCmp(name, "--limit-modules=") == 0 ||
+           JLI_StrCCmp(name, "--add-exports=") == 0 ||
+           JLI_StrCCmp(name, "--add-reads=") == 0 ||
+           JLI_StrCCmp(name, "--patch-module=") == 0;
+}
+
 /*
  * Test if the given name has a white space option.
  */
@@ -1236,7 +1247,7 @@
         char *option = NULL;
         char *value = NULL;
         int kind = GetOpt(&argc, &argv, &option, &value);
-        jboolean has_arg = value != NULL;
+        jboolean has_arg = value != NULL && JLI_StrLen(value) > 0;
 
 /*
  * Option to set main entry point
@@ -1285,19 +1296,13 @@
 /*
  * Error missing argument
  */
-        } else if (!has_arg && IsWhiteSpaceOption(arg)) {
-            if (JLI_StrCmp(arg, "--module-path") == 0 ||
-                JLI_StrCmp(arg, "-p") == 0 ||
-                JLI_StrCmp(arg, "--upgrade-module-path") == 0) {
-                REPORT_ERROR (has_arg, ARG_ERROR4, arg);
-            } else if (JLI_StrCmp(arg, "--add-modules") == 0 ||
-                       JLI_StrCmp(arg, "--limit-modules") == 0 ||
-                       JLI_StrCmp(arg, "--add-exports") == 0 ||
-                       JLI_StrCmp(arg, "--add-opens") == 0 ||
-                       JLI_StrCmp(arg, "--add-reads") == 0 ||
-                       JLI_StrCmp(arg, "--patch-module") == 0) {
-                REPORT_ERROR (has_arg, ARG_ERROR6, arg);
-            }
+        } else if (!has_arg && (JLI_StrCmp(arg, "--module-path") == 0 ||
+                                JLI_StrCmp(arg, "-p") == 0 ||
+                                JLI_StrCmp(arg, "--upgrade-module-path") == 0)) {
+            REPORT_ERROR (has_arg, ARG_ERROR4, arg);
+
+        } else if (!has_arg && (IsModuleOption(arg) || IsLongFormModuleOption(arg))) {
+            REPORT_ERROR (has_arg, ARG_ERROR6, arg);
 /*
  * The following cases will cause the argument parsing to stop
  */
diff --git a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
index 20370e1..1fc1ce8 100644
--- a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
+++ b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -299,6 +299,16 @@
 
     /* -- Basic infrastructure -- */
 
+    private native long getNameMax0(String path);
+
+    public int getNameMax(String path) {
+        long nameMax = getNameMax0(path);
+        if (nameMax > Integer.MAX_VALUE) {
+            nameMax = Integer.MAX_VALUE;
+        }
+        return (int)nameMax;
+    }
+
     public int compare(File f1, File f2) {
         return f1.getPath().compareTo(f2.getPath());
     }
diff --git a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
index f26b010..78d9f7f 100644
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -109,13 +109,9 @@
         private String helperPath(String javahome, String osArch) {
             switch (this) {
                 case SOLARIS:
-                    if (osArch.equals("x86")) { osArch = "i386"; }
-                    else if (osArch.equals("x86_64")) { osArch = "amd64"; }
                     // fall through...
                 case LINUX:
                 case AIX:
-                    return javahome + "/lib/" + osArch + "/jspawnhelper";
-
                 case BSD:
                     return javahome + "/lib/jspawnhelper";
 
diff --git a/jdk/src/java.base/unix/classes/module-info.java.extra b/jdk/src/java.base/unix/classes/module-info.java.extra
new file mode 100644
index 0000000..43f85b0
--- /dev/null
+++ b/jdk/src/java.base/unix/classes/module-info.java.extra
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// jdk.vm.compiler uses Unsafe and VM classes from jdk.internal.misc
+exports jdk.internal.misc to jdk.vm.compiler;
+opens   jdk.internal.misc to jdk.vm.compiler;
+
+// jdk.vm.compiler uses com.sun.crypto.provider to generate crypto intrinsics
+opens com.sun.crypto.provider to jdk.vm.compiler;
+
+exports jdk.internal.module to jdk.vm.compiler;
+
+// AOT uses jdk.internal.misc.Unsafe
+exports jdk.internal.misc to jdk.aot;
diff --git a/jdk/src/java.base/unix/conf/arm/jvm.cfg b/jdk/src/java.base/unix/conf/arm/jvm.cfg
new file mode 100644
index 0000000..58efe00
--- /dev/null
+++ b/jdk/src/java.base/unix/conf/arm/jvm.cfg
@@ -0,0 +1,36 @@
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+# 
+# List of JVMs that can be used as an option to java, javac, etc.
+# Order is important -- first in this list is the default JVM.
+# NOTE that this both this file and its format are UNSUPPORTED and
+# WILL GO AWAY in a future release.
+#
+# You may also select a JVM in an arbitrary location with the
+# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
+# and may not be available in a future release.
+#
+-server KNOWN
+-client KNOWN
+-minimal KNOWN
diff --git a/jdk/src/java.base/unix/native/libjava/UnixFileSystem_md.c b/jdk/src/java.base/unix/native/libjava/UnixFileSystem_md.c
index cd16693..d204c1b 100644
--- a/jdk/src/java.base/unix/native/libjava/UnixFileSystem_md.c
+++ b/jdk/src/java.base/unix/native/libjava/UnixFileSystem_md.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
  * questions.
  */
 
+#include <unistd.h>
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -38,6 +39,10 @@
 #include <dlfcn.h>
 #include <limits.h>
 
+#if defined(__solaris__) && !defined(NAME_MAX)
+#define NAME_MAX MAXNAMLEN
+#endif
+
 #include "jni.h"
 #include "jni_util.h"
 #include "jlong.h"
@@ -487,3 +492,14 @@
     } END_PLATFORM_STRING(env, path);
     return rv;
 }
+
+JNIEXPORT jlong JNICALL
+Java_java_io_UnixFileSystem_getNameMax0(JNIEnv *env, jobject this,
+                                        jstring pathname)
+{
+    jlong length = -1;
+    WITH_PLATFORM_STRING(env, pathname, path) {
+        length = (jlong)pathconf(path, _PC_NAME_MAX);
+    } END_PLATFORM_STRING(env, path);
+    return length != -1 ? length : (jlong)NAME_MAX;
+}
diff --git a/jdk/src/java.base/unix/native/libjli/java_md.h b/jdk/src/java.base/unix/native/libjli/java_md.h
index 8e95ace..f0eaa30 100644
--- a/jdk/src/java.base/unix/native/libjli/java_md.h
+++ b/jdk/src/java.base/unix/native/libjli/java_md.h
@@ -54,10 +54,8 @@
 const char *SetExecname(char **argv);
 const char *GetExecName();
 static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
-                           char *jvmpath, jint jvmpathsize, const char * arch,
-                           int bitsWanted);
-static jboolean GetJREPath(char *path, jint pathsize, const char * arch,
-                           jboolean speculative);
+                           char *jvmpath, jint jvmpathsize, int bitsWanted);
+static jboolean GetJREPath(char *path, jint pathsize, jboolean speculative);
 
 #if defined(_AIX)
 #include "java_md_aix.h"
diff --git a/jdk/src/java.base/unix/native/libjli/java_md_solinux.c b/jdk/src/java.base/unix/native/libjli/java_md_solinux.c
index b9091aa..cb9afc0 100644
--- a/jdk/src/java.base/unix/native/libjli/java_md_solinux.c
+++ b/jdk/src/java.base/unix/native/libjli/java_md_solinux.c
@@ -52,9 +52,6 @@
 #endif
 
 #ifdef __solaris__
-#  ifndef LIBARCHNAME
-#    error "The macro LIBARCHNAME was not defined on the compile line"
-#  endif
 #  include <sys/systeminfo.h>
 #  include <sys/elf.h>
 #  include <stdio.h>
@@ -188,12 +185,13 @@
     return JNI_FALSE;
 }
 /*
- * contains a lib/$LIBARCHNAME/{server,client}/libjvm.so ?
+ * contains a lib/{server,client}/libjvm.so ?
  */
 static jboolean
 ContainsLibJVM(const char *env) {
-    char clientPattern[PATH_MAX + 1];
-    char serverPattern[PATH_MAX + 1];
+    /* the usual suspects */
+    char clientPattern[] = "lib/client";
+    char serverPattern[] = "lib/server";
     char *envpath;
     char *path;
     jboolean clientPatternFound;
@@ -204,10 +202,6 @@
         return JNI_FALSE;
     }
 
-    /* the usual suspects */
-    JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", LIBARCHNAME);
-    JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", LIBARCHNAME);
-
     /* to optimize for time, test if any of our usual suspects are present. */
     clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
     serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
@@ -322,7 +316,6 @@
 
     /* Check data model flags, and exec process, if needed */
     {
-      char *arch        = LIBARCHNAME; /* like sparc or sparcv9 */
       char * jvmtype    = NULL;
       int  argc         = *pargc;
       char **argv       = *pargv;
@@ -408,12 +401,12 @@
          jvmpath does not exist */
       if (wanted == running) {
         /* Find out where the JRE is that we will be using. */
-        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+        if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
           JLI_ReportErrorMessage(JRE_ERROR1);
           exit(2);
         }
-        JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
-                     jrepath, FILESEP, FILESEP,  arch, FILESEP);
+        JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%sjvm.cfg",
+                     jrepath, FILESEP, FILESEP, FILESEP);
         /* Find the specified JVM type */
         if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
           JLI_ReportErrorMessage(CFG_ERROR7);
@@ -427,7 +420,7 @@
             exit(4);
         }
 
-        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {
+        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, 0 )) {
           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
           exit(4);
         }
@@ -444,21 +437,21 @@
             return;
         }
 #else
-            JLI_MemFree(newargv);
-            return;
+        JLI_MemFree(newargv);
+        return;
 #endif /* SETENV_REQUIRED */
-    } else {  /* do the same speculatively or exit */
+      } else {  /* do the same speculatively or exit */
         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
         exit(1);
-    }
+      }
 #ifdef SETENV_REQUIRED
         if (mustsetenv) {
             /*
              * We will set the LD_LIBRARY_PATH as follows:
              *
              *     o          $JVMPATH (directory portion only)
-             *     o          $JRE/lib/$LIBARCHNAME
-             *     o          $JRE/../lib/$LIBARCHNAME
+             *     o          $JRE/lib
+             *     o          $JRE/../lib
              *
              * followed by the user's previous effective LD_LIBRARY_PATH, if
              * any.
@@ -515,43 +508,44 @@
 #endif /* __solaris__ */
 
             /* runpath contains current effective LD_LIBRARY_PATH setting */
-
-            jvmpath = JLI_StringDup(jvmpath);
-            new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
-                    2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +
+            { /* New scope to declare local variable */
+              char *new_jvmpath = JLI_StringDup(jvmpath);
+              new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
+                      2 * JLI_StrLen(jrepath) +
 #ifdef AIX
-                    /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
-                    JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") +
+                      /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
+                      JLI_StrLen(jrepath) + JLI_StrLen("/lib//jli:") +
 #endif
-                    JLI_StrLen(jvmpath) + 52;
-            new_runpath = JLI_MemAlloc(new_runpath_size);
-            newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
+                      JLI_StrLen(new_jvmpath) + 52;
+              new_runpath = JLI_MemAlloc(new_runpath_size);
+              newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
 
 
-            /*
-             * Create desired LD_LIBRARY_PATH value for target data model.
-             */
-            {
+              /*
+               * Create desired LD_LIBRARY_PATH value for target data model.
+               */
+              {
                 /* remove the name of the .so from the JVM path */
-                lastslash = JLI_StrRChr(jvmpath, '/');
+                lastslash = JLI_StrRChr(new_jvmpath, '/');
                 if (lastslash)
                     *lastslash = '\0';
 
                 sprintf(new_runpath, LD_LIBRARY_PATH "="
                         "%s:"
-                        "%s/lib/%s:"
+                        "%s/lib:"
 #ifdef AIX
-                        "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
+                        "%s/lib/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
 #endif
-                        "%s/../lib/%s",
-                        jvmpath,
-                        jrepath, arch,
+                        "%s/../lib",
+                        new_jvmpath,
+                        jrepath,
 #ifdef AIX
-                        jrepath, arch,
+                        jrepath,
 #endif
-                        jrepath, arch
+                        jrepath
                         );
 
+                JLI_MemFree(new_jvmpath);
 
                 /*
                  * Check to make sure that the prefix of the current path is the
@@ -571,6 +565,7 @@
                     JLI_MemFree(new_runpath);
                     return;
                 }
+              }
             }
 
             /*
@@ -638,14 +633,14 @@
  */
 static jboolean
 GetJVMPath(const char *jrepath, const char *jvmtype,
-           char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+           char *jvmpath, jint jvmpathsize, int bitsWanted)
 {
     struct stat s;
 
     if (JLI_StrChr(jvmtype, '/')) {
         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
     } else {
-        JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
+        JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
     }
 
     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
@@ -663,14 +658,14 @@
  * Find path to JRE based on .exe's location or registry settings.
  */
 static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
 {
     char libjava[MAXPATHLEN];
     struct stat s;
 
     if (GetApplicationHome(path, pathsize)) {
         /* Is JRE co-located with the application? */
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
         if (access(libjava, F_OK) == 0) {
             JLI_TraceLauncher("JRE path is %s\n", path);
             return JNI_TRUE;
@@ -681,7 +676,7 @@
             return JNI_FALSE;
         }
         /* Does the app ship a private JRE in <apphome>/jre directory? */
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
         if (access(libjava, F_OK) == 0) {
             JLI_StrCat(path, "/jre");
             JLI_TraceLauncher("JRE path is %s\n", path);
@@ -690,7 +685,7 @@
     }
 
     if (GetApplicationHomeFromDll(path, pathsize)) {
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
         if (stat(libjava, &s) == 0) {
             JLI_TraceLauncher("JRE path is %s\n", path);
             return JNI_TRUE;
@@ -856,12 +851,12 @@
         char jrePath[MAXPATHLEN];
         char splashPath[MAXPATHLEN];
 
-        if (!GetJREPath(jrePath, sizeof(jrePath), LIBARCHNAME, JNI_FALSE)) {
+        if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
             JLI_ReportErrorMessage(JRE_ERROR1);
             return NULL;
         }
-        ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",
-                     jrePath, LIBARCHNAME, SPLASHSCREEN_SO);
+        ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
+                     jrePath, SPLASHSCREEN_SO);
 
         if (ret >= (int) sizeof(splashPath)) {
             JLI_ReportErrorMessage(JRE_ERROR11);
diff --git a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c
index e2e0f10..385b319 100644
--- a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c
+++ b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c
@@ -37,273 +37,10 @@
 
 #include "java_net_Inet4AddressImpl.h"
 
-#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
-#define HAS_GLIBC_GETHOSTBY_R   1
-#endif
-
-
-#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
+#if defined(MACOSX)
 extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
-
-/* Use getaddrinfo(3), which is thread safe */
-/************************************************************************
- * Inet4AddressImpl
- */
-
-/*
- * Class:     java_net_Inet4AddressImpl
- * Method:    getLocalHostName
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
-    char hostname[NI_MAXHOST+1];
-
-    hostname[0] = '\0';
-    if (gethostname(hostname, NI_MAXHOST)) {
-        /* Something went wrong, maybe networking is not setup? */
-        strcpy(hostname, "localhost");
-    } else {
-         struct addrinfo  hints, *res;
-         int error;
-
-         memset(&hints, 0, sizeof(hints));
-         hints.ai_flags = AI_CANONNAME;
-         hints.ai_family = AF_UNSPEC;
-
-         error = getaddrinfo(hostname, NULL, &hints, &res);
-
-         if (error == 0) {
-             /* host is known to name service */
-             error = getnameinfo(res->ai_addr,
-                                 res->ai_addrlen,
-                                 hostname,
-                                 NI_MAXHOST,
-                                 NULL,
-                                 0,
-                                 NI_NAMEREQD);
-
-             /* if getnameinfo fails hostname is still the value
-                from gethostname */
-
-             freeaddrinfo(res);
-        }
-    }
-    return (*env)->NewStringUTF(env, hostname);
-}
-
-/*
- * Find an internet address for a given hostname.  Note that this
- * code only works for addresses of type INET. The translation
- * of %d.%d.%d.%d to an address (int) occurs in java now, so the
- * String "host" shouldn't *ever* be a %d.%d.%d.%d string
- *
- * Class:     java_net_Inet4AddressImpl
- * Method:    lookupAllHostAddr
- * Signature: (Ljava/lang/String;)[[B
- */
-
-JNIEXPORT jobjectArray JNICALL
-Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
-                                                jstring host) {
-    const char *hostname;
-    jobject name;
-    jobjectArray ret = 0;
-    int retLen = 0;
-
-    int getaddrinfo_error=0;
-    struct addrinfo hints, *res, *resNew = NULL;
-
-    initInetAddressIDs(env);
-    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
-
-    if (IS_NULL(host)) {
-        JNU_ThrowNullPointerException(env, "host is null");
-        return 0;
-    }
-    hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
-    CHECK_NULL_RETURN(hostname, NULL);
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_flags = AI_CANONNAME;
-    hints.ai_family = AF_INET;
-
-    /*
-     * Workaround for Solaris bug 4160367 - if a hostname contains a
-     * white space then 0.0.0.0 is returned
-     */
-    if (isspace((unsigned char)hostname[0])) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
-                        (char *)hostname);
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-        return NULL;
-    }
-
-
-    getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
-
-#ifdef MACOSX
-    if (getaddrinfo_error) {
-        // If getaddrinfo fails try getifaddrs.
-        ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
-        if (ret != NULL || (*env)->ExceptionCheck(env)) {
-            JNU_ReleaseStringPlatformChars(env, host, hostname);
-            return ret;
-        }
-    }
 #endif
 
-    if (getaddrinfo_error) {
-        /* report error */
-        NET_ThrowUnknownHostExceptionWithGaiError(
-            env, hostname, getaddrinfo_error);
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-        return NULL;
-    } else {
-        int i = 0;
-        struct addrinfo *itr, *last = NULL, *iterator = res;
-        while (iterator != NULL) {
-            int skip = 0;
-            itr = resNew;
-
-            while (itr != NULL) {
-                struct sockaddr_in *addr1, *addr2;
-
-                addr1 = (struct sockaddr_in *)iterator->ai_addr;
-                addr2 = (struct sockaddr_in *)itr->ai_addr;
-                if (addr1->sin_addr.s_addr ==
-                    addr2->sin_addr.s_addr) {
-                    skip = 1;
-                    break;
-                }
-
-                itr = itr->ai_next;
-            }
-
-            if (!skip) {
-                struct addrinfo *next
-                    = (struct addrinfo*) malloc(sizeof(struct addrinfo));
-                if (!next) {
-                    JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
-                    ret = NULL;
-                    goto cleanupAndReturn;
-                }
-                memcpy(next, iterator, sizeof(struct addrinfo));
-                next->ai_next = NULL;
-                if (resNew == NULL) {
-                    resNew = next;
-                } else {
-                    last->ai_next = next;
-                }
-                last = next;
-                i++;
-            }
-            iterator = iterator->ai_next;
-        }
-
-        retLen = i;
-        iterator = resNew;
-        i = 0;
-
-        name = (*env)->NewStringUTF(env, hostname);
-        if (IS_NULL(name)) {
-          goto cleanupAndReturn;
-        }
-
-        ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
-        if (IS_NULL(ret)) {
-            /* we may have memory to free at the end of this */
-            goto cleanupAndReturn;
-        }
-
-        while (iterator != NULL) {
-            /* We need 4 bytes to store ipv4 address; */
-            int len = 4;
-
-            jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
-            if (IS_NULL(iaObj)) {
-                /* we may have memory to free at the end of this */
-                ret = NULL;
-                goto cleanupAndReturn;
-            }
-            setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
-            setInetAddress_hostName(env, iaObj, name);
-            (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
-            i++;
-            iterator = iterator->ai_next;
-        }
-    }
-
-cleanupAndReturn:
-    {
-        struct addrinfo *iterator, *tmp;
-        iterator = resNew;
-        while (iterator != NULL) {
-            tmp = iterator;
-            iterator = iterator->ai_next;
-            free(tmp);
-        }
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-    }
-
-    freeaddrinfo(res);
-
-    return ret;
-
-}
-
-/*
- * Class:     java_net_Inet4AddressImpl
- * Method:    getHostByAddr
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
-                                            jbyteArray addrArray) {
-    jstring ret = NULL;
-
-    char host[NI_MAXHOST+1];
-    jfieldID fid;
-    int error = 0;
-    jint family;
-    struct sockaddr *him ;
-    int len = 0;
-    jbyte caddr[4];
-    jint addr;
-
-    struct sockaddr_in him4;
-    struct sockaddr *sa;
-
-    /*
-         * For IPv4 addresses construct a sockaddr_in structure.
-         */
-    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
-    addr = ((caddr[0]<<24) & 0xff000000);
-    addr |= ((caddr[1] <<16) & 0xff0000);
-    addr |= ((caddr[2] <<8) & 0xff00);
-    addr |= (caddr[3] & 0xff);
-    memset((char *) &him4, 0, sizeof(him4));
-    him4.sin_addr.s_addr = htonl(addr);
-    him4.sin_family = AF_INET;
-    sa = (struct sockaddr *) &him4;
-    len = sizeof(him4);
-
-    error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
-
-    if (!error) {
-        ret = (*env)->NewStringUTF(env, host);
-    }
-
-    if (ret == NULL) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
-    }
-
-    return ret;
-
-}
-
-#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
-
 /* the initial size of our hostent buffers */
 #ifndef NI_MAXHOST
 #define NI_MAXHOST 1025
@@ -405,6 +142,17 @@
 
     error = getaddrinfo(hostname, NULL, &hints, &res);
 
+#ifdef MACOSX
+    if (error) {
+        // If getaddrinfo fails try getifaddrs, see bug 8170910.
+        ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
+        if (ret != NULL || (*env)->ExceptionCheck(env)) {
+            JNU_ReleaseStringPlatformChars(env, host, hostname);
+            return ret;
+        }
+    }
+#endif
+
     if (error) {
         /* report error */
         NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
@@ -475,7 +223,7 @@
         }
     }
 
- cleanupAndReturn:
+cleanupAndReturn:
     {
         struct addrinfo *iterator, *tmp;
         iterator = resNew;
@@ -535,8 +283,6 @@
     return ret;
 }
 
-#endif /* _ALLBSD_SOURCE */
-
 #define SET_NONBLOCKING(fd) {           \
         int flags = fcntl(fd, F_GETFL); \
         flags |= O_NONBLOCK;            \
diff --git a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
index edd756b..e6b13bb 100644
--- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
+++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package java.io;
 
+import java.io.File;
+import java.nio.file.Path;
 import java.util.Locale;
 import java.util.Properties;
 import sun.security.action.GetPropertyAction;
@@ -627,6 +629,27 @@
 
     /* -- Basic infrastructure -- */
 
+    // Obtain maximum file component length from GetVolumeInformation which
+    // expects the path to be null or a root component ending in a backslash
+    private native int getNameMax0(String path);
+
+    public int getNameMax(String path) {
+        String s = null;
+        if (path != null) {
+            File f = new File(path);
+            if (f.isAbsolute()) {
+                Path root = f.toPath().getRoot();
+                if (root != null) {
+                    s = root.toString();
+                    if (!s.endsWith("\\")) {
+                        s = s + "\\";
+                    }
+                }
+            }
+        }
+        return getNameMax0(s);
+    }
+
     @Override
     public int compare(File f1, File f2) {
         return f1.getPath().compareToIgnoreCase(f2.getPath());
diff --git a/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c
index 1e29fd2..5e1664e 100644
--- a/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c
+++ b/jdk/src/java.base/windows/native/libjava/WinNTFileSystem_md.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -887,3 +887,42 @@
     free(pathbuf);
     return rv;
 }
+
+// pathname is expected to be either null or to contain the root
+// of the path terminated by a backslash
+JNIEXPORT jint JNICALL
+Java_java_io_WinNTFileSystem_getNameMax0(JNIEnv *env, jobject this,
+                                         jstring pathname)
+{
+    BOOL res = 0;
+    DWORD maxComponentLength;
+
+    if (pathname == NULL) {
+            res = GetVolumeInformationW(NULL,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        &maxComponentLength,
+                                        NULL,
+                                        NULL,
+                                        0);
+    } else {
+        WITH_UNICODE_STRING(env, pathname, path) {
+            res = GetVolumeInformationW(path,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        &maxComponentLength,
+                                        NULL,
+                                        NULL,
+                                        0);
+        } END_UNICODE_STRING(env, path);
+    }
+
+    if (res == 0) {
+        JNU_ThrowIOExceptionWithLastError(env,
+            "Could not get maximum component length");
+    }
+
+    return (jint)maxComponentLength;
+}
diff --git a/jdk/src/java.base/windows/native/libjli/java_md.c b/jdk/src/java.base/windows/native/libjli/java_md.c
index adb90a5..385fc8c 100644
--- a/jdk/src/java.base/windows/native/libjli/java_md.c
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c
@@ -151,22 +151,6 @@
 }
 
 /*
- * Returns the arch path, to get the current arch use the
- * macro GetArch, nbits here is ignored for now.
- */
-const char *
-GetArchPath(int nbits)
-{
-#ifdef _M_AMD64
-    return "amd64";
-#elif defined(_M_IA64)
-    return "ia64";
-#else
-    return "i386";
-#endif
-}
-
-/*
  *
  */
 void
@@ -207,8 +191,8 @@
         exit(2);
     }
 
-    JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
-        jrepath, FILESEP, FILESEP, (char*)GetArch(), FILESEP);
+    JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
+        jrepath, FILESEP, FILESEP);
 
     /* Find the specified JVM type */
     if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
diff --git a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c
index f7dc5c2..8a901af 100644
--- a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c
+++ b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c
@@ -113,24 +113,22 @@
  * Class:     java_net_Inet4AddressImpl
  * Method:    lookupAllHostAddr
  * Signature: (Ljava/lang/String;)[[B
- *
- * This is almost shared code
  */
-
 JNIEXPORT jobjectArray JNICALL
 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
-                                                jstring host) {
-    const char *hostname;
-    struct hostent *hp;
-    unsigned int addr[4];
-
+                                                 jstring host) {
     jobjectArray ret = NULL;
+    const char *hostname;
+    int error = 0;
+    unsigned int addr[4];
+    struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
+        *iterator;
 
     initInetAddressIDs(env);
     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 
     if (IS_NULL(host)) {
-        JNU_ThrowNullPointerException(env, "host argument");
+        JNU_ThrowNullPointerException(env, "host argument is null");
         return NULL;
     }
     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
@@ -166,9 +164,9 @@
         /*
          * Return an byte array with the populated address.
          */
-        address = (addr[3]<<24) & 0xff000000;
-        address |= (addr[2]<<16) & 0xff0000;
-        address |= (addr[1]<<8) & 0xff00;
+        address = (addr[3] << 24) & 0xff000000;
+        address |= (addr[2] << 16) & 0xff0000;
+        address |= (addr[1] << 8) & 0xff00;
         address |= addr[0];
 
         ret = (*env)->NewObjectArray(env, 1, ia_class, NULL);
@@ -179,58 +177,95 @@
 
         iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
         if (IS_NULL(iaObj)) {
-          ret = NULL;
-          goto cleanupAndReturn;
+            ret = NULL;
+            goto cleanupAndReturn;
         }
         setInetAddress_addr(env, iaObj, ntohl(address));
         (*env)->SetObjectArrayElement(env, ret, 0, iaObj);
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-        return ret;
+        goto cleanupAndReturn;
     }
 
-    /*
-     * Perform the lookup
-     */
-    if ((hp = gethostbyname((char*)hostname)) != NULL) {
-        struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
-        int len = sizeof(struct in_addr);
-        int i = 0;
+    // try once, with our static buffer
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_CANONNAME;
+    hints.ai_family = AF_INET;
 
-        while (*addrp != (struct in_addr *) 0) {
-            i++;
-            addrp++;
+    error = getaddrinfo(hostname, NULL, &hints, &res);
+
+    if (error) {
+        NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException",
+                                     hostname);
+        goto cleanupAndReturn;
+    } else {
+        int i = 0;
+        iterator = res;
+        while (iterator != NULL) {
+            // skip duplicates
+            int skip = 0;
+            struct addrinfo *iteratorNew = resNew;
+            while (iteratorNew != NULL) {
+                struct sockaddr_in *addr1, *addr2;
+                addr1 = (struct sockaddr_in *)iterator->ai_addr;
+                addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
+                if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
+                    skip = 1;
+                    break;
+                }
+                iteratorNew = iteratorNew->ai_next;
+            }
+
+            if (!skip) {
+                struct addrinfo *next
+                    = (struct addrinfo *)malloc(sizeof(struct addrinfo));
+                if (!next) {
+                    JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
+                    ret = NULL;
+                    goto cleanupAndReturn;
+                }
+                memcpy(next, iterator, sizeof(struct addrinfo));
+                next->ai_next = NULL;
+                if (resNew == NULL) {
+                    resNew = next;
+                } else {
+                    last->ai_next = next;
+                }
+                last = next;
+                i++;
+            }
+            iterator = iterator->ai_next;
         }
 
+        // allocate array - at this point i contains the number of addresses
         ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
-
         if (IS_NULL(ret)) {
             goto cleanupAndReturn;
         }
 
-        addrp = (struct in_addr **) hp->h_addr_list;
         i = 0;
-        while (*addrp != (struct in_addr *) 0) {
-          jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
-          if (IS_NULL(iaObj)) {
-            ret = NULL;
-            goto cleanupAndReturn;
-          }
-          setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));
-          setInetAddress_hostName(env, iaObj, host);
-          (*env)->SetObjectArrayElement(env, ret, i, iaObj);
-          addrp++;
-          i++;
+        iterator = resNew;
+        while (iterator != NULL) {
+            jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
+            if (IS_NULL(iaObj)) {
+                ret = NULL;
+                goto cleanupAndReturn;
+            }
+            setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in *)
+                                (iterator->ai_addr))->sin_addr.s_addr));
+            setInetAddress_hostName(env, iaObj, host);
+            (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
+            iterator = iterator->ai_next;
         }
-    } else if (WSAGetLastError() == WSATRY_AGAIN) {
-        NET_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "UnknownHostException",
-                                     hostname);
-    } else {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
     }
-
 cleanupAndReturn:
     JNU_ReleaseStringPlatformChars(env, host, hostname);
+    while (resNew != NULL) {
+        last = resNew;
+        resNew = resNew->ai_next;
+        free(last);
+    }
+    if (res != NULL) {
+        freeaddrinfo(res);
+    }
     return ret;
 }
 
@@ -238,30 +273,42 @@
  * Class:     java_net_Inet4AddressImpl
  * Method:    getHostByAddr
  * Signature: (I)Ljava/lang/String;
+ *
+ * Theoretically the UnknownHostException could be enriched with gai error
+ * information. But as it is silently ignored anyway, there's no need for this.
+ * It's only important that either a valid hostname is returned or an
+ * UnknownHostException is thrown.
  */
 JNIEXPORT jstring JNICALL
 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
-                                            jbyteArray addrArray) {
-    struct hostent *hp;
+                                             jbyteArray addrArray) {
+    jstring ret = NULL;
+    char host[NI_MAXHOST + 1];
     jbyte caddr[4];
     jint addr;
-    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
-    addr = ((caddr[0]<<24) & 0xff000000);
-    addr |= ((caddr[1] <<16) & 0xff0000);
-    addr |= ((caddr[2] <<8) & 0xff00);
-    addr |= (caddr[3] & 0xff);
-    addr = htonl(addr);
+    struct sockaddr_in sa;
 
-    hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
-    if (hp == NULL) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
-        return NULL;
+    // construct a sockaddr_in structure
+    memset((char *)&sa, 0, sizeof(struct sockaddr_in));
+    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
+    addr = ((caddr[0] << 24) & 0xff000000);
+    addr |= ((caddr[1] << 16) & 0xff0000);
+    addr |= ((caddr[2] << 8) & 0xff00);
+    addr |= (caddr[3] & 0xff);
+    sa.sin_addr.s_addr = htonl(addr);
+    sa.sin_family = AF_INET;
+
+    if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in),
+                    host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
+        JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
+    } else {
+        ret = (*env)->NewStringUTF(env, host);
+        if (ret == NULL) {
+            JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
+        }
     }
-    if (hp->h_name == NULL) { /* Deal with bug in Windows XP */
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
-        return NULL;
-    }
-    return JNU_NewStringPlatform(env, hp->h_name);
+
+    return ret;
 }
 
 static jboolean
diff --git a/jdk/src/java.compact1/share/classes/module-info.java b/jdk/src/java.compact1/share/classes/module-info.java
deleted file mode 100644
index 72d4357..0000000
--- a/jdk/src/java.compact1/share/classes/module-info.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Aggregates {@code java.base}, {@code java.logging}, and {@code java.scripting}.
- */
-module java.compact1 {
-    requires transitive java.logging;
-    requires transitive java.scripting;
-}
-
diff --git a/jdk/src/java.compact2/share/classes/module-info.java b/jdk/src/java.compact2/share/classes/module-info.java
deleted file mode 100644
index 0666be8..0000000
--- a/jdk/src/java.compact2/share/classes/module-info.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Supplements {@code java.compact1} with JDBC, JAXP, and RMI.
- */
-module java.compact2 {
-    requires transitive java.compact1;
-    requires transitive java.rmi;
-    requires transitive java.sql;
-    requires transitive java.xml;
-}
-
diff --git a/jdk/src/java.compact3/share/classes/module-info.java b/jdk/src/java.compact3/share/classes/module-info.java
deleted file mode 100644
index 9783a40..0000000
--- a/jdk/src/java.compact3/share/classes/module-info.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Supplements {@code java.compact2} with JDBC RowSet, JMX, JNDI, Compiler,
- * Instrumentation, Preferences, Security, and XML cryptography APIs.
- */
-module java.compact3 {
-    requires transitive java.compact2;
-    requires transitive java.compiler;
-    requires transitive java.instrument;
-    requires transitive java.management;
-    requires transitive java.naming;
-    requires transitive java.prefs;
-    requires transitive java.security.jgss;
-    requires transitive java.security.sasl;
-    requires transitive java.sql.rowset;
-    requires transitive java.xml.crypto;
-}
-
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java b/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java
deleted file mode 100644
index a0cc080..0000000
--- a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jndi.cosnaming;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-
-import java.net.MalformedURLException;
-import com.sun.jndi.toolkit.url.UrlUtil;
-
-/**
- * Extract components of a "corbaname" URL.
- *
- * The format of an corbaname URL is defined in INS 99-12-03 as follows.
- * <pre>{@code
- * corbaname url = "corbaname:" <corbaloc_obj> ["#" <string_name>]
- * corbaloc_obj  = <obj_addr_list> ["/" <key_string>]
- * obj_addr_list = as defined in a corbaloc URL
- * key_string    = as defined in a corbaloc URL
- * string_name   = stringified COS name | empty_string
- * }</pre>
- * Characters in {@code <string_name>} are escaped as follows.
- * US-ASCII alphanumeric characters are not escaped. Any characters outside
- * of this range are escaped except for the following:
- * <pre>{@code
- *        ; / : ? @ & = + $ , - _ . ! ~ * ; ( )
- * }</pre>
- * Escaped characters is escaped by using a % followed by its 2 hexadecimal
- * numbers representing the octet.
- * <p>
- * The corbaname URL is parsed into two parts: a corbaloc URL and a COS name.
- * The corbaloc URL is constructed by concatenation {@code "corbaloc:"} with
- * {@code <corbaloc_obj>}.
- * The COS name is {@code <string_name>} with the escaped characters resolved.
- * <p>
- * A corbaname URL is resolved by:
- * <ol>
- * <li>Construct a corbaloc URL by concatenating {@code "corbaloc:"} and {@code <corbaloc_obj>}.
- * <li>Resolve the corbaloc URL to a NamingContext by using
- * <pre>{@code
- *     nctx = ORB.string_to_object(corbalocUrl);
- * }</pre>
- * <li>Resolve {@code <string_name>} in the NamingContext.
- * </ol>
- *
- * @author Rosanna Lee
- */
-
-public final class CorbanameUrl {
-    private String stringName;
-    private String location;
-
-    /**
-     * Returns a possibly empty but non-null string that is the "string_name"
-     * portion of the URL.
-     */
-    public String getStringName() {
-        return stringName;
-    }
-
-    public Name getCosName() throws NamingException {
-        return CNCtx.parser.parse(stringName);
-    }
-
-    public String getLocation() {
-        return "corbaloc:" + location;
-    }
-
-    public CorbanameUrl(String url) throws MalformedURLException {
-
-        if (!url.startsWith("corbaname:")) {
-            throw new MalformedURLException("Invalid corbaname URL: " + url);
-        }
-
-        int addrStart = 10;  // "corbaname:"
-
-        int addrEnd = url.indexOf('#', addrStart);
-        if (addrEnd < 0) {
-            addrEnd = url.length();
-            stringName = "";
-        } else {
-            stringName = UrlUtil.decode(url.substring(addrEnd+1));
-        }
-        location = url.substring(addrStart, addrEnd);
-
-        int keyStart = location.indexOf('/');
-        if (keyStart >= 0) {
-            // Has key string
-            if (keyStart == (location.length() -1)) {
-                location += "NameService";
-            }
-        } else {
-            location += "/NameService";
-        }
-    }
-/*
-    // for testing only
-    public static void main(String[] args) {
-        try {
-            CorbanameUrl url = new CorbanameUrl(args[0]);
-
-            System.out.println("location: " + url.getLocation());
-            System.out.println("string name: " + url.getStringName());
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
-        }
-    }
-*/
-}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java b/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java
deleted file mode 100644
index a51d6a4..0000000
--- a/jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jndi.cosnaming;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-
-import java.net.MalformedURLException;
-import java.util.Vector;
-import java.util.StringTokenizer;
-import com.sun.jndi.toolkit.url.UrlUtil;
-
-/**
- * Extract components of an "iiop" or "iiopname" URL.
- *
- * The format of an iiopname URL is defined in INS 98-10-11 as follows:
- *
- * <pre>
- * iiopname url = "iiopname://" [addr_list]["/" string_name]
- * addr_list    = [address ","]* address
- * address      = [version host [":" port]]
- * host         = DNS style host name | IP address
- * version      = major "." minor "@" | empty_string
- * port         = number
- * major        = number
- * minor        = number
- * string_name  = stringified name | empty_string
- * </pre>
- *
- * The default port is 9999. The default version is "1.0"
- * US-ASCII alphanumeric characters are not escaped. Any characters outside
- * of this range are escaped except for the following:
- * <pre>{@code
- * ; / : ? : @ & = + $ , - _ . ! ~ *  ' ( )
- * }</pre>
- * Escaped characters is escaped by using a % followed by its 2 hexadecimal
- * numbers representing the octet.
- *
- * For backward compatibility,  the "iiop" URL as defined in INS 97-6-6
- * is also supported:
- * <pre>{@code
- * iiop url     = "iiop://" [host [":" port]] ["/" string_name]
- * }</pre>
- * The default port is 900.
- *
- * @author Rosanna Lee
- */
-
-public final class IiopUrl {
-    static final private int DEFAULT_IIOPNAME_PORT = 9999;
-    static final private int DEFAULT_IIOP_PORT = 900;
-    static final private String DEFAULT_HOST = "localhost";
-    private Vector<Address> addresses;
-    private String stringName;
-
-    public static class Address {
-        public int port = -1;
-        public int major, minor;
-        public String host;
-
-        public Address(String hostPortVers, boolean oldFormat)
-            throws MalformedURLException {
-            // [version host [":" port]]
-            int start;
-
-            // Parse version
-            int at;
-            if (oldFormat || (at = hostPortVers.indexOf('@')) < 0) {
-                major = 1;
-                minor = 0;
-                start = 0;     // start at the beginning
-            } else {
-                int dot = hostPortVers.indexOf('.');
-                if (dot < 0) {
-                    throw new MalformedURLException(
-                        "invalid version: " + hostPortVers);
-                }
-                try {
-                    major = Integer.parseInt(hostPortVers.substring(0, dot));
-                    minor = Integer.parseInt(hostPortVers.substring(dot+1, at));
-                } catch (NumberFormatException e) {
-                    throw new MalformedURLException(
-                        "Nonnumeric version: " + hostPortVers);
-                }
-                start = at + 1;  // skip '@' sign
-            }
-
-            // Parse host and port
-            int slash = hostPortVers.indexOf('/', start);
-            if (slash < 0) {
-                slash = hostPortVers.length();
-            }
-            if (hostPortVers.startsWith("[", start)) {  // at IPv6 literal
-                int brac = hostPortVers.indexOf(']', start + 1);
-                if (brac < 0 || brac > slash) {
-                    throw new IllegalArgumentException(
-                        "IiopURL: name is an Invalid URL: " + hostPortVers);
-                }
-
-                // include brackets
-                host = hostPortVers.substring(start, brac + 1);
-                start = brac + 1;
-            } else {      // at hostname or IPv4
-                int colon = hostPortVers.indexOf(':', start);
-                int hostEnd = (colon < 0 || colon > slash)
-                    ? slash
-                    : colon;
-                if (start < hostEnd) {
-                    host = hostPortVers.substring(start, hostEnd);
-                }
-                start = hostEnd;   // skip past host
-            }
-            if ((start + 1 < slash)) {
-                if ( hostPortVers.startsWith(":", start)) { // parse port
-                    start++;    // skip past ":"
-                    port = Integer.parseInt(hostPortVers.
-                                            substring(start, slash));
-                } else {
-                    throw new IllegalArgumentException(
-                        "IiopURL: name is an Invalid URL: " + hostPortVers);
-                }
-            }
-            start = slash;
-            if ("".equals(host) || host == null) {
-                host = DEFAULT_HOST ;
-            }
-            if (port == -1) {
-                port = (oldFormat ? DEFAULT_IIOP_PORT :
-                                DEFAULT_IIOPNAME_PORT);
-            }
-        }
-    }
-
-    public Vector<Address> getAddresses() {
-        return addresses;
-    }
-
-    /**
-     * Returns a possibly empty but non-null string that is the "string_name"
-     * portion of the URL.
-     */
-    public String getStringName() {
-        return stringName;
-    }
-
-    public Name getCosName() throws NamingException {
-        return CNCtx.parser.parse(stringName);
-    }
-
-    public IiopUrl(String url) throws MalformedURLException {
-        int addrStart;
-        boolean oldFormat;
-
-        if (url.startsWith("iiopname://")) {
-            oldFormat = false;
-            addrStart = 11;
-        } else if (url.startsWith("iiop://")) {
-            oldFormat = true;
-            addrStart = 7;
-        } else {
-            throw new MalformedURLException("Invalid iiop/iiopname URL: " + url);
-        }
-        int addrEnd = url.indexOf('/', addrStart);
-        if (addrEnd < 0) {
-            addrEnd = url.length();
-            stringName = "";
-        } else {
-            stringName = UrlUtil.decode(url.substring(addrEnd+1));
-        }
-        addresses = new Vector<>(3);
-        if (oldFormat) {
-            // Only one host:port part, not multiple
-            addresses.addElement(
-                new Address(url.substring(addrStart, addrEnd), oldFormat));
-        } else {
-            StringTokenizer tokens =
-                new StringTokenizer(url.substring(addrStart, addrEnd), ",");
-            while (tokens.hasMoreTokens()) {
-                addresses.addElement(new Address(tokens.nextToken(), oldFormat));
-            }
-            if (addresses.size() == 0) {
-                addresses.addElement(new Address("", oldFormat));
-            }
-        }
-    }
-
-    // for testing only
-    /*public static void main(String[] args) {
-        try {
-            IiopUrl url = new IiopUrl(args[0]);
-            Vector addrs = url.getAddresses();
-            String name = url.getStringName();
-
-            for (int i = 0; i < addrs.size(); i++) {
-                Address addr = (Address)addrs.elementAt(i);
-                System.out.println("host: " + addr.host);
-                System.out.println("port: " + addr.port);
-                System.out.println("version: " + addr.major + " " + addr.minor);
-            }
-            System.out.println("name: " + name);
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
-        }
-    } */
-}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java b/jdk/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java
deleted file mode 100644
index 122c9df..0000000
--- a/jdk/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jndi.toolkit.corba;
-
-// Needed for RMI/IIOP
-import java.rmi.Remote;
-
-import java.rmi.RemoteException;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.Enumeration;
-import java.applet.Applet;
-
-import org.omg.CORBA.ORB;
-
-import javax.naming.Context;
-import javax.naming.ConfigurationException;
-import javax.rmi.CORBA.Stub;
-import javax.rmi.PortableRemoteObject;
-
-/**
-  * Contains utilities for performing CORBA-related tasks:
-  * 1. Get the org.omg.CORBA.Object for a java.rmi.Remote object.
-  * 2. Create an ORB to use for a given host/port, and environment properties.
-  *
-  * @author Simon Nash
-  * @author Bryan Atsatt
-  */
-
-public class CorbaUtils {
-    /**
-      * Returns the CORBA object reference associated with a Remote
-      * object by using the javax.rmi.CORBA package.
-      *<p>
-      * This method effective does the following:
-      * <blockquote><pre>
-      * java.lang.Object stub;
-      * try {
-      *     stub = PortableRemoteObject.toStub(remoteObj);
-      * } catch (Exception e) {
-      *     throw new ConfigurationException("Object not exported or not found");
-      * }
-      * if (!(stub instanceof javax.rmi.CORBA.Stub)) {
-      *     return null; // JRMP impl or JRMP stub
-      * }
-      * try {
-      *     ((javax.rmi.CORBA.Stub)stub).connect(orb);  // try to connect IIOP stub
-      * } catch (RemoteException e) {
-      *     // ignore 'already connected' error
-      * }
-      * return (javax.rmi.CORBA.Stub)stub;
-      * </pre></blockquote>
-      *
-      * @param remoteObj The non-null remote object for
-      * @param orb       The non-null ORB to connect the remote object to
-      * @return The CORBA Object for remoteObj; null if {@code remoteObj}
-      *                 is a JRMP implementation or JRMP stub.
-      * @exception ConfigurationException The CORBA Object cannot be obtained
-      *         because of configuration problems.
-      */
-    public static org.omg.CORBA.Object remoteToCorba(Remote remoteObj, ORB orb)
-        throws ConfigurationException {
-
-// First, get remoteObj's stub
-
-            // javax.rmi.CORBA.Stub stub = PortableRemoteObject.toStub(remoteObj);
-
-            Remote stub;
-
-            try {
-                stub = PortableRemoteObject.toStub(remoteObj);
-            } catch (Throwable t) {
-                ConfigurationException ce = new ConfigurationException(
-    "Problem with PortableRemoteObject.toStub(); object not exported or stub not found");
-                ce.setRootCause(t);
-                throw ce;
-            }
-
-// Next, make sure that the stub is javax.rmi.CORBA.Stub
-
-            if (!(stub instanceof Stub)) {
-                return null;  // JRMP implementation or JRMP stub
-            }
-
-// Next, make sure that the stub is connected
-            try {
-                ((Stub) stub).connect(orb);
-            } catch (RemoteException e) {
-                // ignore RemoteException because stub might have already
-                // been connected
-            } catch (Throwable t) {
-                ConfigurationException ce = new ConfigurationException(
-                        "Problem invoking javax.rmi.CORBA.Stub.connect()");
-                ce.setRootCause(t);
-                throw ce;
-            }
-// Finally, return stub
-            return (org.omg.CORBA.Object)stub;
-    }
-
-    /**
-     * Get ORB using given server and port number, and properties from environment.
-     *
-     * @param server Possibly null server; if null means use default;
-     *               For applet, it is the applet host; for app, it is localhost.
-     * @param port   Port number, -1 means default port
-     * @param env    Possibly null environment. Contains environment properties.
-     *               Could contain ORB itself; or applet used for initializing ORB.
-     *               Use all String properties from env for initializing ORB
-     * @return A non-null ORB.
-     */
-    public static ORB getOrb(String server, int port, Hashtable<?,?> env) {
-        // See if we can get info from environment
-        Properties orbProp;
-
-        // Extract any org.omg.CORBA properties from environment
-        if (env != null) {
-            if (env instanceof Properties) {
-                // Already a Properties, just clone
-                orbProp = (Properties) env.clone();
-            } else {
-                // Get all String properties
-                Enumeration<?> envProp;
-                orbProp = new Properties();
-                for (envProp = env.keys(); envProp.hasMoreElements();) {
-                    String key = (String)envProp.nextElement();
-                    Object val = env.get(key);
-                    if (val instanceof String) {
-                        orbProp.put(key, val);
-                    }
-                }
-            }
-        } else {
-            orbProp = new Properties();
-        }
-
-        if (server != null) {
-            orbProp.put("org.omg.CORBA.ORBInitialHost", server);
-        }
-        if (port >= 0) {
-            orbProp.put("org.omg.CORBA.ORBInitialPort", ""+port);
-        }
-
-        // Get Applet from environment
-        if (env != null) {
-            @SuppressWarnings("deprecation")
-            Applet applet = (Applet) env.get(Context.APPLET);
-            if (applet != null) {
-            // Create ORBs using applet and orbProp
-                return ORB.init(applet, orbProp);
-            }
-        }
-
-        return ORB.init(new String[0], orbProp);
-    }
-}
diff --git a/jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java b/jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java
deleted file mode 100644
index 445fa49..0000000
--- a/jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jndi.url.iiop;
-
-import javax.naming.spi.ResolveResult;
-import javax.naming.*;
-import java.util.Hashtable;
-import java.net.MalformedURLException;
-
-import com.sun.jndi.cosnaming.IiopUrl;
-import com.sun.jndi.cosnaming.CorbanameUrl;
-
-/**
- * An IIOP URL context.
- *
- * @author Rosanna Lee
- */
-
-public class iiopURLContext
-        extends com.sun.jndi.toolkit.url.GenericURLContext {
-
-    iiopURLContext(Hashtable<?,?> env) {
-        super(env);
-    }
-
-    /**
-      * Resolves 'name' into a target context with remaining name.
-      * It only resolves the hostname/port number. The remaining name
-      * contains the rest of the name found in the URL.
-      *
-      * For example, with a iiop URL "iiop://localhost:900/rest/of/name",
-      * this method resolves "iiop://localhost:900/" to the "NameService"
-      * context on for the ORB at 'localhost' on port 900,
-      * and returns as the remaining name "rest/of/name".
-      */
-    protected ResolveResult getRootURLContext(String name, Hashtable<?,?> env)
-    throws NamingException {
-        return iiopURLContextFactory.getUsingURLIgnoreRest(name, env);
-    }
-
-    /**
-     * Return the suffix of an "iiop", "iiopname", or "corbaname" url.
-     * prefix parameter is ignored.
-     */
-    protected Name getURLSuffix(String prefix, String url)
-        throws NamingException {
-        try {
-            if (url.startsWith("iiop://") || url.startsWith("iiopname://")) {
-                IiopUrl parsedUrl = new IiopUrl(url);
-                return parsedUrl.getCosName();
-            } else if (url.startsWith("corbaname:")) {
-                CorbanameUrl parsedUrl = new CorbanameUrl(url);
-                return parsedUrl.getCosName();
-            } else {
-                throw new MalformedURLException("Not a valid URL: " + url);
-            }
-        } catch (MalformedURLException e) {
-            throw new InvalidNameException(e.getMessage());
-        }
-    }
-}
diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java
index 36e703e..7aaf089 100644
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java
@@ -34,10 +34,18 @@
 
 import sun.lwawt.macosx.LWCToolkit;
 import sun.security.action.GetBooleanAction;
-import sun.security.action.GetPropertyAction;
 
 // MenuBar implementation for Mac L&F
 public class AquaMenuBarUI extends BasicMenuBarUI implements ScreenMenuBarProvider {
+
+    static {
+        java.security.AccessController.doPrivileged(
+                (java.security.PrivilegedAction<Void>) () -> {
+            System.loadLibrary("osxui");
+            return null;
+        });
+    }
+
     // Utilities
     public void uninstallUI(final JComponent c) {
         if (fScreenMenuBar != null) {
@@ -134,7 +142,7 @@
     ScreenMenuBar fScreenMenuBar;
     boolean useScreenMenuBar = getScreenMenuBarProperty();
 
-    static boolean getScreenMenuBarProperty() {
+    public static boolean getScreenMenuBarProperty() {
         // Do not allow AWT to set the screen menu bar if it's embedded in another UI toolkit
         if (LWCToolkit.isEmbedded()) return false;
         if (AccessController.doPrivileged(
diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java
index 0c505b2..45f4832 100644
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java
@@ -141,12 +141,24 @@
         }
     }
 
-    protected void registerFontsInDir(String dirName, boolean useJavaRasterizer, int fontRank, boolean defer, boolean resolveSymLinks) {
-        loadNativeDirFonts(dirName);
+    protected void registerFontsInDir(final String dirName, boolean useJavaRasterizer,
+                                      int fontRank, boolean defer, boolean resolveSymLinks) {
+
+        String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () -> {
+            return new File(dirName).list(getTrueTypeFilter());
+        });
+
+        if (files == null) {
+           return;
+        } else {
+            for (String f : files) {
+                loadNativeDirFonts(dirName+File.separator+f);
+            }
+        }
         super.registerFontsInDir(dirName, useJavaRasterizer, fontRank, defer, resolveSymLinks);
     }
 
-    private native void loadNativeDirFonts(String dirName);
+    private native void loadNativeDirFonts(String fontPath);
     private native void loadNativeFonts();
 
     void registerFont(String fontName, String fontFamilyName) {
diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
index d93b4bb..d0c8275 100644
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
@@ -33,11 +33,14 @@
 import java.awt.event.*;
 import java.beans.*;
 import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
 
 import javax.swing.*;
 
 import sun.awt.*;
 import sun.awt.AWTAccessor.ComponentAccessor;
+import sun.awt.AWTAccessor.WindowAccessor;
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLSurfaceData;
 import sun.lwawt.*;
@@ -1031,6 +1034,11 @@
         return !peer.isSimpleWindow() && target.getFocusableWindowState();
     }
 
+    private boolean isBlocked() {
+        LWWindowPeer blocker = (peer != null) ? peer.getBlocker() : null;
+        return (blocker != null);
+    }
+
     /*
      * An utility method for the support of the auto request focus.
      * Updates the focusable state of the window under certain
@@ -1063,29 +1071,70 @@
         return true;
     }
 
+    private boolean isOneOfOwnersOrSelf(CPlatformWindow window) {
+        while (window != null) {
+            if (this == window) {
+                return true;
+            }
+            window = window.owner;
+        }
+        return false;
+    }
+
+    private CPlatformWindow getRootOwner() {
+        CPlatformWindow rootOwner = this;
+        while (rootOwner.owner != null) {
+            rootOwner = rootOwner.owner;
+        }
+        return rootOwner;
+    }
+
     private void orderAboveSiblings() {
-        if (owner == null) {
-            return;
+        // Recursively pop up the windows from the very bottom, (i.e. root owner) so that
+        // the windows are ordered above their nearest owner; ancestors of the window,
+        // which is going to become 'main window', are placed above their siblings.
+        CPlatformWindow rootOwner = getRootOwner();
+        if (rootOwner.isVisible()) {
+            CWrapper.NSWindow.orderFront(rootOwner.getNSWindowPtr());
         }
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+        orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target));
+    }
 
-        // NOTE: the logic will fail if we have a hierarchy like:
-        //       visible root owner
-        //          invisible owner
-        //              visible dialog
-        // However, this is an unlikely scenario for real life apps
-        if (owner.isVisible()) {
-            // Recursively pop up the windows from the very bottom so that only
-            // the very top-most one becomes the main window
-            owner.orderAboveSiblings();
+    private void orderAboveSiblingsImpl(Window[] windows) {
+        ArrayList<Window> childWindows = new ArrayList<Window>();
 
-            // Order the window to front of the stack of child windows
-            final long nsWindowSelfPtr = getNSWindowPtr();
-            final long nsWindowOwnerPtr = owner.getNSWindowPtr();
-            CWrapper.NSWindow.orderFront(nsWindowOwnerPtr);
-            CWrapper.NSWindow.orderWindow(nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove, nsWindowOwnerPtr);
+        final ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+
+        // Go through the list of windows and perform ordering.
+        for (Window w : windows) {
+            final Object p = componentAccessor.getPeer(w);
+            if (p instanceof LWWindowPeer) {
+                CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
+                if (pw != null && pw.isVisible()) {
+                    // If the window is one of ancestors of 'main window' or is going to become main by itself,
+                    // the window should be ordered above its siblings; otherwise the window is just ordered
+                    // above its nearest parent.
+                    if (pw.isOneOfOwnersOrSelf(this)) {
+                        CWrapper.NSWindow.orderFront(pw.getNSWindowPtr());
+                    } else {
+                        CWrapper.NSWindow.orderWindow(pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove,
+                                pw.owner.getNSWindowPtr());
+                    }
+                    pw.applyWindowLevel(w);
+                }
+            }
+            // Retrieve the child windows for each window from the list and store them for future use.
+            // Note: we collect data about child windows even for invisible owners, since they may have
+            // visible children.
+            childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w)));
         }
-
-        applyWindowLevel(target);
+        // If some windows, which have just been ordered, have any child windows, let's start new iteration
+        // and order these child windows.
+        if (!childWindows.isEmpty()) {
+            orderAboveSiblingsImpl(childWindows.toArray(new Window[0]));
+        }
     }
 
     protected void applyWindowLevel(Window target) {
diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
index 309bc8c..9c46300 100644
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
@@ -25,6 +25,7 @@
 
 package sun.lwawt.macosx;
 
+import com.apple.laf.AquaMenuBarUI;
 import java.awt.peer.TaskbarPeer;
 import java.awt.*;
 import java.awt.datatransfer.Clipboard;
@@ -43,6 +44,7 @@
 import java.util.*;
 import java.util.concurrent.Callable;
 import java.net.MalformedURLException;
+import javax.swing.UIManager;
 
 import sun.awt.*;
 import sun.awt.datatransfer.DataTransferer;
@@ -935,4 +937,13 @@
     protected PlatformWindow getPlatformWindowUnderMouse() {
         return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse();
     }
+
+    @Override
+    public void updateScreenMenuBarUI() {
+        if (AquaMenuBarUI.getScreenMenuBarProperty())  {
+            UIManager.put("MenuBarUI", "com.apple.laf.AquaMenuBarUI");
+        } else {
+            UIManager.put("MenuBarUI", null);
+        }
+    }
 }
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m
index 8b76294..ca983d0 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m
@@ -430,7 +430,22 @@
     [super dealloc];
 }
 
-// Tests wheather the corresponding Java paltform window is visible or not
+// Tests whether window is blocked by modal dialog/window
+- (BOOL) isBlocked {
+    BOOL isBlocked = NO;
+    
+    JNIEnv *env = [ThreadUtilities getJNIEnv];
+    jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+    if (platformWindow != NULL) {
+        static JNF_MEMBER_CACHE(jm_isBlocked, jc_CPlatformWindow, "isBlocked", "()Z");
+        isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
+        (*env)->DeleteLocalRef(env, platformWindow);
+    }
+    
+    return isBlocked;
+}
+
+// Tests whether the corresponding Java platform window is visible or not
 + (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window {
     BOOL isVisible = NO;
 
@@ -454,8 +469,9 @@
 - (void) orderChildWindows:(BOOL)focus {
 AWT_ASSERT_APPKIT_THREAD;
 
-    if (self.isMinimizing) {
+    if (self.isMinimizing || [self isBlocked]) {
         // Do not perform any ordering, if iconify is in progress
+        // or the window is blocked by a modal window
         return;
     }
 
@@ -809,18 +825,20 @@
 
 - (void)sendEvent:(NSEvent *)event {
         if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
-            // Move parent windows to front and make sure that a child window is displayed
-            // in front of its nearest parent.
-            if (self.ownerWindow != nil) {
-                JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
-                jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
-                if (platformWindow != NULL) {
-                    static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
-                    JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
-                    (*env)->DeleteLocalRef(env, platformWindow);
+            if ([self isBlocked]) {
+                // Move parent windows to front and make sure that a child window is displayed
+                // in front of its nearest parent.
+                if (self.ownerWindow != nil) {
+                    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
+                    jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+                    if (platformWindow != NULL) {
+                        static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
+                        JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
+                        (*env)->DeleteLocalRef(env, platformWindow);
+                    }
                 }
+                [self orderChildWindows:YES];
             }
-            [self orderChildWindows:YES];
 
             NSPoint p = [NSEvent mouseLocation];
             NSRect frame = [self.nsWindow frame];
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m
index ac82ca8..bcf7893 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m
@@ -115,19 +115,18 @@
             if (keyWindow != nil) {
                 return;
             }
-        }
-        else {
-            static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
-            static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
-            
-            NSUInteger modifiers = [currEvent modifierFlags];
-            jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
-            
-            JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
-        }
+		}
+		
+        static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
+        static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
+
+        NSUInteger modifiers = [currEvent modifierFlags];
+        jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
+
+        JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
     }
     JNF_COCOA_EXIT(env);
-    
+	
 }
 
 - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m
index d374e5a..bca2102 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m
@@ -404,19 +404,14 @@
 {
 JNF_COCOA_ENTER(env);
 
-    NSString *nsFilePath = JNFJavaToNSString(env, filename);
-
-    FSRef iFile;
-    OSStatus status = CreateFSRef(&iFile, nsFilePath);
-
-    if (status == noErr) {
-        ATSFontContainerRef oContainer;
-        status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal,
-                                                  kATSFontFormatUnspecified,
-                                                  NULL, kNilOptions,
-                                                  &oContainer);
-    }
-
+    NSString *path = JNFJavaToNSString(env, filename);
+    NSURL *url = [NSURL fileURLWithPath:(NSString *)path];
+    bool res = CTFontManagerRegisterFontsForURL((CFURLRef)url, kCTFontManagerScopeProcess, nil);
+#ifdef DEBUG
+    NSLog(@"path is : %@", (NSString*)path);
+    NSLog(@"url is : %@", (NSString*)url);
+    printf("res is %d\n", res);
+#endif
 JNF_COCOA_EXIT(env);
 }
 
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
index 79cdf5b..1d9269f 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m
@@ -591,7 +591,7 @@
 static inline GlyphInfo *
 CGGI_CreateImageForUnicode
     (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
-     const CGGI_RenderingMode *mode, const UniChar uniChar)
+     const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar)
 {
     // save the state of the world
     CGContextSaveGState(canvas->context);
@@ -668,7 +668,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jlong glyphInfos[],
-                                        const UniChar uniChars[],
+                                        const UnicodeScalarValue uniChars[],
                                         const CGGlyph glyphs[],
                                         const CFIndex len)
 {
@@ -720,7 +720,7 @@
 static inline void
 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
                          const CGGI_RenderingMode *mode,
-                         const UniChar uniChars[], const CGGlyph glyphs[],
+                         const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                          const size_t maxWidth, const size_t maxHeight,
                          const CFIndex len)
 {
@@ -767,7 +767,7 @@
 static inline void
 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
                       const CGGI_RenderingMode *mode,
-                      const UniChar uniChars[], const CGGlyph glyphs[],
+                      const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 {
     AWTFont *font = strike->fAWTFont;
@@ -817,7 +817,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jint rawGlyphCodes[],
-                                        UniChar uniChars[], CGGlyph glyphs[],
+                                        UnicodeScalarValue uniChars[], CGGlyph glyphs[],
                                         CGSize advances[], CGRect bboxes[],
                                         const CFIndex len)
 {
@@ -860,7 +860,7 @@
         CGRect bboxes[len];
         CGSize advances[len];
         CGGlyph glyphs[len];
-        UniChar uniChars[len];
+        UnicodeScalarValue uniChars[len];
 
         CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                                 rawGlyphCodes, uniChars, glyphs,
@@ -871,7 +871,7 @@
 
     // just do one malloc, and carve it up for all the buffers
     void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
-                          sizeof(CGGlyph) * sizeof(UniChar) * len);
+                          sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
     if (buffer == NULL) {
         [[NSException exceptionWithName:NSMallocException
             reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
@@ -880,7 +880,7 @@
     CGRect *bboxes = (CGRect *)(buffer);
     CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
     CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
-    UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
+    UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
 
     CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                             rawGlyphCodes, uniChars, glyphs,
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h
index a0ede94..cbd3dc5 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h
@@ -32,7 +32,9 @@
 #pragma mark --- CoreText Support ---
 
 #define HI_SURROGATE_START 0xD800
+#define HI_SURROGATE_END   0xDBFF
 #define LO_SURROGATE_START 0xDC00
+#define LO_SURROGATE_END   0xDFFF
 
 /*
  *    Transform Unicode characters into glyphs.
diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m
index 1bcd9f5..5663b30 100644
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m
@@ -103,24 +103,34 @@
 
     size_t i;
     for (i = 0; i < count; i++) {
+        UniChar unicode = unicodes[i];
+        UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
+        bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
+                             && nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
+
         CGGlyph glyph = glyphs[i];
         if (glyph > 0) {
             glyphsAsInts[i] = glyph;
+            if (surrogatePair) i++;
             continue;
         }
 
-        UniChar unicode = unicodes[i];
-        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
+        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicodes[i],
+                                                                          surrogatePair ? 2 : 1);
         if (fallback) {
-            CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
+            CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
+            glyph = glyphs[i];
             CFRelease(fallback);
         }
 
         if (glyph > 0) {
-            glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
+            int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
+                                            + nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
+            glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
         } else {
             glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
         }
+        if (surrogatePair) i++;
     }
 }
 
@@ -158,8 +168,18 @@
         return (CTFontRef)font->fFont;
     }
 
-    UTF16Char character = -glyphCode;
-    return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    int codePoint = -glyphCode;
+    if (codePoint >= 0x10000) {
+        UTF16Char chars[2];
+        CGGlyph glyphs[2];
+        CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
+        CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
+        *glyphRef = glyphs[0];
+        return result;
+    } else {
+        UTF16Char character = codePoint;
+        return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    }
 }
 
 // Breakup a 32 bit unicode value into the component surrogate pairs
diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
index 1c194fb..2b94d15 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java
@@ -541,10 +541,10 @@
     }
 
     // Stream position initially at beginning, left at end
-    // if ignoreUnknownFields is true, do not load fields for which
+    // if readUnknownTags is false, do not load fields for which
     // a tag cannot be found in an allowed TagSet.
     public void initialize(ImageInputStream stream, boolean isPrimaryIFD,
-        boolean ignoreUnknownFields) throws IOException {
+        boolean ignoreMetadata, boolean readUnknownTags) throws IOException {
 
         removeTIFFFields();
 
@@ -553,10 +553,16 @@
 
         List<TIFFTagSet> tagSetList = getTagSetList();
 
+        // Configure essential tag variables if this is the primary IFD and
+        // either all metadata are being ignored, or metadata are not being
+        // ignored but both unknown tags are being ignored and the tag set
+        // list does not contain the baseline tags.
         boolean ensureEssentialTags = false;
         TIFFTagSet baselineTagSet = null;
-        if (isPrimaryIFD && ignoreUnknownFields
-            && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) {
+        if (isPrimaryIFD &&
+            (ignoreMetadata ||
+             (!readUnknownTags &&
+              !tagSetList.contains(BaselineTIFFTagSet.getInstance())))) {
             ensureEssentialTags = true;
             initializeEssentialTags();
             baselineTagSet = BaselineTIFFTagSet.getInstance();
@@ -590,9 +596,12 @@
                 tag = baselineTagSet.getTag(tagNumber);
             }
 
-            // Ignore unknown fields, fields with unknown type, and fields
+            // Ignore non-essential fields, unknown fields unless forcibly
+            // being read, fields with unknown type, and fields
             // with count out of int range.
-            if((tag == null && ignoreUnknownFields)
+            if((ignoreMetadata &&
+                (!ensureEssentialTags || !essentialTags.contains(tagNumber)))
+                || (tag == null && !readUnknownTags)
                 || (tag != null && !tag.isDataTypeOK(type))
                 || longCount > Integer.MAX_VALUE) {
                 // Skip the value/offset so as to leave the stream
@@ -701,7 +710,8 @@
                     tagSets.add(tag.getTagSet());
                     TIFFIFD subIFD = new TIFFIFD(tagSets);
 
-                    subIFD.initialize(stream, false, ignoreUnknownFields);
+                    subIFD.initialize(stream, false, ignoreMetadata,
+                                      readUnknownTags);
                     TIFFField f = new TIFFField(tag, type, e.offset, subIFD);
                     addTIFFField(f);
                 } else {
diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
index a145531..ef68d13 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
@@ -82,12 +82,13 @@
     }
 
     public void initializeFromStream(ImageInputStream stream,
-                                     boolean ignoreUnknownFields)
+                                     boolean ignoreMetadata,
+                                     boolean readUnknownTags)
         throws IOException {
-        rootIFD.initialize(stream, true, ignoreUnknownFields);
+        rootIFD.initialize(stream, true, ignoreMetadata, readUnknownTags);
     }
 
-    public void addShortOrLongField(int tagNumber, int value) {
+    public void addShortOrLongField(int tagNumber, long value) {
         TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value);
         rootIFD.addTIFFField(field);
     }
diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
index 91778e7..3ccc3cd 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java
@@ -305,16 +305,19 @@
         try {
             // Create an object to store the image metadata
             List<TIFFTagSet> tagSets;
+            boolean readUnknownTags = false;
             if (imageReadParam instanceof TIFFImageReadParam) {
-                tagSets
-                        = ((TIFFImageReadParam) imageReadParam).getAllowedTagSets();
+                TIFFImageReadParam tp = (TIFFImageReadParam)imageReadParam;
+                tagSets = tp.getAllowedTagSets();
+                readUnknownTags = tp.getReadUnknownTags();
             } else {
                 tagSets = new ArrayList<TIFFTagSet>(1);
                 tagSets.add(BaselineTIFFTagSet.getInstance());
             }
 
             this.imageMetadata = new TIFFImageMetadata(tagSets);
-            imageMetadata.initializeFromStream(stream, ignoreMetadata);
+            imageMetadata.initializeFromStream(stream, ignoreMetadata,
+                                               readUnknownTags);
         } catch (IIOException iioe) {
             throw iioe;
         } catch (IOException ioe) {
diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
index 8e0942d..6d27c01 100644
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
@@ -3015,7 +3015,7 @@
         List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(1);
         tagSets.add(BaselineTIFFTagSet.getInstance());
         TIFFIFD rootIFD = new TIFFIFD(tagSets);
-        rootIFD.initialize(stream, true, true);
+        rootIFD.initialize(stream, true, false, false);
         stream.reset();
 
         return rootIFD;
diff --git a/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java b/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java
index 470ad9a..f966a76 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,17 +22,24 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.awt.peer.CheckboxMenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
-import java.io.ObjectOutputStream;
-import java.io.ObjectInputStream;
 import java.io.IOException;
-import javax.accessibility.*;
-import sun.awt.AWTAccessor;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EventListener;
 
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
+import sun.awt.AWTAccessor;
 
 /**
  * This class represents a check box that can be included in a menu.
@@ -43,7 +50,8 @@
  * of {@code CheckBoxMenuItem}:
  * <p>
  * <img src="doc-files/MenuBar-1.gif"
- * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
+ * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More
+ * Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
  * style="float:center; margin: 7px 10px;">
  * <p>
  * The item labeled {@code Check} shows a check box menu item
@@ -84,9 +92,9 @@
     * @see #getState()
     * @see #setState(boolean)
     */
-    boolean state = false;
+    private volatile boolean state;
 
-    transient ItemListener itemListener;
+    private transient volatile ItemListener itemListener;
 
     private static final String base = "chkmenuitem";
     private static int nameCounter = 0;
diff --git a/jdk/src/java.desktop/share/classes/java/awt/Menu.java b/jdk/src/java.desktop/share/classes/java/awt/Menu.java
index 70b5ee1..4bd1bba 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/Menu.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/Menu.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,15 +22,20 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuPeer;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.util.Vector;
 import java.util.Enumeration;
-import java.awt.peer.MenuPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
+import java.util.Vector;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
 import sun.awt.AWTAccessor;
 
 /**
@@ -78,7 +83,7 @@
      * @serial
      * @see #countItems()
      */
-    Vector<MenuItem> items = new Vector<>();
+    private final Vector<MenuItem> items = new Vector<>();
 
     /**
      * This field indicates whether the menu has the
@@ -92,7 +97,7 @@
      * @serial
      * @see #isTearOff()
      */
-    boolean             tearOff;
+    private final boolean tearOff;
 
     /**
      * This field will be set to {@code true}
@@ -102,7 +107,7 @@
      *
      * @serial
      */
-    boolean             isHelpMenu;
+    volatile boolean isHelpMenu;
 
     private static final String base = "menu";
     private static int nameCounter = 0;
@@ -415,8 +420,8 @@
             if (peer != null) {
                 peer.delItem(index);
                 mi.removeNotify();
-                mi.parent = null;
             }
+            mi.parent = null;
         }
     }
 
diff --git a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java
index 4a57b0d..8d0d51d 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,16 +22,21 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuBarPeer;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.util.Vector;
 import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
 import sun.awt.AWTAccessor;
-import java.awt.peer.MenuBarPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
 
 /**
  * The {@code MenuBar} class encapsulates the platform's
@@ -94,7 +99,7 @@
      * @serial
      * @see #countMenus()
      */
-    Vector<Menu> menus = new Vector<>();
+    private final Vector<Menu> menus = new Vector<>();
 
     /**
      * This menu is a special menu dedicated to
@@ -106,7 +111,7 @@
      * @see #getHelpMenu()
      * @see #setHelpMenu(Menu)
      */
-    Menu helpMenu;
+    private volatile Menu helpMenu;
 
     private static final String base = "menubar";
     private static int nameCounter = 0;
@@ -252,8 +257,8 @@
             if (peer != null) {
                 peer.delMenu(index);
                 m.removeNotify();
-                m.parent = null;
             }
+            m.parent = null;
             if (helpMenu == m) {
                 helpMenu = null;
                 m.isHelpMenu = false;
diff --git a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java
index c609739..fb3c72c 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,21 +22,28 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
-import java.awt.peer.MenuComponentPeer;
 import java.awt.event.ActionEvent;
+import java.awt.peer.MenuComponentPeer;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import sun.awt.AppContext;
-import sun.awt.AWTAccessor;
-import sun.awt.ComponentFactory;
-
-import javax.accessibility.*;
-
 import java.security.AccessControlContext;
 import java.security.AccessController;
 
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleComponent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+
+import sun.awt.AWTAccessor;
+import sun.awt.AppContext;
+import sun.awt.ComponentFactory;
+
 /**
  * The abstract class {@code MenuComponent} is the superclass
  * of all menu-related components. In this respect, the class
@@ -60,13 +67,13 @@
     }
 
     transient volatile MenuComponentPeer peer;
-    transient MenuContainer parent;
+    transient volatile MenuContainer parent;
 
     /**
      * The {@code AppContext} of the {@code MenuComponent}.
      * This is set in the constructor and never changes.
      */
-    transient AppContext appContext;
+    private transient volatile AppContext appContext;
 
     /**
      * The menu component's font. This value can be
@@ -77,7 +84,7 @@
      * @see #setFont(Font)
      * @see #getFont()
      */
-    volatile Font font;
+    private volatile Font font;
 
     /**
      * The menu component's name, which defaults to {@code null}.
@@ -85,7 +92,7 @@
      * @see #getName()
      * @see #setName(String)
      */
-    private String name;
+    private volatile String name;
 
     /**
      * A variable to indicate whether a name is explicitly set.
@@ -94,14 +101,14 @@
      * @serial
      * @see #setName(String)
      */
-    private boolean nameExplicitlySet = false;
+    private volatile boolean nameExplicitlySet;
 
     /**
      * Defaults to {@code false}.
      * @serial
      * @see #dispatchEvent(AWTEvent)
      */
-    boolean newEventsOnly = false;
+    volatile boolean newEventsOnly;
 
     /*
      * The menu's AccessControlContext.
diff --git a/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java b/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java
index 3a70fe2..e0611cc 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,15 +22,25 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
 import java.awt.peer.MenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
-import java.io.ObjectOutputStream;
-import java.io.ObjectInputStream;
 import java.io.IOException;
-import javax.accessibility.*;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EventListener;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
 import sun.awt.AWTAccessor;
 
 /**
@@ -111,7 +121,7 @@
      * @see #isEnabled()
      * @see #setEnabled(boolean)
      */
-    boolean enabled = true;
+    private volatile boolean enabled = true;
 
     /**
      * {@code label} is the label of a menu item.
@@ -121,7 +131,7 @@
      * @see #getLabel()
      * @see #setLabel(String)
      */
-    String label;
+    volatile String label;
 
     /**
      * This field indicates the command that has been issued
@@ -134,7 +144,7 @@
      * @see #setActionCommand(String)
      * @see #getActionCommand()
      */
-    String actionCommand;
+    private volatile String actionCommand;
 
     /**
      * The eventMask is ONLY set by subclasses via enableEvents.
@@ -144,9 +154,9 @@
      *
      * @serial
      */
-    long eventMask;
+    volatile long eventMask;
 
-    transient ActionListener actionListener;
+    private transient volatile ActionListener actionListener;
 
     /**
      * A sequence of key stokes that ia associated with
@@ -160,7 +170,7 @@
      * @see #setShortcut(MenuShortcut)
      * @see #deleteShortcut()
      */
-    private MenuShortcut shortcut = null;
+    private volatile MenuShortcut shortcut;
 
     private static final String base = "menuitem";
     private static int nameCounter = 0;
diff --git a/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java b/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java
index 253351f..4846074 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,9 @@
 package java.awt;
 
 import java.awt.peer.PopupMenuPeer;
-import javax.accessibility.*;
 
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
 
 import sun.awt.AWTAccessor;
 
@@ -48,7 +49,7 @@
     private static final String base = "popup";
     static int nameCounter = 0;
 
-    transient boolean isTrayIconPopup = false;
+    transient volatile boolean isTrayIconPopup;
 
     static {
         AWTAccessor.setPopupMenuAccessor(
diff --git a/jdk/src/java.desktop/share/classes/java/awt/Window.java b/jdk/src/java.desktop/share/classes/java/awt/Window.java
index ed7d63a..8d122be 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/Window.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java
@@ -4122,6 +4122,10 @@
             public void setTrayIconWindow(Window w, boolean isTrayIconWindow) {
                 w.isTrayIconWindow = isTrayIconWindow;
             }
+
+            public Window[] getOwnedWindows(Window w) {
+                return w.getOwnedWindows_NoClientCode();
+            }
         }); // WindowAccessor
     } // static
 
diff --git a/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java b/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java
index 7d85854..63ceb3f 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java
@@ -279,7 +279,7 @@
     }
 
     /**
-     * Sets the cursor for this drag operation to the specified
+     * Sets the custom cursor for this drag operation to the specified
      * {@code Cursor}.  If the specified {@code Cursor}
      * is {@code null}, the default drag cursor behavior is
      * activated for this drag operation, otherwise it is deactivated.
@@ -298,9 +298,11 @@
     }
 
     /**
-     * Returns the current drag {@code Cursor}.
+     * Returns the current custom drag {@code Cursor}.
      *
-     * @return the current drag {@code Cursor}
+     * @return the current custom drag {@code Cursor}, if it was set
+     *         otherwise returns {@code null}.
+     * @see #setCursor
      */
 
     public Cursor getCursor() { return cursor; }
diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java b/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java
index 9d190a9..89c4387 100644
--- a/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java
+++ b/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java
@@ -64,27 +64,71 @@
 public abstract class AbstractMultiResolutionImage extends java.awt.Image
         implements MultiResolutionImage {
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getWidth(observer)}.
+     *
+     * @return the width of the base image, or -1 if the width is not yet known
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public int getWidth(ImageObserver observer) {
         return getBaseImage().getWidth(observer);
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getHeight(observer)}.
+     *
+     * @return the height of the base image, or -1 if the height is not yet known
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public int getHeight(ImageObserver observer) {
         return getBaseImage().getHeight(observer);
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getSource()}.
+     *
+     * @return the image producer that produces the pixels for the base image
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public ImageProducer getSource() {
         return getBaseImage().getSource();
     }
 
+    /**
+     * As per the contract of the base {@code Image#getGraphics()} method,
+     * this implementation will always throw {@code UnsupportedOperationException}
+     * since only off-screen images can return a {@code Graphics} object.
+     *
+     * @return throws {@code UnsupportedOperationException}
+     * @throws UnsupportedOperationException this method is not supported
+     */
     @Override
     public Graphics getGraphics() {
         throw new UnsupportedOperationException("getGraphics() not supported"
                 + " on Multi-Resolution Images");
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getProperty(name, observer)}.
+     *
+     * @return the value of the named property in the base image
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public Object getProperty(String name, ImageObserver observer) {
         return getBaseImage().getProperty(name, observer);
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
index 2fc49cf..5cff365 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html
@@ -216,22 +216,27 @@
 
 <h4><a name="MetadataIssuesRead"/>Metadata Issues</h4>
 
-By default all fields in the TIFF image file directory (IFD) are loaded into
-the native image metadata object. In cases where the IFD includes fields which
-contain large amounts of data this could be very inefficient. Which fields
-are loaded may be controlled by setting which TIFF tags the reader is allowed
-to recognize and whether it is ignoring metadata. The reader is informed to
-disregard metadata as usual via the <code>ignoreMetadata</code> parameter of
+By default all recognized fields in the TIFF image file directory (IFD) are
+loaded into the native image metadata object. Which fields are loaded may be
+controlled by setting which TIFF tags the reader is allowed to recognize,
+whether to read fields with unrecognized tags, and whether to ignore all
+metadata. The reader is informed to disregard all metadata as usual via the
+<code>ignoreMetadata</code> parameter of
 <code>ImageReader.setInput(Object,boolean,boolean)</code>. It is
 informed of which <a href="../../plugins/tiff/TIFFTag.html">TIFFTag</a>s to
 recognize or not to recognize via
-<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code>
-and
+<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code> and
 <code>TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet)</code>.
-If <code>ignoreMetadata</code> is <code>true</code>, then the reader will
-load into the native image metadata object only those fields which have a
-<code>TIFFTag</code> contained in the one of the allowed
-<code>TIFFTagSet</code>s.
+If <code>ignoreMetadata</code> is <code>true</code>, then only metadata
+essential to reading the image will be loaded into the native image metadata
+object. If <code>ignoreMetadata</code> is <code>false</code>, then the reader
+will by default load into the native image metadata object only those fields
+which are either essential to reading the image or have a <code>TIFFTag</code>
+contained in the one of the allowed <code>TIFFTagSet</code>s. Reading of
+fields with tags not in the allowed <code>TIFFTagSet</code>s may be forced
+by passing in a <code>TIFFImageReadParam</code> on which
+<code>TIFFImageReadParam.setReadUnknownTags(boolean)</code> has been
+invoked with parameter <code>true</code>.
 
 <p>Use of a <a href="../../plugins/tiff/TIFFDirectory.html">TIFFDirectory</a>
 object may simplify gaining access to metadata values. An instance of
@@ -534,7 +539,7 @@
 <tr>
 <td>ZLib</td>
 <td>"Deflate/Inflate" compression (see note following this table)</td>
-<td><a href="http://partners.adobe.com/asn/developer/pdfs/tn/TIFFphotoshop.pdf">
+<td><a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf">
 Adobe Photoshop&#174; TIFF Technical Notes</a> (PDF)</td>
 </tr>
 <tr>
@@ -545,9 +550,9 @@
 <tr>
 <td>Deflate</td>
 <td>"Zip-in-TIFF" compression (see note following this table)</td>
-<td><a href="http://www.isi.edu/in-notes/rfc1950.txt">
+<td><a href="https://tools.ietf.org/html/rfc1950">
 ZLIB Compressed Data Format Specification</a>,
-<a href="http://www.isi.edu/in-notes/rfc1951.txt">
+<a href="https://tools.ietf.org/html/rfc1951">
 DEFLATE Compressed Data Format Specification</a></td>
 </tr>
 <tr>
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java
index 8c9ce8e..d618199 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java
@@ -224,7 +224,7 @@
      * A value to be used with the "Compression" tag.
      *
      * @see #TAG_COMPRESSION
-     * @see <a href="http://www.isi.edu/in-notes/rfc1951.txt">DEFLATE specification</a>
+     * @see <a href="https://tools.ietf.org/html/rfc1951">DEFLATE specification</a>
      * @see <a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf"> TIFF Specification Supplement 2</a>
      */
     public static final int COMPRESSION_DEFLATE = 32946;
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java
index 3ecfe50..0788843 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java
@@ -29,7 +29,7 @@
 
 /**
  * A class representing the extra tags found in a
- * <a href="http://tools.ietf.org/html/rfc2306"> TIFF-F</a> (RFC 2036) file.
+ * <a href="http://tools.ietf.org/html/rfc2306.html">TIFF-F</a> (RFC 2036) file.
  *
  * @since 9
  */
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java
index 4f77c29..18962ed 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java
@@ -30,10 +30,7 @@
 /**
  * A class representing the tags found in a GeoTIFF IFD.  GeoTIFF is a
  * standard for annotating georeferenced or geocoded raster imagery.
- * The GeoTIFF specification may be found at <a
- * href="http://www.remotesensing.org/geotiff/spec/geotiffhome.html">
- * {@code http://www.remotesensing.org/geotiff/spec/geotiffhome.html}
- * </a>. This class does <i>not</i> handle the <i>GeoKey</i>s referenced
+ * This class does <i>not</i> handle the <i>GeoKey</i>s referenced
  * from a <i>GeoKeyDirectoryTag</i> as those are not TIFF tags per se.
  *
  * <p>The definitions of the data types referenced by the field
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java
index 8ac2316..b36406b 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java
@@ -263,14 +263,16 @@
  */
 public final class TIFFField implements Cloneable {
 
-    private static final String[] typeNames = {
+    private static final long MAX_UINT32 = 0xffffffffL;
+
+    private static final String[] TYPE_NAMES = {
         null,
         "Byte", "Ascii", "Short", "Long", "Rational",
         "SByte", "Undefined", "SShort", "SLong", "SRational",
         "Float", "Double", "IFDPointer"
     };
 
-    private static final boolean[] isIntegral = {
+    private static final boolean[] IS_INTEGRAL = {
         false,
         true, false, true, true, false,
         true, true, true, true, false,
@@ -544,6 +546,9 @@
      * @throws IllegalArgumentException if {@code data} is an instance of
      * a class incompatible with the specified type.
      * @throws IllegalArgumentException if the size of the data array is wrong.
+     * @throws IllegalArgumentException if the type of the data array is
+     * {@code TIFF_LONG}, {@code TIFF_RATIONAL}, or {@code TIFF_IFD_POINTER}
+     * and any of the elements is negative or greater than {@code 0xffffffff}.
      */
     public TIFFField(TIFFTag tag, int type, int count, Object data) {
         if(tag == null) {
@@ -587,15 +592,50 @@
         case TIFFTag.TIFF_LONG:
             isDataArrayCorrect = data instanceof long[]
                 && ((long[])data).length == count;
+            if (isDataArrayCorrect) {
+                for (long datum : (long[])data) {
+                    if (datum < 0) {
+                        throw new IllegalArgumentException
+                            ("Negative value supplied for TIFF_LONG");
+                    }
+                    if (datum > MAX_UINT32) {
+                        throw new IllegalArgumentException
+                            ("Too large value supplied for TIFF_LONG");
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_IFD_POINTER:
             isDataArrayCorrect = data instanceof long[]
                 && ((long[])data).length == 1;
+            if (((long[])data)[0] < 0) {
+                throw new IllegalArgumentException
+                    ("Negative value supplied for TIFF_IFD_POINTER");
+            }
+            if (((long[])data)[0] > MAX_UINT32) {
+                throw new IllegalArgumentException
+                    ("Too large value supplied for TIFF_IFD_POINTER");
+            }
             break;
         case TIFFTag.TIFF_RATIONAL:
             isDataArrayCorrect = data instanceof long[][]
-                && ((long[][])data).length == count
-                && ((long[][])data)[0].length == 2;
+                && ((long[][])data).length == count;
+            if (isDataArrayCorrect) {
+                for (long[] datum : (long[][])data) {
+                    if (datum.length != 2) {
+                        isDataArrayCorrect = false;
+                        break;
+                    }
+                    if (datum[0] < 0 || datum[1] < 0) {
+                        throw new IllegalArgumentException
+                            ("Negative value supplied for TIFF_RATIONAL");
+                    }
+                    if (datum[0] > MAX_UINT32 || datum[1] > MAX_UINT32) {
+                        throw new IllegalArgumentException
+                            ("Too large value supplied for TIFF_RATIONAL");
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_SSHORT:
             isDataArrayCorrect = data instanceof short[]
@@ -607,8 +647,15 @@
             break;
         case TIFFTag.TIFF_SRATIONAL:
             isDataArrayCorrect = data instanceof int[][]
-                && ((int[][])data).length == count
-                && ((int[][])data)[0].length == 2;
+                && ((int[][])data).length == count;
+            if (isDataArrayCorrect) {
+                for (int[] datum : (int[][])data) {
+                    if (datum.length != 2) {
+                        isDataArrayCorrect = false;
+                        break;
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_FLOAT:
             isDataArrayCorrect = data instanceof float[]
@@ -658,27 +705,32 @@
 
     /**
      * Constructs a {@code TIFFField} with a single non-negative integral
-     * value.
-     * The field will have type
-     * {@link TIFFTag#TIFF_SHORT  TIFF_SHORT} if
-     * {@code val < 65536} and type
-     * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise.  The count
-     * of the field will be unity.
+     * value. The field will have type {@link TIFFTag#TIFF_SHORT TIFF_SHORT}
+     * if {@code value} is in {@code [0,0xffff]}, and type
+     * {@link TIFFTag#TIFF_LONG TIFF_LONG} if {@code value} is in
+     * {@code [0x10000,0xffffffff]}. The count of the field will be unity.
      *
      * @param tag The tag to associate with this field.
      * @param value The value to associate with this field.
      * @throws NullPointerException if {@code tag == null}.
-     * @throws IllegalArgumentException if the derived type is unacceptable
-     * for the supplied {@code TIFFTag}.
-     * @throws IllegalArgumentException if {@code value < 0}.
+     * @throws IllegalArgumentException if {@code value} is not in
+     * {@code [0,0xffffffff]}.
+     * @throws IllegalArgumentException if {@code value} is in
+     * {@code [0,0xffff]} and {@code TIFF_SHORT} is an unacceptable type
+     * for the {@code TIFFTag}, or if {@code value} is in
+     * {@code [0x10000,0xffffffff]} and {@code TIFF_LONG} is an unacceptable
+     * type for the {@code TIFFTag}.
      */
-    public TIFFField(TIFFTag tag, int value) {
+    public TIFFField(TIFFTag tag, long value) {
         if(tag == null) {
             throw new NullPointerException("tag == null!");
         }
         if (value < 0) {
             throw new IllegalArgumentException("value < 0!");
         }
+        if (value > MAX_UINT32) {
+            throw new IllegalArgumentException("value > 0xffffffff!");
+        }
 
         this.tag = tag;
         this.tagNumber = tag.getNumber();
@@ -687,7 +739,8 @@
         if (value < 65536) {
             if (!tag.isDataTypeOK(TIFFTag.TIFF_SHORT)) {
                 throw new IllegalArgumentException("Illegal data type "
-                    + TIFFTag.TIFF_SHORT + " for " + tag.getName() + " tag");
+                    + getTypeName(TIFFTag.TIFF_SHORT) + " for tag "
+                    + "\"" + tag.getName() + "\"");
             }
             this.type = TIFFTag.TIFF_SHORT;
             char[] cdata = new char[1];
@@ -696,7 +749,8 @@
         } else {
             if (!tag.isDataTypeOK(TIFFTag.TIFF_LONG)) {
                 throw new IllegalArgumentException("Illegal data type "
-                    + TIFFTag.TIFF_LONG + " for " + tag.getName() + " tag");
+                    + getTypeName(TIFFTag.TIFF_LONG) + " for tag "
+                    + "\"" + tag.getName() + "\"");
             }
             this.type = TIFFTag.TIFF_LONG;
             long[] ldata = new long[1];
@@ -799,7 +853,7 @@
             throw new IllegalArgumentException("Unknown data type "+dataType);
         }
 
-        return typeNames[dataType];
+        return TYPE_NAMES[dataType];
     }
 
     /**
@@ -812,7 +866,7 @@
      */
     public static int getTypeByName(String typeName) {
         for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) {
-            if (typeName.equals(typeNames[i])) {
+            if (typeName.equals(TYPE_NAMES[i])) {
                 return i;
             }
         }
@@ -887,7 +941,7 @@
      * @return Whether the field type is integral.
      */
     public boolean isIntegral() {
-        return isIntegral[type];
+        return IS_INTEGRAL[type];
     }
 
     /**
diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
index 1b8821a..0abf602 100644
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java
@@ -46,11 +46,18 @@
  * {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet}
  * are included.
  *
+ * <p> Forcing reading of fields corresponding to {@code TIFFTag}s
+ * not in any of the allowed {@code TIFFTagSet}s may be effected via
+ * {@link #setReadUnknownTags setReadUnknownTags}.
+ *
  * @since 9
  */
 public final class TIFFImageReadParam extends ImageReadParam {
 
-    private List<TIFFTagSet> allowedTagSets = new ArrayList<TIFFTagSet>(4);
+    private final List<TIFFTagSet> allowedTagSets =
+        new ArrayList<TIFFTagSet>(4);
+
+    private boolean readUnknownTags = false;
 
     /**
      * Constructs a {@code TIFFImageReadParam}.  Tags defined by
@@ -72,7 +79,8 @@
 
     /**
      * Adds a {@code TIFFTagSet} object to the list of allowed
-     * tag sets.
+     * tag sets.  Attempting to add a duplicate object to the list
+     * has no effect.
      *
      * @param tagSet a {@code TIFFTagSet}.
      *
@@ -83,7 +91,9 @@
         if (tagSet == null) {
             throw new IllegalArgumentException("tagSet == null!");
         }
-        allowedTagSets.add(tagSet);
+        if (!allowedTagSets.contains(tagSet)) {
+            allowedTagSets.add(tagSet);
+        }
     }
 
     /**
@@ -113,4 +123,27 @@
     public List<TIFFTagSet> getAllowedTagSets() {
         return allowedTagSets;
     }
+
+    /**
+     * Set whether to read fields corresponding to {@code TIFFTag}s not in
+     * the allowed {@code TIFFTagSet}s. The default setting is {@code false}.
+     * If the TIFF {@code ImageReader} is ignoring metadata, then a setting
+     * of {@code true} is overridden as all metadata are ignored except those
+     * essential to reading the image itself.
+     *
+     * @param readUnknownTags Whether to read fields of unrecognized tags
+     */
+    public void setReadUnknownTags(boolean readUnknownTags) {
+        this.readUnknownTags = readUnknownTags;
+    }
+
+    /**
+     * Retrieve the setting of whether to read fields corresponding to unknown
+     * {@code TIFFTag}s.
+     *
+     * @return Whether to read fields of unrecognized tags
+     */
+    public boolean getReadUnknownTags() {
+        return readUnknownTags;
+    }
 }
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java b/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java
index 5bc2f06..542e1cb 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java
@@ -182,6 +182,8 @@
      */
     private int modelRowCount;
 
+    // Whether to print warning about JDK-8160087
+    private static boolean warning8160087 = true;
 
     /**
      * Creates an empty <code>DefaultRowSorter</code>.
@@ -489,10 +491,7 @@
      */
     public int convertRowIndexToView(int index) {
         if (modelToView == null) {
-            if (index < 0 || index >= modelRowCount) {
-                throw new IndexOutOfBoundsException("Invalid index");
-            }
-            return index;
+            return convertUnsortedUnfiltered(index);
         }
         return modelToView[index];
     }
@@ -504,14 +503,30 @@
      */
     public int convertRowIndexToModel(int index) {
         if (viewToModel == null) {
-            if (index < 0 || index >= modelRowCount) {
-                throw new IndexOutOfBoundsException("Invalid index");
-            }
-            return index;
+            return convertUnsortedUnfiltered(index);
         }
         return viewToModel[index].modelIndex;
     }
 
+    private int convertUnsortedUnfiltered(int index) {
+        if (index < 0 || index >= modelRowCount) {
+            if(index >= modelRowCount &&
+                                      index < getModelWrapper().getRowCount()) {
+                // 8160087
+                if(warning8160087) {
+                    warning8160087 = false;
+                    System.err.println("WARNING: row index is bigger than " +
+                            "sorter's row count. Most likely this is a wrong " +
+                            "sorter usage.");
+                }
+            } else {
+                throw new IndexOutOfBoundsException("Invalid index");
+            }
+        }
+        return index;
+    }
+
+
     private boolean isUnsorted() {
         List<? extends SortKey> keys = getSortKeys();
         int keySize = keys.size();
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java b/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java
index 979d2b8..7582a02 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java
@@ -27,6 +27,7 @@
 import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Insets;
+import java.awt.Toolkit;
 import java.awt.event.*;
 import java.beans.JavaBean;
 import java.beans.BeanProperty;
@@ -41,6 +42,8 @@
 import javax.swing.plaf.*;
 import javax.accessibility.*;
 
+import sun.awt.SunToolkit;
+
 /**
  * An implementation of a menu bar. You add <code>JMenu</code> objects to the
  * menu bar to construct a menu. When the user selects a <code>JMenu</code>
@@ -144,6 +147,10 @@
      * @see JComponent#updateUI
      */
     public void updateUI() {
+        Toolkit tk = Toolkit.getDefaultToolkit();
+        if (tk instanceof SunToolkit) {
+            ((SunToolkit)tk).updateScreenMenuBarUI();
+        }
         setUI((MenuBarUI)UIManager.getUI(this));
     }
 
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java b/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java
index 491d163..4457658 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java
@@ -47,6 +47,7 @@
 import java.util.Collections;
 
 import sun.awt.AWTAccessor;
+import sun.swing.SwingUtilities2;
 
 /**
  * The "viewport" or "porthole" through which you see the underlying
@@ -1034,9 +1035,16 @@
     private boolean isBlitting() {
         Component view = getView();
         return (scrollMode == BLIT_SCROLL_MODE) &&
-               (view instanceof JComponent) && view.isOpaque();
+               (view instanceof JComponent) && view.isOpaque() && !isFPScale();
     }
 
+    private boolean isFPScale() {
+        GraphicsConfiguration gc = getGraphicsConfiguration();
+        if (gc != null) {
+            return SwingUtilities2.isFloatingPointScale(gc.getDefaultTransform());
+        }
+        return false;
+    }
 
     /**
      * Returns the <code>JViewport</code>'s one child or <code>null</code>.
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java
index 1db4906..8737b6b 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java
@@ -45,7 +45,11 @@
 import sun.security.action.GetPropertyAction;
 
 import com.sun.java.swing.SwingUtilities3;
+import java.awt.geom.AffineTransform;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.pipe.Region;
 import sun.swing.SwingAccessor;
+import sun.swing.SwingUtilities2;
 import sun.swing.SwingUtilities2.RepaintListener;
 
 /**
@@ -1517,9 +1521,12 @@
             // standard Image buffer.
             boolean paintCompleted = false;
             Image offscreen;
+            int sw = w + 1;
+            int sh = h + 1;
+
             if (repaintManager.useVolatileDoubleBuffer() &&
                 (offscreen = getValidImage(repaintManager.
-                getVolatileOffscreenBuffer(bufferComponent, w, h))) != null) {
+                getVolatileOffscreenBuffer(bufferComponent, sw, sh))) != null) {
                 VolatileImage vImage = (java.awt.image.VolatileImage)offscreen;
                 GraphicsConfiguration gc = bufferComponent.
                                             getGraphicsConfiguration();
@@ -1529,7 +1536,7 @@
                                    VolatileImage.IMAGE_INCOMPATIBLE) {
                         repaintManager.resetVolatileDoubleBuffer(gc);
                         offscreen = repaintManager.getVolatileOffscreenBuffer(
-                            bufferComponent,w, h);
+                            bufferComponent, sw, sh);
                         vImage = (java.awt.image.VolatileImage)offscreen;
                     }
                     paintDoubleBuffered(paintingComponent, vImage, g, x, y,
@@ -1589,8 +1596,18 @@
          * Paints a portion of a component to an offscreen buffer.
          */
         protected void paintDoubleBuffered(JComponent c, Image image,
-                            Graphics g, int clipX, int clipY,
-                            int clipW, int clipH) {
+                Graphics g, int clipX, int clipY,
+                int clipW, int clipH) {
+            if (image instanceof VolatileImage && isPixelsCopying(c, g)) {
+                paintDoubleBufferedFPScales(c, image, g, clipX, clipY, clipW, clipH);
+            } else {
+                paintDoubleBufferedImpl(c, image, g, clipX, clipY, clipW, clipH);
+            }
+        }
+
+        private void paintDoubleBufferedImpl(JComponent c, Image image,
+                                             Graphics g, int clipX, int clipY,
+                                             int clipW, int clipH) {
             Graphics osg = image.getGraphics();
             int bw = Math.min(clipW, image.getWidth(null));
             int bh = Math.min(clipH, image.getHeight(null));
@@ -1629,6 +1646,76 @@
             }
         }
 
+        private void paintDoubleBufferedFPScales(JComponent c, Image image,
+                                                 Graphics g, int clipX, int clipY,
+                                                 int clipW, int clipH) {
+            Graphics osg = image.getGraphics();
+            Graphics2D g2d = (Graphics2D) g;
+            Graphics2D osg2d = (Graphics2D) osg;
+
+            AffineTransform identity = new AffineTransform();
+            int bw = Math.min(clipW, image.getWidth(null));
+            int bh = Math.min(clipH, image.getHeight(null));
+            int x, y, maxx, maxy;
+
+            AffineTransform tx = g2d.getTransform();
+            double scaleX = tx.getScaleX();
+            double scaleY = tx.getScaleY();
+            double trX = tx.getTranslateX();
+            double trY = tx.getTranslateY();
+
+            boolean translucent = volatileBufferType != Transparency.OPAQUE;
+            Composite oldComposite = g2d.getComposite();
+
+            try {
+                for (x = clipX, maxx = clipX + clipW; x < maxx; x += bw) {
+                    for (y = clipY, maxy = clipY + clipH; y < maxy; y += bh) {
+
+                        // draw x, y, bw, bh
+                        int pixelx1 = Region.clipRound(x * scaleX + trX);
+                        int pixely1 = Region.clipRound(y * scaleY + trY);
+                        int pixelx2 = Region.clipRound((x + bw) * scaleX + trX);
+                        int pixely2 = Region.clipRound((y + bh) * scaleY + trY);
+                        int pixelw = pixelx2 - pixelx1;
+                        int pixelh = pixely2 - pixely1;
+
+                        osg2d.setTransform(identity);
+                        if (translucent) {
+                            final Color oldBg = g2d.getBackground();
+                            g2d.setBackground(c.getBackground());
+                            g2d.clearRect(pixelx1, pixely1, pixelw, pixelh);
+                            g2d.setBackground(oldBg);
+                        }
+
+                        osg2d.setClip(0, 0, pixelw, pixelh);
+                        osg2d.translate(trX - pixelx1, trY - pixely1);
+                        osg2d.scale(scaleX, scaleY);
+                        c.paintToOffscreen(osg, x, y, bw, bh, maxx, maxy);
+
+                        g2d.setTransform(identity);
+                        g2d.setClip(pixelx1, pixely1, pixelw, pixelh);
+                        AffineTransform stx = new AffineTransform();
+                        stx.translate(pixelx1, pixely1);
+                        stx.scale(scaleX, scaleY);
+                        g2d.setTransform(stx);
+
+                        if (translucent) {
+                            g2d.setComposite(AlphaComposite.Src);
+                        }
+
+                        g2d.drawImage(image, 0, 0, c);
+
+                        if (translucent) {
+                            g2d.setComposite(oldComposite);
+                        }
+                        g2d.setTransform(tx);
+                    }
+                }
+            } finally {
+                osg.dispose();
+            }
+        }
+
         /**
          * If <code>image</code> is non-null with a positive size it
          * is returned, otherwise null is returned.
@@ -1671,8 +1758,32 @@
          */
         protected void dispose() {
         }
-    }
 
+        private boolean isPixelsCopying(JComponent c, Graphics g) {
+
+            AffineTransform tx = getTransform(g);
+            GraphicsConfiguration gc = c.getGraphicsConfiguration();
+
+            if (tx == null || gc == null
+                    || !SwingUtilities2.isFloatingPointScale(tx)) {
+                return false;
+            }
+
+            AffineTransform gcTx = gc.getDefaultTransform();
+
+            return gcTx.getScaleX() == tx.getScaleX()
+                    && gcTx.getScaleY() == tx.getScaleY();
+        }
+
+        private static AffineTransform getTransform(Graphics g) {
+            if (g instanceof SunGraphics2D) {
+                return ((SunGraphics2D) g).transform;
+            } else if (g instanceof Graphics2D) {
+                return ((Graphics2D) g).getTransform();
+            }
+            return null;
+        }
+    }
 
     private class DoubleBufferInfo {
         public Image image;
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
index 9113258..32db72d 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
@@ -571,7 +571,9 @@
 
     /**
      * Obsolete class, not used in this version.
+     * @deprecated As of JDK version 9. Obsolete class.
      */
+    @Deprecated(since = "9")
     protected class SingleClickListener extends MouseAdapter {
         /**
          * Constructs an instance of {@code SingleClickListener}.
@@ -584,7 +586,9 @@
 
     /**
      * Obsolete class, not used in this version.
+     * @deprecated As of JDK version 9. Obsolete class.
      */
+    @Deprecated(since = "9")
     @SuppressWarnings("serial") // Superclass is not serializable across versions
     protected class FileRenderer extends DefaultListCellRenderer  {
     }
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java
index 6bb0226..dde3437 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java
@@ -26,6 +26,7 @@
 
 import java.awt.*;
 import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
 import java.lang.ref.SoftReference;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -750,7 +751,6 @@
          *   valid location in the associated document
          * @see View#modelToView
          */
-        @SuppressWarnings("deprecation")
         public Shape modelToView(int pos, Shape a, Position.Bias b)
                 throws BadLocationException {
             Rectangle alloc = a.getBounds();
@@ -777,9 +777,11 @@
             if (pos > p0) {
                 Segment segment = SegmentCache.getSharedSegment();
                 loadText(segment, p0, pos);
-                alloc.x += Utilities.getTabbedTextWidth(segment, metrics,
-                        alloc.x, WrappedPlainView.this, p0);
+                float x = alloc.x;
+                x += Utilities.getTabbedTextWidth(segment, metrics, x,
+                                                  WrappedPlainView.this, p0);
                 SegmentCache.releaseSharedSegment(segment);
+                return new Rectangle2D.Float(x, alloc.y, alloc.width, alloc.height);
             }
             return alloc;
         }
diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java
index b20d8d6..29a435c 100644
--- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java
@@ -360,6 +360,12 @@
          * Marks the specified window as an utility window for TrayIcon.
          */
         void setTrayIconWindow(Window w, boolean isTrayIconWindow);
+
+        /**
+         * Return an array containing all the windows this
+         * window currently owns.
+         */
+        Window[] getOwnedWindows(Window w);
     }
 
     /**
diff --git a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java
index f2a9971..de1d303 100644
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java
@@ -1857,6 +1857,9 @@
         return time == null ? -1 : time;
     }
 
+    public void updateScreenMenuBarUI() {
+    }
+
     // Cosntant alpha
     public boolean isWindowOpacitySupported() {
         return false;
diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java
index 2fe2236..4c0abc9 100644
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java
@@ -3101,10 +3101,10 @@
             if (scaleX == 1 && scaleY == 1) {
                 return null;
             }
-            sx1 = Region.clipScale(sx1, scaleX);
-            sx2 = Region.clipScale(sx2, scaleX);
-            sy1 = Region.clipScale(sy1, scaleY);
-            sy2 = Region.clipScale(sy2, scaleY);
+            sx1 = Region.clipRound(sx1 * scaleX);
+            sx2 = Region.clipRound(sx2 * scaleX);
+            sy1 = Region.clipRound(sy1 * scaleY);
+            sy2 = Region.clipRound(sy2 * scaleY);
 
             AffineTransform tx = null;
             if (xform != null) {
diff --git a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java
index 9671ec9..14b3eaa 100644
--- a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java
+++ b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java
@@ -305,6 +305,12 @@
             int startY = (int)Math.floor(y * scaleY);
             int width  = (int)Math.ceil((x + w) * scaleX) - startX;
             int height = (int)Math.ceil((y + h) * scaleY) - startY;
+            if (startX + width > linestride) {
+                width = linestride - startX;
+            }
+            if (startY + height > bbImage.getHeight()) {
+                height = bbImage.getHeight() - startY;
+            }
 
             for (int i = 0; i < height; i++) {
                 int from = (startY + i) * linestride + startX;
diff --git a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java
index 5bf01c5..f55290b 100644
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java
+++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java
@@ -33,6 +33,7 @@
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import static java.awt.geom.AffineTransform.TYPE_FLIP;
+import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
 import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
 import java.awt.print.PrinterGraphics;
 import java.text.BreakIterator;
@@ -2162,6 +2163,19 @@
         return false;
     }
 
+    public static boolean isFloatingPointScale(AffineTransform tx) {
+        int type = tx.getType() & ~(TYPE_FLIP | TYPE_TRANSLATION);
+        if (type == 0) {
+            return false;
+        } else if ((type & ~TYPE_MASK_SCALE) == 0) {
+            double scaleX = tx.getScaleX();
+            double scaleY = tx.getScaleY();
+            return (scaleX != (int) scaleX) || (scaleY != (int) scaleY);
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Returns the client property for the given key if it is set; otherwise
      * returns the {@L&F} property.
diff --git a/jdk/src/java.desktop/share/legal/colorimaging.md b/jdk/src/java.desktop/share/legal/colorimaging.md
new file mode 100644
index 0000000..e5a011b
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/colorimaging.md
@@ -0,0 +1,5 @@
+## Eastman Kodak Company: Kodak Color Management System (kcms) and portions of color management and imaging software
+
+### Notice
+
+Portions Copyright Eastman Kodak Company 1991-2003
diff --git a/jdk/src/java.desktop/share/legal/giflib.md b/jdk/src/java.desktop/share/legal/giflib.md
new file mode 100644
index 0000000..a2c1e7e
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/giflib.md
@@ -0,0 +1,26 @@
+## GIFLIB v5.1.4
+
+### GIFLIB License
+<pre>
+
+The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/harfbuzz.md b/jdk/src/java.desktop/share/legal/harfbuzz.md
new file mode 100644
index 0000000..0e8033a
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/harfbuzz.md
@@ -0,0 +1,63 @@
+## Harfbuzz v1.3.0
+
+### Harfbuzz License
+
+http://cgit.freedesktop.org/harfbuzz/tree/COPYING
+
+<pre>
+
+HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
+For parts of HarfBuzz that are licensed under different licenses see individual
+files names COPYING in subdirectories where applicable.
+
+Copyright © 2010,2011,2012, 2013  Google, Inc.
+Copyright © 2012, 2013  Mozilla Foundation
+Copyright © 2011  Codethink Limited
+Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
+Copyright © 2009  Keith Stribley
+Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+Copyright © 2009, 2011  Martin Hosken and SIL International
+Copyright © 2007  Chris Wilson
+Copyright © 2006  Behdad Esfahbod
+Copyright © 2005  David Turner
+Copyright © 2004,2007,2008,2009,2010, 2013  Red Hat, Inc.
+Copyright © 1998-2004  David Turner and Werner Lemberg
+
+For full copyright notices consult the individual files in the package.
+
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+All source code, except for one section, is licensed as above.   The one
+exception is licensed with a slightly different MIT variant:
+The contents of this directory are licensed under the following terms:
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/jpeg.md b/jdk/src/java.desktop/share/legal/jpeg.md
new file mode 100644
index 0000000..681d9f5
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/jpeg.md
@@ -0,0 +1,83 @@
+## JPEG rb6
+
+### JPEG License
+<pre>
+
+Must reproduce following license in documentation and/or other materials
+provided with distribution:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose.  This software is provided "AS IS",
+and you, its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-1998, Thomas G. Lane.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute
+this software (or portions thereof) for any purpose, without fee,
+subject to these conditions:
+
+(1) If any part of the source code for this software is distributed,
+then this README file must be included, with this copyright and no-warranty
+notice unaltered; and any additions, deletions, or changes to the original
+files must be clearly indicated in accompanying documentation.
+
+(2) If only executable code is distributed, then the accompanying documentation
+must state that "this software is based in part on the work of the
+Independent JPEG Group".
+
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library.  If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived
+from it.  This software may be referred to only as "the Independent JPEG
+Group's software".
+
+We specifically permit and encourage the use of this software as the basis
+of commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it.
+(See the file ansi2knr.c for full details.)  However, since ansi2knr.c is
+not needed as part of any program generated from the IJG code, this does not
+limit you more than the foregoing paragraphs do.
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltconfig, ltmain.sh).  Another support script, install-sh, is copyright
+by M.I.T. but is also freely distributable.
+
+It appears that the arithmetic coding option of the JPEG spec is covered
+by patents owned by IBM, AT&T, and Mitsubishi.  Hence arithmetic coding
+cannot legally be used without obtaining one or more licenses.  For this
+reason, support for arithmetic coding has been removed from the free
+JPEG software. (Since arithmetic coding provides only a marginal gain
+over the unpatented Huffman mode, it is unlikely that very many
+implementations will support it.) So far as we are aware, there are
+no patent restrictions on the remaining code.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support
+has been removed altogether, and the GIF writer has been simplified to
+produce "uncompressed GIFs".  This technique does not use the LZW algorithm;
+the resulting GIF files are larger than usual, but are readable by all
+standard GIF decoders.
+
+We are required to state that "The Graphics Interchange Format(c) is
+the Copyright property of CompuServe Incorporated.  GIF(sm) is a
+Service Mark property of CompuServe Incorporated."
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/lcms.md b/jdk/src/java.desktop/share/legal/lcms.md
new file mode 100644
index 0000000..d744755
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/lcms.md
@@ -0,0 +1,27 @@
+## Little Color Management System (LCMS) v2.8
+
+### LCMS License
+<pre>
+
+Little Color Management System
+Copyright (c) 1998-2016 Marti Maria Saguer
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/libpng.md b/jdk/src/java.desktop/share/legal/libpng.md
new file mode 100644
index 0000000..cd9f613
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/libpng.md
@@ -0,0 +1,109 @@
+## Libpng v 1.6.23
+
+### Libpng License
+<pre>
+
+This copy of the libpng notices is provided for your convenience.  In case of
+any discrepancy between this copy and the notices in the file png.h that is
+included in the libpng distribution, the latter shall prevail.
+
+COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+
+If you modify libpng you may insert additional notices immediately following
+this sentence.
+
+This code is released under the libpng license.
+
+libpng versions 1.0.7, July 1, 2000 through 1.6.23, June 9, 2016 are
+Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are
+derived from libpng-1.0.6, and are distributed according to the same
+disclaimer and license as libpng-1.0.6 with the following individuals
+added to the list of Contributing Authors:
+
+   Simon-Pierre Cadieux
+   Eric S. Raymond
+   Mans Rullgard
+   Cosmin Truta
+   Gilles Vollant
+   James Yu
+
+and with the following additions to the disclaimer:
+
+   There is no warranty against interference with your enjoyment of the
+   library or against infringement.  There is no warranty that our
+   efforts or the library will fulfill any of your particular purposes
+   or needs.  This library is provided with all faults, and the entire
+   risk of satisfactory quality, performance, accuracy, and effort is with
+   the user.
+
+Some files in the "contrib" directory and some configure-generated
+files that are distributed with libpng have other copyright owners and
+are released under other open source licenses.
+
+libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+libpng-0.96, and are distributed according to the same disclaimer and
+license as libpng-0.96, with the following individuals added to the list
+of Contributing Authors:
+
+   Tom Lane
+   Glenn Randers-Pehrson
+   Willem van Schaik
+
+libpng versions 0.89, June 1996, through 0.96, May 1997, are
+Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+and are distributed according to the same disclaimer and license as
+libpng-0.88, with the following individuals added to the list of
+Contributing Authors:
+
+   John Bowler
+   Kevin Bracey
+   Sam Bushell
+   Magnus Holmgren
+   Greg Roelofs
+   Tom Tanner
+
+Some files in the "scripts" directory have other copyright owners
+but are released under this license.
+
+libpng versions 0.5, May 1995, through 0.88, January 1996, are
+Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+
+For the purposes of this copyright and license, "Contributing Authors"
+is defined as the following set of individuals:
+
+   Andreas Dilger
+   Dave Martindale
+   Guy Eric Schalnat
+   Paul Schmidt
+   Tim Wegner
+
+The PNG Reference Library is supplied "AS IS".  The Contributing Authors
+and Group 42, Inc. disclaim all warranties, expressed or implied,
+including, without limitation, the warranties of merchantability and of
+fitness for any purpose.  The Contributing Authors and Group 42, Inc.
+assume no liability for direct, indirect, incidental, special, exemplary,
+or consequential damages, which may result from the use of the PNG
+Reference Library, even if advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+  1. The origin of this source code must not be misrepresented.
+
+  2. Altered versions must be plainly marked as such and must not
+     be misrepresented as being the original source.
+
+  3. This Copyright notice may not be removed or altered from any
+     source or altered source distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit, without
+fee, and encourage the use of this source code as a component to
+supporting the PNG file format in commercial products.  If you use this
+source code in a product, acknowledgment is not required but would be
+appreciated.
+
+END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/mesa3d.md b/jdk/src/java.desktop/share/legal/mesa3d.md
new file mode 100644
index 0000000..50c2114
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/mesa3d.md
@@ -0,0 +1,28 @@
+## Mesa 3-D Graphics Library v4.1
+
+### Mesa 3-D Graphics Library License
+<pre>
+
+Mesa 3-D graphics library
+Version:  4.1
+
+Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/legal/opengl.md b/jdk/src/java.desktop/share/legal/opengl.md
new file mode 100644
index 0000000..41c811b
--- /dev/null
+++ b/jdk/src/java.desktop/share/legal/opengl.md
@@ -0,0 +1,27 @@
+## Khronos Group OpenGL Headers v2.1
+
+### Khronos Group License
+<pre>
+
+Copyright (c) 2007 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
+</pre>
diff --git a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c
index 95a92f2..41cf186 100644
--- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c
+++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c
@@ -140,7 +140,7 @@
         indices[storei] = baseIndex + cluster;
         glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);
         positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;
-        positions[(storei*2)+1] = startY + y + glyphPos[i].y_offset * scale;
+        positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
         x += glyphPos[i].x_advance * scale;
         y += glyphPos[i].y_advance * scale;
         storei++;
diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java
index 85e578b..74444b8 100644
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -123,15 +123,26 @@
             // Change in the size of the content window means, well, change of the size
             // Change in the location of the content window means change in insets
             boolean needHandleResize = !(newBounds.equals(getBounds()));
+            boolean needPaint = width <= 0 || height <= 0;
             reshape(newBounds);
             if (needHandleResize) {
                 insLog.fine("Sending RESIZED");
                 handleResize(newBounds);
             }
+            if (needPaint) {
+                postPaintEvent(target, 0, 0, newBounds.width, newBounds.height);
+            }
         } finally {
             XToolkit.awtUnlock();
         }
-        validateSurface();
+    }
+
+    @Override
+    public void handleExposeEvent(XEvent xev) {
+        if (width <= 0 || height <= 0) {
+            return;
+        }
+        super.handleExposeEvent(xev);
     }
 
     // NOTE: This method may be called by privileged threads.
diff --git a/jdk/src/java.desktop/unix/legal/fontconfig.md b/jdk/src/java.desktop/unix/legal/fontconfig.md
new file mode 100644
index 0000000..abdebf3
--- /dev/null
+++ b/jdk/src/java.desktop/unix/legal/fontconfig.md
@@ -0,0 +1,24 @@
+## FontConfig v2.5
+
+### FontConfig License
+<pre>
+
+Copyright 2001,2003 Keith Packard
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that the
+above copyright notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting documentation, and that
+the name of Keith Packard not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior permission.
+Keith Packard makes no representations about the suitability of this software
+for any purpose.  It is provided "as is" without express or implied warranty.
+
+KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
+PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+</pre>
diff --git a/jdk/src/java.desktop/unix/legal/xwindows.md b/jdk/src/java.desktop/unix/legal/xwindows.md
new file mode 100644
index 0000000..42b2841
--- /dev/null
+++ b/jdk/src/java.desktop/unix/legal/xwindows.md
@@ -0,0 +1,232 @@
+## X Windows System v6.8.2
+
+### X Windows System License
+<pre>
+
+This is the copyright for the files in src/java.desktop/unix/native/libawt_xawt:
+list.h, multiVis.h, wsutils.h, list.c, multiVis.c
+
+Copyright (c) 1994 Hewlett-Packard Co.
+Copyright (c) 1996 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+___________________________
+
+
+The files in motif/lib/Xm/util included this copyright:
+mkdirhier.man,xmkmf.man, chownxterm.c, makeg.man, mergelib.cpp,
+ lndir.man, makestrs.man, checktree.c, lndir.c, makestrs.c
+
+Copyright (c) 1993, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealing in this Software without prior written authorization from the
+X Consortium.
+
+_____________________________
+
+Xmos_r.h:
+/*
+Copyright (c) 1996 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+*/
+
+_____________________________
+
+Copyright notice for extutil.h:
+Copyright 1989, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+*
+* Author: Jim Fulton, MIT The Open Group
+*
+* Xlib Extension-Writing Utilities
+*
+* This package contains utilities for writing the client API for various
+* protocol extensions. THESE INTERFACES ARE NOT PART OF THE X STANDARD AND
+* ARE SUBJECT TO CHANGE!
+*/
+
+_____________________________
+
+Copyright notice for HPkeysym.h:
+/*
+
+Copyright 1987, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Hewlett Packard
+or Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD
+TO THIS SOFWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. Hewlett-Packard shall not be liable for errors
+contained herein or direct, indirect, special, incidental or
+consequential damages in connection with the furnishing,
+performance, or use of this material.
+
+*/
+_____________________________________
+
+Copyright notice in keysym2ucs.h:
+
+Copyright 1987, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts
+
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+</pre>
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
index 080fdc8..f2d3286 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
@@ -251,7 +251,8 @@
     m_bPauseDestroy = FALSE;
 
     m_MessagesProcessing = 0;
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     if (!sm_PrimaryDynamicTableBuilt) {
         // do it once.
         AwtComponent::BuildPrimaryDynamicTable();
@@ -1208,6 +1209,7 @@
         WIN_MSG(WM_XBUTTONDOWN)
         WIN_MSG(WM_XBUTTONUP)
         WIN_MSG(WM_MOUSEWHEEL)
+        WIN_MSG(WM_MOUSEHWHEEL)
         WIN_MSG(WM_PARENTNOTIFY)
         WIN_MSG(WM_ENTERMENULOOP)
         WIN_MSG(WM_EXITMENULOOP)
@@ -1639,6 +1641,7 @@
       case WM_XBUTTONUP:
       case WM_MOUSEMOVE:
       case WM_MOUSEWHEEL:
+      case WM_MOUSEHWHEEL:
       case WM_AWT_MOUSEENTER:
       case WM_AWT_MOUSEEXIT:
           curPos = ::GetMessagePos();
@@ -1708,10 +1711,12 @@
           case WM_AWT_MOUSEEXIT:
               mr = WmMouseExit(static_cast<UINT>(wParam), myPos.x, myPos.y);
               break;
-          case  WM_MOUSEWHEEL:
+          case WM_MOUSEWHEEL:
+          case WM_MOUSEHWHEEL:
               mr = WmMouseWheel(GET_KEYSTATE_WPARAM(wParam),
                                 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
-                                GET_WHEEL_DELTA_WPARAM(wParam));
+                                GET_WHEEL_DELTA_WPARAM(wParam),
+                                switchMessage == WM_MOUSEHWHEEL);
               break;
           }
           break;
@@ -2078,13 +2083,15 @@
 
 MsgRouting AwtComponent::WmSetFocus(HWND hWndLostFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
 MsgRouting AwtComponent::WmKillFocus(HWND hWndGotFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
@@ -2461,7 +2468,7 @@
 }
 
 MsgRouting AwtComponent::WmMouseWheel(UINT flags, int x, int y,
-                                      int wheelRotation)
+                                      int wheelRotation, BOOL isHorizontal)
 {
     // convert coordinates to be Component-relative, not screen relative
     // for wheeling when outside the window, this works similar to
@@ -2475,42 +2482,54 @@
 
     // set some defaults
     jint scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-    jint scrollLines = 3;
+    jint scrollUnits = 3;
 
     BOOL result;
-    UINT platformLines;
-
-    m_wheelRotationAmount += wheelRotation;
+    UINT platformUnits;
+    jint roundedWheelRotation;
+    jdouble preciseWheelRotation;
 
     // AWT interprets wheel rotation differently than win32, so we need to
     // decode wheel amount.
-    jint roundedWheelRotation = m_wheelRotationAmount / (-1 * WHEEL_DELTA);
-    jdouble preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+    jint modifiers = GetJavaModifiers();
+    if (isHorizontal) {
+        modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK;
+        m_wheelRotationAmountX += wheelRotation;
+        roundedWheelRotation = m_wheelRotationAmountX / (WHEEL_DELTA);
+        preciseWheelRotation = (jdouble) wheelRotation / (WHEEL_DELTA);
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
+                                        &platformUnits, 0);
+    } else {
+        m_wheelRotationAmountY += wheelRotation;
+        roundedWheelRotation = m_wheelRotationAmountY / (-1 * WHEEL_DELTA);
+        preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
+                                        &platformUnits, 0);
+    }
 
     MSG msg;
-    result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
-                                    &platformLines, 0);
     InitMessage(&msg, lastMessage, MAKEWPARAM(flags, wheelRotation),
                 MAKELPARAM(x, y));
 
     if (result) {
-        if (platformLines == WHEEL_PAGESCROLL) {
+        if (platformUnits == WHEEL_PAGESCROLL) {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_BLOCK_SCROLL;
-            scrollLines = 1;
+            scrollUnits = 1;
         }
         else {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-            scrollLines = platformLines;
+            scrollUnits = platformUnits;
         }
     }
 
     DTRACE_PRINTLN("calling SendMouseWheelEvent");
 
     SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, ::JVM_CurrentTimeMillis(NULL, 0),
-                        eventPt.x, eventPt.y, GetJavaModifiers(), 0, 0, scrollType,
-                        scrollLines, roundedWheelRotation, preciseWheelRotation, &msg);
+                        eventPt.x, eventPt.y, modifiers, 0, 0, scrollType,
+                        scrollUnits, roundedWheelRotation, preciseWheelRotation, &msg);
 
-    m_wheelRotationAmount %= WHEEL_DELTA;
+    m_wheelRotationAmountX %= WHEEL_DELTA;
+    m_wheelRotationAmountY %= WHEEL_DELTA;
     // this message could be propagated up to the parent chain
     // by the mouse message post processors
     return mrConsume;
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h
index bcf96a7..0d6bf7a 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h
@@ -522,7 +522,7 @@
     virtual MsgRouting WmMouseMove(UINT flags, int x, int y);
     virtual MsgRouting WmMouseExit(UINT flags, int x, int y);
     virtual MsgRouting WmMouseWheel(UINT flags, int x, int y,
-                                    int wheelRotation);
+                                    int wheelRotation, BOOL isHorizontal);
     virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
@@ -824,7 +824,8 @@
     int windowMoveLockPosCY;
 
     // 6524352: support finer-resolution
-    int m_wheelRotationAmount;
+    int m_wheelRotationAmountX;
+    int m_wheelRotationAmountY;
 
     BOOL deadKeyActive;
 
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp
index fb65b85..e341371 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp
@@ -240,6 +240,7 @@
             (wParam == WM_RBUTTONDOWN) ||
             (wParam == WM_MOUSEACTIVATE) ||
             (wParam == WM_MOUSEWHEEL) ||
+            (wParam == WM_MOUSEHWHEEL) ||
             (wParam == WM_NCLBUTTONDOWN) ||
             (wParam == WM_NCMBUTTONDOWN) ||
             (wParam == WM_NCRBUTTONDOWN))
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
index 6c8d65a..9bc6366 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
@@ -484,7 +484,10 @@
             if (fgProcessID != ::GetCurrentProcessId()) {
                 AwtWindow* window = (AwtWindow*)GetComponent(GetHWnd());
 
-                if (window != NULL && window->IsFocusableWindow() && window->IsAutoRequestFocus() &&
+                if (window != NULL &&
+                    window->IsFocusableWindow() &&
+                    window->IsAutoRequestFocus() &&
+                    !::IsWindowVisible(GetHWnd()) && // the window is really showing
                     !::IsWindow(GetModalBlocker(GetHWnd())))
                 {
                     // When the Java process is not allowed to set the foreground window
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp
index 0fffffb..4a0ac90 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp
@@ -1590,7 +1590,7 @@
      * the mouse, not the Component with the input focus.
      */
 
-    if (msg.message == WM_MOUSEWHEEL) {
+    if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) {
             //i.e. mouse is over client area for this window
             DWORD hWndForWheelProcess;
             DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess);
diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h b/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h
index d0131af..ba8a449 100644
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@
 #define WM_MOUSEWHEEL                   0x020A
 #endif //WM_MOUSEWHEEL
 
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL                  0x020E
+#endif //WM_MOUSEHWHEEL
+
 #ifndef WHEEL_DELTA
 #define WHEEL_DELTA                     120
 #endif //WHEEL_DELTA
@@ -54,12 +58,16 @@
 #endif //WHEEL_PAGESCROLL
 
 #ifndef SPI_GETWHEELSCROLLLINES
-#define SPI_GETWHEELSCROLLLINES         104
+#define SPI_GETWHEELSCROLLLINES         0x0068
 #endif //SPI_GETWHEELSCROLLLINES
 
+#ifndef SPI_GETWHEELSCROLLCHARS
+#define SPI_GETWHEELSCROLLCHARS         0x006C
+#endif //SPI_GETWHEELSCROLLCHARS
+
 #ifndef SM_MOUSEWHEELPRESENT
 #define SM_MOUSEWHEELPRESENT            75
-#endif //SPI_GETWHEELSCROLLLINES
+#endif //SM_MOUSEWHEELPRESENT
 
 #ifndef COLOR_HOTLIGHT
 #define COLOR_HOTLIGHT                  26
diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
index e0860f8..f2014ee 100644
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,9 @@
 
 import com.sun.jmx.remote.util.ClassLogger;
 import com.sun.jmx.remote.util.EnvHelp;
+import java.lang.reflect.UndeclaredThrowableException;
 import java.rmi.UnmarshalException;
+import java.util.concurrent.RejectedExecutionException;
 
 
 public abstract class ClientNotifForwarder {
@@ -559,10 +561,38 @@
                     }
                 }
             } else {
-                executor.execute(this);
+                try {
+                    executor.execute(this);
+                } catch (Exception e) {
+                    if (isRejectedExecutionException(e)) {
+                        // We reached here because the executor was shutdown.
+                        // If executor was supplied by client, then it was shutdown
+                        // abruptly or JMXConnector was shutdown along with executor
+                        // while this thread was suspended at L564.
+                        if (!(executor instanceof LinearExecutor)) {
+                            // Spawn new executor that will do cleanup if JMXConnector is closed
+                            // or keep notif system running otherwise
+                            executor = new LinearExecutor();
+                            executor.execute(this);
+                        }
+                    } else {
+                        throw e;
+                    }
+                }
             }
         }
 
+        private boolean isRejectedExecutionException(Exception e) {
+            Throwable cause = e;
+            while (cause != null) {
+                if (cause instanceof RejectedExecutionException) {
+                    return true;
+                }
+                cause = cause.getCause();
+            }
+            return false;
+        }
+
         void dispatchNotification(TargetedNotification tn,
                                   Integer myListenerID,
                                   Map<Integer, ClientListenerInfo> listeners) {
@@ -866,7 +896,7 @@
 // -------------------------------------------------
 
     private final ClassLoader defaultClassLoader;
-    private final Executor executor;
+    private Executor executor;
 
     private final Map<Integer, ClientListenerInfo> infoList =
             new HashMap<Integer, ClientListenerInfo>();
diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java
index 0e3e109..510b688 100644
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java
@@ -27,7 +27,6 @@
 
 import java.util.ArrayList; // JDK 1.2
 import java.util.List;
-import java.util.Iterator;
 
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
@@ -290,23 +289,28 @@
      * @param threshold an entry idle since this time has expired.
      * @return true if no more connections in list
      */
-    synchronized boolean expire(long threshold) {
-        Iterator<ConnectionDesc> iter = conns.iterator();
-        ConnectionDesc entry;
-        while (iter.hasNext()) {
-            entry = iter.next();
+    boolean expire(long threshold) {
+        List<ConnectionDesc> clonedConns;
+        synchronized(this) {
+            clonedConns = new ArrayList<>(conns);
+        }
+        List<ConnectionDesc> expired = new ArrayList<>();
+
+        for (ConnectionDesc entry : clonedConns) {
+            d("expire(): ", entry);
             if (entry.expire(threshold)) {
-                d("expire(): removing ", entry);
-                td("Expired ", entry);
-
-                iter.remove();  // remove from pool
-
-                // Don't need to call notify() because we're
-                // removing only idle connections. If there were
-                // idle connections, then there should be no waiters.
+                expired.add(entry);
+                td("expire(): Expired ", entry);
             }
         }
-        return conns.isEmpty();  // whether whole list has 'expired'
+
+        synchronized (this) {
+            conns.removeAll(expired);
+            // Don't need to call notify() because we're
+            // removing only idle connections. If there were
+            // idle connections, then there should be no waiters.
+            return conns.isEmpty();  // whether whole list has 'expired'
+        }
     }
 
     /**
diff --git a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java
index a2813bf..504c87d 100644
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java
@@ -25,11 +25,11 @@
 
 package com.sun.jndi.ldap.pool;
 
+import java.util.ArrayList;
 import java.util.Map;
 import java.util.WeakHashMap;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedList;
 
 import java.io.PrintStream;
@@ -166,17 +166,25 @@
      *          and removed.
      */
     public void expire(long threshold) {
+        Collection<ConnectionsRef> copy;
         synchronized (map) {
-            Iterator<ConnectionsRef> iter = map.values().iterator();
-            Connections conns;
-            while (iter.hasNext()) {
-                conns = iter.next().getConnections();
-                if (conns.expire(threshold)) {
-                    d("expire(): removing ", conns);
-                    iter.remove();
-                }
+            copy = new ArrayList<>(map.values());
+        }
+
+        ArrayList<ConnectionsRef> removed = new ArrayList<>();
+        Connections conns;
+        for (ConnectionsRef ref : copy) {
+            conns = ref.getConnections();
+            if (conns.expire(threshold)) {
+                d("expire(): removing ", conns);
+                removed.add(ref);
             }
         }
+
+        synchronized (map) {
+            map.values().removeAll(removed);
+        }
+
         expungeStaleConnections();
     }
 
diff --git a/jdk/src/java.naming/share/classes/module-info.java b/jdk/src/java.naming/share/classes/module-info.java
index b896469..f524a4c 100644
--- a/jdk/src/java.naming/share/classes/module-info.java
+++ b/jdk/src/java.naming/share/classes/module-info.java
@@ -37,7 +37,6 @@
     exports com.sun.jndi.toolkit.ctx to
         jdk.naming.dns;
     exports com.sun.jndi.toolkit.url to
-        java.corba,
         jdk.naming.dns,
         jdk.naming.rmi;
     uses javax.naming.ldap.StartTlsResponse;
diff --git a/jdk/src/java.se/share/classes/module-info.java b/jdk/src/java.se/share/classes/module-info.java
index cbd67e5..2756756 100644
--- a/jdk/src/java.se/share/classes/module-info.java
+++ b/jdk/src/java.se/share/classes/module-info.java
@@ -26,12 +26,25 @@
 /**
  * Defines the core Java SE API.
  * <P>
- * The modules defining
- * CORBA and Java EE APIs are not required by this module, but they are
- * required by {@code java.se.ee}.
+ * The modules defining CORBA and Java EE APIs are not required by
+ * this module, but they are required by {@code java.se.ee}.
  */
 module java.se {
-    requires transitive java.compact3;
+    requires transitive java.compiler;
     requires transitive java.datatransfer;
     requires transitive java.desktop;
+    requires transitive java.instrument;
+    requires transitive java.logging;
+    requires transitive java.management;
+    requires transitive java.naming;
+    requires transitive java.prefs;
+    requires transitive java.rmi;
+    requires transitive java.scripting;
+    requires transitive java.security.jgss;
+    requires transitive java.security.sasl;
+    requires transitive java.sql;
+    requires transitive java.sql.rowset;
+    requires transitive java.xml;
+    requires transitive java.xml.crypto;
 }
+
diff --git a/jdk/src/java.security.jgss/share/classes/module-info.java b/jdk/src/java.security.jgss/share/classes/module-info.java
index 6380721..78a7249 100644
--- a/jdk/src/java.security.jgss/share/classes/module-info.java
+++ b/jdk/src/java.security.jgss/share/classes/module-info.java
@@ -42,6 +42,12 @@
         jdk.security.jgss;
     exports sun.security.krb5.internal.ktab to
         jdk.security.auth;
+
+    // Opens for reflective instantiation of sun.net.www.protocol.http.spnego.NegotiatorImpl
+    // to sun.net.www.protocol.http.HttpURLConnection
+    opens sun.net.www.protocol.http.spnego to
+        java.base;
+
     provides java.security.Provider with sun.security.jgss.SunProvider;
     provides sun.security.ssl.ClientKeyExchangeService
         with sun.security.krb5.internal.ssl.Krb5KeyExchangeService;
diff --git a/jdk/src/java.smartcardio/unix/legal/pcsclite.md b/jdk/src/java.smartcardio/unix/legal/pcsclite.md
new file mode 100644
index 0000000..f90e9cc
--- /dev/null
+++ b/jdk/src/java.smartcardio/unix/legal/pcsclite.md
@@ -0,0 +1,41 @@
+## PC/SC Lite for Suse Linux v1.1.1
+
+### PC/SC Lite for Suse Linux License
+<pre>
+
+Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
+Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+     This product includes software developed by:
+      David Corcoran <corcoran@linuxnet.com>
+      http://www.linuxnet.com (MUSCLE)
+4. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
index a32cf8f..7fe5900 100644
--- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
+++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
@@ -41,46 +41,41 @@
 
 
 /**
- * <P>The basic service for managing a set of JDBC drivers.<br>
- * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
- * JDBC 2.0 API, provides another way to connect to a data source.
- * The use of a <code>DataSource</code> object is the preferred means of
+ * The basic service for managing a set of JDBC drivers.
+ * <p>
+ * <strong>NOTE:</strong> The {@link javax.sql.DataSource} interface, provides
+ * another way to connect to a data source.
+ * The use of a {@code DataSource} object is the preferred means of
  * connecting to a data source.
- *
- * <P>As part of its initialization, the <code>DriverManager</code> class will
- * attempt to load the driver classes referenced in the "jdbc.drivers"
- * system property. This allows a user to customize the JDBC Drivers
- * used by their applications. For example in your
- * ~/.hotjava/properties file you might specify:
- * <pre>
- * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
- * </pre>
- *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
- * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
- * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
- * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
- * implementation of <code>java.sql.Driver</code>.  For example, to load the <code>my.sql.Driver</code> class,
- * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
- * <pre>
- * <code>my.sql.Driver</code>
- * </pre>
- *
- * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
- * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
- * modification.
- *
- * <P>When the method <code>getConnection</code> is called,
- * the <code>DriverManager</code> will attempt to
- * locate a suitable driver from amongst those loaded at
- * initialization and those loaded explicitly using the same classloader
- * as the current applet or application.
- *
  * <P>
- * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
- * logging stream can be set only if the proper
- * permission has been granted.  Normally this will be done with
- * the tool PolicyTool, which can be used to grant <code>permission
- * java.sql.SQLPermission "setLog"</code>.
+ * As part of its initialization, the {@code DriverManager} class will
+ * attempt to load available JDBC drivers by using:
+ * <ul>
+ * <li>The {@code jdbc.drivers} system property which contains a
+ * colon separated list of fully qualified class names of JDBC drivers. Each
+ * driver is loaded using the {@linkplain ClassLoader#getSystemClassLoader
+ * system class loader}:
+ * <ul>
+ * <li>{@code jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver}
+ * </ul>
+ *
+ * <li>Service providers of the {@code java.sql.Driver} class, that are loaded
+ * via the {@linkplain ServiceLoader#load service-provider loading} mechanism.
+ *</ul>
+ *
+ *<P>
+ * @ImplNote
+ * {@code DriverManager} initialization is done lazily and looks up service
+ * providers using the thread context class loader.  The drivers loaded and
+ * available to an application will depend on the thread context class loader of
+ * the thread that triggers driver initialization by {@code DriverManager}.
+ *
+ * <P>When the method {@code getConnection} is called,
+ * the {@code DriverManager} will attempt to
+ * locate a suitable driver from amongst those loaded at
+ * initialization and those loaded explicitly using the same class loader
+ * as the current application.
+ *
  * @see Driver
  * @see Connection
  */
@@ -137,29 +132,15 @@
     /**
      * Sets the logging/tracing <code>PrintWriter</code> object
      * that is used by the <code>DriverManager</code> and all drivers.
-     * <P>
-     * There is a minor versioning problem created by the introduction
-     * of the method <code>setLogWriter</code>.  The
-     * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
-     * that will be returned by <code>getLogStream</code>---the Java platform does
-     * not provide a backward conversion.  As a result, a new application
-     * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
-     * <code>getLogStream</code> will likely not see debugging information written
-     * by that driver.
      *<P>
-     * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
-     * to see that there is an <code>SQLPermission</code> object before setting
-     * the logging stream.  If a <code>SecurityManager</code> exists and its
-     * <code>checkPermission</code> method denies setting the log writer, this
-     * method throws a <code>java.lang.SecurityException</code>.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("setLog")}
+     * permission to check that the caller is allowed to call {@code setLogWriter}.
      *
      * @param out the new logging/tracing <code>PrintStream</code> object;
      *      <code>null</code> to disable logging and tracing
-     * @throws SecurityException
-     *    if a security manager exists and its
-     *    <code>checkPermission</code> method denies
-     *    setting the log writer
-     *
+     * @throws SecurityException if a security manager exists and its
+     * {@code checkPermission} method denies permission to set the log writer.
      * @see SecurityManager#checkPermission
      * @see #getLogWriter
      * @since 1.2
@@ -374,8 +355,9 @@
      * If a {@code null} value is specified for the driver to be removed, then no
      * action is taken.
      * <p>
-     * If a security manager exists and its {@code checkPermission} denies
-     * permission, then a {@code SecurityException} will be thrown.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("deregisterDriver")}
+     * permission to check that the caller is allowed to deregister a JDBC Driver.
      * <p>
      * If the specified driver is not found in the list of registered drivers,
      * then no action is taken.  If the driver was found, it will be removed
@@ -501,17 +483,14 @@
      * by the <code>DriverManager</code>
      * and all drivers.
      *<P>
-     * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
-     * to see that there is an <code>SQLPermission</code> object before setting
-     * the logging stream.  If a <code>SecurityManager</code> exists and its
-     * <code>checkPermission</code> method denies setting the log writer, this
-     * method throws a <code>java.lang.SecurityException</code>.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("setLog")}
+     * permission to check that the caller is allowed to call {@code setLogStream}.
      *
      * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
      * @deprecated Use {@code setLogWriter}
      * @throws SecurityException if a security manager exists and its
-     *    <code>checkPermission</code> method denies setting the log stream
-     *
+     * {@code checkPermission} method denies permission to set the log stream.
      * @see SecurityManager#checkPermission
      * @see #getLogStream
      */
diff --git a/jdk/src/java.xml.crypto/share/legal/santuario.md b/jdk/src/java.xml.crypto/share/legal/santuario.md
new file mode 100644
index 0000000..0d8be1b
--- /dev/null
+++ b/jdk/src/java.xml.crypto/share/legal/santuario.md
@@ -0,0 +1,225 @@
+## Apache Santuario v1.5.4
+
+### Notice
+<pre>
+
+  Apache Santuario - XML Security for Java
+  Copyright 1999-2015 The Apache Software Foundation
+
+  This product includes software developed at
+  The Apache Software Foundation (http://www.apache.org/).
+
+  It was originally based on software copyright (c) 2001, Institute for
+  Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
+
+  The development of this software was partly funded by the European
+  Commission in the <WebSig> project in the ISIS Programme.
+
+</pre>
+
+### Apache 2.0 License
+<pre>
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+</pre>
diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java
index cd3cf14..297779d 100644
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,8 @@
 
 package com.sun.java.accessibility.util;
 
-import java.util.*;
 import java.awt.*;
 import java.awt.event.*;
-import javax.accessibility.*;
 import javax.swing.*;
 import javax.swing.event.*;
 import sun.awt.AWTPermissions;
@@ -55,7 +53,7 @@
      * @deprecated This field is unused; to get the component with focus use the
      * getComponentWithFocus method.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected Component componentWithFocus = null;
 
     static private Component componentWithFocus_private = null;
@@ -69,7 +67,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ComponentListener     componentListener     = null;
 
     static private ComponentListener componentListener_private = null;
@@ -82,7 +80,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ContainerListener     containerListener     = null;
 
     static private ContainerListener containerListener_private = null;
@@ -95,7 +93,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected FocusListener         focusListener         = null;
 
     static private FocusListener focusListener_private = null;
@@ -108,7 +106,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected KeyListener           keyListener           = null;
 
     static private KeyListener keyListener_private = null;
@@ -121,7 +119,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected MouseListener         mouseListener         = null;
 
     static private MouseListener mouseListener_private = null;
@@ -134,7 +132,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected MouseMotionListener   mouseMotionListener   = null;
 
     static private MouseMotionListener mouseMotionListener_private = null;
@@ -147,7 +145,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected WindowListener        windowListener        = null;
 
     static private WindowListener windowListener_private = null;
@@ -162,7 +160,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ActionListener        actionListener        = null;
 
     static private ActionListener actionListener_private = null;
@@ -175,7 +173,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected AdjustmentListener    adjustmentListener    = null;
 
     static private AdjustmentListener adjustmentListener_private = null;
@@ -188,7 +186,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ItemListener          itemListener          = null;
 
     static private ItemListener itemListener_private = null;
@@ -201,7 +199,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected TextListener          textListener          = null;
 
     static private TextListener textListener_private = null;
@@ -212,13 +210,8 @@
      * This listener calls the other registered listeners when an event
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
-     *
-     * @deprecated This field is unused.
      */
-    @Deprecated
-    static protected AWTEventsListener awtListener = new AWTEventsListener();
-
-    static private final AWTEventsListener awtListener_private = new AWTEventsListener();
+    static private final AWTEventsListener awtListener = new AWTEventsListener();
 
     /**
      * Returns the component that currently has keyboard focus.  The return
@@ -253,7 +246,7 @@
     static public void addComponentListener(ComponentListener l) {
         if (componentListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.COMPONENT);
+            awtListener.installListeners(EventID.COMPONENT);
         }
         componentListener_private = AWTEventMulticaster.add(componentListener_private, l);
     }
@@ -268,7 +261,7 @@
     static public void removeComponentListener(ComponentListener l) {
         componentListener_private = AWTEventMulticaster.remove(componentListener_private, l);
         if (componentListener_private == null) {
-            awtListener_private.removeListeners(EventID.COMPONENT);
+            awtListener.removeListeners(EventID.COMPONENT);
         }
     }
 
@@ -335,7 +328,7 @@
     static public void addKeyListener(KeyListener l) {
         if (keyListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.KEY);
+            awtListener.installListeners(EventID.KEY);
         }
         keyListener_private = AWTEventMulticaster.add(keyListener_private, l);
     }
@@ -350,7 +343,7 @@
     static public void removeKeyListener(KeyListener l) {
         keyListener_private = AWTEventMulticaster.remove(keyListener_private, l);
         if (keyListener_private == null)  {
-            awtListener_private.removeListeners(EventID.KEY);
+            awtListener.removeListeners(EventID.KEY);
         }
     }
 
@@ -367,7 +360,7 @@
     static public void addMouseListener(MouseListener l) {
         if (mouseListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.MOUSE);
+            awtListener.installListeners(EventID.MOUSE);
         }
         mouseListener_private = AWTEventMulticaster.add(mouseListener_private, l);
     }
@@ -382,7 +375,7 @@
     static public void removeMouseListener(MouseListener l) {
         mouseListener_private = AWTEventMulticaster.remove(mouseListener_private, l);
         if (mouseListener_private == null) {
-            awtListener_private.removeListeners(EventID.MOUSE);
+            awtListener.removeListeners(EventID.MOUSE);
         }
     }
 
@@ -399,7 +392,7 @@
     static public void addMouseMotionListener(MouseMotionListener l) {
         if (mouseMotionListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.MOTION);
+            awtListener.installListeners(EventID.MOTION);
         }
         mouseMotionListener_private = AWTEventMulticaster.add(mouseMotionListener_private, l);
     }
@@ -414,7 +407,7 @@
     static public void removeMouseMotionListener(MouseMotionListener l) {
         mouseMotionListener_private = AWTEventMulticaster.remove(mouseMotionListener_private, l);
         if (mouseMotionListener_private == null) {
-            awtListener_private.removeListeners(EventID.MOTION);
+            awtListener.removeListeners(EventID.MOTION);
         }
     }
 
@@ -431,7 +424,7 @@
     static public void addWindowListener(WindowListener l) {
         if (windowListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.WINDOW);
+            awtListener.installListeners(EventID.WINDOW);
         }
         windowListener_private = AWTEventMulticaster.add(windowListener_private, l);
     }
@@ -446,7 +439,7 @@
     static public void removeWindowListener(WindowListener l) {
         windowListener_private = AWTEventMulticaster.remove(windowListener_private, l);
         if (windowListener_private == null) {
-            awtListener_private.removeListeners(EventID.WINDOW);
+            awtListener.removeListeners(EventID.WINDOW);
         }
     }
 
@@ -463,7 +456,7 @@
     static public void addActionListener(ActionListener l) {
         if (actionListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ACTION);
+            awtListener.installListeners(EventID.ACTION);
         }
         actionListener_private = AWTEventMulticaster.add(actionListener_private, l);
     }
@@ -478,7 +471,7 @@
     static public void removeActionListener(ActionListener l) {
         actionListener_private = AWTEventMulticaster.remove(actionListener_private, l);
         if (actionListener_private == null) {
-            awtListener_private.removeListeners(EventID.ACTION);
+            awtListener.removeListeners(EventID.ACTION);
         }
     }
 
@@ -496,7 +489,7 @@
     static public void addAdjustmentListener(AdjustmentListener l) {
         if (adjustmentListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ADJUSTMENT);
+            awtListener.installListeners(EventID.ADJUSTMENT);
         }
         adjustmentListener_private = AWTEventMulticaster.add(adjustmentListener_private, l);
     }
@@ -511,7 +504,7 @@
     static public void removeAdjustmentListener(AdjustmentListener l) {
         adjustmentListener_private = AWTEventMulticaster.remove(adjustmentListener_private, l);
         if (adjustmentListener_private == null) {
-            awtListener_private.removeListeners(EventID.ADJUSTMENT);
+            awtListener.removeListeners(EventID.ADJUSTMENT);
         }
     }
 
@@ -528,7 +521,7 @@
     static public void addItemListener(ItemListener l) {
         if (itemListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ITEM);
+            awtListener.installListeners(EventID.ITEM);
         }
         itemListener_private = AWTEventMulticaster.add(itemListener_private, l);
     }
@@ -543,7 +536,7 @@
     static public void removeItemListener(ItemListener l) {
         itemListener_private = AWTEventMulticaster.remove(itemListener_private, l);
         if (itemListener_private == null) {
-            awtListener_private.removeListeners(EventID.ITEM);
+            awtListener.removeListeners(EventID.ITEM);
         }
     }
 
@@ -560,7 +553,7 @@
     static public void addTextListener(TextListener l) {
         if (textListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.TEXT);
+            awtListener.installListeners(EventID.TEXT);
         }
         textListener_private = AWTEventMulticaster.add(textListener_private, l);
     }
@@ -575,7 +568,7 @@
     static public void removeTextListener(TextListener l) {
         textListener_private = AWTEventMulticaster.remove(textListener_private, l);
         if (textListener_private == null) {
-            awtListener_private.removeListeners(EventID.TEXT);
+            awtListener.removeListeners(EventID.TEXT);
         }
     }
 
diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java
index 603ba03..e26718d 100644
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,7 @@
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
      */
-    static protected final AccessibilityEventListener accessibilityListener =
+    static private final AccessibilityEventListener accessibilityListener =
         new AccessibilityEventListener();
 
     /**
diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java
index bbb0fcb..c5dcda4 100644
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,7 +71,7 @@
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
      */
-    static protected final SwingEventListener swingListener = new SwingEventListener();
+    static private final SwingEventListener swingListener = new SwingEventListener();
 
     /**
      * Adds the specified listener to receive all {@link EventID#ANCESTOR ANCESTOR}
diff --git a/jdk/src/jdk.crypto.ec/share/legal/ecc.md b/jdk/src/jdk.crypto.ec/share/legal/ecc.md
new file mode 100644
index 0000000..6d4fc59
--- /dev/null
+++ b/jdk/src/jdk.crypto.ec/share/legal/ecc.md
@@ -0,0 +1,530 @@
+## Mozilla Elliptic Curve Cryptography
+
+### Notice
+<pre>
+
+This notice is provided with respect to Elliptic Curve Cryptography,
+which is included with JRE, JDK, and OpenJDK.
+
+You are receiving a copy of the Elliptic Curve Cryptography library in source
+form with the JDK and OpenJDK source distributions, and as object code in
+the JRE & JDK runtimes.
+
+In the case of the JRE & JDK runtimes, the terms of the Oracle license do
+NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
+following license, separately from Oracle's JDK & JRE.  If you do not wish to
+install the Elliptic Curve Cryptography library, you may delete the
+Elliptic Curve Cryptography library:
+   - On Solaris and Linux systems: delete $(JAVA_HOME)/lib/libsunec.so
+   - On Mac OSX systems: delete $(JAVA_HOME)/lib/libsunec.dylib
+   - On Windows systems: delete $(JAVA_HOME)\bin\sunec.dll
+
+</pre>
+
+### LGPL 2.1 License
+<pre>
+
+                  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!
+
+</pre>
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java b/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java
deleted file mode 100644
index 07f4c1b..0000000
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module jdk.crypto.pkcs11 {
-    // Depends on SunEC provider for EC related functionality
-    requires jdk.crypto.ec;
-    provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
-}
-
diff --git a/jdk/src/jdk.crypto.token/share/classes/module-info.java b/jdk/src/jdk.crypto.token/share/classes/module-info.java
new file mode 100644
index 0000000..b587d0d
--- /dev/null
+++ b/jdk/src/jdk.crypto.token/share/classes/module-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.crypto.token {
+    // Depends on SunEC provider for EC related functionality
+    requires jdk.crypto.ec;
+    provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
+}
+
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Config.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Config.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Config.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Config.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/KeyCache.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/KeyCache.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/KeyCache.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/KeyCache.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Cipher.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Cipher.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DHKeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11DHKeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DHKeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11DHKeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Digest.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Digest.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Digest.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Digest.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECKeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Key.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Key.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Key.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Key.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyAgreement.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyAgreement.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyAgreement.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyAgreement.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyStore.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11KeyStore.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Mac.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Mac.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Mac.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Mac.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSACipher.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11RSACipher.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSACipher.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11RSACipher.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecureRandom.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11SecureRandom.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecureRandom.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11SecureRandom.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Signature.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Signature.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Util.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Util.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Util.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Util.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Secmod.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Secmod.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Secmod.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Secmod.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Session.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Session.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Session.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Session.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SessionManager.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/SessionManager.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SessionManager.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/SessionManager.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/SunPKCS11.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/SunPKCS11.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/TemplateManager.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/TemplateManager.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/TemplateManager.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/TemplateManager.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Token.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Token.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Token.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Token.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ATTRIBUTE.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ATTRIBUTE.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ATTRIBUTE.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ATTRIBUTE.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_CREATEMUTEX.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_CREATEMUTEX.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_CREATEMUTEX.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_CREATEMUTEX.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DATE.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_DATE.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DATE.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_DATE.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DESTROYMUTEX.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_DESTROYMUTEX.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DESTROYMUTEX.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_DESTROYMUTEX.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_INFO.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_INFO.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_INFO.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_INFO.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_LOCKMUTEX.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_LOCKMUTEX.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_LOCKMUTEX.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_LOCKMUTEX.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM_INFO.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM_INFO.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM_INFO.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM_INFO.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_NOTIFY.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_NOTIFY.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_NOTIFY.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_NOTIFY.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SESSION_INFO.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SESSION_INFO.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SESSION_INFO.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SESSION_INFO.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SLOT_INFO.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SLOT_INFO.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SLOT_INFO.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SLOT_INFO.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TOKEN_INFO.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_TOKEN_INFO.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TOKEN_INFO.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_TOKEN_INFO.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_VERSION.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_VERSION.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_VERSION.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_VERSION.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Constants.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/Constants.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Constants.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/Constants.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Functions.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/Functions.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Functions.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/Functions.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java
diff --git a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11RuntimeException.java b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11RuntimeException.java
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11RuntimeException.java
rename to jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/wrapper/PKCS11RuntimeException.java
diff --git a/jdk/src/jdk.crypto.token/share/legal/pkcs11cryptotoken.md b/jdk/src/jdk.crypto.token/share/legal/pkcs11cryptotoken.md
new file mode 100644
index 0000000..6f7e3fb
--- /dev/null
+++ b/jdk/src/jdk.crypto.token/share/legal/pkcs11cryptotoken.md
@@ -0,0 +1,20 @@
+## PKCS #11 Cryptographic Token Interface, v2.20 amendment 3 Header Files
+
+### PKCS #11 Cryptographic Token Interface License
+<pre>
+
+License to copy and use this software is granted provided that it is
+identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+(Cryptoki)" in all material mentioning or referencing this software.
+
+License is also granted to make and use derivative works provided that
+such works are identified as "derived from the RSA Security Inc. PKCS #11
+Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+referencing the derived work.
+
+RSA Security Inc. makes no representations concerning either the
+merchantability of this software or the suitability of this software for
+any particular purpose. It is provided "as is" without express or implied
+warranty of any kind.
+
+</pre>
diff --git a/jdk/src/jdk.crypto.token/share/legal/pkcs11wrapper.md b/jdk/src/jdk.crypto.token/share/legal/pkcs11wrapper.md
new file mode 100644
index 0000000..9eb453b
--- /dev/null
+++ b/jdk/src/jdk.crypto.token/share/legal/pkcs11wrapper.md
@@ -0,0 +1,46 @@
+## IAIK (Institute for Applied Information Processing and Communication) PKCS#11 wrapper files v1
+
+### IAIK License
+<pre>
+
+Copyright (c) 2002 Graz University of Technology. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. The end-user documentation included with the redistribution, if any, must
+   include the following acknowledgment:
+
+   "This product includes software developed by IAIK of Graz University of
+    Technology."
+
+   Alternately, this acknowledgment may appear in the software itself, if and
+   wherever such third-party acknowledgments normally appear.
+
+4. The names "Graz University of Technology" and "IAIK of Graz University of
+   Technology" must not be used to endorse or promote products derived from this
+   software without prior written permission.
+
+5. Products derived from this software may not be called "IAIK PKCS Wrapper",
+   nor may "IAIK" appear in their name, without prior written permission of
+   Graz University of Technology.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/j2secmod.h
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_convert.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_crypt.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_digest.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_dual.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_general.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_keymgmt.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_mutex.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_objmgmt.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sessmgmt.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_sign.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/p11_util.c
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs-11v2-20a3.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs-11v2-20a3.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs-11v2-20a3.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs-11v2-20a3.h
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11.h
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11f.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11f.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11f.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11f.h
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11t.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11t.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11t.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11t.h
diff --git a/jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11wrapper.h b/jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11wrapper.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11wrapper.h
rename to jdk/src/jdk.crypto.token/share/native/libj2pkcs11/pkcs11wrapper.h
diff --git a/jdk/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg b/jdk/src/jdk.crypto.token/solaris/conf/security/sunpkcs11-solaris.cfg
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg
rename to jdk/src/jdk.crypto.token/solaris/conf/security/sunpkcs11-solaris.cfg
diff --git a/jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c b/jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c
rename to jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.c
diff --git a/jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.h b/jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.h
rename to jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/j2secmod_md.h
diff --git a/jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c b/jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c
rename to jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.c
diff --git a/jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.h b/jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.h
rename to jdk/src/jdk.crypto.token/unix/native/libj2pkcs11/p11_md.h
diff --git a/jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c b/jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c
rename to jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.c
diff --git a/jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h b/jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h
rename to jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/j2secmod_md.h
diff --git a/jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c b/jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.c
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c
rename to jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.c
diff --git a/jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h b/jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.h
similarity index 100%
rename from jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h
rename to jdk/src/jdk.crypto.token/windows/native/libj2pkcs11/p11_md.h
diff --git a/jdk/src/jdk.internal.le/share/legal/jline.md b/jdk/src/jdk.internal.le/share/legal/jline.md
new file mode 100644
index 0000000..c3c114b
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/legal/jline.md
@@ -0,0 +1,39 @@
+## JLine v2.12.1
+
+### JLine License
+<pre>
+
+Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with
+the distribution.
+
+Neither the name of JLine nor the names of its contributors
+may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/jdk/src/jdk.internal.opt/share/legal/jopt-simple.md b/jdk/src/jdk.internal.opt/share/legal/jopt-simple.md
new file mode 100644
index 0000000..0d40507
--- /dev/null
+++ b/jdk/src/jdk.internal.opt/share/legal/jopt-simple.md
@@ -0,0 +1,27 @@
+## jopt-simple v4.6
+
+### MIT License
+<pre>
+
+Copyright (c) 2004-2015 Paul R. Holser, Jr.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+</pre>
diff --git a/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java
index d74edd5..3c6061c 100644
--- a/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java
+++ b/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java
@@ -430,7 +430,7 @@
          * SHA384withECDSA for a 384-bit EC key.
          *
          * @implNote This implementation makes use of comparable strengths
-         * as defined in Tables 2 and 3 of NIST SP 800-57 Part 1-Rev.3.
+         * as defined in Tables 2 and 3 of NIST SP 800-57 Part 1-Rev.4.
          * Specifically, if a DSA or RSA key with a key size greater than 7680
          * bits, or an EC key with a key size greater than or equal to 512 bits,
          * SHA-512 will be used as the hash function for the signature.
diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java
index 6299213..1b5d48a 100644
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java
@@ -34,6 +34,7 @@
 import java.nio.file.Paths;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import jdk.internal.module.ModuleResolution;
 
 /**
  * Parser for GNU Style Options.
@@ -158,6 +159,31 @@
                                                                 ModuleFinder.of(paths));
                 }
             },
+            new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
+                void process(Main jartool, String opt, String arg) {
+                    ModuleResolution mres = jartool.moduleResolution;
+                    jartool.moduleResolution = mres.withDoNotResolveByDefault();
+                }
+                boolean isExtra() { return true; }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    ModuleResolution mres = ModuleResolution.empty();
+                    if (jartool.moduleResolution.doNotResolveByDefault())
+                        mres.withDoNotResolveByDefault();
+
+                    if (arg.equals("deprecated")) {
+                        jartool.moduleResolution = mres.withDeprecated();
+                    } else if (arg.equals("deprecated-for-removal")) {
+                        jartool.moduleResolution = mres.withDeprecatedForRemoval();
+                    } else if (arg.equals("incubating")) {
+                        jartool.moduleResolution = mres.withIncubating();
+                    } else {
+                        throw new BadArgs("error.bad.reason", arg);
+                    }
+                }
+                boolean isExtra() { return true; }
+            },
             new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
                 void process(Main jartool, String opt, String arg) {
                     jartool.flag0 = true;
@@ -175,17 +201,20 @@
             // Other options
             new Option(true, true, OptionType.OTHER, "--help", "-h") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
-                    if (jartool.info == null) {
-                        if (arg == null) {
-                            jartool.info = Main.Info.HELP;
-                            return;
-                        }
-
-                        if (!arg.equals("compat"))
-                            throw new BadArgs("error.illegal.option", arg).showUsage(true);
-
-                        jartool.info = Main.Info.COMPAT_HELP;
+                    if (arg == null) {
+                        jartool.info = Main.Info.HELP;
+                        return;
                     }
+
+                    if (!arg.equals("compat"))
+                        throw new BadArgs("error.illegal.option", arg).showUsage(true);
+
+                    jartool.info = Main.Info.COMPAT_HELP;
+                }
+            },
+            new Option(false, OptionType.OTHER, "--help-extra") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    jartool.info = Main.Info.HELP_EXTRA;
                 }
             },
             new Option(false, OptionType.OTHER, "--version") {
@@ -229,6 +258,8 @@
 
         boolean isHidden() { return false; }
 
+        boolean isExtra() { return false; }
+
         boolean matches(String opt) {
             for (String a : aliases) {
                 if (a.equals(opt)) {
@@ -292,6 +323,14 @@
     }
 
     static void printHelp(PrintWriter out) {
+        printHelp(out, false);
+    }
+
+    static void printHelpExtra(PrintWriter out) {
+        printHelp(out, true);
+    }
+
+    private static void printHelp(PrintWriter out, boolean printExtra) {
         out.format("%s%n", Main.getMsg("main.help.preopt"));
         for (OptionType type : OptionType.values()) {
             boolean typeHeadingWritten = false;
@@ -304,6 +343,9 @@
                 if (o.isHidden() || name.equals("h")) {
                     continue;
                 }
+                if (o.isExtra() && !printExtra) {
+                    continue;
+                }
                 if (!typeHeadingWritten) {
                     out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
                     typeHeadingWritten = true;
diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
index 6d00af8..8e0fc01 100644
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
@@ -47,7 +47,6 @@
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Function;
-import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -57,11 +56,11 @@
 import java.util.jar.Manifest;
 import java.text.MessageFormat;
 
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
 import jdk.internal.util.jar.JarIndex;
 
 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
@@ -211,6 +210,7 @@
     /* To support additional GNU Style informational options */
     enum Info {
         HELP(GNUStyleOptions::printHelp),
+        HELP_EXTRA(GNUStyleOptions::printHelpExtra),
         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
         USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
         VERSION(GNUStyleOptions::printVersion);
@@ -225,6 +225,7 @@
     /* Modular jar related options */
     Version moduleVersion;
     Pattern modulesToHash;
+    ModuleResolution moduleResolution = ModuleResolution.empty();
     ModuleFinder moduleFinder = ModuleFinder.of();
 
     private static final String MODULE_INFO = "module-info.class";
@@ -1991,12 +1992,13 @@
                   .collect(joining(" "));
     }
 
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
     private void printModuleDescriptor(InputStream entryInputStream)
         throws IOException
     {
-        ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
+        ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
+        ModuleDescriptor md = attrs.descriptor();
+        ModuleHashes hashes = attrs.recordedHashes();
+
         StringBuilder sb = new StringBuilder();
         sb.append("\n");
         if (md.isOpen())
@@ -2043,15 +2045,24 @@
 
         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-        JLMA.hashes(md).ifPresent(hashes ->
-                hashes.names().stream().sorted().forEach(
+        if (hashes != null) {
+            hashes.names().stream().sorted().forEach(
                     mod -> sb.append("\n  hashes ").append(mod).append(" ")
                              .append(hashes.algorithm()).append(" ")
-                             .append(hashes.hashFor(mod))));
+                             .append(toHex(hashes.hashFor(mod))));
+        }
 
         output(sb.toString());
     }
 
+    private static String toHex(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
     private static String toBinaryName(String classname) {
         return (classname.replace('.', '/')) + ".class";
     }
@@ -2212,6 +2223,10 @@
             }
         }
 
+        if (moduleResolution.value() != 0) {
+            extender.moduleResolution(moduleResolution);
+        }
+
         extender.write(baos);
         return baos.toByteArray();
     }
@@ -2228,13 +2243,12 @@
             // Create a module finder that finds the modular JAR
             // being created/updated
             URI uri = Paths.get(fname).toUri();
-            ModuleReference mref = new ModuleReference(descriptor, uri,
-                new Supplier<>() {
-                    @Override
-                    public ModuleReader get() {
-                        throw new UnsupportedOperationException("should not reach here");
-                    }
-                });
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException("should not reach here");
+                }
+            };
 
             // Compose a module finder with the module path and
             // the modular JAR being created or updated
diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties
index dd1d0ff..c575f3b 100644
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties
@@ -46,6 +46,8 @@
 	 together!
 error.bad.dflag=\
         '-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
+error.bad.reason=\
+        bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
 error.nosuch.fileordir=\
         {0} : no such file or directory
 error.write.file=\
@@ -246,6 +248,12 @@
 main.help.opt.create.update.module-path=\
 \  -p, --module-path          Location of module dependence for generating\n\
 \                             the hash
+main.help.opt.create.update.do-not-resolve-by-default=\
+\      --do-not-resolve-by-default  Exclude from the default root set of modules
+main.help.opt.create.update.warn-if-resolved=\
+\      --warn-if-resolved     Hint for a tool to issue a warning if the module\n\
+\                             is resolved. One of deprecated, deprecated-for-removal,\n\
+\                             or incubating
 main.help.opt.create.update.index=\
 \ Operation modifiers valid only in create, update, and generate-index mode:\n
 main.help.opt.create.update.index.no-compress=\
@@ -254,6 +262,8 @@
 \ Other options:\n
 main.help.opt.other.help=\
 \  -?, --help[:compat]        Give this, or optionally the compatibility, help
+main.help.opt.other.help-extra=\
+\      --help-extra           Give help on extra options
 main.help.opt.other.version=\
 \      --version              Print program version
 main.help.postopt=\
diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java
index b5cd9c6..2cd6453 100644
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -315,10 +315,14 @@
             return;
         }
         Value nthArgValue = arguments.get(paramCount - 1);
-        if (nthArgValue == null) {
+        if (nthArgValue == null && argCount == paramCount) {
+            // We have one varargs parameter and it is null
+            // so we don't have to do anything.
             return;
         }
-        Type nthArgType = nthArgValue.type();
+        // If the first varargs parameter is null, then don't
+        // access its type since it can't be an array.
+        Type nthArgType = (nthArgValue == null) ? null : nthArgValue.type();
         if (nthArgType instanceof ArrayTypeImpl) {
             if (argCount == paramCount &&
                 ((ArrayTypeImpl)nthArgType).isAssignableTo(lastParamType)) {
diff --git a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/SDE.c b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/SDE.c
index 6ff7025..1f3aa41 100644
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/SDE.c
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/SDE.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -249,16 +249,19 @@
         int lastLn = 0;
         int sti;
 
+        if (cnt < 0) {
+            return;
+        }
         loadDebugInfo(env, clazz);
         if (!isValid()) {
             return; /* no SDE or not SourceMap - return unchanged */
         }
         sti = stratumTableIndex(globalDefaultStratumId);
-        if (sti == baseStratumIndex) {
+        if (sti == baseStratumIndex || sti < 0) {
             return; /* Java stratum - return unchanged */
         }
         LOG_MISC(("SDE is re-ordering the line table"));
-        for (; cnt-->0; ++fromEntry) {
+        for (; cnt-- > 0; ++fromEntry) {
             int jplsLine = fromEntry->line_number;
             int lti = stiLineTableIndex(sti, jplsLine);
             if (lti >= 0) {
diff --git a/jdk/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c b/jdk/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c
index 33e062e..9692f4f 100644
--- a/jdk/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c
+++ b/jdk/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -196,18 +196,10 @@
     } else if (cmd == SO_LINGER) {
         struct linger arg;
         arg.l_onoff = on;
-
-        if(on) {
-            arg.l_linger = (unsigned short)value.i;
-            if(setsockopt(fd, SOL_SOCKET, SO_LINGER,
-                          (char*)&arg, sizeof(arg)) < 0) {
-                return SYS_ERR;
-            }
-        } else {
-            if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
-                           (char*)&arg, sizeof(arg)) < 0) {
-                return SYS_ERR;
-            }
+        arg.l_linger = (on) ? (unsigned short)value.i : 0;
+        if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
+                       (char*)&arg, sizeof(arg)) < 0) {
+          return SYS_ERR;
         }
     } else if (cmd == SO_SNDBUF) {
         jint buflen = value.i;
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
index c02630d..27f79dd 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
@@ -34,9 +34,9 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UncheckedIOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
 import java.io.Writer;
 import java.lang.module.ModuleDescriptor;
 import java.nio.charset.StandardCharsets;
@@ -58,10 +58,10 @@
 import static java.util.stream.Collectors.*;
 
 import jdk.tools.jlink.internal.BasicImageWriter;
-import jdk.tools.jlink.internal.plugins.FileCopierPlugin.SymImageFile;
 import jdk.tools.jlink.internal.ExecutableImage;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
+import jdk.tools.jlink.plugin.ResourcePoolEntry.Type;
 import jdk.tools.jlink.plugin.ResourcePoolModule;
 import jdk.tools.jlink.plugin.PluginException;
 
@@ -70,6 +70,13 @@
  * Default Image Builder. This builder creates the default runtime image layout.
  */
 public final class DefaultImageBuilder implements ImageBuilder {
+    // Top-level directory names in a modular runtime image
+    public static final String BIN_DIRNAME      = "bin";
+    public static final String CONF_DIRNAME     = "conf";
+    public static final String INCLUDE_DIRNAME  = "include";
+    public static final String LIB_DIRNAME      = "lib";
+    public static final String LEGAL_DIRNAME    = "legal";
+    public static final String MAN_DIRNAME      = "man";
 
     /**
      * The default java executable Image.
@@ -123,6 +130,7 @@
     }
 
     private final Path root;
+    private final Map<String, String> launchers;
     private final Path mdir;
     private final Set<String> modules = new HashSet<>();
     private String targetOsName;
@@ -133,28 +141,13 @@
      * @param root The image root directory.
      * @throws IOException
      */
-    public DefaultImageBuilder(Path root) throws IOException {
-        Objects.requireNonNull(root);
-
-        this.root = root;
+    public DefaultImageBuilder(Path root, Map<String, String> launchers) throws IOException {
+        this.root = Objects.requireNonNull(root);
+        this.launchers = Objects.requireNonNull(launchers);
         this.mdir = root.resolve("lib");
         Files.createDirectories(mdir);
     }
 
-    private void storeRelease(ResourcePool pool) throws IOException {
-        Properties props = new Properties();
-        Optional<ResourcePoolEntry> release = pool.findEntry("/java.base/release");
-        if (release.isPresent()) {
-            try (InputStream is = release.get().content()) {
-                props.load(is);
-            }
-        }
-        File r = new File(root.toFile(), "release");
-        try (FileOutputStream fo = new FileOutputStream(r)) {
-            props.store(fo, null);
-        }
-    }
-
     @Override
     public void storeFiles(ResourcePool files) {
         try {
@@ -172,10 +165,8 @@
                 throw new PluginException("TargetPlatform attribute is missing for java.base module");
             }
 
-            // store 'release' file
-            storeRelease(files);
+            Path bin = root.resolve(BIN_DIRNAME);
 
-            Path bin = root.resolve("bin");
             // check any duplicated resource files
             Map<Path, Set<String>> duplicates = new HashMap<>();
             files.entries()
@@ -224,19 +215,27 @@
                 }
 
                 // jspawnhelper is in lib or lib/<arch>
-                Path lib = root.resolve("lib");
+                Path lib = root.resolve(LIB_DIRNAME);
                 if (Files.isDirectory(lib)) {
                     Files.find(lib, 2, (path, attrs) -> {
                         return path.getFileName().toString().equals("jspawnhelper")
                                 || path.getFileName().toString().equals("jexec");
                     }).forEach(this::setExecutable);
                 }
+
+                // read-only legal notices/license files
+                Path legal = root.resolve(LEGAL_DIRNAME);
+                if (Files.isDirectory(legal)) {
+                    Files.find(legal, 2, (path, attrs) -> {
+                        return attrs.isRegularFile();
+                    }).forEach(this::setReadOnly);
+                }
             }
 
             // If native files are stripped completely, <root>/bin dir won't exist!
             // So, don't bother generating launcher scripts.
             if (Files.isDirectory(bin)) {
-                 prepareApplicationFiles(files, modules);
+                 prepareApplicationFiles(files);
             }
         } catch (IOException ex) {
             throw new PluginException(ex);
@@ -247,22 +246,44 @@
      * Generates launcher scripts.
      *
      * @param imageContent The image content.
-     * @param modules The set of modules that the runtime image contains.
      * @throws IOException
      */
-    protected void prepareApplicationFiles(ResourcePool imageContent, Set<String> modules) throws IOException {
+    protected void prepareApplicationFiles(ResourcePool imageContent) throws IOException {
         // generate launch scripts for the modules with a main class
-        for (String module : modules) {
+        for (Map.Entry<String, String> entry : launchers.entrySet()) {
+            String launcherEntry = entry.getValue();
+            int slashIdx = launcherEntry.indexOf("/");
+            String module, mainClassName;
+            if (slashIdx == -1) {
+                module = launcherEntry;
+                mainClassName = null;
+            } else {
+                module = launcherEntry.substring(0, slashIdx);
+                assert !module.isEmpty();
+                mainClassName = launcherEntry.substring(slashIdx + 1);
+                assert !mainClassName.isEmpty();
+            }
+
             String path = "/" + module + "/module-info.class";
             Optional<ResourcePoolEntry> res = imageContent.findEntry(path);
             if (!res.isPresent()) {
                 throw new IOException("module-info.class not found for " + module + " module");
             }
-            Optional<String> mainClass;
             ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes());
-            mainClass = ModuleDescriptor.read(stream).mainClass();
-            if (mainClass.isPresent()) {
-                Path cmd = root.resolve("bin").resolve(module);
+            Optional<String> mainClass = ModuleDescriptor.read(stream).mainClass();
+            if (mainClassName == null && mainClass.isPresent()) {
+                mainClassName = mainClass.get();
+            }
+
+            if (mainClassName != null) {
+                // make sure main class exists!
+                if (!imageContent.findEntry("/" + module + "/" +
+                        mainClassName.replace('.', '/') + ".class").isPresent()) {
+                    throw new IllegalArgumentException(module + " does not have main class: " + mainClassName);
+                }
+
+                String launcherFile = entry.getKey();
+                Path cmd = root.resolve("bin").resolve(launcherFile);
                 // generate shell script for Unix platforms
                 StringBuilder sb = new StringBuilder();
                 sb.append("#!/bin/sh")
@@ -273,7 +294,7 @@
                         .append("\n");
                 sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
                         .append(module).append('/')
-                        .append(mainClass.get())
+                        .append(mainClassName)
                         .append(" $@\n");
 
                 try (BufferedWriter writer = Files.newBufferedWriter(cmd,
@@ -287,7 +308,7 @@
                 }
                 // generate .bat file for Windows
                 if (isWindows()) {
-                    Path bat = root.resolve("bin").resolve(module + ".bat");
+                    Path bat = root.resolve(BIN_DIRNAME).resolve(launcherFile + ".bat");
                     sb = new StringBuilder();
                     sb.append("@echo off")
                             .append("\r\n");
@@ -297,7 +318,7 @@
                             .append("\r\n");
                     sb.append("\"%DIR%\\java\" %JLINK_VM_OPTIONS% -m ")
                             .append(module).append('/')
-                            .append(mainClass.get())
+                            .append(mainClassName)
                             .append(" %*\r\n");
 
                     try (BufferedWriter writer = Files.newBufferedWriter(bat,
@@ -306,6 +327,8 @@
                         writer.write(sb.toString());
                     }
                 }
+            } else {
+                throw new IllegalArgumentException(module + " doesn't contain main class & main not specified in command line");
             }
         }
     }
@@ -331,6 +354,7 @@
 
         String module = "/" + entry.moduleName() + "/";
         String filename = entry.path().substring(module.length());
+
         // Remove radical native|config|...
         return filename.substring(filename.indexOf('/') + 1);
     }
@@ -344,23 +368,27 @@
                 String filename = entryToFileName(entry);
                 return Paths.get(nativeDir(filename), filename);
             case NATIVE_CMD:
-                return Paths.get("bin", entryToFileName(entry));
+                return Paths.get(BIN_DIRNAME, entryToFileName(entry));
             case CONFIG:
-                return Paths.get("conf", entryToFileName(entry));
+                return Paths.get(CONF_DIRNAME, entryToFileName(entry));
             case HEADER_FILE:
-                return Paths.get("include", entryToFileName(entry));
+                return Paths.get(INCLUDE_DIRNAME, entryToFileName(entry));
             case MAN_PAGE:
-                return Paths.get("man", entryToFileName(entry));
+                return Paths.get(MAN_DIRNAME, entryToFileName(entry));
+            case LEGAL_NOTICE:
+                return Paths.get(LEGAL_DIRNAME, entryToFileName(entry));
             case TOP:
                 return Paths.get(entryToFileName(entry));
-            case OTHER:
-                return Paths.get("other", entryToFileName(entry));
             default:
                 throw new IllegalArgumentException("invalid type: " + entry);
         }
     }
 
     private void accept(ResourcePoolEntry file) throws IOException {
+        if (file.linkedTarget() != null && file.type() != Type.LEGAL_NOTICE) {
+            throw new UnsupportedOperationException("symbolic link not implemented: " + file);
+        }
+
         try (InputStream in = file.content()) {
             switch (file.type()) {
                 case NATIVE_LIB:
@@ -373,28 +401,26 @@
                     p.toFile().setExecutable(true);
                     break;
                 case CONFIG:
-                    writeEntry(in, root.resolve(entryToImagePath(file)));
-                    break;
                 case HEADER_FILE:
-                    writeEntry(in, root.resolve(entryToImagePath(file)));
-                    break;
                 case MAN_PAGE:
                     writeEntry(in, root.resolve(entryToImagePath(file)));
                     break;
-                case TOP:
-                    break;
-                case OTHER:
-                    String filename = entryToFileName(file);
-                    if (file instanceof SymImageFile) {
-                        SymImageFile sym = (SymImageFile) file;
-                        Path target = root.resolve(sym.getTargetPath());
-                        if (!Files.exists(target)) {
-                            throw new IOException("Sym link target " + target
-                                    + " doesn't exist");
-                        }
-                        writeSymEntry(root.resolve(filename), target);
+                case LEGAL_NOTICE:
+                    Path source = entryToImagePath(file);
+                    if (file.linkedTarget() == null) {
+                        writeEntry(in, root.resolve(source));
                     } else {
-                        writeEntry(in, root.resolve(filename));
+                        Path target = entryToImagePath(file.linkedTarget());
+                        Path relPath = source.getParent().relativize(target);
+                        writeSymLinkEntry(root.resolve(source), relPath);
+                    }
+                    break;
+                case TOP:
+                    // Copy TOP files of the "java.base" module (only)
+                    if ("java.base".equals(file.moduleName())) {
+                        writeEntry(in, root.resolve(entryToImagePath(file)));
+                    } else {
+                        throw new InternalError("unexpected TOP entry: " + file.path());
                     }
                     break;
                 default:
@@ -417,16 +443,36 @@
         Files.createLink(dstFile, target);
     }
 
+    /*
+     * Create a symbolic link to the given target if the target platform
+     * supports symbolic link; otherwise, it will create a tiny file
+     * to contain the path to the target.
+     */
+    private void writeSymLinkEntry(Path dstFile, Path target) throws IOException {
+        Objects.requireNonNull(dstFile);
+        Objects.requireNonNull(target);
+        Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
+        if (!isWindows() && root.getFileSystem()
+                                .supportedFileAttributeViews()
+                                .contains("posix")) {
+            Files.createSymbolicLink(dstFile, target);
+        } else {
+            try (BufferedWriter writer = Files.newBufferedWriter(dstFile)) {
+                writer.write(String.format("Please see %s%n", target.toString()));
+            }
+        }
+    }
+
     private String nativeDir(String filename) {
         if (isWindows()) {
             if (filename.endsWith(".dll") || filename.endsWith(".diz")
                     || filename.endsWith(".pdb") || filename.endsWith(".map")) {
-                return "bin";
+                return BIN_DIRNAME;
             } else {
-                return "lib";
+                return LIB_DIRNAME;
             }
         } else {
-            return "lib";
+            return LIB_DIRNAME;
         }
     }
 
@@ -449,6 +495,21 @@
         }
     }
 
+    /**
+     * chmod ugo-w file
+     */
+    private void setReadOnly(Path file) {
+        try {
+            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+            perms.remove(PosixFilePermission.OWNER_WRITE);
+            perms.remove(PosixFilePermission.GROUP_WRITE);
+            perms.remove(PosixFilePermission.OTHERS_WRITE);
+            Files.setPosixFilePermissions(file, perms);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
     private static void createUtf8File(File file, String content) throws IOException {
         try (OutputStream fout = new FileOutputStream(file);
                 Writer output = new OutputStreamWriter(fout, "UTF-8")) {
@@ -465,7 +526,7 @@
     private static void patchScripts(ExecutableImage img, List<String> args) throws IOException {
         Objects.requireNonNull(args);
         if (!args.isEmpty()) {
-            Files.find(img.getHome().resolve("bin"), 2, (path, attrs) -> {
+            Files.find(img.getHome().resolve(BIN_DIRNAME), 2, (path, attrs) -> {
                 return img.getModules().contains(path.getFileName().toString());
             }).forEach((p) -> {
                 try {
@@ -497,7 +558,7 @@
     }
 
     public static ExecutableImage getExecutableImage(Path root) {
-        Path binDir = root.resolve("bin");
+        Path binDir = root.resolve(BIN_DIRNAME);
         if (Files.exists(binDir.resolve("java")) ||
             Files.exists(binDir.resolve("java.exe"))) {
             return new DefaultExecutableImage(root, retrieveModules(root));
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java
index 9c89607..c56346b 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java
@@ -48,6 +48,7 @@
             NATIVE_LIB,
             NATIVE_CMD,
             HEADER_FILE,
+            LEGAL_NOTICE,
             MAN_PAGE,
             SERVICE;
         }
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ArchiveEntryResourcePoolEntry.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ArchiveEntryResourcePoolEntry.java
index 01fd19d..5791981 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ArchiveEntryResourcePoolEntry.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ArchiveEntryResourcePoolEntry.java
@@ -66,19 +66,21 @@
     private static ResourcePoolEntry.Type getImageFileType(Archive.Entry entry) {
         switch(entry.type()) {
             case CLASS_OR_RESOURCE:
-                return ResourcePoolEntry.Type.CLASS_OR_RESOURCE;
+                return Type.CLASS_OR_RESOURCE;
             case CONFIG:
-                return ResourcePoolEntry.Type.CONFIG;
-            case NATIVE_CMD:
-                return ResourcePoolEntry.Type.NATIVE_CMD;
-            case NATIVE_LIB:
-                return ResourcePoolEntry.Type.NATIVE_LIB;
+                return Type.CONFIG;
             case HEADER_FILE:
-                return ResourcePoolEntry.Type.HEADER_FILE;
+                return Type.HEADER_FILE;
+            case LEGAL_NOTICE:
+                return Type.LEGAL_NOTICE;
             case MAN_PAGE:
-                return ResourcePoolEntry.Type.MAN_PAGE;
+                return Type.MAN_PAGE;
+            case NATIVE_CMD:
+                return Type.NATIVE_CMD;
+            case NATIVE_LIB:
+                return Type.NATIVE_LIB;
             default:
-                return ResourcePoolEntry.Type.OTHER;
+                throw new IllegalArgumentException("Unknown archive entry type: " + entry.type());
         }
     }
 }
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
index 4a5cbff..0eb7ade 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
@@ -53,7 +53,9 @@
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
 
 /**
  * Implementation for the jlink tool.
@@ -109,6 +111,27 @@
             task.options.output = path;
         }, "--output"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
+            String[] values = arg.split("=");
+            // check values
+            if (values.length != 2 || values[0].isEmpty() || values[1].isEmpty()) {
+                throw taskHelper.newBadArgs("err.launcher.value.format", arg);
+            } else {
+                String commandName = values[0];
+                String moduleAndMain = values[1];
+                int idx = moduleAndMain.indexOf("/");
+                if (idx != -1) {
+                    if (moduleAndMain.substring(0, idx).isEmpty()) {
+                        throw taskHelper.newBadArgs("err.launcher.module.name.empty", arg);
+                    }
+
+                    if (moduleAndMain.substring(idx + 1).isEmpty()) {
+                        throw taskHelper.newBadArgs("err.launcher.main.class.empty", arg);
+                    }
+                }
+                task.options.launchers.put(commandName, moduleAndMain);
+            }
+        }, "--launcher"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
             if ("little".equals(arg)) {
                 task.options.endian = ByteOrder.LITTLE_ENDIAN;
             } else if ("big".equals(arg)) {
@@ -168,6 +191,7 @@
         final Set<String> limitMods = new HashSet<>();
         final Set<String> addMods = new HashSet<>();
         Path output;
+        final Map<String, String> launchers = new HashMap<>();
         Path packagedModulesPath;
         ByteOrder endian = ByteOrder.nativeOrder();
         boolean ignoreSigning = false;
@@ -260,7 +284,8 @@
                                     config.getModules(),
                                     config.getByteOrder(),
                                     null,
-                                    IGNORE_SIGNING_DEFAULT);
+                                    IGNORE_SIGNING_DEFAULT,
+                                    null);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
@@ -284,7 +309,7 @@
     }
 
     private void postProcessOnly(Path existingImage) throws Exception {
-        PluginsConfiguration config = taskHelper.getPluginsConfig(null);
+        PluginsConfiguration config = taskHelper.getPluginsConfig(null, null);
         ExecutableImage img = DefaultImageBuilder.getExecutableImage(existingImage);
         if (img == null) {
             throw taskHelper.newBadArgs("err.existing.image.invalid");
@@ -328,11 +353,12 @@
                                                           roots,
                                                           options.endian,
                                                           options.packagedModulesPath,
-                                                          options.ignoreSigning);
+                                                          options.ignoreSigning,
+                                                          log);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.
-                parseConfiguration(taskHelper.getPluginsConfig(options.output));
+                parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers));
 
         //Ask the stack to proceed
         stack.operate(imageProvider);
@@ -344,9 +370,7 @@
      */
     private ModuleFinder modulePathFinder() {
         Path[] entries = options.modulePath.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, entries);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
         if (!options.limitMods.isEmpty()) {
             finder = limitFinder(finder, options.limitMods, Collections.emptySet());
         }
@@ -364,8 +388,7 @@
                                                Set<String> roots)
     {
         Path[] entries = paths.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, entries);
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
 
         // if limitmods is specified then limit the universe
         if (!limitMods.isEmpty()) {
@@ -386,7 +409,8 @@
                                                      Set<String> roots,
                                                      ByteOrder order,
                                                      Path retainModulesPath,
-                                                     boolean ignoreSigning)
+                                                     boolean ignoreSigning,
+                                                     PrintWriter log)
             throws IOException
     {
         if (roots.isEmpty()) {
@@ -398,6 +422,27 @@
                                  ModuleFinder.of(),
                                  roots);
 
+        // emit warning for modules that end with a digit
+        cf.modules().stream()
+            .map(ResolvedModule::name)
+            .filter(mn -> !Checks.hasLegalModuleNameLastCharacter(mn))
+            .forEach(mn -> System.err.println("WARNING: Module name \""
+                                              + mn + "\" may soon be illegal"));
+
+        // emit a warning for any incubating modules in the configuration
+        if (log != null) {
+            String im = cf.modules()
+                          .stream()
+                          .map(ResolvedModule::reference)
+                          .filter(ModuleResolution::hasIncubatingWarning)
+                          .map(ModuleReference::descriptor)
+                          .map(ModuleDescriptor::name)
+                          .collect(Collectors.joining(", "));
+
+            if (!"".equals(im))
+                log.println("WARNING: Using incubator modules: " + im);
+        }
+
         Map<String, Path> mods = cf.modules().stream()
             .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
         return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java
index 0a528ee..2450db6 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java
@@ -130,14 +130,16 @@
                 return EntryType.CLASS_OR_RESOURCE;
             case CONFIG:
                 return EntryType.CONFIG;
+            case HEADER_FILES:
+                return EntryType.HEADER_FILE;
+            case LEGAL_NOTICES:
+                return EntryType.LEGAL_NOTICE;
+            case MAN_PAGES:
+                return EntryType.MAN_PAGE;
             case NATIVE_LIBS:
                 return EntryType.NATIVE_LIB;
             case NATIVE_CMDS:
                 return EntryType.NATIVE_CMD;
-            case HEADER_FILES:
-                return EntryType.HEADER_FILE;
-            case MAN_PAGES:
-                return EntryType.MAN_PAGE;
             default:
                 throw new InternalError("unexpected entry: " + section);
         }
@@ -145,13 +147,28 @@
 
     private Entry toEntry(JmodFile.Entry entry) {
         EntryType type = toEntryType(entry.section());
+        String prefix = entry.section().jmodDir();
         String name = entry.name();
-        String path = entry.section().jmodDir() + "/" + name;
-
-        // Entry.path() contains the kind of file native, conf, bin, ...
-        // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
+        String path = prefix + "/" + name;
         String resourceName = name;
-        if (type != EntryType.CLASS_OR_RESOURCE) {
+
+        // The resource name represents the path of ResourcePoolEntry
+        // and its subpath defines the ultimate path to be written
+        // to the image relative to the directory corresponding to that
+        // resource type.
+        //
+        // For classes and resources, the resource name does not have
+        // a prefix (<package>/<name>). They will be written to the jimage.
+        //
+        // For other kind of entries, it will keep the section name as
+        // the prefix for unique identification.  The subpath (taking
+        // out the section name) is the pathname to be written to the
+        // corresponding directory in the image.
+        //
+        if (type == EntryType.LEGAL_NOTICE) {
+            // legal notices are written to per-module directory
+            resourceName = prefix + "/" + moduleName + "/" + name;
+        } else if (type != EntryType.CLASS_OR_RESOURCE) {
             resourceName = path;
         }
 
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
index 63ce3cd..9c81c77 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java
@@ -28,6 +28,7 @@
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -78,10 +79,12 @@
     }
 
     private static ModuleReference moduleReference(ModuleDescriptor desc) {
-        return new ModuleReference(desc, null, () -> {
-            IOException ioe = new IOException("<module reader unsupported>");
-            throw new UncheckedIOException(ioe);
-        });
+        return new ModuleReference(desc, null) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 
     private static Map<String, ModuleReference> allModRefs(ResourcePool pool) {
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolEntryFactory.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolEntryFactory.java
index 664e60e..e2a0218 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolEntryFactory.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolEntryFactory.java
@@ -51,6 +51,12 @@
                 original.path(), original.type(), file);
     }
 
+    public static ResourcePoolEntry createSymbolicLink(String path,
+                                                       ResourcePoolEntry.Type type,
+                                                       ResourcePoolEntry target) {
+        return new SymLinkResourcePoolEntry(moduleFrom(path), path, type, target);
+    }
+
     private static String moduleFrom(String path) {
         Objects.requireNonNull(path);
         if (path.isEmpty() || path.charAt(0) != '/') {
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
index 10d1e73..e3b0461 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java
@@ -52,8 +52,8 @@
         String p = "/" + mod.name() + "/module-info.class";
         Optional<ResourcePoolEntry> content = mod.findEntry(p);
         if (!content.isPresent()) {
-              throw new PluginException("No module-info for " + mod.name()
-                      + " module");
+              throw new PluginException("module-info.class not found for " +
+                  mod.name() + " module");
         }
         ByteBuffer bb = ByteBuffer.wrap(content.get().contentBytes());
         try {
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/SymLinkResourcePoolEntry.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/SymLinkResourcePoolEntry.java
new file mode 100644
index 0000000..6f96c36
--- /dev/null
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/SymLinkResourcePoolEntry.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * A symbolic link ResourcePoolEntry.  It will be created in the image
+ * as a symbolic link to the target when the target platform supports
+ * symbolic links; otherwise, it will create a file containing the
+ * path to the target file.
+ */
+public class SymLinkResourcePoolEntry extends AbstractResourcePoolEntry {
+    private final ResourcePoolEntry target;
+
+    /**
+     * Create a new SymLinkResourcePoolEntry.
+     *
+     * @param module The module name.
+     * @param path   The path for the resource content.
+     * @param type   The data type.
+     * @param target Target entry in the image
+     */
+    public SymLinkResourcePoolEntry(String module,
+                                    String path,
+                                    ResourcePoolEntry.Type type,
+                                    ResourcePoolEntry target) {
+        super(module, path, type);
+        this.target = Objects.requireNonNull(target);
+    }
+
+    @Override
+    public long contentLength() {
+        return target.contentLength();
+    }
+
+    @Override
+    public InputStream content() {
+        return target.content();
+    }
+
+    @Override
+    public ResourcePoolEntry linkedTarget() {
+        return target;
+    }
+}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java
index fc7d85f..19044f5 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java
@@ -58,7 +58,7 @@
 import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
 import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
 import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
 
 /**
  *
@@ -403,7 +403,7 @@
             return null;
         }
 
-        private PluginsConfiguration getPluginsConfig(Path output
+        private PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers
                     ) throws IOException, BadArgs {
             if (output != null) {
                 if (Files.exists(output)) {
@@ -440,9 +440,9 @@
             // recreate or postprocessing don't require an output directory.
             ImageBuilder builder = null;
             if (output != null) {
-                builder = new DefaultImageBuilder(output);
-
+                builder = new DefaultImageBuilder(output, launchers);
             }
+
             return new Jlink.PluginsConfiguration(pluginsList,
                     builder, lastSorter);
         }
@@ -745,9 +745,9 @@
                 + bundleHelper.getMessage(key, args));
     }
 
-    public PluginsConfiguration getPluginsConfig(Path output)
+    public PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers)
             throws IOException, BadArgs {
-        return pluginOptions.getPluginsConfig(output);
+        return pluginOptions.getPluginsConfig(output, launchers);
     }
 
     public Path getExistingImage() {
@@ -765,9 +765,7 @@
     static Layer createPluginsLayer(List<Path> paths) {
 
         Path[] dirs = paths.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, dirs);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
         Configuration bootConfiguration = Layer.boot().configuration();
         try {
             Configuration cf = bootConfiguration
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java
index 5b06d81..dd0889d 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java
@@ -49,6 +49,7 @@
  */
 public final class AppRuntimeImageBuilder {
     private Path outputDir = null;
+    private Map<String, String> launchers = Collections.emptyMap();
     private List<Path> modulePath = null;
     private Set<String> addModules = null;
     private Set<String> limitModules = null;
@@ -62,6 +63,10 @@
         outputDir = value;
     }
 
+    public void setLaunchers(Map<String, String> value) {
+        launchers = value;
+    }
+
     public void setModulePath(List<Path> value) {
         modulePath = value;
     }
@@ -120,7 +125,7 @@
 
         // build the image
         Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration(
-            plugins, new DefaultImageBuilder(outputDir), null);
+            plugins, new DefaultImageBuilder(outputDir, launchers), null);
         Jlink jlink = new Jlink();
         jlink.build(jlinkConfig, pluginConfig);
     }
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java
deleted file mode 100644
index a0384bb..0000000
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.internal.plugins;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import jdk.tools.jlink.internal.PathResourcePoolEntry;
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.ResourcePoolBuilder;
-import jdk.tools.jlink.plugin.ResourcePoolEntry;
-import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.Utils;
-
-/**
- *
- * Copy files to image from various locations.
- */
-public class FileCopierPlugin implements Plugin {
-
-    public static final String NAME = "copy-files";
-
-    private static final class CopiedFile {
-
-        Path source;
-        Path target;
-    }
-    private final List<CopiedFile> files = new ArrayList<>();
-
-    /**
-     * Symbolic link to another path.
-     */
-    public static abstract class SymImageFile extends PathResourcePoolEntry {
-
-        private final String targetPath;
-
-        public SymImageFile(String targetPath, String module, String path,
-                ResourcePoolEntry.Type type, Path file) {
-            super(module, path, type, file);
-            this.targetPath = targetPath;
-        }
-
-        public String getTargetPath() {
-            return targetPath;
-        }
-    }
-
-    private static final class SymImageFileImpl extends SymImageFile {
-
-        public SymImageFileImpl(String targetPath, Path file, String module,
-                String path, ResourcePoolEntry.Type type) {
-            super(targetPath, module, path, type, file);
-        }
-    }
-
-    private static final class DirectoryCopy implements FileVisitor<Path> {
-
-        private final Path source;
-        private final ResourcePoolBuilder pool;
-        private final String targetDir;
-        private final List<SymImageFile> symlinks = new ArrayList<>();
-
-        DirectoryCopy(Path source, ResourcePoolBuilder pool, String targetDir) {
-            this.source = source;
-            this.pool = pool;
-            this.targetDir = targetDir;
-        }
-
-        @Override
-        public FileVisitResult preVisitDirectory(Path dir,
-                BasicFileAttributes attrs) throws IOException {
-            return FileVisitResult.CONTINUE;
-        }
-
-        @Override
-        public FileVisitResult visitFile(Path file,
-                BasicFileAttributes attrs) throws IOException {
-            Objects.requireNonNull(file);
-            Objects.requireNonNull(attrs);
-            String path = targetDir + "/" + source.relativize(file);
-            if (attrs.isSymbolicLink()) {
-                Path symTarget = Files.readSymbolicLink(file);
-                if (!Files.exists(symTarget)) {
-                    // relative to file parent?
-                    Path parent = file.getParent();
-                    if (parent != null) {
-                        symTarget = parent.resolve(symTarget);
-                    }
-                }
-                if (!Files.exists(symTarget)) {
-                    System.err.println("WARNING: Skipping sym link, target "
-                            + Files.readSymbolicLink(file) + "not found");
-                    return FileVisitResult.CONTINUE;
-                }
-                SymImageFileImpl impl = new SymImageFileImpl(symTarget.toString(),
-                        file, path, Objects.requireNonNull(file.getFileName()).toString(),
-                        ResourcePoolEntry.Type.OTHER);
-                symlinks.add(impl);
-            } else {
-                addFile(pool, file, path);
-            }
-            return FileVisitResult.CONTINUE;
-        }
-
-        @Override
-        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
-                throws IOException {
-            if (exc != null) {
-                throw exc;
-            }
-            return FileVisitResult.CONTINUE;
-        }
-
-        @Override
-        public FileVisitResult visitFileFailed(Path file, IOException exc)
-                throws IOException {
-            throw exc;
-        }
-    }
-
-    private static void addFile(ResourcePoolBuilder pool, Path file, String path)
-            throws IOException {
-        Objects.requireNonNull(pool);
-        Objects.requireNonNull(file);
-        Objects.requireNonNull(path);
-        ResourcePoolEntry impl = ResourcePoolEntry.create(
-                "/java.base/other/" + path,
-                ResourcePoolEntry.Type.OTHER, file);
-        try {
-            pool.add(impl);
-        } catch (Exception ex) {
-            throw new IOException(ex);
-        }
-    }
-
-    @Override
-    public void configure(Map<String, String> config) {
-        List<String> arguments = Utils.parseList(config.get(NAME));
-        if (arguments.isEmpty()) {
-            throw new RuntimeException("Invalid argument for " + NAME);
-        }
-
-        String javahome = System.getProperty("java.home");
-        for (String a : arguments) {
-            int i = a.indexOf("=");
-            CopiedFile cf = new CopiedFile();
-            if (i == -1) {
-                Path file = Paths.get(a);
-                if (file.isAbsolute()) {
-                    cf.source = file;
-                    // The target is the image root directory.
-                    cf.target = file.getFileName();
-                } else {
-                    file = new File(javahome, a).toPath();
-                    cf.source = file;
-                    cf.target = Paths.get(a);
-                }
-            } else {
-                String target = a.substring(i + 1);
-                String f = a.substring(0, i);
-                Path file = Paths.get(f);
-                if (file.isAbsolute()) {
-                    cf.source = file;
-                } else {
-                    cf.source = new File(javahome,
-                            file.toFile().getPath()).toPath();
-                }
-                cf.target = Paths.get(target);
-            }
-            if (!Files.exists(cf.source)) {
-                System.err.println("Skipping file " + cf.source
-                        + ", it doesn't exist");
-            } else {
-                files.add(cf);
-            }
-        }
-    }
-
-    @Override
-    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
-        in.transformAndCopy((file) -> {
-            return file;
-        }, out);
-
-        // Add new files.
-        try {
-            for (CopiedFile file : files) {
-                if (Files.isRegularFile(file.source)) {
-                    addFile(out, file.source, file.target.toString());
-                } else if (Files.isDirectory(file.source)) {
-                    DirectoryCopy dc = new DirectoryCopy(file.source,
-                            out, file.target.toString());
-                    Files.walkFileTree(file.source, dc);
-                    // Add symlinks after actual content
-                    for (SymImageFile imf : dc.symlinks) {
-                        try {
-                            out.add(imf);
-                        } catch (Exception ex) {
-                            throw new PluginException(ex);
-                        }
-                    }
-                }
-            }
-        } catch (IOException ex) {
-            throw new UncheckedIOException(ex);
-        }
-
-        return out.build();
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public String getDescription() {
-        return PluginsResourceBundle.getDescription(NAME);
-    }
-
-    @Override
-    public boolean hasArguments() {
-        return true;
-    }
-
-    @Override
-    public String getArgumentsDescription() {
-       return PluginsResourceBundle.getArgument(NAME);
-    }
-}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java
new file mode 100644
index 0000000..4cf5b0c
--- /dev/null
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.tools.jlink.internal.ModuleSorter;
+import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.ResourcePool;
+import jdk.tools.jlink.plugin.ResourcePoolBuilder;
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+import jdk.tools.jlink.plugin.ResourcePoolEntry.Type;
+import jdk.tools.jlink.plugin.ResourcePoolModule;
+
+/**
+ * A plugin to de-duplicate the legal notices from JMOD files.
+ *
+ * For a de-duplicated legal notice, the actual copy will be in
+ * the base module and with symbolic links in other modules.
+ * On platform that does not support symbolic links, a file
+ * will be created to contain the path to the linked target.
+ */
+public final class LegalNoticeFilePlugin implements Plugin {
+
+    private static final String NAME = "dedup-legal-notices";
+    private static final String ERROR_IF_NOT_SAME_CONTENT = "error-if-not-same-content";
+    private final Map<String, List<ResourcePoolEntry>> licenseOrNotice =
+        new HashMap<>();
+
+    private boolean errorIfNotSameContent = false;
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Set<State> getState() {
+        return EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        String arg = config.get(NAME);
+        if (arg != null) {
+            if (arg.equals(ERROR_IF_NOT_SAME_CONTENT)) {
+                errorIfNotSameContent = true;
+            } else {
+                throw new IllegalArgumentException(NAME + ": " + arg);
+            }
+        }
+    }
+
+    @Override
+    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+        // Sort modules in the topological order
+        // process all legal notices/licenses entries
+        new ModuleSorter(in.moduleView())
+            .sorted()
+            .flatMap(ResourcePoolModule::entries)
+            .filter(entry -> entry.type() == Type.LEGAL_NOTICE)
+            .forEach(this::dedupLegalNoticeEntry);
+
+        in.entries()
+            .filter(entry -> entry.type() != Type.LEGAL_NOTICE)
+            .forEach(out::add);
+
+        licenseOrNotice.values().stream()
+            .flatMap(List::stream)
+            .forEach(out::add);
+        return out.build();
+    }
+
+    private void dedupLegalNoticeEntry(ResourcePoolEntry entry) {
+        Path path = Utils.getJRTFSPath(entry.path());
+        Path filename = path.getFileName();
+
+        List<ResourcePoolEntry> entries =
+            licenseOrNotice.computeIfAbsent(filename.toString(), _k -> new ArrayList<>());
+
+        Optional<ResourcePoolEntry> otarget = entries.stream()
+            .filter(e -> e.linkedTarget() == null)
+            .filter(e -> Arrays.equals(e.contentBytes(), entry.contentBytes()))
+            .findFirst();
+        if (!otarget.isPresent()) {
+            if (errorIfNotSameContent) {
+                // all legal notices of the same file name are expected
+                // to contain the same content
+                Optional<ResourcePoolEntry> ores =
+                    entries.stream().filter(e -> e.linkedTarget() == null)
+                           .findAny();
+
+                if (ores.isPresent()) {
+                    throw new PluginException(ores.get().path() + " " +
+                        entry.path() + " contain different content");
+                }
+            }
+            entries.add(entry);
+        } else {
+            entries.add(ResourcePoolEntry.createSymLink(entry.path(),
+                                                        entry.type(),
+                                                        otarget.get()));
+        }
+    }
+
+    @Override
+    public Category getType() {
+        return Category.TRANSFORMER;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(NAME);
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+        return PluginsResourceBundle.getArgument(NAME);
+    }
+}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java
deleted file mode 100644
index 6be8c5f..0000000
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java
+++ /dev/null
@@ -1,1083 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.internal.plugins;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.IntSupplier;
-
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleInfoExtender;
-import jdk.internal.module.SystemModules;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.*;
-
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*;
-import jdk.tools.jlink.plugin.ResourcePoolBuilder;
-import jdk.tools.jlink.plugin.ResourcePoolEntry;
-
-/**
- * Jlink plugin to reconstitute module descriptors for system modules.
- * It will extend module-info.class with Packages attribute,
- * if not present. It also determines the number of packages of
- * the boot layer at link time.
- *
- * This plugin will override jdk.internal.module.SystemModules class
- *
- * @see java.lang.module.SystemModuleFinder
- * @see SystemModules
- */
-public final class SystemModuleDescriptorPlugin implements Plugin {
-    private static final JavaLangModuleAccess JLMA =
-        SharedSecrets.getJavaLangModuleAccess();
-
-    private static final String NAME = "system-modules";
-    private static final String DESCRIPTION =
-        PluginsResourceBundle.getDescription(NAME);
-
-    private boolean enabled;
-    public SystemModuleDescriptorPlugin() {
-        this.enabled = true;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public String getDescription() {
-        return DESCRIPTION;
-    }
-
-    @Override
-    public Set<State> getState() {
-        return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
-                       : EnumSet.of(State.DISABLED);
-    }
-
-    @Override
-    public void configure(Map<String, String> config) {
-        if (config.containsKey(NAME)) {
-            enabled = false;
-        }
-    }
-
-    @Override
-    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
-        if (!enabled) {
-            throw new PluginException(NAME + " was set");
-        }
-
-        SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
-
-        // generate the byte code to create ModuleDescriptors
-        // skip parsing module-info.class and skip name check
-        in.moduleView().modules().forEach(module -> {
-
-            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
-                // automatic module not supported yet
-                () ->  new PluginException("module-info.class not found for " +
-                    module.name() + " module")
-            );
-
-            assert module.name().equals(data.moduleName());
-            try {
-                ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes());
-                ModuleDescriptor md = ModuleDescriptor.read(bain);
-                validateNames(md);
-
-                Set<String> packages = module.packages();
-                generator.addModule(md, module.packages());
-
-                // add Packages attribute if not exist
-                if (md.packages().isEmpty() && packages.size() > 0) {
-                    bain.reset();
-                    ModuleInfoRewriter minfoWriter =
-                        new ModuleInfoRewriter(bain, module.packages());
-                    // replace with the overridden version
-                    data = data.copyWithContent(minfoWriter.getBytes());
-                }
-                out.add(data);
-            } catch (IOException e) {
-                throw new PluginException(e);
-            }
-        });
-
-        // Generate the new class
-        ClassWriter cwriter = generator.getClassWriter();
-        in.entries().forEach(data -> {
-            if (data.path().endsWith("module-info.class"))
-                return;
-            if (generator.isOverriddenClass(data.path())) {
-                byte[] bytes = cwriter.toByteArray();
-                ResourcePoolEntry ndata = data.copyWithContent(bytes);
-                out.add(ndata);
-            } else {
-                out.add(data);
-            }
-        });
-
-        return out.build();
-    }
-
-    /*
-     * Add Packages attribute
-     */
-    class ModuleInfoRewriter extends ByteArrayOutputStream {
-        final ModuleInfoExtender extender;
-        ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
-            this.extender = ModuleInfoExtender.newExtender(in);
-            // Add Packages attribute
-            this.extender.packages(packages);
-            this.extender.write(this);
-        }
-
-        byte[] getBytes() {
-            return buf;
-        }
-    }
-
-    void validateNames(ModuleDescriptor md) {
-        Checks.requireModuleName(md.name());
-        for (Requires req : md.requires()) {
-            Checks.requireModuleName(req.name());
-        }
-        for (Exports e : md.exports()) {
-            Checks.requirePackageName(e.source());
-            if (e.isQualified())
-                e.targets().forEach(Checks::requireModuleName);
-        }
-        for (Opens opens : md.opens()) {
-            Checks.requirePackageName(opens.source());
-            if (opens.isQualified())
-                opens.targets().forEach(Checks::requireModuleName);
-        }
-        for (Provides provides : md.provides()) {
-            Checks.requireServiceTypeName(provides.service());
-            provides.providers().forEach(Checks::requireServiceProviderName);
-        }
-        for (String service : md.uses()) {
-            Checks.requireServiceTypeName(service);
-        }
-        for (String pn : md.packages()) {
-            Checks.requirePackageName(pn);
-        }
-    }
-
-    /*
-     * Returns the initial capacity for a new Set or Map of the given size
-     * to avoid resizing.
-     */
-    static final int initialCapacity(int size) {
-        if (size == 0) {
-            return 0;
-        } else {
-            // Adjust to try and get size/capacity as close to the
-            // HashSet/HashMap default load factor without going over.
-            return (int)(Math.ceil((double)size / 0.75));
-        }
-    }
-
-    /**
-     * ClassWriter of a new jdk.internal.module.SystemModules class
-     * to reconstitute ModuleDescriptor of the system modules.
-     */
-    static class SystemModulesClassGenerator {
-        private static final String CLASSNAME =
-            "jdk/internal/module/SystemModules";
-        private static final String MODULE_DESCRIPTOR_BUILDER =
-            "jdk/internal/module/Builder";
-        private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
-            "[Ljava/lang/module/ModuleDescriptor;";
-        private static final String REQUIRES_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Requires$Modifier";
-        private static final String EXPORTS_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Exports$Modifier";
-        private static final String OPENS_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Opens$Modifier";
-
-        // static variables in SystemModules class
-        private static final String MODULE_NAMES = "MODULE_NAMES";
-        private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
-        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
-
-        private static final int MAX_LOCAL_VARS = 256;
-
-        private final int BUILDER_VAR    = 0;
-        private final int MD_VAR         = 1;  // variable for ModuleDescriptor
-        private int nextLocalVar         = 2;  // index to next local variable
-
-        private final ClassWriter cw;
-        private MethodVisitor mv;
-        private int nextModulesIndex = 0;
-
-        // list of all ModuleDescriptorBuilders, invoked in turn when building.
-        private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
-
-        // module name to hash
-        private final Map<String, byte[]> modulesToHash = new HashMap<>();
-
-        // module name to index in MODULES_TO_HASH
-        private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
-
-        // A builder to create one single Set instance for a given set of
-        // names or modifiers to reduce the footprint
-        // e.g. target modules of qualified exports
-        private final DedupSetBuilder dedupSetBuilder
-            = new DedupSetBuilder(this::getNextLocalVar);
-
-        public SystemModulesClassGenerator() {
-            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
-                                      ClassWriter.COMPUTE_FRAMES);
-        }
-
-        private int getNextLocalVar() {
-            return nextLocalVar++;
-        }
-
-        /*
-         * static initializer initializing the static fields
-         *
-         * static Map<String, ModuleDescriptor> map = new HashMap<>();
-         */
-        private void clinit(int numModules, int numPackages) {
-            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
-                     null, "java/lang/Object", null);
-
-            // public static String[] MODULE_NAMES = new String[] {....};
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
-                    "[Ljava/lang/String;", null, null)
-                    .visitEnd();
-
-            // public static byte[][] MODULES_TO_HASH
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
-                "[[B", null, null)
-                .visitEnd();
-
-            // public static int PACKAGES_IN_BOOT_LAYER;
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
-                    "I", null, numPackages)
-                    .visitEnd();
-
-            this.mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
-                    null, null);
-            mv.visitCode();
-
-            // create the MODULE_NAMES array
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-
-            int index = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                mv.visitInsn(DUP);                  // arrayref
-                pushInt(index++);
-                mv.visitLdcInsn(builder.md.name()); // value
-                mv.visitInsn(AASTORE);
-            }
-
-            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
-                    "[Ljava/lang/String;");
-
-            // create the MODULES_TO_HASH array
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "[B");
-
-            index = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                String mn = builder.md.name();
-                byte[] recordedHash = modulesToHash.get(mn);
-                if (recordedHash != null) {
-                    mv.visitInsn(DUP);              // arrayref
-                    pushInt(index);
-                    pushInt(recordedHash.length);
-                    mv.visitIntInsn(NEWARRAY, T_BYTE);
-                    for (int i = 0; i < recordedHash.length; i++) {
-                        mv.visitInsn(DUP);              // arrayref
-                        pushInt(i);
-                        mv.visitIntInsn(BIPUSH, recordedHash[i]);
-                        mv.visitInsn(BASTORE);
-                    }
-                    mv.visitInsn(AASTORE);
-                    modulesToHashIndex.put(mn, index);
-                }
-                index++;
-            }
-
-            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
-
-            mv.visitInsn(RETURN);
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-
-        }
-
-        /*
-         * Adds the given ModuleDescriptor to the system module list, and
-         * prepares mapping from various Sets to SetBuilders to emit an
-         * optimized number of sets during build.
-         */
-        public void addModule(ModuleDescriptor md, Set<String> packages) {
-            ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
-            builders.add(builder);
-
-            // exports
-            for (Exports e : md.exports()) {
-                dedupSetBuilder.stringSet(e.targets());
-                dedupSetBuilder.exportsModifiers(e.modifiers());
-            }
-
-            // opens
-            for (Opens opens : md.opens()) {
-                dedupSetBuilder.stringSet(opens.targets());
-                dedupSetBuilder.opensModifiers(opens.modifiers());
-            }
-
-            // requires
-            for (Requires r : md.requires()) {
-                dedupSetBuilder.requiresModifiers(r.modifiers());
-            }
-
-            // uses
-            dedupSetBuilder.stringSet(md.uses());
-
-            // hashes
-            JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
-        }
-
-        /*
-         * Generate bytecode for SystemModules
-         */
-        public ClassWriter getClassWriter() {
-            int numModules = builders.size();
-            int numPackages = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                numPackages += builder.md.packages().size();
-            }
-
-            this.clinit(numModules, numPackages);
-            this.mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
-                                     "modules", "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
-                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, null);
-            mv.visitCode();
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
-            mv.visitVarInsn(ASTORE, MD_VAR);
-
-            for (ModuleDescriptorBuilder builder : builders) {
-                builder.build();
-            }
-            mv.visitVarInsn(ALOAD, MD_VAR);
-            mv.visitInsn(ARETURN);
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-            return cw;
-        }
-
-        public boolean isOverriddenClass(String path) {
-            return path.equals("/java.base/" + CLASSNAME + ".class");
-        }
-
-        void pushInt(int num) {
-            if (num <= 5) {
-                mv.visitInsn(ICONST_0 + num);
-            } else if (num < Byte.MAX_VALUE) {
-                mv.visitIntInsn(BIPUSH, num);
-            } else if (num < Short.MAX_VALUE) {
-                mv.visitIntInsn(SIPUSH, num);
-            } else {
-                throw new IllegalArgumentException("exceed limit: " + num);
-            }
-        }
-
-        class ModuleDescriptorBuilder {
-            static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
-            static final String EXPORTS_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Exports;";
-            static final String OPENS_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Opens;";
-            static final String PROVIDES_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Provides;";
-            static final String REQUIRES_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Requires;";
-
-            // method signature for static Builder::newExports, newOpens,
-            // newProvides, newRequires methods
-            static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
-                    + EXPORTS_TYPE;
-            static final String EXPORTS_MODIFIER_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
-            static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
-                    + OPENS_TYPE;
-            static final String OPENS_MODIFIER_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
-            static final String PROVIDES_STRING_LIST_SIG =
-                "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
-            static final String REQUIRES_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
-
-            // method signature for Builder instance methods that
-            // return this Builder instance
-            static final String EXPORTS_ARRAY_SIG =
-                "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
-            static final String OPENS_ARRAY_SIG =
-                "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
-            static final String PROVIDES_ARRAY_SIG =
-                "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
-            static final String REQUIRES_ARRAY_SIG =
-                "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
-            static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
-            static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String STRING_BYTE_ARRAY_SIG =
-                "(Ljava/lang/String;[B)" + BUILDER_TYPE;
-            static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
-
-
-            final ModuleDescriptor md;
-            final Set<String> packages;
-
-            ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
-                if (md.isAutomatic()) {
-                    throw new InternalError("linking automatic module is not supported");
-                }
-                this.md = md;
-                this.packages = packages;
-            }
-
-            void build() {
-                // new jdk.internal.module.Builder
-                newBuilder();
-
-                // requires
-                requires(md.requires());
-
-                // exports
-                exports(md.exports());
-
-                // opens
-                opens(md.opens());
-
-                // uses
-                uses(md.uses());
-
-                // provides
-                provides(md.provides());
-
-                // all packages
-                packages(packages);
-
-                // version
-                md.version().ifPresent(this::version);
-
-                // main class
-                md.mainClass().ifPresent(this::mainClass);
-
-                // hashes
-                JLMA.hashes(md).ifPresent(mh -> {
-                    algorithm(mh.algorithm());
-                    mh.names().forEach(mn -> moduleHash(mn, mh.hashFor(mn)));
-                });
-
-                putModuleDescriptor();
-            }
-
-            void newBuilder() {
-                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
-                mv.visitInsn(DUP);
-                mv.visitLdcInsn(md.name());
-                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
-                    "<init>", "(Ljava/lang/String;)V", false);
-                mv.visitVarInsn(ASTORE, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-
-                if (md.isOpen()) {
-                    setModuleBit("open", true);
-                }
-                if (md.isSynthetic()) {
-                    setModuleBit("synthetic", true);
-                }
-            }
-
-            /*
-             * Invoke Builder.<methodName>(boolean value)
-             */
-            void setModuleBit(String methodName, boolean value) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                if (value) {
-                    mv.visitInsn(ICONST_1);
-                } else {
-                    mv.visitInsn(ICONST_0);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   methodName, BOOLEAN_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Put ModuleDescriptor into the modules array
-             */
-            void putModuleDescriptor() {
-                mv.visitVarInsn(ALOAD, MD_VAR);
-                pushInt(nextModulesIndex++);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(md.hashCode());
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "build", "(I)Ljava/lang/module/ModuleDescriptor;",
-                                   false);
-                mv.visitInsn(AASTORE);
-            }
-
-            /*
-             * Call Builder::newRequires to create Requires instances and
-             * then pass it to the builder by calling:
-             *      Builder.requires(Requires[])
-             *
-             */
-            void requires(Set<Requires> requires) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(requires.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
-                int arrayIndex = 0;
-                for (Requires require : requires) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newRequires(require.modifiers(), require.name());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", REQUIRES_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.newRequires(Set<Modifier> mods, String mn)
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newRequires(mods, mn);
-             */
-            void newRequires(Set<Requires.Modifier> mods, String name) {
-                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                                   "newRequires", REQUIRES_SET_STRING_SIG, false);
-            }
-
-            /*
-             * Call Builder::newExports to create Exports instances and
-             * then pass it to the builder by calling:
-             *      Builder.exports(Exports[])
-             *
-             */
-            void exports(Set<Exports> exports) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(exports.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
-                int arrayIndex = 0;
-                for (Exports export : exports) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newExports(export.modifiers(), export.source(), export.targets());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "exports", EXPORTS_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke
-             *     Builder.newExports(Set<Exports.Modifier> ms, String pn,
-             *                        Set<String> targets)
-             * or
-             *     Builder.newExports(Set<Exports.Modifier> ms, String pn)
-             *
-             * Set<String> targets = new HashSet<>();
-             * targets.add(t);
-             * :
-             * :
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newExports(mods, pn, targets);
-             */
-            void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
-                int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
-                if (!targets.isEmpty()) {
-                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitVarInsn(ALOAD, stringSetIndex);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                        "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
-                } else {
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                        "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
-                }
-            }
-
-
-            /**
-             * Call Builder::newOpens to create Opens instances and
-             * then pass it to the builder by calling:
-             *      Builder.opens(Opens[])
-             *
-             */
-            void opens(Set<Opens> opens) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(opens.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
-                int arrayIndex = 0;
-                for (Opens open : opens) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newOpens(open.modifiers(), open.source(), open.targets());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                        "opens", OPENS_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke
-             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn,
-             *                        Set<String> targets)
-             * or
-             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn)
-             *
-             * Set<String> targets = new HashSet<>();
-             * targets.add(t);
-             * :
-             * :
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newOpens(mods, pn, targets);
-             */
-            void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
-                int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
-                if (!targets.isEmpty()) {
-                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitVarInsn(ALOAD, stringSetIndex);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                            "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
-                } else {
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                            "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
-                }
-            }
-
-            /*
-             * Invoke Builder.uses(Set<String> uses)
-             */
-            void uses(Set<String> uses) {
-                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "uses", SET_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-            * Call Builder::newProvides to create Provides instances and
-            * then pass it to the builder by calling:
-            *      Builder.provides(Provides[] provides)
-            *
-            */
-            void provides(Collection<Provides> provides) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(provides.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
-                int arrayIndex = 0;
-                for (Provides provide : provides) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newProvides(provide.service(), provide.providers());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "provides", PROVIDES_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.newProvides(String service, Set<String> providers)
-             *
-             * Set<String> providers = new HashSet<>();
-             * providers.add(impl);
-             * :
-             * :
-             * Builder.newProvides(service, providers);
-             */
-            void newProvides(String service, List<String> providers) {
-                mv.visitLdcInsn(service);
-                pushInt(providers.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-                int arrayIndex = 0;
-                for (String provider : providers) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    mv.visitLdcInsn(provider);
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
-                                   "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
-                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                                   "newProvides", PROVIDES_STRING_LIST_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.packages(String pn)
-             */
-            void packages(Set<String> packages) {
-                int varIndex = dedupSetBuilder.newStringSet(packages);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "packages", SET_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.mainClass(String cn)
-             */
-            void mainClass(String cn) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(cn);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "mainClass", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.version(Version v);
-             */
-            void version(Version v) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(v.toString());
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "version", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.algorithm(String a);
-             */
-            void algorithm(String alg) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(alg);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "algorithm", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.moduleHash(String name, byte[] hash);
-             */
-            void moduleHash(String name, byte[] hash) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(name);
-
-                // must exist
-                Integer index = modulesToHashIndex.get(name);
-                if (index != null) {
-                    mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
-                    pushInt(index);
-                    mv.visitInsn(AALOAD);
-                    assert(Objects.equals(hash, modulesToHash.get(name)));
-                } else {
-                    pushInt(hash.length);
-                    mv.visitIntInsn(NEWARRAY, T_BYTE);
-                    for (int i = 0; i < hash.length; i++) {
-                        mv.visitInsn(DUP);              // arrayref
-                        pushInt(i);
-                        mv.visitIntInsn(BIPUSH, hash[i]);
-                        mv.visitInsn(BASTORE);
-                    }
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "moduleHash", STRING_BYTE_ARRAY_SIG, false);
-                mv.visitInsn(POP);
-            }
-        }
-
-        /*
-         * Wraps set creation, ensuring identical sets are properly deduplicated.
-         */
-        class DedupSetBuilder {
-            // map Set<String> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
-
-            // map Set<Requires.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
-                requiresModifiersSets = new HashMap<>();
-
-            // map Set<Exports.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
-                exportsModifiersSets = new HashMap<>();
-
-            // map Set<Opens.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
-                opensModifiersSets = new HashMap<>();
-
-            private final int stringSetVar;
-            private final int enumSetVar;
-            private final IntSupplier localVarSupplier;
-
-            DedupSetBuilder(IntSupplier localVarSupplier) {
-                this.stringSetVar = localVarSupplier.getAsInt();
-                this.enumSetVar = localVarSupplier.getAsInt();
-                this.localVarSupplier = localVarSupplier;
-            }
-
-            /*
-             * Add the given set of strings to this builder.
-             */
-            void stringSet(Set<String> strings) {
-                stringSets.computeIfAbsent(strings,
-                    s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Exports.Modifiers
-             */
-            void exportsModifiers(Set<Exports.Modifier> mods) {
-                exportsModifiersSets.computeIfAbsent(mods, s ->
-                                new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
-                                        enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Opens.Modifiers
-             */
-            void opensModifiers(Set<Opens.Modifier> mods) {
-                opensModifiersSets.computeIfAbsent(mods, s ->
-                                new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
-                                        enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Requires.Modifiers
-             */
-            void requiresModifiers(Set<Requires.Modifier> mods) {
-                requiresModifiersSets.computeIfAbsent(mods, s ->
-                    new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
-                                         enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Retrieve the index to the given set of Strings. Emit code to
-             * generate it when SetBuilder::build is called.
-             */
-            int indexOfStringSet(Set<String> names) {
-                return stringSets.get(names).build();
-            }
-
-            /*
-             * Retrieve the index to the given set of Exports.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
-                return exportsModifiersSets.get(mods).build();
-            }
-
-            /**
-             * Retrieve the index to the given set of Opens.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
-                return opensModifiersSets.get(mods).build();
-            }
-
-
-            /*
-             * Retrieve the index to the given set of Requires.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
-                return requiresModifiersSets.get(mods).build();
-            }
-
-            /*
-             * Build a new string set without any attempt to deduplicate it.
-             */
-            int newStringSet(Set<String> names) {
-                int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
-                assert index == stringSetVar;
-                return index;
-            }
-        }
-
-        /*
-         * SetBuilder generates bytecode to create one single instance of Set
-         * for a given set of elements and assign to a local variable slot.
-         * When there is only one single reference to a Set<T>,
-         * it will reuse defaultVarIndex.  For a Set with multiple references,
-         * it will use a new local variable retrieved from the nextLocalVar
-         */
-        class SetBuilder<T> {
-            private final Set<T> elements;
-            private final int defaultVarIndex;
-            private final IntSupplier nextLocalVar;
-            private int refCount;
-            private int localVarIndex;
-
-            SetBuilder(Set<T> elements,
-                       int defaultVarIndex,
-                       IntSupplier nextLocalVar) {
-                this.elements = elements;
-                this.defaultVarIndex = defaultVarIndex;
-                this.nextLocalVar = nextLocalVar;
-            }
-
-            /*
-             * Increments the number of references to this particular set.
-             */
-            final void increment() {
-                refCount++;
-            }
-
-            /**
-             * Generate the appropriate instructions to load an object reference
-             * to the element onto the stack.
-             */
-            void visitElement(T element, MethodVisitor mv) {
-                mv.visitLdcInsn(element);
-            }
-
-            /*
-             * Build bytecode for the Set represented by this builder,
-             * or get the local variable index of a previously generated set
-             * (in the local scope).
-             *
-             * @return local variable index of the generated set.
-             */
-            final int build() {
-                int index = localVarIndex;
-                if (localVarIndex == 0) {
-                    // if non-empty and more than one set reference this builder,
-                    // emit to a unique local
-                    index = refCount <= 1 ? defaultVarIndex
-                                          : nextLocalVar.getAsInt();
-                    if (index < MAX_LOCAL_VARS) {
-                        localVarIndex = index;
-                    } else {
-                        // overflow: disable optimization by using localVarIndex = 0
-                        index = defaultVarIndex;
-                    }
-
-                    generateSetOf(index);
-                }
-                return index;
-            }
-
-            private void generateSetOf(int index) {
-                if (elements.size() <= 10) {
-                    // call Set.of(e1, e2, ...)
-                    StringBuilder sb = new StringBuilder("(");
-                    for (T t : elements) {
-                        sb.append("Ljava/lang/Object;");
-                        visitElement(t, mv);
-                    }
-                    sb.append(")Ljava/util/Set;");
-                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
-                            "of", sb.toString(), true);
-                } else {
-                    // call Set.of(E... elements)
-                    pushInt(elements.size());
-                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-                    int arrayIndex = 0;
-                    for (T t : elements) {
-                        mv.visitInsn(DUP);    // arrayref
-                        pushInt(arrayIndex);
-                        visitElement(t, mv);  // value
-                        mv.visitInsn(AASTORE);
-                        arrayIndex++;
-                    }
-                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
-                            "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
-                }
-                mv.visitVarInsn(ASTORE, index);
-            }
-        }
-
-        /*
-         * Generates bytecode to create one single instance of EnumSet
-         * for a given set of modifiers and assign to a local variable slot.
-         */
-        class EnumSetBuilder<T> extends SetBuilder<T> {
-
-            private final String className;
-
-            EnumSetBuilder(Set<T> modifiers, String className,
-                           int defaultVarIndex,
-                           IntSupplier nextLocalVar) {
-                super(modifiers, defaultVarIndex, nextLocalVar);
-                this.className = className;
-            }
-
-            /**
-             * Loads an Enum field.
-             */
-            void visitElement(T t, MethodVisitor mv) {
-                mv.visitFieldInsn(GETSTATIC, className, t.toString(),
-                                  "L" + className + ";");
-            }
-        }
-    }
-}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
new file mode 100644
index 0000000..32281d4
--- /dev/null
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.IntSupplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.SystemModules;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.ResourcePool;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.ResourcePoolBuilder;
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+
+/**
+ * Jlink plugin to reconstitute module descriptors for system modules.
+ * It will extend module-info.class with Packages attribute,
+ * if not present. It also determines the number of packages of
+ * the boot layer at link time.
+ *
+ * This plugin will override jdk.internal.module.SystemModules class
+ *
+ * @see jdk.internal.module.SystemModuleFinder
+ * @see SystemModules
+ */
+public final class SystemModulesPlugin implements Plugin {
+    private static final JavaLangModuleAccess JLMA =
+        SharedSecrets.getJavaLangModuleAccess();
+
+    private static final String NAME = "system-modules";
+    private static final String DESCRIPTION =
+        PluginsResourceBundle.getDescription(NAME);
+
+    private boolean enabled;
+    public SystemModulesPlugin() {
+        this.enabled = true;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return DESCRIPTION;
+    }
+
+    @Override
+    public Set<State> getState() {
+        return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
+                       : EnumSet.of(State.DISABLED);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        if (config.containsKey(NAME)) {
+            enabled = false;
+        }
+    }
+
+    @Override
+    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+        if (!enabled) {
+            throw new PluginException(NAME + " was set");
+        }
+
+        SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
+
+        // generate the byte code to create ModuleDescriptors
+        // skip parsing module-info.class and skip name check
+        in.moduleView().modules().forEach(module -> {
+
+            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
+                // automatic module not supported yet
+                () ->  new PluginException("module-info.class not found for " +
+                    module.name() + " module")
+            );
+
+            assert module.name().equals(data.moduleName());
+            try {
+                ModuleInfo moduleInfo = new ModuleInfo(data.contentBytes(), module.packages());
+                generator.addModule(moduleInfo);
+
+                // link-time validation
+                moduleInfo.validateNames();
+                // check if any exported or open package is not present
+                moduleInfo.validatePackages();
+
+                // Packages attribute needs update
+                if (moduleInfo.shouldAddPackagesAttribute()) {
+                    // replace with the overridden version
+                    data = data.copyWithContent(moduleInfo.getBytes());
+                }
+                out.add(data);
+            } catch (IOException e) {
+                throw new PluginException(e);
+            }
+        });
+
+        // Generate the new class
+        ClassWriter cwriter = generator.getClassWriter();
+        in.entries().forEach(data -> {
+            if (data.path().endsWith("module-info.class"))
+                return;
+            if (generator.isOverriddenClass(data.path())) {
+                byte[] bytes = cwriter.toByteArray();
+                ResourcePoolEntry ndata = data.copyWithContent(bytes);
+                out.add(ndata);
+            } else {
+                out.add(data);
+            }
+        });
+
+        return out.build();
+    }
+
+    class ModuleInfo {
+        final ModuleDescriptor descriptor;
+        final ModuleHashes recordedHashes;
+        final ModuleResolution moduleResolution;
+        final Set<String> packages;
+        final ByteArrayInputStream bain;
+
+        ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
+            this.bain = new ByteArrayInputStream(bytes);
+            this.packages = packages;
+
+            Attributes attrs = jdk.internal.module.ModuleInfo.read(bain, null);
+            this.descriptor = attrs.descriptor();
+            this.recordedHashes = attrs.recordedHashes();
+            this.moduleResolution = attrs.moduleResolution();
+
+            if (descriptor.isAutomatic()) {
+                throw new InternalError("linking automatic module is not supported");
+            }
+        }
+
+        String moduleName() {
+            return descriptor.name();
+        }
+
+        /**
+         * Validates names in ModuleDescriptor
+         */
+        void validateNames() {
+            Checks.requireModuleName(descriptor.name());
+            for (Requires req : descriptor.requires()) {
+                Checks.requireModuleName(req.name());
+            }
+            for (Exports e : descriptor.exports()) {
+                Checks.requirePackageName(e.source());
+                if (e.isQualified())
+                    e.targets().forEach(Checks::requireModuleName);
+            }
+            for (Opens opens : descriptor.opens()) {
+                Checks.requirePackageName(opens.source());
+                if (opens.isQualified())
+                    opens.targets().forEach(Checks::requireModuleName);
+            }
+            for (Provides provides : descriptor.provides()) {
+                Checks.requireServiceTypeName(provides.service());
+                provides.providers().forEach(Checks::requireServiceProviderName);
+            }
+            for (String service : descriptor.uses()) {
+                Checks.requireServiceTypeName(service);
+            }
+            for (String pn : descriptor.packages()) {
+                Checks.requirePackageName(pn);
+            }
+        }
+
+
+        /**
+         * Validates if exported and open packages are present
+         */
+        void validatePackages() {
+            Set<String> nonExistPackages = new TreeSet<>();
+            descriptor.exports().stream()
+                .map(Exports::source)
+                .filter(pn -> !packages.contains(pn))
+                .forEach(nonExistPackages::add);
+
+            descriptor.opens().stream()
+                .map(Opens::source)
+                .filter(pn -> !packages.contains(pn))
+                .forEach(nonExistPackages::add);
+
+            if (!nonExistPackages.isEmpty()) {
+                throw new PluginException("Packages that are exported or open in "
+                    + descriptor.name() + " are not present: " + nonExistPackages);
+            }
+        }
+
+        /**
+         * Returns true if the PackagesAttribute should be written
+         */
+        boolean shouldAddPackagesAttribute() {
+            return descriptor.packages().isEmpty() && packages.size() > 0;
+        }
+
+        /**
+         * Returns the bytes for the module-info.class with PackagesAttribute
+         * if it contains at least one package
+         */
+        byte[] getBytes() throws IOException {
+            bain.reset();
+
+            // add Packages attribute if not exist
+            if (shouldAddPackagesAttribute()) {
+                return new ModuleInfoRewriter(bain, packages).getBytes();
+            } else {
+                return bain.readAllBytes();
+            }
+        }
+
+        class ModuleInfoRewriter extends ByteArrayOutputStream {
+            final ModuleInfoExtender extender;
+            ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
+                this.extender = ModuleInfoExtender.newExtender(in);
+                // Add Packages attribute
+                if (packages.size() > 0) {
+                    this.extender.packages(packages);
+                }
+                this.extender.write(this);
+            }
+
+            byte[] getBytes() {
+                return buf;
+            }
+        }
+    }
+
+    /**
+     * ClassWriter of a new jdk.internal.module.SystemModules class
+     * to reconstitute ModuleDescriptor of the system modules.
+     */
+    static class SystemModulesClassGenerator {
+        private static final String CLASSNAME =
+            "jdk/internal/module/SystemModules";
+        private static final String MODULE_DESCRIPTOR_BUILDER =
+            "jdk/internal/module/Builder";
+        private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
+            "[Ljava/lang/module/ModuleDescriptor;";
+        private static final String REQUIRES_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Requires$Modifier";
+        private static final String EXPORTS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Exports$Modifier";
+        private static final String OPENS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Opens$Modifier";
+        private static final String MODULE_HASHES_ARRAY_SIGNATURE  =
+            "[Ljdk/internal/module/ModuleHashes;";
+        private static final String MODULE_RESOLUTION_CLASSNAME  =
+            "jdk/internal/module/ModuleResolution";
+        private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE  =
+            "[Ljdk/internal/module/ModuleResolution;";
+
+        // static variables in SystemModules class
+        private static final String MODULE_NAMES = "MODULE_NAMES";
+        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
+
+        private static final int MAX_LOCAL_VARS = 256;
+
+        private final int BUILDER_VAR    = 0;
+        private final int MD_VAR         = 1;  // variable for ModuleDescriptor
+        private final int MH_VAR         = 1;  // variable for ModuleHashes
+        private int nextLocalVar         = 2;  // index to next local variable
+
+        private final ClassWriter cw;
+
+        // Method visitor for generating the SystemModules::modules() method
+        private MethodVisitor mv;
+
+        // list of all ModuleDescriptorBuilders, invoked in turn when building.
+        private final List<ModuleInfo> moduleInfos = new ArrayList<>();
+
+        // A builder to create one single Set instance for a given set of
+        // names or modifiers to reduce the footprint
+        // e.g. target modules of qualified exports
+        private final DedupSetBuilder dedupSetBuilder
+            = new DedupSetBuilder(this::getNextLocalVar);
+
+        public SystemModulesClassGenerator() {
+            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
+                                      ClassWriter.COMPUTE_FRAMES);
+        }
+
+        private int getNextLocalVar() {
+            return nextLocalVar++;
+        }
+
+        /*
+         * static initializer initializing the static fields
+         *
+         * static Map<String, ModuleDescriptor> map = new HashMap<>();
+         */
+        private void clinit(int numModules, int numPackages,
+                            boolean hasSplitPackages) {
+            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
+                     null, "java/lang/Object", null);
+
+            // public static String[] MODULE_NAMES = new String[] {....};
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
+                    "[Ljava/lang/String;", null, null)
+                    .visitEnd();
+
+            // public static int PACKAGES_IN_BOOT_LAYER;
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
+                    "I", null, numPackages)
+                    .visitEnd();
+
+            MethodVisitor clinit =
+                cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
+                               null, null);
+            clinit.visitCode();
+
+            // create the MODULE_NAMES array
+            pushInt(clinit, numModules);
+            clinit.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+            int index = 0;
+            for (ModuleInfo minfo : moduleInfos) {
+                clinit.visitInsn(DUP);                  // arrayref
+                pushInt(clinit, index++);
+                clinit.visitLdcInsn(minfo.moduleName()); // value
+                clinit.visitInsn(AASTORE);
+            }
+
+            clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
+                    "[Ljava/lang/String;");
+
+            clinit.visitInsn(RETURN);
+            clinit.visitMaxs(0, 0);
+            clinit.visitEnd();
+
+            // public static boolean hasSplitPackages();
+            MethodVisitor split =
+                cw.visitMethod(ACC_PUBLIC+ACC_STATIC, "hasSplitPackages",
+                               "()Z", null, null);
+            split.visitCode();
+            split.visitInsn(hasSplitPackages ? ICONST_1 : ICONST_0);
+            split.visitInsn(IRETURN);
+            split.visitMaxs(0, 0);
+            split.visitEnd();
+
+        }
+
+        /*
+         * Adds the given ModuleDescriptor to the system module list, and
+         * prepares mapping from various Sets to SetBuilders to emit an
+         * optimized number of sets during build.
+         */
+        public void addModule(ModuleInfo moduleInfo) {
+            ModuleDescriptor md = moduleInfo.descriptor;
+            moduleInfos.add(moduleInfo);
+
+            // exports
+            for (Exports e : md.exports()) {
+                dedupSetBuilder.stringSet(e.targets());
+                dedupSetBuilder.exportsModifiers(e.modifiers());
+            }
+
+            // opens
+            for (Opens opens : md.opens()) {
+                dedupSetBuilder.stringSet(opens.targets());
+                dedupSetBuilder.opensModifiers(opens.modifiers());
+            }
+
+            // requires
+            for (Requires r : md.requires()) {
+                dedupSetBuilder.requiresModifiers(r.modifiers());
+            }
+
+            // uses
+            dedupSetBuilder.stringSet(md.uses());
+        }
+
+        /*
+         * Generate bytecode for SystemModules
+         */
+        public ClassWriter getClassWriter() {
+            int numModules = moduleInfos.size();
+            Set<String> allPackages = new HashSet<>();
+            int packageCount = 0;
+            for (ModuleInfo minfo : moduleInfos) {
+                allPackages.addAll(minfo.packages);
+                packageCount += minfo.packages.size();
+            }
+
+            int numPackages = allPackages.size();
+            boolean hasSplitPackages = (numPackages < packageCount);
+            clinit(numModules, numPackages, hasSplitPackages);
+
+            // generate SystemModules::descriptors
+            genDescriptorsMethod();
+            // generate SystemModules::hashes
+            genHashesMethod();
+            // generate SystemModules::moduleResolutions
+            genModuleResolutionsMethod();
+
+            return cw;
+        }
+
+        /*
+         * Generate bytecode for SystemModules::descriptors method
+         */
+        private void genDescriptorsMethod() {
+            this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+                                     "descriptors",
+                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+                                     null);
+            mv.visitCode();
+            pushInt(mv, moduleInfos.size());
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
+            mv.visitVarInsn(ASTORE, MD_VAR);
+
+            for (int index = 0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                new ModuleDescriptorBuilder(minfo.descriptor,
+                                            minfo.packages,
+                                            index).build();
+            }
+            mv.visitVarInsn(ALOAD, MD_VAR);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+
+        }
+
+        /*
+         * Generate bytecode for SystemModules::hashes method
+         */
+        private void genHashesMethod() {
+            MethodVisitor hmv =
+                cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+                               "hashes",
+                               "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+                               "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+                               null);
+            hmv.visitCode();
+            pushInt(hmv, moduleInfos.size());
+            hmv.visitTypeInsn(ANEWARRAY, "jdk/internal/module/ModuleHashes");
+            hmv.visitVarInsn(ASTORE, MH_VAR);
+
+            for (int index = 0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                if (minfo.recordedHashes != null) {
+                    new ModuleHashesBuilder(minfo.recordedHashes,
+                                            index,
+                                            hmv).build();
+                }
+            }
+
+            hmv.visitVarInsn(ALOAD, MH_VAR);
+            hmv.visitInsn(ARETURN);
+            hmv.visitMaxs(0, 0);
+            hmv.visitEnd();
+
+        }
+
+        /*
+         * Generate bytecode for SystemModules::methodResoultions method
+         */
+        private void genModuleResolutionsMethod() {
+            MethodVisitor mresmv =
+                cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+                               "moduleResolutions",
+                               "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+                               "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+                               null);
+            mresmv.visitCode();
+            pushInt(mresmv, moduleInfos.size());
+            mresmv.visitTypeInsn(ANEWARRAY, MODULE_RESOLUTION_CLASSNAME);
+            mresmv.visitVarInsn(ASTORE, 0);
+
+            for (int index=0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                if (minfo.moduleResolution != null) {
+                    mresmv.visitVarInsn(ALOAD, 0);
+                    pushInt(mresmv, index);
+                    mresmv.visitTypeInsn(NEW, MODULE_RESOLUTION_CLASSNAME);
+                    mresmv.visitInsn(DUP);
+                    mresmv.visitLdcInsn(minfo.moduleResolution.value());
+                    mresmv.visitMethodInsn(INVOKESPECIAL,
+                                           MODULE_RESOLUTION_CLASSNAME,
+                                           "<init>",
+                                           "(I)V", false);
+                    mresmv.visitInsn(AASTORE);
+                }
+            }
+            mresmv.visitVarInsn(ALOAD, 0);
+            mresmv.visitInsn(ARETURN);
+            mresmv.visitMaxs(0, 0);
+            mresmv.visitEnd();
+        }
+
+        public boolean isOverriddenClass(String path) {
+            return path.equals("/java.base/" + CLASSNAME + ".class");
+        }
+
+        void pushInt(MethodVisitor mv, int num) {
+            if (num <= 5) {
+                mv.visitInsn(ICONST_0 + num);
+            } else if (num < Byte.MAX_VALUE) {
+                mv.visitIntInsn(BIPUSH, num);
+            } else if (num < Short.MAX_VALUE) {
+                mv.visitIntInsn(SIPUSH, num);
+            } else {
+                throw new IllegalArgumentException("exceed limit: " + num);
+            }
+        }
+
+        class ModuleDescriptorBuilder {
+            static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
+            static final String EXPORTS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Exports;";
+            static final String OPENS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Opens;";
+            static final String PROVIDES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Provides;";
+            static final String REQUIRES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Requires;";
+
+            // method signature for static Builder::newExports, newOpens,
+            // newProvides, newRequires methods
+            static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + EXPORTS_TYPE;
+            static final String EXPORTS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + OPENS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
+            static final String PROVIDES_STRING_LIST_SIG =
+                "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
+            static final String REQUIRES_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
+            static final String REQUIRES_SET_STRING_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;)" + REQUIRES_TYPE;
+
+            // method signature for Builder instance methods that
+            // return this Builder instance
+            static final String EXPORTS_ARRAY_SIG =
+                "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
+            static final String OPENS_ARRAY_SIG =
+                "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
+            static final String PROVIDES_ARRAY_SIG =
+                "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
+            static final String REQUIRES_ARRAY_SIG =
+                "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
+            static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
+            static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
+
+            final ModuleDescriptor md;
+            final Set<String> packages;
+            final int index;
+            ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) {
+                if (md.isAutomatic()) {
+                    throw new InternalError("linking automatic module is not supported");
+                }
+                this.md = md;
+                this.packages = packages;
+                this.index = index;
+            }
+
+            void build() {
+                // new jdk.internal.module.Builder
+                newBuilder();
+
+                // requires
+                requires(md.requires());
+
+                // exports
+                exports(md.exports());
+
+                // opens
+                opens(md.opens());
+
+                // uses
+                uses(md.uses());
+
+                // provides
+                provides(md.provides());
+
+                // all packages
+                packages(packages);
+
+                // version
+                md.version().ifPresent(this::version);
+
+                // main class
+                md.mainClass().ifPresent(this::mainClass);
+
+                putModuleDescriptor();
+            }
+
+            void newBuilder() {
+                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
+                mv.visitInsn(DUP);
+                mv.visitLdcInsn(md.name());
+                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
+                    "<init>", "(Ljava/lang/String;)V", false);
+                mv.visitVarInsn(ASTORE, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+
+                if (md.isOpen()) {
+                    setModuleBit("open", true);
+                }
+                if (md.isSynthetic()) {
+                    setModuleBit("synthetic", true);
+                }
+            }
+
+            /*
+             * Invoke Builder.<methodName>(boolean value)
+             */
+            void setModuleBit(String methodName, boolean value) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                if (value) {
+                    mv.visitInsn(ICONST_1);
+                } else {
+                    mv.visitInsn(ICONST_0);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    methodName, BOOLEAN_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Put ModuleDescriptor into the modules array
+             */
+            void putModuleDescriptor() {
+                mv.visitVarInsn(ALOAD, MD_VAR);
+                pushInt(mv, index);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(md.hashCode());
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "build", "(I)Ljava/lang/module/ModuleDescriptor;",
+                    false);
+                mv.visitInsn(AASTORE);
+            }
+
+            /*
+             * Call Builder::newRequires to create Requires instances and
+             * then pass it to the builder by calling:
+             *      Builder.requires(Requires[])
+             *
+             */
+            void requires(Set<Requires> requires) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, requires.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
+                int arrayIndex = 0;
+                for (Requires require : requires) {
+                    String compiledVersion = null;
+                    if (require.compiledVersion().isPresent()) {
+                        compiledVersion = require.compiledVersion().get().toString();
+                    }
+
+                    mv.visitInsn(DUP);               // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newRequires(require.modifiers(), require.name(), compiledVersion);
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "requires", REQUIRES_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.newRequires(Set<Modifier> mods, String mn, String compiledVersion)
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newRequires(mods, mn, compiledVersion);
+             */
+            void newRequires(Set<Requires.Modifier> mods, String name, String compiledVersion) {
+                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitLdcInsn(name);
+                if (compiledVersion != null) {
+                    mv.visitLdcInsn(compiledVersion);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newRequires", REQUIRES_SET_STRING_STRING_SIG, false);
+                } else {
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newRequires", REQUIRES_SET_STRING_SIG, false);
+                }
+            }
+
+            /*
+             * Call Builder::newExports to create Exports instances and
+             * then pass it to the builder by calling:
+             *      Builder.exports(Exports[])
+             *
+             */
+            void exports(Set<Exports> exports) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, exports.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
+                int arrayIndex = 0;
+                for (Exports export : exports) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newExports(export.modifiers(), export.source(), export.targets());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "exports", EXPORTS_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newExports(mods, pn, targets);
+             */
+            void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+
+            /**
+             * Call Builder::newOpens to create Opens instances and
+             * then pass it to the builder by calling:
+             * Builder.opens(Opens[])
+             */
+            void opens(Set<Opens> opens) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, opens.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
+                int arrayIndex = 0;
+                for (Opens open : opens) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newOpens(open.modifiers(), open.source(), open.targets());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "opens", OPENS_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newOpens(mods, pn, targets);
+             */
+            void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+            /*
+             * Invoke Builder.uses(Set<String> uses)
+             */
+            void uses(Set<String> uses) {
+                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "uses", SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+            * Call Builder::newProvides to create Provides instances and
+            * then pass it to the builder by calling:
+            *      Builder.provides(Provides[] provides)
+            *
+            */
+            void provides(Collection<Provides> provides) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, provides.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
+                int arrayIndex = 0;
+                for (Provides provide : provides) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newProvides(provide.service(), provide.providers());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "provides", PROVIDES_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.newProvides(String service, Set<String> providers)
+             *
+             * Set<String> providers = new HashSet<>();
+             * providers.add(impl);
+             * :
+             * :
+             * Builder.newProvides(service, providers);
+             */
+            void newProvides(String service, List<String> providers) {
+                mv.visitLdcInsn(service);
+                pushInt(mv, providers.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                int arrayIndex = 0;
+                for (String provider : providers) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    mv.visitLdcInsn(provider);
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
+                    "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
+                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                    "newProvides", PROVIDES_STRING_LIST_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.packages(String pn)
+             */
+            void packages(Set<String> packages) {
+                int varIndex = dedupSetBuilder.newStringSet(packages);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "packages", SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.mainClass(String cn)
+             */
+            void mainClass(String cn) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(cn);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "mainClass", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.version(Version v);
+             */
+            void version(Version v) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(v.toString());
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "version", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+        }
+
+        class ModuleHashesBuilder {
+            private static final String MODULE_HASHES_BUILDER =
+                "jdk/internal/module/ModuleHashes$Builder";
+            private static final String MODULE_HASHES_BUILDER_TYPE =
+                "L" + MODULE_HASHES_BUILDER + ";";
+            static final String STRING_BYTE_ARRAY_SIG =
+                "(Ljava/lang/String;[B)" + MODULE_HASHES_BUILDER_TYPE;
+
+            final ModuleHashes recordedHashes;
+            final MethodVisitor hmv;
+            final int index;
+
+            ModuleHashesBuilder(ModuleHashes hashes, int index, MethodVisitor hmv) {
+                this.recordedHashes = hashes;
+                this.hmv = hmv;
+                this.index = index;
+            }
+
+            /**
+             * Build ModuleHashes
+             */
+            void build() {
+                if (recordedHashes == null)
+                    return;
+
+                // new jdk.internal.module.ModuleHashes.Builder
+                newModuleHashesBuilder();
+
+                // Invoke ModuleHashes.Builder::hashForModule
+                recordedHashes
+                    .names()
+                    .forEach(mn -> hashForModule(mn, recordedHashes.hashFor(mn)));
+
+                // Put ModuleHashes into the hashes array
+                pushModuleHashes();
+            }
+
+
+            /*
+             * Create ModuleHashes.Builder instance
+             */
+            void newModuleHashesBuilder() {
+                hmv.visitTypeInsn(NEW, MODULE_HASHES_BUILDER);
+                hmv.visitInsn(DUP);
+                hmv.visitLdcInsn(recordedHashes.algorithm());
+                pushInt(hmv, ((4 * recordedHashes.names().size()) / 3) + 1);
+                hmv.visitMethodInsn(INVOKESPECIAL, MODULE_HASHES_BUILDER,
+                    "<init>", "(Ljava/lang/String;I)V", false);
+                hmv.visitVarInsn(ASTORE, BUILDER_VAR);
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+            }
+
+
+            /*
+             * Invoke ModuleHashes.Builder::build and put the returned
+             * ModuleHashes to the hashes array
+             */
+            void pushModuleHashes() {
+                hmv.visitVarInsn(ALOAD, MH_VAR);
+                pushInt(hmv, index);
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+                hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+                    "build", "()Ljdk/internal/module/ModuleHashes;",
+                    false);
+                hmv.visitInsn(AASTORE);
+            }
+
+            /*
+             * Invoke ModuleHashes.Builder.hashForModule(String name, byte[] hash);
+             */
+            void hashForModule(String name, byte[] hash) {
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+                hmv.visitLdcInsn(name);
+
+                pushInt(hmv, hash.length);
+                hmv.visitIntInsn(NEWARRAY, T_BYTE);
+                for (int i = 0; i < hash.length; i++) {
+                    hmv.visitInsn(DUP);              // arrayref
+                    pushInt(hmv, i);
+                    hmv.visitIntInsn(BIPUSH, hash[i]);
+                    hmv.visitInsn(BASTORE);
+                }
+
+                hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+                    "hashForModule", STRING_BYTE_ARRAY_SIG, false);
+                hmv.visitInsn(POP);
+            }
+        }
+
+        /*
+         * Wraps set creation, ensuring identical sets are properly deduplicated.
+         */
+        class DedupSetBuilder {
+            // map Set<String> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
+
+            // map Set<Requires.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
+                requiresModifiersSets = new HashMap<>();
+
+            // map Set<Exports.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
+                exportsModifiersSets = new HashMap<>();
+
+            // map Set<Opens.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
+                opensModifiersSets = new HashMap<>();
+
+            private final int stringSetVar;
+            private final int enumSetVar;
+            private final IntSupplier localVarSupplier;
+
+            DedupSetBuilder(IntSupplier localVarSupplier) {
+                this.stringSetVar = localVarSupplier.getAsInt();
+                this.enumSetVar = localVarSupplier.getAsInt();
+                this.localVarSupplier = localVarSupplier;
+            }
+
+            /*
+             * Add the given set of strings to this builder.
+             */
+            void stringSet(Set<String> strings) {
+                stringSets.computeIfAbsent(strings,
+                    s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Exports.Modifiers
+             */
+            void exportsModifiers(Set<Exports.Modifier> mods) {
+                exportsModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Opens.Modifiers
+             */
+            void opensModifiers(Set<Opens.Modifier> mods) {
+                opensModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Requires.Modifiers
+             */
+            void requiresModifiers(Set<Requires.Modifier> mods) {
+                requiresModifiersSets.computeIfAbsent(mods, s ->
+                    new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
+                                         enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Retrieve the index to the given set of Strings. Emit code to
+             * generate it when SetBuilder::build is called.
+             */
+            int indexOfStringSet(Set<String> names) {
+                return stringSets.get(names).build();
+            }
+
+            /*
+             * Retrieve the index to the given set of Exports.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
+                return exportsModifiersSets.get(mods).build();
+            }
+
+            /**
+             * Retrieve the index to the given set of Opens.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
+                return opensModifiersSets.get(mods).build();
+            }
+
+
+            /*
+             * Retrieve the index to the given set of Requires.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
+                return requiresModifiersSets.get(mods).build();
+            }
+
+            /*
+             * Build a new string set without any attempt to deduplicate it.
+             */
+            int newStringSet(Set<String> names) {
+                int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
+                assert index == stringSetVar;
+                return index;
+            }
+        }
+
+        /*
+         * SetBuilder generates bytecode to create one single instance of Set
+         * for a given set of elements and assign to a local variable slot.
+         * When there is only one single reference to a Set<T>,
+         * it will reuse defaultVarIndex.  For a Set with multiple references,
+         * it will use a new local variable retrieved from the nextLocalVar
+         */
+        class SetBuilder<T> {
+            private final Set<T> elements;
+            private final int defaultVarIndex;
+            private final IntSupplier nextLocalVar;
+            private int refCount;
+            private int localVarIndex;
+
+            SetBuilder(Set<T> elements,
+                       int defaultVarIndex,
+                       IntSupplier nextLocalVar) {
+                this.elements = elements;
+                this.defaultVarIndex = defaultVarIndex;
+                this.nextLocalVar = nextLocalVar;
+            }
+
+            /*
+             * Increments the number of references to this particular set.
+             */
+            final void increment() {
+                refCount++;
+            }
+
+            /**
+             * Generate the appropriate instructions to load an object reference
+             * to the element onto the stack.
+             */
+            void visitElement(T element, MethodVisitor mv) {
+                mv.visitLdcInsn(element);
+            }
+
+            /*
+             * Build bytecode for the Set represented by this builder,
+             * or get the local variable index of a previously generated set
+             * (in the local scope).
+             *
+             * @return local variable index of the generated set.
+             */
+            final int build() {
+                int index = localVarIndex;
+                if (localVarIndex == 0) {
+                    // if non-empty and more than one set reference this builder,
+                    // emit to a unique local
+                    index = refCount <= 1 ? defaultVarIndex
+                                          : nextLocalVar.getAsInt();
+                    if (index < MAX_LOCAL_VARS) {
+                        localVarIndex = index;
+                    } else {
+                        // overflow: disable optimization by using localVarIndex = 0
+                        index = defaultVarIndex;
+                    }
+
+                    generateSetOf(index);
+                }
+                return index;
+            }
+
+            private void generateSetOf(int index) {
+                if (elements.size() <= 10) {
+                    // call Set.of(e1, e2, ...)
+                    StringBuilder sb = new StringBuilder("(");
+                    for (T t : elements) {
+                        sb.append("Ljava/lang/Object;");
+                        visitElement(t, mv);
+                    }
+                    sb.append(")Ljava/util/Set;");
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", sb.toString(), true);
+                } else {
+                    // call Set.of(E... elements)
+                    pushInt(mv, elements.size());
+                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                    int arrayIndex = 0;
+                    for (T t : elements) {
+                        mv.visitInsn(DUP);    // arrayref
+                        pushInt(mv, arrayIndex);
+                        visitElement(t, mv);  // value
+                        mv.visitInsn(AASTORE);
+                        arrayIndex++;
+                    }
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
+                }
+                mv.visitVarInsn(ASTORE, index);
+            }
+        }
+
+        /*
+         * Generates bytecode to create one single instance of EnumSet
+         * for a given set of modifiers and assign to a local variable slot.
+         */
+        class EnumSetBuilder<T> extends SetBuilder<T> {
+
+            private final String className;
+
+            EnumSetBuilder(Set<T> modifiers, String className,
+                           int defaultVarIndex,
+                           IntSupplier nextLocalVar) {
+                super(modifiers, defaultVarIndex, nextLocalVar);
+                this.className = className;
+            }
+
+            /**
+             * Loads an Enum field.
+             */
+            void visitElement(T t, MethodVisitor mv) {
+                mv.visitFieldInsn(GETSTATIC, className, t.toString(),
+                                  "L" + className + ";");
+            }
+        }
+    }
+}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolEntry.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolEntry.java
index 9dcc83a..cf09709 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolEntry.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolEntry.java
@@ -52,21 +52,23 @@
      * <li>
      * <ul>CLASS_OR_RESOURCE: A java class or resource file.</ul>
      * <ul>CONFIG: A configuration file.</ul>
-     * <ul>NATIVE_CMD: A native process launcher.</ul>
+     * <ul>HEADER_FILE: A header file.</ul>
+     * <ul>LEGAL_NOTICE: A legal notice.</ul>
+     * <ul>MAN_PAGE: A man page.</ul>
+     * <ul>NATIVE_CMD: A native executable launcher.</ul>
      * <ul>NATIVE_LIB: A native library.</ul>
      * <ul>TOP: A top-level file in the jdk run-time image directory.</ul>
-     * <ul>OTHER: Other kind of file.</ul>
      * </li>
      */
     public enum Type {
         CLASS_OR_RESOURCE,
         CONFIG,
+        HEADER_FILE,
+        LEGAL_NOTICE,
+        MAN_PAGE,
         NATIVE_CMD,
         NATIVE_LIB,
-        HEADER_FILE,
-        MAN_PAGE,
-        TOP,
-        OTHER
+        TOP
     }
 
     /**
@@ -105,6 +107,17 @@
     public InputStream content();
 
     /**
+     * Returns a target linked with this entry.
+     *
+     * @implSpec The default implementation returns {@code null}.
+     *
+     * @return the target ResourcePoolEntry linked with this entry.
+     */
+    public default ResourcePoolEntry linkedTarget() {
+        return null;
+    }
+
+    /**
      * The ResourcePoolEntry content as an array of bytes.
      *
      * @return An Array of bytes.
@@ -199,4 +212,21 @@
     public static ResourcePoolEntry create(String path, Path file) {
         return create(path, Type.CLASS_OR_RESOURCE, file);
     }
+
+    /**
+     * Create a ResourcePoolEntry for a resource the given path and type.
+     * If the target platform supports symbolic links, it will be created
+     * as a symbolic link to the given target entry; otherwise, the
+     * ResourcePoolEntry contains the relative path to the target entry.
+     *
+     * @param path The resource path.
+     * @param type The ResourcePoolEntry type.
+     * @param target The target entry
+     * @return A new ResourcePoolEntry
+     */
+    public static ResourcePoolEntry createSymLink(String path,
+                                                  ResourcePoolEntry.Type type,
+                                                  ResourcePoolEntry target) {
+        return ResourcePoolEntryFactory.createSymbolicLink(path, type, target);
+    }
 }
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
index a56c77b..5f88c60 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
@@ -53,6 +53,11 @@
 main.opt.output=\
 \      --output <path>                   Location of output path
 
+main.opt.launcher=\
+\      --launcher <command>=<module>     Launcher command name for the module\n\
+\      --launcher <command>=<module>/<main>\n\
+\                                        Launcher command name for the module and the main class
+
 main.command.files=\
 \      @<filename>                       Read options from file
 
@@ -91,6 +96,9 @@
 
 
 err.unknown.byte.order:unknown byte order {0}
+err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
+err.launcher.module.name.empty:launcher module name cannot be empty: {0}
+err.launcher.value.format:launcher value should be of form <command>=<module>[/<main-class>]: {0}
 err.output.must.be.specified:--output must be specified
 err.modulepath.must.be.specified:--module-path must be specified
 err.mods.must.be.specified:no modules specified to {0}
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties
index 2bd58f6..3c2983e 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties
@@ -52,11 +52,12 @@
 By default, all resources are compressed. You can express the set \n\
 of resources to compress or not compress (use ^ for negation).
 
-copy-files.argument=<List of <file path>=<image target> to copy to the image>.
+dedup-legal-notices.argument=[error-if-not-same-content]
 
-copy-files.description=\
-If files to copy are not absolute path, JDK home dir is used.\n\
-e.g.: jrt-fs.jar,LICENSE,/home/me/myfile.txt=somewhere/conf.txt
+dedup-legal-notices.description=\
+De-duplicate all legal notices.  If error-if-not-same-content is\n\
+specified then it will be an error if two files of the same filename\n\
+are different.
 
 exclude-files.argument=<pattern-list> of files to exclude
 
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
index 40dad9f..ecc53f9 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java
@@ -31,7 +31,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
@@ -67,6 +66,7 @@
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -84,7 +84,6 @@
 import java.util.stream.Collectors;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
-import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
@@ -100,10 +99,11 @@
 import jdk.internal.joptsimple.OptionSpec;
 import jdk.internal.joptsimple.ValueConverter;
 import jdk.internal.loader.ResourceHelper;
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
 import jdk.tools.jlink.internal.Utils;
 
 import static java.util.stream.Collectors.joining;
@@ -165,6 +165,7 @@
         Mode mode;
         Path jmodFile;
         boolean help;
+        boolean helpExtra;
         boolean version;
         List<Path> classpath;
         List<Path> cmds;
@@ -172,6 +173,7 @@
         List<Path> libs;
         List<Path> headerFiles;
         List<Path> manPages;
+        List<Path> legalNotices;;
         ModuleFinder moduleFinder;
         Version moduleVersion;
         String mainClass;
@@ -179,6 +181,7 @@
         String osArch;
         String osVersion;
         Pattern modulesToHash;
+        ModuleResolution moduleResolution;
         boolean dryrun;
         List<PathMatcher> excludes;
         Path extractDir;
@@ -192,7 +195,7 @@
                 showUsageSummary();
                 return EXIT_CMDERR;
             }
-            if (options.help) {
+            if (options.help || options.helpExtra) {
                 showHelp();
                 return EXIT_OK;
             }
@@ -288,8 +291,8 @@
     private boolean describe() throws IOException {
         try (JmodFile jf = new JmodFile(options.jmodFile)) {
             try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
-                ModuleDescriptor md = ModuleDescriptor.read(in);
-                printModuleDescriptor(md);
+                ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
+                printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
                 return true;
             } catch (IOException e) {
                 throw new CommandException("err.module.descriptor.not.found");
@@ -303,9 +306,7 @@
                   .collect(joining(" "));
     }
 
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
-    private void printModuleDescriptor(ModuleDescriptor md)
+    private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
         throws IOException
     {
         StringBuilder sb = new StringBuilder();
@@ -351,15 +352,24 @@
 
         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-        JLMA.hashes(md).ifPresent(
-            hashes -> hashes.names().stream().sorted().forEach(
-                mod -> sb.append("\n  hashes ").append(mod).append(" ")
-                         .append(hashes.algorithm()).append(" ")
-                         .append(hashes.hashFor(mod))));
+        if (hashes != null) {
+            hashes.names().stream().sorted().forEach(
+                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                             .append(hashes.algorithm()).append(" ")
+                             .append(toHex(hashes.hashFor(mod))));
+        }
 
         out.println(sb.toString());
     }
 
+    private String toHex(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
     private boolean create() throws IOException {
         JmodFileWriter jmod = new JmodFileWriter();
 
@@ -392,6 +402,7 @@
         final List<Path> classpath = options.classpath;
         final List<Path> headerFiles = options.headerFiles;
         final List<Path> manPages = options.manPages;
+        final List<Path> legalNotices = options.legalNotices;
 
         final Version moduleVersion = options.moduleVersion;
         final String mainClass = options.mainClass;
@@ -400,6 +411,7 @@
         final String osVersion = options.osVersion;
         final List<PathMatcher> excludes = options.excludes;
         final Hasher hasher = hasher();
+        final ModuleResolution moduleResolution = options.moduleResolution;
 
         JmodFileWriter() { }
 
@@ -413,11 +425,12 @@
             // classes
             processClasses(out, classpath);
 
-            processSection(out, Section.NATIVE_CMDS, cmds);
-            processSection(out, Section.NATIVE_LIBS, libs);
             processSection(out, Section.CONFIG, configs);
             processSection(out, Section.HEADER_FILES, headerFiles);
+            processSection(out, Section.LEGAL_NOTICES, legalNotices);
             processSection(out, Section.MAN_PAGES, manPages);
+            processSection(out, Section.NATIVE_CMDS, cmds);
+            processSection(out, Section.NATIVE_LIBS, libs);
 
         }
 
@@ -508,6 +521,10 @@
                     }
                 }
 
+                if (moduleResolution != null && moduleResolution.value() != 0) {
+                    extender.moduleResolution(moduleResolution);
+                }
+
                 // write the (possibly extended or modified) module-info.class
                 out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
             }
@@ -536,12 +553,12 @@
                 }
 
                 URI uri = options.jmodFile.toUri();
-                ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
+                ModuleReference mref = new ModuleReference(descriptor, uri) {
                     @Override
-                    public ModuleReader get() {
+                    public ModuleReader open() {
                         throw new UnsupportedOperationException();
                     }
-                });
+                };
 
                 // compose a module finder with the module path and also
                 // a module finder that can find the jmod file being created
@@ -677,39 +694,41 @@
             if (paths == null)
                 return;
 
-            for (Path p : paths)
+            for (Path p : paths) {
                 processSection(out, section, p);
+            }
         }
 
-        void processSection(JmodOutputStream out, Section section, Path top)
+        void processSection(JmodOutputStream out, Section section, Path path)
             throws IOException
         {
-            Files.walkFileTree(top, Set.of(FileVisitOption.FOLLOW_LINKS),
-                    Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
-                @Override
-                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
-                    throws IOException
-                {
-                    Path relPath = top.relativize(file);
-                    if (relPath.toString().equals(MODULE_INFO)
-                        && !Section.CLASSES.equals(section))
-                        warning("warn.ignore.entry", MODULE_INFO, section);
+            Files.walkFileTree(path, Set.of(FileVisitOption.FOLLOW_LINKS),
+                Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                        throws IOException
+                    {
+                        Path relPath = path.relativize(file);
+                        if (relPath.toString().equals(MODULE_INFO)
+                                && !Section.CLASSES.equals(section))
+                            warning("warn.ignore.entry", MODULE_INFO, section);
 
-                    if (!relPath.toString().equals(MODULE_INFO)
-                        && !matches(relPath, excludes)) {
-                        try (InputStream in = Files.newInputStream(file)) {
-                            out.writeEntry(in, section, relPath.toString());
-                        } catch (IOException x) {
-                            if (x.getMessage().contains("duplicate entry")) {
-                                warning("warn.ignore.duplicate.entry", relPath.toString(), section);
-                                return FileVisitResult.CONTINUE;
+                        if (!relPath.toString().equals(MODULE_INFO)
+                                && !matches(relPath, excludes)) {
+                            try (InputStream in = Files.newInputStream(file)) {
+                                out.writeEntry(in, section, relPath.toString());
+                            } catch (IOException x) {
+                                if (x.getMessage().contains("duplicate entry")) {
+                                    warning("warn.ignore.duplicate.entry",
+                                            relPath.toString(), section);
+                                    return FileVisitResult.CONTINUE;
+                                }
+                                throw x;
                             }
-                            throw x;
                         }
+                        return FileVisitResult.CONTINUE;
                     }
-                    return FileVisitResult.CONTINUE;
-                }
-            });
+                });
         }
 
         boolean matches(Path path, List<PathMatcher> matchers) {
@@ -1136,6 +1155,28 @@
         @Override public String valuePattern() { return "module-version"; }
     }
 
+    static class WarnIfResolvedReasonConverter
+        implements ValueConverter<ModuleResolution>
+    {
+        @Override
+        public ModuleResolution convert(String value) {
+            if (value.equals("deprecated"))
+                return ModuleResolution.empty().withDeprecated();
+            else if (value.equals("deprecated-for-removal"))
+                return ModuleResolution.empty().withDeprecatedForRemoval();
+            else if (value.equals("incubating"))
+                return ModuleResolution.empty().withIncubating();
+            else
+                throw new CommandException("err.bad.WarnIfResolvedReason", value);
+        }
+
+        @Override public Class<ModuleResolution> valueType() {
+            return ModuleResolution.class;
+        }
+
+        @Override public String valuePattern() { return "reason"; }
+    }
+
     static class PatternConverter implements ValueConverter<Pattern> {
         @Override
         public Pattern convert(String value) {
@@ -1179,12 +1220,24 @@
      */
     private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
 
-        private JmodHelpFormatter() { super(80, 2); }
+        private final Options opts;
+
+        private JmodHelpFormatter(Options opts) {
+            super(80, 2);
+            this.opts = opts;
+        }
 
         @Override
         public String format(Map<String, ? extends OptionDescriptor> options) {
-            Map<String, OptionDescriptor> all = new HashMap<>();
+            Map<String, OptionDescriptor> all = new LinkedHashMap<>();
             all.putAll(options);
+
+            // extra options
+            if (!opts.helpExtra) {
+                all.remove("do-not-resolve-by-default");
+                all.remove("warn-if-resolved");
+            }
+
             all.put(CMD_FILENAME, new OptionDescriptor() {
                 @Override
                 public Collection<String> options() {
@@ -1240,7 +1293,8 @@
     private final OptionParser parser = new OptionParser("hp");
 
     private void handleOptions(String[] args) {
-        parser.formatHelpWith(new JmodHelpFormatter());
+        options = new Options();
+        parser.formatHelpWith(new JmodHelpFormatter(options));
 
         OptionSpec<Path> classPath
                 = parser.accepts("class-path", getMessage("main.opt.class-path"))
@@ -1266,7 +1320,7 @@
                         .withValuesConvertedBy(new ExtractDirPathConverter());
 
         OptionSpec<Void> dryrun
-            = parser.accepts("dry-run", getMessage("main.opt.dry-run"));
+                = parser.accepts("dry-run", getMessage("main.opt.dry-run"));
 
         OptionSpec<PathMatcher> excludes
                 = parser.accepts("exclude", getMessage("main.opt.exclude"))
@@ -1282,11 +1336,14 @@
                 = parser.acceptsAll(Set.of("h", "help"), getMessage("main.opt.help"))
                         .forHelp();
 
+        OptionSpec<Void> helpExtra
+                = parser.accepts("help-extra", getMessage("main.opt.help-extra"));
+
         OptionSpec<Path> headerFiles
-            = parser.accepts("header-files", getMessage("main.opt.header-files"))
-                    .withRequiredArg()
-                    .withValuesSeparatedBy(File.pathSeparatorChar)
-                    .withValuesConvertedBy(DirPathConverter.INSTANCE);
+                = parser.accepts("header-files", getMessage("main.opt.header-files"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
 
         OptionSpec<Path> libs
                 = parser.accepts("libs", getMessage("main.opt.libs"))
@@ -1294,13 +1351,20 @@
                         .withValuesSeparatedBy(File.pathSeparatorChar)
                         .withValuesConvertedBy(DirPathConverter.INSTANCE);
 
+        OptionSpec<Path> legalNotices
+                = parser.accepts("legal-notices", getMessage("main.opt.legal-notices"))
+                        .withRequiredArg()
+                        .withValuesSeparatedBy(File.pathSeparatorChar)
+                        .withValuesConvertedBy(DirPathConverter.INSTANCE);
+
+
         OptionSpec<String> mainClass
                 = parser.accepts("main-class", getMessage("main.opt.main-class"))
                         .withRequiredArg()
                         .describedAs(getMessage("main.opt.main-class.arg"));
 
         OptionSpec<Path> manPages
-            = parser.accepts("man-pages", getMessage("main.opt.man-pages"))
+                = parser.accepts("man-pages", getMessage("main.opt.man-pages"))
                         .withRequiredArg()
                         .withValuesSeparatedBy(File.pathSeparatorChar)
                         .withValuesConvertedBy(DirPathConverter.INSTANCE);
@@ -1332,6 +1396,15 @@
                         .withRequiredArg()
                         .describedAs(getMessage("main.opt.os-version.arg"));
 
+        OptionSpec<Void> doNotResolveByDefault
+                = parser.accepts("do-not-resolve-by-default",
+                                 getMessage("main.opt.do-not-resolve-by-default"));
+
+        OptionSpec<ModuleResolution> warnIfResolved
+                = parser.accepts("warn-if-resolved", getMessage("main.opt.warn-if-resolved"))
+                        .withRequiredArg()
+                        .withValuesConvertedBy(new WarnIfResolvedReasonConverter());
+
         OptionSpec<Void> version
                 = parser.accepts("version", getMessage("main.opt.version"));
 
@@ -1341,9 +1414,9 @@
         try {
             OptionSet opts = parser.parse(args);
 
-            if (opts.has(help) || opts.has(version)) {
-                options = new Options();
+            if (opts.has(help) || opts.has(helpExtra) || opts.has(version)) {
                 options.help = opts.has(help);
+                options.helpExtra = opts.has(helpExtra);
                 options.version = opts.has(version);
                 return;  // informational message will be shown
             }
@@ -1352,7 +1425,6 @@
             if (words.isEmpty())
                 throw new CommandException("err.missing.mode").showUsage(true);
             String verb = words.get(0);
-            options = new Options();
             try {
                 options.mode = Enum.valueOf(Mode.class, verb.toUpperCase());
             } catch (IllegalArgumentException e) {
@@ -1377,9 +1449,11 @@
                 options.headerFiles = opts.valuesOf(headerFiles);
             if (opts.has(manPages))
                 options.manPages = opts.valuesOf(manPages);
+            if (opts.has(legalNotices))
+                options.legalNotices = opts.valuesOf(legalNotices);
             if (opts.has(modulePath)) {
                 Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
-                options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs);
+                options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
             }
             if (opts.has(moduleVersion))
                 options.moduleVersion = opts.valueOf(moduleVersion);
@@ -1391,6 +1465,13 @@
                 options.osArch = opts.valueOf(osArch);
             if (opts.has(osVersion))
                 options.osVersion = opts.valueOf(osVersion);
+            if (opts.has(warnIfResolved))
+                options.moduleResolution = opts.valueOf(warnIfResolved);
+            if (opts.has(doNotResolveByDefault)) {
+                if (options.moduleResolution == null)
+                    options.moduleResolution = ModuleResolution.empty();
+                options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault();
+            }
             if (opts.has(hashModules)) {
                 options.modulesToHash = opts.valueOf(hashModules);
                 // if storing hashes then the module path is required
diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
index bdf5635..f878102 100644
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties
@@ -47,6 +47,7 @@
 \hash      - Records hashes of tied modules.
 
 main.opt.help=Print this usage message
+main.opt.help-extra=Print help on extra options
 main.opt.version=Version information
 main.opt.class-path=Application jar files|dir containing classes
 main.opt.libs=Location of native libraries
@@ -58,6 +59,7 @@
 \ list, each element using one the following forms: <glob-pattern>,\
 \ glob:<glob-pattern> or regex:<regex-pattern>
 main.opt.header-files=Location of header files
+main.opt.legal-notices=Location of legal notices
 main.opt.module-version= Module version
 main.opt.main-class=Main class
 main.opt.main-class.arg=class-name
@@ -73,6 +75,9 @@
 \ with modules matching the given <regex-pattern> and depending upon it directly\
 \ or indirectly. The hashes are recorded in the JMOD file being created, or\
 \ a JMOD file or modular JAR on the module path specified the jmod hash command.
+main.opt.do-not-resolve-by-default=Exclude from the default root set of modules
+main.opt.warn-if-resolved=Hint for a tool to issue a warning if the module \
+is resolved. One of deprecated, deprecated-for-removal, or incubating
 
 main.opt.cmdfile=Read options from the specified file
 
@@ -95,6 +100,8 @@
 err.file.already.exists=file already exists: {0}
 err.jmod.not.found=no jmod file found: {0}
 err.bad.pattern=bad pattern {0}
+err.bad.WarnIfResolvedReason=bad reason: {0}, must be one of deprecated,\
+\ deprecated-for-removal, or incubating
 err.unknown.option=unknown option(s): {0}
 err.missing.arg=no value given for {0}
 err.internal.error=internal error: {0} {1} {2}
@@ -104,6 +111,6 @@
 warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0}
 warn.module.resolution.fail=No hashes recorded: {0}
 warn.ignore.entry=ignoring entry {0}, in section {1}
-warn.ignore.duplicate.entry=ignoring duplicate entry {0}, in section{1}
+warn.ignore.duplicate.entry=ignoring duplicate entry {0}, in section {1}
 
 
diff --git a/jdk/src/jdk.jlink/share/classes/module-info.java b/jdk/src/jdk.jlink/share/classes/module-info.java
index e20c763..69c4ae9 100644
--- a/jdk/src/jdk.jlink/share/classes/module-info.java
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java
@@ -36,12 +36,12 @@
         jdk.tools.jlink.internal.Main.JlinkToolProvider;
 
     provides jdk.tools.jlink.plugin.Plugin with
-        jdk.tools.jlink.internal.plugins.FileCopierPlugin,
         jdk.tools.jlink.internal.plugins.StripDebugPlugin,
         jdk.tools.jlink.internal.plugins.ExcludePlugin,
         jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
         jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
-        jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
+        jdk.tools.jlink.internal.plugins.LegalNoticeFilePlugin,
+        jdk.tools.jlink.internal.plugins.SystemModulesPlugin,
         jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
         jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
         jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
diff --git a/jdk/src/jdk.localedata/share/legal/cldr.md b/jdk/src/jdk.localedata/share/legal/cldr.md
new file mode 100644
index 0000000..21e6d4c
--- /dev/null
+++ b/jdk/src/jdk.localedata/share/legal/cldr.md
@@ -0,0 +1,42 @@
+## Unicode Common Local Data Repository (CLDR) v29
+
+### CLDR License
+<pre>
+
+Copyright © 1991-2016 Unicode, Inc. All rights reserved.
+
+Distributed under the Terms of Use in
+http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation
+(the "Data Files") or Unicode software and any associated documentation
+(the "Software") to deal in the Data Files or Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of
+the Data Files or Software, and to permit persons to whom the Data Files
+or Software are furnished to do so, provided that
+(a) this copyright and permission notice appear with all copies
+of the Data Files or Software,
+(b) this copyright and permission notice appear in associated
+documentation, and
+(c) there is clear notice in each modified Data File or in the Software
+as well as in the documentation associated with the Data File(s) or
+Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in these Data Files or Software without prior written authorization of
+the copyright holder.
+
+</pre>
diff --git a/jdk/src/jdk.localedata/share/legal/thaidict.md b/jdk/src/jdk.localedata/share/legal/thaidict.md
new file mode 100644
index 0000000..f8b1133
--- /dev/null
+++ b/jdk/src/jdk.localedata/share/legal/thaidict.md
@@ -0,0 +1,31 @@
+## Thai Dictionary
+
+### Thai Dictionary License
+<pre>
+
+Copyright (C) 1982 The Royal Institute, Thai Royal Government.
+
+Copyright (C) 1998 National Electronics and Computer Technology Center,
+National Science and Technology Development Agency,
+Ministry of Science Technology and Environment,
+Thai Royal Government.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+</pre>
diff --git a/jdk/src/jdk.pack/share/classes/module-info.java b/jdk/src/jdk.pack/share/classes/module-info.java
new file mode 100644
index 0000000..3cedd09
--- /dev/null
+++ b/jdk/src/jdk.pack/share/classes/module-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.pack {
+}
+
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp b/jdk/src/jdk.pack/share/native/common-unpack/bands.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp
rename to jdk/src/jdk.pack/share/native/common-unpack/bands.cpp
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/bands.h b/jdk/src/jdk.pack/share/native/common-unpack/bands.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/bands.h
rename to jdk/src/jdk.pack/share/native/common-unpack/bands.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp b/jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp
rename to jdk/src/jdk.pack/share/native/common-unpack/bytes.cpp
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/bytes.h b/jdk/src/jdk.pack/share/native/common-unpack/bytes.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/bytes.h
rename to jdk/src/jdk.pack/share/native/common-unpack/bytes.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp b/jdk/src/jdk.pack/share/native/common-unpack/coding.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp
rename to jdk/src/jdk.pack/share/native/common-unpack/coding.cpp
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/coding.h b/jdk/src/jdk.pack/share/native/common-unpack/coding.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/coding.h
rename to jdk/src/jdk.pack/share/native/common-unpack/coding.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/constants.h b/jdk/src/jdk.pack/share/native/common-unpack/constants.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/constants.h
rename to jdk/src/jdk.pack/share/native/common-unpack/constants.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/defines.h b/jdk/src/jdk.pack/share/native/common-unpack/defines.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/defines.h
rename to jdk/src/jdk.pack/share/native/common-unpack/defines.h
diff --git a/jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp b/jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp
new file mode 100644
index 0000000..8f7a09d
--- /dev/null
+++ b/jdk/src/jdk.pack/share/native/common-unpack/unpack.cpp
@@ -0,0 +1,5244 @@
+/*
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -*- C++ -*-
+// Program for unpacking specially compressed Java packages.
+// John R. Rose
+
+/*
+ * When compiling for a 64bit LP64 system (longs and pointers being 64bits),
+ *    the printf format %ld is correct and use of %lld will cause warning
+ *    errors from some compilers (gcc/g++).
+ * _LP64 can be explicitly set (used on Linux).
+ * Should be checking for the Visual C++ since the _LP64 is set on the 64-bit
+ * systems but the correct format prefix for 64-bit integers is ll.
+ * Solaris compilers will define __sparcv9 or __x86_64 on 64bit compilations.
+ */
+#if !defined (_MSC_VER) && \
+    (defined(_LP64) || defined(__sparcv9) || defined(__x86_64))
+  #define LONG_LONG_FORMAT "%ld"
+  #define LONG_LONG_HEX_FORMAT "%lx"
+#else
+  #define LONG_LONG_FORMAT "%lld"
+  #define LONG_LONG_HEX_FORMAT "%016llx"
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <limits.h>
+#include <time.h>
+
+
+
+
+#include "defines.h"
+#include "bytes.h"
+#include "utils.h"
+#include "coding.h"
+#include "bands.h"
+
+#include "constants.h"
+
+#include "zip.h"
+
+#include "unpack.h"
+
+
+// tags, in canonical order:
+static const byte TAGS_IN_ORDER[] = {
+  CONSTANT_Utf8,
+  CONSTANT_Integer,
+  CONSTANT_Float,
+  CONSTANT_Long,
+  CONSTANT_Double,
+  CONSTANT_String,
+  CONSTANT_Class,
+  CONSTANT_Signature,
+  CONSTANT_NameandType,
+  CONSTANT_Fieldref,
+  CONSTANT_Methodref,
+  CONSTANT_InterfaceMethodref,
+  // constants defined as of JDK 7
+  CONSTANT_MethodHandle,
+  CONSTANT_MethodType,
+  CONSTANT_BootstrapMethod,
+  CONSTANT_InvokeDynamic
+};
+#define N_TAGS_IN_ORDER (sizeof TAGS_IN_ORDER)
+
+#ifndef PRODUCT
+static const char* TAG_NAME[] = {
+  "*None",
+  "Utf8",
+  "*Unicode",
+  "Integer",
+  "Float",
+  "Long",
+  "Double",
+  "Class",
+  "String",
+  "Fieldref",
+  "Methodref",
+  "InterfaceMethodref",
+  "NameandType",
+  "*Signature",
+  "unused14",
+  "MethodHandle",
+  "MethodType",
+  "*BootstrapMethod",
+  "InvokeDynamic",
+  0
+};
+
+static const char* ATTR_CONTEXT_NAME[] = {  // match ATTR_CONTEXT_NAME, etc.
+  "class", "field", "method", "code"
+};
+
+#else
+
+#define ATTR_CONTEXT_NAME ((const char**)null)
+
+#endif
+
+// Note that REQUESTED_LDC comes first, then the normal REQUESTED,
+// in the regular constant pool.
+enum { REQUESTED_NONE = -1,
+       // The codes below REQUESTED_NONE are in constant pool output order,
+       // for the sake of outputEntry_cmp:
+       REQUESTED_LDC = -99, REQUESTED
+};
+
+#define NO_INORD ((uint)-1)
+
+struct entry {
+  byte tag;
+
+  #if 0
+  byte bits;
+  enum {
+    //EB_EXTRA = 1,
+    EB_SUPER = 2
+  };
+  #endif
+  unsigned short nrefs;  // pack w/ tag
+
+  int  outputIndex;
+  uint inord;   // &cp.entries[cp.tag_base[this->tag]+this->inord] == this
+
+  entry* *refs;
+
+  // put last to pack best
+  union {
+    bytes b;
+    int i;
+    jlong l;
+  } value;
+
+  void requestOutputIndex(cpool& cp, int req = REQUESTED);
+  int getOutputIndex() {
+    assert(outputIndex > REQUESTED_NONE);
+    return outputIndex;
+  }
+
+  entry* ref(int refnum) {
+    assert((uint)refnum < nrefs);
+    return refs[refnum];
+  }
+
+  const char* utf8String() {
+    assert(tagMatches(CONSTANT_Utf8));
+    if (value.b.len != strlen((const char*)value.b.ptr)) {
+      unpack_abort("bad utf8 encoding");
+      // and fall through
+    }
+    return (const char*)value.b.ptr;
+  }
+
+  entry* className() {
+    assert(tagMatches(CONSTANT_Class));
+    return ref(0);
+  }
+
+  entry* memberClass() {
+    assert(tagMatches(CONSTANT_AnyMember));
+    return ref(0);
+  }
+
+  entry* memberDescr() {
+    assert(tagMatches(CONSTANT_AnyMember));
+    return ref(1);
+  }
+
+  entry* descrName() {
+    assert(tagMatches(CONSTANT_NameandType));
+    return ref(0);
+  }
+
+  entry* descrType() {
+    assert(tagMatches(CONSTANT_NameandType));
+    return ref(1);
+  }
+
+  int typeSize();
+
+  bytes& asUtf8();
+  int    asInteger() { assert(tag == CONSTANT_Integer); return value.i; }
+
+  bool isUtf8(bytes& b) { return tagMatches(CONSTANT_Utf8) && value.b.equals(b); }
+
+  bool isDoubleWord() { return tag == CONSTANT_Double || tag == CONSTANT_Long; }
+
+  bool tagMatches(byte tag2) {
+    return (tag2 == tag)
+      || (tag2 == CONSTANT_Utf8 && tag == CONSTANT_Signature)
+      #ifndef PRODUCT
+      || (tag2 == CONSTANT_FieldSpecific
+          && tag >= CONSTANT_Integer && tag <= CONSTANT_String && tag != CONSTANT_Class)
+      || (tag2 == CONSTANT_AnyMember
+          && tag >= CONSTANT_Fieldref && tag <= CONSTANT_InterfaceMethodref)
+      #endif
+      ;
+  }
+
+#ifdef PRODUCT
+  const char* string() { return NULL; }
+#else
+  const char* string();  // see far below
+#endif
+};
+
+entry* cpindex::get(uint i) {
+  if (i >= len)
+    return null;
+  else if (base1 != null)
+    // primary index
+    return &base1[i];
+  else
+    // secondary index
+    return base2[i];
+}
+
+inline bytes& entry::asUtf8() {
+  assert(tagMatches(CONSTANT_Utf8));
+  return value.b;
+}
+
+int entry::typeSize() {
+  assert(tagMatches(CONSTANT_Utf8));
+  const char* sigp = (char*) value.b.ptr;
+  switch (*sigp) {
+  case '(': sigp++; break;  // skip opening '('
+  case 'D':
+  case 'J': return 2; // double field
+  default:  return 1; // field
+  }
+  int siglen = 0;
+  for (;;) {
+    int ch = *sigp++;
+    switch (ch) {
+    case 'D': case 'J':
+      siglen += 1;
+      break;
+    case '[':
+      // Skip rest of array info.
+      while (ch == '[') { ch = *sigp++; }
+      if (ch != 'L')  break;
+      // else fall through
+    case 'L':
+      sigp = strchr(sigp, ';');
+      if (sigp == null) {
+          unpack_abort("bad data");
+          return 0;
+      }
+      sigp += 1;
+      break;
+    case ')':  // closing ')'
+      return siglen;
+    }
+    siglen += 1;
+  }
+}
+
+inline cpindex* cpool::getFieldIndex(entry* classRef) {
+  if (classRef == NULL) { abort("missing class reference"); return NULL; }
+  assert(classRef->tagMatches(CONSTANT_Class));
+  assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]);
+  return &member_indexes[classRef->inord*2+0];
+}
+inline cpindex* cpool::getMethodIndex(entry* classRef) {
+  if (classRef == NULL) { abort("missing class reference"); return NULL; }
+  assert(classRef->tagMatches(CONSTANT_Class));
+  assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]);
+  return &member_indexes[classRef->inord*2+1];
+}
+
+struct inner_class {
+  entry* inner;
+  entry* outer;
+  entry* name;
+  int    flags;
+  inner_class* next_sibling;
+  bool   requested;
+};
+
+// Here is where everything gets deallocated:
+void unpacker::free() {
+  int i;
+  assert(jniobj == null); // caller resp.
+  assert(infileptr == null);  // caller resp.
+  if (jarout != null)  jarout->reset();
+  if (gzin != null)    { gzin->free(); gzin = null; }
+  if (free_input)  input.free();
+  // free everybody ever allocated with U_NEW or (recently) with T_NEW
+  assert(smallbuf.base()  == null || mallocs.contains(smallbuf.base()));
+  assert(tsmallbuf.base() == null || tmallocs.contains(tsmallbuf.base()));
+  mallocs.freeAll();
+  tmallocs.freeAll();
+  smallbuf.init();
+  tsmallbuf.init();
+  bcimap.free();
+  class_fixup_type.free();
+  class_fixup_offset.free();
+  class_fixup_ref.free();
+  code_fixup_type.free();
+  code_fixup_offset.free();
+  code_fixup_source.free();
+  requested_ics.free();
+  cp.requested_bsms.free();
+  cur_classfile_head.free();
+  cur_classfile_tail.free();
+  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++)
+    attr_defs[i].free();
+
+  // free CP state
+  cp.outputEntries.free();
+  for (i = 0; i < CONSTANT_Limit; i++)
+    cp.tag_extras[i].free();
+}
+
+// input handling
+// Attempts to advance rplimit so that (rplimit-rp) is at least 'more'.
+// Will eagerly read ahead by larger chunks, if possible.
+// Returns false if (rplimit-rp) is not at least 'more',
+// unless rplimit hits input.limit().
+bool unpacker::ensure_input(jlong more) {
+  julong want = more - input_remaining();
+  if ((jlong)want <= 0)          return true;  // it's already in the buffer
+  if (rplimit == input.limit())  return true;  // not expecting any more
+
+  if (read_input_fn == null) {
+    // assume it is already all there
+    bytes_read += input.limit() - rplimit;
+    rplimit = input.limit();
+    return true;
+  }
+  CHECK_0;
+
+  julong remaining = (input.limit() - rplimit);  // how much left to read?
+  byte* rpgoal = (want >= remaining)? input.limit(): rplimit + (size_t)want;
+  enum { CHUNK_SIZE = (1<<14) };
+  julong fetch = want;
+  if (fetch < CHUNK_SIZE)
+    fetch = CHUNK_SIZE;
+  if (fetch > remaining*3/4)
+    fetch = remaining;
+  // Try to fetch at least "more" bytes.
+  while ((jlong)fetch > 0) {
+    jlong nr = (*read_input_fn)(this, rplimit, fetch, remaining);
+    if (nr <= 0) {
+      return (rplimit >= rpgoal);
+    }
+    remaining -= nr;
+    rplimit += nr;
+    fetch -= nr;
+    bytes_read += nr;
+    assert(remaining == (julong)(input.limit() - rplimit));
+  }
+  return true;
+}
+
+// output handling
+
+fillbytes* unpacker::close_output(fillbytes* which) {
+  assert(wp != null);
+  if (which == null) {
+    if (wpbase == cur_classfile_head.base()) {
+      which = &cur_classfile_head;
+    } else {
+      which = &cur_classfile_tail;
+    }
+  }
+  assert(wpbase  == which->base());
+  assert(wplimit == which->end());
+  which->setLimit(wp);
+  wp      = null;
+  wplimit = null;
+  //wpbase = null;
+  return which;
+}
+
+//maybe_inline
+void unpacker::ensure_put_space(size_t size) {
+  if (wp + size <= wplimit)  return;
+  // Determine which segment needs expanding.
+  fillbytes* which = close_output();
+  byte* wp0 = which->grow(size);
+  wpbase  = which->base();
+  wplimit = which->end();
+  wp = wp0;
+}
+
+maybe_inline
+byte* unpacker::put_space(size_t size) {
+  byte* wp0 = wp;
+  byte* wp1 = wp0 + size;
+  if (wp1 > wplimit) {
+    ensure_put_space(size);
+    wp0 = wp;
+    wp1 = wp0 + size;
+  }
+  wp = wp1;
+  return wp0;
+}
+
+maybe_inline
+void unpacker::putu2_at(byte* wp, int n) {
+  if (n != (unsigned short)n) {
+    unpack_abort(ERROR_OVERFLOW);
+    return;
+  }
+  wp[0] = (n) >> 8;
+  wp[1] = (n) >> 0;
+}
+
+maybe_inline
+void unpacker::putu4_at(byte* wp, int n) {
+  wp[0] = (n) >> 24;
+  wp[1] = (n) >> 16;
+  wp[2] = (n) >> 8;
+  wp[3] = (n) >> 0;
+}
+
+maybe_inline
+void unpacker::putu8_at(byte* wp, jlong n) {
+  putu4_at(wp+0, (int)((julong)n >> 32));
+  putu4_at(wp+4, (int)((julong)n >> 0));
+}
+
+maybe_inline
+void unpacker::putu2(int n) {
+  putu2_at(put_space(2), n);
+}
+
+maybe_inline
+void unpacker::putu4(int n) {
+  putu4_at(put_space(4), n);
+}
+
+maybe_inline
+void unpacker::putu8(jlong n) {
+  putu8_at(put_space(8), n);
+}
+
+maybe_inline
+int unpacker::putref_index(entry* e, int size) {
+  if (e == null)
+    return 0;
+  else if (e->outputIndex > REQUESTED_NONE)
+    return e->outputIndex;
+  else if (e->tag == CONSTANT_Signature)
+    return putref_index(e->ref(0), size);
+  else {
+    e->requestOutputIndex(cp, (size == 1 ? REQUESTED_LDC : REQUESTED));
+    // Later on we'll fix the bits.
+    class_fixup_type.addByte(size);
+    class_fixup_offset.add((int)wpoffset());
+    class_fixup_ref.add(e);
+#ifdef PRODUCT
+    return 0;
+#else
+    return 0x20+size;  // 0x22 is easy to eyeball
+#endif
+  }
+}
+
+maybe_inline
+void unpacker::putref(entry* e) {
+  int oidx = putref_index(e, 2);
+  putu2_at(put_space(2), oidx);
+}
+
+maybe_inline
+void unpacker::putu1ref(entry* e) {
+  int oidx = putref_index(e, 1);
+  putu1_at(put_space(1), oidx);
+}
+
+
+static int total_cp_size[] = {0, 0};
+static int largest_cp_ref[] = {0, 0};
+static int hash_probes[] = {0, 0};
+
+// Allocation of small and large blocks.
+
+enum { CHUNK = (1 << 14), SMALL = (1 << 9) };
+
+// Call malloc.  Try to combine small blocks and free much later.
+void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) {
+  if (!smallOK || size > SMALL) {
+    void* res = must_malloc((int)size);
+    (temp ? &tmallocs : &mallocs)->add(res);
+    return res;
+  }
+  fillbytes& xsmallbuf = *(temp ? &tsmallbuf : &smallbuf);
+  if (!xsmallbuf.canAppend(size+1)) {
+    xsmallbuf.init(CHUNK);
+    (temp ? &tmallocs : &mallocs)->add(xsmallbuf.base());
+  }
+  int growBy = (int)size;
+  growBy += -growBy & 7;  // round up mod 8
+  return xsmallbuf.grow(growBy);
+}
+
+maybe_inline
+void unpacker::saveTo(bytes& b, byte* ptr, size_t len) {
+  b.ptr = U_NEW(byte, add_size(len,1));
+  if (aborting()) {
+    b.len = 0;
+    return;
+  }
+  b.len = len;
+  b.copyFrom(ptr, len);
+}
+
+bool testBit(int archive_options, int bitMask) {
+    return (archive_options & bitMask) != 0;
+}
+
+// Read up through band_headers.
+// Do the archive_size dance to set the size of the input mega-buffer.
+void unpacker::read_file_header() {
+  // Read file header to determine file type and total size.
+  enum {
+    MAGIC_BYTES = 4,
+    AH_LENGTH_0 = 3,  // archive_header_0 = {minver, majver, options}
+    AH_LENGTH_MIN = 15, // observed in spec {header_0[3], cp_counts[8], class_counts[4]}
+    AH_LENGTH_0_MAX = AH_LENGTH_0 + 1,  // options might have 2 bytes
+    AH_LENGTH   = 30, //maximum archive header length (w/ all fields)
+    // Length contributions from optional header fields:
+    AH_LENGTH_S = 2, // archive_header_S = optional {size_hi, size_lo}
+    AH_ARCHIVE_SIZE_HI = 0, // offset in archive_header_S
+    AH_ARCHIVE_SIZE_LO = 1, // offset in archive_header_S
+    AH_FILE_HEADER_LEN = 5, // file_counts = {{size_hi, size_lo), next, modtile, files}
+    AH_SPECIAL_FORMAT_LEN = 2, // special_count = {layouts, band_headers}
+    AH_CP_NUMBER_LEN = 4,      // cp_number_counts = {int, float, long, double}
+    AH_CP_EXTRA_LEN = 4,        // cp_attr_counts = {MH, MT, InDy, BSM}
+    ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S,
+    FIRST_READ  = MAGIC_BYTES + AH_LENGTH_MIN
+  };
+
+  assert(AH_LENGTH_MIN    == 15); // # of UNSIGNED5 fields required after archive_magic
+  // An absolute minimum null archive is magic[4], {minver,majver,options}[3],
+  // archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes.
+  // (Note that archive_size is optional; it may be 0..10 bytes in length.)
+  // The first read must capture everything up through the options field.
+  // This happens to work even if {minver,majver,options} is a pathological
+  // 15 bytes long.  Legal pack files limit those three fields to 1+1+2 bytes.
+  assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX);
+
+  // Up through archive_size, the largest possible archive header is
+  // magic[4], {minver,majver,options}[4], archive_size[10].
+  // (Note only the low 12 bits of options are allowed to be non-zero.)
+  // In order to parse archive_size, we need at least this many bytes
+  // in the first read.  Of course, if archive_size_hi is more than
+  // a byte, we probably will fail to allocate the buffer, since it
+  // will be many gigabytes long.  This is a practical, not an
+  // architectural limit to Pack200 archive sizes.
+  assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2*B_MAX);
+
+  bool foreign_buf = (read_input_fn == null);
+  byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200];  // 200 is for JAR I/O
+  if (foreign_buf) {
+    // inbytes is all there is
+    input.set(inbytes);
+    rp      = input.base();
+    rplimit = input.limit();
+  } else {
+    // inbytes, if not empty, contains some read-ahead we must use first
+    // ensure_input will take care of copying it into initbuf,
+    // then querying read_input_fn for any additional data needed.
+    // However, the caller must assume that we use up all of inbytes.
+    // There is no way to tell the caller that we used only part of them.
+    // Therefore, the caller must use only a bare minimum of read-ahead.
+    if (inbytes.len > FIRST_READ) {
+      abort("too much read-ahead");
+      return;
+    }
+    input.set(initbuf, sizeof(initbuf));
+    input.b.clear();
+    input.b.copyFrom(inbytes);
+    rplimit = rp = input.base();
+    rplimit += inbytes.len;
+    bytes_read += inbytes.len;
+  }
+  // Read only 19 bytes, which is certain to contain #archive_options fields,
+  // but is certain not to overflow past the archive_header.
+  input.b.len = FIRST_READ;
+  if (!ensure_input(FIRST_READ))
+    abort("EOF reading archive magic number");
+
+  if (rp[0] == 'P' && rp[1] == 'K') {
+#ifdef UNPACK_JNI
+    // Java driver must handle this case before we get this far.
+    abort("encountered a JAR header in unpacker");
+#else
+    // In the Unix-style program, we simply simulate a copy command.
+    // Copy until EOF; assume the JAR file is the last segment.
+    fprintf(errstrm, "Copy-mode.\n");
+    for (;;) {
+      jarout->write_data(rp, (int)input_remaining());
+      if (foreign_buf)
+        break;  // one-time use of a passed in buffer
+      if (input.size() < CHUNK) {
+        // Get some breathing room.
+        input.set(U_NEW(byte, (size_t) CHUNK + C_SLOP), (size_t) CHUNK);
+        CHECK;
+      }
+      rp = rplimit = input.base();
+      if (!ensure_input(1))
+        break;
+    }
+    jarout->closeJarFile(false);
+#endif
+    return;
+  }
+
+  // Read the magic number.
+  magic = 0;
+  for (int i1 = 0; i1 < (int)sizeof(magic); i1++) {
+    magic <<= 8;
+    magic += (*rp++ & 0xFF);
+  }
+
+  // Read the first 3 values from the header.
+  value_stream hdr;
+  int          hdrVals = 0;
+  int          hdrValsSkipped = 0;  // for assert
+  hdr.init(rp, rplimit, UNSIGNED5_spec);
+  minver = hdr.getInt();
+  majver = hdr.getInt();
+  hdrVals += 2;
+
+  int majmin[4][2] = {
+      {JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION},
+      {JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION},
+      {JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION},
+      {JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION}
+  };
+  int majminfound = false;
+  for (int i = 0 ; i < 4 ; i++) {
+      if (majver == majmin[i][0] && minver == majmin[i][1]) {
+          majminfound = true;
+          break;
+      }
+  }
+  if (majminfound == null) {
+    char message[200];
+    sprintf(message, "@" ERROR_FORMAT ": magic/ver = "
+            "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d\n",
+            magic, majver, minver,
+            JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION,
+            JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION,
+            JAVA_PACKAGE_MAGIC, JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION,
+            JAVA_PACKAGE_MAGIC, JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION);
+    abort(message);
+  }
+  CHECK;
+
+  archive_options = hdr.getInt();
+  hdrVals += 1;
+  assert(hdrVals == AH_LENGTH_0);  // first three fields only
+  bool haveSizeHi = testBit(archive_options, AO_HAVE_FILE_SIZE_HI);
+  bool haveModTime = testBit(archive_options, AO_HAVE_FILE_MODTIME);
+  bool haveFileOpt = testBit(archive_options, AO_HAVE_FILE_OPTIONS);
+
+  bool haveSpecial = testBit(archive_options, AO_HAVE_SPECIAL_FORMATS);
+  bool haveFiles = testBit(archive_options, AO_HAVE_FILE_HEADERS);
+  bool haveNumbers = testBit(archive_options, AO_HAVE_CP_NUMBERS);
+  bool haveCPExtra = testBit(archive_options, AO_HAVE_CP_EXTRAS);
+
+  if (majver < JAVA7_PACKAGE_MAJOR_VERSION) {
+    if (haveCPExtra) {
+        abort("Format bits for Java 7 must be zero in previous releases");
+        return;
+    }
+  }
+  if (testBit(archive_options, AO_UNUSED_MBZ)) {
+    abort("High archive option bits are reserved and must be zero");
+    return;
+  }
+  if (haveFiles) {
+    uint hi = hdr.getInt();
+    uint lo = hdr.getInt();
+    julong x = band::makeLong(hi, lo);
+    archive_size = (size_t) x;
+    if (archive_size != x) {
+      // Silly size specified; force overflow.
+      archive_size = PSIZE_MAX+1;
+    }
+    hdrVals += 2;
+  } else {
+    hdrValsSkipped += 2;
+  }
+
+  // Now we can size the whole archive.
+  // Read everything else into a mega-buffer.
+  rp = hdr.rp;
+  size_t header_size_0 = (rp - input.base()); // used-up header (4byte + 3int)
+  size_t header_size_1 = (rplimit - rp);      // buffered unused initial fragment
+  size_t header_size   = header_size_0 + header_size_1;
+  unsized_bytes_read = header_size_0;
+  CHECK;
+  if (foreign_buf) {
+    if (archive_size > header_size_1) {
+      abort("EOF reading fixed input buffer");
+      return;
+    }
+  } else if (archive_size != 0) {
+    if (archive_size < ARCHIVE_SIZE_MIN) {
+      abort("impossible archive size");  // bad input data
+      return;
+    }
+    if (archive_size < header_size_1) {
+      abort("too much read-ahead");  // somehow we pre-fetched too much?
+      return;
+    }
+    input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
+              header_size_0 + archive_size);
+    CHECK;
+    assert(input.limit()[0] == 0);
+    // Move all the bytes we read initially into the real buffer.
+    input.b.copyFrom(initbuf, header_size);
+    rp      = input.b.ptr + header_size_0;
+    rplimit = input.b.ptr + header_size;
+  } else {
+    // It's more complicated and painful.
+    // A zero archive_size means that we must read until EOF.
+    input.init(CHUNK*2);
+    CHECK;
+    input.b.len = input.allocated;
+    rp = rplimit = input.base();
+    // Set up input buffer as if we already read the header:
+    input.b.copyFrom(initbuf, header_size);
+    CHECK;
+    rplimit += header_size;
+    while (ensure_input(input.limit() - rp)) {
+      size_t dataSoFar = input_remaining();
+      size_t nextSize = add_size(dataSoFar, CHUNK);
+      input.ensureSize(nextSize);
+      CHECK;
+      input.b.len = input.allocated;
+      rp = rplimit = input.base();
+      rplimit += dataSoFar;
+    }
+    size_t dataSize = (rplimit - input.base());
+    input.b.len = dataSize;
+    input.grow(C_SLOP);
+    CHECK;
+    free_input = true;  // free it later
+    input.b.len = dataSize;
+    assert(input.limit()[0] == 0);
+    rp = rplimit = input.base();
+    rplimit += dataSize;
+    rp += header_size_0;  // already scanned these bytes...
+  }
+  live_input = true;    // mark as "do not reuse"
+  if (aborting()) {
+    abort("cannot allocate large input buffer for package file");
+    return;
+  }
+
+  // read the rest of the header fields  int assertSkipped = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S;
+  int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S;
+  if (haveSpecial)
+    remainingHeaders += AH_SPECIAL_FORMAT_LEN;
+  if (haveFiles)
+     remainingHeaders += AH_FILE_HEADER_LEN;
+  if (haveNumbers)
+    remainingHeaders += AH_CP_NUMBER_LEN;
+  if (haveCPExtra)
+    remainingHeaders += AH_CP_EXTRA_LEN;
+
+  ensure_input(remainingHeaders * B_MAX);
+  CHECK;
+  hdr.rp      = rp;
+  hdr.rplimit = rplimit;
+
+  if (haveFiles) {
+    archive_next_count = hdr.getInt();
+    CHECK_COUNT(archive_next_count);
+    archive_modtime = hdr.getInt();
+    file_count = hdr.getInt();
+    CHECK_COUNT(file_count);
+    hdrVals += 3;
+  } else {
+    hdrValsSkipped += 3;
+  }
+
+  if (haveSpecial) {
+    band_headers_size = hdr.getInt();
+    CHECK_COUNT(band_headers_size);
+    attr_definition_count = hdr.getInt();
+    CHECK_COUNT(attr_definition_count);
+    hdrVals += 2;
+  } else {
+    hdrValsSkipped += 2;
+  }
+
+  int cp_counts[N_TAGS_IN_ORDER];
+  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
+    if (!haveNumbers) {
+      switch (TAGS_IN_ORDER[k]) {
+      case CONSTANT_Integer:
+      case CONSTANT_Float:
+      case CONSTANT_Long:
+      case CONSTANT_Double:
+        cp_counts[k] = 0;
+        hdrValsSkipped += 1;
+        continue;
+      }
+    }
+    if (!haveCPExtra) {
+        switch(TAGS_IN_ORDER[k]) {
+        case CONSTANT_MethodHandle:
+        case CONSTANT_MethodType:
+        case CONSTANT_InvokeDynamic:
+        case CONSTANT_BootstrapMethod:
+          cp_counts[k] = 0;
+          hdrValsSkipped += 1;
+          continue;
+        }
+    }
+    cp_counts[k] = hdr.getInt();
+    CHECK_COUNT(cp_counts[k]);
+    hdrVals += 1;
+  }
+
+  ic_count = hdr.getInt();
+  CHECK_COUNT(ic_count);
+  default_class_minver = hdr.getInt();
+  default_class_majver = hdr.getInt();
+  class_count = hdr.getInt();
+  CHECK_COUNT(class_count);
+  hdrVals += 4;
+
+  // done with archive_header, time to reconcile to ensure
+  // we have read everything correctly
+  hdrVals += hdrValsSkipped;
+  assert(hdrVals == AH_LENGTH);
+  rp = hdr.rp;
+  if (rp > rplimit)
+    abort("EOF reading archive header");
+
+  // Now size the CP.
+#ifndef PRODUCT
+  // bool x = (N_TAGS_IN_ORDER == CONSTANT_Limit);
+  // assert(x);
+#endif //PRODUCT
+  cp.init(this, cp_counts);
+  CHECK;
+
+  default_file_modtime = archive_modtime;
+  if (default_file_modtime == 0 && haveModTime)
+    default_file_modtime = DEFAULT_ARCHIVE_MODTIME;  // taken from driver
+  if (testBit(archive_options, AO_DEFLATE_HINT))
+    default_file_options |= FO_DEFLATE_HINT;
+
+  // meta-bytes, if any, immediately follow archive header
+  //band_headers.readData(band_headers_size);
+  ensure_input(band_headers_size);
+  if (input_remaining() < (size_t)band_headers_size) {
+    abort("EOF reading band headers");
+    return;
+  }
+  bytes band_headers;
+  // The "1+" allows an initial byte to be pushed on the front.
+  band_headers.set(1+U_NEW(byte, 1+band_headers_size+C_SLOP),
+                   band_headers_size);
+  CHECK;
+  // Start scanning band headers here:
+  band_headers.copyFrom(rp, band_headers.len);
+  rp += band_headers.len;
+  assert(rp <= rplimit);
+  meta_rp = band_headers.ptr;
+  // Put evil meta-codes at the end of the band headers,
+  // so we are sure to throw an error if we run off the end.
+  bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
+}
+
+void unpacker::finish() {
+  if (verbose >= 1) {
+    fprintf(errstrm,
+            "A total of "
+            LONG_LONG_FORMAT " bytes were read in %d segment(s).\n",
+            (bytes_read_before_reset+bytes_read),
+            segments_read_before_reset+1);
+    fprintf(errstrm,
+            "A total of "
+            LONG_LONG_FORMAT " file content bytes were written.\n",
+            (bytes_written_before_reset+bytes_written));
+    fprintf(errstrm,
+            "A total of %d files (of which %d are classes) were written to output.\n",
+            files_written_before_reset+files_written,
+            classes_written_before_reset+classes_written);
+  }
+  if (jarout != null)
+    jarout->closeJarFile(true);
+  if (errstrm != null) {
+    if (errstrm == stdout || errstrm == stderr) {
+      fflush(errstrm);
+    } else {
+      fclose(errstrm);
+    }
+    errstrm = null;
+    errstrm_name = null;
+  }
+}
+
+
+// Cf. PackageReader.readConstantPoolCounts
+void cpool::init(unpacker* u_, int counts[CONSTANT_Limit]) {
+  this->u = u_;
+
+  // Fill-pointer for CP.
+  int next_entry = 0;
+
+  // Size the constant pool:
+  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
+    byte tag = TAGS_IN_ORDER[k];
+    int  len = counts[k];
+    tag_count[tag] = len;
+    tag_base[tag] = next_entry;
+    next_entry += len;
+    // Detect and defend against constant pool size overflow.
+    // (Pack200 forbids the sum of CP counts to exceed 2^29-1.)
+    enum {
+      CP_SIZE_LIMIT = (1<<29),
+      IMPLICIT_ENTRY_COUNT = 1  // empty Utf8 string
+    };
+    if (len >= (1<<29) || len < 0
+        || next_entry >= CP_SIZE_LIMIT+IMPLICIT_ENTRY_COUNT) {
+      abort("archive too large:  constant pool limit exceeded");
+      return;
+    }
+  }
+
+  // Close off the end of the CP:
+  nentries = next_entry;
+
+  // place a limit on future CP growth:
+  size_t generous = 0;
+  generous = add_size(generous, u->ic_count); // implicit name
+  generous = add_size(generous, u->ic_count); // outer
+  generous = add_size(generous, u->ic_count); // outer.utf8
+  generous = add_size(generous, 40); // WKUs, misc
+  generous = add_size(generous, u->class_count); // implicit SourceFile strings
+  maxentries = (uint)add_size(nentries, generous);
+
+  // Note that this CP does not include "empty" entries
+  // for longs and doubles.  Those are introduced when
+  // the entries are renumbered for classfile output.
+
+  entries = U_NEW(entry, maxentries);
+  CHECK;
+
+  first_extra_entry = &entries[nentries];
+
+  // Initialize the standard indexes.
+  for (int tag = 0; tag < CONSTANT_Limit; tag++) {
+    entry* cpMap = &entries[tag_base[tag]];
+    tag_index[tag].init(tag_count[tag], cpMap, tag);
+  }
+
+  // Initialize *all* our entries once
+  for (uint i = 0 ; i < maxentries ; i++) {
+    entries[i].outputIndex = REQUESTED_NONE;
+  }
+
+  initGroupIndexes();
+  // Initialize hashTab to a generous power-of-two size.
+  uint pow2 = 1;
+  uint target = maxentries + maxentries/2;  // 60% full
+  while (pow2 < target)  pow2 <<= 1;
+  hashTab = U_NEW(entry*, hashTabLength = pow2);
+}
+
+static byte* store_Utf8_char(byte* cp, unsigned short ch) {
+  if (ch >= 0x001 && ch <= 0x007F) {
+    *cp++ = (byte) ch;
+  } else if (ch <= 0x07FF) {
+    *cp++ = (byte) (0xC0 | ((ch >>  6) & 0x1F));
+    *cp++ = (byte) (0x80 | ((ch >>  0) & 0x3F));
+  } else {
+    *cp++ = (byte) (0xE0 | ((ch >> 12) & 0x0F));
+    *cp++ = (byte) (0x80 | ((ch >>  6) & 0x3F));
+    *cp++ = (byte) (0x80 | ((ch >>  0) & 0x3F));
+  }
+  return cp;
+}
+
+static byte* skip_Utf8_chars(byte* cp, int len) {
+  for (;; cp++) {
+    int ch = *cp & 0xFF;
+    if ((ch & 0xC0) != 0x80) {
+      if (len-- == 0)
+        return cp;
+      if (ch < 0x80 && len == 0)
+        return cp+1;
+    }
+  }
+}
+
+static int compare_Utf8_chars(bytes& b1, bytes& b2) {
+  int l1 = (int)b1.len;
+  int l2 = (int)b2.len;
+  int l0 = (l1 < l2) ? l1 : l2;
+  byte* p1 = b1.ptr;
+  byte* p2 = b2.ptr;
+  int c0 = 0;
+  for (int i = 0; i < l0; i++) {
+    int c1 = p1[i] & 0xFF;
+    int c2 = p2[i] & 0xFF;
+    if (c1 != c2) {
+      // Before returning the obvious answer,
+      // check to see if c1 or c2 is part of a 0x0000,
+      // which encodes as {0xC0,0x80}.  The 0x0000 is the
+      // lowest-sorting Java char value, and yet it encodes
+      // as if it were the first char after 0x7F, which causes
+      // strings containing nulls to sort too high.  All other
+      // comparisons are consistent between Utf8 and Java chars.
+      if (c1 == 0xC0 && (p1[i+1] & 0xFF) == 0x80)  c1 = 0;
+      if (c2 == 0xC0 && (p2[i+1] & 0xFF) == 0x80)  c2 = 0;
+      if (c0 == 0xC0) {
+        assert(((c1|c2) & 0xC0) == 0x80);  // c1 & c2 are extension chars
+        if (c1 == 0x80)  c1 = 0;  // will sort below c2
+        if (c2 == 0x80)  c2 = 0;  // will sort below c1
+      }
+      return c1 - c2;
+    }
+    c0 = c1;  // save away previous char
+  }
+  // common prefix is identical; return length difference if any
+  return l1 - l2;
+}
+
+// Cf. PackageReader.readUtf8Bands
+local_inline
+void unpacker::read_Utf8_values(entry* cpMap, int len) {
+  // Implicit first Utf8 string is the empty string.
+  enum {
+    // certain bands begin with implicit zeroes
+    PREFIX_SKIP_2 = 2,
+    SUFFIX_SKIP_1 = 1
+  };
+
+  int i;
+
+  // First band:  Read lengths of shared prefixes.
+  if (len > PREFIX_SKIP_2)
+    cp_Utf8_prefix.readData(len - PREFIX_SKIP_2);
+    NOT_PRODUCT(else cp_Utf8_prefix.readData(0));  // for asserts
+
+  // Second band:  Read lengths of unshared suffixes:
+  if (len > SUFFIX_SKIP_1)
+    cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1);
+    NOT_PRODUCT(else cp_Utf8_suffix.readData(0));  // for asserts
+
+  bytes* allsuffixes = T_NEW(bytes, len);
+  CHECK;
+
+  int nbigsuf = 0;
+  fillbytes charbuf;    // buffer to allocate small strings
+  charbuf.init();
+
+  // Third band:  Read the char values in the unshared suffixes:
+  cp_Utf8_chars.readData(cp_Utf8_suffix.getIntTotal());
+  for (i = 0; i < len; i++) {
+    int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();
+    if (suffix < 0) {
+      abort("bad utf8 suffix");
+      return;
+    }
+    if (suffix == 0 && i >= SUFFIX_SKIP_1) {
+      // chars are packed in cp_Utf8_big_chars
+      nbigsuf += 1;
+      continue;
+    }
+    bytes& chars  = allsuffixes[i];
+    uint size3    = suffix * 3;     // max Utf8 length
+    bool isMalloc = (suffix > SMALL);
+    if (isMalloc) {
+      chars.malloc(size3);
+    } else {
+      if (!charbuf.canAppend(size3+1)) {
+        assert(charbuf.allocated == 0 || tmallocs.contains(charbuf.base()));
+        charbuf.init(CHUNK);  // Reset to new buffer.
+        tmallocs.add(charbuf.base());
+      }
+      chars.set(charbuf.grow(size3+1), size3);
+    }
+    CHECK;
+    byte* chp = chars.ptr;
+    for (int j = 0; j < suffix; j++) {
+      unsigned short ch = cp_Utf8_chars.getInt();
+      chp = store_Utf8_char(chp, ch);
+    }
+    // shrink to fit:
+    if (isMalloc) {
+      chars.realloc(chp - chars.ptr);
+      CHECK;
+      tmallocs.add(chars.ptr); // free it later
+    } else {
+      int shrink = (int)(chars.limit() - chp);
+      chars.len -= shrink;
+      charbuf.b.len -= shrink;  // ungrow to reclaim buffer space
+      // Note that we did not reclaim the final '\0'.
+      assert(chars.limit() == charbuf.limit()-1);
+      assert(strlen((char*)chars.ptr) == chars.len);
+    }
+  }
+  //cp_Utf8_chars.done();
+#ifndef PRODUCT
+  charbuf.b.set(null, 0); // tidy
+#endif
+
+  // Fourth band:  Go back and size the specially packed strings.
+  int maxlen = 0;
+  cp_Utf8_big_suffix.readData(nbigsuf);
+  cp_Utf8_suffix.rewind();
+  for (i = 0; i < len; i++) {
+    int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();
+    int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();
+    if (prefix < 0 || prefix+suffix < 0) {
+       abort("bad utf8 prefix");
+       return;
+    }
+    bytes& chars = allsuffixes[i];
+    if (suffix == 0 && i >= SUFFIX_SKIP_1) {
+      suffix = cp_Utf8_big_suffix.getInt();
+      assert(chars.ptr == null);
+      chars.len = suffix;  // just a momentary hack
+    } else {
+      assert(chars.ptr != null);
+    }
+    if (maxlen < prefix + suffix) {
+      maxlen = prefix + suffix;
+    }
+  }
+  //cp_Utf8_suffix.done();      // will use allsuffixes[i].len (ptr!=null)
+  //cp_Utf8_big_suffix.done();  // will use allsuffixes[i].len
+
+  // Fifth band(s):  Get the specially packed characters.
+  cp_Utf8_big_suffix.rewind();
+  for (i = 0; i < len; i++) {
+    bytes& chars = allsuffixes[i];
+    if (chars.ptr != null)  continue;  // already input
+    int suffix = (int)chars.len;  // pick up the hack
+    uint size3 = suffix * 3;
+    if (suffix == 0)  continue;  // done with empty string
+    chars.malloc(size3);
+    CHECK;
+    byte* chp = chars.ptr;
+    band saved_band = cp_Utf8_big_chars;
+    cp_Utf8_big_chars.readData(suffix);
+    CHECK;
+    for (int j = 0; j < suffix; j++) {
+      unsigned short ch = cp_Utf8_big_chars.getInt();
+      CHECK;
+      chp = store_Utf8_char(chp, ch);
+    }
+    chars.realloc(chp - chars.ptr);
+    CHECK;
+    tmallocs.add(chars.ptr);  // free it later
+    //cp_Utf8_big_chars.done();
+    cp_Utf8_big_chars = saved_band;  // reset the band for the next string
+  }
+  cp_Utf8_big_chars.readData(0);  // zero chars
+  //cp_Utf8_big_chars.done();
+
+  // Finally, sew together all the prefixes and suffixes.
+  bytes bigbuf;
+  bigbuf.malloc(maxlen * 3 + 1);  // max Utf8 length, plus slop for null
+  CHECK;
+  int prevlen = 0;  // previous string length (in chars)
+  tmallocs.add(bigbuf.ptr);  // free after this block
+  CHECK;
+  cp_Utf8_prefix.rewind();
+  for (i = 0; i < len; i++) {
+    bytes& chars = allsuffixes[i];
+    int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();
+    CHECK;
+    int suffix = (int)chars.len;
+    byte* fillp;
+    // by induction, the buffer is already filled with the prefix
+    // make sure the prefix value is not corrupted, though:
+    if (prefix > prevlen) {
+       abort("utf8 prefix overflow");
+       return;
+    }
+    fillp = skip_Utf8_chars(bigbuf.ptr, prefix);
+    // copy the suffix into the same buffer:
+    fillp = chars.writeTo(fillp);
+    assert(bigbuf.inBounds(fillp));
+    *fillp = 0;  // bigbuf must contain a well-formed Utf8 string
+    int length = (int)(fillp - bigbuf.ptr);
+    bytes& value = cpMap[i].value.b;
+    value.set(U_NEW(byte, add_size(length,1)), length);
+    value.copyFrom(bigbuf.ptr, length);
+    CHECK;
+    // Index all Utf8 strings
+    entry* &htref = cp.hashTabRef(CONSTANT_Utf8, value);
+    if (htref == null) {
+      // Note that if two identical strings are transmitted,
+      // the first is taken to be the canonical one.
+      htref = &cpMap[i];
+    }
+    prevlen = prefix + suffix;
+  }
+  //cp_Utf8_prefix.done();
+
+  // Free intermediate buffers.
+  free_temps();
+}
+
+local_inline
+void unpacker::read_single_words(band& cp_band, entry* cpMap, int len) {
+  cp_band.readData(len);
+  for (int i = 0; i < len; i++) {
+    cpMap[i].value.i = cp_band.getInt();  // coding handles signs OK
+  }
+}
+
+maybe_inline
+void unpacker::read_double_words(band& cp_bands, entry* cpMap, int len) {
+  band& cp_band_hi = cp_bands;
+  band& cp_band_lo = cp_bands.nextBand();
+  cp_band_hi.readData(len);
+  cp_band_lo.readData(len);
+  for (int i = 0; i < len; i++) {
+    cpMap[i].value.l = cp_band_hi.getLong(cp_band_lo, true);
+  }
+  //cp_band_hi.done();
+  //cp_band_lo.done();
+}
+
+maybe_inline
+void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len) {
+  assert(refTag == CONSTANT_Utf8);
+  cp_band.setIndexByTag(refTag);
+  cp_band.readData(len);
+  CHECK;
+  int indexTag = (cp_band.bn == e_cp_Class) ? CONSTANT_Class : 0;
+  for (int i = 0; i < len; i++) {
+    entry& e = cpMap[i];
+    e.refs = U_NEW(entry*, e.nrefs = 1);
+    entry* utf = cp_band.getRef();
+    CHECK;
+    e.refs[0] = utf;
+    e.value.b = utf->value.b;  // copy value of Utf8 string to self
+    if (indexTag != 0) {
+      // Maintain cross-reference:
+      entry* &htref = cp.hashTabRef(indexTag, e.value.b);
+      if (htref == null) {
+        // Note that if two identical classes are transmitted,
+        // the first is taken to be the canonical one.
+        htref = &e;
+      }
+    }
+  }
+  //cp_band.done();
+}
+
+maybe_inline
+void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag,
+                                entry* cpMap, int len) {
+  band& cp_band1 = cp_band;
+  band& cp_band2 = cp_band.nextBand();
+  cp_band1.setIndexByTag(ref1Tag);
+  cp_band2.setIndexByTag(ref2Tag);
+  cp_band1.readData(len);
+  cp_band2.readData(len);
+  CHECK;
+  for (int i = 0; i < len; i++) {
+    entry& e = cpMap[i];
+    e.refs = U_NEW(entry*, e.nrefs = 2);
+    e.refs[0] = cp_band1.getRef();
+    CHECK;
+    e.refs[1] = cp_band2.getRef();
+    CHECK;
+  }
+  //cp_band1.done();
+  //cp_band2.done();
+}
+
+// Cf. PackageReader.readSignatureBands
+maybe_inline
+void unpacker::read_signature_values(entry* cpMap, int len) {
+  cp_Signature_form.setIndexByTag(CONSTANT_Utf8);
+  cp_Signature_form.readData(len);
+  CHECK;
+  int ncTotal = 0;
+  int i;
+  for (i = 0; i < len; i++) {
+    entry& e = cpMap[i];
+    entry& form = *cp_Signature_form.getRef();
+    CHECK;
+    int nc = 0;
+
+    for (int j = 0; j < (int)form.value.b.len; j++) {
+      int c = form.value.b.ptr[j];
+      if (c == 'L') nc++;
+    }
+    ncTotal += nc;
+    e.refs = U_NEW(entry*, cpMap[i].nrefs = 1 + nc);
+    CHECK;
+    e.refs[0] = &form;
+  }
+  //cp_Signature_form.done();
+  cp_Signature_classes.setIndexByTag(CONSTANT_Class);
+  cp_Signature_classes.readData(ncTotal);
+  for (i = 0; i < len; i++) {
+    entry& e = cpMap[i];
+    for (int j = 1; j < e.nrefs; j++) {
+      e.refs[j] = cp_Signature_classes.getRef();
+      CHECK;
+    }
+  }
+  //cp_Signature_classes.done();
+}
+
+maybe_inline
+void unpacker::checkLegacy(const char* name) {
+  if (u->majver < JAVA7_PACKAGE_MAJOR_VERSION) {
+      char message[100];
+      snprintf(message, 99, "unexpected band %s\n", name);
+      abort(message);
+  }
+}
+
+maybe_inline
+void unpacker::read_method_handle(entry* cpMap, int len) {
+  if (len > 0) {
+    checkLegacy(cp_MethodHandle_refkind.name);
+  }
+  cp_MethodHandle_refkind.readData(len);
+  cp_MethodHandle_member.setIndexByTag(CONSTANT_AnyMember);
+  cp_MethodHandle_member.readData(len);
+  for (int i = 0 ; i < len ; i++) {
+    entry& e = cpMap[i];
+    e.value.i = cp_MethodHandle_refkind.getInt();
+    e.refs = U_NEW(entry*, e.nrefs = 1);
+    e.refs[0] = cp_MethodHandle_member.getRef();
+    CHECK;
+  }
+}
+
+maybe_inline
+void unpacker::read_method_type(entry* cpMap, int len) {
+  if (len > 0) {
+    checkLegacy(cp_MethodType.name);
+  }
+  cp_MethodType.setIndexByTag(CONSTANT_Signature);
+  cp_MethodType.readData(len);
+  for (int i = 0 ; i < len ; i++) {
+      entry& e = cpMap[i];
+      e.refs = U_NEW(entry*, e.nrefs = 1);
+      e.refs[0] = cp_MethodType.getRef();
+      CHECK;
+  }
+}
+
+maybe_inline
+void unpacker::read_bootstrap_methods(entry* cpMap, int len) {
+  if (len > 0) {
+    checkLegacy(cp_BootstrapMethod_ref.name);
+  }
+  cp_BootstrapMethod_ref.setIndexByTag(CONSTANT_MethodHandle);
+  cp_BootstrapMethod_ref.readData(len);
+
+  cp_BootstrapMethod_arg_count.readData(len);
+  int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal();
+  cp_BootstrapMethod_arg.setIndexByTag(CONSTANT_LoadableValue);
+  cp_BootstrapMethod_arg.readData(totalArgCount);
+  for (int i = 0; i < len; i++) {
+    entry& e = cpMap[i];
+    int argc = cp_BootstrapMethod_arg_count.getInt();
+    e.value.i = argc;
+    e.refs = U_NEW(entry*, e.nrefs = argc + 1);
+    e.refs[0] = cp_BootstrapMethod_ref.getRef();
+    for (int j = 1 ; j < e.nrefs ; j++) {
+      e.refs[j] = cp_BootstrapMethod_arg.getRef();
+      CHECK;
+    }
+  }
+}
+// Cf. PackageReader.readConstantPool
+void unpacker::read_cp() {
+  byte* rp0 = rp;
+
+  int i;
+
+  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
+    byte tag = TAGS_IN_ORDER[k];
+    int  len = cp.tag_count[tag];
+    int base = cp.tag_base[tag];
+
+    PRINTCR((1,"Reading %d %s entries...", len, NOT_PRODUCT(TAG_NAME[tag])+0));
+    entry* cpMap = &cp.entries[base];
+    for (i = 0; i < len; i++) {
+      cpMap[i].tag = tag;
+      cpMap[i].inord = i;
+    }
+    // Initialize the tag's CP index right away, since it might be needed
+    // in the next pass to initialize the CP for another tag.
+#ifndef PRODUCT
+    cpindex* ix = &cp.tag_index[tag];
+    assert(ix->ixTag == tag);
+    assert((int)ix->len   == len);
+    assert(ix->base1 == cpMap);
+#endif
+
+    switch (tag) {
+    case CONSTANT_Utf8:
+      read_Utf8_values(cpMap, len);
+      break;
+    case CONSTANT_Integer:
+      read_single_words(cp_Int, cpMap, len);
+      break;
+    case CONSTANT_Float:
+      read_single_words(cp_Float, cpMap, len);
+      break;
+    case CONSTANT_Long:
+      read_double_words(cp_Long_hi /*& cp_Long_lo*/, cpMap, len);
+      break;
+    case CONSTANT_Double:
+      read_double_words(cp_Double_hi /*& cp_Double_lo*/, cpMap, len);
+      break;
+    case CONSTANT_String:
+      read_single_refs(cp_String, CONSTANT_Utf8, cpMap, len);
+      break;
+    case CONSTANT_Class:
+      read_single_refs(cp_Class, CONSTANT_Utf8, cpMap, len);
+      break;
+    case CONSTANT_Signature:
+      read_signature_values(cpMap, len);
+      break;
+    case CONSTANT_NameandType:
+      read_double_refs(cp_Descr_name /*& cp_Descr_type*/,
+                       CONSTANT_Utf8, CONSTANT_Signature,
+                       cpMap, len);
+      break;
+    case CONSTANT_Fieldref:
+      read_double_refs(cp_Field_class /*& cp_Field_desc*/,
+                       CONSTANT_Class, CONSTANT_NameandType,
+                       cpMap, len);
+      break;
+    case CONSTANT_Methodref:
+      read_double_refs(cp_Method_class /*& cp_Method_desc*/,
+                       CONSTANT_Class, CONSTANT_NameandType,
+                       cpMap, len);
+      break;
+    case CONSTANT_InterfaceMethodref:
+      read_double_refs(cp_Imethod_class /*& cp_Imethod_desc*/,
+                       CONSTANT_Class, CONSTANT_NameandType,
+                       cpMap, len);
+      break;
+    case CONSTANT_MethodHandle:
+      // consumes cp_MethodHandle_refkind and cp_MethodHandle_member
+      read_method_handle(cpMap, len);
+      break;
+    case CONSTANT_MethodType:
+      // consumes cp_MethodType
+      read_method_type(cpMap, len);
+      break;
+    case CONSTANT_InvokeDynamic:
+      read_double_refs(cp_InvokeDynamic_spec, CONSTANT_BootstrapMethod,
+                       CONSTANT_NameandType,
+                       cpMap, len);
+      break;
+    case CONSTANT_BootstrapMethod:
+      // consumes cp_BootstrapMethod_ref, cp_BootstrapMethod_arg_count and cp_BootstrapMethod_arg
+      read_bootstrap_methods(cpMap, len);
+      break;
+    default:
+      assert(false);
+      break;
+    }
+    CHECK;
+  }
+
+  cp.expandSignatures();
+  CHECK;
+  cp.initMemberIndexes();
+  CHECK;
+
+  PRINTCR((1,"parsed %d constant pool entries in %d bytes", cp.nentries, (rp - rp0)));
+
+  #define SNAME(n,s) #s "\0"
+  const char* symNames = (
+    ALL_ATTR_DO(SNAME)
+    "<init>"
+  );
+  #undef SNAME
+
+  for (int sn = 0; sn < cpool::s_LIMIT; sn++) {
+    assert(symNames[0] >= '0' && symNames[0] <= 'Z');  // sanity
+    bytes name; name.set(symNames);
+    if (name.len > 0 && name.ptr[0] != '0') {
+      cp.sym[sn] = cp.ensureUtf8(name);
+      PRINTCR((4, "well-known sym %d=%s", sn, cp.sym[sn]->string()));
+    }
+    symNames += name.len + 1;  // skip trailing null to next name
+  }
+
+  band::initIndexes(this);
+}
+
+static band* no_bands[] = { null };  // shared empty body
+
+inline
+band& unpacker::attr_definitions::fixed_band(int e_class_xxx) {
+  return u->all_bands[xxx_flags_hi_bn + (e_class_xxx-e_class_flags_hi)];
+}
+inline band& unpacker::attr_definitions::xxx_flags_hi()
+  { return fixed_band(e_class_flags_hi); }
+inline band& unpacker::attr_definitions::xxx_flags_lo()
+  { return fixed_band(e_class_flags_lo); }
+inline band& unpacker::attr_definitions::xxx_attr_count()
+  { return fixed_band(e_class_attr_count); }
+inline band& unpacker::attr_definitions::xxx_attr_indexes()
+  { return fixed_band(e_class_attr_indexes); }
+inline band& unpacker::attr_definitions::xxx_attr_calls()
+  { return fixed_band(e_class_attr_calls); }
+
+
+inline
+unpacker::layout_definition*
+unpacker::attr_definitions::defineLayout(int idx,
+                                         entry* nameEntry,
+                                         const char* layout) {
+  const char* name = nameEntry->value.b.strval();
+  layout_definition* lo = defineLayout(idx, name, layout);
+  CHECK_0;
+  lo->nameEntry = nameEntry;
+  return lo;
+}
+
+unpacker::layout_definition*
+unpacker::attr_definitions::defineLayout(int idx,
+                                         const char* name,
+                                         const char* layout) {
+  assert(flag_limit != 0);  // must be set up already
+  if (idx >= 0) {
+    // Fixed attr.
+    if (idx >= (int)flag_limit)
+      abort("attribute index too large");
+    if (isRedefined(idx))
+      abort("redefined attribute index");
+    redef |= ((julong)1<<idx);
+  } else {
+    idx = flag_limit + overflow_count.length();
+    overflow_count.add(0);  // make a new counter
+  }
+  layout_definition* lo = U_NEW(layout_definition, 1);
+  CHECK_0;
+  lo->idx = idx;
+  lo->name = name;
+  lo->layout = layout;
+  for (int adds = (idx+1) - layouts.length(); adds > 0; adds--) {
+    layouts.add(null);
+  }
+  CHECK_0;
+  layouts.get(idx) = lo;
+  return lo;
+}
+
+band**
+unpacker::attr_definitions::buildBands(unpacker::layout_definition* lo) {
+  int i;
+  if (lo->elems != null)
+    return lo->bands();
+  if (lo->layout[0] == '\0') {
+    lo->elems = no_bands;
+  } else {
+    // Create bands for this attribute by parsing the layout.
+    bool hasCallables = lo->hasCallables();
+    bands_made = 0x10000;  // base number for bands made
+    const char* lp = lo->layout;
+    lp = parseLayout(lp, lo->elems, -1);
+    CHECK_0;
+    if (lp[0] != '\0' || band_stack.length() > 0) {
+      abort("garbage at end of layout");
+    }
+    band_stack.popTo(0);
+    CHECK_0;
+
+    // Fix up callables to point at their callees.
+    band** bands = lo->elems;
+    assert(bands == lo->bands());
+    int num_callables = 0;
+    if (hasCallables) {
+      while (bands[num_callables] != null) {
+        if (bands[num_callables]->le_kind != EK_CBLE) {
+          abort("garbage mixed with callables");
+          break;
+        }
+        num_callables += 1;
+      }
+    }
+    for (i = 0; i < calls_to_link.length(); i++) {
+      band& call = *(band*) calls_to_link.get(i);
+      assert(call.le_kind == EK_CALL);
+      // Determine the callee.
+      int call_num = call.le_len;
+      if (call_num < 0 || call_num >= num_callables) {
+        abort("bad call in layout");
+        break;
+      }
+      band& cble = *bands[call_num];
+      // Link the call to it.
+      call.le_body[0] = &cble;
+      // Distinguish backward calls and callables:
+      assert(cble.le_kind == EK_CBLE);
+      assert(cble.le_len == call_num);
+      cble.le_back |= call.le_back;
+    }
+    calls_to_link.popTo(0);
+  }
+  return lo->elems;
+}
+
+/* attribute layout language parser
+
+  attribute_layout:
+        ( layout_element )* | ( callable )+
+  layout_element:
+        ( integral | replication | union | call | reference )
+
+  callable:
+        '[' body ']'
+  body:
+        ( layout_element )+
+
+  integral:
+        ( unsigned_int | signed_int | bc_index | bc_offset | flag )
+  unsigned_int:
+        uint_type
+  signed_int:
+        'S' uint_type
+  any_int:
+        ( unsigned_int | signed_int )
+  bc_index:
+        ( 'P' uint_type | 'PO' uint_type )
+  bc_offset:
+        'O' any_int
+  flag:
+        'F' uint_type
+  uint_type:
+        ( 'B' | 'H' | 'I' | 'V' )
+
+  replication:
+        'N' uint_type '[' body ']'
+
+  union:
+        'T' any_int (union_case)* '(' ')' '[' (body)? ']'
+  union_case:
+        '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']'
+  union_case_tag:
+        ( numeral | numeral '-' numeral )
+  call:
+        '(' numeral ')'
+
+  reference:
+        reference_type ( 'N' )? uint_type
+  reference_type:
+        ( constant_ref | schema_ref | utf8_ref | untyped_ref )
+  constant_ref:
+        ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' )
+  schema_ref:
+        ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' )
+  utf8_ref:
+        'RU'
+  untyped_ref:
+        'RQ'
+
+  numeral:
+        '(' ('-')? (digit)+ ')'
+  digit:
+        ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
+
+*/
+
+const char*
+unpacker::attr_definitions::parseIntLayout(const char* lp, band* &res,
+                                           byte le_kind, bool can_be_signed) {
+  const char* lp0 = lp;
+  band* b = U_NEW(band, 1);
+  CHECK_(lp);
+  char le = *lp++;
+  int spec = UNSIGNED5_spec;
+  if (le == 'S' && can_be_signed) {
+    // Note:  This is the last use of sign.  There is no 'EF_SIGN'.
+    spec = SIGNED5_spec;
+    le = *lp++;
+  } else if (le == 'B') {
+    spec = BYTE1_spec;  // unsigned byte
+  }
+  b->init(u, bands_made++, spec);
+  b->le_kind = le_kind;
+  int le_len = 0;
+  switch (le) {
+  case 'B': le_len = 1; break;
+  case 'H': le_len = 2; break;
+  case 'I': le_len = 4; break;
+  case 'V': le_len = 0; break;
+  default:  abort("bad layout element");
+  }
+  b->le_len = le_len;
+  band_stack.add(b);
+  res = b;
+  return lp;
+}
+
+const char*
+unpacker::attr_definitions::parseNumeral(const char* lp, int &res) {
+  const char* lp0 = lp;
+  bool sgn = false;
+  if (*lp == '0') { res = 0; return lp+1; }  // special case '0'
+  if (*lp == '-') { sgn = true; lp++; }
+  const char* dp = lp;
+  int con = 0;
+  while (*dp >= '0' && *dp <= '9') {
+    int con0 = con;
+    con *= 10;
+    con += (*dp++) - '0';
+    if (con <= con0) { con = -1; break; }  //  numeral overflow
+  }
+  if (lp == dp) {
+    abort("missing numeral in layout");
+    return "";
+  }
+  lp = dp;
+  if (con < 0 && !(sgn && con == -con)) {
+    // (Portability note:  Misses the error if int is not 32 bits.)
+    abort("numeral overflow");
+    return "" ;
+  }
+  if (sgn)  con = -con;
+  res = con;
+  return lp;
+}
+
+band**
+unpacker::attr_definitions::popBody(int bs_base) {
+  // Return everything that was pushed, as a null-terminated pointer array.
+  int bs_limit = band_stack.length();
+  if (bs_base == bs_limit) {
+    return no_bands;
+  } else {
+    int nb = bs_limit - bs_base;
+    band** res = U_NEW(band*, add_size(nb, 1));
+    CHECK_(no_bands);
+    for (int i = 0; i < nb; i++) {
+      band* b = (band*) band_stack.get(bs_base + i);
+      res[i] = b;
+    }
+    band_stack.popTo(bs_base);
+    return res;
+  }
+}
+
+const char*
+unpacker::attr_definitions::parseLayout(const char* lp, band** &res,
+                                        int curCble) {
+  const char* lp0 = lp;
+  int bs_base = band_stack.length();
+  bool top_level = (bs_base == 0);
+  band* b;
+  enum { can_be_signed = true };  // optional arg to parseIntLayout
+
+  for (bool done = false; !done; ) {
+    switch (*lp++) {
+    case 'B': case 'H': case 'I': case 'V': // unsigned_int
+    case 'S': // signed_int
+      --lp; // reparse
+    case 'F':
+      lp = parseIntLayout(lp, b, EK_INT);
+      break;
+    case 'P':
+      {
+        int le_bci = EK_BCI;
+        if (*lp == 'O') {
+          ++lp;
+          le_bci = EK_BCID;
+        }
+        assert(*lp != 'S');  // no PSH, etc.
+        lp = parseIntLayout(lp, b, EK_INT);
+        b->le_bci = le_bci;
+        if (le_bci == EK_BCI)
+          b->defc = coding::findBySpec(BCI5_spec);
+        else
+          b->defc = coding::findBySpec(BRANCH5_spec);
+      }
+      break;
+    case 'O':
+      lp = parseIntLayout(lp, b, EK_INT, can_be_signed);
+      b->le_bci = EK_BCO;
+      b->defc = coding::findBySpec(BRANCH5_spec);
+      break;
+    case 'N': // replication: 'N' uint '[' elem ... ']'
+      lp = parseIntLayout(lp, b, EK_REPL);
+      assert(*lp == '[');
+      ++lp;
+      lp = parseLayout(lp, b->le_body, curCble);
+      CHECK_(lp);
+      break;
+    case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']'
+      lp = parseIntLayout(lp, b, EK_UN, can_be_signed);
+      {
+        int union_base = band_stack.length();
+        for (;;) {   // for each case
+          band& k_case = *U_NEW(band, 1);
+          CHECK_(lp);
+          band_stack.add(&k_case);
+          k_case.le_kind = EK_CASE;
+          k_case.bn = bands_made++;
+          if (*lp++ != '(') {
+            abort("bad union case");
+            return "";
+          }
+          if (*lp++ != ')') {
+            --lp;  // reparse
+            // Read some case values.  (Use band_stack for temp. storage.)
+            int case_base = band_stack.length();
+            for (;;) {
+              int caseval = 0;
+              lp = parseNumeral(lp, caseval);
+              band_stack.add((void*)(size_t)caseval);
+              if (*lp == '-') {
+                // new in version 160, allow (1-5) for (1,2,3,4,5)
+                if (u->majver < JAVA6_PACKAGE_MAJOR_VERSION) {
+                  abort("bad range in union case label (old archive format)");
+                  return "";
+                }
+                int caselimit = caseval;
+                lp++;
+                lp = parseNumeral(lp, caselimit);
+                if (caseval >= caselimit
+                    || (uint)(caselimit - caseval) > 0x10000) {
+                  // Note:  0x10000 is arbitrary implementation restriction.
+                  // We can remove it later if it's important to.
+                  abort("bad range in union case label");
+                  return "";
+                }
+                for (;;) {
+                  ++caseval;
+                  band_stack.add((void*)(size_t)caseval);
+                  if (caseval == caselimit)  break;
+                }
+              }
+              if (*lp != ',')  break;
+              lp++;
+            }
+            if (*lp++ != ')') {
+              abort("bad case label");
+              return "";
+            }
+            // save away the case labels
+            int ntags = band_stack.length() - case_base;
+            int* tags = U_NEW(int, add_size(ntags, 1));
+            CHECK_(lp);
+            k_case.le_casetags = tags;
+            *tags++ = ntags;
+            for (int i = 0; i < ntags; i++) {
+              *tags++ = ptrlowbits(band_stack.get(case_base+i));
+            }
+            band_stack.popTo(case_base);
+            CHECK_(lp);
+          }
+          // Got le_casetags.  Now grab the body.
+          assert(*lp == '[');
+          ++lp;
+          lp = parseLayout(lp, k_case.le_body, curCble);
+          CHECK_(lp);
+          if (k_case.le_casetags == null)  break;  // done
+        }
+        b->le_body = popBody(union_base);
+      }
+      break;
+    case '(': // call: '(' -?NN* ')'
+      {
+        band& call = *U_NEW(band, 1);
+        CHECK_(lp);
+        band_stack.add(&call);
+        call.le_kind = EK_CALL;
+        call.bn = bands_made++;
+        call.le_body = U_NEW(band*, 2); // fill in later
+        int call_num = 0;
+        lp = parseNumeral(lp, call_num);
+        call.le_back = (call_num <= 0);
+        call_num += curCble;  // numeral is self-relative offset
+        call.le_len = call_num;  //use le_len as scratch
+        calls_to_link.add(&call);
+        CHECK_(lp);
+        if (*lp++ != ')') {
+          abort("bad call label");
+          return "";
+        }
+      }
+      break;
+    case 'K': // reference_type: constant_ref
+    case 'R': // reference_type: schema_ref
+      {
+        int ixTag = CONSTANT_None;
+        if (lp[-1] == 'K') {
+          switch (*lp++) {
+          case 'I': ixTag = CONSTANT_Integer; break;
+          case 'J': ixTag = CONSTANT_Long; break;
+          case 'F': ixTag = CONSTANT_Float; break;
+          case 'D': ixTag = CONSTANT_Double; break;
+          case 'S': ixTag = CONSTANT_String; break;
+          case 'Q': ixTag = CONSTANT_FieldSpecific; break;
+
+          // new in 1.7
+          case 'M': ixTag = CONSTANT_MethodHandle; break;
+          case 'T': ixTag = CONSTANT_MethodType; break;
+          case 'L': ixTag = CONSTANT_LoadableValue; break;
+          }
+        } else {
+          switch (*lp++) {
+          case 'C': ixTag = CONSTANT_Class; break;
+          case 'S': ixTag = CONSTANT_Signature; break;
+          case 'D': ixTag = CONSTANT_NameandType; break;
+          case 'F': ixTag = CONSTANT_Fieldref; break;
+          case 'M': ixTag = CONSTANT_Methodref; break;
+          case 'I': ixTag = CONSTANT_InterfaceMethodref; break;
+          case 'U': ixTag = CONSTANT_Utf8; break; //utf8_ref
+          case 'Q': ixTag = CONSTANT_All; break; //untyped_ref
+
+          // new in 1.7
+          case 'Y': ixTag = CONSTANT_InvokeDynamic; break;
+          case 'B': ixTag = CONSTANT_BootstrapMethod; break;
+          case 'N': ixTag = CONSTANT_AnyMember; break;
+          }
+        }
+        if (ixTag == CONSTANT_None) {
+          abort("bad reference layout");
+          break;
+        }
+        bool nullOK = false;
+        if (*lp == 'N') {
+          nullOK = true;
+          lp++;
+        }
+        lp = parseIntLayout(lp, b, EK_REF);
+        b->defc = coding::findBySpec(UNSIGNED5_spec);
+        b->initRef(ixTag, nullOK);
+      }
+      break;
+    case '[':
+      {
+        // [callable1][callable2]...
+        if (!top_level) {
+          abort("bad nested callable");
+          break;
+        }
+        curCble += 1;
+        NOT_PRODUCT(int call_num = band_stack.length() - bs_base);
+        band& cble = *U_NEW(band, 1);
+        CHECK_(lp);
+        band_stack.add(&cble);
+        cble.le_kind = EK_CBLE;
+        NOT_PRODUCT(cble.le_len = call_num);
+        cble.bn = bands_made++;
+        lp = parseLayout(lp, cble.le_body, curCble);
+      }
+      break;
+    case ']':
+      // Hit a closing brace.  This ends whatever body we were in.
+      done = true;
+      break;
+    case '\0':
+      // Hit a null.  Also ends the (top-level) body.
+      --lp;  // back up, so caller can see the null also
+      done = true;
+      break;
+    default:
+      abort("bad layout");
+      break;
+    }
+    CHECK_(lp);
+  }
+
+  // Return the accumulated bands:
+  res = popBody(bs_base);
+  return lp;
+}
+
+void unpacker::read_attr_defs() {
+  int i;
+
+  // Tell each AD which attrc it is and where its fixed flags are:
+  attr_defs[ATTR_CONTEXT_CLASS].attrc            = ATTR_CONTEXT_CLASS;
+  attr_defs[ATTR_CONTEXT_CLASS].xxx_flags_hi_bn  = e_class_flags_hi;
+  attr_defs[ATTR_CONTEXT_FIELD].attrc            = ATTR_CONTEXT_FIELD;
+  attr_defs[ATTR_CONTEXT_FIELD].xxx_flags_hi_bn  = e_field_flags_hi;
+  attr_defs[ATTR_CONTEXT_METHOD].attrc           = ATTR_CONTEXT_METHOD;
+  attr_defs[ATTR_CONTEXT_METHOD].xxx_flags_hi_bn = e_method_flags_hi;
+  attr_defs[ATTR_CONTEXT_CODE].attrc             = ATTR_CONTEXT_CODE;
+  attr_defs[ATTR_CONTEXT_CODE].xxx_flags_hi_bn   = e_code_flags_hi;
+
+  // Decide whether bands for the optional high flag words are present.
+  attr_defs[ATTR_CONTEXT_CLASS]
+    .setHaveLongFlags(testBit(archive_options, AO_HAVE_CLASS_FLAGS_HI));
+  attr_defs[ATTR_CONTEXT_FIELD]
+    .setHaveLongFlags(testBit(archive_options, AO_HAVE_FIELD_FLAGS_HI));
+  attr_defs[ATTR_CONTEXT_METHOD]
+    .setHaveLongFlags(testBit(archive_options, AO_HAVE_METHOD_FLAGS_HI));
+  attr_defs[ATTR_CONTEXT_CODE]
+    .setHaveLongFlags(testBit(archive_options, AO_HAVE_CODE_FLAGS_HI));
+
+  // Set up built-in attrs.
+  // (The simple ones are hard-coded.  The metadata layouts are not.)
+  const char* md_layout = (
+    // parameter annotations:
+#define MDL0 \
+    "[NB[(1)]]"
+    MDL0
+    // annotations:
+#define MDL1 \
+    "[NH[(1)]]"
+    MDL1
+#define MDL2 \
+    "[RSHNH[RUH(1)]]"
+    MDL2
+    // element_value:
+#define MDL3 \
+    "[TB"                        \
+      "(66,67,73,83,90)[KIH]"    \
+      "(68)[KDH]"                \
+      "(70)[KFH]"                \
+      "(74)[KJH]"                \
+      "(99)[RSH]"                \
+      "(101)[RSHRUH]"            \
+      "(115)[RUH]"               \
+      "(91)[NH[(0)]]"            \
+      "(64)["                    \
+        /* nested annotation: */ \
+        "RSH"                    \
+        "NH[RUH(0)]"             \
+        "]"                      \
+      "()[]"                     \
+    "]"
+    MDL3
+    );
+
+  const char* md_layout_P = md_layout;
+  const char* md_layout_A = md_layout+strlen(MDL0);
+  const char* md_layout_V = md_layout+strlen(MDL0 MDL1 MDL2);
+  assert(0 == strncmp(&md_layout_A[-3], ")]][", 4));
+  assert(0 == strncmp(&md_layout_V[-3], ")]][", 4));
+
+const char* type_md_layout(
+    "[NH[(1)(2)(3)]]"
+    // target-type + target_info
+    "[TB"
+       "(0,1)[B]"
+       "(16)[FH]"
+       "(17,18)[BB]"
+       "(19,20,21)[]"
+       "(22)[B]"
+       "(23)[H]"
+       "(64,65)[NH[PHOHH]]"
+       "(66)[H]"
+       "(67,68,69,70)[PH]"
+       "(71,72,73,74,75)[PHB]"
+       "()[]]"
+    // target-path
+    "[NB[BB]]"
+    // annotation + element_value
+    MDL2
+    MDL3
+);
+
+  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
+    attr_definitions& ad = attr_defs[i];
+    if (i != ATTR_CONTEXT_CODE) {
+      ad.defineLayout(X_ATTR_RuntimeVisibleAnnotations,
+                      "RuntimeVisibleAnnotations", md_layout_A);
+      ad.defineLayout(X_ATTR_RuntimeInvisibleAnnotations,
+                      "RuntimeInvisibleAnnotations", md_layout_A);
+      if (i == ATTR_CONTEXT_METHOD) {
+        ad.defineLayout(METHOD_ATTR_RuntimeVisibleParameterAnnotations,
+                        "RuntimeVisibleParameterAnnotations", md_layout_P);
+        ad.defineLayout(METHOD_ATTR_RuntimeInvisibleParameterAnnotations,
+                        "RuntimeInvisibleParameterAnnotations", md_layout_P);
+        ad.defineLayout(METHOD_ATTR_AnnotationDefault,
+                        "AnnotationDefault", md_layout_V);
+      }
+    }
+    ad.defineLayout(X_ATTR_RuntimeVisibleTypeAnnotations,
+                    "RuntimeVisibleTypeAnnotations", type_md_layout);
+    ad.defineLayout(X_ATTR_RuntimeInvisibleTypeAnnotations,
+                    "RuntimeInvisibleTypeAnnotations", type_md_layout);
+  }
+
+  attr_definition_headers.readData(attr_definition_count);
+  attr_definition_name.readData(attr_definition_count);
+  attr_definition_layout.readData(attr_definition_count);
+
+  CHECK;
+
+  // Initialize correct predef bits, to distinguish predefs from new defs.
+#define ORBIT(n,s) |((julong)1<<n)
+  attr_defs[ATTR_CONTEXT_CLASS].predef
+    = (0 X_ATTR_DO(ORBIT) CLASS_ATTR_DO(ORBIT));
+  attr_defs[ATTR_CONTEXT_FIELD].predef
+    = (0 X_ATTR_DO(ORBIT) FIELD_ATTR_DO(ORBIT));
+  attr_defs[ATTR_CONTEXT_METHOD].predef
+    = (0 X_ATTR_DO(ORBIT) METHOD_ATTR_DO(ORBIT));
+  attr_defs[ATTR_CONTEXT_CODE].predef
+    = (0 O_ATTR_DO(ORBIT) CODE_ATTR_DO(ORBIT));
+#undef ORBIT
+  // Clear out the redef bits, folding them back into predef.
+  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
+    attr_defs[i].predef |= attr_defs[i].redef;
+    attr_defs[i].redef = 0;
+  }
+
+  // Now read the transmitted locally defined attrs.
+  // This will set redef bits again.
+  for (i = 0; i < attr_definition_count; i++) {
+    int    header  = attr_definition_headers.getByte();
+    int    attrc   = ADH_BYTE_CONTEXT(header);
+    int    idx     = ADH_BYTE_INDEX(header);
+    entry* name    = attr_definition_name.getRef();
+    CHECK;
+    entry* layout  = attr_definition_layout.getRef();
+    CHECK;
+    attr_defs[attrc].defineLayout(idx, name, layout->value.b.strval());
+  }
+}
+
+#define NO_ENTRY_YET ((entry*)-1)
+
+static bool isDigitString(bytes& x, int beg, int end) {
+  if (beg == end)  return false;  // null string
+  byte* xptr = x.ptr;
+  for (int i = beg; i < end; i++) {
+    char ch = xptr[i];
+    if (!(ch >= '0' && ch <= '9'))  return false;
+  }
+  return true;
+}
+
+enum {  // constants for parsing class names
+  SLASH_MIN = '.',
+  SLASH_MAX = '/',
+  DOLLAR_MIN = 0,
+  DOLLAR_MAX = '-'
+};
+
+static int lastIndexOf(int chmin, int chmax, bytes& x, int pos) {
+  byte* ptr = x.ptr;
+  for (byte* cp = ptr + pos; --cp >= ptr; ) {
+    assert(x.inBounds(cp));
+    if (*cp >= chmin && *cp <= chmax)
+      return (int)(cp - ptr);
+  }
+  return -1;
+}
+
+maybe_inline
+inner_class* cpool::getIC(entry* inner) {
+  if (inner == null)  return null;
+  assert(inner->tag == CONSTANT_Class);
+  if (inner->inord == NO_INORD)  return null;
+  inner_class* ic = ic_index[inner->inord];
+  assert(ic == null || ic->inner == inner);
+  return ic;
+}
+
+maybe_inline
+inner_class* cpool::getFirstChildIC(entry* outer) {
+  if (outer == null)  return null;
+  assert(outer->tag == CONSTANT_Class);
+  if (outer->inord == NO_INORD)  return null;
+  inner_class* ic = ic_child_index[outer->inord];
+  assert(ic == null || ic->outer == outer);
+  return ic;
+}
+
+maybe_inline
+inner_class* cpool::getNextChildIC(inner_class* child) {
+  inner_class* ic = child->next_sibling;
+  assert(ic == null || ic->outer == child->outer);
+  return ic;
+}
+
+void unpacker::read_ics() {
+  int i;
+  int index_size = cp.tag_count[CONSTANT_Class];
+  inner_class** ic_index       = U_NEW(inner_class*, index_size);
+  inner_class** ic_child_index = U_NEW(inner_class*, index_size);
+  cp.ic_index = ic_index;
+  cp.ic_child_index = ic_child_index;
+  ics = U_NEW(inner_class, ic_count);
+  ic_this_class.readData(ic_count);
+  ic_flags.readData(ic_count);
+  CHECK;
+  // Scan flags to get count of long-form bands.
+  int long_forms = 0;
+  for (i = 0; i < ic_count; i++) {
+    int flags = ic_flags.getInt();  // may be long form!
+    if ((flags & ACC_IC_LONG_FORM) != 0) {
+      long_forms += 1;
+      ics[i].name = NO_ENTRY_YET;
+    }
+    flags &= ~ACC_IC_LONG_FORM;
+    entry* inner = ic_this_class.getRef();
+    CHECK;
+    uint inord = inner->inord;
+    assert(inord < (uint)cp.tag_count[CONSTANT_Class]);
+    if (ic_index[inord] != null) {
+      abort("identical inner class");
+      break;
+    }
+    ic_index[inord] = &ics[i];
+    ics[i].inner = inner;
+    ics[i].flags = flags;
+    assert(cp.getIC(inner) == &ics[i]);
+  }
+  CHECK;
+  //ic_this_class.done();
+  //ic_flags.done();
+  ic_outer_class.readData(long_forms);
+  ic_name.readData(long_forms);
+  for (i = 0; i < ic_count; i++) {
+    if (ics[i].name == NO_ENTRY_YET) {
+      // Long form.
+      ics[i].outer = ic_outer_class.getRefN();
+      CHECK;
+      ics[i].name  = ic_name.getRefN();
+      CHECK;
+    } else {
+      // Fill in outer and name based on inner.
+      bytes& n = ics[i].inner->value.b;
+      bytes pkgOuter;
+      bytes number;
+      bytes name;
+      // Parse n into pkgOuter and name (and number).
+      PRINTCR((5, "parse short IC name %s", n.ptr));
+      int dollar1, dollar2;  // pointers to $ in the pattern
+      // parse n = (<pkg>/)*<outer>($<number>)?($<name>)?
+      int nlen = (int)n.len;
+      int pkglen = lastIndexOf(SLASH_MIN,  SLASH_MAX,  n, nlen) + 1;
+      dollar2    = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, nlen);
+      if (dollar2 < 0) {
+         abort();
+         return;
+      }
+      assert(dollar2 >= pkglen);
+      if (isDigitString(n, dollar2+1, nlen)) {
+        // n = (<pkg>/)*<outer>$<number>
+        number = n.slice(dollar2+1, nlen);
+        name.set(null,0);
+        dollar1 = dollar2;
+      } else if (pkglen < (dollar1
+                           = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, dollar2-1))
+                 && isDigitString(n, dollar1+1, dollar2)) {
+        // n = (<pkg>/)*<outer>$<number>$<name>
+        number = n.slice(dollar1+1, dollar2);
+        name = n.slice(dollar2+1, nlen);
+      } else {
+        // n = (<pkg>/)*<outer>$<name>
+        dollar1 = dollar2;
+        number.set(null,0);
+        name = n.slice(dollar2+1, nlen);
+      }
+      if (number.ptr == null) {
+        if (dollar1 < 0) {
+          abort();
+          return;
+        }
+        pkgOuter = n.slice(0, dollar1);
+      } else {
+        pkgOuter.set(null,0);
+      }
+      PRINTCR((5,"=> %s$ 0%s $%s",
+              pkgOuter.string(), number.string(), name.string()));
+
+      if (pkgOuter.ptr != null)
+        ics[i].outer = cp.ensureClass(pkgOuter);
+
+      if (name.ptr != null)
+        ics[i].name = cp.ensureUtf8(name);
+    }
+
+    // update child/sibling list
+    if (ics[i].outer != null) {
+      uint outord = ics[i].outer->inord;
+      if (outord != NO_INORD) {
+        assert(outord < (uint)cp.tag_count[CONSTANT_Class]);
+        ics[i].next_sibling = ic_child_index[outord];
+        ic_child_index[outord] = &ics[i];
+      }
+    }
+  }
+  //ic_outer_class.done();
+  //ic_name.done();
+}
+
+void unpacker::read_classes() {
+  PRINTCR((1,"  ...scanning %d classes...", class_count));
+  class_this.readData(class_count);
+  class_super.readData(class_count);
+  class_interface_count.readData(class_count);
+  class_interface.readData(class_interface_count.getIntTotal());
+
+  CHECK;
+
+  #if 0
+  int i;
+  // Make a little mark on super-classes.
+  for (i = 0; i < class_count; i++) {
+    entry* e = class_super.getRefN();
+    if (e != null)  e->bits |= entry::EB_SUPER;
+  }
+  class_super.rewind();
+  #endif
+
+  // Members.
+  class_field_count.readData(class_count);
+  class_method_count.readData(class_count);
+
+  CHECK;
+
+  int field_count = class_field_count.getIntTotal();
+  int method_count = class_method_count.getIntTotal();
+
+  field_descr.readData(field_count);
+  read_attrs(ATTR_CONTEXT_FIELD, field_count);
+  CHECK;
+
+  method_descr.readData(method_count);
+  read_attrs(ATTR_CONTEXT_METHOD, method_count);
+
+  CHECK;
+
+  read_attrs(ATTR_CONTEXT_CLASS, class_count);
+  CHECK;
+
+  read_code_headers();
+
+  PRINTCR((1,"scanned %d classes, %d fields, %d methods, %d code headers",
+          class_count, field_count, method_count, code_count));
+}
+
+maybe_inline
+int unpacker::attr_definitions::predefCount(uint idx) {
+  return isPredefined(idx) ? flag_count[idx] : 0;
+}
+
+void unpacker::read_attrs(int attrc, int obj_count) {
+  attr_definitions& ad = attr_defs[attrc];
+  assert(ad.attrc == attrc);
+
+  int i, idx, count;
+
+  CHECK;
+
+  bool haveLongFlags = ad.haveLongFlags();
+
+  band& xxx_flags_hi = ad.xxx_flags_hi();
+  assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
+  if (haveLongFlags)
+    xxx_flags_hi.readData(obj_count);
+  CHECK;
+
+  band& xxx_flags_lo = ad.xxx_flags_lo();
+  assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
+  xxx_flags_lo.readData(obj_count);
+  CHECK;
+
+  // pre-scan flags, counting occurrences of each index bit
+  julong indexMask = ad.flagIndexMask();  // which flag bits are index bits?
+  for (i = 0; i < obj_count; i++) {
+    julong indexBits = xxx_flags_hi.getLong(xxx_flags_lo, haveLongFlags);
+    if ((indexBits & ~indexMask) > (ushort)-1) {
+      abort("undefined attribute flag bit");
+      return;
+    }
+    indexBits &= indexMask;  // ignore classfile flag bits
+    for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) {
+      ad.flag_count[idx] += (int)(indexBits & 1);
+    }
+  }
+  // we'll scan these again later for output:
+  xxx_flags_lo.rewind();
+  xxx_flags_hi.rewind();
+
+  band& xxx_attr_count = ad.xxx_attr_count();
+  assert(endsWith(xxx_attr_count.name, "_attr_count"));
+  // There is one count element for each 1<<16 bit set in flags:
+  xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
+  CHECK;
+
+  band& xxx_attr_indexes = ad.xxx_attr_indexes();
+  assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
+  int overflowIndexCount = xxx_attr_count.getIntTotal();
+  xxx_attr_indexes.readData(overflowIndexCount);
+  CHECK;
+  // pre-scan attr indexes, counting occurrences of each value
+  for (i = 0; i < overflowIndexCount; i++) {
+    idx = xxx_attr_indexes.getInt();
+    if (!ad.isIndex(idx)) {
+      abort("attribute index out of bounds");
+      return;
+    }
+    ad.getCount(idx) += 1;
+  }
+  xxx_attr_indexes.rewind();  // we'll scan it again later for output
+
+  // We will need a backward call count for each used backward callable.
+  int backwardCounts = 0;
+  for (idx = 0; idx < ad.layouts.length(); idx++) {
+    layout_definition* lo = ad.getLayout(idx);
+    if (lo != null && ad.getCount(idx) != 0) {
+      // Build the bands lazily, only when they are used.
+      band** bands = ad.buildBands(lo);
+      CHECK;
+      if (lo->hasCallables()) {
+        for (i = 0; bands[i] != null; i++) {
+          if (bands[i]->le_back) {
+            assert(bands[i]->le_kind == EK_CBLE);
+            backwardCounts += 1;
+          }
+        }
+      }
+    }
+  }
+  ad.xxx_attr_calls().readData(backwardCounts);
+  CHECK;
+
+  // Read built-in bands.
+  // Mostly, these are hand-coded equivalents to readBandData().
+  switch (attrc) {
+  case ATTR_CONTEXT_CLASS:
+
+    count = ad.predefCount(CLASS_ATTR_SourceFile);
+    class_SourceFile_RUN.readData(count);
+    CHECK;
+
+    count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
+    class_EnclosingMethod_RC.readData(count);
+    class_EnclosingMethod_RDN.readData(count);
+    CHECK;
+
+    count = ad.predefCount(X_ATTR_Signature);
+    class_Signature_RS.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
+    CHECK;
+
+    count = ad.predefCount(CLASS_ATTR_InnerClasses);
+    class_InnerClasses_N.readData(count);
+    CHECK;
+
+    count = class_InnerClasses_N.getIntTotal();
+    class_InnerClasses_RC.readData(count);
+    class_InnerClasses_F.readData(count);
+    CHECK;
+    // Drop remaining columns wherever flags are zero:
+    count -= class_InnerClasses_F.getIntCount(0);
+    class_InnerClasses_outer_RCN.readData(count);
+    class_InnerClasses_name_RUN.readData(count);
+    CHECK;
+
+    count = ad.predefCount(CLASS_ATTR_ClassFile_version);
+    class_ClassFile_version_minor_H.readData(count);
+    class_ClassFile_version_major_H.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
+    CHECK;
+    break;
+
+  case ATTR_CONTEXT_FIELD:
+
+    count = ad.predefCount(FIELD_ATTR_ConstantValue);
+    field_ConstantValue_KQ.readData(count);
+    CHECK;
+
+    count = ad.predefCount(X_ATTR_Signature);
+    field_Signature_RS.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
+    CHECK;
+    break;
+
+  case ATTR_CONTEXT_METHOD:
+
+    code_count = ad.predefCount(METHOD_ATTR_Code);
+    // Code attrs are handled very specially below...
+
+    count = ad.predefCount(METHOD_ATTR_Exceptions);
+    method_Exceptions_N.readData(count);
+    count = method_Exceptions_N.getIntTotal();
+    method_Exceptions_RC.readData(count);
+    CHECK;
+
+    count = ad.predefCount(X_ATTR_Signature);
+    method_Signature_RS.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
+    ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
+    ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
+    ad.readBandData(METHOD_ATTR_AnnotationDefault);
+    CHECK;
+
+    count = ad.predefCount(METHOD_ATTR_MethodParameters);
+    method_MethodParameters_NB.readData(count);
+    count = method_MethodParameters_NB.getIntTotal();
+    method_MethodParameters_name_RUN.readData(count);
+    method_MethodParameters_flag_FH.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
+    CHECK;
+
+    break;
+
+  case ATTR_CONTEXT_CODE:
+    // (keep this code aligned with its brother in unpacker::write_attrs)
+    count = ad.predefCount(CODE_ATTR_StackMapTable);
+    // disable this feature in old archives!
+    if (count != 0 && majver < JAVA6_PACKAGE_MAJOR_VERSION) {
+      abort("undefined StackMapTable attribute (old archive format)");
+      return;
+    }
+    code_StackMapTable_N.readData(count);
+    CHECK;
+    count = code_StackMapTable_N.getIntTotal();
+    code_StackMapTable_frame_T.readData(count);
+    CHECK;
+    // the rest of it depends in a complicated way on frame tags
+    {
+      int fat_frame_count = 0;
+      int offset_count = 0;
+      int type_count = 0;
+      for (int k = 0; k < count; k++) {
+        int tag = code_StackMapTable_frame_T.getByte();
+        if (tag <= 127) {
+          // (64-127)  [(2)]
+          if (tag >= 64)  type_count++;
+        } else if (tag <= 251) {
+          // (247)     [(1)(2)]
+          // (248-251) [(1)]
+          if (tag >= 247)  offset_count++;
+          if (tag == 247)  type_count++;
+        } else if (tag <= 254) {
+          // (252)     [(1)(2)]
+          // (253)     [(1)(2)(2)]
+          // (254)     [(1)(2)(2)(2)]
+          offset_count++;
+          type_count += (tag - 251);
+        } else {
+          // (255)     [(1)NH[(2)]NH[(2)]]
+          fat_frame_count++;
+        }
+      }
+
+      // done pre-scanning frame tags:
+      code_StackMapTable_frame_T.rewind();
+
+      // deal completely with fat frames:
+      offset_count += fat_frame_count;
+      code_StackMapTable_local_N.readData(fat_frame_count);
+      CHECK;
+      type_count += code_StackMapTable_local_N.getIntTotal();
+      code_StackMapTable_stack_N.readData(fat_frame_count);
+      type_count += code_StackMapTable_stack_N.getIntTotal();
+      CHECK;
+      // read the rest:
+      code_StackMapTable_offset.readData(offset_count);
+      code_StackMapTable_T.readData(type_count);
+      CHECK;
+      // (7) [RCH]
+      count = code_StackMapTable_T.getIntCount(7);
+      code_StackMapTable_RC.readData(count);
+      CHECK;
+      // (8) [PH]
+      count = code_StackMapTable_T.getIntCount(8);
+      code_StackMapTable_P.readData(count);
+      CHECK;
+    }
+
+    count = ad.predefCount(CODE_ATTR_LineNumberTable);
+    code_LineNumberTable_N.readData(count);
+    CHECK;
+    count = code_LineNumberTable_N.getIntTotal();
+    code_LineNumberTable_bci_P.readData(count);
+    code_LineNumberTable_line.readData(count);
+    CHECK;
+
+    count = ad.predefCount(CODE_ATTR_LocalVariableTable);
+    code_LocalVariableTable_N.readData(count);
+    CHECK;
+    count = code_LocalVariableTable_N.getIntTotal();
+    code_LocalVariableTable_bci_P.readData(count);
+    code_LocalVariableTable_span_O.readData(count);
+    code_LocalVariableTable_name_RU.readData(count);
+    code_LocalVariableTable_type_RS.readData(count);
+    code_LocalVariableTable_slot.readData(count);
+    CHECK;
+
+    count = ad.predefCount(CODE_ATTR_LocalVariableTypeTable);
+    code_LocalVariableTypeTable_N.readData(count);
+    count = code_LocalVariableTypeTable_N.getIntTotal();
+    code_LocalVariableTypeTable_bci_P.readData(count);
+    code_LocalVariableTypeTable_span_O.readData(count);
+    code_LocalVariableTypeTable_name_RU.readData(count);
+    code_LocalVariableTypeTable_type_RS.readData(count);
+    code_LocalVariableTypeTable_slot.readData(count);
+    CHECK;
+
+    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
+    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
+    CHECK;
+
+    break;
+  }
+
+  // Read compressor-defined bands.
+  for (idx = 0; idx < ad.layouts.length(); idx++) {
+    if (ad.getLayout(idx) == null)
+      continue;  // none at this fixed index <32
+    if (idx < (int)ad.flag_limit && ad.isPredefined(idx))
+      continue;  // already handled
+    if (ad.getCount(idx) == 0)
+      continue;  // no attributes of this type (then why transmit layouts?)
+    ad.readBandData(idx);
+  }
+}
+
+void unpacker::attr_definitions::readBandData(int idx) {
+  int j;
+  uint count = getCount(idx);
+  if (count == 0)  return;
+  layout_definition* lo = getLayout(idx);
+  if (lo != null) {
+    PRINTCR((1, "counted %d [redefined = %d predefined = %d] attributes of type %s.%s",
+            count, isRedefined(idx), isPredefined(idx),
+            ATTR_CONTEXT_NAME[attrc], lo->name));
+  }
+  bool hasCallables = lo->hasCallables();
+  band** bands = lo->bands();
+  if (!hasCallables) {
+    // Read through the rest of the bands in a regular way.
+    readBandData(bands, count);
+  } else {
+    // Deal with the callables.
+    // First set up the forward entry count for each callable.
+    // This is stored on band::length of the callable.
+    bands[0]->expectMoreLength(count);
+    for (j = 0; bands[j] != null; j++) {
+      band& j_cble = *bands[j];
+      assert(j_cble.le_kind == EK_CBLE);
+      if (j_cble.le_back) {
+        // Add in the predicted effects of backward calls, too.
+        int back_calls = xxx_attr_calls().getInt();
+        j_cble.expectMoreLength(back_calls);
+        // In a moment, more forward calls may increment j_cble.length.
+      }
+    }
+    // Now consult whichever callables have non-zero entry counts.
+    readBandData(bands, (uint)-1);
+  }
+}
+
+// Recursive helper to the previous function:
+void unpacker::attr_definitions::readBandData(band** body, uint count) {
+  int j, k;
+  for (j = 0; body[j] != null; j++) {
+    band& b = *body[j];
+    if (b.defc != null) {
+      // It has data, so read it.
+      b.readData(count);
+    }
+    switch (b.le_kind) {
+    case EK_REPL:
+      {
+        int reps = b.getIntTotal();
+        readBandData(b.le_body, reps);
+      }
+      break;
+    case EK_UN:
+      {
+        int remaining = count;
+        for (k = 0; b.le_body[k] != null; k++) {
+          band& k_case = *b.le_body[k];
+          int   k_count = 0;
+          if (k_case.le_casetags == null) {
+            k_count = remaining;  // last (empty) case
+          } else {
+            int* tags = k_case.le_casetags;
+            int ntags = *tags++;  // 1st element is length (why not?)
+            while (ntags-- > 0) {
+              int tag = *tags++;
+              k_count += b.getIntCount(tag);
+            }
+          }
+          readBandData(k_case.le_body, k_count);
+          remaining -= k_count;
+        }
+        assert(remaining == 0);
+      }
+      break;
+    case EK_CALL:
+      // Push the count forward, if it is not a backward call.
+      if (!b.le_back) {
+        band& cble = *b.le_body[0];
+        assert(cble.le_kind == EK_CBLE);
+        cble.expectMoreLength(count);
+      }
+      break;
+    case EK_CBLE:
+      assert((int)count == -1);  // incoming count is meaningless
+      k = b.length;
+      assert(k >= 0);
+      // This is intended and required for non production mode.
+      assert((b.length = -1)); // make it unable to accept more calls now.
+      readBandData(b.le_body, k);
+      break;
+    }
+  }
+}
+
+static inline
+band** findMatchingCase(int matchTag, band** cases) {
+  for (int k = 0; cases[k] != null; k++) {
+    band& k_case = *cases[k];
+    if (k_case.le_casetags != null) {
+      // If it has tags, it must match a tag.
+      int* tags = k_case.le_casetags;
+      int ntags = *tags++;  // 1st element is length
+      for (; ntags > 0; ntags--) {
+        int tag = *tags++;
+        if (tag == matchTag)
+          break;
+      }
+      if (ntags == 0)
+        continue;   // does not match
+    }
+    return k_case.le_body;
+  }
+  return null;
+}
+
+// write attribute band data:
+void unpacker::putlayout(band** body) {
+  int i;
+  int prevBII = -1;
+  int prevBCI = -1;
+  if (body == NULL) {
+    abort("putlayout: unexpected NULL for body");
+    return;
+  }
+  for (i = 0; body[i] != null; i++) {
+    band& b = *body[i];
+    byte le_kind = b.le_kind;
+
+    // Handle scalar part, if any.
+    int    x = 0;
+    entry* e = null;
+    if (b.defc != null) {
+      // It has data, so unparse an element.
+      if (b.ixTag != CONSTANT_None) {
+        assert(le_kind == EK_REF);
+        if (b.ixTag == CONSTANT_FieldSpecific)
+          e = b.getRefUsing(cp.getKQIndex());
+        else
+          e = b.getRefN();
+        CHECK;
+        switch (b.le_len) {
+        case 0: break;
+        case 1: putu1ref(e); break;
+        case 2: putref(e); break;
+        case 4: putu2(0); putref(e); break;
+        default: assert(false);
+        }
+      } else {
+        assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN);
+        x = b.getInt();
+
+        assert(!b.le_bci || prevBCI == (int)to_bci(prevBII));
+        switch (b.le_bci) {
+        case EK_BCI:   // PH:  transmit R(bci), store bci
+          x = to_bci(prevBII = x);
+          prevBCI = x;
+          break;
+        case EK_BCID:  // POH: transmit D(R(bci)), store bci
+          x = to_bci(prevBII += x);
+          prevBCI = x;
+          break;
+        case EK_BCO:   // OH:  transmit D(R(bci)), store D(bci)
+          x = to_bci(prevBII += x) - prevBCI;
+          prevBCI += x;
+          break;
+        }
+        assert(!b.le_bci || prevBCI == (int)to_bci(prevBII));
+
+        CHECK;
+        switch (b.le_len) {
+        case 0: break;
+        case 1: putu1(x); break;
+        case 2: putu2(x); break;
+        case 4: putu4(x); break;
+        default: assert(false);
+        }
+      }
+    }
+
+    // Handle subparts, if any.
+    switch (le_kind) {
+    case EK_REPL:
+      // x is the repeat count
+      while (x-- > 0) {
+        putlayout(b.le_body);
+      }
+      break;
+    case EK_UN:
+      // x is the tag
+      putlayout(findMatchingCase(x, b.le_body));
+      break;
+    case EK_CALL:
+      {
+        band& cble = *b.le_body[0];
+        assert(cble.le_kind == EK_CBLE);
+        assert(cble.le_len == b.le_len);
+        putlayout(cble.le_body);
+      }
+      break;
+
+    #ifndef PRODUCT
+    case EK_CBLE:
+    case EK_CASE:
+      assert(false);  // should not reach here
+    #endif
+    }
+  }
+}
+
+void unpacker::read_files() {
+  file_name.readData(file_count);
+  if (testBit(archive_options, AO_HAVE_FILE_SIZE_HI))
+    file_size_hi.readData(file_count);
+  file_size_lo.readData(file_count);
+  if (testBit(archive_options, AO_HAVE_FILE_MODTIME))
+    file_modtime.readData(file_count);
+  int allFiles = file_count + class_count;
+  if (testBit(archive_options, AO_HAVE_FILE_OPTIONS)) {
+    file_options.readData(file_count);
+    // FO_IS_CLASS_STUB might be set, causing overlap between classes and files
+    for (int i = 0; i < file_count; i++) {
+      if ((file_options.getInt() & FO_IS_CLASS_STUB) != 0) {
+        allFiles -= 1;  // this one counts as both class and file
+      }
+    }
+    file_options.rewind();
+  }
+  assert((default_file_options & FO_IS_CLASS_STUB) == 0);
+  files_remaining = allFiles;
+}
+
+maybe_inline
+void unpacker::get_code_header(int& max_stack,
+                               int& max_na_locals,
+                               int& handler_count,
+                               int& cflags) {
+  int sc = code_headers.getByte();
+  if (sc == 0) {
+    max_stack = max_na_locals = handler_count = cflags = -1;
+    return;
+  }
+  // Short code header is the usual case:
+  int nh;
+  int mod;
+  if (sc < 1 + 12*12) {
+    sc -= 1;
+    nh = 0;
+    mod = 12;
+  } else if (sc < 1 + 12*12 + 8*8) {
+    sc -= 1 + 12*12;
+    nh = 1;
+    mod = 8;
+  } else {
+    assert(sc < 1 + 12*12 + 8*8 + 7*7);
+    sc -= 1 + 12*12 + 8*8;
+    nh = 2;
+    mod = 7;
+  }
+  max_stack     = sc % mod;
+  max_na_locals = sc / mod;  // caller must add static, siglen
+  handler_count = nh;
+  if (testBit(archive_options, AO_HAVE_ALL_CODE_FLAGS))
+    cflags      = -1;
+  else
+    cflags      = 0;  // this one has no attributes
+}
+
+// Cf. PackageReader.readCodeHeaders
+void unpacker::read_code_headers() {
+  code_headers.readData(code_count);
+  CHECK;
+  int totalHandlerCount = 0;
+  int totalFlagsCount   = 0;
+  for (int i = 0; i < code_count; i++) {
+    int max_stack, max_locals, handler_count, cflags;
+    get_code_header(max_stack, max_locals, handler_count, cflags);
+    if (max_stack < 0)      code_max_stack.expectMoreLength(1);
+    if (max_locals < 0)     code_max_na_locals.expectMoreLength(1);
+    if (handler_count < 0)  code_handler_count.expectMoreLength(1);
+    else                    totalHandlerCount += handler_count;
+    if (cflags < 0)         totalFlagsCount += 1;
+  }
+  code_headers.rewind();  // replay later during writing
+
+  code_max_stack.readData();
+  code_max_na_locals.readData();
+  code_handler_count.readData();
+  totalHandlerCount += code_handler_count.getIntTotal();
+  CHECK;
+
+  // Read handler specifications.
+  // Cf. PackageReader.readCodeHandlers.
+  code_handler_start_P.readData(totalHandlerCount);
+  code_handler_end_PO.readData(totalHandlerCount);
+  code_handler_catch_PO.readData(totalHandlerCount);
+  code_handler_class_RCN.readData(totalHandlerCount);
+  CHECK;
+
+  read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
+  CHECK;
+}
+
+static inline bool is_in_range(uint n, uint min, uint max) {
+  return n - min <= max - min;  // unsigned arithmetic!
+}
+static inline bool is_field_op(int bc) {
+  return is_in_range(bc, bc_getstatic, bc_putfield);
+}
+static inline bool is_invoke_init_op(int bc) {
+  return is_in_range(bc, _invokeinit_op, _invokeinit_limit-1);
+}
+static inline bool is_self_linker_op(int bc) {
+  return is_in_range(bc, _self_linker_op, _self_linker_limit-1);
+}
+static bool is_branch_op(int bc) {
+  return is_in_range(bc, bc_ifeq,   bc_jsr)
+      || is_in_range(bc, bc_ifnull, bc_jsr_w);
+}
+static bool is_local_slot_op(int bc) {
+  return is_in_range(bc, bc_iload,  bc_aload)
+      || is_in_range(bc, bc_istore, bc_astore)
+      || bc == bc_iinc || bc == bc_ret;
+}
+band* unpacker::ref_band_for_op(int bc) {
+  switch (bc) {
+  case bc_ildc:
+  case bc_ildc_w:
+    return &bc_intref;
+  case bc_fldc:
+  case bc_fldc_w:
+    return &bc_floatref;
+  case bc_lldc2_w:
+    return &bc_longref;
+  case bc_dldc2_w:
+    return &bc_doubleref;
+  case bc_sldc:
+  case bc_sldc_w:
+    return &bc_stringref;
+  case bc_cldc:
+  case bc_cldc_w:
+    return &bc_classref;
+  case bc_qldc: case bc_qldc_w:
+    return &bc_loadablevalueref;
+
+  case bc_getstatic:
+  case bc_putstatic:
+  case bc_getfield:
+  case bc_putfield:
+    return &bc_fieldref;
+
+  case _invokespecial_int:
+  case _invokestatic_int:
+    return &bc_imethodref;
+  case bc_invokevirtual:
+  case bc_invokespecial:
+  case bc_invokestatic:
+    return &bc_methodref;
+  case bc_invokeinterface:
+    return &bc_imethodref;
+  case bc_invokedynamic:
+    return &bc_indyref;
+
+  case bc_new:
+  case bc_anewarray:
+  case bc_checkcast:
+  case bc_instanceof:
+  case bc_multianewarray:
+    return &bc_classref;
+  }
+  return null;
+}
+
+maybe_inline
+band* unpacker::ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar) {
+  if (!is_self_linker_op(bc))  return null;
+  int idx = (bc - _self_linker_op);
+  bool isSuper = (idx >= _self_linker_super_flag);
+  if (isSuper)  idx -= _self_linker_super_flag;
+  bool isAload = (idx >= _self_linker_aload_flag);
+  if (isAload)  idx -= _self_linker_aload_flag;
+  int origBC = _first_linker_op + idx;
+  bool isField = is_field_op(origBC);
+  isAloadVar = isAload;
+  origBCVar  = _first_linker_op + idx;
+  if (!isSuper)
+    return isField? &bc_thisfield: &bc_thismethod;
+  else
+    return isField? &bc_superfield: &bc_supermethod;
+}
+
+// Cf. PackageReader.readByteCodes
+inline  // called exactly once => inline
+void unpacker::read_bcs() {
+  PRINTCR((3, "reading compressed bytecodes and operands for %d codes...",
+          code_count));
+
+  // read from bc_codes and bc_case_count
+  fillbytes all_switch_ops;
+  all_switch_ops.init();
+  CHECK;
+
+  // Read directly from rp/rplimit.
+  //Do this later:  bc_codes.readData(...)
+  byte* rp0 = rp;
+
+  band* bc_which;
+  byte* opptr = rp;
+  byte* oplimit = rplimit;
+
+  bool  isAload;  // passed by ref and then ignored
+  int   junkBC;   // passed by ref and then ignored
+  for (int k = 0; k < code_count; k++) {
+    // Scan one method:
+    for (;;) {
+      if (opptr+2 > oplimit) {
+        rp = opptr;
+        ensure_input(2);
+        oplimit = rplimit;
+        rp = rp0;  // back up
+      }
+      if (opptr == oplimit) { abort(); break; }
+      int bc = *opptr++ & 0xFF;
+      bool isWide = false;
+      if (bc == bc_wide) {
+        if (opptr == oplimit) { abort(); break; }
+        bc = *opptr++ & 0xFF;
+        isWide = true;
+      }
+      // Adjust expectations of various band sizes.
+      switch (bc) {
+      case bc_tableswitch:
+      case bc_lookupswitch:
+        all_switch_ops.addByte(bc);
+        break;
+      case bc_iinc:
+        bc_local.expectMoreLength(1);
+        bc_which = isWide ? &bc_short : &bc_byte;
+        bc_which->expectMoreLength(1);
+        break;
+      case bc_sipush:
+        bc_short.expectMoreLength(1);
+        break;
+      case bc_bipush:
+        bc_byte.expectMoreLength(1);
+        break;
+      case bc_newarray:
+        bc_byte.expectMoreLength(1);
+        break;
+      case bc_multianewarray:
+        assert(ref_band_for_op(bc) == &bc_classref);
+        bc_classref.expectMoreLength(1);
+        bc_byte.expectMoreLength(1);
+        break;
+      case bc_ref_escape:
+        bc_escrefsize.expectMoreLength(1);
+        bc_escref.expectMoreLength(1);
+        break;
+      case bc_byte_escape:
+        bc_escsize.expectMoreLength(1);
+        // bc_escbyte will have to be counted too
+        break;
+      default:
+        if (is_invoke_init_op(bc)) {
+          bc_initref.expectMoreLength(1);
+          break;
+        }
+        bc_which = ref_band_for_self_op(bc, isAload, junkBC);
+        if (bc_which != null) {
+          bc_which->expectMoreLength(1);
+          break;
+        }
+        if (is_branch_op(bc)) {
+          bc_label.expectMoreLength(1);
+          break;
+        }
+        bc_which = ref_band_for_op(bc);
+        if (bc_which != null) {
+          bc_which->expectMoreLength(1);
+          assert(bc != bc_multianewarray);  // handled elsewhere
+          break;
+        }
+        if (is_local_slot_op(bc)) {
+          bc_local.expectMoreLength(1);
+          break;
+        }
+        break;
+      case bc_end_marker:
+        // Increment k and test against code_count.
+        goto doneScanningMethod;
+      }
+    }
+  doneScanningMethod:{}
+    if (aborting())  break;
+  }
+
+  // Go through the formality, so we can use it in a regular fashion later:
+  assert(rp == rp0);
+  bc_codes.readData((int)(opptr - rp));
+
+  int i = 0;
+
+  // To size instruction bands correctly, we need info on switches:
+  bc_case_count.readData((int)all_switch_ops.size());
+  for (i = 0; i < (int)all_switch_ops.size(); i++) {
+    int caseCount = bc_case_count.getInt();
+    int bc        = all_switch_ops.getByte(i);
+    bc_label.expectMoreLength(1+caseCount); // default label + cases
+    bc_case_value.expectMoreLength(bc == bc_tableswitch ? 1 : caseCount);
+    PRINTCR((2, "switch bc=%d caseCount=%d", bc, caseCount));
+  }
+  bc_case_count.rewind();  // uses again for output
+
+  all_switch_ops.free();
+
+  for (i = e_bc_case_value; i <= e_bc_escsize; i++) {
+    all_bands[i].readData();
+  }
+
+  // The bc_escbyte band is counted by the immediately previous band.
+  bc_escbyte.readData(bc_escsize.getIntTotal());
+
+  PRINTCR((3, "scanned %d opcode and %d operand bytes for %d codes...",
+          (int)(bc_codes.size()),
+          (int)(bc_escsize.maxRP() - bc_case_value.minRP()),
+          code_count));
+}
+
+void unpacker::read_bands() {
+  byte* rp0 = rp;
+  CHECK;
+  read_file_header();
+  CHECK;
+
+  if (cp.nentries == 0) {
+    // read_file_header failed to read a CP, because it copied a JAR.
+    return;
+  }
+
+  // Do this after the file header has been read:
+  check_options();
+
+  read_cp();
+  CHECK;
+  read_attr_defs();
+  CHECK;
+  read_ics();
+  CHECK;
+  read_classes();
+  CHECK;
+  read_bcs();
+  CHECK;
+  read_files();
+}
+
+/// CP routines
+
+entry*& cpool::hashTabRef(byte tag, bytes& b) {
+  PRINTCR((5, "hashTabRef tag=%d %s[%d]", tag, b.string(), b.len));
+  uint hash = tag + (int)b.len;
+  for (int i = 0; i < (int)b.len; i++) {
+    hash = hash * 31 + (0xFF & b.ptr[i]);
+  }
+  entry**  ht = hashTab;
+  int    hlen = hashTabLength;
+  assert((hlen & (hlen-1)) == 0);  // must be power of 2
+  uint hash1 = hash & (hlen-1);    // == hash % hlen
+  uint hash2 = 0;                  // lazily computed (requires mod op.)
+  int probes = 0;
+  while (ht[hash1] != null) {
+    entry& e = *ht[hash1];
+    if (e.value.b.equals(b) && e.tag == tag)
+      break;
+    if (hash2 == 0)
+      // Note:  hash2 must be relatively prime to hlen, hence the "|1".
+      hash2 = (((hash % 499) & (hlen-1)) | 1);
+    hash1 += hash2;
+    if (hash1 >= (uint)hlen)  hash1 -= hlen;
+    assert(hash1 < (uint)hlen);
+    assert(++probes < hlen);
+  }
+  #ifndef PRODUCT
+  hash_probes[0] += 1;
+  hash_probes[1] += probes;
+  #endif
+  PRINTCR((5, " => @%d %p", hash1, ht[hash1]));
+  return ht[hash1];
+}
+
+maybe_inline
+static void insert_extra(entry* e, ptrlist& extras) {
+  // This ordering helps implement the Pack200 requirement
+  // of a predictable CP order in the class files produced.
+  e->inord = NO_INORD;  // mark as an "extra"
+  extras.add(e);
+  // Note:  We will sort the list (by string-name) later.
+}
+
+entry* cpool::ensureUtf8(bytes& b) {
+  entry*& ix = hashTabRef(CONSTANT_Utf8, b);
+  if (ix != null)  return ix;
+  // Make one.
+  if (nentries == maxentries) {
+    abort("cp utf8 overflow");
+    return &entries[tag_base[CONSTANT_Utf8]];  // return something
+  }
+  entry& e = entries[nentries++];
+  e.tag = CONSTANT_Utf8;
+  u->saveTo(e.value.b, b);
+  assert(&e >= first_extra_entry);
+  insert_extra(&e, tag_extras[CONSTANT_Utf8]);
+  PRINTCR((4,"ensureUtf8 miss %s", e.string()));
+  return ix = &e;
+}
+
+entry* cpool::ensureClass(bytes& b) {
+  entry*& ix = hashTabRef(CONSTANT_Class, b);
+  if (ix != null)  return ix;
+  // Make one.
+  if (nentries == maxentries) {
+    abort("cp class overflow");
+    return &entries[tag_base[CONSTANT_Class]];  // return something
+  }
+  entry& e = entries[nentries++];
+  e.tag = CONSTANT_Class;
+  e.nrefs = 1;
+  e.refs = U_NEW(entry*, 1);
+  ix = &e;  // hold my spot in the index
+  entry* utf = ensureUtf8(b);
+  e.refs[0] = utf;
+  e.value.b = utf->value.b;
+  assert(&e >= first_extra_entry);
+  insert_extra(&e, tag_extras[CONSTANT_Class]);
+  PRINTCR((4,"ensureClass miss %s", e.string()));
+  return &e;
+}
+
+void cpool::expandSignatures() {
+  int i;
+  int nsigs = 0;
+  int nreused = 0;
+  int first_sig = tag_base[CONSTANT_Signature];
+  int sig_limit = tag_count[CONSTANT_Signature] + first_sig;
+  fillbytes buf;
+  buf.init(1<<10);
+  CHECK;
+  for (i = first_sig; i < sig_limit; i++) {
+    entry& e = entries[i];
+    assert(e.tag == CONSTANT_Signature);
+    int refnum = 0;
+    bytes form = e.refs[refnum++]->asUtf8();
+    buf.empty();
+    for (int j = 0; j < (int)form.len; j++) {
+      int c = form.ptr[j];
+      buf.addByte(c);
+      if (c == 'L') {
+        entry* cls = e.refs[refnum++];
+        buf.append(cls->className()->asUtf8());
+      }
+    }
+    assert(refnum == e.nrefs);
+    bytes& sig = buf.b;
+    PRINTCR((5,"signature %d %s -> %s", i, form.ptr, sig.ptr));
+
+    // try to find a pre-existing Utf8:
+    entry* &e2 = hashTabRef(CONSTANT_Utf8, sig);
+    if (e2 != null) {
+      assert(e2->isUtf8(sig));
+      e.value.b = e2->value.b;
+      e.refs[0] = e2;
+      e.nrefs = 1;
+      PRINTCR((5,"signature replaced %d => %s", i, e.string()));
+      nreused++;
+    } else {
+      // there is no other replacement; reuse this CP entry as a Utf8
+      u->saveTo(e.value.b, sig);
+      e.tag = CONSTANT_Utf8;
+      e.nrefs = 0;
+      e2 = &e;
+      PRINTCR((5,"signature changed %d => %s", e.inord, e.string()));
+    }
+    nsigs++;
+  }
+  PRINTCR((1,"expanded %d signatures (reused %d utfs)", nsigs, nreused));
+  buf.free();
+
+  // go expunge all references to remaining signatures:
+  for (i = 0; i < (int)nentries; i++) {
+    entry& e = entries[i];
+    for (int j = 0; j < e.nrefs; j++) {
+      entry*& e2 = e.refs[j];
+      if (e2 != null && e2->tag == CONSTANT_Signature)
+        e2 = e2->refs[0];
+    }
+  }
+}
+
+bool isLoadableValue(int tag) {
+  switch(tag) {
+    case CONSTANT_Integer:
+    case CONSTANT_Float:
+    case CONSTANT_Long:
+    case CONSTANT_Double:
+    case CONSTANT_String:
+    case CONSTANT_Class:
+    case CONSTANT_MethodHandle:
+    case CONSTANT_MethodType:
+      return true;
+    default:
+      return false;
+  }
+}
+/*
+ * this method can be used to size an array using null as the parameter,
+ * thereafter can be reused to initialize the array using a valid pointer
+ * as a parameter.
+ */
+int cpool::initLoadableValues(entry** loadable_entries) {
+  int loadable_count = 0;
+  for (int i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
+    int tag = TAGS_IN_ORDER[i];
+    if (!isLoadableValue(tag))
+      continue;
+    if (loadable_entries != NULL) {
+      for (int n = 0 ; n < tag_count[tag] ; n++) {
+        loadable_entries[loadable_count + n] = &entries[tag_base[tag] + n];
+      }
+    }
+    loadable_count += tag_count[tag];
+  }
+  return loadable_count;
+}
+
+// Initialize various views into the constant pool.
+void cpool::initGroupIndexes() {
+  // Initialize All
+  int all_count = 0;
+  for (int tag = CONSTANT_None ; tag < CONSTANT_Limit ; tag++) {
+    all_count += tag_count[tag];
+  }
+  entry* all_entries = &entries[tag_base[CONSTANT_None]];
+  tag_group_count[CONSTANT_All - CONSTANT_All] = all_count;
+  tag_group_index[CONSTANT_All - CONSTANT_All].init(all_count, all_entries, CONSTANT_All);
+
+  // Initialize LoadableValues
+  int loadable_count = initLoadableValues(NULL);
+  entry** loadable_entries = U_NEW(entry*, loadable_count);
+  initLoadableValues(loadable_entries);
+  tag_group_count[CONSTANT_LoadableValue - CONSTANT_All] = loadable_count;
+  tag_group_index[CONSTANT_LoadableValue - CONSTANT_All].init(loadable_count,
+                  loadable_entries, CONSTANT_LoadableValue);
+
+// Initialize AnyMembers
+  int any_count = tag_count[CONSTANT_Fieldref] +
+                  tag_count[CONSTANT_Methodref] +
+                  tag_count[CONSTANT_InterfaceMethodref];
+  entry *any_entries = &entries[tag_base[CONSTANT_Fieldref]];
+  tag_group_count[CONSTANT_AnyMember - CONSTANT_All] = any_count;
+  tag_group_index[CONSTANT_AnyMember - CONSTANT_All].init(any_count,
+                                               any_entries, CONSTANT_AnyMember);
+}
+
+void cpool::initMemberIndexes() {
+  // This function does NOT refer to any class schema.
+  // It is totally internal to the cpool.
+  int i, j;
+
+  // Get the pre-existing indexes:
+  int   nclasses = tag_count[CONSTANT_Class];
+  entry* classes = tag_base[CONSTANT_Class] + entries;
+  int   nfields  = tag_count[CONSTANT_Fieldref];
+  entry* fields  = tag_base[CONSTANT_Fieldref] + entries;
+  int   nmethods = tag_count[CONSTANT_Methodref];
+  entry* methods = tag_base[CONSTANT_Methodref] + entries;
+
+  int*     field_counts  = T_NEW(int, nclasses);
+  int*     method_counts = T_NEW(int, nclasses);
+  cpindex* all_indexes   = U_NEW(cpindex, nclasses*2);
+  entry**  field_ix      = U_NEW(entry*, add_size(nfields, nclasses));
+  entry**  method_ix     = U_NEW(entry*, add_size(nmethods, nclasses));
+
+  for (j = 0; j < nfields; j++) {
+    entry& f = fields[j];
+    i = f.memberClass()->inord;
+    assert(i < nclasses);
+    field_counts[i]++;
+  }
+  for (j = 0; j < nmethods; j++) {
+    entry& m = methods[j];
+    i = m.memberClass()->inord;
+    assert(i < nclasses);
+    method_counts[i]++;
+  }
+
+  int fbase = 0, mbase = 0;
+  for (i = 0; i < nclasses; i++) {
+    int fc = field_counts[i];
+    int mc = method_counts[i];
+    all_indexes[i*2+0].init(fc, field_ix+fbase,
+                            CONSTANT_Fieldref  + SUBINDEX_BIT);
+    all_indexes[i*2+1].init(mc, method_ix+mbase,
+                            CONSTANT_Methodref + SUBINDEX_BIT);
+    // reuse field_counts and member_counts as fill pointers:
+    field_counts[i] = fbase;
+    method_counts[i] = mbase;
+    PRINTCR((3, "class %d fields @%d[%d] methods @%d[%d]",
+            i, fbase, fc, mbase, mc));
+    fbase += fc+1;
+    mbase += mc+1;
+    // (the +1 leaves a space between every subarray)
+  }
+  assert(fbase == nfields+nclasses);
+  assert(mbase == nmethods+nclasses);
+
+  for (j = 0; j < nfields; j++) {
+    entry& f = fields[j];
+    i = f.memberClass()->inord;
+    field_ix[field_counts[i]++] = &f;
+  }
+  for (j = 0; j < nmethods; j++) {
+    entry& m = methods[j];
+    i = m.memberClass()->inord;
+    method_ix[method_counts[i]++] = &m;
+  }
+
+  member_indexes = all_indexes;
+
+#ifndef PRODUCT
+  // Test the result immediately on every class and field.
+  int fvisited = 0, mvisited = 0;
+  int prevord, len;
+  for (i = 0; i < nclasses; i++) {
+    entry*   cls = &classes[i];
+    cpindex* fix = getFieldIndex(cls);
+    cpindex* mix = getMethodIndex(cls);
+    PRINTCR((2, "field and method index for %s [%d] [%d]",
+            cls->string(), mix->len, fix->len));
+    prevord = -1;
+    for (j = 0, len = fix->len; j < len; j++) {
+      entry* f = fix->get(j);
+      assert(f != null);
+      PRINTCR((3, "- field %s", f->string()));
+      assert(f->memberClass() == cls);
+      assert(prevord < (int)f->inord);
+      prevord = f->inord;
+      fvisited++;
+    }
+    assert(fix->base2[j] == null);
+    prevord = -1;
+    for (j = 0, len = mix->len; j < len; j++) {
+      entry* m = mix->get(j);
+      assert(m != null);
+      PRINTCR((3, "- method %s", m->string()));
+      assert(m->memberClass() == cls);
+      assert(prevord < (int)m->inord);
+      prevord = m->inord;
+      mvisited++;
+    }
+    assert(mix->base2[j] == null);
+  }
+  assert(fvisited == nfields);
+  assert(mvisited == nmethods);
+#endif
+
+  // Free intermediate buffers.
+  u->free_temps();
+}
+
+void entry::requestOutputIndex(cpool& cp, int req) {
+  assert(outputIndex <= REQUESTED_NONE);  // must not have assigned indexes yet
+  if (tag == CONSTANT_Signature) {
+    ref(0)->requestOutputIndex(cp, req);
+    return;
+  }
+  assert(req == REQUESTED || req == REQUESTED_LDC);
+  if (outputIndex != REQUESTED_NONE) {
+    if (req == REQUESTED_LDC)
+      outputIndex = req;  // this kind has precedence
+    return;
+  }
+  outputIndex = req;
+  //assert(!cp.outputEntries.contains(this));
+  assert(tag != CONSTANT_Signature);
+  // The BSMs are jetisoned to a side table, however all references
+  // that the BSMs refer to,  need to be considered.
+  if (tag == CONSTANT_BootstrapMethod) {
+    // this is a a pseudo-op entry; an attribute will be generated later on
+    cp.requested_bsms.add(this);
+  } else {
+    // all other tag types go into real output file CP:
+    cp.outputEntries.add(this);
+  }
+  for (int j = 0; j < nrefs; j++) {
+    ref(j)->requestOutputIndex(cp);
+  }
+}
+
+void cpool::resetOutputIndexes() {
+    /*
+     * reset those few entries that are being used in the current class
+     * (Caution since this method is called after every class written, a loop
+     * over every global constant pool entry would be a quadratic cost.)
+     */
+
+  int noes    = outputEntries.length();
+  entry** oes = (entry**) outputEntries.base();
+  for (int i = 0 ; i < noes ; i++) {
+    entry& e = *oes[i];
+    e.outputIndex = REQUESTED_NONE;
+  }
+
+  // do the same for bsms and reset them if required
+  int nbsms = requested_bsms.length();
+  entry** boes = (entry**) requested_bsms.base();
+  for (int i = 0 ; i < nbsms ; i++) {
+    entry& e = *boes[i];
+    e.outputIndex = REQUESTED_NONE;
+  }
+  outputIndexLimit = 0;
+  outputEntries.empty();
+#ifndef PRODUCT
+  // ensure things are cleared out
+  for (int i = 0; i < (int)maxentries; i++)
+    assert(entries[i].outputIndex == REQUESTED_NONE);
+#endif
+}
+
+static const byte TAG_ORDER[CONSTANT_Limit] = {
+  0, 1, 0, 2, 3, 4, 5, 7, 6, 10, 11, 12, 9, 8, 0, 13, 14, 15, 16
+};
+
+extern "C"
+int outputEntry_cmp(const void* e1p, const void* e2p) {
+  // Sort entries according to the Pack200 rules for deterministic
+  // constant pool ordering.
+  //
+  // The four sort keys as follows, in order of decreasing importance:
+  //   1. ldc first, then non-ldc guys
+  //   2. normal cp_All entries by input order (i.e., address order)
+  //   3. after that, extra entries by lexical order (as in tag_extras[*])
+  entry& e1 = *(entry*) *(void**) e1p;
+  entry& e2 = *(entry*) *(void**) e2p;
+  int   oi1 = e1.outputIndex;
+  int   oi2 = e2.outputIndex;
+  assert(oi1 == REQUESTED || oi1 == REQUESTED_LDC);
+  assert(oi2 == REQUESTED || oi2 == REQUESTED_LDC);
+  if (oi1 != oi2) {
+    if (oi1 == REQUESTED_LDC)  return 0-1;
+    if (oi2 == REQUESTED_LDC)  return 1-0;
+    // Else fall through; neither is an ldc request.
+  }
+  if (e1.inord != NO_INORD || e2.inord != NO_INORD) {
+    // One or both is normal.  Use input order.
+    if (&e1 > &e2)  return 1-0;
+    if (&e1 < &e2)  return 0-1;
+    return 0;  // equal pointers
+  }
+  // Both are extras.  Sort by tag and then by value.
+  if (e1.tag != e2.tag) {
+    return TAG_ORDER[e1.tag] - TAG_ORDER[e2.tag];
+  }
+  // If the tags are the same, use string comparison.
+  return compare_Utf8_chars(e1.value.b, e2.value.b);
+}
+
+void cpool::computeOutputIndexes() {
+  int i;
+
+#ifndef PRODUCT
+  // outputEntries must be a complete list of those requested:
+  static uint checkStart = 0;
+  int checkStep = 1;
+  if (nentries > 100)  checkStep = nentries / 100;
+  for (i = (int)(checkStart++ % checkStep); i < (int)nentries; i += checkStep) {
+    entry& e = entries[i];
+    if (e.tag == CONSTANT_BootstrapMethod) {
+      if (e.outputIndex != REQUESTED_NONE) {
+        assert(requested_bsms.contains(&e));
+      } else {
+        assert(!requested_bsms.contains(&e));
+      }
+    } else {
+      if (e.outputIndex != REQUESTED_NONE) {
+        assert(outputEntries.contains(&e));
+      } else {
+        assert(!outputEntries.contains(&e));
+      }
+    }
+  }
+
+  // check hand-initialization of TAG_ORDER
+  for (i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
+    byte tag = TAGS_IN_ORDER[i];
+    assert(TAG_ORDER[tag] == i+1);
+  }
+#endif
+
+  int    noes =           outputEntries.length();
+  entry** oes = (entry**) outputEntries.base();
+
+  // Sort the output constant pool into the order required by Pack200.
+  PTRLIST_QSORT(outputEntries, outputEntry_cmp);
+
+  // Allocate a new index for each entry that needs one.
+  // We do this in two passes, one for LDC entries and one for the rest.
+  int nextIndex = 1;  // always skip index #0 in output cpool
+  for (i = 0; i < noes; i++) {
+    entry& e = *oes[i];
+    assert(e.outputIndex >= REQUESTED_LDC);
+    e.outputIndex = nextIndex++;
+    if (e.isDoubleWord())  nextIndex++;  // do not use the next index
+  }
+  outputIndexLimit = nextIndex;
+  PRINTCR((3,"renumbering CP to %d entries", outputIndexLimit));
+}
+
+#ifndef PRODUCT
+// debugging goo
+
+unpacker* debug_u;
+
+static bytes& getbuf(size_t len) {  // for debugging only!
+  static int bn = 0;
+  static bytes bufs[8];
+  bytes& buf = bufs[bn++ & 7];
+  while (buf.len < len + 10) {
+    buf.realloc(buf.len ? buf.len * 2 : 1000);
+  }
+  buf.ptr[0] = 0;  // for the sake of strcat
+  return buf;
+}
+
+const char* entry::string() {
+  bytes buf;
+  switch (tag) {
+  case CONSTANT_None:
+    return "<empty>";
+  case CONSTANT_Signature:
+    if (value.b.ptr == null)
+      return ref(0)->string();
+    // else fall through:
+  case CONSTANT_Utf8:
+    buf = value.b;
+    break;
+  case CONSTANT_Integer:
+  case CONSTANT_Float:
+    buf = getbuf(12);
+    sprintf((char*)buf.ptr, "0x%08x", value.i);
+    break;
+  case CONSTANT_Long:
+  case CONSTANT_Double:
+    buf = getbuf(24);
+    sprintf((char*)buf.ptr, "0x" LONG_LONG_HEX_FORMAT, value.l);
+    break;
+  default:
+    if (nrefs == 0) {
+      return TAG_NAME[tag];
+    } else if (nrefs == 1) {
+      return refs[0]->string();
+    } else {
+      const char* s1 = refs[0]->string();
+      const char* s2 = refs[1]->string();
+      buf = getbuf(strlen(s1) + 1 + strlen(s2) + 4 + 1);
+      buf.strcat(s1).strcat(" ").strcat(s2);
+      if (nrefs > 2)  buf.strcat(" ...");
+    }
+  }
+  return (const char*)buf.ptr;
+}
+
+void print_cp_entry(int i) {
+  entry& e = debug_u->cp.entries[i];
+
+  if ((uint)e.tag < CONSTANT_Limit) {
+    printf(" %d\t%s %s\n", i, TAG_NAME[e.tag], e.string());
+  } else {
+    printf(" %d\t%d %s\n", i, e.tag, e.string());
+  }
+}
+
+void print_cp_entries(int beg, int end) {
+  for (int i = beg; i < end; i++)
+    print_cp_entry(i);
+}
+
+void print_cp() {
+  print_cp_entries(0, debug_u->cp.nentries);
+}
+
+#endif
+
+// Unpacker Start
+
+const char str_tf[] = "true\0false";
+#undef STR_TRUE
+#undef STR_FALSE
+#define STR_TRUE   (&str_tf[0])
+#define STR_FALSE  (&str_tf[5])
+
+const char* unpacker::get_option(const char* prop) {
+  if (prop == null )  return null;
+  if (strcmp(prop, UNPACK_DEFLATE_HINT) == 0) {
+    return deflate_hint_or_zero == 0? null : STR_TF(deflate_hint_or_zero > 0);
+#ifdef HAVE_STRIP
+  } else if (strcmp(prop, UNPACK_STRIP_COMPILE) == 0) {
+    return STR_TF(strip_compile);
+  } else if (strcmp(prop, UNPACK_STRIP_DEBUG) == 0) {
+    return STR_TF(strip_debug);
+  } else if (strcmp(prop, UNPACK_STRIP_JCOV) == 0) {
+    return STR_TF(strip_jcov);
+#endif /*HAVE_STRIP*/
+  } else if (strcmp(prop, UNPACK_REMOVE_PACKFILE) == 0) {
+    return STR_TF(remove_packfile);
+  } else if (strcmp(prop, DEBUG_VERBOSE) == 0) {
+    return saveIntStr(verbose);
+  } else if (strcmp(prop, UNPACK_MODIFICATION_TIME) == 0) {
+    return (modification_time_or_zero == 0)? null:
+      saveIntStr(modification_time_or_zero);
+  } else if (strcmp(prop, UNPACK_LOG_FILE) == 0) {
+    return log_file;
+  } else {
+    return NULL; // unknown option ignore
+  }
+}
+
+bool unpacker::set_option(const char* prop, const char* value) {
+  if (prop == NULL)  return false;
+  if (strcmp(prop, UNPACK_DEFLATE_HINT) == 0) {
+    deflate_hint_or_zero = ( (value == null || strcmp(value, "keep") == 0)
+                                ? 0: BOOL_TF(value) ? +1: -1);
+#ifdef HAVE_STRIP
+  } else if (strcmp(prop, UNPACK_STRIP_COMPILE) == 0) {
+    strip_compile = STR_TF(value);
+  } else if (strcmp(prop, UNPACK_STRIP_DEBUG) == 0) {
+    strip_debug = STR_TF(value);
+  } else if (strcmp(prop, UNPACK_STRIP_JCOV) == 0) {
+    strip_jcov = STR_TF(value);
+#endif /*HAVE_STRIP*/
+  } else if (strcmp(prop, UNPACK_REMOVE_PACKFILE) == 0) {
+    remove_packfile = STR_TF(value);
+  } else if (strcmp(prop, DEBUG_VERBOSE) == 0) {
+    verbose = (value == null)? 0: atoi(value);
+  } else if (strcmp(prop, DEBUG_VERBOSE ".bands") == 0) {
+#ifndef PRODUCT
+    verbose_bands = (value == null)? 0: atoi(value);
+#endif
+  } else if (strcmp(prop, UNPACK_MODIFICATION_TIME) == 0) {
+    if (value == null || (strcmp(value, "keep") == 0)) {
+      modification_time_or_zero = 0;
+    } else if (strcmp(value, "now") == 0) {
+      time_t now;
+      time(&now);
+      modification_time_or_zero = (int) now;
+    } else {
+      modification_time_or_zero = atoi(value);
+      if (modification_time_or_zero == 0)
+        modification_time_or_zero = 1;  // make non-zero
+    }
+  } else if (strcmp(prop, UNPACK_LOG_FILE) == 0) {
+    log_file = (value == null)? value: saveStr(value);
+  } else {
+    return false; // unknown option ignore
+  }
+  return true;
+}
+
+// Deallocate all internal storage and reset to a clean state.
+// Do not disturb any input or output connections, including
+// infileptr, infileno, inbytes, read_input_fn, jarout, or errstrm.
+// Do not reset any unpack options.
+void unpacker::reset() {
+  bytes_read_before_reset      += bytes_read;
+  bytes_written_before_reset   += bytes_written;
+  files_written_before_reset   += files_written;
+  classes_written_before_reset += classes_written;
+  segments_read_before_reset   += 1;
+  if (verbose >= 2) {
+    fprintf(errstrm,
+            "After segment %d, "
+            LONG_LONG_FORMAT " bytes read and "
+            LONG_LONG_FORMAT " bytes written.\n",
+            segments_read_before_reset-1,
+            bytes_read_before_reset, bytes_written_before_reset);
+    fprintf(errstrm,
+            "After segment %d, %d files (of which %d are classes) written to output.\n",
+            segments_read_before_reset-1,
+            files_written_before_reset, classes_written_before_reset);
+    if (archive_next_count != 0) {
+      fprintf(errstrm,
+              "After segment %d, %d segment%s remaining (estimated).\n",
+              segments_read_before_reset-1,
+              archive_next_count, archive_next_count==1?"":"s");
+    }
+  }
+
+  unpacker save_u = (*this);  // save bytewise image
+  infileptr = null;  // make asserts happy
+  jniobj = null;  // make asserts happy
+  jarout = null;  // do not close the output jar
+  gzin = null;  // do not close the input gzip stream
+  bytes esn;
+  if (errstrm_name != null) {
+    esn.saveFrom(errstrm_name);
+  } else {
+    esn.set(null, 0);
+  }
+  this->free();
+  mtrace('s', 0, 0);  // note the boundary between segments
+  this->init(read_input_fn);
+
+  // restore selected interface state:
+#define SAVE(x) this->x = save_u.x
+  SAVE(jniobj);
+  SAVE(jnienv);
+  SAVE(infileptr);  // buffered
+  SAVE(infileno);   // unbuffered
+  SAVE(inbytes);    // direct
+  SAVE(jarout);
+  SAVE(gzin);
+  //SAVE(read_input_fn);
+  SAVE(errstrm);
+  SAVE(verbose);  // verbose level, 0 means no output
+  SAVE(strip_compile);
+  SAVE(strip_debug);
+  SAVE(strip_jcov);
+  SAVE(remove_packfile);
+  SAVE(deflate_hint_or_zero);  // ==0 means not set, otherwise -1 or 1
+  SAVE(modification_time_or_zero);
+  SAVE(bytes_read_before_reset);
+  SAVE(bytes_written_before_reset);
+  SAVE(files_written_before_reset);
+  SAVE(classes_written_before_reset);
+  SAVE(segments_read_before_reset);
+#undef SAVE
+  if (esn.len > 0) {
+    errstrm_name = saveStr(esn.strval());
+    esn.free();
+  }
+  log_file = errstrm_name;
+  // Note:  If we use strip_names, watch out:  They get nuked here.
+}
+
+void unpacker::init(read_input_fn_t input_fn) {
+  int i;
+  NOT_PRODUCT(debug_u = this);
+  BYTES_OF(*this).clear();
+#ifndef PRODUCT
+  free();  // just to make sure freeing is idempotent
+#endif
+  this->u = this;    // self-reference for U_NEW macro
+  errstrm = stdout;  // default error-output
+  log_file = LOGFILE_STDOUT;
+  read_input_fn = input_fn;
+  all_bands = band::makeBands(this);
+  // Make a default jar buffer; caller may safely overwrite it.
+  jarout = U_NEW(jar, 1);
+  jarout->init(this);
+  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++)
+    attr_defs[i].u = u;  // set up outer ptr
+}
+
+const char* unpacker::get_abort_message() {
+   return abort_message;
+}
+
+void unpacker::dump_options() {
+  static const char* opts[] = {
+    UNPACK_LOG_FILE,
+    UNPACK_DEFLATE_HINT,
+#ifdef HAVE_STRIP
+    UNPACK_STRIP_COMPILE,
+    UNPACK_STRIP_DEBUG,
+    UNPACK_STRIP_JCOV,
+#endif /*HAVE_STRIP*/
+    UNPACK_REMOVE_PACKFILE,
+    DEBUG_VERBOSE,
+    UNPACK_MODIFICATION_TIME,
+    null
+  };
+  for (int i = 0; opts[i] != null; i++) {
+    const char* str = get_option(opts[i]);
+    if (str == null) {
+      if (verbose == 0)  continue;
+      str = "(not set)";
+    }
+    fprintf(errstrm, "%s=%s\n", opts[i], str);
+  }
+}
+
+
+// Usage: unpack a byte buffer
+// packptr is a reference to byte buffer containing a
+// packed file and len is the length of the buffer.
+// If null, the callback is used to fill an internal buffer.
+void unpacker::start(void* packptr, size_t len) {
+  CHECK;
+  NOT_PRODUCT(debug_u = this);
+  if (packptr != null && len != 0) {
+    inbytes.set((byte*) packptr, len);
+  }
+  CHECK;
+  read_bands();
+}
+
+void unpacker::check_options() {
+  const char* strue  = "true";
+  const char* sfalse = "false";
+  if (deflate_hint_or_zero != 0) {
+    bool force_deflate_hint = (deflate_hint_or_zero > 0);
+    if (force_deflate_hint)
+      default_file_options |= FO_DEFLATE_HINT;
+    else
+      default_file_options &= ~FO_DEFLATE_HINT;
+    // Turn off per-file deflate hint by force.
+    suppress_file_options |= FO_DEFLATE_HINT;
+  }
+  if (modification_time_or_zero != 0) {
+    default_file_modtime = modification_time_or_zero;
+    // Turn off per-file modtime by force.
+    archive_options &= ~AO_HAVE_FILE_MODTIME;
+  }
+  // %%% strip_compile, etc...
+}
+
+// classfile writing
+
+void unpacker::reset_cur_classfile() {
+  // set defaults
+  cur_class_minver = default_class_minver;
+  cur_class_majver = default_class_majver;
+
+  // reset constant pool state
+  cp.resetOutputIndexes();
+
+  // reset fixups
+  class_fixup_type.empty();
+  class_fixup_offset.empty();
+  class_fixup_ref.empty();
+  requested_ics.empty();
+  cp.requested_bsms.empty();
+}
+
+cpindex* cpool::getKQIndex() {
+  char ch = '?';
+  if (u->cur_descr != null) {
+    entry* type = u->cur_descr->descrType();
+    ch = type->value.b.ptr[0];
+  }
+  byte tag = CONSTANT_Integer;
+  switch (ch) {
+  case 'L': tag = CONSTANT_String;   break;
+  case 'I': tag = CONSTANT_Integer;  break;
+  case 'J': tag = CONSTANT_Long;     break;
+  case 'F': tag = CONSTANT_Float;    break;
+  case 'D': tag = CONSTANT_Double;   break;
+  case 'B': case 'S': case 'C':
+  case 'Z': tag = CONSTANT_Integer;  break;
+  default:  abort("bad KQ reference"); break;
+  }
+  return getIndex(tag);
+}
+
+uint unpacker::to_bci(uint bii) {
+  uint  len =         bcimap.length();
+  uint* map = (uint*) bcimap.base();
+  assert(len > 0);  // must be initialized before using to_bci
+  if (len == 0) {
+    abort("bad bcimap");
+    return 0;
+  }
+  if (bii < len)
+    return map[bii];
+  // Else it's a fractional or out-of-range BCI.
+  uint key = bii-len;
+  for (int i = len; ; i--) {
+    if (map[i-1]-(i-1) <= key)
+      break;
+    else
+      --bii;
+  }
+  return bii;
+}
+
+void unpacker::put_stackmap_type() {
+  int tag = code_StackMapTable_T.getByte();
+  putu1(tag);
+  switch (tag) {
+  case 7: // (7) [RCH]
+    putref(code_StackMapTable_RC.getRef());
+    break;
+  case 8: // (8) [PH]
+    putu2(to_bci(code_StackMapTable_P.getInt()));
+    CHECK;
+    break;
+  }
+}
+
+// Functions for writing code.
+
+maybe_inline
+void unpacker::put_label(int curIP, int size) {
+  code_fixup_type.addByte(size);
+  code_fixup_offset.add((int)put_empty(size));
+  code_fixup_source.add(curIP);
+}
+
+inline  // called exactly once => inline
+void unpacker::write_bc_ops() {
+  bcimap.empty();
+  code_fixup_type.empty();
+  code_fixup_offset.empty();
+  code_fixup_source.empty();
+
+  band* bc_which;
+
+  byte*  opptr = bc_codes.curRP();
+  // No need for oplimit, since the codes are pre-counted.
+
+  size_t codeBase = wpoffset();
+
+  bool   isAload;  // copy-out result
+  int    origBC;
+
+  entry* thisClass  = cur_class;
+  entry* superClass = cur_super;
+  entry* newClass   = null;  // class of last _new opcode
+
+  // overwrite any prior index on these bands; it changes w/ current class:
+  bc_thisfield.setIndex(    cp.getFieldIndex( thisClass));
+  bc_thismethod.setIndex(   cp.getMethodIndex(thisClass));
+  if (superClass != null) {
+    bc_superfield.setIndex( cp.getFieldIndex( superClass));
+    bc_supermethod.setIndex(cp.getMethodIndex(superClass));
+  } else {
+    NOT_PRODUCT(bc_superfield.setIndex(null));
+    NOT_PRODUCT(bc_supermethod.setIndex(null));
+  }
+  CHECK;
+
+  for (int curIP = 0; ; curIP++) {
+    CHECK;
+    int curPC = (int)(wpoffset() - codeBase);
+    bcimap.add(curPC);
+    ensure_put_space(10);  // covers most instrs w/o further bounds check
+    int bc = *opptr++ & 0xFF;
+
+    putu1_fast(bc);
+    // Note:  See '--wp' below for pseudo-bytecodes like bc_end_marker.
+
+    bool isWide = false;
+    if (bc == bc_wide) {
+      bc = *opptr++ & 0xFF;
+      putu1_fast(bc);
+      isWide = true;
+    }
+    switch (bc) {
+    case bc_end_marker:
+      --wp;  // not really part of the code
+      assert(opptr <= bc_codes.maxRP());
+      bc_codes.curRP() = opptr;  // advance over this in bc_codes
+      goto doneScanningMethod;
+    case bc_tableswitch: // apc:  (df, lo, hi, (hi-lo+1)*(label))
+    case bc_lookupswitch: // apc:  (df, nc, nc*(case, label))
+      {
+        int caseCount = bc_case_count.getInt();
+        while (((wpoffset() - codeBase) % 4) != 0)  putu1_fast(0);
+        ensure_put_space(30 + caseCount*8);
+        put_label(curIP, 4);  //int df = bc_label.getInt();
+        if (bc == bc_tableswitch) {
+          int lo = bc_case_value.getInt();
+          int hi = lo + caseCount-1;
+          putu4(lo);
+          putu4(hi);
+          for (int j = 0; j < caseCount; j++) {
+            put_label(curIP, 4); //int lVal = bc_label.getInt();
+            //int cVal = lo + j;
+          }
+        } else {
+          putu4(caseCount);
+          for (int j = 0; j < caseCount; j++) {
+            int cVal = bc_case_value.getInt();
+            putu4(cVal);
+            put_label(curIP, 4); //int lVal = bc_label.getInt();
+          }
+        }
+        assert((int)to_bci(curIP) == curPC);
+        continue;
+      }
+    case bc_iinc:
+      {
+        int local = bc_local.getInt();
+        int delta = (isWide ? bc_short : bc_byte).getInt();
+        if (isWide) {
+          putu2(local);
+          putu2(delta);
+        } else {
+          putu1_fast(local);
+          putu1_fast(delta);
+        }
+        continue;
+      }
+    case bc_sipush:
+      {
+        int val = bc_short.getInt();
+        putu2(val);
+        continue;
+      }
+    case bc_bipush:
+    case bc_newarray:
+      {
+        int val = bc_byte.getByte();
+        putu1_fast(val);
+        continue;
+      }
+    case bc_ref_escape:
+      {
+        // Note that insnMap has one entry for this.
+        --wp;  // not really part of the code
+        int size = bc_escrefsize.getInt();
+        entry* ref = bc_escref.getRefN();
+        CHECK;
+        switch (size) {
+        case 1: putu1ref(ref); break;
+        case 2: putref(ref);   break;
+        default: assert(false);
+        }
+        continue;
+      }
+    case bc_byte_escape:
+      {
+        // Note that insnMap has one entry for all these bytes.
+        --wp;  // not really part of the code
+        int size = bc_escsize.getInt();
+        if (size < 0) { assert(false); continue; }
+        ensure_put_space(size);
+        for (int j = 0; j < size; j++)
+          putu1_fast(bc_escbyte.getByte());
+        continue;
+      }
+    default:
+      if (is_invoke_init_op(bc)) {
+        origBC = bc_invokespecial;
+        entry* classRef;
+        switch (bc - _invokeinit_op) {
+        case _invokeinit_self_option:   classRef = thisClass;  break;
+        case _invokeinit_super_option:  classRef = superClass; break;
+        default: assert(bc == _invokeinit_op+_invokeinit_new_option);
+        case _invokeinit_new_option:    classRef = newClass;   break;
+        }
+        wp[-1] = origBC;  // overwrite with origBC
+        int coding = bc_initref.getInt();
+        // Find the nth overloading of <init> in classRef.
+        entry*   ref = null;
+        cpindex* ix = cp.getMethodIndex(classRef);
+        CHECK;
+        for (int j = 0, which_init = 0; ; j++) {
+          ref = (ix == null)? null: ix->get(j);
+          if (ref == null)  break;  // oops, bad input
+          assert(ref->tag == CONSTANT_Methodref);
+          if (ref->memberDescr()->descrName() == cp.sym[cpool::s_lt_init_gt]) {
+            if (which_init++ == coding)  break;
+          }
+        }
+        putref(ref);
+        continue;
+      }
+      bc_which = ref_band_for_self_op(bc, isAload, origBC);
+      if (bc_which != null) {
+        if (!isAload) {
+          wp[-1] = origBC;  // overwrite with origBC
+        } else {
+          wp[-1] = bc_aload_0;  // overwrite with _aload_0
+          // Note: insnMap keeps the _aload_0 separate.
+          bcimap.add(++curPC);
+          ++curIP;
+          putu1_fast(origBC);
+        }
+        entry* ref = bc_which->getRef();
+        CHECK;
+        putref(ref);
+        continue;
+      }
+      if (is_branch_op(bc)) {
+        //int lVal = bc_label.getInt();
+        if (bc < bc_goto_w) {
+          put_label(curIP, 2);  //putu2(lVal & 0xFFFF);
+        } else {
+          assert(bc <= bc_jsr_w);
+          put_label(curIP, 4);  //putu4(lVal);
+        }
+        assert((int)to_bci(curIP) == curPC);
+        continue;
+      }
+      bc_which = ref_band_for_op(bc);
+      if (bc_which != null) {
+        entry* ref = bc_which->getRefCommon(bc_which->ix, bc_which->nullOK);
+        CHECK;
+        if (ref == null && bc_which == &bc_classref) {
+          // Shorthand for class self-references.
+          ref = thisClass;
+        }
+        origBC = bc;
+        switch (bc) {
+        case _invokestatic_int:
+          origBC = bc_invokestatic;
+          break;
+        case _invokespecial_int:
+          origBC = bc_invokespecial;
+          break;
+        case bc_ildc:
+        case bc_cldc:
+        case bc_fldc:
+        case bc_sldc:
+        case bc_qldc:
+          origBC = bc_ldc;
+          break;
+        case bc_ildc_w:
+        case bc_cldc_w:
+        case bc_fldc_w:
+        case bc_sldc_w:
+        case bc_qldc_w:
+          origBC = bc_ldc_w;
+          break;
+        case bc_lldc2_w:
+        case bc_dldc2_w:
+          origBC = bc_ldc2_w;
+          break;
+        case bc_new:
+          newClass = ref;
+          break;
+        }
+        wp[-1] = origBC;  // overwrite with origBC
+        if (origBC == bc_ldc) {
+          putu1ref(ref);
+        } else {
+          putref(ref);
+        }
+        if (origBC == bc_multianewarray) {
+          // Copy the trailing byte also.
+          int val = bc_byte.getByte();
+          putu1_fast(val);
+        } else if (origBC == bc_invokeinterface) {
+          int argSize = ref->memberDescr()->descrType()->typeSize();
+          putu1_fast(1 + argSize);
+          putu1_fast(0);
+        } else if (origBC == bc_invokedynamic) {
+          // pad the next two byte
+          putu1_fast(0);
+          putu1_fast(0);
+        }
+        continue;
+      }
+      if (is_local_slot_op(bc)) {
+        int local = bc_local.getInt();
+        if (isWide) {
+          putu2(local);
+          if (bc == bc_iinc) {
+            int iVal = bc_short.getInt();
+            putu2(iVal);
+          }
+        } else {
+          putu1_fast(local);
+          if (bc == bc_iinc) {
+            int iVal = bc_byte.getByte();
+            putu1_fast(iVal);
+          }
+        }
+        continue;
+      }
+      // Random bytecode.  Just copy it.
+      assert(bc < bc_bytecode_limit);
+    }
+  }
+ doneScanningMethod:{}
+  //bcimap.add(curPC);  // PC limit is already also in map, from bc_end_marker
+
+  // Armed with a bcimap, we can now fix up all the labels.
+  for (int i = 0; i < (int)code_fixup_type.size(); i++) {
+    int   type   = code_fixup_type.getByte(i);
+    byte* bp     = wp_at(code_fixup_offset.get(i));
+    int   curIP  = code_fixup_source.get(i);
+    int   destIP = curIP + bc_label.getInt();
+    int   span   = to_bci(destIP) - to_bci(curIP);
+    CHECK;
+    switch (type) {
+    case 2: putu2_at(bp, (ushort)span); break;
+    case 4: putu4_at(bp,         span); break;
+    default: assert(false);
+    }
+  }
+}
+
+inline  // called exactly once => inline
+void unpacker::write_code() {
+  int j;
+
+  int max_stack, max_locals, handler_count, cflags;
+  get_code_header(max_stack, max_locals, handler_count, cflags);
+
+  if (max_stack < 0)      max_stack = code_max_stack.getInt();
+  if (max_locals < 0)     max_locals = code_max_na_locals.getInt();
+  if (handler_count < 0)  handler_count = code_handler_count.getInt();
+
+  int siglen = cur_descr->descrType()->typeSize();
+  CHECK;
+  if ((cur_descr_flags & ACC_STATIC) == 0)  siglen++;
+  max_locals += siglen;
+
+  putu2(max_stack);
+  putu2(max_locals);
+  size_t bcbase = put_empty(4);
+
+  // Write the bytecodes themselves.
+  write_bc_ops();
+  CHECK;
+
+  byte* bcbasewp = wp_at(bcbase);
+  putu4_at(bcbasewp, (int)(wp - (bcbasewp+4)));  // size of code attr
+
+  putu2(handler_count);
+  for (j = 0; j < handler_count; j++) {
+    int bii = code_handler_start_P.getInt();
+    putu2(to_bci(bii));
+    bii    += code_handler_end_PO.getInt();
+    putu2(to_bci(bii));
+    bii    += code_handler_catch_PO.getInt();
+    putu2(to_bci(bii));
+    putref(code_handler_class_RCN.getRefN());
+    CHECK;
+  }
+
+  julong indexBits = cflags;
+  if (cflags < 0) {
+    bool haveLongFlags = attr_defs[ATTR_CONTEXT_CODE].haveLongFlags();
+    indexBits = code_flags_hi.getLong(code_flags_lo, haveLongFlags);
+  }
+  write_attrs(ATTR_CONTEXT_CODE, indexBits);
+}
+
+int unpacker::write_attrs(int attrc, julong indexBits) {
+  CHECK_0;
+  if (indexBits == 0) {
+    // Quick short-circuit.
+    putu2(0);
+    return 0;
+  }
+
+  attr_definitions& ad = attr_defs[attrc];
+
+  int i, j, j2, idx, count;
+
+  int oiCount = 0;
+  if (ad.isPredefined(X_ATTR_OVERFLOW)
+      && (indexBits & ((julong)1<<X_ATTR_OVERFLOW)) != 0) {
+    indexBits -= ((julong)1<<X_ATTR_OVERFLOW);
+    oiCount = ad.xxx_attr_count().getInt();
+  }
+
+  int bitIndexes[X_ATTR_LIMIT_FLAGS_HI];
+  int biCount = 0;
+
+  // Fill bitIndexes with index bits, in order.
+  for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) {
+    if ((indexBits & 1) != 0)
+      bitIndexes[biCount++] = idx;
+  }
+  assert(biCount <= (int)lengthof(bitIndexes));
+
+  // Write a provisional attribute count, perhaps to be corrected later.
+  int naOffset = (int)wpoffset();
+  int na0 = biCount + oiCount;
+  putu2(na0);
+
+  int na = 0;
+  for (i = 0; i < na0; i++) {
+    if (i < biCount)
+      idx = bitIndexes[i];
+    else
+      idx = ad.xxx_attr_indexes().getInt();
+    assert(ad.isIndex(idx));
+    entry* aname = null;
+    entry* ref;  // scratch
+    size_t abase = put_empty(2+4);
+    CHECK_0;
+    if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) {
+      // Switch on the attrc and idx simultaneously.
+      switch (ADH_BYTE(attrc, idx)) {
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS,  X_ATTR_OVERFLOW):
+      case ADH_BYTE(ATTR_CONTEXT_FIELD,  X_ATTR_OVERFLOW):
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_OVERFLOW):
+      case ADH_BYTE(ATTR_CONTEXT_CODE,   X_ATTR_OVERFLOW):
+        // no attribute at all, so back up on this one
+        wp = wp_at(abase);
+        continue;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_ClassFile_version):
+        cur_class_minver = class_ClassFile_version_minor_H.getInt();
+        cur_class_majver = class_ClassFile_version_major_H.getInt();
+        // back up; not a real attribute
+        wp = wp_at(abase);
+        continue;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_InnerClasses):
+        // note the existence of this attr, but save for later
+        if (cur_class_has_local_ics)
+          abort("too many InnerClasses attrs");
+        cur_class_has_local_ics = true;
+        wp = wp_at(abase);
+        continue;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_SourceFile):
+        aname = cp.sym[cpool::s_SourceFile];
+        ref = class_SourceFile_RUN.getRefN();
+        CHECK_0;
+        if (ref == null) {
+          bytes& n = cur_class->ref(0)->value.b;
+          // parse n = (<pkg>/)*<outer>?($<id>)*
+          int pkglen = lastIndexOf(SLASH_MIN,  SLASH_MAX,  n, (int)n.len)+1;
+          bytes prefix = n.slice(pkglen, n.len);
+          for (;;) {
+            // Work backwards, finding all '$', '#', etc.
+            int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, (int)prefix.len);
+            if (dollar < 0)  break;
+            prefix = prefix.slice(0, dollar);
+          }
+          const char* suffix = ".java";
+          int len = (int)(prefix.len + strlen(suffix));
+          bytes name; name.set(T_NEW(byte, add_size(len, 1)), len);
+          name.strcat(prefix).strcat(suffix);
+          ref = cp.ensureUtf8(name);
+        }
+        putref(ref);
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_EnclosingMethod):
+        aname = cp.sym[cpool::s_EnclosingMethod];
+        putref(class_EnclosingMethod_RC.getRefN());
+        CHECK_0;
+        putref(class_EnclosingMethod_RDN.getRefN());
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_FIELD, FIELD_ATTR_ConstantValue):
+        aname = cp.sym[cpool::s_ConstantValue];
+        putref(field_ConstantValue_KQ.getRefUsing(cp.getKQIndex()));
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Code):
+        aname = cp.sym[cpool::s_Code];
+        write_code();
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Exceptions):
+        aname = cp.sym[cpool::s_Exceptions];
+        putu2(count = method_Exceptions_N.getInt());
+        for (j = 0; j < count; j++) {
+          putref(method_Exceptions_RC.getRefN());
+          CHECK_0;
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_MethodParameters):
+        aname = cp.sym[cpool::s_MethodParameters];
+        putu1(count = method_MethodParameters_NB.getByte());
+        for (j = 0; j < count; j++) {
+          putref(method_MethodParameters_name_RUN.getRefN());
+          putu2(method_MethodParameters_flag_FH.getInt());
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_StackMapTable):
+        aname = cp.sym[cpool::s_StackMapTable];
+        // (keep this code aligned with its brother in unpacker::read_attrs)
+        putu2(count = code_StackMapTable_N.getInt());
+        for (j = 0; j < count; j++) {
+          int tag = code_StackMapTable_frame_T.getByte();
+          putu1(tag);
+          if (tag <= 127) {
+            // (64-127)  [(2)]
+            if (tag >= 64)  put_stackmap_type();
+            CHECK_0;
+          } else if (tag <= 251) {
+            // (247)     [(1)(2)]
+            // (248-251) [(1)]
+            if (tag >= 247)  putu2(code_StackMapTable_offset.getInt());
+            if (tag == 247)  put_stackmap_type();
+            CHECK_0;
+          } else if (tag <= 254) {
+            // (252)     [(1)(2)]
+            // (253)     [(1)(2)(2)]
+            // (254)     [(1)(2)(2)(2)]
+            putu2(code_StackMapTable_offset.getInt());
+            CHECK_0;
+            for (int k = (tag - 251); k > 0; k--) {
+              put_stackmap_type();
+              CHECK_0;
+            }
+          } else {
+            // (255)     [(1)NH[(2)]NH[(2)]]
+            putu2(code_StackMapTable_offset.getInt());
+            putu2(j2 = code_StackMapTable_local_N.getInt());
+            while (j2-- > 0) {put_stackmap_type(); CHECK_0;}
+            putu2(j2 = code_StackMapTable_stack_N.getInt());
+            while (j2-- > 0)  {put_stackmap_type(); CHECK_0;}
+          }
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LineNumberTable):
+        aname = cp.sym[cpool::s_LineNumberTable];
+        putu2(count = code_LineNumberTable_N.getInt());
+        for (j = 0; j < count; j++) {
+          putu2(to_bci(code_LineNumberTable_bci_P.getInt()));
+          CHECK_0;
+          putu2(code_LineNumberTable_line.getInt());
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTable):
+        aname = cp.sym[cpool::s_LocalVariableTable];
+        putu2(count = code_LocalVariableTable_N.getInt());
+        for (j = 0; j < count; j++) {
+          int bii = code_LocalVariableTable_bci_P.getInt();
+          int bci = to_bci(bii);
+          CHECK_0;
+          putu2(bci);
+          bii    += code_LocalVariableTable_span_O.getInt();
+          putu2(to_bci(bii) - bci);
+          CHECK_0;
+          putref(code_LocalVariableTable_name_RU.getRefN());
+          CHECK_0;
+          putref(code_LocalVariableTable_type_RS.getRefN());
+          CHECK_0;
+          putu2(code_LocalVariableTable_slot.getInt());
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTypeTable):
+        aname = cp.sym[cpool::s_LocalVariableTypeTable];
+        putu2(count = code_LocalVariableTypeTable_N.getInt());
+        for (j = 0; j < count; j++) {
+          int bii = code_LocalVariableTypeTable_bci_P.getInt();
+          int bci = to_bci(bii);
+          CHECK_0;
+          putu2(bci);
+          bii    += code_LocalVariableTypeTable_span_O.getInt();
+          putu2(to_bci(bii) - bci);
+          CHECK_0;
+          putref(code_LocalVariableTypeTable_name_RU.getRefN());
+          CHECK_0;
+          putref(code_LocalVariableTypeTable_type_RS.getRefN());
+          CHECK_0;
+          putu2(code_LocalVariableTypeTable_slot.getInt());
+        }
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Signature):
+        aname = cp.sym[cpool::s_Signature];
+        putref(class_Signature_RS.getRefN());
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Signature):
+        aname = cp.sym[cpool::s_Signature];
+        putref(field_Signature_RS.getRefN());
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Signature):
+        aname = cp.sym[cpool::s_Signature];
+        putref(method_Signature_RS.getRefN());
+        break;
+
+      case ADH_BYTE(ATTR_CONTEXT_CLASS,  X_ATTR_Deprecated):
+      case ADH_BYTE(ATTR_CONTEXT_FIELD,  X_ATTR_Deprecated):
+      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Deprecated):
+        aname = cp.sym[cpool::s_Deprecated];
+        // no data
+        break;
+      }
+    }
+    CHECK_0;
+    if (aname == null) {
+      // Unparse a compressor-defined attribute.
+      layout_definition* lo = ad.getLayout(idx);
+      if (lo == null) {
+        abort("bad layout index");
+        break;
+      }
+      assert((int)lo->idx == idx);
+      aname = lo->nameEntry;
+      if (aname == null) {
+        bytes nameb; nameb.set(lo->name);
+        aname = cp.ensureUtf8(nameb);
+        // Cache the name entry for next time.
+        lo->nameEntry = aname;
+      }
+      // Execute all the layout elements.
+      band** bands = lo->bands();
+      if (lo->hasCallables()) {
+        band& cble = *bands[0];
+        assert(cble.le_kind == EK_CBLE);
+        bands = cble.le_body;
+      }
+      putlayout(bands);
+    }
+
+    if (aname == null)
+      abort("bad attribute index");
+    CHECK_0;
+
+    byte* wp1 = wp;
+    wp = wp_at(abase);
+
+    // DTRT if this attr is on the strip-list.
+    // (Note that we emptied the data out of the band first.)
+    if (ad.strip_names.contains(aname)) {
+      continue;
+    }
+
+    // patch the name and length
+    putref(aname);
+    putu4((int)(wp1 - (wp+4)));  // put the attr size
+    wp = wp1;
+    na++;  // count the attrs actually written
+  }
+
+  if (na != na0)
+    // Refresh changed count.
+    putu2_at(wp_at(naOffset), na);
+  return na;
+}
+
+void unpacker::write_members(int num, int attrc) {
+  CHECK;
+  attr_definitions& ad = attr_defs[attrc];
+  band& member_flags_hi = ad.xxx_flags_hi();
+  band& member_flags_lo = ad.xxx_flags_lo();
+  band& member_descr = (&member_flags_hi)[e_field_descr-e_field_flags_hi];
+  assert(endsWith(member_descr.name, "_descr"));
+  assert(endsWith(member_flags_lo.name, "_flags_lo"));
+  assert(endsWith(member_flags_lo.name, "_flags_lo"));
+  bool haveLongFlags = ad.haveLongFlags();
+
+  putu2(num);
+  julong indexMask = attr_defs[attrc].flagIndexMask();
+  for (int i = 0; i < num; i++) {
+    julong mflags = member_flags_hi.getLong(member_flags_lo, haveLongFlags);
+    entry* mdescr = member_descr.getRef();
+    cur_descr = mdescr;
+    putu2(cur_descr_flags = (ushort)(mflags & ~indexMask));
+    CHECK;
+    putref(mdescr->descrName());
+    putref(mdescr->descrType());
+    write_attrs(attrc, (mflags & indexMask));
+    CHECK;
+  }
+  cur_descr = null;
+}
+
+extern "C"
+int raw_address_cmp(const void* p1p, const void* p2p) {
+  void* p1 = *(void**) p1p;
+  void* p2 = *(void**) p2p;
+  return (p1 > p2)? 1: (p1 < p2)? -1: 0;
+}
+
+/*
+ * writes the InnerClass attributes and returns the updated attribute
+ */
+int  unpacker::write_ics(int naOffset, int na) {
+#ifdef ASSERT
+  for (int i = 0; i < ic_count; i++) {
+    assert(!ics[i].requested);
+  }
+#endif
+  // First, consult the global table and the local constant pool,
+  // and decide on the globally implied inner classes.
+  // (Note that we read the cpool's outputIndex fields, but we
+  // do not yet write them, since the local IC attribute might
+  // reverse a global decision to declare an IC.)
+  assert(requested_ics.length() == 0);  // must start out empty
+  // Always include all members of the current class.
+  for (inner_class* child = cp.getFirstChildIC(cur_class);
+       child != null;
+       child = cp.getNextChildIC(child)) {
+    child->requested = true;
+    requested_ics.add(child);
+  }
+  // And, for each inner class mentioned in the constant pool,
+  // include it and all its outers.
+  int    noes =           cp.outputEntries.length();
+  entry** oes = (entry**) cp.outputEntries.base();
+  for (int i = 0; i < noes; i++) {
+    entry& e = *oes[i];
+    if (e.tag != CONSTANT_Class)  continue;  // wrong sort
+    for (inner_class* ic = cp.getIC(&e);
+         ic != null;
+         ic = cp.getIC(ic->outer)) {
+      if (ic->requested)  break;  // already processed
+      ic->requested = true;
+      requested_ics.add(ic);
+    }
+  }
+  int local_ics = requested_ics.length();
+  // Second, consult a local attribute (if any) and adjust the global set.
+  inner_class* extra_ics = null;
+  int      num_extra_ics = 0;
+  if (cur_class_has_local_ics) {
+    // adjust the set of ICs by symmetric set difference w/ the locals
+    num_extra_ics = class_InnerClasses_N.getInt();
+    if (num_extra_ics == 0) {
+      // Explicit zero count has an irregular meaning:  It deletes the attr.
+      local_ics = 0;  // (short-circuit all tests of requested bits)
+    } else {
+      extra_ics = T_NEW(inner_class, num_extra_ics);
+      // Note:  extra_ics will be freed up by next call to get_next_file().
+    }
+  }
+  for (int i = 0; i < num_extra_ics; i++) {
+    inner_class& extra_ic = extra_ics[i];
+    extra_ic.inner = class_InnerClasses_RC.getRef();
+    CHECK_0;
+    // Find the corresponding equivalent global IC:
+    inner_class* global_ic = cp.getIC(extra_ic.inner);
+    int flags = class_InnerClasses_F.getInt();
+    if (flags == 0) {
+      // The extra IC is simply a copy of a global IC.
+      if (global_ic == null) {
+        abort("bad reference to inner class");
+        break;
+      }
+      extra_ic = (*global_ic);  // fill in rest of fields
+    } else {
+      flags &= ~ACC_IC_LONG_FORM;  // clear high bit if set to get clean zero
+      extra_ic.flags = flags;
+      extra_ic.outer = class_InnerClasses_outer_RCN.getRefN();
+      CHECK_0;
+      extra_ic.name  = class_InnerClasses_name_RUN.getRefN();
+      CHECK_0;
+      // Detect if this is an exact copy of the global tuple.
+      if (global_ic != null) {
+        if (global_ic->flags != extra_ic.flags ||
+            global_ic->outer != extra_ic.outer ||
+            global_ic->name  != extra_ic.name) {
+          global_ic = null;  // not really the same, so break the link
+        }
+      }
+    }
+    if (global_ic != null && global_ic->requested) {
+      // This local repetition reverses the globally implied request.
+      global_ic->requested = false;
+      extra_ic.requested = false;
+      local_ics -= 1;
+    } else {
+      // The global either does not exist, or is not yet requested.
+      extra_ic.requested = true;
+      local_ics += 1;
+    }
+  }
+  // Finally, if there are any that survived, put them into an attribute.
+  // (Note that a zero-count attribute is always deleted.)
+  // The putref calls below will tell the constant pool to add any
+  // necessary local CP references to support the InnerClasses attribute.
+  // This step must be the last round of additions to the local CP.
+  if (local_ics > 0) {
+    // append the new attribute:
+    putref(cp.sym[cpool::s_InnerClasses]);
+    putu4(2 + 2*4*local_ics);
+    putu2(local_ics);
+    PTRLIST_QSORT(requested_ics, raw_address_cmp);
+    int num_global_ics = requested_ics.length();
+    for (int i = -num_global_ics; i < num_extra_ics; i++) {
+      inner_class* ic;
+      if (i < 0)
+        ic = (inner_class*) requested_ics.get(num_global_ics+i);
+      else
+        ic = &extra_ics[i];
+      if (ic->requested) {
+        putref(ic->inner);
+        putref(ic->outer);
+        putref(ic->name);
+        putu2(ic->flags);
+        NOT_PRODUCT(local_ics--);
+      }
+    }
+    assert(local_ics == 0);           // must balance
+    putu2_at(wp_at(naOffset), ++na);  // increment class attr count
+  }
+
+  // Tidy up global 'requested' bits:
+  for (int i = requested_ics.length(); --i >= 0; ) {
+    inner_class* ic = (inner_class*) requested_ics.get(i);
+    ic->requested = false;
+  }
+  requested_ics.empty();
+  return na;
+}
+
+/*
+ * Writes the BootstrapMethods attribute and returns the updated attribute count
+ */
+int unpacker::write_bsms(int naOffset, int na) {
+  cur_class_local_bsm_count = cp.requested_bsms.length();
+  if (cur_class_local_bsm_count > 0) {
+    int    noes =           cp.outputEntries.length();
+    entry** oes = (entry**) cp.outputEntries.base();
+    PTRLIST_QSORT(cp.requested_bsms, outputEntry_cmp);
+    // append the BootstrapMethods attribute (after the InnerClasses attr):
+    putref(cp.sym[cpool::s_BootstrapMethods]);
+    // make a note of the offset, for lazy patching
+    int sizeOffset = (int)wpoffset();
+    putu4(-99);  // attr size will be patched
+    putu2(cur_class_local_bsm_count);
+    int written_bsms = 0;
+    for (int i = 0 ; i < cur_class_local_bsm_count ; i++) {
+      entry* e = (entry*)cp.requested_bsms.get(i);
+      assert(e->outputIndex != REQUESTED_NONE);
+      // output index is the index within the array
+      e->outputIndex = i;
+      putref(e->refs[0]);  // bsm
+      putu2(e->nrefs-1);  // number of args after bsm
+      for (int j = 1; j < e->nrefs; j++) {
+        putref(e->refs[j]);
+      }
+      written_bsms += 1;
+    }
+    assert(written_bsms == cur_class_local_bsm_count);  // else insane
+    byte* sizewp = wp_at(sizeOffset);
+    putu4_at(sizewp, (int)(wp - (sizewp+4)));  // size of code attr
+    putu2_at(wp_at(naOffset), ++na);  // increment class attr count
+  }
+  return na;
+}
+
+void unpacker::write_classfile_tail() {
+
+  cur_classfile_tail.empty();
+  set_output(&cur_classfile_tail);
+
+  int i, num;
+
+  attr_definitions& ad = attr_defs[ATTR_CONTEXT_CLASS];
+
+  bool haveLongFlags = ad.haveLongFlags();
+  julong kflags = class_flags_hi.getLong(class_flags_lo, haveLongFlags);
+  julong indexMask = ad.flagIndexMask();
+
+  cur_class = class_this.getRef();
+  CHECK;
+  cur_super = class_super.getRef();
+  CHECK;
+
+  if (cur_super == cur_class)  cur_super = null;
+  // special representation for java/lang/Object
+
+  putu2((ushort)(kflags & ~indexMask));
+  putref(cur_class);
+  putref(cur_super);
+
+  putu2(num = class_interface_count.getInt());
+  for (i = 0; i < num; i++) {
+    putref(class_interface.getRef());
+    CHECK;
+  }
+
+  write_members(class_field_count.getInt(),  ATTR_CONTEXT_FIELD);
+  write_members(class_method_count.getInt(), ATTR_CONTEXT_METHOD);
+  CHECK;
+
+  cur_class_has_local_ics = false;  // may be set true by write_attrs
+
+  int naOffset = (int)wpoffset();   // note the attr count location
+  int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask));
+  CHECK;
+
+  na = write_bsms(naOffset, na);
+  CHECK;
+
+  // choose which inner classes (if any) pertain to k:
+  na = write_ics(naOffset, na);
+  CHECK;
+
+  close_output();
+  cp.computeOutputIndexes();
+
+  // rewrite CP references in the tail
+  int nextref = 0;
+  for (i = 0; i < (int)class_fixup_type.size(); i++) {
+    int    type = class_fixup_type.getByte(i);
+    byte*  fixp = wp_at(class_fixup_offset.get(i));
+    entry* e    = (entry*)class_fixup_ref.get(nextref++);
+    int    idx  = e->getOutputIndex();
+    switch (type) {
+    case 1:  putu1_at(fixp, idx);  break;
+    case 2:  putu2_at(fixp, idx);  break;
+    default: assert(false);  // should not reach here
+    }
+  }
+  CHECK;
+}
+
+void unpacker::write_classfile_head() {
+  cur_classfile_head.empty();
+  set_output(&cur_classfile_head);
+
+  putu4(JAVA_MAGIC);
+  putu2(cur_class_minver);
+  putu2(cur_class_majver);
+  putu2(cp.outputIndexLimit);
+
+  int checkIndex = 1;
+  int    noes =           cp.outputEntries.length();
+  entry** oes = (entry**) cp.outputEntries.base();
+  for (int i = 0; i < noes; i++) {
+    entry& e = *oes[i];
+    assert(e.getOutputIndex() == checkIndex++);
+    byte tag = e.tag;
+    assert(tag != CONSTANT_Signature);
+    putu1(tag);
+    switch (tag) {
+    case CONSTANT_Utf8:
+      putu2((int)e.value.b.len);
+      put_bytes(e.value.b);
+      break;
+    case CONSTANT_Integer:
+    case CONSTANT_Float:
+      putu4(e.value.i);
+      break;
+    case CONSTANT_Long:
+    case CONSTANT_Double:
+      putu8(e.value.l);
+      assert(checkIndex++);
+      break;
+    case CONSTANT_Class:
+    case CONSTANT_String:
+      // just write the ref
+      putu2(e.refs[0]->getOutputIndex());
+      break;
+    case CONSTANT_Fieldref:
+    case CONSTANT_Methodref:
+    case CONSTANT_InterfaceMethodref:
+    case CONSTANT_NameandType:
+    case CONSTANT_InvokeDynamic:
+      putu2(e.refs[0]->getOutputIndex());
+      putu2(e.refs[1]->getOutputIndex());
+      break;
+    case CONSTANT_MethodHandle:
+        putu1(e.value.i);
+        putu2(e.refs[0]->getOutputIndex());
+        break;
+    case CONSTANT_MethodType:
+      putu2(e.refs[0]->getOutputIndex());
+      break;
+    case CONSTANT_BootstrapMethod: // should not happen
+    default:
+      abort(ERROR_INTERNAL);
+    }
+  }
+
+#ifndef PRODUCT
+  total_cp_size[0] += cp.outputIndexLimit;
+  total_cp_size[1] += (int)cur_classfile_head.size();
+#endif
+  close_output();
+}
+
+unpacker::file* unpacker::get_next_file() {
+  CHECK_0;
+  free_temps();
+  if (files_remaining == 0) {
+    // Leave a clue that we're exhausted.
+    cur_file.name = null;
+    cur_file.size = null;
+    if (archive_size != 0) {
+      julong predicted_size = unsized_bytes_read + archive_size;
+      if (predicted_size != bytes_read)
+        abort("archive header had incorrect size");
+    }
+    return null;
+  }
+  files_remaining -= 1;
+  assert(files_written < file_count || classes_written < class_count);
+  cur_file.name = "";
+  cur_file.size = 0;
+  cur_file.modtime = default_file_modtime;
+  cur_file.options = default_file_options;
+  cur_file.data[0].set(null, 0);
+  cur_file.data[1].set(null, 0);
+  if (files_written < file_count) {
+    entry* e = file_name.getRef();
+    CHECK_0;
+    cur_file.name = e->utf8String();
+    CHECK_0;
+    bool haveLongSize = (testBit(archive_options, AO_HAVE_FILE_SIZE_HI));
+    cur_file.size = file_size_hi.getLong(file_size_lo, haveLongSize);
+    if (testBit(archive_options, AO_HAVE_FILE_MODTIME))
+      cur_file.modtime += file_modtime.getInt();  //relative to archive modtime
+    if (testBit(archive_options, AO_HAVE_FILE_OPTIONS))
+      cur_file.options |= file_options.getInt() & ~suppress_file_options;
+  } else if (classes_written < class_count) {
+    // there is a class for a missing file record
+    cur_file.options |= FO_IS_CLASS_STUB;
+  }
+  if ((cur_file.options & FO_IS_CLASS_STUB) != 0) {
+    assert(classes_written < class_count);
+    classes_written += 1;
+    if (cur_file.size != 0) {
+      abort("class file size transmitted");
+      return null;
+    }
+    reset_cur_classfile();
+
+    // write the meat of the classfile:
+    write_classfile_tail();
+    cur_file.data[1] = cur_classfile_tail.b;
+    CHECK_0;
+
+    // write the CP of the classfile, second:
+    write_classfile_head();
+    cur_file.data[0] = cur_classfile_head.b;
+    CHECK_0;
+
+    cur_file.size += cur_file.data[0].len;
+    cur_file.size += cur_file.data[1].len;
+    if (cur_file.name[0] == '\0') {
+      bytes& prefix = cur_class->ref(0)->value.b;
+      const char* suffix = ".class";
+      int len = (int)(prefix.len + strlen(suffix));
+      bytes name; name.set(T_NEW(byte, add_size(len, 1)), len);
+      cur_file.name = name.strcat(prefix).strcat(suffix).strval();
+    }
+  } else {
+    // If there is buffered file data, produce a pointer to it.
+    if (cur_file.size != (size_t) cur_file.size) {
+      // Silly size specified.
+      abort("resource file too large");
+      return null;
+    }
+    size_t rpleft = input_remaining();
+    if (rpleft > 0) {
+      if (rpleft > cur_file.size)
+        rpleft = (size_t) cur_file.size;
+      cur_file.data[0].set(rp, rpleft);
+      rp += rpleft;
+    }
+    if (rpleft < cur_file.size) {
+      // Caller must read the rest.
+      size_t fleft = (size_t)cur_file.size - rpleft;
+      bytes_read += fleft;  // Credit it to the overall archive size.
+    }
+  }
+  CHECK_0;
+  bytes_written += cur_file.size;
+  files_written += 1;
+  return &cur_file;
+}
+
+// Write a file to jarout.
+void unpacker::write_file_to_jar(unpacker::file* f) {
+  size_t htsize = f->data[0].len + f->data[1].len;
+  julong fsize = f->size;
+#ifndef PRODUCT
+  if (nowrite NOT_PRODUCT(|| skipfiles-- > 0)) {
+    PRINTCR((2,"would write %d bytes to %s", (int) fsize, f->name));
+    return;
+  }
+#endif
+  if (htsize == fsize) {
+    jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime,
+                        f->data[0], f->data[1]);
+  } else {
+    assert(input_remaining() == 0);
+    bytes part1, part2;
+    part1.len = f->data[0].len;
+    part1.set(T_NEW(byte, part1.len), part1.len);
+    part1.copyFrom(f->data[0]);
+    assert(f->data[1].len == 0);
+    part2.set(null, 0);
+    size_t fleft = (size_t) fsize - part1.len;
+    assert(bytes_read > fleft);  // part2 already credited by get_next_file
+    bytes_read -= fleft;
+    if (fleft > 0) {
+      // Must read some more.
+      if (live_input) {
+        // Stop using the input buffer.  Make a new one:
+        if (free_input)  input.free();
+        input.init(fleft > (1<<12) ? fleft : (1<<12));
+        free_input = true;
+        live_input = false;
+      } else {
+        // Make it large enough.
+        assert(free_input);  // must be reallocable
+        input.ensureSize(fleft);
+      }
+      rplimit = rp = input.base();
+      CHECK;
+      input.setLimit(rp + fleft);
+      if (!ensure_input(fleft))
+        abort("EOF reading resource file");
+      part2.ptr = input_scan();
+      part2.len = input_remaining();
+      rplimit = rp = input.base();
+    }
+    jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime,
+                        part1, part2);
+  }
+  if (verbose >= 3) {
+    fprintf(errstrm, "Wrote "
+                     LONG_LONG_FORMAT " bytes to: %s\n", fsize, f->name);
+  }
+}
+
+// Redirect the stdio to the specified file in the unpack.log.file option
+void unpacker::redirect_stdio() {
+  if (log_file == null) {
+    log_file = LOGFILE_STDOUT;
+  }
+  if (log_file == errstrm_name)
+    // Nothing more to be done.
+    return;
+  errstrm_name = log_file;
+  if (strcmp(log_file, LOGFILE_STDERR) == 0) {
+    errstrm = stderr;
+    return;
+  } else if (strcmp(log_file, LOGFILE_STDOUT) == 0) {
+    errstrm = stdout;
+    return;
+  } else if (log_file[0] != '\0' && (errstrm = fopen(log_file,"a+")) != NULL) {
+    return;
+  } else {
+    fprintf(stderr, "Can not open log file %s\n", log_file);
+    // Last resort
+    // (Do not use stdout, since it might be jarout->jarfp.)
+    errstrm = stderr;
+    log_file = errstrm_name = LOGFILE_STDERR;
+  }
+}
+
+#ifndef PRODUCT
+int unpacker::printcr_if_verbose(int level, const char* fmt ...) {
+  if (verbose < level)  return 0;
+  va_list vl;
+  va_start(vl, fmt);
+  char fmtbuf[300];
+  strcpy(fmtbuf+100, fmt);
+  strcat(fmtbuf+100, "\n");
+  char* fmt2 = fmtbuf+100;
+  while (level-- > 0)  *--fmt2 = ' ';
+  vfprintf(errstrm, fmt2, vl);
+  return 1;  // for ?: usage
+}
+#endif
+
+void unpacker::abort(const char* message) {
+  if (message == null)  message = "error unpacking archive";
+#ifdef UNPACK_JNI
+  if (message[0] == '@') {  // secret convention for sprintf
+     bytes saved;
+     saved.saveFrom(message+1);
+     mallocs.add(message = saved.strval());
+   }
+  abort_message = message;
+  return;
+#else
+  if (message[0] == '@')  ++message;
+  fprintf(errstrm, "%s\n", message);
+#ifndef PRODUCT
+  fflush(errstrm);
+  ::abort();
+#else
+  exit(-1);
+#endif
+#endif // JNI
+}
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/unpack.h b/jdk/src/jdk.pack/share/native/common-unpack/unpack.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/unpack.h
rename to jdk/src/jdk.pack/share/native/common-unpack/unpack.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp b/jdk/src/jdk.pack/share/native/common-unpack/utils.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp
rename to jdk/src/jdk.pack/share/native/common-unpack/utils.cpp
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/utils.h b/jdk/src/jdk.pack/share/native/common-unpack/utils.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/utils.h
rename to jdk/src/jdk.pack/share/native/common-unpack/utils.h
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp b/jdk/src/jdk.pack/share/native/common-unpack/zip.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp
rename to jdk/src/jdk.pack/share/native/common-unpack/zip.cpp
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/zip.h b/jdk/src/jdk.pack/share/native/common-unpack/zip.h
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/common-unpack/zip.h
rename to jdk/src/jdk.pack/share/native/common-unpack/zip.h
diff --git a/jdk/src/jdk.pack200/share/native/libunpack/jni.cpp b/jdk/src/jdk.pack/share/native/libunpack/jni.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/libunpack/jni.cpp
rename to jdk/src/jdk.pack/share/native/libunpack/jni.cpp
diff --git a/jdk/src/jdk.pack200/share/native/unpack200/main.cpp b/jdk/src/jdk.pack/share/native/unpack200/main.cpp
similarity index 100%
rename from jdk/src/jdk.pack200/share/native/unpack200/main.cpp
rename to jdk/src/jdk.pack/share/native/unpack200/main.cpp
diff --git a/jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest b/jdk/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest
similarity index 100%
rename from jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest
rename to jdk/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest
diff --git a/jdk/src/jdk.pack200/share/classes/module-info.java b/jdk/src/jdk.pack200/share/classes/module-info.java
deleted file mode 100644
index ffca94f..0000000
--- a/jdk/src/jdk.pack200/share/classes/module-info.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module jdk.pack200 {
-}
-
diff --git a/jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp b/jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp
deleted file mode 100644
index 435d5dd..0000000
--- a/jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp
+++ /dev/null
@@ -1,5238 +0,0 @@
-/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// -*- C++ -*-
-// Program for unpacking specially compressed Java packages.
-// John R. Rose
-
-/*
- * When compiling for a 64bit LP64 system (longs and pointers being 64bits),
- *    the printf format %ld is correct and use of %lld will cause warning
- *    errors from some compilers (gcc/g++).
- * _LP64 can be explicitly set (used on Linux).
- * Should be checking for the Visual C++ since the _LP64 is set on the 64-bit
- * systems but the correct format prefix for 64-bit integers is ll.
- * Solaris compilers will define __sparcv9 or __x86_64 on 64bit compilations.
- */
-#if !defined (_MSC_VER) && \
-    (defined(_LP64) || defined(__sparcv9) || defined(__x86_64))
-  #define LONG_LONG_FORMAT "%ld"
-  #define LONG_LONG_HEX_FORMAT "%lx"
-#else
-  #define LONG_LONG_FORMAT "%lld"
-  #define LONG_LONG_HEX_FORMAT "%016llx"
-#endif
-
-#include <sys/types.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include <limits.h>
-#include <time.h>
-
-
-
-
-#include "defines.h"
-#include "bytes.h"
-#include "utils.h"
-#include "coding.h"
-#include "bands.h"
-
-#include "constants.h"
-
-#include "zip.h"
-
-#include "unpack.h"
-
-
-// tags, in canonical order:
-static const byte TAGS_IN_ORDER[] = {
-  CONSTANT_Utf8,
-  CONSTANT_Integer,
-  CONSTANT_Float,
-  CONSTANT_Long,
-  CONSTANT_Double,
-  CONSTANT_String,
-  CONSTANT_Class,
-  CONSTANT_Signature,
-  CONSTANT_NameandType,
-  CONSTANT_Fieldref,
-  CONSTANT_Methodref,
-  CONSTANT_InterfaceMethodref,
-  // constants defined as of JDK 7
-  CONSTANT_MethodHandle,
-  CONSTANT_MethodType,
-  CONSTANT_BootstrapMethod,
-  CONSTANT_InvokeDynamic
-};
-#define N_TAGS_IN_ORDER (sizeof TAGS_IN_ORDER)
-
-#ifndef PRODUCT
-static const char* TAG_NAME[] = {
-  "*None",
-  "Utf8",
-  "*Unicode",
-  "Integer",
-  "Float",
-  "Long",
-  "Double",
-  "Class",
-  "String",
-  "Fieldref",
-  "Methodref",
-  "InterfaceMethodref",
-  "NameandType",
-  "*Signature",
-  "unused14",
-  "MethodHandle",
-  "MethodType",
-  "*BootstrapMethod",
-  "InvokeDynamic",
-  0
-};
-
-static const char* ATTR_CONTEXT_NAME[] = {  // match ATTR_CONTEXT_NAME, etc.
-  "class", "field", "method", "code"
-};
-
-#else
-
-#define ATTR_CONTEXT_NAME ((const char**)null)
-
-#endif
-
-// Note that REQUESTED_LDC comes first, then the normal REQUESTED,
-// in the regular constant pool.
-enum { REQUESTED_NONE = -1,
-       // The codes below REQUESTED_NONE are in constant pool output order,
-       // for the sake of outputEntry_cmp:
-       REQUESTED_LDC = -99, REQUESTED
-};
-
-#define NO_INORD ((uint)-1)
-
-struct entry {
-  byte tag;
-
-  #if 0
-  byte bits;
-  enum {
-    //EB_EXTRA = 1,
-    EB_SUPER = 2
-  };
-  #endif
-  unsigned short nrefs;  // pack w/ tag
-
-  int  outputIndex;
-  uint inord;   // &cp.entries[cp.tag_base[this->tag]+this->inord] == this
-
-  entry* *refs;
-
-  // put last to pack best
-  union {
-    bytes b;
-    int i;
-    jlong l;
-  } value;
-
-  void requestOutputIndex(cpool& cp, int req = REQUESTED);
-  int getOutputIndex() {
-    assert(outputIndex > REQUESTED_NONE);
-    return outputIndex;
-  }
-
-  entry* ref(int refnum) {
-    assert((uint)refnum < nrefs);
-    return refs[refnum];
-  }
-
-  const char* utf8String() {
-    assert(tagMatches(CONSTANT_Utf8));
-    if (value.b.len != strlen((const char*)value.b.ptr)) {
-      unpack_abort("bad utf8 encoding");
-      // and fall through
-    }
-    return (const char*)value.b.ptr;
-  }
-
-  entry* className() {
-    assert(tagMatches(CONSTANT_Class));
-    return ref(0);
-  }
-
-  entry* memberClass() {
-    assert(tagMatches(CONSTANT_AnyMember));
-    return ref(0);
-  }
-
-  entry* memberDescr() {
-    assert(tagMatches(CONSTANT_AnyMember));
-    return ref(1);
-  }
-
-  entry* descrName() {
-    assert(tagMatches(CONSTANT_NameandType));
-    return ref(0);
-  }
-
-  entry* descrType() {
-    assert(tagMatches(CONSTANT_NameandType));
-    return ref(1);
-  }
-
-  int typeSize();
-
-  bytes& asUtf8();
-  int    asInteger() { assert(tag == CONSTANT_Integer); return value.i; }
-
-  bool isUtf8(bytes& b) { return tagMatches(CONSTANT_Utf8) && value.b.equals(b); }
-
-  bool isDoubleWord() { return tag == CONSTANT_Double || tag == CONSTANT_Long; }
-
-  bool tagMatches(byte tag2) {
-    return (tag2 == tag)
-      || (tag2 == CONSTANT_Utf8 && tag == CONSTANT_Signature)
-      #ifndef PRODUCT
-      || (tag2 == CONSTANT_FieldSpecific
-          && tag >= CONSTANT_Integer && tag <= CONSTANT_String && tag != CONSTANT_Class)
-      || (tag2 == CONSTANT_AnyMember
-          && tag >= CONSTANT_Fieldref && tag <= CONSTANT_InterfaceMethodref)
-      #endif
-      ;
-  }
-
-#ifdef PRODUCT
-  const char* string() { return NULL; }
-#else
-  const char* string();  // see far below
-#endif
-};
-
-entry* cpindex::get(uint i) {
-  if (i >= len)
-    return null;
-  else if (base1 != null)
-    // primary index
-    return &base1[i];
-  else
-    // secondary index
-    return base2[i];
-}
-
-inline bytes& entry::asUtf8() {
-  assert(tagMatches(CONSTANT_Utf8));
-  return value.b;
-}
-
-int entry::typeSize() {
-  assert(tagMatches(CONSTANT_Utf8));
-  const char* sigp = (char*) value.b.ptr;
-  switch (*sigp) {
-  case '(': sigp++; break;  // skip opening '('
-  case 'D':
-  case 'J': return 2; // double field
-  default:  return 1; // field
-  }
-  int siglen = 0;
-  for (;;) {
-    int ch = *sigp++;
-    switch (ch) {
-    case 'D': case 'J':
-      siglen += 1;
-      break;
-    case '[':
-      // Skip rest of array info.
-      while (ch == '[') { ch = *sigp++; }
-      if (ch != 'L')  break;
-      // else fall through
-    case 'L':
-      sigp = strchr(sigp, ';');
-      if (sigp == null) {
-          unpack_abort("bad data");
-          return 0;
-      }
-      sigp += 1;
-      break;
-    case ')':  // closing ')'
-      return siglen;
-    }
-    siglen += 1;
-  }
-}
-
-inline cpindex* cpool::getFieldIndex(entry* classRef) {
-  if (classRef == NULL) { abort("missing class reference"); return NULL; }
-  assert(classRef->tagMatches(CONSTANT_Class));
-  assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]);
-  return &member_indexes[classRef->inord*2+0];
-}
-inline cpindex* cpool::getMethodIndex(entry* classRef) {
-  if (classRef == NULL) { abort("missing class reference"); return NULL; }
-  assert(classRef->tagMatches(CONSTANT_Class));
-  assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]);
-  return &member_indexes[classRef->inord*2+1];
-}
-
-struct inner_class {
-  entry* inner;
-  entry* outer;
-  entry* name;
-  int    flags;
-  inner_class* next_sibling;
-  bool   requested;
-};
-
-// Here is where everything gets deallocated:
-void unpacker::free() {
-  int i;
-  assert(jniobj == null); // caller resp.
-  assert(infileptr == null);  // caller resp.
-  if (jarout != null)  jarout->reset();
-  if (gzin != null)    { gzin->free(); gzin = null; }
-  if (free_input)  input.free();
-  // free everybody ever allocated with U_NEW or (recently) with T_NEW
-  assert(smallbuf.base()  == null || mallocs.contains(smallbuf.base()));
-  assert(tsmallbuf.base() == null || tmallocs.contains(tsmallbuf.base()));
-  mallocs.freeAll();
-  tmallocs.freeAll();
-  smallbuf.init();
-  tsmallbuf.init();
-  bcimap.free();
-  class_fixup_type.free();
-  class_fixup_offset.free();
-  class_fixup_ref.free();
-  code_fixup_type.free();
-  code_fixup_offset.free();
-  code_fixup_source.free();
-  requested_ics.free();
-  cp.requested_bsms.free();
-  cur_classfile_head.free();
-  cur_classfile_tail.free();
-  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++)
-    attr_defs[i].free();
-
-  // free CP state
-  cp.outputEntries.free();
-  for (i = 0; i < CONSTANT_Limit; i++)
-    cp.tag_extras[i].free();
-}
-
-// input handling
-// Attempts to advance rplimit so that (rplimit-rp) is at least 'more'.
-// Will eagerly read ahead by larger chunks, if possible.
-// Returns false if (rplimit-rp) is not at least 'more',
-// unless rplimit hits input.limit().
-bool unpacker::ensure_input(jlong more) {
-  julong want = more - input_remaining();
-  if ((jlong)want <= 0)          return true;  // it's already in the buffer
-  if (rplimit == input.limit())  return true;  // not expecting any more
-
-  if (read_input_fn == null) {
-    // assume it is already all there
-    bytes_read += input.limit() - rplimit;
-    rplimit = input.limit();
-    return true;
-  }
-  CHECK_0;
-
-  julong remaining = (input.limit() - rplimit);  // how much left to read?
-  byte* rpgoal = (want >= remaining)? input.limit(): rplimit + (size_t)want;
-  enum { CHUNK_SIZE = (1<<14) };
-  julong fetch = want;
-  if (fetch < CHUNK_SIZE)
-    fetch = CHUNK_SIZE;
-  if (fetch > remaining*3/4)
-    fetch = remaining;
-  // Try to fetch at least "more" bytes.
-  while ((jlong)fetch > 0) {
-    jlong nr = (*read_input_fn)(this, rplimit, fetch, remaining);
-    if (nr <= 0) {
-      return (rplimit >= rpgoal);
-    }
-    remaining -= nr;
-    rplimit += nr;
-    fetch -= nr;
-    bytes_read += nr;
-    assert(remaining == (julong)(input.limit() - rplimit));
-  }
-  return true;
-}
-
-// output handling
-
-fillbytes* unpacker::close_output(fillbytes* which) {
-  assert(wp != null);
-  if (which == null) {
-    if (wpbase == cur_classfile_head.base()) {
-      which = &cur_classfile_head;
-    } else {
-      which = &cur_classfile_tail;
-    }
-  }
-  assert(wpbase  == which->base());
-  assert(wplimit == which->end());
-  which->setLimit(wp);
-  wp      = null;
-  wplimit = null;
-  //wpbase = null;
-  return which;
-}
-
-//maybe_inline
-void unpacker::ensure_put_space(size_t size) {
-  if (wp + size <= wplimit)  return;
-  // Determine which segment needs expanding.
-  fillbytes* which = close_output();
-  byte* wp0 = which->grow(size);
-  wpbase  = which->base();
-  wplimit = which->end();
-  wp = wp0;
-}
-
-maybe_inline
-byte* unpacker::put_space(size_t size) {
-  byte* wp0 = wp;
-  byte* wp1 = wp0 + size;
-  if (wp1 > wplimit) {
-    ensure_put_space(size);
-    wp0 = wp;
-    wp1 = wp0 + size;
-  }
-  wp = wp1;
-  return wp0;
-}
-
-maybe_inline
-void unpacker::putu2_at(byte* wp, int n) {
-  if (n != (unsigned short)n) {
-    unpack_abort(ERROR_OVERFLOW);
-    return;
-  }
-  wp[0] = (n) >> 8;
-  wp[1] = (n) >> 0;
-}
-
-maybe_inline
-void unpacker::putu4_at(byte* wp, int n) {
-  wp[0] = (n) >> 24;
-  wp[1] = (n) >> 16;
-  wp[2] = (n) >> 8;
-  wp[3] = (n) >> 0;
-}
-
-maybe_inline
-void unpacker::putu8_at(byte* wp, jlong n) {
-  putu4_at(wp+0, (int)((julong)n >> 32));
-  putu4_at(wp+4, (int)((julong)n >> 0));
-}
-
-maybe_inline
-void unpacker::putu2(int n) {
-  putu2_at(put_space(2), n);
-}
-
-maybe_inline
-void unpacker::putu4(int n) {
-  putu4_at(put_space(4), n);
-}
-
-maybe_inline
-void unpacker::putu8(jlong n) {
-  putu8_at(put_space(8), n);
-}
-
-maybe_inline
-int unpacker::putref_index(entry* e, int size) {
-  if (e == null)
-    return 0;
-  else if (e->outputIndex > REQUESTED_NONE)
-    return e->outputIndex;
-  else if (e->tag == CONSTANT_Signature)
-    return putref_index(e->ref(0), size);
-  else {
-    e->requestOutputIndex(cp, (size == 1 ? REQUESTED_LDC : REQUESTED));
-    // Later on we'll fix the bits.
-    class_fixup_type.addByte(size);
-    class_fixup_offset.add((int)wpoffset());
-    class_fixup_ref.add(e);
-#ifdef PRODUCT
-    return 0;
-#else
-    return 0x20+size;  // 0x22 is easy to eyeball
-#endif
-  }
-}
-
-maybe_inline
-void unpacker::putref(entry* e) {
-  int oidx = putref_index(e, 2);
-  putu2_at(put_space(2), oidx);
-}
-
-maybe_inline
-void unpacker::putu1ref(entry* e) {
-  int oidx = putref_index(e, 1);
-  putu1_at(put_space(1), oidx);
-}
-
-
-static int total_cp_size[] = {0, 0};
-static int largest_cp_ref[] = {0, 0};
-static int hash_probes[] = {0, 0};
-
-// Allocation of small and large blocks.
-
-enum { CHUNK = (1 << 14), SMALL = (1 << 9) };
-
-// Call malloc.  Try to combine small blocks and free much later.
-void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) {
-  if (!smallOK || size > SMALL) {
-    void* res = must_malloc((int)size);
-    (temp ? &tmallocs : &mallocs)->add(res);
-    return res;
-  }
-  fillbytes& xsmallbuf = *(temp ? &tsmallbuf : &smallbuf);
-  if (!xsmallbuf.canAppend(size+1)) {
-    xsmallbuf.init(CHUNK);
-    (temp ? &tmallocs : &mallocs)->add(xsmallbuf.base());
-  }
-  int growBy = (int)size;
-  growBy += -growBy & 7;  // round up mod 8
-  return xsmallbuf.grow(growBy);
-}
-
-maybe_inline
-void unpacker::saveTo(bytes& b, byte* ptr, size_t len) {
-  b.ptr = U_NEW(byte, add_size(len,1));
-  if (aborting()) {
-    b.len = 0;
-    return;
-  }
-  b.len = len;
-  b.copyFrom(ptr, len);
-}
-
-bool testBit(int archive_options, int bitMask) {
-    return (archive_options & bitMask) != 0;
-}
-
-// Read up through band_headers.
-// Do the archive_size dance to set the size of the input mega-buffer.
-void unpacker::read_file_header() {
-  // Read file header to determine file type and total size.
-  enum {
-    MAGIC_BYTES = 4,
-    AH_LENGTH_0 = 3,  // archive_header_0 = {minver, majver, options}
-    AH_LENGTH_MIN = 15, // observed in spec {header_0[3], cp_counts[8], class_counts[4]}
-    AH_LENGTH_0_MAX = AH_LENGTH_0 + 1,  // options might have 2 bytes
-    AH_LENGTH   = 30, //maximum archive header length (w/ all fields)
-    // Length contributions from optional header fields:
-    AH_LENGTH_S = 2, // archive_header_S = optional {size_hi, size_lo}
-    AH_ARCHIVE_SIZE_HI = 0, // offset in archive_header_S
-    AH_ARCHIVE_SIZE_LO = 1, // offset in archive_header_S
-    AH_FILE_HEADER_LEN = 5, // file_counts = {{size_hi, size_lo), next, modtile, files}
-    AH_SPECIAL_FORMAT_LEN = 2, // special_count = {layouts, band_headers}
-    AH_CP_NUMBER_LEN = 4,      // cp_number_counts = {int, float, long, double}
-    AH_CP_EXTRA_LEN = 4,        // cp_attr_counts = {MH, MT, InDy, BSM}
-    ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S,
-    FIRST_READ  = MAGIC_BYTES + AH_LENGTH_MIN
-  };
-
-  assert(AH_LENGTH_MIN    == 15); // # of UNSIGNED5 fields required after archive_magic
-  // An absolute minimum null archive is magic[4], {minver,majver,options}[3],
-  // archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes.
-  // (Note that archive_size is optional; it may be 0..10 bytes in length.)
-  // The first read must capture everything up through the options field.
-  // This happens to work even if {minver,majver,options} is a pathological
-  // 15 bytes long.  Legal pack files limit those three fields to 1+1+2 bytes.
-  assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX);
-
-  // Up through archive_size, the largest possible archive header is
-  // magic[4], {minver,majver,options}[4], archive_size[10].
-  // (Note only the low 12 bits of options are allowed to be non-zero.)
-  // In order to parse archive_size, we need at least this many bytes
-  // in the first read.  Of course, if archive_size_hi is more than
-  // a byte, we probably will fail to allocate the buffer, since it
-  // will be many gigabytes long.  This is a practical, not an
-  // architectural limit to Pack200 archive sizes.
-  assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2*B_MAX);
-
-  bool foreign_buf = (read_input_fn == null);
-  byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200];  // 200 is for JAR I/O
-  if (foreign_buf) {
-    // inbytes is all there is
-    input.set(inbytes);
-    rp      = input.base();
-    rplimit = input.limit();
-  } else {
-    // inbytes, if not empty, contains some read-ahead we must use first
-    // ensure_input will take care of copying it into initbuf,
-    // then querying read_input_fn for any additional data needed.
-    // However, the caller must assume that we use up all of inbytes.
-    // There is no way to tell the caller that we used only part of them.
-    // Therefore, the caller must use only a bare minimum of read-ahead.
-    if (inbytes.len > FIRST_READ) {
-      abort("too much read-ahead");
-      return;
-    }
-    input.set(initbuf, sizeof(initbuf));
-    input.b.clear();
-    input.b.copyFrom(inbytes);
-    rplimit = rp = input.base();
-    rplimit += inbytes.len;
-    bytes_read += inbytes.len;
-  }
-  // Read only 19 bytes, which is certain to contain #archive_options fields,
-  // but is certain not to overflow past the archive_header.
-  input.b.len = FIRST_READ;
-  if (!ensure_input(FIRST_READ))
-    abort("EOF reading archive magic number");
-
-  if (rp[0] == 'P' && rp[1] == 'K') {
-#ifdef UNPACK_JNI
-    // Java driver must handle this case before we get this far.
-    abort("encountered a JAR header in unpacker");
-#else
-    // In the Unix-style program, we simply simulate a copy command.
-    // Copy until EOF; assume the JAR file is the last segment.
-    fprintf(errstrm, "Copy-mode.\n");
-    for (;;) {
-      jarout->write_data(rp, (int)input_remaining());
-      if (foreign_buf)
-        break;  // one-time use of a passed in buffer
-      if (input.size() < CHUNK) {
-        // Get some breathing room.
-        input.set(U_NEW(byte, (size_t) CHUNK + C_SLOP), (size_t) CHUNK);
-        CHECK;
-      }
-      rp = rplimit = input.base();
-      if (!ensure_input(1))
-        break;
-    }
-    jarout->closeJarFile(false);
-#endif
-    return;
-  }
-
-  // Read the magic number.
-  magic = 0;
-  for (int i1 = 0; i1 < (int)sizeof(magic); i1++) {
-    magic <<= 8;
-    magic += (*rp++ & 0xFF);
-  }
-
-  // Read the first 3 values from the header.
-  value_stream hdr;
-  int          hdrVals = 0;
-  int          hdrValsSkipped = 0;  // for assert
-  hdr.init(rp, rplimit, UNSIGNED5_spec);
-  minver = hdr.getInt();
-  majver = hdr.getInt();
-  hdrVals += 2;
-
-  int majmin[4][2] = {
-      {JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION},
-      {JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION},
-      {JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION},
-      {JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION}
-  };
-  int majminfound = false;
-  for (int i = 0 ; i < 4 ; i++) {
-      if (majver == majmin[i][0] && minver == majmin[i][1]) {
-          majminfound = true;
-          break;
-      }
-  }
-  if (majminfound == null) {
-    char message[200];
-    sprintf(message, "@" ERROR_FORMAT ": magic/ver = "
-            "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d\n",
-            magic, majver, minver,
-            JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION,
-            JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION,
-            JAVA_PACKAGE_MAGIC, JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION,
-            JAVA_PACKAGE_MAGIC, JAVA8_PACKAGE_MAJOR_VERSION, JAVA8_PACKAGE_MINOR_VERSION);
-    abort(message);
-  }
-  CHECK;
-
-  archive_options = hdr.getInt();
-  hdrVals += 1;
-  assert(hdrVals == AH_LENGTH_0);  // first three fields only
-  bool haveSizeHi = testBit(archive_options, AO_HAVE_FILE_SIZE_HI);
-  bool haveModTime = testBit(archive_options, AO_HAVE_FILE_MODTIME);
-  bool haveFileOpt = testBit(archive_options, AO_HAVE_FILE_OPTIONS);
-
-  bool haveSpecial = testBit(archive_options, AO_HAVE_SPECIAL_FORMATS);
-  bool haveFiles = testBit(archive_options, AO_HAVE_FILE_HEADERS);
-  bool haveNumbers = testBit(archive_options, AO_HAVE_CP_NUMBERS);
-  bool haveCPExtra = testBit(archive_options, AO_HAVE_CP_EXTRAS);
-
-  if (majver < JAVA7_PACKAGE_MAJOR_VERSION) {
-    if (haveCPExtra) {
-        abort("Format bits for Java 7 must be zero in previous releases");
-        return;
-    }
-  }
-  if (testBit(archive_options, AO_UNUSED_MBZ)) {
-    abort("High archive option bits are reserved and must be zero");
-    return;
-  }
-  if (haveFiles) {
-    uint hi = hdr.getInt();
-    uint lo = hdr.getInt();
-    julong x = band::makeLong(hi, lo);
-    archive_size = (size_t) x;
-    if (archive_size != x) {
-      // Silly size specified; force overflow.
-      archive_size = PSIZE_MAX+1;
-    }
-    hdrVals += 2;
-  } else {
-    hdrValsSkipped += 2;
-  }
-
-  // Now we can size the whole archive.
-  // Read everything else into a mega-buffer.
-  rp = hdr.rp;
-  size_t header_size_0 = (rp - input.base()); // used-up header (4byte + 3int)
-  size_t header_size_1 = (rplimit - rp);      // buffered unused initial fragment
-  size_t header_size   = header_size_0 + header_size_1;
-  unsized_bytes_read = header_size_0;
-  CHECK;
-  if (foreign_buf) {
-    if (archive_size > header_size_1) {
-      abort("EOF reading fixed input buffer");
-      return;
-    }
-  } else if (archive_size != 0) {
-    if (archive_size < ARCHIVE_SIZE_MIN) {
-      abort("impossible archive size");  // bad input data
-      return;
-    }
-    if (archive_size < header_size_1) {
-      abort("too much read-ahead");  // somehow we pre-fetched too much?
-      return;
-    }
-    input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
-              header_size_0 + archive_size);
-    CHECK;
-    assert(input.limit()[0] == 0);
-    // Move all the bytes we read initially into the real buffer.
-    input.b.copyFrom(initbuf, header_size);
-    rp      = input.b.ptr + header_size_0;
-    rplimit = input.b.ptr + header_size;
-  } else {
-    // It's more complicated and painful.
-    // A zero archive_size means that we must read until EOF.
-    input.init(CHUNK*2);
-    CHECK;
-    input.b.len = input.allocated;
-    rp = rplimit = input.base();
-    // Set up input buffer as if we already read the header:
-    input.b.copyFrom(initbuf, header_size);
-    CHECK;
-    rplimit += header_size;
-    while (ensure_input(input.limit() - rp)) {
-      size_t dataSoFar = input_remaining();
-      size_t nextSize = add_size(dataSoFar, CHUNK);
-      input.ensureSize(nextSize);
-      CHECK;
-      input.b.len = input.allocated;
-      rp = rplimit = input.base();
-      rplimit += dataSoFar;
-    }
-    size_t dataSize = (rplimit - input.base());
-    input.b.len = dataSize;
-    input.grow(C_SLOP);
-    CHECK;
-    free_input = true;  // free it later
-    input.b.len = dataSize;
-    assert(input.limit()[0] == 0);
-    rp = rplimit = input.base();
-    rplimit += dataSize;
-    rp += header_size_0;  // already scanned these bytes...
-  }
-  live_input = true;    // mark as "do not reuse"
-  if (aborting()) {
-    abort("cannot allocate large input buffer for package file");
-    return;
-  }
-
-  // read the rest of the header fields  int assertSkipped = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S;
-  int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S;
-  if (haveSpecial)
-    remainingHeaders += AH_SPECIAL_FORMAT_LEN;
-  if (haveFiles)
-     remainingHeaders += AH_FILE_HEADER_LEN;
-  if (haveNumbers)
-    remainingHeaders += AH_CP_NUMBER_LEN;
-  if (haveCPExtra)
-    remainingHeaders += AH_CP_EXTRA_LEN;
-
-  ensure_input(remainingHeaders * B_MAX);
-  CHECK;
-  hdr.rp      = rp;
-  hdr.rplimit = rplimit;
-
-  if (haveFiles) {
-    archive_next_count = hdr.getInt();
-    CHECK_COUNT(archive_next_count);
-    archive_modtime = hdr.getInt();
-    file_count = hdr.getInt();
-    CHECK_COUNT(file_count);
-    hdrVals += 3;
-  } else {
-    hdrValsSkipped += 3;
-  }
-
-  if (haveSpecial) {
-    band_headers_size = hdr.getInt();
-    CHECK_COUNT(band_headers_size);
-    attr_definition_count = hdr.getInt();
-    CHECK_COUNT(attr_definition_count);
-    hdrVals += 2;
-  } else {
-    hdrValsSkipped += 2;
-  }
-
-  int cp_counts[N_TAGS_IN_ORDER];
-  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
-    if (!haveNumbers) {
-      switch (TAGS_IN_ORDER[k]) {
-      case CONSTANT_Integer:
-      case CONSTANT_Float:
-      case CONSTANT_Long:
-      case CONSTANT_Double:
-        cp_counts[k] = 0;
-        hdrValsSkipped += 1;
-        continue;
-      }
-    }
-    if (!haveCPExtra) {
-        switch(TAGS_IN_ORDER[k]) {
-        case CONSTANT_MethodHandle:
-        case CONSTANT_MethodType:
-        case CONSTANT_InvokeDynamic:
-        case CONSTANT_BootstrapMethod:
-          cp_counts[k] = 0;
-          hdrValsSkipped += 1;
-          continue;
-        }
-    }
-    cp_counts[k] = hdr.getInt();
-    CHECK_COUNT(cp_counts[k]);
-    hdrVals += 1;
-  }
-
-  ic_count = hdr.getInt();
-  CHECK_COUNT(ic_count);
-  default_class_minver = hdr.getInt();
-  default_class_majver = hdr.getInt();
-  class_count = hdr.getInt();
-  CHECK_COUNT(class_count);
-  hdrVals += 4;
-
-  // done with archive_header, time to reconcile to ensure
-  // we have read everything correctly
-  hdrVals += hdrValsSkipped;
-  assert(hdrVals == AH_LENGTH);
-  rp = hdr.rp;
-  if (rp > rplimit)
-    abort("EOF reading archive header");
-
-  // Now size the CP.
-#ifndef PRODUCT
-  // bool x = (N_TAGS_IN_ORDER == CONSTANT_Limit);
-  // assert(x);
-#endif //PRODUCT
-  cp.init(this, cp_counts);
-  CHECK;
-
-  default_file_modtime = archive_modtime;
-  if (default_file_modtime == 0 && haveModTime)
-    default_file_modtime = DEFAULT_ARCHIVE_MODTIME;  // taken from driver
-  if (testBit(archive_options, AO_DEFLATE_HINT))
-    default_file_options |= FO_DEFLATE_HINT;
-
-  // meta-bytes, if any, immediately follow archive header
-  //band_headers.readData(band_headers_size);
-  ensure_input(band_headers_size);
-  if (input_remaining() < (size_t)band_headers_size) {
-    abort("EOF reading band headers");
-    return;
-  }
-  bytes band_headers;
-  // The "1+" allows an initial byte to be pushed on the front.
-  band_headers.set(1+U_NEW(byte, 1+band_headers_size+C_SLOP),
-                   band_headers_size);
-  CHECK;
-  // Start scanning band headers here:
-  band_headers.copyFrom(rp, band_headers.len);
-  rp += band_headers.len;
-  assert(rp <= rplimit);
-  meta_rp = band_headers.ptr;
-  // Put evil meta-codes at the end of the band headers,
-  // so we are sure to throw an error if we run off the end.
-  bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
-}
-
-void unpacker::finish() {
-  if (verbose >= 1) {
-    fprintf(errstrm,
-            "A total of "
-            LONG_LONG_FORMAT " bytes were read in %d segment(s).\n",
-            (bytes_read_before_reset+bytes_read),
-            segments_read_before_reset+1);
-    fprintf(errstrm,
-            "A total of "
-            LONG_LONG_FORMAT " file content bytes were written.\n",
-            (bytes_written_before_reset+bytes_written));
-    fprintf(errstrm,
-            "A total of %d files (of which %d are classes) were written to output.\n",
-            files_written_before_reset+files_written,
-            classes_written_before_reset+classes_written);
-  }
-  if (jarout != null)
-    jarout->closeJarFile(true);
-  if (errstrm != null) {
-    if (errstrm == stdout || errstrm == stderr) {
-      fflush(errstrm);
-    } else {
-      fclose(errstrm);
-    }
-    errstrm = null;
-    errstrm_name = null;
-  }
-}
-
-
-// Cf. PackageReader.readConstantPoolCounts
-void cpool::init(unpacker* u_, int counts[CONSTANT_Limit]) {
-  this->u = u_;
-
-  // Fill-pointer for CP.
-  int next_entry = 0;
-
-  // Size the constant pool:
-  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
-    byte tag = TAGS_IN_ORDER[k];
-    int  len = counts[k];
-    tag_count[tag] = len;
-    tag_base[tag] = next_entry;
-    next_entry += len;
-    // Detect and defend against constant pool size overflow.
-    // (Pack200 forbids the sum of CP counts to exceed 2^29-1.)
-    enum {
-      CP_SIZE_LIMIT = (1<<29),
-      IMPLICIT_ENTRY_COUNT = 1  // empty Utf8 string
-    };
-    if (len >= (1<<29) || len < 0
-        || next_entry >= CP_SIZE_LIMIT+IMPLICIT_ENTRY_COUNT) {
-      abort("archive too large:  constant pool limit exceeded");
-      return;
-    }
-  }
-
-  // Close off the end of the CP:
-  nentries = next_entry;
-
-  // place a limit on future CP growth:
-  size_t generous = 0;
-  generous = add_size(generous, u->ic_count); // implicit name
-  generous = add_size(generous, u->ic_count); // outer
-  generous = add_size(generous, u->ic_count); // outer.utf8
-  generous = add_size(generous, 40); // WKUs, misc
-  generous = add_size(generous, u->class_count); // implicit SourceFile strings
-  maxentries = (uint)add_size(nentries, generous);
-
-  // Note that this CP does not include "empty" entries
-  // for longs and doubles.  Those are introduced when
-  // the entries are renumbered for classfile output.
-
-  entries = U_NEW(entry, maxentries);
-  CHECK;
-
-  first_extra_entry = &entries[nentries];
-
-  // Initialize the standard indexes.
-  for (int tag = 0; tag < CONSTANT_Limit; tag++) {
-    entry* cpMap = &entries[tag_base[tag]];
-    tag_index[tag].init(tag_count[tag], cpMap, tag);
-  }
-
-  // Initialize *all* our entries once
-  for (uint i = 0 ; i < maxentries ; i++) {
-    entries[i].outputIndex = REQUESTED_NONE;
-  }
-
-  initGroupIndexes();
-  // Initialize hashTab to a generous power-of-two size.
-  uint pow2 = 1;
-  uint target = maxentries + maxentries/2;  // 60% full
-  while (pow2 < target)  pow2 <<= 1;
-  hashTab = U_NEW(entry*, hashTabLength = pow2);
-}
-
-static byte* store_Utf8_char(byte* cp, unsigned short ch) {
-  if (ch >= 0x001 && ch <= 0x007F) {
-    *cp++ = (byte) ch;
-  } else if (ch <= 0x07FF) {
-    *cp++ = (byte) (0xC0 | ((ch >>  6) & 0x1F));
-    *cp++ = (byte) (0x80 | ((ch >>  0) & 0x3F));
-  } else {
-    *cp++ = (byte) (0xE0 | ((ch >> 12) & 0x0F));
-    *cp++ = (byte) (0x80 | ((ch >>  6) & 0x3F));
-    *cp++ = (byte) (0x80 | ((ch >>  0) & 0x3F));
-  }
-  return cp;
-}
-
-static byte* skip_Utf8_chars(byte* cp, int len) {
-  for (;; cp++) {
-    int ch = *cp & 0xFF;
-    if ((ch & 0xC0) != 0x80) {
-      if (len-- == 0)
-        return cp;
-      if (ch < 0x80 && len == 0)
-        return cp+1;
-    }
-  }
-}
-
-static int compare_Utf8_chars(bytes& b1, bytes& b2) {
-  int l1 = (int)b1.len;
-  int l2 = (int)b2.len;
-  int l0 = (l1 < l2) ? l1 : l2;
-  byte* p1 = b1.ptr;
-  byte* p2 = b2.ptr;
-  int c0 = 0;
-  for (int i = 0; i < l0; i++) {
-    int c1 = p1[i] & 0xFF;
-    int c2 = p2[i] & 0xFF;
-    if (c1 != c2) {
-      // Before returning the obvious answer,
-      // check to see if c1 or c2 is part of a 0x0000,
-      // which encodes as {0xC0,0x80}.  The 0x0000 is the
-      // lowest-sorting Java char value, and yet it encodes
-      // as if it were the first char after 0x7F, which causes
-      // strings containing nulls to sort too high.  All other
-      // comparisons are consistent between Utf8 and Java chars.
-      if (c1 == 0xC0 && (p1[i+1] & 0xFF) == 0x80)  c1 = 0;
-      if (c2 == 0xC0 && (p2[i+1] & 0xFF) == 0x80)  c2 = 0;
-      if (c0 == 0xC0) {
-        assert(((c1|c2) & 0xC0) == 0x80);  // c1 & c2 are extension chars
-        if (c1 == 0x80)  c1 = 0;  // will sort below c2
-        if (c2 == 0x80)  c2 = 0;  // will sort below c1
-      }
-      return c1 - c2;
-    }
-    c0 = c1;  // save away previous char
-  }
-  // common prefix is identical; return length difference if any
-  return l1 - l2;
-}
-
-// Cf. PackageReader.readUtf8Bands
-local_inline
-void unpacker::read_Utf8_values(entry* cpMap, int len) {
-  // Implicit first Utf8 string is the empty string.
-  enum {
-    // certain bands begin with implicit zeroes
-    PREFIX_SKIP_2 = 2,
-    SUFFIX_SKIP_1 = 1
-  };
-
-  int i;
-
-  // First band:  Read lengths of shared prefixes.
-  if (len > PREFIX_SKIP_2)
-    cp_Utf8_prefix.readData(len - PREFIX_SKIP_2);
-    NOT_PRODUCT(else cp_Utf8_prefix.readData(0));  // for asserts
-
-  // Second band:  Read lengths of unshared suffixes:
-  if (len > SUFFIX_SKIP_1)
-    cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1);
-    NOT_PRODUCT(else cp_Utf8_suffix.readData(0));  // for asserts
-
-  bytes* allsuffixes = T_NEW(bytes, len);
-  CHECK;
-
-  int nbigsuf = 0;
-  fillbytes charbuf;    // buffer to allocate small strings
-  charbuf.init();
-
-  // Third band:  Read the char values in the unshared suffixes:
-  cp_Utf8_chars.readData(cp_Utf8_suffix.getIntTotal());
-  for (i = 0; i < len; i++) {
-    int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();
-    if (suffix < 0) {
-      abort("bad utf8 suffix");
-      return;
-    }
-    if (suffix == 0 && i >= SUFFIX_SKIP_1) {
-      // chars are packed in cp_Utf8_big_chars
-      nbigsuf += 1;
-      continue;
-    }
-    bytes& chars  = allsuffixes[i];
-    uint size3    = suffix * 3;     // max Utf8 length
-    bool isMalloc = (suffix > SMALL);
-    if (isMalloc) {
-      chars.malloc(size3);
-    } else {
-      if (!charbuf.canAppend(size3+1)) {
-        assert(charbuf.allocated == 0 || tmallocs.contains(charbuf.base()));
-        charbuf.init(CHUNK);  // Reset to new buffer.
-        tmallocs.add(charbuf.base());
-      }
-      chars.set(charbuf.grow(size3+1), size3);
-    }
-    CHECK;
-    byte* chp = chars.ptr;
-    for (int j = 0; j < suffix; j++) {
-      unsigned short ch = cp_Utf8_chars.getInt();
-      chp = store_Utf8_char(chp, ch);
-    }
-    // shrink to fit:
-    if (isMalloc) {
-      chars.realloc(chp - chars.ptr);
-      CHECK;
-      tmallocs.add(chars.ptr); // free it later
-    } else {
-      int shrink = (int)(chars.limit() - chp);
-      chars.len -= shrink;
-      charbuf.b.len -= shrink;  // ungrow to reclaim buffer space
-      // Note that we did not reclaim the final '\0'.
-      assert(chars.limit() == charbuf.limit()-1);
-      assert(strlen((char*)chars.ptr) == chars.len);
-    }
-  }
-  //cp_Utf8_chars.done();
-#ifndef PRODUCT
-  charbuf.b.set(null, 0); // tidy
-#endif
-
-  // Fourth band:  Go back and size the specially packed strings.
-  int maxlen = 0;
-  cp_Utf8_big_suffix.readData(nbigsuf);
-  cp_Utf8_suffix.rewind();
-  for (i = 0; i < len; i++) {
-    int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();
-    int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();
-    if (prefix < 0 || prefix+suffix < 0) {
-       abort("bad utf8 prefix");
-       return;
-    }
-    bytes& chars = allsuffixes[i];
-    if (suffix == 0 && i >= SUFFIX_SKIP_1) {
-      suffix = cp_Utf8_big_suffix.getInt();
-      assert(chars.ptr == null);
-      chars.len = suffix;  // just a momentary hack
-    } else {
-      assert(chars.ptr != null);
-    }
-    if (maxlen < prefix + suffix) {
-      maxlen = prefix + suffix;
-    }
-  }
-  //cp_Utf8_suffix.done();      // will use allsuffixes[i].len (ptr!=null)
-  //cp_Utf8_big_suffix.done();  // will use allsuffixes[i].len
-
-  // Fifth band(s):  Get the specially packed characters.
-  cp_Utf8_big_suffix.rewind();
-  for (i = 0; i < len; i++) {
-    bytes& chars = allsuffixes[i];
-    if (chars.ptr != null)  continue;  // already input
-    int suffix = (int)chars.len;  // pick up the hack
-    uint size3 = suffix * 3;
-    if (suffix == 0)  continue;  // done with empty string
-    chars.malloc(size3);
-    CHECK;
-    byte* chp = chars.ptr;
-    band saved_band = cp_Utf8_big_chars;
-    cp_Utf8_big_chars.readData(suffix);
-    CHECK;
-    for (int j = 0; j < suffix; j++) {
-      unsigned short ch = cp_Utf8_big_chars.getInt();
-      CHECK;
-      chp = store_Utf8_char(chp, ch);
-    }
-    chars.realloc(chp - chars.ptr);
-    CHECK;
-    tmallocs.add(chars.ptr);  // free it later
-    //cp_Utf8_big_chars.done();
-    cp_Utf8_big_chars = saved_band;  // reset the band for the next string
-  }
-  cp_Utf8_big_chars.readData(0);  // zero chars
-  //cp_Utf8_big_chars.done();
-
-  // Finally, sew together all the prefixes and suffixes.
-  bytes bigbuf;
-  bigbuf.malloc(maxlen * 3 + 1);  // max Utf8 length, plus slop for null
-  CHECK;
-  int prevlen = 0;  // previous string length (in chars)
-  tmallocs.add(bigbuf.ptr);  // free after this block
-  CHECK;
-  cp_Utf8_prefix.rewind();
-  for (i = 0; i < len; i++) {
-    bytes& chars = allsuffixes[i];
-    int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();
-    CHECK;
-    int suffix = (int)chars.len;
-    byte* fillp;
-    // by induction, the buffer is already filled with the prefix
-    // make sure the prefix value is not corrupted, though:
-    if (prefix > prevlen) {
-       abort("utf8 prefix overflow");
-       return;
-    }
-    fillp = skip_Utf8_chars(bigbuf.ptr, prefix);
-    // copy the suffix into the same buffer:
-    fillp = chars.writeTo(fillp);
-    assert(bigbuf.inBounds(fillp));
-    *fillp = 0;  // bigbuf must contain a well-formed Utf8 string
-    int length = (int)(fillp - bigbuf.ptr);
-    bytes& value = cpMap[i].value.b;
-    value.set(U_NEW(byte, add_size(length,1)), length);
-    value.copyFrom(bigbuf.ptr, length);
-    CHECK;
-    // Index all Utf8 strings
-    entry* &htref = cp.hashTabRef(CONSTANT_Utf8, value);
-    if (htref == null) {
-      // Note that if two identical strings are transmitted,
-      // the first is taken to be the canonical one.
-      htref = &cpMap[i];
-    }
-    prevlen = prefix + suffix;
-  }
-  //cp_Utf8_prefix.done();
-
-  // Free intermediate buffers.
-  free_temps();
-}
-
-local_inline
-void unpacker::read_single_words(band& cp_band, entry* cpMap, int len) {
-  cp_band.readData(len);
-  for (int i = 0; i < len; i++) {
-    cpMap[i].value.i = cp_band.getInt();  // coding handles signs OK
-  }
-}
-
-maybe_inline
-void unpacker::read_double_words(band& cp_bands, entry* cpMap, int len) {
-  band& cp_band_hi = cp_bands;
-  band& cp_band_lo = cp_bands.nextBand();
-  cp_band_hi.readData(len);
-  cp_band_lo.readData(len);
-  for (int i = 0; i < len; i++) {
-    cpMap[i].value.l = cp_band_hi.getLong(cp_band_lo, true);
-  }
-  //cp_band_hi.done();
-  //cp_band_lo.done();
-}
-
-maybe_inline
-void unpacker::read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len) {
-  assert(refTag == CONSTANT_Utf8);
-  cp_band.setIndexByTag(refTag);
-  cp_band.readData(len);
-  CHECK;
-  int indexTag = (cp_band.bn == e_cp_Class) ? CONSTANT_Class : 0;
-  for (int i = 0; i < len; i++) {
-    entry& e = cpMap[i];
-    e.refs = U_NEW(entry*, e.nrefs = 1);
-    entry* utf = cp_band.getRef();
-    CHECK;
-    e.refs[0] = utf;
-    e.value.b = utf->value.b;  // copy value of Utf8 string to self
-    if (indexTag != 0) {
-      // Maintain cross-reference:
-      entry* &htref = cp.hashTabRef(indexTag, e.value.b);
-      if (htref == null) {
-        // Note that if two identical classes are transmitted,
-        // the first is taken to be the canonical one.
-        htref = &e;
-      }
-    }
-  }
-  //cp_band.done();
-}
-
-maybe_inline
-void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag,
-                                entry* cpMap, int len) {
-  band& cp_band1 = cp_band;
-  band& cp_band2 = cp_band.nextBand();
-  cp_band1.setIndexByTag(ref1Tag);
-  cp_band2.setIndexByTag(ref2Tag);
-  cp_band1.readData(len);
-  cp_band2.readData(len);
-  CHECK;
-  for (int i = 0; i < len; i++) {
-    entry& e = cpMap[i];
-    e.refs = U_NEW(entry*, e.nrefs = 2);
-    e.refs[0] = cp_band1.getRef();
-    CHECK;
-    e.refs[1] = cp_band2.getRef();
-    CHECK;
-  }
-  //cp_band1.done();
-  //cp_band2.done();
-}
-
-// Cf. PackageReader.readSignatureBands
-maybe_inline
-void unpacker::read_signature_values(entry* cpMap, int len) {
-  cp_Signature_form.setIndexByTag(CONSTANT_Utf8);
-  cp_Signature_form.readData(len);
-  CHECK;
-  int ncTotal = 0;
-  int i;
-  for (i = 0; i < len; i++) {
-    entry& e = cpMap[i];
-    entry& form = *cp_Signature_form.getRef();
-    CHECK;
-    int nc = 0;
-
-    for (int j = 0; j < (int)form.value.b.len; j++) {
-      int c = form.value.b.ptr[j];
-      if (c == 'L') nc++;
-    }
-    ncTotal += nc;
-    e.refs = U_NEW(entry*, cpMap[i].nrefs = 1 + nc);
-    CHECK;
-    e.refs[0] = &form;
-  }
-  //cp_Signature_form.done();
-  cp_Signature_classes.setIndexByTag(CONSTANT_Class);
-  cp_Signature_classes.readData(ncTotal);
-  for (i = 0; i < len; i++) {
-    entry& e = cpMap[i];
-    for (int j = 1; j < e.nrefs; j++) {
-      e.refs[j] = cp_Signature_classes.getRef();
-      CHECK;
-    }
-  }
-  //cp_Signature_classes.done();
-}
-
-maybe_inline
-void unpacker::checkLegacy(const char* name) {
-  if (u->majver < JAVA7_PACKAGE_MAJOR_VERSION) {
-      char message[100];
-      snprintf(message, 99, "unexpected band %s\n", name);
-      abort(message);
-  }
-}
-
-maybe_inline
-void unpacker::read_method_handle(entry* cpMap, int len) {
-  if (len > 0) {
-    checkLegacy(cp_MethodHandle_refkind.name);
-  }
-  cp_MethodHandle_refkind.readData(len);
-  cp_MethodHandle_member.setIndexByTag(CONSTANT_AnyMember);
-  cp_MethodHandle_member.readData(len);
-  for (int i = 0 ; i < len ; i++) {
-    entry& e = cpMap[i];
-    e.value.i = cp_MethodHandle_refkind.getInt();
-    e.refs = U_NEW(entry*, e.nrefs = 1);
-    e.refs[0] = cp_MethodHandle_member.getRef();
-    CHECK;
-  }
-}
-
-maybe_inline
-void unpacker::read_method_type(entry* cpMap, int len) {
-  if (len > 0) {
-    checkLegacy(cp_MethodType.name);
-  }
-  cp_MethodType.setIndexByTag(CONSTANT_Signature);
-  cp_MethodType.readData(len);
-  for (int i = 0 ; i < len ; i++) {
-      entry& e = cpMap[i];
-      e.refs = U_NEW(entry*, e.nrefs = 1);
-      e.refs[0] = cp_MethodType.getRef();
-      CHECK;
-  }
-}
-
-maybe_inline
-void unpacker::read_bootstrap_methods(entry* cpMap, int len) {
-  if (len > 0) {
-    checkLegacy(cp_BootstrapMethod_ref.name);
-  }
-  cp_BootstrapMethod_ref.setIndexByTag(CONSTANT_MethodHandle);
-  cp_BootstrapMethod_ref.readData(len);
-
-  cp_BootstrapMethod_arg_count.readData(len);
-  int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal();
-  cp_BootstrapMethod_arg.setIndexByTag(CONSTANT_LoadableValue);
-  cp_BootstrapMethod_arg.readData(totalArgCount);
-  for (int i = 0; i < len; i++) {
-    entry& e = cpMap[i];
-    int argc = cp_BootstrapMethod_arg_count.getInt();
-    e.value.i = argc;
-    e.refs = U_NEW(entry*, e.nrefs = argc + 1);
-    e.refs[0] = cp_BootstrapMethod_ref.getRef();
-    for (int j = 1 ; j < e.nrefs ; j++) {
-      e.refs[j] = cp_BootstrapMethod_arg.getRef();
-      CHECK;
-    }
-  }
-}
-// Cf. PackageReader.readConstantPool
-void unpacker::read_cp() {
-  byte* rp0 = rp;
-
-  int i;
-
-  for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) {
-    byte tag = TAGS_IN_ORDER[k];
-    int  len = cp.tag_count[tag];
-    int base = cp.tag_base[tag];
-
-    PRINTCR((1,"Reading %d %s entries...", len, NOT_PRODUCT(TAG_NAME[tag])+0));
-    entry* cpMap = &cp.entries[base];
-    for (i = 0; i < len; i++) {
-      cpMap[i].tag = tag;
-      cpMap[i].inord = i;
-    }
-    // Initialize the tag's CP index right away, since it might be needed
-    // in the next pass to initialize the CP for another tag.
-#ifndef PRODUCT
-    cpindex* ix = &cp.tag_index[tag];
-    assert(ix->ixTag == tag);
-    assert((int)ix->len   == len);
-    assert(ix->base1 == cpMap);
-#endif
-
-    switch (tag) {
-    case CONSTANT_Utf8:
-      read_Utf8_values(cpMap, len);
-      break;
-    case CONSTANT_Integer:
-      read_single_words(cp_Int, cpMap, len);
-      break;
-    case CONSTANT_Float:
-      read_single_words(cp_Float, cpMap, len);
-      break;
-    case CONSTANT_Long:
-      read_double_words(cp_Long_hi /*& cp_Long_lo*/, cpMap, len);
-      break;
-    case CONSTANT_Double:
-      read_double_words(cp_Double_hi /*& cp_Double_lo*/, cpMap, len);
-      break;
-    case CONSTANT_String:
-      read_single_refs(cp_String, CONSTANT_Utf8, cpMap, len);
-      break;
-    case CONSTANT_Class:
-      read_single_refs(cp_Class, CONSTANT_Utf8, cpMap, len);
-      break;
-    case CONSTANT_Signature:
-      read_signature_values(cpMap, len);
-      break;
-    case CONSTANT_NameandType:
-      read_double_refs(cp_Descr_name /*& cp_Descr_type*/,
-                       CONSTANT_Utf8, CONSTANT_Signature,
-                       cpMap, len);
-      break;
-    case CONSTANT_Fieldref:
-      read_double_refs(cp_Field_class /*& cp_Field_desc*/,
-                       CONSTANT_Class, CONSTANT_NameandType,
-                       cpMap, len);
-      break;
-    case CONSTANT_Methodref:
-      read_double_refs(cp_Method_class /*& cp_Method_desc*/,
-                       CONSTANT_Class, CONSTANT_NameandType,
-                       cpMap, len);
-      break;
-    case CONSTANT_InterfaceMethodref:
-      read_double_refs(cp_Imethod_class /*& cp_Imethod_desc*/,
-                       CONSTANT_Class, CONSTANT_NameandType,
-                       cpMap, len);
-      break;
-    case CONSTANT_MethodHandle:
-      // consumes cp_MethodHandle_refkind and cp_MethodHandle_member
-      read_method_handle(cpMap, len);
-      break;
-    case CONSTANT_MethodType:
-      // consumes cp_MethodType
-      read_method_type(cpMap, len);
-      break;
-    case CONSTANT_InvokeDynamic:
-      read_double_refs(cp_InvokeDynamic_spec, CONSTANT_BootstrapMethod,
-                       CONSTANT_NameandType,
-                       cpMap, len);
-      break;
-    case CONSTANT_BootstrapMethod:
-      // consumes cp_BootstrapMethod_ref, cp_BootstrapMethod_arg_count and cp_BootstrapMethod_arg
-      read_bootstrap_methods(cpMap, len);
-      break;
-    default:
-      assert(false);
-      break;
-    }
-    CHECK;
-  }
-
-  cp.expandSignatures();
-  CHECK;
-  cp.initMemberIndexes();
-  CHECK;
-
-  PRINTCR((1,"parsed %d constant pool entries in %d bytes", cp.nentries, (rp - rp0)));
-
-  #define SNAME(n,s) #s "\0"
-  const char* symNames = (
-    ALL_ATTR_DO(SNAME)
-    "<init>"
-  );
-  #undef SNAME
-
-  for (int sn = 0; sn < cpool::s_LIMIT; sn++) {
-    assert(symNames[0] >= '0' && symNames[0] <= 'Z');  // sanity
-    bytes name; name.set(symNames);
-    if (name.len > 0 && name.ptr[0] != '0') {
-      cp.sym[sn] = cp.ensureUtf8(name);
-      PRINTCR((4, "well-known sym %d=%s", sn, cp.sym[sn]->string()));
-    }
-    symNames += name.len + 1;  // skip trailing null to next name
-  }
-
-  band::initIndexes(this);
-}
-
-static band* no_bands[] = { null };  // shared empty body
-
-inline
-band& unpacker::attr_definitions::fixed_band(int e_class_xxx) {
-  return u->all_bands[xxx_flags_hi_bn + (e_class_xxx-e_class_flags_hi)];
-}
-inline band& unpacker::attr_definitions::xxx_flags_hi()
-  { return fixed_band(e_class_flags_hi); }
-inline band& unpacker::attr_definitions::xxx_flags_lo()
-  { return fixed_band(e_class_flags_lo); }
-inline band& unpacker::attr_definitions::xxx_attr_count()
-  { return fixed_band(e_class_attr_count); }
-inline band& unpacker::attr_definitions::xxx_attr_indexes()
-  { return fixed_band(e_class_attr_indexes); }
-inline band& unpacker::attr_definitions::xxx_attr_calls()
-  { return fixed_band(e_class_attr_calls); }
-
-
-inline
-unpacker::layout_definition*
-unpacker::attr_definitions::defineLayout(int idx,
-                                         entry* nameEntry,
-                                         const char* layout) {
-  const char* name = nameEntry->value.b.strval();
-  layout_definition* lo = defineLayout(idx, name, layout);
-  CHECK_0;
-  lo->nameEntry = nameEntry;
-  return lo;
-}
-
-unpacker::layout_definition*
-unpacker::attr_definitions::defineLayout(int idx,
-                                         const char* name,
-                                         const char* layout) {
-  assert(flag_limit != 0);  // must be set up already
-  if (idx >= 0) {
-    // Fixed attr.
-    if (idx >= (int)flag_limit)
-      abort("attribute index too large");
-    if (isRedefined(idx))
-      abort("redefined attribute index");
-    redef |= ((julong)1<<idx);
-  } else {
-    idx = flag_limit + overflow_count.length();
-    overflow_count.add(0);  // make a new counter
-  }
-  layout_definition* lo = U_NEW(layout_definition, 1);
-  CHECK_0;
-  lo->idx = idx;
-  lo->name = name;
-  lo->layout = layout;
-  for (int adds = (idx+1) - layouts.length(); adds > 0; adds--) {
-    layouts.add(null);
-  }
-  CHECK_0;
-  layouts.get(idx) = lo;
-  return lo;
-}
-
-band**
-unpacker::attr_definitions::buildBands(unpacker::layout_definition* lo) {
-  int i;
-  if (lo->elems != null)
-    return lo->bands();
-  if (lo->layout[0] == '\0') {
-    lo->elems = no_bands;
-  } else {
-    // Create bands for this attribute by parsing the layout.
-    bool hasCallables = lo->hasCallables();
-    bands_made = 0x10000;  // base number for bands made
-    const char* lp = lo->layout;
-    lp = parseLayout(lp, lo->elems, -1);
-    CHECK_0;
-    if (lp[0] != '\0' || band_stack.length() > 0) {
-      abort("garbage at end of layout");
-    }
-    band_stack.popTo(0);
-    CHECK_0;
-
-    // Fix up callables to point at their callees.
-    band** bands = lo->elems;
-    assert(bands == lo->bands());
-    int num_callables = 0;
-    if (hasCallables) {
-      while (bands[num_callables] != null) {
-        if (bands[num_callables]->le_kind != EK_CBLE) {
-          abort("garbage mixed with callables");
-          break;
-        }
-        num_callables += 1;
-      }
-    }
-    for (i = 0; i < calls_to_link.length(); i++) {
-      band& call = *(band*) calls_to_link.get(i);
-      assert(call.le_kind == EK_CALL);
-      // Determine the callee.
-      int call_num = call.le_len;
-      if (call_num < 0 || call_num >= num_callables) {
-        abort("bad call in layout");
-        break;
-      }
-      band& cble = *bands[call_num];
-      // Link the call to it.
-      call.le_body[0] = &cble;
-      // Distinguish backward calls and callables:
-      assert(cble.le_kind == EK_CBLE);
-      assert(cble.le_len == call_num);
-      cble.le_back |= call.le_back;
-    }
-    calls_to_link.popTo(0);
-  }
-  return lo->elems;
-}
-
-/* attribute layout language parser
-
-  attribute_layout:
-        ( layout_element )* | ( callable )+
-  layout_element:
-        ( integral | replication | union | call | reference )
-
-  callable:
-        '[' body ']'
-  body:
-        ( layout_element )+
-
-  integral:
-        ( unsigned_int | signed_int | bc_index | bc_offset | flag )
-  unsigned_int:
-        uint_type
-  signed_int:
-        'S' uint_type
-  any_int:
-        ( unsigned_int | signed_int )
-  bc_index:
-        ( 'P' uint_type | 'PO' uint_type )
-  bc_offset:
-        'O' any_int
-  flag:
-        'F' uint_type
-  uint_type:
-        ( 'B' | 'H' | 'I' | 'V' )
-
-  replication:
-        'N' uint_type '[' body ']'
-
-  union:
-        'T' any_int (union_case)* '(' ')' '[' (body)? ']'
-  union_case:
-        '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']'
-  union_case_tag:
-        ( numeral | numeral '-' numeral )
-  call:
-        '(' numeral ')'
-
-  reference:
-        reference_type ( 'N' )? uint_type
-  reference_type:
-        ( constant_ref | schema_ref | utf8_ref | untyped_ref )
-  constant_ref:
-        ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' )
-  schema_ref:
-        ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' )
-  utf8_ref:
-        'RU'
-  untyped_ref:
-        'RQ'
-
-  numeral:
-        '(' ('-')? (digit)+ ')'
-  digit:
-        ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
-
-*/
-
-const char*
-unpacker::attr_definitions::parseIntLayout(const char* lp, band* &res,
-                                           byte le_kind, bool can_be_signed) {
-  const char* lp0 = lp;
-  band* b = U_NEW(band, 1);
-  CHECK_(lp);
-  char le = *lp++;
-  int spec = UNSIGNED5_spec;
-  if (le == 'S' && can_be_signed) {
-    // Note:  This is the last use of sign.  There is no 'EF_SIGN'.
-    spec = SIGNED5_spec;
-    le = *lp++;
-  } else if (le == 'B') {
-    spec = BYTE1_spec;  // unsigned byte
-  }
-  b->init(u, bands_made++, spec);
-  b->le_kind = le_kind;
-  int le_len = 0;
-  switch (le) {
-  case 'B': le_len = 1; break;
-  case 'H': le_len = 2; break;
-  case 'I': le_len = 4; break;
-  case 'V': le_len = 0; break;
-  default:  abort("bad layout element");
-  }
-  b->le_len = le_len;
-  band_stack.add(b);
-  res = b;
-  return lp;
-}
-
-const char*
-unpacker::attr_definitions::parseNumeral(const char* lp, int &res) {
-  const char* lp0 = lp;
-  bool sgn = false;
-  if (*lp == '0') { res = 0; return lp+1; }  // special case '0'
-  if (*lp == '-') { sgn = true; lp++; }
-  const char* dp = lp;
-  int con = 0;
-  while (*dp >= '0' && *dp <= '9') {
-    int con0 = con;
-    con *= 10;
-    con += (*dp++) - '0';
-    if (con <= con0) { con = -1; break; }  //  numeral overflow
-  }
-  if (lp == dp) {
-    abort("missing numeral in layout");
-    return "";
-  }
-  lp = dp;
-  if (con < 0 && !(sgn && con == -con)) {
-    // (Portability note:  Misses the error if int is not 32 bits.)
-    abort("numeral overflow");
-    return "" ;
-  }
-  if (sgn)  con = -con;
-  res = con;
-  return lp;
-}
-
-band**
-unpacker::attr_definitions::popBody(int bs_base) {
-  // Return everything that was pushed, as a null-terminated pointer array.
-  int bs_limit = band_stack.length();
-  if (bs_base == bs_limit) {
-    return no_bands;
-  } else {
-    int nb = bs_limit - bs_base;
-    band** res = U_NEW(band*, add_size(nb, 1));
-    CHECK_(no_bands);
-    for (int i = 0; i < nb; i++) {
-      band* b = (band*) band_stack.get(bs_base + i);
-      res[i] = b;
-    }
-    band_stack.popTo(bs_base);
-    return res;
-  }
-}
-
-const char*
-unpacker::attr_definitions::parseLayout(const char* lp, band** &res,
-                                        int curCble) {
-  const char* lp0 = lp;
-  int bs_base = band_stack.length();
-  bool top_level = (bs_base == 0);
-  band* b;
-  enum { can_be_signed = true };  // optional arg to parseIntLayout
-
-  for (bool done = false; !done; ) {
-    switch (*lp++) {
-    case 'B': case 'H': case 'I': case 'V': // unsigned_int
-    case 'S': // signed_int
-      --lp; // reparse
-    case 'F':
-      lp = parseIntLayout(lp, b, EK_INT);
-      break;
-    case 'P':
-      {
-        int le_bci = EK_BCI;
-        if (*lp == 'O') {
-          ++lp;
-          le_bci = EK_BCID;
-        }
-        assert(*lp != 'S');  // no PSH, etc.
-        lp = parseIntLayout(lp, b, EK_INT);
-        b->le_bci = le_bci;
-        if (le_bci == EK_BCI)
-          b->defc = coding::findBySpec(BCI5_spec);
-        else
-          b->defc = coding::findBySpec(BRANCH5_spec);
-      }
-      break;
-    case 'O':
-      lp = parseIntLayout(lp, b, EK_INT, can_be_signed);
-      b->le_bci = EK_BCO;
-      b->defc = coding::findBySpec(BRANCH5_spec);
-      break;
-    case 'N': // replication: 'N' uint '[' elem ... ']'
-      lp = parseIntLayout(lp, b, EK_REPL);
-      assert(*lp == '[');
-      ++lp;
-      lp = parseLayout(lp, b->le_body, curCble);
-      CHECK_(lp);
-      break;
-    case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']'
-      lp = parseIntLayout(lp, b, EK_UN, can_be_signed);
-      {
-        int union_base = band_stack.length();
-        for (;;) {   // for each case
-          band& k_case = *U_NEW(band, 1);
-          CHECK_(lp);
-          band_stack.add(&k_case);
-          k_case.le_kind = EK_CASE;
-          k_case.bn = bands_made++;
-          if (*lp++ != '(') {
-            abort("bad union case");
-            return "";
-          }
-          if (*lp++ != ')') {
-            --lp;  // reparse
-            // Read some case values.  (Use band_stack for temp. storage.)
-            int case_base = band_stack.length();
-            for (;;) {
-              int caseval = 0;
-              lp = parseNumeral(lp, caseval);
-              band_stack.add((void*)(size_t)caseval);
-              if (*lp == '-') {
-                // new in version 160, allow (1-5) for (1,2,3,4,5)
-                if (u->majver < JAVA6_PACKAGE_MAJOR_VERSION) {
-                  abort("bad range in union case label (old archive format)");
-                  return "";
-                }
-                int caselimit = caseval;
-                lp++;
-                lp = parseNumeral(lp, caselimit);
-                if (caseval >= caselimit
-                    || (uint)(caselimit - caseval) > 0x10000) {
-                  // Note:  0x10000 is arbitrary implementation restriction.
-                  // We can remove it later if it's important to.
-                  abort("bad range in union case label");
-                  return "";
-                }
-                for (;;) {
-                  ++caseval;
-                  band_stack.add((void*)(size_t)caseval);
-                  if (caseval == caselimit)  break;
-                }
-              }
-              if (*lp != ',')  break;
-              lp++;
-            }
-            if (*lp++ != ')') {
-              abort("bad case label");
-              return "";
-            }
-            // save away the case labels
-            int ntags = band_stack.length() - case_base;
-            int* tags = U_NEW(int, add_size(ntags, 1));
-            CHECK_(lp);
-            k_case.le_casetags = tags;
-            *tags++ = ntags;
-            for (int i = 0; i < ntags; i++) {
-              *tags++ = ptrlowbits(band_stack.get(case_base+i));
-            }
-            band_stack.popTo(case_base);
-            CHECK_(lp);
-          }
-          // Got le_casetags.  Now grab the body.
-          assert(*lp == '[');
-          ++lp;
-          lp = parseLayout(lp, k_case.le_body, curCble);
-          CHECK_(lp);
-          if (k_case.le_casetags == null)  break;  // done
-        }
-        b->le_body = popBody(union_base);
-      }
-      break;
-    case '(': // call: '(' -?NN* ')'
-      {
-        band& call = *U_NEW(band, 1);
-        CHECK_(lp);
-        band_stack.add(&call);
-        call.le_kind = EK_CALL;
-        call.bn = bands_made++;
-        call.le_body = U_NEW(band*, 2); // fill in later
-        int call_num = 0;
-        lp = parseNumeral(lp, call_num);
-        call.le_back = (call_num <= 0);
-        call_num += curCble;  // numeral is self-relative offset
-        call.le_len = call_num;  //use le_len as scratch
-        calls_to_link.add(&call);
-        CHECK_(lp);
-        if (*lp++ != ')') {
-          abort("bad call label");
-          return "";
-        }
-      }
-      break;
-    case 'K': // reference_type: constant_ref
-    case 'R': // reference_type: schema_ref
-      {
-        int ixTag = CONSTANT_None;
-        if (lp[-1] == 'K') {
-          switch (*lp++) {
-          case 'I': ixTag = CONSTANT_Integer; break;
-          case 'J': ixTag = CONSTANT_Long; break;
-          case 'F': ixTag = CONSTANT_Float; break;
-          case 'D': ixTag = CONSTANT_Double; break;
-          case 'S': ixTag = CONSTANT_String; break;
-          case 'Q': ixTag = CONSTANT_FieldSpecific; break;
-
-          // new in 1.7
-          case 'M': ixTag = CONSTANT_MethodHandle; break;
-          case 'T': ixTag = CONSTANT_MethodType; break;
-          case 'L': ixTag = CONSTANT_LoadableValue; break;
-          }
-        } else {
-          switch (*lp++) {
-          case 'C': ixTag = CONSTANT_Class; break;
-          case 'S': ixTag = CONSTANT_Signature; break;
-          case 'D': ixTag = CONSTANT_NameandType; break;
-          case 'F': ixTag = CONSTANT_Fieldref; break;
-          case 'M': ixTag = CONSTANT_Methodref; break;
-          case 'I': ixTag = CONSTANT_InterfaceMethodref; break;
-          case 'U': ixTag = CONSTANT_Utf8; break; //utf8_ref
-          case 'Q': ixTag = CONSTANT_All; break; //untyped_ref
-
-          // new in 1.7
-          case 'Y': ixTag = CONSTANT_InvokeDynamic; break;
-          case 'B': ixTag = CONSTANT_BootstrapMethod; break;
-          case 'N': ixTag = CONSTANT_AnyMember; break;
-          }
-        }
-        if (ixTag == CONSTANT_None) {
-          abort("bad reference layout");
-          break;
-        }
-        bool nullOK = false;
-        if (*lp == 'N') {
-          nullOK = true;
-          lp++;
-        }
-        lp = parseIntLayout(lp, b, EK_REF);
-        b->defc = coding::findBySpec(UNSIGNED5_spec);
-        b->initRef(ixTag, nullOK);
-      }
-      break;
-    case '[':
-      {
-        // [callable1][callable2]...
-        if (!top_level) {
-          abort("bad nested callable");
-          break;
-        }
-        curCble += 1;
-        NOT_PRODUCT(int call_num = band_stack.length() - bs_base);
-        band& cble = *U_NEW(band, 1);
-        CHECK_(lp);
-        band_stack.add(&cble);
-        cble.le_kind = EK_CBLE;
-        NOT_PRODUCT(cble.le_len = call_num);
-        cble.bn = bands_made++;
-        lp = parseLayout(lp, cble.le_body, curCble);
-      }
-      break;
-    case ']':
-      // Hit a closing brace.  This ends whatever body we were in.
-      done = true;
-      break;
-    case '\0':
-      // Hit a null.  Also ends the (top-level) body.
-      --lp;  // back up, so caller can see the null also
-      done = true;
-      break;
-    default:
-      abort("bad layout");
-      break;
-    }
-    CHECK_(lp);
-  }
-
-  // Return the accumulated bands:
-  res = popBody(bs_base);
-  return lp;
-}
-
-void unpacker::read_attr_defs() {
-  int i;
-
-  // Tell each AD which attrc it is and where its fixed flags are:
-  attr_defs[ATTR_CONTEXT_CLASS].attrc            = ATTR_CONTEXT_CLASS;
-  attr_defs[ATTR_CONTEXT_CLASS].xxx_flags_hi_bn  = e_class_flags_hi;
-  attr_defs[ATTR_CONTEXT_FIELD].attrc            = ATTR_CONTEXT_FIELD;
-  attr_defs[ATTR_CONTEXT_FIELD].xxx_flags_hi_bn  = e_field_flags_hi;
-  attr_defs[ATTR_CONTEXT_METHOD].attrc           = ATTR_CONTEXT_METHOD;
-  attr_defs[ATTR_CONTEXT_METHOD].xxx_flags_hi_bn = e_method_flags_hi;
-  attr_defs[ATTR_CONTEXT_CODE].attrc             = ATTR_CONTEXT_CODE;
-  attr_defs[ATTR_CONTEXT_CODE].xxx_flags_hi_bn   = e_code_flags_hi;
-
-  // Decide whether bands for the optional high flag words are present.
-  attr_defs[ATTR_CONTEXT_CLASS]
-    .setHaveLongFlags(testBit(archive_options, AO_HAVE_CLASS_FLAGS_HI));
-  attr_defs[ATTR_CONTEXT_FIELD]
-    .setHaveLongFlags(testBit(archive_options, AO_HAVE_FIELD_FLAGS_HI));
-  attr_defs[ATTR_CONTEXT_METHOD]
-    .setHaveLongFlags(testBit(archive_options, AO_HAVE_METHOD_FLAGS_HI));
-  attr_defs[ATTR_CONTEXT_CODE]
-    .setHaveLongFlags(testBit(archive_options, AO_HAVE_CODE_FLAGS_HI));
-
-  // Set up built-in attrs.
-  // (The simple ones are hard-coded.  The metadata layouts are not.)
-  const char* md_layout = (
-    // parameter annotations:
-#define MDL0 \
-    "[NB[(1)]]"
-    MDL0
-    // annotations:
-#define MDL1 \
-    "[NH[(1)]]"
-    MDL1
-#define MDL2 \
-    "[RSHNH[RUH(1)]]"
-    MDL2
-    // element_value:
-#define MDL3 \
-    "[TB"                        \
-      "(66,67,73,83,90)[KIH]"    \
-      "(68)[KDH]"                \
-      "(70)[KFH]"                \
-      "(74)[KJH]"                \
-      "(99)[RSH]"                \
-      "(101)[RSHRUH]"            \
-      "(115)[RUH]"               \
-      "(91)[NH[(0)]]"            \
-      "(64)["                    \
-        /* nested annotation: */ \
-        "RSH"                    \
-        "NH[RUH(0)]"             \
-        "]"                      \
-      "()[]"                     \
-    "]"
-    MDL3
-    );
-
-  const char* md_layout_P = md_layout;
-  const char* md_layout_A = md_layout+strlen(MDL0);
-  const char* md_layout_V = md_layout+strlen(MDL0 MDL1 MDL2);
-  assert(0 == strncmp(&md_layout_A[-3], ")]][", 4));
-  assert(0 == strncmp(&md_layout_V[-3], ")]][", 4));
-
-const char* type_md_layout(
-    "[NH[(1)(2)(3)]]"
-    // target-type + target_info
-    "[TB"
-       "(0,1)[B]"
-       "(16)[FH]"
-       "(17,18)[BB]"
-       "(19,20,21)[]"
-       "(22)[B]"
-       "(23)[H]"
-       "(64,65)[NH[PHOHH]]"
-       "(66)[H]"
-       "(67,68,69,70)[PH]"
-       "(71,72,73,74,75)[PHB]"
-       "()[]]"
-    // target-path
-    "[NB[BB]]"
-    // annotation + element_value
-    MDL2
-    MDL3
-);
-
-  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
-    attr_definitions& ad = attr_defs[i];
-    if (i != ATTR_CONTEXT_CODE) {
-      ad.defineLayout(X_ATTR_RuntimeVisibleAnnotations,
-                      "RuntimeVisibleAnnotations", md_layout_A);
-      ad.defineLayout(X_ATTR_RuntimeInvisibleAnnotations,
-                      "RuntimeInvisibleAnnotations", md_layout_A);
-      if (i == ATTR_CONTEXT_METHOD) {
-        ad.defineLayout(METHOD_ATTR_RuntimeVisibleParameterAnnotations,
-                        "RuntimeVisibleParameterAnnotations", md_layout_P);
-        ad.defineLayout(METHOD_ATTR_RuntimeInvisibleParameterAnnotations,
-                        "RuntimeInvisibleParameterAnnotations", md_layout_P);
-        ad.defineLayout(METHOD_ATTR_AnnotationDefault,
-                        "AnnotationDefault", md_layout_V);
-      }
-    }
-    ad.defineLayout(X_ATTR_RuntimeVisibleTypeAnnotations,
-                    "RuntimeVisibleTypeAnnotations", type_md_layout);
-    ad.defineLayout(X_ATTR_RuntimeInvisibleTypeAnnotations,
-                    "RuntimeInvisibleTypeAnnotations", type_md_layout);
-  }
-
-  attr_definition_headers.readData(attr_definition_count);
-  attr_definition_name.readData(attr_definition_count);
-  attr_definition_layout.readData(attr_definition_count);
-
-  CHECK;
-
-  // Initialize correct predef bits, to distinguish predefs from new defs.
-#define ORBIT(n,s) |((julong)1<<n)
-  attr_defs[ATTR_CONTEXT_CLASS].predef
-    = (0 X_ATTR_DO(ORBIT) CLASS_ATTR_DO(ORBIT));
-  attr_defs[ATTR_CONTEXT_FIELD].predef
-    = (0 X_ATTR_DO(ORBIT) FIELD_ATTR_DO(ORBIT));
-  attr_defs[ATTR_CONTEXT_METHOD].predef
-    = (0 X_ATTR_DO(ORBIT) METHOD_ATTR_DO(ORBIT));
-  attr_defs[ATTR_CONTEXT_CODE].predef
-    = (0 O_ATTR_DO(ORBIT) CODE_ATTR_DO(ORBIT));
-#undef ORBIT
-  // Clear out the redef bits, folding them back into predef.
-  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
-    attr_defs[i].predef |= attr_defs[i].redef;
-    attr_defs[i].redef = 0;
-  }
-
-  // Now read the transmitted locally defined attrs.
-  // This will set redef bits again.
-  for (i = 0; i < attr_definition_count; i++) {
-    int    header  = attr_definition_headers.getByte();
-    int    attrc   = ADH_BYTE_CONTEXT(header);
-    int    idx     = ADH_BYTE_INDEX(header);
-    entry* name    = attr_definition_name.getRef();
-    CHECK;
-    entry* layout  = attr_definition_layout.getRef();
-    CHECK;
-    attr_defs[attrc].defineLayout(idx, name, layout->value.b.strval());
-  }
-}
-
-#define NO_ENTRY_YET ((entry*)-1)
-
-static bool isDigitString(bytes& x, int beg, int end) {
-  if (beg == end)  return false;  // null string
-  byte* xptr = x.ptr;
-  for (int i = beg; i < end; i++) {
-    char ch = xptr[i];
-    if (!(ch >= '0' && ch <= '9'))  return false;
-  }
-  return true;
-}
-
-enum {  // constants for parsing class names
-  SLASH_MIN = '.',
-  SLASH_MAX = '/',
-  DOLLAR_MIN = 0,
-  DOLLAR_MAX = '-'
-};
-
-static int lastIndexOf(int chmin, int chmax, bytes& x, int pos) {
-  byte* ptr = x.ptr;
-  for (byte* cp = ptr + pos; --cp >= ptr; ) {
-    assert(x.inBounds(cp));
-    if (*cp >= chmin && *cp <= chmax)
-      return (int)(cp - ptr);
-  }
-  return -1;
-}
-
-maybe_inline
-inner_class* cpool::getIC(entry* inner) {
-  if (inner == null)  return null;
-  assert(inner->tag == CONSTANT_Class);
-  if (inner->inord == NO_INORD)  return null;
-  inner_class* ic = ic_index[inner->inord];
-  assert(ic == null || ic->inner == inner);
-  return ic;
-}
-
-maybe_inline
-inner_class* cpool::getFirstChildIC(entry* outer) {
-  if (outer == null)  return null;
-  assert(outer->tag == CONSTANT_Class);
-  if (outer->inord == NO_INORD)  return null;
-  inner_class* ic = ic_child_index[outer->inord];
-  assert(ic == null || ic->outer == outer);
-  return ic;
-}
-
-maybe_inline
-inner_class* cpool::getNextChildIC(inner_class* child) {
-  inner_class* ic = child->next_sibling;
-  assert(ic == null || ic->outer == child->outer);
-  return ic;
-}
-
-void unpacker::read_ics() {
-  int i;
-  int index_size = cp.tag_count[CONSTANT_Class];
-  inner_class** ic_index       = U_NEW(inner_class*, index_size);
-  inner_class** ic_child_index = U_NEW(inner_class*, index_size);
-  cp.ic_index = ic_index;
-  cp.ic_child_index = ic_child_index;
-  ics = U_NEW(inner_class, ic_count);
-  ic_this_class.readData(ic_count);
-  ic_flags.readData(ic_count);
-  CHECK;
-  // Scan flags to get count of long-form bands.
-  int long_forms = 0;
-  for (i = 0; i < ic_count; i++) {
-    int flags = ic_flags.getInt();  // may be long form!
-    if ((flags & ACC_IC_LONG_FORM) != 0) {
-      long_forms += 1;
-      ics[i].name = NO_ENTRY_YET;
-    }
-    flags &= ~ACC_IC_LONG_FORM;
-    entry* inner = ic_this_class.getRef();
-    CHECK;
-    uint inord = inner->inord;
-    assert(inord < (uint)cp.tag_count[CONSTANT_Class]);
-    if (ic_index[inord] != null) {
-      abort("identical inner class");
-      break;
-    }
-    ic_index[inord] = &ics[i];
-    ics[i].inner = inner;
-    ics[i].flags = flags;
-    assert(cp.getIC(inner) == &ics[i]);
-  }
-  CHECK;
-  //ic_this_class.done();
-  //ic_flags.done();
-  ic_outer_class.readData(long_forms);
-  ic_name.readData(long_forms);
-  for (i = 0; i < ic_count; i++) {
-    if (ics[i].name == NO_ENTRY_YET) {
-      // Long form.
-      ics[i].outer = ic_outer_class.getRefN();
-      CHECK;
-      ics[i].name  = ic_name.getRefN();
-      CHECK;
-    } else {
-      // Fill in outer and name based on inner.
-      bytes& n = ics[i].inner->value.b;
-      bytes pkgOuter;
-      bytes number;
-      bytes name;
-      // Parse n into pkgOuter and name (and number).
-      PRINTCR((5, "parse short IC name %s", n.ptr));
-      int dollar1, dollar2;  // pointers to $ in the pattern
-      // parse n = (<pkg>/)*<outer>($<number>)?($<name>)?
-      int nlen = (int)n.len;
-      int pkglen = lastIndexOf(SLASH_MIN,  SLASH_MAX,  n, nlen) + 1;
-      dollar2    = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, nlen);
-      if (dollar2 < 0) {
-         abort();
-         return;
-      }
-      assert(dollar2 >= pkglen);
-      if (isDigitString(n, dollar2+1, nlen)) {
-        // n = (<pkg>/)*<outer>$<number>
-        number = n.slice(dollar2+1, nlen);
-        name.set(null,0);
-        dollar1 = dollar2;
-      } else if (pkglen < (dollar1
-                           = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, dollar2-1))
-                 && isDigitString(n, dollar1+1, dollar2)) {
-        // n = (<pkg>/)*<outer>$<number>$<name>
-        number = n.slice(dollar1+1, dollar2);
-        name = n.slice(dollar2+1, nlen);
-      } else {
-        // n = (<pkg>/)*<outer>$<name>
-        dollar1 = dollar2;
-        number.set(null,0);
-        name = n.slice(dollar2+1, nlen);
-      }
-      if (number.ptr == null)
-        pkgOuter = n.slice(0, dollar1);
-      else
-        pkgOuter.set(null,0);
-      PRINTCR((5,"=> %s$ 0%s $%s",
-              pkgOuter.string(), number.string(), name.string()));
-
-      if (pkgOuter.ptr != null)
-        ics[i].outer = cp.ensureClass(pkgOuter);
-
-      if (name.ptr != null)
-        ics[i].name = cp.ensureUtf8(name);
-    }
-
-    // update child/sibling list
-    if (ics[i].outer != null) {
-      uint outord = ics[i].outer->inord;
-      if (outord != NO_INORD) {
-        assert(outord < (uint)cp.tag_count[CONSTANT_Class]);
-        ics[i].next_sibling = ic_child_index[outord];
-        ic_child_index[outord] = &ics[i];
-      }
-    }
-  }
-  //ic_outer_class.done();
-  //ic_name.done();
-}
-
-void unpacker::read_classes() {
-  PRINTCR((1,"  ...scanning %d classes...", class_count));
-  class_this.readData(class_count);
-  class_super.readData(class_count);
-  class_interface_count.readData(class_count);
-  class_interface.readData(class_interface_count.getIntTotal());
-
-  CHECK;
-
-  #if 0
-  int i;
-  // Make a little mark on super-classes.
-  for (i = 0; i < class_count; i++) {
-    entry* e = class_super.getRefN();
-    if (e != null)  e->bits |= entry::EB_SUPER;
-  }
-  class_super.rewind();
-  #endif
-
-  // Members.
-  class_field_count.readData(class_count);
-  class_method_count.readData(class_count);
-
-  CHECK;
-
-  int field_count = class_field_count.getIntTotal();
-  int method_count = class_method_count.getIntTotal();
-
-  field_descr.readData(field_count);
-  read_attrs(ATTR_CONTEXT_FIELD, field_count);
-  CHECK;
-
-  method_descr.readData(method_count);
-  read_attrs(ATTR_CONTEXT_METHOD, method_count);
-
-  CHECK;
-
-  read_attrs(ATTR_CONTEXT_CLASS, class_count);
-  CHECK;
-
-  read_code_headers();
-
-  PRINTCR((1,"scanned %d classes, %d fields, %d methods, %d code headers",
-          class_count, field_count, method_count, code_count));
-}
-
-maybe_inline
-int unpacker::attr_definitions::predefCount(uint idx) {
-  return isPredefined(idx) ? flag_count[idx] : 0;
-}
-
-void unpacker::read_attrs(int attrc, int obj_count) {
-  attr_definitions& ad = attr_defs[attrc];
-  assert(ad.attrc == attrc);
-
-  int i, idx, count;
-
-  CHECK;
-
-  bool haveLongFlags = ad.haveLongFlags();
-
-  band& xxx_flags_hi = ad.xxx_flags_hi();
-  assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
-  if (haveLongFlags)
-    xxx_flags_hi.readData(obj_count);
-  CHECK;
-
-  band& xxx_flags_lo = ad.xxx_flags_lo();
-  assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
-  xxx_flags_lo.readData(obj_count);
-  CHECK;
-
-  // pre-scan flags, counting occurrences of each index bit
-  julong indexMask = ad.flagIndexMask();  // which flag bits are index bits?
-  for (i = 0; i < obj_count; i++) {
-    julong indexBits = xxx_flags_hi.getLong(xxx_flags_lo, haveLongFlags);
-    if ((indexBits & ~indexMask) > (ushort)-1) {
-      abort("undefined attribute flag bit");
-      return;
-    }
-    indexBits &= indexMask;  // ignore classfile flag bits
-    for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) {
-      ad.flag_count[idx] += (int)(indexBits & 1);
-    }
-  }
-  // we'll scan these again later for output:
-  xxx_flags_lo.rewind();
-  xxx_flags_hi.rewind();
-
-  band& xxx_attr_count = ad.xxx_attr_count();
-  assert(endsWith(xxx_attr_count.name, "_attr_count"));
-  // There is one count element for each 1<<16 bit set in flags:
-  xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
-  CHECK;
-
-  band& xxx_attr_indexes = ad.xxx_attr_indexes();
-  assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
-  int overflowIndexCount = xxx_attr_count.getIntTotal();
-  xxx_attr_indexes.readData(overflowIndexCount);
-  CHECK;
-  // pre-scan attr indexes, counting occurrences of each value
-  for (i = 0; i < overflowIndexCount; i++) {
-    idx = xxx_attr_indexes.getInt();
-    if (!ad.isIndex(idx)) {
-      abort("attribute index out of bounds");
-      return;
-    }
-    ad.getCount(idx) += 1;
-  }
-  xxx_attr_indexes.rewind();  // we'll scan it again later for output
-
-  // We will need a backward call count for each used backward callable.
-  int backwardCounts = 0;
-  for (idx = 0; idx < ad.layouts.length(); idx++) {
-    layout_definition* lo = ad.getLayout(idx);
-    if (lo != null && ad.getCount(idx) != 0) {
-      // Build the bands lazily, only when they are used.
-      band** bands = ad.buildBands(lo);
-      CHECK;
-      if (lo->hasCallables()) {
-        for (i = 0; bands[i] != null; i++) {
-          if (bands[i]->le_back) {
-            assert(bands[i]->le_kind == EK_CBLE);
-            backwardCounts += 1;
-          }
-        }
-      }
-    }
-  }
-  ad.xxx_attr_calls().readData(backwardCounts);
-  CHECK;
-
-  // Read built-in bands.
-  // Mostly, these are hand-coded equivalents to readBandData().
-  switch (attrc) {
-  case ATTR_CONTEXT_CLASS:
-
-    count = ad.predefCount(CLASS_ATTR_SourceFile);
-    class_SourceFile_RUN.readData(count);
-    CHECK;
-
-    count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
-    class_EnclosingMethod_RC.readData(count);
-    class_EnclosingMethod_RDN.readData(count);
-    CHECK;
-
-    count = ad.predefCount(X_ATTR_Signature);
-    class_Signature_RS.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
-    CHECK;
-
-    count = ad.predefCount(CLASS_ATTR_InnerClasses);
-    class_InnerClasses_N.readData(count);
-    CHECK;
-
-    count = class_InnerClasses_N.getIntTotal();
-    class_InnerClasses_RC.readData(count);
-    class_InnerClasses_F.readData(count);
-    CHECK;
-    // Drop remaining columns wherever flags are zero:
-    count -= class_InnerClasses_F.getIntCount(0);
-    class_InnerClasses_outer_RCN.readData(count);
-    class_InnerClasses_name_RUN.readData(count);
-    CHECK;
-
-    count = ad.predefCount(CLASS_ATTR_ClassFile_version);
-    class_ClassFile_version_minor_H.readData(count);
-    class_ClassFile_version_major_H.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
-    CHECK;
-    break;
-
-  case ATTR_CONTEXT_FIELD:
-
-    count = ad.predefCount(FIELD_ATTR_ConstantValue);
-    field_ConstantValue_KQ.readData(count);
-    CHECK;
-
-    count = ad.predefCount(X_ATTR_Signature);
-    field_Signature_RS.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
-    CHECK;
-    break;
-
-  case ATTR_CONTEXT_METHOD:
-
-    code_count = ad.predefCount(METHOD_ATTR_Code);
-    // Code attrs are handled very specially below...
-
-    count = ad.predefCount(METHOD_ATTR_Exceptions);
-    method_Exceptions_N.readData(count);
-    count = method_Exceptions_N.getIntTotal();
-    method_Exceptions_RC.readData(count);
-    CHECK;
-
-    count = ad.predefCount(X_ATTR_Signature);
-    method_Signature_RS.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
-    ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
-    ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
-    ad.readBandData(METHOD_ATTR_AnnotationDefault);
-    CHECK;
-
-    count = ad.predefCount(METHOD_ATTR_MethodParameters);
-    method_MethodParameters_NB.readData(count);
-    count = method_MethodParameters_NB.getIntTotal();
-    method_MethodParameters_name_RUN.readData(count);
-    method_MethodParameters_flag_FH.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
-    CHECK;
-
-    break;
-
-  case ATTR_CONTEXT_CODE:
-    // (keep this code aligned with its brother in unpacker::write_attrs)
-    count = ad.predefCount(CODE_ATTR_StackMapTable);
-    // disable this feature in old archives!
-    if (count != 0 && majver < JAVA6_PACKAGE_MAJOR_VERSION) {
-      abort("undefined StackMapTable attribute (old archive format)");
-      return;
-    }
-    code_StackMapTable_N.readData(count);
-    CHECK;
-    count = code_StackMapTable_N.getIntTotal();
-    code_StackMapTable_frame_T.readData(count);
-    CHECK;
-    // the rest of it depends in a complicated way on frame tags
-    {
-      int fat_frame_count = 0;
-      int offset_count = 0;
-      int type_count = 0;
-      for (int k = 0; k < count; k++) {
-        int tag = code_StackMapTable_frame_T.getByte();
-        if (tag <= 127) {
-          // (64-127)  [(2)]
-          if (tag >= 64)  type_count++;
-        } else if (tag <= 251) {
-          // (247)     [(1)(2)]
-          // (248-251) [(1)]
-          if (tag >= 247)  offset_count++;
-          if (tag == 247)  type_count++;
-        } else if (tag <= 254) {
-          // (252)     [(1)(2)]
-          // (253)     [(1)(2)(2)]
-          // (254)     [(1)(2)(2)(2)]
-          offset_count++;
-          type_count += (tag - 251);
-        } else {
-          // (255)     [(1)NH[(2)]NH[(2)]]
-          fat_frame_count++;
-        }
-      }
-
-      // done pre-scanning frame tags:
-      code_StackMapTable_frame_T.rewind();
-
-      // deal completely with fat frames:
-      offset_count += fat_frame_count;
-      code_StackMapTable_local_N.readData(fat_frame_count);
-      CHECK;
-      type_count += code_StackMapTable_local_N.getIntTotal();
-      code_StackMapTable_stack_N.readData(fat_frame_count);
-      type_count += code_StackMapTable_stack_N.getIntTotal();
-      CHECK;
-      // read the rest:
-      code_StackMapTable_offset.readData(offset_count);
-      code_StackMapTable_T.readData(type_count);
-      CHECK;
-      // (7) [RCH]
-      count = code_StackMapTable_T.getIntCount(7);
-      code_StackMapTable_RC.readData(count);
-      CHECK;
-      // (8) [PH]
-      count = code_StackMapTable_T.getIntCount(8);
-      code_StackMapTable_P.readData(count);
-      CHECK;
-    }
-
-    count = ad.predefCount(CODE_ATTR_LineNumberTable);
-    code_LineNumberTable_N.readData(count);
-    CHECK;
-    count = code_LineNumberTable_N.getIntTotal();
-    code_LineNumberTable_bci_P.readData(count);
-    code_LineNumberTable_line.readData(count);
-    CHECK;
-
-    count = ad.predefCount(CODE_ATTR_LocalVariableTable);
-    code_LocalVariableTable_N.readData(count);
-    CHECK;
-    count = code_LocalVariableTable_N.getIntTotal();
-    code_LocalVariableTable_bci_P.readData(count);
-    code_LocalVariableTable_span_O.readData(count);
-    code_LocalVariableTable_name_RU.readData(count);
-    code_LocalVariableTable_type_RS.readData(count);
-    code_LocalVariableTable_slot.readData(count);
-    CHECK;
-
-    count = ad.predefCount(CODE_ATTR_LocalVariableTypeTable);
-    code_LocalVariableTypeTable_N.readData(count);
-    count = code_LocalVariableTypeTable_N.getIntTotal();
-    code_LocalVariableTypeTable_bci_P.readData(count);
-    code_LocalVariableTypeTable_span_O.readData(count);
-    code_LocalVariableTypeTable_name_RU.readData(count);
-    code_LocalVariableTypeTable_type_RS.readData(count);
-    code_LocalVariableTypeTable_slot.readData(count);
-    CHECK;
-
-    ad.readBandData(X_ATTR_RuntimeVisibleTypeAnnotations);
-    ad.readBandData(X_ATTR_RuntimeInvisibleTypeAnnotations);
-    CHECK;
-
-    break;
-  }
-
-  // Read compressor-defined bands.
-  for (idx = 0; idx < ad.layouts.length(); idx++) {
-    if (ad.getLayout(idx) == null)
-      continue;  // none at this fixed index <32
-    if (idx < (int)ad.flag_limit && ad.isPredefined(idx))
-      continue;  // already handled
-    if (ad.getCount(idx) == 0)
-      continue;  // no attributes of this type (then why transmit layouts?)
-    ad.readBandData(idx);
-  }
-}
-
-void unpacker::attr_definitions::readBandData(int idx) {
-  int j;
-  uint count = getCount(idx);
-  if (count == 0)  return;
-  layout_definition* lo = getLayout(idx);
-  if (lo != null) {
-    PRINTCR((1, "counted %d [redefined = %d predefined = %d] attributes of type %s.%s",
-            count, isRedefined(idx), isPredefined(idx),
-            ATTR_CONTEXT_NAME[attrc], lo->name));
-  }
-  bool hasCallables = lo->hasCallables();
-  band** bands = lo->bands();
-  if (!hasCallables) {
-    // Read through the rest of the bands in a regular way.
-    readBandData(bands, count);
-  } else {
-    // Deal with the callables.
-    // First set up the forward entry count for each callable.
-    // This is stored on band::length of the callable.
-    bands[0]->expectMoreLength(count);
-    for (j = 0; bands[j] != null; j++) {
-      band& j_cble = *bands[j];
-      assert(j_cble.le_kind == EK_CBLE);
-      if (j_cble.le_back) {
-        // Add in the predicted effects of backward calls, too.
-        int back_calls = xxx_attr_calls().getInt();
-        j_cble.expectMoreLength(back_calls);
-        // In a moment, more forward calls may increment j_cble.length.
-      }
-    }
-    // Now consult whichever callables have non-zero entry counts.
-    readBandData(bands, (uint)-1);
-  }
-}
-
-// Recursive helper to the previous function:
-void unpacker::attr_definitions::readBandData(band** body, uint count) {
-  int j, k;
-  for (j = 0; body[j] != null; j++) {
-    band& b = *body[j];
-    if (b.defc != null) {
-      // It has data, so read it.
-      b.readData(count);
-    }
-    switch (b.le_kind) {
-    case EK_REPL:
-      {
-        int reps = b.getIntTotal();
-        readBandData(b.le_body, reps);
-      }
-      break;
-    case EK_UN:
-      {
-        int remaining = count;
-        for (k = 0; b.le_body[k] != null; k++) {
-          band& k_case = *b.le_body[k];
-          int   k_count = 0;
-          if (k_case.le_casetags == null) {
-            k_count = remaining;  // last (empty) case
-          } else {
-            int* tags = k_case.le_casetags;
-            int ntags = *tags++;  // 1st element is length (why not?)
-            while (ntags-- > 0) {
-              int tag = *tags++;
-              k_count += b.getIntCount(tag);
-            }
-          }
-          readBandData(k_case.le_body, k_count);
-          remaining -= k_count;
-        }
-        assert(remaining == 0);
-      }
-      break;
-    case EK_CALL:
-      // Push the count forward, if it is not a backward call.
-      if (!b.le_back) {
-        band& cble = *b.le_body[0];
-        assert(cble.le_kind == EK_CBLE);
-        cble.expectMoreLength(count);
-      }
-      break;
-    case EK_CBLE:
-      assert((int)count == -1);  // incoming count is meaningless
-      k = b.length;
-      assert(k >= 0);
-      // This is intended and required for non production mode.
-      assert((b.length = -1)); // make it unable to accept more calls now.
-      readBandData(b.le_body, k);
-      break;
-    }
-  }
-}
-
-static inline
-band** findMatchingCase(int matchTag, band** cases) {
-  for (int k = 0; cases[k] != null; k++) {
-    band& k_case = *cases[k];
-    if (k_case.le_casetags != null) {
-      // If it has tags, it must match a tag.
-      int* tags = k_case.le_casetags;
-      int ntags = *tags++;  // 1st element is length
-      for (; ntags > 0; ntags--) {
-        int tag = *tags++;
-        if (tag == matchTag)
-          break;
-      }
-      if (ntags == 0)
-        continue;   // does not match
-    }
-    return k_case.le_body;
-  }
-  return null;
-}
-
-// write attribute band data:
-void unpacker::putlayout(band** body) {
-  int i;
-  int prevBII = -1;
-  int prevBCI = -1;
-  if (body == NULL) {
-    abort("putlayout: unexpected NULL for body");
-    return;
-  }
-  for (i = 0; body[i] != null; i++) {
-    band& b = *body[i];
-    byte le_kind = b.le_kind;
-
-    // Handle scalar part, if any.
-    int    x = 0;
-    entry* e = null;
-    if (b.defc != null) {
-      // It has data, so unparse an element.
-      if (b.ixTag != CONSTANT_None) {
-        assert(le_kind == EK_REF);
-        if (b.ixTag == CONSTANT_FieldSpecific)
-          e = b.getRefUsing(cp.getKQIndex());
-        else
-          e = b.getRefN();
-        CHECK;
-        switch (b.le_len) {
-        case 0: break;
-        case 1: putu1ref(e); break;
-        case 2: putref(e); break;
-        case 4: putu2(0); putref(e); break;
-        default: assert(false);
-        }
-      } else {
-        assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN);
-        x = b.getInt();
-
-        assert(!b.le_bci || prevBCI == (int)to_bci(prevBII));
-        switch (b.le_bci) {
-        case EK_BCI:   // PH:  transmit R(bci), store bci
-          x = to_bci(prevBII = x);
-          prevBCI = x;
-          break;
-        case EK_BCID:  // POH: transmit D(R(bci)), store bci
-          x = to_bci(prevBII += x);
-          prevBCI = x;
-          break;
-        case EK_BCO:   // OH:  transmit D(R(bci)), store D(bci)
-          x = to_bci(prevBII += x) - prevBCI;
-          prevBCI += x;
-          break;
-        }
-        assert(!b.le_bci || prevBCI == (int)to_bci(prevBII));
-
-        CHECK;
-        switch (b.le_len) {
-        case 0: break;
-        case 1: putu1(x); break;
-        case 2: putu2(x); break;
-        case 4: putu4(x); break;
-        default: assert(false);
-        }
-      }
-    }
-
-    // Handle subparts, if any.
-    switch (le_kind) {
-    case EK_REPL:
-      // x is the repeat count
-      while (x-- > 0) {
-        putlayout(b.le_body);
-      }
-      break;
-    case EK_UN:
-      // x is the tag
-      putlayout(findMatchingCase(x, b.le_body));
-      break;
-    case EK_CALL:
-      {
-        band& cble = *b.le_body[0];
-        assert(cble.le_kind == EK_CBLE);
-        assert(cble.le_len == b.le_len);
-        putlayout(cble.le_body);
-      }
-      break;
-
-    #ifndef PRODUCT
-    case EK_CBLE:
-    case EK_CASE:
-      assert(false);  // should not reach here
-    #endif
-    }
-  }
-}
-
-void unpacker::read_files() {
-  file_name.readData(file_count);
-  if (testBit(archive_options, AO_HAVE_FILE_SIZE_HI))
-    file_size_hi.readData(file_count);
-  file_size_lo.readData(file_count);
-  if (testBit(archive_options, AO_HAVE_FILE_MODTIME))
-    file_modtime.readData(file_count);
-  int allFiles = file_count + class_count;
-  if (testBit(archive_options, AO_HAVE_FILE_OPTIONS)) {
-    file_options.readData(file_count);
-    // FO_IS_CLASS_STUB might be set, causing overlap between classes and files
-    for (int i = 0; i < file_count; i++) {
-      if ((file_options.getInt() & FO_IS_CLASS_STUB) != 0) {
-        allFiles -= 1;  // this one counts as both class and file
-      }
-    }
-    file_options.rewind();
-  }
-  assert((default_file_options & FO_IS_CLASS_STUB) == 0);
-  files_remaining = allFiles;
-}
-
-maybe_inline
-void unpacker::get_code_header(int& max_stack,
-                               int& max_na_locals,
-                               int& handler_count,
-                               int& cflags) {
-  int sc = code_headers.getByte();
-  if (sc == 0) {
-    max_stack = max_na_locals = handler_count = cflags = -1;
-    return;
-  }
-  // Short code header is the usual case:
-  int nh;
-  int mod;
-  if (sc < 1 + 12*12) {
-    sc -= 1;
-    nh = 0;
-    mod = 12;
-  } else if (sc < 1 + 12*12 + 8*8) {
-    sc -= 1 + 12*12;
-    nh = 1;
-    mod = 8;
-  } else {
-    assert(sc < 1 + 12*12 + 8*8 + 7*7);
-    sc -= 1 + 12*12 + 8*8;
-    nh = 2;
-    mod = 7;
-  }
-  max_stack     = sc % mod;
-  max_na_locals = sc / mod;  // caller must add static, siglen
-  handler_count = nh;
-  if (testBit(archive_options, AO_HAVE_ALL_CODE_FLAGS))
-    cflags      = -1;
-  else
-    cflags      = 0;  // this one has no attributes
-}
-
-// Cf. PackageReader.readCodeHeaders
-void unpacker::read_code_headers() {
-  code_headers.readData(code_count);
-  CHECK;
-  int totalHandlerCount = 0;
-  int totalFlagsCount   = 0;
-  for (int i = 0; i < code_count; i++) {
-    int max_stack, max_locals, handler_count, cflags;
-    get_code_header(max_stack, max_locals, handler_count, cflags);
-    if (max_stack < 0)      code_max_stack.expectMoreLength(1);
-    if (max_locals < 0)     code_max_na_locals.expectMoreLength(1);
-    if (handler_count < 0)  code_handler_count.expectMoreLength(1);
-    else                    totalHandlerCount += handler_count;
-    if (cflags < 0)         totalFlagsCount += 1;
-  }
-  code_headers.rewind();  // replay later during writing
-
-  code_max_stack.readData();
-  code_max_na_locals.readData();
-  code_handler_count.readData();
-  totalHandlerCount += code_handler_count.getIntTotal();
-  CHECK;
-
-  // Read handler specifications.
-  // Cf. PackageReader.readCodeHandlers.
-  code_handler_start_P.readData(totalHandlerCount);
-  code_handler_end_PO.readData(totalHandlerCount);
-  code_handler_catch_PO.readData(totalHandlerCount);
-  code_handler_class_RCN.readData(totalHandlerCount);
-  CHECK;
-
-  read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
-  CHECK;
-}
-
-static inline bool is_in_range(uint n, uint min, uint max) {
-  return n - min <= max - min;  // unsigned arithmetic!
-}
-static inline bool is_field_op(int bc) {
-  return is_in_range(bc, bc_getstatic, bc_putfield);
-}
-static inline bool is_invoke_init_op(int bc) {
-  return is_in_range(bc, _invokeinit_op, _invokeinit_limit-1);
-}
-static inline bool is_self_linker_op(int bc) {
-  return is_in_range(bc, _self_linker_op, _self_linker_limit-1);
-}
-static bool is_branch_op(int bc) {
-  return is_in_range(bc, bc_ifeq,   bc_jsr)
-      || is_in_range(bc, bc_ifnull, bc_jsr_w);
-}
-static bool is_local_slot_op(int bc) {
-  return is_in_range(bc, bc_iload,  bc_aload)
-      || is_in_range(bc, bc_istore, bc_astore)
-      || bc == bc_iinc || bc == bc_ret;
-}
-band* unpacker::ref_band_for_op(int bc) {
-  switch (bc) {
-  case bc_ildc:
-  case bc_ildc_w:
-    return &bc_intref;
-  case bc_fldc:
-  case bc_fldc_w:
-    return &bc_floatref;
-  case bc_lldc2_w:
-    return &bc_longref;
-  case bc_dldc2_w:
-    return &bc_doubleref;
-  case bc_sldc:
-  case bc_sldc_w:
-    return &bc_stringref;
-  case bc_cldc:
-  case bc_cldc_w:
-    return &bc_classref;
-  case bc_qldc: case bc_qldc_w:
-    return &bc_loadablevalueref;
-
-  case bc_getstatic:
-  case bc_putstatic:
-  case bc_getfield:
-  case bc_putfield:
-    return &bc_fieldref;
-
-  case _invokespecial_int:
-  case _invokestatic_int:
-    return &bc_imethodref;
-  case bc_invokevirtual:
-  case bc_invokespecial:
-  case bc_invokestatic:
-    return &bc_methodref;
-  case bc_invokeinterface:
-    return &bc_imethodref;
-  case bc_invokedynamic:
-    return &bc_indyref;
-
-  case bc_new:
-  case bc_anewarray:
-  case bc_checkcast:
-  case bc_instanceof:
-  case bc_multianewarray:
-    return &bc_classref;
-  }
-  return null;
-}
-
-maybe_inline
-band* unpacker::ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar) {
-  if (!is_self_linker_op(bc))  return null;
-  int idx = (bc - _self_linker_op);
-  bool isSuper = (idx >= _self_linker_super_flag);
-  if (isSuper)  idx -= _self_linker_super_flag;
-  bool isAload = (idx >= _self_linker_aload_flag);
-  if (isAload)  idx -= _self_linker_aload_flag;
-  int origBC = _first_linker_op + idx;
-  bool isField = is_field_op(origBC);
-  isAloadVar = isAload;
-  origBCVar  = _first_linker_op + idx;
-  if (!isSuper)
-    return isField? &bc_thisfield: &bc_thismethod;
-  else
-    return isField? &bc_superfield: &bc_supermethod;
-}
-
-// Cf. PackageReader.readByteCodes
-inline  // called exactly once => inline
-void unpacker::read_bcs() {
-  PRINTCR((3, "reading compressed bytecodes and operands for %d codes...",
-          code_count));
-
-  // read from bc_codes and bc_case_count
-  fillbytes all_switch_ops;
-  all_switch_ops.init();
-  CHECK;
-
-  // Read directly from rp/rplimit.
-  //Do this later:  bc_codes.readData(...)
-  byte* rp0 = rp;
-
-  band* bc_which;
-  byte* opptr = rp;
-  byte* oplimit = rplimit;
-
-  bool  isAload;  // passed by ref and then ignored
-  int   junkBC;   // passed by ref and then ignored
-  for (int k = 0; k < code_count; k++) {
-    // Scan one method:
-    for (;;) {
-      if (opptr+2 > oplimit) {
-        rp = opptr;
-        ensure_input(2);
-        oplimit = rplimit;
-        rp = rp0;  // back up
-      }
-      if (opptr == oplimit) { abort(); break; }
-      int bc = *opptr++ & 0xFF;
-      bool isWide = false;
-      if (bc == bc_wide) {
-        if (opptr == oplimit) { abort(); break; }
-        bc = *opptr++ & 0xFF;
-        isWide = true;
-      }
-      // Adjust expectations of various band sizes.
-      switch (bc) {
-      case bc_tableswitch:
-      case bc_lookupswitch:
-        all_switch_ops.addByte(bc);
-        break;
-      case bc_iinc:
-        bc_local.expectMoreLength(1);
-        bc_which = isWide ? &bc_short : &bc_byte;
-        bc_which->expectMoreLength(1);
-        break;
-      case bc_sipush:
-        bc_short.expectMoreLength(1);
-        break;
-      case bc_bipush:
-        bc_byte.expectMoreLength(1);
-        break;
-      case bc_newarray:
-        bc_byte.expectMoreLength(1);
-        break;
-      case bc_multianewarray:
-        assert(ref_band_for_op(bc) == &bc_classref);
-        bc_classref.expectMoreLength(1);
-        bc_byte.expectMoreLength(1);
-        break;
-      case bc_ref_escape:
-        bc_escrefsize.expectMoreLength(1);
-        bc_escref.expectMoreLength(1);
-        break;
-      case bc_byte_escape:
-        bc_escsize.expectMoreLength(1);
-        // bc_escbyte will have to be counted too
-        break;
-      default:
-        if (is_invoke_init_op(bc)) {
-          bc_initref.expectMoreLength(1);
-          break;
-        }
-        bc_which = ref_band_for_self_op(bc, isAload, junkBC);
-        if (bc_which != null) {
-          bc_which->expectMoreLength(1);
-          break;
-        }
-        if (is_branch_op(bc)) {
-          bc_label.expectMoreLength(1);
-          break;
-        }
-        bc_which = ref_band_for_op(bc);
-        if (bc_which != null) {
-          bc_which->expectMoreLength(1);
-          assert(bc != bc_multianewarray);  // handled elsewhere
-          break;
-        }
-        if (is_local_slot_op(bc)) {
-          bc_local.expectMoreLength(1);
-          break;
-        }
-        break;
-      case bc_end_marker:
-        // Increment k and test against code_count.
-        goto doneScanningMethod;
-      }
-    }
-  doneScanningMethod:{}
-    if (aborting())  break;
-  }
-
-  // Go through the formality, so we can use it in a regular fashion later:
-  assert(rp == rp0);
-  bc_codes.readData((int)(opptr - rp));
-
-  int i = 0;
-
-  // To size instruction bands correctly, we need info on switches:
-  bc_case_count.readData((int)all_switch_ops.size());
-  for (i = 0; i < (int)all_switch_ops.size(); i++) {
-    int caseCount = bc_case_count.getInt();
-    int bc        = all_switch_ops.getByte(i);
-    bc_label.expectMoreLength(1+caseCount); // default label + cases
-    bc_case_value.expectMoreLength(bc == bc_tableswitch ? 1 : caseCount);
-    PRINTCR((2, "switch bc=%d caseCount=%d", bc, caseCount));
-  }
-  bc_case_count.rewind();  // uses again for output
-
-  all_switch_ops.free();
-
-  for (i = e_bc_case_value; i <= e_bc_escsize; i++) {
-    all_bands[i].readData();
-  }
-
-  // The bc_escbyte band is counted by the immediately previous band.
-  bc_escbyte.readData(bc_escsize.getIntTotal());
-
-  PRINTCR((3, "scanned %d opcode and %d operand bytes for %d codes...",
-          (int)(bc_codes.size()),
-          (int)(bc_escsize.maxRP() - bc_case_value.minRP()),
-          code_count));
-}
-
-void unpacker::read_bands() {
-  byte* rp0 = rp;
-  CHECK;
-  read_file_header();
-  CHECK;
-
-  if (cp.nentries == 0) {
-    // read_file_header failed to read a CP, because it copied a JAR.
-    return;
-  }
-
-  // Do this after the file header has been read:
-  check_options();
-
-  read_cp();
-  CHECK;
-  read_attr_defs();
-  CHECK;
-  read_ics();
-  CHECK;
-  read_classes();
-  CHECK;
-  read_bcs();
-  CHECK;
-  read_files();
-}
-
-/// CP routines
-
-entry*& cpool::hashTabRef(byte tag, bytes& b) {
-  PRINTCR((5, "hashTabRef tag=%d %s[%d]", tag, b.string(), b.len));
-  uint hash = tag + (int)b.len;
-  for (int i = 0; i < (int)b.len; i++) {
-    hash = hash * 31 + (0xFF & b.ptr[i]);
-  }
-  entry**  ht = hashTab;
-  int    hlen = hashTabLength;
-  assert((hlen & (hlen-1)) == 0);  // must be power of 2
-  uint hash1 = hash & (hlen-1);    // == hash % hlen
-  uint hash2 = 0;                  // lazily computed (requires mod op.)
-  int probes = 0;
-  while (ht[hash1] != null) {
-    entry& e = *ht[hash1];
-    if (e.value.b.equals(b) && e.tag == tag)
-      break;
-    if (hash2 == 0)
-      // Note:  hash2 must be relatively prime to hlen, hence the "|1".
-      hash2 = (((hash % 499) & (hlen-1)) | 1);
-    hash1 += hash2;
-    if (hash1 >= (uint)hlen)  hash1 -= hlen;
-    assert(hash1 < (uint)hlen);
-    assert(++probes < hlen);
-  }
-  #ifndef PRODUCT
-  hash_probes[0] += 1;
-  hash_probes[1] += probes;
-  #endif
-  PRINTCR((5, " => @%d %p", hash1, ht[hash1]));
-  return ht[hash1];
-}
-
-maybe_inline
-static void insert_extra(entry* e, ptrlist& extras) {
-  // This ordering helps implement the Pack200 requirement
-  // of a predictable CP order in the class files produced.
-  e->inord = NO_INORD;  // mark as an "extra"
-  extras.add(e);
-  // Note:  We will sort the list (by string-name) later.
-}
-
-entry* cpool::ensureUtf8(bytes& b) {
-  entry*& ix = hashTabRef(CONSTANT_Utf8, b);
-  if (ix != null)  return ix;
-  // Make one.
-  if (nentries == maxentries) {
-    abort("cp utf8 overflow");
-    return &entries[tag_base[CONSTANT_Utf8]];  // return something
-  }
-  entry& e = entries[nentries++];
-  e.tag = CONSTANT_Utf8;
-  u->saveTo(e.value.b, b);
-  assert(&e >= first_extra_entry);
-  insert_extra(&e, tag_extras[CONSTANT_Utf8]);
-  PRINTCR((4,"ensureUtf8 miss %s", e.string()));
-  return ix = &e;
-}
-
-entry* cpool::ensureClass(bytes& b) {
-  entry*& ix = hashTabRef(CONSTANT_Class, b);
-  if (ix != null)  return ix;
-  // Make one.
-  if (nentries == maxentries) {
-    abort("cp class overflow");
-    return &entries[tag_base[CONSTANT_Class]];  // return something
-  }
-  entry& e = entries[nentries++];
-  e.tag = CONSTANT_Class;
-  e.nrefs = 1;
-  e.refs = U_NEW(entry*, 1);
-  ix = &e;  // hold my spot in the index
-  entry* utf = ensureUtf8(b);
-  e.refs[0] = utf;
-  e.value.b = utf->value.b;
-  assert(&e >= first_extra_entry);
-  insert_extra(&e, tag_extras[CONSTANT_Class]);
-  PRINTCR((4,"ensureClass miss %s", e.string()));
-  return &e;
-}
-
-void cpool::expandSignatures() {
-  int i;
-  int nsigs = 0;
-  int nreused = 0;
-  int first_sig = tag_base[CONSTANT_Signature];
-  int sig_limit = tag_count[CONSTANT_Signature] + first_sig;
-  fillbytes buf;
-  buf.init(1<<10);
-  CHECK;
-  for (i = first_sig; i < sig_limit; i++) {
-    entry& e = entries[i];
-    assert(e.tag == CONSTANT_Signature);
-    int refnum = 0;
-    bytes form = e.refs[refnum++]->asUtf8();
-    buf.empty();
-    for (int j = 0; j < (int)form.len; j++) {
-      int c = form.ptr[j];
-      buf.addByte(c);
-      if (c == 'L') {
-        entry* cls = e.refs[refnum++];
-        buf.append(cls->className()->asUtf8());
-      }
-    }
-    assert(refnum == e.nrefs);
-    bytes& sig = buf.b;
-    PRINTCR((5,"signature %d %s -> %s", i, form.ptr, sig.ptr));
-
-    // try to find a pre-existing Utf8:
-    entry* &e2 = hashTabRef(CONSTANT_Utf8, sig);
-    if (e2 != null) {
-      assert(e2->isUtf8(sig));
-      e.value.b = e2->value.b;
-      e.refs[0] = e2;
-      e.nrefs = 1;
-      PRINTCR((5,"signature replaced %d => %s", i, e.string()));
-      nreused++;
-    } else {
-      // there is no other replacement; reuse this CP entry as a Utf8
-      u->saveTo(e.value.b, sig);
-      e.tag = CONSTANT_Utf8;
-      e.nrefs = 0;
-      e2 = &e;
-      PRINTCR((5,"signature changed %d => %s", e.inord, e.string()));
-    }
-    nsigs++;
-  }
-  PRINTCR((1,"expanded %d signatures (reused %d utfs)", nsigs, nreused));
-  buf.free();
-
-  // go expunge all references to remaining signatures:
-  for (i = 0; i < (int)nentries; i++) {
-    entry& e = entries[i];
-    for (int j = 0; j < e.nrefs; j++) {
-      entry*& e2 = e.refs[j];
-      if (e2 != null && e2->tag == CONSTANT_Signature)
-        e2 = e2->refs[0];
-    }
-  }
-}
-
-bool isLoadableValue(int tag) {
-  switch(tag) {
-    case CONSTANT_Integer:
-    case CONSTANT_Float:
-    case CONSTANT_Long:
-    case CONSTANT_Double:
-    case CONSTANT_String:
-    case CONSTANT_Class:
-    case CONSTANT_MethodHandle:
-    case CONSTANT_MethodType:
-      return true;
-    default:
-      return false;
-  }
-}
-/*
- * this method can be used to size an array using null as the parameter,
- * thereafter can be reused to initialize the array using a valid pointer
- * as a parameter.
- */
-int cpool::initLoadableValues(entry** loadable_entries) {
-  int loadable_count = 0;
-  for (int i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
-    int tag = TAGS_IN_ORDER[i];
-    if (!isLoadableValue(tag))
-      continue;
-    if (loadable_entries != NULL) {
-      for (int n = 0 ; n < tag_count[tag] ; n++) {
-        loadable_entries[loadable_count + n] = &entries[tag_base[tag] + n];
-      }
-    }
-    loadable_count += tag_count[tag];
-  }
-  return loadable_count;
-}
-
-// Initialize various views into the constant pool.
-void cpool::initGroupIndexes() {
-  // Initialize All
-  int all_count = 0;
-  for (int tag = CONSTANT_None ; tag < CONSTANT_Limit ; tag++) {
-    all_count += tag_count[tag];
-  }
-  entry* all_entries = &entries[tag_base[CONSTANT_None]];
-  tag_group_count[CONSTANT_All - CONSTANT_All] = all_count;
-  tag_group_index[CONSTANT_All - CONSTANT_All].init(all_count, all_entries, CONSTANT_All);
-
-  // Initialize LoadableValues
-  int loadable_count = initLoadableValues(NULL);
-  entry** loadable_entries = U_NEW(entry*, loadable_count);
-  initLoadableValues(loadable_entries);
-  tag_group_count[CONSTANT_LoadableValue - CONSTANT_All] = loadable_count;
-  tag_group_index[CONSTANT_LoadableValue - CONSTANT_All].init(loadable_count,
-                  loadable_entries, CONSTANT_LoadableValue);
-
-// Initialize AnyMembers
-  int any_count = tag_count[CONSTANT_Fieldref] +
-                  tag_count[CONSTANT_Methodref] +
-                  tag_count[CONSTANT_InterfaceMethodref];
-  entry *any_entries = &entries[tag_base[CONSTANT_Fieldref]];
-  tag_group_count[CONSTANT_AnyMember - CONSTANT_All] = any_count;
-  tag_group_index[CONSTANT_AnyMember - CONSTANT_All].init(any_count,
-                                               any_entries, CONSTANT_AnyMember);
-}
-
-void cpool::initMemberIndexes() {
-  // This function does NOT refer to any class schema.
-  // It is totally internal to the cpool.
-  int i, j;
-
-  // Get the pre-existing indexes:
-  int   nclasses = tag_count[CONSTANT_Class];
-  entry* classes = tag_base[CONSTANT_Class] + entries;
-  int   nfields  = tag_count[CONSTANT_Fieldref];
-  entry* fields  = tag_base[CONSTANT_Fieldref] + entries;
-  int   nmethods = tag_count[CONSTANT_Methodref];
-  entry* methods = tag_base[CONSTANT_Methodref] + entries;
-
-  int*     field_counts  = T_NEW(int, nclasses);
-  int*     method_counts = T_NEW(int, nclasses);
-  cpindex* all_indexes   = U_NEW(cpindex, nclasses*2);
-  entry**  field_ix      = U_NEW(entry*, add_size(nfields, nclasses));
-  entry**  method_ix     = U_NEW(entry*, add_size(nmethods, nclasses));
-
-  for (j = 0; j < nfields; j++) {
-    entry& f = fields[j];
-    i = f.memberClass()->inord;
-    assert(i < nclasses);
-    field_counts[i]++;
-  }
-  for (j = 0; j < nmethods; j++) {
-    entry& m = methods[j];
-    i = m.memberClass()->inord;
-    assert(i < nclasses);
-    method_counts[i]++;
-  }
-
-  int fbase = 0, mbase = 0;
-  for (i = 0; i < nclasses; i++) {
-    int fc = field_counts[i];
-    int mc = method_counts[i];
-    all_indexes[i*2+0].init(fc, field_ix+fbase,
-                            CONSTANT_Fieldref  + SUBINDEX_BIT);
-    all_indexes[i*2+1].init(mc, method_ix+mbase,
-                            CONSTANT_Methodref + SUBINDEX_BIT);
-    // reuse field_counts and member_counts as fill pointers:
-    field_counts[i] = fbase;
-    method_counts[i] = mbase;
-    PRINTCR((3, "class %d fields @%d[%d] methods @%d[%d]",
-            i, fbase, fc, mbase, mc));
-    fbase += fc+1;
-    mbase += mc+1;
-    // (the +1 leaves a space between every subarray)
-  }
-  assert(fbase == nfields+nclasses);
-  assert(mbase == nmethods+nclasses);
-
-  for (j = 0; j < nfields; j++) {
-    entry& f = fields[j];
-    i = f.memberClass()->inord;
-    field_ix[field_counts[i]++] = &f;
-  }
-  for (j = 0; j < nmethods; j++) {
-    entry& m = methods[j];
-    i = m.memberClass()->inord;
-    method_ix[method_counts[i]++] = &m;
-  }
-
-  member_indexes = all_indexes;
-
-#ifndef PRODUCT
-  // Test the result immediately on every class and field.
-  int fvisited = 0, mvisited = 0;
-  int prevord, len;
-  for (i = 0; i < nclasses; i++) {
-    entry*   cls = &classes[i];
-    cpindex* fix = getFieldIndex(cls);
-    cpindex* mix = getMethodIndex(cls);
-    PRINTCR((2, "field and method index for %s [%d] [%d]",
-            cls->string(), mix->len, fix->len));
-    prevord = -1;
-    for (j = 0, len = fix->len; j < len; j++) {
-      entry* f = fix->get(j);
-      assert(f != null);
-      PRINTCR((3, "- field %s", f->string()));
-      assert(f->memberClass() == cls);
-      assert(prevord < (int)f->inord);
-      prevord = f->inord;
-      fvisited++;
-    }
-    assert(fix->base2[j] == null);
-    prevord = -1;
-    for (j = 0, len = mix->len; j < len; j++) {
-      entry* m = mix->get(j);
-      assert(m != null);
-      PRINTCR((3, "- method %s", m->string()));
-      assert(m->memberClass() == cls);
-      assert(prevord < (int)m->inord);
-      prevord = m->inord;
-      mvisited++;
-    }
-    assert(mix->base2[j] == null);
-  }
-  assert(fvisited == nfields);
-  assert(mvisited == nmethods);
-#endif
-
-  // Free intermediate buffers.
-  u->free_temps();
-}
-
-void entry::requestOutputIndex(cpool& cp, int req) {
-  assert(outputIndex <= REQUESTED_NONE);  // must not have assigned indexes yet
-  if (tag == CONSTANT_Signature) {
-    ref(0)->requestOutputIndex(cp, req);
-    return;
-  }
-  assert(req == REQUESTED || req == REQUESTED_LDC);
-  if (outputIndex != REQUESTED_NONE) {
-    if (req == REQUESTED_LDC)
-      outputIndex = req;  // this kind has precedence
-    return;
-  }
-  outputIndex = req;
-  //assert(!cp.outputEntries.contains(this));
-  assert(tag != CONSTANT_Signature);
-  // The BSMs are jetisoned to a side table, however all references
-  // that the BSMs refer to,  need to be considered.
-  if (tag == CONSTANT_BootstrapMethod) {
-    // this is a a pseudo-op entry; an attribute will be generated later on
-    cp.requested_bsms.add(this);
-  } else {
-    // all other tag types go into real output file CP:
-    cp.outputEntries.add(this);
-  }
-  for (int j = 0; j < nrefs; j++) {
-    ref(j)->requestOutputIndex(cp);
-  }
-}
-
-void cpool::resetOutputIndexes() {
-    /*
-     * reset those few entries that are being used in the current class
-     * (Caution since this method is called after every class written, a loop
-     * over every global constant pool entry would be a quadratic cost.)
-     */
-
-  int noes    = outputEntries.length();
-  entry** oes = (entry**) outputEntries.base();
-  for (int i = 0 ; i < noes ; i++) {
-    entry& e = *oes[i];
-    e.outputIndex = REQUESTED_NONE;
-  }
-
-  // do the same for bsms and reset them if required
-  int nbsms = requested_bsms.length();
-  entry** boes = (entry**) requested_bsms.base();
-  for (int i = 0 ; i < nbsms ; i++) {
-    entry& e = *boes[i];
-    e.outputIndex = REQUESTED_NONE;
-  }
-  outputIndexLimit = 0;
-  outputEntries.empty();
-#ifndef PRODUCT
-  // ensure things are cleared out
-  for (int i = 0; i < (int)maxentries; i++)
-    assert(entries[i].outputIndex == REQUESTED_NONE);
-#endif
-}
-
-static const byte TAG_ORDER[CONSTANT_Limit] = {
-  0, 1, 0, 2, 3, 4, 5, 7, 6, 10, 11, 12, 9, 8, 0, 13, 14, 15, 16
-};
-
-extern "C"
-int outputEntry_cmp(const void* e1p, const void* e2p) {
-  // Sort entries according to the Pack200 rules for deterministic
-  // constant pool ordering.
-  //
-  // The four sort keys as follows, in order of decreasing importance:
-  //   1. ldc first, then non-ldc guys
-  //   2. normal cp_All entries by input order (i.e., address order)
-  //   3. after that, extra entries by lexical order (as in tag_extras[*])
-  entry& e1 = *(entry*) *(void**) e1p;
-  entry& e2 = *(entry*) *(void**) e2p;
-  int   oi1 = e1.outputIndex;
-  int   oi2 = e2.outputIndex;
-  assert(oi1 == REQUESTED || oi1 == REQUESTED_LDC);
-  assert(oi2 == REQUESTED || oi2 == REQUESTED_LDC);
-  if (oi1 != oi2) {
-    if (oi1 == REQUESTED_LDC)  return 0-1;
-    if (oi2 == REQUESTED_LDC)  return 1-0;
-    // Else fall through; neither is an ldc request.
-  }
-  if (e1.inord != NO_INORD || e2.inord != NO_INORD) {
-    // One or both is normal.  Use input order.
-    if (&e1 > &e2)  return 1-0;
-    if (&e1 < &e2)  return 0-1;
-    return 0;  // equal pointers
-  }
-  // Both are extras.  Sort by tag and then by value.
-  if (e1.tag != e2.tag) {
-    return TAG_ORDER[e1.tag] - TAG_ORDER[e2.tag];
-  }
-  // If the tags are the same, use string comparison.
-  return compare_Utf8_chars(e1.value.b, e2.value.b);
-}
-
-void cpool::computeOutputIndexes() {
-  int i;
-
-#ifndef PRODUCT
-  // outputEntries must be a complete list of those requested:
-  static uint checkStart = 0;
-  int checkStep = 1;
-  if (nentries > 100)  checkStep = nentries / 100;
-  for (i = (int)(checkStart++ % checkStep); i < (int)nentries; i += checkStep) {
-    entry& e = entries[i];
-    if (e.tag == CONSTANT_BootstrapMethod) {
-      if (e.outputIndex != REQUESTED_NONE) {
-        assert(requested_bsms.contains(&e));
-      } else {
-        assert(!requested_bsms.contains(&e));
-      }
-    } else {
-      if (e.outputIndex != REQUESTED_NONE) {
-        assert(outputEntries.contains(&e));
-      } else {
-        assert(!outputEntries.contains(&e));
-      }
-    }
-  }
-
-  // check hand-initialization of TAG_ORDER
-  for (i = 0; i < (int)N_TAGS_IN_ORDER; i++) {
-    byte tag = TAGS_IN_ORDER[i];
-    assert(TAG_ORDER[tag] == i+1);
-  }
-#endif
-
-  int    noes =           outputEntries.length();
-  entry** oes = (entry**) outputEntries.base();
-
-  // Sort the output constant pool into the order required by Pack200.
-  PTRLIST_QSORT(outputEntries, outputEntry_cmp);
-
-  // Allocate a new index for each entry that needs one.
-  // We do this in two passes, one for LDC entries and one for the rest.
-  int nextIndex = 1;  // always skip index #0 in output cpool
-  for (i = 0; i < noes; i++) {
-    entry& e = *oes[i];
-    assert(e.outputIndex >= REQUESTED_LDC);
-    e.outputIndex = nextIndex++;
-    if (e.isDoubleWord())  nextIndex++;  // do not use the next index
-  }
-  outputIndexLimit = nextIndex;
-  PRINTCR((3,"renumbering CP to %d entries", outputIndexLimit));
-}
-
-#ifndef PRODUCT
-// debugging goo
-
-unpacker* debug_u;
-
-static bytes& getbuf(size_t len) {  // for debugging only!
-  static int bn = 0;
-  static bytes bufs[8];
-  bytes& buf = bufs[bn++ & 7];
-  while (buf.len < len + 10) {
-    buf.realloc(buf.len ? buf.len * 2 : 1000);
-  }
-  buf.ptr[0] = 0;  // for the sake of strcat
-  return buf;
-}
-
-const char* entry::string() {
-  bytes buf;
-  switch (tag) {
-  case CONSTANT_None:
-    return "<empty>";
-  case CONSTANT_Signature:
-    if (value.b.ptr == null)
-      return ref(0)->string();
-    // else fall through:
-  case CONSTANT_Utf8:
-    buf = value.b;
-    break;
-  case CONSTANT_Integer:
-  case CONSTANT_Float:
-    buf = getbuf(12);
-    sprintf((char*)buf.ptr, "0x%08x", value.i);
-    break;
-  case CONSTANT_Long:
-  case CONSTANT_Double:
-    buf = getbuf(24);
-    sprintf((char*)buf.ptr, "0x" LONG_LONG_HEX_FORMAT, value.l);
-    break;
-  default:
-    if (nrefs == 0) {
-      return TAG_NAME[tag];
-    } else if (nrefs == 1) {
-      return refs[0]->string();
-    } else {
-      const char* s1 = refs[0]->string();
-      const char* s2 = refs[1]->string();
-      buf = getbuf(strlen(s1) + 1 + strlen(s2) + 4 + 1);
-      buf.strcat(s1).strcat(" ").strcat(s2);
-      if (nrefs > 2)  buf.strcat(" ...");
-    }
-  }
-  return (const char*)buf.ptr;
-}
-
-void print_cp_entry(int i) {
-  entry& e = debug_u->cp.entries[i];
-
-  if ((uint)e.tag < CONSTANT_Limit) {
-    printf(" %d\t%s %s\n", i, TAG_NAME[e.tag], e.string());
-  } else {
-    printf(" %d\t%d %s\n", i, e.tag, e.string());
-  }
-}
-
-void print_cp_entries(int beg, int end) {
-  for (int i = beg; i < end; i++)
-    print_cp_entry(i);
-}
-
-void print_cp() {
-  print_cp_entries(0, debug_u->cp.nentries);
-}
-
-#endif
-
-// Unpacker Start
-
-const char str_tf[] = "true\0false";
-#undef STR_TRUE
-#undef STR_FALSE
-#define STR_TRUE   (&str_tf[0])
-#define STR_FALSE  (&str_tf[5])
-
-const char* unpacker::get_option(const char* prop) {
-  if (prop == null )  return null;
-  if (strcmp(prop, UNPACK_DEFLATE_HINT) == 0) {
-    return deflate_hint_or_zero == 0? null : STR_TF(deflate_hint_or_zero > 0);
-#ifdef HAVE_STRIP
-  } else if (strcmp(prop, UNPACK_STRIP_COMPILE) == 0) {
-    return STR_TF(strip_compile);
-  } else if (strcmp(prop, UNPACK_STRIP_DEBUG) == 0) {
-    return STR_TF(strip_debug);
-  } else if (strcmp(prop, UNPACK_STRIP_JCOV) == 0) {
-    return STR_TF(strip_jcov);
-#endif /*HAVE_STRIP*/
-  } else if (strcmp(prop, UNPACK_REMOVE_PACKFILE) == 0) {
-    return STR_TF(remove_packfile);
-  } else if (strcmp(prop, DEBUG_VERBOSE) == 0) {
-    return saveIntStr(verbose);
-  } else if (strcmp(prop, UNPACK_MODIFICATION_TIME) == 0) {
-    return (modification_time_or_zero == 0)? null:
-      saveIntStr(modification_time_or_zero);
-  } else if (strcmp(prop, UNPACK_LOG_FILE) == 0) {
-    return log_file;
-  } else {
-    return NULL; // unknown option ignore
-  }
-}
-
-bool unpacker::set_option(const char* prop, const char* value) {
-  if (prop == NULL)  return false;
-  if (strcmp(prop, UNPACK_DEFLATE_HINT) == 0) {
-    deflate_hint_or_zero = ( (value == null || strcmp(value, "keep") == 0)
-                                ? 0: BOOL_TF(value) ? +1: -1);
-#ifdef HAVE_STRIP
-  } else if (strcmp(prop, UNPACK_STRIP_COMPILE) == 0) {
-    strip_compile = STR_TF(value);
-  } else if (strcmp(prop, UNPACK_STRIP_DEBUG) == 0) {
-    strip_debug = STR_TF(value);
-  } else if (strcmp(prop, UNPACK_STRIP_JCOV) == 0) {
-    strip_jcov = STR_TF(value);
-#endif /*HAVE_STRIP*/
-  } else if (strcmp(prop, UNPACK_REMOVE_PACKFILE) == 0) {
-    remove_packfile = STR_TF(value);
-  } else if (strcmp(prop, DEBUG_VERBOSE) == 0) {
-    verbose = (value == null)? 0: atoi(value);
-  } else if (strcmp(prop, DEBUG_VERBOSE ".bands") == 0) {
-#ifndef PRODUCT
-    verbose_bands = (value == null)? 0: atoi(value);
-#endif
-  } else if (strcmp(prop, UNPACK_MODIFICATION_TIME) == 0) {
-    if (value == null || (strcmp(value, "keep") == 0)) {
-      modification_time_or_zero = 0;
-    } else if (strcmp(value, "now") == 0) {
-      time_t now;
-      time(&now);
-      modification_time_or_zero = (int) now;
-    } else {
-      modification_time_or_zero = atoi(value);
-      if (modification_time_or_zero == 0)
-        modification_time_or_zero = 1;  // make non-zero
-    }
-  } else if (strcmp(prop, UNPACK_LOG_FILE) == 0) {
-    log_file = (value == null)? value: saveStr(value);
-  } else {
-    return false; // unknown option ignore
-  }
-  return true;
-}
-
-// Deallocate all internal storage and reset to a clean state.
-// Do not disturb any input or output connections, including
-// infileptr, infileno, inbytes, read_input_fn, jarout, or errstrm.
-// Do not reset any unpack options.
-void unpacker::reset() {
-  bytes_read_before_reset      += bytes_read;
-  bytes_written_before_reset   += bytes_written;
-  files_written_before_reset   += files_written;
-  classes_written_before_reset += classes_written;
-  segments_read_before_reset   += 1;
-  if (verbose >= 2) {
-    fprintf(errstrm,
-            "After segment %d, "
-            LONG_LONG_FORMAT " bytes read and "
-            LONG_LONG_FORMAT " bytes written.\n",
-            segments_read_before_reset-1,
-            bytes_read_before_reset, bytes_written_before_reset);
-    fprintf(errstrm,
-            "After segment %d, %d files (of which %d are classes) written to output.\n",
-            segments_read_before_reset-1,
-            files_written_before_reset, classes_written_before_reset);
-    if (archive_next_count != 0) {
-      fprintf(errstrm,
-              "After segment %d, %d segment%s remaining (estimated).\n",
-              segments_read_before_reset-1,
-              archive_next_count, archive_next_count==1?"":"s");
-    }
-  }
-
-  unpacker save_u = (*this);  // save bytewise image
-  infileptr = null;  // make asserts happy
-  jniobj = null;  // make asserts happy
-  jarout = null;  // do not close the output jar
-  gzin = null;  // do not close the input gzip stream
-  bytes esn;
-  if (errstrm_name != null) {
-    esn.saveFrom(errstrm_name);
-  } else {
-    esn.set(null, 0);
-  }
-  this->free();
-  mtrace('s', 0, 0);  // note the boundary between segments
-  this->init(read_input_fn);
-
-  // restore selected interface state:
-#define SAVE(x) this->x = save_u.x
-  SAVE(jniobj);
-  SAVE(jnienv);
-  SAVE(infileptr);  // buffered
-  SAVE(infileno);   // unbuffered
-  SAVE(inbytes);    // direct
-  SAVE(jarout);
-  SAVE(gzin);
-  //SAVE(read_input_fn);
-  SAVE(errstrm);
-  SAVE(verbose);  // verbose level, 0 means no output
-  SAVE(strip_compile);
-  SAVE(strip_debug);
-  SAVE(strip_jcov);
-  SAVE(remove_packfile);
-  SAVE(deflate_hint_or_zero);  // ==0 means not set, otherwise -1 or 1
-  SAVE(modification_time_or_zero);
-  SAVE(bytes_read_before_reset);
-  SAVE(bytes_written_before_reset);
-  SAVE(files_written_before_reset);
-  SAVE(classes_written_before_reset);
-  SAVE(segments_read_before_reset);
-#undef SAVE
-  if (esn.len > 0) {
-    errstrm_name = saveStr(esn.strval());
-    esn.free();
-  }
-  log_file = errstrm_name;
-  // Note:  If we use strip_names, watch out:  They get nuked here.
-}
-
-void unpacker::init(read_input_fn_t input_fn) {
-  int i;
-  NOT_PRODUCT(debug_u = this);
-  BYTES_OF(*this).clear();
-#ifndef PRODUCT
-  free();  // just to make sure freeing is idempotent
-#endif
-  this->u = this;    // self-reference for U_NEW macro
-  errstrm = stdout;  // default error-output
-  log_file = LOGFILE_STDOUT;
-  read_input_fn = input_fn;
-  all_bands = band::makeBands(this);
-  // Make a default jar buffer; caller may safely overwrite it.
-  jarout = U_NEW(jar, 1);
-  jarout->init(this);
-  for (i = 0; i < ATTR_CONTEXT_LIMIT; i++)
-    attr_defs[i].u = u;  // set up outer ptr
-}
-
-const char* unpacker::get_abort_message() {
-   return abort_message;
-}
-
-void unpacker::dump_options() {
-  static const char* opts[] = {
-    UNPACK_LOG_FILE,
-    UNPACK_DEFLATE_HINT,
-#ifdef HAVE_STRIP
-    UNPACK_STRIP_COMPILE,
-    UNPACK_STRIP_DEBUG,
-    UNPACK_STRIP_JCOV,
-#endif /*HAVE_STRIP*/
-    UNPACK_REMOVE_PACKFILE,
-    DEBUG_VERBOSE,
-    UNPACK_MODIFICATION_TIME,
-    null
-  };
-  for (int i = 0; opts[i] != null; i++) {
-    const char* str = get_option(opts[i]);
-    if (str == null) {
-      if (verbose == 0)  continue;
-      str = "(not set)";
-    }
-    fprintf(errstrm, "%s=%s\n", opts[i], str);
-  }
-}
-
-
-// Usage: unpack a byte buffer
-// packptr is a reference to byte buffer containing a
-// packed file and len is the length of the buffer.
-// If null, the callback is used to fill an internal buffer.
-void unpacker::start(void* packptr, size_t len) {
-  CHECK;
-  NOT_PRODUCT(debug_u = this);
-  if (packptr != null && len != 0) {
-    inbytes.set((byte*) packptr, len);
-  }
-  CHECK;
-  read_bands();
-}
-
-void unpacker::check_options() {
-  const char* strue  = "true";
-  const char* sfalse = "false";
-  if (deflate_hint_or_zero != 0) {
-    bool force_deflate_hint = (deflate_hint_or_zero > 0);
-    if (force_deflate_hint)
-      default_file_options |= FO_DEFLATE_HINT;
-    else
-      default_file_options &= ~FO_DEFLATE_HINT;
-    // Turn off per-file deflate hint by force.
-    suppress_file_options |= FO_DEFLATE_HINT;
-  }
-  if (modification_time_or_zero != 0) {
-    default_file_modtime = modification_time_or_zero;
-    // Turn off per-file modtime by force.
-    archive_options &= ~AO_HAVE_FILE_MODTIME;
-  }
-  // %%% strip_compile, etc...
-}
-
-// classfile writing
-
-void unpacker::reset_cur_classfile() {
-  // set defaults
-  cur_class_minver = default_class_minver;
-  cur_class_majver = default_class_majver;
-
-  // reset constant pool state
-  cp.resetOutputIndexes();
-
-  // reset fixups
-  class_fixup_type.empty();
-  class_fixup_offset.empty();
-  class_fixup_ref.empty();
-  requested_ics.empty();
-  cp.requested_bsms.empty();
-}
-
-cpindex* cpool::getKQIndex() {
-  char ch = '?';
-  if (u->cur_descr != null) {
-    entry* type = u->cur_descr->descrType();
-    ch = type->value.b.ptr[0];
-  }
-  byte tag = CONSTANT_Integer;
-  switch (ch) {
-  case 'L': tag = CONSTANT_String;   break;
-  case 'I': tag = CONSTANT_Integer;  break;
-  case 'J': tag = CONSTANT_Long;     break;
-  case 'F': tag = CONSTANT_Float;    break;
-  case 'D': tag = CONSTANT_Double;   break;
-  case 'B': case 'S': case 'C':
-  case 'Z': tag = CONSTANT_Integer;  break;
-  default:  abort("bad KQ reference"); break;
-  }
-  return getIndex(tag);
-}
-
-uint unpacker::to_bci(uint bii) {
-  uint  len =         bcimap.length();
-  uint* map = (uint*) bcimap.base();
-  assert(len > 0);  // must be initialized before using to_bci
-  if (len == 0) {
-    abort("bad bcimap");
-    return 0;
-  }
-  if (bii < len)
-    return map[bii];
-  // Else it's a fractional or out-of-range BCI.
-  uint key = bii-len;
-  for (int i = len; ; i--) {
-    if (map[i-1]-(i-1) <= key)
-      break;
-    else
-      --bii;
-  }
-  return bii;
-}
-
-void unpacker::put_stackmap_type() {
-  int tag = code_StackMapTable_T.getByte();
-  putu1(tag);
-  switch (tag) {
-  case 7: // (7) [RCH]
-    putref(code_StackMapTable_RC.getRef());
-    break;
-  case 8: // (8) [PH]
-    putu2(to_bci(code_StackMapTable_P.getInt()));
-    CHECK;
-    break;
-  }
-}
-
-// Functions for writing code.
-
-maybe_inline
-void unpacker::put_label(int curIP, int size) {
-  code_fixup_type.addByte(size);
-  code_fixup_offset.add((int)put_empty(size));
-  code_fixup_source.add(curIP);
-}
-
-inline  // called exactly once => inline
-void unpacker::write_bc_ops() {
-  bcimap.empty();
-  code_fixup_type.empty();
-  code_fixup_offset.empty();
-  code_fixup_source.empty();
-
-  band* bc_which;
-
-  byte*  opptr = bc_codes.curRP();
-  // No need for oplimit, since the codes are pre-counted.
-
-  size_t codeBase = wpoffset();
-
-  bool   isAload;  // copy-out result
-  int    origBC;
-
-  entry* thisClass  = cur_class;
-  entry* superClass = cur_super;
-  entry* newClass   = null;  // class of last _new opcode
-
-  // overwrite any prior index on these bands; it changes w/ current class:
-  bc_thisfield.setIndex(    cp.getFieldIndex( thisClass));
-  bc_thismethod.setIndex(   cp.getMethodIndex(thisClass));
-  if (superClass != null) {
-    bc_superfield.setIndex( cp.getFieldIndex( superClass));
-    bc_supermethod.setIndex(cp.getMethodIndex(superClass));
-  } else {
-    NOT_PRODUCT(bc_superfield.setIndex(null));
-    NOT_PRODUCT(bc_supermethod.setIndex(null));
-  }
-  CHECK;
-
-  for (int curIP = 0; ; curIP++) {
-    CHECK;
-    int curPC = (int)(wpoffset() - codeBase);
-    bcimap.add(curPC);
-    ensure_put_space(10);  // covers most instrs w/o further bounds check
-    int bc = *opptr++ & 0xFF;
-
-    putu1_fast(bc);
-    // Note:  See '--wp' below for pseudo-bytecodes like bc_end_marker.
-
-    bool isWide = false;
-    if (bc == bc_wide) {
-      bc = *opptr++ & 0xFF;
-      putu1_fast(bc);
-      isWide = true;
-    }
-    switch (bc) {
-    case bc_end_marker:
-      --wp;  // not really part of the code
-      assert(opptr <= bc_codes.maxRP());
-      bc_codes.curRP() = opptr;  // advance over this in bc_codes
-      goto doneScanningMethod;
-    case bc_tableswitch: // apc:  (df, lo, hi, (hi-lo+1)*(label))
-    case bc_lookupswitch: // apc:  (df, nc, nc*(case, label))
-      {
-        int caseCount = bc_case_count.getInt();
-        while (((wpoffset() - codeBase) % 4) != 0)  putu1_fast(0);
-        ensure_put_space(30 + caseCount*8);
-        put_label(curIP, 4);  //int df = bc_label.getInt();
-        if (bc == bc_tableswitch) {
-          int lo = bc_case_value.getInt();
-          int hi = lo + caseCount-1;
-          putu4(lo);
-          putu4(hi);
-          for (int j = 0; j < caseCount; j++) {
-            put_label(curIP, 4); //int lVal = bc_label.getInt();
-            //int cVal = lo + j;
-          }
-        } else {
-          putu4(caseCount);
-          for (int j = 0; j < caseCount; j++) {
-            int cVal = bc_case_value.getInt();
-            putu4(cVal);
-            put_label(curIP, 4); //int lVal = bc_label.getInt();
-          }
-        }
-        assert((int)to_bci(curIP) == curPC);
-        continue;
-      }
-    case bc_iinc:
-      {
-        int local = bc_local.getInt();
-        int delta = (isWide ? bc_short : bc_byte).getInt();
-        if (isWide) {
-          putu2(local);
-          putu2(delta);
-        } else {
-          putu1_fast(local);
-          putu1_fast(delta);
-        }
-        continue;
-      }
-    case bc_sipush:
-      {
-        int val = bc_short.getInt();
-        putu2(val);
-        continue;
-      }
-    case bc_bipush:
-    case bc_newarray:
-      {
-        int val = bc_byte.getByte();
-        putu1_fast(val);
-        continue;
-      }
-    case bc_ref_escape:
-      {
-        // Note that insnMap has one entry for this.
-        --wp;  // not really part of the code
-        int size = bc_escrefsize.getInt();
-        entry* ref = bc_escref.getRefN();
-        CHECK;
-        switch (size) {
-        case 1: putu1ref(ref); break;
-        case 2: putref(ref);   break;
-        default: assert(false);
-        }
-        continue;
-      }
-    case bc_byte_escape:
-      {
-        // Note that insnMap has one entry for all these bytes.
-        --wp;  // not really part of the code
-        int size = bc_escsize.getInt();
-        ensure_put_space(size);
-        for (int j = 0; j < size; j++)
-          putu1_fast(bc_escbyte.getByte());
-        continue;
-      }
-    default:
-      if (is_invoke_init_op(bc)) {
-        origBC = bc_invokespecial;
-        entry* classRef;
-        switch (bc - _invokeinit_op) {
-        case _invokeinit_self_option:   classRef = thisClass;  break;
-        case _invokeinit_super_option:  classRef = superClass; break;
-        default: assert(bc == _invokeinit_op+_invokeinit_new_option);
-        case _invokeinit_new_option:    classRef = newClass;   break;
-        }
-        wp[-1] = origBC;  // overwrite with origBC
-        int coding = bc_initref.getInt();
-        // Find the nth overloading of <init> in classRef.
-        entry*   ref = null;
-        cpindex* ix = cp.getMethodIndex(classRef);
-        CHECK;
-        for (int j = 0, which_init = 0; ; j++) {
-          ref = (ix == null)? null: ix->get(j);
-          if (ref == null)  break;  // oops, bad input
-          assert(ref->tag == CONSTANT_Methodref);
-          if (ref->memberDescr()->descrName() == cp.sym[cpool::s_lt_init_gt]) {
-            if (which_init++ == coding)  break;
-          }
-        }
-        putref(ref);
-        continue;
-      }
-      bc_which = ref_band_for_self_op(bc, isAload, origBC);
-      if (bc_which != null) {
-        if (!isAload) {
-          wp[-1] = origBC;  // overwrite with origBC
-        } else {
-          wp[-1] = bc_aload_0;  // overwrite with _aload_0
-          // Note: insnMap keeps the _aload_0 separate.
-          bcimap.add(++curPC);
-          ++curIP;
-          putu1_fast(origBC);
-        }
-        entry* ref = bc_which->getRef();
-        CHECK;
-        putref(ref);
-        continue;
-      }
-      if (is_branch_op(bc)) {
-        //int lVal = bc_label.getInt();
-        if (bc < bc_goto_w) {
-          put_label(curIP, 2);  //putu2(lVal & 0xFFFF);
-        } else {
-          assert(bc <= bc_jsr_w);
-          put_label(curIP, 4);  //putu4(lVal);
-        }
-        assert((int)to_bci(curIP) == curPC);
-        continue;
-      }
-      bc_which = ref_band_for_op(bc);
-      if (bc_which != null) {
-        entry* ref = bc_which->getRefCommon(bc_which->ix, bc_which->nullOK);
-        CHECK;
-        if (ref == null && bc_which == &bc_classref) {
-          // Shorthand for class self-references.
-          ref = thisClass;
-        }
-        origBC = bc;
-        switch (bc) {
-        case _invokestatic_int:
-          origBC = bc_invokestatic;
-          break;
-        case _invokespecial_int:
-          origBC = bc_invokespecial;
-          break;
-        case bc_ildc:
-        case bc_cldc:
-        case bc_fldc:
-        case bc_sldc:
-        case bc_qldc:
-          origBC = bc_ldc;
-          break;
-        case bc_ildc_w:
-        case bc_cldc_w:
-        case bc_fldc_w:
-        case bc_sldc_w:
-        case bc_qldc_w:
-          origBC = bc_ldc_w;
-          break;
-        case bc_lldc2_w:
-        case bc_dldc2_w:
-          origBC = bc_ldc2_w;
-          break;
-        case bc_new:
-          newClass = ref;
-          break;
-        }
-        wp[-1] = origBC;  // overwrite with origBC
-        if (origBC == bc_ldc) {
-          putu1ref(ref);
-        } else {
-          putref(ref);
-        }
-        if (origBC == bc_multianewarray) {
-          // Copy the trailing byte also.
-          int val = bc_byte.getByte();
-          putu1_fast(val);
-        } else if (origBC == bc_invokeinterface) {
-          int argSize = ref->memberDescr()->descrType()->typeSize();
-          putu1_fast(1 + argSize);
-          putu1_fast(0);
-        } else if (origBC == bc_invokedynamic) {
-          // pad the next two byte
-          putu1_fast(0);
-          putu1_fast(0);
-        }
-        continue;
-      }
-      if (is_local_slot_op(bc)) {
-        int local = bc_local.getInt();
-        if (isWide) {
-          putu2(local);
-          if (bc == bc_iinc) {
-            int iVal = bc_short.getInt();
-            putu2(iVal);
-          }
-        } else {
-          putu1_fast(local);
-          if (bc == bc_iinc) {
-            int iVal = bc_byte.getByte();
-            putu1_fast(iVal);
-          }
-        }
-        continue;
-      }
-      // Random bytecode.  Just copy it.
-      assert(bc < bc_bytecode_limit);
-    }
-  }
- doneScanningMethod:{}
-  //bcimap.add(curPC);  // PC limit is already also in map, from bc_end_marker
-
-  // Armed with a bcimap, we can now fix up all the labels.
-  for (int i = 0; i < (int)code_fixup_type.size(); i++) {
-    int   type   = code_fixup_type.getByte(i);
-    byte* bp     = wp_at(code_fixup_offset.get(i));
-    int   curIP  = code_fixup_source.get(i);
-    int   destIP = curIP + bc_label.getInt();
-    int   span   = to_bci(destIP) - to_bci(curIP);
-    CHECK;
-    switch (type) {
-    case 2: putu2_at(bp, (ushort)span); break;
-    case 4: putu4_at(bp,         span); break;
-    default: assert(false);
-    }
-  }
-}
-
-inline  // called exactly once => inline
-void unpacker::write_code() {
-  int j;
-
-  int max_stack, max_locals, handler_count, cflags;
-  get_code_header(max_stack, max_locals, handler_count, cflags);
-
-  if (max_stack < 0)      max_stack = code_max_stack.getInt();
-  if (max_locals < 0)     max_locals = code_max_na_locals.getInt();
-  if (handler_count < 0)  handler_count = code_handler_count.getInt();
-
-  int siglen = cur_descr->descrType()->typeSize();
-  CHECK;
-  if ((cur_descr_flags & ACC_STATIC) == 0)  siglen++;
-  max_locals += siglen;
-
-  putu2(max_stack);
-  putu2(max_locals);
-  size_t bcbase = put_empty(4);
-
-  // Write the bytecodes themselves.
-  write_bc_ops();
-  CHECK;
-
-  byte* bcbasewp = wp_at(bcbase);
-  putu4_at(bcbasewp, (int)(wp - (bcbasewp+4)));  // size of code attr
-
-  putu2(handler_count);
-  for (j = 0; j < handler_count; j++) {
-    int bii = code_handler_start_P.getInt();
-    putu2(to_bci(bii));
-    bii    += code_handler_end_PO.getInt();
-    putu2(to_bci(bii));
-    bii    += code_handler_catch_PO.getInt();
-    putu2(to_bci(bii));
-    putref(code_handler_class_RCN.getRefN());
-    CHECK;
-  }
-
-  julong indexBits = cflags;
-  if (cflags < 0) {
-    bool haveLongFlags = attr_defs[ATTR_CONTEXT_CODE].haveLongFlags();
-    indexBits = code_flags_hi.getLong(code_flags_lo, haveLongFlags);
-  }
-  write_attrs(ATTR_CONTEXT_CODE, indexBits);
-}
-
-int unpacker::write_attrs(int attrc, julong indexBits) {
-  CHECK_0;
-  if (indexBits == 0) {
-    // Quick short-circuit.
-    putu2(0);
-    return 0;
-  }
-
-  attr_definitions& ad = attr_defs[attrc];
-
-  int i, j, j2, idx, count;
-
-  int oiCount = 0;
-  if (ad.isPredefined(X_ATTR_OVERFLOW)
-      && (indexBits & ((julong)1<<X_ATTR_OVERFLOW)) != 0) {
-    indexBits -= ((julong)1<<X_ATTR_OVERFLOW);
-    oiCount = ad.xxx_attr_count().getInt();
-  }
-
-  int bitIndexes[X_ATTR_LIMIT_FLAGS_HI];
-  int biCount = 0;
-
-  // Fill bitIndexes with index bits, in order.
-  for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) {
-    if ((indexBits & 1) != 0)
-      bitIndexes[biCount++] = idx;
-  }
-  assert(biCount <= (int)lengthof(bitIndexes));
-
-  // Write a provisional attribute count, perhaps to be corrected later.
-  int naOffset = (int)wpoffset();
-  int na0 = biCount + oiCount;
-  putu2(na0);
-
-  int na = 0;
-  for (i = 0; i < na0; i++) {
-    if (i < biCount)
-      idx = bitIndexes[i];
-    else
-      idx = ad.xxx_attr_indexes().getInt();
-    assert(ad.isIndex(idx));
-    entry* aname = null;
-    entry* ref;  // scratch
-    size_t abase = put_empty(2+4);
-    CHECK_0;
-    if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) {
-      // Switch on the attrc and idx simultaneously.
-      switch (ADH_BYTE(attrc, idx)) {
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS,  X_ATTR_OVERFLOW):
-      case ADH_BYTE(ATTR_CONTEXT_FIELD,  X_ATTR_OVERFLOW):
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_OVERFLOW):
-      case ADH_BYTE(ATTR_CONTEXT_CODE,   X_ATTR_OVERFLOW):
-        // no attribute at all, so back up on this one
-        wp = wp_at(abase);
-        continue;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_ClassFile_version):
-        cur_class_minver = class_ClassFile_version_minor_H.getInt();
-        cur_class_majver = class_ClassFile_version_major_H.getInt();
-        // back up; not a real attribute
-        wp = wp_at(abase);
-        continue;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_InnerClasses):
-        // note the existence of this attr, but save for later
-        if (cur_class_has_local_ics)
-          abort("too many InnerClasses attrs");
-        cur_class_has_local_ics = true;
-        wp = wp_at(abase);
-        continue;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_SourceFile):
-        aname = cp.sym[cpool::s_SourceFile];
-        ref = class_SourceFile_RUN.getRefN();
-        CHECK_0;
-        if (ref == null) {
-          bytes& n = cur_class->ref(0)->value.b;
-          // parse n = (<pkg>/)*<outer>?($<id>)*
-          int pkglen = lastIndexOf(SLASH_MIN,  SLASH_MAX,  n, (int)n.len)+1;
-          bytes prefix = n.slice(pkglen, n.len);
-          for (;;) {
-            // Work backwards, finding all '$', '#', etc.
-            int dollar = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, (int)prefix.len);
-            if (dollar < 0)  break;
-            prefix = prefix.slice(0, dollar);
-          }
-          const char* suffix = ".java";
-          int len = (int)(prefix.len + strlen(suffix));
-          bytes name; name.set(T_NEW(byte, add_size(len, 1)), len);
-          name.strcat(prefix).strcat(suffix);
-          ref = cp.ensureUtf8(name);
-        }
-        putref(ref);
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_EnclosingMethod):
-        aname = cp.sym[cpool::s_EnclosingMethod];
-        putref(class_EnclosingMethod_RC.getRefN());
-        CHECK_0;
-        putref(class_EnclosingMethod_RDN.getRefN());
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_FIELD, FIELD_ATTR_ConstantValue):
-        aname = cp.sym[cpool::s_ConstantValue];
-        putref(field_ConstantValue_KQ.getRefUsing(cp.getKQIndex()));
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Code):
-        aname = cp.sym[cpool::s_Code];
-        write_code();
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Exceptions):
-        aname = cp.sym[cpool::s_Exceptions];
-        putu2(count = method_Exceptions_N.getInt());
-        for (j = 0; j < count; j++) {
-          putref(method_Exceptions_RC.getRefN());
-          CHECK_0;
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_MethodParameters):
-        aname = cp.sym[cpool::s_MethodParameters];
-        putu1(count = method_MethodParameters_NB.getByte());
-        for (j = 0; j < count; j++) {
-          putref(method_MethodParameters_name_RUN.getRefN());
-          putu2(method_MethodParameters_flag_FH.getInt());
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_StackMapTable):
-        aname = cp.sym[cpool::s_StackMapTable];
-        // (keep this code aligned with its brother in unpacker::read_attrs)
-        putu2(count = code_StackMapTable_N.getInt());
-        for (j = 0; j < count; j++) {
-          int tag = code_StackMapTable_frame_T.getByte();
-          putu1(tag);
-          if (tag <= 127) {
-            // (64-127)  [(2)]
-            if (tag >= 64)  put_stackmap_type();
-            CHECK_0;
-          } else if (tag <= 251) {
-            // (247)     [(1)(2)]
-            // (248-251) [(1)]
-            if (tag >= 247)  putu2(code_StackMapTable_offset.getInt());
-            if (tag == 247)  put_stackmap_type();
-            CHECK_0;
-          } else if (tag <= 254) {
-            // (252)     [(1)(2)]
-            // (253)     [(1)(2)(2)]
-            // (254)     [(1)(2)(2)(2)]
-            putu2(code_StackMapTable_offset.getInt());
-            CHECK_0;
-            for (int k = (tag - 251); k > 0; k--) {
-              put_stackmap_type();
-              CHECK_0;
-            }
-          } else {
-            // (255)     [(1)NH[(2)]NH[(2)]]
-            putu2(code_StackMapTable_offset.getInt());
-            putu2(j2 = code_StackMapTable_local_N.getInt());
-            while (j2-- > 0) {put_stackmap_type(); CHECK_0;}
-            putu2(j2 = code_StackMapTable_stack_N.getInt());
-            while (j2-- > 0)  {put_stackmap_type(); CHECK_0;}
-          }
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LineNumberTable):
-        aname = cp.sym[cpool::s_LineNumberTable];
-        putu2(count = code_LineNumberTable_N.getInt());
-        for (j = 0; j < count; j++) {
-          putu2(to_bci(code_LineNumberTable_bci_P.getInt()));
-          CHECK_0;
-          putu2(code_LineNumberTable_line.getInt());
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTable):
-        aname = cp.sym[cpool::s_LocalVariableTable];
-        putu2(count = code_LocalVariableTable_N.getInt());
-        for (j = 0; j < count; j++) {
-          int bii = code_LocalVariableTable_bci_P.getInt();
-          int bci = to_bci(bii);
-          CHECK_0;
-          putu2(bci);
-          bii    += code_LocalVariableTable_span_O.getInt();
-          putu2(to_bci(bii) - bci);
-          CHECK_0;
-          putref(code_LocalVariableTable_name_RU.getRefN());
-          CHECK_0;
-          putref(code_LocalVariableTable_type_RS.getRefN());
-          CHECK_0;
-          putu2(code_LocalVariableTable_slot.getInt());
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTypeTable):
-        aname = cp.sym[cpool::s_LocalVariableTypeTable];
-        putu2(count = code_LocalVariableTypeTable_N.getInt());
-        for (j = 0; j < count; j++) {
-          int bii = code_LocalVariableTypeTable_bci_P.getInt();
-          int bci = to_bci(bii);
-          CHECK_0;
-          putu2(bci);
-          bii    += code_LocalVariableTypeTable_span_O.getInt();
-          putu2(to_bci(bii) - bci);
-          CHECK_0;
-          putref(code_LocalVariableTypeTable_name_RU.getRefN());
-          CHECK_0;
-          putref(code_LocalVariableTypeTable_type_RS.getRefN());
-          CHECK_0;
-          putu2(code_LocalVariableTypeTable_slot.getInt());
-        }
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Signature):
-        aname = cp.sym[cpool::s_Signature];
-        putref(class_Signature_RS.getRefN());
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Signature):
-        aname = cp.sym[cpool::s_Signature];
-        putref(field_Signature_RS.getRefN());
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Signature):
-        aname = cp.sym[cpool::s_Signature];
-        putref(method_Signature_RS.getRefN());
-        break;
-
-      case ADH_BYTE(ATTR_CONTEXT_CLASS,  X_ATTR_Deprecated):
-      case ADH_BYTE(ATTR_CONTEXT_FIELD,  X_ATTR_Deprecated):
-      case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Deprecated):
-        aname = cp.sym[cpool::s_Deprecated];
-        // no data
-        break;
-      }
-    }
-    CHECK_0;
-    if (aname == null) {
-      // Unparse a compressor-defined attribute.
-      layout_definition* lo = ad.getLayout(idx);
-      if (lo == null) {
-        abort("bad layout index");
-        break;
-      }
-      assert((int)lo->idx == idx);
-      aname = lo->nameEntry;
-      if (aname == null) {
-        bytes nameb; nameb.set(lo->name);
-        aname = cp.ensureUtf8(nameb);
-        // Cache the name entry for next time.
-        lo->nameEntry = aname;
-      }
-      // Execute all the layout elements.
-      band** bands = lo->bands();
-      if (lo->hasCallables()) {
-        band& cble = *bands[0];
-        assert(cble.le_kind == EK_CBLE);
-        bands = cble.le_body;
-      }
-      putlayout(bands);
-    }
-
-    if (aname == null)
-      abort("bad attribute index");
-    CHECK_0;
-
-    byte* wp1 = wp;
-    wp = wp_at(abase);
-
-    // DTRT if this attr is on the strip-list.
-    // (Note that we emptied the data out of the band first.)
-    if (ad.strip_names.contains(aname)) {
-      continue;
-    }
-
-    // patch the name and length
-    putref(aname);
-    putu4((int)(wp1 - (wp+4)));  // put the attr size
-    wp = wp1;
-    na++;  // count the attrs actually written
-  }
-
-  if (na != na0)
-    // Refresh changed count.
-    putu2_at(wp_at(naOffset), na);
-  return na;
-}
-
-void unpacker::write_members(int num, int attrc) {
-  CHECK;
-  attr_definitions& ad = attr_defs[attrc];
-  band& member_flags_hi = ad.xxx_flags_hi();
-  band& member_flags_lo = ad.xxx_flags_lo();
-  band& member_descr = (&member_flags_hi)[e_field_descr-e_field_flags_hi];
-  assert(endsWith(member_descr.name, "_descr"));
-  assert(endsWith(member_flags_lo.name, "_flags_lo"));
-  assert(endsWith(member_flags_lo.name, "_flags_lo"));
-  bool haveLongFlags = ad.haveLongFlags();
-
-  putu2(num);
-  julong indexMask = attr_defs[attrc].flagIndexMask();
-  for (int i = 0; i < num; i++) {
-    julong mflags = member_flags_hi.getLong(member_flags_lo, haveLongFlags);
-    entry* mdescr = member_descr.getRef();
-    cur_descr = mdescr;
-    putu2(cur_descr_flags = (ushort)(mflags & ~indexMask));
-    CHECK;
-    putref(mdescr->descrName());
-    putref(mdescr->descrType());
-    write_attrs(attrc, (mflags & indexMask));
-    CHECK;
-  }
-  cur_descr = null;
-}
-
-extern "C"
-int raw_address_cmp(const void* p1p, const void* p2p) {
-  void* p1 = *(void**) p1p;
-  void* p2 = *(void**) p2p;
-  return (p1 > p2)? 1: (p1 < p2)? -1: 0;
-}
-
-/*
- * writes the InnerClass attributes and returns the updated attribute
- */
-int  unpacker::write_ics(int naOffset, int na) {
-#ifdef ASSERT
-  for (int i = 0; i < ic_count; i++) {
-    assert(!ics[i].requested);
-  }
-#endif
-  // First, consult the global table and the local constant pool,
-  // and decide on the globally implied inner classes.
-  // (Note that we read the cpool's outputIndex fields, but we
-  // do not yet write them, since the local IC attribute might
-  // reverse a global decision to declare an IC.)
-  assert(requested_ics.length() == 0);  // must start out empty
-  // Always include all members of the current class.
-  for (inner_class* child = cp.getFirstChildIC(cur_class);
-       child != null;
-       child = cp.getNextChildIC(child)) {
-    child->requested = true;
-    requested_ics.add(child);
-  }
-  // And, for each inner class mentioned in the constant pool,
-  // include it and all its outers.
-  int    noes =           cp.outputEntries.length();
-  entry** oes = (entry**) cp.outputEntries.base();
-  for (int i = 0; i < noes; i++) {
-    entry& e = *oes[i];
-    if (e.tag != CONSTANT_Class)  continue;  // wrong sort
-    for (inner_class* ic = cp.getIC(&e);
-         ic != null;
-         ic = cp.getIC(ic->outer)) {
-      if (ic->requested)  break;  // already processed
-      ic->requested = true;
-      requested_ics.add(ic);
-    }
-  }
-  int local_ics = requested_ics.length();
-  // Second, consult a local attribute (if any) and adjust the global set.
-  inner_class* extra_ics = null;
-  int      num_extra_ics = 0;
-  if (cur_class_has_local_ics) {
-    // adjust the set of ICs by symmetric set difference w/ the locals
-    num_extra_ics = class_InnerClasses_N.getInt();
-    if (num_extra_ics == 0) {
-      // Explicit zero count has an irregular meaning:  It deletes the attr.
-      local_ics = 0;  // (short-circuit all tests of requested bits)
-    } else {
-      extra_ics = T_NEW(inner_class, num_extra_ics);
-      // Note:  extra_ics will be freed up by next call to get_next_file().
-    }
-  }
-  for (int i = 0; i < num_extra_ics; i++) {
-    inner_class& extra_ic = extra_ics[i];
-    extra_ic.inner = class_InnerClasses_RC.getRef();
-    CHECK_0;
-    // Find the corresponding equivalent global IC:
-    inner_class* global_ic = cp.getIC(extra_ic.inner);
-    int flags = class_InnerClasses_F.getInt();
-    if (flags == 0) {
-      // The extra IC is simply a copy of a global IC.
-      if (global_ic == null) {
-        abort("bad reference to inner class");
-        break;
-      }
-      extra_ic = (*global_ic);  // fill in rest of fields
-    } else {
-      flags &= ~ACC_IC_LONG_FORM;  // clear high bit if set to get clean zero
-      extra_ic.flags = flags;
-      extra_ic.outer = class_InnerClasses_outer_RCN.getRefN();
-      CHECK_0;
-      extra_ic.name  = class_InnerClasses_name_RUN.getRefN();
-      CHECK_0;
-      // Detect if this is an exact copy of the global tuple.
-      if (global_ic != null) {
-        if (global_ic->flags != extra_ic.flags ||
-            global_ic->outer != extra_ic.outer ||
-            global_ic->name  != extra_ic.name) {
-          global_ic = null;  // not really the same, so break the link
-        }
-      }
-    }
-    if (global_ic != null && global_ic->requested) {
-      // This local repetition reverses the globally implied request.
-      global_ic->requested = false;
-      extra_ic.requested = false;
-      local_ics -= 1;
-    } else {
-      // The global either does not exist, or is not yet requested.
-      extra_ic.requested = true;
-      local_ics += 1;
-    }
-  }
-  // Finally, if there are any that survived, put them into an attribute.
-  // (Note that a zero-count attribute is always deleted.)
-  // The putref calls below will tell the constant pool to add any
-  // necessary local CP references to support the InnerClasses attribute.
-  // This step must be the last round of additions to the local CP.
-  if (local_ics > 0) {
-    // append the new attribute:
-    putref(cp.sym[cpool::s_InnerClasses]);
-    putu4(2 + 2*4*local_ics);
-    putu2(local_ics);
-    PTRLIST_QSORT(requested_ics, raw_address_cmp);
-    int num_global_ics = requested_ics.length();
-    for (int i = -num_global_ics; i < num_extra_ics; i++) {
-      inner_class* ic;
-      if (i < 0)
-        ic = (inner_class*) requested_ics.get(num_global_ics+i);
-      else
-        ic = &extra_ics[i];
-      if (ic->requested) {
-        putref(ic->inner);
-        putref(ic->outer);
-        putref(ic->name);
-        putu2(ic->flags);
-        NOT_PRODUCT(local_ics--);
-      }
-    }
-    assert(local_ics == 0);           // must balance
-    putu2_at(wp_at(naOffset), ++na);  // increment class attr count
-  }
-
-  // Tidy up global 'requested' bits:
-  for (int i = requested_ics.length(); --i >= 0; ) {
-    inner_class* ic = (inner_class*) requested_ics.get(i);
-    ic->requested = false;
-  }
-  requested_ics.empty();
-  return na;
-}
-
-/*
- * Writes the BootstrapMethods attribute and returns the updated attribute count
- */
-int unpacker::write_bsms(int naOffset, int na) {
-  cur_class_local_bsm_count = cp.requested_bsms.length();
-  if (cur_class_local_bsm_count > 0) {
-    int    noes =           cp.outputEntries.length();
-    entry** oes = (entry**) cp.outputEntries.base();
-    PTRLIST_QSORT(cp.requested_bsms, outputEntry_cmp);
-    // append the BootstrapMethods attribute (after the InnerClasses attr):
-    putref(cp.sym[cpool::s_BootstrapMethods]);
-    // make a note of the offset, for lazy patching
-    int sizeOffset = (int)wpoffset();
-    putu4(-99);  // attr size will be patched
-    putu2(cur_class_local_bsm_count);
-    int written_bsms = 0;
-    for (int i = 0 ; i < cur_class_local_bsm_count ; i++) {
-      entry* e = (entry*)cp.requested_bsms.get(i);
-      assert(e->outputIndex != REQUESTED_NONE);
-      // output index is the index within the array
-      e->outputIndex = i;
-      putref(e->refs[0]);  // bsm
-      putu2(e->nrefs-1);  // number of args after bsm
-      for (int j = 1; j < e->nrefs; j++) {
-        putref(e->refs[j]);
-      }
-      written_bsms += 1;
-    }
-    assert(written_bsms == cur_class_local_bsm_count);  // else insane
-    byte* sizewp = wp_at(sizeOffset);
-    putu4_at(sizewp, (int)(wp - (sizewp+4)));  // size of code attr
-    putu2_at(wp_at(naOffset), ++na);  // increment class attr count
-  }
-  return na;
-}
-
-void unpacker::write_classfile_tail() {
-
-  cur_classfile_tail.empty();
-  set_output(&cur_classfile_tail);
-
-  int i, num;
-
-  attr_definitions& ad = attr_defs[ATTR_CONTEXT_CLASS];
-
-  bool haveLongFlags = ad.haveLongFlags();
-  julong kflags = class_flags_hi.getLong(class_flags_lo, haveLongFlags);
-  julong indexMask = ad.flagIndexMask();
-
-  cur_class = class_this.getRef();
-  CHECK;
-  cur_super = class_super.getRef();
-  CHECK;
-
-  if (cur_super == cur_class)  cur_super = null;
-  // special representation for java/lang/Object
-
-  putu2((ushort)(kflags & ~indexMask));
-  putref(cur_class);
-  putref(cur_super);
-
-  putu2(num = class_interface_count.getInt());
-  for (i = 0; i < num; i++) {
-    putref(class_interface.getRef());
-    CHECK;
-  }
-
-  write_members(class_field_count.getInt(),  ATTR_CONTEXT_FIELD);
-  write_members(class_method_count.getInt(), ATTR_CONTEXT_METHOD);
-  CHECK;
-
-  cur_class_has_local_ics = false;  // may be set true by write_attrs
-
-  int naOffset = (int)wpoffset();   // note the attr count location
-  int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask));
-  CHECK;
-
-  na = write_bsms(naOffset, na);
-  CHECK;
-
-  // choose which inner classes (if any) pertain to k:
-  na = write_ics(naOffset, na);
-  CHECK;
-
-  close_output();
-  cp.computeOutputIndexes();
-
-  // rewrite CP references in the tail
-  int nextref = 0;
-  for (i = 0; i < (int)class_fixup_type.size(); i++) {
-    int    type = class_fixup_type.getByte(i);
-    byte*  fixp = wp_at(class_fixup_offset.get(i));
-    entry* e    = (entry*)class_fixup_ref.get(nextref++);
-    int    idx  = e->getOutputIndex();
-    switch (type) {
-    case 1:  putu1_at(fixp, idx);  break;
-    case 2:  putu2_at(fixp, idx);  break;
-    default: assert(false);  // should not reach here
-    }
-  }
-  CHECK;
-}
-
-void unpacker::write_classfile_head() {
-  cur_classfile_head.empty();
-  set_output(&cur_classfile_head);
-
-  putu4(JAVA_MAGIC);
-  putu2(cur_class_minver);
-  putu2(cur_class_majver);
-  putu2(cp.outputIndexLimit);
-
-  int checkIndex = 1;
-  int    noes =           cp.outputEntries.length();
-  entry** oes = (entry**) cp.outputEntries.base();
-  for (int i = 0; i < noes; i++) {
-    entry& e = *oes[i];
-    assert(e.getOutputIndex() == checkIndex++);
-    byte tag = e.tag;
-    assert(tag != CONSTANT_Signature);
-    putu1(tag);
-    switch (tag) {
-    case CONSTANT_Utf8:
-      putu2((int)e.value.b.len);
-      put_bytes(e.value.b);
-      break;
-    case CONSTANT_Integer:
-    case CONSTANT_Float:
-      putu4(e.value.i);
-      break;
-    case CONSTANT_Long:
-    case CONSTANT_Double:
-      putu8(e.value.l);
-      assert(checkIndex++);
-      break;
-    case CONSTANT_Class:
-    case CONSTANT_String:
-      // just write the ref
-      putu2(e.refs[0]->getOutputIndex());
-      break;
-    case CONSTANT_Fieldref:
-    case CONSTANT_Methodref:
-    case CONSTANT_InterfaceMethodref:
-    case CONSTANT_NameandType:
-    case CONSTANT_InvokeDynamic:
-      putu2(e.refs[0]->getOutputIndex());
-      putu2(e.refs[1]->getOutputIndex());
-      break;
-    case CONSTANT_MethodHandle:
-        putu1(e.value.i);
-        putu2(e.refs[0]->getOutputIndex());
-        break;
-    case CONSTANT_MethodType:
-      putu2(e.refs[0]->getOutputIndex());
-      break;
-    case CONSTANT_BootstrapMethod: // should not happen
-    default:
-      abort(ERROR_INTERNAL);
-    }
-  }
-
-#ifndef PRODUCT
-  total_cp_size[0] += cp.outputIndexLimit;
-  total_cp_size[1] += (int)cur_classfile_head.size();
-#endif
-  close_output();
-}
-
-unpacker::file* unpacker::get_next_file() {
-  CHECK_0;
-  free_temps();
-  if (files_remaining == 0) {
-    // Leave a clue that we're exhausted.
-    cur_file.name = null;
-    cur_file.size = null;
-    if (archive_size != 0) {
-      julong predicted_size = unsized_bytes_read + archive_size;
-      if (predicted_size != bytes_read)
-        abort("archive header had incorrect size");
-    }
-    return null;
-  }
-  files_remaining -= 1;
-  assert(files_written < file_count || classes_written < class_count);
-  cur_file.name = "";
-  cur_file.size = 0;
-  cur_file.modtime = default_file_modtime;
-  cur_file.options = default_file_options;
-  cur_file.data[0].set(null, 0);
-  cur_file.data[1].set(null, 0);
-  if (files_written < file_count) {
-    entry* e = file_name.getRef();
-    CHECK_0;
-    cur_file.name = e->utf8String();
-    CHECK_0;
-    bool haveLongSize = (testBit(archive_options, AO_HAVE_FILE_SIZE_HI));
-    cur_file.size = file_size_hi.getLong(file_size_lo, haveLongSize);
-    if (testBit(archive_options, AO_HAVE_FILE_MODTIME))
-      cur_file.modtime += file_modtime.getInt();  //relative to archive modtime
-    if (testBit(archive_options, AO_HAVE_FILE_OPTIONS))
-      cur_file.options |= file_options.getInt() & ~suppress_file_options;
-  } else if (classes_written < class_count) {
-    // there is a class for a missing file record
-    cur_file.options |= FO_IS_CLASS_STUB;
-  }
-  if ((cur_file.options & FO_IS_CLASS_STUB) != 0) {
-    assert(classes_written < class_count);
-    classes_written += 1;
-    if (cur_file.size != 0) {
-      abort("class file size transmitted");
-      return null;
-    }
-    reset_cur_classfile();
-
-    // write the meat of the classfile:
-    write_classfile_tail();
-    cur_file.data[1] = cur_classfile_tail.b;
-    CHECK_0;
-
-    // write the CP of the classfile, second:
-    write_classfile_head();
-    cur_file.data[0] = cur_classfile_head.b;
-    CHECK_0;
-
-    cur_file.size += cur_file.data[0].len;
-    cur_file.size += cur_file.data[1].len;
-    if (cur_file.name[0] == '\0') {
-      bytes& prefix = cur_class->ref(0)->value.b;
-      const char* suffix = ".class";
-      int len = (int)(prefix.len + strlen(suffix));
-      bytes name; name.set(T_NEW(byte, add_size(len, 1)), len);
-      cur_file.name = name.strcat(prefix).strcat(suffix).strval();
-    }
-  } else {
-    // If there is buffered file data, produce a pointer to it.
-    if (cur_file.size != (size_t) cur_file.size) {
-      // Silly size specified.
-      abort("resource file too large");
-      return null;
-    }
-    size_t rpleft = input_remaining();
-    if (rpleft > 0) {
-      if (rpleft > cur_file.size)
-        rpleft = (size_t) cur_file.size;
-      cur_file.data[0].set(rp, rpleft);
-      rp += rpleft;
-    }
-    if (rpleft < cur_file.size) {
-      // Caller must read the rest.
-      size_t fleft = (size_t)cur_file.size - rpleft;
-      bytes_read += fleft;  // Credit it to the overall archive size.
-    }
-  }
-  CHECK_0;
-  bytes_written += cur_file.size;
-  files_written += 1;
-  return &cur_file;
-}
-
-// Write a file to jarout.
-void unpacker::write_file_to_jar(unpacker::file* f) {
-  size_t htsize = f->data[0].len + f->data[1].len;
-  julong fsize = f->size;
-#ifndef PRODUCT
-  if (nowrite NOT_PRODUCT(|| skipfiles-- > 0)) {
-    PRINTCR((2,"would write %d bytes to %s", (int) fsize, f->name));
-    return;
-  }
-#endif
-  if (htsize == fsize) {
-    jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime,
-                        f->data[0], f->data[1]);
-  } else {
-    assert(input_remaining() == 0);
-    bytes part1, part2;
-    part1.len = f->data[0].len;
-    part1.set(T_NEW(byte, part1.len), part1.len);
-    part1.copyFrom(f->data[0]);
-    assert(f->data[1].len == 0);
-    part2.set(null, 0);
-    size_t fleft = (size_t) fsize - part1.len;
-    assert(bytes_read > fleft);  // part2 already credited by get_next_file
-    bytes_read -= fleft;
-    if (fleft > 0) {
-      // Must read some more.
-      if (live_input) {
-        // Stop using the input buffer.  Make a new one:
-        if (free_input)  input.free();
-        input.init(fleft > (1<<12) ? fleft : (1<<12));
-        free_input = true;
-        live_input = false;
-      } else {
-        // Make it large enough.
-        assert(free_input);  // must be reallocable
-        input.ensureSize(fleft);
-      }
-      rplimit = rp = input.base();
-      CHECK;
-      input.setLimit(rp + fleft);
-      if (!ensure_input(fleft))
-        abort("EOF reading resource file");
-      part2.ptr = input_scan();
-      part2.len = input_remaining();
-      rplimit = rp = input.base();
-    }
-    jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime,
-                        part1, part2);
-  }
-  if (verbose >= 3) {
-    fprintf(errstrm, "Wrote "
-                     LONG_LONG_FORMAT " bytes to: %s\n", fsize, f->name);
-  }
-}
-
-// Redirect the stdio to the specified file in the unpack.log.file option
-void unpacker::redirect_stdio() {
-  if (log_file == null) {
-    log_file = LOGFILE_STDOUT;
-  }
-  if (log_file == errstrm_name)
-    // Nothing more to be done.
-    return;
-  errstrm_name = log_file;
-  if (strcmp(log_file, LOGFILE_STDERR) == 0) {
-    errstrm = stderr;
-    return;
-  } else if (strcmp(log_file, LOGFILE_STDOUT) == 0) {
-    errstrm = stdout;
-    return;
-  } else if (log_file[0] != '\0' && (errstrm = fopen(log_file,"a+")) != NULL) {
-    return;
-  } else {
-    fprintf(stderr, "Can not open log file %s\n", log_file);
-    // Last resort
-    // (Do not use stdout, since it might be jarout->jarfp.)
-    errstrm = stderr;
-    log_file = errstrm_name = LOGFILE_STDERR;
-  }
-}
-
-#ifndef PRODUCT
-int unpacker::printcr_if_verbose(int level, const char* fmt ...) {
-  if (verbose < level)  return 0;
-  va_list vl;
-  va_start(vl, fmt);
-  char fmtbuf[300];
-  strcpy(fmtbuf+100, fmt);
-  strcat(fmtbuf+100, "\n");
-  char* fmt2 = fmtbuf+100;
-  while (level-- > 0)  *--fmt2 = ' ';
-  vfprintf(errstrm, fmt2, vl);
-  return 1;  // for ?: usage
-}
-#endif
-
-void unpacker::abort(const char* message) {
-  if (message == null)  message = "error unpacking archive";
-#ifdef UNPACK_JNI
-  if (message[0] == '@') {  // secret convention for sprintf
-     bytes saved;
-     saved.saveFrom(message+1);
-     mallocs.add(message = saved.strval());
-   }
-  abort_message = message;
-  return;
-#else
-  if (message[0] == '@')  ++message;
-  fprintf(errstrm, "%s\n", message);
-#ifndef PRODUCT
-  fflush(errstrm);
-  ::abort();
-#else
-  exit(-1);
-#endif
-#endif // JNI
-}
diff --git a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
index 5497114..641fa2f 100644
--- a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
+++ b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java
@@ -27,8 +27,10 @@
 
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.misc.VM;
+import jdk.internal.ref.Cleaner;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
+import sun.nio.ch.DirectBuffer;
 
 import java.lang.reflect.Field;
 import java.security.ProtectionDomain;
@@ -1228,4 +1230,28 @@
     public void fullFence() {
         theInternalUnsafe.fullFence();
     }
+
+    /**
+     * Invokes the given direct byte buffer's cleaner, if any.
+     *
+     * @param directBuffer a direct byte buffer
+     * @throws NullPointerException if {@code directBuffer} is null
+     * @throws IllegalArgumentException if {@code directBuffer} is non-direct,
+     * or is a {@link java.nio.Buffer#slice slice}, or is a
+     * {@link java.nio.Buffer#duplicate duplicate}
+     * @since 9
+     */
+    public void invokeCleaner(java.nio.ByteBuffer directBuffer) {
+        if (!directBuffer.isDirect())
+            throw new IllegalArgumentException("buffer is non-direct");
+
+        DirectBuffer db = (DirectBuffer)directBuffer;
+        if (db.attachment() != null)
+            throw new IllegalArgumentException("duplicate or slice");
+
+        Cleaner cleaner = db.cleaner();
+        if (cleaner != null) {
+            cleaner.clean();
+        }
+    }
 }
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index 7959eaa..cc64579 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -205,6 +205,8 @@
 
 java/rmi/transport/dgcDeadLock/DGCDeadLock.java                 8029360 macosx-all
 
+java/rmi/registry/readTest/readTest.sh                          7146543 generic-all
+
 ############################################################################
 
 # jdk_security
@@ -215,12 +217,12 @@
 
 sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java      8026393 generic-all
 
-sun/security/krb5/auto/HttpNegotiateServer.java                 8038079 generic-all
-
 sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java         8161232 macosx-all
 
 sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java  8171043 windows-all
 
+javax/net/ssl/DTLS/PacketLossRetransmission.java                8169086 macosx-x64
+
 ############################################################################
 
 # jdk_sound
@@ -232,6 +234,8 @@
 
 javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all
 
+javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java 8168881 generic-all
+
 ############################################################################
 
 # jdk_imageio
@@ -263,7 +267,8 @@
 tools/jimage/JImageListTest.java                                8169713 generic-all
 tools/jimage/JImageVerifyTest.java                              8169713 generic-all
 
-tools/jlink/ModuleNamesOrderTest.java                           8171070 generic-all
+
+tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java       8169971 windows-x64
 
 ############################################################################
 
@@ -287,8 +292,6 @@
 
 # jdk_util
 
-java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java 8062512 generic-all
-
 java/util/BitSet/BitSetStreamTest.java                          8079538 generic-all
 
 
diff --git a/jdk/test/com/sun/jdi/EvalArraysAsList.sh b/jdk/test/com/sun/jdi/EvalArraysAsList.sh
new file mode 100644
index 0000000..fa5cd93
--- /dev/null
+++ b/jdk/test/com/sun/jdi/EvalArraysAsList.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#  @test
+#  @bug 8160024
+#  @summary jdb returns invalid argument count if first parameter to Arrays.asList is null
+#
+#  @run shell/timeout=300 EvalArraysAsList.sh
+#
+#  The test checks if evaluation of the expression java.util.Arrays.asList(null, "a")
+#  works normally and does not throw an IllegalArgumentException.
+
+classname=EvalArraysAsList
+
+createJavaFile()
+{
+    cat <<EOF > $classname.java.1
+public class $classname {
+    public static void main(String[] args) {
+        java.util.List<Object> l = java.util.Arrays.asList(null, "a");
+        System.out.println("java.util.Arrays.asList(null, \"a\") returns: " + l);
+        return;    // @1 breakpoint
+    }
+}
+EOF
+}
+
+# drive jdb by sending cmds to it and examining its output
+dojdbCmds()
+{
+    setBkpts @1
+    runToBkpt @1
+
+    cmd eval "java.util.Arrays.asList(null, null)"
+    jdbFailIfPresent "IllegalArgumentException" 3
+
+    cmd eval "java.util.Arrays.asList(null, \"a\")"
+    jdbFailIfPresent "IllegalArgumentException" 3
+
+    cmd eval "java.util.Arrays.asList(\"a\", null)"
+    jdbFailIfPresent "IllegalArgumentException" 3
+}
+
+
+mysetup()
+{
+    if [ -z "$TESTSRC" ] ; then
+        TESTSRC=.
+    fi
+
+    for ii in . $TESTSRC $TESTSRC/.. ; do
+        if [ -r "$ii/ShellScaffold.sh" ] ; then
+            . $ii/ShellScaffold.sh
+            break
+        fi
+    done
+}
+
+# You could replace this next line with the contents
+# of ShellScaffold.sh and this script will run just the same.
+mysetup
+
+runit
+pass
diff --git a/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java
index 368731e..748e49a 100644
--- a/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java
+++ b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -226,9 +226,10 @@
         sm.grantPermission(new RuntimePermission("createClassLoader"));
         sm.grantPermission(new ReflectPermission("suppressAccessChecks"));
         sm.grantPermission(new java.util.logging.LoggingPermission("control", ""));
-        sm.grantPermission(new java.lang.RuntimePermission("exitVM.97"));
+        sm.grantPermission(new java.lang.RuntimePermission("exitVM.*"));
         sm.grantPermission(new java.lang.RuntimePermission("modifyThreadGroup"));
         sm.grantPermission(new java.lang.RuntimePermission("modifyThread"));
+        sm.grantPermission(new java.security.SecurityPermission("getProperty.jdk.jar.disabledAlgorithms"));
         for(MBeanOperationInfo opInfo : info.getOperations()) {
             Permission opPermission = new MBeanPermission(info.getClassName(),
                     opInfo.getName(),
diff --git a/jdk/test/java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java b/jdk/test/java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java
new file mode 100644
index 0000000..6db0225
--- /dev/null
+++ b/jdk/test/java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169589
+ * @summary Activating a dialog puts to back another dialog owned by the same frame
+ * @author Dmitry Markov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main DialogAboveFrameTest
+ */
+
+import java.awt.Color;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+
+import test.java.awt.regtesthelpers.Util;
+
+public class DialogAboveFrameTest {
+    public static void main(String[] args) {
+        Robot robot = Util.createRobot();
+
+        Frame frame = new Frame("Frame");
+        frame.setBackground(Color.BLUE);
+        frame.setBounds(200, 50, 300, 300);
+        frame.setVisible(true);
+
+        Dialog dialog1 = new Dialog(frame, "Dialog 1", false);
+        dialog1.setBackground(Color.RED);
+        dialog1.setBounds(100, 100, 200, 200);
+        dialog1.setVisible(true);
+
+        Dialog dialog2 = new Dialog(frame, "Dialog 2", false);
+        dialog2.setBackground(Color.GREEN);
+        dialog2.setBounds(400, 100, 200, 200);
+        dialog2.setVisible(true);
+
+        Util.waitForIdle(robot);
+
+        Util.clickOnComp(dialog2, robot);
+        Util.waitForIdle(robot);
+
+        Point point = dialog1.getLocationOnScreen();
+        int x = point.x + (int)(dialog1.getWidth() * 0.9);
+        int y = point.y + (int)(dialog1.getHeight() * 0.9);
+
+        try {
+            if (!robot.getPixelColor(x, y).equals(dialog1.getBackground())) {
+                throw new RuntimeException("Test FAILED: Dialog is behind the frame");
+            }
+        } finally {
+            frame.dispose();
+            dialog1.dispose();
+            dialog2.dispose();
+        }
+    }
+}
+
diff --git a/jdk/test/java/awt/JAWT/JAWT.sh b/jdk/test/java/awt/JAWT/JAWT.sh
index ab511d8..d01ff02 100644
--- a/jdk/test/java/awt/JAWT/JAWT.sh
+++ b/jdk/test/java/awt/JAWT/JAWT.sh
@@ -122,7 +122,7 @@
 
 # Skip unsupported platforms
 case `uname -m` in
-    arm* | ppc* )
+    arm* | ppc* | s390* )
       echo "Test passed. Not supported on current architecture."
       exit 0
       ;;
diff --git a/jdk/test/java/awt/JAWT/Makefile.unix b/jdk/test/java/awt/JAWT/Makefile.unix
index b3be2f9..978d6ce 100644
--- a/jdk/test/java/awt/JAWT/Makefile.unix
+++ b/jdk/test/java/awt/JAWT/Makefile.unix
@@ -1,4 +1,4 @@
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 
 J_INC =		$(TESTJAVA)/include
 INCLUDES =	-I$(J_INC) -I$(J_INC)/$(SYST) -I.
-LIBS =		-L$(TESTJAVA)/lib/$(ARCH) -ljawt -lX11
+LIBS =		-L$(TESTJAVA)/lib -ljawt -lX11
 
 all:		$(CLASSES) libmylib.so
 
diff --git a/jdk/test/java/awt/Menu/WrongParentAfterRemoveMenu/WrongParentAfterRemoveMenu.java b/jdk/test/java/awt/Menu/WrongParentAfterRemoveMenu/WrongParentAfterRemoveMenu.java
new file mode 100644
index 0000000..18dc479
--- /dev/null
+++ b/jdk/test/java/awt/Menu/WrongParentAfterRemoveMenu/WrongParentAfterRemoveMenu.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.PopupMenu;
+import java.awt.Window;
+
+/**
+ * @test
+ * @bug 8165769
+ * @key headful
+ */
+public final class WrongParentAfterRemoveMenu {
+
+    public static void main(final String[] args) {
+        testMenuBar();
+        testComponent();
+        testFrame();
+    }
+
+    private static void testFrame() {
+        // peer exists
+        Frame frame = new Frame();
+        try {
+            frame.pack();
+            PopupMenu popupMenu = new PopupMenu();
+            frame.add(popupMenu);
+            checkParent(popupMenu, frame);
+            frame.remove(popupMenu);
+            checkParent(popupMenu, null);
+        } finally {
+            frame.dispose();
+        }
+        // peer is null
+        frame = new Frame();
+        PopupMenu popupMenu = new PopupMenu();
+        frame.add(popupMenu);
+        checkParent(popupMenu, frame);
+        frame.remove(popupMenu);
+        checkParent(popupMenu, null);
+    }
+
+    private static void testComponent() {
+        // peer exists
+        Window w = new Window(null);
+        try {
+            w.pack();
+            PopupMenu popupMenu = new PopupMenu();
+            w.add(popupMenu);
+            checkParent(popupMenu, w);
+            w.remove(popupMenu);
+            checkParent(popupMenu, null);
+        } finally {
+            w.dispose();
+        }
+        // peer is null
+        w = new Window(null);
+        PopupMenu popupMenu = new PopupMenu();
+        w.add(popupMenu);
+        checkParent(popupMenu, w);
+        w.remove(popupMenu);
+        checkParent(popupMenu, null);
+    }
+
+    private static void testMenuBar() {
+        // peer exists
+        MenuBar mb = new MenuBar();
+        try {
+            mb.addNotify();
+            Menu m1 = new Menu();
+            Menu m2 = new Menu();
+            m1.add(m2);
+            mb.add(m1);
+            checkParent(m1, mb);
+            checkParent(m2, m1);
+            m1.remove(m2);
+            checkParent(m2, null);
+            mb.remove(m1);
+            checkParent(m1, null);
+        } finally {
+            mb.removeNotify();
+        }
+        // peer is null
+        mb = new MenuBar();
+        Menu m1 = new Menu();
+        Menu m2 = new Menu();
+        m1.add(m2);
+        mb.add(m1);
+        checkParent(m1, mb);
+        checkParent(m2, m1);
+        m1.remove(m2);
+        checkParent(m2, null);
+        mb.remove(m1);
+        checkParent(m1, null);
+    }
+
+    private static void checkParent(final Menu menu, final Object parent) {
+        if (menu.getParent() != parent) {
+            System.err.println("Expected: " + parent);
+            System.err.println("Actual: " + menu.getParent());
+            throw new RuntimeException("Wrong parent");
+        }
+    }
+}
diff --git a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java
index 26c4f72..a4c026b 100644
--- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java
+++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java
@@ -44,9 +44,11 @@
 import javax.imageio.ImageIO;
 
 /**
- * @test @bug 8145174 8151787
+ * @test
+ * @bug 8145174 8151787 8168657
  * @summary HiDPI splash screen support on Linux
  * @modules java.desktop/sun.java2d
+ * @requires (os.family == "linux")
  * @run main UnixMultiResolutionSplashTest
  */
 public class UnixMultiResolutionSplashTest {
diff --git a/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java b/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java
index 5ef5f1d..06d4dc4 100644
--- a/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java
+++ b/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java
@@ -25,6 +25,7 @@
   test
   @bug 6242241
   @summary Tests basic DnD functionality in an applet
+  @requires (os.family == "windows")
   @author Your Name: Alexey Utkin area=dnd
   @run applet/manual=yesno DnDFileGroupDescriptor.html
 */
diff --git a/jdk/test/java/awt/font/Fallback/SurrogatesFallbackTest.java b/jdk/test/java/awt/font/Fallback/SurrogatesFallbackTest.java
new file mode 100644
index 0000000..9a87243
--- /dev/null
+++ b/jdk/test/java/awt/font/Fallback/SurrogatesFallbackTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 JetBrains s.r.o.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/* @test
+ * @bug 8169202
+ * @summary verify font fallback for surrogate pairs on macOS
+ * @requires os.family == "mac"
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+import java.awt.image.BufferedImage;
+import java.util.function.Consumer;
+
+public class SurrogatesFallbackTest {
+    private static final int CHARACTER = 0x1d400; // MATHEMATICAL BOLD CAPITAL A
+    private static final Font FONT = new Font("Menlo", // expected to fallback to STIXGeneral for the character above
+                                              Font.PLAIN,
+                                              12);
+    private static final int IMAGE_WIDTH = 20;
+    private static final int IMAGE_HEIGHT = 20;
+    private static final int GLYPH_X = 5;
+    private static final int GLYPH_Y = 15;
+
+    public static void main(String[] args) {
+        BufferedImage noGlyph = createImage(g -> {});
+        BufferedImage missingGlyph = createImage(g -> {
+            GlyphVector gv = FONT.createGlyphVector(g.getFontRenderContext(), new int[]{FONT.getMissingGlyphCode()});
+            g.drawGlyphVector(gv, GLYPH_X, GLYPH_Y);
+        });
+        BufferedImage surrogateCharGlyph = createImage(g -> {
+            g.setFont(FONT);
+            g.drawString(new String(Character.toChars(CHARACTER)), GLYPH_X, GLYPH_Y);
+        });
+
+        if (imagesAreEqual(surrogateCharGlyph, noGlyph)) {
+            throw new RuntimeException("Character was not rendered");
+        }
+        if (imagesAreEqual(surrogateCharGlyph, missingGlyph)) {
+            throw new RuntimeException("Character is rendered as missing");
+        }
+    }
+
+    private static BufferedImage createImage(Consumer<Graphics2D> drawing) {
+        BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = image.createGraphics();
+        g.setColor(Color.white);
+        g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+        g.setColor(Color.black);
+        drawing.accept(g);
+        g.dispose();
+        return image;
+    }
+
+    private static boolean imagesAreEqual(BufferedImage i1, BufferedImage i2) {
+        if (i1.getWidth() != i2.getWidth() || i1.getHeight() != i2.getHeight()) return false;
+        for (int i = 0; i < i1.getWidth(); i++) {
+            for (int j = 0; j < i1.getHeight(); j++) {
+                if (i1.getRGB(i, j) != i2.getRGB(i, j)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
+
diff --git a/jdk/test/java/awt/font/TextLayout/ArabicDiacriticTest.java b/jdk/test/java/awt/font/TextLayout/ArabicDiacriticTest.java
new file mode 100644
index 0000000..e74edf8
--- /dev/null
+++ b/jdk/test/java/awt/font/TextLayout/ArabicDiacriticTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+/* @test
+ * @summary verify Arab Diacritic Positioning
+ * @bug 8168759
+ */
+
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.util.Locale;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class ArabicDiacriticTest {
+
+    static final String SAMPLE =
+     "\u0627\u0644\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629";
+
+    static final String STR1 = "\u0644\u0639\u064e\u0629";
+    static final String STR2 = "\u0644\u0639\u0629";
+
+    static JFrame frame;
+    static final String FONT = "DejaVu Sans";
+
+    public static void main(String args[]) throws Exception {
+        showText(); // for a human
+        measureText(); // for the test harness
+        Thread.sleep(5000);
+        frame.dispose();
+    }
+
+    static void showText() {
+        SwingUtilities.invokeLater(() -> {
+            frame = new JFrame();
+            JLabel label = new JLabel(SAMPLE);
+            Font font = new Font(FONT, Font.PLAIN, 36);
+            label.setFont(font);
+            frame.setLayout(new GridLayout(3,1));
+            frame.add(label);
+            label = new JLabel(STR1);
+            label.setFont(font);
+            frame.add(label);
+            label = new JLabel(STR2);
+            label.setFont(font);
+            frame.add(label);
+            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            frame.pack();
+            frame.setLocationRelativeTo(null);
+            frame.setVisible(true);
+        });
+    }
+
+    static void measureText() {
+        Font font = new Font(FONT, Font.PLAIN, 36);
+        if (!font.getFamily(Locale.ENGLISH).equals(FONT)) {
+            return;
+        }
+        FontRenderContext frc = new FontRenderContext(null, false, false);
+        TextLayout tl1 = new TextLayout(STR1, font, frc);
+        TextLayout tl2 = new TextLayout(STR2, font, frc);
+        Rectangle r1 = tl1.getPixelBounds(frc, 0f, 0f);
+        Rectangle r2 = tl2.getPixelBounds(frc, 0f, 0f);
+        if (r1.height > r2.height) {
+            System.out.println(font);
+            System.out.println(r1);
+            System.out.println(r2);
+            throw new RuntimeException("BAD BOUNDS");
+        }
+    }
+}
diff --git a/jdk/test/java/io/File/createTempFile/NameTooLong.java b/jdk/test/java/io/File/createTempFile/NameTooLong.java
new file mode 100644
index 0000000..b86bd73
--- /dev/null
+++ b/jdk/test/java/io/File/createTempFile/NameTooLong.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8148023
+ * @summary Verify that createTempFile() will not fail for long component names.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+public class NameTooLong {
+    public static void main(String[] args) {
+        String[][] prefixSuffix = new String[][] {
+            new String[] {"1234567890123456789012345678901234567xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx89012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890","txt"},
+            new String[] {"prefix","1234567890123456789012345678901234567xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx89012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.txt"},
+            new String[] {"prefix",".txt1234567890123456789012345678901234567xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx89012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"}
+        };
+
+        int failures = 0;
+        int index = 0;
+        for (String[] ps : prefixSuffix) {
+            File f;
+            try {
+                f = File.createTempFile(ps[0], ps[1]);
+                String s = f.toPath().getFileName().toString();
+                if (!s.startsWith(ps[0].substring(0, 3))) {
+                    System.err.printf("%s did not start with %s%n", s,
+                        ps[0].substring(0, 3));
+                    failures++;
+                }
+                if (ps[1].startsWith(".")
+                    && !s.contains(ps[1].substring(0, 4))) {
+                    System.err.printf("%s did not contain %s%n", s,
+                        ps[1].substring(0, 4));;
+                    failures++;
+                }
+            } catch (IOException e) {
+                failures++;
+                System.err.println();
+                e.printStackTrace();
+                System.err.println();
+            }
+            index++;
+        }
+
+        if (failures != 0) {
+            throw new RuntimeException("Test failed!");
+        }
+    }
+}
diff --git a/jdk/test/java/io/FilePermission/Invalid.java b/jdk/test/java/io/FilePermission/Invalid.java
index 38c6a98..2a343d7 100644
--- a/jdk/test/java/io/FilePermission/Invalid.java
+++ b/jdk/test/java/io/FilePermission/Invalid.java
@@ -37,6 +37,9 @@
 
     public static void main(String args[]) throws Exception {
 
+        // Allmighty
+        FilePermission af = new FilePermission("<<ALL FILES>>", "read");
+
         // Normal
         FilePermission fp = new FilePermission("a", "read");
 
@@ -57,6 +60,9 @@
         // Invalid implies itself
         Asserts.assertTrue(fp1.implies(fp1));
 
+        // <<ALL FILES>> implies invalid
+        Asserts.assertTrue(af.implies(fp1));
+
         // and not implies or implied by anything else, including other
         // invalid ones
         Asserts.assertFalse(fp.implies(fp1));
diff --git a/jdk/test/java/lang/SecurityManager/CheckSecurityProvider.java b/jdk/test/java/lang/SecurityManager/CheckSecurityProvider.java
index 1c7f7b4..722ccd7 100644
--- a/jdk/test/java/lang/SecurityManager/CheckSecurityProvider.java
+++ b/jdk/test/java/lang/SecurityManager/CheckSecurityProvider.java
@@ -62,7 +62,7 @@
         if (os.equals("SunOS")) {
             layer.findModule("jdk.crypto.ucrypto")
                 .ifPresent(m -> expected.add("com.oracle.security.ucrypto.UcryptoProvider"));
-            layer.findModule("jdk.crypto.pkcs11")
+            layer.findModule("jdk.crypto.token")
                 .ifPresent(m -> expected.add("sun.security.pkcs11.SunPKCS11"));
         }
         expected.add("sun.security.provider.Sun");
@@ -91,7 +91,7 @@
             expected.add("apple.security.AppleProvider");
         }
         if (!os.equals("SunOS")) {
-            layer.findModule("jdk.crypto.pkcs11")
+            layer.findModule("jdk.crypto.token")
                 .ifPresent(m -> expected.add("sun.security.pkcs11.SunPKCS11"));
         }
 
diff --git a/jdk/test/java/lang/StackTraceElement/ModuleFrames.java b/jdk/test/java/lang/StackTraceElement/ModuleFrames.java
index a3b6675..6f23160 100644
--- a/jdk/test/java/lang/StackTraceElement/ModuleFrames.java
+++ b/jdk/test/java/lang/StackTraceElement/ModuleFrames.java
@@ -27,6 +27,9 @@
  * @run testng ModuleFrames
  */
 
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 
 import org.testng.annotations.Test;
@@ -47,11 +50,30 @@
             assertEquals(topFrame.getModuleName(), "java.base",
                     "Expected top frame to be in module java.base");
 
-            assertTrue(topFrame.toString().contains("java.base"),
-                    "Expected toString of top frame to include java.base");
+            assertTrue(topFrame.toString().startsWith("java.base"),
+                    "Expected toString of top frame to omit loader name, start with module name: java.base");
+
+            assertTrue(!topFrame.toString().contains("@"),
+                    "Expected toString of top frame not to include module version ('@')");
+
+            Path home = Paths.get(System.getProperty("java.home"));
+            boolean isImage = Files.exists(home.resolve("lib").resolve("modules"));
+            if (isImage) {
+                assertTrue(!topFrame.getModuleVersion().isEmpty(),
+                        "Expected non-empty STE.getModuleVersion() for top frame");
+            }
 
             assertNull(thisFrame.getModuleName(),
                     "Expected frame for test not to have a module name");
+
+            assertTrue(thisFrame.toString().startsWith(this.getClass().getName()),
+                    "Expected toString to start with class name (no loader or module name");
+
+            ClassLoader testCL = this.getClass().getClassLoader();
+            if (ClassLoader.getSystemClassLoader().getClass().isInstance(testCL)) {
+                assertEquals(thisFrame.getClassLoaderName(), "app",
+                        "Expect STE to have loader name of \"app\"");
+            }
         }
     }
 
diff --git a/jdk/test/java/lang/StrictMath/ExpTests.java b/jdk/test/java/lang/StrictMath/ExpTests.java
new file mode 100644
index 0000000..0a2e1f0
--- /dev/null
+++ b/jdk/test/java/lang/StrictMath/ExpTests.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8139688
+ * @key randomness
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.RandomFactory
+ * @build Tests
+ * @build FdlibmTranslit
+ * @build ExpTests
+ * @run main ExpTests
+ * @summary Tests specifically for StrictMath.exp
+ */
+
+import jdk.testlibrary.RandomFactory;
+
+/**
+ * The role of this test is to verify that the FDLIBM exp algorithm is
+ * being used by running golden file style tests on values that may
+ * vary from one conforming exponential implementation to another.
+ */
+
+public class ExpTests {
+    private ExpTests(){}
+
+    public static void main(String [] argv) {
+        int failures = 0;
+
+        failures += testExp();
+        failures += testAgainstTranslit();
+
+        if (failures > 0) {
+            System.err.println("Testing the exponential incurred "
+                               + failures + " failures.");
+            throw new RuntimeException();
+        }
+    }
+
+    // From the fdlibm source, the overflow threshold in hex is:
+    // 0x4086_2E42_FEFA_39EF.
+    static final double EXP_OVERFLOW_THRESH  = Double.longBitsToDouble(0x4086_2E42_FEFA_39EFL);
+
+    // From the fdlibm source, the underflow threshold in hex is:
+    // 0xc087_4910_D52D_3051L.
+    static final double EXP_UNDERFLOW_THRESH = Double.longBitsToDouble(0xc087_4910_D52D_3051L);
+
+    static int testExp() {
+        int failures = 0;
+
+        double [][] testCases = {
+            // Some of these could be moved to common Math/StrictMath exp testing.
+            {Double.NaN,                      Double.NaN},
+            {Double.MAX_VALUE,                Double.POSITIVE_INFINITY},
+            {Double.POSITIVE_INFINITY,        Double.POSITIVE_INFINITY},
+            {Double.NEGATIVE_INFINITY,        +0.0},
+            {EXP_OVERFLOW_THRESH,                 0x1.ffff_ffff_fff2ap1023},
+            {Math.nextUp(EXP_OVERFLOW_THRESH),    Double.POSITIVE_INFINITY},
+            {Math.nextDown(EXP_UNDERFLOW_THRESH), +0.0},
+            {EXP_UNDERFLOW_THRESH,                +Double.MIN_VALUE},
+        };
+
+        for(double[] testCase: testCases)
+            failures+=testExpCase(testCase[0], testCase[1]);
+
+        return failures;
+    }
+
+    static int testExpCase(double input, double expected) {
+        int failures = 0;
+
+        failures+=Tests.test("StrictMath.exp(double)", input,
+                             StrictMath.exp(input), expected);
+        return failures;
+    }
+
+    // Initialize shared random number generator
+    private static java.util.Random random = RandomFactory.getRandom();
+
+    /**
+     * Test StrictMath.exp against transliteration port of exp.
+     */
+    private static int testAgainstTranslit() {
+        int failures = 0;
+
+        double[] decisionPoints = {
+            // Near overflow threshold
+            EXP_OVERFLOW_THRESH - 512*Math.ulp(EXP_OVERFLOW_THRESH),
+
+            // Near underflow threshold
+            EXP_UNDERFLOW_THRESH - 512*Math.ulp(EXP_UNDERFLOW_THRESH),
+
+            // Straddle algorithm conditional checks
+            Double.longBitsToDouble(0x4086_2E42_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3fd6_2e42_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3FF0_A2B2_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3e30_0000_0000_0000L - 512L),
+
+            // Other notable points
+            Double.MIN_NORMAL - Math.ulp(Double.MIN_NORMAL)*512,
+            -Double.MIN_VALUE*512,
+        };
+
+        for (double decisionPoint : decisionPoints) {
+            double ulp = Math.ulp(decisionPoint);
+            failures += testRange(decisionPoint - 1024*ulp, ulp, 1_024);
+        }
+
+        // Try out some random values
+        for (int i = 0; i < 100; i++) {
+            double x = Tests.createRandomDouble(random);
+            failures += testRange(x, Math.ulp(x), 100);
+        }
+
+        return failures;
+    }
+
+    private static int testRange(double start, double increment, int count) {
+        int failures = 0;
+        double x = start;
+        for (int i = 0; i < count; i++, x += increment) {
+            failures += testExpCase(x, FdlibmTranslit.Exp.compute(x));
+        }
+        return failures;
+    }
+}
diff --git a/jdk/test/java/lang/StrictMath/FdlibmTranslit.java b/jdk/test/java/lang/StrictMath/FdlibmTranslit.java
index 64d4ca6..5ad48cb 100644
--- a/jdk/test/java/lang/StrictMath/FdlibmTranslit.java
+++ b/jdk/test/java/lang/StrictMath/FdlibmTranslit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,7 +48,8 @@
      */
     private static double __LO(double x, int low) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+                                       (low    & 0x0000_0000_FFFF_FFFFL));
     }
 
     /**
@@ -65,7 +66,8 @@
      */
     private static double __HI(double x, int high) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+                                       ( ((long)high)) << 32 );
     }
 
     public static double hypot(double x, double y) {
@@ -250,4 +252,136 @@
                 return w;
         }
     }
+
+    /**
+     * Returns the exponential of x.
+     *
+     * Method
+     *   1. Argument reduction:
+     *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+     *      Given x, find r and integer k such that
+     *
+     *               x = k*ln2 + r,  |r| <= 0.5*ln2.
+     *
+     *      Here r will be represented as r = hi-lo for better
+     *      accuracy.
+     *
+     *   2. Approximation of exp(r) by a special rational function on
+     *      the interval [0,0.34658]:
+     *      Write
+     *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+     *      We use a special Reme algorithm on [0,0.34658] to generate
+     *      a polynomial of degree 5 to approximate R. The maximum error
+     *      of this polynomial approximation is bounded by 2**-59. In
+     *      other words,
+     *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+     *      (where z=r*r, and the values of P1 to P5 are listed below)
+     *      and
+     *          |                  5          |     -59
+     *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+     *          |                             |
+     *      The computation of exp(r) thus becomes
+     *                             2*r
+     *              exp(r) = 1 + -------
+     *                            R - r
+     *                                 r*R1(r)
+     *                     = 1 + r + ----------- (for better accuracy)
+     *                                2 - R1(r)
+     *      where
+     *                               2       4             10
+     *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+     *
+     *   3. Scale back to obtain exp(x):
+     *      From step 1, we have
+     *         exp(x) = 2^k * exp(r)
+     *
+     * Special cases:
+     *      exp(INF) is INF, exp(NaN) is NaN;
+     *      exp(-INF) is 0, and
+     *      for finite argument, only exp(0)=1 is exact.
+     *
+     * Accuracy:
+     *      according to an error analysis, the error is always less than
+     *      1 ulp (unit in the last place).
+     *
+     * Misc. info.
+     *      For IEEE double
+     *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+     *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+     *
+     * Constants:
+     * The hexadecimal values are the intended ones for the following
+     * constants. The decimal values may be used, provided that the
+     * compiler will convert from decimal to binary accurately enough
+     * to produce the hexadecimal values shown.
+     */
+    static class Exp {
+        private static final double one     = 1.0;
+        private static final double[] halF = {0.5,-0.5,};
+        private static final double huge    = 1.0e+300;
+        private static final double twom1000= 9.33263618503218878990e-302;      /* 2**-1000=0x01700000,0*/
+        private static final double o_threshold=  7.09782712893383973096e+02;   /* 0x40862E42, 0xFEFA39EF */
+        private static final double u_threshold= -7.45133219101941108420e+02;   /* 0xc0874910, 0xD52D3051 */
+        private static final double[] ln2HI   ={ 6.93147180369123816490e-01,    /* 0x3fe62e42, 0xfee00000 */
+                                                 -6.93147180369123816490e-01};  /* 0xbfe62e42, 0xfee00000 */
+        private static final double[] ln2LO   ={ 1.90821492927058770002e-10,    /* 0x3dea39ef, 0x35793c76 */
+                                                 -1.90821492927058770002e-10,}; /* 0xbdea39ef, 0x35793c76 */
+        private static final double invln2 =  1.44269504088896338700e+00;       /* 0x3ff71547, 0x652b82fe */
+        private static final double P1   =  1.66666666666666019037e-01;         /* 0x3FC55555, 0x5555553E */
+        private static final double P2   = -2.77777777770155933842e-03;         /* 0xBF66C16C, 0x16BEBD93 */
+        private static final double P3   =  6.61375632143793436117e-05;         /* 0x3F11566A, 0xAF25DE2C */
+        private static final double P4   = -1.65339022054652515390e-06;         /* 0xBEBBBD41, 0xC5D26BF1 */
+        private static final double P5   =  4.13813679705723846039e-08;         /* 0x3E663769, 0x72BEA4D0 */
+
+        public static strictfp double compute(double x) {
+            double y,hi=0,lo=0,c,t;
+            int k=0,xsb;
+            /*unsigned*/ int hx;
+
+            hx  = __HI(x);  /* high word of x */
+            xsb = (hx>>31)&1;               /* sign bit of x */
+            hx &= 0x7fffffff;               /* high word of |x| */
+
+            /* filter out non-finite argument */
+            if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+                    if(((hx&0xfffff)|__LO(x))!=0)
+                        return x+x;                /* NaN */
+                    else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */
+                }
+                if(x > o_threshold) return huge*huge; /* overflow */
+                if(x < u_threshold) return twom1000*twom1000; /* underflow */
+            }
+
+            /* argument reduction */
+            if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+                if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                    hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+                } else {
+                    k  = (int)(invln2*x+halF[xsb]);
+                    t  = k;
+                    hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                    lo = t*ln2LO[0];
+                }
+                x  = hi - lo;
+            }
+            else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */
+                if(huge+x>one) return one+x;/* trigger inexact */
+            }
+            else k = 0;
+
+            /* x is now in primary range */
+            t  = x*x;
+            c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+            if(k==0)        return one-((x*c)/(c-2.0)-x);
+            else            y = one-((lo-(x*c)/(2.0-c))-hi);
+            if(k >= -1021) {
+                y = __HI(y, __HI(y) + (k<<20)); /* add k to y's exponent */
+                return y;
+            } else {
+                y = __HI(y, __HI(y) + ((k+1000)<<20));/* add k to y's exponent */
+                return y*twom1000;
+            }
+        }
+    }
 }
diff --git a/jdk/test/java/lang/invoke/DropLookupModeTest.java b/jdk/test/java/lang/invoke/DropLookupModeTest.java
new file mode 100644
index 0000000..be7d0a6
--- /dev/null
+++ b/jdk/test/java/lang/invoke/DropLookupModeTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run testng DropLookupModeTest
+ * @summary Basic unit tests Lookup::dropLookupMode
+ */
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class DropLookupModeTest {
+
+    /**
+     * Basic test of dropLookupMode
+     */
+    public void testBasic() {
+        final Lookup fullPowerLookup = MethodHandles.lookup();
+        final Class<?> lc = fullPowerLookup.lookupClass();
+        assertTrue(fullPowerLookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+        Lookup lookup = fullPowerLookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+        lookup = fullPowerLookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+        lookup = fullPowerLookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+        lookup = fullPowerLookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC));
+
+        lookup = fullPowerLookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    /**
+     * Starting with a full power Lookup, use dropLookupMode to create new Lookups
+     * with reduced access.
+     */
+    public void testReducingAccess() {
+        Lookup lookup = MethodHandles.lookup();
+        final Class<?> lc = lookup.lookupClass();
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+        lookup = lookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+        lookup = lookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+        lookup = lookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+        lookup = lookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = lookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+
+        // repeat with lookup has no access
+        lookup = lookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    /**
+     * Test dropLookupMode on the public Lookup.
+     */
+    public void testPublicLookup() {
+        final Lookup publicLookup = MethodHandles.publicLookup();
+        final Class<?> lc = publicLookup.lookupClass();
+        assertTrue(publicLookup.lookupModes() == PUBLIC);
+
+        Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    @DataProvider(name = "badInput")
+    public Object[][] badInput() {
+        return new Object[][] {
+                { 0,                        null },
+                { (PACKAGE|PRIVATE),        null },    // two modes
+                { Integer.MAX_VALUE,        null },
+                { Integer.MIN_VALUE,        null },
+        };
+    }
+
+    /**
+     * Check that IllegalArgumentException is thrown for bad input
+     */
+    @Test(dataProvider = "badInput", expectedExceptions = {IllegalArgumentException.class})
+    public void testBadInput(Integer modeToDrop, Object ignore) {
+        MethodHandles.lookup().dropLookupMode(modeToDrop);
+    }
+
+}
\ No newline at end of file
diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java
index 87dfbd7..823ae87 100644
--- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java
@@ -84,8 +84,7 @@
 
     // Invoke MethodHandles.privateLookupIn with a reduced-power caller
     public void testReducedAccessCallerSameModule() throws Throwable {
-        // drop access
-        Lookup caller = MethodHandles.lookup().in(publicType);
+        Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
         assertTrue((caller.lookupModes() & PRIVATE) == 0);
         assertTrue((caller.lookupModes() & PACKAGE) == 0);
         assertTrue((caller.lookupModes() & MODULE) != 0);
diff --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java
index efaa498..276ecf7 100644
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java
@@ -23,8 +23,7 @@
 
 /**
  * @test
- * @modules java.base/java.lang.module:open
- *          java.base/jdk.internal.module
+ * @modules java.base/jdk.internal.module
  * @run testng ModuleDescriptorTest
  * @summary Basic test for java.lang.module.ModuleDescriptor and its builder
  */
@@ -41,16 +40,13 @@
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
 import java.lang.module.ModuleDescriptor.Version;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Module;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 
@@ -66,10 +62,20 @@
     public Object[][] invalidJavaIdentifiers() {
         return new Object[][]{
 
-            { null,         null },
-            { ".foo",       null },
-            { "foo.",       null },
-            { "[foo]",      null },
+            { null,             null },
+            { "1",              null },
+            { "1foo",           null },
+            { ".foo",           null },
+            { "foo.",           null },
+            { "[foo]",          null },
+            { "foo.1",          null },
+            { "1foo.bar",       null },
+            { "foo.1bar",       null },
+            { "foo.[bar]",      null },
+            { "foo..bar",       null },
+            { "foo.bar.1",      null },
+            { "foo.bar.1gus",   null },
+            { "foo.bar.[gus]",  null },
 
         };
     }
@@ -86,6 +92,15 @@
             .next();
     }
 
+    private Requires requires(Set<Modifier> mods, String mn, Version v) {
+        return ModuleDescriptor.module("m")
+            .requires(mods, mn, v)
+            .build()
+            .requires()
+            .iterator()
+            .next();
+    }
+
     private Requires requires(String mn) {
         return requires(Collections.emptySet(), mn);
     }
@@ -103,6 +118,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertTrue(r.modifiers().isEmpty());
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithOneModifier() {
@@ -111,6 +127,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithTwoModifiers() {
@@ -119,6 +136,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithAllModifiers() {
@@ -127,6 +145,18 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
+    }
+
+    public void testRequiresWithCompiledVersion() {
+        Version v = Version.parse("1.0");
+        Requires r = requires(Set.of(), "foo", v);
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertEquals(r.modifiers(), Set.of());
+        assertEquals(r.name(), "foo");
+        assertTrue(r.compiledVersion().isPresent());
+        assertEquals(r.compiledVersion().get().toString(), "1.0");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
@@ -167,6 +197,16 @@
         ModuleDescriptor.module("m").requires((Requires) null);
     }
 
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testRequiresWithNullModifiers() {
+        ModuleDescriptor.module("m").requires(null, "foo");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testRequiresWithNullVersion() {
+        ModuleDescriptor.module("m").requires(Set.of(), "foo", null);
+    }
+
     public void testRequiresCompare() {
         Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo");
         Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar");
@@ -190,6 +230,20 @@
         assertTrue(r2.compareTo(r1) == 0);
     }
 
+    public void testRequiresCompareWithSameCompiledVersion() {
+        Requires r1 = requires(Set.of(), "foo", Version.parse("2.0"));
+        Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+        assertTrue(r1.compareTo(r2) == 0);
+        assertTrue(r2.compareTo(r1) == 0);
+    }
+
+    public void testRequiresCompareWithDifferentCompiledVersion() {
+        Requires r1 = requires(Set.of(), "foo", Version.parse("1.0"));
+        Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+        assertTrue(r1.compareTo(r2) < 0);
+        assertTrue(r2.compareTo(r1) > 0);
+    }
+
     public void testRequiresEqualsAndHashCode() {
         Requires r1 = requires("foo");
         Requires r2 = requires("foo");
@@ -208,6 +262,17 @@
         r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
         r2 = requires(Set.of(), "foo");
         assertNotEquals(r1, r2);
+
+        Version v1 = Version.parse("1.0");
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        Version v2 = Version.parse("2.0");
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v2);
+        assertNotEquals(r1, r2);
     }
 
     public void testRequiresToString() {
@@ -938,7 +1003,7 @@
     };
 
     // basic test reading module-info.class
-    public void testRead1() throws Exception {
+    public void testRead() throws Exception {
         Module base = Object.class.getModule();
 
         try (InputStream in = base.getResourceAsStream("module-info.class")) {
@@ -954,45 +1019,6 @@
             assertEquals(descriptor.name(), "java.base");
         }
     }
-
-    /**
-     * Test reading a module-info.class that has a module name, requires,
-     * and qualified exports with module names that are not supported in the
-     * Java Language.
-     */
-    public void testRead2() throws Exception {
-        // use non-public constructor to create a Builder that is not strict
-        Constructor<?> ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class);
-        ctor.setAccessible(true);
-
-        Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false);
-        ModuleDescriptor descriptor = builder
-                .requires("java.base")
-                .requires("-m1")
-                .exports("p", Set.of("m2-"))
-                .build();
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ModuleInfoWriter.write(descriptor, baos);
-        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
-
-        descriptor = ModuleDescriptor.read(bb);
-        assertEquals(descriptor.name(), "m?1");
-
-        Set<String> requires = descriptor.requires()
-                .stream()
-                .map(Requires::name)
-                .collect(Collectors.toSet());
-        assertTrue(requires.size() == 2);
-        assertTrue(requires.contains("java.base"));
-        assertTrue(requires.contains("-m1"));
-
-        assertTrue(descriptor.exports().size() == 1);
-        Exports e = descriptor.exports().iterator().next();
-        assertTrue(e.targets().size() == 1);
-        assertTrue(e.targets().contains("m2-"));
-    }
-
     /**
      * Test ModuleDescriptor with a packager finder
      */
diff --git a/jdk/test/java/lang/module/ModuleNamesTest.java b/jdk/test/java/lang/module/ModuleNamesTest.java
new file mode 100644
index 0000000..c0790ea
--- /dev/null
+++ b/jdk/test/java/lang/module/ModuleNamesTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.misc
+ *          java.base/jdk.internal.module
+ * @run testng ModuleNamesTest
+ * @summary Basic test of reading a module-info.class with module names that
+ *          are legal in class files but not legal in the Java Language
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleInfoWriter;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleNamesTest {
+
+    @DataProvider(name = "legalModuleNames")
+    public Object[][] legalModuleNames() {
+        return new Object[][] {
+
+                { ".",              "." },
+                { ".foo",           ".foo" },
+                { "foo.",           "foo." },
+                { "foo.bar",        "foo.bar" },
+
+                { "..",             ".." },
+                { "..foo",          "..foo" },
+                { "foo..",          "foo.." },
+                { "foo..bar",       "foo..bar" },
+
+                { "[",              "[" },
+                { "[foo",           "[foo" },
+                { "foo[",           "foo[" },
+                { "foo[bar",        "foo[bar" },
+
+                { ";",              ";" },
+                { ";foo",           ";foo" },
+                { "foo;",           "foo;" },
+                { "foo;bar",        "foo;bar" },
+
+                { "\\\\",           "\\" },
+                { "\\\\foo",        "\\foo" },
+                { "foo\\\\",        "foo\\" },
+                { "foo\\\\bar",     "foo\\bar" },
+
+                { "\\\\\\\\",       "\\\\" },
+                { "\\\\\\\\foo",    "\\\\foo" },
+                { "foo\\\\\\\\",    "foo\\\\" },
+                { "foo\\\\\\\\bar", "foo\\\\bar" },
+
+                { "\\:",            ":" },
+                { "\\:foo",         ":foo" },
+                { "foo\\:",         "foo:" },
+                { "foo\\:bar",      "foo:bar" },
+
+                { "\\:\\:",         "::" },
+                { "\\:\\:foo",      "::foo" },
+                { "foo\\:\\:",      "foo::" },
+                { "foo\\:\\:bar",   "foo::bar" },
+
+                { "\\@",            "@" },
+                { "\\@foo",         "@foo" },
+                { "foo\\@",         "foo@" },
+                { "foo\\@bar",      "foo@bar" },
+
+                { "\\@\\@",         "@@" },
+                { "\\@\\@foo",      "@@foo" },
+                { "foo\\@\\@",      "foo@@" },
+                { "foo\\@\\@bar",   "foo@@bar" },
+
+                { makeString("", 0x20, ""),        " "  },
+                { makeString("foo", 0x20, ""),     "foo " },
+                { makeString("", 0x20, "foo"),     " foo" },
+                { makeString("foo", 0x20, "bar"),  "foo bar" },
+        };
+    }
+
+    @DataProvider(name = "illegalModuleNames")
+    public Object[][] illegalModuleNames() {
+        return new Object[][] {
+
+                { "",               null },
+
+                { ":",              null },
+                { ":foo",           null },
+                { "foo:",           null },
+                { "foo:bar",        null },
+
+                { "@",              null },
+                { "@foo",           null },
+                { "foo@",           null },
+                { "foo@bar",        null },
+
+                { "\\",            null },
+                { "\\foo",         null },
+                { "foo\\",         null },
+                { "foo\\bar",      null },
+
+                { makeString("", 0x00, ""),         null },
+                { makeString("", 0x00, "foo"),      null },
+                { makeString("foo", 0x00, ""),      null },
+                { makeString("foo", 0x00, "bar"),   null },
+
+                { makeString("", 0x1f, ""),         null },
+                { makeString("", 0x1f, "foo"),      null },
+                { makeString("foo", 0x1f, ""),      null },
+                { makeString("foo", 0x1f, "bar"),   null },
+
+        };
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalModuleName(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+        ByteBuffer bb = toBuffer(md);
+        String name = ModuleDescriptor.read(bb).name();
+        assertEquals(name, expected);
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalModuleName(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);  // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalRequires(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Requires> requires = descriptor.requires().stream()
+                .filter(r -> !r.name().equals("java.base"))
+                .findAny();
+        assertTrue(requires.isPresent());
+        assertEquals(requires.get().name(), expected);
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalRequires(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalExports(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .exports("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Exports> export = descriptor.exports().stream().findAny();
+        assertTrue(export.isPresent());
+        assertTrue(export.get().targets().contains(expected));
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalExports(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .exports("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalOpens(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .opens("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Opens> opens = descriptor.opens().stream().findAny();
+        assertTrue(opens.isPresent());
+        assertTrue(opens.get().targets().contains(expected));
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalOpens(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .opens("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    /**
+     * Returns a Builder that does not validate module names.
+     */
+    private Builder newBuilder(String mn) {
+        return SharedSecrets.getJavaLangModuleAccess()
+                            .newModuleBuilder(mn, false, false, false);
+    }
+
+    /**
+     * Returns a {@code ByteBuffer} containing the given module descriptor
+     * in module-info.class format.
+     */
+    private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        return ByteBuffer.wrap(baos.toByteArray());
+    }
+
+    /**
+     * Returns a string containing a given code point.
+     */
+    private String makeString(String prefix, int codePoint, String suffix) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(prefix);
+        sb.appendCodePoint(codePoint);
+        sb.append(suffix);
+        return sb.toString();
+    }
+}
diff --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
index 63c4c74..d956c24 100644
--- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
+++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @library /lib/testlibrary
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.module
  *          jdk.compiler
  * @build ModuleReaderTest CompilerUtils JarUtils
  * @run testng ModuleReaderTest
@@ -53,7 +53,7 @@
 import java.util.stream.Collectors;
 import java.util.spi.ToolProvider;
 
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
 
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
@@ -216,9 +216,7 @@
      */
     void test(Path mp) throws IOException {
 
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, mp);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, mp);
         ModuleReference mref = finder.find(TEST_MODULE).get();
         ModuleReader reader = mref.open();
 
diff --git a/jdk/test/java/lang/module/ModuleReferenceTest.java b/jdk/test/java/lang/module/ModuleReferenceTest.java
index 6b480bb..bf2db12 100644
--- a/jdk/test/java/lang/module/ModuleReferenceTest.java
+++ b/jdk/test/java/lang/module/ModuleReferenceTest.java
@@ -31,7 +31,6 @@
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.net.URI;
-import java.util.function.Supplier;
 
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
@@ -39,8 +38,13 @@
 @Test
 public class ModuleReferenceTest {
 
-    private Supplier<ModuleReader> makeSupplier() {
-        return () -> { throw new UnsupportedOperationException(); };
+    private ModuleReference newModuleReference(ModuleDescriptor descriptor, URI uri) {
+        return new ModuleReference(descriptor, uri) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 
     public void testBasic() throws Exception {
@@ -53,25 +57,16 @@
 
         URI uri = URI.create("module:/m");
 
-        Supplier<ModuleReader> supplier = makeSupplier();
-
-        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+        ModuleReference mref = newModuleReference(descriptor, uri);
 
         assertTrue(mref.descriptor().equals(descriptor));
         assertTrue(mref.location().get().equals(uri));
-
-        // check that the supplier is called
-        try {
-            mref.open();
-            assertTrue(false);
-        } catch (UnsupportedOperationException expected) { }
     }
 
-
     @Test(expectedExceptions = { NullPointerException.class })
     public void testNullDescriptor() throws Exception {
         URI location = URI.create("module:/m");
-        new ModuleReference(null, location, makeSupplier());
+        newModuleReference(null, location);
     }
 
     public void testNullLocation() {
@@ -79,55 +74,8 @@
             = ModuleDescriptor.module("m")
                 .exports("p")
                 .build();
-        Supplier<ModuleReader> supplier = makeSupplier();
-        ModuleReference mref = new ModuleReference(descriptor, null, supplier);
+        ModuleReference mref = newModuleReference(descriptor, null);
         assertTrue(!mref.location().isPresent());
     }
 
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullSupplier() throws Exception {
-        ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
-        URI location = URI.create("module:/m");
-        new ModuleReference(descriptor, location, null);
-    }
-
-
-    public void testEqualsAndHashCode() {
-        ModuleDescriptor descriptor1
-            = ModuleDescriptor.module("m1")
-                .exports("p")
-                .build();
-        ModuleDescriptor descriptor2
-            = ModuleDescriptor.module("m1")
-                .exports("p")
-                .build();
-
-        URI uri = URI.create("module:/m1");
-        Supplier<ModuleReader> supplier = makeSupplier();
-
-        ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
-        ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
-        ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
-
-        assertTrue(mref1.equals(mref1));
-        assertTrue(mref1.equals(mref2));
-        assertTrue(mref2.equals(mref1));
-        assertTrue(mref1.hashCode() == mref2.hashCode());
-
-        assertTrue(mref3.equals(mref3));
-        assertFalse(mref3.equals(mref1));
-        assertFalse(mref1.equals(mref3));
-    }
-
-
-    public void testToString() {
-        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
-        URI uri = URI.create("module:/m1");
-        Supplier<ModuleReader> supplier = makeSupplier();
-        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-        String s = mref.toString();
-        assertTrue(s.contains("m1"));
-        assertTrue(s.contains(uri.toString()));
-    }
-
 }
diff --git a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java
index 1746d6d..0390698 100644
--- a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java
+++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java
@@ -119,7 +119,6 @@
             List<Attribute> attrs = new ArrayList<>();
             attrs.add(new ClassFileAttributes.ModuleAttribute());
             attrs.add(new ClassFileAttributes.ModulePackagesAttribute());
-            attrs.add(new ClassFileAttributes.ModuleVersionAttribute());
             attrs.add(new ClassFileAttributes.ModuleTargetAttribute());
             cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
 
diff --git a/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java b/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java
index 7a4ce53..47feb49 100644
--- a/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java
+++ b/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java
@@ -21,10 +21,11 @@
  * questions.
  */
 
-/**
+/*
  * @test
  * @bug 4167874
- * @modules jdk.httpserver
+ * @modules java.logging
+ *          jdk.httpserver
  * @library ../../../../com/sun/net/httpserver
  * @library /lib/testlibrary
  * @build FileServerHandler jdk.testlibrary.FileUtils
@@ -33,10 +34,13 @@
  * @summary URL-downloaded jar files can consume all available file descriptors
  */
 
-import java.io.*;
-import java.net.*;
-import java.lang.reflect.*;
-import com.sun.net.httpserver.*;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpServer;
 
 public class CloseTest extends Common {
 
@@ -130,7 +134,7 @@
         // load tests
         loadClass ("com.foo.TestClass1", loader, false);
         loadClass ("com.foo.TestClass", loader, true);
-        loadClass ("java.sql.Array", loader, true);
+        loadClass ("java.util.ArrayList", loader, true);
 
         // now check we can delete the path
         rm_minus_rf (new File(name));
diff --git a/jdk/test/java/nio/charset/coders/BashStreams.java b/jdk/test/java/nio/charset/coders/BashStreams.java
index 1658021..b8f775d 100644
--- a/jdk/test/java/nio/charset/coders/BashStreams.java
+++ b/jdk/test/java/nio/charset/coders/BashStreams.java
@@ -23,7 +23,7 @@
 
 /* @test
  * @summary Stochastic test of charset-based streams
- * @key randomness intermittent
+ * @key randomness
  */
 
 import java.io.*;
diff --git a/jdk/test/java/rmi/Naming/LookupNameWithColon.java b/jdk/test/java/rmi/Naming/LookupNameWithColon.java
index a0d1e93..cdd2473 100644
--- a/jdk/test/java/rmi/Naming/LookupNameWithColon.java
+++ b/jdk/test/java/rmi/Naming/LookupNameWithColon.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
             "multiple:colons:in:name"
         };
 
-        Registry reg = TestLibrary.createRegistryOnUnusedPort();
+        Registry reg = TestLibrary.createRegistryOnEphemeralPort();
         int port = TestLibrary.getRegistryPort(reg);
 
         for (int i = 0; i < names.length; i++) {
diff --git a/jdk/test/java/rmi/Naming/RmiIsNoScheme.java b/jdk/test/java/rmi/Naming/RmiIsNoScheme.java
index a044ff1..1f202cf 100644
--- a/jdk/test/java/rmi/Naming/RmiIsNoScheme.java
+++ b/jdk/test/java/rmi/Naming/RmiIsNoScheme.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,7 @@
         System.err.println("\nRegression test for bug 4626311\n");
 
         try {
-            Registry registry = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
             int registryPort = TestLibrary.getRegistryPort(registry);
             Naming.rebind("//:" + registryPort + "/RmiIsNoScheme",
                           new RmiIsNoScheme());
diff --git a/jdk/test/java/rmi/Naming/UnderscoreHost.java b/jdk/test/java/rmi/Naming/UnderscoreHost.java
index c253ec2..6cfa9c9 100644
--- a/jdk/test/java/rmi/Naming/UnderscoreHost.java
+++ b/jdk/test/java/rmi/Naming/UnderscoreHost.java
@@ -1,5 +1,5 @@
  /*
-  * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
@@ -80,7 +80,7 @@
         try {
             HostVerifyingSocketFactory hvf = new HostVerifyingSocketFactory();
             RMISocketFactory.setSocketFactory(hvf);
-            Registry r = TestLibrary.createRegistryOnUnusedPort();
+            Registry r = TestLibrary.createRegistryOnEphemeralPort();
             int port = TestLibrary.getRegistryPort(r);
             t = new UnderscoreHost();
             r.rebind(NAME, t);
diff --git a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java
index 815bb22e..bfa1217 100644
--- a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java
+++ b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,8 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary
+ *          java.base/sun.nio.ch
+ * @build TestLibrary RMID ActivationLibrary RMIDSelectorProvider
  *     DownloadActivationGroup MyActivationGroupImpl DownloadActivationGroup_Stub
  * @run main/othervm/policy=security.policy/timeout=240 DownloadActivationGroup
  */
@@ -123,7 +124,7 @@
              * Start rmid.
              */
             RMID.removeLog();
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             String execPolicyOption = "-Dsun.rmi.activation.execPolicy=none";
             rmid.addOptions(new String[] { execPolicyOption });
             rmid.start();
diff --git a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/rmid.security.policy
new file mode 100644
index 0000000..f2c4f1d
--- /dev/null
+++ b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/rmid.security.policy
@@ -0,0 +1,7 @@
+grant {
+    permission java.lang.RuntimePermission "selectorProvider";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read";
+    permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
+};
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java b/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java
index 521598d..9a316e7 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java
+++ b/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,8 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary
+ *          java.base/sun.nio.ch
+ * @build TestLibrary RMID ActivationLibrary RMIDSelectorProvider
  * @run main/othervm/policy=security.policy/timeout=480 IdempotentActiveGroup
  */
 
@@ -63,7 +64,7 @@
 
         try {
             RMID.removeLog();
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             rmid.start();
 
             System.err.println("Create group descriptor");
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/rmid.security.policy
new file mode 100644
index 0000000..f2c4f1d
--- /dev/null
+++ b/jdk/test/java/rmi/activation/ActivationSystem/activeGroup/rmid.security.policy
@@ -0,0 +1,7 @@
+grant {
+    permission java.lang.RuntimePermission "selectorProvider";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read";
+    permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
+};
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java b/jdk/test/java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java
index 3e7798c..27bb48b 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java
+++ b/jdk/test/java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java
@@ -110,7 +110,7 @@
 
         try {
             RMID.removeLog();
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             rmid.start();
 
             /*
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java
index 5099ab1..43318ce 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java
+++ b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,8 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary
+ *          java.base/sun.nio.ch
+ * @build TestLibrary RMID ActivationLibrary RMIDSelectorProvider
  *     CanCreateStubs StubClassesPermitted_Stub
  * @run main/othervm/java.security.policy=security.policy/secure=java.lang.SecurityManager/timeout=240 StubClassesPermitted
  */
@@ -84,7 +85,7 @@
         try {
             TestLibrary.suggestSecurityManager("java.lang.SecurityManager");
 
-            registry = TestLibrary.createRegistryOnUnusedPort();
+            registry = TestLibrary.createRegistryOnEphemeralPort();
             registryPort = TestLibrary.getRegistryPort(registry);
 
             // must run with java.lang.SecurityManager or the test
@@ -98,7 +99,7 @@
 
             // start an rmid.
             RMID.removeLog();
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             rmid.start();
 
             //rmid.addOptions(new String[] {"-C-Djava.rmi.server.logCalls=true"});
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy
index 0c1df59..640fb78 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy
+++ b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy
@@ -4,4 +4,9 @@
 
     // test needs to export a set of internal APIs to access them from unamed module
     permission com.sun.rmi.rmid.ExecOptionPermission "*";
+    permission java.lang.RuntimePermission "selectorProvider";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read";
+    permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
 };
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java
index 7f4e1d2..fcd2161 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java
+++ b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,8 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary ActivateMe
+ *          java.base/sun.nio.ch
+ * @build TestLibrary RMID ActivationLibrary ActivateMe RMIDSelectorProvider
  * @run main/othervm/policy=security.policy UnregisterGroup
  */
 
@@ -76,7 +77,7 @@
 
         try {
             RMID.removeLog();
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             rmid.start();
 
             /* Cause activation groups to have a security policy that will
diff --git a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy
index 0e43c5d..ce485f6 100644
--- a/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy
+++ b/jdk/test/java/rmi/activation/ActivationSystem/unregisterGroup/rmid.security.policy
@@ -1,4 +1,9 @@
 grant {
     permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default";
     permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*";
+    permission java.lang.RuntimePermission "selectorProvider";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read";
+    permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
 };
diff --git a/jdk/test/java/rmi/registry/emptyName/EmptyName.java b/jdk/test/java/rmi/registry/emptyName/EmptyName.java
index e3f271a..97b82a1 100644
--- a/jdk/test/java/rmi/registry/emptyName/EmptyName.java
+++ b/jdk/test/java/rmi/registry/emptyName/EmptyName.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@
 
 public class EmptyName {
     public static void main(String[] args) throws Exception {
-        Registry impl = TestLibrary.createRegistryOnUnusedPort();
+        Registry impl = TestLibrary.createRegistryOnEphemeralPort();
         Registry stub = (Registry) RemoteObject.toStub(impl);
         stub.bind("", stub);
         stub.lookup("");
diff --git a/jdk/test/java/rmi/registry/reexport/Reexport.java b/jdk/test/java/rmi/registry/reexport/Reexport.java
index a0c9707..b0b29ef 100644
--- a/jdk/test/java/rmi/registry/reexport/Reexport.java
+++ b/jdk/test/java/rmi/registry/reexport/Reexport.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary JavaVM RegistryRunner RegistryRunner_Stub
+ * @build TestLibrary REGISTRY RegistryRunner
  * @run main/othervm Reexport
  */
 
@@ -54,27 +54,20 @@
     static public void main(String[] argv) {
 
         Registry reg = null;
-        int regPort = TestLibrary.getUnusedRandomPort();
-
         try {
             System.err.println("\nregression test for 4120329\n");
 
             // establish the registry (we hope)
-            System.err.println("Starting registry on port " + regPort);
-            Reexport.makeRegistry(regPort);
+            makeRegistry();
 
             // Get a handle to the registry
             System.err.println("Creating duplicate registry, this should fail...");
-            reg = createReg(true, regPort);
-
-            if (reg != null) {
-                TestLibrary.bomb("failed was able to duplicate the registry?!?");
-            }
+            reg = createReg(true);
 
             // Kill the first registry.
             System.err.println("Bringing down the first registry");
             try {
-                Reexport.killRegistry(regPort);
+                killRegistry();
             } catch (Exception foo) {
             }
 
@@ -82,7 +75,7 @@
             System.err.println("Trying again to start our own " +
                                "registry... this should work");
 
-            reg = createReg(false, regPort);
+            reg = createReg(false);
 
             if (reg == null) {
                 TestLibrary.bomb("Could not create registry on second try");
@@ -94,17 +87,19 @@
             TestLibrary.bomb(e);
         } finally {
             // dont leave the registry around to affect other tests.
-            killRegistry(regPort);
-
+            killRegistry();
             reg = null;
         }
     }
 
-    static Registry createReg(boolean remoteOk, int port) {
+    static Registry createReg(boolean remoteOk) {
         Registry reg = null;
 
         try {
             reg = LocateRegistry.createRegistry(port);
+            if (remoteOk) {
+                TestLibrary.bomb("Remote registry is up, an Exception is expected!");
+            }
         } catch (Throwable e) {
             if (remoteOk) {
                 System.err.println("EXPECTING PORT IN USE EXCEPTION:");
@@ -114,43 +109,29 @@
                 TestLibrary.bomb((Exception) e);
             }
         }
-
         return reg;
     }
 
-    public static void makeRegistry(int p) {
-        // sadly, we can't kill a registry if we have too-close control
-        // over it.  We must make it in a subprocess, and then kill the
-        // subprocess when it has served our needs.
-
+    public static void makeRegistry() {
         try {
-            JavaVM jvm = new JavaVM("RegistryRunner", "", Integer.toString(p));
-            jvm.start();
-            Reexport.subreg = jvm;
+            subreg = REGISTRY.createREGISTRY();
+            subreg.start();
+            port = subreg.getPort();
+            System.out.println("Starting registry on port " + port);
         } catch (IOException e) {
             // one of these is summarily dropped, can't remember which one
             System.out.println ("Test setup failed - cannot run rmiregistry");
             TestLibrary.bomb("Test setup failed - cannot run test", e);
         }
-        // Slop - wait for registry to come up.  This is stupid.
-        try {
-            Thread.sleep (5000);
-        } catch (Exception whatever) {
-        }
     }
 
-    private static JavaVM subreg = null;
+    private static REGISTRY subreg = null;
+    private static int port = -1;
 
-    public static void killRegistry(int port) {
-        if (Reexport.subreg != null) {
-
-            RegistryRunner.requestExit(port);
-
-            try {
-                Reexport.subreg.waitFor();
-            } catch (InterruptedException ie) {
-            }
+    public static void killRegistry() {
+        if (subreg != null) {
+            subreg.shutdown();
+            subreg = null;
         }
-        Reexport.subreg = null;
     }
 }
diff --git a/jdk/test/java/rmi/reliability/juicer/AppleUserImpl.java b/jdk/test/java/rmi/reliability/juicer/AppleUserImpl.java
index 8aeba6d..a8e9f1e 100644
--- a/jdk/test/java/rmi/reliability/juicer/AppleUserImpl.java
+++ b/jdk/test/java/rmi/reliability/juicer/AppleUserImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -313,7 +313,7 @@
 
             synchronized (user) {
                 // create new registry and bind new AppleUserImpl in registry
-                Registry registry = TestLibrary.createRegistryOnUnusedPort();
+                Registry registry = TestLibrary.createRegistryOnEphemeralPort();
                 registryPort = TestLibrary.getRegistryPort(registry);
                 LocateRegistry.getRegistry(registryPort).rebind("AppleUser",
                                                                  user);
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java
index 86512a9..3509a3f 100644
--- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java
@@ -32,7 +32,8 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary Echo EchoImpl EchoImpl_Stub
+ *          java.base/sun.nio.ch
+ * @build TestLibrary Echo EchoImpl EchoImpl_Stub RMIDSelectorProvider
  * @run main/othervm/policy=security.policy/timeout=360 UseCustomSocketFactory
  */
 
@@ -42,7 +43,7 @@
 import java.rmi.registry.*;
 
 public class UseCustomSocketFactory {
-    static final int REGISTRY_PORT = TestLibrary.getUnusedRandomPort();
+    static int registryPort = -1;
 
     static String[] protocol = new String[] { "", "compress", "xor" };
 
@@ -53,7 +54,8 @@
         TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager");
 
         try {
-            LocateRegistry.createRegistry(REGISTRY_PORT);
+            Registry reg = LocateRegistry.createRegistry(0);
+            registryPort = TestLibrary.getRegistryPort(reg);
         } catch (RemoteException e) {
             TestLibrary.bomb("creating registry", e);
         }
@@ -61,7 +63,7 @@
         RMID rmid = null;
 
         try {
-            rmid = RMID.createRMID();
+            rmid = RMID.createRMIDOnEphemeralPort();
             rmid.addArguments(new String[] {
                 "-C-Djava.security.policy=" +
                     TestParams.defaultGroupPolicy +
@@ -89,7 +91,7 @@
                                          "-Djava.security.policy=" +
                                          TestParams.defaultPolicy +
                                          " -Drmi.registry.port=" +
-                                         REGISTRY_PORT +
+                                         registryPort +
                                          " -Djava.rmi.activation.port=" +
                                          rmidPort,
                                          protocol[i]);
@@ -107,7 +109,7 @@
                 long stopTime = System.currentTimeMillis() + 24000;
                 do {
                     try {
-                        echo[i] = (Echo) Naming.lookup("//:" + REGISTRY_PORT +
+                        echo[i] = (Echo) Naming.lookup("//:" + registryPort +
                                                        "/EchoServer");
                         break;
                     } catch (NotBoundException e) {
@@ -137,7 +139,7 @@
             } finally {
                 serverVM.destroy();
                 try {
-                    Naming.unbind("//:" + REGISTRY_PORT + "/EchoServer");
+                    Naming.unbind("//:" + registryPort + "/EchoServer");
                 } catch (RemoteException | NotBoundException | MalformedURLException e) {
                     TestLibrary.bomb("unbinding EchoServer", e);
                 }
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/rmid.security.policy b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/rmid.security.policy
new file mode 100644
index 0000000..f2c4f1d
--- /dev/null
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/rmid.security.policy
@@ -0,0 +1,7 @@
+grant {
+    permission java.lang.RuntimePermission "selectorProvider";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read";
+    permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read";
+    permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
+};
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/security.policy b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/security.policy
index 6c8a471..324624d 100644
--- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/security.policy
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/activatable/security.policy
@@ -20,6 +20,13 @@
   permission java.util.PropertyPermission "java.security.policy", "read";
   permission java.util.PropertyPermission "java.security.manager", "read";
 
+  // used by TestLibrary to get the RMI Registry port
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.proxy";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp";
+
   // used by TestLibrary to determine test environment 
   permission java.util.PropertyPermission "test.*", "read";
   permission java.util.PropertyPermission "user.dir", "read";
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java
index 1a39bc7..0b6dc76 100644
--- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,7 @@
         System.out.println("\nRegression test for bug 4148850\n");
 
         TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager");
-        int registryPort = TestLibrary.getUnusedRandomPort();
+        int registryPort = -1;
 
         try {
             impl = new HelloImpl();
@@ -68,9 +68,10 @@
              * allow the rmiregistry to be secure.
              */
             registry = LocateRegistry.
-                createRegistry(registryPort,
+                createRegistry(0,
                                new Compress.CompressRMIClientSocketFactory(),
                                new Compress.CompressRMIServerSocketFactory());
+            registryPort = TestLibrary.getRegistryPort(registry);
             registry.rebind("/HelloServer", impl);
             checkStub(registry, "RMIServerSocket");
 
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/security.policy b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/security.policy
index 523ea94..70bf79a 100644
--- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/security.policy
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/registry/security.policy
@@ -22,6 +22,13 @@
   permission java.util.PropertyPermission "java.security.policy", "read";
   permission java.util.PropertyPermission "java.security.manager", "read";
 
+  // used by TestLibrary to get the RMI Registry port
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.proxy";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp";
+
   // test needs to export rmid and communicate with objects on arbitrary ports
   permission java.net.SocketPermission "*:1024-", "connect,accept,listen";
 };
diff --git a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java
index 21ff49c..4df810a 100644
--- a/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java
+++ b/jdk/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,7 @@
         TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager");
 
         try {
-            Registry registry = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
             registryPort = TestLibrary.getRegistryPort(registry);
         } catch (RemoteException e) {
             TestLibrary.bomb("creating registry", e);
diff --git a/jdk/test/java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java b/jdk/test/java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java
index 27530b9..9c46f36 100644
--- a/jdk/test/java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java
+++ b/jdk/test/java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,7 +80,7 @@
             UnicastRemoteObject.exportObject(obj);
             System.err.println("exported shutdown monitor");
 
-            Registry localRegistry = TestLibrary.createRegistryOnUnusedPort();
+            Registry localRegistry = TestLibrary.createRegistryOnEphemeralPort();
             int registryPort = TestLibrary.getRegistryPort(localRegistry);
             System.err.println("created local registry");
 
diff --git a/jdk/test/java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java b/jdk/test/java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java
index f529f64..9979b69 100644
--- a/jdk/test/java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java
+++ b/jdk/test/java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,7 @@
     public static void main(String[] args) {
         try {
             System.err.println("\nRegression test for bug 4331349\n");
-            Registry registry = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
             int registryPort = TestLibrary.getRegistryPort(registry);
             Remote obj = new UnexportLeak();
             WeakReference wr = new WeakReference(obj);
diff --git a/jdk/test/java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java b/jdk/test/java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java
index 0694209..df3dde5 100644
--- a/jdk/test/java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java
+++ b/jdk/test/java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
         try {
             UnicastRemoteObject.exportObject(obj);
             System.err.println("exported remote object");
-            Registry registry1 = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry1 = TestLibrary.createRegistryOnEphemeralPort();
             int port = TestLibrary.getRegistryPort(registry1);
             System.err.println("created registry");
 
diff --git a/jdk/test/java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java b/jdk/test/java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java
index f468779..2c4bb4d 100644
--- a/jdk/test/java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java
+++ b/jdk/test/java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -122,7 +122,7 @@
             UnicastRemoteObject.exportObject(obj);
             System.err.println("exported remote object");
 
-            Registry registry1 = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry1 = TestLibrary.createRegistryOnEphemeralPort();
             int port = TestLibrary.getRegistryPort(registry1);
             System.err.println("created registry");
 
diff --git a/jdk/test/java/rmi/testlibrary/JavaVM.java b/jdk/test/java/rmi/testlibrary/JavaVM.java
index 04f1589..087e700 100644
--- a/jdk/test/java/rmi/testlibrary/JavaVM.java
+++ b/jdk/test/java/rmi/testlibrary/JavaVM.java
@@ -22,6 +22,7 @@
  */
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -37,6 +38,26 @@
  */
 public class JavaVM {
 
+    static class CachedOutputStream extends OutputStream {
+        ByteArrayOutputStream ba;
+        OutputStream os;
+
+        public CachedOutputStream(OutputStream os) {
+            this.os = os;
+            this.ba = new ByteArrayOutputStream();
+        }
+
+        public void write(int b) throws IOException {
+            ba.write(b);
+            os.write(b);
+        }
+
+        public void reset() throws IOException {
+            os.flush();
+            ba.reset();
+        }
+    }
+
     public static final long POLLTIME_MS = 100L;
 
     protected Process vm = null;
@@ -44,8 +65,8 @@
     private String classname = "";
     protected String args = "";
     protected String options = "";
-    private OutputStream outputStream = System.out;
-    private OutputStream errorStream = System.err;
+    protected CachedOutputStream outputStream = new CachedOutputStream(System.out);
+    protected CachedOutputStream errorStream = new CachedOutputStream(System.err);
     private String policyFileName = null;
     private StreamPipe outPipe;
     private StreamPipe errPipe;
@@ -76,8 +97,8 @@
                   String options, String args,
                   OutputStream out, OutputStream err) {
         this(classname, options, args);
-        this.outputStream = out;
-        this.errorStream = err;
+        this.outputStream = new CachedOutputStream(out);
+        this.errorStream = new CachedOutputStream(err);
     }
 
     // Prepends passed opts array to current options
@@ -117,6 +138,8 @@
      * Exec the VM as specified in this object's constructor.
      */
     private void start0() throws IOException {
+        outputStream.reset();
+        errorStream.reset();
 
         if (vm != null)
             throw new IllegalStateException("JavaVM already started");
diff --git a/jdk/test/java/rmi/testlibrary/REGISTRY.java b/jdk/test/java/rmi/testlibrary/REGISTRY.java
new file mode 100644
index 0000000..d372198
--- /dev/null
+++ b/jdk/test/java/rmi/testlibrary/REGISTRY.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Class to run and control rmiregistry in a sub-process.
+ *
+ * We can't kill a registry if we have too-close control
+ * over it.  We must make it in a subprocess, and then kill the
+ * subprocess when it has served our needs.
+ */
+public class REGISTRY extends JavaVM {
+
+    private static double startTimeout = 20_000 * TestLibrary.getTimeoutFactor();
+
+    private int port = -1;
+
+    private REGISTRY(OutputStream out, OutputStream err,
+                    String options, int port) {
+        super("RegistryRunner", options, Integer.toString(port), out, err);
+        this.port = port;
+    }
+
+    public static REGISTRY createREGISTRY() {
+        return createREGISTRY(System.out, System.err, "", 0);
+    }
+
+    public static REGISTRY createREGISTRY(OutputStream out, OutputStream err,
+                                    String options, int port) {
+        options += " --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED"
+                 + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED"
+                 + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED"
+                 + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED";
+        REGISTRY reg = new REGISTRY(out, err, options, port);
+        return reg;
+    }
+
+    /**
+     * Starts the registry in a sub-process and waits up to
+     * the given timeout period to confirm that it's running,
+     * and get the port where it's running.
+     */
+    public void start() throws IOException {
+        super.start();
+        long startTime = System.currentTimeMillis();
+        long deadline = TestLibrary.computeDeadline(startTime, (long)startTimeout);
+        while (true) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException ignore) { }
+
+            String output = outputStream.ba.toString();
+            port = RegistryRunner.getRegistryPort(output);
+            if (port != -1) {
+                break;
+            }
+            if (System.currentTimeMillis() > deadline) {
+                TestLibrary.bomb("Failed to start registry, giving up after " +
+                    (System.currentTimeMillis() - startTime) + "ms.", null);
+            }
+        }
+    }
+
+    /**
+     * Shuts down the registry.
+     */
+    public void shutdown() {
+        RegistryRunner.requestExit(port);
+    }
+
+    /**
+     * Gets the port where the registry is serving.
+     */
+    public int getPort() {
+        return port;
+    }
+}
diff --git a/jdk/test/java/rmi/testlibrary/RegistryRunner.java b/jdk/test/java/rmi/testlibrary/RegistryRunner.java
index 6290c79..f79403c 100644
--- a/jdk/test/java/rmi/testlibrary/RegistryRunner.java
+++ b/jdk/test/java/rmi/testlibrary/RegistryRunner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,13 +28,16 @@
 import java.rmi.server.*;
 
 /**
- * Class to run a registry whos VM can be told to exit remotely; using
+ * Class to run a registry whose VM can be told to exit remotely; using
  * the rmiregistry in this fashion makes tests more robust under
  * windows where Process.destroy() seems not to be 100% reliable.
  */
 public class RegistryRunner extends UnicastRemoteObject
     implements RemoteExiter
 {
+    private static final String PORT_LABEL_START = "RegistryRunner.port.start:";
+    private static final String PORT_LABEL_END = "RegistryRunner.port.end";
+
     private static Registry registry = null;
     private static RemoteExiter exiter = null;
 
@@ -59,16 +62,16 @@
     public static void requestExit(int port) {
 
         try {
-            RemoteExiter exiter =
+            RemoteExiter e =
                 (RemoteExiter)
                 Naming.lookup("rmi://localhost:" +
                               port +
                               "/RemoteExiter");
             try {
-                exiter.exit();
+                e.exit();
             } catch (RemoteException re) {
             }
-            exiter = null;
+            e = null;
         } catch (java.net.MalformedURLException mfue) {
             // will not happen
         } catch (NotBoundException nbe) {
@@ -79,7 +82,21 @@
         }
     }
 
+    public static int getRegistryPort(String output) {
+        int idxStart = output.indexOf(PORT_LABEL_START);
+        int idxEnd = output.indexOf(PORT_LABEL_END);
+        if (idxStart == -1 || idxEnd == -1) {
+            return -1;
+        }
+        idxStart = idxStart+PORT_LABEL_START.length();
+        String portStr = output.substring(idxStart, idxEnd);
+        int port = Integer.valueOf(portStr);
+        System.err.println("registry is running at port: " + port);
+        return port;
+    }
+
     public static void main(String[] args) {
+
         try {
             if (args.length == 0) {
                 System.err.println("Usage: <port>");
@@ -88,17 +105,23 @@
             int port = -1;
             try {
                 port = Integer.parseInt(args[0]);
-            } catch (NumberFormatException nfe) {
-            }
+            } catch (NumberFormatException ignore) { }
 
             // create a registry
             registry = LocateRegistry.createRegistry(port);
+            if (port == 0) {
+                port = TestLibrary.getRegistryPort(registry);
+            }
 
             // create a remote object to tell this VM to exit
             exiter = new RegistryRunner();
             Naming.rebind("rmi://localhost:" + port +
                           "/RemoteExiter", exiter);
 
+            // this output is important for REGISTRY to get the port
+            // where rmiregistry is serving
+            System.out.println(PORT_LABEL_START + port + PORT_LABEL_END);
+
         } catch (Exception e) {
             System.err.println(e.getMessage());
             e.printStackTrace();
diff --git a/jdk/test/java/rmi/testlibrary/RegistryRunner_Stub.java b/jdk/test/java/rmi/testlibrary/RegistryRunner_Stub.java
deleted file mode 100644
index 679c0d1..0000000
--- a/jdk/test/java/rmi/testlibrary/RegistryRunner_Stub.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// Stub class generated by rmic, do not edit.
-// Contents subject to change without notice.
-
-public final class RegistryRunner_Stub
-    extends java.rmi.server.RemoteStub
-    implements RemoteExiter, java.rmi.Remote
-{
-    private static final long serialVersionUID = 2;
-
-    private static java.lang.reflect.Method $method_exit_0;
-
-    static {
-        try {
-            $method_exit_0 = RemoteExiter.class.getMethod("exit", new java.lang.Class[] {});
-        } catch (java.lang.NoSuchMethodException e) {
-            throw new java.lang.NoSuchMethodError(
-                "stub class initialization failed");
-        }
-    }
-
-    // constructors
-    public RegistryRunner_Stub(java.rmi.server.RemoteRef ref) {
-        super(ref);
-    }
-
-    // methods from remote interfaces
-
-    // implementation of exit()
-    public void exit()
-        throws java.rmi.RemoteException
-    {
-        try {
-            ref.invoke(this, $method_exit_0, null, -6307240473358936408L);
-        } catch (java.lang.RuntimeException e) {
-            throw e;
-        } catch (java.rmi.RemoteException e) {
-            throw e;
-        } catch (java.lang.Exception e) {
-            throw new java.rmi.UnexpectedException("undeclared checked exception", e);
-        }
-    }
-}
diff --git a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
index 19d4d6c..359e971 100644
--- a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
+++ b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
             System.err.println
                 ("\nRegression test for bug/rfe 4115683\n");
 
-            Registry registry = TestLibrary.createRegistryOnUnusedPort();
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
             REGISTRY_PORT = TestLibrary.getRegistryPort(registry);
             registry.bind("CheckFQDN", checkFQDN);
 
diff --git a/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
index b54cbfb..8e35c8b 100644
--- a/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
+++ b/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
  * @library ../../testlibrary
  * @modules java.rmi/sun.rmi.registry
  *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.transport:open
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary CheckLeaseLeak_Stub LeaseLeakClient LeaseLeak
@@ -90,7 +91,7 @@
 
         try {
             Registry registry =
-                TestLibrary.createRegistryOnUnusedPort();
+                TestLibrary.createRegistryOnEphemeralPort();
             int registryPort = TestLibrary.getRegistryPort(registry);
 
             leakServer = new CheckLeaseLeak();
diff --git a/jdk/test/java/rmi/transport/handshakeFailure/HandshakeFailure.java b/jdk/test/java/rmi/transport/handshakeFailure/HandshakeFailure.java
index fc7341f..d99e967 100644
--- a/jdk/test/java/rmi/transport/handshakeFailure/HandshakeFailure.java
+++ b/jdk/test/java/rmi/transport/handshakeFailure/HandshakeFailure.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,10 @@
  * java.rmi.ConnectException or ConnectIOException, not a MarshalException.
  * @author Peter Jones
  *
- * @library ../../testlibrary
  * @modules java.rmi/sun.rmi.registry
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary
  * @run main/othervm HandshakeFailure
  */
 
@@ -49,7 +47,6 @@
 
 public class HandshakeFailure {
 
-    private static final int PORT = TestLibrary.getUnusedRandomPort();
     private static final int TIMEOUT = 10000;
 
     public static void main(String[] args) throws Exception {
@@ -57,12 +54,13 @@
         /*
          * Listen on port...
          */
-        ServerSocket serverSocket = new ServerSocket(PORT);
+        ServerSocket serverSocket = new ServerSocket(0);
+        int port = serverSocket.getLocalPort();
 
         /*
          * (Attempt RMI call to port in separate thread.)
          */
-        Registry registry = LocateRegistry.getRegistry(PORT);
+        Registry registry = LocateRegistry.getRegistry(port);
         Connector connector = new Connector(registry);
         Thread t = new Thread(connector);
         t.setDaemon(true);
@@ -93,7 +91,7 @@
                 System.err.println();
 
                 if (connector.exception instanceof MarshalException) {
-                    System.err.println(
+                    throw new RuntimeException(
                         "TEST FAILED: MarshalException thrown, expecting " +
                         "java.rmi.ConnectException or ConnectIOException");
                 } else if (connector.exception instanceof ConnectException ||
diff --git a/jdk/test/java/rmi/transport/handshakeTimeout/HandshakeTimeout.java b/jdk/test/java/rmi/transport/handshakeTimeout/HandshakeTimeout.java
index 7a20f20..d763b55 100644
--- a/jdk/test/java/rmi/transport/handshakeTimeout/HandshakeTimeout.java
+++ b/jdk/test/java/rmi/transport/handshakeTimeout/HandshakeTimeout.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,12 +33,10 @@
  * this point (because no data for the invocation has yet been written).
  * @author Peter Jones
  *
- * @library ../../testlibrary
  * @modules java.rmi/sun.rmi.registry
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary
  * @run main/othervm HandshakeTimeout
  */
 
@@ -51,7 +49,6 @@
 
 public class HandshakeTimeout {
 
-    private static final int PORT = TestLibrary.getUnusedRandomPort();
     private static final int TIMEOUT = 10000;
 
     public static void main(String[] args) throws Exception {
@@ -62,12 +59,13 @@
         /*
          * Listen on port, but never process connections made to it.
          */
-        ServerSocket serverSocket = new ServerSocket(PORT);
+        ServerSocket serverSocket = new ServerSocket(0);
+        int port = serverSocket.getLocalPort();
 
         /*
          * Attempt RMI call to port in separate thread.
          */
-        Registry registry = LocateRegistry.getRegistry(PORT);
+        Registry registry = LocateRegistry.getRegistry(port);
         Connector connector = new Connector(registry);
         Thread t = new Thread(connector);
         t.setDaemon(true);
@@ -91,7 +89,7 @@
                 System.err.println();
 
                 if (connector.exception instanceof MarshalException) {
-                    System.err.println(
+                    throw new RuntimeException(
                         "TEST FAILED: MarshalException thrown, expecting " +
                         "java.rmi.ConnectException or ConnectIOException");
                 } else if (connector.exception instanceof ConnectException ||
diff --git a/jdk/test/java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java b/jdk/test/java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java
index 38c2e2a..5e2da33 100644
--- a/jdk/test/java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java
+++ b/jdk/test/java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,6 @@
 import java.rmi.server.UnicastRemoteObject;
 
 public class RapidExportUnexport {
-    private static final int PORT = TestLibrary.getUnusedRandomPort();
     private static final int REPS = 100;
     private static final long TIMEOUT = 60000;
 
@@ -55,7 +54,7 @@
         long start = System.currentTimeMillis();
         for (int i = 0; i < REPS; i++) {
             System.err.println(i);
-            UnicastRemoteObject.exportObject(impl, PORT);
+            UnicastRemoteObject.exportObject(impl, 0);
             UnicastRemoteObject.unexportObject(impl, true);
             Thread.sleep(1);    // work around BindException (bug?)
         }
diff --git a/jdk/test/java/security/Signature/NoProvider.java b/jdk/test/java/security/Signature/NoProvider.java
new file mode 100644
index 0000000..782f06f
--- /dev/null
+++ b/jdk/test/java/security/Signature/NoProvider.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8165751
+ * @summary Verify that that a subclass of Signature that does not contain a
+ *     provider can be used to verify.
+ * @run main/othervm -Djava.security.debug=provider NoProvider
+ */
+
+import java.security.*;
+
+public class NoProvider {
+
+    private static class NoProviderPublicKey implements PublicKey {
+
+        public String getAlgorithm() {
+            return "NoProvider";
+        }
+        public String getFormat() {
+            return "none";
+        }
+        public byte[] getEncoded() {
+            return new byte[1];
+        }
+    }
+
+    private static class NoProviderSignature extends Signature {
+
+        public NoProviderSignature() {
+            super("NoProvider");
+        }
+
+        protected void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+            // do nothing
+        }
+
+        protected void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+            // do nothing
+        }
+
+        protected void engineUpdate(byte b) throws SignatureException {
+            // do nothing
+        }
+
+        protected void engineUpdate(byte[] b, int off, int len)
+            throws SignatureException {
+            // do nothing
+        }
+
+        protected byte[] engineSign() throws SignatureException {
+            return new byte[1];
+        }
+
+        protected boolean engineVerify(byte[] sigBytes)
+            throws SignatureException {
+            return false;
+        }
+
+        @Deprecated
+        protected void engineSetParameter(String param, Object value)
+            throws InvalidParameterException {
+            // do nothing
+        }
+
+        @Deprecated
+        protected Object engineGetParameter(String param)
+            throws InvalidParameterException {
+            return null;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new NoProviderSignature().initVerify(new NoProviderPublicKey());
+    }
+}
diff --git a/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.java b/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.java
index 5cc0bdc..b8071b0 100644
--- a/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.java
+++ b/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,8 @@
 
 import java.text.SimpleDateFormat;
 import java.time.chrono.JapaneseDate;
+import java.time.chrono.JapaneseEra;
+import java.time.format.TextStyle;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
@@ -140,6 +142,27 @@
             System.err.printf("JapaneseDate: got=\"%s\", expected=\"%s\"%n", got, expected);
             errors++;
         }
+        JapaneseEra jera = jdate.getEra();
+        got = jera.getDisplayName(TextStyle.FULL, Locale.US);
+        if (!NEW_ERA_NAME.equals(got)) {
+            System.err.printf("JapaneseEra (FULL): got=\"%s\", expected=\"%s\"%n", got, NEW_ERA_NAME);
+            errors++;
+        }
+        got = jera.getDisplayName(TextStyle.SHORT, Locale.US);
+        if (!NEW_ERA_NAME.equals(got)) {
+            System.err.printf("JapaneseEra (SHORT): got=\"%s\", expected=\"%s\"%n", got, NEW_ERA_NAME);
+            errors++;
+        }
+        got = jera.getDisplayName(TextStyle.NARROW, Locale.US);
+        if (!NEW_ERA_ABBR.equals(got)) {
+            System.err.printf("JapaneseEra (NARROW): got=\"%s\", expected=\"%s\"%n", got, NEW_ERA_ABBR);
+            errors++;
+        }
+        got = jera.getDisplayName(TextStyle.NARROW_STANDALONE, Locale.US);
+        if (!NEW_ERA_ABBR.equals(got)) {
+            System.err.printf("JapaneseEra (NARROW_STANDALONE): got=\"%s\", expected=\"%s\"%n", got, NEW_ERA_ABBR);
+            errors++;
+        }
     }
 
     private static void testValidation(String eraName) {
diff --git a/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.sh b/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.sh
index ade093c..5feb37d 100644
--- a/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.sh
+++ b/jdk/test/java/util/Calendar/SupplementalJapaneseEraTest.sh
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
 #
 
 # @test
-# @bug 8048123
+# @bug 8048123 8054214
 # @summary Test for jdk.calendar.japanese.supplemental.era support
 # @build SupplementalJapaneseEraTest
 # @run shell SupplementalJapaneseEraTest.sh
diff --git a/jdk/test/java/util/Map/Collisions.java b/jdk/test/java/util/Map/Collisions.java
index 7b825fc..62f78a5 100644
--- a/jdk/test/java/util/Map/Collisions.java
+++ b/jdk/test/java/util/Map/Collisions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,427 +24,155 @@
 /*
  * @test
  * @bug 7126277
- * @run main Collisions -shortrun
+ * @run testng/othervm -Dtest.map.collisions.shortrun=true Collisions
  * @summary Ensure Maps behave well with lots of hashCode() collisions.
- * @author Mike Duigou
  */
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.BitSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.function.Supplier;
 
-public class Collisions {
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
 
-    /**
-     * Number of elements per map.
-     */
-    private static final int TEST_SIZE = 5000;
+public class Collisions extends MapWithCollisionsProviders {
 
-    static final class HashableInteger implements Comparable<HashableInteger> {
+    @Test(dataProvider = "mapsWithObjects")
+    void testIntegerIteration(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
+        Map<IntKey, IntKey> map = ms.get();
+        int mapSize = map.size();
 
-        final int value;
-        final int hashmask; //yes duplication
-
-        HashableInteger(int value, int hashmask) {
-            this.value = value;
-            this.hashmask = hashmask;
+        BitSet all = new BitSet(mapSize);
+        for (Map.Entry<IntKey, IntKey> each : map.entrySet()) {
+            assertFalse(all.get(each.getKey().getValue()), "Iteration: key already seen");
+            all.set(each.getKey().getValue());
         }
 
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof HashableInteger) {
-                HashableInteger other = (HashableInteger) obj;
+        all.flip(0, mapSize);
+        assertTrue(all.isEmpty(), "Iteration: some keys not visited");
 
-                return other.value == value;
-            }
-
-            return false;
+        for (IntKey each : map.keySet()) {
+            assertFalse(all.get(each.getValue()), "Iteration: key already seen");
+            all.set(each.getValue());
         }
 
-        @Override
-        public int hashCode() {
-            return value % hashmask;
-        }
-
-        @Override
-        public int compareTo(HashableInteger o) {
-            return value - o.value;
-        }
-
-        @Override
-        public String toString() {
-            return Integer.toString(value);
-        }
-    }
-
-    private static Object[][] makeTestData(int size) {
-        HashableInteger UNIQUE_OBJECTS[] = new HashableInteger[size];
-        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[size];
-        String UNIQUE_STRINGS[] = new String[size];
-        String COLLIDING_STRINGS[] = new String[size];
-
-        for (int i = 0; i < size; i++) {
-            UNIQUE_OBJECTS[i] = new HashableInteger(i, Integer.MAX_VALUE);
-            COLLIDING_OBJECTS[i] = new HashableInteger(i, 10);
-            UNIQUE_STRINGS[i] = unhash(i);
-            COLLIDING_STRINGS[i] = (0 == i % 2)
-                    ? UNIQUE_STRINGS[i / 2]
-                    : "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];
-        }
-
-     return new Object[][] {
-            new Object[]{"Unique Objects", UNIQUE_OBJECTS},
-            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
-            new Object[]{"Unique Strings", UNIQUE_STRINGS},
-            new Object[]{"Colliding Strings", COLLIDING_STRINGS}
-        };
-    }
-
-    /**
-     * Returns a string with a hash equal to the argument.
-     *
-     * @return string with a hash equal to the argument.
-     */
-    public static String unhash(int target) {
-        StringBuilder answer = new StringBuilder();
-        if (target < 0) {
-            // String with hash of Integer.MIN_VALUE, 0x80000000
-            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");
-
-            if (target == Integer.MIN_VALUE) {
-                return answer.toString();
-            }
-            // Find target without sign bit set
-            target = target & Integer.MAX_VALUE;
-        }
-
-        unhash0(answer, target);
-        return answer.toString();
-    }
-
-    private static void unhash0(StringBuilder partial, int target) {
-        int div = target / 31;
-        int rem = target % 31;
-
-        if (div <= Character.MAX_VALUE) {
-            if (div != 0) {
-                partial.append((char) div);
-            }
-            partial.append((char) rem);
-        } else {
-            unhash0(partial, div);
-            partial.append((char) rem);
-        }
-    }
-
-    private static void realMain(String[] args) throws Throwable {
-        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
-
-        Object[][] mapKeys = makeTestData(shortRun ? (TEST_SIZE / 2) : TEST_SIZE);
-
-        // loop through data sets
-        for (Object[] keys_desc : mapKeys) {
-            Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
-                        new HashMap<>(),
-                        new Hashtable<>(),
-                        new IdentityHashMap<>(),
-                        new LinkedHashMap<>(),
-                        new TreeMap<>(),
-                        new WeakHashMap<>(),
-                        new ConcurrentHashMap<>(),
-                        new ConcurrentSkipListMap<>()
-                    };
-
-            // for each map type.
-            for (Map<Object, Object> map : maps) {
-                String desc = (String) keys_desc[0];
-                Object[] keys = (Object[]) keys_desc[1];
-                try {
-                    testMap(map, desc, keys);
-                } catch(Exception all) {
-                    unexpected("Failed for " + map.getClass().getName() + " with " + desc, all);
-                }
-            }
-        }
-    }
-
-    private static <T> void testMap(Map<T, T> map, String keys_desc, T[] keys) {
-        System.out.println(map.getClass() + " : " + keys_desc);
-        System.out.flush();
-        testInsertion(map, keys_desc, keys);
-
-        if (keys[0] instanceof HashableInteger) {
-            testIntegerIteration((Map<HashableInteger, HashableInteger>) map, (HashableInteger[]) keys);
-        } else {
-            testStringIteration((Map<String, String>) map, (String[]) keys);
-        }
-
-        testContainsKey(map, keys_desc, keys);
-
-        testRemove(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testKeysIteratorRemove(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testValuesIteratorRemove(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testEntriesIteratorRemove(map, keys_desc, keys);
-
-        check(map.isEmpty());
-    }
-
-    private static <T> void testInsertion(Map<T, T> map, String keys_desc, T[] keys) {
-        check(map.size() == 0 && map.isEmpty(), "map empty");
-
-        for (int i = 0; i < keys.length; i++) {
-            check(map.size() == i, "insertion: map expected size m%d != i%d", map.size(), i);
-            check(null == map.put(keys[i], keys[i]), "insertion: put(%s[%d])", keys_desc, i);
-            check(map.containsKey(keys[i]), "insertion: containsKey(%s[%d])", keys_desc, i);
-            check(map.containsValue(keys[i]), "insertion: containsValue(%s[%d])", keys_desc, i);
-        }
-
-        check(map.size() == keys.length, "map expected size m%d != k%d", map.size(), keys.length);
-    }
-
-    private static void testIntegerIteration(Map<HashableInteger, HashableInteger> map, HashableInteger[] keys) {
-        check(map.size() == keys.length, "map expected size m%d != k%d", map.size(), keys.length);
-
-        BitSet all = new BitSet(keys.length);
-        for (Map.Entry<HashableInteger, HashableInteger> each : map.entrySet()) {
-            check(!all.get(each.getKey().value), "Iteration: key already seen");
-            all.set(each.getKey().value);
-        }
-
-        all.flip(0, keys.length);
-        check(all.isEmpty(), "Iteration: some keys not visited");
-
-        for (HashableInteger each : map.keySet()) {
-            check(!all.get(each.value), "Iteration: key already seen");
-            all.set(each.value);
-        }
-
-        all.flip(0, keys.length);
-        check(all.isEmpty(), "Iteration: some keys not visited");
+        all.flip(0, mapSize);
+        assertTrue(all.isEmpty(), "Iteration: some keys not visited");
 
         int count = 0;
-        for (HashableInteger each : map.values()) {
+        for (IntKey each : map.values()) {
             count++;
         }
 
-        check(map.size() == count, "Iteration: value count matches size m%d != c%d", map.size(), count);
+        assertEquals(map.size(), count,
+                String.format("Iteration: value count matches size m%d != c%d", map.size(), count));
     }
 
-    private static void testStringIteration(Map<String, String> map, String[] keys) {
-        check(map.size() == keys.length, "map expected size m%d != k%d", map.size(), keys.length);
+    @Test(dataProvider = "mapsWithStrings")
+    void testStringIteration(String desc, Supplier<Map<String, String>> ms, String val) {
+        Map<String, String> map = ms.get();
+        int mapSize = map.size();
 
-        BitSet all = new BitSet(keys.length);
+        BitSet all = new BitSet(mapSize);
         for (Map.Entry<String, String> each : map.entrySet()) {
             String key = each.getKey();
             boolean longKey = key.length() > 5;
-            int index = key.hashCode() + (longKey ? keys.length / 2 : 0);
-            check(!all.get(index), "key already seen");
+            int index = key.hashCode() + (longKey ? mapSize / 2 : 0);
+            assertFalse(all.get(index), "key already seen");
             all.set(index);
         }
 
-        all.flip(0, keys.length);
-        check(all.isEmpty(), "some keys not visited");
+        all.flip(0, mapSize);
+        assertTrue(all.isEmpty(), "some keys not visited");
 
         for (String each : map.keySet()) {
             boolean longKey = each.length() > 5;
-            int index = each.hashCode() + (longKey ? keys.length / 2 : 0);
-            check(!all.get(index), "key already seen");
+            int index = each.hashCode() + (longKey ? mapSize / 2 : 0);
+            assertFalse(all.get(index), "key already seen");
             all.set(index);
         }
 
-        all.flip(0, keys.length);
-        check(all.isEmpty(), "some keys not visited");
+        all.flip(0, mapSize);
+        assertTrue(all.isEmpty(), "some keys not visited");
 
         int count = 0;
         for (String each : map.values()) {
             count++;
         }
 
-        check(map.size() == keys.length, "value count matches size m%d != k%d", map.size(), keys.length);
+        assertEquals(map.size(), mapSize,
+                String.format("value count matches size m%d != k%d", map.size(), mapSize));
     }
 
-    private static <T> void testContainsKey(Map<T, T> map, String keys_desc, T[] keys) {
-        for (int i = 0; i < keys.length; i++) {
-            T each = keys[i];
-            check(map.containsKey(each), "containsKey: %s[%d]%s", keys_desc, i, each);
-        }
-    }
-
-    private static <T> void testRemove(Map<T, T> map, String keys_desc, T[] keys) {
-        check(map.size() == keys.length, "remove: map expected size m%d != k%d", map.size(), keys.length);
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
 
         for (int i = 0; i < keys.length; i++) {
-            T each = keys[i];
-            check(null != map.remove(each), "remove: %s[%d]%s", keys_desc, i, each);
+            Object each = keys[i];
+            assertNotNull(map.remove(each),
+                    String.format("remove: %s[%d]%s", desc, i, each));
         }
 
-        check(map.size() == 0 && map.isEmpty(), "remove: map empty. size=%d", map.size());
+        assertTrue(map.size() == 0 && map.isEmpty(),
+                String.format("remove: map empty. size=%d", map.size()));
     }
 
-    private static <T> void testKeysIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {
-        check(map.size() == keys.length, "remove: map expected size m%d != k%d", map.size(), keys.length);
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testKeysIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
 
-        Iterator<T> each = map.keySet().iterator();
+        Iterator<Object> each = map.keySet().iterator();
         while (each.hasNext()) {
-            T t = each.next();
+            Object t = each.next();
             each.remove();
-            check(!map.containsKey(t), "not removed: %s", each);
+            assertFalse(map.containsKey(t), String.format("not removed: %s", each));
         }
 
-        check(map.size() == 0 && map.isEmpty(), "remove: map empty. size=%d", map.size());
+        assertTrue(map.size() == 0 && map.isEmpty(),
+                String.format("remove: map empty. size=%d", map.size()));
     }
 
-    private static <T> void testValuesIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {
-        check(map.size() == keys.length, "remove: map expected size m%d != k%d", map.size(), keys.length);
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testValuesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
 
-        Iterator<T> each = map.values().iterator();
+        Iterator<Object> each = map.values().iterator();
         while (each.hasNext()) {
-            T t = each.next();
+            Object t = each.next();
             each.remove();
-            check(!map.containsValue(t), "not removed: %s", each);
+            assertFalse(map.containsValue(t), String.format("not removed: %s", each));
         }
 
-        check(map.size() == 0 && map.isEmpty(), "remove: map empty. size=%d", map.size());
+        assertTrue(map.size() == 0 && map.isEmpty(),
+                String.format("remove: map empty. size=%d", map.size()));
     }
 
-    private static <T> void testEntriesIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {
-        check(map.size() == keys.length, "remove: map expected size m%d != k%d", map.size(), keys.length);
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testEntriesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
 
-        Iterator<Map.Entry<T,T>> each = map.entrySet().iterator();
+        Iterator<Map.Entry<Object, Object>> each = map.entrySet().iterator();
         while (each.hasNext()) {
-            Map.Entry<T,T> t = each.next();
-            T key = t.getKey();
-            T value = t.getValue();
+            Map.Entry<Object, Object> t = each.next();
+            Object key = t.getKey();
+            Object value = t.getValue();
             each.remove();
-            check((map instanceof IdentityHashMap) || !map.entrySet().contains(t), "not removed: %s", each);
-            check(!map.containsKey(key),                                           "not removed: %s", each);
-            check(!map.containsValue(value),                                       "not removed: %s", each);
+            assertTrue((map instanceof IdentityHashMap) || !map.entrySet().contains(t),
+                    String.format("not removed: %s", each));
+            assertFalse(map.containsKey(key),
+                    String.format("not removed: %s", each));
+            assertFalse(map.containsValue(value),
+                    String.format("not removed: %s", each));
         }
 
-        check(map.size() == 0 && map.isEmpty(), "remove: map empty. size=%d", map.size());
+        assertTrue(map.size() == 0 && map.isEmpty(),
+                String.format("remove: map empty. size=%d", map.size()));
     }
 
-    //--------------------- Infrastructure ---------------------------
-    static volatile int passed = 0, failed = 0;
-
-    static void pass() {
-        passed++;
-    }
-
-    static void fail() {
-        failed++;
-        (new Error("Failure")).printStackTrace(System.err);
-    }
-
-    static void fail(String msg) {
-        failed++;
-        (new Error("Failure: " + msg)).printStackTrace(System.err);
-    }
-
-    static void abort() {
-        fail();
-        System.exit(1);
-    }
-
-    static void abort(String msg) {
-        fail(msg);
-        System.exit(1);
-    }
-
-    static void unexpected(String msg, Throwable t) {
-        System.err.println("Unexpected: " + msg);
-        unexpected(t);
-    }
-
-    static void unexpected(Throwable t) {
-        failed++;
-        t.printStackTrace(System.err);
-    }
-
-    static void check(boolean cond) {
-        if (cond) {
-            pass();
-        } else {
-            fail();
-        }
-    }
-
-    static void check(boolean cond, String desc) {
-        if (cond) {
-            pass();
-        } else {
-            fail(desc);
-        }
-    }
-
-    static void check(boolean cond, String fmt, int i) {
-        if (cond) {
-            pass();
-        } else {
-            fail(String.format(fmt, i));
-        }
-    }
-
-    static void check(boolean cond, String fmt, Object o) {
-        if (cond) {
-            pass();
-        } else {
-            fail(String.format(fmt, o));
-        }
-    }
-
-    static void check(boolean cond, String fmt, int i1, int i2) {
-        if (cond) {
-            pass();
-        } else {
-            fail(String.format(fmt, i1, i2));
-        }
-    }
-
-    static void check(boolean cond, String fmt, String s, int i) {
-        if (cond) {
-            pass();
-        } else {
-            fail(String.format(fmt, s, i));
-        }
-    }
-
-    static void check(boolean cond, String fmt, String s, int i, Object o) {
-        if (cond) {
-            pass();
-        } else {
-            fail(String.format(fmt, s, i, o));
-        }
-    }
-
-    static void equal(Object x, Object y) {
-        if (Objects.equals(x, y)) {
-            pass();
-        } else {
-            fail(x + " not equal to " + y);
-        }
-    }
-
-    public static void main(String[] args) throws Throwable {
-        Thread.currentThread().setName(Collisions.class.getName());
-//        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
-        try {
-            realMain(args);
-        } catch (Throwable t) {
-            unexpected(t);
-        }
-
-        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
-        if (failed > 0) {
-            throw new Error("Some tests failed");
-        }
-    }
 }
diff --git a/jdk/test/java/util/Map/InPlaceOpsCollisions.java b/jdk/test/java/util/Map/InPlaceOpsCollisions.java
index c368d83..22ac0c2 100644
--- a/jdk/test/java/util/Map/InPlaceOpsCollisions.java
+++ b/jdk/test/java/util/Map/InPlaceOpsCollisions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,325 +24,162 @@
 /*
  * @test
  * @bug 8005698
- * @run main InPlaceOpsCollisions -shortrun
+ * @run testng/othervm -Dtest.map.collisions.shortrun=true InPlaceOpsCollisions
  * @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
- * @author Brent Christian
  */
-import java.util.*;
-import java.util.function.*;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
 
-public class InPlaceOpsCollisions {
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
 
-    /**
-     * Number of elements per map.
-     */
-    private static final int TEST_SIZE = 5000;
+public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
 
-    static final class HashableInteger implements Comparable<HashableInteger> {
-
-        final int value;
-        final int hashmask; //yes duplication
-
-        HashableInteger(int value, int hashmask) {
-            this.value = value;
-            this.hashmask = hashmask;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof HashableInteger) {
-                HashableInteger other = (HashableInteger) obj;
-
-                return other.value == value;
-            }
-
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return value % hashmask;
-        }
-
-        @Override
-        public int compareTo(HashableInteger o) {
-            return value - o.value;
-        }
-
-        @Override
-        public String toString() {
-            return Integer.toString(value);
-        }
-    }
-
-    static HashableInteger EXTRA_INT_VAL;
-    static String EXTRA_STRING_VAL;
-
-    private static Object[][] makeTestData(int size) {
-        HashableInteger UNIQUE_OBJECTS[] = new HashableInteger[size];
-        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[size];
-        String UNIQUE_STRINGS[] = new String[size];
-        String COLLIDING_STRINGS[] = new String[size];
-
-        for (int i = 0; i < size; i++) {
-            UNIQUE_OBJECTS[i] = new HashableInteger(i, Integer.MAX_VALUE);
-            COLLIDING_OBJECTS[i] = new HashableInteger(i, 10);
-            UNIQUE_STRINGS[i] = unhash(i);
-            COLLIDING_STRINGS[i] = (0 == i % 2)
-                    ? UNIQUE_STRINGS[i / 2]
-                    : "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];
-        }
-        EXTRA_INT_VAL = new HashableInteger(size, Integer.MAX_VALUE);
-        EXTRA_STRING_VAL = new String ("Extra Value");
-
-     return new Object[][] {
-            new Object[]{"Unique Objects", UNIQUE_OBJECTS},
-            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
-            new Object[]{"Unique Strings", UNIQUE_STRINGS},
-            new Object[]{"Colliding Strings", COLLIDING_STRINGS}
-        };
-    }
-
-    /**
-     * Returns a string with a hash equal to the argument.
-     *
-     * @return string with a hash equal to the argument.
-     */
-    public static String unhash(int target) {
-        StringBuilder answer = new StringBuilder();
-        if (target < 0) {
-            // String with hash of Integer.MIN_VALUE, 0x80000000
-            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");
-
-            if (target == Integer.MIN_VALUE) {
-                return answer.toString();
-            }
-            // Find target without sign bit set
-            target = target & Integer.MAX_VALUE;
-        }
-
-        unhash0(answer, target);
-        return answer.toString();
-    }
-
-    private static void unhash0(StringBuilder partial, int target) {
-        int div = target / 31;
-        int rem = target % 31;
-
-        if (div <= Character.MAX_VALUE) {
-            if (div != 0) {
-                partial.append((char) div);
-            }
-            partial.append((char) rem);
-        } else {
-            unhash0(partial, div);
-            partial.append((char) rem);
-        }
-    }
-
-    private static void realMain(String[] args) throws Throwable {
-        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
-
-        Object[][] mapKeys = makeTestData(shortRun ? (TEST_SIZE / 2) : TEST_SIZE);
-
-        // loop through data sets
-        for (Object[] keys_desc : mapKeys) {
-            Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
-                        new HashMap<>(),
-                        new LinkedHashMap<>(),
-                    };
-
-            // for each map type.
-            for (Map<Object, Object> map : maps) {
-                String desc = (String) keys_desc[0];
-                Object[] keys = (Object[]) keys_desc[1];
-                try {
-                    testInPlaceOps(map, desc, keys);
-                } catch(Exception all) {
-                    unexpected("Failed for " + map.getClass().getName() + " with " + desc, all);
-                }
-            }
-        }
-    }
-
-    private static <T> void testInsertion(Map<T, T> map, String keys_desc, T[] keys) {
-        check("map empty", (map.size() == 0) && map.isEmpty());
-
-        for (int i = 0; i < keys.length; i++) {
-            check(String.format("insertion: map expected size m%d != i%d", map.size(), i),
-                    map.size() == i);
-            check(String.format("insertion: put(%s[%d])", keys_desc, i), null == map.put(keys[i], keys[i]));
-            check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
-            check(String.format("insertion: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
-        }
-
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
-                map.size() == keys.length);
-    }
-
-
-    private static <T> void testInPlaceOps(Map<T, T> map, String keys_desc, T[] keys) {
-        System.out.println(map.getClass() + " : " + keys_desc + ", testInPlaceOps");
-        System.out.flush();
-
-        testInsertion(map, keys_desc, keys);
-        testPutIfAbsent(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testRemoveMapping(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testReplaceOldValue(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testReplaceIfMapped(map, keys_desc, keys);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testComputeIfAbsent(map, keys_desc, keys, (k) -> getExtraVal(keys[0]));
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testComputeIfAbsent(map, keys_desc, keys, (k) -> null);
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testComputeIfPresent(map, keys_desc, keys, (k, v) -> getExtraVal(keys[0]));
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testComputeIfPresent(map, keys_desc, keys, (k, v) -> null);
-
-        if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error
-            map.clear();
-            testInsertion(map, keys_desc, keys);
-            testComputeNonNull(map, keys_desc, keys);
-        }
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testComputeNull(map, keys_desc, keys);
-
-        if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error
-            map.clear();
-            testInsertion(map, keys_desc, keys);
-            testMergeNonNull(map, keys_desc, keys);
-        }
-
-        map.clear();
-        testInsertion(map, keys_desc, keys);
-        testMergeNull(map, keys_desc, keys);
-    }
-
-
-
-    private static <T> void testPutIfAbsent(Map<T, T> map, String keys_desc, T[] keys) {
-        T extraVal = getExtraVal(keys[0]);
-        T retVal;
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testPutIfAbsent(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        Object retVal;
         removeOddKeys(map, keys);
         for (int i = 0; i < keys.length; i++) {
-            retVal = map.putIfAbsent(keys[i], extraVal);
+            retVal = map.putIfAbsent(keys[i], val);
             if (i % 2 == 0) { // even: not absent, not put
-                check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);
-                check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
-                check(String.format("putIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
+
+                assertEquals(retVal, keys[i],
+                        String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
+                assertEquals(keys[i], map.get(keys[i]),
+                        String.format("putIfAbsent: get(%s[%d])", desc, i));
+                assertTrue(map.containsValue(keys[i]),
+                        String.format("putIfAbsent: containsValue(%s[%d])", desc, i));
             } else { // odd: absent, was put
-                check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == null);
-                check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
-                check(String.format("putIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+                assertNull(retVal,
+                        String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("putIfAbsent: get(%s[%d])", desc, i));
+                assertFalse(map.containsValue(keys[i]),
+                        String.format("putIfAbsent: !containsValue(%s[%d])", desc, i));
             }
-            check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+            assertTrue(map.containsKey(keys[i]),
+                    String.format("insertion: containsKey(%s[%d])", desc, i));
         }
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
-                map.size() == keys.length);
+        assertEquals(map.size(), keys.length,
+                String.format("map expected size m%d != k%d", map.size(), keys.length));
     }
 
-    private static <T> void testRemoveMapping(Map<T, T> map, String keys_desc, T[] keys) {
-        T extraVal = getExtraVal(keys[0]);
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
         boolean removed;
         int removes = 0;
-        remapOddKeys(map, keys);
+        remapOddKeys(map, keys, val);
         for (int i = 0; i < keys.length; i++) {
             removed = map.remove(keys[i], keys[i]);
             if (i % 2 == 0) { // even: original mapping, should be removed
-                check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), removed);
-                check(String.format("removeMapping: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
-                check(String.format("removeMapping: !containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
-                check(String.format("removeMapping: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+                assertTrue(removed,
+                        String.format("removeMapping: retVal(%s[%d])", desc, i));
+                assertNull(map.get(keys[i]),
+                        String.format("removeMapping: get(%s[%d])", desc, i));
+                assertFalse(map.containsKey(keys[i]),
+                        String.format("removeMapping: !containsKey(%s[%d])", desc, i));
+                assertFalse(map.containsValue(keys[i]),
+                        String.format("removeMapping: !containsValue(%s[%d])", desc, i));
                 removes++;
             } else { // odd: new mapping, not removed
-                check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), !removed);
-                check(String.format("removeMapping: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
-                check(String.format("removeMapping: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
-                check(String.format("removeMapping: containsValue(%s[%d])", keys_desc, i), map.containsValue(extraVal));
+                assertFalse(removed,
+                        String.format("removeMapping: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("removeMapping: get(%s[%d])", desc, i));
+                assertTrue(map.containsKey(keys[i]),
+                        String.format("removeMapping: containsKey(%s[%d])", desc, i));
+                assertTrue(map.containsValue(val),
+                        String.format("removeMapping: containsValue(%s[%d])", desc, i));
             }
         }
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
-                map.size() == keys.length - removes);
+        assertEquals(map.size(), keys.length - removes,
+                String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
     }
 
-    private static <T> void testReplaceOldValue(Map<T, T> map, String keys_desc, T[] keys) {
-        // remap odds to extraVal
-        // call replace to replace for extraVal, for all keys
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testReplaceOldValue(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        // remap odds to val
+        // call replace to replace for val, for all keys
         // check that all keys map to value from keys array
-        T extraVal = getExtraVal(keys[0]);
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
         boolean replaced;
-        remapOddKeys(map, keys);
+        remapOddKeys(map, keys, val);
 
         for (int i = 0; i < keys.length; i++) {
-            replaced = map.replace(keys[i], extraVal, keys[i]);
+            replaced = map.replace(keys[i], val, keys[i]);
             if (i % 2 == 0) { // even: original mapping, should not be replaced
-                check(String.format("replaceOldValue: retVal(%s[%d])", keys_desc, i), !replaced);
+                assertFalse(replaced,
+                        String.format("replaceOldValue: retVal(%s[%d])", desc, i));
             } else { // odd: new mapping, should be replaced
-                check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), replaced);
+                assertTrue(replaced,
+                        String.format("replaceOldValue: get(%s[%d])", desc, i));
             }
-            check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
-            check(String.format("replaceOldValue: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
-            check(String.format("replaceOldValue: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
-//            removes++;
+            assertEquals(keys[i], map.get(keys[i]),
+                    String.format("replaceOldValue: get(%s[%d])", desc, i));
+            assertTrue(map.containsKey(keys[i]),
+                    String.format("replaceOldValue: containsKey(%s[%d])", desc, i));
+            assertTrue(map.containsValue(keys[i]),
+                    String.format("replaceOldValue: containsValue(%s[%d])", desc, i));
         }
-        check(String.format("replaceOldValue: !containsValue(%s[%s])", keys_desc, extraVal.toString()), !map.containsValue(extraVal));
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
-                map.size() == keys.length);
+        assertFalse(map.containsValue(val),
+                String.format("replaceOldValue: !containsValue(%s[%s])", desc, val));
+        assertEquals(map.size(), keys.length,
+                String.format("map expected size m%d != k%d", map.size(), keys.length));
     }
 
-    // TODO: Test case for key mapped to null value
-    private static <T> void testReplaceIfMapped(Map<T, T> map, String keys_desc, T[] keys) {
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testReplaceIfMapped(String desc, Supplier<Map<Object, Object>> ms, Object val) {
         // remove odd keys
         // call replace for all keys[]
         // odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map
-        T extraVal = getExtraVal(keys[0]);
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
         int expectedSize1 = 0;
         removeOddKeys(map, keys);
         int expectedSize2 = map.size();
 
         for (int i = 0; i < keys.length; i++) {
-            T retVal = map.replace(keys[i], extraVal);
+            Object retVal = map.replace(keys[i], val);
             if (i % 2 == 0) { // even: still in map, should be replaced
-                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == keys[i]);
-                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
-                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                assertEquals(retVal, keys[i],
+                        String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("replaceIfMapped: get(%s[%d])", desc, i));
+                assertTrue(map.containsKey(keys[i]),
+                        String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
                 expectedSize1++;
             } else { // odd: was removed, should not be replaced
-                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);
-                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
-                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                assertNull(retVal,
+                        String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
+                assertNull(map.get(keys[i]),
+                        String.format("replaceIfMapped: get(%s[%d])", desc, i));
+                assertFalse(map.containsKey(keys[i]),
+                        String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
             }
-            check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+            assertFalse(map.containsValue(keys[i]),
+                    String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
         }
-        check(String.format("replaceIfMapped: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
-        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),
-                map.size() == expectedSize1);
-        check(String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2),
-                map.size() == expectedSize2);
+        assertTrue(map.containsValue(val),
+                String.format("replaceIfMapped: containsValue(%s[%s])", desc, val));
+        assertEquals(map.size(), expectedSize1,
+                String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
+        assertEquals(map.size(), expectedSize2,
+                String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2));
 
     }
 
-    private static <T> void testComputeIfAbsent(Map<T, T> map, String keys_desc, T[] keys,
-                                                Function<T,T> mappingFunction) {
+    private static <T> void testComputeIfAbsent(Map<T, T> map, String desc, T[] keys,
+            Function<T, T> mappingFunction) {
         // remove a third of the keys
         // call computeIfAbsent for all keys, func returns EXTRA
         // check that removed keys now -> EXTRA, other keys -> original val
@@ -353,29 +190,54 @@
         for (int i = 0; i < keys.length; i++) {
             retVal = map.computeIfAbsent(keys[i], mappingFunction);
             if (i % 3 != 2) { // key present, not computed
-                check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);
-                check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
-                check(String.format("computeIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
-                check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                assertEquals(retVal, keys[i],
+                        String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
+                assertEquals(keys[i], map.get(keys[i]),
+                        String.format("computeIfAbsent: get(%s[%d])", desc, i));
+                assertTrue(map.containsValue(keys[i]),
+                        String.format("computeIfAbsent: containsValue(%s[%d])", desc, i));
+                assertTrue(map.containsKey(keys[i]),
+                        String.format("insertion: containsKey(%s[%d])", desc, i));
                 expectedSize++;
             } else { // key absent, computed unless function return null
-                check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == expectedVal);
-                check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), expectedVal == map.get(keys[i]));
-                check(String.format("computeIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+                assertEquals(retVal, expectedVal,
+                        String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
+                assertEquals(expectedVal, map.get(keys[i]),
+                        String.format("computeIfAbsent: get(%s[%d])", desc, i));
+                assertFalse(map.containsValue(keys[i]),
+                        String.format("computeIfAbsent: !containsValue(%s[%d])", desc, i));
                 // mapping should not be added if function returns null
-                check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]) != (expectedVal == null));
-                if (expectedVal != null) { expectedSize++; }
+                assertTrue(map.containsKey(keys[i]) != (expectedVal == null),
+                        String.format("insertion: containsKey(%s[%d])", desc, i));
+                if (expectedVal != null) {
+                    expectedSize++;
+                }
             }
         }
         if (expectedVal != null) {
-            check(String.format("computeIfAbsent: containsValue(%s[%s])", keys_desc, expectedVal), map.containsValue(expectedVal));
+            assertTrue(map.containsValue(expectedVal),
+                    String.format("computeIfAbsent: containsValue(%s[%s])", desc, expectedVal));
         }
-        check(String.format("map expected size m%d != k%d", map.size(), expectedSize),
-                map.size() == expectedSize);
+        assertEquals(map.size(), expectedSize,
+                String.format("map expected size m%d != k%d", map.size(), expectedSize));
     }
 
-    private static <T> void testComputeIfPresent(Map<T, T> map, String keys_desc, T[] keys,
-                                                BiFunction<T,T,T> mappingFunction) {
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testComputeIfAbsentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        testComputeIfAbsent(map, desc, keys, (k) -> val);
+    }
+
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testComputeIfAbsentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        testComputeIfAbsent(map, desc, keys, (k) -> null);
+    }
+
+    private static <T> void testComputeIfPresent(Map<T, T> map, String desc, T[] keys,
+            BiFunction<T, T, T> mappingFunction) {
         // remove a third of the keys
         // call testComputeIfPresent for all keys[]
         // removed keys should remain absent, even keys should be mapped to $RESULT
@@ -388,156 +250,205 @@
             T retVal = map.computeIfPresent(keys[i], mappingFunction);
             if (i % 3 != 2) { // key present
                 if (funcResult == null) { // was removed
-                    check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                    assertFalse(map.containsKey(keys[i]),
+                            String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
                 } else { // value was replaced
-                    check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                    assertTrue(map.containsKey(keys[i]),
+                            String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
                     expectedSize1++;
                 }
-                check(String.format("computeIfPresent: retVal(%s[%s])", keys_desc, i), retVal == funcResult);
-                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), funcResult == map.get(keys[i]));
+                assertEquals(retVal, funcResult,
+                        String.format("computeIfPresent: retVal(%s[%s])", desc, i));
+                assertEquals(funcResult, map.get(keys[i]),
+                        String.format("replaceIfMapped: get(%s[%d])", desc, i));
 
             } else { // odd: was removed, should not be replaced
-                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);
-                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
-                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                assertNull(retVal,
+                        String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
+                assertNull(map.get(keys[i]),
+                        String.format("replaceIfMapped: get(%s[%d])", desc, i));
+                assertFalse(map.containsKey(keys[i]),
+                        String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
             }
-            check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+            assertFalse(map.containsValue(keys[i]),
+                    String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
         }
-        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),
-                map.size() == expectedSize1);
+        assertEquals(map.size(), expectedSize1,
+                String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
     }
 
-    private static <T> void testComputeNonNull(Map<T, T> map, String keys_desc, T[] keys) {
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testComputeIfPresentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        testComputeIfPresent(map, desc, keys, (k, v) -> val);
+    }
+
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testComputeIfPresentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        testComputeIfPresent(map, desc, keys, (k, v) -> null);
+    }
+
+    @Test(dataProvider = "hashMapsWithObjects")
+    void testComputeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
         // remove a third of the keys
         // call compute() for all keys[]
         // all keys should be present: removed keys -> EXTRA, others to k-1
-        BiFunction<T,T,T> mappingFunction = (k, v) -> {
-                if (v == null) {
-                    return getExtraVal(keys[0]);
-                } else {
-                    return keys[Integer.parseInt(k.toString()) - 1];
-                }
-            };
-        T extraVal = getExtraVal(keys[0]);
+        Map<IntKey, IntKey> map = ms.get();
+        IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
+        BiFunction<IntKey, IntKey, IntKey> mappingFunction = (k, v) -> {
+            if (v == null) {
+                return val;
+            } else {
+                return keys[k.getValue() - 1];
+            }
+        };
         removeThirdKeys(map, keys);
         for (int i = 1; i < keys.length; i++) {
-            T retVal = map.compute(keys[i], mappingFunction);
+            IntKey retVal = map.compute(keys[i], mappingFunction);
             if (i % 3 != 2) { // key present, should be mapped to k-1
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));
+                assertEquals(retVal, keys[i - 1],
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(keys[i - 1], map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
             } else { // odd: was removed, should be replaced with EXTRA
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                assertEquals(retVal, val,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
             }
-            check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+            assertTrue(map.containsKey(keys[i]),
+                    String.format("compute: containsKey(%s[%d])", desc, i));
         }
-        check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),
-                map.size() == keys.length);
-        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
-        check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));
+        assertEquals(map.size(), keys.length,
+                String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
+        assertTrue(map.containsValue(val),
+                String.format("compute: containsValue(%s[%s])", desc, val));
+        assertFalse(map.containsValue(null),
+                String.format("compute: !containsValue(%s,[null])", desc));
     }
 
-    private static <T> void testComputeNull(Map<T, T> map, String keys_desc, T[] keys) {
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testComputeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
         // remove a third of the keys
         // call compute() for all keys[]
         // removed keys should -> EXTRA
         // for other keys: func returns null, should have no mapping
-        BiFunction<T,T,T> mappingFunction = (k, v) -> {
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        BiFunction<Object, Object, Object> mappingFunction = (k, v) -> {
             // if absent/null -> EXTRA
             // if present -> null
             if (v == null) {
-                return getExtraVal(keys[0]);
+                return val;
             } else {
                 return null;
             }
         };
-        T extraVal = getExtraVal(keys[0]);
         int expectedSize = 0;
         removeThirdKeys(map, keys);
         for (int i = 0; i < keys.length; i++) {
-            T retVal = map.compute(keys[i], mappingFunction);
+            Object retVal = map.compute(keys[i], mappingFunction);
             if (i % 3 != 2) { // key present, func returned null, should be absent from map
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
-                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
-                check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));
+                assertNull(retVal,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertNull(map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
+                assertFalse(map.containsKey(keys[i]),
+                        String.format("compute: containsKey(%s[%d])", desc, i));
+                assertFalse(map.containsValue(keys[i]),
+                        String.format("compute: containsValue(%s[%s])", desc, i));
             } else { // odd: was removed, should now be mapped to EXTRA
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
-                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                assertEquals(retVal, val,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
+                assertTrue(map.containsKey(keys[i]),
+                        String.format("compute: containsKey(%s[%d])", desc, i));
                 expectedSize++;
             }
         }
-        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
-        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),
-                map.size() == expectedSize);
+        assertTrue(map.containsValue(val),
+                String.format("compute: containsValue(%s[%s])", desc, val));
+        assertEquals(map.size(), expectedSize,
+                String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
     }
 
-    private static <T> void testMergeNonNull(Map<T, T> map, String keys_desc, T[] keys) {
+    @Test(dataProvider = "hashMapsWithObjects")
+    void testMergeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
         // remove a third of the keys
         // call merge() for all keys[]
         // all keys should be present: removed keys now -> EXTRA, other keys -> k-1
+        Map<IntKey, IntKey> map = ms.get();
+        IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
 
         // Map to preceding key
-        BiFunction<T,T,T> mappingFunction = (k, v) -> keys[Integer.parseInt(k.toString()) - 1];
-        T extraVal = getExtraVal(keys[0]);
+        BiFunction<IntKey, IntKey, IntKey> mappingFunction
+                = (k, v) -> keys[k.getValue() - 1];
         removeThirdKeys(map, keys);
         for (int i = 1; i < keys.length; i++) {
-            T retVal = map.merge(keys[i], extraVal, mappingFunction);
+            IntKey retVal = map.merge(keys[i], val, mappingFunction);
             if (i % 3 != 2) { // key present, should be mapped to k-1
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));
+                assertEquals(retVal, keys[i - 1],
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(keys[i - 1], map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
             } else { // odd: was removed, should be replaced with EXTRA
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                assertEquals(retVal, val,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
             }
-            check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+            assertTrue(map.containsKey(keys[i]),
+                    String.format("compute: containsKey(%s[%d])", desc, i));
         }
 
-        check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),
-                map.size() == keys.length);
-        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
-        check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));
-
+        assertEquals(map.size(), keys.length,
+                String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
+        assertTrue(map.containsValue(val),
+                String.format("compute: containsValue(%s[%s])", desc, val));
+        assertFalse(map.containsValue(null),
+                String.format("compute: !containsValue(%s,[null])", desc));
     }
 
-    private static <T> void testMergeNull(Map<T, T> map, String keys_desc, T[] keys) {
+    @Test(dataProvider = "mapsWithObjectsAndStrings")
+    void testMergeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
         // remove a third of the keys
         // call merge() for all keys[]
         // result: removed keys -> EXTRA, other keys absent
 
-        BiFunction<T,T,T> mappingFunction = (k, v) -> null;
-        T extraVal = getExtraVal(keys[0]);
+        Map<Object, Object> map = ms.get();
+        Object[] keys = map.keySet().toArray();
+        BiFunction<Object, Object, Object> mappingFunction = (k, v) -> null;
         int expectedSize = 0;
         removeThirdKeys(map, keys);
         for (int i = 0; i < keys.length; i++) {
-            T retVal = map.merge(keys[i], extraVal, mappingFunction);
+            Object retVal = map.merge(keys[i], val, mappingFunction);
             if (i % 3 != 2) { // key present, func returned null, should be absent from map
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
-                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                assertNull(retVal,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertNull(map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
+                assertFalse(map.containsKey(keys[i]),
+                        String.format("compute: containsKey(%s[%d])", desc, i));
             } else { // odd: was removed, should now be mapped to EXTRA
-                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
-                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
-                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                assertEquals(retVal, val,
+                        String.format("compute: retVal(%s[%d])", desc, i));
+                assertEquals(val, map.get(keys[i]),
+                        String.format("compute: get(%s[%d])", desc, i));
+                assertTrue(map.containsKey(keys[i]),
+                        String.format("compute: containsKey(%s[%d])", desc, i));
                 expectedSize++;
             }
-            check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));
+            assertFalse(map.containsValue(keys[i]),
+                    String.format("compute: containsValue(%s[%s])", desc, i));
         }
-        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
-        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),
-                map.size() == expectedSize);
-    }
-
-    /*
-     * Return the EXTRA val for the key type being used
-     */
-    private static <T> T getExtraVal(T key) {
-        if (key instanceof HashableInteger) {
-            return (T)EXTRA_INT_VAL;
-        } else {
-            return (T)EXTRA_STRING_VAL;
-        }
+        assertTrue(map.containsValue(val),
+                String.format("compute: containsValue(%s[%s])", desc, val));
+        assertEquals(map.size(), expectedSize,
+                String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
     }
 
     /*
@@ -551,8 +462,8 @@
                 removes++;
             }
         }
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
-                map.size() == keys.length - removes);
+        assertEquals(map.size(), keys.length - removes,
+                String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
     }
 
     /*
@@ -570,95 +481,19 @@
                 removes++;
             }
         }
-        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
-                map.size() == keys.length - removes);
+        assertEquals(map.size(), keys.length - removes,
+                String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
     }
 
     /*
      * Re-map the odd-numbered keys to map to the EXTRA value
      */
-    private static <T> void remapOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
-        T extraVal = getExtraVal(keys[0]);
+    private static <T> void remapOddKeys(Map<T, T> map, T[] keys, T val) {
         for (int i = 0; i < keys.length; i++) {
             if (i % 2 != 0) {
-                map.put(keys[i], extraVal);
+                map.put(keys[i], val);
             }
         }
     }
 
-    //--------------------- Infrastructure ---------------------------
-    static volatile int passed = 0, failed = 0;
-
-    static void pass() {
-        passed++;
-    }
-
-    static void fail() {
-        failed++;
-        (new Error("Failure")).printStackTrace(System.err);
-    }
-
-    static void fail(String msg) {
-        failed++;
-        (new Error("Failure: " + msg)).printStackTrace(System.err);
-    }
-
-    static void abort() {
-        fail();
-        System.exit(1);
-    }
-
-    static void abort(String msg) {
-        fail(msg);
-        System.exit(1);
-    }
-
-    static void unexpected(String msg, Throwable t) {
-        System.err.println("Unexpected: " + msg);
-        unexpected(t);
-    }
-
-    static void unexpected(Throwable t) {
-        failed++;
-        t.printStackTrace(System.err);
-    }
-
-    static void check(boolean cond) {
-        if (cond) {
-            pass();
-        } else {
-            fail();
-        }
-    }
-
-    static void check(String desc, boolean cond) {
-        if (cond) {
-            pass();
-        } else {
-            fail(desc);
-        }
-    }
-
-    static void equal(Object x, Object y) {
-        if (Objects.equals(x, y)) {
-            pass();
-        } else {
-            fail(x + " not equal to " + y);
-        }
-    }
-
-    public static void main(String[] args) throws Throwable {
-        Thread.currentThread().setName(Collisions.class.getName());
-//        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
-        try {
-            realMain(args);
-        } catch (Throwable t) {
-            unexpected(t);
-        }
-
-        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
-        if (failed > 0) {
-            throw new Error("Some tests failed");
-        }
-    }
 }
diff --git a/jdk/test/java/util/Map/MapWithCollisionsProviders.java b/jdk/test/java/util/Map/MapWithCollisionsProviders.java
new file mode 100644
index 0000000..3e687a2
--- /dev/null
+++ b/jdk/test/java/util/Map/MapWithCollisionsProviders.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.function.Supplier;
+
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
+
+public class MapWithCollisionsProviders {
+
+    private static final int TEST_SIZE
+            = Boolean.valueOf(System.getProperty("test.map.collisions.shortrun"))
+            ? 2500
+            : 5000;
+
+    private static final IntKey EXTRA_INTKEY_VAL
+            = new IntKey(TEST_SIZE, Integer.MAX_VALUE);
+
+    private static final String EXTRA_STRING_VAL = "Extra Value";
+
+    public static final class IntKey implements Comparable<IntKey> {
+
+        private final int value;
+        private final int hashmask; //yes duplication
+
+        IntKey(int value, int hashmask) {
+            this.value = value;
+            this.hashmask = hashmask;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof IntKey) {
+                IntKey other = (IntKey) obj;
+
+                return other.value == value;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return value % hashmask;
+        }
+
+        @Override
+        public int compareTo(IntKey o) {
+            return value - o.value;
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toString(value);
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    private static Object[] createUniqueObjectKeys() {
+        IntKey UNIQUE_OBJECTS[] = new IntKey[TEST_SIZE];
+        for (int i = 0; i < TEST_SIZE; i++) {
+            UNIQUE_OBJECTS[i] = new IntKey(i, Integer.MAX_VALUE);
+        }
+        return UNIQUE_OBJECTS;
+    }
+
+    private static Object[] createUniqueStringKeys() {
+        String UNIQUE_STRINGS[] = new String[TEST_SIZE];
+        for (int i = 0; i < TEST_SIZE; i++) {
+            UNIQUE_STRINGS[i] = unhash(i);
+        }
+        return UNIQUE_STRINGS;
+    }
+
+    private static Object[] createCollidingObjectKeys() {
+        IntKey COLLIDING_OBJECTS[] = new IntKey[TEST_SIZE];
+        for (int i = 0; i < TEST_SIZE; i++) {
+            COLLIDING_OBJECTS[i] = new IntKey(i, 10);
+        }
+        return COLLIDING_OBJECTS;
+    }
+
+    private static Object[] createCollidingStringKeys() {
+        String COLLIDING_STRINGS[] = new String[TEST_SIZE];
+        String UNIQUE_STRINGS[] = new String[TEST_SIZE];
+        for (int i = 0; i < TEST_SIZE; i++) {
+            UNIQUE_STRINGS[i] = unhash(i);
+            COLLIDING_STRINGS[i] = (0 == i % 2)
+                    ? UNIQUE_STRINGS[i / 2]
+                    : "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];
+        }
+        return COLLIDING_STRINGS;
+    }
+
+    /**
+     * Returns a string with a hash equal to the argument.
+     *
+     * @return string with a hash equal to the argument.
+     */
+    private static String unhash(int target) {
+        StringBuilder answer = new StringBuilder();
+        if (target < 0) {
+            // String with hash of Integer.MIN_VALUE, 0x80000000
+            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");
+
+            if (target == Integer.MIN_VALUE) {
+                return answer.toString();
+            }
+            // Find target without sign bit set
+            target = target & Integer.MAX_VALUE;
+        }
+
+        unhash0(answer, target);
+        return answer.toString();
+    }
+
+    private static void unhash0(StringBuilder partial, int target) {
+        int div = target / 31;
+        int rem = target % 31;
+
+        if (div <= Character.MAX_VALUE) {
+            if (div != 0) {
+                partial.append((char) div);
+            }
+            partial.append((char) rem);
+        } else {
+            unhash0(partial, div);
+            partial.append((char) rem);
+        }
+    }
+
+    private static <T> Map<T, T> fillMap(Map<T, T> m, T[] keys) {
+        for (T k : keys) {
+            m.put(k, k);
+            assertTrue(m.containsKey(k));
+            assertTrue(m.containsValue(k));
+        }
+        assertEquals(m.size(), keys.length);
+        return m;
+    }
+
+    private static <T> Supplier<Map<T, T>> createMap(Map<T, T> m, T[] keys) {
+        return () -> fillMap(m, keys);
+    }
+
+    private static <T> Object[] createCase(String desc, Map<T, T> m, T[] keys, T val) {
+        return new Object[]{desc, createMap(m, keys), val};
+    }
+
+    private static <T> Collection<Object[]> makeMapsMoreTypes(String desc,
+                                                              T[] keys,
+                                                              T val) {
+        Collection<Object[]> cases = new ArrayList<>();
+        cases.add(createCase("Hashtable with " + desc,
+                             new Hashtable<>(), keys, val));
+        cases.add(createCase("IdentityHashMap with " + desc,
+                             new IdentityHashMap<>(), keys, val));
+        cases.add(createCase("TreeMap with " + desc,
+                             new TreeMap<>(), keys, val));
+        cases.add(createCase("WeakHashMap with " + desc,
+                             new WeakHashMap<>(), keys, val));
+        cases.add(createCase("ConcurrentHashMap with " + desc,
+                             new ConcurrentHashMap<>(), keys, val));
+        cases.add(createCase("ConcurrentSkipListMap with " + desc,
+                             new ConcurrentSkipListMap<>(), keys, val));
+        return cases;
+    }
+
+    private static <T> Collection<Object[]> makeMapsHashMap(String desc,
+                                                            T[] keys,
+                                                            T val) {
+        Collection<Object[]> cases = new ArrayList<>();
+        cases.add(createCase("HashMap with " + desc,
+                             new HashMap<>(), keys, val));
+        cases.add(createCase("LinkedHashMap with " + desc,
+                             new LinkedHashMap<>(), keys, val));
+        return cases;
+    }
+
+    private static <T> Collection<Object[]> makeMaps(String desc, T[] keys, T val) {
+        Collection<Object[]> cases = new ArrayList<>();
+        cases.addAll(makeMapsHashMap(desc, keys, val));
+        cases.addAll(makeMapsMoreTypes(desc, keys, val));
+        return cases;
+    }
+
+    private static <T> Collection<Object[]> makeObjectsCases(String desc, T[] keys) {
+        return makeMaps(desc, keys, EXTRA_INTKEY_VAL);
+    }
+
+    private static <T> Collection<Object[]> makeStringsCases(String desc,
+            T[] keys) {
+        return makeMaps(desc, keys, EXTRA_STRING_VAL);
+    }
+
+    private static final Collection<Object[]> mapsWithObjectsCases
+            = new ArrayList<>() {
+        {
+            addAll(makeObjectsCases("unique objects", createUniqueObjectKeys()));
+            addAll(makeObjectsCases("colliding objects", createCollidingObjectKeys()));
+        }
+    };
+
+    private static final Collection<Object[]> mapsWithStringsCases
+            = new ArrayList<>() {
+        {
+            addAll(makeStringsCases("unique strings", createUniqueStringKeys()));
+            addAll(makeStringsCases("colliding strings", createCollidingStringKeys()));
+        }
+    };
+
+    private static final Collection<Object[]> mapsWithObjectsAndStringsCases
+            = new ArrayList<>() {
+        {
+            addAll(mapsWithObjectsCases);
+            addAll(mapsWithStringsCases);
+        }
+    };
+
+    private static final Collection<Object[]> hashMapsWithObjectsCases
+            = new ArrayList<>() {
+        {
+            addAll(makeMapsHashMap("unique objects",
+                createUniqueObjectKeys(), EXTRA_INTKEY_VAL));
+            addAll(makeMapsHashMap("collisions objects",
+                createCollidingObjectKeys(), EXTRA_INTKEY_VAL));
+        }
+    };
+
+    @DataProvider
+    public Iterator<Object[]> mapsWithObjects() {
+        return mapsWithObjectsCases.iterator();
+    }
+
+    @DataProvider
+    public Iterator<Object[]> mapsWithStrings() {
+        return mapsWithStringsCases.iterator();
+    }
+
+    @DataProvider
+    public Iterator<Object[]> mapsWithObjectsAndStrings() {
+        return mapsWithObjectsAndStringsCases.iterator();
+    }
+
+    @DataProvider
+    public Iterator<Object[]> hashMapsWithObjects() {
+        return hashMapsWithObjectsCases.iterator();
+    }
+
+}
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java b/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java
deleted file mode 100644
index ac2ecc8..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/*
- * @test
- * @bug 6959653
- * @summary Test ResourceBundle.Control provided using SPI.
- * @build UserDefaultControlTest
- * @run shell UserDefaultControlTest.sh
- */
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-public class UserDefaultControlTest {
-    public static void main(String[] args) {
-        ResourceBundle rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.ROOT);
-        String type = rb.getString("type");
-        if (!type.equals("XML")) {
-            throw new RuntimeException("Root Locale: type: got " + type
-                                       + ", expected XML (ASCII)");
-        }
-
-        rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.JAPAN);
-        type = rb.getString("type");
-        // Expect fullwidth "XML"
-        if (!type.equals("\uff38\uff2d\uff2c")) {
-            throw new RuntimeException("Locale.JAPAN: type: got " + type
-                                       + ", expected \uff38\uff2d\uff2c (fullwidth XML)");
-        }
-
-        try {
-            rb = ResourceBundle.getBundle("com.bar.XmlRB", Locale.JAPAN);
-            throw new RuntimeException("com.bar.XmlRB test failed.");
-        } catch (MissingResourceException e) {
-            // OK
-        }
-    }
-}
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh b/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh
deleted file mode 100644
index 5381426..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-# 
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-# 
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-# 
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-# 
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-# 
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.ext.dirs=${TESTSRC} -cp ${TESTCLASSES} UserDefaultControlTest
-
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile
deleted file mode 100644
index 54ebbd5..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code 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 General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-#
-# Makefile for building a ResourceBundleControlProvider jar file for testing.
-#
-#    Usage: make JDK_HOME=... all install
-#
-
-DESTDIR = ..
-TMPDIR = tmp
-SERVICESDIR = $(TMPDIR)/META-INF/services
-TARGETJAR = rbcontrolprovider.jar
-BINDIR = $(JDK_HOME)/bin
-
-
-all: $(TARGETJAR)
-
-install: all
-	cp $(TARGETJAR) $(DESTDIR)
-
-SERVICES = java.util.spi.ResourceBundleControlProvider
-
-FILES_JAVA = UserControlProvider.java \
-             UserXMLControl.java
-
-RESOURCE_FILES = XmlRB.xml \
-                 XmlRB_ja.xml
-
-$(TARGETJAR): $(SERVICES) $(FILES_JAVA) $(RESOURCE_FILES)
-	rm -rf $(TMPDIR) $@
-	mkdir -p $(SERVICESDIR)
-	$(BINDIR)/javac -d $(TMPDIR) $(FILES_JAVA)
-	cp $(SERVICES) $(SERVICESDIR)
-	cp $(RESOURCE_FILES) $(TMPDIR)/com/foo
-	$(BINDIR)/jar  cvf $@ -C $(TMPDIR) .
-
-clean:
-	rm -rf $(TMPDIR) $(TARGETJAR)
-
-.PHONY: all install clean
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java
deleted file mode 100644
index fdaae6d..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.foo;
-
-import java.util.ResourceBundle;
-import java.util.spi.ResourceBundleControlProvider;
-
-public class UserControlProvider implements ResourceBundleControlProvider {
-    static final ResourceBundle.Control XMLCONTROL = new UserXMLControl();
-
-    public ResourceBundle.Control getControl(String baseName) {
-        System.out.println(getClass().getName()+".getControl called for " + baseName);
-
-        // Throws a NPE if baseName is null.
-        if (baseName.startsWith("com.foo.Xml")) {
-            System.out.println("\treturns " + XMLCONTROL);
-            return XMLCONTROL;
-        }
-        System.out.println("\treturns null");
-        return null;
-    }
-}
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java
deleted file mode 100644
index 58809f01..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.foo;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import static java.util.ResourceBundle.Control.*;
-
-public class UserXMLControl extends ResourceBundle.Control {
-    @Override
-    public List<String> getFormats(String baseName) {
-        if (baseName == null) {
-            throw new NullPointerException();
-        }
-        return Arrays.asList("xml");
-    }
-
-    @Override
-    public ResourceBundle newBundle(String baseName, Locale locale,
-                                    String format,
-                                    ClassLoader loader,
-                                    boolean reload)
-        throws IllegalAccessException,
-               InstantiationException, IOException {
-        if (baseName == null || locale == null
-            || format == null || loader == null) {
-            throw new NullPointerException();
-        }
-        ResourceBundle bundle = null;
-        if (format.equals("xml")) {
-            String bundleName = toBundleName(baseName, locale);
-            String resourceName = toResourceName(bundleName, format);
-            URL url = loader.getResource(resourceName);
-            if (url != null) {
-                URLConnection connection = url.openConnection();
-                if (connection != null) {
-                    if (reload) {
-                        // disable caches if reloading
-                        connection.setUseCaches(false);
-                    }
-                    try (InputStream stream = connection.getInputStream()) {
-                        if (stream != null) {
-                            BufferedInputStream bis = new BufferedInputStream(stream);
-                            bundle = new XMLResourceBundle(bis);
-                        }
-                    }
-                }
-            }
-        }
-        return bundle;
-    }
-
-    private static class XMLResourceBundle extends ResourceBundle {
-        private Properties props;
-
-        XMLResourceBundle(InputStream stream) throws IOException {
-            props = new Properties();
-            props.loadFromXML(stream);
-        }
-
-        protected Object handleGetObject(String key) {
-            if (key == null) {
-                throw new NullPointerException();
-            }
-            return props.get(key);
-        }
-
-        public Enumeration<String> getKeys() {
-            // Not implemented
-            return null;
-        }
-    }
-}
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml
deleted file mode 100644
index 689df75..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- 
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.  Oracle designates this
- particular file as subject to the "Classpath" exception as provided
- by Oracle in the LICENSE file that accompanied this code.
- 
- This code 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 General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
- 
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- 
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
--->
-<!---->
-
-<!-- DTD for properties -->
-<!DOCTYPE properties [
-<!ELEMENT properties ( comment?, entry* ) >
-<!ATTLIST properties version CDATA #FIXED "1.0">
-<!ELEMENT comment (#PCDATA) >
-<!ELEMENT entry (#PCDATA) >
-<!ATTLIST entry key CDATA #REQUIRED>
-]>
-
-<properties>
-    <comment>Test data for UserDefaultControlTest.java</comment>
-    <entry key="type">XML</entry>
-</properties>
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml
deleted file mode 100644
index fb273f53..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- 
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.  Oracle designates this
- particular file as subject to the "Classpath" exception as provided
- by Oracle in the LICENSE file that accompanied this code.
- 
- This code 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 General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
- 
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- 
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
--->
-<!---->
-
-<!-- DTD for properties -->
-<!DOCTYPE properties [
-<!ELEMENT properties ( comment?, entry* ) >
-<!ATTLIST properties version CDATA #FIXED "1.0">
-<!ELEMENT comment (#PCDATA) >
-<!ELEMENT entry (#PCDATA) >
-<!ATTLIST entry key CDATA #REQUIRED>
-]>
-
-<properties>
-    <comment>Test data for UserDefaultControlTest.java</comment>
-    <entry key="type">XML</entry>
-</properties>
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/java.util.spi.ResourceBundleControlProvider b/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/java.util.spi.ResourceBundleControlProvider
deleted file mode 100644
index 7c2a19d..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/java.util.spi.ResourceBundleControlProvider
+++ /dev/null
@@ -1 +0,0 @@
-com.foo.UserControlProvider
diff --git a/jdk/test/java/util/spi/ResourceBundleControlProvider/rbcontrolprovider.jar b/jdk/test/java/util/spi/ResourceBundleControlProvider/rbcontrolprovider.jar
deleted file mode 100644
index b7e6a49..0000000
--- a/jdk/test/java/util/spi/ResourceBundleControlProvider/rbcontrolprovider.jar
+++ /dev/null
Binary files differ
diff --git a/jdk/test/javax/crypto/NullCipher/TestNPE.java b/jdk/test/javax/crypto/NullCipher/TestNPE.java
index 0e216d0..c81ce74 100644
--- a/jdk/test/javax/crypto/NullCipher/TestNPE.java
+++ b/jdk/test/javax/crypto/NullCipher/TestNPE.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,10 +23,12 @@
 
 /*
  * @test
- * @bug 4937853
+ * @bug 4937853 8170876
  * @summary Make sure normal calls of NullCipher does not throw NPE.
  * @author Valerie Peng
  * @key randomness
+ * @run main TestNPE
+ * @run main/othervm -Djava.security.debug=provider TestNPE
  */
 import java.util.Arrays;
 import java.security.AlgorithmParameters;
diff --git a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
index 14a5741..c24ebe2 100644
--- a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java
@@ -223,7 +223,7 @@
         ImageReader reader = getTIFFReader();
 
         ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
-        reader.setInput(s, false, true);
+        reader.setInput(s, false, false);
 
         int ni = reader.getNumImages(true);
         check(ni == 2, "invalid number of images");
diff --git a/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java
new file mode 100644
index 0000000..3734b86
--- /dev/null
+++ b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     8154058
+ * @author  a.stepanov
+ * @summary Some checks for ignoring metadata
+ * @run     main ReadUnknownTagsTest
+ */
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import javax.imageio.*;
+import javax.imageio.metadata.*;
+
+import javax.imageio.stream.*;
+import javax.imageio.plugins.tiff.*;
+
+
+public class ReadUnknownTagsTest {
+
+    private final static int SZ = 50;
+    private final static Color C = Color.RED;
+
+    private final static int DESCRIPTION_TAG =
+        BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION;
+    private final static String DESCRIPTION = "A Test Image";
+
+    private final static int FAX_TAG = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA;
+    private final static short FAX_DATA =
+        FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED;
+
+    private final boolean ignoreMetadata;
+    private final boolean readUnknownTags;
+
+    public ReadUnknownTagsTest(boolean ignoreMetadata,
+        boolean readUnknownTags) {
+        this.ignoreMetadata = ignoreMetadata;
+        this.readUnknownTags = readUnknownTags;
+    }
+
+    private ImageWriter getTIFFWriter() {
+
+        java.util.Iterator<ImageWriter> writers =
+            ImageIO.getImageWritersByFormatName("TIFF");
+        if (!writers.hasNext()) {
+            throw new RuntimeException("No writers available for TIFF format");
+        }
+        return writers.next();
+    }
+
+    private ImageReader getTIFFReader() {
+
+        java.util.Iterator<ImageReader> readers =
+            ImageIO.getImageReadersByFormatName("TIFF");
+        if (!readers.hasNext()) {
+            throw new RuntimeException("No readers available for TIFF format");
+        }
+        return readers.next();
+    }
+
+
+    private void writeImage() throws Exception {
+
+        String fn = "test-" + ignoreMetadata + ".tiff";
+        OutputStream s = new BufferedOutputStream(new FileOutputStream(fn));
+        try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) {
+
+            ImageWriter writer = getTIFFWriter();
+            writer.setOutput(ios);
+
+            BufferedImage img = new BufferedImage(SZ, SZ,
+                BufferedImage.TYPE_INT_RGB);
+            Graphics g = img.getGraphics();
+            g.setColor(C);
+            g.fillRect(0, 0, SZ, SZ);
+            g.dispose();
+
+            ImageWriteParam param = writer.getDefaultWriteParam();
+
+            IIOMetadata md = writer.getDefaultImageMetadata(
+                    new ImageTypeSpecifier(img), param);
+
+            TIFFDirectory dir = TIFFDirectory.createFromMetadata(md);
+
+            TIFFTag descTag =
+                BaselineTIFFTagSet.getInstance().getTag(DESCRIPTION_TAG);
+            dir.addTIFFField(new TIFFField(descTag, TIFFTag.TIFF_ASCII, 1,
+                new String[] {DESCRIPTION}));
+
+            TIFFTag faxTag = FaxTIFFTagSet.getInstance().getTag(FAX_TAG);
+            dir.addTIFFField(new TIFFField(faxTag, FAX_DATA));
+
+            writer.write(new IIOImage(img, null, dir.getAsMetadata()));
+
+            ios.flush();
+            writer.dispose();
+        }
+        s.close();
+    }
+
+    private void readAndCheckImage() throws Exception {
+
+        ImageReader reader = getTIFFReader();
+
+        String fn = "test-" + ignoreMetadata + ".tiff";
+        ImageInputStream s = ImageIO.createImageInputStream(new File(fn));
+
+        reader.setInput(s, false, ignoreMetadata);
+
+        int ni = reader.getNumImages(true);
+        check(ni == 1, "invalid number of images");
+
+
+        TIFFImageReadParam param = new TIFFImageReadParam();
+        // fax data are allowed by default
+        param.removeAllowedTagSet(FaxTIFFTagSet.getInstance());
+
+        // readUnknownTags setting
+        if (param.getReadUnknownTags()) {
+            throw new RuntimeException("Default readUnknownTags is not false");
+        }
+        param.setReadUnknownTags(readUnknownTags);
+        if (param.getReadUnknownTags() != readUnknownTags) {
+            throw new RuntimeException("Incorrect readUnknownTags setting "
+                + "\"" + readUnknownTags + "\"");
+        }
+
+        // read images and metadata
+        IIOImage i = reader.readAll(0, param);
+        BufferedImage bi = (BufferedImage) i.getRenderedImage();
+
+        check(bi.getWidth()  == SZ, "invalid width");
+        check(bi.getHeight() == SZ, "invalid height");
+        Color c = new Color(bi.getRGB(SZ / 2, SZ / 2));
+        check(c.equals(C), "invalid color");
+
+        IIOMetadata metadata = i.getMetadata();
+
+        //
+        // Verify presence of image metadata
+        //
+        if (metadata == null) {
+            throw new RuntimeException("No image metadata retrieved");
+        }
+
+        TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
+
+        //
+        // Verify presence of essential ImageWidth field regardless of
+        // settings of ignoreMetadata and readUnknownTags
+        //
+        int failures = 0;
+        if (!dir.containsTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH)) {
+            System.err.println("Metadata is missing essential ImageWidth tag");
+            failures++;
+        } else {
+            TIFFField widthField =
+                dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
+            System.out.printf("ImageWidth: %d%n", widthField.getAsLong(0));
+        }
+
+        //
+        // Verify presence of non-essential baseline ImageDescription field
+        // if and only if ignoreMetadata == false
+        //
+        boolean hasDescription = dir.containsTIFFField(DESCRIPTION_TAG);
+        System.out.println("ImageDescription (" + !ignoreMetadata + "): "
+            + hasDescription);
+        if (ignoreMetadata && hasDescription) {
+            System.err.println
+                ("Description metadata present despite ignoreMetadata");
+            failures++;
+        } else if (!ignoreMetadata && !hasDescription) {
+            System.err.println
+                ("Description metadata absent despite !ignoreMetadata");
+            failures++;
+        }
+
+        //
+        // Verify presence of CleanFaxData field if and only if
+        // ignoreMetadata == false and readUnknownTags == true
+        //
+        boolean shouldHaveFaxField = !ignoreMetadata && readUnknownTags;
+        boolean hasFaxField = dir.containsTIFFField(FAX_TAG);
+        System.out.println("CleanFaxData (" + shouldHaveFaxField + "): "
+            + hasFaxField);
+
+        if (ignoreMetadata) {
+            if (hasFaxField) {
+                System.err.println
+                    ("Fax metadata present despite ignoreMetadata");
+                failures++;
+            }
+        } else { // !ignoreMetadata
+            if (!readUnknownTags && hasFaxField) {
+                System.err.println
+                    ("Fax metadata present despite !readUnknownTags");
+                failures++;
+            } else if (readUnknownTags && !hasFaxField) {
+                System.err.println
+                    ("Fax metadata absent despite readUnknownTags");
+                failures++;
+            }
+        }
+
+        if (failures > 0) {
+            throw new RuntimeException("Test failed for ignoreMetadata "
+                + ignoreMetadata + " and readUnknownTags " + readUnknownTags);
+        }
+    }
+
+    public void run() {
+        try {
+            writeImage();
+            readAndCheckImage();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void check(boolean ok, String msg) {
+        if (!ok) { throw new RuntimeException(msg); }
+    }
+
+    public static void main(String[] args) {
+        int failures = 0;
+
+        System.out.println();
+        for (boolean ignoreMetadata : new boolean[] {false, true}) {
+            for (boolean readUnknownTags : new boolean[] {false, true}) {
+                try {
+                    System.out.printf
+                        ("ignoreMetadata: %s, readUnknownTags: %s%n",
+                        ignoreMetadata, readUnknownTags);
+                    (new ReadUnknownTagsTest(ignoreMetadata,
+                        readUnknownTags)).run();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    failures++;
+                } finally {
+                    System.out.println();
+                }
+            }
+        }
+    }
+}
diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java
index 39c2474..570f5f2 100644
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java
@@ -154,7 +154,7 @@
             "must return null TIFFField");
 
         long offset = 4L;
-        long a[] = {Long.MIN_VALUE, 0, Long.MAX_VALUE};
+        long a[] = {0, Integer.MAX_VALUE, (1 << 32) - 1};
         int v = 100500;
         TIFFField
                 f1 = new TIFFField(tag1, type, offset, d),
diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java
index 936a5e3..9b05bbb 100644
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug     8152183 8149562
+ * @bug     8152183 8149562 8169725 8169728
  * @author  a.stepanov
  * @summary Some checks for TIFFField methods
  * @run     main TIFFFieldTest
@@ -65,7 +65,26 @@
         ok = false;
         try { new TIFFField(tag, -1); }
         catch (IllegalArgumentException e) { ok = true; }
-        check(ok, CONSTRUCT + "invalid count");
+        check(ok, CONSTRUCT + "negative value");
+
+        ok = false;
+        try { new TIFFField(tag, 1L << 32); }
+        catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value > 0xffffffff");
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT);
+            new TIFFField(t, 0x10000);
+        } catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value 0x10000 incompatible with TIFF_SHORT");
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            new TIFFField(t, 0xffff);
+        } catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value 0xffff incompatible with TIFF_LONG");
 
         // check value type recognition
         int v = 1 << 16;
@@ -152,6 +171,94 @@
         check((f.getDirectory() == null) && !f.hasDirectory(),
             "must not have directory");
 
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[6][3];
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SRATIONAL);
+            int[][] tiffSRationals = new int[6][3];
+            new TIFFField(t, TIFFTag.TIFF_SRATIONAL, tiffSRationals.length,
+                tiffSRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            long[] tiffLongs = new long[] {0, -7, 10};
+            new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            long[] tiffLongs = new long[] {0, 7, 0x100000000L};
+            new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+            long[] tiffLongs = new long[] {-7};
+            new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+            long[] tiffLongs = new long[] {0x100000000L};
+            new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[][] {
+                {10, 2},
+                {1, -3},
+                {4,  7}
+            };
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[][] {
+                {10, 2},
+                {0x100000000L, 3},
+                {4,  7}
+            };
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
         // constructor: TIFFField(tag, type, offset, dir)
         List<TIFFTag> tags = new ArrayList<>();
         tags.add(tag);
diff --git a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
index 34fd5ed..6cd71e2 100644
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java
@@ -159,7 +159,7 @@
         ImageReader reader = getTIFFReader();
 
         ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
-        reader.setInput(s, false, true);
+        reader.setInput(s, false, false);
 
         int ni = reader.getNumImages(true);
         check(ni == 1, "invalid number of images: " + ni);
diff --git a/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java b/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java
index ebc0ab2..7301c4f 100644
--- a/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java
+++ b/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,20 +103,13 @@
         mbsc.invoke(mbean, "emitNotification", null, null);
 
         System.out.println("EmptyDomainNotificationTest-main: waiting notif...");
-        final long stopTime = System.currentTimeMillis() + 2000;
         synchronized(li) {
-            long toWait = stopTime - System.currentTimeMillis();
-
-            while (li.received < 1 && toWait > 0) {
-                li.wait(toWait);
-
-                toWait = stopTime - System.currentTimeMillis();
+            while (li.received < 1) {
+                li.wait();
             }
         }
 
-        if (li.received < 1) {
-            throw new RuntimeException("No notif received!");
-        } else if (li.received > 1) {
+        if (li.received != 1) {
             throw new RuntimeException("Wait one notif but got: "+li.received);
         }
 
diff --git a/jdk/test/javax/management/remote/mandatory/threads/ExecutorShutdownTest.java b/jdk/test/javax/management/remote/mandatory/threads/ExecutorShutdownTest.java
new file mode 100644
index 0000000..003780c
--- /dev/null
+++ b/jdk/test/javax/management/remote/mandatory/threads/ExecutorShutdownTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8141591
+ * @summary Tests if notifications are received after executor is shutdown
+ * @author Harsha Wardhana B
+ * @modules java.management
+ * @run clean ExecutorShutdownTest
+ * @run build ExecutorShutdownTest
+ * @run main ExecutorShutdownTest
+ */
+import java.util.*;
+import java.util.concurrent.*;
+import javax.management.*;
+import javax.management.remote.*;
+
+/*
+  When you create a JMXConnector client, you can supply a
+  "fetch-notifications Executor", which is a
+  java.util.concurrent.Executor that will be used each time the
+  connector client wants to call RMIConnection.fetchNotifications.
+  If such executor is not supplies, the connector client will fallback
+  on default LinearExecutor. This test checks if user supplied executor
+  is shutdown abruptly, LinearExecutor is used to handle notifications.
+ */
+public class ExecutorShutdownTest {
+
+    private static final String EXECUTOR_PROPERTY
+            = "jmx.remote.x.fetch.notifications.executor";
+    private static final String NOTIF_TYPE = "test.type";
+
+    public static void main(String[] args) throws Exception {
+
+        // Start JMXConnector Server
+        JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        ObjectName emitName = new ObjectName("blah:type=Emitter");
+        mbs.registerMBean(new Emitter(), emitName);
+        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url,
+                null,
+                mbs);
+        cs.start();
+
+        // Create executor to provide to JMXConnector client
+        ExecutorService executor = Executors.newCachedThreadPool();
+        Map<String, Executor> env = new HashMap<>();
+        env.put(EXECUTOR_PROPERTY, executor);
+        JMXServiceURL addr = cs.getAddress();
+
+        try (JMXConnector cc = JMXConnectorFactory.connect(addr, env)) {
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+            EmitterMBean emitter = (EmitterMBean) MBeanServerInvocationHandler.newProxyInstance(mbsc,
+                    emitName,
+                    EmitterMBean.class,
+                    false);
+            SemaphoreListener listener = new SemaphoreListener();
+            NotificationFilterSupport filter = new NotificationFilterSupport();
+            filter.enableType(NOTIF_TYPE);
+            mbsc.addNotificationListener(emitName, listener, filter, null);
+
+            final int NOTIF_COUNT = 3;
+            for (int i = 0; i < NOTIF_COUNT; i++) {
+                emitter.emit();
+                listener.await();
+            }
+            Thread.sleep(1);
+            listener.checkUnavailable();
+            System.out.println("Got notifications with client provided executor");
+
+            // After shutting down executor, notifications are handled by linear executor
+            executor.shutdown();
+            for (int i = 0; i < NOTIF_COUNT; i++) {
+                emitter.emit();
+                listener.await();
+            }
+            Thread.sleep(1);
+            listener.checkUnavailable();
+            System.out.println("Got notifications with linear executor");
+        }
+        cs.stop();
+        System.out.println("TEST PASSED !!!");
+    }
+
+    /* Simple MBean that sends a notification every time we ask it to.  */
+    public static interface EmitterMBean {
+
+        public void emit();
+    }
+
+    public static class Emitter
+            extends NotificationBroadcasterSupport implements EmitterMBean {
+
+        public void emit() {
+            sendNotification(new Notification(NOTIF_TYPE, this, seq++));
+        }
+
+        private long seq = 1;
+    }
+
+    /* Simple NotificationListener that allows you to wait until a
+       notification has been received.  Since it uses a semaphore, you
+       can wait either before or after the notification has in fact
+       been received and it will work in either case.  */
+    private static class SemaphoreListener implements NotificationListener {
+
+        void await() throws InterruptedException {
+            semaphore.acquire();
+        }
+
+        /* Ensure no extra notifications were received.  If we can acquire
+           the semaphore, that means its release() method was called more
+           times than its acquire() method, which means there were too
+           many notifications.  */
+        void checkUnavailable() throws Exception {
+            if (semaphore.tryAcquire()) {
+                throw new Exception("Got extra notifications!");
+            }
+        }
+
+        public void handleNotification(Notification n, Object h) {
+            semaphore.release();
+        }
+
+        private final Semaphore semaphore = new Semaphore(0);
+    }
+}
diff --git a/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java
index d457766..ecd7dcf 100644
--- a/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java
+++ b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java
@@ -34,15 +34,17 @@
     static final String ERROR = "ERROR";
     X509ExtendedKeyManager akm;
     String expectedAP;
+    boolean doCheck = true;
 
     MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
         this.akm = akm;
     }
 
     public MyX509ExtendedKeyManager(
-            X509ExtendedKeyManager akm, String expectedAP) {
+            X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) {
         this.akm = akm;
         this.expectedAP = expectedAP;
+        this.doCheck = doCheck;
 
     }
 
@@ -104,6 +106,12 @@
 
     private void checkALPN(String ap) {
 
+        if (!doCheck) {
+            System.out.println("Skipping KeyManager checks " +
+                "because a callback has been registered");
+            return;
+        }
+
         if (ERROR.equals(expectedAP)) {
             throw new RuntimeException("Should not reach here");
         }
diff --git a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java
index de4ea6c..b17da74 100644
--- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java
+++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java
@@ -26,23 +26,53 @@
 
 /*
  * @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLEngineAlpnTest h2          h2          h2
- * @run main/othervm SSLEngineAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLEngineAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLEngineAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLEngineAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLEngineAlpnTest H2          h2          ERROR
- * @run main/othervm SSLEngineAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2       http/1.1    ERROR
  */
 /**
  * A simple SSLEngine-based client/server that demonstrates the proposed API
  * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
  *
+ * Usage:
+ *     java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
  * This example is based on our standard SSLEngineTemplate.
  *
  * The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
@@ -98,6 +128,7 @@
 import java.io.*;
 import java.security.*;
 import java.nio.*;
+import java.util.Arrays;
 
 public class SSLEngineAlpnTest {
 
@@ -117,6 +148,9 @@
      */
     private static final boolean debug = false;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     private final SSLContext sslc;
 
     private SSLEngine clientEngine;     // client Engine
@@ -157,17 +191,21 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
 
-        SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]);
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !args[1].equals("UNUSED"); // is callback being used?
+
+        SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
         try {
-            test.runTest(convert(args[0]), convert(args[1]), args[2]);
+            test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -199,7 +237,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(ts);
@@ -215,12 +254,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings = null;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
@@ -247,12 +289,12 @@
      * One could easily separate these phases into separate
      * sections of code.
      */
-    private void runTest(String[] serverAPs, String[] clientAPs,
-            String expectedAP) throws Exception {
+    private void runTest(String[] serverAPs, String callbackAP,
+            String[] clientAPs, String expectedAP) throws Exception {
 
         boolean dataDone = false;
 
-        createSSLEngines(serverAPs, clientAPs);
+        createSSLEngines(serverAPs, callbackAP, clientAPs);
         createBuffers();
 
         SSLEngineResult clientResult;   // results from client's last operation
@@ -364,8 +406,8 @@
      * Using the SSLContext created during object creation,
      * create/configure the SSLEngines we'll use for this test.
      */
-    private void createSSLEngines(String[] serverAPs, String[] clientAPs)
-        throws Exception {
+    private void createSSLEngines(String[] serverAPs, String callbackAP,
+            String[] clientAPs) throws Exception {
         /*
          * Configure the serverEngine to act as a server in the SSL/TLS
          * handshake.  Also, require SSL client authentication.
@@ -385,18 +427,42 @@
          */
         String[] suites = sslp.getCipherSuites();
         sslp.setCipherSuites(suites);
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslp.setUseCipherSuitesOrder(true);  // Set server side order
 
         serverEngine.setSSLParameters(sslp);
 
+        // check that no callback has been registered
+        if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            serverEngine.setHandshakeApplicationProtocolSelector(
+                (sslEngine, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (serverEngine.getHandshakeApplicationProtocolSelector()
+                    == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"
+                    + " should return non-null");
+            }
+        }
+
         /*
          * Similar to above, but using client mode instead.
          */
         clientEngine = sslc.createSSLEngine("client", 80);
         clientEngine.setUseClientMode(true);
         sslp = clientEngine.getSSLParameters();
-        sslp.setApplicationProtocols(clientAPs);
+        if (clientAPs != null) {
+            sslp.setApplicationProtocols(clientAPs);
+        }
         clientEngine.setSSLParameters(sslp);
 
         if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
diff --git a/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java b/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java
index a310cbb..a9373ed 100644
--- a/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java
+++ b/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java
@@ -26,22 +26,61 @@
 
 /*
  * @test
- * @bug 8051498 8145849 8158978
+ * @bug 8051498 8145849 8158978 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLServerSocketAlpnTest h2          h2          h2
- * @run main/othervm SSLServerSocketAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLServerSocketAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLServerSocketAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLServerSocketAlpnTest H2          h2          ERROR
- * @run main/othervm SSLServerSocketAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 H2       http/1.1    ERROR
+ *
  * @author Brad Wetmore
  */
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ *     java SSLServerSocketAlpnTest
+ *             <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
 import java.io.*;
 import java.security.KeyStore;
+import java.util.Arrays;
 
 import javax.net.ssl.*;
 
@@ -73,6 +112,9 @@
     static String trustFilename = System.getProperty("test.src", ".") + "/"
             + pathToStores + "/" + trustStoreFile;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     /*
      * SSLContext
      */
@@ -89,6 +131,7 @@
     static boolean debug = false;
 
     static String[] serverAPs;
+    static String callbackAP;
     static String[] clientAPs;
     static String expectedAP;
 
@@ -129,7 +172,9 @@
         sslp.setUseCipherSuitesOrder(true); // Set server side order
 
         // Set the ALPN selection.
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslServerSocket.setSSLParameters(sslp);
 
         serverPort = sslServerSocket.getLocalPort();
@@ -146,6 +191,25 @@
                     + "return null before the handshake starts");
         }
 
+        // check that no callback has been registered
+        if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            sslSocket.setHandshakeApplicationProtocolSelector(
+                (serverSocket, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"
+                    + " should return non-null");
+            }
+        }
+
         sslSocket.startHandshake();
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -276,14 +340,19 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
         serverAPs = convert(args[0]);
-        clientAPs = convert(args[1]);
-        expectedAP = args[2];
+        callbackAP = args[1];
+        clientAPs = convert(args[2]);
+        expectedAP = args[3];
+
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
 
         /*
          * Start the tests.
@@ -291,7 +360,7 @@
         try {
             new SSLServerSocketAlpnTest();
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -322,7 +391,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(trustKS);
@@ -338,12 +408,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
diff --git a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java
index fd52f25..ef72474 100644
--- a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java
+++ b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java
@@ -26,22 +26,60 @@
 
 /*
  * @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLSocketAlpnTest h2          h2          h2
- * @run main/othervm SSLSocketAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLSocketAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLSocketAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLSocketAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLSocketAlpnTest H2          h2          ERROR
- * @run main/othervm SSLSocketAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLSocketAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2       http/1.1    ERROR
+ *
  * @author Brad Wetmore
  */
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ *     java SSLSocketAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
 import java.io.*;
 import java.security.KeyStore;
+import java.util.Arrays;
 
 import javax.net.ssl.*;
 
@@ -73,6 +111,9 @@
     static String trustFilename = System.getProperty("test.src", ".") + "/"
             + pathToStores + "/" + trustStoreFile;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     /*
      * SSLContext
      */
@@ -89,6 +130,7 @@
     static boolean debug = false;
 
     static String[] serverAPs;
+    static String callbackAP;
     static String[] clientAPs;
     static String expectedAP;
 
@@ -136,7 +178,9 @@
         sslp.setUseCipherSuitesOrder(true); // Set server side order
 
         // Set the ALPN selection.
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslSocket.setSSLParameters(sslp);
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -144,6 +188,24 @@
                     + "return null before the handshake starts");
         }
 
+        // check that no callback has been registered
+        if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            sslSocket.setHandshakeApplicationProtocolSelector(
+                (serverSocket, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"                     + " should return non-null");
+            }
+        }
+
         sslSocket.startHandshake();
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -274,14 +336,19 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
         serverAPs = convert(args[0]);
-        clientAPs = convert(args[1]);
-        expectedAP = args[2];
+        callbackAP = args[1];
+        clientAPs = convert(args[2]);
+        expectedAP = args[3];
+
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
 
         /*
          * Start the tests.
@@ -289,7 +356,7 @@
         try {
             new SSLSocketAlpnTest();
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -320,7 +387,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(trustKS);
@@ -336,12 +404,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
diff --git a/jdk/test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java b/jdk/test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java
index e9338cc..0527318 100644
--- a/jdk/test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java
+++ b/jdk/test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
  * @bug 4387882
  * @summary Need to revisit the javadocs for JSSE, especially the
  *      promoted classes.
+ * @library /javax/net/ssl/templates
  * @run main/othervm SSLSessionNulls
  *
  *     SunJSSE does not support dynamic system properties, no way to re-use
@@ -33,109 +34,35 @@
  * @author Brad Wetmore
  */
 
-import java.io.*;
-import java.net.*;
-import javax.net.ssl.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
-public class SSLSessionNulls {
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
 
-    /*
-     * =============================================================
-     * Set the various variables needed for the tests, then
-     * specify what tests to run on each side.
-     */
+public class SSLSessionNulls extends SSLSocketTemplate {
 
-    /*
-     * Should we run the client or server in a separate thread?
-     * Both sides can throw exceptions, but do you have a preference
-     * as to which side should be the main thread.
-     */
-    static boolean separateServerThread = true;
-
-    /*
-     * Where do we find the keystores?
-     */
-    static String pathToStores = "../etc";
-    static String keyStoreFile = "keystore";
-    static String trustStoreFile = "truststore";
-    static String passwd = "passphrase";
-
-    /*
-     * Is the server ready to serve?
-     */
-    volatile static boolean serverReady = false;
-
-    /*
-     * Turn on SSL debugging?
-     */
-    static boolean debug = false;
-
-    /*
-     * If the client or server is doing some kind of object creation
-     * that the other side depends on, and that thread prematurely
-     * exits, you may experience a hang.  The test harness will
-     * terminate all hung threads after its timeout has expired,
-     * currently 3 minutes by default, but you might try to be
-     * smart about it....
-     */
-
-    /*
-     * Define the server side of the test.
-     *
-     * If the server prematurely exits, serverReady will be set to true
-     * to avoid infinite hangs.
-     */
-    void doServerSide() throws Exception {
-        SSLServerSocketFactory sslssf =
-            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
-        SSLServerSocket sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
-        serverPort = sslServerSocket.getLocalPort();
-
-        /*
-         * Signal Client, we're ready for his connect.
-         */
-        serverReady = true;
-
-        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
-        InputStream sslIS = sslSocket.getInputStream();
-        OutputStream sslOS = sslSocket.getOutputStream();
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
 
         sslIS.read();
         sslOS.write(85);
         sslOS.flush();
-
-        sslSocket.close();
     }
 
-    /*
-     * Define the client side of the test.
-     *
-     * If the server prematurely exits, serverReady will be set to true
-     * to avoid infinite hangs.
-     */
-    void doClientSide() throws Exception {
-
-        /*
-         * Wait for server to get started.
-         */
-        while (!serverReady) {
-            Thread.sleep(50);
-        }
-
-        SSLSocketFactory sslsf =
-            (SSLSocketFactory) SSLSocketFactory.getDefault();
-        SSLSocket sslSocket = (SSLSocket)
-            sslsf.createSocket("localhost", serverPort);
-
-        InputStream sslIS = sslSocket.getInputStream();
-        OutputStream sslOS = sslSocket.getOutputStream();
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
 
         sslOS.write(280);
         sslOS.flush();
         sslIS.read();
 
-        SSLSession sslSession = sslSocket.getSession();
+        SSLSession sslSession = socket.getSession();
 
         try {
             sslSession.getValue(null);
@@ -163,128 +90,9 @@
             throw new IOException(
                 "getValueNames didn't return 0-length arrary");
         }
-
-        sslSocket.close();
     }
 
-    /*
-     * =============================================================
-     * The remainder is just support stuff
-     */
-
-    // use any free port by default
-    volatile int serverPort = 0;
-
-    volatile Exception serverException = null;
-    volatile Exception clientException = null;
-
     public static void main(String[] args) throws Exception {
-        String keyFilename =
-            System.getProperty("test.src", "./") + "/" + pathToStores +
-                "/" + keyStoreFile;
-        String trustFilename =
-            System.getProperty("test.src", "./") + "/" + pathToStores +
-                "/" + trustStoreFile;
-
-        System.setProperty("javax.net.ssl.keyStore", keyFilename);
-        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
-        System.setProperty("javax.net.ssl.trustStore", trustFilename);
-        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
-
-        if (debug)
-            System.setProperty("javax.net.debug", "all");
-
-        /*
-         * Start the tests.
-         */
-        new SSLSessionNulls();
-    }
-
-    Thread clientThread = null;
-    Thread serverThread = null;
-
-    /*
-     * Primary constructor, used to drive remainder of the test.
-     *
-     * Fork off the other side, then do your work.
-     */
-    SSLSessionNulls() throws Exception {
-        if (separateServerThread) {
-            startServer(true);
-            startClient(false);
-        } else {
-            startClient(true);
-            startServer(false);
-        }
-
-        /*
-         * Wait for other side to close down.
-         */
-        if (separateServerThread) {
-            serverThread.join();
-        } else {
-            clientThread.join();
-        }
-
-        /*
-         * When we get here, the test is pretty much over.
-         *
-         * If the main thread excepted, that propagates back
-         * immediately.  If the other thread threw an exception, we
-         * should report back.
-         */
-        if (serverException != null) {
-            System.out.print("Server Exception:");
-            throw serverException;
-        }
-        if (clientException != null) {
-            System.out.print("Client Exception:");
-            throw clientException;
-        }
-    }
-
-    void startServer(boolean newThread) throws Exception {
-        if (newThread) {
-            serverThread = new Thread() {
-                public void run() {
-                    try {
-                        doServerSide();
-                    } catch (Exception e) {
-                        /*
-                         * Our server thread just died.
-                         *
-                         * Release the client, if not active already...
-                         */
-                        System.err.println("Server died...");
-                        serverReady = true;
-                        serverException = e;
-                    }
-                }
-            };
-            serverThread.start();
-        } else {
-            doServerSide();
-        }
-    }
-
-    void startClient(boolean newThread) throws Exception {
-        if (newThread) {
-            clientThread = new Thread() {
-                public void run() {
-                    try {
-                        doClientSide();
-                    } catch (Exception e) {
-                        /*
-                         * Our client thread just died.
-                         */
-                        System.err.println("Client died...");
-                        clientException = e;
-                    }
-                }
-            };
-            clientThread.start();
-        } else {
-            doClientSide();
-        }
+        new SSLSessionNulls().run();
     }
 }
diff --git a/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java b/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java
index f8373a6..5444285 100644
--- a/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java
+++ b/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,30 +29,37 @@
 
 /*
  * @test
- * @bug 8013810
- * @summary Test that print service returned without filter are of the same class as with name filter
+ * @bug 8013810 8025439
+ * @summary Test that print service returned without filter are of the same class
+ *          as with name filter
  */
 public class GetPrintServices {
 
-  public static void main(String[] args) throws Exception {
-    for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
-      String serviceName = service.getName();
-      PrintService serviceByName = lookupByName(serviceName);
-      if (!service.equals(serviceByName)) {
-        throw new RuntimeException("NOK " + serviceName
+    public static void main(String[] args) throws Exception {
+        for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
+            String serviceName = service.getName();
+            PrinterName name = service.getAttribute(PrinterName.class);
+            String printerName = name.getValue();
+
+            PrintService serviceByName = lookupByName(printerName);
+            System.out.println("service " + service);
+            System.out.println("serviceByName " + serviceByName);
+            if (!service.equals(serviceByName)) {
+                throw new RuntimeException("NOK " + serviceName
                                    + " expected: " + service.getClass().getName()
                                    + " got: " + serviceByName.getClass().getName());
-      }
+            }
+        }
+        System.out.println("Test PASSED");
     }
-    System.out.println("Test PASSED");
-  }
 
-  private static PrintService lookupByName(String name) {
-    AttributeSet attributes = new HashAttributeSet();
-    attributes.add(new PrinterName(name, null));
-    for (PrintService service : PrintServiceLookup.lookupPrintServices(null, attributes)) {
-      return service;
+    private static PrintService lookupByName(String name) {
+        AttributeSet attributes = new HashAttributeSet();
+        attributes.add(new PrinterName(name, null));
+        for (PrintService service :
+             PrintServiceLookup.lookupPrintServices(null, attributes)) {
+            return service;
+        }
+        return null;
     }
-    return null;
-  }
 }
diff --git a/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java b/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java
index c7ea83f..7bf4a44 100644
--- a/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java
+++ b/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java
@@ -26,7 +26,7 @@
   * @summary Test to check JComboBox does not lose its ability to invoke
   * registerd ActionListener in case of exception in ActionListener
   * @run main ActionListenerExceptionTest
-  */
+ */
 
 import java.awt.AWTEvent;
 import java.awt.AWTException;
@@ -44,6 +44,7 @@
 import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 
 public class ActionListenerExceptionTest {
@@ -133,7 +134,11 @@
         SwingUtilities.invokeAndWait(new Runnable() {
             public void run() {
                 Object comp = combo.getUI().getAccessibleChild(combo, 0);
-                JComponent scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(0);
+                int i = 0;
+                JComponent scrollPane;
+                do {
+                    scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(i++);
+                } while (!(scrollPane instanceof JScrollPane));
 
                 menuItemHeight = scrollPane.getSize().height / TOTAL_MENU_ITEMS;
                 yPos = scrollPane.getLocationOnScreen().y + menuItemHeight / 2;
diff --git a/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java b/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java
index 5c6080c..81dfea0 100644
--- a/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java
+++ b/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java
@@ -24,10 +24,12 @@
  /*
  @test
  @key headful
- @bug 8062946
+ @bug 8062946 8159906
  @summary Verify Transparency upon iconify/deiconify sequence
  @run main TransparencyTest
  */
+import java.awt.GraphicsEnvironment;
+import java.awt.GraphicsDevice;
 import java.awt.Color;
 import java.awt.Point;
 import java.awt.Robot;
@@ -43,7 +45,7 @@
     private static final int WIDTH = 250;
     private static final int HEIGHT = 250;
     private static final float OPACITY = 0.60f;
-    private static Point dlgPos;
+    private static volatile Point dlgPos;
 
     public static void createAndShowGUI() {
         frame = new JFrame("JFrame");
@@ -67,6 +69,14 @@
 
     public static void main(String[] args) throws Exception {
 
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice gd = ge.getDefaultScreenDevice();
+        GraphicsDevice.WindowTranslucency mode = GraphicsDevice.WindowTranslucency.TRANSLUCENT;
+        boolean translucencyCheck = gd.isWindowTranslucencySupported(mode);
+        if(!translucencyCheck) {
+            return;
+    }
+
         Robot robot = new Robot();
         // create a GUI
         SwingUtilities.invokeAndWait(new Runnable() {
diff --git a/jdk/test/javax/swing/JLightweightFrame/JLightweightFrameRoundTest.java b/jdk/test/javax/swing/JLightweightFrame/JLightweightFrameRoundTest.java
new file mode 100644
index 0000000..f02bcc0
--- /dev/null
+++ b/jdk/test/javax/swing/JLightweightFrame/JLightweightFrameRoundTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8170387
+ * @summary JLightweightFrame#syncCopyBuffer() may throw IOOBE
+ * @modules java.desktop/sun.swing
+ * @run main JLightweightFrameRoundTest
+ */
+
+import sun.swing.JLightweightFrame;
+import sun.swing.LightweightContent;
+
+import javax.swing.*;
+
+public class JLightweightFrameRoundTest {
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            JLightweightFrame jLightweightFrame = new JLightweightFrame();
+            jLightweightFrame.setContent(new XLightweightContent());
+            jLightweightFrame.setSize(600, 600);
+            jLightweightFrame.notifyDisplayChanged(1.0001, 1.0001);
+        });
+    }
+
+    static class XLightweightContent implements LightweightContent {
+        @Override
+        public JComponent getComponent() {
+            return new JPanel();
+        }
+
+        @Override
+        public void paintLock() {}
+
+        @Override
+        public void paintUnlock() {}
+
+        @Override
+        public void imageBufferReset(int[] data, int x, int y, int width,
+                                     int height, int linestride,
+                                     double scaleX,
+                                     double scaleY) {}
+
+        @Override
+        public void imageReshaped(int x, int y, int width, int height) {}
+
+        @Override
+        public void imageUpdated(int dirtyX, int dirtyY, int dirtyWidth,
+                                 int dirtyHeight) {}
+
+        @Override
+        public void focusGrabbed() {}
+
+        @Override
+        public void focusUngrabbed() {}
+
+        @Override
+        public void preferredSizeChanged(int width, int height) {}
+
+        @Override
+        public void maximumSizeChanged(int width, int height) {}
+
+        @Override
+        public void minimumSizeChanged(int width, int height) {}
+    }
+}
diff --git a/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java b/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java
index 4b95dc9..a9ad28e 100644
--- a/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java
+++ b/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java
@@ -26,22 +26,31 @@
  * @key headful
  * @library ../../regtesthelpers
  * @build Util
- * @bug 8033699 8154043
+ * @bug 8033699 8154043 8167160
  * @summary  Incorrect radio button behavior when pressing tab key
- * @author Vivi An
  * @run main bug8033699
  */
-
-import javax.swing.*;
-import javax.swing.event.*;
-import java.awt.event.*;
-import java.awt.*;
+import java.awt.KeyboardFocusManager;
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
 
 public class bug8033699 {
-    private static Robot robot;
 
+    private static JFrame mainFrame;
+    private static Robot robot;
     private static JButton btnStart;
-    private static ButtonGroup btnGrp;
     private static JButton btnEnd;
     private static JButton btnMiddle;
     private static JRadioButton radioBtn1;
@@ -51,7 +60,9 @@
 
     public static void main(String args[]) throws Throwable {
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
+                changeLAF();
                 createAndShowGUI();
             }
         });
@@ -84,11 +95,30 @@
 
         // down key circle back to first button in grouped radio button
         runTest8();
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                mainFrame.dispose();
+            }
+        });
+    }
+
+    private static void changeLAF() {
+        String currentLAF = UIManager.getLookAndFeel().toString();
+        System.out.println(currentLAF);
+        currentLAF = currentLAF.toLowerCase();
+        if (currentLAF.contains("aqua") || currentLAF.contains("nimbus")) {
+            try {
+                UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        }
     }
 
     private static void createAndShowGUI() {
-        JFrame mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
-
+        mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
         btnStart = new JButton("Start");
         btnEnd = new JButton("End");
         btnMiddle = new JButton("Middle");
@@ -132,12 +162,13 @@
     }
 
     // Radio button Group as a single component when traversing through tab key
-    private static void runTest1() throws Exception{
+    private static void runTest1() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_TAB);
 
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
                     System.out.println("Radio Button Group Go To Next Component through Tab Key failed");
@@ -148,9 +179,10 @@
     }
 
     // Non-Grouped Radio button as a single component when traversing through tab key
-    private static void runTest2() throws Exception{
+    private static void runTest2() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) {
                     System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed");
@@ -161,11 +193,12 @@
     }
 
     // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key
-    private static void runTest3() throws Exception{
+    private static void runTest3() throws Exception {
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
                     System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed");
@@ -176,10 +209,11 @@
     }
 
     // Using arrow key to move focus in radio button group
-    private static void runTest4() throws Exception{
+    private static void runTest4() throws Exception {
         hitKey(robot, KeyEvent.VK_DOWN);
         hitKey(robot, KeyEvent.VK_RIGHT);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) {
                     System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed");
@@ -189,10 +223,11 @@
         });
     }
 
-    private static void runTest5() throws Exception{
+    private static void runTest5() throws Exception {
         hitKey(robot, KeyEvent.VK_UP);
         hitKey(robot, KeyEvent.VK_LEFT);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
                     System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed");
@@ -202,10 +237,11 @@
         });
     }
 
-    private static void runTest6() throws Exception{
+    private static void runTest6() throws Exception {
         hitKey(robot, KeyEvent.VK_UP);
         hitKey(robot, KeyEvent.VK_UP);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) {
                     System.out.println("Radio button Group Circle Back To First Button Test");
@@ -215,9 +251,10 @@
         });
     }
 
-    private static void runTest7() throws Exception{
+    private static void runTest7() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) {
                     System.out.println("Separate Component added in button group layout");
@@ -227,9 +264,10 @@
         });
     }
 
-    private static void runTest8() throws Exception{
+    private static void runTest8() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
                     System.out.println("Separate Component added in button group layout");
diff --git a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java
index 4c773c0..9ab19f7 100644
--- a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java
+++ b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java
@@ -42,7 +42,6 @@
 import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 import javax.swing.KeyStroke;
-import javax.swing.LookAndFeel;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
@@ -133,41 +132,19 @@
     }
 
     private static void runTestCase() throws Exception {
-        LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
         focusOn(a);
-        if (isExcludedLookAndFeel(lookAndFeel)) {
-            robot.keyPress(KeyEvent.VK_ENTER);
-            robot.keyRelease(KeyEvent.VK_ENTER);
-            robot.waitForIdle();
-            isFocusOwner(b, "forward");
-            robot.keyPress(KeyEvent.VK_SHIFT);
-            robot.keyPress(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_SHIFT);
-            robot.waitForIdle();
-            isFocusOwner(a, "backward");
 
-        } else {
+        robot.keyPress(KeyEvent.VK_ENTER);
+        robot.keyRelease(KeyEvent.VK_ENTER);
+        robot.waitForIdle();
+        isFocusOwner(next, "forward");
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.keyRelease(KeyEvent.VK_TAB);
+        robot.keyRelease(KeyEvent.VK_SHIFT);
+        robot.waitForIdle();
+        isFocusOwner(a, "backward");
 
-            robot.keyPress(KeyEvent.VK_ENTER);
-            robot.keyRelease(KeyEvent.VK_ENTER);
-            robot.waitForIdle();
-            isFocusOwner(next, "forward");
-            robot.keyPress(KeyEvent.VK_SHIFT);
-            robot.keyPress(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_SHIFT);
-            robot.waitForIdle();
-            isFocusOwner(d, "backward");
-        }
-
-    }
-
-    private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) {
-
-        return lookAndFeel.toString().toLowerCase().contains("aqua")
-                || lookAndFeel.toString().toLowerCase().contains("nimbus")
-                || lookAndFeel.toString().toLowerCase().contains("gtk");
     }
 
     private static void focusOn(Component component)
diff --git a/jdk/test/javax/swing/JTable/SorterIOOBEtest/DefaultRowSorterIOOBEtest.java b/jdk/test/javax/swing/JTable/SorterIOOBEtest/DefaultRowSorterIOOBEtest.java
new file mode 100644
index 0000000..fec0847
--- /dev/null
+++ b/jdk/test/javax/swing/JTable/SorterIOOBEtest/DefaultRowSorterIOOBEtest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8160087
+ * @summary Change IOOBE to warning in the scenarios when it had not being
+ *          thrown before the JDK-8078514
+ * @run main/othervm DefaultRowSorterIOOBEtest
+ */
+
+import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultRowSorterIOOBEtest extends TableRowSorter<TableModel> {
+    static List<String> rows = new ArrayList<>();
+
+    static TableModel tableModel = new AbstractTableModel() {
+
+        @Override
+        public int getRowCount() {
+            return rows.size();
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 1;
+        }
+
+        @Override
+        public Object getValueAt(int rowIndex, int columnIndex) {
+            return rows.get(rowIndex);
+        }
+    };
+
+    public static void main(String[] args) {
+        DefaultRowSorter<TableModel, Integer> sorter =
+            new DefaultRowSorter<>() {
+            {
+                setModelWrapper(new SorterModelWrapper());
+            }
+        };
+
+        PrintStream err = System.err;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(10000) {
+            @Override
+            public synchronized void write(byte[] b, int off, int len) {
+                super.write(b, off, len);
+                err.print(new String(b, off, len));
+            }
+        };
+        System.setErr(new PrintStream(bos));
+
+        rows.add("New");
+
+        sorter.convertRowIndexToView(0);
+        sorter.convertRowIndexToModel(0);
+
+        String out = new String(bos.toByteArray());
+        if(out.indexOf("WARNING:") < 0) {
+            throw new RuntimeException("No warnings found");
+        }
+    }
+
+    static class SorterModelWrapper extends
+                            DefaultRowSorter.ModelWrapper<TableModel, Integer> {
+
+        @Override
+        public TableModel getModel() {
+            return tableModel;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return tableModel.getColumnCount();
+        }
+
+        @Override
+        public int getRowCount() {
+            return tableModel.getRowCount();
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            return tableModel.getValueAt(row, column);
+        }
+
+        @Override
+        public Integer getIdentifier(int row) {
+            return row;
+        }
+    }
+}
diff --git a/jdk/test/javax/swing/RepaintManager/8162350/RepaintManagerFPUIScaleTest.java b/jdk/test/javax/swing/RepaintManager/8162350/RepaintManagerFPUIScaleTest.java
new file mode 100644
index 0000000..e20f3a8
--- /dev/null
+++ b/jdk/test/javax/swing/RepaintManager/8162350/RepaintManagerFPUIScaleTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/*
+ * @test
+ * @bug 8162350
+ * @summary RepaintManager shifts repainted region when the floating point UI scale is used
+ * @run main/manual/othervm -Dsun.java2d.uiScale=1.5 RepaintManagerFPUIScaleTest
+ */
+public class RepaintManagerFPUIScaleTest {
+
+    private static volatile boolean testResult = false;
+    private static volatile CountDownLatch countDownLatch;
+    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
+            + "Check JScrollPane correctly repaints the view"
+            + " when UI scale has floating point value:\n"
+            + "\n"
+            + "1. Scroll down the JScrollPane\n"
+            + "2. Select some values\n"
+            + "If the scrolled selected value is painted without artifacts,"
+            + "press PASS, else press FAIL.";
+
+    public static void main(String args[]) throws Exception {
+
+        countDownLatch = new CountDownLatch(1);
+
+        SwingUtilities.invokeLater(RepaintManagerFPUIScaleTest::createUI);
+        countDownLatch.await(15, TimeUnit.MINUTES);
+
+        if (!testResult) {
+            throw new RuntimeException("Test fails!");
+        }
+    }
+
+    private static void createUI() {
+
+        final JFrame mainFrame = new JFrame("Motif L&F icons test");
+        GridBagLayout layout = new GridBagLayout();
+        JPanel mainControlPanel = new JPanel(layout);
+        JPanel resultButtonPanel = new JPanel(layout);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+
+        JComponent testPanel = createComponent();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(testPanel, gbc);
+
+        JTextArea instructionTextArea = new JTextArea();
+        instructionTextArea.setText(INSTRUCTIONS);
+        instructionTextArea.setEditable(false);
+        instructionTextArea.setBackground(Color.white);
+
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(instructionTextArea, gbc);
+
+        JButton passButton = new JButton("Pass");
+        passButton.setActionCommand("Pass");
+        passButton.addActionListener((ActionEvent e) -> {
+            testResult = true;
+            mainFrame.dispose();
+            countDownLatch.countDown();
+
+        });
+
+        JButton failButton = new JButton("Fail");
+        failButton.setActionCommand("Fail");
+        failButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        resultButtonPanel.add(passButton, gbc);
+
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        resultButtonPanel.add(failButton, gbc);
+
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        mainControlPanel.add(resultButtonPanel, gbc);
+
+        mainFrame.add(mainControlPanel);
+        mainFrame.pack();
+
+        mainFrame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+        mainFrame.setVisible(true);
+    }
+
+    private static JComponent createComponent() {
+
+        int N = 100;
+        String[] data = new String[N];
+        for (int i = 0; i < N; i++) {
+            data[i] = "Floating point test List Item: " + i;
+        }
+        JList list = new JList(data);
+        list.setCellRenderer(new TestListCellRenderer());
+
+        JScrollPane scrollPane = new JScrollPane(list);
+        return scrollPane;
+    }
+
+    private static Color[] COLORS = {
+        Color.RED, Color.ORANGE, Color.GREEN, Color.BLUE, Color.GRAY
+    };
+
+    private static Image createTestImage(int width, int height, int colorindex) {
+
+        Color color = COLORS[colorindex % COLORS.length];
+
+        AffineTransform tx = GraphicsEnvironment
+                .getLocalGraphicsEnvironment()
+                .getDefaultScreenDevice()
+                .getDefaultConfiguration()
+                .getDefaultTransform();
+
+        Image baseImage = createTestImage(width, height, 1, 1, color);
+        Image rvImage = createTestImage(width, height, tx.getScaleX(), tx.getScaleY(), color);
+
+        return new BaseMultiResolutionImage(baseImage, rvImage);
+    }
+
+    private static Image createTestImage(int w, int h,
+            double scaleX, double scaleY, Color color) {
+
+        int width = (int) Math.ceil(scaleX * w);
+        int height = (int) Math.ceil(scaleY * h);
+        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+        Graphics2D g = img.createGraphics();
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, width, height);
+        g.scale(scaleX, scaleY);
+        g.setColor(color);
+        int d = 1;
+        int d2 = 2 * d;
+        g.drawLine(d, h / 2, w - d2, h / 2);
+        g.drawLine(w / 2, d, w / 2, h - d2);
+        g.drawRect(d, d, w - d2, h - d2);
+        g.dispose();
+
+        return img;
+    }
+
+    static class TestListCellRenderer extends DefaultListCellRenderer {
+
+        public Component getListCellRendererComponent(
+                JList list,
+                Object value,
+                int index,
+                boolean isSelected,
+                boolean cellHasFocus) {
+            Component retValue = super.getListCellRendererComponent(
+                    list, value, index, isSelected, cellHasFocus
+            );
+            setIcon(new ImageIcon(createTestImage(20, 10, index)));
+            return retValue;
+        }
+    }
+}
diff --git a/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java
index fc53de9..4504475 100644
--- a/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java
+++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java
@@ -44,20 +44,20 @@
  * @key headful
  * @summary [macos 10.12] Trackpad scrolling of text on OS X 10.12 Sierra
  *    is very fast (Trackpad, Retina only)
+ * @requires (os.family == "windows" | os.family == "mac")
  * @run main/manual/othervm TooMuchWheelRotationEventsTest
  */
 public class TooMuchWheelRotationEventsTest {
 
     private static volatile boolean testResult = false;
     private static volatile CountDownLatch countDownLatch;
-    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
-            + "Try to check the issue on Mac OS X 10.12 Sierra with trackpad"
-            + " on Retina display.\n"
+    private static final String INSTRUCTIONS = " INSTRUCTIONS:\n"
+            + " Try to check the issue with trackpad\n"
             + "\n"
-            + "If the trackpad is not supported, press PASS\n"
+            + " If the trackpad is not supported, press PASS\n"
             + "\n"
-            + "Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
-            + "If the text area is scrolled too fast press FAIL, else press PASS.";
+            + " Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
+            + " If the text area is scrolled too fast press FAIL, else press PASS.";
 
     public static void main(String args[]) throws Exception {
         countDownLatch = new CountDownLatch(1);
@@ -138,6 +138,7 @@
                 countDownLatch.countDown();
             }
         });
+        mainFrame.setLocationRelativeTo(null);
         mainFrame.setVisible(true);
     }
 
diff --git a/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java b/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java
index f6f571a..25066da 100644
--- a/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java
+++ b/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java
@@ -23,7 +23,7 @@
  */
 
 /* @test
-   @bug 6427244 8144240 8166003
+   @bug 6427244 8144240 8166003 8169879
    @summary Test that pressing HOME correctly moves caret in I18N document.
    @author Sergey Groznyh
    @library ../../../regtesthelpers
@@ -69,10 +69,12 @@
         bug6427244 t = new bug6427244();
         for (String space: SPACES) {
             t.init(space);
-            t.runAllTests();
+            t.testCaretPosition();
         }
 
         System.out.println("OK");
+        // Dispose the test interface upon completion
+        t.destroyTestInterface();
     }
 
     void init(final String space) {
@@ -113,29 +115,65 @@
         }
     }
 
-    void blockTillDisplayed(JComponent comp) {
-        if(comp != null) {
-            while (!comp.isVisible()) {
-                try {
+    void destroyTestInterface() {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    // Dispose the frame
+                    jf.dispose();
+                 }
+            });
+        } catch (Exception ex) {
+            // No-op
+        }
+    }
+
+    void blockTillDisplayed(JComponent comp) throws Exception {
+        while (comp != null && isCompVisible == false) {
+            try {
+                SwingUtilities.invokeAndWait(new Runnable() {
+                    @Override
+                    public void run() {
+                        isCompVisible = comp.isVisible();
+                     }
+                });
+
+                if (isCompVisible == false) {
+                    // A short wait for component to be visible
                     Thread.sleep(1000);
-                } catch (InterruptedException ie) {
-                    /* No-op */
                 }
+            } catch (InterruptedException ex) {
+                // No-op. Thread resumed from sleep
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
             }
         }
     }
 
     public void testCaretPosition() {
-        Point p = tp.getLocationOnScreen();
-        // the right-top corner position
-        p.x += (dim.width - 5);
-        p.y += 5;
-        ROBOT.mouseMove(p.x, p.y);
+        final Point p[] = new Point[1];
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    p[0] = tp.getLocationOnScreen();
+
+                    // the right-top corner position
+                    p[0].x += (dim.width - 5);
+                    p[0].y += 5;
+                }
+            });
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+        ROBOT.mouseMove(p[0].x, p[0].y);
         ROBOT.clickMouse();
         ROBOT.hitKey(KeyEvent.VK_HOME);
         ROBOT.waitForIdle();
         // this will fail if caret moves out of the 1st line.
         if (getCaretOrdinate() != 0) {
+            // Dispose the test interface upon completion
+            destroyTestInterface();
             throw new RuntimeException("Test Failed.");
         }
     }
@@ -162,7 +200,8 @@
         return y[0];
     }
 
-    JFrame jf;
-    JTextPane tp;
-    Dimension dim;
+    private JFrame jf;
+    private JTextPane tp;
+    private Dimension dim;
+    private volatile boolean isCompVisible = false;
 }
diff --git a/jdk/test/javax/swing/text/html/StyleSheet/bug4936917.java b/jdk/test/javax/swing/text/html/StyleSheet/bug4936917.java
new file mode 100644
index 0000000..10fe6e8
--- /dev/null
+++ b/jdk/test/javax/swing/text/html/StyleSheet/bug4936917.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/* @test
+   @bug 4936917 7190578
+   @summary  Tests if background is correctly painted when <BODY> has css margins
+   @author Denis Sharypov
+   @library ../../../regtesthelpers
+   @run main bug4936917
+*/
+
+
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.Robot;
+import java.util.Timer;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+
+public class bug4936917 {
+
+    private boolean passed = false;
+    private Timer timer;
+    private JEditorPane editorPane;
+    private static JFrame f;
+    private volatile Point p = null;
+
+    private String text =
+                "<html><head><style>" +
+                "body {background-color: #cccccc; margin-top: 36.000000pt;}" +
+                "</style></head>" +
+                "<body> some text </body></html>";
+
+    public void init() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                editorPane = new JEditorPane("text/html", "");
+                editorPane.setEditable(false);
+                editorPane.setMargin(new java.awt.Insets(0, 0, 0, 0));
+                editorPane.setText(text);
+
+                f = new JFrame();
+                f.getContentPane().add(editorPane);
+                f.setSize(600, 400);
+                f.setVisible(true);
+            }
+        });
+        blockTillDisplayed(editorPane);
+        Robot robot  = new Robot();
+        robot.waitForIdle();
+
+        int x0 = p.x + 15 ;
+        int y = p.y + 15;
+        int match = 0;
+        int nonmatch = 0;
+
+        passed = true;
+        for (int x = x0; x < x0 + 10; x++) {
+            System.out.println("color ("+x+"," + y +")=" + robot.getPixelColor(x,y));
+            if (!robot.getPixelColor(x, y).equals(new Color(0xcc, 0xcc, 0xcc))) {
+                nonmatch++;
+            } else match++;
+        }
+        if (nonmatch > match) {
+            passed = false;
+        }
+    }
+
+    void blockTillDisplayed(JComponent comp) throws Exception {
+        while (p == null) {
+            try {
+                SwingUtilities.invokeAndWait(() -> {
+                    p = comp.getLocationOnScreen();
+                });
+            } catch (IllegalStateException e) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException ie) {
+                }
+            }
+        }
+    }
+
+    public void destroy() throws Exception {
+        SwingUtilities.invokeAndWait(()->f.dispose());
+        if(!passed) {
+            throw new RuntimeException("Test failed.");
+        }
+    }
+
+
+    public static void main(String args[]) throws Exception {
+            bug4936917 test = new bug4936917();
+            test.init();
+            test.destroy();
+    }
+}
diff --git a/jdk/test/jdk/internal/misc/VM/RuntimeArguments.java b/jdk/test/jdk/internal/misc/VM/RuntimeArguments.java
index 754b2ad..f45d9f7 100644
--- a/jdk/test/jdk/internal/misc/VM/RuntimeArguments.java
+++ b/jdk/test/jdk/internal/misc/VM/RuntimeArguments.java
@@ -26,7 +26,6 @@
  * @summary Basic test of VM::getRuntimeArguments
  * @library /lib/testlibrary
  * @modules java.base/jdk.internal.misc
- *          java.compact3
  *          jdk.zipfs
  * @run testng RuntimeArguments
  */
@@ -64,11 +63,11 @@
                       "--add-modules",
                       "jdk.zipfs",
                       "--limit-modules",
-                      "java.compact3"),
+                      "java.logging,java.xml,jdk.charsets,jdk.zipfs"),
               // expected runtime arguments
               List.of("--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
                       "--add-modules=jdk.zipfs",
-                      "--limit-modules=java.compact3"),
+                      "--limit-modules=java.logging,java.xml,jdk.charsets,jdk.zipfs"),
             },
         };
     };
diff --git a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java
index cd25a49..72e3370 100644
--- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java
+++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java
@@ -24,9 +24,7 @@
 /**
  * @test
  * @summary Verify the defining class loader of each module never delegates
- *          to its child class loader. Also sanity check java.compact2
- *          requires.
- * @modules java.compact2
+ *          to its child class loader.
  * @run testng/othervm --add-modules=ALL-SYSTEM VerifyModuleDelegation
  */
 
@@ -46,21 +44,10 @@
 
 public class VerifyModuleDelegation {
     private static final String JAVA_BASE = "java.base";
-    private static final String JAVA_COMPACT1 = "java.compact1";
-    private static final String JAVA_COMPACT2 = "java.compact2";
 
     private static final ModuleDescriptor BASE
         = ModuleDescriptor.module(JAVA_BASE).build();
 
-    private static final ModuleDescriptor COMPACT2
-        = ModuleDescriptor.module(JAVA_COMPACT2)
-            .requires(Set.of(MANDATED), JAVA_BASE)
-            .requires(Set.of(TRANSITIVE), JAVA_COMPACT1)
-            .requires(Set.of(TRANSITIVE), "java.rmi")
-            .requires(Set.of(TRANSITIVE), "java.sql")
-            .requires(Set.of(TRANSITIVE), "java.xml")
-            .build();
-
     private static final Set<ModuleDescriptor> MREFS
             = Layer.boot().modules().stream().map(Module::getDescriptor)
                 .collect(toSet());
@@ -79,14 +66,6 @@
 
         check(md, BASE);
     }
-    @Test
-    public void checkCompact2() {
-        ModuleDescriptor md =
-                MREFS.stream()
-                     .filter(d -> d.name().equals(JAVA_COMPACT2))
-                     .findFirst().orElseThrow(Error::new);
-        check(md, COMPACT2);
-    }
 
     @Test
     public void checkLoaderDelegation() {
diff --git a/jdk/test/jdk/modules/incubator/DefaultImage.java b/jdk/test/jdk/modules/incubator/DefaultImage.java
new file mode 100644
index 0000000..ff6f526
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/DefaultImage.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Ensure no incubator modules are resolved by default in the image
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng DefaultImage
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class DefaultImage {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+    private static final Path CP_DIR = Paths.get("cp");
+
+    @BeforeTest
+    private void setup() throws Throwable {
+        Path src = TEST_SRC.resolve("src").resolve("cp").resolve("listmods");
+        assertTrue(CompilerUtils.compile(src, CP_DIR));
+    }
+
+    public void test() throws Throwable {
+        if (isExplodedBuild()) {
+            System.out.println("Test cannot run on exploded build");
+            return;
+        }
+
+        java("-cp", CP_DIR.toString(),
+             "listmods.ListModules")
+            .assertSuccess()
+            .resultChecker(r -> r.assertOutputContains("java.base"))
+            .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+    }
+
+    @DataProvider(name = "tokens")
+    public Object[][] singleModuleValues() throws IOException {
+        return new Object[][]{ { "ALL-DEFAULT" }, { "ALL-SYSTEM"} };
+    }
+
+    @Test(dataProvider = "tokens")
+    public void testAddMods(String addModsToken) throws Throwable {
+        if (isExplodedBuild()) {
+            System.out.println("Test cannot run on exploded build");
+            return;
+        }
+
+        java("--add-modules", addModsToken,
+             "-cp", CP_DIR.toString(),
+             "listmods.ListModules")
+            .assertSuccess()
+            .resultChecker(r -> r.assertOutputContains("java.base"))
+            .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+    }
+
+    static ToolResult java(String... opts) throws Throwable {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        String[] options = Stream.concat(Stream.of(getJava()), Stream.of(opts))
+                .toArray(String[]::new);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        int exitValue = executeCommand(pb).outputTo(ps)
+                .errorTo(ps)
+                .getExitValue();
+
+        return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class ToolResult {
+        final int exitCode;
+        final String output;
+
+        ToolResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+
+        ToolResult assertSuccess() {
+            assertEquals(exitCode, 0,
+                    "Expected exit code 0, got " + exitCode
+                            + ", with output[" + output + "]");
+            return this;
+        }
+
+        ToolResult resultChecker(Consumer<ToolResult> r) {
+            r.accept(this);
+            return this;
+        }
+
+        ToolResult assertOutputContains(String subString) {
+            assertTrue(output.contains(subString),
+                       "Expected to find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+
+        ToolResult assertOutputDoesNotContain(String subString) {
+            assertFalse(output.contains(subString),
+                        "Expected to NOT find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+    }
+
+    static String getJava() {
+        Path image = Paths.get(JAVA_HOME);
+        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+        Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+        if (Files.notExists(java))
+            throw new RuntimeException(java + " not found");
+        return java.toAbsolutePath().toString();
+    }
+
+    static boolean isExplodedBuild() {
+        Path modulesPath = Paths.get(JAVA_HOME).resolve("lib").resolve("modules");
+        return Files.notExists(modulesPath);
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/ImageModules.java b/jdk/test/jdk/modules/incubator/ImageModules.java
new file mode 100644
index 0000000..347b1d4
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/ImageModules.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Basic test for incubator modules in jmods and images
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jartool jdk.jlink
+ * @build CompilerUtils
+ * @run testng/othervm ImageModules
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class ImageModules {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods");
+
+    private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path CP_DIR = Paths.get("cp");
+    private static final Path JARS_DIR = Paths.get("jars");
+    private static final Path JMODS_DIR = Paths.get("jmods");
+    private static final Path IMAGE = Paths.get("image");
+
+    private static final String JAVA_BASE = "java.base";
+    private final String[] modules = new String[] { "message.writer",
+                                                    "message.converter" };
+
+    @BeforeTest
+    private void setup() throws Throwable {
+        Path src = TEST_SRC.resolve("src");
+        for (String name : modules) {
+            assertTrue(CompilerUtils.compile(src.resolve(name),
+                                             MODS_DIR,
+                                             "--module-source-path", src.toString()));
+        }
+
+        assertTrue(CompilerUtils.compile(src.resolve("cp"),
+                                         CP_DIR,
+                                         "--module-path", MODS_DIR.toString(),
+                                         "--add-modules", "message.writer"));
+    }
+
+    @DataProvider(name = "singleModule")
+    public Object[][] singleModuleValues() throws IOException {
+        Object[][] values = new Object[][]{
+         // { Extra args to the build the message.converter jmod
+         //   Tokens to pass to the run time --add-modules option
+         //   SUCCESS or FAILURE expected
+         //   Messages expected in the run time output
+         //   Messages that must not appear in the run time output },
+            { "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base"),
+              List.of("WARNING") },
+            { "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+              List.of("WARNING", "message.converter") },
+            { "--warn-if-resolved=incubating",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.converter"),
+              List.of() },
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+              List.of("WARNING", "message.converter") },
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("message.converter"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base", "WARNING"),
+              List.of() }
+        };
+        return values;
+    }
+
+    @Test(dataProvider = "singleModule")
+    public void singleModule(String extraJmodArg,
+                             List<String> addModsTokens,
+                             Consumer<ToolResult> assertExitCode,
+                             List<String> expectedOutput,
+                             List<String> unexpectedOutput)
+        throws Throwable
+    {
+        if (Files.notExists(JDK_JMODS)) {
+            System.out.println("JDK jmods not found test cannot run.");
+            return;
+        }
+
+        FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+        FileUtils.deleteFileTreeUnchecked(IMAGE);
+        Files.createDirectories(JMODS_DIR);
+        Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+        jmod("create",
+             "--class-path", MODS_DIR.resolve("message.converter").toString(),
+             extraJmodArg,
+             converterJmod.toString())
+            .assertSuccess();
+
+        String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+        jlink("--module-path", mpath,
+              "--add-modules", JAVA_BASE + ",message.converter",
+              "--output", IMAGE.toString())
+             .assertSuccess();
+
+        for (String addModsToken : addModsTokens) {
+            String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+            for (String systemProp : props)
+                java(IMAGE,
+                     systemProp,
+                     "--add-modules", addModsToken,
+                     "-cp", CP_DIR.toString(),
+                     "test.ConvertToLowerCase", "HEllo WoRlD")
+                    .resultChecker(assertExitCode)
+                    .resultChecker(r -> {
+                        expectedOutput.forEach(e -> r.assertContains(e));
+                        unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+                    });
+        }
+    }
+
+    @Test
+    public void singleModularJar() throws Throwable {
+        FileUtils.deleteFileTreeUnchecked(JARS_DIR);
+        Files.createDirectories(JARS_DIR);
+        Path converterJar = JARS_DIR.resolve("converter.jar");
+
+        jar("--create",
+            "--file", converterJar.toString(),
+            "--warn-if-resolved=incubating",
+            "-C", MODS_DIR.resolve("message.converter").toString() , ".")
+            .assertSuccess();
+
+
+        java(Paths.get(JAVA_HOME),
+             "--module-path", JARS_DIR.toString(),
+             "--add-modules", "message.converter",
+             "-cp", CP_DIR.toString(),
+             "test.ConvertToLowerCase", "HEllo WoRlD")
+            .assertSuccess()
+            .resultChecker(r -> {
+                r.assertContains("WARNING: Using incubator modules: message.converter");
+            });
+    }
+
+    @DataProvider(name = "twoModules")
+    public Object[][] twoModulesValues() throws IOException {
+        Object[][] values = new Object[][]{
+         // { Extra args to the build the message.writer jmod
+         //   Extra args to the build the message.converter jmod
+         //   Tokens to pass to the run time --add-modules option
+         //   SUCCESS or FAILURE expected
+         //   Messages expected in the run time output
+         //   Messages that must not appear in the run time output },
+            { "",
+              "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+              List.of() },
+            { "",
+              "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+              List.of() },
+            { "--do-not-resolve-by-default",
+              "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+              List.of("message.writer") },
+            { "--do-not-resolve-by-default",
+              "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+              List.of("message.converter", "message.writer") },
+        // now add in warnings
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              "",
+              List.of("message.writer"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.writer"),
+              List.of() },
+            { "",
+              "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("message.writer"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.converter"),
+              List.of() } };
+        return values;
+    }
+
+    @Test(dataProvider = "twoModules")
+    public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg,
+                                                String extraSecondJmodArg,
+                                                List<String> addModsTokens,
+                                                Consumer<ToolResult> assertExitCode,
+                                                List<String> expectedOutput,
+                                                List<String> unexpectedOutput)
+        throws Throwable
+    {
+        if (Files.notExists(JDK_JMODS)) {
+            System.out.println("JDK jmods not found test cannot run.");
+            return;
+        }
+
+        FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+        FileUtils.deleteFileTreeUnchecked(IMAGE);
+        Files.createDirectories(JMODS_DIR);
+        Path writerJmod = JMODS_DIR.resolve("writer.jmod");
+        Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+        jmod("create",
+             extraFirstJmodArg,
+             "--class-path", MODS_DIR.resolve("message.writer").toString(),
+             writerJmod.toString());
+
+        jmod("create",
+             "--class-path", MODS_DIR.resolve("message.converter").toString(),
+             extraSecondJmodArg,
+             converterJmod.toString())
+            .assertSuccess();
+
+        String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+        jlink("--module-path", mpath,
+              "--add-modules", JAVA_BASE + ",message.writer,message.converter",
+              "--output", IMAGE.toString())
+             .assertSuccess();
+
+        for (String addModsToken : addModsTokens) {
+            String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+            for (String systemProp : props)
+                java(IMAGE,
+                     systemProp,
+                     "--add-modules", addModsToken,
+                     "-cp", CP_DIR.toString(),
+                     "test.WriteUpperCase", "hello chegar !!!")
+                    .resultChecker(assertExitCode)
+                    .resultChecker(r -> {
+                        expectedOutput.forEach(e -> r.assertContains(e));
+                        unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+                    });
+        }
+    }
+
+    static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
+            .orElseThrow(() -> new RuntimeException("jmod tool not found"));
+    static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+            .orElseThrow(() -> new RuntimeException("jar tool not found"));
+    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+            .orElseThrow(() -> new RuntimeException("jlink tool not found"));
+
+    static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); }
+
+    static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); }
+
+    static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); }
+
+    static ToolResult java(Path image, String... opts) throws Throwable {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        String[] options = Stream.concat(Stream.of(getJava(image)),
+                                         Stream.of(opts).filter(s -> !s.equals("")))
+                                 .toArray(String[]::new);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        int exitValue = executeCommand(pb).outputTo(ps)
+                                          .errorTo(ps)
+                                          .getExitValue();
+
+        return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static ToolResult execTool(ToolProvider tool, String... args) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        List<String> filteredArgs = Stream.of(args)
+                                          .map(s -> s.split(" ")).flatMap(Stream::of)
+                                          .filter(s -> !s.equals(""))
+                                          .collect(Collectors.toList());
+        System.out.println(tool + " " + filteredArgs);
+        int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {}));
+        return new ToolResult(ec, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class ToolResult {
+        final int exitCode;
+        final String output;
+
+        ToolResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+
+        static Consumer<ToolResult> ASSERT_SUCCESS = r ->
+            assertEquals(r.exitCode, 0,
+                        "Expected exit code 0, got " + r.exitCode
+                                + ", with output[" + r.output + "]");
+        static Consumer<ToolResult> ASSERT_FAILURE = r ->
+            assertNotEquals(r.exitCode, 0,
+                           "Expected exit code != 0, got " + r.exitCode
+                                   + ", with output[" + r.output + "]");
+
+        ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; }
+        ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; }
+        ToolResult resultChecker(Consumer<ToolResult> r) { r.accept(this); return this; }
+
+        ToolResult assertContains(String subString) {
+            assertTrue(output.contains(subString),
+                       "Expected to find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+        ToolResult assertDoesNotContains(String subString) {
+            assertFalse(output.contains(subString),
+                       "Expected to NOT find [" + subString + "], in output ["
+                           + output + "]" + "\n");
+            return this;
+        }
+    }
+
+    static String getJava(Path image) {
+        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+        Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+        if (Files.notExists(java))
+            throw new RuntimeException(java + " not found");
+        return java.toAbsolutePath().toString();
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/src/cp/listmods/ListModules.java b/jdk/test/jdk/modules/incubator/src/cp/listmods/ListModules.java
new file mode 100644
index 0000000..2d80d19
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/cp/listmods/ListModules.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package listmods;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ListModules {
+    public static void main(String[] args) throws Exception {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java b/jdk/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java
new file mode 100644
index 0000000..cf0d1c7
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ConvertToLowerCase {
+    public static void main(String[] args) {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+        System.out.println(converter.MessageConverter.toLowerCase(args[0]));
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java b/jdk/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java
new file mode 100644
index 0000000..844fccb
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class WriteUpperCase {
+    public static void main(String[] args) {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+        writer.MessageWriter.writeOn(args[0], System.out);
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/src/message.converter/converter/MessageConverter.java b/jdk/test/jdk/modules/incubator/src/message.converter/converter/MessageConverter.java
new file mode 100644
index 0000000..d9604df
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/converter/MessageConverter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package converter;
+
+public class MessageConverter {
+    public static String toUpperCase(String message) {
+        return message.toUpperCase(java.util.Locale.ROOT);
+    }
+
+    public static String toLowerCase(String message) {
+        return message.toLowerCase(java.util.Locale.ROOT);
+    }
+}
diff --git a/jdk/test/jdk/modules/incubator/src/message.converter/module-info.java b/jdk/test/jdk/modules/incubator/src/message.converter/module-info.java
new file mode 100644
index 0000000..6fbfa70
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/module-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module message.converter {
+    exports converter;
+}
diff --git a/jdk/test/jdk/modules/incubator/src/message.writer/module-info.java b/jdk/test/jdk/modules/incubator/src/message.writer/module-info.java
new file mode 100644
index 0000000..09370cc
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/module-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module message.writer {
+    requires message.converter;
+    exports writer;
+}
diff --git a/jdk/test/jdk/modules/incubator/src/message.writer/writer/MessageWriter.java b/jdk/test/jdk/modules/incubator/src/message.writer/writer/MessageWriter.java
new file mode 100644
index 0000000..0c6ba17
--- /dev/null
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/writer/MessageWriter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package writer;
+
+import java.io.PrintStream;
+import java.util.Locale;
+
+public class MessageWriter {
+    public static void writeOn(String message, PrintStream out) {
+        String newMesssage = converter.MessageConverter.toUpperCase(message);
+        if (!newMesssage.equals(message.toUpperCase(Locale.ROOT)))
+            throw new RuntimeException("Expected " + message.toUpperCase(Locale.ROOT)
+                                       + ", got " + newMesssage );
+
+        out.println(newMesssage);
+    }
+}
diff --git a/jdk/test/lib/testlibrary/ModuleSourceBuilder.java b/jdk/test/lib/testlibrary/ModuleSourceBuilder.java
new file mode 100644
index 0000000..3d11649
--- /dev/null
+++ b/jdk/test/lib/testlibrary/ModuleSourceBuilder.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Utility class for creating test modules.
+ */
+public class ModuleSourceBuilder {
+    private static String MODULE_INFO_JAVA = "module-info.java";
+    private static Pattern MODULE_PATTERN =
+        Pattern.compile("module\\s+((?:\\w+\\.)*)");
+    private static Pattern PACKAGE_PATTERN =
+                       Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))");
+    private static Pattern CLASS_PATTERN =
+          Pattern.compile("(?:public\\s+)?(?:class|enum|interface)\\s+(\\w+)");
+
+    private final Path dir;
+    public ModuleSourceBuilder(Path dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * Create java source files of the given module
+     */
+    public void writeJavaFiles(String module, String moduleInfoJava, String... contents)
+        throws IOException
+    {
+        Path msrc = dir.resolve(module);
+        new JavaSource(moduleInfoJava).write(msrc);
+        for (String c : contents) {
+            new JavaSource(c).write(msrc);
+        }
+    }
+
+    /**
+     * Compile the module to the given destination.
+     */
+    public void compile(String module, Path dest, String... options)
+        throws IOException
+    {
+        Path msrc = dir.resolve(module);
+        Stream<String> args =
+            Stream.concat(Arrays.stream(options),
+                          Stream.of("--module-source-path",
+                                    dir.toString()));
+        assertTrue(CompilerUtils.compile(msrc, dest, args.toArray(String[]::new)),
+                   "Fail to compile " + module);
+    }
+
+    static class JavaSource {
+        final String source;
+        JavaSource(String source) {
+            this.source = source;
+        }
+
+        /**
+         * Writes the source code to a file in a specified directory.
+         * @param dir the directory
+         * @throws IOException if there is a problem writing the file
+         */
+        public void write(Path dir) throws IOException {
+            Path file = dir.resolve(getJavaFileNameFromSource(source));
+            Files.createDirectories(file.getParent());
+            try (BufferedWriter out = Files.newBufferedWriter(file)) {
+                out.write(source.replace("\n", System.lineSeparator()));
+            }
+        }
+
+        /**
+         * Extracts the Java file name from the class declaration.
+         * This method is intended for simple files and uses regular expressions,
+         * so comments matching the pattern can make the method fail.
+         */
+        static String getJavaFileNameFromSource(String source) {
+            String packageName = null;
+
+            Matcher matcher = MODULE_PATTERN.matcher(source);
+            if (matcher.find())
+                return MODULE_INFO_JAVA;
+
+            matcher = PACKAGE_PATTERN.matcher(source);
+            if (matcher.find())
+                packageName = matcher.group(1).replace(".", "/");
+
+            matcher = CLASS_PATTERN.matcher(source);
+            if (matcher.find()) {
+                String className = matcher.group(1) + ".java";
+                return (packageName == null) ? className : packageName + "/" + className;
+            } else if (packageName != null) {
+                return packageName + "/package-info.java";
+            } else {
+                throw new Error("Could not extract the java class " +
+                    "name from the provided source");
+            }
+        }
+    }
+}
diff --git a/jdk/test/lib/testlibrary/ModuleUtils.java b/jdk/test/lib/testlibrary/ModuleUtils.java
index c227464..b3c9d5e 100644
--- a/jdk/test/lib/testlibrary/ModuleUtils.java
+++ b/jdk/test/lib/testlibrary/ModuleUtils.java
@@ -32,7 +32,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Supplier;
 
 
 /**
@@ -58,12 +57,13 @@
 
             URI uri = URI.create("module:/" + name);
 
-            Supplier<ModuleReader> supplier = () -> {
-                throw new UnsupportedOperationException();
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException();
+                }
             };
 
-            ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-
             namesToReference.put(name, mref);
         }
 
diff --git a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java
index 482e93e..0a27bf7 100644
--- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java
+++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java
@@ -56,8 +56,6 @@
     private static final  String TEST_SRC = System.getProperty("test.src");
     private static final  String OSNAME = System.getProperty("os.name");
     private static final  String ARCH;
-    private static final  String LIBARCH;
-
     static {
         // magic with os.arch
         String osarch = System.getProperty("os.arch");
@@ -84,7 +82,6 @@
                 ARCH = osarch;
             }
         }
-        LIBARCH = ARCH.equals("i586") ? "i386" : ARCH;
     }
 
     public static void main(String[] args) throws Exception {
@@ -184,15 +181,12 @@
     }
 
     private static Path findLibjvm(FileSystem FS) {
-        Path libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "jre", "lib", LIBARCH));
-        if (libjvmPath == null) {
-            libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "lib", LIBARCH));
-        }
+        Path libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "lib"));
         return libjvmPath;
     }
 
     private static Path findLibjvm(Path libPath) {
-        // ARCH/libjvm.so -> ARCH/server/libjvm.so -> ARCH/client/libjvm.so
+        // libjvm.so -> server/libjvm.so -> client/libjvm.so
         Path libjvmPath = libPath.resolve("libjvm.so");
         if (isFileOk(libjvmPath)) {
             return libjvmPath;
diff --git a/jdk/test/sun/misc/InvokeCleaner.java b/jdk/test/sun/misc/InvokeCleaner.java
new file mode 100644
index 0000000..3367d15
--- /dev/null
+++ b/jdk/test/sun/misc/InvokeCleaner.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8171377
+ * @summary Basic test for Unsafe::invokeCleaner
+ * @modules jdk.unsupported
+ * @run testng/othervm InvokeCleaner
+ */
+
+import java.io.Closeable;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import sun.misc.Unsafe;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+public class InvokeCleaner {
+
+    static Unsafe UNSAFE;
+    static Path bob = Paths.get("bob");
+    static List<Closeable> closeables = new ArrayList<>();
+
+    @BeforeClass
+    static void init() throws Exception {
+        UNSAFE = getUnsafe();
+
+        byte[] srcData = new byte[20];
+        for (int i=0; i<20; i++)
+            srcData[i] = (byte)i;
+        Files.write(bob, srcData);
+    }
+
+    @DataProvider(name = "badBuffers")
+    static Object[][] createBadBuffers() throws Exception {
+        FileChannel fc = FileChannel.open(bob);
+        closeables.add(fc);
+        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+
+        return new Object[][] {
+                { ByteBuffer.allocate(0) },
+                { ByteBuffer.allocate(10) },
+                { ByteBuffer.allocate(10).duplicate() },
+                { ByteBuffer.allocate(10).slice() },
+                { ByteBuffer.allocateDirect(10).duplicate() },
+                { ByteBuffer.allocateDirect(10).slice() },
+                { ByteBuffer.allocateDirect(0).duplicate() },
+                { ByteBuffer.allocateDirect(0).slice() },
+                { mbb.duplicate() },
+                { mbb.slice() }
+        };
+    }
+
+    @Test(dataProvider="badBuffers",
+          expectedExceptions = IllegalArgumentException.class)
+    public void badBuffers(ByteBuffer buffer) throws Exception {
+        UNSAFE.invokeCleaner(buffer);
+    }
+
+    @DataProvider(name = "goodBuffers")
+    static Object[][] createGoodBuffers() throws Exception {
+        FileChannel fc = FileChannel.open(bob);
+        closeables.add(fc);
+        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+        mbb.load();
+
+        return new Object[][] {
+                { ByteBuffer.allocateDirect(0) },
+                { ByteBuffer.allocateDirect(10) },
+                { mbb },
+                { fc.map(FileChannel.MapMode.READ_ONLY, 1, 11) }
+        };
+    }
+
+    @Test(dataProvider="goodBuffers")
+    public void goodBuffers(ByteBuffer buffer) throws Exception {
+        UNSAFE.invokeCleaner(buffer);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void npe() throws Exception {
+        UNSAFE.invokeCleaner(null);
+    }
+
+    static Unsafe getUnsafe() throws ReflectiveOperationException {
+        Field f = Unsafe.class.getDeclaredField("theUnsafe");
+        f.setAccessible(true);
+        return (Unsafe)f.get(null);
+    }
+
+    @AfterClass
+    public void cleanup() throws Exception {
+        for(Closeable fc : closeables)
+            fc.close();
+    }
+}
diff --git a/jdk/test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java b/jdk/test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java
index 6e5a9bc..4672fb6 100644
--- a/jdk/test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java
+++ b/jdk/test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java
@@ -43,6 +43,7 @@
 import java.io.OutputStreamWriter;
 import java.net.HttpURLConnection;
 import java.net.URL;
+
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocket;
@@ -70,6 +71,8 @@
 
     @Override
     protected void runServerApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        sslIS.read();
         BufferedWriter bw = new BufferedWriter(
                 new OutputStreamWriter(socket.getOutputStream()));
         bw.write("HTTP/1.1 200 OK\r\n\r\n\r\n");
diff --git a/jdk/test/sun/rmi/rmic/newrmic/equivalence/AppleUserImpl.java b/jdk/test/sun/rmi/rmic/newrmic/equivalence/AppleUserImpl.java
index ee34213..ca31273 100644
--- a/jdk/test/sun/rmi/rmic/newrmic/equivalence/AppleUserImpl.java
+++ b/jdk/test/sun/rmi/rmic/newrmic/equivalence/AppleUserImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -253,7 +253,7 @@
             int port = -1;
             // create new registry and bind new AppleUserImpl in registry
             try {
-                Registry registry = TestLibrary.createRegistryOnUnusedPort();
+                Registry registry = TestLibrary.createRegistryOnEphemeralPort();
                 port = TestLibrary.getRegistryPort(registry);
                 Naming.rebind("rmi://localhost:" + port + "/AppleUser",user);
             } catch (RemoteException e) {
diff --git a/jdk/test/sun/rmi/runtime/Log/checkLogging/CheckLogging.java b/jdk/test/sun/rmi/runtime/Log/checkLogging/CheckLogging.java
index dc23b48..2b3d2d5 100644
--- a/jdk/test/sun/rmi/runtime/Log/checkLogging/CheckLogging.java
+++ b/jdk/test/sun/rmi/runtime/Log/checkLogging/CheckLogging.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,7 +103,7 @@
     private static Registry registry;
     static {
         try {
-            registry = TestLibrary.createRegistryOnUnusedPort();
+            registry = TestLibrary.createRegistryOnEphemeralPort();
             REGISTRY_PORT = TestLibrary.getRegistryPort(registry);
             LOCATION = "rmi://localhost:" + REGISTRY_PORT + "/";
         } catch (Exception e) {
diff --git a/jdk/test/sun/security/ec/TestEC.java b/jdk/test/sun/security/ec/TestEC.java
index c82e1fd..93ad04e 100644
--- a/jdk/test/sun/security/ec/TestEC.java
+++ b/jdk/test/sun/security/ec/TestEC.java
@@ -34,8 +34,8 @@
  * @library ../pkcs11/ec
  * @library ../pkcs11/sslecc
  * @library ../../../java/security/testlibrary
- * @modules jdk.crypto.pkcs11/sun.security.pkcs11.wrapper
- * @compile --add-modules jdk.crypto.pkcs11 TestEC.java
+ * @modules jdk.crypto.token/sun.security.pkcs11.wrapper
+ * @compile --add-modules jdk.crypto.token TestEC.java
  * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC
  * @run main/othervm/java.security.policy=TestEC.policy -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC
  */
diff --git a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
index 2ef3765..55f2d1a 100644
--- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
+++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
@@ -23,17 +23,12 @@
 
 /*
  * @test
- * @bug 6578647 6829283
- * @modules java.base/sun.security.util
- *          java.security.jgss/sun.security.jgss
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ktab
+ * @bug 6578647 6829283 8171340
  * @run main/othervm HttpNegotiateServer
- * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
- * @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
+ * @summary Undefined requesting URL in java.net.Authenticator
+ *          .getPasswordAuthentication()
+ * @summary HTTP/Negotiate: Authenticator triggered again when
+ *          user cancels the first one
  */
 
 import com.sun.net.httpserver.Headers;
@@ -247,16 +242,15 @@
         java.net.Authenticator.setDefault(new KnowAllAuthenticator());
 
         reader = new BufferedReader(new InputStreamReader(
-                webUrl.openConnection().getInputStream()));
+                webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
         if (!reader.readLine().equals(CONTENT)) {
             throw new RuntimeException("Bad content");
         }
 
         reader = new BufferedReader(new InputStreamReader(
-                proxyUrl.openConnection(
-                new Proxy(Proxy.Type.HTTP,
-                    new InetSocketAddress(PROXY_HOST, proxyPort)))
-                .getInputStream()));
+                proxyUrl.openConnection(new Proxy(Proxy.Type.HTTP,
+                                new InetSocketAddress(PROXY_HOST, proxyPort)))
+                        .getInputStream()));
         if (!reader.readLine().equals(CONTENT)) {
             throw new RuntimeException("Bad content");
         }
@@ -267,7 +261,7 @@
         java.net.Authenticator.setDefault(new KnowNothingAuthenticator());
         try {
             new BufferedReader(new InputStreamReader(
-                    webUrl.openConnection().getInputStream()));
+                    webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
         } catch (IOException ioe) {
             // Will fail since no username and password is provided.
         }
@@ -281,7 +275,7 @@
         try {
             URL url = webUrl;
 
-            URLConnection conn = url.openConnection();
+            URLConnection conn = url.openConnection(Proxy.NO_PROXY);
             conn.connect();
             inputStream = conn.getInputStream();
             byte[] b = new byte[inputStream.available()];
@@ -292,7 +286,7 @@
             System.out.println("Length: " + s.length());
             System.out.println(s);
         } catch (Exception ex) {
-              throw new RuntimeException(ex);
+            throw new RuntimeException(ex);
         } finally {
             if (inputStream != null) {
                 try {
@@ -314,7 +308,8 @@
 
         CallbackHandler callback = new CallbackHandler() {
             @Override
-            public void handle(Callback[] pCallbacks) throws IOException, UnsupportedCallbackException {
+            public void handle(Callback[] pCallbacks)
+                    throws IOException, UnsupportedCallbackException {
                 for (Callback cb : pCallbacks) {
                     if (cb instanceof NameCallback) {
                         NameCallback ncb = (NameCallback)cb;
@@ -330,7 +325,8 @@
         };
 
         final String jaasConfigName = "oracle.test.kerberos.login";
-        final String krb5LoginModule = "com.sun.security.auth.module.Krb5LoginModule";
+        final String krb5LoginModule
+                = "com.sun.security.auth.module.Krb5LoginModule";
 
         Configuration loginConfig = new Configuration() {
             @Override
@@ -354,7 +350,8 @@
         // oracle context/subject/login
         LoginContext context = null;
         try {
-            context = new LoginContext("oracle.test.kerberos.login", null, callback, loginConfig);
+            context = new LoginContext(
+                    "oracle.test.kerberos.login", null, callback, loginConfig);
             context.login();
 
         } catch (LoginException ex) {
@@ -365,29 +362,35 @@
 
         Subject subject = context.getSubject();
 
-        final PrivilegedExceptionAction<Object> test_action = new PrivilegedExceptionAction<Object>() {
+        final PrivilegedExceptionAction<Object> test_action
+                = new PrivilegedExceptionAction<Object>() {
             public Object run() throws Exception {
                 testConnect();
                 return null;
             }
         };
 
-        System.err.println("\n\nExpecting to succeed when executing with the the logged in subject.");
+        System.err.println("\n\nExpecting to succeed when executing " +
+                "with the the logged in subject.");
 
         try {
             Subject.doAs(subject, test_action);
-            System.err.println("\n\nConnection succeed when executing with the the logged in subject.");
+            System.err.println("\n\nConnection succeed when executing " +
+                    "with the the logged in subject.");
         } catch (PrivilegedActionException e) {
-            System.err.println("\n\nFailure unexpected when executing with the the logged in subject.");
+            System.err.println("\n\nFailure unexpected when executing " +
+                    "with the the logged in subject.");
             e.printStackTrace();
             throw new RuntimeException("Failed to login as subject");
         }
 
         try {
-            System.err.println("\n\nExpecting to fail when running with the current user's login.");
+            System.err.println("\n\nExpecting to fail when running " +
+                    "with the current user's login.");
             testConnect();
         } catch (Exception ex) {
-            System.err.println("\nConnect failed when running with the current user's login:\n" + ex.getMessage());
+            System.err.println("\nConnect failed when running " +
+                    "with the current user's login:\n" + ex.getMessage());
         }
     }
 
@@ -457,8 +460,9 @@
                     return m.createCredential(
                             null,
                             GSSCredential.INDEFINITE_LIFETIME,
-                            MyServerAuthenticator.this.scheme.equalsIgnoreCase("Negotiate")?
-                                    GSSUtil.GSS_SPNEGO_MECH_OID:
+                            MyServerAuthenticator.this.scheme
+                                        .equalsIgnoreCase("Negotiate") ?
+                                    GSSUtil.GSS_SPNEGO_MECH_OID :
                                     GSSUtil.GSS_KRB5_MECH_OID,
                             GSSCredential.ACCEPT_ONLY);
                 }
@@ -472,7 +476,8 @@
             GSSContext c = null;
             String auth = exch.getRequestHeaders().getFirst(respHdr);
             try {
-                c = (GSSContext)exch.getHttpContext().getAttributes().get("GSSContext");
+                c = (GSSContext)exch.getHttpContext()
+                        .getAttributes().get("GSSContext");
                 if (auth == null) {                 // First request
                     Headers map = exch.getResponseHeaders();
                     map.set (reqHdr, scheme);        // Challenge!
@@ -485,7 +490,8 @@
                     exch.getHttpContext().getAttributes().put("GSSContext", c);
                     return new com.sun.net.httpserver.Authenticator.Retry(err);
                 } else {                            // Later requests
-                    byte[] token = Base64.getMimeDecoder().decode(auth.split(" ")[1]);
+                    byte[] token = Base64.getMimeDecoder()
+                            .decode(auth.split(" ")[1]);
                     token = c.acceptSecContext(token, 0, token.length);
                     Headers map = exch.getResponseHeaders();
                     map.set (reqHdr, scheme + " " + Base64.getMimeEncoder()
diff --git a/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java b/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java
index 72dbb72..643134b 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ReinitCipher
  * @run main/othervm ReinitCipher sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java b/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java
index 49880d3..7804116 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java
@@ -27,7 +27,7 @@
  * @summary Test internal PKCS5Padding impl with various error conditions.
  * @author Valerie Peng
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestPKCS5PaddingError
  * @run main/othervm TestPKCS5PaddingError sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java
index 160ce1c..abf5818 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestRSACipher
  * @run main/othervm TestRSACipher sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java
index 4e4fb60..d1c5485 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java
@@ -27,7 +27,7 @@
  * @summary basic test for RSA cipher key wrapping functionality
  * @author Valerie Peng
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestRSACipherWrap
  * @run main/othervm TestRSACipherWrap sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java b/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java
index ed85f31..7444c76 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java
@@ -28,7 +28,7 @@
  * @author Valerie Peng
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestRawRSACipher
  * @run main/othervm TestRawRSACipher sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java
index e94c61d..3ba5dab 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java
@@ -28,7 +28,7 @@
  * @author Valerie Peng
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestSymmCiphers
  * @run main/othervm TestSymmCiphers sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java
index 4fc7d7b..f96c4a0 100644
--- a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java
@@ -28,7 +28,7 @@
  * @author Valerie Peng
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestSymmCiphersNoPad
  * @run main/othervm TestSymmCiphersNoPad sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java b/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java
index 52b6989..7e3ceae 100644
--- a/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java
+++ b/jdk/test/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java
@@ -26,7 +26,7 @@
  * @bug 8072452
  * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm SupportedDHKeys
  * @run main/othervm SupportedDHKeys sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java
index c43dc08..18a526d 100644
--- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java
+++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java
@@ -27,7 +27,7 @@
  * @summary Verify that DH works properly
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestDH
  * @run main/othervm TestDH sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java
index 4834b76..d231efd 100644
--- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java
+++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java
@@ -26,7 +26,7 @@
  * @bug 7146728
  * @summary Interop test for DH with secret that has a leading 0x00 byte
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestInterop
  * @run main/othervm TestInterop sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java
index f082fee..687daff 100644
--- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java
+++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java
@@ -27,7 +27,7 @@
  * @summary KAT test for DH (normal and with secret that has leading a 0x00 byte)
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestShort
  * @run main/othervm TestShort sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java b/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java
index cdfa887..df0853c 100644
--- a/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java
+++ b/jdk/test/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java
@@ -26,7 +26,7 @@
  * @bug 8072452
  * @summary Support DHE sizes up to 8192-bits and DSA sizes up to 3072-bits
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm UnsupportedDHKeys
  * @run main/othervm UnsupportedDHKeys sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java b/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java
index 9e2b6da..3b5d831 100644
--- a/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java
+++ b/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm DESParity
  * @run main/othervm DESParity sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java b/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java
index f529739..ee2ccaa 100644
--- a/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java
+++ b/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java
@@ -27,7 +27,7 @@
  * @summary test the KeyGenerator
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestKeyGenerator
  * @run main/othervm TestKeyGenerator sm
  */
diff --git a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java
index f5a0a10..4c04226 100644
--- a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java
+++ b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java
@@ -27,7 +27,7 @@
  * @summary Ensure that DH key pairs can be generated for 512 - 8192 bits
  * @author Valerie Peng
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestDH2048
  * @run main/othervm TestDH2048 sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Mac/MacKAT.java b/jdk/test/sun/security/pkcs11/Mac/MacKAT.java
index c068ac0..0894ea9 100644
--- a/jdk/test/sun/security/pkcs11/Mac/MacKAT.java
+++ b/jdk/test/sun/security/pkcs11/Mac/MacKAT.java
@@ -27,7 +27,7 @@
  * @summary Basic known-answer-test for Hmac algorithms
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm MacKAT
  * @run main/othervm MacKAT sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java b/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java
index c1ee2ec..818f173 100644
--- a/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java
+++ b/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java
@@ -27,7 +27,7 @@
  * @summary Check if doFinal and update operation result in same Mac
  * @author Yu-Ching Valerie Peng, Bill Situ, Alexander Fomin
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm MacSameTest
  * @run main/othervm MacSameTest sm
  * @key randomness
diff --git a/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java b/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java
index 97dcb73..9973f46 100644
--- a/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java
+++ b/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ReinitMac
  * @run main/othervm ReinitMac sm
  */
diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java b/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java
index 64d7ff5..3226442 100644
--- a/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java
+++ b/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ByteBuffers
  * @run main/othervm ByteBuffers sm
  */
diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java b/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java
index 4a3b71f..42aa231 100644
--- a/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java
+++ b/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java
@@ -27,7 +27,7 @@
  * @summary Basic known-answer-test for all our MessageDigest algorithms
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm DigestKAT
  * @run main/othervm DigestKAT sm
  */
diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java b/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java
index 3414a57..04e43bb 100644
--- a/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java
+++ b/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ReinitDigest
  * @run main/othervm ReinitDigest sm
  */
diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java b/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java
index 4bac079..2374e9b 100644
--- a/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java
+++ b/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java
@@ -28,7 +28,7 @@
  * @author Valerie Peng
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestCloning
  * @run main/othervm TestCloning sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Provider/Absolute.java b/jdk/test/sun/security/pkcs11/Provider/Absolute.java
index 7906ac1..05d0e78 100644
--- a/jdk/test/sun/security/pkcs11/Provider/Absolute.java
+++ b/jdk/test/sun/security/pkcs11/Provider/Absolute.java
@@ -24,7 +24,7 @@
  * @test
  * @bug 7003952 7191662
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @summary load DLLs and launch executables using fully qualified path
  */
 
diff --git a/jdk/test/sun/security/pkcs11/SampleTest.java b/jdk/test/sun/security/pkcs11/SampleTest.java
index 5d5c684..f3ee5bd 100644
--- a/jdk/test/sun/security/pkcs11/SampleTest.java
+++ b/jdk/test/sun/security/pkcs11/SampleTest.java
@@ -27,7 +27,7 @@
  * @summary XXX todo
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  */
 
 import java.security.Provider;
diff --git a/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java
index 82fc4ab..b6875a7 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java
@@ -27,7 +27,7 @@
  * @summary Test that the PKCS#11 KeyStore handles RSA, DSA, and EC keys
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm AddPrivateKey
  * @run main/othervm AddPrivateKey sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java b/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java
index 1e085c3..c03cb86 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java
@@ -27,7 +27,7 @@
  * @summary make sure we can add a trusted cert to the NSS KeyStore module
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm AddTrustedCert
  * @run main/othervm AddTrustedCert sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/Crypto.java b/jdk/test/sun/security/pkcs11/Secmod/Crypto.java
index b1b4372..da57418 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/Crypto.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/Crypto.java
@@ -27,7 +27,7 @@
  * @summary verify that NSS no-db mode works correctly
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm Crypto
  * @run main/othervm Crypto sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java
index 9dd1fe0..39db0a3 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java
@@ -28,7 +28,7 @@
  *          and use a private key
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm GetPrivateKey
  * @run main/othervm GetPrivateKey sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java
index 360e5d1..c02a98a 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java
@@ -27,7 +27,7 @@
  * @summary store a NSS PKCS11 PrivateKeyEntry to JKS KeyStore throws confusing NPE
  * @author Wang Weijun
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm JksSetPrivateKey
  * @run main/othervm JksSetPrivateKey sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java b/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java
index 2e1d85c..e421883 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java
@@ -26,7 +26,7 @@
  * @bug 8048622 8134232
  * @summary Checks that PKCS#11 keystore can't be loaded with wrong password
  * @library ../
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm LoadKeystore
  * @run main/othervm LoadKeystore sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java b/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java
index a26a586..8735bc6 100644
--- a/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java
+++ b/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java
@@ -27,7 +27,7 @@
  * @summary make sure we can access the NSS trust anchor module
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TrustAnchors
  * @run main/othervm TrustAnchors sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java b/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java
index 3145431..1994977 100644
--- a/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java
+++ b/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm Basic
  * @run main/othervm Basic sm
  */
diff --git a/jdk/test/sun/security/pkcs11/SecureRandom/TestDeserialization.java b/jdk/test/sun/security/pkcs11/SecureRandom/TestDeserialization.java
index 37985dd..27a3575 100644
--- a/jdk/test/sun/security/pkcs11/SecureRandom/TestDeserialization.java
+++ b/jdk/test/sun/security/pkcs11/SecureRandom/TestDeserialization.java
@@ -26,7 +26,7 @@
  * @bug 6837847
  * @summary Ensure a deserialized PKCS#11 SecureRandom is functional.
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  */
 
 import java.io.ByteArrayInputStream;
diff --git a/jdk/test/sun/security/pkcs11/Serialize/SerializeProvider.java b/jdk/test/sun/security/pkcs11/Serialize/SerializeProvider.java
index a3deb72..b22465f 100644
--- a/jdk/test/sun/security/pkcs11/Serialize/SerializeProvider.java
+++ b/jdk/test/sun/security/pkcs11/Serialize/SerializeProvider.java
@@ -27,7 +27,7 @@
  * @summary Test that the SunPKCS11 provider can be serialized
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  */
 
 import java.io.ByteArrayInputStream;
diff --git a/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java b/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java
index 3d1afa3..854da84 100644
--- a/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java
+++ b/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ByteBuffers
  * @run main/othervm ByteBuffers sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Signature/ReinitSignature.java b/jdk/test/sun/security/pkcs11/Signature/ReinitSignature.java
index 30f1d7f..9a07226 100644
--- a/jdk/test/sun/security/pkcs11/Signature/ReinitSignature.java
+++ b/jdk/test/sun/security/pkcs11/Signature/ReinitSignature.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main ReinitSignature
  * @run main ReinitSignature
  * @run main ReinitSignature
diff --git a/jdk/test/sun/security/pkcs11/Signature/TestDSA.java b/jdk/test/sun/security/pkcs11/Signature/TestDSA.java
index b707d98..11bfbfd 100644
--- a/jdk/test/sun/security/pkcs11/Signature/TestDSA.java
+++ b/jdk/test/sun/security/pkcs11/Signature/TestDSA.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestDSA
  * @run main/othervm TestDSA sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java b/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java
index c1a0dc1..673098e 100644
--- a/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java
+++ b/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java
@@ -28,7 +28,7 @@
  * with unsupported key sizes
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestDSAKeyLength
  * @run main/othervm TestDSAKeyLength sm
  */
diff --git a/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java b/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java
index 7618851..8e70e22 100644
--- a/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java
+++ b/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java
@@ -27,7 +27,7 @@
  * @summary Make sure initSign/initVerify() check RSA key lengths
  * @author Yu-Ching Valerie Peng
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestRSAKeyLength
  * @run main/othervm TestRSAKeyLength sm
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java b/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java
index 3117c98..46d44f4 100644
--- a/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java
+++ b/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java
@@ -29,7 +29,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @library ../../../../java/security/testlibrary
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ReadCertificates
  * @run main/othervm ReadCertificates sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java b/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java
index 57af804..8efbb0a 100644
--- a/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java
+++ b/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java
@@ -29,7 +29,7 @@
  * @library ..
  * @library ../../../../java/security/testlibrary
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm ReadPKCS12
  * @run main/othervm ReadPKCS12 sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/TestCurves.java b/jdk/test/sun/security/pkcs11/ec/TestCurves.java
index 41e5761..b079001 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestCurves.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestCurves.java
@@ -27,8 +27,8 @@
  * @summary Basic consistency test for all curves using ECDSA and ECDH
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11/sun.security.pkcs11.wrapper
- * @compile --add-modules jdk.crypto.pkcs11 TestCurves.java
+ * @modules jdk.crypto.token/sun.security.pkcs11.wrapper
+ * @compile --add-modules jdk.crypto.token TestCurves.java
  * @run main/othervm TestCurves
  * @run main/othervm TestCurves sm
  * @key randomness
diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDH.java b/jdk/test/sun/security/pkcs11/ec/TestECDH.java
index d5432b0..a967f8e 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestECDH.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestECDH.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @library ../../../../java/security/testlibrary
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestECDH
  * @run main/othervm TestECDH sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDH2.java b/jdk/test/sun/security/pkcs11/ec/TestECDH2.java
index d064e52..2da9fbc 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestECDH2.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestECDH2.java
@@ -29,7 +29,7 @@
  * @library ..
  * @library ../../../../java/security/testlibrary
  * @modules java.base/sun.security.util
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @compile -XDignore.symbol.file TestECDH2.java
  * @run main/othervm TestECDH2
  * @run main/othervm TestECDH2 sm
diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDSA.java b/jdk/test/sun/security/pkcs11/ec/TestECDSA.java
index fd5de68..8b516cc 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestECDSA.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestECDSA.java
@@ -29,7 +29,7 @@
  * @library ..
  * @library ../../../../java/security/testlibrary
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestECDSA
  * @run main/othervm TestECDSA sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java b/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java
index fa0c5fc..0a9b9c6 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java
@@ -29,7 +29,7 @@
  * @library ..
  * @library ../../../../java/security/testlibrary
  * @modules java.base/sun.security.util
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @compile -XDignore.symbol.file TestECDSA2.java
  * @run main/othervm TestECDSA2
  * @run main/othervm TestECDSA2 sm
diff --git a/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java b/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java
index 4ce1050..9d50c95 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java
@@ -27,7 +27,7 @@
  * @summary Verify that we can use ECGenParameterSpec
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestECGenSpec
  * @run main/othervm TestECGenSpec sm
  */
diff --git a/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java b/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java
index 827af91..524c048 100644
--- a/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java
+++ b/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java
@@ -27,7 +27,7 @@
  * @summary Test the P11ECKeyFactory
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestKeyFactory
  * @run main/othervm TestKeyFactory sm
  */
diff --git a/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java b/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java
index 311a9b7..00c7199 100644
--- a/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java
+++ b/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm KeyWrap
  * @run main/othervm KeyWrap sm
  */
diff --git a/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java
index a79330b..012142e 100644
--- a/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java
+++ b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @library ../../../../java/security/testlibrary
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestCACerts
  * @run main/othervm TestCACerts sm TestCACerts.policy
  */
diff --git a/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java b/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java
index d8292bc..f999afa 100644
--- a/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java
+++ b/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java
@@ -27,7 +27,7 @@
  * @summary Test KeyFactory of the new RSA provider
  * @author Andreas Sterbenz
  * @library ..
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestKeyFactory
  * @run main/othervm TestKeyFactory sm rsakeys.ks.policy
  */
diff --git a/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java
index 84bbb60..6671509 100644
--- a/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java
+++ b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java
@@ -29,7 +29,7 @@
  * @library ..
  * @library /lib/testlibrary
  * @build jdk.testlibrary.*
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm -Djava.security.debug=sunpkcs11 TestKeyPairGenerator
  * @run main/othervm -Djava.security.debug=sunpkcs11 TestKeyPairGenerator
  *                                                   sm TestKeyPairGenerator.policy
diff --git a/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java b/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java
index 84283b8..e0c61d8 100644
--- a/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java
+++ b/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @key randomness
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestSignatures
  * @run main/othervm TestSignatures sm rsakeys.ks.policy
  */
diff --git a/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java b/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java
index 11fcaac..a168965 100644
--- a/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java
+++ b/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java
@@ -33,7 +33,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @library ../../../../java/security/testlibrary
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
  *      ClientJSSEServerJSSE
  * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
diff --git a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
index 81a8b45..c0b58d0 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @modules java.base/sun.security.internal.spec
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @run main/othervm TestKeyMaterial
  * @run main/othervm TestKeyMaterial sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java b/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java
index 2d9dc28..e455cce 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java
@@ -27,7 +27,7 @@
  * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement
  * @library ..
  * @author Pasi Eronen
- * @modules jdk.crypto.pkcs11
+ * @modules jdk.crypto.token
  * @run main/othervm TestLeadingZeroesP11
  * @run main/othervm TestLeadingZeroesP11 sm
  */
diff --git a/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java
index de68636..abaceb3 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java
@@ -29,7 +29,7 @@
  * @library ..
  * @modules java.base/sun.security.internal.interfaces
  *          java.base/sun.security.internal.spec
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @run main/othervm TestMasterSecret
  * @run main/othervm TestMasterSecret sm TestMasterSecret.policy
  */
diff --git a/jdk/test/sun/security/pkcs11/tls/TestPRF.java b/jdk/test/sun/security/pkcs11/tls/TestPRF.java
index 47b49e9..9efdb00 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestPRF.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestPRF.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @modules java.base/sun.security.internal.spec
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @run main/othervm TestPRF
  * @run main/othervm TestPRF sm policy
  */
diff --git a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java
index 67191a7..6bdace2 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java
@@ -28,7 +28,7 @@
  * @author Andreas Sterbenz
  * @library ..
  * @modules java.base/sun.security.internal.spec
- *          jdk.crypto.pkcs11
+ *          jdk.crypto.token
  * @run main/othervm TestPremaster
  * @run main/othervm TestPremaster sm policy
  */
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java b/jdk/test/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java
new file mode 100644
index 0000000..6afeb27
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8047305 8075618
+ * @summary Tests jarsigner tool and JarSigner API work with multi-release JAR files.
+ * @library /test/lib
+ * @library /lib/testlibrary
+ * @run main MVJarSigningTest
+ */
+
+import jdk.security.jarsigner.JarSigner;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+
+public class MVJarSigningTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src", ".");
+    private static final String USR_DIR = System.getProperty("user.dir", ".");
+    private static final String JAR_NAME = "MV.jar";
+    private static final String KEYSTORE = "keystore.jks";
+    private static final String ALIAS = "JavaTest";
+    private static final String STOREPASS = "changeit";
+    private static final String KEYPASS = "changeit";
+    private static final String SIGNED_JAR = "Signed.jar";
+    private static final String POLICY_FILE = "SignedJar.policy";
+    private static final String VERSION_MESSAGE = "I am running on version 9";
+
+    public static void main(String[] args) throws Throwable {
+        // compile java files in jarContent directory
+        compile("jarContent");
+
+        // create multi-release jar
+        Path classes = Paths.get("classes");
+        jar("cf", JAR_NAME, "-C", classes.resolve("base").toString(), ".",
+                "--release", "9", "-C", classes.resolve("v9").toString(), ".",
+                "--release", "10", "-C", classes.resolve("v10").toString(), ".")
+            .shouldHaveExitValue(0);
+
+        genKey();
+        signJar(JAR_NAME)
+            .shouldHaveExitValue(0)
+            .shouldMatch("signing.*META-INF/versions/9/version/Version.class")
+            .shouldMatch("signing.*META-INF/versions/10/version/Version.class")
+            .shouldMatch("signing.*version/Main.class")
+            .shouldMatch("signing.*version/Version.class");
+        verify(SIGNED_JAR);
+
+        // test with JarSigner API
+        Files.deleteIfExists(Paths.get(SIGNED_JAR));
+        signWithJarSignerAPI(JAR_NAME);
+        verify(SIGNED_JAR);
+
+        // test Permission granted
+        File keypass = new File("keypass");
+        try (FileOutputStream fos = new FileOutputStream(keypass)) {
+            fos.write(KEYPASS.getBytes());
+        }
+        String[] cmd = {
+                "-classpath", SIGNED_JAR,
+                "-Djava.security.manager",
+                "-Djava.security.policy=" +
+                TEST_SRC + File.separator + POLICY_FILE,
+                "version.Main"};
+        ProcessTools.executeTestJvm(cmd)
+            .shouldHaveExitValue(0)
+            .shouldContain(VERSION_MESSAGE);
+    }
+
+    private static void compile (String jarContent_path) throws Throwable {
+        Path classes = Paths.get(USR_DIR, "classes", "base");
+        Path source = Paths.get(TEST_SRC, jarContent_path, "base", "version");
+        CompilerUtils.compile(source, classes);
+
+        classes = Paths.get(USR_DIR, "classes", "v9");
+        source = Paths.get(TEST_SRC, jarContent_path , "v9", "version");
+        CompilerUtils.compile(source, classes);
+
+        classes = Paths.get(USR_DIR, "classes", "v10");
+        source = Paths.get(TEST_SRC, jarContent_path, "v10", "version");
+        CompilerUtils.compile(source, classes);
+    }
+
+    private static OutputAnalyzer jar(String...args) throws Throwable {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jar");
+        Stream.of(args).forEach(launcher::addToolArg);
+        return ProcessTools.executeCommand(launcher.getCommand());
+    }
+
+    private static void genKey() throws Throwable {
+        String keytool = JDKToolFinder.getJDKTool("keytool");
+        Files.deleteIfExists(Paths.get(KEYSTORE));
+        ProcessTools.executeCommand(keytool,
+                "-J-Duser.language=en",
+                "-J-Duser.country=US",
+                "-genkey",
+                "-alias", ALIAS,
+                "-keystore", KEYSTORE,
+                "-keypass", KEYPASS,
+                "-dname", "cn=sample",
+                "-storepass", STOREPASS
+        ).shouldHaveExitValue(0);
+    }
+
+    private static OutputAnalyzer signJar(String jarName) throws Throwable {
+        List<String> args = new ArrayList<>();
+        args.add("-verbose");
+        args.add("-signedjar");
+        args.add(SIGNED_JAR);
+        args.add(jarName);
+        args.add(ALIAS);
+
+        return jarsigner(args);
+    }
+
+    private static void verify(String signedJarName) throws Throwable {
+        verifyJar(signedJarName)
+            .shouldHaveExitValue(0)
+            .shouldContain("jar verified")
+            .shouldMatch("smk.*META-INF/versions/9/version/Version.class")
+            .shouldMatch("smk.*META-INF/versions/10/version/Version.class")
+            .shouldMatch("smk.*version/Main.class")
+            .shouldMatch("smk.*version/Version.class");
+    }
+
+    private static OutputAnalyzer verifyJar(String signedJarName) throws Throwable {
+        List<String> args = new ArrayList<>();
+        args.add("-verbose");
+        args.add("-verify");
+        args.add(signedJarName);
+
+        return jarsigner(args);
+    }
+
+    private static OutputAnalyzer jarsigner(List<String> extra)
+            throws Throwable {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner")
+                .addVMArg("-Duser.language=en")
+                .addVMArg("-Duser.country=US")
+                .addToolArg("-keystore")
+                .addToolArg(KEYSTORE)
+                .addToolArg("-storepass")
+                .addToolArg(STOREPASS)
+                .addToolArg("-keypass")
+                .addToolArg(KEYPASS);
+        for (String s : extra) {
+            if (s.startsWith("-J")) {
+                launcher.addVMArg(s.substring(2));
+            } else {
+                launcher.addToolArg(s);
+            }
+        }
+        return ProcessTools.executeCommand(launcher.getCommand());
+    }
+
+    private static void signWithJarSignerAPI(String jarName)
+            throws Throwable {
+        // Get JarSigner
+        try (FileInputStream fis = new FileInputStream(KEYSTORE)) {
+                KeyStore ks = KeyStore.getInstance("JKS");
+                ks.load(fis, STOREPASS.toCharArray());
+                PrivateKey pk = (PrivateKey)ks.getKey(ALIAS, KEYPASS.toCharArray());
+                Certificate cert = ks.getCertificate(ALIAS);
+                JarSigner signer = new JarSigner.Builder(pk,
+                        CertificateFactory.getInstance("X.509").generateCertPath(
+                                Collections.singletonList(cert)))
+                        .build();
+            // Sign jar
+            try (ZipFile src = new JarFile(jarName);
+                    FileOutputStream out = new FileOutputStream(SIGNED_JAR)) {
+                signer.sign(src,out);
+            }
+        }
+    }
+
+}
+
+
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/SignedJar.policy b/jdk/test/sun/security/tools/jarsigner/multiRelease/SignedJar.policy
new file mode 100644
index 0000000..f39efb5
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/SignedJar.policy
@@ -0,0 +1,10 @@
+keystore "file:keystore.jks";
+keystorePasswordURL "file:keypass";
+
+grant signedBy "JavaTest" {
+    permission java.lang.RuntimePermission "setIO";
+};
+
+grant signedBy "other" {
+    permission java.lang.RuntimePermission "setFactory";
+};
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Main.java b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Main.java
new file mode 100644
index 0000000..482b147
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Main.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package version;
+
+import java.security.Permission;
+
+public class Main {
+
+    public static void main(String[] args) {
+        Version v = new Version();
+        System.out.println("I am running on version " + v.getVersion());
+    }
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Version.java b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Version.java
new file mode 100644
index 0000000..3ad4440
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Version.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package version;
+
+public class Version {
+
+    public int getVersion() {
+        return 8;
+    }
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v10/version/Version.java b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v10/version/Version.java
new file mode 100644
index 0000000..0a816cb
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v10/version/Version.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package version;
+
+public class Version {
+
+    public int getVersion() {
+        return 10;
+    }
+}
+
diff --git a/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v9/version/Version.java b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v9/version/Version.java
new file mode 100644
index 0000000..39b09f0
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v9/version/Version.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package version;
+
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+
+public class Version {
+    private static final Permission PERM1 = new RuntimePermission("setIO");
+    private static final Permission PERM2 = new RuntimePermission("setFactory");
+
+    public int getVersion() {
+        checkPermission(PERM1, false);
+        checkPermission(PERM2, true);
+        return 9;
+    }
+
+    private void checkPermission(Permission perm, boolean expectException) {
+        boolean getException = (Boolean) AccessController
+                .doPrivileged((PrivilegedAction) () -> {
+            try {
+                AccessController.checkPermission(perm);
+                return (Boolean) false;
+            } catch (AccessControlException ex) {
+                return (Boolean) true;
+            }
+        });
+
+        if (expectException ^ getException) {
+            String message = "Check Permission :" + perm + "\n ExpectException = "
+                    + expectException + "\n getException = " + getException;
+            throw new RuntimeException(message);
+        }
+    }
+}
diff --git a/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java b/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java
index 998e1b2..9285044 100644
--- a/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java
+++ b/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java
@@ -44,7 +44,7 @@
 import jdk.testlibrary.OutputAnalyzer;
 import jdk.testlibrary.ProcessTools;
 import jdk.test.lib.apps.LingeredApp;
-import jdk.testlibrary.Platform;
+import jdk.test.lib.Platform;
 
 public class BasicLauncherTest {
 
@@ -230,8 +230,7 @@
                                                        Arrays.asList(toolArgs));
     }
 
-    public static void main(String[] args)
-        throws IOException {
+    public static void main(String[] args) throws Exception {
 
         if (!Platform.shouldSAAttach()) {
             // Silently skip the test if we don't have enough permissions to attach
diff --git a/jdk/test/sun/tools/jhsdb/HeapDumpTest.java b/jdk/test/sun/tools/jhsdb/HeapDumpTest.java
index 59772a3..bc1d655 100644
--- a/jdk/test/sun/tools/jhsdb/HeapDumpTest.java
+++ b/jdk/test/sun/tools/jhsdb/HeapDumpTest.java
@@ -41,7 +41,7 @@
 import jdk.testlibrary.OutputAnalyzer;
 import jdk.testlibrary.ProcessTools;
 import jdk.test.lib.apps.LingeredApp;
-import jdk.testlibrary.Platform;
+import jdk.test.lib.Platform;
 
 public class HeapDumpTest {
 
@@ -109,8 +109,7 @@
         dump.delete();
     }
 
-    public static void main(String[] args)
-        throws IOException {
+    public static void main(String[] args) throws Exception {
 
         if (!Platform.shouldSAAttach()) {
             // Silently skip the test if we don't have enough permissions to attach
diff --git a/jdk/test/sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java b/jdk/test/sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java
index 1f88fd3..75437fa 100644
--- a/jdk/test/sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java
+++ b/jdk/test/sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java
@@ -30,7 +30,7 @@
 
 import jdk.test.lib.apps.LingeredApp;
 import jdk.testlibrary.Utils;
-import jdk.testlibrary.Platform;
+import jdk.test.lib.Platform;
 
 /*
  * @test
diff --git a/jdk/test/tools/jar/compat/CLICompatibility.java b/jdk/test/tools/jar/compat/CLICompatibility.java
index 9355f18..c31762e 100644
--- a/jdk/test/tools/jar/compat/CLICompatibility.java
+++ b/jdk/test/tools/jar/compat/CLICompatibility.java
@@ -43,6 +43,7 @@
 import static java.lang.String.format;
 import static java.lang.System.out;
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
 /*
@@ -428,10 +429,12 @@
 
         jar("--help")
             .assertSuccess()
-            .resultChecker(r ->
+            .resultChecker(r -> {
                 assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
-                           "Failed, got [" + r.output + "]")
-            );
+                           "Failed, got [" + r.output + "]");
+                assertFalse(r.output.contains("--do-not-resolve-by-default"));
+                assertFalse(r.output.contains("--warn-if-resolved"));
+            });
 
         jar("--help:compat")
             .assertSuccess()
@@ -439,6 +442,15 @@
                 assertTrue(r.output.startsWith("Compatibility Interface:"),
                            "Failed, got [" + r.output + "]")
             );
+
+        jar("--help-extra")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
+                           "Failed, got [" + r.output + "]");
+                assertTrue(r.output.contains("--do-not-resolve-by-default"));
+                assertTrue(r.output.contains("--warn-if-resolved"));
+            });
     }
 
     // -- Infrastructure
diff --git a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java
index 9232926..2d1d844 100644
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java
@@ -25,16 +25,18 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Module;
 import java.util.Optional;
 import java.util.StringJoiner;
 import java.util.HashSet;
 import java.util.Set;
-
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 import jdk.test.bar.internal.Message;
 
 public class Bar {
@@ -71,9 +73,14 @@
         if (!sj.toString().equals(""))
             System.out.println("contains:" + sj.toString());
 
-        ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
-        JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
-        Optional<ModuleHashes> oHashes = jlma.hashes(foo);
-        System.out.println("hashes:" + oHashes.get().hashFor("bar"));
+
+        Module foo = jdk.test.foo.Foo.class.getModule();
+        Optional<ResolvedModule> om = foo.getLayer().configuration().findModule(foo.getName());
+        assert om.isPresent();
+        ModuleReference mref = om.get().reference();
+        assert mref instanceof ModuleReferenceImpl;
+        ModuleHashes hashes = ((ModuleReferenceImpl) mref).recordedHashes();
+        assert hashes != null;
+        System.out.println("hashes:" + hashes.hashFor("bar"));
     }
 }
diff --git a/jdk/test/tools/jimage/VerifyJimage.java b/jdk/test/tools/jimage/VerifyJimage.java
index 30628ad..d5415af 100644
--- a/jdk/test/tools/jimage/VerifyJimage.java
+++ b/jdk/test/tools/jimage/VerifyJimage.java
@@ -49,7 +49,7 @@
  * @test
  * @summary Verify jimage
  * @modules java.base/jdk.internal.jimage
- * @run main/othervm --add-modules=ALL-SYSTEM VerifyJimage
+ * @run main/othervm --add-modules=ALL-SYSTEM,jdk.incubator.httpclient VerifyJimage
  */
 
 /**
diff --git a/jdk/test/tools/jlink/CustomPluginTest.java b/jdk/test/tools/jlink/CustomPluginTest.java
index 2464735..9fad705 100644
--- a/jdk/test/tools/jlink/CustomPluginTest.java
+++ b/jdk/test/tools/jlink/CustomPluginTest.java
@@ -156,7 +156,7 @@
                 .option("--rogue-filter")
                 .option("/foo/")
                 .call()
-                .assertFailure("java.lang.module.ResolutionException");
+                .assertFailure("foo not found");
         }
 
         {
diff --git a/jdk/test/tools/jlink/IntegrationTest.java b/jdk/test/tools/jlink/IntegrationTest.java
index 8d6bb30..e966667 100644
--- a/jdk/test/tools/jlink/IntegrationTest.java
+++ b/jdk/test/tools/jlink/IntegrationTest.java
@@ -186,7 +186,7 @@
             lst.add(new MyPostProcessor());
         }
         // Image builder
-        DefaultImageBuilder builder = new DefaultImageBuilder(output);
+        DefaultImageBuilder builder = new DefaultImageBuilder(output, Collections.emptyMap());
         PluginsConfiguration plugins
                 = new Jlink.PluginsConfiguration(lst, builder, null);
 
diff --git a/jdk/test/tools/jlink/JLinkTest.java b/jdk/test/tools/jlink/JLinkTest.java
index 4d12ddc..874c9df 100644
--- a/jdk/test/tools/jlink/JLinkTest.java
+++ b/jdk/test/tools/jlink/JLinkTest.java
@@ -191,17 +191,6 @@
         }
 
         {
-            // License files
-            String copied = "LICENSE";
-            String[] arr = copied.split(",");
-            String[] copyFiles = new String[2];
-            copyFiles[0] = "--copy-files";
-            copyFiles[1] = copied;
-            Path imageDir = helper.generateDefaultImage(copyFiles, "composite2").assertSuccess();
-            helper.checkImage(imageDir, "composite2", null, null, arr);
-        }
-
-        {
             // List plugins
             StringWriter writer = new StringWriter();
             PrintWriter pw = new PrintWriter(writer);
diff --git a/jdk/test/tools/jlink/ModuleNamesOrderTest.java b/jdk/test/tools/jlink/ModuleNamesOrderTest.java
index 09a4dfd..20b642d 100644
--- a/jdk/test/tools/jlink/ModuleNamesOrderTest.java
+++ b/jdk/test/tools/jlink/ModuleNamesOrderTest.java
@@ -38,6 +38,12 @@
  * @bug 8168925
  * @summary MODULES property should be topologically ordered and space-separated list
  * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
  * @build tests.*
  * @run main ModuleNamesOrderTest
  */
diff --git a/jdk/test/tools/jlink/ReleaseImplementorTest.java b/jdk/test/tools/jlink/ReleaseImplementorTest.java
new file mode 100644
index 0000000..7f935ea
--- /dev/null
+++ b/jdk/test/tools/jlink/ReleaseImplementorTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+/*
+ * @test
+ * @bug 8171316
+ * @summary Add IMPLEMENTOR property to the release file
+ * @run main ReleaseImplementorTest
+ */
+public class ReleaseImplementorTest {
+    public static void main(String[] args) throws Exception {
+        Properties props = new Properties();
+        Path release = Paths.get(System.getProperty("test.jdk"), "release");
+        try (InputStream in = Files.newInputStream(release)) {
+            props.load(in);
+        }
+
+        if (!props.containsKey("IMPLEMENTOR")) {
+            throw new RuntimeException("IMPLEMENTOR key is missing");
+        }
+
+        String implementor = props.getProperty("IMPLEMENTOR");
+        if (implementor.length() < 3) {
+            throw new RuntimeException("IMPLEMENTOR value is not expected length");
+        }
+
+        if (implementor.charAt(0) != '"' ||
+            implementor.charAt(implementor.length() - 1) != '"') {
+            throw new RuntimeException("IMPLEMENTOR value not quoted property");
+        }
+
+        System.out.println("IMPLEMENTOR is " + implementor);
+    }
+}
diff --git a/jdk/test/tools/jlink/basic/BasicTest.java b/jdk/test/tools/jlink/basic/BasicTest.java
index 87b2b0e..ae49a01 100644
--- a/jdk/test/tools/jlink/basic/BasicTest.java
+++ b/jdk/test/tools/jlink/basic/BasicTest.java
@@ -87,20 +87,29 @@
         JarUtils.createJarFile(jarfile, classes);
 
         Path image = Paths.get("mysmallimage");
-        runJmod(jarfile.toString(), TEST_MODULE);
-        runJlink(image, TEST_MODULE, "--compress", "2");
-        execute(image, TEST_MODULE);
+        runJmod(jarfile.toString(), TEST_MODULE, true);
+        runJlink(image, TEST_MODULE, "--compress", "2", "--launcher", "foo=" + TEST_MODULE);
+        execute(image, "foo");
 
         Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
 
         image = Paths.get("myimage");
-        runJmod(classes.toString(), TEST_MODULE);
-        runJlink(image, TEST_MODULE);
-        execute(image, TEST_MODULE);
+        runJmod(classes.toString(), TEST_MODULE, true);
+        runJlink(image, TEST_MODULE, "--launcher", "bar=" + TEST_MODULE);
+        execute(image, "bar");
+
+        Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
+
+        image = Paths.get("myimage2");
+        runJmod(classes.toString(), TEST_MODULE, false /* no ModuleMainClass! */);
+        // specify main class in --launcher command line
+        runJlink(image, TEST_MODULE, "--launcher", "bar2=" + TEST_MODULE + "/jdk.test.Test");
+        execute(image, "bar2");
+
     }
 
-    private void execute(Path image, String moduleName) throws Throwable {
-        String cmd = image.resolve("bin").resolve(moduleName).toString();
+    private void execute(Path image, String scriptName) throws Throwable {
+        String cmd = image.resolve("bin").resolve(scriptName).toString();
         OutputAnalyzer analyzer;
         if (System.getProperty("os.name").startsWith("Windows")) {
             analyzer = ProcessTools.executeProcess("sh.exe", cmd, "1", "2", "3");
@@ -127,14 +136,25 @@
         }
     }
 
-    private void runJmod(String cp, String modName) {
-        int rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+    private void runJmod(String cp, String modName, boolean main) {
+        int rc;
+        if (main) {
+            rc = JMOD_TOOL.run(System.out, System.out, new String[] {
                 "create",
                 "--class-path", cp,
                 "--module-version", "1.0",
                 "--main-class", "jdk.test.Test",
+                jmods.resolve(modName + ".jmod").toString()
+            });
+        } else {
+            rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+                "create",
+                "--class-path", cp,
+                "--module-version", "1.0",
                 jmods.resolve(modName + ".jmod").toString(),
-        });
+            });
+        }
+
         if (rc != 0) {
             throw new AssertionError("Jmod failed: rc = " + rc);
         }
diff --git a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java
deleted file mode 100644
index 9137ed3..0000000
--- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @summary Test files copy plugin
- * @author Jean-Francois Denise
- * @modules jdk.jlink/jdk.tools.jlink.internal
- *          jdk.jlink/jdk.tools.jlink.builder
- *          jdk.jlink/jdk.tools.jlink.internal.plugins
- * @run main FileCopierPluginTest
- */
-
-import java.io.File;
-import java.net.URI;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import jdk.tools.jlink.internal.ResourcePoolManager;
-import jdk.tools.jlink.builder.DefaultImageBuilder;
-
-import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.ResourcePoolEntry;
-import jdk.tools.jlink.plugin.ResourcePool;
-
-public class FileCopierPluginTest {
-
-    public static void main(String[] args) throws Exception {
-        new FileCopierPluginTest().test();
-    }
-
-    /**
-     * 3 cases - Absolute, no target ==> copy in image root dir - Absolute and
-     * target ==> copy in image root dir/target - Relative ==> copy from JDK
-     * home dir.
-     *
-     * @throws Exception
-     */
-    public void test() throws Exception {
-        FileCopierPlugin plug = new FileCopierPlugin();
-        String content = "You \n should \n be \bthere.\n";
-        String name = "sample.txt";
-        File src = new File("src");
-        src.mkdir();
-        // Need a fake bin
-        File bin = new File("bin");
-        bin.mkdir();
-
-        File txt = new File(src, name);
-        txt.createNewFile();
-
-        String target = "target" + File.separator + name;
-        Files.write(txt.toPath(), content.getBytes());
-        File lic = new File(System.getProperty("java.home"), "LICENSE.txt");
-        StringBuilder builder = new StringBuilder();
-        int expected = lic.exists() ? 4 : 3;
-        if (lic.exists()) {
-            builder.append("LICENSE.txt,");
-        }
-        builder.append(txt.getAbsolutePath()+",");
-        builder.append(txt.getAbsolutePath() + "=" + target+",");
-        builder.append(src.getAbsolutePath() + "=src2");
-
-        Map<String, String> conf = new HashMap<>();
-        conf.put(FileCopierPlugin.NAME, builder.toString());
-        plug.configure(conf);
-        ResourcePoolManager poolMgr = new ResourcePoolManager();
-        // java.base/module-info.class is used to add "release" file
-        // We read it from jrt-fs and add a ResourcePoolEntry
-        poolMgr.add(
-            ResourcePoolEntry.create("/java.base/module-info.class",
-                ResourcePoolEntry.Type.CLASS_OR_RESOURCE, getJavaBaseModuleInfo()));
-        expected++;
-        ResourcePool pool = plug.transform(
-                new ResourcePoolManager().resourcePool(),
-                poolMgr.resourcePoolBuilder());
-        if (pool.entryCount() != expected) {
-            throw new AssertionError("Wrong number of added files");
-        }
-        pool.entries().forEach(f -> {
-            if (!f.type().equals(ResourcePoolEntry.Type.OTHER) &&
-                !f.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) {
-                throw new AssertionError("Invalid type " + f.type()
-                        + " for file " + f.path());
-            }
-            if (f.content() == null) {
-                throw new AssertionError("Null stream for file " + f.path());
-            }
-        });
-        Path root = new File(".").toPath();
-        DefaultImageBuilder imgbuilder = new DefaultImageBuilder(root);
-        imgbuilder.storeFiles(pool);
-
-        if (lic.exists()) {
-            File license = new File(root.toFile(), "LICENSE.txt");
-            if (!license.exists() || license.length() == 0) {
-                throw new AssertionError("Invalid license file "
-                        + license.getAbsoluteFile());
-            }
-        }
-
-        File sample1 = new File(root.toFile(), txt.getName());
-        if (!sample1.exists() || sample1.length() == 0) {
-            throw new AssertionError("Invalide sample1 file "
-                    + sample1.getAbsoluteFile());
-        }
-        if (!new String(Files.readAllBytes(sample1.toPath())).equals(content)) {
-            throw new AssertionError("Invalid Content in sample1");
-        }
-
-        File sample2 = new File(root.toFile(), target);
-        if (!sample2.exists() || sample2.length() == 0) {
-            throw new AssertionError("Invalide sample2 file "
-                    + sample2.getAbsoluteFile());
-        }
-        if (!new String(Files.readAllBytes(sample2.toPath())).equals(content)) {
-            throw new AssertionError("Invalid Content in sample2");
-        }
-
-        File src2 = new File(root.toFile(), "src2");
-        if (!src2.exists() || src2.list().length != 1) {
-            throw new AssertionError("Invalide src2 dir "
-                    + src2.getAbsoluteFile());
-        }
-        File f = src2.listFiles()[0];
-        if (!f.getName().equals(txt.getName())) {
-            throw new AssertionError("Invalide file name in src2 dir "
-                    + f.getAbsoluteFile());
-        }
-        if (!new String(Files.readAllBytes(f.toPath())).equals(content)) {
-            throw new AssertionError("Invalid Content in src2 dir");
-        }
-    }
-
-    // read java.base/module-info.class from jrt-fs
-    private static Path getJavaBaseModuleInfo() {
-        return Paths.get(URI.create("jrt:/modules/java.base/module-info.class"));
-    }
-}
diff --git a/jdk/test/tools/jlink/plugins/LegalFilePluginTest.java b/jdk/test/tools/jlink/plugins/LegalFilePluginTest.java
new file mode 100644
index 0000000..d5b3dfd
--- /dev/null
+++ b/jdk/test/tools/jlink/plugins/LegalFilePluginTest.java
@@ -0,0 +1,387 @@
+/**
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8169925
+ * @summary Validate the license files deduplicated in the image
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ *          jdk.jlink
+ * @build CompilerUtils
+ * @run testng LegalFilePluginTest
+ */
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class LegalFilePluginTest {
+    static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
+        .orElseThrow(() ->
+            new RuntimeException("jmod tool not found")
+        );
+
+    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+        .orElseThrow(() ->
+            new RuntimeException("jlink tool not found")
+        );
+
+    static final Path MODULE_PATH = Paths.get(System.getProperty("java.home"), "jmods");
+    static final Path SRC_DIR = Paths.get("src");
+    static final Path MODS_DIR = Paths.get("mods");
+    static final Path JMODS_DIR = Paths.get("jmods");
+    static final Path LEGAL_DIR = Paths.get("legal");
+    static final Path IMAGES_DIR = Paths.get("images");
+
+    static final Map<List<String>, Map<String,String>> LICENSES = Map.of(
+        // Key is module name and requires
+        // Value is a map of filename to the file content
+        List.of("m1"),       Map.of("LICENSE",         "m1 LICENSE",
+                                    "m1-license.txt",  "m1 license",
+                                    "test-license",    "test license v1"),
+        List.of("m2", "m1"), Map.of("m2-license",      "m2 license",
+                                    "test-license",    "test license v1"),
+        List.of("m3"),       Map.of("m3-license.md",   "m3 license",
+                                    "test-license",    "test license v3"),
+        List.of("m4"),       Map.of("test-license",    "test license v4")
+    );
+
+    @BeforeTest
+    private void setup() throws Exception {
+        List<JmodFileBuilder> builders = new ArrayList<>();
+        for (Map.Entry<List<String>, Map<String,String>> e : LICENSES.entrySet()) {
+            List<String> names = e.getKey();
+            String mn = names.get(0);
+            JmodFileBuilder builder = new JmodFileBuilder(mn);
+            builders.add(builder);
+
+            if (names.size() > 1) {
+                names.subList(1, names.size())
+                     .stream()
+                     .forEach(builder::requires);
+            }
+            e.getValue().entrySet()
+               .stream()
+               .forEach(f -> builder.licenseFile(f.getKey(), f.getValue()));
+            // generate source
+            builder.writeModuleInfo();
+        }
+
+        // create jmod file
+        for (JmodFileBuilder builder: builders) {
+            builder.build();
+        }
+
+    }
+
+    private String imageDir(String dir) {
+        return IMAGES_DIR.resolve(dir).toString();
+    }
+
+
+    @DataProvider(name = "modules")
+    public Object[][] jlinkoptions() {
+        String m2TestLicenseContent =
+            symlinkContent(Paths.get("legal", "m2", "test-license"),
+                           Paths.get("legal", "m1", "test-license"),
+                            "test license v1");
+        // options and expected header files & man pages
+        return new Object[][] {
+            {   new String [] {
+                    "test1",
+                    "--add-modules=m1",
+                },
+                Map.of( "m1/LICENSE",        "m1 LICENSE",
+                        "m1/m1-license.txt", "m1 license",
+                        "m1/test-license",   "test license v1")
+            },
+            {   new String [] {
+                    "test2",
+                    "--add-modules=m1,m2",
+                },
+                Map.of( "m1/LICENSE",        "m1 LICENSE",
+                        "m1/m1-license.txt", "m1 license",
+                        "m1/test-license",   "test license v1",
+                        "m2/m2-license",     "m2 license",
+                        "m2/test-license",   m2TestLicenseContent),
+            },
+            {   new String [] {
+                "test3",
+                "--add-modules=m2,m3",
+            },
+                Map.of( "m1/LICENSE",        "m1 LICENSE",
+                        "m1/m1-license.txt", "m1 license",
+                        "m1/test-license",   "test license v1",
+                        "m2/m2-license",     "m2 license",
+                        "m2/test-license",   m2TestLicenseContent,
+                        "m3/m3-license.md",  "m3 license",
+                        "m3/test-license",   "test license v3"),
+            },
+        };
+    }
+
+    private static String symlinkContent(Path source, Path target, String content) {
+        String osName = System.getProperty("os.name");
+        if (!osName.startsWith("Windows") && MODULE_PATH.getFileSystem()
+                                                        .supportedFileAttributeViews()
+                                                        .contains("posix")) {
+            // symlink created
+            return content;
+        } else {
+            // tiny file is created
+            Path symlink = source.getParent().relativize(target);
+            return String.format("Please see %s", symlink.toString());
+        }
+    }
+
+    @Test(dataProvider = "modules")
+    public void test(String[] opts, Map<String,String> expectedFiles) throws Exception {
+        if (Files.notExists(MODULE_PATH)) {
+            // exploded image
+            return;
+        }
+
+        String dir = opts[0];
+        List<String> options = new ArrayList<>();
+        for (int i = 1; i < opts.length; i++) {
+            options.add(opts[i]);
+        }
+
+        String mpath = MODULE_PATH.toString() + File.pathSeparator +
+                       JMODS_DIR.toString();
+        Stream.of("--module-path", mpath,
+                  "--output", imageDir(dir))
+              .forEach(options::add);
+
+        Path image = createImage(dir, options);
+
+        Files.walk(image.resolve("legal"), Integer.MAX_VALUE)
+            .filter(p -> Files.isRegularFile(p))
+            .filter(p -> p.getParent().endsWith("m1") ||
+                         p.getParent().endsWith("m2") ||
+                         p.getParent().endsWith("m3") ||
+                         p.getParent().endsWith("m4"))
+            .forEach(p -> {
+                String fn = image.resolve("legal").relativize(p)
+                                 .toString()
+                                 .replace(File.separatorChar, '/');
+                System.out.println(fn);
+                if (!expectedFiles.containsKey(fn)) {
+                    throw new RuntimeException(fn + " should not be in the image");
+                }
+                compareFileContent(p, expectedFiles.get(fn));
+            });
+    }
+
+    @Test
+    public void errorIfNotSameContent() {
+        if (Files.notExists(MODULE_PATH)) {
+            // exploded image
+            return;
+        }
+
+        String dir = "test";
+
+        String mpath = MODULE_PATH.toString() + File.pathSeparator +
+                       JMODS_DIR.toString();
+        List<String> options = Stream.of("--dedup-legal-notices",
+                                         "error-if-not-same-content",
+                                         "--module-path", mpath,
+                                         "--add-modules=m3,m4",
+                                         "--output", imageDir(dir))
+                                     .collect(Collectors.toList());
+
+        StringWriter writer = new StringWriter();
+        PrintWriter pw = new PrintWriter(writer);
+        System.out.println("jlink " + options.stream().collect(Collectors.joining(" ")));
+        int rc = JLINK_TOOL.run(pw, pw,
+                                options.toArray(new String[0]));
+        assertTrue(rc != 0);
+        assertTrue(writer.toString().trim()
+                         .matches("Error:.*/m4/legal/m4/test-license .*contain different content"));
+    }
+
+    private void compareFileContent(Path file, String content) {
+        try {
+            byte[] bytes = Files.readAllBytes(file);
+            byte[] expected = String.format("%s%n", content).getBytes();
+            assertEquals(bytes, expected, String.format("%s not matched:%nfile: %s%nexpected:%s%n",
+                file.toString(), new String(bytes), new String(expected)));
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private Path createImage(String outputDir, List<String> options) {
+        System.out.println("jlink " + options.stream().collect(Collectors.joining(" ")));
+        int rc = JLINK_TOOL.run(System.out, System.out,
+                                options.toArray(new String[0]));
+        assertTrue(rc == 0);
+
+        return IMAGES_DIR.resolve(outputDir);
+    }
+
+    private void deleteDirectory(Path dir) throws IOException {
+        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                throws IOException
+            {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                throws IOException
+            {
+                Files.delete(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    /**
+     * Builder to create JMOD file
+     */
+    class JmodFileBuilder {
+
+        final String name;
+        final Set<String> requires = new HashSet<>();
+        final Map<String, String> licenses = new HashMap<>();
+
+        JmodFileBuilder(String name) throws IOException {
+            this.name = name;
+
+            Path msrc = SRC_DIR.resolve(name);
+            if (Files.exists(msrc)) {
+                deleteDirectory(msrc);
+            }
+        }
+
+        JmodFileBuilder writeModuleInfo()throws IOException {
+            Path msrc = SRC_DIR.resolve(name);
+            Files.createDirectories(msrc);
+            Path minfo = msrc.resolve("module-info.java");
+            try (BufferedWriter bw = Files.newBufferedWriter(minfo);
+                 PrintWriter writer = new PrintWriter(bw)) {
+                writer.format("module %s {%n", name);
+                for (String req : requires) {
+                    writer.format("    requires %s;%n", req);
+                }
+                writer.format("}%n");
+            }
+            return this;
+        }
+
+        JmodFileBuilder licenseFile(String filename, String content) {
+            licenses.put(filename, content);
+            return this;
+        }
+
+        JmodFileBuilder requires(String name) {
+            requires.add(name);
+            return this;
+        }
+
+        Path build() throws IOException {
+            compileModule();
+
+            Path mdir = LEGAL_DIR.resolve(name);
+            for (Map.Entry<String,String> e : licenses.entrySet()) {
+                Files.createDirectories(mdir);
+                String filename = e.getKey();
+                String content = e.getValue();
+                Path file = mdir.resolve(filename);
+                try (BufferedWriter writer = Files.newBufferedWriter(file);
+                     PrintWriter pw = new PrintWriter(writer)) {
+                    pw.println(content);
+                }
+            }
+
+            return createJmodFile();
+        }
+
+
+        void compileModule() throws IOException {
+            Path msrc = SRC_DIR.resolve(name);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                                             "--module-source-path",
+                                             SRC_DIR.toString()));
+        }
+
+        Path createJmodFile() throws IOException {
+            Path mclasses = MODS_DIR.resolve(name);
+            Files.createDirectories(JMODS_DIR);
+            Path outfile = JMODS_DIR.resolve(name + ".jmod");
+            List<String> args = new ArrayList<>();
+            args.add("create");
+            // add classes
+            args.add("--class-path");
+            args.add(mclasses.toString());
+            if (licenses.size() > 0) {
+                args.add("--legal-notices");
+                args.add(LEGAL_DIR.resolve(name).toString());
+            }
+            args.add(outfile.toString());
+
+            if (Files.exists(outfile))
+                Files.delete(outfile);
+
+            System.out.println("jmod " +
+                args.stream().collect(Collectors.joining(" ")));
+
+            int rc = JMOD_TOOL.run(System.out, System.out,
+                                   args.toArray(new String[args.size()]));
+            if (rc != 0) {
+                throw new AssertionError("jmod failed: rc = " + rc);
+            }
+            return outfile;
+        }
+    }
+}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java
new file mode 100644
index 0000000..fb7f556
--- /dev/null
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import static jdk.testlibrary.ProcessTools.*;
+
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jlink
+ * @build CompiledVersionTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
+ * @run testng CompiledVersionTest
+ */
+
+public class CompiledVersionTest {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path IMAGE = Paths.get("image");
+    private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+    private static final String MAIN_MID = "test/jdk.test.Main";
+
+    // the names of the modules in this test
+    private static String[] modules  = new String[] { "m1", "m2", "test"};
+    private static String[] versions = new String[] { "1.0", "2-ea", "3-internal"};
+
+
+    private static boolean hasJmods() {
+        if (!Files.exists(JMODS)) {
+            System.err.println("Test skipped. NO jmods directory");
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Throwable {
+        if (!hasJmods()) return;
+
+        for (int i=0; i < modules.length; i++) {
+            String mn = modules[i];
+            String version = versions[i];
+            Path msrc = SRC_DIR.resolve(mn);
+            if (version.equals("0")) {
+                assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                    "--module-source-path", SRC_DIR.toString()));
+            } else {
+                assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                    "--module-source-path", SRC_DIR.toString(),
+                    "--module-version", version));
+            }
+        }
+
+        if (Files.exists(IMAGE)) {
+            FileUtils.deleteFileTreeUnchecked(IMAGE);
+        }
+
+        createImage(IMAGE, modules);
+    }
+
+    private void createImage(Path outputDir, String... modules) throws Throwable {
+        Path jlink = Paths.get(JAVA_HOME, "bin", "jlink");
+        String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString();
+        assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(),
+                        "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
+                        "--module-path", mp)
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+
+    /*
+     * Test the image created when linking with a module with
+     * no Packages attribute
+     */
+    @Test
+    public void testCompiledVersions() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        Stream<String> options = Stream.concat(
+            Stream.of(java.toString(), "-m", MAIN_MID, String.valueOf(modules.length)),
+            Stream.concat(Arrays.stream(modules), Arrays.stream(versions))
+        );
+
+        assertTrue(executeProcess(options.toArray(String[]::new))
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
index d74b6b8..83559fb 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java
@@ -59,7 +59,7 @@
     private void testModuleDescriptor(ModuleDescriptor md) {
         assertUnmodifiable(md.packages(), "package");
         assertUnmodifiable(md.requires(),
-                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
+                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require", null));
         for (Requires req : md.requires()) {
             assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
         }
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
index 0875db2..35d1eec 100644
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java
@@ -39,7 +39,7 @@
 /**
  * @test
  * @library /lib/testlibrary
- * @modules jdk.compiler
+ * @modules jdk.compiler jdk.jlink
  * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
  * @run testng UserModuleTest
  */
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java
new file mode 100644
index 0000000..e5c6fe8
--- /dev/null
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+
+/*
+ * Main class to verify if ModuleDescriptor carries the correct version
+ */
+public class Main {
+    static final Map<String, String> nameToVersion = new HashMap<>();
+
+    // jdk.test.Main $count $module-name... $version...
+    public static void main(String... args) throws Exception {
+        int count = args.length > 0 ? Integer.valueOf(args[0]) : 0;
+        if (count < 1 || args.length != count*2+1) {
+            throw new IllegalArgumentException(Arrays.toString(args));
+        }
+
+        List<String> modules = List.of(Arrays.copyOfRange(args, 1, 1+count));
+        List<String> versions = List.of(Arrays.copyOfRange(args, 1+count, args.length));
+        for (int i=0; i < modules.size(); i++) {
+            System.out.format("module %s expects %s version%n",
+                              modules.get(i), versions.get(i));
+            nameToVersion.put(modules.get(i), versions.get(i));
+        }
+
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
+                                                  Collections.emptyMap());
+        // check the module descriptor of a system module
+        for (int i=0; i < modules.size(); i++) {
+            String mn = modules.get(i);
+            Module module = Layer.boot().findModule(mn).orElseThrow(
+                () -> new RuntimeException(mn + " not found")
+            );
+
+            // check ModuleDescriptor from the run-time
+            validate(module.getDescriptor());
+
+            // check module-info.class in the image
+            Path path = fs.getPath("/", "modules", modules.get(i), "module-info.class");
+            validate(ModuleDescriptor.read(Files.newInputStream(path)));
+        }
+    }
+
+    static void validate(ModuleDescriptor descriptor) {
+        checkVersion(descriptor.name(), descriptor.version());
+        descriptor.requires()
+            .stream()
+            .filter(r -> !r.name().equals("java.base"))
+            .forEach(r -> checkVersion(r.name(), r.compiledVersion()));
+    }
+
+    static void checkVersion(String mn, Optional<ModuleDescriptor.Version> version) {
+        boolean matched;
+        String v = nameToVersion.get(mn);
+        if (version.isPresent()) {
+            matched = version.get().toString().equals(v);
+        } else {
+            // 0 indicate no version
+            matched = v.equals("0");
+        }
+
+        if (!matched) {
+            throw new RuntimeException(mn + " mismatched version " + version
+                + " expected: " + v);
+        }
+    }
+}
diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/module-info.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/module-info.java
new file mode 100644
index 0000000..83e15da
--- /dev/null
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/module-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test {
+    requires m1;
+    requires m2;
+    exports jdk.test;
+}
diff --git a/jdk/test/tools/jmod/JmodTest.java b/jdk/test/tools/jmod/JmodTest.java
index 9e19eef..970320a 100644
--- a/jdk/test/tools/jmod/JmodTest.java
+++ b/jdk/test/tools/jmod/JmodTest.java
@@ -470,9 +470,22 @@
     public void testHelp() {
         jmod("--help")
             .assertSuccess()
-            .resultChecker(r ->
-                assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed")
-            );
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");
+                assertFalse(r.output.contains("--do-not-resolve-by-default"));
+                assertFalse(r.output.contains("--warn-if-resolved"));
+            });
+    }
+
+    @Test
+    public void testHelpExtra() {
+        jmod("--help-extra")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");
+                assertContains(r.output, "--do-not-resolve-by-default");
+                assertContains(r.output, "--warn-if-resolved");
+            });
     }
 
     @Test
diff --git a/jdk/test/tools/jmod/hashes/HashesTest.java b/jdk/test/tools/jmod/hashes/HashesTest.java
index 22752e7..8d4b2f6 100644
--- a/jdk/test/tools/jmod/hashes/HashesTest.java
+++ b/jdk/test/tools/jmod/hashes/HashesTest.java
@@ -50,14 +50,13 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.spi.ToolProvider;
 import java.util.stream.Collectors;
 
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModulePath;
 
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
@@ -103,54 +102,53 @@
     @Test
     public void test() throws Exception {
         for (String mn : modules) {
-            assertFalse(hashes(mn).isPresent());
+            assertTrue(hashes(mn) == null);
         }
 
         // hash m1 in m2
         jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1");
-        checkHashes(hashes("m2").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
 
         // hash m1 in m2
         jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m2").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
 
         // create m2.jmod with no hash
         jmod("m2");
         // run jmod hash command to hash m1 in m2 and m3
         runJmod(Arrays.asList("hash", "--module-path", jmods.toString(),
                 "--hash-modules", ".*"));
-        checkHashes(hashes("m2").get(), "m1");
-        checkHashes(hashes("m3").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
+        checkHashes(hashes("m3"), "m1");
 
         jmod("org.bar");
         jmod("org.foo");
 
         jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*");
-        checkHashes(hashes("org.bar").get(), "org.foo");
+        checkHashes(hashes("org.bar"), "org.foo");
 
         jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m3").get(), "org.foo", "org.bar", "m1");
+        checkHashes(hashes("m3"), "org.foo", "org.bar", "m1");
     }
 
     private void checkHashes(ModuleHashes hashes, String... hashModules) {
         assertTrue(hashes.names().equals(Set.of(hashModules)));
     }
 
-    private Optional<ModuleHashes> hashes(String name) throws Exception {
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, jmods.resolve(name + ".jmod"));
+    private ModuleHashes hashes(String name) throws Exception {
+        ModuleFinder finder = new ModulePath(Runtime.version(),
+                                             true,
+                                             jmods.resolve(name + ".jmod"));
         ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
         ModuleReader reader = mref.open();
         try (InputStream in = reader.open("module-info.class").get()) {
-            ModuleDescriptor md = ModuleDescriptor.read(in);
-            JavaLangModuleAccess jmla = SharedSecrets.getJavaLangModuleAccess();
-            Optional<ModuleHashes> hashes = jmla.hashes(md);
+            ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
             System.out.format("hashes in module %s %s%n", name,
-                              hashes.isPresent() ? "present" : "absent");
-            if (hashes.isPresent()) {
-                hashes.get().names().stream()
+                    (hashes != null) ? "present" : "absent");
+            if (hashes != null) {
+                hashes.names().stream()
                     .sorted()
-                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.get().hashFor(n)));
+                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.hashFor(n)));
             }
             return hashes;
         } finally {
diff --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java
index 344730a..dbd6255 100644
--- a/jdk/test/tools/launcher/MiscTests.java
+++ b/jdk/test/tools/launcher/MiscTests.java
@@ -80,8 +80,8 @@
         createFile(new File(mainClass + ".java"), scratch);
 
         compile(mainClass + ".java",
-                "--add-modules=jdk.crypto.pkcs11",
-                "--add-exports=jdk.crypto.pkcs11/sun.security.pkcs11=ALL-UNNAMED");
+                "--add-modules=jdk.crypto.token",
+                "--add-exports=jdk.crypto.token/sun.security.pkcs11=ALL-UNNAMED");
 
         File testJar = new File("Foo.jar");
         testJar.delete();
diff --git a/jdk/test/tools/launcher/RunpathTest.java b/jdk/test/tools/launcher/RunpathTest.java
index 00e7573..2730f5d 100644
--- a/jdk/test/tools/launcher/RunpathTest.java
+++ b/jdk/test/tools/launcher/RunpathTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,7 @@
     }
 
     void testRpath() {
-        String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib/" + getJreArch() + ".*";
+        String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib.*";
         elfCheck(javaCmd, expectedRpath);
     }
 
diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java
index afbde07..aa507b6 100644
--- a/jdk/test/tools/launcher/VersionCheck.java
+++ b/jdk/test/tools/launcher/VersionCheck.java
@@ -51,6 +51,7 @@
         "jaccessinspector-32",
         "jaccesswalker",
         "jaccesswalker-32",
+        "jaotc",
         "javaw",
         "javaws",
         "jcontrol",
@@ -72,6 +73,7 @@
         "jaccessinspector-32",
         "jaccesswalker",
         "jaccesswalker-32",
+        "jaotc",
         "jar",
         "jarsigner",
         "java-rmi",
diff --git a/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java b/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java
new file mode 100644
index 0000000..5df7f0d
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8168836
+ * @summary Basic argument validation for --add-exports
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddExportsTestWarningError CompilerUtils ModuleSourceBuilder
+ * @build jdk.testlibrary.*
+ * @run testng AddExportsTestWarningError
+ */
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.OutputAnalyzer;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddExportsTestWarningError {
+
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path SRC_DIR = Paths.get("src");
+    private static final String M1_MAIN = "m1/p1.C1";
+    private static final String M3_MAIN = "m3/p3.C3";
+
+    @BeforeTest
+    public void setup() throws Exception {
+        ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR);
+        builder.writeJavaFiles("m1",
+            "module m1 { }",
+            "package p1; public class C1 { " +
+                "    public static void main(String... args) {}" +
+                "}");
+
+        builder.writeJavaFiles("m2",
+            "module m2 { requires m1; exports p2; }",
+            "package p2; public class C2 {  private p1.C1 c1; }");
+
+        builder.writeJavaFiles("m3",
+            "module m3 { requires m2; }",
+            "package p3; class C3 { " +
+                "    p1.C1 c; " +
+                "    public static void main(String... args) { new p2.C2(); }" +
+                "}");
+
+        builder.compile("m1", MODS_DIR);
+        builder.compile("m2", MODS_DIR, "--add-exports", "m1/p1=m2");
+        builder.compile("m3", MODS_DIR, "--add-exports", "m1/p1=m3");
+    }
+
+
+    @DataProvider(name = "goodcases")
+    public Object[][] goodCases() {
+        return new Object[][]{
+
+            // empty items
+            { "m1/p1=,m2,m3",       null },
+            { "m1/p1=m2,,m3",       null },
+            { "m1/p1=m2,m3,",       null },
+
+            // duplicates
+            { "m1/p1=m2,m2,m3,,",   null },
+
+        };
+    }
+
+
+    @Test(dataProvider = "goodcases")
+    public void test(String value, String ignore) throws Exception {
+        testNoWarning(value);
+    }
+
+
+    @DataProvider(name = "illFormedAddExports")
+    public Object[][] illFormedAddExports() {
+        return new Object[][]{
+            { "m1",         "Unable to parse --add-exports <module>=<value>: m1"},
+
+            // missing source part
+            { "=m2",        "Unable to parse --add-exports <module>=<value>: =m2"},
+            { "/=m2",       "Unable to parse --add-exports <module>/<package>: /" },
+            { "m1=m2",      "Unable to parse --add-exports <module>/<package>: m1" },
+            { "/p1=m2",     "Unable to parse --add-exports <module>/<package>: /p1" },
+            { "m1p1=m2",    "Unable to parse --add-exports <module>/<package>: m1p1" },
+
+            // empty list, missing target
+            { "m1/p1=",     "Unable to parse --add-exports <module>=<value>: m1/p1=" },
+            { "m1/p1=,,",   "Target must be specified: --add-exports m1/p1=,," },
+        };
+    }
+
+    @Test(dataProvider = "illFormedAddExports")
+    public void testIllFormedAddExports(String value, String msg) throws Exception {
+        testError(value, msg);
+    }
+
+
+    @DataProvider(name = "unknownNames")
+    public Object[][] unknownNames() {
+        return new Object[][]{
+
+            // source not found
+            {"DoesNotExist/p=m1",  "WARNING: Unknown module: DoesNotExist specified in --add-exports"},
+            {"m1/DoesNotExist=m2", "WARNING: package DoesNotExist not in m1"},
+
+            // target not found
+            {"m1/p1=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified in --add-exports"},
+
+            // bad names
+            {"m*/p1=m2",           "WARNING: Unknown module: m* specified in --add-exports"},
+            {"m1/p!=m2",           "WARNING: package p! not in m1"},
+            {"m1/p1=m!",           "WARNING: Unknown module: m! specified in --add-exports"},
+
+        };
+    }
+
+
+    @Test(dataProvider = "unknownNames")
+    public void testUnknownNames(String value, String msg) throws Exception {
+        testWarning(value, msg);
+    }
+
+
+    @DataProvider(name = "missingArguments")
+    public Object[][] missingArguments() {
+        return new Object[][]{
+            { new String[] { "--add-exports" },
+                "Error: --add-exports requires modules to be specified"},
+
+            { new String[] { "--add-exports=" },
+                "Error: --add-exports= requires modules to be specified" },
+
+            { new String[] { "--add-exports", "" },
+                "Error: --add-exports requires modules to be specified"}
+
+        };
+    }
+
+
+    @Test(dataProvider = "missingArguments")
+    public void testMissingArguments(String[] options, String msg) throws Exception {
+        String[] args = Stream.concat(Arrays.stream(options),
+                                      Stream.of("-version"))
+                              .toArray(String[]::new);
+        int exitValue = executeTestJava(args)
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain(msg)
+            .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+     private void testWarning(String value, String msg) throws Exception {
+        int exitValue =
+            executeTestJava("--add-exports", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M1_MAIN)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain(msg)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    private void testError(String value, String msg) throws Exception {
+        int exitValue =
+            executeTestJava("--add-exports", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M1_MAIN)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain(msg)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+    private void testNoWarning(String value) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(new BufferedOutputStream(baos));
+        OutputAnalyzer outputAnalyzer =
+            executeTestJava("--add-exports", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M3_MAIN)
+                .outputTo(ps)
+                .errorTo(ps);
+
+        assertTrue(outputAnalyzer.getExitValue() == 0);
+
+        System.out.println(baos.toString());
+        String[] output = baos.toString().split("\\R");
+        assertFalse(Arrays.stream(output)
+                          .filter(s -> !s.matches("WARNING: Module name .* may soon be illegal"))
+                          .filter(s -> s.startsWith("WARNING:"))
+                          .findAny().isPresent());
+
+    }
+}
diff --git a/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java b/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java
new file mode 100644
index 0000000..325ca32
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8168836
+ * @summary  Basic argument validation for --add-reads
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddReadsTestWarningError CompilerUtils ModuleSourceBuilder
+ * @build jdk.testlibrary.*
+ * @run testng AddReadsTestWarningError
+ */
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.OutputAnalyzer;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddReadsTestWarningError {
+
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path SRC_DIR = Paths.get("src");
+    private static final String M1_MAIN = "m1/p1.C1";
+    private static final String M4_MAIN = "m4/p4.C4";
+
+    @BeforeTest
+    public void setup() throws Exception {
+        ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR);
+        builder.writeJavaFiles("m1",
+            "module m1 { requires m4; }",
+            "package p1; public class C1 { " +
+            "    public static void main(String... args) {" +
+            "        p2.C2 c2 = new p2.C2();" +
+            "        p3.C3 c3 = new p3.C3();" +
+            "    }" +
+            "}"
+        );
+
+        builder.writeJavaFiles("m2",
+            "module m2 { exports p2; }",
+            "package p2; public class C2 { }"
+        );
+
+        builder.writeJavaFiles("m3",
+            "module m3 { exports p3; }",
+            "package p3; public class C3 { }"
+        );
+
+        builder.writeJavaFiles("m4",
+            "module m4 { requires m2; requires m3; }",
+            "package p4; public class C4 { " +
+            "    public static void main(String... args) {}" +
+            "}"
+        );
+
+        builder.compile("m2", MODS_DIR);
+        builder.compile("m3", MODS_DIR);
+        builder.compile("m4", MODS_DIR);
+        builder.compile("m1", MODS_DIR, "--add-reads", "m1=m2,m3");
+    }
+
+
+    @DataProvider(name = "goodcases")
+    public Object[][] goodCases() {
+        return new Object[][]{
+            // empty items
+            { "m1=,m2,m3",       null },
+            { "m1=m2,,m3",       null },
+            { "m1=m2,m3,",       null },
+
+            // duplicates
+            { "m1=m2,m2,m3,,",  null },
+
+        };
+    }
+
+
+    @Test(dataProvider = "goodcases")
+    public void test(String value, String ignore) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(new BufferedOutputStream(baos));
+        OutputAnalyzer outputAnalyzer =
+            executeTestJava("--add-reads", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M1_MAIN)
+                .outputTo(ps)
+                .errorTo(ps);
+
+        assertTrue(outputAnalyzer.getExitValue() == 0);
+
+        System.out.println(baos.toString());
+        String[] output = baos.toString().split("\\R");
+        assertFalse(Arrays.stream(output)
+                          .filter(s -> !s.matches("WARNING: Module name .* may soon be illegal"))
+                          .filter(s -> s.startsWith("WARNING:"))
+                          .findAny().isPresent());
+    }
+
+
+    @DataProvider(name = "illFormedAddReads")
+    public Object[][] illFormedAddReads() {
+        return new Object[][]{
+            { "m1",         "Unable to parse --add-reads <module>=<value>: m1" },
+
+            // missing source part
+            { "=m2",        "Unable to parse --add-reads <module>=<value>: =m2" },
+
+            // empty list, missing target
+            { "m1=",        "Unable to parse --add-reads <module>=<value>: m1=" },
+
+            // empty list
+            { "m1=,,",      "Target must be specified: --add-reads m1=,," },
+        };
+    }
+
+
+    @Test(dataProvider = "illFormedAddReads")
+    public void testIllFormedAddReads(String value, String msg) throws Exception {
+        int exitValue =
+            executeTestJava("--add-reads", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M4_MAIN)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain(msg)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+
+    @DataProvider(name = "unknownNames")
+    public Object[][] unknownNames() {
+        return new Object[][]{
+
+            // source not found
+            {"DoesNotExist=m2",    "WARNING: Unknown module: DoesNotExist specified in --add-reads"},
+
+            // target not found
+            {"m2=DoesNotExist",    "WARNING: Unknown module: DoesNotExist specified in --add-reads"},
+
+            // bad names
+            {"m*=m2",              "WARNING: Unknown module: m* specified in --add-reads"},
+            {"m2=m!",              "WARNING: Unknown module: m! specified in --add-reads"},
+
+        };
+    }
+
+    @Test(dataProvider = "unknownNames")
+    public void testUnknownNames(String value, String msg) throws Exception {
+        int exitValue =
+            executeTestJava("--add-reads", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", M4_MAIN)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain(msg)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    @DataProvider(name = "missingArguments")
+    public Object[][] missingArguments() {
+        return new Object[][]{
+            { new String[] {"--add-reads" },
+                "Error: --add-reads requires modules to be specified"},
+
+            { new String[] { "--add-reads=" },
+                "Error: --add-reads= requires modules to be specified"},
+
+            { new String[] { "--add-reads", "" },
+                "Error: --add-reads requires modules to be specified"},
+        };
+    }
+
+    @Test(dataProvider = "missingArguments")
+    public void testEmptyArgument(String[] options, String msg) throws Exception {
+        String[] args = Stream.concat(Arrays.stream(options), Stream.of("-version"))
+                              .toArray(String[]::new);
+        int exitValue = executeTestJava(args)
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .shouldContain(msg)
+            .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+}
diff --git a/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java
index 2618fba..208e36f 100644
--- a/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java
+++ b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java
@@ -24,7 +24,7 @@
 /**
  * @test
  * @library /lib/testlibrary
- * @modules java.desktop java.compact1 jdk.compiler
+ * @modules java.desktop java.logging jdk.compiler
  * @build LimitModsTest CompilerUtils jdk.testlibrary.*
  * @run testng LimitModsTest
  * @summary Basic tests for java --limit-modules
@@ -83,13 +83,12 @@
         assertTrue(exitValue == 0);
 
 
-        // java --limit-modules java.compact1 --list-modules
-        exitValue = executeTestJava("--limit-modules", "java.compact1", "--list-modules")
+        // java --limit-modules java.logging --list-modules
+        exitValue = executeTestJava("--limit-modules", "java.logging", "--list-modules")
             .outputTo(System.out)
             .errorTo(System.out)
             .shouldContain("java.base")
             .shouldContain("java.logging")
-            .shouldContain("java.compact1")
             .shouldNotContain("java.xml")
             .getExitValue();
 
diff --git a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java
index eb21d2d..b386f40 100644
--- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java
+++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java
@@ -147,12 +147,12 @@
     @Test
     public void testListWithLimitMods1() throws Exception {
         OutputAnalyzer output
-            = executeTestJava("--limit-modules", "java.compact1", "--list-modules")
+            = executeTestJava("--limit-modules", "java.management", "--list-modules")
                 .outputTo(System.out)
                 .errorTo(System.out);
-        output.shouldContain("java.compact1");
+        output.shouldContain("java.rmi");
         output.shouldContain("java.base");
-        output.shouldNotContain("java.xml");
+        output.shouldNotContain("java.scripting");
         assertTrue(output.getExitValue() == 0);
     }
 
@@ -161,7 +161,7 @@
     public void testListWithLimitMods2() throws Exception {
         OutputAnalyzer output
             = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--limit-modules", "java.compact1",
+                              "--limit-modules", "java.management",
                               "--list-modules")
                 .outputTo(System.out)
                 .errorTo(System.out);
diff --git a/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java b/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java
new file mode 100644
index 0000000..711bedf
--- /dev/null
+++ b/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8168836
+ * @summary Basic argument validation for --patch-module
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build PatchTestWarningError CompilerUtils JarUtils jdk.testlibrary.*
+ * @run testng PatchTestWarningError
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+/**
+ * This test
+ * See PatchTestWarningError for test description.
+ */
+
+@Test
+public class PatchTestWarningError {
+
+    // top-level source directory
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    // source/destination tree for the test module
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // source/destination tree for patch tree 1
+    private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
+    private static final Path PATCHES1_DIR = Paths.get("patches1");
+
+    // source/destination tree for patch tree 2
+    private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
+    private static final Path PATCHES2_DIR = Paths.get("patches2");
+
+    // patch path for java.base
+    private static final String PATCHES_PATH =
+        PATCHES1_DIR.resolve("java.base") + File.pathSeparator +
+            PATCHES2_DIR.resolve("java.base");
+
+    // the classes overridden or added with --patch-module
+    private static final String[] CLASSES = {
+
+        // java.base = boot loader
+        "java.base/java.text.Annotation",           // override class
+        "java.base/java.text.AnnotationBuddy",      // add class to package
+        "java.base/java.lang2.Object",              // new package
+
+    };
+
+
+    @BeforeTest
+    public void setup() throws Exception {
+
+        // javac -d mods/test src/test/**
+        boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
+                                                MODS_DIR.resolve("test"));
+        assertTrue(compiled, "classes did not compile");
+
+        // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/**
+        Path src = SRC1_DIR.resolve("java.base");
+        Path output = PATCHES1_DIR.resolve(src.getFileName());
+        Files.createDirectories(output);
+        String mn = src.getFileName().toString();
+        compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+        assertTrue(compiled, "classes did not compile");
+
+        // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/**
+        src = SRC2_DIR.resolve("java.base");
+        output = PATCHES2_DIR.resolve(src.getFileName());
+        Files.createDirectories(output);
+        mn = src.getFileName().toString();
+        compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
+        assertTrue(compiled, "classes did not compile");
+
+    }
+
+    /**
+     * Test with --patch-module options patching the same module
+     */
+    public void testDuplicateModule() throws Exception {
+        int exitValue =
+            executeTestJava("--patch-module", "java.base=" + PATCHES1_DIR.resolve("java.base"),
+                            "--patch-module", "java.base=" + PATCHES2_DIR.resolve("java.base"),
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", "test/jdk.test.Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                // error output by VM
+                .shouldContain("Cannot specify java.base more than once to --patch-module")
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+
+    @DataProvider(name = "emptyItem")
+    public Object[][] emptyItems() {
+        String patch1 = PATCHES1_DIR.resolve("java.base").toString();
+        String patch2 = PATCHES2_DIR.resolve("java.base").toString();
+        String pathSep = File.pathSeparator;
+        return new Object[][]{
+
+            { "java.base="+ pathSep + patch1 + pathSep + patch2,            null },
+            { "java.base="+ patch1 + pathSep + pathSep + patch2,            null },
+            { "java.base="+ patch1 + pathSep + patch2 + pathSep + pathSep,  null },
+        };
+    }
+
+    /**
+     * Empty item in a non-empty path list
+     */
+    @Test(dataProvider = "emptyItem")
+    public void testEmptyItem(String value, String msg) throws Exception {
+        // the argument to the test is the list of classes overridden or added
+        String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
+
+        int exitValue =
+            executeTestJava("--patch-module", value,
+                            "--add-exports", "java.base/java.lang2=test",
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", "test/jdk.test.Main", arg)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test bad module name that should emit a warning
+     */
+    public void testBadName() throws Exception {
+        // the argument to the test is the list of classes overridden or added
+        String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
+
+        int exitValue =
+            executeTestJava("--patch-module", "DoesNotExist=tmp",
+                            "--patch-module", "java.base=" + PATCHES_PATH,
+                            "--add-exports", "java.base/java.lang2=test",
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", "test/jdk.test.Main", arg)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("WARNING: Unknown module: DoesNotExist specified in --patch-module")
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+    @DataProvider(name = "badArguments")
+    public Object[][] badArguments() {
+        return new Object[][]{
+
+            // source not found
+            { "=tmp",            "Unable to parse --patch-module <module>=<value>: =tmp" },
+
+            // target not found: check by VM
+            { "java.base",       "Missing '=' in --patch-module specification" },
+            { "foo",             "Missing '=' in --patch-module specification" },
+
+            // target not found
+            { "java.base=",      "Unable to parse --patch-module <module>=<value>: java.base="  },
+            { "java.base=" + File.pathSeparator,
+              "Target must be specified: --patch-module java.base=" + File.pathSeparator }
+        };
+    }
+
+    /**
+     * Test ill-formed argument to --patch-module
+     */
+    @Test(dataProvider = "badArguments")
+    public void testBadArgument(String value, String msg) throws Exception {
+        int exitValue =
+            executeTestJava("--patch-module", value,
+                            "--module-path", MODS_DIR.toString(),
+                            "-m", "test/jdk.test.Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain(msg)
+                .getExitValue();
+
+        assertTrue(exitValue != 0);
+    }
+}
diff --git a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java
index a56c8dd..a774fc7 100644
--- a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java
+++ b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java
@@ -29,4 +29,8 @@
  */
 public final class SystemModules {
     public static final String[] MODULE_NAMES = new String[0];
+
+    public static boolean hasSplitPackages() {
+        return true;
+    }
 }
diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
index 144405e..97e5f76 100644
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
@@ -41,6 +41,8 @@
 import com.sun.tools.classfile.CompilationID_attribute;
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
@@ -80,9 +82,9 @@
 import com.sun.tools.classfile.ModuleHashes_attribute;
 import com.sun.tools.classfile.ModuleHashes_attribute.Entry;
 import com.sun.tools.classfile.ModuleMainClass_attribute;
+import com.sun.tools.classfile.ModuleResolution_attribute;
 import com.sun.tools.classfile.ModuleTarget_attribute;
 import com.sun.tools.classfile.ModulePackages_attribute;
-import com.sun.tools.classfile.ModuleVersion_attribute;
 import com.sun.tools.classfile.Opcode;
 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -670,6 +672,40 @@
     }
 
     @Override
+    public String visitModule(CONSTANT_Module_info info, Integer p) {
+        String value = slist.get(p);
+        if (value == null) {
+            try {
+                value = visit(cfpool.get(info.name_index), info.name_index);
+                slist.set(p, value);
+                xpool.add(new Element("CONSTANT_Module",
+                        new String[]{"id", p.toString()},
+                        value));
+            } catch (ConstantPoolException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public String visitPackage(CONSTANT_Package_info info, Integer p) {
+        String value = slist.get(p);
+        if (value == null) {
+            try {
+                value = visit(cfpool.get(info.name_index), info.name_index);
+                slist.set(p, value);
+                xpool.add(new Element("CONSTANT_Package",
+                        new String[]{"id", p.toString()},
+                        value));
+            } catch (ConstantPoolException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return value;
+    }
+
+    @Override
     public String visitDouble(CONSTANT_Double_info c, Integer p) {
         String value = slist.get(p);
         if (value == null) {
@@ -1495,20 +1531,20 @@
     }
 
     @Override
-    public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
-        Element e = new Element(x.getCpString(attr.attribute_name_index));
-        e.add(x.getCpString(attr.os_name_index));
-        e.add(x.getCpString(attr.os_arch_index));
-        e.add(x.getCpString(attr.os_version_index));
+    public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) {
+        Element e = new Element("ModuleResolution");
+        e.setAttr("flags", Integer.toString(attr.resolution_flags));
         e.trimToSize();
         p.add(e);
         return null;
     }
 
     @Override
-    public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
+    public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
-        e.add(x.getCpString(attr.version_index));
+        e.add(x.getCpString(attr.os_name_index));
+        e.add(x.getCpString(attr.os_arch_index));
+        e.add(x.getCpString(attr.os_version_index));
         e.trimToSize();
         p.add(e);
         return null;
diff --git a/make/Bundles.gmk b/make/Bundles.gmk
index 5fa35e1..04e6857 100644
--- a/make/Bundles.gmk
+++ b/make/Bundles.gmk
@@ -43,16 +43,21 @@
 $(eval $(call IncludeCustomExtension, , Bundles-pre.gmk))
 ################################################################################
 # BUNDLE : Name of bundle to create
-# FILES : Files in BASE_DIR to add to bundle
-# SPECIAL_INCLUDES : List of directories inside BASE_DIR to look for additional
+# FILES : Files in BASE_DIRS to add to bundle
+# SPECIAL_INCLUDES : List of directories inside BASE_DIRS to look for additional
 #     files in. These files will not get proper dependency handling. Use when
 #     files or directories may contain spaces.
-# BASE_DIR : Base directory for the root dir in the bundle.
+# BASE_DIRS : Base directories for the root dir in the bundle.
 # SUBDIR : Optional name of root dir in bundle.
 SetupBundleFile = $(NamedParamsMacroTemplate)
 define SetupBundleFileBody
 
-  $1_RELATIVE_FILES := $$(patsubst $$($1_BASE_DIR)/%, %, $$($1_FILES))
+  $$(foreach d, $$($1_BASE_DIRS), \
+    $$(eval $1_$$d_RELATIVE_FILES := $$$$(patsubst $$d/%, %, \
+        $$$$(filter $$d/%, $$$$($1_FILES)))) \
+    $$(eval $1_$$d_LIST_FILE := \
+        $(SUPPORT_OUTPUTDIR)/bundles/_$1_$$$$(subst /,_,$$$$(patsubst $(TOPDIR)/%,%,$$d)_files)) \
+  )
 
   ifneq ($$(filter %.tar.gz, $$($1_BUNDLE_NAME)), )
     $1_TYPE := tar.gz
@@ -65,55 +70,65 @@
   $$(call SetIfEmpty, $1_UNZIP_DEBUGINFO, false)
 
   $(BUNDLES_OUTPUTDIR)/$$($1_BUNDLE_NAME): $$($1_FILES)
-	$$(eval $$(call ListPathsSafely, \
-	    $1_RELATIVE_FILES, \
-	    $(SUPPORT_OUTPUTDIR)/bundles/_$1_files))
+	$$(foreach d, $$($1_BASE_DIRS), \
+	  $$(eval $$(call ListPathsSafely, \
+	      $1_$$d_RELATIVE_FILES, $$($1_$$d_LIST_FILE))) \
+	)
 	$$(call MakeDir, $$(@D))
         ifneq ($$($1_SPECIAL_INCLUDES), )
 	  $$(foreach i, $$($1_SPECIAL_INCLUDES), \
-	      ($(CD) $$($1_BASE_DIR) && $(FIND) $$i \
-	          >> $(SUPPORT_OUTPUTDIR)/bundles/_$1_files ) ; )
+	    $$(foreach d, $$d, \
+	      ($(CD) $$d && $(FIND) $$i \
+	          >> $(SUPPORT_OUTPUTDIR)/bundles/_$1_files ) ; ))
         endif
-        ifneq ($$($1_SUBDIR), )
-          ifeq ($$($1_TYPE)-$(TAR_SUPPORTS_TRANSFORM)-$$($1_UNZIP_DEBUGINFO), tar.gz-true-false)
-	    $(CD) $$($1_BASE_DIR) \
-	        && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
-                    -$(TAR_INCLUDE_PARAM) $(SUPPORT_OUTPUTDIR)/bundles/_$1_files \
-	            --transform 's|^|$$($1_SUBDIR)/|' $(TAR_IGNORE_EXIT_VALUE) ) \
-	        | $(GZIP) > $$@
-          else
-            # If a subdir has been specified, copy all files into a temporary
-            # location with this subdir before creating the tar file
-	    $(RM) -r $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR)
-	    $(MKDIR) -p $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR)
-	    ( $(CD) $$($1_BASE_DIR) \
-	        && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $(SUPPORT_OUTPUTDIR)/bundles/_$1_files \
-	            $(TAR_IGNORE_EXIT_VALUE) ) \
-	        | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )
-            # Unzip any zipped debuginfo files
-            ifeq ($$($1_UNZIP_DEBUGINFO), true)
-	      for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \
-	        $(CD) $$$${f%/*} && $(UNZIP) -q $$$${f} && $(RM) $$$${f}; \
-	      done
-            endif
-            ifeq ($$($1_TYPE), tar.gz)
-	      $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && \
-	          ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) $$($1_SUBDIR) $(TAR_IGNORE_EXIT_VALUE) ) \
-	          | $(GZIP) > $$@
-            else ifeq ($$($1_TYPE), zip)
-	      $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && $(ZIPEXE) -qr $$@ .
-            endif
-          endif
+        ifeq ($$($1_SUBDIR)-$$($1_TYPE)-$$($1_UNZIP_DEBUGINFO), .-zip-false)
+          # If no subdir is specified, zip can be done directly from BASE_DIRS.
+	  $$(foreach d, $$($1_BASE_DIRS), \
+	    ( $(CD) $$d \
+	    && $(ZIPEXE) -qru $$@ . -i@$$($1_$$d_LIST_FILE) \
+	    || test "$$$$?" = "12" )$$(NEWLINE))
+        else ifeq ($$($1_SUBDIR)-$$($1_TYPE)-$$($1_UNZIP_DEBUGINFO)-$$(words $$($1_BASE_DIRS)), \
+            .-tar.gz-false-1)
+          # If no subdir is specified and only one BASE_DIR, tar.gz can be done
+          # directly from BASE_DIR.
+	  $(CD) $$($1_BASE_DIRS) \
+	      && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+	          -$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
+	          $(TAR_IGNORE_EXIT_VALUE) ) \
+	      | $(GZIP) > $$@
+        else ifeq ($$($1_TYPE)-$(TAR_SUPPORTS_TRANSFORM)-$$($1_UNZIP_DEBUGINFO)-$$(words $$($1_BASE_DIRS)), \
+            tar.gz-true-false-1)
+          # If only one BASE_DIR, but with a SUBDIR set, tar.gz can use the
+          # transform option to create bundle directly from the BASE_DIR.
+	  $(CD) $$($1_BASE_DIRS) \
+	      && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+	          -$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
+	          $$(if $$($1_SUBDIR), --transform 's|^|$$($1_SUBDIR)/|') \
+	          $(TAR_IGNORE_EXIT_VALUE) ) \
+	      | $(GZIP) > $$@
         else
+          # In all other cases, need to copy all files into a temporary location
+          # before creation bundle.
+	  $(RM) -r $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR)
+	  $(MKDIR) -p $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR)
+	  $$(foreach d, $$($1_BASE_DIRS), \
+	    ( $(CD) $$d \
+	    && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $$($1_$$d_LIST_FILE) \
+	        $(TAR_IGNORE_EXIT_VALUE) ) \
+	    | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )$$(NEWLINE) )
+          # Unzip any zipped debuginfo files
+          ifeq ($$($1_UNZIP_DEBUGINFO), true)
+	    for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \
+	      $(CD) $$$${f%/*} && $(UNZIP) -q $$$${f} && $(RM) $$$${f}; \
+	    done
+          endif
           ifeq ($$($1_TYPE), tar.gz)
-	    $(CD) $$($1_BASE_DIR) \
-	        && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
-	            -$(TAR_INCLUDE_PARAM) $(SUPPORT_OUTPUTDIR)/bundles/_$1_files \
-	            $(TAR_IGNORE_EXIT_VALUE) ) \
-	        | $(GZIP) > $$@
+	    $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && \
+	    ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+	        $$(if $$($1_SUBDIR), $$($1_SUBDIR), .) $(TAR_IGNORE_EXIT_VALUE) ) \
+	    | $(GZIP) > $$@
           else ifeq ($$($1_TYPE), zip)
-	    $(CD) $$($1_BASE_DIR) \
-	        && $(ZIPEXE) -qr $$@ . -i@$(SUPPORT_OUTPUTDIR)/bundles/_$1_files
+	    $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && $(ZIPEXE) -qr $$@ .
           endif
         endif
 
@@ -219,7 +234,7 @@
       BUNDLE_NAME := $(JDK_BUNDLE_NAME), \
       FILES := $(JDK_BUNDLE_FILES), \
       SPECIAL_INCLUDES := $(JDK_SPECIAL_INCLUDES), \
-      BASE_DIR := $(JDK_IMAGE_DIR), \
+      BASE_DIRS := $(JDK_IMAGE_DIR), \
       SUBDIR := $(JDK_BUNDLE_SUBDIR), \
   ))
 
@@ -228,7 +243,7 @@
   $(eval $(call SetupBundleFile, BUILD_JRE_BUNDLE, \
       BUNDLE_NAME := $(JRE_BUNDLE_NAME), \
       FILES := $(JRE_BUNDLE_FILES), \
-      BASE_DIR := $(JRE_IMAGE_DIR), \
+      BASE_DIRS := $(JRE_IMAGE_DIR), \
       SUBDIR := $(JRE_BUNDLE_SUBDIR), \
   ))
 
@@ -237,7 +252,7 @@
   $(eval $(call SetupBundleFile, BUILD_JDK_SYMBOLS_BUNDLE, \
       BUNDLE_NAME := $(JDK_SYMBOLS_BUNDLE_NAME), \
       FILES := $(JDK_SYMBOLS_BUNDLE_FILES), \
-      BASE_DIR := $(JDK_IMAGE_DIR), \
+      BASE_DIRS := $(JDK_IMAGE_DIR) $(wildcard $(SYMBOLS_IMAGE_DIR)), \
       SUBDIR := $(JDK_BUNDLE_SUBDIR), \
       UNZIP_DEBUGINFO := true, \
   ))
@@ -247,7 +262,7 @@
   $(eval $(call SetupBundleFile, BUILD_JRE_SYMBOLS_BUNDLE, \
       BUNDLE_NAME := $(JRE_SYMBOLS_BUNDLE_NAME), \
       FILES := $(JRE_SYMBOLS_BUNDLE_FILES), \
-      BASE_DIR := $(JRE_IMAGE_DIR), \
+      BASE_DIRS := $(JRE_IMAGE_DIR), \
       SUBDIR := $(JRE_BUNDLE_SUBDIR), \
       UNZIP_DEBUGINFO := true, \
   ))
@@ -257,7 +272,7 @@
   $(eval $(call SetupBundleFile, BUILD_DEMOS_BUNDLE, \
       BUNDLE_NAME := $(DEMOS_BUNDLE_NAME), \
       FILES := $(DEMOS_BUNDLE_FILES), \
-      BASE_DIR := $(JDK_IMAGE_DIR), \
+      BASE_DIRS := $(JDK_IMAGE_DIR), \
       SUBDIR := $(JDK_BUNDLE_SUBDIR), \
   ))
 
@@ -272,7 +287,7 @@
   $(eval $(call SetupBundleFile, BUILD_TEST_BUNDLE, \
       BUNDLE_NAME := $(TEST_BUNDLE_NAME), \
       FILES := $(TEST_BUNDLE_FILES), \
-      BASE_DIR := $(TEST_IMAGE_DIR), \
+      BASE_DIRS := $(TEST_IMAGE_DIR), \
   ))
 
   TEST_TARGETS += $(BUILD_TEST_BUNDLE)
@@ -286,7 +301,7 @@
   $(eval $(call SetupBundleFile, BUILD_DOCS_BUNDLE, \
       BUNDLE_NAME := $(DOCS_BUNDLE_NAME), \
       FILES := $(DOCS_BUNDLE_FILES), \
-      BASE_DIR := $(DOCS_IMAGE_DIR), \
+      BASE_DIRS := $(DOCS_IMAGE_DIR), \
       SUBDIR := docs, \
   ))
 
diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk
index 59d317a..b9c7c76 100644
--- a/make/CompileJavaModules.gmk
+++ b/make/CompileJavaModules.gmk
@@ -344,8 +344,6 @@
 
 ################################################################################
 
-jdk.accessibility_ADD_JAVAC_FLAGS := -Xlint:-exports
-
 ################################################################################
 
 jdk.compiler_ADD_JAVAC_FLAGS := -Xdoclint:all/protected '-Xdoclint/package:-com.sun.tools.*,-jdk.internal.*' \
@@ -448,7 +446,51 @@
 
 ################################################################################
 
-jdk.vm.ci_ADD_JAVAC_FLAGS := -Xlint:-exports
+# -parameters provides method's parameters information in class file,
+# JVMCI compilers make use of that information for various sanity checks.
+# Don't use Indy strings concatenation to have good JVMCI startup performance.
+
+jdk.vm.ci_ADD_JAVAC_FLAGS := -parameters -Xlint:-exports -XDstringConcat=inline
+
+################################################################################
+
+jdk.vm.compiler_ADD_JAVAC_FLAGS := -parameters -XDstringConcat=inline
+
+jdk.vm.compiler_EXCLUDES += \
+    org.graalvm.compiler.core.match.processor \
+    org.graalvm.compiler.nodeinfo.processor \
+    org.graalvm.compiler.options.processor \
+    org.graalvm.compiler.serviceprovider.processor \
+    org.graalvm.compiler.replacements.verifier \
+    org.graalvm.compiler.api.directives.test \
+    org.graalvm.compiler.api.test \
+    org.graalvm.compiler.asm.aarch64.test \
+    org.graalvm.compiler.asm.amd64.test \
+    org.graalvm.compiler.asm.sparc.test \
+    org.graalvm.compiler.asm.test \
+    org.graalvm.compiler.core.amd64.test \
+    org.graalvm.compiler.core.sparc.test \
+    org.graalvm.compiler.core.test \
+    org.graalvm.compiler.debug.test \
+    org.graalvm.compiler.graph.test \
+    org.graalvm.compiler.hotspot.amd64.test \
+    org.graalvm.compiler.hotspot.lir.test \
+    org.graalvm.compiler.hotspot.test \
+    org.graalvm.compiler.jtt \
+    org.graalvm.compiler.lir.jtt \
+    org.graalvm.compiler.lir.test \
+    org.graalvm.compiler.microbenchmarks \
+    org.graalvm.compiler.nodes.test \
+    org.graalvm.compiler.options.test \
+    org.graalvm.compiler.phases.common.test \
+    org.graalvm.compiler.replacements.test \
+    org.graalvm.compiler.test \
+    org.graalvm.compiler.virtual.bench \
+    #
+
+################################################################################
+
+jdk.aot_ADD_JAVAC_FLAGS := -parameters -XDstringConcat=inline
 
 ################################################################################
 
@@ -511,6 +553,22 @@
   MODULESOURCEPATH := $(call PathList, $(JVMCI_MODULESOURCEPATH))
 endif
 
+ifeq ($(MODULE), jdk.vm.compiler)
+  ## WORKAROUND jdk.vm.compiler source structure issue
+  VM_COMPILER_MODULESOURCEPATH := $(MODULESOURCEPATH) \
+      $(subst /$(MODULE)/,/*/, $(filter-out %processor/src %test/src %jtt/src %bench/src %microbenchmarks/src, \
+          $(wildcard $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes/*/src)))
+  MODULESOURCEPATH := $(call PathList, $(VM_COMPILER_MODULESOURCEPATH))
+endif
+
+ifeq ($(MODULE), jdk.aot)
+  ## WORKAROUND jdk.aot source structure issue
+  AOT_MODULESOURCEPATH := $(MODULESOURCEPATH) \
+      $(subst /$(MODULE)/,/*/, $(filter-out %processor/src, \
+          $(wildcard $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes/*/src)))
+  MODULESOURCEPATH := $(call PathList, $(AOT_MODULESOURCEPATH))
+endif
+
 $(eval $(call SetupJavaCompilation, $(MODULE), \
     SETUP := $(if $($(MODULE)_SETUP), $($(MODULE)_SETUP), GENERATE_JDKBYTECODE), \
     MODULE := $(MODULE), \
diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk
index 8f3748b..fd502f1 100644
--- a/make/CreateJmods.gmk
+++ b/make/CreateJmods.gmk
@@ -79,6 +79,21 @@
   DEPS += $(call CacheFind, $(MAN_DIR))
 endif
 
+LEGAL_NOTICES := \
+    $(SUPPORT_OUTPUTDIR)/modules_legal/java.base \
+    $(call FindModuleLegalDirs, $(MODULE)) \
+    #
+
+LEGAL_NOTICES_PATH := $(call PathList, $(LEGAL_NOTICES))
+DEPS += $(call CacheFind, $(LEGAL_NOTICES))
+
+JMOD_FLAGS += --legal-notices $(LEGAL_NOTICES_PATH)
+
+ifeq ($(filter-out jdk.incubator.%, $(MODULE)), )
+  JMOD_FLAGS += --do-not-resolve-by-default
+  JMOD_FLAGS += --warn-if-resolved=incubating
+endif
+
 # Add dependencies on other jmod files. Only java.base needs access to other
 # jmods.
 ifeq ($(MODULE), java.base)
@@ -112,7 +127,6 @@
   DEPS := $(filter-out $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist, $(DEPS))
 endif
 
-# TODO: What about headers?
 # Create jmods in a temp dir and then move them into place to keep the
 # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times.
 $(JMODS_DIR)/$(MODULE).jmod: $(DEPS)
diff --git a/make/Help.gmk b/make/Help.gmk
index 45a5820..bd10fa2 100644
--- a/make/Help.gmk
+++ b/make/Help.gmk
@@ -66,6 +66,12 @@
 	$(info $(_) make clean-<module>-<phase> # Remove all build results related to a certain)
 	$(info $(_)                        # module and phase)
 	$(info )
+	$(info Targets for Hotspot)
+	$(info $(_) make hotspot           # Build all of hotspot)
+	$(info $(_) make hotspot-<variant> # Build just the specified jvm variant)
+	$(info $(_) make hotspot-gensrc    # Only build the gensrc part of hotspot)
+	$(info $(_) make hotspot-<variant>-<phase> # Build the specified phase for the specified module)
+	$(info )
 	$(info Targets for specific modules)
 	$(info $(_) make <module>          # Build <module> and everything it depends on)
 	$(info $(_) make <module>-<phase>  # Compile the specified phase for the specified module)
diff --git a/make/Images.gmk b/make/Images.gmk
index fa3d3ba..1806b9e 100644
--- a/make/Images.gmk
+++ b/make/Images.gmk
@@ -47,16 +47,43 @@
     $(PLATFORM_MODULES) $(JRE_TOOL_MODULES))
 JDK_MODULES += $(ALL_MODULES)
 
-# Compact builds have additional modules
-COMPACT1_EXTRA_MODULES := jdk.localedata jdk.crypto.pkcs11 jdk.crypto.ec \
-    jdk.unsupported
-COMPACT2_EXTRA_MODULES := jdk.xml.dom jdk.httpserver
-COMPACT3_EXTRA_MODULES := java.smartcardio jdk.management \
-    jdk.naming.dns jdk.naming.rmi jdk.sctp jdk.security.auth
+# Modules list for compact builds 
+JRE_COMPACT1_MODULES := \
+    java.logging \
+    java.scripting \
+    jdk.localedata \
+    jdk.crypto.token \
+    jdk.crypto.ec \
+    jdk.unsupported \
+    #
 
-JRE_COMPACT1_MODULES := java.compact1 $(COMPACT1_EXTRA_MODULES)
-JRE_COMPACT2_MODULES := $(JRE_COMPACT1_MODULES) java.compact2 $(COMPACT2_EXTRA_MODULES)
-JRE_COMPACT3_MODULES := $(JRE_COMPACT2_MODULES) java.compact3 $(COMPACT3_EXTRA_MODULES)
+JRE_COMPACT2_MODULES := \
+    $(JRE_COMPACT1_MODULES) \
+    java.rmi \
+    java.sql \
+    java.xml \
+    jdk.xml.dom \
+    jdk.httpserver \
+    #
+
+JRE_COMPACT3_MODULES := \
+    $(JRE_COMPACT2_MODULES) \
+    java.smartcardio \
+    java.compiler \
+    java.instrument \
+    java.management \
+    java.naming \
+    java.prefs \
+    java.security.jgss \
+    java.security.sasl \
+    java.sql.rowset \
+    java.xml.crypto \
+    jdk.management \
+    jdk.naming.dns \
+    jdk.naming.rmi \
+    jdk.sctp \
+    jdk.security.auth \
+    #
 
 JRE_MODULES_LIST := $(call CommaList, $(JRE_MODULES))
 JDK_MODULES_LIST := $(call CommaList, $(JDK_MODULES))
@@ -92,6 +119,7 @@
     --endian $(OPENJDK_BUILD_CPU_ENDIAN) \
     --release-info $(BASE_RELEASE_FILE) \
     --order-resources=$(call CommaList, $(JLINK_ORDER_RESOURCES)) \
+    --dedup-legal-notices=error-if-not-same-content \
     $(JLINK_JLI_CLASSES) \
     #
 
@@ -287,8 +315,6 @@
 ################################################################################
 # doc files
 
-JRE_DOC_FILES ?= LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README
-JDK_DOC_FILES ?= LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README
 JRE_DOC_LOCATION ?= $(JDK_TOPDIR)
 JDK_DOC_LOCATION ?= $(JDK_TOPDIR)
 
@@ -317,11 +343,11 @@
 ################################################################################
 # src.zip
 
-$(JDK_IMAGE_DIR)/src.zip: $(SUPPORT_OUTPUTDIR)/src.zip
+$(JDK_IMAGE_DIR)/lib/src.zip: $(SUPPORT_OUTPUTDIR)/src.zip
 	$(call LogInfo, Copying $(patsubst $(OUTPUT_ROOT)/%,%,$@))
 	$(install-file)
 
-JDK_TARGETS += $(JDK_IMAGE_DIR)/src.zip
+JDK_TARGETS += $(JDK_IMAGE_DIR)/lib/src.zip
 
 ################################################################################
 # /demo dir
diff --git a/make/InterimImage.gmk b/make/InterimImage.gmk
index d22a709..486b24d 100644
--- a/make/InterimImage.gmk
+++ b/make/InterimImage.gmk
@@ -38,7 +38,7 @@
 
 JMODS := $(patsubst %, $(INTERIM_JMODS_DIR)/%.jmod, $(INTERIM_IMAGE_MODULES))
 
-JLINK_TOOL := $(JLINK) \
+JLINK_TOOL := $(JLINK) -J-Djlink.debug=true \
     --module-path $(INTERIM_JMODS_DIR) \
     --endian $(OPENJDK_BUILD_CPU_ENDIAN)
 
diff --git a/make/Javadoc.gmk b/make/Javadoc.gmk
index b16cba1..c8e0a44 100644
--- a/make/Javadoc.gmk
+++ b/make/Javadoc.gmk
@@ -122,6 +122,7 @@
     org.w3c.dom.html \
     org.w3c.dom.stylesheets \
     org.w3c.dom.xpath \
+    org.graalvm.compiler.% \
     #
 
 CORE_PACKAGES := $(filter-out $(CORE_EXCLUDED_PACKAGES), \
@@ -576,12 +577,13 @@
     PACKAGES := \
         jdk.jshell \
         jdk.jshell.spi \
-        jdk.jshell.execution, \
+        jdk.jshell.execution \
+        jdk.jshell.tool, \
     API_ROOT := jdk, \
     DEST_DIR := jshell, \
-    OVERVIEW := $(LANGTOOLS_TOPDIR)/src/jdk.jshell/share/classes/jdk/jshell/overview.html, \
     TITLE := JShell API, \
     FIRST_COPYRIGHT_YEAR := 2015, \
+    SPLIT_INDEX := TRUE, \
 ))
 
 TARGETS += $(jshellapi)
diff --git a/make/Jprt.gmk b/make/Jprt.gmk
index d42f361..3a337af 100644
--- a/make/Jprt.gmk
+++ b/make/Jprt.gmk
@@ -81,7 +81,6 @@
   # Optional symbols bundle
   ifeq ($(GCOV_ENABLED), true)
     jprt_bundle: $(JPRT_ARCHIVE_SYMBOLS_BUNDLE)
-    zip-bundles: $(SYMBOLS_ZIP_BUNDLE)
 
     $(JPRT_ARCHIVE_SYMBOLS_BUNDLE): product-images
 	$(call MakeDir, $(@D))
diff --git a/make/Main.gmk b/make/Main.gmk
index e264d91..6aa135b 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -85,10 +85,14 @@
 
   buildtools-modules:
 	+($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileModuleTools.gmk)
+
+  buildtools-hotspot:
+	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileTools.gmk)
 endif
 
 ALL_TARGETS += buildtools-langtools interim-langtools \
-    interim-rmic interim-cldrconverter buildtools-jdk buildtools-modules
+    interim-rmic interim-cldrconverter buildtools-jdk buildtools-modules \
+    buildtools-hotspot
 
 ################################################################################
 # Special targets for certain modules
@@ -236,15 +240,35 @@
 ################################################################################
 # Build hotspot target
 
-ifeq ($(BUILD_HOTSPOT),true)
-  hotspot:
-	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f BuildHotspot.gmk)
-endif
+HOTSPOT_VARIANT_TARGETS := $(addprefix hotspot-, $(JVM_VARIANTS))
+HOTSPOT_VARIANT_GENSRC_TARGETS := $(addsuffix -gensrc, $(HOTSPOT_VARIANT_TARGETS))
+HOTSPOT_VARIANT_LIBS_TARGETS := $(addsuffix -libs, $(HOTSPOT_VARIANT_TARGETS))
+
+define DeclareHotspotGensrcRecipe
+  hotspot-$1-gensrc:
+	$$(call LogInfo, Building JVM variant '$1' with features '$(JVM_FEATURES_$1)')
+	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) -f gensrc/GenerateSources.gmk \
+	    JVM_VARIANT=$1)
+endef
+
+$(foreach v, $(JVM_VARIANTS), $(eval $(call DeclareHotspotGensrcRecipe,$v)))
+
+define DeclareHotspotLibsRecipe
+  hotspot-$1-libs:
+	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) -f lib/CompileLibraries.gmk \
+	    JVM_VARIANT=$1)
+endef
+
+$(foreach v, $(JVM_VARIANTS), $(eval $(call DeclareHotspotLibsRecipe,$v)))
+
+hotspot-jsig:
+	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) -f lib/CompileLibjsig.gmk)
 
 hotspot-ide-project:
 	+($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f ide/CreateVSProject.gmk)
 
-ALL_TARGETS += hotspot hotspot-ide-project
+ALL_TARGETS += $(HOTSPOT_VARIANT_TARGETS) $(HOTSPOT_VARIANT_GENSRC_TARGETS) \
+    $(HOTSPOT_VARIANT_LIBS_TARGETS) hotspot-jsig hotspot-ide-project
 
 ################################################################################
 # Build demos and samples targets
@@ -527,11 +551,13 @@
 
   buildtools-jdk: interim-langtools interim-cldrconverter
 
+  buildtools-hotspot: interim-langtools
+
   buildtools-modules: exploded-image-base
 
   $(CORBA_GENSRC_TARGETS): interim-langtools
 
-  $(HOTSPOT_GENSRC_TARGETS): interim-langtools
+  $(HOTSPOT_GENSRC_TARGETS): interim-langtools buildtools-hotspot
 
   $(JDK_GENSRC_TARGETS): interim-langtools buildtools-jdk
 
@@ -545,11 +571,18 @@
 
   $(JAVA_TARGETS): interim-langtools
 
+  # Declare dependencies between hotspot-<variant>* targets
+  $(foreach v, $(JVM_VARIANTS), \
+      $(eval hotspot-$v: hotspot-$v-gensrc hotspot-$v-libs) \
+      $(eval hotspot-$v-libs: hotspot-$v-gensrc) \
+  )
+
   hotspot-ide-project: hotspot exploded-image
 
   generate-exported-symbols: java.base-libs jdk.jdwp.agent-libs
 
-  $(LIBS_TARGETS): hotspot
+  # Building one JVM variant is enough to start building the other libs
+  $(LIBS_TARGETS): hotspot-$(JVM_VARIANT_MAIN)-libs
 
   $(LAUNCHER_TARGETS): java.base-libs
 
@@ -601,6 +634,14 @@
   # current JDK.
   jdk.vm.ci-gensrc-hotspot: java.base-java
 
+  # The annotation processing for jdk.vm.compiler needs classes from the current JDK.
+  jdk.vm.compiler-gensrc-hotspot: java.base-java java.management-java \
+      jdk.management-java jdk.vm.ci-java jdk.unsupported-java
+
+  # For jdk.vm.compiler, the gensrc step is generating a module-info.java.extra
+  # file to be processed by the gensrc-moduleinfo target.
+  jdk.vm.compiler-gensrc-moduleinfo: jdk.vm.compiler-gensrc-hotspot
+
   # Explicitly add dependencies for special targets
   java.base-java: unpack-sec
 
@@ -615,6 +656,9 @@
         $(addsuffix -jmod, $(call FindAllUpgradeableModules)), $(JMOD_TARGETS))
   endif
 
+  # Building java.base-jmod requires all of hotspot to be built.
+  java.base-jmod: hotspot
+
   # Declare dependencies from <module>-jmod to all other module targets
   # When creating a BUILDJDK, the java compilation has already been done by the
   # normal build and copied in.
@@ -659,6 +703,9 @@
         exploded-image-optimize
   endif
 
+  # All modules include the main license files from java.base.
+  $(JMOD_TARGETS): java.base-copy
+
   zip-security: java.base-java java.security.jgss-java java.security.jgss-libs \
       $(filter jdk.crypto%, $(JAVA_TARGETS))
 
@@ -686,6 +733,7 @@
 
   jdk-image: jmods zip-source demos samples release-file
   jre-image: jmods release-file
+  symbols-image: $(LIBS_TARGETS) $(LAUNCHER_TARGETS)
 
   profiles: jmods release-file
 
@@ -702,7 +750,7 @@
   docs-javadoc: $(GENSRC_TARGETS) rmic
 
   # The gensrc step for jdk.jdi creates an html file that is used by docs-copy.
-  docs-copy: hotspot jdk.jdi-gensrc
+  docs-copy: hotspot-$(JVM_VARIANT_MAIN)-gensrc jdk.jdi-gensrc
 
   docs-zip: docs-javadoc docs-copy
 
@@ -725,7 +773,8 @@
 
   test-image-failure-handler: build-test-failure-handler
 
-  build-test-hotspot-jtreg-native: buildtools-jdk hotspot
+  build-test-hotspot-jtreg-native: buildtools-jdk \
+      hotspot-$(JVM_VARIANT_MAIN)-libs
 
   build-test-jdk-jtreg-native: buildtools-jdk
 
@@ -757,7 +806,17 @@
 # Virtual targets without recipes
 
 buildtools: buildtools-langtools interim-langtools interim-rmic \
-    buildtools-jdk
+    buildtools-jdk buildtools-hotspot
+
+hotspot: $(HOTSPOT_VARIANT_TARGETS) hotspot-jsig
+
+hotspot-libs: hotspot-jsig
+
+# Create targets hotspot-libs and hotspot-gensrc.
+$(foreach v, $(JVM_VARIANTS), \
+  $(eval hotspot-libs: hotspot-$v-libs) \
+  $(eval hotspot-gensrc: hotspot-$v-gensrc) \
+)
 
 gensrc: $(GENSRC_TARGETS)
 
@@ -788,6 +847,10 @@
 $(foreach m, $(LIBS_MODULES), $(eval $m: $m-libs))
 $(foreach m, $(LAUNCHER_MODULES), $(eval $m: $m-launchers))
 $(foreach m, $(ALL_COPY_MODULES), $(eval $m: $m-copy))
+
+# Building java.base includes building all of hotspot.
+java.base: hotspot
+
 demos: demos-jdk
 
 samples: samples-jdk
@@ -843,7 +906,8 @@
 # all-bundles packages all our deliverables as tar.gz bundles.
 all-bundles: product-bundles test-bundles docs-bundles
 
-ALL_TARGETS += buildtools gensrc gendata copy java rmic libs launchers jmods \
+ALL_TARGETS += buildtools hotspot hotspot-libs hotspot-gensrc gensrc gendata \
+    copy java rmic libs launchers jmods \
     jdk.jdwp.agent-gensrc $(ALL_MODULES) demos samples \
     exploded-image-base exploded-image \
     create-buildjdk mac-bundles product-images docs-image test-image all-images \
diff --git a/make/ReleaseFile.gmk b/make/ReleaseFile.gmk
index d68d9e4..b57cb7b 100644
--- a/make/ReleaseFile.gmk
+++ b/make/ReleaseFile.gmk
@@ -47,6 +47,7 @@
   $(if $(JDK_ARCH_ABI_PROP_NAME), \
     $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"))
   $(call info-file-item, "SOURCE", "$(strip $(SOURCE_REVISION))")
+  $(call info-file-item, "IMPLEMENTOR", "$(COMPANY_NAME)")
 endef
 
 # Param 1 - The file containing the MODULES list
diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk
index c894a8a..465171a 100644
--- a/make/ZipSecurity.gmk
+++ b/make/ZipSecurity.gmk
@@ -43,8 +43,8 @@
         modules/java.base/com/sun/crypto/provider \
         modules/jdk.crypto.ec/sun/security/ec \
         modules/jdk.crypto.mscapi/sun/security/mscapi \
-        modules/jdk.crypto.pkcs11/sun/security/pkcs11 \
-        modules/jdk.crypto.pkcs11/sun/security/pkcs11/wrapper \
+        modules/jdk.crypto.token/sun/security/pkcs11 \
+        modules/jdk.crypto.token/sun/security/pkcs11/wrapper \
         modules/jdk.crypto.ucrypto/com/oracle/security/ucrypto \
         modules/java.base/javax/net \
         modules/java.base/javax/security/cert \
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index ec04e1b..8c033a7 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -861,13 +861,8 @@
 ################################################################################
 # Find lib dir for module
 # Param 1 - module name
-ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
-  FindLibDirForModule = \
-      $(SUPPORT_OUTPUTDIR)/modules_libs/$(strip $1)$(OPENJDK_TARGET_CPU_LIBDIR)
-else
-  FindLibDirForModule = \
-      $(SUPPORT_OUTPUTDIR)/modules_libs/$(strip $1)
-endif
+FindLibDirForModule = \
+    $(SUPPORT_OUTPUTDIR)/modules_libs/$(strip $1)
 
 ################################################################################
 # Return a string suitable for use after a -classpath or --module-path option. It
diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
index bb990d0..9749420 100644
--- a/make/common/Modules.gmk
+++ b/make/common/Modules.gmk
@@ -83,9 +83,6 @@
 NON_UPGRADEABLE_MODULES +=
 
 AGGREGATOR_MODULES += \
-    java.compact1 \
-    java.compact2 \
-    java.compact3 \
     java.se \
     java.se.ee \
     #
@@ -107,7 +104,7 @@
     jdk.accessibility \
     jdk.charsets \
     jdk.crypto.ec \
-    jdk.crypto.pkcs11 \
+    jdk.crypto.token \
     jdk.desktop \
     jdk.dynalink \
     jdk.jsobject \
@@ -122,7 +119,7 @@
 
 JRE_TOOL_MODULES += \
     jdk.jdwp.agent \
-    jdk.pack200 \
+    jdk.pack \
     jdk.scripting.nashorn.shell \
     #
 
@@ -145,6 +142,20 @@
 endif
 
 ################################################################################
+# Filter out Graal specific modules if Graal build is disabled
+
+ifeq ($(INCLUDE_GRAAL), false)
+  MODULES_FILTER += jdk.vm.compiler
+endif
+
+################################################################################
+# Filter out aot specific modules if aot is disabled
+
+ifeq ($(ENABLE_AOT), false)
+  MODULES_FILTER += jdk.aot
+endif
+
+################################################################################
 # Module list macros
 
 # Use append so that the custom extension may add to these variables
@@ -286,6 +297,21 @@
 
 ################################################################################
 
+LEGAL_SUBDIRS += $(OPENJDK_TARGET_OS)/legal
+ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE))
+  LEGAL_SUBDIRS += $(OPENJDK_TARGET_OS_TYPE)/legal
+endif
+LEGAL_SUBDIRS += share/legal
+
+# Find all legal dirs for a particular module
+# $1 - Module to find legal dirs for
+FindModuleLegalDirs = \
+    $(strip $(wildcard \
+        $(addsuffix /$(strip $1), $(IMPORT_MODULES_LEGAL)) \
+        $(foreach sub, $(LEGAL_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS)))))
+
+################################################################################
+
 # Param 1 - Name of module
 define ReadSingleImportMetaData
     ifneq ($$(wildcard $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties), )
diff --git a/nashorn/.hgtags b/nashorn/.hgtags
index 1f29f88..66da00e 100644
--- a/nashorn/.hgtags
+++ b/nashorn/.hgtags
@@ -382,3 +382,4 @@
 55f5a96988de8237f3ee65a69aa4a48aed9ca8d4 jdk-9+146
 9e86d6383456a1eb0298c72bb9ca363939ad90cf jdk-9+147
 0a4bc2f049132ddc20985565bb41b2be8a458dda jdk-9+148
+c281306d33d83c92e0d870ace385d5f99678d7e7 jdk-9+149
diff --git a/nashorn/THIRD_PARTY_README b/nashorn/THIRD_PARTY_README
deleted file mode 100644
index a93b35b..0000000
--- a/nashorn/THIRD_PARTY_README
+++ /dev/null
@@ -1,3605 +0,0 @@
-DO NOT TRANSLATE OR LOCALIZE.
------------------------------
-
-%% This notice is provided with respect to ASM Bytecode Manipulation 
-Framework v5.0, which may be included with JRE 8, and JDK 8, and 
-OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2011 France Télécom
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holders nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to BSDiff v4.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 2003-2005 Colin Percival
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CodeViewer 1.0, which may be
-included with JDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1999 by CoolServlets.com.
-
-Any errors or suggested improvements to this class can be reported as
-instructed on CoolServlets.com. We hope you enjoy this program... your
-comments will encourage further development!  This software is distributed
-under the terms of the BSD License.  Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-Neither name of CoolServlets.com nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Cryptix AES 3.2.0, which may be
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Cryptix General License
-
-Copyright (c) 1995-2005 The Cryptix Foundation Limited.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  1. Redistributions of source code must retain the copyright notice,
-     this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in
-     the documentation and/or other materials provided with the
-     distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to CUP Parser Generator for 
-Java 0.10k, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted, provided
-that the above copyright notice appear in all copies and that both the
-copyright notice and this permission notice and warranty disclaimer appear in
-supporting documentation, and that the names of the authors or their
-employers not be used in advertising or publicity pertaining to distribution of
-the software without specific, written prior permission.
-
-The authors and their employers disclaim all warranties with regard to
-this software, including all implied warranties of merchantability and fitness.
-In no event shall the authors or their employers be liable for any special,
-indirect or consequential damages or any damages whatsoever resulting from
-loss of use, data or profits, whether in an action of contract, negligence or
-other tortious action, arising out of or in connection with the use or
-performance of this software.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Document Object Model (DOM) Level 2
-& 3, which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-W3C SOFTWARE NOTICE AND LICENSE
-
-http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
-
-This work (and included software, documentation such as READMEs, or other
-related items) is being provided by the copyright holders under the following
-license. By obtaining, using and/or copying this work, you (the licensee)
-agree that you have read, understood, and will comply with the following terms
-and conditions.
-
-Permission to copy, modify, and distribute this software and its
-documentation, with or without modification, for any purpose and without fee
-or royalty is hereby granted, provided that you include the following on ALL
-copies of the software and documentation or portions thereof, including
-modifications:
-
-   1.The full text of this NOTICE in a location viewable to users of the
-   redistributed or derivative work.
-
-   2.Any pre-existing intellectual property disclaimers, notices, or terms and
-   conditions. If none exist, the W3C Software Short Notice should be included
-   (hypertext is preferred, text is permitted) within the body of any
-   redistributed or derivative code.
-
-   3.Notice of any changes or modifications to the files, including the date
-   changes were made. (We recommend you provide URIs to the location from
-   which the code is derived.)
-
-THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
-MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
-PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
-THIRD PARTY PATENTS,COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
-
-COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
-DOCUMENTATION.  The name and trademarks of copyright holders may NOT be used
-in advertising or publicity pertaining to the software without specific,
-written prior permission. Title to copyright in this software and any
-associated documentation will at all times remain with copyright holders.
-
-____________________________________
-
-This formulation of W3C's notice and license became active on December 31
-2002. This version removes the copyright ownership notice such that this
-license can be used with materials other than those owned by the W3C, reflects
-that ERCIM is now a host of the W3C, includes references to this specific
-dated version of the license, and removes the ambiguous grant of "use".
-Otherwise, this version is the same as the previous version and is written so
-as to preserve the Free Software Foundation's assessment of GPL compatibility
-and OSI's certification under the Open Source Definition. Please see our
-Copyright FAQ for common questions about using materials from our site,
-including specific terms and conditions for packages like libwww, Amaya, and
-Jigsaw. Other questions about this notice can be directed to
-site-policy@w3.org.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Dynalink v0.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2009-2013, Attila Szegedi
-
-All rights reserved.Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following conditions are
-met:* Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.  * Redistributions in
-binary form must reproduce the above copyright notice,   this list of
-conditions and the following disclaimer in the documentation  and/or other
-materials provided with the distribution.  * Neither the name of Attila
-Szegedi nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Elliptic Curve Cryptography, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
-You are receiving a copy of the Elliptic Curve Cryptography library in source
-form with the JDK 8 and OpenJDK 8 source distributions, and as object code in
-the JRE 8 & JDK 8 runtimes.
-
-In the case of the JRE 8 & JDK 8 runtimes, the terms of the Oracle license do
-NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
-following license, separately from Oracle's JDK & JRE.  If you do not wish to
-install the Elliptic Curve Cryptography library, you may delete the library
-named libsunec.so (on Solaris and Linux systems) or sunec.dll (on Windows
-systems) from the JRE bin directory reserved for native libraries.
-
-
---- begin of LICENSE ---
-
-                  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!
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to  ECMAScript Language
-Specification ECMA-262 Edition 5.1 which may be included with 
-JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright notice
-Copyright © 2011 Ecma International
-Ecma International
-Rue du Rhone 114
-CH-1204 Geneva
-Tel: +41 22 849 6000
-Fax: +41 22 849 6001
-Web: http://www.ecma-international.org
-
-This document and possible translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it or assist
-in its implementation may be prepared, copied, published, and distributed, in
-whole or in part, without restriction of any kind, provided that the above
-copyright notice and this section are included on all such copies and derivative
-works. However, this document itself may not be modified in any way, including
-by removing the copyright notice or references to Ecma International, except as
-needed for the purpose of developing any document or deliverable produced by
-Ecma International (in which case the rules applied to copyrights must be
-followed) or as required to translate it into languages other than English. The
-limited permissions granted above are perpetual and will not be revoked by Ecma
-International or its successors or assigns. This document and the information
-contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL
-DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
-WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
-RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
-PURPOSE." Software License
-
-All Software contained in this document ("Software)" is protected by copyright
-and is being made available under the "BSD License", included below. This
-Software may be subject to third party rights (rights from parties other than
-Ecma International), including patent rights, and no licenses under such third
-party rights are granted under this license even if the third party concerned is
-a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS
-AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
-INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO
-IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and
-binary forms, with or without modification, are permitted provided that the
-following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the authors nor Ecma International may be used to endorse
-or promote products derived from this software without specific prior written
-permission.
-
-THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Dynalink library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Copyright (c) 2009-2013, Attila Szegedi
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the copyright holder nor the names of
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- end of LICENSE ---
-
-%% This notice is provided with respect to Joni library which is included
-with the Nashorn technology.
-
---- begin of LICENSE ---
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to FontConfig 2.5, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 source distributions on
-Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright © 2001,2003 Keith Packard
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation, and that
-the name of Keith Packard not be used in advertising or publicity pertaining
-to distribution of the software without specific, written prior permission.
-Keith Packard makes no representations about the suitability of this software
-for any purpose.  It is provided "as is" without express or implied warranty.
-
-KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL KEITH
-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IAIK PKCS#11 Wrapper, 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-IAIK PKCS#11 Wrapper License
-
-Copyright (c) 2002 Graz University of Technology. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-   "This product includes software developed by IAIK of Graz University of
-    Technology."
-
-   Alternately, this acknowledgment may appear in the software itself, if and
-   wherever such third-party acknowledgments normally appear.
-
-4. The names "Graz University of Technology" and "IAIK of Graz University of
-   Technology" must not be used to endorse or promote products derived from this
-   software without prior written permission.
-
-5. Products derived from this software may not be called "IAIK PKCS Wrapper",
-   nor may "IAIK" appear in their name, without prior written permission of
-   Graz University of Technology.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to ICU4C 4.0.1 and ICU4J 4.4, which 
-may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 1995-2010 International Business Machines Corporation and others 
-
-All rights reserved. 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice appear
-in all copies of the Software and that both the above copyright notice(s) and
-this permission notice appear in supporting documentation.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
-All trademarks and registered trademarks mentioned herein are the property of
-their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to IJG JPEG 6b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library.  If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it.  This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Joni v1.1.9, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JOpt-Simple v3.0,  which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (c) 2004-2009 Paul R. Holser, Jr.
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
---------------------------------------------------------------------------------
-
-%% This notice is provided with respect to JSON, which may be included 
-with JRE 8 & JDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality, which 
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- (C) Copyright IBM Corp. 1999 All Rights Reserved.
- Copyright 1997 The Open Group Research Institute. All rights reserved.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kerberos functionality from 
-FundsXpress, INC., which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- Copyright (C) 1998 by the FundsXpress, INC.
-
- All rights reserved.
-
- Export of this software from the United States of America may require
- a specific license from the United States Government.  It is the
- responsibility of any person or organization contemplating export to
- obtain such a license before exporting.
-
- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- distribute this software and its documentation for any purpose and
- without fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation, and that
- the name of FundsXpress. not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.  FundsXpress makes no representations about the suitability of
- this software for any purpose.  It is provided "as is" without express
- or implied warranty.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Kronos OpenGL headers, which may be 
-included with JDK 8 and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Copyright (c) 2007 The Khronos Group Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and/or associated documentation files (the "Materials"), to
- deal in the Materials without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Materials, and to permit persons to whom the Materials are
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Materials.
-
- THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- MATERIALS.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions Copyright Eastman Kodak Company 1992
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libpng 1.5.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-This copy of the libpng notices is provided for your convenience.  In case of
-any discrepancy between this copy and the notices in the file png.h that is
-included in the libpng distribution, the latter shall prevail.
-
-COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
-
-If you modify libpng you may insert additional notices immediately following
-this sentence.
-
-This code is released under the libpng license.
-
-libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
-Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.2.5
-with the following individual added to the list of Contributing Authors
-
-   Cosmin Truta
-
-libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
-Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-1.0.6
-with the following individuals added to the list of Contributing Authors
-
-   Simon-Pierre Cadieux
-   Eric S. Raymond
-   Gilles Vollant
-
-and with the following additions to the disclaimer:
-
-   There is no warranty against interference with your enjoyment of the
-   library or against infringement.  There is no warranty that our
-   efforts or the library will fulfill any of your particular purposes
-   or needs.  This library is provided with all faults, and the entire
-   risk of satisfactory quality, performance, accuracy, and effort is with
-   the user.
-
-libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
-Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
-distributed according to the same disclaimer and license as libpng-0.96,
-with the following individuals added to the list of Contributing Authors:
-
-   Tom Lane
-   Glenn Randers-Pehrson
-   Willem van Schaik
-
-libpng versions 0.89, June 1996, through 0.96, May 1997, are
-Copyright (c) 1996, 1997 Andreas Dilger
-Distributed according to the same disclaimer and license as libpng-0.88,
-with the following individuals added to the list of Contributing Authors:
-
-   John Bowler
-   Kevin Bracey
-   Sam Bushell
-   Magnus Holmgren
-   Greg Roelofs
-   Tom Tanner
-
-libpng versions 0.5, May 1995, through 0.88, January 1996, are
-Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
-
-For the purposes of this copyright and license, "Contributing Authors"
-is defined as the following set of individuals:
-
-   Andreas Dilger
-   Dave Martindale
-   Guy Eric Schalnat
-   Paul Schmidt
-   Tim Wegner
-
-The PNG Reference Library is supplied "AS IS".  The Contributing Authors
-and Group 42, Inc. disclaim all warranties, expressed or implied,
-including, without limitation, the warranties of merchantability and of
-fitness for any purpose.  The Contributing Authors and Group 42, Inc.
-assume no liability for direct, indirect, incidental, special, exemplary,
-or consequential damages, which may result from the use of the PNG
-Reference Library, even if advised of the possibility of such damage.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-source code, or portions hereof, for any purpose, without fee, subject
-to the following restrictions:
-
-1. The origin of this source code must not be misrepresented.
-
-2. Altered versions must be plainly marked as such and must not
-   be misrepresented as being the original source.
-
-3. This Copyright notice may not be removed or altered from any
-   source or altered source distribution.
-
-The Contributing Authors and Group 42, Inc. specifically permit, without
-fee, and encourage the use of this source code as a component to
-supporting the PNG file format in commercial products.  If you use this
-source code in a product, acknowledgment is not required but would be
-appreciated.
-
-
-A "png_get_copyright" function is available, for convenient use in "about"
-boxes and the like:
-
-   printf("%s",png_get_copyright(NULL));
-
-Also, the PNG logo (in PNG format, of course) is supplied in the
-files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
-
-Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
-certification mark of the Open Source Initiative.
-
-Glenn Randers-Pehrson
-glennrp at users.sourceforge.net
-July 7, 2011
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to libungif 4.1.3, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Little CMS 2.4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Little CMS
-Copyright (c) 1998-2010 Marti Maria Saguer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Lucida is a registered trademark or trademark of Bigelow & Holmes in the
-U.S. and other countries.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mesa 3D Graphics Library v4.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 source distributions.
-
---- begin of LICENSE ---
-
- Mesa 3-D graphics library
- Version:  4.1
-
- Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Mozilla Network Security
-Services (NSS), which is supplied with the JDK test suite in the OpenJDK
-source code repository. It is licensed under Mozilla Public License (MPL),
-version 2.0.
-
-The NSS libraries are supplied in executable form, built from unmodified
-NSS source code labeled with the "NSS_3.13.1_RTM" release tag.
-
-The NSS source code is available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/src
-
-The NSS libraries are available in the OpenJDK source code repository at:
-    jdk/test/sun/security/pkcs11/nss/lib
-
---- begin of LICENSE ---
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PC/SC Lite for Suse Linux v.1.1.1,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Copyright (c) 1999-2004 David Corcoran <corcoran@linuxnet.com>
-Copyright (c) 1999-2004 Ludovic Rousseau <ludovic.rousseau (at) free.fr>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-     This product includes software developed by: 
-      David Corcoran <corcoran@linuxnet.com>
-      http://www.linuxnet.com (MUSCLE)
-4. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-Changes to this license can be made only by the copyright author with 
-explicit written consent.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to PorterStemmer v4, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-See: http://tartarus.org/~martin/PorterStemmer
-
-The software is completely free for any purpose, unless notes at the head of
-the program text indicates otherwise (which is rare). In any case, the notes
-about licensing are never more restrictive than the BSD License.
-
-In every case where the software is not written by me (Martin Porter), this
-licensing arrangement has been endorsed by the contributor, and it is
-therefore unnecessary to ask the contributor again to confirm it.
-
-I have not asked any contributors (or their employers, if they have them) for
-proofs that they have the right to distribute their software in this way.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Relax NG Object/Parser v.20050510,
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) Kohsuke Kawaguchi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions: The above copyright
-notice and this permission notice shall be included in all copies or
-substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to RelaxNGCC v1.12, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (c) 2000-2003 Daisuke Okajima and Kohsuke Kawaguchi.  
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-3. The end-user documentation included with the redistribution, if any, must
-   include the following acknowledgment:
-
-    "This product includes software developed by Daisuke Okajima
-    and Kohsuke Kawaguchi (http://relaxngcc.sf.net/)."
-
-Alternately, this acknowledgment may appear in the software itself, if and
-wherever such third-party acknowledgments normally appear.
-
-4. The names of the copyright holders must not be used to endorse or promote
-   products derived from this software without prior written permission. For
-   written permission, please contact the copyright holders.
-
-5. Products derived from this software may not be called "RELAXNGCC", nor may
-  "RELAXNGCC" appear in their name, without prior written permission of the
-  copyright holders.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE APACHE
-SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SAX 2.0.1, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
- SAX is free!
-
- In fact, it's not possible to own a license to SAX, since it's been placed in
- the public domain.
-
- No Warranty
-
- Because SAX is released to the public domain, there is no warranty for the
- design or for the software implementation, to the extent permitted by
- applicable law. Except when otherwise stated in writing the copyright holders
- and/or other parties provide SAX "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 SAX is with you. Should SAX prove
- defective, you assume the cost of all necessary servicing, repair or
- correction.
-
- 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
- SAX, be liable to you for damages, including any general, special, incidental
- or consequential damages arising out of the use or inability to use SAX
- (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 SAX to
- operate with any other programs), even if such holder or other party has been
- advised of the possibility of such damages.
-
- Copyright Disclaimers 
-
- This page includes statements to that effect by David Megginson, who would
- have been able to claim copyright for the original work.  SAX 1.0
-
- Version 1.0 of the Simple API for XML (SAX), created collectively by the
- membership of the XML-DEV mailing list, is hereby released into the public
- domain.
-
- No one owns SAX: you may use it freely in both commercial and non-commercial
- applications, bundle it with your software distribution, include it on a
- CD-ROM, list the source code in a book, mirror the documentation at your own
- web site, or use it in any other way you see fit.
-
- David Megginson, sax@megginson.com
- 1998-05-11
-
- SAX 2.0 
-
- I hereby abandon any property rights to SAX 2.0 (the Simple API for XML), and
- release all of the SAX 2.0 source code, compiled code, and documentation
- contained in this distribution into the Public Domain. SAX comes with NO
- WARRANTY or guarantee of fitness for any purpose.
-
- David Megginson, david@megginson.com
- 2000-05-05
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to SoftFloat version 2b, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux/ARM.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-SoftFloat was written by me, John R. Hauser. This work was made possible in 
-part by the International Computer Science Institute, located at Suite 600, 
-1947 Center Street, Berkeley, California 94704. Funding was partially 
-provided by the National Science Foundation under grant MIP-9311980. The 
-original version of this code was written as part of a project to build 
-a fixed-point vector processor in collaboration with the University of 
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. 
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort 
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT 
-TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO 
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL 
-LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO 
-FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER 
-SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, 
-COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE 
-SOFTWARE. 
-
-Derivative works are acceptable, even for commercial purposes, provided 
-that the minimal documentation requirements stated in the source code are 
-satisfied. 
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Sparkle 1.5,
-which may be included with JRE 8 on Mac OS X.
-
---- begin of LICENSE ---
-
-Copyright (c) 2012 Sparkle.org and Andy Matuschak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% Portions licensed from Taligent, Inc.
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Thai Dictionary, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Copyright (C) 1982 The Royal Institute, Thai Royal Government.
-
-Copyright (C) 1998 National Electronics and Computer Technology Center,
-National Science and Technology Development Agency,
-Ministry of Science Technology and Environment,
-Thai Royal Government.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Unicode 6.2.0 & CLDR 21.0.1
-which may be included with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-Unicode Terms of Use
-
-For the general privacy policy governing access to this site, see the Unicode
-Privacy Policy. For trademark usage, see the Unicode® Consortium Name and
-Trademark Usage Policy.
-
-A. Unicode Copyright.
-   1. Copyright © 1991-2013 Unicode, Inc. All rights reserved.
-
-   2. Certain documents and files on this website contain a legend indicating
-      that "Modification is permitted." Any person is hereby authorized,
-      without fee, to modify such documents and files to create derivative
-      works conforming to the Unicode® Standard, subject to Terms and
-      Conditions herein.
-
-    3. Any person is hereby authorized, without fee, to view, use, reproduce,
-       and distribute all documents and files solely for informational
-       purposes in the creation of products supporting the Unicode Standard,
-       subject to the Terms and Conditions herein.
-
-    4. Further specifications of rights and restrictions pertaining to the use
-       of the particular set of data files known as the "Unicode Character
-       Database" can be found in Exhibit 1.
-
-    5. Each version of the Unicode Standard has further specifications of
-       rights and restrictions of use. For the book editions (Unicode 5.0 and
-       earlier), these are found on the back of the title page. The online
-       code charts carry specific restrictions. All other files, including
-       online documentation of the core specification for Unicode 6.0 and
-       later, are covered under these general Terms of Use.
-
-    6. No license is granted to "mirror" the Unicode website where a fee is
-       charged for access to the "mirror" site.
-
-    7. Modification is not permitted with respect to this document. All copies
-       of this document must be verbatim.
-
-B. Restricted Rights Legend. Any technical data or software which is licensed
-   to the United States of America, its agencies and/or instrumentalities
-   under this Agreement is commercial technical data or commercial computer
-   software developed exclusively at private expense as defined in FAR 2.101,
-   or DFARS 252.227-7014 (June 1995), as applicable. For technical data, use,
-   duplication, or disclosure by the Government is subject to restrictions as
-   set forth in DFARS 202.227-7015 Technical Data, Commercial and Items (Nov
-   1995) and this Agreement. For Software, in accordance with FAR 12-212 or
-   DFARS 227-7202, as applicable, use, duplication or disclosure by the
-   Government is subject to the restrictions set forth in this Agreement.
-
-C. Warranties and Disclaimers.
-   1. This publication and/or website may include technical or typographical
-      errors or other inaccuracies . Changes are periodically added to the
-      information herein; these changes will be incorporated in new editions
-      of the publication and/or website. Unicode may make improvements and/or
-      changes in the product(s) and/or program(s) described in this
-      publication and/or website at any time.
-
-    2. If this file has been purchased on magnetic or optical media from
-       Unicode, Inc. the sole and exclusive remedy for any claim will be
-       exchange of the defective media within ninety (90) days of original
-       purchase.
-
-    3. EXCEPT AS PROVIDED IN SECTION C.2, THIS PUBLICATION AND/OR SOFTWARE IS
-       PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS, IMPLIED,
-       OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
-       UNICODE AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR ERRORS OR
-       OMISSIONS IN THIS PUBLICATION AND/OR SOFTWARE OR OTHER DOCUMENTS WHICH
-       ARE REFERENCED BY OR LINKED TO THIS PUBLICATION OR THE UNICODE WEBSITE.
-
-D. Waiver of Damages. In no event shall Unicode or its licensors be liable for
-   any special, incidental, indirect or consequential damages of any kind, or
-   any damages whatsoever, whether or not Unicode was advised of the
-   possibility of the damage, including, without limitation, those resulting
-   from the following: loss of use, data or profits, in connection with the
-   use, modification or distribution of this information or its derivatives.
-
-E.Trademarks & Logos.
-   1. The Unicode Word Mark and the Unicode Logo are trademarks of Unicode,
-      Inc.  “The Unicode Consortium” and “Unicode, Inc.” are trade names of
-      Unicode, Inc.  Use of the information and materials found on this
-      website indicates your acknowledgement of Unicode, Inc.’s exclusive
-      worldwide rights in the Unicode Word Mark, the Unicode Logo, and the
-      Unicode trade names.
-
-   2. The Unicode Consortium Name and Trademark Usage Policy (“Trademark
-      Policy”) are incorporated herein by reference and you agree to abide by
-      the provisions of the Trademark Policy, which may be changed from time
-      to time in the sole discretion of Unicode, Inc.
-
-   3. All third party trademarks referenced herein are the property of their
-      respective owners.
-
-Miscellaneous.
-   1. Jurisdiction and Venue. This server is operated from a location in the
-      State of California, United States of America. Unicode makes no
-      representation that the materials are appropriate for use in other
-      locations. If you access this server from other locations, you are
-      responsible for compliance with local laws. This Agreement, all use of
-      this site and any claims and damages resulting from use of this site are
-      governed solely by the laws of the State of California without regard to
-      any principles which would apply the laws of a different jurisdiction.
-      The user agrees that any disputes regarding this site shall be resolved
-      solely in the courts located in Santa Clara County, California. The user
-      agrees said courts have personal jurisdiction and agree to waive any
-      right to transfer the dispute to any other forum.
-
-   2. Modification by Unicode.  Unicode shall have the right to modify this
-      Agreement at any time by posting it to this site. The user may not
-      assign any part of this Agreement without Unicode’s prior written
-      consent.
-
-   3. Taxes. The user agrees to pay any taxes arising from access to this
-      website or use of the information herein, except for those based on
-      Unicode’s net income.
-
-   4. Severability.  If any provision of this Agreement is declared invalid or
-      unenforceable, the remaining provisions of this Agreement shall remain
-      in effect.
-
-   5. Entire Agreement. This Agreement constitutes the entire agreement
-      between the parties.
-
-EXHIBIT 1
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-Unicode Data Files include all data files under the directories
-http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
-http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
-online code charts under the directory http://www.unicode.org/Public/.
-Software includes any source code published in the Unicode Standard or under
-the directories http://www.unicode.org/Public/,
-http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
-
-NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
-INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
-FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
-BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
-AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
-SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under the
-Terms of Use in http://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the Unicode data files and any associated documentation (the "Data Files")
-or Unicode software and any associated documentation (the "Software") to deal
-in the Data Files or Software without restriction, including without
-limitation the rights to use, copy, modify, merge, publish, distribute, and/or
-sell copies of the Data Files or Software, and to permit persons to whom the
-Data Files or Software are furnished to do so, provided that (a) the above
-copyright notice(s) and this permission notice appear with all copies of the
-Data Files or Software, (b) both the above copyright notice(s) and this
-permission notice appear in associated documentation, and (c) there is clear
-notice in each modified Data File or in the Software as well as in the
-documentation associated with the Data File(s) or Software that the data or
-software has been modified.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
-THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
-DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in these Data Files or Software without prior written authorization of the
-copyright holder.
-
-Unicode and the Unicode logo are trademarks of Unicode, Inc. in the United
-States and other countries. All third party trademarks referenced herein are
-the property of their respective owners.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to UPX v3.01, which may be included 
-with JRE 8 on Windows.
-
---- begin of LICENSE ---
-
-Use of any of this software is governed by the terms of the license below:
-
-
-                 ooooo     ooo ooooooooo.   ooooooo  ooooo
-                 `888'     `8' `888   `Y88.  `8888    d8'
-                  888       8   888   .d88'    Y888..8P
-                  888       8   888ooo88P'      `8888'
-                  888       8   888            .8PY888.
-                  `88.    .8'   888           d8'  `888b
-                    `YbodP'    o888o        o888o  o88888o
-
-
-                    The Ultimate Packer for eXecutables
-          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
-               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
-                          http://www.nexus.hu/upx
-                            http://upx.tsx.org
-
-
-PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
-TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
-
-
-ABSTRACT
-========
-
-   UPX and UCL are copyrighted software distributed under the terms
-   of the GNU General Public License (hereinafter the "GPL").
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   As a special exception we grant the free usage of UPX for all
-   executables, including commercial programs.
-   See below for details and restrictions.
-
-
-COPYRIGHT
-=========
-
-   UPX and UCL are copyrighted software. All rights remain with the authors.
-
-   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-   UPX is Copyright (C) 1996-2000 Laszlo Molnar
-
-   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
-
-
-GNU GENERAL PUBLIC LICENSE
-==========================
-
-   UPX and the UCL library are free software; you can redistribute them
-   and/or modify them under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   UPX and UCL are distributed in the hope that they will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; see the file COPYING.
-
-
-SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
-============================================
-
-   The stub which is imbedded in each UPX compressed program is part
-   of UPX and UCL, and contains code that is under our copyright. The
-   terms of the GNU General Public License still apply as compressing
-   a program is a special form of linking with our stub.
-
-   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
-   permission to freely use and distribute all UPX compressed programs
-   (including commercial ones), subject to the following restrictions:
-
-   1. You must compress your program with a completely unmodified UPX
-      version; either with our precompiled version, or (at your option)
-      with a self compiled version of the unmodified UPX sources as
-      distributed by us.
-   2. This also implies that the UPX stub must be completely unmodfied, i.e.
-      the stub imbedded in your compressed program must be byte-identical
-      to the stub that is produced by the official unmodified UPX version.
-   3. The decompressor and any other code from the stub must exclusively get
-      used by the unmodified UPX stub for decompressing your program at
-      program startup. No portion of the stub may get read, copied,
-      called or otherwise get used or accessed by your program.
-
-
-ANNOTATIONS
-===========
-
-  - You can use a modified UPX version or modified UPX stub only for
-    programs that are compatible with the GNU General Public License.
-
-  - We grant you special permission to freely use and distribute all UPX
-    compressed programs. But any modification of the UPX stub (such as,
-    but not limited to, removing our copyright string or making your
-    program non-decompressible) will immediately revoke your right to
-    use and distribute a UPX compressed program.
-
-  - UPX is not a software protection tool; by requiring that you use
-    the unmodified UPX version for your proprietary programs we
-    make sure that any user can decompress your program. This protects
-    both you and your users as nobody can hide malicious code -
-    any program that cannot be decompressed is highly suspicious
-    by definition.
-
-  - You can integrate all or part of UPX and UCL into projects that
-    are compatible with the GNU GPL, but obviously you cannot grant
-    any special exceptions beyond the GPL for our code in your project.
-
-  - We want to actively support manufacturers of virus scanners and
-    similar security software. Please contact us if you would like to
-    incorporate parts of UPX or UCL into such a product.
-
-
-
-Markus F.X.J. Oberhumer                   Laszlo Molnar
-markus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu
-
-Linz, Austria, 25 Feb 2000
-
-Additional License(s)
-
-The UPX license file is at http://upx.sourceforge.net/upx-license.html.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to Xfree86-VidMode Extension 1.0,
-which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-Version 1.1 of XFree86 ProjectLicence.
-
-Copyright (C) 1994-2004 The XFree86 Project, Inc.    All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicence, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so,subject to the following conditions:
-
-   1. Redistributions of source code must retain the above copyright
-   notice,this list of conditions, and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution, and in the same place
-   and form as other copyright, license and disclaimer information.
-
-   3. The end-user documentation included with the redistribution, if any,must
-   include the following acknowledgment: "This product includes
-   software developed by The XFree86 Project, Inc (http://www.xfree86.org/) and
-   its contributors", in the same place and form as other third-party
-   acknowledgments. Alternately, this acknowledgment may appear in the software
-   itself, in the same form and location as other such third-party
-   acknowledgments.
-
-    4. Except as contained in this notice, the name of The XFree86 Project,Inc
-    shall not be used in advertising or otherwise to promote the sale, use
-    or other dealings in this Software without prior written authorization from
-    The XFree86 Project, Inc.
-
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-    WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-    EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-    DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-    DAMAGE.  
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to X Window System 6.8.2, which may be 
-included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris.
-
---- begin of LICENSE ---
-
-          Licenses
-The X.Org Foundation March 2004
-
-1. Introduction
-
-The X.org Foundation X Window System distribution is a compilation of code and
-documentation from many sources. This document is intended primarily as a
-guide to the licenses used in the distribution: you must check each file
-and/or package for precise redistribution terms. None-the-less, this summary
-may be useful to many users. No software incorporating the XFree86 1.1 license
-has been incorporated.
-
-This document is based on the compilation from XFree86.
-
-2. XFree86 License
-
-XFree86 code without an explicit copyright is covered by the following
-copyright/license:
-
-Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the XFree86 Project shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from the XFree86 Project.
-
-3. Other Licenses
-
-Portions of code are covered by the following licenses/copyrights. See
-individual files for the copyright dates.
-
-3.1. X/MIT Copyrights
-
-3.1.1. X Consortium
-
-Copyright (C) <date> X Consortium
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
-CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from the X Consortium.
-
-X Window System is a trademark of X Consortium, Inc.
-
-3.1.2. The Open Group
-
-Copyright <date> The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that the
-above copyright notice appear in all copies and that both that copyright
-notice and this permission notice appear in supporting documentation.
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from The Open Group.  3.2.
-Berkeley-based copyrights:
-
-o
-3.2.1. General
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.2. UCB/LBL
-
-Copyright (c) 1993 The Regents of the University of California. All rights
-reserved.
-
-This software was developed by the Computer Systems Engineering group at
-Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to
-Berkeley.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement: This product includes software
-developed by the University of California, Lawrence Berkeley Laboratory.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the University of California, Berkeley and its contributors.
-
-   4. Neither the name of the University nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.3. The
-NetBSD Foundation, Inc.
-
-Copyright (c) 2003 The NetBSD Foundation, Inc. All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation by Ben
-Collver <collver1@attbi.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement: This product includes software
-   developed by the NetBSD Foundation, Inc. and its contributors.
-
-   4. Neither the name of The NetBSD Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS
-IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  3.2.4. Theodore
-Ts'o.
-
-Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   and the entire permission notice in its entirety, including the disclaimer
-   of warranties.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. he name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.5. Theo de Raadt and Damien Miller
-
-Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. Copyright (c)
-2001-2002 Damien Miller. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.2.6. Todd C. Miller
-
-Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  3.2.7. Thomas
-Winischhofer
-
-Copyright (C) 2001-2004 Thomas Winischhofer
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-   1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-
-   2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-   3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.  3.3. NVIDIA Corp
-
-Copyright (c) 1996 NVIDIA, Corp. All rights reserved.
-
-NOTICE TO USER: The source code is copyrighted under U.S. and international
-laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design
-patents pending on the design and interface of the NV chips. Users and
-possessors of this source code are hereby granted a nonexclusive, royalty-free
-copyright and design patent license to use this code in individual and
-commercial software.
-
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
-
-Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and
-foreign countries.
-
-NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
-CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
-WARRANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE
-FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
-DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.  3.4. GLX Public
-License
-
-GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License")
-
-Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby
-grants permission to Recipient (defined below), under Recipient's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below), and to permit persons to whom the Subject Software is
-furnished in accordance with this License to do the same, subject to all of
-the following terms and conditions, which Recipient accepts by engaging in any
-such use, copying, modifying, merging, publishing, distributing, sublicensing
-or selling:
-
-1. Definitions.
-
-    (a) "Original Software" means source code of computer software code which
-    is described in Exhibit A as Original Software.
-
-    (b) "Modifications" means any addition to or deletion from the substance
-    or structure of either the Original Software or any previous
-    Modifications. When Subject Software is released as a series of files, a
-    Modification means (i) any addition to or deletion from the contents of a
-    file containing Original Software or previous Modifications and (ii) any
-    new file that contains any part of the Original Code or previous
-    Modifications.
-
-    (c) "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    (d) "Recipient" means an individual or a legal entity exercising rights
-    under, and complying with all of the terms of, this License. For legal
-    entities, "Recipient" includes any entity which controls, is controlled
-    by, or is under common control with Recipient. For purposes of this
-    definition, "control" of an entity means (a) the power, direct or
-    indirect, to direct or manage such entity, or (b) ownership of fifty
-    percent (50%) or more of the outstanding shares or beneficial ownership of
-    such entity.
-
-2. Redistribution of Source Code Subject to These Terms. Redistributions of
-Subject Software in source code form must retain the notice set forth in
-Exhibit A, below, in every file. A copy of this License must be included in
-any documentation for such Subject Software where the recipients' rights
-relating to Subject Software are described. Recipient may distribute the
-source code version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the source code version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-3. Redistribution in Executable Form. The notice set forth in Exhibit A must
-be conspicuously included in any notice in an executable version of Subject
-Software, related documentation or collateral in which Recipient describes the
-user's rights relating to the Subject Software. Recipient may distribute the
-executable version of Subject Software under a license of Recipient's choice,
-which may contain terms different from this License, provided that (i)
-Recipient is in compliance with the terms of this License, and (ii) the
-license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of
-this License, which terms may not be modified or superseded by any other terms
-of such license. If Recipient distributes the executable version under a
-different license Recipient must make it absolutely clear that any terms which
-differ from this License are offered by Recipient alone, not by SGI. Recipient
-hereby agrees to indemnify SGI for any liability incurred by SGI as a result
-of any such terms Recipient offers.
-
-4. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software which is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-5. No Trademark Rights. This License does not grant any rights to use any
-trade name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from
-the Subject Software without prior written permission of SGI.
-
-6. No Other Rights. This License does not grant any rights with respect to the
-OpenGL API or to any software or hardware implementation thereof or to any
-other software whatsoever, nor shall any other rights or licenses not
-expressly granted hereunder arise by implication, estoppel or otherwise with
-respect to the Subject Software. Title to and ownership of the Original
-Software at all times remains with SGI. All rights in the Original Software
-not expressly granted under this License are reserved.
-
-7. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-8. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Exhibit A notice required under Sections 2 and 3,
-above, and in the text of any related documentation, license agreement or
-collateral in which Recipient describes end user's rights relating to the
-Subject Software. If Recipient obtains such knowledge after it makes Subject
-Software available to any other person or entity, Recipient shall take other
-steps (such as notifying appropriate mailing lists or newsgroups) reasonably
-calculated to inform those who received the Subject Software that new
-knowledge has been obtained.
-
-9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
-STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF
-THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY
-TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO
-THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT.
-
-11. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from
-and against any loss, liability, damages, costs or expenses (including the
-payment of reasonable attorneys fees) arising out of Recipient's use,
-modification, reproduction and distribution of the Subject Software or out of
-any representation or warranty made by Recipient.
-
-12. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-13. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed so as to achieve as nearly as
-possible the same economic effect as the original provision and the remainder
-of this License will remain in effect. This License shall be governed by and
-construed in accordance with the laws of the United States and the State of
-California as applied to agreements entered into and to be performed entirely
-within California between California residents. Any litigation relating to
-this License shall be subject to the exclusive jurisdiction of the Federal
-Courts of the Northern District of California (or, absent subject matter
-jurisdiction in such courts, the courts of the State of California), with
-venue lying exclusively in Santa Clara County, California, with the losing
-party responsible for costs, including without limitation, court costs and
-reasonable attorneys fees and expenses. The application of the United Nations
-Convention on Contracts for the International Sale of Goods is expressly
-excluded. Any law or regulation which provides that the language of a contract
-shall be construed against the drafter shall not apply to this License.
-
-Exhibit A
-
-The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13
-of the GLX Public License Version 1.0 (the "License"). You may not use this
-file except in compliance with those sections of the License. You may obtain a
-copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N.
-Shoreline Blvd., Mountain View, CA 94043 or at
-http://www.sgi.com/software/opensource/glx/license.html.
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON-
-INFRINGEMENT. See the License for the specific language governing rights and
-limitations under the License.
-
-The Original Software is GLX version 1.2 source code, released February, 1999.
-The developer of the Original Software is Silicon Graphics, Inc. Those
-portions of the Subject Software created by Silicon Graphics, Inc. are
-Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.  3.5. CID
-Font Code Public License
-
-CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License")
-
-Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI")
-hereby grants permission to Recipient (defined below), under SGI's copyrights
-in the Original Software (defined below), to use, copy, modify, merge,
-publish, distribute, sublicense and/or sell copies of Subject Software
-(defined below) in both source code and executable form, and to permit persons
-to whom the Subject Software is furnished in accordance with this License to
-do the same, subject to all of the following terms and conditions, which
-Recipient accepts by engaging in any such use, copying, modifying, merging,
-publication, distributing, sublicensing or selling:
-
-1. Definitions.
-
-    a. "Original Software" means source code of computer software code that is
-    described in Exhibit A as Original Software.
-
-    b. "Modifications" means any addition to or deletion from the substance or
-    structure of either the Original Software or any previous Modifications.
-    When Subject Software is released as a series of files, a Modification
-    means (i) any addition to or deletion from the contents of a file
-    containing Original Software or previous Modifications and (ii) any new
-    file that contains any part of the Original Code or previous
-    Modifications.
-
-    c. "Subject Software" means the Original Software or Modifications or the
-    combination of the Original Software and Modifications, or portions of any
-    of the foregoing.
-
-    d. "Recipient" means an individual or a legal entity exercising rights
-    under the terms of this License. For legal entities, "Recipient" includes
-    any entity that controls, is controlled by, or is under common control
-    with Recipient. For purposes of this definition, "control" of an entity
-    means (i) the power, direct or indirect, to direct or manage such entity,
-    or (ii) ownership of fifty percent (50%) or more of the outstanding shares
-    or beneficial ownership of such entity.
-
-    e. "Required Notice" means the notice set forth in Exhibit A to this
-    License.
-
-    f. "Accompanying Technology" means any software or other technology that
-    is not a Modification and that is distributed or made publicly available
-    by Recipient with the Subject Software. Separate software files that do
-    not contain any Original Software or any previous Modification shall not
-    be deemed a Modification, even if such software files are aggregated as
-    part of a product, or in any medium of storage, with any file that does
-    contain Original Software or any previous Modification.
-
-2. License Terms. All distribution of the Subject Software must be made
-subject to the terms of this License. A copy of this License and the Required
-Notice must be included in any documentation for Subject Software where
-Recipient's rights relating to Subject Software and/or any Accompanying
-Technology are described. Distributions of Subject Software in source code
-form must also include the Required Notice in every file distributed. In
-addition, a ReadMe file entitled "Important Legal Notice" must be distributed
-with each distribution of one or more files that incorporate Subject Software.
-That file must be included with distributions made in both source code and
-executable form. A copy of the License and the Required Notice must be
-included in that file. Recipient may distribute Accompanying Technology under
-a license of Recipient's choice, which may contain terms different from this
-License, provided that (i) Recipient is in compliance with the terms of this
-License, (ii) such other license terms do not modify or supersede the terms of
-this License as applicable to the Subject Software, (iii) Recipient hereby
-indemnifies SGI for any liability incurred by SGI as a result of the
-distribution of Accompanying Technology or the use of other license terms.
-
-3. Termination. This License and the rights granted hereunder will terminate
-automatically if Recipient fails to comply with terms herein and fails to cure
-such breach within 30 days of the breach. Any sublicense to the Subject
-Software that is properly granted shall survive any termination of this
-License absent termination by the terms of such sublicense. Provisions which,
-by their nature, must remain in effect beyond the termination of this License
-shall survive.
-
-4. Trademark Rights. This License does not grant any rights to use any trade
-name, trademark or service mark whatsoever. No trade name, trademark or
-service mark of SGI may be used to endorse or promote products derived from or
-incorporating any Subject Software without prior written permission of SGI.
-
-5. No Other Rights. No rights or licenses not expressly granted hereunder
-shall arise by implication, estoppel or otherwise. Title to and ownership of
-the Original Software at all times remains with SGI. All rights in the
-Original Software not expressly granted under this License are reserved.
-
-6. Compliance with Laws; Non-Infringement. Recipient shall comply with all
-applicable laws and regulations in connection with use and distribution of the
-Subject Software, including but not limited to, all export and import control
-laws and regulations of the U.S. government and other countries. Recipient may
-not distribute Subject Software that (i) in any way infringes (directly or
-contributorily) the rights (including patent, copyright, trade secret,
-trademark or other intellectual property rights of any kind) of any other
-person or entity, or (ii) breaches any representation or warranty, express,
-implied or statutory, which under any applicable law it might be deemed to
-have been distributed.
-
-7. Claims of Infringement. If Recipient at any time has knowledge of any one
-or more third party claims that reproduction, modification, use, distribution,
-import or sale of Subject Software (including particular functionality or code
-incorporated in Subject Software) infringes the third party's intellectual
-property rights, Recipient must place in a well-identified web page bearing
-the title "LEGAL" a description of each such claim and a description of the
-party making each such claim in sufficient detail that a user of the Subject
-Software will know whom to contact regarding the claim. Also, upon gaining
-such knowledge of any such claim, Recipient must conspicuously include the URL
-for such web page in the Required Notice, and in the text of any related
-documentation, license agreement or collateral in which Recipient describes
-end user's rights relating to the Subject Software. If Recipient obtains such
-knowledge after it makes Subject Software available to any other person or
-entity, Recipient shall take other steps (such as notifying appropriate
-mailing lists or newsgroups) reasonably calculated to provide such knowledge
-to those who received the Subject Software.
-
-8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
-LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS,
-MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO
-RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE
-PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
-SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
-ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED
-HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
-WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY),
-CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT
-ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND
-LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED.
-
-10. Indemnity. Recipient shall be solely responsible for damages arising,
-directly or indirectly, out of its utilization of rights under this License.
-Recipient will defend, indemnify and hold SGI and its successors and assigns
-harmless from and against any loss, liability, damages, costs or expenses
-(including the payment of reasonable attorneys fees) arising out of
-(Recipient's use, modification, reproduction and distribution of the Subject
-Software or out of any representation or warranty made by Recipient.
-
-11. U.S. Government End Users. The Subject Software is a "commercial item"
-consisting of "commercial computer software" as such terms are defined in
-title 48 of the Code of Federal Regulations and all U.S. Government End Users
-acquire only the rights set forth in this License and are subject to the terms
-of this License.
-
-12. Miscellaneous. This License represents the complete agreement concerning
-subject matter hereof. If any provision of this License is held to be
-unenforceable by any judicial or administrative authority having proper
-jurisdiction with respect thereto, such provision shall be reformed so as to
-achieve as nearly as possible the same economic effect as the original
-provision and the remainder of this License will remain in effect. This
-License shall be governed by and construed in accordance with the laws of the
-United States and the State of California as applied to agreements entered
-into and to be performed entirely within California between California
-residents. Any litigation relating to this License shall be subject to the
-exclusive jurisdiction of the Federal Courts of the Northern District of
-California (or, absent subject matter jurisdiction in such courts, the courts
-of the State of California), with venue lying exclusively in Santa Clara
-County, California, with the losing party responsible for costs, including
-without limitation, court costs and reasonable attorneys fees and expenses.
-The application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded. Any law or regulation that
-provides that the language of a contract shall be construed against the
-drafter shall not apply to this License.
-
-Exhibit A
-
-Copyright (c) 1994-1999 Silicon Graphics, Inc.
-
-The contents of this file are subject to the CID Font Code Public License
-Version 1.0 (the "License"). You may not use this file except in compliance
-with the License. You may obtain a copy of the License at Silicon Graphics,
-Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
-or at http://www.sgi.com/software/opensource/cid/license.html
-
-Software distributed under the License is distributed on an "AS IS" basis. ALL
-WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF
-NON-INFRINGEMENT. See the License for the specific language governing rights
-and limitations under the License.
-
-The Original Software (as defined in the License) is CID font code that was
-developed by Silicon Graphics, Inc. Those portions of the Subject Software (as
-defined in the License) that were created by Silicon Graphics, Inc. are
-Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved.
-
-[NOTE: When using this text in connection with Subject Software delivered
-solely in object code form, Recipient may replace the words "this file" with
-"this software" in both the first and second sentences.] 3.6. Bitstream Vera
-Fonts Copyright
-
-The fonts have a generous copyright, allowing derivative works (as long as
-"Bitstream" or "Vera" are not in the names), and full redistribution (so long
-as they are not *sold* by themselves). They can be be bundled, redistributed
-and sold with any software.
-
-The fonts are distributed under the following copyright:
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.  3.7. Bigelow & Holmes
-Inc and URW++ GmbH Luxi font license
-
-Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font instruction
-code copyright (c) 2001 by URW++ GmbH. All Rights Reserved. Luxi is a
-registered trademark of Bigelow & Holmes Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of these Fonts and associated documentation files (the "Font Software"), to
-deal in the Font Software, including without limitation the rights to use,
-copy, merge, publish, distribute, sublicense, and/or sell copies of the Font
-Software, and to permit persons to whom the Font Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software.
-
-The Font Software may not be modified, altered, or added to, and in particular
-the designs of glyphs or characters in the Fonts may not be modified nor may
-additional glyphs or characters be added to the Fonts. This License becomes
-null and void when the Fonts or Font Software have been modified.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BIGELOW & HOLMES INC. OR URW++
-GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
-GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
-INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
-SOFTWARE.
-
-Except as contained in this notice, the names of Bigelow & Holmes Inc. and
-URW++ GmbH. shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Font Software without prior written
-authorization from Bigelow & Holmes Inc. and URW++ GmbH.
-
-For further information, contact:
-
-info@urwpp.de or design@bigelowandholmes.com
-
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to zlib v1.2.5, which may be included 
-with JRE 8, JDK 8, and OpenJDK 8.
-
---- begin of LICENSE ---
-
-  version 1.2.5, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
-%% This notice is provided with respect to the following which may be 
-included with JRE 8, JDK 8, and OpenJDK 8, except where noted:
-
-  Apache Commons Math 2.2
-  Apache Derby 10.10.1.2        [included with JDK 8]
-  Apache Jakarta BCEL 5.2 
-  Apache Jakarta Regexp 1.4 
-  Apache Santuario XML Security for Java 1.5.4
-  Apache Xalan-Java 2.7.1 
-  Apache Xerces Java 2.10.0 
-  Apache XML Resolver 1.1 
-  Dynalink 0.5
-
-
---- begin of LICENSE ---
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
---- end of LICENSE ---
-
--------------------------------------------------------------------------------
-
diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml
index cbf7f29..6237191 100644
--- a/nashorn/make/build.xml
+++ b/nashorn/make/build.xml
@@ -278,7 +278,6 @@
       </classpath>
       <fileset dir="${dynalink.module.src.dir}" includes="**/*.java"/>
       <fileset dir="${nashorn.module.src.dir}" includes="**/*.java"/>
-      <fileset dir="${nashorn.shell.module.src.dir}" includes="**/*.java"/>
       <link href="http://docs.oracle.com/javase/8/docs/api/"/>
     </javadoc>
   </target>
diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties
index 9b61ea8..da1c640 100644
--- a/nashorn/make/project.properties
+++ b/nashorn/make/project.properties
@@ -356,6 +356,7 @@
   -server \
   ${test.module.imports} \
   ${run.test.jvmargs.external} \
+  --add-modules jdk.scripting.nashorn.shell \
   ${nashorn.override.option} \
   -Dfile.encoding=UTF-8 \
   -Duser.language=${run.test.user.language} \
diff --git a/nashorn/src/jdk.dynalink/share/legal/dynalink.md b/nashorn/src/jdk.dynalink/share/legal/dynalink.md
new file mode 100644
index 0000000..b8ee7cb
--- /dev/null
+++ b/nashorn/src/jdk.dynalink/share/legal/dynalink.md
@@ -0,0 +1,31 @@
+## Dynalink v.5
+
+### Dynalink License
+<pre>
+
+Copyright (c) 2009-2013, Attila Szegedi
+
+All rights reserved.Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* Neither the name of Attila Szegedi nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
index c40943b..a40ed5f 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
@@ -39,7 +39,6 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.io.UncheckedIOException;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -49,6 +48,7 @@
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.lang.reflect.Field;
 import java.lang.reflect.Layer;
@@ -1349,10 +1349,12 @@
     static Module createModuleTrusted(final Layer parent, final ModuleDescriptor descriptor, final ClassLoader loader) {
         final String mn = descriptor.name();
 
-        final ModuleReference mref = new ModuleReference(descriptor, null, () -> {
-            IOException ioe = new IOException("<dynamic module>");
-            throw new UncheckedIOException(ioe);
-        });
+        final ModuleReference mref = new ModuleReference(descriptor, null) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
 
         final ModuleFinder finder = new ModuleFinder() {
             @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index e04167d..250dbe5 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -107,14 +107,13 @@
 
         @Override
         public ArrayData ensure(final long safeIndex) {
-            if (safeIndex > 0L) {
-                if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
-                    return new SparseArrayData(this, safeIndex + 1);
-                }
-                //known to fit in int
-                return toRealArrayData((int)safeIndex);
-           }
-           return this;
+            assert safeIndex >= 0L;
+            if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
+                return new SparseArrayData(this, safeIndex + 1);
+            }
+            //known to fit in int
+            return toRealArrayData((int)safeIndex);
+
         }
 
         @Override
@@ -133,8 +132,8 @@
         }
 
         @Override
-        public void shiftLeft(final int by) {
-            //nop, always empty or we wouldn't be of this class
+        public ArrayData shiftLeft(final int by) {
+            return this; //nop, always empty or we wouldn't be of this class
         }
 
         @Override
@@ -451,13 +450,13 @@
     /**
      * Shift the array data left
      *
-     * TODO: explore start at an index and not at zero, to make these operations
-     * even faster. Offset everything from the index. Costs memory but is probably
-     * worth it
+     * TODO: This is used for Array.prototype.shift() which only shifts by 1,
+     * so we might consider dropping the offset parameter.
      *
      * @param by offset to shift
+     * @return New arraydata (or same)
      */
-    public abstract void shiftLeft(final int by);
+    public abstract ArrayData shiftLeft(final int by);
 
     /**
      * Shift the array right
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
index 19ecec2..47e6454 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
@@ -68,9 +68,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         underlying.shiftLeft(by);
         setLength(underlying.length());
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
index f18b4a4..2b03265 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
@@ -82,7 +82,7 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         throw unsupported("shiftLeft");
     }
 
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
index bd706c7..62e1ced 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
@@ -76,9 +76,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         deleted.shiftLeft(by, length());
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
index 7a6f098..d471031 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
@@ -101,10 +101,12 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         lo = Math.max(0, lo - by);
         hi = Math.max(-1, hi - by);
+
+        return isEmpty() ? getUnderlying() : this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
index ef899fc..03a6545 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
@@ -176,8 +176,15 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
index 73fcb08..3804e32 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
@@ -121,8 +121,14 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
index cb99de8..027bd6b 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
@@ -98,8 +98,14 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
index 4cb04e3..5be96e8 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
@@ -36,6 +36,7 @@
  * Handle arrays where the index is very large.
  */
 class SparseArrayData extends ArrayData {
+    /** Maximum size for dense arrays */
     static final int MAX_DENSE_LENGTH = 1024 * 1024;
 
     /** Underlying array. */
@@ -51,7 +52,7 @@
         this(underlying, length, new TreeMap<>());
     }
 
-    SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
+    private SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
         super(length);
         assert underlying.length() <= length;
         this.underlying = underlying;
@@ -89,38 +90,49 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        underlying.shiftLeft(by);
+    public ArrayData shiftLeft(final int by) {
+        underlying = underlying.shiftLeft(by);
 
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long newIndex = entry.getKey() - by;
-            if (newIndex < maxDenseLength) {
-                underlying = underlying.set((int) newIndex, entry.getValue(), false);
-            } else if (newIndex >= 0) {
-                newSparseMap.put(newIndex, entry.getValue());
+            if (newIndex >= 0) {
+                if (newIndex < maxDenseLength) {
+                    final long oldLength = underlying.length();
+                    underlying = underlying.ensure(newIndex)
+                            .set((int) newIndex, entry.getValue(), false)
+                            .safeDelete(oldLength, newIndex - 1, false);
+                } else {
+                    newSparseMap.put(newIndex, entry.getValue());
+                }
             }
         }
 
         sparseMap = newSparseMap;
         setLength(Math.max(length() - by, 0));
+
+        return sparseMap.isEmpty() ? underlying : this;
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
+        // Move elements from underlying to sparse map if necessary
         final long len = underlying.length();
         if (len + by > maxDenseLength) {
-            for (long i = maxDenseLength - by; i < len; i++) {
+            // Length of underlying array after shrinking, before right-shifting
+            final long tempLength = Math.max(0, maxDenseLength - by);
+            for (long i = tempLength; i < len; i++) {
                 if (underlying.has((int) i)) {
                     newSparseMap.put(i + by, underlying.getObject((int) i));
                 }
             }
-            underlying = underlying.shrink((int) (maxDenseLength - by));
+            underlying = underlying.shrink((int) tempLength);
+            underlying.setLength(tempLength);
         }
 
-        underlying.shiftRight(by);
+        underlying = underlying.shiftRight(by);
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long newIndex = entry.getKey() + by;
@@ -135,14 +147,6 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        // Usually #ensure only needs to be called if safeIndex is greater or equal current length.
-        // SparseArrayData is an exception as an index smaller than our current length may still
-        // exceed the underlying ArrayData's capacity. Because of this, SparseArrayData invokes
-        // its ensure method internally in various places where other ArrayData subclasses don't,
-        // making it safe for outside uses to only call ensure(safeIndex) if safeIndex >= length.
-        if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
-            underlying = underlying.ensure(safeIndex);
-        }
         if (safeIndex >= length()) {
             setLength(safeIndex + 1);
         }
@@ -167,8 +171,7 @@
     public ArrayData set(final int index, final Object value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -183,8 +186,7 @@
     public ArrayData set(final int index, final int value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -198,8 +200,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
index 2eaf61e..60a5b93 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
index 977b9e9..c6b1bd9 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
@@ -77,9 +77,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         undefined.shiftLeft(by, length());
+        return this;
     }
 
     @Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/legal/double-conversion.md b/nashorn/src/jdk.scripting.nashorn/share/legal/double-conversion.md
new file mode 100644
index 0000000..b662346
--- /dev/null
+++ b/nashorn/src/jdk.scripting.nashorn/share/legal/double-conversion.md
@@ -0,0 +1,36 @@
+## Double-conversion v1.1.5
+
+### Double-conversion License
+
+https://raw.githubusercontent.com/google/double-conversion/master/LICENSE
+
+<pre>
+
+Copyright 2006-2011, the V8 project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following
+  disclaimer in the documentation and/or other materials provided
+  with the distribution.
+* Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+</pre>
diff --git a/nashorn/src/jdk.scripting.nashorn/share/legal/joni.md b/nashorn/src/jdk.scripting.nashorn/share/legal/joni.md
new file mode 100644
index 0000000..d13f1e6
--- /dev/null
+++ b/nashorn/src/jdk.scripting.nashorn/share/legal/joni.md
@@ -0,0 +1,26 @@
+## JRuby Joni v1.1.9
+
+### JRuby License
+<pre>
+
+Jruby 2012
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+</pre>
diff --git a/nashorn/test/script/basic/JDK-8171219.js b/nashorn/test/script/basic/JDK-8171219.js
new file mode 100644
index 0000000..6c1cf72
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8171219.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8171219: Missing checks in sparse array shift() implementation
+ *
+ * @test
+ * @run
+ */
+
+var a = [];
+a[1048577] = 1;
+a.shift();
+a[1] = 2;
+a.shift();
+var ka = Object.keys(a);
+Assert.assertTrue(ka.length === 2);
+Assert.assertTrue(ka[0] === '0');
+Assert.assertTrue(ka[1] === '1048575');
+Assert.assertTrue(a.length === 1048576);
+Assert.assertTrue(a[0] === 2);
+Assert.assertTrue(a[1048575] = 1);
+
+var b = [];
+b[1048577] = 1;
+b.unshift(2);
+b.shift();
+b[1] = 3;
+b.shift();
+var kb = Object.keys(b);
+Assert.assertTrue(kb.length === 2);
+Assert.assertTrue(kb[0] === '0');
+Assert.assertTrue(kb[1] === '1048576');
+Assert.assertTrue(b.length === 1048577);
+Assert.assertTrue(b[0] === 3);
+Assert.assertTrue(b[1048576] = 1);
+
diff --git a/test/failure_handler/src/share/conf/mac.properties b/test/failure_handler/src/share/conf/mac.properties
index e2b1ac2..0e962f6 100644
--- a/test/failure_handler/src/share/conf/mac.properties
+++ b/test/failure_handler/src/share/conf/mac.properties
@@ -29,6 +29,7 @@
 # process info to gather
 ################################################################################
 onTimeout=\
+  native.DevToolsSecurity \
   native.vmmap native.heap native.leaks native.spindump \
   native.stack native.core
 ################################################################################
@@ -36,22 +37,34 @@
 native.javaOnly=false
 native.args=%p
 
-# Some of them require root privileges
-native.vmmap.app=vmmap
-native.heap.app=heap
-native.leaks.app=leaks
+native.DevToolsSecurity.app=DevToolsSecurity
+native.DevToolsSecurity.args=--status
+
+# spindump requires root privileges
 native.spindump.app=spindump
 native.spindump.args=%p -stdout
 
-native.stack.app=lldb
+native.vmmap.app=bash
+native.vmmap.delimiter=\0
+native.vmmap.args=-c\0DevToolsSecurity --status | grep -q enabled && vmmap %p
+
+native.leaks.app=bash
+native.leaks.delimiter=\0
+native.leaks.args=-c\0DevToolsSecurity --status | grep -q enabled && leaks %p
+
+native.heap.app=bash
+native.heap.delimiter=\0
+native.heap.args=-c\0DevToolsSecurity --status | grep -q enabled && heap %p
+
+native.stack.app=bash
 native.stack.delimiter=\0
 native.stack.params.repeat=6
-native.stack.args=-o\0attach %p\0-o\0thread backtrace all\0-o\0detach\0-o\0quit
+native.stack.args=-c\0DevToolsSecurity --status | grep -q enabled && lldb -o 'attach %p' -o 'thread backtrace all' -o 'detach' -o 'quit'
 
 native.core.app=bash
 native.core.delimiter=\0
 native.core.args=-c\0gcore -o ./core.%p %p || \
-  lldb -o 'attach %p' -o 'process save-core core.%p' -o 'detach' -o 'quit'
+  (DevToolsSecurity --status | grep -q enabled && lldb -o 'attach %p' -o 'process save-core core.%p' -o 'detach' -o 'quit')
 native.core.params.timeout=3600000
 ################################################################################
 # environment info to gather
@@ -89,7 +102,6 @@
 memory.vmstat.app=vm_stat
 memory.vmstat.args=-c 3 3
 
-
 netstat.app=netstat
 netstat.av.args=-av
 netstat.aL.args=-aL
diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java
index 5c088b6..06299e7 100644
--- a/test/jtreg-ext/requires/VMProps.java
+++ b/test/jtreg-ext/requires/VMProps.java
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -60,9 +61,10 @@
         map.put("vm.flightRecorder", vmFlightRecorder());
         map.put("vm.simpleArch", vmArch());
         map.put("vm.debug", vmDebug());
+        map.put("vm.jvmci", vmJvmci());
         vmGC(map); // vm.gc.X = true/false
 
-        dump(map);
+        VMProps.dump(map);
         return map;
     }
 
@@ -156,6 +158,14 @@
     }
 
     /**
+     * @return true if VM supports JVMCI and false otherwise
+     */
+    protected String vmJvmci() {
+        // builds with jvmci have this flag
+        return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null);
+    }
+
+    /**
      * For all existing GC sets vm.gc.X property.
      * Example vm.gc.G1=true means:
      *    VM supports G1
@@ -180,7 +190,7 @@
      *
      * @param map
      */
-    protected void dump(Map<String, String> map) {
+    protected static void dump(Map<String, String> map) {
         String dumpFileName = System.getProperty("vmprops.dump");
         if (dumpFileName == null) {
             return;
@@ -188,7 +198,7 @@
         List<String> lines = new ArrayList<>();
         map.forEach((k, v) -> lines.add(k + ":" + v));
         try {
-            Files.write(Paths.get(dumpFileName), lines);
+            Files.write(Paths.get(dumpFileName), lines, StandardOpenOption.APPEND);
         } catch (IOException e) {
             throw new RuntimeException("Failed to dump properties into '"
                     + dumpFileName + "'", e);
diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java
index f648bfb..3f92437 100644
--- a/test/lib/jdk/test/lib/Platform.java
+++ b/test/lib/jdk/test/lib/Platform.java
@@ -160,9 +160,8 @@
         return vmVersion;
     }
 
-    // Returns true for sparc and sparcv9.
-    public static boolean isSparc() {
-        return isArch("sparc.*");
+    public static boolean isAArch64() {
+        return isArch("aarch64");
     }
 
     public static boolean isARM() {
@@ -173,9 +172,14 @@
         return isArch("ppc.*");
     }
 
-    public static boolean isX86() {
-        // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
-        return isArch("(i386)|(x86(?!_64))");
+    // Returns true for IBM z System running linux.
+    public static boolean isS390x() {
+        return isArch("s390.*") || isArch("s/390.*") || isArch("zArch_64");
+    }
+
+    // Returns true for sparc and sparcv9.
+    public static boolean isSparc() {
+        return isArch("sparc.*");
     }
 
     public static boolean isX64() {
@@ -183,8 +187,9 @@
         return isArch("(amd64)|(x86_64)");
     }
 
-    public static boolean isAArch64() {
-        return isArch("aarch64");
+    public static boolean isX86() {
+        // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
+        return isArch("(i386)|(x86(?!_64))");
     }
 
     public static String getOsArch() {
@@ -200,6 +205,7 @@
         if (isAix()) {
             return false;   // SA not implemented.
         } else if (isLinux()) {
+            if (isS390x()) { return false; }   // SA not implemented.
             return canPtraceAttachLinux();
         } else if (isOSX()) {
             return canAttachOSX();
diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java
index c01657f..5a2b507 100644
--- a/test/lib/sun/hotspot/WhiteBox.java
+++ b/test/lib/sun/hotspot/WhiteBox.java
@@ -229,7 +229,7 @@
     return isMethodCompiled0(method, isOsr);
   }
   public        boolean isMethodCompilable(Executable method) {
-    return isMethodCompilable(method, -1 /*any*/);
+    return isMethodCompilable(method, -2 /*any*/);
   }
   public        boolean isMethodCompilable(Executable method, int compLevel) {
     return isMethodCompilable(method, compLevel, false /*not osr*/);
@@ -277,7 +277,7 @@
     return deoptimizeMethod0(method, isOsr);
   }
   public        void    makeMethodNotCompilable(Executable method) {
-    makeMethodNotCompilable(method, -1 /*any*/);
+    makeMethodNotCompilable(method, -2 /*any*/);
   }
   public        void    makeMethodNotCompilable(Executable method, int compLevel) {
     makeMethodNotCompilable(method, compLevel, false /*not osr*/);
@@ -301,7 +301,7 @@
     return testSetDontInlineMethod0(method, value);
   }
   public        int     getCompileQueuesSize() {
-    return getCompileQueueSize(-1 /*any*/);
+    return getCompileQueueSize(-2 /*any*/);
   }
   public native int     getCompileQueueSize(int compLevel);
   private native boolean testSetForceInlineMethod0(Executable method, boolean value);
diff --git a/test/lib/sun/hotspot/code/CodeBlob.java b/test/lib/sun/hotspot/code/CodeBlob.java
index e303cad..2c90729 100644
--- a/test/lib/sun/hotspot/code/CodeBlob.java
+++ b/test/lib/sun/hotspot/code/CodeBlob.java
@@ -49,8 +49,13 @@
     assert obj.length == 4;
     name = (String) obj[0];
     size = (Integer) obj[1];
-    code_blob_type = BlobType.values()[(Integer) obj[2]];
-    assert code_blob_type.id == (Integer) obj[2];
+    int blob_type_index = (Integer) obj[2];
+    if (blob_type_index == -1) { // AOT
+      code_blob_type = null;
+    } else {
+      code_blob_type = BlobType.values()[blob_type_index];
+      assert code_blob_type.id == (Integer) obj[2];
+    }
     address = (Long) obj[3];
   }
   public final String name;